Repository: DeathKing/Learning-SICP Branch: master Commit: 211bbe61b9de Files: 135 Total size: 10.2 MB Directory structure: gitextract_b_q_3yll/ ├── .gitignore ├── Ass/ │ ├── lec10a.chn+eng.ass │ ├── lec10a.chn.ass │ ├── lec10a.eng.ass │ ├── lec10b.chn+eng.ass │ ├── lec10b.chn.ass │ ├── lec10b.eng.ass │ ├── lec1a.chn+eng.ass │ ├── lec1a.chn.ass │ ├── lec1a.eng.ass │ ├── lec3a.chn+eng.ass │ ├── lec3a.chn.ass │ ├── lec3a.eng.ass │ ├── lec3b.chn+eng.ass │ ├── lec3b.chn.ass │ ├── lec3b.eng.ass │ ├── lec4a.chn+eng.ass │ ├── lec4a.chn.ass │ ├── lec4a.eng.ass │ ├── lec4b.chn+eng.ass │ ├── lec4b.chn.ass │ ├── lec4b.eng.ass │ ├── lec5a.chn+eng.ass │ ├── lec5a.chn.ass │ ├── lec5a.eng.ass │ ├── lec5b.chn+eng.ass │ ├── lec5b.chn.ass │ ├── lec5b.eng.ass │ ├── lec6a.chn+eng.ass │ ├── lec6a.chn.ass │ ├── lec6a.eng.ass │ ├── lec6b.chn+eng.ass │ ├── lec6b.chn.ass │ ├── lec6b.eng.ass │ ├── lec7a.chn+eng.ass │ ├── lec7a.chn.ass │ ├── lec7a.eng.ass │ ├── lec7b.chn+eng.ass │ ├── lec7b.chn.ass │ ├── lec7b.eng.ass │ ├── lec8a.chn+eng.ass │ ├── lec8a.chn.ass │ ├── lec8a.eng.ass │ ├── lec8b.chn+eng.ass │ ├── lec8b.chn.ass │ ├── lec8b.eng.ass │ ├── lec9a.chn+eng.ass │ ├── lec9a.chn.ass │ ├── lec9a.eng.ass │ ├── lec9b.chn+eng.ass │ ├── lec9b.chn.ass │ └── lec9b.eng.ass ├── Preface/ │ ├── pre1.txt │ ├── pre2.txt │ ├── pre3.txt │ ├── pre4.txt │ └── pre5.txt ├── README.md ├── SrtCN/ │ ├── lec10a.eng.srt │ ├── lec10a.srt │ ├── lec10b.eng.srt │ ├── lec10b.srt │ ├── lec1a.srt │ ├── lec1b.srt │ ├── lec2a.srt │ ├── lec2b.srt │ ├── lec3a.srt │ ├── lec3b.srt │ ├── lec4a.srt │ ├── lec4b.srt │ ├── lec5a.srt │ ├── lec5b.srt │ ├── lec6a.srt │ ├── lec6b.srt │ ├── lec7a.srt │ ├── lec7b.srt │ ├── lec8a.chn.srt │ ├── lec8a.srt │ ├── lec8b.eng.srt │ ├── lec8b.srt │ ├── lec9a.srt │ ├── lec9b.eng.srt │ └── lec9b.srt ├── SrtEN/ │ ├── lec10a_512kb.mp4.srt │ ├── lec10b_512kb.mp4.srt │ ├── lec1a_512kb.mp4.srt │ ├── lec1b_512kb.mp4.srt │ ├── lec2a_512kb.mp4.srt │ ├── lec2b_512kb.mp4.srt │ ├── lec3a_512kb.mp4.srt │ ├── lec3b_512kb.mp4.srt │ ├── lec4a_512kb.mp4.srt │ ├── lec4b_512kb.mp4.srt │ ├── lec5a_512kb.mp4.srt │ ├── lec5b_512kb.mp4.srt │ ├── lec6a_512kb.mp4.srt │ ├── lec6b_512kb.mp4.srt │ ├── lec7a_512kb.mp4.srt │ ├── lec7b_512kb.mp4.srt │ ├── lec8a_512kb.mp4.srt │ ├── lec8b_512kb.mp4.srt │ ├── lec9a_512kb.mp4.srt │ └── lec9b_512kb.mp4.srt ├── Sub/ │ ├── lec10a.txt │ ├── lec10b.txt │ ├── lec1a.txt │ ├── lec1b.txt │ ├── lec2a.txt │ ├── lec2b.txt │ ├── lec3a.txt │ ├── lec3b.txt │ ├── lec4a.txt │ ├── lec4b.txt │ ├── lec5a.txt │ ├── lec5b.txt │ ├── lec6a.txt │ ├── lec6b.txt │ ├── lec7a.txt │ ├── lec7b.txt │ ├── lec8a.txt │ ├── lec8b.txt │ ├── lec9a.txt │ └── lec9b.txt └── Tools/ ├── con2table.rb ├── contributor.json ├── download-sicp-movies.sh ├── lec.json ├── lec2tabel.rb ├── merge.rb ├── pdf2txt.rb ├── separate.rb ├── split.pl ├── split.rb ├── timeline.rb └── util.rb ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.*~ #*# .DS_Store Thumbs.db *.backup Tools/*.srt Tools/*.ass ================================================ FILE: Ass/lec10a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 1691 Video Position: 197 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:19.36,0:00:22.65,EN,,0,0,0,,PROFESSOR: Last time, we took a look at Dialogue: 0,0:00:22.65,0:00:25.67,EN,,0,0,0,,an explicit control evaluator for Lisp Dialogue: 0,0:00:25.67,0:00:28.97,EN,,0,0,0,,and that bridged the gap between all these high-level languages Dialogue: 0,0:00:29.05,0:00:32.14,EN,,0,0,0,,like Lisp and query language all that stuff Dialogue: 0,0:00:32.50,0:00:36.16,EN,,0,0,0,,bridged the gap between that and a conventional register machine. Dialogue: 0,0:00:36.70,0:00:40.14,EN,,0,0,0,,And in fact, you can think of the explicit control evaluator Dialogue: 0,0:00:40.16,0:00:44.38,EN,,0,0,0,,either as, say the code for a Lisp interpreter Dialogue: 0,0:00:44.40,0:00:45.95,EN,,0,0,0,,if you wanted to implement it in the Dialogue: 0,0:00:46.52,0:00:49.50,EN,,0,0,0,,assembly language of some conventional register transfer machine, Dialogue: 0,0:00:49.50,0:00:51.50,EN,,0,0,0,,or, if you like, you can think of it as the microcode Dialogue: 0,0:00:52.08,0:00:54.56,EN,,0,0,0,,of some machine that's going to be specially designed to run Lisp. Dialogue: 0,0:00:55.20,0:00:55.92,EN,,0,0,0,,In either case, Dialogue: 0,0:00:55.92,0:00:58.68,EN,,0,0,0,,Nwhat we're doing is we're taking a machine Dialogue: 0,0:00:58.94,0:01:00.51,EN,,0,0,0,,that speaks some low-level language Dialogue: 0,0:01:01.42,0:01:03.32,EN,,0,0,0,,and we're raising the machine Dialogue: 0,0:01:03.37,0:01:04.88,EN,,0,0,0,,to a high-level language like Lisp Dialogue: 0,0:01:05.36,0:01:06.35,EN,,0,0,0,,by writing an interpreter. Dialogue: 0,0:01:08.22,0:01:09.58,EN,,0,0,0,,So for instance Dialogue: 0,0:01:11.82,0:01:13.77,EN,,0,0,0,,here, conceptually, Dialogue: 0,0:01:18.01,0:01:19.47,EN,,0,0,0,,here conceptually is a Dialogue: 0,0:01:20.54,0:01:23.44,EN,,0,0,0,,a special purpose machine for computing factorials. Dialogue: 0,0:01:24.09,0:01:27.39,EN,,0,0,0,,It takes in five and puts out 120. Dialogue: 0,0:01:28.92,0:01:30.83,EN,,0,0,0,,And what this special purpose machine is Dialogue: 0,0:01:30.97,0:01:32.72,EN,,0,0,0,,actually a Lisp interpreter Dialogue: 0,0:01:33.50,0:01:36.17,EN,,0,0,0,,that's configured itself to run factorials Dialogue: 0,0:01:38.35,0:01:40.99,EN,,0,0,0,,because you feed into it a description of the factorial machine. Dialogue: 0,0:01:42.12,0:01:43.70,EN,,0,0,0,,So that's what an interpreter is. Dialogue: 0,0:01:43.70,0:01:45.66,EN,,0,0,0,,It configures itself to Dialogue: 0,0:01:46.37,0:01:49.24,EN,,0,0,0,,emulate a machine whose description you read in. Dialogue: 0,0:01:50.07,0:01:51.93,EN,,0,0,0,,Now, inside the Lisp interpreter, what's that? Dialogue: 0,0:01:52.04,0:01:55.44,EN,,0,0,0,,Well, that might be your general register language interpreter Dialogue: 0,0:01:56.98,0:02:00.18,EN,,0,0,0,,that configures itself to behave like a Lisp interpreter Dialogue: 0,0:02:00.18,0:02:02.03,EN,,0,0,0,,because you put in a whole bunch of instructions Dialogue: 0,0:02:02.12,0:02:03.04,EN,,0,0,0,,in register language. Dialogue: 0,0:02:03.37,0:02:05.16,EN,,0,0,0,,This is the explicit control evaluator. Dialogue: 0,0:02:07.05,0:02:08.70,EN,,0,0,0,,And then it also has some sort of library Dialogue: 0,0:02:08.73,0:02:11.08,EN,,0,0,0,,a library of primitive operators and Lisp operations Dialogue: 0,0:02:11.12,0:02:12.28,EN,,0,0,0,,all sorts of things like that. Dialogue: 0,0:02:12.75,0:02:16.89,EN,,0,0,0,,That's the general strategy of interpretation. Dialogue: 0,0:02:17.32,0:02:18.51,EN,,0,0,0,,And the point is, what we're doing Dialogue: 0,0:02:18.60,0:02:20.14,EN,,0,0,0,,is we're writing an interpreter Dialogue: 0,0:02:21.62,0:02:23.40,EN,,0,0,0,,to raise the machine Dialogue: 0,0:02:23.42,0:02:25.24,EN,,0,0,0,,to the level of the programs that we want to write. Dialogue: 0,0:02:25.24,0:02:26.72,EN,,0,0,0,,Well, there's another strategy Dialogue: 0,0:02:27.42,0:02:28.89,EN,,0,0,0,,a different one, which is compilation. Dialogue: 0,0:02:29.04,0:02:30.43,EN,,0,0,0,,Compilation's a little bit different. Dialogue: 0,0:02:31.04,0:02:31.50,EN,,0,0,0,,Here-- Dialogue: 0,0:02:33.37,0:02:34.75,EN,,0,0,0,,here we might have produced Dialogue: 0,0:02:35.67,0:02:38.52,EN,,0,0,0,,a special purpose machine for, Dialogue: 0,0:02:38.62,0:02:39.98,EN,,0,0,0,,for computing factorials Dialogue: 0,0:02:43.62,0:02:46.26,EN,,0,0,0,,starting with some sort of machine that speaks register language Dialogue: 0,0:02:46.26,0:02:47.72,EN,,0,0,0,,except we're going to do a different strategy. Dialogue: 0,0:02:47.72,0:02:50.38,EN,,0,0,0,,We take our factorial program. Dialogue: 0,0:02:51.55,0:02:53.92,EN,,0,0,0,,We use that as the source code into a compiler. Dialogue: 0,0:02:53.92,0:02:55.15,EN,,0,0,0,,What the compiler will do Dialogue: 0,0:02:55.15,0:02:57.62,EN,,0,0,0,,is translate that factorial program Dialogue: 0,0:02:57.62,0:02:59.07,EN,,0,0,0,,into some register machine language. Dialogue: 0,0:03:00.25,0:03:03.40,EN,,0,0,0,,And this will now be not the explicit control evaluator for Lisp Dialogue: 0,0:03:03.40,0:03:06.17,EN,,0,0,0,,this will be some register language for computing factorials. Dialogue: 0,0:03:06.49,0:03:08.36,EN,,0,0,0,,So this is the translation of that. Dialogue: 0,0:03:10.54,0:03:12.41,EN,,0,0,0,,That will go into some sort of loader Dialogue: 0,0:03:13.35,0:03:15.21,EN,,0,0,0,,which will combine this code Dialogue: 0,0:03:15.31,0:03:16.84,EN,,0,0,0,,with code selected from the library Dialogue: 0,0:03:16.86,0:03:18.65,EN,,0,0,0,,to do things like primitive multiplication. Dialogue: 0,0:03:19.82,0:03:21.69,EN,,0,0,0,,And then we'll produce a load module Dialogue: 0,0:03:22.22,0:03:25.06,EN,,0,0,0,,which configures the register language machine Dialogue: 0,0:03:25.06,0:03:27.24,EN,,0,0,0,,to be a special purpose factorial machine. Dialogue: 0,0:03:28.12,0:03:30.22,EN,,0,0,0,,So that's a, that's a different strategy. Dialogue: 0,0:03:30.22,0:03:31.22,EN,,0,0,0,,In interpretation, Dialogue: 0,0:03:31.22,0:03:32.01,EN,,0,0,0,,we're raising Dialogue: 0,0:03:32.91,0:03:35.23,EN,,0,0,0,,the machine to the level of our language, like Lisp. Dialogue: 0,0:03:35.32,0:03:36.34,EN,,0,0,0,,In compilation Dialogue: 0,0:03:36.34,0:03:38.43,EN,,0,0,0,,we're taking our program and lowering Dialogue: 0,0:03:38.48,0:03:40.56,EN,,0,0,0,,it to the language that's spoken by the machine. Dialogue: 0,0:03:41.96,0:03:43.84,EN,,0,0,0,,Well, how do these two strategies compare? Dialogue: 0,0:03:44.30,0:03:49.42,EN,,0,0,0,,The compiler can produce code that will execute more efficiently. Dialogue: 0,0:03:52.05,0:03:53.90,EN,,0,0,0,,The essential reason for that Dialogue: 0,0:03:54.17,0:03:58.89,EN,,0,0,0,,is that if you think about the register operations that are running Dialogue: 0,0:04:01.92,0:04:04.49,EN,,0,0,0,,the interpreter has to produce register operations Dialogue: 0,0:04:04.97,0:04:06.75,EN,,0,0,0,,which, in principle, are going to be general enough Dialogue: 0,0:04:07.32,0:04:08.94,EN,,0,0,0,,to execute any Lisp procedure. Dialogue: 0,0:04:10.22,0:04:12.25,EN,,0,0,0,,Whereas the compiler only has to worry about Dialogue: 0,0:04:12.27,0:04:14.92,EN,,0,0,0,,producing a special bunch of register operations for Dialogue: 0,0:04:15.52,0:04:18.22,EN,,0,0,0,,for doing the particular Lisp procedure that you've compiled. Dialogue: 0,0:04:20.17,0:04:21.20,EN,,0,0,0,,Or another way to say that Dialogue: 0,0:04:21.20,0:04:25.31,EN,,0,0,0,,is that the interpreter is a general purpose simulator Dialogue: 0,0:04:25.92,0:04:27.58,EN,,0,0,0,,that when you read in a Lisp procedure Dialogue: 0,0:04:27.58,0:04:31.32,EN,,0,0,0,,then those can simulate the program described by that, by that procedure. Dialogue: 0,0:04:31.32,0:04:33.87,EN,,0,0,0,,So the interpreter is worrying about making a general purpose simulator Dialogue: 0,0:04:34.62,0:04:35.96,EN,,0,0,0,,whereas the compiler, in effect, Dialogue: 0,0:04:36.00,0:04:37.68,EN,,0,0,0,,is configuring the thing to be the machine Dialogue: 0,0:04:37.71,0:04:39.34,EN,,0,0,0,,that the interpreter would have been simulating. Dialogue: 0,0:04:40.02,0:04:41.34,EN,,0,0,0,,So the compiler can be faster. Dialogue: 0,0:04:52.55,0:04:53.64,EN,,0,0,0,,OK, On the other hand Dialogue: 0,0:04:55.97,0:04:58.28,EN,,0,0,0,,the interpreter is a nicer environment for debugging. Dialogue: 0,0:04:59.43,0:05:01.25,EN,,0,0,0,,And the reason for that is that we've got the Dialogue: 0,0:05:01.57,0:05:03.02,EN,,0,0,0,,the source code actually there. Dialogue: 0,0:05:03.02,0:05:04.81,EN,,0,0,0,,We're interpreting it That's what we're working with. Dialogue: 0,0:05:05.87,0:05:07.69,EN,,0,0,0,,And we also have the library around. Dialogue: 0,0:05:07.90,0:05:10.89,EN,,0,0,0,,See, the interpreter--the library sitting there is part of the interpreter. Dialogue: 0,0:05:11.30,0:05:13.16,EN,,0,0,0,,The compiler only pulls out from the library Dialogue: 0,0:05:13.20,0:05:14.56,EN,,0,0,0,,what it needs to run the program. Dialogue: 0,0:05:14.87,0:05:17.00,EN,,0,0,0,,So if you're in the middle of debugging Dialogue: 0,0:05:18.00,0:05:20.72,EN,,0,0,0,,and you might like to write a little extra program Dialogue: 0,0:05:20.80,0:05:22.57,EN,,0,0,0,,to examine some run time data structure Dialogue: 0,0:05:23.05,0:05:24.25,EN,,0,0,0,,or to produce some computation Dialogue: 0,0:05:24.30,0:05:25.92,EN,,0,0,0,,that you didn't think of when you wrote the program Dialogue: 0,0:05:25.95,0:05:27.53,EN,,0,0,0,,the interpreter can do that perfectly well Dialogue: 0,0:05:28.05,0:05:29.21,EN,,0,0,0,,whereas the compiler can't. Dialogue: 0,0:05:29.62,0:05:31.90,EN,,0,0,0,,So there are sort of dual, dual advantages. Dialogue: 0,0:05:31.90,0:05:34.48,EN,,0,0,0,,The compiler will produce code that executes faster. Dialogue: 0,0:05:34.85,0:05:37.02,EN,,0,0,0,,The interpreter is a better environment for debugging. Dialogue: 0,0:05:38.95,0:05:41.40,EN,,0,0,0,,And most Lisp systems end up having both Dialogue: 0,0:05:42.92,0:05:45.23,EN,,0,0,0,,end up being configured so you have an interpreter Dialogue: 0,0:05:45.24,0:05:47.08,EN,,0,0,0,,that you use when you're developing your code. Dialogue: 0,0:05:47.08,0:05:48.62,EN,,0,0,0,,Then you can speed it up by compiling. Dialogue: 0,0:05:49.02,0:05:50.03,EN,,0,0,0,,And very often, Dialogue: 0,0:05:50.04,0:05:51.68,EN,,0,0,0,,you can arrange that compiled code Dialogue: 0,0:05:51.69,0:05:53.56,EN,,0,0,0,,and interpreted code can call each other. Dialogue: 0,0:05:54.60,0:05:56.33,EN,,0,0,0,,We'll see how to do that, That's not hard. Dialogue: 0,0:05:59.27,0:05:59.85,EN,,0,0,0,,OK Dialogue: 0,0:06:00.97,0:06:02.09,EN,,0,0,0,,In fact, the way we'll-- Dialogue: 0,0:06:04.30,0:06:05.75,EN,,0,0,0,,in the compiler we're going to make Dialogue: 0,0:06:05.75,0:06:07.58,EN,,0,0,0,,the way we'll arrange for compiled coding Dialogue: 0,0:06:07.58,0:06:09.45,EN,,0,0,0,,and interpreted code to call to call each other Dialogue: 0,0:06:09.90,0:06:12.06,EN,,0,0,0,,is that we'll have the compiler use exactly Dialogue: 0,0:06:12.11,0:06:14.40,EN,,0,0,0,,the same register conventions as the interpreter. Dialogue: 0,0:06:18.42,0:06:21.72,EN,,0,0,0,,Well, the idea of a compiler Dialogue: 0,0:06:21.76,0:06:25.74,EN,,0,0,0,,is very much like the idea of an interpreter or evaluator. Dialogue: 0,0:06:25.87,0:06:26.46,EN,,0,0,0,,It's the same thing. Dialogue: 0,0:06:27.05,0:06:29.39,EN,,0,0,0,,See, the evaluator walks over the code Dialogue: 0,0:06:29.82,0:06:32.35,EN,,0,0,0,,and performs some register operations. Dialogue: 0,0:06:33.65,0:06:34.97,EN,,0,0,0,,That's what we did yesterday. Dialogue: 0,0:06:37.10,0:06:40.27,EN,,0,0,0,,Well, the compiler essentially would like to walk over the code Dialogue: 0,0:06:40.52,0:06:43.00,EN,,0,0,0,,and produce the register operations Dialogue: 0,0:06:43.04,0:06:44.67,EN,,0,0,0,,that the evaluator would have done Dialogue: 0,0:06:45.23,0:06:46.64,EN,,0,0,0,,were it evaluating the thing. Dialogue: 0,0:06:48.60,0:06:49.95,EN,,0,0,0,,And that gives us some model Dialogue: 0,0:06:50.60,0:06:53.77,EN,,0,0,0,,for how to implement a zeroth-order compiler Dialogue: 0,0:06:55.30,0:06:58.32,EN,,0,0,0,,a very bad compiler but essentially a compiler. Dialogue: 0,0:06:58.32,0:06:59.32,EN,,0,0,0,,A model for doing that Dialogue: 0,0:06:59.36,0:07:00.59,EN,,0,0,0,,is you just take the evaluator, Dialogue: 0,0:07:00.68,0:07:01.88,EN,,0,0,0,,you run it over the code Dialogue: 0,0:07:02.80,0:07:06.06,EN,,0,0,0,,but instead of executing the actual operations Dialogue: 0,0:07:06.06,0:07:07.15,EN,,0,0,0,,you just save them away. Dialogue: 0,0:07:07.55,0:07:08.82,EN,,0,0,0,,And that's your compiled code. Dialogue: 0,0:07:08.82,0:07:10.24,EN,,0,0,0,,So let me give you an example of that. Dialogue: 0,0:07:12.70,0:07:14.14,EN,,0,0,0,,Suppose we're going to compile-- Dialogue: 0,0:07:15.10,0:07:17.90,EN,,0,0,0,,Suppose we want to compile the expression f of x. Dialogue: 0,0:07:25.07,0:07:25.96,EN,,0,0,0,,So let's assume that Dialogue: 0,0:07:25.96,0:07:28.06,EN,,0,0,0,,we've got f of x in the exp register Dialogue: 0,0:07:28.06,0:07:29.55,EN,,0,0,0,,and something in the environment register. Dialogue: 0,0:07:30.10,0:07:32.20,EN,,0,0,0,,And now imagine starting up the evaluator. Dialogue: 0,0:07:34.60,0:07:35.71,EN,,0,0,0,,Well, it looks at the expression Dialogue: 0,0:07:35.71,0:07:37.36,EN,,0,0,0,,and it sees that it's an application. Dialogue: 0,0:07:37.92,0:07:41.90,EN,,0,0,0,,And it branches to a place in the Dialogue: 0,0:07:42.52,0:07:45.15,EN,,0,0,0,,in the evaluator code we saw called ev-application. Dialogue: 0,0:07:47.12,0:07:48.12,EN,,0,0,0,,And then it begins. Dialogue: 0,0:07:48.16,0:07:50.08,EN,,0,0,0,,It stores away the operands and unev Dialogue: 0,0:07:50.08,0:07:52.44,EN,,0,0,0,,and then it's going to put the operator in exp, Dialogue: 0,0:07:52.48,0:07:54.27,EN,,0,0,0,,and it's going to go recursively evaluate it. Dialogue: 0,0:07:54.47,0:07:56.08,EN,,0,0,0,,That's the process that we walk through. Dialogue: 0,0:07:56.67,0:07:57.84,EN,,0,0,0,,And if you start looking at the code, Dialogue: 0,0:07:57.87,0:07:59.74,EN,,0,0,0,,you start seeing some register operations. Dialogue: 0,0:08:00.20,0:08:02.30,EN,,0,0,0,,You see assign to unev the operands Dialogue: 0,0:08:02.30,0:08:03.95,EN,,0,0,0,,assign to exp the operator, Dialogue: 0,0:08:04.09,0:08:06.20,EN,,0,0,0,,save the environment, generate that, and so on. Dialogue: 0,0:08:10.22,0:08:11.93,EN,,0,0,0,,Well, if we look on the overhead here Dialogue: 0,0:08:15.75,0:08:19.58,EN,,0,0,0,,we can see those operations starting to be produced. Dialogue: 0,0:08:20.82,0:08:22.52,EN,,0,0,0,,Here's sort of the first real operation Dialogue: 0,0:08:22.72,0:08:24.80,EN,,0,0,0,,that the evaluator would have done. Dialogue: 0,0:08:25.00,0:08:27.20,EN,,0,0,0,,It pulls the operands out of the exp register Dialogue: 0,0:08:27.47,0:08:28.62,EN,,0,0,0,,and assigns it to unev. Dialogue: 0,0:08:30.03,0:08:32.27,EN,,0,0,0,,And then it assigns something to the expression register, Dialogue: 0,0:08:32.30,0:08:33.46,EN,,0,0,0,,and it saves continue Dialogue: 0,0:08:33.46,0:08:34.62,EN,,0,0,0,,and it saves env. Dialogue: 0,0:08:34.62,0:08:38.65,EN,,0,0,0,,And all I'm doing here is writing down the register assignments Dialogue: 0,0:08:39.57,0:08:42.32,EN,,0,0,0,,that the evaluator would have done in executing that code. Dialogue: 0,0:08:42.77,0:08:43.79,EN,,0,0,0,,And can zoom out a little bit. Dialogue: 0,0:08:44.30,0:08:47.13,EN,,0,0,0,,Altogether, there are about 19 operations there. Dialogue: 0,0:08:49.40,0:08:51.64,EN,,0,0,0,,And this is the--this will be the piece of code Dialogue: 0,0:08:52.05,0:08:53.90,EN,,0,0,0,,up until the point where Dialogue: 0,0:08:54.75,0:08:57.10,EN,,0,0,0,,the evaluator branches off to apply-dispatch. Dialogue: 0,0:08:57.86,0:08:59.16,EN,,0,0,0,,And in fact, in this compiler Dialogue: 0,0:08:59.20,0:09:01.18,EN,,0,0,0,,we're not going to worry about apply-dispatch at all. Dialogue: 0,0:09:01.30,0:09:02.11,EN,,0,0,0,,We're going to have everything Dialogue: 0,0:09:02.35,0:09:05.04,EN,,0,0,0,,we're going to have both interpreted code and compiled code. Dialogue: 0,0:09:06.07,0:09:07.61,EN,,0,0,0,,Always evaluate procedures, Dialogue: 0,0:09:07.61,0:09:09.85,EN,,0,0,0,,always apply procedures by going to apply-dispatch. Dialogue: 0,0:09:10.27,0:09:12.32,EN,,0,0,0,,That will easily allow interpreted code and Dialogue: 0,0:09:12.36,0:09:13.71,EN,,0,0,0,,compiled code to call each other. Dialogue: 0,0:09:18.27,0:09:19.87,EN,,0,0,0,,Well, in principle, that's all we need to do. Dialogue: 0,0:09:21.05,0:09:22.66,EN,,0,0,0,,You just run the evaluator. Dialogue: 0,0:09:22.66,0:09:24.50,EN,,0,0,0,,So the compiler's a lot like the evaluator. Dialogue: 0,0:09:24.50,0:09:26.47,EN,,0,0,0,,You run it, except it stashes away these operations Dialogue: 0,0:09:26.47,0:09:28.40,EN,,0,0,0,,instead of actually executing them. Dialogue: 0,0:09:29.35,0:09:31.39,EN,,0,0,0,,Well, that's not, that's not quite true. there's Dialogue: 0,0:09:32.91,0:09:34.99,EN,,0,0,0,,There's only one little lie in that. Dialogue: 0,0:09:36.24,0:09:39.29,EN,,0,0,0,,What you have to worry about is if you have a, a predicate. Dialogue: 0,0:09:40.12,0:09:42.16,EN,,0,0,0,,If you have some kind of test you want to do Dialogue: 0,0:09:43.45,0:09:46.03,EN,,0,0,0,,obviously, at the point when you're compiling it Dialogue: 0,0:09:46.52,0:09:47.98,EN,,0,0,0,,you don't know which branch of these-- Dialogue: 0,0:09:48.32,0:09:50.14,EN,,0,0,0,,of a conditional like this you're going to do. Dialogue: 0,0:09:51.13,0:09:53.92,EN,,0,0,0,,So you can't say which one the evaluator would have done. Dialogue: 0,0:09:54.90,0:09:57.12,EN,,0,0,0,,So all you do there is very simple. Dialogue: 0,0:09:57.12,0:09:58.49,EN,,0,0,0,,You compile both branches. Dialogue: 0,0:09:59.32,0:10:01.29,EN,,0,0,0,,So you compile a structure that looks like this. Dialogue: 0,0:10:02.00,0:10:03.98,EN,,0,0,0,,That'll compile into something that says, Dialogue: 0,0:10:05.31,0:10:09.15,EN,,0,0,0,,the code, the code for P. Dialogue: 0,0:10:10.71,0:10:16.51,EN,,0,0,0,,And it puts its results in, say, the val register. Dialogue: 0,0:10:18.17,0:10:20.64,EN,,0,0,0,,So you walk the interpreter over the predicate Dialogue: 0,0:10:21.35,0:10:24.19,EN,,0,0,0,,and make sure that the result would go into the val register. Dialogue: 0,0:10:24.70,0:10:27.22,EN,,0,0,0,,And then you compile an instruction that says Dialogue: 0,0:10:27.22,0:10:33.79,EN,,0,0,0,,branch if, if val is true Dialogue: 0,0:10:37.17,0:10:38.75,EN,,0,0,0,,to a place we'll call label one. Dialogue: 0,0:10:44.97,0:10:47.52,EN,,0,0,0,,Then we, we will put the code for B Dialogue: 0,0:10:49.42,0:10:52.32,EN,,0,0,0,,to walk the interpreter--walk the interpreter over B. Dialogue: 0,0:10:53.62,0:10:57.21,EN,,0,0,0,,And then go to put in an instruction that says, Dialogue: 0,0:10:57.23,0:10:58.75,EN,,0,0,0,,go to the next thing, whatever Dialogue: 0,0:11:02.20,0:11:04.56,EN,,0,0,0,,whatever was supposed to happen after this thing was done. Dialogue: 0,0:11:04.95,0:11:06.09,EN,,0,0,0,,You put in that instruction. Dialogue: 0,0:11:06.88,0:11:08.62,EN,,0,0,0,,And here you put label one. Dialogue: 0,0:11:12.12,0:11:13.80,EN,,0,0,0,,And here you put the code for A. Dialogue: 0,0:11:19.47,0:11:25.85,EN,,0,0,0,,And you put go to next thing. Dialogue: 0,0:11:31.42,0:11:32.88,EN,,0,0,0,,So that's how you treat a conditional. Dialogue: 0,0:11:32.98,0:11:34.65,EN,,0,0,0,,You generate a little block like that. Dialogue: 0,0:11:35.75,0:11:38.12,EN,,0,0,0,,And other than that Dialogue: 0,0:11:38.95,0:11:41.55,EN,,0,0,0,,this zeroth-order compiler is the same as the evaluator. Dialogue: 0,0:11:42.55,0:11:45.12,EN,,0,0,0,,It's just stashing away the instructions instead of executing them. Dialogue: 0,0:11:46.55,0:11:47.60,EN,,0,0,0,,That seems pretty simple, Dialogue: 0,0:11:47.64,0:11:49.08,EN,,0,0,0,,but we've gained something by that. Dialogue: 0,0:11:50.12,0:11:52.62,EN,,0,0,0,,See, already that's going to be more efficient than the evaluator. Dialogue: 0,0:11:53.52,0:11:56.14,EN,,0,0,0,,Because, if you watch the evaluator run Dialogue: 0,0:11:56.35,0:12:01.05,EN,,0,0,0,,it's not only generating the register operations we wrote down Dialogue: 0,0:12:01.27,0:12:03.50,EN,,0,0,0,,it's also doing things to decide which ones to generate. Dialogue: 0,0:12:04.70,0:12:07.23,EN,,0,0,0,,So the very first thing it does, say here Dialogue: 0,0:12:07.92,0:12:09.77,EN,,0,0,0,,here for instance, is go do some tests Dialogue: 0,0:12:09.77,0:12:11.56,EN,,0,0,0,,and decide that this is an application Dialogue: 0,0:12:13.57,0:12:15.05,EN,,0,0,0,,and then branch off to the place that, Dialogue: 0,0:12:15.39,0:12:16.62,EN,,0,0,0,,that handles applications. Dialogue: 0,0:12:16.62,0:12:18.44,EN,,0,0,0,,In other words, what the evaluator's doing Dialogue: 0,0:12:18.62,0:12:22.76,EN,,0,0,0,,is simultaneously analyzing the code to see what to do Dialogue: 0,0:12:23.47,0:12:24.99,EN,,0,0,0,,and running these operations. Dialogue: 0,0:12:25.55,0:12:28.28,EN,,0,0,0,,And when you-- if you run the evaluator a million times Dialogue: 0,0:12:28.28,0:12:30.30,EN,,0,0,0,,that analysis phase happens a million times Dialogue: 0,0:12:30.85,0:12:32.58,EN,,0,0,0,,whereas in the compiler, it's happened once Dialogue: 0,0:12:32.58,0:12:34.81,EN,,0,0,0,,and then you just have the register operations themselves. Dialogue: 0,0:12:39.20,0:12:41.68,EN,,0,0,0,,Ok, that's a, a zeroth-order compiler Dialogue: 0,0:12:41.80,0:12:44.04,EN,,0,0,0,,but it is a wretched, wretched compiler. Dialogue: 0,0:12:44.45,0:12:45.28,EN,,0,0,0,,It's really dumb. Dialogue: 0,0:12:46.90,0:12:48.41,EN,,0,0,0,,Let's--let's go back and, Dialogue: 0,0:12:49.88,0:12:50.97,EN,,0,0,0,,and look at this overhead. Dialogue: 0,0:12:52.02,0:12:55.29,EN,,0,0,0,,So look at look at some of the operations this thing is doing. Dialogue: 0,0:12:55.85,0:12:56.88,EN,,0,0,0,,We're supposedly Dialogue: 0,0:12:59.72,0:13:02.28,EN,,0,0,0,,looking at the operations in interpreting f of x. Dialogue: 0,0:13:03.52,0:13:04.84,EN,,0,0,0,,Now, look here what it's doing. Dialogue: 0,0:13:05.17,0:13:06.11,EN,,0,0,0,,For example, here Dialogue: 0,0:13:07.15,0:13:11.98,EN,,0,0,0,,it assigns to exp the operator in fetch of exp. Dialogue: 0,0:13:13.75,0:13:15.87,EN,,0,0,0,,But see, there's no reason to do that, because this is-- Dialogue: 0,0:13:16.22,0:13:17.47,EN,,0,0,0,,the compiler knows Dialogue: 0,0:13:17.66,0:13:21.84,EN,,0,0,0,,that the operator, fetch of exp, is f right here. Dialogue: 0,0:13:23.35,0:13:25.56,EN,,0,0,0,,So there's no reason why this instruction should say that. Dialogue: 0,0:13:25.70,0:13:28.88,EN,,0,0,0,,It should say, we'll assign to exp, f. Dialogue: 0,0:13:29.45,0:13:31.08,EN,,0,0,0,,Or in fact, you don't need exp at all. Dialogue: 0,0:13:31.87,0:13:33.56,EN,,0,0,0,,There's no reason it should have exp at all. Dialogue: 0,0:13:33.56,0:13:35.16,EN,,0,0,0,,What, what did exp get used for? Dialogue: 0,0:13:35.18,0:13:36.33,EN,,0,0,0,,Well, if we come down here Dialogue: 0,0:13:40.77,0:13:42.20,EN,,0,0,0,,we're going to assign to val Dialogue: 0,0:13:43.05,0:13:47.34,EN,,0,0,0,,look up the stuff in exp in the environment. Dialogue: 0,0:13:48.68,0:13:49.53,EN,,0,0,0,,So what we really should do Dialogue: 0,0:13:49.55,0:13:51.54,EN,,0,0,0,,get rid of the exp register altogether Dialogue: 0,0:13:51.54,0:13:53.32,EN,,0,0,0,,and just change this instruction to say, Dialogue: 0,0:13:53.34,0:13:54.16,EN,,0,0,0,,assign to val Dialogue: 0,0:13:54.45,0:13:56.06,EN,,0,0,0,,look up the variable value Dialogue: 0,0:13:56.36,0:13:58.40,EN,,0,0,0,,of the symbol f in the environment. Dialogue: 0,0:14:01.09,0:14:01.77,EN,,0,0,0,,Similarly Dialogue: 0,0:14:02.57,0:14:04.27,EN,,0,0,0,,back up here, we don't need unev at all Dialogue: 0,0:14:04.72,0:14:05.79,EN,,0,0,0,,because we know Dialogue: 0,0:14:06.22,0:14:09.16,EN,,0,0,0,,what the operands of fetch of exp are for this piece of code. Dialogue: 0,0:14:09.16,0:14:10.62,EN,,0,0,0,,It's the, it's the list x. Dialogue: 0,0:14:13.25,0:14:14.06,EN,,0,0,0,,So in some sense Dialogue: 0,0:14:16.17,0:14:19.39,EN,,0,0,0,,you don't want unev and exp at all. Dialogue: 0,0:14:19.67,0:14:21.05,EN,,0,0,0,,See, what they really are in some sense, Dialogue: 0,0:14:21.08,0:14:25.30,EN,,0,0,0,,those aren't registers of the actual machine that's supposed to run. Dialogue: 0,0:14:25.30,0:14:26.40,EN,,0,0,0,,Those are registers Dialogue: 0,0:14:26.60,0:14:29.50,EN,,0,0,0,,that have to do with arranging the thing that can simulate that machine. Dialogue: 0,0:14:30.72,0:14:33.77,EN,,0,0,0,,So they're always going to hold expressions Dialogue: 0,0:14:34.00,0:14:36.04,EN,,0,0,0,,which from the compiler's point of view, Dialogue: 0,0:14:36.06,0:14:36.81,EN,,0,0,0,,are just constants, Dialogue: 0,0:14:36.95,0:14:38.48,EN,,0,0,0,,so can be put right into the code. Dialogue: 0,0:14:39.47,0:14:41.34,EN,,0,0,0,,So you can forget about all the operations Dialogue: 0,0:14:41.36,0:14:42.54,EN,,0,0,0,,worrying about exp and unev Dialogue: 0,0:14:42.57,0:14:43.77,EN,,0,0,0,,and just use those constants. Dialogue: 0,0:14:44.02,0:14:48.00,EN,,0,0,0,,Similarly, again, if we go, go back and look here Dialogue: 0,0:14:48.00,0:14:51.32,EN,,0,0,0,,there are things like assign to continue eval-args. Dialogue: 0,0:14:53.75,0:14:55.39,EN,,0,0,0,,Now, that has nothing to do with anything. Dialogue: 0,0:14:55.62,0:14:57.76,EN,,0,0,0,,That was just the evaluator Dialogue: 0,0:14:58.08,0:15:00.17,EN,,0,0,0,,keeping track of where it should go next Dialogue: 0,0:15:02.70,0:15:05.96,EN,,0,0,0,,to evaluate the arguments in some, in some application. Dialogue: 0,0:15:06.82,0:15:08.65,EN,,0,0,0,,But of course, that's irrelevant to the compiler, Dialogue: 0,0:15:08.65,0:15:13.88,EN,,0,0,0,,because you-- the analysis phase will have already done that. Dialogue: 0,0:15:15.05,0:15:16.83,EN,,0,0,0,,So this is completely irrelevant. Dialogue: 0,0:15:17.70,0:15:19.32,EN,,0,0,0,,So a lot of these, these assignments Dialogue: 0,0:15:19.32,0:15:21.30,EN,,0,0,0,,to continue have not to do Dialogue: 0,0:15:21.30,0:15:24.62,EN,,0,0,0,,where the running machine is supposed to continue Dialogue: 0,0:15:24.64,0:15:25.77,EN,,0,0,0,,in keeping track of its state. Dialogue: 0,0:15:26.07,0:15:28.72,EN,,0,0,0,,It has to, to do with where the evaluator analysis should continue Dialogue: 0,0:15:28.72,0:15:30.03,EN,,0,0,0,,and those are completely irrelevant. Dialogue: 0,0:15:30.06,0:15:31.23,EN,,0,0,0,,So we can get rid of them. Dialogue: 0,0:15:43.90,0:15:45.98,EN,,0,0,0,,Ok, well, if we, if we simply do that, Dialogue: 0,0:15:46.16,0:15:47.75,EN,,0,0,0,,make those kinds of optimizations Dialogue: 0,0:15:47.75,0:15:51.64,EN,,0,0,0,,get rid, get rid of worrying about exp and unev Dialogue: 0,0:15:51.75,0:15:56.22,EN,,0,0,0,,and get rid of these irrelevant register assignments to continue Dialogue: 0,0:15:57.25,0:15:59.96,EN,,0,0,0,,then we can take this literal code Dialogue: 0,0:16:01.48,0:16:06.20,EN,,0,0,0,,these sort of 19 instructions that the evaluator would have done Dialogue: 0,0:16:06.91,0:16:08.12,EN,,0,0,0,,and then replace them. Dialogue: 0,0:16:08.36,0:16:10.33,EN,,0,0,0,,Let's look at the, at the slide. Dialogue: 0,0:16:12.27,0:16:15.34,EN,,0,0,0,,Replace them by--we get rid of about half of them. Dialogue: 0,0:16:18.28,0:16:20.75,EN,,0,0,0,,And again, this is just sort of filtering Dialogue: 0,0:16:21.07,0:16:24.46,EN,,0,0,0,,what the evaluator would have done by getting rid of the irrelevant stuff. Dialogue: 0,0:16:25.17,0:16:26.22,EN,,0,0,0,,And you see, for instance Dialogue: 0,0:16:27.47,0:16:29.66,EN,,0,0,0,,here the--where the evaluator said, Dialogue: 0,0:16:29.68,0:16:32.43,EN,,0,0,0,,assign val, look up variable value, fetch of exp Dialogue: 0,0:16:32.46,0:16:34.22,EN,,0,0,0,,here we have put in the constant f. Dialogue: 0,0:16:35.44,0:16:37.02,EN,,0,0,0,,Here we've put in the constant x. Dialogue: 0,0:16:40.02,0:16:42.41,EN,,0,0,0,,So there's a, there's a little better compiler. Dialogue: 0,0:16:43.79,0:16:46.76,EN,,0,0,0,,It's still pretty dumb. Dialogue: 0,0:16:47.95,0:16:49.58,EN,,0,0,0,,It's still doing a lot of dumb things. Dialogue: 0,0:16:50.45,0:16:52.52,EN,,0,0,0,,Again, if we go look at the slide again Dialogue: 0,0:16:52.88,0:16:53.93,EN,,0,0,0,,look at the very beginning here Dialogue: 0,0:16:56.34,0:16:58.17,EN,,0,0,0,,we see a save the environment Dialogue: 0,0:16:59.35,0:17:01.72,EN,,0,0,0,,assign something to the val register Dialogue: 0,0:17:01.80,0:17:03.35,EN,,0,0,0,,and restore the environment. Dialogue: 0,0:17:03.35,0:17:04.41,EN,,0,0,0,,Where'd that come from? Dialogue: 0,0:17:04.91,0:17:07.10,EN,,0,0,0,,That came from the evaluator back here saying Dialogue: 0,0:17:07.15,0:17:10.28,EN,,0,0,0,,oh, I'm in the middle of evaluating an application. Dialogue: 0,0:17:11.10,0:17:14.68,EN,,0,0,0,,So I'm going to recursively call eval dispatch. Dialogue: 0,0:17:15.87,0:17:17.98,EN,,0,0,0,,So I'd better save the thing I'm going to need later, Dialogue: 0,0:17:17.98,0:17:19.08,EN,,0,0,0,,which is the environment. Dialogue: 0,0:17:19.77,0:17:22.86,EN,,0,0,0,,This was the result of recursively calling eval dispatch. Dialogue: 0,0:17:23.47,0:17:25.77,EN,,0,0,0,,It was evaluating the symbol f in that case. Dialogue: 0,0:17:26.50,0:17:28.27,EN,,0,0,0,,Then it came back from eval dispatch, Dialogue: 0,0:17:28.28,0:17:29.66,EN,,0,0,0,,restored the environment. Dialogue: 0,0:17:31.25,0:17:32.28,EN,,0,0,0,,But in fact, Dialogue: 0,0:17:32.59,0:17:35.88,EN,,0,0,0,,the actual thing it ended up doing in the evaluation Dialogue: 0,0:17:35.92,0:17:37.71,EN,,0,0,0,,is not going to hurt the environment at all. Dialogue: 0,0:17:38.67,0:17:40.80,EN,,0,0,0,,So there's no reason to be saving the environment Dialogue: 0,0:17:40.84,0:17:42.22,EN,,0,0,0,,and restoring the environment here. Dialogue: 0,0:17:45.67,0:17:46.62,EN,,0,0,0,,Similarly Dialogue: 0,0:17:49.79,0:17:51.39,EN,,0,0,0,,here I'm saving the argument list. Dialogue: 0,0:17:53.07,0:17:55.80,EN,,0,0,0,,That's a piece of the argument evaluation loop, Dialogue: 0,0:17:55.82,0:17:56.86,EN,,0,0,0,,saving the argument list Dialogue: 0,0:17:57.20,0:17:58.03,EN,,0,0,0,,and here you restore it. Dialogue: 0,0:17:58.08,0:18:00.51,EN,,0,0,0,,But the actual thing that you ended up doing Dialogue: 0,0:18:00.80,0:18:02.28,EN,,0,0,0,,didn't trash the argument list. Dialogue: 0,0:18:02.84,0:18:04.17,EN,,0,0,0,,So there was no reason to save it. Dialogue: 0,0:18:08.65,0:18:12.88,EN,,0,0,0,,So another way to say, another way to say that Dialogue: 0,0:18:13.77,0:18:14.80,EN,,0,0,0,,is that the, Dialogue: 0,0:18:16.43,0:18:19.13,EN,,0,0,0,,the evaluator has to be maximally pessimistic Dialogue: 0,0:18:19.87,0:18:21.07,EN,,0,0,0,,because as far from its point of view Dialogue: 0,0:18:21.08,0:18:23.06,EN,,0,0,0,,it's just going off to evaluate something. Dialogue: 0,0:18:23.24,0:18:24.97,EN,,0,0,0,,So it better save what it's going to need later. Dialogue: 0,0:18:26.12,0:18:27.79,EN,,0,0,0,,But once you've done the analysis, Dialogue: 0,0:18:27.82,0:18:29.68,EN,,0,0,0,,the compiler is in a position to say Dialogue: 0,0:18:29.72,0:18:31.47,EN,,0,0,0,,well, what actually did I need to save? Dialogue: 0,0:18:32.12,0:18:33.31,EN,,0,0,0,,And doesn't need to do any-- Dialogue: 0,0:18:33.42,0:18:37.30,EN,,0,0,0,,it doesn't need to be as careful as the evaluator Dialogue: 0,0:18:37.30,0:18:38.80,EN,,0,0,0,,because it knows what it actually needs Dialogue: 0,0:18:39.69,0:18:41.16,EN,,0,0,0,,Well, in any case, if we do that Dialogue: 0,0:18:42.50,0:18:45.71,EN,,0,0,0,,and eliminate all those redundant saves and restores Dialogue: 0,0:18:46.40,0:18:49.05,EN,,0,0,0,,then we can get it down to this. Dialogue: 0,0:18:49.90,0:18:51.53,EN,,0,0,0,,And you see there are actually only three Dialogue: 0,0:18:51.64,0:18:53.71,EN,,0,0,0,,only three instructions that we actually need Dialogue: 0,0:18:54.07,0:18:55.72,EN,,0,0,0,,down from the initial 11 or so Dialogue: 0,0:18:55.97,0:18:58.81,EN,,0,0,0,,or the initial 20 or so in the original one. Dialogue: 0,0:18:59.87,0:19:00.92,EN,,0,0,0,,And that's just saying, Dialogue: 0,0:19:01.12,0:19:03.18,EN,,0,0,0,,of those register operations Dialogue: 0,0:19:03.27,0:19:04.94,EN,,0,0,0,,which ones did we actually need? Dialogue: 0,0:19:09.42,0:19:11.74,EN,,0,0,0,,Let me just sort of summarize that in another way, Dialogue: 0,0:19:11.74,0:19:13.48,EN,,0,0,0,,just to show you in a little better picture. Dialogue: 0,0:19:16.00,0:19:17.52,EN,,0,0,0,,Here's a picture of starting-- Dialogue: 0,0:19:18.77,0:19:20.81,EN,,0,0,0,,This is looking at all the saves and restores. Dialogue: 0,0:19:23.50,0:19:25.23,EN,,0,0,0,,So here's the expression, f of x Dialogue: 0,0:19:25.32,0:19:27.87,EN,,0,0,0,,and then this traces through, on the bottom here Dialogue: 0,0:19:28.75,0:19:31.80,EN,,0,0,0,,the various places in the evaluator Dialogue: 0,0:19:34.97,0:19:38.04,EN,,0,0,0,,that were passed when the evaluation happened. Dialogue: 0,0:19:38.04,0:19:40.01,EN,,0,0,0,,And then here, here you see arrows. Dialogue: 0,0:19:40.22,0:19:42.08,EN,,0,0,0,,Arrow down means register saved. Dialogue: 0,0:19:42.40,0:19:44.84,EN,,0,0,0,,So the first thing that happened is the environment got saved. Dialogue: 0,0:19:46.82,0:19:48.68,EN,,0,0,0,,And over here, the environment got restored. Dialogue: 0,0:19:52.38,0:19:54.54,EN,,0,0,0,,so there are all the pairs of stack operations. Dialogue: 0,0:19:56.12,0:19:57.56,EN,,0,0,0,,Now, if you go ahead and say Dialogue: 0,0:19:58.12,0:20:00.78,EN,,0,0,0,,well, let's remember that we don't--that unev Dialogue: 0,0:20:00.89,0:20:03.02,EN,,0,0,0,,for instance, is a completely useless register. Dialogue: 0,0:20:07.80,0:20:09.78,EN,,0,0,0,,And if we use the constant structure of the code Dialogue: 0,0:20:09.78,0:20:12.52,EN,,0,0,0,,well, we don't need, we don't need to save unev. Dialogue: 0,0:20:16.20,0:20:19.15,EN,,0,0,0,,And then, depending on how we set up the discipline of the-- Dialogue: 0,0:20:19.16,0:20:21.88,EN,,0,0,0,,of calling other things that apply, Dialogue: 0,0:20:21.88,0:20:23.85,EN,,0,0,0,,we may or may not need to save continue. Dialogue: 0,0:20:27.40,0:20:28.74,EN,,0,0,0,,That's the first step I did. Dialogue: 0,0:20:28.74,0:20:30.51,EN,,0,0,0,,And then we can look and see what's actually, Dialogue: 0,0:20:31.71,0:20:32.70,EN,,0,0,0,,what's actually needed. Dialogue: 0,0:20:33.07,0:20:35.56,EN,,0,0,0,,See, we don't-- didn't really need to save env Dialogue: 0,0:20:36.04,0:20:37.82,EN,,0,0,0,,across-evaluating f Dialogue: 0,0:20:38.08,0:20:39.92,EN,,0,0,0,,because it wouldn't, it wouldn't trash it. Dialogue: 0,0:20:39.92,0:20:41.31,EN,,0,0,0,,So if we take advantage of that Dialogue: 0,0:20:44.12,0:20:47.56,EN,,0,0,0,,and see the evaluation of f here Dialogue: 0,0:20:48.57,0:20:50.44,EN,,0,0,0,,doesn't really need to worry about, Dialogue: 0,0:20:51.61,0:20:52.60,EN,,0,0,0,,about hurting env. Dialogue: 0,0:20:52.60,0:20:54.94,EN,,0,0,0,,And similarly, the evaluation of x here Dialogue: 0,0:20:57.17,0:20:58.89,EN,,0,0,0,,when the evaluator did that it said Dialogue: 0,0:20:58.91,0:21:01.64,EN,,0,0,0,,Oh, I'd better preserve the function register around that Dialogue: 0,0:21:02.07,0:21:03.22,EN,,0,0,0,,because I might need it later. Dialogue: 0,0:21:03.28,0:21:04.89,EN,,0,0,0,,And I better preserve the argument list. Dialogue: 0,0:21:06.90,0:21:09.05,EN,,0,0,0,,Whereas the compiler is now in a position to know Dialogue: 0,0:21:09.05,0:21:10.38,EN,,0,0,0,,well, we didn't really need to save-- Dialogue: 0,0:21:10.52,0:21:11.84,EN,,0,0,0,,to do those saves and restores. Dialogue: 0,0:21:12.70,0:21:16.09,EN,,0,0,0,,So in fact, all of the stack operations done by the evaluator Dialogue: 0,0:21:16.32,0:21:19.58,EN,,0,0,0,,turned out to be unnecessary or overly pessimistic. Dialogue: 0,0:21:19.62,0:21:21.45,EN,,0,0,0,,And the compiler is in a position to know that. Dialogue: 0,0:21:27.35,0:21:28.48,EN,,0,0,0,,Well that's the basic idea. Dialogue: 0,0:21:29.80,0:21:31.00,EN,,0,0,0,,We take the evaluator Dialogue: 0,0:21:31.00,0:21:33.24,EN,,0,0,0,,we eliminate the things that you don't need Dialogue: 0,0:21:33.24,0:21:35.24,EN,,0,0,0,,that in some sense have nothing to do with the compiler at all Dialogue: 0,0:21:35.24,0:21:36.19,EN,,0,0,0,,just the evaluator Dialogue: 0,0:21:37.40,0:21:40.40,EN,,0,0,0,,and then you see which stack operations are unnecessary. Dialogue: 0,0:21:40.82,0:21:43.76,EN,,0,0,0,,That's the basic structure of the compiler that's Dialogue: 0,0:21:43.85,0:21:45.04,EN,,0,0,0,,that's described in the book. Dialogue: 0,0:21:45.04,0:21:47.00,EN,,0,0,0,,Let me just show you how a Dialogue: 0,0:21:47.76,0:21:49.68,EN,,0,0,0,,that examples a little bit too simple. Dialogue: 0,0:21:51.20,0:21:53.26,EN,,0,0,0,,To see how you, how you actually save a lot Dialogue: 0,0:21:53.29,0:21:56.06,EN,,0,0,0,,let's look at a little bit more complicated expression. Dialogue: 0,0:21:58.15,0:22:01.93,EN,,0,0,0,,(F (G X) 1) Dialogue: 0,0:22:03.87,0:22:05.52,EN,,0,0,0,,And I'm not going to go through all the code. Dialogue: 0,0:22:06.40,0:22:08.56,EN,,0,0,0,,There's a, there's a fair pile of it. Dialogue: 0,0:22:09.72,0:22:12.35,EN,,0,0,0,,I think there are, there are something like 16 Dialogue: 0,0:22:12.35,0:22:14.67,EN,,0,0,0,,16 pairs of register saves and restores Dialogue: 0,0:22:14.70,0:22:16.25,EN,,0,0,0,,as the evaluator walks through that. Dialogue: 0,0:22:17.00,0:22:18.57,EN,,0,0,0,,Here's a diagram of them. Dialogue: 0,0:22:20.57,0:22:21.95,EN,,0,0,0,,Let's see. You see what's going on. Dialogue: 0,0:22:22.97,0:22:23.90,EN,,0,0,0,,You start out by-- Dialogue: 0,0:22:24.25,0:22:26.62,EN,,0,0,0,,the evaluator says, oh, I'm about to do an application. Dialogue: 0,0:22:26.90,0:22:29.13,EN,,0,0,0,,I'll preserve the environment. I'll restore it here. Dialogue: 0,0:22:30.65,0:22:34.44,EN,,0,0,0,,Then I'm about to do the first operand. Dialogue: 0,0:22:36.81,0:22:39.28,EN,,0,0,0,,Here it recursively goes to the evaluator. Dialogue: 0,0:22:39.28,0:22:40.89,EN,,0,0,0,,The evaluator says, oh, this is an application, Dialogue: 0,0:22:40.91,0:22:42.10,EN,,0,0,0,,I'll save the environment Dialogue: 0,0:22:42.10,0:22:44.97,EN,,0,0,0,,do the operator of that combination, restore it here. Dialogue: 0,0:22:45.80,0:22:48.92,EN,,0,0,0,,This save--this restore matches that save. Dialogue: 0,0:22:49.77,0:22:50.78,EN,,0,0,0,,And so on. Dialogue: 0,0:22:51.65,0:22:52.51,EN,,0,0,0,,There's unev here, Dialogue: 0,0:22:52.52,0:22:54.62,EN,,0,0,0,,which turns out to be completely unnecessary Dialogue: 0,0:22:54.97,0:22:56.60,EN,,0,0,0,,continues getting bumped around here. Dialogue: 0,0:22:57.42,0:23:00.41,EN,,0,0,0,,The function register is getting, getting saved Dialogue: 0,0:23:00.78,0:23:04.36,EN,,0,0,0,,across the first operands, across the operands. Dialogue: 0,0:23:05.10,0:23:06.52,EN,,0,0,0,,All sorts of things are going on. Dialogue: 0,0:23:06.78,0:23:09.39,EN,,0,0,0,,But if you say, well, what of those really were the business of Dialogue: 0,0:23:09.87,0:23:11.66,EN,,0,0,0,,the compiler as opposed to the evaluator Dialogue: 0,0:23:12.27,0:23:13.55,EN,,0,0,0,,you get rid of a whole bunch. Dialogue: 0,0:23:14.30,0:23:16.64,EN,,0,0,0,,And then on top of that, if you say things like Dialogue: 0,0:23:19.40,0:23:22.54,EN,,0,0,0,,the evaluation of F doesn't hurt the environment register, Dialogue: 0,0:23:23.82,0:23:26.51,EN,,0,0,0,,or simply looking up the symbol X, Dialogue: 0,0:23:29.28,0:23:32.09,EN,,0,0,0,,you don't have to protect the function register against that. Dialogue: 0,0:23:34.30,0:23:37.60,EN,,0,0,0,,So you come down to just a couple of, a couple of pairs here. Dialogue: 0,0:23:40.25,0:23:42.27,EN,,0,0,0,,And still, you can do a little better. Dialogue: 0,0:23:42.27,0:23:44.33,EN,,0,0,0,,Look what's going on here with the environment register. Dialogue: 0,0:23:45.21,0:23:47.39,EN,,0,0,0,,The environment register comes along and says, oh, Dialogue: 0,0:23:51.00,0:23:52.25,EN,,0,0,0,,here's a combination. Dialogue: 0,0:23:54.33,0:23:55.69,EN,,0,0,0,,This evaluator, by the way, Dialogue: 0,0:23:55.78,0:23:57.27,EN,,0,0,0,,doesn't know anything about G. Dialogue: 0,0:23:58.57,0:24:00.73,EN,,0,0,0,,So here it says, so it says, Dialogue: 0,0:24:01.29,0:24:03.45,EN,,0,0,0,,I'd better save the environment register, Dialogue: 0,0:24:03.96,0:24:05.42,EN,,0,0,0,,because evaluating G might be Dialogue: 0,0:24:05.42,0:24:07.42,EN,,0,0,0,,some arbitrary piece of code that would trash it Dialogue: 0,0:24:07.55,0:24:09.45,EN,,0,0,0,,and I'm going to need it later, Dialogue: 0,0:24:10.17,0:24:11.40,EN,,0,0,0,,after this argument, Dialogue: 0,0:24:12.22,0:24:13.37,EN,,0,0,0,,for doing the second argument. Dialogue: 0,0:24:15.60,0:24:17.24,EN,,0,0,0,,So that's why this one didn't go away, Dialogue: 0,0:24:19.07,0:24:22.54,EN,,0,0,0,,because the compiler made no assumptions about what G would do. Dialogue: 0,0:24:22.54,0:24:23.60,EN,,0,0,0,,On the other hand, Dialogue: 0,0:24:24.61,0:24:26.52,EN,,0,0,0,,if you look at what the second argument is, Dialogue: 0,0:24:26.64,0:24:27.70,EN,,0,0,0,,that's just looking up one. Dialogue: 0,0:24:27.70,0:24:29.60,EN,,0,0,0,,That doesn't need this environment register. Dialogue: 0,0:24:30.77,0:24:32.04,EN,,0,0,0,,So there's no reason to save it. Dialogue: 0,0:24:32.06,0:24:33.77,EN,,0,0,0,,So in fact, you can get rid of that one, too. Dialogue: 0,0:24:34.85,0:24:37.81,EN,,0,0,0,,And from this whole pile of, of register operations, Dialogue: 0,0:24:37.98,0:24:40.08,EN,,0,0,0,,if you simply do a little bit of reasoning like that, Dialogue: 0,0:24:40.55,0:24:43.05,EN,,0,0,0,,you get down to, I think, just two pairs of saves and restores. Dialogue: 0,0:24:45.10,0:24:46.97,EN,,0,0,0,,And those, in fact, could go away further if you, Dialogue: 0,0:24:47.52,0:24:49.08,EN,,0,0,0,,if you knew something about G. Dialogue: 0,0:24:56.27,0:24:57.85,EN,,0,0,0,,So again, the general idea Dialogue: 0,0:24:57.95,0:24:59.98,EN,,0,0,0,,is that the reason the compiler can be better Dialogue: 0,0:24:59.98,0:25:02.56,EN,,0,0,0,,is that the interpreter doesn't know what it's about to encounter. Dialogue: 0,0:25:03.25,0:25:05.04,EN,,0,0,0,,It has to be maximally pessimistic Dialogue: 0,0:25:05.05,0:25:06.70,EN,,0,0,0,,to protect itself. Dialogue: 0,0:25:07.90,0:25:08.76,EN,,0,0,0,,The compiler Dialogue: 0,0:25:09.48,0:25:12.38,EN,,0,0,0,,only has to deal with what actually had to be saved. Dialogue: 0,0:25:13.37,0:25:15.20,EN,,0,0,0,,And there are two reasons that something Dialogue: 0,0:25:15.24,0:25:17.37,EN,,0,0,0,,might not have to be saved. Dialogue: 0,0:25:17.82,0:25:18.70,EN,,0,0,0,,One is that Dialogue: 0,0:25:18.70,0:25:19.82,EN,,0,0,0,,what you're protecting it against, Dialogue: 0,0:25:19.95,0:25:21.44,EN,,0,0,0,,in fact, didn't trash the register, Dialogue: 0,0:25:22.08,0:25:23.58,EN,,0,0,0,,like it was just a variable look-up. Dialogue: 0,0:25:24.12,0:25:25.20,EN,,0,0,0,,And the other one is, Dialogue: 0,0:25:25.32,0:25:27.10,EN,,0,0,0,,that the thing that you were saving it for Dialogue: 0,0:25:28.28,0:25:29.92,EN,,0,0,0,,might turn out not to actually need it. Dialogue: 0,0:25:30.81,0:25:34.27,EN,,0,0,0,,So those are the two basic pieces of knowledge Dialogue: 0,0:25:34.30,0:25:35.88,EN,,0,0,0,,that the compiler can take advantage of Dialogue: 0,0:25:36.27,0:25:37.76,EN,,0,0,0,,in making the code more efficient. Dialogue: 0,0:25:44.27,0:25:45.32,EN,,0,0,0,,Let's break for questions. Dialogue: 0,0:25:51.20,0:25:53.10,EN,,0,0,0,,AUDIENCE: You kept saying that the uneval register, Dialogue: 0,0:25:53.13,0:25:56.40,EN,,0,0,0,,unev register didn't need to be used at all. Dialogue: 0,0:25:56.41,0:25:58.68,EN,,0,0,0,,Does that mean that you could just map a six-register machine? Dialogue: 0,0:25:58.70,0:26:00.08,EN,,0,0,0,,Or is that, in this particular example, Dialogue: 0,0:26:00.11,0:26:01.18,EN,,0,0,0,,it didn't need to be used? Dialogue: 0,0:26:01.72,0:26:02.81,EN,,0,0,0,,PROFESSOR: For the compiler, Dialogue: 0,0:26:04.31,0:26:07.42,EN,,0,0,0,,you could generate code for the six-register, five, right? Dialogue: 0,0:26:07.56,0:26:09.02,EN,,0,0,0,,Because that exp goes away also. Dialogue: 0,0:26:09.40,0:26:14.57,EN,,0,0,0,,Assuming--yeah, you can get rid of both exp and unev Dialogue: 0,0:26:14.57,0:26:16.87,EN,,0,0,0,,because, see, those are data structures of the evaluator. Dialogue: 0,0:26:17.36,0:26:19.36,EN,,0,0,0,,Those are all things that would be constants Dialogue: 0,0:26:19.39,0:26:20.87,EN,,0,0,0,,from the point of view of the compiler. Dialogue: 0,0:26:21.65,0:26:22.44,EN,,0,0,0,,The only thing is Dialogue: 0,0:26:22.48,0:26:24.59,EN,,0,0,0,,this particular compiler is set up Dialogue: 0,0:26:24.79,0:26:27.92,EN,,0,0,0,,so that interpreted code and compiled code can coexist. Dialogue: 0,0:26:29.32,0:26:30.72,EN,,0,0,0,,So the way to think about it is, Dialogue: 0,0:26:30.97,0:26:32.29,EN,,0,0,0,,is maybe you build a chip Dialogue: 0,0:26:34.30,0:26:35.50,EN,,0,0,0,,which is the evaluator, Dialogue: 0,0:26:35.88,0:26:37.28,EN,,0,0,0,,and what the compiler might do Dialogue: 0,0:26:37.31,0:26:39.02,EN,,0,0,0,,is generate code for that chip. Dialogue: 0,0:26:40.40,0:26:41.90,EN,,0,0,0,,It just wouldn't use two of the registers. Dialogue: 0,0:26:51.52,0:26:52.47,EN,,0,0,0,,All right, let's take a break. Dialogue: 0,0:26:53.55,0:27:07.18,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:27:29.21,0:27:32.43,EN,,0,0,0,,We just looked at what the compiler is supposed to do. Dialogue: 0,0:27:32.78,0:27:36.04,EN,,0,0,0,,Now let's very briefly look at how, Dialogue: 0,0:27:36.15,0:27:37.47,EN,,0,0,0,,how this gets accomplished. Dialogue: 0,0:27:38.26,0:27:39.58,EN,,0,0,0,,And I'm going to give no details. Dialogue: 0,0:27:39.60,0:27:42.17,EN,,0,0,0,,There's, there's a giant pile of code in the book Dialogue: 0,0:27:42.22,0:27:43.42,EN,,0,0,0,,that gives all the details. Dialogue: 0,0:27:43.45,0:27:45.31,EN,,0,0,0,,But what I want to do is just show you the, Dialogue: 0,0:27:45.96,0:27:47.26,EN,,0,0,0,,the essential idea here. Dialogue: 0,0:27:49.49,0:27:51.36,EN,,0,0,0,,Worry about the details some other time. Dialogue: 0,0:27:51.51,0:27:55.30,EN,,0,0,0,,Let's imagine that we're compiling an expression Dialogue: 0,0:27:55.30,0:27:57.01,EN,,0,0,0,,that looks like there's some operator Dialogue: 0,0:27:57.48,0:27:58.56,EN,,0,0,0,,and there are two arguments. Dialogue: 0,0:28:03.56,0:28:04.24,EN,,0,0,0,,Now, the-- Dialogue: 0,0:28:06.27,0:28:08.14,EN,,0,0,0,,what's the code that the compiler should generate? Dialogue: 0,0:28:08.85,0:28:09.78,EN,,0,0,0,,Well, first of all, Dialogue: 0,0:28:09.83,0:28:11.20,EN,,0,0,0,,it should recursively go off Dialogue: 0,0:28:11.90,0:28:13.28,EN,,0,0,0,,and compile the operator. Dialogue: 0,0:28:14.37,0:28:19.02,EN,,0,0,0,,So it says, I'll compile the operator. Dialogue: 0,0:28:21.16,0:28:24.54,EN,,0,0,0,,And where I'm going to need that Dialogue: 0,0:28:24.84,0:28:27.95,EN,,0,0,0,,is to be in the function register, eventually. Dialogue: 0,0:28:28.42,0:28:29.60,EN,,0,0,0,,So I'll compile some instructions Dialogue: 0,0:28:29.64,0:28:31.56,EN,,0,0,0,,that will compile the operator Dialogue: 0,0:28:31.69,0:28:38.62,EN,,0,0,0,,and end up with the result in the function register. Dialogue: 0,0:28:45.51,0:28:46.94,EN,,0,0,0,,The next thing it's going to do, Dialogue: 0,0:28:47.71,0:28:49.68,EN,,0,0,0,,another piece is to say, Dialogue: 0,0:28:49.68,0:28:55.17,EN,,0,0,0,,I have to compile the first argument. Dialogue: 0,0:28:55.17,0:28:56.80,EN,,0,0,0,,So it calls itself recursively. Dialogue: 0,0:28:58.04,0:29:03.36,EN,,0,0,0,,And let's say the result will go into val. Dialogue: 0,0:29:09.07,0:29:10.75,EN,,0,0,0,,And then what it's going to need to do is Dialogue: 0,0:29:10.75,0:29:12.26,EN,,0,0,0,,start setting up the argument list. Dialogue: 0,0:29:12.95,0:29:25.50,EN,,0,0,0,,So it'll say, assign to argl cons of fetch-- Dialogue: 0,0:29:25.55,0:29:27.10,EN,,0,0,0,,so it generates this literal instruction-- Dialogue: 0,0:29:27.50,0:29:32.51,EN,,0,0,0,,fetch of val onto empty list. Dialogue: 0,0:29:35.00,0:29:36.05,EN,,0,0,0,,However, Dialogue: 0,0:29:37.99,0:29:40.61,EN,,0,0,0,,it might have to work-- when it gets here, Dialogue: 0,0:29:41.32,0:29:42.82,EN,,0,0,0,,it's going to need the environment. Dialogue: 0,0:29:43.95,0:29:45.29,EN,,0,0,0,,It's going to need whatever environment was here Dialogue: 0,0:29:45.32,0:29:48.21,EN,,0,0,0,,in order to do this evaluation of the first argument. Dialogue: 0,0:29:49.04,0:29:51.18,EN,,0,0,0,,So it has to ensure that Dialogue: 0,0:29:51.92,0:29:53.76,EN,,0,0,0,,the compilation of this operand, Dialogue: 0,0:29:55.32,0:29:57.85,EN,,0,0,0,,or it has to protect the function register Dialogue: 0,0:29:58.01,0:30:00.98,EN,,0,0,0,,against whatever might happen in the compilation of this operand. Dialogue: 0,0:30:01.30,0:30:03.08,EN,,0,0,0,,So it puts a note here and says, oh, Dialogue: 0,0:30:03.37,0:30:12.89,EN,,0,0,0,,this piece should be done preserving the environment register. Dialogue: 0,0:30:17.39,0:30:18.44,EN,,0,0,0,,Similarly, here, Dialogue: 0,0:30:21.02,0:30:23.30,EN,,0,0,0,,after it gets done compiling the first operand, Dialogue: 0,0:30:23.57,0:30:24.67,EN,,0,0,0,,it's going to say, I'd better-- Dialogue: 0,0:30:24.71,0:30:27.92,EN,,0,0,0,,I'm going to need to know the environment for the second operand. Dialogue: 0,0:30:27.92,0:30:29.46,EN,,0,0,0,,So it puts a little note here, saying, Dialogue: 0,0:30:29.71,0:30:35.96,EN,,0,0,0,,yeah, this is also done preserving env. Dialogue: 0,0:30:39.42,0:30:41.02,EN,,0,0,0,,Now it goes on and says, well, Dialogue: 0,0:30:41.12,0:30:42.83,EN,,0,0,0,,the next chunk of code Dialogue: 0,0:30:43.31,0:30:49.74,EN,,0,0,0,,is the one that's going to compile the second argument. Dialogue: 0,0:30:50.82,0:30:52.64,EN,,0,0,0,,And let's say Dialogue: 0,0:30:52.99,0:30:59.28,EN,,0,0,0,,And let's say it'll compile it with a targeted to val, as they say. Dialogue: 0,0:31:03.86,0:31:06.70,EN,,0,0,0,,And then it'll generate the literal instruction, Dialogue: 0,0:31:07.84,0:31:09.25,EN,,0,0,0,,building up the argument list. Dialogue: 0,0:31:09.55,0:31:15.28,EN,,0,0,0,,So it'll say, assign to argl Dialogue: 0,0:31:20.22,0:31:28.94,EN,,0,0,0,,cons of the new value it just got onto the old argument list. Dialogue: 0,0:31:33.97,0:31:34.64,EN,,0,0,0,,However, Dialogue: 0,0:31:34.81,0:31:36.58,EN,,0,0,0,,in order to have the old argument list, Dialogue: 0,0:31:37.15,0:31:40.99,EN,,0,0,0,,it better have arranged that the argument list didn't get trashed Dialogue: 0,0:31:41.30,0:31:42.69,EN,,0,0,0,,by whatever happened in here. Dialogue: 0,0:31:43.50,0:31:45.17,EN,,0,0,0,,So it puts a little note here and says, Dialogue: 0,0:31:45.34,0:31:51.64,EN,,0,0,0,,oh, this has to be done preserving argl. Dialogue: 0,0:31:54.16,0:31:56.03,EN,,0,0,0,,Now it's got the argument list set up. Dialogue: 0,0:31:58.01,0:32:02.86,EN,,0,0,0,,And it's all ready to go to apply dispatch. Dialogue: 0,0:32:07.02,0:32:10.80,EN,,0,0,0,,It generates this literal instruction. Dialogue: 0,0:32:15.19,0:32:17.37,EN,,0,0,0,,Because now it's got the arguments in argl Dialogue: 0,0:32:18.15,0:32:20.59,EN,,0,0,0,,and the operator in fun, Dialogue: 0,0:32:20.59,0:32:22.89,EN,,0,0,0,,but wait, it's only got the operator in fun Dialogue: 0,0:32:23.27,0:32:26.64,EN,,0,0,0,,if it had ensured that this block of code Dialogue: 0,0:32:27.09,0:32:29.27,EN,,0,0,0,,didn't trash what was in the function register. Dialogue: 0,0:32:29.67,0:32:31.24,EN,,0,0,0,,So it puts a little note here and says, Dialogue: 0,0:32:31.55,0:32:32.73,EN,,0,0,0,,oh, yes, all this stuff here Dialogue: 0,0:32:34.88,0:32:40.73,EN,,0,0,0,,had better be done preserving the function register. Dialogue: 0,0:32:43.71,0:32:46.15,EN,,0,0,0,,So that's the little--so when it starts ticking-- Dialogue: 0,0:32:46.15,0:32:47.10,EN,,0,0,0,,so basically, what the Dialogue: 0,0:32:48.20,0:32:50.24,EN,,0,0,0,,what the compiler does is Dialogue: 0,0:32:50.54,0:32:52.46,EN,,0,0,0,,append a whole bunch of code sequences. Dialogue: 0,0:32:53.50,0:32:58.83,EN,,0,0,0,,See, what it's got in it is little primitive pieces of things Dialogue: 0,0:32:58.86,0:33:00.12,EN,,0,0,0,,like how to look up a symbol, Dialogue: 0,0:33:01.44,0:33:02.60,EN,,0,0,0,,how to do a conditional. Dialogue: 0,0:33:02.64,0:33:05.44,EN,,0,0,0,,Those are all little pieces of things. Dialogue: 0,0:33:05.44,0:33:07.99,EN,,0,0,0,,And then it appends them together in this sort of discipline. Dialogue: 0,0:33:08.78,0:33:10.79,EN,,0,0,0,,So the basic means of combining things Dialogue: 0,0:33:10.86,0:33:13.18,EN,,0,0,0,,is to append two code sequences. Dialogue: 0,0:33:21.55,0:33:22.86,EN,,0,0,0,,That's what's going on here. Dialogue: 0,0:33:25.58,0:33:27.24,EN,,0,0,0,,And it's a little bit tricky. Dialogue: 0,0:33:27.56,0:33:30.37,EN,,0,0,0,,The idea is that it appends two code sequences, Dialogue: 0,0:33:31.60,0:33:33.76,EN,,0,0,0,,taking care to preserve a register. Dialogue: 0,0:33:35.63,0:33:37.93,EN,,0,0,0,,So the actual append operation looks like this. Dialogue: 0,0:33:39.15,0:33:40.65,EN,,0,0,0,,What it wants to do is say, if-- Dialogue: 0,0:33:41.20,0:33:44.11,EN,,0,0,0,,here's what it means to append two code sequences. Dialogue: 0,0:33:44.53,0:33:53.63,EN,,0,0,0,,So if sequence one needs register-- Dialogue: 0,0:33:53.66,0:33:54.72,EN,,0,0,0,,I should change this. Dialogue: 0,0:33:54.72,0:33:56.87,EN,,0,0,0,,Append sequence one to sequence two, Dialogue: 0,0:33:57.42,0:34:03.96,EN,,0,0,0,,preserving some register. Dialogue: 0,0:34:08.52,0:34:09.91,EN,,0,0,0,,Let me say, and. Dialogue: 0,0:34:11.36,0:34:13.03,EN,,0,0,0,,So it's clear that sequence one comes first. Dialogue: 0,0:34:13.88,0:34:19.87,EN,,0,0,0,,So if sequence two needs the register Dialogue: 0,0:34:21.12,0:34:27.85,EN,,0,0,0,,and sequence one modifies the register, Dialogue: 0,0:34:33.68,0:34:36.30,EN,,0,0,0,,then the instructions that the compiler spits out, Dialogue: 0,0:34:36.97,0:34:41.34,EN,,0,0,0,,are save the register. Dialogue: 0,0:34:43.02,0:34:44.19,EN,,0,0,0,,Here's the code. Dialogue: 0,0:34:44.35,0:34:45.35,EN,,0,0,0,,You generate this code. Dialogue: 0,0:34:45.35,0:34:46.28,EN,,0,0,0,,Save the register, Dialogue: 0,0:34:46.72,0:34:52.97,EN,,0,0,0,,and then you put out the recursively compiled stuff for sequence one. Dialogue: 0,0:34:53.30,0:34:54.84,EN,,0,0,0,,And then you restore the register. Dialogue: 0,0:35:00.52,0:35:03.92,EN,,0,0,0,,And then you put out the recursively compiled stuff Dialogue: 0,0:35:04.46,0:35:05.47,EN,,0,0,0,,for sequence two. Dialogue: 0,0:35:07.07,0:35:09.62,EN,,0,0,0,,That's in the case where you need to do it. Dialogue: 0,0:35:09.62,0:35:11.82,EN,,0,0,0,,Sequence two actually needs the register, Dialogue: 0,0:35:11.82,0:35:13.74,EN,,0,0,0,,and sequence one actually clobbers it. Dialogue: 0,0:35:15.12,0:35:17.07,EN,,0,0,0,,So that's sort of if. Otherwise, Dialogue: 0,0:35:20.50,0:35:26.57,EN,,0,0,0,,all you spit out is sequence one followed by sequence two. Dialogue: 0,0:35:28.17,0:35:30.30,EN,,0,0,0,,So that's the basic operation Dialogue: 0,0:35:30.59,0:35:33.52,EN,,0,0,0,,for sticking together these bits of code fragments, Dialogue: 0,0:35:33.93,0:35:35.93,EN,,0,0,0,,these bits of instructions into a sequence. Dialogue: 0,0:35:36.89,0:35:38.87,EN,,0,0,0,,And you see, from this point of view, Dialogue: 0,0:35:40.94,0:35:45.96,EN,,0,0,0,,the difference between the interpreter and the compiler, in some sense, Dialogue: 0,0:35:46.82,0:35:49.34,EN,,0,0,0,,is that where the compiler has these preserving notes, Dialogue: 0,0:35:50.14,0:35:52.22,EN,,0,0,0,,and says, maybe I'll actually generate the Dialogue: 0,0:35:52.49,0:35:54.22,EN,,0,0,0,,saves and restores and maybe I won't, Dialogue: 0,0:35:55.19,0:35:57.24,EN,,0,0,0,,the interpreter being maximally pessimistic Dialogue: 0,0:35:57.28,0:35:58.90,EN,,0,0,0,,always has a save and restore here. Dialogue: 0,0:36:00.76,0:36:01.93,EN,,0,0,0,,That's the essential difference. Dialogue: 0,0:36:04.16,0:36:06.05,EN,,0,0,0,,Well, in order to do this, of course, Dialogue: 0,0:36:06.65,0:36:09.40,EN,,0,0,0,,the compiler needs some theory of Dialogue: 0,0:36:09.56,0:36:11.96,EN,,0,0,0,,what code sequences need and modifier registers. Dialogue: 0,0:36:14.26,0:36:17.28,EN,,0,0,0,,So the tiny little fragments that you put in, like Dialogue: 0,0:36:17.48,0:36:21.00,EN,,0,0,0,,the basic primitive code fragments, Dialogue: 0,0:36:22.74,0:36:24.59,EN,,0,0,0,,say, what are the operations that you do Dialogue: 0,0:36:24.92,0:36:26.04,EN,,0,0,0,,when you look up a variable? Dialogue: 0,0:36:26.89,0:36:29.02,EN,,0,0,0,,What are the sequence of things that you do Dialogue: 0,0:36:29.05,0:36:30.68,EN,,0,0,0,,when you compile a constant Dialogue: 0,0:36:30.97,0:36:32.10,EN,,0,0,0,,or apply a function? Dialogue: 0,0:36:32.97,0:36:34.48,EN,,0,0,0,,Those have little notations in there Dialogue: 0,0:36:34.67,0:36:36.46,EN,,0,0,0,,about what they need and what they modify. Dialogue: 0,0:36:38.78,0:36:41.50,EN,,0,0,0,,So the bottom-level data structures-- Dialogue: 0,0:36:42.66,0:36:44.33,EN,,0,0,0,,Well, I'll say this. Dialogue: 0,0:36:44.39,0:36:47.91,EN,,0,0,0,,A code sequence to the compiler looks like this. Dialogue: 0,0:36:48.07,0:36:51.42,EN,,0,0,0,,It has the actual sequence of instructions. Dialogue: 0,0:36:55.67,0:36:56.81,EN,,0,0,0,,And then, along with it, Dialogue: 0,0:36:57.18,0:37:02.60,EN,,0,0,0,,there's the set of registers modified. Dialogue: 0,0:37:10.54,0:37:12.60,EN,,0,0,0,,And then there's the set of registers needed. Dialogue: 0,0:37:20.00,0:37:22.46,EN,,0,0,0,,So that's the information the compiler has Dialogue: 0,0:37:23.00,0:37:26.41,EN,,0,0,0,,that it draws on in order to be able to do this operation. Dialogue: 0,0:37:29.30,0:37:31.08,EN,,0,0,0,,And where do those come from? Well. Dialogue: 0,0:37:32.91,0:37:34.49,EN,,0,0,0,,Well, those come from, you might expect, Dialogue: 0,0:37:34.51,0:37:35.53,EN,,0,0,0,,for the very primitive ones, Dialogue: 0,0:37:35.55,0:37:36.84,EN,,0,0,0,,we're going to put them in by hand. Dialogue: 0,0:37:37.24,0:37:38.86,EN,,0,0,0,,And then, when we combine two sequences, Dialogue: 0,0:37:38.89,0:37:41.02,EN,,0,0,0,,we'll figure out what these things should be. Dialogue: 0,0:37:42.16,0:37:44.12,EN,,0,0,0,,So for example, a very primitive one, let's see. Dialogue: 0,0:37:48.43,0:37:51.40,EN,,0,0,0,,How about doing a register assignment. Dialogue: 0,0:37:51.77,0:37:53.50,EN,,0,0,0,,So a primitive sequence might say, Dialogue: 0,0:37:53.52,0:37:56.22,EN,,0,0,0,,oh, it's code fragment. Dialogue: 0,0:37:56.22,0:38:03.17,EN,,0,0,0,,Its code instruction is assigned to R1, fetch of R2. Dialogue: 0,0:38:03.17,0:38:04.27,EN,,0,0,0,,So this is an example. Dialogue: 0,0:38:05.42,0:38:08.52,EN,,0,0,0,,That might be an example of a sequence of instructions. Dialogue: 0,0:38:08.77,0:38:10.53,EN,,0,0,0,,And along with that, it'll say, Oh Dialogue: 0,0:38:10.64,0:38:15.76,EN,,0,0,0,,oh, what I need to remember is that that modifies R1 Dialogue: 0,0:38:18.60,0:38:21.16,EN,,0,0,0,,and then it needs R2. Dialogue: 0,0:38:24.69,0:38:26.99,EN,,0,0,0,,So when you're first building this compiler, Dialogue: 0,0:38:27.10,0:38:29.35,EN,,0,0,0,,you put in little fragments of stuff like that. Dialogue: 0,0:38:30.95,0:38:33.20,EN,,0,0,0,,And now, when it combines two sequences, Dialogue: 0,0:38:36.70,0:38:38.04,EN,,0,0,0,,if I'm going to combine, Dialogue: 0,0:38:38.92,0:38:41.58,EN,,0,0,0,,let's say, sequence one, Dialogue: 0,0:38:42.88,0:38:47.16,EN,,0,0,0,,that modifies a bunch of registers M1, Dialogue: 0,0:38:48.45,0:38:51.42,EN,,0,0,0,,and needs a bunch of registers N1. Dialogue: 0,0:38:54.85,0:38:59.48,EN,,0,0,0,,And I'm going to combine that with sequence two. Dialogue: 0,0:39:00.81,0:39:05.96,EN,,0,0,0,,That modifies a bunch of registers M2, Dialogue: 0,0:39:07.11,0:39:10.00,EN,,0,0,0,,and needs a bunch of registers N2. Dialogue: 0,0:39:12.44,0:39:14.83,EN,,0,0,0,,Then, well, we can reason it out. Dialogue: 0,0:39:15.11,0:39:16.32,EN,,0,0,0,,The new code fragment, Dialogue: 0,0:39:17.18,0:39:21.82,EN,,0,0,0,,sequence one, and-- followed by sequence two, Dialogue: 0,0:39:24.09,0:39:26.45,EN,,0,0,0,,well, what's it going to modify? Dialogue: 0,0:39:27.80,0:39:29.18,EN,,0,0,0,,The things that it will modify are the things Dialogue: 0,0:39:29.20,0:39:32.68,EN,,0,0,0,,that are modified either by sequence one or sequence two. Dialogue: 0,0:39:34.00,0:39:36.35,EN,,0,0,0,,So the union of these two Dialogue: 0,0:39:37.68,0:39:39.64,EN,,0,0,0,,sets are what the new thing modifies. Dialogue: 0,0:39:40.46,0:39:41.79,EN,,0,0,0,,And then you say, well, what is this-- Dialogue: 0,0:39:44.66,0:39:46.41,EN,,0,0,0,,what registers is it going to need? Dialogue: 0,0:39:47.95,0:39:49.77,EN,,0,0,0,,It's going to need the things that are, Dialogue: 0,0:39:49.93,0:39:51.85,EN,,0,0,0,,first of all, needed by sequence one. Dialogue: 0,0:39:52.91,0:39:54.49,EN,,0,0,0,,So what it needs is sequence one. Dialogue: 0,0:39:55.19,0:39:58.28,EN,,0,0,0,,And then, well, not quite all of the ones Dialogue: 0,0:39:58.32,0:39:59.61,EN,,0,0,0,,that are needed by sequence two. Dialogue: 0,0:39:59.75,0:40:03.49,EN,,0,0,0,,What it needs are the ones that are needed by sequence two Dialogue: 0,0:40:03.88,0:40:06.88,EN,,0,0,0,,that have not been set up by sequence one. Dialogue: 0,0:40:08.14,0:40:09.72,EN,,0,0,0,,So it's sort of the union of Dialogue: 0,0:40:11.66,0:40:13.40,EN,,0,0,0,,the things that sequence two needs Dialogue: 0,0:40:14.51,0:40:18.52,EN,,0,0,0,,minus the ones that sequence one modifies. Dialogue: 0,0:40:19.31,0:40:20.88,EN,,0,0,0,,Because it worries about setting them up. Dialogue: 0,0:40:23.95,0:40:26.26,EN,,0,0,0,,So there's the basic structure of the compiler. Dialogue: 0,0:40:26.70,0:40:29.82,EN,,0,0,0,,The way you do register optimizations is you Dialogue: 0,0:40:30.22,0:40:32.70,EN,,0,0,0,,you have some strategies for what needs to be preserved. Dialogue: 0,0:40:34.10,0:40:35.63,EN,,0,0,0,,That depends on a data structure. Dialogue: 0,0:40:35.72,0:40:38.51,EN,,0,0,0,,Well, it depends on the operation of what it means to put things together. Dialogue: 0,0:40:39.03,0:40:41.63,EN,,0,0,0,,Preserving something, that depends on knowing Dialogue: 0,0:40:41.93,0:40:47.28,EN,,0,0,0,,what registers are needed and modified by these code fragments. Dialogue: 0,0:40:48.75,0:40:51.26,EN,,0,0,0,,That depends on having little data structures, Dialogue: 0,0:40:51.42,0:40:55.43,EN,,0,0,0,,which say, a code sequence is the actual instructions, Dialogue: 0,0:40:55.60,0:40:57.33,EN,,0,0,0,,what they modify and what they need. Dialogue: 0,0:40:57.33,0:40:59.77,EN,,0,0,0,,That comes from, at the primitive level, building it in. Dialogue: 0,0:40:59.79,0:41:01.36,EN,,0,0,0,,At the primitive level, Dialogue: 0,0:41:01.37,0:41:02.52,EN,,0,0,0,,it's going to be completely obvious Dialogue: 0,0:41:03.00,0:41:04.44,EN,,0,0,0,,what something needs and modifies. Dialogue: 0,0:41:04.82,0:41:05.35,EN,,0,0,0,,Plus, Dialogue: 0,0:41:05.44,0:41:08.60,EN,,0,0,0,,this particular way that says, when I build up bigger ones, Dialogue: 0,0:41:09.28,0:41:11.89,EN,,0,0,0,,here's how I generate the new set of registers modified Dialogue: 0,0:41:11.93,0:41:13.37,EN,,0,0,0,,and the new set of registers needed. Dialogue: 0,0:41:15.27,0:41:17.77,EN,,0,0,0,,And that's the whole-- well, I shouldn't say that's the whole thing. Dialogue: 0,0:41:17.77,0:41:19.34,EN,,0,0,0,,That's the whole thing except for about Dialogue: 0,0:41:19.74,0:41:21.87,EN,,0,0,0,,about 30 pages of details in the book. Dialogue: 0,0:41:22.31,0:41:27.69,EN,,0,0,0,,But it is a perfectly usable rudimentary compiler. Dialogue: 0,0:41:28.76,0:41:31.37,EN,,0,0,0,,Let me kind of show you what it does. Dialogue: 0,0:41:31.39,0:41:35.56,EN,,0,0,0,,Suppose we start out with recursive factorial. Dialogue: 0,0:41:36.20,0:41:38.60,EN,,0,0,0,,And these slides are going to be much too small to read. Dialogue: 0,0:41:38.60,0:41:39.79,EN,,0,0,0,,I just want to flash through the code Dialogue: 0,0:41:39.79,0:41:41.28,EN,,0,0,0,,and show you about how much it is. Dialogue: 0,0:41:42.25,0:41:43.29,EN,,0,0,0,,That starts out with-- Dialogue: 0,0:41:44.32,0:41:45.68,EN,,0,0,0,,here's a first block of it, Dialogue: 0,0:41:45.95,0:41:47.68,EN,,0,0,0,,where it compiles a procedure entry Dialogue: 0,0:41:47.69,0:41:48.73,EN,,0,0,0,,and does a bunch of assignments. Dialogue: 0,0:41:48.75,0:41:51.48,EN,,0,0,0,,And this thing is basically up through the part where Dialogue: 0,0:41:52.65,0:41:53.90,EN,,0,0,0,,sets up to do the predicate Dialogue: 0,0:41:54.31,0:41:56.59,EN,,0,0,0,,and test whether the predicate's true. Dialogue: 0,0:41:56.97,0:41:57.85,EN,,0,0,0,,The second part Dialogue: 0,0:41:58.46,0:42:03.73,EN,,0,0,0,,is what results from-- in the recursive call to fact of n minus one. Dialogue: 0,0:42:04.12,0:42:05.05,EN,,0,0,0,,And this last part Dialogue: 0,0:42:06.07,0:42:07.48,EN,,0,0,0,,is coming back from that Dialogue: 0,0:42:07.87,0:42:09.90,EN,,0,0,0,,and then taking care of the constant case. Dialogue: 0,0:42:09.90,0:42:13.16,EN,,0,0,0,,So that's about how much code it would produce for factorial. Dialogue: 0,0:42:13.72,0:42:17.69,EN,,0,0,0,,We could make this compiler much, much better, of course. Dialogue: 0,0:42:18.67,0:42:21.24,EN,,0,0,0,,The main way we could make it better is Dialogue: 0,0:42:21.24,0:42:24.00,EN,,0,0,0,,to allow the compiler to make any assumptions at all Dialogue: 0,0:42:24.35,0:42:26.27,EN,,0,0,0,,about what happens when you call a procedure. Dialogue: 0,0:42:26.97,0:42:28.28,EN,,0,0,0,,So this compiler, for instance, Dialogue: 0,0:42:28.30,0:42:32.32,EN,,0,0,0,,doesn't even know, say, that multiplication Dialogue: 0,0:42:33.12,0:42:36.14,EN,,0,0,0,,you say, is something that could be coded in line. Dialogue: 0,0:42:36.14,0:42:37.87,EN,,0,0,0,,Instead, it sets up this whole mechanism. Dialogue: 0,0:42:38.00,0:42:39.34,EN,,0,0,0,,It goes to apply-dispatch. Dialogue: 0,0:42:41.37,0:42:42.49,EN,,0,0,0,,That's a tremendous waste, Dialogue: 0,0:42:42.54,0:42:45.02,EN,,0,0,0,,because what you do every time you go to apply-dispatch Dialogue: 0,0:42:45.02,0:42:46.80,EN,,0,0,0,,is you have to concern about this argument list, Dialogue: 0,0:42:47.40,0:42:49.10,EN,,0,0,0,,because it's a very general thing you're going to. Dialogue: 0,0:42:49.13,0:42:51.07,EN,,0,0,0,,In any real compiler, of course, Dialogue: 0,0:42:51.08,0:42:53.29,EN,,0,0,0,,you're going to have registers for holding arguments. Dialogue: 0,0:42:53.77,0:42:55.31,EN,,0,0,0,,And you're going to start preserving Dialogue: 0,0:42:56.38,0:42:58.05,EN,,0,0,0,,saving the way you use those registers Dialogue: 0,0:42:58.05,0:43:01.61,EN,,0,0,0,,similar to the same strategy here. Dialogue: 0,0:43:02.85,0:43:05.93,EN,,0,0,0,,So that's probably the very main way Dialogue: 0,0:43:05.95,0:43:08.30,EN,,0,0,0,,this particular compiler in the book could be fixed. Dialogue: 0,0:43:08.69,0:43:09.70,EN,,0,0,0,,There are other things like Dialogue: 0,0:43:09.70,0:43:11.82,EN,,0,0,0,,looking up variable values and Dialogue: 0,0:43:11.83,0:43:13.87,EN,,0,0,0,,making more efficient primitive operations, Dialogue: 0,0:43:13.88,0:43:14.56,EN,,0,0,0,,and all sorts of things. Dialogue: 0,0:43:14.59,0:43:16.60,EN,,0,0,0,,Essentially, a good Lisp compiler Dialogue: 0,0:43:16.62,0:43:18.49,EN,,0,0,0,,can absorb an arbitrary amount of effort. Dialogue: 0,0:43:19.72,0:43:21.63,EN,,0,0,0,,And probably one of the reasons Dialogue: 0,0:43:21.89,0:43:23.04,EN,,0,0,0,,Lisp is slow Dialogue: 0,0:43:23.63,0:43:25.44,EN,,0,0,0,,with compared to languages like FORTRAN Dialogue: 0,0:43:25.90,0:43:28.19,EN,,0,0,0,,is that, if you look over history Dialogue: 0,0:43:28.22,0:43:31.12,EN,,0,0,0,,the amount of effort that's gone into building Lisp compilers, Dialogue: 0,0:43:31.16,0:43:32.35,EN,,0,0,0,,it's nowhere near the amount of effort Dialogue: 0,0:43:32.36,0:43:33.90,EN,,0,0,0,,that's gone into FORTRAN compilers. Dialogue: 0,0:43:34.43,0:43:35.79,EN,,0,0,0,,And maybe that's something that will Dialogue: 0,0:43:35.92,0:43:37.68,EN,,0,0,0,,that will change over the next couple of years. Dialogue: 0,0:43:38.00,0:43:38.83,EN,,0,0,0,,OK, let's break. Dialogue: 0,0:43:43.80,0:43:44.65,EN,,0,0,0,,Questions? Dialogue: 0,0:43:48.27,0:43:49.95,EN,,0,0,0,,AUDIENCE: One of the very first classes-- Dialogue: 0,0:43:49.95,0:43:51.40,EN,,0,0,0,,I don't know if it was during class or after class- Dialogue: 0,0:43:51.47,0:43:53.88,EN,,0,0,0,,you showed me the, the Dialogue: 0,0:43:54.00,0:43:57.52,EN,,0,0,0,,say, addition has a primitive that we don't see, Dialogue: 0,0:43:57.69,0:43:59.21,EN,,0,0,0,,and-percent add or something like that. Dialogue: 0,0:43:59.82,0:44:01.65,EN,,0,0,0,,Is that because, Dialogue: 0,0:44:01.65,0:44:02.60,EN,,0,0,0,,if you're doing inline code Dialogue: 0,0:44:02.60,0:44:08.19,EN,,0,0,0,,you'd want to just do it for two operators, operands? Dialogue: 0,0:44:08.70,0:44:10.25,EN,,0,0,0,,But if you had more operands, Dialogue: 0,0:44:10.28,0:44:11.47,EN,,0,0,0,,you'd want to do something special? Dialogue: 0,0:44:12.71,0:44:16.04,EN,,0,0,0,,PROFESSOR: Yeah, you're looking in the actual scheme implementation. Dialogue: 0,0:44:16.06,0:44:17.84,EN,,0,0,0,,There's a plus, and a plus is some operator. Dialogue: 0,0:44:17.90,0:44:20.19,EN,,0,0,0,,And then if you go look inside the code for plus, Dialogue: 0,0:44:20.33,0:44:21.37,EN,,0,0,0,,you see something called-- Dialogue: 0,0:44:21.57,0:44:24.14,EN,,0,0,0,,I forget-- and-percent plus or something like that. Dialogue: 0,0:44:24.55,0:44:25.79,EN,,0,0,0,,And what's going on there is Dialogue: 0,0:44:25.79,0:44:27.92,EN,,0,0,0,,is that particular kind of optimization. Dialogue: 0,0:44:28.47,0:44:31.87,EN,,0,0,0,,Because, see, general plus takes an arbitrary number of arguments. Dialogue: 0,0:44:35.02,0:44:36.38,EN,,0,0,0,,So the most general plus Dialogue: 0,0:44:36.76,0:44:38.25,EN,,0,0,0,,says, oh, if I have an argument list, Dialogue: 0,0:44:38.28,0:44:40.62,EN,,0,0,0,,I'd better cons it up in some list Dialogue: 0,0:44:41.63,0:44:44.14,EN,,0,0,0,,and then figure out how many there were or something like that. Dialogue: 0,0:44:44.72,0:44:46.16,EN,,0,0,0,,That's terribly inefficient, Dialogue: 0,0:44:46.81,0:44:49.25,EN,,0,0,0,,especially since most of the time you're probably adding two numbers. Dialogue: 0,0:44:49.25,0:44:51.24,EN,,0,0,0,,You don't want to really have to cons this argument list. Dialogue: 0,0:44:52.04,0:44:53.93,EN,,0,0,0,,So what you'd like to do is build Dialogue: 0,0:44:55.66,0:44:57.71,EN,,0,0,0,,the code for plus with a bunch of entries. Dialogue: 0,0:44:58.15,0:45:00.17,EN,,0,0,0,,So most of what it's doing is the same. Dialogue: 0,0:45:00.49,0:45:01.95,EN,,0,0,0,,However, there might be a special entry Dialogue: 0,0:45:01.98,0:45:03.92,EN,,0,0,0,,that you'd go to if you knew there were only two arguments. Dialogue: 0,0:45:04.56,0:45:05.87,EN,,0,0,0,,And those you'll put in registers. Dialogue: 0,0:45:05.87,0:45:06.97,EN,,0,0,0,,they won't be in an argument list Dialogue: 0,0:45:06.99,0:45:07.98,EN,,0,0,0,,and you won't have to CONS. Dialogue: 0,0:45:08.67,0:45:10.42,EN,,0,0,0,,That's how a lot of these things work. Dialogue: 0,0:45:12.30,0:45:13.72,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:00:00.01,0:00:05.02,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:05.37,0:00:11.84,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N杨启钊\N(windfarer) Dialogue: 0,0:00:05.37,0:00:11.84,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:05.37,0:00:11.84,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:05.37,0:00:11.84,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:05.37,0:00:11.84,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:11.84,0:00:13.84,Declare,,0,0,0,,{\an2\fad(500,500)}编译 Dialogue: 0,0:00:19.36,0:00:22.65,Default,,0,0,0,,教授: 上节课 我们学习了 Dialogue: 0,0:00:22.65,0:00:25.67,Default,,0,0,0,,一个显式控制的Lisp求值器 Dialogue: 0,0:00:25.67,0:00:28.97,Default,,0,0,0,,它弥合了像Lisp Dialogue: 0,0:00:29.05,0:00:32.14,Default,,0,0,0,,或者查询语言之类的高级语言 Dialogue: 0,0:00:32.50,0:00:36.16,Default,,0,0,0,,与传统寄存器机器之间的鸿沟 Dialogue: 0,0:00:36.70,0:00:40.14,Default,,0,0,0,,事实上 你可以将显式控制求值器 Dialogue: 0,0:00:40.16,0:00:44.38,Default,,0,0,0,,看作是 在一台常见的 Dialogue: 0,0:00:44.40,0:00:45.95,Default,,0,0,0,,寄存机器上实现的 Dialogue: 0,0:00:46.52,0:00:49.50,Default,,0,0,0,,Lisp求值器的汇编代码 Dialogue: 0,0:00:49.50,0:00:51.50,Default,,0,0,0,,或者 你可以把它看做是 Dialogue: 0,0:00:52.08,0:00:54.56,Default,,0,0,0,,某台专门运行Lisp的机器的微程序 Dialogue: 0,0:00:55.20,0:00:55.92,Default,,0,0,0,,无论是那种情况 Dialogue: 0,0:00:55.92,0:00:58.68,Default,,0,0,0,,我们都是把一台 Dialogue: 0,0:00:58.94,0:01:00.51,Default,,0,0,0,,处理低级语言的机器 Dialogue: 0,0:01:01.42,0:01:03.32,Default,,0,0,0,,抬高到一个层次 Dialogue: 0,0:01:03.37,0:01:04.88,Default,,0,0,0,,以便处理像Lisp这样的高级语言 Dialogue: 0,0:01:05.36,0:01:06.35,Default,,0,0,0,,这是通过编写解释器来实现的 Dialogue: 0,0:01:08.22,0:01:09.58,Default,,0,0,0,,来看个例子 Dialogue: 0,0:01:11.82,0:01:13.77,Default,,0,0,0,,这里 从概念上来说 Dialogue: 0,0:01:18.01,0:01:19.47,Default,,0,0,0,,从概念上来说 这是一台 Dialogue: 0,0:01:20.54,0:01:23.44,Default,,0,0,0,,专用于计算阶乘的机器 Dialogue: 0,0:01:24.09,0:01:27.39,Default,,0,0,0,,输入5 输出120 Dialogue: 0,0:01:28.92,0:01:30.83,Default,,0,0,0,,这个专用机器实际上 Dialogue: 0,0:01:30.97,0:01:32.72,Default,,0,0,0,,是一个Lisp解释器 Dialogue: 0,0:01:33.50,0:01:36.17,Default,,0,0,0,,它将自己配置为计算阶乘 Dialogue: 0,0:01:38.35,0:01:40.99,Default,,0,0,0,,因为你向它送入了一台阶乘机器的描述 Dialogue: 0,0:01:42.12,0:01:43.70,Default,,0,0,0,,这就是解释器 Dialogue: 0,0:01:43.70,0:01:45.66,Default,,0,0,0,,它将自己配置为 Dialogue: 0,0:01:46.37,0:01:49.24,Default,,0,0,0,,模拟你所输入描述的机器 Dialogue: 0,0:01:50.07,0:01:51.93,Default,,0,0,0,,那么 在Lisp解释器里是什么? Dialogue: 0,0:01:52.04,0:01:55.44,Default,,0,0,0,,里面可能是通用的寄存器语言解释器 Dialogue: 0,0:01:56.98,0:02:00.18,Default,,0,0,0,,它将自己配置成像Lisp解释器那样 Dialogue: 0,0:02:00.18,0:02:02.03,Default,,0,0,0,,因为你输入了一系列用寄存器语言 Dialogue: 0,0:02:02.12,0:02:03.04,Default,,0,0,0,,编写的指令 Dialogue: 0,0:02:03.37,0:02:05.16,Default,,0,0,0,,这就是显式控制求值器 Dialogue: 0,0:02:07.05,0:02:08.70,Default,,0,0,0,,它里面也有一些库 Dialogue: 0,0:02:08.73,0:02:11.08,Default,,0,0,0,,由基本运算符和Lisp运算 Dialogue: 0,0:02:11.12,0:02:12.28,Default,,0,0,0,,等等要素组成 Dialogue: 0,0:02:12.75,0:02:16.89,Default,,0,0,0,,这是解释执行的一般策略 Dialogue: 0,0:02:17.32,0:02:18.51,Default,,0,0,0,,事实上 我们所做的是 Dialogue: 0,0:02:18.60,0:02:20.14,Default,,0,0,0,,通过编写解释器 Dialogue: 0,0:02:21.62,0:02:23.40,Default,,0,0,0,,将机器抬升到 Dialogue: 0,0:02:23.42,0:02:25.24,Default,,0,0,0,,我们程序所在的层次 Dialogue: 0,0:02:25.24,0:02:26.72,Default,,0,0,0,,当然 还有另外一种策略 Dialogue: 0,0:02:27.42,0:02:28.89,Default,,0,0,0,,这种不同的策略就是编译 Dialogue: 0,0:02:29.04,0:02:30.43,Default,,0,0,0,,编译有一些不同 Dialogue: 0,0:02:31.04,0:02:31.50,Default,,0,0,0,,这里 Dialogue: 0,0:02:33.37,0:02:34.75,Default,,0,0,0,,我们可能已经实现了 Dialogue: 0,0:02:35.67,0:02:38.52,Default,,0,0,0,,一个特定用途的机器 Dialogue: 0,0:02:38.62,0:02:39.98,Default,,0,0,0,,用来计算阶乘 Dialogue: 0,0:02:43.62,0:02:46.26,Default,,0,0,0,,从某种使用寄存器语言的机器开始 Dialogue: 0,0:02:46.26,0:02:47.72,Default,,0,0,0,,但是 我们将让它执行不同的策略 Dialogue: 0,0:02:47.72,0:02:50.38,Default,,0,0,0,,把我们的阶乘程序 Dialogue: 0,0:02:51.55,0:02:53.92,Default,,0,0,0,,作为源代码输入编译器 Dialogue: 0,0:02:53.92,0:02:55.15,Default,,0,0,0,,编译器就会 Dialogue: 0,0:02:55.15,0:02:57.62,Default,,0,0,0,,把这个阶乘程序 Dialogue: 0,0:02:57.62,0:02:59.07,Default,,0,0,0,,翻译成某种寄存器机器语言 Dialogue: 0,0:03:00.25,0:03:03.40,Default,,0,0,0,,现在它并不是Lisp的显式控制求值器 Dialogue: 0,0:03:03.40,0:03:06.17,Default,,0,0,0,,而是某种用来计算阶乘的寄存器语言 Dialogue: 0,0:03:06.49,0:03:08.36,Default,,0,0,0,,这就是翻译的过程 Dialogue: 0,0:03:10.54,0:03:12.41,Default,,0,0,0,,它将进入某种加载器 Dialogue: 0,0:03:13.35,0:03:15.21,Default,,0,0,0,,它会把这些代码 Dialogue: 0,0:03:15.31,0:03:16.84,Default,,0,0,0,,和从程序库中选取的代码 Dialogue: 0,0:03:16.86,0:03:18.65,Default,,0,0,0,,比如乘法运算等 结合在一起 Dialogue: 0,0:03:19.82,0:03:21.69,Default,,0,0,0,,随后我们将生成一个加载模块 Dialogue: 0,0:03:22.22,0:03:25.06,Default,,0,0,0,,它把寄存器语言机器配置成 Dialogue: 0,0:03:25.06,0:03:27.24,Default,,0,0,0,,一个专门用来计算阶乘的机器 Dialogue: 0,0:03:28.12,0:03:30.22,Default,,0,0,0,,这就是不同的策略 Dialogue: 0,0:03:30.22,0:03:31.22,Default,,0,0,0,,在解释中 Dialogue: 0,0:03:31.22,0:03:32.01,Default,,0,0,0,,我们把机器 Dialogue: 0,0:03:32.91,0:03:35.23,Default,,0,0,0,,抬升到Lisp语言的层次 Dialogue: 0,0:03:35.32,0:03:36.34,Default,,0,0,0,,而在编译中 Dialogue: 0,0:03:36.34,0:03:38.43,Default,,0,0,0,,我们将我们的程序下降到 Dialogue: 0,0:03:38.48,0:03:40.56,Default,,0,0,0,,机器语言的层次 Dialogue: 0,0:03:41.96,0:03:43.84,Default,,0,0,0,,那么 这两个策略有什么区别呢? Dialogue: 0,0:03:44.30,0:03:49.42,Default,,0,0,0,,编译器可以生成执行起来更有效率的代码 Dialogue: 0,0:03:52.05,0:03:53.90,Default,,0,0,0,,主要原因是 Dialogue: 0,0:03:54.17,0:03:58.89,Default,,0,0,0,,如果你考虑运行中的寄存器操作 Dialogue: 0,0:04:01.92,0:04:04.49,Default,,0,0,0,,解释器需要生成寄存器的操作 Dialogue: 0,0:04:04.97,0:04:06.75,Default,,0,0,0,,从原则上来讲 它需要足够通用 Dialogue: 0,0:04:07.32,0:04:08.94,Default,,0,0,0,,以支持任何Lisp过程的执行 Dialogue: 0,0:04:10.22,0:04:12.25,Default,,0,0,0,,而编译器只需要 Dialogue: 0,0:04:12.27,0:04:14.92,Default,,0,0,0,,生成一组特定的寄存器操作 Dialogue: 0,0:04:15.52,0:04:18.22,Default,,0,0,0,,用来执行你所编译的那部分特定的Lisp过程 Dialogue: 0,0:04:20.17,0:04:21.20,Default,,0,0,0,,换一种说法 Dialogue: 0,0:04:21.20,0:04:25.31,Default,,0,0,0,,解释器是一种通用的模拟器 Dialogue: 0,0:04:25.92,0:04:27.58,Default,,0,0,0,,当你输入一个Lisp过程时 Dialogue: 0,0:04:27.58,0:04:31.32,Default,,0,0,0,,它们就会模拟那个过程所描述的程序 Dialogue: 0,0:04:31.32,0:04:33.87,Default,,0,0,0,,所以解释器旨在成为一个通用模拟器 Dialogue: 0,0:04:34.62,0:04:35.96,Default,,0,0,0,,而编译器 实际上 Dialogue: 0,0:04:36.00,0:04:37.68,Default,,0,0,0,,只需要将东西配置成 Dialogue: 0,0:04:37.71,0:04:39.34,Default,,0,0,0,,解释器将要去模拟的机器 Dialogue: 0,0:04:40.02,0:04:41.34,Default,,0,0,0,,所以编译器可以运行得更快 Dialogue: 0,0:04:52.55,0:04:53.64,Default,,0,0,0,,另一方面 Dialogue: 0,0:04:55.97,0:04:58.28,Default,,0,0,0,,解释器更适合用来排查错误 Dialogue: 0,0:04:59.43,0:05:01.25,Default,,0,0,0,,这是因为 Dialogue: 0,0:05:01.57,0:05:03.02,Default,,0,0,0,,我们的源代码实际上就在那里 Dialogue: 0,0:05:03.02,0:05:04.81,Default,,0,0,0,,我们正在解释它们 Dialogue: 0,0:05:05.87,0:05:07.69,Default,,0,0,0,,并且库也在其中 Dialogue: 0,0:05:07.90,0:05:10.89,Default,,0,0,0,,看 库是解释器的一部分 Dialogue: 0,0:05:11.30,0:05:13.16,Default,,0,0,0,,而编译器只会拉取 Dialogue: 0,0:05:13.20,0:05:14.56,Default,,0,0,0,,运行程序所需要的代码 Dialogue: 0,0:05:14.87,0:05:17.00,Default,,0,0,0,,所以 如果你在排查错误的途中 Dialogue: 0,0:05:18.00,0:05:20.72,Default,,0,0,0,,你想写一些额外的代码 Dialogue: 0,0:05:20.80,0:05:22.57,Default,,0,0,0,,来考察运行过程中的数据类型 Dialogue: 0,0:05:23.05,0:05:24.25,Default,,0,0,0,,或者做一些 Dialogue: 0,0:05:24.30,0:05:25.92,Default,,0,0,0,,在写程序时没有想到的计算 Dialogue: 0,0:05:25.95,0:05:27.53,Default,,0,0,0,,解释器可以完美搞定这些 Dialogue: 0,0:05:28.05,0:05:29.21,Default,,0,0,0,,而编译器不行 Dialogue: 0,0:05:29.62,0:05:31.90,Default,,0,0,0,,所以它们各有优点 Dialogue: 0,0:05:31.90,0:05:34.48,Default,,0,0,0,,编译器将生成运行更快的代码 Dialogue: 0,0:05:34.85,0:05:37.02,Default,,0,0,0,,而解释器是一种更适合排错的环境 Dialogue: 0,0:05:38.95,0:05:41.40,Default,,0,0,0,,大多数Lisp系统最终将二者都实现了 Dialogue: 0,0:05:42.92,0:05:45.23,Default,,0,0,0,,这样你就可以在开发阶段 Dialogue: 0,0:05:45.24,0:05:47.08,Default,,0,0,0,,可以使用解释器 Dialogue: 0,0:05:47.08,0:05:48.62,Default,,0,0,0,,随后通过编译加速代码的运行 Dialogue: 0,0:05:49.02,0:05:50.03,Default,,0,0,0,,并且通常 Dialogue: 0,0:05:50.04,0:05:51.68,Default,,0,0,0,,你能够让被编译的代码 Dialogue: 0,0:05:51.69,0:05:53.56,Default,,0,0,0,,和被解释的代码互相调用 Dialogue: 0,0:05:54.60,0:05:56.33,Default,,0,0,0,,我们将学习如何做到 其实不难 Dialogue: 0,0:05:59.27,0:05:59.85,Default,,0,0,0,,好 Dialogue: 0,0:06:00.97,0:06:02.09,Default,,0,0,0,,事实上 Dialogue: 0,0:06:04.30,0:06:05.75,Default,,0,0,0,,在我们将要构建的编译器中 Dialogue: 0,0:06:05.75,0:06:07.58,Default,,0,0,0,,我们实现编译的代码和解释的代码 Dialogue: 0,0:06:07.58,0:06:09.45,Default,,0,0,0,,互相调用的方式是 Dialogue: 0,0:06:09.90,0:06:12.06,Default,,0,0,0,,我们让编译器和解释器使用 Dialogue: 0,0:06:12.11,0:06:14.40,Default,,0,0,0,,使用完全一致的寄存器约定 Dialogue: 0,0:06:18.42,0:06:21.72,Default,,0,0,0,,编译器的理念 Dialogue: 0,0:06:21.76,0:06:25.74,Default,,0,0,0,,与解释器或求值器的理念很像 Dialogue: 0,0:06:25.87,0:06:26.46,Default,,0,0,0,,它们是相同的 Dialogue: 0,0:06:27.05,0:06:29.39,Default,,0,0,0,,求值器遍历代码 Dialogue: 0,0:06:29.82,0:06:32.35,Default,,0,0,0,,产生一些寄存器操作 Dialogue: 0,0:06:33.65,0:06:34.97,Default,,0,0,0,,就是我们昨天做的事情 Dialogue: 0,0:06:37.10,0:06:40.27,Default,,0,0,0,,而编译器会读取代码 Dialogue: 0,0:06:40.52,0:06:43.00,Default,,0,0,0,,生成一些进行求值时 Dialogue: 0,0:06:43.04,0:06:44.67,Default,,0,0,0,,求值器会进行的 Dialogue: 0,0:06:45.23,0:06:46.64,Default,,0,0,0,,相关寄存器操作 Dialogue: 0,0:06:48.60,0:06:49.95,Default,,0,0,0,,这就给我们提供了一个模型 Dialogue: 0,0:06:50.60,0:06:53.77,Default,,0,0,0,,来实现一个零阶编译器 Dialogue: 0,0:06:55.30,0:06:58.32,Default,,0,0,0,,一个很差劲但是能用的编译器 Dialogue: 0,0:06:58.32,0:06:59.32,Default,,0,0,0,,这种模型就是 Dialogue: 0,0:06:59.36,0:07:00.59,Default,,0,0,0,,你用求值器 Dialogue: 0,0:07:00.68,0:07:01.88,Default,,0,0,0,,把代码跑一遍 Dialogue: 0,0:07:02.80,0:07:06.06,Default,,0,0,0,,但不去执行实际的操作 Dialogue: 0,0:07:06.06,0:07:07.15,Default,,0,0,0,,只是把它们保存下来 Dialogue: 0,0:07:07.55,0:07:08.82,Default,,0,0,0,,那就是你编译后的代码 Dialogue: 0,0:07:08.82,0:07:10.24,Default,,0,0,0,,让我举个例子 Dialogue: 0,0:07:12.70,0:07:14.14,Default,,0,0,0,,假设我们要编译 Dialogue: 0,0:07:15.10,0:07:17.90,Default,,0,0,0,,编译(F X) 这个表达式 Dialogue: 0,0:07:25.07,0:07:25.96,Default,,0,0,0,,我们假设 Dialogue: 0,0:07:25.96,0:07:28.06,Default,,0,0,0,,EXP寄存器中保存着(F X) Dialogue: 0,0:07:28.06,0:07:29.55,Default,,0,0,0,,而ENV寄存器又保存着其它东西 Dialogue: 0,0:07:30.10,0:07:32.20,Default,,0,0,0,,想象我们启动了求值器 Dialogue: 0,0:07:34.60,0:07:35.71,Default,,0,0,0,,它读取了表达式 Dialogue: 0,0:07:35.71,0:07:37.36,Default,,0,0,0,,判断它是一个应用 Dialogue: 0,0:07:37.92,0:07:41.90,Default,,0,0,0,,它分支到求值器代码中的一个地方 Dialogue: 0,0:07:42.52,0:07:45.15,Default,,0,0,0,,我们之前见过的叫EV-APPLICATION的地方 Dialogue: 0,0:07:47.12,0:07:48.12,Default,,0,0,0,,然后继续处理 Dialogue: 0,0:07:48.16,0:07:50.08,Default,,0,0,0,,恢复运算对象和UNEV Dialogue: 0,0:07:50.08,0:07:52.44,Default,,0,0,0,,然后之后它将运算符放在EXP寄存器中 Dialogue: 0,0:07:52.48,0:07:54.27,Default,,0,0,0,,递归地对它求值 Dialogue: 0,0:07:54.47,0:07:56.08,Default,,0,0,0,,这就是我们经历的过程 Dialogue: 0,0:07:56.67,0:07:57.84,Default,,0,0,0,,如果你看代码 Dialogue: 0,0:07:57.87,0:07:59.74,Default,,0,0,0,,会看到一些寄存器操作 Dialogue: 0,0:08:00.20,0:08:02.30,Default,,0,0,0,,你会看到将运算对象赋值给UNEV寄存器 Dialogue: 0,0:08:02.30,0:08:03.95,Default,,0,0,0,,把运算符赋值给EXP Dialogue: 0,0:08:04.09,0:08:06.20,Default,,0,0,0,,保存环境、生成新环境 等等 Dialogue: 0,0:08:10.22,0:08:11.93,Default,,0,0,0,,如果我们来看下这里的投影 Dialogue: 0,0:08:15.75,0:08:19.58,Default,,0,0,0,,我们会看到产生的这些操作 Dialogue: 0,0:08:20.82,0:08:22.52,Default,,0,0,0,,这是求值器实际要进行的 Dialogue: 0,0:08:22.72,0:08:24.80,Default,,0,0,0,,第一个操作 Dialogue: 0,0:08:25.00,0:08:27.20,Default,,0,0,0,,它将运算对象从EXP寄存器里取出来 Dialogue: 0,0:08:27.47,0:08:28.62,Default,,0,0,0,,并将它赋值给UNEV Dialogue: 0,0:08:30.03,0:08:32.27,Default,,0,0,0,,然后它给EXP寄存器赋了某个值 Dialogue: 0,0:08:32.30,0:08:33.46,Default,,0,0,0,,然后保存CONTINUE Dialogue: 0,0:08:33.46,0:08:34.62,Default,,0,0,0,,保存ENV Dialogue: 0,0:08:34.62,0:08:38.65,Default,,0,0,0,,我在这里就只是寄存器赋值 Dialogue: 0,0:08:39.57,0:08:42.32,Default,,0,0,0,,这就是求值器求值代码时进行的操作 Dialogue: 0,0:08:42.77,0:08:43.79,Default,,0,0,0,,我们缩小画面看看 Dialogue: 0,0:08:44.30,0:08:47.13,Default,,0,0,0,,总计有19个操作 Dialogue: 0,0:08:49.40,0:08:51.64,Default,,0,0,0,,这些代码 Dialogue: 0,0:08:52.05,0:08:53.90,Default,,0,0,0,,对应着 Dialogue: 0,0:08:54.75,0:08:57.10,Default,,0,0,0,,求值器跳转到APPLY-DISPATCH代码之前 Dialogue: 0,0:08:57.86,0:08:59.16,Default,,0,0,0,,事实上 在这个编译器中 Dialogue: 0,0:08:59.20,0:09:01.18,Default,,0,0,0,,我们不需要再关心APPLY-DISPATCH了 Dialogue: 0,0:09:01.30,0:09:02.11,Default,,0,0,0,,我们有所有东西 Dialogue: 0,0:09:02.35,0:09:05.04,Default,,0,0,0,,我们拥有解释后和编译后的所有代码 Dialogue: 0,0:09:06.07,0:09:07.61,Default,,0,0,0,,通常求值过程 Dialogue: 0,0:09:07.61,0:09:09.85,Default,,0,0,0,,是由APPLY-DISPATCH处理的 Dialogue: 0,0:09:10.27,0:09:12.32,Default,,0,0,0,,这将让被解释后代码与编译后代码 Dialogue: 0,0:09:12.36,0:09:13.71,Default,,0,0,0,,很容易互相调用 Dialogue: 0,0:09:18.27,0:09:19.87,Default,,0,0,0,,从原理上来说 这样做足矣 Dialogue: 0,0:09:21.05,0:09:22.66,Default,,0,0,0,,只需运行求值器 Dialogue: 0,0:09:22.66,0:09:24.50,Default,,0,0,0,,因而编译器非常像求值器 Dialogue: 0,0:09:24.50,0:09:26.47,Default,,0,0,0,,你运行它 唯一不同是你把操作存下来 Dialogue: 0,0:09:26.47,0:09:28.40,Default,,0,0,0,,而不是实际执行它们 Dialogue: 0,0:09:29.35,0:09:31.39,Default,,0,0,0,,这其实不完全正确 Dialogue: 0,0:09:32.91,0:09:34.99,Default,,0,0,0,,这里面我们撒了个小谎 Dialogue: 0,0:09:36.24,0:09:39.29,Default,,0,0,0,,你需要关心的是:如果有个谓词 Dialogue: 0,0:09:40.12,0:09:42.16,Default,,0,0,0,,如果你要进行某种测试 Dialogue: 0,0:09:43.45,0:09:46.03,Default,,0,0,0,,显然 在你编译时 Dialogue: 0,0:09:46.52,0:09:47.98,Default,,0,0,0,,你不知道这些分支中 Dialogue: 0,0:09:48.32,0:09:50.14,Default,,0,0,0,,哪条分支会被执行 Dialogue: 0,0:09:51.13,0:09:53.92,Default,,0,0,0,,所以你不能确定求值器将对哪个求值 Dialogue: 0,0:09:54.90,0:09:57.12,Default,,0,0,0,,因此在这里就很简单 Dialogue: 0,0:09:57.12,0:09:58.49,Default,,0,0,0,,你把两个分支全编译了 Dialogue: 0,0:09:59.32,0:10:01.29,Default,,0,0,0,,因此你编译出一个这样的结构 Dialogue: 0,0:10:02.00,0:10:03.98,Default,,0,0,0,,它们都会被编译成 Dialogue: 0,0:10:05.31,0:10:09.15,Default,,0,0,0,,首先是P的代码 Dialogue: 0,0:10:10.71,0:10:16.51,Default,,0,0,0,,它把结果存入VAL寄存器 Dialogue: 0,0:10:18.17,0:10:20.64,Default,,0,0,0,,解释器对谓词求值 Dialogue: 0,0:10:21.35,0:10:24.19,Default,,0,0,0,,并保证结果会放到VAL寄存器中 Dialogue: 0,0:10:24.70,0:10:27.22,Default,,0,0,0,,随后你编译一条指令 Dialogue: 0,0:10:27.22,0:10:33.79,Default,,0,0,0,,如果VAL是TRUE Dialogue: 0,0:10:37.17,0:10:38.75,Default,,0,0,0,,就转到LABEL1这个地方 Dialogue: 0,0:10:44.97,0:10:47.52,Default,,0,0,0,,然后我们写下B的代码 Dialogue: 0,0:10:49.42,0:10:52.32,Default,,0,0,0,,让解释器对B进行求值 Dialogue: 0,0:10:53.62,0:10:57.21,Default,,0,0,0,,然后写一句指令 Dialogue: 0,0:10:57.23,0:10:58.75,Default,,0,0,0,,用来跳转到下一条指令 Dialogue: 0,0:11:02.20,0:11:04.56,Default,,0,0,0,,就是它结束之后要去的地方 Dialogue: 0,0:11:04.95,0:11:06.09,Default,,0,0,0,,你放入那个指令 Dialogue: 0,0:11:06.88,0:11:08.62,Default,,0,0,0,,这里你写下LABEL1 Dialogue: 0,0:11:12.12,0:11:13.80,Default,,0,0,0,,这里写A的代码 Dialogue: 0,0:11:19.47,0:11:25.85,Default,,0,0,0,,然后又是跳转到下一条指令 Dialogue: 0,0:11:31.42,0:11:32.88,Default,,0,0,0,,这就是处理条件分支的办法 Dialogue: 0,0:11:32.98,0:11:34.65,Default,,0,0,0,,你生成一小段这样的代码 Dialogue: 0,0:11:35.75,0:11:38.12,Default,,0,0,0,,除此之外 Dialogue: 0,0:11:38.95,0:11:41.55,Default,,0,0,0,,这个零阶编译器与求值器一模一样 Dialogue: 0,0:11:42.55,0:11:45.12,Default,,0,0,0,,它只是把指令存起来 而不执行它们 Dialogue: 0,0:11:46.55,0:11:47.60,Default,,0,0,0,,看起来很简单 Dialogue: 0,0:11:47.64,0:11:49.08,Default,,0,0,0,,但我们已经取得了某些收获 Dialogue: 0,0:11:50.12,0:11:52.62,Default,,0,0,0,,它会比求值器更有效率 Dialogue: 0,0:11:53.52,0:11:56.14,Default,,0,0,0,,因为 如果你观察求值器的运行 Dialogue: 0,0:11:56.35,0:12:01.05,Default,,0,0,0,,它并不只是进行寄存器操作 Dialogue: 0,0:12:01.27,0:12:03.50,Default,,0,0,0,,它还会决定执行哪个 Dialogue: 0,0:12:04.70,0:12:07.23,Default,,0,0,0,,它做的第一件事就是 Dialogue: 0,0:12:07.92,0:12:09.77,Default,,0,0,0,,以它为例 就是进行某些测试 Dialogue: 0,0:12:09.77,0:12:11.56,Default,,0,0,0,,确定它是一个应用 Dialogue: 0,0:12:13.57,0:12:15.05,Default,,0,0,0,,然后就跳转到 Dialogue: 0,0:12:15.39,0:12:16.62,Default,,0,0,0,,处理应用的地方去 Dialogue: 0,0:12:16.62,0:12:18.44,Default,,0,0,0,,换句话说 求值器做的事情是 Dialogue: 0,0:12:18.62,0:12:22.76,Default,,0,0,0,,分析代码需要进行的运算 Dialogue: 0,0:12:23.47,0:12:24.99,Default,,0,0,0,,同时并执行它们 Dialogue: 0,0:12:25.55,0:12:28.28,Default,,0,0,0,,当你运行求值器一百万次 Dialogue: 0,0:12:28.28,0:12:30.30,Default,,0,0,0,,这个分析过程就进行一百万次 Dialogue: 0,0:12:30.85,0:12:32.58,Default,,0,0,0,,而在编译器中 它只会进行一次 Dialogue: 0,0:12:32.58,0:12:34.81,Default,,0,0,0,,之后就只有寄存器操作了 Dialogue: 0,0:12:39.20,0:12:41.68,Default,,0,0,0,,这就是零阶编译器了 Dialogue: 0,0:12:41.80,0:12:44.04,Default,,0,0,0,,但它是个拙劣的编译器 Dialogue: 0,0:12:44.45,0:12:45.28,Default,,0,0,0,,它挺蠢的 Dialogue: 0,0:12:46.90,0:12:48.41,Default,,0,0,0,,让我们回过头来 Dialogue: 0,0:12:49.88,0:12:50.97,Default,,0,0,0,,看看这张投影 Dialogue: 0,0:12:52.02,0:12:55.29,Default,,0,0,0,,看看这个东西做的一些操作 Dialogue: 0,0:12:55.85,0:12:56.88,Default,,0,0,0,,我们想看看 Dialogue: 0,0:12:59.72,0:13:02.28,Default,,0,0,0,,在解释(F X)时的操作 Dialogue: 0,0:13:03.52,0:13:04.84,Default,,0,0,0,,这里就是它做了什么 Dialogue: 0,0:13:05.17,0:13:06.11,Default,,0,0,0,,举个例子 这里 Dialogue: 0,0:13:07.15,0:13:11.98,Default,,0,0,0,,它将(OPERATOR (FETCH EXP))赋值给EXP Dialogue: 0,0:13:13.75,0:13:15.87,Default,,0,0,0,,其实没必要这样做 Dialogue: 0,0:13:16.22,0:13:17.47,Default,,0,0,0,,因为编译器知道 Dialogue: 0,0:13:17.66,0:13:21.84,Default,,0,0,0,,(OPERATOR (FETCH EXP))的值就是F Dialogue: 0,0:13:23.35,0:13:25.56,Default,,0,0,0,,因此这个指令没理由存在 Dialogue: 0,0:13:25.70,0:13:28.88,Default,,0,0,0,,应该改为:要把F赋值给EXP Dialogue: 0,0:13:29.45,0:13:31.08,Default,,0,0,0,,或者实际上 你完全不需要EXP Dialogue: 0,0:13:31.87,0:13:33.56,Default,,0,0,0,,没有理由需要EXP Dialogue: 0,0:13:33.56,0:13:35.16,Default,,0,0,0,,EXP是用来做什么的? Dialogue: 0,0:13:35.18,0:13:36.33,Default,,0,0,0,,我们看这里 Dialogue: 0,0:13:40.77,0:13:42.20,Default,,0,0,0,,我们对VAL赋值 Dialogue: 0,0:13:43.05,0:13:47.34,Default,,0,0,0,,在环境里的EXP里寻找东西 Dialogue: 0,0:13:48.68,0:13:49.53,Default,,0,0,0,,因此 我们实际上是要 Dialogue: 0,0:13:49.55,0:13:51.54,Default,,0,0,0,,替换掉所有的EXP寄存器 Dialogue: 0,0:13:51.54,0:13:53.32,Default,,0,0,0,,把这个指令修改为 Dialogue: 0,0:13:53.34,0:13:54.16,Default,,0,0,0,,给VAL赋值 Dialogue: 0,0:13:54.45,0:13:56.06,Default,,0,0,0,,在环境中查找 Dialogue: 0,0:13:56.36,0:13:58.40,Default,,0,0,0,,符号F的值 Dialogue: 0,0:14:01.09,0:14:01.77,Default,,0,0,0,,类似地 Dialogue: 0,0:14:02.57,0:14:04.27,Default,,0,0,0,,回到这里 我们也完全不需要UNEV Dialogue: 0,0:14:04.72,0:14:05.79,Default,,0,0,0,,因为我们知道 Dialogue: 0,0:14:06.22,0:14:09.16,Default,,0,0,0,,因为我们知道 (FETCH EXP)取出的运算对象 Dialogue: 0,0:14:09.16,0:14:10.62,Default,,0,0,0,,就是'(X) Dialogue: 0,0:14:13.25,0:14:14.06,Default,,0,0,0,,从某种意义上来说 Dialogue: 0,0:14:16.17,0:14:19.39,Default,,0,0,0,,你完全不需要UNEV和EXP Dialogue: 0,0:14:19.67,0:14:21.05,Default,,0,0,0,,看看它们实际上是什么 Dialogue: 0,0:14:21.08,0:14:25.30,Default,,0,0,0,,它们不是实际运行机器的寄存器 Dialogue: 0,0:14:25.30,0:14:26.40,Default,,0,0,0,,它们实际上是 Dialogue: 0,0:14:26.60,0:14:29.50,Default,,0,0,0,,为了模拟该机器的而设置的寄存器 Dialogue: 0,0:14:30.72,0:14:33.77,Default,,0,0,0,,所以它们保存一些表达式 Dialogue: 0,0:14:34.00,0:14:36.04,Default,,0,0,0,,以编译器的视角看来 Dialogue: 0,0:14:36.06,0:14:36.81,Default,,0,0,0,,它们就是常量 Dialogue: 0,0:14:36.95,0:14:38.48,Default,,0,0,0,,因此可以直接把它们放到代码中 Dialogue: 0,0:14:39.47,0:14:41.34,Default,,0,0,0,,你可以忘掉那些关于 Dialogue: 0,0:14:41.36,0:14:42.54,Default,,0,0,0,,EXP和UNEV的操作 Dialogue: 0,0:14:42.57,0:14:43.77,Default,,0,0,0,,只用那些常量 Dialogue: 0,0:14:44.02,0:14:48.00,Default,,0,0,0,,与之相似 如果我们回顾这里 Dialogue: 0,0:14:48.00,0:14:51.32,Default,,0,0,0,,有像(ASSIGN CONTINUE EVAL-ARGS)之类的语句 Dialogue: 0,0:14:53.75,0:14:55.39,Default,,0,0,0,,现在 它和任何东西都没有关系 Dialogue: 0,0:14:55.62,0:14:57.76,Default,,0,0,0,,它只是求值器 Dialogue: 0,0:14:58.08,0:15:00.17,Default,,0,0,0,,维护了下一步需要去哪 Dialogue: 0,0:15:02.70,0:15:05.96,Default,,0,0,0,,在某些应用中对参数进行求值 Dialogue: 0,0:15:06.82,0:15:08.65,Default,,0,0,0,,当然 这与编译器没关系 Dialogue: 0,0:15:08.65,0:15:13.88,Default,,0,0,0,,因为这个分析过程已经被编译器做完了 Dialogue: 0,0:15:15.05,0:15:16.83,Default,,0,0,0,,所以编译后的代码完全不需要它 Dialogue: 0,0:15:17.70,0:15:19.32,Default,,0,0,0,,因此许多向CONTINUE寄存器 Dialogue: 0,0:15:19.32,0:15:21.30,Default,,0,0,0,,赋值的操作都是无用的 Dialogue: 0,0:15:21.30,0:15:24.62,Default,,0,0,0,,运行着的机器留着它们 Dialogue: 0,0:15:24.64,0:15:25.77,Default,,0,0,0,,是为了跟踪它的状态 Dialogue: 0,0:15:26.07,0:15:28.72,Default,,0,0,0,,是为了知道求值器的下一步分析 Dialogue: 0,0:15:28.72,0:15:30.03,Default,,0,0,0,,而它们是完全无关的 Dialogue: 0,0:15:30.06,0:15:31.23,Default,,0,0,0,,因此我们可以去掉它们 Dialogue: 0,0:15:43.90,0:15:45.98,Default,,0,0,0,,那么 如果我们简单地 Dialogue: 0,0:15:46.16,0:15:47.75,Default,,0,0,0,,进行这类优化 Dialogue: 0,0:15:47.75,0:15:51.64,Default,,0,0,0,,不再考虑EXP和UNEV Dialogue: 0,0:15:51.75,0:15:56.22,Default,,0,0,0,,去掉这些无关的寄存器赋值 Dialogue: 0,0:15:57.25,0:15:59.96,Default,,0,0,0,,我们就可以找到这些代码 Dialogue: 0,0:16:01.48,0:16:06.20,Default,,0,0,0,,也就是求值器会执行的这19条指令 Dialogue: 0,0:16:06.91,0:16:08.12,Default,,0,0,0,,给替换掉 Dialogue: 0,0:16:08.36,0:16:10.33,Default,,0,0,0,,请看幻灯片 Dialogue: 0,0:16:12.27,0:16:15.34,Default,,0,0,0,,我们去掉了大概一半 Dialogue: 0,0:16:18.28,0:16:20.75,Default,,0,0,0,,同样 这就是某种过滤 Dialogue: 0,0:16:21.07,0:16:24.46,Default,,0,0,0,,把无关的东西去掉 Dialogue: 0,0:16:25.17,0:16:26.22,Default,,0,0,0,,你们看 比如说 Dialogue: 0,0:16:27.47,0:16:29.66,Default,,0,0,0,,这里 求值器说 Dialogue: 0,0:16:29.68,0:16:32.43,Default,,0,0,0,,(ASSIGN VAL (LOOKUP 'F (FETCH ENV))) Dialogue: 0,0:16:32.46,0:16:34.22,Default,,0,0,0,,这里 我们放入了一个常量F Dialogue: 0,0:16:35.44,0:16:37.02,Default,,0,0,0,,这里又放了一个常量X Dialogue: 0,0:16:40.02,0:16:42.41,Default,,0,0,0,,因此 这个编译器又稍微好一点 Dialogue: 0,0:16:43.79,0:16:46.76,Default,,0,0,0,,但它还是比较蠢 Dialogue: 0,0:16:47.95,0:16:49.58,Default,,0,0,0,,它仍会做很多蠢事 Dialogue: 0,0:16:50.45,0:16:52.52,Default,,0,0,0,,我们再看幻灯片 Dialogue: 0,0:16:52.88,0:16:53.93,Default,,0,0,0,,看最开头的地方 Dialogue: 0,0:16:56.34,0:16:58.17,Default,,0,0,0,,我们调用(SAVE ENV)保存环境 Dialogue: 0,0:16:59.35,0:17:01.72,Default,,0,0,0,,然后给VAL寄存器赋某个值 Dialogue: 0,0:17:01.80,0:17:03.35,Default,,0,0,0,,然后恢复环境 Dialogue: 0,0:17:03.35,0:17:04.41,Default,,0,0,0,,它是从哪来的 Dialogue: 0,0:17:04.91,0:17:07.10,Default,,0,0,0,,它来自求值器的这个地方 Dialogue: 0,0:17:07.15,0:17:10.28,Default,,0,0,0,,哦 我在正在对一个应用求值 Dialogue: 0,0:17:11.10,0:17:14.68,Default,,0,0,0,,因此我要递归调用EVAL-DISPATCH Dialogue: 0,0:17:15.87,0:17:17.98,Default,,0,0,0,,我最好把接下来要用到的东西 Dialogue: 0,0:17:17.98,0:17:19.08,Default,,0,0,0,,保存到环境中 Dialogue: 0,0:17:19.77,0:17:22.86,Default,,0,0,0,,这就是递归调用EVAL-DISPATCH的结果 Dialogue: 0,0:17:23.47,0:17:25.77,Default,,0,0,0,,刚才那个例子就是对符号F求值的结果 Dialogue: 0,0:17:26.50,0:17:28.27,Default,,0,0,0,,从EVAL-DISPATCH中返回 Dialogue: 0,0:17:28.28,0:17:29.66,Default,,0,0,0,,将环境恢复 Dialogue: 0,0:17:31.25,0:17:32.28,Default,,0,0,0,,但是实际上 Dialogue: 0,0:17:32.59,0:17:35.88,Default,,0,0,0,,这个求值过程中 所进行的操作 Dialogue: 0,0:17:35.92,0:17:37.71,Default,,0,0,0,,完全不会影响环境 Dialogue: 0,0:17:38.67,0:17:40.80,Default,,0,0,0,,所以这里没必要先保存环境 Dialogue: 0,0:17:40.84,0:17:42.22,Default,,0,0,0,,再恢复环境 Dialogue: 0,0:17:45.67,0:17:46.62,Default,,0,0,0,,与之类似 Dialogue: 0,0:17:49.79,0:17:51.39,Default,,0,0,0,,这里 我们保存了参数表 Dialogue: 0,0:17:53.07,0:17:55.80,Default,,0,0,0,,那是一个求值参数的循环 Dialogue: 0,0:17:55.82,0:17:56.86,Default,,0,0,0,,先保存参数表 Dialogue: 0,0:17:57.20,0:17:58.03,Default,,0,0,0,,然后在这里恢复 Dialogue: 0,0:17:58.08,0:18:00.51,Default,,0,0,0,,但事实上最后 Dialogue: 0,0:18:00.80,0:18:02.28,Default,,0,0,0,,并没有变更参数表 Dialogue: 0,0:18:02.84,0:18:04.17,Default,,0,0,0,,所以不需要保存它 Dialogue: 0,0:18:08.65,0:18:12.88,Default,,0,0,0,,换种方式来说 Dialogue: 0,0:18:13.77,0:18:14.80,Default,,0,0,0,,怎么说呢 Dialogue: 0,0:18:16.43,0:18:19.13,Default,,0,0,0,,求值器需要最大限度地保持悲观 Dialogue: 0,0:18:19.87,0:18:21.07,Default,,0,0,0,,因为 从它的视角来看 Dialogue: 0,0:18:21.08,0:18:23.06,Default,,0,0,0,,只知道接下来是要对某些东西进行求值 Dialogue: 0,0:18:23.24,0:18:24.97,Default,,0,0,0,,所以最好把稍后要用的都存下来 Dialogue: 0,0:18:26.12,0:18:27.79,Default,,0,0,0,,一旦你完成了分析 Dialogue: 0,0:18:27.82,0:18:29.68,Default,,0,0,0,,从编译器的角度就会考虑 Dialogue: 0,0:18:29.72,0:18:31.47,Default,,0,0,0,,哪些是我真正需要存下来的? Dialogue: 0,0:18:32.12,0:18:33.31,Default,,0,0,0,,我们需要去 -- Dialogue: 0,0:18:33.42,0:18:37.30,Default,,0,0,0,,它不需要像求值器一样小心翼翼 Dialogue: 0,0:18:37.30,0:18:38.80,Default,,0,0,0,,因为它知道 实际需要什么 Dialogue: 0,0:18:39.69,0:18:41.16,Default,,0,0,0,,无论如何 如果我们完成了优化 Dialogue: 0,0:18:42.50,0:18:45.71,Default,,0,0,0,,消除掉所有多余的保存和恢复 Dialogue: 0,0:18:46.40,0:18:49.05,Default,,0,0,0,,那么我们可以得到这样的结果 Dialogue: 0,0:18:49.90,0:18:51.53,Default,,0,0,0,,我们可以发现 Dialogue: 0,0:18:51.64,0:18:53.71,Default,,0,0,0,,只有三条指令是必须的 Dialogue: 0,0:18:54.07,0:18:55.72,Default,,0,0,0,,从刚才的11条指令优化成这样 Dialogue: 0,0:18:55.97,0:18:58.81,Default,,0,0,0,,或是从原始的20条指令优化而来 Dialogue: 0,0:18:59.87,0:19:00.92,Default,,0,0,0,,这告诉我们 Dialogue: 0,0:19:01.12,0:19:03.18,Default,,0,0,0,,对于这些寄存器操作 Dialogue: 0,0:19:03.27,0:19:04.94,Default,,0,0,0,,哪些是必需的? Dialogue: 0,0:19:09.42,0:19:11.74,Default,,0,0,0,,让我换个方式来总结一下 Dialogue: 0,0:19:11.74,0:19:13.48,Default,,0,0,0,,我先给你们看一张图 Dialogue: 0,0:19:16.00,0:19:17.52,Default,,0,0,0,,这张图片 Dialogue: 0,0:19:18.77,0:19:20.81,Default,,0,0,0,,展示了所有的保存和恢复 Dialogue: 0,0:19:23.50,0:19:25.23,Default,,0,0,0,,这里是表达式(F X) Dialogue: 0,0:19:25.32,0:19:27.87,Default,,0,0,0,,在下面这里 Dialogue: 0,0:19:28.75,0:19:31.80,Default,,0,0,0,,是对求值器中各种地方的跟踪 Dialogue: 0,0:19:34.97,0:19:38.04,Default,,0,0,0,,在求值发生时会使用这些地方 Dialogue: 0,0:19:38.04,0:19:40.01,Default,,0,0,0,,在这里 你可以看到箭头 Dialogue: 0,0:19:40.22,0:19:42.08,Default,,0,0,0,,下箭头代表寄存器的保存 Dialogue: 0,0:19:42.40,0:19:44.84,Default,,0,0,0,,所以最先保存的是ENV寄存器 Dialogue: 0,0:19:46.82,0:19:48.68,Default,,0,0,0,,然后 在这里恢复ENV Dialogue: 0,0:19:52.38,0:19:54.54,Default,,0,0,0,,这些都是成对的栈操作 Dialogue: 0,0:19:56.12,0:19:57.56,Default,,0,0,0,,如果你更进一步 Dialogue: 0,0:19:58.12,0:20:00.78,Default,,0,0,0,,我们记得 Dialogue: 0,0:20:00.89,0:20:03.02,Default,,0,0,0,,UNEV是个完全没用的寄存器 Dialogue: 0,0:20:07.80,0:20:09.78,Default,,0,0,0,,如果我们用固定结构的代码 Dialogue: 0,0:20:09.78,0:20:12.52,Default,,0,0,0,,就不需要保存UNEV 因为完全用不上 Dialogue: 0,0:20:16.20,0:20:19.15,Default,,0,0,0,,然后 根据我们约定的 Dialogue: 0,0:20:19.16,0:20:21.88,Default,,0,0,0,,应用过程的准则 Dialogue: 0,0:20:21.88,0:20:23.85,Default,,0,0,0,,我们会选择是否保存CONTINUE Dialogue: 0,0:20:27.40,0:20:28.74,Default,,0,0,0,,这就是我们做的第一件事 Dialogue: 0,0:20:28.74,0:20:30.51,Default,,0,0,0,,然后我们可以看看 Dialogue: 0,0:20:31.71,0:20:32.70,Default,,0,0,0,,实际需要些什么 Dialogue: 0,0:20:33.07,0:20:35.56,Default,,0,0,0,,其实在求值F的过程中 Dialogue: 0,0:20:36.04,0:20:37.82,Default,,0,0,0,,我们不需要保存ENV Dialogue: 0,0:20:38.08,0:20:39.92,Default,,0,0,0,,因为它不会被破坏 Dialogue: 0,0:20:39.92,0:20:41.31,Default,,0,0,0,,因此 如果我们利用这点 Dialogue: 0,0:20:44.12,0:20:47.56,Default,,0,0,0,,这里对F的求值 Dialogue: 0,0:20:48.57,0:20:50.44,Default,,0,0,0,,完全不需要担心 Dialogue: 0,0:20:51.61,0:20:52.60,Default,,0,0,0,,会破坏ENV Dialogue: 0,0:20:52.60,0:20:54.94,Default,,0,0,0,,类似地 这里对X的求值 Dialogue: 0,0:20:57.17,0:20:58.89,Default,,0,0,0,,当求值器进行求值时 它会说 Dialogue: 0,0:20:58.91,0:21:01.64,Default,,0,0,0,,我最好保存好与之有关的FUN寄存器 Dialogue: 0,0:21:02.07,0:21:03.22,Default,,0,0,0,,因为后面也许会用得着 Dialogue: 0,0:21:03.28,0:21:04.89,Default,,0,0,0,,我最好也保存参数表 Dialogue: 0,0:21:06.90,0:21:09.05,Default,,0,0,0,,然而 在这如果是编译器的话 Dialogue: 0,0:21:09.05,0:21:10.38,Default,,0,0,0,,实际需要哪些寄存器 Dialogue: 0,0:21:10.52,0:21:11.84,Default,,0,0,0,,从而进行相关的保存与恢复 Dialogue: 0,0:21:12.70,0:21:16.09,Default,,0,0,0,,事实上 这里求值器做的所有栈操作 Dialogue: 0,0:21:16.32,0:21:19.58,Default,,0,0,0,,都证明是过于悲观而不必要 Dialogue: 0,0:21:19.62,0:21:21.45,Default,,0,0,0,,而编译器在这里是知道这一点的 Dialogue: 0,0:21:27.35,0:21:28.48,Default,,0,0,0,,这是最基础的想法 Dialogue: 0,0:21:29.80,0:21:31.00,Default,,0,0,0,,我们把求值器 Dialogue: 0,0:21:31.00,0:21:33.24,Default,,0,0,0,,剔除那些不需要的东西 Dialogue: 0,0:21:33.24,0:21:35.24,Default,,0,0,0,,去除那些对于编译器完全无用的东西 Dialogue: 0,0:21:35.24,0:21:36.19,Default,,0,0,0,,只保留求值的部分 Dialogue: 0,0:21:37.40,0:21:40.40,Default,,0,0,0,,然后你可以看到哪些栈操作是不必要的 Dialogue: 0,0:21:40.82,0:21:43.76,Default,,0,0,0,,这就是书中所描述的编译器 Dialogue: 0,0:21:43.85,0:21:45.04,Default,,0,0,0,,的基本结构 Dialogue: 0,0:21:45.04,0:21:47.00,Default,,0,0,0,,我给你们展示一下这 Dialogue: 0,0:21:47.76,0:21:49.68,Default,,0,0,0,,这个简单的例子 Dialogue: 0,0:21:51.20,0:21:53.26,Default,,0,0,0,,为了说清楚 多余的东西是怎样保存的 Dialogue: 0,0:21:53.29,0:21:56.06,Default,,0,0,0,,我们来看一个稍复杂的表达式 Dialogue: 0,0:21:58.15,0:22:01.93,Default,,0,0,0,,(F (G X) 1) Dialogue: 0,0:22:03.87,0:22:05.52,Default,,0,0,0,,我们不会讲解所有的代码 Dialogue: 0,0:22:06.40,0:22:08.56,Default,,0,0,0,,因为代码有点多 Dialogue: 0,0:22:09.72,0:22:12.35,Default,,0,0,0,,我认为在求值器在处理它时 Dialogue: 0,0:22:12.35,0:22:14.67,Default,,0,0,0,,大概会产生 Dialogue: 0,0:22:14.70,0:22:16.25,Default,,0,0,0,,16对保存-恢复操作 Dialogue: 0,0:22:17.00,0:22:18.57,Default,,0,0,0,,这有一张图表 Dialogue: 0,0:22:20.57,0:22:21.95,Default,,0,0,0,,演示了其中的过程 Dialogue: 0,0:22:22.97,0:22:23.90,Default,,0,0,0,,你从这里开始-- Dialogue: 0,0:22:24.25,0:22:26.62,Default,,0,0,0,,求值器说:“我要求值一个应用” Dialogue: 0,0:22:26.90,0:22:29.13,Default,,0,0,0,,在这里保存ENV 又在这里恢复 Dialogue: 0,0:22:30.65,0:22:34.44,Default,,0,0,0,,然后处理第一个运算对象 Dialogue: 0,0:22:36.81,0:22:39.28,Default,,0,0,0,,这是求值器的递归调用 Dialogue: 0,0:22:39.28,0:22:40.89,Default,,0,0,0,,求值器发现 这是一个应用 Dialogue: 0,0:22:40.91,0:22:42.10,Default,,0,0,0,,又会保存环境 Dialogue: 0,0:22:42.10,0:22:44.97,Default,,0,0,0,,求值组合式的运算符 然后在这里恢复环境 Dialogue: 0,0:22:45.80,0:22:48.92,Default,,0,0,0,,这个恢复匹配的是这个保存操作 Dialogue: 0,0:22:49.77,0:22:50.78,Default,,0,0,0,,以此类推 Dialogue: 0,0:22:51.65,0:22:52.51,Default,,0,0,0,,这里的UNEV Dialogue: 0,0:22:52.52,0:22:54.62,Default,,0,0,0,,完全没有必要存在 Dialogue: 0,0:22:54.97,0:22:56.60,Default,,0,0,0,,CONTINUE寄存器不断地被保存-恢复 Dialogue: 0,0:22:57.42,0:23:00.41,Default,,0,0,0,,而FUN寄存器则是在 Dialogue: 0,0:23:00.78,0:23:04.36,Default,,0,0,0,,处理运算对象期间被保存 Dialogue: 0,0:23:05.10,0:23:06.52,Default,,0,0,0,,这类的事情一直在发生 Dialogue: 0,0:23:06.78,0:23:09.39,Default,,0,0,0,,但如果你问 跟求值器相比 Dialogue: 0,0:23:09.87,0:23:11.66,Default,,0,0,0,,编译器究竟要做什么? Dialogue: 0,0:23:12.27,0:23:13.55,Default,,0,0,0,,你会去掉一大堆东西 Dialogue: 0,0:23:14.30,0:23:16.64,Default,,0,0,0,,在这个的基础上 如果你说 Dialogue: 0,0:23:19.40,0:23:22.54,Default,,0,0,0,,对F的求值不会修改ENV寄存器 Dialogue: 0,0:23:23.82,0:23:26.51,Default,,0,0,0,,或者对符号X的查找 Dialogue: 0,0:23:29.28,0:23:32.09,Default,,0,0,0,,不需要特别保护FUN寄存器 Dialogue: 0,0:23:34.30,0:23:37.60,Default,,0,0,0,,就得到了只有几对的保存-恢复操作 Dialogue: 0,0:23:40.25,0:23:42.27,Default,,0,0,0,,然而 你还可以再优化一下 Dialogue: 0,0:23:42.27,0:23:44.33,Default,,0,0,0,,看看这里的ENV寄存器发生了什么 Dialogue: 0,0:23:45.21,0:23:47.39,Default,,0,0,0,,我们观察ENV寄存器的操作 发现 Dialogue: 0,0:23:51.00,0:23:52.25,Default,,0,0,0,,这是一个组合式 Dialogue: 0,0:23:54.33,0:23:55.69,Default,,0,0,0,,而这个求值器 Dialogue: 0,0:23:55.78,0:23:57.27,Default,,0,0,0,,对G一无所知 Dialogue: 0,0:23:58.57,0:24:00.73,Default,,0,0,0,,所以在这 它说 Dialogue: 0,0:24:01.29,0:24:03.45,Default,,0,0,0,,我最好保存ENV寄存器 Dialogue: 0,0:24:03.96,0:24:05.42,Default,,0,0,0,,因为对G的求值 Dialogue: 0,0:24:05.42,0:24:07.42,Default,,0,0,0,,可能会修改ENV寄存器的值 Dialogue: 0,0:24:07.55,0:24:09.45,Default,,0,0,0,,而我稍后可能会需要它 Dialogue: 0,0:24:10.17,0:24:11.40,Default,,0,0,0,,在这个参数之后 Dialogue: 0,0:24:12.22,0:24:13.37,Default,,0,0,0,,在处理第二个参数的时候 Dialogue: 0,0:24:15.60,0:24:17.24,Default,,0,0,0,,这就是为什么它没被优化掉 Dialogue: 0,0:24:19.07,0:24:22.54,Default,,0,0,0,,因为编译器没有对G将要做的事情做任何假设 Dialogue: 0,0:24:22.54,0:24:23.60,Default,,0,0,0,,另一方面 Dialogue: 0,0:24:24.61,0:24:26.52,Default,,0,0,0,,如果你看看这里的第二个参数 Dialogue: 0,0:24:26.64,0:24:27.70,Default,,0,0,0,,它只是查找“1”这个常量 Dialogue: 0,0:24:27.70,0:24:29.60,Default,,0,0,0,,这不需要ENV寄存器 Dialogue: 0,0:24:30.77,0:24:32.04,Default,,0,0,0,,因此没必要保存它 Dialogue: 0,0:24:32.06,0:24:33.77,Default,,0,0,0,,事实上 你也可以把这个也去掉 Dialogue: 0,0:24:34.85,0:24:37.81,Default,,0,0,0,,这一堆寄存器操作 Dialogue: 0,0:24:37.98,0:24:40.08,Default,,0,0,0,,如果你像这样简单地推理的话 Dialogue: 0,0:24:40.55,0:24:43.05,Default,,0,0,0,,只会剩下两对保存-恢复操作 Dialogue: 0,0:24:45.10,0:24:46.97,Default,,0,0,0,,而这些 如果你知道关于G的某些信息的话 Dialogue: 0,0:24:47.52,0:24:49.08,Default,,0,0,0,,可以进一步优化 Dialogue: 0,0:24:56.27,0:24:57.85,Default,,0,0,0,,基本的理念是 Dialogue: 0,0:24:57.95,0:24:59.98,Default,,0,0,0,,编译器之所以更好 Dialogue: 0,0:24:59.98,0:25:02.56,Default,,0,0,0,,是因为解释器对于将要处理的东西一无所知 Dialogue: 0,0:25:03.25,0:25:05.04,Default,,0,0,0,,它不得不以最悲观的方式保存东西 Dialogue: 0,0:25:05.05,0:25:06.70,Default,,0,0,0,,来保护它自己 Dialogue: 0,0:25:07.90,0:25:08.76,Default,,0,0,0,,而编译器 Dialogue: 0,0:25:09.48,0:25:12.38,Default,,0,0,0,,只需要保存实际需要的东西 Dialogue: 0,0:25:13.37,0:25:15.20,Default,,0,0,0,,某个东西是否需要保存 Dialogue: 0,0:25:15.24,0:25:17.37,Default,,0,0,0,,有两种原因 Dialogue: 0,0:25:17.82,0:25:18.70,Default,,0,0,0,,一种是 Dialogue: 0,0:25:18.70,0:25:19.82,Default,,0,0,0,,你保护的东西 Dialogue: 0,0:25:19.95,0:25:21.44,Default,,0,0,0,,不会修改寄存器 Dialogue: 0,0:25:22.08,0:25:23.58,Default,,0,0,0,,例如 变量查找 Dialogue: 0,0:25:24.12,0:25:25.20,Default,,0,0,0,,另一种原因是 Dialogue: 0,0:25:25.32,0:25:27.10,Default,,0,0,0,,你所保存的东西 Dialogue: 0,0:25:28.28,0:25:29.92,Default,,0,0,0,,最后并不会被用到 Dialogue: 0,0:25:30.81,0:25:34.27,Default,,0,0,0,,因此 编译器正是利用了 Dialogue: 0,0:25:34.30,0:25:35.88,Default,,0,0,0,,这两条基本原则 Dialogue: 0,0:25:36.27,0:25:37.76,Default,,0,0,0,,来让代码变得更高效的 Dialogue: 0,0:25:44.27,0:25:45.32,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:25:51.20,0:25:53.10,Default,,0,0,0,,学生: 你一直在说UNEV寄存器 Dialogue: 0,0:25:53.13,0:25:56.40,Default,,0,0,0,,UNEV寄存器完全不会被用到 Dialogue: 0,0:25:56.41,0:25:58.68,Default,,0,0,0,,是否意味着 机器只需要6个寄存器足矣? Dialogue: 0,0:25:58.70,0:26:00.08,Default,,0,0,0,,或者是说 在这个特定的例子里 Dialogue: 0,0:26:00.11,0:26:01.18,Default,,0,0,0,,它没有被用到? Dialogue: 0,0:26:01.72,0:26:02.81,Default,,0,0,0,,教授: 对于编译器 Dialogue: 0,0:26:04.31,0:26:07.42,Default,,0,0,0,,你可以生成6个或5个寄存器的代码 Dialogue: 0,0:26:07.56,0:26:09.02,Default,,0,0,0,,因为EXP寄存器也没有用到 Dialogue: 0,0:26:09.40,0:26:14.57,Default,,0,0,0,,是的 你可以把EXP和UNEV都去掉 Dialogue: 0,0:26:14.57,0:26:16.87,Default,,0,0,0,,因为这些是求值器的数据结构 Dialogue: 0,0:26:17.36,0:26:19.36,Default,,0,0,0,,以编译器的视角来看 Dialogue: 0,0:26:19.39,0:26:20.87,Default,,0,0,0,,这些东西都是常量 Dialogue: 0,0:26:21.65,0:26:22.44,Default,,0,0,0,,关键在于 Dialogue: 0,0:26:22.48,0:26:24.59,Default,,0,0,0,,这个特定编译器是被构造出来的 Dialogue: 0,0:26:24.79,0:26:27.92,Default,,0,0,0,,因此被解释的代码和被编译的代码可以共存 Dialogue: 0,0:26:29.32,0:26:30.72,Default,,0,0,0,,可以这样看待它 Dialogue: 0,0:26:30.97,0:26:32.29,Default,,0,0,0,,你构建了一个芯片 Dialogue: 0,0:26:34.30,0:26:35.50,Default,,0,0,0,,它就是求值器 Dialogue: 0,0:26:35.88,0:26:37.28,Default,,0,0,0,,而编译器可以做的就是 Dialogue: 0,0:26:37.31,0:26:39.02,Default,,0,0,0,,为这个芯片生成代码 Dialogue: 0,0:26:40.40,0:26:41.90,Default,,0,0,0,,只是它不会用到两个寄存器而已 Dialogue: 0,0:26:51.52,0:26:52.47,Default,,0,0,0,,好 休息一会 Dialogue: 0,0:26:53.55,0:27:07.18,Default,,0,0,0,,[音乐] Dialogue: 0,0:27:07.37,0:27:11.42,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:27:14.57,0:27:18.12,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:27:18.17,0:27:22.08,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:27:22.22,0:27:26.48,Declare,,0,0,0,,{\an2\fad(500,500)}编译 Dialogue: 0,0:27:29.21,0:27:32.43,Default,,0,0,0,,我们刚才研究了编译器应该要做什么 Dialogue: 0,0:27:32.78,0:27:36.04,Default,,0,0,0,,现在我们来简略地看看 Dialogue: 0,0:27:36.15,0:27:37.47,Default,,0,0,0,,这些目标如何达成 Dialogue: 0,0:27:38.26,0:27:39.58,Default,,0,0,0,,而我不会给出细节 Dialogue: 0,0:27:39.60,0:27:42.17,Default,,0,0,0,,在书中有一大堆代码 Dialogue: 0,0:27:42.22,0:27:43.42,Default,,0,0,0,,展示了所有细节 Dialogue: 0,0:27:43.45,0:27:45.31,Default,,0,0,0,,我要做的 是给你们展示 Dialogue: 0,0:27:45.96,0:27:47.26,Default,,0,0,0,,其中的关键思想 Dialogue: 0,0:27:49.49,0:27:51.36,Default,,0,0,0,,换个时间再来关心细节 Dialogue: 0,0:27:51.51,0:27:55.30,Default,,0,0,0,,设想我们正在编译一条表达式 Dialogue: 0,0:27:55.30,0:27:57.01,Default,,0,0,0,,这里有一些运算符 Dialogue: 0,0:27:57.48,0:27:58.56,Default,,0,0,0,,和两个参数 Dialogue: 0,0:28:03.56,0:28:04.24,Default,,0,0,0,,现在 Dialogue: 0,0:28:06.27,0:28:08.14,Default,,0,0,0,,这个编译器会生成什么代码? Dialogue: 0,0:28:08.85,0:28:09.78,Default,,0,0,0,,首先 Dialogue: 0,0:28:09.83,0:28:11.20,Default,,0,0,0,,它会递归运行 Dialogue: 0,0:28:11.90,0:28:13.28,Default,,0,0,0,,编译运算符 Dialogue: 0,0:28:14.37,0:28:19.02,Default,,0,0,0,,它说 我要编译运算符 Dialogue: 0,0:28:21.16,0:28:24.54,Default,,0,0,0,,最后我需要让它们的结果 Dialogue: 0,0:28:24.84,0:28:27.95,Default,,0,0,0,,存放在FUN寄存器中 Dialogue: 0,0:28:28.42,0:28:29.60,Default,,0,0,0,,所以我编译一些指令 Dialogue: 0,0:28:29.64,0:28:31.56,Default,,0,0,0,,它们会编译运算符 Dialogue: 0,0:28:31.69,0:28:38.62,Default,,0,0,0,,最后把结果放在FUN寄存器中 Dialogue: 0,0:28:45.51,0:28:46.94,Default,,0,0,0,,接下来我要做的是 Dialogue: 0,0:28:47.71,0:28:49.68,Default,,0,0,0,,另一个代码片段则说 Dialogue: 0,0:28:49.68,0:28:55.17,Default,,0,0,0,,我要编译第一个参数 Dialogue: 0,0:28:55.17,0:28:56.80,Default,,0,0,0,,因此它递归调地用自己 Dialogue: 0,0:28:58.04,0:29:03.36,Default,,0,0,0,,而结果会被放在VAL中 Dialogue: 0,0:29:09.07,0:29:10.75,Default,,0,0,0,,接下来需要做的是 Dialogue: 0,0:29:10.75,0:29:12.26,Default,,0,0,0,,建立起参数表 Dialogue: 0,0:29:12.95,0:29:25.50,Default,,0,0,0,,(ASSIGN ARGL (CONS (FETCH -- Dialogue: 0,0:29:25.55,0:29:27.10,Default,,0,0,0,,它会生成这些代码 Dialogue: 0,0:29:27.50,0:29:32.51,Default,,0,0,0,,(FETCH VAL) '())) Dialogue: 0,0:29:35.00,0:29:36.05,Default,,0,0,0,,然而 Dialogue: 0,0:29:37.99,0:29:40.61,Default,,0,0,0,,当它到这里时 Dialogue: 0,0:29:41.32,0:29:42.82,Default,,0,0,0,,它可能需要环境 Dialogue: 0,0:29:43.95,0:29:45.29,Default,,0,0,0,,它需要环境 Dialogue: 0,0:29:45.32,0:29:48.21,Default,,0,0,0,,这是求值第一个参数所需要的 Dialogue: 0,0:29:49.04,0:29:51.18,Default,,0,0,0,,因此 它需要保证 Dialogue: 0,0:29:51.92,0:29:53.76,Default,,0,0,0,,对运算对象的编译 Dialogue: 0,0:29:55.32,0:29:57.85,Default,,0,0,0,,或者说它需要保护FUN寄存器 Dialogue: 0,0:29:58.01,0:30:00.98,Default,,0,0,0,,来应对编译运算对象时发生的各种情况 Dialogue: 0,0:30:01.30,0:30:03.08,Default,,0,0,0,,因此它在这做了个标注说 Dialogue: 0,0:30:03.37,0:30:12.89,Default,,0,0,0,,这个片段需要保护ENV寄存器 Dialogue: 0,0:30:17.39,0:30:18.44,Default,,0,0,0,,与之类似 这里 Dialogue: 0,0:30:21.02,0:30:23.30,Default,,0,0,0,,在完成第一个运算对象的编译后 Dialogue: 0,0:30:23.57,0:30:24.67,Default,,0,0,0,,它会说 我最好-- Dialogue: 0,0:30:24.71,0:30:27.92,Default,,0,0,0,,我需要知道第二个运算对象的环境 Dialogue: 0,0:30:27.92,0:30:29.46,Default,,0,0,0,,所以它在这做了个标注 Dialogue: 0,0:30:29.71,0:30:35.96,Default,,0,0,0,,这里也需要保护ENV Dialogue: 0,0:30:39.42,0:30:41.02,Default,,0,0,0,,现在它继续运行 Dialogue: 0,0:30:41.12,0:30:42.83,Default,,0,0,0,,下一段代码 Dialogue: 0,0:30:43.31,0:30:49.74,Default,,0,0,0,,是要编译第二个参数 Dialogue: 0,0:30:50.82,0:30:52.64,Default,,0,0,0,,它将会 Dialogue: 0,0:30:52.99,0:30:59.28,Default,,0,0,0,,把编译的结果按约定放入到VAL中 Dialogue: 0,0:31:03.86,0:31:06.70,Default,,0,0,0,,随后它会生成一条指令 Dialogue: 0,0:31:07.84,0:31:09.25,Default,,0,0,0,,从而建立起参数表 Dialogue: 0,0:31:09.55,0:31:15.28,Default,,0,0,0,,(ASSIGN ARGL Dialogue: 0,0:31:20.22,0:31:28.94,Default,,0,0,0,,(CONS (FETCH VAL) (FETCH ARGL)) Dialogue: 0,0:31:33.97,0:31:34.64,Default,,0,0,0,,然而 Dialogue: 0,0:31:34.81,0:31:36.58,Default,,0,0,0,,为了取得旧的参数表 Dialogue: 0,0:31:37.15,0:31:40.99,Default,,0,0,0,,它最好保证这期间发生的任何事情 Dialogue: 0,0:31:41.30,0:31:42.69,Default,,0,0,0,,都不影响旧的参数表 Dialogue: 0,0:31:43.50,0:31:45.17,Default,,0,0,0,,因此它在这做了个标注说 Dialogue: 0,0:31:45.34,0:31:51.64,Default,,0,0,0,,哦 这里需要保护ARGL Dialogue: 0,0:31:54.16,0:31:56.03,Default,,0,0,0,,现在参数表就建立好了 Dialogue: 0,0:31:58.01,0:32:02.86,Default,,0,0,0,,现在可以准备去APPLY-DISPATCH了 Dialogue: 0,0:32:07.02,0:32:10.80,Default,,0,0,0,,它生成了这条指令 Dialogue: 0,0:32:15.19,0:32:17.37,Default,,0,0,0,,因为现在参数都在ARGL中 Dialogue: 0,0:32:18.15,0:32:20.59,Default,,0,0,0,,运算符在FUN中 Dialogue: 0,0:32:20.59,0:32:22.89,Default,,0,0,0,,如果只是单纯地把运算符放到FUN寄存器中 Dialogue: 0,0:32:23.27,0:32:26.64,Default,,0,0,0,,就需要它保证这块代码 Dialogue: 0,0:32:27.09,0:32:29.27,Default,,0,0,0,,不会破坏FUN寄存器里的东西 Dialogue: 0,0:32:29.67,0:32:31.24,Default,,0,0,0,,所以它在这做了个标注说 Dialogue: 0,0:32:31.55,0:32:32.73,Default,,0,0,0,,这里的所有东西 Dialogue: 0,0:32:34.88,0:32:40.73,Default,,0,0,0,,最好能够在保护FUN寄存器的情况下完成 Dialogue: 0,0:32:43.71,0:32:46.15,Default,,0,0,0,,所以这就是-- Dialogue: 0,0:32:46.15,0:32:47.10,Default,,0,0,0,,基本上来说 Dialogue: 0,0:32:48.20,0:32:50.24,Default,,0,0,0,,编译器所做的就是 Dialogue: 0,0:32:50.54,0:32:52.46,Default,,0,0,0,,追加一大堆的代码 Dialogue: 0,0:32:53.50,0:32:58.83,Default,,0,0,0,,而这些代码之中都是一些基本运算 Dialogue: 0,0:32:58.86,0:33:00.12,Default,,0,0,0,,比如符号查找 Dialogue: 0,0:33:01.44,0:33:02.60,Default,,0,0,0,,条件分支的处理 Dialogue: 0,0:33:02.64,0:33:05.44,Default,,0,0,0,,都是一些琐碎的事情 Dialogue: 0,0:33:05.44,0:33:07.99,Default,,0,0,0,,然后按照这种准则将它们追加到一起 Dialogue: 0,0:33:08.78,0:33:10.79,Default,,0,0,0,,因此 组合的基本手段就是 Dialogue: 0,0:33:10.86,0:33:13.18,Default,,0,0,0,,将一段代码追加到另一段的后面 Dialogue: 0,0:33:21.55,0:33:22.86,Default,,0,0,0,,就是这里发生的事情 Dialogue: 0,0:33:25.58,0:33:27.24,Default,,0,0,0,,这有点取巧 Dialogue: 0,0:33:27.56,0:33:30.37,Default,,0,0,0,,向一段代码后面追加代码的思路是 Dialogue: 0,0:33:31.60,0:33:33.76,Default,,0,0,0,,小心保护寄存器 Dialogue: 0,0:33:35.63,0:33:37.93,Default,,0,0,0,,追加操作看起来像这样 Dialogue: 0,0:33:39.15,0:33:40.65,Default,,0,0,0,,它要做的是 Dialogue: 0,0:33:41.20,0:33:44.11,Default,,0,0,0,,代码的追加是这么来做的 Dialogue: 0,0:33:44.53,0:33:53.63,Default,,0,0,0,,如果SEQ1需要寄存器-- Dialogue: 0,0:33:53.66,0:33:54.72,Default,,0,0,0,,我应该改一下这个 Dialogue: 0,0:33:54.72,0:33:56.87,Default,,0,0,0,,在SEQ1后面追加SEQ2 Dialogue: 0,0:33:57.42,0:34:03.96,Default,,0,0,0,,并保护一些寄存器 Dialogue: 0,0:34:08.52,0:34:09.91,Default,,0,0,0,,这里改成AND Dialogue: 0,0:34:11.36,0:34:13.03,Default,,0,0,0,,这样的话前后顺序就清楚了 Dialogue: 0,0:34:13.88,0:34:19.87,Default,,0,0,0,,如果SEQ2需要寄存器 Dialogue: 0,0:34:21.12,0:34:27.85,Default,,0,0,0,,而SEQ1又修改了寄存器 Dialogue: 0,0:34:33.68,0:34:36.30,Default,,0,0,0,,那么编译器生成的指令是 Dialogue: 0,0:34:36.97,0:34:41.34,Default,,0,0,0,,保存寄存器 Dialogue: 0,0:34:43.02,0:34:44.19,Default,,0,0,0,,这就是代码 Dialogue: 0,0:34:44.35,0:34:45.35,Default,,0,0,0,,生成这段代码 Dialogue: 0,0:34:45.35,0:34:46.28,Default,,0,0,0,,保存寄存器 Dialogue: 0,0:34:46.72,0:34:52.97,Default,,0,0,0,,然后写下递归编译SEQ1的结果 Dialogue: 0,0:34:53.30,0:34:54.84,Default,,0,0,0,,然后恢复寄存器 Dialogue: 0,0:35:00.52,0:35:03.92,Default,,0,0,0,,再写下递归编译 Dialogue: 0,0:35:04.46,0:35:05.47,Default,,0,0,0,,SEQ2的结果 Dialogue: 0,0:35:07.07,0:35:09.62,Default,,0,0,0,,这就是你需要做的 Dialogue: 0,0:35:09.62,0:35:11.82,Default,,0,0,0,,实际上SEQ2需要寄存器 Dialogue: 0,0:35:11.82,0:35:13.74,Default,,0,0,0,,而SEQ1改动了它 Dialogue: 0,0:35:15.12,0:35:17.07,Default,,0,0,0,,否则的话 Dialogue: 0,0:35:20.50,0:35:26.57,Default,,0,0,0,,得到的就是SEQ1后面跟着SEQ2 Dialogue: 0,0:35:28.17,0:35:30.30,Default,,0,0,0,,这就是把两个代码片段 Dialogue: 0,0:35:30.59,0:35:33.52,Default,,0,0,0,,连接到一起的基本操作 Dialogue: 0,0:35:33.93,0:35:35.93,Default,,0,0,0,,把这些指令组合成序列 Dialogue: 0,0:35:36.89,0:35:38.87,Default,,0,0,0,,我们可以发现 从这个角度看 Dialogue: 0,0:35:40.94,0:35:45.96,Default,,0,0,0,,解释器和编译器的区别 Dialogue: 0,0:35:46.82,0:35:49.34,Default,,0,0,0,,是编译器有保护寄存器的标注 Dialogue: 0,0:35:50.14,0:35:52.22,Default,,0,0,0,,上面记录着 Dialogue: 0,0:35:52.49,0:35:54.22,Default,,0,0,0,,是否需要生成保存-恢复代码 Dialogue: 0,0:35:55.19,0:35:57.24,Default,,0,0,0,,而解释器会以最悲观的方式处理 Dialogue: 0,0:35:57.28,0:35:58.90,Default,,0,0,0,,总是会进行保存-恢复 Dialogue: 0,0:36:00.76,0:36:01.93,Default,,0,0,0,,这就是关键的区别 Dialogue: 0,0:36:04.16,0:36:06.05,Default,,0,0,0,,为了实现这个 Dialogue: 0,0:36:06.65,0:36:09.40,Default,,0,0,0,,编译器需要一些理论 Dialogue: 0,0:36:09.56,0:36:11.96,Default,,0,0,0,,来确定代码序列会需要、又会修改哪些寄存器 Dialogue: 0,0:36:14.26,0:36:17.28,Default,,0,0,0,,所以你放入的小片段 Dialogue: 0,0:36:17.48,0:36:21.00,Default,,0,0,0,,例如这段基础代码 Dialogue: 0,0:36:22.74,0:36:24.59,Default,,0,0,0,,当你查找一个变量时 Dialogue: 0,0:36:24.92,0:36:26.04,Default,,0,0,0,,进行了哪些操作? Dialogue: 0,0:36:26.89,0:36:29.02,Default,,0,0,0,,你又是做了些什么 Dialogue: 0,0:36:29.05,0:36:30.68,Default,,0,0,0,,来编译一个常量 Dialogue: 0,0:36:30.97,0:36:32.10,Default,,0,0,0,,或者应用一个函数 Dialogue: 0,0:36:32.97,0:36:34.48,Default,,0,0,0,,它们都会带有一些标注 Dialogue: 0,0:36:34.67,0:36:36.46,Default,,0,0,0,,说明了它们需要的和修改的寄存器 Dialogue: 0,0:36:38.78,0:36:41.50,Default,,0,0,0,,所以底层的数据结构 Dialogue: 0,0:36:42.66,0:36:44.33,Default,,0,0,0,,我会这样讲 Dialogue: 0,0:36:44.39,0:36:47.91,Default,,0,0,0,,传递给编译器的代码序列大概是这样 Dialogue: 0,0:36:48.07,0:36:51.42,Default,,0,0,0,,它里面有实际的指令序列 Dialogue: 0,0:36:55.67,0:36:56.81,Default,,0,0,0,,跟它一起的还有 Dialogue: 0,0:36:57.18,0:37:02.60,Default,,0,0,0,,一组被修改的寄存器 Dialogue: 0,0:37:10.54,0:37:12.60,Default,,0,0,0,,还有一组需要的寄存器 Dialogue: 0,0:37:20.00,0:37:22.46,Default,,0,0,0,,为了能够执行此操作 Dialogue: 0,0:37:23.00,0:37:26.41,Default,,0,0,0,,编译器必须要掌握这些信息 Dialogue: 0,0:37:29.30,0:37:31.08,Default,,0,0,0,,它们从哪来呢 Dialogue: 0,0:37:32.91,0:37:34.49,Default,,0,0,0,,它们来自于--你们可能也想到了 Dialogue: 0,0:37:34.51,0:37:35.53,Default,,0,0,0,,对于那些最基本的片段 Dialogue: 0,0:37:35.55,0:37:36.84,Default,,0,0,0,,我们会手工添加 Dialogue: 0,0:37:37.24,0:37:38.86,Default,,0,0,0,,然后 当我们组合两个序列时 Dialogue: 0,0:37:38.89,0:37:41.02,Default,,0,0,0,,我们会计算出这两个集合 Dialogue: 0,0:37:42.16,0:37:44.12,Default,,0,0,0,,举一个非常基本的例子 Dialogue: 0,0:37:48.43,0:37:51.40,Default,,0,0,0,,例如做一个寄存器赋值 Dialogue: 0,0:37:51.77,0:37:53.50,Default,,0,0,0,,因此 基本代码片段会说 Dialogue: 0,0:37:53.52,0:37:56.22,Default,,0,0,0,,噢 它是个代码片段 Dialogue: 0,0:37:56.22,0:38:03.17,Default,,0,0,0,,代码的指令部分是(ASSIGN R1 (FETCH R2)) Dialogue: 0,0:38:03.17,0:38:04.27,Default,,0,0,0,,这个例子就是这样的 Dialogue: 0,0:38:05.42,0:38:08.52,Default,,0,0,0,,一段指令序列大概就是这样 Dialogue: 0,0:38:08.77,0:38:10.53,Default,,0,0,0,,和它在一起的是 Dialogue: 0,0:38:10.64,0:38:15.76,Default,,0,0,0,,它需要记得修改了R1 Dialogue: 0,0:38:18.60,0:38:21.16,Default,,0,0,0,,然后它需要R2 Dialogue: 0,0:38:24.69,0:38:26.99,Default,,0,0,0,,因此当你开始构建编译器时 Dialogue: 0,0:38:27.10,0:38:29.35,Default,,0,0,0,,你放入这样的一个片段 Dialogue: 0,0:38:30.95,0:38:33.20,Default,,0,0,0,,当它组合两个序列时 Dialogue: 0,0:38:36.70,0:38:38.04,Default,,0,0,0,,我要组合 Dialogue: 0,0:38:38.92,0:38:41.58,Default,,0,0,0,,代码片段S1 Dialogue: 0,0:38:42.88,0:38:47.16,Default,,0,0,0,,修改了一组寄存器M1 Dialogue: 0,0:38:48.45,0:38:51.42,Default,,0,0,0,,并且需要一组寄存器N1 Dialogue: 0,0:38:54.85,0:38:59.48,Default,,0,0,0,,并且我要把它和序列S2组合到一起 Dialogue: 0,0:39:00.81,0:39:05.96,Default,,0,0,0,,后者修改了一组寄存器M2 Dialogue: 0,0:39:07.11,0:39:10.00,Default,,0,0,0,,并且需要一组寄存器N2 Dialogue: 0,0:39:12.44,0:39:14.83,Default,,0,0,0,,这样我们就能得出结果 Dialogue: 0,0:39:15.11,0:39:16.32,Default,,0,0,0,,新的代码片段是这样的 Dialogue: 0,0:39:17.18,0:39:21.82,Default,,0,0,0,,指令序列S1后面跟着S2 Dialogue: 0,0:39:24.09,0:39:26.45,Default,,0,0,0,,它要修改什么? Dialogue: 0,0:39:27.80,0:39:29.18,Default,,0,0,0,,它要修改的是 Dialogue: 0,0:39:29.20,0:39:32.68,Default,,0,0,0,,被S1或者被S2修改的寄存器 Dialogue: 0,0:39:34.00,0:39:36.35,Default,,0,0,0,,N1和N2的并集 Dialogue: 0,0:39:37.68,0:39:39.64,Default,,0,0,0,,就是新的修改集 Dialogue: 0,0:39:40.46,0:39:41.79,Default,,0,0,0,,然后你问 Dialogue: 0,0:39:44.66,0:39:46.41,Default,,0,0,0,,又需要哪些寄存器? Dialogue: 0,0:39:47.95,0:39:49.77,Default,,0,0,0,,需要这些寄存器的是 Dialogue: 0,0:39:49.93,0:39:51.85,Default,,0,0,0,,首先 一定是序列S1需要的 Dialogue: 0,0:39:52.91,0:39:54.49,Default,,0,0,0,,因此必然有N1 Dialogue: 0,0:39:55.19,0:39:58.28,Default,,0,0,0,,然后 并不是N2里面的所有元素 Dialogue: 0,0:39:58.32,0:39:59.61,Default,,0,0,0,,我们都需要 Dialogue: 0,0:39:59.75,0:40:03.49,Default,,0,0,0,,新的修改集需要N2中那些 Dialogue: 0,0:40:03.88,0:40:06.88,Default,,0,0,0,,没有被S1修改过的寄存器 Dialogue: 0,0:40:08.14,0:40:09.72,Default,,0,0,0,,所以 这个并集是N1并上 Dialogue: 0,0:40:11.66,0:40:13.40,Default,,0,0,0,,序列S2的需要集N2 Dialogue: 0,0:40:14.51,0:40:18.52,Default,,0,0,0,,减去序列S1的修改集M1 Dialogue: 0,0:40:19.31,0:40:20.88,Default,,0,0,0,,因为它关心的是如何设置它们 Dialogue: 0,0:40:23.95,0:40:26.26,Default,,0,0,0,,这就是编译器的基本结构 Dialogue: 0,0:40:26.70,0:40:29.82,Default,,0,0,0,,我们进行寄存器优化的方式是 Dialogue: 0,0:40:30.22,0:40:32.70,Default,,0,0,0,,一些策略来应对需要保护的东西 Dialogue: 0,0:40:34.10,0:40:35.63,Default,,0,0,0,,这取决于数据结构 Dialogue: 0,0:40:35.72,0:40:38.51,Default,,0,0,0,,这取决于将东西组合在一起的操作 Dialogue: 0,0:40:39.03,0:40:41.63,Default,,0,0,0,,想知道要保护哪些东西 Dialogue: 0,0:40:41.93,0:40:47.28,Default,,0,0,0,,就需要知道这段代码需要以及修改的寄存器 Dialogue: 0,0:40:48.75,0:40:51.26,Default,,0,0,0,,这就需要我们有一个数据结构 Dialogue: 0,0:40:51.42,0:40:55.43,Default,,0,0,0,,它不但要存放实际的指令序列 Dialogue: 0,0:40:55.60,0:40:57.33,Default,,0,0,0,,它修改了什么 又需要什么 Dialogue: 0,0:40:57.33,0:40:59.77,Default,,0,0,0,,这些信息来自于--最基本的情况是内置的 Dialogue: 0,0:40:59.79,0:41:01.36,Default,,0,0,0,,对于最基本的情况 Dialogue: 0,0:41:01.37,0:41:02.52,Default,,0,0,0,,我们可以容易地知道 Dialogue: 0,0:41:03.00,0:41:04.44,Default,,0,0,0,,需要哪些寄存器 又修改了哪些 Dialogue: 0,0:41:04.82,0:41:05.35,Default,,0,0,0,,另外 Dialogue: 0,0:41:05.44,0:41:08.60,Default,,0,0,0,,利用这个特定的方法构建复杂指令时 Dialogue: 0,0:41:09.28,0:41:11.89,Default,,0,0,0,,我们可以像这样生成新的修改集 Dialogue: 0,0:41:11.93,0:41:13.37,Default,,0,0,0,,以及新的需要集 Dialogue: 0,0:41:15.27,0:41:17.77,Default,,0,0,0,,这就是全部的内容 -- 我不该这么说 Dialogue: 0,0:41:17.77,0:41:19.34,Default,,0,0,0,,这就是书里面大概30页的细节 Dialogue: 0,0:41:19.74,0:41:21.87,Default,,0,0,0,,的核心内容了 Dialogue: 0,0:41:22.31,0:41:27.69,Default,,0,0,0,,但它是一个完全可用的初级编译器 Dialogue: 0,0:41:28.76,0:41:31.37,Default,,0,0,0,,让我给你展示一下它能做什么 Dialogue: 0,0:41:31.39,0:41:35.56,Default,,0,0,0,,假设我们从一个递归阶乘开始 Dialogue: 0,0:41:36.20,0:41:38.60,Default,,0,0,0,,这些幻灯片的字太小不适合阅读 Dialogue: 0,0:41:38.60,0:41:39.79,Default,,0,0,0,,我只想快速翻一下代码 Dialogue: 0,0:41:39.79,0:41:41.28,Default,,0,0,0,,让你们看看它有多少代码 Dialogue: 0,0:41:42.25,0:41:43.29,Default,,0,0,0,,代码从这开始-- Dialogue: 0,0:41:44.32,0:41:45.68,Default,,0,0,0,,这是代码的第一部分 Dialogue: 0,0:41:45.95,0:41:47.68,Default,,0,0,0,,这里编译了一个过程入口 Dialogue: 0,0:41:47.69,0:41:48.73,Default,,0,0,0,,并进行了一些赋值操作 Dialogue: 0,0:41:48.75,0:41:51.48,Default,,0,0,0,,这基本上对应了解释器中 Dialogue: 0,0:41:52.65,0:41:53.90,Default,,0,0,0,,进行判断之前的部分 Dialogue: 0,0:41:54.31,0:41:56.59,Default,,0,0,0,,并判断谓词是否成立 Dialogue: 0,0:41:56.97,0:41:57.85,Default,,0,0,0,,第二部分是 Dialogue: 0,0:41:58.46,0:42:03.73,Default,,0,0,0,,递归调用N-1的阶乘的结果 Dialogue: 0,0:42:04.12,0:42:05.05,Default,,0,0,0,,最后一部分是 Dialogue: 0,0:42:06.07,0:42:07.48,Default,,0,0,0,,从那里返回 Dialogue: 0,0:42:07.87,0:42:09.90,Default,,0,0,0,,并处理递归的基本情况 Dialogue: 0,0:42:09.90,0:42:13.16,Default,,0,0,0,,这就是编译阶乘会生成的代码量 Dialogue: 0,0:42:13.72,0:42:17.69,Default,,0,0,0,,当然 我们可以把这个编译器做得更好 Dialogue: 0,0:42:18.67,0:42:21.24,Default,,0,0,0,,优化它的主要方式是 Dialogue: 0,0:42:21.24,0:42:24.00,Default,,0,0,0,,当你调用一个过程时 Dialogue: 0,0:42:24.35,0:42:26.27,Default,,0,0,0,,允许编译器做任何假设 Dialogue: 0,0:42:26.97,0:42:28.28,Default,,0,0,0,,举例来说 Dialogue: 0,0:42:28.30,0:42:32.32,Default,,0,0,0,,这个编译器甚至不知道 Dialogue: 0,0:42:33.12,0:42:36.14,Default,,0,0,0,,乘法可以被内联执行 Dialogue: 0,0:42:36.14,0:42:37.87,Default,,0,0,0,,它则会自行构建起整个机制 Dialogue: 0,0:42:38.00,0:42:39.34,Default,,0,0,0,,进行APPLY-DISPATCH Dialogue: 0,0:42:41.37,0:42:42.49,Default,,0,0,0,,这是极大的浪费 Dialogue: 0,0:42:42.54,0:42:45.02,Default,,0,0,0,,因为 每当你进行APPLY-DISPATCH时 Dialogue: 0,0:42:45.02,0:42:46.80,Default,,0,0,0,,你都要关心这个参数表 Dialogue: 0,0:42:47.40,0:42:49.10,Default,,0,0,0,,因为它是个很普遍的操作 Dialogue: 0,0:42:49.13,0:42:51.07,Default,,0,0,0,,在任何真实的编译器中 Dialogue: 0,0:42:51.08,0:42:53.29,Default,,0,0,0,,你会有寄存器来暂存参数 Dialogue: 0,0:42:53.77,0:42:55.31,Default,,0,0,0,,你要开始保护 Dialogue: 0,0:42:56.38,0:42:58.05,Default,,0,0,0,,保存这些寄存器 Dialogue: 0,0:42:58.05,0:43:01.61,Default,,0,0,0,,和这里的策略相近 Dialogue: 0,0:43:02.85,0:43:05.93,Default,,0,0,0,,因此 我们可能主要通过这个方法 Dialogue: 0,0:43:05.95,0:43:08.30,Default,,0,0,0,,来优化书中这个特定的编译器 Dialogue: 0,0:43:08.69,0:43:09.70,Default,,0,0,0,,还有其它的一些方法 Dialogue: 0,0:43:09.70,0:43:11.82,Default,,0,0,0,,比如查找变量的值 Dialogue: 0,0:43:11.83,0:43:13.87,Default,,0,0,0,,使用更高效的基本操作 Dialogue: 0,0:43:13.88,0:43:14.56,Default,,0,0,0,,等等方法 Dialogue: 0,0:43:14.59,0:43:16.60,Default,,0,0,0,,本质上来说 一个好的Lisp编译器 Dialogue: 0,0:43:16.62,0:43:18.49,Default,,0,0,0,,可以吸收任意数量的努力 Dialogue: 0,0:43:19.72,0:43:21.63,Default,,0,0,0,,可能这其中的一个原因是 Dialogue: 0,0:43:21.89,0:43:23.04,Default,,0,0,0,,跟FORTRAN这类语言相比 Dialogue: 0,0:43:23.63,0:43:25.44,Default,,0,0,0,,Lisp就要慢一些 Dialogue: 0,0:43:25.90,0:43:28.19,Default,,0,0,0,,如果你回头审视历史 Dialogue: 0,0:43:28.22,0:43:31.12,Default,,0,0,0,,会发现人们为构建Lisp编译器而呕心沥血 Dialogue: 0,0:43:31.16,0:43:32.35,Default,,0,0,0,,但也远远没有接近 Dialogue: 0,0:43:32.36,0:43:33.90,Default,,0,0,0,,构建FORTRAN编译器的工作量 Dialogue: 0,0:43:34.43,0:43:35.79,Default,,0,0,0,,在接下来的几年 Dialogue: 0,0:43:35.92,0:43:37.68,Default,,0,0,0,,情况可能会发生变化 Dialogue: 0,0:43:38.00,0:43:38.83,Default,,0,0,0,,好吧 就讲到这里 Dialogue: 0,0:43:43.80,0:43:44.65,Default,,0,0,0,,有问题吗 Dialogue: 0,0:43:48.27,0:43:49.95,Default,,0,0,0,,学生: 很早的一个课时里-- Dialogue: 0,0:43:49.95,0:43:51.40,Default,,0,0,0,,我不记得是课上还是课后-- Dialogue: 0,0:43:51.47,0:43:53.88,Default,,0,0,0,,你向我们展示了 Dialogue: 0,0:43:54.00,0:43:57.52,Default,,0,0,0,,ADD操作有一些我们看不到的基本运算 Dialogue: 0,0:43:57.69,0:43:59.21,Default,,0,0,0,,类似于ADD%之类的 Dialogue: 0,0:43:59.82,0:44:01.65,Default,,0,0,0,,这是因为 Dialogue: 0,0:44:01.65,0:44:02.60,Default,,0,0,0,,你想把代码内联为 Dialogue: 0,0:44:02.60,0:44:08.19,Default,,0,0,0,,专门针对二元运算对象的运算么? Dialogue: 0,0:44:08.70,0:44:10.25,Default,,0,0,0,,但如果你有更多的运算对象 Dialogue: 0,0:44:10.28,0:44:11.47,Default,,0,0,0,,你会做什么特殊的事情吗? Dialogue: 0,0:44:12.71,0:44:16.04,Default,,0,0,0,,教授: 你看的是Scheme的实际实现 Dialogue: 0,0:44:16.06,0:44:17.84,Default,,0,0,0,,其中有一个‘+’ 这是一个运算符 Dialogue: 0,0:44:17.90,0:44:20.19,Default,,0,0,0,,如果你看‘+’的源代码 Dialogue: 0,0:44:20.33,0:44:21.37,Default,,0,0,0,,你会看到一些叫做-- Dialogue: 0,0:44:21.57,0:44:24.14,Default,,0,0,0,,我记不清了--可能叫ADD%、PLUS之类的东西 Dialogue: 0,0:44:24.55,0:44:25.79,Default,,0,0,0,,这里所进行的 Dialogue: 0,0:44:25.79,0:44:27.92,Default,,0,0,0,,就是你说的那种优化 Dialogue: 0,0:44:28.47,0:44:31.87,Default,,0,0,0,,因为 广义的‘+’接受任意数量的参数 Dialogue: 0,0:44:35.02,0:44:36.38,Default,,0,0,0,,所以 广义加法 Dialogue: 0,0:44:36.76,0:44:38.25,Default,,0,0,0,,会说:如果我有一个参数表 Dialogue: 0,0:44:38.28,0:44:40.62,Default,,0,0,0,,我最好将它们用CONS连接到表里 Dialogue: 0,0:44:41.63,0:44:44.14,Default,,0,0,0,,并指出有多少个参数 Dialogue: 0,0:44:44.72,0:44:46.16,Default,,0,0,0,,这样效率非常低下 Dialogue: 0,0:44:46.81,0:44:49.25,Default,,0,0,0,,因为大部分时间你在把两个数相加 Dialogue: 0,0:44:49.25,0:44:51.24,Default,,0,0,0,,你不必把整个参数表连接到一起 Dialogue: 0,0:44:52.04,0:44:53.93,Default,,0,0,0,,所以你想做的是 Dialogue: 0,0:44:55.66,0:44:57.71,Default,,0,0,0,,构建把一堆东西相加的代码 Dialogue: 0,0:44:58.15,0:45:00.17,Default,,0,0,0,,所以它做的大部分事情是一样的 Dialogue: 0,0:45:00.49,0:45:01.95,Default,,0,0,0,,但这里可能有个特殊的入口 Dialogue: 0,0:45:01.98,0:45:03.92,Default,,0,0,0,,如果你知道只有两个参数 Dialogue: 0,0:45:04.56,0:45:05.87,Default,,0,0,0,,你会把它们放到寄存器中 Dialogue: 0,0:45:05.87,0:45:06.97,Default,,0,0,0,,它们不需要参数表 Dialogue: 0,0:45:06.99,0:45:07.98,Default,,0,0,0,,你也不必用CONS连接它们 Dialogue: 0,0:45:08.67,0:45:10.42,Default,,0,0,0,,这就是这些东西工作的原理 Dialogue: 0,0:45:12.30,0:45:13.72,Default,,0,0,0,,好吧 下课吧 Dialogue: 0,0:45:14.10,0:45:42.97,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:45:14.10,0:45:42.97,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec10a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 6 Video Position: 355 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.01,0:00:05.02,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:05.37,0:00:11.84,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N杨启钊\N(windfarer) Dialogue: 0,0:00:05.37,0:00:11.84,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:05.37,0:00:11.84,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:05.37,0:00:11.84,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:05.37,0:00:11.84,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:11.84,0:00:13.84,Declare,,0,0,0,,{\an2\fad(500,500)}编译 Dialogue: 0,0:00:19.36,0:00:22.65,Default,,0,0,0,,教授: 上节课 我们学习了 Dialogue: 0,0:00:22.65,0:00:25.67,Default,,0,0,0,,一个显式控制的Lisp求值器 Dialogue: 0,0:00:25.67,0:00:28.97,Default,,0,0,0,,它弥合了像Lisp Dialogue: 0,0:00:29.05,0:00:32.14,Default,,0,0,0,,或者查询语言之类的高级语言 Dialogue: 0,0:00:32.50,0:00:36.16,Default,,0,0,0,,与传统寄存器机器之间的鸿沟 Dialogue: 0,0:00:36.70,0:00:40.14,Default,,0,0,0,,事实上 你可以将显式控制求值器 Dialogue: 0,0:00:40.16,0:00:44.38,Default,,0,0,0,,看作是 在一台常见的 Dialogue: 0,0:00:44.40,0:00:45.95,Default,,0,0,0,,寄存机器上实现的 Dialogue: 0,0:00:46.52,0:00:49.50,Default,,0,0,0,,Lisp求值器的汇编代码 Dialogue: 0,0:00:49.50,0:00:51.50,Default,,0,0,0,,或者 你可以把它看做是 Dialogue: 0,0:00:52.08,0:00:54.56,Default,,0,0,0,,某台专门运行Lisp的机器的微程序 Dialogue: 0,0:00:55.20,0:00:55.92,Default,,0,0,0,,无论是那种情况 Dialogue: 0,0:00:55.92,0:00:58.68,Default,,0,0,0,,我们都是把一台 Dialogue: 0,0:00:58.94,0:01:00.51,Default,,0,0,0,,处理低级语言的机器 Dialogue: 0,0:01:01.42,0:01:03.32,Default,,0,0,0,,抬高到一个层次 Dialogue: 0,0:01:03.37,0:01:04.88,Default,,0,0,0,,以便处理像Lisp这样的高级语言 Dialogue: 0,0:01:05.36,0:01:06.35,Default,,0,0,0,,这是通过编写解释器来实现的 Dialogue: 0,0:01:08.22,0:01:09.58,Default,,0,0,0,,来看个例子 Dialogue: 0,0:01:11.82,0:01:13.77,Default,,0,0,0,,这里 从概念上来说 Dialogue: 0,0:01:18.01,0:01:19.47,Default,,0,0,0,,从概念上来说 这是一台 Dialogue: 0,0:01:20.54,0:01:23.44,Default,,0,0,0,,专用于计算阶乘的机器 Dialogue: 0,0:01:24.09,0:01:27.39,Default,,0,0,0,,输入5 输出120 Dialogue: 0,0:01:28.92,0:01:30.83,Default,,0,0,0,,这个专用机器实际上 Dialogue: 0,0:01:30.97,0:01:32.72,Default,,0,0,0,,是一个Lisp解释器 Dialogue: 0,0:01:33.50,0:01:36.17,Default,,0,0,0,,它将自己配置为计算阶乘 Dialogue: 0,0:01:38.35,0:01:40.99,Default,,0,0,0,,因为你向它送入了一台阶乘机器的描述 Dialogue: 0,0:01:42.12,0:01:43.70,Default,,0,0,0,,这就是解释器 Dialogue: 0,0:01:43.70,0:01:45.66,Default,,0,0,0,,它将自己配置为 Dialogue: 0,0:01:46.37,0:01:49.24,Default,,0,0,0,,模拟你所输入描述的机器 Dialogue: 0,0:01:50.07,0:01:51.93,Default,,0,0,0,,那么 在Lisp解释器里是什么? Dialogue: 0,0:01:52.04,0:01:55.44,Default,,0,0,0,,里面可能是通用的寄存器语言解释器 Dialogue: 0,0:01:56.98,0:02:00.18,Default,,0,0,0,,它将自己配置成像Lisp解释器那样 Dialogue: 0,0:02:00.18,0:02:02.03,Default,,0,0,0,,因为你输入了一系列用寄存器语言 Dialogue: 0,0:02:02.12,0:02:03.04,Default,,0,0,0,,编写的指令 Dialogue: 0,0:02:03.37,0:02:05.16,Default,,0,0,0,,这就是显式控制求值器 Dialogue: 0,0:02:07.05,0:02:08.70,Default,,0,0,0,,它里面也有一些库 Dialogue: 0,0:02:08.73,0:02:11.08,Default,,0,0,0,,由基本运算符和Lisp运算 Dialogue: 0,0:02:11.12,0:02:12.28,Default,,0,0,0,,等等要素组成 Dialogue: 0,0:02:12.75,0:02:16.89,Default,,0,0,0,,这是解释执行的一般策略 Dialogue: 0,0:02:17.32,0:02:18.51,Default,,0,0,0,,事实上 我们所做的是 Dialogue: 0,0:02:18.60,0:02:20.14,Default,,0,0,0,,通过编写解释器 Dialogue: 0,0:02:21.62,0:02:23.40,Default,,0,0,0,,将机器抬升到 Dialogue: 0,0:02:23.42,0:02:25.24,Default,,0,0,0,,我们程序所在的层次 Dialogue: 0,0:02:25.24,0:02:26.72,Default,,0,0,0,,当然 还有另外一种策略 Dialogue: 0,0:02:27.42,0:02:28.89,Default,,0,0,0,,这种不同的策略就是编译 Dialogue: 0,0:02:29.04,0:02:30.43,Default,,0,0,0,,编译有一些不同 Dialogue: 0,0:02:31.04,0:02:31.50,Default,,0,0,0,,这里 Dialogue: 0,0:02:33.37,0:02:34.75,Default,,0,0,0,,我们可能已经实现了 Dialogue: 0,0:02:35.67,0:02:38.52,Default,,0,0,0,,一个特定用途的机器 Dialogue: 0,0:02:38.62,0:02:39.98,Default,,0,0,0,,用来计算阶乘 Dialogue: 0,0:02:43.62,0:02:46.26,Default,,0,0,0,,从某种使用寄存器语言的机器开始 Dialogue: 0,0:02:46.26,0:02:47.72,Default,,0,0,0,,但是 我们将让它执行不同的策略 Dialogue: 0,0:02:47.72,0:02:50.38,Default,,0,0,0,,把我们的阶乘程序 Dialogue: 0,0:02:51.55,0:02:53.92,Default,,0,0,0,,作为源代码输入编译器 Dialogue: 0,0:02:53.92,0:02:55.15,Default,,0,0,0,,编译器就会 Dialogue: 0,0:02:55.15,0:02:57.62,Default,,0,0,0,,把这个阶乘程序 Dialogue: 0,0:02:57.62,0:02:59.07,Default,,0,0,0,,翻译成某种寄存器机器语言 Dialogue: 0,0:03:00.25,0:03:03.40,Default,,0,0,0,,现在它并不是Lisp的显式控制求值器 Dialogue: 0,0:03:03.40,0:03:06.17,Default,,0,0,0,,而是某种用来计算阶乘的寄存器语言 Dialogue: 0,0:03:06.49,0:03:08.36,Default,,0,0,0,,这就是翻译的过程 Dialogue: 0,0:03:10.54,0:03:12.41,Default,,0,0,0,,它将进入某种加载器 Dialogue: 0,0:03:13.35,0:03:15.21,Default,,0,0,0,,它会把这些代码 Dialogue: 0,0:03:15.31,0:03:16.84,Default,,0,0,0,,和从程序库中选取的代码 Dialogue: 0,0:03:16.86,0:03:18.65,Default,,0,0,0,,比如乘法运算等 结合在一起 Dialogue: 0,0:03:19.82,0:03:21.69,Default,,0,0,0,,随后我们将生成一个加载模块 Dialogue: 0,0:03:22.22,0:03:25.06,Default,,0,0,0,,它把寄存器语言机器配置成 Dialogue: 0,0:03:25.06,0:03:27.24,Default,,0,0,0,,一个专门用来计算阶乘的机器 Dialogue: 0,0:03:28.12,0:03:30.22,Default,,0,0,0,,这就是不同的策略 Dialogue: 0,0:03:30.22,0:03:31.22,Default,,0,0,0,,在解释中 Dialogue: 0,0:03:31.22,0:03:32.01,Default,,0,0,0,,我们把机器 Dialogue: 0,0:03:32.91,0:03:35.23,Default,,0,0,0,,抬升到Lisp语言的层次 Dialogue: 0,0:03:35.32,0:03:36.34,Default,,0,0,0,,而在编译中 Dialogue: 0,0:03:36.34,0:03:38.43,Default,,0,0,0,,我们将我们的程序下降到 Dialogue: 0,0:03:38.48,0:03:40.56,Default,,0,0,0,,机器语言的层次 Dialogue: 0,0:03:41.96,0:03:43.84,Default,,0,0,0,,那么 这两个策略有什么区别呢? Dialogue: 0,0:03:44.30,0:03:49.42,Default,,0,0,0,,编译器可以生成执行起来更有效率的代码 Dialogue: 0,0:03:52.05,0:03:53.90,Default,,0,0,0,,主要原因是 Dialogue: 0,0:03:54.17,0:03:58.89,Default,,0,0,0,,如果你考虑运行中的寄存器操作 Dialogue: 0,0:04:01.92,0:04:04.49,Default,,0,0,0,,解释器需要生成寄存器的操作 Dialogue: 0,0:04:04.97,0:04:06.75,Default,,0,0,0,,从原则上来讲 它需要足够通用 Dialogue: 0,0:04:07.32,0:04:08.94,Default,,0,0,0,,以支持任何Lisp过程的执行 Dialogue: 0,0:04:10.22,0:04:12.25,Default,,0,0,0,,而编译器只需要 Dialogue: 0,0:04:12.27,0:04:14.92,Default,,0,0,0,,生成一组特定的寄存器操作 Dialogue: 0,0:04:15.52,0:04:18.22,Default,,0,0,0,,用来执行你所编译的那部分特定的Lisp过程 Dialogue: 0,0:04:20.17,0:04:21.20,Default,,0,0,0,,换一种说法 Dialogue: 0,0:04:21.20,0:04:25.31,Default,,0,0,0,,解释器是一种通用的模拟器 Dialogue: 0,0:04:25.92,0:04:27.58,Default,,0,0,0,,当你输入一个Lisp过程时 Dialogue: 0,0:04:27.58,0:04:31.32,Default,,0,0,0,,它们就会模拟那个过程所描述的程序 Dialogue: 0,0:04:31.32,0:04:33.87,Default,,0,0,0,,所以解释器旨在成为一个通用模拟器 Dialogue: 0,0:04:34.62,0:04:35.96,Default,,0,0,0,,而编译器 实际上 Dialogue: 0,0:04:36.00,0:04:37.68,Default,,0,0,0,,只需要将东西配置成 Dialogue: 0,0:04:37.71,0:04:39.34,Default,,0,0,0,,解释器将要去模拟的机器 Dialogue: 0,0:04:40.02,0:04:41.34,Default,,0,0,0,,所以编译器可以运行得更快 Dialogue: 0,0:04:52.55,0:04:53.64,Default,,0,0,0,,另一方面 Dialogue: 0,0:04:55.97,0:04:58.28,Default,,0,0,0,,解释器更适合用来排查错误 Dialogue: 0,0:04:59.43,0:05:01.25,Default,,0,0,0,,这是因为 Dialogue: 0,0:05:01.57,0:05:03.02,Default,,0,0,0,,我们的源代码实际上就在那里 Dialogue: 0,0:05:03.02,0:05:04.81,Default,,0,0,0,,我们正在解释它们 Dialogue: 0,0:05:05.87,0:05:07.69,Default,,0,0,0,,并且库也在其中 Dialogue: 0,0:05:07.90,0:05:10.89,Default,,0,0,0,,看 库是解释器的一部分 Dialogue: 0,0:05:11.30,0:05:13.16,Default,,0,0,0,,而编译器只会拉取 Dialogue: 0,0:05:13.20,0:05:14.56,Default,,0,0,0,,运行程序所需要的代码 Dialogue: 0,0:05:14.87,0:05:17.00,Default,,0,0,0,,所以 如果你在排查错误的途中 Dialogue: 0,0:05:18.00,0:05:20.72,Default,,0,0,0,,你想写一些额外的代码 Dialogue: 0,0:05:20.80,0:05:22.57,Default,,0,0,0,,来考察运行过程中的数据类型 Dialogue: 0,0:05:23.05,0:05:24.25,Default,,0,0,0,,或者做一些 Dialogue: 0,0:05:24.30,0:05:25.92,Default,,0,0,0,,在写程序时没有想到的计算 Dialogue: 0,0:05:25.95,0:05:27.53,Default,,0,0,0,,解释器可以完美搞定这些 Dialogue: 0,0:05:28.05,0:05:29.21,Default,,0,0,0,,而编译器不行 Dialogue: 0,0:05:29.62,0:05:31.90,Default,,0,0,0,,所以它们各有优点 Dialogue: 0,0:05:31.90,0:05:34.48,Default,,0,0,0,,编译器将生成运行更快的代码 Dialogue: 0,0:05:34.85,0:05:37.02,Default,,0,0,0,,而解释器是一种更适合排错的环境 Dialogue: 0,0:05:38.95,0:05:41.40,Default,,0,0,0,,大多数Lisp系统最终将二者都实现了 Dialogue: 0,0:05:42.92,0:05:45.23,Default,,0,0,0,,这样你就可以在开发阶段 Dialogue: 0,0:05:45.24,0:05:47.08,Default,,0,0,0,,可以使用解释器 Dialogue: 0,0:05:47.08,0:05:48.62,Default,,0,0,0,,随后通过编译加速代码的运行 Dialogue: 0,0:05:49.02,0:05:50.03,Default,,0,0,0,,并且通常 Dialogue: 0,0:05:50.04,0:05:51.68,Default,,0,0,0,,你能够让被编译的代码 Dialogue: 0,0:05:51.69,0:05:53.56,Default,,0,0,0,,和被解释的代码互相调用 Dialogue: 0,0:05:54.60,0:05:56.33,Default,,0,0,0,,我们将学习如何做到 其实不难 Dialogue: 0,0:05:59.27,0:05:59.85,Default,,0,0,0,,好 Dialogue: 0,0:06:00.97,0:06:02.09,Default,,0,0,0,,事实上 Dialogue: 0,0:06:04.30,0:06:05.75,Default,,0,0,0,,在我们将要构建的编译器中 Dialogue: 0,0:06:05.75,0:06:07.58,Default,,0,0,0,,我们实现编译的代码和解释的代码 Dialogue: 0,0:06:07.58,0:06:09.45,Default,,0,0,0,,互相调用的方式是 Dialogue: 0,0:06:09.90,0:06:12.06,Default,,0,0,0,,我们让编译器和解释器使用 Dialogue: 0,0:06:12.11,0:06:14.40,Default,,0,0,0,,使用完全一致的寄存器约定 Dialogue: 0,0:06:18.42,0:06:21.72,Default,,0,0,0,,编译器的理念 Dialogue: 0,0:06:21.76,0:06:25.74,Default,,0,0,0,,与解释器或求值器的理念很像 Dialogue: 0,0:06:25.87,0:06:26.46,Default,,0,0,0,,它们是相同的 Dialogue: 0,0:06:27.05,0:06:29.39,Default,,0,0,0,,求值器遍历代码 Dialogue: 0,0:06:29.82,0:06:32.35,Default,,0,0,0,,产生一些寄存器操作 Dialogue: 0,0:06:33.65,0:06:34.97,Default,,0,0,0,,就是我们昨天做的事情 Dialogue: 0,0:06:37.10,0:06:40.27,Default,,0,0,0,,而编译器会读取代码 Dialogue: 0,0:06:40.52,0:06:43.00,Default,,0,0,0,,生成一些进行求值时 Dialogue: 0,0:06:43.04,0:06:44.67,Default,,0,0,0,,求值器会进行的 Dialogue: 0,0:06:45.23,0:06:46.64,Default,,0,0,0,,相关寄存器操作 Dialogue: 0,0:06:48.60,0:06:49.95,Default,,0,0,0,,这就给我们提供了一个模型 Dialogue: 0,0:06:50.60,0:06:53.77,Default,,0,0,0,,来实现一个零阶编译器 Dialogue: 0,0:06:55.30,0:06:58.32,Default,,0,0,0,,一个很差劲但是能用的编译器 Dialogue: 0,0:06:58.32,0:06:59.32,Default,,0,0,0,,这种模型就是 Dialogue: 0,0:06:59.36,0:07:00.59,Default,,0,0,0,,你用求值器 Dialogue: 0,0:07:00.68,0:07:01.88,Default,,0,0,0,,把代码跑一遍 Dialogue: 0,0:07:02.80,0:07:06.06,Default,,0,0,0,,但不去执行实际的操作 Dialogue: 0,0:07:06.06,0:07:07.15,Default,,0,0,0,,只是把它们保存下来 Dialogue: 0,0:07:07.55,0:07:08.82,Default,,0,0,0,,那就是你编译后的代码 Dialogue: 0,0:07:08.82,0:07:10.24,Default,,0,0,0,,让我举个例子 Dialogue: 0,0:07:12.70,0:07:14.14,Default,,0,0,0,,假设我们要编译 Dialogue: 0,0:07:15.10,0:07:17.90,Default,,0,0,0,,编译(F X) 这个表达式 Dialogue: 0,0:07:25.07,0:07:25.96,Default,,0,0,0,,我们假设 Dialogue: 0,0:07:25.96,0:07:28.06,Default,,0,0,0,,EXP寄存器中保存着(F X) Dialogue: 0,0:07:28.06,0:07:29.55,Default,,0,0,0,,而ENV寄存器又保存着其它东西 Dialogue: 0,0:07:30.10,0:07:32.20,Default,,0,0,0,,想象我们启动了求值器 Dialogue: 0,0:07:34.60,0:07:35.71,Default,,0,0,0,,它读取了表达式 Dialogue: 0,0:07:35.71,0:07:37.36,Default,,0,0,0,,判断它是一个应用 Dialogue: 0,0:07:37.92,0:07:41.90,Default,,0,0,0,,它分支到求值器代码中的一个地方 Dialogue: 0,0:07:42.52,0:07:45.15,Default,,0,0,0,,我们之前见过的叫EV-APPLICATION的地方 Dialogue: 0,0:07:47.12,0:07:48.12,Default,,0,0,0,,然后继续处理 Dialogue: 0,0:07:48.16,0:07:50.08,Default,,0,0,0,,恢复运算对象和UNEV Dialogue: 0,0:07:50.08,0:07:52.44,Default,,0,0,0,,然后之后它将运算符放在EXP寄存器中 Dialogue: 0,0:07:52.48,0:07:54.27,Default,,0,0,0,,递归地对它求值 Dialogue: 0,0:07:54.47,0:07:56.08,Default,,0,0,0,,这就是我们经历的过程 Dialogue: 0,0:07:56.67,0:07:57.84,Default,,0,0,0,,如果你看代码 Dialogue: 0,0:07:57.87,0:07:59.74,Default,,0,0,0,,会看到一些寄存器操作 Dialogue: 0,0:08:00.20,0:08:02.30,Default,,0,0,0,,你会看到将运算对象赋值给UNEV寄存器 Dialogue: 0,0:08:02.30,0:08:03.95,Default,,0,0,0,,把运算符赋值给EXP Dialogue: 0,0:08:04.09,0:08:06.20,Default,,0,0,0,,保存环境、生成新环境 等等 Dialogue: 0,0:08:10.22,0:08:11.93,Default,,0,0,0,,如果我们来看下这里的投影 Dialogue: 0,0:08:15.75,0:08:19.58,Default,,0,0,0,,我们会看到产生的这些操作 Dialogue: 0,0:08:20.82,0:08:22.52,Default,,0,0,0,,这是求值器实际要进行的 Dialogue: 0,0:08:22.72,0:08:24.80,Default,,0,0,0,,第一个操作 Dialogue: 0,0:08:25.00,0:08:27.20,Default,,0,0,0,,它将运算对象从EXP寄存器里取出来 Dialogue: 0,0:08:27.47,0:08:28.62,Default,,0,0,0,,并将它赋值给UNEV Dialogue: 0,0:08:30.03,0:08:32.27,Default,,0,0,0,,然后它给EXP寄存器赋了某个值 Dialogue: 0,0:08:32.30,0:08:33.46,Default,,0,0,0,,然后保存CONTINUE Dialogue: 0,0:08:33.46,0:08:34.62,Default,,0,0,0,,保存ENV Dialogue: 0,0:08:34.62,0:08:38.65,Default,,0,0,0,,我在这里就只是寄存器赋值 Dialogue: 0,0:08:39.57,0:08:42.32,Default,,0,0,0,,这就是求值器求值代码时进行的操作 Dialogue: 0,0:08:42.77,0:08:43.79,Default,,0,0,0,,我们缩小画面看看 Dialogue: 0,0:08:44.30,0:08:47.13,Default,,0,0,0,,总计有19个操作 Dialogue: 0,0:08:49.40,0:08:51.64,Default,,0,0,0,,这些代码 Dialogue: 0,0:08:52.05,0:08:53.90,Default,,0,0,0,,对应着 Dialogue: 0,0:08:54.75,0:08:57.10,Default,,0,0,0,,求值器跳转到APPLY-DISPATCH代码之前 Dialogue: 0,0:08:57.86,0:08:59.16,Default,,0,0,0,,事实上 在这个编译器中 Dialogue: 0,0:08:59.20,0:09:01.18,Default,,0,0,0,,我们不需要再关心APPLY-DISPATCH了 Dialogue: 0,0:09:01.30,0:09:02.11,Default,,0,0,0,,我们有所有东西 Dialogue: 0,0:09:02.35,0:09:05.04,Default,,0,0,0,,我们拥有解释后和编译后的所有代码 Dialogue: 0,0:09:06.07,0:09:07.61,Default,,0,0,0,,通常求值过程 Dialogue: 0,0:09:07.61,0:09:09.85,Default,,0,0,0,,是由APPLY-DISPATCH处理的 Dialogue: 0,0:09:10.27,0:09:12.32,Default,,0,0,0,,这将让被解释后代码与编译后代码 Dialogue: 0,0:09:12.36,0:09:13.71,Default,,0,0,0,,很容易互相调用 Dialogue: 0,0:09:18.27,0:09:19.87,Default,,0,0,0,,从原理上来说 这样做足矣 Dialogue: 0,0:09:21.05,0:09:22.66,Default,,0,0,0,,只需运行求值器 Dialogue: 0,0:09:22.66,0:09:24.50,Default,,0,0,0,,因而编译器非常像求值器 Dialogue: 0,0:09:24.50,0:09:26.47,Default,,0,0,0,,你运行它 唯一不同是你把操作存下来 Dialogue: 0,0:09:26.47,0:09:28.40,Default,,0,0,0,,而不是实际执行它们 Dialogue: 0,0:09:29.35,0:09:31.39,Default,,0,0,0,,这其实不完全正确 Dialogue: 0,0:09:32.91,0:09:34.99,Default,,0,0,0,,这里面我们撒了个小谎 Dialogue: 0,0:09:36.24,0:09:39.29,Default,,0,0,0,,你需要关心的是:如果有个谓词 Dialogue: 0,0:09:40.12,0:09:42.16,Default,,0,0,0,,如果你要进行某种测试 Dialogue: 0,0:09:43.45,0:09:46.03,Default,,0,0,0,,显然 在你编译时 Dialogue: 0,0:09:46.52,0:09:47.98,Default,,0,0,0,,你不知道这些分支中 Dialogue: 0,0:09:48.32,0:09:50.14,Default,,0,0,0,,哪条分支会被执行 Dialogue: 0,0:09:51.13,0:09:53.92,Default,,0,0,0,,所以你不能确定求值器将对哪个求值 Dialogue: 0,0:09:54.90,0:09:57.12,Default,,0,0,0,,因此在这里就很简单 Dialogue: 0,0:09:57.12,0:09:58.49,Default,,0,0,0,,你把两个分支全编译了 Dialogue: 0,0:09:59.32,0:10:01.29,Default,,0,0,0,,因此你编译出一个这样的结构 Dialogue: 0,0:10:02.00,0:10:03.98,Default,,0,0,0,,它们都会被编译成 Dialogue: 0,0:10:05.31,0:10:09.15,Default,,0,0,0,,首先是P的代码 Dialogue: 0,0:10:10.71,0:10:16.51,Default,,0,0,0,,它把结果存入VAL寄存器 Dialogue: 0,0:10:18.17,0:10:20.64,Default,,0,0,0,,解释器对谓词求值 Dialogue: 0,0:10:21.35,0:10:24.19,Default,,0,0,0,,并保证结果会放到VAL寄存器中 Dialogue: 0,0:10:24.70,0:10:27.22,Default,,0,0,0,,随后你编译一条指令 Dialogue: 0,0:10:27.22,0:10:33.79,Default,,0,0,0,,如果VAL是TRUE Dialogue: 0,0:10:37.17,0:10:38.75,Default,,0,0,0,,就转到LABEL1这个地方 Dialogue: 0,0:10:44.97,0:10:47.52,Default,,0,0,0,,然后我们写下B的代码 Dialogue: 0,0:10:49.42,0:10:52.32,Default,,0,0,0,,让解释器对B进行求值 Dialogue: 0,0:10:53.62,0:10:57.21,Default,,0,0,0,,然后写一句指令 Dialogue: 0,0:10:57.23,0:10:58.75,Default,,0,0,0,,用来跳转到下一条指令 Dialogue: 0,0:11:02.20,0:11:04.56,Default,,0,0,0,,就是它结束之后要去的地方 Dialogue: 0,0:11:04.95,0:11:06.09,Default,,0,0,0,,你放入那个指令 Dialogue: 0,0:11:06.88,0:11:08.62,Default,,0,0,0,,这里你写下LABEL1 Dialogue: 0,0:11:12.12,0:11:13.80,Default,,0,0,0,,这里写A的代码 Dialogue: 0,0:11:19.47,0:11:25.85,Default,,0,0,0,,然后又是跳转到下一条指令 Dialogue: 0,0:11:31.42,0:11:32.88,Default,,0,0,0,,这就是处理条件分支的办法 Dialogue: 0,0:11:32.98,0:11:34.65,Default,,0,0,0,,你生成一小段这样的代码 Dialogue: 0,0:11:35.75,0:11:38.12,Default,,0,0,0,,除此之外 Dialogue: 0,0:11:38.95,0:11:41.55,Default,,0,0,0,,这个零阶编译器与求值器一模一样 Dialogue: 0,0:11:42.55,0:11:45.12,Default,,0,0,0,,它只是把指令存起来 而不执行它们 Dialogue: 0,0:11:46.55,0:11:47.60,Default,,0,0,0,,看起来很简单 Dialogue: 0,0:11:47.64,0:11:49.08,Default,,0,0,0,,但我们已经取得了某些收获 Dialogue: 0,0:11:50.12,0:11:52.62,Default,,0,0,0,,它会比求值器更有效率 Dialogue: 0,0:11:53.52,0:11:56.14,Default,,0,0,0,,因为 如果你观察求值器的运行 Dialogue: 0,0:11:56.35,0:12:01.05,Default,,0,0,0,,它并不只是进行寄存器操作 Dialogue: 0,0:12:01.27,0:12:03.50,Default,,0,0,0,,它还会决定执行哪个 Dialogue: 0,0:12:04.70,0:12:07.23,Default,,0,0,0,,它做的第一件事就是 Dialogue: 0,0:12:07.92,0:12:09.77,Default,,0,0,0,,以它为例 就是进行某些测试 Dialogue: 0,0:12:09.77,0:12:11.56,Default,,0,0,0,,确定它是一个应用 Dialogue: 0,0:12:13.57,0:12:15.05,Default,,0,0,0,,然后就跳转到 Dialogue: 0,0:12:15.39,0:12:16.62,Default,,0,0,0,,处理应用的地方去 Dialogue: 0,0:12:16.62,0:12:18.44,Default,,0,0,0,,换句话说 求值器做的事情是 Dialogue: 0,0:12:18.62,0:12:22.76,Default,,0,0,0,,分析代码需要进行的运算 Dialogue: 0,0:12:23.47,0:12:24.99,Default,,0,0,0,,同时并执行它们 Dialogue: 0,0:12:25.55,0:12:28.28,Default,,0,0,0,,当你运行求值器一百万次 Dialogue: 0,0:12:28.28,0:12:30.30,Default,,0,0,0,,这个分析过程就进行一百万次 Dialogue: 0,0:12:30.85,0:12:32.58,Default,,0,0,0,,而在编译器中 它只会进行一次 Dialogue: 0,0:12:32.58,0:12:34.81,Default,,0,0,0,,之后就只有寄存器操作了 Dialogue: 0,0:12:39.20,0:12:41.68,Default,,0,0,0,,这就是零阶编译器了 Dialogue: 0,0:12:41.80,0:12:44.04,Default,,0,0,0,,但它是个拙劣的编译器 Dialogue: 0,0:12:44.45,0:12:45.28,Default,,0,0,0,,它挺蠢的 Dialogue: 0,0:12:46.90,0:12:48.41,Default,,0,0,0,,让我们回过头来 Dialogue: 0,0:12:49.88,0:12:50.97,Default,,0,0,0,,看看这张投影 Dialogue: 0,0:12:52.02,0:12:55.29,Default,,0,0,0,,看看这个东西做的一些操作 Dialogue: 0,0:12:55.85,0:12:56.88,Default,,0,0,0,,我们想看看 Dialogue: 0,0:12:59.72,0:13:02.28,Default,,0,0,0,,在解释(F X)时的操作 Dialogue: 0,0:13:03.52,0:13:04.84,Default,,0,0,0,,这里就是它做了什么 Dialogue: 0,0:13:05.17,0:13:06.11,Default,,0,0,0,,举个例子 这里 Dialogue: 0,0:13:07.15,0:13:11.98,Default,,0,0,0,,它将(OPERATOR (FETCH EXP))赋值给EXP Dialogue: 0,0:13:13.75,0:13:15.87,Default,,0,0,0,,其实没必要这样做 Dialogue: 0,0:13:16.22,0:13:17.47,Default,,0,0,0,,因为编译器知道 Dialogue: 0,0:13:17.66,0:13:21.84,Default,,0,0,0,,(OPERATOR (FETCH EXP))的值就是F Dialogue: 0,0:13:23.35,0:13:25.56,Default,,0,0,0,,因此这个指令没理由存在 Dialogue: 0,0:13:25.70,0:13:28.88,Default,,0,0,0,,应该改为:要把F赋值给EXP Dialogue: 0,0:13:29.45,0:13:31.08,Default,,0,0,0,,或者实际上 你完全不需要EXP Dialogue: 0,0:13:31.87,0:13:33.56,Default,,0,0,0,,没有理由需要EXP Dialogue: 0,0:13:33.56,0:13:35.16,Default,,0,0,0,,EXP是用来做什么的? Dialogue: 0,0:13:35.18,0:13:36.33,Default,,0,0,0,,我们看这里 Dialogue: 0,0:13:40.77,0:13:42.20,Default,,0,0,0,,我们对VAL赋值 Dialogue: 0,0:13:43.05,0:13:47.34,Default,,0,0,0,,在环境里的EXP里寻找东西 Dialogue: 0,0:13:48.68,0:13:49.53,Default,,0,0,0,,因此 我们实际上是要 Dialogue: 0,0:13:49.55,0:13:51.54,Default,,0,0,0,,替换掉所有的EXP寄存器 Dialogue: 0,0:13:51.54,0:13:53.32,Default,,0,0,0,,把这个指令修改为 Dialogue: 0,0:13:53.34,0:13:54.16,Default,,0,0,0,,给VAL赋值 Dialogue: 0,0:13:54.45,0:13:56.06,Default,,0,0,0,,在环境中查找 Dialogue: 0,0:13:56.36,0:13:58.40,Default,,0,0,0,,符号F的值 Dialogue: 0,0:14:01.09,0:14:01.77,Default,,0,0,0,,类似地 Dialogue: 0,0:14:02.57,0:14:04.27,Default,,0,0,0,,回到这里 我们也完全不需要UNEV Dialogue: 0,0:14:04.72,0:14:05.79,Default,,0,0,0,,因为我们知道 Dialogue: 0,0:14:06.22,0:14:09.16,Default,,0,0,0,,因为我们知道 (FETCH EXP)取出的运算对象 Dialogue: 0,0:14:09.16,0:14:10.62,Default,,0,0,0,,就是'(X) Dialogue: 0,0:14:13.25,0:14:14.06,Default,,0,0,0,,从某种意义上来说 Dialogue: 0,0:14:16.17,0:14:19.39,Default,,0,0,0,,你完全不需要UNEV和EXP Dialogue: 0,0:14:19.67,0:14:21.05,Default,,0,0,0,,看看它们实际上是什么 Dialogue: 0,0:14:21.08,0:14:25.30,Default,,0,0,0,,它们不是实际运行机器的寄存器 Dialogue: 0,0:14:25.30,0:14:26.40,Default,,0,0,0,,它们实际上是 Dialogue: 0,0:14:26.60,0:14:29.50,Default,,0,0,0,,为了模拟该机器的而设置的寄存器 Dialogue: 0,0:14:30.72,0:14:33.77,Default,,0,0,0,,所以它们保存一些表达式 Dialogue: 0,0:14:34.00,0:14:36.04,Default,,0,0,0,,以编译器的视角看来 Dialogue: 0,0:14:36.06,0:14:36.81,Default,,0,0,0,,它们就是常量 Dialogue: 0,0:14:36.95,0:14:38.48,Default,,0,0,0,,因此可以直接把它们放到代码中 Dialogue: 0,0:14:39.47,0:14:41.34,Default,,0,0,0,,你可以忘掉那些关于 Dialogue: 0,0:14:41.36,0:14:42.54,Default,,0,0,0,,EXP和UNEV的操作 Dialogue: 0,0:14:42.57,0:14:43.77,Default,,0,0,0,,只用那些常量 Dialogue: 0,0:14:44.02,0:14:48.00,Default,,0,0,0,,与之相似 如果我们回顾这里 Dialogue: 0,0:14:48.00,0:14:51.32,Default,,0,0,0,,有像(ASSIGN CONTINUE EVAL-ARGS)之类的语句 Dialogue: 0,0:14:53.75,0:14:55.39,Default,,0,0,0,,现在 它和任何东西都没有关系 Dialogue: 0,0:14:55.62,0:14:57.76,Default,,0,0,0,,它只是求值器 Dialogue: 0,0:14:58.08,0:15:00.17,Default,,0,0,0,,维护了下一步需要去哪 Dialogue: 0,0:15:02.70,0:15:05.96,Default,,0,0,0,,在某些应用中对参数进行求值 Dialogue: 0,0:15:06.82,0:15:08.65,Default,,0,0,0,,当然 这与编译器没关系 Dialogue: 0,0:15:08.65,0:15:13.88,Default,,0,0,0,,因为这个分析过程已经被编译器做完了 Dialogue: 0,0:15:15.05,0:15:16.83,Default,,0,0,0,,所以编译后的代码完全不需要它 Dialogue: 0,0:15:17.70,0:15:19.32,Default,,0,0,0,,因此许多向CONTINUE寄存器 Dialogue: 0,0:15:19.32,0:15:21.30,Default,,0,0,0,,赋值的操作都是无用的 Dialogue: 0,0:15:21.30,0:15:24.62,Default,,0,0,0,,运行着的机器留着它们 Dialogue: 0,0:15:24.64,0:15:25.77,Default,,0,0,0,,是为了跟踪它的状态 Dialogue: 0,0:15:26.07,0:15:28.72,Default,,0,0,0,,是为了知道求值器的下一步分析 Dialogue: 0,0:15:28.72,0:15:30.03,Default,,0,0,0,,而它们是完全无关的 Dialogue: 0,0:15:30.06,0:15:31.23,Default,,0,0,0,,因此我们可以去掉它们 Dialogue: 0,0:15:43.90,0:15:45.98,Default,,0,0,0,,那么 如果我们简单地 Dialogue: 0,0:15:46.16,0:15:47.75,Default,,0,0,0,,进行这类优化 Dialogue: 0,0:15:47.75,0:15:51.64,Default,,0,0,0,,不再考虑EXP和UNEV Dialogue: 0,0:15:51.75,0:15:56.22,Default,,0,0,0,,去掉这些无关的寄存器赋值 Dialogue: 0,0:15:57.25,0:15:59.96,Default,,0,0,0,,我们就可以找到这些代码 Dialogue: 0,0:16:01.48,0:16:06.20,Default,,0,0,0,,也就是求值器会执行的这19条指令 Dialogue: 0,0:16:06.91,0:16:08.12,Default,,0,0,0,,给替换掉 Dialogue: 0,0:16:08.36,0:16:10.33,Default,,0,0,0,,请看幻灯片 Dialogue: 0,0:16:12.27,0:16:15.34,Default,,0,0,0,,我们去掉了大概一半 Dialogue: 0,0:16:18.28,0:16:20.75,Default,,0,0,0,,同样 这就是某种过滤 Dialogue: 0,0:16:21.07,0:16:24.46,Default,,0,0,0,,把无关的东西去掉 Dialogue: 0,0:16:25.17,0:16:26.22,Default,,0,0,0,,你们看 比如说 Dialogue: 0,0:16:27.47,0:16:29.66,Default,,0,0,0,,这里 求值器说 Dialogue: 0,0:16:29.68,0:16:32.43,Default,,0,0,0,,(ASSIGN VAL (LOOKUP 'F (FETCH ENV))) Dialogue: 0,0:16:32.46,0:16:34.22,Default,,0,0,0,,这里 我们放入了一个常量F Dialogue: 0,0:16:35.44,0:16:37.02,Default,,0,0,0,,这里又放了一个常量X Dialogue: 0,0:16:40.02,0:16:42.41,Default,,0,0,0,,因此 这个编译器又稍微好一点 Dialogue: 0,0:16:43.79,0:16:46.76,Default,,0,0,0,,但它还是比较蠢 Dialogue: 0,0:16:47.95,0:16:49.58,Default,,0,0,0,,它仍会做很多蠢事 Dialogue: 0,0:16:50.45,0:16:52.52,Default,,0,0,0,,我们再看幻灯片 Dialogue: 0,0:16:52.88,0:16:53.93,Default,,0,0,0,,看最开头的地方 Dialogue: 0,0:16:56.34,0:16:58.17,Default,,0,0,0,,我们调用(SAVE ENV)保存环境 Dialogue: 0,0:16:59.35,0:17:01.72,Default,,0,0,0,,然后给VAL寄存器赋某个值 Dialogue: 0,0:17:01.80,0:17:03.35,Default,,0,0,0,,然后恢复环境 Dialogue: 0,0:17:03.35,0:17:04.41,Default,,0,0,0,,它是从哪来的 Dialogue: 0,0:17:04.91,0:17:07.10,Default,,0,0,0,,它来自求值器的这个地方 Dialogue: 0,0:17:07.15,0:17:10.28,Default,,0,0,0,,哦 我在正在对一个应用求值 Dialogue: 0,0:17:11.10,0:17:14.68,Default,,0,0,0,,因此我要递归调用EVAL-DISPATCH Dialogue: 0,0:17:15.87,0:17:17.98,Default,,0,0,0,,我最好把接下来要用到的东西 Dialogue: 0,0:17:17.98,0:17:19.08,Default,,0,0,0,,保存到环境中 Dialogue: 0,0:17:19.77,0:17:22.86,Default,,0,0,0,,这就是递归调用EVAL-DISPATCH的结果 Dialogue: 0,0:17:23.47,0:17:25.77,Default,,0,0,0,,刚才那个例子就是对符号F求值的结果 Dialogue: 0,0:17:26.50,0:17:28.27,Default,,0,0,0,,从EVAL-DISPATCH中返回 Dialogue: 0,0:17:28.28,0:17:29.66,Default,,0,0,0,,将环境恢复 Dialogue: 0,0:17:31.25,0:17:32.28,Default,,0,0,0,,但是实际上 Dialogue: 0,0:17:32.59,0:17:35.88,Default,,0,0,0,,这个求值过程中 所进行的操作 Dialogue: 0,0:17:35.92,0:17:37.71,Default,,0,0,0,,完全不会影响环境 Dialogue: 0,0:17:38.67,0:17:40.80,Default,,0,0,0,,所以这里没必要先保存环境 Dialogue: 0,0:17:40.84,0:17:42.22,Default,,0,0,0,,再恢复环境 Dialogue: 0,0:17:45.67,0:17:46.62,Default,,0,0,0,,与之类似 Dialogue: 0,0:17:49.79,0:17:51.39,Default,,0,0,0,,这里 我们保存了参数表 Dialogue: 0,0:17:53.07,0:17:55.80,Default,,0,0,0,,那是一个求值参数的循环 Dialogue: 0,0:17:55.82,0:17:56.86,Default,,0,0,0,,先保存参数表 Dialogue: 0,0:17:57.20,0:17:58.03,Default,,0,0,0,,然后在这里恢复 Dialogue: 0,0:17:58.08,0:18:00.51,Default,,0,0,0,,但事实上最后 Dialogue: 0,0:18:00.80,0:18:02.28,Default,,0,0,0,,并没有变更参数表 Dialogue: 0,0:18:02.84,0:18:04.17,Default,,0,0,0,,所以不需要保存它 Dialogue: 0,0:18:08.65,0:18:12.88,Default,,0,0,0,,换种方式来说 Dialogue: 0,0:18:13.77,0:18:14.80,Default,,0,0,0,,怎么说呢 Dialogue: 0,0:18:16.43,0:18:19.13,Default,,0,0,0,,求值器需要最大限度地保持悲观 Dialogue: 0,0:18:19.87,0:18:21.07,Default,,0,0,0,,因为 从它的视角来看 Dialogue: 0,0:18:21.08,0:18:23.06,Default,,0,0,0,,只知道接下来是要对某些东西进行求值 Dialogue: 0,0:18:23.24,0:18:24.97,Default,,0,0,0,,所以最好把稍后要用的都存下来 Dialogue: 0,0:18:26.12,0:18:27.79,Default,,0,0,0,,一旦你完成了分析 Dialogue: 0,0:18:27.82,0:18:29.68,Default,,0,0,0,,从编译器的角度就会考虑 Dialogue: 0,0:18:29.72,0:18:31.47,Default,,0,0,0,,哪些是我真正需要存下来的? Dialogue: 0,0:18:32.12,0:18:33.31,Default,,0,0,0,,我们需要去 -- Dialogue: 0,0:18:33.42,0:18:37.30,Default,,0,0,0,,它不需要像求值器一样小心翼翼 Dialogue: 0,0:18:37.30,0:18:38.80,Default,,0,0,0,,因为它知道 实际需要什么 Dialogue: 0,0:18:39.69,0:18:41.16,Default,,0,0,0,,无论如何 如果我们完成了优化 Dialogue: 0,0:18:42.50,0:18:45.71,Default,,0,0,0,,消除掉所有多余的保存和恢复 Dialogue: 0,0:18:46.40,0:18:49.05,Default,,0,0,0,,那么我们可以得到这样的结果 Dialogue: 0,0:18:49.90,0:18:51.53,Default,,0,0,0,,我们可以发现 Dialogue: 0,0:18:51.64,0:18:53.71,Default,,0,0,0,,只有三条指令是必须的 Dialogue: 0,0:18:54.07,0:18:55.72,Default,,0,0,0,,从刚才的11条指令优化成这样 Dialogue: 0,0:18:55.97,0:18:58.81,Default,,0,0,0,,或是从原始的20条指令优化而来 Dialogue: 0,0:18:59.87,0:19:00.92,Default,,0,0,0,,这告诉我们 Dialogue: 0,0:19:01.12,0:19:03.18,Default,,0,0,0,,对于这些寄存器操作 Dialogue: 0,0:19:03.27,0:19:04.94,Default,,0,0,0,,哪些是必需的? Dialogue: 0,0:19:09.42,0:19:11.74,Default,,0,0,0,,让我换个方式来总结一下 Dialogue: 0,0:19:11.74,0:19:13.48,Default,,0,0,0,,我先给你们看一张图 Dialogue: 0,0:19:16.00,0:19:17.52,Default,,0,0,0,,这张图片 Dialogue: 0,0:19:18.77,0:19:20.81,Default,,0,0,0,,展示了所有的保存和恢复 Dialogue: 0,0:19:23.50,0:19:25.23,Default,,0,0,0,,这里是表达式(F X) Dialogue: 0,0:19:25.32,0:19:27.87,Default,,0,0,0,,在下面这里 Dialogue: 0,0:19:28.75,0:19:31.80,Default,,0,0,0,,是对求值器中各种地方的跟踪 Dialogue: 0,0:19:34.97,0:19:38.04,Default,,0,0,0,,在求值发生时会使用这些地方 Dialogue: 0,0:19:38.04,0:19:40.01,Default,,0,0,0,,在这里 你可以看到箭头 Dialogue: 0,0:19:40.22,0:19:42.08,Default,,0,0,0,,下箭头代表寄存器的保存 Dialogue: 0,0:19:42.40,0:19:44.84,Default,,0,0,0,,所以最先保存的是ENV寄存器 Dialogue: 0,0:19:46.82,0:19:48.68,Default,,0,0,0,,然后 在这里恢复ENV Dialogue: 0,0:19:52.38,0:19:54.54,Default,,0,0,0,,这些都是成对的栈操作 Dialogue: 0,0:19:56.12,0:19:57.56,Default,,0,0,0,,如果你更进一步 Dialogue: 0,0:19:58.12,0:20:00.78,Default,,0,0,0,,我们记得 Dialogue: 0,0:20:00.89,0:20:03.02,Default,,0,0,0,,UNEV是个完全没用的寄存器 Dialogue: 0,0:20:07.80,0:20:09.78,Default,,0,0,0,,如果我们用固定结构的代码 Dialogue: 0,0:20:09.78,0:20:12.52,Default,,0,0,0,,就不需要保存UNEV 因为完全用不上 Dialogue: 0,0:20:16.20,0:20:19.15,Default,,0,0,0,,然后 根据我们约定的 Dialogue: 0,0:20:19.16,0:20:21.88,Default,,0,0,0,,应用过程的准则 Dialogue: 0,0:20:21.88,0:20:23.85,Default,,0,0,0,,我们会选择是否保存CONTINUE Dialogue: 0,0:20:27.40,0:20:28.74,Default,,0,0,0,,这就是我们做的第一件事 Dialogue: 0,0:20:28.74,0:20:30.51,Default,,0,0,0,,然后我们可以看看 Dialogue: 0,0:20:31.71,0:20:32.70,Default,,0,0,0,,实际需要些什么 Dialogue: 0,0:20:33.07,0:20:35.56,Default,,0,0,0,,其实在求值F的过程中 Dialogue: 0,0:20:36.04,0:20:37.82,Default,,0,0,0,,我们不需要保存ENV Dialogue: 0,0:20:38.08,0:20:39.92,Default,,0,0,0,,因为它不会被破坏 Dialogue: 0,0:20:39.92,0:20:41.31,Default,,0,0,0,,因此 如果我们利用这点 Dialogue: 0,0:20:44.12,0:20:47.56,Default,,0,0,0,,这里对F的求值 Dialogue: 0,0:20:48.57,0:20:50.44,Default,,0,0,0,,完全不需要担心 Dialogue: 0,0:20:51.61,0:20:52.60,Default,,0,0,0,,会破坏ENV Dialogue: 0,0:20:52.60,0:20:54.94,Default,,0,0,0,,类似地 这里对X的求值 Dialogue: 0,0:20:57.17,0:20:58.89,Default,,0,0,0,,当求值器进行求值时 它会说 Dialogue: 0,0:20:58.91,0:21:01.64,Default,,0,0,0,,我最好保存好与之有关的FUN寄存器 Dialogue: 0,0:21:02.07,0:21:03.22,Default,,0,0,0,,因为后面也许会用得着 Dialogue: 0,0:21:03.28,0:21:04.89,Default,,0,0,0,,我最好也保存参数表 Dialogue: 0,0:21:06.90,0:21:09.05,Default,,0,0,0,,然而 在这如果是编译器的话 Dialogue: 0,0:21:09.05,0:21:10.38,Default,,0,0,0,,实际需要哪些寄存器 Dialogue: 0,0:21:10.52,0:21:11.84,Default,,0,0,0,,从而进行相关的保存与恢复 Dialogue: 0,0:21:12.70,0:21:16.09,Default,,0,0,0,,事实上 这里求值器做的所有栈操作 Dialogue: 0,0:21:16.32,0:21:19.58,Default,,0,0,0,,都证明是过于悲观而不必要 Dialogue: 0,0:21:19.62,0:21:21.45,Default,,0,0,0,,而编译器在这里是知道这一点的 Dialogue: 0,0:21:27.35,0:21:28.48,Default,,0,0,0,,这是最基础的想法 Dialogue: 0,0:21:29.80,0:21:31.00,Default,,0,0,0,,我们把求值器 Dialogue: 0,0:21:31.00,0:21:33.24,Default,,0,0,0,,剔除那些不需要的东西 Dialogue: 0,0:21:33.24,0:21:35.24,Default,,0,0,0,,去除那些对于编译器完全无用的东西 Dialogue: 0,0:21:35.24,0:21:36.19,Default,,0,0,0,,只保留求值的部分 Dialogue: 0,0:21:37.40,0:21:40.40,Default,,0,0,0,,然后你可以看到哪些栈操作是不必要的 Dialogue: 0,0:21:40.82,0:21:43.76,Default,,0,0,0,,这就是书中所描述的编译器 Dialogue: 0,0:21:43.85,0:21:45.04,Default,,0,0,0,,的基本结构 Dialogue: 0,0:21:45.04,0:21:47.00,Default,,0,0,0,,我给你们展示一下这 Dialogue: 0,0:21:47.76,0:21:49.68,Default,,0,0,0,,这个简单的例子 Dialogue: 0,0:21:51.20,0:21:53.26,Default,,0,0,0,,为了说清楚 多余的东西是怎样保存的 Dialogue: 0,0:21:53.29,0:21:56.06,Default,,0,0,0,,我们来看一个稍复杂的表达式 Dialogue: 0,0:21:58.15,0:22:01.93,Default,,0,0,0,,(F (G X) 1) Dialogue: 0,0:22:03.87,0:22:05.52,Default,,0,0,0,,我们不会讲解所有的代码 Dialogue: 0,0:22:06.40,0:22:08.56,Default,,0,0,0,,因为代码有点多 Dialogue: 0,0:22:09.72,0:22:12.35,Default,,0,0,0,,我认为在求值器在处理它时 Dialogue: 0,0:22:12.35,0:22:14.67,Default,,0,0,0,,大概会产生 Dialogue: 0,0:22:14.70,0:22:16.25,Default,,0,0,0,,16对保存-恢复操作 Dialogue: 0,0:22:17.00,0:22:18.57,Default,,0,0,0,,这有一张图表 Dialogue: 0,0:22:20.57,0:22:21.95,Default,,0,0,0,,演示了其中的过程 Dialogue: 0,0:22:22.97,0:22:23.90,Default,,0,0,0,,你从这里开始-- Dialogue: 0,0:22:24.25,0:22:26.62,Default,,0,0,0,,求值器说:“我要求值一个应用” Dialogue: 0,0:22:26.90,0:22:29.13,Default,,0,0,0,,在这里保存ENV 又在这里恢复 Dialogue: 0,0:22:30.65,0:22:34.44,Default,,0,0,0,,然后处理第一个运算对象 Dialogue: 0,0:22:36.81,0:22:39.28,Default,,0,0,0,,这是求值器的递归调用 Dialogue: 0,0:22:39.28,0:22:40.89,Default,,0,0,0,,求值器发现 这是一个应用 Dialogue: 0,0:22:40.91,0:22:42.10,Default,,0,0,0,,又会保存环境 Dialogue: 0,0:22:42.10,0:22:44.97,Default,,0,0,0,,求值组合式的运算符 然后在这里恢复环境 Dialogue: 0,0:22:45.80,0:22:48.92,Default,,0,0,0,,这个恢复匹配的是这个保存操作 Dialogue: 0,0:22:49.77,0:22:50.78,Default,,0,0,0,,以此类推 Dialogue: 0,0:22:51.65,0:22:52.51,Default,,0,0,0,,这里的UNEV Dialogue: 0,0:22:52.52,0:22:54.62,Default,,0,0,0,,完全没有必要存在 Dialogue: 0,0:22:54.97,0:22:56.60,Default,,0,0,0,,CONTINUE寄存器不断地被保存-恢复 Dialogue: 0,0:22:57.42,0:23:00.41,Default,,0,0,0,,而FUN寄存器则是在 Dialogue: 0,0:23:00.78,0:23:04.36,Default,,0,0,0,,处理运算对象期间被保存 Dialogue: 0,0:23:05.10,0:23:06.52,Default,,0,0,0,,这类的事情一直在发生 Dialogue: 0,0:23:06.78,0:23:09.39,Default,,0,0,0,,但如果你问 跟求值器相比 Dialogue: 0,0:23:09.87,0:23:11.66,Default,,0,0,0,,编译器究竟要做什么? Dialogue: 0,0:23:12.27,0:23:13.55,Default,,0,0,0,,你会去掉一大堆东西 Dialogue: 0,0:23:14.30,0:23:16.64,Default,,0,0,0,,在这个的基础上 如果你说 Dialogue: 0,0:23:19.40,0:23:22.54,Default,,0,0,0,,对F的求值不会修改ENV寄存器 Dialogue: 0,0:23:23.82,0:23:26.51,Default,,0,0,0,,或者对符号X的查找 Dialogue: 0,0:23:29.28,0:23:32.09,Default,,0,0,0,,不需要特别保护FUN寄存器 Dialogue: 0,0:23:34.30,0:23:37.60,Default,,0,0,0,,就得到了只有几对的保存-恢复操作 Dialogue: 0,0:23:40.25,0:23:42.27,Default,,0,0,0,,然而 你还可以再优化一下 Dialogue: 0,0:23:42.27,0:23:44.33,Default,,0,0,0,,看看这里的ENV寄存器发生了什么 Dialogue: 0,0:23:45.21,0:23:47.39,Default,,0,0,0,,我们观察ENV寄存器的操作 发现 Dialogue: 0,0:23:51.00,0:23:52.25,Default,,0,0,0,,这是一个组合式 Dialogue: 0,0:23:54.33,0:23:55.69,Default,,0,0,0,,而这个求值器 Dialogue: 0,0:23:55.78,0:23:57.27,Default,,0,0,0,,对G一无所知 Dialogue: 0,0:23:58.57,0:24:00.73,Default,,0,0,0,,所以在这 它说 Dialogue: 0,0:24:01.29,0:24:03.45,Default,,0,0,0,,我最好保存ENV寄存器 Dialogue: 0,0:24:03.96,0:24:05.42,Default,,0,0,0,,因为对G的求值 Dialogue: 0,0:24:05.42,0:24:07.42,Default,,0,0,0,,可能会修改ENV寄存器的值 Dialogue: 0,0:24:07.55,0:24:09.45,Default,,0,0,0,,而我稍后可能会需要它 Dialogue: 0,0:24:10.17,0:24:11.40,Default,,0,0,0,,在这个参数之后 Dialogue: 0,0:24:12.22,0:24:13.37,Default,,0,0,0,,在处理第二个参数的时候 Dialogue: 0,0:24:15.60,0:24:17.24,Default,,0,0,0,,这就是为什么它没被优化掉 Dialogue: 0,0:24:19.07,0:24:22.54,Default,,0,0,0,,因为编译器没有对G将要做的事情做任何假设 Dialogue: 0,0:24:22.54,0:24:23.60,Default,,0,0,0,,另一方面 Dialogue: 0,0:24:24.61,0:24:26.52,Default,,0,0,0,,如果你看看这里的第二个参数 Dialogue: 0,0:24:26.64,0:24:27.70,Default,,0,0,0,,它只是查找“1”这个常量 Dialogue: 0,0:24:27.70,0:24:29.60,Default,,0,0,0,,这不需要ENV寄存器 Dialogue: 0,0:24:30.77,0:24:32.04,Default,,0,0,0,,因此没必要保存它 Dialogue: 0,0:24:32.06,0:24:33.77,Default,,0,0,0,,事实上 你也可以把这个也去掉 Dialogue: 0,0:24:34.85,0:24:37.81,Default,,0,0,0,,这一堆寄存器操作 Dialogue: 0,0:24:37.98,0:24:40.08,Default,,0,0,0,,如果你像这样简单地推理的话 Dialogue: 0,0:24:40.55,0:24:43.05,Default,,0,0,0,,只会剩下两对保存-恢复操作 Dialogue: 0,0:24:45.10,0:24:46.97,Default,,0,0,0,,而这些 如果你知道关于G的某些信息的话 Dialogue: 0,0:24:47.52,0:24:49.08,Default,,0,0,0,,可以进一步优化 Dialogue: 0,0:24:56.27,0:24:57.85,Default,,0,0,0,,基本的理念是 Dialogue: 0,0:24:57.95,0:24:59.98,Default,,0,0,0,,编译器之所以更好 Dialogue: 0,0:24:59.98,0:25:02.56,Default,,0,0,0,,是因为解释器对于将要处理的东西一无所知 Dialogue: 0,0:25:03.25,0:25:05.04,Default,,0,0,0,,它不得不以最悲观的方式保存东西 Dialogue: 0,0:25:05.05,0:25:06.70,Default,,0,0,0,,来保护它自己 Dialogue: 0,0:25:07.90,0:25:08.76,Default,,0,0,0,,而编译器 Dialogue: 0,0:25:09.48,0:25:12.38,Default,,0,0,0,,只需要保存实际需要的东西 Dialogue: 0,0:25:13.37,0:25:15.20,Default,,0,0,0,,某个东西是否需要保存 Dialogue: 0,0:25:15.24,0:25:17.37,Default,,0,0,0,,有两种原因 Dialogue: 0,0:25:17.82,0:25:18.70,Default,,0,0,0,,一种是 Dialogue: 0,0:25:18.70,0:25:19.82,Default,,0,0,0,,你保护的东西 Dialogue: 0,0:25:19.95,0:25:21.44,Default,,0,0,0,,不会修改寄存器 Dialogue: 0,0:25:22.08,0:25:23.58,Default,,0,0,0,,例如 变量查找 Dialogue: 0,0:25:24.12,0:25:25.20,Default,,0,0,0,,另一种原因是 Dialogue: 0,0:25:25.32,0:25:27.10,Default,,0,0,0,,你所保存的东西 Dialogue: 0,0:25:28.28,0:25:29.92,Default,,0,0,0,,最后并不会被用到 Dialogue: 0,0:25:30.81,0:25:34.27,Default,,0,0,0,,因此 编译器正是利用了 Dialogue: 0,0:25:34.30,0:25:35.88,Default,,0,0,0,,这两条基本原则 Dialogue: 0,0:25:36.27,0:25:37.76,Default,,0,0,0,,来让代码变得更高效的 Dialogue: 0,0:25:44.27,0:25:45.32,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:25:51.20,0:25:53.10,Default,,0,0,0,,学生: 你一直在说UNEV寄存器 Dialogue: 0,0:25:53.13,0:25:56.40,Default,,0,0,0,,UNEV寄存器完全不会被用到 Dialogue: 0,0:25:56.41,0:25:58.68,Default,,0,0,0,,是否意味着 机器只需要6个寄存器足矣? Dialogue: 0,0:25:58.70,0:26:00.08,Default,,0,0,0,,或者是说 在这个特定的例子里 Dialogue: 0,0:26:00.11,0:26:01.18,Default,,0,0,0,,它没有被用到? Dialogue: 0,0:26:01.72,0:26:02.81,Default,,0,0,0,,教授: 对于编译器 Dialogue: 0,0:26:04.31,0:26:07.42,Default,,0,0,0,,你可以生成6个或5个寄存器的代码 Dialogue: 0,0:26:07.56,0:26:09.02,Default,,0,0,0,,因为EXP寄存器也没有用到 Dialogue: 0,0:26:09.40,0:26:14.57,Default,,0,0,0,,是的 你可以把EXP和UNEV都去掉 Dialogue: 0,0:26:14.57,0:26:16.87,Default,,0,0,0,,因为这些是求值器的数据结构 Dialogue: 0,0:26:17.36,0:26:19.36,Default,,0,0,0,,以编译器的视角来看 Dialogue: 0,0:26:19.39,0:26:20.87,Default,,0,0,0,,这些东西都是常量 Dialogue: 0,0:26:21.65,0:26:22.44,Default,,0,0,0,,关键在于 Dialogue: 0,0:26:22.48,0:26:24.59,Default,,0,0,0,,这个特定编译器是被构造出来的 Dialogue: 0,0:26:24.79,0:26:27.92,Default,,0,0,0,,因此被解释的代码和被编译的代码可以共存 Dialogue: 0,0:26:29.32,0:26:30.72,Default,,0,0,0,,可以这样看待它 Dialogue: 0,0:26:30.97,0:26:32.29,Default,,0,0,0,,你构建了一个芯片 Dialogue: 0,0:26:34.30,0:26:35.50,Default,,0,0,0,,它就是求值器 Dialogue: 0,0:26:35.88,0:26:37.28,Default,,0,0,0,,而编译器可以做的就是 Dialogue: 0,0:26:37.31,0:26:39.02,Default,,0,0,0,,为这个芯片生成代码 Dialogue: 0,0:26:40.40,0:26:41.90,Default,,0,0,0,,只是它不会用到两个寄存器而已 Dialogue: 0,0:26:51.52,0:26:52.47,Default,,0,0,0,,好 休息一会 Dialogue: 0,0:26:53.55,0:27:07.18,Default,,0,0,0,,[音乐] Dialogue: 0,0:27:07.37,0:27:11.42,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:27:14.57,0:27:18.12,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:27:18.17,0:27:22.08,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:27:22.22,0:27:26.48,Declare,,0,0,0,,{\an2\fad(500,500)}编译 Dialogue: 0,0:27:29.21,0:27:32.43,Default,,0,0,0,,我们刚才研究了编译器应该要做什么 Dialogue: 0,0:27:32.78,0:27:36.04,Default,,0,0,0,,现在我们来简略地看看 Dialogue: 0,0:27:36.15,0:27:37.47,Default,,0,0,0,,这些目标如何达成 Dialogue: 0,0:27:38.26,0:27:39.58,Default,,0,0,0,,而我不会给出细节 Dialogue: 0,0:27:39.60,0:27:42.17,Default,,0,0,0,,在书中有一大堆代码 Dialogue: 0,0:27:42.22,0:27:43.42,Default,,0,0,0,,展示了所有细节 Dialogue: 0,0:27:43.45,0:27:45.31,Default,,0,0,0,,我要做的 是给你们展示 Dialogue: 0,0:27:45.96,0:27:47.26,Default,,0,0,0,,其中的关键思想 Dialogue: 0,0:27:49.49,0:27:51.36,Default,,0,0,0,,换个时间再来关心细节 Dialogue: 0,0:27:51.51,0:27:55.30,Default,,0,0,0,,设想我们正在编译一条表达式 Dialogue: 0,0:27:55.30,0:27:57.01,Default,,0,0,0,,这里有一些运算符 Dialogue: 0,0:27:57.48,0:27:58.56,Default,,0,0,0,,和两个参数 Dialogue: 0,0:28:03.56,0:28:04.24,Default,,0,0,0,,现在 Dialogue: 0,0:28:06.27,0:28:08.14,Default,,0,0,0,,这个编译器会生成什么代码? Dialogue: 0,0:28:08.85,0:28:09.78,Default,,0,0,0,,首先 Dialogue: 0,0:28:09.83,0:28:11.20,Default,,0,0,0,,它会递归运行 Dialogue: 0,0:28:11.90,0:28:13.28,Default,,0,0,0,,编译运算符 Dialogue: 0,0:28:14.37,0:28:19.02,Default,,0,0,0,,它说 我要编译运算符 Dialogue: 0,0:28:21.16,0:28:24.54,Default,,0,0,0,,最后我需要让它们的结果 Dialogue: 0,0:28:24.84,0:28:27.95,Default,,0,0,0,,存放在FUN寄存器中 Dialogue: 0,0:28:28.42,0:28:29.60,Default,,0,0,0,,所以我编译一些指令 Dialogue: 0,0:28:29.64,0:28:31.56,Default,,0,0,0,,它们会编译运算符 Dialogue: 0,0:28:31.69,0:28:38.62,Default,,0,0,0,,最后把结果放在FUN寄存器中 Dialogue: 0,0:28:45.51,0:28:46.94,Default,,0,0,0,,接下来我要做的是 Dialogue: 0,0:28:47.71,0:28:49.68,Default,,0,0,0,,另一个代码片段则说 Dialogue: 0,0:28:49.68,0:28:55.17,Default,,0,0,0,,我要编译第一个参数 Dialogue: 0,0:28:55.17,0:28:56.80,Default,,0,0,0,,因此它递归调地用自己 Dialogue: 0,0:28:58.04,0:29:03.36,Default,,0,0,0,,而结果会被放在VAL中 Dialogue: 0,0:29:09.07,0:29:10.75,Default,,0,0,0,,接下来需要做的是 Dialogue: 0,0:29:10.75,0:29:12.26,Default,,0,0,0,,建立起参数表 Dialogue: 0,0:29:12.95,0:29:25.50,Default,,0,0,0,,(ASSIGN ARGL (CONS (FETCH -- Dialogue: 0,0:29:25.55,0:29:27.10,Default,,0,0,0,,它会生成这些代码 Dialogue: 0,0:29:27.50,0:29:32.51,Default,,0,0,0,,(FETCH VAL) '())) Dialogue: 0,0:29:35.00,0:29:36.05,Default,,0,0,0,,然而 Dialogue: 0,0:29:37.99,0:29:40.61,Default,,0,0,0,,当它到这里时 Dialogue: 0,0:29:41.32,0:29:42.82,Default,,0,0,0,,它可能需要环境 Dialogue: 0,0:29:43.95,0:29:45.29,Default,,0,0,0,,它需要环境 Dialogue: 0,0:29:45.32,0:29:48.21,Default,,0,0,0,,这是求值第一个参数所需要的 Dialogue: 0,0:29:49.04,0:29:51.18,Default,,0,0,0,,因此 它需要保证 Dialogue: 0,0:29:51.92,0:29:53.76,Default,,0,0,0,,对运算对象的编译 Dialogue: 0,0:29:55.32,0:29:57.85,Default,,0,0,0,,或者说它需要保护FUN寄存器 Dialogue: 0,0:29:58.01,0:30:00.98,Default,,0,0,0,,来应对编译运算对象时发生的各种情况 Dialogue: 0,0:30:01.30,0:30:03.08,Default,,0,0,0,,因此它在这做了个标注说 Dialogue: 0,0:30:03.37,0:30:12.89,Default,,0,0,0,,这个片段需要保护ENV寄存器 Dialogue: 0,0:30:17.39,0:30:18.44,Default,,0,0,0,,与之类似 这里 Dialogue: 0,0:30:21.02,0:30:23.30,Default,,0,0,0,,在完成第一个运算对象的编译后 Dialogue: 0,0:30:23.57,0:30:24.67,Default,,0,0,0,,它会说 我最好-- Dialogue: 0,0:30:24.71,0:30:27.92,Default,,0,0,0,,我需要知道第二个运算对象的环境 Dialogue: 0,0:30:27.92,0:30:29.46,Default,,0,0,0,,所以它在这做了个标注 Dialogue: 0,0:30:29.71,0:30:35.96,Default,,0,0,0,,这里也需要保护ENV Dialogue: 0,0:30:39.42,0:30:41.02,Default,,0,0,0,,现在它继续运行 Dialogue: 0,0:30:41.12,0:30:42.83,Default,,0,0,0,,下一段代码 Dialogue: 0,0:30:43.31,0:30:49.74,Default,,0,0,0,,是要编译第二个参数 Dialogue: 0,0:30:50.82,0:30:52.64,Default,,0,0,0,,它将会 Dialogue: 0,0:30:52.99,0:30:59.28,Default,,0,0,0,,把编译的结果按约定放入到VAL中 Dialogue: 0,0:31:03.86,0:31:06.70,Default,,0,0,0,,随后它会生成一条指令 Dialogue: 0,0:31:07.84,0:31:09.25,Default,,0,0,0,,从而建立起参数表 Dialogue: 0,0:31:09.55,0:31:15.28,Default,,0,0,0,,(ASSIGN ARGL Dialogue: 0,0:31:20.22,0:31:28.94,Default,,0,0,0,,(CONS (FETCH VAL) (FETCH ARGL)) Dialogue: 0,0:31:33.97,0:31:34.64,Default,,0,0,0,,然而 Dialogue: 0,0:31:34.81,0:31:36.58,Default,,0,0,0,,为了取得旧的参数表 Dialogue: 0,0:31:37.15,0:31:40.99,Default,,0,0,0,,它最好保证这期间发生的任何事情 Dialogue: 0,0:31:41.30,0:31:42.69,Default,,0,0,0,,都不影响旧的参数表 Dialogue: 0,0:31:43.50,0:31:45.17,Default,,0,0,0,,因此它在这做了个标注说 Dialogue: 0,0:31:45.34,0:31:51.64,Default,,0,0,0,,哦 这里需要保护ARGL Dialogue: 0,0:31:54.16,0:31:56.03,Default,,0,0,0,,现在参数表就建立好了 Dialogue: 0,0:31:58.01,0:32:02.86,Default,,0,0,0,,现在可以准备去APPLY-DISPATCH了 Dialogue: 0,0:32:07.02,0:32:10.80,Default,,0,0,0,,它生成了这条指令 Dialogue: 0,0:32:15.19,0:32:17.37,Default,,0,0,0,,因为现在参数都在ARGL中 Dialogue: 0,0:32:18.15,0:32:20.59,Default,,0,0,0,,运算符在FUN中 Dialogue: 0,0:32:20.59,0:32:22.89,Default,,0,0,0,,如果只是单纯地把运算符放到FUN寄存器中 Dialogue: 0,0:32:23.27,0:32:26.64,Default,,0,0,0,,就需要它保证这块代码 Dialogue: 0,0:32:27.09,0:32:29.27,Default,,0,0,0,,不会破坏FUN寄存器里的东西 Dialogue: 0,0:32:29.67,0:32:31.24,Default,,0,0,0,,所以它在这做了个标注说 Dialogue: 0,0:32:31.55,0:32:32.73,Default,,0,0,0,,这里的所有东西 Dialogue: 0,0:32:34.88,0:32:40.73,Default,,0,0,0,,最好能够在保护FUN寄存器的情况下完成 Dialogue: 0,0:32:43.71,0:32:46.15,Default,,0,0,0,,所以这就是-- Dialogue: 0,0:32:46.15,0:32:47.10,Default,,0,0,0,,基本上来说 Dialogue: 0,0:32:48.20,0:32:50.24,Default,,0,0,0,,编译器所做的就是 Dialogue: 0,0:32:50.54,0:32:52.46,Default,,0,0,0,,追加一大堆的代码 Dialogue: 0,0:32:53.50,0:32:58.83,Default,,0,0,0,,而这些代码之中都是一些基本运算 Dialogue: 0,0:32:58.86,0:33:00.12,Default,,0,0,0,,比如符号查找 Dialogue: 0,0:33:01.44,0:33:02.60,Default,,0,0,0,,条件分支的处理 Dialogue: 0,0:33:02.64,0:33:05.44,Default,,0,0,0,,都是一些琐碎的事情 Dialogue: 0,0:33:05.44,0:33:07.99,Default,,0,0,0,,然后按照这种准则将它们追加到一起 Dialogue: 0,0:33:08.78,0:33:10.79,Default,,0,0,0,,因此 组合的基本手段就是 Dialogue: 0,0:33:10.86,0:33:13.18,Default,,0,0,0,,将一段代码追加到另一段的后面 Dialogue: 0,0:33:21.55,0:33:22.86,Default,,0,0,0,,就是这里发生的事情 Dialogue: 0,0:33:25.58,0:33:27.24,Default,,0,0,0,,这有点取巧 Dialogue: 0,0:33:27.56,0:33:30.37,Default,,0,0,0,,向一段代码后面追加代码的思路是 Dialogue: 0,0:33:31.60,0:33:33.76,Default,,0,0,0,,小心保护寄存器 Dialogue: 0,0:33:35.63,0:33:37.93,Default,,0,0,0,,追加操作看起来像这样 Dialogue: 0,0:33:39.15,0:33:40.65,Default,,0,0,0,,它要做的是 Dialogue: 0,0:33:41.20,0:33:44.11,Default,,0,0,0,,代码的追加是这么来做的 Dialogue: 0,0:33:44.53,0:33:53.63,Default,,0,0,0,,如果SEQ1需要寄存器-- Dialogue: 0,0:33:53.66,0:33:54.72,Default,,0,0,0,,我应该改一下这个 Dialogue: 0,0:33:54.72,0:33:56.87,Default,,0,0,0,,在SEQ1后面追加SEQ2 Dialogue: 0,0:33:57.42,0:34:03.96,Default,,0,0,0,,并保护一些寄存器 Dialogue: 0,0:34:08.52,0:34:09.91,Default,,0,0,0,,这里改成AND Dialogue: 0,0:34:11.36,0:34:13.03,Default,,0,0,0,,这样的话前后顺序就清楚了 Dialogue: 0,0:34:13.88,0:34:19.87,Default,,0,0,0,,如果SEQ2需要寄存器 Dialogue: 0,0:34:21.12,0:34:27.85,Default,,0,0,0,,而SEQ1又修改了寄存器 Dialogue: 0,0:34:33.68,0:34:36.30,Default,,0,0,0,,那么编译器生成的指令是 Dialogue: 0,0:34:36.97,0:34:41.34,Default,,0,0,0,,保存寄存器 Dialogue: 0,0:34:43.02,0:34:44.19,Default,,0,0,0,,这就是代码 Dialogue: 0,0:34:44.35,0:34:45.35,Default,,0,0,0,,生成这段代码 Dialogue: 0,0:34:45.35,0:34:46.28,Default,,0,0,0,,保存寄存器 Dialogue: 0,0:34:46.72,0:34:52.97,Default,,0,0,0,,然后写下递归编译SEQ1的结果 Dialogue: 0,0:34:53.30,0:34:54.84,Default,,0,0,0,,然后恢复寄存器 Dialogue: 0,0:35:00.52,0:35:03.92,Default,,0,0,0,,再写下递归编译 Dialogue: 0,0:35:04.46,0:35:05.47,Default,,0,0,0,,SEQ2的结果 Dialogue: 0,0:35:07.07,0:35:09.62,Default,,0,0,0,,这就是你需要做的 Dialogue: 0,0:35:09.62,0:35:11.82,Default,,0,0,0,,实际上SEQ2需要寄存器 Dialogue: 0,0:35:11.82,0:35:13.74,Default,,0,0,0,,而SEQ1改动了它 Dialogue: 0,0:35:15.12,0:35:17.07,Default,,0,0,0,,否则的话 Dialogue: 0,0:35:20.50,0:35:26.57,Default,,0,0,0,,得到的就是SEQ1后面跟着SEQ2 Dialogue: 0,0:35:28.17,0:35:30.30,Default,,0,0,0,,这就是把两个代码片段 Dialogue: 0,0:35:30.59,0:35:33.52,Default,,0,0,0,,连接到一起的基本操作 Dialogue: 0,0:35:33.93,0:35:35.93,Default,,0,0,0,,把这些指令组合成序列 Dialogue: 0,0:35:36.89,0:35:38.87,Default,,0,0,0,,我们可以发现 从这个角度看 Dialogue: 0,0:35:40.94,0:35:45.96,Default,,0,0,0,,解释器和编译器的区别 Dialogue: 0,0:35:46.82,0:35:49.34,Default,,0,0,0,,是编译器有保护寄存器的标注 Dialogue: 0,0:35:50.14,0:35:52.22,Default,,0,0,0,,上面记录着 Dialogue: 0,0:35:52.49,0:35:54.22,Default,,0,0,0,,是否需要生成保存-恢复代码 Dialogue: 0,0:35:55.19,0:35:57.24,Default,,0,0,0,,而解释器会以最悲观的方式处理 Dialogue: 0,0:35:57.28,0:35:58.90,Default,,0,0,0,,总是会进行保存-恢复 Dialogue: 0,0:36:00.76,0:36:01.93,Default,,0,0,0,,这就是关键的区别 Dialogue: 0,0:36:04.16,0:36:06.05,Default,,0,0,0,,为了实现这个 Dialogue: 0,0:36:06.65,0:36:09.40,Default,,0,0,0,,编译器需要一些理论 Dialogue: 0,0:36:09.56,0:36:11.96,Default,,0,0,0,,来确定代码序列会需要、又会修改哪些寄存器 Dialogue: 0,0:36:14.26,0:36:17.28,Default,,0,0,0,,所以你放入的小片段 Dialogue: 0,0:36:17.48,0:36:21.00,Default,,0,0,0,,例如这段基础代码 Dialogue: 0,0:36:22.74,0:36:24.59,Default,,0,0,0,,当你查找一个变量时 Dialogue: 0,0:36:24.92,0:36:26.04,Default,,0,0,0,,进行了哪些操作? Dialogue: 0,0:36:26.89,0:36:29.02,Default,,0,0,0,,你又是做了些什么 Dialogue: 0,0:36:29.05,0:36:30.68,Default,,0,0,0,,来编译一个常量 Dialogue: 0,0:36:30.97,0:36:32.10,Default,,0,0,0,,或者应用一个函数 Dialogue: 0,0:36:32.97,0:36:34.48,Default,,0,0,0,,它们都会带有一些标注 Dialogue: 0,0:36:34.67,0:36:36.46,Default,,0,0,0,,说明了它们需要的和修改的寄存器 Dialogue: 0,0:36:38.78,0:36:41.50,Default,,0,0,0,,所以底层的数据结构 Dialogue: 0,0:36:42.66,0:36:44.33,Default,,0,0,0,,我会这样讲 Dialogue: 0,0:36:44.39,0:36:47.91,Default,,0,0,0,,传递给编译器的代码序列大概是这样 Dialogue: 0,0:36:48.07,0:36:51.42,Default,,0,0,0,,它里面有实际的指令序列 Dialogue: 0,0:36:55.67,0:36:56.81,Default,,0,0,0,,跟它一起的还有 Dialogue: 0,0:36:57.18,0:37:02.60,Default,,0,0,0,,一组被修改的寄存器 Dialogue: 0,0:37:10.54,0:37:12.60,Default,,0,0,0,,还有一组需要的寄存器 Dialogue: 0,0:37:20.00,0:37:22.46,Default,,0,0,0,,为了能够执行此操作 Dialogue: 0,0:37:23.00,0:37:26.41,Default,,0,0,0,,编译器必须要掌握这些信息 Dialogue: 0,0:37:29.30,0:37:31.08,Default,,0,0,0,,它们从哪来呢 Dialogue: 0,0:37:32.91,0:37:34.49,Default,,0,0,0,,它们来自于--你们可能也想到了 Dialogue: 0,0:37:34.51,0:37:35.53,Default,,0,0,0,,对于那些最基本的片段 Dialogue: 0,0:37:35.55,0:37:36.84,Default,,0,0,0,,我们会手工添加 Dialogue: 0,0:37:37.24,0:37:38.86,Default,,0,0,0,,然后 当我们组合两个序列时 Dialogue: 0,0:37:38.89,0:37:41.02,Default,,0,0,0,,我们会计算出这两个集合 Dialogue: 0,0:37:42.16,0:37:44.12,Default,,0,0,0,,举一个非常基本的例子 Dialogue: 0,0:37:48.43,0:37:51.40,Default,,0,0,0,,例如做一个寄存器赋值 Dialogue: 0,0:37:51.77,0:37:53.50,Default,,0,0,0,,因此 基本代码片段会说 Dialogue: 0,0:37:53.52,0:37:56.22,Default,,0,0,0,,噢 它是个代码片段 Dialogue: 0,0:37:56.22,0:38:03.17,Default,,0,0,0,,代码的指令部分是(ASSIGN R1 (FETCH R2)) Dialogue: 0,0:38:03.17,0:38:04.27,Default,,0,0,0,,这个例子就是这样的 Dialogue: 0,0:38:05.42,0:38:08.52,Default,,0,0,0,,一段指令序列大概就是这样 Dialogue: 0,0:38:08.77,0:38:10.53,Default,,0,0,0,,和它在一起的是 Dialogue: 0,0:38:10.64,0:38:15.76,Default,,0,0,0,,它需要记得修改了R1 Dialogue: 0,0:38:18.60,0:38:21.16,Default,,0,0,0,,然后它需要R2 Dialogue: 0,0:38:24.69,0:38:26.99,Default,,0,0,0,,因此当你开始构建编译器时 Dialogue: 0,0:38:27.10,0:38:29.35,Default,,0,0,0,,你放入这样的一个片段 Dialogue: 0,0:38:30.95,0:38:33.20,Default,,0,0,0,,当它组合两个序列时 Dialogue: 0,0:38:36.70,0:38:38.04,Default,,0,0,0,,我要组合 Dialogue: 0,0:38:38.92,0:38:41.58,Default,,0,0,0,,代码片段S1 Dialogue: 0,0:38:42.88,0:38:47.16,Default,,0,0,0,,修改了一组寄存器M1 Dialogue: 0,0:38:48.45,0:38:51.42,Default,,0,0,0,,并且需要一组寄存器N1 Dialogue: 0,0:38:54.85,0:38:59.48,Default,,0,0,0,,并且我要把它和序列S2组合到一起 Dialogue: 0,0:39:00.81,0:39:05.96,Default,,0,0,0,,后者修改了一组寄存器M2 Dialogue: 0,0:39:07.11,0:39:10.00,Default,,0,0,0,,并且需要一组寄存器N2 Dialogue: 0,0:39:12.44,0:39:14.83,Default,,0,0,0,,这样我们就能得出结果 Dialogue: 0,0:39:15.11,0:39:16.32,Default,,0,0,0,,新的代码片段是这样的 Dialogue: 0,0:39:17.18,0:39:21.82,Default,,0,0,0,,指令序列S1后面跟着S2 Dialogue: 0,0:39:24.09,0:39:26.45,Default,,0,0,0,,它要修改什么? Dialogue: 0,0:39:27.80,0:39:29.18,Default,,0,0,0,,它要修改的是 Dialogue: 0,0:39:29.20,0:39:32.68,Default,,0,0,0,,被S1或者被S2修改的寄存器 Dialogue: 0,0:39:34.00,0:39:36.35,Default,,0,0,0,,N1和N2的并集 Dialogue: 0,0:39:37.68,0:39:39.64,Default,,0,0,0,,就是新的修改集 Dialogue: 0,0:39:40.46,0:39:41.79,Default,,0,0,0,,然后你问 Dialogue: 0,0:39:44.66,0:39:46.41,Default,,0,0,0,,又需要哪些寄存器? Dialogue: 0,0:39:47.95,0:39:49.77,Default,,0,0,0,,需要这些寄存器的是 Dialogue: 0,0:39:49.93,0:39:51.85,Default,,0,0,0,,首先 一定是序列S1需要的 Dialogue: 0,0:39:52.91,0:39:54.49,Default,,0,0,0,,因此必然有N1 Dialogue: 0,0:39:55.19,0:39:58.28,Default,,0,0,0,,然后 并不是N2里面的所有元素 Dialogue: 0,0:39:58.32,0:39:59.61,Default,,0,0,0,,我们都需要 Dialogue: 0,0:39:59.75,0:40:03.49,Default,,0,0,0,,新的修改集需要N2中那些 Dialogue: 0,0:40:03.88,0:40:06.88,Default,,0,0,0,,没有被S1修改过的寄存器 Dialogue: 0,0:40:08.14,0:40:09.72,Default,,0,0,0,,所以 这个并集是N1并上 Dialogue: 0,0:40:11.66,0:40:13.40,Default,,0,0,0,,序列S2的需要集N2 Dialogue: 0,0:40:14.51,0:40:18.52,Default,,0,0,0,,减去序列S1的修改集M1 Dialogue: 0,0:40:19.31,0:40:20.88,Default,,0,0,0,,因为它关心的是如何设置它们 Dialogue: 0,0:40:23.95,0:40:26.26,Default,,0,0,0,,这就是编译器的基本结构 Dialogue: 0,0:40:26.70,0:40:29.82,Default,,0,0,0,,我们进行寄存器优化的方式是 Dialogue: 0,0:40:30.22,0:40:32.70,Default,,0,0,0,,一些策略来应对需要保护的东西 Dialogue: 0,0:40:34.10,0:40:35.63,Default,,0,0,0,,这取决于数据结构 Dialogue: 0,0:40:35.72,0:40:38.51,Default,,0,0,0,,这取决于将东西组合在一起的操作 Dialogue: 0,0:40:39.03,0:40:41.63,Default,,0,0,0,,想知道要保护哪些东西 Dialogue: 0,0:40:41.93,0:40:47.28,Default,,0,0,0,,就需要知道这段代码需要以及修改的寄存器 Dialogue: 0,0:40:48.75,0:40:51.26,Default,,0,0,0,,这就需要我们有一个数据结构 Dialogue: 0,0:40:51.42,0:40:55.43,Default,,0,0,0,,它不但要存放实际的指令序列 Dialogue: 0,0:40:55.60,0:40:57.33,Default,,0,0,0,,它修改了什么 又需要什么 Dialogue: 0,0:40:57.33,0:40:59.77,Default,,0,0,0,,这些信息来自于--最基本的情况是内置的 Dialogue: 0,0:40:59.79,0:41:01.36,Default,,0,0,0,,对于最基本的情况 Dialogue: 0,0:41:01.37,0:41:02.52,Default,,0,0,0,,我们可以容易地知道 Dialogue: 0,0:41:03.00,0:41:04.44,Default,,0,0,0,,需要哪些寄存器 又修改了哪些 Dialogue: 0,0:41:04.82,0:41:05.35,Default,,0,0,0,,另外 Dialogue: 0,0:41:05.44,0:41:08.60,Default,,0,0,0,,利用这个特定的方法构建复杂指令时 Dialogue: 0,0:41:09.28,0:41:11.89,Default,,0,0,0,,我们可以像这样生成新的修改集 Dialogue: 0,0:41:11.93,0:41:13.37,Default,,0,0,0,,以及新的需要集 Dialogue: 0,0:41:15.27,0:41:17.77,Default,,0,0,0,,这就是全部的内容 -- 我不该这么说 Dialogue: 0,0:41:17.77,0:41:19.34,Default,,0,0,0,,这就是书里面大概30页的细节 Dialogue: 0,0:41:19.74,0:41:21.87,Default,,0,0,0,,的核心内容了 Dialogue: 0,0:41:22.31,0:41:27.69,Default,,0,0,0,,但它是一个完全可用的初级编译器 Dialogue: 0,0:41:28.76,0:41:31.37,Default,,0,0,0,,让我给你展示一下它能做什么 Dialogue: 0,0:41:31.39,0:41:35.56,Default,,0,0,0,,假设我们从一个递归阶乘开始 Dialogue: 0,0:41:36.20,0:41:38.60,Default,,0,0,0,,这些幻灯片的字太小不适合阅读 Dialogue: 0,0:41:38.60,0:41:39.79,Default,,0,0,0,,我只想快速翻一下代码 Dialogue: 0,0:41:39.79,0:41:41.28,Default,,0,0,0,,让你们看看它有多少代码 Dialogue: 0,0:41:42.25,0:41:43.29,Default,,0,0,0,,代码从这开始-- Dialogue: 0,0:41:44.32,0:41:45.68,Default,,0,0,0,,这是代码的第一部分 Dialogue: 0,0:41:45.95,0:41:47.68,Default,,0,0,0,,这里编译了一个过程入口 Dialogue: 0,0:41:47.69,0:41:48.73,Default,,0,0,0,,并进行了一些赋值操作 Dialogue: 0,0:41:48.75,0:41:51.48,Default,,0,0,0,,这基本上对应了解释器中 Dialogue: 0,0:41:52.65,0:41:53.90,Default,,0,0,0,,进行判断之前的部分 Dialogue: 0,0:41:54.31,0:41:56.59,Default,,0,0,0,,并判断谓词是否成立 Dialogue: 0,0:41:56.97,0:41:57.85,Default,,0,0,0,,第二部分是 Dialogue: 0,0:41:58.46,0:42:03.73,Default,,0,0,0,,递归调用N-1的阶乘的结果 Dialogue: 0,0:42:04.12,0:42:05.05,Default,,0,0,0,,最后一部分是 Dialogue: 0,0:42:06.07,0:42:07.48,Default,,0,0,0,,从那里返回 Dialogue: 0,0:42:07.87,0:42:09.90,Default,,0,0,0,,并处理递归的基本情况 Dialogue: 0,0:42:09.90,0:42:13.16,Default,,0,0,0,,这就是编译阶乘会生成的代码量 Dialogue: 0,0:42:13.72,0:42:17.69,Default,,0,0,0,,当然 我们可以把这个编译器做得更好 Dialogue: 0,0:42:18.67,0:42:21.24,Default,,0,0,0,,优化它的主要方式是 Dialogue: 0,0:42:21.24,0:42:24.00,Default,,0,0,0,,当你调用一个过程时 Dialogue: 0,0:42:24.35,0:42:26.27,Default,,0,0,0,,允许编译器做任何假设 Dialogue: 0,0:42:26.97,0:42:28.28,Default,,0,0,0,,举例来说 Dialogue: 0,0:42:28.30,0:42:32.32,Default,,0,0,0,,这个编译器甚至不知道 Dialogue: 0,0:42:33.12,0:42:36.14,Default,,0,0,0,,乘法可以被内联执行 Dialogue: 0,0:42:36.14,0:42:37.87,Default,,0,0,0,,它则会自行构建起整个机制 Dialogue: 0,0:42:38.00,0:42:39.34,Default,,0,0,0,,进行APPLY-DISPATCH Dialogue: 0,0:42:41.37,0:42:42.49,Default,,0,0,0,,这是极大的浪费 Dialogue: 0,0:42:42.54,0:42:45.02,Default,,0,0,0,,因为 每当你进行APPLY-DISPATCH时 Dialogue: 0,0:42:45.02,0:42:46.80,Default,,0,0,0,,你都要关心这个参数表 Dialogue: 0,0:42:47.40,0:42:49.10,Default,,0,0,0,,因为它是个很普遍的操作 Dialogue: 0,0:42:49.13,0:42:51.07,Default,,0,0,0,,在任何真实的编译器中 Dialogue: 0,0:42:51.08,0:42:53.29,Default,,0,0,0,,你会有寄存器来暂存参数 Dialogue: 0,0:42:53.77,0:42:55.31,Default,,0,0,0,,你要开始保护 Dialogue: 0,0:42:56.38,0:42:58.05,Default,,0,0,0,,保存这些寄存器 Dialogue: 0,0:42:58.05,0:43:01.61,Default,,0,0,0,,和这里的策略相近 Dialogue: 0,0:43:02.85,0:43:05.93,Default,,0,0,0,,因此 我们可能主要通过这个方法 Dialogue: 0,0:43:05.95,0:43:08.30,Default,,0,0,0,,来优化书中这个特定的编译器 Dialogue: 0,0:43:08.69,0:43:09.70,Default,,0,0,0,,还有其它的一些方法 Dialogue: 0,0:43:09.70,0:43:11.82,Default,,0,0,0,,比如查找变量的值 Dialogue: 0,0:43:11.83,0:43:13.87,Default,,0,0,0,,使用更高效的基本操作 Dialogue: 0,0:43:13.88,0:43:14.56,Default,,0,0,0,,等等方法 Dialogue: 0,0:43:14.59,0:43:16.60,Default,,0,0,0,,本质上来说 一个好的Lisp编译器 Dialogue: 0,0:43:16.62,0:43:18.49,Default,,0,0,0,,可以吸收任意数量的努力 Dialogue: 0,0:43:19.72,0:43:21.63,Default,,0,0,0,,可能这其中的一个原因是 Dialogue: 0,0:43:21.89,0:43:23.04,Default,,0,0,0,,跟FORTRAN这类语言相比 Dialogue: 0,0:43:23.63,0:43:25.44,Default,,0,0,0,,Lisp就要慢一些 Dialogue: 0,0:43:25.90,0:43:28.19,Default,,0,0,0,,如果你回头审视历史 Dialogue: 0,0:43:28.22,0:43:31.12,Default,,0,0,0,,会发现人们为构建Lisp编译器而呕心沥血 Dialogue: 0,0:43:31.16,0:43:32.35,Default,,0,0,0,,但也远远没有接近 Dialogue: 0,0:43:32.36,0:43:33.90,Default,,0,0,0,,构建FORTRAN编译器的工作量 Dialogue: 0,0:43:34.43,0:43:35.79,Default,,0,0,0,,在接下来的几年 Dialogue: 0,0:43:35.92,0:43:37.68,Default,,0,0,0,,情况可能会发生变化 Dialogue: 0,0:43:38.00,0:43:38.83,Default,,0,0,0,,好吧 就讲到这里 Dialogue: 0,0:43:43.80,0:43:44.65,Default,,0,0,0,,有问题吗 Dialogue: 0,0:43:48.27,0:43:49.95,Default,,0,0,0,,学生: 很早的一个课时里-- Dialogue: 0,0:43:49.95,0:43:51.40,Default,,0,0,0,,我不记得是课上还是课后-- Dialogue: 0,0:43:51.47,0:43:53.88,Default,,0,0,0,,你向我们展示了 Dialogue: 0,0:43:54.00,0:43:57.52,Default,,0,0,0,,ADD操作有一些我们看不到的基本运算 Dialogue: 0,0:43:57.69,0:43:59.21,Default,,0,0,0,,类似于ADD%之类的 Dialogue: 0,0:43:59.82,0:44:01.65,Default,,0,0,0,,这是因为 Dialogue: 0,0:44:01.65,0:44:02.60,Default,,0,0,0,,你想把代码内联为 Dialogue: 0,0:44:02.60,0:44:08.19,Default,,0,0,0,,专门针对二元运算对象的运算么? Dialogue: 0,0:44:08.70,0:44:10.25,Default,,0,0,0,,但如果你有更多的运算对象 Dialogue: 0,0:44:10.28,0:44:11.47,Default,,0,0,0,,你会做什么特殊的事情吗? Dialogue: 0,0:44:12.71,0:44:16.04,Default,,0,0,0,,教授: 你看的是Scheme的实际实现 Dialogue: 0,0:44:16.06,0:44:17.84,Default,,0,0,0,,其中有一个‘+’ 这是一个运算符 Dialogue: 0,0:44:17.90,0:44:20.19,Default,,0,0,0,,如果你看‘+’的源代码 Dialogue: 0,0:44:20.33,0:44:21.37,Default,,0,0,0,,你会看到一些叫做-- Dialogue: 0,0:44:21.57,0:44:24.14,Default,,0,0,0,,我记不清了--可能叫ADD%、PLUS之类的东西 Dialogue: 0,0:44:24.55,0:44:25.79,Default,,0,0,0,,这里所进行的 Dialogue: 0,0:44:25.79,0:44:27.92,Default,,0,0,0,,就是你说的那种优化 Dialogue: 0,0:44:28.47,0:44:31.87,Default,,0,0,0,,因为 广义的‘+’接受任意数量的参数 Dialogue: 0,0:44:35.02,0:44:36.38,Default,,0,0,0,,所以 广义加法 Dialogue: 0,0:44:36.76,0:44:38.25,Default,,0,0,0,,会说:如果我有一个参数表 Dialogue: 0,0:44:38.28,0:44:40.62,Default,,0,0,0,,我最好将它们用CONS连接到表里 Dialogue: 0,0:44:41.63,0:44:44.14,Default,,0,0,0,,并指出有多少个参数 Dialogue: 0,0:44:44.72,0:44:46.16,Default,,0,0,0,,这样效率非常低下 Dialogue: 0,0:44:46.81,0:44:49.25,Default,,0,0,0,,因为大部分时间你在把两个数相加 Dialogue: 0,0:44:49.25,0:44:51.24,Default,,0,0,0,,你不必把整个参数表连接到一起 Dialogue: 0,0:44:52.04,0:44:53.93,Default,,0,0,0,,所以你想做的是 Dialogue: 0,0:44:55.66,0:44:57.71,Default,,0,0,0,,构建把一堆东西相加的代码 Dialogue: 0,0:44:58.15,0:45:00.17,Default,,0,0,0,,所以它做的大部分事情是一样的 Dialogue: 0,0:45:00.49,0:45:01.95,Default,,0,0,0,,但这里可能有个特殊的入口 Dialogue: 0,0:45:01.98,0:45:03.92,Default,,0,0,0,,如果你知道只有两个参数 Dialogue: 0,0:45:04.56,0:45:05.87,Default,,0,0,0,,你会把它们放到寄存器中 Dialogue: 0,0:45:05.87,0:45:06.97,Default,,0,0,0,,它们不需要参数表 Dialogue: 0,0:45:06.99,0:45:07.98,Default,,0,0,0,,你也不必用CONS连接它们 Dialogue: 0,0:45:08.67,0:45:10.42,Default,,0,0,0,,这就是这些东西工作的原理 Dialogue: 0,0:45:12.30,0:45:13.72,Default,,0,0,0,,好吧 下课吧 Dialogue: 0,0:45:14.10,0:45:42.97,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:45:14.10,0:45:42.97,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec10a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:11.84,0:00:13.84,EN,,0,0,0,,Compilation Dialogue: 0,0:00:19.36,0:00:22.65,EN,,0,0,0,,PROFESSOR: Last time, we took a look at Dialogue: 0,0:00:22.65,0:00:25.67,EN,,0,0,0,,an explicit control evaluator for Lisp Dialogue: 0,0:00:25.67,0:00:28.97,EN,,0,0,0,,and that bridged the gap between all these high-level languages Dialogue: 0,0:00:29.05,0:00:32.14,EN,,0,0,0,,like Lisp and query language all that stuff Dialogue: 0,0:00:32.50,0:00:36.16,EN,,0,0,0,,bridged the gap between that and a conventional register machine. Dialogue: 0,0:00:36.70,0:00:40.14,EN,,0,0,0,,And in fact, you can think of the explicit control evaluator Dialogue: 0,0:00:40.16,0:00:44.38,EN,,0,0,0,,either as, say the code for a Lisp interpreter Dialogue: 0,0:00:44.40,0:00:45.95,EN,,0,0,0,,if you wanted to implement it in the Dialogue: 0,0:00:46.52,0:00:49.50,EN,,0,0,0,,assembly language of some conventional register transfer machine, Dialogue: 0,0:00:49.50,0:00:51.50,EN,,0,0,0,,or, if you like, you can think of it as the microcode Dialogue: 0,0:00:52.08,0:00:54.56,EN,,0,0,0,,of some machine that's going to be specially designed to run Lisp. Dialogue: 0,0:00:55.20,0:00:55.92,EN,,0,0,0,,In either case, Dialogue: 0,0:00:55.92,0:00:58.68,EN,,0,0,0,,Nwhat we're doing is we're taking a machine Dialogue: 0,0:00:58.94,0:01:00.51,EN,,0,0,0,,that speaks some low-level language Dialogue: 0,0:01:01.42,0:01:03.32,EN,,0,0,0,,and we're raising the machine Dialogue: 0,0:01:03.37,0:01:04.88,EN,,0,0,0,,to a high-level language like Lisp Dialogue: 0,0:01:05.36,0:01:06.35,EN,,0,0,0,,by writing an interpreter. Dialogue: 0,0:01:08.22,0:01:09.58,EN,,0,0,0,,So for instance Dialogue: 0,0:01:11.82,0:01:13.77,EN,,0,0,0,,here, conceptually, Dialogue: 0,0:01:18.01,0:01:19.47,EN,,0,0,0,,here conceptually is a Dialogue: 0,0:01:20.54,0:01:23.44,EN,,0,0,0,,a special purpose machine for computing factorials. Dialogue: 0,0:01:24.09,0:01:27.39,EN,,0,0,0,,It takes in five and puts out 120. Dialogue: 0,0:01:28.92,0:01:30.83,EN,,0,0,0,,And what this special purpose machine is Dialogue: 0,0:01:30.97,0:01:32.72,EN,,0,0,0,,actually a Lisp interpreter Dialogue: 0,0:01:33.50,0:01:36.17,EN,,0,0,0,,that's configured itself to run factorials Dialogue: 0,0:01:38.35,0:01:40.99,EN,,0,0,0,,because you feed into it a description of the factorial machine. Dialogue: 0,0:01:42.12,0:01:43.70,EN,,0,0,0,,So that's what an interpreter is. Dialogue: 0,0:01:43.70,0:01:45.66,EN,,0,0,0,,It configures itself to Dialogue: 0,0:01:46.37,0:01:49.24,EN,,0,0,0,,emulate a machine whose description you read in. Dialogue: 0,0:01:50.07,0:01:51.93,EN,,0,0,0,,Now, inside the Lisp interpreter, what's that? Dialogue: 0,0:01:52.04,0:01:55.44,EN,,0,0,0,,Well, that might be your general register language interpreter Dialogue: 0,0:01:56.98,0:02:00.18,EN,,0,0,0,,that configures itself to behave like a Lisp interpreter Dialogue: 0,0:02:00.18,0:02:02.03,EN,,0,0,0,,because you put in a whole bunch of instructions Dialogue: 0,0:02:02.12,0:02:03.04,EN,,0,0,0,,in register language. Dialogue: 0,0:02:03.37,0:02:05.16,EN,,0,0,0,,This is the explicit control evaluator. Dialogue: 0,0:02:07.05,0:02:08.70,EN,,0,0,0,,And then it also has some sort of library Dialogue: 0,0:02:08.73,0:02:11.08,EN,,0,0,0,,a library of primitive operators and Lisp operations Dialogue: 0,0:02:11.12,0:02:12.28,EN,,0,0,0,,all sorts of things like that. Dialogue: 0,0:02:12.75,0:02:16.89,EN,,0,0,0,,That's the general strategy of interpretation. Dialogue: 0,0:02:17.32,0:02:18.51,EN,,0,0,0,,And the point is, what we're doing Dialogue: 0,0:02:18.60,0:02:20.14,EN,,0,0,0,,is we're writing an interpreter Dialogue: 0,0:02:21.62,0:02:23.40,EN,,0,0,0,,to raise the machine Dialogue: 0,0:02:23.42,0:02:25.24,EN,,0,0,0,,to the level of the programs that we want to write. Dialogue: 0,0:02:25.24,0:02:26.72,EN,,0,0,0,,Well, there's another strategy Dialogue: 0,0:02:27.42,0:02:28.89,EN,,0,0,0,,a different one, which is compilation. Dialogue: 0,0:02:29.04,0:02:30.43,EN,,0,0,0,,Compilation's a little bit different. Dialogue: 0,0:02:31.04,0:02:31.50,EN,,0,0,0,,Here-- Dialogue: 0,0:02:33.37,0:02:34.75,EN,,0,0,0,,here we might have produced Dialogue: 0,0:02:35.67,0:02:38.52,EN,,0,0,0,,a special purpose machine for, Dialogue: 0,0:02:38.62,0:02:39.98,EN,,0,0,0,,for computing factorials Dialogue: 0,0:02:43.62,0:02:46.26,EN,,0,0,0,,starting with some sort of machine that speaks register language Dialogue: 0,0:02:46.26,0:02:47.72,EN,,0,0,0,,except we're going to do a different strategy. Dialogue: 0,0:02:47.72,0:02:50.38,EN,,0,0,0,,We take our factorial program. Dialogue: 0,0:02:51.55,0:02:53.92,EN,,0,0,0,,We use that as the source code into a compiler. Dialogue: 0,0:02:53.92,0:02:55.15,EN,,0,0,0,,What the compiler will do Dialogue: 0,0:02:55.15,0:02:57.62,EN,,0,0,0,,is translate that factorial program Dialogue: 0,0:02:57.62,0:02:59.07,EN,,0,0,0,,into some register machine language. Dialogue: 0,0:03:00.25,0:03:03.40,EN,,0,0,0,,And this will now be not the explicit control evaluator for Lisp Dialogue: 0,0:03:03.40,0:03:06.17,EN,,0,0,0,,this will be some register language for computing factorials. Dialogue: 0,0:03:06.49,0:03:08.36,EN,,0,0,0,,So this is the translation of that. Dialogue: 0,0:03:10.54,0:03:12.41,EN,,0,0,0,,That will go into some sort of loader Dialogue: 0,0:03:13.35,0:03:15.21,EN,,0,0,0,,which will combine this code Dialogue: 0,0:03:15.31,0:03:16.84,EN,,0,0,0,,with code selected from the library Dialogue: 0,0:03:16.86,0:03:18.65,EN,,0,0,0,,to do things like primitive multiplication. Dialogue: 0,0:03:19.82,0:03:21.69,EN,,0,0,0,,And then we'll produce a load module Dialogue: 0,0:03:22.22,0:03:25.06,EN,,0,0,0,,which configures the register language machine Dialogue: 0,0:03:25.06,0:03:27.24,EN,,0,0,0,,to be a special purpose factorial machine. Dialogue: 0,0:03:28.12,0:03:30.22,EN,,0,0,0,,So that's a, that's a different strategy. Dialogue: 0,0:03:30.22,0:03:31.22,EN,,0,0,0,,In interpretation, Dialogue: 0,0:03:31.22,0:03:32.01,EN,,0,0,0,,we're raising Dialogue: 0,0:03:32.91,0:03:35.23,EN,,0,0,0,,the machine to the level of our language, like Lisp. Dialogue: 0,0:03:35.32,0:03:36.34,EN,,0,0,0,,In compilation Dialogue: 0,0:03:36.34,0:03:38.43,EN,,0,0,0,,we're taking our program and lowering Dialogue: 0,0:03:38.48,0:03:40.56,EN,,0,0,0,,it to the language that's spoken by the machine. Dialogue: 0,0:03:41.96,0:03:43.84,EN,,0,0,0,,Well, how do these two strategies compare? Dialogue: 0,0:03:44.30,0:03:49.42,EN,,0,0,0,,The compiler can produce code that will execute more efficiently. Dialogue: 0,0:03:52.05,0:03:53.90,EN,,0,0,0,,The essential reason for that Dialogue: 0,0:03:54.17,0:03:58.89,EN,,0,0,0,,is that if you think about the register operations that are running Dialogue: 0,0:04:01.92,0:04:04.49,EN,,0,0,0,,the interpreter has to produce register operations Dialogue: 0,0:04:04.97,0:04:06.75,EN,,0,0,0,,which, in principle, are going to be general enough Dialogue: 0,0:04:07.32,0:04:08.94,EN,,0,0,0,,to execute any Lisp procedure. Dialogue: 0,0:04:10.22,0:04:12.25,EN,,0,0,0,,Whereas the compiler only has to worry about Dialogue: 0,0:04:12.27,0:04:14.92,EN,,0,0,0,,producing a special bunch of register operations for Dialogue: 0,0:04:15.52,0:04:18.22,EN,,0,0,0,,for doing the particular Lisp procedure that you've compiled. Dialogue: 0,0:04:20.17,0:04:21.20,EN,,0,0,0,,Or another way to say that Dialogue: 0,0:04:21.20,0:04:25.31,EN,,0,0,0,,is that the interpreter is a general purpose simulator Dialogue: 0,0:04:25.92,0:04:27.58,EN,,0,0,0,,that when you read in a Lisp procedure Dialogue: 0,0:04:27.58,0:04:31.32,EN,,0,0,0,,then those can simulate the program described by that, by that procedure. Dialogue: 0,0:04:31.32,0:04:33.87,EN,,0,0,0,,So the interpreter is worrying about making a general purpose simulator Dialogue: 0,0:04:34.62,0:04:35.96,EN,,0,0,0,,whereas the compiler, in effect, Dialogue: 0,0:04:36.00,0:04:37.68,EN,,0,0,0,,is configuring the thing to be the machine Dialogue: 0,0:04:37.71,0:04:39.34,EN,,0,0,0,,that the interpreter would have been simulating. Dialogue: 0,0:04:40.02,0:04:41.34,EN,,0,0,0,,So the compiler can be faster. Dialogue: 0,0:04:52.55,0:04:53.64,EN,,0,0,0,,OK, On the other hand Dialogue: 0,0:04:55.97,0:04:58.28,EN,,0,0,0,,the interpreter is a nicer environment for debugging. Dialogue: 0,0:04:59.43,0:05:01.25,EN,,0,0,0,,And the reason for that is that we've got the Dialogue: 0,0:05:01.57,0:05:03.02,EN,,0,0,0,,the source code actually there. Dialogue: 0,0:05:03.02,0:05:04.81,EN,,0,0,0,,We're interpreting it That's what we're working with. Dialogue: 0,0:05:05.87,0:05:07.69,EN,,0,0,0,,And we also have the library around. Dialogue: 0,0:05:07.90,0:05:10.89,EN,,0,0,0,,See, the interpreter--the library sitting there is part of the interpreter. Dialogue: 0,0:05:11.30,0:05:13.16,EN,,0,0,0,,The compiler only pulls out from the library Dialogue: 0,0:05:13.20,0:05:14.56,EN,,0,0,0,,what it needs to run the program. Dialogue: 0,0:05:14.87,0:05:17.00,EN,,0,0,0,,So if you're in the middle of debugging Dialogue: 0,0:05:18.00,0:05:20.72,EN,,0,0,0,,and you might like to write a little extra program Dialogue: 0,0:05:20.80,0:05:22.57,EN,,0,0,0,,to examine some run time data structure Dialogue: 0,0:05:23.05,0:05:24.25,EN,,0,0,0,,or to produce some computation Dialogue: 0,0:05:24.30,0:05:25.92,EN,,0,0,0,,that you didn't think of when you wrote the program Dialogue: 0,0:05:25.95,0:05:27.53,EN,,0,0,0,,the interpreter can do that perfectly well Dialogue: 0,0:05:28.05,0:05:29.21,EN,,0,0,0,,whereas the compiler can't. Dialogue: 0,0:05:29.62,0:05:31.90,EN,,0,0,0,,So there are sort of dual, dual advantages. Dialogue: 0,0:05:31.90,0:05:34.48,EN,,0,0,0,,The compiler will produce code that executes faster. Dialogue: 0,0:05:34.85,0:05:37.02,EN,,0,0,0,,The interpreter is a better environment for debugging. Dialogue: 0,0:05:38.95,0:05:41.40,EN,,0,0,0,,And most Lisp systems end up having both Dialogue: 0,0:05:42.92,0:05:45.23,EN,,0,0,0,,end up being configured so you have an interpreter Dialogue: 0,0:05:45.24,0:05:47.08,EN,,0,0,0,,that you use when you're developing your code. Dialogue: 0,0:05:47.08,0:05:48.62,EN,,0,0,0,,Then you can speed it up by compiling. Dialogue: 0,0:05:49.02,0:05:50.03,EN,,0,0,0,,And very often, Dialogue: 0,0:05:50.04,0:05:51.68,EN,,0,0,0,,you can arrange that compiled code Dialogue: 0,0:05:51.69,0:05:53.56,EN,,0,0,0,,and interpreted code can call each other. Dialogue: 0,0:05:54.60,0:05:56.33,EN,,0,0,0,,We'll see how to do that, That's not hard. Dialogue: 0,0:05:59.27,0:05:59.85,EN,,0,0,0,,OK Dialogue: 0,0:06:00.97,0:06:02.09,EN,,0,0,0,,In fact, the way we'll-- Dialogue: 0,0:06:04.30,0:06:05.75,EN,,0,0,0,,in the compiler we're going to make Dialogue: 0,0:06:05.75,0:06:07.58,EN,,0,0,0,,the way we'll arrange for compiled coding Dialogue: 0,0:06:07.58,0:06:09.45,EN,,0,0,0,,and interpreted code to call to call each other Dialogue: 0,0:06:09.90,0:06:12.06,EN,,0,0,0,,is that we'll have the compiler use exactly Dialogue: 0,0:06:12.11,0:06:14.40,EN,,0,0,0,,the same register conventions as the interpreter. Dialogue: 0,0:06:18.42,0:06:21.72,EN,,0,0,0,,Well, the idea of a compiler Dialogue: 0,0:06:21.76,0:06:25.74,EN,,0,0,0,,is very much like the idea of an interpreter or evaluator. Dialogue: 0,0:06:25.87,0:06:26.46,EN,,0,0,0,,It's the same thing. Dialogue: 0,0:06:27.05,0:06:29.39,EN,,0,0,0,,See, the evaluator walks over the code Dialogue: 0,0:06:29.82,0:06:32.35,EN,,0,0,0,,and performs some register operations. Dialogue: 0,0:06:33.65,0:06:34.97,EN,,0,0,0,,That's what we did yesterday. Dialogue: 0,0:06:37.10,0:06:40.27,EN,,0,0,0,,Well, the compiler essentially would like to walk over the code Dialogue: 0,0:06:40.52,0:06:43.00,EN,,0,0,0,,and produce the register operations Dialogue: 0,0:06:43.04,0:06:44.67,EN,,0,0,0,,that the evaluator would have done Dialogue: 0,0:06:45.23,0:06:46.64,EN,,0,0,0,,were it evaluating the thing. Dialogue: 0,0:06:48.60,0:06:49.95,EN,,0,0,0,,And that gives us some model Dialogue: 0,0:06:50.60,0:06:53.77,EN,,0,0,0,,for how to implement a zeroth-order compiler Dialogue: 0,0:06:55.30,0:06:58.32,EN,,0,0,0,,a very bad compiler but essentially a compiler. Dialogue: 0,0:06:58.32,0:06:59.32,EN,,0,0,0,,A model for doing that Dialogue: 0,0:06:59.36,0:07:00.59,EN,,0,0,0,,is you just take the evaluator, Dialogue: 0,0:07:00.68,0:07:01.88,EN,,0,0,0,,you run it over the code Dialogue: 0,0:07:02.80,0:07:06.06,EN,,0,0,0,,but instead of executing the actual operations Dialogue: 0,0:07:06.06,0:07:07.15,EN,,0,0,0,,you just save them away. Dialogue: 0,0:07:07.55,0:07:08.82,EN,,0,0,0,,And that's your compiled code. Dialogue: 0,0:07:08.82,0:07:10.24,EN,,0,0,0,,So let me give you an example of that. Dialogue: 0,0:07:12.70,0:07:14.14,EN,,0,0,0,,Suppose we're going to compile-- Dialogue: 0,0:07:15.10,0:07:17.90,EN,,0,0,0,,Suppose we want to compile the expression f of x. Dialogue: 0,0:07:25.07,0:07:25.96,EN,,0,0,0,,So let's assume that Dialogue: 0,0:07:25.96,0:07:28.06,EN,,0,0,0,,we've got f of x in the exp register Dialogue: 0,0:07:28.06,0:07:29.55,EN,,0,0,0,,and something in the environment register. Dialogue: 0,0:07:30.10,0:07:32.20,EN,,0,0,0,,And now imagine starting up the evaluator. Dialogue: 0,0:07:34.60,0:07:35.71,EN,,0,0,0,,Well, it looks at the expression Dialogue: 0,0:07:35.71,0:07:37.36,EN,,0,0,0,,and it sees that it's an application. Dialogue: 0,0:07:37.92,0:07:41.90,EN,,0,0,0,,And it branches to a place in the Dialogue: 0,0:07:42.52,0:07:45.15,EN,,0,0,0,,in the evaluator code we saw called ev-application. Dialogue: 0,0:07:47.12,0:07:48.12,EN,,0,0,0,,And then it begins. Dialogue: 0,0:07:48.16,0:07:50.08,EN,,0,0,0,,It stores away the operands and unev Dialogue: 0,0:07:50.08,0:07:52.44,EN,,0,0,0,,and then it's going to put the operator in exp, Dialogue: 0,0:07:52.48,0:07:54.27,EN,,0,0,0,,and it's going to go recursively evaluate it. Dialogue: 0,0:07:54.47,0:07:56.08,EN,,0,0,0,,That's the process that we walk through. Dialogue: 0,0:07:56.67,0:07:57.84,EN,,0,0,0,,And if you start looking at the code, Dialogue: 0,0:07:57.87,0:07:59.74,EN,,0,0,0,,you start seeing some register operations. Dialogue: 0,0:08:00.20,0:08:02.30,EN,,0,0,0,,You see assign to unev the operands Dialogue: 0,0:08:02.30,0:08:03.95,EN,,0,0,0,,assign to exp the operator, Dialogue: 0,0:08:04.09,0:08:06.20,EN,,0,0,0,,save the environment, generate that, and so on. Dialogue: 0,0:08:10.22,0:08:11.93,EN,,0,0,0,,Well, if we look on the overhead here Dialogue: 0,0:08:15.75,0:08:19.58,EN,,0,0,0,,we can see those operations starting to be produced. Dialogue: 0,0:08:20.82,0:08:22.52,EN,,0,0,0,,Here's sort of the first real operation Dialogue: 0,0:08:22.72,0:08:24.80,EN,,0,0,0,,that the evaluator would have done. Dialogue: 0,0:08:25.00,0:08:27.20,EN,,0,0,0,,It pulls the operands out of the exp register Dialogue: 0,0:08:27.47,0:08:28.62,EN,,0,0,0,,and assigns it to unev. Dialogue: 0,0:08:30.03,0:08:32.27,EN,,0,0,0,,And then it assigns something to the expression register, Dialogue: 0,0:08:32.30,0:08:33.46,EN,,0,0,0,,and it saves continue Dialogue: 0,0:08:33.46,0:08:34.62,EN,,0,0,0,,and it saves env. Dialogue: 0,0:08:34.62,0:08:38.65,EN,,0,0,0,,And all I'm doing here is writing down the register assignments Dialogue: 0,0:08:39.57,0:08:42.32,EN,,0,0,0,,that the evaluator would have done in executing that code. Dialogue: 0,0:08:42.77,0:08:43.79,EN,,0,0,0,,And can zoom out a little bit. Dialogue: 0,0:08:44.30,0:08:47.13,EN,,0,0,0,,Altogether, there are about 19 operations there. Dialogue: 0,0:08:49.40,0:08:51.64,EN,,0,0,0,,And this is the--this will be the piece of code Dialogue: 0,0:08:52.05,0:08:53.90,EN,,0,0,0,,up until the point where Dialogue: 0,0:08:54.75,0:08:57.10,EN,,0,0,0,,the evaluator branches off to apply-dispatch. Dialogue: 0,0:08:57.86,0:08:59.16,EN,,0,0,0,,And in fact, in this compiler Dialogue: 0,0:08:59.20,0:09:01.18,EN,,0,0,0,,we're not going to worry about apply-dispatch at all. Dialogue: 0,0:09:01.30,0:09:02.11,EN,,0,0,0,,We're going to have everything Dialogue: 0,0:09:02.35,0:09:05.04,EN,,0,0,0,,we're going to have both interpreted code and compiled code. Dialogue: 0,0:09:06.07,0:09:07.61,EN,,0,0,0,,Always evaluate procedures, Dialogue: 0,0:09:07.61,0:09:09.85,EN,,0,0,0,,always apply procedures by going to apply-dispatch. Dialogue: 0,0:09:10.27,0:09:12.32,EN,,0,0,0,,That will easily allow interpreted code and Dialogue: 0,0:09:12.36,0:09:13.71,EN,,0,0,0,,compiled code to call each other. Dialogue: 0,0:09:18.27,0:09:19.87,EN,,0,0,0,,Well, in principle, that's all we need to do. Dialogue: 0,0:09:21.05,0:09:22.66,EN,,0,0,0,,You just run the evaluator. Dialogue: 0,0:09:22.66,0:09:24.50,EN,,0,0,0,,So the compiler's a lot like the evaluator. Dialogue: 0,0:09:24.50,0:09:26.47,EN,,0,0,0,,You run it, except it stashes away these operations Dialogue: 0,0:09:26.47,0:09:28.40,EN,,0,0,0,,instead of actually executing them. Dialogue: 0,0:09:29.35,0:09:31.39,EN,,0,0,0,,Well, that's not, that's not quite true. there's Dialogue: 0,0:09:32.91,0:09:34.99,EN,,0,0,0,,There's only one little lie in that. Dialogue: 0,0:09:36.24,0:09:39.29,EN,,0,0,0,,What you have to worry about is if you have a, a predicate. Dialogue: 0,0:09:40.12,0:09:42.16,EN,,0,0,0,,If you have some kind of test you want to do Dialogue: 0,0:09:43.45,0:09:46.03,EN,,0,0,0,,obviously, at the point when you're compiling it Dialogue: 0,0:09:46.52,0:09:47.98,EN,,0,0,0,,you don't know which branch of these-- Dialogue: 0,0:09:48.32,0:09:50.14,EN,,0,0,0,,of a conditional like this you're going to do. Dialogue: 0,0:09:51.13,0:09:53.92,EN,,0,0,0,,So you can't say which one the evaluator would have done. Dialogue: 0,0:09:54.90,0:09:57.12,EN,,0,0,0,,So all you do there is very simple. Dialogue: 0,0:09:57.12,0:09:58.49,EN,,0,0,0,,You compile both branches. Dialogue: 0,0:09:59.32,0:10:01.29,EN,,0,0,0,,So you compile a structure that looks like this. Dialogue: 0,0:10:02.00,0:10:03.98,EN,,0,0,0,,That'll compile into something that says, Dialogue: 0,0:10:05.31,0:10:09.15,EN,,0,0,0,,the code, the code for P. Dialogue: 0,0:10:10.71,0:10:16.51,EN,,0,0,0,,And it puts its results in, say, the val register. Dialogue: 0,0:10:18.17,0:10:20.64,EN,,0,0,0,,So you walk the interpreter over the predicate Dialogue: 0,0:10:21.35,0:10:24.19,EN,,0,0,0,,and make sure that the result would go into the val register. Dialogue: 0,0:10:24.70,0:10:27.22,EN,,0,0,0,,And then you compile an instruction that says Dialogue: 0,0:10:27.22,0:10:33.79,EN,,0,0,0,,branch if, if val is true Dialogue: 0,0:10:37.17,0:10:38.75,EN,,0,0,0,,to a place we'll call label one. Dialogue: 0,0:10:44.97,0:10:47.52,EN,,0,0,0,,Then we, we will put the code for B Dialogue: 0,0:10:49.42,0:10:52.32,EN,,0,0,0,,to walk the interpreter--walk the interpreter over B. Dialogue: 0,0:10:53.62,0:10:57.21,EN,,0,0,0,,And then go to put in an instruction that says, Dialogue: 0,0:10:57.23,0:10:58.75,EN,,0,0,0,,go to the next thing, whatever Dialogue: 0,0:11:02.20,0:11:04.56,EN,,0,0,0,,whatever was supposed to happen after this thing was done. Dialogue: 0,0:11:04.95,0:11:06.09,EN,,0,0,0,,You put in that instruction. Dialogue: 0,0:11:06.88,0:11:08.62,EN,,0,0,0,,And here you put label one. Dialogue: 0,0:11:12.12,0:11:13.80,EN,,0,0,0,,And here you put the code for A. Dialogue: 0,0:11:19.47,0:11:25.85,EN,,0,0,0,,And you put go to next thing. Dialogue: 0,0:11:31.42,0:11:32.88,EN,,0,0,0,,So that's how you treat a conditional. Dialogue: 0,0:11:32.98,0:11:34.65,EN,,0,0,0,,You generate a little block like that. Dialogue: 0,0:11:35.75,0:11:38.12,EN,,0,0,0,,And other than that Dialogue: 0,0:11:38.95,0:11:41.55,EN,,0,0,0,,this zeroth-order compiler is the same as the evaluator. Dialogue: 0,0:11:42.55,0:11:45.12,EN,,0,0,0,,It's just stashing away the instructions instead of executing them. Dialogue: 0,0:11:46.55,0:11:47.60,EN,,0,0,0,,That seems pretty simple, Dialogue: 0,0:11:47.64,0:11:49.08,EN,,0,0,0,,but we've gained something by that. Dialogue: 0,0:11:50.12,0:11:52.62,EN,,0,0,0,,See, already that's going to be more efficient than the evaluator. Dialogue: 0,0:11:53.52,0:11:56.14,EN,,0,0,0,,Because, if you watch the evaluator run Dialogue: 0,0:11:56.35,0:12:01.05,EN,,0,0,0,,it's not only generating the register operations we wrote down Dialogue: 0,0:12:01.27,0:12:03.50,EN,,0,0,0,,it's also doing things to decide which ones to generate. Dialogue: 0,0:12:04.70,0:12:07.23,EN,,0,0,0,,So the very first thing it does, say here Dialogue: 0,0:12:07.92,0:12:09.77,EN,,0,0,0,,here for instance, is go do some tests Dialogue: 0,0:12:09.77,0:12:11.56,EN,,0,0,0,,and decide that this is an application Dialogue: 0,0:12:13.57,0:12:15.05,EN,,0,0,0,,and then branch off to the place that, Dialogue: 0,0:12:15.39,0:12:16.62,EN,,0,0,0,,that handles applications. Dialogue: 0,0:12:16.62,0:12:18.44,EN,,0,0,0,,In other words, what the evaluator's doing Dialogue: 0,0:12:18.62,0:12:22.76,EN,,0,0,0,,is simultaneously analyzing the code to see what to do Dialogue: 0,0:12:23.47,0:12:24.99,EN,,0,0,0,,and running these operations. Dialogue: 0,0:12:25.55,0:12:28.28,EN,,0,0,0,,And when you-- if you run the evaluator a million times Dialogue: 0,0:12:28.28,0:12:30.30,EN,,0,0,0,,that analysis phase happens a million times Dialogue: 0,0:12:30.85,0:12:32.58,EN,,0,0,0,,whereas in the compiler, it's happened once Dialogue: 0,0:12:32.58,0:12:34.81,EN,,0,0,0,,and then you just have the register operations themselves. Dialogue: 0,0:12:39.20,0:12:41.68,EN,,0,0,0,,Ok, that's a, a zeroth-order compiler Dialogue: 0,0:12:41.80,0:12:44.04,EN,,0,0,0,,but it is a wretched, wretched compiler. Dialogue: 0,0:12:44.45,0:12:45.28,EN,,0,0,0,,It's really dumb. Dialogue: 0,0:12:46.90,0:12:48.41,EN,,0,0,0,,Let's--let's go back and, Dialogue: 0,0:12:49.88,0:12:50.97,EN,,0,0,0,,and look at this overhead. Dialogue: 0,0:12:52.02,0:12:55.29,EN,,0,0,0,,So look at look at some of the operations this thing is doing. Dialogue: 0,0:12:55.85,0:12:56.88,EN,,0,0,0,,We're supposedly Dialogue: 0,0:12:59.72,0:13:02.28,EN,,0,0,0,,looking at the operations in interpreting f of x. Dialogue: 0,0:13:03.52,0:13:04.84,EN,,0,0,0,,Now, look here what it's doing. Dialogue: 0,0:13:05.17,0:13:06.11,EN,,0,0,0,,For example, here Dialogue: 0,0:13:07.15,0:13:11.98,EN,,0,0,0,,it assigns to exp the operator in fetch of exp. Dialogue: 0,0:13:13.75,0:13:15.87,EN,,0,0,0,,But see, there's no reason to do that, because this is-- Dialogue: 0,0:13:16.22,0:13:17.47,EN,,0,0,0,,the compiler knows Dialogue: 0,0:13:17.66,0:13:21.84,EN,,0,0,0,,that the operator, fetch of exp, is f right here. Dialogue: 0,0:13:23.35,0:13:25.56,EN,,0,0,0,,So there's no reason why this instruction should say that. Dialogue: 0,0:13:25.70,0:13:28.88,EN,,0,0,0,,It should say, we'll assign to exp, f. Dialogue: 0,0:13:29.45,0:13:31.08,EN,,0,0,0,,Or in fact, you don't need exp at all. Dialogue: 0,0:13:31.87,0:13:33.56,EN,,0,0,0,,There's no reason it should have exp at all. Dialogue: 0,0:13:33.56,0:13:35.16,EN,,0,0,0,,What, what did exp get used for? Dialogue: 0,0:13:35.18,0:13:36.33,EN,,0,0,0,,Well, if we come down here Dialogue: 0,0:13:40.77,0:13:42.20,EN,,0,0,0,,we're going to assign to val Dialogue: 0,0:13:43.05,0:13:47.34,EN,,0,0,0,,look up the stuff in exp in the environment. Dialogue: 0,0:13:48.68,0:13:49.53,EN,,0,0,0,,So what we really should do Dialogue: 0,0:13:49.55,0:13:51.54,EN,,0,0,0,,get rid of the exp register altogether Dialogue: 0,0:13:51.54,0:13:53.32,EN,,0,0,0,,and just change this instruction to say, Dialogue: 0,0:13:53.34,0:13:54.16,EN,,0,0,0,,assign to val Dialogue: 0,0:13:54.45,0:13:56.06,EN,,0,0,0,,look up the variable value Dialogue: 0,0:13:56.36,0:13:58.40,EN,,0,0,0,,of the symbol f in the environment. Dialogue: 0,0:14:01.09,0:14:01.77,EN,,0,0,0,,Similarly Dialogue: 0,0:14:02.57,0:14:04.27,EN,,0,0,0,,back up here, we don't need unev at all Dialogue: 0,0:14:04.72,0:14:05.79,EN,,0,0,0,,because we know Dialogue: 0,0:14:06.22,0:14:09.16,EN,,0,0,0,,what the operands of fetch of exp are for this piece of code. Dialogue: 0,0:14:09.16,0:14:10.62,EN,,0,0,0,,It's the, it's the list x. Dialogue: 0,0:14:13.25,0:14:14.06,EN,,0,0,0,,So in some sense Dialogue: 0,0:14:16.17,0:14:19.39,EN,,0,0,0,,you don't want unev and exp at all. Dialogue: 0,0:14:19.67,0:14:21.05,EN,,0,0,0,,See, what they really are in some sense, Dialogue: 0,0:14:21.08,0:14:25.30,EN,,0,0,0,,those aren't registers of the actual machine that's supposed to run. Dialogue: 0,0:14:25.30,0:14:26.40,EN,,0,0,0,,Those are registers Dialogue: 0,0:14:26.60,0:14:29.50,EN,,0,0,0,,that have to do with arranging the thing that can simulate that machine. Dialogue: 0,0:14:30.72,0:14:33.77,EN,,0,0,0,,So they're always going to hold expressions Dialogue: 0,0:14:34.00,0:14:36.04,EN,,0,0,0,,which from the compiler's point of view, Dialogue: 0,0:14:36.06,0:14:36.81,EN,,0,0,0,,are just constants, Dialogue: 0,0:14:36.95,0:14:38.48,EN,,0,0,0,,so can be put right into the code. Dialogue: 0,0:14:39.47,0:14:41.34,EN,,0,0,0,,So you can forget about all the operations Dialogue: 0,0:14:41.36,0:14:42.54,EN,,0,0,0,,worrying about exp and unev Dialogue: 0,0:14:42.57,0:14:43.77,EN,,0,0,0,,and just use those constants. Dialogue: 0,0:14:44.02,0:14:48.00,EN,,0,0,0,,Similarly, again, if we go, go back and look here Dialogue: 0,0:14:48.00,0:14:51.32,EN,,0,0,0,,there are things like assign to continue eval-args. Dialogue: 0,0:14:53.75,0:14:55.39,EN,,0,0,0,,Now, that has nothing to do with anything. Dialogue: 0,0:14:55.62,0:14:57.76,EN,,0,0,0,,That was just the evaluator Dialogue: 0,0:14:58.08,0:15:00.17,EN,,0,0,0,,keeping track of where it should go next Dialogue: 0,0:15:02.70,0:15:05.96,EN,,0,0,0,,to evaluate the arguments in some, in some application. Dialogue: 0,0:15:06.82,0:15:08.65,EN,,0,0,0,,But of course, that's irrelevant to the compiler, Dialogue: 0,0:15:08.65,0:15:13.88,EN,,0,0,0,,because you-- the analysis phase will have already done that. Dialogue: 0,0:15:15.05,0:15:16.83,EN,,0,0,0,,So this is completely irrelevant. Dialogue: 0,0:15:17.70,0:15:19.32,EN,,0,0,0,,So a lot of these, these assignments Dialogue: 0,0:15:19.32,0:15:21.30,EN,,0,0,0,,to continue have not to do Dialogue: 0,0:15:21.30,0:15:24.62,EN,,0,0,0,,where the running machine is supposed to continue Dialogue: 0,0:15:24.64,0:15:25.77,EN,,0,0,0,,in keeping track of its state. Dialogue: 0,0:15:26.07,0:15:28.72,EN,,0,0,0,,It has to, to do with where the evaluator analysis should continue Dialogue: 0,0:15:28.72,0:15:30.03,EN,,0,0,0,,and those are completely irrelevant. Dialogue: 0,0:15:30.06,0:15:31.23,EN,,0,0,0,,So we can get rid of them. Dialogue: 0,0:15:43.90,0:15:45.98,EN,,0,0,0,,Ok, well, if we, if we simply do that, Dialogue: 0,0:15:46.16,0:15:47.75,EN,,0,0,0,,make those kinds of optimizations Dialogue: 0,0:15:47.75,0:15:51.64,EN,,0,0,0,,get rid, get rid of worrying about exp and unev Dialogue: 0,0:15:51.75,0:15:56.22,EN,,0,0,0,,and get rid of these irrelevant register assignments to continue Dialogue: 0,0:15:57.25,0:15:59.96,EN,,0,0,0,,then we can take this literal code Dialogue: 0,0:16:01.48,0:16:06.20,EN,,0,0,0,,these sort of 19 instructions that the evaluator would have done Dialogue: 0,0:16:06.91,0:16:08.12,EN,,0,0,0,,and then replace them. Dialogue: 0,0:16:08.36,0:16:10.33,EN,,0,0,0,,Let's look at the, at the slide. Dialogue: 0,0:16:12.27,0:16:15.34,EN,,0,0,0,,Replace them by--we get rid of about half of them. Dialogue: 0,0:16:18.28,0:16:20.75,EN,,0,0,0,,And again, this is just sort of filtering Dialogue: 0,0:16:21.07,0:16:24.46,EN,,0,0,0,,what the evaluator would have done by getting rid of the irrelevant stuff. Dialogue: 0,0:16:25.17,0:16:26.22,EN,,0,0,0,,And you see, for instance Dialogue: 0,0:16:27.47,0:16:29.66,EN,,0,0,0,,here the--where the evaluator said, Dialogue: 0,0:16:29.68,0:16:32.43,EN,,0,0,0,,assign val, look up variable value, fetch of exp Dialogue: 0,0:16:32.46,0:16:34.22,EN,,0,0,0,,here we have put in the constant f. Dialogue: 0,0:16:35.44,0:16:37.02,EN,,0,0,0,,Here we've put in the constant x. Dialogue: 0,0:16:40.02,0:16:42.41,EN,,0,0,0,,So there's a, there's a little better compiler. Dialogue: 0,0:16:43.79,0:16:46.76,EN,,0,0,0,,It's still pretty dumb. Dialogue: 0,0:16:47.95,0:16:49.58,EN,,0,0,0,,It's still doing a lot of dumb things. Dialogue: 0,0:16:50.45,0:16:52.52,EN,,0,0,0,,Again, if we go look at the slide again Dialogue: 0,0:16:52.88,0:16:53.93,EN,,0,0,0,,look at the very beginning here Dialogue: 0,0:16:56.34,0:16:58.17,EN,,0,0,0,,we see a save the environment Dialogue: 0,0:16:59.35,0:17:01.72,EN,,0,0,0,,assign something to the val register Dialogue: 0,0:17:01.80,0:17:03.35,EN,,0,0,0,,and restore the environment. Dialogue: 0,0:17:03.35,0:17:04.41,EN,,0,0,0,,Where'd that come from? Dialogue: 0,0:17:04.91,0:17:07.10,EN,,0,0,0,,That came from the evaluator back here saying Dialogue: 0,0:17:07.15,0:17:10.28,EN,,0,0,0,,oh, I'm in the middle of evaluating an application. Dialogue: 0,0:17:11.10,0:17:14.68,EN,,0,0,0,,So I'm going to recursively call eval dispatch. Dialogue: 0,0:17:15.87,0:17:17.98,EN,,0,0,0,,So I'd better save the thing I'm going to need later, Dialogue: 0,0:17:17.98,0:17:19.08,EN,,0,0,0,,which is the environment. Dialogue: 0,0:17:19.77,0:17:22.86,EN,,0,0,0,,This was the result of recursively calling eval dispatch. Dialogue: 0,0:17:23.47,0:17:25.77,EN,,0,0,0,,It was evaluating the symbol f in that case. Dialogue: 0,0:17:26.50,0:17:28.27,EN,,0,0,0,,Then it came back from eval dispatch, Dialogue: 0,0:17:28.28,0:17:29.66,EN,,0,0,0,,restored the environment. Dialogue: 0,0:17:31.25,0:17:32.28,EN,,0,0,0,,But in fact, Dialogue: 0,0:17:32.59,0:17:35.88,EN,,0,0,0,,the actual thing it ended up doing in the evaluation Dialogue: 0,0:17:35.92,0:17:37.71,EN,,0,0,0,,is not going to hurt the environment at all. Dialogue: 0,0:17:38.67,0:17:40.80,EN,,0,0,0,,So there's no reason to be saving the environment Dialogue: 0,0:17:40.84,0:17:42.22,EN,,0,0,0,,and restoring the environment here. Dialogue: 0,0:17:45.67,0:17:46.62,EN,,0,0,0,,Similarly Dialogue: 0,0:17:49.79,0:17:51.39,EN,,0,0,0,,here I'm saving the argument list. Dialogue: 0,0:17:53.07,0:17:55.80,EN,,0,0,0,,That's a piece of the argument evaluation loop, Dialogue: 0,0:17:55.82,0:17:56.86,EN,,0,0,0,,saving the argument list Dialogue: 0,0:17:57.20,0:17:58.03,EN,,0,0,0,,and here you restore it. Dialogue: 0,0:17:58.08,0:18:00.51,EN,,0,0,0,,But the actual thing that you ended up doing Dialogue: 0,0:18:00.80,0:18:02.28,EN,,0,0,0,,didn't trash the argument list. Dialogue: 0,0:18:02.84,0:18:04.17,EN,,0,0,0,,So there was no reason to save it. Dialogue: 0,0:18:08.65,0:18:12.88,EN,,0,0,0,,So another way to say, another way to say that Dialogue: 0,0:18:13.77,0:18:14.80,EN,,0,0,0,,is that the, Dialogue: 0,0:18:16.43,0:18:19.13,EN,,0,0,0,,the evaluator has to be maximally pessimistic Dialogue: 0,0:18:19.87,0:18:21.07,EN,,0,0,0,,because as far from its point of view Dialogue: 0,0:18:21.08,0:18:23.06,EN,,0,0,0,,it's just going off to evaluate something. Dialogue: 0,0:18:23.24,0:18:24.97,EN,,0,0,0,,So it better save what it's going to need later. Dialogue: 0,0:18:26.12,0:18:27.79,EN,,0,0,0,,But once you've done the analysis, Dialogue: 0,0:18:27.82,0:18:29.68,EN,,0,0,0,,the compiler is in a position to say Dialogue: 0,0:18:29.72,0:18:31.47,EN,,0,0,0,,well, what actually did I need to save? Dialogue: 0,0:18:32.12,0:18:33.31,EN,,0,0,0,,And doesn't need to do any-- Dialogue: 0,0:18:33.42,0:18:37.30,EN,,0,0,0,,it doesn't need to be as careful as the evaluator Dialogue: 0,0:18:37.30,0:18:38.80,EN,,0,0,0,,because it knows what it actually needs Dialogue: 0,0:18:39.69,0:18:41.16,EN,,0,0,0,,Well, in any case, if we do that Dialogue: 0,0:18:42.50,0:18:45.71,EN,,0,0,0,,and eliminate all those redundant saves and restores Dialogue: 0,0:18:46.40,0:18:49.05,EN,,0,0,0,,then we can get it down to this. Dialogue: 0,0:18:49.90,0:18:51.53,EN,,0,0,0,,And you see there are actually only three Dialogue: 0,0:18:51.64,0:18:53.71,EN,,0,0,0,,only three instructions that we actually need Dialogue: 0,0:18:54.07,0:18:55.72,EN,,0,0,0,,down from the initial 11 or so Dialogue: 0,0:18:55.97,0:18:58.81,EN,,0,0,0,,or the initial 20 or so in the original one. Dialogue: 0,0:18:59.87,0:19:00.92,EN,,0,0,0,,And that's just saying, Dialogue: 0,0:19:01.12,0:19:03.18,EN,,0,0,0,,of those register operations Dialogue: 0,0:19:03.27,0:19:04.94,EN,,0,0,0,,which ones did we actually need? Dialogue: 0,0:19:09.42,0:19:11.74,EN,,0,0,0,,Let me just sort of summarize that in another way, Dialogue: 0,0:19:11.74,0:19:13.48,EN,,0,0,0,,just to show you in a little better picture. Dialogue: 0,0:19:16.00,0:19:17.52,EN,,0,0,0,,Here's a picture of starting-- Dialogue: 0,0:19:18.77,0:19:20.81,EN,,0,0,0,,This is looking at all the saves and restores. Dialogue: 0,0:19:23.50,0:19:25.23,EN,,0,0,0,,So here's the expression, f of x Dialogue: 0,0:19:25.32,0:19:27.87,EN,,0,0,0,,and then this traces through, on the bottom here Dialogue: 0,0:19:28.75,0:19:31.80,EN,,0,0,0,,the various places in the evaluator Dialogue: 0,0:19:34.97,0:19:38.04,EN,,0,0,0,,that were passed when the evaluation happened. Dialogue: 0,0:19:38.04,0:19:40.01,EN,,0,0,0,,And then here, here you see arrows. Dialogue: 0,0:19:40.22,0:19:42.08,EN,,0,0,0,,Arrow down means register saved. Dialogue: 0,0:19:42.40,0:19:44.84,EN,,0,0,0,,So the first thing that happened is the environment got saved. Dialogue: 0,0:19:46.82,0:19:48.68,EN,,0,0,0,,And over here, the environment got restored. Dialogue: 0,0:19:52.38,0:19:54.54,EN,,0,0,0,,so there are all the pairs of stack operations. Dialogue: 0,0:19:56.12,0:19:57.56,EN,,0,0,0,,Now, if you go ahead and say Dialogue: 0,0:19:58.12,0:20:00.78,EN,,0,0,0,,well, let's remember that we don't--that unev Dialogue: 0,0:20:00.89,0:20:03.02,EN,,0,0,0,,for instance, is a completely useless register. Dialogue: 0,0:20:07.80,0:20:09.78,EN,,0,0,0,,And if we use the constant structure of the code Dialogue: 0,0:20:09.78,0:20:12.52,EN,,0,0,0,,well, we don't need, we don't need to save unev. Dialogue: 0,0:20:16.20,0:20:19.15,EN,,0,0,0,,And then, depending on how we set up the discipline of the-- Dialogue: 0,0:20:19.16,0:20:21.88,EN,,0,0,0,,of calling other things that apply, Dialogue: 0,0:20:21.88,0:20:23.85,EN,,0,0,0,,we may or may not need to save continue. Dialogue: 0,0:20:27.40,0:20:28.74,EN,,0,0,0,,That's the first step I did. Dialogue: 0,0:20:28.74,0:20:30.51,EN,,0,0,0,,And then we can look and see what's actually, Dialogue: 0,0:20:31.71,0:20:32.70,EN,,0,0,0,,what's actually needed. Dialogue: 0,0:20:33.07,0:20:35.56,EN,,0,0,0,,See, we don't-- didn't really need to save env Dialogue: 0,0:20:36.04,0:20:37.82,EN,,0,0,0,,across-evaluating f Dialogue: 0,0:20:38.08,0:20:39.92,EN,,0,0,0,,because it wouldn't, it wouldn't trash it. Dialogue: 0,0:20:39.92,0:20:41.31,EN,,0,0,0,,So if we take advantage of that Dialogue: 0,0:20:44.12,0:20:47.56,EN,,0,0,0,,and see the evaluation of f here Dialogue: 0,0:20:48.57,0:20:50.44,EN,,0,0,0,,doesn't really need to worry about, Dialogue: 0,0:20:51.61,0:20:52.60,EN,,0,0,0,,about hurting env. Dialogue: 0,0:20:52.60,0:20:54.94,EN,,0,0,0,,And similarly, the evaluation of x here Dialogue: 0,0:20:57.17,0:20:58.89,EN,,0,0,0,,when the evaluator did that it said Dialogue: 0,0:20:58.91,0:21:01.64,EN,,0,0,0,,Oh, I'd better preserve the function register around that Dialogue: 0,0:21:02.07,0:21:03.22,EN,,0,0,0,,because I might need it later. Dialogue: 0,0:21:03.28,0:21:04.89,EN,,0,0,0,,And I better preserve the argument list. Dialogue: 0,0:21:06.90,0:21:09.05,EN,,0,0,0,,Whereas the compiler is now in a position to know Dialogue: 0,0:21:09.05,0:21:10.38,EN,,0,0,0,,well, we didn't really need to save-- Dialogue: 0,0:21:10.52,0:21:11.84,EN,,0,0,0,,to do those saves and restores. Dialogue: 0,0:21:12.70,0:21:16.09,EN,,0,0,0,,So in fact, all of the stack operations done by the evaluator Dialogue: 0,0:21:16.32,0:21:19.58,EN,,0,0,0,,turned out to be unnecessary or overly pessimistic. Dialogue: 0,0:21:19.62,0:21:21.45,EN,,0,0,0,,And the compiler is in a position to know that. Dialogue: 0,0:21:27.35,0:21:28.48,EN,,0,0,0,,Well that's the basic idea. Dialogue: 0,0:21:29.80,0:21:31.00,EN,,0,0,0,,We take the evaluator Dialogue: 0,0:21:31.00,0:21:33.24,EN,,0,0,0,,we eliminate the things that you don't need Dialogue: 0,0:21:33.24,0:21:35.24,EN,,0,0,0,,that in some sense have nothing to do with the compiler at all Dialogue: 0,0:21:35.24,0:21:36.19,EN,,0,0,0,,just the evaluator Dialogue: 0,0:21:37.40,0:21:40.40,EN,,0,0,0,,and then you see which stack operations are unnecessary. Dialogue: 0,0:21:40.82,0:21:43.76,EN,,0,0,0,,That's the basic structure of the compiler that's Dialogue: 0,0:21:43.85,0:21:45.04,EN,,0,0,0,,that's described in the book. Dialogue: 0,0:21:45.04,0:21:47.00,EN,,0,0,0,,Let me just show you how a Dialogue: 0,0:21:47.76,0:21:49.68,EN,,0,0,0,,that examples a little bit too simple. Dialogue: 0,0:21:51.20,0:21:53.26,EN,,0,0,0,,To see how you, how you actually save a lot Dialogue: 0,0:21:53.29,0:21:56.06,EN,,0,0,0,,let's look at a little bit more complicated expression. Dialogue: 0,0:21:58.15,0:22:01.93,EN,,0,0,0,,(F (G X) 1) Dialogue: 0,0:22:03.87,0:22:05.52,EN,,0,0,0,,And I'm not going to go through all the code. Dialogue: 0,0:22:06.40,0:22:08.56,EN,,0,0,0,,There's a, there's a fair pile of it. Dialogue: 0,0:22:09.72,0:22:12.35,EN,,0,0,0,,I think there are, there are something like 16 Dialogue: 0,0:22:12.35,0:22:14.67,EN,,0,0,0,,16 pairs of register saves and restores Dialogue: 0,0:22:14.70,0:22:16.25,EN,,0,0,0,,as the evaluator walks through that. Dialogue: 0,0:22:17.00,0:22:18.57,EN,,0,0,0,,Here's a diagram of them. Dialogue: 0,0:22:20.57,0:22:21.95,EN,,0,0,0,,Let's see. You see what's going on. Dialogue: 0,0:22:22.97,0:22:23.90,EN,,0,0,0,,You start out by-- Dialogue: 0,0:22:24.25,0:22:26.62,EN,,0,0,0,,the evaluator says, oh, I'm about to do an application. Dialogue: 0,0:22:26.90,0:22:29.13,EN,,0,0,0,,I'll preserve the environment. I'll restore it here. Dialogue: 0,0:22:30.65,0:22:34.44,EN,,0,0,0,,Then I'm about to do the first operand. Dialogue: 0,0:22:36.81,0:22:39.28,EN,,0,0,0,,Here it recursively goes to the evaluator. Dialogue: 0,0:22:39.28,0:22:40.89,EN,,0,0,0,,The evaluator says, oh, this is an application, Dialogue: 0,0:22:40.91,0:22:42.10,EN,,0,0,0,,I'll save the environment Dialogue: 0,0:22:42.10,0:22:44.97,EN,,0,0,0,,do the operator of that combination, restore it here. Dialogue: 0,0:22:45.80,0:22:48.92,EN,,0,0,0,,This save--this restore matches that save. Dialogue: 0,0:22:49.77,0:22:50.78,EN,,0,0,0,,And so on. Dialogue: 0,0:22:51.65,0:22:52.51,EN,,0,0,0,,There's unev here, Dialogue: 0,0:22:52.52,0:22:54.62,EN,,0,0,0,,which turns out to be completely unnecessary Dialogue: 0,0:22:54.97,0:22:56.60,EN,,0,0,0,,continues getting bumped around here. Dialogue: 0,0:22:57.42,0:23:00.41,EN,,0,0,0,,The function register is getting, getting saved Dialogue: 0,0:23:00.78,0:23:04.36,EN,,0,0,0,,across the first operands, across the operands. Dialogue: 0,0:23:05.10,0:23:06.52,EN,,0,0,0,,All sorts of things are going on. Dialogue: 0,0:23:06.78,0:23:09.39,EN,,0,0,0,,But if you say, well, what of those really were the business of Dialogue: 0,0:23:09.87,0:23:11.66,EN,,0,0,0,,the compiler as opposed to the evaluator Dialogue: 0,0:23:12.27,0:23:13.55,EN,,0,0,0,,you get rid of a whole bunch. Dialogue: 0,0:23:14.30,0:23:16.64,EN,,0,0,0,,And then on top of that, if you say things like Dialogue: 0,0:23:19.40,0:23:22.54,EN,,0,0,0,,the evaluation of F doesn't hurt the environment register, Dialogue: 0,0:23:23.82,0:23:26.51,EN,,0,0,0,,or simply looking up the symbol X, Dialogue: 0,0:23:29.28,0:23:32.09,EN,,0,0,0,,you don't have to protect the function register against that. Dialogue: 0,0:23:34.30,0:23:37.60,EN,,0,0,0,,So you come down to just a couple of, a couple of pairs here. Dialogue: 0,0:23:40.25,0:23:42.27,EN,,0,0,0,,And still, you can do a little better. Dialogue: 0,0:23:42.27,0:23:44.33,EN,,0,0,0,,Look what's going on here with the environment register. Dialogue: 0,0:23:45.21,0:23:47.39,EN,,0,0,0,,The environment register comes along and says, oh, Dialogue: 0,0:23:51.00,0:23:52.25,EN,,0,0,0,,here's a combination. Dialogue: 0,0:23:54.33,0:23:55.69,EN,,0,0,0,,This evaluator, by the way, Dialogue: 0,0:23:55.78,0:23:57.27,EN,,0,0,0,,doesn't know anything about G. Dialogue: 0,0:23:58.57,0:24:00.73,EN,,0,0,0,,So here it says, so it says, Dialogue: 0,0:24:01.29,0:24:03.45,EN,,0,0,0,,I'd better save the environment register, Dialogue: 0,0:24:03.96,0:24:05.42,EN,,0,0,0,,because evaluating G might be Dialogue: 0,0:24:05.42,0:24:07.42,EN,,0,0,0,,some arbitrary piece of code that would trash it Dialogue: 0,0:24:07.55,0:24:09.45,EN,,0,0,0,,and I'm going to need it later, Dialogue: 0,0:24:10.17,0:24:11.40,EN,,0,0,0,,after this argument, Dialogue: 0,0:24:12.22,0:24:13.37,EN,,0,0,0,,for doing the second argument. Dialogue: 0,0:24:15.60,0:24:17.24,EN,,0,0,0,,So that's why this one didn't go away, Dialogue: 0,0:24:19.07,0:24:22.54,EN,,0,0,0,,because the compiler made no assumptions about what G would do. Dialogue: 0,0:24:22.54,0:24:23.60,EN,,0,0,0,,On the other hand, Dialogue: 0,0:24:24.61,0:24:26.52,EN,,0,0,0,,if you look at what the second argument is, Dialogue: 0,0:24:26.64,0:24:27.70,EN,,0,0,0,,that's just looking up one. Dialogue: 0,0:24:27.70,0:24:29.60,EN,,0,0,0,,That doesn't need this environment register. Dialogue: 0,0:24:30.77,0:24:32.04,EN,,0,0,0,,So there's no reason to save it. Dialogue: 0,0:24:32.06,0:24:33.77,EN,,0,0,0,,So in fact, you can get rid of that one, too. Dialogue: 0,0:24:34.85,0:24:37.81,EN,,0,0,0,,And from this whole pile of, of register operations, Dialogue: 0,0:24:37.98,0:24:40.08,EN,,0,0,0,,if you simply do a little bit of reasoning like that, Dialogue: 0,0:24:40.55,0:24:43.05,EN,,0,0,0,,you get down to, I think, just two pairs of saves and restores. Dialogue: 0,0:24:45.10,0:24:46.97,EN,,0,0,0,,And those, in fact, could go away further if you, Dialogue: 0,0:24:47.52,0:24:49.08,EN,,0,0,0,,if you knew something about G. Dialogue: 0,0:24:56.27,0:24:57.85,EN,,0,0,0,,So again, the general idea Dialogue: 0,0:24:57.95,0:24:59.98,EN,,0,0,0,,is that the reason the compiler can be better Dialogue: 0,0:24:59.98,0:25:02.56,EN,,0,0,0,,is that the interpreter doesn't know what it's about to encounter. Dialogue: 0,0:25:03.25,0:25:05.04,EN,,0,0,0,,It has to be maximally pessimistic Dialogue: 0,0:25:05.05,0:25:06.70,EN,,0,0,0,,to protect itself. Dialogue: 0,0:25:07.90,0:25:08.76,EN,,0,0,0,,The compiler Dialogue: 0,0:25:09.48,0:25:12.38,EN,,0,0,0,,only has to deal with what actually had to be saved. Dialogue: 0,0:25:13.37,0:25:15.20,EN,,0,0,0,,And there are two reasons that something Dialogue: 0,0:25:15.24,0:25:17.37,EN,,0,0,0,,might not have to be saved. Dialogue: 0,0:25:17.82,0:25:18.70,EN,,0,0,0,,One is that Dialogue: 0,0:25:18.70,0:25:19.82,EN,,0,0,0,,what you're protecting it against, Dialogue: 0,0:25:19.95,0:25:21.44,EN,,0,0,0,,in fact, didn't trash the register, Dialogue: 0,0:25:22.08,0:25:23.58,EN,,0,0,0,,like it was just a variable look-up. Dialogue: 0,0:25:24.12,0:25:25.20,EN,,0,0,0,,And the other one is, Dialogue: 0,0:25:25.32,0:25:27.10,EN,,0,0,0,,that the thing that you were saving it for Dialogue: 0,0:25:28.28,0:25:29.92,EN,,0,0,0,,might turn out not to actually need it. Dialogue: 0,0:25:30.81,0:25:34.27,EN,,0,0,0,,So those are the two basic pieces of knowledge Dialogue: 0,0:25:34.30,0:25:35.88,EN,,0,0,0,,that the compiler can take advantage of Dialogue: 0,0:25:36.27,0:25:37.76,EN,,0,0,0,,in making the code more efficient. Dialogue: 0,0:25:44.27,0:25:45.32,EN,,0,0,0,,Let's break for questions. Dialogue: 0,0:25:51.20,0:25:53.10,EN,,0,0,0,,AUDIENCE: You kept saying that the uneval register, Dialogue: 0,0:25:53.13,0:25:56.40,EN,,0,0,0,,unev register didn't need to be used at all. Dialogue: 0,0:25:56.41,0:25:58.68,EN,,0,0,0,,Does that mean that you could just map a six-register machine? Dialogue: 0,0:25:58.70,0:26:00.08,EN,,0,0,0,,Or is that, in this particular example, Dialogue: 0,0:26:00.11,0:26:01.18,EN,,0,0,0,,it didn't need to be used? Dialogue: 0,0:26:01.72,0:26:02.81,EN,,0,0,0,,PROFESSOR: For the compiler, Dialogue: 0,0:26:04.31,0:26:07.42,EN,,0,0,0,,you could generate code for the six-register, five, right? Dialogue: 0,0:26:07.56,0:26:09.02,EN,,0,0,0,,Because that exp goes away also. Dialogue: 0,0:26:09.40,0:26:14.57,EN,,0,0,0,,Assuming--yeah, you can get rid of both exp and unev Dialogue: 0,0:26:14.57,0:26:16.87,EN,,0,0,0,,because, see, those are data structures of the evaluator. Dialogue: 0,0:26:17.36,0:26:19.36,EN,,0,0,0,,Those are all things that would be constants Dialogue: 0,0:26:19.39,0:26:20.87,EN,,0,0,0,,from the point of view of the compiler. Dialogue: 0,0:26:21.65,0:26:22.44,EN,,0,0,0,,The only thing is Dialogue: 0,0:26:22.48,0:26:24.59,EN,,0,0,0,,this particular compiler is set up Dialogue: 0,0:26:24.79,0:26:27.92,EN,,0,0,0,,so that interpreted code and compiled code can coexist. Dialogue: 0,0:26:29.32,0:26:30.72,EN,,0,0,0,,So the way to think about it is, Dialogue: 0,0:26:30.97,0:26:32.29,EN,,0,0,0,,is maybe you build a chip Dialogue: 0,0:26:34.30,0:26:35.50,EN,,0,0,0,,which is the evaluator, Dialogue: 0,0:26:35.88,0:26:37.28,EN,,0,0,0,,and what the compiler might do Dialogue: 0,0:26:37.31,0:26:39.02,EN,,0,0,0,,is generate code for that chip. Dialogue: 0,0:26:40.40,0:26:41.90,EN,,0,0,0,,It just wouldn't use two of the registers. Dialogue: 0,0:26:51.52,0:26:52.47,EN,,0,0,0,,All right, let's take a break. Dialogue: 0,0:26:53.55,0:27:07.18,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:27:07.37,0:27:11.42,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:27:14.57,0:27:18.12,EN,,0,0,0,,By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:27:18.17,0:27:22.08,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:27:22.22,0:27:26.48,EN,,0,0,0,,Compilation Dialogue: 0,0:27:29.21,0:27:32.43,EN,,0,0,0,,We just looked at what the compiler is supposed to do. Dialogue: 0,0:27:32.78,0:27:36.04,EN,,0,0,0,,Now let's very briefly look at how, Dialogue: 0,0:27:36.15,0:27:37.47,EN,,0,0,0,,how this gets accomplished. Dialogue: 0,0:27:38.26,0:27:39.58,EN,,0,0,0,,And I'm going to give no details. Dialogue: 0,0:27:39.60,0:27:42.17,EN,,0,0,0,,There's, there's a giant pile of code in the book Dialogue: 0,0:27:42.22,0:27:43.42,EN,,0,0,0,,that gives all the details. Dialogue: 0,0:27:43.45,0:27:45.31,EN,,0,0,0,,But what I want to do is just show you the, Dialogue: 0,0:27:45.96,0:27:47.26,EN,,0,0,0,,the essential idea here. Dialogue: 0,0:27:49.49,0:27:51.36,EN,,0,0,0,,Worry about the details some other time. Dialogue: 0,0:27:51.51,0:27:55.30,EN,,0,0,0,,Let's imagine that we're compiling an expression Dialogue: 0,0:27:55.30,0:27:57.01,EN,,0,0,0,,that looks like there's some operator Dialogue: 0,0:27:57.48,0:27:58.56,EN,,0,0,0,,and there are two arguments. Dialogue: 0,0:28:03.56,0:28:04.24,EN,,0,0,0,,Now, the-- Dialogue: 0,0:28:06.27,0:28:08.14,EN,,0,0,0,,what's the code that the compiler should generate? Dialogue: 0,0:28:08.85,0:28:09.78,EN,,0,0,0,,Well, first of all, Dialogue: 0,0:28:09.83,0:28:11.20,EN,,0,0,0,,it should recursively go off Dialogue: 0,0:28:11.90,0:28:13.28,EN,,0,0,0,,and compile the operator. Dialogue: 0,0:28:14.37,0:28:19.02,EN,,0,0,0,,So it says, I'll compile the operator. Dialogue: 0,0:28:21.16,0:28:24.54,EN,,0,0,0,,And where I'm going to need that Dialogue: 0,0:28:24.84,0:28:27.95,EN,,0,0,0,,is to be in the function register, eventually. Dialogue: 0,0:28:28.42,0:28:29.60,EN,,0,0,0,,So I'll compile some instructions Dialogue: 0,0:28:29.64,0:28:31.56,EN,,0,0,0,,that will compile the operator Dialogue: 0,0:28:31.69,0:28:38.62,EN,,0,0,0,,and end up with the result in the function register. Dialogue: 0,0:28:45.51,0:28:46.94,EN,,0,0,0,,The next thing it's going to do, Dialogue: 0,0:28:47.71,0:28:49.68,EN,,0,0,0,,another piece is to say, Dialogue: 0,0:28:49.68,0:28:55.17,EN,,0,0,0,,I have to compile the first argument. Dialogue: 0,0:28:55.17,0:28:56.80,EN,,0,0,0,,So it calls itself recursively. Dialogue: 0,0:28:58.04,0:29:03.36,EN,,0,0,0,,And let's say the result will go into val. Dialogue: 0,0:29:09.07,0:29:10.75,EN,,0,0,0,,And then what it's going to need to do is Dialogue: 0,0:29:10.75,0:29:12.26,EN,,0,0,0,,start setting up the argument list. Dialogue: 0,0:29:12.95,0:29:25.50,EN,,0,0,0,,So it'll say, assign to argl cons of fetch-- Dialogue: 0,0:29:25.55,0:29:27.10,EN,,0,0,0,,so it generates this literal instruction-- Dialogue: 0,0:29:27.50,0:29:32.51,EN,,0,0,0,,fetch of val onto empty list. Dialogue: 0,0:29:35.00,0:29:36.05,EN,,0,0,0,,However, Dialogue: 0,0:29:37.99,0:29:40.61,EN,,0,0,0,,it might have to work-- when it gets here, Dialogue: 0,0:29:41.32,0:29:42.82,EN,,0,0,0,,it's going to need the environment. Dialogue: 0,0:29:43.95,0:29:45.29,EN,,0,0,0,,It's going to need whatever environment was here Dialogue: 0,0:29:45.32,0:29:48.21,EN,,0,0,0,,in order to do this evaluation of the first argument. Dialogue: 0,0:29:49.04,0:29:51.18,EN,,0,0,0,,So it has to ensure that Dialogue: 0,0:29:51.92,0:29:53.76,EN,,0,0,0,,the compilation of this operand, Dialogue: 0,0:29:55.32,0:29:57.85,EN,,0,0,0,,or it has to protect the function register Dialogue: 0,0:29:58.01,0:30:00.98,EN,,0,0,0,,against whatever might happen in the compilation of this operand. Dialogue: 0,0:30:01.30,0:30:03.08,EN,,0,0,0,,So it puts a note here and says, oh, Dialogue: 0,0:30:03.37,0:30:12.89,EN,,0,0,0,,this piece should be done preserving the environment register. Dialogue: 0,0:30:17.39,0:30:18.44,EN,,0,0,0,,Similarly, here, Dialogue: 0,0:30:21.02,0:30:23.30,EN,,0,0,0,,after it gets done compiling the first operand, Dialogue: 0,0:30:23.57,0:30:24.67,EN,,0,0,0,,it's going to say, I'd better-- Dialogue: 0,0:30:24.71,0:30:27.92,EN,,0,0,0,,I'm going to need to know the environment for the second operand. Dialogue: 0,0:30:27.92,0:30:29.46,EN,,0,0,0,,So it puts a little note here, saying, Dialogue: 0,0:30:29.71,0:30:35.96,EN,,0,0,0,,yeah, this is also done preserving env. Dialogue: 0,0:30:39.42,0:30:41.02,EN,,0,0,0,,Now it goes on and says, well, Dialogue: 0,0:30:41.12,0:30:42.83,EN,,0,0,0,,the next chunk of code Dialogue: 0,0:30:43.31,0:30:49.74,EN,,0,0,0,,is the one that's going to compile the second argument. Dialogue: 0,0:30:50.82,0:30:52.64,EN,,0,0,0,,And let's say Dialogue: 0,0:30:52.99,0:30:59.28,EN,,0,0,0,,And let's say it'll compile it with a targeted to val, as they say. Dialogue: 0,0:31:03.86,0:31:06.70,EN,,0,0,0,,And then it'll generate the literal instruction, Dialogue: 0,0:31:07.84,0:31:09.25,EN,,0,0,0,,building up the argument list. Dialogue: 0,0:31:09.55,0:31:15.28,EN,,0,0,0,,So it'll say, assign to argl Dialogue: 0,0:31:20.22,0:31:28.94,EN,,0,0,0,,cons of the new value it just got onto the old argument list. Dialogue: 0,0:31:33.97,0:31:34.64,EN,,0,0,0,,However, Dialogue: 0,0:31:34.81,0:31:36.58,EN,,0,0,0,,in order to have the old argument list, Dialogue: 0,0:31:37.15,0:31:40.99,EN,,0,0,0,,it better have arranged that the argument list didn't get trashed Dialogue: 0,0:31:41.30,0:31:42.69,EN,,0,0,0,,by whatever happened in here. Dialogue: 0,0:31:43.50,0:31:45.17,EN,,0,0,0,,So it puts a little note here and says, Dialogue: 0,0:31:45.34,0:31:51.64,EN,,0,0,0,,oh, this has to be done preserving argl. Dialogue: 0,0:31:54.16,0:31:56.03,EN,,0,0,0,,Now it's got the argument list set up. Dialogue: 0,0:31:58.01,0:32:02.86,EN,,0,0,0,,And it's all ready to go to apply dispatch. Dialogue: 0,0:32:07.02,0:32:10.80,EN,,0,0,0,,It generates this literal instruction. Dialogue: 0,0:32:15.19,0:32:17.37,EN,,0,0,0,,Because now it's got the arguments in argl Dialogue: 0,0:32:18.15,0:32:20.59,EN,,0,0,0,,and the operator in fun, Dialogue: 0,0:32:20.59,0:32:22.89,EN,,0,0,0,,but wait, it's only got the operator in fun Dialogue: 0,0:32:23.27,0:32:26.64,EN,,0,0,0,,if it had ensured that this block of code Dialogue: 0,0:32:27.09,0:32:29.27,EN,,0,0,0,,didn't trash what was in the function register. Dialogue: 0,0:32:29.67,0:32:31.24,EN,,0,0,0,,So it puts a little note here and says, Dialogue: 0,0:32:31.55,0:32:32.73,EN,,0,0,0,,oh, yes, all this stuff here Dialogue: 0,0:32:34.88,0:32:40.73,EN,,0,0,0,,had better be done preserving the function register. Dialogue: 0,0:32:43.71,0:32:46.15,EN,,0,0,0,,So that's the little--so when it starts ticking-- Dialogue: 0,0:32:46.15,0:32:47.10,EN,,0,0,0,,so basically, what the Dialogue: 0,0:32:48.20,0:32:50.24,EN,,0,0,0,,what the compiler does is Dialogue: 0,0:32:50.54,0:32:52.46,EN,,0,0,0,,append a whole bunch of code sequences. Dialogue: 0,0:32:53.50,0:32:58.83,EN,,0,0,0,,See, what it's got in it is little primitive pieces of things Dialogue: 0,0:32:58.86,0:33:00.12,EN,,0,0,0,,like how to look up a symbol, Dialogue: 0,0:33:01.44,0:33:02.60,EN,,0,0,0,,how to do a conditional. Dialogue: 0,0:33:02.64,0:33:05.44,EN,,0,0,0,,Those are all little pieces of things. Dialogue: 0,0:33:05.44,0:33:07.99,EN,,0,0,0,,And then it appends them together in this sort of discipline. Dialogue: 0,0:33:08.78,0:33:10.79,EN,,0,0,0,,So the basic means of combining things Dialogue: 0,0:33:10.86,0:33:13.18,EN,,0,0,0,,is to append two code sequences. Dialogue: 0,0:33:21.55,0:33:22.86,EN,,0,0,0,,That's what's going on here. Dialogue: 0,0:33:25.58,0:33:27.24,EN,,0,0,0,,And it's a little bit tricky. Dialogue: 0,0:33:27.56,0:33:30.37,EN,,0,0,0,,The idea is that it appends two code sequences, Dialogue: 0,0:33:31.60,0:33:33.76,EN,,0,0,0,,taking care to preserve a register. Dialogue: 0,0:33:35.63,0:33:37.93,EN,,0,0,0,,So the actual append operation looks like this. Dialogue: 0,0:33:39.15,0:33:40.65,EN,,0,0,0,,What it wants to do is say, if-- Dialogue: 0,0:33:41.20,0:33:44.11,EN,,0,0,0,,here's what it means to append two code sequences. Dialogue: 0,0:33:44.53,0:33:53.63,EN,,0,0,0,,So if sequence one needs register-- Dialogue: 0,0:33:53.66,0:33:54.72,EN,,0,0,0,,I should change this. Dialogue: 0,0:33:54.72,0:33:56.87,EN,,0,0,0,,Append sequence one to sequence two, Dialogue: 0,0:33:57.42,0:34:03.96,EN,,0,0,0,,preserving some register. Dialogue: 0,0:34:08.52,0:34:09.91,EN,,0,0,0,,Let me say, and. Dialogue: 0,0:34:11.36,0:34:13.03,EN,,0,0,0,,So it's clear that sequence one comes first. Dialogue: 0,0:34:13.88,0:34:19.87,EN,,0,0,0,,So if sequence two needs the register Dialogue: 0,0:34:21.12,0:34:27.85,EN,,0,0,0,,and sequence one modifies the register, Dialogue: 0,0:34:33.68,0:34:36.30,EN,,0,0,0,,then the instructions that the compiler spits out, Dialogue: 0,0:34:36.97,0:34:41.34,EN,,0,0,0,,are save the register. Dialogue: 0,0:34:43.02,0:34:44.19,EN,,0,0,0,,Here's the code. Dialogue: 0,0:34:44.35,0:34:45.35,EN,,0,0,0,,You generate this code. Dialogue: 0,0:34:45.35,0:34:46.28,EN,,0,0,0,,Save the register, Dialogue: 0,0:34:46.72,0:34:52.97,EN,,0,0,0,,and then you put out the recursively compiled stuff for sequence one. Dialogue: 0,0:34:53.30,0:34:54.84,EN,,0,0,0,,And then you restore the register. Dialogue: 0,0:35:00.52,0:35:03.92,EN,,0,0,0,,And then you put out the recursively compiled stuff Dialogue: 0,0:35:04.46,0:35:05.47,EN,,0,0,0,,for sequence two. Dialogue: 0,0:35:07.07,0:35:09.62,EN,,0,0,0,,That's in the case where you need to do it. Dialogue: 0,0:35:09.62,0:35:11.82,EN,,0,0,0,,Sequence two actually needs the register, Dialogue: 0,0:35:11.82,0:35:13.74,EN,,0,0,0,,and sequence one actually clobbers it. Dialogue: 0,0:35:15.12,0:35:17.07,EN,,0,0,0,,So that's sort of if. Otherwise, Dialogue: 0,0:35:20.50,0:35:26.57,EN,,0,0,0,,all you spit out is sequence one followed by sequence two. Dialogue: 0,0:35:28.17,0:35:30.30,EN,,0,0,0,,So that's the basic operation Dialogue: 0,0:35:30.59,0:35:33.52,EN,,0,0,0,,for sticking together these bits of code fragments, Dialogue: 0,0:35:33.93,0:35:35.93,EN,,0,0,0,,these bits of instructions into a sequence. Dialogue: 0,0:35:36.89,0:35:38.87,EN,,0,0,0,,And you see, from this point of view, Dialogue: 0,0:35:40.94,0:35:45.96,EN,,0,0,0,,the difference between the interpreter and the compiler, in some sense, Dialogue: 0,0:35:46.82,0:35:49.34,EN,,0,0,0,,is that where the compiler has these preserving notes, Dialogue: 0,0:35:50.14,0:35:52.22,EN,,0,0,0,,and says, maybe I'll actually generate the Dialogue: 0,0:35:52.49,0:35:54.22,EN,,0,0,0,,saves and restores and maybe I won't, Dialogue: 0,0:35:55.19,0:35:57.24,EN,,0,0,0,,the interpreter being maximally pessimistic Dialogue: 0,0:35:57.28,0:35:58.90,EN,,0,0,0,,always has a save and restore here. Dialogue: 0,0:36:00.76,0:36:01.93,EN,,0,0,0,,That's the essential difference. Dialogue: 0,0:36:04.16,0:36:06.05,EN,,0,0,0,,Well, in order to do this, of course, Dialogue: 0,0:36:06.65,0:36:09.40,EN,,0,0,0,,the compiler needs some theory of Dialogue: 0,0:36:09.56,0:36:11.96,EN,,0,0,0,,what code sequences need and modifier registers. Dialogue: 0,0:36:14.26,0:36:17.28,EN,,0,0,0,,So the tiny little fragments that you put in, like Dialogue: 0,0:36:17.48,0:36:21.00,EN,,0,0,0,,the basic primitive code fragments, Dialogue: 0,0:36:22.74,0:36:24.59,EN,,0,0,0,,say, what are the operations that you do Dialogue: 0,0:36:24.92,0:36:26.04,EN,,0,0,0,,when you look up a variable? Dialogue: 0,0:36:26.89,0:36:29.02,EN,,0,0,0,,What are the sequence of things that you do Dialogue: 0,0:36:29.05,0:36:30.68,EN,,0,0,0,,when you compile a constant Dialogue: 0,0:36:30.97,0:36:32.10,EN,,0,0,0,,or apply a function? Dialogue: 0,0:36:32.97,0:36:34.48,EN,,0,0,0,,Those have little notations in there Dialogue: 0,0:36:34.67,0:36:36.46,EN,,0,0,0,,about what they need and what they modify. Dialogue: 0,0:36:38.78,0:36:41.50,EN,,0,0,0,,So the bottom-level data structures-- Dialogue: 0,0:36:42.66,0:36:44.33,EN,,0,0,0,,Well, I'll say this. Dialogue: 0,0:36:44.39,0:36:47.91,EN,,0,0,0,,A code sequence to the compiler looks like this. Dialogue: 0,0:36:48.07,0:36:51.42,EN,,0,0,0,,It has the actual sequence of instructions. Dialogue: 0,0:36:55.67,0:36:56.81,EN,,0,0,0,,And then, along with it, Dialogue: 0,0:36:57.18,0:37:02.60,EN,,0,0,0,,there's the set of registers modified. Dialogue: 0,0:37:10.54,0:37:12.60,EN,,0,0,0,,And then there's the set of registers needed. Dialogue: 0,0:37:20.00,0:37:22.46,EN,,0,0,0,,So that's the information the compiler has Dialogue: 0,0:37:23.00,0:37:26.41,EN,,0,0,0,,that it draws on in order to be able to do this operation. Dialogue: 0,0:37:29.30,0:37:31.08,EN,,0,0,0,,And where do those come from? Well. Dialogue: 0,0:37:32.91,0:37:34.49,EN,,0,0,0,,Well, those come from, you might expect, Dialogue: 0,0:37:34.51,0:37:35.53,EN,,0,0,0,,for the very primitive ones, Dialogue: 0,0:37:35.55,0:37:36.84,EN,,0,0,0,,we're going to put them in by hand. Dialogue: 0,0:37:37.24,0:37:38.86,EN,,0,0,0,,And then, when we combine two sequences, Dialogue: 0,0:37:38.89,0:37:41.02,EN,,0,0,0,,we'll figure out what these things should be. Dialogue: 0,0:37:42.16,0:37:44.12,EN,,0,0,0,,So for example, a very primitive one, let's see. Dialogue: 0,0:37:48.43,0:37:51.40,EN,,0,0,0,,How about doing a register assignment. Dialogue: 0,0:37:51.77,0:37:53.50,EN,,0,0,0,,So a primitive sequence might say, Dialogue: 0,0:37:53.52,0:37:56.22,EN,,0,0,0,,oh, it's code fragment. Dialogue: 0,0:37:56.22,0:38:03.17,EN,,0,0,0,,Its code instruction is assigned to R1, fetch of R2. Dialogue: 0,0:38:03.17,0:38:04.27,EN,,0,0,0,,So this is an example. Dialogue: 0,0:38:05.42,0:38:08.52,EN,,0,0,0,,That might be an example of a sequence of instructions. Dialogue: 0,0:38:08.77,0:38:10.53,EN,,0,0,0,,And along with that, it'll say, Oh Dialogue: 0,0:38:10.64,0:38:15.76,EN,,0,0,0,,oh, what I need to remember is that that modifies R1 Dialogue: 0,0:38:18.60,0:38:21.16,EN,,0,0,0,,and then it needs R2. Dialogue: 0,0:38:24.69,0:38:26.99,EN,,0,0,0,,So when you're first building this compiler, Dialogue: 0,0:38:27.10,0:38:29.35,EN,,0,0,0,,you put in little fragments of stuff like that. Dialogue: 0,0:38:30.95,0:38:33.20,EN,,0,0,0,,And now, when it combines two sequences, Dialogue: 0,0:38:36.70,0:38:38.04,EN,,0,0,0,,if I'm going to combine, Dialogue: 0,0:38:38.92,0:38:41.58,EN,,0,0,0,,let's say, sequence one, Dialogue: 0,0:38:42.88,0:38:47.16,EN,,0,0,0,,that modifies a bunch of registers M1, Dialogue: 0,0:38:48.45,0:38:51.42,EN,,0,0,0,,and needs a bunch of registers N1. Dialogue: 0,0:38:54.85,0:38:59.48,EN,,0,0,0,,And I'm going to combine that with sequence two. Dialogue: 0,0:39:00.81,0:39:05.96,EN,,0,0,0,,That modifies a bunch of registers M2, Dialogue: 0,0:39:07.11,0:39:10.00,EN,,0,0,0,,and needs a bunch of registers N2. Dialogue: 0,0:39:12.44,0:39:14.83,EN,,0,0,0,,Then, well, we can reason it out. Dialogue: 0,0:39:15.11,0:39:16.32,EN,,0,0,0,,The new code fragment, Dialogue: 0,0:39:17.18,0:39:21.82,EN,,0,0,0,,sequence one, and-- followed by sequence two, Dialogue: 0,0:39:24.09,0:39:26.45,EN,,0,0,0,,well, what's it going to modify? Dialogue: 0,0:39:27.80,0:39:29.18,EN,,0,0,0,,The things that it will modify are the things Dialogue: 0,0:39:29.20,0:39:32.68,EN,,0,0,0,,that are modified either by sequence one or sequence two. Dialogue: 0,0:39:34.00,0:39:36.35,EN,,0,0,0,,So the union of these two Dialogue: 0,0:39:37.68,0:39:39.64,EN,,0,0,0,,sets are what the new thing modifies. Dialogue: 0,0:39:40.46,0:39:41.79,EN,,0,0,0,,And then you say, well, what is this-- Dialogue: 0,0:39:44.66,0:39:46.41,EN,,0,0,0,,what registers is it going to need? Dialogue: 0,0:39:47.95,0:39:49.77,EN,,0,0,0,,It's going to need the things that are, Dialogue: 0,0:39:49.93,0:39:51.85,EN,,0,0,0,,first of all, needed by sequence one. Dialogue: 0,0:39:52.91,0:39:54.49,EN,,0,0,0,,So what it needs is sequence one. Dialogue: 0,0:39:55.19,0:39:58.28,EN,,0,0,0,,And then, well, not quite all of the ones Dialogue: 0,0:39:58.32,0:39:59.61,EN,,0,0,0,,that are needed by sequence two. Dialogue: 0,0:39:59.75,0:40:03.49,EN,,0,0,0,,What it needs are the ones that are needed by sequence two Dialogue: 0,0:40:03.88,0:40:06.88,EN,,0,0,0,,that have not been set up by sequence one. Dialogue: 0,0:40:08.14,0:40:09.72,EN,,0,0,0,,So it's sort of the union of Dialogue: 0,0:40:11.66,0:40:13.40,EN,,0,0,0,,the things that sequence two needs Dialogue: 0,0:40:14.51,0:40:18.52,EN,,0,0,0,,minus the ones that sequence one modifies. Dialogue: 0,0:40:19.31,0:40:20.88,EN,,0,0,0,,Because it worries about setting them up. Dialogue: 0,0:40:23.95,0:40:26.26,EN,,0,0,0,,So there's the basic structure of the compiler. Dialogue: 0,0:40:26.70,0:40:29.82,EN,,0,0,0,,The way you do register optimizations is you Dialogue: 0,0:40:30.22,0:40:32.70,EN,,0,0,0,,you have some strategies for what needs to be preserved. Dialogue: 0,0:40:34.10,0:40:35.63,EN,,0,0,0,,That depends on a data structure. Dialogue: 0,0:40:35.72,0:40:38.51,EN,,0,0,0,,Well, it depends on the operation of what it means to put things together. Dialogue: 0,0:40:39.03,0:40:41.63,EN,,0,0,0,,Preserving something, that depends on knowing Dialogue: 0,0:40:41.93,0:40:47.28,EN,,0,0,0,,what registers are needed and modified by these code fragments. Dialogue: 0,0:40:48.75,0:40:51.26,EN,,0,0,0,,That depends on having little data structures, Dialogue: 0,0:40:51.42,0:40:55.43,EN,,0,0,0,,which say, a code sequence is the actual instructions, Dialogue: 0,0:40:55.60,0:40:57.33,EN,,0,0,0,,what they modify and what they need. Dialogue: 0,0:40:57.33,0:40:59.77,EN,,0,0,0,,That comes from, at the primitive level, building it in. Dialogue: 0,0:40:59.79,0:41:01.36,EN,,0,0,0,,At the primitive level, Dialogue: 0,0:41:01.37,0:41:02.52,EN,,0,0,0,,it's going to be completely obvious Dialogue: 0,0:41:03.00,0:41:04.44,EN,,0,0,0,,what something needs and modifies. Dialogue: 0,0:41:04.82,0:41:05.35,EN,,0,0,0,,Plus, Dialogue: 0,0:41:05.44,0:41:08.60,EN,,0,0,0,,this particular way that says, when I build up bigger ones, Dialogue: 0,0:41:09.28,0:41:11.89,EN,,0,0,0,,here's how I generate the new set of registers modified Dialogue: 0,0:41:11.93,0:41:13.37,EN,,0,0,0,,and the new set of registers needed. Dialogue: 0,0:41:15.27,0:41:17.77,EN,,0,0,0,,And that's the whole-- well, I shouldn't say that's the whole thing. Dialogue: 0,0:41:17.77,0:41:19.34,EN,,0,0,0,,That's the whole thing except for about Dialogue: 0,0:41:19.74,0:41:21.87,EN,,0,0,0,,about 30 pages of details in the book. Dialogue: 0,0:41:22.31,0:41:27.69,EN,,0,0,0,,But it is a perfectly usable rudimentary compiler. Dialogue: 0,0:41:28.76,0:41:31.37,EN,,0,0,0,,Let me kind of show you what it does. Dialogue: 0,0:41:31.39,0:41:35.56,EN,,0,0,0,,Suppose we start out with recursive factorial. Dialogue: 0,0:41:36.20,0:41:38.60,EN,,0,0,0,,And these slides are going to be much too small to read. Dialogue: 0,0:41:38.60,0:41:39.79,EN,,0,0,0,,I just want to flash through the code Dialogue: 0,0:41:39.79,0:41:41.28,EN,,0,0,0,,and show you about how much it is. Dialogue: 0,0:41:42.25,0:41:43.29,EN,,0,0,0,,That starts out with-- Dialogue: 0,0:41:44.32,0:41:45.68,EN,,0,0,0,,here's a first block of it, Dialogue: 0,0:41:45.95,0:41:47.68,EN,,0,0,0,,where it compiles a procedure entry Dialogue: 0,0:41:47.69,0:41:48.73,EN,,0,0,0,,and does a bunch of assignments. Dialogue: 0,0:41:48.75,0:41:51.48,EN,,0,0,0,,And this thing is basically up through the part where Dialogue: 0,0:41:52.65,0:41:53.90,EN,,0,0,0,,sets up to do the predicate Dialogue: 0,0:41:54.31,0:41:56.59,EN,,0,0,0,,and test whether the predicate's true. Dialogue: 0,0:41:56.97,0:41:57.85,EN,,0,0,0,,The second part Dialogue: 0,0:41:58.46,0:42:03.73,EN,,0,0,0,,is what results from-- in the recursive call to fact of n minus one. Dialogue: 0,0:42:04.12,0:42:05.05,EN,,0,0,0,,And this last part Dialogue: 0,0:42:06.07,0:42:07.48,EN,,0,0,0,,is coming back from that Dialogue: 0,0:42:07.87,0:42:09.90,EN,,0,0,0,,and then taking care of the constant case. Dialogue: 0,0:42:09.90,0:42:13.16,EN,,0,0,0,,So that's about how much code it would produce for factorial. Dialogue: 0,0:42:13.72,0:42:17.69,EN,,0,0,0,,We could make this compiler much, much better, of course. Dialogue: 0,0:42:18.67,0:42:21.24,EN,,0,0,0,,The main way we could make it better is Dialogue: 0,0:42:21.24,0:42:24.00,EN,,0,0,0,,to allow the compiler to make any assumptions at all Dialogue: 0,0:42:24.35,0:42:26.27,EN,,0,0,0,,about what happens when you call a procedure. Dialogue: 0,0:42:26.97,0:42:28.28,EN,,0,0,0,,So this compiler, for instance, Dialogue: 0,0:42:28.30,0:42:32.32,EN,,0,0,0,,doesn't even know, say, that multiplication Dialogue: 0,0:42:33.12,0:42:36.14,EN,,0,0,0,,you say, is something that could be coded in line. Dialogue: 0,0:42:36.14,0:42:37.87,EN,,0,0,0,,Instead, it sets up this whole mechanism. Dialogue: 0,0:42:38.00,0:42:39.34,EN,,0,0,0,,It goes to apply-dispatch. Dialogue: 0,0:42:41.37,0:42:42.49,EN,,0,0,0,,That's a tremendous waste, Dialogue: 0,0:42:42.54,0:42:45.02,EN,,0,0,0,,because what you do every time you go to apply-dispatch Dialogue: 0,0:42:45.02,0:42:46.80,EN,,0,0,0,,is you have to concern about this argument list, Dialogue: 0,0:42:47.40,0:42:49.10,EN,,0,0,0,,because it's a very general thing you're going to. Dialogue: 0,0:42:49.13,0:42:51.07,EN,,0,0,0,,In any real compiler, of course, Dialogue: 0,0:42:51.08,0:42:53.29,EN,,0,0,0,,you're going to have registers for holding arguments. Dialogue: 0,0:42:53.77,0:42:55.31,EN,,0,0,0,,And you're going to start preserving Dialogue: 0,0:42:56.38,0:42:58.05,EN,,0,0,0,,saving the way you use those registers Dialogue: 0,0:42:58.05,0:43:01.61,EN,,0,0,0,,similar to the same strategy here. Dialogue: 0,0:43:02.85,0:43:05.93,EN,,0,0,0,,So that's probably the very main way Dialogue: 0,0:43:05.95,0:43:08.30,EN,,0,0,0,,this particular compiler in the book could be fixed. Dialogue: 0,0:43:08.69,0:43:09.70,EN,,0,0,0,,There are other things like Dialogue: 0,0:43:09.70,0:43:11.82,EN,,0,0,0,,looking up variable values and Dialogue: 0,0:43:11.83,0:43:13.87,EN,,0,0,0,,making more efficient primitive operations, Dialogue: 0,0:43:13.88,0:43:14.56,EN,,0,0,0,,and all sorts of things. Dialogue: 0,0:43:14.59,0:43:16.60,EN,,0,0,0,,Essentially, a good Lisp compiler Dialogue: 0,0:43:16.62,0:43:18.49,EN,,0,0,0,,can absorb an arbitrary amount of effort. Dialogue: 0,0:43:19.72,0:43:21.63,EN,,0,0,0,,And probably one of the reasons Dialogue: 0,0:43:21.89,0:43:23.04,EN,,0,0,0,,Lisp is slow Dialogue: 0,0:43:23.63,0:43:25.44,EN,,0,0,0,,with compared to languages like FORTRAN Dialogue: 0,0:43:25.90,0:43:28.19,EN,,0,0,0,,is that, if you look over history Dialogue: 0,0:43:28.22,0:43:31.12,EN,,0,0,0,,the amount of effort that's gone into building Lisp compilers, Dialogue: 0,0:43:31.16,0:43:32.35,EN,,0,0,0,,it's nowhere near the amount of effort Dialogue: 0,0:43:32.36,0:43:33.90,EN,,0,0,0,,that's gone into FORTRAN compilers. Dialogue: 0,0:43:34.43,0:43:35.79,EN,,0,0,0,,And maybe that's something that will Dialogue: 0,0:43:35.92,0:43:37.68,EN,,0,0,0,,that will change over the next couple of years. Dialogue: 0,0:43:38.00,0:43:38.83,EN,,0,0,0,,OK, let's break. Dialogue: 0,0:43:43.80,0:43:44.65,EN,,0,0,0,,Questions? Dialogue: 0,0:43:48.27,0:43:49.95,EN,,0,0,0,,AUDIENCE: One of the very first classes-- Dialogue: 0,0:43:49.95,0:43:51.40,EN,,0,0,0,,I don't know if it was during class or after class- Dialogue: 0,0:43:51.47,0:43:53.88,EN,,0,0,0,,you showed me the, the Dialogue: 0,0:43:54.00,0:43:57.52,EN,,0,0,0,,say, addition has a primitive that we don't see, Dialogue: 0,0:43:57.69,0:43:59.21,EN,,0,0,0,,and-percent add or something like that. Dialogue: 0,0:43:59.82,0:44:01.65,EN,,0,0,0,,Is that because, Dialogue: 0,0:44:01.65,0:44:02.60,EN,,0,0,0,,if you're doing inline code Dialogue: 0,0:44:02.60,0:44:08.19,EN,,0,0,0,,you'd want to just do it for two operators, operands? Dialogue: 0,0:44:08.70,0:44:10.25,EN,,0,0,0,,But if you had more operands, Dialogue: 0,0:44:10.28,0:44:11.47,EN,,0,0,0,,you'd want to do something special? Dialogue: 0,0:44:12.71,0:44:16.04,EN,,0,0,0,,PROFESSOR: Yeah, you're looking in the actual scheme implementation. Dialogue: 0,0:44:16.06,0:44:17.84,EN,,0,0,0,,There's a plus, and a plus is some operator. Dialogue: 0,0:44:17.90,0:44:20.19,EN,,0,0,0,,And then if you go look inside the code for plus, Dialogue: 0,0:44:20.33,0:44:21.37,EN,,0,0,0,,you see something called-- Dialogue: 0,0:44:21.57,0:44:24.14,EN,,0,0,0,,I forget-- and-percent plus or something like that. Dialogue: 0,0:44:24.55,0:44:25.79,EN,,0,0,0,,And what's going on there is Dialogue: 0,0:44:25.79,0:44:27.92,EN,,0,0,0,,is that particular kind of optimization. Dialogue: 0,0:44:28.47,0:44:31.87,EN,,0,0,0,,Because, see, general plus takes an arbitrary number of arguments. Dialogue: 0,0:44:35.02,0:44:36.38,EN,,0,0,0,,So the most general plus Dialogue: 0,0:44:36.76,0:44:38.25,EN,,0,0,0,,says, oh, if I have an argument list, Dialogue: 0,0:44:38.28,0:44:40.62,EN,,0,0,0,,I'd better cons it up in some list Dialogue: 0,0:44:41.63,0:44:44.14,EN,,0,0,0,,and then figure out how many there were or something like that. Dialogue: 0,0:44:44.72,0:44:46.16,EN,,0,0,0,,That's terribly inefficient, Dialogue: 0,0:44:46.81,0:44:49.25,EN,,0,0,0,,especially since most of the time you're probably adding two numbers. Dialogue: 0,0:44:49.25,0:44:51.24,EN,,0,0,0,,You don't want to really have to cons this argument list. Dialogue: 0,0:44:52.04,0:44:53.93,EN,,0,0,0,,So what you'd like to do is build Dialogue: 0,0:44:55.66,0:44:57.71,EN,,0,0,0,,the code for plus with a bunch of entries. Dialogue: 0,0:44:58.15,0:45:00.17,EN,,0,0,0,,So most of what it's doing is the same. Dialogue: 0,0:45:00.49,0:45:01.95,EN,,0,0,0,,However, there might be a special entry Dialogue: 0,0:45:01.98,0:45:03.92,EN,,0,0,0,,that you'd go to if you knew there were only two arguments. Dialogue: 0,0:45:04.56,0:45:05.87,EN,,0,0,0,,And those you'll put in registers. Dialogue: 0,0:45:05.87,0:45:06.97,EN,,0,0,0,,they won't be in an argument list Dialogue: 0,0:45:06.99,0:45:07.98,EN,,0,0,0,,and you won't have to CONS. Dialogue: 0,0:45:08.67,0:45:10.42,EN,,0,0,0,,That's how a lot of these things work. Dialogue: 0,0:45:12.30,0:45:13.72,EN,,0,0,0,,OK, let's take a break. ================================================ FILE: Ass/lec10b.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 2622 Video Position: 105949 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:18.91,0:00:20.61,EN,,0,0,0,,PROFESSOR: Well, there's one bit of mystery left, Dialogue: 0,0:00:21.16,0:00:23.36,EN,,0,0,0,,which I'd like to get rid of right now. Dialogue: 0,0:00:24.44,0:00:28.80,EN,,0,0,0,,And that's that we've been blithely doing things like cons Dialogue: 0,0:00:30.00,0:00:31.62,EN,,0,0,0,,assuming there's always another one. Dialogue: 0,0:00:32.80,0:00:36.32,EN,,0,0,0,,That we've been doing these things like Dialogue: 0,0:00:36.51,0:00:37.44,EN,,0,0,0,,car-ing and cdr-ing Dialogue: 0,0:00:37.47,0:00:38.72,EN,,0,0,0,,and assuming that we had some idea Dialogue: 0,0:00:38.75,0:00:39.74,EN,,0,0,0,,how this can be done. Dialogue: 0,0:00:40.02,0:00:40.67,EN,,0,0,0,,Now indeed Dialogue: 0,0:00:41.07,0:00:44.40,EN,,0,0,0,,we said that that's equivalent to having procedures. Dialogue: 0,0:00:45.37,0:00:47.57,EN,,0,0,0,,OK? But that doesn't really solve the problem, Dialogue: 0,0:00:47.73,0:00:50.25,EN,,0,0,0,,because the procedure need all sorts of complicated mechanisms Dialogue: 0,0:00:50.27,0:00:51.37,EN,,0,0,0,,like environment structures Dialogue: 0,0:00:51.64,0:00:52.76,EN,,0,0,0,,and things like that to work. Dialogue: 0,0:00:53.01,0:00:54.89,EN,,0,0,0,,And those were ultimately made out of conses Dialogue: 0,0:00:54.89,0:00:56.42,EN,,0,0,0,,in the model that we had, Dialogue: 0,0:00:56.70,0:00:58.47,EN,,0,0,0,,so that really doesn't solve the problem. Dialogue: 0,0:00:59.38,0:01:01.13,EN,,0,0,0,,Now the problem here is Dialogue: 0,0:01:01.31,0:01:03.97,EN,,0,0,0,,is the glue the data structure's made out of. Dialogue: 0,0:01:04.76,0:01:06.40,EN,,0,0,0,,What kind of possible thing could it be? Dialogue: 0,0:01:07.04,0:01:10.46,EN,,0,0,0,,OK? We've been showing you things like a machine, Dialogue: 0,0:01:10.46,0:01:13.96,EN,,0,0,0,,a computer that has a controller, Dialogue: 0,0:01:14.27,0:01:15.45,EN,,0,0,0,,and some registers, Dialogue: 0,0:01:15.45,0:01:16.47,EN,,0,0,0,,and maybe a stack. Dialogue: 0,0:01:16.98,0:01:18.12,EN,,0,0,0,,And we haven't said anything about, Dialogue: 0,0:01:18.16,0:01:19.95,EN,,0,0,0,,for example, larger memory. Dialogue: 0,0:01:20.57,0:01:22.38,EN,,0,0,0,,And I think that's what we have to worry about right now. Dialogue: 0,0:01:23.74,0:01:26.56,EN,,0,0,0,,But just to make it perfectly clear Dialogue: 0,0:01:26.59,0:01:27.88,EN,,0,0,0,,that this is an inessential, Dialogue: 0,0:01:28.82,0:01:30.79,EN,,0,0,0,,purely implementational thing, Dialogue: 0,0:01:31.10,0:01:32.60,EN,,0,0,0,,I'd like to show you, for example, Dialogue: 0,0:01:32.60,0:01:34.20,EN,,0,0,0,,how you can do it all with the numbers. Dialogue: 0,0:01:35.23,0:01:36.82,EN,,0,0,0,,That's an easy one. Dialogue: 0,0:01:37.59,0:01:39.00,EN,,0,0,0,,Famous fellow by the name of Godel, Dialogue: 0,0:01:44.09,0:01:46.01,EN,,0,0,0,,a logician at the end of the 1930s, Dialogue: 0,0:01:46.38,0:01:48.70,EN,,0,0,0,,invented a very clever way Dialogue: 0,0:01:48.70,0:01:52.27,EN,,0,0,0,,of encoding the complicated expressions Dialogue: 0,0:01:52.81,0:01:53.52,EN,,0,0,0,,as numbers. Dialogue: 0,0:01:54.32,0:01:55.05,EN,,0,0,0,,For example-- Dialogue: 0,0:01:55.05,0:01:58.00,EN,,0,0,0,,I'm not saying exactly what Godel's scheme is, Dialogue: 0,0:01:58.00,0:01:59.48,EN,,0,0,0,,because he didn't use words like cons. Dialogue: 0,0:01:59.66,0:02:00.60,EN,,0,0,0,,He had other kinds of Dialogue: 0,0:02:00.91,0:02:02.60,EN,,0,0,0,,of ways of combining to make expressions. Dialogue: 0,0:02:03.09,0:02:03.88,EN,,0,0,0,,But he said, Dialogue: 0,0:02:03.92,0:02:06.81,EN,,0,0,0,,I'm going to assign a number to every algebraic expression. Dialogue: 0,0:02:07.92,0:02:09.72,EN,,0,0,0,,And the way I'm going to manufacture these numbers Dialogue: 0,0:02:09.72,0:02:11.65,EN,,0,0,0,,is by combining the numbers of the parts. Dialogue: 0,0:02:12.47,0:02:13.45,EN,,0,0,0,,So for example, Dialogue: 0,0:02:13.62,0:02:15.35,EN,,0,0,0,,what we were doing our world, Dialogue: 0,0:02:15.35,0:02:18.01,EN,,0,0,0,,we could say that if objects Dialogue: 0,0:02:20.78,0:02:22.22,EN,,0,0,0,,are represented by numbers, Dialogue: 0,0:02:30.67,0:02:37.93,EN,,0,0,0,,then cons of x and y Dialogue: 0,0:02:38.04,0:02:41.07,EN,,0,0,0,,could be represented by, Dialogue: 0,0:02:41.55,0:02:43.77,EN,,0,0,0,,2 to the x times 3 to the y. Dialogue: 0,0:02:46.13,0:02:48.03,EN,,0,0,0,,Because then we could extract the parts. Dialogue: 0,0:02:49.56,0:02:50.97,EN,,0,0,0,,We could say, for example, Dialogue: 0,0:02:51.18,0:02:55.88,EN,,0,0,0,,that then car of, say, x Dialogue: 0,0:02:56.55,0:03:05.18,EN,,0,0,0,,is the number of factors of 2 in x. Dialogue: 0,0:03:06.69,0:03:08.78,EN,,0,0,0,,OK? And of course cdr is the same thing. Dialogue: 0,0:03:10.69,0:03:15.57,EN,,0,0,0,,It's the number of factors of 3 in x. Dialogue: 0,0:03:16.51,0:03:18.65,EN,,0,0,0,,Now this is a perfectly reasonable scheme, Dialogue: 0,0:03:19.10,0:03:20.11,EN,,0,0,0,,except for the fact that Dialogue: 0,0:03:20.12,0:03:22.52,EN,,0,0,0,,the numbers rapidly get to be much larger Dialogue: 0,0:03:22.83,0:03:23.98,EN,,0,0,0,,in number of digits Dialogue: 0,0:03:24.32,0:03:26.55,EN,,0,0,0,,than the number of protons in the universe. Dialogue: 0,0:03:27.95,0:03:29.88,EN,,0,0,0,,So there's no easy way to use this scheme Dialogue: 0,0:03:29.90,0:03:31.21,EN,,0,0,0,,other than the theoretical one. Dialogue: 0,0:03:33.43,0:03:34.48,EN,,0,0,0,,On the other hand, Dialogue: 0,0:03:35.12,0:03:37.55,EN,,0,0,0,,there are other ways of representing these things. Dialogue: 0,0:03:38.45,0:03:40.01,EN,,0,0,0,,We have been thinking in terms Dialogue: 0,0:03:40.25,0:03:42.42,EN,,0,0,0,,of little boxes, boxes. Dialogue: 0,0:03:43.32,0:03:46.43,EN,,0,0,0,,We've been thinking about our cons structures Dialogue: 0,0:03:46.50,0:03:48.05,EN,,0,0,0,,as looking sort of like this. Dialogue: 0,0:03:50.28,0:03:52.57,EN,,0,0,0,,They're little pigeon holes with things in them. Dialogue: 0,0:03:53.56,0:03:55.47,EN,,0,0,0,,And of course we arrange them in little trees. Dialogue: 0,0:03:57.21,0:03:59.97,EN,,0,0,0,,I wish that the semiconductor manufacturers Dialogue: 0,0:03:59.97,0:04:02.07,EN,,0,0,0,,would supply me with something appropriate for this, Dialogue: 0,0:04:02.70,0:04:03.76,EN,,0,0,0,,but actually Dialogue: 0,0:04:03.85,0:04:05.31,EN,,0,0,0,,what they do supply me with Dialogue: 0,0:04:06.20,0:04:07.96,EN,,0,0,0,,is a linear memory. Dialogue: 0,0:04:09.38,0:04:13.46,EN,,0,0,0,,Memory is sort of a big pile of pigeonholes, Dialogue: 0,0:04:15.12,0:04:16.34,EN,,0,0,0,,pigeonholes like this. Dialogue: 0,0:04:17.72,0:04:20.25,EN,,0,0,0,,Each of which can hold a certain sized object, Dialogue: 0,0:04:20.94,0:04:22.20,EN,,0,0,0,,a fixed size object. Dialogue: 0,0:04:23.39,0:04:24.07,EN,,0,0,0,,So, for example, Dialogue: 0,0:04:24.07,0:04:25.66,EN,,0,0,0,,a complicated list with 25 elements Dialogue: 0,0:04:25.66,0:04:26.64,EN,,0,0,0,,won't fit in one of these. Dialogue: 0,0:04:28.55,0:04:29.26,EN,,0,0,0,,However, each of these Dialogue: 0,0:04:29.29,0:04:30.88,EN,,0,0,0,,is indexed by an address. Dialogue: 0,0:04:33.97,0:04:34.99,EN,,0,0,0,,So the address might be Dialogue: 0,0:04:35.02,0:04:35.50,EN,,0,0,0,,zero here, Dialogue: 0,0:04:35.50,0:04:36.22,EN,,0,0,0,,one here, Dialogue: 0,0:04:36.22,0:04:36.70,EN,,0,0,0,,two here, Dialogue: 0,0:04:36.70,0:04:37.25,EN,,0,0,0,,three here, Dialogue: 0,0:04:37.25,0:04:37.94,EN,,0,0,0,,and so on. Dialogue: 0,0:04:38.06,0:04:40.40,EN,,0,0,0,,That we write these down as numbers is unimportant. Dialogue: 0,0:04:40.40,0:04:41.68,EN,,0,0,0,,What matters is that they're distinct Dialogue: 0,0:04:41.95,0:04:43.42,EN,,0,0,0,,as a way to get to the next one. Dialogue: 0,0:04:44.97,0:04:46.14,EN,,0,0,0,,And inside of each of these, Dialogue: 0,0:04:46.36,0:04:49.11,EN,,0,0,0,,we can stuff something into these pigeonholes. Dialogue: 0,0:04:49.53,0:04:50.77,EN,,0,0,0,,That's what memory is like, Dialogue: 0,0:04:51.02,0:04:53.66,EN,,0,0,0,,for those of you who haven't built a computer. Dialogue: 0,0:04:54.15,0:04:54.65,EN,,0,0,0,,Now. Dialogue: 0,0:04:56.69,0:04:57.53,EN,,0,0,0,,Now the problem is Dialogue: 0,0:04:57.53,0:04:59.97,EN,,0,0,0,,how are we going to impose on this type of structure, Dialogue: 0,0:05:00.42,0:05:01.72,EN,,0,0,0,,this nice tree structure. Dialogue: 0,0:05:03.29,0:05:04.57,EN,,0,0,0,,Well it's not very hard, Dialogue: 0,0:05:04.57,0:05:06.35,EN,,0,0,0,,and there have been numerous schemes involved in this. Dialogue: 0,0:05:06.87,0:05:08.80,EN,,0,0,0,,The most important one is to say, Dialogue: 0,0:05:08.80,0:05:11.18,EN,,0,0,0,,well assuming that the semiconductor manufacturer Dialogue: 0,0:05:11.20,0:05:13.90,EN,,0,0,0,,allows me to arrange my memory Dialogue: 0,0:05:13.98,0:05:15.77,EN,,0,0,0,,so that one of these pigeonholes is big enough Dialogue: 0,0:05:16.28,0:05:18.20,EN,,0,0,0,,to hold the address of another Dialogue: 0,0:05:19.35,0:05:20.83,EN,,0,0,0,,OK. I have been made. Dialogue: 0,0:05:22.05,0:05:23.45,EN,,0,0,0,,Now it actually has to be a little bit bigger Dialogue: 0,0:05:23.48,0:05:27.52,EN,,0,0,0,,because I have to also install or store some information Dialogue: 0,0:05:27.56,0:05:30.09,EN,,0,0,0,,as to a tag which describes the kind of thing that's there. Dialogue: 0,0:05:30.39,0:05:31.64,EN,,0,0,0,,And we'll see that in a second. Dialogue: 0,0:05:32.62,0:05:34.40,EN,,0,0,0,,And of course if the semiconductor manufacturer Dialogue: 0,0:05:34.43,0:05:35.88,EN,,0,0,0,,doesn't arrange it so I can do that, Dialogue: 0,0:05:36.08,0:05:38.44,EN,,0,0,0,,then of course I can, with some cleverness, Dialogue: 0,0:05:38.57,0:05:41.82,EN,,0,0,0,,arrange combinations of these to fit together in that way. Dialogue: 0,0:05:43.77,0:05:47.05,EN,,0,0,0,,So we're going to have to imagine Dialogue: 0,0:05:47.05,0:05:49.54,EN,,0,0,0,,imposing this complicated tree structure Dialogue: 0,0:05:49.54,0:05:51.20,EN,,0,0,0,,on our nice linear memory. Dialogue: 0,0:05:51.74,0:05:54.47,EN,,0,0,0,,If we look at the first still store, Dialogue: 0,0:05:54.47,0:05:58.30,EN,,0,0,0,,we see a classic scheme for doing that. Dialogue: 0,0:05:59.49,0:06:02.62,EN,,0,0,0,,It's a standard way of representing list structures Dialogue: 0,0:06:03.22,0:06:05.87,EN,,0,0,0,,in a linear memory. Dialogue: 0,0:06:06.27,0:06:08.32,EN,,0,0,0,,What we do is we divide this memory Dialogue: 0,0:06:08.88,0:06:11.12,EN,,0,0,0,,into two parts. Dialogue: 0,0:06:12.03,0:06:13.42,EN,,0,0,0,,An array called the cars, Dialogue: 0,0:06:14.45,0:06:15.88,EN,,0,0,0,,and an array called the cdrs. Dialogue: 0,0:06:17.58,0:06:18.86,EN,,0,0,0,,Now whether those happen to be Dialogue: 0,0:06:18.88,0:06:21.04,EN,,0,0,0,,sequential addresses or whatever, Dialogue: 0,0:06:21.12,0:06:22.00,EN,,0,0,0,,it's not important. Dialogue: 0,0:06:22.87,0:06:25.20,EN,,0,0,0,,That's somebody's implementation details. Dialogue: 0,0:06:25.80,0:06:28.40,EN,,0,0,0,,But there are two arrays here. Dialogue: 0,0:06:28.96,0:06:30.36,EN,,0,0,0,,Linear arrays indexed Dialogue: 0,0:06:30.46,0:06:32.59,EN,,0,0,0,,by sequential indices like this. Dialogue: 0,0:06:34.84,0:06:36.85,EN,,0,0,0,,What is stored in each of these pigeonholes Dialogue: 0,0:06:37.46,0:06:39.85,EN,,0,0,0,,is a typed object. Dialogue: 0,0:06:41.43,0:06:42.57,EN,,0,0,0,,And what we have here Dialogue: 0,0:06:42.57,0:06:45.71,EN,,0,0,0,,are types which begin with letters like p, Dialogue: 0,0:06:45.71,0:06:46.57,EN,,0,0,0,,standing for a pair. Dialogue: 0,0:06:47.79,0:06:49.37,EN,,0,0,0,,Or n, standing for a number. Dialogue: 0,0:06:50.04,0:06:52.25,EN,,0,0,0,,Or e, standing for an empty list. Dialogue: 0,0:06:54.81,0:06:55.83,EN,,0,0,0,,The end of the list. Dialogue: 0,0:06:57.02,0:06:58.59,EN,,0,0,0,,And so if we wish to represent Dialogue: 0,0:06:58.99,0:06:59.97,EN,,0,0,0,,an object like this, Dialogue: 0,0:07:00.01,0:07:02.16,EN,,0,0,0,,the list beginning with 1, 2 Dialogue: 0,0:07:02.65,0:07:04.01,EN,,0,0,0,,and then having a 3 and a 4 Dialogue: 0,0:07:04.01,0:07:05.50,EN,,0,0,0,,and then having a 3 and a 4 as its second and third elements. Dialogue: 0,0:07:06.43,0:07:08.83,EN,,0,0,0,,A list containing a list as its first part Dialogue: 0,0:07:09.35,0:07:10.65,EN,,0,0,0,,and then two numbers Dialogue: 0,0:07:10.65,0:07:12.00,EN,,0,0,0,,as a second and third parts. Dialogue: 0,0:07:12.87,0:07:14.81,EN,,0,0,0,,Then of course we draw it sort of like this these days, Dialogue: 0,0:07:14.84,0:07:16.67,EN,,0,0,0,,in box-and-pointer notation. Dialogue: 0,0:07:17.32,0:07:18.00,EN,,0,0,0,,And you see, Dialogue: 0,0:07:18.00,0:07:20.04,EN,,0,0,0,,these are the three cells Dialogue: 0,0:07:20.25,0:07:22.01,EN,,0,0,0,,that have as their car pointer Dialogue: 0,0:07:22.27,0:07:27.10,EN,,0,0,0,,the object which is either 1, 2 or 3 or 4. Dialogue: 0,0:07:28.39,0:07:29.75,EN,,0,0,0,,And then of course the 1, 2, Dialogue: 0,0:07:29.75,0:07:31.32,EN,,0,0,0,,the car of this entire structure, Dialogue: 0,0:07:31.32,0:07:32.65,EN,,0,0,0,,is itself a substructure Dialogue: 0,0:07:32.88,0:07:34.75,EN,,0,0,0,,which contains a sublist like that. Dialogue: 0,0:07:35.94,0:07:37.07,EN,,0,0,0,,What I'm about to do Dialogue: 0,0:07:37.20,0:07:39.92,EN,,0,0,0,,is put down places which are-- Dialogue: 0,0:07:39.95,0:07:41.46,EN,,0,0,0,,I'm going to assign indices. Dialogue: 0,0:07:41.84,0:07:43.40,EN,,0,0,0,,Like this 1, over here, Dialogue: 0,0:07:43.56,0:07:47.05,EN,,0,0,0,,represents the index of this cell. Dialogue: 0,0:07:49.85,0:07:51.47,EN,,0,0,0,,But that pointer that we see here Dialogue: 0,0:07:52.37,0:07:54.86,EN,,0,0,0,,is a reference to the Dialogue: 0,0:07:55.07,0:07:57.29,EN,,0,0,0,,pair of pigeonholes in the cars and the cdrs Dialogue: 0,0:07:57.40,0:07:58.67,EN,,0,0,0,,that are labeled by 1 Dialogue: 0,0:07:58.76,0:08:00.33,EN,,0,0,0,,in my linear memory down here. Dialogue: 0,0:08:02.00,0:08:04.06,EN,,0,0,0,,So if I wish to impose this structure Dialogue: 0,0:08:04.16,0:08:05.26,EN,,0,0,0,,on my linear memory, Dialogue: 0,0:08:05.85,0:08:07.52,EN,,0,0,0,,what I do is I say, oh yes, Dialogue: 0,0:08:07.52,0:08:11.88,EN,,0,0,0,,why don't we drop this into cell 1? Dialogue: 0,0:08:11.95,0:08:12.66,EN,,0,0,0,,Well I said, I pick 1. Dialogue: 0,0:08:12.66,0:08:13.85,EN,,0,0,0,,There's 1. OK? Dialogue: 0,0:08:14.27,0:08:16.22,EN,,0,0,0,,And that says that its car, Dialogue: 0,0:08:16.22,0:08:17.74,EN,,0,0,0,,I'm going to assign it to be a pair. Dialogue: 0,0:08:17.95,0:08:18.72,EN,,0,0,0,,It's a pair, Dialogue: 0,0:08:20.02,0:08:21.55,EN,,0,0,0,,which is in index 5. Dialogue: 0,0:08:22.59,0:08:23.90,EN,,0,0,0,,And the cdr, Dialogue: 0,0:08:23.90,0:08:25.13,EN,,0,0,0,,which is this one over here, Dialogue: 0,0:08:25.39,0:08:26.13,EN,,0,0,0,,is a pair Dialogue: 0,0:08:26.13,0:08:27.70,EN,,0,0,0,,which I'm going to stick into place 2. Dialogue: 0,0:08:28.34,0:08:28.98,EN,,0,0,0,,p2. Dialogue: 0,0:08:30.89,0:08:32.95,EN,,0,0,0,,And take a look at p2. Dialogue: 0,0:08:32.95,0:08:34.72,EN,,0,0,0,,Oh yes, well p2 is a thing Dialogue: 0,0:08:34.90,0:08:37.22,EN,,0,0,0,,whose car is the number 3, Dialogue: 0,0:08:37.34,0:08:38.64,EN,,0,0,0,,so as you see, an n3. Dialogue: 0,0:08:39.52,0:08:41.52,EN,,0,0,0,,And whose cdr, over here, Dialogue: 0,0:08:41.72,0:08:43.40,EN,,0,0,0,,is a pair, Dialogue: 0,0:08:43.97,0:08:45.81,EN,,0,0,0,,which lives in place 4. Dialogue: 0,0:08:46.64,0:08:47.79,EN,,0,0,0,,So that's what this p4 is. Dialogue: 0,0:08:48.65,0:08:51.16,EN,,0,0,0,,p4 is a number Dialogue: 0,0:08:51.85,0:08:53.87,EN,,0,0,0,,whose value is 4 in its car Dialogue: 0,0:08:54.60,0:08:55.65,EN,,0,0,0,,and whose cdr Dialogue: 0,0:08:55.84,0:08:58.48,EN,,0,0,0,,is an empty list right there. Dialogue: 0,0:08:59.17,0:08:59.90,EN,,0,0,0,,And that ends it. Dialogue: 0,0:09:00.69,0:09:04.57,EN,,0,0,0,,So this is the traditional way of representing Dialogue: 0,0:09:04.90,0:09:09.55,EN,,0,0,0,,this kind of binary tree in a linear memory. Dialogue: 0,0:09:11.62,0:09:15.10,EN,,0,0,0,,Now the next question, of course, Dialogue: 0,0:09:15.10,0:09:16.36,EN,,0,0,0,,that we might want to worry about Dialogue: 0,0:09:16.60,0:09:18.19,EN,,0,0,0,,is just a little bit of implementation. Dialogue: 0,0:09:18.44,0:09:20.33,EN,,0,0,0,,That means that when I write procedures Dialogue: 0,0:09:20.36,0:09:23.62,EN,,0,0,0,,of the form assigned a, Dialogue: 0,0:09:24.54,0:09:27.10,EN,,0,0,0,,lines of register machine code Dialogue: 0,0:09:27.21,0:09:30.14,EN,,0,0,0,,of the form assigned a, the car of fetch of b, Dialogue: 0,0:09:30.84,0:09:31.85,EN,,0,0,0,,what I really mean Dialogue: 0,0:09:31.97,0:09:37.10,EN,,0,0,0,,is addressing these elements. Dialogue: 0,0:09:38.74,0:09:40.25,EN,,0,0,0,,And so we're going to think of that as Dialogue: 0,0:09:40.68,0:09:42.94,EN,,0,0,0,,a abbreviation for it. Dialogue: 0,0:09:44.47,0:09:46.33,EN,,0,0,0,,Now of course in order to write that down Dialogue: 0,0:09:46.35,0:09:48.59,EN,,0,0,0,,I'm going to introduce some sort of a structure Dialogue: 0,0:09:48.62,0:09:49.42,EN,,0,0,0,,called a vector. Dialogue: 0,0:09:52.12,0:09:53.31,EN,,0,0,0,,And we're going to have something which will Dialogue: 0,0:09:53.48,0:09:54.54,EN,,0,0,0,,reference a vector, Dialogue: 0,0:09:56.84,0:09:58.51,EN,,0,0,0,,just so we can write it down. Dialogue: 0,0:09:58.71,0:10:00.22,EN,,0,0,0,,Which takes the name of the vector, Dialogue: 0,0:10:01.02,0:10:03.97,EN,,0,0,0,,or the-- I don't think that name is the right word. Dialogue: 0,0:10:03.97,0:10:09.40,EN,,0,0,0,,Which takes the vector and the index, Dialogue: 0,0:10:11.20,0:10:13.05,EN,,0,0,0,,and I have to have a way of setting one of those Dialogue: 0,0:10:13.10,0:10:14.27,EN,,0,0,0,,with something called a vector set, Dialogue: 0,0:10:14.65,0:10:15.60,EN,,0,0,0,,I don't really care. Dialogue: 0,0:10:16.28,0:10:17.55,EN,,0,0,0,,But let's look, for example, Dialogue: 0,0:10:18.11,0:10:20.42,EN,,0,0,0,,at then that kind of implementation Dialogue: 0,0:10:21.25,0:10:23.18,EN,,0,0,0,,of car and cdr. Dialogue: 0,0:10:26.47,0:10:28.41,EN,,0,0,0,,So for example if I happen to have Dialogue: 0,0:10:28.88,0:10:30.80,EN,,0,0,0,,a register b, Dialogue: 0,0:10:31.15,0:10:34.64,EN,,0,0,0,,which contains the type index of a pair, Dialogue: 0,0:10:35.95,0:10:38.80,EN,,0,0,0,,and therefore it is the pointer to a pair, Dialogue: 0,0:10:39.35,0:10:40.85,EN,,0,0,0,,then I could take the car of that and Dialogue: 0,0:10:41.55,0:10:44.11,EN,,0,0,0,,OK if I-- write this down-- I might put that in register a. Dialogue: 0,0:10:44.49,0:10:46.86,EN,,0,0,0,,What that really is is a representation of Dialogue: 0,0:10:47.37,0:10:50.19,EN,,0,0,0,,the assign to a, Dialogue: 0,0:10:50.19,0:10:51.92,EN,,0,0,0,,the value of vector reffing-- Dialogue: 0,0:10:52.80,0:10:55.24,EN,,0,0,0,,or array indexing, if you will-- or something, Dialogue: 0,0:10:55.42,0:10:57.63,EN,,0,0,0,,the cars object-- Dialogue: 0,0:10:58.40,0:11:00.92,EN,,0,0,0,,whatever that is-- with the index, b. Dialogue: 0,0:11:02.65,0:11:03.63,EN,,0,0,0,,And similarly for cdr. Dialogue: 0,0:11:04.10,0:11:05.72,EN,,0,0,0,,And we can do the same thing Dialogue: 0,0:11:05.90,0:11:08.32,EN,,0,0,0,,for assignment to data structures, Dialogue: 0,0:11:08.92,0:11:10.92,EN,,0,0,0,,If we need to do that sort of things at all. Dialogue: 0,0:11:11.84,0:11:13.80,EN,,0,0,0,,It's not too hard to build that. Dialogue: 0,0:11:14.58,0:11:15.72,EN,,0,0,0,,Well now the next question is Dialogue: 0,0:11:15.72,0:11:17.00,EN,,0,0,0,,how are we going to do allocation. Dialogue: 0,0:11:18.01,0:11:20.13,EN,,0,0,0,,And every so often I say I want a cons. Dialogue: 0,0:11:21.40,0:11:23.42,EN,,0,0,0,,Now conses don't grow on trees. Dialogue: 0,0:11:23.79,0:11:24.81,EN,,0,0,0,,Or maybe they should. Dialogue: 0,0:11:25.34,0:11:26.56,EN,,0,0,0,,But I have to have some way Dialogue: 0,0:11:26.70,0:11:28.97,EN,,0,0,0,,I have to have some way of getting the next one. Dialogue: 0,0:11:29.98,0:11:31.47,EN,,0,0,0,,I have to have some idea of Dialogue: 0,0:11:31.47,0:11:33.04,EN,,0,0,0,,if their memory is unused Dialogue: 0,0:11:33.69,0:11:35.05,EN,,0,0,0,,that I might want to allocate from. Dialogue: 0,0:11:35.63,0:11:37.38,EN,,0,0,0,,And there are many schemes for doing this. Dialogue: 0,0:11:37.38,0:11:39.07,EN,,0,0,0,,And the particular thing I'm showing you right now Dialogue: 0,0:11:39.23,0:11:40.45,EN,,0,0,0,,is not essential. Dialogue: 0,0:11:42.10,0:11:43.18,EN,,0,0,0,,However it's convenient Dialogue: 0,0:11:43.20,0:11:44.44,EN,,0,0,0,,and has been done many times. Dialogue: 0,0:11:44.60,0:11:47.20,EN,,0,0,0,,It's one schemes called the free list allocation scheme. Dialogue: 0,0:11:47.66,0:11:48.68,EN,,0,0,0,,What that means is Dialogue: 0,0:11:48.68,0:11:51.12,EN,,0,0,0,,that all of the free memory that there is in the world Dialogue: 0,0:11:51.55,0:11:53.08,EN,,0,0,0,,is linked together in a linked list, Dialogue: 0,0:11:54.55,0:11:56.22,EN,,0,0,0,,just like all the other stuff. Dialogue: 0,0:11:56.96,0:11:59.07,EN,,0,0,0,,And whenever you need a free cell Dialogue: 0,0:11:59.07,0:12:00.12,EN,,0,0,0,,to make a new cons, Dialogue: 0,0:12:00.95,0:12:02.26,EN,,0,0,0,,you grab the first one Dialogue: 0,0:12:02.26,0:12:03.82,EN,,0,0,0,,make the free list be the cdr of it, Dialogue: 0,0:12:04.32,0:12:05.55,EN,,0,0,0,,and then allocate that. Dialogue: 0,0:12:06.03,0:12:08.32,EN,,0,0,0,,And so what that looks like is something like this. Dialogue: 0,0:12:09.53,0:12:13.32,EN,,0,0,0,,Here we have the free list Dialogue: 0,0:12:13.95,0:12:16.81,EN,,0,0,0,,starting in 6. Dialogue: 0,0:12:18.51,0:12:23.47,EN,,0,0,0,,And what that is is a pointer-off to say 8. Dialogue: 0,0:12:24.86,0:12:25.62,EN,,0,0,0,,So what it says is, Dialogue: 0,0:12:25.62,0:12:26.55,EN,,0,0,0,,this one is free Dialogue: 0,0:12:26.55,0:12:27.95,EN,,0,0,0,,and the next one is an 8. Dialogue: 0,0:12:28.87,0:12:29.88,EN,,0,0,0,,This one is free Dialogue: 0,0:12:30.04,0:12:32.08,EN,,0,0,0,,and the next one is in 3, Dialogue: 0,0:12:32.32,0:12:33.45,EN,,0,0,0,,the next one that's free. Dialogue: 0,0:12:33.93,0:12:34.95,EN,,0,0,0,,That one's free Dialogue: 0,0:12:35.04,0:12:37.68,EN,,0,0,0,,and the next one is in 0. Dialogue: 0,0:12:37.87,0:12:38.49,EN,,0,0,0,,That one's free Dialogue: 0,0:12:38.52,0:12:39.82,EN,,0,0,0,,and the next one's in 15. Dialogue: 0,0:12:40.94,0:12:41.84,EN,,0,0,0,,Something like that. Dialogue: 0,0:12:42.78,0:12:44.64,EN,,0,0,0,,We can imagine having such a structure. Dialogue: 0,0:12:46.40,0:12:48.03,EN,,0,0,0,,Given that we have something like that, Dialogue: 0,0:12:49.45,0:12:50.92,EN,,0,0,0,,then it's possible to Dialogue: 0,0:12:50.92,0:12:52.22,EN,,0,0,0,,just get one when you need it. Dialogue: 0,0:12:53.82,0:12:56.46,EN,,0,0,0,,And so a program for doing cons, Dialogue: 0,0:12:57.45,0:12:59.13,EN,,0,0,0,,this is what cons might turn into. Dialogue: 0,0:12:59.32,0:13:02.57,EN,,0,0,0,,To assign to a register A the result of cons-ing, Dialogue: 0,0:13:02.95,0:13:05.82,EN,,0,0,0,,a B onto C, Dialogue: 0,0:13:06.20,0:13:09.04,EN,,0,0,0,,the value in this containing B and the value containing C, Dialogue: 0,0:13:09.27,0:13:10.52,EN,,0,0,0,,what we have to do is Dialogue: 0,0:13:10.56,0:13:12.24,EN,,0,0,0,,get the current tail ahead of the freelist, Dialogue: 0,0:13:12.47,0:13:14.30,EN,,0,0,0,,make the free list be its cdr. Dialogue: 0,0:13:15.64,0:13:18.33,EN,,0,0,0,,Then we have to change the cars Dialogue: 0,0:13:18.41,0:13:22.49,EN,,0,0,0,,to be the thing we're making up to be in A Dialogue: 0,0:13:23.13,0:13:25.45,EN,,0,0,0,,to be the B, the thing in B. Dialogue: 0,0:13:25.90,0:13:28.65,EN,,0,0,0,,And we have to make change the cdrs of Dialogue: 0,0:13:29.20,0:13:31.72,EN,,0,0,0,,the thing that's in A to be C. Dialogue: 0,0:13:33.20,0:13:34.76,EN,,0,0,0,,And then what we have in A Dialogue: 0,0:13:34.78,0:13:36.65,EN,,0,0,0,,is the right new frob, whatever it is. Dialogue: 0,0:13:36.81,0:13:37.92,EN,,0,0,0,,The object that we want. Dialogue: 0,0:13:40.47,0:13:42.50,EN,,0,0,0,,Now there's a little bit of Dialogue: 0,0:13:42.50,0:13:43.97,EN,,0,0,0,,a cheat here that I haven't told you about, Dialogue: 0,0:13:43.97,0:13:45.32,EN,,0,0,0,,which is somewhere around here Dialogue: 0,0:13:45.53,0:13:47.32,EN,,0,0,0,,I haven't set the type of the thing that I've Dialogue: 0,0:13:48.45,0:13:50.48,EN,,0,0,0,,the type of the thing Dialogue: 0,0:13:50.51,0:13:51.87,EN,,0,0,0,,that I'm cons-ing up to be a pair, Dialogue: 0,0:13:52.30,0:13:53.05,EN,,0,0,0,,and I ought to. Dialogue: 0,0:13:53.51,0:13:56.57,EN,,0,0,0,,So there should be some sort of bits here are being set, Dialogue: 0,0:13:56.60,0:13:57.76,EN,,0,0,0,,and I just haven't written that down. Dialogue: 0,0:13:59.81,0:14:00.86,EN,,0,0,0,,We could have arranged it, of course, Dialogue: 0,0:14:00.89,0:14:02.45,EN,,0,0,0,,for the free list to be made out of pairs. Dialogue: 0,0:14:03.10,0:14:04.88,EN,,0,0,0,,And so then there's no problem with that. Dialogue: 0,0:14:06.43,0:14:07.74,EN,,0,0,0,,But that sort of-- Dialogue: 0,0:14:07.82,0:14:09.92,EN,,0,0,0,,again, an inessential detail in a way Dialogue: 0,0:14:10.22,0:14:12.88,EN,,0,0,0,,some particular programmer or architect Dialogue: 0,0:14:12.92,0:14:14.27,EN,,0,0,0,,or whatever might manufacture Dialogue: 0,0:14:14.33,0:14:16.68,EN,,0,0,0,,his machine or Lisp system. Dialogue: 0,0:14:17.54,0:14:18.71,EN,,0,0,0,,So for example, Dialogue: 0,0:14:19.07,0:14:20.24,EN,,0,0,0,,just looking at this, Dialogue: 0,0:14:20.65,0:14:23.45,EN,,0,0,0,,to allocate Dialogue: 0,0:14:23.55,0:14:26.83,EN,,0,0,0,,given that I had already the structure that you saw before, Dialogue: 0,0:14:27.21,0:14:30.26,EN,,0,0,0,,supposing I wanted to allocate a new cell, Dialogue: 0,0:14:30.55,0:14:36.61,EN,,0,0,0,,which is going to be representation of list one, one, two, Dialogue: 0,0:14:37.24,0:14:39.87,EN,,0,0,0,,where already one two was the car Dialogue: 0,0:14:40.28,0:14:42.16,EN,,0,0,0,,of the list we were playing with before. Dialogue: 0,0:14:43.43,0:14:44.45,EN,,0,0,0,,Well that's not so hard. Dialogue: 0,0:14:44.78,0:14:46.20,EN,,0,0,0,,I stored that one in one, Dialogue: 0,0:14:46.20,0:14:49.17,EN,,0,0,0,,so p1 one is the representation of this. Dialogue: 0,0:14:49.53,0:14:50.83,EN,,0,0,0,,This is p5. Dialogue: 0,0:14:51.67,0:14:53.51,EN,,0,0,0,,That's going to be the cdr of this. Dialogue: 0,0:14:54.07,0:14:55.52,EN,,0,0,0,,Now we're going to pull something off the free list, Dialogue: 0,0:14:55.52,0:14:57.30,EN,,0,0,0,,but remember the free list started at six. Dialogue: 0,0:14:57.78,0:15:00.18,EN,,0,0,0,,The new free list after this allocation is eight, Dialogue: 0,0:15:00.60,0:15:02.55,EN,,0,0,0,,a free list beginning at eight. Dialogue: 0,0:15:02.89,0:15:03.52,EN,,0,0,0,,And of course Dialogue: 0,0:15:03.72,0:15:06.04,EN,,0,0,0,,in six now we have a number one, Dialogue: 0,0:15:06.15,0:15:07.10,EN,,0,0,0,,which is what we wanted, Dialogue: 0,0:15:07.39,0:15:11.56,EN,,0,0,0,,with its cdr being the pair starting in location five. Dialogue: 0,0:15:13.33,0:15:14.50,EN,,0,0,0,,And that's no big deal. Dialogue: 0,0:15:16.81,0:15:20.45,EN,,0,0,0,,So the only problem really remaining here is, Dialogue: 0,0:15:21.00,0:15:23.40,EN,,0,0,0,,well, I don't have an infinitely large memory. Dialogue: 0,0:15:25.08,0:15:26.66,EN,,0,0,0,,If I do this for a little while, Dialogue: 0,0:15:27.25,0:15:28.00,EN,,0,0,0,,say, for example, Dialogue: 0,0:15:28.01,0:15:30.14,EN,,0,0,0,,supposing it takes me a microsecond to do a cons, Dialogue: 0,0:15:30.60,0:15:32.97,EN,,0,0,0,,and I have a million cons memory Dialogue: 0,0:15:33.60,0:15:35.27,EN,,0,0,0,,then I'm only going to run out in a second, Dialogue: 0,0:15:35.95,0:15:37.00,EN,,0,0,0,,and that's pretty bad. Dialogue: 0,0:15:38.00,0:15:40.62,EN,,0,0,0,,So what we do to prevent that disaster, Dialogue: 0,0:15:40.62,0:15:42.19,EN,,0,0,0,,that ecological disaster, Dialogue: 0,0:15:42.60,0:15:44.30,EN,,0,0,0,,talk about right after questions. Dialogue: 0,0:15:44.30,0:15:45.26,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:15:51.50,0:15:51.69,EN,,0,0,0,,Yes. Dialogue: 0,0:15:52.03,0:15:54.67,EN,,0,0,0,,AUDIENCE: In the environment diagrams that we were drawing Dialogue: 0,0:15:54.67,0:15:58.25,EN,,0,0,0,,we would use the body of procedures, Dialogue: 0,0:15:58.25,0:16:00.67,EN,,0,0,0,,and you would eventually wind up with Dialogue: 0,0:16:00.80,0:16:03.60,EN,,0,0,0,,things that were no longer useful in that structure. Dialogue: 0,0:16:03.60,0:16:04.16,EN,,0,0,0,,PROFESSOR: Yes, madam. Dialogue: 0,0:16:04.93,0:16:06.67,EN,,0,0,0,,AUDIENCE: How is that represented? Dialogue: 0,0:16:06.76,0:16:08.75,EN,,0,0,0,,PROFESSOR: There's two problems here. OK? Dialogue: 0,0:16:09.18,0:16:10.25,EN,,0,0,0,,One you were asking Dialogue: 0,0:16:10.25,0:16:13.43,EN,,0,0,0,,is that material becomes useless. Dialogue: 0,0:16:13.87,0:16:14.92,EN,,0,0,0,,We'll talk about that in a second. Dialogue: 0,0:16:14.92,0:16:17.00,EN,,0,0,0,,That has to do with how to prevent ecological disasters. Dialogue: 0,0:16:17.63,0:16:19.20,EN,,0,0,0,,Right? If I make a lot of garbage Dialogue: 0,0:16:19.20,0:16:21.39,EN,,0,0,0,,I have to somehow be able to clean up after myself. Dialogue: 0,0:16:21.82,0:16:22.97,EN,,0,0,0,,And we'll talk about that in a second. Dialogue: 0,0:16:23.43,0:16:24.57,EN,,0,0,0,,The other question you're asking Dialogue: 0,0:16:24.57,0:16:27.21,EN,,0,0,0,,is how you represent the environments, I think. Dialogue: 0,0:16:27.28,0:16:27.60,EN,,0,0,0,,AUDIENCE: Yes. Dialogue: 0,0:16:27.60,0:16:28.19,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:16:28.19,0:16:30.62,EN,,0,0,0,,And the environment structures can be represented in arbitrary ways. Dialogue: 0,0:16:30.92,0:16:31.78,EN,,0,0,0,,There are lots of them. Dialogue: 0,0:16:31.78,0:16:33.34,EN,,0,0,0,,I mean, here I'm just telling you about list cells. Dialogue: 0,0:16:33.63,0:16:34.92,EN,,0,0,0,,Of course every real system Dialogue: 0,0:16:34.92,0:16:36.72,EN,,0,0,0,,has vectors of arbitrary length Dialogue: 0,0:16:36.72,0:16:39.15,EN,,0,0,0,,as well as the vectors of length, too, Dialogue: 0,0:16:39.31,0:16:40.51,EN,,0,0,0,,which represent list cells. Dialogue: 0,0:16:41.08,0:16:44.90,EN,,0,0,0,,And the environment structures that one uses in a Dialogue: 0,0:16:44.90,0:16:46.99,EN,,0,0,0,,professionally written Lisp system Dialogue: 0,0:16:47.30,0:16:49.69,EN,,0,0,0,,tend to be vectors Dialogue: 0,0:16:49.69,0:16:51.92,EN,,0,0,0,,which contain a number of elements approximately Dialogue: 0,0:16:51.92,0:16:54.60,EN,,0,0,0,,equal to the number of arguments-- a little bit more Dialogue: 0,0:16:55.35,0:16:56.86,EN,,0,0,0,,because you need sort of glue. Dialogue: 0,0:16:57.40,0:17:00.74,EN,,0,0,0,,OK? So remember, the environment is in a frame. Dialogue: 0,0:17:00.74,0:17:03.98,EN,,0,0,0,,The frames are constructed by applying a procedure. Dialogue: 0,0:17:03.98,0:17:04.78,EN,,0,0,0,,In doing so, Dialogue: 0,0:17:04.80,0:17:07.60,EN,,0,0,0,,an allocation is made of a place Dialogue: 0,0:17:07.64,0:17:11.27,EN,,0,0,0,,which is the number of arguments long plus some glue Dialogue: 0,0:17:11.27,0:17:12.71,EN,,0,0,0,,that gets linked into a chain. Dialogue: 0,0:17:13.32,0:17:15.66,EN,,0,0,0,,It's just like algol at that level. Dialogue: 0,0:17:19.81,0:17:20.72,EN,,0,0,0,,There any other questions? Dialogue: 0,0:17:23.70,0:17:23.92,EN,,0,0,0,,OK. Dialogue: 0,0:17:23.92,0:17:25.55,EN,,0,0,0,,Thank you, and let's take a short break. Dialogue: 0,0:17:26.35,0:17:45.48,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:18:12.27,0:18:14.24,EN,,0,0,0,,PROFESSOR: Well, as I just said, Dialogue: 0,0:18:14.55,0:18:15.50,EN,,0,0,0,,computer memories Dialogue: 0,0:18:15.82,0:18:17.96,EN,,0,0,0,,supplied by the semiconductor manufacturers Dialogue: 0,0:18:18.16,0:18:19.00,EN,,0,0,0,,are finite. Dialogue: 0,0:18:19.42,0:18:20.40,EN,,0,0,0,,And that's quite a pity. Dialogue: 0,0:18:21.62,0:18:23.35,EN,,0,0,0,,It might not always be that way. Dialogue: 0,0:18:24.03,0:18:25.40,EN,,0,0,0,,Just for a quick calculation, Dialogue: 0,0:18:25.44,0:18:28.86,EN,,0,0,0,,you can see that it's possible that if memory's Dialogue: 0,0:18:28.86,0:18:30.80,EN,,0,0,0,,prices keep going at the rate they're going Dialogue: 0,0:18:31.22,0:18:33.68,EN,,0,0,0,,that if you still took a microsecond second to do a cons, Dialogue: 0,0:18:34.42,0:18:35.90,EN,,0,0,0,,then-- first of all, everybody Dialogue: 0,0:18:35.90,0:18:37.07,EN,,0,0,0,,should know that there's about pi Dialogue: 0,0:18:37.10,0:18:38.86,EN,,0,0,0,,times ten to the seventh seconds in a year. Dialogue: 0,0:18:39.45,0:18:41.12,EN,,0,0,0,,And so that would be Dialogue: 0,0:18:41.50,0:18:42.73,EN,,0,0,0,,ten to the seventh plus ten to the sixth Dialogue: 0,0:18:42.73,0:18:43.94,EN,,0,0,0,,is ten to the thirteenth. Dialogue: 0,0:18:43.94,0:18:45.50,EN,,0,0,0,,So there's maybe ten to the fourteenth conses Dialogue: 0,0:18:45.50,0:18:46.80,EN,,0,0,0,,in the life of a machine. Dialogue: 0,0:18:47.52,0:18:49.40,EN,,0,0,0,,If there was ten to the fourteenth words of memory Dialogue: 0,0:18:49.68,0:18:50.57,EN,,0,0,0,,on your machine, Dialogue: 0,0:18:51.20,0:18:52.16,EN,,0,0,0,,you'd never run out. Dialogue: 0,0:18:53.04,0:18:53.85,EN,,0,0,0,,OK so that will be, Dialogue: 0,0:18:53.95,0:18:55.76,EN,,0,0,0,,And that's not completely unreasonable. Dialogue: 0,0:18:56.31,0:18:58.46,EN,,0,0,0,,Ten to the fourteenth is not a very large number. Dialogue: 0,0:19:01.45,0:19:04.70,EN,,0,0,0,,Even for... I don't think it is. Dialogue: 0,0:19:05.18,0:19:07.39,EN,,0,0,0,,But then again I like to play with astronomy. Dialogue: 0,0:19:07.93,0:19:11.04,EN,,0,0,0,,It's at least ten to the eighteenth centimeters Dialogue: 0,0:19:11.10,0:19:12.45,EN,,0,0,0,,between us and the nearest star. Dialogue: 0,0:19:12.93,0:19:18.85,EN,,0,0,0,,But the thing I'm about to worry about is, Dialogue: 0,0:19:19.15,0:19:21.27,EN,,0,0,0,,at least in the current economic state of affairs, Dialogue: 0,0:19:21.27,0:19:23.57,EN,,0,0,0,,ten to the fourteenth pieces of memory is expensive. Dialogue: 0,0:19:24.20,0:19:26.62,EN,,0,0,0,,And so I suppose what we have to do Dialogue: 0,0:19:26.81,0:19:28.51,EN,,0,0,0,,is make do with much smaller memories. Dialogue: 0,0:19:30.02,0:19:30.59,EN,,0,0,0,,Now Dialogue: 0,0:19:32.84,0:19:35.07,EN,,0,0,0,,in general we want to have an illusion of infinity. Dialogue: 0,0:19:35.80,0:19:37.22,EN,,0,0,0,,All we need to do is arrange it Dialogue: 0,0:19:37.82,0:19:39.68,EN,,0,0,0,,so that whenever you look, the thing is there. Dialogue: 0,0:19:41.92,0:19:45.55,EN,,0,0,0,,That's, that's really an important idea. Dialogue: 0,0:19:49.54,0:19:51.97,EN,,0,0,0,,A person or a computer lives only a finite amount of time Dialogue: 0,0:19:52.32,0:19:54.59,EN,,0,0,0,,and can only take a finite number of looks at something. Dialogue: 0,0:19:55.28,0:19:57.37,EN,,0,0,0,,And so you really only need a finite amount of stuff. Dialogue: 0,0:19:58.19,0:19:59.00,EN,,0,0,0,,But you have to arrange it Dialogue: 0,0:19:59.00,0:20:00.38,EN,,0,0,0,,so no matter how much there is, Dialogue: 0,0:20:00.77,0:20:03.46,EN,,0,0,0,,how much you really claim there is, Dialogue: 0,0:20:03.46,0:20:04.74,EN,,0,0,0,,there's always enough stuff Dialogue: 0,0:20:04.74,0:20:06.90,EN,,0,0,0,,so that when you take a look, it's there. Dialogue: 0,0:20:06.90,0:20:08.15,EN,,0,0,0,,And so you only need a finite amount. Dialogue: 0,0:20:08.75,0:20:09.94,EN,,0,0,0,,But let's see. Dialogue: 0,0:20:11.63,0:20:13.32,EN,,0,0,0,,One problem is, as was brought up, Dialogue: 0,0:20:13.92,0:20:15.45,EN,,0,0,0,,that there are possible ways Dialogue: 0,0:20:15.72,0:20:17.84,EN,,0,0,0,,that there is lots of stuff Dialogue: 0,0:20:17.88,0:20:19.16,EN,,0,0,0,,that we make that we don't need. Dialogue: 0,0:20:19.41,0:20:21.81,EN,,0,0,0,,And we could recycle the material out of which its made. Dialogue: 0,0:20:22.62,0:20:23.53,EN,,0,0,0,,An example Dialogue: 0,0:20:24.15,0:20:25.79,EN,,0,0,0,,for is, is the fact Dialogue: 0,0:20:25.79,0:20:28.40,EN,,0,0,0,,when we're building environment structures, Dialogue: 0,0:20:28.40,0:20:30.47,EN,,0,0,0,,and we do so every time we call a procedure. Dialogue: 0,0:20:30.47,0:20:32.56,EN,,0,0,0,,We have built in it a environment frame. Dialogue: 0,0:20:33.14,0:20:34.03,EN,,0,0,0,,That environment frame Dialogue: 0,0:20:34.22,0:20:36.07,EN,,0,0,0,,doesn't necessarily have a very long lifetime. Dialogue: 0,0:20:36.73,0:20:38.69,EN,,0,0,0,,Its lifetime, meaning its usefulness, Dialogue: 0,0:20:39.42,0:20:42.60,EN,,0,0,0,,may exist only over the invocation of the procedure. Dialogue: 0,0:20:42.85,0:20:45.27,EN,,0,0,0,,Or if the procedure exports another procedure Dialogue: 0,0:20:45.27,0:20:46.67,EN,,0,0,0,,by returning it as a value Dialogue: 0,0:20:46.87,0:20:48.52,EN,,0,0,0,,and that procedure is defined inside of it, Dialogue: 0,0:20:48.52,0:20:50.80,EN,,0,0,0,,well then the lifetime of the Dialogue: 0,0:20:51.07,0:20:53.39,EN,,0,0,0,,frame of the outer procedure still is Dialogue: 0,0:20:53.50,0:20:56.12,EN,,0,0,0,,only the lifetime of the procedure Dialogue: 0,0:20:57.02,0:20:57.90,EN,,0,0,0,,which was exported. Dialogue: 0,0:20:58.53,0:20:59.57,EN,,0,0,0,,And so ultimately, Dialogue: 0,0:20:59.57,0:21:00.97,EN,,0,0,0,,a lot of that is garbage. Dialogue: 0,0:21:01.96,0:21:04.10,EN,,0,0,0,,There are other ways of producing garbage as well. Dialogue: 0,0:21:05.37,0:21:06.67,EN,,0,0,0,,Users produce garbage. Dialogue: 0,0:21:07.24,0:21:08.07,EN,,0,0,0,,An example of Dialogue: 0,0:21:08.07,0:21:10.22,EN,,0,0,0,,user garbage is something like this. Dialogue: 0,0:21:10.93,0:21:14.00,EN,,0,0,0,,If we write a program to, for example, Dialogue: 0,0:21:14.00,0:21:15.80,EN,,0,0,0,,append two lists together, Dialogue: 0,0:21:16.05,0:21:18.14,EN,,0,0,0,,well one way to do it is to Dialogue: 0,0:21:18.32,0:21:21.37,EN,,0,0,0,,reverse the first list onto the empty list Dialogue: 0,0:21:21.37,0:21:23.72,EN,,0,0,0,,and reverse that onto the second list. Dialogue: 0,0:21:24.70,0:21:26.92,EN,,0,0,0,,Now that's not terribly bad way of doing it. Dialogue: 0,0:21:28.16,0:21:28.85,EN,,0,0,0,,And however, Dialogue: 0,0:21:28.85,0:21:30.09,EN,,0,0,0,,the intermediate result, Dialogue: 0,0:21:30.11,0:21:32.02,EN,,0,0,0,,which is the reversal of the first list Dialogue: 0,0:21:33.87,0:21:35.57,EN,,0,0,0,,as done by this program, Dialogue: 0,0:21:36.70,0:21:38.52,EN,,0,0,0,,is never going to be accessed ever again Dialogue: 0,0:21:38.52,0:21:40.56,EN,,0,0,0,,after it's copied back on to the second. Dialogue: 0,0:21:41.01,0:21:42.23,EN,,0,0,0,,It's an intermediate result. Dialogue: 0,0:21:43.58,0:21:45.43,EN,,0,0,0,,It's going to be hard to ever see Dialogue: 0,0:21:46.07,0:21:48.05,EN,,0,0,0,,how anybody would ever be able to access it. Dialogue: 0,0:21:48.60,0:21:49.84,EN,,0,0,0,,In fact, it will go away. Dialogue: 0,0:21:51.05,0:21:52.90,EN,,0,0,0,,Now if we make a lot of garbage like that, Dialogue: 0,0:21:52.90,0:21:54.20,EN,,0,0,0,,and we should be allowed to, Dialogue: 0,0:21:54.80,0:21:57.29,EN,,0,0,0,,then there's got to be some way to reclaim that garbage. Dialogue: 0,0:21:58.80,0:22:00.90,EN,,0,0,0,,Well, what I'd like to tell you about now Dialogue: 0,0:22:01.70,0:22:03.77,EN,,0,0,0,,is a very clever technique Dialogue: 0,0:22:04.32,0:22:07.58,EN,,0,0,0,,whereby a Lisp system Dialogue: 0,0:22:07.95,0:22:11.21,EN,,0,0,0,,can prove a small theorem every so often Dialogue: 0,0:22:11.29,0:22:13.50,EN,,0,0,0,,on the form the following piece of junk Dialogue: 0,0:22:14.72,0:22:16.09,EN,,0,0,0,,will never be accessed again. Dialogue: 0,0:22:17.41,0:22:19.80,EN,,0,0,0,,It can have no affect on the future of the computation. Dialogue: 0,0:22:21.40,0:22:23.61,EN,,0,0,0,,It's actually based on a very simple idea. Dialogue: 0,0:22:24.72,0:22:28.06,EN,,0,0,0,,We've designed our computers to look sort of like this. Dialogue: 0,0:22:28.95,0:22:30.67,EN,,0,0,0,,There's some data path, Dialogue: 0,0:22:31.87,0:22:33.40,EN,,0,0,0,,which contains the registers. Dialogue: 0,0:22:34.92,0:22:38.04,EN,,0,0,0,,You know, there are things like exp, and env, Dialogue: 0,0:22:39.04,0:22:42.19,EN,,0,0,0,,and val, and so on. Dialogue: 0,0:22:42.61,0:22:44.02,EN,,0,0,0,,And there's one here called stack, Dialogue: 0,0:22:46.02,0:22:49.45,EN,,0,0,0,,some sort which points off to a structure somewhere, Dialogue: 0,0:22:49.50,0:22:50.22,EN,,0,0,0,,which is the stack. Dialogue: 0,0:22:50.24,0:22:51.48,EN,,0,0,0,,And we'll worry about that in a second. Dialogue: 0,0:22:51.64,0:22:53.62,EN,,0,0,0,,There's some finite controller, Dialogue: 0,0:22:54.38,0:22:56.57,EN,,0,0,0,,finite state machine controller. Dialogue: 0,0:22:56.73,0:22:59.51,EN,,0,0,0,,And there's some control signals that go this way and Dialogue: 0,0:22:59.80,0:23:01.44,EN,,0,0,0,,predicate results that come this way, Dialogue: 0,0:23:01.87,0:23:03.13,EN,,0,0,0,,not the interesting part. Dialogue: 0,0:23:03.35,0:23:06.51,EN,,0,0,0,,There's some sort of structured memory, Dialogue: 0,0:23:06.80,0:23:08.27,EN,,0,0,0,,which I just told you how to make, Dialogue: 0,0:23:08.27,0:23:10.17,EN,,0,0,0,,which may contain a stack. Dialogue: 0,0:23:10.46,0:23:11.48,EN,,0,0,0,,I didn't tell you how to make things Dialogue: 0,0:23:11.48,0:23:12.43,EN,,0,0,0,,of arbitrary shape, Dialogue: 0,0:23:12.56,0:23:13.39,EN,,0,0,0,,only pairs. Dialogue: 0,0:23:13.60,0:23:14.20,EN,,0,0,0,,But in fact Dialogue: 0,0:23:14.35,0:23:15.44,EN,,0,0,0,,with what I've told you can Dialogue: 0,0:23:15.47,0:23:16.96,EN,,0,0,0,,with what I've told you can simulate a stack by a big list. Dialogue: 0,0:23:17.77,0:23:18.85,EN,,0,0,0,,I don't plan to do that, Dialogue: 0,0:23:18.85,0:23:20.01,EN,,0,0,0,,it's not a nice way to do it. Dialogue: 0,0:23:20.36,0:23:22.60,EN,,0,0,0,,But we could have something like that. Dialogue: 0,0:23:22.99,0:23:25.28,EN,,0,0,0,,We have all sorts of little data structures in here Dialogue: 0,0:23:25.64,0:23:27.75,EN,,0,0,0,,that are hooked together in funny ways. Dialogue: 0,0:23:30.11,0:23:32.02,EN,,0,0,0,,They connect to other things. Dialogue: 0,0:23:32.56,0:23:33.25,EN,,0,0,0,,And so on. Dialogue: 0,0:23:33.25,0:23:34.22,EN,,0,0,0,,And ultimately Dialogue: 0,0:23:34.45,0:23:37.19,EN,,0,0,0,,things up there are pointers to these. Dialogue: 0,0:23:37.19,0:23:38.87,EN,,0,0,0,,The things that are in the registers Dialogue: 0,0:23:39.40,0:23:41.40,EN,,0,0,0,,are pointers off to the data structures Dialogue: 0,0:23:41.44,0:23:43.08,EN,,0,0,0,,that live in this list structure memory. Dialogue: 0,0:23:44.91,0:23:49.80,EN,,0,0,0,,Now the truth of the matter is Dialogue: 0,0:23:51.05,0:23:52.56,EN,,0,0,0,,that the entire consciousness Dialogue: 0,0:23:52.57,0:23:53.92,EN,,0,0,0,,of this machine is in these registers. Dialogue: 0,0:23:55.76,0:23:58.51,EN,,0,0,0,,There is no possible way that the machine, Dialogue: 0,0:23:58.75,0:24:01.07,EN,,0,0,0,,if done correctly, if built correctly, Dialogue: 0,0:24:01.37,0:24:03.41,EN,,0,0,0,,can access anything in this list structure memory Dialogue: 0,0:24:04.57,0:24:07.05,EN,,0,0,0,,unless the thing in that list structure memory is Dialogue: 0,0:24:08.09,0:24:10.88,EN,,0,0,0,,is connected by a sequence of data structures Dialogue: 0,0:24:11.64,0:24:13.06,EN,,0,0,0,,to the registers. Dialogue: 0,0:24:15.07,0:24:15.98,EN,,0,0,0,,If it's accessible Dialogue: 0,0:24:16.22,0:24:18.31,EN,,0,0,0,,by legitimate data structure selectors Dialogue: 0,0:24:19.08,0:24:21.12,EN,,0,0,0,,from the pointers that are stored in these registers. Dialogue: 0,0:24:22.28,0:24:24.46,EN,,0,0,0,,Things like array references, perhaps. Dialogue: 0,0:24:24.94,0:24:27.92,EN,,0,0,0,,Or cons cell references, cars and cdrs. Dialogue: 0,0:24:29.08,0:24:30.95,EN,,0,0,0,,But I can't just talk about a random place in this memory, Dialogue: 0,0:24:30.95,0:24:31.95,EN,,0,0,0,,because I can't get to it. Dialogue: 0,0:24:32.74,0:24:34.90,EN,,0,0,0,,These are being arbitrary names I'm not allowed to count, Dialogue: 0,0:24:37.00,0:24:39.16,EN,,0,0,0,,at least as I'm evaluating expressions. Dialogue: 0,0:24:41.62,0:24:42.57,EN,,0,0,0,,If that's the case Dialogue: 0,0:24:43.27,0:24:45.07,EN,,0,0,0,,then there's a very simple theorem to be proved. Dialogue: 0,0:24:47.16,0:24:47.69,EN,,0,0,0,,Which is, Dialogue: 0,0:24:47.90,0:24:50.52,EN,,0,0,0,,if I start with all lead pointers that are in all these registers Dialogue: 0,0:24:51.16,0:24:52.55,EN,,0,0,0,,and recursively chase out, Dialogue: 0,0:24:52.82,0:24:56.15,EN,,0,0,0,,marking all the places I can get to by selectors, Dialogue: 0,0:24:56.90,0:24:59.40,EN,,0,0,0,,then eventually I mark everything they can be gotten to. Dialogue: 0,0:25:00.65,0:25:02.69,EN,,0,0,0,,Anything which is not so marked is garbage Dialogue: 0,0:25:02.69,0:25:03.75,EN,,0,0,0,,and can be recycled. Dialogue: 0,0:25:05.56,0:25:06.20,EN,,0,0,0,,Very simple. Dialogue: 0,0:25:07.20,0:25:09.10,EN,,0,0,0,,Cannot affect the future of the computation. Dialogue: 0,0:25:11.18,0:25:12.84,EN,,0,0,0,,So let me show you that in a particular Dialogue: 0,0:25:13.93,0:25:15.75,EN,,0,0,0,,in a particular example. Dialogue: 0,0:25:17.12,0:25:19.37,EN,,0,0,0,,Now that means I'm going to have to append to my Dialogue: 0,0:25:19.69,0:25:22.08,EN,,0,0,0,,description of the list structure a mark. Dialogue: 0,0:25:23.64,0:25:24.89,EN,,0,0,0,,And so here, for example, Dialogue: 0,0:25:25.37,0:25:27.28,EN,,0,0,0,,is a list structured memory. Dialogue: 0,0:25:29.08,0:25:30.32,EN,,0,0,0,,And in this list structured memory Dialogue: 0,0:25:30.33,0:25:31.33,EN,,0,0,0,,is a list structure Dialogue: 0,0:25:31.33,0:25:33.95,EN,,0,0,0,,beginning in a place I'm going to call-- Dialogue: 0,0:25:35.87,0:25:36.62,EN,,0,0,0,,this is the root. Dialogue: 0,0:25:38.59,0:25:40.12,EN,,0,0,0,,Now it doesn't really have to have a root. Dialogue: 0,0:25:40.12,0:25:41.95,EN,,0,0,0,,It could be a bunch of them, like all the registers. Dialogue: 0,0:25:42.67,0:25:43.98,EN,,0,0,0,,But I could cleverly arrange it Dialogue: 0,0:25:44.13,0:25:46.30,EN,,0,0,0,,so all the registers, all the things that are in old registers Dialogue: 0,0:25:46.30,0:25:47.77,EN,,0,0,0,,are also at the right moment Dialogue: 0,0:25:48.28,0:25:50.46,EN,,0,0,0,,put into this root structure, Dialogue: 0,0:25:50.46,0:25:51.85,EN,,0,0,0,,and then we've got one pointer to it. Dialogue: 0,0:25:51.85,0:25:52.67,EN,,0,0,0,,I don't really care. Dialogue: 0,0:25:54.57,0:25:55.63,EN,,0,0,0,,So the idea is Dialogue: 0,0:25:55.64,0:25:56.65,EN,,0,0,0,,we're going to cons up stuff Dialogue: 0,0:25:56.67,0:25:58.01,EN,,0,0,0,,until our free list is empty. Dialogue: 0,0:25:58.72,0:25:59.67,EN,,0,0,0,,We've run out of things. Dialogue: 0,0:26:00.95,0:26:04.47,EN,,0,0,0,,Now we're going to do this process of proving the theorem Dialogue: 0,0:26:04.47,0:26:05.90,EN,,0,0,0,,that a certain percentage of the memory Dialogue: 0,0:26:05.95,0:26:06.90,EN,,0,0,0,,is got crap in it. Dialogue: 0,0:26:07.85,0:26:09.15,EN,,0,0,0,,And then we're going to recycle that Dialogue: 0,0:26:09.78,0:26:10.87,EN,,0,0,0,,to grow new trees, Dialogue: 0,0:26:12.19,0:26:14.57,EN,,0,0,0,,a standard use of such garbage. Dialogue: 0,0:26:17.09,0:26:18.64,EN,,0,0,0,,So in any case, what do we have here? Dialogue: 0,0:26:18.84,0:26:20.78,EN,,0,0,0,,Well we have some data structure Dialogue: 0,0:26:20.89,0:26:24.27,EN,,0,0,0,,which starts out over here in p5. Dialogue: 0,0:26:25.15,0:26:26.75,EN,,0,0,0,,Sorry, and it will start at one Dialogue: 0,0:26:27.27,0:26:28.51,EN,,0,0,0,,And in fact Dialogue: 0,0:26:28.89,0:26:32.20,EN,,0,0,0,,it has a car in p5, Dialogue: 0,0:26:32.27,0:26:33.58,EN,,0,0,0,,and its cdr is in two. Dialogue: 0,0:26:33.98,0:26:35.64,EN,,0,0,0,,And all the marks start out at zero. Dialogue: 0,0:26:36.70,0:26:39.00,EN,,0,0,0,,Well let's start marking, just to play this game. Dialogue: 0,0:26:39.92,0:26:40.52,EN,,0,0,0,,OK. Dialogue: 0,0:26:42.54,0:26:44.27,EN,,0,0,0,,So for example, Dialogue: 0,0:26:44.47,0:26:46.95,EN,,0,0,0,,since I can access one from the root Dialogue: 0,0:26:46.95,0:26:47.82,EN,,0,0,0,,I will mark that. Dialogue: 0,0:26:48.39,0:26:49.17,EN,,0,0,0,,Let me mark it. Dialogue: 0,0:26:50.96,0:26:51.45,EN,,0,0,0,,Bang. Dialogue: 0,0:26:52.22,0:26:52.94,EN,,0,0,0,,That's marked. Dialogue: 0,0:26:54.41,0:26:57.51,EN,,0,0,0,,OK. Now since I have a five here Dialogue: 0,0:26:57.64,0:26:58.64,EN,,0,0,0,,I can go to five Dialogue: 0,0:26:59.02,0:27:00.72,EN,,0,0,0,,and see, well I'll mark that. Dialogue: 0,0:27:01.45,0:27:01.76,EN,,0,0,0,,Bang. Dialogue: 0,0:27:01.76,0:27:02.60,EN,,0,0,0,,That's useful stuff. Dialogue: 0,0:27:02.90,0:27:05.10,EN,,0,0,0,,But five references as a number in its car, Dialogue: 0,0:27:05.27,0:27:06.65,EN,,0,0,0,,I'm not interested in marking numbers Dialogue: 0,0:27:06.91,0:27:08.17,EN,,0,0,0,,but its cdr is seven. Dialogue: 0,0:27:08.70,0:27:09.75,EN,,0,0,0,,So I can mark that. Dialogue: 0,0:27:10.45,0:27:10.81,EN,,0,0,0,,Bang. Dialogue: 0,0:27:11.80,0:27:13.40,EN,,0,0,0,,OK? Seven is the empty list, Dialogue: 0,0:27:13.67,0:27:15.10,EN,,0,0,0,,the only thing that references, Dialogue: 0,0:27:15.59,0:27:17.12,EN,,0,0,0,,and it's got a number in its car. Dialogue: 0,0:27:17.12,0:27:17.85,EN,,0,0,0,,Not interesting. Dialogue: 0,0:27:19.49,0:27:20.50,EN,,0,0,0,,Well now let's go back here. Dialogue: 0,0:27:20.50,0:27:21.65,EN,,0,0,0,,I forgot about something. Dialogue: 0,0:27:21.65,0:27:22.17,EN,,0,0,0,,Two. Dialogue: 0,0:27:22.84,0:27:24.85,EN,,0,0,0,,See in other words, if I'm looking at cell one, Dialogue: 0,0:27:25.42,0:27:29.45,EN,,0,0,0,,cell one contains a two right over here. Dialogue: 0,0:27:30.37,0:27:31.30,EN,,0,0,0,,A reference to two. Dialogue: 0,0:27:32.01,0:27:34.97,EN,,0,0,0,,That means I should go mark two. Dialogue: 0,0:27:35.70,0:27:36.27,EN,,0,0,0,,Bang. Dialogue: 0,0:27:37.14,0:27:38.89,EN,,0,0,0,,Two contains a reference to four. Dialogue: 0,0:27:39.13,0:27:40.27,EN,,0,0,0,,It's got a number in its car, Dialogue: 0,0:27:40.27,0:27:41.20,EN,,0,0,0,,I'm not interested in that Dialogue: 0,0:27:41.47,0:27:42.60,EN,,0,0,0,,so I'm going to go mark that. Dialogue: 0,0:27:43.78,0:27:46.10,EN,,0,0,0,,Four refers to seven through its car, Dialogue: 0,0:27:46.75,0:27:48.17,EN,,0,0,0,,and is empty in its cdr, Dialogue: 0,0:27:48.47,0:27:49.57,EN,,0,0,0,,but I've already marked that one Dialogue: 0,0:27:49.57,0:27:50.75,EN,,0,0,0,,so I don't have to mark it again. Dialogue: 0,0:27:51.40,0:27:53.05,EN,,0,0,0,,This is all the accessible structure Dialogue: 0,0:27:53.07,0:27:53.87,EN,,0,0,0,,from that place. Dialogue: 0,0:27:55.00,0:27:56.57,EN,,0,0,0,,Simple recursive mark algorithm. Dialogue: 0,0:27:58.71,0:28:01.79,EN,,0,0,0,,Now there are some unhappinesses about that algorithm, Dialogue: 0,0:28:01.90,0:28:04.02,EN,,0,0,0,,and we can worry about that a second. Dialogue: 0,0:28:04.92,0:28:06.16,EN,,0,0,0,,But basically you'll see Dialogue: 0,0:28:06.19,0:28:07.85,EN,,0,0,0,,that all the things that have not been marked Dialogue: 0,0:28:09.62,0:28:11.50,EN,,0,0,0,,are places that are free, Dialogue: 0,0:28:11.50,0:28:12.41,EN,,0,0,0,,and I could recycle. Dialogue: 0,0:28:14.25,0:28:15.75,EN,,0,0,0,,So the next stage after that is going to be Dialogue: 0,0:28:15.75,0:28:17.05,EN,,0,0,0,,to scan through all of my memory, Dialogue: 0,0:28:17.94,0:28:20.35,EN,,0,0,0,,looking for things that are not marked. Dialogue: 0,0:28:21.18,0:28:22.45,EN,,0,0,0,,Every time I come across a marked thing Dialogue: 0,0:28:22.45,0:28:23.22,EN,,0,0,0,,I unmark it, Dialogue: 0,0:28:23.22,0:28:24.86,EN,,0,0,0,,and every time I come across an unmarked thing Dialogue: 0,0:28:25.07,0:28:27.82,EN,,0,0,0,,I'm going to link it together in my free list. Dialogue: 0,0:28:28.77,0:28:30.30,EN,,0,0,0,,Classic, very simple algorithm. Dialogue: 0,0:28:32.12,0:28:33.10,EN,,0,0,0,,So let's see. Dialogue: 0,0:28:33.84,0:28:34.77,EN,,0,0,0,,Is that very simple? Dialogue: 0,0:28:34.77,0:28:35.42,EN,,0,0,0,,Yes it is. Dialogue: 0,0:28:35.57,0:28:37.79,EN,,0,0,0,,I'm not going to go through the code in any detail, Dialogue: 0,0:28:38.00,0:28:39.65,EN,,0,0,0,,but I just want to show you about how long it is. Dialogue: 0,0:28:40.09,0:28:41.10,EN,,0,0,0,,Let's look at the mark phase. Dialogue: 0,0:28:41.72,0:28:43.98,EN,,0,0,0,,Here's the first part of the mark phase. Dialogue: 0,0:28:45.06,0:28:46.00,EN,,0,0,0,,We pick up the root. Dialogue: 0,0:28:46.32,0:28:47.52,EN,,0,0,0,,We're going to do some Dialogue: 0,0:28:47.67,0:28:51.05,EN,,0,0,0,,We're going to use that as a recursive procedure call. Dialogue: 0,0:28:52.38,0:28:54.47,EN,,0,0,0,,We're going to sweep from there, Dialogue: 0,0:28:54.77,0:28:56.95,EN,,0,0,0,,after when we're done with marking. Dialogue: 0,0:28:57.38,0:28:59.79,EN,,0,0,0,,And then we're going to do a little couple of instructions Dialogue: 0,0:28:59.80,0:29:01.36,EN,,0,0,0,,that do this checking out on the marks Dialogue: 0,0:29:01.39,0:29:03.07,EN,,0,0,0,,and changing the marks and things like that, Dialogue: 0,0:29:03.07,0:29:04.90,EN,,0,0,0,,according to the algorithm I've just shown you. Dialogue: 0,0:29:05.23,0:29:06.47,EN,,0,0,0,,OK? It comes out here. Dialogue: 0,0:29:06.47,0:29:07.65,EN,,0,0,0,,You have to mark the cars of things Dialogue: 0,0:29:07.87,0:29:10.21,EN,,0,0,0,,and you also have to be able to mark the cdrs of things. Dialogue: 0,0:29:10.66,0:29:12.10,EN,,0,0,0,,That's the entire mark phase. Dialogue: 0,0:29:14.37,0:29:16.16,EN,,0,0,0,,I'll just tell you a little story about this. Dialogue: 0,0:29:16.59,0:29:19.37,EN,,0,0,0,,The old DEC PDP-6 computer, Dialogue: 0,0:29:20.93,0:29:22.09,EN,,0,0,0,,this was the way that Dialogue: 0,0:29:22.35,0:29:24.85,EN,,0,0,0,,the mark-sweep garbage collection, as it was, was written. Dialogue: 0,0:29:26.91,0:29:28.40,EN,,0,0,0,,The program was so small Dialogue: 0,0:29:29.25,0:29:31.60,EN,,0,0,0,,that with the data that it needed, Dialogue: 0,0:29:32.20,0:29:34.87,EN,,0,0,0,,with the registers that it needed to manipulate the memory, Dialogue: 0,0:29:36.16,0:29:38.14,EN,,0,0,0,,it fit into the fast registers of the machine, Dialogue: 0,0:29:38.16,0:29:38.97,EN,,0,0,0,,which were 16. Dialogue: 0,0:29:39.28,0:29:39.80,EN,,0,0,0,,The whole program. Dialogue: 0,0:29:40.01,0:29:42.01,EN,,0,0,0,,And you could execute instructions in the fast registers. Dialogue: 0,0:29:43.17,0:29:44.83,EN,,0,0,0,,So it's an extremely small program, Dialogue: 0,0:29:45.85,0:29:46.88,EN,,0,0,0,,and it could run very fast. Dialogue: 0,0:29:48.87,0:29:51.30,EN,,0,0,0,,Now unfortunately, of course, Dialogue: 0,0:29:51.61,0:29:54.02,EN,,0,0,0,,this program, because the fact that it's recursive Dialogue: 0,0:29:54.80,0:29:57.55,EN,,0,0,0,,in the way that you do something first Dialogue: 0,0:29:57.55,0:29:58.99,EN,,0,0,0,,and then you do something after that, Dialogue: 0,0:29:59.21,0:30:00.88,EN,,0,0,0,,you have to work on the cars and then the cdrs, Dialogue: 0,0:30:01.15,0:30:02.75,EN,,0,0,0,,it requires auxiliary memory. Dialogue: 0,0:30:03.41,0:30:05.23,EN,,0,0,0,,So Lisp systems-- Dialogue: 0,0:30:05.44,0:30:07.42,EN,,0,0,0,,those requires a stack for marking. Dialogue: 0,0:30:08.26,0:30:11.05,EN,,0,0,0,,Lisp systems that are built this way Dialogue: 0,0:30:11.57,0:30:14.16,EN,,0,0,0,,have a limit to the depth of recursion you can have Dialogue: 0,0:30:14.42,0:30:17.37,EN,,0,0,0,,in data structures in either the car or the cdr, Dialogue: 0,0:30:17.81,0:30:19.35,EN,,0,0,0,,and that doesn't work very nicely. Dialogue: 0,0:30:19.93,0:30:20.60,EN,,0,0,0,,On the other hand, Dialogue: 0,0:30:20.64,0:30:22.12,EN,,0,0,0,,you never notice it if it's big enough. Dialogue: 0,0:30:23.18,0:30:25.13,EN,,0,0,0,,And that's certainly been Dialogue: 0,0:30:25.55,0:30:28.17,EN,,0,0,0,,the case for most Maclisp, for example, Dialogue: 0,0:30:28.69,0:30:29.88,EN,,0,0,0,,which ran Macsyma Dialogue: 0,0:30:29.96,0:30:31.10,EN,,0,0,0,,where you could deal with expressions Dialogue: 0,0:30:31.10,0:30:32.72,EN,,0,0,0,,of thousands of elements long. Dialogue: 0,0:30:33.56,0:30:36.02,EN,,0,0,0,,These are algebraic expressions with thousand of terms. Dialogue: 0,0:30:36.82,0:30:38.10,EN,,0,0,0,,And there's no problem with that. Dialogue: 0,0:30:39.49,0:30:40.82,EN,,0,0,0,,Such, the garbage collector does work. Dialogue: 0,0:30:42.19,0:30:42.92,EN,,0,0,0,,On the other hand, Dialogue: 0,0:30:42.92,0:30:45.37,EN,,0,0,0,,there's a very clever modification to this algorithm, Dialogue: 0,0:30:45.37,0:30:46.47,EN,,0,0,0,,which I will not describe, Dialogue: 0,0:30:46.80,0:30:48.22,EN,,0,0,0,,by Peter Deutsch and Schorr and Waite-- Dialogue: 0,0:30:48.64,0:30:51.82,EN,,0,0,0,,and Schorr and Waite, Herb Schorr from IBM Dialogue: 0,0:30:51.87,0:30:53.52,EN,,0,0,0,,and Waite who I don't know. Dialogue: 0,0:30:54.01,0:30:56.51,EN,,0,0,0,,Whrere... That algorithm Dialogue: 0,0:30:56.67,0:30:57.79,EN,,0,0,0,,allows you build Dialogue: 0,0:30:57.84,0:30:59.55,EN,,0,0,0,,you do can do this without auxiliary memory, Dialogue: 0,0:31:00.50,0:31:02.80,EN,,0,0,0,,by remembering as you walk the data structures Dialogue: 0,0:31:02.97,0:31:05.52,EN,,0,0,0,,where you came from by reversing the pointers as you go down Dialogue: 0,0:31:05.52,0:31:07.52,EN,,0,0,0,,and crawling up the reverse pointers as you go up. Dialogue: 0,0:31:07.79,0:31:08.99,EN,,0,0,0,,It's a rather tricky algorithm. Dialogue: 0,0:31:09.13,0:31:10.24,EN,,0,0,0,,The first time you write it-- Dialogue: 0,0:31:10.25,0:31:11.71,EN,,0,0,0,,or in fact, the first three times you write it it Dialogue: 0,0:31:11.71,0:31:12.72,EN,,0,0,0,,it has a terrible bug in it. Dialogue: 0,0:31:14.35,0:31:16.72,EN,,0,0,0,,And it's also about, it's quite rather slow, Dialogue: 0,0:31:16.72,0:31:17.67,EN,,0,0,0,,because it's complicated. Dialogue: 0,0:31:18.11,0:31:20.30,EN,,0,0,0,,It takes about six times as many memory references Dialogue: 0,0:31:20.85,0:31:23.22,EN,,0,0,0,,to do the sorts of things that we're talking about. Dialogue: 0,0:31:24.58,0:31:27.07,EN,,0,0,0,,Well now once I've done this marking phase, Dialogue: 0,0:31:27.50,0:31:30.12,EN,,0,0,0,,and I get into a position where things look like this, Dialogue: 0,0:31:30.17,0:31:31.26,EN,,0,0,0,,let's look-- yes. Dialogue: 0,0:31:31.51,0:31:34.03,EN,,0,0,0,,Here we have the mark done, Dialogue: 0,0:31:34.08,0:31:35.00,EN,,0,0,0,,just as I did it. Dialogue: 0,0:31:35.59,0:31:37.33,EN,,0,0,0,,Now we have to perform the sweep phase. Dialogue: 0,0:31:37.60,0:31:39.32,EN,,0,0,0,,And I described to you what this sweep is like. Dialogue: 0,0:31:39.82,0:31:42.34,EN,,0,0,0,,I'm going to walk down from one end of memory or the other, Dialogue: 0,0:31:42.34,0:31:43.34,EN,,0,0,0,,I don't care where, Dialogue: 0,0:31:43.62,0:31:46.17,EN,,0,0,0,,scanning every cell that's in the memory. Dialogue: 0,0:31:47.17,0:31:48.67,EN,,0,0,0,,And as I scan these cells, Dialogue: 0,0:31:49.20,0:31:50.97,EN,,0,0,0,,I'm going to link them together, Dialogue: 0,0:31:50.99,0:31:52.84,EN,,0,0,0,,if they are free, into the free list. Dialogue: 0,0:31:53.15,0:31:54.05,EN,,0,0,0,,And if they're not free, Dialogue: 0,0:31:54.05,0:31:56.07,EN,,0,0,0,,I'm going to unmark them so the marks become zero. Dialogue: 0,0:31:57.50,0:31:58.57,EN,,0,0,0,,And in fact what I get-- Dialogue: 0,0:31:58.70,0:32:00.46,EN,,0,0,0,,well the program is not very complicated. Dialogue: 0,0:32:00.46,0:32:02.22,EN,,0,0,0,,It looks sort of like this-- it's a little longer. Dialogue: 0,0:32:02.78,0:32:04.17,EN,,0,0,0,,Here's the first piece of it. Dialogue: 0,0:32:04.82,0:32:06.71,EN,,0,0,0,,This one's coming down from the top of memory. Dialogue: 0,0:32:06.71,0:32:09.58,EN,,0,0,0,,I don't want you to try to understand this at this point. Dialogue: 0,0:32:09.58,0:32:10.55,EN,,0,0,0,,It's rather simple. Dialogue: 0,0:32:11.03,0:32:12.52,EN,,0,0,0,,It's a very simple algorithm, Dialogue: 0,0:32:13.07,0:32:15.97,EN,,0,0,0,,but there's pieces of it that just sort of look like this. Dialogue: 0,0:32:15.97,0:32:17.37,EN,,0,0,0,,They're all sort of obvious. Dialogue: 0,0:32:18.60,0:32:20.08,EN,,0,0,0,,And after we've done the sweep, Dialogue: 0,0:32:20.30,0:32:21.77,EN,,0,0,0,,we get an answer that looks like that. Dialogue: 0,0:32:25.33,0:32:26.54,EN,,0,0,0,,Now there are some disadvantages Dialogue: 0,0:32:26.56,0:32:28.20,EN,,0,0,0,,with mark-sweep algorithms of this sort. Dialogue: 0,0:32:29.59,0:32:30.35,EN,,0,0,0,,Serious ones. Dialogue: 0,0:32:31.45,0:32:33.20,EN,,0,0,0,,One important disadvantage is Dialogue: 0,0:32:33.20,0:32:34.97,EN,,0,0,0,,that your memories get larger and larger. Dialogue: 0,0:32:36.82,0:32:38.87,EN,,0,0,0,,As you say, address spaces get larger and larger, Dialogue: 0,0:32:38.87,0:32:40.80,EN,,0,0,0,,you're willing to represent more and more stuff, Dialogue: 0,0:32:41.37,0:32:44.52,EN,,0,0,0,,then it gets very costly to scan all of memory. Dialogue: 0,0:32:46.36,0:32:47.39,EN,,0,0,0,,What you'd really like to do Dialogue: 0,0:32:47.40,0:32:48.68,EN,,0,0,0,,is only scan useful stuff. Dialogue: 0,0:32:50.49,0:32:51.55,EN,,0,0,0,,It would even be better Dialogue: 0,0:32:52.07,0:32:53.90,EN,,0,0,0,,if you realized that some stuff Dialogue: 0,0:32:54.48,0:32:57.72,EN,,0,0,0,,was known to be good and useful, Dialogue: 0,0:32:58.28,0:33:00.37,EN,,0,0,0,,and you don't have to look at it more than once or twice. Dialogue: 0,0:33:00.37,0:33:01.20,EN,,0,0,0,,Or very rarely. Dialogue: 0,0:33:01.55,0:33:04.32,EN,,0,0,0,,Whereas other stuff that you're not so sure about, Dialogue: 0,0:33:05.00,0:33:06.22,EN,,0,0,0,,you can look at more detail Dialogue: 0,0:33:07.10,0:33:08.75,EN,,0,0,0,,every time you want to do this, Dialogue: 0,0:33:09.93,0:33:10.85,EN,,0,0,0,,want to garbage collect. Dialogue: 0,0:33:11.91,0:33:13.74,EN,,0,0,0,,Well there are algorithms Dialogue: 0,0:33:13.76,0:33:15.10,EN,,0,0,0,,that are organized in this way. Dialogue: 0,0:33:15.66,0:33:18.16,EN,,0,0,0,,Let me tell you about a famous old algorithm Dialogue: 0,0:33:18.28,0:33:19.47,EN,,0,0,0,,which allows you only look at Dialogue: 0,0:33:19.50,0:33:21.37,EN,,0,0,0,,the part of memory which is known to be useful. Dialogue: 0,0:33:23.12,0:33:23.85,EN,,0,0,0,,And which happens to be Dialogue: 0,0:33:23.87,0:33:25.29,EN,,0,0,0,,the fastest known garbage collector algorithm. Dialogue: 0,0:33:26.31,0:33:29.45,EN,,0,0,0,,This is the Minsky-Fenichel-Yochelson garbage collector algorithm. Dialogue: 0,0:33:30.40,0:33:33.18,EN,,0,0,0,,It was invented by Minsky Dialogue: 0,0:33:33.20,0:33:36.06,EN,,0,0,0,,in 1961 or '60 or something, Dialogue: 0,0:33:36.52,0:33:40.48,EN,,0,0,0,,for the RLE PDP-1 Lisp, Dialogue: 0,0:33:40.51,0:33:43.44,EN,,0,0,0,,which had 4,096 words of list memory, Dialogue: 0,0:33:45.79,0:33:46.76,EN,,0,0,0,,and a drum. Dialogue: 0,0:33:48.48,0:33:49.39,EN,,0,0,0,,And the whole idea Dialogue: 0,0:33:50.03,0:33:51.87,EN,,0,0,0,,was to garbage collect this terrible memory. Dialogue: 0,0:33:53.05,0:33:54.35,EN,,0,0,0,,What Minsky realized Dialogue: 0,0:33:54.38,0:33:55.62,EN,,0,0,0,,was the easiest way to do this Dialogue: 0,0:33:56.20,0:33:58.47,EN,,0,0,0,,is to scan the memory in the same sense, Dialogue: 0,0:33:58.47,0:34:00.60,EN,,0,0,0,,walking the good structure, Dialogue: 0,0:34:01.57,0:34:03.52,EN,,0,0,0,,copying it out into the drum, Dialogue: 0,0:34:04.70,0:34:05.47,EN,,0,0,0,,compacted. Dialogue: 0,0:34:06.35,0:34:08.86,EN,,0,0,0,,And then when we were done copying it all out, Dialogue: 0,0:34:09.12,0:34:10.90,EN,,0,0,0,,then you swap that back into your memory. Dialogue: 0,0:34:12.30,0:34:13.68,EN,,0,0,0,,Now whether or you not use a drum, Dialogue: 0,0:34:13.72,0:34:14.71,EN,,0,0,0,,or another piece of memory, Dialogue: 0,0:34:14.71,0:34:16.42,EN,,0,0,0,,or something like that isn't important. Dialogue: 0,0:34:17.03,0:34:17.42,EN,,0,0,0,,In fact, Dialogue: 0,0:34:17.44,0:34:19.60,EN,,0,0,0,,I don't think people use drums anymore for anything. Dialogue: 0,0:34:20.35,0:34:23.77,EN,,0,0,0,,But this algorithm basically Dialogue: 0,0:34:24.03,0:34:25.42,EN,,0,0,0,,depends upon having Dialogue: 0,0:34:25.42,0:34:27.42,EN,,0,0,0,,about twice as much address space Dialogue: 0,0:34:27.48,0:34:28.57,EN,,0,0,0,,you're actually using. Dialogue: 0,0:34:30.27,0:34:32.96,EN,,0,0,0,,And so what you have is some, initially, Dialogue: 0,0:34:33.12,0:34:36.60,EN,,0,0,0,,some mixture of useful data and garbage. Dialogue: 0,0:34:37.11,0:34:38.97,EN,,0,0,0,,So this is called fromspace. Dialogue: 0,0:34:45.17,0:34:47.05,EN,,0,0,0,,And this is a mixture of crud. Dialogue: 0,0:34:47.87,0:34:49.79,EN,,0,0,0,,Some of it's important and some of it isn't. Dialogue: 0,0:34:52.00,0:34:53.85,EN,,0,0,0,,Now there's another place Dialogue: 0,0:34:54.17,0:34:55.61,EN,,0,0,0,,which is hopefully big enough, Dialogue: 0,0:34:55.77,0:34:57.00,EN,,0,0,0,,if we recall, tospace, Dialogue: 0,0:34:57.12,0:34:58.24,EN,,0,0,0,,which is where we're copying to. Dialogue: 0,0:35:01.59,0:35:02.60,EN,,0,0,0,,And what happens is-- Dialogue: 0,0:35:02.60,0:35:04.06,EN,,0,0,0,,and I'm not going to go through this detail. Dialogue: 0,0:35:04.16,0:35:07.07,EN,,0,0,0,,It's in our book quite explicitly. Dialogue: 0,0:35:07.59,0:35:10.40,EN,,0,0,0,,There's a root point where you start from. Dialogue: 0,0:35:11.03,0:35:14.30,EN,,0,0,0,,And the idea is that you start with the root. Dialogue: 0,0:35:14.60,0:35:16.42,EN,,0,0,0,,You copy the first thing you see, Dialogue: 0,0:35:17.83,0:35:19.37,EN,,0,0,0,,the first thing that the root points at, Dialogue: 0,0:35:19.75,0:35:21.31,EN,,0,0,0,,to the beginning of tospace. Dialogue: 0,0:35:22.81,0:35:24.12,EN,,0,0,0,,The first thing is a pair Dialogue: 0,0:35:24.16,0:35:25.60,EN,,0,0,0,,or something like, a data structure. Dialogue: 0,0:35:27.56,0:35:30.19,EN,,0,0,0,,You then also leave behind Dialogue: 0,0:35:30.38,0:35:31.56,EN,,0,0,0,,a broken heart saying, Dialogue: 0,0:35:31.77,0:35:35.74,EN,,0,0,0,,I moved this object from here to here, Dialogue: 0,0:35:35.74,0:35:37.05,EN,,0,0,0,,giving the place where it moved to. Dialogue: 0,0:35:37.80,0:35:39.65,EN,,0,0,0,,This is called a broken heart because Dialogue: 0,0:35:39.65,0:35:40.78,EN,,0,0,0,,a friend of mine who implemented Dialogue: 0,0:35:40.78,0:35:43.39,EN,,0,0,0,,one of these in 1966 Dialogue: 0,0:35:43.82,0:35:45.26,EN,,0,0,0,,was a very romantic character Dialogue: 0,0:35:45.26,0:35:46.76,EN,,0,0,0,,and called it a broken heart. Dialogue: 0,0:35:49.58,0:35:50.54,EN,,0,0,0,,But in any case, Dialogue: 0,0:35:51.15,0:35:52.72,EN,,0,0,0,,the next thing you do Dialogue: 0,0:35:52.94,0:35:55.00,EN,,0,0,0,,is now you have a new free pointer which is here, Dialogue: 0,0:35:55.17,0:35:56.38,EN,,0,0,0,,and you start scanning. Dialogue: 0,0:35:56.88,0:35:59.68,EN,,0,0,0,,You scan this data structure you just copied. Dialogue: 0,0:36:00.55,0:36:02.19,EN,,0,0,0,,And every time you encounter a pointer in it, Dialogue: 0,0:36:02.19,0:36:03.92,EN,,0,0,0,,you treat it as if it was the root pointer here. Dialogue: 0,0:36:04.00,0:36:04.59,EN,,0,0,0,,Oh, I'm sorry. Dialogue: 0,0:36:04.60,0:36:05.69,EN,,0,0,0,,The other thing you do Dialogue: 0,0:36:05.71,0:36:07.08,EN,,0,0,0,,is you now move the root pointer to there. Dialogue: 0,0:36:09.22,0:36:10.17,EN,,0,0,0,,So now you scan this, Dialogue: 0,0:36:10.17,0:36:10.99,EN,,0,0,0,,and everything you see Dialogue: 0,0:36:11.00,0:36:12.41,EN,,0,0,0,,you treat as it were the root pointer. Dialogue: 0,0:36:14.11,0:36:15.45,EN,,0,0,0,,So if you see something, Dialogue: 0,0:36:15.45,0:36:17.40,EN,,0,0,0,,well it points up into there somewhere. Dialogue: 0,0:36:18.51,0:36:19.92,EN,,0,0,0,,Is it pointing at a thing Dialogue: 0,0:36:19.93,0:36:20.99,EN,,0,0,0,,which you've not copied yet? Dialogue: 0,0:36:21.78,0:36:22.87,EN,,0,0,0,,Is there a broken heart there? Dialogue: 0,0:36:23.88,0:36:24.84,EN,,0,0,0,,If there's a broken heart there Dialogue: 0,0:36:24.84,0:36:26.11,EN,,0,0,0,,and it's something you have copied, Dialogue: 0,0:36:26.20,0:36:27.34,EN,,0,0,0,,you've just replaced this pointer Dialogue: 0,0:36:27.36,0:36:28.75,EN,,0,0,0,,with the thing a broken heart points at. Dialogue: 0,0:36:29.82,0:36:32.03,EN,,0,0,0,,If this thing has not been copied, Dialogue: 0,0:36:32.12,0:36:34.08,EN,,0,0,0,,you copy it to the next place over here. Dialogue: 0,0:36:34.43,0:36:35.95,EN,,0,0,0,,Move your free pointer over here, Dialogue: 0,0:36:37.05,0:36:40.60,EN,,0,0,0,,and then leave a broken heart behind Dialogue: 0,0:36:41.05,0:36:41.80,EN,,0,0,0,,and scan. Dialogue: 0,0:36:43.67,0:36:46.40,EN,,0,0,0,,And eventually when the scant pointer hits the free pointer, Dialogue: 0,0:36:46.82,0:36:48.52,EN,,0,0,0,,everything in memory has been copied. Dialogue: 0,0:36:50.14,0:36:51.04,EN,,0,0,0,,And then there's a whole bunch Dialogue: 0,0:36:51.05,0:36:51.95,EN,,0,0,0,,of empty space up here, Dialogue: 0,0:36:51.96,0:36:53.28,EN,,0,0,0,,which you could either make into a free list, Dialogue: 0,0:36:53.31,0:36:54.47,EN,,0,0,0,,if that's what you want to do. Dialogue: 0,0:36:54.47,0:36:56.27,EN,,0,0,0,,But generally you don't in this kind of system. Dialogue: 0,0:36:56.27,0:36:59.15,EN,,0,0,0,,In this system you sequentially allocate your memory. Dialogue: 0,0:37:00.91,0:37:02.48,EN,,0,0,0,,That is a very, very nice algorithm, Dialogue: 0,0:37:02.97,0:37:04.57,EN,,0,0,0,,and sort of the one we use in the Dialogue: 0,0:37:04.67,0:37:05.97,EN,,0,0,0,,the scheme that you've been using. Dialogue: 0,0:37:06.79,0:37:09.47,EN,,0,0,0,,And it's known to be... it's expected-- Dialogue: 0,0:37:09.47,0:37:10.86,EN,,0,0,0,,I believe no one has found Dialogue: 0,0:37:10.89,0:37:12.12,EN,,0,0,0,,a faster algorithm than that. Dialogue: 0,0:37:12.40,0:37:14.85,EN,,0,0,0,,There are very simple modifications to this algorithm Dialogue: 0,0:37:14.85,0:37:16.77,EN,,0,0,0,,invented by Henry Baker Dialogue: 0,0:37:17.17,0:37:20.31,EN,,0,0,0,,which allow one to run this algorithm in real time, Dialogue: 0,0:37:20.31,0:37:21.92,EN,,0,0,0,,meaning you don't have to stop to garbage collect. Dialogue: 0,0:37:22.14,0:37:24.33,EN,,0,0,0,,But you could interleave the consing Dialogue: 0,0:37:24.36,0:37:26.17,EN,,0,0,0,,that the machine does when its running Dialogue: 0,0:37:26.32,0:37:28.40,EN,,0,0,0,,with steps of the garbage collection process, Dialogue: 0,0:37:28.85,0:37:31.20,EN,,0,0,0,,so that the thing, the garbage collector's distributed Dialogue: 0,0:37:31.20,0:37:32.19,EN,,0,0,0,,and the machine doesn't have to stop, Dialogue: 0,0:37:32.41,0:37:33.47,EN,,0,0,0,,and garbage collecting can start. Dialogue: 0,0:37:34.64,0:37:37.87,EN,,0,0,0,,Of course in the case of machines with virtual memory Dialogue: 0,0:37:38.90,0:37:41.20,EN,,0,0,0,,where a lot of it is in inaccessible places, Dialogue: 0,0:37:41.50,0:37:43.60,EN,,0,0,0,,this becomes a very expensive process. Dialogue: 0,0:37:44.28,0:37:46.43,EN,,0,0,0,,And there have been numerous Dialogue: 0,0:37:47.16,0:37:48.65,EN,,0,0,0,,attempts to make this much better. Dialogue: 0,0:37:49.19,0:37:51.15,EN,,0,0,0,,There is a nice paper, Dialogue: 0,0:37:51.16,0:37:52.41,EN,,0,0,0,,for those of you who are interested, Dialogue: 0,0:37:52.64,0:37:54.27,EN,,0,0,0,,by Moon and other people Dialogue: 0,0:37:54.65,0:37:56.89,EN,,0,0,0,,which describes a modification to Dialogue: 0,0:37:56.92,0:37:59.44,EN,,0,0,0,,the incremental Minsky-Fenichel-Yochelson algorithm, Dialogue: 0,0:37:59.51,0:38:01.20,EN,,0,0,0,,and modification the Baker algorithm Dialogue: 0,0:38:01.42,0:38:06.54,EN,,0,0,0,,which is more efficient for virtual memory systems. Dialogue: 0,0:38:08.27,0:38:12.32,EN,,0,0,0,,Well I think now the mystery to this is sort of gone. Dialogue: 0,0:38:12.84,0:38:14.09,EN,,0,0,0,,And I'd like to see if there are any questions. Dialogue: 0,0:38:19.78,0:38:19.95,EN,,0,0,0,,Yes. Dialogue: 0,0:38:20.60,0:38:23.58,EN,,0,0,0,,AUDIENCE: I saw one of you run the garbage collector Dialogue: 0,0:38:23.64,0:38:25.05,EN,,0,0,0,,on the systems upstairs, Dialogue: 0,0:38:25.93,0:38:27.88,EN,,0,0,0,,and it seemed to me to run extremely fast. Dialogue: 0,0:38:27.96,0:38:28.40,EN,,0,0,0,,PROFESSOR: Yes Dialogue: 0,0:38:28.49,0:38:29.52,EN,,0,0,0,,AUDIENCE: Did the whole thing take-- Dialogue: 0,0:38:30.11,0:38:31.88,EN,,0,0,0,,does it sweep through all of memory? Dialogue: 0,0:38:31.88,0:38:32.22,EN,,0,0,0,,PROFESSOR: No. Dialogue: 0,0:38:32.25,0:38:34.11,EN,,0,0,0,,It swept through exactly what was needed Dialogue: 0,0:38:34.33,0:38:35.63,EN,,0,0,0,,to copy the useful structure. Dialogue: 0,0:38:37.32,0:38:38.36,EN,,0,0,0,,It's a copying collector. Dialogue: 0,0:38:38.44,0:38:38.91,EN,,0,0,0,,AUDIENCE: OK. Dialogue: 0,0:38:39.30,0:38:40.88,EN,,0,0,0,,PROFESSOR: And it's rather... it is very fast. Dialogue: 0,0:38:41.85,0:38:45.88,EN,,0,0,0,,On the whole, I suppose to copy in a Bobcat Dialogue: 0,0:38:47.12,0:38:51.56,EN,,0,0,0,,to copy, I think, a three megabyte thing or something Dialogue: 0,0:38:52.43,0:38:53.24,EN,,0,0,0,,is less than a second, Dialogue: 0,0:38:55.00,0:38:55.69,EN,,0,0,0,,real time Dialogue: 0,0:38:56.54,0:38:58.46,EN,,0,0,0,,Really, these are very small programs. Dialogue: 0,0:38:58.62,0:39:01.50,EN,,0,0,0,,One thing you should realise is that Dialogue: 0,0:39:02.91,0:39:04.40,EN,,0,0,0,,garbage collectors have to be small. Dialogue: 0,0:39:05.40,0:39:07.10,EN,,0,0,0,,Not because they have to be fast, Dialogue: 0,0:39:07.90,0:39:09.23,EN,,0,0,0,,but because no one can debug Dialogue: 0,0:39:09.26,0:39:10.48,EN,,0,0,0,,a complicated garbage collector. Dialogue: 0,0:39:11.34,0:39:12.91,EN,,0,0,0,,A garbage collector, if it doesn't work, Dialogue: 0,0:39:14.04,0:39:15.93,EN,,0,0,0,,will trash your memory in such a way Dialogue: 0,0:39:15.93,0:39:17.39,EN,,0,0,0,,that you cannot figure out what the hell happened. Dialogue: 0,0:39:18.35,0:39:19.67,EN,,0,0,0,,You need an audit trail. Dialogue: 0,0:39:20.66,0:39:22.01,EN,,0,0,0,,Because it rearranges everything, Dialogue: 0,0:39:22.04,0:39:23.24,EN,,0,0,0,,and how do you know what happened there? Dialogue: 0,0:39:23.74,0:39:26.58,EN,,0,0,0,,So this is the only kind of program that Dialogue: 0,0:39:26.92,0:39:28.40,EN,,0,0,0,,it really, seriously matters Dialogue: 0,0:39:28.54,0:39:29.79,EN,,0,0,0,,if you stare at it long enough Dialogue: 0,0:39:29.82,0:39:31.07,EN,,0,0,0,,so you believe that it works. Dialogue: 0,0:39:31.34,0:39:33.36,EN,,0,0,0,,That means and sort of prove it to yourself. Dialogue: 0,0:39:33.92,0:39:36.11,EN,,0,0,0,,And that, that... So there's no way to debug it. Dialogue: 0,0:39:36.94,0:39:38.96,EN,,0,0,0,,And that takes it being small enough Dialogue: 0,0:39:38.96,0:39:39.97,EN,,0,0,0,,so you can hold it in your head. Dialogue: 0,0:39:41.45,0:39:43.90,EN,,0,0,0,,So garbage collectors are special in this way. Dialogue: 0,0:39:45.02,0:39:47.12,EN,,0,0,0,,So every reasonable garbage collector has gotten small, Dialogue: 0,0:39:47.13,0:39:48.45,EN,,0,0,0,,and generally small programs are fast. Dialogue: 0,0:39:52.05,0:39:52.43,EN,,0,0,0,,Yes. Dialogue: 0,0:39:52.43,0:39:54.51,EN,,0,0,0,,AUDIENCE: Can you repeat the name of this technique once again? Dialogue: 0,0:39:54.68,0:39:56.92,EN,,0,0,0,,PROFESSOR: That's the Minsky-Fenichel-Yochelson garbage collector. Dialogue: 0,0:39:57.88,0:39:58.43,EN,,0,0,0,,AUDIENCE: You got that? Dialogue: 0,0:39:59.00,0:40:00.78,EN,,0,0,0,,PROFESSOR: Minsky invented it in '61 Dialogue: 0,0:40:00.81,0:40:02.21,EN,,0,0,0,,for the RLE PDP-1. Dialogue: 0,0:40:02.21,0:40:06.17,EN,,0,0,0,,A version of it was developed and elaborated Dialogue: 0,0:40:06.45,0:40:10.27,EN,,0,0,0,,to be used in Multics Maclisp by Fenichel and Yochelson Dialogue: 0,0:40:11.37,0:40:14.75,EN,,0,0,0,,in somewhere around 1968 or '69. Dialogue: 0,0:40:19.57,0:40:21.36,EN,,0,0,0,,OK. Let's take a break. Dialogue: 0,0:40:22.64,0:40:32.36,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:41:17.31,0:41:19.67,EN,,0,0,0,,PROFESSOR: Well we've come to the end of this subject, Dialogue: 0,0:41:20.08,0:41:23.85,EN,,0,0,0,,and we've already shown you a universal machine Dialogue: 0,0:41:24.47,0:41:26.74,EN,,0,0,0,,which is down to evaluator. Dialogue: 0,0:41:27.02,0:41:28.38,EN,,0,0,0,,It's down to the level of detail Dialogue: 0,0:41:28.38,0:41:29.67,EN,,0,0,0,,you could imagine you could make one. Dialogue: 0,0:41:30.19,0:41:33.32,EN,,0,0,0,,This is a particular implementation of Lisp, Dialogue: 0,0:41:33.90,0:41:36.01,EN,,0,0,0,,built on one of those Dialogue: 0,0:41:36.16,0:41:38.05,EN,,0,0,0,,scheme chips that was talked about yesterday, Dialogue: 0,0:41:38.20,0:41:38.91,EN,,0,0,0,,sitting over here. Dialogue: 0,0:41:39.35,0:41:42.00,EN,,0,0,0,,This is mostly interface to somebody's memory Dialogue: 0,0:41:42.60,0:41:44.75,EN,,0,0,0,,with a little bit of timing and other such stuff. Dialogue: 0,0:41:45.22,0:41:47.25,EN,,0,0,0,,But this fellow actually ran Lisp Dialogue: 0,0:41:47.77,0:41:50.17,EN,,0,0,0,,at a fairly reasonable rate, as interpretive. Dialogue: 0,0:41:50.61,0:41:53.82,EN,,0,0,0,,It ran Lisp as fast as a DEC PDP-10 Dialogue: 0,0:41:54.22,0:41:55.65,EN,,0,0,0,,back in 1979. Dialogue: 0,0:41:56.50,0:41:59.67,EN,,0,0,0,,And so it's gotten pretty hardware. Dialogue: 0,0:42:00.02,0:42:00.89,EN,,0,0,0,,Pretty concrete. Dialogue: 0,0:42:02.47,0:42:04.70,EN,,0,0,0,,We've also downed you a bit Dialogue: 0,0:42:04.72,0:42:06.07,EN,,0,0,0,,with the things you can compute. Dialogue: 0,0:42:07.37,0:42:08.76,EN,,0,0,0,,But is it the case that Dialogue: 0,0:42:09.32,0:42:10.55,EN,,0,0,0,,there are things we can't compute? Dialogue: 0,0:42:11.85,0:42:13.50,EN,,0,0,0,,And so I'd like to end this with Dialogue: 0,0:42:13.75,0:42:15.87,EN,,0,0,0,,showing you some things that you'd like be able to compute Dialogue: 0,0:42:16.60,0:42:17.22,EN,,0,0,0,,that you can't. Dialogue: 0,0:42:18.19,0:42:19.45,EN,,0,0,0,,The answer is yes, Dialogue: 0,0:42:19.45,0:42:20.82,EN,,0,0,0,,there are things you can't compute. Dialogue: 0,0:42:22.72,0:42:23.47,EN,,0,0,0,,For example, Dialogue: 0,0:42:24.45,0:42:25.82,EN,,0,0,0,,something you'd really like is-- Dialogue: 0,0:42:27.80,0:42:29.36,EN,,0,0,0,,if you're writing a compiler Dialogue: 0,0:42:29.77,0:42:31.42,EN,,0,0,0,,you'd like a program that would check Dialogue: 0,0:42:32.00,0:42:33.97,EN,,0,0,0,,that the thing you're going to do will work. Dialogue: 0,0:42:34.63,0:42:35.40,EN,,0,0,0,,Wouldn't that be nice? Dialogue: 0,0:42:36.08,0:42:37.87,EN,,0,0,0,,You'd like something that would catch infinite loops, Dialogue: 0,0:42:37.87,0:42:38.54,EN,,0,0,0,,for example, Dialogue: 0,0:42:39.45,0:42:42.42,EN,,0,0,0,,in programs that were written by users. Dialogue: 0,0:42:43.19,0:42:45.12,EN,,0,0,0,,But in general you can't write such a program Dialogue: 0,0:42:45.35,0:42:46.49,EN,,0,0,0,,that will read any program Dialogue: 0,0:42:46.51,0:42:47.45,EN,,0,0,0,,and determine whether or not Dialogue: 0,0:42:48.35,0:42:49.30,EN,,0,0,0,,it's an infinite loop. Dialogue: 0,0:42:50.99,0:42:51.71,EN,,0,0,0,,Let me show you that. Dialogue: 0,0:42:51.76,0:42:53.80,EN,,0,0,0,,It's a little bit of a minor mathematics. Dialogue: 0,0:42:58.78,0:42:59.65,EN,,0,0,0,,Let's imagine Dialogue: 0,0:43:00.05,0:43:01.78,EN,,0,0,0,,that we just had a mathematical function Dialogue: 0,0:43:01.78,0:43:02.62,EN,,0,0,0,,before we start. Dialogue: 0,0:43:02.62,0:43:03.42,EN,,0,0,0,,And there is one, Dialogue: 0,0:43:03.84,0:43:04.67,EN,,0,0,0,,called s, Dialogue: 0,0:43:05.47,0:43:07.54,EN,,0,0,0,,which takes a procedure Dialogue: 0,0:43:12.64,0:43:14.23,EN,,0,0,0,,and its argument, a. Dialogue: 0,0:43:19.17,0:43:20.52,EN,,0,0,0,,And what s does Dialogue: 0,0:43:21.65,0:43:24.01,EN,,0,0,0,,is it determines whether or not Dialogue: 0,0:43:24.01,0:43:25.97,EN,,0,0,0,,it's safe to run p on a. Dialogue: 0,0:43:26.90,0:43:28.17,EN,,0,0,0,,And what I mean by that is this: Dialogue: 0,0:43:28.76,0:43:35.12,EN,,0,0,0,,it's true if p applied to a Dialogue: 0,0:43:35.62,0:43:36.74,EN,,0,0,0,,will converge Dialogue: 0,0:43:41.40,0:43:42.45,EN,,0,0,0,,to a value Dialogue: 0,0:43:44.35,0:43:45.33,EN,,0,0,0,,without an error. Dialogue: 0,0:43:52.70,0:43:53.68,EN,,0,0,0,,And it's false Dialogue: 0,0:43:56.10,0:43:57.04,EN,,0,0,0,,if p of a Dialogue: 0,0:43:59.67,0:44:00.76,EN,,0,0,0,,loops forever Dialogue: 0,0:44:05.87,0:44:06.95,EN,,0,0,0,,or makes an error. Dialogue: 0,0:44:15.23,0:44:17.22,EN,,0,0,0,,Now that's surely a function. Dialogue: 0,0:44:18.78,0:44:20.72,EN,,0,0,0,,There is some for every procedure Dialogue: 0,0:44:21.20,0:44:22.85,EN,,0,0,0,,and for every argument you could give it Dialogue: 0,0:44:23.92,0:44:25.45,EN,,0,0,0,,that is either true or false Dialogue: 0,0:44:25.92,0:44:27.85,EN,,0,0,0,,that it converges without making an error. Dialogue: 0,0:44:28.44,0:44:30.15,EN,,0,0,0,,And you could make a giant table of them. Dialogue: 0,0:44:32.22,0:44:32.92,EN,,0,0,0,,But the question is, Dialogue: 0,0:44:32.92,0:44:34.09,EN,,0,0,0,,can you write a procedure Dialogue: 0,0:44:34.09,0:44:35.92,EN,,0,0,0,,that compute the values of this function? Dialogue: 0,0:44:37.43,0:44:38.92,EN,,0,0,0,,Well let's assume that we can. Dialogue: 0,0:44:39.72,0:44:40.55,EN,,0,0,0,,Suppose Dialogue: 0,0:44:44.33,0:44:45.58,EN,,0,0,0,,that we have a procedure Dialogue: 0,0:44:48.55,0:44:52.73,EN,,0,0,0,,procedure called "safe" Dialogue: 0,0:44:56.54,0:44:59.90,EN,,0,0,0,,that computes the value of s. Dialogue: 0,0:45:12.65,0:45:14.89,EN,,0,0,0,,Now I'm going to show you by several methods Dialogue: 0,0:45:15.90,0:45:18.51,EN,,0,0,0,,that you can't do this. Dialogue: 0,0:45:19.76,0:45:20.62,EN,,0,0,0,,The easiest one, Dialogue: 0,0:45:20.62,0:45:21.28,EN,,0,0,0,,or the first one, Dialogue: 0,0:45:21.31,0:45:23.45,EN,,0,0,0,,let's define a procedure called diag1. Dialogue: 0,0:45:23.76,0:45:24.86,EN,,0,0,0,,Given that we have safe, Dialogue: 0,0:45:25.20,0:45:26.99,EN,,0,0,0,,we can define diag1 Dialogue: 0,0:45:34.42,0:45:35.55,EN,,0,0,0,,diag1 Dialogue: 0,0:45:37.82,0:45:41.60,EN,,0,0,0,,to be the procedure of one argument, p, Dialogue: 0,0:45:42.45,0:45:44.05,EN,,0,0,0,,which has the following properties. Dialogue: 0,0:45:44.78,0:45:50.67,EN,,0,0,0,,If it's safe to apply p to itself, Dialogue: 0,0:45:53.32,0:45:55.32,EN,,0,0,0,,then I wish to have an infinite loop. Dialogue: 0,0:45:59.22,0:46:00.92,EN,,0,0,0,,Otherwise I'm going to return 3. Dialogue: 0,0:46:03.68,0:46:04.47,EN,,0,0,0,,Maybe it was 42. Dialogue: 0,0:46:04.47,0:46:06.42,EN,,0,0,0,,What's the answer to the big question? Dialogue: 0,0:46:07.06,0:46:08.87,EN,,0,0,0,,Where of course we know what an infinite loop is. Dialogue: 0,0:46:12.05,0:46:12.96,EN,,0,0,0,,Infinite loop, Dialogue: 0,0:46:13.82,0:46:16.02,EN,,0,0,0,,to be a procedure of no arguments, Dialogue: 0,0:46:16.02,0:46:18.07,EN,,0,0,0,,which is that nice lambda calculus loop. Dialogue: 0,0:46:18.35,0:46:20.44,EN,,0,0,0,,Lambda of x, Dialogue: 0,0:46:21.30,0:46:24.68,EN,,0,0,0,,applied to lambda of x, x of x. Dialogue: 0,0:46:24.68,0:46:26.55,EN,,0,0,0,,So there's nothing left to the imagination here. Dialogue: 0,0:46:29.83,0:46:31.17,EN,,0,0,0,,Well let's see what the story is. Dialogue: 0,0:46:32.50,0:46:33.90,EN,,0,0,0,,I'm supposing it's the case Dialogue: 0,0:46:35.45,0:46:38.77,EN,,0,0,0,,that we worry about the procedure Dialogue: 0,0:46:39.00,0:46:43.45,EN,,0,0,0,,called diag1 applied to diag1. Dialogue: 0,0:46:46.27,0:46:47.77,EN,,0,0,0,,Well what could it possibly be? Dialogue: 0,0:46:49.97,0:46:51.39,EN,,0,0,0,,Well I don't know. Dialogue: 0,0:46:51.39,0:46:53.21,EN,,0,0,0,,We're going to substitute diag1 Dialogue: 0,0:46:53.55,0:46:55.50,EN,,0,0,0,,for p in the body here. Dialogue: 0,0:46:57.31,0:47:00.22,EN,,0,0,0,,Well is it safe to compute diag1 of diag1? Dialogue: 0,0:47:00.22,0:47:00.78,EN,,0,0,0,,I don't know. Dialogue: 0,0:47:00.78,0:47:01.82,EN,,0,0,0,,There are two possibilities. Dialogue: 0,0:47:03.40,0:47:05.50,EN,,0,0,0,,If it's safe to compute diag1 of diag1 Dialogue: 0,0:47:05.92,0:47:06.89,EN,,0,0,0,,that means it shouldn't loop. Dialogue: 0,0:47:08.49,0:47:09.22,EN,,0,0,0,,That means I go to here, Dialogue: 0,0:47:09.22,0:47:10.35,EN,,0,0,0,,but then I produce an infinite loop. Dialogue: 0,0:47:10.56,0:47:11.57,EN,,0,0,0,,So it can't be safe. Dialogue: 0,0:47:12.21,0:47:14.78,EN,,0,0,0,,But if it's not safe to compute diag1 of diag1 Dialogue: 0,0:47:14.90,0:47:16.02,EN,,0,0,0,,then the answer to this is 3. Dialogue: 0,0:47:16.02,0:47:17.26,EN,,0,0,0,,But that's diag1 of diag1, Dialogue: 0,0:47:17.26,0:47:17.93,EN,,0,0,0,,so it had to be safe. Dialogue: 0,0:47:20.53,0:47:23.60,EN,,0,0,0,,So therefore by contradiction Dialogue: 0,0:47:24.32,0:47:26.30,EN,,0,0,0,,you cannot produce safe. Dialogue: 0,0:47:27.40,0:47:29.80,EN,,0,0,0,,For those of you who were boggled by that one Dialogue: 0,0:47:30.25,0:47:32.15,EN,,0,0,0,,I'm going to say it again, in a different way. Dialogue: 0,0:47:32.82,0:47:34.00,EN,,0,0,0,,Listen to one more alternative. Dialogue: 0,0:47:35.53,0:47:36.95,EN,,0,0,0,,Let's define diag2. Dialogue: 0,0:47:39.84,0:47:41.60,EN,,0,0,0,,These are named diag because Dialogue: 0,0:47:42.65,0:47:44.72,EN,,0,0,0,,of Cantor's diagonal argument. Dialogue: 0,0:47:45.00,0:47:47.05,EN,,0,0,0,,These are instances of Dialogue: 0,0:47:47.05,0:47:49.05,EN,,0,0,0,,a famous argument which was originally used by Dialogue: 0,0:47:49.45,0:47:52.65,EN,,0,0,0,,Cantor in the late part of the last century Dialogue: 0,0:47:52.77,0:47:56.10,EN,,0,0,0,,to prove that the real numbers were not countable, Dialogue: 0,0:47:56.67,0:47:58.00,EN,,0,0,0,,that there are too many real numbers Dialogue: 0,0:47:58.06,0:47:59.42,EN,,0,0,0,,to be counted by integers. Dialogue: 0,0:48:00.19,0:48:01.74,EN,,0,0,0,,That there are more points on a line, Dialogue: 0,0:48:01.74,0:48:02.50,EN,,0,0,0,,for example, Dialogue: 0,0:48:02.50,0:48:04.42,EN,,0,0,0,,than there are counting numbers. Dialogue: 0,0:48:05.26,0:48:06.85,EN,,0,0,0,,It may or may not be obvious, Dialogue: 0,0:48:06.85,0:48:08.17,EN,,0,0,0,,and I don't want to get into that now. Dialogue: 0,0:48:10.90,0:48:12.45,EN,,0,0,0,,But diag2 Dialogue: 0,0:48:13.30,0:48:15.82,EN,,0,0,0,,is again a procedure of one argument p. Dialogue: 0,0:48:15.82,0:48:17.47,EN,,0,0,0,,It's almost the same as the previous one, Dialogue: 0,0:48:17.72,0:48:24.32,EN,,0,0,0,,which is, if it's safe to compute p on p, Dialogue: 0,0:48:25.17,0:48:26.67,EN,,0,0,0,,then I'm going to produce-- Dialogue: 0,0:48:27.26,0:48:28.14,EN,,0,0,0,,Oops, if Dialogue: 0,0:48:29.31,0:48:31.02,EN,,0,0,0,,then I want to compute Dialogue: 0,0:48:31.57,0:48:37.58,EN,,0,0,0,,some other things Dialogue: 0,0:48:38.96,0:48:40.21,EN,,0,0,0,,Otherwise I'm going to put out false. Dialogue: 0,0:48:43.60,0:48:45.30,EN,,0,0,0,,Where other then it says, Dialogue: 0,0:48:45.47,0:48:46.35,EN,,0,0,0,,whatever p of p, Dialogue: 0,0:48:46.35,0:48:47.47,EN,,0,0,0,,I'm going to put out something else. Dialogue: 0,0:48:48.88,0:48:50.03,EN,,0,0,0,,I can give you an example of Dialogue: 0,0:48:50.07,0:48:51.52,EN,,0,0,0,,a definition of other than Dialogue: 0,0:48:51.60,0:48:52.57,EN,,0,0,0,,which I think works. Dialogue: 0,0:48:53.89,0:48:54.51,EN,,0,0,0,,Let's see. Dialogue: 0,0:48:55.64,0:48:56.08,EN,,0,0,0,,Yes. Dialogue: 0,0:48:56.33,0:48:57.26,EN,,0,0,0,,Where other than Dialogue: 0,0:49:04.03,0:49:06.11,EN,,0,0,0,,be a procedure of one argument x Dialogue: 0,0:49:06.57,0:49:07.26,EN,,0,0,0,,which says, Dialogue: 0,0:49:08.05,0:49:12.96,EN,,0,0,0,,if its eq x to, say, quote a, Dialogue: 0,0:49:13.47,0:49:15.07,EN,,0,0,0,,then the answer is quote b. Dialogue: 0,0:49:15.72,0:49:16.80,EN,,0,0,0,,Otherwise it's quote a. Dialogue: 0,0:49:20.27,0:49:21.90,EN,,0,0,0,,That always produces something Dialogue: 0,0:49:22.07,0:49:23.45,EN,,0,0,0,,which is not what its argument is. Dialogue: 0,0:49:25.20,0:49:26.12,EN,,0,0,0,,That's all it is. Dialogue: 0,0:49:26.54,0:49:27.37,EN,,0,0,0,,That's all I wanted. Dialogue: 0,0:49:28.25,0:49:29.58,EN,,0,0,0,,Well now let's consider this one, Dialogue: 0,0:49:29.58,0:49:31.15,EN,,0,0,0,,diag2 of diag2. Dialogue: 0,0:49:38.28,0:49:38.94,EN,,0,0,0,,Well look. Dialogue: 0,0:49:39.95,0:49:41.72,EN,,0,0,0,,This only does something dangerous, Dialogue: 0,0:49:42.00,0:49:43.45,EN,,0,0,0,,like calling p of p, Dialogue: 0,0:49:44.75,0:49:45.95,EN,,0,0,0,,if it's safe to do so. Dialogue: 0,0:49:47.47,0:49:49.16,EN,,0,0,0,,So if safe defined at all, Dialogue: 0,0:49:50.30,0:49:52.49,EN,,0,0,0,,if you can define such a procedure, safe, Dialogue: 0,0:49:52.97,0:49:54.32,EN,,0,0,0,,then this procedure Dialogue: 0,0:49:54.60,0:49:56.40,EN,,0,0,0,,is always defined and therefore safe Dialogue: 0,0:49:56.52,0:49:57.22,EN,,0,0,0,,on any inputs. Dialogue: 0,0:50:01.54,0:50:03.50,EN,,0,0,0,,So diag2 of diag2 Dialogue: 0,0:50:03.87,0:50:12.20,EN,,0,0,0,,must reduce to other than diag2 of diag2. Dialogue: 0,0:50:15.82,0:50:16.97,EN,,0,0,0,,And that doesn't make sense, Dialogue: 0,0:50:17.80,0:50:19.02,EN,,0,0,0,,so we have a contradiction, Dialogue: 0,0:50:19.85,0:50:21.57,EN,,0,0,0,,and therefore we can't define safe. Dialogue: 0,0:50:22.95,0:50:24.23,EN,,0,0,0,,I just waned to do that twice, Dialogue: 0,0:50:24.78,0:50:25.82,EN,,0,0,0,,slightly differently, Dialogue: 0,0:50:26.84,0:50:27.90,EN,,0,0,0,,so you wouldn't feel Dialogue: 0,0:50:29.07,0:50:30.86,EN,,0,0,0,,that the first one was a trick. Dialogue: 0,0:50:32.54,0:50:33.45,EN,,0,0,0,,They may be both tricks, Dialogue: 0,0:50:33.80,0:50:35.15,EN,,0,0,0,,but they're at least slightly different. Dialogue: 0,0:50:37.30,0:50:39.20,EN,,0,0,0,,So I suppose that pretty much wraps it up. Dialogue: 0,0:50:40.03,0:50:41.97,EN,,0,0,0,,I've just proved what we call the halting theorem, Dialogue: 0,0:50:43.00,0:50:44.70,EN,,0,0,0,,and I suppose with that we're going to halt. Dialogue: 0,0:50:46.72,0:50:47.63,EN,,0,0,0,,I hope you have a good time. Dialogue: 0,0:50:50.90,0:50:51.76,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:50:53.30,0:50:53.56,EN,,0,0,0,,Yes. Dialogue: 0,0:50:53.81,0:50:56.27,EN,,0,0,0,,AUDIENCE: What is the value of s of diag1? Dialogue: 0,0:50:56.75,0:50:57.23,EN,,0,0,0,,PROFESSOR: Of what? Dialogue: 0,0:50:57.50,0:50:58.80,EN,,0,0,0,,AUDIENCE: S of diag1. Dialogue: 0,0:51:00.12,0:51:02.20,EN,,0,0,0,,If you said s is a function, and then we can Dialogue: 0,0:51:02.30,0:51:03.63,EN,,0,0,0,,PROFESSOR: Oh, I don't know. Dialogue: 0,0:51:03.87,0:51:04.35,EN,,0,0,0,,I don't know. Dialogue: 0,0:51:04.35,0:51:04.88,EN,,0,0,0,,It's a function, Dialogue: 0,0:51:04.88,0:51:05.85,EN,,0,0,0,,but I don't know how to compute it. Dialogue: 0,0:51:06.80,0:51:08.00,EN,,0,0,0,,I can't do it. Dialogue: 0,0:51:08.61,0:51:09.64,EN,,0,0,0,,I'm just a machine, too. Dialogue: 0,0:51:11.53,0:51:11.88,EN,,0,0,0,,Right? Dialogue: 0,0:51:11.90,0:51:13.37,EN,,0,0,0,,And there's no machine Dialogue: 0,0:51:13.37,0:51:14.05,EN,,0,0,0,,that in principle-- Dialogue: 0,0:51:14.47,0:51:16.87,EN,,0,0,0,,it might be that in that particular case you just asked, Dialogue: 0,0:51:16.87,0:51:18.32,EN,,0,0,0,,with some thinking I could figure it out. Dialogue: 0,0:51:18.58,0:51:19.37,EN,,0,0,0,,But in general Dialogue: 0,0:51:19.60,0:51:21.05,EN,,0,0,0,,I can't compute the value of s Dialogue: 0,0:51:21.05,0:51:22.52,EN,,0,0,0,,any better than any other machine can. Dialogue: 0,0:51:23.78,0:51:24.92,EN,,0,0,0,,There is such a function, Dialogue: 0,0:51:25.92,0:51:28.00,EN,,0,0,0,,it's just that no machine can be built to compute it. Dialogue: 0,0:51:29.58,0:51:30.05,EN,,0,0,0,,Now Dialogue: 0,0:51:30.67,0:51:33.67,EN,,0,0,0,,there's a way of saying that that should not be surprising. Dialogue: 0,0:51:35.22,0:51:36.25,EN,,0,0,0,,Going through this-- Dialogue: 0,0:51:36.25,0:51:38.36,EN,,0,0,0,,I mean, I don't have time to do this here, Dialogue: 0,0:51:38.45,0:51:43.00,EN,,0,0,0,,but the number of functions is very large. Dialogue: 0,0:51:44.40,0:51:47.58,EN,,0,0,0,,If there's a certain number of answers possible Dialogue: 0,0:51:47.75,0:51:49.62,EN,,0,0,0,,and a certain number of inputs possible, Dialogue: 0,0:51:49.87,0:51:51.80,EN,,0,0,0,,then it's the number of answers raised to the number inputs Dialogue: 0,0:51:51.80,0:51:53.20,EN,,0,0,0,,is the number of possible functions. Dialogue: 0,0:51:54.50,0:51:55.48,EN,,0,0,0,,On one variable. Dialogue: 0,0:51:56.51,0:51:59.24,EN,,0,0,0,,Now that's always bigger Dialogue: 0,0:52:00.09,0:52:03.21,EN,,0,0,0,,than the thing you're raising to, Dialogue: 0,0:52:03.58,0:52:04.32,EN,,0,0,0,,the exponent. Dialogue: 0,0:52:05.48,0:52:09.80,EN,,0,0,0,,The number of functions is larger Dialogue: 0,0:52:09.95,0:52:12.72,EN,,0,0,0,,than the number of programs Dialogue: 0,0:52:13.30,0:52:14.10,EN,,0,0,0,,that one can write, Dialogue: 0,0:52:14.82,0:52:16.45,EN,,0,0,0,,by an infinity counting argument. Dialogue: 0,0:52:17.57,0:52:19.00,EN,,0,0,0,,And it's much larger. Dialogue: 0,0:52:19.47,0:52:22.12,EN,,0,0,0,,So there must be a lot of functions Dialogue: 0,0:52:22.12,0:52:23.48,EN,,0,0,0,,that can't be computed by programs. Dialogue: 0,0:52:25.92,0:52:26.59,EN,,0,0,0,,AUDIENCE: A few moments ago Dialogue: 0,0:52:26.64,0:52:28.25,EN,,0,0,0,,you were talking about specifications Dialogue: 0,0:52:28.30,0:52:30.04,EN,,0,0,0,,and automatic generation of solutions. Dialogue: 0,0:52:30.64,0:52:31.61,EN,,0,0,0,,Do you see any steps Dialogue: 0,0:52:31.82,0:52:33.36,EN,,0,0,0,,between specifications and solutions? Dialogue: 0,0:52:37.25,0:52:38.22,EN,,0,0,0,,PROFESSOR: Steps between. Dialogue: 0,0:52:38.72,0:52:39.37,EN,,0,0,0,,You mean, you're saying, Dialogue: 0,0:52:39.37,0:52:42.60,EN,,0,0,0,,how you go about constructing Dialogue: 0,0:52:42.60,0:52:44.78,EN,,0,0,0,,devices given that have specifications for the device? Dialogue: 0,0:52:45.05,0:52:48.36,EN,,0,0,0,,AUDIENCE: There's a lot of software engineering Dialogue: 0,0:52:48.36,0:52:49.90,EN,,0,0,0,,that goes through specifications through Dialogue: 0,0:52:49.90,0:52:51.90,EN,,0,0,0,,many layers of design and then implementation. Dialogue: 0,0:52:52.43,0:52:52.85,EN,,0,0,0,,PROFESSOR: Yes? Dialogue: 0,0:52:52.85,0:52:53.70,EN,,0,0,0,,AUDIENCE: I was curious Dialogue: 0,0:52:53.70,0:52:54.62,EN,,0,0,0,,if you think that's realistic. Dialogue: 0,0:52:55.60,0:52:57.17,EN,,0,0,0,,PROFESSOR: Well I think that some of it's realistic Dialogue: 0,0:52:57.17,0:52:58.10,EN,,0,0,0,,and some of it isn't. Dialogue: 0,0:52:58.10,0:53:00.32,EN,,0,0,0,,I mean, surely if I want to build an electrical filter Dialogue: 0,0:53:01.17,0:53:07.16,EN,,0,0,0,,and I have a rather interesting possibility. Dialogue: 0,0:53:07.16,0:53:09.42,EN,,0,0,0,,Supposing I want to build a thing that matches Dialogue: 0,0:53:09.64,0:53:14.07,EN,,0,0,0,,that matches some power output to the radio transmitter, Dialogue: 0,0:53:14.47,0:53:18.75,EN,,0,0,0,,to some antenna. Dialogue: 0,0:53:19.90,0:53:21.47,EN,,0,0,0,,And I'm really out of this power-- Dialogue: 0,0:53:21.48,0:53:23.04,EN,,0,0,0,,it's output tube out here. Dialogue: 0,0:53:23.23,0:53:25.26,EN,,0,0,0,,And the problem is that they have different impedances. Dialogue: 0,0:53:25.92,0:53:27.55,EN,,0,0,0,,I want them to match the impedances. Dialogue: 0,0:53:27.55,0:53:28.97,EN,,0,0,0,,I also want to make a filter in there Dialogue: 0,0:53:29.15,0:53:31.71,EN,,0,0,0,,which is going to get rid of some harmonic radiation. Dialogue: 0,0:53:32.78,0:53:36.63,EN,,0,0,0,,Well one old-fashioned technique for doing this is called Dialogue: 0,0:53:36.82,0:53:38.67,EN,,0,0,0,,image impedances, or something like that. Dialogue: 0,0:53:38.86,0:53:39.50,EN,,0,0,0,,And what you do Dialogue: 0,0:53:39.50,0:53:40.85,EN,,0,0,0,,is you say you have a basic module Dialogue: 0,0:53:40.85,0:53:42.75,EN,,0,0,0,,called an L-section. Dialogue: 0,0:53:43.30,0:53:43.98,EN,,0,0,0,,Looks like this. Dialogue: 0,0:53:47.08,0:53:49.80,EN,,0,0,0,,If I happen to connect this to some resistance, r, Dialogue: 0,0:53:50.05,0:53:52.60,EN,,0,0,0,,and if I make this impedance x, xl, Dialogue: 0,0:53:52.72,0:53:55.20,EN,,0,0,0,,and if it happens to be q times r, Dialogue: 0,0:53:55.26,0:53:58.52,EN,,0,0,0,,then this produces a low pass filter Dialogue: 0,0:53:58.52,0:54:00.72,EN,,0,0,0,,with a q square plus one impedance match. Dialogue: 0,0:54:02.11,0:54:02.86,EN,,0,0,0,,Just what I need. Dialogue: 0,0:54:03.12,0:54:04.28,EN,,0,0,0,,Because now I can take two of these, Dialogue: 0,0:54:04.30,0:54:05.08,EN,,0,0,0,,hook them together Dialogue: 0,0:54:05.82,0:54:06.38,EN,,0,0,0,,like this. Dialogue: 0,0:54:11.66,0:54:13.15,EN,,0,0,0,,OK, and I take another one Dialogue: 0,0:54:16.00,0:54:17.45,EN,,0,0,0,,and I'll hook them together like that. Dialogue: 0,0:54:18.29,0:54:19.95,EN,,0,0,0,,And I have two L-sections hooked together. Dialogue: 0,0:54:20.32,0:54:23.07,EN,,0,0,0,,And this will step the impedance down to one that I know, Dialogue: 0,0:54:23.37,0:54:25.22,EN,,0,0,0,,and this will step it up to one I know. Dialogue: 0,0:54:25.53,0:54:26.64,EN,,0,0,0,,Each of these is a low pass filter Dialogue: 0,0:54:26.67,0:54:27.82,EN,,0,0,0,,getting rid of some harmonics. Dialogue: 0,0:54:28.09,0:54:29.07,EN,,0,0,0,,It's good filter, Dialogue: 0,0:54:29.07,0:54:30.27,EN,,0,0,0,,it's called a pie-section filter. Dialogue: 0,0:54:30.27,0:54:30.62,EN,,0,0,0,,Great. Dialogue: 0,0:54:31.70,0:54:34.09,EN,,0,0,0,,Except for the fact that in doing what I just did, Dialogue: 0,0:54:34.12,0:54:37.85,EN,,0,0,0,,I've made a terrible inefficiency in this system. Dialogue: 0,0:54:38.62,0:54:39.60,EN,,0,0,0,,I've made two coils Dialogue: 0,0:54:39.61,0:54:40.59,EN,,0,0,0,,where I should have made one. Dialogue: 0,0:54:41.62,0:54:44.60,EN,,0,0,0,,And the problem with most software engineering art Dialogue: 0,0:54:44.89,0:54:46.88,EN,,0,0,0,,is that there's no mechanism, Dialogue: 0,0:54:46.92,0:54:48.65,EN,,0,0,0,,other than people optimization and compilers, Dialogue: 0,0:54:48.80,0:54:51.34,EN,,0,0,0,,for getting rid of the redundant parts Dialogue: 0,0:54:51.34,0:54:53.55,EN,,0,0,0,,that are constructed when doing top down design. Dialogue: 0,0:54:55.35,0:54:56.07,EN,,0,0,0,,It's even worse, Dialogue: 0,0:54:56.07,0:54:57.58,EN,,0,0,0,,there are lots of very important structures Dialogue: 0,0:54:57.60,0:54:59.02,EN,,0,0,0,,that you can't construct at all this way. Dialogue: 0,0:55:01.11,0:55:03.53,EN,,0,0,0,,So I think that the standard top down design Dialogue: 0,0:55:03.53,0:55:04.87,EN,,0,0,0,,is a rather shallow business. Dialogue: 0,0:55:05.71,0:55:06.60,EN,,0,0,0,,Doesn't really capture Dialogue: 0,0:55:06.60,0:55:08.10,EN,,0,0,0,,what people want to do in design. Dialogue: 0,0:55:08.31,0:55:10.10,EN,,0,0,0,,I'll give you another electrical example. Dialogue: 0,0:55:10.10,0:55:11.75,EN,,0,0,0,,Electrical examples are so much clearer Dialogue: 0,0:55:11.90,0:55:13.13,EN,,0,0,0,,than computational examples, Dialogue: 0,0:55:13.16,0:55:14.78,EN,,0,0,0,,because computation examples require Dialogue: 0,0:55:14.80,0:55:16.52,EN,,0,0,0,,a certain degree of complexity to explain them. Dialogue: 0,0:55:17.22,0:55:19.16,EN,,0,0,0,,But one of my favorite examples Dialogue: 0,0:55:19.16,0:55:20.04,EN,,0,0,0,,in the electrical world Dialogue: 0,0:55:20.60,0:55:22.80,EN,,0,0,0,,is how would I ever come up with the output stage Dialogue: 0,0:55:23.28,0:55:26.55,EN,,0,0,0,,of this inter-stage connection in an IF amplifier. Dialogue: 0,0:55:27.53,0:55:29.44,EN,,0,0,0,,It's a little transistor here, Dialogue: 0,0:55:29.52,0:55:31.50,EN,,0,0,0,,and let's see. Dialogue: 0,0:55:32.41,0:55:33.40,EN,,0,0,0,,Well I'm going to have a tank, Dialogue: 0,0:55:36.45,0:55:39.17,EN,,0,0,0,,and I'm going to hook this up to, say, Dialogue: 0,0:55:41.37,0:55:43.97,EN,,0,0,0,,I'm going to link-couple that to the input of the next stage. Dialogue: 0,0:55:44.36,0:55:47.47,EN,,0,0,0,,Here's a perfectly plausible plan-- Dialogue: 0,0:55:48.22,0:55:50.87,EN,,0,0,0,,well except for the fact that since I put that going up Dialogue: 0,0:55:50.87,0:55:52.92,EN,,0,0,0,,I should make that going that way. OK? Dialogue: 0,0:55:53.17,0:55:55.45,EN,,0,0,0,,Here's a perfectly plausible plan for a-- Dialogue: 0,0:55:55.98,0:55:56.57,EN,,0,0,0,,no I shouldn't. Dialogue: 0,0:55:57.12,0:55:57.79,EN,,0,0,0,,I'm dumb. Dialogue: 0,0:55:58.40,0:55:59.07,EN,,0,0,0,,Excuse me. Dialogue: 0,0:55:59.69,0:56:00.42,EN,,0,0,0,,Doesn't matter. Dialogue: 0,0:56:00.73,0:56:01.54,EN,,0,0,0,,The point is it's a perfect Dialogue: 0,0:56:01.54,0:56:03.42,EN,,0,0,0,,plan for a couple two stages together. Dialogue: 0,0:56:04.54,0:56:06.92,EN,,0,0,0,,Now what the problem is what's this hierarchically? Dialogue: 0,0:56:07.62,0:56:08.80,EN,,0,0,0,,It's not one thing. Dialogue: 0,0:56:09.48,0:56:11.99,EN,,0,0,0,,Hierarchically it doesn't make any sense at all. Dialogue: 0,0:56:11.99,0:56:14.32,EN,,0,0,0,,It's the inductance of a tuned circuit, Dialogue: 0,0:56:15.55,0:56:18.02,EN,,0,0,0,,it's the primary of a transformer, Dialogue: 0,0:56:19.10,0:56:21.82,EN,,0,0,0,,and it's also the DC path by Dialogue: 0,0:56:21.82,0:56:23.57,EN,,0,0,0,,which bias conditions get to the Dialogue: 0,0:56:23.57,0:56:25.10,EN,,0,0,0,,collector of that transistor. Dialogue: 0,0:56:26.46,0:56:28.35,EN,,0,0,0,,And there's no simple top-down design Dialogue: 0,0:56:28.38,0:56:30.17,EN,,0,0,0,,that's going to produce a structure like that Dialogue: 0,0:56:30.22,0:56:34.02,EN,,0,0,0,,with so many overlapping uses for a particular thing. Dialogue: 0,0:56:34.53,0:56:36.72,EN,,0,0,0,,Playing Scrabble, Dialogue: 0,0:56:36.96,0:56:39.88,EN,,0,0,0,,where you have to do triple word scores, or whatever, Dialogue: 0,0:56:40.49,0:56:43.60,EN,,0,0,0,,is not so easy in top-down design strategy. Dialogue: 0,0:56:44.95,0:56:47.08,EN,,0,0,0,,Yet most of real engineering is based on Dialogue: 0,0:56:47.36,0:56:50.70,EN,,0,0,0,,on getting the most oomph for effort. Dialogue: 0,0:56:52.14,0:56:53.52,EN,,0,0,0,,And that's what you're seeing here. Dialogue: 0,0:56:54.86,0:56:55.55,EN,,0,0,0,,Yeah? Dialogue: 0,0:56:55.55,0:56:56.81,EN,,0,0,0,,AUDIENCE: Is this the last question? Dialogue: 0,0:57:00.28,0:57:02.03,EN,,0,0,0,,[LAUGHTER] Dialogue: 0,0:57:18.64,0:57:19.63,EN,,0,0,0,,PROFESSOR: Apparently so. Dialogue: 0,0:57:23.57,0:57:24.12,EN,,0,0,0,,Thank you. Dialogue: 0,0:57:25.90,0:57:36.50,EN,,0,0,0,,[APPLAUSE] Dialogue: 0,0:00:00.00,0:00:03.48,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:00.00,0:00:03.48,Declare,,0,0,0,,{\fad(500,500)\pos(313,99)}“让我们举杯,祝福那些\N\N\N\N将他们的思想镶嵌在\N\N\N\N   重重括号之间的Lisp程序员。” Dialogue: 0,0:00:04.75,0:00:11.77,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N杨启钊\N(windfarer) Dialogue: 0,0:00:04.75,0:00:11.77,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.75,0:00:11.77,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:04.75,0:00:11.77,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:04.75,0:00:11.77,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:11.88,0:00:15.72,Declare,,0,0,0,,{\an2\fad(500,500)}存储分配与垃圾收集 Dialogue: 0,0:00:18.91,0:00:20.61,Default,,0,0,0,,教授: 接下来我要解开 Dialogue: 0,0:00:21.16,0:00:23.36,Default,,0,0,0,,目前仅剩的谜团 Dialogue: 0,0:00:24.44,0:00:28.80,Default,,0,0,0,,我们能毫无顾虑地进行CONS Dialogue: 0,0:00:30.00,0:00:31.62,Default,,0,0,0,,就好像空间足够多一样 Dialogue: 0,0:00:32.80,0:00:36.32,Default,,0,0,0,,我们总是在使用 Dialogue: 0,0:00:36.51,0:00:37.44,Default,,0,0,0,,CAR和CDR Dialogue: 0,0:00:37.47,0:00:38.72,Default,,0,0,0,,并假设知道我们知道 Dialogue: 0,0:00:38.75,0:00:39.74,Default,,0,0,0,,它们是如何实现的 Dialogue: 0,0:00:40.02,0:00:40.67,Default,,0,0,0,,事实上 Dialogue: 0,0:00:41.07,0:00:44.40,Default,,0,0,0,,我们认为它们是基本过程 Dialogue: 0,0:00:45.37,0:00:47.57,Default,,0,0,0,,但这没有真正解决问题 Dialogue: 0,0:00:47.73,0:00:50.25,Default,,0,0,0,,因为过程依赖各种复杂的机制 Dialogue: 0,0:00:50.27,0:00:51.37,Default,,0,0,0,,需要诸如环境结构之类的东西 Dialogue: 0,0:00:51.64,0:00:52.76,Default,,0,0,0,,才能运行起来 Dialogue: 0,0:00:53.01,0:00:54.89,Default,,0,0,0,,而归根结底它们也是 Dialogue: 0,0:00:54.89,0:00:56.42,Default,,0,0,0,,由CONS之类的东西构成的 Dialogue: 0,0:00:56.70,0:00:58.47,Default,,0,0,0,,这的确没有解决问题 Dialogue: 0,0:00:59.38,0:01:01.13,Default,,0,0,0,,目前的问题是 Dialogue: 0,0:01:01.31,0:01:03.97,Default,,0,0,0,,粘合这些数据结构的是什么东西? Dialogue: 0,0:01:04.76,0:01:06.40,Default,,0,0,0,,它可能是怎样的一个东西? Dialogue: 0,0:01:07.04,0:01:10.46,Default,,0,0,0,,我们已经见过了一台机器 Dialogue: 0,0:01:10.46,0:01:13.96,Default,,0,0,0,,一台计算机具有一个控制器 Dialogue: 0,0:01:14.27,0:01:15.45,Default,,0,0,0,,和一些寄存器 Dialogue: 0,0:01:15.45,0:01:16.47,Default,,0,0,0,,还可能有一个栈 Dialogue: 0,0:01:16.98,0:01:18.12,Default,,0,0,0,,但是我们还没提到一些东西 Dialogue: 0,0:01:18.16,0:01:19.95,Default,,0,0,0,,例如 大内存 Dialogue: 0,0:01:20.57,0:01:22.38,Default,,0,0,0,,我想 现在是时候讨论它们了 Dialogue: 0,0:01:23.74,0:01:26.56,Default,,0,0,0,,但是先要说清楚 Dialogue: 0,0:01:26.59,0:01:27.88,Default,,0,0,0,,这个并不是必须的 Dialogue: 0,0:01:28.82,0:01:30.79,Default,,0,0,0,,只是一些实现上的细节 Dialogue: 0,0:01:31.10,0:01:32.60,Default,,0,0,0,,让我举个例子 Dialogue: 0,0:01:32.60,0:01:34.20,Default,,0,0,0,,如何用数字来表示这些东西 Dialogue: 0,0:01:35.23,0:01:36.82,Default,,0,0,0,,有个比较简单的方法 Dialogue: 0,0:01:37.59,0:01:39.00,Default,,0,0,0,,一位著名的逻辑学家 哥德尔 Dialogue: 0,0:01:44.09,0:01:46.01,Default,,0,0,0,,在20世纪30年代末 Dialogue: 0,0:01:46.38,0:01:48.70,Default,,0,0,0,,发明了一个很巧妙的方法 Dialogue: 0,0:01:48.70,0:01:52.27,Default,,0,0,0,,能够把复杂的表达式 Dialogue: 0,0:01:52.81,0:01:53.52,Default,,0,0,0,,表示成数字 Dialogue: 0,0:01:54.32,0:01:55.05,Default,,0,0,0,,例如 Dialogue: 0,0:01:55.05,0:01:58.00,Default,,0,0,0,,我不会照搬哥德尔的方法 Dialogue: 0,0:01:58.00,0:01:59.48,Default,,0,0,0,,因为他没有使用CONS之类的术语 Dialogue: 0,0:01:59.66,0:02:00.60,Default,,0,0,0,,他使用了其它的组合手段 Dialogue: 0,0:02:00.91,0:02:02.60,Default,,0,0,0,,来编码表达式 Dialogue: 0,0:02:03.09,0:02:03.88,Default,,0,0,0,,他的思路是 Dialogue: 0,0:02:03.92,0:02:06.81,Default,,0,0,0,,用不同数字分别代表每个代数式 Dialogue: 0,0:02:07.92,0:02:09.72,Default,,0,0,0,,通过组合各个部分的数字 Dialogue: 0,0:02:09.72,0:02:11.65,Default,,0,0,0,,来形成新的表达式 Dialogue: 0,0:02:12.47,0:02:13.45,Default,,0,0,0,,举例来说 Dialogue: 0,0:02:13.62,0:02:15.35,Default,,0,0,0,,我们在创造世界的时候 Dialogue: 0,0:02:15.35,0:02:18.01,Default,,0,0,0,,如果用数字 Dialogue: 0,0:02:20.78,0:02:22.22,Default,,0,0,0,,来表示对象 Dialogue: 0,0:02:30.67,0:02:37.93,Default,,0,0,0,,那么(CONS X Y) Dialogue: 0,0:02:38.04,0:02:41.07,Default,,0,0,0,,就可以表示为 Dialogue: 0,0:02:41.55,0:02:43.77,Default,,0,0,0,,2^X * 3^Y Dialogue: 0,0:02:46.13,0:02:48.03,Default,,0,0,0,,因为这样我们还能取出它的每一部分 Dialogue: 0,0:02:49.56,0:02:50.97,Default,,0,0,0,,举例来说 Dialogue: 0,0:02:51.18,0:02:55.88,Default,,0,0,0,,(CAR X) Dialogue: 0,0:02:56.55,0:03:05.18,Default,,0,0,0,,就是X中因数2的个数 Dialogue: 0,0:03:06.69,0:03:08.78,Default,,0,0,0,,当然(CDR X)是一样的 Dialogue: 0,0:03:10.69,0:03:15.57,Default,,0,0,0,,它就X中因数3的个数 Dialogue: 0,0:03:16.51,0:03:18.65,Default,,0,0,0,,这是个非常合理的方案 Dialogue: 0,0:03:19.10,0:03:20.11,Default,,0,0,0,,只不过就是 Dialogue: 0,0:03:20.12,0:03:22.52,Default,,0,0,0,,数字的位数 Dialogue: 0,0:03:22.83,0:03:23.98,Default,,0,0,0,,会急剧地增大 Dialogue: 0,0:03:24.32,0:03:26.55,Default,,0,0,0,,甚至比宇宙中的粒子还多 Dialogue: 0,0:03:27.95,0:03:29.88,Default,,0,0,0,,所以除了在理论中 Dialogue: 0,0:03:29.90,0:03:31.21,Default,,0,0,0,,没有实现这种方案的好办法 Dialogue: 0,0:03:33.43,0:03:34.48,Default,,0,0,0,,另一方面 Dialogue: 0,0:03:35.12,0:03:37.55,Default,,0,0,0,,也有其它的表示方式 Dialogue: 0,0:03:38.45,0:03:40.01,Default,,0,0,0,,我们把它们表示为 Dialogue: 0,0:03:40.25,0:03:42.42,Default,,0,0,0,,一些小盒子 Dialogue: 0,0:03:43.32,0:03:46.43,Default,,0,0,0,,我们把CONS结构 Dialogue: 0,0:03:46.50,0:03:48.05,Default,,0,0,0,,想象为这样的东西 Dialogue: 0,0:03:50.28,0:03:52.57,Default,,0,0,0,,它们是里面装着东西的小隔间 Dialogue: 0,0:03:53.56,0:03:55.47,Default,,0,0,0,,这些格子组成一个树 Dialogue: 0,0:03:57.21,0:03:59.97,Default,,0,0,0,,我希望半导体制造商 Dialogue: 0,0:03:59.97,0:04:02.07,Default,,0,0,0,,能够提供适配这样需求的芯片 Dialogue: 0,0:04:02.70,0:04:03.76,Default,,0,0,0,,但事实上 Dialogue: 0,0:04:03.85,0:04:05.31,Default,,0,0,0,,他们提供给我的却是 Dialogue: 0,0:04:06.20,0:04:07.96,Default,,0,0,0,,线性的内存 Dialogue: 0,0:04:09.38,0:04:13.46,Default,,0,0,0,,内存是一串小隔间 Dialogue: 0,0:04:15.12,0:04:16.34,Default,,0,0,0,,像这样的小隔间 Dialogue: 0,0:04:17.72,0:04:20.25,Default,,0,0,0,,每个小隔间里可以保存确定大小的对象 Dialogue: 0,0:04:20.94,0:04:22.20,Default,,0,0,0,,一个尺寸固定的对象 Dialogue: 0,0:04:23.39,0:04:24.07,Default,,0,0,0,,例如 Dialogue: 0,0:04:24.07,0:04:25.66,Default,,0,0,0,,一个含25个元素的表 Dialogue: 0,0:04:25.66,0:04:26.64,Default,,0,0,0,,就放不进这里 Dialogue: 0,0:04:28.55,0:04:29.26,Default,,0,0,0,,然而 它们中的每一个 Dialogue: 0,0:04:29.29,0:04:30.88,Default,,0,0,0,,都是由地址索引的 Dialogue: 0,0:04:33.97,0:04:34.99,Default,,0,0,0,,因此它们的地址可能是 Dialogue: 0,0:04:35.02,0:04:35.50,Default,,0,0,0,,这里是0 Dialogue: 0,0:04:35.50,0:04:36.22,Default,,0,0,0,,这里是1 Dialogue: 0,0:04:36.22,0:04:36.70,Default,,0,0,0,,这里是2 Dialogue: 0,0:04:36.70,0:04:37.25,Default,,0,0,0,,这里是3 Dialogue: 0,0:04:37.25,0:04:37.94,Default,,0,0,0,,以此类推 Dialogue: 0,0:04:38.06,0:04:40.40,Default,,0,0,0,,这里写的数字并不重要 Dialogue: 0,0:04:40.40,0:04:41.68,Default,,0,0,0,,重要的是 它们不重复 Dialogue: 0,0:04:41.95,0:04:43.42,Default,,0,0,0,,有了它们就能找到下一个在哪 Dialogue: 0,0:04:44.97,0:04:46.14,Default,,0,0,0,,在其中每一个小隔间里面 Dialogue: 0,0:04:46.36,0:04:49.11,Default,,0,0,0,,我们可以把东西放进去 Dialogue: 0,0:04:49.53,0:04:50.77,Default,,0,0,0,,对于没有造过计算机的我们来说 Dialogue: 0,0:04:51.02,0:04:53.66,Default,,0,0,0,,内存就是这样子的 Dialogue: 0,0:04:54.15,0:04:54.65,Default,,0,0,0,,现在 Dialogue: 0,0:04:56.69,0:04:57.53,Default,,0,0,0,,现在的问题是 Dialogue: 0,0:04:57.53,0:04:59.97,Default,,0,0,0,,如何用这样的结构 Dialogue: 0,0:05:00.42,0:05:01.72,Default,,0,0,0,,来实现这个树形结构 Dialogue: 0,0:05:03.29,0:05:04.57,Default,,0,0,0,,其实并不难 Dialogue: 0,0:05:04.57,0:05:06.35,Default,,0,0,0,,已经有大量的方案来做这个了 Dialogue: 0,0:05:06.87,0:05:08.80,Default,,0,0,0,,最重要的一个方案是 Dialogue: 0,0:05:08.80,0:05:11.18,Default,,0,0,0,,假设半导体制造商 Dialogue: 0,0:05:11.20,0:05:13.90,Default,,0,0,0,,允许我安排自己的内存 Dialogue: 0,0:05:13.98,0:05:15.77,Default,,0,0,0,,使得其中每个小隔间都足够大 Dialogue: 0,0:05:16.28,0:05:18.20,Default,,0,0,0,,能够装得下另一个的地址 Dialogue: 0,0:05:19.35,0:05:20.83,Default,,0,0,0,,我需要这么来安排 Dialogue: 0,0:05:22.05,0:05:23.45,Default,,0,0,0,,事实上它需要更大一点 Dialogue: 0,0:05:23.48,0:05:27.52,Default,,0,0,0,,因为我还要在里面存放一些信息 Dialogue: 0,0:05:27.56,0:05:30.09,Default,,0,0,0,,它标示了这里面是什么东西 Dialogue: 0,0:05:30.39,0:05:31.64,Default,,0,0,0,,我们过一会就能看到 Dialogue: 0,0:05:32.62,0:05:34.40,Default,,0,0,0,,当然 如果半导体制造商 Dialogue: 0,0:05:34.43,0:05:35.88,Default,,0,0,0,,没有这么来制造 Dialogue: 0,0:05:36.08,0:05:38.44,Default,,0,0,0,,我就需要用一些机智的方式 Dialogue: 0,0:05:38.57,0:05:41.82,Default,,0,0,0,,把它们组合起来以供使用 Dialogue: 0,0:05:43.77,0:05:47.05,Default,,0,0,0,,我们想象一下 Dialogue: 0,0:05:47.05,0:05:49.54,Default,,0,0,0,,把这个复杂的树形结构 Dialogue: 0,0:05:49.54,0:05:51.20,Default,,0,0,0,,塞进线性内存里 Dialogue: 0,0:05:51.74,0:05:54.47,Default,,0,0,0,,我们来看第一张幻灯片 Dialogue: 0,0:05:54.47,0:05:58.30,Default,,0,0,0,,可以看到一个传统的实现方案 Dialogue: 0,0:05:59.49,0:06:02.62,Default,,0,0,0,,它是把表结构放入线性内存 Dialogue: 0,0:06:03.22,0:06:05.87,Default,,0,0,0,,的标准方式 Dialogue: 0,0:06:06.27,0:06:08.32,Default,,0,0,0,,我们把这块内存 Dialogue: 0,0:06:08.88,0:06:11.12,Default,,0,0,0,,分为两部分 Dialogue: 0,0:06:12.03,0:06:13.42,Default,,0,0,0,,一个叫THE-CARS的数组 Dialogue: 0,0:06:14.45,0:06:15.88,Default,,0,0,0,,一个叫THE-CDRS的数组 Dialogue: 0,0:06:17.58,0:06:18.86,Default,,0,0,0,,无论它们是 Dialogue: 0,0:06:18.88,0:06:21.04,Default,,0,0,0,,顺序的地址或是其它的 Dialogue: 0,0:06:21.12,0:06:22.00,Default,,0,0,0,,其实并不重要 Dialogue: 0,0:06:22.87,0:06:25.20,Default,,0,0,0,,这是实现细节了 Dialogue: 0,0:06:25.80,0:06:28.40,Default,,0,0,0,,但有两个数组 Dialogue: 0,0:06:28.96,0:06:30.36,Default,,0,0,0,,线性数组是由 Dialogue: 0,0:06:30.46,0:06:32.59,Default,,0,0,0,,顺序的下标索引的 Dialogue: 0,0:06:34.84,0:06:36.85,Default,,0,0,0,,每个小格子里存的 Dialogue: 0,0:06:37.46,0:06:39.85,Default,,0,0,0,,是一个带类型的对象 Dialogue: 0,0:06:41.43,0:06:42.57,Default,,0,0,0,,这里的类型 Dialogue: 0,0:06:42.57,0:06:45.71,Default,,0,0,0,,以字母P开头 Dialogue: 0,0:06:45.71,0:06:46.57,Default,,0,0,0,,表示序对 Dialogue: 0,0:06:47.79,0:06:49.37,Default,,0,0,0,,以N开头 表示数字 Dialogue: 0,0:06:50.04,0:06:52.25,Default,,0,0,0,,E开头 表示空表 Dialogue: 0,0:06:54.81,0:06:55.83,Default,,0,0,0,,也就是表尾标志 Dialogue: 0,0:06:57.02,0:06:58.59,Default,,0,0,0,,如果我们想表示 Dialogue: 0,0:06:58.99,0:06:59.97,Default,,0,0,0,,这样一个对象 Dialogue: 0,0:07:00.01,0:07:02.16,Default,,0,0,0,,首元素为(1 2) Dialogue: 0,0:07:02.65,0:07:04.01,Default,,0,0,0,,然后3、4分别作为 Dialogue: 0,0:07:04.01,0:07:05.50,Default,,0,0,0,,它的第二和第三个元素 Dialogue: 0,0:07:06.43,0:07:08.83,Default,,0,0,0,,这个表的第一部分也是一个表 Dialogue: 0,0:07:09.35,0:07:10.65,Default,,0,0,0,,后面接着是两个数字 Dialogue: 0,0:07:10.65,0:07:12.00,Default,,0,0,0,,分别为第二和第三部分 Dialogue: 0,0:07:12.87,0:07:14.81,Default,,0,0,0,,现在我们用盒子-指针表示法 Dialogue: 0,0:07:14.84,0:07:16.67,Default,,0,0,0,,来描绘它 Dialogue: 0,0:07:17.32,0:07:18.00,Default,,0,0,0,,你能发现 Dialogue: 0,0:07:18.00,0:07:20.04,Default,,0,0,0,,这里有三个单元 Dialogue: 0,0:07:20.25,0:07:22.01,Default,,0,0,0,,它们的CAR指针 Dialogue: 0,0:07:22.27,0:07:27.10,Default,,0,0,0,,分别指向对象(1 2)、3以及4 Dialogue: 0,0:07:28.39,0:07:29.75,Default,,0,0,0,,当然这个(1 2) Dialogue: 0,0:07:29.75,0:07:31.32,Default,,0,0,0,,即整个结构的CAR Dialogue: 0,0:07:31.32,0:07:32.65,Default,,0,0,0,,本身就是一个子结构 Dialogue: 0,0:07:32.88,0:07:34.75,Default,,0,0,0,,包含一个像这样的子表 Dialogue: 0,0:07:35.94,0:07:37.07,Default,,0,0,0,,我要做的是 Dialogue: 0,0:07:37.20,0:07:39.92,Default,,0,0,0,,就是按照下标 Dialogue: 0,0:07:39.95,0:07:41.46,Default,,0,0,0,,把它们放进去 Dialogue: 0,0:07:41.84,0:07:43.40,Default,,0,0,0,,像这里的1 Dialogue: 0,0:07:43.56,0:07:47.05,Default,,0,0,0,,代表了这个格子的下标 Dialogue: 0,0:07:49.85,0:07:51.47,Default,,0,0,0,,这里的指针 Dialogue: 0,0:07:52.37,0:07:54.86,Default,,0,0,0,,是对THE-CARS Dialogue: 0,0:07:55.07,0:07:57.29,Default,,0,0,0,,和THE-CDRS里的小格子的引用 Dialogue: 0,0:07:57.40,0:07:58.67,Default,,0,0,0,,它在我的线性内存中 Dialogue: 0,0:07:58.76,0:08:00.33,Default,,0,0,0,,被标记为1的地方 Dialogue: 0,0:08:02.00,0:08:04.06,Default,,0,0,0,,如果我想把这个结构 Dialogue: 0,0:08:04.16,0:08:05.26,Default,,0,0,0,,塞进线性内存中 Dialogue: 0,0:08:05.85,0:08:07.52,Default,,0,0,0,,要做的是 Dialogue: 0,0:08:07.52,0:08:11.88,Default,,0,0,0,,把它放进格子1中 Dialogue: 0,0:08:11.95,0:08:12.66,Default,,0,0,0,,我要选取1号格子 Dialogue: 0,0:08:12.66,0:08:13.85,Default,,0,0,0,,这个就是1号格子 Dialogue: 0,0:08:14.27,0:08:16.22,Default,,0,0,0,,这是它的CAR Dialogue: 0,0:08:16.22,0:08:17.74,Default,,0,0,0,,我要把它赋值给一个序对 Dialogue: 0,0:08:17.95,0:08:18.72,Default,,0,0,0,,这个序对 Dialogue: 0,0:08:20.02,0:08:21.55,Default,,0,0,0,,序号是5 Dialogue: 0,0:08:22.59,0:08:23.90,Default,,0,0,0,,它的CDR Dialogue: 0,0:08:23.90,0:08:25.13,Default,,0,0,0,,就是这个 Dialogue: 0,0:08:25.39,0:08:26.13,Default,,0,0,0,,它是个序对 Dialogue: 0,0:08:26.13,0:08:27.70,Default,,0,0,0,,我会把它放到2的位置 Dialogue: 0,0:08:28.34,0:08:28.98,Default,,0,0,0,,即P2 Dialogue: 0,0:08:30.89,0:08:32.95,Default,,0,0,0,,我们看P2 Dialogue: 0,0:08:32.95,0:08:34.72,Default,,0,0,0,,P2的CAR Dialogue: 0,0:08:34.90,0:08:37.22,Default,,0,0,0,,是数字3 Dialogue: 0,0:08:37.34,0:08:38.64,Default,,0,0,0,,如你所见N3 Dialogue: 0,0:08:39.52,0:08:41.52,Default,,0,0,0,,这里 它的CDR Dialogue: 0,0:08:41.72,0:08:43.40,Default,,0,0,0,,是一个序对 Dialogue: 0,0:08:43.97,0:08:45.81,Default,,0,0,0,,在位置4 Dialogue: 0,0:08:46.64,0:08:47.79,Default,,0,0,0,,这就是P4 Dialogue: 0,0:08:48.65,0:08:51.16,Default,,0,0,0,,P4是一个数字 Dialogue: 0,0:08:51.85,0:08:53.87,Default,,0,0,0,,它的CAR部分是数字4 Dialogue: 0,0:08:54.60,0:08:55.65,Default,,0,0,0,,它的CDR Dialogue: 0,0:08:55.84,0:08:58.48,Default,,0,0,0,,是个空表 就在这儿 Dialogue: 0,0:08:59.17,0:08:59.90,Default,,0,0,0,,这个表就结束了 Dialogue: 0,0:09:00.69,0:09:04.57,Default,,0,0,0,,这就是在线性内存中 Dialogue: 0,0:09:04.90,0:09:09.55,Default,,0,0,0,,表示二叉树的传统方式 Dialogue: 0,0:09:11.62,0:09:15.10,Default,,0,0,0,,那么 下一个问题是 Dialogue: 0,0:09:15.10,0:09:16.36,Default,,0,0,0,,我们需要关心 Dialogue: 0,0:09:16.60,0:09:18.19,Default,,0,0,0,,如何去实现 Dialogue: 0,0:09:18.44,0:09:20.33,Default,,0,0,0,,这意味着当我写下一个过程 Dialogue: 0,0:09:20.36,0:09:23.62,Default,,0,0,0,,用来给A赋值时 Dialogue: 0,0:09:24.54,0:09:27.10,Default,,0,0,0,,使用寄存机器的代码来编写的 Dialogue: 0,0:09:27.21,0:09:30.14,Default,,0,0,0,,(ASSIGN A (FETCH B)) Dialogue: 0,0:09:30.84,0:09:31.85,Default,,0,0,0,,我实际上想做的是 Dialogue: 0,0:09:31.97,0:09:37.10,Default,,0,0,0,,定位这些元素 Dialogue: 0,0:09:38.74,0:09:40.25,Default,,0,0,0,,那段机器代码只是 Dialogue: 0,0:09:40.68,0:09:42.94,Default,,0,0,0,,这个复杂过程的简写 Dialogue: 0,0:09:44.47,0:09:46.33,Default,,0,0,0,,当然 为了把它“写下来” Dialogue: 0,0:09:46.35,0:09:48.59,Default,,0,0,0,,我要引入一种 Dialogue: 0,0:09:48.62,0:09:49.42,Default,,0,0,0,,称为“向量”的结构 Dialogue: 0,0:09:52.12,0:09:53.31,Default,,0,0,0,,我们得有一种东西 Dialogue: 0,0:09:53.48,0:09:54.54,Default,,0,0,0,,用来引用向量 Dialogue: 0,0:09:56.84,0:09:58.51,Default,,0,0,0,,这样我们就能把它写下来 Dialogue: 0,0:09:58.71,0:10:00.22,Default,,0,0,0,,它的参数之一是向量的名字 Dialogue: 0,0:10:01.02,0:10:03.97,Default,,0,0,0,,我觉得这个名字起得不太靠谱 Dialogue: 0,0:10:03.97,0:10:09.40,Default,,0,0,0,,它接受VECTOR和INDEX两个参数 Dialogue: 0,0:10:11.20,0:10:13.05,Default,,0,0,0,,我可以用VECTOR-SET! Dialogue: 0,0:10:13.10,0:10:14.27,Default,,0,0,0,,来为其中的分量赋值 Dialogue: 0,0:10:14.65,0:10:15.60,Default,,0,0,0,,我不太在意 Dialogue: 0,0:10:16.28,0:10:17.55,Default,,0,0,0,,我们来看一看 Dialogue: 0,0:10:18.11,0:10:20.42,Default,,0,0,0,,在这种实现中 Dialogue: 0,0:10:21.25,0:10:23.18,Default,,0,0,0,,CAR和CDR是什么样子的 Dialogue: 0,0:10:26.47,0:10:28.41,Default,,0,0,0,,比如说 如果我刚好有 Dialogue: 0,0:10:28.88,0:10:30.80,Default,,0,0,0,,一个寄存器B Dialogue: 0,0:10:31.15,0:10:34.64,Default,,0,0,0,,它存了一个序对的下标 Dialogue: 0,0:10:35.95,0:10:38.80,Default,,0,0,0,,即它是指向一个序对的指针 Dialogue: 0,0:10:39.35,0:10:40.85,Default,,0,0,0,,我可以取它的CAR Dialogue: 0,0:10:41.55,0:10:44.11,Default,,0,0,0,,存到寄存器A里面 Dialogue: 0,0:10:44.49,0:10:46.86,Default,,0,0,0,,事实上它是 Dialogue: 0,0:10:47.37,0:10:50.19,Default,,0,0,0,,把A赋值为-- Dialogue: 0,0:10:50.19,0:10:51.92,Default,,0,0,0,,引用向量的一个分量-- Dialogue: 0,0:10:52.80,0:10:55.24,Default,,0,0,0,,或者你可以把它叫做索引一个数组 Dialogue: 0,0:10:55.42,0:10:57.63,Default,,0,0,0,,目标向量为THE-CARS Dialogue: 0,0:10:58.40,0:11:00.92,Default,,0,0,0,,而目标分量是B Dialogue: 0,0:11:02.65,0:11:03.63,Default,,0,0,0,,CDR的操作也类似 Dialogue: 0,0:11:04.10,0:11:05.72,Default,,0,0,0,,我们可以用同样的方式 Dialogue: 0,0:11:05.90,0:11:08.32,Default,,0,0,0,,来对数据结构赋值 Dialogue: 0,0:11:08.92,0:11:10.92,Default,,0,0,0,,如果我们需要这么做的话 Dialogue: 0,0:11:11.84,0:11:13.80,Default,,0,0,0,,构建这个并不太难 Dialogue: 0,0:11:14.58,0:11:15.72,Default,,0,0,0,,下一个问题是 Dialogue: 0,0:11:15.72,0:11:17.00,Default,,0,0,0,,我们如何分配它们 Dialogue: 0,0:11:18.01,0:11:20.13,Default,,0,0,0,,我们经常需要一个新的序对 Dialogue: 0,0:11:21.40,0:11:23.42,Default,,0,0,0,,当然 CONS并没有长在树上 Dialogue: 0,0:11:23.79,0:11:24.81,Default,,0,0,0,,或许它们应该那样 Dialogue: 0,0:11:25.34,0:11:26.56,Default,,0,0,0,,我必须得有某种方法 Dialogue: 0,0:11:26.70,0:11:28.97,Default,,0,0,0,,来获得一个可用的序对 Dialogue: 0,0:11:29.98,0:11:31.47,Default,,0,0,0,,我需要某种方案 Dialogue: 0,0:11:31.47,0:11:33.04,Default,,0,0,0,,当内存不再使用的时候 Dialogue: 0,0:11:33.69,0:11:35.05,Default,,0,0,0,,我可以重新分配它们 Dialogue: 0,0:11:35.63,0:11:37.38,Default,,0,0,0,,有很多方案可以实现这一点 Dialogue: 0,0:11:37.38,0:11:39.07,Default,,0,0,0,,现在我给你们展示的这个东西 Dialogue: 0,0:11:39.23,0:11:40.45,Default,,0,0,0,,并是不必要的 Dialogue: 0,0:11:42.10,0:11:43.18,Default,,0,0,0,,然而它很方便 Dialogue: 0,0:11:43.20,0:11:44.44,Default,,0,0,0,,并且被实现很多次了 Dialogue: 0,0:11:44.60,0:11:47.20,Default,,0,0,0,,其中一种基于“空闲表”的分配方案 Dialogue: 0,0:11:47.66,0:11:48.68,Default,,0,0,0,,它的意思就是 Dialogue: 0,0:11:48.68,0:11:51.12,Default,,0,0,0,,世界上所有的空闲内存 Dialogue: 0,0:11:51.55,0:11:53.08,Default,,0,0,0,,都连在一个链表中 Dialogue: 0,0:11:54.55,0:11:56.22,Default,,0,0,0,,就像其它东西一样 Dialogue: 0,0:11:56.96,0:11:59.07,Default,,0,0,0,,每当你需要一个新的格子 Dialogue: 0,0:11:59.07,0:12:00.12,Default,,0,0,0,,来进行CONS的时候 Dialogue: 0,0:12:00.95,0:12:02.26,Default,,0,0,0,,你选择第一个格子 Dialogue: 0,0:12:02.26,0:12:03.82,Default,,0,0,0,,将它的CDR指向空闲表 Dialogue: 0,0:12:04.32,0:12:05.55,Default,,0,0,0,,然后分配它 Dialogue: 0,0:12:06.03,0:12:08.32,Default,,0,0,0,,就像这样 Dialogue: 0,0:12:09.53,0:12:13.32,Default,,0,0,0,,这里 我们的空闲表 Dialogue: 0,0:12:13.95,0:12:16.81,Default,,0,0,0,,就是从6开始 Dialogue: 0,0:12:18.51,0:12:23.47,Default,,0,0,0,,它是一个指向8的指针 Dialogue: 0,0:12:24.86,0:12:25.62,Default,,0,0,0,,它表示 Dialogue: 0,0:12:25.62,0:12:26.55,Default,,0,0,0,,当前这个是空闲的 Dialogue: 0,0:12:26.55,0:12:27.95,Default,,0,0,0,,下一个在位置8 Dialogue: 0,0:12:28.87,0:12:29.88,Default,,0,0,0,,这个是空闲的 Dialogue: 0,0:12:30.04,0:12:32.08,Default,,0,0,0,,下一个在位置3 Dialogue: 0,0:12:32.32,0:12:33.45,Default,,0,0,0,,下一个是空闲的 Dialogue: 0,0:12:33.93,0:12:34.95,Default,,0,0,0,,这个是空闲的 Dialogue: 0,0:12:35.04,0:12:37.68,Default,,0,0,0,,下一个在位置0 Dialogue: 0,0:12:37.87,0:12:38.49,Default,,0,0,0,,这个是空闲的 Dialogue: 0,0:12:38.52,0:12:39.82,Default,,0,0,0,,下一个在位置15 Dialogue: 0,0:12:40.94,0:12:41.84,Default,,0,0,0,,以此类推 Dialogue: 0,0:12:42.78,0:12:44.64,Default,,0,0,0,,我们可以想象有这样的结构 Dialogue: 0,0:12:46.40,0:12:48.03,Default,,0,0,0,,一旦我们有了这样的机制 Dialogue: 0,0:12:49.45,0:12:50.92,Default,,0,0,0,,那么当你需要空间的时候 Dialogue: 0,0:12:50.92,0:12:52.22,Default,,0,0,0,,就能获取一个 Dialogue: 0,0:12:53.82,0:12:56.46,Default,,0,0,0,,那些使用了CONS的程序 Dialogue: 0,0:12:57.45,0:12:59.13,Default,,0,0,0,,内存可能就是像这样的 Dialogue: 0,0:12:59.32,0:13:02.57,Default,,0,0,0,,把B和C进行CONS之后的值 Dialogue: 0,0:13:02.95,0:13:05.82,Default,,0,0,0,,赋值给A寄存器 Dialogue: 0,0:13:06.20,0:13:09.04,Default,,0,0,0,,结果包括B和C Dialogue: 0,0:13:09.27,0:13:10.52,Default,,0,0,0,,我们要做的是 Dialogue: 0,0:13:10.56,0:13:12.24,Default,,0,0,0,,把当前的尾部格子 即空闲表的前个格子 Dialogue: 0,0:13:12.47,0:13:14.30,Default,,0,0,0,,让它的CDR指向空闲表 Dialogue: 0,0:13:15.64,0:13:18.33,Default,,0,0,0,,我们要把THE-CARS中 Dialogue: 0,0:13:18.41,0:13:22.49,Default,,0,0,0,,由A索引的格子 Dialogue: 0,0:13:23.13,0:13:25.45,Default,,0,0,0,,修改为B中的内容 Dialogue: 0,0:13:25.90,0:13:28.65,Default,,0,0,0,,THE-CDRS中由A索引的格子 Dialogue: 0,0:13:29.20,0:13:31.72,Default,,0,0,0,,修改为C的值 Dialogue: 0,0:13:33.20,0:13:34.76,Default,,0,0,0,,现在A所指的格子里面 Dialogue: 0,0:13:34.78,0:13:36.65,Default,,0,0,0,,就是新构建好的对象了 Dialogue: 0,0:13:36.81,0:13:37.92,Default,,0,0,0,,这就是我们要的对象 Dialogue: 0,0:13:40.47,0:13:42.50,Default,,0,0,0,,我之前告诉过你们 Dialogue: 0,0:13:42.50,0:13:43.97,Default,,0,0,0,,这里撒了个谎 Dialogue: 0,0:13:43.97,0:13:45.32,Default,,0,0,0,,也就是在这里的某处 Dialogue: 0,0:13:45.53,0:13:47.32,Default,,0,0,0,,我本来应该 Dialogue: 0,0:13:48.45,0:13:50.48,Default,,0,0,0,,把我CONS起来的对象 Dialogue: 0,0:13:50.51,0:13:51.87,Default,,0,0,0,,设置为序对类型 Dialogue: 0,0:13:52.30,0:13:53.05,Default,,0,0,0,,但我没有 Dialogue: 0,0:13:53.51,0:13:56.57,Default,,0,0,0,,因此这里应该需要设置一些比特位 Dialogue: 0,0:13:56.60,0:13:57.76,Default,,0,0,0,,我只是还没把它写下来 Dialogue: 0,0:13:59.81,0:14:00.86,Default,,0,0,0,,当然 这个很好实现 Dialogue: 0,0:14:00.89,0:14:02.45,Default,,0,0,0,,因为空闲表本来就是用序对实现的 Dialogue: 0,0:14:03.10,0:14:04.88,Default,,0,0,0,,因此这是没问题的 Dialogue: 0,0:14:06.43,0:14:07.74,Default,,0,0,0,,但这也就是-- Dialogue: 0,0:14:07.82,0:14:09.92,Default,,0,0,0,,这些都是无关紧要的细节 Dialogue: 0,0:14:10.22,0:14:12.88,Default,,0,0,0,,取决于那些想要自制 Dialogue: 0,0:14:12.92,0:14:14.27,Default,,0,0,0,,计算机或Lisp系统的 Dialogue: 0,0:14:14.33,0:14:16.68,Default,,0,0,0,,程序员或架构师 Dialogue: 0,0:14:17.54,0:14:18.71,Default,,0,0,0,,例如 Dialogue: 0,0:14:19.07,0:14:20.24,Default,,0,0,0,,看这个 Dialogue: 0,0:14:20.65,0:14:23.45,Default,,0,0,0,,假设我们要为 Dialogue: 0,0:14:23.55,0:14:26.83,Default,,0,0,0,,这个之前见过的数据结构分配空间 Dialogue: 0,0:14:27.21,0:14:30.26,Default,,0,0,0,,假设我要分配一个新格子 Dialogue: 0,0:14:30.55,0:14:36.61,Default,,0,0,0,,来表示表(1 1 2) Dialogue: 0,0:14:37.24,0:14:39.87,Default,,0,0,0,,其中(1 2)又是 Dialogue: 0,0:14:40.28,0:14:42.16,Default,,0,0,0,,之前一个表的CAR元素 Dialogue: 0,0:14:43.43,0:14:44.45,Default,,0,0,0,,这不怎么难 Dialogue: 0,0:14:44.78,0:14:46.20,Default,,0,0,0,,我用1号单元来存放数字“1” Dialogue: 0,0:14:46.20,0:14:49.17,Default,,0,0,0,,那么P1表示的就是这个单元 Dialogue: 0,0:14:49.53,0:14:50.83,Default,,0,0,0,,这个是P5 Dialogue: 0,0:14:51.67,0:14:53.51,Default,,0,0,0,,它是应该是这个的CDR Dialogue: 0,0:14:54.07,0:14:55.52,Default,,0,0,0,,现在我们要从空闲表中取出一些东西 Dialogue: 0,0:14:55.52,0:14:57.30,Default,,0,0,0,,空闲表现在是从6开始的 Dialogue: 0,0:14:57.78,0:15:00.18,Default,,0,0,0,,而在分配之后 空闲表将从8开始 Dialogue: 0,0:15:00.60,0:15:02.55,Default,,0,0,0,,一个从8开始的空闲表 Dialogue: 0,0:15:02.89,0:15:03.52,Default,,0,0,0,,当然 Dialogue: 0,0:15:03.72,0:15:06.04,Default,,0,0,0,,现在6里面是数字1 Dialogue: 0,0:15:06.15,0:15:07.10,Default,,0,0,0,,就是我们想要的 Dialogue: 0,0:15:07.39,0:15:11.56,Default,,0,0,0,,它的CDR是在位置5的序对 Dialogue: 0,0:15:13.33,0:15:14.50,Default,,0,0,0,,没费多少力气 Dialogue: 0,0:15:16.81,0:15:20.45,Default,,0,0,0,,这里依然存在的一个问题是 Dialogue: 0,0:15:21.00,0:15:23.40,Default,,0,0,0,,我们没有无限大的内存 Dialogue: 0,0:15:25.08,0:15:26.66,Default,,0,0,0,,如果我像这么操作了一会儿 Dialogue: 0,0:15:27.25,0:15:28.00,Default,,0,0,0,,比如说 Dialogue: 0,0:15:28.01,0:15:30.14,Default,,0,0,0,,假设进行一次CONS花费1微秒 Dialogue: 0,0:15:30.60,0:15:32.97,Default,,0,0,0,,如果要进行一百万次CONS Dialogue: 0,0:15:33.60,0:15:35.27,Default,,0,0,0,,那么我就要消耗1秒钟的时间 Dialogue: 0,0:15:35.95,0:15:37.00,Default,,0,0,0,,这就很糟糕了 Dialogue: 0,0:15:38.00,0:15:40.62,Default,,0,0,0,,如何预防这样的灾难 Dialogue: 0,0:15:40.62,0:15:42.19,Default,,0,0,0,,这种生态灾难 Dialogue: 0,0:15:42.60,0:15:44.30,Default,,0,0,0,,在提问环节之后我们再继续讨论 Dialogue: 0,0:15:44.30,0:15:45.26,Default,,0,0,0,,有人要提问吗? Dialogue: 0,0:15:51.50,0:15:51.69,Default,,0,0,0,,请讲 Dialogue: 0,0:15:52.03,0:15:54.67,Default,,0,0,0,,学生:在环境图表中 Dialogue: 0,0:15:54.67,0:15:58.25,Default,,0,0,0,,我们画了过程体 Dialogue: 0,0:15:58.25,0:16:00.67,Default,,0,0,0,,但是在过程应用结束后 Dialogue: 0,0:16:00.80,0:16:03.60,Default,,0,0,0,,这些环境中的东西就不再有用了 Dialogue: 0,0:16:03.60,0:16:04.16,Default,,0,0,0,,教授:说得很对 Dialogue: 0,0:16:04.93,0:16:06.67,Default,,0,0,0,,学生:它是如何表示的? Dialogue: 0,0:16:06.76,0:16:08.75,Default,,0,0,0,,教授:这其实是两个问题 Dialogue: 0,0:16:09.18,0:16:10.25,Default,,0,0,0,,第一个问题是 Dialogue: 0,0:16:10.25,0:16:13.43,Default,,0,0,0,,材料没用了 Dialogue: 0,0:16:13.87,0:16:14.92,Default,,0,0,0,,我们稍后就会讲 Dialogue: 0,0:16:14.92,0:16:17.00,Default,,0,0,0,,如何预防生态灾难 Dialogue: 0,0:16:17.63,0:16:19.20,Default,,0,0,0,,如果我制造了一堆垃圾 Dialogue: 0,0:16:19.20,0:16:21.39,Default,,0,0,0,,我需要自己清理掉 Dialogue: 0,0:16:21.82,0:16:22.97,Default,,0,0,0,,我们一会儿就要讲 Dialogue: 0,0:16:23.43,0:16:24.57,Default,,0,0,0,,第二个问题 Dialogue: 0,0:16:24.57,0:16:27.21,Default,,0,0,0,,你问的是如何表示环境 Dialogue: 0,0:16:27.28,0:16:27.60,Default,,0,0,0,,学生:对 Dialogue: 0,0:16:27.60,0:16:28.19,Default,,0,0,0,,教授:好 Dialogue: 0,0:16:28.19,0:16:30.62,Default,,0,0,0,,环境结构能够以任意的方式表示 Dialogue: 0,0:16:30.92,0:16:31.78,Default,,0,0,0,,有很多种表示方式 Dialogue: 0,0:16:31.78,0:16:33.34,Default,,0,0,0,,这里 我只讲了基于表结构的内存 Dialogue: 0,0:16:33.63,0:16:34.92,Default,,0,0,0,,当然 每个真实的系统 Dialogue: 0,0:16:34.92,0:16:36.72,Default,,0,0,0,,都有任意长度的向量 Dialogue: 0,0:16:36.72,0:16:39.15,Default,,0,0,0,,也有固定长度的向量 Dialogue: 0,0:16:39.31,0:16:40.51,Default,,0,0,0,,它们都可以作为内存的表示方法 Dialogue: 0,0:16:41.08,0:16:44.90,Default,,0,0,0,,在一个专业的Lisp系统中 Dialogue: 0,0:16:44.90,0:16:46.99,Default,,0,0,0,,环境结构是用 Dialogue: 0,0:16:47.30,0:16:49.69,Default,,0,0,0,,向量表示的 Dialogue: 0,0:16:49.69,0:16:51.92,Default,,0,0,0,,它所包含的元素的数量 Dialogue: 0,0:16:51.92,0:16:54.60,Default,,0,0,0,,比参数的个数稍微多一点 Dialogue: 0,0:16:55.35,0:16:56.86,Default,,0,0,0,,因为你需要某种“粘合剂” Dialogue: 0,0:16:57.40,0:17:00.74,Default,,0,0,0,,记住环境是在框架里的 Dialogue: 0,0:17:00.74,0:17:03.98,Default,,0,0,0,,框架是应用过程时被构建出来的 Dialogue: 0,0:17:03.98,0:17:04.78,Default,,0,0,0,,这种情况下 Dialogue: 0,0:17:04.80,0:17:07.60,Default,,0,0,0,,所分配的空间大小为 Dialogue: 0,0:17:07.64,0:17:11.27,Default,,0,0,0,,实际参数加上“粘合剂”占用的空间 Dialogue: 0,0:17:11.27,0:17:12.71,Default,,0,0,0,,然后将它连接到某条链上 Dialogue: 0,0:17:13.32,0:17:15.66,Default,,0,0,0,,在这个层次上 和ALGOL差不多 Dialogue: 0,0:17:19.81,0:17:20.72,Default,,0,0,0,,还有其它问题吗? Dialogue: 0,0:17:23.70,0:17:23.92,Default,,0,0,0,,好 Dialogue: 0,0:17:23.92,0:17:25.55,Default,,0,0,0,,谢谢 我们休息一下 Dialogue: 0,0:17:26.35,0:17:45.48,Default,,0,0,0,,[音乐] Dialogue: 0,0:17:45.53,0:17:50.01,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:17:55.74,0:17:59.04,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:17:59.13,0:18:04.22,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:18:04.32,0:18:09.87,Declare,,0,0,0,,{\an2\fad(500,500)}存储分配与垃圾收集 Dialogue: 0,0:18:12.27,0:18:14.24,Default,,0,0,0,,教授:如同我刚才说过的那样 Dialogue: 0,0:18:14.55,0:18:15.50,Default,,0,0,0,,半导体厂商 Dialogue: 0,0:18:15.82,0:18:17.96,Default,,0,0,0,,所生产的计算机内存 Dialogue: 0,0:18:18.16,0:18:19.00,Default,,0,0,0,,容量是有限的 Dialogue: 0,0:18:19.42,0:18:20.40,Default,,0,0,0,,这的确很可惜 Dialogue: 0,0:18:21.62,0:18:23.35,Default,,0,0,0,,但它也可能不总是这样 Dialogue: 0,0:18:24.03,0:18:25.40,Default,,0,0,0,,简单算一下 Dialogue: 0,0:18:25.44,0:18:28.86,Default,,0,0,0,,你可以看到 如果内存的价格 Dialogue: 0,0:18:28.86,0:18:30.80,Default,,0,0,0,,继续保持当前的趋势的话 Dialogue: 0,0:18:31.22,0:18:33.68,Default,,0,0,0,,如果你执行CONS的时候也只需要1微秒 Dialogue: 0,0:18:34.42,0:18:35.90,Default,,0,0,0,,那么 首先大家知道 Dialogue: 0,0:18:35.90,0:18:37.07,Default,,0,0,0,,一年大约有 Dialogue: 0,0:18:37.10,0:18:38.86,Default,,0,0,0,,PI*10^7秒 Dialogue: 0,0:18:39.45,0:18:41.12,Default,,0,0,0,,那么就有 Dialogue: 0,0:18:41.50,0:18:42.73,Default,,0,0,0,,10^6乘以10^7 Dialogue: 0,0:18:42.73,0:18:43.94,Default,,0,0,0,,也就是10^13 Dialogue: 0,0:18:43.94,0:18:45.50,Default,,0,0,0,,那么在机器的一生中 Dialogue: 0,0:18:45.50,0:18:46.80,Default,,0,0,0,,就能有10^14个CONS Dialogue: 0,0:18:47.52,0:18:49.40,Default,,0,0,0,,如果你的机器上 Dialogue: 0,0:18:49.68,0:18:50.57,Default,,0,0,0,,有10^14个字的内存 Dialogue: 0,0:18:51.20,0:18:52.16,Default,,0,0,0,,你就永远不会用完 Dialogue: 0,0:18:53.04,0:18:53.85,Default,,0,0,0,,这样就会…… Dialogue: 0,0:18:53.95,0:18:55.76,Default,,0,0,0,,这并不是完全没有道理 Dialogue: 0,0:18:56.31,0:18:58.46,Default,,0,0,0,,10^14次方不是个非常大的数字 Dialogue: 0,0:19:01.45,0:19:04.70,Default,,0,0,0,,我不觉得它是个很大的数字 Dialogue: 0,0:19:05.18,0:19:07.39,Default,,0,0,0,,但我喜欢在天文学领域进行比较 Dialogue: 0,0:19:07.93,0:19:11.04,Default,,0,0,0,,距离我们最近的星星 Dialogue: 0,0:19:11.10,0:19:12.45,Default,,0,0,0,,至少有10^18次方厘米远 Dialogue: 0,0:19:12.93,0:19:18.85,Default,,0,0,0,,我担心的是 Dialogue: 0,0:19:19.15,0:19:21.27,Default,,0,0,0,,至少以现在的经济状况 Dialogue: 0,0:19:21.27,0:19:23.57,Default,,0,0,0,,10^14大小的内存很贵 Dialogue: 0,0:19:24.20,0:19:26.62,Default,,0,0,0,,因此我认为我们需要 Dialogue: 0,0:19:26.81,0:19:28.51,Default,,0,0,0,,适应更小的内存 Dialogue: 0,0:19:30.02,0:19:30.59,Default,,0,0,0,,现在 Dialogue: 0,0:19:32.84,0:19:35.07,Default,,0,0,0,,广义地说 我们营造一种无限内存的假象 Dialogue: 0,0:19:35.80,0:19:37.22,Default,,0,0,0,,我们需要整理它 Dialogue: 0,0:19:37.82,0:19:39.68,Default,,0,0,0,,以便在我们需要内存的时候就能获得它 Dialogue: 0,0:19:41.92,0:19:45.55,Default,,0,0,0,,这个想法非常重要 Dialogue: 0,0:19:49.54,0:19:51.97,Default,,0,0,0,,人或者计算机只能存在有限的时间 Dialogue: 0,0:19:52.32,0:19:54.59,Default,,0,0,0,,只能看有限的东西 Dialogue: 0,0:19:55.28,0:19:57.37,Default,,0,0,0,,因此你只需要有限的东西 Dialogue: 0,0:19:58.19,0:19:59.00,Default,,0,0,0,,只要你合理地安排它们 Dialogue: 0,0:19:59.00,0:20:00.38,Default,,0,0,0,,使得不管实际有多少内存 Dialogue: 0,0:20:00.77,0:20:03.46,Default,,0,0,0,,你要求这里有多少 Dialogue: 0,0:20:03.46,0:20:04.74,Default,,0,0,0,,当你去看的时候 Dialogue: 0,0:20:04.74,0:20:06.90,Default,,0,0,0,,总有足够的东西 Dialogue: 0,0:20:06.90,0:20:08.15,Default,,0,0,0,,因此你只需要有限的数量 Dialogue: 0,0:20:08.75,0:20:09.94,Default,,0,0,0,,我们来看看 Dialogue: 0,0:20:11.63,0:20:13.32,Default,,0,0,0,,我们之前提过一个问题 Dialogue: 0,0:20:13.92,0:20:15.45,Default,,0,0,0,,在很多情况下 Dialogue: 0,0:20:15.72,0:20:17.84,Default,,0,0,0,,我们制造了大量 Dialogue: 0,0:20:17.88,0:20:19.16,Default,,0,0,0,,不需要的东西 Dialogue: 0,0:20:19.41,0:20:21.81,Default,,0,0,0,,我们可以进行回收再利用 Dialogue: 0,0:20:22.62,0:20:23.53,Default,,0,0,0,,举个例子 Dialogue: 0,0:20:24.15,0:20:25.79,Default,,0,0,0,,事实上 Dialogue: 0,0:20:25.79,0:20:28.40,Default,,0,0,0,,当我们调用一个过程的时候 Dialogue: 0,0:20:28.40,0:20:30.47,Default,,0,0,0,,都会构建环境结构 Dialogue: 0,0:20:30.47,0:20:32.56,Default,,0,0,0,,我们把它构建在一个环境框架中 Dialogue: 0,0:20:33.14,0:20:34.03,Default,,0,0,0,,这个环境框架 Dialogue: 0,0:20:34.22,0:20:36.07,Default,,0,0,0,,不用存在很长时间 Dialogue: 0,0:20:36.73,0:20:38.69,Default,,0,0,0,,只有在进行过程调用的时候 Dialogue: 0,0:20:39.42,0:20:42.60,Default,,0,0,0,,它的存在才是有用的 Dialogue: 0,0:20:42.85,0:20:45.27,Default,,0,0,0,,如果过程把另一个过程 Dialogue: 0,0:20:45.27,0:20:46.67,Default,,0,0,0,,作为返回值返回 Dialogue: 0,0:20:46.87,0:20:48.52,Default,,0,0,0,,并且这个过程是在它的内部定义的 Dialogue: 0,0:20:48.52,0:20:50.80,Default,,0,0,0,,那么外层过程的 Dialogue: 0,0:20:51.07,0:20:53.39,Default,,0,0,0,,存活时间仍然是 Dialogue: 0,0:20:53.50,0:20:56.12,Default,,0,0,0,,被返回的过程的 Dialogue: 0,0:20:57.02,0:20:57.90,Default,,0,0,0,,存活时间 Dialogue: 0,0:20:58.53,0:20:59.57,Default,,0,0,0,,最终 Dialogue: 0,0:20:59.57,0:21:00.97,Default,,0,0,0,,就会制造很多垃圾 Dialogue: 0,0:21:01.96,0:21:04.10,Default,,0,0,0,,还有其它的途径可以制造垃圾 Dialogue: 0,0:21:05.37,0:21:06.67,Default,,0,0,0,,用户也会制造垃圾 Dialogue: 0,0:21:07.24,0:21:08.07,Default,,0,0,0,,举例来说 Dialogue: 0,0:21:08.07,0:21:10.22,Default,,0,0,0,,用户制造的垃圾像是这样 Dialogue: 0,0:21:10.93,0:21:14.00,Default,,0,0,0,,如果我们写个程序 Dialogue: 0,0:21:14.00,0:21:15.80,Default,,0,0,0,,把两个表连接到一起 Dialogue: 0,0:21:16.05,0:21:18.14,Default,,0,0,0,,唯一的办法是 Dialogue: 0,0:21:18.32,0:21:21.37,Default,,0,0,0,,把第一个表逆序塞到空表中 Dialogue: 0,0:21:21.37,0:21:23.72,Default,,0,0,0,,再把新表逆序塞到第二个表中 Dialogue: 0,0:21:24.70,0:21:26.92,Default,,0,0,0,,这种解法并不是很糟糕 Dialogue: 0,0:21:28.16,0:21:28.85,Default,,0,0,0,,然而 Dialogue: 0,0:21:28.85,0:21:30.09,Default,,0,0,0,,程序所生成的 Dialogue: 0,0:21:30.11,0:21:32.02,Default,,0,0,0,,中间结果 Dialogue: 0,0:21:33.87,0:21:35.57,Default,,0,0,0,,即第一个表的逆序表 Dialogue: 0,0:21:36.70,0:21:38.52,Default,,0,0,0,,在它被复制到第二个表之后 Dialogue: 0,0:21:38.52,0:21:40.56,Default,,0,0,0,,就再也不会被用到了 Dialogue: 0,0:21:41.01,0:21:42.23,Default,,0,0,0,,它是个中间结果 Dialogue: 0,0:21:43.58,0:21:45.43,Default,,0,0,0,,它很难被找到 Dialogue: 0,0:21:46.07,0:21:48.05,Default,,0,0,0,,没有人能访问到它 Dialogue: 0,0:21:48.60,0:21:49.84,Default,,0,0,0,,事实上 它会消失掉 Dialogue: 0,0:21:51.05,0:21:52.90,Default,,0,0,0,,如果我们像这样制造了大量的垃圾 Dialogue: 0,0:21:52.90,0:21:54.20,Default,,0,0,0,,系统也应该允许我们这么干 Dialogue: 0,0:21:54.80,0:21:57.29,Default,,0,0,0,,但应该有某些方法去回收这些垃圾 Dialogue: 0,0:21:58.80,0:22:00.90,Default,,0,0,0,,现在 我要告诉你 Dialogue: 0,0:22:01.70,0:22:03.77,Default,,0,0,0,,一个非常聪明的技巧 Dialogue: 0,0:22:04.32,0:22:07.58,Default,,0,0,0,,一个Lisp系统 Dialogue: 0,0:22:07.95,0:22:11.21,Default,,0,0,0,,通常可以证明一条小定理 Dialogue: 0,0:22:11.29,0:22:13.50,Default,,0,0,0,,也就是 某段内存中的值 Dialogue: 0,0:22:14.72,0:22:16.09,Default,,0,0,0,,之后不再会被用到 Dialogue: 0,0:22:17.41,0:22:19.80,Default,,0,0,0,,它对以后的计算没有任何影响 Dialogue: 0,0:22:21.40,0:22:23.61,Default,,0,0,0,,事实上 这基于一个很简单的想法 Dialogue: 0,0:22:24.72,0:22:28.06,Default,,0,0,0,,我们已经把计算机设计成这个样子 Dialogue: 0,0:22:28.95,0:22:30.67,Default,,0,0,0,,有一些数据通路 Dialogue: 0,0:22:31.87,0:22:33.40,Default,,0,0,0,,其中有寄存器 Dialogue: 0,0:22:34.92,0:22:38.04,Default,,0,0,0,,有EXP、ENV Dialogue: 0,0:22:39.04,0:22:42.19,Default,,0,0,0,,和VAL之类的寄存器 Dialogue: 0,0:22:42.61,0:22:44.02,Default,,0,0,0,,这里有个叫STACK的东西 Dialogue: 0,0:22:46.02,0:22:49.45,Default,,0,0,0,,某种指向一个结构的东西 Dialogue: 0,0:22:49.50,0:22:50.22,Default,,0,0,0,,它是个栈 Dialogue: 0,0:22:50.24,0:22:51.48,Default,,0,0,0,,我们过一会再研究它 Dialogue: 0,0:22:51.64,0:22:53.62,Default,,0,0,0,,这里有一些 Dialogue: 0,0:22:54.38,0:22:56.57,Default,,0,0,0,,有穷状态控制器 Dialogue: 0,0:22:56.73,0:22:59.51,Default,,0,0,0,,控制信号在这之间流通 Dialogue: 0,0:22:59.80,0:23:01.44,Default,,0,0,0,,比如谓词的返回结果 Dialogue: 0,0:23:01.87,0:23:03.13,Default,,0,0,0,,这部分并不太有趣 Dialogue: 0,0:23:03.35,0:23:06.51,Default,,0,0,0,,这里有某种结构化的内存 Dialogue: 0,0:23:06.80,0:23:08.27,Default,,0,0,0,,我刚才给你讲过如何构建它 Dialogue: 0,0:23:08.27,0:23:10.17,Default,,0,0,0,,它可能包括一个栈 Dialogue: 0,0:23:10.46,0:23:11.48,Default,,0,0,0,,我没有告诉你如何把东西 Dialogue: 0,0:23:11.48,0:23:12.43,Default,,0,0,0,,构建成任意形状 Dialogue: 0,0:23:12.56,0:23:13.39,Default,,0,0,0,,只有序对 Dialogue: 0,0:23:13.60,0:23:14.20,Default,,0,0,0,,但事实上 Dialogue: 0,0:23:14.35,0:23:15.44,Default,,0,0,0,,我告诉过你 Dialogue: 0,0:23:15.47,0:23:16.96,Default,,0,0,0,,可以用一张大表来模拟栈 Dialogue: 0,0:23:17.77,0:23:18.85,Default,,0,0,0,,我没准备干这个 Dialogue: 0,0:23:18.85,0:23:20.01,Default,,0,0,0,,这不是个好办法 Dialogue: 0,0:23:20.36,0:23:22.60,Default,,0,0,0,,但是我们可以有这样一个东西 Dialogue: 0,0:23:22.99,0:23:25.28,Default,,0,0,0,,这里有各种数据结构 Dialogue: 0,0:23:25.64,0:23:27.75,Default,,0,0,0,,它们通过有趣的方式互相连接 Dialogue: 0,0:23:30.11,0:23:32.02,Default,,0,0,0,,它们和其它东西连接到一起 Dialogue: 0,0:23:32.56,0:23:33.25,Default,,0,0,0,,以此类推 Dialogue: 0,0:23:33.25,0:23:34.22,Default,,0,0,0,,归根结底 Dialogue: 0,0:23:34.45,0:23:37.19,Default,,0,0,0,,这里的东西是指向这里的指针 Dialogue: 0,0:23:37.19,0:23:38.87,Default,,0,0,0,,寄存器里的指针 Dialogue: 0,0:23:39.40,0:23:41.40,Default,,0,0,0,,指向的是表结构内存中 Dialogue: 0,0:23:41.44,0:23:43.08,Default,,0,0,0,,数据结构 Dialogue: 0,0:23:44.91,0:23:49.80,Default,,0,0,0,,现在 我们的问题是 Dialogue: 0,0:23:51.05,0:23:52.56,Default,,0,0,0,,机器的整个意识 Dialogue: 0,0:23:52.57,0:23:53.92,Default,,0,0,0,,是在寄存器里的 Dialogue: 0,0:23:55.76,0:23:58.51,Default,,0,0,0,,如果这个机器 Dialogue: 0,0:23:58.75,0:24:01.07,Default,,0,0,0,,构建得正确的话 Dialogue: 0,0:24:01.37,0:24:03.41,Default,,0,0,0,,它无法访问表结构内存中任何的东西 Dialogue: 0,0:24:04.57,0:24:07.05,Default,,0,0,0,,除非这个表结构内存中的数据 Dialogue: 0,0:24:08.09,0:24:10.88,Default,,0,0,0,,通过一系列的数据结构 Dialogue: 0,0:24:11.64,0:24:13.06,Default,,0,0,0,,与寄存器相连接 Dialogue: 0,0:24:15.07,0:24:15.98,Default,,0,0,0,,如果它能够 Dialogue: 0,0:24:16.22,0:24:18.31,Default,,0,0,0,,被合法的数据结构选择函数访问到 Dialogue: 0,0:24:19.08,0:24:21.12,Default,,0,0,0,,通过寄存器里保存的指针能够访问它 Dialogue: 0,0:24:22.28,0:24:24.46,Default,,0,0,0,,比如说 数组引用 Dialogue: 0,0:24:24.94,0:24:27.92,Default,,0,0,0,,或者针对序对的引用--CAR或者CDR Dialogue: 0,0:24:29.08,0:24:30.95,Default,,0,0,0,,但我不能随意访问内存中的位置 Dialogue: 0,0:24:30.95,0:24:31.95,Default,,0,0,0,,因为我找不到它 Dialogue: 0,0:24:32.74,0:24:34.90,Default,,0,0,0,,至少在我求值某条表达式的时候 Dialogue: 0,0:24:37.00,0:24:39.16,Default,,0,0,0,,我是不允许去访问那个任意名字的 Dialogue: 0,0:24:41.62,0:24:42.57,Default,,0,0,0,,如果是这样的话 Dialogue: 0,0:24:43.27,0:24:45.07,Default,,0,0,0,,就可以证明一个简单的理论 Dialogue: 0,0:24:47.16,0:24:47.69,Default,,0,0,0,,就是说 Dialogue: 0,0:24:47.90,0:24:50.52,Default,,0,0,0,,如果我从这些寄存器指向的地方开始 Dialogue: 0,0:24:51.16,0:24:52.55,Default,,0,0,0,,递归地遍历 Dialogue: 0,0:24:52.82,0:24:56.15,Default,,0,0,0,,标记选择函数所有能访问到内存 Dialogue: 0,0:24:56.90,0:24:59.40,Default,,0,0,0,,最终就能标记所有能访问的东西 Dialogue: 0,0:25:00.65,0:25:02.69,Default,,0,0,0,,任何未标记的都是垃圾 Dialogue: 0,0:25:02.69,0:25:03.75,Default,,0,0,0,,它们可以被回收 Dialogue: 0,0:25:05.56,0:25:06.20,Default,,0,0,0,,非常简单 Dialogue: 0,0:25:07.20,0:25:09.10,Default,,0,0,0,,不会影响之后的计算 Dialogue: 0,0:25:11.18,0:25:12.84,Default,,0,0,0,,我来举一个 Dialogue: 0,0:25:13.93,0:25:15.75,Default,,0,0,0,,具体的例子 Dialogue: 0,0:25:17.12,0:25:19.37,Default,,0,0,0,,在此之前 需要给我的表结构内存 Dialogue: 0,0:25:19.69,0:25:22.08,Default,,0,0,0,,添加一个叫MARK的标志位 Dialogue: 0,0:25:23.64,0:25:24.89,Default,,0,0,0,,因此 在这里 Dialogue: 0,0:25:25.37,0:25:27.28,Default,,0,0,0,,就有一个表结构内存 Dialogue: 0,0:25:29.08,0:25:30.32,Default,,0,0,0,,这块表内存中 Dialogue: 0,0:25:30.33,0:25:31.33,Default,,0,0,0,,存放了一个表数据结构 Dialogue: 0,0:25:31.33,0:25:33.95,Default,,0,0,0,,我们把这个起始位置 Dialogue: 0,0:25:35.87,0:25:36.62,Default,,0,0,0,,称为“根” Dialogue: 0,0:25:38.59,0:25:40.12,Default,,0,0,0,,不一定只有一个根 Dialogue: 0,0:25:40.12,0:25:41.95,Default,,0,0,0,,与寄存器类似 可以有很多这种东西 Dialogue: 0,0:25:42.67,0:25:43.98,Default,,0,0,0,,但我可以巧妙地安排它们 Dialogue: 0,0:25:44.13,0:25:46.30,Default,,0,0,0,,把所有在旧寄存器里的东西 Dialogue: 0,0:25:46.30,0:25:47.77,Default,,0,0,0,,在何时的时间点 Dialogue: 0,0:25:48.28,0:25:50.46,Default,,0,0,0,,放入到这个根结构中 Dialogue: 0,0:25:50.46,0:25:51.85,Default,,0,0,0,,然后用一个指针指向它 Dialogue: 0,0:25:51.85,0:25:52.67,Default,,0,0,0,,这不是重点 Dialogue: 0,0:25:54.57,0:25:55.63,Default,,0,0,0,,思路就是 Dialogue: 0,0:25:55.64,0:25:56.65,Default,,0,0,0,,我们要不断地进行CONS Dialogue: 0,0:25:56.67,0:25:58.01,Default,,0,0,0,,直到空闲表为空 Dialogue: 0,0:25:58.72,0:25:59.67,Default,,0,0,0,,这样就用尽了所有空间 Dialogue: 0,0:26:00.95,0:26:04.47,Default,,0,0,0,,现在我们要证明这个理论 Dialogue: 0,0:26:04.47,0:26:05.90,Default,,0,0,0,,也就是一部分的内存 Dialogue: 0,0:26:05.95,0:26:06.90,Default,,0,0,0,,已经没有用了 Dialogue: 0,0:26:07.85,0:26:09.15,Default,,0,0,0,,然后我们要回收它 Dialogue: 0,0:26:09.78,0:26:10.87,Default,,0,0,0,,构建一个新的树 Dialogue: 0,0:26:12.19,0:26:14.57,Default,,0,0,0,,这是这些垃圾的标准使用方式 Dialogue: 0,0:26:17.09,0:26:18.64,Default,,0,0,0,,那么我们要做什么呢? Dialogue: 0,0:26:18.84,0:26:20.78,Default,,0,0,0,,从P5这个位置开始 Dialogue: 0,0:26:20.89,0:26:24.27,Default,,0,0,0,,存了一些数据结构 Dialogue: 0,0:26:25.15,0:26:26.75,Default,,0,0,0,,说错了--是从1开始 Dialogue: 0,0:26:27.27,0:26:28.51,Default,,0,0,0,,事实上 Dialogue: 0,0:26:28.89,0:26:32.20,Default,,0,0,0,,它的CAR部分存放在P5这个位置 Dialogue: 0,0:26:32.27,0:26:33.58,Default,,0,0,0,,而CDR部分存在在P2这个位置 Dialogue: 0,0:26:33.98,0:26:35.64,Default,,0,0,0,,最开始 所有的标记都是0 Dialogue: 0,0:26:36.70,0:26:39.00,Default,,0,0,0,,我们要开始标记了 Dialogue: 0,0:26:39.92,0:26:40.52,Default,,0,0,0,,好 Dialogue: 0,0:26:42.54,0:26:44.27,Default,,0,0,0,,例如 Dialogue: 0,0:26:44.47,0:26:46.95,Default,,0,0,0,,因为我可以从根访问到位置P1 Dialogue: 0,0:26:46.95,0:26:47.82,Default,,0,0,0,,我就标记一下 Dialogue: 0,0:26:48.39,0:26:49.17,Default,,0,0,0,,我来标一下 Dialogue: 0,0:26:50.96,0:26:51.45,Default,,0,0,0,,好了 Dialogue: 0,0:26:52.22,0:26:52.94,Default,,0,0,0,,这个被标记了 Dialogue: 0,0:26:54.41,0:26:57.51,Default,,0,0,0,,因为它指向位置P5 Dialogue: 0,0:26:57.64,0:26:58.64,Default,,0,0,0,,所以我来到了5号格子 Dialogue: 0,0:26:59.02,0:27:00.72,Default,,0,0,0,,然后 我要标记这个 Dialogue: 0,0:27:01.45,0:27:01.76,Default,,0,0,0,,标好了 Dialogue: 0,0:27:01.76,0:27:02.60,Default,,0,0,0,,这个笔真好用 Dialogue: 0,0:27:02.90,0:27:05.10,Default,,0,0,0,,但是5号位置的CAR部分是一个数字 Dialogue: 0,0:27:05.27,0:27:06.65,Default,,0,0,0,,我对标记数字不感兴趣 Dialogue: 0,0:27:06.91,0:27:08.17,Default,,0,0,0,,但它的CDR部分是P7 Dialogue: 0,0:27:08.70,0:27:09.75,Default,,0,0,0,,所以我可以标记它 Dialogue: 0,0:27:10.45,0:27:10.81,Default,,0,0,0,,又标好了 Dialogue: 0,0:27:11.80,0:27:13.40,Default,,0,0,0,,P7的CDR部分是空表 Dialogue: 0,0:27:13.67,0:27:15.10,Default,,0,0,0,,而它唯一所引用的元素则是 Dialogue: 0,0:27:15.59,0:27:17.12,Default,,0,0,0,,它的CAR部分是个数字 Dialogue: 0,0:27:17.12,0:27:17.85,Default,,0,0,0,,我对它不感兴趣 Dialogue: 0,0:27:19.49,0:27:20.50,Default,,0,0,0,,让我们回到这里 Dialogue: 0,0:27:20.50,0:27:21.65,Default,,0,0,0,,我忘记了一些事情 Dialogue: 0,0:27:21.65,0:27:22.17,Default,,0,0,0,,P2 Dialogue: 0,0:27:22.84,0:27:24.85,Default,,0,0,0,,换句话说 如果我看1号格子 Dialogue: 0,0:27:25.42,0:27:29.45,Default,,0,0,0,,1号格子的CDR部分指向P2 Dialogue: 0,0:27:30.37,0:27:31.30,Default,,0,0,0,,一个指向P2的引用 Dialogue: 0,0:27:32.01,0:27:34.97,Default,,0,0,0,,这意味着我应该标记P2 Dialogue: 0,0:27:35.70,0:27:36.27,Default,,0,0,0,,好了 Dialogue: 0,0:27:37.14,0:27:38.89,Default,,0,0,0,,P2包含了了一个到P4的引用 Dialogue: 0,0:27:39.13,0:27:40.27,Default,,0,0,0,,而P2的CAR部分是个数字 Dialogue: 0,0:27:40.27,0:27:41.20,Default,,0,0,0,,我对它不感兴趣 Dialogue: 0,0:27:41.47,0:27:42.60,Default,,0,0,0,,所以我要标记P4 Dialogue: 0,0:27:43.78,0:27:46.10,Default,,0,0,0,,P4的CAR部分引用了P7 Dialogue: 0,0:27:46.75,0:27:48.17,Default,,0,0,0,,它的CDR是空的 Dialogue: 0,0:27:48.47,0:27:49.57,Default,,0,0,0,,但由于我已经标记过P7了 Dialogue: 0,0:27:49.57,0:27:50.75,Default,,0,0,0,,就不再次标记它了 Dialogue: 0,0:27:51.40,0:27:53.05,Default,,0,0,0,,这就是这个地方 Dialogue: 0,0:27:53.07,0:27:53.87,Default,,0,0,0,,所能访问的所有单元 Dialogue: 0,0:27:55.00,0:27:56.57,Default,,0,0,0,,很简单的递归标记算法 Dialogue: 0,0:27:58.71,0:28:01.79,Default,,0,0,0,,这个算法有一些不足的地方 Dialogue: 0,0:28:01.90,0:28:04.02,Default,,0,0,0,,我们稍后会说 Dialogue: 0,0:28:04.92,0:28:06.16,Default,,0,0,0,,但基本上你能看到 Dialogue: 0,0:28:06.19,0:28:07.85,Default,,0,0,0,,所有没被标记的地方 Dialogue: 0,0:28:09.62,0:28:11.50,Default,,0,0,0,,都是无用的 Dialogue: 0,0:28:11.50,0:28:12.41,Default,,0,0,0,,可以回收 Dialogue: 0,0:28:14.25,0:28:15.75,Default,,0,0,0,,所以下一步就是 Dialogue: 0,0:28:15.75,0:28:17.05,Default,,0,0,0,,扫描整个内存 Dialogue: 0,0:28:17.94,0:28:20.35,Default,,0,0,0,,寻找未被标记的格子 Dialogue: 0,0:28:21.18,0:28:22.45,Default,,0,0,0,,每当遇到一个已标记的格子 Dialogue: 0,0:28:22.45,0:28:23.22,Default,,0,0,0,,就把标记去掉 Dialogue: 0,0:28:23.22,0:28:24.86,Default,,0,0,0,,每当遇到未标记的格子时 Dialogue: 0,0:28:25.07,0:28:27.82,Default,,0,0,0,,我就把它连接到我的空闲表中 Dialogue: 0,0:28:28.77,0:28:30.30,Default,,0,0,0,,传统而且非常简单的算法 Dialogue: 0,0:28:32.12,0:28:33.10,Default,,0,0,0,,我们来看看 Dialogue: 0,0:28:33.84,0:28:34.77,Default,,0,0,0,,它很简单吗? Dialogue: 0,0:28:34.77,0:28:35.42,Default,,0,0,0,,是的 Dialogue: 0,0:28:35.57,0:28:37.79,Default,,0,0,0,,我不会深入代码细节 Dialogue: 0,0:28:38.00,0:28:39.65,Default,,0,0,0,,只是想给你看看它有多长 Dialogue: 0,0:28:40.09,0:28:41.10,Default,,0,0,0,,看这个标记阶段 Dialogue: 0,0:28:41.72,0:28:43.98,Default,,0,0,0,,这是标记阶段的第一部分 Dialogue: 0,0:28:45.06,0:28:46.00,Default,,0,0,0,,我们找到根 Dialogue: 0,0:28:46.32,0:28:47.52,Default,,0,0,0,,我们要 Dialogue: 0,0:28:47.67,0:28:51.05,Default,,0,0,0,,对它进行递归过程调用 Dialogue: 0,0:28:52.38,0:28:54.47,Default,,0,0,0,,当我们完成标记之后 Dialogue: 0,0:28:54.77,0:28:56.95,Default,,0,0,0,,就从这里开始清除 Dialogue: 0,0:28:57.38,0:28:59.79,Default,,0,0,0,,然后我们将执行一些指令 Dialogue: 0,0:28:59.80,0:29:01.36,Default,,0,0,0,,来检查这些标记 Dialogue: 0,0:29:01.39,0:29:03.07,Default,,0,0,0,,或者更改这些标记 Dialogue: 0,0:29:03.07,0:29:04.90,Default,,0,0,0,,按照我刚才讲的那个算法进行 Dialogue: 0,0:29:05.23,0:29:06.47,Default,,0,0,0,,代码在这里 Dialogue: 0,0:29:06.47,0:29:07.65,Default,,0,0,0,,你需要标记它们的CAR Dialogue: 0,0:29:07.87,0:29:10.21,Default,,0,0,0,,也需要标记它们的CDR Dialogue: 0,0:29:10.66,0:29:12.10,Default,,0,0,0,,这就是整个标记阶段 Dialogue: 0,0:29:14.37,0:29:16.16,Default,,0,0,0,,我给你讲个关于它的小故事 Dialogue: 0,0:29:16.59,0:29:19.37,Default,,0,0,0,,古董货DEC PDP-6计算机 Dialogue: 0,0:29:20.93,0:29:22.09,Default,,0,0,0,,它上面的 Dialogue: 0,0:29:22.35,0:29:24.85,Default,,0,0,0,,标记-清除垃圾回收系统就是这么写的 Dialogue: 0,0:29:26.91,0:29:28.40,Default,,0,0,0,,程序很短 Dialogue: 0,0:29:29.25,0:29:31.60,Default,,0,0,0,,以至于它需要的数据 Dialogue: 0,0:29:32.20,0:29:34.87,Default,,0,0,0,,以及用来操作内存的所需的寄存器 Dialogue: 0,0:29:36.16,0:29:38.14,Default,,0,0,0,,都能够放入到计算机的 Dialogue: 0,0:29:38.16,0:29:38.97,Default,,0,0,0,,16个快速寄存器中 Dialogue: 0,0:29:39.28,0:29:39.80,Default,,0,0,0,,整个程序 Dialogue: 0,0:29:40.01,0:29:42.01,Default,,0,0,0,,你可以在快速寄存器里执行指令 Dialogue: 0,0:29:43.17,0:29:44.83,Default,,0,0,0,,所以这是个非常小的程序 Dialogue: 0,0:29:45.85,0:29:46.88,Default,,0,0,0,,它跑得飞快 Dialogue: 0,0:29:48.87,0:29:51.30,Default,,0,0,0,,然而很不幸 Dialogue: 0,0:29:51.61,0:29:54.02,Default,,0,0,0,,因为这个程序是递归的 Dialogue: 0,0:29:54.80,0:29:57.55,Default,,0,0,0,,因为你需要先做某件事儿 Dialogue: 0,0:29:57.55,0:29:58.99,Default,,0,0,0,,然后再去做另外一件事儿 Dialogue: 0,0:29:59.21,0:30:00.88,Default,,0,0,0,,你得先处理CAR 再处理CDR Dialogue: 0,0:30:01.15,0:30:02.75,Default,,0,0,0,,这就需要辅助内存 Dialogue: 0,0:30:03.41,0:30:05.23,Default,,0,0,0,,所以Lisp系统 Dialogue: 0,0:30:05.44,0:30:07.42,Default,,0,0,0,,需要一个栈来进行标记 Dialogue: 0,0:30:08.26,0:30:11.05,Default,,0,0,0,,Lisp系统通过这样的方式 Dialogue: 0,0:30:11.57,0:30:14.16,Default,,0,0,0,,限制了你在数据结构上 Dialogue: 0,0:30:14.42,0:30:17.37,Default,,0,0,0,,进行CAR或者CDR递归的深度 Dialogue: 0,0:30:17.81,0:30:19.35,Default,,0,0,0,,这并不太靠谱 Dialogue: 0,0:30:19.93,0:30:20.60,Default,,0,0,0,,另外一方面 Dialogue: 0,0:30:20.64,0:30:22.12,Default,,0,0,0,,当它足够大的时候你不会发现 Dialogue: 0,0:30:23.18,0:30:25.13,Default,,0,0,0,,例如 这样的情况 Dialogue: 0,0:30:25.55,0:30:28.17,Default,,0,0,0,,发生在大多数MacLisp系统上 Dialogue: 0,0:30:28.69,0:30:29.88,Default,,0,0,0,,在它上面运行的Macsyma Dialogue: 0,0:30:29.96,0:30:31.10,Default,,0,0,0,,允许你处理 Dialogue: 0,0:30:31.10,0:30:32.72,Default,,0,0,0,,有成千上万个元素的表达式 Dialogue: 0,0:30:33.56,0:30:36.02,Default,,0,0,0,,有很多代数式有大量的项 Dialogue: 0,0:30:36.82,0:30:38.10,Default,,0,0,0,,这没什么问题 Dialogue: 0,0:30:39.49,0:30:40.82,Default,,0,0,0,,垃圾回收器能正常工作 Dialogue: 0,0:30:42.19,0:30:42.92,Default,,0,0,0,,另一方面 Dialogue: 0,0:30:42.92,0:30:45.37,Default,,0,0,0,,这个算法有个很精妙的修改版 Dialogue: 0,0:30:45.37,0:30:46.47,Default,,0,0,0,,但我不会去讲 Dialogue: 0,0:30:46.80,0:30:48.22,Default,,0,0,0,,它是由Peter Deutsch Dialogue: 0,0:30:48.64,0:30:51.82,Default,,0,0,0,,来自IBM的Herb Schorr Dialogue: 0,0:30:51.87,0:30:53.52,Default,,0,0,0,,和我不太认识的Waite所提出 Dialogue: 0,0:30:54.01,0:30:56.51,Default,,0,0,0,,这个算法 Dialogue: 0,0:30:56.67,0:30:57.79,Default,,0,0,0,,可以不使用 Dialogue: 0,0:30:57.84,0:30:59.55,Default,,0,0,0,,额外的辅助内存 Dialogue: 0,0:31:00.50,0:31:02.80,Default,,0,0,0,,只需要在遍历整个数据结构的时候 Dialogue: 0,0:31:02.97,0:31:05.52,Default,,0,0,0,,记住你是从哪里来的并反转指针 Dialogue: 0,0:31:05.52,0:31:07.52,Default,,0,0,0,,回溯的时候 再去反转这个指针 Dialogue: 0,0:31:07.79,0:31:08.99,Default,,0,0,0,,这是个很取巧的算法 Dialogue: 0,0:31:09.13,0:31:10.24,Default,,0,0,0,,你第一次写它的时候 Dialogue: 0,0:31:10.25,0:31:11.71,Default,,0,0,0,,事实上 你前三次写它的时候 Dialogue: 0,0:31:11.71,0:31:12.72,Default,,0,0,0,,都会遇到严重的BUG Dialogue: 0,0:31:14.35,0:31:16.72,Default,,0,0,0,,也可能奇慢无比 Dialogue: 0,0:31:16.72,0:31:17.67,Default,,0,0,0,,因为这个算法太复杂了 Dialogue: 0,0:31:18.11,0:31:20.30,Default,,0,0,0,,它用了大概六倍的内存引用 Dialogue: 0,0:31:20.85,0:31:23.22,Default,,0,0,0,,来完成我们刚才讨论的任务 Dialogue: 0,0:31:24.58,0:31:27.07,Default,,0,0,0,,一旦我完成了标记阶段 Dialogue: 0,0:31:27.50,0:31:30.12,Default,,0,0,0,,我们就面临着这样的状况 Dialogue: 0,0:31:30.17,0:31:31.26,Default,,0,0,0,,请看 Dialogue: 0,0:31:31.51,0:31:34.03,Default,,0,0,0,,这里完成了标记工作 Dialogue: 0,0:31:34.08,0:31:35.00,Default,,0,0,0,,和我刚才描述的一样 Dialogue: 0,0:31:35.59,0:31:37.33,Default,,0,0,0,,现在我们要进行清除阶段 Dialogue: 0,0:31:37.60,0:31:39.32,Default,,0,0,0,,我刚才已经讲过如何清除了 Dialogue: 0,0:31:39.82,0:31:42.34,Default,,0,0,0,,我要从内存的一端开始 Dialogue: 0,0:31:42.34,0:31:43.34,Default,,0,0,0,,哪一端都可以 Dialogue: 0,0:31:43.62,0:31:46.17,Default,,0,0,0,,扫描内存中的每个格子 Dialogue: 0,0:31:47.17,0:31:48.67,Default,,0,0,0,,在扫描的同时 Dialogue: 0,0:31:49.20,0:31:50.97,Default,,0,0,0,,如果是空闲内存 Dialogue: 0,0:31:50.99,0:31:52.84,Default,,0,0,0,,就把它们连接到空闲表中 Dialogue: 0,0:31:53.15,0:31:54.05,Default,,0,0,0,,如果它们不是空闲内存 Dialogue: 0,0:31:54.05,0:31:56.07,Default,,0,0,0,,我就把它们的标记清除掉 Dialogue: 0,0:31:57.50,0:31:58.57,Default,,0,0,0,,事实上 Dialogue: 0,0:31:58.70,0:32:00.46,Default,,0,0,0,,最终的程序并不很复杂 Dialogue: 0,0:32:00.46,0:32:02.22,Default,,0,0,0,,它只是变长了一些 Dialogue: 0,0:32:02.78,0:32:04.17,Default,,0,0,0,,这是第一部分 Dialogue: 0,0:32:04.82,0:32:06.71,Default,,0,0,0,,它从内存的顶端向下遍历 Dialogue: 0,0:32:06.71,0:32:09.58,Default,,0,0,0,,我不期望你现在就搞懂它 Dialogue: 0,0:32:09.58,0:32:10.55,Default,,0,0,0,,它挺简单的 Dialogue: 0,0:32:11.03,0:32:12.52,Default,,0,0,0,,这是个非常简单的算法 Dialogue: 0,0:32:13.07,0:32:15.97,Default,,0,0,0,,其中的一段代码像是这样 Dialogue: 0,0:32:15.97,0:32:17.37,Default,,0,0,0,,非常显而易见 Dialogue: 0,0:32:18.60,0:32:20.08,Default,,0,0,0,,在清理结束后 Dialogue: 0,0:32:20.30,0:32:21.77,Default,,0,0,0,,我们就得到了像这样的结果 Dialogue: 0,0:32:25.33,0:32:26.54,Default,,0,0,0,,这种标记-清除算法 Dialogue: 0,0:32:26.56,0:32:28.20,Default,,0,0,0,,有一些缺点 Dialogue: 0,0:32:29.59,0:32:30.35,Default,,0,0,0,,最严重的一个是 Dialogue: 0,0:32:31.45,0:32:33.20,Default,,0,0,0,,最严重的缺点是 Dialogue: 0,0:32:33.20,0:32:34.97,Default,,0,0,0,,当你的内存越来越大 Dialogue: 0,0:32:36.82,0:32:38.87,Default,,0,0,0,,地址空间也就会越来越大 Dialogue: 0,0:32:38.87,0:32:40.80,Default,,0,0,0,,你想用它存更多东西 Dialogue: 0,0:32:41.37,0:32:44.52,Default,,0,0,0,,那么扫描整个内存就会非常耗时 Dialogue: 0,0:32:46.36,0:32:47.39,Default,,0,0,0,,你真正想做的是 Dialogue: 0,0:32:47.40,0:32:48.68,Default,,0,0,0,,只扫描有用的东西 Dialogue: 0,0:32:50.49,0:32:51.55,Default,,0,0,0,,这样就会好一点 Dialogue: 0,0:32:52.07,0:32:53.90,Default,,0,0,0,,如果你意识到 Dialogue: 0,0:32:54.48,0:32:57.72,Default,,0,0,0,,哪些东西已知是有用的 Dialogue: 0,0:32:58.28,0:33:00.37,Default,,0,0,0,,你就没必要去多次检查它 Dialogue: 0,0:33:00.37,0:33:01.20,Default,,0,0,0,,或者不用经常去检查它 Dialogue: 0,0:33:01.55,0:33:04.32,Default,,0,0,0,,对于那些你不太确定的 Dialogue: 0,0:33:05.00,0:33:06.22,Default,,0,0,0,,你可以在每次需要的时候 Dialogue: 0,0:33:07.10,0:33:08.75,Default,,0,0,0,,进行仔细检查 Dialogue: 0,0:33:09.93,0:33:10.85,Default,,0,0,0,,也就是垃圾收集的时候 Dialogue: 0,0:33:11.91,0:33:13.74,Default,,0,0,0,,这些算法 Dialogue: 0,0:33:13.76,0:33:15.10,Default,,0,0,0,,就是用了这样的方法 Dialogue: 0,0:33:15.66,0:33:18.16,Default,,0,0,0,,我要介绍一个著名的古老算法 Dialogue: 0,0:33:18.28,0:33:19.47,Default,,0,0,0,,这种算法允许你 Dialogue: 0,0:33:19.50,0:33:21.37,Default,,0,0,0,,只检查内存中已知是有用的部分 Dialogue: 0,0:33:23.12,0:33:23.85,Default,,0,0,0,,这让它成为了 Dialogue: 0,0:33:23.87,0:33:25.29,Default,,0,0,0,,目前已知最快的垃圾收集算法 Dialogue: 0,0:33:26.31,0:33:29.45,Default,,0,0,0,,它就是 Minsky-Fenichel-Yochelson 垃圾收集算法 Dialogue: 0,0:33:30.40,0:33:33.18,Default,,0,0,0,,它是由Minsky Dialogue: 0,0:33:33.20,0:33:36.06,Default,,0,0,0,,在1960、61年左右发明的 Dialogue: 0,0:33:36.52,0:33:40.48,Default,,0,0,0,,当时是给RLE PDP-1 Lisp用的 Dialogue: 0,0:33:40.51,0:33:43.44,Default,,0,0,0,,这个机器只有4096个字的线性内存 Dialogue: 0,0:33:45.79,0:33:46.76,Default,,0,0,0,,还有个磁鼓 Dialogue: 0,0:33:48.48,0:33:49.39,Default,,0,0,0,,为了能够 Dialogue: 0,0:33:50.03,0:33:51.87,Default,,0,0,0,,在这种恶劣的条件下进行垃圾收集 Dialogue: 0,0:33:53.05,0:33:54.35,Default,,0,0,0,,Minsky意识到 Dialogue: 0,0:33:54.38,0:33:55.62,Default,,0,0,0,,达成目的最容易的方法是 Dialogue: 0,0:33:56.20,0:33:58.47,Default,,0,0,0,,在扫描内存的同时 Dialogue: 0,0:33:58.47,0:34:00.60,Default,,0,0,0,,遍历那些好的数据结构 Dialogue: 0,0:34:01.57,0:34:03.52,Default,,0,0,0,,把它复制到磁鼓中 Dialogue: 0,0:34:04.70,0:34:05.47,Default,,0,0,0,,压缩一下 Dialogue: 0,0:34:06.35,0:34:08.86,Default,,0,0,0,,之后把它们复制出来 Dialogue: 0,0:34:09.12,0:34:10.90,Default,,0,0,0,,并把它们交换回内存里 Dialogue: 0,0:34:12.30,0:34:13.68,Default,,0,0,0,,不管是使用的是磁鼓 Dialogue: 0,0:34:13.72,0:34:14.71,Default,,0,0,0,,或者其它的内存 Dialogue: 0,0:34:14.71,0:34:16.42,Default,,0,0,0,,这都不重要 Dialogue: 0,0:34:17.03,0:34:17.42,Default,,0,0,0,,事实上 Dialogue: 0,0:34:17.44,0:34:19.60,Default,,0,0,0,,我觉得现在应该没人用磁鼓了吧 Dialogue: 0,0:34:20.35,0:34:23.77,Default,,0,0,0,,但这个算法基本上 Dialogue: 0,0:34:24.03,0:34:25.42,Default,,0,0,0,,要依赖于 Dialogue: 0,0:34:25.42,0:34:27.42,Default,,0,0,0,,大约两倍于 Dialogue: 0,0:34:27.48,0:34:28.57,Default,,0,0,0,,你实际使用的内存 Dialogue: 0,0:34:30.27,0:34:32.96,Default,,0,0,0,,最开始的情况是 Dialogue: 0,0:34:33.12,0:34:36.60,Default,,0,0,0,,有用的数据和垃圾混在了一起 Dialogue: 0,0:34:37.11,0:34:38.97,Default,,0,0,0,,它被称为FROMSPACE Dialogue: 0,0:34:45.17,0:34:47.05,Default,,0,0,0,,这是CRUD的混合 Dialogue: 0,0:34:47.87,0:34:49.79,Default,,0,0,0,,有些是有用的 有些没有用 Dialogue: 0,0:34:52.00,0:34:53.85,Default,,0,0,0,,现在还有另外一块空间 Dialogue: 0,0:34:54.17,0:34:55.61,Default,,0,0,0,,它需要足够大 Dialogue: 0,0:34:55.77,0:34:57.00,Default,,0,0,0,,这个地方叫TOSPACE Dialogue: 0,0:34:57.12,0:34:58.24,Default,,0,0,0,,要把东西复制进去 Dialogue: 0,0:35:01.59,0:35:02.60,Default,,0,0,0,,接下来会发生的是 Dialogue: 0,0:35:02.60,0:35:04.06,Default,,0,0,0,,我不会深入细节 Dialogue: 0,0:35:04.16,0:35:07.07,Default,,0,0,0,,书上写得很清楚了 Dialogue: 0,0:35:07.59,0:35:10.40,Default,,0,0,0,,这里有一个根节点 Dialogue: 0,0:35:11.03,0:35:14.30,Default,,0,0,0,,你从根节点开始 Dialogue: 0,0:35:14.60,0:35:16.42,Default,,0,0,0,,复制你看到的第一个东西 Dialogue: 0,0:35:17.83,0:35:19.37,Default,,0,0,0,,根指针指向的第一个东西 Dialogue: 0,0:35:19.75,0:35:21.31,Default,,0,0,0,,复制到TOSPACE的头部 Dialogue: 0,0:35:22.81,0:35:24.12,Default,,0,0,0,,这些东西一般是一个序对 Dialogue: 0,0:35:24.16,0:35:25.60,Default,,0,0,0,,或者是类似的数据结构 Dialogue: 0,0:35:27.56,0:35:30.19,Default,,0,0,0,,然后在那里留下 Dialogue: 0,0:35:30.38,0:35:31.56,Default,,0,0,0,,一颗“破碎的心” Dialogue: 0,0:35:31.77,0:35:35.74,Default,,0,0,0,,表示我把东西从这里移动到了这里 Dialogue: 0,0:35:35.74,0:35:37.05,Default,,0,0,0,,指示了移动的目的地 Dialogue: 0,0:35:37.80,0:35:39.65,Default,,0,0,0,,叫作破碎的心是因为 Dialogue: 0,0:35:39.65,0:35:40.78,Default,,0,0,0,,我的一个朋友 Dialogue: 0,0:35:40.78,0:35:43.39,Default,,0,0,0,,在1966年实现了这个算法 Dialogue: 0,0:35:43.82,0:35:45.26,Default,,0,0,0,,而他是个文艺青年 Dialogue: 0,0:35:45.26,0:35:46.76,Default,,0,0,0,,就取名叫“破碎的心” Dialogue: 0,0:35:49.58,0:35:50.54,Default,,0,0,0,,不论如何 Dialogue: 0,0:35:51.15,0:35:52.72,Default,,0,0,0,,接下来要做的是 Dialogue: 0,0:35:52.94,0:35:55.00,Default,,0,0,0,,FREE指针现在指向这里 Dialogue: 0,0:35:55.17,0:35:56.38,Default,,0,0,0,,然后开始扫描 Dialogue: 0,0:35:56.88,0:35:59.68,Default,,0,0,0,,扫描这个刚复制过来的数据结构 Dialogue: 0,0:36:00.55,0:36:02.19,Default,,0,0,0,,每当你遇到其中的指针 Dialogue: 0,0:36:02.19,0:36:03.92,Default,,0,0,0,,你把它当作是这里的根指针 Dialogue: 0,0:36:04.00,0:36:04.59,Default,,0,0,0,,哦 不好意思 Dialogue: 0,0:36:04.60,0:36:05.69,Default,,0,0,0,,我们还需要做的是 Dialogue: 0,0:36:05.71,0:36:07.08,Default,,0,0,0,,你将根指针移动到这里 Dialogue: 0,0:36:09.22,0:36:10.17,Default,,0,0,0,,因此在扫描的过程中 Dialogue: 0,0:36:10.17,0:36:10.99,Default,,0,0,0,,把遇到的每个指针 Dialogue: 0,0:36:11.00,0:36:12.41,Default,,0,0,0,,都可以当作是ROOT指针 Dialogue: 0,0:36:14.11,0:36:15.45,Default,,0,0,0,,如果你遇到了某个指针 Dialogue: 0,0:36:15.45,0:36:17.40,Default,,0,0,0,,指向了这里的某个地方 Dialogue: 0,0:36:18.51,0:36:19.92,Default,,0,0,0,,它指向的东西 Dialogue: 0,0:36:19.93,0:36:20.99,Default,,0,0,0,,你复制过了吗? Dialogue: 0,0:36:21.78,0:36:22.87,Default,,0,0,0,,这里是“破碎的心”吗 Dialogue: 0,0:36:23.88,0:36:24.84,Default,,0,0,0,,如果那里是破碎的心 Dialogue: 0,0:36:24.84,0:36:26.11,Default,,0,0,0,,就说明那里的东西复制过了 Dialogue: 0,0:36:26.20,0:36:27.34,Default,,0,0,0,,只需要用破碎的心所指向的地址 Dialogue: 0,0:36:27.36,0:36:28.75,Default,,0,0,0,,来替换它指针即可 Dialogue: 0,0:36:29.82,0:36:32.03,Default,,0,0,0,,如果它还没被复制 Dialogue: 0,0:36:32.12,0:36:34.08,Default,,0,0,0,,你把它复制到这里 Dialogue: 0,0:36:34.43,0:36:35.95,Default,,0,0,0,,把FREE指针移到这里 Dialogue: 0,0:36:37.05,0:36:40.60,Default,,0,0,0,,然后在那里放置一颗破碎的心 Dialogue: 0,0:36:41.05,0:36:41.80,Default,,0,0,0,,继续扫描 Dialogue: 0,0:36:43.67,0:36:46.40,Default,,0,0,0,,最终SCAN指针追上了FREE指针 Dialogue: 0,0:36:46.82,0:36:48.52,Default,,0,0,0,,内存里的所有东西都被复制了 Dialogue: 0,0:36:50.14,0:36:51.04,Default,,0,0,0,,这样这里就剩下了 Dialogue: 0,0:36:51.05,0:36:51.95,Default,,0,0,0,,大量的空闲空间 Dialogue: 0,0:36:51.96,0:36:53.28,Default,,0,0,0,,如果你需要的话 Dialogue: 0,0:36:53.31,0:36:54.47,Default,,0,0,0,,你可以把它组织为空闲表 Dialogue: 0,0:36:54.47,0:36:56.27,Default,,0,0,0,,但这种系统通常不这么来做 Dialogue: 0,0:36:56.27,0:36:59.15,Default,,0,0,0,,这类系统中 内存是顺序分配的 Dialogue: 0,0:37:00.91,0:37:02.48,Default,,0,0,0,,这是个非常 非常好的算法 Dialogue: 0,0:37:02.97,0:37:04.57,Default,,0,0,0,,你们现在使用的Scheme系统中 Dialogue: 0,0:37:04.67,0:37:05.97,Default,,0,0,0,,就使用了这种算法 Dialogue: 0,0:37:06.79,0:37:09.47,Default,,0,0,0,,它应该是-- Dialogue: 0,0:37:09.47,0:37:10.86,Default,,0,0,0,,我相信还没有人发现 Dialogue: 0,0:37:10.89,0:37:12.12,Default,,0,0,0,,比它跑得更快的算法 Dialogue: 0,0:37:12.40,0:37:14.85,Default,,0,0,0,,有一些对这个算法的简单修改 Dialogue: 0,0:37:14.85,0:37:16.77,Default,,0,0,0,,由Henry Baker发明 Dialogue: 0,0:37:17.17,0:37:20.31,Default,,0,0,0,,它让你能实时运行这个算法 Dialogue: 0,0:37:20.31,0:37:21.92,Default,,0,0,0,,也就是说进行回收时不需要暂停程序 Dialogue: 0,0:37:22.14,0:37:24.33,Default,,0,0,0,,你能够让机器运行时 Dialogue: 0,0:37:24.36,0:37:26.17,Default,,0,0,0,,进行的各种CONS操作 Dialogue: 0,0:37:26.32,0:37:28.40,Default,,0,0,0,,与垃圾回收过程交错进行 Dialogue: 0,0:37:28.85,0:37:31.20,Default,,0,0,0,,垃圾回收器是分散的 Dialogue: 0,0:37:31.20,0:37:32.19,Default,,0,0,0,,机器不需要停下来 Dialogue: 0,0:37:32.41,0:37:33.47,Default,,0,0,0,,再让垃圾回收开始运作 Dialogue: 0,0:37:34.64,0:37:37.87,Default,,0,0,0,,当然 在使用虚拟内存的机器中 Dialogue: 0,0:37:38.90,0:37:41.20,Default,,0,0,0,,有很多内存无法访问 Dialogue: 0,0:37:41.50,0:37:43.60,Default,,0,0,0,,这会让整个过程变得耗时 Dialogue: 0,0:37:44.28,0:37:46.43,Default,,0,0,0,,有很多人尝试 Dialogue: 0,0:37:47.16,0:37:48.65,Default,,0,0,0,,将它改进得更好 Dialogue: 0,0:37:49.19,0:37:51.15,Default,,0,0,0,,对于感兴趣的同学 Dialogue: 0,0:37:51.16,0:37:52.41,Default,,0,0,0,,这有一篇论文 Dialogue: 0,0:37:52.64,0:37:54.27,Default,,0,0,0,,作者是Moon等人 Dialogue: 0,0:37:54.65,0:37:56.89,Default,,0,0,0,,这篇论文描述了 Dialogue: 0,0:37:56.92,0:37:59.44,Default,,0,0,0,,增量式Minsky-Fenichel-Yochelson算法 Dialogue: 0,0:37:59.51,0:38:01.20,Default,,0,0,0,,和Baker算法的修改 Dialogue: 0,0:38:01.42,0:38:06.54,Default,,0,0,0,,让使用虚拟内存的系统更加高效 Dialogue: 0,0:38:08.27,0:38:12.32,Default,,0,0,0,,现在最后一个谜团也解开了 Dialogue: 0,0:38:12.84,0:38:14.09,Default,,0,0,0,,有什么疑惑吗? Dialogue: 0,0:38:19.78,0:38:19.95,Default,,0,0,0,,请讲 Dialogue: 0,0:38:20.60,0:38:23.58,Default,,0,0,0,,学生:我在楼上的系统上 Dialogue: 0,0:38:23.64,0:38:25.05,Default,,0,0,0,,你们运行垃圾收集器的时候 Dialogue: 0,0:38:25.93,0:38:27.88,Default,,0,0,0,,它看起来跑得飞快 Dialogue: 0,0:38:27.96,0:38:28.40,Default,,0,0,0,,教授:是的 Dialogue: 0,0:38:28.49,0:38:29.52,Default,,0,0,0,,学生:整个过程花费了-- Dialogue: 0,0:38:30.11,0:38:31.88,Default,,0,0,0,,它真的扫描了整个内存吗? Dialogue: 0,0:38:31.88,0:38:32.22,Default,,0,0,0,,教授:没有 Dialogue: 0,0:38:32.25,0:38:34.11,Default,,0,0,0,,它只扫描了那些需要的 Dialogue: 0,0:38:34.33,0:38:35.63,Default,,0,0,0,,去复制那些有用的数据结构 Dialogue: 0,0:38:37.32,0:38:38.36,Default,,0,0,0,,它是个复制收集器 Dialogue: 0,0:38:38.44,0:38:38.91,Default,,0,0,0,,学生:好吧 Dialogue: 0,0:38:39.30,0:38:40.88,Default,,0,0,0,,教授:但它确实很快 Dialogue: 0,0:38:41.85,0:38:45.88,Default,,0,0,0,,整体来说 我想如果要复制 Dialogue: 0,0:38:47.12,0:38:51.56,Default,,0,0,0,,一个大约3MB的东西 Dialogue: 0,0:38:52.43,0:38:53.24,Default,,0,0,0,,将在一秒内完成 Dialogue: 0,0:38:55.00,0:38:55.69,Default,,0,0,0,,而且是实时的 Dialogue: 0,0:38:56.54,0:38:58.46,Default,,0,0,0,,它们是非常小的程序 Dialogue: 0,0:38:58.62,0:39:01.50,Default,,0,0,0,,你需要注意到的一件事是 Dialogue: 0,0:39:02.91,0:39:04.40,Default,,0,0,0,,垃圾收集器必须要小 Dialogue: 0,0:39:05.40,0:39:07.10,Default,,0,0,0,,不是因为它们需要运行得快 Dialogue: 0,0:39:07.90,0:39:09.23,Default,,0,0,0,,因为没有人能够调试 Dialogue: 0,0:39:09.26,0:39:10.48,Default,,0,0,0,,复杂的垃圾收集器 Dialogue: 0,0:39:11.34,0:39:12.91,Default,,0,0,0,,如果一个垃圾收集器不能正常工作 Dialogue: 0,0:39:14.04,0:39:15.93,Default,,0,0,0,,它会把你的内存搞得一团糟 Dialogue: 0,0:39:15.93,0:39:17.39,Default,,0,0,0,,而你却束手无策 Dialogue: 0,0:39:18.35,0:39:19.67,Default,,0,0,0,,你需要跟踪审计 Dialogue: 0,0:39:20.66,0:39:22.01,Default,,0,0,0,,因为它把所有东西都换了位置 Dialogue: 0,0:39:22.04,0:39:23.24,Default,,0,0,0,,你需要知道那里发生了什么 Dialogue: 0,0:39:23.74,0:39:26.58,Default,,0,0,0,,所以这是唯一一种 Dialogue: 0,0:39:26.92,0:39:28.40,Default,,0,0,0,,真正非常重要的程序 Dialogue: 0,0:39:28.54,0:39:29.79,Default,,0,0,0,,如果你盯着它看足够久 Dialogue: 0,0:39:29.82,0:39:31.07,Default,,0,0,0,,那么你就相信它有效 Dialogue: 0,0:39:31.34,0:39:33.36,Default,,0,0,0,,这意味着某种“自我证明” Dialogue: 0,0:39:33.92,0:39:36.11,Default,,0,0,0,,因此我们无法对它进行查错 Dialogue: 0,0:39:36.94,0:39:38.96,Default,,0,0,0,,这意味着它需要足够小 Dialogue: 0,0:39:38.96,0:39:39.97,Default,,0,0,0,,你的大脑能够思考它的工作情况 Dialogue: 0,0:39:41.45,0:39:43.90,Default,,0,0,0,,正因如此 垃圾收集器十分特殊 Dialogue: 0,0:39:45.02,0:39:47.12,Default,,0,0,0,,所以实用的垃圾收集器一定要短小 Dialogue: 0,0:39:47.13,0:39:48.45,Default,,0,0,0,,而通常短小的程序运行得就快 Dialogue: 0,0:39:52.05,0:39:52.43,Default,,0,0,0,,请讲 Dialogue: 0,0:39:52.43,0:39:54.51,Default,,0,0,0,,学生:您能再重复一遍这个技术的名字吗? Dialogue: 0,0:39:54.68,0:39:56.92,Default,,0,0,0,,教授:Minsky-Fenichel-Yochelson垃圾回收器 Dialogue: 0,0:39:57.88,0:39:58.43,Default,,0,0,0,,学生:什么? Dialogue: 0,0:39:59.00,0:40:00.78,Default,,0,0,0,,教授:Minsky在1961年 Dialogue: 0,0:40:00.81,0:40:02.21,Default,,0,0,0,,为RLE PDP-1设计了这个算法 Dialogue: 0,0:40:02.21,0:40:06.17,Default,,0,0,0,,Fenichel和Yochelson改进并精化了算法 Dialogue: 0,0:40:06.45,0:40:10.27,Default,,0,0,0,,将它用在了Multics平台的MacLisp中 Dialogue: 0,0:40:11.37,0:40:14.75,Default,,0,0,0,,那时大约是1968或者1969年 Dialogue: 0,0:40:19.57,0:40:21.36,Default,,0,0,0,,好吧 我们休息一下 Dialogue: 0,0:40:22.64,0:40:32.36,Default,,0,0,0,,[音乐] Dialogue: 0,0:40:32.41,0:40:36.19,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:41:03.15,0:41:07.18,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:41:07.20,0:41:10.17,Declare,,0,0,0,,{\an2\fad(500,500)\pos(320,470)}《计算机程序的构造和解释》 Dialogue: 0,0:41:10.20,0:41:14.22,Declare,,0,0,0,,{\an2\fad(500,500)}计算的极限 Dialogue: 0,0:41:17.31,0:41:19.67,Default,,0,0,0,,教授:我们已经到课程的最后一部分了 Dialogue: 0,0:41:20.08,0:41:23.85,Default,,0,0,0,,我已经给你们展示了一台通用机器 Dialogue: 0,0:41:24.47,0:41:26.74,Default,,0,0,0,,它被简化为求值器 Dialogue: 0,0:41:27.02,0:41:28.38,Default,,0,0,0,,它被简化到 Dialogue: 0,0:41:28.38,0:41:29.67,Default,,0,0,0,,你自己也能构造出来 Dialogue: 0,0:41:30.19,0:41:33.32,Default,,0,0,0,,这是一个特定的Lisp实现 Dialogue: 0,0:41:33.90,0:41:36.01,Default,,0,0,0,,它是用 Dialogue: 0,0:41:36.16,0:41:38.05,Default,,0,0,0,,昨天讲过的Scheme芯片制作的 Dialogue: 0,0:41:38.20,0:41:38.91,Default,,0,0,0,,就是这个 Dialogue: 0,0:41:39.35,0:41:42.00,Default,,0,0,0,,这基本上就是暴露给他人内存的接口了 Dialogue: 0,0:41:42.60,0:41:44.75,Default,,0,0,0,,里面有节拍发生器等组件 Dialogue: 0,0:41:45.22,0:41:47.25,Default,,0,0,0,,尽管是解释执行 Dialogue: 0,0:41:47.77,0:41:50.17,Default,,0,0,0,,但它们运行Lisp的速度还算不错 Dialogue: 0,0:41:50.61,0:41:53.82,Default,,0,0,0,,它跑得像1979年的 Dialogue: 0,0:41:54.22,0:41:55.65,Default,,0,0,0,,DEC PDP-10一样快 Dialogue: 0,0:41:56.50,0:41:59.67,Default,,0,0,0,,作为一个十足的硬件 Dialogue: 0,0:42:00.02,0:42:00.89,Default,,0,0,0,,算是十分“实在”了 Dialogue: 0,0:42:02.47,0:42:04.70,Default,,0,0,0,,我们为你们讲解了一些 Dialogue: 0,0:42:04.72,0:42:06.07,Default,,0,0,0,,可以被计算的东西 Dialogue: 0,0:42:07.37,0:42:08.76,Default,,0,0,0,,但我们是否可能遇到 Dialogue: 0,0:42:09.32,0:42:10.55,Default,,0,0,0,,我们无法计算的情况? Dialogue: 0,0:42:11.85,0:42:13.50,Default,,0,0,0,,课程的最后 Dialogue: 0,0:42:13.75,0:42:15.87,Default,,0,0,0,,我想展示一些你认为可以被计算 Dialogue: 0,0:42:16.60,0:42:17.22,Default,,0,0,0,,但实际上不能的东西 Dialogue: 0,0:42:18.19,0:42:19.45,Default,,0,0,0,,实际上 Dialogue: 0,0:42:19.45,0:42:20.82,Default,,0,0,0,,确实有我们无法计算的东西 Dialogue: 0,0:42:22.72,0:42:23.47,Default,,0,0,0,,例如 Dialogue: 0,0:42:24.45,0:42:25.82,Default,,0,0,0,,我们想要这样的一种东西 Dialogue: 0,0:42:27.80,0:42:29.36,Default,,0,0,0,,当我们在编写编译器时 Dialogue: 0,0:42:29.77,0:42:31.42,Default,,0,0,0,,你想用一个程序检查 Dialogue: 0,0:42:32.00,0:42:33.97,Default,,0,0,0,,你的代码能否正常运行 Dialogue: 0,0:42:34.63,0:42:35.40,Default,,0,0,0,,这不是很棒吗? Dialogue: 0,0:42:36.08,0:42:37.87,Default,,0,0,0,,你希望能够捕获死循环 Dialogue: 0,0:42:37.87,0:42:38.54,Default,,0,0,0,,例如 Dialogue: 0,0:42:39.45,0:42:42.42,Default,,0,0,0,,用户编写的程序里的死循环 Dialogue: 0,0:42:43.19,0:42:45.12,Default,,0,0,0,,但通常来说 你写不出这样的程序 Dialogue: 0,0:42:45.35,0:42:46.49,Default,,0,0,0,,它读取某个程序 Dialogue: 0,0:42:46.51,0:42:47.45,Default,,0,0,0,,并检测它 Dialogue: 0,0:42:48.35,0:42:49.30,Default,,0,0,0,,是不是死循环 Dialogue: 0,0:42:50.99,0:42:51.71,Default,,0,0,0,,我来展示一下 Dialogue: 0,0:42:51.76,0:42:53.80,Default,,0,0,0,,这个需要涉及到数学知识 Dialogue: 0,0:42:58.78,0:42:59.65,Default,,0,0,0,,设想 Dialogue: 0,0:43:00.05,0:43:01.78,Default,,0,0,0,,在我们开始之前 Dialogue: 0,0:43:01.78,0:43:02.62,Default,,0,0,0,,有一个数学函数 Dialogue: 0,0:43:02.62,0:43:03.42,Default,,0,0,0,,这里就有一个 Dialogue: 0,0:43:03.84,0:43:04.67,Default,,0,0,0,,记作S Dialogue: 0,0:43:05.47,0:43:07.54,Default,,0,0,0,,它接受一个过程 Dialogue: 0,0:43:12.64,0:43:14.23,Default,,0,0,0,,和它的参数A Dialogue: 0,0:43:19.17,0:43:20.52,Default,,0,0,0,,S所做的是 Dialogue: 0,0:43:21.65,0:43:24.01,Default,,0,0,0,,检测以A为参数运行P时 Dialogue: 0,0:43:24.01,0:43:25.97,Default,,0,0,0,,是否安全 Dialogue: 0,0:43:26.90,0:43:28.17,Default,,0,0,0,,换句话说就是 Dialogue: 0,0:43:28.76,0:43:35.12,Default,,0,0,0,,如果(P A) Dialogue: 0,0:43:35.62,0:43:36.74,Default,,0,0,0,,在没有出错的情况下 Dialogue: 0,0:43:41.40,0:43:42.45,Default,,0,0,0,,能够返回一个值 Dialogue: 0,0:43:44.35,0:43:45.33,Default,,0,0,0,,那么S就为TRUE Dialogue: 0,0:43:52.70,0:43:53.68,Default,,0,0,0,,但如果(P A) Dialogue: 0,0:43:56.10,0:43:57.04,Default,,0,0,0,,是死循环 Dialogue: 0,0:43:59.67,0:44:00.76,Default,,0,0,0,,或者抛出错误 Dialogue: 0,0:44:05.87,0:44:06.95,Default,,0,0,0,,那么S就为FALSE Dialogue: 0,0:44:15.23,0:44:17.22,Default,,0,0,0,,这确实是个函数 Dialogue: 0,0:44:18.78,0:44:20.72,Default,,0,0,0,,对于你输入的任何过程 Dialogue: 0,0:44:21.20,0:44:22.85,Default,,0,0,0,,或者任何参数 Dialogue: 0,0:44:23.92,0:44:25.45,Default,,0,0,0,,它只能返回TRUE或FALSE Dialogue: 0,0:44:25.92,0:44:27.85,Default,,0,0,0,,它会返回一个值而且不会报错 Dialogue: 0,0:44:28.44,0:44:30.15,Default,,0,0,0,,你可以为它们画一张巨大的表格 Dialogue: 0,0:44:32.22,0:44:32.92,Default,,0,0,0,,但问题是 Dialogue: 0,0:44:32.92,0:44:34.09,Default,,0,0,0,,你能写一个过程 Dialogue: 0,0:44:34.09,0:44:35.92,Default,,0,0,0,,来计算这个函数的值吗? Dialogue: 0,0:44:37.43,0:44:38.92,Default,,0,0,0,,假设我们能做到 Dialogue: 0,0:44:39.72,0:44:40.55,Default,,0,0,0,,假设 Dialogue: 0,0:44:44.33,0:44:45.58,Default,,0,0,0,,我们有个过程 Dialogue: 0,0:44:48.55,0:44:52.73,Default,,0,0,0,,一个叫作SAFE?的过程 Dialogue: 0,0:44:56.54,0:44:59.90,Default,,0,0,0,,它能计算S的值 Dialogue: 0,0:45:12.65,0:45:14.89,Default,,0,0,0,,现在我要用几种方法 Dialogue: 0,0:45:15.90,0:45:18.51,Default,,0,0,0,,证明你做不到 Dialogue: 0,0:45:19.76,0:45:20.62,Default,,0,0,0,,最简单的一个 Dialogue: 0,0:45:20.62,0:45:21.28,Default,,0,0,0,,或者说第一个 Dialogue: 0,0:45:21.31,0:45:23.45,Default,,0,0,0,,我们定义一个叫DIAG1的过程 Dialogue: 0,0:45:23.76,0:45:24.86,Default,,0,0,0,,给定了SAFE?过程 Dialogue: 0,0:45:25.20,0:45:26.99,Default,,0,0,0,,我们可以把DIAG1定义为 Dialogue: 0,0:45:34.42,0:45:35.55,Default,,0,0,0,,把DIAG1定义为 Dialogue: 0,0:45:37.82,0:45:41.60,Default,,0,0,0,,只含有参数P的过程 Dialogue: 0,0:45:42.45,0:45:44.05,Default,,0,0,0,,它有着这样的属性 Dialogue: 0,0:45:44.78,0:45:50.67,Default,,0,0,0,,如果(SAFE? P P)为真 Dialogue: 0,0:45:53.32,0:45:55.32,Default,,0,0,0,,那么我就主动陷入死循环 Dialogue: 0,0:45:59.22,0:46:00.92,Default,,0,0,0,,否则我会返回3 Dialogue: 0,0:46:03.68,0:46:04.47,Default,,0,0,0,,它也可能是42 Dialogue: 0,0:46:04.47,0:46:06.42,Default,,0,0,0,,宇宙的终极答案是什么? Dialogue: 0,0:46:07.06,0:46:08.87,Default,,0,0,0,,我们当然知道死循环是什么 Dialogue: 0,0:46:12.05,0:46:12.96,Default,,0,0,0,,死循环INF是 Dialogue: 0,0:46:13.82,0:46:16.02,Default,,0,0,0,,一个无参过程 Dialogue: 0,0:46:16.02,0:46:18.07,Default,,0,0,0,,这是一个极好的LAMBADA演算循环 Dialogue: 0,0:46:18.35,0:46:20.44,Default,,0,0,0,,(LAMBDA (X) (X X)) Dialogue: 0,0:46:21.30,0:46:24.68,Default,,0,0,0,,应用到(LAMBDA (X) (X X)) Dialogue: 0,0:46:24.68,0:46:26.55,Default,,0,0,0,,没什么想象的余地了 Dialogue: 0,0:46:29.83,0:46:31.17,Default,,0,0,0,,我们来看下会发生什么 Dialogue: 0,0:46:32.50,0:46:33.90,Default,,0,0,0,,我假设 Dialogue: 0,0:46:35.45,0:46:38.77,Default,,0,0,0,,我们考虑 Dialogue: 0,0:46:39.00,0:46:43.45,Default,,0,0,0,,把DIAG1应用到DIAG1上 Dialogue: 0,0:46:46.27,0:46:47.77,Default,,0,0,0,,那会发生什么呢? Dialogue: 0,0:46:49.97,0:46:51.39,Default,,0,0,0,,我不知道 Dialogue: 0,0:46:51.39,0:46:53.21,Default,,0,0,0,,将DIAG1代换为 Dialogue: 0,0:46:53.55,0:46:55.50,Default,,0,0,0,,P的过程体 Dialogue: 0,0:46:57.31,0:47:00.22,Default,,0,0,0,,(SAFE? DIAG1 DIAG1)会返回什么呢? Dialogue: 0,0:47:00.22,0:47:00.78,Default,,0,0,0,,我不知道 Dialogue: 0,0:47:00.78,0:47:01.82,Default,,0,0,0,,有两种可能 Dialogue: 0,0:47:03.40,0:47:05.50,Default,,0,0,0,,如果计算(DIAG1 DIAG1)是安全的 Dialogue: 0,0:47:05.92,0:47:06.89,Default,,0,0,0,,这意味着没有死循环 Dialogue: 0,0:47:08.49,0:47:09.22,Default,,0,0,0,,那么我就要来到这里 Dialogue: 0,0:47:09.22,0:47:10.35,Default,,0,0,0,,但是随即我就陷入了死循环 Dialogue: 0,0:47:10.56,0:47:11.57,Default,,0,0,0,,所以它不是安全的 Dialogue: 0,0:47:12.21,0:47:14.78,Default,,0,0,0,,但如果计算(DIAG1 DIAG1)不安全 Dialogue: 0,0:47:14.90,0:47:16.02,Default,,0,0,0,,那么它的结果是3 Dialogue: 0,0:47:16.02,0:47:17.26,Default,,0,0,0,,但是调用(DIAG1 DIAG1)又必须能够返回 Dialogue: 0,0:47:17.26,0:47:17.93,Default,,0,0,0,,所以它必须安全才行 Dialogue: 0,0:47:20.53,0:47:23.60,Default,,0,0,0,,因此 通过归纳出这个矛盾 Dialogue: 0,0:47:24.32,0:47:26.30,Default,,0,0,0,,我们无法写出这个SAFE?过程 Dialogue: 0,0:47:27.40,0:47:29.80,Default,,0,0,0,,如果大家没有听明白这种表述 Dialogue: 0,0:47:30.25,0:47:32.15,Default,,0,0,0,,我换个方式再讲一遍 Dialogue: 0,0:47:32.82,0:47:34.00,Default,,0,0,0,,请听另一个版本 Dialogue: 0,0:47:35.53,0:47:36.95,Default,,0,0,0,,我们定义DIAG2 Dialogue: 0,0:47:39.84,0:47:41.60,Default,,0,0,0,,取名叫DIAG是因为 Dialogue: 0,0:47:42.65,0:47:44.72,Default,,0,0,0,,它来源于康托尔的对角论证法 Dialogue: 0,0:47:45.00,0:47:47.05,Default,,0,0,0,,这些事例最初都来自于 Dialogue: 0,0:47:47.05,0:47:49.05,Default,,0,0,0,,一个著名的论证 Dialogue: 0,0:47:49.45,0:47:52.65,Default,,0,0,0,,也就是康托尔在19世纪末 Dialogue: 0,0:47:52.77,0:47:56.10,Default,,0,0,0,,证明了实数是不可数的 Dialogue: 0,0:47:56.67,0:47:58.00,Default,,0,0,0,,整数与实数 Dialogue: 0,0:47:58.06,0:47:59.42,Default,,0,0,0,,无法形成一一映射 Dialogue: 0,0:48:00.19,0:48:01.74,Default,,0,0,0,,数轴上的点 Dialogue: 0,0:48:01.74,0:48:02.50,Default,,0,0,0,,举例来说 Dialogue: 0,0:48:02.50,0:48:04.42,Default,,0,0,0,,比数轴上的刻度还要多 Dialogue: 0,0:48:05.26,0:48:06.85,Default,,0,0,0,,这或许不是个显而易见的结论 Dialogue: 0,0:48:06.85,0:48:08.17,Default,,0,0,0,,但我不想深入讨论这个 Dialogue: 0,0:48:10.90,0:48:12.45,Default,,0,0,0,,但是DIAG2 Dialogue: 0,0:48:13.30,0:48:15.82,Default,,0,0,0,,也是一个参数为P的单参过程 Dialogue: 0,0:48:15.82,0:48:17.47,Default,,0,0,0,,这几乎与之前的例子相同 Dialogue: 0,0:48:17.72,0:48:24.32,Default,,0,0,0,,如果计算(P P)是安全的 Dialogue: 0,0:48:25.17,0:48:26.67,Default,,0,0,0,,那么我就要 Dialogue: 0,0:48:27.26,0:48:28.14,Default,,0,0,0,,哦 漏了一个IF Dialogue: 0,0:48:29.31,0:48:31.02,Default,,0,0,0,,那么我就去计算 Dialogue: 0,0:48:31.57,0:48:37.58,Default,,0,0,0,,一些(P P)之外的东西 Dialogue: 0,0:48:38.96,0:48:40.21,Default,,0,0,0,,否则我就返回FALSE Dialogue: 0,0:48:43.60,0:48:45.30,Default,,0,0,0,,这里的OTHER-THAN意思是 Dialogue: 0,0:48:45.47,0:48:46.35,Default,,0,0,0,,不管这个(P P)是什么 Dialogue: 0,0:48:46.35,0:48:47.47,Default,,0,0,0,,我都返回一些别的东西 Dialogue: 0,0:48:48.88,0:48:50.03,Default,,0,0,0,,我来给出一个 Dialogue: 0,0:48:50.07,0:48:51.52,Default,,0,0,0,,OTHER-THAN的一个定义 Dialogue: 0,0:48:51.60,0:48:52.57,Default,,0,0,0,,我觉得它是可用的 Dialogue: 0,0:48:53.89,0:48:54.51,Default,,0,0,0,,来看看 Dialogue: 0,0:48:55.64,0:48:56.08,Default,,0,0,0,,好 Dialogue: 0,0:48:56.33,0:48:57.26,Default,,0,0,0,,定义OTHER-THAN Dialogue: 0,0:49:04.03,0:49:06.11,Default,,0,0,0,,参数为X的单参过程 Dialogue: 0,0:49:06.57,0:49:07.26,Default,,0,0,0,,过程体是 Dialogue: 0,0:49:08.05,0:49:12.96,Default,,0,0,0,,如果(EQ? X 'A) Dialogue: 0,0:49:13.47,0:49:15.07,Default,,0,0,0,,那么结果是'B Dialogue: 0,0:49:15.72,0:49:16.80,Default,,0,0,0,,否则结果是'A Dialogue: 0,0:49:20.27,0:49:21.90,Default,,0,0,0,,这样无论参数是什么 Dialogue: 0,0:49:22.07,0:49:23.45,Default,,0,0,0,,返回值跟参数总是不相同的 Dialogue: 0,0:49:25.20,0:49:26.12,Default,,0,0,0,,就是这样了 Dialogue: 0,0:49:26.54,0:49:27.37,Default,,0,0,0,,这就是我要的 Dialogue: 0,0:49:28.25,0:49:29.58,Default,,0,0,0,,我们考虑一下这个 Dialogue: 0,0:49:29.58,0:49:31.15,Default,,0,0,0,,(DIAG2 DIAG2) Dialogue: 0,0:49:38.28,0:49:38.94,Default,,0,0,0,,看 Dialogue: 0,0:49:39.95,0:49:41.72,Default,,0,0,0,,这个东西会做些危险的事情 Dialogue: 0,0:49:42.00,0:49:43.45,Default,,0,0,0,,比如求值(P P) Dialogue: 0,0:49:44.75,0:49:45.95,Default,,0,0,0,,如果它是安全的 Dialogue: 0,0:49:47.47,0:49:49.16,Default,,0,0,0,,如果SAFE?能够被定义的话 Dialogue: 0,0:49:50.30,0:49:52.49,Default,,0,0,0,,如果你能定义SAFE?过程 Dialogue: 0,0:49:52.97,0:49:54.32,Default,,0,0,0,,那么这个过程 Dialogue: 0,0:49:54.60,0:49:56.40,Default,,0,0,0,,也就顺理成章地是安全的 Dialogue: 0,0:49:56.52,0:49:57.22,Default,,0,0,0,,对于任意输入来说都是 Dialogue: 0,0:50:01.54,0:50:03.50,Default,,0,0,0,,那么(DIAG2 DIAG2) Dialogue: 0,0:50:03.87,0:50:12.20,Default,,0,0,0,,就会返回(OTHER-THAN (DIAG2 DIAG2)) Dialogue: 0,0:50:15.82,0:50:16.97,Default,,0,0,0,,这说不通 Dialogue: 0,0:50:17.80,0:50:19.02,Default,,0,0,0,,又产生了悖论 Dialogue: 0,0:50:19.85,0:50:21.57,Default,,0,0,0,,因此我们不能定义SAFE? Dialogue: 0,0:50:22.95,0:50:24.23,Default,,0,0,0,,我只想这样证明两次 Dialogue: 0,0:50:24.78,0:50:25.82,Default,,0,0,0,,有些许不同 Dialogue: 0,0:50:26.84,0:50:27.90,Default,,0,0,0,,你不会感到 Dialogue: 0,0:50:29.07,0:50:30.86,Default,,0,0,0,,第一个证明是个把戏 Dialogue: 0,0:50:32.54,0:50:33.45,Default,,0,0,0,,它们可能都是把戏 Dialogue: 0,0:50:33.80,0:50:35.15,Default,,0,0,0,,但它们稍微有些不同 Dialogue: 0,0:50:37.30,0:50:39.20,Default,,0,0,0,,因此 我想这就基本上讲清楚了 Dialogue: 0,0:50:40.03,0:50:41.97,Default,,0,0,0,,我们刚刚证明了所谓的“停机问题” Dialogue: 0,0:50:43.00,0:50:44.70,Default,,0,0,0,,我想 本课程也即将画上句号 Dialogue: 0,0:50:46.72,0:50:47.63,Default,,0,0,0,,希望你们有所收获 Dialogue: 0,0:50:50.90,0:50:51.76,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:50:53.30,0:50:53.56,Default,,0,0,0,,请讲 Dialogue: 0,0:50:53.81,0:50:56.27,Default,,0,0,0,,学生: (S DIAG1)的值是什么? Dialogue: 0,0:50:56.75,0:50:57.23,Default,,0,0,0,,教授: 什么的值? Dialogue: 0,0:50:57.50,0:50:58.80,Default,,0,0,0,,学生: (S DIAG1)的值 Dialogue: 0,0:51:00.12,0:51:02.20,Default,,0,0,0,,如果你说S是个函数 我们就可以-- Dialogue: 0,0:51:02.30,0:51:03.63,Default,,0,0,0,,教授: 噢 我不知道啊 Dialogue: 0,0:51:03.87,0:51:04.35,Default,,0,0,0,,我不知道 Dialogue: 0,0:51:04.35,0:51:04.88,Default,,0,0,0,,它是一个函数 Dialogue: 0,0:51:04.88,0:51:05.85,Default,,0,0,0,,但我不知道如何计算它 Dialogue: 0,0:51:06.80,0:51:08.00,Default,,0,0,0,,我做不到 Dialogue: 0,0:51:08.61,0:51:09.64,Default,,0,0,0,,我也只是个机器 Dialogue: 0,0:51:11.53,0:51:11.88,Default,,0,0,0,,对吧? Dialogue: 0,0:51:11.90,0:51:13.37,Default,,0,0,0,,原则上来说 Dialogue: 0,0:51:13.37,0:51:14.05,Default,,0,0,0,,没有机器 Dialogue: 0,0:51:14.47,0:51:16.87,Default,,0,0,0,,当然 也有可能会处在你刚才问的那个情况中 Dialogue: 0,0:51:16.87,0:51:18.32,Default,,0,0,0,,花点时间还是可以计算出来 Dialogue: 0,0:51:18.58,0:51:19.37,Default,,0,0,0,,但通常情况下 Dialogue: 0,0:51:19.60,0:51:21.05,Default,,0,0,0,,我无法计算S的值 Dialogue: 0,0:51:21.05,0:51:22.52,Default,,0,0,0,,别的机器也做不到 Dialogue: 0,0:51:23.78,0:51:24.92,Default,,0,0,0,,存在这样一个函数 Dialogue: 0,0:51:25.92,0:51:28.00,Default,,0,0,0,,没有任何机器能够计算它 Dialogue: 0,0:51:29.58,0:51:30.05,Default,,0,0,0,,现在 Dialogue: 0,0:51:30.67,0:51:33.67,Default,,0,0,0,,我这么来说也不会让你们吃惊 Dialogue: 0,0:51:35.22,0:51:36.25,Default,,0,0,0,,来想一想 Dialogue: 0,0:51:36.25,0:51:38.36,Default,,0,0,0,,现在我没有时间给你们展示 Dialogue: 0,0:51:38.45,0:51:43.00,Default,,0,0,0,,但这样的函数非常多 Dialogue: 0,0:51:44.40,0:51:47.58,Default,,0,0,0,,如果有一定量的可能输入 Dialogue: 0,0:51:47.75,0:51:49.62,Default,,0,0,0,,和一定量可能的结果 Dialogue: 0,0:51:49.87,0:51:51.80,Default,,0,0,0,,那么结果数量的输入数量次幂 Dialogue: 0,0:51:51.80,0:51:53.20,Default,,0,0,0,,就是可能的函数的数量 Dialogue: 0,0:51:54.50,0:51:55.48,Default,,0,0,0,,这还是单参的函数 Dialogue: 0,0:51:56.51,0:51:59.24,Default,,0,0,0,,而多参函数的个数 Dialogue: 0,0:52:00.09,0:52:03.21,Default,,0,0,0,,又比这个幂次方 Dialogue: 0,0:52:03.58,0:52:04.32,Default,,0,0,0,,这个指数还要大 Dialogue: 0,0:52:05.48,0:52:09.80,Default,,0,0,0,,函数的数量 Dialogue: 0,0:52:09.95,0:52:12.72,Default,,0,0,0,,比一个人能写出的 Dialogue: 0,0:52:13.30,0:52:14.10,Default,,0,0,0,,程序的数量更多 Dialogue: 0,0:52:14.82,0:52:16.45,Default,,0,0,0,,因为有无穷多的参数 Dialogue: 0,0:52:17.57,0:52:19.00,Default,,0,0,0,,可能会更多 Dialogue: 0,0:52:19.47,0:52:22.12,Default,,0,0,0,,所以不可计算的函数数量 Dialogue: 0,0:52:22.12,0:52:23.48,Default,,0,0,0,,一定会非常多 Dialogue: 0,0:52:25.92,0:52:26.59,Default,,0,0,0,,学生:不久前 Dialogue: 0,0:52:26.64,0:52:28.25,Default,,0,0,0,,你讲了规范 Dialogue: 0,0:52:28.30,0:52:30.04,Default,,0,0,0,,和自动生成解决方案 Dialogue: 0,0:52:30.64,0:52:31.61,Default,,0,0,0,,您觉得通过规范 Dialogue: 0,0:52:31.82,0:52:33.36,Default,,0,0,0,,能够生成解决方案么? Dialogue: 0,0:52:37.25,0:52:38.22,Default,,0,0,0,,教授:“生成” Dialogue: 0,0:52:38.72,0:52:39.37,Default,,0,0,0,,你是说 Dialogue: 0,0:52:39.37,0:52:42.60,Default,,0,0,0,,如何按照规范 Dialogue: 0,0:52:42.60,0:52:44.78,Default,,0,0,0,,构建相应的装置吗? Dialogue: 0,0:52:45.05,0:52:48.36,Default,,0,0,0,,学生:软件工程中有很多 Dialogue: 0,0:52:48.36,0:52:49.90,Default,,0,0,0,,层次化的设计 Dialogue: 0,0:52:49.90,0:52:51.90,Default,,0,0,0,,并进行实现的规范 Dialogue: 0,0:52:52.43,0:52:52.85,Default,,0,0,0,,教授:是的 Dialogue: 0,0:52:52.85,0:52:53.70,Default,,0,0,0,,学生:我很好奇 Dialogue: 0,0:52:53.70,0:52:54.62,Default,,0,0,0,,您觉得这现实吗? Dialogue: 0,0:52:55.60,0:52:57.17,Default,,0,0,0,,教授:我觉得其中一些是现实的 Dialogue: 0,0:52:57.17,0:52:58.10,Default,,0,0,0,,另一些不现实 Dialogue: 0,0:52:58.10,0:53:00.32,Default,,0,0,0,,如果你想制造一个滤波器 Dialogue: 0,0:53:01.17,0:53:07.16,Default,,0,0,0,,我这有个挺有趣的例子 Dialogue: 0,0:53:07.16,0:53:09.42,Default,,0,0,0,,假设我想制造一个东西 Dialogue: 0,0:53:09.64,0:53:14.07,Default,,0,0,0,,把无线电发射器的输出 Dialogue: 0,0:53:14.47,0:53:18.75,Default,,0,0,0,,连接到某条天线上 Dialogue: 0,0:53:19.90,0:53:21.47,Default,,0,0,0,,我先把它引出来 Dialogue: 0,0:53:21.48,0:53:23.04,Default,,0,0,0,,这里是输出管线 Dialogue: 0,0:53:23.23,0:53:25.26,Default,,0,0,0,,问题是它们的阻抗不同 Dialogue: 0,0:53:25.92,0:53:27.55,Default,,0,0,0,,我希望能够匹配阻抗 Dialogue: 0,0:53:27.55,0:53:28.97,Default,,0,0,0,,我也想在其中加入一个滤波器 Dialogue: 0,0:53:29.15,0:53:31.71,Default,,0,0,0,,用来过滤一些谐波辐射 Dialogue: 0,0:53:32.78,0:53:36.63,Default,,0,0,0,,一种老派的技术叫作 Dialogue: 0,0:53:36.82,0:53:38.67,Default,,0,0,0,,“影像阻抗”之类的东西 Dialogue: 0,0:53:38.86,0:53:39.50,Default,,0,0,0,,你要做的是 Dialogue: 0,0:53:39.50,0:53:40.85,Default,,0,0,0,,你有个基础的模块 Dialogue: 0,0:53:40.85,0:53:42.75,Default,,0,0,0,,称为L型滤波器 Dialogue: 0,0:53:43.30,0:53:43.98,Default,,0,0,0,,就像这样 Dialogue: 0,0:53:47.08,0:53:49.80,Default,,0,0,0,,如果把它连接到某些电阻R上 Dialogue: 0,0:53:50.05,0:53:52.60,Default,,0,0,0,,如果我把它的阻抗记作X_L Dialogue: 0,0:53:52.72,0:53:55.20,Default,,0,0,0,,而它的值刚好又等于Q*R Dialogue: 0,0:53:55.26,0:53:58.52,Default,,0,0,0,,这就成了一个低通滤波器 Dialogue: 0,0:53:58.52,0:54:00.72,Default,,0,0,0,,有Q^2+1的等效阻抗 Dialogue: 0,0:54:02.11,0:54:02.86,Default,,0,0,0,,这就是我想要的 Dialogue: 0,0:54:03.12,0:54:04.28,Default,,0,0,0,,因为这样我就可以 Dialogue: 0,0:54:04.30,0:54:05.08,Default,,0,0,0,,把它们匹配到一起了 Dialogue: 0,0:54:05.82,0:54:06.38,Default,,0,0,0,,就像这样 Dialogue: 0,0:54:11.66,0:54:13.15,Default,,0,0,0,,我拿来另一个 Dialogue: 0,0:54:16.00,0:54:17.45,Default,,0,0,0,,想这样把它们连到一起 Dialogue: 0,0:54:18.29,0:54:19.95,Default,,0,0,0,,有两个L型滤波器连接起来 Dialogue: 0,0:54:20.32,0:54:23.07,Default,,0,0,0,,这能让它的阻抗降到我知道的值 Dialogue: 0,0:54:23.37,0:54:25.22,Default,,0,0,0,,让它的阻抗升到我知道的值 Dialogue: 0,0:54:25.53,0:54:26.64,Default,,0,0,0,,这两个低通滤波器 Dialogue: 0,0:54:26.67,0:54:27.82,Default,,0,0,0,,都过滤掉了一些谐波 Dialogue: 0,0:54:28.09,0:54:29.07,Default,,0,0,0,,这是个不错的滤波器 Dialogue: 0,0:54:29.07,0:54:30.27,Default,,0,0,0,,这就是π型滤波器 Dialogue: 0,0:54:30.27,0:54:30.62,Default,,0,0,0,,很好 Dialogue: 0,0:54:31.70,0:54:34.09,Default,,0,0,0,,除了实际上 Dialogue: 0,0:54:34.12,0:54:37.85,Default,,0,0,0,,我在系统里放了些无用的东西 Dialogue: 0,0:54:38.62,0:54:39.60,Default,,0,0,0,,我在本该只用一个的地方 Dialogue: 0,0:54:39.61,0:54:40.59,Default,,0,0,0,,用了两个线圈 Dialogue: 0,0:54:41.62,0:54:44.60,Default,,0,0,0,,在大多数软件工程技艺中 Dialogue: 0,0:54:44.89,0:54:46.88,Default,,0,0,0,,在人工优化和编译之外 Dialogue: 0,0:54:46.92,0:54:48.65,Default,,0,0,0,,不存在一种机制 Dialogue: 0,0:54:48.80,0:54:51.34,Default,,0,0,0,,能在自顶向下的设计中 Dialogue: 0,0:54:51.34,0:54:53.55,Default,,0,0,0,,去掉冗余的部分 Dialogue: 0,0:54:55.35,0:54:56.07,Default,,0,0,0,,或许会更糟 Dialogue: 0,0:54:56.07,0:54:57.58,Default,,0,0,0,,有很多重要的结构 Dialogue: 0,0:54:57.60,0:54:59.02,Default,,0,0,0,,你无法采用这种方式构建 Dialogue: 0,0:55:01.11,0:55:03.53,Default,,0,0,0,,我觉得标准的自上而下的设计方式 Dialogue: 0,0:55:03.53,0:55:04.87,Default,,0,0,0,,是一种很短视的手段 Dialogue: 0,0:55:05.71,0:55:06.60,Default,,0,0,0,,它不会真的抓到 Dialogue: 0,0:55:06.60,0:55:08.10,Default,,0,0,0,,设计者真正想要的结果 Dialogue: 0,0:55:08.31,0:55:10.10,Default,,0,0,0,,我再举一个电子学的例子 Dialogue: 0,0:55:10.10,0:55:11.75,Default,,0,0,0,,电子学的例子 Dialogue: 0,0:55:11.90,0:55:13.13,Default,,0,0,0,,要比计算的例子直观得多 Dialogue: 0,0:55:13.16,0:55:14.78,Default,,0,0,0,,因为计算的例子 Dialogue: 0,0:55:14.80,0:55:16.52,Default,,0,0,0,,解释起来比较复杂 Dialogue: 0,0:55:17.22,0:55:19.16,Default,,0,0,0,,在电子学世界中 Dialogue: 0,0:55:19.16,0:55:20.04,Default,,0,0,0,,我最喜欢的例子之一是 Dialogue: 0,0:55:20.60,0:55:22.80,Default,,0,0,0,,是如何设计中频放大器中 Dialogue: 0,0:55:23.28,0:55:26.55,Default,,0,0,0,,输入级和输出级的连接方式 Dialogue: 0,0:55:27.53,0:55:29.44,Default,,0,0,0,,这是一个三极管 Dialogue: 0,0:55:29.52,0:55:31.50,Default,,0,0,0,,我们来看看 Dialogue: 0,0:55:32.41,0:55:33.40,Default,,0,0,0,,这有个LC震荡电路 Dialogue: 0,0:55:36.45,0:55:39.17,Default,,0,0,0,,我要把它 Dialogue: 0,0:55:41.37,0:55:43.97,Default,,0,0,0,,把它与下一级的输入线圈耦合在一起 Dialogue: 0,0:55:44.36,0:55:47.47,Default,,0,0,0,,这是个完美的可行方案 Dialogue: 0,0:55:48.22,0:55:50.87,Default,,0,0,0,,除了我这个电流方向画错了 Dialogue: 0,0:55:50.87,0:55:52.92,Default,,0,0,0,,电流应该是这个方向 Dialogue: 0,0:55:53.17,0:55:55.45,Default,,0,0,0,,这是个完美的可行方案 Dialogue: 0,0:55:55.98,0:55:56.57,Default,,0,0,0,,不对 Dialogue: 0,0:55:57.12,0:55:57.79,Default,,0,0,0,,我犯蠢了 Dialogue: 0,0:55:58.40,0:55:59.07,Default,,0,0,0,,对不起 Dialogue: 0,0:55:59.69,0:56:00.42,Default,,0,0,0,,这不重要 Dialogue: 0,0:56:00.73,0:56:01.54,Default,,0,0,0,,关键在于这是一个 Dialogue: 0,0:56:01.54,0:56:03.42,Default,,0,0,0,,把两级耦合起来的完美方案 Dialogue: 0,0:56:04.54,0:56:06.92,Default,,0,0,0,,分层来看时会产生什么问题? Dialogue: 0,0:56:07.62,0:56:08.80,Default,,0,0,0,,它就不是同一个东西了 Dialogue: 0,0:56:09.48,0:56:11.99,Default,,0,0,0,,当分层来看时它就没有任何意义了 Dialogue: 0,0:56:11.99,0:56:14.32,Default,,0,0,0,,这是一个调谐电路的电感 Dialogue: 0,0:56:15.55,0:56:18.02,Default,,0,0,0,,这是变压器的初级线圈 Dialogue: 0,0:56:19.10,0:56:21.82,Default,,0,0,0,,这是直流的通路 Dialogue: 0,0:56:21.82,0:56:23.57,Default,,0,0,0,,它是三极管的集电极 Dialogue: 0,0:56:23.57,0:56:25.10,Default,,0,0,0,,的偏置条件 Dialogue: 0,0:56:26.46,0:56:28.35,Default,,0,0,0,,没有任何简单的自顶向下设计 Dialogue: 0,0:56:28.38,0:56:30.17,Default,,0,0,0,,能够得到这样的结构 Dialogue: 0,0:56:30.22,0:56:34.02,Default,,0,0,0,,对于同一个东西有大量的复用 Dialogue: 0,0:56:34.53,0:56:36.72,Default,,0,0,0,,玩拼字游戏 Dialogue: 0,0:56:36.96,0:56:39.88,Default,,0,0,0,,当你要完成三倍分数的词时 Dialogue: 0,0:56:40.49,0:56:43.60,Default,,0,0,0,,自顶向下的设计策略并不容易 Dialogue: 0,0:56:44.95,0:56:47.08,Default,,0,0,0,,然而 大多数实际的工程学都是 Dialogue: 0,0:56:47.36,0:56:50.70,Default,,0,0,0,,秉承着“尽其力而为之” Dialogue: 0,0:56:52.14,0:56:53.52,Default,,0,0,0,,那就是你所看到的东西 Dialogue: 0,0:56:54.86,0:56:55.55,Default,,0,0,0,,嗯? Dialogue: 0,0:56:55.55,0:56:56.81,Default,,0,0,0,,学生:这是最后一个问题吗? Dialogue: 0,0:57:00.28,0:57:02.03,Default,,0,0,0,,[笑声] Dialogue: 0,0:57:18.64,0:57:19.63,Default,,0,0,0,,教授:看起来是 Dialogue: 0,0:57:23.57,0:57:24.12,Default,,0,0,0,,谢谢大家 Dialogue: 0,0:57:25.90,0:57:36.50,Default,,0,0,0,,[掌声] Dialogue: 0,0:58:47.29,0:58:51.13,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:58:47.29,0:58:51.13,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP Dialogue: 0,0:58:51.87,0:58:53.71,Default,,0,0,0,,{\an4\pos(33,231)}  你所知道的有关计算的东西,其他人也都能学到。绝不要认为\N\N\N似乎成功计算的钥匙就掌握在你的手里。你所掌握的,也是我认为\N\N\N并希望的,也就是智慧:那种看到这一机器比你第一次站在它面前\N\N\N时能做得更多的能力,这样你才能将它向前推进。\N\N\N\N\N               Alan J. Perlis (1922.4.1 - 1990.1.7) ================================================ FILE: Ass/lec10b.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Audio File: ../../../../Movies/Lec10b_480_muxed.mp4 Video File: ../../../../Movies/Lec10b_480_muxed.mp4 Video AR Mode: 4 Video AR Value: 1.333333 Video Zoom Percent: 2.000000 Scroll Position: 1311 Active Line: 1321 Video Position: 105851 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:03.48,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:00.00,0:00:03.48,Declare,,0,0,0,,{\fad(500,500)\pos(316,274)}“让我们举杯,祝福那些\N\N\N\N将他们的思想镶嵌在\N\N\N\N   重重括号之间的Lisp程序员。” Dialogue: 0,0:00:04.75,0:00:11.77,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N杨启钊\N(windfarer) Dialogue: 0,0:00:04.75,0:00:11.77,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.75,0:00:11.77,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:04.75,0:00:11.77,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:04.75,0:00:11.77,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:11.88,0:00:15.72,Declare,,0,0,0,,{\an2\fad(500,500)}存储分配与垃圾收集 Dialogue: 0,0:00:18.91,0:00:20.61,Default,,0,0,0,,教授: 接下来我要解开 Dialogue: 0,0:00:21.16,0:00:23.36,Default,,0,0,0,,目前仅剩的谜团 Dialogue: 0,0:00:24.44,0:00:28.80,Default,,0,0,0,,我们能毫无顾虑地进行CONS Dialogue: 0,0:00:30.00,0:00:31.62,Default,,0,0,0,,就好像空间足够多一样 Dialogue: 0,0:00:32.80,0:00:36.32,Default,,0,0,0,,我们总是在使用 Dialogue: 0,0:00:36.51,0:00:37.44,Default,,0,0,0,,CAR和CDR Dialogue: 0,0:00:37.47,0:00:38.72,Default,,0,0,0,,并假设知道我们知道 Dialogue: 0,0:00:38.75,0:00:39.74,Default,,0,0,0,,它们是如何实现的 Dialogue: 0,0:00:40.02,0:00:40.67,Default,,0,0,0,,事实上 Dialogue: 0,0:00:41.07,0:00:44.40,Default,,0,0,0,,我们认为它们是基本过程 Dialogue: 0,0:00:45.37,0:00:47.57,Default,,0,0,0,,但这没有真正解决问题 Dialogue: 0,0:00:47.73,0:00:50.25,Default,,0,0,0,,因为过程依赖各种复杂的机制 Dialogue: 0,0:00:50.27,0:00:51.37,Default,,0,0,0,,需要诸如环境结构之类的东西 Dialogue: 0,0:00:51.64,0:00:52.76,Default,,0,0,0,,才能运行起来 Dialogue: 0,0:00:53.01,0:00:54.89,Default,,0,0,0,,而归根结底它们也是 Dialogue: 0,0:00:54.89,0:00:56.42,Default,,0,0,0,,由CONS之类的东西构成的 Dialogue: 0,0:00:56.70,0:00:58.47,Default,,0,0,0,,这的确没有解决问题 Dialogue: 0,0:00:59.38,0:01:01.13,Default,,0,0,0,,目前的问题是 Dialogue: 0,0:01:01.31,0:01:03.97,Default,,0,0,0,,粘合这些数据结构的是什么东西? Dialogue: 0,0:01:04.76,0:01:06.40,Default,,0,0,0,,它可能是怎样的一个东西? Dialogue: 0,0:01:07.04,0:01:10.46,Default,,0,0,0,,我们已经见过了一台机器 Dialogue: 0,0:01:10.46,0:01:13.96,Default,,0,0,0,,一台计算机具有一个控制器 Dialogue: 0,0:01:14.27,0:01:15.45,Default,,0,0,0,,和一些寄存器 Dialogue: 0,0:01:15.45,0:01:16.47,Default,,0,0,0,,还可能有一个栈 Dialogue: 0,0:01:16.98,0:01:18.12,Default,,0,0,0,,但是我们还没提到一些东西 Dialogue: 0,0:01:18.16,0:01:19.95,Default,,0,0,0,,例如 大内存 Dialogue: 0,0:01:20.57,0:01:22.38,Default,,0,0,0,,我想 现在是时候讨论它们了 Dialogue: 0,0:01:23.74,0:01:26.56,Default,,0,0,0,,但是先要说清楚 Dialogue: 0,0:01:26.59,0:01:27.88,Default,,0,0,0,,这个并不是必须的 Dialogue: 0,0:01:28.82,0:01:30.79,Default,,0,0,0,,只是一些实现上的细节 Dialogue: 0,0:01:31.10,0:01:32.60,Default,,0,0,0,,让我举个例子 Dialogue: 0,0:01:32.60,0:01:34.20,Default,,0,0,0,,如何用数字来表示这些东西 Dialogue: 0,0:01:35.23,0:01:36.82,Default,,0,0,0,,有个比较简单的方法 Dialogue: 0,0:01:37.59,0:01:39.00,Default,,0,0,0,,一位著名的逻辑学家 哥德尔 Dialogue: 0,0:01:44.09,0:01:46.01,Default,,0,0,0,,在20世纪30年代末 Dialogue: 0,0:01:46.38,0:01:48.70,Default,,0,0,0,,发明了一个很巧妙的方法 Dialogue: 0,0:01:48.70,0:01:52.27,Default,,0,0,0,,能够把复杂的表达式 Dialogue: 0,0:01:52.81,0:01:53.52,Default,,0,0,0,,表示成数字 Dialogue: 0,0:01:54.32,0:01:55.05,Default,,0,0,0,,例如 Dialogue: 0,0:01:55.05,0:01:58.00,Default,,0,0,0,,我不会照搬哥德尔的方法 Dialogue: 0,0:01:58.00,0:01:59.48,Default,,0,0,0,,因为他没有使用CONS之类的术语 Dialogue: 0,0:01:59.66,0:02:00.60,Default,,0,0,0,,他使用了其它的组合手段 Dialogue: 0,0:02:00.91,0:02:02.60,Default,,0,0,0,,来编码表达式 Dialogue: 0,0:02:03.09,0:02:03.88,Default,,0,0,0,,他的思路是 Dialogue: 0,0:02:03.92,0:02:06.81,Default,,0,0,0,,用不同数字分别代表每个代数式 Dialogue: 0,0:02:07.92,0:02:09.72,Default,,0,0,0,,通过组合各个部分的数字 Dialogue: 0,0:02:09.72,0:02:11.65,Default,,0,0,0,,来形成新的表达式 Dialogue: 0,0:02:12.47,0:02:13.45,Default,,0,0,0,,举例来说 Dialogue: 0,0:02:13.62,0:02:15.35,Default,,0,0,0,,我们在创造世界的时候 Dialogue: 0,0:02:15.35,0:02:18.01,Default,,0,0,0,,如果用数字 Dialogue: 0,0:02:20.78,0:02:22.22,Default,,0,0,0,,来表示对象 Dialogue: 0,0:02:30.67,0:02:37.93,Default,,0,0,0,,那么(CONS X Y) Dialogue: 0,0:02:38.04,0:02:41.07,Default,,0,0,0,,就可以表示为 Dialogue: 0,0:02:41.55,0:02:43.77,Default,,0,0,0,,2^X * 3^Y Dialogue: 0,0:02:46.13,0:02:48.03,Default,,0,0,0,,因为这样我们还能取出它的每一部分 Dialogue: 0,0:02:49.56,0:02:50.97,Default,,0,0,0,,举例来说 Dialogue: 0,0:02:51.18,0:02:55.88,Default,,0,0,0,,(CAR X) Dialogue: 0,0:02:56.55,0:03:05.18,Default,,0,0,0,,就是X中因数2的个数 Dialogue: 0,0:03:06.69,0:03:08.78,Default,,0,0,0,,当然(CDR X)是一样的 Dialogue: 0,0:03:10.69,0:03:15.57,Default,,0,0,0,,它就X中因数3的个数 Dialogue: 0,0:03:16.51,0:03:18.65,Default,,0,0,0,,这是个非常合理的方案 Dialogue: 0,0:03:19.10,0:03:20.11,Default,,0,0,0,,只不过就是 Dialogue: 0,0:03:20.12,0:03:22.52,Default,,0,0,0,,数字的位数 Dialogue: 0,0:03:22.83,0:03:23.98,Default,,0,0,0,,会急剧地增大 Dialogue: 0,0:03:24.32,0:03:26.55,Default,,0,0,0,,甚至比宇宙中的粒子还多 Dialogue: 0,0:03:27.95,0:03:29.88,Default,,0,0,0,,所以除了在理论中 Dialogue: 0,0:03:29.90,0:03:31.21,Default,,0,0,0,,没有实现这种方案的好办法 Dialogue: 0,0:03:33.43,0:03:34.48,Default,,0,0,0,,另一方面 Dialogue: 0,0:03:35.12,0:03:37.55,Default,,0,0,0,,也有其它的表示方式 Dialogue: 0,0:03:38.45,0:03:40.01,Default,,0,0,0,,我们把它们表示为 Dialogue: 0,0:03:40.25,0:03:42.42,Default,,0,0,0,,一些小盒子 Dialogue: 0,0:03:43.32,0:03:46.43,Default,,0,0,0,,我们把CONS结构 Dialogue: 0,0:03:46.50,0:03:48.05,Default,,0,0,0,,想象为这样的东西 Dialogue: 0,0:03:50.28,0:03:52.57,Default,,0,0,0,,它们是里面装着东西的小隔间 Dialogue: 0,0:03:53.56,0:03:55.47,Default,,0,0,0,,这些格子组成一个树 Dialogue: 0,0:03:57.21,0:03:59.97,Default,,0,0,0,,我希望半导体制造商 Dialogue: 0,0:03:59.97,0:04:02.07,Default,,0,0,0,,能够提供适配这样需求的芯片 Dialogue: 0,0:04:02.70,0:04:03.76,Default,,0,0,0,,但事实上 Dialogue: 0,0:04:03.85,0:04:05.31,Default,,0,0,0,,他们提供给我的却是 Dialogue: 0,0:04:06.20,0:04:07.96,Default,,0,0,0,,线性的内存 Dialogue: 0,0:04:09.38,0:04:13.46,Default,,0,0,0,,内存是一串小隔间 Dialogue: 0,0:04:15.12,0:04:16.34,Default,,0,0,0,,像这样的小隔间 Dialogue: 0,0:04:17.72,0:04:20.25,Default,,0,0,0,,每个小隔间里可以保存确定大小的对象 Dialogue: 0,0:04:20.94,0:04:22.20,Default,,0,0,0,,一个尺寸固定的对象 Dialogue: 0,0:04:23.39,0:04:24.07,Default,,0,0,0,,例如 Dialogue: 0,0:04:24.07,0:04:25.66,Default,,0,0,0,,一个含25个元素的表 Dialogue: 0,0:04:25.66,0:04:26.64,Default,,0,0,0,,就放不进这里 Dialogue: 0,0:04:28.55,0:04:29.26,Default,,0,0,0,,然而 它们中的每一个 Dialogue: 0,0:04:29.29,0:04:30.88,Default,,0,0,0,,都是由地址索引的 Dialogue: 0,0:04:33.97,0:04:34.99,Default,,0,0,0,,因此它们的地址可能是 Dialogue: 0,0:04:35.02,0:04:35.50,Default,,0,0,0,,这里是0 Dialogue: 0,0:04:35.50,0:04:36.22,Default,,0,0,0,,这里是1 Dialogue: 0,0:04:36.22,0:04:36.70,Default,,0,0,0,,这里是2 Dialogue: 0,0:04:36.70,0:04:37.25,Default,,0,0,0,,这里是3 Dialogue: 0,0:04:37.25,0:04:37.94,Default,,0,0,0,,以此类推 Dialogue: 0,0:04:38.06,0:04:40.40,Default,,0,0,0,,这里写的数字并不重要 Dialogue: 0,0:04:40.40,0:04:41.68,Default,,0,0,0,,重要的是 它们不重复 Dialogue: 0,0:04:41.95,0:04:43.42,Default,,0,0,0,,有了它们就能找到下一个在哪 Dialogue: 0,0:04:44.97,0:04:46.14,Default,,0,0,0,,在其中每一个小隔间里面 Dialogue: 0,0:04:46.36,0:04:49.11,Default,,0,0,0,,我们可以把东西放进去 Dialogue: 0,0:04:49.53,0:04:50.77,Default,,0,0,0,,对于没有造过计算机的我们来说 Dialogue: 0,0:04:51.02,0:04:53.66,Default,,0,0,0,,内存就是这样子的 Dialogue: 0,0:04:54.15,0:04:54.65,Default,,0,0,0,,现在 Dialogue: 0,0:04:56.69,0:04:57.53,Default,,0,0,0,,现在的问题是 Dialogue: 0,0:04:57.53,0:04:59.97,Default,,0,0,0,,如何用这样的结构 Dialogue: 0,0:05:00.42,0:05:01.72,Default,,0,0,0,,来实现这个树形结构 Dialogue: 0,0:05:03.29,0:05:04.57,Default,,0,0,0,,其实并不难 Dialogue: 0,0:05:04.57,0:05:06.35,Default,,0,0,0,,已经有大量的方案来做这个了 Dialogue: 0,0:05:06.87,0:05:08.80,Default,,0,0,0,,最重要的一个方案是 Dialogue: 0,0:05:08.80,0:05:11.18,Default,,0,0,0,,假设半导体制造商 Dialogue: 0,0:05:11.20,0:05:13.90,Default,,0,0,0,,允许我安排自己的内存 Dialogue: 0,0:05:13.98,0:05:15.77,Default,,0,0,0,,使得其中每个小隔间都足够大 Dialogue: 0,0:05:16.28,0:05:18.20,Default,,0,0,0,,能够装得下另一个的地址 Dialogue: 0,0:05:19.35,0:05:20.83,Default,,0,0,0,,我需要这么来安排 Dialogue: 0,0:05:22.05,0:05:23.45,Default,,0,0,0,,事实上它需要更大一点 Dialogue: 0,0:05:23.48,0:05:27.52,Default,,0,0,0,,因为我还要在里面存放一些信息 Dialogue: 0,0:05:27.56,0:05:30.09,Default,,0,0,0,,它标示了这里面是什么东西 Dialogue: 0,0:05:30.39,0:05:31.64,Default,,0,0,0,,我们过一会就能看到 Dialogue: 0,0:05:32.62,0:05:34.40,Default,,0,0,0,,当然 如果半导体制造商 Dialogue: 0,0:05:34.43,0:05:35.88,Default,,0,0,0,,没有这么来制造 Dialogue: 0,0:05:36.08,0:05:38.44,Default,,0,0,0,,我就需要用一些机智的方式 Dialogue: 0,0:05:38.57,0:05:41.82,Default,,0,0,0,,把它们组合起来以供使用 Dialogue: 0,0:05:43.77,0:05:47.05,Default,,0,0,0,,我们想象一下 Dialogue: 0,0:05:47.05,0:05:49.54,Default,,0,0,0,,把这个复杂的树形结构 Dialogue: 0,0:05:49.54,0:05:51.20,Default,,0,0,0,,塞进线性内存里 Dialogue: 0,0:05:51.74,0:05:54.47,Default,,0,0,0,,我们来看第一张幻灯片 Dialogue: 0,0:05:54.47,0:05:58.30,Default,,0,0,0,,可以看到一个传统的实现方案 Dialogue: 0,0:05:59.49,0:06:02.62,Default,,0,0,0,,它是把表结构放入线性内存 Dialogue: 0,0:06:03.22,0:06:05.87,Default,,0,0,0,,的标准方式 Dialogue: 0,0:06:06.27,0:06:08.32,Default,,0,0,0,,我们把这块内存 Dialogue: 0,0:06:08.88,0:06:11.12,Default,,0,0,0,,分为两部分 Dialogue: 0,0:06:12.03,0:06:13.42,Default,,0,0,0,,一个叫THE-CARS的数组 Dialogue: 0,0:06:14.45,0:06:15.88,Default,,0,0,0,,一个叫THE-CDRS的数组 Dialogue: 0,0:06:17.58,0:06:18.86,Default,,0,0,0,,无论它们是 Dialogue: 0,0:06:18.88,0:06:21.04,Default,,0,0,0,,顺序的地址或是其它的 Dialogue: 0,0:06:21.12,0:06:22.00,Default,,0,0,0,,其实并不重要 Dialogue: 0,0:06:22.87,0:06:25.20,Default,,0,0,0,,这是实现细节了 Dialogue: 0,0:06:25.80,0:06:28.40,Default,,0,0,0,,但有两个数组 Dialogue: 0,0:06:28.96,0:06:30.36,Default,,0,0,0,,线性数组是由 Dialogue: 0,0:06:30.46,0:06:32.59,Default,,0,0,0,,顺序的下标索引的 Dialogue: 0,0:06:34.84,0:06:36.85,Default,,0,0,0,,每个小格子里存的 Dialogue: 0,0:06:37.46,0:06:39.85,Default,,0,0,0,,是一个带类型的对象 Dialogue: 0,0:06:41.43,0:06:42.57,Default,,0,0,0,,这里的类型 Dialogue: 0,0:06:42.57,0:06:45.71,Default,,0,0,0,,以字母P开头 Dialogue: 0,0:06:45.71,0:06:46.57,Default,,0,0,0,,表示序对 Dialogue: 0,0:06:47.79,0:06:49.37,Default,,0,0,0,,以N开头 表示数字 Dialogue: 0,0:06:50.04,0:06:52.25,Default,,0,0,0,,E开头 表示空表 Dialogue: 0,0:06:54.81,0:06:55.83,Default,,0,0,0,,也就是表尾标志 Dialogue: 0,0:06:57.02,0:06:58.59,Default,,0,0,0,,如果我们想表示 Dialogue: 0,0:06:58.99,0:06:59.97,Default,,0,0,0,,这样一个对象 Dialogue: 0,0:07:00.01,0:07:02.16,Default,,0,0,0,,首元素为(1 2) Dialogue: 0,0:07:02.65,0:07:04.01,Default,,0,0,0,,然后3、4分别作为 Dialogue: 0,0:07:04.01,0:07:05.50,Default,,0,0,0,,它的第二和第三个元素 Dialogue: 0,0:07:06.43,0:07:08.83,Default,,0,0,0,,这个表的第一部分也是一个表 Dialogue: 0,0:07:09.35,0:07:10.65,Default,,0,0,0,,后面接着是两个数字 Dialogue: 0,0:07:10.65,0:07:12.00,Default,,0,0,0,,分别为第二和第三部分 Dialogue: 0,0:07:12.87,0:07:14.81,Default,,0,0,0,,现在我们用盒子-指针表示法 Dialogue: 0,0:07:14.84,0:07:16.67,Default,,0,0,0,,来描绘它 Dialogue: 0,0:07:17.32,0:07:18.00,Default,,0,0,0,,你能发现 Dialogue: 0,0:07:18.00,0:07:20.04,Default,,0,0,0,,这里有三个单元 Dialogue: 0,0:07:20.25,0:07:22.01,Default,,0,0,0,,它们的CAR指针 Dialogue: 0,0:07:22.27,0:07:27.10,Default,,0,0,0,,分别指向对象(1 2)、3以及4 Dialogue: 0,0:07:28.39,0:07:29.75,Default,,0,0,0,,当然这个(1 2) Dialogue: 0,0:07:29.75,0:07:31.32,Default,,0,0,0,,即整个结构的CAR Dialogue: 0,0:07:31.32,0:07:32.65,Default,,0,0,0,,本身就是一个子结构 Dialogue: 0,0:07:32.88,0:07:34.75,Default,,0,0,0,,包含一个像这样的子表 Dialogue: 0,0:07:35.94,0:07:37.07,Default,,0,0,0,,我要做的是 Dialogue: 0,0:07:37.20,0:07:39.92,Default,,0,0,0,,就是按照下标 Dialogue: 0,0:07:39.95,0:07:41.46,Default,,0,0,0,,把它们放进去 Dialogue: 0,0:07:41.84,0:07:43.40,Default,,0,0,0,,像这里的1 Dialogue: 0,0:07:43.56,0:07:47.05,Default,,0,0,0,,代表了这个格子的下标 Dialogue: 0,0:07:49.85,0:07:51.47,Default,,0,0,0,,这里的指针 Dialogue: 0,0:07:52.37,0:07:54.86,Default,,0,0,0,,是对THE-CARS Dialogue: 0,0:07:55.07,0:07:57.29,Default,,0,0,0,,和THE-CDRS里的小格子的引用 Dialogue: 0,0:07:57.40,0:07:58.67,Default,,0,0,0,,它在我的线性内存中 Dialogue: 0,0:07:58.76,0:08:00.33,Default,,0,0,0,,被标记为1的地方 Dialogue: 0,0:08:02.00,0:08:04.06,Default,,0,0,0,,如果我想把这个结构 Dialogue: 0,0:08:04.16,0:08:05.26,Default,,0,0,0,,塞进线性内存中 Dialogue: 0,0:08:05.85,0:08:07.52,Default,,0,0,0,,要做的是 Dialogue: 0,0:08:07.52,0:08:11.88,Default,,0,0,0,,把它放进格子1中 Dialogue: 0,0:08:11.95,0:08:12.66,Default,,0,0,0,,我要选取1号格子 Dialogue: 0,0:08:12.66,0:08:13.85,Default,,0,0,0,,这个就是1号格子 Dialogue: 0,0:08:14.27,0:08:16.22,Default,,0,0,0,,这是它的CAR Dialogue: 0,0:08:16.22,0:08:17.74,Default,,0,0,0,,我要把它赋值给一个序对 Dialogue: 0,0:08:17.95,0:08:18.72,Default,,0,0,0,,这个序对 Dialogue: 0,0:08:20.02,0:08:21.55,Default,,0,0,0,,序号是5 Dialogue: 0,0:08:22.59,0:08:23.90,Default,,0,0,0,,它的CDR Dialogue: 0,0:08:23.90,0:08:25.13,Default,,0,0,0,,就是这个 Dialogue: 0,0:08:25.39,0:08:26.13,Default,,0,0,0,,它是个序对 Dialogue: 0,0:08:26.13,0:08:27.70,Default,,0,0,0,,我会把它放到2的位置 Dialogue: 0,0:08:28.34,0:08:28.98,Default,,0,0,0,,即P2 Dialogue: 0,0:08:30.89,0:08:32.95,Default,,0,0,0,,我们看P2 Dialogue: 0,0:08:32.95,0:08:34.72,Default,,0,0,0,,P2的CAR Dialogue: 0,0:08:34.90,0:08:37.22,Default,,0,0,0,,是数字3 Dialogue: 0,0:08:37.34,0:08:38.64,Default,,0,0,0,,如你所见N3 Dialogue: 0,0:08:39.52,0:08:41.52,Default,,0,0,0,,这里 它的CDR Dialogue: 0,0:08:41.72,0:08:43.40,Default,,0,0,0,,是一个序对 Dialogue: 0,0:08:43.97,0:08:45.81,Default,,0,0,0,,在位置4 Dialogue: 0,0:08:46.64,0:08:47.79,Default,,0,0,0,,这就是P4 Dialogue: 0,0:08:48.65,0:08:51.16,Default,,0,0,0,,P4是一个数字 Dialogue: 0,0:08:51.85,0:08:53.87,Default,,0,0,0,,它的CAR部分是数字4 Dialogue: 0,0:08:54.60,0:08:55.65,Default,,0,0,0,,它的CDR Dialogue: 0,0:08:55.84,0:08:58.48,Default,,0,0,0,,是个空表 就在这儿 Dialogue: 0,0:08:59.17,0:08:59.90,Default,,0,0,0,,这个表就结束了 Dialogue: 0,0:09:00.69,0:09:04.57,Default,,0,0,0,,这就是在线性内存中 Dialogue: 0,0:09:04.90,0:09:09.55,Default,,0,0,0,,表示二叉树的传统方式 Dialogue: 0,0:09:11.62,0:09:15.10,Default,,0,0,0,,那么 下一个问题是 Dialogue: 0,0:09:15.10,0:09:16.36,Default,,0,0,0,,我们需要关心 Dialogue: 0,0:09:16.60,0:09:18.19,Default,,0,0,0,,如何去实现 Dialogue: 0,0:09:18.44,0:09:20.33,Default,,0,0,0,,这意味着当我写下一个过程 Dialogue: 0,0:09:20.36,0:09:23.62,Default,,0,0,0,,用来给A赋值时 Dialogue: 0,0:09:24.54,0:09:27.10,Default,,0,0,0,,使用寄存机器的代码来编写的 Dialogue: 0,0:09:27.21,0:09:30.14,Default,,0,0,0,,(ASSIGN A (FETCH B)) Dialogue: 0,0:09:30.84,0:09:31.85,Default,,0,0,0,,我实际上想做的是 Dialogue: 0,0:09:31.97,0:09:37.10,Default,,0,0,0,,定位这些元素 Dialogue: 0,0:09:38.74,0:09:40.25,Default,,0,0,0,,那段机器代码只是 Dialogue: 0,0:09:40.68,0:09:42.94,Default,,0,0,0,,这个复杂过程的简写 Dialogue: 0,0:09:44.47,0:09:46.33,Default,,0,0,0,,当然 为了把它“写下来” Dialogue: 0,0:09:46.35,0:09:48.59,Default,,0,0,0,,我要引入一种 Dialogue: 0,0:09:48.62,0:09:49.42,Default,,0,0,0,,称为“向量”的结构 Dialogue: 0,0:09:52.12,0:09:53.31,Default,,0,0,0,,我们得有一种东西 Dialogue: 0,0:09:53.48,0:09:54.54,Default,,0,0,0,,用来引用向量 Dialogue: 0,0:09:56.84,0:09:58.51,Default,,0,0,0,,这样我们就能把它写下来 Dialogue: 0,0:09:58.71,0:10:00.22,Default,,0,0,0,,它的参数之一是向量的名字 Dialogue: 0,0:10:01.02,0:10:03.97,Default,,0,0,0,,我觉得这个名字起得不太靠谱 Dialogue: 0,0:10:03.97,0:10:09.40,Default,,0,0,0,,它接受VECTOR和INDEX两个参数 Dialogue: 0,0:10:11.20,0:10:13.05,Default,,0,0,0,,我可以用VECTOR-SET! Dialogue: 0,0:10:13.10,0:10:14.27,Default,,0,0,0,,来为其中的分量赋值 Dialogue: 0,0:10:14.65,0:10:15.60,Default,,0,0,0,,我不太在意 Dialogue: 0,0:10:16.28,0:10:17.55,Default,,0,0,0,,我们来看一看 Dialogue: 0,0:10:18.11,0:10:20.42,Default,,0,0,0,,在这种实现中 Dialogue: 0,0:10:21.25,0:10:23.18,Default,,0,0,0,,CAR和CDR是什么样子的 Dialogue: 0,0:10:26.47,0:10:28.41,Default,,0,0,0,,比如说 如果我刚好有 Dialogue: 0,0:10:28.88,0:10:30.80,Default,,0,0,0,,一个寄存器B Dialogue: 0,0:10:31.15,0:10:34.64,Default,,0,0,0,,它存了一个序对的下标 Dialogue: 0,0:10:35.95,0:10:38.80,Default,,0,0,0,,即它是指向一个序对的指针 Dialogue: 0,0:10:39.35,0:10:40.85,Default,,0,0,0,,我可以取它的CAR Dialogue: 0,0:10:41.55,0:10:44.11,Default,,0,0,0,,存到寄存器A里面 Dialogue: 0,0:10:44.49,0:10:46.86,Default,,0,0,0,,事实上它是 Dialogue: 0,0:10:47.37,0:10:50.19,Default,,0,0,0,,把A赋值为-- Dialogue: 0,0:10:50.19,0:10:51.92,Default,,0,0,0,,引用向量的一个分量-- Dialogue: 0,0:10:52.80,0:10:55.24,Default,,0,0,0,,或者你可以把它叫做索引一个数组 Dialogue: 0,0:10:55.42,0:10:57.63,Default,,0,0,0,,目标向量为THE-CARS Dialogue: 0,0:10:58.40,0:11:00.92,Default,,0,0,0,,而目标分量是B Dialogue: 0,0:11:02.65,0:11:03.63,Default,,0,0,0,,CDR的操作也类似 Dialogue: 0,0:11:04.10,0:11:05.72,Default,,0,0,0,,我们可以用同样的方式 Dialogue: 0,0:11:05.90,0:11:08.32,Default,,0,0,0,,来对数据结构赋值 Dialogue: 0,0:11:08.92,0:11:10.92,Default,,0,0,0,,如果我们需要这么做的话 Dialogue: 0,0:11:11.84,0:11:13.80,Default,,0,0,0,,构建这个并不太难 Dialogue: 0,0:11:14.58,0:11:15.72,Default,,0,0,0,,下一个问题是 Dialogue: 0,0:11:15.72,0:11:17.00,Default,,0,0,0,,我们如何分配它们 Dialogue: 0,0:11:18.01,0:11:20.13,Default,,0,0,0,,我们经常需要一个新的序对 Dialogue: 0,0:11:21.40,0:11:23.42,Default,,0,0,0,,当然 CONS并没有长在树上 Dialogue: 0,0:11:23.79,0:11:24.81,Default,,0,0,0,,或许它们应该那样 Dialogue: 0,0:11:25.34,0:11:26.56,Default,,0,0,0,,我必须得有某种方法 Dialogue: 0,0:11:26.70,0:11:28.97,Default,,0,0,0,,来获得一个可用的序对 Dialogue: 0,0:11:29.98,0:11:31.47,Default,,0,0,0,,我需要某种方案 Dialogue: 0,0:11:31.47,0:11:33.04,Default,,0,0,0,,当内存不再使用的时候 Dialogue: 0,0:11:33.69,0:11:35.05,Default,,0,0,0,,我可以重新分配它们 Dialogue: 0,0:11:35.63,0:11:37.38,Default,,0,0,0,,有很多方案可以实现这一点 Dialogue: 0,0:11:37.38,0:11:39.07,Default,,0,0,0,,现在我给你们展示的这个东西 Dialogue: 0,0:11:39.23,0:11:40.45,Default,,0,0,0,,并是不必要的 Dialogue: 0,0:11:42.10,0:11:43.18,Default,,0,0,0,,然而它很方便 Dialogue: 0,0:11:43.20,0:11:44.44,Default,,0,0,0,,并且被实现很多次了 Dialogue: 0,0:11:44.60,0:11:47.20,Default,,0,0,0,,其中一种基于“空闲表”的分配方案 Dialogue: 0,0:11:47.66,0:11:48.68,Default,,0,0,0,,它的意思就是 Dialogue: 0,0:11:48.68,0:11:51.12,Default,,0,0,0,,世界上所有的空闲内存 Dialogue: 0,0:11:51.55,0:11:53.08,Default,,0,0,0,,都连在一个链表中 Dialogue: 0,0:11:54.55,0:11:56.22,Default,,0,0,0,,就像其它东西一样 Dialogue: 0,0:11:56.96,0:11:59.07,Default,,0,0,0,,每当你需要一个新的格子 Dialogue: 0,0:11:59.07,0:12:00.12,Default,,0,0,0,,来进行CONS的时候 Dialogue: 0,0:12:00.95,0:12:02.26,Default,,0,0,0,,你选择第一个格子 Dialogue: 0,0:12:02.26,0:12:03.82,Default,,0,0,0,,将它的CDR指向空闲表 Dialogue: 0,0:12:04.32,0:12:05.55,Default,,0,0,0,,然后分配它 Dialogue: 0,0:12:06.03,0:12:08.32,Default,,0,0,0,,就像这样 Dialogue: 0,0:12:09.53,0:12:13.32,Default,,0,0,0,,这里 我们的空闲表 Dialogue: 0,0:12:13.95,0:12:16.81,Default,,0,0,0,,就是从6开始 Dialogue: 0,0:12:18.51,0:12:23.47,Default,,0,0,0,,它是一个指向8的指针 Dialogue: 0,0:12:24.86,0:12:25.62,Default,,0,0,0,,它表示 Dialogue: 0,0:12:25.62,0:12:26.55,Default,,0,0,0,,当前这个是空闲的 Dialogue: 0,0:12:26.55,0:12:27.95,Default,,0,0,0,,下一个在位置8 Dialogue: 0,0:12:28.87,0:12:29.88,Default,,0,0,0,,这个是空闲的 Dialogue: 0,0:12:30.04,0:12:32.08,Default,,0,0,0,,下一个在位置3 Dialogue: 0,0:12:32.32,0:12:33.45,Default,,0,0,0,,下一个是空闲的 Dialogue: 0,0:12:33.93,0:12:34.95,Default,,0,0,0,,这个是空闲的 Dialogue: 0,0:12:35.04,0:12:37.68,Default,,0,0,0,,下一个在位置0 Dialogue: 0,0:12:37.87,0:12:38.49,Default,,0,0,0,,这个是空闲的 Dialogue: 0,0:12:38.52,0:12:39.82,Default,,0,0,0,,下一个在位置15 Dialogue: 0,0:12:40.94,0:12:41.84,Default,,0,0,0,,以此类推 Dialogue: 0,0:12:42.78,0:12:44.64,Default,,0,0,0,,我们可以想象有这样的结构 Dialogue: 0,0:12:46.40,0:12:48.03,Default,,0,0,0,,一旦我们有了这样的机制 Dialogue: 0,0:12:49.45,0:12:50.92,Default,,0,0,0,,那么当你需要空间的时候 Dialogue: 0,0:12:50.92,0:12:52.22,Default,,0,0,0,,就能获取一个 Dialogue: 0,0:12:53.82,0:12:56.46,Default,,0,0,0,,那些使用了CONS的程序 Dialogue: 0,0:12:57.45,0:12:59.13,Default,,0,0,0,,内存可能就是像这样的 Dialogue: 0,0:12:59.32,0:13:02.57,Default,,0,0,0,,把B和C进行CONS之后的值 Dialogue: 0,0:13:02.95,0:13:05.82,Default,,0,0,0,,赋值给A寄存器 Dialogue: 0,0:13:06.20,0:13:09.04,Default,,0,0,0,,结果包括B和C Dialogue: 0,0:13:09.27,0:13:10.52,Default,,0,0,0,,我们要做的是 Dialogue: 0,0:13:10.56,0:13:12.24,Default,,0,0,0,,把当前的尾部格子 即空闲表的前个格子 Dialogue: 0,0:13:12.47,0:13:14.30,Default,,0,0,0,,让它的CDR指向空闲表 Dialogue: 0,0:13:15.64,0:13:18.33,Default,,0,0,0,,我们要把THE-CARS中 Dialogue: 0,0:13:18.41,0:13:22.49,Default,,0,0,0,,由A索引的格子 Dialogue: 0,0:13:23.13,0:13:25.45,Default,,0,0,0,,修改为B中的内容 Dialogue: 0,0:13:25.90,0:13:28.65,Default,,0,0,0,,THE-CDRS中由A索引的格子 Dialogue: 0,0:13:29.20,0:13:31.72,Default,,0,0,0,,修改为C的值 Dialogue: 0,0:13:33.20,0:13:34.76,Default,,0,0,0,,现在A所指的格子里面 Dialogue: 0,0:13:34.78,0:13:36.65,Default,,0,0,0,,就是新构建好的对象了 Dialogue: 0,0:13:36.81,0:13:37.92,Default,,0,0,0,,这就是我们要的对象 Dialogue: 0,0:13:40.47,0:13:42.50,Default,,0,0,0,,我之前告诉过你们 Dialogue: 0,0:13:42.50,0:13:43.97,Default,,0,0,0,,这里撒了个谎 Dialogue: 0,0:13:43.97,0:13:45.32,Default,,0,0,0,,也就是在这里的某处 Dialogue: 0,0:13:45.53,0:13:47.32,Default,,0,0,0,,我本来应该 Dialogue: 0,0:13:48.45,0:13:50.48,Default,,0,0,0,,把我CONS起来的对象 Dialogue: 0,0:13:50.51,0:13:51.87,Default,,0,0,0,,设置为序对类型 Dialogue: 0,0:13:52.30,0:13:53.05,Default,,0,0,0,,但我没有 Dialogue: 0,0:13:53.51,0:13:56.57,Default,,0,0,0,,因此这里应该需要设置一些比特位 Dialogue: 0,0:13:56.60,0:13:57.76,Default,,0,0,0,,我只是还没把它写下来 Dialogue: 0,0:13:59.81,0:14:00.86,Default,,0,0,0,,当然 这个很好实现 Dialogue: 0,0:14:00.89,0:14:02.45,Default,,0,0,0,,因为空闲表本来就是用序对实现的 Dialogue: 0,0:14:03.10,0:14:04.88,Default,,0,0,0,,因此这是没问题的 Dialogue: 0,0:14:06.43,0:14:07.74,Default,,0,0,0,,但这也就是-- Dialogue: 0,0:14:07.82,0:14:09.92,Default,,0,0,0,,这些都是无关紧要的细节 Dialogue: 0,0:14:10.22,0:14:12.88,Default,,0,0,0,,取决于那些想要自制 Dialogue: 0,0:14:12.92,0:14:14.27,Default,,0,0,0,,计算机或Lisp系统的 Dialogue: 0,0:14:14.33,0:14:16.68,Default,,0,0,0,,程序员或架构师 Dialogue: 0,0:14:17.54,0:14:18.71,Default,,0,0,0,,例如 Dialogue: 0,0:14:19.07,0:14:20.24,Default,,0,0,0,,看这个 Dialogue: 0,0:14:20.65,0:14:23.45,Default,,0,0,0,,假设我们要为 Dialogue: 0,0:14:23.55,0:14:26.83,Default,,0,0,0,,这个之前见过的数据结构分配空间 Dialogue: 0,0:14:27.21,0:14:30.26,Default,,0,0,0,,假设我要分配一个新格子 Dialogue: 0,0:14:30.55,0:14:36.61,Default,,0,0,0,,来表示表(1 1 2) Dialogue: 0,0:14:37.24,0:14:39.87,Default,,0,0,0,,其中(1 2)又是 Dialogue: 0,0:14:40.28,0:14:42.16,Default,,0,0,0,,之前一个表的CAR元素 Dialogue: 0,0:14:43.43,0:14:44.45,Default,,0,0,0,,这不怎么难 Dialogue: 0,0:14:44.78,0:14:46.20,Default,,0,0,0,,我用1号单元来存放数字“1” Dialogue: 0,0:14:46.20,0:14:49.17,Default,,0,0,0,,那么P1表示的就是这个单元 Dialogue: 0,0:14:49.53,0:14:50.83,Default,,0,0,0,,这个是P5 Dialogue: 0,0:14:51.67,0:14:53.51,Default,,0,0,0,,它是应该是这个的CDR Dialogue: 0,0:14:54.07,0:14:55.52,Default,,0,0,0,,现在我们要从空闲表中取出一些东西 Dialogue: 0,0:14:55.52,0:14:57.30,Default,,0,0,0,,空闲表现在是从6开始的 Dialogue: 0,0:14:57.78,0:15:00.18,Default,,0,0,0,,而在分配之后 空闲表将从8开始 Dialogue: 0,0:15:00.60,0:15:02.55,Default,,0,0,0,,一个从8开始的空闲表 Dialogue: 0,0:15:02.89,0:15:03.52,Default,,0,0,0,,当然 Dialogue: 0,0:15:03.72,0:15:06.04,Default,,0,0,0,,现在6里面是数字1 Dialogue: 0,0:15:06.15,0:15:07.10,Default,,0,0,0,,就是我们想要的 Dialogue: 0,0:15:07.39,0:15:11.56,Default,,0,0,0,,它的CDR是在位置5的序对 Dialogue: 0,0:15:13.33,0:15:14.50,Default,,0,0,0,,没费多少力气 Dialogue: 0,0:15:16.81,0:15:20.45,Default,,0,0,0,,这里依然存在的一个问题是 Dialogue: 0,0:15:21.00,0:15:23.40,Default,,0,0,0,,我们没有无限大的内存 Dialogue: 0,0:15:25.08,0:15:26.66,Default,,0,0,0,,如果我像这么操作了一会儿 Dialogue: 0,0:15:27.25,0:15:28.00,Default,,0,0,0,,比如说 Dialogue: 0,0:15:28.01,0:15:30.14,Default,,0,0,0,,假设进行一次CONS花费1微秒 Dialogue: 0,0:15:30.60,0:15:32.97,Default,,0,0,0,,如果要进行一百万次CONS Dialogue: 0,0:15:33.60,0:15:35.27,Default,,0,0,0,,那么我就要消耗1秒钟的时间 Dialogue: 0,0:15:35.95,0:15:37.00,Default,,0,0,0,,这就很糟糕了 Dialogue: 0,0:15:38.00,0:15:40.62,Default,,0,0,0,,如何预防这样的灾难 Dialogue: 0,0:15:40.62,0:15:42.19,Default,,0,0,0,,这种生态灾难 Dialogue: 0,0:15:42.60,0:15:44.30,Default,,0,0,0,,在提问环节之后我们再继续讨论 Dialogue: 0,0:15:44.30,0:15:45.26,Default,,0,0,0,,有人要提问吗? Dialogue: 0,0:15:51.50,0:15:51.69,Default,,0,0,0,,请讲 Dialogue: 0,0:15:52.03,0:15:54.67,Default,,0,0,0,,学生:在环境图表中 Dialogue: 0,0:15:54.67,0:15:58.25,Default,,0,0,0,,我们画了过程体 Dialogue: 0,0:15:58.25,0:16:00.67,Default,,0,0,0,,但是在过程应用结束后 Dialogue: 0,0:16:00.80,0:16:03.60,Default,,0,0,0,,这些环境中的东西就不再有用了 Dialogue: 0,0:16:03.60,0:16:04.16,Default,,0,0,0,,教授:说得很对 Dialogue: 0,0:16:04.93,0:16:06.67,Default,,0,0,0,,学生:它是如何表示的? Dialogue: 0,0:16:06.76,0:16:08.75,Default,,0,0,0,,教授:这其实是两个问题 Dialogue: 0,0:16:09.18,0:16:10.25,Default,,0,0,0,,第一个问题是 Dialogue: 0,0:16:10.25,0:16:13.43,Default,,0,0,0,,材料没用了 Dialogue: 0,0:16:13.87,0:16:14.92,Default,,0,0,0,,我们稍后就会讲 Dialogue: 0,0:16:14.92,0:16:17.00,Default,,0,0,0,,如何预防生态灾难 Dialogue: 0,0:16:17.63,0:16:19.20,Default,,0,0,0,,如果我制造了一堆垃圾 Dialogue: 0,0:16:19.20,0:16:21.39,Default,,0,0,0,,我需要自己清理掉 Dialogue: 0,0:16:21.82,0:16:22.97,Default,,0,0,0,,我们一会儿就要讲 Dialogue: 0,0:16:23.43,0:16:24.57,Default,,0,0,0,,第二个问题 Dialogue: 0,0:16:24.57,0:16:27.21,Default,,0,0,0,,你问的是如何表示环境 Dialogue: 0,0:16:27.28,0:16:27.60,Default,,0,0,0,,学生:对 Dialogue: 0,0:16:27.60,0:16:28.19,Default,,0,0,0,,教授:好 Dialogue: 0,0:16:28.19,0:16:30.62,Default,,0,0,0,,环境结构能够以任意的方式表示 Dialogue: 0,0:16:30.92,0:16:31.78,Default,,0,0,0,,有很多种表示方式 Dialogue: 0,0:16:31.78,0:16:33.34,Default,,0,0,0,,这里 我只讲了基于表结构的内存 Dialogue: 0,0:16:33.63,0:16:34.92,Default,,0,0,0,,当然 每个真实的系统 Dialogue: 0,0:16:34.92,0:16:36.72,Default,,0,0,0,,都有任意长度的向量 Dialogue: 0,0:16:36.72,0:16:39.15,Default,,0,0,0,,也有固定长度的向量 Dialogue: 0,0:16:39.31,0:16:40.51,Default,,0,0,0,,它们都可以作为内存的表示方法 Dialogue: 0,0:16:41.08,0:16:44.90,Default,,0,0,0,,在一个专业的Lisp系统中 Dialogue: 0,0:16:44.90,0:16:46.99,Default,,0,0,0,,环境结构是用 Dialogue: 0,0:16:47.30,0:16:49.69,Default,,0,0,0,,向量表示的 Dialogue: 0,0:16:49.69,0:16:51.92,Default,,0,0,0,,它所包含的元素的数量 Dialogue: 0,0:16:51.92,0:16:54.60,Default,,0,0,0,,比参数的个数稍微多一点 Dialogue: 0,0:16:55.35,0:16:56.86,Default,,0,0,0,,因为你需要某种“粘合剂” Dialogue: 0,0:16:57.40,0:17:00.74,Default,,0,0,0,,记住环境是在框架里的 Dialogue: 0,0:17:00.74,0:17:03.98,Default,,0,0,0,,框架是应用过程时被构建出来的 Dialogue: 0,0:17:03.98,0:17:04.78,Default,,0,0,0,,这种情况下 Dialogue: 0,0:17:04.80,0:17:07.60,Default,,0,0,0,,所分配的空间大小为 Dialogue: 0,0:17:07.64,0:17:11.27,Default,,0,0,0,,实际参数加上“粘合剂”占用的空间 Dialogue: 0,0:17:11.27,0:17:12.71,Default,,0,0,0,,然后将它连接到某条链上 Dialogue: 0,0:17:13.32,0:17:15.66,Default,,0,0,0,,在这个层次上 和ALGOL差不多 Dialogue: 0,0:17:19.81,0:17:20.72,Default,,0,0,0,,还有其它问题吗? Dialogue: 0,0:17:23.70,0:17:23.92,Default,,0,0,0,,好 Dialogue: 0,0:17:23.92,0:17:25.55,Default,,0,0,0,,谢谢 我们休息一下 Dialogue: 0,0:17:26.35,0:17:45.48,Default,,0,0,0,,[音乐] Dialogue: 0,0:17:45.53,0:17:50.01,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:17:55.74,0:17:59.04,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:17:59.13,0:18:04.22,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:18:04.32,0:18:09.87,Declare,,0,0,0,,{\an2\fad(500,500)}存储分配与垃圾收集 Dialogue: 0,0:18:12.27,0:18:14.24,Default,,0,0,0,,教授:如同我刚才说过的那样 Dialogue: 0,0:18:14.55,0:18:15.50,Default,,0,0,0,,半导体厂商 Dialogue: 0,0:18:15.82,0:18:17.96,Default,,0,0,0,,所生产的计算机内存 Dialogue: 0,0:18:18.16,0:18:19.00,Default,,0,0,0,,容量是有限的 Dialogue: 0,0:18:19.42,0:18:20.40,Default,,0,0,0,,这的确很可惜 Dialogue: 0,0:18:21.62,0:18:23.35,Default,,0,0,0,,但它也可能不总是这样 Dialogue: 0,0:18:24.03,0:18:25.40,Default,,0,0,0,,简单算一下 Dialogue: 0,0:18:25.44,0:18:28.86,Default,,0,0,0,,你可以看到 如果内存的价格 Dialogue: 0,0:18:28.86,0:18:30.80,Default,,0,0,0,,继续保持当前的趋势的话 Dialogue: 0,0:18:31.22,0:18:33.68,Default,,0,0,0,,如果你执行CONS的时候也只需要1微秒 Dialogue: 0,0:18:34.42,0:18:35.90,Default,,0,0,0,,那么 首先大家知道 Dialogue: 0,0:18:35.90,0:18:37.07,Default,,0,0,0,,一年大约有 Dialogue: 0,0:18:37.10,0:18:38.86,Default,,0,0,0,,PI*10^7秒 Dialogue: 0,0:18:39.45,0:18:41.12,Default,,0,0,0,,那么就有 Dialogue: 0,0:18:41.50,0:18:42.73,Default,,0,0,0,,10^6乘以10^7 Dialogue: 0,0:18:42.73,0:18:43.94,Default,,0,0,0,,也就是10^13 Dialogue: 0,0:18:43.94,0:18:45.50,Default,,0,0,0,,那么在机器的一生中 Dialogue: 0,0:18:45.50,0:18:46.80,Default,,0,0,0,,就能有10^14个CONS Dialogue: 0,0:18:47.52,0:18:49.40,Default,,0,0,0,,如果你的机器上 Dialogue: 0,0:18:49.68,0:18:50.57,Default,,0,0,0,,有10^14个字的内存 Dialogue: 0,0:18:51.20,0:18:52.16,Default,,0,0,0,,你就永远不会用完 Dialogue: 0,0:18:53.04,0:18:53.85,Default,,0,0,0,,这样就会…… Dialogue: 0,0:18:53.95,0:18:55.76,Default,,0,0,0,,这并不是完全没有道理 Dialogue: 0,0:18:56.31,0:18:58.46,Default,,0,0,0,,10^14次方不是个非常大的数字 Dialogue: 0,0:19:01.45,0:19:04.70,Default,,0,0,0,,我不觉得它是个很大的数字 Dialogue: 0,0:19:05.18,0:19:07.39,Default,,0,0,0,,但我喜欢在天文学领域进行比较 Dialogue: 0,0:19:07.93,0:19:11.04,Default,,0,0,0,,距离我们最近的星星 Dialogue: 0,0:19:11.10,0:19:12.45,Default,,0,0,0,,至少有10^18次方厘米远 Dialogue: 0,0:19:12.93,0:19:18.85,Default,,0,0,0,,我担心的是 Dialogue: 0,0:19:19.15,0:19:21.27,Default,,0,0,0,,至少以现在的经济状况 Dialogue: 0,0:19:21.27,0:19:23.57,Default,,0,0,0,,10^14大小的内存很贵 Dialogue: 0,0:19:24.20,0:19:26.62,Default,,0,0,0,,因此我认为我们需要 Dialogue: 0,0:19:26.81,0:19:28.51,Default,,0,0,0,,适应更小的内存 Dialogue: 0,0:19:30.02,0:19:30.59,Default,,0,0,0,,现在 Dialogue: 0,0:19:32.84,0:19:35.07,Default,,0,0,0,,广义地说 我们营造一种无限内存的假象 Dialogue: 0,0:19:35.80,0:19:37.22,Default,,0,0,0,,我们需要整理它 Dialogue: 0,0:19:37.82,0:19:39.68,Default,,0,0,0,,以便在我们需要内存的时候就能获得它 Dialogue: 0,0:19:41.92,0:19:45.55,Default,,0,0,0,,这个想法非常重要 Dialogue: 0,0:19:49.54,0:19:51.97,Default,,0,0,0,,人或者计算机只能存在有限的时间 Dialogue: 0,0:19:52.32,0:19:54.59,Default,,0,0,0,,只能看有限的东西 Dialogue: 0,0:19:55.28,0:19:57.37,Default,,0,0,0,,因此你只需要有限的东西 Dialogue: 0,0:19:58.19,0:19:59.00,Default,,0,0,0,,只要你合理地安排它们 Dialogue: 0,0:19:59.00,0:20:00.38,Default,,0,0,0,,使得不管实际有多少内存 Dialogue: 0,0:20:00.77,0:20:03.46,Default,,0,0,0,,你要求这里有多少 Dialogue: 0,0:20:03.46,0:20:04.74,Default,,0,0,0,,当你去看的时候 Dialogue: 0,0:20:04.74,0:20:06.90,Default,,0,0,0,,总有足够的东西 Dialogue: 0,0:20:06.90,0:20:08.15,Default,,0,0,0,,因此你只需要有限的数量 Dialogue: 0,0:20:08.75,0:20:09.94,Default,,0,0,0,,我们来看看 Dialogue: 0,0:20:11.63,0:20:13.32,Default,,0,0,0,,我们之前提过一个问题 Dialogue: 0,0:20:13.92,0:20:15.45,Default,,0,0,0,,在很多情况下 Dialogue: 0,0:20:15.72,0:20:17.84,Default,,0,0,0,,我们制造了大量 Dialogue: 0,0:20:17.88,0:20:19.16,Default,,0,0,0,,不需要的东西 Dialogue: 0,0:20:19.41,0:20:21.81,Default,,0,0,0,,我们可以进行回收再利用 Dialogue: 0,0:20:22.62,0:20:23.53,Default,,0,0,0,,举个例子 Dialogue: 0,0:20:24.15,0:20:25.79,Default,,0,0,0,,事实上 Dialogue: 0,0:20:25.79,0:20:28.40,Default,,0,0,0,,当我们调用一个过程的时候 Dialogue: 0,0:20:28.40,0:20:30.47,Default,,0,0,0,,都会构建环境结构 Dialogue: 0,0:20:30.47,0:20:32.56,Default,,0,0,0,,我们把它构建在一个环境框架中 Dialogue: 0,0:20:33.14,0:20:34.03,Default,,0,0,0,,这个环境框架 Dialogue: 0,0:20:34.22,0:20:36.07,Default,,0,0,0,,不用存在很长时间 Dialogue: 0,0:20:36.73,0:20:38.69,Default,,0,0,0,,只有在进行过程调用的时候 Dialogue: 0,0:20:39.42,0:20:42.60,Default,,0,0,0,,它的存在才是有用的 Dialogue: 0,0:20:42.85,0:20:45.27,Default,,0,0,0,,如果过程把另一个过程 Dialogue: 0,0:20:45.27,0:20:46.67,Default,,0,0,0,,作为返回值返回 Dialogue: 0,0:20:46.87,0:20:48.52,Default,,0,0,0,,并且这个过程是在它的内部定义的 Dialogue: 0,0:20:48.52,0:20:50.80,Default,,0,0,0,,那么外层过程的 Dialogue: 0,0:20:51.07,0:20:53.39,Default,,0,0,0,,存活时间仍然是 Dialogue: 0,0:20:53.50,0:20:56.12,Default,,0,0,0,,被返回的过程的 Dialogue: 0,0:20:57.02,0:20:57.90,Default,,0,0,0,,存活时间 Dialogue: 0,0:20:58.53,0:20:59.57,Default,,0,0,0,,最终 Dialogue: 0,0:20:59.57,0:21:00.97,Default,,0,0,0,,就会制造很多垃圾 Dialogue: 0,0:21:01.96,0:21:04.10,Default,,0,0,0,,还有其它的途径可以制造垃圾 Dialogue: 0,0:21:05.37,0:21:06.67,Default,,0,0,0,,用户也会制造垃圾 Dialogue: 0,0:21:07.24,0:21:08.07,Default,,0,0,0,,举例来说 Dialogue: 0,0:21:08.07,0:21:10.22,Default,,0,0,0,,用户制造的垃圾像是这样 Dialogue: 0,0:21:10.93,0:21:14.00,Default,,0,0,0,,如果我们写个程序 Dialogue: 0,0:21:14.00,0:21:15.80,Default,,0,0,0,,把两个表连接到一起 Dialogue: 0,0:21:16.05,0:21:18.14,Default,,0,0,0,,唯一的办法是 Dialogue: 0,0:21:18.32,0:21:21.37,Default,,0,0,0,,把第一个表逆序塞到空表中 Dialogue: 0,0:21:21.37,0:21:23.72,Default,,0,0,0,,再把新表逆序塞到第二个表中 Dialogue: 0,0:21:24.70,0:21:26.92,Default,,0,0,0,,这种解法并不是很糟糕 Dialogue: 0,0:21:28.16,0:21:28.85,Default,,0,0,0,,然而 Dialogue: 0,0:21:28.85,0:21:30.09,Default,,0,0,0,,程序所生成的 Dialogue: 0,0:21:30.11,0:21:32.02,Default,,0,0,0,,中间结果 Dialogue: 0,0:21:33.87,0:21:35.57,Default,,0,0,0,,即第一个表的逆序表 Dialogue: 0,0:21:36.70,0:21:38.52,Default,,0,0,0,,在它被复制到第二个表之后 Dialogue: 0,0:21:38.52,0:21:40.56,Default,,0,0,0,,就再也不会被用到了 Dialogue: 0,0:21:41.01,0:21:42.23,Default,,0,0,0,,它是个中间结果 Dialogue: 0,0:21:43.58,0:21:45.43,Default,,0,0,0,,它很难被找到 Dialogue: 0,0:21:46.07,0:21:48.05,Default,,0,0,0,,没有人能访问到它 Dialogue: 0,0:21:48.60,0:21:49.84,Default,,0,0,0,,事实上 它会消失掉 Dialogue: 0,0:21:51.05,0:21:52.90,Default,,0,0,0,,如果我们像这样制造了大量的垃圾 Dialogue: 0,0:21:52.90,0:21:54.20,Default,,0,0,0,,系统也应该允许我们这么干 Dialogue: 0,0:21:54.80,0:21:57.29,Default,,0,0,0,,但应该有某些方法去回收这些垃圾 Dialogue: 0,0:21:58.80,0:22:00.90,Default,,0,0,0,,现在 我要告诉你 Dialogue: 0,0:22:01.70,0:22:03.77,Default,,0,0,0,,一个非常聪明的技巧 Dialogue: 0,0:22:04.32,0:22:07.58,Default,,0,0,0,,一个Lisp系统 Dialogue: 0,0:22:07.95,0:22:11.21,Default,,0,0,0,,通常可以证明一条小定理 Dialogue: 0,0:22:11.29,0:22:13.50,Default,,0,0,0,,也就是 某段内存中的值 Dialogue: 0,0:22:14.72,0:22:16.09,Default,,0,0,0,,之后不再会被用到 Dialogue: 0,0:22:17.41,0:22:19.80,Default,,0,0,0,,它对以后的计算没有任何影响 Dialogue: 0,0:22:21.40,0:22:23.61,Default,,0,0,0,,事实上 这基于一个很简单的想法 Dialogue: 0,0:22:24.72,0:22:28.06,Default,,0,0,0,,我们已经把计算机设计成这个样子 Dialogue: 0,0:22:28.95,0:22:30.67,Default,,0,0,0,,有一些数据通路 Dialogue: 0,0:22:31.87,0:22:33.40,Default,,0,0,0,,其中有寄存器 Dialogue: 0,0:22:34.92,0:22:38.04,Default,,0,0,0,,有EXP、ENV Dialogue: 0,0:22:39.04,0:22:42.19,Default,,0,0,0,,和VAL之类的寄存器 Dialogue: 0,0:22:42.61,0:22:44.02,Default,,0,0,0,,这里有个叫STACK的东西 Dialogue: 0,0:22:46.02,0:22:49.45,Default,,0,0,0,,某种指向一个结构的东西 Dialogue: 0,0:22:49.50,0:22:50.22,Default,,0,0,0,,它是个栈 Dialogue: 0,0:22:50.24,0:22:51.48,Default,,0,0,0,,我们过一会再研究它 Dialogue: 0,0:22:51.64,0:22:53.62,Default,,0,0,0,,这里有一些 Dialogue: 0,0:22:54.38,0:22:56.57,Default,,0,0,0,,有穷状态控制器 Dialogue: 0,0:22:56.73,0:22:59.51,Default,,0,0,0,,控制信号在这之间流通 Dialogue: 0,0:22:59.80,0:23:01.44,Default,,0,0,0,,比如谓词的返回结果 Dialogue: 0,0:23:01.87,0:23:03.13,Default,,0,0,0,,这部分并不太有趣 Dialogue: 0,0:23:03.35,0:23:06.51,Default,,0,0,0,,这里有某种结构化的内存 Dialogue: 0,0:23:06.80,0:23:08.27,Default,,0,0,0,,我刚才给你讲过如何构建它 Dialogue: 0,0:23:08.27,0:23:10.17,Default,,0,0,0,,它可能包括一个栈 Dialogue: 0,0:23:10.46,0:23:11.48,Default,,0,0,0,,我没有告诉你如何把东西 Dialogue: 0,0:23:11.48,0:23:12.43,Default,,0,0,0,,构建成任意形状 Dialogue: 0,0:23:12.56,0:23:13.39,Default,,0,0,0,,只有序对 Dialogue: 0,0:23:13.60,0:23:14.20,Default,,0,0,0,,但事实上 Dialogue: 0,0:23:14.35,0:23:15.44,Default,,0,0,0,,我告诉过你 Dialogue: 0,0:23:15.47,0:23:16.96,Default,,0,0,0,,可以用一张大表来模拟栈 Dialogue: 0,0:23:17.77,0:23:18.85,Default,,0,0,0,,我没准备干这个 Dialogue: 0,0:23:18.85,0:23:20.01,Default,,0,0,0,,这不是个好办法 Dialogue: 0,0:23:20.36,0:23:22.60,Default,,0,0,0,,但是我们可以有这样一个东西 Dialogue: 0,0:23:22.99,0:23:25.28,Default,,0,0,0,,这里有各种数据结构 Dialogue: 0,0:23:25.64,0:23:27.75,Default,,0,0,0,,它们通过有趣的方式互相连接 Dialogue: 0,0:23:30.11,0:23:32.02,Default,,0,0,0,,它们和其它东西连接到一起 Dialogue: 0,0:23:32.56,0:23:33.25,Default,,0,0,0,,以此类推 Dialogue: 0,0:23:33.25,0:23:34.22,Default,,0,0,0,,归根结底 Dialogue: 0,0:23:34.45,0:23:37.19,Default,,0,0,0,,这里的东西是指向这里的指针 Dialogue: 0,0:23:37.19,0:23:38.87,Default,,0,0,0,,寄存器里的指针 Dialogue: 0,0:23:39.40,0:23:41.40,Default,,0,0,0,,指向的是表结构内存中 Dialogue: 0,0:23:41.44,0:23:43.08,Default,,0,0,0,,数据结构 Dialogue: 0,0:23:44.91,0:23:49.80,Default,,0,0,0,,现在 我们的问题是 Dialogue: 0,0:23:51.05,0:23:52.56,Default,,0,0,0,,机器的整个意识 Dialogue: 0,0:23:52.57,0:23:53.92,Default,,0,0,0,,是在寄存器里的 Dialogue: 0,0:23:55.76,0:23:58.51,Default,,0,0,0,,如果这个机器 Dialogue: 0,0:23:58.75,0:24:01.07,Default,,0,0,0,,构建得正确的话 Dialogue: 0,0:24:01.37,0:24:03.41,Default,,0,0,0,,它无法访问表结构内存中任何的东西 Dialogue: 0,0:24:04.57,0:24:07.05,Default,,0,0,0,,除非这个表结构内存中的数据 Dialogue: 0,0:24:08.09,0:24:10.88,Default,,0,0,0,,通过一系列的数据结构 Dialogue: 0,0:24:11.64,0:24:13.06,Default,,0,0,0,,与寄存器相连接 Dialogue: 0,0:24:15.07,0:24:15.98,Default,,0,0,0,,如果它能够 Dialogue: 0,0:24:16.22,0:24:18.31,Default,,0,0,0,,被合法的数据结构选择函数访问到 Dialogue: 0,0:24:19.08,0:24:21.12,Default,,0,0,0,,通过寄存器里保存的指针能够访问它 Dialogue: 0,0:24:22.28,0:24:24.46,Default,,0,0,0,,比如说 数组引用 Dialogue: 0,0:24:24.94,0:24:27.92,Default,,0,0,0,,或者针对序对的引用--CAR或者CDR Dialogue: 0,0:24:29.08,0:24:30.95,Default,,0,0,0,,但我不能随意访问内存中的位置 Dialogue: 0,0:24:30.95,0:24:31.95,Default,,0,0,0,,因为我找不到它 Dialogue: 0,0:24:32.74,0:24:34.90,Default,,0,0,0,,至少在我求值某条表达式的时候 Dialogue: 0,0:24:37.00,0:24:39.16,Default,,0,0,0,,我是不允许去访问那个任意名字的 Dialogue: 0,0:24:41.62,0:24:42.57,Default,,0,0,0,,如果是这样的话 Dialogue: 0,0:24:43.27,0:24:45.07,Default,,0,0,0,,就可以证明一个简单的理论 Dialogue: 0,0:24:47.16,0:24:47.69,Default,,0,0,0,,就是说 Dialogue: 0,0:24:47.90,0:24:50.52,Default,,0,0,0,,如果我从这些寄存器指向的地方开始 Dialogue: 0,0:24:51.16,0:24:52.55,Default,,0,0,0,,递归地遍历 Dialogue: 0,0:24:52.82,0:24:56.15,Default,,0,0,0,,标记选择函数所有能访问到内存 Dialogue: 0,0:24:56.90,0:24:59.40,Default,,0,0,0,,最终就能标记所有能访问的东西 Dialogue: 0,0:25:00.65,0:25:02.69,Default,,0,0,0,,任何未标记的都是垃圾 Dialogue: 0,0:25:02.69,0:25:03.75,Default,,0,0,0,,它们可以被回收 Dialogue: 0,0:25:05.56,0:25:06.20,Default,,0,0,0,,非常简单 Dialogue: 0,0:25:07.20,0:25:09.10,Default,,0,0,0,,不会影响之后的计算 Dialogue: 0,0:25:11.18,0:25:12.84,Default,,0,0,0,,我来举一个 Dialogue: 0,0:25:13.93,0:25:15.75,Default,,0,0,0,,具体的例子 Dialogue: 0,0:25:17.12,0:25:19.37,Default,,0,0,0,,在此之前 需要给我的表结构内存 Dialogue: 0,0:25:19.69,0:25:22.08,Default,,0,0,0,,添加一个叫MARK的标志位 Dialogue: 0,0:25:23.64,0:25:24.89,Default,,0,0,0,,因此 在这里 Dialogue: 0,0:25:25.37,0:25:27.28,Default,,0,0,0,,就有一个表结构内存 Dialogue: 0,0:25:29.08,0:25:30.32,Default,,0,0,0,,这块表内存中 Dialogue: 0,0:25:30.33,0:25:31.33,Default,,0,0,0,,存放了一个表数据结构 Dialogue: 0,0:25:31.33,0:25:33.95,Default,,0,0,0,,我们把这个起始位置 Dialogue: 0,0:25:35.87,0:25:36.62,Default,,0,0,0,,称为“根” Dialogue: 0,0:25:38.59,0:25:40.12,Default,,0,0,0,,不一定只有一个根 Dialogue: 0,0:25:40.12,0:25:41.95,Default,,0,0,0,,与寄存器类似 可以有很多这种东西 Dialogue: 0,0:25:42.67,0:25:43.98,Default,,0,0,0,,但我可以巧妙地安排它们 Dialogue: 0,0:25:44.13,0:25:46.30,Default,,0,0,0,,把所有在旧寄存器里的东西 Dialogue: 0,0:25:46.30,0:25:47.77,Default,,0,0,0,,在何时的时间点 Dialogue: 0,0:25:48.28,0:25:50.46,Default,,0,0,0,,放入到这个根结构中 Dialogue: 0,0:25:50.46,0:25:51.85,Default,,0,0,0,,然后用一个指针指向它 Dialogue: 0,0:25:51.85,0:25:52.67,Default,,0,0,0,,这不是重点 Dialogue: 0,0:25:54.57,0:25:55.63,Default,,0,0,0,,思路就是 Dialogue: 0,0:25:55.64,0:25:56.65,Default,,0,0,0,,我们要不断地进行CONS Dialogue: 0,0:25:56.67,0:25:58.01,Default,,0,0,0,,直到空闲表为空 Dialogue: 0,0:25:58.72,0:25:59.67,Default,,0,0,0,,这样就用尽了所有空间 Dialogue: 0,0:26:00.95,0:26:04.47,Default,,0,0,0,,现在我们要证明这个理论 Dialogue: 0,0:26:04.47,0:26:05.90,Default,,0,0,0,,也就是一部分的内存 Dialogue: 0,0:26:05.95,0:26:06.90,Default,,0,0,0,,已经没有用了 Dialogue: 0,0:26:07.85,0:26:09.15,Default,,0,0,0,,然后我们要回收它 Dialogue: 0,0:26:09.78,0:26:10.87,Default,,0,0,0,,构建一个新的树 Dialogue: 0,0:26:12.19,0:26:14.57,Default,,0,0,0,,这是这些垃圾的标准使用方式 Dialogue: 0,0:26:17.09,0:26:18.64,Default,,0,0,0,,那么我们要做什么呢? Dialogue: 0,0:26:18.84,0:26:20.78,Default,,0,0,0,,从P5这个位置开始 Dialogue: 0,0:26:20.89,0:26:24.27,Default,,0,0,0,,存了一些数据结构 Dialogue: 0,0:26:25.15,0:26:26.75,Default,,0,0,0,,说错了--是从1开始 Dialogue: 0,0:26:27.27,0:26:28.51,Default,,0,0,0,,事实上 Dialogue: 0,0:26:28.89,0:26:32.20,Default,,0,0,0,,它的CAR部分存放在P5这个位置 Dialogue: 0,0:26:32.27,0:26:33.58,Default,,0,0,0,,而CDR部分存在在P2这个位置 Dialogue: 0,0:26:33.98,0:26:35.64,Default,,0,0,0,,最开始 所有的标记都是0 Dialogue: 0,0:26:36.70,0:26:39.00,Default,,0,0,0,,我们要开始标记了 Dialogue: 0,0:26:39.92,0:26:40.52,Default,,0,0,0,,好 Dialogue: 0,0:26:42.54,0:26:44.27,Default,,0,0,0,,例如 Dialogue: 0,0:26:44.47,0:26:46.95,Default,,0,0,0,,因为我可以从根访问到位置P1 Dialogue: 0,0:26:46.95,0:26:47.82,Default,,0,0,0,,我就标记一下 Dialogue: 0,0:26:48.39,0:26:49.17,Default,,0,0,0,,我来标一下 Dialogue: 0,0:26:50.96,0:26:51.45,Default,,0,0,0,,好了 Dialogue: 0,0:26:52.22,0:26:52.94,Default,,0,0,0,,这个被标记了 Dialogue: 0,0:26:54.41,0:26:57.51,Default,,0,0,0,,因为它指向位置P5 Dialogue: 0,0:26:57.64,0:26:58.64,Default,,0,0,0,,所以我来到了5号格子 Dialogue: 0,0:26:59.02,0:27:00.72,Default,,0,0,0,,然后 我要标记这个 Dialogue: 0,0:27:01.45,0:27:01.76,Default,,0,0,0,,标好了 Dialogue: 0,0:27:01.76,0:27:02.60,Default,,0,0,0,,这个笔真好用 Dialogue: 0,0:27:02.90,0:27:05.10,Default,,0,0,0,,但是5号位置的CAR部分是一个数字 Dialogue: 0,0:27:05.27,0:27:06.65,Default,,0,0,0,,我对标记数字不感兴趣 Dialogue: 0,0:27:06.91,0:27:08.17,Default,,0,0,0,,但它的CDR部分是P7 Dialogue: 0,0:27:08.70,0:27:09.75,Default,,0,0,0,,所以我可以标记它 Dialogue: 0,0:27:10.45,0:27:10.81,Default,,0,0,0,,又标好了 Dialogue: 0,0:27:11.80,0:27:13.40,Default,,0,0,0,,P7的CDR部分是空表 Dialogue: 0,0:27:13.67,0:27:15.10,Default,,0,0,0,,而它唯一所引用的元素则是 Dialogue: 0,0:27:15.59,0:27:17.12,Default,,0,0,0,,它的CAR部分是个数字 Dialogue: 0,0:27:17.12,0:27:17.85,Default,,0,0,0,,我对它不感兴趣 Dialogue: 0,0:27:19.49,0:27:20.50,Default,,0,0,0,,让我们回到这里 Dialogue: 0,0:27:20.50,0:27:21.65,Default,,0,0,0,,我忘记了一些事情 Dialogue: 0,0:27:21.65,0:27:22.17,Default,,0,0,0,,P2 Dialogue: 0,0:27:22.84,0:27:24.85,Default,,0,0,0,,换句话说 如果我看1号格子 Dialogue: 0,0:27:25.42,0:27:29.45,Default,,0,0,0,,1号格子的CDR部分指向P2 Dialogue: 0,0:27:30.37,0:27:31.30,Default,,0,0,0,,一个指向P2的引用 Dialogue: 0,0:27:32.01,0:27:34.97,Default,,0,0,0,,这意味着我应该标记P2 Dialogue: 0,0:27:35.70,0:27:36.27,Default,,0,0,0,,好了 Dialogue: 0,0:27:37.14,0:27:38.89,Default,,0,0,0,,P2包含了了一个到P4的引用 Dialogue: 0,0:27:39.13,0:27:40.27,Default,,0,0,0,,而P2的CAR部分是个数字 Dialogue: 0,0:27:40.27,0:27:41.20,Default,,0,0,0,,我对它不感兴趣 Dialogue: 0,0:27:41.47,0:27:42.60,Default,,0,0,0,,所以我要标记P4 Dialogue: 0,0:27:43.78,0:27:46.10,Default,,0,0,0,,P4的CAR部分引用了P7 Dialogue: 0,0:27:46.75,0:27:48.17,Default,,0,0,0,,它的CDR是空的 Dialogue: 0,0:27:48.47,0:27:49.57,Default,,0,0,0,,但由于我已经标记过P7了 Dialogue: 0,0:27:49.57,0:27:50.75,Default,,0,0,0,,就不再次标记它了 Dialogue: 0,0:27:51.40,0:27:53.05,Default,,0,0,0,,这就是这个地方 Dialogue: 0,0:27:53.07,0:27:53.87,Default,,0,0,0,,所能访问的所有单元 Dialogue: 0,0:27:55.00,0:27:56.57,Default,,0,0,0,,很简单的递归标记算法 Dialogue: 0,0:27:58.71,0:28:01.79,Default,,0,0,0,,这个算法有一些不足的地方 Dialogue: 0,0:28:01.90,0:28:04.02,Default,,0,0,0,,我们稍后会说 Dialogue: 0,0:28:04.92,0:28:06.16,Default,,0,0,0,,但基本上你能看到 Dialogue: 0,0:28:06.19,0:28:07.85,Default,,0,0,0,,所有没被标记的地方 Dialogue: 0,0:28:09.62,0:28:11.50,Default,,0,0,0,,都是无用的 Dialogue: 0,0:28:11.50,0:28:12.41,Default,,0,0,0,,可以回收 Dialogue: 0,0:28:14.25,0:28:15.75,Default,,0,0,0,,所以下一步就是 Dialogue: 0,0:28:15.75,0:28:17.05,Default,,0,0,0,,扫描整个内存 Dialogue: 0,0:28:17.94,0:28:20.35,Default,,0,0,0,,寻找未被标记的格子 Dialogue: 0,0:28:21.18,0:28:22.45,Default,,0,0,0,,每当遇到一个已标记的格子 Dialogue: 0,0:28:22.45,0:28:23.22,Default,,0,0,0,,就把标记去掉 Dialogue: 0,0:28:23.22,0:28:24.86,Default,,0,0,0,,每当遇到未标记的格子时 Dialogue: 0,0:28:25.07,0:28:27.82,Default,,0,0,0,,我就把它连接到我的空闲表中 Dialogue: 0,0:28:28.77,0:28:30.30,Default,,0,0,0,,传统而且非常简单的算法 Dialogue: 0,0:28:32.12,0:28:33.10,Default,,0,0,0,,我们来看看 Dialogue: 0,0:28:33.84,0:28:34.77,Default,,0,0,0,,它很简单吗? Dialogue: 0,0:28:34.77,0:28:35.42,Default,,0,0,0,,是的 Dialogue: 0,0:28:35.57,0:28:37.79,Default,,0,0,0,,我不会深入代码细节 Dialogue: 0,0:28:38.00,0:28:39.65,Default,,0,0,0,,只是想给你看看它有多长 Dialogue: 0,0:28:40.09,0:28:41.10,Default,,0,0,0,,看这个标记阶段 Dialogue: 0,0:28:41.72,0:28:43.98,Default,,0,0,0,,这是标记阶段的第一部分 Dialogue: 0,0:28:45.06,0:28:46.00,Default,,0,0,0,,我们找到根 Dialogue: 0,0:28:46.32,0:28:47.52,Default,,0,0,0,,我们要 Dialogue: 0,0:28:47.67,0:28:51.05,Default,,0,0,0,,对它进行递归过程调用 Dialogue: 0,0:28:52.38,0:28:54.47,Default,,0,0,0,,当我们完成标记之后 Dialogue: 0,0:28:54.77,0:28:56.95,Default,,0,0,0,,就从这里开始清除 Dialogue: 0,0:28:57.38,0:28:59.79,Default,,0,0,0,,然后我们将执行一些指令 Dialogue: 0,0:28:59.80,0:29:01.36,Default,,0,0,0,,来检查这些标记 Dialogue: 0,0:29:01.39,0:29:03.07,Default,,0,0,0,,或者更改这些标记 Dialogue: 0,0:29:03.07,0:29:04.90,Default,,0,0,0,,按照我刚才讲的那个算法进行 Dialogue: 0,0:29:05.23,0:29:06.47,Default,,0,0,0,,代码在这里 Dialogue: 0,0:29:06.47,0:29:07.65,Default,,0,0,0,,你需要标记它们的CAR Dialogue: 0,0:29:07.87,0:29:10.21,Default,,0,0,0,,也需要标记它们的CDR Dialogue: 0,0:29:10.66,0:29:12.10,Default,,0,0,0,,这就是整个标记阶段 Dialogue: 0,0:29:14.37,0:29:16.16,Default,,0,0,0,,我给你讲个关于它的小故事 Dialogue: 0,0:29:16.59,0:29:19.37,Default,,0,0,0,,古董货DEC PDP-6计算机 Dialogue: 0,0:29:20.93,0:29:22.09,Default,,0,0,0,,它上面的 Dialogue: 0,0:29:22.35,0:29:24.85,Default,,0,0,0,,标记-清除垃圾回收系统就是这么写的 Dialogue: 0,0:29:26.91,0:29:28.40,Default,,0,0,0,,程序很短 Dialogue: 0,0:29:29.25,0:29:31.60,Default,,0,0,0,,以至于它需要的数据 Dialogue: 0,0:29:32.20,0:29:34.87,Default,,0,0,0,,以及用来操作内存的所需的寄存器 Dialogue: 0,0:29:36.16,0:29:38.14,Default,,0,0,0,,都能够放入到计算机的 Dialogue: 0,0:29:38.16,0:29:38.97,Default,,0,0,0,,16个快速寄存器中 Dialogue: 0,0:29:39.28,0:29:39.80,Default,,0,0,0,,整个程序 Dialogue: 0,0:29:40.01,0:29:42.01,Default,,0,0,0,,你可以在快速寄存器里执行指令 Dialogue: 0,0:29:43.17,0:29:44.83,Default,,0,0,0,,所以这是个非常小的程序 Dialogue: 0,0:29:45.85,0:29:46.88,Default,,0,0,0,,它跑得飞快 Dialogue: 0,0:29:48.87,0:29:51.30,Default,,0,0,0,,然而很不幸 Dialogue: 0,0:29:51.61,0:29:54.02,Default,,0,0,0,,因为这个程序是递归的 Dialogue: 0,0:29:54.80,0:29:57.55,Default,,0,0,0,,因为你需要先做某件事儿 Dialogue: 0,0:29:57.55,0:29:58.99,Default,,0,0,0,,然后再去做另外一件事儿 Dialogue: 0,0:29:59.21,0:30:00.88,Default,,0,0,0,,你得先处理CAR 再处理CDR Dialogue: 0,0:30:01.15,0:30:02.75,Default,,0,0,0,,这就需要辅助内存 Dialogue: 0,0:30:03.41,0:30:05.23,Default,,0,0,0,,所以Lisp系统 Dialogue: 0,0:30:05.44,0:30:07.42,Default,,0,0,0,,需要一个栈来进行标记 Dialogue: 0,0:30:08.26,0:30:11.05,Default,,0,0,0,,Lisp系统通过这样的方式 Dialogue: 0,0:30:11.57,0:30:14.16,Default,,0,0,0,,限制了你在数据结构上 Dialogue: 0,0:30:14.42,0:30:17.37,Default,,0,0,0,,进行CAR或者CDR递归的深度 Dialogue: 0,0:30:17.81,0:30:19.35,Default,,0,0,0,,这并不太靠谱 Dialogue: 0,0:30:19.93,0:30:20.60,Default,,0,0,0,,另外一方面 Dialogue: 0,0:30:20.64,0:30:22.12,Default,,0,0,0,,当它足够大的时候你不会发现 Dialogue: 0,0:30:23.18,0:30:25.13,Default,,0,0,0,,例如 这样的情况 Dialogue: 0,0:30:25.55,0:30:28.17,Default,,0,0,0,,发生在大多数MacLisp系统上 Dialogue: 0,0:30:28.69,0:30:29.88,Default,,0,0,0,,在它上面运行的Macsyma Dialogue: 0,0:30:29.96,0:30:31.10,Default,,0,0,0,,允许你处理 Dialogue: 0,0:30:31.10,0:30:32.72,Default,,0,0,0,,有成千上万个元素的表达式 Dialogue: 0,0:30:33.56,0:30:36.02,Default,,0,0,0,,有很多代数式有大量的项 Dialogue: 0,0:30:36.82,0:30:38.10,Default,,0,0,0,,这没什么问题 Dialogue: 0,0:30:39.49,0:30:40.82,Default,,0,0,0,,垃圾回收器能正常工作 Dialogue: 0,0:30:42.19,0:30:42.92,Default,,0,0,0,,另一方面 Dialogue: 0,0:30:42.92,0:30:45.37,Default,,0,0,0,,这个算法有个很精妙的修改版 Dialogue: 0,0:30:45.37,0:30:46.47,Default,,0,0,0,,但我不会去讲 Dialogue: 0,0:30:46.80,0:30:48.22,Default,,0,0,0,,它是由Peter Deutsch Dialogue: 0,0:30:48.64,0:30:51.82,Default,,0,0,0,,来自IBM的Herb Schorr Dialogue: 0,0:30:51.87,0:30:53.52,Default,,0,0,0,,和我不太认识的Waite所提出 Dialogue: 0,0:30:54.01,0:30:56.51,Default,,0,0,0,,这个算法 Dialogue: 0,0:30:56.67,0:30:57.79,Default,,0,0,0,,可以不使用 Dialogue: 0,0:30:57.84,0:30:59.55,Default,,0,0,0,,额外的辅助内存 Dialogue: 0,0:31:00.50,0:31:02.80,Default,,0,0,0,,只需要在遍历整个数据结构的时候 Dialogue: 0,0:31:02.97,0:31:05.52,Default,,0,0,0,,记住你是从哪里来的并反转指针 Dialogue: 0,0:31:05.52,0:31:07.52,Default,,0,0,0,,回溯的时候 再去反转这个指针 Dialogue: 0,0:31:07.79,0:31:08.99,Default,,0,0,0,,这是个很取巧的算法 Dialogue: 0,0:31:09.13,0:31:10.24,Default,,0,0,0,,你第一次写它的时候 Dialogue: 0,0:31:10.25,0:31:11.71,Default,,0,0,0,,事实上 你前三次写它的时候 Dialogue: 0,0:31:11.71,0:31:12.72,Default,,0,0,0,,都会遇到严重的BUG Dialogue: 0,0:31:14.35,0:31:16.72,Default,,0,0,0,,也可能奇慢无比 Dialogue: 0,0:31:16.72,0:31:17.67,Default,,0,0,0,,因为这个算法太复杂了 Dialogue: 0,0:31:18.11,0:31:20.30,Default,,0,0,0,,它用了大概六倍的内存引用 Dialogue: 0,0:31:20.85,0:31:23.22,Default,,0,0,0,,来完成我们刚才讨论的任务 Dialogue: 0,0:31:24.58,0:31:27.07,Default,,0,0,0,,一旦我完成了标记阶段 Dialogue: 0,0:31:27.50,0:31:30.12,Default,,0,0,0,,我们就面临着这样的状况 Dialogue: 0,0:31:30.17,0:31:31.26,Default,,0,0,0,,请看 Dialogue: 0,0:31:31.51,0:31:34.03,Default,,0,0,0,,这里完成了标记工作 Dialogue: 0,0:31:34.08,0:31:35.00,Default,,0,0,0,,和我刚才描述的一样 Dialogue: 0,0:31:35.59,0:31:37.33,Default,,0,0,0,,现在我们要进行清除阶段 Dialogue: 0,0:31:37.60,0:31:39.32,Default,,0,0,0,,我刚才已经讲过如何清除了 Dialogue: 0,0:31:39.82,0:31:42.34,Default,,0,0,0,,我要从内存的一端开始 Dialogue: 0,0:31:42.34,0:31:43.34,Default,,0,0,0,,哪一端都可以 Dialogue: 0,0:31:43.62,0:31:46.17,Default,,0,0,0,,扫描内存中的每个格子 Dialogue: 0,0:31:47.17,0:31:48.67,Default,,0,0,0,,在扫描的同时 Dialogue: 0,0:31:49.20,0:31:50.97,Default,,0,0,0,,如果是空闲内存 Dialogue: 0,0:31:50.99,0:31:52.84,Default,,0,0,0,,就把它们连接到空闲表中 Dialogue: 0,0:31:53.15,0:31:54.05,Default,,0,0,0,,如果它们不是空闲内存 Dialogue: 0,0:31:54.05,0:31:56.07,Default,,0,0,0,,我就把它们的标记清除掉 Dialogue: 0,0:31:57.50,0:31:58.57,Default,,0,0,0,,事实上 Dialogue: 0,0:31:58.70,0:32:00.46,Default,,0,0,0,,最终的程序并不很复杂 Dialogue: 0,0:32:00.46,0:32:02.22,Default,,0,0,0,,它只是变长了一些 Dialogue: 0,0:32:02.78,0:32:04.17,Default,,0,0,0,,这是第一部分 Dialogue: 0,0:32:04.82,0:32:06.71,Default,,0,0,0,,它从内存的顶端向下遍历 Dialogue: 0,0:32:06.71,0:32:09.58,Default,,0,0,0,,我不期望你现在就搞懂它 Dialogue: 0,0:32:09.58,0:32:10.55,Default,,0,0,0,,它挺简单的 Dialogue: 0,0:32:11.03,0:32:12.52,Default,,0,0,0,,这是个非常简单的算法 Dialogue: 0,0:32:13.07,0:32:15.97,Default,,0,0,0,,其中的一段代码像是这样 Dialogue: 0,0:32:15.97,0:32:17.37,Default,,0,0,0,,非常显而易见 Dialogue: 0,0:32:18.60,0:32:20.08,Default,,0,0,0,,在清理结束后 Dialogue: 0,0:32:20.30,0:32:21.77,Default,,0,0,0,,我们就得到了像这样的结果 Dialogue: 0,0:32:25.33,0:32:26.54,Default,,0,0,0,,这种标记-清除算法 Dialogue: 0,0:32:26.56,0:32:28.20,Default,,0,0,0,,有一些缺点 Dialogue: 0,0:32:29.59,0:32:30.35,Default,,0,0,0,,最严重的一个是 Dialogue: 0,0:32:31.45,0:32:33.20,Default,,0,0,0,,最严重的缺点是 Dialogue: 0,0:32:33.20,0:32:34.97,Default,,0,0,0,,当你的内存越来越大 Dialogue: 0,0:32:36.82,0:32:38.87,Default,,0,0,0,,地址空间也就会越来越大 Dialogue: 0,0:32:38.87,0:32:40.80,Default,,0,0,0,,你想用它存更多东西 Dialogue: 0,0:32:41.37,0:32:44.52,Default,,0,0,0,,那么扫描整个内存就会非常耗时 Dialogue: 0,0:32:46.36,0:32:47.39,Default,,0,0,0,,你真正想做的是 Dialogue: 0,0:32:47.40,0:32:48.68,Default,,0,0,0,,只扫描有用的东西 Dialogue: 0,0:32:50.49,0:32:51.55,Default,,0,0,0,,这样就会好一点 Dialogue: 0,0:32:52.07,0:32:53.90,Default,,0,0,0,,如果你意识到 Dialogue: 0,0:32:54.48,0:32:57.72,Default,,0,0,0,,哪些东西已知是有用的 Dialogue: 0,0:32:58.28,0:33:00.37,Default,,0,0,0,,你就没必要去多次检查它 Dialogue: 0,0:33:00.37,0:33:01.20,Default,,0,0,0,,或者不用经常去检查它 Dialogue: 0,0:33:01.55,0:33:04.32,Default,,0,0,0,,对于那些你不太确定的 Dialogue: 0,0:33:05.00,0:33:06.22,Default,,0,0,0,,你可以在每次需要的时候 Dialogue: 0,0:33:07.10,0:33:08.75,Default,,0,0,0,,进行仔细检查 Dialogue: 0,0:33:09.93,0:33:10.85,Default,,0,0,0,,也就是垃圾收集的时候 Dialogue: 0,0:33:11.91,0:33:13.74,Default,,0,0,0,,这些算法 Dialogue: 0,0:33:13.76,0:33:15.10,Default,,0,0,0,,就是用了这样的方法 Dialogue: 0,0:33:15.66,0:33:18.16,Default,,0,0,0,,我要介绍一个著名的古老算法 Dialogue: 0,0:33:18.28,0:33:19.47,Default,,0,0,0,,这种算法允许你 Dialogue: 0,0:33:19.50,0:33:21.37,Default,,0,0,0,,只检查内存中已知是有用的部分 Dialogue: 0,0:33:23.12,0:33:23.85,Default,,0,0,0,,这让它成为了 Dialogue: 0,0:33:23.87,0:33:25.29,Default,,0,0,0,,目前已知最快的垃圾收集算法 Dialogue: 0,0:33:26.31,0:33:29.45,Default,,0,0,0,,它就是 Minsky-Fenichel-Yochelson 垃圾收集算法 Dialogue: 0,0:33:30.40,0:33:33.18,Default,,0,0,0,,它是由Minsky Dialogue: 0,0:33:33.20,0:33:36.06,Default,,0,0,0,,在1960、61年左右发明的 Dialogue: 0,0:33:36.52,0:33:40.48,Default,,0,0,0,,当时是给RLE PDP-1 Lisp用的 Dialogue: 0,0:33:40.51,0:33:43.44,Default,,0,0,0,,这个机器只有4096个字的线性内存 Dialogue: 0,0:33:45.79,0:33:46.76,Default,,0,0,0,,还有个磁鼓 Dialogue: 0,0:33:48.48,0:33:49.39,Default,,0,0,0,,为了能够 Dialogue: 0,0:33:50.03,0:33:51.87,Default,,0,0,0,,在这种恶劣的条件下进行垃圾收集 Dialogue: 0,0:33:53.05,0:33:54.35,Default,,0,0,0,,Minsky意识到 Dialogue: 0,0:33:54.38,0:33:55.62,Default,,0,0,0,,达成目的最容易的方法是 Dialogue: 0,0:33:56.20,0:33:58.47,Default,,0,0,0,,在扫描内存的同时 Dialogue: 0,0:33:58.47,0:34:00.60,Default,,0,0,0,,遍历那些好的数据结构 Dialogue: 0,0:34:01.57,0:34:03.52,Default,,0,0,0,,把它复制到磁鼓中 Dialogue: 0,0:34:04.70,0:34:05.47,Default,,0,0,0,,压缩一下 Dialogue: 0,0:34:06.35,0:34:08.86,Default,,0,0,0,,之后把它们复制出来 Dialogue: 0,0:34:09.12,0:34:10.90,Default,,0,0,0,,并把它们交换回内存里 Dialogue: 0,0:34:12.30,0:34:13.68,Default,,0,0,0,,不管是使用的是磁鼓 Dialogue: 0,0:34:13.72,0:34:14.71,Default,,0,0,0,,或者其它的内存 Dialogue: 0,0:34:14.71,0:34:16.42,Default,,0,0,0,,这都不重要 Dialogue: 0,0:34:17.03,0:34:17.42,Default,,0,0,0,,事实上 Dialogue: 0,0:34:17.44,0:34:19.60,Default,,0,0,0,,我觉得现在应该没人用磁鼓了吧 Dialogue: 0,0:34:20.35,0:34:23.77,Default,,0,0,0,,但这个算法基本上 Dialogue: 0,0:34:24.03,0:34:25.42,Default,,0,0,0,,要依赖于 Dialogue: 0,0:34:25.42,0:34:27.42,Default,,0,0,0,,大约两倍于 Dialogue: 0,0:34:27.48,0:34:28.57,Default,,0,0,0,,你实际使用的内存 Dialogue: 0,0:34:30.27,0:34:32.96,Default,,0,0,0,,最开始的情况是 Dialogue: 0,0:34:33.12,0:34:36.60,Default,,0,0,0,,有用的数据和垃圾混在了一起 Dialogue: 0,0:34:37.11,0:34:38.97,Default,,0,0,0,,它被称为FROMSPACE Dialogue: 0,0:34:45.17,0:34:47.05,Default,,0,0,0,,这是CRUD的混合 Dialogue: 0,0:34:47.87,0:34:49.79,Default,,0,0,0,,有些是有用的 有些没有用 Dialogue: 0,0:34:52.00,0:34:53.85,Default,,0,0,0,,现在还有另外一块空间 Dialogue: 0,0:34:54.17,0:34:55.61,Default,,0,0,0,,它需要足够大 Dialogue: 0,0:34:55.77,0:34:57.00,Default,,0,0,0,,这个地方叫TOSPACE Dialogue: 0,0:34:57.12,0:34:58.24,Default,,0,0,0,,要把东西复制进去 Dialogue: 0,0:35:01.59,0:35:02.60,Default,,0,0,0,,接下来会发生的是 Dialogue: 0,0:35:02.60,0:35:04.06,Default,,0,0,0,,我不会深入细节 Dialogue: 0,0:35:04.16,0:35:07.07,Default,,0,0,0,,书上写得很清楚了 Dialogue: 0,0:35:07.59,0:35:10.40,Default,,0,0,0,,这里有一个根节点 Dialogue: 0,0:35:11.03,0:35:14.30,Default,,0,0,0,,你从根节点开始 Dialogue: 0,0:35:14.60,0:35:16.42,Default,,0,0,0,,复制你看到的第一个东西 Dialogue: 0,0:35:17.83,0:35:19.37,Default,,0,0,0,,根指针指向的第一个东西 Dialogue: 0,0:35:19.75,0:35:21.31,Default,,0,0,0,,复制到TOSPACE的头部 Dialogue: 0,0:35:22.81,0:35:24.12,Default,,0,0,0,,这些东西一般是一个序对 Dialogue: 0,0:35:24.16,0:35:25.60,Default,,0,0,0,,或者是类似的数据结构 Dialogue: 0,0:35:27.56,0:35:30.19,Default,,0,0,0,,然后在那里留下 Dialogue: 0,0:35:30.38,0:35:31.56,Default,,0,0,0,,一颗“破碎的心” Dialogue: 0,0:35:31.77,0:35:35.74,Default,,0,0,0,,表示我把东西从这里移动到了这里 Dialogue: 0,0:35:35.74,0:35:37.05,Default,,0,0,0,,指示了移动的目的地 Dialogue: 0,0:35:37.80,0:35:39.65,Default,,0,0,0,,叫作破碎的心是因为 Dialogue: 0,0:35:39.65,0:35:40.78,Default,,0,0,0,,我的一个朋友 Dialogue: 0,0:35:40.78,0:35:43.39,Default,,0,0,0,,在1966年实现了这个算法 Dialogue: 0,0:35:43.82,0:35:45.26,Default,,0,0,0,,而他是个文艺青年 Dialogue: 0,0:35:45.26,0:35:46.76,Default,,0,0,0,,就取名叫“破碎的心” Dialogue: 0,0:35:49.58,0:35:50.54,Default,,0,0,0,,不论如何 Dialogue: 0,0:35:51.15,0:35:52.72,Default,,0,0,0,,接下来要做的是 Dialogue: 0,0:35:52.94,0:35:55.00,Default,,0,0,0,,FREE指针现在指向这里 Dialogue: 0,0:35:55.17,0:35:56.38,Default,,0,0,0,,然后开始扫描 Dialogue: 0,0:35:56.88,0:35:59.68,Default,,0,0,0,,扫描这个刚复制过来的数据结构 Dialogue: 0,0:36:00.55,0:36:02.19,Default,,0,0,0,,每当你遇到其中的指针 Dialogue: 0,0:36:02.19,0:36:03.92,Default,,0,0,0,,你把它当作是这里的根指针 Dialogue: 0,0:36:04.00,0:36:04.59,Default,,0,0,0,,哦 不好意思 Dialogue: 0,0:36:04.60,0:36:05.69,Default,,0,0,0,,我们还需要做的是 Dialogue: 0,0:36:05.71,0:36:07.08,Default,,0,0,0,,你将根指针移动到这里 Dialogue: 0,0:36:09.22,0:36:10.17,Default,,0,0,0,,因此在扫描的过程中 Dialogue: 0,0:36:10.17,0:36:10.99,Default,,0,0,0,,把遇到的每个指针 Dialogue: 0,0:36:11.00,0:36:12.41,Default,,0,0,0,,都可以当作是ROOT指针 Dialogue: 0,0:36:14.11,0:36:15.45,Default,,0,0,0,,如果你遇到了某个指针 Dialogue: 0,0:36:15.45,0:36:17.40,Default,,0,0,0,,指向了这里的某个地方 Dialogue: 0,0:36:18.51,0:36:19.92,Default,,0,0,0,,它指向的东西 Dialogue: 0,0:36:19.93,0:36:20.99,Default,,0,0,0,,你复制过了吗? Dialogue: 0,0:36:21.78,0:36:22.87,Default,,0,0,0,,这里是“破碎的心”吗 Dialogue: 0,0:36:23.88,0:36:24.84,Default,,0,0,0,,如果那里是破碎的心 Dialogue: 0,0:36:24.84,0:36:26.11,Default,,0,0,0,,就说明那里的东西复制过了 Dialogue: 0,0:36:26.20,0:36:27.34,Default,,0,0,0,,只需要用破碎的心所指向的地址 Dialogue: 0,0:36:27.36,0:36:28.75,Default,,0,0,0,,来替换它指针即可 Dialogue: 0,0:36:29.82,0:36:32.03,Default,,0,0,0,,如果它还没被复制 Dialogue: 0,0:36:32.12,0:36:34.08,Default,,0,0,0,,你把它复制到这里 Dialogue: 0,0:36:34.43,0:36:35.95,Default,,0,0,0,,把FREE指针移到这里 Dialogue: 0,0:36:37.05,0:36:40.60,Default,,0,0,0,,然后在那里放置一颗破碎的心 Dialogue: 0,0:36:41.05,0:36:41.80,Default,,0,0,0,,继续扫描 Dialogue: 0,0:36:43.67,0:36:46.40,Default,,0,0,0,,最终SCAN指针追上了FREE指针 Dialogue: 0,0:36:46.82,0:36:48.52,Default,,0,0,0,,内存里的所有东西都被复制了 Dialogue: 0,0:36:50.14,0:36:51.04,Default,,0,0,0,,这样这里就剩下了 Dialogue: 0,0:36:51.05,0:36:51.95,Default,,0,0,0,,大量的空闲空间 Dialogue: 0,0:36:51.96,0:36:53.28,Default,,0,0,0,,如果你需要的话 Dialogue: 0,0:36:53.31,0:36:54.47,Default,,0,0,0,,你可以把它组织为空闲表 Dialogue: 0,0:36:54.47,0:36:56.27,Default,,0,0,0,,但这种系统通常不这么来做 Dialogue: 0,0:36:56.27,0:36:59.15,Default,,0,0,0,,这类系统中 内存是顺序分配的 Dialogue: 0,0:37:00.91,0:37:02.48,Default,,0,0,0,,这是个非常 非常好的算法 Dialogue: 0,0:37:02.97,0:37:04.57,Default,,0,0,0,,你们现在使用的Scheme系统中 Dialogue: 0,0:37:04.67,0:37:05.97,Default,,0,0,0,,就使用了这种算法 Dialogue: 0,0:37:06.79,0:37:09.47,Default,,0,0,0,,它应该是-- Dialogue: 0,0:37:09.47,0:37:10.86,Default,,0,0,0,,我相信还没有人发现 Dialogue: 0,0:37:10.89,0:37:12.12,Default,,0,0,0,,比它跑得更快的算法 Dialogue: 0,0:37:12.40,0:37:14.85,Default,,0,0,0,,有一些对这个算法的简单修改 Dialogue: 0,0:37:14.85,0:37:16.77,Default,,0,0,0,,由Henry Baker发明 Dialogue: 0,0:37:17.17,0:37:20.31,Default,,0,0,0,,它让你能实时运行这个算法 Dialogue: 0,0:37:20.31,0:37:21.92,Default,,0,0,0,,也就是说进行回收时不需要暂停程序 Dialogue: 0,0:37:22.14,0:37:24.33,Default,,0,0,0,,你能够让机器运行时 Dialogue: 0,0:37:24.36,0:37:26.17,Default,,0,0,0,,进行的各种CONS操作 Dialogue: 0,0:37:26.32,0:37:28.40,Default,,0,0,0,,与垃圾回收过程交错进行 Dialogue: 0,0:37:28.85,0:37:31.20,Default,,0,0,0,,垃圾回收器是分散的 Dialogue: 0,0:37:31.20,0:37:32.19,Default,,0,0,0,,机器不需要停下来 Dialogue: 0,0:37:32.41,0:37:33.47,Default,,0,0,0,,再让垃圾回收开始运作 Dialogue: 0,0:37:34.64,0:37:37.87,Default,,0,0,0,,当然 在使用虚拟内存的机器中 Dialogue: 0,0:37:38.90,0:37:41.20,Default,,0,0,0,,有很多内存无法访问 Dialogue: 0,0:37:41.50,0:37:43.60,Default,,0,0,0,,这会让整个过程变得耗时 Dialogue: 0,0:37:44.28,0:37:46.43,Default,,0,0,0,,有很多人尝试 Dialogue: 0,0:37:47.16,0:37:48.65,Default,,0,0,0,,将它改进得更好 Dialogue: 0,0:37:49.19,0:37:51.15,Default,,0,0,0,,对于感兴趣的同学 Dialogue: 0,0:37:51.16,0:37:52.41,Default,,0,0,0,,这有一篇论文 Dialogue: 0,0:37:52.64,0:37:54.27,Default,,0,0,0,,作者是Moon等人 Dialogue: 0,0:37:54.65,0:37:56.89,Default,,0,0,0,,这篇论文描述了 Dialogue: 0,0:37:56.92,0:37:59.44,Default,,0,0,0,,增量式Minsky-Fenichel-Yochelson算法 Dialogue: 0,0:37:59.51,0:38:01.20,Default,,0,0,0,,和Baker算法的修改 Dialogue: 0,0:38:01.42,0:38:06.54,Default,,0,0,0,,让使用虚拟内存的系统更加高效 Dialogue: 0,0:38:08.27,0:38:12.32,Default,,0,0,0,,现在最后一个谜团也解开了 Dialogue: 0,0:38:12.84,0:38:14.09,Default,,0,0,0,,有什么疑惑吗? Dialogue: 0,0:38:19.78,0:38:19.95,Default,,0,0,0,,请讲 Dialogue: 0,0:38:20.60,0:38:23.58,Default,,0,0,0,,学生:我在楼上的系统上 Dialogue: 0,0:38:23.64,0:38:25.05,Default,,0,0,0,,你们运行垃圾收集器的时候 Dialogue: 0,0:38:25.93,0:38:27.88,Default,,0,0,0,,它看起来跑得飞快 Dialogue: 0,0:38:27.96,0:38:28.40,Default,,0,0,0,,教授:是的 Dialogue: 0,0:38:28.49,0:38:29.52,Default,,0,0,0,,学生:整个过程花费了-- Dialogue: 0,0:38:30.11,0:38:31.88,Default,,0,0,0,,它真的扫描了整个内存吗? Dialogue: 0,0:38:31.88,0:38:32.22,Default,,0,0,0,,教授:没有 Dialogue: 0,0:38:32.25,0:38:34.11,Default,,0,0,0,,它只扫描了那些需要的 Dialogue: 0,0:38:34.33,0:38:35.63,Default,,0,0,0,,去复制那些有用的数据结构 Dialogue: 0,0:38:37.32,0:38:38.36,Default,,0,0,0,,它是个复制收集器 Dialogue: 0,0:38:38.44,0:38:38.91,Default,,0,0,0,,学生:好吧 Dialogue: 0,0:38:39.30,0:38:40.88,Default,,0,0,0,,教授:但它确实很快 Dialogue: 0,0:38:41.85,0:38:45.88,Default,,0,0,0,,整体来说 我想如果要复制 Dialogue: 0,0:38:47.12,0:38:51.56,Default,,0,0,0,,一个大约3MB的东西 Dialogue: 0,0:38:52.43,0:38:53.24,Default,,0,0,0,,将在一秒内完成 Dialogue: 0,0:38:55.00,0:38:55.69,Default,,0,0,0,,而且是实时的 Dialogue: 0,0:38:56.54,0:38:58.46,Default,,0,0,0,,它们是非常小的程序 Dialogue: 0,0:38:58.62,0:39:01.50,Default,,0,0,0,,你需要注意到的一件事是 Dialogue: 0,0:39:02.91,0:39:04.40,Default,,0,0,0,,垃圾收集器必须要小 Dialogue: 0,0:39:05.40,0:39:07.10,Default,,0,0,0,,不是因为它们需要运行得快 Dialogue: 0,0:39:07.90,0:39:09.23,Default,,0,0,0,,因为没有人能够调试 Dialogue: 0,0:39:09.26,0:39:10.48,Default,,0,0,0,,复杂的垃圾收集器 Dialogue: 0,0:39:11.34,0:39:12.91,Default,,0,0,0,,如果一个垃圾收集器不能正常工作 Dialogue: 0,0:39:14.04,0:39:15.93,Default,,0,0,0,,它会把你的内存搞得一团糟 Dialogue: 0,0:39:15.93,0:39:17.39,Default,,0,0,0,,而你却束手无策 Dialogue: 0,0:39:18.35,0:39:19.67,Default,,0,0,0,,你需要跟踪审计 Dialogue: 0,0:39:20.66,0:39:22.01,Default,,0,0,0,,因为它把所有东西都换了位置 Dialogue: 0,0:39:22.04,0:39:23.24,Default,,0,0,0,,你需要知道那里发生了什么 Dialogue: 0,0:39:23.74,0:39:26.58,Default,,0,0,0,,所以这是唯一一种 Dialogue: 0,0:39:26.92,0:39:28.40,Default,,0,0,0,,真正非常重要的程序 Dialogue: 0,0:39:28.54,0:39:29.79,Default,,0,0,0,,如果你盯着它看足够久 Dialogue: 0,0:39:29.82,0:39:31.07,Default,,0,0,0,,那么你就相信它有效 Dialogue: 0,0:39:31.34,0:39:33.36,Default,,0,0,0,,这意味着某种“自我证明” Dialogue: 0,0:39:33.92,0:39:36.11,Default,,0,0,0,,因此我们无法对它进行查错 Dialogue: 0,0:39:36.94,0:39:38.96,Default,,0,0,0,,这意味着它需要足够小 Dialogue: 0,0:39:38.96,0:39:39.97,Default,,0,0,0,,你的大脑能够思考它的工作情况 Dialogue: 0,0:39:41.45,0:39:43.90,Default,,0,0,0,,正因如此 垃圾收集器十分特殊 Dialogue: 0,0:39:45.02,0:39:47.12,Default,,0,0,0,,所以实用的垃圾收集器一定要短小 Dialogue: 0,0:39:47.13,0:39:48.45,Default,,0,0,0,,而通常短小的程序运行得就快 Dialogue: 0,0:39:52.05,0:39:52.43,Default,,0,0,0,,请讲 Dialogue: 0,0:39:52.43,0:39:54.51,Default,,0,0,0,,学生:您能再重复一遍这个技术的名字吗? Dialogue: 0,0:39:54.68,0:39:56.92,Default,,0,0,0,,教授:Minsky-Fenichel-Yochelson垃圾回收器 Dialogue: 0,0:39:57.88,0:39:58.43,Default,,0,0,0,,学生:什么? Dialogue: 0,0:39:59.00,0:40:00.78,Default,,0,0,0,,教授:Minsky在1961年 Dialogue: 0,0:40:00.81,0:40:02.21,Default,,0,0,0,,为RLE PDP-1设计了这个算法 Dialogue: 0,0:40:02.21,0:40:06.17,Default,,0,0,0,,Fenichel和Yochelson改进并精化了算法 Dialogue: 0,0:40:06.45,0:40:10.27,Default,,0,0,0,,将它用在了Multics平台的MacLisp中 Dialogue: 0,0:40:11.37,0:40:14.75,Default,,0,0,0,,那时大约是1968或者1969年 Dialogue: 0,0:40:19.57,0:40:21.36,Default,,0,0,0,,好吧 我们休息一下 Dialogue: 0,0:40:22.64,0:40:32.36,Default,,0,0,0,,[音乐] Dialogue: 0,0:40:32.41,0:40:36.19,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:41:03.15,0:41:07.18,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:41:07.20,0:41:10.17,Declare,,0,0,0,,{\an2\fad(500,500)\pos(320,470)}《计算机程序的构造和解释》 Dialogue: 0,0:41:10.20,0:41:14.22,Declare,,0,0,0,,{\an2\fad(500,500)}计算的极限 Dialogue: 0,0:41:17.31,0:41:19.67,Default,,0,0,0,,教授:我们已经到课程的最后一部分了 Dialogue: 0,0:41:20.08,0:41:23.85,Default,,0,0,0,,我已经给你们展示了一台通用机器 Dialogue: 0,0:41:24.47,0:41:26.74,Default,,0,0,0,,它被简化为求值器 Dialogue: 0,0:41:27.02,0:41:28.38,Default,,0,0,0,,它被简化到 Dialogue: 0,0:41:28.38,0:41:29.67,Default,,0,0,0,,你自己也能构造出来 Dialogue: 0,0:41:30.19,0:41:33.32,Default,,0,0,0,,这是一个特定的Lisp实现 Dialogue: 0,0:41:33.90,0:41:36.01,Default,,0,0,0,,它是用 Dialogue: 0,0:41:36.16,0:41:38.05,Default,,0,0,0,,昨天讲过的Scheme芯片制作的 Dialogue: 0,0:41:38.20,0:41:38.91,Default,,0,0,0,,就是这个 Dialogue: 0,0:41:39.35,0:41:42.00,Default,,0,0,0,,这基本上就是暴露给他人内存的接口了 Dialogue: 0,0:41:42.60,0:41:44.75,Default,,0,0,0,,里面有节拍发生器等组件 Dialogue: 0,0:41:45.22,0:41:47.25,Default,,0,0,0,,尽管是解释执行 Dialogue: 0,0:41:47.77,0:41:50.17,Default,,0,0,0,,但它们运行Lisp的速度还算不错 Dialogue: 0,0:41:50.61,0:41:53.82,Default,,0,0,0,,它跑得像1979年的 Dialogue: 0,0:41:54.22,0:41:55.65,Default,,0,0,0,,DEC PDP-10一样快 Dialogue: 0,0:41:56.50,0:41:59.67,Default,,0,0,0,,作为一个十足的硬件 Dialogue: 0,0:42:00.02,0:42:00.89,Default,,0,0,0,,算是十分“实在”了 Dialogue: 0,0:42:02.47,0:42:04.70,Default,,0,0,0,,我们为你们讲解了一些 Dialogue: 0,0:42:04.72,0:42:06.07,Default,,0,0,0,,可以被计算的东西 Dialogue: 0,0:42:07.37,0:42:08.76,Default,,0,0,0,,但我们是否可能遇到 Dialogue: 0,0:42:09.32,0:42:10.55,Default,,0,0,0,,我们无法计算的情况? Dialogue: 0,0:42:11.85,0:42:13.50,Default,,0,0,0,,课程的最后 Dialogue: 0,0:42:13.75,0:42:15.87,Default,,0,0,0,,我想展示一些你认为可以被计算 Dialogue: 0,0:42:16.60,0:42:17.22,Default,,0,0,0,,但实际上不能的东西 Dialogue: 0,0:42:18.19,0:42:19.45,Default,,0,0,0,,实际上 Dialogue: 0,0:42:19.45,0:42:20.82,Default,,0,0,0,,确实有我们无法计算的东西 Dialogue: 0,0:42:22.72,0:42:23.47,Default,,0,0,0,,例如 Dialogue: 0,0:42:24.45,0:42:25.82,Default,,0,0,0,,我们想要这样的一种东西 Dialogue: 0,0:42:27.80,0:42:29.36,Default,,0,0,0,,当我们在编写编译器时 Dialogue: 0,0:42:29.77,0:42:31.42,Default,,0,0,0,,你想用一个程序检查 Dialogue: 0,0:42:32.00,0:42:33.97,Default,,0,0,0,,你的代码能否正常运行 Dialogue: 0,0:42:34.63,0:42:35.40,Default,,0,0,0,,这不是很棒吗? Dialogue: 0,0:42:36.08,0:42:37.87,Default,,0,0,0,,你希望能够捕获死循环 Dialogue: 0,0:42:37.87,0:42:38.54,Default,,0,0,0,,例如 Dialogue: 0,0:42:39.45,0:42:42.42,Default,,0,0,0,,用户编写的程序里的死循环 Dialogue: 0,0:42:43.19,0:42:45.12,Default,,0,0,0,,但通常来说 你写不出这样的程序 Dialogue: 0,0:42:45.35,0:42:46.49,Default,,0,0,0,,它读取某个程序 Dialogue: 0,0:42:46.51,0:42:47.45,Default,,0,0,0,,并检测它 Dialogue: 0,0:42:48.35,0:42:49.30,Default,,0,0,0,,是不是死循环 Dialogue: 0,0:42:50.99,0:42:51.71,Default,,0,0,0,,我来展示一下 Dialogue: 0,0:42:51.76,0:42:53.80,Default,,0,0,0,,这个需要涉及到数学知识 Dialogue: 0,0:42:58.78,0:42:59.65,Default,,0,0,0,,设想 Dialogue: 0,0:43:00.05,0:43:01.78,Default,,0,0,0,,在我们开始之前 Dialogue: 0,0:43:01.78,0:43:02.62,Default,,0,0,0,,有一个数学函数 Dialogue: 0,0:43:02.62,0:43:03.42,Default,,0,0,0,,这里就有一个 Dialogue: 0,0:43:03.84,0:43:04.67,Default,,0,0,0,,记作S Dialogue: 0,0:43:05.47,0:43:07.54,Default,,0,0,0,,它接受一个过程 Dialogue: 0,0:43:12.64,0:43:14.23,Default,,0,0,0,,和它的参数A Dialogue: 0,0:43:19.17,0:43:20.52,Default,,0,0,0,,S所做的是 Dialogue: 0,0:43:21.65,0:43:24.01,Default,,0,0,0,,检测以A为参数运行P时 Dialogue: 0,0:43:24.01,0:43:25.97,Default,,0,0,0,,是否安全 Dialogue: 0,0:43:26.90,0:43:28.17,Default,,0,0,0,,换句话说就是 Dialogue: 0,0:43:28.76,0:43:35.12,Default,,0,0,0,,如果(P A) Dialogue: 0,0:43:35.62,0:43:36.74,Default,,0,0,0,,在没有出错的情况下 Dialogue: 0,0:43:41.40,0:43:42.45,Default,,0,0,0,,能够返回一个值 Dialogue: 0,0:43:44.35,0:43:45.33,Default,,0,0,0,,那么S就为TRUE Dialogue: 0,0:43:52.70,0:43:53.68,Default,,0,0,0,,但如果(P A) Dialogue: 0,0:43:56.10,0:43:57.04,Default,,0,0,0,,是死循环 Dialogue: 0,0:43:59.67,0:44:00.76,Default,,0,0,0,,或者抛出错误 Dialogue: 0,0:44:05.87,0:44:06.95,Default,,0,0,0,,那么S就为FALSE Dialogue: 0,0:44:15.23,0:44:17.22,Default,,0,0,0,,这确实是个函数 Dialogue: 0,0:44:18.78,0:44:20.72,Default,,0,0,0,,对于你输入的任何过程 Dialogue: 0,0:44:21.20,0:44:22.85,Default,,0,0,0,,或者任何参数 Dialogue: 0,0:44:23.92,0:44:25.45,Default,,0,0,0,,它只能返回TRUE或FALSE Dialogue: 0,0:44:25.92,0:44:27.85,Default,,0,0,0,,它会返回一个值而且不会报错 Dialogue: 0,0:44:28.44,0:44:30.15,Default,,0,0,0,,你可以为它们画一张巨大的表格 Dialogue: 0,0:44:32.22,0:44:32.92,Default,,0,0,0,,但问题是 Dialogue: 0,0:44:32.92,0:44:34.09,Default,,0,0,0,,你能写一个过程 Dialogue: 0,0:44:34.09,0:44:35.92,Default,,0,0,0,,来计算这个函数的值吗? Dialogue: 0,0:44:37.43,0:44:38.92,Default,,0,0,0,,假设我们能做到 Dialogue: 0,0:44:39.72,0:44:40.55,Default,,0,0,0,,假设 Dialogue: 0,0:44:44.33,0:44:45.58,Default,,0,0,0,,我们有个过程 Dialogue: 0,0:44:48.55,0:44:52.73,Default,,0,0,0,,一个叫作SAFE?的过程 Dialogue: 0,0:44:56.54,0:44:59.90,Default,,0,0,0,,它能计算S的值 Dialogue: 0,0:45:12.65,0:45:14.89,Default,,0,0,0,,现在我要用几种方法 Dialogue: 0,0:45:15.90,0:45:18.51,Default,,0,0,0,,证明你做不到 Dialogue: 0,0:45:19.76,0:45:20.62,Default,,0,0,0,,最简单的一个 Dialogue: 0,0:45:20.62,0:45:21.28,Default,,0,0,0,,或者说第一个 Dialogue: 0,0:45:21.31,0:45:23.45,Default,,0,0,0,,我们定义一个叫DIAG1的过程 Dialogue: 0,0:45:23.76,0:45:24.86,Default,,0,0,0,,给定了SAFE?过程 Dialogue: 0,0:45:25.20,0:45:26.99,Default,,0,0,0,,我们可以把DIAG1定义为 Dialogue: 0,0:45:34.42,0:45:35.55,Default,,0,0,0,,把DIAG1定义为 Dialogue: 0,0:45:37.82,0:45:41.60,Default,,0,0,0,,只含有参数P的过程 Dialogue: 0,0:45:42.45,0:45:44.05,Default,,0,0,0,,它有着这样的属性 Dialogue: 0,0:45:44.78,0:45:50.67,Default,,0,0,0,,如果(SAFE? P P)为真 Dialogue: 0,0:45:53.32,0:45:55.32,Default,,0,0,0,,那么我就主动陷入死循环 Dialogue: 0,0:45:59.22,0:46:00.92,Default,,0,0,0,,否则我会返回3 Dialogue: 0,0:46:03.68,0:46:04.47,Default,,0,0,0,,它也可能是42 Dialogue: 0,0:46:04.47,0:46:06.42,Default,,0,0,0,,宇宙的终极答案是什么? Dialogue: 0,0:46:07.06,0:46:08.87,Default,,0,0,0,,我们当然知道死循环是什么 Dialogue: 0,0:46:12.05,0:46:12.96,Default,,0,0,0,,死循环INF是 Dialogue: 0,0:46:13.82,0:46:16.02,Default,,0,0,0,,一个无参过程 Dialogue: 0,0:46:16.02,0:46:18.07,Default,,0,0,0,,这是一个极好的LAMBADA演算循环 Dialogue: 0,0:46:18.35,0:46:20.44,Default,,0,0,0,,(LAMBDA (X) (X X)) Dialogue: 0,0:46:21.30,0:46:24.68,Default,,0,0,0,,应用到(LAMBDA (X) (X X)) Dialogue: 0,0:46:24.68,0:46:26.55,Default,,0,0,0,,没什么想象的余地了 Dialogue: 0,0:46:29.83,0:46:31.17,Default,,0,0,0,,我们来看下会发生什么 Dialogue: 0,0:46:32.50,0:46:33.90,Default,,0,0,0,,我假设 Dialogue: 0,0:46:35.45,0:46:38.77,Default,,0,0,0,,我们考虑 Dialogue: 0,0:46:39.00,0:46:43.45,Default,,0,0,0,,把DIAG1应用到DIAG1上 Dialogue: 0,0:46:46.27,0:46:47.77,Default,,0,0,0,,那会发生什么呢? Dialogue: 0,0:46:49.97,0:46:51.39,Default,,0,0,0,,我不知道 Dialogue: 0,0:46:51.39,0:46:53.21,Default,,0,0,0,,将DIAG1代换为 Dialogue: 0,0:46:53.55,0:46:55.50,Default,,0,0,0,,P的过程体 Dialogue: 0,0:46:57.31,0:47:00.22,Default,,0,0,0,,(SAFE? DIAG1 DIAG1)会返回什么呢? Dialogue: 0,0:47:00.22,0:47:00.78,Default,,0,0,0,,我不知道 Dialogue: 0,0:47:00.78,0:47:01.82,Default,,0,0,0,,有两种可能 Dialogue: 0,0:47:03.40,0:47:05.50,Default,,0,0,0,,如果计算(DIAG1 DIAG1)是安全的 Dialogue: 0,0:47:05.92,0:47:06.89,Default,,0,0,0,,这意味着没有死循环 Dialogue: 0,0:47:08.49,0:47:09.22,Default,,0,0,0,,那么我就要来到这里 Dialogue: 0,0:47:09.22,0:47:10.35,Default,,0,0,0,,但是随即我就陷入了死循环 Dialogue: 0,0:47:10.56,0:47:11.57,Default,,0,0,0,,所以它不是安全的 Dialogue: 0,0:47:12.21,0:47:14.78,Default,,0,0,0,,但如果计算(DIAG1 DIAG1)不安全 Dialogue: 0,0:47:14.90,0:47:16.02,Default,,0,0,0,,那么它的结果是3 Dialogue: 0,0:47:16.02,0:47:17.26,Default,,0,0,0,,但是调用(DIAG1 DIAG1)又必须能够返回 Dialogue: 0,0:47:17.26,0:47:17.93,Default,,0,0,0,,所以它必须安全才行 Dialogue: 0,0:47:20.53,0:47:23.60,Default,,0,0,0,,因此 通过归纳出这个矛盾 Dialogue: 0,0:47:24.32,0:47:26.30,Default,,0,0,0,,我们无法写出这个SAFE?过程 Dialogue: 0,0:47:27.40,0:47:29.80,Default,,0,0,0,,如果大家没有听明白这种表述 Dialogue: 0,0:47:30.25,0:47:32.15,Default,,0,0,0,,我换个方式再讲一遍 Dialogue: 0,0:47:32.82,0:47:34.00,Default,,0,0,0,,请听另一个版本 Dialogue: 0,0:47:35.53,0:47:36.95,Default,,0,0,0,,我们定义DIAG2 Dialogue: 0,0:47:39.84,0:47:41.60,Default,,0,0,0,,取名叫DIAG是因为 Dialogue: 0,0:47:42.65,0:47:44.72,Default,,0,0,0,,它来源于康托尔的对角论证法 Dialogue: 0,0:47:45.00,0:47:47.05,Default,,0,0,0,,这些事例最初都来自于 Dialogue: 0,0:47:47.05,0:47:49.05,Default,,0,0,0,,一个著名的论证 Dialogue: 0,0:47:49.45,0:47:52.65,Default,,0,0,0,,也就是康托尔在19世纪末 Dialogue: 0,0:47:52.77,0:47:56.10,Default,,0,0,0,,证明了实数是不可数的 Dialogue: 0,0:47:56.67,0:47:58.00,Default,,0,0,0,,整数与实数 Dialogue: 0,0:47:58.06,0:47:59.42,Default,,0,0,0,,无法形成一一映射 Dialogue: 0,0:48:00.19,0:48:01.74,Default,,0,0,0,,数轴上的点 Dialogue: 0,0:48:01.74,0:48:02.50,Default,,0,0,0,,举例来说 Dialogue: 0,0:48:02.50,0:48:04.42,Default,,0,0,0,,比数轴上的刻度还要多 Dialogue: 0,0:48:05.26,0:48:06.85,Default,,0,0,0,,这或许不是个显而易见的结论 Dialogue: 0,0:48:06.85,0:48:08.17,Default,,0,0,0,,但我不想深入讨论这个 Dialogue: 0,0:48:10.90,0:48:12.45,Default,,0,0,0,,但是DIAG2 Dialogue: 0,0:48:13.30,0:48:15.82,Default,,0,0,0,,也是一个参数为P的单参过程 Dialogue: 0,0:48:15.82,0:48:17.47,Default,,0,0,0,,这几乎与之前的例子相同 Dialogue: 0,0:48:17.72,0:48:24.32,Default,,0,0,0,,如果计算(P P)是安全的 Dialogue: 0,0:48:25.17,0:48:26.67,Default,,0,0,0,,那么我就要 Dialogue: 0,0:48:27.26,0:48:28.14,Default,,0,0,0,,哦 漏了一个IF Dialogue: 0,0:48:29.31,0:48:31.02,Default,,0,0,0,,那么我就去计算 Dialogue: 0,0:48:31.57,0:48:37.58,Default,,0,0,0,,一些(P P)之外的东西 Dialogue: 0,0:48:38.96,0:48:40.21,Default,,0,0,0,,否则我就返回FALSE Dialogue: 0,0:48:43.60,0:48:45.30,Default,,0,0,0,,这里的OTHER-THAN意思是 Dialogue: 0,0:48:45.47,0:48:46.35,Default,,0,0,0,,不管这个(P P)是什么 Dialogue: 0,0:48:46.35,0:48:47.47,Default,,0,0,0,,我都返回一些别的东西 Dialogue: 0,0:48:48.88,0:48:50.03,Default,,0,0,0,,我来给出一个 Dialogue: 0,0:48:50.07,0:48:51.52,Default,,0,0,0,,OTHER-THAN的一个定义 Dialogue: 0,0:48:51.60,0:48:52.57,Default,,0,0,0,,我觉得它是可用的 Dialogue: 0,0:48:53.89,0:48:54.51,Default,,0,0,0,,来看看 Dialogue: 0,0:48:55.64,0:48:56.08,Default,,0,0,0,,好 Dialogue: 0,0:48:56.33,0:48:57.26,Default,,0,0,0,,定义OTHER-THAN Dialogue: 0,0:49:04.03,0:49:06.11,Default,,0,0,0,,参数为X的单参过程 Dialogue: 0,0:49:06.57,0:49:07.26,Default,,0,0,0,,过程体是 Dialogue: 0,0:49:08.05,0:49:12.96,Default,,0,0,0,,如果(EQ? X 'A) Dialogue: 0,0:49:13.47,0:49:15.07,Default,,0,0,0,,那么结果是'B Dialogue: 0,0:49:15.72,0:49:16.80,Default,,0,0,0,,否则结果是'A Dialogue: 0,0:49:20.27,0:49:21.90,Default,,0,0,0,,这样无论参数是什么 Dialogue: 0,0:49:22.07,0:49:23.45,Default,,0,0,0,,返回值跟参数总是不相同的 Dialogue: 0,0:49:25.20,0:49:26.12,Default,,0,0,0,,就是这样了 Dialogue: 0,0:49:26.54,0:49:27.37,Default,,0,0,0,,这就是我要的 Dialogue: 0,0:49:28.25,0:49:29.58,Default,,0,0,0,,我们考虑一下这个 Dialogue: 0,0:49:29.58,0:49:31.15,Default,,0,0,0,,(DIAG2 DIAG2) Dialogue: 0,0:49:38.28,0:49:38.94,Default,,0,0,0,,看 Dialogue: 0,0:49:39.95,0:49:41.72,Default,,0,0,0,,这个东西会做些危险的事情 Dialogue: 0,0:49:42.00,0:49:43.45,Default,,0,0,0,,比如求值(P P) Dialogue: 0,0:49:44.75,0:49:45.95,Default,,0,0,0,,如果它是安全的 Dialogue: 0,0:49:47.47,0:49:49.16,Default,,0,0,0,,如果SAFE?能够被定义的话 Dialogue: 0,0:49:50.30,0:49:52.49,Default,,0,0,0,,如果你能定义SAFE?过程 Dialogue: 0,0:49:52.97,0:49:54.32,Default,,0,0,0,,那么这个过程 Dialogue: 0,0:49:54.60,0:49:56.40,Default,,0,0,0,,也就顺理成章地是安全的 Dialogue: 0,0:49:56.52,0:49:57.22,Default,,0,0,0,,对于任意输入来说都是 Dialogue: 0,0:50:01.54,0:50:03.50,Default,,0,0,0,,那么(DIAG2 DIAG2) Dialogue: 0,0:50:03.87,0:50:12.20,Default,,0,0,0,,就会返回(OTHER-THAN (DIAG2 DIAG2)) Dialogue: 0,0:50:15.82,0:50:16.97,Default,,0,0,0,,这说不通 Dialogue: 0,0:50:17.80,0:50:19.02,Default,,0,0,0,,又产生了悖论 Dialogue: 0,0:50:19.85,0:50:21.57,Default,,0,0,0,,因此我们不能定义SAFE? Dialogue: 0,0:50:22.95,0:50:24.23,Default,,0,0,0,,我只想这样证明两次 Dialogue: 0,0:50:24.78,0:50:25.82,Default,,0,0,0,,有些许不同 Dialogue: 0,0:50:26.84,0:50:27.90,Default,,0,0,0,,你不会感到 Dialogue: 0,0:50:29.07,0:50:30.86,Default,,0,0,0,,第一个证明是个把戏 Dialogue: 0,0:50:32.54,0:50:33.45,Default,,0,0,0,,它们可能都是把戏 Dialogue: 0,0:50:33.80,0:50:35.15,Default,,0,0,0,,但它们稍微有些不同 Dialogue: 0,0:50:37.30,0:50:39.20,Default,,0,0,0,,因此 我想这就基本上讲清楚了 Dialogue: 0,0:50:40.03,0:50:41.97,Default,,0,0,0,,我们刚刚证明了所谓的“停机问题” Dialogue: 0,0:50:43.00,0:50:44.70,Default,,0,0,0,,我想 本课程也即将画上句号 Dialogue: 0,0:50:46.72,0:50:47.63,Default,,0,0,0,,希望你们有所收获 Dialogue: 0,0:50:50.90,0:50:51.76,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:50:53.30,0:50:53.56,Default,,0,0,0,,请讲 Dialogue: 0,0:50:53.81,0:50:56.27,Default,,0,0,0,,学生: (S DIAG1)的值是什么? Dialogue: 0,0:50:56.75,0:50:57.23,Default,,0,0,0,,教授: 什么的值? Dialogue: 0,0:50:57.50,0:50:58.80,Default,,0,0,0,,学生: (S DIAG1)的值 Dialogue: 0,0:51:00.12,0:51:02.20,Default,,0,0,0,,如果你说S是个函数 我们就可以-- Dialogue: 0,0:51:02.30,0:51:03.63,Default,,0,0,0,,教授: 噢 我不知道啊 Dialogue: 0,0:51:03.87,0:51:04.35,Default,,0,0,0,,我不知道 Dialogue: 0,0:51:04.35,0:51:04.88,Default,,0,0,0,,它是一个函数 Dialogue: 0,0:51:04.88,0:51:05.85,Default,,0,0,0,,但我不知道如何计算它 Dialogue: 0,0:51:06.80,0:51:08.00,Default,,0,0,0,,我做不到 Dialogue: 0,0:51:08.61,0:51:09.64,Default,,0,0,0,,我也只是个机器 Dialogue: 0,0:51:11.53,0:51:11.88,Default,,0,0,0,,对吧? Dialogue: 0,0:51:11.90,0:51:13.37,Default,,0,0,0,,原则上来说 Dialogue: 0,0:51:13.37,0:51:14.05,Default,,0,0,0,,没有机器 Dialogue: 0,0:51:14.47,0:51:16.87,Default,,0,0,0,,当然 也有可能会处在你刚才问的那个情况中 Dialogue: 0,0:51:16.87,0:51:18.32,Default,,0,0,0,,花点时间还是可以计算出来 Dialogue: 0,0:51:18.58,0:51:19.37,Default,,0,0,0,,但通常情况下 Dialogue: 0,0:51:19.60,0:51:21.05,Default,,0,0,0,,我无法计算S的值 Dialogue: 0,0:51:21.05,0:51:22.52,Default,,0,0,0,,别的机器也做不到 Dialogue: 0,0:51:23.78,0:51:24.92,Default,,0,0,0,,存在这样一个函数 Dialogue: 0,0:51:25.92,0:51:28.00,Default,,0,0,0,,没有任何机器能够计算它 Dialogue: 0,0:51:29.58,0:51:30.05,Default,,0,0,0,,现在 Dialogue: 0,0:51:30.67,0:51:33.67,Default,,0,0,0,,我这么来说也不会让你们吃惊 Dialogue: 0,0:51:35.22,0:51:36.25,Default,,0,0,0,,来想一想 Dialogue: 0,0:51:36.25,0:51:38.36,Default,,0,0,0,,现在我没有时间给你们展示 Dialogue: 0,0:51:38.45,0:51:43.00,Default,,0,0,0,,但这样的函数非常多 Dialogue: 0,0:51:44.40,0:51:47.58,Default,,0,0,0,,如果有一定量的可能输入 Dialogue: 0,0:51:47.75,0:51:49.62,Default,,0,0,0,,和一定量可能的结果 Dialogue: 0,0:51:49.87,0:51:51.80,Default,,0,0,0,,那么结果数量的输入数量次幂 Dialogue: 0,0:51:51.80,0:51:53.20,Default,,0,0,0,,就是可能的函数的数量 Dialogue: 0,0:51:54.50,0:51:55.48,Default,,0,0,0,,这还是单参的函数 Dialogue: 0,0:51:56.51,0:51:59.24,Default,,0,0,0,,而多参函数的个数 Dialogue: 0,0:52:00.09,0:52:03.21,Default,,0,0,0,,又比这个幂次方 Dialogue: 0,0:52:03.58,0:52:04.32,Default,,0,0,0,,这个指数还要大 Dialogue: 0,0:52:05.48,0:52:09.80,Default,,0,0,0,,函数的数量 Dialogue: 0,0:52:09.95,0:52:12.72,Default,,0,0,0,,比一个人能写出的 Dialogue: 0,0:52:13.30,0:52:14.10,Default,,0,0,0,,程序的数量更多 Dialogue: 0,0:52:14.82,0:52:16.45,Default,,0,0,0,,因为有无穷多的参数 Dialogue: 0,0:52:17.57,0:52:19.00,Default,,0,0,0,,可能会更多 Dialogue: 0,0:52:19.47,0:52:22.12,Default,,0,0,0,,所以不可计算的函数数量 Dialogue: 0,0:52:22.12,0:52:23.48,Default,,0,0,0,,一定会非常多 Dialogue: 0,0:52:25.92,0:52:26.59,Default,,0,0,0,,学生:不久前 Dialogue: 0,0:52:26.64,0:52:28.25,Default,,0,0,0,,你讲了规范 Dialogue: 0,0:52:28.30,0:52:30.04,Default,,0,0,0,,和自动生成解决方案 Dialogue: 0,0:52:30.64,0:52:31.61,Default,,0,0,0,,您觉得通过规范 Dialogue: 0,0:52:31.82,0:52:33.36,Default,,0,0,0,,能够生成解决方案么? Dialogue: 0,0:52:37.25,0:52:38.22,Default,,0,0,0,,教授:“生成” Dialogue: 0,0:52:38.72,0:52:39.37,Default,,0,0,0,,你是说 Dialogue: 0,0:52:39.37,0:52:42.60,Default,,0,0,0,,如何按照规范 Dialogue: 0,0:52:42.60,0:52:44.78,Default,,0,0,0,,构建相应的装置吗? Dialogue: 0,0:52:45.05,0:52:48.36,Default,,0,0,0,,学生:软件工程中有很多 Dialogue: 0,0:52:48.36,0:52:49.90,Default,,0,0,0,,层次化的设计 Dialogue: 0,0:52:49.90,0:52:51.90,Default,,0,0,0,,并进行实现的规范 Dialogue: 0,0:52:52.43,0:52:52.85,Default,,0,0,0,,教授:是的 Dialogue: 0,0:52:52.85,0:52:53.70,Default,,0,0,0,,学生:我很好奇 Dialogue: 0,0:52:53.70,0:52:54.62,Default,,0,0,0,,您觉得这现实吗? Dialogue: 0,0:52:55.60,0:52:57.17,Default,,0,0,0,,教授:我觉得其中一些是现实的 Dialogue: 0,0:52:57.17,0:52:58.10,Default,,0,0,0,,另一些不现实 Dialogue: 0,0:52:58.10,0:53:00.32,Default,,0,0,0,,如果你想制造一个滤波器 Dialogue: 0,0:53:01.17,0:53:07.16,Default,,0,0,0,,我这有个挺有趣的例子 Dialogue: 0,0:53:07.16,0:53:09.42,Default,,0,0,0,,假设我想制造一个东西 Dialogue: 0,0:53:09.64,0:53:14.07,Default,,0,0,0,,把无线电发射器的输出 Dialogue: 0,0:53:14.47,0:53:18.75,Default,,0,0,0,,连接到某条天线上 Dialogue: 0,0:53:19.90,0:53:21.47,Default,,0,0,0,,我先把它引出来 Dialogue: 0,0:53:21.48,0:53:23.04,Default,,0,0,0,,这里是输出管线 Dialogue: 0,0:53:23.23,0:53:25.26,Default,,0,0,0,,问题是它们的阻抗不同 Dialogue: 0,0:53:25.92,0:53:27.55,Default,,0,0,0,,我希望能够匹配阻抗 Dialogue: 0,0:53:27.55,0:53:28.97,Default,,0,0,0,,我也想在其中加入一个滤波器 Dialogue: 0,0:53:29.15,0:53:31.71,Default,,0,0,0,,用来过滤一些谐波辐射 Dialogue: 0,0:53:32.78,0:53:36.63,Default,,0,0,0,,一种老派的技术叫作 Dialogue: 0,0:53:36.82,0:53:38.67,Default,,0,0,0,,“影像阻抗”之类的东西 Dialogue: 0,0:53:38.86,0:53:39.50,Default,,0,0,0,,你要做的是 Dialogue: 0,0:53:39.50,0:53:40.85,Default,,0,0,0,,你有个基础的模块 Dialogue: 0,0:53:40.85,0:53:42.75,Default,,0,0,0,,称为L型滤波器 Dialogue: 0,0:53:43.30,0:53:43.98,Default,,0,0,0,,就像这样 Dialogue: 0,0:53:47.08,0:53:49.80,Default,,0,0,0,,如果把它连接到某些电阻R上 Dialogue: 0,0:53:50.05,0:53:52.60,Default,,0,0,0,,如果我把它的阻抗记作X_L Dialogue: 0,0:53:52.72,0:53:55.20,Default,,0,0,0,,而它的值刚好又等于Q*R Dialogue: 0,0:53:55.26,0:53:58.52,Default,,0,0,0,,这就成了一个低通滤波器 Dialogue: 0,0:53:58.52,0:54:00.72,Default,,0,0,0,,有Q^2+1的等效阻抗 Dialogue: 0,0:54:02.11,0:54:02.86,Default,,0,0,0,,这就是我想要的 Dialogue: 0,0:54:03.12,0:54:04.28,Default,,0,0,0,,因为这样我就可以 Dialogue: 0,0:54:04.30,0:54:05.08,Default,,0,0,0,,把它们匹配到一起了 Dialogue: 0,0:54:05.82,0:54:06.38,Default,,0,0,0,,就像这样 Dialogue: 0,0:54:11.66,0:54:13.15,Default,,0,0,0,,我拿来另一个 Dialogue: 0,0:54:16.00,0:54:17.45,Default,,0,0,0,,想这样把它们连到一起 Dialogue: 0,0:54:18.29,0:54:19.95,Default,,0,0,0,,有两个L型滤波器连接起来 Dialogue: 0,0:54:20.32,0:54:23.07,Default,,0,0,0,,这能让它的阻抗降到我知道的值 Dialogue: 0,0:54:23.37,0:54:25.22,Default,,0,0,0,,让它的阻抗升到我知道的值 Dialogue: 0,0:54:25.53,0:54:26.64,Default,,0,0,0,,这两个低通滤波器 Dialogue: 0,0:54:26.67,0:54:27.82,Default,,0,0,0,,都过滤掉了一些谐波 Dialogue: 0,0:54:28.09,0:54:29.07,Default,,0,0,0,,这是个不错的滤波器 Dialogue: 0,0:54:29.07,0:54:30.27,Default,,0,0,0,,这就是π型滤波器 Dialogue: 0,0:54:30.27,0:54:30.62,Default,,0,0,0,,很好 Dialogue: 0,0:54:31.70,0:54:34.09,Default,,0,0,0,,除了实际上 Dialogue: 0,0:54:34.12,0:54:37.85,Default,,0,0,0,,我在系统里放了些无用的东西 Dialogue: 0,0:54:38.62,0:54:39.60,Default,,0,0,0,,我在本该只用一个的地方 Dialogue: 0,0:54:39.61,0:54:40.59,Default,,0,0,0,,用了两个线圈 Dialogue: 0,0:54:41.62,0:54:44.60,Default,,0,0,0,,在大多数软件工程技艺中 Dialogue: 0,0:54:44.89,0:54:46.88,Default,,0,0,0,,在人工优化和编译之外 Dialogue: 0,0:54:46.92,0:54:48.65,Default,,0,0,0,,不存在一种机制 Dialogue: 0,0:54:48.80,0:54:51.34,Default,,0,0,0,,能在自顶向下的设计中 Dialogue: 0,0:54:51.34,0:54:53.55,Default,,0,0,0,,去掉冗余的部分 Dialogue: 0,0:54:55.35,0:54:56.07,Default,,0,0,0,,或许会更糟 Dialogue: 0,0:54:56.07,0:54:57.58,Default,,0,0,0,,有很多重要的结构 Dialogue: 0,0:54:57.60,0:54:59.02,Default,,0,0,0,,你无法采用这种方式构建 Dialogue: 0,0:55:01.11,0:55:03.53,Default,,0,0,0,,我觉得标准的自上而下的设计方式 Dialogue: 0,0:55:03.53,0:55:04.87,Default,,0,0,0,,是一种很短视的手段 Dialogue: 0,0:55:05.71,0:55:06.60,Default,,0,0,0,,它不会真的抓到 Dialogue: 0,0:55:06.60,0:55:08.10,Default,,0,0,0,,设计者真正想要的结果 Dialogue: 0,0:55:08.31,0:55:10.10,Default,,0,0,0,,我再举一个电子学的例子 Dialogue: 0,0:55:10.10,0:55:11.75,Default,,0,0,0,,电子学的例子 Dialogue: 0,0:55:11.90,0:55:13.13,Default,,0,0,0,,要比计算的例子直观得多 Dialogue: 0,0:55:13.16,0:55:14.78,Default,,0,0,0,,因为计算的例子 Dialogue: 0,0:55:14.80,0:55:16.52,Default,,0,0,0,,解释起来比较复杂 Dialogue: 0,0:55:17.22,0:55:19.16,Default,,0,0,0,,在电子学世界中 Dialogue: 0,0:55:19.16,0:55:20.04,Default,,0,0,0,,我最喜欢的例子之一是 Dialogue: 0,0:55:20.60,0:55:22.80,Default,,0,0,0,,是如何设计中频放大器中 Dialogue: 0,0:55:23.28,0:55:26.55,Default,,0,0,0,,输入级和输出级的连接方式 Dialogue: 0,0:55:27.53,0:55:29.44,Default,,0,0,0,,这是一个三极管 Dialogue: 0,0:55:29.52,0:55:31.50,Default,,0,0,0,,我们来看看 Dialogue: 0,0:55:32.41,0:55:33.40,Default,,0,0,0,,这有个LC震荡电路 Dialogue: 0,0:55:36.45,0:55:39.17,Default,,0,0,0,,我要把它 Dialogue: 0,0:55:41.37,0:55:43.97,Default,,0,0,0,,把它与下一级的输入线圈耦合在一起 Dialogue: 0,0:55:44.36,0:55:47.47,Default,,0,0,0,,这是个完美的可行方案 Dialogue: 0,0:55:48.22,0:55:50.87,Default,,0,0,0,,除了我这个电流方向画错了 Dialogue: 0,0:55:50.87,0:55:52.92,Default,,0,0,0,,电流应该是这个方向 Dialogue: 0,0:55:53.17,0:55:55.45,Default,,0,0,0,,这是个完美的可行方案 Dialogue: 0,0:55:55.98,0:55:56.57,Default,,0,0,0,,不对 Dialogue: 0,0:55:57.12,0:55:57.79,Default,,0,0,0,,我犯蠢了 Dialogue: 0,0:55:58.40,0:55:59.07,Default,,0,0,0,,对不起 Dialogue: 0,0:55:59.69,0:56:00.42,Default,,0,0,0,,这不重要 Dialogue: 0,0:56:00.73,0:56:01.54,Default,,0,0,0,,关键在于这是一个 Dialogue: 0,0:56:01.54,0:56:03.42,Default,,0,0,0,,把两级耦合起来的完美方案 Dialogue: 0,0:56:04.54,0:56:06.92,Default,,0,0,0,,分层来看时会产生什么问题? Dialogue: 0,0:56:07.62,0:56:08.80,Default,,0,0,0,,它就不是同一个东西了 Dialogue: 0,0:56:09.48,0:56:11.99,Default,,0,0,0,,当分层来看时它就没有任何意义了 Dialogue: 0,0:56:11.99,0:56:14.32,Default,,0,0,0,,这是一个调谐电路的电感 Dialogue: 0,0:56:15.55,0:56:18.02,Default,,0,0,0,,这是变压器的初级线圈 Dialogue: 0,0:56:19.10,0:56:21.82,Default,,0,0,0,,这是直流的通路 Dialogue: 0,0:56:21.82,0:56:23.57,Default,,0,0,0,,它是三极管的集电极 Dialogue: 0,0:56:23.57,0:56:25.10,Default,,0,0,0,,的偏置条件 Dialogue: 0,0:56:26.46,0:56:28.35,Default,,0,0,0,,没有任何简单的自顶向下设计 Dialogue: 0,0:56:28.38,0:56:30.17,Default,,0,0,0,,能够得到这样的结构 Dialogue: 0,0:56:30.22,0:56:34.02,Default,,0,0,0,,对于同一个东西有大量的复用 Dialogue: 0,0:56:34.53,0:56:36.72,Default,,0,0,0,,玩拼字游戏 Dialogue: 0,0:56:36.96,0:56:39.88,Default,,0,0,0,,当你要完成三倍分数的词时 Dialogue: 0,0:56:40.49,0:56:43.60,Default,,0,0,0,,自顶向下的设计策略并不容易 Dialogue: 0,0:56:44.95,0:56:47.08,Default,,0,0,0,,然而 大多数实际的工程学都是 Dialogue: 0,0:56:47.36,0:56:50.70,Default,,0,0,0,,秉承着“尽其力而为之” Dialogue: 0,0:56:52.14,0:56:53.52,Default,,0,0,0,,那就是你所看到的东西 Dialogue: 0,0:56:54.86,0:56:55.55,Default,,0,0,0,,嗯? Dialogue: 0,0:56:55.55,0:56:56.81,Default,,0,0,0,,学生:这是最后一个问题吗? Dialogue: 0,0:57:00.28,0:57:02.03,Default,,0,0,0,,[笑声] Dialogue: 0,0:57:18.64,0:57:19.63,Default,,0,0,0,,教授:看起来是 Dialogue: 0,0:57:23.57,0:57:24.12,Default,,0,0,0,,谢谢大家 Dialogue: 0,0:57:25.90,0:57:36.50,Default,,0,0,0,,[掌声] Dialogue: 0,0:58:47.29,0:58:51.13,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:58:47.29,0:58:51.13,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP Dialogue: 0,0:58:51.87,0:58:53.71,Default,,0,0,0,,{\an4\pos(33,231)}  你所知道的有关计算的东西,其他人也都能学到。绝不要认为\N\N\N似乎成功计算的钥匙就掌握在你的手里。你所掌握的,也是我认为\N\N\N并希望的,也就是智慧:那种看到这一机器比你第一次站在它面前\N\N\N时能做得更多的能力,这样你才能将它向前推进。\N\N\N\N\N               Alan J. Perlis (1922.4.1 - 1990.1.7) ================================================ FILE: Ass/lec10b.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 1311 Video Position: 103256 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:11.88,0:00:18.11,EN,,0,0,0,,Storage Allocation & Garbage Collection Dialogue: 0,0:00:18.91,0:00:20.61,EN,,0,0,0,,PROFESSOR: Well, there's one bit of mystery left, Dialogue: 0,0:00:21.16,0:00:23.36,EN,,0,0,0,,which I'd like to get rid of right now. Dialogue: 0,0:00:24.44,0:00:28.80,EN,,0,0,0,,And that's that we've been blithely doing things like cons Dialogue: 0,0:00:30.00,0:00:31.62,EN,,0,0,0,,assuming there's always another one. Dialogue: 0,0:00:32.80,0:00:36.32,EN,,0,0,0,,That we've been doing these things like Dialogue: 0,0:00:36.51,0:00:37.44,EN,,0,0,0,,car-ing and cdr-ing Dialogue: 0,0:00:37.47,0:00:38.72,EN,,0,0,0,,and assuming that we had some idea Dialogue: 0,0:00:38.75,0:00:39.74,EN,,0,0,0,,how this can be done. Dialogue: 0,0:00:40.02,0:00:40.67,EN,,0,0,0,,Now indeed Dialogue: 0,0:00:41.07,0:00:44.40,EN,,0,0,0,,we said that that's equivalent to having procedures. Dialogue: 0,0:00:45.37,0:00:47.57,EN,,0,0,0,,OK? But that doesn't really solve the problem, Dialogue: 0,0:00:47.73,0:00:50.25,EN,,0,0,0,,because the procedure need all sorts of complicated mechanisms Dialogue: 0,0:00:50.27,0:00:51.37,EN,,0,0,0,,like environment structures Dialogue: 0,0:00:51.64,0:00:52.76,EN,,0,0,0,,and things like that to work. Dialogue: 0,0:00:53.01,0:00:54.89,EN,,0,0,0,,And those were ultimately made out of conses Dialogue: 0,0:00:54.89,0:00:56.42,EN,,0,0,0,,in the model that we had, Dialogue: 0,0:00:56.70,0:00:58.47,EN,,0,0,0,,so that really doesn't solve the problem. Dialogue: 0,0:00:59.38,0:01:01.13,EN,,0,0,0,,Now the problem here is Dialogue: 0,0:01:01.31,0:01:03.97,EN,,0,0,0,,is the glue the data structure's made out of. Dialogue: 0,0:01:04.76,0:01:06.40,EN,,0,0,0,,What kind of possible thing could it be? Dialogue: 0,0:01:07.04,0:01:10.46,EN,,0,0,0,,OK? We've been showing you things like a machine, Dialogue: 0,0:01:10.46,0:01:13.96,EN,,0,0,0,,a computer that has a controller, Dialogue: 0,0:01:14.27,0:01:15.45,EN,,0,0,0,,and some registers, Dialogue: 0,0:01:15.45,0:01:16.47,EN,,0,0,0,,and maybe a stack. Dialogue: 0,0:01:16.98,0:01:18.12,EN,,0,0,0,,And we haven't said anything about, Dialogue: 0,0:01:18.16,0:01:19.95,EN,,0,0,0,,for example, larger memory. Dialogue: 0,0:01:20.57,0:01:22.38,EN,,0,0,0,,And I think that's what we have to worry about right now. Dialogue: 0,0:01:23.74,0:01:26.56,EN,,0,0,0,,But just to make it perfectly clear Dialogue: 0,0:01:26.59,0:01:27.88,EN,,0,0,0,,that this is an inessential, Dialogue: 0,0:01:28.82,0:01:30.79,EN,,0,0,0,,purely implementational thing, Dialogue: 0,0:01:31.10,0:01:32.60,EN,,0,0,0,,I'd like to show you, for example, Dialogue: 0,0:01:32.60,0:01:34.20,EN,,0,0,0,,how you can do it all with the numbers. Dialogue: 0,0:01:35.23,0:01:36.82,EN,,0,0,0,,That's an easy one. Dialogue: 0,0:01:37.59,0:01:39.00,EN,,0,0,0,,Famous fellow by the name of Godel, Dialogue: 0,0:01:44.09,0:01:46.01,EN,,0,0,0,,a logician at the end of the 1930s, Dialogue: 0,0:01:46.38,0:01:48.70,EN,,0,0,0,,invented a very clever way Dialogue: 0,0:01:48.70,0:01:52.27,EN,,0,0,0,,of encoding the complicated expressions Dialogue: 0,0:01:52.81,0:01:53.52,EN,,0,0,0,,as numbers. Dialogue: 0,0:01:54.32,0:01:55.05,EN,,0,0,0,,For example-- Dialogue: 0,0:01:55.05,0:01:58.00,EN,,0,0,0,,I'm not saying exactly what Godel's scheme is, Dialogue: 0,0:01:58.00,0:01:59.48,EN,,0,0,0,,because he didn't use words like cons. Dialogue: 0,0:01:59.66,0:02:00.60,EN,,0,0,0,,He had other kinds of Dialogue: 0,0:02:00.91,0:02:02.60,EN,,0,0,0,,of ways of combining to make expressions. Dialogue: 0,0:02:03.09,0:02:03.88,EN,,0,0,0,,But he said, Dialogue: 0,0:02:03.92,0:02:06.81,EN,,0,0,0,,I'm going to assign a number to every algebraic expression. Dialogue: 0,0:02:07.92,0:02:09.72,EN,,0,0,0,,And the way I'm going to manufacture these numbers Dialogue: 0,0:02:09.72,0:02:11.65,EN,,0,0,0,,is by combining the numbers of the parts. Dialogue: 0,0:02:12.47,0:02:13.45,EN,,0,0,0,,So for example, Dialogue: 0,0:02:13.62,0:02:15.35,EN,,0,0,0,,what we were doing our world, Dialogue: 0,0:02:15.35,0:02:18.01,EN,,0,0,0,,we could say that if objects Dialogue: 0,0:02:20.78,0:02:22.22,EN,,0,0,0,,are represented by numbers, Dialogue: 0,0:02:30.67,0:02:37.93,EN,,0,0,0,,then cons of x and y Dialogue: 0,0:02:38.04,0:02:41.07,EN,,0,0,0,,could be represented by, Dialogue: 0,0:02:41.55,0:02:43.77,EN,,0,0,0,,2 to the x times 3 to the y. Dialogue: 0,0:02:46.13,0:02:48.03,EN,,0,0,0,,Because then we could extract the parts. Dialogue: 0,0:02:49.56,0:02:50.97,EN,,0,0,0,,We could say, for example, Dialogue: 0,0:02:51.18,0:02:55.88,EN,,0,0,0,,that then car of, say, x Dialogue: 0,0:02:56.55,0:03:05.18,EN,,0,0,0,,is the number of factors of 2 in x. Dialogue: 0,0:03:06.69,0:03:08.78,EN,,0,0,0,,OK? And of course cdr is the same thing. Dialogue: 0,0:03:10.69,0:03:15.57,EN,,0,0,0,,It's the number of factors of 3 in x. Dialogue: 0,0:03:16.51,0:03:18.65,EN,,0,0,0,,Now this is a perfectly reasonable scheme, Dialogue: 0,0:03:19.10,0:03:20.11,EN,,0,0,0,,except for the fact that Dialogue: 0,0:03:20.12,0:03:22.52,EN,,0,0,0,,the numbers rapidly get to be much larger Dialogue: 0,0:03:22.83,0:03:23.98,EN,,0,0,0,,in number of digits Dialogue: 0,0:03:24.32,0:03:26.55,EN,,0,0,0,,than the number of protons in the universe. Dialogue: 0,0:03:27.95,0:03:29.88,EN,,0,0,0,,So there's no easy way to use this scheme Dialogue: 0,0:03:29.90,0:03:31.21,EN,,0,0,0,,other than the theoretical one. Dialogue: 0,0:03:33.43,0:03:34.48,EN,,0,0,0,,On the other hand, Dialogue: 0,0:03:35.12,0:03:37.55,EN,,0,0,0,,there are other ways of representing these things. Dialogue: 0,0:03:38.45,0:03:40.01,EN,,0,0,0,,We have been thinking in terms Dialogue: 0,0:03:40.25,0:03:42.42,EN,,0,0,0,,of little boxes, boxes. Dialogue: 0,0:03:43.32,0:03:46.43,EN,,0,0,0,,We've been thinking about our cons structures Dialogue: 0,0:03:46.50,0:03:48.05,EN,,0,0,0,,as looking sort of like this. Dialogue: 0,0:03:50.28,0:03:52.57,EN,,0,0,0,,They're little pigeon holes with things in them. Dialogue: 0,0:03:53.56,0:03:55.47,EN,,0,0,0,,And of course we arrange them in little trees. Dialogue: 0,0:03:57.21,0:03:59.97,EN,,0,0,0,,I wish that the semiconductor manufacturers Dialogue: 0,0:03:59.97,0:04:02.07,EN,,0,0,0,,would supply me with something appropriate for this, Dialogue: 0,0:04:02.70,0:04:03.76,EN,,0,0,0,,but actually Dialogue: 0,0:04:03.85,0:04:05.31,EN,,0,0,0,,what they do supply me with Dialogue: 0,0:04:06.20,0:04:07.96,EN,,0,0,0,,is a linear memory. Dialogue: 0,0:04:09.38,0:04:13.46,EN,,0,0,0,,Memory is sort of a big pile of pigeonholes, Dialogue: 0,0:04:15.12,0:04:16.34,EN,,0,0,0,,pigeonholes like this. Dialogue: 0,0:04:17.72,0:04:20.25,EN,,0,0,0,,Each of which can hold a certain sized object, Dialogue: 0,0:04:20.94,0:04:22.20,EN,,0,0,0,,a fixed size object. Dialogue: 0,0:04:23.39,0:04:24.07,EN,,0,0,0,,So, for example, Dialogue: 0,0:04:24.07,0:04:25.66,EN,,0,0,0,,a complicated list with 25 elements Dialogue: 0,0:04:25.66,0:04:26.64,EN,,0,0,0,,won't fit in one of these. Dialogue: 0,0:04:28.55,0:04:29.26,EN,,0,0,0,,However, each of these Dialogue: 0,0:04:29.29,0:04:30.88,EN,,0,0,0,,is indexed by an address. Dialogue: 0,0:04:33.97,0:04:34.99,EN,,0,0,0,,So the address might be Dialogue: 0,0:04:35.02,0:04:35.50,EN,,0,0,0,,zero here, Dialogue: 0,0:04:35.50,0:04:36.22,EN,,0,0,0,,one here, Dialogue: 0,0:04:36.22,0:04:36.70,EN,,0,0,0,,two here, Dialogue: 0,0:04:36.70,0:04:37.25,EN,,0,0,0,,three here, Dialogue: 0,0:04:37.25,0:04:37.94,EN,,0,0,0,,and so on. Dialogue: 0,0:04:38.06,0:04:40.40,EN,,0,0,0,,That we write these down as numbers is unimportant. Dialogue: 0,0:04:40.40,0:04:41.68,EN,,0,0,0,,What matters is that they're distinct Dialogue: 0,0:04:41.95,0:04:43.42,EN,,0,0,0,,as a way to get to the next one. Dialogue: 0,0:04:44.97,0:04:46.14,EN,,0,0,0,,And inside of each of these, Dialogue: 0,0:04:46.36,0:04:49.11,EN,,0,0,0,,we can stuff something into these pigeonholes. Dialogue: 0,0:04:49.53,0:04:50.77,EN,,0,0,0,,That's what memory is like, Dialogue: 0,0:04:51.02,0:04:53.66,EN,,0,0,0,,for those of you who haven't built a computer. Dialogue: 0,0:04:54.15,0:04:54.65,EN,,0,0,0,,Now. Dialogue: 0,0:04:56.69,0:04:57.53,EN,,0,0,0,,Now the problem is Dialogue: 0,0:04:57.53,0:04:59.97,EN,,0,0,0,,how are we going to impose on this type of structure, Dialogue: 0,0:05:00.42,0:05:01.72,EN,,0,0,0,,this nice tree structure. Dialogue: 0,0:05:03.29,0:05:04.57,EN,,0,0,0,,Well it's not very hard, Dialogue: 0,0:05:04.57,0:05:06.35,EN,,0,0,0,,and there have been numerous schemes involved in this. Dialogue: 0,0:05:06.87,0:05:08.80,EN,,0,0,0,,The most important one is to say, Dialogue: 0,0:05:08.80,0:05:11.18,EN,,0,0,0,,well assuming that the semiconductor manufacturer Dialogue: 0,0:05:11.20,0:05:13.90,EN,,0,0,0,,allows me to arrange my memory Dialogue: 0,0:05:13.98,0:05:15.77,EN,,0,0,0,,so that one of these pigeonholes is big enough Dialogue: 0,0:05:16.28,0:05:18.20,EN,,0,0,0,,to hold the address of another Dialogue: 0,0:05:19.35,0:05:20.83,EN,,0,0,0,,OK. I have been made. Dialogue: 0,0:05:22.05,0:05:23.45,EN,,0,0,0,,Now it actually has to be a little bit bigger Dialogue: 0,0:05:23.48,0:05:27.52,EN,,0,0,0,,because I have to also install or store some information Dialogue: 0,0:05:27.56,0:05:30.09,EN,,0,0,0,,as to a tag which describes the kind of thing that's there. Dialogue: 0,0:05:30.39,0:05:31.64,EN,,0,0,0,,And we'll see that in a second. Dialogue: 0,0:05:32.62,0:05:34.40,EN,,0,0,0,,And of course if the semiconductor manufacturer Dialogue: 0,0:05:34.43,0:05:35.88,EN,,0,0,0,,doesn't arrange it so I can do that, Dialogue: 0,0:05:36.08,0:05:38.44,EN,,0,0,0,,then of course I can, with some cleverness, Dialogue: 0,0:05:38.57,0:05:41.82,EN,,0,0,0,,arrange combinations of these to fit together in that way. Dialogue: 0,0:05:43.77,0:05:47.05,EN,,0,0,0,,So we're going to have to imagine Dialogue: 0,0:05:47.05,0:05:49.54,EN,,0,0,0,,imposing this complicated tree structure Dialogue: 0,0:05:49.54,0:05:51.20,EN,,0,0,0,,on our nice linear memory. Dialogue: 0,0:05:51.74,0:05:54.47,EN,,0,0,0,,If we look at the first still store, Dialogue: 0,0:05:54.47,0:05:58.30,EN,,0,0,0,,we see a classic scheme for doing that. Dialogue: 0,0:05:59.49,0:06:02.62,EN,,0,0,0,,It's a standard way of representing list structures Dialogue: 0,0:06:03.22,0:06:05.87,EN,,0,0,0,,in a linear memory. Dialogue: 0,0:06:06.27,0:06:08.32,EN,,0,0,0,,What we do is we divide this memory Dialogue: 0,0:06:08.88,0:06:11.12,EN,,0,0,0,,into two parts. Dialogue: 0,0:06:12.03,0:06:13.42,EN,,0,0,0,,An array called the cars, Dialogue: 0,0:06:14.45,0:06:15.88,EN,,0,0,0,,and an array called the cdrs. Dialogue: 0,0:06:17.58,0:06:18.86,EN,,0,0,0,,Now whether those happen to be Dialogue: 0,0:06:18.88,0:06:21.04,EN,,0,0,0,,sequential addresses or whatever, Dialogue: 0,0:06:21.12,0:06:22.00,EN,,0,0,0,,it's not important. Dialogue: 0,0:06:22.87,0:06:25.20,EN,,0,0,0,,That's somebody's implementation details. Dialogue: 0,0:06:25.80,0:06:28.40,EN,,0,0,0,,But there are two arrays here. Dialogue: 0,0:06:28.96,0:06:30.36,EN,,0,0,0,,Linear arrays indexed Dialogue: 0,0:06:30.46,0:06:32.59,EN,,0,0,0,,by sequential indices like this. Dialogue: 0,0:06:34.84,0:06:36.85,EN,,0,0,0,,What is stored in each of these pigeonholes Dialogue: 0,0:06:37.46,0:06:39.85,EN,,0,0,0,,is a typed object. Dialogue: 0,0:06:41.43,0:06:42.57,EN,,0,0,0,,And what we have here Dialogue: 0,0:06:42.57,0:06:45.71,EN,,0,0,0,,are types which begin with letters like p, Dialogue: 0,0:06:45.71,0:06:46.57,EN,,0,0,0,,standing for a pair. Dialogue: 0,0:06:47.79,0:06:49.37,EN,,0,0,0,,Or n, standing for a number. Dialogue: 0,0:06:50.04,0:06:52.25,EN,,0,0,0,,Or e, standing for an empty list. Dialogue: 0,0:06:54.81,0:06:55.83,EN,,0,0,0,,The end of the list. Dialogue: 0,0:06:57.02,0:06:58.59,EN,,0,0,0,,And so if we wish to represent Dialogue: 0,0:06:58.99,0:06:59.97,EN,,0,0,0,,an object like this, Dialogue: 0,0:07:00.01,0:07:02.16,EN,,0,0,0,,the list beginning with 1, 2 Dialogue: 0,0:07:02.65,0:07:04.01,EN,,0,0,0,,and then having a 3 and a 4 Dialogue: 0,0:07:04.01,0:07:05.50,EN,,0,0,0,,and then having a 3 and a 4 as its second and third elements. Dialogue: 0,0:07:06.43,0:07:08.83,EN,,0,0,0,,A list containing a list as its first part Dialogue: 0,0:07:09.35,0:07:10.65,EN,,0,0,0,,and then two numbers Dialogue: 0,0:07:10.65,0:07:12.00,EN,,0,0,0,,as a second and third parts. Dialogue: 0,0:07:12.87,0:07:14.81,EN,,0,0,0,,Then of course we draw it sort of like this these days, Dialogue: 0,0:07:14.84,0:07:16.67,EN,,0,0,0,,in box-and-pointer notation. Dialogue: 0,0:07:17.32,0:07:18.00,EN,,0,0,0,,And you see, Dialogue: 0,0:07:18.00,0:07:20.04,EN,,0,0,0,,these are the three cells Dialogue: 0,0:07:20.25,0:07:22.01,EN,,0,0,0,,that have as their car pointer Dialogue: 0,0:07:22.27,0:07:27.10,EN,,0,0,0,,the object which is either 1, 2 or 3 or 4. Dialogue: 0,0:07:28.39,0:07:29.75,EN,,0,0,0,,And then of course the 1, 2, Dialogue: 0,0:07:29.75,0:07:31.32,EN,,0,0,0,,the car of this entire structure, Dialogue: 0,0:07:31.32,0:07:32.65,EN,,0,0,0,,is itself a substructure Dialogue: 0,0:07:32.88,0:07:34.75,EN,,0,0,0,,which contains a sublist like that. Dialogue: 0,0:07:35.94,0:07:37.07,EN,,0,0,0,,What I'm about to do Dialogue: 0,0:07:37.20,0:07:39.92,EN,,0,0,0,,is put down places which are-- Dialogue: 0,0:07:39.95,0:07:41.46,EN,,0,0,0,,I'm going to assign indices. Dialogue: 0,0:07:41.84,0:07:43.40,EN,,0,0,0,,Like this 1, over here, Dialogue: 0,0:07:43.56,0:07:47.05,EN,,0,0,0,,represents the index of this cell. Dialogue: 0,0:07:49.85,0:07:51.47,EN,,0,0,0,,But that pointer that we see here Dialogue: 0,0:07:52.37,0:07:54.86,EN,,0,0,0,,is a reference to the Dialogue: 0,0:07:55.07,0:07:57.29,EN,,0,0,0,,pair of pigeonholes in the cars and the cdrs Dialogue: 0,0:07:57.40,0:07:58.67,EN,,0,0,0,,that are labeled by 1 Dialogue: 0,0:07:58.76,0:08:00.33,EN,,0,0,0,,in my linear memory down here. Dialogue: 0,0:08:02.00,0:08:04.06,EN,,0,0,0,,So if I wish to impose this structure Dialogue: 0,0:08:04.16,0:08:05.26,EN,,0,0,0,,on my linear memory, Dialogue: 0,0:08:05.85,0:08:07.52,EN,,0,0,0,,what I do is I say, oh yes, Dialogue: 0,0:08:07.52,0:08:11.88,EN,,0,0,0,,why don't we drop this into cell 1? Dialogue: 0,0:08:11.95,0:08:12.66,EN,,0,0,0,,Well I said, I pick 1. Dialogue: 0,0:08:12.66,0:08:13.85,EN,,0,0,0,,There's 1. OK? Dialogue: 0,0:08:14.27,0:08:16.22,EN,,0,0,0,,And that says that its car, Dialogue: 0,0:08:16.22,0:08:17.74,EN,,0,0,0,,I'm going to assign it to be a pair. Dialogue: 0,0:08:17.95,0:08:18.72,EN,,0,0,0,,It's a pair, Dialogue: 0,0:08:20.02,0:08:21.55,EN,,0,0,0,,which is in index 5. Dialogue: 0,0:08:22.59,0:08:23.90,EN,,0,0,0,,And the cdr, Dialogue: 0,0:08:23.90,0:08:25.13,EN,,0,0,0,,which is this one over here, Dialogue: 0,0:08:25.39,0:08:26.13,EN,,0,0,0,,is a pair Dialogue: 0,0:08:26.13,0:08:27.70,EN,,0,0,0,,which I'm going to stick into place 2. Dialogue: 0,0:08:28.34,0:08:28.98,EN,,0,0,0,,p2. Dialogue: 0,0:08:30.89,0:08:32.95,EN,,0,0,0,,And take a look at p2. Dialogue: 0,0:08:32.95,0:08:34.72,EN,,0,0,0,,Oh yes, well p2 is a thing Dialogue: 0,0:08:34.90,0:08:37.22,EN,,0,0,0,,whose car is the number 3, Dialogue: 0,0:08:37.34,0:08:38.64,EN,,0,0,0,,so as you see, an n3. Dialogue: 0,0:08:39.52,0:08:41.52,EN,,0,0,0,,And whose cdr, over here, Dialogue: 0,0:08:41.72,0:08:43.40,EN,,0,0,0,,is a pair, Dialogue: 0,0:08:43.97,0:08:45.81,EN,,0,0,0,,which lives in place 4. Dialogue: 0,0:08:46.64,0:08:47.79,EN,,0,0,0,,So that's what this p4 is. Dialogue: 0,0:08:48.65,0:08:51.16,EN,,0,0,0,,p4 is a number Dialogue: 0,0:08:51.85,0:08:53.87,EN,,0,0,0,,whose value is 4 in its car Dialogue: 0,0:08:54.60,0:08:55.65,EN,,0,0,0,,and whose cdr Dialogue: 0,0:08:55.84,0:08:58.48,EN,,0,0,0,,is an empty list right there. Dialogue: 0,0:08:59.17,0:08:59.90,EN,,0,0,0,,And that ends it. Dialogue: 0,0:09:00.69,0:09:04.57,EN,,0,0,0,,So this is the traditional way of representing Dialogue: 0,0:09:04.90,0:09:09.55,EN,,0,0,0,,this kind of binary tree in a linear memory. Dialogue: 0,0:09:11.62,0:09:15.10,EN,,0,0,0,,Now the next question, of course, Dialogue: 0,0:09:15.10,0:09:16.36,EN,,0,0,0,,that we might want to worry about Dialogue: 0,0:09:16.60,0:09:18.19,EN,,0,0,0,,is just a little bit of implementation. Dialogue: 0,0:09:18.44,0:09:20.33,EN,,0,0,0,,That means that when I write procedures Dialogue: 0,0:09:20.36,0:09:23.62,EN,,0,0,0,,of the form assigned a, Dialogue: 0,0:09:24.54,0:09:27.10,EN,,0,0,0,,lines of register machine code Dialogue: 0,0:09:27.21,0:09:30.14,EN,,0,0,0,,of the form assigned a, the car of fetch of b, Dialogue: 0,0:09:30.84,0:09:31.85,EN,,0,0,0,,what I really mean Dialogue: 0,0:09:31.97,0:09:37.10,EN,,0,0,0,,is addressing these elements. Dialogue: 0,0:09:38.74,0:09:40.25,EN,,0,0,0,,And so we're going to think of that as Dialogue: 0,0:09:40.68,0:09:42.94,EN,,0,0,0,,a abbreviation for it. Dialogue: 0,0:09:44.47,0:09:46.33,EN,,0,0,0,,Now of course in order to write that down Dialogue: 0,0:09:46.35,0:09:48.59,EN,,0,0,0,,I'm going to introduce some sort of a structure Dialogue: 0,0:09:48.62,0:09:49.42,EN,,0,0,0,,called a vector. Dialogue: 0,0:09:52.12,0:09:53.31,EN,,0,0,0,,And we're going to have something which will Dialogue: 0,0:09:53.48,0:09:54.54,EN,,0,0,0,,reference a vector, Dialogue: 0,0:09:56.84,0:09:58.51,EN,,0,0,0,,just so we can write it down. Dialogue: 0,0:09:58.71,0:10:00.22,EN,,0,0,0,,Which takes the name of the vector, Dialogue: 0,0:10:01.02,0:10:03.97,EN,,0,0,0,,or the-- I don't think that name is the right word. Dialogue: 0,0:10:03.97,0:10:09.40,EN,,0,0,0,,Which takes the vector and the index, Dialogue: 0,0:10:11.20,0:10:13.05,EN,,0,0,0,,and I have to have a way of setting one of those Dialogue: 0,0:10:13.10,0:10:14.27,EN,,0,0,0,,with something called a vector set, Dialogue: 0,0:10:14.65,0:10:15.60,EN,,0,0,0,,I don't really care. Dialogue: 0,0:10:16.28,0:10:17.55,EN,,0,0,0,,But let's look, for example, Dialogue: 0,0:10:18.11,0:10:20.42,EN,,0,0,0,,at then that kind of implementation Dialogue: 0,0:10:21.25,0:10:23.18,EN,,0,0,0,,of car and cdr. Dialogue: 0,0:10:26.47,0:10:28.41,EN,,0,0,0,,So for example if I happen to have Dialogue: 0,0:10:28.88,0:10:30.80,EN,,0,0,0,,a register b, Dialogue: 0,0:10:31.15,0:10:34.64,EN,,0,0,0,,which contains the type index of a pair, Dialogue: 0,0:10:35.95,0:10:38.80,EN,,0,0,0,,and therefore it is the pointer to a pair, Dialogue: 0,0:10:39.35,0:10:40.85,EN,,0,0,0,,then I could take the car of that and Dialogue: 0,0:10:41.55,0:10:44.11,EN,,0,0,0,,OK if I-- write this down-- I might put that in register a. Dialogue: 0,0:10:44.49,0:10:46.86,EN,,0,0,0,,What that really is is a representation of Dialogue: 0,0:10:47.37,0:10:50.19,EN,,0,0,0,,the assign to a, Dialogue: 0,0:10:50.19,0:10:51.92,EN,,0,0,0,,the value of vector reffing-- Dialogue: 0,0:10:52.80,0:10:55.24,EN,,0,0,0,,or array indexing, if you will-- or something, Dialogue: 0,0:10:55.42,0:10:57.63,EN,,0,0,0,,the cars object-- Dialogue: 0,0:10:58.40,0:11:00.92,EN,,0,0,0,,whatever that is-- with the index, b. Dialogue: 0,0:11:02.65,0:11:03.63,EN,,0,0,0,,And similarly for cdr. Dialogue: 0,0:11:04.10,0:11:05.72,EN,,0,0,0,,And we can do the same thing Dialogue: 0,0:11:05.90,0:11:08.32,EN,,0,0,0,,for assignment to data structures, Dialogue: 0,0:11:08.92,0:11:10.92,EN,,0,0,0,,If we need to do that sort of things at all. Dialogue: 0,0:11:11.84,0:11:13.80,EN,,0,0,0,,It's not too hard to build that. Dialogue: 0,0:11:14.58,0:11:15.72,EN,,0,0,0,,Well now the next question is Dialogue: 0,0:11:15.72,0:11:17.00,EN,,0,0,0,,how are we going to do allocation. Dialogue: 0,0:11:18.01,0:11:20.13,EN,,0,0,0,,And every so often I say I want a cons. Dialogue: 0,0:11:21.40,0:11:23.42,EN,,0,0,0,,Now conses don't grow on trees. Dialogue: 0,0:11:23.79,0:11:24.81,EN,,0,0,0,,Or maybe they should. Dialogue: 0,0:11:25.34,0:11:26.56,EN,,0,0,0,,But I have to have some way Dialogue: 0,0:11:26.70,0:11:28.97,EN,,0,0,0,,I have to have some way of getting the next one. Dialogue: 0,0:11:29.98,0:11:31.47,EN,,0,0,0,,I have to have some idea of Dialogue: 0,0:11:31.47,0:11:33.04,EN,,0,0,0,,if their memory is unused Dialogue: 0,0:11:33.69,0:11:35.05,EN,,0,0,0,,that I might want to allocate from. Dialogue: 0,0:11:35.63,0:11:37.38,EN,,0,0,0,,And there are many schemes for doing this. Dialogue: 0,0:11:37.38,0:11:39.07,EN,,0,0,0,,And the particular thing I'm showing you right now Dialogue: 0,0:11:39.23,0:11:40.45,EN,,0,0,0,,is not essential. Dialogue: 0,0:11:42.10,0:11:43.18,EN,,0,0,0,,However it's convenient Dialogue: 0,0:11:43.20,0:11:44.44,EN,,0,0,0,,and has been done many times. Dialogue: 0,0:11:44.60,0:11:47.20,EN,,0,0,0,,It's one schemes called the free list allocation scheme. Dialogue: 0,0:11:47.66,0:11:48.68,EN,,0,0,0,,What that means is Dialogue: 0,0:11:48.68,0:11:51.12,EN,,0,0,0,,that all of the free memory that there is in the world Dialogue: 0,0:11:51.55,0:11:53.08,EN,,0,0,0,,is linked together in a linked list, Dialogue: 0,0:11:54.55,0:11:56.22,EN,,0,0,0,,just like all the other stuff. Dialogue: 0,0:11:56.96,0:11:59.07,EN,,0,0,0,,And whenever you need a free cell Dialogue: 0,0:11:59.07,0:12:00.12,EN,,0,0,0,,to make a new cons, Dialogue: 0,0:12:00.95,0:12:02.26,EN,,0,0,0,,you grab the first one Dialogue: 0,0:12:02.26,0:12:03.82,EN,,0,0,0,,make the free list be the cdr of it, Dialogue: 0,0:12:04.32,0:12:05.55,EN,,0,0,0,,and then allocate that. Dialogue: 0,0:12:06.03,0:12:08.32,EN,,0,0,0,,And so what that looks like is something like this. Dialogue: 0,0:12:09.53,0:12:13.32,EN,,0,0,0,,Here we have the free list Dialogue: 0,0:12:13.95,0:12:16.81,EN,,0,0,0,,starting in 6. Dialogue: 0,0:12:18.51,0:12:23.47,EN,,0,0,0,,And what that is is a pointer-off to say 8. Dialogue: 0,0:12:24.86,0:12:25.62,EN,,0,0,0,,So what it says is, Dialogue: 0,0:12:25.62,0:12:26.55,EN,,0,0,0,,this one is free Dialogue: 0,0:12:26.55,0:12:27.95,EN,,0,0,0,,and the next one is an 8. Dialogue: 0,0:12:28.87,0:12:29.88,EN,,0,0,0,,This one is free Dialogue: 0,0:12:30.04,0:12:32.08,EN,,0,0,0,,and the next one is in 3, Dialogue: 0,0:12:32.32,0:12:33.45,EN,,0,0,0,,the next one that's free. Dialogue: 0,0:12:33.93,0:12:34.95,EN,,0,0,0,,That one's free Dialogue: 0,0:12:35.04,0:12:37.68,EN,,0,0,0,,and the next one is in 0. Dialogue: 0,0:12:37.87,0:12:38.49,EN,,0,0,0,,That one's free Dialogue: 0,0:12:38.52,0:12:39.82,EN,,0,0,0,,and the next one's in 15. Dialogue: 0,0:12:40.94,0:12:41.84,EN,,0,0,0,,Something like that. Dialogue: 0,0:12:42.78,0:12:44.64,EN,,0,0,0,,We can imagine having such a structure. Dialogue: 0,0:12:46.40,0:12:48.03,EN,,0,0,0,,Given that we have something like that, Dialogue: 0,0:12:49.45,0:12:50.92,EN,,0,0,0,,then it's possible to Dialogue: 0,0:12:50.92,0:12:52.22,EN,,0,0,0,,just get one when you need it. Dialogue: 0,0:12:53.82,0:12:56.46,EN,,0,0,0,,And so a program for doing cons, Dialogue: 0,0:12:57.45,0:12:59.13,EN,,0,0,0,,this is what cons might turn into. Dialogue: 0,0:12:59.32,0:13:02.57,EN,,0,0,0,,To assign to a register A the result of cons-ing, Dialogue: 0,0:13:02.95,0:13:05.82,EN,,0,0,0,,a B onto C, Dialogue: 0,0:13:06.20,0:13:09.04,EN,,0,0,0,,the value in this containing B and the value containing C, Dialogue: 0,0:13:09.27,0:13:10.52,EN,,0,0,0,,what we have to do is Dialogue: 0,0:13:10.56,0:13:12.24,EN,,0,0,0,,get the current tail ahead of the freelist, Dialogue: 0,0:13:12.47,0:13:14.30,EN,,0,0,0,,make the free list be its cdr. Dialogue: 0,0:13:15.64,0:13:18.33,EN,,0,0,0,,Then we have to change the cars Dialogue: 0,0:13:18.41,0:13:22.49,EN,,0,0,0,,to be the thing we're making up to be in A Dialogue: 0,0:13:23.13,0:13:25.45,EN,,0,0,0,,to be the B, the thing in B. Dialogue: 0,0:13:25.90,0:13:28.65,EN,,0,0,0,,And we have to make change the cdrs of Dialogue: 0,0:13:29.20,0:13:31.72,EN,,0,0,0,,the thing that's in A to be C. Dialogue: 0,0:13:33.20,0:13:34.76,EN,,0,0,0,,And then what we have in A Dialogue: 0,0:13:34.78,0:13:36.65,EN,,0,0,0,,is the right new frob, whatever it is. Dialogue: 0,0:13:36.81,0:13:37.92,EN,,0,0,0,,The object that we want. Dialogue: 0,0:13:40.47,0:13:42.50,EN,,0,0,0,,Now there's a little bit of Dialogue: 0,0:13:42.50,0:13:43.97,EN,,0,0,0,,a cheat here that I haven't told you about, Dialogue: 0,0:13:43.97,0:13:45.32,EN,,0,0,0,,which is somewhere around here Dialogue: 0,0:13:45.53,0:13:47.32,EN,,0,0,0,,I haven't set the type of the thing that I've Dialogue: 0,0:13:48.45,0:13:50.48,EN,,0,0,0,,the type of the thing Dialogue: 0,0:13:50.51,0:13:51.87,EN,,0,0,0,,that I'm cons-ing up to be a pair, Dialogue: 0,0:13:52.30,0:13:53.05,EN,,0,0,0,,and I ought to. Dialogue: 0,0:13:53.51,0:13:56.57,EN,,0,0,0,,So there should be some sort of bits here are being set, Dialogue: 0,0:13:56.60,0:13:57.76,EN,,0,0,0,,and I just haven't written that down. Dialogue: 0,0:13:59.81,0:14:00.86,EN,,0,0,0,,We could have arranged it, of course, Dialogue: 0,0:14:00.89,0:14:02.45,EN,,0,0,0,,for the free list to be made out of pairs. Dialogue: 0,0:14:03.10,0:14:04.88,EN,,0,0,0,,And so then there's no problem with that. Dialogue: 0,0:14:06.43,0:14:07.74,EN,,0,0,0,,But that sort of-- Dialogue: 0,0:14:07.82,0:14:09.92,EN,,0,0,0,,again, an inessential detail in a way Dialogue: 0,0:14:10.22,0:14:12.88,EN,,0,0,0,,some particular programmer or architect Dialogue: 0,0:14:12.92,0:14:14.27,EN,,0,0,0,,or whatever might manufacture Dialogue: 0,0:14:14.33,0:14:16.68,EN,,0,0,0,,his machine or Lisp system. Dialogue: 0,0:14:17.54,0:14:18.71,EN,,0,0,0,,So for example, Dialogue: 0,0:14:19.07,0:14:20.24,EN,,0,0,0,,just looking at this, Dialogue: 0,0:14:20.65,0:14:23.45,EN,,0,0,0,,to allocate Dialogue: 0,0:14:23.55,0:14:26.83,EN,,0,0,0,,given that I had already the structure that you saw before, Dialogue: 0,0:14:27.21,0:14:30.26,EN,,0,0,0,,supposing I wanted to allocate a new cell, Dialogue: 0,0:14:30.55,0:14:36.61,EN,,0,0,0,,which is going to be representation of list one, one, two, Dialogue: 0,0:14:37.24,0:14:39.87,EN,,0,0,0,,where already one two was the car Dialogue: 0,0:14:40.28,0:14:42.16,EN,,0,0,0,,of the list we were playing with before. Dialogue: 0,0:14:43.43,0:14:44.45,EN,,0,0,0,,Well that's not so hard. Dialogue: 0,0:14:44.78,0:14:46.20,EN,,0,0,0,,I stored that one in one, Dialogue: 0,0:14:46.20,0:14:49.17,EN,,0,0,0,,so p1 one is the representation of this. Dialogue: 0,0:14:49.53,0:14:50.83,EN,,0,0,0,,This is p5. Dialogue: 0,0:14:51.67,0:14:53.51,EN,,0,0,0,,That's going to be the cdr of this. Dialogue: 0,0:14:54.07,0:14:55.52,EN,,0,0,0,,Now we're going to pull something off the free list, Dialogue: 0,0:14:55.52,0:14:57.30,EN,,0,0,0,,but remember the free list started at six. Dialogue: 0,0:14:57.78,0:15:00.18,EN,,0,0,0,,The new free list after this allocation is eight, Dialogue: 0,0:15:00.60,0:15:02.55,EN,,0,0,0,,a free list beginning at eight. Dialogue: 0,0:15:02.89,0:15:03.52,EN,,0,0,0,,And of course Dialogue: 0,0:15:03.72,0:15:06.04,EN,,0,0,0,,in six now we have a number one, Dialogue: 0,0:15:06.15,0:15:07.10,EN,,0,0,0,,which is what we wanted, Dialogue: 0,0:15:07.39,0:15:11.56,EN,,0,0,0,,with its cdr being the pair starting in location five. Dialogue: 0,0:15:13.33,0:15:14.50,EN,,0,0,0,,And that's no big deal. Dialogue: 0,0:15:16.81,0:15:20.45,EN,,0,0,0,,So the only problem really remaining here is, Dialogue: 0,0:15:21.00,0:15:23.40,EN,,0,0,0,,well, I don't have an infinitely large memory. Dialogue: 0,0:15:25.08,0:15:26.66,EN,,0,0,0,,If I do this for a little while, Dialogue: 0,0:15:27.25,0:15:28.00,EN,,0,0,0,,say, for example, Dialogue: 0,0:15:28.01,0:15:30.14,EN,,0,0,0,,supposing it takes me a microsecond to do a cons, Dialogue: 0,0:15:30.60,0:15:32.97,EN,,0,0,0,,and I have a million cons memory Dialogue: 0,0:15:33.60,0:15:35.27,EN,,0,0,0,,then I'm only going to run out in a second, Dialogue: 0,0:15:35.95,0:15:37.00,EN,,0,0,0,,and that's pretty bad. Dialogue: 0,0:15:38.00,0:15:40.62,EN,,0,0,0,,So what we do to prevent that disaster, Dialogue: 0,0:15:40.62,0:15:42.19,EN,,0,0,0,,that ecological disaster, Dialogue: 0,0:15:42.60,0:15:44.30,EN,,0,0,0,,talk about right after questions. Dialogue: 0,0:15:44.30,0:15:45.26,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:15:51.50,0:15:51.69,EN,,0,0,0,,Yes. Dialogue: 0,0:15:52.03,0:15:54.67,EN,,0,0,0,,AUDIENCE: In the environment diagrams that we were drawing Dialogue: 0,0:15:54.67,0:15:58.25,EN,,0,0,0,,we would use the body of procedures, Dialogue: 0,0:15:58.25,0:16:00.67,EN,,0,0,0,,and you would eventually wind up with Dialogue: 0,0:16:00.80,0:16:03.60,EN,,0,0,0,,things that were no longer useful in that structure. Dialogue: 0,0:16:03.60,0:16:04.16,EN,,0,0,0,,PROFESSOR: Yes, madam. Dialogue: 0,0:16:04.93,0:16:06.67,EN,,0,0,0,,AUDIENCE: How is that represented? Dialogue: 0,0:16:06.76,0:16:08.75,EN,,0,0,0,,PROFESSOR: There's two problems here. OK? Dialogue: 0,0:16:09.18,0:16:10.25,EN,,0,0,0,,One you were asking Dialogue: 0,0:16:10.25,0:16:13.43,EN,,0,0,0,,is that material becomes useless. Dialogue: 0,0:16:13.87,0:16:14.92,EN,,0,0,0,,We'll talk about that in a second. Dialogue: 0,0:16:14.92,0:16:17.00,EN,,0,0,0,,That has to do with how to prevent ecological disasters. Dialogue: 0,0:16:17.63,0:16:19.20,EN,,0,0,0,,Right? If I make a lot of garbage Dialogue: 0,0:16:19.20,0:16:21.39,EN,,0,0,0,,I have to somehow be able to clean up after myself. Dialogue: 0,0:16:21.82,0:16:22.97,EN,,0,0,0,,And we'll talk about that in a second. Dialogue: 0,0:16:23.43,0:16:24.57,EN,,0,0,0,,The other question you're asking Dialogue: 0,0:16:24.57,0:16:27.21,EN,,0,0,0,,is how you represent the environments, I think. Dialogue: 0,0:16:27.28,0:16:27.60,EN,,0,0,0,,AUDIENCE: Yes. Dialogue: 0,0:16:27.60,0:16:28.19,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:16:28.19,0:16:30.62,EN,,0,0,0,,And the environment structures can be represented in arbitrary ways. Dialogue: 0,0:16:30.92,0:16:31.78,EN,,0,0,0,,There are lots of them. Dialogue: 0,0:16:31.78,0:16:33.34,EN,,0,0,0,,I mean, here I'm just telling you about list cells. Dialogue: 0,0:16:33.63,0:16:34.92,EN,,0,0,0,,Of course every real system Dialogue: 0,0:16:34.92,0:16:36.72,EN,,0,0,0,,has vectors of arbitrary length Dialogue: 0,0:16:36.72,0:16:39.15,EN,,0,0,0,,as well as the vectors of length, too, Dialogue: 0,0:16:39.31,0:16:40.51,EN,,0,0,0,,which represent list cells. Dialogue: 0,0:16:41.08,0:16:44.90,EN,,0,0,0,,And the environment structures that one uses in a Dialogue: 0,0:16:44.90,0:16:46.99,EN,,0,0,0,,professionally written Lisp system Dialogue: 0,0:16:47.30,0:16:49.69,EN,,0,0,0,,tend to be vectors Dialogue: 0,0:16:49.69,0:16:51.92,EN,,0,0,0,,which contain a number of elements approximately Dialogue: 0,0:16:51.92,0:16:54.60,EN,,0,0,0,,equal to the number of arguments-- a little bit more Dialogue: 0,0:16:55.35,0:16:56.86,EN,,0,0,0,,because you need sort of glue. Dialogue: 0,0:16:57.40,0:17:00.74,EN,,0,0,0,,OK? So remember, the environment is in a frame. Dialogue: 0,0:17:00.74,0:17:03.98,EN,,0,0,0,,The frames are constructed by applying a procedure. Dialogue: 0,0:17:03.98,0:17:04.78,EN,,0,0,0,,In doing so, Dialogue: 0,0:17:04.80,0:17:07.60,EN,,0,0,0,,an allocation is made of a place Dialogue: 0,0:17:07.64,0:17:11.27,EN,,0,0,0,,which is the number of arguments long plus some glue Dialogue: 0,0:17:11.27,0:17:12.71,EN,,0,0,0,,that gets linked into a chain. Dialogue: 0,0:17:13.32,0:17:15.66,EN,,0,0,0,,It's just like algol at that level. Dialogue: 0,0:17:19.81,0:17:20.72,EN,,0,0,0,,There any other questions? Dialogue: 0,0:17:23.70,0:17:23.92,EN,,0,0,0,,OK. Dialogue: 0,0:17:23.92,0:17:25.55,EN,,0,0,0,,Thank you, and let's take a short break. Dialogue: 0,0:17:26.35,0:17:45.48,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:17:45.53,0:17:50.01,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:17:55.74,0:17:59.04,EN,,0,0,0,,By: Prof. Harold Abelson && Sussman Jay Sussman Dialogue: 0,0:17:59.13,0:18:04.22,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:18:04.32,0:18:09.87,EN,,0,0,0,,Storage Allocation & Garbage Collection Dialogue: 0,0:18:12.27,0:18:14.24,EN,,0,0,0,,PROFESSOR: Well, as I just said, Dialogue: 0,0:18:14.55,0:18:15.50,EN,,0,0,0,,computer memories Dialogue: 0,0:18:15.82,0:18:17.96,EN,,0,0,0,,supplied by the semiconductor manufacturers Dialogue: 0,0:18:18.16,0:18:19.00,EN,,0,0,0,,are finite. Dialogue: 0,0:18:19.42,0:18:20.40,EN,,0,0,0,,And that's quite a pity. Dialogue: 0,0:18:21.62,0:18:23.35,EN,,0,0,0,,It might not always be that way. Dialogue: 0,0:18:24.03,0:18:25.40,EN,,0,0,0,,Just for a quick calculation, Dialogue: 0,0:18:25.44,0:18:28.86,EN,,0,0,0,,you can see that it's possible that if memory's Dialogue: 0,0:18:28.86,0:18:30.80,EN,,0,0,0,,prices keep going at the rate they're going Dialogue: 0,0:18:31.22,0:18:33.68,EN,,0,0,0,,that if you still took a microsecond second to do a cons, Dialogue: 0,0:18:34.42,0:18:35.90,EN,,0,0,0,,then-- first of all, everybody Dialogue: 0,0:18:35.90,0:18:37.07,EN,,0,0,0,,should know that there's about pi Dialogue: 0,0:18:37.10,0:18:38.86,EN,,0,0,0,,times ten to the seventh seconds in a year. Dialogue: 0,0:18:39.45,0:18:41.12,EN,,0,0,0,,And so that would be Dialogue: 0,0:18:41.50,0:18:42.73,EN,,0,0,0,,ten to the seventh plus ten to the sixth Dialogue: 0,0:18:42.73,0:18:43.94,EN,,0,0,0,,is ten to the thirteenth. Dialogue: 0,0:18:43.94,0:18:45.50,EN,,0,0,0,,So there's maybe ten to the fourteenth conses Dialogue: 0,0:18:45.50,0:18:46.80,EN,,0,0,0,,in the life of a machine. Dialogue: 0,0:18:47.52,0:18:49.40,EN,,0,0,0,,If there was ten to the fourteenth words of memory Dialogue: 0,0:18:49.68,0:18:50.57,EN,,0,0,0,,on your machine, Dialogue: 0,0:18:51.20,0:18:52.16,EN,,0,0,0,,you'd never run out. Dialogue: 0,0:18:53.04,0:18:53.85,EN,,0,0,0,,OK so that will be, Dialogue: 0,0:18:53.95,0:18:55.76,EN,,0,0,0,,And that's not completely unreasonable. Dialogue: 0,0:18:56.31,0:18:58.46,EN,,0,0,0,,Ten to the fourteenth is not a very large number. Dialogue: 0,0:19:01.45,0:19:04.70,EN,,0,0,0,,Even for... I don't think it is. Dialogue: 0,0:19:05.18,0:19:07.39,EN,,0,0,0,,But then again I like to play with astronomy. Dialogue: 0,0:19:07.93,0:19:11.04,EN,,0,0,0,,It's at least ten to the eighteenth centimeters Dialogue: 0,0:19:11.10,0:19:12.45,EN,,0,0,0,,between us and the nearest star. Dialogue: 0,0:19:12.93,0:19:18.85,EN,,0,0,0,,But the thing I'm about to worry about is, Dialogue: 0,0:19:19.15,0:19:21.27,EN,,0,0,0,,at least in the current economic state of affairs, Dialogue: 0,0:19:21.27,0:19:23.57,EN,,0,0,0,,ten to the fourteenth pieces of memory is expensive. Dialogue: 0,0:19:24.20,0:19:26.62,EN,,0,0,0,,And so I suppose what we have to do Dialogue: 0,0:19:26.81,0:19:28.51,EN,,0,0,0,,is make do with much smaller memories. Dialogue: 0,0:19:30.02,0:19:30.59,EN,,0,0,0,,Now Dialogue: 0,0:19:32.84,0:19:35.07,EN,,0,0,0,,in general we want to have an illusion of infinity. Dialogue: 0,0:19:35.80,0:19:37.22,EN,,0,0,0,,All we need to do is arrange it Dialogue: 0,0:19:37.82,0:19:39.68,EN,,0,0,0,,so that whenever you look, the thing is there. Dialogue: 0,0:19:41.92,0:19:45.55,EN,,0,0,0,,That's, that's really an important idea. Dialogue: 0,0:19:49.54,0:19:51.97,EN,,0,0,0,,A person or a computer lives only a finite amount of time Dialogue: 0,0:19:52.32,0:19:54.59,EN,,0,0,0,,and can only take a finite number of looks at something. Dialogue: 0,0:19:55.28,0:19:57.37,EN,,0,0,0,,And so you really only need a finite amount of stuff. Dialogue: 0,0:19:58.19,0:19:59.00,EN,,0,0,0,,But you have to arrange it Dialogue: 0,0:19:59.00,0:20:00.38,EN,,0,0,0,,so no matter how much there is, Dialogue: 0,0:20:00.77,0:20:03.46,EN,,0,0,0,,how much you really claim there is, Dialogue: 0,0:20:03.46,0:20:04.74,EN,,0,0,0,,there's always enough stuff Dialogue: 0,0:20:04.74,0:20:06.90,EN,,0,0,0,,so that when you take a look, it's there. Dialogue: 0,0:20:06.90,0:20:08.15,EN,,0,0,0,,And so you only need a finite amount. Dialogue: 0,0:20:08.75,0:20:09.94,EN,,0,0,0,,But let's see. Dialogue: 0,0:20:11.63,0:20:13.32,EN,,0,0,0,,One problem is, as was brought up, Dialogue: 0,0:20:13.92,0:20:15.45,EN,,0,0,0,,that there are possible ways Dialogue: 0,0:20:15.72,0:20:17.84,EN,,0,0,0,,that there is lots of stuff Dialogue: 0,0:20:17.88,0:20:19.16,EN,,0,0,0,,that we make that we don't need. Dialogue: 0,0:20:19.41,0:20:21.81,EN,,0,0,0,,And we could recycle the material out of which its made. Dialogue: 0,0:20:22.62,0:20:23.53,EN,,0,0,0,,An example Dialogue: 0,0:20:24.15,0:20:25.79,EN,,0,0,0,,for is, is the fact Dialogue: 0,0:20:25.79,0:20:28.40,EN,,0,0,0,,when we're building environment structures, Dialogue: 0,0:20:28.40,0:20:30.47,EN,,0,0,0,,and we do so every time we call a procedure. Dialogue: 0,0:20:30.47,0:20:32.56,EN,,0,0,0,,We have built in it a environment frame. Dialogue: 0,0:20:33.14,0:20:34.03,EN,,0,0,0,,That environment frame Dialogue: 0,0:20:34.22,0:20:36.07,EN,,0,0,0,,doesn't necessarily have a very long lifetime. Dialogue: 0,0:20:36.73,0:20:38.69,EN,,0,0,0,,Its lifetime, meaning its usefulness, Dialogue: 0,0:20:39.42,0:20:42.60,EN,,0,0,0,,may exist only over the invocation of the procedure. Dialogue: 0,0:20:42.85,0:20:45.27,EN,,0,0,0,,Or if the procedure exports another procedure Dialogue: 0,0:20:45.27,0:20:46.67,EN,,0,0,0,,by returning it as a value Dialogue: 0,0:20:46.87,0:20:48.52,EN,,0,0,0,,and that procedure is defined inside of it, Dialogue: 0,0:20:48.52,0:20:50.80,EN,,0,0,0,,well then the lifetime of the Dialogue: 0,0:20:51.07,0:20:53.39,EN,,0,0,0,,frame of the outer procedure still is Dialogue: 0,0:20:53.50,0:20:56.12,EN,,0,0,0,,only the lifetime of the procedure Dialogue: 0,0:20:57.02,0:20:57.90,EN,,0,0,0,,which was exported. Dialogue: 0,0:20:58.53,0:20:59.57,EN,,0,0,0,,And so ultimately, Dialogue: 0,0:20:59.57,0:21:00.97,EN,,0,0,0,,a lot of that is garbage. Dialogue: 0,0:21:01.96,0:21:04.10,EN,,0,0,0,,There are other ways of producing garbage as well. Dialogue: 0,0:21:05.37,0:21:06.67,EN,,0,0,0,,Users produce garbage. Dialogue: 0,0:21:07.24,0:21:08.07,EN,,0,0,0,,An example of Dialogue: 0,0:21:08.07,0:21:10.22,EN,,0,0,0,,user garbage is something like this. Dialogue: 0,0:21:10.93,0:21:14.00,EN,,0,0,0,,If we write a program to, for example, Dialogue: 0,0:21:14.00,0:21:15.80,EN,,0,0,0,,append two lists together, Dialogue: 0,0:21:16.05,0:21:18.14,EN,,0,0,0,,well one way to do it is to Dialogue: 0,0:21:18.32,0:21:21.37,EN,,0,0,0,,reverse the first list onto the empty list Dialogue: 0,0:21:21.37,0:21:23.72,EN,,0,0,0,,and reverse that onto the second list. Dialogue: 0,0:21:24.70,0:21:26.92,EN,,0,0,0,,Now that's not terribly bad way of doing it. Dialogue: 0,0:21:28.16,0:21:28.85,EN,,0,0,0,,And however, Dialogue: 0,0:21:28.85,0:21:30.09,EN,,0,0,0,,the intermediate result, Dialogue: 0,0:21:30.11,0:21:32.02,EN,,0,0,0,,which is the reversal of the first list Dialogue: 0,0:21:33.87,0:21:35.57,EN,,0,0,0,,as done by this program, Dialogue: 0,0:21:36.70,0:21:38.52,EN,,0,0,0,,is never going to be accessed ever again Dialogue: 0,0:21:38.52,0:21:40.56,EN,,0,0,0,,after it's copied back on to the second. Dialogue: 0,0:21:41.01,0:21:42.23,EN,,0,0,0,,It's an intermediate result. Dialogue: 0,0:21:43.58,0:21:45.43,EN,,0,0,0,,It's going to be hard to ever see Dialogue: 0,0:21:46.07,0:21:48.05,EN,,0,0,0,,how anybody would ever be able to access it. Dialogue: 0,0:21:48.60,0:21:49.84,EN,,0,0,0,,In fact, it will go away. Dialogue: 0,0:21:51.05,0:21:52.90,EN,,0,0,0,,Now if we make a lot of garbage like that, Dialogue: 0,0:21:52.90,0:21:54.20,EN,,0,0,0,,and we should be allowed to, Dialogue: 0,0:21:54.80,0:21:57.29,EN,,0,0,0,,then there's got to be some way to reclaim that garbage. Dialogue: 0,0:21:58.80,0:22:00.90,EN,,0,0,0,,Well, what I'd like to tell you about now Dialogue: 0,0:22:01.70,0:22:03.77,EN,,0,0,0,,is a very clever technique Dialogue: 0,0:22:04.32,0:22:07.58,EN,,0,0,0,,whereby a Lisp system Dialogue: 0,0:22:07.95,0:22:11.21,EN,,0,0,0,,can prove a small theorem every so often Dialogue: 0,0:22:11.29,0:22:13.50,EN,,0,0,0,,on the form the following piece of junk Dialogue: 0,0:22:14.72,0:22:16.09,EN,,0,0,0,,will never be accessed again. Dialogue: 0,0:22:17.41,0:22:19.80,EN,,0,0,0,,It can have no affect on the future of the computation. Dialogue: 0,0:22:21.40,0:22:23.61,EN,,0,0,0,,It's actually based on a very simple idea. Dialogue: 0,0:22:24.72,0:22:28.06,EN,,0,0,0,,We've designed our computers to look sort of like this. Dialogue: 0,0:22:28.95,0:22:30.67,EN,,0,0,0,,There's some data path, Dialogue: 0,0:22:31.87,0:22:33.40,EN,,0,0,0,,which contains the registers. Dialogue: 0,0:22:34.92,0:22:38.04,EN,,0,0,0,,You know, there are things like exp, and env, Dialogue: 0,0:22:39.04,0:22:42.19,EN,,0,0,0,,and val, and so on. Dialogue: 0,0:22:42.61,0:22:44.02,EN,,0,0,0,,And there's one here called stack, Dialogue: 0,0:22:46.02,0:22:49.45,EN,,0,0,0,,some sort which points off to a structure somewhere, Dialogue: 0,0:22:49.50,0:22:50.22,EN,,0,0,0,,which is the stack. Dialogue: 0,0:22:50.24,0:22:51.48,EN,,0,0,0,,And we'll worry about that in a second. Dialogue: 0,0:22:51.64,0:22:53.62,EN,,0,0,0,,There's some finite controller, Dialogue: 0,0:22:54.38,0:22:56.57,EN,,0,0,0,,finite state machine controller. Dialogue: 0,0:22:56.73,0:22:59.51,EN,,0,0,0,,And there's some control signals that go this way and Dialogue: 0,0:22:59.80,0:23:01.44,EN,,0,0,0,,predicate results that come this way, Dialogue: 0,0:23:01.87,0:23:03.13,EN,,0,0,0,,not the interesting part. Dialogue: 0,0:23:03.35,0:23:06.51,EN,,0,0,0,,There's some sort of structured memory, Dialogue: 0,0:23:06.80,0:23:08.27,EN,,0,0,0,,which I just told you how to make, Dialogue: 0,0:23:08.27,0:23:10.17,EN,,0,0,0,,which may contain a stack. Dialogue: 0,0:23:10.46,0:23:11.48,EN,,0,0,0,,I didn't tell you how to make things Dialogue: 0,0:23:11.48,0:23:12.43,EN,,0,0,0,,of arbitrary shape, Dialogue: 0,0:23:12.56,0:23:13.39,EN,,0,0,0,,only pairs. Dialogue: 0,0:23:13.60,0:23:14.20,EN,,0,0,0,,But in fact Dialogue: 0,0:23:14.35,0:23:15.44,EN,,0,0,0,,with what I've told you can Dialogue: 0,0:23:15.47,0:23:16.96,EN,,0,0,0,,with what I've told you can simulate a stack by a big list. Dialogue: 0,0:23:17.77,0:23:18.85,EN,,0,0,0,,I don't plan to do that, Dialogue: 0,0:23:18.85,0:23:20.01,EN,,0,0,0,,it's not a nice way to do it. Dialogue: 0,0:23:20.36,0:23:22.60,EN,,0,0,0,,But we could have something like that. Dialogue: 0,0:23:22.99,0:23:25.28,EN,,0,0,0,,We have all sorts of little data structures in here Dialogue: 0,0:23:25.64,0:23:27.75,EN,,0,0,0,,that are hooked together in funny ways. Dialogue: 0,0:23:30.11,0:23:32.02,EN,,0,0,0,,They connect to other things. Dialogue: 0,0:23:32.56,0:23:33.25,EN,,0,0,0,,And so on. Dialogue: 0,0:23:33.25,0:23:34.22,EN,,0,0,0,,And ultimately Dialogue: 0,0:23:34.45,0:23:37.19,EN,,0,0,0,,things up there are pointers to these. Dialogue: 0,0:23:37.19,0:23:38.87,EN,,0,0,0,,The things that are in the registers Dialogue: 0,0:23:39.40,0:23:41.40,EN,,0,0,0,,are pointers off to the data structures Dialogue: 0,0:23:41.44,0:23:43.08,EN,,0,0,0,,that live in this list structure memory. Dialogue: 0,0:23:44.91,0:23:49.80,EN,,0,0,0,,Now the truth of the matter is Dialogue: 0,0:23:51.05,0:23:52.56,EN,,0,0,0,,that the entire consciousness Dialogue: 0,0:23:52.57,0:23:53.92,EN,,0,0,0,,of this machine is in these registers. Dialogue: 0,0:23:55.76,0:23:58.51,EN,,0,0,0,,There is no possible way that the machine, Dialogue: 0,0:23:58.75,0:24:01.07,EN,,0,0,0,,if done correctly, if built correctly, Dialogue: 0,0:24:01.37,0:24:03.41,EN,,0,0,0,,can access anything in this list structure memory Dialogue: 0,0:24:04.57,0:24:07.05,EN,,0,0,0,,unless the thing in that list structure memory is Dialogue: 0,0:24:08.09,0:24:10.88,EN,,0,0,0,,is connected by a sequence of data structures Dialogue: 0,0:24:11.64,0:24:13.06,EN,,0,0,0,,to the registers. Dialogue: 0,0:24:15.07,0:24:15.98,EN,,0,0,0,,If it's accessible Dialogue: 0,0:24:16.22,0:24:18.31,EN,,0,0,0,,by legitimate data structure selectors Dialogue: 0,0:24:19.08,0:24:21.12,EN,,0,0,0,,from the pointers that are stored in these registers. Dialogue: 0,0:24:22.28,0:24:24.46,EN,,0,0,0,,Things like array references, perhaps. Dialogue: 0,0:24:24.94,0:24:27.92,EN,,0,0,0,,Or cons cell references, cars and cdrs. Dialogue: 0,0:24:29.08,0:24:30.95,EN,,0,0,0,,But I can't just talk about a random place in this memory, Dialogue: 0,0:24:30.95,0:24:31.95,EN,,0,0,0,,because I can't get to it. Dialogue: 0,0:24:32.74,0:24:34.90,EN,,0,0,0,,These are being arbitrary names I'm not allowed to count, Dialogue: 0,0:24:37.00,0:24:39.16,EN,,0,0,0,,at least as I'm evaluating expressions. Dialogue: 0,0:24:41.62,0:24:42.57,EN,,0,0,0,,If that's the case Dialogue: 0,0:24:43.27,0:24:45.07,EN,,0,0,0,,then there's a very simple theorem to be proved. Dialogue: 0,0:24:47.16,0:24:47.69,EN,,0,0,0,,Which is, Dialogue: 0,0:24:47.90,0:24:50.52,EN,,0,0,0,,if I start with all lead pointers that are in all these registers Dialogue: 0,0:24:51.16,0:24:52.55,EN,,0,0,0,,and recursively chase out, Dialogue: 0,0:24:52.82,0:24:56.15,EN,,0,0,0,,marking all the places I can get to by selectors, Dialogue: 0,0:24:56.90,0:24:59.40,EN,,0,0,0,,then eventually I mark everything they can be gotten to. Dialogue: 0,0:25:00.65,0:25:02.69,EN,,0,0,0,,Anything which is not so marked is garbage Dialogue: 0,0:25:02.69,0:25:03.75,EN,,0,0,0,,and can be recycled. Dialogue: 0,0:25:05.56,0:25:06.20,EN,,0,0,0,,Very simple. Dialogue: 0,0:25:07.20,0:25:09.10,EN,,0,0,0,,Cannot affect the future of the computation. Dialogue: 0,0:25:11.18,0:25:12.84,EN,,0,0,0,,So let me show you that in a particular Dialogue: 0,0:25:13.93,0:25:15.75,EN,,0,0,0,,in a particular example. Dialogue: 0,0:25:17.12,0:25:19.37,EN,,0,0,0,,Now that means I'm going to have to append to my Dialogue: 0,0:25:19.69,0:25:22.08,EN,,0,0,0,,description of the list structure a mark. Dialogue: 0,0:25:23.64,0:25:24.89,EN,,0,0,0,,And so here, for example, Dialogue: 0,0:25:25.37,0:25:27.28,EN,,0,0,0,,is a list structured memory. Dialogue: 0,0:25:29.08,0:25:30.32,EN,,0,0,0,,And in this list structured memory Dialogue: 0,0:25:30.33,0:25:31.33,EN,,0,0,0,,is a list structure Dialogue: 0,0:25:31.33,0:25:33.95,EN,,0,0,0,,beginning in a place I'm going to call-- Dialogue: 0,0:25:35.87,0:25:36.62,EN,,0,0,0,,this is the root. Dialogue: 0,0:25:38.59,0:25:40.12,EN,,0,0,0,,Now it doesn't really have to have a root. Dialogue: 0,0:25:40.12,0:25:41.95,EN,,0,0,0,,It could be a bunch of them, like all the registers. Dialogue: 0,0:25:42.67,0:25:43.98,EN,,0,0,0,,But I could cleverly arrange it Dialogue: 0,0:25:44.13,0:25:46.30,EN,,0,0,0,,so all the registers, all the things that are in old registers Dialogue: 0,0:25:46.30,0:25:47.77,EN,,0,0,0,,are also at the right moment Dialogue: 0,0:25:48.28,0:25:50.46,EN,,0,0,0,,put into this root structure, Dialogue: 0,0:25:50.46,0:25:51.85,EN,,0,0,0,,and then we've got one pointer to it. Dialogue: 0,0:25:51.85,0:25:52.67,EN,,0,0,0,,I don't really care. Dialogue: 0,0:25:54.57,0:25:55.63,EN,,0,0,0,,So the idea is Dialogue: 0,0:25:55.64,0:25:56.65,EN,,0,0,0,,we're going to cons up stuff Dialogue: 0,0:25:56.67,0:25:58.01,EN,,0,0,0,,until our free list is empty. Dialogue: 0,0:25:58.72,0:25:59.67,EN,,0,0,0,,We've run out of things. Dialogue: 0,0:26:00.95,0:26:04.47,EN,,0,0,0,,Now we're going to do this process of proving the theorem Dialogue: 0,0:26:04.47,0:26:05.90,EN,,0,0,0,,that a certain percentage of the memory Dialogue: 0,0:26:05.95,0:26:06.90,EN,,0,0,0,,is got crap in it. Dialogue: 0,0:26:07.85,0:26:09.15,EN,,0,0,0,,And then we're going to recycle that Dialogue: 0,0:26:09.78,0:26:10.87,EN,,0,0,0,,to grow new trees, Dialogue: 0,0:26:12.19,0:26:14.57,EN,,0,0,0,,a standard use of such garbage. Dialogue: 0,0:26:17.09,0:26:18.64,EN,,0,0,0,,So in any case, what do we have here? Dialogue: 0,0:26:18.84,0:26:20.78,EN,,0,0,0,,Well we have some data structure Dialogue: 0,0:26:20.89,0:26:24.27,EN,,0,0,0,,which starts out over here in p5. Dialogue: 0,0:26:25.15,0:26:26.75,EN,,0,0,0,,Sorry, and it will start at one Dialogue: 0,0:26:27.27,0:26:28.51,EN,,0,0,0,,And in fact Dialogue: 0,0:26:28.89,0:26:32.20,EN,,0,0,0,,it has a car in p5, Dialogue: 0,0:26:32.27,0:26:33.58,EN,,0,0,0,,and its cdr is in two. Dialogue: 0,0:26:33.98,0:26:35.64,EN,,0,0,0,,And all the marks start out at zero. Dialogue: 0,0:26:36.70,0:26:39.00,EN,,0,0,0,,Well let's start marking, just to play this game. Dialogue: 0,0:26:39.92,0:26:40.52,EN,,0,0,0,,OK. Dialogue: 0,0:26:42.54,0:26:44.27,EN,,0,0,0,,So for example, Dialogue: 0,0:26:44.47,0:26:46.95,EN,,0,0,0,,since I can access one from the root Dialogue: 0,0:26:46.95,0:26:47.82,EN,,0,0,0,,I will mark that. Dialogue: 0,0:26:48.39,0:26:49.17,EN,,0,0,0,,Let me mark it. Dialogue: 0,0:26:50.96,0:26:51.45,EN,,0,0,0,,Bang. Dialogue: 0,0:26:52.22,0:26:52.94,EN,,0,0,0,,That's marked. Dialogue: 0,0:26:54.41,0:26:57.51,EN,,0,0,0,,OK. Now since I have a five here Dialogue: 0,0:26:57.64,0:26:58.64,EN,,0,0,0,,I can go to five Dialogue: 0,0:26:59.02,0:27:00.72,EN,,0,0,0,,and see, well I'll mark that. Dialogue: 0,0:27:01.45,0:27:01.76,EN,,0,0,0,,Bang. Dialogue: 0,0:27:01.76,0:27:02.60,EN,,0,0,0,,That's useful stuff. Dialogue: 0,0:27:02.90,0:27:05.10,EN,,0,0,0,,But five references as a number in its car, Dialogue: 0,0:27:05.27,0:27:06.65,EN,,0,0,0,,I'm not interested in marking numbers Dialogue: 0,0:27:06.91,0:27:08.17,EN,,0,0,0,,but its cdr is seven. Dialogue: 0,0:27:08.70,0:27:09.75,EN,,0,0,0,,So I can mark that. Dialogue: 0,0:27:10.45,0:27:10.81,EN,,0,0,0,,Bang. Dialogue: 0,0:27:11.80,0:27:13.40,EN,,0,0,0,,OK? Seven is the empty list, Dialogue: 0,0:27:13.67,0:27:15.10,EN,,0,0,0,,the only thing that references, Dialogue: 0,0:27:15.59,0:27:17.12,EN,,0,0,0,,and it's got a number in its car. Dialogue: 0,0:27:17.12,0:27:17.85,EN,,0,0,0,,Not interesting. Dialogue: 0,0:27:19.49,0:27:20.50,EN,,0,0,0,,Well now let's go back here. Dialogue: 0,0:27:20.50,0:27:21.65,EN,,0,0,0,,I forgot about something. Dialogue: 0,0:27:21.65,0:27:22.17,EN,,0,0,0,,Two. Dialogue: 0,0:27:22.84,0:27:24.85,EN,,0,0,0,,See in other words, if I'm looking at cell one, Dialogue: 0,0:27:25.42,0:27:29.45,EN,,0,0,0,,cell one contains a two right over here. Dialogue: 0,0:27:30.37,0:27:31.30,EN,,0,0,0,,A reference to two. Dialogue: 0,0:27:32.01,0:27:34.97,EN,,0,0,0,,That means I should go mark two. Dialogue: 0,0:27:35.70,0:27:36.27,EN,,0,0,0,,Bang. Dialogue: 0,0:27:37.14,0:27:38.89,EN,,0,0,0,,Two contains a reference to four. Dialogue: 0,0:27:39.13,0:27:40.27,EN,,0,0,0,,It's got a number in its car, Dialogue: 0,0:27:40.27,0:27:41.20,EN,,0,0,0,,I'm not interested in that Dialogue: 0,0:27:41.47,0:27:42.60,EN,,0,0,0,,so I'm going to go mark that. Dialogue: 0,0:27:43.78,0:27:46.10,EN,,0,0,0,,Four refers to seven through its car, Dialogue: 0,0:27:46.75,0:27:48.17,EN,,0,0,0,,and is empty in its cdr, Dialogue: 0,0:27:48.47,0:27:49.57,EN,,0,0,0,,but I've already marked that one Dialogue: 0,0:27:49.57,0:27:50.75,EN,,0,0,0,,so I don't have to mark it again. Dialogue: 0,0:27:51.40,0:27:53.05,EN,,0,0,0,,This is all the accessible structure Dialogue: 0,0:27:53.07,0:27:53.87,EN,,0,0,0,,from that place. Dialogue: 0,0:27:55.00,0:27:56.57,EN,,0,0,0,,Simple recursive mark algorithm. Dialogue: 0,0:27:58.71,0:28:01.79,EN,,0,0,0,,Now there are some unhappinesses about that algorithm, Dialogue: 0,0:28:01.90,0:28:04.02,EN,,0,0,0,,and we can worry about that a second. Dialogue: 0,0:28:04.92,0:28:06.16,EN,,0,0,0,,But basically you'll see Dialogue: 0,0:28:06.19,0:28:07.85,EN,,0,0,0,,that all the things that have not been marked Dialogue: 0,0:28:09.62,0:28:11.50,EN,,0,0,0,,are places that are free, Dialogue: 0,0:28:11.50,0:28:12.41,EN,,0,0,0,,and I could recycle. Dialogue: 0,0:28:14.25,0:28:15.75,EN,,0,0,0,,So the next stage after that is going to be Dialogue: 0,0:28:15.75,0:28:17.05,EN,,0,0,0,,to scan through all of my memory, Dialogue: 0,0:28:17.94,0:28:20.35,EN,,0,0,0,,looking for things that are not marked. Dialogue: 0,0:28:21.18,0:28:22.45,EN,,0,0,0,,Every time I come across a marked thing Dialogue: 0,0:28:22.45,0:28:23.22,EN,,0,0,0,,I unmark it, Dialogue: 0,0:28:23.22,0:28:24.86,EN,,0,0,0,,and every time I come across an unmarked thing Dialogue: 0,0:28:25.07,0:28:27.82,EN,,0,0,0,,I'm going to link it together in my free list. Dialogue: 0,0:28:28.77,0:28:30.30,EN,,0,0,0,,Classic, very simple algorithm. Dialogue: 0,0:28:32.12,0:28:33.10,EN,,0,0,0,,So let's see. Dialogue: 0,0:28:33.84,0:28:34.77,EN,,0,0,0,,Is that very simple? Dialogue: 0,0:28:34.77,0:28:35.42,EN,,0,0,0,,Yes it is. Dialogue: 0,0:28:35.57,0:28:37.79,EN,,0,0,0,,I'm not going to go through the code in any detail, Dialogue: 0,0:28:38.00,0:28:39.65,EN,,0,0,0,,but I just want to show you about how long it is. Dialogue: 0,0:28:40.09,0:28:41.10,EN,,0,0,0,,Let's look at the mark phase. Dialogue: 0,0:28:41.72,0:28:43.98,EN,,0,0,0,,Here's the first part of the mark phase. Dialogue: 0,0:28:45.06,0:28:46.00,EN,,0,0,0,,We pick up the root. Dialogue: 0,0:28:46.32,0:28:47.52,EN,,0,0,0,,We're going to do some Dialogue: 0,0:28:47.67,0:28:51.05,EN,,0,0,0,,We're going to use that as a recursive procedure call. Dialogue: 0,0:28:52.38,0:28:54.47,EN,,0,0,0,,We're going to sweep from there, Dialogue: 0,0:28:54.77,0:28:56.95,EN,,0,0,0,,after when we're done with marking. Dialogue: 0,0:28:57.38,0:28:59.79,EN,,0,0,0,,And then we're going to do a little couple of instructions Dialogue: 0,0:28:59.80,0:29:01.36,EN,,0,0,0,,that do this checking out on the marks Dialogue: 0,0:29:01.39,0:29:03.07,EN,,0,0,0,,and changing the marks and things like that, Dialogue: 0,0:29:03.07,0:29:04.90,EN,,0,0,0,,according to the algorithm I've just shown you. Dialogue: 0,0:29:05.23,0:29:06.47,EN,,0,0,0,,OK? It comes out here. Dialogue: 0,0:29:06.47,0:29:07.65,EN,,0,0,0,,You have to mark the cars of things Dialogue: 0,0:29:07.87,0:29:10.21,EN,,0,0,0,,and you also have to be able to mark the cdrs of things. Dialogue: 0,0:29:10.66,0:29:12.10,EN,,0,0,0,,That's the entire mark phase. Dialogue: 0,0:29:14.37,0:29:16.16,EN,,0,0,0,,I'll just tell you a little story about this. Dialogue: 0,0:29:16.59,0:29:19.37,EN,,0,0,0,,The old DEC PDP-6 computer, Dialogue: 0,0:29:20.93,0:29:22.09,EN,,0,0,0,,this was the way that Dialogue: 0,0:29:22.35,0:29:24.85,EN,,0,0,0,,the mark-sweep garbage collection, as it was, was written. Dialogue: 0,0:29:26.91,0:29:28.40,EN,,0,0,0,,The program was so small Dialogue: 0,0:29:29.25,0:29:31.60,EN,,0,0,0,,that with the data that it needed, Dialogue: 0,0:29:32.20,0:29:34.87,EN,,0,0,0,,with the registers that it needed to manipulate the memory, Dialogue: 0,0:29:36.16,0:29:38.14,EN,,0,0,0,,it fit into the fast registers of the machine, Dialogue: 0,0:29:38.16,0:29:38.97,EN,,0,0,0,,which were 16. Dialogue: 0,0:29:39.28,0:29:39.80,EN,,0,0,0,,The whole program. Dialogue: 0,0:29:40.01,0:29:42.01,EN,,0,0,0,,And you could execute instructions in the fast registers. Dialogue: 0,0:29:43.17,0:29:44.83,EN,,0,0,0,,So it's an extremely small program, Dialogue: 0,0:29:45.85,0:29:46.88,EN,,0,0,0,,and it could run very fast. Dialogue: 0,0:29:48.87,0:29:51.30,EN,,0,0,0,,Now unfortunately, of course, Dialogue: 0,0:29:51.61,0:29:54.02,EN,,0,0,0,,this program, because the fact that it's recursive Dialogue: 0,0:29:54.80,0:29:57.55,EN,,0,0,0,,in the way that you do something first Dialogue: 0,0:29:57.55,0:29:58.99,EN,,0,0,0,,and then you do something after that, Dialogue: 0,0:29:59.21,0:30:00.88,EN,,0,0,0,,you have to work on the cars and then the cdrs, Dialogue: 0,0:30:01.15,0:30:02.75,EN,,0,0,0,,it requires auxiliary memory. Dialogue: 0,0:30:03.41,0:30:05.23,EN,,0,0,0,,So Lisp systems-- Dialogue: 0,0:30:05.44,0:30:07.42,EN,,0,0,0,,those requires a stack for marking. Dialogue: 0,0:30:08.26,0:30:11.05,EN,,0,0,0,,Lisp systems that are built this way Dialogue: 0,0:30:11.57,0:30:14.16,EN,,0,0,0,,have a limit to the depth of recursion you can have Dialogue: 0,0:30:14.42,0:30:17.37,EN,,0,0,0,,in data structures in either the car or the cdr, Dialogue: 0,0:30:17.81,0:30:19.35,EN,,0,0,0,,and that doesn't work very nicely. Dialogue: 0,0:30:19.93,0:30:20.60,EN,,0,0,0,,On the other hand, Dialogue: 0,0:30:20.64,0:30:22.12,EN,,0,0,0,,you never notice it if it's big enough. Dialogue: 0,0:30:23.18,0:30:25.13,EN,,0,0,0,,And that's certainly been Dialogue: 0,0:30:25.55,0:30:28.17,EN,,0,0,0,,the case for most Maclisp, for example, Dialogue: 0,0:30:28.69,0:30:29.88,EN,,0,0,0,,which ran Macsyma Dialogue: 0,0:30:29.96,0:30:31.10,EN,,0,0,0,,where you could deal with expressions Dialogue: 0,0:30:31.10,0:30:32.72,EN,,0,0,0,,of thousands of elements long. Dialogue: 0,0:30:33.56,0:30:36.02,EN,,0,0,0,,These are algebraic expressions with thousand of terms. Dialogue: 0,0:30:36.82,0:30:38.10,EN,,0,0,0,,And there's no problem with that. Dialogue: 0,0:30:39.49,0:30:40.82,EN,,0,0,0,,Such, the garbage collector does work. Dialogue: 0,0:30:42.19,0:30:42.92,EN,,0,0,0,,On the other hand, Dialogue: 0,0:30:42.92,0:30:45.37,EN,,0,0,0,,there's a very clever modification to this algorithm, Dialogue: 0,0:30:45.37,0:30:46.47,EN,,0,0,0,,which I will not describe, Dialogue: 0,0:30:46.80,0:30:48.22,EN,,0,0,0,,by Peter Deutsch and Schorr and Waite-- Dialogue: 0,0:30:48.64,0:30:51.82,EN,,0,0,0,,and Schorr and Waite, Herb Schorr from IBM Dialogue: 0,0:30:51.87,0:30:53.52,EN,,0,0,0,,and Waite who I don't know. Dialogue: 0,0:30:54.01,0:30:56.51,EN,,0,0,0,,Whrere... That algorithm Dialogue: 0,0:30:56.67,0:30:57.79,EN,,0,0,0,,allows you build Dialogue: 0,0:30:57.84,0:30:59.55,EN,,0,0,0,,you do can do this without auxiliary memory, Dialogue: 0,0:31:00.50,0:31:02.80,EN,,0,0,0,,by remembering as you walk the data structures Dialogue: 0,0:31:02.97,0:31:05.52,EN,,0,0,0,,where you came from by reversing the pointers as you go down Dialogue: 0,0:31:05.52,0:31:07.52,EN,,0,0,0,,and crawling up the reverse pointers as you go up. Dialogue: 0,0:31:07.79,0:31:08.99,EN,,0,0,0,,It's a rather tricky algorithm. Dialogue: 0,0:31:09.13,0:31:10.24,EN,,0,0,0,,The first time you write it-- Dialogue: 0,0:31:10.25,0:31:11.71,EN,,0,0,0,,or in fact, the first three times you write it it Dialogue: 0,0:31:11.71,0:31:12.72,EN,,0,0,0,,it has a terrible bug in it. Dialogue: 0,0:31:14.35,0:31:16.72,EN,,0,0,0,,And it's also about, it's quite rather slow, Dialogue: 0,0:31:16.72,0:31:17.67,EN,,0,0,0,,because it's complicated. Dialogue: 0,0:31:18.11,0:31:20.30,EN,,0,0,0,,It takes about six times as many memory references Dialogue: 0,0:31:20.85,0:31:23.22,EN,,0,0,0,,to do the sorts of things that we're talking about. Dialogue: 0,0:31:24.58,0:31:27.07,EN,,0,0,0,,Well now once I've done this marking phase, Dialogue: 0,0:31:27.50,0:31:30.12,EN,,0,0,0,,and I get into a position where things look like this, Dialogue: 0,0:31:30.17,0:31:31.26,EN,,0,0,0,,let's look-- yes. Dialogue: 0,0:31:31.51,0:31:34.03,EN,,0,0,0,,Here we have the mark done, Dialogue: 0,0:31:34.08,0:31:35.00,EN,,0,0,0,,just as I did it. Dialogue: 0,0:31:35.59,0:31:37.33,EN,,0,0,0,,Now we have to perform the sweep phase. Dialogue: 0,0:31:37.60,0:31:39.32,EN,,0,0,0,,And I described to you what this sweep is like. Dialogue: 0,0:31:39.82,0:31:42.34,EN,,0,0,0,,I'm going to walk down from one end of memory or the other, Dialogue: 0,0:31:42.34,0:31:43.34,EN,,0,0,0,,I don't care where, Dialogue: 0,0:31:43.62,0:31:46.17,EN,,0,0,0,,scanning every cell that's in the memory. Dialogue: 0,0:31:47.17,0:31:48.67,EN,,0,0,0,,And as I scan these cells, Dialogue: 0,0:31:49.20,0:31:50.97,EN,,0,0,0,,I'm going to link them together, Dialogue: 0,0:31:50.99,0:31:52.84,EN,,0,0,0,,if they are free, into the free list. Dialogue: 0,0:31:53.15,0:31:54.05,EN,,0,0,0,,And if they're not free, Dialogue: 0,0:31:54.05,0:31:56.07,EN,,0,0,0,,I'm going to unmark them so the marks become zero. Dialogue: 0,0:31:57.50,0:31:58.57,EN,,0,0,0,,And in fact what I get-- Dialogue: 0,0:31:58.70,0:32:00.46,EN,,0,0,0,,well the program is not very complicated. Dialogue: 0,0:32:00.46,0:32:02.22,EN,,0,0,0,,It looks sort of like this-- it's a little longer. Dialogue: 0,0:32:02.78,0:32:04.17,EN,,0,0,0,,Here's the first piece of it. Dialogue: 0,0:32:04.82,0:32:06.71,EN,,0,0,0,,This one's coming down from the top of memory. Dialogue: 0,0:32:06.71,0:32:09.58,EN,,0,0,0,,I don't want you to try to understand this at this point. Dialogue: 0,0:32:09.58,0:32:10.55,EN,,0,0,0,,It's rather simple. Dialogue: 0,0:32:11.03,0:32:12.52,EN,,0,0,0,,It's a very simple algorithm, Dialogue: 0,0:32:13.07,0:32:15.97,EN,,0,0,0,,but there's pieces of it that just sort of look like this. Dialogue: 0,0:32:15.97,0:32:17.37,EN,,0,0,0,,They're all sort of obvious. Dialogue: 0,0:32:18.60,0:32:20.08,EN,,0,0,0,,And after we've done the sweep, Dialogue: 0,0:32:20.30,0:32:21.77,EN,,0,0,0,,we get an answer that looks like that. Dialogue: 0,0:32:25.33,0:32:26.54,EN,,0,0,0,,Now there are some disadvantages Dialogue: 0,0:32:26.56,0:32:28.20,EN,,0,0,0,,with mark-sweep algorithms of this sort. Dialogue: 0,0:32:29.59,0:32:30.35,EN,,0,0,0,,Serious ones. Dialogue: 0,0:32:31.45,0:32:33.20,EN,,0,0,0,,One important disadvantage is Dialogue: 0,0:32:33.20,0:32:34.97,EN,,0,0,0,,that your memories get larger and larger. Dialogue: 0,0:32:36.82,0:32:38.87,EN,,0,0,0,,As you say, address spaces get larger and larger, Dialogue: 0,0:32:38.87,0:32:40.80,EN,,0,0,0,,you're willing to represent more and more stuff, Dialogue: 0,0:32:41.37,0:32:44.52,EN,,0,0,0,,then it gets very costly to scan all of memory. Dialogue: 0,0:32:46.36,0:32:47.39,EN,,0,0,0,,What you'd really like to do Dialogue: 0,0:32:47.40,0:32:48.68,EN,,0,0,0,,is only scan useful stuff. Dialogue: 0,0:32:50.49,0:32:51.55,EN,,0,0,0,,It would even be better Dialogue: 0,0:32:52.07,0:32:53.90,EN,,0,0,0,,if you realized that some stuff Dialogue: 0,0:32:54.48,0:32:57.72,EN,,0,0,0,,was known to be good and useful, Dialogue: 0,0:32:58.28,0:33:00.37,EN,,0,0,0,,and you don't have to look at it more than once or twice. Dialogue: 0,0:33:00.37,0:33:01.20,EN,,0,0,0,,Or very rarely. Dialogue: 0,0:33:01.55,0:33:04.32,EN,,0,0,0,,Whereas other stuff that you're not so sure about, Dialogue: 0,0:33:05.00,0:33:06.22,EN,,0,0,0,,you can look at more detail Dialogue: 0,0:33:07.10,0:33:08.75,EN,,0,0,0,,every time you want to do this, Dialogue: 0,0:33:09.93,0:33:10.85,EN,,0,0,0,,want to garbage collect. Dialogue: 0,0:33:11.91,0:33:13.74,EN,,0,0,0,,Well there are algorithms Dialogue: 0,0:33:13.76,0:33:15.10,EN,,0,0,0,,that are organized in this way. Dialogue: 0,0:33:15.66,0:33:18.16,EN,,0,0,0,,Let me tell you about a famous old algorithm Dialogue: 0,0:33:18.28,0:33:19.47,EN,,0,0,0,,which allows you only look at Dialogue: 0,0:33:19.50,0:33:21.37,EN,,0,0,0,,the part of memory which is known to be useful. Dialogue: 0,0:33:23.12,0:33:23.85,EN,,0,0,0,,And which happens to be Dialogue: 0,0:33:23.87,0:33:25.29,EN,,0,0,0,,the fastest known garbage collector algorithm. Dialogue: 0,0:33:26.31,0:33:29.45,EN,,0,0,0,,This is the Minsky-Fenichel-Yochelson garbage collector algorithm. Dialogue: 0,0:33:30.40,0:33:33.18,EN,,0,0,0,,It was invented by Minsky Dialogue: 0,0:33:33.20,0:33:36.06,EN,,0,0,0,,in 1961 or '60 or something, Dialogue: 0,0:33:36.52,0:33:40.48,EN,,0,0,0,,for the RLE PDP-1 Lisp, Dialogue: 0,0:33:40.51,0:33:43.44,EN,,0,0,0,,which had 4,096 words of list memory, Dialogue: 0,0:33:45.79,0:33:46.76,EN,,0,0,0,,and a drum. Dialogue: 0,0:33:48.48,0:33:49.39,EN,,0,0,0,,And the whole idea Dialogue: 0,0:33:50.03,0:33:51.87,EN,,0,0,0,,was to garbage collect this terrible memory. Dialogue: 0,0:33:53.05,0:33:54.35,EN,,0,0,0,,What Minsky realized Dialogue: 0,0:33:54.38,0:33:55.62,EN,,0,0,0,,was the easiest way to do this Dialogue: 0,0:33:56.20,0:33:58.47,EN,,0,0,0,,is to scan the memory in the same sense, Dialogue: 0,0:33:58.47,0:34:00.60,EN,,0,0,0,,walking the good structure, Dialogue: 0,0:34:01.57,0:34:03.52,EN,,0,0,0,,copying it out into the drum, Dialogue: 0,0:34:04.70,0:34:05.47,EN,,0,0,0,,compacted. Dialogue: 0,0:34:06.35,0:34:08.86,EN,,0,0,0,,And then when we were done copying it all out, Dialogue: 0,0:34:09.12,0:34:10.90,EN,,0,0,0,,then you swap that back into your memory. Dialogue: 0,0:34:12.30,0:34:13.68,EN,,0,0,0,,Now whether or you not use a drum, Dialogue: 0,0:34:13.72,0:34:14.71,EN,,0,0,0,,or another piece of memory, Dialogue: 0,0:34:14.71,0:34:16.42,EN,,0,0,0,,or something like that isn't important. Dialogue: 0,0:34:17.03,0:34:17.42,EN,,0,0,0,,In fact, Dialogue: 0,0:34:17.44,0:34:19.60,EN,,0,0,0,,I don't think people use drums anymore for anything. Dialogue: 0,0:34:20.35,0:34:23.77,EN,,0,0,0,,But this algorithm basically Dialogue: 0,0:34:24.03,0:34:25.42,EN,,0,0,0,,depends upon having Dialogue: 0,0:34:25.42,0:34:27.42,EN,,0,0,0,,about twice as much address space Dialogue: 0,0:34:27.48,0:34:28.57,EN,,0,0,0,,you're actually using. Dialogue: 0,0:34:30.27,0:34:32.96,EN,,0,0,0,,And so what you have is some, initially, Dialogue: 0,0:34:33.12,0:34:36.60,EN,,0,0,0,,some mixture of useful data and garbage. Dialogue: 0,0:34:37.11,0:34:38.97,EN,,0,0,0,,So this is called fromspace. Dialogue: 0,0:34:45.17,0:34:47.05,EN,,0,0,0,,And this is a mixture of crud. Dialogue: 0,0:34:47.87,0:34:49.79,EN,,0,0,0,,Some of it's important and some of it isn't. Dialogue: 0,0:34:52.00,0:34:53.85,EN,,0,0,0,,Now there's another place Dialogue: 0,0:34:54.17,0:34:55.61,EN,,0,0,0,,which is hopefully big enough, Dialogue: 0,0:34:55.77,0:34:57.00,EN,,0,0,0,,if we recall, tospace, Dialogue: 0,0:34:57.12,0:34:58.24,EN,,0,0,0,,which is where we're copying to. Dialogue: 0,0:35:01.59,0:35:02.60,EN,,0,0,0,,And what happens is-- Dialogue: 0,0:35:02.60,0:35:04.06,EN,,0,0,0,,and I'm not going to go through this detail. Dialogue: 0,0:35:04.16,0:35:07.07,EN,,0,0,0,,It's in our book quite explicitly. Dialogue: 0,0:35:07.59,0:35:10.40,EN,,0,0,0,,There's a root point where you start from. Dialogue: 0,0:35:11.03,0:35:14.30,EN,,0,0,0,,And the idea is that you start with the root. Dialogue: 0,0:35:14.60,0:35:16.42,EN,,0,0,0,,You copy the first thing you see, Dialogue: 0,0:35:17.83,0:35:19.37,EN,,0,0,0,,the first thing that the root points at, Dialogue: 0,0:35:19.75,0:35:21.31,EN,,0,0,0,,to the beginning of tospace. Dialogue: 0,0:35:22.81,0:35:24.12,EN,,0,0,0,,The first thing is a pair Dialogue: 0,0:35:24.16,0:35:25.60,EN,,0,0,0,,or something like, a data structure. Dialogue: 0,0:35:27.56,0:35:30.19,EN,,0,0,0,,You then also leave behind Dialogue: 0,0:35:30.38,0:35:31.56,EN,,0,0,0,,a broken heart saying, Dialogue: 0,0:35:31.77,0:35:35.74,EN,,0,0,0,,I moved this object from here to here, Dialogue: 0,0:35:35.74,0:35:37.05,EN,,0,0,0,,giving the place where it moved to. Dialogue: 0,0:35:37.80,0:35:39.65,EN,,0,0,0,,This is called a broken heart because Dialogue: 0,0:35:39.65,0:35:40.78,EN,,0,0,0,,a friend of mine who implemented Dialogue: 0,0:35:40.78,0:35:43.39,EN,,0,0,0,,one of these in 1966 Dialogue: 0,0:35:43.82,0:35:45.26,EN,,0,0,0,,was a very romantic character Dialogue: 0,0:35:45.26,0:35:46.76,EN,,0,0,0,,and called it a broken heart. Dialogue: 0,0:35:49.58,0:35:50.54,EN,,0,0,0,,But in any case, Dialogue: 0,0:35:51.15,0:35:52.72,EN,,0,0,0,,the next thing you do Dialogue: 0,0:35:52.94,0:35:55.00,EN,,0,0,0,,is now you have a new free pointer which is here, Dialogue: 0,0:35:55.17,0:35:56.38,EN,,0,0,0,,and you start scanning. Dialogue: 0,0:35:56.88,0:35:59.68,EN,,0,0,0,,You scan this data structure you just copied. Dialogue: 0,0:36:00.55,0:36:02.19,EN,,0,0,0,,And every time you encounter a pointer in it, Dialogue: 0,0:36:02.19,0:36:03.92,EN,,0,0,0,,you treat it as if it was the root pointer here. Dialogue: 0,0:36:04.00,0:36:04.59,EN,,0,0,0,,Oh, I'm sorry. Dialogue: 0,0:36:04.60,0:36:05.69,EN,,0,0,0,,The other thing you do Dialogue: 0,0:36:05.71,0:36:07.08,EN,,0,0,0,,is you now move the root pointer to there. Dialogue: 0,0:36:09.22,0:36:10.17,EN,,0,0,0,,So now you scan this, Dialogue: 0,0:36:10.17,0:36:10.99,EN,,0,0,0,,and everything you see Dialogue: 0,0:36:11.00,0:36:12.41,EN,,0,0,0,,you treat as it were the root pointer. Dialogue: 0,0:36:14.11,0:36:15.45,EN,,0,0,0,,So if you see something, Dialogue: 0,0:36:15.45,0:36:17.40,EN,,0,0,0,,well it points up into there somewhere. Dialogue: 0,0:36:18.51,0:36:19.92,EN,,0,0,0,,Is it pointing at a thing Dialogue: 0,0:36:19.93,0:36:20.99,EN,,0,0,0,,which you've not copied yet? Dialogue: 0,0:36:21.78,0:36:22.87,EN,,0,0,0,,Is there a broken heart there? Dialogue: 0,0:36:23.88,0:36:24.84,EN,,0,0,0,,If there's a broken heart there Dialogue: 0,0:36:24.84,0:36:26.11,EN,,0,0,0,,and it's something you have copied, Dialogue: 0,0:36:26.20,0:36:27.34,EN,,0,0,0,,you've just replaced this pointer Dialogue: 0,0:36:27.36,0:36:28.75,EN,,0,0,0,,with the thing a broken heart points at. Dialogue: 0,0:36:29.82,0:36:32.03,EN,,0,0,0,,If this thing has not been copied, Dialogue: 0,0:36:32.12,0:36:34.08,EN,,0,0,0,,you copy it to the next place over here. Dialogue: 0,0:36:34.43,0:36:35.95,EN,,0,0,0,,Move your free pointer over here, Dialogue: 0,0:36:37.05,0:36:40.60,EN,,0,0,0,,and then leave a broken heart behind Dialogue: 0,0:36:41.05,0:36:41.80,EN,,0,0,0,,and scan. Dialogue: 0,0:36:43.67,0:36:46.40,EN,,0,0,0,,And eventually when the scant pointer hits the free pointer, Dialogue: 0,0:36:46.82,0:36:48.52,EN,,0,0,0,,everything in memory has been copied. Dialogue: 0,0:36:50.14,0:36:51.04,EN,,0,0,0,,And then there's a whole bunch Dialogue: 0,0:36:51.05,0:36:51.95,EN,,0,0,0,,of empty space up here, Dialogue: 0,0:36:51.96,0:36:53.28,EN,,0,0,0,,which you could either make into a free list, Dialogue: 0,0:36:53.31,0:36:54.47,EN,,0,0,0,,if that's what you want to do. Dialogue: 0,0:36:54.47,0:36:56.27,EN,,0,0,0,,But generally you don't in this kind of system. Dialogue: 0,0:36:56.27,0:36:59.15,EN,,0,0,0,,In this system you sequentially allocate your memory. Dialogue: 0,0:37:00.91,0:37:02.48,EN,,0,0,0,,That is a very, very nice algorithm, Dialogue: 0,0:37:02.97,0:37:04.57,EN,,0,0,0,,and sort of the one we use in the Dialogue: 0,0:37:04.67,0:37:05.97,EN,,0,0,0,,the scheme that you've been using. Dialogue: 0,0:37:06.79,0:37:09.47,EN,,0,0,0,,And it's known to be... it's expected-- Dialogue: 0,0:37:09.47,0:37:10.86,EN,,0,0,0,,I believe no one has found Dialogue: 0,0:37:10.89,0:37:12.12,EN,,0,0,0,,a faster algorithm than that. Dialogue: 0,0:37:12.40,0:37:14.85,EN,,0,0,0,,There are very simple modifications to this algorithm Dialogue: 0,0:37:14.85,0:37:16.77,EN,,0,0,0,,invented by Henry Baker Dialogue: 0,0:37:17.17,0:37:20.31,EN,,0,0,0,,which allow one to run this algorithm in real time, Dialogue: 0,0:37:20.31,0:37:21.92,EN,,0,0,0,,meaning you don't have to stop to garbage collect. Dialogue: 0,0:37:22.14,0:37:24.33,EN,,0,0,0,,But you could interleave the consing Dialogue: 0,0:37:24.36,0:37:26.17,EN,,0,0,0,,that the machine does when its running Dialogue: 0,0:37:26.32,0:37:28.40,EN,,0,0,0,,with steps of the garbage collection process, Dialogue: 0,0:37:28.85,0:37:31.20,EN,,0,0,0,,so that the thing, the garbage collector's distributed Dialogue: 0,0:37:31.20,0:37:32.19,EN,,0,0,0,,and the machine doesn't have to stop, Dialogue: 0,0:37:32.41,0:37:33.47,EN,,0,0,0,,and garbage collecting can start. Dialogue: 0,0:37:34.64,0:37:37.87,EN,,0,0,0,,Of course in the case of machines with virtual memory Dialogue: 0,0:37:38.90,0:37:41.20,EN,,0,0,0,,where a lot of it is in inaccessible places, Dialogue: 0,0:37:41.50,0:37:43.60,EN,,0,0,0,,this becomes a very expensive process. Dialogue: 0,0:37:44.28,0:37:46.43,EN,,0,0,0,,And there have been numerous Dialogue: 0,0:37:47.16,0:37:48.65,EN,,0,0,0,,attempts to make this much better. Dialogue: 0,0:37:49.19,0:37:51.15,EN,,0,0,0,,There is a nice paper, Dialogue: 0,0:37:51.16,0:37:52.41,EN,,0,0,0,,for those of you who are interested, Dialogue: 0,0:37:52.64,0:37:54.27,EN,,0,0,0,,by Moon and other people Dialogue: 0,0:37:54.65,0:37:56.89,EN,,0,0,0,,which describes a modification to Dialogue: 0,0:37:56.92,0:37:59.44,EN,,0,0,0,,the incremental Minsky-Fenichel-Yochelson algorithm, Dialogue: 0,0:37:59.51,0:38:01.20,EN,,0,0,0,,and modification the Baker algorithm Dialogue: 0,0:38:01.42,0:38:06.54,EN,,0,0,0,,which is more efficient for virtual memory systems. Dialogue: 0,0:38:08.27,0:38:12.32,EN,,0,0,0,,Well I think now the mystery to this is sort of gone. Dialogue: 0,0:38:12.84,0:38:14.09,EN,,0,0,0,,And I'd like to see if there are any questions. Dialogue: 0,0:38:19.78,0:38:19.95,EN,,0,0,0,,Yes. Dialogue: 0,0:38:20.60,0:38:23.58,EN,,0,0,0,,AUDIENCE: I saw one of you run the garbage collector Dialogue: 0,0:38:23.64,0:38:25.05,EN,,0,0,0,,on the systems upstairs, Dialogue: 0,0:38:25.93,0:38:27.88,EN,,0,0,0,,and it seemed to me to run extremely fast. Dialogue: 0,0:38:27.96,0:38:28.40,EN,,0,0,0,,PROFESSOR: Yes Dialogue: 0,0:38:28.49,0:38:29.52,EN,,0,0,0,,AUDIENCE: Did the whole thing take-- Dialogue: 0,0:38:30.11,0:38:31.88,EN,,0,0,0,,does it sweep through all of memory? Dialogue: 0,0:38:31.88,0:38:32.22,EN,,0,0,0,,PROFESSOR: No. Dialogue: 0,0:38:32.25,0:38:34.11,EN,,0,0,0,,It swept through exactly what was needed Dialogue: 0,0:38:34.33,0:38:35.63,EN,,0,0,0,,to copy the useful structure. Dialogue: 0,0:38:37.32,0:38:38.36,EN,,0,0,0,,It's a copying collector. Dialogue: 0,0:38:38.44,0:38:38.91,EN,,0,0,0,,AUDIENCE: OK. Dialogue: 0,0:38:39.30,0:38:40.88,EN,,0,0,0,,PROFESSOR: And it's rather... it is very fast. Dialogue: 0,0:38:41.85,0:38:45.88,EN,,0,0,0,,On the whole, I suppose to copy in a Bobcat Dialogue: 0,0:38:47.12,0:38:51.56,EN,,0,0,0,,to copy, I think, a three megabyte thing or something Dialogue: 0,0:38:52.43,0:38:53.24,EN,,0,0,0,,is less than a second, Dialogue: 0,0:38:55.00,0:38:55.69,EN,,0,0,0,,real time Dialogue: 0,0:38:56.54,0:38:58.46,EN,,0,0,0,,Really, these are very small programs. Dialogue: 0,0:38:58.62,0:39:01.50,EN,,0,0,0,,One thing you should realise is that Dialogue: 0,0:39:02.91,0:39:04.40,EN,,0,0,0,,garbage collectors have to be small. Dialogue: 0,0:39:05.40,0:39:07.10,EN,,0,0,0,,Not because they have to be fast, Dialogue: 0,0:39:07.90,0:39:09.23,EN,,0,0,0,,but because no one can debug Dialogue: 0,0:39:09.26,0:39:10.48,EN,,0,0,0,,a complicated garbage collector. Dialogue: 0,0:39:11.34,0:39:12.91,EN,,0,0,0,,A garbage collector, if it doesn't work, Dialogue: 0,0:39:14.04,0:39:15.93,EN,,0,0,0,,will trash your memory in such a way Dialogue: 0,0:39:15.93,0:39:17.39,EN,,0,0,0,,that you cannot figure out what the hell happened. Dialogue: 0,0:39:18.35,0:39:19.67,EN,,0,0,0,,You need an audit trail. Dialogue: 0,0:39:20.66,0:39:22.01,EN,,0,0,0,,Because it rearranges everything, Dialogue: 0,0:39:22.04,0:39:23.24,EN,,0,0,0,,and how do you know what happened there? Dialogue: 0,0:39:23.74,0:39:26.58,EN,,0,0,0,,So this is the only kind of program that Dialogue: 0,0:39:26.92,0:39:28.40,EN,,0,0,0,,it really, seriously matters Dialogue: 0,0:39:28.54,0:39:29.79,EN,,0,0,0,,if you stare at it long enough Dialogue: 0,0:39:29.82,0:39:31.07,EN,,0,0,0,,so you believe that it works. Dialogue: 0,0:39:31.34,0:39:33.36,EN,,0,0,0,,That means and sort of prove it to yourself. Dialogue: 0,0:39:33.92,0:39:36.11,EN,,0,0,0,,And that, that... So there's no way to debug it. Dialogue: 0,0:39:36.94,0:39:38.96,EN,,0,0,0,,And that takes it being small enough Dialogue: 0,0:39:38.96,0:39:39.97,EN,,0,0,0,,so you can hold it in your head. Dialogue: 0,0:39:41.45,0:39:43.90,EN,,0,0,0,,So garbage collectors are special in this way. Dialogue: 0,0:39:45.02,0:39:47.12,EN,,0,0,0,,So every reasonable garbage collector has gotten small, Dialogue: 0,0:39:47.13,0:39:48.45,EN,,0,0,0,,and generally small programs are fast. Dialogue: 0,0:39:52.05,0:39:52.43,EN,,0,0,0,,Yes. Dialogue: 0,0:39:52.43,0:39:54.51,EN,,0,0,0,,AUDIENCE: Can you repeat the name of this technique once again? Dialogue: 0,0:39:54.68,0:39:56.92,EN,,0,0,0,,PROFESSOR: That's the Minsky-Fenichel-Yochelson garbage collector. Dialogue: 0,0:39:57.88,0:39:58.43,EN,,0,0,0,,AUDIENCE: You got that? Dialogue: 0,0:39:59.00,0:40:00.78,EN,,0,0,0,,PROFESSOR: Minsky invented it in '61 Dialogue: 0,0:40:00.81,0:40:02.21,EN,,0,0,0,,for the RLE PDP-1. Dialogue: 0,0:40:02.21,0:40:06.17,EN,,0,0,0,,A version of it was developed and elaborated Dialogue: 0,0:40:06.45,0:40:10.27,EN,,0,0,0,,to be used in Multics Maclisp by Fenichel and Yochelson Dialogue: 0,0:40:11.37,0:40:14.75,EN,,0,0,0,,in somewhere around 1968 or '69. Dialogue: 0,0:40:19.57,0:40:21.36,EN,,0,0,0,,OK. Let's take a break. Dialogue: 0,0:40:22.64,0:40:32.36,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:40:32.41,0:40:36.19,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:41:03.15,0:41:07.18,EN,,0,0,0,,By: Prof. Harold Abelson && Sussman Jay Sussman Dialogue: 0,0:41:07.20,0:41:10.17,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:41:10.20,0:41:14.22,EN,,0,0,0,,Not Everything Can Be Computed Dialogue: 0,0:41:17.31,0:41:19.67,EN,,0,0,0,,PROFESSOR: Well we've come to the end of this subject, Dialogue: 0,0:41:20.08,0:41:23.85,EN,,0,0,0,,and we've already shown you a universal machine Dialogue: 0,0:41:24.47,0:41:26.74,EN,,0,0,0,,which is down to evaluator. Dialogue: 0,0:41:27.02,0:41:28.38,EN,,0,0,0,,It's down to the level of detail Dialogue: 0,0:41:28.38,0:41:29.67,EN,,0,0,0,,you could imagine you could make one. Dialogue: 0,0:41:30.19,0:41:33.32,EN,,0,0,0,,This is a particular implementation of Lisp, Dialogue: 0,0:41:33.90,0:41:36.01,EN,,0,0,0,,built on one of those Dialogue: 0,0:41:36.16,0:41:38.05,EN,,0,0,0,,scheme chips that was talked about yesterday, Dialogue: 0,0:41:38.20,0:41:38.91,EN,,0,0,0,,sitting over here. Dialogue: 0,0:41:39.35,0:41:42.00,EN,,0,0,0,,This is mostly interface to somebody's memory Dialogue: 0,0:41:42.60,0:41:44.75,EN,,0,0,0,,with a little bit of timing and other such stuff. Dialogue: 0,0:41:45.22,0:41:47.25,EN,,0,0,0,,But this fellow actually ran Lisp Dialogue: 0,0:41:47.77,0:41:50.17,EN,,0,0,0,,at a fairly reasonable rate, as interpretive. Dialogue: 0,0:41:50.61,0:41:53.82,EN,,0,0,0,,It ran Lisp as fast as a DEC PDP-10 Dialogue: 0,0:41:54.22,0:41:55.65,EN,,0,0,0,,back in 1979. Dialogue: 0,0:41:56.50,0:41:59.67,EN,,0,0,0,,And so it's gotten pretty hardware. Dialogue: 0,0:42:00.02,0:42:00.89,EN,,0,0,0,,Pretty concrete. Dialogue: 0,0:42:02.47,0:42:04.70,EN,,0,0,0,,We've also downed you a bit Dialogue: 0,0:42:04.72,0:42:06.07,EN,,0,0,0,,with the things you can compute. Dialogue: 0,0:42:07.37,0:42:08.76,EN,,0,0,0,,But is it the case that Dialogue: 0,0:42:09.32,0:42:10.55,EN,,0,0,0,,there are things we can't compute? Dialogue: 0,0:42:11.85,0:42:13.50,EN,,0,0,0,,And so I'd like to end this with Dialogue: 0,0:42:13.75,0:42:15.87,EN,,0,0,0,,showing you some things that you'd like be able to compute Dialogue: 0,0:42:16.60,0:42:17.22,EN,,0,0,0,,that you can't. Dialogue: 0,0:42:18.19,0:42:19.45,EN,,0,0,0,,The answer is yes, Dialogue: 0,0:42:19.45,0:42:20.82,EN,,0,0,0,,there are things you can't compute. Dialogue: 0,0:42:22.72,0:42:23.47,EN,,0,0,0,,For example, Dialogue: 0,0:42:24.45,0:42:25.82,EN,,0,0,0,,something you'd really like is-- Dialogue: 0,0:42:27.80,0:42:29.36,EN,,0,0,0,,if you're writing a compiler Dialogue: 0,0:42:29.77,0:42:31.42,EN,,0,0,0,,you'd like a program that would check Dialogue: 0,0:42:32.00,0:42:33.97,EN,,0,0,0,,that the thing you're going to do will work. Dialogue: 0,0:42:34.63,0:42:35.40,EN,,0,0,0,,Wouldn't that be nice? Dialogue: 0,0:42:36.08,0:42:37.87,EN,,0,0,0,,You'd like something that would catch infinite loops, Dialogue: 0,0:42:37.87,0:42:38.54,EN,,0,0,0,,for example, Dialogue: 0,0:42:39.45,0:42:42.42,EN,,0,0,0,,in programs that were written by users. Dialogue: 0,0:42:43.19,0:42:45.12,EN,,0,0,0,,But in general you can't write such a program Dialogue: 0,0:42:45.35,0:42:46.49,EN,,0,0,0,,that will read any program Dialogue: 0,0:42:46.51,0:42:47.45,EN,,0,0,0,,and determine whether or not Dialogue: 0,0:42:48.35,0:42:49.30,EN,,0,0,0,,it's an infinite loop. Dialogue: 0,0:42:50.99,0:42:51.71,EN,,0,0,0,,Let me show you that. Dialogue: 0,0:42:51.76,0:42:53.80,EN,,0,0,0,,It's a little bit of a minor mathematics. Dialogue: 0,0:42:58.78,0:42:59.65,EN,,0,0,0,,Let's imagine Dialogue: 0,0:43:00.05,0:43:01.78,EN,,0,0,0,,that we just had a mathematical function Dialogue: 0,0:43:01.78,0:43:02.62,EN,,0,0,0,,before we start. Dialogue: 0,0:43:02.62,0:43:03.42,EN,,0,0,0,,And there is one, Dialogue: 0,0:43:03.84,0:43:04.67,EN,,0,0,0,,called s, Dialogue: 0,0:43:05.47,0:43:07.54,EN,,0,0,0,,which takes a procedure Dialogue: 0,0:43:12.64,0:43:14.23,EN,,0,0,0,,and its argument, a. Dialogue: 0,0:43:19.17,0:43:20.52,EN,,0,0,0,,And what s does Dialogue: 0,0:43:21.65,0:43:24.01,EN,,0,0,0,,is it determines whether or not Dialogue: 0,0:43:24.01,0:43:25.97,EN,,0,0,0,,it's safe to run p on a. Dialogue: 0,0:43:26.90,0:43:28.17,EN,,0,0,0,,And what I mean by that is this: Dialogue: 0,0:43:28.76,0:43:35.12,EN,,0,0,0,,it's true if p applied to a Dialogue: 0,0:43:35.62,0:43:36.74,EN,,0,0,0,,will converge Dialogue: 0,0:43:41.40,0:43:42.45,EN,,0,0,0,,to a value Dialogue: 0,0:43:44.35,0:43:45.33,EN,,0,0,0,,without an error. Dialogue: 0,0:43:52.70,0:43:53.68,EN,,0,0,0,,And it's false Dialogue: 0,0:43:56.10,0:43:57.04,EN,,0,0,0,,if p of a Dialogue: 0,0:43:59.67,0:44:00.76,EN,,0,0,0,,loops forever Dialogue: 0,0:44:05.87,0:44:06.95,EN,,0,0,0,,or makes an error. Dialogue: 0,0:44:15.23,0:44:17.22,EN,,0,0,0,,Now that's surely a function. Dialogue: 0,0:44:18.78,0:44:20.72,EN,,0,0,0,,There is some for every procedure Dialogue: 0,0:44:21.20,0:44:22.85,EN,,0,0,0,,and for every argument you could give it Dialogue: 0,0:44:23.92,0:44:25.45,EN,,0,0,0,,that is either true or false Dialogue: 0,0:44:25.92,0:44:27.85,EN,,0,0,0,,that it converges without making an error. Dialogue: 0,0:44:28.44,0:44:30.15,EN,,0,0,0,,And you could make a giant table of them. Dialogue: 0,0:44:32.22,0:44:32.92,EN,,0,0,0,,But the question is, Dialogue: 0,0:44:32.92,0:44:34.09,EN,,0,0,0,,can you write a procedure Dialogue: 0,0:44:34.09,0:44:35.92,EN,,0,0,0,,that compute the values of this function? Dialogue: 0,0:44:37.43,0:44:38.92,EN,,0,0,0,,Well let's assume that we can. Dialogue: 0,0:44:39.72,0:44:40.55,EN,,0,0,0,,Suppose Dialogue: 0,0:44:44.33,0:44:45.58,EN,,0,0,0,,that we have a procedure Dialogue: 0,0:44:48.55,0:44:52.73,EN,,0,0,0,,procedure called "safe" Dialogue: 0,0:44:56.54,0:44:59.90,EN,,0,0,0,,that computes the value of s. Dialogue: 0,0:45:12.65,0:45:14.89,EN,,0,0,0,,Now I'm going to show you by several methods Dialogue: 0,0:45:15.90,0:45:18.51,EN,,0,0,0,,that you can't do this. Dialogue: 0,0:45:19.76,0:45:20.62,EN,,0,0,0,,The easiest one, Dialogue: 0,0:45:20.62,0:45:21.28,EN,,0,0,0,,or the first one, Dialogue: 0,0:45:21.31,0:45:23.45,EN,,0,0,0,,let's define a procedure called diag1. Dialogue: 0,0:45:23.76,0:45:24.86,EN,,0,0,0,,Given that we have safe, Dialogue: 0,0:45:25.20,0:45:26.99,EN,,0,0,0,,we can define diag1 Dialogue: 0,0:45:34.42,0:45:35.55,EN,,0,0,0,,diag1 Dialogue: 0,0:45:37.82,0:45:41.60,EN,,0,0,0,,to be the procedure of one argument, p, Dialogue: 0,0:45:42.45,0:45:44.05,EN,,0,0,0,,which has the following properties. Dialogue: 0,0:45:44.78,0:45:50.67,EN,,0,0,0,,If it's safe to apply p to itself, Dialogue: 0,0:45:53.32,0:45:55.32,EN,,0,0,0,,then I wish to have an infinite loop. Dialogue: 0,0:45:59.22,0:46:00.92,EN,,0,0,0,,Otherwise I'm going to return 3. Dialogue: 0,0:46:03.68,0:46:04.47,EN,,0,0,0,,Maybe it was 42. Dialogue: 0,0:46:04.47,0:46:06.42,EN,,0,0,0,,What's the answer to the big question? Dialogue: 0,0:46:07.06,0:46:08.87,EN,,0,0,0,,Where of course we know what an infinite loop is. Dialogue: 0,0:46:12.05,0:46:12.96,EN,,0,0,0,,Infinite loop, Dialogue: 0,0:46:13.82,0:46:16.02,EN,,0,0,0,,to be a procedure of no arguments, Dialogue: 0,0:46:16.02,0:46:18.07,EN,,0,0,0,,which is that nice lambda calculus loop. Dialogue: 0,0:46:18.35,0:46:20.44,EN,,0,0,0,,Lambda of x, Dialogue: 0,0:46:21.30,0:46:24.68,EN,,0,0,0,,applied to lambda of x, x of x. Dialogue: 0,0:46:24.68,0:46:26.55,EN,,0,0,0,,So there's nothing left to the imagination here. Dialogue: 0,0:46:29.83,0:46:31.17,EN,,0,0,0,,Well let's see what the story is. Dialogue: 0,0:46:32.50,0:46:33.90,EN,,0,0,0,,I'm supposing it's the case Dialogue: 0,0:46:35.45,0:46:38.77,EN,,0,0,0,,that we worry about the procedure Dialogue: 0,0:46:39.00,0:46:43.45,EN,,0,0,0,,called diag1 applied to diag1. Dialogue: 0,0:46:46.27,0:46:47.77,EN,,0,0,0,,Well what could it possibly be? Dialogue: 0,0:46:49.97,0:46:51.39,EN,,0,0,0,,Well I don't know. Dialogue: 0,0:46:51.39,0:46:53.21,EN,,0,0,0,,We're going to substitute diag1 Dialogue: 0,0:46:53.55,0:46:55.50,EN,,0,0,0,,for p in the body here. Dialogue: 0,0:46:57.31,0:47:00.22,EN,,0,0,0,,Well is it safe to compute diag1 of diag1? Dialogue: 0,0:47:00.22,0:47:00.78,EN,,0,0,0,,I don't know. Dialogue: 0,0:47:00.78,0:47:01.82,EN,,0,0,0,,There are two possibilities. Dialogue: 0,0:47:03.40,0:47:05.50,EN,,0,0,0,,If it's safe to compute diag1 of diag1 Dialogue: 0,0:47:05.92,0:47:06.89,EN,,0,0,0,,that means it shouldn't loop. Dialogue: 0,0:47:08.49,0:47:09.22,EN,,0,0,0,,That means I go to here, Dialogue: 0,0:47:09.22,0:47:10.35,EN,,0,0,0,,but then I produce an infinite loop. Dialogue: 0,0:47:10.56,0:47:11.57,EN,,0,0,0,,So it can't be safe. Dialogue: 0,0:47:12.21,0:47:14.78,EN,,0,0,0,,But if it's not safe to compute diag1 of diag1 Dialogue: 0,0:47:14.90,0:47:16.02,EN,,0,0,0,,then the answer to this is 3. Dialogue: 0,0:47:16.02,0:47:17.26,EN,,0,0,0,,But that's diag1 of diag1, Dialogue: 0,0:47:17.26,0:47:17.93,EN,,0,0,0,,so it had to be safe. Dialogue: 0,0:47:20.53,0:47:23.60,EN,,0,0,0,,So therefore by contradiction Dialogue: 0,0:47:24.32,0:47:26.30,EN,,0,0,0,,you cannot produce safe. Dialogue: 0,0:47:27.40,0:47:29.80,EN,,0,0,0,,For those of you who were boggled by that one Dialogue: 0,0:47:30.25,0:47:32.15,EN,,0,0,0,,I'm going to say it again, in a different way. Dialogue: 0,0:47:32.82,0:47:34.00,EN,,0,0,0,,Listen to one more alternative. Dialogue: 0,0:47:35.53,0:47:36.95,EN,,0,0,0,,Let's define diag2. Dialogue: 0,0:47:39.84,0:47:41.60,EN,,0,0,0,,These are named diag because Dialogue: 0,0:47:42.65,0:47:44.72,EN,,0,0,0,,of Cantor's diagonal argument. Dialogue: 0,0:47:45.00,0:47:47.05,EN,,0,0,0,,These are instances of Dialogue: 0,0:47:47.05,0:47:49.05,EN,,0,0,0,,a famous argument which was originally used by Dialogue: 0,0:47:49.45,0:47:52.65,EN,,0,0,0,,Cantor in the late part of the last century Dialogue: 0,0:47:52.77,0:47:56.10,EN,,0,0,0,,to prove that the real numbers were not countable, Dialogue: 0,0:47:56.67,0:47:58.00,EN,,0,0,0,,that there are too many real numbers Dialogue: 0,0:47:58.06,0:47:59.42,EN,,0,0,0,,to be counted by integers. Dialogue: 0,0:48:00.19,0:48:01.74,EN,,0,0,0,,That there are more points on a line, Dialogue: 0,0:48:01.74,0:48:02.50,EN,,0,0,0,,for example, Dialogue: 0,0:48:02.50,0:48:04.42,EN,,0,0,0,,than there are counting numbers. Dialogue: 0,0:48:05.26,0:48:06.85,EN,,0,0,0,,It may or may not be obvious, Dialogue: 0,0:48:06.85,0:48:08.17,EN,,0,0,0,,and I don't want to get into that now. Dialogue: 0,0:48:10.90,0:48:12.45,EN,,0,0,0,,But diag2 Dialogue: 0,0:48:13.30,0:48:15.82,EN,,0,0,0,,is again a procedure of one argument p. Dialogue: 0,0:48:15.82,0:48:17.47,EN,,0,0,0,,It's almost the same as the previous one, Dialogue: 0,0:48:17.72,0:48:24.32,EN,,0,0,0,,which is, if it's safe to compute p on p, Dialogue: 0,0:48:25.17,0:48:26.67,EN,,0,0,0,,then I'm going to produce-- Dialogue: 0,0:48:27.26,0:48:28.14,EN,,0,0,0,,Oops, if Dialogue: 0,0:48:29.31,0:48:31.02,EN,,0,0,0,,then I want to compute Dialogue: 0,0:48:31.57,0:48:37.58,EN,,0,0,0,,some other things Dialogue: 0,0:48:38.96,0:48:40.21,EN,,0,0,0,,Otherwise I'm going to put out false. Dialogue: 0,0:48:43.60,0:48:45.30,EN,,0,0,0,,Where other then it says, Dialogue: 0,0:48:45.47,0:48:46.35,EN,,0,0,0,,whatever p of p, Dialogue: 0,0:48:46.35,0:48:47.47,EN,,0,0,0,,I'm going to put out something else. Dialogue: 0,0:48:48.88,0:48:50.03,EN,,0,0,0,,I can give you an example of Dialogue: 0,0:48:50.07,0:48:51.52,EN,,0,0,0,,a definition of other than Dialogue: 0,0:48:51.60,0:48:52.57,EN,,0,0,0,,which I think works. Dialogue: 0,0:48:53.89,0:48:54.51,EN,,0,0,0,,Let's see. Dialogue: 0,0:48:55.64,0:48:56.08,EN,,0,0,0,,Yes. Dialogue: 0,0:48:56.33,0:48:57.26,EN,,0,0,0,,Where other than Dialogue: 0,0:49:04.03,0:49:06.11,EN,,0,0,0,,be a procedure of one argument x Dialogue: 0,0:49:06.57,0:49:07.26,EN,,0,0,0,,which says, Dialogue: 0,0:49:08.05,0:49:12.96,EN,,0,0,0,,if its eq x to, say, quote a, Dialogue: 0,0:49:13.47,0:49:15.07,EN,,0,0,0,,then the answer is quote b. Dialogue: 0,0:49:15.72,0:49:16.80,EN,,0,0,0,,Otherwise it's quote a. Dialogue: 0,0:49:20.27,0:49:21.90,EN,,0,0,0,,That always produces something Dialogue: 0,0:49:22.07,0:49:23.45,EN,,0,0,0,,which is not what its argument is. Dialogue: 0,0:49:25.20,0:49:26.12,EN,,0,0,0,,That's all it is. Dialogue: 0,0:49:26.54,0:49:27.37,EN,,0,0,0,,That's all I wanted. Dialogue: 0,0:49:28.25,0:49:29.58,EN,,0,0,0,,Well now let's consider this one, Dialogue: 0,0:49:29.58,0:49:31.15,EN,,0,0,0,,diag2 of diag2. Dialogue: 0,0:49:38.28,0:49:38.94,EN,,0,0,0,,Well look. Dialogue: 0,0:49:39.95,0:49:41.72,EN,,0,0,0,,This only does something dangerous, Dialogue: 0,0:49:42.00,0:49:43.45,EN,,0,0,0,,like calling p of p, Dialogue: 0,0:49:44.75,0:49:45.95,EN,,0,0,0,,if it's safe to do so. Dialogue: 0,0:49:47.47,0:49:49.16,EN,,0,0,0,,So if safe defined at all, Dialogue: 0,0:49:50.30,0:49:52.49,EN,,0,0,0,,if you can define such a procedure, safe, Dialogue: 0,0:49:52.97,0:49:54.32,EN,,0,0,0,,then this procedure Dialogue: 0,0:49:54.60,0:49:56.40,EN,,0,0,0,,is always defined and therefore safe Dialogue: 0,0:49:56.52,0:49:57.22,EN,,0,0,0,,on any inputs. Dialogue: 0,0:50:01.54,0:50:03.50,EN,,0,0,0,,So diag2 of diag2 Dialogue: 0,0:50:03.87,0:50:12.20,EN,,0,0,0,,must reduce to other than diag2 of diag2. Dialogue: 0,0:50:15.82,0:50:16.97,EN,,0,0,0,,And that doesn't make sense, Dialogue: 0,0:50:17.80,0:50:19.02,EN,,0,0,0,,so we have a contradiction, Dialogue: 0,0:50:19.85,0:50:21.57,EN,,0,0,0,,and therefore we can't define safe. Dialogue: 0,0:50:22.95,0:50:24.23,EN,,0,0,0,,I just waned to do that twice, Dialogue: 0,0:50:24.78,0:50:25.82,EN,,0,0,0,,slightly differently, Dialogue: 0,0:50:26.84,0:50:27.90,EN,,0,0,0,,so you wouldn't feel Dialogue: 0,0:50:29.07,0:50:30.86,EN,,0,0,0,,that the first one was a trick. Dialogue: 0,0:50:32.54,0:50:33.45,EN,,0,0,0,,They may be both tricks, Dialogue: 0,0:50:33.80,0:50:35.15,EN,,0,0,0,,but they're at least slightly different. Dialogue: 0,0:50:37.30,0:50:39.20,EN,,0,0,0,,So I suppose that pretty much wraps it up. Dialogue: 0,0:50:40.03,0:50:41.97,EN,,0,0,0,,I've just proved what we call the halting theorem, Dialogue: 0,0:50:43.00,0:50:44.70,EN,,0,0,0,,and I suppose with that we're going to halt. Dialogue: 0,0:50:46.72,0:50:47.63,EN,,0,0,0,,I hope you have a good time. Dialogue: 0,0:50:50.90,0:50:51.76,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:50:53.30,0:50:53.56,EN,,0,0,0,,Yes. Dialogue: 0,0:50:53.81,0:50:56.27,EN,,0,0,0,,AUDIENCE: What is the value of s of diag1? Dialogue: 0,0:50:56.75,0:50:57.23,EN,,0,0,0,,PROFESSOR: Of what? Dialogue: 0,0:50:57.50,0:50:58.80,EN,,0,0,0,,AUDIENCE: S of diag1. Dialogue: 0,0:51:00.12,0:51:02.20,EN,,0,0,0,,If you said s is a function, and then we can Dialogue: 0,0:51:02.30,0:51:03.63,EN,,0,0,0,,PROFESSOR: Oh, I don't know. Dialogue: 0,0:51:03.87,0:51:04.35,EN,,0,0,0,,I don't know. Dialogue: 0,0:51:04.35,0:51:04.88,EN,,0,0,0,,It's a function, Dialogue: 0,0:51:04.88,0:51:05.85,EN,,0,0,0,,but I don't know how to compute it. Dialogue: 0,0:51:06.80,0:51:08.00,EN,,0,0,0,,I can't do it. Dialogue: 0,0:51:08.61,0:51:09.64,EN,,0,0,0,,I'm just a machine, too. Dialogue: 0,0:51:11.53,0:51:11.88,EN,,0,0,0,,Right? Dialogue: 0,0:51:11.90,0:51:13.37,EN,,0,0,0,,And there's no machine Dialogue: 0,0:51:13.37,0:51:14.05,EN,,0,0,0,,that in principle-- Dialogue: 0,0:51:14.47,0:51:16.87,EN,,0,0,0,,it might be that in that particular case you just asked, Dialogue: 0,0:51:16.87,0:51:18.32,EN,,0,0,0,,with some thinking I could figure it out. Dialogue: 0,0:51:18.58,0:51:19.37,EN,,0,0,0,,But in general Dialogue: 0,0:51:19.60,0:51:21.05,EN,,0,0,0,,I can't compute the value of s Dialogue: 0,0:51:21.05,0:51:22.52,EN,,0,0,0,,any better than any other machine can. Dialogue: 0,0:51:23.78,0:51:24.92,EN,,0,0,0,,There is such a function, Dialogue: 0,0:51:25.92,0:51:28.00,EN,,0,0,0,,it's just that no machine can be built to compute it. Dialogue: 0,0:51:29.58,0:51:30.05,EN,,0,0,0,,Now Dialogue: 0,0:51:30.67,0:51:33.67,EN,,0,0,0,,there's a way of saying that that should not be surprising. Dialogue: 0,0:51:35.22,0:51:36.25,EN,,0,0,0,,Going through this-- Dialogue: 0,0:51:36.25,0:51:38.36,EN,,0,0,0,,I mean, I don't have time to do this here, Dialogue: 0,0:51:38.45,0:51:43.00,EN,,0,0,0,,but the number of functions is very large. Dialogue: 0,0:51:44.40,0:51:47.58,EN,,0,0,0,,If there's a certain number of answers possible Dialogue: 0,0:51:47.75,0:51:49.62,EN,,0,0,0,,and a certain number of inputs possible, Dialogue: 0,0:51:49.87,0:51:51.80,EN,,0,0,0,,then it's the number of answers raised to the number inputs Dialogue: 0,0:51:51.80,0:51:53.20,EN,,0,0,0,,is the number of possible functions. Dialogue: 0,0:51:54.50,0:51:55.48,EN,,0,0,0,,On one variable. Dialogue: 0,0:51:56.51,0:51:59.24,EN,,0,0,0,,Now that's always bigger Dialogue: 0,0:52:00.09,0:52:03.21,EN,,0,0,0,,than the thing you're raising to, Dialogue: 0,0:52:03.58,0:52:04.32,EN,,0,0,0,,the exponent. Dialogue: 0,0:52:05.48,0:52:09.80,EN,,0,0,0,,The number of functions is larger Dialogue: 0,0:52:09.95,0:52:12.72,EN,,0,0,0,,than the number of programs Dialogue: 0,0:52:13.30,0:52:14.10,EN,,0,0,0,,that one can write, Dialogue: 0,0:52:14.82,0:52:16.45,EN,,0,0,0,,by an infinity counting argument. Dialogue: 0,0:52:17.57,0:52:19.00,EN,,0,0,0,,And it's much larger. Dialogue: 0,0:52:19.47,0:52:22.12,EN,,0,0,0,,So there must be a lot of functions Dialogue: 0,0:52:22.12,0:52:23.48,EN,,0,0,0,,that can't be computed by programs. Dialogue: 0,0:52:25.92,0:52:26.59,EN,,0,0,0,,AUDIENCE: A few moments ago Dialogue: 0,0:52:26.64,0:52:28.25,EN,,0,0,0,,you were talking about specifications Dialogue: 0,0:52:28.30,0:52:30.04,EN,,0,0,0,,and automatic generation of solutions. Dialogue: 0,0:52:30.64,0:52:31.61,EN,,0,0,0,,Do you see any steps Dialogue: 0,0:52:31.82,0:52:33.36,EN,,0,0,0,,between specifications and solutions? Dialogue: 0,0:52:37.25,0:52:38.22,EN,,0,0,0,,PROFESSOR: Steps between. Dialogue: 0,0:52:38.72,0:52:39.37,EN,,0,0,0,,You mean, you're saying, Dialogue: 0,0:52:39.37,0:52:42.60,EN,,0,0,0,,how you go about constructing Dialogue: 0,0:52:42.60,0:52:44.78,EN,,0,0,0,,devices given that have specifications for the device? Dialogue: 0,0:52:45.05,0:52:48.36,EN,,0,0,0,,AUDIENCE: There's a lot of software engineering Dialogue: 0,0:52:48.36,0:52:49.90,EN,,0,0,0,,that goes through specifications through Dialogue: 0,0:52:49.90,0:52:51.90,EN,,0,0,0,,many layers of design and then implementation. Dialogue: 0,0:52:52.43,0:52:52.85,EN,,0,0,0,,PROFESSOR: Yes? Dialogue: 0,0:52:52.85,0:52:53.70,EN,,0,0,0,,AUDIENCE: I was curious Dialogue: 0,0:52:53.70,0:52:54.62,EN,,0,0,0,,if you think that's realistic. Dialogue: 0,0:52:55.60,0:52:57.17,EN,,0,0,0,,PROFESSOR: Well I think that some of it's realistic Dialogue: 0,0:52:57.17,0:52:58.10,EN,,0,0,0,,and some of it isn't. Dialogue: 0,0:52:58.10,0:53:00.32,EN,,0,0,0,,I mean, surely if I want to build an electrical filter Dialogue: 0,0:53:01.17,0:53:07.16,EN,,0,0,0,,and I have a rather interesting possibility. Dialogue: 0,0:53:07.16,0:53:09.42,EN,,0,0,0,,Supposing I want to build a thing that matches Dialogue: 0,0:53:09.64,0:53:14.07,EN,,0,0,0,,that matches some power output to the radio transmitter, Dialogue: 0,0:53:14.47,0:53:18.75,EN,,0,0,0,,to some antenna. Dialogue: 0,0:53:19.90,0:53:21.47,EN,,0,0,0,,And I'm really out of this power-- Dialogue: 0,0:53:21.48,0:53:23.04,EN,,0,0,0,,it's output tube out here. Dialogue: 0,0:53:23.23,0:53:25.26,EN,,0,0,0,,And the problem is that they have different impedances. Dialogue: 0,0:53:25.92,0:53:27.55,EN,,0,0,0,,I want them to match the impedances. Dialogue: 0,0:53:27.55,0:53:28.97,EN,,0,0,0,,I also want to make a filter in there Dialogue: 0,0:53:29.15,0:53:31.71,EN,,0,0,0,,which is going to get rid of some harmonic radiation. Dialogue: 0,0:53:32.78,0:53:36.63,EN,,0,0,0,,Well one old-fashioned technique for doing this is called Dialogue: 0,0:53:36.82,0:53:38.67,EN,,0,0,0,,image impedances, or something like that. Dialogue: 0,0:53:38.86,0:53:39.50,EN,,0,0,0,,And what you do Dialogue: 0,0:53:39.50,0:53:40.85,EN,,0,0,0,,is you say you have a basic module Dialogue: 0,0:53:40.85,0:53:42.75,EN,,0,0,0,,called an L-section. Dialogue: 0,0:53:43.30,0:53:43.98,EN,,0,0,0,,Looks like this. Dialogue: 0,0:53:47.08,0:53:49.80,EN,,0,0,0,,If I happen to connect this to some resistance, r, Dialogue: 0,0:53:50.05,0:53:52.60,EN,,0,0,0,,and if I make this impedance x, xl, Dialogue: 0,0:53:52.72,0:53:55.20,EN,,0,0,0,,and if it happens to be q times r, Dialogue: 0,0:53:55.26,0:53:58.52,EN,,0,0,0,,then this produces a low pass filter Dialogue: 0,0:53:58.52,0:54:00.72,EN,,0,0,0,,with a q square plus one impedance match. Dialogue: 0,0:54:02.11,0:54:02.86,EN,,0,0,0,,Just what I need. Dialogue: 0,0:54:03.12,0:54:04.28,EN,,0,0,0,,Because now I can take two of these, Dialogue: 0,0:54:04.30,0:54:05.08,EN,,0,0,0,,hook them together Dialogue: 0,0:54:05.82,0:54:06.38,EN,,0,0,0,,like this. Dialogue: 0,0:54:11.66,0:54:13.15,EN,,0,0,0,,OK, and I take another one Dialogue: 0,0:54:16.00,0:54:17.45,EN,,0,0,0,,and I'll hook them together like that. Dialogue: 0,0:54:18.29,0:54:19.95,EN,,0,0,0,,And I have two L-sections hooked together. Dialogue: 0,0:54:20.32,0:54:23.07,EN,,0,0,0,,And this will step the impedance down to one that I know, Dialogue: 0,0:54:23.37,0:54:25.22,EN,,0,0,0,,and this will step it up to one I know. Dialogue: 0,0:54:25.53,0:54:26.64,EN,,0,0,0,,Each of these is a low pass filter Dialogue: 0,0:54:26.67,0:54:27.82,EN,,0,0,0,,getting rid of some harmonics. Dialogue: 0,0:54:28.09,0:54:29.07,EN,,0,0,0,,It's good filter, Dialogue: 0,0:54:29.07,0:54:30.27,EN,,0,0,0,,it's called a pie-section filter. Dialogue: 0,0:54:30.27,0:54:30.62,EN,,0,0,0,,Great. Dialogue: 0,0:54:31.70,0:54:34.09,EN,,0,0,0,,Except for the fact that in doing what I just did, Dialogue: 0,0:54:34.12,0:54:37.85,EN,,0,0,0,,I've made a terrible inefficiency in this system. Dialogue: 0,0:54:38.62,0:54:39.60,EN,,0,0,0,,I've made two coils Dialogue: 0,0:54:39.61,0:54:40.59,EN,,0,0,0,,where I should have made one. Dialogue: 0,0:54:41.62,0:54:44.60,EN,,0,0,0,,And the problem with most software engineering art Dialogue: 0,0:54:44.89,0:54:46.88,EN,,0,0,0,,is that there's no mechanism, Dialogue: 0,0:54:46.92,0:54:48.65,EN,,0,0,0,,other than people optimization and compilers, Dialogue: 0,0:54:48.80,0:54:51.34,EN,,0,0,0,,for getting rid of the redundant parts Dialogue: 0,0:54:51.34,0:54:53.55,EN,,0,0,0,,that are constructed when doing top down design. Dialogue: 0,0:54:55.35,0:54:56.07,EN,,0,0,0,,It's even worse, Dialogue: 0,0:54:56.07,0:54:57.58,EN,,0,0,0,,there are lots of very important structures Dialogue: 0,0:54:57.60,0:54:59.02,EN,,0,0,0,,that you can't construct at all this way. Dialogue: 0,0:55:01.11,0:55:03.53,EN,,0,0,0,,So I think that the standard top down design Dialogue: 0,0:55:03.53,0:55:04.87,EN,,0,0,0,,is a rather shallow business. Dialogue: 0,0:55:05.71,0:55:06.60,EN,,0,0,0,,Doesn't really capture Dialogue: 0,0:55:06.60,0:55:08.10,EN,,0,0,0,,what people want to do in design. Dialogue: 0,0:55:08.31,0:55:10.10,EN,,0,0,0,,I'll give you another electrical example. Dialogue: 0,0:55:10.10,0:55:11.75,EN,,0,0,0,,Electrical examples are so much clearer Dialogue: 0,0:55:11.90,0:55:13.13,EN,,0,0,0,,than computational examples, Dialogue: 0,0:55:13.16,0:55:14.78,EN,,0,0,0,,because computation examples require Dialogue: 0,0:55:14.80,0:55:16.52,EN,,0,0,0,,a certain degree of complexity to explain them. Dialogue: 0,0:55:17.22,0:55:19.16,EN,,0,0,0,,But one of my favorite examples Dialogue: 0,0:55:19.16,0:55:20.04,EN,,0,0,0,,in the electrical world Dialogue: 0,0:55:20.60,0:55:22.80,EN,,0,0,0,,is how would I ever come up with the output stage Dialogue: 0,0:55:23.28,0:55:26.55,EN,,0,0,0,,of this inter-stage connection in an IF amplifier. Dialogue: 0,0:55:27.53,0:55:29.44,EN,,0,0,0,,It's a little transistor here, Dialogue: 0,0:55:29.52,0:55:31.50,EN,,0,0,0,,and let's see. Dialogue: 0,0:55:32.41,0:55:33.40,EN,,0,0,0,,Well I'm going to have a tank, Dialogue: 0,0:55:36.45,0:55:39.17,EN,,0,0,0,,and I'm going to hook this up to, say, Dialogue: 0,0:55:41.37,0:55:43.97,EN,,0,0,0,,I'm going to link-couple that to the input of the next stage. Dialogue: 0,0:55:44.36,0:55:47.47,EN,,0,0,0,,Here's a perfectly plausible plan-- Dialogue: 0,0:55:48.22,0:55:50.87,EN,,0,0,0,,well except for the fact that since I put that going up Dialogue: 0,0:55:50.87,0:55:52.92,EN,,0,0,0,,I should make that going that way. OK? Dialogue: 0,0:55:53.17,0:55:55.45,EN,,0,0,0,,Here's a perfectly plausible plan for a-- Dialogue: 0,0:55:55.98,0:55:56.57,EN,,0,0,0,,no I shouldn't. Dialogue: 0,0:55:57.12,0:55:57.79,EN,,0,0,0,,I'm dumb. Dialogue: 0,0:55:58.40,0:55:59.07,EN,,0,0,0,,Excuse me. Dialogue: 0,0:55:59.69,0:56:00.42,EN,,0,0,0,,Doesn't matter. Dialogue: 0,0:56:00.73,0:56:01.54,EN,,0,0,0,,The point is it's a perfect Dialogue: 0,0:56:01.54,0:56:03.42,EN,,0,0,0,,plan for a couple two stages together. Dialogue: 0,0:56:04.54,0:56:06.92,EN,,0,0,0,,Now what the problem is what's this hierarchically? Dialogue: 0,0:56:07.62,0:56:08.80,EN,,0,0,0,,It's not one thing. Dialogue: 0,0:56:09.48,0:56:11.99,EN,,0,0,0,,Hierarchically it doesn't make any sense at all. Dialogue: 0,0:56:11.99,0:56:14.32,EN,,0,0,0,,It's the inductance of a tuned circuit, Dialogue: 0,0:56:15.55,0:56:18.02,EN,,0,0,0,,it's the primary of a transformer, Dialogue: 0,0:56:19.10,0:56:21.82,EN,,0,0,0,,and it's also the DC path by Dialogue: 0,0:56:21.82,0:56:23.57,EN,,0,0,0,,which bias conditions get to the Dialogue: 0,0:56:23.57,0:56:25.10,EN,,0,0,0,,collector of that transistor. Dialogue: 0,0:56:26.46,0:56:28.35,EN,,0,0,0,,And there's no simple top-down design Dialogue: 0,0:56:28.38,0:56:30.17,EN,,0,0,0,,that's going to produce a structure like that Dialogue: 0,0:56:30.22,0:56:34.02,EN,,0,0,0,,with so many overlapping uses for a particular thing. Dialogue: 0,0:56:34.53,0:56:36.72,EN,,0,0,0,,Playing Scrabble, Dialogue: 0,0:56:36.96,0:56:39.88,EN,,0,0,0,,where you have to do triple word scores, or whatever, Dialogue: 0,0:56:40.49,0:56:43.60,EN,,0,0,0,,is not so easy in top-down design strategy. Dialogue: 0,0:56:44.95,0:56:47.08,EN,,0,0,0,,Yet most of real engineering is based on Dialogue: 0,0:56:47.36,0:56:50.70,EN,,0,0,0,,on getting the most oomph for effort. Dialogue: 0,0:56:52.14,0:56:53.52,EN,,0,0,0,,And that's what you're seeing here. Dialogue: 0,0:56:54.86,0:56:55.55,EN,,0,0,0,,Yeah? Dialogue: 0,0:56:55.55,0:56:56.81,EN,,0,0,0,,AUDIENCE: Is this the last question? Dialogue: 0,0:57:00.28,0:57:02.03,EN,,0,0,0,,[LAUGHTER] Dialogue: 0,0:57:18.64,0:57:19.63,EN,,0,0,0,,PROFESSOR: Apparently so. Dialogue: 0,0:57:23.57,0:57:24.12,EN,,0,0,0,,Thank you. Dialogue: 0,0:57:25.30,0:57:36.50,EN,,0,0,0,,[APPLAUSE] ================================================ FILE: Ass/lec1a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal PlayResX: 640 PlayResY: 480 Scroll Position: 1037 Active Line: 1035 Audio URI: lec1a_Rerip_remux.mp4 Video Zoom Percent: 0.875 Video File: lec1a_Rerip_remux.mp4 Video Aspect Ratio: c1.33333 Video Position: 1302 Last Style Storage: Default YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:14.71,0:00:17.89,EN,,0,0,0,,I'd like to welcome you to this course on computer science. Dialogue: 0,0:00:28.40,0:00:29.85,EN,,0,0,0,,Actually, that's a terrible way to start. Dialogue: 0,0:00:29.85,0:00:32.34,EN,,0,0,0,,Computer science is a terrible name for this business. Dialogue: 0,0:00:32.83,0:00:34.30,EN,,0,0,0,,First of all, it's not a science. Dialogue: 0,0:00:35.92,0:00:39.81,EN,,0,0,0,,It might be engineering or it might be art, Dialogue: 0,0:00:40.09,0:00:42.91,EN,,0,0,0,,but we'll actually see that computer so-called science Dialogue: 0,0:00:42.93,0:00:44.97,EN,,0,0,0,,actually has a lot in common with magic, Dialogue: 0,0:00:45.01,0:00:46.35,EN,,0,0,0,,and we'll see that in this course. Dialogue: 0,0:00:47.28,0:00:48.22,EN,,0,0,0,,So it's not a science. Dialogue: 0,0:00:48.23,0:00:52.30,EN,,0,0,0,,It's also not really very much about computers. Dialogue: 0,0:00:53.39,0:00:55.47,EN,,0,0,0,,And it's not about computers in the same sense Dialogue: 0,0:00:55.47,0:01:00.05,EN,,0,0,0,,that physics is not really about particle accelerators, Dialogue: 0,0:01:00.80,0:01:05.58,EN,,0,0,0,,and biology is not really about microscopes and petri dishes. Dialogue: 0,0:01:06.46,0:01:10.25,EN,,0,0,0,,And it's not about computers in the same sense Dialogue: 0,0:01:10.31,0:01:14.88,EN,,0,0,0,,that geometry is not really about using surveying instruments. Dialogue: 0,0:01:16.48,0:01:19.01,EN,,0,0,0,,In fact, there's a lot of commonality Dialogue: 0,0:01:19.33,0:01:21.45,EN,,0,0,0,,between computer science and geometry. Dialogue: 0,0:01:21.45,0:01:22.66,EN,,0,0,0,,Geometry, first of all, Dialogue: 0,0:01:23.02,0:01:24.98,EN,,0,0,0,,is another subject with a lousy name. Dialogue: 0,0:01:25.58,0:01:27.85,EN,,0,0,0,,The name comes from Gaia, meaning the Earth, Dialogue: 0,0:01:27.90,0:01:29.09,EN,,0,0,0,,and metron, meaning to measure. Dialogue: 0,0:01:29.82,0:01:33.39,EN,,0,0,0,,Geometry originally meant measuring the Earth or surveying. Dialogue: 0,0:01:34.37,0:01:36.89,EN,,0,0,0,,And the reason for that was that, thousands of years ago, Dialogue: 0,0:01:37.69,0:01:41.69,EN,,0,0,0,,the Egyptian priesthood developed the rudiments of geometry Dialogue: 0,0:01:42.59,0:01:46.33,EN,,0,0,0,,in order to figure out how to restore the boundaries of fields Dialogue: 0,0:01:46.35,0:01:48.69,EN,,0,0,0,,that were destroyed in the annual flooding of the Nile. Dialogue: 0,0:01:49.47,0:01:50.65,EN,,0,0,0,,And to the Egyptians who did that, Dialogue: 0,0:01:50.65,0:01:53.93,EN,,0,0,0,,geometry really was the use of surveying instruments. Dialogue: 0,0:01:55.63,0:01:58.55,EN,,0,0,0,,Now, the reason that we think computer science is about computers Dialogue: 0,0:01:58.57,0:02:02.49,EN,,0,0,0,,is pretty much the same reason that the Egyptians thought geometry Dialogue: 0,0:02:02.51,0:02:04.10,EN,,0,0,0,,was about surveying instruments. Dialogue: 0,0:02:04.59,0:02:07.37,EN,,0,0,0,,And that is, when some field is just getting started Dialogue: 0,0:02:07.39,0:02:09.86,EN,,0,0,0,,and you don't really understand it very well, Dialogue: 0,0:02:11.10,0:02:16.64,EN,,0,0,0,,it's very easy to confuse the essence of what you're doing with the tools that you use. Dialogue: 0,0:02:17.65,0:02:20.30,EN,,0,0,0,,And indeed, on some absolute scale of things, Dialogue: 0,0:02:20.30,0:02:24.82,EN,,0,0,0,,we probably know less about the essence of computer science Dialogue: 0,0:02:24.83,0:02:27.49,EN,,0,0,0,,than the ancient Egyptians really knew about geometry. Dialogue: 0,0:02:30.25,0:02:32.64,EN,,0,0,0,,Well, what do I mean by the essence of computer science? Dialogue: 0,0:02:32.65,0:02:34.41,EN,,0,0,0,,What do I mean by the essence of geometry? Dialogue: 0,0:02:34.41,0:02:36.45,EN,,0,0,0,,See, it's certainly true that these Egyptians went off Dialogue: 0,0:02:36.46,0:02:37.67,EN,,0,0,0,,and used surveying instruments, Dialogue: 0,0:02:37.69,0:02:41.55,EN,,0,0,0,,but when we look back on them after a couple of thousand years, Dialogue: 0,0:02:41.57,0:02:41.85,EN,,0,0,0,,we say, Dialogue: 0,0:02:41.87,0:02:43.64,EN,,0,0,0,,gee, what they were doing, Dialogue: 0,0:02:43.71,0:02:45.48,EN,,0,0,0,,the important stuff they were doing, Dialogue: 0,0:02:45.62,0:02:50.45,EN,,0,0,0,,was to begin to formalize notions about space and time, Dialogue: 0,0:02:51.58,0:02:57.53,EN,,0,0,0,,to start a way of talking about mathematical truths formally. Dialogue: 0,0:02:58.01,0:02:59.61,EN,,0,0,0,,That led to the axiomatic method. Dialogue: 0,0:02:59.61,0:03:02.53,EN,,0,0,0,,That led to sort of all of modern mathematics, Dialogue: 0,0:03:04.16,0:03:06.90,EN,,0,0,0,,figuring out a way to talk precisely about Dialogue: 0,0:03:07.25,0:03:10.19,EN,,0,0,0,,so-called declarative knowledge, what is true. Dialogue: 0,0:03:12.45,0:03:16.25,EN,,0,0,0,,Well, similarly, I think in the future people will look back and say, Dialogue: 0,0:03:16.27,0:03:19.36,EN,,0,0,0,,yes, those primitives in the 20th century were fiddling around Dialogue: 0,0:03:19.36,0:03:21.20,EN,,0,0,0,,with these gadgets called computers, Dialogue: 0,0:03:21.77,0:03:26.25,EN,,0,0,0,,but really what they were doing is starting to learn Dialogue: 0,0:03:26.25,0:03:32.55,EN,,0,0,0,,how to formalize intuitions about process, Dialogue: 0,0:03:32.64,0:03:34.13,EN,,0,0,0,,how to do things, Dialogue: 0,0:03:39.02,0:03:51.25,EN,,0,0,0,,starting to develop a way to talk precisely about how-to knowledge, Dialogue: 0,0:03:51.76,0:03:56.03,EN,,0,0,0,,as opposed to geometry that talks about what is true. Dialogue: 0,0:03:56.53,0:03:58.57,EN,,0,0,0,,Let me give you an example of that. Dialogue: 0,0:04:02.30,0:04:02.69,EN,,0,0,0,,Let's take a look Dialogue: 0,0:04:02.70,0:04:09.82,EN,,0,0,0,,Here is a piece of mathematics that says what a square root is. Dialogue: 0,0:04:10.09,0:04:14.35,EN,,0,0,0,,The square root of X is the number Y, Dialogue: 0,0:04:15.98,0:04:20.38,EN,,0,0,0,,such that Y squared is equal to X and Y is greater than 0. Dialogue: 0,0:04:20.43,0:04:22.50,EN,,0,0,0,,Now, that's a fine piece of mathematics, Dialogue: 0,0:04:22.88,0:04:25.25,EN,,0,0,0,,but just telling you what a square root is Dialogue: 0,0:04:25.63,0:04:30.29,EN,,0,0,0,,doesn't really say anything about how you might go out and find one. Dialogue: 0,0:04:31.42,0:04:35.90,EN,,0,0,0,,So let's contrast that with a piece of imperative knowledge, Dialogue: 0,0:04:37.13,0:04:39.92,EN,,0,0,0,,how you might go out and find a square root. Dialogue: 0,0:04:39.95,0:04:45.74,EN,,0,0,0,,This, in fact, also comes from Egypt, not ancient, ancient Egypt. Dialogue: 0,0:04:45.76,0:04:48.88,EN,,0,0,0,,This is an algorithm due to Heron of Alexandria, Dialogue: 0,0:04:49.90,0:04:52.77,EN,,0,0,0,,called how to find a square root by successive averaging. Dialogue: 0,0:04:52.89,0:04:55.13,EN,,0,0,0,,And what it says is that, Dialogue: 0,0:04:55.15,0:04:58.06,EN,,0,0,0,,in order to find a square root, Dialogue: 0,0:05:03.34,0:05:08.33,EN,,0,0,0,,you make a guess, you improve that guess -- Dialogue: 0,0:05:10.19,0:05:11.44,EN,,0,0,0,,and the way you improve the guess Dialogue: 0,0:05:11.45,0:05:13.95,EN,,0,0,0,,is to average the guess and X over the guess, Dialogue: 0,0:05:14.41,0:05:15.60,EN,,0,0,0,,and we'll talk a little bit later about Dialogue: 0,0:05:15.61,0:05:17.12,EN,,0,0,0,,why that's a reasonable thing-- Dialogue: 0,0:05:17.14,0:05:19.37,EN,,0,0,0,,and you keep improving the guess until it's good enough. Dialogue: 0,0:05:19.73,0:05:20.85,EN,,0,0,0,,That's a method. Dialogue: 0,0:05:20.99,0:05:24.65,EN,,0,0,0,,That's how to do something as opposed to Dialogue: 0,0:05:24.72,0:05:27.33,EN,,0,0,0,,declarative knowledge that says what you're looking for. Dialogue: 0,0:05:28.05,0:05:29.76,EN,,0,0,0,,That's a process. Dialogue: 0,0:05:34.40,0:05:38.25,EN,,0,0,0,,Well, what's a process in general? Dialogue: 0,0:05:39.01,0:05:40.14,EN,,0,0,0,,It's kind of hard to say. Dialogue: 0,0:05:40.16,0:05:43.72,EN,,0,0,0,,You can think of it as like a magical spirit Dialogue: 0,0:05:44.77,0:05:47.33,EN,,0,0,0,,that sort of lives in the computer and does something. Dialogue: 0,0:05:48.01,0:05:54.11,EN,,0,0,0,,And the thing that directs a process is Dialogue: 0,0:05:54.13,0:05:57.98,EN,,0,0,0,,a pattern of rules called a procedure. Dialogue: 0,0:06:01.98,0:06:04.73,EN,,0,0,0,,So procedures are the spells, if you like, Dialogue: 0,0:06:05.23,0:06:09.40,EN,,0,0,0,,that control these magical spirits that are the processes. Dialogue: 0,0:06:10.75,0:06:12.75,EN,,0,0,0,,I guess you know everyone needs a magical language, Dialogue: 0,0:06:12.77,0:06:14.55,EN,,0,0,0,,and sorcerers, real sorcerers, Dialogue: 0,0:06:14.57,0:06:18.59,EN,,0,0,0,,use ancient Arcadian or Sumerian or Babylonian or whatever. Dialogue: 0,0:06:18.62,0:06:20.09,EN,,0,0,0,,We're going to conjure our spirits Dialogue: 0,0:06:20.13,0:06:22.71,EN,,0,0,0,,in a magical language called Lisp, Dialogue: 0,0:06:24.37,0:06:28.01,EN,,0,0,0,,which is a language designed for talking about, Dialogue: 0,0:06:28.57,0:06:31.84,EN,,0,0,0,,for casting the spells that are procedures to direct the processes. Dialogue: 0,0:06:31.87,0:06:33.91,EN,,0,0,0,,Now, it's very easy to learn Lisp. Dialogue: 0,0:06:33.97,0:06:35.98,EN,,0,0,0,,In fact, in a few minutes, I'm going to teach you, Dialogue: 0,0:06:36.00,0:06:37.16,EN,,0,0,0,,essentially, all of Lisp. Dialogue: 0,0:06:37.37,0:06:38.96,EN,,0,0,0,,I'm going to teach you, essentially, all of the rules. Dialogue: 0,0:06:40.77,0:06:43.65,EN,,0,0,0,,And you shouldn't find that particularly surprising. Dialogue: 0,0:06:43.69,0:06:45.87,EN,,0,0,0,,That's sort of like saying it's very easy Dialogue: 0,0:06:45.90,0:06:47.01,EN,,0,0,0,,to learn the rules of chess. Dialogue: 0,0:06:47.04,0:06:48.13,EN,,0,0,0,,And indeed, in a few minutes, Dialogue: 0,0:06:48.17,0:06:49.70,EN,,0,0,0,,you can tell somebody the rules of chess. Dialogue: 0,0:06:50.81,0:06:52.24,EN,,0,0,0,,But of course, that's very different from Dialogue: 0,0:06:52.25,0:06:55.37,EN,,0,0,0,,saying you understand the implications of those rules Dialogue: 0,0:06:55.42,0:06:58.05,EN,,0,0,0,,and how to use those rules to become a masterful chess player. Dialogue: 0,0:06:58.49,0:06:59.82,EN,,0,0,0,,Well, Lisp is the same way. Dialogue: 0,0:07:00.41,0:07:02.18,EN,,0,0,0,,We're going to state the rules in a few minutes, Dialogue: 0,0:07:02.36,0:07:03.55,EN,,0,0,0,,and it'll be very easy to see. Dialogue: 0,0:07:03.62,0:07:07.09,EN,,0,0,0,,But what's really hard is going to be the implications of those rules, Dialogue: 0,0:07:07.32,0:07:10.46,EN,,0,0,0,,how you exploit those rules to be a master programmer. Dialogue: 0,0:07:12.06,0:07:15.29,EN,,0,0,0,,And the implications of those rules are going to take us the, Dialogue: 0,0:07:15.31,0:07:18.56,EN,,0,0,0,,well, the whole rest of the subject and, of course, way beyond. Dialogue: 0,0:07:21.45,0:07:23.11,EN,,0,0,0,,OK, so in computer science, Dialogue: 0,0:07:24.49,0:07:26.19,EN,,0,0,0,,we're in the business of Dialogue: 0,0:07:26.21,0:07:30.58,EN,,0,0,0,,formalizing this sort of how-to imperative knowledge, Dialogue: 0,0:07:30.62,0:07:32.10,EN,,0,0,0,,how to do stuff. Dialogue: 0,0:07:33.37,0:07:35.39,EN,,0,0,0,,And the real issues of computer science are, of course, Dialogue: 0,0:07:35.41,0:07:38.36,EN,,0,0,0,,not telling people how to do square roots. Dialogue: 0,0:07:39.09,0:07:40.06,EN,,0,0,0,,Because if that was all it was, Dialogue: 0,0:07:40.09,0:07:41.34,EN,,0,0,0,,there wouldn't be no big deal. Dialogue: 0,0:07:41.57,0:07:44.05,EN,,0,0,0,,The real problems come when we try to Dialogue: 0,0:07:44.08,0:07:46.16,EN,,0,0,0,,build very, very large systems, Dialogue: 0,0:07:46.61,0:07:49.53,EN,,0,0,0,,computer programs that are thousands of pages long, Dialogue: 0,0:07:49.58,0:07:53.98,EN,,0,0,0,,so long that nobody can really hold them in their heads all at once. Dialogue: 0,0:07:54.73,0:07:58.81,EN,,0,0,0,,And the only reason that that's possible is because Dialogue: 0,0:07:58.86,0:08:18.97,EN,,0,0,0,,there are techniques for controlling the complexity of these large systems. Dialogue: 0,0:08:20.30,0:08:22.69,EN,,0,0,0,,And these techniques that are controlling complexity Dialogue: 0,0:08:22.72,0:08:24.17,EN,,0,0,0,,are what this course is really about. Dialogue: 0,0:08:24.65,0:08:25.47,EN,,0,0,0,,And in some sense, Dialogue: 0,0:08:25.50,0:08:27.47,EN,,0,0,0,,that's really what computer science is about. Dialogue: 0,0:08:29.63,0:08:31.89,EN,,0,0,0,,Now, that may seem like a very strange thing to say. Dialogue: 0,0:08:31.92,0:08:35.61,EN,,0,0,0,,Because after all, a lot of people besides computer scientists Dialogue: 0,0:08:35.65,0:08:37.82,EN,,0,0,0,,deal with controlling complexity. Dialogue: 0,0:08:37.84,0:08:41.02,EN,,0,0,0,,A large airliner is an extremely complex system, Dialogue: 0,0:08:41.82,0:08:43.79,EN,,0,0,0,,and the aeronautical engineers who design that Dialogue: 0,0:08:44.05,0:08:46.13,EN,,0,0,0,,are dealing with immense complexity. Dialogue: 0,0:08:47.09,0:08:50.19,EN,,0,0,0,,But there's a difference between that kind of complexity Dialogue: 0,0:08:50.75,0:08:52.60,EN,,0,0,0,,and what we deal with in computer science. Dialogue: 0,0:08:55.18,0:08:57.73,EN,,0,0,0,,And that is that computer science, Dialogue: 0,0:08:57.79,0:09:00.09,EN,,0,0,0,,in some sense, isn't real. Dialogue: 0,0:09:02.69,0:09:06.62,EN,,0,0,0,,You see, when an engineer is designing a physical system, Dialogue: 0,0:09:07.14,0:09:08.49,EN,,0,0,0,,that's made out of real parts. Dialogue: 0,0:09:09.40,0:09:11.18,EN,,0,0,0,,The engineers who worry about that Dialogue: 0,0:09:11.85,0:09:16.65,EN,,0,0,0,,have to address problems of tolerance and approximation and noise in the system. Dialogue: 0,0:09:16.67,0:09:19.02,EN,,0,0,0,,So for example, as an electrical engineer, Dialogue: 0,0:09:19.09,0:09:21.71,EN,,0,0,0,,I can go off and easily build a one-stage amplifier Dialogue: 0,0:09:21.73,0:09:23.03,EN,,0,0,0,,or a two-stage amplifier, Dialogue: 0,0:09:23.41,0:09:25.39,EN,,0,0,0,,and I can imagine cascading a lot of them Dialogue: 0,0:09:25.45,0:09:26.91,EN,,0,0,0,,to build a million-stage amplifier. Dialogue: 0,0:09:26.99,0:09:28.75,EN,,0,0,0,,But it's ridiculous to build such a thing, Dialogue: 0,0:09:28.98,0:09:32.15,EN,,0,0,0,,because long before the millionth stage, Dialogue: 0,0:09:32.16,0:09:34.56,EN,,0,0,0,,the thermal noise in those components way at the beginning Dialogue: 0,0:09:34.57,0:09:36.80,EN,,0,0,0,,is going to get amplified and make the whole thing meaningless. Dialogue: 0,0:09:39.10,0:09:43.12,EN,,0,0,0,,Computer science deals with idealized components. Dialogue: 0,0:09:44.12,0:09:47.63,EN,,0,0,0,,We know as much as we want about these little program Dialogue: 0,0:09:47.65,0:09:49.56,EN,,0,0,0,,and data pieces that we're fitting things together. Dialogue: 0,0:09:51.90,0:09:53.20,EN,,0,0,0,,We don't have to worry about tolerance. Dialogue: 0,0:09:53.21,0:09:56.99,EN,,0,0,0,,And that means that, in building a large program, Dialogue: 0,0:09:58.13,0:10:00.03,EN,,0,0,0,,there's not all that much difference Dialogue: 0,0:10:00.35,0:10:04.18,EN,,0,0,0,,between what I can build and what I can imagine, Dialogue: 0,0:10:05.53,0:10:07.60,EN,,0,0,0,,because the parts are these abstract entities Dialogue: 0,0:10:07.63,0:10:10.32,EN,,0,0,0,,that I know as much as I want. Dialogue: 0,0:10:10.33,0:10:12.39,EN,,0,0,0,,I know about them as precisely as I'd like. Dialogue: 0,0:10:13.45,0:10:15.50,EN,,0,0,0,,So as opposed to other kinds of engineering, Dialogue: 0,0:10:15.66,0:10:17.42,EN,,0,0,0,,where the constraints on what you can build Dialogue: 0,0:10:17.44,0:10:18.90,EN,,0,0,0,,are the constraints of physical systems, Dialogue: 0,0:10:18.94,0:10:21.02,EN,,0,0,0,,the constraints of physics and noise and approximation, Dialogue: 0,0:10:21.21,0:10:25.60,EN,,0,0,0,,the constraints imposed in building large software systems Dialogue: 0,0:10:25.64,0:10:27.58,EN,,0,0,0,,are the limitations of our own minds. Dialogue: 0,0:10:29.12,0:10:29.98,EN,,0,0,0,,So in that sense, Dialogue: 0,0:10:30.00,0:10:33.67,EN,,0,0,0,,computer science is like an abstract form of engineering. Dialogue: 0,0:10:33.80,0:10:35.73,EN,,0,0,0,,It's the kind of engineering where you ignore Dialogue: 0,0:10:35.76,0:10:38.02,EN,,0,0,0,,the constraints that are imposed by reality. Dialogue: 0,0:10:41.97,0:10:46.15,EN,,0,0,0,,Well, what are some of these techniques? Dialogue: 0,0:10:46.28,0:10:48.39,EN,,0,0,0,,They're not special to computer science. Dialogue: 0,0:10:50.39,0:10:52.55,EN,,0,0,0,,First technique, which is used in all of engineering, Dialogue: 0,0:10:53.36,0:10:58.91,EN,,0,0,0,,is a kind of abstraction called black-box abstraction. Dialogue: 0,0:11:07.71,0:11:12.58,EN,,0,0,0,,Take something and build a box about it. Dialogue: 0,0:11:14.37,0:11:20.09,EN,,0,0,0,,Let's see, for example, if we looked at that square root method, Dialogue: 0,0:11:22.64,0:11:28.53,EN,,0,0,0,,I might want to take that and build a box. Dialogue: 0,0:11:29.89,0:11:37.52,EN,,0,0,0,,That sort of says, to find the square root of X. Dialogue: 0,0:11:38.86,0:11:41.27,EN,,0,0,0,,And that might be a whole complicated set of rules. Dialogue: 0,0:11:42.64,0:11:46.69,EN,,0,0,0,,And that might end up being a kind of thing where I can put in, Dialogue: 0,0:11:46.81,0:11:50.06,EN,,0,0,0,,say, 36 and say, what's the square root of 36? Dialogue: 0,0:11:50.25,0:11:51.46,EN,,0,0,0,,And out comes 6. Dialogue: 0,0:11:53.89,0:11:56.22,EN,,0,0,0,,And the important thing is that Dialogue: 0,0:11:56.24,0:12:00.03,EN,,0,0,0,,I'd like to design that so that Dialogue: 0,0:12:00.06,0:12:04.08,EN,,0,0,0,,if George comes along and would like to compute, Dialogue: 0,0:12:05.10,0:12:09.37,EN,,0,0,0,,say, the square root of A plus the square root of B, Dialogue: 0,0:12:11.34,0:12:14.38,EN,,0,0,0,,he can take this thing and use it as a module Dialogue: 0,0:12:14.43,0:12:15.74,EN,,0,0,0,,without having to look inside Dialogue: 0,0:12:15.77,0:12:17.31,EN,,0,0,0,,and build something that looks like this, Dialogue: 0,0:12:18.45,0:12:24.20,EN,,0,0,0,,like an A and a B and a square root box and another square root box Dialogue: 0,0:12:24.53,0:12:33.87,EN,,0,0,0,,and then something that adds that would put out the answer. Dialogue: 0,0:12:33.96,0:12:38.15,EN,,0,0,0,,And you can see, just from the fact that I want to do that, Dialogue: 0,0:12:38.92,0:12:40.42,EN,,0,0,0,,is from George's point of view, Dialogue: 0,0:12:40.51,0:12:43.10,EN,,0,0,0,,the internals of what's in here should not be important. Dialogue: 0,0:12:44.19,0:12:47.25,EN,,0,0,0,,So for instance, it shouldn't matter that, when I wrote this, Dialogue: 0,0:12:47.27,0:12:50.43,EN,,0,0,0,,I said I want to find the square root of X. Dialogue: 0,0:12:50.61,0:12:52.27,EN,,0,0,0,,I could have said the square root of Y, Dialogue: 0,0:12:52.72,0:12:55.62,EN,,0,0,0,,or the square root of A, or anything at all Dialogue: 0,0:12:56.70,0:13:02.35,EN,,0,0,0,,That's the fundamental notion of putting something in a box Dialogue: 0,0:13:03.53,0:13:06.44,EN,,0,0,0,,using black-box abstraction to suppress detail. Dialogue: 0,0:13:07.60,0:13:10.99,EN,,0,0,0,,And the reason for that is you want to go off and build bigger boxes. Dialogue: 0,0:13:12.05,0:13:14.57,EN,,0,0,0,,Now, there's another reason for doing black-box abstraction Dialogue: 0,0:13:14.59,0:13:18.41,EN,,0,0,0,,other than you want to suppress detail for building bigger boxes. Dialogue: 0,0:13:18.48,0:13:25.02,EN,,0,0,0,,Sometimes you want to say that your way of doing something, Dialogue: 0,0:13:25.04,0:13:26.88,EN,,0,0,0,,your how-to method, Dialogue: 0,0:13:28.44,0:13:30.79,EN,,0,0,0,,is an instance of a more general thing, Dialogue: 0,0:13:31.16,0:13:34.57,EN,,0,0,0,,and you'd like your language to be able to express that generality. Dialogue: 0,0:13:35.57,0:13:37.93,EN,,0,0,0,,Let me show you another example Dialogue: 0,0:13:37.97,0:13:38.86,EN,,0,0,0,,sticking with square roots. Dialogue: 0,0:13:38.89,0:13:42.16,EN,,0,0,0,,Let's go back and take another look at that slide Dialogue: 0,0:13:42.19,0:13:43.75,EN,,0,0,0,,with the square root algorithm on it. Dialogue: 0,0:13:44.16,0:13:45.62,EN,,0,0,0,,Remember what that says. Dialogue: 0,0:13:45.79,0:13:49.82,EN,,0,0,0,,That says, in order to do something, I make a guess, Dialogue: 0,0:13:50.62,0:13:54.84,EN,,0,0,0,,and I improve that guess, and I sort of keep improving that guess. Dialogue: 0,0:13:55.66,0:14:00.14,EN,,0,0,0,,So there's the general strategy of, I'm looking for something, Dialogue: 0,0:14:01.15,0:14:04.00,EN,,0,0,0,,and the way I find it is that I keep improving it. Dialogue: 0,0:14:04.16,0:14:10.25,EN,,0,0,0,,Now, that's a particular case of another kind of strategy Dialogue: 0,0:14:10.97,0:14:13.23,EN,,0,0,0,,for finding a fixed point of something. Dialogue: 0,0:14:14.57,0:14:16.59,EN,,0,0,0,,So you have a fixed point of a function. Dialogue: 0,0:14:17.13,0:14:26.03,EN,,0,0,0,,A fixed point of a function is something, is a value. Dialogue: 0,0:14:26.13,0:14:31.79,EN,,0,0,0,,A fixed point of a function F is a value Y, such that F of Y equals Y. Dialogue: 0,0:14:32.97,0:14:40.89,EN,,0,0,0,,And the way I might do that is start with a guess. Dialogue: 0,0:14:42.00,0:14:45.85,EN,,0,0,0,,And then if I want something that doesn't change when I keep applying F, Dialogue: 0,0:14:45.96,0:14:49.45,EN,,0,0,0,,is I'll keep applying F over and over until that result doesn't change very much. Dialogue: 0,0:14:50.05,0:14:51.93,EN,,0,0,0,,So there's a general strategy. Dialogue: 0,0:14:52.24,0:14:56.17,EN,,0,0,0,,And then, for example, to compute the square root of X, Dialogue: 0,0:14:56.24,0:15:03.45,EN,,0,0,0,,I can try and find a fixed point of the function which takes Y to the average of X/Y. Dialogue: 0,0:15:03.55,0:15:07.52,EN,,0,0,0,,And the idea that is that if I really had Y equal to the square root of X, Dialogue: 0,0:15:08.01,0:15:11.80,EN,,0,0,0,,then Y and X/Y would be the same value. Dialogue: 0,0:15:12.00,0:15:13.90,EN,,0,0,0,,They'd both be the square root of X, Dialogue: 0,0:15:14.86,0:15:18.85,EN,,0,0,0,,because X over the square root of X is the square root of X. Dialogue: 0,0:15:19.09,0:15:21.84,EN,,0,0,0,,And so the average if Y were equal to the square of X, Dialogue: 0,0:15:22.25,0:15:25.21,EN,,0,0,0,,then the average wouldn't change. Dialogue: 0,0:15:25.98,0:15:28.93,EN,,0,0,0,,So the square root of X is a fixed point of that particular function. Dialogue: 0,0:15:30.09,0:15:33.85,EN,,0,0,0,,Now, what I'd like to have, I'd like to express Dialogue: 0,0:15:33.98,0:15:36.42,EN,,0,0,0,,the general strategy for finding fixed points. Dialogue: 0,0:15:36.57,0:15:40.13,EN,,0,0,0,,So what I might imagine doing, is to find, Dialogue: 0,0:15:41.02,0:15:46.45,EN,,0,0,0,,is to be able to use my language to define a box that says "fixed point," Dialogue: 0,0:15:49.58,0:15:52.19,EN,,0,0,0,,just like I could make a box that says "square root." Dialogue: 0,0:15:52.21,0:15:55.18,EN,,0,0,0,,And I'd like to be able to express this in my language. Dialogue: 0,0:15:56.08,0:16:01.37,EN,,0,0,0,,So I'd like to express not only the imperative how-to knowledge Dialogue: 0,0:16:01.42,0:16:03.21,EN,,0,0,0,,of a particular thing like square root, Dialogue: 0,0:16:03.58,0:16:05.60,EN,,0,0,0,,but I'd like to be able to express the imperative knowledge Dialogue: 0,0:16:05.66,0:16:08.27,EN,,0,0,0,,of how to do a general thing like how to find fixed point. Dialogue: 0,0:16:09.82,0:16:12.25,EN,,0,0,0,,And in fact, let's go back and look at that slide again. Dialogue: 0,0:16:15.02,0:16:23.28,EN,,0,0,0,,See, not only is this a piece of imperative knowledge, Dialogue: 0,0:16:23.33,0:16:25.32,EN,,0,0,0,,how to find a fixed point, Dialogue: 0,0:16:26.25,0:16:27.39,EN,,0,0,0,,but over here on the bottom, Dialogue: 0,0:16:27.42,0:16:30.32,EN,,0,0,0,,there's another piece of imperative knowledge which says, Dialogue: 0,0:16:30.41,0:16:35.85,EN,,0,0,0,,one way to compute square root is to apply this general fixed point method. Dialogue: 0,0:16:36.17,0:16:38.89,EN,,0,0,0,,So I'd like to also be able to express that imperative knowledge. Dialogue: 0,0:16:39.74,0:16:40.70,EN,,0,0,0,,What would that look like? Dialogue: 0,0:16:40.73,0:16:44.90,EN,,0,0,0,,That would say, this fixed point box is such that Dialogue: 0,0:16:45.76,0:16:58.21,EN,,0,0,0,,if I input to it the function that takes Y to the average of Y and X/Y, Dialogue: 0,0:16:59.77,0:17:06.23,EN,,0,0,0,,then what should come out of that fixed point box is a method for finding square roots. Dialogue: 0,0:17:08.91,0:17:10.24,EN,,0,0,0,,So in these boxes we're building, Dialogue: 0,0:17:10.27,0:17:15.07,EN,,0,0,0,,we're not only building boxes that you input numbers and output numbers, Dialogue: 0,0:17:16.40,0:17:18.54,EN,,0,0,0,,we're going to be building in boxes that, Dialogue: 0,0:17:18.67,0:17:21.34,EN,,0,0,0,,in effect, compute methods like finding square root. Dialogue: 0,0:17:22.22,0:17:25.85,EN,,0,0,0,,And my take is their inputs functions, Dialogue: 0,0:17:26.49,0:17:29.29,EN,,0,0,0,,like Y goes to the average of Y and X/Y. Dialogue: 0,0:17:29.71,0:17:31.49,EN,,0,0,0,,The reason we want to do that, Dialogue: 0,0:17:32.21,0:17:35.60,EN,,0,0,0,,the reason this is a procedure, will end up being a procedure, Dialogue: 0,0:17:35.63,0:17:38.61,EN,,0,0,0,,as we'll see, whose value is another procedure, Dialogue: 0,0:17:39.31,0:17:41.10,EN,,0,0,0,,the reason we want to do that is because Dialogue: 0,0:17:41.52,0:17:46.27,EN,,0,0,0,,procedures are going to be our ways of talking about imperative knowledge. Dialogue: 0,0:17:48.00,0:17:49.93,EN,,0,0,0,,And the way to make that very powerful is Dialogue: 0,0:17:49.93,0:17:52.13,EN,,0,0,0,,to be able to talk about other kinds of knowledge. Dialogue: 0,0:17:53.42,0:17:56.52,EN,,0,0,0,,So here is a procedure that, in effect, talks about another procedure, Dialogue: 0,0:17:57.10,0:18:00.34,EN,,0,0,0,,a general strategy that itself talks about general strategies. Dialogue: 0,0:18:03.57,0:18:08.24,EN,,0,0,0,,Well, our first topic in this course-- Dialogue: 0,0:18:08.25,0:18:09.69,EN,,0,0,0,,there'll be three major topics-- Dialogue: 0,0:18:09.74,0:18:10.94,EN,,0,0,0,,will be black-box abstraction. Dialogue: 0,0:18:10.97,0:18:13.31,EN,,0,0,0,,Let's look at that in a little bit more detail. Dialogue: 0,0:18:15.12,0:18:24.04,EN,,0,0,0,,What we're going to do is we will start out talking about Dialogue: 0,0:18:24.08,0:18:26.72,EN,,0,0,0,,how Lisp is built up out of primitive objects. Dialogue: 0,0:18:27.36,0:18:29.20,EN,,0,0,0,,What does the language supply with us? Dialogue: 0,0:18:29.49,0:18:33.58,EN,,0,0,0,,And we'll see that there are primitive procedures and primitive data. Dialogue: 0,0:18:36.16,0:18:37.04,EN,,0,0,0,,Then we're going to see, Dialogue: 0,0:18:37.05,0:18:38.77,EN,,0,0,0,,how do you take those primitives and Dialogue: 0,0:18:38.81,0:18:40.76,EN,,0,0,0,,combine them to make more complicated things, Dialogue: 0,0:18:41.45,0:18:42.92,EN,,0,0,0,,means of combination? Dialogue: 0,0:18:43.20,0:18:46.30,EN,,0,0,0,,And what we'll see is that there are ways of putting things together, Dialogue: 0,0:18:46.45,0:18:50.48,EN,,0,0,0,,putting primitive procedures together to make more complicated procedures. Dialogue: 0,0:18:50.96,0:18:54.43,EN,,0,0,0,,And we'll see how to put primitive data together to make compound data. Dialogue: 0,0:18:56.21,0:18:59.34,EN,,0,0,0,,Then we'll say, well, having made those compounds things, Dialogue: 0,0:18:59.79,0:19:01.29,EN,,0,0,0,,how do you abstract them? Dialogue: 0,0:19:02.91,0:19:04.97,EN,,0,0,0,,How do you put those black boxes around them Dialogue: 0,0:19:05.04,0:19:07.73,EN,,0,0,0,,so you can use them as components in more complex things? Dialogue: 0,0:19:08.16,0:19:10.93,EN,,0,0,0,,And we'll see that's done by defining procedures and Dialogue: 0,0:19:11.52,0:19:14.79,EN,,0,0,0,,a technique for dealing with compound data called data abstraction. Dialogue: 0,0:19:15.61,0:19:17.36,EN,,0,0,0,,And then, what's maybe the most important thing, Dialogue: 0,0:19:17.92,0:19:21.49,EN,,0,0,0,,is going from just the rules to how does an expert work? Dialogue: 0,0:19:21.61,0:19:27.12,EN,,0,0,0,,How do you express common patterns of doing things, like saying, well, Dialogue: 0,0:19:27.15,0:19:28.64,EN,,0,0,0,,there's a general method of fixed point and Dialogue: 0,0:19:28.69,0:19:30.87,EN,,0,0,0,,square root is a particular case of that? Dialogue: 0,0:19:31.90,0:19:34.41,EN,,0,0,0,,And we're going to use-- Dialogue: 0,0:19:34.59,0:19:35.63,EN,,0,0,0,,I've already hinted at it-- Dialogue: 0,0:19:35.66,0:19:37.30,EN,,0,0,0,,something called higher-order procedures, Dialogue: 0,0:19:37.34,0:19:42.05,EN,,0,0,0,,namely procedures whose inputs and outputs are themselves procedures. Dialogue: 0,0:19:42.96,0:19:44.86,EN,,0,0,0,,And then we'll also see something very interesting. Dialogue: 0,0:19:44.86,0:19:48.49,EN,,0,0,0,,We'll see, as we go further and further on and become more abstract, Dialogue: 0,0:19:48.80,0:19:50.31,EN,,0,0,0,,there'll be very-- Dialogue: 0,0:19:50.43,0:19:53.61,EN,,0,0,0,,well, the line between what we consider to be data and Dialogue: 0,0:19:53.63,0:19:57.80,EN,,0,0,0,,what we consider to be procedures is going to blur at an incredible rate. Dialogue: 0,0:20:02.89,0:20:07.12,EN,,0,0,0,,Well, that's our first subject, black-box abstraction. Dialogue: 0,0:20:07.12,0:20:08.62,EN,,0,0,0,,Let's look at the second topic. Dialogue: 0,0:20:11.10,0:20:13.88,EN,,0,0,0,,I can introduce it like this. Dialogue: 0,0:20:13.89,0:20:18.09,EN,,0,0,0,,See, suppose I want to express the idea-- Dialogue: 0,0:20:19.42,0:20:22.51,EN,,0,0,0,,remember, we're talking about ideas-- Dialogue: 0,0:20:22.91,0:20:25.53,EN,,0,0,0,,suppose I want to express the idea that Dialogue: 0,0:20:26.41,0:20:35.12,EN,,0,0,0,,I can take something and multiply it by the sum of two other things. Dialogue: 0,0:20:36.09,0:20:37.93,EN,,0,0,0,,So for example, I might say, Dialogue: 0,0:20:38.11,0:20:41.52,EN,,0,0,0,,if I had 1 and 3 and multiply that by 2, I get 8. Dialogue: 0,0:20:42.03,0:20:45.11,EN,,0,0,0,,But I'm talking about the general idea of what's called linear combination, Dialogue: 0,0:20:45.44,0:20:47.98,EN,,0,0,0,,that you can add two things and multiply them by something else. Dialogue: 0,0:20:49.28,0:20:51.01,EN,,0,0,0,,It's very easy when I think about it for numbers, Dialogue: 0,0:20:51.05,0:20:55.41,EN,,0,0,0,,but suppose I also want to use that same idea to think about, Dialogue: 0,0:20:56.08,0:20:58.58,EN,,0,0,0,,I could add two vectors, a1 and a2, Dialogue: 0,0:20:59.89,0:21:03.26,EN,,0,0,0,,and then scale them by some factor x and get another vector. Dialogue: 0,0:21:03.33,0:21:09.75,EN,,0,0,0,,Or I might say, I want to think about a1 and a2 as being polynomials, Dialogue: 0,0:21:11.07,0:21:13.90,EN,,0,0,0,,and I might want to add those two polynomials and Dialogue: 0,0:21:13.92,0:21:16.86,EN,,0,0,0,,then multiply them by 2 to get a more complicated one. Dialogue: 0,0:21:20.16,0:21:23.83,EN,,0,0,0,,Or a1 and a2 might be electrical signals, Dialogue: 0,0:21:24.56,0:21:27.77,EN,,0,0,0,,and I might want to think about summing those two electrical signals and Dialogue: 0,0:21:27.81,0:21:30.27,EN,,0,0,0,,then putting the whole thing through an amplifier, Dialogue: 0,0:21:30.28,0:21:33.03,EN,,0,0,0,,multiplying it by some factor of 2 or something. Dialogue: 0,0:21:33.82,0:21:36.93,EN,,0,0,0,,The idea is I want to think about the general notion of that. Dialogue: 0,0:21:38.32,0:21:45.42,EN,,0,0,0,,Now, if our language is going to be good language for expressing those kind of general ideas, Dialogue: 0,0:21:47.07,0:21:49.31,EN,,0,0,0,,if I really, really can do that, Dialogue: 0,0:21:50.65,0:21:52.09,EN,,0,0,0,,I'd like to be able to say Dialogue: 0,0:21:54.99,0:22:00.41,EN,,0,0,0,,I'm going to multiply by x the sum of a1 and a2, Dialogue: 0,0:22:02.80,0:22:05.07,EN,,0,0,0,,and I'd like that to express the general idea of Dialogue: 0,0:22:06.03,0:22:09.23,EN,,0,0,0,,all different kinds of things that a1 and a2 could be. Dialogue: 0,0:22:10.03,0:22:11.58,EN,,0,0,0,,Now, if you think about that, there's a problem, Dialogue: 0,0:22:11.58,0:22:16.17,EN,,0,0,0,,because after all, the actual primitive operations Dialogue: 0,0:22:16.21,0:22:18.33,EN,,0,0,0,,that go on in the machine are obviously going to be different Dialogue: 0,0:22:18.38,0:22:22.98,EN,,0,0,0,,if I'm adding two numbers than if I'm adding two polynomials, Dialogue: 0,0:22:23.29,0:22:27.49,EN,,0,0,0,,or if I'm adding the representation of two electrical signals or wave forms. Dialogue: 0,0:22:27.89,0:22:32.53,EN,,0,0,0,,Somewhere, there has to be the knowledge of the kinds of various things Dialogue: 0,0:22:32.87,0:22:34.25,EN,,0,0,0,,that you can add and the ways of adding them. Dialogue: 0,0:22:37.09,0:22:38.64,EN,,0,0,0,,Now, to construct such a system, Dialogue: 0,0:22:38.78,0:22:40.67,EN,,0,0,0,,the question is, where do I put that knowledge? Dialogue: 0,0:22:41.20,0:22:44.41,EN,,0,0,0,,How do I think about the different kinds of choices I have? Dialogue: 0,0:22:44.56,0:22:48.42,EN,,0,0,0,,And if tomorrow George comes up with a new kind of object Dialogue: 0,0:22:48.45,0:22:50.32,EN,,0,0,0,,that might be added and multiplied, Dialogue: 0,0:22:51.01,0:22:53.32,EN,,0,0,0,,how do I add George's new object to the system Dialogue: 0,0:22:53.52,0:22:55.68,EN,,0,0,0,,without screwing up everything that was already there? Dialogue: 0,0:22:57.81,0:23:00.54,EN,,0,0,0,,Well, that's going to be the second big topic, Dialogue: 0,0:23:00.57,0:23:03.16,EN,,0,0,0,,the way of controlling that kind of complexity. Dialogue: 0,0:23:03.84,0:23:08.43,EN,,0,0,0,,And the way you do that is by establishing conventional interfaces, Dialogue: 0,0:23:17.44,0:23:20.21,EN,,0,0,0,,agreed upon ways of plugging things together. Dialogue: 0,0:23:20.25,0:23:22.04,EN,,0,0,0,,Just like in electrical engineering, Dialogue: 0,0:23:22.94,0:23:25.39,EN,,0,0,0,,people have standard impedances for connectors, Dialogue: 0,0:23:26.16,0:23:28.62,EN,,0,0,0,,and then you know if you build something with one of those standard impedances, Dialogue: 0,0:23:28.67,0:23:30.40,EN,,0,0,0,,you can plug it together with something else. Dialogue: 0,0:23:32.78,0:23:35.68,EN,,0,0,0,,So that's going to be our second large topic, conventional interfaces. Dialogue: 0,0:23:35.73,0:23:40.94,EN,,0,0,0,,What we're going to see is, first, we're going to talk about the problem of generic operations, Dialogue: 0,0:23:40.97,0:23:42.22,EN,,0,0,0,,which is the one I alluded to, Dialogue: 0,0:23:42.59,0:23:47.28,EN,,0,0,0,,things like "plus" that have to work with all different kinds of data. Dialogue: 0,0:23:52.61,0:23:54.57,EN,,0,0,0,,So we talk about generic operations. Dialogue: 0,0:23:54.61,0:23:56.99,EN,,0,0,0,,Then we're going to talk about really large-scale structures. Dialogue: 0,0:23:58.32,0:24:00.83,EN,,0,0,0,,How do you put together very large programs Dialogue: 0,0:24:01.02,0:24:04.89,EN,,0,0,0,,that model the kinds of complex systems in the real world that you'd like to model? Dialogue: 0,0:24:05.53,0:24:06.53,EN,,0,0,0,,And what we're going to see is that Dialogue: 0,0:24:06.57,0:24:11.81,EN,,0,0,0,,there are two very important metaphors for putting together such systems. Dialogue: 0,0:24:11.85,0:24:13.90,EN,,0,0,0,,One is called object-oriented programming, Dialogue: 0,0:24:14.09,0:24:18.94,EN,,0,0,0,,where you sort of think of your system as a kind of society Dialogue: 0,0:24:19.37,0:24:22.36,EN,,0,0,0,,full of little things that interact by sending information between them. Dialogue: 0,0:24:23.44,0:24:27.81,EN,,0,0,0,,And then the second one is operations on aggregates, called streams, Dialogue: 0,0:24:27.98,0:24:31.50,EN,,0,0,0,,where you think of a large system put together kind of Dialogue: 0,0:24:31.50,0:24:35.29,EN,,0,0,0,,like a signal processing engineer puts together a large electrical system. Dialogue: 0,0:24:38.93,0:24:40.49,EN,,0,0,0,,That's going to be our second topic. Dialogue: 0,0:24:43.37,0:24:45.93,EN,,0,0,0,,Now, the third thing we're going to come to, Dialogue: 0,0:24:45.95,0:24:49.70,EN,,0,0,0,,the third basic technique for controlling complexity, Dialogue: 0,0:24:49.74,0:24:50.94,EN,,0,0,0,,is making new languages. Dialogue: 0,0:24:51.69,0:24:55.42,EN,,0,0,0,,Because sometimes, when you're sort of overwhelmed by the complexity of a design, Dialogue: 0,0:24:55.47,0:24:59.69,EN,,0,0,0,,the way that you control that complexity is to pick a new design language. Dialogue: 0,0:25:01.41,0:25:05.60,EN,,0,0,0,,And the purpose of the new design language will be to highlight different aspects of the system. Dialogue: 0,0:25:05.79,0:25:09.36,EN,,0,0,0,,It will suppress some kinds of details and emphasize other kinds of details. Dialogue: 0,0:25:12.99,0:25:15.93,EN,,0,0,0,,This is going to be the most magical part of the course. Dialogue: 0,0:25:16.03,0:25:21.20,EN,,0,0,0,,We're going to start out by actually looking at the technology for building new computer languages. Dialogue: 0,0:25:21.82,0:25:26.30,EN,,0,0,0,,The first thing we're going to do is actually build in Lisp. Dialogue: 0,0:25:29.23,0:25:34.02,EN,,0,0,0,,We're going to express in Lisp the process of interpreting Lisp itself. Dialogue: 0,0:25:34.29,0:25:36.94,EN,,0,0,0,,And that's going to be a very sort of self-circular thing. Dialogue: 0,0:25:36.96,0:25:39.92,EN,,0,0,0,,There's a little mystical symbol that has to do with that. Dialogue: 0,0:25:40.97,0:25:46.38,EN,,0,0,0,,The process of interpreting Lisp is sort of a giant wheel of two processes, Dialogue: 0,0:25:46.57,0:25:47.71,EN,,0,0,0,,apply and eval, Dialogue: 0,0:25:47.89,0:25:50.87,EN,,0,0,0,,which sort of constantly reduce expressions to each other. Dialogue: 0,0:25:52.54,0:25:54.24,EN,,0,0,0,,Then we're going to see all sorts of other magical things. Dialogue: 0,0:25:54.25,0:25:56.85,EN,,0,0,0,,Here's another magical symbol. Dialogue: 0,0:25:57.12,0:26:01.52,EN,,0,0,0,,This is sort of the Y operator, Dialogue: 0,0:26:01.55,0:26:06.45,EN,,0,0,0,,which is, in some sense, the expression of infinity inside our procedural language. Dialogue: 0,0:26:06.51,0:26:07.44,EN,,0,0,0,,We'll take a look at that. Dialogue: 0,0:26:08.40,0:26:13.73,EN,,0,0,0,,In any case, this section of the course is called Metalinguistic Abstraction, Dialogue: 0,0:26:16.17,0:26:26.23,EN,,0,0,0,,abstracting by talking about how you construct new languages. Dialogue: 0,0:26:30.22,0:26:35.71,EN,,0,0,0,,As I said, we're going to start out by looking at the process of interpretation. Dialogue: 0,0:26:35.74,0:26:42.12,EN,,0,0,0,,We're going to look at this apply-eval loop, and build Lisp. Dialogue: 0,0:26:42.16,0:26:44.17,EN,,0,0,0,,Then, just to show you that this is very general, Dialogue: 0,0:26:44.37,0:26:48.26,EN,,0,0,0,,we're going to use exactly the same technology to build a very different kind of language, Dialogue: 0,0:26:48.53,0:26:50.31,EN,,0,0,0,,a so-called logic programming language, Dialogue: 0,0:26:50.53,0:26:54.83,EN,,0,0,0,,where you don't really talk about procedures at all that have inputs and outputs. Dialogue: 0,0:26:54.86,0:26:57.25,EN,,0,0,0,,What you do is talk about relations between things. Dialogue: 0,0:26:57.31,0:27:03.92,EN,,0,0,0,,And then finally, we're going to talk about how you implement these things very concretely Dialogue: 0,0:27:03.95,0:27:05.60,EN,,0,0,0,,on the very simplest kind of machines. Dialogue: 0,0:27:05.65,0:27:08.39,EN,,0,0,0,,We'll see something like this. Dialogue: 0,0:27:09.13,0:27:12.14,EN,,0,0,0,,This is a picture of a chip, Dialogue: 0,0:27:12.16,0:27:17.47,EN,,0,0,0,,which is the Lisp interpreter that we will be talking about then in hardware. Dialogue: 0,0:27:20.88,0:27:23.79,EN,,0,0,0,,Well, there's an outline of the course, three big topics. Dialogue: 0,0:27:24.88,0:27:29.41,EN,,0,0,0,,Black-box abstraction, conventional interfaces, metalinguistic abstraction. Dialogue: 0,0:27:31.58,0:27:33.57,EN,,0,0,0,,Now, let's take a break now and then we'll get started. Dialogue: 0,0:27:52.19,0:28:03.42,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:28:03.92,0:28:06.84,EN,,0,0,0,,Let's actually start in learning Lisp now. Dialogue: 0,0:28:08.06,0:28:10.75,EN,,0,0,0,,Actually, we'll start out by learning something much more important, Dialogue: 0,0:28:10.80,0:28:14.33,EN,,0,0,0,,maybe the very most important thing in this course, which is not Lisp, Dialogue: 0,0:28:14.38,0:28:18.41,EN,,0,0,0,,in particular, of course, but rather a general framework Dialogue: 0,0:28:18.62,0:28:21.89,EN,,0,0,0,,for thinking about languages that I already alluded to. Dialogue: 0,0:28:22.12,0:28:25.10,EN,,0,0,0,,When somebody tells you they're going to show you a language, Dialogue: 0,0:28:25.13,0:28:26.16,EN,,0,0,0,,what you should say is, Dialogue: 0,0:28:26.19,0:28:32.87,EN,,0,0,0,,what I'd like you to tell me is what are the primitive elements? Dialogue: 0,0:28:37.50,0:28:38.78,EN,,0,0,0,,What does the language come with? Dialogue: 0,0:28:38.96,0:28:43.53,EN,,0,0,0,,Then, what are the ways you put those together? Dialogue: 0,0:28:43.68,0:28:47.42,EN,,0,0,0,,What are the means of combination? Dialogue: 0,0:28:50.17,0:28:54.18,EN,,0,0,0,,What are the things that allow you to take these primitive elements Dialogue: 0,0:28:54.37,0:28:56.51,EN,,0,0,0,,and build bigger things out of them? Dialogue: 0,0:28:58.01,0:28:59.61,EN,,0,0,0,,What are the ways of putting things together? Dialogue: 0,0:29:01.39,0:29:05.69,EN,,0,0,0,,And then, what are the means of abstraction? Dialogue: 0,0:29:08.35,0:29:16.85,EN,,0,0,0,,How do we take those complicated things and draw those boxes around them? Dialogue: 0,0:29:16.88,0:29:19.66,EN,,0,0,0,,How do we name them so that we can now use them Dialogue: 0,0:29:19.68,0:29:23.85,EN,,0,0,0,,as if they were primitive elements in making still more complex things? Dialogue: 0,0:29:23.89,0:29:25.66,EN,,0,0,0,,And so on, and so on, and so on. Dialogue: 0,0:29:26.89,0:29:28.08,EN,,0,0,0,,So when someone says to you, gee, Dialogue: 0,0:29:28.09,0:29:29.55,EN,,0,0,0,,I have a great new computer language, Dialogue: 0,0:29:30.86,0:29:34.70,EN,,0,0,0,,you don't say, how many characters does it take to invert a matrix? Dialogue: 0,0:29:35.73,0:29:36.88,EN,,0,0,0,,It's irrelevant. Dialogue: 0,0:29:37.39,0:29:42.30,EN,,0,0,0,,What you say is, if the language did not come with matrices built in Dialogue: 0,0:29:42.33,0:29:43.37,EN,,0,0,0,,or with something else built in, Dialogue: 0,0:29:43.37,0:29:46.03,EN,,0,0,0,,how could I then build that thing? Dialogue: 0,0:29:46.05,0:29:48.47,EN,,0,0,0,,What are the means of combination which would allow me to do that? Dialogue: 0,0:29:48.62,0:29:50.71,EN,,0,0,0,,And then, what are the means of abstraction Dialogue: 0,0:29:51.68,0:29:54.21,EN,,0,0,0,,which allow me then to use those as elements Dialogue: 0,0:29:54.22,0:29:56.52,EN,,0,0,0,,in making more complicated things yet? Dialogue: 0,0:29:58.75,0:30:04.61,EN,,0,0,0,,Well, we're going to see that Lisp has some primitive data and some primitive procedures. Dialogue: 0,0:30:05.25,0:30:07.50,EN,,0,0,0,,In fact, let's really start. Dialogue: 0,0:30:07.55,0:30:14.89,EN,,0,0,0,,And here's a piece of primitive data in Lisp, number 3. Dialogue: 0,0:30:16.27,0:30:19.87,EN,,0,0,0,,Actually, if I'm being very pedantic, that's not the number 3. Dialogue: 0,0:30:19.93,0:30:25.57,EN,,0,0,0,,That's some symbol that represents Plato's concept of the number 3. Dialogue: 0,0:30:26.67,0:30:28.93,EN,,0,0,0,,And here's another. Dialogue: 0,0:30:30.48,0:30:36.06,EN,,0,0,0,,Here's some more primitive data in Lisp, 17.4. Dialogue: 0,0:30:36.08,0:30:39.42,EN,,0,0,0,,Or actually, some representation of 17.4. Dialogue: 0,0:30:40.99,0:30:44.48,EN,,0,0,0,,And here's another one, 5. Dialogue: 0,0:30:46.86,0:30:52.21,EN,,0,0,0,,Here's another primitive object that's built in Lisp, addition. Dialogue: 0,0:30:52.25,0:30:55.68,EN,,0,0,0,,Actually, to use the same kind of pedantic-- Dialogue: 0,0:30:55.71,0:31:00.47,EN,,0,0,0,,this is a name for the primitive method of adding things. Dialogue: 0,0:31:00.53,0:31:02.53,EN,,0,0,0,,Just like this is a name for Plato's number 3, Dialogue: 0,0:31:02.61,0:31:09.32,EN,,0,0,0,,this is a name for Plato's concept of how you add things. Dialogue: 0,0:31:10.32,0:31:11.98,EN,,0,0,0,,So those are some primitive elements. Dialogue: 0,0:31:12.14,0:31:13.76,EN,,0,0,0,,I can put them together. Dialogue: 0,0:31:14.14,0:31:18.29,EN,,0,0,0,,I can say, gee, what's the sum of 3 and 17.4 and 5? Dialogue: 0,0:31:18.69,0:31:21.31,EN,,0,0,0,,And the way I do that is to say, Dialogue: 0,0:31:21.33,0:31:27.71,EN,,0,0,0,,let's apply the sum operator to these three numbers. Dialogue: 0,0:31:27.74,0:31:31.15,EN,,0,0,0,,And I should get, what? 8, 17. 25.4. Dialogue: 0,0:31:34.43,0:31:38.05,EN,,0,0,0,,So I should be able to ask Lisp what the value of this is, Dialogue: 0,0:31:38.94,0:31:40.77,EN,,0,0,0,,and it will return 25.4. Dialogue: 0,0:31:43.58,0:31:44.83,EN,,0,0,0,,Let's introduce some names. Dialogue: 0,0:31:44.88,0:31:51.47,EN,,0,0,0,,This thing that I typed is called a combination. Dialogue: 0,0:31:56.88,0:32:01.94,EN,,0,0,0,,And a combination consists, in general, of applying an operator-- Dialogue: 0,0:32:03.39,0:32:04.72,EN,,0,0,0,,so this is an operator-- Dialogue: 0,0:32:09.71,0:32:12.05,EN,,0,0,0,,to some operands. Dialogue: 0,0:32:13.25,0:32:14.54,EN,,0,0,0,,These are the operands. Dialogue: 0,0:32:21.89,0:32:23.79,EN,,0,0,0,,And of course, I can make more complex things. Dialogue: 0,0:32:23.82,0:32:28.56,EN,,0,0,0,,The reason I can get complexity out of this is because the operands themselves, Dialogue: 0,0:32:29.52,0:32:31.09,EN,,0,0,0,,in general, can be combinations. Dialogue: 0,0:32:31.15,0:32:44.47,EN,,0,0,0,,So for instance, I could say, what is the sum of 3 and the product of 5 and 6 and 8 and 2? Dialogue: 0,0:32:45.66,0:32:52.16,EN,,0,0,0,,And I should get-- let's see-- 30, 40, 43. Dialogue: 0,0:32:52.73,0:32:54.81,EN,,0,0,0,,So Lisp should tell me that that's 43. Dialogue: 0,0:32:56.56,0:33:02.80,EN,,0,0,0,,Forming combinations is the basic needs of combination that we'll be looking at. Dialogue: 0,0:33:04.65,0:33:09.22,EN,,0,0,0,,And then, well, you see some syntax here. Dialogue: 0,0:33:10.56,0:33:13.04,EN,,0,0,0,,Lisp uses what's called prefix notation, Dialogue: 0,0:33:16.22,0:33:25.21,EN,,0,0,0,,which means that the operator is written to the left of the operands. Dialogue: 0,0:33:25.47,0:33:26.48,EN,,0,0,0,,It's just a convention. Dialogue: 0,0:33:27.66,0:33:29.77,EN,,0,0,0,,And notice, it's fully parenthesized. Dialogue: 0,0:33:30.08,0:33:32.32,EN,,0,0,0,,And the parentheses make it completely unambiguous. Dialogue: 0,0:33:32.32,0:33:36.99,EN,,0,0,0,,So by looking at this, I can see that there's the operator, Dialogue: 0,0:33:37.01,0:33:40.99,EN,,0,0,0,,and there are 1, 2, 3, 4 operands. Dialogue: 0,0:33:42.38,0:33:47.97,EN,,0,0,0,,And I can see that the second operand here is itself some combination Dialogue: 0,0:33:48.88,0:33:51.55,EN,,0,0,0,,that has one operator and two operands. Dialogue: 0,0:33:52.43,0:33:54.27,EN,,0,0,0,,Parentheses in Lisp are a little bit, Dialogue: 0,0:33:54.61,0:33:57.71,EN,,0,0,0,,or are very unlike parentheses in conventional mathematics. Dialogue: 0,0:33:57.77,0:34:00.11,EN,,0,0,0,,In mathematics, we sort of use them to mean grouping, Dialogue: 0,0:34:01.21,0:34:03.75,EN,,0,0,0,,and it sort of doesn't hurt if sometimes you leave out parentheses Dialogue: 0,0:34:03.77,0:34:05.56,EN,,0,0,0,,if people understand that that's a group. Dialogue: 0,0:34:05.76,0:34:08.51,EN,,0,0,0,,And in general, it doesn't hurt if you put in extra parentheses, Dialogue: 0,0:34:08.86,0:34:10.94,EN,,0,0,0,,because that maybe makes the grouping more distinct. Dialogue: 0,0:34:10.96,0:34:11.77,EN,,0,0,0,,Lisp is not like that. Dialogue: 0,0:34:13.12,0:34:15.37,EN,,0,0,0,,In Lisp, you cannot leave out parentheses, Dialogue: 0,0:34:16.38,0:34:18.56,EN,,0,0,0,,and you cannot put in extra parentheses, Dialogue: 0,0:34:19.33,0:34:21.28,EN,,0,0,0,,because putting in parentheses always means, Dialogue: 0,0:34:21.37,0:34:27.05,EN,,0,0,0,,exactly and precisely, this is a combination which has meaning, Dialogue: 0,0:34:27.09,0:34:28.81,EN,,0,0,0,,applying operators to operands. Dialogue: 0,0:34:29.04,0:34:32.62,EN,,0,0,0,,And if I left this out, if I left those parentheses out, Dialogue: 0,0:34:32.65,0:34:33.96,EN,,0,0,0,,it would mean something else. Dialogue: 0,0:34:35.41,0:34:37.25,EN,,0,0,0,,In fact, the way to think about this, Dialogue: 0,0:34:37.41,0:34:41.65,EN,,0,0,0,,is really what I'm doing when I write something like this is writing a tree. Dialogue: 0,0:34:42.37,0:34:47.30,EN,,0,0,0,,So this combination is a tree that has a plus and Dialogue: 0,0:34:47.37,0:34:54.46,EN,,0,0,0,,then a 3 and then a something else and an 8 and a 2. Dialogue: 0,0:34:54.48,0:34:56.35,EN,,0,0,0,,And then this something else here is Dialogue: 0,0:34:56.35,0:35:03.22,EN,,0,0,0,,itself a little subtree that has a star and a 5 and a 6. Dialogue: 0,0:35:03.95,0:35:05.53,EN,,0,0,0,,And the way to think of that is, really, Dialogue: 0,0:35:05.55,0:35:09.00,EN,,0,0,0,,what's going on are we're writing these trees, Dialogue: 0,0:35:09.21,0:35:15.10,EN,,0,0,0,,and parentheses are just a way to write this two-dimensional structure Dialogue: 0,0:35:15.79,0:35:17.34,EN,,0,0,0,,as a linear character string. Dialogue: 0,0:35:19.23,0:35:23.81,EN,,0,0,0,,Because at least when Lisp first started and people had teletypes or punch cards or whatever, Dialogue: 0,0:35:24.17,0:35:25.60,EN,,0,0,0,,this was more convenient. Dialogue: 0,0:35:25.97,0:35:30.52,EN,,0,0,0,,Maybe if Lisp started today, the syntax of Lisp would look like that. Dialogue: 0,0:35:31.76,0:35:35.07,EN,,0,0,0,,Well, let's look at what that actually looks like on the computer. Dialogue: 0,0:35:36.29,0:35:39.37,EN,,0,0,0,,Here I have a Lisp interaction set up. Dialogue: 0,0:35:39.41,0:35:40.43,EN,,0,0,0,,There's a editor. Dialogue: 0,0:35:41.13,0:35:44.86,EN,,0,0,0,,And on the top, I'm going to type some values and ask Lisp what they are. Dialogue: 0,0:35:45.12,0:35:46.75,EN,,0,0,0,,So for instance, I can say to Lisp, Dialogue: 0,0:35:46.83,0:35:48.53,EN,,0,0,0,,what's the value of that symbol? Dialogue: 0,0:35:49.44,0:35:50.50,EN,,0,0,0,,That's 3. Dialogue: 0,0:35:50.57,0:35:52.20,EN,,0,0,0,,And I ask Lisp to evaluate it. Dialogue: 0,0:35:52.32,0:35:54.77,EN,,0,0,0,,And there you see Lisp has returned on the bottom, Dialogue: 0,0:35:55.39,0:35:56.84,EN,,0,0,0,,and said, oh yeah, that's 3. Dialogue: 0,0:35:57.58,0:36:04.96,EN,,0,0,0,,Or I can say, what's the sum of 3 and 4 and 8? Dialogue: 0,0:36:06.45,0:36:08.05,EN,,0,0,0,,What's that combination? Dialogue: 0,0:36:08.93,0:36:10.66,EN,,0,0,0,,And ask Lisp to evaluate it. Dialogue: 0,0:36:14.49,0:36:15.68,EN,,0,0,0,,That's 15. Dialogue: 0,0:36:16.57,0:36:18.80,EN,,0,0,0,,Or I can type in something more complicated. Dialogue: 0,0:36:19.25,0:36:34.14,EN,,0,0,0,,I can say, what's the sum of the product of 3 and the sum of 7 and 19.5? Dialogue: 0,0:36:35.21,0:36:38.00,EN,,0,0,0,,And you'll notice here that Lisp has something built in Dialogue: 0,0:36:38.01,0:36:39.76,EN,,0,0,0,,that helps me keep track of all these parentheses. Dialogue: 0,0:36:39.77,0:36:42.13,EN,,0,0,0,,Watch as I type the next closed parentheses, Dialogue: 0,0:36:42.21,0:36:45.01,EN,,0,0,0,,which is going to close the combination starting with the star. Dialogue: 0,0:36:45.52,0:36:47.30,EN,,0,0,0,,The opening one will flash. Dialogue: 0,0:36:47.76,0:36:49.69,EN,,0,0,0,,Here, I'll rub those out and do it again. Dialogue: 0,0:36:50.14,0:36:52.70,EN,,0,0,0,,Type close, and you see that closes the plus. Dialogue: 0,0:36:53.58,0:36:56.41,EN,,0,0,0,,Close again, that closes the star. Dialogue: 0,0:36:57.90,0:37:00.76,EN,,0,0,0,,Now I'm back to the sum, and maybe I'm going to add that all to 4. Dialogue: 0,0:37:01.66,0:37:02.69,EN,,0,0,0,,That closes the plus. Dialogue: 0,0:37:02.73,0:37:07.07,EN,,0,0,0,,Now I have a complete combination, and I can ask Lisp for the value of that. Dialogue: 0,0:37:07.26,0:37:11.66,EN,,0,0,0,,That kind of paren balancing is something that's built into Dialogue: 0,0:37:11.76,0:37:13.29,EN,,0,0,0,,a lot of Lisp systems to help you keep track, Dialogue: 0,0:37:13.36,0:37:16.55,EN,,0,0,0,,because it is kind of hard just by hand doing all these parentheses. Dialogue: 0,0:37:16.81,0:37:21.20,EN,,0,0,0,,There's another kind of convention for keeping track of parentheses. Dialogue: 0,0:37:21.25,0:37:23.68,EN,,0,0,0,,Let me write another complicated combination. Dialogue: 0,0:37:24.77,0:37:34.00,EN,,0,0,0,,Let's take the sum of the product of 3 and 5 and add that to something. Dialogue: 0,0:37:34.03,0:37:35.23,EN,,0,0,0,,And now what I'm going to do is Dialogue: 0,0:37:35.28,0:37:39.85,EN,,0,0,0,,I'm going to indent so that the operands are written vertically. Dialogue: 0,0:37:40.30,0:37:45.65,EN,,0,0,0,,Which the sum of that and the product of 47 and-- Dialogue: 0,0:37:47.02,0:37:54.59,EN,,0,0,0,,let's say the product of 47 with a difference of 20 and 6.8. Dialogue: 0,0:37:54.62,0:37:57.09,EN,,0,0,0,,That means subtract 6.8 from 20. Dialogue: 0,0:37:58.97,0:38:00.19,EN,,0,0,0,,And then you see the parentheses close. Dialogue: 0,0:38:00.22,0:38:03.47,EN,,0,0,0,,Close the minus. Close the star. Dialogue: 0,0:38:03.76,0:38:05.42,EN,,0,0,0,,And now let's get another operator. Dialogue: 0,0:38:05.44,0:38:09.49,EN,,0,0,0,,You see the Lisp editor here is indenting to the right position automatically Dialogue: 0,0:38:10.40,0:38:11.50,EN,,0,0,0,,to help me keep track. Dialogue: 0,0:38:12.61,0:38:14.09,EN,,0,0,0,,I'll do that again. Dialogue: 0,0:38:14.13,0:38:15.89,EN,,0,0,0,,I'll close that last parentheses again. Dialogue: 0,0:38:16.25,0:38:17.71,EN,,0,0,0,,You see it balances the plus. Dialogue: 0,0:38:20.40,0:38:22.64,EN,,0,0,0,,Now I can say, what's the value of that? Dialogue: 0,0:38:23.87,0:38:29.28,EN,,0,0,0,,So those two things, indenting to the right level, Dialogue: 0,0:38:29.31,0:38:30.86,EN,,0,0,0,,which is called pretty printing, Dialogue: 0,0:38:31.55,0:38:33.58,EN,,0,0,0,,and flashing parentheses, Dialogue: 0,0:38:33.89,0:38:37.73,EN,,0,0,0,,are two things that a lot of Lisp systems have built in to help you keep track. Dialogue: 0,0:38:37.76,0:38:39.01,EN,,0,0,0,,And you should learn how to use them. Dialogue: 0,0:38:41.52,0:38:43.17,EN,,0,0,0,,Ok, those are the primitives. Dialogue: 0,0:38:44.73,0:38:46.31,EN,,0,0,0,,There's a means of combination. Dialogue: 0,0:38:46.33,0:38:47.93,EN,,0,0,0,,Now let's go up to the means of abstraction. Dialogue: 0,0:38:49.44,0:38:53.84,EN,,0,0,0,,I'd like to be able to take the idea that I do some combination like this, Dialogue: 0,0:38:53.85,0:38:55.77,EN,,0,0,0,,and abstract it and give it a simple name, Dialogue: 0,0:38:55.81,0:38:57.26,EN,,0,0,0,,so I can use that as an element. Dialogue: 0,0:38:57.31,0:38:59.92,EN,,0,0,0,,And I do that in Lisp with "define." Dialogue: 0,0:39:01.17,0:39:02.43,EN,,0,0,0,,So I can say, for example, Dialogue: 0,0:39:02.73,0:39:15.05,EN,,0,0,0,,define A to be the product of 5 and 5. Dialogue: 0,0:39:18.40,0:39:22.35,EN,,0,0,0,,And now I could say, for example, to Lisp, Dialogue: 0,0:39:22.38,0:39:26.01,EN,,0,0,0,,what is the product of A and A? Dialogue: 0,0:39:27.18,0:39:29.81,EN,,0,0,0,,And this should be 25, and this should be 625. Dialogue: 0,0:39:31.97,0:39:36.01,EN,,0,0,0,,And then, crucial thing, I can now use A-- Dialogue: 0,0:39:36.21,0:39:37.92,EN,,0,0,0,,here I've used it in a combination-- Dialogue: 0,0:39:38.41,0:39:43.55,EN,,0,0,0,,but I could use that in other more complicated things that I name in turn. Dialogue: 0,0:39:43.58,0:39:50.93,EN,,0,0,0,,So I could say, define B to be the sum of, Dialogue: 0,0:39:50.97,0:39:57.45,EN,,0,0,0,,we'll say, A and the product of 5 and A. Dialogue: 0,0:39:59.44,0:40:00.72,EN,,0,0,0,,And then close the plus. Dialogue: 0,0:40:03.45,0:40:05.85,EN,,0,0,0,,Let's take a look at that on the computer and see how that looks. Dialogue: 0,0:40:07.28,0:40:10.68,EN,,0,0,0,,So I'll just type what I wrote on the board. Dialogue: 0,0:40:10.83,0:40:21.73,EN,,0,0,0,,I could say, define A to be the product of 5 and 5. Dialogue: 0,0:40:23.74,0:40:25.38,EN,,0,0,0,,And I'll tell that to Lisp. Dialogue: 0,0:40:25.52,0:40:28.94,EN,,0,0,0,,And notice what Lisp responded there with was an A in the bottom. Dialogue: 0,0:40:29.09,0:40:31.38,EN,,0,0,0,,In general, when you type in a definition in Lisp, Dialogue: 0,0:40:31.50,0:40:35.02,EN,,0,0,0,,it responds with the symbol being defined. Dialogue: 0,0:40:35.63,0:40:39.66,EN,,0,0,0,,Now I could say to Lisp, what is the product of A and A? Dialogue: 0,0:40:42.81,0:40:44.33,EN,,0,0,0,,And it says that's 625. Dialogue: 0,0:40:46.05,0:41:00.34,EN,,0,0,0,,I can define B to be the sum of A and the product of 5 and A. Dialogue: 0,0:41:00.48,0:41:05.70,EN,,0,0,0,,Close a paren closes the star. Close the plus. Close the "define." Dialogue: 0,0:41:07.63,0:41:10.37,EN,,0,0,0,,Lisp says, OK, B, there on the bottom. Dialogue: 0,0:41:11.04,0:41:13.24,EN,,0,0,0,,And now I can say to Lisp, what's the value of B? Dialogue: 0,0:41:17.18,0:41:18.88,EN,,0,0,0,,And I can say something more complicated, Dialogue: 0,0:41:18.93,0:41:26.69,EN,,0,0,0,,like what's the sum of A and the quotient of B and 5? Dialogue: 0,0:41:26.73,0:41:30.25,EN,,0,0,0,,That slash is divide, another primitive operator. Dialogue: 0,0:41:30.38,0:41:32.78,EN,,0,0,0,,I've divided B by 5, added it to A. Dialogue: 0,0:41:33.65,0:41:35.23,EN,,0,0,0,,Lisp says, OK, that's 55. Dialogue: 0,0:41:36.57,0:41:37.92,EN,,0,0,0,,So there's what it looks like. Dialogue: 0,0:41:39.82,0:41:43.40,EN,,0,0,0,,There's the basic means of defining something. Dialogue: 0,0:41:43.44,0:41:49.02,EN,,0,0,0,,It's the simplest kind of naming, but it's not really very powerful. Dialogue: 0,0:41:50.06,0:41:51.60,EN,,0,0,0,,See, what I'd really like to name-- Dialogue: 0,0:41:51.84,0:41:53.37,EN,,0,0,0,,remember, we're talking about general methods-- Dialogue: 0,0:41:53.57,0:41:57.68,EN,,0,0,0,,I'd like to name, oh, the general idea that, for example, Dialogue: 0,0:41:58.11,0:42:17.53,EN,,0,0,0,,I could multiply 5 by 5, or 6 by 6, or 1,001 by 1,001, 1,001.7 by 1,001.7. Dialogue: 0,0:42:17.76,0:42:24.16,EN,,0,0,0,,I'd like to be able to name the general idea of multiplying something by itself. Dialogue: 0,0:42:28.48,0:42:30.11,EN,,0,0,0,,Well, you know what that is. That's called squaring. Dialogue: 0,0:42:31.69,0:42:35.63,EN,,0,0,0,,And the way I can do that in Lisp is I can say, Dialogue: 0,0:42:37.97,0:42:56.25,EN,,0,0,0,,define to square something x, multiply x by itself. Dialogue: 0,0:42:57.87,0:43:01.12,EN,,0,0,0,,And then having done that, I could say to Lisp, Dialogue: 0,0:43:01.12,0:43:05.49,EN,,0,0,0,,for example, what's the square of 10? Dialogue: 0,0:43:06.67,0:43:07.87,EN,,0,0,0,,And Lisp will say 100. Dialogue: 0,0:43:10.70,0:43:14.24,EN,,0,0,0,,So now let's actually look at that a little more closely. Dialogue: 0,0:43:15.29,0:43:16.88,EN,,0,0,0,,Right, there's the definition of square. Dialogue: 0,0:43:17.50,0:43:22.55,EN,,0,0,0,,To square something, multiply it by itself. Dialogue: 0,0:43:23.69,0:43:25.34,EN,,0,0,0,,You see this x here. Dialogue: 0,0:43:26.29,0:43:27.81,EN,,0,0,0,,That x is kind of a pronoun, Dialogue: 0,0:43:27.87,0:43:29.53,EN,,0,0,0,,which is the something that I'm going to square. Dialogue: 0,0:43:31.49,0:43:37.41,EN,,0,0,0,,And what I do with it is I multiply x, I multiply it by itself. Dialogue: 0,0:43:42.22,0:43:48.27,EN,,0,0,0,,OK. So there's the notation for defining a procedure. Dialogue: 0,0:43:48.29,0:43:50.29,EN,,0,0,0,,Actually, this is a little bit confusing, Dialogue: 0,0:43:50.81,0:43:53.97,EN,,0,0,0,,because this is sort of how I might use square. Dialogue: 0,0:43:54.00,0:43:56.80,EN,,0,0,0,,And I say square root of x or square root of 10, Dialogue: 0,0:43:57.55,0:44:00.81,EN,,0,0,0,,but it's not making it very clear that I'm actually naming something. Dialogue: 0,0:44:03.10,0:44:04.91,EN,,0,0,0,,So let me write this definition in another way Dialogue: 0,0:44:05.74,0:44:08.21,EN,,0,0,0,,that makes it a little bit more clear that I'm naming something. Dialogue: 0,0:44:08.54,0:44:29.39,EN,,0,0,0,,I'll say, "define" square to be lambda of x times xx. Dialogue: 0,0:44:36.56,0:44:42.05,EN,,0,0,0,,Here, I'm naming something square, just like over here, I'm naming something A. Dialogue: 0,0:44:43.23,0:44:44.72,EN,,0,0,0,,The thing that I'm naming square-- Dialogue: 0,0:44:44.75,0:44:48.39,EN,,0,0,0,,here, the thing I named A was the value of this combination. Dialogue: 0,0:44:49.29,0:44:52.41,EN,,0,0,0,,Here, the thing that I'm naming square is this thing Dialogue: 0,0:44:52.43,0:44:53.44,EN,,0,0,0,,that begins with lambda, Dialogue: 0,0:44:53.45,0:44:56.77,EN,,0,0,0,,and lambda is Lisp's way of saying make a procedure. Dialogue: 0,0:45:00.24,0:45:02.91,EN,,0,0,0,,Let's look at that more closely on the slide. Dialogue: 0,0:45:04.27,0:45:05.81,EN,,0,0,0,,The way I read that definition is to say, Dialogue: 0,0:45:05.85,0:45:10.33,EN,,0,0,0,,I define square to be make a procedure-- Dialogue: 0,0:45:12.78,0:45:13.97,EN,,0,0,0,,that's what the lambda is-- Dialogue: 0,0:45:14.06,0:45:17.49,EN,,0,0,0,,make a procedure with an argument named x. Dialogue: 0,0:45:19.26,0:45:24.09,EN,,0,0,0,,And what it does is return the results of multiplying x by itself. Dialogue: 0,0:45:24.97,0:45:33.12,EN,,0,0,0,,Now, in general, we're going to be using this top form of defining, Dialogue: 0,0:45:33.41,0:45:35.20,EN,,0,0,0,,just because it's a little bit more convenient. Dialogue: 0,0:45:35.21,0:45:38.67,EN,,0,0,0,,But don't lose sight of the fact that it's really this. Dialogue: 0,0:45:38.86,0:45:41.41,EN,,0,0,0,,In fact, as far as the Lisp interpreter's concerned, Dialogue: 0,0:45:41.61,0:45:45.55,EN,,0,0,0,,there's no difference between typing this to it and typing this to it. Dialogue: 0,0:45:46.51,0:45:53.29,EN,,0,0,0,,And there's a word for that, sort of syntactic sugar. Dialogue: 0,0:45:54.41,0:45:55.80,EN,,0,0,0,,What syntactic sugar means, Dialogue: 0,0:45:56.35,0:46:00.83,EN,,0,0,0,,it's having somewhat more convenient surface forms for typing something. Dialogue: 0,0:46:01.12,0:46:06.11,EN,,0,0,0,,So this is just really syntactic sugar for this underlying Greek thing with the lambda. Dialogue: 0,0:46:07.31,0:46:10.62,EN,,0,0,0,,And the reason you should remember that is don't forget that, Dialogue: 0,0:46:10.80,0:46:13.87,EN,,0,0,0,,when I write something like this, I'm really naming something. Dialogue: 0,0:46:14.46,0:46:16.22,EN,,0,0,0,,I'm naming something square, Dialogue: 0,0:46:16.24,0:46:19.90,EN,,0,0,0,,and the something that I'm naming square is a procedure that's getting constructed. Dialogue: 0,0:46:21.20,0:46:23.90,EN,,0,0,0,,Well, let's look at that on the computer, too. Dialogue: 0,0:46:24.78,0:46:35.95,EN,,0,0,0,,So I'll come and I'll say, define square of x to be times xx. Dialogue: 0,0:46:49.65,0:46:52.32,EN,,0,0,0,,Now I'll tell Lisp that. Dialogue: 0,0:46:53.49,0:46:53.92,EN,,0,0,0,,It says "square." Dialogue: 0,0:46:53.93,0:46:56.29,EN,,0,0,0,,See, I've named something "square." Dialogue: 0,0:46:56.45,0:47:02.88,EN,,0,0,0,,Now, having done that, I can ask Lisp for, what's the square of 1,001? Dialogue: 0,0:47:05.26,0:47:17.69,EN,,0,0,0,,Or in general, I could say, what's the square of the sum of 5 and 7? Dialogue: 0,0:47:22.81,0:47:24.95,EN,,0,0,0,,The square of 12's 144. Dialogue: 0,0:47:25.07,0:47:28.86,EN,,0,0,0,,Or I can use square itself as an element in some combination. Dialogue: 0,0:47:28.88,0:47:37.50,EN,,0,0,0,,I can say, what's the sum of the square of 3 and the square of 4? Dialogue: 0,0:47:42.53,0:47:44.09,EN,,0,0,0,,9 and 16 is 25. Dialogue: 0,0:47:44.91,0:47:50.54,EN,,0,0,0,,Or I can use square as an element in some much more complicated thing. Dialogue: 0,0:47:50.59,0:48:00.51,EN,,0,0,0,,I can say, what's the square of, the sqare of, the square of 1,001? Dialogue: 0,0:48:07.89,0:48:10.63,EN,,0,0,0,,And there's the square of the square of the square of 1,001. Dialogue: 0,0:48:11.20,0:48:15.45,EN,,0,0,0,,Or I can say to Lisp, what is square itself? Dialogue: 0,0:48:15.68,0:48:17.16,EN,,0,0,0,,What's the value of that? Dialogue: 0,0:48:17.44,0:48:22.14,EN,,0,0,0,,And Lisp returns some conventional way of telling me that that's a procedure. Dialogue: 0,0:48:22.27,0:48:23.98,EN,,0,0,0,,It says, "compound procedure square." Dialogue: 0,0:48:24.25,0:48:27.92,EN,,0,0,0,,Remember, the value of square is this procedure, Dialogue: 0,0:48:29.15,0:48:30.89,EN,,0,0,0,,and the thing with the stars and the brackets Dialogue: 0,0:48:31.10,0:48:34.78,EN,,0,0,0,,are just Lisp's conventional way of describing that. Dialogue: 0,0:48:36.11,0:48:41.33,EN,,0,0,0,,Let's look at two more examples of defining. Dialogue: 0,0:48:44.91,0:48:46.91,EN,,0,0,0,,Here are two more procedures. Dialogue: 0,0:48:47.36,0:48:52.84,EN,,0,0,0,,I can define the average of x and y to be the sum of x and y divided by 2. Dialogue: 0,0:48:54.67,0:49:01.49,EN,,0,0,0,,Or having had average and mean square, having had average and square, Dialogue: 0,0:49:01.65,0:49:04.71,EN,,0,0,0,,I can use that to talk about the mean square of something, Dialogue: 0,0:49:04.91,0:49:09.26,EN,,0,0,0,,which is the average of the square of x and the square of y. Dialogue: 0,0:49:10.97,0:49:13.63,EN,,0,0,0,,So for example, having done that, I could say, Dialogue: 0,0:49:13.66,0:49:24.88,EN,,0,0,0,,what's the mean square of 2 and 3? Dialogue: 0,0:49:25.23,0:49:30.24,EN,,0,0,0,,And I should get the average of 4 and 9, which is 6.5. Dialogue: 0,0:49:32.85,0:49:36.64,EN,,0,0,0,,The key thing here is that, having defined square, Dialogue: 0,0:49:36.64,0:49:38.67,EN,,0,0,0,,I can use it as if it were primitive. Dialogue: 0,0:49:41.41,0:49:43.07,EN,,0,0,0,,So if we look here on the slide, Dialogue: 0,0:49:44.65,0:49:45.74,EN,,0,0,0,,if I look at mean square, Dialogue: 0,0:49:47.29,0:49:52.56,EN,,0,0,0,,the person defining mean square doesn't have to know, at this point, Dialogue: 0,0:49:52.61,0:49:55.76,EN,,0,0,0,,whether square was something built into the language Dialogue: 0,0:49:56.94,0:49:58.93,EN,,0,0,0,,or whether it was a procedure that was defined. Dialogue: 0,0:49:59.73,0:50:01.28,EN,,0,0,0,,And that's a key thing in Lisp, Dialogue: 0,0:50:02.30,0:50:07.52,EN,,0,0,0,,that you do not make arbitrary distinctions between things Dialogue: 0,0:50:07.53,0:50:11.82,EN,,0,0,0,,that happen to be primitive in the language and things that happen to be built in. Dialogue: 0,0:50:12.83,0:50:14.73,EN,,0,0,0,,A person using that shouldn't even have to know. Dialogue: 0,0:50:14.93,0:50:18.51,EN,,0,0,0,,So the things you construct get used with all the power and flexibility Dialogue: 0,0:50:18.51,0:50:19.53,EN,,0,0,0,,as if they were primitives. Dialogue: 0,0:50:19.57,0:50:22.57,EN,,0,0,0,,In fact, you can drive that home by looking on the computer one more time. Dialogue: 0,0:50:24.75,0:50:26.30,EN,,0,0,0,,We talked about plus. Dialogue: 0,0:50:26.72,0:50:30.09,EN,,0,0,0,,And in fact, if I come here on the computer screen and say, Dialogue: 0,0:50:30.11,0:50:32.33,EN,,0,0,0,,what is the value of plus? Dialogue: 0,0:50:34.40,0:50:37.20,EN,,0,0,0,,Notice what Lisp types out. On the bottom there, it typed out, Dialogue: 0,0:50:37.25,0:50:38.81,EN,,0,0,0,,"compound procedure plus." Dialogue: 0,0:50:39.89,0:50:42.29,EN,,0,0,0,,Because, in this system, Dialogue: 0,0:50:42.33,0:50:45.49,EN,,0,0,0,,it turns out that the addition operator is itself a compound procedure. Dialogue: 0,0:50:45.97,0:50:47.97,EN,,0,0,0,,And if I didn't just type that in, you'd never know that, Dialogue: 0,0:50:48.06,0:50:49.68,EN,,0,0,0,,and it wouldn't make any difference anyway. Dialogue: 0,0:50:49.84,0:50:50.51,EN,,0,0,0,,We don't care. Dialogue: 0,0:50:50.56,0:50:53.39,EN,,0,0,0,,It's below the level of the abstraction that we're dealing with. Dialogue: 0,0:50:54.17,0:50:59.11,EN,,0,0,0,,So the key thing is you cannot tell, should not be able to tell, in general, Dialogue: 0,0:50:59.17,0:51:03.82,EN,,0,0,0,,the difference between things that are built in and things that are compound. Dialogue: 0,0:51:03.84,0:51:04.38,EN,,0,0,0,,Why is that? Dialogue: 0,0:51:04.38,0:51:08.07,EN,,0,0,0,,Because the things that are compound have an abstraction wrapper wrapped around them. Dialogue: 0,0:51:09.05,0:51:11.61,EN,,0,0,0,,We've seen almost all the elements of Lisp now. Dialogue: 0,0:51:12.67,0:51:14.53,EN,,0,0,0,,There's only one more we have to look at, Dialogue: 0,0:51:14.57,0:51:16.53,EN,,0,0,0,,and that is how to make a case analysis. Dialogue: 0,0:51:16.59,0:51:17.70,EN,,0,0,0,,Let me show you what I mean. Dialogue: 0,0:51:18.96,0:51:24.08,EN,,0,0,0,,We might want to think about the mathematical definition of the absolute value functions. Dialogue: 0,0:51:24.11,0:51:30.03,EN,,0,0,0,,I might say the absolute value of x is the function Dialogue: 0,0:51:30.16,0:51:37.24,EN,,0,0,0,,which has the property that it's negative of x. For x less than 0, Dialogue: 0,0:51:37.92,0:51:41.13,EN,,0,0,0,,it's 0 for x equal to 0. Dialogue: 0,0:51:42.64,0:51:46.62,EN,,0,0,0,,And it's x for x greater than 0. Dialogue: 0,0:51:49.15,0:51:51.90,EN,,0,0,0,,And Lisp has a way of making case analyses. Dialogue: 0,0:51:52.11,0:51:53.85,EN,,0,0,0,,Let me define for you absolute value. Dialogue: 0,0:51:55.55,0:52:02.41,EN,,0,0,0,,Say define the absolute value of x is conditional. Dialogue: 0,0:52:03.02,0:52:05.67,EN,,0,0,0,,This means case analysis, COND. Dialogue: 0,0:52:09.23,0:52:19.09,EN,,0,0,0,,If x is less than 0, the answer is negate x. Dialogue: 0,0:52:22.99,0:52:24.88,EN,,0,0,0,,What I've written here is a clause. Dialogue: 0,0:52:24.99,0:52:35.54,EN,,0,0,0,,This whole thing is a conditional clause, and it has two parts. Dialogue: 0,0:52:36.35,0:52:44.70,EN,,0,0,0,,This part here is a predicate or a condition. Dialogue: 0,0:52:44.83,0:52:45.90,EN,,0,0,0,,That's a condition. Dialogue: 0,0:52:46.11,0:52:48.29,EN,,0,0,0,,And the condition is expressed by something called a predicate, Dialogue: 0,0:52:48.33,0:52:51.05,EN,,0,0,0,,and a predicate in Lisp is some sort of thing Dialogue: 0,0:52:51.37,0:52:52.87,EN,,0,0,0,,that returns either true or false. Dialogue: 0,0:52:53.53,0:52:56.13,EN,,0,0,0,,And you see Lisp has a primitive procedure, less-than, Dialogue: 0,0:52:57.29,0:52:59.08,EN,,0,0,0,,that tests whether something is true or false. Dialogue: 0,0:53:00.54,0:53:06.32,EN,,0,0,0,,And the other part of a clause is an action or a thing to do, Dialogue: 0,0:53:06.93,0:53:08.14,EN,,0,0,0,,in the case where that's true. Dialogue: 0,0:53:08.17,0:53:09.81,EN,,0,0,0,,And here, what I'm doing is negating x. Dialogue: 0,0:53:10.08,0:53:14.41,EN,,0,0,0,,The negation operator, the minus sign in Lisp is a little bit funny. Dialogue: 0,0:53:14.56,0:53:18.43,EN,,0,0,0,,If there's two or more arguments, Dialogue: 0,0:53:18.58,0:53:22.49,EN,,0,0,0,,if there's two arguments it subtracts the second one from the first, and we saw that. Dialogue: 0,0:53:22.53,0:53:24.13,EN,,0,0,0,,And if there's one argument, it negates it. Dialogue: 0,0:53:25.13,0:53:27.87,EN,,0,0,0,,So this corresponds to that. Dialogue: 0,0:53:27.87,0:53:29.69,EN,,0,0,0,,And then there's another COND clause. Dialogue: 0,0:53:30.64,0:53:35.87,EN,,0,0,0,,It says, in the case where x is equal to 0, the answer is 0. Dialogue: 0,0:53:37.95,0:53:44.75,EN,,0,0,0,,And in the case where x is greater than 0, the answer is x. Dialogue: 0,0:53:45.33,0:53:49.38,EN,,0,0,0,,Close that clause. Close the COND. Close the definition. Dialogue: 0,0:53:49.57,0:53:51.29,EN,,0,0,0,,And there's the definition of absolute value. Dialogue: 0,0:53:51.31,0:53:53.66,EN,,0,0,0,,And you see it's the case analysis that looks very much Dialogue: 0,0:53:53.66,0:53:56.04,EN,,0,0,0,,like the case analysis you use in mathematics. Dialogue: 0,0:53:58.14,0:54:03.07,EN,,0,0,0,,There's a somewhat different way of writing a restricted case analysis. Dialogue: 0,0:54:03.07,0:54:06.24,EN,,0,0,0,,Often, you have a case analysis where you only have one case, Dialogue: 0,0:54:06.93,0:54:08.07,EN,,0,0,0,,where you test something, Dialogue: 0,0:54:08.33,0:54:10.75,EN,,0,0,0,,and then depending on whether it's true or false, you do something. Dialogue: 0,0:54:11.01,0:54:15.90,EN,,0,0,0,,And here's another definition of absolute value Dialogue: 0,0:54:16.00,0:54:17.19,EN,,0,0,0,,which looks almost the same, Dialogue: 0,0:54:17.66,0:54:22.56,EN,,0,0,0,,which says, if x is less than 0, the result is negate x. Dialogue: 0,0:54:24.41,0:54:25.97,EN,,0,0,0,,Otherwise, the answer is x. Dialogue: 0,0:54:26.05,0:54:27.25,EN,,0,0,0,,And we'll be using "if" a lot. Dialogue: 0,0:54:27.29,0:54:29.13,EN,,0,0,0,,But again, the thing to remember is that Dialogue: 0,0:54:29.13,0:54:32.70,EN,,0,0,0,,this form of absolute value that you're looking at here, Dialogue: 0,0:54:34.30,0:54:36.98,EN,,0,0,0,,and then this one over here that I wrote on the board, Dialogue: 0,0:54:37.52,0:54:38.80,EN,,0,0,0,,are essentially the same. Dialogue: 0,0:54:39.09,0:54:42.26,EN,,0,0,0,,And "if" and COND are-- well, whichever way you like it. Dialogue: 0,0:54:42.30,0:54:44.45,EN,,0,0,0,,You can think of COND as syntactic sugar for "if", Dialogue: 0,0:54:44.99,0:54:47.36,EN,,0,0,0,,or you can think of "if" as syntactic sugar for COND, Dialogue: 0,0:54:47.39,0:54:48.65,EN,,0,0,0,,and it doesn't make any difference. Dialogue: 0,0:54:49.21,0:54:51.35,EN,,0,0,0,,The person implementing a Lisp system will pick one Dialogue: 0,0:54:51.39,0:54:52.97,EN,,0,0,0,,and implement the other in terms of that. Dialogue: 0,0:54:53.15,0:54:54.67,EN,,0,0,0,,And it doesn't matter which one you pick. Dialogue: 0,0:55:02.27,0:55:05.36,EN,,0,0,0,,Why don't we break now, and then take some questions. Dialogue: 0,0:55:05.69,0:55:10.08,EN,,0,0,0,,How come sometimes when I write define, Dialogue: 0,0:55:11.09,0:55:14.75,EN,,0,0,0,,I put an open paren here and say, Dialogue: 0,0:55:14.81,0:55:16.45,EN,,0,0,0,,define open paren something or other, Dialogue: 0,0:55:16.86,0:55:20.81,EN,,0,0,0,,and sometimes when I write this, I don't put an open paren? Dialogue: 0,0:55:22.06,0:55:27.23,EN,,0,0,0,,The answer is, this particular form of "define", Dialogue: 0,0:55:27.26,0:55:29.41,EN,,0,0,0,,where you say define some expression, Dialogue: 0,0:55:29.47,0:55:32.13,EN,,0,0,0,,is this very special thing for defining procedures. Dialogue: 0,0:55:33.61,0:55:40.21,EN,,0,0,0,,But again, what it really means is I'm defining this symbol, square, to be that. Dialogue: 0,0:55:41.45,0:55:45.98,EN,,0,0,0,,So the way you should think about it is what "define" does is you write "define", Dialogue: 0,0:55:47.15,0:55:50.06,EN,,0,0,0,,and the second thing you write is the symbol here-- no open paren-- Dialogue: 0,0:55:50.17,0:55:51.49,EN,,0,0,0,,the symbol you're defining Dialogue: 0,0:55:52.08,0:55:53.70,EN,,0,0,0,,and what you're defining it to be. Dialogue: 0,0:55:54.65,0:55:57.55,EN,,0,0,0,,That's like here and like here. Dialogue: 0,0:55:57.61,0:56:00.29,EN,,0,0,0,,That's sort of the basic way you use "define." Dialogue: 0,0:56:01.12,0:56:03.65,EN,,0,0,0,,And then, there's this special syntactic trick Dialogue: 0,0:56:04.29,0:56:07.04,EN,,0,0,0,,which allows you to define procedures that look like this. Dialogue: 0,0:56:08.17,0:56:11.49,EN,,0,0,0,,So the difference is, it's whether or not you're defining a procedure. Dialogue: 0,0:56:12.91,0:56:37.60,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:56:38.05,0:56:41.98,EN,,0,0,0,,Well, believe it or not, you actually now know enough Lisp Dialogue: 0,0:56:42.78,0:56:45.42,EN,,0,0,0,,to write essentially any numerical procedure Dialogue: 0,0:56:46.25,0:56:49.63,EN,,0,0,0,,that you'd write in a language like FORTRAN or Basic or whatever, Dialogue: 0,0:56:49.66,0:56:51.01,EN,,0,0,0,,or, essentially, any other language. Dialogue: 0,0:56:52.05,0:56:54.76,EN,,0,0,0,,And you're probably saying, that's not believable, Dialogue: 0,0:56:54.81,0:56:56.65,EN,,0,0,0,,because you know that these languages have things Dialogue: 0,0:56:56.65,0:57:00.22,EN,,0,0,0,,like "for statements", and "do until while" or something. Dialogue: 0,0:57:00.99,0:57:04.59,EN,,0,0,0,,But we don't really need any of that. Dialogue: 0,0:57:05.05,0:57:07.13,EN,,0,0,0,,In fact, we're not going to use any of that in this course. Dialogue: 0,0:57:08.25,0:57:10.16,EN,,0,0,0,,Let me show you. Dialogue: 0,0:57:10.25,0:57:13.61,EN,,0,0,0,,Again, looking back at square root, Dialogue: 0,0:57:13.65,0:57:19.03,EN,,0,0,0,,let's go back to this square root algorithm of Heron of Alexandria. Dialogue: 0,0:57:19.09,0:57:19.97,EN,,0,0,0,,Remember what that said. Dialogue: 0,0:57:20.06,0:57:23.67,EN,,0,0,0,,It said, to find an approximation to the square root of X, Dialogue: 0,0:57:25.07,0:57:26.16,EN,,0,0,0,,you make a guess, Dialogue: 0,0:57:27.45,0:57:31.88,EN,,0,0,0,,you improve that guess by averaging the guess and X over the guess. Dialogue: 0,0:57:32.94,0:57:36.06,EN,,0,0,0,,You keep improving that until the guess is good enough. Dialogue: 0,0:57:36.72,0:57:38.43,EN,,0,0,0,,I already alluded to the idea. Dialogue: 0,0:57:38.56,0:57:42.24,EN,,0,0,0,,The idea is that, if the initial guess that you took Dialogue: 0,0:57:43.04,0:57:46.91,EN,,0,0,0,,was actually equal to the square root of X, Dialogue: 0,0:57:47.15,0:57:50.06,EN,,0,0,0,,then G here would be equal to X/G. Dialogue: 0,0:57:52.89,0:57:55.33,EN,,0,0,0,,So if you hit the square root, averaging them wouldn't change it. Dialogue: 0,0:57:55.69,0:57:59.62,EN,,0,0,0,,If the G that you picked was larger than the square root of X, Dialogue: 0,0:58:00.38,0:58:02.94,EN,,0,0,0,,then X/G will be smaller than the square root of X, Dialogue: 0,0:58:03.21,0:58:05.37,EN,,0,0,0,,so that when you average G and X/G, Dialogue: 0,0:58:05.63,0:58:07.57,EN,,0,0,0,,you get something in between. Dialogue: 0,0:58:08.96,0:58:12.95,EN,,0,0,0,,So if you pick a G that's too small, your answer will be too large. Dialogue: 0,0:58:13.12,0:58:14.81,EN,,0,0,0,,If you pick a G that's too large, Dialogue: 0,0:58:16.32,0:58:18.06,EN,,0,0,0,,if your G is larger than the square root of X Dialogue: 0,0:58:18.08,0:58:20.35,EN,,0,0,0,,and X/G will be smaller than the square root of X. Dialogue: 0,0:58:21.23,0:58:23.65,EN,,0,0,0,,So averaging always gives you something in between. Dialogue: 0,0:58:24.53,0:58:28.13,EN,,0,0,0,,And then, it's not quite trivial, but it's possible to show that, Dialogue: 0,0:58:28.17,0:58:31.76,EN,,0,0,0,,in fact, if G misses the square root of X by a little bit, Dialogue: 0,0:58:31.81,0:58:37.99,EN,,0,0,0,,the average of G and X/G will actually keep getting closer to the square root of X. Dialogue: 0,0:58:38.03,0:58:38.99,EN,,0,0,0,,So if you keep doing this enough, Dialogue: 0,0:58:39.42,0:58:41.18,EN,,0,0,0,,you'll eventually get as close as you want. Dialogue: 0,0:58:41.71,0:58:42.85,EN,,0,0,0,,And then there's another fact, Dialogue: 0,0:58:43.02,0:58:47.65,EN,,0,0,0,,that you can always start out this process by using 1 as an initial guess. Dialogue: 0,0:58:49.23,0:58:51.35,EN,,0,0,0,,And it'll always converge to the square root of X. Dialogue: 0,0:58:52.24,0:58:56.77,EN,,0,0,0,,So that's this method of successive averaging due to Heron of Alexandria. Dialogue: 0,0:58:56.81,0:58:59.21,EN,,0,0,0,,Let's write it in Lisp. Dialogue: 0,0:59:00.57,0:59:02.61,EN,,0,0,0,,Well, the central idea is, Dialogue: 0,0:59:02.65,0:59:07.19,EN,,0,0,0,,what does it mean to try a guess for the square root of X? Dialogue: 0,0:59:08.30,0:59:09.37,EN,,0,0,0,,Let's write that. Dialogue: 0,0:59:09.79,0:59:25.02,EN,,0,0,0,,So we'll say, define to try a guess for the square root of X, Dialogue: 0,0:59:26.45,0:59:28.24,EN,,0,0,0,,what do we do? We'll say, Dialogue: 0,0:59:28.29,0:59:45.26,EN,,0,0,0,,if the guess is good enough to be a guess for the square root of X, Dialogue: 0,0:59:46.54,0:59:49.52,EN,,0,0,0,,then, as an answer, we'll take the guess. Dialogue: 0,0:59:51.61,0:59:57.01,EN,,0,0,0,,Otherwise, we will try the improved guess. Dialogue: 0,0:59:58.19,1:00:04.24,EN,,0,0,0,,We'll improve that guess for the square root of X, Dialogue: 0,1:00:05.26,1:00:09.33,EN,,0,0,0,,and we'll try that as a guess for the square root of X. Dialogue: 0,1:00:09.36,1:00:12.96,EN,,0,0,0,,Close the "try." Close the "if." Close the "define." Dialogue: 0,1:00:13.31,1:00:14.81,EN,,0,0,0,,So that's how we try a guess. Dialogue: 0,1:00:15.85,1:00:17.60,EN,,0,0,0,,And then, the next part of the process said, Dialogue: 0,1:00:17.73,1:00:21.90,EN,,0,0,0,,in order to compute square roots, we'll say, Dialogue: 0,1:00:21.93,1:00:30.17,EN,,0,0,0,,define to compute the square root of X, Dialogue: 0,1:00:30.80,1:00:35.79,EN,,0,0,0,,we will try 1 as a guess for the square root of X. Dialogue: 0,1:00:37.42,1:00:39.59,EN,,0,0,0,,Well, we have to define a couple more things. Dialogue: 0,1:00:40.08,1:00:43.36,EN,,0,0,0,,We have to say, how is a guess good enough? Dialogue: 0,1:00:43.84,1:00:45.29,EN,,0,0,0,,And how do we improve a guess? Dialogue: 0,1:00:45.85,1:00:47.10,EN,,0,0,0,,So let's look at that. Dialogue: 0,1:00:47.39,1:00:54.24,EN,,0,0,0,,The algorithm to improve a guess for the square root of X, Dialogue: 0,1:00:54.64,1:00:57.18,EN,,0,0,0,,we average-- that was the algorithm-- Dialogue: 0,1:00:57.18,1:01:02.16,EN,,0,0,0,,we average the guess with the quotient of dividing X by the guess. Dialogue: 0,1:01:02.99,1:01:04.57,EN,,0,0,0,,That's how we improve a guess. Dialogue: 0,1:01:05.85,1:01:08.80,EN,,0,0,0,,And to tell whether a guess is good enough, well, we have to decide something. Dialogue: 0,1:01:08.86,1:01:11.36,EN,,0,0,0,,This is supposed to be a guess for the square root of X, Dialogue: 0,1:01:11.37,1:01:14.03,EN,,0,0,0,,so one possible thing you can do is say, Dialogue: 0,1:01:14.06,1:01:16.07,EN,,0,0,0,,when you take that guess and square it, Dialogue: 0,1:01:16.64,1:01:18.41,EN,,0,0,0,,do you get something very close to X? Dialogue: 0,1:01:18.59,1:01:21.10,EN,,0,0,0,,So one way to say that is to say, Dialogue: 0,1:01:21.12,1:01:24.31,EN,,0,0,0,,I square the guess, subtract X from that, Dialogue: 0,1:01:25.15,1:01:27.15,EN,,0,0,0,,and see if the absolute value of that Dialogue: 0,1:01:27.20,1:01:32.05,EN,,0,0,0,,whole thing is less than some small number, which depends on my purposes. Dialogue: 0,1:01:34.70,1:01:41.42,EN,,0,0,0,,So there's a complete procedure for how to compute the square root of X. Dialogue: 0,1:01:41.47,1:01:43.53,EN,,0,0,0,,Let's look at the structure of that a little bit. Dialogue: 0,1:01:47.84,1:01:49.12,EN,,0,0,0,,I have the whole thing. Dialogue: 0,1:01:49.15,1:01:55.44,EN,,0,0,0,,I have the notion of how to compute a square root. Dialogue: 0,1:01:55.53,1:01:56.88,EN,,0,0,0,,That's some kind of module. Dialogue: 0,1:01:57.05,1:01:58.46,EN,,0,0,0,,That's some kind of black box. Dialogue: 0,1:01:58.72,1:02:08.02,EN,,0,0,0,,It's defined in terms of how to try a guess for the square root of X. Dialogue: 0,1:02:09.31,1:02:14.10,EN,,0,0,0,,"Try" is defined in terms of, well, Dialogue: 0,1:02:14.61,1:02:18.03,EN,,0,0,0,,telling whether something is good enough and telling how to improve something. Dialogue: 0,1:02:18.73,1:02:19.68,EN,,0,0,0,,So good enough. Dialogue: 0,1:02:19.89,1:02:28.85,EN,,0,0,0,,"Try" is defined in terms of "good enough" and "improve". Dialogue: 0,1:02:30.96,1:02:32.56,EN,,0,0,0,,And let's see what else I fill in. Dialogue: 0,1:02:32.71,1:02:34.29,EN,,0,0,0,,Well, I'll go down this tree. Dialogue: 0,1:02:34.73,1:02:38.49,EN,,0,0,0,,"Good enough" was defined in terms of absolute value, and square. Dialogue: 0,1:02:40.97,1:02:44.13,EN,,0,0,0,,And improve was defined in terms of something called averaging Dialogue: 0,1:02:45.17,1:02:46.70,EN,,0,0,0,,and then some other primitive operator. Dialogue: 0,1:02:46.72,1:02:48.88,EN,,0,0,0,,Square root's defined in terms of "try". Dialogue: 0,1:02:48.88,1:02:53.31,EN,,0,0,0,,"Try" is defined in terms of "good enough" and "improve", Dialogue: 0,1:02:54.01,1:02:55.39,EN,,0,0,0,,but also "try" itself. Dialogue: 0,1:02:55.58,1:03:00.86,EN,,0,0,0,,So "try" is also defined in terms of how to try itself. Dialogue: 0,1:03:02.75,1:03:04.72,EN,,0,0,0,,Well, that may give you some problems. Dialogue: 0,1:03:04.72,1:03:08.16,EN,,0,0,0,,Your high school geometry teacher probably told you Dialogue: 0,1:03:08.67,1:03:12.57,EN,,0,0,0,,that it's naughty to try and define things in terms of themselves, Dialogue: 0,1:03:12.88,1:03:13.92,EN,,0,0,0,,because it doesn't make sense. Dialogue: 0,1:03:13.92,1:03:14.72,EN,,0,0,0,,But that's false. Dialogue: 0,1:03:16.03,1:03:19.68,EN,,0,0,0,,Sometimes it makes perfect sense to define things in terms of themselves. Dialogue: 0,1:03:20.16,1:03:24.38,EN,,0,0,0,,And this is the case. And we can look at that. Dialogue: 0,1:03:24.38,1:03:26.89,EN,,0,0,0,,We could write down what this means, and say, Dialogue: 0,1:03:26.91,1:03:30.33,EN,,0,0,0,,suppose I asked Lisp what the square root of 2 is. Dialogue: 0,1:03:32.65,1:03:34.67,EN,,0,0,0,,What's the square root of 2 mean? Dialogue: 0,1:03:35.79,1:03:43.61,EN,,0,0,0,,Well, that means I try 1 as a guess for the square root of 2. Dialogue: 0,1:03:46.97,1:03:50.92,EN,,0,0,0,,Now I look. I say, gee, is 1 a good enough guess for the square root of 2? Dialogue: 0,1:03:51.65,1:03:53.69,EN,,0,0,0,,And that depends on the test that "good enough" does. Dialogue: 0,1:03:54.61,1:03:56.56,EN,,0,0,0,,And in this case, "good enough" will say, Dialogue: 0,1:03:56.65,1:03:59.05,EN,,0,0,0,,no, 1 is not a good enough guess for the square root of 2. Dialogue: 0,1:03:59.79,1:04:08.22,EN,,0,0,0,,So that will reduce to saying, I have to try an improved-- Dialogue: 0,1:04:08.64,1:04:12.63,EN,,0,0,0,,improve 1 as a guess for the square root of 2, Dialogue: 0,1:04:15.15,1:04:17.46,EN,,0,0,0,,and try that as a guess for the square root of 2. Dialogue: 0,1:04:19.13,1:04:22.07,EN,,0,0,0,,Improving 1 as a guess for the square root of 2 Dialogue: 0,1:04:22.09,1:04:25.08,EN,,0,0,0,,means I average 1 and 2 divided by 1. Dialogue: 0,1:04:27.10,1:04:29.10,EN,,0,0,0,,So this is going to be average. Dialogue: 0,1:04:29.58,1:04:39.44,EN,,0,0,0,,This piece here will be the average of 1 and the quotient of 2 by 1. Dialogue: 0,1:04:40.83,1:04:42.75,EN,,0,0,0,,That's this piece here. Dialogue: 0,1:04:43.85,1:04:46.72,EN,,0,0,0,,And I'm gonna try... And this is 1.5. Dialogue: 0,1:04:49.07,1:04:54.40,EN,,0,0,0,,So this square root of 2 reduces to trying 1 for the square root of 2, Dialogue: 0,1:04:54.56,1:05:04.83,EN,,0,0,0,,which reduces to trying 1.5 as a guess for the square root of 2. Dialogue: 0,1:05:06.03,1:05:08.06,EN,,0,0,0,,So that makes sense. Dialogue: 0,1:05:08.11,1:05:09.52,EN,,0,0,0,,Let's look at the rest of the process. Dialogue: 0,1:05:09.73,1:05:15.00,EN,,0,0,0,,If I try 1.5, that reduces. Dialogue: 0,1:05:15.01,1:05:19.05,EN,,0,0,0,,1.5 turns out to be not good enough as a guess for the square root of 2. Dialogue: 0,1:05:20.22,1:05:22.00,EN,,0,0,0,,So that reduces to trying the average of Dialogue: 0,1:05:22.01,1:05:26.17,EN,,0,0,0,,1.5 and 2 divided by 1.5 as a guess for the square root of 2. Dialogue: 0,1:05:28.29,1:05:30.37,EN,,0,0,0,,That average turns out to be 1.333. Dialogue: 0,1:05:31.18,1:05:35.24,EN,,0,0,0,,So this whole thing reduces to trying 1.333 as a guess for the square root of 2. Dialogue: 0,1:05:35.28,1:05:36.06,EN,,0,0,0,,And then so on. Dialogue: 0,1:05:38.01,1:05:41.66,EN,,0,0,0,,That reduces to another called a "good enough", 1.4 something or other. Dialogue: 0,1:05:41.73,1:05:44.47,EN,,0,0,0,,And then it keeps going until the process finally stops Dialogue: 0,1:05:44.85,1:05:47.92,EN,,0,0,0,,with something that "good enough" thinks is good enough, which, Dialogue: 0,1:05:47.97,1:05:51.28,EN,,0,0,0,,in this case, is 1.4142 something or other. Dialogue: 0,1:05:52.51,1:05:56.05,EN,,0,0,0,,So the process makes perfect sense. Dialogue: 0,1:05:59.93,1:06:03.10,EN,,0,0,0,,This, by the way, is called a recursive definition. Dialogue: 0,1:06:14.40,1:06:20.96,EN,,0,0,0,,And the ability to make recursive definitions is a source of incredible power. Dialogue: 0,1:06:21.95,1:06:23.05,EN,,0,0,0,,And as you can already see I've hinted at, Dialogue: 0,1:06:23.09,1:06:27.21,EN,,0,0,0,,it's the thing that effectively allows you to do these infinite computations Dialogue: 0,1:06:27.25,1:06:28.83,EN,,0,0,0,,that go on until something is true, Dialogue: 0,1:06:29.73,1:06:33.66,EN,,0,0,0,,without having any other constricts other than the ability to call a procedure. Dialogue: 0,1:06:35.97,1:06:37.47,EN,,0,0,0,,Well, let's see, there's one more thing. Dialogue: 0,1:06:37.71,1:06:44.21,EN,,0,0,0,,Let me show you a variant of this definition of square root here on the slide. Dialogue: 0,1:06:44.43,1:06:48.16,EN,,0,0,0,,Here's sort of the same thing. Dialogue: 0,1:06:48.40,1:06:51.49,EN,,0,0,0,,What I've done here is packaged the definitions of Dialogue: 0,1:06:51.52,1:06:56.16,EN,,0,0,0,,"improve" and "good enough" and "try" inside "square root". Dialogue: 0,1:06:56.75,1:07:00.99,EN,,0,0,0,,So, in effect, what I've done is I've built a square root box. Dialogue: 0,1:07:01.81,1:07:08.53,EN,,0,0,0,,So I've built a box that's the square root procedure that someone can use. Dialogue: 0,1:07:08.57,1:07:11.47,EN,,0,0,0,,They might put in 36 and get out 6. Dialogue: 0,1:07:11.81,1:07:13.83,EN,,0,0,0,,And then, packaged inside this box Dialogue: 0,1:07:14.16,1:07:23.85,EN,,0,0,0,,are the definitions of "try" and "good enough" and "improve." Dialogue: 0,1:07:26.78,1:07:28.35,EN,,0,0,0,,So they're hidden inside this box. Dialogue: 0,1:07:28.40,1:07:30.76,EN,,0,0,0,,And the reason for doing that is that, Dialogue: 0,1:07:31.18,1:07:32.85,EN,,0,0,0,,if someone's using this square root, Dialogue: 0,1:07:33.21,1:07:34.73,EN,,0,0,0,,if George is using this square root, Dialogue: 0,1:07:34.75,1:07:37.36,EN,,0,0,0,,George probably doesn't care very much that, Dialogue: 0,1:07:38.29,1:07:40.03,EN,,0,0,0,,when I implemented square root, Dialogue: 0,1:07:40.21,1:07:44.45,EN,,0,0,0,,I had things inside there called "try" and "good enough" and "improve". Dialogue: 0,1:07:46.40,1:07:49.33,EN,,0,0,0,,And in fact, Harry might have a cube root procedure Dialogue: 0,1:07:49.37,1:07:50.96,EN,,0,0,0,,that has "try" and "good enough" and "improve". Dialogue: 0,1:07:51.44,1:07:53.34,EN,,0,0,0,,And in order to not get the whole system confused, Dialogue: 0,1:07:53.36,1:07:57.66,EN,,0,0,0,,it'd be good for Harry to package his internal procedures inside his cube root procedure. Dialogue: 0,1:07:58.40,1:08:00.06,EN,,0,0,0,,Well, this is called block structure, Dialogue: 0,1:08:00.32,1:08:08.96,EN,,0,0,0,,this particular way of packaging internals inside of a definition. Dialogue: 0,1:08:09.97,1:08:12.96,EN,,0,0,0,,And let's go back and look at the slide again. Dialogue: 0,1:08:13.12,1:08:18.57,EN,,0,0,0,,The way to read this kind of procedure is to say, to define "square root", Dialogue: 0,1:08:19.87,1:08:21.84,EN,,0,0,0,,well, inside that definition, Dialogue: 0,1:08:22.13,1:08:25.49,EN,,0,0,0,,I'll have the definition of an "improve" and Dialogue: 0,1:08:25.56,1:08:28.88,EN,,0,0,0,,the definition of "good enough" and the definition of "try." Dialogue: 0,1:08:29.73,1:08:32.38,EN,,0,0,0,,And then, subject to those definitions, Dialogue: 0,1:08:32.48,1:08:35.07,EN,,0,0,0,,the way I do square root is to try 1. Dialogue: 0,1:08:36.08,1:08:39.33,EN,,0,0,0,,And notice here, I don't have to say 1 as a guess for the square root of X, Dialogue: 0,1:08:39.87,1:08:42.32,EN,,0,0,0,,because since it's all inside the square root, Dialogue: 0,1:08:42.84,1:08:44.65,EN,,0,0,0,,it sort of has this X known. Dialogue: 0,1:08:54.06,1:08:56.37,EN,,0,0,0,,Let me summarize. Dialogue: 0,1:08:56.49,1:08:59.49,EN,,0,0,0,,We started out with the idea that Dialogue: 0,1:08:59.51,1:09:03.18,EN,,0,0,0,,what we're going to be doing is expressing imperative knowledge. Dialogue: 0,1:09:04.99,1:09:09.74,EN,,0,0,0,,And in fact, here's a slide that summarizes the way we looked at Lisp. Dialogue: 0,1:09:09.74,1:09:15.12,EN,,0,0,0,,We started out by looking at some primitive elements in addition and multiplication, Dialogue: 0,1:09:15.85,1:09:19.50,EN,,0,0,0,,some predicates for testing whether something is less-than or something's equal. Dialogue: 0,1:09:19.52,1:09:22.99,EN,,0,0,0,,And in fact, we saw really sneakily in the system we're actually using, Dialogue: 0,1:09:23.02,1:09:25.85,EN,,0,0,0,,these aren't actually primitives, but it doesn't matter. Dialogue: 0,1:09:26.62,1:09:28.59,EN,,0,0,0,,What matters is we're going to use them as if they're primitives. Dialogue: 0,1:09:28.61,1:09:29.81,EN,,0,0,0,,We're not going to look inside. Dialogue: 0,1:09:30.29,1:09:33.15,EN,,0,0,0,,We also have some primitive data and some numbers. Dialogue: 0,1:09:34.62,1:09:37.66,EN,,0,0,0,,We saw some means of composition, means of combination, Dialogue: 0,1:09:37.74,1:09:41.37,EN,,0,0,0,,the basic one being composing functions and Dialogue: 0,1:09:41.41,1:09:43.76,EN,,0,0,0,,building combinations with operators and operands. Dialogue: 0,1:09:44.81,1:09:48.43,EN,,0,0,0,,And there were some other things, like COND and "if" and "define". Dialogue: 0,1:09:51.29,1:09:53.69,EN,,0,0,0,,But the main thing about "define," in particular, Dialogue: 0,1:09:53.87,1:09:55.71,EN,,0,0,0,,was that it was the means of abstraction. Dialogue: 0,1:09:55.73,1:09:57.70,EN,,0,0,0,,It was the way that we name things. Dialogue: 0,1:09:57.79,1:10:00.30,EN,,0,0,0,,You can also see from this slide not only where we've been, Dialogue: 0,1:10:01.57,1:10:06.28,EN,,0,0,0,,At some point, we'll have to talk about how you combine primitive data to get compound data, Dialogue: 0,1:10:06.56,1:10:12.03,EN,,0,0,0,,and how you abstract data so you can use large globs of data Dialogue: 0,1:10:12.06,1:10:13.07,EN,,0,0,0,,as if they were primitive. Dialogue: 0,1:10:13.90,1:10:15.87,EN,,0,0,0,,So that's where we're going. Dialogue: 0,1:10:16.38,1:10:22.05,EN,,0,0,0,,But before we do that, for the next couple of lectures we're going to be talking about, Dialogue: 0,1:10:23.26,1:10:26.76,EN,,0,0,0,,first of all, how it is that you make a link Dialogue: 0,1:10:26.88,1:10:30.77,EN,,0,0,0,,between these procedures we write and the processes that happen in the machine. Dialogue: 0,1:10:32.14,1:10:35.98,EN,,0,0,0,,And then, how it is that you start using the power of Lisp Dialogue: 0,1:10:36.38,1:10:39.77,EN,,0,0,0,,to talk not only about these individual little computations, Dialogue: 0,1:10:40.08,1:10:44.15,EN,,0,0,0,,but about general conventional methods of doing things. Dialogue: 0,1:10:44.81,1:10:46.17,EN,,0,0,0,,OK, are there any questions? Dialogue: 0,1:10:46.75,1:10:52.27,EN,,0,0,0,,AUDIENCE: Yes. If we defined A using parentheses instead of as we did, Dialogue: 0,1:10:52.32,1:10:53.50,EN,,0,0,0,,what would be the difference? Dialogue: 0,1:10:53.60,1:10:56.88,EN,,0,0,0,,PROFESSOR: If I wrote this, if I wrote that, Dialogue: 0,1:10:57.53,1:11:02.13,EN,,0,0,0,,what I would be doing is defining a procedure named A. Dialogue: 0,1:11:03.21,1:11:06.85,EN,,0,0,0,,In this case, a procedure of no arguments, which, Dialogue: 0,1:11:06.85,1:11:09.61,EN,,0,0,0,,when I ran it, would give me back 5 times 5. Dialogue: 0,1:11:11.07,1:11:12.29,EN,,0,0,0,,AUDIENCE: Right. I mean, you come up with the same thing, Dialogue: 0,1:11:12.32,1:11:13.92,EN,,0,0,0,,except for you really got a different-- Dialogue: 0,1:11:14.05,1:11:16.63,EN,,0,0,0,,PROFESSOR: Right. And the difference would be, in the old one-- Dialogue: 0,1:11:17.02,1:11:18.35,EN,,0,0,0,,Let me be a little bit clearer here. Dialogue: 0,1:11:19.13,1:11:23.44,EN,,0,0,0,,Let's call this A, like here. Dialogue: 0,1:11:24.13,1:11:27.76,EN,,0,0,0,,And pretend here, just for contrast, I wrote, Dialogue: 0,1:11:27.79,1:11:37.56,EN,,0,0,0,,define D to be the product of 5 and 5. Dialogue: 0,1:11:40.22,1:11:41.57,EN,,0,0,0,,And the difference between those, Dialogue: 0,1:11:41.96,1:11:44.24,EN,,0,0,0,,let's think about interactions with the Lisp interpreter. Dialogue: 0,1:11:45.74,1:11:49.13,EN,,0,0,0,,I could type in A and Lisp would return 25. Dialogue: 0,1:11:52.83,1:11:57.81,EN,,0,0,0,,I could type in D, if I just typed in D, Dialogue: 0,1:11:58.49,1:12:05.55,EN,,0,0,0,,Lisp would return compound procedure D, Dialogue: 0,1:12:07.12,1:12:09.13,EN,,0,0,0,,because that's what it is. It's a procedure. Dialogue: 0,1:12:09.69,1:12:12.59,EN,,0,0,0,,I could run D. I could say, what's the value of running D? Dialogue: 0,1:12:12.59,1:12:15.23,EN,,0,0,0,,Here is a combination with no operands. Dialogue: 0,1:12:16.45,1:12:19.07,EN,,0,0,0,,I see there are no operands. I didn't put any after D. Dialogue: 0,1:12:19.39,1:12:21.34,EN,,0,0,0,,And it would say, oh, that's 25. Dialogue: 0,1:12:23.01,1:12:29.52,EN,,0,0,0,,Or I could say, just for completeness, if I typed in, what's the value of running A? Dialogue: 0,1:12:29.54,1:12:30.57,EN,,0,0,0,,I get an error. Dialogue: 0,1:12:31.79,1:12:35.29,EN,,0,0,0,,The error would be the same one as over there. Dialogue: 0,1:12:35.33,1:12:40.51,EN,,0,0,0,,It'd be the error would say, sorry, 25, which is the value of A, Dialogue: 0,1:12:40.56,1:12:43.24,EN,,0,0,0,,is not an operator that I can apply to something. Dialogue: 0,0:00:00.01,0:00:03.77,Declare,,0,0,0,,{\fad(200,200)}哈尔滨工业大学 IBM技术中心 Dialogue: 0,0:00:00.01,0:00:03.77,Declare,,0,0,0,,{\fad(200,200)\an2}倾情制作 Dialogue: 0,0:00:04.08,0:00:11.36,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:04.08,0:00:11.05,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}字幕&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.08,0:00:11.05,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}后期&特效\N蔡钟毓\N(JohnTitor) Dialogue: 0,0:00:04.08,0:00:11.06,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N匿名 Dialogue: 0,0:00:04.08,0:00:11.06,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:14.71,0:00:17.89,Default,,0,0,0,,欢迎大家来一起学习这门计算机科学的基础课程 Dialogue: 0,0:00:28.40,0:00:29.85,Default,,0,0,0,,事实上 以这样的方式来表述并不恰当 Dialogue: 0,0:00:29.85,0:00:32.34,Default,,0,0,0,,于此来说 计算机科学是个糟糕的名字 Dialogue: 0,0:00:32.83,0:00:34.30,Default,,0,0,0,,首先 它不算是一门科学 Dialogue: 0,0:00:35.92,0:00:39.47,Default,,0,0,0,,它更应该被称为工程或者是艺术 Dialogue: 0,0:00:40.09,0:00:42.91,Default,,0,0,0,,但我们实际上会发现 这个所谓的计算机科学 Dialogue: 0,0:00:42.93,0:00:44.97,Default,,0,0,0,,却与魔法一样的有众多神奇之处 Dialogue: 0,0:00:45.01,0:00:46.35,Default,,0,0,0,,这些将会在课程中一一体现 Dialogue: 0,0:00:47.28,0:00:48.22,Default,,0,0,0,,所以 不能称其为一门科学 Dialogue: 0,0:00:49.09,0:00:52.30,Default,,0,0,0,,这门学科和“计算机”也并非紧密相关 Dialogue: 0,0:00:53.39,0:00:55.47,Default,,0,0,0,,类似的 就像我们说 Dialogue: 0,0:00:55.47,0:01:00.05,Default,,0,0,0,,物理学中并不仅仅有关粒子加速器 Dialogue: 0,0:01:00.80,0:01:05.58,Default,,0,0,0,,生物学中并不全然是显微镜和培养皿一样 Dialogue: 0,0:01:06.46,0:01:10.25,Default,,0,0,0,,同理 Dialogue: 0,0:01:10.31,0:01:14.88,Default,,0,0,0,,几何学中也并不全是介绍如何使用测量仪器 Dialogue: 0,0:01:16.48,0:01:19.01,Default,,0,0,0,,事实上 计算机科学和几何学 Dialogue: 0,0:01:19.33,0:01:21.45,Default,,0,0,0,,有很多共性 Dialogue: 0,0:01:21.45,0:01:22.66,Default,,0,0,0,,首先 几何学 Dialogue: 0,0:01:23.02,0:01:24.98,Default,,0,0,0,,只是另一个有个糟糕名字的学科 Dialogue: 0,0:01:25.58,0:01:27.85,Default,,0,0,0,,这个名字来自于Gaia 意为土地 Dialogue: 0,0:01:27.90,0:01:29.09,Default,,0,0,0,,以及metron 意为测量 Dialogue: 0,0:01:29.82,0:01:33.39,Default,,0,0,0,,几何学最初意为测地或者勘探 Dialogue: 0,0:01:34.37,0:01:36.89,Default,,0,0,0,,这是因为数千年前的埃及祭司 Dialogue: 0,0:01:37.69,0:01:41.69,Default,,0,0,0,,为了计算如何去修复年年被尼罗河的洪水 Dialogue: 0,0:01:42.59,0:01:46.33,Default,,0,0,0,,所毁坏的牧田边界 Dialogue: 0,0:01:46.35,0:01:48.69,Default,,0,0,0,,而建立了几何学基础 Dialogue: 0,0:01:49.47,0:01:50.65,Default,,0,0,0,,而对出于这个目的的埃及人来说 Dialogue: 0,0:01:50.65,0:01:53.93,Default,,0,0,0,,几何学的确是掌握对测量仪器的使用 Dialogue: 0,0:01:55.63,0:01:58.55,Default,,0,0,0,,现在 我们以为计算机科学就是介绍计算机的使用 Dialogue: 0,0:01:58.57,0:02:02.49,Default,,0,0,0,,就正如埃及人认为 Dialogue: 0,0:02:02.51,0:02:04.10,Default,,0,0,0,,几何学是介绍如何使用测量仪器的 Dialogue: 0,0:02:04.59,0:02:07.37,Default,,0,0,0,,换句话说 任何一门学科起步的时候 Dialogue: 0,0:02:07.39,0:02:09.86,Default,,0,0,0,,你都对它了解不深 Dialogue: 0,0:02:11.10,0:02:16.64,Default,,0,0,0,,这很容易使你混淆所做的事与所用之物 Dialogue: 0,0:02:17.65,0:02:20.30,Default,,0,0,0,,确实 就绝对规模来说 Dialogue: 0,0:02:20.30,0:02:24.82,Default,,0,0,0,,我们对计算机科学的实质的了解 Dialogue: 0,0:02:24.83,0:02:27.49,Default,,0,0,0,,比埃及人对几何学的了解还少 Dialogue: 0,0:02:30.25,0:02:32.64,Default,,0,0,0,,那么 我所谓的计算机科学的本质是什么呢 Dialogue: 0,0:02:32.65,0:02:34.41,Default,,0,0,0,,我所谓的几何学本质又是什么呢 Dialogue: 0,0:02:34.41,0:02:36.45,Default,,0,0,0,,看 可以确认的是 古埃及人确实使用测量仪器 Dialogue: 0,0:02:36.46,0:02:37.67,Default,,0,0,0,,并且已经消失多年 Dialogue: 0,0:02:37.69,0:02:41.55,Default,,0,0,0,,但当我们在几千年后回过头来重新审视这段历史 Dialogue: 0,0:02:41.57,0:02:41.85,Default,,0,0,0,,我们会说 Dialogue: 0,0:02:41.87,0:02:43.64,Default,,0,0,0,,天啊 看他们在做什么 Dialogue: 0,0:02:43.71,0:02:45.48,Default,,0,0,0,,他们的工作是多么的重要 Dialogue: 0,0:02:45.62,0:02:50.45,Default,,0,0,0,,已经开始对时间和空间进行形式化表述 Dialogue: 0,0:02:51.58,0:02:57.53,Default,,0,0,0,,并归纳出一套讨论数学真理的形式化方法 Dialogue: 0,0:02:58.01,0:02:59.61,Default,,0,0,0,,这直接导致了公理化方法 Dialogue: 0,0:02:59.61,0:03:02.53,Default,,0,0,0,,以及各种现代数学的产生 Dialogue: 0,0:03:04.16,0:03:06.90,Default,,0,0,0,,同时也指明了一种精确讨论 Dialogue: 0,0:03:07.25,0:03:10.19,Default,,0,0,0,,所谓的描述真理的陈述性知识的方法 Dialogue: 0,0:03:12.45,0:03:16.25,Default,,0,0,0,,与此相似的 我认为未来人们会回过头来审视并说 Dialogue: 0,0:03:16.27,0:03:19.36,Default,,0,0,0,,啊 这些20世纪的原始人 Dialogue: 0,0:03:19.36,0:03:21.20,Default,,0,0,0,,不务正业地玩弄着叫计算机的小玩意 Dialogue: 0,0:03:21.77,0:03:26.25,Default,,0,0,0,,但它们真正在做的是开始学习 Dialogue: 0,0:03:26.25,0:03:32.55,Default,,0,0,0,,如何去对计算过程进行形式化表述 Dialogue: 0,0:03:32.64,0:03:34.13,Default,,0,0,0,,如何去解决问题 Dialogue: 0,0:03:39.02,0:03:51.25,Default,,0,0,0,,并结合两者发展一套对问题处理过程精确表述的方法 Dialogue: 0,0:03:51.76,0:03:56.03,Default,,0,0,0,,这与讨论真理的几何学形成了对照 Dialogue: 0,0:03:56.53,0:03:58.57,Default,,0,0,0,,让我给你们举个例子吧 Dialogue: 0,0:04:02.30,0:04:02.69,Default,,0,0,0,,来瞧瞧 Dialogue: 0,0:04:02.70,0:04:09.82,Default,,0,0,0,,数学中是这样来定义平方根的: Dialogue: 0,0:04:10.09,0:04:14.35,Default,,0,0,0,,定义X的平方根Y是这样一个数 Dialogue: 0,0:04:15.98,0:04:20.38,Default,,0,0,0,,Y的平方等于X 且Y大于等于0 Dialogue: 0,0:04:20.43,0:04:22.50,Default,,0,0,0,,这是一个很好的定义 Dialogue: 0,0:04:22.88,0:04:25.25,Default,,0,0,0,,但它只告诉了你平方根是什么 Dialogue: 0,0:04:25.63,0:04:30.29,Default,,0,0,0,,却没有告诉你如何去求取一个平方根 Dialogue: 0,0:04:31.42,0:04:35.90,Default,,0,0,0,,那么我们将其与一条指令性知识做比较 Dialogue: 0,0:04:37.13,0:04:39.92,Default,,0,0,0,,你如何去求取一个平方根 Dialogue: 0,0:04:39.95,0:04:45.74,Default,,0,0,0,,事实上 这来自于埃及 不太久远的埃及 Dialogue: 0,0:04:45.76,0:04:48.88,Default,,0,0,0,,亚历山大的Heron提出的一个算法 Dialogue: 0,0:04:49.90,0:04:52.77,Default,,0,0,0,,称作连续取均值求平方根法 Dialogue: 0,0:04:52.89,0:04:55.13,Default,,0,0,0,,这个算法是说 Dialogue: 0,0:04:55.15,0:04:58.06,Default,,0,0,0,,为了算出平方根 Dialogue: 0,0:05:03.34,0:05:08.33,Default,,0,0,0,,首先你应该给出一个猜测值guess 并不断改进 Dialogue: 0,0:05:10.19,0:05:11.44,Default,,0,0,0,,改进的方法是通过 Dialogue: 0,0:05:11.45,0:05:13.95,Default,,0,0,0,,不断求猜测值guess与X/guess的平均值 Dialogue: 0,0:05:14.41,0:05:15.60,Default,,0,0,0,,我们稍后将会讨论 Dialogue: 0,0:05:15.61,0:05:17.12,Default,,0,0,0,,为什么这是合理的 Dialogue: 0,0:05:17.14,0:05:19.37,Default,,0,0,0,,通过不断改进 直到它足够精确 Dialogue: 0,0:05:19.73,0:05:20.85,Default,,0,0,0,,这就是实现方法 Dialogue: 0,0:05:20.99,0:05:24.65,Default,,0,0,0,,这也是如何完成一项工作与 Dialogue: 0,0:05:24.72,0:05:27.33,Default,,0,0,0,,其对应的陈述性知识的对照 Dialogue: 0,0:05:28.05,0:05:29.76,Default,,0,0,0,,这就是一个过程 Dialogue: 0,0:05:34.40,0:05:38.25,Default,,0,0,0,,那么 通常来说什么是过程呢? Dialogue: 0,0:05:39.01,0:05:40.14,Default,,0,0,0,,这定义起来非常困难 Dialogue: 0,0:05:40.16,0:05:43.72,Default,,0,0,0,,你可以将它象征性地看成一个活在计算机内 Dialogue: 0,0:05:44.77,0:05:47.33,Default,,0,0,0,,并且可以完成一些操作的精灵 Dialogue: 0,0:05:48.01,0:05:54.11,Default,,0,0,0,,一些被称为程序的规则模式 Dialogue: 0,0:05:54.13,0:05:57.98,Default,,0,0,0,,指导着这类过程的进行 Dialogue: 0,0:06:01.98,0:06:04.73,Default,,0,0,0,,程序可以被认为是符咒 Dialogue: 0,0:06:05.23,0:06:09.40,Default,,0,0,0,,使用程序来控制这些精灵完成一些操作就叫做过程 Dialogue: 0,0:06:10.75,0:06:12.75,Default,,0,0,0,,你们知道人人都需要一门魔法语言 Dialogue: 0,0:06:12.77,0:06:14.55,Default,,0,0,0,,那些魔术师 真正的魔术师 用远古的阿卡狄亚语 Dialogue: 0,0:06:14.57,0:06:18.59,Default,,0,0,0,,或者苏美尔语 或者巴比伦语 或者其它的 Dialogue: 0,0:06:18.62,0:06:20.09,Default,,0,0,0,,而我们将用一门叫Lisp的魔法语言 Dialogue: 0,0:06:20.13,0:06:22.71,Default,,0,0,0,,来召唤出我们的精灵 Dialogue: 0,0:06:24.37,0:06:28.01,Default,,0,0,0,,这门语言是被设计用来 Dialogue: 0,0:06:28.57,0:06:31.84,Default,,0,0,0,,编写如咒语般的程序 来指导过程的进行 Dialogue: 0,0:06:31.87,0:06:33.91,Default,,0,0,0,,学习Lisp非常容易 Dialogue: 0,0:06:33.97,0:06:35.98,Default,,0,0,0,,事实上 我会在几分钟内教会你 Dialogue: 0,0:06:36.00,0:06:37.16,Default,,0,0,0,,整个Lisp Dialogue: 0,0:06:37.37,0:06:38.96,Default,,0,0,0,,及其所有的规则 Dialogue: 0,0:06:40.77,0:06:43.65,Default,,0,0,0,,你不必感到很惊讶 Dialogue: 0,0:06:43.69,0:06:45.87,Default,,0,0,0,,这就像你在学习象棋时 Dialogue: 0,0:06:45.90,0:06:47.01,Default,,0,0,0,,认为象棋的规则十分简单一样 Dialogue: 0,0:06:47.04,0:06:48.13,Default,,0,0,0,,事实也如此 几分钟内 Dialogue: 0,0:06:48.17,0:06:49.70,Default,,0,0,0,,你可以与任何人谈论象棋的规则 Dialogue: 0,0:06:50.81,0:06:52.24,Default,,0,0,0,,但是 这全然不等同于说 Dialogue: 0,0:06:52.25,0:06:55.37,Default,,0,0,0,,你所知道这些规则所蕴含的东西 Dialogue: 0,0:06:55.42,0:06:58.05,Default,,0,0,0,,以及如何利用这些规则去成为象棋大师 Dialogue: 0,0:06:58.49,0:06:59.82,Default,,0,0,0,,Lisp也是如此 Dialogue: 0,0:07:00.41,0:07:02.18,Default,,0,0,0,,我将在几分钟内道清规则 Dialogue: 0,0:07:02.36,0:07:03.55,Default,,0,0,0,,这说起来非常容易 Dialogue: 0,0:07:03.62,0:07:07.09,Default,,0,0,0,,但真正困难的是如何运用这些规则 Dialogue: 0,0:07:07.32,0:07:10.46,Default,,0,0,0,,以及你如何利用这些规则成为编程大师 Dialogue: 0,0:07:12.06,0:07:15.29,Default,,0,0,0,,这些规则的应用将占据我们 Dialogue: 0,0:07:15.31,0:07:18.56,Default,,0,0,0,,余下的课程 甚至更多 Dialogue: 0,0:07:21.45,0:07:23.11,Default,,0,0,0,,所以 在计算机科学中 Dialogue: 0,0:07:24.49,0:07:26.19,Default,,0,0,0,,我们的任务则是 Dialogue: 0,0:07:26.21,0:07:30.58,Default,,0,0,0,,形式化这种如有关“怎么做”的指令性知识 Dialogue: 0,0:07:30.62,0:07:32.10,Default,,0,0,0,,并将之付诸实际 Dialogue: 0,0:07:33.37,0:07:35.39,Default,,0,0,0,,这也便是计算机科学的真正的议题 Dialogue: 0,0:07:35.41,0:07:38.36,Default,,0,0,0,,当然 并不是告诉人们如何去求平方根 Dialogue: 0,0:07:39.09,0:07:40.06,Default,,0,0,0,,因为如果那是计算机科学的全部的的话 Dialogue: 0,0:07:40.09,0:07:41.34,Default,,0,0,0,,就不会有什么大问题了 Dialogue: 0,0:07:41.57,0:07:44.05,Default,,0,0,0,,真正的问题来自于当我们尝试 Dialogue: 0,0:07:44.08,0:07:46.16,Default,,0,0,0,,构建非常非常大的系统时 Dialogue: 0,0:07:46.61,0:07:49.53,Default,,0,0,0,,程序可能会长达数千页 Dialogue: 0,0:07:49.58,0:07:53.98,Default,,0,0,0,,长得没有人能马上将其装入脑中 Dialogue: 0,0:07:54.73,0:07:58.81,Default,,0,0,0,,而使这些得以实现则是因为 Dialogue: 0,0:07:58.86,0:08:18.97,Default,,0,0,0,,我们有在大系统中控制复杂度的技术 Dialogue: 0,0:08:20.30,0:08:22.69,Default,,0,0,0,,这些控制复杂度的技术 Dialogue: 0,0:08:22.72,0:08:24.17,Default,,0,0,0,,正是我们课程所讨论的 Dialogue: 0,0:08:24.65,0:08:25.47,Default,,0,0,0,,从某种意义上来说 Dialogue: 0,0:08:25.50,0:08:27.47,Default,,0,0,0,,这也正是计算机科学的关键所在 Dialogue: 0,0:08:29.63,0:08:31.89,Default,,0,0,0,,这样说听起来或许很奇怪 Dialogue: 0,0:08:31.92,0:08:35.61,Default,,0,0,0,,毕竟 除了计算机科学家外 Dialogue: 0,0:08:35.65,0:08:37.82,Default,,0,0,0,,仍然有很多人在做复杂度控制相关的工作 Dialogue: 0,0:08:37.84,0:08:41.02,Default,,0,0,0,,一个航班就是一个非常复杂的系统 Dialogue: 0,0:08:41.82,0:08:43.79,Default,,0,0,0,,设计它的航空工程师 Dialogue: 0,0:08:44.05,0:08:46.13,Default,,0,0,0,,便在处理这个巨大的复杂度 Dialogue: 0,0:08:47.09,0:08:50.19,Default,,0,0,0,,但这种复杂度又与 Dialogue: 0,0:08:50.75,0:08:52.60,Default,,0,0,0,,计算机科学中的(复杂度)有别 Dialogue: 0,0:08:55.18,0:08:57.73,Default,,0,0,0,,从某种意义上来说 Dialogue: 0,0:08:57.79,0:09:00.09,Default,,0,0,0,,因为计算机科学不是“现实”的 Dialogue: 0,0:09:02.69,0:09:06.62,Default,,0,0,0,,例如 当一名工程师设计物理系统时 Dialogue: 0,0:09:07.14,0:09:08.49,Default,,0,0,0,,这些都是由实在的物理部件构成 Dialogue: 0,0:09:09.40,0:09:11.18,Default,,0,0,0,,负责的该工作的工程师 Dialogue: 0,0:09:11.85,0:09:16.65,Default,,0,0,0,,就得对付系统中的公差、近似值以及噪声 Dialogue: 0,0:09:16.67,0:09:19.02,Default,,0,0,0,,譬如说 作为一名电气工程师 Dialogue: 0,0:09:19.09,0:09:21.71,Default,,0,0,0,,可以很容易的做一个单极放大器 Dialogue: 0,0:09:21.73,0:09:23.03,Default,,0,0,0,,或者是一个双极放大器 Dialogue: 0,0:09:23.41,0:09:25.39,Default,,0,0,0,,也可想象将其大量串联 Dialogue: 0,0:09:25.45,0:09:26.91,Default,,0,0,0,,来建造一个百万极的放大器 Dialogue: 0,0:09:26.99,0:09:28.75,Default,,0,0,0,,但这样做是不可行的 Dialogue: 0,0:09:28.98,0:09:32.15,Default,,0,0,0,,因为在远没到百万数量级的时候 Dialogue: 0,0:09:32.16,0:09:34.56,Default,,0,0,0,,这种组合方法打从头产生的热噪声 Dialogue: 0,0:09:34.57,0:09:36.80,Default,,0,0,0,,会慢慢增强 并使得我们的幸苦付之一炬 Dialogue: 0,0:09:39.10,0:09:43.12,Default,,0,0,0,,计算机科学处理的是理想化组件 Dialogue: 0,0:09:44.12,0:09:47.63,Default,,0,0,0,,我们对将要结合在一起的 Dialogue: 0,0:09:47.65,0:09:49.56,Default,,0,0,0,,程序和数据了如指掌 Dialogue: 0,0:09:51.90,0:09:53.20,Default,,0,0,0,,我们不需要去关心公差 Dialogue: 0,0:09:53.21,0:09:56.99,Default,,0,0,0,,也就是说 在构建大系统时 Dialogue: 0,0:09:58.13,0:10:00.03,Default,,0,0,0,,在我理想和现实之间 Dialogue: 0,0:10:00.35,0:10:04.18,Default,,0,0,0,,并不没有太大的不同 Dialogue: 0,0:10:05.53,0:10:07.60,Default,,0,0,0,,因为这些部分都是抽象单元 Dialogue: 0,0:10:07.63,0:10:10.32,Default,,0,0,0,,可以随心所欲的组合 Dialogue: 0,0:10:10.33,0:10:12.39,Default,,0,0,0,,可以据目前所知而自由构建 Dialogue: 0,0:10:13.45,0:10:15.50,Default,,0,0,0,,就是与其它的工程不同之处 Dialogue: 0,0:10:15.66,0:10:17.42,Default,,0,0,0,,(在其它的工程中)对你所构建系统的约束 Dialogue: 0,0:10:17.44,0:10:18.90,Default,,0,0,0,,来自于物理系统以及 Dialogue: 0,0:10:18.94,0:10:21.02,Default,,0,0,0,,物理定律 噪声 近似值等 Dialogue: 0,0:10:21.21,0:10:25.60,Default,,0,0,0,,而建立大型软件系统时所施加的约束 Dialogue: 0,0:10:25.64,0:10:27.58,Default,,0,0,0,,就是对我们大脑的限制 Dialogue: 0,0:10:29.12,0:10:29.98,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:10:30.00,0:10:33.67,Default,,0,0,0,,计算机科学就像是工程中的一种抽象形式 Dialogue: 0,0:10:33.80,0:10:35.73,Default,,0,0,0,,在这种工程中 我们忽略 Dialogue: 0,0:10:35.76,0:10:38.02,Default,,0,0,0,,现实所施加的约束 Dialogue: 0,0:10:41.97,0:10:46.15,Default,,0,0,0,,那么 这其中有哪些技术呢 Dialogue: 0,0:10:46.28,0:10:48.39,Default,,0,0,0,,计算机科学中并没有特别的技术 Dialogue: 0,0:10:50.39,0:10:52.55,Default,,0,0,0,,第一个技术是在很多工程中都使用的 Dialogue: 0,0:10:53.36,0:10:58.91,Default,,0,0,0,,被称为“黑盒抽象”的方法 Dialogue: 0,0:11:07.71,0:11:12.58,Default,,0,0,0,,即将一些东西组合并封装起来 Dialogue: 0,0:11:14.37,0:11:20.09,Default,,0,0,0,,以之前我们提到的求取平方根的方法为例 Dialogue: 0,0:11:22.64,0:11:28.53,Default,,0,0,0,,我将这些操作视为一个“盒子” Dialogue: 0,0:11:29.89,0:11:37.52,Default,,0,0,0,,也就是说 为了找到X的平方根 Dialogue: 0,0:11:38.86,0:11:41.27,Default,,0,0,0,,或许会有一系列的复杂规则 Dialogue: 0,0:11:42.64,0:11:46.69,Default,,0,0,0,,我们将规则封装 输入数据即可获得结果 Dialogue: 0,0:11:46.81,0:11:50.06,Default,,0,0,0,,比如说 输入36 然后说36的平方根是多少呢 Dialogue: 0,0:11:50.25,0:11:51.46,Default,,0,0,0,,则给出结果 6 Dialogue: 0,0:11:53.89,0:11:56.22,Default,,0,0,0,,重点是 Dialogue: 0,0:11:56.24,0:12:00.03,Default,,0,0,0,,通过这样的设计 Dialogue: 0,0:12:00.06,0:12:04.08,Default,,0,0,0,,可以方便他人的使用 Dialogue: 0,0:12:05.10,0:12:09.37,Default,,0,0,0,,例如Goerge想计算A的平方根加上B的平方根 Dialogue: 0,0:12:11.34,0:12:14.38,Default,,0,0,0,,他无需了解“盒子”内部的构成 Dialogue: 0,0:12:14.43,0:12:15.74,Default,,0,0,0,,而直接可以以模块的形式使用它 Dialogue: 0,0:12:15.77,0:12:17.31,Default,,0,0,0,,也可以利用它去构建新的“盒子” Dialogue: 0,0:12:18.45,0:12:24.20,Default,,0,0,0,,例如构建一个 A和B以及一个平方根和或者另一个平方根盒子 Dialogue: 0,0:12:24.53,0:12:33.87,Default,,0,0,0,,然后将这些结果加在一起并输出答案 Dialogue: 0,0:12:33.96,0:12:38.15,Default,,0,0,0,,如你所见 就我想实现的功能的层面来看 Dialogue: 0,0:12:38.92,0:12:40.42,Default,,0,0,0,,对于George来说 Dialogue: 0,0:12:40.51,0:12:43.10,Default,,0,0,0,,盒子内部是什么样并不重要 Dialogue: 0,0:12:44.19,0:12:47.25,Default,,0,0,0,,例如 以下这些说法都没什么问题 Dialogue: 0,0:12:47.27,0:12:50.43,Default,,0,0,0,,我说求X的平方根 Dialogue: 0,0:12:50.61,0:12:52.27,Default,,0,0,0,,也可以说计算Y的平方根 Dialogue: 0,0:12:52.72,0:12:55.62,Default,,0,0,0,,或者其它任何数的平方根 Dialogue: 0,0:12:56.70,0:13:02.35,Default,,0,0,0,,黑盒抽象的基本规则是 Dialogue: 0,0:13:03.53,0:13:06.44,Default,,0,0,0,,将处理过程放入盒子里以隐藏细节 Dialogue: 0,0:13:07.60,0:13:10.99,Default,,0,0,0,,这样做的原因则是你可以脱身去构建更大的盒子 Dialogue: 0,0:13:12.05,0:13:14.57,Default,,0,0,0,,现在 除了隐藏细节外 Dialogue: 0,0:13:14.59,0:13:18.41,Default,,0,0,0,,使用黑盒抽象还有另外一个原因 Dialogue: 0,0:13:18.48,0:13:25.02,Default,,0,0,0,,有的时候 你想要用你的方法去完成一件事 Dialogue: 0,0:13:25.04,0:13:26.88,Default,,0,0,0,,你的方法 Dialogue: 0,0:13:28.44,0:13:30.79,Default,,0,0,0,,就是一个通法的具体实例 Dialogue: 0,0:13:31.16,0:13:34.57,Default,,0,0,0,,同时 你也希望你的表述方式能够具有普遍性 Dialogue: 0,0:13:35.57,0:13:37.93,Default,,0,0,0,,我们接着用实例来说明 Dialogue: 0,0:13:37.97,0:13:38.86,Default,,0,0,0,,继续刚才关于平方根的讨论 Dialogue: 0,0:13:38.89,0:13:42.16,Default,,0,0,0,,让我们回过头再来看看 Dialogue: 0,0:13:42.19,0:13:43.75,Default,,0,0,0,,求平方根的算法 Dialogue: 0,0:13:44.16,0:13:45.62,Default,,0,0,0,,想一想之前是怎么说的 Dialogue: 0,0:13:45.79,0:13:49.82,Default,,0,0,0,,为了求解 首先要作出猜测 Dialogue: 0,0:13:50.62,0:13:54.84,Default,,0,0,0,,然后基于这个猜测 做出持续不断的改进 Dialogue: 0,0:13:55.66,0:14:00.14,Default,,0,0,0,,因此就存在一个找到某个到结果的通用方法 Dialogue: 0,0:14:01.15,0:14:04.00,Default,,0,0,0,,就是持续不断地改进结果 Dialogue: 0,0:14:04.16,0:14:10.25,Default,,0,0,0,,求取不动点的方法有很多 Dialogue: 0,0:14:10.97,0:14:13.23,Default,,0,0,0,,这种方法只是其中的一个特例 Dialogue: 0,0:14:14.57,0:14:16.59,Default,,0,0,0,,每个函数都有一个不动点 Dialogue: 0,0:14:17.13,0:14:26.03,Default,,0,0,0,,函数的不动点是一个值 Dialogue: 0,0:14:26.13,0:14:31.79,Default,,0,0,0,,F的不动点Y满足F(Y)=Y Dialogue: 0,0:14:32.97,0:14:40.89,Default,,0,0,0,,首先要做是做出一个猜测 Dialogue: 0,0:14:42.00,0:14:45.85,Default,,0,0,0,,在迭代函数F时不会改变的东西则是我们所求的结果 Dialogue: 0,0:14:45.96,0:14:49.45,Default,,0,0,0,,我会不断迭代函数F直到结果不会有很大改变 Dialogue: 0,0:14:50.05,0:14:51.93,Default,,0,0,0,,这就是一个通法 Dialogue: 0,0:14:52.24,0:14:56.17,Default,,0,0,0,,因此 为了计算X的平方根 Dialogue: 0,0:14:56.24,0:15:03.45,Default,,0,0,0,,我可以试着找到Y与X/Y的平均值函数的不动点 Dialogue: 0,0:15:03.55,0:15:07.52,Default,,0,0,0,,因为如果我真有一个等于X平方根的Y Dialogue: 0,0:15:08.01,0:15:11.80,Default,,0,0,0,,那么Y和X/Y应为同一值 Dialogue: 0,0:15:12.00,0:15:13.90,Default,,0,0,0,,它们俩都是X的平方根 Dialogue: 0,0:15:14.86,0:15:18.85,Default,,0,0,0,,因为X除根号X得根号X Dialogue: 0,0:15:19.09,0:15:21.84,Default,,0,0,0,,如果平均值Y等于X的平方根 Dialogue: 0,0:15:22.25,0:15:25.21,Default,,0,0,0,,那么这个平均值就不会改变 Dialogue: 0,0:15:25.98,0:15:28.93,Default,,0,0,0,,因此X的平方根即是某一特定函数的不动点 Dialogue: 0,0:15:30.09,0:15:33.85,Default,,0,0,0,,现在 我将要描述 Dialogue: 0,0:15:33.98,0:15:36.42,Default,,0,0,0,,寻找不动点的通法 Dialogue: 0,0:15:36.57,0:15:40.13,Default,,0,0,0,,我所希望做的就是 Dialogue: 0,0:15:41.02,0:15:46.45,Default,,0,0,0,,用我自己的语言定义一个可以获得不动点的“盒子” Dialogue: 0,0:15:49.58,0:15:52.19,Default,,0,0,0,,正如我可以定义一个输出平方根的盒子一样 Dialogue: 0,0:15:52.21,0:15:55.18,Default,,0,0,0,,我想要用自己的语言来表述 Dialogue: 0,0:15:56.08,0:16:01.37,Default,,0,0,0,,因此 对于这种“怎么做”的指令性知识 Dialogue: 0,0:16:01.42,0:16:03.21,Default,,0,0,0,,我不仅是想表达具体应该如何求平方根 Dialogue: 0,0:16:03.58,0:16:05.60,Default,,0,0,0,,我也希望能够表述更加通用问题 Dialogue: 0,0:16:05.66,0:16:08.27,Default,,0,0,0,,例如 怎么求取不动点 Dialogue: 0,0:16:09.82,0:16:12.25,Default,,0,0,0,,让我们再回过头来看看之前的幻灯片 Dialogue: 0,0:16:15.02,0:16:23.28,Default,,0,0,0,,不但如何去求取一个不动点 Dialogue: 0,0:16:23.33,0:16:25.32,Default,,0,0,0,,是一种指令性知识 Dialogue: 0,0:16:26.25,0:16:27.39,Default,,0,0,0,,在这下面 这里 Dialogue: 0,0:16:27.42,0:16:30.32,Default,,0,0,0,,这儿还有另一种指令性知识 说的是 Dialogue: 0,0:16:30.41,0:16:35.85,Default,,0,0,0,,计算平方根的一种方法就是应用找不动点的方法 Dialogue: 0,0:16:36.17,0:16:38.89,Default,,0,0,0,,如果 也想要表述这种指令性知识 Dialogue: 0,0:16:39.74,0:16:40.70,Default,,0,0,0,,那结果会是什么样呢? Dialogue: 0,0:16:40.73,0:16:44.90,Default,,0,0,0,,这个不动点盒子可能会是这样 Dialogue: 0,0:16:45.76,0:16:58.21,Default,,0,0,0,,如果我输入一个函数 该函数从Y映射到Y和X/Y的平均值 Dialogue: 0,0:16:59.77,0:17:06.23,Default,,0,0,0,,然后我们将会得到求不动点的盒子就是求平方根的一个方法 Dialogue: 0,0:17:08.91,0:17:10.24,Default,,0,0,0,,因此在这些我们构建的盒子中 Dialogue: 0,0:17:10.27,0:17:15.07,Default,,0,0,0,,输入和输出都不局限于数字 Dialogue: 0,0:17:16.40,0:17:18.54,Default,,0,0,0,,我们将要构建能够 Dialogue: 0,0:17:18.67,0:17:21.34,Default,,0,0,0,,找到平方根计算方法的盒子 Dialogue: 0,0:17:22.22,0:17:25.85,Default,,0,0,0,,我输入的是一个函数 Dialogue: 0,0:17:26.49,0:17:29.29,Default,,0,0,0,,比如Y映射到Y和X/Y的平均值的函数 Dialogue: 0,0:17:29.71,0:17:31.49,Default,,0,0,0,,我们之所以采用这种方式是希望 Dialogue: 0,0:17:32.21,0:17:35.60,Default,,0,0,0,,输入是一个过程 输出也是一个过程 Dialogue: 0,0:17:35.63,0:17:38.61,Default,,0,0,0,,如我们所见 一个过程输出了另一个过程 Dialogue: 0,0:17:39.31,0:17:41.10,Default,,0,0,0,,之所以这样做是因为 Dialogue: 0,0:17:41.52,0:17:46.27,Default,,0,0,0,,我们将通过程序来讨论指令性知识 Dialogue: 0,0:17:48.00,0:17:49.93,Default,,0,0,0,,这种处理方式很强大 Dialogue: 0,0:17:49.93,0:17:52.13,Default,,0,0,0,,我们将可以基于此来讨论其它类型的知识 Dialogue: 0,0:17:53.42,0:17:56.52,Default,,0,0,0,,实际上 我们讨论的是一种生成过程的过程 Dialogue: 0,0:17:57.10,0:18:00.34,Default,,0,0,0,,一种生成通法的通法 Dialogue: 0,0:18:03.57,0:18:08.24,Default,,0,0,0,,那么 我们将主要讨论三个主题的内容 Dialogue: 0,0:18:08.25,0:18:09.69,Default,,0,0,0,,而首个主题则是 Dialogue: 0,0:18:09.74,0:18:10.94,Default,,0,0,0,,黑盒抽象 Dialogue: 0,0:18:10.97,0:18:13.31,Default,,0,0,0,,让我们稍稍深入一点 Dialogue: 0,0:18:15.12,0:18:24.04,Default,,0,0,0,,我们将讨论 Dialogue: 0,0:18:24.08,0:18:26.72,Default,,0,0,0,,Lisp是如何通过基本对象建立起来的 Dialogue: 0,0:18:27.36,0:18:29.20,Default,,0,0,0,,以及Lisp的构成 Dialogue: 0,0:18:29.49,0:18:33.58,Default,,0,0,0,,接下来 将会涉及到一些基本过程和基础数据 Dialogue: 0,0:18:36.16,0:18:37.04,Default,,0,0,0,,然后我们将会看到 Dialogue: 0,0:18:37.05,0:18:38.77,Default,,0,0,0,,我们如何使用这些基本对象 Dialogue: 0,0:18:38.81,0:18:40.76,Default,,0,0,0,,并把它们组合起来构建更复杂的东西 Dialogue: 0,0:18:41.45,0:18:42.92,Default,,0,0,0,,及相应的组合方法 Dialogue: 0,0:18:43.20,0:18:46.30,Default,,0,0,0,,后续将讨论各种进行组合的方法以及 Dialogue: 0,0:18:46.45,0:18:50.48,Default,,0,0,0,,如何用基本过程来构建更复杂的过程 Dialogue: 0,0:18:50.96,0:18:54.43,Default,,0,0,0,,同时 我们也将看到如何将基本数据组合成复合数据 Dialogue: 0,0:18:56.21,0:18:59.34,Default,,0,0,0,,然后我们将会介绍如何对复合数据 Dialogue: 0,0:18:59.79,0:19:01.29,Default,,0,0,0,,如何将它们抽象出来 Dialogue: 0,0:19:02.91,0:19:04.97,Default,,0,0,0,,如何用黑盒对它们进行封装 Dialogue: 0,0:19:05.04,0:19:07.73,Default,,0,0,0,,使得你可以将它们作为组件用于更复杂的东西 Dialogue: 0,0:19:08.16,0:19:10.93,Default,,0,0,0,,我们会发现这些都是通过定义程序 Dialogue: 0,0:19:11.52,0:19:14.79,Default,,0,0,0,,以及一种处理复合数据的数据抽象技术完成的 Dialogue: 0,0:19:15.61,0:19:17.36,Default,,0,0,0,,最重要的是 Dialogue: 0,0:19:17.92,0:19:21.49,Default,,0,0,0,,我们可以从中了解到专家是如何工作的 Dialogue: 0,0:19:21.61,0:19:27.12,Default,,0,0,0,,对于找不动点的方法来讲 Dialogue: 0,0:19:27.15,0:19:28.64,Default,,0,0,0,,找平方根的方式是它的一个特例 Dialogue: 0,0:19:28.69,0:19:30.87,Default,,0,0,0,,你如何表述完成工作中所存在的通用模式呢? Dialogue: 0,0:19:31.90,0:19:34.41,Default,,0,0,0,,我们将会使用 Dialogue: 0,0:19:34.59,0:19:35.63,Default,,0,0,0,,之前已经提到过的 Dialogue: 0,0:19:35.66,0:19:37.30,Default,,0,0,0,,某种叫做高阶过程的东西 Dialogue: 0,0:19:37.34,0:19:42.05,Default,,0,0,0,,也就是说 它的输入、输出和它本身都是过程 Dialogue: 0,0:19:42.96,0:19:44.86,Default,,0,0,0,,我们将会看到一些有趣的东西 Dialogue: 0,0:19:44.86,0:19:48.49,Default,,0,0,0,,随着学习的深入 将会越发抽象 Dialogue: 0,0:19:48.80,0:19:50.31,Default,,0,0,0,,那么将会发现 Dialogue: 0,0:19:50.43,0:19:53.61,Default,,0,0,0,,我们认为是数据和我们认为是过程之间的 Dialogue: 0,0:19:53.63,0:19:57.80,Default,,0,0,0,,分界线将变得模糊到难以置信的程度 Dialogue: 0,0:20:02.89,0:20:07.12,Default,,0,0,0,,这便是我们的第一个主题 黑盒抽象 Dialogue: 0,0:20:07.12,0:20:08.62,Default,,0,0,0,,让我们来看看第二个主题 Dialogue: 0,0:20:11.10,0:20:13.88,Default,,0,0,0,,这样说吧 Dialogue: 0,0:20:13.89,0:20:18.09,Default,,0,0,0,,假设我想表达某个想法 Dialogue: 0,0:20:19.42,0:20:22.51,Default,,0,0,0,,请注意 我们讨论的是想法 Dialogue: 0,0:20:22.91,0:20:25.53,Default,,0,0,0,,比如说 Dialogue: 0,0:20:26.41,0:20:35.12,Default,,0,0,0,,我想将某个元素与另两个元素之和相乘 Dialogue: 0,0:20:36.09,0:20:37.93,Default,,0,0,0,,举例来说 Dialogue: 0,0:20:38.11,0:20:41.52,Default,,0,0,0,,我用1和3(之和)乘2 得8 Dialogue: 0,0:20:42.03,0:20:45.11,Default,,0,0,0,,但我这里想讨论的是关于线性组合的基本想法 Dialogue: 0,0:20:45.44,0:20:47.98,Default,,0,0,0,,是说你可以将两个元素的和乘以另一个元素 Dialogue: 0,0:20:49.28,0:20:51.01,Default,,0,0,0,,在数集内思考这个问题是很容易的 Dialogue: 0,0:20:51.05,0:20:55.41,Default,,0,0,0,,但假设我想将这个想法应用于 Dialogue: 0,0:20:56.08,0:20:58.58,Default,,0,0,0,,对两向量a1和a2相加 Dialogue: 0,0:20:59.89,0:21:03.26,Default,,0,0,0,,乘以某一因子x然后得到另一向量 Dialogue: 0,0:21:03.33,0:21:09.75,Default,,0,0,0,,我甚至可以说 若a1和a2皆为多项式 Dialogue: 0,0:21:11.07,0:21:13.90,Default,,0,0,0,,我想对这两个多项式求和 Dialogue: 0,0:21:13.92,0:21:16.86,Default,,0,0,0,,然后乘以2得到一个多项式 Dialogue: 0,0:21:20.16,0:21:23.83,Default,,0,0,0,,同理 a1或a2也可以是电信号 Dialogue: 0,0:21:24.56,0:21:27.77,Default,,0,0,0,,我想将二个信号加和 Dialogue: 0,0:21:27.81,0:21:30.27,Default,,0,0,0,,并将结果放入一个放大器 Dialogue: 0,0:21:30.28,0:21:33.03,Default,,0,0,0,,用一个类似于2的因子乘以它们 Dialogue: 0,0:21:33.82,0:21:36.93,Default,,0,0,0,,这种想法的基本点是 我希望用一个通用记号表示它们 Dialogue: 0,0:21:38.32,0:21:45.42,Default,,0,0,0,,假如我们的语言可以很好的表述这类想法 Dialogue: 0,0:21:47.07,0:21:49.31,Default,,0,0,0,,如果真可以这样的话 Dialogue: 0,0:21:50.65,0:21:52.09,Default,,0,0,0,,我将会以这样的方式表述 Dialogue: 0,0:21:54.99,0:22:00.41,Default,,0,0,0,,用x乘以a1和a2的和 Dialogue: 0,0:22:02.80,0:22:05.07,Default,,0,0,0,,更进一步 我希望做更抽象更基本的表述 Dialogue: 0,0:22:06.03,0:22:09.23,Default,,0,0,0,,使其可以适应各个不同类型的a1和a2 Dialogue: 0,0:22:10.03,0:22:11.58,Default,,0,0,0,,现在回过头来想想 似乎有点问题 Dialogue: 0,0:22:11.58,0:22:16.17,Default,,0,0,0,,毕竟 对两个数字和两个多项式进行加和运算 Dialogue: 0,0:22:16.21,0:22:18.33,Default,,0,0,0,,所用的基本操作 Dialogue: 0,0:22:18.38,0:22:22.98,Default,,0,0,0,,在机器内部显然是不同的 Dialogue: 0,0:22:23.29,0:22:27.49,Default,,0,0,0,,对两个电信号或声波加和也有同样的问题 Dialogue: 0,0:22:27.89,0:22:32.53,Default,,0,0,0,,无论怎样 对不同类型的元素进行求和运算 Dialogue: 0,0:22:32.87,0:22:34.25,Default,,0,0,0,,总是需要使用不同的方法 Dialogue: 0,0:22:37.09,0:22:38.64,Default,,0,0,0,,现在 为了构建这样一个系统 Dialogue: 0,0:22:38.78,0:22:40.67,Default,,0,0,0,,我们将如何使用这些知识呢? Dialogue: 0,0:22:41.20,0:22:44.41,Default,,0,0,0,,如何在各种方法中进行选择? Dialogue: 0,0:22:44.56,0:22:48.42,Default,,0,0,0,,而如果明天George又想出了一种新类型的对象 Dialogue: 0,0:22:48.45,0:22:50.32,Default,,0,0,0,,并将它用于加和以及乘积 Dialogue: 0,0:22:51.01,0:22:53.32,Default,,0,0,0,,我又该如何把这个新类型引入到系统中 Dialogue: 0,0:22:53.52,0:22:55.68,Default,,0,0,0,,而且能够做到不把已有的系统弄得一团糟? Dialogue: 0,0:22:57.81,0:23:00.54,Default,,0,0,0,,这便是我们的第二大主题 Dialogue: 0,0:23:00.57,0:23:03.16,Default,,0,0,0,,控制复杂度的方法 Dialogue: 0,0:23:03.84,0:23:08.43,Default,,0,0,0,,我们实现的方法是按照约定来实现相应的接口 Dialogue: 0,0:23:17.44,0:23:20.21,Default,,0,0,0,,并以此将各部分组合起来 Dialogue: 0,0:23:20.25,0:23:22.04,Default,,0,0,0,,就如同电气工程中 Dialogue: 0,0:23:22.94,0:23:25.39,Default,,0,0,0,,人们为连接器规定标准阻抗 Dialogue: 0,0:23:26.16,0:23:28.62,Default,,0,0,0,,如果用符合这个标准的东西来构建系统 Dialogue: 0,0:23:28.67,0:23:30.40,Default,,0,0,0,,你就知道你可以把各个部件组合在一起 Dialogue: 0,0:23:32.78,0:23:35.68,Default,,0,0,0,,这就是我们将要讨论的第二个主题:约定接口 Dialogue: 0,0:23:35.73,0:23:40.94,Default,,0,0,0,,如我之前提到的 Dialogue: 0,0:23:40.97,0:23:42.22,Default,,0,0,0,,接下来我们将讨论通用操作中的问题 Dialogue: 0,0:23:42.59,0:23:47.28,Default,,0,0,0,,例如对各种不同类型数据进行均适用的加法操作 Dialogue: 0,0:23:52.61,0:23:54.57,Default,,0,0,0,,随后则会讨论通用操作 Dialogue: 0,0:23:54.61,0:23:56.99,Default,,0,0,0,,然后我们将讨论大型架构问题 Dialogue: 0,0:23:58.32,0:24:00.83,Default,,0,0,0,,如果通过对现实世界的复杂系统建模 Dialogue: 0,0:24:01.02,0:24:04.89,Default,,0,0,0,,来构建大型程序 Dialogue: 0,0:24:05.53,0:24:06.53,Default,,0,0,0,,我们将看到 在构建这样的系统时 Dialogue: 0,0:24:06.57,0:24:11.81,Default,,0,0,0,,有两种非常重要的方法 Dialogue: 0,0:24:11.85,0:24:13.90,Default,,0,0,0,,其一是面向对象编程 Dialogue: 0,0:24:14.09,0:24:18.94,Default,,0,0,0,,在这种模式中 你把你的系统想象成一个社区 Dialogue: 0,0:24:19.37,0:24:22.36,Default,,0,0,0,,社区中的各个部分都是通过相互间传递消息联系起来的 Dialogue: 0,0:24:23.44,0:24:27.81,Default,,0,0,0,,其二是关于聚集的操作 称作“流” Dialogue: 0,0:24:27.98,0:24:31.50,Default,,0,0,0,,使用这种方式构建大型系统 Dialogue: 0,0:24:31.50,0:24:35.29,Default,,0,0,0,,类似于电气工程师构造大型电气系统 Dialogue: 0,0:24:38.93,0:24:40.49,Default,,0,0,0,,这就是我们的第二个话题 Dialogue: 0,0:24:43.37,0:24:45.93,Default,,0,0,0,,现在 我们将要讨论第三个话题 Dialogue: 0,0:24:45.95,0:24:49.70,Default,,0,0,0,,控制复杂度的第三个技术 Dialogue: 0,0:24:49.74,0:24:50.94,Default,,0,0,0,,便是定义新的语言 Dialogue: 0,0:24:51.69,0:24:55.42,Default,,0,0,0,,因为有时 当你有点受不了设计的复杂度时 Dialogue: 0,0:24:55.47,0:24:59.69,Default,,0,0,0,,你可以通过定义一门新的语言来控制系统复杂度 Dialogue: 0,0:25:01.41,0:25:05.60,Default,,0,0,0,,新语言的设计意图是为了强调系统的某个方面 Dialogue: 0,0:25:05.79,0:25:09.36,Default,,0,0,0,,它一方面隐藏了部分细节 另一方面则但强调一些其他的细节 Dialogue: 0,0:25:12.99,0:25:15.93,Default,,0,0,0,,这部分将是课程中最神奇的部分 Dialogue: 0,0:25:16.03,0:25:21.20,Default,,0,0,0,,我们将开始于构建新的计算机语言 Dialogue: 0,0:25:21.82,0:25:26.30,Default,,0,0,0,,实际上我们首先要完成的工作已经内建于Lisp之中了 Dialogue: 0,0:25:29.23,0:25:34.02,Default,,0,0,0,,我们将展现如何用Lisp来解释Lisp Dialogue: 0,0:25:34.29,0:25:36.94,Default,,0,0,0,,这是一个非常类似于自循环的过程 Dialogue: 0,0:25:36.96,0:25:39.92,Default,,0,0,0,,这与(Lisp中)一个神奇的符号有关 Dialogue: 0,0:25:40.97,0:25:46.38,Default,,0,0,0,,解释Lisp的步骤是 Dialogue: 0,0:25:46.57,0:25:47.71,Default,,0,0,0,,应用和求值——这两大步骤的轮转 Dialogue: 0,0:25:47.89,0:25:50.87,Default,,0,0,0,,这两者不断地互相交替进行 Dialogue: 0,0:25:52.54,0:25:54.24,Default,,0,0,0,,接下来 我们将看到其余神奇的东西 Dialogue: 0,0:25:54.25,0:25:56.85,Default,,0,0,0,,譬如另一种魔法符号 Dialogue: 0,0:25:57.12,0:26:01.52,Default,,0,0,0,,一种叫做Y运算符的东西 Dialogue: 0,0:26:01.55,0:26:06.45,Default,,0,0,0,,某种意义上 它在过程式语言中用于 表达无限 Dialogue: 0,0:26:06.51,0:26:07.44,Default,,0,0,0,,我们也会谈论到它 Dialogue: 0,0:26:08.40,0:26:13.73,Default,,0,0,0,,总之 这部分课程被称作“元语言抽象” Dialogue: 0,0:26:16.17,0:26:26.23,Default,,0,0,0,,主要讨论如何构建一门新语言 Dialogue: 0,0:26:30.22,0:26:35.71,Default,,0,0,0,,如我所言 我们将从了解解释的过程开始 Dialogue: 0,0:26:35.74,0:26:42.12,Default,,0,0,0,,随后则一起讨论应用-求值循环和构建Lisp Dialogue: 0,0:26:42.16,0:26:44.17,Default,,0,0,0,,你将发现这种方法具有相当的普遍性 Dialogue: 0,0:26:44.37,0:26:48.26,Default,,0,0,0,,我们将用同样的技术去构建一门全完不同的语言 Dialogue: 0,0:26:48.53,0:26:50.31,Default,,0,0,0,,一种所谓的逻辑编程语言 Dialogue: 0,0:26:50.53,0:26:54.83,Default,,0,0,0,,一种无关具有输入和输出的过程 Dialogue: 0,0:26:54.86,0:26:57.25,Default,,0,0,0,,而仅关注元素之间关系的语言 Dialogue: 0,0:26:57.31,0:27:03.92,Default,,0,0,0,,最终 我们将讨论如何将这些东西 Dialogue: 0,0:27:03.95,0:27:05.60,Default,,0,0,0,,实实在在的实现在简单的机器上 Dialogue: 0,0:27:05.65,0:27:08.39,Default,,0,0,0,,比如说这个 Dialogue: 0,0:27:09.13,0:27:12.14,Default,,0,0,0,,如图所示的芯片 Dialogue: 0,0:27:12.16,0:27:17.47,Default,,0,0,0,,就是我们在硬件部分谈及的Lisp解释器 Dialogue: 0,0:27:20.88,0:27:23.79,Default,,0,0,0,,这三大主题就是本课的提纲 Dialogue: 0,0:27:24.88,0:27:29.41,Default,,0,0,0,,黑盒抽象 约定接口 元语言抽象 Dialogue: 0,0:27:31.58,0:27:33.57,Default,,0,0,0,,好 先休息一会儿 然后正式开始 Dialogue: 0,0:27:52.19,0:28:03.42,Default,,0,0,0,,[音乐] Dialogue: 0,0:28:03.92,0:28:06.84,Default,,0,0,0,,现在让我们正式开始学习Lisp Dialogue: 0,0:28:08.06,0:28:10.75,Default,,0,0,0,,事实上 我们将开始学习一些非常重要的内容 Dialogue: 0,0:28:10.80,0:28:14.33,Default,,0,0,0,,在这门课程中最重要的 不是Lisp本身 Dialogue: 0,0:28:14.38,0:28:18.41,Default,,0,0,0,,而是一种的通用框架体系 Dialogue: 0,0:28:18.62,0:28:21.89,Default,,0,0,0,,我们用它来组织我之前提到的语言 Dialogue: 0,0:28:22.12,0:28:25.10,Default,,0,0,0,,当有人要向你展示一门新语言 Dialogue: 0,0:28:25.13,0:28:26.16,Default,,0,0,0,,你应该问他 Dialogue: 0,0:28:26.19,0:28:32.87,Default,,0,0,0,,(构成语言的)基本元素有哪些? Dialogue: 0,0:28:37.50,0:28:38.78,Default,,0,0,0,,这门语言使用哪些基本元素? Dialogue: 0,0:28:38.96,0:28:43.53,Default,,0,0,0,,你是如何将这些元素组合在一起的? Dialogue: 0,0:28:43.68,0:28:47.42,Default,,0,0,0,,组合的方法是什么? Dialogue: 0,0:28:50.17,0:28:54.18,Default,,0,0,0,,允许你将这些基本元素整合在一起 Dialogue: 0,0:28:54.37,0:28:56.51,Default,,0,0,0,,以构建更大的对象的又是什么? Dialogue: 0,0:28:58.01,0:28:59.61,Default,,0,0,0,,把东西构建在一起的方法是什么? Dialogue: 0,0:29:01.39,0:29:05.69,Default,,0,0,0,,以及 抽象的方法是什么? Dialogue: 0,0:29:08.35,0:29:16.85,Default,,0,0,0,,我们如何利用这些元素并把它们封装成盒子? Dialogue: 0,0:29:16.88,0:29:19.66,Default,,0,0,0,,我们如何为它们命名使得我们可以 Dialogue: 0,0:29:19.68,0:29:23.85,Default,,0,0,0,,把它们当作基本元素来用于构建更复杂的东西? Dialogue: 0,0:29:23.89,0:29:25.66,Default,,0,0,0,,等等 等等 等等 Dialogue: 0,0:29:26.89,0:29:28.08,Default,,0,0,0,,因此 当有人告诉你 Dialogue: 0,0:29:28.09,0:29:29.55,Default,,0,0,0,,嘿 我发明了一种新的计算机语言 Dialogue: 0,0:29:30.86,0:29:34.70,Default,,0,0,0,,你不应该问 用你的语言编写求逆矩阵需要多少代码 Dialogue: 0,0:29:35.73,0:29:36.88,Default,,0,0,0,,这是风马牛不相及的 Dialogue: 0,0:29:37.39,0:29:42.30,Default,,0,0,0,,如果该语言没有内建了矩阵或者类似的东西 Dialogue: 0,0:29:42.33,0:29:43.37,Default,,0,0,0,,那你就应该问他 Dialogue: 0,0:29:43.37,0:29:46.03,Default,,0,0,0,,应该如何构建矩阵? Dialogue: 0,0:29:46.05,0:29:48.47,Default,,0,0,0,,如何通过组合来构建? Dialogue: 0,0:29:48.62,0:29:50.71,Default,,0,0,0,,如何对其进行抽象 Dialogue: 0,0:29:51.68,0:29:54.21,Default,,0,0,0,,把它作为基本元素 Dialogue: 0,0:29:54.22,0:29:56.52,Default,,0,0,0,,来构建更复杂的东西? Dialogue: 0,0:29:58.75,0:30:04.61,Default,,0,0,0,,我们将了解到Lisp的一些基本数据和基本过程 Dialogue: 0,0:30:05.25,0:30:07.50,Default,,0,0,0,,好吧 这次是真的开始了 Dialogue: 0,0:30:07.55,0:30:14.89,Default,,0,0,0,,这里有一个Lisp的基本数据 数字3 Dialogue: 0,0:30:16.27,0:30:19.87,Default,,0,0,0,,事实上 如果打破沙锅问到底的话 这不是数字3 Dialogue: 0,0:30:19.93,0:30:25.57,Default,,0,0,0,,这只是一个符号 用以代表柏拉图观念下的数字3的 Dialogue: 0,0:30:26.67,0:30:28.93,Default,,0,0,0,,这又是另一个 Dialogue: 0,0:30:30.48,0:30:36.06,Default,,0,0,0,,这个是Lisp中又一个基本数据 17.4 Dialogue: 0,0:30:36.08,0:30:39.42,Default,,0,0,0,,又或者说 代表17.4 Dialogue: 0,0:30:40.99,0:30:44.48,Default,,0,0,0,,这儿还有一个5 Dialogue: 0,0:30:46.86,0:30:52.21,Default,,0,0,0,,然后这儿又有一个内建于Lisp的基本对象“+” Dialogue: 0,0:30:52.25,0:30:55.68,Default,,0,0,0,,如果又要继续深究的话 Dialogue: 0,0:30:55.71,0:31:00.47,Default,,0,0,0,,这只是一个名字 代表对元素进行加和的基本方法而已 Dialogue: 0,0:31:00.53,0:31:02.53,Default,,0,0,0,,就像这个是柏拉图式的3 Dialogue: 0,0:31:02.61,0:31:09.32,Default,,0,0,0,,这也只是一个代表柏拉图观念下的将某些元素加和起来 Dialogue: 0,0:31:10.32,0:31:11.98,Default,,0,0,0,,这些都是基本元素 Dialogue: 0,0:31:12.14,0:31:13.76,Default,,0,0,0,,我可以将它们放在一起 Dialogue: 0,0:31:14.14,0:31:18.29,Default,,0,0,0,,我可以说 3加17.4加5的和是多少 Dialogue: 0,0:31:18.69,0:31:21.31,Default,,0,0,0,,这等同于说 Dialogue: 0,0:31:21.33,0:31:27.71,Default,,0,0,0,,让我们把求和运算符应用于这三个数 Dialogue: 0,0:31:27.74,0:31:31.15,Default,,0,0,0,,我可以得到什么呢 是8 是17 还是25.4 Dialogue: 0,0:31:34.43,0:31:38.05,Default,,0,0,0,,因此 我可以问Lisp这个的值是多少 Dialogue: 0,0:31:38.94,0:31:40.77,Default,,0,0,0,,(表达式)返回25.4 Dialogue: 0,0:31:43.58,0:31:44.83,Default,,0,0,0,,介绍一些术语吧 Dialogue: 0,0:31:44.88,0:31:51.47,Default,,0,0,0,,我所写的这些东西就叫做组合式 Dialogue: 0,0:31:56.88,0:32:01.94,Default,,0,0,0,,通常 一个组合式是由运算符 Dialogue: 0,0:32:03.39,0:32:04.72,Default,,0,0,0,,这些就是运算符 Dialogue: 0,0:32:09.71,0:32:12.05,Default,,0,0,0,,和应用该运算符的运算对象组成 Dialogue: 0,0:32:13.25,0:32:14.54,Default,,0,0,0,,这些是运算对象 Dialogue: 0,0:32:21.89,0:32:23.79,Default,,0,0,0,,当然 我可以完成更复杂的事 Dialogue: 0,0:32:23.82,0:32:28.56,Default,,0,0,0,,我可以使之更复杂是因为 这些运算对象 Dialogue: 0,0:32:29.52,0:32:31.09,Default,,0,0,0,,通常来说 也可以是组合式 Dialogue: 0,0:32:31.15,0:32:44.47,Default,,0,0,0,,比如 3加上5乘以6乘以8乘以2的积的和是多少 Dialogue: 0,0:32:45.66,0:32:52.16,Default,,0,0,0,,而我应该得到 我算一下 30 40 43 Dialogue: 0,0:32:52.73,0:32:54.81,Default,,0,0,0,,因此Lisp会返回这个表达式的值是43 Dialogue: 0,0:32:56.56,0:33:02.80,Default,,0,0,0,,后续我们将看到构造组合式是组合的基本需求 Dialogue: 0,0:33:04.65,0:33:09.22,Default,,0,0,0,,你所看到的这些语法 Dialogue: 0,0:33:10.56,0:33:13.04,Default,,0,0,0,,就是Lisp用的所谓的前缀表示法 Dialogue: 0,0:33:16.22,0:33:25.21,Default,,0,0,0,,意即操作符在操作数的左端 Dialogue: 0,0:33:25.47,0:33:26.48,Default,,0,0,0,,这只是个约定 Dialogue: 0,0:33:27.66,0:33:29.77,Default,,0,0,0,,注意 这些都被括起来了 Dialogue: 0,0:33:30.08,0:33:32.32,Default,,0,0,0,,这些括号使得它们区别开来 Dialogue: 0,0:33:32.32,0:33:36.99,Default,,0,0,0,,因此只要看看这个 我就可以知道这个是运算符 Dialogue: 0,0:33:37.01,0:33:40.99,Default,,0,0,0,,以及这有1个 2个 3个 4个运算对象 Dialogue: 0,0:33:42.38,0:33:47.97,Default,,0,0,0,,而且我也可以发现第二个运算对象是个组合式 Dialogue: 0,0:33:48.88,0:33:51.55,Default,,0,0,0,,该组合式有一个运算符和两个运算对象 Dialogue: 0,0:33:52.43,0:33:54.27,Default,,0,0,0,,Lisp中的括号 有点或者非常不同于 Dialogue: 0,0:33:54.61,0:33:57.71,Default,,0,0,0,,通常数学中的括号 Dialogue: 0,0:33:57.77,0:34:00.11,Default,,0,0,0,,数学中 我们常将其用于分组 Dialogue: 0,0:34:01.21,0:34:03.75,Default,,0,0,0,,如果有时你忘了闭合括号 但其他人能理解你的意图 Dialogue: 0,0:34:03.77,0:34:05.56,Default,,0,0,0,,这也无关紧要 Dialogue: 0,0:34:05.76,0:34:08.51,Default,,0,0,0,,通常的 你多加了括号也无所谓 Dialogue: 0,0:34:08.86,0:34:10.94,Default,,0,0,0,,因为这样只会使得分组更加明确 Dialogue: 0,0:34:10.96,0:34:11.77,Default,,0,0,0,,Lisp可不像这样 Dialogue: 0,0:34:13.12,0:34:15.37,Default,,0,0,0,,Lisp中你既不能不闭合括号 Dialogue: 0,0:34:16.38,0:34:18.56,Default,,0,0,0,,亦不能添加多余的括号 Dialogue: 0,0:34:19.33,0:34:21.28,Default,,0,0,0,,因为加括号总是意味着 Dialogue: 0,0:34:21.37,0:34:27.05,Default,,0,0,0,,确切的来说 所括之物是一个组合式 Dialogue: 0,0:34:27.09,0:34:28.81,Default,,0,0,0,,表示将运算符应用于运算对象 Dialogue: 0,0:34:29.04,0:34:32.62,Default,,0,0,0,,如果我不闭合这个括号 Dialogue: 0,0:34:32.65,0:34:33.96,Default,,0,0,0,,这个就变成其它的意思了 Dialogue: 0,0:34:35.41,0:34:37.25,Default,,0,0,0,,事实上 我们可以这么来理解这个问题 Dialogue: 0,0:34:37.41,0:34:41.65,Default,,0,0,0,,把我写的这些东西想作一个树 Dialogue: 0,0:34:42.37,0:34:47.30,Default,,0,0,0,,这个组合式实际上是一个树 树具有一个“+” Dialogue: 0,0:34:47.37,0:34:54.46,Default,,0,0,0,,以及 一个3和一些其它的东西和一个8 还有一个2 Dialogue: 0,0:34:54.48,0:34:56.35,Default,,0,0,0,,而这里的其它的东西 Dialogue: 0,0:34:56.35,0:35:03.22,Default,,0,0,0,,它本身是一个有一个“*”一个5和一个6的子树 Dialogue: 0,0:35:03.95,0:35:05.53,Default,,0,0,0,,我们可以这样认为 Dialogue: 0,0:35:05.55,0:35:09.00,Default,,0,0,0,,我们只是在构建这些树而已 Dialogue: 0,0:35:09.21,0:35:15.10,Default,,0,0,0,,括号只是将这种二维结构写作线性字符串 Dialogue: 0,0:35:15.79,0:35:17.34,Default,,0,0,0,,的一种方法罢了 Dialogue: 0,0:35:19.23,0:35:23.81,Default,,0,0,0,,因为至少在Lisp发明时 人们还在用电传打字机或者打孔卡 Dialogue: 0,0:35:24.17,0:35:25.60,Default,,0,0,0,,这种记法方便多了 Dialogue: 0,0:35:25.97,0:35:30.52,Default,,0,0,0,,如果Lisp是在当下被发明的 语法可能会像树那样 Dialogue: 0,0:35:31.76,0:35:35.07,Default,,0,0,0,,那么 让我们看看在计算机里面它究竟是什么样 Dialogue: 0,0:35:36.29,0:35:39.37,Default,,0,0,0,,这里有个Lisp解释套件 Dialogue: 0,0:35:39.41,0:35:40.43,Default,,0,0,0,,这是个编辑器 Dialogue: 0,0:35:41.13,0:35:44.86,Default,,0,0,0,,我将要在上方写一些表达式并让Lisp对其求值 Dialogue: 0,0:35:45.12,0:35:46.75,Default,,0,0,0,,比如 我可以问Lisp Dialogue: 0,0:35:46.83,0:35:48.53,Default,,0,0,0,,这个符号的值是多少 Dialogue: 0,0:35:49.44,0:35:50.50,Default,,0,0,0,,我键入3 Dialogue: 0,0:35:50.57,0:35:52.20,Default,,0,0,0,,然后叫Lisp对其求值 Dialogue: 0,0:35:52.32,0:35:54.77,Default,,0,0,0,,然后你就会看到Lisp在下面返回了一些信息 Dialogue: 0,0:35:55.39,0:35:56.84,Default,,0,0,0,,这个值就是3 Dialogue: 0,0:35:57.58,0:36:04.96,Default,,0,0,0,,我也可以问 3加上4加上8的和是多少 Dialogue: 0,0:36:06.45,0:36:08.05,Default,,0,0,0,,键入这个组合式 Dialogue: 0,0:36:08.93,0:36:10.66,Default,,0,0,0,,让Lisp对其求值 Dialogue: 0,0:36:14.49,0:36:15.68,Default,,0,0,0,,返回15 Dialogue: 0,0:36:16.57,0:36:18.80,Default,,0,0,0,,我可以键入一些更复杂的东西 Dialogue: 0,0:36:19.25,0:36:34.14,Default,,0,0,0,,将3乘以7加19.5的和的乘积求和得多少 Dialogue: 0,0:36:35.21,0:36:38.00,Default,,0,0,0,,你会发现Lisp内建了一些功能 Dialogue: 0,0:36:38.01,0:36:39.76,Default,,0,0,0,,帮你跟踪这些括号 Dialogue: 0,0:36:39.77,0:36:42.13,Default,,0,0,0,,看我键入下一个右圆括号 Dialogue: 0,0:36:42.21,0:36:45.01,Default,,0,0,0,,用于闭合以“*”开头的那个组合式 Dialogue: 0,0:36:45.52,0:36:47.30,Default,,0,0,0,,开头的那个左括号会闪一下 Dialogue: 0,0:36:47.76,0:36:49.69,Default,,0,0,0,,我把这些括号擦去 再示范一次 Dialogue: 0,0:36:50.14,0:36:52.70,Default,,0,0,0,,键入右括号 闭合了“+”组合式 Dialogue: 0,0:36:53.58,0:36:56.41,Default,,0,0,0,,再键入右括号 闭合了“*”组合式 Dialogue: 0,0:36:57.90,0:37:00.76,Default,,0,0,0,,现在我又回到了加 我将它们与4相加 Dialogue: 0,0:37:01.66,0:37:02.69,Default,,0,0,0,,闭合了“+”组合式 Dialogue: 0,0:37:02.73,0:37:07.07,Default,,0,0,0,,现在我补全了组合式 然后我问Lisp它们的值是多少 Dialogue: 0,0:37:07.26,0:37:11.66,Default,,0,0,0,,这种内建于各种Lisp系统的 Dialogue: 0,0:37:11.76,0:37:13.29,Default,,0,0,0,,括号匹配工具帮你跟进(括号匹配) Dialogue: 0,0:37:13.36,0:37:16.55,Default,,0,0,0,,因为手工闭合这些括号太辛苦了 Dialogue: 0,0:37:16.81,0:37:21.20,Default,,0,0,0,,这又是另外一种保持括号跟进的约定 Dialogue: 0,0:37:21.25,0:37:23.68,Default,,0,0,0,,我另外写一个复杂的组合式 Dialogue: 0,0:37:24.77,0:37:34.00,Default,,0,0,0,,将3和5的积与某个元素求和 Dialogue: 0,0:37:34.03,0:37:35.23,Default,,0,0,0,,现在我将要缩进 Dialogue: 0,0:37:35.28,0:37:39.85,Default,,0,0,0,,使得这些运算对象都是垂直书写的 Dialogue: 0,0:37:40.30,0:37:45.65,Default,,0,0,0,,将这些加上47乘以 Dialogue: 0,0:37:47.02,0:37:54.59,Default,,0,0,0,,恩…… 47乘以20和6.8的差 Dialogue: 0,0:37:54.62,0:37:57.09,Default,,0,0,0,,意即从20中减去6.8 Dialogue: 0,0:37:58.97,0:38:00.19,Default,,0,0,0,,然后 这个括号闭合了 Dialogue: 0,0:38:00.22,0:38:03.47,Default,,0,0,0,,闭合“-” 闭合“*” Dialogue: 0,0:38:03.76,0:38:05.42,Default,,0,0,0,,现在 我们再写一个运算符 Dialogue: 0,0:38:05.44,0:38:09.49,Default,,0,0,0,,Lisp编辑器自动缩进到正确的位置 Dialogue: 0,0:38:10.40,0:38:11.50,Default,,0,0,0,,来帮助我保持跟进 Dialogue: 0,0:38:12.61,0:38:14.09,Default,,0,0,0,,我再示范一次 Dialogue: 0,0:38:14.13,0:38:15.89,Default,,0,0,0,,这样就又闭合了最后一个括号 Dialogue: 0,0:38:16.25,0:38:17.71,Default,,0,0,0,,它匹配了这个“+”(的括号) Dialogue: 0,0:38:20.40,0:38:22.64,Default,,0,0,0,,现在我想问 这个的值是多少 Dialogue: 0,0:38:23.87,0:38:29.28,Default,,0,0,0,,因此 这两件事 缩进到正确的位置 Dialogue: 0,0:38:29.31,0:38:30.86,Default,,0,0,0,,也就是所谓的美观的输出 Dialogue: 0,0:38:31.55,0:38:33.58,Default,,0,0,0,,以及闭合提示 Dialogue: 0,0:38:33.89,0:38:37.73,Default,,0,0,0,,是许多Lisp系统所内建用于帮你保持跟进的工具 Dialogue: 0,0:38:37.76,0:38:39.01,Default,,0,0,0,,你应该学习如何使用它们 Dialogue: 0,0:38:41.52,0:38:43.17,Default,,0,0,0,,好 这些都是基本的内容 Dialogue: 0,0:38:44.73,0:38:46.31,Default,,0,0,0,,这就是一种组合的方法 Dialogue: 0,0:38:46.33,0:38:47.93,Default,,0,0,0,,现在让我们来看看抽象的方法 Dialogue: 0,0:38:49.44,0:38:53.84,Default,,0,0,0,,我希望我能够写一些像这样的组合式 Dialogue: 0,0:38:53.85,0:38:55.77,Default,,0,0,0,,将它抽象化并给它命名 Dialogue: 0,0:38:55.81,0:38:57.26,Default,,0,0,0,,使得我可以将其作为一个(我们语言的)元素 Dialogue: 0,0:38:57.31,0:38:59.92,Default,,0,0,0,,在Lisp中 我可以用“define”来实现 Dialogue: 0,0:39:01.17,0:39:02.43,Default,,0,0,0,,比如说 Dialogue: 0,0:39:02.73,0:39:15.05,Default,,0,0,0,,定义A为5乘以5 Dialogue: 0,0:39:18.40,0:39:22.35,Default,,0,0,0,,现在我可以问Lisp Dialogue: 0,0:39:22.38,0:39:26.01,Default,,0,0,0,,A和A的乘积是多少 Dialogue: 0,0:39:27.18,0:39:29.81,Default,,0,0,0,,这个是25所以这个就是625 Dialogue: 0,0:39:31.97,0:39:36.01,Default,,0,0,0,,但更重要的则是 我现在可以使用A Dialogue: 0,0:39:36.21,0:39:37.92,Default,,0,0,0,,我已经在这个组合式里面用过了 Dialogue: 0,0:39:38.41,0:39:43.55,Default,,0,0,0,,但我也可以在更复杂的组合式里面使用它 Dialogue: 0,0:39:43.58,0:39:50.93,Default,,0,0,0,,我也可以说 定义B为 Dialogue: 0,0:39:50.97,0:39:57.45,Default,,0,0,0,,A与5乘以A的积的和 Dialogue: 0,0:39:59.44,0:40:00.72,Default,,0,0,0,,闭合“+” Dialogue: 0,0:40:03.45,0:40:05.85,Default,,0,0,0,,让我们来看看它在计算机中是怎样的吧 Dialogue: 0,0:40:07.28,0:40:10.68,Default,,0,0,0,,我就像黑板上写的那样键入就可以了 Dialogue: 0,0:40:10.83,0:40:21.73,Default,,0,0,0,,我告诉Lisp Dialogue: 0,0:40:23.74,0:40:25.38,Default,,0,0,0,,定义A为5乘以5的积 Dialogue: 0,0:40:25.52,0:40:28.94,Default,,0,0,0,,注意Lisp在下方回应了一个A Dialogue: 0,0:40:29.09,0:40:31.38,Default,,0,0,0,,通常来说 你如果在Lisp中键入了一个定义 Dialogue: 0,0:40:31.50,0:40:35.02,Default,,0,0,0,,它返回被定义的符号 Dialogue: 0,0:40:35.63,0:40:39.66,Default,,0,0,0,,现在我问Lisp A乘以A的积是多少 Dialogue: 0,0:40:42.81,0:40:44.33,Default,,0,0,0,,Lisp返回625 Dialogue: 0,0:40:46.05,0:41:00.34,Default,,0,0,0,,我也可以定义B为A加上5乘以A的积的和 Dialogue: 0,0:41:00.48,0:41:05.70,Default,,0,0,0,,闭合“*” 闭合“+” 闭合“define” Dialogue: 0,0:41:07.63,0:41:10.37,Default,,0,0,0,,Lisp在下方正常返回B Dialogue: 0,0:41:11.04,0:41:13.24,Default,,0,0,0,,现在我可以问Lisp B的值是多少 Dialogue: 0,0:41:17.18,0:41:18.88,Default,,0,0,0,,我也可以问一些更复杂的事 Dialogue: 0,0:41:18.93,0:41:26.69,Default,,0,0,0,,比如A加上B除以5的商的和是多少 Dialogue: 0,0:41:26.73,0:41:30.25,Default,,0,0,0,,这个“/”是另一个基本运算符 代表除 Dialogue: 0,0:41:30.38,0:41:32.78,Default,,0,0,0,,我让B除以5 并加在A上 Dialogue: 0,0:41:33.65,0:41:35.23,Default,,0,0,0,,Lisp正常返回55 Dialogue: 0,0:41:36.57,0:41:37.92,Default,,0,0,0,,就像这样 Dialogue: 0,0:41:39.82,0:41:43.40,Default,,0,0,0,,这是定义东西的基本方法 Dialogue: 0,0:41:43.44,0:41:49.02,Default,,0,0,0,,这是最简单的命名方法 但并不是很强大 Dialogue: 0,0:41:50.06,0:41:51.60,Default,,0,0,0,,注意我们讨论的是通用方法 Dialogue: 0,0:41:51.84,0:41:53.37,Default,,0,0,0,,因此我真正想定义的是 Dialogue: 0,0:41:53.57,0:41:57.68,Default,,0,0,0,,一种通用方法 可以 Dialogue: 0,0:41:58.11,0:42:17.53,Default,,0,0,0,,得到 5乘5 6乘6 1001乘1001 1001.7乘1001.7 Dialogue: 0,0:42:17.76,0:42:24.16,Default,,0,0,0,,我想给一个数与其自身相乘这种想法一个名字 Dialogue: 0,0:42:28.48,0:42:30.11,Default,,0,0,0,,你应该知道 这叫做平方 Dialogue: 0,0:42:31.69,0:42:35.63,Default,,0,0,0,,而在Lisp中我应该这样实现 Dialogue: 0,0:42:37.97,0:42:56.25,Default,,0,0,0,,定义 square某个叫x的东西 为 将x乘以x自己 Dialogue: 0,0:42:57.87,0:43:01.12,Default,,0,0,0,,定义完毕后 我可以问Lisp Dialogue: 0,0:43:01.12,0:43:05.49,Default,,0,0,0,,比如 10的平方是多少 Dialogue: 0,0:43:06.67,0:43:07.87,Default,,0,0,0,,Lisp返回100 Dialogue: 0,0:43:10.70,0:43:14.24,Default,,0,0,0,,让我们深入讨论一下 Dialogue: 0,0:43:15.29,0:43:16.88,Default,,0,0,0,,这儿是square的定义 Dialogue: 0,0:43:17.50,0:43:22.55,Default,,0,0,0,,square某个元素 即是将该元素进行自乘 Dialogue: 0,0:43:23.69,0:43:25.34,Default,,0,0,0,,这里的x Dialogue: 0,0:43:26.29,0:43:27.81,Default,,0,0,0,,应该算是一种代词 Dialogue: 0,0:43:27.87,0:43:29.53,Default,,0,0,0,,指代了我要做平方的元素 Dialogue: 0,0:43:31.49,0:43:37.41,Default,,0,0,0,,实际上我将其乘以x 即是乘以它自己 Dialogue: 0,0:43:42.22,0:43:48.27,Default,,0,0,0,,这些就是定义一个过程的记法 Dialogue: 0,0:43:48.29,0:43:50.29,Default,,0,0,0,,这样说可能把你搞糊涂了 Dialogue: 0,0:43:50.81,0:43:53.97,Default,,0,0,0,,因为这就像我在用square一样 Dialogue: 0,0:43:54.00,0:43:56.80,Default,,0,0,0,,但如果我说x的平方根或者10的平方根 Dialogue: 0,0:43:57.55,0:44:00.81,Default,,0,0,0,,并没有说清楚我对什么做了定义 Dialogue: 0,0:44:03.10,0:44:04.91,Default,,0,0,0,,所以让我换个方式来进行定义 Dialogue: 0,0:44:05.74,0:44:08.21,Default,,0,0,0,,这样可以清楚的看到定义的具体内容 Dialogue: 0,0:44:08.54,0:44:29.39,Default,,0,0,0,,我定义“square”为“(lambda (x) (* x x))” Dialogue: 0,0:44:36.56,0:44:42.05,Default,,0,0,0,,这里 我定义square就像我某命名为A一样 Dialogue: 0,0:44:43.23,0:44:44.72,Default,,0,0,0,,我定义square Dialogue: 0,0:44:44.75,0:44:48.39,Default,,0,0,0,,这里 我把这个组合式的值命名为A Dialogue: 0,0:44:49.29,0:44:52.41,Default,,0,0,0,,在这里 我把这个东西命名为square Dialogue: 0,0:44:52.43,0:44:53.44,Default,,0,0,0,,以lambda开头 Dialogue: 0,0:44:53.45,0:44:56.77,Default,,0,0,0,,lambda在Lisp中用以构建一个过程 Dialogue: 0,0:45:00.24,0:45:02.91,Default,,0,0,0,,请仔细看一下幻灯片上的内容 Dialogue: 0,0:45:04.27,0:45:05.81,Default,,0,0,0,,这个定义读作 Dialogue: 0,0:45:05.85,0:45:10.33,Default,,0,0,0,,将square定义为 Dialogue: 0,0:45:12.78,0:45:13.97,Default,,0,0,0,,一个由lambda构造的 Dialogue: 0,0:45:14.06,0:45:17.49,Default,,0,0,0,,一个有带有参数x的过程 Dialogue: 0,0:45:19.26,0:45:24.09,Default,,0,0,0,,而该过程返回将x自乘的结果 Dialogue: 0,0:45:24.97,0:45:33.12,Default,,0,0,0,,一般来讲 这是最佳的定义方式 Dialogue: 0,0:45:33.41,0:45:35.20,Default,,0,0,0,,因为这个更加方便一点 Dialogue: 0,0:45:35.21,0:45:38.67,Default,,0,0,0,,但是也别忘了它实质上也是这个 Dialogue: 0,0:45:38.86,0:45:41.41,Default,,0,0,0,,事实上 就Lisp解释器而言 Dialogue: 0,0:45:41.61,0:45:45.55,Default,,0,0,0,,这两种方法没有区别 Dialogue: 0,0:45:46.51,0:45:53.29,Default,,0,0,0,,换句话说 这只是一种语法糖 Dialogue: 0,0:45:54.41,0:45:55.80,Default,,0,0,0,,语法糖的意思就是 Dialogue: 0,0:45:56.35,0:46:00.83,Default,,0,0,0,,这种形式输入更方便一些 Dialogue: 0,0:46:01.12,0:46:06.11,Default,,0,0,0,,这只是这下面的有lambda的表达式的语法糖而已 Dialogue: 0,0:46:07.31,0:46:10.62,Default,,0,0,0,,你应该记住 Dialogue: 0,0:46:10.80,0:46:13.87,Default,,0,0,0,,当我这样写的时候 其实是在对某个东西进行命名 Dialogue: 0,0:46:14.46,0:46:16.22,Default,,0,0,0,,我将其命名为square Dialogue: 0,0:46:16.24,0:46:19.90,Default,,0,0,0,,square代表一个构建好的过程 Dialogue: 0,0:46:21.20,0:46:23.90,Default,,0,0,0,,让我们看看在计算机里面又是 怎样的吧 Dialogue: 0,0:46:24.78,0:46:35.95,Default,,0,0,0,,定义“(square x)”为x乘以x的积 Dialogue: 0,0:46:49.65,0:46:52.32,Default,,0,0,0,,将它送入Lisp Dialogue: 0,0:46:53.49,0:46:53.92,Default,,0,0,0,,返回square Dialogue: 0,0:46:53.93,0:46:56.29,Default,,0,0,0,,现在 我已经将某个东西命名为square了 Dialogue: 0,0:46:56.45,0:47:02.88,Default,,0,0,0,,完毕后 我就可以问Lisp 1001的平方是多少 Dialogue: 0,0:47:05.26,0:47:17.69,Default,,0,0,0,,或者更通常的来说 我可以问 5加上7的和的平方是多少 Dialogue: 0,0:47:22.81,0:47:24.95,Default,,0,0,0,,12的平方是144 Dialogue: 0,0:47:25.07,0:47:28.86,Default,,0,0,0,,在某些组合式中我亦可把square当作一个元素 Dialogue: 0,0:47:28.88,0:47:37.50,Default,,0,0,0,,3的平方加上4的平方的和是多少 Dialogue: 0,0:47:42.53,0:47:44.09,Default,,0,0,0,,9加上16得25 Dialogue: 0,0:47:44.91,0:47:50.54,Default,,0,0,0,,我可以将square作为元素用于更复杂的式子 Dialogue: 0,0:47:50.59,0:48:00.51,Default,,0,0,0,,比如 1001的平方点的平方的平方是多少 Dialogue: 0,0:48:07.89,0:48:10.63,Default,,0,0,0,,这就是1001点的平方的平方的平方 Dialogue: 0,0:48:11.20,0:48:15.45,Default,,0,0,0,,我也可以问Lisp square本身是什么 Dialogue: 0,0:48:15.68,0:48:17.16,Default,,0,0,0,,它的值是是什么 Dialogue: 0,0:48:17.44,0:48:22.14,Default,,0,0,0,,Lisp用一种约定的方法告诉我这是一个过程 Dialogue: 0,0:48:22.27,0:48:23.98,Default,,0,0,0,,它返回 复合过程square Dialogue: 0,0:48:24.25,0:48:27.92,Default,,0,0,0,,记住 square的值是一个过程 Dialogue: 0,0:48:29.15,0:48:30.89,Default,,0,0,0,,而那些用星号和括号的记法 Dialogue: 0,0:48:31.10,0:48:34.78,Default,,0,0,0,,只是Lisp用来描述这个过程的约定 Dialogue: 0,0:48:36.11,0:48:41.33,Default,,0,0,0,,让我们再看两个关于define的例子 Dialogue: 0,0:48:44.91,0:48:46.91,Default,,0,0,0,,这有两个过程 Dialogue: 0,0:48:47.36,0:48:52.84,Default,,0,0,0,,定义x和y的平均值为x加上y的和除以2的商 Dialogue: 0,0:48:54.67,0:49:01.49,Default,,0,0,0,,以及定义好平方和平均值后 我可以定义均方 Dialogue: 0,0:49:01.65,0:49:04.71,Default,,0,0,0,,我可以用它们来讨论某元素的均方 Dialogue: 0,0:49:04.91,0:49:09.26,Default,,0,0,0,,即x的平方与y的平方的平均值 Dialogue: 0,0:49:10.97,0:49:13.63,Default,,0,0,0,,当定义好它们后 我可以问 Dialogue: 0,0:49:13.66,0:49:24.88,Default,,0,0,0,,2和3的均方是多少 Dialogue: 0,0:49:25.23,0:49:30.24,Default,,0,0,0,,我将会得到 4和9的平均值 即6.5 Dialogue: 0,0:49:32.85,0:49:36.64,Default,,0,0,0,,关键点在于 定义了square后 Dialogue: 0,0:49:36.64,0:49:38.67,Default,,0,0,0,,我可以把它当作一个基本元素来使用 Dialogue: 0,0:49:41.41,0:49:43.07,Default,,0,0,0,,因此在这里 Dialogue: 0,0:49:44.65,0:49:45.74,Default,,0,0,0,,我在讨论均方的时候 Dialogue: 0,0:49:47.29,0:49:52.56,Default,,0,0,0,,从这点来说 定义均方的人没有必要知道 Dialogue: 0,0:49:52.61,0:49:55.76,Default,,0,0,0,,究竟square是由语言内建支持 Dialogue: 0,0:49:56.94,0:49:58.93,Default,,0,0,0,,还是自定义的过程 Dialogue: 0,0:49:59.73,0:50:01.28,Default,,0,0,0,,这是Lisp的关键之一 Dialogue: 0,0:50:02.30,0:50:07.52,Default,,0,0,0,,你无法准确区别 Dialogue: 0,0:50:07.53,0:50:11.82,Default,,0,0,0,,哪些是语言的基本对象 哪些是语言的内建支持 Dialogue: 0,0:50:12.83,0:50:14.73,Default,,0,0,0,,用户使用时则无需关心这些 Dialogue: 0,0:50:14.93,0:50:18.51,Default,,0,0,0,,你自己构建的东西看起来就像是语言自带的基本对象 Dialogue: 0,0:50:18.51,0:50:19.53,Default,,0,0,0,,具有同样的能力和灵活性 Dialogue: 0,0:50:19.57,0:50:22.57,Default,,0,0,0,,大家可以在课后上机做做测试 Dialogue: 0,0:50:24.75,0:50:26.30,Default,,0,0,0,,我们接下来讨论一下“+”吧 Dialogue: 0,0:50:26.72,0:50:30.09,Default,,0,0,0,,好的 让我们在计算机中看看 Dialogue: 0,0:50:30.11,0:50:32.33,Default,,0,0,0,,“+”的值是什么 Dialogue: 0,0:50:34.40,0:50:37.20,Default,,0,0,0,,注意Lisp在下面的输出 Dialogue: 0,0:50:37.25,0:50:38.81,Default,,0,0,0,,复合过程“+” Dialogue: 0,0:50:39.89,0:50:42.29,Default,,0,0,0,,因为在此系统中 Dialogue: 0,0:50:42.33,0:50:45.49,Default,,0,0,0,,“+”运算符是一个复合过程 Dialogue: 0,0:50:45.97,0:50:47.97,Default,,0,0,0,,但如果我不输入进去做下测试 你永远不会知道 Dialogue: 0,0:50:48.06,0:50:49.68,Default,,0,0,0,,所以这没什么不同 Dialogue: 0,0:50:49.84,0:50:50.51,Default,,0,0,0,,我们并不关心这些 Dialogue: 0,0:50:50.56,0:50:53.39,Default,,0,0,0,,它比我们日常处理的问题更加抽象一些 Dialogue: 0,0:50:54.17,0:50:59.11,Default,,0,0,0,,其关键点在于你无法分辨出 Dialogue: 0,0:50:59.17,0:51:03.82,Default,,0,0,0,,内建元素与复合元素之间的不同 Dialogue: 0,0:51:03.84,0:51:04.38,Default,,0,0,0,,为什么会这样呢? Dialogue: 0,0:51:04.38,0:51:08.07,Default,,0,0,0,,因为复合元素经过了一次抽象封装 (以致于无法分辨) Dialogue: 0,0:51:09.05,0:51:11.61,Default,,0,0,0,,我们已经介绍了Lisp的大多数元素了 Dialogue: 0,0:51:12.67,0:51:14.53,Default,,0,0,0,,还有一个需要进行讨论的 Dialogue: 0,0:51:14.57,0:51:16.53,Default,,0,0,0,,就是如何进行分情况分析 Dialogue: 0,0:51:16.59,0:51:17.70,Default,,0,0,0,,举个例子 Dialogue: 0,0:51:18.96,0:51:24.08,Default,,0,0,0,,让我们考虑绝对值函数的数学定义 Dialogue: 0,0:51:24.11,0:51:30.03,Default,,0,0,0,,我或许会说x的绝对值这样是一个函数 Dialogue: 0,0:51:30.16,0:51:37.24,Default,,0,0,0,,若x小于0 则为-x Dialogue: 0,0:51:37.92,0:51:41.13,Default,,0,0,0,,若x等于0 则为0 Dialogue: 0,0:51:42.64,0:51:46.62,Default,,0,0,0,,若x大于0 则就是x Dialogue: 0,0:51:49.15,0:51:51.90,Default,,0,0,0,,而Lisp则有一套分情况分析方法 Dialogue: 0,0:51:52.11,0:51:53.85,Default,,0,0,0,,以绝对值定义为例 我给大家说明一下 Dialogue: 0,0:51:55.55,0:52:02.41,Default,,0,0,0,,定义绝对值为 x是有多种情况的 Dialogue: 0,0:52:03.02,0:52:05.67,Default,,0,0,0,,这就是分情况分析 Dialogue: 0,0:52:09.23,0:52:19.09,Default,,0,0,0,,如果x小于0 则结果为-x Dialogue: 0,0:52:22.99,0:52:24.88,Default,,0,0,0,,我这里写的是一个子句 Dialogue: 0,0:52:24.99,0:52:35.54,Default,,0,0,0,,这整个是一个由两部分组成的条件表达式 Dialogue: 0,0:52:36.35,0:52:44.70,Default,,0,0,0,,这个部分叫做谓词或者条件 Dialogue: 0,0:52:44.83,0:52:45.90,Default,,0,0,0,,这就是一种情况(条件) Dialogue: 0,0:52:46.11,0:52:48.29,Default,,0,0,0,,用以表达条件的东西叫做谓词 Dialogue: 0,0:52:48.33,0:52:51.05,Default,,0,0,0,,Lisp中的谓词是一种 Dialogue: 0,0:52:51.37,0:52:52.87,Default,,0,0,0,,可以返回true或者false的东西 Dialogue: 0,0:52:53.53,0:52:56.13,Default,,0,0,0,,比如说“小于”是Lisp中的一个基本过程 Dialogue: 0,0:52:57.29,0:52:59.08,Default,,0,0,0,,它返回true或者false Dialogue: 0,0:53:00.54,0:53:06.32,Default,,0,0,0,,子句其余部分为一个动作或者需要做的事 Dialogue: 0,0:53:06.93,0:53:08.14,Default,,0,0,0,,本例中为true Dialogue: 0,0:53:08.17,0:53:09.81,Default,,0,0,0,,在这里 我则是取x的相反数 Dialogue: 0,0:53:10.08,0:53:14.41,Default,,0,0,0,,有趣的是 Lisp中减运算符符与相反数运算符相同 Dialogue: 0,0:53:14.56,0:53:18.43,Default,,0,0,0,,如果有两个及两个以上的参数 Dialogue: 0,0:53:18.58,0:53:22.49,Default,,0,0,0,,正如我们看到的 假设刚好有两个参数 就从第一个中减去第二个 Dialogue: 0,0:53:22.53,0:53:24.13,Default,,0,0,0,,如果只有一个参数 则取其相反数 Dialogue: 0,0:53:25.13,0:53:27.87,Default,,0,0,0,,这与前面相符合 Dialogue: 0,0:53:27.87,0:53:29.69,Default,,0,0,0,,这又是一个COND子句 Dialogue: 0,0:53:30.64,0:53:35.87,Default,,0,0,0,,这是说 在x等于0的时候 结果为0 Dialogue: 0,0:53:37.95,0:53:44.75,Default,,0,0,0,,在x大于0的时候 结果为x Dialogue: 0,0:53:45.33,0:53:49.38,Default,,0,0,0,,闭合子句 闭合COND 闭合define Dialogue: 0,0:53:49.57,0:53:51.29,Default,,0,0,0,,这就是绝对值的定义 Dialogue: 0,0:53:51.31,0:53:53.66,Default,,0,0,0,,你会发现分情况分析 Dialogue: 0,0:53:53.66,0:53:56.04,Default,,0,0,0,,与数学中所用的非常相似 Dialogue: 0,0:53:58.14,0:54:03.07,Default,,0,0,0,,当然还有一些不常用的受限的分情况分析方法 Dialogue: 0,0:54:03.07,0:54:06.24,Default,,0,0,0,,很多时候 你在进行分情况分析时只有一种情况 Dialogue: 0,0:54:06.93,0:54:08.07,Default,,0,0,0,,你首先进行测试 Dialogue: 0,0:54:08.33,0:54:10.75,Default,,0,0,0,,然后根据返回的为true或false来决定如何处理 Dialogue: 0,0:54:11.01,0:54:15.90,Default,,0,0,0,,这是另外一种定义绝对值的方法 Dialogue: 0,0:54:16.00,0:54:17.19,Default,,0,0,0,,但看起来是几乎一样的 Dialogue: 0,0:54:17.66,0:54:22.56,Default,,0,0,0,,像这样 如果x小于0 结果则为x的相反数 Dialogue: 0,0:54:24.41,0:54:25.97,Default,,0,0,0,,否则 结果即为x Dialogue: 0,0:54:26.05,0:54:27.25,Default,,0,0,0,,我们将会大量的使用“if” Dialogue: 0,0:54:27.29,0:54:29.13,Default,,0,0,0,,再次声明 Dialogue: 0,0:54:29.13,0:54:32.70,Default,,0,0,0,,你们在这里看到的绝对值形式 Dialogue: 0,0:54:34.30,0:54:36.98,Default,,0,0,0,,和我在黑板上写的那种 Dialogue: 0,0:54:37.52,0:54:38.80,Default,,0,0,0,,本质上是一样的 Dialogue: 0,0:54:39.09,0:54:42.26,Default,,0,0,0,,而“if”和“COND”则是—— Dialogue: 0,0:54:42.30,0:54:44.45,Default,,0,0,0,,你可以把“COND”当做“if”的语法糖 Dialogue: 0,0:54:44.99,0:54:47.36,Default,,0,0,0,,或者“if”是“COND”的语法糖 Dialogue: 0,0:54:47.39,0:54:48.65,Default,,0,0,0,,这没什么区别 Dialogue: 0,0:54:49.21,0:54:51.35,Default,,0,0,0,,Lisp系统的设计者会从中会选择一个 Dialogue: 0,0:54:51.39,0:54:52.97,Default,,0,0,0,,然后依照这个来实现另外一个 Dialogue: 0,0:54:53.15,0:54:54.67,Default,,0,0,0,,你首先实现哪一个都无所谓 Dialogue: 0,0:55:02.27,0:55:05.36,Default,,0,0,0,,让我们停下来 解决几点疑问 Dialogue: 0,0:55:05.69,0:55:10.08,Default,,0,0,0,,为什么我有时用define时 Dialogue: 0,0:55:11.09,0:55:14.75,Default,,0,0,0,,我在这里使用了一个左括号 Dialogue: 0,0:55:14.81,0:55:16.45,Default,,0,0,0,,输入 define (XXX Dialogue: 0,0:55:16.86,0:55:20.81,Default,,0,0,0,,而有时我这样写时却没加左括号 Dialogue: 0,0:55:22.06,0:55:27.23,Default,,0,0,0,,是因为你所见的 Dialogue: 0,0:55:27.26,0:55:29.41,Default,,0,0,0,,这种“define”表达式 Dialogue: 0,0:55:29.47,0:55:32.13,Default,,0,0,0,,对于定义过程来讲是非常特殊 Dialogue: 0,0:55:33.61,0:55:40.21,Default,,0,0,0,,再次强调 这实际上是说我定义这个叫square的符号为这个 Dialogue: 0,0:55:41.45,0:55:45.98,Default,,0,0,0,,你所知道的则是 你先写一个“define” Dialogue: 0,0:55:47.15,0:55:50.06,Default,,0,0,0,,然后你再写一个符号 没有左括号 Dialogue: 0,0:55:50.17,0:55:51.49,Default,,0,0,0,,这是你将要定义的符号 Dialogue: 0,0:55:52.08,0:55:53.70,Default,,0,0,0,,这又是你要将其定义为什么 Dialogue: 0,0:55:54.65,0:55:57.55,Default,,0,0,0,,就像这儿和这儿 Dialogue: 0,0:55:57.61,0:56:00.29,Default,,0,0,0,,这是“define”的基本使用方法 Dialogue: 0,0:56:01.12,0:56:03.65,Default,,0,0,0,,然而 这种特殊的语法技巧 Dialogue: 0,0:56:04.29,0:56:07.04,Default,,0,0,0,,使得你可以定义像这样的过程 Dialogue: 0,0:56:08.17,0:56:11.49,Default,,0,0,0,,因此区别就在于你是否定义了一个过程 Dialogue: 0,0:56:12.91,0:56:37.60,Default,,0,0,0,,[音乐] Dialogue: 0,0:56:38.05,0:56:41.98,Default,,0,0,0,,信不信由你 你们已经学了足够多的Lisp的知识了 Dialogue: 0,0:56:42.78,0:56:45.42,Default,,0,0,0,,现在你基本上可以编写 Dialogue: 0,0:56:46.25,0:56:49.63,Default,,0,0,0,,FORTRAN、Basic或者其它语言中一样的 Dialogue: 0,0:56:49.66,0:56:51.01,Default,,0,0,0,,数值计算过程了 Dialogue: 0,0:56:52.05,0:56:54.76,Default,,0,0,0,,或许你会说 这不可能 Dialogue: 0,0:56:54.81,0:56:56.65,Default,,0,0,0,,因为你知道这些语言有 Dialogue: 0,0:56:56.65,0:57:00.22,Default,,0,0,0,,像“for”语句和“do-until-whil”语句的东西 Dialogue: 0,0:57:00.99,0:57:04.59,Default,,0,0,0,,实际上这些我们一点也用不着 Dialogue: 0,0:57:05.05,0:57:07.13,Default,,0,0,0,,本课中我们一点也不会使用这些东西 Dialogue: 0,0:57:08.25,0:57:10.16,Default,,0,0,0,,我给你们来个下马威 Dialogue: 0,0:57:10.25,0:57:13.61,Default,,0,0,0,,回过头来看看平方根 Dialogue: 0,0:57:13.65,0:57:19.03,Default,,0,0,0,,让我们看看亚历山大的Heron提出的平方根算法 Dialogue: 0,0:57:19.09,0:57:19.97,Default,,0,0,0,,想想它是怎么说的 Dialogue: 0,0:57:20.06,0:57:23.67,Default,,0,0,0,,算法说 为了找到X的平方根的近似值 Dialogue: 0,0:57:25.07,0:57:26.16,Default,,0,0,0,,你做出猜测 Dialogue: 0,0:57:27.45,0:57:31.88,Default,,0,0,0,,然后通过取guess和X/guess的平均数来改进猜测 Dialogue: 0,0:57:32.94,0:57:36.06,Default,,0,0,0,,你不断改进猜测 直到这个猜测足够好 Dialogue: 0,0:57:36.72,0:57:38.43,Default,,0,0,0,,我已经提到过这种想法 Dialogue: 0,0:57:38.56,0:57:42.24,Default,,0,0,0,,这种想法是说 如果你最初采用的猜测 Dialogue: 0,0:57:43.04,0:57:46.91,Default,,0,0,0,,真真切切的等于X的平方根 Dialogue: 0,0:57:47.15,0:57:50.06,Default,,0,0,0,,那么G就会等于X/G Dialogue: 0,0:57:52.89,0:57:55.33,Default,,0,0,0,,如果你算出平方根 对其取平均数并不会改变它 Dialogue: 0,0:57:55.69,0:57:59.62,Default,,0,0,0,,如果你所采用的G比X的平方根大 Dialogue: 0,0:58:00.38,0:58:02.94,Default,,0,0,0,,那么X/G就会比X的平方根小 Dialogue: 0,0:58:03.21,0:58:05.37,Default,,0,0,0,,因此当你取G与X/G的平均值时 Dialogue: 0,0:58:05.63,0:58:07.57,Default,,0,0,0,,就得到了两者之间的某数 Dialogue: 0,0:58:08.96,0:58:12.95,Default,,0,0,0,,同理 若你采用的G过小 答案则会过大 Dialogue: 0,0:58:13.12,0:58:14.81,Default,,0,0,0,,如果你采用了一个太大的G Dialogue: 0,0:58:16.32,0:58:18.06,Default,,0,0,0,,如果你的G比X的平方根还要大的话 Dialogue: 0,0:58:18.08,0:58:20.35,Default,,0,0,0,,X/G就会比X的平方根还要小 Dialogue: 0,0:58:21.23,0:58:23.65,Default,,0,0,0,,因此取平均值使得你总可以得到两者间的某数 Dialogue: 0,0:58:24.53,0:58:28.13,Default,,0,0,0,,这不是毫无意义的 它表明 Dialogue: 0,0:58:28.17,0:58:31.76,Default,,0,0,0,,事实上 如果G只差X的平方根一点的话 Dialogue: 0,0:58:31.81,0:58:37.99,Default,,0,0,0,,G和X/G的平均值就会慢慢的向X的平方根靠近 Dialogue: 0,0:58:38.03,0:58:38.99,Default,,0,0,0,,只要你不断的这样做 Dialogue: 0,0:58:39.42,0:58:41.18,Default,,0,0,0,,最终就可以不断地靠近 Dialogue: 0,0:58:41.71,0:58:42.85,Default,,0,0,0,,另外一个事实则是 Dialogue: 0,0:58:43.02,0:58:47.65,Default,,0,0,0,,你总可以使用1作为一个初始猜测值来开始计算 Dialogue: 0,0:58:49.23,0:58:51.35,Default,,0,0,0,,它总是朝X的平方根聚拢 Dialogue: 0,0:58:52.24,0:58:56.77,Default,,0,0,0,,这就是亚历山大的Heron的连续求平均值法 Dialogue: 0,0:58:56.81,0:58:59.21,Default,,0,0,0,,让我们在Lisp中实现 Dialogue: 0,0:59:00.57,0:59:02.61,Default,,0,0,0,,中心思想是 Dialogue: 0,0:59:02.65,0:59:07.19,Default,,0,0,0,,尝试将guess作为X的平方根的一个猜想意味着什么 Dialogue: 0,0:59:08.30,0:59:09.37,Default,,0,0,0,,我来编码 Dialogue: 0,0:59:09.79,0:59:25.02,Default,,0,0,0,,定义(try guess x) Dialogue: 0,0:59:26.45,0:59:28.24,Default,,0,0,0,,我们该如何做 我们会说 Dialogue: 0,0:59:28.29,0:59:45.26,Default,,0,0,0,,如果猜测精确到可以作为X的平方根 Dialogue: 0,0:59:46.54,0:59:49.52,Default,,0,0,0,,那么我们就可以将这个猜测作为答案 Dialogue: 0,0:59:51.61,0:59:57.01,Default,,0,0,0,,否则 我们就会尝试改进猜测 Dialogue: 0,0:59:58.19,1:00:04.24,Default,,0,0,0,,我们将通过改进这个猜测来作为X的平方根 Dialogue: 0,1:00:05.26,1:00:09.33,Default,,0,0,0,,并尝试是否为X平方根 Dialogue: 0,1:00:09.36,1:00:12.96,Default,,0,0,0,,闭合try 闭合if 闭合define Dialogue: 0,1:00:13.31,1:00:14.81,Default,,0,0,0,,这就是我们如何尝试一个猜测 Dialogue: 0,1:00:15.85,1:00:17.60,Default,,0,0,0,,然后 这个过程的下一步是说 Dialogue: 0,1:00:17.73,1:00:21.90,Default,,0,0,0,,为了计算平方根 Dialogue: 0,1:00:21.93,1:00:30.17,Default,,0,0,0,,定义计算X的平方根为 Dialogue: 0,1:00:30.80,1:00:35.79,Default,,0,0,0,,从1作为X的平方根的一个猜测开始尝试 Dialogue: 0,1:00:37.42,1:00:39.59,Default,,0,0,0,,我们必须定义一些其它的东西 Dialogue: 0,1:00:40.08,1:00:43.36,Default,,0,0,0,,我们必须说明 一个猜测如何才叫“足够好” Dialogue: 0,1:00:43.84,1:00:45.29,Default,,0,0,0,,我们又该如何改进这个猜测 Dialogue: 0,1:00:45.85,1:00:47.10,Default,,0,0,0,,那么让我们来看看 Dialogue: 0,1:00:47.39,1:00:54.24,Default,,0,0,0,,而改进一个X的平方根的一个猜测的算法则是 Dialogue: 0,1:00:54.64,1:00:57.18,Default,,0,0,0,,取平均数 Dialogue: 0,1:00:57.18,1:01:02.16,Default,,0,0,0,,我们取guess和X/guess的平均数 Dialogue: 0,1:01:02.99,1:01:04.57,Default,,0,0,0,,这就是我们如何改进一个猜测 Dialogue: 0,1:01:05.85,1:01:08.80,Default,,0,0,0,,为了确定一个猜测是否足够精确 我们需要做一下规定 Dialogue: 0,1:01:08.86,1:01:11.36,Default,,0,0,0,,假设这个是X的平方根的一个猜测 Dialogue: 0,1:01:11.37,1:01:14.03,Default,,0,0,0,,你可能做的一件事就是 Dialogue: 0,1:01:14.06,1:01:16.07,Default,,0,0,0,,当你采用这个猜测并将其平方 Dialogue: 0,1:01:16.64,1:01:18.41,Default,,0,0,0,,你会得到一个非常接近于X的数 Dialogue: 0,1:01:18.59,1:01:21.10,Default,,0,0,0,,而表达这个想法的一种方式是 Dialogue: 0,1:01:21.12,1:01:24.31,Default,,0,0,0,,我们用X减去guess的平方 Dialogue: 0,1:01:25.15,1:01:27.15,Default,,0,0,0,,并且确认所得结果的绝对值是否 Dialogue: 0,1:01:27.20,1:01:32.05,Default,,0,0,0,,比一个由你规定的很小的数还要小 Dialogue: 0,1:01:34.70,1:01:41.42,Default,,0,0,0,,因此 我们就有了计算X的平方根的一整套过程 Dialogue: 0,1:01:41.47,1:01:43.53,Default,,0,0,0,,我们再来深入观察一下这个结构 Dialogue: 0,1:01:47.84,1:01:49.12,Default,,0,0,0,,我搞定了整件事 Dialogue: 0,1:01:49.15,1:01:55.44,Default,,0,0,0,,我有一个用于计算X的平方根的记号 Dialogue: 0,1:01:55.53,1:01:56.88,Default,,0,0,0,,这是一种模块 Dialogue: 0,1:01:57.05,1:01:58.46,Default,,0,0,0,,也是一种黑盒 Dialogue: 0,1:01:58.72,1:02:08.02,Default,,0,0,0,,它的定义依赖于如何尝试将一个猜测值作为X的平方根 Dialogue: 0,1:02:09.31,1:02:14.10,Default,,0,0,0,,定义try是用来 Dialogue: 0,1:02:14.61,1:02:18.03,Default,,0,0,0,,确认某数是否足够精确以及如何去改进该数 Dialogue: 0,1:02:18.73,1:02:19.68,Default,,0,0,0,,这是good-enogh? Dialogue: 0,1:02:19.89,1:02:28.85,Default,,0,0,0,,try的定义依赖于good-enough?和improve Dialogue: 0,1:02:30.96,1:02:32.56,Default,,0,0,0,,让我们来看看我填入了些什么 Dialogue: 0,1:02:32.71,1:02:34.29,Default,,0,0,0,,如果我向下拓展这棵树 Dialogue: 0,1:02:34.73,1:02:38.49,Default,,0,0,0,,good-enough?的定义依赖于abs和square Dialogue: 0,1:02:40.97,1:02:44.13,Default,,0,0,0,,而improve的定义依赖于averaging Dialogue: 0,1:02:45.17,1:02:46.70,Default,,0,0,0,,而其它的都是一些基本运算符 Dialogue: 0,1:02:46.72,1:02:48.88,Default,,0,0,0,,平方根的定义依赖于try Dialogue: 0,1:02:48.88,1:02:53.31,Default,,0,0,0,,try的定义依赖于good-enough?和improve Dialogue: 0,1:02:54.01,1:02:55.39,Default,,0,0,0,,甚至依赖于try本身 Dialogue: 0,1:02:55.58,1:03:00.86,Default,,0,0,0,,因此try也按照它如何应用于自身而进行定义 Dialogue: 0,1:03:02.75,1:03:04.72,Default,,0,0,0,,额 这可能会使你有点糊涂 Dialogue: 0,1:03:04.72,1:03:08.16,Default,,0,0,0,,你的高中几何老师或许告诉过你 Dialogue: 0,1:03:08.67,1:03:12.57,Default,,0,0,0,,用一个东西自己去定义自己是很不对的 Dialogue: 0,1:03:12.88,1:03:13.92,Default,,0,0,0,,因为这根本行不通 Dialogue: 0,1:03:13.92,1:03:14.72,Default,,0,0,0,,这(种说法)是错的 Dialogue: 0,1:03:16.03,1:03:19.68,Default,,0,0,0,,有时候用一个东西自己来定义自己非常有意义 Dialogue: 0,1:03:20.16,1:03:24.38,Default,,0,0,0,,我们来看看这个例子 Dialogue: 0,1:03:24.38,1:03:26.89,Default,,0,0,0,,假设我问Lisp:2的平方根是多少 Dialogue: 0,1:03:26.91,1:03:30.33,Default,,0,0,0,,我们可以写出它究竟是什么意思 Dialogue: 0,1:03:32.65,1:03:34.67,Default,,0,0,0,,2的平方根是什么意思 Dialogue: 0,1:03:35.79,1:03:43.61,Default,,0,0,0,,意思就是我将用1作为2的平方根的一个猜测 Dialogue: 0,1:03:46.97,1:03:50.92,Default,,0,0,0,,然后我考虑 对于2的平方根来说 1是一个足够好的猜测么 Dialogue: 0,1:03:51.65,1:03:53.69,Default,,0,0,0,,这取决于good-enough?是如何判断的 Dialogue: 0,1:03:54.61,1:03:56.56,Default,,0,0,0,,本例中 good-enough?会说 Dialogue: 0,1:03:56.65,1:03:59.05,Default,,0,0,0,,不 对于2的平方根来说 1不是一个足够好的猜测 Dialogue: 0,1:03:59.79,1:04:08.22,Default,,0,0,0,,因此我会继续说 我试试一个改进值 Dialogue: 0,1:04:08.64,1:04:12.63,Default,,0,0,0,,改进猜测值1 Dialogue: 0,1:04:15.15,1:04:17.46,Default,,0,0,0,,然后将其作为2的平方根的一个猜测 Dialogue: 0,1:04:19.13,1:04:22.07,Default,,0,0,0,,改进猜测值1用作2的平方根 Dialogue: 0,1:04:22.09,1:04:25.08,Default,,0,0,0,,也就是说我取1和2/1的平均值 Dialogue: 0,1:04:27.10,1:04:29.10,Default,,0,0,0,,因此我们将取平均数 Dialogue: 0,1:04:29.58,1:04:39.44,Default,,0,0,0,,这段代码将会取1和2/1的平均数 Dialogue: 0,1:04:40.83,1:04:42.75,Default,,0,0,0,,那么这段代码 Dialogue: 0,1:04:43.85,1:04:46.72,Default,,0,0,0,,我算算 结果是1.5 Dialogue: 0,1:04:49.07,1:04:54.40,Default,,0,0,0,,因此这个(sqrt 2)还原到(try 1 2) Dialogue: 0,1:04:54.56,1:05:04.83,Default,,0,0,0,,然后还原到(try 1.5 2) Dialogue: 0,1:05:06.03,1:05:08.06,Default,,0,0,0,,因此这行得通 Dialogue: 0,1:05:08.11,1:05:09.52,Default,,0,0,0,,让我们看下剩下的步骤 Dialogue: 0,1:05:09.73,1:05:15.00,Default,,0,0,0,,如果我尝试1.5 则会还原到 Dialogue: 0,1:05:15.01,1:05:19.05,Default,,0,0,0,,1.5作为2的平方根的猜测 并不是足够好 Dialogue: 0,1:05:20.22,1:05:22.00,Default,,0,0,0,,然后又还原到 Dialogue: 0,1:05:22.01,1:05:26.17,Default,,0,0,0,,(try (average 1.5 (/ 2 1.5))) Dialogue: 0,1:05:28.29,1:05:30.37,Default,,0,0,0,,平均值是1.333 Dialogue: 0,1:05:31.18,1:05:35.24,Default,,0,0,0,,然后整个事又还原到(try 1.3333 2) Dialogue: 0,1:05:35.28,1:05:36.06,Default,,0,0,0,,如此进行下去 Dialogue: 0,1:05:38.01,1:05:41.66,Default,,0,0,0,,然后又还原到(good-enough? 1.4)或者其它的 Dialogue: 0,1:05:41.73,1:05:44.47,Default,,0,0,0,,然后这个(步骤)会持续进行到 Dialogue: 0,1:05:44.85,1:05:47.92,Default,,0,0,0,,good-enough?认为足够好了才停止 Dialogue: 0,1:05:47.97,1:05:51.28,Default,,0,0,0,,本例中 是1.4242或者其它的东西 Dialogue: 0,1:05:52.51,1:05:56.05,Default,,0,0,0,,因此这个这个过程运行得非常完美 Dialogue: 0,1:05:59.93,1:06:03.10,Default,,0,0,0,,这种定义方法叫做“递归定义” Dialogue: 0,1:06:14.40,1:06:20.96,Default,,0,0,0,,进行递归定义将会给你带来无穷威力 Dialogue: 0,1:06:21.95,1:06:23.05,Default,,0,0,0,,之前我已提到过 Dialogue: 0,1:06:23.09,1:06:27.21,Default,,0,0,0,,递归定义可以在不增加任何负担的前提下 Dialogue: 0,1:06:27.25,1:06:28.83,Default,,0,0,0,,仅仅通过调用过程 在达到条件之前 Dialogue: 0,1:06:29.73,1:06:33.66,Default,,0,0,0,,完成无限次的计算 Dialogue: 0,1:06:35.97,1:06:37.47,Default,,0,0,0,,还有一点要说明的 Dialogue: 0,1:06:37.71,1:06:44.21,Default,,0,0,0,,我再在这里给你们演示另外一种平方根的定义方法 Dialogue: 0,1:06:44.43,1:06:48.16,Default,,0,0,0,,这两种方法看起来像是一样的 Dialogue: 0,1:06:48.40,1:06:51.49,Default,,0,0,0,,在这儿 我把improve、good-enough?、try的定义 Dialogue: 0,1:06:51.52,1:06:56.16,Default,,0,0,0,,全都封装在了sqrt里面 Dialogue: 0,1:06:56.75,1:07:00.99,Default,,0,0,0,,因此实际上 我们构建了一个平方根盒子 Dialogue: 0,1:07:01.81,1:07:08.53,Default,,0,0,0,,我构建了一个其它人可以使用的平方根盒子 Dialogue: 0,1:07:08.57,1:07:11.47,Default,,0,0,0,,它们输入36 然后(盒子)输出6 Dialogue: 0,1:07:11.81,1:07:13.83,Default,,0,0,0,,但是 盒子里面封装的过程 Dialogue: 0,1:07:14.16,1:07:23.85,Default,,0,0,0,,就是try、good-enough?和improve的定义 Dialogue: 0,1:07:26.78,1:07:28.35,Default,,0,0,0,,它们都隐藏在盒子里面 Dialogue: 0,1:07:28.40,1:07:30.76,Default,,0,0,0,,这样做是因为 Dialogue: 0,1:07:31.18,1:07:32.85,Default,,0,0,0,,如果有人正在使用这个平方根 Dialogue: 0,1:07:33.21,1:07:34.73,Default,,0,0,0,,如果George正在使用这个平方根 Dialogue: 0,1:07:34.75,1:07:37.36,Default,,0,0,0,,George并不会关心 Dialogue: 0,1:07:38.29,1:07:40.03,Default,,0,0,0,,当我在实现平方根时 Dialogue: 0,1:07:40.21,1:07:44.45,Default,,0,0,0,,我定义了盒子内的那些try、good-enough?和improve过程 Dialogue: 0,1:07:46.40,1:07:49.33,Default,,0,0,0,,事实上 Harry可能会实现一个也具有 Dialogue: 0,1:07:49.37,1:07:50.96,Default,,0,0,0,,try、good-enough?和improve的立方根盒子 Dialogue: 0,1:07:51.44,1:07:53.34,Default,,0,0,0,,因此 为了不让整个系统变得混乱 Dialogue: 0,1:07:53.36,1:07:57.66,Default,,0,0,0,,Harry最好把这些内部过程封装在它的立方根过程里 Dialogue: 0,1:07:58.40,1:08:00.06,Default,,0,0,0,,这个叫做块结构 Dialogue: 0,1:08:00.32,1:08:08.96,Default,,0,0,0,,这是把东西打包到定义内部的一种方法 Dialogue: 0,1:08:09.97,1:08:12.96,Default,,0,0,0,,让我们回过头来再看看 Dialogue: 0,1:08:13.12,1:08:18.57,Default,,0,0,0,,这种过程的定义读作 定义“sqrt”为 Dialogue: 0,1:08:19.87,1:08:21.84,Default,,0,0,0,,那么 在其内部 Dialogue: 0,1:08:22.13,1:08:25.49,Default,,0,0,0,,我们已有improve的定义 Dialogue: 0,1:08:25.56,1:08:28.88,Default,,0,0,0,,我们已有good-enough?和try的定义 Dialogue: 0,1:08:29.73,1:08:32.38,Default,,0,0,0,,以及这些定义的实体 Dialogue: 0,1:08:32.48,1:08:35.07,Default,,0,0,0,,我求平方根的定义实体是从1开始尝试 Dialogue: 0,1:08:36.08,1:08:39.33,Default,,0,0,0,,注意这里 我不必将X当做参数传递 Dialogue: 0,1:08:39.87,1:08:42.32,Default,,0,0,0,,因为它们都在平方根内部 Dialogue: 0,1:08:42.84,1:08:44.65,Default,,0,0,0,,它相当于已知这个X了 Dialogue: 0,1:08:54.06,1:08:56.37,Default,,0,0,0,,我来总结下 Dialogue: 0,1:08:56.49,1:08:59.49,Default,,0,0,0,,我们从表述指令性知识 Dialogue: 0,1:08:59.51,1:09:03.18,Default,,0,0,0,,开始学习 Dialogue: 0,1:09:04.99,1:09:09.74,Default,,0,0,0,,这张幻灯片总结了一些关于Lisp的知识 Dialogue: 0,1:09:09.74,1:09:15.12,Default,,0,0,0,,我们从基本元素如“+”和“*”开始 Dialogue: 0,1:09:15.85,1:09:19.50,Default,,0,0,0,,一些用于测试某物小于或等于的谓词 Dialogue: 0,1:09:19.52,1:09:22.99,Default,,0,0,0,,事实上 我们正在使用的系统掩盖了很多细节 Dialogue: 0,1:09:23.02,1:09:25.85,Default,,0,0,0,,这些并不是系统的基本元素 但这无所谓 Dialogue: 0,1:09:26.62,1:09:28.59,Default,,0,0,0,,重要的是我们会把它们当作是基本元素 Dialogue: 0,1:09:28.61,1:09:29.81,Default,,0,0,0,,我们不会去研究系统的内部 Dialogue: 0,1:09:30.29,1:09:33.15,Default,,0,0,0,,我们也有一些基本数据和一些数 Dialogue: 0,1:09:34.62,1:09:37.66,Default,,0,0,0,,我们学习了合成的手段 组合的手段 Dialogue: 0,1:09:37.74,1:09:41.37,Default,,0,0,0,,用运算符和运算对象合成函数 Dialogue: 0,1:09:41.41,1:09:43.76,Default,,0,0,0,,和构建组合式的基本方法 Dialogue: 0,1:09:44.81,1:09:48.43,Default,,0,0,0,,还有一些像是“COND”、“if”和“define”的东西 Dialogue: 0,1:09:51.29,1:09:53.69,Default,,0,0,0,,具体来说 关于“define”的重点则是 Dialogue: 0,1:09:53.87,1:09:55.71,Default,,0,0,0,,它是一种进行抽象的方法 Dialogue: 0,1:09:55.73,1:09:57.70,Default,,0,0,0,,它是我们为某物命名的方法 Dialogue: 0,1:09:57.79,1:10:00.30,Default,,0,0,0,,我们之前提到过 从这里也可以看出来 Dialogue: 0,1:10:01.57,1:10:06.28,Default,,0,0,0,,有时候 我们需要研究如何通过组合基本数据来得到复合数据 Dialogue: 0,1:10:06.56,1:10:12.03,Default,,0,0,0,,以及如何抽象数据 使得你可以在一个更大的环境中 Dialogue: 0,1:10:12.06,1:10:13.07,Default,,0,0,0,,将其当作基本数据使用 Dialogue: 0,1:10:13.90,1:10:15.87,Default,,0,0,0,,这也是我们的目的所在 Dialogue: 0,1:10:16.38,1:10:22.05,Default,,0,0,0,,在我们讨论这个问题之前 下节课我们首先将会讨论 Dialogue: 0,1:10:23.26,1:10:26.76,Default,,0,0,0,,我们编写的过程与机器内部 Dialogue: 0,1:10:26.88,1:10:30.77,Default,,0,0,0,,进程之间的联系 Dialogue: 0,1:10:32.14,1:10:35.98,Default,,0,0,0,,接着 我们将跳出小规模的计算问题 Dialogue: 0,1:10:36.38,1:10:39.77,Default,,0,0,0,,来学习如何发挥Lisp的威力 Dialogue: 0,1:10:40.08,1:10:44.15,Default,,0,0,0,,来解决更加通用的计算问题 Dialogue: 0,1:10:44.81,1:10:46.17,Default,,0,0,0,,好了 大家还有什么问题么 Dialogue: 0,1:10:46.75,1:10:52.27,Default,,0,0,0,,学生:在定义A时 如果我们用一个括号将A括起来 Dialogue: 0,1:10:52.32,1:10:53.50,Default,,0,0,0,,会与不使用括号不同么? Dialogue: 0,1:10:53.60,1:10:56.88,Default,,0,0,0,,教授:如果我这样写 Dialogue: 0,1:10:57.53,1:11:02.13,Default,,0,0,0,,我则会是定义一个过程并命名为A Dialogue: 0,1:11:03.21,1:11:06.85,Default,,0,0,0,,本例中 这个过程没有参数 Dialogue: 0,1:11:06.85,1:11:09.61,Default,,0,0,0,,而当我运行它 则会返回5乘以5 Dialogue: 0,1:11:11.07,1:11:12.29,Default,,0,0,0,,学生:它们俩完成了相同的事 Dialogue: 0,1:11:12.32,1:11:13.92,Default,,0,0,0,,但本质上是否相同? Dialogue: 0,1:11:14.05,1:11:16.63,Default,,0,0,0,,教授:好 的确会有不同 之前的那一个 Dialogue: 0,1:11:17.02,1:11:18.35,Default,,0,0,0,,我还是在这里写清楚一点吧 Dialogue: 0,1:11:19.13,1:11:23.44,Default,,0,0,0,,我们还是把这个叫做A Dialogue: 0,1:11:24.13,1:11:27.76,Default,,0,0,0,,作为对比 我们假装这里有一个 Dialogue: 0,1:11:27.79,1:11:37.56,Default,,0,0,0,,我定义D为5乘以5 Dialogue: 0,1:11:40.22,1:11:41.57,Default,,0,0,0,,这两者的区别则是 Dialogue: 0,1:11:41.96,1:11:44.24,Default,,0,0,0,,让我们看看它们在Lisp解释器中是怎样的 Dialogue: 0,1:11:45.74,1:11:49.13,Default,,0,0,0,,我在Lisp中键入A 返回25 Dialogue: 0,1:11:52.83,1:11:57.81,Default,,0,0,0,,如果我仅仅键入D Dialogue: 0,1:11:58.49,1:12:05.55,Default,,0,0,0,,Lisp返回复合过程D Dialogue: 0,1:12:07.12,1:12:09.13,Default,,0,0,0,,因为D就是一个过程 Dialogue: 0,1:12:09.69,1:12:12.59,Default,,0,0,0,,我可以运行D 我可以问运行D的结果是什么 Dialogue: 0,1:12:12.59,1:12:15.23,Default,,0,0,0,,这是一个没有运算数的组合式 Dialogue: 0,1:12:16.45,1:12:19.07,Default,,0,0,0,,我考虑到它没有运算数 所以我在D后面没有键入任何东西 Dialogue: 0,1:12:19.39,1:12:21.34,Default,,0,0,0,,Lisp则会说结果是25 Dialogue: 0,1:12:23.01,1:12:29.52,Default,,0,0,0,,我再说周全一点 如果我键入 A的运行结果是多少 Dialogue: 0,1:12:29.54,1:12:30.57,Default,,0,0,0,,只能得到一个错误 Dialogue: 0,1:12:31.79,1:12:35.29,Default,,0,0,0,,跟这里的错误一样 Dialogue: 0,1:12:35.33,1:12:40.51,Default,,0,0,0,,这个错误是因为 A的值——25 Dialogue: 0,1:12:40.56,1:12:43.24,Default,,0,0,0,,并不是我可以应用于某物的运算符 Dialogue: 0,1:12:43.36,1:12:55.05,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:12:43.37,1:12:55.05,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/FoOTOo/Learning-SICP Dialogue: 0,1:12:49.11,1:12:51.11,Default,,0,0,0,, ================================================ FILE: Ass/lec1a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal PlayResX: 640 PlayResY: 480 Scroll Position: 982 Active Line: 988 Audio URI: lec1a_Rerip_remux.mp4 Video Zoom Percent: 0.75 Video File: lec1a_Rerip_remux.mp4 Video Aspect Ratio: c1.33333 Video Position: 124661 Last Style Storage: Default YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Default,雅黑宋体,24,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,35,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.01,0:00:03.77,Declare,,0,0,0,,{\fad(200,200)}哈尔滨工业大学 IBM技术中心 Dialogue: 0,0:00:00.01,0:00:03.77,Declare,,0,0,0,,{\fad(200,200)\an2}倾情制作 Dialogue: 0,0:00:04.08,0:00:11.36,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:04.08,0:00:11.05,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}字幕&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.08,0:00:11.05,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}后期&特效\N蔡钟毓\N(JohnTitor) Dialogue: 0,0:00:04.08,0:00:11.06,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N匿名 Dialogue: 0,0:00:04.08,0:00:11.06,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:14.71,0:00:17.89,Default,,0,0,0,,欢迎大家来一起学习这门计算机科学的基础课程 Dialogue: 0,0:00:28.40,0:00:29.85,Default,,0,0,0,,事实上 以这样的方式来表述并不恰当 Dialogue: 0,0:00:29.85,0:00:32.34,Default,,0,0,0,,于此来说 计算机科学是个糟糕的名字 Dialogue: 0,0:00:32.83,0:00:34.30,Default,,0,0,0,,首先 它不算是一门科学 Dialogue: 0,0:00:35.92,0:00:39.47,Default,,0,0,0,,它更应该被称为工程或者是艺术 Dialogue: 0,0:00:40.09,0:00:42.91,Default,,0,0,0,,但我们实际上会发现 这个所谓的计算机科学 Dialogue: 0,0:00:42.93,0:00:44.97,Default,,0,0,0,,却与魔法一样的有众多神奇之处 Dialogue: 0,0:00:45.01,0:00:46.35,Default,,0,0,0,,这些将会在课程中一一体现 Dialogue: 0,0:00:47.28,0:00:48.22,Default,,0,0,0,,所以 不能称其为一门科学 Dialogue: 0,0:00:49.09,0:00:52.30,Default,,0,0,0,,这门学科和“计算机”也并非紧密相关 Dialogue: 0,0:00:53.39,0:00:55.47,Default,,0,0,0,,类似的 就像我们说 Dialogue: 0,0:00:55.47,0:01:00.05,Default,,0,0,0,,物理学中并不仅仅有关粒子加速器 Dialogue: 0,0:01:00.80,0:01:05.58,Default,,0,0,0,,生物学中并不全然是显微镜和培养皿一样 Dialogue: 0,0:01:06.46,0:01:10.25,Default,,0,0,0,,同理 Dialogue: 0,0:01:10.31,0:01:14.88,Default,,0,0,0,,几何学中也并不全是介绍如何使用测量仪器 Dialogue: 0,0:01:16.48,0:01:19.01,Default,,0,0,0,,事实上 计算机科学和几何学 Dialogue: 0,0:01:19.33,0:01:21.45,Default,,0,0,0,,有很多共性 Dialogue: 0,0:01:21.45,0:01:22.66,Default,,0,0,0,,首先 几何学 Dialogue: 0,0:01:23.02,0:01:24.98,Default,,0,0,0,,只是另一个有个糟糕名字的学科 Dialogue: 0,0:01:25.58,0:01:27.85,Default,,0,0,0,,这个名字来自于Gaia 意为土地 Dialogue: 0,0:01:27.90,0:01:29.09,Default,,0,0,0,,以及metron 意为测量 Dialogue: 0,0:01:29.82,0:01:33.39,Default,,0,0,0,,几何学最初意为测地或者勘探 Dialogue: 0,0:01:34.37,0:01:36.89,Default,,0,0,0,,这是因为数千年前的埃及祭司 Dialogue: 0,0:01:37.69,0:01:41.69,Default,,0,0,0,,为了计算如何去修复年年被尼罗河的洪水 Dialogue: 0,0:01:42.59,0:01:46.33,Default,,0,0,0,,所毁坏的牧田边界 Dialogue: 0,0:01:46.35,0:01:48.69,Default,,0,0,0,,而建立了几何学基础 Dialogue: 0,0:01:49.47,0:01:50.65,Default,,0,0,0,,而对出于这个目的的埃及人来说 Dialogue: 0,0:01:50.65,0:01:53.93,Default,,0,0,0,,几何学的确是掌握对测量仪器的使用 Dialogue: 0,0:01:55.63,0:01:58.55,Default,,0,0,0,,现在 我们以为计算机科学就是介绍计算机的使用 Dialogue: 0,0:01:58.57,0:02:02.49,Default,,0,0,0,,就正如埃及人认为 Dialogue: 0,0:02:02.51,0:02:04.10,Default,,0,0,0,,几何学是介绍如何使用测量仪器的 Dialogue: 0,0:02:04.59,0:02:07.37,Default,,0,0,0,,换句话说 任何一门学科起步的时候 Dialogue: 0,0:02:07.39,0:02:09.86,Default,,0,0,0,,你都对它了解不深 Dialogue: 0,0:02:11.10,0:02:16.64,Default,,0,0,0,,这很容易使你混淆所做的事与所用之物 Dialogue: 0,0:02:17.65,0:02:20.30,Default,,0,0,0,,确实 就绝对规模来说 Dialogue: 0,0:02:20.30,0:02:24.82,Default,,0,0,0,,我们对计算机科学的实质的了解 Dialogue: 0,0:02:24.83,0:02:27.49,Default,,0,0,0,,比埃及人对几何学的了解还少 Dialogue: 0,0:02:30.25,0:02:32.64,Default,,0,0,0,,那么 我所谓的计算机科学的本质是什么呢 Dialogue: 0,0:02:32.65,0:02:34.41,Default,,0,0,0,,我所谓的几何学本质又是什么呢 Dialogue: 0,0:02:34.41,0:02:36.45,Default,,0,0,0,,看 可以确认的是 古埃及人确实使用测量仪器 Dialogue: 0,0:02:36.46,0:02:37.67,Default,,0,0,0,,并且已经消失多年 Dialogue: 0,0:02:37.69,0:02:41.55,Default,,0,0,0,,但当我们在几千年后回过头来重新审视这段历史 Dialogue: 0,0:02:41.57,0:02:41.85,Default,,0,0,0,,我们会说 Dialogue: 0,0:02:41.87,0:02:43.64,Default,,0,0,0,,天啊 看他们在做什么 Dialogue: 0,0:02:43.71,0:02:45.48,Default,,0,0,0,,他们的工作是多么的重要 Dialogue: 0,0:02:45.62,0:02:50.45,Default,,0,0,0,,已经开始对时间和空间进行形式化表述 Dialogue: 0,0:02:51.58,0:02:57.53,Default,,0,0,0,,并归纳出一套讨论数学真理的形式化方法 Dialogue: 0,0:02:58.01,0:02:59.61,Default,,0,0,0,,这直接导致了公理化方法 Dialogue: 0,0:02:59.61,0:03:02.53,Default,,0,0,0,,以及各种现代数学的产生 Dialogue: 0,0:03:04.16,0:03:06.90,Default,,0,0,0,,同时也指明了一种精确讨论 Dialogue: 0,0:03:07.25,0:03:10.19,Default,,0,0,0,,所谓的描述真理的陈述性知识的方法 Dialogue: 0,0:03:12.45,0:03:16.25,Default,,0,0,0,,与此相似的 我认为未来人们会回过头来审视并说 Dialogue: 0,0:03:16.27,0:03:19.36,Default,,0,0,0,,啊 这些20世纪的原始人 Dialogue: 0,0:03:19.36,0:03:21.20,Default,,0,0,0,,不务正业地玩弄着叫计算机的小玩意 Dialogue: 0,0:03:21.77,0:03:26.25,Default,,0,0,0,,但它们真正在做的是开始学习 Dialogue: 0,0:03:26.25,0:03:32.55,Default,,0,0,0,,如何去对计算过程进行形式化表述 Dialogue: 0,0:03:32.64,0:03:34.13,Default,,0,0,0,,如何去解决问题 Dialogue: 0,0:03:39.02,0:03:51.25,Default,,0,0,0,,并结合两者发展一套对问题处理过程精确表述的方法 Dialogue: 0,0:03:51.76,0:03:56.03,Default,,0,0,0,,这与讨论真理的几何学形成了对照 Dialogue: 0,0:03:56.53,0:03:58.57,Default,,0,0,0,,让我给你们举个例子吧 Dialogue: 0,0:04:02.30,0:04:02.69,Default,,0,0,0,,来瞧瞧 Dialogue: 0,0:04:02.70,0:04:09.82,Default,,0,0,0,,数学中是这样来定义平方根的: Dialogue: 0,0:04:10.09,0:04:14.35,Default,,0,0,0,,定义X的平方根Y是这样一个数 Dialogue: 0,0:04:15.98,0:04:20.38,Default,,0,0,0,,Y的平方等于X 且Y大于等于0 Dialogue: 0,0:04:20.43,0:04:22.50,Default,,0,0,0,,这是一个很好的定义 Dialogue: 0,0:04:22.88,0:04:25.25,Default,,0,0,0,,但它只告诉了你平方根是什么 Dialogue: 0,0:04:25.63,0:04:30.29,Default,,0,0,0,,却没有告诉你如何去求取一个平方根 Dialogue: 0,0:04:31.42,0:04:35.90,Default,,0,0,0,,那么我们将其与一条指令性知识做比较 Dialogue: 0,0:04:37.13,0:04:39.92,Default,,0,0,0,,你如何去求取一个平方根 Dialogue: 0,0:04:39.95,0:04:45.74,Default,,0,0,0,,事实上 这来自于埃及 不太久远的埃及 Dialogue: 0,0:04:45.76,0:04:48.88,Default,,0,0,0,,亚历山大的Heron提出的一个算法 Dialogue: 0,0:04:49.90,0:04:52.77,Default,,0,0,0,,称作连续取均值求平方根法 Dialogue: 0,0:04:52.89,0:04:55.13,Default,,0,0,0,,这个算法是说 Dialogue: 0,0:04:55.15,0:04:58.06,Default,,0,0,0,,为了算出平方根 Dialogue: 0,0:05:03.34,0:05:08.33,Default,,0,0,0,,首先你应该给出一个猜测值guess 并不断改进 Dialogue: 0,0:05:10.19,0:05:11.44,Default,,0,0,0,,改进的方法是通过 Dialogue: 0,0:05:11.45,0:05:13.95,Default,,0,0,0,,不断求猜测值guess与X/guess的平均值 Dialogue: 0,0:05:14.41,0:05:15.60,Default,,0,0,0,,我们稍后将会讨论 Dialogue: 0,0:05:15.61,0:05:17.12,Default,,0,0,0,,为什么这是合理的 Dialogue: 0,0:05:17.14,0:05:19.37,Default,,0,0,0,,通过不断改进 直到它足够精确 Dialogue: 0,0:05:19.73,0:05:20.85,Default,,0,0,0,,这就是实现方法 Dialogue: 0,0:05:20.99,0:05:24.65,Default,,0,0,0,,这也是如何完成一项工作与 Dialogue: 0,0:05:24.72,0:05:27.33,Default,,0,0,0,,其对应的陈述性知识的对照 Dialogue: 0,0:05:28.05,0:05:29.76,Default,,0,0,0,,这就是一个过程 Dialogue: 0,0:05:34.40,0:05:38.25,Default,,0,0,0,,那么 通常来说什么是过程呢? Dialogue: 0,0:05:39.01,0:05:40.14,Default,,0,0,0,,这定义起来非常困难 Dialogue: 0,0:05:40.16,0:05:43.72,Default,,0,0,0,,你可以将它象征性地看成一个活在计算机内 Dialogue: 0,0:05:44.77,0:05:47.33,Default,,0,0,0,,并且可以完成一些操作的精灵 Dialogue: 0,0:05:48.01,0:05:54.11,Default,,0,0,0,,一些被称为程序的规则模式 Dialogue: 0,0:05:54.13,0:05:57.98,Default,,0,0,0,,指导着这类过程的进行 Dialogue: 0,0:06:01.98,0:06:04.73,Default,,0,0,0,,程序可以被认为是符咒 Dialogue: 0,0:06:05.23,0:06:09.40,Default,,0,0,0,,使用程序来控制这些精灵完成一些操作就叫做过程 Dialogue: 0,0:06:10.75,0:06:12.75,Default,,0,0,0,,你们知道人人都需要一门魔法语言 Dialogue: 0,0:06:12.77,0:06:14.55,Default,,0,0,0,,那些魔术师 真正的魔术师 用远古的阿卡狄亚语 Dialogue: 0,0:06:14.57,0:06:18.59,Default,,0,0,0,,或者苏美尔语 或者巴比伦语 或者其它的 Dialogue: 0,0:06:18.62,0:06:20.09,Default,,0,0,0,,而我们将用一门叫Lisp的魔法语言 Dialogue: 0,0:06:20.13,0:06:22.71,Default,,0,0,0,,来召唤出我们的精灵 Dialogue: 0,0:06:24.37,0:06:28.01,Default,,0,0,0,,这门语言是被设计用来 Dialogue: 0,0:06:28.57,0:06:31.84,Default,,0,0,0,,编写如咒语般的程序 来指导过程的进行 Dialogue: 0,0:06:31.87,0:06:33.91,Default,,0,0,0,,学习Lisp非常容易 Dialogue: 0,0:06:33.97,0:06:35.98,Default,,0,0,0,,事实上 我会在几分钟内教会你 Dialogue: 0,0:06:36.00,0:06:37.16,Default,,0,0,0,,整个Lisp Dialogue: 0,0:06:37.37,0:06:38.96,Default,,0,0,0,,及其所有的规则 Dialogue: 0,0:06:40.77,0:06:43.65,Default,,0,0,0,,你不必感到很惊讶 Dialogue: 0,0:06:43.69,0:06:45.87,Default,,0,0,0,,这就像你在学习象棋时 Dialogue: 0,0:06:45.90,0:06:47.01,Default,,0,0,0,,认为象棋的规则十分简单一样 Dialogue: 0,0:06:47.04,0:06:48.13,Default,,0,0,0,,事实也如此 几分钟内 Dialogue: 0,0:06:48.17,0:06:49.70,Default,,0,0,0,,你可以与任何人谈论象棋的规则 Dialogue: 0,0:06:50.81,0:06:52.24,Default,,0,0,0,,但是 这全然不等同于说 Dialogue: 0,0:06:52.25,0:06:55.37,Default,,0,0,0,,你所知道这些规则所蕴含的东西 Dialogue: 0,0:06:55.42,0:06:58.05,Default,,0,0,0,,以及如何利用这些规则去成为象棋大师 Dialogue: 0,0:06:58.49,0:06:59.82,Default,,0,0,0,,Lisp也是如此 Dialogue: 0,0:07:00.41,0:07:02.18,Default,,0,0,0,,我将在几分钟内道清规则 Dialogue: 0,0:07:02.36,0:07:03.55,Default,,0,0,0,,这说起来非常容易 Dialogue: 0,0:07:03.62,0:07:07.09,Default,,0,0,0,,但真正困难的是如何运用这些规则 Dialogue: 0,0:07:07.32,0:07:10.46,Default,,0,0,0,,以及你如何利用这些规则成为编程大师 Dialogue: 0,0:07:12.06,0:07:15.29,Default,,0,0,0,,这些规则的应用将占据我们 Dialogue: 0,0:07:15.31,0:07:18.56,Default,,0,0,0,,余下的课程 甚至更多 Dialogue: 0,0:07:21.45,0:07:23.11,Default,,0,0,0,,所以 在计算机科学中 Dialogue: 0,0:07:24.49,0:07:26.19,Default,,0,0,0,,我们的任务则是 Dialogue: 0,0:07:26.21,0:07:30.58,Default,,0,0,0,,形式化这种如有关“怎么做”的指令性知识 Dialogue: 0,0:07:30.62,0:07:32.10,Default,,0,0,0,,并将之付诸实际 Dialogue: 0,0:07:33.37,0:07:35.39,Default,,0,0,0,,这也便是计算机科学的真正的议题 Dialogue: 0,0:07:35.41,0:07:38.36,Default,,0,0,0,,当然 并不是告诉人们如何去求平方根 Dialogue: 0,0:07:39.09,0:07:40.06,Default,,0,0,0,,因为如果那是计算机科学的全部的的话 Dialogue: 0,0:07:40.09,0:07:41.34,Default,,0,0,0,,就不会有什么大问题了 Dialogue: 0,0:07:41.57,0:07:44.05,Default,,0,0,0,,真正的问题来自于当我们尝试 Dialogue: 0,0:07:44.08,0:07:46.16,Default,,0,0,0,,构建非常非常大的系统时 Dialogue: 0,0:07:46.61,0:07:49.53,Default,,0,0,0,,程序可能会长达数千页 Dialogue: 0,0:07:49.58,0:07:53.98,Default,,0,0,0,,长得没有人能马上将其装入脑中 Dialogue: 0,0:07:54.73,0:07:58.81,Default,,0,0,0,,而使这些得以实现则是因为 Dialogue: 0,0:07:58.86,0:08:18.97,Default,,0,0,0,,我们有在大系统中控制复杂度的技术 Dialogue: 0,0:08:20.30,0:08:22.69,Default,,0,0,0,,这些控制复杂度的技术 Dialogue: 0,0:08:22.72,0:08:24.17,Default,,0,0,0,,正是我们课程所讨论的 Dialogue: 0,0:08:24.65,0:08:25.47,Default,,0,0,0,,从某种意义上来说 Dialogue: 0,0:08:25.50,0:08:27.47,Default,,0,0,0,,这也正是计算机科学的关键所在 Dialogue: 0,0:08:29.63,0:08:31.89,Default,,0,0,0,,这样说听起来或许很奇怪 Dialogue: 0,0:08:31.92,0:08:35.61,Default,,0,0,0,,毕竟 除了计算机科学家外 Dialogue: 0,0:08:35.65,0:08:37.82,Default,,0,0,0,,仍然有很多人在做复杂度控制相关的工作 Dialogue: 0,0:08:37.84,0:08:41.02,Default,,0,0,0,,一个航班就是一个非常复杂的系统 Dialogue: 0,0:08:41.82,0:08:43.79,Default,,0,0,0,,设计它的航空工程师 Dialogue: 0,0:08:44.05,0:08:46.13,Default,,0,0,0,,便在处理这个巨大的复杂度 Dialogue: 0,0:08:47.09,0:08:50.19,Default,,0,0,0,,但这种复杂度又与 Dialogue: 0,0:08:50.75,0:08:52.60,Default,,0,0,0,,计算机科学中的(复杂度)有别 Dialogue: 0,0:08:55.18,0:08:57.73,Default,,0,0,0,,从某种意义上来说 Dialogue: 0,0:08:57.79,0:09:00.09,Default,,0,0,0,,因为计算机科学不是“现实”的 Dialogue: 0,0:09:02.69,0:09:06.62,Default,,0,0,0,,例如 当一名工程师设计物理系统时 Dialogue: 0,0:09:07.14,0:09:08.49,Default,,0,0,0,,这些都是由实在的物理部件构成 Dialogue: 0,0:09:09.40,0:09:11.18,Default,,0,0,0,,负责的该工作的工程师 Dialogue: 0,0:09:11.85,0:09:16.65,Default,,0,0,0,,就得对付系统中的公差、近似值以及噪声 Dialogue: 0,0:09:16.67,0:09:19.02,Default,,0,0,0,,譬如说 作为一名电气工程师 Dialogue: 0,0:09:19.09,0:09:21.71,Default,,0,0,0,,可以很容易的做一个单极放大器 Dialogue: 0,0:09:21.73,0:09:23.03,Default,,0,0,0,,或者是一个双极放大器 Dialogue: 0,0:09:23.41,0:09:25.39,Default,,0,0,0,,也可想象将其大量串联 Dialogue: 0,0:09:25.45,0:09:26.91,Default,,0,0,0,,来建造一个百万极的放大器 Dialogue: 0,0:09:26.99,0:09:28.75,Default,,0,0,0,,但这样做是不可行的 Dialogue: 0,0:09:28.98,0:09:32.15,Default,,0,0,0,,因为在远没到百万数量级的时候 Dialogue: 0,0:09:32.16,0:09:34.56,Default,,0,0,0,,这种组合方法打从头产生的热噪声 Dialogue: 0,0:09:34.57,0:09:36.80,Default,,0,0,0,,会慢慢增强 并使得我们的幸苦付之一炬 Dialogue: 0,0:09:39.10,0:09:43.12,Default,,0,0,0,,计算机科学处理的是理想化组件 Dialogue: 0,0:09:44.12,0:09:47.63,Default,,0,0,0,,我们对将要结合在一起的 Dialogue: 0,0:09:47.65,0:09:49.56,Default,,0,0,0,,程序和数据了如指掌 Dialogue: 0,0:09:51.90,0:09:53.20,Default,,0,0,0,,我们不需要去关心公差 Dialogue: 0,0:09:53.21,0:09:56.99,Default,,0,0,0,,也就是说 在构建大系统时 Dialogue: 0,0:09:58.13,0:10:00.03,Default,,0,0,0,,在我理想和现实之间 Dialogue: 0,0:10:00.35,0:10:04.18,Default,,0,0,0,,并不没有太大的不同 Dialogue: 0,0:10:05.53,0:10:07.60,Default,,0,0,0,,因为这些部分都是抽象单元 Dialogue: 0,0:10:07.63,0:10:10.32,Default,,0,0,0,,可以随心所欲的组合 Dialogue: 0,0:10:10.33,0:10:12.39,Default,,0,0,0,,可以据目前所知而自由构建 Dialogue: 0,0:10:13.45,0:10:15.50,Default,,0,0,0,,就是与其它的工程不同之处 Dialogue: 0,0:10:15.66,0:10:17.42,Default,,0,0,0,,(在其它的工程中)对你所构建系统的约束 Dialogue: 0,0:10:17.44,0:10:18.90,Default,,0,0,0,,来自于物理系统以及 Dialogue: 0,0:10:18.94,0:10:21.02,Default,,0,0,0,,物理定律 噪声 近似值等 Dialogue: 0,0:10:21.21,0:10:25.60,Default,,0,0,0,,而建立大型软件系统时所施加的约束 Dialogue: 0,0:10:25.64,0:10:27.58,Default,,0,0,0,,就是对我们大脑的限制 Dialogue: 0,0:10:29.12,0:10:29.98,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:10:30.00,0:10:33.67,Default,,0,0,0,,计算机科学就像是工程中的一种抽象形式 Dialogue: 0,0:10:33.80,0:10:35.73,Default,,0,0,0,,在这种工程中 我们忽略 Dialogue: 0,0:10:35.76,0:10:38.02,Default,,0,0,0,,现实所施加的约束 Dialogue: 0,0:10:41.97,0:10:46.15,Default,,0,0,0,,那么 这其中有哪些技术呢 Dialogue: 0,0:10:46.28,0:10:48.39,Default,,0,0,0,,计算机科学中并没有特别的技术 Dialogue: 0,0:10:50.39,0:10:52.55,Default,,0,0,0,,第一个技术是在很多工程中都使用的 Dialogue: 0,0:10:53.36,0:10:58.91,Default,,0,0,0,,被称为“黑盒抽象”的方法 Dialogue: 0,0:11:07.71,0:11:12.58,Default,,0,0,0,,即将一些东西组合并封装起来 Dialogue: 0,0:11:14.37,0:11:20.09,Default,,0,0,0,,以之前我们提到的求取平方根的方法为例 Dialogue: 0,0:11:22.64,0:11:28.53,Default,,0,0,0,,我将这些操作视为一个“盒子” Dialogue: 0,0:11:29.89,0:11:37.52,Default,,0,0,0,,也就是说 为了找到X的平方根 Dialogue: 0,0:11:38.86,0:11:41.27,Default,,0,0,0,,或许会有一系列的复杂规则 Dialogue: 0,0:11:42.64,0:11:46.69,Default,,0,0,0,,我们将规则封装 输入数据即可获得结果 Dialogue: 0,0:11:46.81,0:11:50.06,Default,,0,0,0,,比如说 输入36 然后说36的平方根是多少呢 Dialogue: 0,0:11:50.25,0:11:51.46,Default,,0,0,0,,则给出结果 6 Dialogue: 0,0:11:53.89,0:11:56.22,Default,,0,0,0,,重点是 Dialogue: 0,0:11:56.24,0:12:00.03,Default,,0,0,0,,通过这样的设计 Dialogue: 0,0:12:00.06,0:12:04.08,Default,,0,0,0,,可以方便他人的使用 Dialogue: 0,0:12:05.10,0:12:09.37,Default,,0,0,0,,例如Goerge想计算A的平方根加上B的平方根 Dialogue: 0,0:12:11.34,0:12:14.38,Default,,0,0,0,,他无需了解“盒子”内部的构成 Dialogue: 0,0:12:14.43,0:12:15.74,Default,,0,0,0,,而直接可以以模块的形式使用它 Dialogue: 0,0:12:15.77,0:12:17.31,Default,,0,0,0,,也可以利用它去构建新的“盒子” Dialogue: 0,0:12:18.45,0:12:24.20,Default,,0,0,0,,例如构建一个 A和B以及一个平方根和或者另一个平方根盒子 Dialogue: 0,0:12:24.53,0:12:33.87,Default,,0,0,0,,然后将这些结果加在一起并输出答案 Dialogue: 0,0:12:33.96,0:12:38.15,Default,,0,0,0,,如你所见 就我想实现的功能的层面来看 Dialogue: 0,0:12:38.92,0:12:40.42,Default,,0,0,0,,对于George来说 Dialogue: 0,0:12:40.51,0:12:43.10,Default,,0,0,0,,盒子内部是什么样并不重要 Dialogue: 0,0:12:44.19,0:12:47.25,Default,,0,0,0,,例如 以下这些说法都没什么问题 Dialogue: 0,0:12:47.27,0:12:50.43,Default,,0,0,0,,我说求X的平方根 Dialogue: 0,0:12:50.61,0:12:52.27,Default,,0,0,0,,也可以说计算Y的平方根 Dialogue: 0,0:12:52.72,0:12:55.62,Default,,0,0,0,,或者其它任何数的平方根 Dialogue: 0,0:12:56.70,0:13:02.35,Default,,0,0,0,,黑盒抽象的基本规则是 Dialogue: 0,0:13:03.53,0:13:06.44,Default,,0,0,0,,将处理过程放入盒子里以隐藏细节 Dialogue: 0,0:13:07.60,0:13:10.99,Default,,0,0,0,,这样做的原因则是你可以脱身去构建更大的盒子 Dialogue: 0,0:13:12.05,0:13:14.57,Default,,0,0,0,,现在 除了隐藏细节外 Dialogue: 0,0:13:14.59,0:13:18.41,Default,,0,0,0,,使用黑盒抽象还有另外一个原因 Dialogue: 0,0:13:18.48,0:13:25.02,Default,,0,0,0,,有的时候 你想要用你的方法去完成一件事 Dialogue: 0,0:13:25.04,0:13:26.88,Default,,0,0,0,,你的方法 Dialogue: 0,0:13:28.44,0:13:30.79,Default,,0,0,0,,就是一个通法的具体实例 Dialogue: 0,0:13:31.16,0:13:34.57,Default,,0,0,0,,同时 你也希望你的表述方式能够具有普遍性 Dialogue: 0,0:13:35.57,0:13:37.93,Default,,0,0,0,,我们接着用实例来说明 Dialogue: 0,0:13:37.97,0:13:38.86,Default,,0,0,0,,继续刚才关于平方根的讨论 Dialogue: 0,0:13:38.89,0:13:42.16,Default,,0,0,0,,让我们回过头再来看看 Dialogue: 0,0:13:42.19,0:13:43.75,Default,,0,0,0,,求平方根的算法 Dialogue: 0,0:13:44.16,0:13:45.62,Default,,0,0,0,,想一想之前是怎么说的 Dialogue: 0,0:13:45.79,0:13:49.82,Default,,0,0,0,,为了求解 首先要作出猜测 Dialogue: 0,0:13:50.62,0:13:54.84,Default,,0,0,0,,然后基于这个猜测 做出持续不断的改进 Dialogue: 0,0:13:55.66,0:14:00.14,Default,,0,0,0,,因此就存在一个找到某个到结果的通用方法 Dialogue: 0,0:14:01.15,0:14:04.00,Default,,0,0,0,,就是持续不断地改进结果 Dialogue: 0,0:14:04.16,0:14:10.25,Default,,0,0,0,,求取不动点的方法有很多 Dialogue: 0,0:14:10.97,0:14:13.23,Default,,0,0,0,,这种方法只是其中的一个特例 Dialogue: 0,0:14:14.57,0:14:16.59,Default,,0,0,0,,每个函数都有一个不动点 Dialogue: 0,0:14:17.13,0:14:26.03,Default,,0,0,0,,函数的不动点是一个值 Dialogue: 0,0:14:26.13,0:14:31.79,Default,,0,0,0,,F的不动点Y满足F(Y)=Y Dialogue: 0,0:14:32.97,0:14:40.89,Default,,0,0,0,,首先要做是做出一个猜测 Dialogue: 0,0:14:42.00,0:14:45.85,Default,,0,0,0,,在迭代函数F时不会改变的东西则是我们所求的结果 Dialogue: 0,0:14:45.96,0:14:49.45,Default,,0,0,0,,我会不断迭代函数F直到结果不会有很大改变 Dialogue: 0,0:14:50.05,0:14:51.93,Default,,0,0,0,,这就是一个通法 Dialogue: 0,0:14:52.24,0:14:56.17,Default,,0,0,0,,因此 为了计算X的平方根 Dialogue: 0,0:14:56.24,0:15:03.45,Default,,0,0,0,,我可以试着找到Y与X/Y的平均值函数的不动点 Dialogue: 0,0:15:03.55,0:15:07.52,Default,,0,0,0,,因为如果我真有一个等于X平方根的Y Dialogue: 0,0:15:08.01,0:15:11.80,Default,,0,0,0,,那么Y和X/Y应为同一值 Dialogue: 0,0:15:12.00,0:15:13.90,Default,,0,0,0,,它们俩都是X的平方根 Dialogue: 0,0:15:14.86,0:15:18.85,Default,,0,0,0,,因为X除根号X得根号X Dialogue: 0,0:15:19.09,0:15:21.84,Default,,0,0,0,,如果平均值Y等于X的平方根 Dialogue: 0,0:15:22.25,0:15:25.21,Default,,0,0,0,,那么这个平均值就不会改变 Dialogue: 0,0:15:25.98,0:15:28.93,Default,,0,0,0,,因此X的平方根即是某一特定函数的不动点 Dialogue: 0,0:15:30.09,0:15:33.85,Default,,0,0,0,,现在 我将要描述 Dialogue: 0,0:15:33.98,0:15:36.42,Default,,0,0,0,,寻找不动点的通法 Dialogue: 0,0:15:36.57,0:15:40.13,Default,,0,0,0,,我所希望做的就是 Dialogue: 0,0:15:41.02,0:15:46.45,Default,,0,0,0,,用我自己的语言定义一个可以获得不动点的“盒子” Dialogue: 0,0:15:49.58,0:15:52.19,Default,,0,0,0,,正如我可以定义一个输出平方根的盒子一样 Dialogue: 0,0:15:52.21,0:15:55.18,Default,,0,0,0,,我想要用自己的语言来表述 Dialogue: 0,0:15:56.08,0:16:01.37,Default,,0,0,0,,因此 对于这种“怎么做”的指令性知识 Dialogue: 0,0:16:01.42,0:16:03.21,Default,,0,0,0,,我不仅是想表达具体应该如何求平方根 Dialogue: 0,0:16:03.58,0:16:05.60,Default,,0,0,0,,我也希望能够表述更加通用问题 Dialogue: 0,0:16:05.66,0:16:08.27,Default,,0,0,0,,例如 怎么求取不动点 Dialogue: 0,0:16:09.82,0:16:12.25,Default,,0,0,0,,让我们再回过头来看看之前的幻灯片 Dialogue: 0,0:16:15.02,0:16:23.28,Default,,0,0,0,,不但如何去求取一个不动点 Dialogue: 0,0:16:23.33,0:16:25.32,Default,,0,0,0,,是一种指令性知识 Dialogue: 0,0:16:26.25,0:16:27.39,Default,,0,0,0,,在这下面 这里 Dialogue: 0,0:16:27.42,0:16:30.32,Default,,0,0,0,,这儿还有另一种指令性知识 说的是 Dialogue: 0,0:16:30.41,0:16:35.85,Default,,0,0,0,,计算平方根的一种方法就是应用找不动点的方法 Dialogue: 0,0:16:36.17,0:16:38.89,Default,,0,0,0,,如果 也想要表述这种指令性知识 Dialogue: 0,0:16:39.74,0:16:40.70,Default,,0,0,0,,那结果会是什么样呢? Dialogue: 0,0:16:40.73,0:16:44.90,Default,,0,0,0,,这个不动点盒子可能会是这样 Dialogue: 0,0:16:45.76,0:16:58.21,Default,,0,0,0,,如果我输入一个函数 该函数从Y映射到Y和X/Y的平均值 Dialogue: 0,0:16:59.77,0:17:06.23,Default,,0,0,0,,然后我们将会得到求不动点的盒子就是求平方根的一个方法 Dialogue: 0,0:17:08.91,0:17:10.24,Default,,0,0,0,,因此在这些我们构建的盒子中 Dialogue: 0,0:17:10.27,0:17:15.07,Default,,0,0,0,,输入和输出都不局限于数字 Dialogue: 0,0:17:16.40,0:17:18.54,Default,,0,0,0,,我们将要构建能够 Dialogue: 0,0:17:18.67,0:17:21.34,Default,,0,0,0,,找到平方根计算方法的盒子 Dialogue: 0,0:17:22.22,0:17:25.85,Default,,0,0,0,,我输入的是一个函数 Dialogue: 0,0:17:26.49,0:17:29.29,Default,,0,0,0,,比如Y映射到Y和X/Y的平均值的函数 Dialogue: 0,0:17:29.71,0:17:31.49,Default,,0,0,0,,我们之所以采用这种方式是希望 Dialogue: 0,0:17:32.21,0:17:35.60,Default,,0,0,0,,输入是一个过程 输出也是一个过程 Dialogue: 0,0:17:35.63,0:17:38.61,Default,,0,0,0,,如我们所见 一个过程输出了另一个过程 Dialogue: 0,0:17:39.31,0:17:41.10,Default,,0,0,0,,之所以这样做是因为 Dialogue: 0,0:17:41.52,0:17:46.27,Default,,0,0,0,,我们将通过程序来讨论指令性知识 Dialogue: 0,0:17:48.00,0:17:49.93,Default,,0,0,0,,这种处理方式很强大 Dialogue: 0,0:17:49.93,0:17:52.13,Default,,0,0,0,,我们将可以基于此来讨论其它类型的知识 Dialogue: 0,0:17:53.42,0:17:56.52,Default,,0,0,0,,实际上 我们讨论的是一种生成过程的过程 Dialogue: 0,0:17:57.10,0:18:00.34,Default,,0,0,0,,一种生成通法的通法 Dialogue: 0,0:18:03.57,0:18:08.24,Default,,0,0,0,,那么 我们将主要讨论三个主题的内容 Dialogue: 0,0:18:08.25,0:18:09.69,Default,,0,0,0,,而首个主题则是 Dialogue: 0,0:18:09.74,0:18:10.94,Default,,0,0,0,,黑盒抽象 Dialogue: 0,0:18:10.97,0:18:13.31,Default,,0,0,0,,让我们稍稍深入一点 Dialogue: 0,0:18:15.12,0:18:24.04,Default,,0,0,0,,我们将讨论 Dialogue: 0,0:18:24.08,0:18:26.72,Default,,0,0,0,,Lisp是如何通过基本对象建立起来的 Dialogue: 0,0:18:27.36,0:18:29.20,Default,,0,0,0,,以及Lisp的构成 Dialogue: 0,0:18:29.49,0:18:33.58,Default,,0,0,0,,接下来 将会涉及到一些基本过程和基础数据 Dialogue: 0,0:18:36.16,0:18:37.04,Default,,0,0,0,,然后我们将会看到 Dialogue: 0,0:18:37.05,0:18:38.77,Default,,0,0,0,,我们如何使用这些基本对象 Dialogue: 0,0:18:38.81,0:18:40.76,Default,,0,0,0,,并把它们组合起来构建更复杂的东西 Dialogue: 0,0:18:41.45,0:18:42.92,Default,,0,0,0,,及相应的组合方法 Dialogue: 0,0:18:43.20,0:18:46.30,Default,,0,0,0,,后续将讨论各种进行组合的方法以及 Dialogue: 0,0:18:46.45,0:18:50.48,Default,,0,0,0,,如何用基本过程来构建更复杂的过程 Dialogue: 0,0:18:50.96,0:18:54.43,Default,,0,0,0,,同时 我们也将看到如何将基本数据组合成复合数据 Dialogue: 0,0:18:56.21,0:18:59.34,Default,,0,0,0,,然后我们将会介绍如何对复合数据 Dialogue: 0,0:18:59.79,0:19:01.29,Default,,0,0,0,,如何将它们抽象出来 Dialogue: 0,0:19:02.91,0:19:04.97,Default,,0,0,0,,如何用黑盒对它们进行封装 Dialogue: 0,0:19:05.04,0:19:07.73,Default,,0,0,0,,使得你可以将它们作为组件用于更复杂的东西 Dialogue: 0,0:19:08.16,0:19:10.93,Default,,0,0,0,,我们会发现这些都是通过定义程序 Dialogue: 0,0:19:11.52,0:19:14.79,Default,,0,0,0,,以及一种处理复合数据的数据抽象技术完成的 Dialogue: 0,0:19:15.61,0:19:17.36,Default,,0,0,0,,最重要的是 Dialogue: 0,0:19:17.92,0:19:21.49,Default,,0,0,0,,我们可以从中了解到专家是如何工作的 Dialogue: 0,0:19:21.61,0:19:27.12,Default,,0,0,0,,对于找不动点的方法来讲 Dialogue: 0,0:19:27.15,0:19:28.64,Default,,0,0,0,,找平方根的方式是它的一个特例 Dialogue: 0,0:19:28.69,0:19:30.87,Default,,0,0,0,,你如何表述完成工作中所存在的通用模式呢? Dialogue: 0,0:19:31.90,0:19:34.41,Default,,0,0,0,,我们将会使用 Dialogue: 0,0:19:34.59,0:19:35.63,Default,,0,0,0,,之前已经提到过的 Dialogue: 0,0:19:35.66,0:19:37.30,Default,,0,0,0,,某种叫做高阶过程的东西 Dialogue: 0,0:19:37.34,0:19:42.05,Default,,0,0,0,,也就是说 它的输入、输出和它本身都是过程 Dialogue: 0,0:19:42.96,0:19:44.86,Default,,0,0,0,,我们将会看到一些有趣的东西 Dialogue: 0,0:19:44.86,0:19:48.49,Default,,0,0,0,,随着学习的深入 将会越发抽象 Dialogue: 0,0:19:48.80,0:19:50.31,Default,,0,0,0,,那么将会发现 Dialogue: 0,0:19:50.43,0:19:53.61,Default,,0,0,0,,我们认为是数据和我们认为是过程之间的 Dialogue: 0,0:19:53.63,0:19:57.80,Default,,0,0,0,,分界线将变得模糊到难以置信的程度 Dialogue: 0,0:20:02.89,0:20:07.12,Default,,0,0,0,,这便是我们的第一个主题 黑盒抽象 Dialogue: 0,0:20:07.12,0:20:08.62,Default,,0,0,0,,让我们来看看第二个主题 Dialogue: 0,0:20:11.10,0:20:13.88,Default,,0,0,0,,这样说吧 Dialogue: 0,0:20:13.89,0:20:18.09,Default,,0,0,0,,假设我想表达某个想法 Dialogue: 0,0:20:19.42,0:20:22.51,Default,,0,0,0,,请注意 我们讨论的是想法 Dialogue: 0,0:20:22.91,0:20:25.53,Default,,0,0,0,,比如说 Dialogue: 0,0:20:26.41,0:20:35.12,Default,,0,0,0,,我想将某个元素与另两个元素之和相乘 Dialogue: 0,0:20:36.09,0:20:37.93,Default,,0,0,0,,举例来说 Dialogue: 0,0:20:38.11,0:20:41.52,Default,,0,0,0,,我用1和3(之和)乘2 得8 Dialogue: 0,0:20:42.03,0:20:45.11,Default,,0,0,0,,但我这里想讨论的是关于线性组合的基本想法 Dialogue: 0,0:20:45.44,0:20:47.98,Default,,0,0,0,,是说你可以将两个元素的和乘以另一个元素 Dialogue: 0,0:20:49.28,0:20:51.01,Default,,0,0,0,,在数集内思考这个问题是很容易的 Dialogue: 0,0:20:51.05,0:20:55.41,Default,,0,0,0,,但假设我想将这个想法应用于 Dialogue: 0,0:20:56.08,0:20:58.58,Default,,0,0,0,,对两向量a1和a2相加 Dialogue: 0,0:20:59.89,0:21:03.26,Default,,0,0,0,,乘以某一因子x然后得到另一向量 Dialogue: 0,0:21:03.33,0:21:09.75,Default,,0,0,0,,我甚至可以说 若a1和a2皆为多项式 Dialogue: 0,0:21:11.07,0:21:13.90,Default,,0,0,0,,我想对这两个多项式求和 Dialogue: 0,0:21:13.92,0:21:16.86,Default,,0,0,0,,然后乘以2得到一个多项式 Dialogue: 0,0:21:20.16,0:21:23.83,Default,,0,0,0,,同理 a1或a2也可以是电信号 Dialogue: 0,0:21:24.56,0:21:27.77,Default,,0,0,0,,我想将二个信号加和 Dialogue: 0,0:21:27.81,0:21:30.27,Default,,0,0,0,,并将结果放入一个放大器 Dialogue: 0,0:21:30.28,0:21:33.03,Default,,0,0,0,,用一个类似于2的因子乘以它们 Dialogue: 0,0:21:33.82,0:21:36.93,Default,,0,0,0,,这种想法的基本点是 我希望用一个通用记号表示它们 Dialogue: 0,0:21:38.32,0:21:45.42,Default,,0,0,0,,假如我们的语言可以很好的表述这类想法 Dialogue: 0,0:21:47.07,0:21:49.31,Default,,0,0,0,,如果真可以这样的话 Dialogue: 0,0:21:50.65,0:21:52.09,Default,,0,0,0,,我将会以这样的方式表述 Dialogue: 0,0:21:54.99,0:22:00.41,Default,,0,0,0,,用x乘以a1和a2的和 Dialogue: 0,0:22:02.80,0:22:05.07,Default,,0,0,0,,更进一步 我希望做更抽象更基本的表述 Dialogue: 0,0:22:06.03,0:22:09.23,Default,,0,0,0,,使其可以适应各个不同类型的a1和a2 Dialogue: 0,0:22:10.03,0:22:11.58,Default,,0,0,0,,现在回过头来想想 似乎有点问题 Dialogue: 0,0:22:11.58,0:22:16.17,Default,,0,0,0,,毕竟 对两个数字和两个多项式进行加和运算 Dialogue: 0,0:22:16.21,0:22:18.33,Default,,0,0,0,,所用的基本操作 Dialogue: 0,0:22:18.38,0:22:22.98,Default,,0,0,0,,在机器内部显然是不同的 Dialogue: 0,0:22:23.29,0:22:27.49,Default,,0,0,0,,对两个电信号或声波加和也有同样的问题 Dialogue: 0,0:22:27.89,0:22:32.53,Default,,0,0,0,,无论怎样 对不同类型的元素进行求和运算 Dialogue: 0,0:22:32.87,0:22:34.25,Default,,0,0,0,,总是需要使用不同的方法 Dialogue: 0,0:22:37.09,0:22:38.64,Default,,0,0,0,,现在 为了构建这样一个系统 Dialogue: 0,0:22:38.78,0:22:40.67,Default,,0,0,0,,我们将如何使用这些知识呢? Dialogue: 0,0:22:41.20,0:22:44.41,Default,,0,0,0,,如何在各种方法中进行选择? Dialogue: 0,0:22:44.56,0:22:48.42,Default,,0,0,0,,而如果明天George又想出了一种新类型的对象 Dialogue: 0,0:22:48.45,0:22:50.32,Default,,0,0,0,,并将它用于加和以及乘积 Dialogue: 0,0:22:51.01,0:22:53.32,Default,,0,0,0,,我又该如何把这个新类型引入到系统中 Dialogue: 0,0:22:53.52,0:22:55.68,Default,,0,0,0,,而且能够做到不把已有的系统弄得一团糟? Dialogue: 0,0:22:57.81,0:23:00.54,Default,,0,0,0,,这便是我们的第二大主题 Dialogue: 0,0:23:00.57,0:23:03.16,Default,,0,0,0,,控制复杂度的方法 Dialogue: 0,0:23:03.84,0:23:08.43,Default,,0,0,0,,我们实现的方法是按照约定来实现相应的接口 Dialogue: 0,0:23:17.44,0:23:20.21,Default,,0,0,0,,并以此将各部分组合起来 Dialogue: 0,0:23:20.25,0:23:22.04,Default,,0,0,0,,就如同电气工程中 Dialogue: 0,0:23:22.94,0:23:25.39,Default,,0,0,0,,人们为连接器规定标准阻抗 Dialogue: 0,0:23:26.16,0:23:28.62,Default,,0,0,0,,如果用符合这个标准的东西来构建系统 Dialogue: 0,0:23:28.67,0:23:30.40,Default,,0,0,0,,你就知道你可以把各个部件组合在一起 Dialogue: 0,0:23:32.78,0:23:35.68,Default,,0,0,0,,这就是我们将要讨论的第二个主题:约定接口 Dialogue: 0,0:23:35.73,0:23:40.94,Default,,0,0,0,,如我之前提到的 Dialogue: 0,0:23:40.97,0:23:42.22,Default,,0,0,0,,接下来我们将讨论通用操作中的问题 Dialogue: 0,0:23:42.59,0:23:47.28,Default,,0,0,0,,例如对各种不同类型数据进行均适用的加法操作 Dialogue: 0,0:23:52.61,0:23:54.57,Default,,0,0,0,,随后则会讨论通用操作 Dialogue: 0,0:23:54.61,0:23:56.99,Default,,0,0,0,,然后我们将讨论大型架构问题 Dialogue: 0,0:23:58.32,0:24:00.83,Default,,0,0,0,,如果通过对现实世界的复杂系统建模 Dialogue: 0,0:24:01.02,0:24:04.89,Default,,0,0,0,,来构建大型程序 Dialogue: 0,0:24:05.53,0:24:06.53,Default,,0,0,0,,我们将看到 在构建这样的系统时 Dialogue: 0,0:24:06.57,0:24:11.81,Default,,0,0,0,,有两种非常重要的方法 Dialogue: 0,0:24:11.85,0:24:13.90,Default,,0,0,0,,其一是面向对象编程 Dialogue: 0,0:24:14.09,0:24:18.94,Default,,0,0,0,,在这种模式中 你把你的系统想象成一个社区 Dialogue: 0,0:24:19.37,0:24:22.36,Default,,0,0,0,,社区中的各个部分都是通过相互间传递消息联系起来的 Dialogue: 0,0:24:23.44,0:24:27.81,Default,,0,0,0,,其二是关于聚集的操作 称作“流” Dialogue: 0,0:24:27.98,0:24:31.50,Default,,0,0,0,,使用这种方式构建大型系统 Dialogue: 0,0:24:31.50,0:24:35.29,Default,,0,0,0,,类似于电气工程师构造大型电气系统 Dialogue: 0,0:24:38.93,0:24:40.49,Default,,0,0,0,,这就是我们的第二个话题 Dialogue: 0,0:24:43.37,0:24:45.93,Default,,0,0,0,,现在 我们将要讨论第三个话题 Dialogue: 0,0:24:45.95,0:24:49.70,Default,,0,0,0,,控制复杂度的第三个技术 Dialogue: 0,0:24:49.74,0:24:50.94,Default,,0,0,0,,便是定义新的语言 Dialogue: 0,0:24:51.69,0:24:55.42,Default,,0,0,0,,因为有时 当你有点受不了设计的复杂度时 Dialogue: 0,0:24:55.47,0:24:59.69,Default,,0,0,0,,你可以通过定义一门新的语言来控制系统复杂度 Dialogue: 0,0:25:01.41,0:25:05.60,Default,,0,0,0,,新语言的设计意图是为了强调系统的某个方面 Dialogue: 0,0:25:05.79,0:25:09.36,Default,,0,0,0,,它一方面隐藏了部分细节 另一方面则但强调一些其他的细节 Dialogue: 0,0:25:12.99,0:25:15.93,Default,,0,0,0,,这部分将是课程中最神奇的部分 Dialogue: 0,0:25:16.03,0:25:21.20,Default,,0,0,0,,我们将开始于构建新的计算机语言 Dialogue: 0,0:25:21.82,0:25:26.30,Default,,0,0,0,,实际上我们首先要完成的工作已经内建于Lisp之中了 Dialogue: 0,0:25:29.23,0:25:34.02,Default,,0,0,0,,我们将展现如何用Lisp来解释Lisp Dialogue: 0,0:25:34.29,0:25:36.94,Default,,0,0,0,,这是一个非常类似于自循环的过程 Dialogue: 0,0:25:36.96,0:25:39.92,Default,,0,0,0,,这与(Lisp中)一个神奇的符号有关 Dialogue: 0,0:25:40.97,0:25:46.38,Default,,0,0,0,,解释Lisp的步骤是 Dialogue: 0,0:25:46.57,0:25:47.71,Default,,0,0,0,,应用和求值——这两大步骤的轮转 Dialogue: 0,0:25:47.89,0:25:50.87,Default,,0,0,0,,这两者不断地互相交替进行 Dialogue: 0,0:25:52.54,0:25:54.24,Default,,0,0,0,,接下来 我们将看到其余神奇的东西 Dialogue: 0,0:25:54.25,0:25:56.85,Default,,0,0,0,,譬如另一种魔法符号 Dialogue: 0,0:25:57.12,0:26:01.52,Default,,0,0,0,,一种叫做Y运算符的东西 Dialogue: 0,0:26:01.55,0:26:06.45,Default,,0,0,0,,某种意义上 它在过程式语言中用于 表达无限 Dialogue: 0,0:26:06.51,0:26:07.44,Default,,0,0,0,,我们也会谈论到它 Dialogue: 0,0:26:08.40,0:26:13.73,Default,,0,0,0,,总之 这部分课程被称作“元语言抽象” Dialogue: 0,0:26:16.17,0:26:26.23,Default,,0,0,0,,主要讨论如何构建一门新语言 Dialogue: 0,0:26:30.22,0:26:35.71,Default,,0,0,0,,如我所言 我们将从了解解释的过程开始 Dialogue: 0,0:26:35.74,0:26:42.12,Default,,0,0,0,,随后则一起讨论应用-求值循环和构建Lisp Dialogue: 0,0:26:42.16,0:26:44.17,Default,,0,0,0,,你将发现这种方法具有相当的普遍性 Dialogue: 0,0:26:44.37,0:26:48.26,Default,,0,0,0,,我们将用同样的技术去构建一门全完不同的语言 Dialogue: 0,0:26:48.53,0:26:50.31,Default,,0,0,0,,一种所谓的逻辑编程语言 Dialogue: 0,0:26:50.53,0:26:54.83,Default,,0,0,0,,一种无关具有输入和输出的过程 Dialogue: 0,0:26:54.86,0:26:57.25,Default,,0,0,0,,而仅关注元素之间关系的语言 Dialogue: 0,0:26:57.31,0:27:03.92,Default,,0,0,0,,最终 我们将讨论如何将这些东西 Dialogue: 0,0:27:03.95,0:27:05.60,Default,,0,0,0,,实实在在的实现在简单的机器上 Dialogue: 0,0:27:05.65,0:27:08.39,Default,,0,0,0,,比如说这个 Dialogue: 0,0:27:09.13,0:27:12.14,Default,,0,0,0,,如图所示的芯片 Dialogue: 0,0:27:12.16,0:27:17.47,Default,,0,0,0,,就是我们在硬件部分谈及的Lisp解释器 Dialogue: 0,0:27:20.88,0:27:23.79,Default,,0,0,0,,这三大主题就是本课的提纲 Dialogue: 0,0:27:24.88,0:27:29.41,Default,,0,0,0,,黑盒抽象 约定接口 元语言抽象 Dialogue: 0,0:27:31.58,0:27:33.57,Default,,0,0,0,,好 先休息一会儿 然后正式开始 Dialogue: 0,0:27:52.19,0:28:03.42,Default,,0,0,0,,[音乐] Dialogue: 0,0:28:03.92,0:28:06.84,Default,,0,0,0,,现在让我们正式开始学习Lisp Dialogue: 0,0:28:08.06,0:28:10.75,Default,,0,0,0,,事实上 我们将开始学习一些非常重要的内容 Dialogue: 0,0:28:10.80,0:28:14.33,Default,,0,0,0,,在这门课程中最重要的 不是Lisp本身 Dialogue: 0,0:28:14.38,0:28:18.41,Default,,0,0,0,,而是一种的通用框架体系 Dialogue: 0,0:28:18.62,0:28:21.89,Default,,0,0,0,,我们用它来组织我之前提到的语言 Dialogue: 0,0:28:22.12,0:28:25.10,Default,,0,0,0,,当有人要向你展示一门新语言 Dialogue: 0,0:28:25.13,0:28:26.16,Default,,0,0,0,,你应该问他 Dialogue: 0,0:28:26.19,0:28:32.87,Default,,0,0,0,,(构成语言的)基本元素有哪些? Dialogue: 0,0:28:37.50,0:28:38.78,Default,,0,0,0,,这门语言使用哪些基本元素? Dialogue: 0,0:28:38.96,0:28:43.53,Default,,0,0,0,,你是如何将这些元素组合在一起的? Dialogue: 0,0:28:43.68,0:28:47.42,Default,,0,0,0,,组合的方法是什么? Dialogue: 0,0:28:50.17,0:28:54.18,Default,,0,0,0,,允许你将这些基本元素整合在一起 Dialogue: 0,0:28:54.37,0:28:56.51,Default,,0,0,0,,以构建更大的对象的又是什么? Dialogue: 0,0:28:58.01,0:28:59.61,Default,,0,0,0,,把东西构建在一起的方法是什么? Dialogue: 0,0:29:01.39,0:29:05.69,Default,,0,0,0,,以及 抽象的方法是什么? Dialogue: 0,0:29:08.35,0:29:16.85,Default,,0,0,0,,我们如何利用这些元素并把它们封装成盒子? Dialogue: 0,0:29:16.88,0:29:19.66,Default,,0,0,0,,我们如何为它们命名使得我们可以 Dialogue: 0,0:29:19.68,0:29:23.85,Default,,0,0,0,,把它们当作基本元素来用于构建更复杂的东西? Dialogue: 0,0:29:23.89,0:29:25.66,Default,,0,0,0,,等等 等等 等等 Dialogue: 0,0:29:26.89,0:29:28.08,Default,,0,0,0,,因此 当有人告诉你 Dialogue: 0,0:29:28.09,0:29:29.55,Default,,0,0,0,,嘿 我发明了一种新的计算机语言 Dialogue: 0,0:29:30.86,0:29:34.70,Default,,0,0,0,,你不应该问 用你的语言编写求逆矩阵需要多少代码 Dialogue: 0,0:29:35.73,0:29:36.88,Default,,0,0,0,,这是风马牛不相及的 Dialogue: 0,0:29:37.39,0:29:42.30,Default,,0,0,0,,如果该语言没有内建了矩阵或者类似的东西 Dialogue: 0,0:29:42.33,0:29:43.37,Default,,0,0,0,,那你就应该问他 Dialogue: 0,0:29:43.37,0:29:46.03,Default,,0,0,0,,应该如何构建矩阵? Dialogue: 0,0:29:46.05,0:29:48.47,Default,,0,0,0,,如何通过组合来构建? Dialogue: 0,0:29:48.62,0:29:50.71,Default,,0,0,0,,如何对其进行抽象 Dialogue: 0,0:29:51.68,0:29:54.21,Default,,0,0,0,,把它作为基本元素 Dialogue: 0,0:29:54.22,0:29:56.52,Default,,0,0,0,,来构建更复杂的东西? Dialogue: 0,0:29:58.75,0:30:04.61,Default,,0,0,0,,我们将了解到Lisp的一些基本数据和基本过程 Dialogue: 0,0:30:05.25,0:30:07.50,Default,,0,0,0,,好吧 这次是真的开始了 Dialogue: 0,0:30:07.55,0:30:14.89,Default,,0,0,0,,这里有一个Lisp的基本数据 数字3 Dialogue: 0,0:30:16.27,0:30:19.87,Default,,0,0,0,,事实上 如果打破沙锅问到底的话 这不是数字3 Dialogue: 0,0:30:19.93,0:30:25.57,Default,,0,0,0,,这只是一个符号 用以代表柏拉图观念下的数字3的 Dialogue: 0,0:30:26.67,0:30:28.93,Default,,0,0,0,,这又是另一个 Dialogue: 0,0:30:30.48,0:30:36.06,Default,,0,0,0,,这个是Lisp中又一个基本数据 17.4 Dialogue: 0,0:30:36.08,0:30:39.42,Default,,0,0,0,,又或者说 代表17.4 Dialogue: 0,0:30:40.99,0:30:44.48,Default,,0,0,0,,这儿还有一个5 Dialogue: 0,0:30:46.86,0:30:52.21,Default,,0,0,0,,然后这儿又有一个内建于Lisp的基本对象“+” Dialogue: 0,0:30:52.25,0:30:55.68,Default,,0,0,0,,如果又要继续深究的话 Dialogue: 0,0:30:55.71,0:31:00.47,Default,,0,0,0,,这只是一个名字 代表对元素进行加和的基本方法而已 Dialogue: 0,0:31:00.53,0:31:02.53,Default,,0,0,0,,就像这个是柏拉图式的3 Dialogue: 0,0:31:02.61,0:31:09.32,Default,,0,0,0,,这也只是一个代表柏拉图观念下的将某些元素加和起来 Dialogue: 0,0:31:10.32,0:31:11.98,Default,,0,0,0,,这些都是基本元素 Dialogue: 0,0:31:12.14,0:31:13.76,Default,,0,0,0,,我可以将它们放在一起 Dialogue: 0,0:31:14.14,0:31:18.29,Default,,0,0,0,,我可以说 3加17.4加5的和是多少 Dialogue: 0,0:31:18.69,0:31:21.31,Default,,0,0,0,,这等同于说 Dialogue: 0,0:31:21.33,0:31:27.71,Default,,0,0,0,,让我们把求和运算符应用于这三个数 Dialogue: 0,0:31:27.74,0:31:31.15,Default,,0,0,0,,我可以得到什么呢 是8 是17 还是25.4 Dialogue: 0,0:31:34.43,0:31:38.05,Default,,0,0,0,,因此 我可以问Lisp这个的值是多少 Dialogue: 0,0:31:38.94,0:31:40.77,Default,,0,0,0,,(表达式)返回25.4 Dialogue: 0,0:31:43.58,0:31:44.83,Default,,0,0,0,,介绍一些术语吧 Dialogue: 0,0:31:44.88,0:31:51.47,Default,,0,0,0,,我所写的这些东西就叫做组合式 Dialogue: 0,0:31:56.88,0:32:01.94,Default,,0,0,0,,通常 一个组合式是由运算符 Dialogue: 0,0:32:03.39,0:32:04.72,Default,,0,0,0,,这些就是运算符 Dialogue: 0,0:32:09.71,0:32:12.05,Default,,0,0,0,,和应用该运算符的运算对象组成 Dialogue: 0,0:32:13.25,0:32:14.54,Default,,0,0,0,,这些是运算对象 Dialogue: 0,0:32:21.89,0:32:23.79,Default,,0,0,0,,当然 我可以完成更复杂的事 Dialogue: 0,0:32:23.82,0:32:28.56,Default,,0,0,0,,我可以使之更复杂是因为 这些运算对象 Dialogue: 0,0:32:29.52,0:32:31.09,Default,,0,0,0,,通常来说 也可以是组合式 Dialogue: 0,0:32:31.15,0:32:44.47,Default,,0,0,0,,比如 3加上5乘以6乘以8乘以2的积的和是多少 Dialogue: 0,0:32:45.66,0:32:52.16,Default,,0,0,0,,而我应该得到 我算一下 30 40 43 Dialogue: 0,0:32:52.73,0:32:54.81,Default,,0,0,0,,因此Lisp会返回这个表达式的值是43 Dialogue: 0,0:32:56.56,0:33:02.80,Default,,0,0,0,,后续我们将看到构造组合式是组合的基本需求 Dialogue: 0,0:33:04.65,0:33:09.22,Default,,0,0,0,,你所看到的这些语法 Dialogue: 0,0:33:10.56,0:33:13.04,Default,,0,0,0,,就是Lisp用的所谓的前缀表示法 Dialogue: 0,0:33:16.22,0:33:25.21,Default,,0,0,0,,意即操作符在操作数的左端 Dialogue: 0,0:33:25.47,0:33:26.48,Default,,0,0,0,,这只是个约定 Dialogue: 0,0:33:27.66,0:33:29.77,Default,,0,0,0,,注意 这些都被括起来了 Dialogue: 0,0:33:30.08,0:33:32.32,Default,,0,0,0,,这些括号使得它们区别开来 Dialogue: 0,0:33:32.32,0:33:36.99,Default,,0,0,0,,因此只要看看这个 我就可以知道这个是运算符 Dialogue: 0,0:33:37.01,0:33:40.99,Default,,0,0,0,,以及这有1个 2个 3个 4个运算对象 Dialogue: 0,0:33:42.38,0:33:47.97,Default,,0,0,0,,而且我也可以发现第二个运算对象是个组合式 Dialogue: 0,0:33:48.88,0:33:51.55,Default,,0,0,0,,该组合式有一个运算符和两个运算对象 Dialogue: 0,0:33:52.43,0:33:54.27,Default,,0,0,0,,Lisp中的括号 有点或者非常不同于 Dialogue: 0,0:33:54.61,0:33:57.71,Default,,0,0,0,,通常数学中的括号 Dialogue: 0,0:33:57.77,0:34:00.11,Default,,0,0,0,,数学中 我们常将其用于分组 Dialogue: 0,0:34:01.21,0:34:03.75,Default,,0,0,0,,如果有时你忘了闭合括号 但其他人能理解你的意图 Dialogue: 0,0:34:03.77,0:34:05.56,Default,,0,0,0,,这也无关紧要 Dialogue: 0,0:34:05.76,0:34:08.51,Default,,0,0,0,,通常的 你多加了括号也无所谓 Dialogue: 0,0:34:08.86,0:34:10.94,Default,,0,0,0,,因为这样只会使得分组更加明确 Dialogue: 0,0:34:10.96,0:34:11.77,Default,,0,0,0,,Lisp可不像这样 Dialogue: 0,0:34:13.12,0:34:15.37,Default,,0,0,0,,Lisp中你既不能不闭合括号 Dialogue: 0,0:34:16.38,0:34:18.56,Default,,0,0,0,,亦不能添加多余的括号 Dialogue: 0,0:34:19.33,0:34:21.28,Default,,0,0,0,,因为加括号总是意味着 Dialogue: 0,0:34:21.37,0:34:27.05,Default,,0,0,0,,确切的来说 所括之物是一个组合式 Dialogue: 0,0:34:27.09,0:34:28.81,Default,,0,0,0,,表示将运算符应用于运算对象 Dialogue: 0,0:34:29.04,0:34:32.62,Default,,0,0,0,,如果我不闭合这个括号 Dialogue: 0,0:34:32.65,0:34:33.96,Default,,0,0,0,,这个就变成其它的意思了 Dialogue: 0,0:34:35.41,0:34:37.25,Default,,0,0,0,,事实上 我们可以这么来理解这个问题 Dialogue: 0,0:34:37.41,0:34:41.65,Default,,0,0,0,,把我写的这些东西想作一个树 Dialogue: 0,0:34:42.37,0:34:47.30,Default,,0,0,0,,这个组合式实际上是一个树 树具有一个“+” Dialogue: 0,0:34:47.37,0:34:54.46,Default,,0,0,0,,以及 一个3和一些其它的东西和一个8 还有一个2 Dialogue: 0,0:34:54.48,0:34:56.35,Default,,0,0,0,,而这里的其它的东西 Dialogue: 0,0:34:56.35,0:35:03.22,Default,,0,0,0,,它本身是一个有一个“*”一个5和一个6的子树 Dialogue: 0,0:35:03.95,0:35:05.53,Default,,0,0,0,,我们可以这样认为 Dialogue: 0,0:35:05.55,0:35:09.00,Default,,0,0,0,,我们只是在构建这些树而已 Dialogue: 0,0:35:09.21,0:35:15.10,Default,,0,0,0,,括号只是将这种二维结构写作线性字符串 Dialogue: 0,0:35:15.79,0:35:17.34,Default,,0,0,0,,的一种方法罢了 Dialogue: 0,0:35:19.23,0:35:23.81,Default,,0,0,0,,因为至少在Lisp发明时 人们还在用电传打字机或者打孔卡 Dialogue: 0,0:35:24.17,0:35:25.60,Default,,0,0,0,,这种记法方便多了 Dialogue: 0,0:35:25.97,0:35:30.52,Default,,0,0,0,,如果Lisp是在当下被发明的 语法可能会像树那样 Dialogue: 0,0:35:31.76,0:35:35.07,Default,,0,0,0,,那么 让我们看看在计算机里面它究竟是什么样 Dialogue: 0,0:35:36.29,0:35:39.37,Default,,0,0,0,,这里有个Lisp解释套件 Dialogue: 0,0:35:39.41,0:35:40.43,Default,,0,0,0,,这是个编辑器 Dialogue: 0,0:35:41.13,0:35:44.86,Default,,0,0,0,,我将要在上方写一些表达式并让Lisp对其求值 Dialogue: 0,0:35:45.12,0:35:46.75,Default,,0,0,0,,比如 我可以问Lisp Dialogue: 0,0:35:46.83,0:35:48.53,Default,,0,0,0,,这个符号的值是多少 Dialogue: 0,0:35:49.44,0:35:50.50,Default,,0,0,0,,我键入3 Dialogue: 0,0:35:50.57,0:35:52.20,Default,,0,0,0,,然后叫Lisp对其求值 Dialogue: 0,0:35:52.32,0:35:54.77,Default,,0,0,0,,然后你就会看到Lisp在下面返回了一些信息 Dialogue: 0,0:35:55.39,0:35:56.84,Default,,0,0,0,,这个值就是3 Dialogue: 0,0:35:57.58,0:36:04.96,Default,,0,0,0,,我也可以问 3加上4加上8的和是多少 Dialogue: 0,0:36:06.45,0:36:08.05,Default,,0,0,0,,键入这个组合式 Dialogue: 0,0:36:08.93,0:36:10.66,Default,,0,0,0,,让Lisp对其求值 Dialogue: 0,0:36:14.49,0:36:15.68,Default,,0,0,0,,返回15 Dialogue: 0,0:36:16.57,0:36:18.80,Default,,0,0,0,,我可以键入一些更复杂的东西 Dialogue: 0,0:36:19.25,0:36:34.14,Default,,0,0,0,,将3乘以7加19.5的和的乘积求和得多少 Dialogue: 0,0:36:35.21,0:36:38.00,Default,,0,0,0,,你会发现Lisp内建了一些功能 Dialogue: 0,0:36:38.01,0:36:39.76,Default,,0,0,0,,帮你跟踪这些括号 Dialogue: 0,0:36:39.77,0:36:42.13,Default,,0,0,0,,看我键入下一个右圆括号 Dialogue: 0,0:36:42.21,0:36:45.01,Default,,0,0,0,,用于闭合以“*”开头的那个组合式 Dialogue: 0,0:36:45.52,0:36:47.30,Default,,0,0,0,,开头的那个左括号会闪一下 Dialogue: 0,0:36:47.76,0:36:49.69,Default,,0,0,0,,我把这些括号擦去 再示范一次 Dialogue: 0,0:36:50.14,0:36:52.70,Default,,0,0,0,,键入右括号 闭合了“+”组合式 Dialogue: 0,0:36:53.58,0:36:56.41,Default,,0,0,0,,再键入右括号 闭合了“*”组合式 Dialogue: 0,0:36:57.90,0:37:00.76,Default,,0,0,0,,现在我又回到了加 我将它们与4相加 Dialogue: 0,0:37:01.66,0:37:02.69,Default,,0,0,0,,闭合了“+”组合式 Dialogue: 0,0:37:02.73,0:37:07.07,Default,,0,0,0,,现在我补全了组合式 然后我问Lisp它们的值是多少 Dialogue: 0,0:37:07.26,0:37:11.66,Default,,0,0,0,,这种内建于各种Lisp系统的 Dialogue: 0,0:37:11.76,0:37:13.29,Default,,0,0,0,,括号匹配工具帮你跟进(括号匹配) Dialogue: 0,0:37:13.36,0:37:16.55,Default,,0,0,0,,因为手工闭合这些括号太辛苦了 Dialogue: 0,0:37:16.81,0:37:21.20,Default,,0,0,0,,这又是另外一种保持括号跟进的约定 Dialogue: 0,0:37:21.25,0:37:23.68,Default,,0,0,0,,我另外写一个复杂的组合式 Dialogue: 0,0:37:24.77,0:37:34.00,Default,,0,0,0,,将3和5的积与某个元素求和 Dialogue: 0,0:37:34.03,0:37:35.23,Default,,0,0,0,,现在我将要缩进 Dialogue: 0,0:37:35.28,0:37:39.85,Default,,0,0,0,,使得这些运算对象都是垂直书写的 Dialogue: 0,0:37:40.30,0:37:45.65,Default,,0,0,0,,将这些加上47乘以 Dialogue: 0,0:37:47.02,0:37:54.59,Default,,0,0,0,,恩…… 47乘以20和6.8的差 Dialogue: 0,0:37:54.62,0:37:57.09,Default,,0,0,0,,意即从20中减去6.8 Dialogue: 0,0:37:58.97,0:38:00.19,Default,,0,0,0,,然后 这个括号闭合了 Dialogue: 0,0:38:00.22,0:38:03.47,Default,,0,0,0,,闭合“-” 闭合“*” Dialogue: 0,0:38:03.76,0:38:05.42,Default,,0,0,0,,现在 我们再写一个运算符 Dialogue: 0,0:38:05.44,0:38:09.49,Default,,0,0,0,,Lisp编辑器自动缩进到正确的位置 Dialogue: 0,0:38:10.40,0:38:11.50,Default,,0,0,0,,来帮助我保持跟进 Dialogue: 0,0:38:12.61,0:38:14.09,Default,,0,0,0,,我再示范一次 Dialogue: 0,0:38:14.13,0:38:15.89,Default,,0,0,0,,这样就又闭合了最后一个括号 Dialogue: 0,0:38:16.25,0:38:17.71,Default,,0,0,0,,它匹配了这个“+”(的括号) Dialogue: 0,0:38:20.40,0:38:22.64,Default,,0,0,0,,现在我想问 这个的值是多少 Dialogue: 0,0:38:23.87,0:38:29.28,Default,,0,0,0,,因此 这两件事 缩进到正确的位置 Dialogue: 0,0:38:29.31,0:38:30.86,Default,,0,0,0,,也就是所谓的美观的输出 Dialogue: 0,0:38:31.55,0:38:33.58,Default,,0,0,0,,以及闭合提示 Dialogue: 0,0:38:33.89,0:38:37.73,Default,,0,0,0,,是许多Lisp系统所内建用于帮你保持跟进的工具 Dialogue: 0,0:38:37.76,0:38:39.01,Default,,0,0,0,,你应该学习如何使用它们 Dialogue: 0,0:38:41.52,0:38:43.17,Default,,0,0,0,,好 这些都是基本的内容 Dialogue: 0,0:38:44.73,0:38:46.31,Default,,0,0,0,,这就是一种组合的方法 Dialogue: 0,0:38:46.33,0:38:47.93,Default,,0,0,0,,现在让我们来看看抽象的方法 Dialogue: 0,0:38:49.44,0:38:53.84,Default,,0,0,0,,我希望我能够写一些像这样的组合式 Dialogue: 0,0:38:53.85,0:38:55.77,Default,,0,0,0,,将它抽象化并给它命名 Dialogue: 0,0:38:55.81,0:38:57.26,Default,,0,0,0,,使得我可以将其作为一个(我们语言的)元素 Dialogue: 0,0:38:57.31,0:38:59.92,Default,,0,0,0,,在Lisp中 我可以用“define”来实现 Dialogue: 0,0:39:01.17,0:39:02.43,Default,,0,0,0,,比如说 Dialogue: 0,0:39:02.73,0:39:15.05,Default,,0,0,0,,定义A为5乘以5 Dialogue: 0,0:39:18.40,0:39:22.35,Default,,0,0,0,,现在我可以问Lisp Dialogue: 0,0:39:22.38,0:39:26.01,Default,,0,0,0,,A和A的乘积是多少 Dialogue: 0,0:39:27.18,0:39:29.81,Default,,0,0,0,,这个是25所以这个就是625 Dialogue: 0,0:39:31.97,0:39:36.01,Default,,0,0,0,,但更重要的则是 我现在可以使用A Dialogue: 0,0:39:36.21,0:39:37.92,Default,,0,0,0,,我已经在这个组合式里面用过了 Dialogue: 0,0:39:38.41,0:39:43.55,Default,,0,0,0,,但我也可以在更复杂的组合式里面使用它 Dialogue: 0,0:39:43.58,0:39:50.93,Default,,0,0,0,,我也可以说 定义B为 Dialogue: 0,0:39:50.97,0:39:57.45,Default,,0,0,0,,A与5乘以A的积的和 Dialogue: 0,0:39:59.44,0:40:00.72,Default,,0,0,0,,闭合“+” Dialogue: 0,0:40:03.45,0:40:05.85,Default,,0,0,0,,让我们来看看它在计算机中是怎样的吧 Dialogue: 0,0:40:07.28,0:40:10.68,Default,,0,0,0,,我就像黑板上写的那样键入就可以了 Dialogue: 0,0:40:10.83,0:40:21.73,Default,,0,0,0,,我告诉Lisp Dialogue: 0,0:40:23.74,0:40:25.38,Default,,0,0,0,,定义A为5乘以5的积 Dialogue: 0,0:40:25.52,0:40:28.94,Default,,0,0,0,,注意Lisp在下方回应了一个A Dialogue: 0,0:40:29.09,0:40:31.38,Default,,0,0,0,,通常来说 你如果在Lisp中键入了一个定义 Dialogue: 0,0:40:31.50,0:40:35.02,Default,,0,0,0,,它返回被定义的符号 Dialogue: 0,0:40:35.63,0:40:39.66,Default,,0,0,0,,现在我问Lisp A乘以A的积是多少 Dialogue: 0,0:40:42.81,0:40:44.33,Default,,0,0,0,,Lisp返回625 Dialogue: 0,0:40:46.05,0:41:00.34,Default,,0,0,0,,我也可以定义B为A加上5乘以A的积的和 Dialogue: 0,0:41:00.48,0:41:05.70,Default,,0,0,0,,闭合“*” 闭合“+” 闭合“define” Dialogue: 0,0:41:07.63,0:41:10.37,Default,,0,0,0,,Lisp在下方正常返回B Dialogue: 0,0:41:11.04,0:41:13.24,Default,,0,0,0,,现在我可以问Lisp B的值是多少 Dialogue: 0,0:41:17.18,0:41:18.88,Default,,0,0,0,,我也可以问一些更复杂的事 Dialogue: 0,0:41:18.93,0:41:26.69,Default,,0,0,0,,比如A加上B除以5的商的和是多少 Dialogue: 0,0:41:26.73,0:41:30.25,Default,,0,0,0,,这个“/”是另一个基本运算符 代表除 Dialogue: 0,0:41:30.38,0:41:32.78,Default,,0,0,0,,我让B除以5 并加在A上 Dialogue: 0,0:41:33.65,0:41:35.23,Default,,0,0,0,,Lisp正常返回55 Dialogue: 0,0:41:36.57,0:41:37.92,Default,,0,0,0,,就像这样 Dialogue: 0,0:41:39.82,0:41:43.40,Default,,0,0,0,,这是定义东西的基本方法 Dialogue: 0,0:41:43.44,0:41:49.02,Default,,0,0,0,,这是最简单的命名方法 但并不是很强大 Dialogue: 0,0:41:50.06,0:41:51.60,Default,,0,0,0,,注意我们讨论的是通用方法 Dialogue: 0,0:41:51.84,0:41:53.37,Default,,0,0,0,,因此我真正想定义的是 Dialogue: 0,0:41:53.57,0:41:57.68,Default,,0,0,0,,一种通用方法 可以 Dialogue: 0,0:41:58.11,0:42:17.53,Default,,0,0,0,,得到 5乘5 6乘6 1001乘1001 1001.7乘1001.7 Dialogue: 0,0:42:17.76,0:42:24.16,Default,,0,0,0,,我想给一个数与其自身相乘这种想法一个名字 Dialogue: 0,0:42:28.48,0:42:30.11,Default,,0,0,0,,你应该知道 这叫做平方 Dialogue: 0,0:42:31.69,0:42:35.63,Default,,0,0,0,,而在Lisp中我应该这样实现 Dialogue: 0,0:42:37.97,0:42:56.25,Default,,0,0,0,,定义 square某个叫x的东西 为 将x乘以x自己 Dialogue: 0,0:42:57.87,0:43:01.12,Default,,0,0,0,,定义完毕后 我可以问Lisp Dialogue: 0,0:43:01.12,0:43:05.49,Default,,0,0,0,,比如 10的平方是多少 Dialogue: 0,0:43:06.67,0:43:07.87,Default,,0,0,0,,Lisp返回100 Dialogue: 0,0:43:10.70,0:43:14.24,Default,,0,0,0,,让我们深入讨论一下 Dialogue: 0,0:43:15.29,0:43:16.88,Default,,0,0,0,,这儿是square的定义 Dialogue: 0,0:43:17.50,0:43:22.55,Default,,0,0,0,,square某个元素 即是将该元素进行自乘 Dialogue: 0,0:43:23.69,0:43:25.34,Default,,0,0,0,,这里的x Dialogue: 0,0:43:26.29,0:43:27.81,Default,,0,0,0,,应该算是一种代词 Dialogue: 0,0:43:27.87,0:43:29.53,Default,,0,0,0,,指代了我要做平方的元素 Dialogue: 0,0:43:31.49,0:43:37.41,Default,,0,0,0,,实际上我将其乘以x 即是乘以它自己 Dialogue: 0,0:43:42.22,0:43:48.27,Default,,0,0,0,,这些就是定义一个过程的记法 Dialogue: 0,0:43:48.29,0:43:50.29,Default,,0,0,0,,这样说可能把你搞糊涂了 Dialogue: 0,0:43:50.81,0:43:53.97,Default,,0,0,0,,因为这就像我在用square一样 Dialogue: 0,0:43:54.00,0:43:56.80,Default,,0,0,0,,但如果我说x的平方根或者10的平方根 Dialogue: 0,0:43:57.55,0:44:00.81,Default,,0,0,0,,并没有说清楚我对什么做了定义 Dialogue: 0,0:44:03.10,0:44:04.91,Default,,0,0,0,,所以让我换个方式来进行定义 Dialogue: 0,0:44:05.74,0:44:08.21,Default,,0,0,0,,这样可以清楚的看到定义的具体内容 Dialogue: 0,0:44:08.54,0:44:29.39,Default,,0,0,0,,我定义“square”为“(lambda (x) (* x x))” Dialogue: 0,0:44:36.56,0:44:42.05,Default,,0,0,0,,这里 我定义square就像我某命名为A一样 Dialogue: 0,0:44:43.23,0:44:44.72,Default,,0,0,0,,我定义square Dialogue: 0,0:44:44.75,0:44:48.39,Default,,0,0,0,,这里 我把这个组合式的值命名为A Dialogue: 0,0:44:49.29,0:44:52.41,Default,,0,0,0,,在这里 我把这个东西命名为square Dialogue: 0,0:44:52.43,0:44:53.44,Default,,0,0,0,,以lambda开头 Dialogue: 0,0:44:53.45,0:44:56.77,Default,,0,0,0,,lambda在Lisp中用以构建一个过程 Dialogue: 0,0:45:00.24,0:45:02.91,Default,,0,0,0,,请仔细看一下幻灯片上的内容 Dialogue: 0,0:45:04.27,0:45:05.81,Default,,0,0,0,,这个定义读作 Dialogue: 0,0:45:05.85,0:45:10.33,Default,,0,0,0,,将square定义为 Dialogue: 0,0:45:12.78,0:45:13.97,Default,,0,0,0,,一个由lambda构造的 Dialogue: 0,0:45:14.06,0:45:17.49,Default,,0,0,0,,一个有带有参数x的过程 Dialogue: 0,0:45:19.26,0:45:24.09,Default,,0,0,0,,而该过程返回将x自乘的结果 Dialogue: 0,0:45:24.97,0:45:33.12,Default,,0,0,0,,一般来讲 这是最佳的定义方式 Dialogue: 0,0:45:33.41,0:45:35.20,Default,,0,0,0,,因为这个更加方便一点 Dialogue: 0,0:45:35.21,0:45:38.67,Default,,0,0,0,,但是也别忘了它实质上也是这个 Dialogue: 0,0:45:38.86,0:45:41.41,Default,,0,0,0,,事实上 就Lisp解释器而言 Dialogue: 0,0:45:41.61,0:45:45.55,Default,,0,0,0,,这两种方法没有区别 Dialogue: 0,0:45:46.51,0:45:53.29,Default,,0,0,0,,换句话说 这只是一种语法糖 Dialogue: 0,0:45:54.41,0:45:55.80,Default,,0,0,0,,语法糖的意思就是 Dialogue: 0,0:45:56.35,0:46:00.83,Default,,0,0,0,,这种形式输入更方便一些 Dialogue: 0,0:46:01.12,0:46:06.11,Default,,0,0,0,,这只是这下面的有lambda的表达式的语法糖而已 Dialogue: 0,0:46:07.31,0:46:10.62,Default,,0,0,0,,你应该记住 Dialogue: 0,0:46:10.80,0:46:13.87,Default,,0,0,0,,当我这样写的时候 其实是在对某个东西进行命名 Dialogue: 0,0:46:14.46,0:46:16.22,Default,,0,0,0,,我将其命名为square Dialogue: 0,0:46:16.24,0:46:19.90,Default,,0,0,0,,square代表一个构建好的过程 Dialogue: 0,0:46:21.20,0:46:23.90,Default,,0,0,0,,让我们看看在计算机里面又是 怎样的吧 Dialogue: 0,0:46:24.78,0:46:35.95,Default,,0,0,0,,定义“(square x)”为x乘以x的积 Dialogue: 0,0:46:49.65,0:46:52.32,Default,,0,0,0,,将它送入Lisp Dialogue: 0,0:46:53.49,0:46:53.92,Default,,0,0,0,,返回square Dialogue: 0,0:46:53.93,0:46:56.29,Default,,0,0,0,,现在 我已经将某个东西命名为square了 Dialogue: 0,0:46:56.45,0:47:02.88,Default,,0,0,0,,完毕后 我就可以问Lisp 1001的平方是多少 Dialogue: 0,0:47:05.26,0:47:17.69,Default,,0,0,0,,或者更通常的来说 我可以问 5加上7的和的平方是多少 Dialogue: 0,0:47:22.81,0:47:24.95,Default,,0,0,0,,12的平方是144 Dialogue: 0,0:47:25.07,0:47:28.86,Default,,0,0,0,,在某些组合式中我亦可把square当作一个元素 Dialogue: 0,0:47:28.88,0:47:37.50,Default,,0,0,0,,3的平方加上4的平方的和是多少 Dialogue: 0,0:47:42.53,0:47:44.09,Default,,0,0,0,,9加上16得25 Dialogue: 0,0:47:44.91,0:47:50.54,Default,,0,0,0,,我可以将square作为元素用于更复杂的式子 Dialogue: 0,0:47:50.59,0:48:00.51,Default,,0,0,0,,比如 1001的平方点的平方的平方是多少 Dialogue: 0,0:48:07.89,0:48:10.63,Default,,0,0,0,,这就是1001点的平方的平方的平方 Dialogue: 0,0:48:11.20,0:48:15.45,Default,,0,0,0,,我也可以问Lisp square本身是什么 Dialogue: 0,0:48:15.68,0:48:17.16,Default,,0,0,0,,它的值是是什么 Dialogue: 0,0:48:17.44,0:48:22.14,Default,,0,0,0,,Lisp用一种约定的方法告诉我这是一个过程 Dialogue: 0,0:48:22.27,0:48:23.98,Default,,0,0,0,,它返回 复合过程square Dialogue: 0,0:48:24.25,0:48:27.92,Default,,0,0,0,,记住 square的值是一个过程 Dialogue: 0,0:48:29.15,0:48:30.89,Default,,0,0,0,,而那些用星号和括号的记法 Dialogue: 0,0:48:31.10,0:48:34.78,Default,,0,0,0,,只是Lisp用来描述这个过程的约定 Dialogue: 0,0:48:36.11,0:48:41.33,Default,,0,0,0,,让我们再看两个关于define的例子 Dialogue: 0,0:48:44.91,0:48:46.91,Default,,0,0,0,,这有两个过程 Dialogue: 0,0:48:47.36,0:48:52.84,Default,,0,0,0,,定义x和y的平均值为x加上y的和除以2的商 Dialogue: 0,0:48:54.67,0:49:01.49,Default,,0,0,0,,以及定义好平方和平均值后 我可以定义均方 Dialogue: 0,0:49:01.65,0:49:04.71,Default,,0,0,0,,我可以用它们来讨论某元素的均方 Dialogue: 0,0:49:04.91,0:49:09.26,Default,,0,0,0,,即x的平方与y的平方的平均值 Dialogue: 0,0:49:10.97,0:49:13.63,Default,,0,0,0,,当定义好它们后 我可以问 Dialogue: 0,0:49:13.66,0:49:24.88,Default,,0,0,0,,2和3的均方是多少 Dialogue: 0,0:49:25.23,0:49:30.24,Default,,0,0,0,,我将会得到 4和9的平均值 即6.5 Dialogue: 0,0:49:32.85,0:49:36.64,Default,,0,0,0,,关键点在于 定义了square后 Dialogue: 0,0:49:36.64,0:49:38.67,Default,,0,0,0,,我可以把它当作一个基本元素来使用 Dialogue: 0,0:49:41.41,0:49:43.07,Default,,0,0,0,,因此在这里 Dialogue: 0,0:49:44.65,0:49:45.74,Default,,0,0,0,,我在讨论均方的时候 Dialogue: 0,0:49:47.29,0:49:52.56,Default,,0,0,0,,从这点来说 定义均方的人没有必要知道 Dialogue: 0,0:49:52.61,0:49:55.76,Default,,0,0,0,,究竟square是由语言内建支持 Dialogue: 0,0:49:56.94,0:49:58.93,Default,,0,0,0,,还是自定义的过程 Dialogue: 0,0:49:59.73,0:50:01.28,Default,,0,0,0,,这是Lisp的关键之一 Dialogue: 0,0:50:02.30,0:50:07.52,Default,,0,0,0,,你无法准确区别 Dialogue: 0,0:50:07.53,0:50:11.82,Default,,0,0,0,,哪些是语言的基本对象 哪些是语言的内建支持 Dialogue: 0,0:50:12.83,0:50:14.73,Default,,0,0,0,,用户使用时则无需关心这些 Dialogue: 0,0:50:14.93,0:50:18.51,Default,,0,0,0,,你自己构建的东西看起来就像是语言自带的基本对象 Dialogue: 0,0:50:18.51,0:50:19.53,Default,,0,0,0,,具有同样的能力和灵活性 Dialogue: 0,0:50:19.57,0:50:22.57,Default,,0,0,0,,大家可以在课后上机做做测试 Dialogue: 0,0:50:24.75,0:50:26.30,Default,,0,0,0,,我们接下来讨论一下“+”吧 Dialogue: 0,0:50:26.72,0:50:30.09,Default,,0,0,0,,好的 让我们在计算机中看看 Dialogue: 0,0:50:30.11,0:50:32.33,Default,,0,0,0,,“+”的值是什么 Dialogue: 0,0:50:34.40,0:50:37.20,Default,,0,0,0,,注意Lisp在下面的输出 Dialogue: 0,0:50:37.25,0:50:38.81,Default,,0,0,0,,复合过程“+” Dialogue: 0,0:50:39.89,0:50:42.29,Default,,0,0,0,,因为在此系统中 Dialogue: 0,0:50:42.33,0:50:45.49,Default,,0,0,0,,“+”运算符是一个复合过程 Dialogue: 0,0:50:45.97,0:50:47.97,Default,,0,0,0,,但如果我不输入进去做下测试 你永远不会知道 Dialogue: 0,0:50:48.06,0:50:49.68,Default,,0,0,0,,所以这没什么不同 Dialogue: 0,0:50:49.84,0:50:50.51,Default,,0,0,0,,我们并不关心这些 Dialogue: 0,0:50:50.56,0:50:53.39,Default,,0,0,0,,它比我们日常处理的问题更加抽象一些 Dialogue: 0,0:50:54.17,0:50:59.11,Default,,0,0,0,,其关键点在于你无法分辨出 Dialogue: 0,0:50:59.17,0:51:03.82,Default,,0,0,0,,内建元素与复合元素之间的不同 Dialogue: 0,0:51:03.84,0:51:04.38,Default,,0,0,0,,为什么会这样呢? Dialogue: 0,0:51:04.38,0:51:08.07,Default,,0,0,0,,因为复合元素经过了一次抽象封装 (以致于无法分辨) Dialogue: 0,0:51:09.05,0:51:11.61,Default,,0,0,0,,我们已经介绍了Lisp的大多数元素了 Dialogue: 0,0:51:12.67,0:51:14.53,Default,,0,0,0,,还有一个需要进行讨论的 Dialogue: 0,0:51:14.57,0:51:16.53,Default,,0,0,0,,就是如何进行分情况分析 Dialogue: 0,0:51:16.59,0:51:17.70,Default,,0,0,0,,举个例子 Dialogue: 0,0:51:18.96,0:51:24.08,Default,,0,0,0,,让我们考虑绝对值函数的数学定义 Dialogue: 0,0:51:24.11,0:51:30.03,Default,,0,0,0,,我或许会说x的绝对值这样是一个函数 Dialogue: 0,0:51:30.16,0:51:37.24,Default,,0,0,0,,若x小于0 则为-x Dialogue: 0,0:51:37.92,0:51:41.13,Default,,0,0,0,,若x等于0 则为0 Dialogue: 0,0:51:42.64,0:51:46.62,Default,,0,0,0,,若x大于0 则就是x Dialogue: 0,0:51:49.15,0:51:51.90,Default,,0,0,0,,而Lisp则有一套分情况分析方法 Dialogue: 0,0:51:52.11,0:51:53.85,Default,,0,0,0,,以绝对值定义为例 我给大家说明一下 Dialogue: 0,0:51:55.55,0:52:02.41,Default,,0,0,0,,定义绝对值为 x是有多种情况的 Dialogue: 0,0:52:03.02,0:52:05.67,Default,,0,0,0,,这就是分情况分析 Dialogue: 0,0:52:09.23,0:52:19.09,Default,,0,0,0,,如果x小于0 则结果为-x Dialogue: 0,0:52:22.99,0:52:24.88,Default,,0,0,0,,我这里写的是一个子句 Dialogue: 0,0:52:24.99,0:52:35.54,Default,,0,0,0,,这整个是一个由两部分组成的条件表达式 Dialogue: 0,0:52:36.35,0:52:44.70,Default,,0,0,0,,这个部分叫做谓词或者条件 Dialogue: 0,0:52:44.83,0:52:45.90,Default,,0,0,0,,这就是一种情况(条件) Dialogue: 0,0:52:46.11,0:52:48.29,Default,,0,0,0,,用以表达条件的东西叫做谓词 Dialogue: 0,0:52:48.33,0:52:51.05,Default,,0,0,0,,Lisp中的谓词是一种 Dialogue: 0,0:52:51.37,0:52:52.87,Default,,0,0,0,,可以返回true或者false的东西 Dialogue: 0,0:52:53.53,0:52:56.13,Default,,0,0,0,,比如说“小于”是Lisp中的一个基本过程 Dialogue: 0,0:52:57.29,0:52:59.08,Default,,0,0,0,,它返回true或者false Dialogue: 0,0:53:00.54,0:53:06.32,Default,,0,0,0,,子句其余部分为一个动作或者需要做的事 Dialogue: 0,0:53:06.93,0:53:08.14,Default,,0,0,0,,本例中为true Dialogue: 0,0:53:08.17,0:53:09.81,Default,,0,0,0,,在这里 我则是取x的相反数 Dialogue: 0,0:53:10.08,0:53:14.41,Default,,0,0,0,,有趣的是 Lisp中减运算符符与相反数运算符相同 Dialogue: 0,0:53:14.56,0:53:18.43,Default,,0,0,0,,如果有两个及两个以上的参数 Dialogue: 0,0:53:18.58,0:53:22.49,Default,,0,0,0,,正如我们看到的 假设刚好有两个参数 就从第一个中减去第二个 Dialogue: 0,0:53:22.53,0:53:24.13,Default,,0,0,0,,如果只有一个参数 则取其相反数 Dialogue: 0,0:53:25.13,0:53:27.87,Default,,0,0,0,,这与前面相符合 Dialogue: 0,0:53:27.87,0:53:29.69,Default,,0,0,0,,这又是一个COND子句 Dialogue: 0,0:53:30.64,0:53:35.87,Default,,0,0,0,,这是说 在x等于0的时候 结果为0 Dialogue: 0,0:53:37.95,0:53:44.75,Default,,0,0,0,,在x大于0的时候 结果为x Dialogue: 0,0:53:45.33,0:53:49.38,Default,,0,0,0,,闭合子句 闭合COND 闭合define Dialogue: 0,0:53:49.57,0:53:51.29,Default,,0,0,0,,这就是绝对值的定义 Dialogue: 0,0:53:51.31,0:53:53.66,Default,,0,0,0,,你会发现分情况分析 Dialogue: 0,0:53:53.66,0:53:56.04,Default,,0,0,0,,与数学中所用的非常相似 Dialogue: 0,0:53:58.14,0:54:03.07,Default,,0,0,0,,当然还有一些不常用的受限的分情况分析方法 Dialogue: 0,0:54:03.07,0:54:06.24,Default,,0,0,0,,很多时候 你在进行分情况分析时只有一种情况 Dialogue: 0,0:54:06.93,0:54:08.07,Default,,0,0,0,,你首先进行测试 Dialogue: 0,0:54:08.33,0:54:10.75,Default,,0,0,0,,然后根据返回的为true或false来决定如何处理 Dialogue: 0,0:54:11.01,0:54:15.90,Default,,0,0,0,,这是另外一种定义绝对值的方法 Dialogue: 0,0:54:16.00,0:54:17.19,Default,,0,0,0,,但看起来是几乎一样的 Dialogue: 0,0:54:17.66,0:54:22.56,Default,,0,0,0,,像这样 如果x小于0 结果则为x的相反数 Dialogue: 0,0:54:24.41,0:54:25.97,Default,,0,0,0,,否则 结果即为x Dialogue: 0,0:54:26.05,0:54:27.25,Default,,0,0,0,,我们将会大量的使用“if” Dialogue: 0,0:54:27.29,0:54:29.13,Default,,0,0,0,,再次声明 Dialogue: 0,0:54:29.13,0:54:32.70,Default,,0,0,0,,你们在这里看到的绝对值形式 Dialogue: 0,0:54:34.30,0:54:36.98,Default,,0,0,0,,和我在黑板上写的那种 Dialogue: 0,0:54:37.52,0:54:38.80,Default,,0,0,0,,本质上是一样的 Dialogue: 0,0:54:39.09,0:54:42.26,Default,,0,0,0,,而“if”和“COND”则是—— Dialogue: 0,0:54:42.30,0:54:44.45,Default,,0,0,0,,你可以把“COND”当做“if”的语法糖 Dialogue: 0,0:54:44.99,0:54:47.36,Default,,0,0,0,,或者“if”是“COND”的语法糖 Dialogue: 0,0:54:47.39,0:54:48.65,Default,,0,0,0,,这没什么区别 Dialogue: 0,0:54:49.21,0:54:51.35,Default,,0,0,0,,Lisp系统的设计者会从中会选择一个 Dialogue: 0,0:54:51.39,0:54:52.97,Default,,0,0,0,,然后依照这个来实现另外一个 Dialogue: 0,0:54:53.15,0:54:54.67,Default,,0,0,0,,你首先实现哪一个都无所谓 Dialogue: 0,0:55:02.27,0:55:05.36,Default,,0,0,0,,让我们停下来 解决几点疑问 Dialogue: 0,0:55:05.69,0:55:10.08,Default,,0,0,0,,为什么我有时用define时 Dialogue: 0,0:55:11.09,0:55:14.75,Default,,0,0,0,,我在这里使用了一个左括号 Dialogue: 0,0:55:14.81,0:55:16.45,Default,,0,0,0,,输入 define (XXX Dialogue: 0,0:55:16.86,0:55:20.81,Default,,0,0,0,,而有时我这样写时却没加左括号 Dialogue: 0,0:55:22.06,0:55:27.23,Default,,0,0,0,,是因为你所见的 Dialogue: 0,0:55:27.26,0:55:29.41,Default,,0,0,0,,这种“define”表达式 Dialogue: 0,0:55:29.47,0:55:32.13,Default,,0,0,0,,对于定义过程来讲是非常特殊 Dialogue: 0,0:55:33.61,0:55:40.21,Default,,0,0,0,,再次强调 这实际上是说我定义这个叫square的符号为这个 Dialogue: 0,0:55:41.45,0:55:45.98,Default,,0,0,0,,你所知道的则是 你先写一个“define” Dialogue: 0,0:55:47.15,0:55:50.06,Default,,0,0,0,,然后你再写一个符号 没有左括号 Dialogue: 0,0:55:50.17,0:55:51.49,Default,,0,0,0,,这是你将要定义的符号 Dialogue: 0,0:55:52.08,0:55:53.70,Default,,0,0,0,,这又是你要将其定义为什么 Dialogue: 0,0:55:54.65,0:55:57.55,Default,,0,0,0,,就像这儿和这儿 Dialogue: 0,0:55:57.61,0:56:00.29,Default,,0,0,0,,这是“define”的基本使用方法 Dialogue: 0,0:56:01.12,0:56:03.65,Default,,0,0,0,,然而 这种特殊的语法技巧 Dialogue: 0,0:56:04.29,0:56:07.04,Default,,0,0,0,,使得你可以定义像这样的过程 Dialogue: 0,0:56:08.17,0:56:11.49,Default,,0,0,0,,因此区别就在于你是否定义了一个过程 Dialogue: 0,0:56:12.91,0:56:37.60,Default,,0,0,0,,[音乐] Dialogue: 0,0:56:38.05,0:56:41.98,Default,,0,0,0,,信不信由你 你们已经学了足够多的Lisp的知识了 Dialogue: 0,0:56:42.78,0:56:45.42,Default,,0,0,0,,现在你基本上可以编写 Dialogue: 0,0:56:46.25,0:56:49.63,Default,,0,0,0,,FORTRAN、Basic或者其它语言中一样的 Dialogue: 0,0:56:49.66,0:56:51.01,Default,,0,0,0,,数值计算过程了 Dialogue: 0,0:56:52.05,0:56:54.76,Default,,0,0,0,,或许你会说 这不可能 Dialogue: 0,0:56:54.81,0:56:56.65,Default,,0,0,0,,因为你知道这些语言有 Dialogue: 0,0:56:56.65,0:57:00.22,Default,,0,0,0,,像“for”语句和“do-until-whil”语句的东西 Dialogue: 0,0:57:00.99,0:57:04.59,Default,,0,0,0,,实际上这些我们一点也用不着 Dialogue: 0,0:57:05.05,0:57:07.13,Default,,0,0,0,,本课中我们一点也不会使用这些东西 Dialogue: 0,0:57:08.25,0:57:10.16,Default,,0,0,0,,我给你们来个下马威 Dialogue: 0,0:57:10.25,0:57:13.61,Default,,0,0,0,,回过头来看看平方根 Dialogue: 0,0:57:13.65,0:57:19.03,Default,,0,0,0,,让我们看看亚历山大的Heron提出的平方根算法 Dialogue: 0,0:57:19.09,0:57:19.97,Default,,0,0,0,,想想它是怎么说的 Dialogue: 0,0:57:20.06,0:57:23.67,Default,,0,0,0,,算法说 为了找到X的平方根的近似值 Dialogue: 0,0:57:25.07,0:57:26.16,Default,,0,0,0,,你做出猜测 Dialogue: 0,0:57:27.45,0:57:31.88,Default,,0,0,0,,然后通过取guess和X/guess的平均数来改进猜测 Dialogue: 0,0:57:32.94,0:57:36.06,Default,,0,0,0,,你不断改进猜测 直到这个猜测足够好 Dialogue: 0,0:57:36.72,0:57:38.43,Default,,0,0,0,,我已经提到过这种想法 Dialogue: 0,0:57:38.56,0:57:42.24,Default,,0,0,0,,这种想法是说 如果你最初采用的猜测 Dialogue: 0,0:57:43.04,0:57:46.91,Default,,0,0,0,,真真切切的等于X的平方根 Dialogue: 0,0:57:47.15,0:57:50.06,Default,,0,0,0,,那么G就会等于X/G Dialogue: 0,0:57:52.89,0:57:55.33,Default,,0,0,0,,如果你算出平方根 对其取平均数并不会改变它 Dialogue: 0,0:57:55.69,0:57:59.62,Default,,0,0,0,,如果你所采用的G比X的平方根大 Dialogue: 0,0:58:00.38,0:58:02.94,Default,,0,0,0,,那么X/G就会比X的平方根小 Dialogue: 0,0:58:03.21,0:58:05.37,Default,,0,0,0,,因此当你取G与X/G的平均值时 Dialogue: 0,0:58:05.63,0:58:07.57,Default,,0,0,0,,就得到了两者之间的某数 Dialogue: 0,0:58:08.96,0:58:12.95,Default,,0,0,0,,同理 若你采用的G过小 答案则会过大 Dialogue: 0,0:58:13.12,0:58:14.81,Default,,0,0,0,,如果你采用了一个太大的G Dialogue: 0,0:58:16.32,0:58:18.06,Default,,0,0,0,,如果你的G比X的平方根还要大的话 Dialogue: 0,0:58:18.08,0:58:20.35,Default,,0,0,0,,X/G就会比X的平方根还要小 Dialogue: 0,0:58:21.23,0:58:23.65,Default,,0,0,0,,因此取平均值使得你总可以得到两者间的某数 Dialogue: 0,0:58:24.53,0:58:28.13,Default,,0,0,0,,这不是毫无意义的 它表明 Dialogue: 0,0:58:28.17,0:58:31.76,Default,,0,0,0,,事实上 如果G只差X的平方根一点的话 Dialogue: 0,0:58:31.81,0:58:37.99,Default,,0,0,0,,G和X/G的平均值就会慢慢的向X的平方根靠近 Dialogue: 0,0:58:38.03,0:58:38.99,Default,,0,0,0,,只要你不断的这样做 Dialogue: 0,0:58:39.42,0:58:41.18,Default,,0,0,0,,最终就可以不断地靠近 Dialogue: 0,0:58:41.71,0:58:42.85,Default,,0,0,0,,另外一个事实则是 Dialogue: 0,0:58:43.02,0:58:47.65,Default,,0,0,0,,你总可以使用1作为一个初始猜测值来开始计算 Dialogue: 0,0:58:49.23,0:58:51.35,Default,,0,0,0,,它总是朝X的平方根聚拢 Dialogue: 0,0:58:52.24,0:58:56.77,Default,,0,0,0,,这就是亚历山大的Heron的连续求平均值法 Dialogue: 0,0:58:56.81,0:58:59.21,Default,,0,0,0,,让我们在Lisp中实现 Dialogue: 0,0:59:00.57,0:59:02.61,Default,,0,0,0,,中心思想是 Dialogue: 0,0:59:02.65,0:59:07.19,Default,,0,0,0,,尝试将guess作为X的平方根的一个猜想意味着什么 Dialogue: 0,0:59:08.30,0:59:09.37,Default,,0,0,0,,我来编码 Dialogue: 0,0:59:09.79,0:59:25.02,Default,,0,0,0,,定义(try guess x) Dialogue: 0,0:59:26.45,0:59:28.24,Default,,0,0,0,,我们该如何做 我们会说 Dialogue: 0,0:59:28.29,0:59:45.26,Default,,0,0,0,,如果猜测精确到可以作为X的平方根 Dialogue: 0,0:59:46.54,0:59:49.52,Default,,0,0,0,,那么我们就可以将这个猜测作为答案 Dialogue: 0,0:59:51.61,0:59:57.01,Default,,0,0,0,,否则 我们就会尝试改进猜测 Dialogue: 0,0:59:58.19,1:00:04.24,Default,,0,0,0,,我们将通过改进这个猜测来作为X的平方根 Dialogue: 0,1:00:05.26,1:00:09.33,Default,,0,0,0,,并尝试是否为X平方根 Dialogue: 0,1:00:09.36,1:00:12.96,Default,,0,0,0,,闭合try 闭合if 闭合define Dialogue: 0,1:00:13.31,1:00:14.81,Default,,0,0,0,,这就是我们如何尝试一个猜测 Dialogue: 0,1:00:15.85,1:00:17.60,Default,,0,0,0,,然后 这个过程的下一步是说 Dialogue: 0,1:00:17.73,1:00:21.90,Default,,0,0,0,,为了计算平方根 Dialogue: 0,1:00:21.93,1:00:30.17,Default,,0,0,0,,定义计算X的平方根为 Dialogue: 0,1:00:30.80,1:00:35.79,Default,,0,0,0,,从1作为X的平方根的一个猜测开始尝试 Dialogue: 0,1:00:37.42,1:00:39.59,Default,,0,0,0,,我们必须定义一些其它的东西 Dialogue: 0,1:00:40.08,1:00:43.36,Default,,0,0,0,,我们必须说明 一个猜测如何才叫“足够好” Dialogue: 0,1:00:43.84,1:00:45.29,Default,,0,0,0,,我们又该如何改进这个猜测 Dialogue: 0,1:00:45.85,1:00:47.10,Default,,0,0,0,,那么让我们来看看 Dialogue: 0,1:00:47.39,1:00:54.24,Default,,0,0,0,,而改进一个X的平方根的一个猜测的算法则是 Dialogue: 0,1:00:54.64,1:00:57.18,Default,,0,0,0,,取平均数 Dialogue: 0,1:00:57.18,1:01:02.16,Default,,0,0,0,,我们取guess和X/guess的平均数 Dialogue: 0,1:01:02.99,1:01:04.57,Default,,0,0,0,,这就是我们如何改进一个猜测 Dialogue: 0,1:01:05.85,1:01:08.80,Default,,0,0,0,,为了确定一个猜测是否足够精确 我们需要做一下规定 Dialogue: 0,1:01:08.86,1:01:11.36,Default,,0,0,0,,假设这个是X的平方根的一个猜测 Dialogue: 0,1:01:11.37,1:01:14.03,Default,,0,0,0,,你可能做的一件事就是 Dialogue: 0,1:01:14.06,1:01:16.07,Default,,0,0,0,,当你采用这个猜测并将其平方 Dialogue: 0,1:01:16.64,1:01:18.41,Default,,0,0,0,,你会得到一个非常接近于X的数 Dialogue: 0,1:01:18.59,1:01:21.10,Default,,0,0,0,,而表达这个想法的一种方式是 Dialogue: 0,1:01:21.12,1:01:24.31,Default,,0,0,0,,我们用X减去guess的平方 Dialogue: 0,1:01:25.15,1:01:27.15,Default,,0,0,0,,并且确认所得结果的绝对值是否 Dialogue: 0,1:01:27.20,1:01:32.05,Default,,0,0,0,,比一个由你规定的很小的数还要小 Dialogue: 0,1:01:34.70,1:01:41.42,Default,,0,0,0,,因此 我们就有了计算X的平方根的一整套过程 Dialogue: 0,1:01:41.47,1:01:43.53,Default,,0,0,0,,我们再来深入观察一下这个结构 Dialogue: 0,1:01:47.84,1:01:49.12,Default,,0,0,0,,我搞定了整件事 Dialogue: 0,1:01:49.15,1:01:55.44,Default,,0,0,0,,我有一个用于计算X的平方根的记号 Dialogue: 0,1:01:55.53,1:01:56.88,Default,,0,0,0,,这是一种模块 Dialogue: 0,1:01:57.05,1:01:58.46,Default,,0,0,0,,也是一种黑盒 Dialogue: 0,1:01:58.72,1:02:08.02,Default,,0,0,0,,它的定义依赖于如何尝试将一个猜测值作为X的平方根 Dialogue: 0,1:02:09.31,1:02:14.10,Default,,0,0,0,,定义try是用来 Dialogue: 0,1:02:14.61,1:02:18.03,Default,,0,0,0,,确认某数是否足够精确以及如何去改进该数 Dialogue: 0,1:02:18.73,1:02:19.68,Default,,0,0,0,,这是good-enogh? Dialogue: 0,1:02:19.89,1:02:28.85,Default,,0,0,0,,try的定义依赖于good-enough?和improve Dialogue: 0,1:02:30.96,1:02:32.56,Default,,0,0,0,,让我们来看看我填入了些什么 Dialogue: 0,1:02:32.71,1:02:34.29,Default,,0,0,0,,如果我向下拓展这棵树 Dialogue: 0,1:02:34.73,1:02:38.49,Default,,0,0,0,,good-enough?的定义依赖于abs和square Dialogue: 0,1:02:40.97,1:02:44.13,Default,,0,0,0,,而improve的定义依赖于averaging Dialogue: 0,1:02:45.17,1:02:46.70,Default,,0,0,0,,而其它的都是一些基本运算符 Dialogue: 0,1:02:46.72,1:02:48.88,Default,,0,0,0,,平方根的定义依赖于try Dialogue: 0,1:02:48.88,1:02:53.31,Default,,0,0,0,,try的定义依赖于good-enough?和improve Dialogue: 0,1:02:54.01,1:02:55.39,Default,,0,0,0,,甚至依赖于try本身 Dialogue: 0,1:02:55.58,1:03:00.86,Default,,0,0,0,,因此try也按照它如何应用于自身而进行定义 Dialogue: 0,1:03:02.75,1:03:04.72,Default,,0,0,0,,额 这可能会使你有点糊涂 Dialogue: 0,1:03:04.72,1:03:08.16,Default,,0,0,0,,你的高中几何老师或许告诉过你 Dialogue: 0,1:03:08.67,1:03:12.57,Default,,0,0,0,,用一个东西自己去定义自己是很不对的 Dialogue: 0,1:03:12.88,1:03:13.92,Default,,0,0,0,,因为这根本行不通 Dialogue: 0,1:03:13.92,1:03:14.72,Default,,0,0,0,,这(种说法)是错的 Dialogue: 0,1:03:16.03,1:03:19.68,Default,,0,0,0,,有时候用一个东西自己来定义自己非常有意义 Dialogue: 0,1:03:20.16,1:03:24.38,Default,,0,0,0,,我们来看看这个例子 Dialogue: 0,1:03:24.38,1:03:26.89,Default,,0,0,0,,假设我问Lisp:2的平方根是多少 Dialogue: 0,1:03:26.91,1:03:30.33,Default,,0,0,0,,我们可以写出它究竟是什么意思 Dialogue: 0,1:03:32.65,1:03:34.67,Default,,0,0,0,,2的平方根是什么意思 Dialogue: 0,1:03:35.79,1:03:43.61,Default,,0,0,0,,意思就是我将用1作为2的平方根的一个猜测 Dialogue: 0,1:03:46.97,1:03:50.92,Default,,0,0,0,,然后我考虑 对于2的平方根来说 1是一个足够好的猜测么 Dialogue: 0,1:03:51.65,1:03:53.69,Default,,0,0,0,,这取决于good-enough?是如何判断的 Dialogue: 0,1:03:54.61,1:03:56.56,Default,,0,0,0,,本例中 good-enough?会说 Dialogue: 0,1:03:56.65,1:03:59.05,Default,,0,0,0,,不 对于2的平方根来说 1不是一个足够好的猜测 Dialogue: 0,1:03:59.79,1:04:08.22,Default,,0,0,0,,因此我会继续说 我试试一个改进值 Dialogue: 0,1:04:08.64,1:04:12.63,Default,,0,0,0,,改进猜测值1 Dialogue: 0,1:04:15.15,1:04:17.46,Default,,0,0,0,,然后将其作为2的平方根的一个猜测 Dialogue: 0,1:04:19.13,1:04:22.07,Default,,0,0,0,,改进猜测值1用作2的平方根 Dialogue: 0,1:04:22.09,1:04:25.08,Default,,0,0,0,,也就是说我取1和2/1的平均值 Dialogue: 0,1:04:27.10,1:04:29.10,Default,,0,0,0,,因此我们将取平均数 Dialogue: 0,1:04:29.58,1:04:39.44,Default,,0,0,0,,这段代码将会取1和2/1的平均数 Dialogue: 0,1:04:40.83,1:04:42.75,Default,,0,0,0,,那么这段代码 Dialogue: 0,1:04:43.85,1:04:46.72,Default,,0,0,0,,我算算 结果是1.5 Dialogue: 0,1:04:49.07,1:04:54.40,Default,,0,0,0,,因此这个(sqrt 2)还原到(try 1 2) Dialogue: 0,1:04:54.56,1:05:04.83,Default,,0,0,0,,然后还原到(try 1.5 2) Dialogue: 0,1:05:06.03,1:05:08.06,Default,,0,0,0,,因此这行得通 Dialogue: 0,1:05:08.11,1:05:09.52,Default,,0,0,0,,让我们看下剩下的步骤 Dialogue: 0,1:05:09.73,1:05:15.00,Default,,0,0,0,,如果我尝试1.5 则会还原到 Dialogue: 0,1:05:15.01,1:05:19.05,Default,,0,0,0,,1.5作为2的平方根的猜测 并不是足够好 Dialogue: 0,1:05:20.22,1:05:22.00,Default,,0,0,0,,然后又还原到 Dialogue: 0,1:05:22.01,1:05:26.17,Default,,0,0,0,,(try (average 1.5 (/ 2 1.5))) Dialogue: 0,1:05:28.29,1:05:30.37,Default,,0,0,0,,平均值是1.333 Dialogue: 0,1:05:31.18,1:05:35.24,Default,,0,0,0,,然后整个事又还原到(try 1.3333 2) Dialogue: 0,1:05:35.28,1:05:36.06,Default,,0,0,0,,如此进行下去 Dialogue: 0,1:05:38.01,1:05:41.66,Default,,0,0,0,,然后又还原到(good-enough? 1.4)或者其它的 Dialogue: 0,1:05:41.73,1:05:44.47,Default,,0,0,0,,然后这个(步骤)会持续进行到 Dialogue: 0,1:05:44.85,1:05:47.92,Default,,0,0,0,,good-enough?认为足够好了才停止 Dialogue: 0,1:05:47.97,1:05:51.28,Default,,0,0,0,,本例中 是1.4242或者其它的东西 Dialogue: 0,1:05:52.51,1:05:56.05,Default,,0,0,0,,因此这个这个过程运行得非常完美 Dialogue: 0,1:05:59.93,1:06:03.10,Default,,0,0,0,,这种定义方法叫做“递归定义” Dialogue: 0,1:06:14.40,1:06:20.96,Default,,0,0,0,,进行递归定义将会给你带来无穷威力 Dialogue: 0,1:06:21.95,1:06:23.05,Default,,0,0,0,,之前我已提到过 Dialogue: 0,1:06:23.09,1:06:27.21,Default,,0,0,0,,递归定义可以在不增加任何负担的前提下 Dialogue: 0,1:06:27.25,1:06:28.83,Default,,0,0,0,,仅仅通过调用过程 在达到条件之前 Dialogue: 0,1:06:29.73,1:06:33.66,Default,,0,0,0,,完成无限次的计算 Dialogue: 0,1:06:35.97,1:06:37.47,Default,,0,0,0,,还有一点要说明的 Dialogue: 0,1:06:37.71,1:06:44.21,Default,,0,0,0,,我再在这里给你们演示另外一种平方根的定义方法 Dialogue: 0,1:06:44.43,1:06:48.16,Default,,0,0,0,,这两种方法看起来像是一样的 Dialogue: 0,1:06:48.40,1:06:51.49,Default,,0,0,0,,在这儿 我把improve、good-enough?、try的定义 Dialogue: 0,1:06:51.52,1:06:56.16,Default,,0,0,0,,全都封装在了sqrt里面 Dialogue: 0,1:06:56.75,1:07:00.99,Default,,0,0,0,,因此实际上 我们构建了一个平方根盒子 Dialogue: 0,1:07:01.81,1:07:08.53,Default,,0,0,0,,我构建了一个其它人可以使用的平方根盒子 Dialogue: 0,1:07:08.57,1:07:11.47,Default,,0,0,0,,它们输入36 然后(盒子)输出6 Dialogue: 0,1:07:11.81,1:07:13.83,Default,,0,0,0,,但是 盒子里面封装的过程 Dialogue: 0,1:07:14.16,1:07:23.85,Default,,0,0,0,,就是try、good-enough?和improve的定义 Dialogue: 0,1:07:26.78,1:07:28.35,Default,,0,0,0,,它们都隐藏在盒子里面 Dialogue: 0,1:07:28.40,1:07:30.76,Default,,0,0,0,,这样做是因为 Dialogue: 0,1:07:31.18,1:07:32.85,Default,,0,0,0,,如果有人正在使用这个平方根 Dialogue: 0,1:07:33.21,1:07:34.73,Default,,0,0,0,,如果George正在使用这个平方根 Dialogue: 0,1:07:34.75,1:07:37.36,Default,,0,0,0,,George并不会关心 Dialogue: 0,1:07:38.29,1:07:40.03,Default,,0,0,0,,当我在实现平方根时 Dialogue: 0,1:07:40.21,1:07:44.45,Default,,0,0,0,,我定义了盒子内的那些try、good-enough?和improve过程 Dialogue: 0,1:07:46.40,1:07:49.33,Default,,0,0,0,,事实上 Harry可能会实现一个也具有 Dialogue: 0,1:07:49.37,1:07:50.96,Default,,0,0,0,,try、good-enough?和improve的立方根盒子 Dialogue: 0,1:07:51.44,1:07:53.34,Default,,0,0,0,,因此 为了不让整个系统变得混乱 Dialogue: 0,1:07:53.36,1:07:57.66,Default,,0,0,0,,Harry最好把这些内部过程封装在它的立方根过程里 Dialogue: 0,1:07:58.40,1:08:00.06,Default,,0,0,0,,这个叫做块结构 Dialogue: 0,1:08:00.32,1:08:08.96,Default,,0,0,0,,这是把东西打包到定义内部的一种方法 Dialogue: 0,1:08:09.97,1:08:12.96,Default,,0,0,0,,让我们回过头来再看看 Dialogue: 0,1:08:13.12,1:08:18.57,Default,,0,0,0,,这种过程的定义读作 定义“sqrt”为 Dialogue: 0,1:08:19.87,1:08:21.84,Default,,0,0,0,,那么 在其内部 Dialogue: 0,1:08:22.13,1:08:25.49,Default,,0,0,0,,我们已有improve的定义 Dialogue: 0,1:08:25.56,1:08:28.88,Default,,0,0,0,,我们已有good-enough?和try的定义 Dialogue: 0,1:08:29.73,1:08:32.38,Default,,0,0,0,,以及这些定义的实体 Dialogue: 0,1:08:32.48,1:08:35.07,Default,,0,0,0,,我求平方根的定义实体是从1开始尝试 Dialogue: 0,1:08:36.08,1:08:39.33,Default,,0,0,0,,注意这里 我不必将X当做参数传递 Dialogue: 0,1:08:39.87,1:08:42.32,Default,,0,0,0,,因为它们都在平方根内部 Dialogue: 0,1:08:42.84,1:08:44.65,Default,,0,0,0,,它相当于已知这个X了 Dialogue: 0,1:08:54.06,1:08:56.37,Default,,0,0,0,,我来总结下 Dialogue: 0,1:08:56.49,1:08:59.49,Default,,0,0,0,,我们从表述指令性知识 Dialogue: 0,1:08:59.51,1:09:03.18,Default,,0,0,0,,开始学习 Dialogue: 0,1:09:04.99,1:09:09.74,Default,,0,0,0,,这张幻灯片总结了一些关于Lisp的知识 Dialogue: 0,1:09:09.74,1:09:15.12,Default,,0,0,0,,我们从基本元素如“+”和“*”开始 Dialogue: 0,1:09:15.85,1:09:19.50,Default,,0,0,0,,一些用于测试某物小于或等于的谓词 Dialogue: 0,1:09:19.52,1:09:22.99,Default,,0,0,0,,事实上 我们正在使用的系统掩盖了很多细节 Dialogue: 0,1:09:23.02,1:09:25.85,Default,,0,0,0,,这些并不是系统的基本元素 但这无所谓 Dialogue: 0,1:09:26.62,1:09:28.59,Default,,0,0,0,,重要的是我们会把它们当作是基本元素 Dialogue: 0,1:09:28.61,1:09:29.81,Default,,0,0,0,,我们不会去研究系统的内部 Dialogue: 0,1:09:30.29,1:09:33.15,Default,,0,0,0,,我们也有一些基本数据和一些数 Dialogue: 0,1:09:34.62,1:09:37.66,Default,,0,0,0,,我们学习了合成的手段 组合的手段 Dialogue: 0,1:09:37.74,1:09:41.37,Default,,0,0,0,,用运算符和运算对象合成函数 Dialogue: 0,1:09:41.41,1:09:43.76,Default,,0,0,0,,和构建组合式的基本方法 Dialogue: 0,1:09:44.81,1:09:48.43,Default,,0,0,0,,还有一些像是“COND”、“if”和“define”的东西 Dialogue: 0,1:09:51.29,1:09:53.69,Default,,0,0,0,,具体来说 关于“define”的重点则是 Dialogue: 0,1:09:53.87,1:09:55.71,Default,,0,0,0,,它是一种进行抽象的方法 Dialogue: 0,1:09:55.73,1:09:57.70,Default,,0,0,0,,它是我们为某物命名的方法 Dialogue: 0,1:09:57.79,1:10:00.30,Default,,0,0,0,,我们之前提到过 从这里也可以看出来 Dialogue: 0,1:10:01.57,1:10:06.28,Default,,0,0,0,,有时候 我们需要研究如何通过组合基本数据来得到复合数据 Dialogue: 0,1:10:06.56,1:10:12.03,Default,,0,0,0,,以及如何抽象数据 使得你可以在一个更大的环境中 Dialogue: 0,1:10:12.06,1:10:13.07,Default,,0,0,0,,将其当作基本数据使用 Dialogue: 0,1:10:13.90,1:10:15.87,Default,,0,0,0,,这也是我们的目的所在 Dialogue: 0,1:10:16.38,1:10:22.05,Default,,0,0,0,,在我们讨论这个问题之前 下节课我们首先将会讨论 Dialogue: 0,1:10:23.26,1:10:26.76,Default,,0,0,0,,我们编写的过程与机器内部 Dialogue: 0,1:10:26.88,1:10:30.77,Default,,0,0,0,,进程之间的联系 Dialogue: 0,1:10:32.14,1:10:35.98,Default,,0,0,0,,接着 我们将跳出小规模的计算问题 Dialogue: 0,1:10:36.38,1:10:39.77,Default,,0,0,0,,来学习如何发挥Lisp的威力 Dialogue: 0,1:10:40.08,1:10:44.15,Default,,0,0,0,,来解决更加通用的计算问题 Dialogue: 0,1:10:44.81,1:10:46.17,Default,,0,0,0,,好了 大家还有什么问题么 Dialogue: 0,1:10:46.75,1:10:52.27,Default,,0,0,0,,学生:在定义A时 如果我们用一个括号将A括起来 Dialogue: 0,1:10:52.32,1:10:53.50,Default,,0,0,0,,会与不使用括号不同么? Dialogue: 0,1:10:53.60,1:10:56.88,Default,,0,0,0,,教授:如果我这样写 Dialogue: 0,1:10:57.53,1:11:02.13,Default,,0,0,0,,我则会是定义一个过程并命名为A Dialogue: 0,1:11:03.21,1:11:06.85,Default,,0,0,0,,本例中 这个过程没有参数 Dialogue: 0,1:11:06.85,1:11:09.61,Default,,0,0,0,,而当我运行它 则会返回5乘以5 Dialogue: 0,1:11:11.07,1:11:12.29,Default,,0,0,0,,学生:它们俩完成了相同的事 Dialogue: 0,1:11:12.32,1:11:13.92,Default,,0,0,0,,但本质上是否相同? Dialogue: 0,1:11:14.05,1:11:16.63,Default,,0,0,0,,教授:好 的确会有不同 之前的那一个 Dialogue: 0,1:11:17.02,1:11:18.35,Default,,0,0,0,,我还是在这里写清楚一点吧 Dialogue: 0,1:11:19.13,1:11:23.44,Default,,0,0,0,,我们还是把这个叫做A Dialogue: 0,1:11:24.13,1:11:27.76,Default,,0,0,0,,作为对比 我们假装这里有一个 Dialogue: 0,1:11:27.79,1:11:37.56,Default,,0,0,0,,我定义D为5乘以5 Dialogue: 0,1:11:40.22,1:11:41.57,Default,,0,0,0,,这两者的区别则是 Dialogue: 0,1:11:41.96,1:11:44.24,Default,,0,0,0,,让我们看看它们在Lisp解释器中是怎样的 Dialogue: 0,1:11:45.74,1:11:49.13,Default,,0,0,0,,我在Lisp中键入A 返回25 Dialogue: 0,1:11:52.83,1:11:57.81,Default,,0,0,0,,如果我仅仅键入D Dialogue: 0,1:11:58.49,1:12:05.55,Default,,0,0,0,,Lisp返回复合过程D Dialogue: 0,1:12:07.12,1:12:09.13,Default,,0,0,0,,因为D就是一个过程 Dialogue: 0,1:12:09.69,1:12:12.59,Default,,0,0,0,,我可以运行D 我可以问运行D的结果是什么 Dialogue: 0,1:12:12.59,1:12:15.23,Default,,0,0,0,,这是一个没有运算数的组合式 Dialogue: 0,1:12:16.45,1:12:19.07,Default,,0,0,0,,我考虑到它没有运算数 所以我在D后面没有键入任何东西 Dialogue: 0,1:12:19.39,1:12:21.34,Default,,0,0,0,,Lisp则会说结果是25 Dialogue: 0,1:12:23.01,1:12:29.52,Default,,0,0,0,,我再说周全一点 如果我键入 A的运行结果是多少 Dialogue: 0,1:12:29.54,1:12:30.57,Default,,0,0,0,,只能得到一个错误 Dialogue: 0,1:12:31.79,1:12:35.29,Default,,0,0,0,,跟这里的错误一样 Dialogue: 0,1:12:35.33,1:12:40.51,Default,,0,0,0,,这个错误是因为 A的值——25 Dialogue: 0,1:12:40.56,1:12:43.24,Default,,0,0,0,,并不是我可以应用于某物的运算符 Dialogue: 0,1:12:43.84,1:12:48.88,Default,,0,0,0,,MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:12:49.13,1:12:54.86,Default,,0,0,0,,本项目主页\Nhttps://github.com/FoOTOo/Learning-SICP ================================================ FILE: Ass/lec1a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal PlayResX: 640 PlayResY: 480 Audio URI: lec1a_Rerip_remux.mp4 Scroll Position: 752 Active Line: 753 Video Zoom Percent: 0.875 Video File: lec1a_Rerip_remux.mp4 Video Aspect Ratio: c1.33333 Video Position: 95862 Last Style Storage: Default YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Default,Calisto MT,23,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:14.71,0:00:17.89,Default,,0,0,0,,I'd like to welcome you to this course on computer science. Dialogue: 0,0:00:28.40,0:00:29.85,Default,,0,0,0,,Actually, that's a terrible way to start. Dialogue: 0,0:00:29.85,0:00:32.34,Default,,0,0,0,,Computer science is a terrible name for this business. Dialogue: 0,0:00:32.83,0:00:34.30,Default,,0,0,0,,First of all, it's not a science. Dialogue: 0,0:00:35.92,0:00:39.81,Default,,0,0,0,,It might be engineering or it might be art, Dialogue: 0,0:00:40.09,0:00:42.91,Default,,0,0,0,,but we'll actually see that computer so-called science Dialogue: 0,0:00:42.93,0:00:44.97,Default,,0,0,0,,actually has a lot in common with magic, Dialogue: 0,0:00:45.01,0:00:46.35,Default,,0,0,0,,and we'll see that in this course. Dialogue: 0,0:00:47.28,0:00:48.22,Default,,0,0,0,,So it's not a science. Dialogue: 0,0:00:48.23,0:00:52.30,Default,,0,0,0,,It's also not really very much about computers. Dialogue: 0,0:00:53.39,0:00:55.47,Default,,0,0,0,,And it's not about computers in the same sense Dialogue: 0,0:00:55.47,0:01:00.05,Default,,0,0,0,,that physics is not really about particle accelerators, Dialogue: 0,0:01:00.80,0:01:05.58,Default,,0,0,0,,and biology is not really about microscopes and petri dishes. Dialogue: 0,0:01:06.46,0:01:10.25,Default,,0,0,0,,And it's not about computers in the same sense Dialogue: 0,0:01:10.31,0:01:14.88,Default,,0,0,0,,that geometry is not really about using surveying instruments. Dialogue: 0,0:01:16.48,0:01:19.01,Default,,0,0,0,,In fact, there's a lot of commonality Dialogue: 0,0:01:19.33,0:01:21.45,Default,,0,0,0,,between computer science and geometry. Dialogue: 0,0:01:21.45,0:01:22.66,Default,,0,0,0,,Geometry, first of all, Dialogue: 0,0:01:23.02,0:01:24.98,Default,,0,0,0,,is another subject with a lousy name. Dialogue: 0,0:01:25.58,0:01:27.85,Default,,0,0,0,,The name comes from Gaia, meaning the Earth, Dialogue: 0,0:01:27.90,0:01:29.09,Default,,0,0,0,,and metron, meaning to measure. Dialogue: 0,0:01:29.82,0:01:33.39,Default,,0,0,0,,Geometry originally meant measuring the Earth or surveying. Dialogue: 0,0:01:34.37,0:01:36.89,Default,,0,0,0,,And the reason for that was that, thousands of years ago, Dialogue: 0,0:01:37.69,0:01:41.69,Default,,0,0,0,,the Egyptian priesthood developed the rudiments of geometry Dialogue: 0,0:01:42.59,0:01:46.33,Default,,0,0,0,,in order to figure out how to restore the boundaries of fields Dialogue: 0,0:01:46.35,0:01:48.69,Default,,0,0,0,,that were destroyed in the annual flooding of the Nile. Dialogue: 0,0:01:49.47,0:01:50.65,Default,,0,0,0,,And to the Egyptians who did that, Dialogue: 0,0:01:50.65,0:01:53.93,Default,,0,0,0,,geometry really was the use of surveying instruments. Dialogue: 0,0:01:55.63,0:01:58.55,Default,,0,0,0,,Now, the reason that we think computer science is about computers Dialogue: 0,0:01:58.57,0:02:02.49,Default,,0,0,0,,is pretty much the same reason that the Egyptians thought geometry Dialogue: 0,0:02:02.51,0:02:04.10,Default,,0,0,0,,was about surveying instruments. Dialogue: 0,0:02:04.59,0:02:07.37,Default,,0,0,0,,And that is, when some field is just getting started Dialogue: 0,0:02:07.39,0:02:09.86,Default,,0,0,0,,and you don't really understand it very well, Dialogue: 0,0:02:11.10,0:02:16.64,Default,,0,0,0,,it's very easy to confuse the essence of what you're doing with the tools that you use. Dialogue: 0,0:02:17.65,0:02:20.30,Default,,0,0,0,,And indeed, on some absolute scale of things, Dialogue: 0,0:02:20.30,0:02:24.82,Default,,0,0,0,,we probably know less about the essence of computer science Dialogue: 0,0:02:24.83,0:02:27.49,Default,,0,0,0,,than the ancient Egyptians really knew about geometry. Dialogue: 0,0:02:30.25,0:02:32.64,Default,,0,0,0,,Well, what do I mean by the essence of computer science? Dialogue: 0,0:02:32.65,0:02:34.41,Default,,0,0,0,,What do I mean by the essence of geometry? Dialogue: 0,0:02:34.41,0:02:36.45,Default,,0,0,0,,See, it's certainly true that these Egyptians went off Dialogue: 0,0:02:36.46,0:02:37.67,Default,,0,0,0,,and used surveying instruments, Dialogue: 0,0:02:37.69,0:02:41.55,Default,,0,0,0,,but when we look back on them after a couple of thousand years, Dialogue: 0,0:02:41.57,0:02:41.85,Default,,0,0,0,,we say, Dialogue: 0,0:02:41.87,0:02:43.64,Default,,0,0,0,,gee, what they were doing, Dialogue: 0,0:02:43.71,0:02:45.48,Default,,0,0,0,,the important stuff they were doing, Dialogue: 0,0:02:45.62,0:02:50.45,Default,,0,0,0,,was to begin to formalize notions about space and time, Dialogue: 0,0:02:51.58,0:02:57.53,Default,,0,0,0,,to start a way of talking about mathematical truths formally. Dialogue: 0,0:02:58.01,0:02:59.61,Default,,0,0,0,,That led to the axiomatic method. Dialogue: 0,0:02:59.61,0:03:02.53,Default,,0,0,0,,That led to sort of all of modern mathematics, Dialogue: 0,0:03:04.16,0:03:06.90,Default,,0,0,0,,figuring out a way to talk precisely about Dialogue: 0,0:03:07.25,0:03:10.19,Default,,0,0,0,,so-called declarative knowledge, what is true. Dialogue: 0,0:03:12.45,0:03:16.25,Default,,0,0,0,,Well, similarly, I think in the future people will look back and say, Dialogue: 0,0:03:16.27,0:03:19.36,Default,,0,0,0,,yes, those primitives in the 20th century were fiddling around Dialogue: 0,0:03:19.36,0:03:21.20,Default,,0,0,0,,with these gadgets called computers, Dialogue: 0,0:03:21.77,0:03:26.25,Default,,0,0,0,,but really what they were doing is starting to learn Dialogue: 0,0:03:26.25,0:03:32.55,Default,,0,0,0,,how to formalize intuitions about process, Dialogue: 0,0:03:32.64,0:03:34.13,Default,,0,0,0,,how to do things, Dialogue: 0,0:03:39.02,0:03:51.25,Default,,0,0,0,,starting to develop a way to talk precisely about how-to knowledge, Dialogue: 0,0:03:51.76,0:03:56.03,Default,,0,0,0,,as opposed to geometry that talks about what is true. Dialogue: 0,0:03:56.53,0:03:58.57,Default,,0,0,0,,Let me give you an example of that. Dialogue: 0,0:04:02.30,0:04:02.69,Default,,0,0,0,,Let's take a look Dialogue: 0,0:04:02.70,0:04:09.82,Default,,0,0,0,,Here is a piece of mathematics that says what a square root is. Dialogue: 0,0:04:10.09,0:04:14.35,Default,,0,0,0,,The square root of X is the number Y, Dialogue: 0,0:04:15.98,0:04:20.38,Default,,0,0,0,,such that Y squared is equal to X and Y is greater than 0. Dialogue: 0,0:04:20.43,0:04:22.50,Default,,0,0,0,,Now, that's a fine piece of mathematics, Dialogue: 0,0:04:22.88,0:04:25.25,Default,,0,0,0,,but just telling you what a square root is Dialogue: 0,0:04:25.63,0:04:30.29,Default,,0,0,0,,doesn't really say anything about how you might go out and find one. Dialogue: 0,0:04:31.42,0:04:35.90,Default,,0,0,0,,So let's contrast that with a piece of imperative knowledge, Dialogue: 0,0:04:37.13,0:04:39.92,Default,,0,0,0,,how you might go out and find a square root. Dialogue: 0,0:04:39.95,0:04:45.74,Default,,0,0,0,,This, in fact, also comes from Egypt, not ancient, ancient Egypt. Dialogue: 0,0:04:45.76,0:04:48.88,Default,,0,0,0,,This is an algorithm due to Heron of Alexandria, Dialogue: 0,0:04:49.90,0:04:52.77,Default,,0,0,0,,called how to find a square root by successive averaging. Dialogue: 0,0:04:52.89,0:04:55.13,Default,,0,0,0,,And what it says is that, Dialogue: 0,0:04:55.15,0:04:58.06,Default,,0,0,0,,in order to find a square root, Dialogue: 0,0:05:03.34,0:05:08.33,Default,,0,0,0,,you make a guess, you improve that guess -- Dialogue: 0,0:05:10.19,0:05:11.44,Default,,0,0,0,,and the way you improve the guess Dialogue: 0,0:05:11.45,0:05:13.95,Default,,0,0,0,,is to average the guess and X over the guess, Dialogue: 0,0:05:14.41,0:05:15.60,Default,,0,0,0,,and we'll talk a little bit later about Dialogue: 0,0:05:15.61,0:05:17.12,Default,,0,0,0,,why that's a reasonable thing-- Dialogue: 0,0:05:17.14,0:05:19.37,Default,,0,0,0,,and you keep improving the guess until it's good enough. Dialogue: 0,0:05:19.73,0:05:20.85,Default,,0,0,0,,That's a method. Dialogue: 0,0:05:20.99,0:05:24.65,Default,,0,0,0,,That's how to do something as opposed to Dialogue: 0,0:05:24.72,0:05:27.33,Default,,0,0,0,,declarative knowledge that says what you're looking for. Dialogue: 0,0:05:28.05,0:05:29.76,Default,,0,0,0,,That's a process. Dialogue: 0,0:05:34.40,0:05:38.25,Default,,0,0,0,,Well, what's a process in general? Dialogue: 0,0:05:39.01,0:05:40.14,Default,,0,0,0,,It's kind of hard to say. Dialogue: 0,0:05:40.16,0:05:43.72,Default,,0,0,0,,You can think of it as like a magical spirit Dialogue: 0,0:05:44.77,0:05:47.33,Default,,0,0,0,,that sort of lives in the computer and does something. Dialogue: 0,0:05:48.01,0:05:54.11,Default,,0,0,0,,And the thing that directs a process is Dialogue: 0,0:05:54.13,0:05:57.98,Default,,0,0,0,,a pattern of rules called a procedure. Dialogue: 0,0:06:01.98,0:06:04.73,Default,,0,0,0,,So procedures are the spells, if you like, Dialogue: 0,0:06:05.23,0:06:09.40,Default,,0,0,0,,that control these magical spirits that are the processes. Dialogue: 0,0:06:10.75,0:06:12.75,Default,,0,0,0,,I guess you know everyone needs a magical language, Dialogue: 0,0:06:12.77,0:06:14.55,Default,,0,0,0,,and sorcerers, real sorcerers, Dialogue: 0,0:06:14.57,0:06:18.59,Default,,0,0,0,,use ancient Arcadian or Sumerian or Babylonian or whatever. Dialogue: 0,0:06:18.62,0:06:20.09,Default,,0,0,0,,We're going to conjure our spirits Dialogue: 0,0:06:20.13,0:06:22.71,Default,,0,0,0,,in a magical language called Lisp, Dialogue: 0,0:06:24.37,0:06:28.01,Default,,0,0,0,,which is a language designed for talking about, Dialogue: 0,0:06:28.57,0:06:31.84,Default,,0,0,0,,for casting the spells that are procedures to direct the processes. Dialogue: 0,0:06:31.87,0:06:33.91,Default,,0,0,0,,Now, it's very easy to learn Lisp. Dialogue: 0,0:06:33.97,0:06:35.98,Default,,0,0,0,,In fact, in a few minutes, I'm going to teach you, Dialogue: 0,0:06:36.00,0:06:37.16,Default,,0,0,0,,essentially, all of Lisp. Dialogue: 0,0:06:37.37,0:06:38.96,Default,,0,0,0,,I'm going to teach you, essentially, all of the rules. Dialogue: 0,0:06:40.77,0:06:43.65,Default,,0,0,0,,And you shouldn't find that particularly surprising. Dialogue: 0,0:06:43.69,0:06:45.87,Default,,0,0,0,,That's sort of like saying it's very easy Dialogue: 0,0:06:45.90,0:06:47.01,Default,,0,0,0,,to learn the rules of chess. Dialogue: 0,0:06:47.04,0:06:48.13,Default,,0,0,0,,And indeed, in a few minutes, Dialogue: 0,0:06:48.17,0:06:49.70,Default,,0,0,0,,you can tell somebody the rules of chess. Dialogue: 0,0:06:50.81,0:06:52.24,Default,,0,0,0,,But of course, that's very different from Dialogue: 0,0:06:52.25,0:06:55.37,Default,,0,0,0,,saying you understand the implications of those rules Dialogue: 0,0:06:55.42,0:06:58.05,Default,,0,0,0,,and how to use those rules to become a masterful chess player. Dialogue: 0,0:06:58.49,0:06:59.82,Default,,0,0,0,,Well, Lisp is the same way. Dialogue: 0,0:07:00.41,0:07:02.18,Default,,0,0,0,,We're going to state the rules in a few minutes, Dialogue: 0,0:07:02.36,0:07:03.55,Default,,0,0,0,,and it'll be very easy to see. Dialogue: 0,0:07:03.62,0:07:07.09,Default,,0,0,0,,But what's really hard is going to be the implications of those rules, Dialogue: 0,0:07:07.32,0:07:10.46,Default,,0,0,0,,how you exploit those rules to be a master programmer. Dialogue: 0,0:07:12.06,0:07:15.29,Default,,0,0,0,,And the implications of those rules are going to take us the, Dialogue: 0,0:07:15.31,0:07:18.56,Default,,0,0,0,,well, the whole rest of the subject and, of course, way beyond. Dialogue: 0,0:07:21.45,0:07:23.11,Default,,0,0,0,,OK, so in computer science, Dialogue: 0,0:07:24.49,0:07:26.19,Default,,0,0,0,,we're in the business of Dialogue: 0,0:07:26.21,0:07:30.58,Default,,0,0,0,,formalizing this sort of how-to imperative knowledge, Dialogue: 0,0:07:30.62,0:07:32.10,Default,,0,0,0,,how to do stuff. Dialogue: 0,0:07:33.37,0:07:35.39,Default,,0,0,0,,And the real issues of computer science are, of course, Dialogue: 0,0:07:35.41,0:07:38.36,Default,,0,0,0,,not telling people how to do square roots. Dialogue: 0,0:07:39.09,0:07:40.06,Default,,0,0,0,,Because if that was all it was, Dialogue: 0,0:07:40.09,0:07:41.34,Default,,0,0,0,,there wouldn't be no big deal. Dialogue: 0,0:07:41.57,0:07:44.05,Default,,0,0,0,,The real problems come when we try to Dialogue: 0,0:07:44.08,0:07:46.16,Default,,0,0,0,,build very, very large systems, Dialogue: 0,0:07:46.61,0:07:49.53,Default,,0,0,0,,computer programs that are thousands of pages long, Dialogue: 0,0:07:49.58,0:07:53.98,Default,,0,0,0,,so long that nobody can really hold them in their heads all at once. Dialogue: 0,0:07:54.73,0:07:58.81,Default,,0,0,0,,And the only reason that that's possible is because Dialogue: 0,0:07:58.86,0:08:18.97,Default,,0,0,0,,there are techniques for controlling the complexity of these large systems. Dialogue: 0,0:08:20.30,0:08:22.69,Default,,0,0,0,,And these techniques that are controlling complexity Dialogue: 0,0:08:22.72,0:08:24.17,Default,,0,0,0,,are what this course is really about. Dialogue: 0,0:08:24.65,0:08:25.47,Default,,0,0,0,,And in some sense, Dialogue: 0,0:08:25.50,0:08:27.47,Default,,0,0,0,,that's really what computer science is about. Dialogue: 0,0:08:29.63,0:08:31.89,Default,,0,0,0,,Now, that may seem like a very strange thing to say. Dialogue: 0,0:08:31.92,0:08:35.61,Default,,0,0,0,,Because after all, a lot of people besides computer scientists Dialogue: 0,0:08:35.65,0:08:37.82,Default,,0,0,0,,deal with controlling complexity. Dialogue: 0,0:08:37.84,0:08:41.02,Default,,0,0,0,,A large airliner is an extremely complex system, Dialogue: 0,0:08:41.82,0:08:43.79,Default,,0,0,0,,and the aeronautical engineers who design that Dialogue: 0,0:08:44.05,0:08:46.13,Default,,0,0,0,,are dealing with immense complexity. Dialogue: 0,0:08:47.09,0:08:50.19,Default,,0,0,0,,But there's a difference between that kind of complexity Dialogue: 0,0:08:50.75,0:08:52.60,Default,,0,0,0,,and what we deal with in computer science. Dialogue: 0,0:08:55.18,0:08:57.73,Default,,0,0,0,,And that is that computer science, Dialogue: 0,0:08:57.79,0:09:00.09,Default,,0,0,0,,in some sense, isn't real. Dialogue: 0,0:09:02.69,0:09:06.62,Default,,0,0,0,,You see, when an engineer is designing a physical system, Dialogue: 0,0:09:07.14,0:09:08.49,Default,,0,0,0,,that's made out of real parts. Dialogue: 0,0:09:09.40,0:09:11.18,Default,,0,0,0,,The engineers who worry about that Dialogue: 0,0:09:11.85,0:09:16.65,Default,,0,0,0,,have to address problems of tolerance and approximation and noise in the system. Dialogue: 0,0:09:16.67,0:09:19.02,Default,,0,0,0,,So for example, as an electrical engineer, Dialogue: 0,0:09:19.09,0:09:21.71,Default,,0,0,0,,I can go off and easily build a one-stage amplifier Dialogue: 0,0:09:21.73,0:09:23.03,Default,,0,0,0,,or a two-stage amplifier, Dialogue: 0,0:09:23.41,0:09:25.39,Default,,0,0,0,,and I can imagine cascading a lot of them Dialogue: 0,0:09:25.45,0:09:26.91,Default,,0,0,0,,to build a million-stage amplifier. Dialogue: 0,0:09:26.99,0:09:28.75,Default,,0,0,0,,But it's ridiculous to build such a thing, Dialogue: 0,0:09:28.98,0:09:32.15,Default,,0,0,0,,because long before the millionth stage, Dialogue: 0,0:09:32.16,0:09:34.56,Default,,0,0,0,,the thermal noise in those components way at the beginning Dialogue: 0,0:09:34.57,0:09:36.80,Default,,0,0,0,,is going to get amplified and make the whole thing meaningless. Dialogue: 0,0:09:39.10,0:09:43.12,Default,,0,0,0,,Computer science deals with idealized components. Dialogue: 0,0:09:44.12,0:09:47.63,Default,,0,0,0,,We know as much as we want about these little program Dialogue: 0,0:09:47.65,0:09:49.56,Default,,0,0,0,,and data pieces that we're fitting things together. Dialogue: 0,0:09:51.90,0:09:53.20,Default,,0,0,0,,We don't have to worry about tolerance. Dialogue: 0,0:09:53.21,0:09:56.99,Default,,0,0,0,,And that means that, in building a large program, Dialogue: 0,0:09:58.13,0:10:00.03,Default,,0,0,0,,there's not all that much difference Dialogue: 0,0:10:00.35,0:10:04.18,Default,,0,0,0,,between what I can build and what I can imagine, Dialogue: 0,0:10:05.53,0:10:07.60,Default,,0,0,0,,because the parts are these abstract entities Dialogue: 0,0:10:07.63,0:10:10.32,Default,,0,0,0,,that I know as much as I want. Dialogue: 0,0:10:10.33,0:10:12.39,Default,,0,0,0,,I know about them as precisely as I'd like. Dialogue: 0,0:10:13.45,0:10:15.50,Default,,0,0,0,,So as opposed to other kinds of engineering, Dialogue: 0,0:10:15.66,0:10:17.42,Default,,0,0,0,,where the constraints on what you can build Dialogue: 0,0:10:17.44,0:10:18.90,Default,,0,0,0,,are the constraints of physical systems, Dialogue: 0,0:10:18.94,0:10:21.02,Default,,0,0,0,,the constraints of physics and noise and approximation, Dialogue: 0,0:10:21.21,0:10:25.60,Default,,0,0,0,,the constraints imposed in building large software systems Dialogue: 0,0:10:25.64,0:10:27.58,Default,,0,0,0,,are the limitations of our own minds. Dialogue: 0,0:10:29.12,0:10:29.98,Default,,0,0,0,,So in that sense, Dialogue: 0,0:10:30.00,0:10:33.67,Default,,0,0,0,,computer science is like an abstract form of engineering. Dialogue: 0,0:10:33.80,0:10:35.73,Default,,0,0,0,,It's the kind of engineering where you ignore Dialogue: 0,0:10:35.76,0:10:38.02,Default,,0,0,0,,the constraints that are imposed by reality. Dialogue: 0,0:10:41.97,0:10:46.15,Default,,0,0,0,,Well, what are some of these techniques? Dialogue: 0,0:10:46.28,0:10:48.39,Default,,0,0,0,,They're not special to computer science. Dialogue: 0,0:10:50.39,0:10:52.55,Default,,0,0,0,,First technique, which is used in all of engineering, Dialogue: 0,0:10:53.36,0:10:58.91,Default,,0,0,0,,is a kind of abstraction called black-box abstraction. Dialogue: 0,0:11:07.71,0:11:12.58,Default,,0,0,0,,Take something and build a box about it. Dialogue: 0,0:11:14.37,0:11:20.09,Default,,0,0,0,,Let's see, for example, if we looked at that square root method, Dialogue: 0,0:11:22.64,0:11:28.53,Default,,0,0,0,,I might want to take that and build a box. Dialogue: 0,0:11:29.89,0:11:37.52,Default,,0,0,0,,That sort of says, to find the square root of X. Dialogue: 0,0:11:38.86,0:11:41.27,Default,,0,0,0,,And that might be a whole complicated set of rules. Dialogue: 0,0:11:42.64,0:11:46.69,Default,,0,0,0,,And that might end up being a kind of thing where I can put in, Dialogue: 0,0:11:46.81,0:11:50.06,Default,,0,0,0,,say, 36 and say, what's the square root of 36? Dialogue: 0,0:11:50.25,0:11:51.46,Default,,0,0,0,,And out comes 6. Dialogue: 0,0:11:53.89,0:11:56.22,Default,,0,0,0,,And the important thing is that Dialogue: 0,0:11:56.24,0:12:00.03,Default,,0,0,0,,I'd like to design that so that Dialogue: 0,0:12:00.06,0:12:04.08,Default,,0,0,0,,if George comes along and would like to compute, Dialogue: 0,0:12:05.10,0:12:09.37,Default,,0,0,0,,say, the square root of A plus the square root of B, Dialogue: 0,0:12:11.34,0:12:14.38,Default,,0,0,0,,he can take this thing and use it as a module Dialogue: 0,0:12:14.43,0:12:15.74,Default,,0,0,0,,without having to look inside Dialogue: 0,0:12:15.77,0:12:17.31,Default,,0,0,0,,and build something that looks like this, Dialogue: 0,0:12:18.45,0:12:24.20,Default,,0,0,0,,like an A and a B and a square root box and another square root box Dialogue: 0,0:12:24.53,0:12:33.87,Default,,0,0,0,,and then something that adds that would put out the answer. Dialogue: 0,0:12:33.96,0:12:38.15,Default,,0,0,0,,And you can see, just from the fact that I want to do that, Dialogue: 0,0:12:38.92,0:12:40.42,Default,,0,0,0,,is from George's point of view, Dialogue: 0,0:12:40.51,0:12:43.10,Default,,0,0,0,,the internals of what's in here should not be important. Dialogue: 0,0:12:44.19,0:12:47.25,Default,,0,0,0,,So for instance, it shouldn't matter that, when I wrote this, Dialogue: 0,0:12:47.27,0:12:50.43,Default,,0,0,0,,I said I want to find the square root of X. Dialogue: 0,0:12:50.61,0:12:52.27,Default,,0,0,0,,I could have said the square root of Y, Dialogue: 0,0:12:52.72,0:12:55.62,Default,,0,0,0,,or the square root of A, or anything at all Dialogue: 0,0:12:56.70,0:13:02.35,Default,,0,0,0,,That's the fundamental notion of putting something in a box Dialogue: 0,0:13:03.53,0:13:06.44,Default,,0,0,0,,using black-box abstraction to suppress detail. Dialogue: 0,0:13:07.60,0:13:10.99,Default,,0,0,0,,And the reason for that is you want to go off and build bigger boxes. Dialogue: 0,0:13:12.05,0:13:14.57,Default,,0,0,0,,Now, there's another reason for doing black-box abstraction Dialogue: 0,0:13:14.59,0:13:18.41,Default,,0,0,0,,other than you want to suppress detail for building bigger boxes. Dialogue: 0,0:13:18.48,0:13:25.02,Default,,0,0,0,,Sometimes you want to say that your way of doing something, Dialogue: 0,0:13:25.04,0:13:26.88,Default,,0,0,0,,your how-to method, Dialogue: 0,0:13:28.44,0:13:30.79,Default,,0,0,0,,is an instance of a more general thing, Dialogue: 0,0:13:31.16,0:13:34.57,Default,,0,0,0,,and you'd like your language to be able to express that generality. Dialogue: 0,0:13:35.57,0:13:37.93,Default,,0,0,0,,Let me show you another example Dialogue: 0,0:13:37.97,0:13:38.86,Default,,0,0,0,,sticking with square roots. Dialogue: 0,0:13:38.89,0:13:42.16,Default,,0,0,0,,Let's go back and take another look at that slide Dialogue: 0,0:13:42.19,0:13:43.75,Default,,0,0,0,,with the square root algorithm on it. Dialogue: 0,0:13:44.16,0:13:45.62,Default,,0,0,0,,Remember what that says. Dialogue: 0,0:13:45.79,0:13:49.82,Default,,0,0,0,,That says, in order to do something, I make a guess, Dialogue: 0,0:13:50.62,0:13:54.84,Default,,0,0,0,,and I improve that guess, and I sort of keep improving that guess. Dialogue: 0,0:13:55.66,0:14:00.14,Default,,0,0,0,,So there's the general strategy of, I'm looking for something, Dialogue: 0,0:14:01.15,0:14:04.00,Default,,0,0,0,,and the way I find it is that I keep improving it. Dialogue: 0,0:14:04.16,0:14:10.25,Default,,0,0,0,,Now, that's a particular case of another kind of strategy Dialogue: 0,0:14:10.97,0:14:13.23,Default,,0,0,0,,for finding a fixed point of something. Dialogue: 0,0:14:14.57,0:14:16.59,Default,,0,0,0,,So you have a fixed point of a function. Dialogue: 0,0:14:17.13,0:14:26.03,Default,,0,0,0,,A fixed point of a function is something, is a value. Dialogue: 0,0:14:26.13,0:14:31.79,Default,,0,0,0,,A fixed point of a function F is a value Y, such that F of Y equals Y. Dialogue: 0,0:14:32.97,0:14:40.89,Default,,0,0,0,,And the way I might do that is start with a guess. Dialogue: 0,0:14:42.00,0:14:45.85,Default,,0,0,0,,And then if I want something that doesn't change when I keep applying F, Dialogue: 0,0:14:45.96,0:14:49.45,Default,,0,0,0,,is I'll keep applying F over and over until that result doesn't change very much. Dialogue: 0,0:14:50.05,0:14:51.93,Default,,0,0,0,,So there's a general strategy. Dialogue: 0,0:14:52.24,0:14:56.17,Default,,0,0,0,,And then, for example, to compute the square root of X, Dialogue: 0,0:14:56.24,0:15:03.45,Default,,0,0,0,,I can try and find a fixed point of the function which takes Y to the average of X/Y. Dialogue: 0,0:15:03.55,0:15:07.52,Default,,0,0,0,,And the idea that is that if I really had Y equal to the square root of X, Dialogue: 0,0:15:08.01,0:15:11.80,Default,,0,0,0,,then Y and X/Y would be the same value. Dialogue: 0,0:15:12.00,0:15:13.90,Default,,0,0,0,,They'd both be the square root of X, Dialogue: 0,0:15:14.86,0:15:18.85,Default,,0,0,0,,because X over the square root of X is the square root of X. Dialogue: 0,0:15:19.09,0:15:21.84,Default,,0,0,0,,And so the average if Y were equal to the square of X, Dialogue: 0,0:15:22.25,0:15:25.21,Default,,0,0,0,,then the average wouldn't change. Dialogue: 0,0:15:25.98,0:15:28.93,Default,,0,0,0,,So the square root of X is a fixed point of that particular function. Dialogue: 0,0:15:30.09,0:15:33.85,Default,,0,0,0,,Now, what I'd like to have, I'd like to express Dialogue: 0,0:15:33.98,0:15:36.42,Default,,0,0,0,,the general strategy for finding fixed points. Dialogue: 0,0:15:36.57,0:15:40.13,Default,,0,0,0,,So what I might imagine doing, is to find, Dialogue: 0,0:15:41.02,0:15:46.45,Default,,0,0,0,,is to be able to use my language to define a box that says "fixed point," Dialogue: 0,0:15:49.58,0:15:52.19,Default,,0,0,0,,just like I could make a box that says "square root." Dialogue: 0,0:15:52.21,0:15:55.18,Default,,0,0,0,,And I'd like to be able to express this in my language. Dialogue: 0,0:15:56.08,0:16:01.37,Default,,0,0,0,,So I'd like to express not only the imperative how-to knowledge Dialogue: 0,0:16:01.42,0:16:03.21,Default,,0,0,0,,of a particular thing like square root, Dialogue: 0,0:16:03.58,0:16:05.60,Default,,0,0,0,,but I'd like to be able to express the imperative knowledge Dialogue: 0,0:16:05.66,0:16:08.27,Default,,0,0,0,,of how to do a general thing like how to find fixed point. Dialogue: 0,0:16:09.82,0:16:12.25,Default,,0,0,0,,And in fact, let's go back and look at that slide again. Dialogue: 0,0:16:15.02,0:16:23.28,Default,,0,0,0,,See, not only is this a piece of imperative knowledge, Dialogue: 0,0:16:23.33,0:16:25.32,Default,,0,0,0,,how to find a fixed point, Dialogue: 0,0:16:26.25,0:16:27.39,Default,,0,0,0,,but over here on the bottom, Dialogue: 0,0:16:27.42,0:16:30.32,Default,,0,0,0,,there's another piece of imperative knowledge which says, Dialogue: 0,0:16:30.41,0:16:35.85,Default,,0,0,0,,one way to compute square root is to apply this general fixed point method. Dialogue: 0,0:16:36.17,0:16:38.89,Default,,0,0,0,,So I'd like to also be able to express that imperative knowledge. Dialogue: 0,0:16:39.74,0:16:40.70,Default,,0,0,0,,What would that look like? Dialogue: 0,0:16:40.73,0:16:44.90,Default,,0,0,0,,That would say, this fixed point box is such that Dialogue: 0,0:16:45.76,0:16:58.21,Default,,0,0,0,,if I input to it the function that takes Y to the average of Y and X/Y, Dialogue: 0,0:16:59.77,0:17:06.23,Default,,0,0,0,,then what should come out of that fixed point box is a method for finding square roots. Dialogue: 0,0:17:08.91,0:17:10.24,Default,,0,0,0,,So in these boxes we're building, Dialogue: 0,0:17:10.27,0:17:15.07,Default,,0,0,0,,we're not only building boxes that you input numbers and output numbers, Dialogue: 0,0:17:16.40,0:17:18.54,Default,,0,0,0,,we're going to be building in boxes that, Dialogue: 0,0:17:18.67,0:17:21.34,Default,,0,0,0,,in effect, compute methods like finding square root. Dialogue: 0,0:17:22.22,0:17:25.85,Default,,0,0,0,,And my take is their inputs functions, Dialogue: 0,0:17:26.49,0:17:29.29,Default,,0,0,0,,like Y goes to the average of Y and X/Y. Dialogue: 0,0:17:29.71,0:17:31.49,Default,,0,0,0,,The reason we want to do that, Dialogue: 0,0:17:32.21,0:17:35.60,Default,,0,0,0,,the reason this is a procedure, will end up being a procedure, Dialogue: 0,0:17:35.63,0:17:38.61,Default,,0,0,0,,as we'll see, whose value is another procedure, Dialogue: 0,0:17:39.31,0:17:41.10,Default,,0,0,0,,the reason we want to do that is because Dialogue: 0,0:17:41.52,0:17:46.27,Default,,0,0,0,,procedures are going to be our ways of talking about imperative knowledge. Dialogue: 0,0:17:48.00,0:17:49.93,Default,,0,0,0,,And the way to make that very powerful is Dialogue: 0,0:17:49.93,0:17:52.13,Default,,0,0,0,,to be able to talk about other kinds of knowledge. Dialogue: 0,0:17:53.42,0:17:56.52,Default,,0,0,0,,So here is a procedure that, in effect, talks about another procedure, Dialogue: 0,0:17:57.10,0:18:00.34,Default,,0,0,0,,a general strategy that itself talks about general strategies. Dialogue: 0,0:18:03.57,0:18:08.24,Default,,0,0,0,,Well, our first topic in this course-- Dialogue: 0,0:18:08.25,0:18:09.69,Default,,0,0,0,,there'll be three major topics-- Dialogue: 0,0:18:09.74,0:18:10.94,Default,,0,0,0,,will be black-box abstraction. Dialogue: 0,0:18:10.97,0:18:13.31,Default,,0,0,0,,Let's look at that in a little bit more detail. Dialogue: 0,0:18:15.12,0:18:24.04,Default,,0,0,0,,What we're going to do is we will start out talking about Dialogue: 0,0:18:24.08,0:18:26.72,Default,,0,0,0,,how Lisp is built up out of primitive objects. Dialogue: 0,0:18:27.36,0:18:29.20,Default,,0,0,0,,What does the language supply with us? Dialogue: 0,0:18:29.49,0:18:33.58,Default,,0,0,0,,And we'll see that there are primitive procedures and primitive data. Dialogue: 0,0:18:36.16,0:18:37.04,Default,,0,0,0,,Then we're going to see, Dialogue: 0,0:18:37.05,0:18:38.77,Default,,0,0,0,,how do you take those primitives and Dialogue: 0,0:18:38.81,0:18:40.76,Default,,0,0,0,,combine them to make more complicated things, Dialogue: 0,0:18:41.45,0:18:42.92,Default,,0,0,0,,means of combination? Dialogue: 0,0:18:43.20,0:18:46.30,Default,,0,0,0,,And what we'll see is that there are ways of putting things together, Dialogue: 0,0:18:46.45,0:18:50.48,Default,,0,0,0,,putting primitive procedures together to make more complicated procedures. Dialogue: 0,0:18:50.96,0:18:54.43,Default,,0,0,0,,And we'll see how to put primitive data together to make compound data. Dialogue: 0,0:18:56.21,0:18:59.34,Default,,0,0,0,,Then we'll say, well, having made those compounds things, Dialogue: 0,0:18:59.79,0:19:01.29,Default,,0,0,0,,how do you abstract them? Dialogue: 0,0:19:02.91,0:19:04.97,Default,,0,0,0,,How do you put those black boxes around them Dialogue: 0,0:19:05.04,0:19:07.73,Default,,0,0,0,,so you can use them as components in more complex things? Dialogue: 0,0:19:08.16,0:19:10.93,Default,,0,0,0,,And we'll see that's done by defining procedures and Dialogue: 0,0:19:11.52,0:19:14.79,Default,,0,0,0,,a technique for dealing with compound data called data abstraction. Dialogue: 0,0:19:15.61,0:19:17.36,Default,,0,0,0,,And then, what's maybe the most important thing, Dialogue: 0,0:19:17.92,0:19:21.49,Default,,0,0,0,,is going from just the rules to how does an expert work? Dialogue: 0,0:19:21.61,0:19:27.12,Default,,0,0,0,,How do you express common patterns of doing things, like saying, well, Dialogue: 0,0:19:27.15,0:19:28.64,Default,,0,0,0,,there's a general method of fixed point and Dialogue: 0,0:19:28.69,0:19:30.87,Default,,0,0,0,,square root is a particular case of that? Dialogue: 0,0:19:31.90,0:19:34.41,Default,,0,0,0,,And we're going to use-- Dialogue: 0,0:19:34.59,0:19:35.63,Default,,0,0,0,,I've already hinted at it-- Dialogue: 0,0:19:35.66,0:19:37.30,Default,,0,0,0,,something called higher-order procedures, Dialogue: 0,0:19:37.34,0:19:42.05,Default,,0,0,0,,namely procedures whose inputs and outputs are themselves procedures. Dialogue: 0,0:19:42.96,0:19:44.86,Default,,0,0,0,,And then we'll also see something very interesting. Dialogue: 0,0:19:44.86,0:19:48.49,Default,,0,0,0,,We'll see, as we go further and further on and become more abstract, Dialogue: 0,0:19:48.80,0:19:50.31,Default,,0,0,0,,there'll be very-- Dialogue: 0,0:19:50.43,0:19:53.61,Default,,0,0,0,,well, the line between what we consider to be data and Dialogue: 0,0:19:53.63,0:19:57.80,Default,,0,0,0,,what we consider to be procedures is going to blur at an incredible rate. Dialogue: 0,0:20:02.89,0:20:07.12,Default,,0,0,0,,Well, that's our first subject, black-box abstraction. Dialogue: 0,0:20:07.12,0:20:08.62,Default,,0,0,0,,Let's look at the second topic. Dialogue: 0,0:20:11.10,0:20:13.88,Default,,0,0,0,,I can introduce it like this. Dialogue: 0,0:20:13.89,0:20:18.09,Default,,0,0,0,,See, suppose I want to express the idea-- Dialogue: 0,0:20:19.42,0:20:22.51,Default,,0,0,0,,remember, we're talking about ideas-- Dialogue: 0,0:20:22.91,0:20:25.53,Default,,0,0,0,,suppose I want to express the idea that Dialogue: 0,0:20:26.41,0:20:35.12,Default,,0,0,0,,I can take something and multiply it by the sum of two other things. Dialogue: 0,0:20:36.09,0:20:37.93,Default,,0,0,0,,So for example, I might say, Dialogue: 0,0:20:38.11,0:20:41.52,Default,,0,0,0,,if I had 1 and 3 and multiply that by 2, I get 8. Dialogue: 0,0:20:42.03,0:20:45.11,Default,,0,0,0,,But I'm talking about the general idea of what's called linear combination, Dialogue: 0,0:20:45.44,0:20:47.98,Default,,0,0,0,,that you can add two things and multiply them by something else. Dialogue: 0,0:20:49.28,0:20:51.01,Default,,0,0,0,,It's very easy when I think about it for numbers, Dialogue: 0,0:20:51.05,0:20:55.41,Default,,0,0,0,,but suppose I also want to use that same idea to think about, Dialogue: 0,0:20:56.08,0:20:58.58,Default,,0,0,0,,I could add two vectors, a1 and a2, Dialogue: 0,0:20:59.89,0:21:03.26,Default,,0,0,0,,and then scale them by some factor x and get another vector. Dialogue: 0,0:21:03.33,0:21:09.75,Default,,0,0,0,,Or I might say, I want to think about a1 and a2 as being polynomials, Dialogue: 0,0:21:11.07,0:21:13.90,Default,,0,0,0,,and I might want to add those two polynomials and Dialogue: 0,0:21:13.92,0:21:16.86,Default,,0,0,0,,then multiply them by 2 to get a more complicated one. Dialogue: 0,0:21:20.16,0:21:23.83,Default,,0,0,0,,Or a1 and a2 might be electrical signals, Dialogue: 0,0:21:24.56,0:21:27.77,Default,,0,0,0,,and I might want to think about summing those two electrical signals and Dialogue: 0,0:21:27.81,0:21:30.27,Default,,0,0,0,,then putting the whole thing through an amplifier, Dialogue: 0,0:21:30.28,0:21:33.03,Default,,0,0,0,,multiplying it by some factor of 2 or something. Dialogue: 0,0:21:33.82,0:21:36.93,Default,,0,0,0,,The idea is I want to think about the general notion of that. Dialogue: 0,0:21:38.32,0:21:45.42,Default,,0,0,0,,Now, if our language is going to be good language for expressing those kind of general ideas, Dialogue: 0,0:21:47.07,0:21:49.31,Default,,0,0,0,,if I really, really can do that, Dialogue: 0,0:21:50.65,0:21:52.09,Default,,0,0,0,,I'd like to be able to say Dialogue: 0,0:21:54.99,0:22:00.41,Default,,0,0,0,,I'm going to multiply by x the sum of a1 and a2, Dialogue: 0,0:22:02.80,0:22:05.07,Default,,0,0,0,,and I'd like that to express the general idea of Dialogue: 0,0:22:06.03,0:22:09.23,Default,,0,0,0,,all different kinds of things that a1 and a2 could be. Dialogue: 0,0:22:10.03,0:22:11.58,Default,,0,0,0,,Now, if you think about that, there's a problem, Dialogue: 0,0:22:11.58,0:22:16.17,Default,,0,0,0,,because after all, the actual primitive operations Dialogue: 0,0:22:16.21,0:22:18.33,Default,,0,0,0,,that go on in the machine are obviously going to be different Dialogue: 0,0:22:18.38,0:22:22.98,Default,,0,0,0,,if I'm adding two numbers than if I'm adding two polynomials, Dialogue: 0,0:22:23.29,0:22:27.49,Default,,0,0,0,,or if I'm adding the representation of two electrical signals or wave forms. Dialogue: 0,0:22:27.89,0:22:32.53,Default,,0,0,0,,Somewhere, there has to be the knowledge of the kinds of various things Dialogue: 0,0:22:32.87,0:22:34.25,Default,,0,0,0,,that you can add and the ways of adding them. Dialogue: 0,0:22:37.09,0:22:38.64,Default,,0,0,0,,Now, to construct such a system, Dialogue: 0,0:22:38.78,0:22:40.67,Default,,0,0,0,,the question is, where do I put that knowledge? Dialogue: 0,0:22:41.20,0:22:44.41,Default,,0,0,0,,How do I think about the different kinds of choices I have? Dialogue: 0,0:22:44.56,0:22:48.42,Default,,0,0,0,,And if tomorrow George comes up with a new kind of object Dialogue: 0,0:22:48.45,0:22:50.32,Default,,0,0,0,,that might be added and multiplied, Dialogue: 0,0:22:51.01,0:22:53.32,Default,,0,0,0,,how do I add George's new object to the system Dialogue: 0,0:22:53.52,0:22:55.68,Default,,0,0,0,,without screwing up everything that was already there? Dialogue: 0,0:22:57.81,0:23:00.54,Default,,0,0,0,,Well, that's going to be the second big topic, Dialogue: 0,0:23:00.57,0:23:03.16,Default,,0,0,0,,the way of controlling that kind of complexity. Dialogue: 0,0:23:03.84,0:23:08.43,Default,,0,0,0,,And the way you do that is by establishing conventional interfaces, Dialogue: 0,0:23:17.44,0:23:20.21,Default,,0,0,0,,agreed upon ways of plugging things together. Dialogue: 0,0:23:20.25,0:23:22.04,Default,,0,0,0,,Just like in electrical engineering, Dialogue: 0,0:23:22.94,0:23:25.39,Default,,0,0,0,,people have standard impedances for connectors, Dialogue: 0,0:23:26.16,0:23:28.62,Default,,0,0,0,,and then you know if you build something with one of those standard impedances, Dialogue: 0,0:23:28.67,0:23:30.40,Default,,0,0,0,,you can plug it together with something else. Dialogue: 0,0:23:32.78,0:23:35.68,Default,,0,0,0,,So that's going to be our second large topic, conventional interfaces. Dialogue: 0,0:23:35.73,0:23:40.94,Default,,0,0,0,,What we're going to see is, first, we're going to talk about the problem of generic operations, Dialogue: 0,0:23:40.97,0:23:42.22,Default,,0,0,0,,which is the one I alluded to, Dialogue: 0,0:23:42.59,0:23:47.28,Default,,0,0,0,,things like "plus" that have to work with all different kinds of data. Dialogue: 0,0:23:52.61,0:23:54.57,Default,,0,0,0,,So we talk about generic operations. Dialogue: 0,0:23:54.61,0:23:56.99,Default,,0,0,0,,Then we're going to talk about really large-scale structures. Dialogue: 0,0:23:58.32,0:24:00.83,Default,,0,0,0,,How do you put together very large programs Dialogue: 0,0:24:01.02,0:24:04.89,Default,,0,0,0,,that model the kinds of complex systems in the real world that you'd like to model? Dialogue: 0,0:24:05.53,0:24:06.53,Default,,0,0,0,,And what we're going to see is that Dialogue: 0,0:24:06.57,0:24:11.81,Default,,0,0,0,,there are two very important metaphors for putting together such systems. Dialogue: 0,0:24:11.85,0:24:13.90,Default,,0,0,0,,One is called object-oriented programming, Dialogue: 0,0:24:14.09,0:24:18.94,Default,,0,0,0,,where you sort of think of your system as a kind of society Dialogue: 0,0:24:19.37,0:24:22.36,Default,,0,0,0,,full of little things that interact by sending information between them. Dialogue: 0,0:24:23.44,0:24:27.81,Default,,0,0,0,,And then the second one is operations on aggregates, called streams, Dialogue: 0,0:24:27.98,0:24:31.50,Default,,0,0,0,,where you think of a large system put together kind of Dialogue: 0,0:24:31.50,0:24:35.29,Default,,0,0,0,,like a signal processing engineer puts together a large electrical system. Dialogue: 0,0:24:38.93,0:24:40.49,Default,,0,0,0,,That's going to be our second topic. Dialogue: 0,0:24:43.37,0:24:45.93,Default,,0,0,0,,Now, the third thing we're going to come to, Dialogue: 0,0:24:45.95,0:24:49.70,Default,,0,0,0,,the third basic technique for controlling complexity, Dialogue: 0,0:24:49.74,0:24:50.94,Default,,0,0,0,,is making new languages. Dialogue: 0,0:24:51.69,0:24:55.42,Default,,0,0,0,,Because sometimes, when you're sort of overwhelmed by the complexity of a design, Dialogue: 0,0:24:55.47,0:24:59.69,Default,,0,0,0,,the way that you control that complexity is to pick a new design language. Dialogue: 0,0:25:01.41,0:25:05.60,Default,,0,0,0,,And the purpose of the new design language will be to highlight different aspects of the system. Dialogue: 0,0:25:05.79,0:25:09.36,Default,,0,0,0,,It will suppress some kinds of details and emphasize other kinds of details. Dialogue: 0,0:25:12.99,0:25:15.93,Default,,0,0,0,,This is going to be the most magical part of the course. Dialogue: 0,0:25:16.03,0:25:21.20,Default,,0,0,0,,We're going to start out by actually looking at the technology for building new computer languages. Dialogue: 0,0:25:21.82,0:25:26.30,Default,,0,0,0,,The first thing we're going to do is actually build in Lisp. Dialogue: 0,0:25:29.23,0:25:34.02,Default,,0,0,0,,We're going to express in Lisp the process of interpreting Lisp itself. Dialogue: 0,0:25:34.29,0:25:36.94,Default,,0,0,0,,And that's going to be a very sort of self-circular thing. Dialogue: 0,0:25:36.96,0:25:39.92,Default,,0,0,0,,There's a little mystical symbol that has to do with that. Dialogue: 0,0:25:40.97,0:25:46.38,Default,,0,0,0,,The process of interpreting Lisp is sort of a giant wheel of two processes, Dialogue: 0,0:25:46.57,0:25:47.71,Default,,0,0,0,,apply and eval, Dialogue: 0,0:25:47.89,0:25:50.87,Default,,0,0,0,,which sort of constantly reduce expressions to each other. Dialogue: 0,0:25:52.54,0:25:54.24,Default,,0,0,0,,Then we're going to see all sorts of other magical things. Dialogue: 0,0:25:54.25,0:25:56.85,Default,,0,0,0,,Here's another magical symbol. Dialogue: 0,0:25:57.12,0:26:01.52,Default,,0,0,0,,This is sort of the Y operator, Dialogue: 0,0:26:01.55,0:26:06.45,Default,,0,0,0,,which is, in some sense, the expression of infinity inside our procedural language. Dialogue: 0,0:26:06.51,0:26:07.44,Default,,0,0,0,,We'll take a look at that. Dialogue: 0,0:26:08.40,0:26:13.73,Default,,0,0,0,,In any case, this section of the course is called Metalinguistic Abstraction, Dialogue: 0,0:26:16.17,0:26:26.23,Default,,0,0,0,,abstracting by talking about how you construct new languages. Dialogue: 0,0:26:30.22,0:26:35.71,Default,,0,0,0,,As I said, we're going to start out by looking at the process of interpretation. Dialogue: 0,0:26:35.74,0:26:42.12,Default,,0,0,0,,We're going to look at this apply-eval loop, and build Lisp. Dialogue: 0,0:26:42.16,0:26:44.17,Default,,0,0,0,,Then, just to show you that this is very general, Dialogue: 0,0:26:44.37,0:26:48.26,Default,,0,0,0,,we're going to use exactly the same technology to build a very different kind of language, Dialogue: 0,0:26:48.53,0:26:50.31,Default,,0,0,0,,a so-called logic programming language, Dialogue: 0,0:26:50.53,0:26:54.83,Default,,0,0,0,,where you don't really talk about procedures at all that have inputs and outputs. Dialogue: 0,0:26:54.86,0:26:57.25,Default,,0,0,0,,What you do is talk about relations between things. Dialogue: 0,0:26:57.31,0:27:03.92,Default,,0,0,0,,And then finally, we're going to talk about how you implement these things very concretely Dialogue: 0,0:27:03.95,0:27:05.60,Default,,0,0,0,,on the very simplest kind of machines. Dialogue: 0,0:27:05.65,0:27:08.39,Default,,0,0,0,,We'll see something like this. Dialogue: 0,0:27:09.13,0:27:12.14,Default,,0,0,0,,This is a picture of a chip, Dialogue: 0,0:27:12.16,0:27:17.47,Default,,0,0,0,,which is the Lisp interpreter that we will be talking about then in hardware. Dialogue: 0,0:27:20.88,0:27:23.79,Default,,0,0,0,,Well, there's an outline of the course, three big topics. Dialogue: 0,0:27:24.88,0:27:29.41,Default,,0,0,0,,Black-box abstraction, conventional interfaces, metalinguistic abstraction. Dialogue: 0,0:27:31.58,0:27:33.57,Default,,0,0,0,,Now, let's take a break now and then we'll get started. Dialogue: 0,0:27:52.19,0:28:03.42,Default,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:28:03.92,0:28:06.84,Default,,0,0,0,,Let's actually start in learning Lisp now. Dialogue: 0,0:28:08.06,0:28:10.75,Default,,0,0,0,,Actually, we'll start out by learning something much more important, Dialogue: 0,0:28:10.80,0:28:14.33,Default,,0,0,0,,maybe the very most important thing in this course, which is not Lisp, Dialogue: 0,0:28:14.38,0:28:18.41,Default,,0,0,0,,in particular, of course, but rather a general framework Dialogue: 0,0:28:18.62,0:28:21.89,Default,,0,0,0,,for thinking about languages that I already alluded to. Dialogue: 0,0:28:22.12,0:28:25.10,Default,,0,0,0,,When somebody tells you they're going to show you a language, Dialogue: 0,0:28:25.13,0:28:26.16,Default,,0,0,0,,what you should say is, Dialogue: 0,0:28:26.19,0:28:32.87,Default,,0,0,0,,what I'd like you to tell me is what are the primitive elements? Dialogue: 0,0:28:37.50,0:28:38.78,Default,,0,0,0,,What does the language come with? Dialogue: 0,0:28:38.96,0:28:43.53,Default,,0,0,0,,Then, what are the ways you put those together? Dialogue: 0,0:28:43.68,0:28:47.42,Default,,0,0,0,,What are the means of combination? Dialogue: 0,0:28:50.17,0:28:54.18,Default,,0,0,0,,What are the things that allow you to take these primitive elements Dialogue: 0,0:28:54.37,0:28:56.51,Default,,0,0,0,,and build bigger things out of them? Dialogue: 0,0:28:58.01,0:28:59.61,Default,,0,0,0,,What are the ways of putting things together? Dialogue: 0,0:29:01.39,0:29:05.69,Default,,0,0,0,,And then, what are the means of abstraction? Dialogue: 0,0:29:08.35,0:29:16.85,Default,,0,0,0,,How do we take those complicated things and draw those boxes around them? Dialogue: 0,0:29:16.88,0:29:19.66,Default,,0,0,0,,How do we name them so that we can now use them Dialogue: 0,0:29:19.68,0:29:23.85,Default,,0,0,0,,as if they were primitive elements in making still more complex things? Dialogue: 0,0:29:23.89,0:29:25.66,Default,,0,0,0,,And so on, and so on, and so on. Dialogue: 0,0:29:26.89,0:29:28.08,Default,,0,0,0,,So when someone says to you, gee, Dialogue: 0,0:29:28.09,0:29:29.55,Default,,0,0,0,,I have a great new computer language, Dialogue: 0,0:29:30.86,0:29:34.70,Default,,0,0,0,,you don't say, how many characters does it take to invert a matrix? Dialogue: 0,0:29:35.73,0:29:36.88,Default,,0,0,0,,It's irrelevant. Dialogue: 0,0:29:37.39,0:29:42.30,Default,,0,0,0,,What you say is, if the language did not come with matrices built in Dialogue: 0,0:29:42.33,0:29:43.37,Default,,0,0,0,,or with something else built in, Dialogue: 0,0:29:43.37,0:29:46.03,Default,,0,0,0,,how could I then build that thing? Dialogue: 0,0:29:46.05,0:29:48.47,Default,,0,0,0,,What are the means of combination which would allow me to do that? Dialogue: 0,0:29:48.62,0:29:50.71,Default,,0,0,0,,And then, what are the means of abstraction Dialogue: 0,0:29:51.68,0:29:54.21,Default,,0,0,0,,which allow me then to use those as elements Dialogue: 0,0:29:54.22,0:29:56.52,Default,,0,0,0,,in making more complicated things yet? Dialogue: 0,0:29:58.75,0:30:04.61,Default,,0,0,0,,Well, we're going to see that Lisp has some primitive data and some primitive procedures. Dialogue: 0,0:30:05.25,0:30:07.50,Default,,0,0,0,,In fact, let's really start. Dialogue: 0,0:30:07.55,0:30:14.89,Default,,0,0,0,,And here's a piece of primitive data in Lisp, number 3. Dialogue: 0,0:30:16.27,0:30:19.87,Default,,0,0,0,,Actually, if I'm being very pedantic, that's not the number 3. Dialogue: 0,0:30:19.93,0:30:25.57,Default,,0,0,0,,That's some symbol that represents Plato's concept of the number 3. Dialogue: 0,0:30:26.67,0:30:28.93,Default,,0,0,0,,And here's another. Dialogue: 0,0:30:30.48,0:30:36.06,Default,,0,0,0,,Here's some more primitive data in Lisp, 17.4. Dialogue: 0,0:30:36.08,0:30:39.42,Default,,0,0,0,,Or actually, some representation of 17.4. Dialogue: 0,0:30:40.99,0:30:44.48,Default,,0,0,0,,And here's another one, 5. Dialogue: 0,0:30:46.86,0:30:52.21,Default,,0,0,0,,Here's another primitive object that's built in Lisp, addition. Dialogue: 0,0:30:52.25,0:30:55.68,Default,,0,0,0,,Actually, to use the same kind of pedantic-- Dialogue: 0,0:30:55.71,0:31:00.47,Default,,0,0,0,,this is a name for the primitive method of adding things. Dialogue: 0,0:31:00.53,0:31:02.53,Default,,0,0,0,,Just like this is a name for Plato's number 3, Dialogue: 0,0:31:02.61,0:31:09.32,Default,,0,0,0,,this is a name for Plato's concept of how you add things. Dialogue: 0,0:31:10.32,0:31:11.98,Default,,0,0,0,,So those are some primitive elements. Dialogue: 0,0:31:12.14,0:31:13.76,Default,,0,0,0,,I can put them together. Dialogue: 0,0:31:14.14,0:31:18.29,Default,,0,0,0,,I can say, gee, what's the sum of 3 and 17.4 and 5? Dialogue: 0,0:31:18.69,0:31:21.31,Default,,0,0,0,,And the way I do that is to say, Dialogue: 0,0:31:21.33,0:31:27.71,Default,,0,0,0,,let's apply the sum operator to these three numbers. Dialogue: 0,0:31:27.74,0:31:31.15,Default,,0,0,0,,And I should get, what? 8, 17. 25.4. Dialogue: 0,0:31:34.43,0:31:38.05,Default,,0,0,0,,So I should be able to ask Lisp what the value of this is, Dialogue: 0,0:31:38.94,0:31:40.77,Default,,0,0,0,,and it will return 25.4. Dialogue: 0,0:31:43.58,0:31:44.83,Default,,0,0,0,,Let's introduce some names. Dialogue: 0,0:31:44.88,0:31:51.47,Default,,0,0,0,,This thing that I typed is called a combination. Dialogue: 0,0:31:56.88,0:32:01.94,Default,,0,0,0,,And a combination consists, in general, of applying an operator-- Dialogue: 0,0:32:03.39,0:32:04.72,Default,,0,0,0,,so this is an operator-- Dialogue: 0,0:32:09.71,0:32:12.05,Default,,0,0,0,,to some operands. Dialogue: 0,0:32:13.25,0:32:14.54,Default,,0,0,0,,These are the operands. Dialogue: 0,0:32:21.89,0:32:23.79,Default,,0,0,0,,And of course, I can make more complex things. Dialogue: 0,0:32:23.82,0:32:28.56,Default,,0,0,0,,The reason I can get complexity out of this is because the operands themselves, Dialogue: 0,0:32:29.52,0:32:31.09,Default,,0,0,0,,in general, can be combinations. Dialogue: 0,0:32:31.15,0:32:44.47,Default,,0,0,0,,So for instance, I could say, what is the sum of 3 and the product of 5 and 6 and 8 and 2? Dialogue: 0,0:32:45.66,0:32:52.16,Default,,0,0,0,,And I should get-- let's see-- 30, 40, 43. Dialogue: 0,0:32:52.73,0:32:54.81,Default,,0,0,0,,So Lisp should tell me that that's 43. Dialogue: 0,0:32:56.56,0:33:02.80,Default,,0,0,0,,Forming combinations is the basic needs of combination that we'll be looking at. Dialogue: 0,0:33:04.65,0:33:09.22,Default,,0,0,0,,And then, well, you see some syntax here. Dialogue: 0,0:33:10.56,0:33:13.04,Default,,0,0,0,,Lisp uses what's called prefix notation, Dialogue: 0,0:33:16.22,0:33:25.21,Default,,0,0,0,,which means that the operator is written to the left of the operands. Dialogue: 0,0:33:25.47,0:33:26.48,Default,,0,0,0,,It's just a convention. Dialogue: 0,0:33:27.66,0:33:29.77,Default,,0,0,0,,And notice, it's fully parenthesized. Dialogue: 0,0:33:30.08,0:33:32.32,Default,,0,0,0,,And the parentheses make it completely unambiguous. Dialogue: 0,0:33:32.32,0:33:36.99,Default,,0,0,0,,So by looking at this, I can see that there's the operator, Dialogue: 0,0:33:37.01,0:33:40.99,Default,,0,0,0,,and there are 1, 2, 3, 4 operands. Dialogue: 0,0:33:42.38,0:33:47.97,Default,,0,0,0,,And I can see that the second operand here is itself some combination Dialogue: 0,0:33:48.88,0:33:51.55,Default,,0,0,0,,that has one operator and two operands. Dialogue: 0,0:33:52.43,0:33:54.27,Default,,0,0,0,,Parentheses in Lisp are a little bit, Dialogue: 0,0:33:54.61,0:33:57.71,Default,,0,0,0,,or are very unlike parentheses in conventional mathematics. Dialogue: 0,0:33:57.77,0:34:00.11,Default,,0,0,0,,In mathematics, we sort of use them to mean grouping, Dialogue: 0,0:34:01.21,0:34:03.75,Default,,0,0,0,,and it sort of doesn't hurt if sometimes you leave out parentheses Dialogue: 0,0:34:03.77,0:34:05.56,Default,,0,0,0,,if people understand that that's a group. Dialogue: 0,0:34:05.76,0:34:08.51,Default,,0,0,0,,And in general, it doesn't hurt if you put in extra parentheses, Dialogue: 0,0:34:08.86,0:34:10.94,Default,,0,0,0,,because that maybe makes the grouping more distinct. Dialogue: 0,0:34:10.96,0:34:11.77,Default,,0,0,0,,Lisp is not like that. Dialogue: 0,0:34:13.12,0:34:15.37,Default,,0,0,0,,In Lisp, you cannot leave out parentheses, Dialogue: 0,0:34:16.38,0:34:18.56,Default,,0,0,0,,and you cannot put in extra parentheses, Dialogue: 0,0:34:19.33,0:34:21.28,Default,,0,0,0,,because putting in parentheses always means, Dialogue: 0,0:34:21.37,0:34:27.05,Default,,0,0,0,,exactly and precisely, this is a combination which has meaning, Dialogue: 0,0:34:27.09,0:34:28.81,Default,,0,0,0,,applying operators to operands. Dialogue: 0,0:34:29.04,0:34:32.62,Default,,0,0,0,,And if I left this out, if I left those parentheses out, Dialogue: 0,0:34:32.65,0:34:33.96,Default,,0,0,0,,it would mean something else. Dialogue: 0,0:34:35.41,0:34:37.25,Default,,0,0,0,,In fact, the way to think about this, Dialogue: 0,0:34:37.41,0:34:41.65,Default,,0,0,0,,is really what I'm doing when I write something like this is writing a tree. Dialogue: 0,0:34:42.37,0:34:47.30,Default,,0,0,0,,So this combination is a tree that has a plus and Dialogue: 0,0:34:47.37,0:34:54.46,Default,,0,0,0,,then a 3 and then a something else and an 8 and a 2. Dialogue: 0,0:34:54.48,0:34:56.35,Default,,0,0,0,,And then this something else here is Dialogue: 0,0:34:56.35,0:35:03.22,Default,,0,0,0,,itself a little subtree that has a star and a 5 and a 6. Dialogue: 0,0:35:03.95,0:35:05.53,Default,,0,0,0,,And the way to think of that is, really, Dialogue: 0,0:35:05.55,0:35:09.00,Default,,0,0,0,,what's going on are we're writing these trees, Dialogue: 0,0:35:09.21,0:35:15.10,Default,,0,0,0,,and parentheses are just a way to write this two-dimensional structure Dialogue: 0,0:35:15.79,0:35:17.34,Default,,0,0,0,,as a linear character string. Dialogue: 0,0:35:19.23,0:35:23.81,Default,,0,0,0,,Because at least when Lisp first started and people had teletypes or punch cards or whatever, Dialogue: 0,0:35:24.17,0:35:25.60,Default,,0,0,0,,this was more convenient. Dialogue: 0,0:35:25.97,0:35:30.52,Default,,0,0,0,,Maybe if Lisp started today, the syntax of Lisp would look like that. Dialogue: 0,0:35:31.76,0:35:35.07,Default,,0,0,0,,Well, let's look at what that actually looks like on the computer. Dialogue: 0,0:35:36.29,0:35:39.37,Default,,0,0,0,,Here I have a Lisp interaction set up. Dialogue: 0,0:35:39.41,0:35:40.43,Default,,0,0,0,,There's a editor. Dialogue: 0,0:35:41.13,0:35:44.86,Default,,0,0,0,,And on the top, I'm going to type some values and ask Lisp what they are. Dialogue: 0,0:35:45.12,0:35:46.75,Default,,0,0,0,,So for instance, I can say to Lisp, Dialogue: 0,0:35:46.83,0:35:48.53,Default,,0,0,0,,what's the value of that symbol? Dialogue: 0,0:35:49.44,0:35:50.50,Default,,0,0,0,,That's 3. Dialogue: 0,0:35:50.57,0:35:52.20,Default,,0,0,0,,And I ask Lisp to evaluate it. Dialogue: 0,0:35:52.32,0:35:54.77,Default,,0,0,0,,And there you see Lisp has returned on the bottom, Dialogue: 0,0:35:55.39,0:35:56.84,Default,,0,0,0,,and said, oh yeah, that's 3. Dialogue: 0,0:35:57.58,0:36:04.96,Default,,0,0,0,,Or I can say, what's the sum of 3 and 4 and 8? Dialogue: 0,0:36:06.45,0:36:08.05,Default,,0,0,0,,What's that combination? Dialogue: 0,0:36:08.93,0:36:10.66,Default,,0,0,0,,And ask Lisp to evaluate it. Dialogue: 0,0:36:14.49,0:36:15.68,Default,,0,0,0,,That's 15. Dialogue: 0,0:36:16.57,0:36:18.80,Default,,0,0,0,,Or I can type in something more complicated. Dialogue: 0,0:36:19.25,0:36:34.14,Default,,0,0,0,,I can say, what's the sum of the product of 3 and the sum of 7 and 19.5? Dialogue: 0,0:36:35.21,0:36:38.00,Default,,0,0,0,,And you'll notice here that Lisp has something built in Dialogue: 0,0:36:38.01,0:36:39.76,Default,,0,0,0,,that helps me keep track of all these parentheses. Dialogue: 0,0:36:39.77,0:36:42.13,Default,,0,0,0,,Watch as I type the next closed parentheses, Dialogue: 0,0:36:42.21,0:36:45.01,Default,,0,0,0,,which is going to close the combination starting with the star. Dialogue: 0,0:36:45.52,0:36:47.30,Default,,0,0,0,,The opening one will flash. Dialogue: 0,0:36:47.76,0:36:49.69,Default,,0,0,0,,Here, I'll rub those out and do it again. Dialogue: 0,0:36:50.14,0:36:52.70,Default,,0,0,0,,Type close, and you see that closes the plus. Dialogue: 0,0:36:53.58,0:36:56.41,Default,,0,0,0,,Close again, that closes the star. Dialogue: 0,0:36:57.90,0:37:00.76,Default,,0,0,0,,Now I'm back to the sum, and maybe I'm going to add that all to 4. Dialogue: 0,0:37:01.66,0:37:02.69,Default,,0,0,0,,That closes the plus. Dialogue: 0,0:37:02.73,0:37:07.07,Default,,0,0,0,,Now I have a complete combination, and I can ask Lisp for the value of that. Dialogue: 0,0:37:07.26,0:37:11.66,Default,,0,0,0,,That kind of paren balancing is something that's built into Dialogue: 0,0:37:11.76,0:37:13.29,Default,,0,0,0,,a lot of Lisp systems to help you keep track, Dialogue: 0,0:37:13.36,0:37:16.55,Default,,0,0,0,,because it is kind of hard just by hand doing all these parentheses. Dialogue: 0,0:37:16.81,0:37:21.20,Default,,0,0,0,,There's another kind of convention for keeping track of parentheses. Dialogue: 0,0:37:21.25,0:37:23.68,Default,,0,0,0,,Let me write another complicated combination. Dialogue: 0,0:37:24.77,0:37:34.00,Default,,0,0,0,,Let's take the sum of the product of 3 and 5 and add that to something. Dialogue: 0,0:37:34.03,0:37:35.23,Default,,0,0,0,,And now what I'm going to do is Dialogue: 0,0:37:35.28,0:37:39.85,Default,,0,0,0,,I'm going to indent so that the operands are written vertically. Dialogue: 0,0:37:40.30,0:37:45.65,Default,,0,0,0,,Which the sum of that and the product of 47 and-- Dialogue: 0,0:37:47.02,0:37:54.59,Default,,0,0,0,,let's say the product of 47 with a difference of 20 and 6.8. Dialogue: 0,0:37:54.62,0:37:57.09,Default,,0,0,0,,That means subtract 6.8 from 20. Dialogue: 0,0:37:58.97,0:38:00.19,Default,,0,0,0,,And then you see the parentheses close. Dialogue: 0,0:38:00.22,0:38:03.47,Default,,0,0,0,,Close the minus. Close the star. Dialogue: 0,0:38:03.76,0:38:05.42,Default,,0,0,0,,And now let's get another operator. Dialogue: 0,0:38:05.44,0:38:09.49,Default,,0,0,0,,You see the Lisp editor here is indenting to the right position automatically Dialogue: 0,0:38:10.40,0:38:11.50,Default,,0,0,0,,to help me keep track. Dialogue: 0,0:38:12.61,0:38:14.09,Default,,0,0,0,,I'll do that again. Dialogue: 0,0:38:14.13,0:38:15.89,Default,,0,0,0,,I'll close that last parentheses again. Dialogue: 0,0:38:16.25,0:38:17.71,Default,,0,0,0,,You see it balances the plus. Dialogue: 0,0:38:20.40,0:38:22.64,Default,,0,0,0,,Now I can say, what's the value of that? Dialogue: 0,0:38:23.87,0:38:29.28,Default,,0,0,0,,So those two things, indenting to the right level, Dialogue: 0,0:38:29.31,0:38:30.86,Default,,0,0,0,,which is called pretty printing, Dialogue: 0,0:38:31.55,0:38:33.58,Default,,0,0,0,,and flashing parentheses, Dialogue: 0,0:38:33.89,0:38:37.73,Default,,0,0,0,,are two things that a lot of Lisp systems have built in to help you keep track. Dialogue: 0,0:38:37.76,0:38:39.01,Default,,0,0,0,,And you should learn how to use them. Dialogue: 0,0:38:41.52,0:38:43.17,Default,,0,0,0,,Ok, those are the primitives. Dialogue: 0,0:38:44.73,0:38:46.31,Default,,0,0,0,,There's a means of combination. Dialogue: 0,0:38:46.33,0:38:47.93,Default,,0,0,0,,Now let's go up to the means of abstraction. Dialogue: 0,0:38:49.44,0:38:53.84,Default,,0,0,0,,I'd like to be able to take the idea that I do some combination like this, Dialogue: 0,0:38:53.85,0:38:55.77,Default,,0,0,0,,and abstract it and give it a simple name, Dialogue: 0,0:38:55.81,0:38:57.26,Default,,0,0,0,,so I can use that as an element. Dialogue: 0,0:38:57.31,0:38:59.92,Default,,0,0,0,,And I do that in Lisp with "define." Dialogue: 0,0:39:01.17,0:39:02.43,Default,,0,0,0,,So I can say, for example, Dialogue: 0,0:39:02.73,0:39:15.05,Default,,0,0,0,,define A to be the product of 5 and 5. Dialogue: 0,0:39:18.40,0:39:22.35,Default,,0,0,0,,And now I could say, for example, to Lisp, Dialogue: 0,0:39:22.38,0:39:26.01,Default,,0,0,0,,what is the product of A and A? Dialogue: 0,0:39:27.18,0:39:29.81,Default,,0,0,0,,And this should be 25, and this should be 625. Dialogue: 0,0:39:31.97,0:39:36.01,Default,,0,0,0,,And then, crucial thing, I can now use A-- Dialogue: 0,0:39:36.21,0:39:37.92,Default,,0,0,0,,here I've used it in a combination-- Dialogue: 0,0:39:38.41,0:39:43.55,Default,,0,0,0,,but I could use that in other more complicated things that I name in turn. Dialogue: 0,0:39:43.58,0:39:50.93,Default,,0,0,0,,So I could say, define B to be the sum of, Dialogue: 0,0:39:50.97,0:39:57.45,Default,,0,0,0,,we'll say, A and the product of 5 and A. Dialogue: 0,0:39:59.44,0:40:00.72,Default,,0,0,0,,And then close the plus. Dialogue: 0,0:40:03.45,0:40:05.85,Default,,0,0,0,,Let's take a look at that on the computer and see how that looks. Dialogue: 0,0:40:07.28,0:40:10.68,Default,,0,0,0,,So I'll just type what I wrote on the board. Dialogue: 0,0:40:10.83,0:40:21.73,Default,,0,0,0,,I could say, define A to be the product of 5 and 5. Dialogue: 0,0:40:23.74,0:40:25.38,Default,,0,0,0,,And I'll tell that to Lisp. Dialogue: 0,0:40:25.52,0:40:28.94,Default,,0,0,0,,And notice what Lisp responded there with was an A in the bottom. Dialogue: 0,0:40:29.09,0:40:31.38,Default,,0,0,0,,In general, when you type in a definition in Lisp, Dialogue: 0,0:40:31.50,0:40:35.02,Default,,0,0,0,,it responds with the symbol being defined. Dialogue: 0,0:40:35.63,0:40:39.66,Default,,0,0,0,,Now I could say to Lisp, what is the product of A and A? Dialogue: 0,0:40:42.81,0:40:44.33,Default,,0,0,0,,And it says that's 625. Dialogue: 0,0:40:46.05,0:41:00.34,Default,,0,0,0,,I can define B to be the sum of A and the product of 5 and A. Dialogue: 0,0:41:00.48,0:41:05.70,Default,,0,0,0,,Close a paren closes the star. Close the plus. Close the "define." Dialogue: 0,0:41:07.63,0:41:10.37,Default,,0,0,0,,Lisp says, OK, B, there on the bottom. Dialogue: 0,0:41:11.04,0:41:13.24,Default,,0,0,0,,And now I can say to Lisp, what's the value of B? Dialogue: 0,0:41:17.18,0:41:18.88,Default,,0,0,0,,And I can say something more complicated, Dialogue: 0,0:41:18.93,0:41:26.69,Default,,0,0,0,,like what's the sum of A and the quotient of B and 5? Dialogue: 0,0:41:26.73,0:41:30.25,Default,,0,0,0,,That slash is divide, another primitive operator. Dialogue: 0,0:41:30.38,0:41:32.78,Default,,0,0,0,,I've divided B by 5, added it to A. Dialogue: 0,0:41:33.65,0:41:35.23,Default,,0,0,0,,Lisp says, OK, that's 55. Dialogue: 0,0:41:36.57,0:41:37.92,Default,,0,0,0,,So there's what it looks like. Dialogue: 0,0:41:39.82,0:41:43.40,Default,,0,0,0,,There's the basic means of defining something. Dialogue: 0,0:41:43.44,0:41:49.02,Default,,0,0,0,,It's the simplest kind of naming, but it's not really very powerful. Dialogue: 0,0:41:50.06,0:41:51.60,Default,,0,0,0,,See, what I'd really like to name-- Dialogue: 0,0:41:51.84,0:41:53.37,Default,,0,0,0,,remember, we're talking about general methods-- Dialogue: 0,0:41:53.57,0:41:57.68,Default,,0,0,0,,I'd like to name, oh, the general idea that, for example, Dialogue: 0,0:41:58.11,0:42:17.53,Default,,0,0,0,,I could multiply 5 by 5, or 6 by 6, or 1,001 by 1,001, 1,001.7 by 1,001.7. Dialogue: 0,0:42:17.76,0:42:24.16,Default,,0,0,0,,I'd like to be able to name the general idea of multiplying something by itself. Dialogue: 0,0:42:28.48,0:42:30.11,Default,,0,0,0,,Well, you know what that is. That's called squaring. Dialogue: 0,0:42:31.69,0:42:35.63,Default,,0,0,0,,And the way I can do that in Lisp is I can say, Dialogue: 0,0:42:37.97,0:42:56.25,Default,,0,0,0,,define to square something x, multiply x by itself. Dialogue: 0,0:42:57.87,0:43:01.12,Default,,0,0,0,,And then having done that, I could say to Lisp, Dialogue: 0,0:43:01.12,0:43:05.49,Default,,0,0,0,,for example, what's the square of 10? Dialogue: 0,0:43:06.67,0:43:07.87,Default,,0,0,0,,And Lisp will say 100. Dialogue: 0,0:43:10.70,0:43:14.24,Default,,0,0,0,,So now let's actually look at that a little more closely. Dialogue: 0,0:43:15.29,0:43:16.88,Default,,0,0,0,,Right, there's the definition of square. Dialogue: 0,0:43:17.50,0:43:22.55,Default,,0,0,0,,To square something, multiply it by itself. Dialogue: 0,0:43:23.69,0:43:25.34,Default,,0,0,0,,You see this x here. Dialogue: 0,0:43:26.29,0:43:27.81,Default,,0,0,0,,That x is kind of a pronoun, Dialogue: 0,0:43:27.87,0:43:29.53,Default,,0,0,0,,which is the something that I'm going to square. Dialogue: 0,0:43:31.49,0:43:37.41,Default,,0,0,0,,And what I do with it is I multiply x, I multiply it by itself. Dialogue: 0,0:43:42.22,0:43:48.27,Default,,0,0,0,,OK. So there's the notation for defining a procedure. Dialogue: 0,0:43:48.29,0:43:50.29,Default,,0,0,0,,Actually, this is a little bit confusing, Dialogue: 0,0:43:50.81,0:43:53.97,Default,,0,0,0,,because this is sort of how I might use square. Dialogue: 0,0:43:54.00,0:43:56.80,Default,,0,0,0,,And I say square root of x or square root of 10, Dialogue: 0,0:43:57.55,0:44:00.81,Default,,0,0,0,,but it's not making it very clear that I'm actually naming something. Dialogue: 0,0:44:03.10,0:44:04.91,Default,,0,0,0,,So let me write this definition in another way Dialogue: 0,0:44:05.74,0:44:08.21,Default,,0,0,0,,that makes it a little bit more clear that I'm naming something. Dialogue: 0,0:44:08.54,0:44:29.39,Default,,0,0,0,,I'll say, "define" square to be lambda of x times xx. Dialogue: 0,0:44:36.56,0:44:42.05,Default,,0,0,0,,Here, I'm naming something square, just like over here, I'm naming something A. Dialogue: 0,0:44:43.23,0:44:44.72,Default,,0,0,0,,The thing that I'm naming square-- Dialogue: 0,0:44:44.75,0:44:48.39,Default,,0,0,0,,here, the thing I named A was the value of this combination. Dialogue: 0,0:44:49.29,0:44:52.41,Default,,0,0,0,,Here, the thing that I'm naming square is this thing Dialogue: 0,0:44:52.43,0:44:53.44,Default,,0,0,0,,that begins with lambda, Dialogue: 0,0:44:53.45,0:44:56.77,Default,,0,0,0,,and lambda is Lisp's way of saying make a procedure. Dialogue: 0,0:45:00.24,0:45:02.91,Default,,0,0,0,,Let's look at that more closely on the slide. Dialogue: 0,0:45:04.27,0:45:05.81,Default,,0,0,0,,The way I read that definition is to say, Dialogue: 0,0:45:05.85,0:45:10.33,Default,,0,0,0,,I define square to be make a procedure-- Dialogue: 0,0:45:12.78,0:45:13.97,Default,,0,0,0,,that's what the lambda is-- Dialogue: 0,0:45:14.06,0:45:17.49,Default,,0,0,0,,make a procedure with an argument named x. Dialogue: 0,0:45:19.26,0:45:24.09,Default,,0,0,0,,And what it does is return the results of multiplying x by itself. Dialogue: 0,0:45:24.97,0:45:33.12,Default,,0,0,0,,Now, in general, we're going to be using this top form of defining, Dialogue: 0,0:45:33.41,0:45:35.20,Default,,0,0,0,,just because it's a little bit more convenient. Dialogue: 0,0:45:35.21,0:45:38.67,Default,,0,0,0,,But don't lose sight of the fact that it's really this. Dialogue: 0,0:45:38.86,0:45:41.41,Default,,0,0,0,,In fact, as far as the Lisp interpreter's concerned, Dialogue: 0,0:45:41.61,0:45:45.55,Default,,0,0,0,,there's no difference between typing this to it and typing this to it. Dialogue: 0,0:45:46.51,0:45:53.29,Default,,0,0,0,,And there's a word for that, sort of syntactic sugar. Dialogue: 0,0:45:54.41,0:45:55.80,Default,,0,0,0,,What syntactic sugar means, Dialogue: 0,0:45:56.35,0:46:00.83,Default,,0,0,0,,it's having somewhat more convenient surface forms for typing something. Dialogue: 0,0:46:01.12,0:46:06.11,Default,,0,0,0,,So this is just really syntactic sugar for this underlying Greek thing with the lambda. Dialogue: 0,0:46:07.31,0:46:10.62,Default,,0,0,0,,And the reason you should remember that is don't forget that, Dialogue: 0,0:46:10.80,0:46:13.87,Default,,0,0,0,,when I write something like this, I'm really naming something. Dialogue: 0,0:46:14.46,0:46:16.22,Default,,0,0,0,,I'm naming something square, Dialogue: 0,0:46:16.24,0:46:19.90,Default,,0,0,0,,and the something that I'm naming square is a procedure that's getting constructed. Dialogue: 0,0:46:21.20,0:46:23.90,Default,,0,0,0,,Well, let's look at that on the computer, too. Dialogue: 0,0:46:24.78,0:46:35.95,Default,,0,0,0,,So I'll come and I'll say, define square of x to be times xx. Dialogue: 0,0:46:49.65,0:46:52.32,Default,,0,0,0,,Now I'll tell Lisp that. Dialogue: 0,0:46:53.49,0:46:53.92,Default,,0,0,0,,It says "square." Dialogue: 0,0:46:53.93,0:46:56.29,Default,,0,0,0,,See, I've named something "square." Dialogue: 0,0:46:56.45,0:47:02.88,Default,,0,0,0,,Now, having done that, I can ask Lisp for, what's the square of 1,001? Dialogue: 0,0:47:05.26,0:47:17.69,Default,,0,0,0,,Or in general, I could say, what's the square of the sum of 5 and 7? Dialogue: 0,0:47:22.81,0:47:24.95,Default,,0,0,0,,The square of 12's 144. Dialogue: 0,0:47:25.07,0:47:28.86,Default,,0,0,0,,Or I can use square itself as an element in some combination. Dialogue: 0,0:47:28.88,0:47:37.50,Default,,0,0,0,,I can say, what's the sum of the square of 3 and the square of 4? Dialogue: 0,0:47:42.53,0:47:44.09,Default,,0,0,0,,9 and 16 is 25. Dialogue: 0,0:47:44.91,0:47:50.54,Default,,0,0,0,,Or I can use square as an element in some much more complicated thing. Dialogue: 0,0:47:50.59,0:48:00.51,Default,,0,0,0,,I can say, what's the square of, the sqare of, the square of 1,001? Dialogue: 0,0:48:07.89,0:48:10.63,Default,,0,0,0,,And there's the square of the square of the square of 1,001. Dialogue: 0,0:48:11.20,0:48:15.45,Default,,0,0,0,,Or I can say to Lisp, what is square itself? Dialogue: 0,0:48:15.68,0:48:17.16,Default,,0,0,0,,What's the value of that? Dialogue: 0,0:48:17.44,0:48:22.14,Default,,0,0,0,,And Lisp returns some conventional way of telling me that that's a procedure. Dialogue: 0,0:48:22.27,0:48:23.98,Default,,0,0,0,,It says, "compound procedure square." Dialogue: 0,0:48:24.25,0:48:27.92,Default,,0,0,0,,Remember, the value of square is this procedure, Dialogue: 0,0:48:29.15,0:48:30.89,Default,,0,0,0,,and the thing with the stars and the brackets Dialogue: 0,0:48:31.10,0:48:34.78,Default,,0,0,0,,are just Lisp's conventional way of describing that. Dialogue: 0,0:48:36.11,0:48:41.33,Default,,0,0,0,,Let's look at two more examples of defining. Dialogue: 0,0:48:44.91,0:48:46.91,Default,,0,0,0,,Here are two more procedures. Dialogue: 0,0:48:47.36,0:48:52.84,Default,,0,0,0,,I can define the average of x and y to be the sum of x and y divided by 2. Dialogue: 0,0:48:54.67,0:49:01.49,Default,,0,0,0,,Or having had average and mean square, having had average and square, Dialogue: 0,0:49:01.65,0:49:04.71,Default,,0,0,0,,I can use that to talk about the mean square of something, Dialogue: 0,0:49:04.91,0:49:09.26,Default,,0,0,0,,which is the average of the square of x and the square of y. Dialogue: 0,0:49:10.97,0:49:13.63,Default,,0,0,0,,So for example, having done that, I could say, Dialogue: 0,0:49:13.66,0:49:24.88,Default,,0,0,0,,what's the mean square of 2 and 3? Dialogue: 0,0:49:25.23,0:49:30.24,Default,,0,0,0,,And I should get the average of 4 and 9, which is 6.5. Dialogue: 0,0:49:32.85,0:49:36.64,Default,,0,0,0,,The key thing here is that, having defined square, Dialogue: 0,0:49:36.64,0:49:38.67,Default,,0,0,0,,I can use it as if it were primitive. Dialogue: 0,0:49:41.41,0:49:43.07,Default,,0,0,0,,So if we look here on the slide, Dialogue: 0,0:49:44.65,0:49:45.74,Default,,0,0,0,,if I look at mean square, Dialogue: 0,0:49:47.29,0:49:52.56,Default,,0,0,0,,the person defining mean square doesn't have to know, at this point, Dialogue: 0,0:49:52.61,0:49:55.76,Default,,0,0,0,,whether square was something built into the language Dialogue: 0,0:49:56.94,0:49:58.93,Default,,0,0,0,,or whether it was a procedure that was defined. Dialogue: 0,0:49:59.73,0:50:01.28,Default,,0,0,0,,And that's a key thing in Lisp, Dialogue: 0,0:50:02.30,0:50:07.52,Default,,0,0,0,,that you do not make arbitrary distinctions between things Dialogue: 0,0:50:07.53,0:50:11.82,Default,,0,0,0,,that happen to be primitive in the language and things that happen to be built in. Dialogue: 0,0:50:12.83,0:50:14.73,Default,,0,0,0,,A person using that shouldn't even have to know. Dialogue: 0,0:50:14.93,0:50:18.51,Default,,0,0,0,,So the things you construct get used with all the power and flexibility Dialogue: 0,0:50:18.51,0:50:19.53,Default,,0,0,0,,as if they were primitives. Dialogue: 0,0:50:19.57,0:50:22.57,Default,,0,0,0,,In fact, you can drive that home by looking on the computer one more time. Dialogue: 0,0:50:24.75,0:50:26.30,Default,,0,0,0,,We talked about plus. Dialogue: 0,0:50:26.72,0:50:30.09,Default,,0,0,0,,And in fact, if I come here on the computer screen and say, Dialogue: 0,0:50:30.11,0:50:32.33,Default,,0,0,0,,what is the value of plus? Dialogue: 0,0:50:34.40,0:50:37.20,Default,,0,0,0,,Notice what Lisp types out. On the bottom there, it typed out, Dialogue: 0,0:50:37.25,0:50:38.81,Default,,0,0,0,,"compound procedure plus." Dialogue: 0,0:50:39.89,0:50:42.29,Default,,0,0,0,,Because, in this system, Dialogue: 0,0:50:42.33,0:50:45.49,Default,,0,0,0,,it turns out that the addition operator is itself a compound procedure. Dialogue: 0,0:50:45.97,0:50:47.97,Default,,0,0,0,,And if I didn't just type that in, you'd never know that, Dialogue: 0,0:50:48.06,0:50:49.68,Default,,0,0,0,,and it wouldn't make any difference anyway. Dialogue: 0,0:50:49.84,0:50:50.51,Default,,0,0,0,,We don't care. Dialogue: 0,0:50:50.56,0:50:53.39,Default,,0,0,0,,It's below the level of the abstraction that we're dealing with. Dialogue: 0,0:50:54.17,0:50:59.11,Default,,0,0,0,,So the key thing is you cannot tell, should not be able to tell, in general, Dialogue: 0,0:50:59.17,0:51:03.82,Default,,0,0,0,,the difference between things that are built in and things that are compound. Dialogue: 0,0:51:03.84,0:51:04.38,Default,,0,0,0,,Why is that? Dialogue: 0,0:51:04.38,0:51:08.07,Default,,0,0,0,,Because the things that are compound have an abstraction wrapper wrapped around them. Dialogue: 0,0:51:09.05,0:51:11.61,Default,,0,0,0,,We've seen almost all the elements of Lisp now. Dialogue: 0,0:51:12.67,0:51:14.53,Default,,0,0,0,,There's only one more we have to look at, Dialogue: 0,0:51:14.57,0:51:16.53,Default,,0,0,0,,and that is how to make a case analysis. Dialogue: 0,0:51:16.59,0:51:17.70,Default,,0,0,0,,Let me show you what I mean. Dialogue: 0,0:51:18.96,0:51:24.08,Default,,0,0,0,,We might want to think about the mathematical definition of the absolute value functions. Dialogue: 0,0:51:24.11,0:51:30.03,Default,,0,0,0,,I might say the absolute value of x is the function Dialogue: 0,0:51:30.16,0:51:37.24,Default,,0,0,0,,which has the property that it's negative of x. For x less than 0, Dialogue: 0,0:51:37.92,0:51:41.13,Default,,0,0,0,,it's 0 for x equal to 0. Dialogue: 0,0:51:42.64,0:51:46.62,Default,,0,0,0,,And it's x for x greater than 0. Dialogue: 0,0:51:49.15,0:51:51.90,Default,,0,0,0,,And Lisp has a way of making case analyses. Dialogue: 0,0:51:52.11,0:51:53.85,Default,,0,0,0,,Let me define for you absolute value. Dialogue: 0,0:51:55.55,0:52:02.41,Default,,0,0,0,,Say define the absolute value of x is conditional. Dialogue: 0,0:52:03.02,0:52:05.67,Default,,0,0,0,,This means case analysis, COND. Dialogue: 0,0:52:09.23,0:52:19.09,Default,,0,0,0,,If x is less than 0, the answer is negate x. Dialogue: 0,0:52:22.99,0:52:24.88,Default,,0,0,0,,What I've written here is a clause. Dialogue: 0,0:52:24.99,0:52:35.54,Default,,0,0,0,,This whole thing is a conditional clause, and it has two parts. Dialogue: 0,0:52:36.35,0:52:44.70,Default,,0,0,0,,This part here is a predicate or a condition. Dialogue: 0,0:52:44.83,0:52:45.90,Default,,0,0,0,,That's a condition. Dialogue: 0,0:52:46.11,0:52:48.29,Default,,0,0,0,,And the condition is expressed by something called a predicate, Dialogue: 0,0:52:48.33,0:52:51.05,Default,,0,0,0,,and a predicate in Lisp is some sort of thing Dialogue: 0,0:52:51.37,0:52:52.87,Default,,0,0,0,,that returns either true or false. Dialogue: 0,0:52:53.53,0:52:56.13,Default,,0,0,0,,And you see Lisp has a primitive procedure, less-than, Dialogue: 0,0:52:57.29,0:52:59.08,Default,,0,0,0,,that tests whether something is true or false. Dialogue: 0,0:53:00.54,0:53:06.32,Default,,0,0,0,,And the other part of a clause is an action or a thing to do, Dialogue: 0,0:53:06.93,0:53:08.14,Default,,0,0,0,,in the case where that's true. Dialogue: 0,0:53:08.17,0:53:09.81,Default,,0,0,0,,And here, what I'm doing is negating x. Dialogue: 0,0:53:10.08,0:53:14.41,Default,,0,0,0,,The negation operator, the minus sign in Lisp is a little bit funny. Dialogue: 0,0:53:14.56,0:53:18.43,Default,,0,0,0,,If there's two or more arguments, Dialogue: 0,0:53:18.58,0:53:22.49,Default,,0,0,0,,if there's two arguments it subtracts the second one from the first, and we saw that. Dialogue: 0,0:53:22.53,0:53:24.13,Default,,0,0,0,,And if there's one argument, it negates it. Dialogue: 0,0:53:25.13,0:53:27.87,Default,,0,0,0,,So this corresponds to that. Dialogue: 0,0:53:27.87,0:53:29.69,Default,,0,0,0,,And then there's another COND clause. Dialogue: 0,0:53:30.64,0:53:35.87,Default,,0,0,0,,It says, in the case where x is equal to 0, the answer is 0. Dialogue: 0,0:53:37.95,0:53:44.75,Default,,0,0,0,,And in the case where x is greater than 0, the answer is x. Dialogue: 0,0:53:45.33,0:53:49.38,Default,,0,0,0,,Close that clause. Close the COND. Close the definition. Dialogue: 0,0:53:49.57,0:53:51.29,Default,,0,0,0,,And there's the definition of absolute value. Dialogue: 0,0:53:51.31,0:53:53.66,Default,,0,0,0,,And you see it's the case analysis that looks very much Dialogue: 0,0:53:53.66,0:53:56.04,Default,,0,0,0,,like the case analysis you use in mathematics. Dialogue: 0,0:53:58.14,0:54:03.07,Default,,0,0,0,,There's a somewhat different way of writing a restricted case analysis. Dialogue: 0,0:54:03.07,0:54:06.24,Default,,0,0,0,,Often, you have a case analysis where you only have one case, Dialogue: 0,0:54:06.93,0:54:08.07,Default,,0,0,0,,where you test something, Dialogue: 0,0:54:08.33,0:54:10.75,Default,,0,0,0,,and then depending on whether it's true or false, you do something. Dialogue: 0,0:54:11.01,0:54:15.90,Default,,0,0,0,,And here's another definition of absolute value Dialogue: 0,0:54:16.00,0:54:17.19,Default,,0,0,0,,which looks almost the same, Dialogue: 0,0:54:17.66,0:54:22.56,Default,,0,0,0,,which says, if x is less than 0, the result is negate x. Dialogue: 0,0:54:24.41,0:54:25.97,Default,,0,0,0,,Otherwise, the answer is x. Dialogue: 0,0:54:26.05,0:54:27.25,Default,,0,0,0,,And we'll be using "if" a lot. Dialogue: 0,0:54:27.29,0:54:29.13,Default,,0,0,0,,But again, the thing to remember is that Dialogue: 0,0:54:29.13,0:54:32.70,Default,,0,0,0,,this form of absolute value that you're looking at here, Dialogue: 0,0:54:34.30,0:54:36.98,Default,,0,0,0,,and then this one over here that I wrote on the board, Dialogue: 0,0:54:37.52,0:54:38.80,Default,,0,0,0,,are essentially the same. Dialogue: 0,0:54:39.09,0:54:42.26,Default,,0,0,0,,And "if" and COND are-- well, whichever way you like it. Dialogue: 0,0:54:42.30,0:54:44.45,Default,,0,0,0,,You can think of COND as syntactic sugar for "if", Dialogue: 0,0:54:44.99,0:54:47.36,Default,,0,0,0,,or you can think of "if" as syntactic sugar for COND, Dialogue: 0,0:54:47.39,0:54:48.65,Default,,0,0,0,,and it doesn't make any difference. Dialogue: 0,0:54:49.21,0:54:51.35,Default,,0,0,0,,The person implementing a Lisp system will pick one Dialogue: 0,0:54:51.39,0:54:52.97,Default,,0,0,0,,and implement the other in terms of that. Dialogue: 0,0:54:53.15,0:54:54.67,Default,,0,0,0,,And it doesn't matter which one you pick. Dialogue: 0,0:55:02.27,0:55:05.36,Default,,0,0,0,,Why don't we break now, and then take some questions. Dialogue: 0,0:55:05.69,0:55:10.08,Default,,0,0,0,,How come sometimes when I write define, Dialogue: 0,0:55:11.09,0:55:14.75,Default,,0,0,0,,I put an open paren here and say, Dialogue: 0,0:55:14.81,0:55:16.45,Default,,0,0,0,,define open paren something or other, Dialogue: 0,0:55:16.86,0:55:20.81,Default,,0,0,0,,and sometimes when I write this, I don't put an open paren? Dialogue: 0,0:55:22.06,0:55:27.23,Default,,0,0,0,,The answer is, this particular form of "define", Dialogue: 0,0:55:27.26,0:55:29.41,Default,,0,0,0,,where you say define some expression, Dialogue: 0,0:55:29.47,0:55:32.13,Default,,0,0,0,,is this very special thing for defining procedures. Dialogue: 0,0:55:33.61,0:55:40.21,Default,,0,0,0,,But again, what it really means is I'm defining this symbol, square, to be that. Dialogue: 0,0:55:41.45,0:55:45.98,Default,,0,0,0,,So the way you should think about it is what "define" does is you write "define", Dialogue: 0,0:55:47.15,0:55:50.06,Default,,0,0,0,,and the second thing you write is the symbol here-- no open paren-- Dialogue: 0,0:55:50.17,0:55:51.49,Default,,0,0,0,,the symbol you're defining Dialogue: 0,0:55:52.08,0:55:53.70,Default,,0,0,0,,and what you're defining it to be. Dialogue: 0,0:55:54.65,0:55:57.55,Default,,0,0,0,,That's like here and like here. Dialogue: 0,0:55:57.61,0:56:00.29,Default,,0,0,0,,That's sort of the basic way you use "define." Dialogue: 0,0:56:01.12,0:56:03.65,Default,,0,0,0,,And then, there's this special syntactic trick Dialogue: 0,0:56:04.29,0:56:07.04,Default,,0,0,0,,which allows you to define procedures that look like this. Dialogue: 0,0:56:08.17,0:56:11.49,Default,,0,0,0,,So the difference is, it's whether or not you're defining a procedure. Dialogue: 0,0:56:12.91,0:56:37.60,Default,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:56:38.05,0:56:41.98,Default,,0,0,0,,Well, believe it or not, you actually now know enough Lisp Dialogue: 0,0:56:42.78,0:56:45.42,Default,,0,0,0,,to write essentially any numerical procedure Dialogue: 0,0:56:46.25,0:56:49.63,Default,,0,0,0,,that you'd write in a language like FORTRAN or Basic or whatever, Dialogue: 0,0:56:49.66,0:56:51.01,Default,,0,0,0,,or, essentially, any other language. Dialogue: 0,0:56:52.05,0:56:54.76,Default,,0,0,0,,And you're probably saying, that's not believable, Dialogue: 0,0:56:54.81,0:56:56.65,Default,,0,0,0,,because you know that these languages have things Dialogue: 0,0:56:56.65,0:57:00.22,Default,,0,0,0,,like "for statements", and "do until while" or something. Dialogue: 0,0:57:00.99,0:57:04.59,Default,,0,0,0,,But we don't really need any of that. Dialogue: 0,0:57:05.05,0:57:07.13,Default,,0,0,0,,In fact, we're not going to use any of that in this course. Dialogue: 0,0:57:08.25,0:57:10.16,Default,,0,0,0,,Let me show you. Dialogue: 0,0:57:10.25,0:57:13.61,Default,,0,0,0,,Again, looking back at square root, Dialogue: 0,0:57:13.65,0:57:19.03,Default,,0,0,0,,let's go back to this square root algorithm of Heron of Alexandria. Dialogue: 0,0:57:19.09,0:57:19.97,Default,,0,0,0,,Remember what that said. Dialogue: 0,0:57:20.06,0:57:23.67,Default,,0,0,0,,It said, to find an approximation to the square root of X, Dialogue: 0,0:57:25.07,0:57:26.16,Default,,0,0,0,,you make a guess, Dialogue: 0,0:57:27.45,0:57:31.88,Default,,0,0,0,,you improve that guess by averaging the guess and X over the guess. Dialogue: 0,0:57:32.94,0:57:36.06,Default,,0,0,0,,You keep improving that until the guess is good enough. Dialogue: 0,0:57:36.72,0:57:38.43,Default,,0,0,0,,I already alluded to the idea. Dialogue: 0,0:57:38.56,0:57:42.24,Default,,0,0,0,,The idea is that, if the initial guess that you took Dialogue: 0,0:57:43.04,0:57:46.91,Default,,0,0,0,,was actually equal to the square root of X, Dialogue: 0,0:57:47.15,0:57:50.06,Default,,0,0,0,,then G here would be equal to X/G. Dialogue: 0,0:57:52.89,0:57:55.33,Default,,0,0,0,,So if you hit the square root, averaging them wouldn't change it. Dialogue: 0,0:57:55.69,0:57:59.62,Default,,0,0,0,,If the G that you picked was larger than the square root of X, Dialogue: 0,0:58:00.38,0:58:02.94,Default,,0,0,0,,then X/G will be smaller than the square root of X, Dialogue: 0,0:58:03.21,0:58:05.37,Default,,0,0,0,,so that when you average G and X/G, Dialogue: 0,0:58:05.63,0:58:07.57,Default,,0,0,0,,you get something in between. Dialogue: 0,0:58:08.96,0:58:12.95,Default,,0,0,0,,So if you pick a G that's too small, your answer will be too large. Dialogue: 0,0:58:13.12,0:58:14.81,Default,,0,0,0,,If you pick a G that's too large, Dialogue: 0,0:58:16.32,0:58:18.06,Default,,0,0,0,,if your G is larger than the square root of X Dialogue: 0,0:58:18.08,0:58:20.35,Default,,0,0,0,,and X/G will be smaller than the square root of X. Dialogue: 0,0:58:21.23,0:58:23.65,Default,,0,0,0,,So averaging always gives you something in between. Dialogue: 0,0:58:24.53,0:58:28.13,Default,,0,0,0,,And then, it's not quite trivial, but it's possible to show that, Dialogue: 0,0:58:28.17,0:58:31.76,Default,,0,0,0,,in fact, if G misses the square root of X by a little bit, Dialogue: 0,0:58:31.81,0:58:37.99,Default,,0,0,0,,the average of G and X/G will actually keep getting closer to the square root of X. Dialogue: 0,0:58:38.03,0:58:38.99,Default,,0,0,0,,So if you keep doing this enough, Dialogue: 0,0:58:39.42,0:58:41.18,Default,,0,0,0,,you'll eventually get as close as you want. Dialogue: 0,0:58:41.71,0:58:42.85,Default,,0,0,0,,And then there's another fact, Dialogue: 0,0:58:43.02,0:58:47.65,Default,,0,0,0,,that you can always start out this process by using 1 as an initial guess. Dialogue: 0,0:58:49.23,0:58:51.35,Default,,0,0,0,,And it'll always converge to the square root of X. Dialogue: 0,0:58:52.24,0:58:56.77,Default,,0,0,0,,So that's this method of successive averaging due to Heron of Alexandria. Dialogue: 0,0:58:56.81,0:58:59.21,Default,,0,0,0,,Let's write it in Lisp. Dialogue: 0,0:59:00.57,0:59:02.61,Default,,0,0,0,,Well, the central idea is, Dialogue: 0,0:59:02.65,0:59:07.19,Default,,0,0,0,,what does it mean to try a guess for the square root of X? Dialogue: 0,0:59:08.30,0:59:09.37,Default,,0,0,0,,Let's write that. Dialogue: 0,0:59:09.79,0:59:25.02,Default,,0,0,0,,So we'll say, define to try a guess for the square root of X, Dialogue: 0,0:59:26.45,0:59:28.24,Default,,0,0,0,,what do we do? We'll say, Dialogue: 0,0:59:28.29,0:59:45.26,Default,,0,0,0,,if the guess is good enough to be a guess for the square root of X, Dialogue: 0,0:59:46.54,0:59:49.52,Default,,0,0,0,,then, as an answer, we'll take the guess. Dialogue: 0,0:59:51.61,0:59:57.01,Default,,0,0,0,,Otherwise, we will try the improved guess. Dialogue: 0,0:59:58.19,1:00:04.24,Default,,0,0,0,,We'll improve that guess for the square root of X, Dialogue: 0,1:00:05.26,1:00:09.33,Default,,0,0,0,,and we'll try that as a guess for the square root of X. Dialogue: 0,1:00:09.36,1:00:12.96,Default,,0,0,0,,Close the "try." Close the "if." Close the "define." Dialogue: 0,1:00:13.31,1:00:14.81,Default,,0,0,0,,So that's how we try a guess. Dialogue: 0,1:00:15.85,1:00:17.60,Default,,0,0,0,,And then, the next part of the process said, Dialogue: 0,1:00:17.73,1:00:21.90,Default,,0,0,0,,in order to compute square roots, we'll say, Dialogue: 0,1:00:21.93,1:00:30.17,Default,,0,0,0,,define to compute the square root of X, Dialogue: 0,1:00:30.80,1:00:35.79,Default,,0,0,0,,we will try 1 as a guess for the square root of X. Dialogue: 0,1:00:37.42,1:00:39.59,Default,,0,0,0,,Well, we have to define a couple more things. Dialogue: 0,1:00:40.08,1:00:43.36,Default,,0,0,0,,We have to say, how is a guess good enough? Dialogue: 0,1:00:43.84,1:00:45.29,Default,,0,0,0,,And how do we improve a guess? Dialogue: 0,1:00:45.85,1:00:47.10,Default,,0,0,0,,So let's look at that. Dialogue: 0,1:00:47.39,1:00:54.24,Default,,0,0,0,,The algorithm to improve a guess for the square root of X, Dialogue: 0,1:00:54.64,1:00:57.18,Default,,0,0,0,,we average-- that was the algorithm-- Dialogue: 0,1:00:57.18,1:01:02.16,Default,,0,0,0,,we average the guess with the quotient of dividing X by the guess. Dialogue: 0,1:01:02.99,1:01:04.57,Default,,0,0,0,,That's how we improve a guess. Dialogue: 0,1:01:05.85,1:01:08.80,Default,,0,0,0,,And to tell whether a guess is good enough, well, we have to decide something. Dialogue: 0,1:01:08.86,1:01:11.36,Default,,0,0,0,,This is supposed to be a guess for the square root of X, Dialogue: 0,1:01:11.37,1:01:14.03,Default,,0,0,0,,so one possible thing you can do is say, Dialogue: 0,1:01:14.06,1:01:16.07,Default,,0,0,0,,when you take that guess and square it, Dialogue: 0,1:01:16.64,1:01:18.41,Default,,0,0,0,,do you get something very close to X? Dialogue: 0,1:01:18.59,1:01:21.10,Default,,0,0,0,,So one way to say that is to say, Dialogue: 0,1:01:21.12,1:01:24.31,Default,,0,0,0,,I square the guess, subtract X from that, Dialogue: 0,1:01:25.15,1:01:27.15,Default,,0,0,0,,and see if the absolute value of that Dialogue: 0,1:01:27.20,1:01:32.05,Default,,0,0,0,,whole thing is less than some small number, which depends on my purposes. Dialogue: 0,1:01:34.70,1:01:41.42,Default,,0,0,0,,So there's a complete procedure for how to compute the square root of X. Dialogue: 0,1:01:41.47,1:01:43.53,Default,,0,0,0,,Let's look at the structure of that a little bit. Dialogue: 0,1:01:47.84,1:01:49.12,Default,,0,0,0,,I have the whole thing. Dialogue: 0,1:01:49.15,1:01:55.44,Default,,0,0,0,,I have the notion of how to compute a square root. Dialogue: 0,1:01:55.53,1:01:56.88,Default,,0,0,0,,That's some kind of module. Dialogue: 0,1:01:57.05,1:01:58.46,Default,,0,0,0,,That's some kind of black box. Dialogue: 0,1:01:58.72,1:02:08.02,Default,,0,0,0,,It's defined in terms of how to try a guess for the square root of X. Dialogue: 0,1:02:09.31,1:02:14.10,Default,,0,0,0,,"Try" is defined in terms of, well, Dialogue: 0,1:02:14.61,1:02:18.03,Default,,0,0,0,,telling whether something is good enough and telling how to improve something. Dialogue: 0,1:02:18.73,1:02:19.68,Default,,0,0,0,,So good enough. Dialogue: 0,1:02:19.89,1:02:28.85,Default,,0,0,0,,"Try" is defined in terms of "good enough" and "improve". Dialogue: 0,1:02:30.96,1:02:32.56,Default,,0,0,0,,And let's see what else I fill in. Dialogue: 0,1:02:32.71,1:02:34.29,Default,,0,0,0,,Well, I'll go down this tree. Dialogue: 0,1:02:34.73,1:02:38.49,Default,,0,0,0,,"Good enough" was defined in terms of absolute value, and square. Dialogue: 0,1:02:40.97,1:02:44.13,Default,,0,0,0,,And improve was defined in terms of something called averaging Dialogue: 0,1:02:45.17,1:02:46.70,Default,,0,0,0,,and then some other primitive operator. Dialogue: 0,1:02:46.72,1:02:48.88,Default,,0,0,0,,Square root's defined in terms of "try". Dialogue: 0,1:02:48.88,1:02:53.31,Default,,0,0,0,,"Try" is defined in terms of "good enough" and "improve", Dialogue: 0,1:02:54.01,1:02:55.39,Default,,0,0,0,,but also "try" itself. Dialogue: 0,1:02:55.58,1:03:00.86,Default,,0,0,0,,So "try" is also defined in terms of how to try itself. Dialogue: 0,1:03:02.75,1:03:04.72,Default,,0,0,0,,Well, that may give you some problems. Dialogue: 0,1:03:04.72,1:03:08.16,Default,,0,0,0,,Your high school geometry teacher probably told you Dialogue: 0,1:03:08.67,1:03:12.57,Default,,0,0,0,,that it's naughty to try and define things in terms of themselves, Dialogue: 0,1:03:12.88,1:03:13.92,Default,,0,0,0,,because it doesn't make sense. Dialogue: 0,1:03:13.92,1:03:14.72,Default,,0,0,0,,But that's false. Dialogue: 0,1:03:16.03,1:03:19.68,Default,,0,0,0,,Sometimes it makes perfect sense to define things in terms of themselves. Dialogue: 0,1:03:20.16,1:03:24.38,Default,,0,0,0,,And this is the case. And we can look at that. Dialogue: 0,1:03:24.38,1:03:26.89,Default,,0,0,0,,We could write down what this means, and say, Dialogue: 0,1:03:26.91,1:03:30.33,Default,,0,0,0,,suppose I asked Lisp what the square root of 2 is. Dialogue: 0,1:03:32.65,1:03:34.67,Default,,0,0,0,,What's the square root of 2 mean? Dialogue: 0,1:03:35.79,1:03:43.61,Default,,0,0,0,,Well, that means I try 1 as a guess for the square root of 2. Dialogue: 0,1:03:46.97,1:03:50.92,Default,,0,0,0,,Now I look. I say, gee, is 1 a good enough guess for the square root of 2? Dialogue: 0,1:03:51.65,1:03:53.69,Default,,0,0,0,,And that depends on the test that "good enough" does. Dialogue: 0,1:03:54.61,1:03:56.56,Default,,0,0,0,,And in this case, "good enough" will say, Dialogue: 0,1:03:56.65,1:03:59.05,Default,,0,0,0,,no, 1 is not a good enough guess for the square root of 2. Dialogue: 0,1:03:59.79,1:04:08.22,Default,,0,0,0,,So that will reduce to saying, I have to try an improved-- Dialogue: 0,1:04:08.64,1:04:12.63,Default,,0,0,0,,improve 1 as a guess for the square root of 2, Dialogue: 0,1:04:15.15,1:04:17.46,Default,,0,0,0,,and try that as a guess for the square root of 2. Dialogue: 0,1:04:19.13,1:04:22.07,Default,,0,0,0,,Improving 1 as a guess for the square root of 2 Dialogue: 0,1:04:22.09,1:04:25.08,Default,,0,0,0,,means I average 1 and 2 divided by 1. Dialogue: 0,1:04:27.10,1:04:29.10,Default,,0,0,0,,So this is going to be average. Dialogue: 0,1:04:29.58,1:04:39.44,Default,,0,0,0,,This piece here will be the average of 1 and the quotient of 2 by 1. Dialogue: 0,1:04:40.83,1:04:42.75,Default,,0,0,0,,That's this piece here. Dialogue: 0,1:04:43.85,1:04:46.72,Default,,0,0,0,,And I'm gonna try... And this is 1.5. Dialogue: 0,1:04:49.07,1:04:54.40,Default,,0,0,0,,So this square root of 2 reduces to trying 1 for the square root of 2, Dialogue: 0,1:04:54.56,1:05:04.83,Default,,0,0,0,,which reduces to trying 1.5 as a guess for the square root of 2. Dialogue: 0,1:05:06.03,1:05:08.06,Default,,0,0,0,,So that makes sense. Dialogue: 0,1:05:08.11,1:05:09.52,Default,,0,0,0,,Let's look at the rest of the process. Dialogue: 0,1:05:09.73,1:05:15.00,Default,,0,0,0,,If I try 1.5, that reduces. Dialogue: 0,1:05:15.01,1:05:19.05,Default,,0,0,0,,1.5 turns out to be not good enough as a guess for the square root of 2. Dialogue: 0,1:05:20.22,1:05:22.00,Default,,0,0,0,,So that reduces to trying the average of Dialogue: 0,1:05:22.01,1:05:26.17,Default,,0,0,0,,1.5 and 2 divided by 1.5 as a guess for the square root of 2. Dialogue: 0,1:05:28.29,1:05:30.37,Default,,0,0,0,,That average turns out to be 1.333. Dialogue: 0,1:05:31.18,1:05:35.24,Default,,0,0,0,,So this whole thing reduces to trying 1.333 as a guess for the square root of 2. Dialogue: 0,1:05:35.28,1:05:36.06,Default,,0,0,0,,And then so on. Dialogue: 0,1:05:38.01,1:05:41.66,Default,,0,0,0,,That reduces to another called a "good enough", 1.4 something or other. Dialogue: 0,1:05:41.73,1:05:44.47,Default,,0,0,0,,And then it keeps going until the process finally stops Dialogue: 0,1:05:44.85,1:05:47.92,Default,,0,0,0,,with something that "good enough" thinks is good enough, which, Dialogue: 0,1:05:47.97,1:05:51.28,Default,,0,0,0,,in this case, is 1.4142 something or other. Dialogue: 0,1:05:52.51,1:05:56.05,Default,,0,0,0,,So the process makes perfect sense. Dialogue: 0,1:05:59.93,1:06:03.10,Default,,0,0,0,,This, by the way, is called a recursive definition. Dialogue: 0,1:06:14.40,1:06:20.96,Default,,0,0,0,,And the ability to make recursive definitions is a source of incredible power. Dialogue: 0,1:06:21.95,1:06:23.05,Default,,0,0,0,,And as you can already see I've hinted at, Dialogue: 0,1:06:23.09,1:06:27.21,Default,,0,0,0,,it's the thing that effectively allows you to do these infinite computations Dialogue: 0,1:06:27.25,1:06:28.83,Default,,0,0,0,,that go on until something is true, Dialogue: 0,1:06:29.73,1:06:33.66,Default,,0,0,0,,without having any other constricts other than the ability to call a procedure. Dialogue: 0,1:06:35.97,1:06:37.47,Default,,0,0,0,,Well, let's see, there's one more thing. Dialogue: 0,1:06:37.71,1:06:44.21,Default,,0,0,0,,Let me show you a variant of this definition of square root here on the slide. Dialogue: 0,1:06:44.43,1:06:48.16,Default,,0,0,0,,Here's sort of the same thing. Dialogue: 0,1:06:48.40,1:06:51.49,Default,,0,0,0,,What I've done here is packaged the definitions of Dialogue: 0,1:06:51.52,1:06:56.16,Default,,0,0,0,,"improve" and "good enough" and "try" inside "square root". Dialogue: 0,1:06:56.75,1:07:00.99,Default,,0,0,0,,So, in effect, what I've done is I've built a square root box. Dialogue: 0,1:07:01.81,1:07:08.53,Default,,0,0,0,,So I've built a box that's the square root procedure that someone can use. Dialogue: 0,1:07:08.57,1:07:11.47,Default,,0,0,0,,They might put in 36 and get out 6. Dialogue: 0,1:07:11.81,1:07:13.83,Default,,0,0,0,,And then, packaged inside this box Dialogue: 0,1:07:14.16,1:07:23.85,Default,,0,0,0,,are the definitions of "try" and "good enough" and "improve." Dialogue: 0,1:07:26.78,1:07:28.35,Default,,0,0,0,,So they're hidden inside this box. Dialogue: 0,1:07:28.40,1:07:30.76,Default,,0,0,0,,And the reason for doing that is that, Dialogue: 0,1:07:31.18,1:07:32.85,Default,,0,0,0,,if someone's using this square root, Dialogue: 0,1:07:33.21,1:07:34.73,Default,,0,0,0,,if George is using this square root, Dialogue: 0,1:07:34.75,1:07:37.36,Default,,0,0,0,,George probably doesn't care very much that, Dialogue: 0,1:07:38.29,1:07:40.03,Default,,0,0,0,,when I implemented square root, Dialogue: 0,1:07:40.21,1:07:44.45,Default,,0,0,0,,I had things inside there called "try" and "good enough" and "improve". Dialogue: 0,1:07:46.40,1:07:49.33,Default,,0,0,0,,And in fact, Harry might have a cube root procedure Dialogue: 0,1:07:49.37,1:07:50.96,Default,,0,0,0,,that has "try" and "good enough" and "improve". Dialogue: 0,1:07:51.44,1:07:53.34,Default,,0,0,0,,And in order to not get the whole system confused, Dialogue: 0,1:07:53.36,1:07:57.66,Default,,0,0,0,,it'd be good for Harry to package his internal procedures inside his cube root procedure. Dialogue: 0,1:07:58.40,1:08:00.06,Default,,0,0,0,,Well, this is called block structure, Dialogue: 0,1:08:00.32,1:08:08.96,Default,,0,0,0,,this particular way of packaging internals inside of a definition. Dialogue: 0,1:08:09.97,1:08:12.96,Default,,0,0,0,,And let's go back and look at the slide again. Dialogue: 0,1:08:13.12,1:08:18.57,Default,,0,0,0,,The way to read this kind of procedure is to say, to define "square root", Dialogue: 0,1:08:19.87,1:08:21.84,Default,,0,0,0,,well, inside that definition, Dialogue: 0,1:08:22.13,1:08:25.49,Default,,0,0,0,,I'll have the definition of an "improve" and Dialogue: 0,1:08:25.56,1:08:28.88,Default,,0,0,0,,the definition of "good enough" and the definition of "try." Dialogue: 0,1:08:29.73,1:08:32.38,Default,,0,0,0,,And then, subject to those definitions, Dialogue: 0,1:08:32.48,1:08:35.07,Default,,0,0,0,,the way I do square root is to try 1. Dialogue: 0,1:08:36.08,1:08:39.33,Default,,0,0,0,,And notice here, I don't have to say 1 as a guess for the square root of X, Dialogue: 0,1:08:39.87,1:08:42.32,Default,,0,0,0,,because since it's all inside the square root, Dialogue: 0,1:08:42.84,1:08:44.65,Default,,0,0,0,,it sort of has this X known. Dialogue: 0,1:08:54.06,1:08:56.37,Default,,0,0,0,,Let me summarize. Dialogue: 0,1:08:56.49,1:08:59.49,Default,,0,0,0,,We started out with the idea that Dialogue: 0,1:08:59.51,1:09:03.18,Default,,0,0,0,,what we're going to be doing is expressing imperative knowledge. Dialogue: 0,1:09:04.99,1:09:09.74,Default,,0,0,0,,And in fact, here's a slide that summarizes the way we looked at Lisp. Dialogue: 0,1:09:09.74,1:09:15.12,Default,,0,0,0,,We started out by looking at some primitive elements in addition and multiplication, Dialogue: 0,1:09:15.85,1:09:19.50,Default,,0,0,0,,some predicates for testing whether something is less-than or something's equal. Dialogue: 0,1:09:19.52,1:09:22.99,Default,,0,0,0,,And in fact, we saw really sneakily in the system we're actually using, Dialogue: 0,1:09:23.02,1:09:25.85,Default,,0,0,0,,these aren't actually primitives, but it doesn't matter. Dialogue: 0,1:09:26.62,1:09:28.59,Default,,0,0,0,,What matters is we're going to use them as if they're primitives. Dialogue: 0,1:09:28.61,1:09:29.81,Default,,0,0,0,,We're not going to look inside. Dialogue: 0,1:09:30.29,1:09:33.15,Default,,0,0,0,,We also have some primitive data and some numbers. Dialogue: 0,1:09:34.62,1:09:37.66,Default,,0,0,0,,We saw some means of composition, means of combination, Dialogue: 0,1:09:37.74,1:09:41.37,Default,,0,0,0,,the basic one being composing functions and Dialogue: 0,1:09:41.41,1:09:43.76,Default,,0,0,0,,building combinations with operators and operands. Dialogue: 0,1:09:44.81,1:09:48.43,Default,,0,0,0,,And there were some other things, like COND and "if" and "define". Dialogue: 0,1:09:51.29,1:09:53.69,Default,,0,0,0,,But the main thing about "define," in particular, Dialogue: 0,1:09:53.87,1:09:55.71,Default,,0,0,0,,was that it was the means of abstraction. Dialogue: 0,1:09:55.73,1:09:57.70,Default,,0,0,0,,It was the way that we name things. Dialogue: 0,1:09:57.79,1:10:00.30,Default,,0,0,0,,You can also see from this slide not only where we've been, Dialogue: 0,1:10:01.57,1:10:06.28,Default,,0,0,0,,At some point, we'll have to talk about how you combine primitive data to get compound data, Dialogue: 0,1:10:06.56,1:10:12.03,Default,,0,0,0,,and how you abstract data so you can use large globs of data Dialogue: 0,1:10:12.06,1:10:13.07,Default,,0,0,0,,as if they were primitive. Dialogue: 0,1:10:13.90,1:10:15.87,Default,,0,0,0,,So that's where we're going. Dialogue: 0,1:10:16.38,1:10:22.05,Default,,0,0,0,,But before we do that, for the next couple of lectures we're going to be talking about, Dialogue: 0,1:10:23.26,1:10:26.76,Default,,0,0,0,,first of all, how it is that you make a link Dialogue: 0,1:10:26.88,1:10:30.77,Default,,0,0,0,,between these procedures we write and the processes that happen in the machine. Dialogue: 0,1:10:32.14,1:10:35.98,Default,,0,0,0,,And then, how it is that you start using the power of Lisp Dialogue: 0,1:10:36.38,1:10:39.77,Default,,0,0,0,,to talk not only about these individual little computations, Dialogue: 0,1:10:40.08,1:10:44.15,Default,,0,0,0,,but about general conventional methods of doing things. Dialogue: 0,1:10:44.81,1:10:46.17,Default,,0,0,0,,OK, are there any questions? Dialogue: 0,1:10:46.75,1:10:52.27,Default,,0,0,0,,AUDIENCE: Yes. If we defined A using parentheses instead of as we did, Dialogue: 0,1:10:52.32,1:10:53.50,Default,,0,0,0,,what would be the difference? Dialogue: 0,1:10:53.60,1:10:56.88,Default,,0,0,0,,PROFESSOR: If I wrote this, if I wrote that, Dialogue: 0,1:10:57.53,1:11:02.13,Default,,0,0,0,,what I would be doing is defining a procedure named A. Dialogue: 0,1:11:03.21,1:11:06.85,Default,,0,0,0,,In this case, a procedure of no arguments, which, Dialogue: 0,1:11:06.85,1:11:09.61,Default,,0,0,0,,when I ran it, would give me back 5 times 5. Dialogue: 0,1:11:11.07,1:11:12.29,Default,,0,0,0,,AUDIENCE: Right. I mean, you come up with the same thing, Dialogue: 0,1:11:12.32,1:11:13.92,Default,,0,0,0,,except for you really got a different-- Dialogue: 0,1:11:14.05,1:11:16.63,Default,,0,0,0,,PROFESSOR: Right. And the difference would be, in the old one-- Dialogue: 0,1:11:17.02,1:11:18.35,Default,,0,0,0,,Let me be a little bit clearer here. Dialogue: 0,1:11:19.13,1:11:23.44,Default,,0,0,0,,Let's call this A, like here. Dialogue: 0,1:11:24.13,1:11:27.76,Default,,0,0,0,,And pretend here, just for contrast, I wrote, Dialogue: 0,1:11:27.79,1:11:37.56,Default,,0,0,0,,define D to be the product of 5 and 5. Dialogue: 0,1:11:40.22,1:11:41.57,Default,,0,0,0,,And the difference between those, Dialogue: 0,1:11:41.96,1:11:44.24,Default,,0,0,0,,let's think about interactions with the Lisp interpreter. Dialogue: 0,1:11:45.74,1:11:49.13,Default,,0,0,0,,I could type in A and Lisp would return 25. Dialogue: 0,1:11:52.83,1:11:57.81,Default,,0,0,0,,I could type in D, if I just typed in D, Dialogue: 0,1:11:58.49,1:12:05.55,Default,,0,0,0,,Lisp would return compound procedure D, Dialogue: 0,1:12:07.12,1:12:09.13,Default,,0,0,0,,because that's what it is. It's a procedure. Dialogue: 0,1:12:09.69,1:12:12.59,Default,,0,0,0,,I could run D. I could say, what's the value of running D? Dialogue: 0,1:12:12.59,1:12:15.23,Default,,0,0,0,,Here is a combination with no operands. Dialogue: 0,1:12:16.45,1:12:19.07,Default,,0,0,0,,I see there are no operands. I didn't put any after D. Dialogue: 0,1:12:19.39,1:12:21.34,Default,,0,0,0,,And it would say, oh, that's 25. Dialogue: 0,1:12:23.01,1:12:29.52,Default,,0,0,0,,Or I could say, just for completeness, if I typed in, what's the value of running A? Dialogue: 0,1:12:29.54,1:12:30.57,Default,,0,0,0,,I get an error. Dialogue: 0,1:12:31.79,1:12:35.29,Default,,0,0,0,,The error would be the same one as over there. Dialogue: 0,1:12:35.33,1:12:40.51,Default,,0,0,0,,It'd be the error would say, sorry, 25, which is the value of A, Dialogue: 0,1:12:40.56,1:12:43.24,Default,,0,0,0,,is not an operator that I can apply to something. ================================================ FILE: Ass/lec3a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: SICP ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Last Style Storage: Default Audio URI: G:\untitled\ref\lec3a_480_muxed.mp4 Video Zoom Percent: 0.625 Scroll Position: 1836 Active Line: 1841 Video File: G:\untitled\ref\lec3a_480_muxed.bk.mp4 Video Aspect Ratio: c1.33333 Video Position: 135623 PlayResX: 640 PlayResY: 480 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:20.94,0:00:23.86,EN,,0,0,0,,PROFESSOR: Well, last time we talked about compound data, Dialogue: 0,0:00:24.94,0:00:29.74,EN,,0,0,0,,and there were two main points to that business. Dialogue: 0,0:00:29.74,0:00:32.48,EN,,0,0,0,,First of all, there was a methodology of data abstraction, Dialogue: 0,0:00:32.94,0:00:39.10,EN,,0,0,0,,and the point of that was that you could isolate the way that data objects are used Dialogue: 0,0:00:40.06,0:00:41.50,EN,,0,0,0,,from the way that they're represented: Dialogue: 0,0:00:41.55,0:00:45.20,EN,,0,0,0,,this idea that there's this guy, George, and you go out make a contract with him; Dialogue: 0,0:00:45.20,0:00:47.48,EN,,0,0,0,,and it's his business to represent the data objects; Dialogue: 0,0:00:47.48,0:00:49.36,EN,,0,0,0,,and at the moment you are using them, Dialogue: 0,0:00:49.36,0:00:51.36,EN,,0,0,0,,you don't think about George's problem. Dialogue: 0,0:00:51.98,0:00:58.44,EN,,0,0,0,,And then secondly, there was this particular way that Lisp has of gluing together things Dialogue: 0,0:00:58.94,0:01:00.52,EN,,0,0,0,,to form objects called pairs, Dialogue: 0,0:01:00.52,0:01:03.54,EN,,0,0,0,,and that's done with cons, car and cdr. Dialogue: 0,0:01:03.54,0:01:07.16,EN,,0,0,0,,And the way that cons, car and cdr are implemented is basically irrelevant. Dialogue: 0,0:01:07.16,0:01:10.02,EN,,0,0,0,,That's sort of George's problem of how to build those things. Dialogue: 0,0:01:10.02,0:01:11.16,EN,,0,0,0,,It could be done as primitives. Dialogue: 0,0:01:11.16,0:01:13.80,EN,,0,0,0,,It could be done using procedures in some weird way, Dialogue: 0,0:01:13.80,0:01:15.22,EN,,0,0,0,,but we're not going to worry about that. Dialogue: 0,0:01:16.02,0:01:19.66,EN,,0,0,0,,And as an example, we looked at rational number arithmetic. Dialogue: 0,0:01:19.66,0:01:21.50,EN,,0,0,0,,We looked at vectors, Dialogue: 0,0:01:21.50,0:01:24.18,EN,,0,0,0,,and here's just a review of vectors. Dialogue: 0,0:01:24.18,0:01:27.64,EN,,0,0,0,,Here's an operation that takes the sum of of two vectors, Dialogue: 0,0:01:27.64,0:01:33.32,EN,,0,0,0,,so we want to add this vector, v1, and this vector, v2, and we get the sum. Dialogue: 0,0:01:34.46,0:01:40.84,EN,,0,0,0,,And the sum is the vector whose coordinates are the sum of the coordinates of the pieces you're adding. Dialogue: 0,0:01:41.28,0:01:45.66,EN,,0,0,0,,So I can say, to define make-vect, right, to add two vectors Dialogue: 0,0:01:45.66,0:01:51.72,EN,,0,0,0,,I make a vector, whose x coordinate is the sum of the two x coordinates, Dialogue: 0,0:01:52.10,0:01:54.82,EN,,0,0,0,,and whose y coordinate is the sum of the two y coordinates. Dialogue: 0,0:01:56.06,0:02:04.10,EN,,0,0,0,,And then similarly, we could have an operation that scales vectors, Dialogue: 0,0:02:04.94,0:02:12.66,EN,,0,0,0,,so here's a procedure scale that multiplies a vector, v, by some number, s. Dialogue: 0,0:02:13.08,0:02:16.14,EN,,0,0,0,,So here's v, v goes from there to there Dialogue: 0,0:02:16.32,0:02:20.22,EN,,0,0,0,,and I scale v, and I get a vector in the same direction that's longer. Dialogue: 0,0:02:21.56,0:02:24.26,EN,,0,0,0,,And again, to scale a vector, I multiply the successive coordinates. Dialogue: 0,0:02:24.26,0:02:30.22,EN,,0,0,0,,So I make a vector, whose x coordinate is the scale factor times the x coordinate Dialogue: 0,0:02:30.56,0:02:33.54,EN,,0,0,0,,and whose y coordinate is the scale factor times the y coordinate. Dialogue: 0,0:02:33.54,0:02:40.28,EN,,0,0,0,,So those are two operations that are implemented using the representation of vectors. Dialogue: 0,0:02:40.28,0:02:45.02,EN,,0,0,0,,And the representation of vectors, for instance, is something that we can build in terms of pairs. Dialogue: 0,0:02:45.34,0:02:51.28,EN,,0,0,0,,So George has gone out and implemented for us make-vector and x coordinate and y coordinate, Dialogue: 0,0:02:53.02,0:02:57.98,EN,,0,0,0,,and this could be done, for instance, using cons,car and cdr; Dialogue: 0,0:02:58.88,0:03:06.78,EN,,0,0,0,,and notice here, I wrote this in a slightly different way. Dialogue: 0,0:03:08.04,0:03:11.00,EN,,0,0,0,,The procedures we've seen before, I've said something like Dialogue: 0,0:03:11.14,0:03:16.22,EN,,0,0,0,,say, make-vector of x and y: cons of x and y. Dialogue: 0,0:03:16.22,0:03:17.98,EN,,0,0,0,,And here I just wrote make-vector cons. Dialogue: 0,0:03:17.98,0:03:20.48,EN,,0,0,0,,And that means something slightly different. Dialogue: 0,0:03:20.48,0:03:26.22,EN,,0,0,0,,Previously we'd say, define make-vector to be a procedure that takes two arguments, x and y, Dialogue: 0,0:03:26.22,0:03:28.04,EN,,0,0,0,,and does cons of x and y. Dialogue: 0,0:03:28.04,0:03:34.12,EN,,0,0,0,,And here I am saying define make-vector to be the thing that cons is, Dialogue: 0,0:03:35.18,0:03:39.66,EN,,0,0,0,,and that's almost the same as the other way we've been writing things. Dialogue: 0,0:03:39.66,0:03:46.58,EN,,0,0,0,,And I just want you to get used to the idea that procedures can be objects, and that you can name them. Dialogue: 0,0:03:48.70,0:03:51.80,EN,,0,0,0,,OK, well there's vector representation, and again, Dialogue: 0,0:03:51.80,0:03:55.68,EN,,0,0,0,,if that was all there was to it,this would all be pretty boring. Dialogue: 0,0:03:57.02,0:04:02.16,EN,,0,0,0,,And the point is, remember, that you can use cons to glue together not just numbers to form pairs, Dialogue: 0,0:04:02.16,0:04:04.16,EN,,0,0,0,,but to glue together arbitrary things. Dialogue: 0,0:04:05.20,0:04:11.60,EN,,0,0,0,,So for instance, if we'd like to represent a line segment, Dialogue: 0,0:04:11.60,0:04:15.64,EN,,0,0,0,,say the line segment that goes from a certain vector: Dialogue: 0,0:04:16.06,0:04:28.30,EN,,0,0,0,,say, the segment from the vector 2,3 to the point represented by the vector 5,1. Dialogue: 0,0:04:28.30,0:04:31.82,EN,,0,0,0,,If we want to represent that line segment, Dialogue: 0,0:04:33.26,0:04:36.20,EN,,0,0,0,,then we can build that as a pair of pairs. Dialogue: 0,0:04:40.72,0:04:42.94,EN,,0,0,0,,So again, we can represent line segments. Dialogue: 0,0:04:42.94,0:04:47.34,EN,,0,0,0,,We can make a constructor that makes a segment using cons, Dialogue: 0,0:04:47.98,0:04:51.60,EN,,0,0,0,,selects out the start of a segment, selects out the end point of the segment; Dialogue: 0,0:04:55.24,0:04:59.76,EN,,0,0,0,,and then if we actually look at that, if we peel away the abstraction layers, Dialogue: 0,0:04:59.88,0:05:02.10,EN,,0,0,0,,and see what's that really is a pair of pairs, Dialogue: 0,0:05:04.66,0:05:06.22,EN,,0,0,0,,we'd say well that's a pair. Dialogue: 0,0:05:06.22,0:05:08.22,EN,,0,0,0,,Here's the segment. Dialogue: 0,0:05:10.00,0:05:16.72,EN,,0,0,0,,It's car, right, it's car pointer is a pair, and it's cdr is also a pair, Dialogue: 0,0:05:18.32,0:05:25.54,EN,,0,0,0,,and then what the car is--here's the car, that itself is a pair of 2 and 3. Dialogue: 0,0:05:26.02,0:05:28.08,EN,,0,0,0,,And similarly the cdr is a pair of 2 and 3. Dialogue: 0,0:05:28.16,0:05:29.24,EN,,0,0,0,,And let me remind you again Dialogue: 0,0:05:29.32,0:05:33.46,EN,,0,0,0,,that a lot of people have some idea that if I'd taken this arrow and somehow Dialogue: 0,0:05:33.80,0:05:36.90,EN,,0,0,0,,written it to point down, that would mean something else. Dialogue: 0,0:05:36.98,0:05:38.28,EN,,0,0,0,,That's irrelevant. Dialogue: 0,0:05:38.58,0:05:43.90,EN,,0,0,0,,It's only how these are connected and not whether this arrow happens to go vertically or horizontally. Dialogue: 0,0:05:47.48,0:05:52.18,EN,,0,0,0,,And again just to remind you, there was this notion of closure. Dialogue: 0,0:05:52.94,0:06:05.62,EN,,0,0,0,,See, closure was the thing that allowed us to start building up complexity, that didn't trap us in pairs. Dialogue: 0,0:06:06.64,0:06:15.24,EN,,0,0,0,,Particularly what I mean is the things that we make, having combined things using cons to get a pair, Dialogue: 0,0:06:16.44,0:06:22.64,EN,,0,0,0,,those things themselves can be combined using cons to make more complicated things. Dialogue: 0,0:06:23.28,0:06:31.98,EN,,0,0,0,,Or as a mathematician might say, the set of data objects in Lisp is closed under the operation of forming pairs. Dialogue: 0,0:06:33.82,0:06:36.34,EN,,0,0,0,,That's the thing that allows us to build complexity. Dialogue: 0,0:06:36.34,0:06:38.04,EN,,0,0,0,,And that seems obvious, but remember Dialogue: 0,0:06:39.06,0:06:42.46,EN,,0,0,0,,a lot of the things in the computer languages that people use are not closed. Dialogue: 0,0:06:42.46,0:06:48.06,EN,,0,0,0,,So for example, forming arrays in Basic and Fortran is not a closed operation, Dialogue: 0,0:06:48.08,0:06:51.94,EN,,0,0,0,,because you can make an array of numbers or character strings or something, Dialogue: 0,0:06:52.04,0:06:54.18,EN,,0,0,0,,but you can't make an array of arrays. Dialogue: 0,0:06:54.64,0:06:56.68,EN,,0,0,0,,And when you look at means of combination Dialogue: 0,0:06:57.60,0:07:02.78,EN,,0,0,0,,you should be asking yourself whether things are closed under that means of combination. Dialogue: 0,0:07:05.06,0:07:08.26,EN,,0,0,0,,Well in any case, because we can form pairs of pairs, Dialogue: 0,0:07:08.86,0:07:12.78,EN,,0,0,0,,we can start using pairs to glue things together in all sorts of different ways. Dialogue: 0,0:07:14.02,0:07:18.26,EN,,0,0,0,,So for instance if I'd like to glue together the four things, 1, 2, 3 and 4, Dialogue: 0,0:07:18.26,0:07:19.82,EN,,0,0,0,,there are a lot of ways I can do it. Dialogue: 0,0:07:20.74,0:07:26.12,EN,,0,0,0,,I could, for example, like we did with that line segment, i could make a pair Dialogue: 0,0:07:29.02,0:07:36.88,EN,,0,0,0,,that had a 1 and a 2 and a 3 and a 4, right? Dialogue: 0,0:07:36.88,0:07:40.06,EN,,0,0,0,,Or if I liked, I could do something like this. Dialogue: 0,0:07:40.06,0:07:45.52,EN,,0,0,0,,I could make a pair, whose first thing is a pair, Dialogue: 0,0:07:46.44,0:07:53.20,EN,,0,0,0,,whose car is 1, and his cdr is itself a pair that has the 2 and the 3 Dialogue: 0,0:07:53.26,0:07:55.08,EN,,0,0,0,,and then I could put the 4 up here. Dialogue: 0,0:07:56.92,0:08:02.16,EN,,0,0,0,,So you see, there are a lot of different ways that I can start using pairs to glue things together, Dialogue: 0,0:08:02.16,0:08:07.74,EN,,0,0,0,,and so it'll be a good idea to establish some kind of conventions,right, Dialogue: 0,0:08:07.74,0:08:11.58,EN,,0,0,0,,that allow us to deal with this thing in some conventional way, Dialogue: 0,0:08:11.58,0:08:14.00,EN,,0,0,0,,so we're not constantly making an ad hoc choice. Dialogue: 0,0:08:15.94,0:08:19.04,EN,,0,0,0,,And Lisp has a particular convention Dialogue: 0,0:08:20.74,0:08:25.82,EN,,0,0,0,,for representing a sequence of things as, essentially, a chain of pairs, Dialogue: 0,0:08:26.78,0:08:28.18,EN,,0,0,0,,and that's called a List. Dialogue: 0,0:08:34.72,0:08:40.50,EN,,0,0,0,,And what a list is is essentially just a convention for representing a sequence. Dialogue: 0,0:08:40.70,0:08:47.38,EN,,0,0,0,,I would represent the sequence 1, 2, 3 and 4 by a sequence of pairs. Dialogue: 0,0:08:48.26,0:08:54.68,EN,,0,0,0,,I'd put 1 here and then the cdr of this would point to another pair Dialogue: 0,0:08:59.20,0:09:01.40,EN,,0,0,0,,whose car was the next thing in the sequence, Dialogue: 0,0:09:01.52,0:09:03.42,EN,,0,0,0,,and the cdr would point to another pair Dialogue: 0,0:09:05.44,0:09:07.30,EN,,0,0,0,,whose car was the next thing in the sequence-- Dialogue: 0,0:09:07.36,0:09:08.44,EN,,0,0,0,,so there's 3-- Dialogue: 0,0:09:08.44,0:09:09.74,EN,,0,0,0,,and then another one. Dialogue: 0,0:09:09.74,0:09:13.22,EN,,0,0,0,,So for each item in the sequence, I'll get a pair. Dialogue: 0,0:09:15.82,0:09:18.32,EN,,0,0,0,,And now there are no more, so I put a special marker Dialogue: 0,0:09:20.72,0:09:22.74,EN,,0,0,0,,that means there's nothing more in the List. Dialogue: 0,0:09:24.14,0:09:34.64,EN,,0,0,0,,OK, so that's a conventional way to glue things together if you want to represent a sequence, right. Dialogue: 0,0:09:34.64,0:09:37.98,EN,,0,0,0,,And what it is is a bunch of pairs, Dialogue: 0,0:09:39.40,0:09:44.80,EN,,0,0,0,,the successive cars of each pair are the items that you want to glue together, Dialogue: 0,0:09:46.00,0:09:48.46,EN,,0,0,0,,and the cdr pointer points to the next pair. Dialogue: 0,0:09:50.02,0:09:56.04,EN,,0,0,0,,Now if I actually wanted to construct that, what I would type into Lisp is this: Dialogue: 0,0:09:56.62,0:09:58.76,EN,,0,0,0,,I'd actually construct that as saying, well this thing is Dialogue: 0,0:09:59.22,0:10:15.28,EN,,0,0,0,,the cons of 1 onto the cons of 2 onto the cons of 3 onto the cons of 4 onto, well, this thing nil. Dialogue: 0,0:10:15.28,0:10:20.00,EN,,0,0,0,,And what nil is is a name for the end of List marker. Dialogue: 0,0:10:20.80,0:10:23.24,EN,,0,0,0,,It's a special name, which means this is the end of the List. Dialogue: 0,0:10:26.24,0:10:30.26,EN,,0,0,0,,OK, so that's how I would actually construct that. Dialogue: 0,0:10:37.54,0:10:41.40,EN,,0,0,0,,Of course, it's a terrible drag to constantly have to write something like Dialogue: 0,0:10:41.45,0:10:45.18,EN,,0,0,0,,the cons of 1 onto the cons of 2 onto the cons of 3, whenever you want to make this thing. Dialogue: 0,0:10:45.18,0:10:50.10,EN,,0,0,0,,So Lisp has an operation that's called LIST, Dialogue: 0,0:10:53.70,0:10:57.72,EN,,0,0,0,,and List is just an abbreviation for this nest of conses. Dialogue: 0,0:10:58.96,0:11:06.32,EN,,0,0,0,,So I could say, I could construct that by saying that is the List of 1, 2, 3 and 4. Dialogue: 0,0:11:07.78,0:11:11.74,EN,,0,0,0,,And all this is is another way, a piece of syntactic sugar, Dialogue: 0,0:11:11.94,0:11:14.76,EN,,0,0,0,,a more convenient way for writing that chain of conses-- Dialogue: 0,0:11:14.76,0:11:17.84,EN,,0,0,0,,cons of cons of cons of cons of cons of cons onto nil. Dialogue: 0,0:11:18.48,0:11:39.78,EN,,0,0,0,,So for example, I could build this thing and say, I'll define 1-TO-4 to be the List of 1, 2, 3 and 4. Dialogue: 0,0:11:47.96,0:11:53.02,EN,,0,0,0,,OK, well notice some of the consequences of using this convention. Dialogue: 0,0:11:53.80,0:11:56.92,EN,,0,0,0,,First of all if I have this List, this 1, 2, 3 and 4, Dialogue: 0,0:11:57.36,0:12:02.64,EN,,0,0,0,,the car of the whole thing is the first element in the List, right. Dialogue: 0,0:12:04.06,0:12:05.28,EN,,0,0,0,,How do I get 2? Dialogue: 0,0:12:05.28,0:12:23.94,EN,,0,0,0,,Well, 2 would be the car of the cdr of this thing 1-TO-4, it would be 2, right. Dialogue: 0,0:12:23.98,0:12:29.48,EN,,0,0,0,,I take this thing, I take the cdr of it, which is this much, Dialogue: 0,0:12:29.82,0:12:31.68,EN,,0,0,0,,and the car of that is 2, Dialogue: 0,0:12:32.58,0:12:47.42,EN,,0,0,0,,and then similarly, the car of the cdr of the cdr of 1-TO-4, cdr, cdr, car-- Dialogue: 0,0:12:47.42,0:12:51.36,EN,,0,0,0,,would give me 3, and so on. Dialogue: 0,0:12:52.68,0:12:55.84,EN,,0,0,0,,Let's take a look at that on the computer screen for a second. Dialogue: 0,0:12:57.50,0:13:11.18,EN,,0,0,0,,I could come up to List, and I could type define 1-TO-4 to be the List of 1, 2, 3 and 4, right. Dialogue: 0,0:13:13.78,0:13:21.28,EN,,0,0,0,,And I'll tell that to Lisp, and it says, fine, that's the definition of 1-TO-4. Dialogue: 0,0:13:22.30,0:13:36.74,EN,,0,0,0,,And I could say, for instance, what's the car of the cdr of the cdr of 1-TO-4, close paren, close paren. Dialogue: 0,0:13:38.34,0:13:42.42,EN,,0,0,0,,Right, so the car of the cdr of the cdr would be 3. Dialogue: 0,0:13:44.08,0:13:50.08,EN,,0,0,0,,Right, or I could say, what's 1-TO-4 itself. Dialogue: 0,0:13:51.26,0:13:57.22,EN,,0,0,0,,And you see what Lisp typed out is 1, 2, 3, 4, enclosed in parentheses, Dialogue: 0,0:13:57.22,0:14:02.12,EN,,0,0,0,,and this notation, typing the elements of the List enclosed in parentheses Dialogue: 0,0:14:02.12,0:14:08.90,EN,,0,0,0,,is Lisp's conventional way for printing back this chain of pairs that represents a sequence. Dialogue: 0,0:14:08.90,0:14:17.14,EN,,0,0,0,,So for example, if I said, what's the cdr of 1-TO-4, Dialogue: 0,0:14:19.30,0:14:21.12,EN,,0,0,0,,that's going to be the rest of the List. Dialogue: 0,0:14:21.32,0:14:26.96,EN,,0,0,0,,That's the thing pointed to by the first pair, which is, again, a sequence that starts off with 2. Dialogue: 0,0:14:28.52,0:14:37.74,EN,,0,0,0,,Or for example, I go off and say, what's the cdr of the cdr of 1-TO-4; Dialogue: 0,0:14:43.24,0:14:44.68,EN,,0,0,0,,then that's 3,4. Dialogue: 0,0:14:44.82,0:14:59.66,EN,,0,0,0,,Or if I say, what's the cdr of the cdr of the cdr of the cdr of 1-TO-4, Dialogue: 0,0:15:04.74,0:15:10.46,EN,,0,0,0,,and I'm down there looking at the end of List pointer itself, and Lisp prints that as just open paren, close paren. Dialogue: 0,0:15:10.96,0:15:13.48,EN,,0,0,0,,You can think of that as a List with nothing in there. Dialogue: 0,0:15:14.12,0:15:21.38,EN,,0,0,0,,All right, see at the end what I did there was I looked at the cdr of the cdr of the cdr of 1-TO-4, Dialogue: 0,0:15:21.42,0:15:25.20,EN,,0,0,0,,and I'm just left with the end of List pointer itself. Dialogue: 0,0:15:25.20,0:15:27.20,EN,,0,0,0,,And that gets printed as open close. Dialogue: 0,0:15:34.14,0:15:39.98,EN,,0,0,0,,All right, well that's a conventional way you can see for working down a List Dialogue: 0,0:15:41.50,0:15:43.44,EN,,0,0,0,,by taking successive cdrs of things. Dialogue: 0,0:15:43.44,0:15:45.00,EN,,0,0,0,,It's called cdring down a List. Dialogue: 0,0:15:46.64,0:15:49.78,EN,,0,0,0,,And of course it's pretty much of a drag to type all those cdrs by hand. Dialogue: 0,0:15:49.78,0:15:52.24,EN,,0,0,0,,You don't do that. You write procedures that do that. Dialogue: 0,0:15:52.96,0:15:59.10,EN,,0,0,0,,And in fact one very, very common thing to do in Lisp is to write procedures that, Dialogue: 0,0:15:59.85,0:16:06.54,EN,,0,0,0,,sort of, take a List of things and do something to every element in List, and return you a List of the results. Dialogue: 0,0:16:07.42,0:16:11.92,EN,,0,0,0,,So what I mean for example, is I might write a procedure called Scale-List, Dialogue: 0,0:16:16.80,0:16:25.24,EN,,0,0,0,,and Scale-List I might say I want to scale by 10 the entire List 1-TO-4, Dialogue: 0,0:16:26.66,0:16:35.32,EN,,0,0,0,,and that would return for me the List 10, 20, 30, 40. Dialogue: 0,0:16:38.25,0:16:40.25,EN,,0,0,0,,Right, it returns List, and Dialogue: 0,0:16:44.49,0:16:49.30,EN,,0,0,0,,well you can see that there's going to be some kind of recursive strategy for doing it. Dialogue: 0,0:16:49.30,0:16:51.30,EN,,0,0,0,,How would I actually write that procedure? Dialogue: 0,0:16:52.52,0:16:59.80,EN,,0,0,0,,The idea would be, well if you'd like to build up a List where you've multiplied every element by 10, Dialogue: 0,0:17:00.44,0:17:04.84,EN,,0,0,0,,what you'd say is well you imagine that you'd taken the rest of the List-- Dialogue: 0,0:17:05.86,0:17:08.42,EN,,0,0,0,,right, the thing represented by the cdr of the List, Dialogue: 0,0:17:08.42,0:17:14.16,EN,,0,0,0,,and suppose I'd already built a List where each of these was multiplied by 10-- Dialogue: 0,0:17:16.06,0:17:19.68,EN,,0,0,0,,that would be Scale-List of the cdr of the List. Dialogue: 0,0:17:20.12,0:17:23.82,EN,,0,0,0,,And then all I have to do is multiply the car of the List by 10, Dialogue: 0,0:17:24.89,0:17:27.24,EN,,0,0,0,,and then cons that onto the rest, and I'll get a List. Dialogue: 0,0:17:29.02,0:17:33.09,EN,,0,0,0,,Right and then similarly, to have scaled the cdr of the List, I'll scale the cdr of that Dialogue: 0,0:17:33.30,0:17:36.20,EN,,0,0,0,,cons onto that 2 multiplied by 10. Dialogue: 0,0:17:36.42,0:17:41.16,EN,,0,0,0,,And finally when I get all the way down to the end, and I only have this end of List pointer. Dialogue: 0,0:17:41.72,0:17:45.28,EN,,0,0,0,,All right, this thing whose name is nil-- well I just returned an end of List pointer. Dialogue: 0,0:17:45.54,0:17:47.68,EN,,0,0,0,,So there's a recursive strategy for doing that. Dialogue: 0,0:17:47.68,0:17:50.52,EN,,0,0,0,,Here's the actual procedure that does that. Dialogue: 0,0:17:50.96,0:17:55.04,EN,,0,0,0,,Right, this is an example of the general strategy of cdr-ing down a List and Dialogue: 0,0:17:55.66,0:17:58.24,EN,,0,0,0,,so called cons-ing up the result, right. Dialogue: 0,0:17:58.24,0:18:06.04,EN,,0,0,0,,So to Scale a List l by some scale factor s, what do I do? Dialogue: 0,0:18:06.04,0:18:10.40,EN,,0,0,0,,Well there's a test, and Lisp has the predicate called null. Dialogue: 0,0:18:10.40,0:18:13.22,EN,,0,0,0,,Null means is this thing the end of List pointer, Dialogue: 0,0:18:13.90,0:18:17.16,EN,,0,0,0,,or another way to think of that is are there any elements in this List, right. Dialogue: 0,0:18:18.17,0:18:23.00,EN,,0,0,0,,But in any case if I'm looking at the end of List pointer, then I just return the end of List pointer. Dialogue: 0,0:18:23.65,0:18:24.60,EN,,0,0,0,,I just return nil, Dialogue: 0,0:18:24.94,0:18:35.14,EN,,0,0,0,,otherwise I cons together the result of doing what I'm going to do to the first element in the List, Dialogue: 0,0:18:35.54,0:18:39.29,EN,,0,0,0,,namely taking the car of l and multiplying it by s, Dialogue: 0,0:18:40.36,0:18:46.34,EN,,0,0,0,,and I cons that onto recursively scaling the rest of the List. Dialogue: 0,0:18:49.98,0:18:52.18,EN,,0,0,0,,OK, so again, the general idea is that you Dialogue: 0,0:18:52.22,0:18:56.09,EN,,0,0,0,,you recursively do something to the rest of the List, to the cdr of the List, Dialogue: 0,0:18:56.48,0:19:01.16,EN,,0,0,0,,and then you cons that onto actually doing something to the first element of the List. Dialogue: 0,0:19:01.16,0:19:05.18,EN,,0,0,0,,When you get down to the end here, you return the end of List pointer, Dialogue: 0,0:19:07.34,0:19:11.36,EN,,0,0,0,,and that's a general pattern for doing something to a list. Dialogue: 0,0:19:14.05,0:19:19.52,EN,,0,0,0,,Well of course you should know by now that the very fact Dialogue: 0,0:19:19.53,0:19:22.62,EN,,0,0,0,,that there's a general pattern there means I shouldn't be writing this procedure at all. Dialogue: 0,0:19:22.62,0:19:24.90,EN,,0,0,0,,What I should do is write a procedure Dialogue: 0,0:19:24.90,0:19:26.32,EN,,0,0,0,,that's the general pattern itself Dialogue: 0,0:19:26.80,0:19:30.30,EN,,0,0,0,,that says, do something to everything in the List and define this thing in terms of that. Dialogue: 0,0:19:30.68,0:19:32.30,EN,,0,0,0,,Right, make some higher order procedure, Dialogue: 0,0:19:32.32,0:19:35.18,EN,,0,0,0,,and here's the higher order procedure that does that. It's called MAP, Dialogue: 0,0:19:36.73,0:19:43.17,EN,,0,0,0,,and what MAP does is it takes a List, takes a List l, and it takes a procedure p, Dialogue: 0,0:19:44.92,0:19:51.08,EN,,0,0,0,,and it returns the List of the elements gotten by applying p to each successive element in the List. Dialogue: 0,0:19:51.81,0:19:55.40,EN,,0,0,0,,All right, so p of e1, p of e2, p of en. Dialogue: 0,0:19:55.64,0:20:01.54,EN,,0,0,0,,Right, so I think of taking this List and transforming it by applying p to each element. Dialogue: 0,0:20:02.52,0:20:07.08,EN,,0,0,0,,And you see all this procedure is is exactly the general strategy I said. Dialogue: 0,0:20:07.08,0:20:09.08,EN,,0,0,0,,Instead of multiply by 10, it's do the procedure. Dialogue: 0,0:20:09.08,0:20:11.64,EN,,0,0,0,,If the List is empty, return nil. Dialogue: 0,0:20:11.86,0:20:16.60,EN,,0,0,0,,Otherwise, apply p to the first element of the List. Dialogue: 0,0:20:17.14,0:20:18.74,EN,,0,0,0,,Right, apply p to car of l, Dialogue: 0,0:20:19.30,0:20:25.40,EN,,0,0,0,,and cons that onto the result of applying p to everything in the cdr of the List, Dialogue: 0,0:20:25.61,0:20:28.84,EN,,0,0,0,,so that's a general procedure called MAP. Dialogue: 0,0:20:29.86,0:20:39.04,EN,,0,0,0,,And I could define Scale-List in terms of MAP. Dialogue: 0,0:20:39.04,0:20:41.04,EN,,0,0,0,,Let me show you that first. Dialogue: 0,0:20:43.46,0:20:52.50,EN,,0,0,0,,But I could say Scale-List is another way to define it is just MAP along the List by the procedure, Dialogue: 0,0:20:52.50,0:20:55.54,EN,,0,0,0,,which takes an item and multiplies it by s. Dialogue: 0,0:20:58.96,0:21:01.90,EN,,0,0,0,,Right, so this is really the way I should think about scaling the List, Dialogue: 0,0:21:02.12,0:21:07.40,EN,,0,0,0,,build that actual recursion into the general strategy, not to every particular procedure I write. Dialogue: 0,0:21:07.40,0:21:11.28,EN,,0,0,0,,And of course, one of the values of doing this is that you start to see commonality. Dialogue: 0,0:21:12.16,0:21:15.02,EN,,0,0,0,,Right, again you're capturing general patterns of usage. Dialogue: 0,0:21:15.96,0:21:31.18,EN,,0,0,0,,For instance, if I said MAP, the square procedure, down this List 1-TO-4, then I'd end up with 1, 4, 9 and 16. Dialogue: 0,0:21:32.48,0:21:37.17,EN,,0,0,0,,Right, or if I said MAP down this List, Dialogue: 0,0:21:37.57,0:21:46.32,EN,,0,0,0,,lambda of x plus x 10, if I MAP that down 1-TO-4, Dialogue: 0,0:21:49.68,0:21:52.86,EN,,0,0,0,,then I'd get the List where everything had 10 added to it: Dialogue: 0,0:21:53.34,0:21:58.17,EN,,0,0,0,,right, so I'd get 11,12, 13, 14. Dialogue: 0,0:22:00.56,0:22:05.76,EN,,0,0,0,,And you can see that's going to be a very, very common idea: doing something to every element in the List. Dialogue: 0,0:22:08.66,0:22:12.22,EN,,0,0,0,,One thing you might think about is writing MAP in an iterative style. Dialogue: 0,0:22:12.22,0:22:16.04,EN,,0,0,0,,The one I wrote happens to evolve a recursive process, Dialogue: 0,0:22:16.36,0:22:19.10,EN,,0,0,0,,but we could just as easily have made one that evolves an iterative process. Dialogue: 0,0:22:19.10,0:22:23.16,EN,,0,0,0,,But see the interesting thing about it is that once you start thinking in terms of MAP-- Dialogue: 0,0:22:24.02,0:22:29.00,EN,,0,0,0,,see, once you say scale is just MAP, you stop thinking about whether it's iterative or recursive, Dialogue: 0,0:22:29.00,0:22:31.82,EN,,0,0,0,,and you just say, well there's this aggregate, there's this List, Dialogue: 0,0:22:32.22,0:22:34.52,EN,,0,0,0,,and what I do is transform every item in the List, Dialogue: 0,0:22:34.56,0:22:38.36,EN,,0,0,0,,and I stop thinking about the particular control structure in order. Dialogue: 0,0:22:38.88,0:22:41.09,EN,,0,0,0,,That's a very, very important idea, Dialogue: 0,0:22:42.36,0:22:46.48,EN,,0,0,0,,and it, I guess it really comes out of APL. Dialogue: 0,0:22:46.48,0:22:49.10,EN,,0,0,0,,It's, sort of, the really important idea in APL Dialogue: 0,0:22:49.12,0:22:51.13,EN,,0,0,0,,that you stop thinking about control structures, Dialogue: 0,0:22:51.41,0:22:53.92,EN,,0,0,0,,and you start thinking about operations on aggregates, Dialogue: 0,0:22:55.01,0:23:00.01,EN,,0,0,0,,and then about halfway through this course,we'll see when we talk about something called stream processing, Dialogue: 0,0:23:00.26,0:23:02.64,EN,,0,0,0,,how that view of the world really comes into its glory. Dialogue: 0,0:23:02.64,0:23:05.30,EN,,0,0,0,,This is just us a, sort of, cute idea. Dialogue: 0,0:23:05.30,0:23:08.70,EN,,0,0,0,,But we'll see much more applications of that later on. Dialogue: 0,0:23:09.36,0:23:16.84,EN,,0,0,0,,Well let me mention that there's something that's very similar to MAP that's also a useful idea, and that's-- Dialogue: 0,0:23:17.56,0:23:22.54,EN,,0,0,0,,see, MAP says I take a List, I apply something to each item, Dialogue: 0,0:23:22.98,0:23:25.62,EN,,0,0,0,,and I return a List of the successive values. Dialogue: 0,0:23:25.98,0:23:28.69,EN,,0,0,0,,There's another thing I might do, which is very, very similar, Dialogue: 0,0:23:29.32,0:23:35.86,EN,,0,0,0,,which is take a List and some action you want to do and then do it to each item in the List in sequence. Dialogue: 0,0:23:36.29,0:23:39.40,EN,,0,0,0,,Don't make a List of the values, just do this particular action, Dialogue: 0,0:23:40.02,0:23:45.10,EN,,0,0,0,,and that's something that's very much like MAP. Dialogue: 0,0:23:45.10,0:23:46.02,EN,,0,0,0,,It's called for-each, Dialogue: 0,0:23:46.74,0:23:49.48,EN,,0,0,0,,and for-each takes a procedure and a List, Dialogue: 0,0:23:49.62,0:23:53.86,EN,,0,0,0,,and what it's going to do is do something to every item in the List. Dialogue: 0,0:23:55.16,0:23:58.53,EN,,0,0,0,,So basically what it does: it says if the List is not empty, Dialogue: 0,0:23:59.74,0:24:01.12,EN,,0,0,0,,if the List is not null, Dialogue: 0,0:24:01.90,0:24:06.25,EN,,0,0,0,,then what I do is, I apply my procedure to the first item in the List, Dialogue: 0,0:24:07.68,0:24:11.66,EN,,0,0,0,,and then I do this thing to the rest of the List. Dialogue: 0,0:24:12.44,0:24:15.25,EN,,0,0,0,,I apply for-each to the cdr of the List. Dialogue: 0,0:24:15.88,0:24:18.73,EN,,0,0,0,,All right, so I do it to the first of the List, do it to the rest of the List, Dialogue: 0,0:24:19.32,0:24:23.92,EN,,0,0,0,,and of course, when I call it recursively, that's going to do it to the rest of the rest of the List and so on. Dialogue: 0,0:24:23.92,0:24:28.12,EN,,0,0,0,,And finally, when I get done, I have to just do something to say I'm done, Dialogue: 0,0:24:28.16,0:24:32.40,EN,,0,0,0,,so we'll return the message "done." So that's very, very similar to MAP. Dialogue: 0,0:24:32.80,0:24:35.12,EN,,0,0,0,,It's mostly different in what it returns. Dialogue: 0,0:24:35.48,0:24:39.90,EN,,0,0,0,,And so for example, if I had some procedure that printed things on the screen, Dialogue: 0,0:24:40.56,0:24:45.81,EN,,0,0,0,,if I wanted to print everything in the List, I could say for-each, print this List. Dialogue: 0,0:24:46.78,0:24:51.33,EN,,0,0,0,,Or if I had a List of figures, and I wanted to draw them on the display, Dialogue: 0,0:24:51.62,0:24:54.86,EN,,0,0,0,,I could say for-each, display on the screen this figure. Dialogue: 0,0:24:58.18,0:24:59.32,EN,,0,0,0,,Take questions. Dialogue: 0,0:25:00.62,0:25:04.26,EN,,0,0,0,,AUDIENCE: Does it create a new copy with something done to it, Dialogue: 0,0:25:04.30,0:25:07.54,EN,,0,0,0,,unless you explicitly tell it to do that? Is that correct? Dialogue: 0,0:25:07.54,0:25:09.18,EN,,0,0,0,,PROFESSOR: Right. Ah. Dialogue: 0,0:25:09.93,0:25:10.94,EN,,0,0,0,,Yeah, that's right. Dialogue: 0,0:25:10.94,0:25:15.14,EN,,0,0,0,,For-each does not create a List. It just sort of does something. Dialogue: 0,0:25:15.14,0:25:17.29,EN,,0,0,0,,So if you have a bunch of things you want to do Dialogue: 0,0:25:18.02,0:25:21.56,EN,,0,0,0,,and you're not worried about values like printing something, or drawing something on the screen, Dialogue: 0,0:25:21.89,0:25:24.60,EN,,0,0,0,,or ringing the bell on the terminal,or for something, Dialogue: 0,0:25:24.60,0:25:27.64,EN,,0,0,0,,you can say for-each, you know, do this for-each of those things in the List, Dialogue: 0,0:25:28.21,0:25:32.42,EN,,0,0,0,,whereas MAP actually builds you this new collection of values that you might want to use. Dialogue: 0,0:25:32.42,0:25:34.16,EN,,0,0,0,,It's just a subtle difference between them. Dialogue: 0,0:25:34.16,0:25:36.30,EN,,0,0,0,,AUDIENCE: Could you write MAP using for-each, Dialogue: 0,0:25:36.32,0:25:40.16,EN,,0,0,0,,so that you did some sort of cons or something to build the List back up? Dialogue: 0,0:25:40.18,0:25:44.46,EN,,0,0,0,,PROFESSOR: Well, sort of. I mean, I probably could. Dialogue: 0,0:25:44.46,0:25:49.98,EN,,0,0,0,,I can't think of how to do it right offhand, but yeah, I could arrange something. Dialogue: 0,0:25:50.48,0:25:54.73,EN,,0,0,0,,AUDIENCE: The vital difference between MAP and for-each is one is recursive and the other is not Dialogue: 0,0:25:54.73,0:26:00.62,EN,,0,0,0,,in the sense you defined early yesterday, I believe. Dialogue: 0,0:26:01.24,0:26:03.86,EN,,0,0,0,,PROFESSOR: Yeah, about MAP and for-each and recursion. Dialogue: 0,0:26:03.86,0:26:05.48,EN,,0,0,0,,Yeah, that's a good point. Dialogue: 0,0:26:05.48,0:26:13.08,EN,,0,0,0,,For the MAP procedure I wrote, that happens to be a recursive process. Dialogue: 0,0:26:13.82,0:26:17.06,EN,,0,0,0,,And the reason for that is that when you've done this thing to the rest of the List, Dialogue: 0,0:26:17.08,0:26:20.96,EN,,0,0,0,,you're waiting for that value so that you can stick it on to the beginning of the List, Dialogue: 0,0:26:21.73,0:26:24.53,EN,,0,0,0,,whereas for-each doesn't really have any values to wait for. Dialogue: 0,0:26:24.84,0:26:26.66,EN,,0,0,0,,So that turns out to be an iterative process. Dialogue: 0,0:26:26.66,0:26:27.72,EN,,0,0,0,,That's not fundamental. Dialogue: 0,0:26:27.72,0:26:31.80,EN,,0,0,0,,I could have defined MAP so that it's evolved by an iterative process. Dialogue: 0,0:26:31.82,0:26:32.82,EN,,0,0,0,,I just didn't happen to. Dialogue: 0,0:26:34.24,0:26:42.90,EN,,0,0,0,,AUDIENCE: If you were to call for each with a List that had embedded Lists, I imagine it would work, right? Dialogue: 0,0:26:42.90,0:26:48.10,EN,,0,0,0,,It would give you the internal elements of each of those internal Lists? Dialogue: 0,0:26:48.70,0:26:50.40,EN,,0,0,0,,PROFESSOR: OK, the question is if I call Dialogue: 0,0:26:50.40,0:26:52.28,EN,,0,0,0,,for-each or map, for that matter Dialogue: 0,0:26:52.81,0:26:55.28,EN,,0,0,0,,with a List that had Lists in it Dialogue: 0,0:26:56.69,0:27:00.60,EN,,0,0,0,,although we haven't really looked at that yet--would that work. Dialogue: 0,0:27:01.02,0:27:06.56,EN,,0,0,0,,The answer is yes in the sense I mean work and no in the sense that you mean work, Dialogue: 0,0:27:06.86,0:27:10.65,EN,,0,0,0,,because all that-- see if I give you a List, Dialogue: 0,0:27:12.80,0:27:14.20,EN,,0,0,0,,where hanging off here is, Dialogue: 0,0:27:16.06,0:27:21.46,EN,,0,0,0,,you know, is something that's not a number, maybe another List or you know, another cons or something, Dialogue: 0,0:27:21.96,0:27:24.54,EN,,0,0,0,,for-each just says do something to each item in this List. Dialogue: 0,0:27:24.54,0:27:26.96,EN,,0,0,0,,It goes down successively looking at the cdrs. Dialogue: 0,0:27:26.96,0:27:27.20,EN,,0,0,0,,AUDIENCE: OK. Dialogue: 0,0:27:27.20,0:27:31.06,EN,,0,0,0,,PROFESSOR: And as far as it's concerned, the first item in this List is whatever is hanging off here. Dialogue: 0,0:27:31.06,0:27:31.65,EN,,0,0,0,,AUDIENCE: Mhm. Dialogue: 0,0:27:31.65,0:27:33.94,EN,,0,0,0,,PROFESSOR: That might or might not be the right thing. Dialogue: 0,0:27:33.94,0:27:35.57,EN,,0,0,0,,AUDIENCE: So it wouldn't go down into the-- Dialogue: 0,0:27:35.57,0:27:36.91,EN,,0,0,0,,PROFESSOR: Absolutely not. Dialogue: 0,0:27:36.91,0:27:38.51,EN,,0,0,0,,I could certainly write something else. Dialogue: 0,0:27:38.51,0:27:42.97,EN,,0,0,0,,There's another, what you're looking for is a common pattern of usage called tree recursion, Dialogue: 0,0:27:43.01,0:27:47.94,EN,,0,0,0,,where you take a List, and you actually go all the way down to the what's called the leaves of the tree. Dialogue: 0,0:27:47.94,0:27:51.05,EN,,0,0,0,,And you could write such a thing, but that's not for-each and it's not MAP. Dialogue: 0,0:27:52.42,0:27:55.05,EN,,0,0,0,,Remember, these things are really being very simple minded. Dialogue: 0,0:27:55.77,0:27:56.89,EN,,0,0,0,,OK, no more questions? Dialogue: 0,0:27:57.68,0:27:58.57,EN,,0,0,0,,All right, let's break. Dialogue: 0,0:27:59.11,0:28:10.99,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:28:11.46,0:28:14.29,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:28:14.32,0:28:17.52,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:28:27.38,0:28:34.22,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:28:34.86,0:28:38.58,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson Escher Example Dialogue: 0,0:28:41.94,0:28:48.65,EN,,0,0,0,,PROFESSOR: What I'd like to do now is spend the rest of this time talking about one example, Dialogue: 0,0:28:50.04,0:28:53.92,EN,,0,0,0,,and this example, I think, pretty much summarizes everything that we've done up until now: Dialogue: 0,0:28:54.74,0:28:56.29,EN,,0,0,0,,all right, and that's List structure Dialogue: 0,0:28:57.17,0:28:59.48,EN,,0,0,0,,and issues of abstraction, Dialogue: 0,0:28:59.54,0:29:00.82,EN,,0,0,0,,and representation Dialogue: 0,0:29:01.60,0:29:04.60,EN,,0,0,0,,and representation and capturing commonality with higher order procedures, Dialogue: 0,0:29:04.60,0:29:09.80,EN,,0,0,0,,and also is going to introduce something we haven't really talked about a lot yet-- what I said is the major third theme in this course: Dialogue: 0,0:29:09.85,0:29:13.46,EN,,0,0,0,,what I said is the major third theme in this course: Dialogue: 0,0:29:13.96,0:29:15.53,EN,,0,0,0,,meta-linguistic abstraction, Dialogue: 0,0:29:15.54,0:29:21.90,EN,,0,0,0,,which is the idea that one of the ways of tackling complexity in engineering design Dialogue: 0,0:29:22.86,0:29:25.80,EN,,0,0,0,,is to build a suitable powerful language. Dialogue: 0,0:29:28.17,0:29:34.74,EN,,0,0,0,,You might recall what I said was pretty much the very most important thing that we're going to tell you in this course is that Dialogue: 0,0:29:34.74,0:29:41.17,EN,,0,0,0,,when you think about a language, you think about it in terms of what are the primitives; Dialogue: 0,0:29:42.98,0:29:46.69,EN,,0,0,0,,what are the means of combination-- Dialogue: 0,0:29:49.72,0:29:52.80,EN,,0,0,0,,right, what are the things that allow you to build bigger things; Dialogue: 0,0:29:53.61,0:29:55.24,EN,,0,0,0,,and then what are the means of abstraction. Dialogue: 0,0:30:00.97,0:30:05.16,EN,,0,0,0,,How do you take those bigger things that you've built Dialogue: 0,0:30:05.56,0:30:07.97,EN,,0,0,0,,put black boxes around them Dialogue: 0,0:30:08.45,0:30:11.71,EN,,0,0,0,,and use them as elements in making something even more complicated? Dialogue: 0,0:30:13.53,0:30:18.72,EN,,0,0,0,,Now the particular language I'm going to talk about is an example Dialogue: 0,0:30:18.73,0:30:22.70,EN,,0,0,0,,that was made up by a friend of ours called Peter Henderson. Dialogue: 0,0:30:28.24,0:30:31.74,EN,,0,0,0,,Peter Henderson is at the University of Stirling in Scotland. Dialogue: 0,0:30:32.78,0:30:40.98,EN,,0,0,0,,And what this language is about is making figures that sort of look like this. Dialogue: 0,0:30:41.86,0:30:46.66,EN,,0,0,0,,This is this is a woodcut by Escher called "Square Limit." Dialogue: 0,0:30:49.33,0:30:57.94,EN,,0,0,0,,You, sort of, see it has this complicated, kind of, recursive, sort of, recursive kind of figure, Dialogue: 0,0:30:58.84,0:31:01.46,EN,,0,0,0,,where there's this fish pattern in the middle and things sort of Dialogue: 0,0:31:01.70,0:31:04.56,EN,,0,0,0,,bleed out smaller and smaller in self similar ways. Dialogue: 0,0:31:08.49,0:31:12.80,EN,,0,0,0,,Anyway, Peter Henderson's language was for describing figures that look like that Dialogue: 0,0:31:13.37,0:31:18.28,EN,,0,0,0,,and designing new ones that look like that and drawing them on a display screen. Dialogue: 0,0:31:20.24,0:31:27.48,EN,,0,0,0,,There's another theme that we'll see illustrated by this example, Dialogue: 0,0:31:28.09,0:31:32.02,EN,,0,0,0,,and that's the issue of what Gerry and I have already mentioned a lot: Dialogue: 0,0:31:32.02,0:31:36.17,EN,,0,0,0,,that there's no real difference, in some sense, between procedures and data. Dialogue: 0,0:31:37.26,0:31:42.40,EN,,0,0,0,,And anyway I hope by the end of this morning, if you're not already, Dialogue: 0,0:31:42.58,0:31:47.60,EN,,0,0,0,,you will be completely confused about what the difference between procedures and data are, Dialogue: 0,0:31:47.96,0:31:49.58,EN,,0,0,0,,if you're not confused about that already. Dialogue: 0,0:31:50.80,0:31:55.28,EN,,0,0,0,,Well in any case, let's start describing Peter's language. Dialogue: 0,0:31:55.28,0:31:57.26,EN,,0,0,0,,I should start by telling you what the primitives are. Dialogue: 0,0:31:58.29,0:32:00.92,EN,,0,0,0,,This language is very simple because there's only one primitive. Dialogue: 0,0:32:03.33,0:32:06.30,EN,,0,0,0,,A primitive is not quite what you think it is. Dialogue: 0,0:32:07.08,0:32:09.18,EN,,0,0,0,,There's only one primitive called a picture, Dialogue: 0,0:32:09.70,0:32:12.11,EN,,0,0,0,,and a picture is not quite what you think it is. Dialogue: 0,0:32:12.11,0:32:14.17,EN,,0,0,0,,Here's an example. Dialogue: 0,0:32:14.17,0:32:15.17,EN,,0,0,0,,This is a picture of George. Dialogue: 0,0:32:19.01,0:32:20.37,EN,,0,0,0,,The idea is that Dialogue: 0,0:32:22.33,0:32:24.57,EN,,0,0,0,,a picture in this language is going to be something Dialogue: 0,0:32:24.89,0:32:31.46,EN,,0,0,0,,that draws a figure scaled to fit a rectangle that you specify. Dialogue: 0,0:32:33.00,0:32:34.42,EN,,0,0,0,,So here you see emphasis line Dialogue: 0,0:32:34.42,0:32:37.70,EN,,0,0,0,,is outline of a rectangle, that's not really part of the picture, Dialogue: 0,0:32:40.49,0:32:47.17,EN,,0,0,0,,but the picture-- you'll give it a rectangle, and it will draw this figure scaled to fit the rectangle. Dialogue: 0,0:32:47.17,0:32:52.16,EN,,0,0,0,,So for example, there's George, and here, this is also George. Dialogue: 0,0:32:53.21,0:32:56.65,EN,,0,0,0,,It's the same picture, right, just scaled to fit a different rectangle. Dialogue: 0,0:32:57.40,0:32:59.28,EN,,0,0,0,,Here's George as a fat kid. Dialogue: 0,0:33:00.01,0:33:03.44,EN,,0,0,0,,That's the same George. Dialogue: 0,0:33:03.81,0:33:05.14,EN,,0,0,0,,It's all the same figure. Dialogue: 0,0:33:05.14,0:33:09.57,EN,,0,0,0,,All of these three things are the same picture in this language. Dialogue: 0,0:33:09.58,0:33:13.04,EN,,0,0,0,,I'm just giving it different rectangles to scale itself in. Dialogue: 0,0:33:16.08,0:33:20.65,EN,,0,0,0,,OK, those are the primitives. That is the primitive. Dialogue: 0,0:33:21.44,0:33:25.25,EN,,0,0,0,,Now let's start talking about the means of combination and the operations. Dialogue: 0,0:33:25.90,0:33:30.17,EN,,0,0,0,,There is, for example, an operation called Rotate. Dialogue: 0,0:33:31.09,0:33:33.66,EN,,0,0,0,,And what Rotate does is, if I have a picture, Dialogue: 0,0:33:35.37,0:33:39.93,EN,,0,0,0,,say a picture that draws an "A" in some rectangle that I give it, Dialogue: 0,0:33:41.84,0:33:45.73,EN,,0,0,0,,the Rotate of that--say the Rotate by 90 degrees would, Dialogue: 0,0:33:47.02,0:33:50.65,EN,,0,0,0,,if I give it a rectangle, draw the same image, Dialogue: 0,0:33:50.65,0:33:53.88,EN,,0,0,0,,but again, scaled to fit that rectangle. Dialogue: 0,0:33:56.11,0:33:58.34,EN,,0,0,0,,So that's Rotate by 90 degrees. Dialogue: 0,0:33:58.34,0:34:03.20,EN,,0,0,0,,There's another operation called Flip that can flip something, either horizontally or vertically. Dialogue: 0,0:34:04.77,0:34:06.00,EN,,0,0,0,,All right, so those are, sort of, operations, Dialogue: 0,0:34:06.01,0:34:10.40,EN,,0,0,0,,or you can think of those as means of combination of one element. Dialogue: 0,0:34:10.89,0:34:12.42,EN,,0,0,0,,I can put things together. Dialogue: 0,0:34:13.44,0:34:15.54,EN,,0,0,0,,There's a means of combination called Beside, Dialogue: 0,0:34:16.46,0:34:24.78,EN,,0,0,0,,and what Beside does: it'll take two pictures, let's say A and B-- Dialogue: 0,0:34:29.02,0:34:33.25,EN,,0,0,0,,and by picture I mean something that's going to draw an image in a specified rectangle-- Dialogue: 0,0:34:34.05,0:34:36.51,EN,,0,0,0,,and what Beside will do-- Dialogue: 0,0:34:37.85,0:34:44.08,EN,,0,0,0,,I have to say, Beside of A and B, the side of two pictures and some number, s. Dialogue: 0,0:34:45.34,0:34:48.08,EN,,0,0,0,,And s will be a number between zero and one. Dialogue: 0,0:34:50.51,0:34:52.57,EN,,0,0,0,,And Beside will draw a picture that looks like this. Dialogue: 0,0:34:52.57,0:34:56.71,EN,,0,0,0,,It will take the rectangle you give it and scale its base by s. Dialogue: 0,0:34:56.71,0:34:58.71,EN,,0,0,0,,Say s is 0.5. Dialogue: 0,0:35:00.18,0:35:07.17,EN,,0,0,0,,And then over here it will draw-- it'll put the first picture, and over here it'll put the second picture. Dialogue: 0,0:35:07.81,0:35:12.65,EN,,0,0,0,,and over here it'll put the second picture. Dialogue: 0,0:35:13.82,0:35:16.44,EN,,0,0,0,,Or for instance if I gave it a different value of s, Dialogue: 0,0:35:16.81,0:35:23.02,EN,,0,0,0,,Or for instance if I gave it a different value of s, if I said Beside with a 0.25, Dialogue: 0,0:35:25.94,0:35:29.09,EN,,0,0,0,,it would do the same thing, except the A would be much skinnier. Dialogue: 0,0:35:34.05,0:35:36.28,EN,,0,0,0,,So it would draw something like that. Dialogue: 0,0:35:37.82,0:35:40.29,EN,,0,0,0,,So there's a means of combination Beside, Dialogue: 0,0:35:40.68,0:35:46.05,EN,,0,0,0,,and similarly there's an Above, which does the same thing except it puts them vertically instead of horizontally. Dialogue: 0,0:35:47.84,0:35:48.89,EN,,0,0,0,,Well let's look at that. Dialogue: 0,0:35:50.74,0:35:56.00,EN,,0,0,0,,All right, there's George and his kid brother, Dialogue: 0,0:35:56.72,0:36:07.05,EN,,0,0,0,,which is, right, constructed by taking George and putting him Beside Dialogue: 0,0:36:10.36,0:36:14.42,EN,,0,0,0,,The Above, taking the empty picture, and there's a thing called the empty picture, Dialogue: 0,0:36:14.52,0:36:16.14,EN,,0,0,0,,which does the obvious thing-- Dialogue: 0,0:36:16.14,0:36:19.14,EN,,0,0,0,,putting the empty picture above a copy of George, Dialogue: 0,0:36:19.14,0:36:21.14,EN,,0,0,0,,and then putting that whole thing Beside George. Dialogue: 0,0:36:28.96,0:36:30.34,EN,,0,0,0,,Here's something called P which is, Dialogue: 0,0:36:31.10,0:36:39.04,EN,,0,0,0,,which is, again, George Beside Flipping George, Dialogue: 0,0:36:40.53,0:36:42.08,EN,,0,0,0,,I think, horizontally in this case, Dialogue: 0,0:36:42.37,0:36:44.80,EN,,0,0,0,,Rotating the whole result 180 degrees Dialogue: 0,0:36:45.80,0:36:50.82,EN,,0,0,0,,putting them Beside one another with the basic rectangle divided at 0.5, Dialogue: 0,0:36:52.56,0:36:53.90,EN,,0,0,0,,right, and I can call that P. Dialogue: 0,0:36:55.90,0:36:57.88,EN,,0,0,0,,And then I can take P, Dialogue: 0,0:36:59.21,0:37:04.96,EN,,0,0,0,,And then I can take P, and put it above the Flipped copy of itself, and I can call that Q. Dialogue: 0,0:37:09.20,0:37:13.26,EN,,0,0,0,,Notice how rapidly that we've built up complexity, Dialogue: 0,0:37:14.36,0:37:21.05,EN,,0,0,0,,just in, you know, 15 seconds, you've gotten from George to that thing Q. Why is that? Dialogue: 0,0:37:22.05,0:37:24.55,EN,,0,0,0,,How are how we able to do that so fast? Dialogue: 0,0:37:25.85,0:37:28.02,EN,,0,0,0,,The answer is the closure property. Dialogue: 0,0:37:28.69,0:37:32.98,EN,,0,0,0,,See, it's the fact that when I take a picture and put it Beside another picture, Dialogue: 0,0:37:34.30,0:37:35.29,EN,,0,0,0,,that's then, again, a picture Dialogue: 0,0:37:35.33,0:37:37.78,EN,,0,0,0,,that I can go and Rotate and Flip or put Above something else. Dialogue: 0,0:37:39.17,0:37:40.88,EN,,0,0,0,,Right, and when I take that element P, Dialogue: 0,0:37:40.89,0:37:44.88,EN,,0,0,0,,which is the Beside or the Flip or the Rotate of something, that's, again, a picture. Dialogue: 0,0:37:45.22,0:37:50.20,EN,,0,0,0,,Right, the world of pictures is closed under those means of combination. Dialogue: 0,0:37:50.77,0:37:52.24,EN,,0,0,0,,So whenever I have something, Dialogue: 0,0:37:52.48,0:37:55.17,EN,,0,0,0,,I can turn right around and use that as an element in something else. Dialogue: 0,0:37:56.33,0:37:58.52,EN,,0,0,0,,So maybe better than List and segments, Dialogue: 0,0:37:58.54,0:38:03.28,EN,,0,0,0,,that just gives you an image for how fast you can build up complexity, because operations are closed. Dialogue: 0,0:38:07.48,0:38:12.02,EN,,0,0,0,,OK, well before we go on with building more things, Dialogue: 0,0:38:12.04,0:38:14.77,EN,,0,0,0,,let's talk about how this language is actually implemented. Dialogue: 0,0:38:16.91,0:38:21.50,EN,,0,0,0,,The basic element that sits under the table here Dialogue: 0,0:38:21.93,0:38:24.52,EN,,0,0,0,,is a thing called a rectangle, Dialogue: 0,0:38:26.09,0:38:28.28,EN,,0,0,0,,and what a rectangle is going to be, Dialogue: 0,0:38:28.28,0:38:33.68,EN,,0,0,0,,it's a thing that specified by an origin Dialogue: 0,0:38:36.45,0:38:40.18,EN,,0,0,0,,that's going to be some vector that says where the rectangle starts. Dialogue: 0,0:38:40.18,0:38:42.29,EN,,0,0,0,,And then there's going to be some other vector Dialogue: 0,0:38:43.66,0:38:46.33,EN,,0,0,0,,that I'm going to call the horizontal part of the rectangle, Dialogue: 0,0:38:55.76,0:38:59.25,EN,,0,0,0,,and another vector called the vertical part of the rectangle. Dialogue: 0,0:39:00.49,0:39:02.68,EN,,0,0,0,,And those three pieces are the elements: Dialogue: 0,0:39:02.68,0:39:04.51,EN,,0,0,0,,where the lower vertex is, Dialogue: 0,0:39:04.93,0:39:09.97,EN,,0,0,0,,how you get to the next vertex over here, and how you get to the vertex over there. Dialogue: 0,0:39:09.97,0:39:12.37,EN,,0,0,0,,The three vectors specify a rectangle. Dialogue: 0,0:39:16.00,0:39:18.93,EN,,0,0,0,,Now to actually build rectangles, what I'll assume is Dialogue: 0,0:39:19.77,0:39:22.06,EN,,0,0,0,,that we have a constructor called "make rectangle," Dialogue: 0,0:39:23.01,0:39:24.26,EN,,0,0,0,,or "make-rect," Dialogue: 0,0:39:27.56,0:39:35.17,EN,,0,0,0,,and selectors for horiz and vert and origin Dialogue: 0,0:39:37.58,0:39:39.65,EN,,0,0,0,,that get out the pieces of that rectangle. Dialogue: 0,0:39:39.65,0:39:42.54,EN,,0,0,0,,And well, you know a lot of ways you can do this now. Dialogue: 0,0:39:42.54,0:39:47.62,EN,,0,0,0,,You can do it by using pairs in some way or other standard List or not. Dialogue: 0,0:39:47.62,0:39:51.40,EN,,0,0,0,,But in any case, the implementation of these things, that's George's problem. Dialogue: 0,0:39:51.40,0:39:53.17,EN,,0,0,0,,It's just a data representation problem. Dialogue: 0,0:39:53.17,0:39:55.47,EN,,0,0,0,,So let's assume we have these rectangles to work with. Dialogue: 0,0:39:59.05,0:40:05.08,EN,,0,0,0,,OK. Now the idea of this, remember what's got to happen. Dialogue: 0,0:40:05.08,0:40:08.22,EN,,0,0,0,,Somehow we have to worry about taking the figure Dialogue: 0,0:40:09.33,0:40:12.97,EN,,0,0,0,,and scaling it to fit some rectangle that you give it, Dialogue: 0,0:40:13.60,0:40:16.60,EN,,0,0,0,,that's the basic thing you have to arrange, Dialogue: 0,0:40:16.60,0:40:18.60,EN,,0,0,0,,that these pictures can do. Dialogue: 0,0:40:22.22,0:40:23.65,EN,,0,0,0,,How do we think about that? Dialogue: 0,0:40:23.65,0:40:27.08,EN,,0,0,0,,Well, one way to think about that is that any time I give you a rectangle, Dialogue: 0,0:40:35.68,0:40:38.68,EN,,0,0,0,,Any time I gave you a rectangle, that defines, Dialogue: 0,0:40:39.25,0:40:45.77,EN,,0,0,0,,that defines,in some sense, a transformation from the standard square into that rectangle. Dialogue: 0,0:40:45.77,0:40:46.54,EN,,0,0,0,,Let me say what I mean. Dialogue: 0,0:40:46.54,0:40:48.53,EN,,0,0,0,,By the standard square, I'll mean something, Dialogue: 0,0:40:49.04,0:40:59.04,EN,,0,0,0,,which is a square whose coordinates are 0,0, and 1,0, and 0,1 and 1,1. Dialogue: 0,0:41:01.40,0:41:05.72,EN,,0,0,0,,And there's some sort of the obvious scaling transformation, Dialogue: 0,0:41:06.12,0:41:10.22,EN,,0,0,0,,which maps this to that and this to that, Dialogue: 0,0:41:10.24,0:41:12.08,EN,,0,0,0,,and sort of, stretches everything uniformly. Dialogue: 0,0:41:12.17,0:41:18.25,EN,,0,0,0,,So we take a line segment like this Dialogue: 0,0:41:19.73,0:41:24.20,EN,,0,0,0,,and end up mapping it to a line segment like that, Dialogue: 0,0:41:26.20,0:41:32.68,EN,,0,0,0,,so some point (x,y) goes to some other point up there. Dialogue: 0,0:41:32.68,0:41:39.37,EN,,0,0,0,,And although it's not important, with a little vector algebra, you could write that formula. Dialogue: 0,0:41:39.37,0:41:43.18,EN,,0,0,0,,The thing that (x,y) goes to, the point that (x,y) goes to is Dialogue: 0,0:41:43.58,0:41:50.74,EN,,0,0,0,,gotten by taking the origin of the rectangle and then adding that as a vector to-- Dialogue: 0,0:41:51.16,0:41:55.48,EN,,0,0,0,,well, take x, the x coordinate, which is something between zero and one, Dialogue: 0,0:41:55.98,0:42:01.84,EN,,0,0,0,,multiply that by the horizontal vector of the rectangle; Dialogue: 0,0:42:07.62,0:42:11.00,EN,,0,0,0,,and take the y coordinate, which is also something between zero and one Dialogue: 0,0:42:11.38,0:42:16.28,EN,,0,0,0,,and multiply that by the vertical vector of the rectangle. Dialogue: 0,0:42:16.74,0:42:19.31,EN,,0,0,0,,That's just a little linear algebra. Dialogue: 0,0:42:19.31,0:42:23.48,EN,,0,0,0,,Anyway, that's the formula, which is the right obvious transformation Dialogue: 0,0:42:23.69,0:42:28.18,EN,,0,0,0,,that takes things into the unit square, into the interior of that rectangle. Dialogue: 0,0:42:31.34,0:42:34.02,EN,,0,0,0,,OK well, let's actually look at that as a procedure. Dialogue: 0,0:42:35.16,0:42:36.29,EN,,0,0,0,,So what we want is Dialogue: 0,0:42:37.80,0:42:40.82,EN,,0,0,0,,the thing which tells us that particular transformation Dialogue: 0,0:42:41.01,0:42:42.52,EN,,0,0,0,,that a rectangle defines. Dialogue: 0,0:42:43.80,0:42:45.22,EN,,0,0,0,,So here's the procedure. Dialogue: 0,0:42:45.22,0:42:47.22,EN,,0,0,0,,I'll call it coordinate-map. Dialogue: 0,0:42:47.77,0:42:52.00,EN,,0,0,0,,Coordinate-map is the thing that takes as its argument a rectangle Dialogue: 0,0:42:53.60,0:42:57.85,EN,,0,0,0,,and returns for you a procedure on points. Dialogue: 0,0:43:00.45,0:43:06.82,EN,,0,0,0,,Right, so for each rectangle you get a way of transforming a point (x,y) into that rectangle. Dialogue: 0,0:43:06.82,0:43:08.02,EN,,0,0,0,,And how do you get it? Dialogue: 0,0:43:08.02,0:43:10.92,EN,,0,0,0,,Well I just-- writing in Lisp what I wrote there on the blackboard-- Dialogue: 0,0:43:10.92,0:43:16.01,EN,,0,0,0,,I add to the origin of the rectangle Dialogue: 0,0:43:20.22,0:43:25.02,EN,,0,0,0,,the result of adding-- I take the horizontal part of the rectangle; Dialogue: 0,0:43:25.02,0:43:27.68,EN,,0,0,0,,I scale that by the x coordinate of the point. Dialogue: 0,0:43:29.65,0:43:32.62,EN,,0,0,0,,I take the vertical vector of the rectangle. Dialogue: 0,0:43:33.51,0:43:37.14,EN,,0,0,0,,I scale that by the y coordinate of the point, Dialogue: 0,0:43:37.14,0:43:39.14,EN,,0,0,0,,and then add all those three things up. Dialogue: 0,0:43:40.13,0:43:41.34,EN,,0,0,0,,That's the procedure. Dialogue: 0,0:43:41.34,0:43:44.54,EN,,0,0,0,,That is the procedure that I'm going to apply to a point. Dialogue: 0,0:43:46.54,0:43:52.17,EN,,0,0,0,,And this whole thing is generated for each rectangle. Dialogue: 0,0:43:52.17,0:43:57.25,EN,,0,0,0,,So any rectangle defines a Coordinate-MAP, which is a procedure on points. Dialogue: 0,0:44:06.66,0:44:10.42,EN,,0,0,0,,All right, so for example, George here, Dialogue: 0,0:44:11.36,0:44:16.34,EN,,0,0,0,,my original George, might have been something that I specified by segments in the unit square, Dialogue: 0,0:44:19.50,0:44:21.96,EN,,0,0,0,,and then for each rectangle I give this thing, Dialogue: 0,0:44:24.14,0:44:28.17,EN,,0,0,0,,I'm going to draw those segments inside that rectangle. Dialogue: 0,0:44:28.17,0:44:29.88,EN,,0,0,0,,How actually do I do that? Dialogue: 0,0:44:30.68,0:44:36.94,EN,,0,0,0,,Well I take each segment in my original reference George that was specified, Dialogue: 0,0:44:38.64,0:44:40.58,EN,,0,0,0,,and to each of the end points of those segments, Dialogue: 0,0:44:40.88,0:44:44.45,EN,,0,0,0,,I applied the COORDINATE-MAP of the particular rectangle I want to draw it in. Dialogue: 0,0:44:44.45,0:44:46.06,EN,,0,0,0,,So for example, this lower rectangle, Dialogue: 0,0:44:46.66,0:44:50.88,EN,,0,0,0,,this George as a fat kid rectangle, has its COORDINATE-MAP. Dialogue: 0,0:44:51.25,0:44:53.69,EN,,0,0,0,,And if I want to draw this image, Dialogue: 0,0:44:55.38,0:44:57.92,EN,,0,0,0,,And if I want to draw this image, what I do is for each segment here, say for this segment, Dialogue: 0,0:44:59.29,0:45:05.34,EN,,0,0,0,,I transformed that point by the coordinate MAP, transform that point by the coordinate MAP. Dialogue: 0,0:45:05.34,0:45:07.09,EN,,0,0,0,,That will give me this point and that point Dialogue: 0,0:45:07.38,0:45:08.94,EN,,0,0,0,,and draw the segment between them. Dialogue: 0,0:45:09.71,0:45:11.52,EN,,0,0,0,,Right, that's the idea. Dialogue: 0,0:45:12.66,0:45:14.78,EN,,0,0,0,,Right, and if I give it a different rectangle like this one, Dialogue: 0,0:45:14.80,0:45:15.76,EN,,0,0,0,,that's a different coordinate-MAP, Dialogue: 0,0:45:15.79,0:45:17.84,EN,,0,0,0,,so I get a different image of those line segments. Dialogue: 0,0:45:19.28,0:45:22.14,EN,,0,0,0,,Well how do we actually get a picture to start with? Dialogue: 0,0:45:22.14,0:45:26.52,EN,,0,0,0,,I can build a picture to start with out of a List of line segments initially. Dialogue: 0,0:45:27.61,0:45:32.20,EN,,0,0,0,,Here's a procedure that builds what I'll call a primitive picture, Dialogue: 0,0:45:33.48,0:45:37.17,EN,,0,0,0,,meaning one I, sort of, got that didn't come out of Beside or Rotate or something. Dialogue: 0,0:45:37.52,0:45:39.60,EN,,0,0,0,,It starts with a List of line segments, Dialogue: 0,0:45:42.94,0:45:44.04,EN,,0,0,0,,And now it does what I said. Dialogue: 0,0:45:44.04,0:45:45.58,EN,,0,0,0,,What's a picture have to be? Dialogue: 0,0:45:45.58,0:45:49.44,EN,,0,0,0,,First of all it's a procedure that's defined on rectangles. Dialogue: 0,0:45:51.70,0:45:53.00,EN,,0,0,0,,What does it do? Dialogue: 0,0:45:53.00,0:45:56.56,EN,,0,0,0,,It says for each-- this is going to be a List of line segments-- Dialogue: 0,0:45:57.66,0:46:03.38,EN,,0,0,0,,for each segment, for each s, which is a segment in this List of segments, Dialogue: 0,0:46:05.89,0:46:07.30,EN,,0,0,0,,well it draws a line. Dialogue: 0,0:46:07.30,0:46:08.82,EN,,0,0,0,,What line does it draw? Dialogue: 0,0:46:10.60,0:46:12.84,EN,,0,0,0,,It gets the start point of that segment, Dialogue: 0,0:46:15.22,0:46:17.94,EN,,0,0,0,,transforms that by the coordinate MAP of the rectangle. Dialogue: 0,0:46:19.54,0:46:21.76,EN,,0,0,0,,That's the first new point it wants to do. Dialogue: 0,0:46:21.76,0:46:26.32,EN,,0,0,0,,Then it takes the endpoint of the segment, transforms that by the coordinate MAP of the rectangle, Dialogue: 0,0:46:26.69,0:46:27.92,EN,,0,0,0,,and then draws a line between. Dialogue: 0,0:46:27.92,0:46:30.84,EN,,0,0,0,,Let's assume drawline is some primitive that's built into the system Dialogue: 0,0:46:31.09,0:46:33.22,EN,,0,0,0,,that actually draws a line on the display. Dialogue: 0,0:46:33.96,0:46:37.10,EN,,0,0,0,,All right, so it transforms the endpoints by the coordinate MAP of the rectangle, Dialogue: 0,0:46:37.13,0:46:38.20,EN,,0,0,0,,draws a line between them, Dialogue: 0,0:46:39.61,0:46:44.12,EN,,0,0,0,,does that for each s in this List of segments. Dialogue: 0,0:46:45.96,0:46:51.40,EN,,0,0,0,,And now remember again, a picture is a procedure that takes a rectangle as argument. Dialogue: 0,0:46:51.40,0:46:55.65,EN,,0,0,0,,So when you hand it a rectangle, this is what it does: draws those lines. Dialogue: 0,0:46:57.17,0:47:01.10,EN,,0,0,0,,All right, so there's-- how would I actually use this thing? Dialogue: 0,0:47:01.22,0:47:04.08,EN,,0,0,0,,Let's make it a little bit more concrete. Dialogue: 0,0:47:05.60,0:47:24.22,EN,,0,0,0,,Right, I would say for instance, define R to be make-rectangle of some stuff, Dialogue: 0,0:47:24.50,0:47:28.66,EN,,0,0,0,,and I'd have to specify some vectors here using make-vector. Dialogue: 0,0:47:29.84,0:47:46.18,EN,,0,0,0,,And then I could say, define say, G to be make-picture, and then some stuff. Dialogue: 0,0:47:46.68,0:47:55.28,EN,,0,0,0,,And what I'd have to specify here is a List of line segments, right, using make segment. Dialogue: 0,0:47:55.28,0:47:58.70,EN,,0,0,0,,Make-segment might be made out of vectors, and vectors might be made out of points. Dialogue: 0,0:47:59.50,0:48:04.60,EN,,0,0,0,,And then if I actually wanted to see the image of G inside a rectangle, Dialogue: 0,0:48:04.65,0:48:11.72,EN,,0,0,0,,well a picture is a procedure that takes a rectangle as argument. Dialogue: 0,0:48:12.06,0:48:16.37,EN,,0,0,0,,So if I then called G with an input of R, Dialogue: 0,0:48:17.96,0:48:23.25,EN,,0,0,0,,that would cause whatever image G is worrying about to be drawn inside the rectangle R. Dialogue: 0,0:48:23.62,0:48:25.62,EN,,0,0,0,,Right, so that's how you'd use that. Dialogue: 0,0:48:26.86,0:48:36.29,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:48:36.29,0:48:39.78,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:48:39.82,0:48:43.54,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:48:51.28,0:48:55.45,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:48:55.50,0:48:58.73,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:48:59.34,0:49:03.02,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson Escher Example Dialogue: 0,0:49:07.72,0:49:12.48,EN,,0,0,0,,PROFESSOR: Well why is it that I say this example is nice? Dialogue: 0,0:49:12.48,0:49:13.74,EN,,0,0,0,,You probably don't think it's nice. Dialogue: 0,0:49:13.74,0:49:15.42,EN,,0,0,0,,You probably think it's more weird than nice. Dialogue: 0,0:49:15.42,0:49:20.92,EN,,0,0,0,,Right, representing these pictures as procedures, which do complicated things with rectangles. Dialogue: 0,0:49:20.92,0:49:22.72,EN,,0,0,0,,So why is it nice? Dialogue: 0,0:49:25.36,0:49:26.69,EN,,0,0,0,,The reason it's nice Dialogue: 0,0:49:27.22,0:49:30.40,EN,,0,0,0,,is that once you've implemented the primitives in this way, Dialogue: 0,0:49:30.97,0:49:35.20,EN,,0,0,0,,the means of combination just fall out by implementing procedures. Dialogue: 0,0:49:35.98,0:49:37.48,EN,,0,0,0,,Let me show you what I mean. Dialogue: 0,0:49:37.48,0:49:39.02,EN,,0,0,0,,Suppose we want to implement Beside. Dialogue: 0,0:49:41.56,0:49:47.36,EN,,0,0,0,,So I'd like to-- suppose I've got a picture. Let's call it P1. Dialogue: 0,0:49:47.36,0:49:50.62,EN,,0,0,0,,P1 is going to be-- and now remember what a picture really is. Dialogue: 0,0:49:50.62,0:49:54.82,EN,,0,0,0,,It's a thing that if you hand it some rectangle, Dialogue: 0,0:49:56.52,0:50:01.46,EN,,0,0,0,,it will cause an image to be drawn in whatever rectangle you hand it. Dialogue: 0,0:50:03.46,0:50:09.26,EN,,0,0,0,,And suppose P2 two is some other picture, and you hand that a rectangle. Dialogue: 0,0:50:09.74,0:50:12.44,EN,,0,0,0,,And whatever rectangle you hand it, it draws some picture. Dialogue: 0,0:50:14.84,0:50:26.60,EN,,0,0,0,,And now if I'd like to implement Beside of P1 and P2 with a scale factor A, Dialogue: 0,0:50:27.04,0:50:28.38,EN,,0,0,0,,well what does that have to be? Dialogue: 0,0:50:28.38,0:50:29.34,EN,,0,0,0,,That's gotta be a picture. Dialogue: 0,0:50:29.92,0:50:33.88,EN,,0,0,0,,It's gotta be a thing that you handed a rectangle and draw something in that rectangle. Dialogue: 0,0:50:34.77,0:50:37.18,EN,,0,0,0,,So if hand Beside this rectangle-- Dialogue: 0,0:50:38.58,0:50:40.12,EN,,0,0,0,,let's hand it a rectangle. Dialogue: 0,0:50:41.50,0:50:42.74,EN,,0,0,0,,Well what's it going to do? Dialogue: 0,0:50:42.76,0:50:46.36,EN,,0,0,0,,It's going to take this rectangle and split it into two Dialogue: 0,0:50:49.29,0:50:51.57,EN,,0,0,0,,at a ratio of A and one minus A. Dialogue: 0,0:50:52.65,0:50:55.12,EN,,0,0,0,,And it will say, oh sure, now I've got two rectangles. Dialogue: 0,0:51:02.34,0:51:06.54,EN,,0,0,0,,And now it goes off to P1 and says P1, well draw yourself in this rectangle, Dialogue: 0,0:51:07.36,0:51:11.64,EN,,0,0,0,,and goes off to P2, and says, P2, fine, draw yourself in this rectangle. Dialogue: 0,0:51:13.28,0:51:16.88,EN,,0,0,0,,The only computation it has to do is figure out what these rectangles are. Dialogue: 0,0:51:17.36,0:51:23.97,EN,,0,0,0,,Remember a rectangle is specified by an origin and a horizontal vector and a vertical vector. Dialogue: 0,0:51:23.98,0:51:25.94,EN,,0,0,0,,so it's got to figure out what these things are. Dialogue: 0,0:51:27.37,0:51:32.29,EN,,0,0,0,,So for this first rectangle, the origin turns out to be the origin of the original rectangle, Dialogue: 0,0:51:33.64,0:51:37.80,EN,,0,0,0,,and the vertical vector is the same as the vertical vector of the original rectangle. Dialogue: 0,0:51:38.89,0:51:46.60,EN,,0,0,0,,The horizontal vector is the horizontal vector of the original rectangle scaled by A. Dialogue: 0,0:51:47.49,0:51:48.90,EN,,0,0,0,,And that's the first rectangle. Dialogue: 0,0:51:49.46,0:51:52.69,EN,,0,0,0,,The second rectangle, the origin Dialogue: 0,0:51:54.06,0:51:59.65,EN,,0,0,0,,The second rectangle, the origin is the original origin plus that horizontal vector scaled by A. Dialogue: 0,0:52:01.20,0:52:03.40,EN,,0,0,0,,The horizontal vector of the second rectangle is Dialogue: 0,0:52:03.77,0:52:06.04,EN,,0,0,0,,the rest of the horizontal vector of the first one, Dialogue: 0,0:52:06.34,0:52:11.66,EN,,0,0,0,,which is 1 minus A times the original H, Dialogue: 0,0:52:12.05,0:52:13.77,EN,,0,0,0,,and the vertical vector is still v. Dialogue: 0,0:52:15.48,0:52:17.98,EN,,0,0,0,,But basically it goes and constructs these two rectangles, Dialogue: 0,0:52:18.00,0:52:20.57,EN,,0,0,0,,and the important point is having constructed the rectangles, Dialogue: 0,0:52:20.93,0:52:24.58,EN,,0,0,0,,it says OK, p1, you draw yourself in there, and p2, you draw yourself in there, Dialogue: 0,0:52:24.62,0:52:26.18,EN,,0,0,0,,and that's all Beside has to do. Dialogue: 0,0:52:27.80,0:52:29.30,EN,,0,0,0,,All right, let's look at that piece of code. Dialogue: 0,0:52:34.33,0:52:35.13,EN,,0,0,0,,Beside Dialogue: 0,0:52:39.64,0:52:46.44,EN,,0,0,0,,Beside of a picture and another picture with some scaling ratio Dialogue: 0,0:52:47.84,0:52:53.64,EN,,0,0,0,,is first of all, since it's a picture, a procedure that's going to take a rectangle as argument. Dialogue: 0,0:52:55.49,0:52:56.56,EN,,0,0,0,,What's it going to do? Dialogue: 0,0:52:56.76,0:53:02.32,EN,,0,0,0,,It says, p1 draw yourself in some rectangle and p2 draw yourself in some other rectangle. Dialogue: 0,0:53:03.21,0:53:04.46,EN,,0,0,0,,And now what are those rectangles? Dialogue: 0,0:53:04.46,0:53:05.48,EN,,0,0,0,,Well here's the computation. Dialogue: 0,0:53:05.48,0:53:06.54,EN,,0,0,0,,It makes a rectangle, Dialogue: 0,0:53:07.52,0:53:10.40,EN,,0,0,0,,and this is the algebra I just did on the board: the origin, something; Dialogue: 0,0:53:10.40,0:53:11.84,EN,,0,0,0,,the horizontal vector, something; Dialogue: 0,0:53:11.84,0:53:13.44,EN,,0,0,0,,and the vertical vector, something. Dialogue: 0,0:53:13.97,0:53:14.81,EN,,0,0,0,,For p2 Dialogue: 0,0:53:15.50,0:53:19.78,EN,,0,0,0,,And for p2, the rectangle it wants has some other origin and horizontal vector and vertical vector. Dialogue: 0,0:53:19.78,0:53:20.70,EN,,0,0,0,,But the important point Dialogue: 0,0:53:21.21,0:53:27.18,EN,,0,0,0,,is that all it's saying is, p1, go do your thing in one rectangle, and p2, go do your thing in another rectangle. Dialogue: 0,0:53:27.74,0:53:29.42,EN,,0,0,0,,That's all the Beside has to do. Dialogue: 0,0:53:30.84,0:53:35.62,EN,,0,0,0,,OK, similarly Rotate-- Dialogue: 0,0:53:36.96,0:53:42.00,EN,,0,0,0,,see if I have this picture A, Dialogue: 0,0:53:42.97,0:53:46.12,EN,,0,0,0,,and I want to look at say rotating A by 90 degrees, Dialogue: 0,0:53:46.37,0:53:51.92,EN,,0,0,0,,what that should mean is, well take this rectangle, Dialogue: 0,0:53:53.94,0:53:58.44,EN,,0,0,0,,which is origin and horizontal vector and vertical vector, Dialogue: 0,0:53:58.78,0:54:03.18,EN,,0,0,0,,and now pretend that it's really the rectangle that looks like this, Dialogue: 0,0:54:03.74,0:54:09.12,EN,,0,0,0,,which has an origin and a horizontal vector up here, and a vertical vector there, Dialogue: 0,0:54:09.60,0:54:12.46,EN,,0,0,0,,and now draw yourself with respect to that rectangle. Dialogue: 0,0:54:13.26,0:54:15.04,EN,,0,0,0,,Let me show you that as a procedure. Dialogue: 0,0:54:17.02,0:54:19.85,EN,,0,0,0,,All right, so we'll Rotate 90 of the picture, Dialogue: 0,0:54:20.61,0:54:22.96,EN,,0,0,0,,because again, a procedure for rectangle, Dialogue: 0,0:54:23.25,0:54:26.12,EN,,0,0,0,,which says, OK picture, draw yourself in some rectangle; Dialogue: 0,0:54:27.21,0:54:30.66,EN,,0,0,0,,and then this algebra is the transformation on the rectangle. Dialogue: 0,0:54:30.66,0:54:33.84,EN,,0,0,0,,It's the one which makes it look like the rectangle is sideways, Dialogue: 0,0:54:33.86,0:54:36.52,EN,,0,0,0,,the origin is someplace else and the vertical vector is someplace else, Dialogue: 0,0:54:37.13,0:54:39.74,EN,,0,0,0,,and the horizontal vector is someplace else, and vertical vector is someplace else. Dialogue: 0,0:54:46.76,0:54:49.90,EN,,0,0,0,,OK, again notice, the crucial thing that's going on here Dialogue: 0,0:54:50.53,0:55:00.97,EN,,0,0,0,,is you're using the representation of pictures as procedures to automatically get the closure property, Dialogue: 0,0:55:01.74,0:55:05.22,EN,,0,0,0,,because what happens is, Beside just has this thing p1. Dialogue: 0,0:55:05.22,0:55:09.40,EN,,0,0,0,,Beside doesn't care if that's a primitive picture or it's line segments Dialogue: 0,0:55:09.61,0:55:12.69,EN,,0,0,0,,if p1 is, itself, the result of doing Aboves or Besides or Rotates. Dialogue: 0,0:55:12.72,0:55:16.08,EN,,0,0,0,,All Beside has to know about, say, p1 Dialogue: 0,0:55:16.29,0:55:19.73,EN,,0,0,0,,p1 is that if you hand p1 a rectangle, it will cause something to be drawn. Dialogue: 0,0:55:21.04,0:55:25.98,EN,,0,0,0,,And above that level, Beside just doesn't-- it's none of its business how p1 accomplishes that drawing. Dialogue: 0,0:55:27.73,0:55:32.25,EN,,0,0,0,,All right, so you're using the procedural representation to ensure this closure. Dialogue: 0,0:55:35.64,0:55:40.81,EN,,0,0,0,,So implementing pictures as procedures makes these means of combination, Dialogue: 0,0:55:41.18,0:55:43.93,EN,,0,0,0,,both pretty simple and also, I think, elegant. Dialogue: 0,0:55:45.92,0:55:48.22,EN,,0,0,0,,But that's not the real punchline. Dialogue: 0,0:55:49.28,0:55:53.52,EN,,0,0,0,,The real punchline comes when you look at the means of abstraction in this language. Dialogue: 0,0:55:54.70,0:55:56.24,EN,,0,0,0,,Because what have we done? Dialogue: 0,0:55:56.24,0:56:03.72,EN,,0,0,0,,We've implemented the means of combination themselves as procedures. Dialogue: 0,0:56:05.85,0:56:09.38,EN,,0,0,0,,And what that means is that when we go to abstract in this language, Dialogue: 0,0:56:10.17,0:56:15.69,EN,,0,0,0,,everything that Lisp supplies us for manipulating procedures Dialogue: 0,0:56:16.33,0:56:21.45,EN,,0,0,0,,automatically available to do things in this picture language. Dialogue: 0,0:56:21.92,0:56:29.74,EN,,0,0,0,,The technical term I want to say is not only is this language implemented in Lisp, obviously it is, Dialogue: 0,0:56:29.76,0:56:32.58,EN,,0,0,0,,but the language is nicely embedded in Lisp. Dialogue: 0,0:56:37.64,0:56:42.08,EN,,0,0,0,,What I mean is by embedding the language in this way, Dialogue: 0,0:56:42.90,0:56:48.86,EN,,0,0,0,,all the power of Lisp is automatically available as an extension to whatever you want to do. Dialogue: 0,0:56:50.06,0:56:51.68,EN,,0,0,0,,And what do I mean by that? Dialogue: 0,0:56:51.97,0:57:02.94,EN,,0,0,0,,Example: say, suppose I want to make a thing that takes four pictures A, B, C and D, Dialogue: 0,0:57:03.76,0:57:07.06,EN,,0,0,0,,and makes a configuration that looks like this. Dialogue: 0,0:57:12.50,0:57:16.96,EN,,0,0,0,,Well you might call that, you know, four pictures or something, four-pict configuration. Dialogue: 0,0:57:16.96,0:57:17.70,EN,,0,0,0,,How do I do that? Dialogue: 0,0:57:17.70,0:57:18.68,EN,,0,0,0,,Well I can obviously do that. Dialogue: 0,0:57:18.68,0:57:23.33,EN,,0,0,0,,I just write a procedure that takes B above D Dialogue: 0,0:57:24.13,0:57:25.85,EN,,0,0,0,,and A above C Dialogue: 0,0:57:26.09,0:57:27.70,EN,,0,0,0,,and puts those things beside each other. Dialogue: 0,0:57:28.24,0:57:31.82,EN,,0,0,0,,So I automatically have Lisp's ability to do procedure composition. Dialogue: 0,0:57:32.92,0:57:35.82,EN,,0,0,0,,And I didn't have to make that specifically in the picture language. Dialogue: 0,0:57:35.82,0:57:39.92,EN,,0,0,0,,It's automatic from the fact that the means of combination are themselves procedures. Dialogue: 0,0:57:40.96,0:57:44.18,EN,,0,0,0,,Or suppose I wanted to do something a little bit more complicated. Dialogue: 0,0:57:44.18,0:57:46.50,EN,,0,0,0,,I wanted to put in a parameter so that for each of these, Dialogue: 0,0:57:46.52,0:57:50.08,EN,,0,0,0,,I could independently specify a rotation by 90 degrees. Dialogue: 0,0:57:50.41,0:57:52.64,EN,,0,0,0,,That's just putting a parameter in the procedure. Dialogue: 0,0:57:53.17,0:57:54.56,EN,,0,0,0,,It's automatically there. Dialogue: 0,0:57:54.80,0:57:57.84,EN,,0,0,0,,Right, it automatically comes from the embedding. Dialogue: 0,0:57:58.16,0:58:05.36,EN,,0,0,0,,Or even more, suppose I wanted to, you know, use recursion. Dialogue: 0,0:58:06.16,0:58:10.78,EN,,0,0,0,,Let's look at a recursive means of combination on pictures. Dialogue: 0,0:58:10.78,0:58:14.64,EN,,0,0,0,,I could say define-- let's see if you can figure out what this one is-- Dialogue: 0,0:58:14.69,0:58:18.97,EN,,0,0,0,,suppose I say define what it means to right-push a picture, Dialogue: 0,0:58:22.84,0:58:29.80,EN,,0,0,0,,right-push a picture and some integer N and some scale factor A. Dialogue: 0,0:58:31.46,0:58:41.22,EN,,0,0,0,,I'll define this to say if N equals 0, then the answer is the picture. Dialogue: 0,0:58:42.20,0:58:54.02,EN,,0,0,0,,Otherwise I'm going to put-- oops, name change: P. Dialogue: 0,0:58:55.88,0:59:00.21,EN,,0,0,0,,Otherwise, I'm going to take P and put it beside Dialogue: 0,0:59:00.92,0:59:18.30,EN,,0,0,0,,the results of recursively right-pushing P with N minus 1 and A and use a scale factor of A. OK, Dialogue: 0,0:59:24.72,0:59:31.12,EN,,0,0,0,,so if N 0 , it's P. Otherwise I put P with a scale factor of A-- Dialogue: 0,0:59:31.12,0:59:32.80,EN,,0,0,0,,I'm sorry I didn't align this right-- Dialogue: 0,0:59:33.66,0:59:38.50,EN,,0,0,0,,recursively beside the result of right-pushing P, N minus 1 times with a scale factor of A. Dialogue: 0,0:59:38.50,0:59:42.00,EN,,0,0,0,,There's a recursive means of combination. Dialogue: 0,0:59:43.78,0:59:44.76,EN,,0,0,0,,What's that look like? Dialogue: 0,0:59:44.76,0:59:45.90,EN,,0,0,0,,Well, here's what it looks like. Dialogue: 0,0:59:46.04,0:59:56.04,EN,,0,0,0,,There's George right-pushed against himself twice with a scale factor of 0.75. Dialogue: 0,0:59:59.26,1:00:00.72,EN,,0,0,0,,Where'd that come from? Dialogue: 0,1:00:00.72,1:00:02.34,EN,,0,0,0,,How did I get all this fancy recursion? Dialogue: 0,1:00:02.34,1:00:05.24,EN,,0,0,0,,And the answer is just automatic, absolutely automatic. Dialogue: 0,1:00:05.24,1:00:09.80,EN,,0,0,0,,Since these are procedures, the embedding says, well sure, I can define recursive procedures. Dialogue: 0,1:00:10.36,1:00:11.68,EN,,0,0,0,,I didn't have to arrange that. Dialogue: 0,1:00:13.56,1:00:16.42,EN,,0,0,0,,And of course, we can do more complicated things of the same sort. Dialogue: 0,1:00:16.42,1:00:18.21,EN,,0,0,0,,I could make something that does an up-push. Dialogue: 0,1:00:18.42,1:00:22.60,EN,,0,0,0,,Right, that sort of goes like this, by recursively putting something above. Dialogue: 0,1:00:22.60,1:00:26.54,EN,,0,0,0,,Or I could make something that, sort of, was this scheme. Dialogue: 0,1:00:26.56,1:00:28.85,EN,,0,0,0,,I might start out with a picture Dialogue: 0,1:00:29.78,1:00:37.16,EN,,0,0,0,,and then, sort of, recursively both push it aside and above Dialogue: 0,1:00:37.57,1:00:38.92,EN,,0,0,0,,and that might put something there. Dialogue: 0,1:00:39.52,1:00:41.82,EN,,0,0,0,,And then up here I put the same recursive thing, Dialogue: 0,1:00:42.36,1:00:44.20,EN,,0,0,0,,and I might end up with something like this. Dialogue: 0,1:00:45.40,1:00:52.50,EN,,0,0,0,,Right, so there's a procedure that's a little bit more complicated than right-push but not much. Dialogue: 0,1:00:53.64,1:00:58.14,EN,,0,0,0,,I just do an Above and a Beside, rather than just a Beside. Dialogue: 0,1:01:01.12,1:01:06.78,EN,,0,0,0,,Now if I take that and apply that with the idea of putting four pictures together, Dialogue: 0,1:01:07.53,1:01:08.65,EN,,0,0,0,,which I can surely do; Dialogue: 0,1:01:09.01,1:01:14.17,EN,,0,0,0,,and I go and I apply that to Q, which we defined before, right, Dialogue: 0,1:01:15.97,1:01:18.73,EN,,0,0,0,,what I end up with this is this thing, Dialogue: 0,1:01:20.14,1:01:25.26,EN,,0,0,0,,which is, sort of, the square limit of Q, done twice. Dialogue: 0,1:01:28.18,1:01:32.25,EN,,0,0,0,,Right, and then we can compare that with Escher's "Square Limit." Dialogue: 0,1:01:32.88,1:01:34.53,EN,,0,0,0,,And you see, it's sort of the same idea. Dialogue: 0,1:01:34.74,1:01:36.94,EN,,0,0,0,,Escher's is, of course, much, much prettier. Dialogue: 0,1:01:36.94,1:01:44.04,EN,,0,0,0,,If we go back and look at George, right, if we go look at George here-- Dialogue: 0,1:01:44.38,1:01:47.37,EN,,0,0,0,,see, I started with a fairly arbitrary design Dialogue: 0,1:01:47.42,1:01:49.26,EN,,0,0,0,,this picture of George and did things with it. Dialogue: 0,1:01:51.22,1:01:53.14,EN,,0,0,0,,Right, whereas if we go look at the Escher picture, right, Dialogue: 0,1:01:54.08,1:01:56.14,EN,,0,0,0,,the Escher picture is not an arbitrary design. Dialogue: 0,1:01:56.14,1:01:57.66,EN,,0,0,0,,It's this very, very clever thing, Dialogue: 0,1:01:57.89,1:02:00.20,EN,,0,0,0,,so that when you take this fish body Dialogue: 0,1:02:01.82,1:02:04.97,EN,,0,0,0,,and Rotate it and shrink it down, it bleeds into the next one really nicely. Dialogue: 0,1:02:07.40,1:02:11.48,EN,,0,0,0,,And of course with George, I didn't really do anything like that. Dialogue: 0,1:02:12.12,1:02:13.90,EN,,0,0,0,,So if we look at George, Dialogue: 0,1:02:15.41,1:02:18.64,EN,,0,0,0,,right, there's a little bit of match up, but not very nice, and it's pretty arbitrary. Dialogue: 0,1:02:18.64,1:02:21.53,EN,,0,0,0,,One very nice project, by the way, Dialogue: 0,1:02:22.30,1:02:27.54,EN,,0,0,0,,would be to write a procedure that could take some basic figure like this George thing Dialogue: 0,1:02:27.86,1:02:29.62,EN,,0,0,0,,and start moving the ends of the lines around, Dialogue: 0,1:02:29.86,1:02:31.20,EN,,0,0,0,,so you got a really nice one Dialogue: 0,1:02:32.13,1:02:34.06,EN,,0,0,0,,when you went and did that "Square Limit" process. Dialogue: 0,1:02:34.68,1:02:36.30,EN,,0,0,0,,That'd be a really nice thing to think about. Dialogue: 0,1:02:38.08,1:02:39.72,EN,,0,0,0,,Well so, we can combine things. Dialogue: 0,1:02:39.72,1:02:41.04,EN,,0,0,0,,We can recursive procedures. Dialogue: 0,1:02:41.04,1:02:43.48,EN,,0,0,0,,We can do all kinds of things, and that's all automatic. Dialogue: 0,1:02:44.60,1:02:48.52,EN,,0,0,0,,Right, the important point, the difference between merely implementing something in a language Dialogue: 0,1:02:48.69,1:02:50.44,EN,,0,0,0,,and embedding something in the language, Dialogue: 0,1:02:50.44,1:02:53.72,EN,,0,0,0,,so that you don't lose the original power of the language, and what Lisp is great at, Dialogue: 0,1:02:54.76,1:02:57.62,EN,,0,0,0,,see Lisp is a lousy language for doing any particular problem. Dialogue: 0,1:02:57.62,1:03:02.10,EN,,0,0,0,,What it's good for is figuring out the right language that you want and embedding that in Lisp. Dialogue: 0,1:03:02.10,1:03:05.44,EN,,0,0,0,,That's the real power of this approach to design. Dialogue: 0,1:03:05.69,1:03:06.82,EN,,0,0,0,,Of course, we can go further. Dialogue: 0,1:03:06.82,1:03:08.81,EN,,0,0,0,,See, you saw the other thing that we can do in Lisp Dialogue: 0,1:03:09.21,1:03:17.52,EN,,0,0,0,,is capture general methods of doing things as higher order procedures. Dialogue: 0,1:03:19.09,1:03:22.57,EN,,0,0,0,,And you probably just from me drawing it got the idea that right-push Dialogue: 0,1:03:23.78,1:03:26.61,EN,,0,0,0,,and the analogous thing where you push something up and up and up and up Dialogue: 0,1:03:26.93,1:03:33.82,EN,,0,0,0,,and this corner push thing are all generalizations of a common kind of idea. Dialogue: 0,1:03:34.72,1:03:37.20,EN,,0,0,0,,So just to illustrate and give you practice in looking at a Dialogue: 0,1:03:37.98,1:03:40.65,EN,,0,0,0,,at a fairly convoluted use of higher order procedures, Dialogue: 0,1:03:41.12,1:03:47.24,EN,,0,0,0,,let me show you the general idea of pushing some means of combination to recursively repeat it. Dialogue: 0,1:03:48.30,1:03:50.70,EN,,0,0,0,,So here's a good one to puzzle out. Dialogue: 0,1:03:51.22,1:04:00.70,EN,,0,0,0,,We'll define it what it means to push using a means of combination. Dialogue: 0,1:04:01.49,1:04:04.88,EN,,0,0,0,,Comb is going to be something like the Beside or Above. Dialogue: 0,1:04:06.18,1:04:07.06,EN,,0,0,0,,Well what's that going to be. Dialogue: 0,1:04:07.06,1:04:12.06,EN,,0,0,0,,That's going to be a procedure, remember what Beside actually was, right. Dialogue: 0,1:04:13.22,1:04:15.18,EN,,0,0,0,,It took a picture, Dialogue: 0,1:04:15.96,1:04:18.08,EN,,0,0,0,,took two pictures and a scale factor. Dialogue: 0,1:04:18.62,1:04:24.28,EN,,0,0,0,,Using that I produced something that took a level number and a picture and a scale factor, Dialogue: 0,1:04:24.28,1:04:25.45,EN,,0,0,0,,that I called right-push. Dialogue: 0,1:04:26.16,1:04:33.66,EN,,0,0,0,,So this is going to be something that takes a picture, a level number and a scale factor, and it's going to say-- Dialogue: 0,1:04:36.16,1:04:39.12,EN,,0,0,0,,I'm going to do some repeated operation. Dialogue: 0,1:04:39.45,1:04:46.62,EN,,0,0,0,,I'm going to repeatedly apply the procedure which takes a picture Dialogue: 0,1:04:48.40,1:04:50.69,EN,,0,0,0,,and applies the means of combination Dialogue: 0,1:04:51.20,1:04:59.08,EN,,0,0,0,,to the picture and the original picture and the one I took in here and the scale factor, Dialogue: 0,1:05:02.26,1:05:07.28,EN,,0,0,0,,and I do the thing which repeats this procedure N times, Dialogue: 0,1:05:12.04,1:05:16.20,EN,,0,0,0,,and I apply that whole thing to my original picture. Dialogue: 0,1:05:19.56,1:05:24.48,EN,,0,0,0,,Repeated here, in case you haven't seen it, is another higher order procedure Dialogue: 0,1:05:24.53,1:05:28.34,EN,,0,0,0,,that takes a procedure and a number Dialogue: 0,1:05:29.54,1:05:34.29,EN,,0,0,0,,and returns for you another procedure that applies this procedure N times. Dialogue: 0,1:05:36.04,1:05:39.30,EN,,0,0,0,,And I think some of you have already written repeated as an exercise, Dialogue: 0,1:05:39.70,1:05:43.01,EN,,0,0,0,,but if you haven't, it's a very good exercise in thinking about higher order procedures. Dialogue: 0,1:05:43.84,1:05:46.90,EN,,0,0,0,,But in any case, the result of this repeated is what I apply to picture. Dialogue: 0,1:05:49.46,1:05:52.38,EN,,0,0,0,,And having done that, that's going to capture the -- Dialogue: 0,1:05:53.12,1:05:57.73,EN,,0,0,0,,that is the thing, the way I got from the idea of Beside to the idea of right-push Dialogue: 0,1:05:59.01,1:06:13.17,EN,,0,0,0,,So having done that, I could say define right-push to be push of Beside. Dialogue: 0,1:06:17.65,1:06:20.32,EN,,0,0,0,,Or if I say, define up-push to be push of Above Dialogue: 0,1:06:20.34,1:06:25.48,EN,,0,0,0,,I'd get the analogous thing or define corner-push to be push of some appropriate thing that did both the Beside and Above, Dialogue: 0,1:06:25.49,1:06:26.70,EN,,0,0,0,,or I could push anything. Dialogue: 0,1:06:28.26,1:06:34.76,EN,,0,0,0,,Anyway this is, if you're having trouble with lambdas, this is an excellent exercise in figuring out what this means. Dialogue: 0,1:06:38.98,1:06:41.00,EN,,0,0,0,,OK, well there's a lot to learn from this example. Dialogue: 0,1:06:42.18,1:06:49.80,EN,,0,0,0,,The main point I've been welling on is the notion of nicely embedding a language inside another language. Dialogue: 0,1:06:50.66,1:06:55.62,EN,,0,0,0,,Right, so that all the power of this language like Lisp of the surrounding language Dialogue: 0,1:06:55.92,1:07:00.28,EN,,0,0,0,,is still accessible to you and appears as a natural extension of the language that you built. Dialogue: 0,1:07:00.98,1:07:04.00,EN,,0,0,0,,That's one thing that this example shows very well. Dialogue: 0,1:07:08.14,1:07:10.94,EN,,0,0,0,,Another thing is, if you go back and think about that, Dialogue: 0,1:07:10.94,1:07:12.28,EN,,0,0,0,,what's procedures and what's data. Dialogue: 0,1:07:12.28,1:07:16.20,EN,,0,0,0,,You know, by the time we get up to here, my God, what's going on. Dialogue: 0,1:07:16.20,1:07:19.66,EN,,0,0,0,,I mean, this is some procedure, and it takes a picture and an argument, Dialogue: 0,1:07:19.66,1:07:20.36,EN,,0,0,0,,and what's a picture. Dialogue: 0,1:07:20.36,1:07:23.82,EN,,0,0,0,,Well, a picture itself, as you remember, was a procedure, and that took a rectangle. Dialogue: 0,1:07:23.82,1:07:25.82,EN,,0,0,0,,And a rectangle is some abstraction. Dialogue: 0,1:07:26.09,1:07:28.13,EN,,0,0,0,,And I hope now that by now you're completely lost Dialogue: 0,1:07:29.14,1:07:33.74,EN,,0,0,0,,as to the question of what in the system is procedure and what's data. Dialogue: 0,1:07:33.74,1:07:34.78,EN,,0,0,0,,You see, there isn't any difference. Dialogue: 0,1:07:35.49,1:07:36.44,EN,,0,0,0,,There really isn't. Dialogue: 0,1:07:37.93,1:07:41.42,EN,,0,0,0,,And you might think of a picture sometimes as a procedure and sometimes as data, Dialogue: 0,1:07:41.84,1:07:44.90,EN,,0,0,0,,but that's just, sort of, you know, making you feel comfortable. Dialogue: 0,1:07:44.90,1:07:47.30,EN,,0,0,0,,It's really both in some sense or neither in some sense. Dialogue: 0,1:07:49.92,1:08:02.20,EN,,0,0,0,,OK, there's a more general point about the structure of the system as creating a language, Dialogue: 0,1:08:02.52,1:08:06.74,EN,,0,0,0,,viewing the engineering design process as one of creating language or Dialogue: 0,1:08:07.84,1:08:13.97,EN,,0,0,0,,or rather one of creating a sort of sequence of layers of language. Dialogue: 0,1:08:14.77,1:08:20.01,EN,,0,0,0,,You see, there's this methodology, or maybe I should say mythology, Dialogue: 0,1:08:20.74,1:08:24.90,EN,,0,0,0,,that's, sort of, charitably called software, quote, engineering. Dialogue: 0,1:08:25.21,1:08:28.04,EN,,0,0,0,,All right, and what does it say, it's says well, you go and you figure out your task, Dialogue: 0,1:08:28.04,1:08:30.04,EN,,0,0,0,,and you figure out exactly what you want to do. Dialogue: 0,1:08:30.40,1:08:32.20,EN,,0,0,0,,And once you figure out exactly what you want to do, Dialogue: 0,1:08:32.22,1:08:34.54,EN,,0,0,0,,you find out that it breaks out into three sub-tasks, Dialogue: 0,1:08:34.54,1:08:35.76,EN,,0,0,0,,and you go and you start working on-- Dialogue: 0,1:08:35.97,1:08:38.94,EN,,0,0,0,,and you work on this sub-task, and you figure out exactly what that is. Dialogue: 0,1:08:38.94,1:08:43.04,EN,,0,0,0,,And you find out that that breaks down into three sub-tasks, and you specify them completely, Dialogue: 0,1:08:43.04,1:08:47.32,EN,,0,0,0,,and you go and you work on those two, and you work on this sub-one, and you specify that exactly. Dialogue: 0,1:08:47.32,1:08:51.10,EN,,0,0,0,,And then finally when you're done, you come back way up here, and you work on your second sub-task, Dialogue: 0,1:08:51.10,1:08:53.40,EN,,0,0,0,,and specify that out and work it out. Dialogue: 0,1:08:53.40,1:08:57.64,EN,,0,0,0,,And then you end up with-- you end up at the end with this beautiful edifice. Dialogue: 0,1:08:57.64,1:09:00.25,EN,,0,0,0,,Right, you end up with a marvelous tree, Dialogue: 0,1:09:00.89,1:09:08.24,EN,,0,0,0,,that where you've broken your task into sub-tasks and broken each of these into sub-tasks and broken those into sub-tasks, right. Dialogue: 0,1:09:09.88,1:09:15.02,EN,,0,0,0,,And each of these nodes is exactly and precisely defined Dialogue: 0,1:09:15.26,1:09:18.66,EN,,0,0,0,,to do the wonderful, beautiful task to make it fit into the whole edifice Dialogue: 0,1:09:18.96,1:09:21.14,EN,,0,0,0,,Right, that's this mythology. Dialogue: 0,1:09:21.14,1:09:25.92,EN,,0,0,0,,See only a computer scientist could possibly believe that you build a complex system like that Dialogue: 0,1:09:27.48,1:09:32.80,EN,,0,0,0,,Right. Contrast that with this Henderson example. Dialogue: 0,1:09:32.80,1:09:34.30,EN,,0,0,0,,It didn't work like that. Dialogue: 0,1:09:35.26,1:09:39.33,EN,,0,0,0,,What happened was that there was a sequence of layers of language. Dialogue: 0,1:09:41.06,1:09:42.05,EN,,0,0,0,,What happened? Dialogue: 0,1:09:42.18,1:09:48.76,EN,,0,0,0,,There was a layer of a thing that allowed us to build primitive pictures. Dialogue: 0,1:09:51.69,1:09:56.24,EN,,0,0,0,,There's primitive pictures and that was a language. Dialogue: 0,1:09:56.32,1:09:57.84,EN,,0,0,0,,I didn't say much about it. Dialogue: 0,1:09:58.22,1:09:59.58,EN,,0,0,0,,We talked about how to construct George, Dialogue: 0,1:09:59.61,1:10:04.88,EN,,0,0,0,,but that was a language where you talked about vectors and line segments and points and where they sat in the unit square. Dialogue: 0,1:10:06.42,1:10:11.29,EN,,0,0,0,,And then on top of that, right, on top of that-- Dialogue: 0,1:10:11.97,1:10:14.10,EN,,0,0,0,,so this is the language of primitive pictures. Dialogue: 0,1:10:17.08,1:10:20.36,EN,,0,0,0,,Right, talking about line segments in particular pictures in the unit square. Dialogue: 0,1:10:21.40,1:10:23.80,EN,,0,0,0,,On top of that was a whole language. Dialogue: 0,1:10:24.05,1:10:30.86,EN,,0,0,0,,There was a language of geometric combinators, Dialogue: 0,1:10:32.66,1:10:36.62,EN,,0,0,0,,a language of geometric positions, Dialogue: 0,1:10:38.77,1:10:46.50,EN,,0,0,0,,which talks about things like Above and Beside and right-push and Rotate. Dialogue: 0,1:10:48.04,1:10:55.70,EN,,0,0,0,,And those things, sort of, happened with reference to the things that are talked about in this language. Dialogue: 0,1:10:58.57,1:11:00.93,EN,,0,0,0,,And then if we like, we saw that above that Dialogue: 0,1:11:02.61,1:11:15.10,EN,,0,0,0,,there was sort of a language of schemes of combination. Dialogue: 0,1:11:21.25,1:11:22.44,EN,,0,0,0,,For example, push, Dialogue: 0,1:11:24.45,1:11:27.88,EN,,0,0,0,,which talked about repeatedly doing something over with a scale factor. Dialogue: 0,1:11:28.38,1:11:31.28,EN,,0,0,0,,And the things that were being discussed in that language Dialogue: 0,1:11:31.50,1:11:34.34,EN,,0,0,0,,were, sort of, the things that happened down here. Dialogue: 0,1:11:36.30,1:11:42.76,EN,,0,0,0,,So what you have is, at each level, the objects that are being talked about Dialogue: 0,1:11:44.68,1:11:47.00,EN,,0,0,0,,are the things that were erected the previous level. Dialogue: 0,1:11:48.08,1:11:52.06,EN,,0,0,0,,What's the difference between this thing and this thing? Dialogue: 0,1:11:53.34,1:11:54.18,EN,,0,0,0,,The answer is Dialogue: 0,1:11:56.14,1:12:01.73,EN,,0,0,0,,that over here in the tree, each node, and in fact, each decomposition down here, Dialogue: 0,1:12:02.14,1:12:05.25,EN,,0,0,0,,is being designed to do a specific task, Dialogue: 0,1:12:07.50,1:12:08.88,EN,,0,0,0,,whereas in the other scheme, Dialogue: 0,1:12:09.21,1:12:14.80,EN,,0,0,0,,what you have is a full range of linguistic power at each level. Dialogue: 0,1:12:16.00,1:12:18.08,EN,,0,0,0,,See what's happening there, at any level, Dialogue: 0,1:12:20.24,1:12:22.72,EN,,0,0,0,,it's not being set up to do a particular task. Dialogue: 0,1:12:23.14,1:12:26.17,EN,,0,0,0,,It's being set up to talk about a whole range of things. Dialogue: 0,1:12:27.62,1:12:30.78,EN,,0,0,0,,The consequence of that for design Dialogue: 0,1:12:31.14,1:12:35.58,EN,,0,0,0,,is that something that's designed in that method is likely to be more robust, Dialogue: 0,1:12:36.61,1:12:38.20,EN,,0,0,0,,where by robust, I mean Dialogue: 0,1:12:38.44,1:12:41.24,EN,,0,0,0,,that if you go and make some change in your description, Dialogue: 0,1:12:42.70,1:12:48.04,EN,,0,0,0,,it's more likely to be captured by a corresponding change, Dialogue: 0,1:12:49.22,1:12:52.60,EN,,0,0,0,,in the way that the language is implemented at the next level up, Dialogue: 0,1:12:54.29,1:12:56.58,EN,,0,0,0,,right, because you've made these levels full. Dialogue: 0,1:12:56.62,1:12:59.66,EN,,0,0,0,,So you're not talking about a particular thing like Beside. Dialogue: 0,1:12:59.94,1:13:03.78,EN,,0,0,0,,You've given yourself a whole vocabulary to express things of that sort, Dialogue: 0,1:13:04.77,1:13:07.02,EN,,0,0,0,,so if you go and change your specifications a little bit, Dialogue: 0,1:13:07.02,1:13:11.38,EN,,0,0,0,,it's more likely that your methodology will able to adapt to capture that change, Dialogue: 0,1:13:12.69,1:13:15.02,EN,,0,0,0,,whereas a design like this is not going to be robust, Dialogue: 0,1:13:15.02,1:13:17.08,EN,,0,0,0,,because if I go and change something that's in here, Dialogue: 0,1:13:17.53,1:13:21.69,EN,,0,0,0,,that might affect the entire way that I decomposed everything down, further down the tree. Dialogue: 0,1:13:23.20,1:13:29.74,EN,,0,0,0,,Right, so very big difference in outlook in decomposition, levels of language rather than, sort of, a strict hierarchy. Dialogue: 0,1:13:30.52,1:13:33.02,EN,,0,0,0,,Not only that, but when you have levels of language Dialogue: 0,1:13:33.50,1:13:35.92,EN,,0,0,0,,you've given yourself a different vocabularies Dialogue: 0,1:13:36.45,1:13:38.74,EN,,0,0,0,,for talking about the design at different levels. Dialogue: 0,1:13:38.74,1:13:40.92,EN,,0,0,0,,So if we go back and look at George one last time, Dialogue: 0,1:13:41.90,1:13:44.08,EN,,0,0,0,,if I wanted to change this picture George, Dialogue: 0,1:13:45.85,1:13:48.68,EN,,0,0,0,,see suddenly I have a whole different ways of describing the change. Dialogue: 0,1:13:48.68,1:13:56.08,EN,,0,0,0,,Like for example, I may want to go to the basic primitive design and move the endpoint of some vector. Dialogue: 0,1:13:57.76,1:14:00.76,EN,,0,0,0,,That's a change that I would discuss at the lowest level. Dialogue: 0,1:14:01.00,1:14:02.50,EN,,0,0,0,,I would say the endpoint is somewhere else. Dialogue: 0,1:14:03.34,1:14:07.98,EN,,0,0,0,,Or I might come up and say, well the next thing I wanted to do, this little replicated element, Dialogue: 0,1:14:09.10,1:14:10.94,EN,,0,0,0,,I might want to do by something else. Dialogue: 0,1:14:10.94,1:14:13.84,EN,,0,0,0,,I might want to put a scale factor in that Beside. Dialogue: 0,1:14:13.84,1:14:19.34,EN,,0,0,0,,That's a change that I would discuss at the next level of design, the level of combinators. Dialogue: 0,1:14:19.34,1:14:25.05,EN,,0,0,0,,Or I might want to say, I might want to change the basic way that I took this pattern Dialogue: 0,1:14:26.49,1:14:30.48,EN,,0,0,0,,and made some recursive decomposition, maybe not bleeding out toward the corners or something else. Dialogue: 0,1:14:31.16,1:14:34.18,EN,,0,0,0,,That would be a change that I would discuss at the highest level. Dialogue: 0,1:14:34.18,1:14:36.37,EN,,0,0,0,,And because I've structured the system to be this way, Dialogue: 0,1:14:36.52,1:14:39.62,EN,,0,0,0,,I have all these vocabularies for talking about change in different ways Dialogue: 0,1:14:39.65,1:14:42.48,EN,,0,0,0,,and a lot of flexibility to decide which one's appropriate. Dialogue: 0,1:14:44.74,1:14:51.05,EN,,0,0,0,,OK, well that's sort of a big point about the difference in software methodology that comes out from Lisp, Dialogue: 0,1:14:51.25,1:14:55.45,EN,,0,0,0,,and it all comes again, out of the notion that really, the design process Dialogue: 0,1:14:56.12,1:14:59.62,EN,,0,0,0,,is not so much implementing programs as implementing languages. Dialogue: 0,1:14:59.62,1:15:01.09,EN,,0,0,0,,And that's really the power of Lisp. Dialogue: 0,1:15:02.21,1:15:03.61,EN,,0,0,0,,OK, thank you. Let's take a break. Dialogue: 0,0:00:00.00,0:00:03.12,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:04.40,0:00:12.16,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:04.40,0:00:12.16,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}字幕&时间轴\N邓雄飞 & S.Michael Dialogue: 0,0:00:04.40,0:00:12.16,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}后期&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.40,0:00:12.16,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞\N Dialogue: 0,0:00:04.40,0:00:12.16,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:12.37,0:00:16.32,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson-Escher的例子\NHenderson Escher Example Dialogue: 0,0:00:20.94,0:00:23.86,Default,,0,0,0,,上节课我们讨论了复合数据 Dialogue: 0,0:00:24.94,0:00:29.74,Default,,0,0,0,,其中有两个关键点 Dialogue: 0,0:00:29.74,0:00:32.48,Default,,0,0,0,,首先 有一种数据抽象的方法学 Dialogue: 0,0:00:32.94,0:00:39.10,Default,,0,0,0,,其要点是将数据的使用 Dialogue: 0,0:00:40.06,0:00:41.50,Default,,0,0,0,,和表示分离开来 Dialogue: 0,0:00:41.55,0:00:45.20,Default,,0,0,0,,比如说 我们可以与一个叫做George的人“签订契约” Dialogue: 0,0:00:45.20,0:00:47.48,Default,,0,0,0,,让他负责数据的表示 Dialogue: 0,0:00:47.48,0:00:49.36,Default,,0,0,0,,而当我们使用这些数据的时候 Dialogue: 0,0:00:49.36,0:00:51.36,Default,,0,0,0,,不需要替George操心他是如何完成数据表示的工作的 Dialogue: 0,0:00:51.98,0:00:58.44,Default,,0,0,0,,其次 Lisp中有一种特殊的方式把对象连接在一起 Dialogue: 0,0:00:58.94,0:01:00.52,Default,,0,0,0,,就是构成“序对” Dialogue: 0,0:01:00.52,0:01:03.54,Default,,0,0,0,,这是通过CONS CAR CDR实现的 Dialogue: 0,0:01:03.54,0:01:07.16,Default,,0,0,0,,而CONS CAR CDR本身是如何实现的 这不重要 Dialogue: 0,0:01:07.16,0:01:10.02,Default,,0,0,0,,George的任务就是如何构建这些东西 Dialogue: 0,0:01:10.02,0:01:11.16,Default,,0,0,0,,可以将它们实现为基本过程 Dialogue: 0,0:01:11.16,0:01:13.80,Default,,0,0,0,,也可以利用一些奇怪的过程来实现 Dialogue: 0,0:01:13.80,0:01:15.22,Default,,0,0,0,,但是我们不用操心这些 Dialogue: 0,0:01:16.02,0:01:19.66,Default,,0,0,0,,举个例子 我们来看下有理数算术 Dialogue: 0,0:01:19.66,0:01:21.50,Default,,0,0,0,,看下向量 Dialogue: 0,0:01:21.50,0:01:24.18,Default,,0,0,0,,我们简单回顾一下向量 Dialogue: 0,0:01:24.18,0:01:27.64,Default,,0,0,0,,这里有个对两个向量求和的操作 Dialogue: 0,0:01:27.64,0:01:33.32,Default,,0,0,0,,我们想要把向量v1和v2相加 Dialogue: 0,0:01:34.46,0:01:40.84,Default,,0,0,0,,它们的和也是一个向量 其坐标是两个向量的坐标的和 Dialogue: 0,0:01:41.28,0:01:45.66,Default,,0,0,0,,所以 定义(+VECT V1 V2)为 Dialogue: 0,0:01:45.66,0:01:51.72,Default,,0,0,0,,我创建一个向量 其X坐标是两向量X坐标的和 Dialogue: 0,0:01:52.10,0:01:54.82,Default,,0,0,0,,而Y坐标是两向量Y坐标的和 Dialogue: 0,0:01:56.06,0:02:04.10,Default,,0,0,0,,类似地 我们也可以定义一个缩放向量的操作 Dialogue: 0,0:02:04.94,0:02:12.66,Default,,0,0,0,,这里的SCALE过程是用数字S乘以向量V Dialogue: 0,0:02:13.08,0:02:16.14,Default,,0,0,0,,向量V从这里到这里 Dialogue: 0,0:02:16.32,0:02:20.22,Default,,0,0,0,,我放大V 得到了与原来同向但更长的向量 Dialogue: 0,0:02:21.56,0:02:24.26,Default,,0,0,0,,为了缩放向量 我需要通过缩放坐标来实现 Dialogue: 0,0:02:24.26,0:02:30.22,Default,,0,0,0,,所以我构建了一个向量 它的X坐标是原向量X坐标的S倍 Dialogue: 0,0:02:30.56,0:02:33.54,Default,,0,0,0,,同时 它的Y坐标是原来向量Y坐标的S倍 Dialogue: 0,0:02:33.54,0:02:40.28,Default,,0,0,0,,上述两个操作都是利用了向量的表示来实现的 Dialogue: 0,0:02:40.28,0:02:45.02,Default,,0,0,0,,而这种向量的表示 我们则可以用序对来实现 Dialogue: 0,0:02:45.34,0:02:51.28,Default,,0,0,0,,因此George需要为我们提供MAKE-VECTOR、XCOR和YCOR Dialogue: 0,0:02:53.02,0:02:57.98,Default,,0,0,0,,他可以使用CONS CAR CDR来实现 Dialogue: 0,0:02:58.88,0:03:06.78,Default,,0,0,0,,但是注意 我这里用了一个略微不同的方式 Dialogue: 0,0:03:08.04,0:03:11.00,Default,,0,0,0,,这个过程我们之前看过 其中我讲过 Dialogue: 0,0:03:11.14,0:03:16.22,Default,,0,0,0,,(MAKE-VECTOR X Y)也就是(CONS X Y) Dialogue: 0,0:03:16.22,0:03:17.98,Default,,0,0,0,,而我这里简单定义MAKE-VECTOR为CONS Dialogue: 0,0:03:17.98,0:03:20.48,Default,,0,0,0,,这就与之前有些不同了 Dialogue: 0,0:03:20.48,0:03:26.22,Default,,0,0,0,,之前我们我们把MAKE-VECTOR定义为需要两个参数的过程 Dialogue: 0,0:03:26.22,0:03:28.04,Default,,0,0,0,,效果是(CONS X Y) Dialogue: 0,0:03:28.04,0:03:34.12,Default,,0,0,0,,这里 我就把MAKE-VECTOR定义为CONS Dialogue: 0,0:03:35.18,0:03:39.66,Default,,0,0,0,,这跟我们之前使用的方式基本上是一样的 Dialogue: 0,0:03:39.66,0:03:46.58,Default,,0,0,0,,大家要习惯于“过程也是对象 而且你可以给他们命名”这种想法 Dialogue: 0,0:03:48.70,0:03:51.80,Default,,0,0,0,,这些就是向量的表示方法了 Dialogue: 0,0:03:51.80,0:03:55.68,Default,,0,0,0,,如果仅仅是那样 那就太无趣了 Dialogue: 0,0:03:57.02,0:04:02.16,Default,,0,0,0,,要记住 要点是我们不仅可以通过使用CONS将数字组合成序对 Dialogue: 0,0:04:02.16,0:04:04.16,Default,,0,0,0,,也可以组合任何东西 Dialogue: 0,0:04:05.20,0:04:11.60,Default,,0,0,0,,例如 如果我想表示一个线段 Dialogue: 0,0:04:11.60,0:04:15.64,Default,,0,0,0,,一个以某个向量为起点的线段 Dialogue: 0,0:04:16.06,0:04:28.30,Default,,0,0,0,,比如从向量(2,3)所代表的起点到向量(5,1)所代表的终点的线段 Dialogue: 0,0:04:28.30,0:04:31.82,Default,,0,0,0,,如果我们想表示这条线段 Dialogue: 0,0:04:33.26,0:04:36.20,Default,,0,0,0,,那么我们可以构建一个序对的序对 Dialogue: 0,0:04:40.72,0:04:42.94,Default,,0,0,0,,这样我们就可以表示一条线段了 Dialogue: 0,0:04:42.94,0:04:47.34,Default,,0,0,0,,我们可以编写一个使用CONS构造线段的构造函数 Dialogue: 0,0:04:47.98,0:04:51.60,Default,,0,0,0,,以及 析取出线段起点、终点的选择函数 Dialogue: 0,0:04:55.24,0:04:59.76,Default,,0,0,0,,那么如果我们剥开抽象层一探究竟 Dialogue: 0,0:04:59.88,0:05:02.10,Default,,0,0,0,,就会发现线段不过是 序对组成的序对 Dialogue: 0,0:05:04.66,0:05:06.22,Default,,0,0,0,,它还是一个序对 Dialogue: 0,0:05:06.22,0:05:08.22,Default,,0,0,0,,这里有个线段 Dialogue: 0,0:05:10.00,0:05:16.72,Default,,0,0,0,,它的CAR部分是个序对 CDR部分也是个序对 Dialogue: 0,0:05:18.32,0:05:25.54,Default,,0,0,0,,它的CAR部分是由2和3构成的序对 Dialogue: 0,0:05:26.02,0:05:28.08,Default,,0,0,0,,CDR部分则由5和1构成的序对 Dialogue: 0,0:05:28.16,0:05:29.24,Default,,0,0,0,,这里我再提醒大家一下 Dialogue: 0,0:05:29.32,0:05:33.46,Default,,0,0,0,,好多人认为如果我箭头向下画的话 Dialogue: 0,0:05:33.80,0:05:36.90,Default,,0,0,0,,会有其它的含意 Dialogue: 0,0:05:36.98,0:05:38.28,Default,,0,0,0,,这是不对的 Dialogue: 0,0:05:38.58,0:05:43.90,Default,,0,0,0,,箭头指示的是对象间如何连接 它指向水平或竖直方向都是无关紧要的 Dialogue: 0,0:05:47.48,0:05:52.18,Default,,0,0,0,,还要提醒一下 序对是具有闭包性质的 Dialogue: 0,0:05:52.94,0:06:05.62,Default,,0,0,0,,闭包性质使我们可以构建更复杂的东西 而不仅仅是简单的序对 Dialogue: 0,0:06:06.64,0:06:15.24,Default,,0,0,0,,在这里我要特别指出 在我们用CONS构建出来的序对的基础上 Dialogue: 0,0:06:16.44,0:06:22.64,Default,,0,0,0,,我们也可以进一步用CONS来构造更复杂的对象 Dialogue: 0,0:06:23.28,0:06:31.98,Default,,0,0,0,,或者用数学家的话说 Lisp中的数据对象在CONS运算下是封闭的 Dialogue: 0,0:06:33.82,0:06:36.34,Default,,0,0,0,,这个性质使我们能够构造更加复杂的数据对象 Dialogue: 0,0:06:36.34,0:06:38.04,Default,,0,0,0,,这个似乎是显然的 但是要记住 Dialogue: 0,0:06:39.06,0:06:42.46,Default,,0,0,0,,人们使用的编程语言中有很多东西并不是封闭的 Dialogue: 0,0:06:42.46,0:06:48.06,Default,,0,0,0,,举例来说 Basic和Fortran中的构造数组操作 就不是封闭的 Dialogue: 0,0:06:48.08,0:06:51.94,Default,,0,0,0,,因为 虽然你可以用数字、字符或字符串等来构造数组 Dialogue: 0,0:06:52.04,0:06:54.18,Default,,0,0,0,,但是你不能创建数组的数组 Dialogue: 0,0:06:54.64,0:06:56.68,Default,,0,0,0,,当考察某种组合的方法时 Dialogue: 0,0:06:57.60,0:07:02.78,Default,,0,0,0,,你应该考察该组合方法是否封闭 Dialogue: 0,0:07:05.06,0:07:08.26,Default,,0,0,0,,不管怎样 因为我们可以构造序对的序对 Dialogue: 0,0:07:08.86,0:07:12.78,Default,,0,0,0,,我们就可以用序对将数据以各种各样的方式组合起来 Dialogue: 0,0:07:14.02,0:07:18.26,Default,,0,0,0,,比如我想要组合四个数 -- 1 2 3 4 Dialogue: 0,0:07:18.26,0:07:19.82,Default,,0,0,0,,我有很多方法 Dialogue: 0,0:07:20.74,0:07:26.12,Default,,0,0,0,,比如 像构造线段那样 我可以构造一个序对 Dialogue: 0,0:07:29.02,0:07:36.88,Default,,0,0,0,,它是((1 2) (3 4)) 对吧? Dialogue: 0,0:07:36.88,0:07:40.06,Default,,0,0,0,,或者如果我喜欢 我可以像这样做 Dialogue: 0,0:07:40.06,0:07:45.52,Default,,0,0,0,,我构造一个序对 它的CAR部分也是一个序对 Dialogue: 0,0:07:46.44,0:07:53.20,Default,,0,0,0,,这个序对的CAR部分为1 而CDR部分为由2、3构成的序对 Dialogue: 0,0:07:53.26,0:07:55.08,Default,,0,0,0,,最后 我把4放在这里 Dialogue: 0,0:07:56.92,0:08:02.16,Default,,0,0,0,,所以你可以看到 组合对象的方式有很多种 Dialogue: 0,0:08:02.16,0:08:07.74,Default,,0,0,0,,因此就有必要建立一些统一的约定 Dialogue: 0,0:08:07.74,0:08:11.58,Default,,0,0,0,,使我们能够用某种的通用的方式处理数据 Dialogue: 0,0:08:11.58,0:08:14.00,Default,,0,0,0,,而不用总是针对具体问题做一些生硬的选择 Dialogue: 0,0:08:15.94,0:08:19.04,Default,,0,0,0,,Lisp里面就有这样一种约定 Dialogue: 0,0:08:20.74,0:08:25.82,Default,,0,0,0,,这个约定将一系列的东西表示成一个序对组成的链 Dialogue: 0,0:08:26.78,0:08:28.18,Default,,0,0,0,,而这样一个数据序列就叫做一个“表” Dialogue: 0,0:08:34.72,0:08:40.50,Default,,0,0,0,,表本质上就是Lisp用来表示序列数据的一个约定而已 Dialogue: 0,0:08:40.70,0:08:47.38,Default,,0,0,0,,我可以使用序对的序列来表示序列 1 2 3 4 Dialogue: 0,0:08:48.26,0:08:54.68,Default,,0,0,0,,我把1放在这里 它的CDR指向另一个序对 Dialogue: 0,0:08:59.20,0:09:01.40,Default,,0,0,0,,这个序对的CAR部分是序列中的下一个数 Dialogue: 0,0:09:01.52,0:09:03.42,Default,,0,0,0,,并且它的CDR指向了另一个序对 Dialogue: 0,0:09:05.44,0:09:07.30,Default,,0,0,0,,它的CAR部分是序列的再下一个数 Dialogue: 0,0:09:07.36,0:09:08.44,Default,,0,0,0,,这个是3 Dialogue: 0,0:09:08.44,0:09:09.74,Default,,0,0,0,,以此类推 Dialogue: 0,0:09:09.74,0:09:13.22,Default,,0,0,0,,所以 序列中的每一个元素都对应着一个序对 Dialogue: 0,0:09:15.82,0:09:18.32,Default,,0,0,0,,而当这个序列中没有其它元素时,我用一个特殊的标记 Dialogue: 0,0:09:20.72,0:09:22.74,Default,,0,0,0,,来表示列表中没有元素了 Dialogue: 0,0:09:24.14,0:09:34.64,Default,,0,0,0,,好 这就是将序列中的元素组合起来的一种约定方式 Dialogue: 0,0:09:34.64,0:09:37.98,Default,,0,0,0,,而它其实就是一堆序对 Dialogue: 0,0:09:39.40,0:09:44.80,Default,,0,0,0,,每个序对中的CAR部分就是我们想要组合到一起的元素 Dialogue: 0,0:09:46.00,0:09:48.46,Default,,0,0,0,,这些序对的CDR部分则指向下一个序对 Dialogue: 0,0:09:50.02,0:09:56.04,Default,,0,0,0,,现在 如果我想要构造它 我需要向Lisp中输入 Dialogue: 0,0:09:56.62,0:09:58.76,Default,,0,0,0,,我会像这样来构造 Dialogue: 0,0:09:59.22,0:10:15.28,Default,,0,0,0,,(CONS 1 (CONS 2 (CONS 3 (CONS 4 NIL)))) Dialogue: 0,0:10:15.28,0:10:20.00,Default,,0,0,0,,NIL是序列末尾标志的名字 Dialogue: 0,0:10:20.80,0:10:23.24,Default,,0,0,0,,它是一个特殊的名字 用以标识表的末尾 Dialogue: 0,0:10:26.24,0:10:30.26,Default,,0,0,0,,好 这就是如何构造一个表 Dialogue: 0,0:10:37.54,0:10:41.40,Default,,0,0,0,,如果每次构造一个表时 都要输入像 Dialogue: 0,0:10:41.45,0:10:45.18,Default,,0,0,0,,(CONS 1 (CONS 2 (CONS 3...的话 将会非常费力 Dialogue: 0,0:10:45.18,0:10:50.10,Default,,0,0,0,,因此Lisp提供了一种叫做LIST的操作 Dialogue: 0,0:10:53.70,0:10:57.72,Default,,0,0,0,,LIST其实是这种嵌套CONS的缩写 Dialogue: 0,0:10:58.96,0:11:06.32,Default,,0,0,0,,它可以让我用(LIST 1 2 3 4)来构造表 Dialogue: 0,0:11:07.78,0:11:11.74,Default,,0,0,0,,这只是另外一种方式 一种语法糖衣 Dialogue: 0,0:11:11.94,0:11:14.76,Default,,0,0,0,,用来简便地书写嵌套的CONS Dialogue: 0,0:11:14.76,0:11:17.84,Default,,0,0,0,,(CONS (CONS (CONS (CONS NIL)))) Dialogue: 0,0:11:18.48,0:11:39.78,Default,,0,0,0,,举例来说 我将构造一个表(1 2 3 4) 并把它叫做1-TO-4 Dialogue: 0,0:11:47.96,0:11:53.02,Default,,0,0,0,,注意使用这种简便写法的结果 Dialogue: 0,0:11:53.80,0:11:56.92,Default,,0,0,0,,首先 如果我有这个表(1 2 3 4) Dialogue: 0,0:11:57.36,0:12:02.64,Default,,0,0,0,,表的CAR把部分就是这个表的第一个元素 对吧? Dialogue: 0,0:12:04.06,0:12:05.28,Default,,0,0,0,,那么 如何获得元素2呢? Dialogue: 0,0:12:05.28,0:12:23.94,Default,,0,0,0,,2应该是1-TO-4的CDR部分的CAR部分 Dialogue: 0,0:12:23.98,0:12:29.48,Default,,0,0,0,,它的CDR是这个 Dialogue: 0,0:12:29.82,0:12:31.68,Default,,0,0,0,,而它的CAR部分是2 Dialogue: 0,0:12:32.58,0:12:47.42,Default,,0,0,0,,同理 1-TO-4的CDR的CDR的CAR部分 Dialogue: 0,0:12:47.42,0:12:51.36,Default,,0,0,0,,是3 以此类推 Dialogue: 0,0:12:52.68,0:12:55.84,Default,,0,0,0,,我们来看下屏幕 Dialogue: 0,0:12:57.50,0:13:11.18,Default,,0,0,0,,我定义一个表(1 2 3 4) 命名为1-TO-4 Dialogue: 0,0:13:13.78,0:13:21.28,Default,,0,0,0,,我这样写 计算机返回定义完成 这个就是1-TO-4的定义 Dialogue: 0,0:13:22.30,0:13:36.74,Default,,0,0,0,,我问 比如 1-TO-4的CDR的CDR的CAR Dialogue: 0,0:13:38.34,0:13:42.42,Default,,0,0,0,,嗯 它是3 Dialogue: 0,0:13:44.08,0:13:50.08,Default,,0,0,0,,或者我问 1-TO-4是什么 Dialogue: 0,0:13:51.26,0:13:57.22,Default,,0,0,0,,Lisp输出的是用括号包围的 (1 2 3 4) Dialogue: 0,0:13:57.22,0:14:02.12,Default,,0,0,0,,用括号将表中的元素包围起来的这种记号 Dialogue: 0,0:14:02.12,0:14:08.90,Default,,0,0,0,,通常用来打印输出表示序列的序对链 Dialogue: 0,0:14:08.90,0:14:17.14,Default,,0,0,0,,又比如 我问1-TO-4的CDR部分是什么 Dialogue: 0,0:14:19.30,0:14:21.12,Default,,0,0,0,,结果是表的剩余部分 Dialogue: 0,0:14:21.32,0:14:26.96,Default,,0,0,0,,这是原表首元素所指向的序对 新序列从2开始 Dialogue: 0,0:14:28.52,0:14:37.74,Default,,0,0,0,,比如 1-TO-4的CDR的CDR部分是什么 Dialogue: 0,0:14:43.24,0:14:44.68,Default,,0,0,0,,返回(3 4) Dialogue: 0,0:14:44.82,0:14:59.66,Default,,0,0,0,,或者 1-TO-4的CDR的CDR的CDR的CDR部分是什么 Dialogue: 0,0:15:04.74,0:15:10.46,Default,,0,0,0,,我们看一下表的尾指针 Lisp返回() Dialogue: 0,0:15:10.96,0:15:13.48,Default,,0,0,0,,你们可以认为这是一个空表 Dialogue: 0,0:15:14.12,0:15:21.38,Default,,0,0,0,,我求取 1-TO-4的CDR的CDR的CDR部分 Dialogue: 0,0:15:21.42,0:15:25.20,Default,,0,0,0,,这就只剩下表尾指针本身 Dialogue: 0,0:15:25.20,0:15:27.20,Default,,0,0,0,,它的输出是() Dialogue: 0,0:15:34.14,0:15:39.98,Default,,0,0,0,,好了 这是处理表的一种常见方式 Dialogue: 0,0:15:41.50,0:15:43.44,Default,,0,0,0,,也就是不断地取CDR部分 Dialogue: 0,0:15:43.44,0:15:45.00,Default,,0,0,0,,这个叫做表的CDRING Dialogue: 0,0:15:46.64,0:15:49.78,Default,,0,0,0,,当然手写这些CDR非常费劲 Dialogue: 0,0:15:49.78,0:15:52.24,Default,,0,0,0,,我们没必要这么做 我们编写程序来这么做 Dialogue: 0,0:15:52.96,0:15:59.10,Default,,0,0,0,,事实上 Lisp中非常普遍的事情是写一些过程 Dialogue: 0,0:15:59.85,0:16:06.54,Default,,0,0,0,,表中所有元素进行某种操作 得到的是由结果构成的表 Dialogue: 0,0:16:07.42,0:16:11.92,Default,,0,0,0,,比如 我写一个SCALE-LIST的过程 Dialogue: 0,0:16:16.80,0:16:25.24,Default,,0,0,0,,我要用SCALE-LIST将表1-TO-4放大10倍 Dialogue: 0,0:16:26.66,0:16:35.32,Default,,0,0,0,,那么它应该返回表(10 20 30 40) Dialogue: 0,0:16:38.25,0:16:40.25,Default,,0,0,0,,没错 它返回一个表 Dialogue: 0,0:16:44.49,0:16:49.30,Default,,0,0,0,,我们可以猜想到这当中采用了某种递归策略 Dialogue: 0,0:16:49.30,0:16:51.30,Default,,0,0,0,,我应该如何编写这个过程呢? Dialogue: 0,0:16:52.52,0:16:59.80,Default,,0,0,0,,如果要构建一个每个元素都乘以10的列表 Dialogue: 0,0:17:00.44,0:17:04.84,Default,,0,0,0,,需要做的是—假设已经得到了结果表的剩余元素 Dialogue: 0,0:17:05.86,0:17:08.42,Default,,0,0,0,,也就是表的CDR部分 Dialogue: 0,0:17:08.42,0:17:14.16,Default,,0,0,0,,这个子表中的每个元素都是原来元素乘以10 Dialogue: 0,0:17:16.06,0:17:19.68,Default,,0,0,0,,这是SCALE-LIST对表CDR部分作用的结果 Dialogue: 0,0:17:20.12,0:17:23.82,Default,,0,0,0,,我需要做的 就只有用表的CAR部分乘以10 Dialogue: 0,0:17:24.89,0:17:27.24,Default,,0,0,0,,然后用CONS将它和剩余部分连接起来 并返回这个表 Dialogue: 0,0:17:29.02,0:17:33.09,Default,,0,0,0,,类似地 为了缩放子表 我得先缩放子表的CDR部分 Dialogue: 0,0:17:33.30,0:17:36.20,Default,,0,0,0,,并将其与2*10连接起来 Dialogue: 0,0:17:36.42,0:17:41.16,Default,,0,0,0,,最终 当我处理到表尾时 这里就只剩表尾指针了 Dialogue: 0,0:17:41.72,0:17:45.28,Default,,0,0,0,,它叫做NIL 我就直接返回表尾指针 Dialogue: 0,0:17:45.54,0:17:47.68,Default,,0,0,0,,所以这就是这个过程的递归策略 Dialogue: 0,0:17:47.68,0:17:50.52,Default,,0,0,0,,这个过程就是这样 Dialogue: 0,0:17:50.96,0:17:55.04,Default,,0,0,0,,这个例子就是对表做CDRING操作的通用策略 Dialogue: 0,0:17:55.66,0:17:58.24,Default,,0,0,0,,也就是所谓的“通过CONS组合结果” Dialogue: 0,0:17:58.24,0:18:06.04,Default,,0,0,0,,那么 对表L缩放S倍 我该如何做呢? Dialogue: 0,0:18:06.04,0:18:10.40,Default,,0,0,0,,首先得做判断 Lisp中有个叫NULL?的谓词 Dialogue: 0,0:18:10.40,0:18:13.22,Default,,0,0,0,,NULL?判断对象是否为表尾 Dialogue: 0,0:18:13.90,0:18:17.16,Default,,0,0,0,,或者说 对象是否为空表 Dialogue: 0,0:18:18.17,0:18:23.00,Default,,0,0,0,,任何情况下 当我处理到表尾时 我就将其返回 Dialogue: 0,0:18:23.65,0:18:24.60,Default,,0,0,0,,简单地返回NIL Dialogue: 0,0:18:24.94,0:18:35.14,Default,,0,0,0,,否则 我就用CONS把列表中的第一个元素经过操作(缩放)后的结果 Dialogue: 0,0:18:35.54,0:18:39.29,Default,,0,0,0,,就是说 取L的CAR部分 然后用它乘以S Dialogue: 0,0:18:40.36,0:18:46.34,Default,,0,0,0,,然后我就用CONS将这个结果 与用递归形式缩放后的表的剩下部分 连接在一起 Dialogue: 0,0:18:49.98,0:18:52.18,Default,,0,0,0,,再说一次 总体的思想是 Dialogue: 0,0:18:52.22,0:18:56.09,Default,,0,0,0,,你要用递归的方式处理表中的剩余元素 即表的CDR部分 Dialogue: 0,0:18:56.48,0:19:01.16,Default,,0,0,0,,然后你用CONS将那部分的结果 与经过处理后的表的第一个元素连接在一起 Dialogue: 0,0:19:01.16,0:19:05.18,Default,,0,0,0,,当你处理到结尾的时候 返回表尾标志NIL Dialogue: 0,0:19:07.34,0:19:11.36,Default,,0,0,0,,这就是对一个表中的数据做某种操作的通用模式 Dialogue: 0,0:19:14.05,0:19:19.52,Default,,0,0,0,,现在 你们应该清楚知道这样一个事实 Dialogue: 0,0:19:19.53,0:19:22.62,Default,,0,0,0,,也就是我不必额外为这种基本模式额外编写过程 Dialogue: 0,0:19:22.62,0:19:24.90,Default,,0,0,0,,我要做的事情就是写一个过程 Dialogue: 0,0:19:24.90,0:19:26.32,Default,,0,0,0,,这是这个基本模式 Dialogue: 0,0:19:26.80,0:19:30.30,Default,,0,0,0,,对表中的元素执行操作 并以表的形式返回结果 Dialogue: 0,0:19:30.68,0:19:32.30,Default,,0,0,0,,好了 我们定义一些高阶过程 Dialogue: 0,0:19:32.32,0:19:35.18,Default,,0,0,0,,我们定义一个叫MAP的高阶过程 来完成这些操作 Dialogue: 0,0:19:36.73,0:19:43.17,Default,,0,0,0,,MAP以表L和过程P为参数 Dialogue: 0,0:19:44.92,0:19:51.08,Default,,0,0,0,,并返回对表L中每个元素应用过程P后得到的新表 Dialogue: 0,0:19:51.81,0:19:55.40,Default,,0,0,0,,这个新表里的元素是(P E1) (P E2) ... 到(P En) Dialogue: 0,0:19:55.64,0:20:01.54,Default,,0,0,0,,所以我指的就是对一个表做这样一种变换:将P应用到表的每一个元素上 Dialogue: 0,0:20:02.52,0:20:07.08,Default,,0,0,0,,你们看到的这些过程正是我提到的通用策略 Dialogue: 0,0:20:07.08,0:20:09.08,Default,,0,0,0,,我们用它写乘以10的过程 Dialogue: 0,0:20:09.08,0:20:11.64,Default,,0,0,0,,如果表是空的 则返回NIL Dialogue: 0,0:20:11.86,0:20:16.60,Default,,0,0,0,,否则 对表的首元素应用P Dialogue: 0,0:20:17.14,0:20:18.74,Default,,0,0,0,,将P应用于L的CAR部分 Dialogue: 0,0:20:19.30,0:20:25.40,Default,,0,0,0,,然后连接它和将P应用于表CDR部分中的剩余元素得到的子表连接起来 Dialogue: 0,0:20:25.61,0:20:28.84,Default,,0,0,0,,这就是一个通用过程--MAP Dialogue: 0,0:20:29.86,0:20:39.04,Default,,0,0,0,,我们可以用MAP来定义SCALE-LIST Dialogue: 0,0:20:39.04,0:20:41.04,Default,,0,0,0,,我给你们展示一下 Dialogue: 0,0:20:43.46,0:20:52.50,Default,,0,0,0,,SCALE-LIST就是用MAP在表L上映射一个特定的过程 Dialogue: 0,0:20:52.50,0:20:55.54,Default,,0,0,0,,这个过程需要一个参数 返回给定参数乘以S的结果 Dialogue: 0,0:20:58.96,0:21:01.90,Default,,0,0,0,,所以我思考缩放表这个过程的正确方式应该是 Dialogue: 0,0:21:02.12,0:21:07.40,Default,,0,0,0,,将这种递归实质实现为通用策略 而不是一个具体针对的过程 Dialogue: 0,0:21:07.40,0:21:11.28,Default,,0,0,0,,当然 这样做的意义之一是 是你会开始发现共性 Dialogue: 0,0:21:12.16,0:21:15.02,Default,,0,0,0,,我们正在掌握使用通用模式 Dialogue: 0,0:21:15.96,0:21:31.18,Default,,0,0,0,,比如 (MAP SQUARE 1-TO-4) 返回(1 4 9 16) Dialogue: 0,0:21:32.48,0:21:37.17,Default,,0,0,0,,对这个表做映射 Dialogue: 0,0:21:37.57,0:21:46.32,Default,,0,0,0,,用(LAMBDA (X) (+ X 10))映射表1-TO-4 Dialogue: 0,0:21:49.68,0:21:52.86,Default,,0,0,0,,我让表的每个元素都加了10 Dialogue: 0,0:21:53.34,0:21:58.17,Default,,0,0,0,,也就是得到了(11 12 13 14) Dialogue: 0,0:22:00.56,0:22:05.76,Default,,0,0,0,,我们看到对表中每个元素做操作是一种非常普遍的想法 Dialogue: 0,0:22:08.66,0:22:12.22,Default,,0,0,0,,而大家需要思考如何编写MAP的迭代版本 Dialogue: 0,0:22:12.22,0:22:16.04,Default,,0,0,0,,我碰巧写的是一个递归版本 Dialogue: 0,0:22:16.36,0:22:19.10,Default,,0,0,0,,但是我们也可以很容易地把它改成迭代过程 Dialogue: 0,0:22:19.10,0:22:23.16,Default,,0,0,0,,有趣的是 一旦你开始用MAP来思考 Dialogue: 0,0:22:24.02,0:22:29.00,Default,,0,0,0,,比如 一旦把缩放看作是一种MAP 就不用关心是迭代还是递归实现 Dialogue: 0,0:22:29.00,0:22:31.82,Default,,0,0,0,,你只会关心 啊 这里有这样一种数据集合 有这样一个表 Dialogue: 0,0:22:32.22,0:22:34.52,Default,,0,0,0,,我要做的是转化表中的每个元素 Dialogue: 0,0:22:34.56,0:22:38.36,Default,,0,0,0,,而不去考虑特别的控制流程或顺序 Dialogue: 0,0:22:38.88,0:22:41.09,Default,,0,0,0,,这是个非常非常重要的想法 Dialogue: 0,0:22:42.36,0:22:46.48,Default,,0,0,0,,我猜这个想法来自APL语言 Dialogue: 0,0:22:46.48,0:22:49.10,Default,,0,0,0,,它是APL中非常重要的思想 Dialogue: 0,0:22:49.12,0:22:51.13,Default,,0,0,0,,即不要去考虑控制结构 Dialogue: 0,0:22:51.41,0:22:53.92,Default,,0,0,0,,而是关注于策略操作 Dialogue: 0,0:22:55.01,0:23:00.01,Default,,0,0,0,,在本课程进行到一半的时候 我们将讨论一种叫做流处理的东西 Dialogue: 0,0:23:00.26,0:23:02.64,Default,,0,0,0,,那时我们将看到这种观点的真正威力 Dialogue: 0,0:23:02.64,0:23:05.30,Default,,0,0,0,,这是一种很聪明的思想 Dialogue: 0,0:23:05.30,0:23:08.70,Default,,0,0,0,,我们可以在以后看到更多应用 Dialogue: 0,0:23:09.36,0:23:16.84,Default,,0,0,0,,还有一些非常有用也非常像MAP的过程 Dialogue: 0,0:23:17.56,0:23:22.54,Default,,0,0,0,,MAP是将某个过程应用于表中每个元素 Dialogue: 0,0:23:22.98,0:23:25.62,Default,,0,0,0,,并返回相应结果构成的表 Dialogue: 0,0:23:25.98,0:23:28.69,Default,,0,0,0,,还有一种与此非常非常相似的操作 Dialogue: 0,0:23:29.32,0:23:35.86,Default,,0,0,0,,也就是给定一个列表和操作 依次将其应用于表中每个元素 Dialogue: 0,0:23:36.29,0:23:39.40,Default,,0,0,0,,而不会建立由结果构成的表 只是为了完成操作 Dialogue: 0,0:23:40.02,0:23:45.10,Default,,0,0,0,,这个过程非常像MAP Dialogue: 0,0:23:45.10,0:23:46.02,Default,,0,0,0,,它就是FOR-EACH Dialogue: 0,0:23:46.74,0:23:49.48,Default,,0,0,0,,它接受一个过程和一个表 Dialogue: 0,0:23:49.62,0:23:53.86,Default,,0,0,0,,它实际上是对表中每个元素执行此操作 Dialogue: 0,0:23:55.16,0:23:58.53,Default,,0,0,0,,通常是这样 如果表非空 Dialogue: 0,0:23:59.74,0:24:01.12,Default,,0,0,0,,也就是不为NIL Dialogue: 0,0:24:01.90,0:24:06.25,Default,,0,0,0,,我将这个过程应用于表的第一个元素 Dialogue: 0,0:24:07.68,0:24:11.66,Default,,0,0,0,,然后对表中其余元素做同样的事情 Dialogue: 0,0:24:12.44,0:24:15.25,Default,,0,0,0,,我将FOR-EACH也应用于表的CDR部分 Dialogue: 0,0:24:15.88,0:24:18.73,Default,,0,0,0,,我对表的首元素进行处理 然后对表其余部分进行处理 Dialogue: 0,0:24:19.32,0:24:23.92,Default,,0,0,0,,当然 以此类推 递归地调用 又会对表其余部分的其余部分做处理 Dialogue: 0,0:24:23.92,0:24:28.12,Default,,0,0,0,,最终 过程结束时 我应该告知系统 Dialogue: 0,0:24:28.16,0:24:32.40,Default,,0,0,0,,所以就返回“DONE” 所以这非常像MAP Dialogue: 0,0:24:32.80,0:24:35.12,Default,,0,0,0,,它们之间只是返回值不同 Dialogue: 0,0:24:35.48,0:24:39.90,Default,,0,0,0,,比如说 如果我有一个可以在屏幕上打印对象的过程 Dialogue: 0,0:24:40.56,0:24:45.81,Default,,0,0,0,,如果我想打印表中的所有元素 可以调用(FOR-EACH PRINT LIST) Dialogue: 0,0:24:46.78,0:24:51.33,Default,,0,0,0,,如果我有一系列图表构成的表 想把它们输出在屏幕上 Dialogue: 0,0:24:51.62,0:24:54.86,Default,,0,0,0,,我可以对这个调用(FOR-EACH DISPLAY FIGURES) Dialogue: 0,0:24:58.18,0:24:59.32,Default,,0,0,0,,有问题么? Dialogue: 0,0:25:00.62,0:25:04.26,Default,,0,0,0,,学生:除非你明确地指定 Dialogue: 0,0:25:04.30,0:25:07.54,Default,,0,0,0,,Lisp会创建一个你正在处理的对象的新拷贝 是这样么? Dialogue: 0,0:25:07.54,0:25:09.18,Default,,0,0,0,,教授:对 Dialogue: 0,0:25:09.93,0:25:10.94,Default,,0,0,0,,就是这样 Dialogue: 0,0:25:10.94,0:25:15.14,Default,,0,0,0,,FOR-EACH不创建新列表 它只是对列表的每一个元素进行处理 Dialogue: 0,0:25:15.14,0:25:17.29,Default,,0,0,0,,所以如果你有一堆事情等着做 Dialogue: 0,0:25:18.02,0:25:21.56,Default,,0,0,0,,并且你并不关心这些值 比如打印 绘图 Dialogue: 0,0:25:21.89,0:25:24.60,Default,,0,0,0,,或者在终端中响铃等等 Dialogue: 0,0:25:24.60,0:25:27.64,Default,,0,0,0,,FOR-EACH对表中每个元素做这些事 Dialogue: 0,0:25:28.21,0:25:32.42,Default,,0,0,0,,而MAP其实构建了一个新集合 这个集合也许是你想要用的 Dialogue: 0,0:25:32.42,0:25:34.16,Default,,0,0,0,,这就是它们之间的微妙关系 Dialogue: 0,0:25:34.16,0:25:36.30,Default,,0,0,0,,学生:你能否用FOR-EACH来构造MAP Dialogue: 0,0:25:36.32,0:25:40.16,Default,,0,0,0,,其中你用类似CONS的操作将表又构造出来了? Dialogue: 0,0:25:40.18,0:25:44.46,Default,,0,0,0,,教授:某种程度上 我也许可以 Dialogue: 0,0:25:44.46,0:25:49.98,Default,,0,0,0,,我不知道如何随手写出它 但是我可以给一些思路 Dialogue: 0,0:25:50.48,0:25:54.73,Default,,0,0,0,,学生:根据昨天的课程 我认为MAP和FOR-EACH的关键区别在于 Dialogue: 0,0:25:54.73,0:26:00.62,Default,,0,0,0,,它们之中一个是递归的 而另一个不是 Dialogue: 0,0:26:01.24,0:26:03.86,Default,,0,0,0,,教授:是的 关于MAP和FOR-EACH和递归 Dialogue: 0,0:26:03.86,0:26:05.48,Default,,0,0,0,,这个观点很好 Dialogue: 0,0:26:05.48,0:26:13.08,Default,,0,0,0,,我写的MAP过程恰巧是一个递归过程 Dialogue: 0,0:26:13.82,0:26:17.06,Default,,0,0,0,,这是因为 你需要得到处理完表的剩余部分后的值 Dialogue: 0,0:26:17.08,0:26:20.96,Default,,0,0,0,,使其与表的开头部分相连 Dialogue: 0,0:26:21.73,0:26:24.53,Default,,0,0,0,,但是FOR-EACH不需要等待返回值 Dialogue: 0,0:26:24.84,0:26:26.66,Default,,0,0,0,,所以它变成了一个迭代的过程 Dialogue: 0,0:26:26.66,0:26:27.72,Default,,0,0,0,,这不是本质 Dialogue: 0,0:26:27.72,0:26:31.80,Default,,0,0,0,,我可以用迭代的方式定义MAP过程 Dialogue: 0,0:26:31.82,0:26:32.82,Default,,0,0,0,,只是我没那么做 Dialogue: 0,0:26:34.24,0:26:42.90,Default,,0,0,0,,学生:将FOR-EACH用在一个列表的列表上的话 我想这是可行的吧? Dialogue: 0,0:26:42.90,0:26:48.10,Default,,0,0,0,,它会对这些内部列表的元素进行处理么? Dialogue: 0,0:26:48.70,0:26:50.40,Default,,0,0,0,,教授:问题是 如果我调用 Dialogue: 0,0:26:50.40,0:26:52.28,Default,,0,0,0,,FOR-EACH或者MAP Dialogue: 0,0:26:52.81,0:26:55.28,Default,,0,0,0,,参数是一个嵌套有一个表的表 Dialogue: 0,0:26:56.69,0:27:00.60,Default,,0,0,0,,虽然我们还没有讲过这个 但是那是可行的 Dialogue: 0,0:27:01.02,0:27:06.56,Default,,0,0,0,,答案是肯定的 不过我俩对“可行”的定义可能有些不同 Dialogue: 0,0:27:06.86,0:27:10.65,Default,,0,0,0,,来看一下 如果我给你一个表 Dialogue: 0,0:27:12.80,0:27:14.20,Default,,0,0,0,,而在个箭头所指的 Dialogue: 0,0:27:16.06,0:27:21.46,Default,,0,0,0,,不是一个数 而是一个表 或者序对 或者是其它东西 Dialogue: 0,0:27:21.96,0:27:24.54,Default,,0,0,0,,FOR-EACH对表中的每个元素做处理 Dialogue: 0,0:27:24.54,0:27:26.96,Default,,0,0,0,,它会不断地处理表CDR部分 Dialogue: 0,0:27:26.96,0:27:27.20,Default,,0,0,0,,学生:嗯 Dialogue: 0,0:27:27.20,0:27:31.06,Default,,0,0,0,,教授:对FOR-EACH来说 表中的第一个元素就是这个箭头所指的东西 Dialogue: 0,0:27:31.06,0:27:31.65,Default,,0,0,0,,学生:唔 Dialogue: 0,0:27:31.65,0:27:33.94,Default,,0,0,0,,教授:这对于你要完成的任务而言 也许是对的 也许不是 Dialogue: 0,0:27:33.94,0:27:35.57,Default,,0,0,0,,学生:所以不能进入子表中 Dialogue: 0,0:27:35.57,0:27:36.91,Default,,0,0,0,,教授:绝对不能 Dialogue: 0,0:27:36.91,0:27:38.51,Default,,0,0,0,,当然我也可以那样写程序 Dialogue: 0,0:27:38.51,0:27:42.97,Default,,0,0,0,,你所说的是另一种公共模式 叫做树递归 Dialogue: 0,0:27:43.01,0:27:47.94,Default,,0,0,0,,当你给它一个表 它会不断向深度递归 直到遇到所谓的“树叶” Dialogue: 0,0:27:47.94,0:27:51.05,Default,,0,0,0,,你可以写出来这个过程 但是它既不是FOR-EACH也不是MAP Dialogue: 0,0:27:52.42,0:27:55.05,Default,,0,0,0,,FOR-EACH和MAP都很简单 Dialogue: 0,0:27:55.77,0:27:56.89,Default,,0,0,0,,好 还有问题么? Dialogue: 0,0:27:57.68,0:27:58.57,Default,,0,0,0,,好的 大家休息一下吧 Dialogue: 0,0:27:59.11,0:28:10.99,Default,,0,0,0,,[音乐] Dialogue: 0,0:28:11.46,0:28:14.29,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:28:14.32,0:28:17.52,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:28:27.38,0:28:34.22,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:28:34.86,0:28:38.58,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson-Escher的例子 Dialogue: 0,0:28:41.94,0:28:48.65,Default,,0,0,0,,教授:我将在本节课余下的时间中 讨论一个实例 Dialogue: 0,0:28:50.04,0:28:53.92,Default,,0,0,0,,这个实例 可以充分地总结我们所学的所有东西 Dialogue: 0,0:28:54.74,0:28:56.29,Default,,0,0,0,,比如 表结构 Dialogue: 0,0:28:57.17,0:28:59.48,Default,,0,0,0,,以及抽象的技术 Dialogue: 0,0:28:59.54,0:29:00.82,Default,,0,0,0,,数据的表示 Dialogue: 0,0:29:01.60,0:29:04.60,Default,,0,0,0,,和用高阶过程描绘共性 Dialogue: 0,0:29:04.60,0:29:09.80,Default,,0,0,0,,也会介绍目前为止还没怎么谈论过的 Dialogue: 0,0:29:09.85,0:29:13.46,Default,,0,0,0,,也就是这门课的第三大主题 Dialogue: 0,0:29:13.96,0:29:15.53,Default,,0,0,0,,元语言抽象 Dialogue: 0,0:29:15.54,0:29:21.90,Default,,0,0,0,,这种在工程设计中控制复杂度的思想 Dialogue: 0,0:29:22.86,0:29:25.80,Default,,0,0,0,,也就是建立一个合适而强大的语言 Dialogue: 0,0:29:28.17,0:29:34.74,Default,,0,0,0,,你们或许记得 我说过在这门课程中 你们将要学到的最重要的事情是 Dialogue: 0,0:29:34.74,0:29:41.17,Default,,0,0,0,,当我们考察一门语言时 关心的是它的基本元素 Dialogue: 0,0:29:42.98,0:29:46.69,Default,,0,0,0,,关心它的组合方法 Dialogue: 0,0:29:49.72,0:29:52.80,Default,,0,0,0,,关心那些让你能够构建更大东西的东西 Dialogue: 0,0:29:53.61,0:29:55.24,Default,,0,0,0,,以及 抽象的方式 Dialogue: 0,0:30:00.97,0:30:05.16,Default,,0,0,0,,如何取用这些你构造出来的“大东西” Dialogue: 0,0:30:05.56,0:30:07.97,Default,,0,0,0,,并将它们放入“黑盒”中 Dialogue: 0,0:30:08.45,0:30:11.71,Default,,0,0,0,,然后用它们来构建更复杂的东西 Dialogue: 0,0:30:13.53,0:30:18.72,Default,,0,0,0,,我将要介绍的一种语言 就是元语言抽象的一个例子 Dialogue: 0,0:30:18.73,0:30:22.70,Default,,0,0,0,,那是我朋友Peter Handerson发明的 Dialogue: 0,0:30:28.24,0:30:31.74,Default,,0,0,0,,他来自苏格兰的Stirling大学 Dialogue: 0,0:30:32.78,0:30:40.98,Default,,0,0,0,,这个语言是用来画这样的图 Dialogue: 0,0:30:41.86,0:30:46.66,Default,,0,0,0,,这是埃舍尔的木版画 《方形极限》 Dialogue: 0,0:30:49.33,0:30:57.94,Default,,0,0,0,,正如大家所见 这里面有着很复杂的...图像的递归 Dialogue: 0,0:30:58.84,0:31:01.46,Default,,0,0,0,,其中中间的鱼形图案以自相似的方式 Dialogue: 0,0:31:01.70,0:31:04.56,Default,,0,0,0,,不断地以更小的形式出现在原来的图案旁边 Dialogue: 0,0:31:08.49,0:31:12.80,Default,,0,0,0,,总之 Peter Hendersion的语言是用来表述这类图形 Dialogue: 0,0:31:13.37,0:31:18.28,Default,,0,0,0,,并且设计类似的图形 将它画在显示器上 Dialogue: 0,0:31:20.24,0:31:27.48,Default,,0,0,0,,这个例子还展示了另外一个主题 Dialogue: 0,0:31:28.09,0:31:32.02,Default,,0,0,0,,这也是我跟Gerry教授多次强调的 Dialogue: 0,0:31:32.02,0:31:36.17,Default,,0,0,0,,也就是过程跟数据之间没有本质的区别 Dialogue: 0,0:31:37.26,0:31:42.40,Default,,0,0,0,,不管如何 我希望今早课程结束后 Dialogue: 0,0:31:42.58,0:31:47.60,Default,,0,0,0,,你们能将过程和数据当作一回事儿 Dialogue: 0,0:31:47.96,0:31:49.58,Default,,0,0,0,,即使现在你们还将它们区别对待 Dialogue: 0,0:31:50.80,0:31:55.28,Default,,0,0,0,,那么 先让我们看一下Peter的语言 Dialogue: 0,0:31:55.28,0:31:57.26,Default,,0,0,0,,我先告诉你们基本元素是什么 Dialogue: 0,0:31:58.29,0:32:00.92,Default,,0,0,0,,这个语言非常简单 因为它的基本元素只有一个 Dialogue: 0,0:32:03.33,0:32:06.30,Default,,0,0,0,,这个基本元素不是大家想象的那样 Dialogue: 0,0:32:07.08,0:32:09.18,Default,,0,0,0,,它唯一的基本元素叫做"图像" Dialogue: 0,0:32:09.70,0:32:12.11,Default,,0,0,0,,但此“图像”非彼“图像” Dialogue: 0,0:32:12.11,0:32:14.17,Default,,0,0,0,,具体地来说 Dialogue: 0,0:32:14.17,0:32:15.17,Default,,0,0,0,,这是George的图像 Dialogue: 0,0:32:19.01,0:32:20.37,Default,,0,0,0,,我们的想法是 Dialogue: 0,0:32:22.33,0:32:24.57,Default,,0,0,0,,在这个语言中的图像是这样一个东西 Dialogue: 0,0:32:24.89,0:32:31.46,Default,,0,0,0,,它能在你指定的一个矩形里画出一个缩放好图像 Dialogue: 0,0:32:33.00,0:32:34.42,Default,,0,0,0,,这里大家看到的强调线 Dialogue: 0,0:32:34.42,0:32:37.70,Default,,0,0,0,,是这个矩形的轮廓 但不是图像的一部分 Dialogue: 0,0:32:40.49,0:32:47.17,Default,,0,0,0,,但是一旦指定一个矩形区域 图像会以以填充的方式绘制满区域 Dialogue: 0,0:32:47.17,0:32:52.16,Default,,0,0,0,,比如 这个是George 在这里 这个也是George Dialogue: 0,0:32:53.21,0:32:56.65,Default,,0,0,0,,它是同一个图像 只是缩放程度不同 Dialogue: 0,0:32:57.40,0:32:59.28,Default,,0,0,0,,这是“胖”George的版本 Dialogue: 0,0:33:00.01,0:33:03.44,Default,,0,0,0,,这个也是George Dialogue: 0,0:33:03.81,0:33:05.14,Default,,0,0,0,,这是同一个图形 Dialogue: 0,0:33:05.14,0:33:09.57,Default,,0,0,0,,这个语言中 这三个都是同一个图像 Dialogue: 0,0:33:09.58,0:33:13.04,Default,,0,0,0,,仅仅是给了不同的矩形区域让它来填充 Dialogue: 0,0:33:16.08,0:33:20.65,Default,,0,0,0,,这就是基本元素 Dialogue: 0,0:33:21.44,0:33:25.25,Default,,0,0,0,,现在 我们来讨论元素组合和操作 Dialogue: 0,0:33:25.90,0:33:30.17,Default,,0,0,0,,比如 这里有一个叫做旋转的操作 Dialogue: 0,0:33:31.09,0:33:33.66,Default,,0,0,0,,如果我有一个图像 “旋转”操作就是 Dialogue: 0,0:33:35.37,0:33:39.93,Default,,0,0,0,,先假定有一个里面有个“A”的矩形 Dialogue: 0,0:33:41.84,0:33:45.73,Default,,0,0,0,,而旋转90度的操作则会 Dialogue: 0,0:33:47.02,0:33:50.65,Default,,0,0,0,,在一个给定的矩形内 绘制同样的图像 Dialogue: 0,0:33:50.65,0:33:53.88,Default,,0,0,0,,但是 会缩放图像以适应矩形 Dialogue: 0,0:33:56.11,0:33:58.34,Default,,0,0,0,,这个就是旋转90度 Dialogue: 0,0:33:58.34,0:34:03.20,Default,,0,0,0,,另一个操作是“翻转” 可以水平翻转也可以竖直翻转 Dialogue: 0,0:34:04.77,0:34:06.00,Default,,0,0,0,,就是这些操作了 Dialogue: 0,0:34:06.01,0:34:10.40,Default,,0,0,0,,或者你可以把它们认为是组合一个元素的各种方式 Dialogue: 0,0:34:10.89,0:34:12.42,Default,,0,0,0,,我可以把它们混合起来 Dialogue: 0,0:34:13.44,0:34:15.54,Default,,0,0,0,,我们有一种叫BESIDE的操作 Dialogue: 0,0:34:16.46,0:34:24.78,Default,,0,0,0,,它做的事情是 给定两个图像A、B -- Dialogue: 0,0:34:29.02,0:34:33.25,Default,,0,0,0,,这里图像是指能在指定的矩形中画一个图案的东西 -- Dialogue: 0,0:34:34.05,0:34:36.51,Default,,0,0,0,,BESIDE将会做的事情 Dialogue: 0,0:34:37.85,0:34:44.08,Default,,0,0,0,,类似于调用(BESIDE A B S) 其中S是一个数 Dialogue: 0,0:34:45.34,0:34:48.08,Default,,0,0,0,,是一个在0到1之间的数 Dialogue: 0,0:34:50.51,0:34:52.57,Default,,0,0,0,,BESIDE绘制像这样的图像 Dialogue: 0,0:34:52.57,0:34:56.71,Default,,0,0,0,,以给定的矩形为基础 但会将基底缩放S Dialogue: 0,0:34:56.71,0:34:58.71,Default,,0,0,0,,这里S是0.5 Dialogue: 0,0:35:00.18,0:35:07.17,Default,,0,0,0,,在这里 它会在这里画第一个图案 Dialogue: 0,0:35:07.81,0:35:12.65,Default,,0,0,0,,在这里画第二个图案 Dialogue: 0,0:35:13.82,0:35:16.44,Default,,0,0,0,,又比如说 我另设一个S的值 Dialogue: 0,0:35:16.81,0:35:23.02,Default,,0,0,0,,比如调用(BESIDE A B 0.25) Dialogue: 0,0:35:25.94,0:35:29.09,Default,,0,0,0,,效果相同 只不过A更瘦了 Dialogue: 0,0:35:34.05,0:35:36.28,Default,,0,0,0,,而B是这样的 Dialogue: 0,0:35:37.82,0:35:40.29,Default,,0,0,0,,这就是组合方法之一:BESIDE Dialogue: 0,0:35:40.68,0:35:46.05,Default,,0,0,0,,类似地 ABOVE方法在竖直方向上做这种操作 Dialogue: 0,0:35:47.84,0:35:48.89,Default,,0,0,0,,我们来看一下 Dialogue: 0,0:35:50.74,0:35:56.00,Default,,0,0,0,,这是George和他的"弟弟" Dialogue: 0,0:35:56.72,0:36:07.05,Default,,0,0,0,,这是通过将George放在一旁 Dialogue: 0,0:36:10.36,0:36:14.42,Default,,0,0,0,,George与空图像的上下组合放在另一旁 Dialogue: 0,0:36:14.52,0:36:16.14,Default,,0,0,0,,这样做的意图很明显 Dialogue: 0,0:36:16.14,0:36:19.14,Default,,0,0,0,,空图像放在了另一个George的上面 Dialogue: 0,0:36:19.14,0:36:21.14,Default,,0,0,0,,合成的图像又放在了George的旁边 Dialogue: 0,0:36:28.96,0:36:30.34,Default,,0,0,0,,这个是图像P Dialogue: 0,0:36:31.10,0:36:39.04,Default,,0,0,0,,像之前一样 是George和翻转后George的BESIDE组合 Dialogue: 0,0:36:40.53,0:36:42.08,Default,,0,0,0,,这里 我们做的是水平翻转 Dialogue: 0,0:36:42.37,0:36:44.80,Default,,0,0,0,,然后整体旋转180度 Dialogue: 0,0:36:45.80,0:36:50.82,Default,,0,0,0,,然后调用BESIDE让它们组合在一起 系数是0.5 Dialogue: 0,0:36:52.56,0:36:53.90,Default,,0,0,0,,这样 我创建了图像P Dialogue: 0,0:36:55.90,0:36:57.88,Default,,0,0,0,,然后使用图像P Dialogue: 0,0:36:59.21,0:37:04.96,Default,,0,0,0,,与它的翻转图像做ABOVE操作 形成图像Q Dialogue: 0,0:37:09.20,0:37:13.26,Default,,0,0,0,,请注意 我们是如何快速地增加复杂度 Dialogue: 0,0:37:14.36,0:37:21.05,Default,,0,0,0,,转瞬之间 我们使用George组合得到了Q 这说明了什么? Dialogue: 0,0:37:22.05,0:37:24.55,Default,,0,0,0,,为什么我们可以做得如此迅速呢? Dialogue: 0,0:37:25.85,0:37:28.02,Default,,0,0,0,,答案是闭包性质 Dialogue: 0,0:37:28.69,0:37:32.98,Default,,0,0,0,,这是因为 当我将两个图像做BESIDE操作后 Dialogue: 0,0:37:34.30,0:37:35.29,Default,,0,0,0,,得到的也是图像 Dialogue: 0,0:37:35.33,0:37:37.78,Default,,0,0,0,,我可以继续执行 ROTATE FLIP 或者 ABOVE操作 Dialogue: 0,0:37:39.17,0:37:40.88,Default,,0,0,0,,而操作的结果P Dialogue: 0,0:37:40.89,0:37:44.88,Default,,0,0,0,,BESIDE FLIP ROTATE操作的结果也是一个图像 Dialogue: 0,0:37:45.22,0:37:50.20,Default,,0,0,0,,在这种组合方法下 图像的世界是封闭的 Dialogue: 0,0:37:50.77,0:37:52.24,Default,,0,0,0,,所以 任何时候我都可以 Dialogue: 0,0:37:52.48,0:37:55.17,Default,,0,0,0,,以一个东西为基本元素 去构造别的东西 Dialogue: 0,0:37:56.33,0:37:58.52,Default,,0,0,0,,这个例子比表和线段更直观 Dialogue: 0,0:37:58.54,0:38:03.28,Default,,0,0,0,,它揭示了 我们如和用封闭的操作 快速增加复杂度 Dialogue: 0,0:38:07.48,0:38:12.02,Default,,0,0,0,,在构建更多东西之前 Dialogue: 0,0:38:12.04,0:38:14.77,Default,,0,0,0,,我们先来看看这个语言是如何实现的 Dialogue: 0,0:38:16.91,0:38:21.50,Default,,0,0,0,,其中基本的一个元素 Dialogue: 0,0:38:21.93,0:38:24.52,Default,,0,0,0,,是一个称作“矩形”的东西 Dialogue: 0,0:38:26.09,0:38:28.28,Default,,0,0,0,,所谓的矩形就是 Dialogue: 0,0:38:28.28,0:38:33.68,Default,,0,0,0,,它有一个原点 Dialogue: 0,0:38:36.45,0:38:40.18,Default,,0,0,0,,原点是一个向量 用以说明矩形是从哪开始 Dialogue: 0,0:38:40.18,0:38:42.29,Default,,0,0,0,,至于其它的向量 Dialogue: 0,0:38:43.66,0:38:46.33,Default,,0,0,0,,我们称其为矩形的水平分量 Dialogue: 0,0:38:55.76,0:38:59.25,Default,,0,0,0,,还有就是矩形的竖直分量 Dialogue: 0,0:39:00.49,0:39:02.68,Default,,0,0,0,,这就是构成矩形的三个基本元素 Dialogue: 0,0:39:02.68,0:39:04.51,Default,,0,0,0,,两个向量用作 Dialogue: 0,0:39:04.93,0:39:09.97,Default,,0,0,0,,计算左上角和右下角的顶点坐标 Dialogue: 0,0:39:09.97,0:39:12.37,Default,,0,0,0,,这三个向量确定了一个矩形 Dialogue: 0,0:39:16.00,0:39:18.93,Default,,0,0,0,,为了构建矩形 我们假设 Dialogue: 0,0:39:19.77,0:39:22.06,Default,,0,0,0,,假设有个“构建矩形”的构造函数 Dialogue: 0,0:39:23.01,0:39:24.26,Default,,0,0,0,,也就是MAKE-RECT Dialogue: 0,0:39:27.56,0:39:35.17,Default,,0,0,0,,以及选择函数 HORIZ、VERT 和 ORIGIN Dialogue: 0,0:39:37.58,0:39:39.65,Default,,0,0,0,,用于取得对应的矩形属性 Dialogue: 0,0:39:39.65,0:39:42.54,Default,,0,0,0,,我们知道有很多方法可以实现它 Dialogue: 0,0:39:42.54,0:39:47.62,Default,,0,0,0,,可以用序对或者表 或者其它东西 Dialogue: 0,0:39:47.62,0:39:51.40,Default,,0,0,0,,但是 这些东西的实现是George的事 Dialogue: 0,0:39:51.40,0:39:53.17,Default,,0,0,0,,这是一个数据表示的问题 Dialogue: 0,0:39:53.17,0:39:55.47,Default,,0,0,0,,现在我们假设已经有了这些矩形了 Dialogue: 0,0:39:59.05,0:40:05.08,Default,,0,0,0,,好的 现在来看我们接下来要做的事情 Dialogue: 0,0:40:05.08,0:40:08.22,Default,,0,0,0,,我们需要关心如何取用图像 Dialogue: 0,0:40:09.33,0:40:12.97,Default,,0,0,0,,将它缩放以适应你给定的矩形 Dialogue: 0,0:40:13.60,0:40:16.60,Default,,0,0,0,,我们要来安排这些事 Dialogue: 0,0:40:16.60,0:40:18.60,Default,,0,0,0,,来完成图像的缩放 Dialogue: 0,0:40:22.22,0:40:23.65,Default,,0,0,0,,有哪些思路呢? Dialogue: 0,0:40:23.65,0:40:27.08,Default,,0,0,0,,一种想法是:无论何时给定一个矩形 Dialogue: 0,0:40:35.68,0:40:38.68,Default,,0,0,0,,无论何时给定一个矩形 也就是说 Dialogue: 0,0:40:39.25,0:40:45.77,Default,,0,0,0,,这在某种意义上是把正方形转换成矩形 Dialogue: 0,0:40:45.77,0:40:46.54,Default,,0,0,0,,也就是说 Dialogue: 0,0:40:46.54,0:40:48.53,Default,,0,0,0,,我所谓的正方形 Dialogue: 0,0:40:49.04,0:40:59.04,Default,,0,0,0,,它的坐标是(0,0)、(1,0)和(1,1) Dialogue: 0,0:41:01.40,0:41:05.72,Default,,0,0,0,,我们有一些显而易见的缩放变换 Dialogue: 0,0:41:06.12,0:41:10.22,Default,,0,0,0,,可以把这个映射成这个 把这个映射成这个 Dialogue: 0,0:41:10.24,0:41:12.08,Default,,0,0,0,,并且 把所有的东西统一地拉伸 Dialogue: 0,0:41:12.17,0:41:18.25,Default,,0,0,0,,我们将这样的一条的线段 Dialogue: 0,0:41:19.73,0:41:24.20,Default,,0,0,0,,将它最终映射到像那样的一条线段 Dialogue: 0,0:41:26.20,0:41:32.68,Default,,0,0,0,,而点(X,Y)变成了这里的另外一个点 Dialogue: 0,0:41:32.68,0:41:39.37,Default,,0,0,0,,这个不打紧 会点儿向量运算 就能写出变换公式 Dialogue: 0,0:41:39.37,0:41:43.18,Default,,0,0,0,,初始点(X,Y)将会变换到的点的坐标是 Dialogue: 0,0:41:43.58,0:41:50.74,Default,,0,0,0,,以矩形原点为基础做向量加法 Dialogue: 0,0:41:51.16,0:41:55.48,Default,,0,0,0,,加上 初始点X坐标 一个介于0和1之间的值 Dialogue: 0,0:41:55.98,0:42:01.84,Default,,0,0,0,,并乘上矩形的水平向量 Dialogue: 0,0:42:07.62,0:42:11.00,Default,,0,0,0,,再加上初始点的Y坐标 也是一个介于0和1的值 Dialogue: 0,0:42:11.38,0:42:16.28,Default,,0,0,0,,并乘上矩形的竖直向量 Dialogue: 0,0:42:16.74,0:42:19.31,Default,,0,0,0,,这是简单的线性代数 Dialogue: 0,0:42:19.31,0:42:23.48,Default,,0,0,0,,这个就是正确的变换公式 Dialogue: 0,0:42:23.69,0:42:28.18,Default,,0,0,0,,它将方形中的物件转化到对应矩形中 Dialogue: 0,0:42:31.34,0:42:34.02,Default,,0,0,0,,现在 我们把它看作是一个过程 Dialogue: 0,0:42:35.16,0:42:36.29,Default,,0,0,0,,我们想要得到的是 Dialogue: 0,0:42:37.80,0:42:40.82,Default,,0,0,0,,由一个单位正方形到特定矩形的 Dialogue: 0,0:42:41.01,0:42:42.52,Default,,0,0,0,,特定变换过程 Dialogue: 0,0:42:43.80,0:42:45.22,Default,,0,0,0,,这个过程具体是这样的 Dialogue: 0,0:42:45.22,0:42:47.22,Default,,0,0,0,,我叫它COORD-MAP Dialogue: 0,0:42:47.77,0:42:52.00,Default,,0,0,0,,COORD-MAP以一个矩形作为参数 Dialogue: 0,0:42:53.60,0:42:57.85,Default,,0,0,0,,它返回一个以点为参数的过程 Dialogue: 0,0:43:00.45,0:43:06.82,Default,,0,0,0,,每个矩形 都对应一个变换点(X, Y)坐标的过程 Dialogue: 0,0:43:06.82,0:43:08.02,Default,,0,0,0,,是怎么得到的呢? Dialogue: 0,0:43:08.02,0:43:10.92,Default,,0,0,0,,就如黑板上的Lisp代码所示 Dialogue: 0,0:43:10.92,0:43:16.01,Default,,0,0,0,,我让矩形的原点加上-- Dialogue: 0,0:43:20.22,0:43:25.02,Default,,0,0,0,,首先是 矩形水平部分 Dialogue: 0,0:43:25.02,0:43:27.68,Default,,0,0,0,,按照点POINT的X坐标缩放 Dialogue: 0,0:43:29.65,0:43:32.62,Default,,0,0,0,,然后是 矩形竖直部分 Dialogue: 0,0:43:33.51,0:43:37.14,Default,,0,0,0,,按照点POINT的Y坐标缩放 Dialogue: 0,0:43:37.14,0:43:39.14,Default,,0,0,0,,然后把它们三个加到一起 Dialogue: 0,0:43:40.13,0:43:41.34,Default,,0,0,0,,这个过程就是这样 Dialogue: 0,0:43:41.34,0:43:44.54,Default,,0,0,0,,这就是我将要应用在点POINT上的过程 Dialogue: 0,0:43:46.54,0:43:52.17,Default,,0,0,0,,这个过程由每个矩形自己生成 Dialogue: 0,0:43:52.17,0:43:57.25,Default,,0,0,0,,每个矩形对应了一个定义在点集上的过程 COORD-MAP Dialogue: 0,0:44:06.66,0:44:10.42,Default,,0,0,0,,比如说 这里的George Dialogue: 0,0:44:11.36,0:44:16.34,Default,,0,0,0,,最初的George 可能是我在单位正方形中通过线段绘制的 Dialogue: 0,0:44:19.50,0:44:21.96,Default,,0,0,0,,而当我把它应用到一个新的矩形中 Dialogue: 0,0:44:24.14,0:44:28.17,Default,,0,0,0,,我将会在新矩形中画出组成George的那些线段来 Dialogue: 0,0:44:28.17,0:44:29.88,Default,,0,0,0,,我是怎么做的呢? Dialogue: 0,0:44:30.68,0:44:36.94,Default,,0,0,0,,我枚举原始George中的每条线段 Dialogue: 0,0:44:38.64,0:44:40.58,Default,,0,0,0,,我对每条线段的终点 Dialogue: 0,0:44:40.88,0:44:44.45,Default,,0,0,0,,应用目标矩形对应的COORD-MAP过程 Dialogue: 0,0:44:44.45,0:44:46.06,Default,,0,0,0,,比如下面的这个矩形 Dialogue: 0,0:44:46.66,0:44:50.88,Default,,0,0,0,,这个胖George 有它对应的COORD-MAP Dialogue: 0,0:44:51.25,0:44:53.69,Default,,0,0,0,,如果我要绘制这个图像 Dialogue: 0,0:44:55.38,0:44:57.92,Default,,0,0,0,,需要做的就是对这里的每条线段 比如这条 Dialogue: 0,0:44:59.29,0:45:05.34,Default,,0,0,0,,用COORD-MAP变换这个点 同时变换这个点 Dialogue: 0,0:45:05.34,0:45:07.09,Default,,0,0,0,,我就得到了这两个点 Dialogue: 0,0:45:07.38,0:45:08.94,Default,,0,0,0,,就可以将在两点之间画线 Dialogue: 0,0:45:09.71,0:45:11.52,Default,,0,0,0,,这就是核心思路 Dialogue: 0,0:45:12.66,0:45:14.78,Default,,0,0,0,,那么如果我给一个不同的矩形 比如这个 Dialogue: 0,0:45:14.80,0:45:15.76,Default,,0,0,0,,得到的是不同的COORD-MAP Dialogue: 0,0:45:15.79,0:45:17.84,Default,,0,0,0,,因此我得到这些线段的不同图像 Dialogue: 0,0:45:19.28,0:45:22.14,Default,,0,0,0,,基本图像又该如何表示呢? Dialogue: 0,0:45:22.14,0:45:26.52,Default,,0,0,0,,可以用线段组成的表来表示 Dialogue: 0,0:45:27.61,0:45:32.20,Default,,0,0,0,,这是用于构建我所谓的“基本图像”的过程 Dialogue: 0,0:45:33.48,0:45:37.17,Default,,0,0,0,,意思是 没有用BESIDE ROTATE等操作 Dialogue: 0,0:45:37.52,0:45:39.60,Default,,0,0,0,,它以由线段组成的表为参数 Dialogue: 0,0:45:42.94,0:45:44.04,Default,,0,0,0,,代码具体行为如下 Dialogue: 0,0:45:44.04,0:45:45.58,Default,,0,0,0,,图像会是什么样子呢? Dialogue: 0,0:45:45.58,0:45:49.44,Default,,0,0,0,,首先 它是一个根据矩形定义的过程 Dialogue: 0,0:45:51.70,0:45:53.00,Default,,0,0,0,,这个过程做什么呢? Dialogue: 0,0:45:53.00,0:45:56.56,Default,,0,0,0,,对于由线段组成的表中每个元素 Dialogue: 0,0:45:57.66,0:46:03.38,Default,,0,0,0,,表中的每条线段S Dialogue: 0,0:46:05.89,0:46:07.30,Default,,0,0,0,,都绘制了一条线 Dialogue: 0,0:46:07.30,0:46:08.82,Default,,0,0,0,,它画什么样的线段呢? Dialogue: 0,0:46:10.60,0:46:12.84,Default,,0,0,0,,先得到线段的起点 Dialogue: 0,0:46:15.22,0:46:17.94,Default,,0,0,0,,用对应的COORD-MAP对其做变换 Dialogue: 0,0:46:19.54,0:46:21.76,Default,,0,0,0,,这是我们想要的第一个点 Dialogue: 0,0:46:21.76,0:46:26.32,Default,,0,0,0,,然后对线段终点做COORD-MAP操作 Dialogue: 0,0:46:26.69,0:46:27.92,Default,,0,0,0,,并将两点连线 Dialogue: 0,0:46:27.92,0:46:30.84,Default,,0,0,0,,我们假设在屏幕上绘制线段是基本操作 Dialogue: 0,0:46:31.09,0:46:33.22,Default,,0,0,0,,已经在系统中实现了 Dialogue: 0,0:46:33.96,0:46:37.10,Default,,0,0,0,,通过COORD-MAP变换了线段终点 Dialogue: 0,0:46:37.13,0:46:38.20,Default,,0,0,0,,再把起点和终点连线 Dialogue: 0,0:46:39.61,0:46:44.12,Default,,0,0,0,,对表中每一条线段S都执行这样的操作 Dialogue: 0,0:46:45.96,0:46:51.40,Default,,0,0,0,,请注意 图像就是一个以矩形为参数的过程 Dialogue: 0,0:46:51.40,0:46:55.65,Default,,0,0,0,,所以当你给图像一个矩形时 它就像这样绘制线段 Dialogue: 0,0:46:57.17,0:47:01.10,Default,,0,0,0,,那好 我应该如何使用它呢? Dialogue: 0,0:47:01.22,0:47:04.08,Default,,0,0,0,,我来说得具体一点 Dialogue: 0,0:47:05.60,0:47:24.22,Default,,0,0,0,,就比如说 (DEFINE R (MAKE-RECT ...)) Dialogue: 0,0:47:24.50,0:47:28.66,Default,,0,0,0,,这里需要用MAKE-VECTOR来构造一些向量 Dialogue: 0,0:47:29.84,0:47:46.18,Default,,0,0,0,,然后定义G为 (DEFINE G (MAKE-PICT ...)) Dialogue: 0,0:47:46.68,0:47:55.28,Default,,0,0,0,,我要在这里使用MAKE-SEGMENT来构建线段组成的表 Dialogue: 0,0:47:55.28,0:47:58.70,Default,,0,0,0,,MAKE-SEGMENT由向量构成 向量由点构成 Dialogue: 0,0:47:59.50,0:48:04.60,Default,,0,0,0,,如果我想在一个矩形中呈现图像G Dialogue: 0,0:48:04.65,0:48:11.72,Default,,0,0,0,,注意 图像是一个过程 它接受一个矩形作为参数 Dialogue: 0,0:48:12.06,0:48:16.37,Default,,0,0,0,,所以 如果我调用(G R) Dialogue: 0,0:48:17.96,0:48:23.25,Default,,0,0,0,,那么无论G是什么 都会在矩形R中绘制出来 Dialogue: 0,0:48:23.62,0:48:25.62,Default,,0,0,0,,这就是我们如何使用它 Dialogue: 0,0:48:26.86,0:48:36.29,Default,,0,0,0,,[音乐] Dialogue: 0,0:48:36.29,0:48:39.78,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:48:39.82,0:48:43.54,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:48:51.28,0:48:55.45,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:48:55.50,0:48:58.73,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:48:59.34,0:49:03.02,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson-Escher的例子 Dialogue: 0,0:49:07.72,0:49:12.48,Default,,0,0,0,,教授:为什么我说这个例子很好呢? Dialogue: 0,0:49:12.48,0:49:13.74,Default,,0,0,0,,也许你们不这么认为 Dialogue: 0,0:49:13.74,0:49:15.42,Default,,0,0,0,,你们可能觉得它很奇怪 Dialogue: 0,0:49:15.42,0:49:20.92,Default,,0,0,0,,用来矩形做复杂变换的过程来表示图像 确实奇怪 Dialogue: 0,0:49:20.92,0:49:22.72,Default,,0,0,0,,那么 它好在哪里呢? Dialogue: 0,0:49:25.36,0:49:26.69,Default,,0,0,0,,原因就是 Dialogue: 0,0:49:27.22,0:49:30.40,Default,,0,0,0,,一旦你按这种方法实现了基本元素 Dialogue: 0,0:49:30.97,0:49:35.20,Default,,0,0,0,,组合的方法就是构造Lisp过程 Dialogue: 0,0:49:35.98,0:49:37.48,Default,,0,0,0,,我给你们演示一下 Dialogue: 0,0:49:37.48,0:49:39.02,Default,,0,0,0,,假设我想实现BESIDE Dialogue: 0,0:49:41.56,0:49:47.36,Default,,0,0,0,,我要做的是 假设有个叫P1的图像 Dialogue: 0,0:49:47.36,0:49:50.62,Default,,0,0,0,,一定要记得:图像本质上是一个过程 Dialogue: 0,0:49:50.62,0:49:54.82,Default,,0,0,0,,当你传递给它一个矩形 Dialogue: 0,0:49:56.52,0:50:01.46,Default,,0,0,0,,它会在你给定的矩形中绘制图形 Dialogue: 0,0:50:03.46,0:50:09.26,Default,,0,0,0,,假设P2是另一个图像 你传递给它一个矩形 Dialogue: 0,0:50:09.74,0:50:12.44,Default,,0,0,0,,无论给它什么矩形 它都会绘制一些图案 Dialogue: 0,0:50:14.84,0:50:26.60,Default,,0,0,0,,现在 我想实现(BESIDE P1 P2 A) A是缩放因子 Dialogue: 0,0:50:27.04,0:50:28.38,Default,,0,0,0,,会得到什么呢? Dialogue: 0,0:50:28.38,0:50:29.34,Default,,0,0,0,,我们会得到一个图像 Dialogue: 0,0:50:29.92,0:50:33.88,Default,,0,0,0,,也就是说你传给它一个矩形 它就会在其中绘图 Dialogue: 0,0:50:34.77,0:50:37.18,Default,,0,0,0,,如果我们在一个矩形中执行BESIDE操作 Dialogue: 0,0:50:38.58,0:50:40.12,Default,,0,0,0,,比如这个矩形 Dialogue: 0,0:50:41.50,0:50:42.74,Default,,0,0,0,,要做什么呢? Dialogue: 0,0:50:42.76,0:50:46.36,Default,,0,0,0,,这将把矩形切分为两部分 Dialogue: 0,0:50:49.29,0:50:51.57,Default,,0,0,0,,一部分比例是A 另一部分是1-A Dialogue: 0,0:50:52.65,0:50:55.12,Default,,0,0,0,,现在 我们就有了两个矩形 Dialogue: 0,0:51:02.34,0:51:06.54,Default,,0,0,0,,然后先让P1在这个矩形中绘制 Dialogue: 0,0:51:07.36,0:51:11.64,Default,,0,0,0,,然后让P2在这个矩形中绘制 Dialogue: 0,0:51:13.28,0:51:16.88,Default,,0,0,0,,BESIDE仅仅需要计算出这些矩形来 Dialogue: 0,0:51:17.36,0:51:23.97,Default,,0,0,0,,由于矩形是由原点、水平向量和竖直向量组成 Dialogue: 0,0:51:23.98,0:51:25.94,Default,,0,0,0,,BESIDE操作需要计算出这些要素 Dialogue: 0,0:51:27.37,0:51:32.29,Default,,0,0,0,,所以对第一个矩形来说 原点变成了矩形的原点 Dialogue: 0,0:51:33.64,0:51:37.80,Default,,0,0,0,,竖直向量与原矩形相同 不发生变化 Dialogue: 0,0:51:38.89,0:51:46.60,Default,,0,0,0,,水平向量是原始矩形的水平向量缩放A倍得到的 Dialogue: 0,0:51:47.49,0:51:48.90,Default,,0,0,0,,这就是第一个矩形 Dialogue: 0,0:51:49.46,0:51:52.69,Default,,0,0,0,,第二个矩形的原点是 Dialogue: 0,0:51:54.06,0:51:59.65,Default,,0,0,0,,原矩形的原点加上矩形的水平向量缩放A倍 Dialogue: 0,0:52:01.20,0:52:03.40,Default,,0,0,0,,第二个矩形的水平向量是 Dialogue: 0,0:52:03.77,0:52:06.04,Default,,0,0,0,,除去前一个矩形水平向量所余下的部分 Dialogue: 0,0:52:06.34,0:52:11.66,Default,,0,0,0,,也就是(1-A)*H H是原矩形的水平向量 Dialogue: 0,0:52:12.05,0:52:13.77,Default,,0,0,0,,它的竖直向量还是V Dialogue: 0,0:52:15.48,0:52:17.98,Default,,0,0,0,,基本上 BESIDE就是构造这两个矩形 Dialogue: 0,0:52:18.00,0:52:20.57,Default,,0,0,0,,但重要的是 一旦构造好这些矩形 Dialogue: 0,0:52:20.93,0:52:24.58,Default,,0,0,0,,它就能让P1、P2在正确的位置绘制 Dialogue: 0,0:52:24.62,0:52:26.18,Default,,0,0,0,,这就是BESIDE需要做的全部工作 Dialogue: 0,0:52:27.80,0:52:29.30,Default,,0,0,0,,我们看一下代码 Dialogue: 0,0:52:34.33,0:52:35.13,Default,,0,0,0,,这是BESIDE Dialogue: 0,0:52:39.64,0:52:46.44,Default,,0,0,0,,(BESIDE P1 P2 A) A是缩放比例 Dialogue: 0,0:52:47.84,0:52:53.64,Default,,0,0,0,,因为该过程返回图像 所以结果是一个以矩形为参数的过程 Dialogue: 0,0:52:55.49,0:52:56.56,Default,,0,0,0,,它做什么呢? Dialogue: 0,0:52:56.76,0:53:02.32,Default,,0,0,0,,它让P1在某个矩形中绘制 P2在另一个矩形中绘制 Dialogue: 0,0:53:03.21,0:53:04.46,Default,,0,0,0,,现在这些矩形又是什么呢? Dialogue: 0,0:53:04.46,0:53:05.48,Default,,0,0,0,,就在这里计算 Dialogue: 0,0:53:05.48,0:53:06.54,Default,,0,0,0,,它创建了一个矩形 Dialogue: 0,0:53:07.52,0:53:10.40,Default,,0,0,0,,用的是我刚才在黑板上写的几何公式 这是矩形的原点 Dialogue: 0,0:53:10.40,0:53:11.84,Default,,0,0,0,,矩形的水平向量 Dialogue: 0,0:53:11.84,0:53:13.44,Default,,0,0,0,,还有矩形的竖直向量 Dialogue: 0,0:53:13.97,0:53:14.81,Default,,0,0,0,,对于P2 Dialogue: 0,0:53:15.50,0:53:19.78,Default,,0,0,0,,矩形需要不同的原点 水平向量和竖直向量 Dialogue: 0,0:53:19.78,0:53:20.70,Default,,0,0,0,,但重要的是 Dialogue: 0,0:53:21.21,0:53:27.18,Default,,0,0,0,,BESIDE只是将这两个矩形分别传递给了P1和P2而已 Dialogue: 0,0:53:27.74,0:53:29.42,Default,,0,0,0,,这就是BESIDE所需要做的 Dialogue: 0,0:53:30.84,0:53:35.62,Default,,0,0,0,,好 ROTATE也很类似 Dialogue: 0,0:53:36.96,0:53:42.00,Default,,0,0,0,,假设我有一个图像A Dialogue: 0,0:53:42.97,0:53:46.12,Default,,0,0,0,,我想让它旋转90度 Dialogue: 0,0:53:46.37,0:53:51.92,Default,,0,0,0,,这意味着 给定这个矩形 Dialogue: 0,0:53:53.94,0:53:58.44,Default,,0,0,0,,它有原点、水平向量和竖直向量 Dialogue: 0,0:53:58.78,0:54:03.18,Default,,0,0,0,,现在假设已经有了这样的矩形 Dialogue: 0,0:54:03.74,0:54:09.12,Default,,0,0,0,,这个矩形的原点、水平向量和竖直向量在这里 Dialogue: 0,0:54:09.60,0:54:12.46,Default,,0,0,0,,然后在矩形里各自绘制自己 Dialogue: 0,0:54:13.26,0:54:15.04,Default,,0,0,0,,我们来看看代码 Dialogue: 0,0:54:17.02,0:54:19.85,Default,,0,0,0,,那么 ROTATE90过程 Dialogue: 0,0:54:20.61,0:54:22.96,Default,,0,0,0,,返回的也是一个以矩形为参数的过程 Dialogue: 0,0:54:23.25,0:54:26.12,Default,,0,0,0,,它就是将图像绘制在一个特定矩形中 Dialogue: 0,0:54:27.21,0:54:30.66,Default,,0,0,0,,这个几何公式就是这个矩形的变换规则 Dialogue: 0,0:54:30.66,0:54:33.84,Default,,0,0,0,,这句代码让矩形看起来像向侧面的 Dialogue: 0,0:54:33.86,0:54:36.52,Default,,0,0,0,,原点在别的地方 竖直向量在别的地方 Dialogue: 0,0:54:37.13,0:54:39.74,Default,,0,0,0,,水平向量在别的地方 竖直向量在别的地方 Dialogue: 0,0:54:46.76,0:54:49.90,Default,,0,0,0,,再次注意 这里的关键是 Dialogue: 0,0:54:50.53,0:55:00.97,Default,,0,0,0,,关键是使用过程来表示图像 使其自动地具有闭包性质 Dialogue: 0,0:55:01.74,0:55:05.22,Default,,0,0,0,,这是因为 实际上 BESIDE只是接受并使用P1 Dialogue: 0,0:55:05.22,0:55:09.40,Default,,0,0,0,,BESIDE并不关心它是一个基本图像还是一些线段 Dialogue: 0,0:55:09.61,0:55:12.69,Default,,0,0,0,,或者P1还是ABOVE、BESIDE、ROTATE等操作的结果 Dialogue: 0,0:55:12.72,0:55:16.08,Default,,0,0,0,,关于P1 BESIDE需要知道的就是 Dialogue: 0,0:55:16.29,0:55:19.73,Default,,0,0,0,,给P1传递一个矩形 就会导致某物的绘制 Dialogue: 0,0:55:21.04,0:55:25.98,Default,,0,0,0,,在这个层面上 BESIDE并不关心P1是如何完成绘制 Dialogue: 0,0:55:27.73,0:55:32.25,Default,,0,0,0,,我们使用过程来表示图像 以保持它的闭包性质 Dialogue: 0,0:55:35.64,0:55:40.81,Default,,0,0,0,,将图像实现为过程 使得组合的方法变得 Dialogue: 0,0:55:41.18,0:55:43.93,Default,,0,0,0,,变得简单而优雅 Dialogue: 0,0:55:45.92,0:55:48.22,Default,,0,0,0,,但这并不是点睛之笔 Dialogue: 0,0:55:49.28,0:55:53.52,Default,,0,0,0,,点睛之笔来自于这门语言中抽象的方法 Dialogue: 0,0:55:54.70,0:55:56.24,Default,,0,0,0,,我们做了些什么? Dialogue: 0,0:55:56.24,0:56:03.72,Default,,0,0,0,,我们把组合的方法实现为了过程 Dialogue: 0,0:56:05.85,0:56:09.38,Default,,0,0,0,,这也就意味着 当我们对这个语言进行抽象时 Dialogue: 0,0:56:10.17,0:56:15.69,Default,,0,0,0,,Lisp提供的 操作过程的一切方法 Dialogue: 0,0:56:16.33,0:56:21.45,Default,,0,0,0,,都可以自动地在这个图像语言中使用 Dialogue: 0,0:56:21.92,0:56:29.74,Default,,0,0,0,,与其用术语“这个语言以Lisp实现” — 虽然确实如此 Dialogue: 0,0:56:29.76,0:56:32.58,Default,,0,0,0,,我想描述为“这个语言嵌入于Lisp” Dialogue: 0,0:56:37.64,0:56:42.08,Default,,0,0,0,,也就是说 通过像这样将语言嵌入 Dialogue: 0,0:56:42.90,0:56:48.86,Default,,0,0,0,,可以以扩展的形式 自动地获得Lisp的所有力量 Dialogue: 0,0:56:50.06,0:56:51.68,Default,,0,0,0,,这又是什么意思呢? Dialogue: 0,0:56:51.97,0:57:02.94,Default,,0,0,0,,举个例子 假设我想用A B C D四副图像做东西 Dialogue: 0,0:57:03.76,0:57:07.06,Default,,0,0,0,,让它们呈现像这样的格局 Dialogue: 0,0:57:12.50,0:57:16.96,Default,,0,0,0,,可以将其称为FOUR-PICT格局 Dialogue: 0,0:57:16.96,0:57:17.70,Default,,0,0,0,,我该如何做呢? Dialogue: 0,0:57:17.70,0:57:18.68,Default,,0,0,0,,我可以很容易的做到这些 Dialogue: 0,0:57:18.68,0:57:23.33,Default,,0,0,0,,写个过程 让B和D做ABOVE Dialogue: 0,0:57:24.13,0:57:25.85,Default,,0,0,0,,A和C做ABOVE Dialogue: 0,0:57:26.09,0:57:27.70,Default,,0,0,0,,得到的结果做BESIDE Dialogue: 0,0:57:28.24,0:57:31.82,Default,,0,0,0,,我自然地拥有Lisp组合过程的能力 Dialogue: 0,0:57:32.92,0:57:35.82,Default,,0,0,0,,这不需要我为图像语言做些特殊处理 Dialogue: 0,0:57:35.82,0:57:39.92,Default,,0,0,0,,事实上 这些组合本身就是过程 Dialogue: 0,0:57:40.96,0:57:44.18,Default,,0,0,0,,假设我想做一些更复杂的事情 Dialogue: 0,0:57:44.18,0:57:46.50,Default,,0,0,0,,我想为这里的每一个传递一个参数 Dialogue: 0,0:57:46.52,0:57:50.08,Default,,0,0,0,,我可以独立地做旋转90度的操作 Dialogue: 0,0:57:50.41,0:57:52.64,Default,,0,0,0,,这只需要我在这个过程中加入一个参数 Dialogue: 0,0:57:53.17,0:57:54.56,Default,,0,0,0,,它自然而然就有了这样的功能 Dialogue: 0,0:57:54.80,0:57:57.84,Default,,0,0,0,,它自动地嵌入进去了 Dialogue: 0,0:57:58.16,0:58:05.36,Default,,0,0,0,,甚至 假设我想使用递归 Dialogue: 0,0:58:06.16,0:58:10.78,Default,,0,0,0,,我们看一下图像递归组合的方法 Dialogue: 0,0:58:10.78,0:58:14.64,Default,,0,0,0,,定义--看看你们能理解这个不 Dialogue: 0,0:58:14.69,0:58:18.97,Default,,0,0,0,,(DEFINE (RIGHT-PUSH PICT N A)) Dialogue: 0,0:58:22.84,0:58:29.80,Default,,0,0,0,,RIGHT-PUSH需要图片P 整数N和缩放因数A Dialogue: 0,0:58:31.46,0:58:41.22,Default,,0,0,0,,定义是:如果N为0 那么返回图像P Dialogue: 0,0:58:42.20,0:58:54.02,Default,,0,0,0,,否则 就-- 哦 这里是P Dialogue: 0,0:58:55.88,0:59:00.21,Default,,0,0,0,,否则 我用图形P做BESIDE操作 Dialogue: 0,0:59:00.92,0:59:18.30,Default,,0,0,0,,BESIDE的另一个操作数是(RIGHT-PUSH P (- N 1) A)的结果 Dialogue: 0,0:59:24.72,0:59:31.12,Default,,0,0,0,,如果N为0 就返回P 否则就对P进行A倍缩放 Dialogue: 0,0:59:31.12,0:59:32.80,Default,,0,0,0,,抱歉 我这里代码没对齐 Dialogue: 0,0:59:33.66,0:59:38.50,Default,,0,0,0,,递归地调用(RIGHT-PUSH P (- N 1) A) 将结果用BESIDE连接 Dialogue: 0,0:59:38.50,0:59:42.00,Default,,0,0,0,,这就是一种递归组合方法 Dialogue: 0,0:59:43.78,0:59:44.76,Default,,0,0,0,,调用的结果会是怎样的? Dialogue: 0,0:59:44.76,0:59:45.90,Default,,0,0,0,,我们来看看 Dialogue: 0,0:59:46.04,0:59:56.04,Default,,0,0,0,,这是(RIGHT-PUSH GEORGE 2 0.75)的结果 Dialogue: 0,0:59:59.26,1:00:00.72,Default,,0,0,0,,这个是从什么地方来的呢? Dialogue: 0,1:00:00.72,1:00:02.34,Default,,0,0,0,,我是如何想象出这些递归来的呢? Dialogue: 0,1:00:02.34,1:00:05.24,Default,,0,0,0,,答案是无意识的 绝对是无意识的 Dialogue: 0,1:00:05.24,1:00:09.80,Default,,0,0,0,,由于它们都是过程 而嵌入的目标系统中允许定义递归过程 Dialogue: 0,1:00:10.36,1:00:11.68,Default,,0,0,0,,我不必自己去做 Dialogue: 0,1:00:13.56,1:00:16.42,Default,,0,0,0,,当然 我们可以模仿这个方法做些更复杂的事 Dialogue: 0,1:00:16.42,1:00:18.21,Default,,0,0,0,,我可以定义做UP-PUSH的过程 Dialogue: 0,1:00:18.42,1:00:22.60,Default,,0,0,0,,对 它可以递归地把图片放在原来的上面 Dialogue: 0,1:00:22.60,1:00:26.54,Default,,0,0,0,,我也可以用这种策略来做些其它事 Dialogue: 0,1:00:26.56,1:00:28.85,Default,,0,0,0,,给定一个图像 Dialogue: 0,1:00:29.78,1:00:37.16,Default,,0,0,0,,然后递归地把它放在原图片的旁边和上面 Dialogue: 0,1:00:37.57,1:00:38.92,Default,,0,0,0,,这里再放一些别的 Dialogue: 0,1:00:39.52,1:00:41.82,Default,,0,0,0,,然后我把同样递归的图像放在这里 Dialogue: 0,1:00:42.36,1:00:44.20,Default,,0,0,0,,我可以用这个来终止 Dialogue: 0,1:00:45.40,1:00:52.50,Default,,0,0,0,,这个过程比RIGHT-PUSH复杂一点 但也不算太多 Dialogue: 0,1:00:53.64,1:00:58.14,Default,,0,0,0,,在BESIDE的基础上 我多加了一个ABOVE操作 Dialogue: 0,1:01:01.12,1:01:06.78,Default,,0,0,0,,如果我把它应用于四张放在一起的图像上 Dialogue: 0,1:01:07.53,1:01:08.65,Default,,0,0,0,,这样做当然没问题 Dialogue: 0,1:01:09.01,1:01:14.17,Default,,0,0,0,,我把它应用于我们之前定义的Q上 Dialogue: 0,1:01:15.97,1:01:18.73,Default,,0,0,0,,我得到的是这个玩意儿 Dialogue: 0,1:01:20.14,1:01:25.26,Default,,0,0,0,,"图像Q的方形极限" 做了两次 Dialogue: 0,1:01:28.18,1:01:32.25,Default,,0,0,0,,好 现在我们将其与Escher的"方形极限"对比一下 Dialogue: 0,1:01:32.88,1:01:34.53,Default,,0,0,0,,可以看到 这都是基于同样的思想 Dialogue: 0,1:01:34.74,1:01:36.94,Default,,0,0,0,,当然 Escher的图像更加漂亮一些 Dialogue: 0,1:01:36.94,1:01:44.04,Default,,0,0,0,,如果我们回过头审视George Dialogue: 0,1:01:44.38,1:01:47.37,Default,,0,0,0,,我最开始用的是非常随意的设计 Dialogue: 0,1:01:47.42,1:01:49.26,Default,,0,0,0,,用了George的图像 做了一些操作 Dialogue: 0,1:01:51.22,1:01:53.14,Default,,0,0,0,,我们再看看Escher的图片 Dialogue: 0,1:01:54.08,1:01:56.14,Default,,0,0,0,,Escher的图片不是随意设计的 Dialogue: 0,1:01:56.14,1:01:57.66,Default,,0,0,0,,这个图案非常精妙 Dialogue: 0,1:01:57.89,1:02:00.20,Default,,0,0,0,,当我们把鱼身 Dialogue: 0,1:02:01.82,1:02:04.97,Default,,0,0,0,,把鱼身旋转并放缩 就会优美地变成下一条鱼 Dialogue: 0,1:02:07.40,1:02:11.48,Default,,0,0,0,,当然我没有刻意处理过George Dialogue: 0,1:02:12.12,1:02:13.90,Default,,0,0,0,,就图像George来说 Dialogue: 0,1:02:15.41,1:02:18.64,Default,,0,0,0,,也有一些地方匹配 但不够好 比较随意 Dialogue: 0,1:02:18.64,1:02:21.53,Default,,0,0,0,,顺便说下 一个好的程序 Dialogue: 0,1:02:22.30,1:02:27.54,Default,,0,0,0,,应该有个过程 能接受像这里George一样的基本图像 Dialogue: 0,1:02:27.86,1:02:29.62,Default,,0,0,0,,然后调整其中的线段终点 Dialogue: 0,1:02:29.86,1:02:31.20,Default,,0,0,0,,这样可以得到一个好看的图像 Dialogue: 0,1:02:32.13,1:02:34.06,Default,,0,0,0,,在做“方形极限”应该注意这些 Dialogue: 0,1:02:34.68,1:02:36.30,Default,,0,0,0,,这是一个非常值得思考的事情 Dialogue: 0,1:02:38.08,1:02:39.72,Default,,0,0,0,,同时 我还可以进行组合 Dialogue: 0,1:02:39.72,1:02:41.04,Default,,0,0,0,,我们还可以使用递归过程 Dialogue: 0,1:02:41.04,1:02:43.48,Default,,0,0,0,,我们可以自然而然地做任何事情 Dialogue: 0,1:02:44.60,1:02:48.52,Default,,0,0,0,,重点在于 在语言中实际实现另一个语言 Dialogue: 0,1:02:48.69,1:02:50.44,Default,,0,0,0,,在语言中嵌入另一个语言的差异 Dialogue: 0,1:02:50.44,1:02:53.72,Default,,0,0,0,,这可以让你不丢失原有语言的能力 而Lisp强大之处在于 Dialogue: 0,1:02:54.76,1:02:57.62,Default,,0,0,0,,Lisp是一个强悍的语言 可以处理任何特定问题 Dialogue: 0,1:02:57.62,1:03:02.10,Default,,0,0,0,,把你想要的语言嵌入到Lisp中才是真的好 Dialogue: 0,1:03:02.10,1:03:05.44,Default,,0,0,0,,这才是这种设计方法的真正力量 Dialogue: 0,1:03:05.69,1:03:06.82,Default,,0,0,0,,我们可以深入一下 Dialogue: 0,1:03:06.82,1:03:08.81,Default,,0,0,0,,在Lisp中我们还可以做些其它的事 Dialogue: 0,1:03:09.21,1:03:17.52,Default,,0,0,0,,就是将通用方法抽象成高阶过程 Dialogue: 0,1:03:19.09,1:03:22.57,Default,,0,0,0,,在我画那些图像时 你们可能已经发现 Dialogue: 0,1:03:23.78,1:03:26.61,Default,,0,0,0,,RIGHT-PUSH和类似的过程 就是一直在上面放东西 Dialogue: 0,1:03:26.93,1:03:33.82,Default,,0,0,0,,而这个CORNER-PUSH则是一种一般性思想的泛化 Dialogue: 0,1:03:34.72,1:03:37.20,Default,,0,0,0,,为了演示并让大家熟悉 Dialogue: 0,1:03:37.98,1:03:40.65,Default,,0,0,0,,使用廊腰缦回的高阶过程 Dialogue: 0,1:03:41.12,1:03:47.24,Default,,0,0,0,,我给大家示范一下“递归地重复某种组合方法”的一般性思想 Dialogue: 0,1:03:48.30,1:03:50.70,Default,,0,0,0,,这个例子可以说明一切 Dialogue: 0,1:03:51.22,1:04:00.70,Default,,0,0,0,,我们可以定义一个依赖于具体组合方式的PUSH过程 Dialogue: 0,1:04:01.49,1:04:04.88,Default,,0,0,0,,COMB的取值可以是BESIDE或ABOVE等 Dialogue: 0,1:04:06.18,1:04:07.06,Default,,0,0,0,,过程的体是什么呢? Dialogue: 0,1:04:07.06,1:04:12.06,Default,,0,0,0,,它返回一个过程 想一想BESIDE实际上是什么 Dialogue: 0,1:04:13.22,1:04:15.18,Default,,0,0,0,,它接受一个图像 Dialogue: 0,1:04:15.96,1:04:18.08,Default,,0,0,0,,哦 它接受两个图像和一个缩放因数 Dialogue: 0,1:04:18.62,1:04:24.28,Default,,0,0,0,,利用这个过程 定义一个接受层数、图像和缩放因数的过程 Dialogue: 0,1:04:24.28,1:04:25.45,Default,,0,0,0,,我称之为RIGHT-PUSH Dialogue: 0,1:04:26.16,1:04:33.66,Default,,0,0,0,,这个过程接受 图像PICT 层数N和缩放因数A Dialogue: 0,1:04:36.16,1:04:39.12,Default,,0,0,0,,我要做一些重复操作 Dialogue: 0,1:04:39.45,1:04:46.62,Default,,0,0,0,,我会重复应用一个接受一个图像P的过程 Dialogue: 0,1:04:48.40,1:04:50.69,Default,,0,0,0,,并把组合的方式应用在 Dialogue: 0,1:04:51.20,1:04:59.08,Default,,0,0,0,,应用在图像PICT和在这里接受的图像P以及缩放因数A Dialogue: 0,1:05:02.26,1:05:07.28,Default,,0,0,0,,我要重复应用这个过程N次 Dialogue: 0,1:05:12.04,1:05:16.20,Default,,0,0,0,,我则是把这整个过程应用在原图片PICT上 Dialogue: 0,1:05:19.56,1:05:24.48,Default,,0,0,0,,虽然之前没提过 这里的REPEATED也是一个高阶过程 Dialogue: 0,1:05:24.53,1:05:28.34,Default,,0,0,0,,它接受一个过程P和一个数字N Dialogue: 0,1:05:29.54,1:05:34.29,Default,,0,0,0,,它返回另一个过程:将给定的过程P重复应用N次的过程 Dialogue: 0,1:05:36.04,1:05:39.30,Default,,0,0,0,,可能有些人已经在练习中编写过REPEATED了 Dialogue: 0,1:05:39.70,1:05:43.01,Default,,0,0,0,,如果还没做的话 这是理解和练习高阶过程的好机会 Dialogue: 0,1:05:43.84,1:05:46.90,Default,,0,0,0,,无论如何 我将把REPEATED过程的结果应用到PICT上 Dialogue: 0,1:05:49.46,1:05:52.38,Default,,0,0,0,,定义好PUSH后 这就 Dialogue: 0,1:05:53.12,1:05:57.73,Default,,0,0,0,,这就是从BESIDE、RIGHT-PUSH中总结出来的一般性思想 Dialogue: 0,1:05:59.01,1:06:13.17,Default,,0,0,0,,现在 我就可以把RIGHT-PUSH定义为 用BESIDE来做PUSH操作 Dialogue: 0,1:06:17.65,1:06:20.32,Default,,0,0,0,,我也可以把UP-PUSH定义为 用ABOVE来做PUSH操作 Dialogue: 0,1:06:20.34,1:06:25.48,Default,,0,0,0,,类似地 CORNER-PUSH就是用BESIDE和ABOVE的适当组合做PUSH操作 Dialogue: 0,1:06:25.49,1:06:26.70,Default,,0,0,0,,我可以用任何东西做PUSH操作 Dialogue: 0,1:06:28.26,1:06:34.76,Default,,0,0,0,,嗯 如果你还不太理解LAMBDA的话 可以参考这个例子 Dialogue: 0,1:06:38.98,1:06:41.00,Default,,0,0,0,,我们可以从这个例子中学到很多东西 Dialogue: 0,1:06:42.18,1:06:49.80,Default,,0,0,0,,我主要想要介绍的是在一个语言中嵌入另一个语言 Dialogue: 0,1:06:50.66,1:06:55.62,Default,,0,0,0,,这样 母体语言--本例中是Lisp--的所有能力 Dialogue: 0,1:06:55.92,1:07:00.28,Default,,0,0,0,,可以作为你所构建语言的一种扩展而取得 Dialogue: 0,1:07:00.98,1:07:04.00,Default,,0,0,0,,这个例子很好地展示了这点 Dialogue: 0,1:07:08.14,1:07:10.94,Default,,0,0,0,,另外 当我们回过头去思考 Dialogue: 0,1:07:10.94,1:07:12.28,Default,,0,0,0,,什么是过程 什么是数据 Dialogue: 0,1:07:12.28,1:07:16.20,Default,,0,0,0,,在这里 天啊 发生了什么 Dialogue: 0,1:07:16.20,1:07:19.66,Default,,0,0,0,,在这里 这是一个过程 它接受一个图像和一个参数 Dialogue: 0,1:07:19.66,1:07:20.36,Default,,0,0,0,,但是 什么是图像呢? Dialogue: 0,1:07:20.36,1:07:23.82,Default,,0,0,0,,请回想 图像本身 就是一个以矩形为参数的过程 Dialogue: 0,1:07:23.82,1:07:25.82,Default,,0,0,0,,这个矩形是某种抽象 Dialogue: 0,1:07:26.09,1:07:28.13,Default,,0,0,0,,我希望你们现在能彻底明白 Dialogue: 0,1:07:29.14,1:07:33.74,Default,,0,0,0,,系统中什么是过程 什么是数据 Dialogue: 0,1:07:33.74,1:07:34.78,Default,,0,0,0,,我们发现 它们没有任何区别 Dialogue: 0,1:07:35.49,1:07:36.44,Default,,0,0,0,,真的没有区别 Dialogue: 0,1:07:37.93,1:07:41.42,Default,,0,0,0,,你可以认为图像有时候是过程 有时候是数据 Dialogue: 0,1:07:41.84,1:07:44.90,Default,,0,0,0,,但是 这只是让你容易理解的一种方法 Dialogue: 0,1:07:44.90,1:07:47.30,Default,,0,0,0,,这有一定道理 也没有道理 Dialogue: 0,1:07:49.92,1:08:02.20,Default,,0,0,0,,关于系统的结构 一种更普遍的观点将其视作创建一种语言 Dialogue: 0,1:08:02.52,1:08:06.74,Default,,0,0,0,,将工程设计过程看作是创建一门语言 Dialogue: 0,1:08:07.84,1:08:13.97,Default,,0,0,0,,准确来说 是创建各种层次的语言 Dialogue: 0,1:08:14.77,1:08:20.01,Default,,0,0,0,,众所周知 有一种方法学 或者叫做“神话学” Dialogue: 0,1:08:20.74,1:08:24.90,Default,,0,0,0,,姑且叫做软件“工程” Dialogue: 0,1:08:25.21,1:08:28.04,Default,,0,0,0,,它声称 你要先计算出你的任务 Dialogue: 0,1:08:28.04,1:08:30.04,Default,,0,0,0,,精确且正确地计算出你的任务 Dialogue: 0,1:08:30.40,1:08:32.20,Default,,0,0,0,,一但你搞清楚要做的东西 Dialogue: 0,1:08:32.22,1:08:34.54,Default,,0,0,0,,你把它划分为三个子任务 Dialogue: 0,1:08:34.54,1:08:35.76,Default,,0,0,0,,然后你开始继续做-- Dialogue: 0,1:08:35.97,1:08:38.94,Default,,0,0,0,,你开始处理这个子任务 然后你明确它是什么 Dialogue: 0,1:08:38.94,1:08:43.04,Default,,0,0,0,,这个子问题就分裂成三个子任务 你把它们处理完 Dialogue: 0,1:08:43.04,1:08:47.32,Default,,0,0,0,,然后你先处理这两个任务 Dialogue: 0,1:08:47.32,1:08:51.10,Default,,0,0,0,,解决完子任务后 你后退到这里 处理第二个子任务 Dialogue: 0,1:08:51.10,1:08:53.40,Default,,0,0,0,,然后把它详细地实现出来 Dialogue: 0,1:08:53.40,1:08:57.64,Default,,0,0,0,,结束之后-- 你完成了这个美丽的大厦 Dialogue: 0,1:08:57.64,1:09:00.25,Default,,0,0,0,,你最后得到了一棵非凡的树 Dialogue: 0,1:09:00.89,1:09:08.24,Default,,0,0,0,,你把任务划分为子任务 子任务再划分为子任务 Dialogue: 0,1:09:09.88,1:09:15.02,Default,,0,0,0,,树中的每个结点都被严谨而准确地定义 Dialogue: 0,1:09:15.26,1:09:18.66,Default,,0,0,0,,为奇妙而精美的任务 以构建整栋大厦 Dialogue: 0,1:09:18.96,1:09:21.14,Default,,0,0,0,,这个就是所谓的“神话学” Dialogue: 0,1:09:21.14,1:09:25.92,Default,,0,0,0,,只有计算机科学家才可能相信你构建的复杂系统像这个样子 Dialogue: 0,1:09:27.48,1:09:32.80,Default,,0,0,0,,好了 我们用Henderson的例子来做对比 Dialogue: 0,1:09:32.80,1:09:34.30,Default,,0,0,0,,它的结构不是那样 Dialogue: 0,1:09:35.26,1:09:39.33,Default,,0,0,0,,事实是:这里有一个语言的层次序列 Dialogue: 0,1:09:41.06,1:09:42.05,Default,,0,0,0,,它是什么? Dialogue: 0,1:09:42.18,1:09:48.76,Default,,0,0,0,,这里有一层 允许我们构建基本图像 Dialogue: 0,1:09:51.69,1:09:56.24,Default,,0,0,0,,这个语言描述基本图像 Dialogue: 0,1:09:56.32,1:09:57.84,Default,,0,0,0,,我们并没有做过多地讨论 Dialogue: 0,1:09:58.22,1:09:59.58,Default,,0,0,0,,我们讨论了如何构造George Dialogue: 0,1:09:59.61,1:10:04.88,Default,,0,0,0,,这个语言是在单位正方形中讨论点、线和向量 Dialogue: 0,1:10:06.42,1:10:11.29,Default,,0,0,0,,而在这之上 Dialogue: 0,1:10:11.97,1:10:14.10,Default,,0,0,0,,这是讨论基本图像的语言 Dialogue: 0,1:10:17.08,1:10:20.36,Default,,0,0,0,,讨论在特定单位正方形中线段的构造 Dialogue: 0,1:10:21.40,1:10:23.80,Default,,0,0,0,,在这个上面是另一个完整的语言 Dialogue: 0,1:10:24.05,1:10:30.86,Default,,0,0,0,,关于几何组合子的语言 Dialogue: 0,1:10:32.66,1:10:36.62,Default,,0,0,0,,关于几何物件的位置 Dialogue: 0,1:10:38.77,1:10:46.50,Default,,0,0,0,,讨论像ABOVE、BESIDE、RIGHT-PUSH和ROTATE这样的东西 Dialogue: 0,1:10:48.04,1:10:55.70,Default,,0,0,0,,这些事情恰巧与我们在这个语言中谈论的事情有关 Dialogue: 0,1:10:58.57,1:11:00.93,Default,,0,0,0,,再细化一点 我们发现在这之上 Dialogue: 0,1:11:02.61,1:11:15.10,Default,,0,0,0,,还有一门语言 描述组合的模式 Dialogue: 0,1:11:21.25,1:11:22.44,Default,,0,0,0,,比如说PUSH Dialogue: 0,1:11:24.45,1:11:27.88,Default,,0,0,0,,也就是用一个放缩因子重复地做一件事儿 Dialogue: 0,1:11:28.38,1:11:31.28,Default,,0,0,0,,我们在那门语言中讨论的问题 Dialogue: 0,1:11:31.50,1:11:34.34,Default,,0,0,0,,正是我这里构建的东西 Dialogue: 0,1:11:36.30,1:11:42.76,Default,,0,0,0,,我们在每一层上所讨论的对象 Dialogue: 0,1:11:44.68,1:11:47.00,Default,,0,0,0,,都是前一个层次所建立的 Dialogue: 0,1:11:48.08,1:11:52.06,Default,,0,0,0,,这个和这个有什么区别呢? Dialogue: 0,1:11:53.34,1:11:54.18,Default,,0,0,0,,这是因为 Dialogue: 0,1:11:56.14,1:12:01.73,Default,,0,0,0,,实际上在这里 树的每一个结点 每一次分解 Dialogue: 0,1:12:02.14,1:12:05.25,Default,,0,0,0,,都是旨在分成确定的任务 Dialogue: 0,1:12:07.50,1:12:08.88,Default,,0,0,0,,而在另一个方案中 Dialogue: 0,1:12:09.21,1:12:14.80,Default,,0,0,0,,你在每个层级上的完完全全的语言层面的能力 Dialogue: 0,1:12:16.00,1:12:18.08,Default,,0,0,0,,这里的每一个层次 Dialogue: 0,1:12:20.24,1:12:22.72,Default,,0,0,0,,都不是被设计为完成一个特定任务 Dialogue: 0,1:12:23.14,1:12:26.17,Default,,0,0,0,,它被设计为讨论整个事情 Dialogue: 0,1:12:27.62,1:12:30.78,Default,,0,0,0,,这样设计导致的结果是: Dialogue: 0,1:12:31.14,1:12:35.58,Default,,0,0,0,,用这种设计方法更加健壮 Dialogue: 0,1:12:36.61,1:12:38.20,Default,,0,0,0,,我所谓的“健壮”是指 Dialogue: 0,1:12:38.44,1:12:41.24,Default,,0,0,0,,当你在描述中做一些改变 Dialogue: 0,1:12:42.70,1:12:48.04,Default,,0,0,0,,我们可以做出相应的改变 Dialogue: 0,1:12:49.22,1:12:52.60,Default,,0,0,0,,用上一层语言实现的方法改变即可 Dialogue: 0,1:12:54.29,1:12:56.58,Default,,0,0,0,,因为你让每个层次都是完全的 Dialogue: 0,1:12:56.62,1:12:59.66,Default,,0,0,0,,所以你不需要讨论像BESIDE这样的特定操作 Dialogue: 0,1:12:59.94,1:13:03.78,Default,,0,0,0,,你为表达这类事物创造了完备的词汇 Dialogue: 0,1:13:04.77,1:13:07.02,Default,,0,0,0,,所以当你轻微修改规格指标时 Dialogue: 0,1:13:07.02,1:13:11.38,Default,,0,0,0,,这种方法论可以捕捉并适应那些变化 Dialogue: 0,1:13:12.69,1:13:15.02,Default,,0,0,0,,然而这种设计却不够健壮 Dialogue: 0,1:13:15.02,1:13:17.08,Default,,0,0,0,,因为 如果我在这里改变一下 Dialogue: 0,1:13:17.53,1:13:21.69,Default,,0,0,0,,那可能会影响我划分这些东西的方式 严重地影响 Dialogue: 0,1:13:23.20,1:13:29.74,Default,,0,0,0,,分解观点的最大不同在于 按层次还是严格继承分解 Dialogue: 0,1:13:30.52,1:13:33.02,Default,,0,0,0,,不只是如此 当你有多个层次的语言时 Dialogue: 0,1:13:33.50,1:13:35.92,Default,,0,0,0,,你就有了不同的词汇储备 Dialogue: 0,1:13:36.45,1:13:38.74,Default,,0,0,0,,用于讨论不同层次上的设计 Dialogue: 0,1:13:38.74,1:13:40.92,Default,,0,0,0,,我们再回过头来看看George Dialogue: 0,1:13:41.90,1:13:44.08,Default,,0,0,0,,如果我想改变图像George Dialogue: 0,1:13:45.85,1:13:48.68,Default,,0,0,0,,我立马得到了一种不同的方式来描述变化 Dialogue: 0,1:13:48.68,1:13:56.08,Default,,0,0,0,,比如 我想在基本设计的层面上 移动某些向量的终点 Dialogue: 0,1:13:57.76,1:14:00.76,Default,,0,0,0,,我会在最底层讨论这个改变 Dialogue: 0,1:14:01.00,1:14:02.50,Default,,0,0,0,,我会另外指定终点位置 Dialogue: 0,1:14:03.34,1:14:07.98,Default,,0,0,0,,我也可以说 我想在这个小的重复元素上做文章 Dialogue: 0,1:14:09.10,1:14:10.94,Default,,0,0,0,,我可能想做些其它操作 Dialogue: 0,1:14:10.94,1:14:13.84,Default,,0,0,0,,我想在BESIDE中使用一个缩放因数 Dialogue: 0,1:14:13.84,1:14:19.34,Default,,0,0,0,,这个改变我会在更高的层次上讨论:在组合子的层次 Dialogue: 0,1:14:19.34,1:14:25.05,Default,,0,0,0,,我也可以改变图像的基本组合模式 Dialogue: 0,1:14:26.49,1:14:30.48,Default,,0,0,0,,做一些递归地分解 可能不会让它们填充满角落 Dialogue: 0,1:14:31.16,1:14:34.18,Default,,0,0,0,,而这样的一个变化 我会在最高层次讨论 Dialogue: 0,1:14:34.18,1:14:36.37,Default,,0,0,0,,正是因为我按这种结构组织系统 Dialogue: 0,1:14:36.52,1:14:39.62,Default,,0,0,0,,我有所有的词汇 可以用不同的方式描述变化 Dialogue: 0,1:14:39.65,1:14:42.48,Default,,0,0,0,,而且可以灵活地决定哪个更合适 Dialogue: 0,1:14:44.74,1:14:51.05,Default,,0,0,0,,这就是Lisp中不同于软件工程方法论的最大要点 Dialogue: 0,1:14:51.25,1:14:55.45,Default,,0,0,0,,它来自于这样一个观点:真正的设计过程 Dialogue: 0,1:14:56.12,1:14:59.62,Default,,0,0,0,,与其说是在设计程序 不如说是在设计语言 Dialogue: 0,1:14:59.62,1:15:01.09,Default,,0,0,0,,而这就是Lisp的力量 Dialogue: 0,1:15:02.21,1:15:03.61,Default,,0,0,0,,谢谢大家 下课 Dialogue: 0,1:15:05.69,1:15:23.37,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:15:05.69,1:15:23.37,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec3a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Audio URI: G:\untitled\ref\lec3a_480_muxed.mp4 Video Zoom Percent: 0.625 Scroll Position: 0 Active Line: 336 Video File: G:\untitled\ref\lec3a_480_muxed.mp4 Video Aspect Ratio: c1.33333 Video Position: 51395 PlayResX: 640 PlayResY: 480 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:03.12,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:04.40,0:00:08.02,Declare,,0,0,0,,{\an2\fad(500,500)}翻译&&时间轴:邓雄飞(Dysprosium)、Savior Michael\N压制&&特效:邓雄飞(Dysprosium)\N校对:邓雄飞(Dysprosium) Dialogue: 0,0:00:08.06,0:00:12.16,Declare,,0,0,0,,{\an2\fad(500,500)}特别感谢:裘宗燕教授 Dialogue: 0,0:00:12.37,0:00:16.32,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson-Escher的例子 Dialogue: 0,0:00:20.94,0:00:23.86,Default,,0,0,0,,上节课我们讨论了复合数据 Dialogue: 0,0:00:24.94,0:00:29.74,Default,,0,0,0,,其中有两个关键点 Dialogue: 0,0:00:29.74,0:00:32.48,Default,,0,0,0,,首先 有一种数据抽象的方法学 Dialogue: 0,0:00:32.94,0:00:39.10,Default,,0,0,0,,其要点是将数据的使用 Dialogue: 0,0:00:40.06,0:00:41.50,Default,,0,0,0,,和表示分离开来 Dialogue: 0,0:00:41.55,0:00:45.20,Default,,0,0,0,,比如说 我们可以与一个叫做George的人“签订契约” Dialogue: 0,0:00:45.20,0:00:47.48,Default,,0,0,0,,让他负责数据的表示 Dialogue: 0,0:00:47.48,0:00:49.36,Default,,0,0,0,,而当我们使用这些数据的时候 Dialogue: 0,0:00:49.36,0:00:51.36,Default,,0,0,0,,不需要替George操心他是如何完成数据表示的工作的 Dialogue: 0,0:00:51.98,0:00:58.44,Default,,0,0,0,,其次 Lisp中有一种特殊的方式把对象连接在一起 Dialogue: 0,0:00:58.94,0:01:00.52,Default,,0,0,0,,就是构成“序对” Dialogue: 0,0:01:00.52,0:01:03.54,Default,,0,0,0,,这是通过CONS CAR CDR实现的 Dialogue: 0,0:01:03.54,0:01:07.16,Default,,0,0,0,,而CONS CAR CDR本身是如何实现的 这不重要 Dialogue: 0,0:01:07.16,0:01:10.02,Default,,0,0,0,,George的任务就是如何构建这些东西 Dialogue: 0,0:01:10.02,0:01:11.16,Default,,0,0,0,,可以将它们实现为基本过程 Dialogue: 0,0:01:11.16,0:01:13.80,Default,,0,0,0,,也可以利用一些奇怪的过程来实现 Dialogue: 0,0:01:13.80,0:01:15.22,Default,,0,0,0,,但是我们不用操心这些 Dialogue: 0,0:01:16.02,0:01:19.66,Default,,0,0,0,,举个例子 我们来看下有理数算术 Dialogue: 0,0:01:19.66,0:01:21.50,Default,,0,0,0,,看下向量 Dialogue: 0,0:01:21.50,0:01:24.18,Default,,0,0,0,,我们简单回顾一下向量 Dialogue: 0,0:01:24.18,0:01:27.64,Default,,0,0,0,,这里有个对两个向量求和的操作 Dialogue: 0,0:01:27.64,0:01:33.32,Default,,0,0,0,,我们想要把向量v1和v2相加 Dialogue: 0,0:01:34.46,0:01:40.84,Default,,0,0,0,,它们的和也是一个向量 其坐标是两个向量的坐标的和 Dialogue: 0,0:01:41.28,0:01:45.66,Default,,0,0,0,,所以 定义(+VECT V1 V2)为 Dialogue: 0,0:01:45.66,0:01:51.72,Default,,0,0,0,,我创建一个向量 其X坐标是两向量X坐标的和 Dialogue: 0,0:01:52.10,0:01:54.82,Default,,0,0,0,,而Y坐标是两向量Y坐标的和 Dialogue: 0,0:01:56.06,0:02:04.10,Default,,0,0,0,,类似地 我们也可以定义一个缩放向量的操作 Dialogue: 0,0:02:04.94,0:02:12.66,Default,,0,0,0,,这里的SCALE过程是用数字S乘以向量V Dialogue: 0,0:02:13.08,0:02:16.14,Default,,0,0,0,,向量V从这里到这里 Dialogue: 0,0:02:16.32,0:02:20.22,Default,,0,0,0,,我放大V 得到了与原来同向但更长的向量 Dialogue: 0,0:02:21.56,0:02:24.26,Default,,0,0,0,,为了缩放向量 我需要通过缩放坐标来实现 Dialogue: 0,0:02:24.26,0:02:30.22,Default,,0,0,0,,所以我构建了一个向量 它的X坐标是原向量X坐标的S倍 Dialogue: 0,0:02:30.56,0:02:33.54,Default,,0,0,0,,同时 它的Y坐标是原来向量Y坐标的S倍 Dialogue: 0,0:02:33.54,0:02:40.28,Default,,0,0,0,,上述两个操作都是利用了向量的表示来实现的 Dialogue: 0,0:02:40.28,0:02:45.02,Default,,0,0,0,,而这种向量的表示 我们则可以用序对来实现 Dialogue: 0,0:02:45.34,0:02:51.28,Default,,0,0,0,,因此George需要为我们提供MAKE-VECTOR、XCOR和YCOR Dialogue: 0,0:02:53.02,0:02:57.98,Default,,0,0,0,,他可以使用CONS CAR CDR来实现 Dialogue: 0,0:02:58.88,0:03:06.78,Default,,0,0,0,,但是注意 我这里用了一个略微不同的方式 Dialogue: 0,0:03:08.04,0:03:11.00,Default,,0,0,0,,这个过程我们之前看过 其中我讲过 Dialogue: 0,0:03:11.14,0:03:16.22,Default,,0,0,0,,(MAKE-VECTOR X Y)也就是(CONS X Y) Dialogue: 0,0:03:16.22,0:03:17.98,Default,,0,0,0,,而我这里简单定义MAKE-VECTOR为CONS Dialogue: 0,0:03:17.98,0:03:20.48,Default,,0,0,0,,这就与之前有些不同了 Dialogue: 0,0:03:20.48,0:03:26.22,Default,,0,0,0,,之前我们我们把MAKE-VECTOR定义为需要两个参数的过程 Dialogue: 0,0:03:26.22,0:03:28.04,Default,,0,0,0,,效果是(CONS X Y) Dialogue: 0,0:03:28.04,0:03:34.12,Default,,0,0,0,,这里 我就把MAKE-VECTOR定义为CONS Dialogue: 0,0:03:35.18,0:03:39.66,Default,,0,0,0,,这跟我们之前使用的方式基本上是一样的 Dialogue: 0,0:03:39.66,0:03:46.58,Default,,0,0,0,,大家要习惯于“过程也是对象 而且你可以给他们命名”这种想法 Dialogue: 0,0:03:48.70,0:03:51.80,Default,,0,0,0,,这些就是向量的表示方法了 Dialogue: 0,0:03:51.80,0:03:55.68,Default,,0,0,0,,如果仅仅是那样 那就太无趣了 Dialogue: 0,0:03:57.02,0:04:02.16,Default,,0,0,0,,要记住 要点是我们不仅可以通过使用CONS将数字组合成序对 Dialogue: 0,0:04:02.16,0:04:04.16,Default,,0,0,0,,也可以组合任何东西 Dialogue: 0,0:04:05.20,0:04:11.60,Default,,0,0,0,,例如 如果我想表示一个线段 Dialogue: 0,0:04:11.60,0:04:15.64,Default,,0,0,0,,一个以某个向量为起点的线段 Dialogue: 0,0:04:16.06,0:04:28.30,Default,,0,0,0,,比如从向量(2,3)所代表的起点到向量(5,1)所代表的终点的线段 Dialogue: 0,0:04:28.30,0:04:31.82,Default,,0,0,0,,如果我们想表示这条线段 Dialogue: 0,0:04:33.26,0:04:36.20,Default,,0,0,0,,那么我们可以构建一个序对的序对 Dialogue: 0,0:04:40.72,0:04:42.94,Default,,0,0,0,,这样我们就可以表示一条线段了 Dialogue: 0,0:04:42.94,0:04:47.34,Default,,0,0,0,,我们可以编写一个使用CONS构造线段的构造函数 Dialogue: 0,0:04:47.98,0:04:51.60,Default,,0,0,0,,以及 析取出线段起点、终点的选择函数 Dialogue: 0,0:04:55.24,0:04:59.76,Default,,0,0,0,,那么如果我们剥开抽象层一探究竟 Dialogue: 0,0:04:59.88,0:05:02.10,Default,,0,0,0,,就会发现线段不过是 序对组成的序对 Dialogue: 0,0:05:04.66,0:05:06.22,Default,,0,0,0,,它还是一个序对 Dialogue: 0,0:05:06.22,0:05:08.22,Default,,0,0,0,,这里有个线段 Dialogue: 0,0:05:10.00,0:05:16.72,Default,,0,0,0,,它的CAR部分是个序对 CDR部分也是个序对 Dialogue: 0,0:05:18.32,0:05:25.54,Default,,0,0,0,,它的CAR部分是由2和3构成的序对 Dialogue: 0,0:05:26.02,0:05:28.08,Default,,0,0,0,,CDR部分则由5和1构成的序对 Dialogue: 0,0:05:28.16,0:05:29.24,Default,,0,0,0,,这里我再提醒大家一下 Dialogue: 0,0:05:29.32,0:05:33.46,Default,,0,0,0,,好多人认为如果我箭头向下画的话 Dialogue: 0,0:05:33.80,0:05:36.90,Default,,0,0,0,,会有其它的含意 Dialogue: 0,0:05:36.98,0:05:38.28,Default,,0,0,0,,这是不对的 Dialogue: 0,0:05:38.58,0:05:43.90,Default,,0,0,0,,箭头指示的是对象间如何连接 它指向水平或竖直方向都是无关紧要的 Dialogue: 0,0:05:47.48,0:05:52.18,Default,,0,0,0,,还要提醒一下 序对是具有闭包性质的 Dialogue: 0,0:05:52.94,0:06:05.62,Default,,0,0,0,,闭包性质使我们可以构建更复杂的东西 而不仅仅是简单的序对 Dialogue: 0,0:06:06.64,0:06:15.24,Default,,0,0,0,,在这里我要特别指出 在我们用CONS构建出来的序对的基础上 Dialogue: 0,0:06:16.44,0:06:22.64,Default,,0,0,0,,我们也可以进一步用CONS来构造更复杂的对象 Dialogue: 0,0:06:23.28,0:06:31.98,Default,,0,0,0,,或者用数学家的话说 Lisp中的数据对象在CONS运算下是封闭的 Dialogue: 0,0:06:33.82,0:06:36.34,Default,,0,0,0,,这个性质使我们能够构造更加复杂的数据对象 Dialogue: 0,0:06:36.34,0:06:38.04,Default,,0,0,0,,这个似乎是显然的 但是要记住 Dialogue: 0,0:06:39.06,0:06:42.46,Default,,0,0,0,,人们使用的编程语言中有很多东西并不是封闭的 Dialogue: 0,0:06:42.46,0:06:48.06,Default,,0,0,0,,举例来说 Basic和Fortran中的构造数组操作 就不是封闭的 Dialogue: 0,0:06:48.08,0:06:51.94,Default,,0,0,0,,因为 虽然你可以用数字、字符或字符串等来构造数组 Dialogue: 0,0:06:52.04,0:06:54.18,Default,,0,0,0,,但是你不能创建数组的数组 Dialogue: 0,0:06:54.64,0:06:56.68,Default,,0,0,0,,当考察某种组合的方法时 Dialogue: 0,0:06:57.60,0:07:02.78,Default,,0,0,0,,你应该考察该组合方法是否封闭 Dialogue: 0,0:07:05.06,0:07:08.26,Default,,0,0,0,,不管怎样 因为我们可以构造序对的序对 Dialogue: 0,0:07:08.86,0:07:12.78,Default,,0,0,0,,我们就可以用序对将数据以各种各样的方式组合起来 Dialogue: 0,0:07:14.02,0:07:18.26,Default,,0,0,0,,比如我想要组合四个数 -- 1 2 3 4 Dialogue: 0,0:07:18.26,0:07:19.82,Default,,0,0,0,,我有很多方法 Dialogue: 0,0:07:20.74,0:07:26.12,Default,,0,0,0,,比如 像构造线段那样 我可以构造一个序对 Dialogue: 0,0:07:29.02,0:07:36.88,Default,,0,0,0,,它是((1 2) (3 4)) 对吧? Dialogue: 0,0:07:36.88,0:07:40.06,Default,,0,0,0,,或者如果我喜欢 我可以像这样做 Dialogue: 0,0:07:40.06,0:07:45.52,Default,,0,0,0,,我构造一个序对 它的CAR部分也是一个序对 Dialogue: 0,0:07:46.44,0:07:53.20,Default,,0,0,0,,这个序对的CAR部分为1 而CDR部分为由2、3构成的序对 Dialogue: 0,0:07:53.26,0:07:55.08,Default,,0,0,0,,最后 我把4放在这里 Dialogue: 0,0:07:56.92,0:08:02.16,Default,,0,0,0,,所以你可以看到 组合对象的方式有很多种 Dialogue: 0,0:08:02.16,0:08:07.74,Default,,0,0,0,,因此就有必要建立一些统一的约定 Dialogue: 0,0:08:07.74,0:08:11.58,Default,,0,0,0,,使我们能够用某种的通用的方式处理数据 Dialogue: 0,0:08:11.58,0:08:14.00,Default,,0,0,0,,而不用总是针对具体问题做一些生硬的选择 Dialogue: 0,0:08:15.94,0:08:19.04,Default,,0,0,0,,Lisp里面就有这样一种约定 Dialogue: 0,0:08:20.74,0:08:25.82,Default,,0,0,0,,这个约定将一系列的东西表示成一个序对组成的链 Dialogue: 0,0:08:26.78,0:08:28.18,Default,,0,0,0,,而这样一个数据序列就叫做一个“表” Dialogue: 0,0:08:34.72,0:08:40.50,Default,,0,0,0,,表本质上就是Lisp用来表示序列数据的一个约定而已 Dialogue: 0,0:08:40.70,0:08:47.38,Default,,0,0,0,,我可以使用序对的序列来表示序列 1 2 3 4 Dialogue: 0,0:08:48.26,0:08:54.68,Default,,0,0,0,,我把1放在这里 它的CDR指向另一个序对 Dialogue: 0,0:08:59.20,0:09:01.40,Default,,0,0,0,,这个序对的CAR部分是序列中的下一个数 Dialogue: 0,0:09:01.52,0:09:03.42,Default,,0,0,0,,并且它的CDR指向了另一个序对 Dialogue: 0,0:09:05.44,0:09:07.30,Default,,0,0,0,,它的CAR部分是序列的再下一个数 Dialogue: 0,0:09:07.36,0:09:08.44,Default,,0,0,0,,这个是3 Dialogue: 0,0:09:08.44,0:09:09.74,Default,,0,0,0,,以此类推 Dialogue: 0,0:09:09.74,0:09:13.22,Default,,0,0,0,,所以 序列中的每一个元素都对应着一个序对 Dialogue: 0,0:09:15.82,0:09:18.32,Default,,0,0,0,,而当这个序列中没有其它元素时,我用一个特殊的标记 Dialogue: 0,0:09:20.72,0:09:22.74,Default,,0,0,0,,来表示列表中没有元素了 Dialogue: 0,0:09:24.14,0:09:34.64,Default,,0,0,0,,好 这就是将序列中的元素组合起来的一种约定方式 Dialogue: 0,0:09:34.64,0:09:37.98,Default,,0,0,0,,而它其实就是一堆序对 Dialogue: 0,0:09:39.40,0:09:44.80,Default,,0,0,0,,每个序对中的CAR部分就是我们想要组合到一起的元素 Dialogue: 0,0:09:46.00,0:09:48.46,Default,,0,0,0,,这些序对的CDR部分则指向下一个序对 Dialogue: 0,0:09:50.02,0:09:56.04,Default,,0,0,0,,现在 如果我想要构造它 我需要向Lisp中输入 Dialogue: 0,0:09:56.62,0:09:58.76,Default,,0,0,0,,我会像这样来构造 Dialogue: 0,0:09:59.22,0:10:15.28,Default,,0,0,0,,(CONS 1 (CONS 2 (CONS 3 (CONS 4 NIL)))) Dialogue: 0,0:10:15.28,0:10:20.00,Default,,0,0,0,,NIL是序列末尾标志的名字 Dialogue: 0,0:10:20.80,0:10:23.24,Default,,0,0,0,,它是一个特殊的名字 标识以达到表的末尾 Dialogue: 0,0:10:26.24,0:10:30.26,Default,,0,0,0,,好 这就是如何构造一个表 Dialogue: 0,0:10:37.54,0:10:41.40,Default,,0,0,0,,如果每次构造一个表时 都要输入像 Dialogue: 0,0:10:41.45,0:10:45.18,Default,,0,0,0,,(CONS 1 (CONS 2 (CONS 3...的话 将会非常费力 Dialogue: 0,0:10:45.18,0:10:50.10,Default,,0,0,0,,因此Lisp提供了一种叫做LIST的操作 Dialogue: 0,0:10:53.70,0:10:57.72,Default,,0,0,0,,LIST其实是这种嵌套CONS的缩写 Dialogue: 0,0:10:58.96,0:11:06.32,Default,,0,0,0,,它可以让我用(LIST 1 2 3 4)来构造表 Dialogue: 0,0:11:07.78,0:11:11.74,Default,,0,0,0,,这只是另外一种方式 一种语法糖衣 Dialogue: 0,0:11:11.94,0:11:14.76,Default,,0,0,0,,用来简便地书写嵌套的CONS Dialogue: 0,0:11:14.76,0:11:17.84,Default,,0,0,0,,(CONS (CONS (CONS (CONS NIL)))) Dialogue: 0,0:11:18.48,0:11:39.78,Default,,0,0,0,,举例来说 我将构造一个表(1 2 3 4) 并把它叫做1-TO-4 Dialogue: 0,0:11:47.96,0:11:53.02,Default,,0,0,0,,注意使用这种简便写法的结果 Dialogue: 0,0:11:53.80,0:11:56.92,Default,,0,0,0,,首先 如果我有这个表(1 2 3 4) Dialogue: 0,0:11:57.36,0:12:02.64,Default,,0,0,0,,表的CAR把部分就是这个表的第一个元素 对吧? Dialogue: 0,0:12:04.06,0:12:05.28,Default,,0,0,0,,那么 如何获得元素2呢? Dialogue: 0,0:12:05.28,0:12:23.94,Default,,0,0,0,,2应该是1-TO-4的CDR部分的CAR部分 Dialogue: 0,0:12:23.98,0:12:29.48,Default,,0,0,0,,它的CDR是这个 Dialogue: 0,0:12:29.82,0:12:31.68,Default,,0,0,0,,而它的CAR部分是2 Dialogue: 0,0:12:32.58,0:12:47.42,Default,,0,0,0,,同理 1-TO-4的CDR的CDR的CAR部分 Dialogue: 0,0:12:47.42,0:12:51.36,Default,,0,0,0,,是3 以此类推 Dialogue: 0,0:12:52.68,0:12:55.84,Default,,0,0,0,,我们来看下屏幕 Dialogue: 0,0:12:57.50,0:13:11.18,Default,,0,0,0,,我定义一个表(1 2 3 4) 命名为1-TO-4 Dialogue: 0,0:13:13.78,0:13:21.28,Default,,0,0,0,,我这样写 计算机返回定义完成 这个就是1-TO-4的定义 Dialogue: 0,0:13:22.30,0:13:36.74,Default,,0,0,0,,我问 比如 1-TO-4的CDR的CDR的CAR Dialogue: 0,0:13:38.34,0:13:42.42,Default,,0,0,0,,嗯 它是3 Dialogue: 0,0:13:44.08,0:13:50.08,Default,,0,0,0,,或者我问 1-TO-4是什么 Dialogue: 0,0:13:51.26,0:13:57.22,Default,,0,0,0,,Lisp输出的是用括号包围的 (1 2 3 4) Dialogue: 0,0:13:57.22,0:14:02.12,Default,,0,0,0,,用括号将表中的元素包围起来的这种记号 Dialogue: 0,0:14:02.12,0:14:08.90,Default,,0,0,0,,通常用来打印输出表示序列的序对链 Dialogue: 0,0:14:08.90,0:14:17.14,Default,,0,0,0,,又比如 我问1-TO-4的CDR部分是什么 Dialogue: 0,0:14:19.30,0:14:21.12,Default,,0,0,0,,结果是表的剩余部分 Dialogue: 0,0:14:21.32,0:14:26.96,Default,,0,0,0,,这是原表首元素所指向的序对 新序列从2开始 Dialogue: 0,0:14:28.52,0:14:37.74,Default,,0,0,0,,比如 1-TO-4的CDR的CDR部分是什么 Dialogue: 0,0:14:43.24,0:14:44.68,Default,,0,0,0,,返回(3 4) Dialogue: 0,0:14:44.82,0:14:59.66,Default,,0,0,0,,或者 1-TO-4的CDR的CDR的CDR的CDR部分是什么 Dialogue: 0,0:15:04.74,0:15:10.46,Default,,0,0,0,,我们看一下表的尾指针 Lisp返回() Dialogue: 0,0:15:10.96,0:15:13.48,Default,,0,0,0,,你们可以认为这是一个空表 Dialogue: 0,0:15:14.12,0:15:21.38,Default,,0,0,0,,我求取 1-TO-4的CDR的CDR的CDR部分 Dialogue: 0,0:15:21.42,0:15:25.20,Default,,0,0,0,,这就只剩下表尾指针本身 Dialogue: 0,0:15:25.20,0:15:27.20,Default,,0,0,0,,它的输出是() Dialogue: 0,0:15:34.14,0:15:39.98,Default,,0,0,0,,好了 这是处理表的一种常见方式 Dialogue: 0,0:15:41.50,0:15:43.44,Default,,0,0,0,,也就是不断地取CDR部分 Dialogue: 0,0:15:43.44,0:15:45.00,Default,,0,0,0,,这个叫做表的CDRING Dialogue: 0,0:15:46.64,0:15:49.78,Default,,0,0,0,,当然手写这些CDR非常费劲 Dialogue: 0,0:15:49.78,0:15:52.24,Default,,0,0,0,,我们没必要这么做 我们编写程序来这么做 Dialogue: 0,0:15:52.96,0:15:59.10,Default,,0,0,0,,事实上 Lisp中非常普遍的事情是写一些过程 Dialogue: 0,0:15:59.85,0:16:06.54,Default,,0,0,0,,表中所有元素进行某种操作 得到的是由结果构成的表 Dialogue: 0,0:16:07.42,0:16:11.92,Default,,0,0,0,,比如 我写一个SCALE-LIST的过程 Dialogue: 0,0:16:16.80,0:16:25.24,Default,,0,0,0,,我要用SCALE-LIST将表1-TO-4放大10倍 Dialogue: 0,0:16:26.66,0:16:35.32,Default,,0,0,0,,那么它应该返回表(10 20 30 40) Dialogue: 0,0:16:38.25,0:16:40.25,Default,,0,0,0,,没错 它返回一个表 Dialogue: 0,0:16:44.49,0:16:49.30,Default,,0,0,0,,我们可以猜想到这当中采用了某种递归策略 Dialogue: 0,0:16:49.30,0:16:51.30,Default,,0,0,0,,我应该如何编写这个过程呢? Dialogue: 0,0:16:52.52,0:16:59.80,Default,,0,0,0,,如果要构建一个每个元素都乘以10的列表 Dialogue: 0,0:17:00.44,0:17:04.84,Default,,0,0,0,,需要做的是—假设已经得到了结果表的剩余元素 Dialogue: 0,0:17:05.86,0:17:08.42,Default,,0,0,0,,也就是表的CDR部分 Dialogue: 0,0:17:08.42,0:17:14.16,Default,,0,0,0,,这个子表中的每个元素都是原来元素乘以10 Dialogue: 0,0:17:16.06,0:17:19.68,Default,,0,0,0,,这是SCALE-LIST对表CDR部分作用的结果 Dialogue: 0,0:17:20.12,0:17:23.82,Default,,0,0,0,,我需要做的 就只有用表的CAR部分乘以10 Dialogue: 0,0:17:24.89,0:17:27.24,Default,,0,0,0,,然后用CONS将它和剩余部分连接起来 并返回这个列表 Dialogue: 0,0:17:29.02,0:17:33.09,Default,,0,0,0,,类似地 为了缩放子表 我得先缩放子表的CDR部分 Dialogue: 0,0:17:33.30,0:17:36.20,Default,,0,0,0,,并将其与2*10连接起来 Dialogue: 0,0:17:36.42,0:17:41.16,Default,,0,0,0,,最终 当我处理到表尾时 这里就只剩表尾指针了 Dialogue: 0,0:17:41.72,0:17:45.28,Default,,0,0,0,,它叫做NIL 我就直接返回表尾指针 Dialogue: 0,0:17:45.54,0:17:47.68,Default,,0,0,0,,所以这就是这个过程的递归策略 Dialogue: 0,0:17:47.68,0:17:50.52,Default,,0,0,0,,这个过程就是这样 Dialogue: 0,0:17:50.96,0:17:55.04,Default,,0,0,0,,这个例子就是对表做CDRING操作的通用策略 Dialogue: 0,0:17:55.66,0:17:58.24,Default,,0,0,0,,也就是所谓的“通过CONS组合结果” Dialogue: 0,0:17:58.24,0:18:06.04,Default,,0,0,0,,那么 对表L缩放S倍 我该如何做呢? Dialogue: 0,0:18:06.04,0:18:10.40,Default,,0,0,0,,首先得做判断 Lisp中有个叫NULL?的谓词 Dialogue: 0,0:18:10.40,0:18:13.22,Default,,0,0,0,,NULL?判断对象是否为表尾 Dialogue: 0,0:18:13.90,0:18:17.16,Default,,0,0,0,,或者说 对象是否为空表 Dialogue: 0,0:18:18.17,0:18:23.00,Default,,0,0,0,,任何情况下 当我处理到表尾时 我就将其返回 Dialogue: 0,0:18:23.65,0:18:24.60,Default,,0,0,0,,简单地返回NIL Dialogue: 0,0:18:24.94,0:18:35.14,Default,,0,0,0,,否则 我就用CONS把列表中的第一个元素经过操作(缩放)后的结果 Dialogue: 0,0:18:35.54,0:18:39.29,Default,,0,0,0,,就是说 取L的CAR部分 然后用它乘以S Dialogue: 0,0:18:40.36,0:18:46.34,Default,,0,0,0,,然后我就用CONS将这个结果 与用递归形式缩放后的表的剩下部分 连接在一起 Dialogue: 0,0:18:49.98,0:18:52.18,Default,,0,0,0,,再说一次 总体的思想是 Dialogue: 0,0:18:52.22,0:18:56.09,Default,,0,0,0,,你要用递归的方式处理表中的剩余元素 即表的CDR部分 Dialogue: 0,0:18:56.48,0:19:01.16,Default,,0,0,0,,然后你用CONS将那部分的结果 与经过处理后的表的第一个元素连接在一起 Dialogue: 0,0:19:01.16,0:19:05.18,Default,,0,0,0,,当你处理到结尾的时候 返回表尾标志NIL Dialogue: 0,0:19:07.34,0:19:11.36,Default,,0,0,0,,这就是对一个表里的数据做某种操作的通用模式 Dialogue: 0,0:19:14.05,0:19:19.52,Default,,0,0,0,,现在 你们应该清楚知道这样一个事实 Dialogue: 0,0:19:19.53,0:19:22.62,Default,,0,0,0,,也就是我不必额外为这种基本模式额外编写过程 Dialogue: 0,0:19:22.62,0:19:24.90,Default,,0,0,0,,我要做的事情就是写一个过程 Dialogue: 0,0:19:24.90,0:19:26.32,Default,,0,0,0,,这是这个基本模式 Dialogue: 0,0:19:26.80,0:19:30.30,Default,,0,0,0,,对表中的元素执行操作 并以表的形式返回结果 Dialogue: 0,0:19:30.68,0:19:32.30,Default,,0,0,0,,好了 我们定义一些高阶过程 Dialogue: 0,0:19:32.32,0:19:35.18,Default,,0,0,0,,我们定义一个叫MAP的高阶过程 来完成这些操作 Dialogue: 0,0:19:36.73,0:19:43.17,Default,,0,0,0,,MAP以表L和过程P为参数 Dialogue: 0,0:19:44.92,0:19:51.08,Default,,0,0,0,,并返回对表L中每个元素应用过程P后得到的新表 Dialogue: 0,0:19:51.81,0:19:55.40,Default,,0,0,0,,这个新表里的元素是(P E1) (P E2) ... 到(P En) Dialogue: 0,0:19:55.64,0:20:01.54,Default,,0,0,0,,所以我指的就是对一个表做这样一种变换:将P应用到表的每一个元素上 Dialogue: 0,0:20:02.52,0:20:07.08,Default,,0,0,0,,你们看到的这些过程正是我提到的通用策略 Dialogue: 0,0:20:07.08,0:20:09.08,Default,,0,0,0,,我们用它写乘以10的过程 Dialogue: 0,0:20:09.08,0:20:11.64,Default,,0,0,0,,如果表是空的 则返回NIL Dialogue: 0,0:20:11.86,0:20:16.60,Default,,0,0,0,,否则 对表的首元素应用P Dialogue: 0,0:20:17.14,0:20:18.74,Default,,0,0,0,,将P应用于L的CAR部分 Dialogue: 0,0:20:19.30,0:20:25.40,Default,,0,0,0,,然后连接它和将P应用于表CDR部分中的剩余元素得到的子表连接起来 Dialogue: 0,0:20:25.61,0:20:28.84,Default,,0,0,0,,这就是一个通用过程--MAP Dialogue: 0,0:20:29.86,0:20:39.04,Default,,0,0,0,,我们可以用MAP来定义SCALE-LIST Dialogue: 0,0:20:39.04,0:20:41.04,Default,,0,0,0,,我给你们展示一下 Dialogue: 0,0:20:43.46,0:20:52.50,Default,,0,0,0,,SCALE-LIST就是对表MAP一个特定的过程 Dialogue: 0,0:20:52.50,0:20:55.54,Default,,0,0,0,,这个过程需要一个参数 返回给定参数乘以S的结果 Dialogue: 0,0:20:58.96,0:21:01.90,Default,,0,0,0,,所以我思考缩放表这个过程的正确方式应该是 Dialogue: 0,0:21:02.12,0:21:07.40,Default,,0,0,0,,将这种递归实质实现为通用策略 而不是一个具体针对的过程 Dialogue: 0,0:21:07.40,0:21:11.28,Default,,0,0,0,,当然 这样做的意义之一是 是你会开始发现共性 Dialogue: 0,0:21:12.16,0:21:15.02,Default,,0,0,0,,我们正在掌握使用通用模式 Dialogue: 0,0:21:15.96,0:21:31.18,Default,,0,0,0,,比如 (MAP SQUARE 1-TO-4) 返回(1 4 9 16) Dialogue: 0,0:21:32.48,0:21:37.17,Default,,0,0,0,,对这个表做映射 Dialogue: 0,0:21:37.57,0:21:46.32,Default,,0,0,0,,用(LAMBDA (X) (+ X 10))映射表1-TO-4 Dialogue: 0,0:21:49.68,0:21:52.86,Default,,0,0,0,,我让表的每个元素都加了10 Dialogue: 0,0:21:53.34,0:21:58.17,Default,,0,0,0,,也就是得到了(11 12 13 14) Dialogue: 0,0:22:00.56,0:22:05.76,Default,,0,0,0,,我们看到对表中每个元素做操作是一种非常普遍的想法 Dialogue: 0,0:22:08.66,0:22:12.22,Default,,0,0,0,,而大家需要思考如何编写MAP的迭代版本 Dialogue: 0,0:22:12.22,0:22:16.04,Default,,0,0,0,,我碰巧写的是一个递归版本 Dialogue: 0,0:22:16.36,0:22:19.10,Default,,0,0,0,,但是我们也可以很容易地把它改成迭代过程 Dialogue: 0,0:22:19.10,0:22:23.16,Default,,0,0,0,,有趣的是 一旦你开始用MAP来思考 Dialogue: 0,0:22:24.02,0:22:29.00,Default,,0,0,0,,比如 一旦把缩放看作是一种MAP 就不用关心是迭代还是递归实现 Dialogue: 0,0:22:29.00,0:22:31.82,Default,,0,0,0,,你只会关心 啊 这里有这样一种数据集合 有这样一个表 Dialogue: 0,0:22:32.22,0:22:34.52,Default,,0,0,0,,我要做的是转化表中的每个元素 Dialogue: 0,0:22:34.56,0:22:38.36,Default,,0,0,0,,而不去考虑特别的控制流程或顺序 Dialogue: 0,0:22:38.88,0:22:41.09,Default,,0,0,0,,这是个非常非常重要的想法 Dialogue: 0,0:22:42.36,0:22:46.48,Default,,0,0,0,,我猜这个想法来自APL语言 Dialogue: 0,0:22:46.48,0:22:49.10,Default,,0,0,0,,它是APL中非常重要的思想 Dialogue: 0,0:22:49.12,0:22:51.13,Default,,0,0,0,,即不要去考虑控制结构 Dialogue: 0,0:22:51.41,0:22:53.92,Default,,0,0,0,,而是关注于策略操作 Dialogue: 0,0:22:55.01,0:23:00.01,Default,,0,0,0,,在本课程进行到一半的时候 我们将讨论一种叫做流处理的东西 Dialogue: 0,0:23:00.26,0:23:02.64,Default,,0,0,0,,那时我们将看到这种观点的真正威力 Dialogue: 0,0:23:02.64,0:23:05.30,Default,,0,0,0,,这是一种很聪明的思想 Dialogue: 0,0:23:05.30,0:23:08.70,Default,,0,0,0,,我们可以在以后看到更多应用 Dialogue: 0,0:23:09.36,0:23:16.84,Default,,0,0,0,,还有一些非常有用也非常像MAP的过程 Dialogue: 0,0:23:17.56,0:23:22.54,Default,,0,0,0,,MAP是将某个过程应用于表中每个元素 Dialogue: 0,0:23:22.98,0:23:25.62,Default,,0,0,0,,并返回相应结果构成的表 Dialogue: 0,0:23:25.98,0:23:28.69,Default,,0,0,0,,还有一种与此非常非常相似的操作 Dialogue: 0,0:23:29.32,0:23:35.86,Default,,0,0,0,,也就是给定一个列表和操作 依次将其应用于表中每个元素 Dialogue: 0,0:23:36.29,0:23:39.40,Default,,0,0,0,,而不会建立由结果构成的表 只是为了完成操作 Dialogue: 0,0:23:40.02,0:23:45.10,Default,,0,0,0,,这个过程非常像MAP Dialogue: 0,0:23:45.10,0:23:46.02,Default,,0,0,0,,它就是FOR-EACH Dialogue: 0,0:23:46.74,0:23:49.48,Default,,0,0,0,,它接受一个过程和一个表 Dialogue: 0,0:23:49.62,0:23:53.86,Default,,0,0,0,,它实际上是对表中每个元素执行此操作 Dialogue: 0,0:23:55.16,0:23:58.53,Default,,0,0,0,,通常是这样 如果表非空 Dialogue: 0,0:23:59.74,0:24:01.12,Default,,0,0,0,,也就是不为NIL Dialogue: 0,0:24:01.90,0:24:06.25,Default,,0,0,0,,我将这个过程应用于表的第一个元素 Dialogue: 0,0:24:07.68,0:24:11.66,Default,,0,0,0,,然后对表中其余元素做同样的事情 Dialogue: 0,0:24:12.44,0:24:15.25,Default,,0,0,0,,我将FOR-EACH也应用于表的CDR部分 Dialogue: 0,0:24:15.88,0:24:18.73,Default,,0,0,0,,我对表的首元素进行处理 然后对表其余部分进行处理 Dialogue: 0,0:24:19.32,0:24:23.92,Default,,0,0,0,,当然 以此类推 递归地调用 又会对表其余部分的其余部分做处理 Dialogue: 0,0:24:23.92,0:24:28.12,Default,,0,0,0,,最终 过程结束时 我应该告知系统 Dialogue: 0,0:24:28.16,0:24:32.40,Default,,0,0,0,,所以就返回“DONE” 所以这非常像MAP Dialogue: 0,0:24:32.80,0:24:35.12,Default,,0,0,0,,它们之间只是返回值不同 Dialogue: 0,0:24:35.48,0:24:39.90,Default,,0,0,0,,比如说 如果我有一个可以在屏幕上打印对象的过程 Dialogue: 0,0:24:40.56,0:24:45.81,Default,,0,0,0,,如果我想打印表中的所有元素 可以调用(FOR-EACH PRINT LIST) Dialogue: 0,0:24:46.78,0:24:51.33,Default,,0,0,0,,如果我有一系列图表构成的表 想把它们输出在屏幕上 Dialogue: 0,0:24:51.62,0:24:54.86,Default,,0,0,0,,我可以对这个调用(FOR-EACH DISPLAY FIGURES) Dialogue: 0,0:24:58.18,0:24:59.32,Default,,0,0,0,,有问题么? Dialogue: 0,0:25:00.62,0:25:04.26,Default,,0,0,0,,学生:除非你明确地指定 Dialogue: 0,0:25:04.30,0:25:07.54,Default,,0,0,0,,Lisp会创建一个你正在处理的对象的新拷贝 是这样么? Dialogue: 0,0:25:07.54,0:25:09.18,Default,,0,0,0,,教授:对 Dialogue: 0,0:25:09.93,0:25:10.94,Default,,0,0,0,,就是这样 Dialogue: 0,0:25:10.94,0:25:15.14,Default,,0,0,0,,FOR-EACH不创建新列表 它只是对列表的每一个元素进行处理 Dialogue: 0,0:25:15.14,0:25:17.29,Default,,0,0,0,,所以如果你有一堆事情等着做 Dialogue: 0,0:25:18.02,0:25:21.56,Default,,0,0,0,,并且你并不关心这些值 比如打印 绘图 Dialogue: 0,0:25:21.89,0:25:24.60,Default,,0,0,0,,或者在终端中响铃等等 Dialogue: 0,0:25:24.60,0:25:27.64,Default,,0,0,0,,FOR-EACH对表中每个元素做这些事 Dialogue: 0,0:25:28.21,0:25:32.42,Default,,0,0,0,,而MAP其实构建了一个新集合 这个集合也许是你想要用的 Dialogue: 0,0:25:32.42,0:25:34.16,Default,,0,0,0,,这就是它们之间的微妙关系 Dialogue: 0,0:25:34.16,0:25:36.30,Default,,0,0,0,,学生:你能否用FOR-EACH来构造MAP Dialogue: 0,0:25:36.32,0:25:40.16,Default,,0,0,0,,其中你用类似CONS的操作将表又构造出来了? Dialogue: 0,0:25:40.18,0:25:44.46,Default,,0,0,0,,教授:某种程度上 我也许可以 Dialogue: 0,0:25:44.46,0:25:49.98,Default,,0,0,0,,我不知道如何随手写出它 但是我可以给一些思路 Dialogue: 0,0:25:50.48,0:25:54.73,Default,,0,0,0,,学生:根据昨天的课程 我认为MAP和FOR-EACH的关键区别在于 Dialogue: 0,0:25:54.73,0:26:00.62,Default,,0,0,0,,它们之中一个是递归的 而另一个不是 Dialogue: 0,0:26:01.24,0:26:03.86,Default,,0,0,0,,教授:是的 关于MAP和FOR-EACH和递归 Dialogue: 0,0:26:03.86,0:26:05.48,Default,,0,0,0,,这个观点很好 Dialogue: 0,0:26:05.48,0:26:13.08,Default,,0,0,0,,我写的MAP过程恰巧是一个递归过程 Dialogue: 0,0:26:13.82,0:26:17.06,Default,,0,0,0,,这是因为 你需要得到处理完表的剩余部分后的值 Dialogue: 0,0:26:17.08,0:26:20.96,Default,,0,0,0,,使其与表的开头部分相连 Dialogue: 0,0:26:21.73,0:26:24.53,Default,,0,0,0,,但是FOR-EACH不需要等待返回值 Dialogue: 0,0:26:24.84,0:26:26.66,Default,,0,0,0,,所以它变成了一个迭代的过程 Dialogue: 0,0:26:26.66,0:26:27.72,Default,,0,0,0,,这不是本质 Dialogue: 0,0:26:27.72,0:26:31.80,Default,,0,0,0,,我可以用迭代的方式定义MAP过程 Dialogue: 0,0:26:31.82,0:26:32.82,Default,,0,0,0,,只是我没那么做 Dialogue: 0,0:26:34.24,0:26:42.90,Default,,0,0,0,,学生:将FOR-EACH用在一个列表的列表上的话 我想这是可行的吧? Dialogue: 0,0:26:42.90,0:26:48.10,Default,,0,0,0,,它会对这些内部列表的元素进行处理么? Dialogue: 0,0:26:48.70,0:26:50.40,Default,,0,0,0,,教授:问题是 如果我调用 Dialogue: 0,0:26:50.40,0:26:52.28,Default,,0,0,0,,FOR-EACH或者MAP Dialogue: 0,0:26:52.81,0:26:55.28,Default,,0,0,0,,参数是一个嵌套有一个表的表 Dialogue: 0,0:26:56.69,0:27:00.60,Default,,0,0,0,,虽然我们还没有讲过这个 但是那是可行的 Dialogue: 0,0:27:01.02,0:27:06.56,Default,,0,0,0,,答案是肯定的 不过我俩对“可行”的定义可能有些不同 Dialogue: 0,0:27:06.86,0:27:10.65,Default,,0,0,0,,来看一下 如果我给你一个表 Dialogue: 0,0:27:12.80,0:27:14.20,Default,,0,0,0,,而在个箭头所指的 Dialogue: 0,0:27:16.06,0:27:21.46,Default,,0,0,0,,不是一个数 而是一个表 或者序对 或者是其它东西 Dialogue: 0,0:27:21.96,0:27:24.54,Default,,0,0,0,,FOR-EACH对表中的每个元素做处理 Dialogue: 0,0:27:24.54,0:27:26.96,Default,,0,0,0,,它会不断地处理表CDR部分 Dialogue: 0,0:27:26.96,0:27:27.20,Default,,0,0,0,,学生:嗯 Dialogue: 0,0:27:27.20,0:27:31.06,Default,,0,0,0,,教授:对FOR-EACH来说 表中的第一个元素就是这个箭头所指的东西 Dialogue: 0,0:27:31.06,0:27:31.65,Default,,0,0,0,,学生:唔 Dialogue: 0,0:27:31.65,0:27:33.94,Default,,0,0,0,,教授:这对于你要完成的任务而言 也许是对的 也许不是 Dialogue: 0,0:27:33.94,0:27:35.57,Default,,0,0,0,,学生:所以不能进入子表中 Dialogue: 0,0:27:35.57,0:27:36.91,Default,,0,0,0,,教授:绝对不能 Dialogue: 0,0:27:36.91,0:27:38.51,Default,,0,0,0,,当然我也可以那样写程序 Dialogue: 0,0:27:38.51,0:27:42.97,Default,,0,0,0,,你所说的是另一种公共模式 叫做树递归 Dialogue: 0,0:27:43.01,0:27:47.94,Default,,0,0,0,,当你给它一个表 它会不断向深度递归 直到遇到所谓的“树叶” Dialogue: 0,0:27:47.94,0:27:51.05,Default,,0,0,0,,你可以写出来这个过程 但是它既不是FOR-EACH也不是MAP Dialogue: 0,0:27:52.42,0:27:55.05,Default,,0,0,0,,FOR-EACH和MAP都很简单 Dialogue: 0,0:27:55.77,0:27:56.89,Default,,0,0,0,,好 还有问题么? Dialogue: 0,0:27:57.68,0:27:58.57,Default,,0,0,0,,好的 大家休息一下吧 Dialogue: 0,0:27:59.11,0:28:10.99,Default,,0,0,0,,[音乐] Dialogue: 0,0:28:11.46,0:28:14.29,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:28:14.32,0:28:17.52,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:28:27.38,0:28:34.22,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:28:34.86,0:28:38.58,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson-Escher的例子 Dialogue: 0,0:28:41.94,0:28:48.65,Default,,0,0,0,,教授:我将在本节课余下的时间中 讨论一个实例 Dialogue: 0,0:28:50.04,0:28:53.92,Default,,0,0,0,,这个实例 可以充分地总结我们所学的所有东西 Dialogue: 0,0:28:54.74,0:28:56.29,Default,,0,0,0,,比如 表结构 Dialogue: 0,0:28:57.17,0:28:59.48,Default,,0,0,0,,以及抽象的技术 Dialogue: 0,0:28:59.54,0:29:00.82,Default,,0,0,0,,数据的表示 Dialogue: 0,0:29:01.60,0:29:04.60,Default,,0,0,0,,和用高阶过程描绘共性 Dialogue: 0,0:29:04.60,0:29:09.80,Default,,0,0,0,,也会介绍目前为止还没怎么谈论过的 Dialogue: 0,0:29:09.85,0:29:13.46,Default,,0,0,0,,也就是这门课的第三大主题 Dialogue: 0,0:29:13.96,0:29:15.53,Default,,0,0,0,,元语言抽象 Dialogue: 0,0:29:15.54,0:29:21.90,Default,,0,0,0,,这种在工程设计中控制复杂度的思想 Dialogue: 0,0:29:22.86,0:29:25.80,Default,,0,0,0,,也就是建立一个合适而强大的语言 Dialogue: 0,0:29:28.17,0:29:34.74,Default,,0,0,0,,你们或许记得 我说过在这门课程中 你们将要学到的最重要的事情是 Dialogue: 0,0:29:34.74,0:29:41.17,Default,,0,0,0,,当我们考察一门语言时 关心的是它的基本元素 Dialogue: 0,0:29:42.98,0:29:46.69,Default,,0,0,0,,关心它的组合方法 Dialogue: 0,0:29:49.72,0:29:52.80,Default,,0,0,0,,关心那些让你能够构建更大东西的东西 Dialogue: 0,0:29:53.61,0:29:55.24,Default,,0,0,0,,以及 抽象的方式 Dialogue: 0,0:30:00.97,0:30:05.16,Default,,0,0,0,,如何取用这些你构造出来的“大东西” Dialogue: 0,0:30:05.56,0:30:07.97,Default,,0,0,0,,并将它们放入“黑盒”中 Dialogue: 0,0:30:08.45,0:30:11.71,Default,,0,0,0,,然后用它们来构建更复杂的东西 Dialogue: 0,0:30:13.53,0:30:18.72,Default,,0,0,0,,我将要介绍的一种语言 就是元语言抽象的一个例子 Dialogue: 0,0:30:18.73,0:30:22.70,Default,,0,0,0,,那是我朋友Peter Handerson发明的 Dialogue: 0,0:30:28.24,0:30:31.74,Default,,0,0,0,,他来自苏格兰的Stirling大学 Dialogue: 0,0:30:32.78,0:30:40.98,Default,,0,0,0,,这个语言是用来画这样的图 Dialogue: 0,0:30:41.86,0:30:46.66,Default,,0,0,0,,这是埃舍尔的木版画 《方形极限》 Dialogue: 0,0:30:49.33,0:30:57.94,Default,,0,0,0,,正如大家所见 这里面有着很复杂的...图像的递归 Dialogue: 0,0:30:58.84,0:31:01.46,Default,,0,0,0,,其中中间的鱼形图案以自相似的方式 Dialogue: 0,0:31:01.70,0:31:04.56,Default,,0,0,0,,不断地以更小的形式出现在原来的团案旁边 Dialogue: 0,0:31:08.49,0:31:12.80,Default,,0,0,0,,总之 Peter Hendersion的语言是用来表述这类图形 Dialogue: 0,0:31:13.37,0:31:18.28,Default,,0,0,0,,并且设计类似的图形 将它画在显示器上 Dialogue: 0,0:31:20.24,0:31:27.48,Default,,0,0,0,,这个例子还展示了另外一个主题 Dialogue: 0,0:31:28.09,0:31:32.02,Default,,0,0,0,,这也是我跟Gerry教授多次强调的 Dialogue: 0,0:31:32.02,0:31:36.17,Default,,0,0,0,,也就是过程跟数据之间没有本质的区别 Dialogue: 0,0:31:37.26,0:31:42.40,Default,,0,0,0,,不管如何 我希望今早课程结束后 Dialogue: 0,0:31:42.58,0:31:47.60,Default,,0,0,0,,你们能将过程和数据当作一回事儿 Dialogue: 0,0:31:47.96,0:31:49.58,Default,,0,0,0,,即使现在你们还将它们区别对待 Dialogue: 0,0:31:50.80,0:31:55.28,Default,,0,0,0,,那么 先让我们看一下Peter的语言 Dialogue: 0,0:31:55.28,0:31:57.26,Default,,0,0,0,,我先告诉你们基本元素是什么 Dialogue: 0,0:31:58.29,0:32:00.92,Default,,0,0,0,,这个语言非常简单 因为它的基本元素只有一个 Dialogue: 0,0:32:03.33,0:32:06.30,Default,,0,0,0,,这个基本元素不是大家想象的那样 Dialogue: 0,0:32:07.08,0:32:09.18,Default,,0,0,0,,它唯一的基本元素叫做"图像" Dialogue: 0,0:32:09.70,0:32:12.11,Default,,0,0,0,,但此“图像”非彼“图像” Dialogue: 0,0:32:12.11,0:32:14.17,Default,,0,0,0,,具体地来说 Dialogue: 0,0:32:14.17,0:32:15.17,Default,,0,0,0,,这是George的图像 Dialogue: 0,0:32:19.01,0:32:20.37,Default,,0,0,0,,我们的想法是 Dialogue: 0,0:32:22.33,0:32:24.57,Default,,0,0,0,,在这个语言中的图像是这样一个东西 Dialogue: 0,0:32:24.89,0:32:31.46,Default,,0,0,0,,它能在你指定的一个矩形里画出一个缩放好图像 Dialogue: 0,0:32:33.00,0:32:34.42,Default,,0,0,0,,这里大家看到的强调线 Dialogue: 0,0:32:34.42,0:32:37.70,Default,,0,0,0,,是这个矩形的轮廓 但不是图像的一部分 Dialogue: 0,0:32:40.49,0:32:47.17,Default,,0,0,0,,但是一旦指定一个矩形区域 图像会以以填充的方式绘制满区域 Dialogue: 0,0:32:47.17,0:32:52.16,Default,,0,0,0,,比如 这个是George 在这里 这个也是George Dialogue: 0,0:32:53.21,0:32:56.65,Default,,0,0,0,,它是同一个图像 只是缩放程度不同 Dialogue: 0,0:32:57.40,0:32:59.28,Default,,0,0,0,,这是“胖”George的版本 Dialogue: 0,0:33:00.01,0:33:03.44,Default,,0,0,0,,这个也是George Dialogue: 0,0:33:03.81,0:33:05.14,Default,,0,0,0,,这是同一个图形 Dialogue: 0,0:33:05.14,0:33:09.57,Default,,0,0,0,,这个语言中 这三个都是同一个图像 Dialogue: 0,0:33:09.58,0:33:13.04,Default,,0,0,0,,仅仅是给了不同的矩形区域让它来填充 Dialogue: 0,0:33:16.08,0:33:20.65,Default,,0,0,0,,这就是基本元素 Dialogue: 0,0:33:21.44,0:33:25.25,Default,,0,0,0,,现在 我们来讨论元素组合和操作 Dialogue: 0,0:33:25.90,0:33:30.17,Default,,0,0,0,,比如 这里有一个叫做旋转的操作 Dialogue: 0,0:33:31.09,0:33:33.66,Default,,0,0,0,,如果我有一个图像 “旋转”操作就是 Dialogue: 0,0:33:35.37,0:33:39.93,Default,,0,0,0,,先假定有一个里面有个“A”的矩形 Dialogue: 0,0:33:41.84,0:33:45.73,Default,,0,0,0,,而旋转90度的操作则会 Dialogue: 0,0:33:47.02,0:33:50.65,Default,,0,0,0,,在一个给定的矩形内 绘制同样的图像 Dialogue: 0,0:33:50.65,0:33:53.88,Default,,0,0,0,,但是 会缩放图像以适应矩形 Dialogue: 0,0:33:56.11,0:33:58.34,Default,,0,0,0,,这个就是旋转90度 Dialogue: 0,0:33:58.34,0:34:03.20,Default,,0,0,0,,另一个操作是“翻转” 可以水平翻转也可以竖直翻转 Dialogue: 0,0:34:04.77,0:34:06.00,Default,,0,0,0,,就是这些操作了 Dialogue: 0,0:34:06.01,0:34:10.40,Default,,0,0,0,,或者你可以把它们认为是组合一个元素的各种方式 Dialogue: 0,0:34:10.89,0:34:12.42,Default,,0,0,0,,我可以把它们混合起来 Dialogue: 0,0:34:13.44,0:34:15.54,Default,,0,0,0,,我们有一种叫BESIDE的操作 Dialogue: 0,0:34:16.46,0:34:24.78,Default,,0,0,0,,它做的事情是 给定两个图像A、B -- Dialogue: 0,0:34:29.02,0:34:33.25,Default,,0,0,0,,这里图像是指能在指定的矩形中画一个图案的东西 -- Dialogue: 0,0:34:34.05,0:34:36.51,Default,,0,0,0,,BESIDE将会做的事情 Dialogue: 0,0:34:37.85,0:34:44.08,Default,,0,0,0,,类似于调用(BESIDE A B S) 其中S是一个数 Dialogue: 0,0:34:45.34,0:34:48.08,Default,,0,0,0,,是一个在0到1之间的数 Dialogue: 0,0:34:50.51,0:34:52.57,Default,,0,0,0,,BESIDE绘制像这样的图像 Dialogue: 0,0:34:52.57,0:34:56.71,Default,,0,0,0,,以给定的矩形为基础 但会将基底缩放S Dialogue: 0,0:34:56.71,0:34:58.71,Default,,0,0,0,,这里S是0.5 Dialogue: 0,0:35:00.18,0:35:07.17,Default,,0,0,0,,在这里 它会在这里画第一个图案 Dialogue: 0,0:35:07.81,0:35:12.65,Default,,0,0,0,,在这里画第二个图案 Dialogue: 0,0:35:13.82,0:35:16.44,Default,,0,0,0,,又比如说 我另设一个S的值 Dialogue: 0,0:35:16.81,0:35:23.02,Default,,0,0,0,,比如调用(BESIDE A B 0.25) Dialogue: 0,0:35:25.94,0:35:29.09,Default,,0,0,0,,效果相同 只不过A更瘦了 Dialogue: 0,0:35:34.05,0:35:36.28,Default,,0,0,0,,而B是这样的 Dialogue: 0,0:35:37.82,0:35:40.29,Default,,0,0,0,,这就是组合方法之一:BESIDE Dialogue: 0,0:35:40.68,0:35:46.05,Default,,0,0,0,,类似地 ABOVE方法在竖直方向上做这种操作 Dialogue: 0,0:35:47.84,0:35:48.89,Default,,0,0,0,,我们来看一下 Dialogue: 0,0:35:50.74,0:35:56.00,Default,,0,0,0,,这是George和他的"弟弟" Dialogue: 0,0:35:56.72,0:36:07.05,Default,,0,0,0,,这是通过将George放在一旁 Dialogue: 0,0:36:10.36,0:36:14.42,Default,,0,0,0,,George与空图像的上下组合放在另一旁 Dialogue: 0,0:36:14.52,0:36:16.14,Default,,0,0,0,,这样做的意图很明显 Dialogue: 0,0:36:16.14,0:36:19.14,Default,,0,0,0,,空图像放在了另一个George的上面 Dialogue: 0,0:36:19.14,0:36:21.14,Default,,0,0,0,,合成的图像又放在了George的旁边 Dialogue: 0,0:36:28.96,0:36:30.34,Default,,0,0,0,,这个是图像P Dialogue: 0,0:36:31.10,0:36:39.04,Default,,0,0,0,,像之前一样 是George和翻转后George的BESIDE组合 Dialogue: 0,0:36:40.53,0:36:42.08,Default,,0,0,0,,这里 我们做的是水平翻转 Dialogue: 0,0:36:42.37,0:36:44.80,Default,,0,0,0,,然后整体旋转180度 Dialogue: 0,0:36:45.80,0:36:50.82,Default,,0,0,0,,然后调用BESIDE让它们组合在一起 系数是0.5 Dialogue: 0,0:36:52.56,0:36:53.90,Default,,0,0,0,,这样 我创建了图像P Dialogue: 0,0:36:55.90,0:36:57.88,Default,,0,0,0,,然后使用图像P Dialogue: 0,0:36:59.21,0:37:04.96,Default,,0,0,0,,与它的翻转图像做ABOVE操作 形成图像Q Dialogue: 0,0:37:09.20,0:37:13.26,Default,,0,0,0,,请注意 我们是如何快速地增加复杂度 Dialogue: 0,0:37:14.36,0:37:21.05,Default,,0,0,0,,转瞬之间 我们使用George组合得到了Q 这说明了什么? Dialogue: 0,0:37:22.05,0:37:24.55,Default,,0,0,0,,为什么我们可以做得如此迅速呢? Dialogue: 0,0:37:25.85,0:37:28.02,Default,,0,0,0,,答案是闭包性质 Dialogue: 0,0:37:28.69,0:37:32.98,Default,,0,0,0,,这是因为 当我将两个图像做BESIDE操作后 Dialogue: 0,0:37:34.30,0:37:35.29,Default,,0,0,0,,得到的也是图像 Dialogue: 0,0:37:35.33,0:37:37.78,Default,,0,0,0,,我可以继续执行 ROTATE FLIP 或者 ABOVE操作 Dialogue: 0,0:37:39.17,0:37:40.88,Default,,0,0,0,,而操作的结果P Dialogue: 0,0:37:40.89,0:37:44.88,Default,,0,0,0,,BESIDE FLIP ROTATE操作的结果也是一个图像 Dialogue: 0,0:37:45.22,0:37:50.20,Default,,0,0,0,,在这种组合方法下 图像的世界是封闭的 Dialogue: 0,0:37:50.77,0:37:52.24,Default,,0,0,0,,所以 任何时候我都可以 Dialogue: 0,0:37:52.48,0:37:55.17,Default,,0,0,0,,以一个东西为基本元素 去构造别的东西 Dialogue: 0,0:37:56.33,0:37:58.52,Default,,0,0,0,,这个例子比表和线段更直观 Dialogue: 0,0:37:58.54,0:38:03.28,Default,,0,0,0,,它揭示了 我们如和用封闭的操作 快速增加复杂度 Dialogue: 0,0:38:07.48,0:38:12.02,Default,,0,0,0,,在构建更多东西之前 Dialogue: 0,0:38:12.04,0:38:14.77,Default,,0,0,0,,我们先来看看这个语言是如何实现的 Dialogue: 0,0:38:16.91,0:38:21.50,Default,,0,0,0,,其中基本的一个元素 Dialogue: 0,0:38:21.93,0:38:24.52,Default,,0,0,0,,是一个称作“矩形”的东西 Dialogue: 0,0:38:26.09,0:38:28.28,Default,,0,0,0,,所谓的矩形就是 Dialogue: 0,0:38:28.28,0:38:33.68,Default,,0,0,0,,它有一个原点 Dialogue: 0,0:38:36.45,0:38:40.18,Default,,0,0,0,,原点是一个向量 用以说明矩形是从哪开始 Dialogue: 0,0:38:40.18,0:38:42.29,Default,,0,0,0,,至于其它的向量 Dialogue: 0,0:38:43.66,0:38:46.33,Default,,0,0,0,,我们称其为矩形的水平分量 Dialogue: 0,0:38:55.76,0:38:59.25,Default,,0,0,0,,还有就是矩形的竖直分量 Dialogue: 0,0:39:00.49,0:39:02.68,Default,,0,0,0,,这就是构成矩形的三个基本元素 Dialogue: 0,0:39:02.68,0:39:04.51,Default,,0,0,0,,两个向量用作 Dialogue: 0,0:39:04.93,0:39:09.97,Default,,0,0,0,,计算左上角和右下角的顶点坐标 Dialogue: 0,0:39:09.97,0:39:12.37,Default,,0,0,0,,这三个向量确定了一个矩形 Dialogue: 0,0:39:16.00,0:39:18.93,Default,,0,0,0,,为了构建矩形 我们假设 Dialogue: 0,0:39:19.77,0:39:22.06,Default,,0,0,0,,假设有个“构建矩形”的构造函数 Dialogue: 0,0:39:23.01,0:39:24.26,Default,,0,0,0,,也就是MAKE-RECT Dialogue: 0,0:39:27.56,0:39:35.17,Default,,0,0,0,,以及选择函数 HORIZ、VERT 和 ORIGIN Dialogue: 0,0:39:37.58,0:39:39.65,Default,,0,0,0,,用于取得对应的矩形属性 Dialogue: 0,0:39:39.65,0:39:42.54,Default,,0,0,0,,我们知道有很多方法可以实现它 Dialogue: 0,0:39:42.54,0:39:47.62,Default,,0,0,0,,可以用序对或者表 或者其它东西 Dialogue: 0,0:39:47.62,0:39:51.40,Default,,0,0,0,,但是 这些东西的实现是George的事 Dialogue: 0,0:39:51.40,0:39:53.17,Default,,0,0,0,,这是一个数据表示的问题 Dialogue: 0,0:39:53.17,0:39:55.47,Default,,0,0,0,,现在我们假设已经有了这些矩形了 Dialogue: 0,0:39:59.05,0:40:05.08,Default,,0,0,0,,好的 现在来看我们接下来要做的事情 Dialogue: 0,0:40:05.08,0:40:08.22,Default,,0,0,0,,我们需要关心如何取用图像 Dialogue: 0,0:40:09.33,0:40:12.97,Default,,0,0,0,,将它缩放以适应你给定的矩形 Dialogue: 0,0:40:13.60,0:40:16.60,Default,,0,0,0,,我们要来安排这些事 Dialogue: 0,0:40:16.60,0:40:18.60,Default,,0,0,0,,来完成图像的缩放 Dialogue: 0,0:40:22.22,0:40:23.65,Default,,0,0,0,,有哪些思路呢? Dialogue: 0,0:40:23.65,0:40:27.08,Default,,0,0,0,,一种想法是:无论何时给定一个矩形 Dialogue: 0,0:40:35.68,0:40:38.68,Default,,0,0,0,,无论何时给定一个矩形 也就是说 Dialogue: 0,0:40:39.25,0:40:45.77,Default,,0,0,0,,这在某种意义上是把正方形转换成矩形 Dialogue: 0,0:40:45.77,0:40:46.54,Default,,0,0,0,,也就是说 Dialogue: 0,0:40:46.54,0:40:48.53,Default,,0,0,0,,我所谓的正方形 Dialogue: 0,0:40:49.04,0:40:59.04,Default,,0,0,0,,它的坐标是(0,0)、(1,0)和(1,1) Dialogue: 0,0:41:01.40,0:41:05.72,Default,,0,0,0,,我们有一些显而易见的缩放变换 Dialogue: 0,0:41:06.12,0:41:10.22,Default,,0,0,0,,可以把这个映射成这个 把这个映射成这个 Dialogue: 0,0:41:10.24,0:41:12.08,Default,,0,0,0,,并且 把所有的东西统一地拉伸 Dialogue: 0,0:41:12.17,0:41:18.25,Default,,0,0,0,,我们将这样的一条的线段 Dialogue: 0,0:41:19.73,0:41:24.20,Default,,0,0,0,,将它最终映射到像那样的一条线段 Dialogue: 0,0:41:26.20,0:41:32.68,Default,,0,0,0,,而点(X,Y)变成了这里的另外一个点 Dialogue: 0,0:41:32.68,0:41:39.37,Default,,0,0,0,,这个不紧要 会点向量运算 就能写出变换公式 Dialogue: 0,0:41:39.37,0:41:43.18,Default,,0,0,0,,初始点(X,Y)将会变换到的点的坐标是 Dialogue: 0,0:41:43.58,0:41:50.74,Default,,0,0,0,,以矩形原点为基础做向量加法 Dialogue: 0,0:41:51.16,0:41:55.48,Default,,0,0,0,,加上 初始点X坐标 一个介于0和1之间的值 Dialogue: 0,0:41:55.98,0:42:01.84,Default,,0,0,0,,并乘上矩形的水平向量 Dialogue: 0,0:42:07.62,0:42:11.00,Default,,0,0,0,,再加上初始点的Y坐标 也是一个介于0和1的值 Dialogue: 0,0:42:11.38,0:42:16.28,Default,,0,0,0,,并乘上矩形的竖直向量 Dialogue: 0,0:42:16.74,0:42:19.31,Default,,0,0,0,,这是简单的线性代数 Dialogue: 0,0:42:19.31,0:42:23.48,Default,,0,0,0,,这个就是正确的变换公式 Dialogue: 0,0:42:23.69,0:42:28.18,Default,,0,0,0,,它将方形中的物件转化到对应矩形中 Dialogue: 0,0:42:31.34,0:42:34.02,Default,,0,0,0,,现在 我们把它看作是一个过程 Dialogue: 0,0:42:35.16,0:42:36.29,Default,,0,0,0,,我们想要得到的是 Dialogue: 0,0:42:37.80,0:42:40.82,Default,,0,0,0,,由一个单位正方形到特定矩形的 Dialogue: 0,0:42:41.01,0:42:42.52,Default,,0,0,0,,特定变换过程 Dialogue: 0,0:42:43.80,0:42:45.22,Default,,0,0,0,,这个过程具体是这样的 Dialogue: 0,0:42:45.22,0:42:47.22,Default,,0,0,0,,我叫它COORD-MAP Dialogue: 0,0:42:47.77,0:42:52.00,Default,,0,0,0,,COORD-MAP以一个矩形作为参数 Dialogue: 0,0:42:53.60,0:42:57.85,Default,,0,0,0,,它返回一个以点为参数的过程 Dialogue: 0,0:43:00.45,0:43:06.82,Default,,0,0,0,,每个矩形 都对应一个变换点(X, Y)坐标的过程 Dialogue: 0,0:43:06.82,0:43:08.02,Default,,0,0,0,,是怎么得到的呢? Dialogue: 0,0:43:08.02,0:43:10.92,Default,,0,0,0,,就如黑板上的Lisp代码所示 Dialogue: 0,0:43:10.92,0:43:16.01,Default,,0,0,0,,我让矩形的原点加上-- Dialogue: 0,0:43:20.22,0:43:25.02,Default,,0,0,0,,首先是 矩形水平部分 Dialogue: 0,0:43:25.02,0:43:27.68,Default,,0,0,0,,按照点POINT的X坐标缩放 Dialogue: 0,0:43:29.65,0:43:32.62,Default,,0,0,0,,然后是 矩形竖直部分 Dialogue: 0,0:43:33.51,0:43:37.14,Default,,0,0,0,,按照点POINT的Y坐标缩放 Dialogue: 0,0:43:37.14,0:43:39.14,Default,,0,0,0,,然后把它们三个加到一起 Dialogue: 0,0:43:40.13,0:43:41.34,Default,,0,0,0,,这个过程就是这样 Dialogue: 0,0:43:41.34,0:43:44.54,Default,,0,0,0,,这就是我将要应用在点POINT上的过程 Dialogue: 0,0:43:46.54,0:43:52.17,Default,,0,0,0,,这个过程由每个矩形自己生成 Dialogue: 0,0:43:52.17,0:43:57.25,Default,,0,0,0,,每个矩形对应了一个定义在点集上的过程 COORD-MAP Dialogue: 0,0:44:06.66,0:44:10.42,Default,,0,0,0,,比如说 这里的George Dialogue: 0,0:44:11.36,0:44:16.34,Default,,0,0,0,,最初的George 可能是我在单位正方形中通过线段绘制的 Dialogue: 0,0:44:19.50,0:44:21.96,Default,,0,0,0,,而当我把它应用到一个新的矩形中 Dialogue: 0,0:44:24.14,0:44:28.17,Default,,0,0,0,,我将会在新矩形中画出组成George的那些线段来 Dialogue: 0,0:44:28.17,0:44:29.88,Default,,0,0,0,,我是怎么做的呢? Dialogue: 0,0:44:30.68,0:44:36.94,Default,,0,0,0,,我枚举原始George中的每条线段 Dialogue: 0,0:44:38.64,0:44:40.58,Default,,0,0,0,,我对每条线段的终点 Dialogue: 0,0:44:40.88,0:44:44.45,Default,,0,0,0,,应用目标矩形对应的COORD-MAP过程 Dialogue: 0,0:44:44.45,0:44:46.06,Default,,0,0,0,,比如下面的这个矩形 Dialogue: 0,0:44:46.66,0:44:50.88,Default,,0,0,0,,这个胖George 有它对应的COORD-MAP Dialogue: 0,0:44:51.25,0:44:53.69,Default,,0,0,0,,如果我要绘制这个图像 Dialogue: 0,0:44:55.38,0:44:57.92,Default,,0,0,0,,需要做的就是对这里的每条线段 比如这条 Dialogue: 0,0:44:59.29,0:45:05.34,Default,,0,0,0,,用COORD-MAP变换这个点 同时变换这个点 Dialogue: 0,0:45:05.34,0:45:07.09,Default,,0,0,0,,我就得到了这两个点 Dialogue: 0,0:45:07.38,0:45:08.94,Default,,0,0,0,,就可以将在两点之间画线 Dialogue: 0,0:45:09.71,0:45:11.52,Default,,0,0,0,,这就是核心思路 Dialogue: 0,0:45:12.66,0:45:14.78,Default,,0,0,0,,那么如果我给一个不同的矩形 比如这个 Dialogue: 0,0:45:14.80,0:45:15.76,Default,,0,0,0,,得到的是不同的COORD-MAP Dialogue: 0,0:45:15.79,0:45:17.84,Default,,0,0,0,,因此我得到这些线段的不同图像 Dialogue: 0,0:45:19.28,0:45:22.14,Default,,0,0,0,,基本图像又该如何表示呢? Dialogue: 0,0:45:22.14,0:45:26.52,Default,,0,0,0,,可以用线段组成的表来表示 Dialogue: 0,0:45:27.61,0:45:32.20,Default,,0,0,0,,这是用于构建我所谓的“基本图像”的过程 Dialogue: 0,0:45:33.48,0:45:37.17,Default,,0,0,0,,意思是 没有用BESIDE ROTATE等操作 Dialogue: 0,0:45:37.52,0:45:39.60,Default,,0,0,0,,它以由线段组成的表为参数 Dialogue: 0,0:45:42.94,0:45:44.04,Default,,0,0,0,,代码具体行为如下 Dialogue: 0,0:45:44.04,0:45:45.58,Default,,0,0,0,,图像会是什么样子呢? Dialogue: 0,0:45:45.58,0:45:49.44,Default,,0,0,0,,首先 它是一个根据矩形定义的过程 Dialogue: 0,0:45:51.70,0:45:53.00,Default,,0,0,0,,这个过程做什么呢? Dialogue: 0,0:45:53.00,0:45:56.56,Default,,0,0,0,,对于由线段组成的表中每个元素 Dialogue: 0,0:45:57.66,0:46:03.38,Default,,0,0,0,,表中的每条线段S Dialogue: 0,0:46:05.89,0:46:07.30,Default,,0,0,0,,都绘制了一条线 Dialogue: 0,0:46:07.30,0:46:08.82,Default,,0,0,0,,它画什么样的线段呢? Dialogue: 0,0:46:10.60,0:46:12.84,Default,,0,0,0,,先得到线段的起点 Dialogue: 0,0:46:15.22,0:46:17.94,Default,,0,0,0,,用对应的COORD-MAP对其做变换 Dialogue: 0,0:46:19.54,0:46:21.76,Default,,0,0,0,,这是我们想要的第一个点 Dialogue: 0,0:46:21.76,0:46:26.32,Default,,0,0,0,,然后对线段终点做COORD-MAP操作 Dialogue: 0,0:46:26.69,0:46:27.92,Default,,0,0,0,,并将两点连线 Dialogue: 0,0:46:27.92,0:46:30.84,Default,,0,0,0,,我们假设在屏幕上绘制线段是基本操作 Dialogue: 0,0:46:31.09,0:46:33.22,Default,,0,0,0,,已经在系统中实现了 Dialogue: 0,0:46:33.96,0:46:37.10,Default,,0,0,0,,通过COORD-MAP变换了线段终点 Dialogue: 0,0:46:37.13,0:46:38.20,Default,,0,0,0,,再把起点和终点连线 Dialogue: 0,0:46:39.61,0:46:44.12,Default,,0,0,0,,对表中每一条线段S都执行这样的操作 Dialogue: 0,0:46:45.96,0:46:51.40,Default,,0,0,0,,请注意 图像就是一个以矩形为参数的过程 Dialogue: 0,0:46:51.40,0:46:55.65,Default,,0,0,0,,所以当你给图像一个矩形时 它就像这样绘制线段 Dialogue: 0,0:46:57.17,0:47:01.10,Default,,0,0,0,,那好 我应该如何使用它呢? Dialogue: 0,0:47:01.22,0:47:04.08,Default,,0,0,0,,我来说得具体一点 Dialogue: 0,0:47:05.60,0:47:24.22,Default,,0,0,0,,就比如说 (DEFINE R (MAKE-RECT ...)) Dialogue: 0,0:47:24.50,0:47:28.66,Default,,0,0,0,,这里需要用MAKE-VECTOR来构造一些向量 Dialogue: 0,0:47:29.84,0:47:46.18,Default,,0,0,0,,然后定义G为 (DEFINE G (MAKE-PICT ...)) Dialogue: 0,0:47:46.68,0:47:55.28,Default,,0,0,0,,我要在这里使用MAKE-SEGMENT来构建线段组成的表 Dialogue: 0,0:47:55.28,0:47:58.70,Default,,0,0,0,,MAKE-SEGMENT由向量构成 向量由点构成 Dialogue: 0,0:47:59.50,0:48:04.60,Default,,0,0,0,,如果我想在一个矩形中呈现图像G Dialogue: 0,0:48:04.65,0:48:11.72,Default,,0,0,0,,注意 图像是一个过程 它接受一个矩形作为参数 Dialogue: 0,0:48:12.06,0:48:16.37,Default,,0,0,0,,所以 如果我调用(G R) Dialogue: 0,0:48:17.96,0:48:23.25,Default,,0,0,0,,那么无论G是什么 都会在矩形R中绘制出来 Dialogue: 0,0:48:23.62,0:48:25.62,Default,,0,0,0,,这就是我们如何使用它 Dialogue: 0,0:48:26.86,0:48:36.29,Default,,0,0,0,,[音乐] Dialogue: 0,0:48:36.29,0:48:39.78,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:48:39.82,0:48:43.54,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:48:51.28,0:48:55.45,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:48:55.50,0:48:58.73,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:48:59.34,0:49:03.02,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson-Escher的例子 Dialogue: 0,0:49:07.72,0:49:12.48,Default,,0,0,0,,教授:为什么我说这个例子很好呢? Dialogue: 0,0:49:12.48,0:49:13.74,Default,,0,0,0,,也许你们不这么认为 Dialogue: 0,0:49:13.74,0:49:15.42,Default,,0,0,0,,你们可能觉得它很奇怪 Dialogue: 0,0:49:15.42,0:49:20.92,Default,,0,0,0,,用来矩形做复杂变换的过程来表示图像 确实奇怪 Dialogue: 0,0:49:20.92,0:49:22.72,Default,,0,0,0,,那么 它好在哪里呢? Dialogue: 0,0:49:25.36,0:49:26.69,Default,,0,0,0,,原因就是 Dialogue: 0,0:49:27.22,0:49:30.40,Default,,0,0,0,,一旦你按这种方法实现了基本元素 Dialogue: 0,0:49:30.97,0:49:35.20,Default,,0,0,0,,组合的方法就是构造Lisp过程 Dialogue: 0,0:49:35.98,0:49:37.48,Default,,0,0,0,,我给你们演示一下 Dialogue: 0,0:49:37.48,0:49:39.02,Default,,0,0,0,,假设我想实现BESIDE Dialogue: 0,0:49:41.56,0:49:47.36,Default,,0,0,0,,我要做的是 假设有个叫P1的图像 Dialogue: 0,0:49:47.36,0:49:50.62,Default,,0,0,0,,一定要记得:图像本质上是一个过程 Dialogue: 0,0:49:50.62,0:49:54.82,Default,,0,0,0,,当你传递给它一个矩形 Dialogue: 0,0:49:56.52,0:50:01.46,Default,,0,0,0,,它会在你给定的矩形中绘制图形 Dialogue: 0,0:50:03.46,0:50:09.26,Default,,0,0,0,,假设P2是另一个图像 你传递给它一个矩形 Dialogue: 0,0:50:09.74,0:50:12.44,Default,,0,0,0,,无论给它什么矩形 它都会绘制一些图案 Dialogue: 0,0:50:14.84,0:50:26.60,Default,,0,0,0,,现在 我想实现(BESIDE P1 P2 A) A是缩放因子 Dialogue: 0,0:50:27.04,0:50:28.38,Default,,0,0,0,,会得到什么呢? Dialogue: 0,0:50:28.38,0:50:29.34,Default,,0,0,0,,我们会得到一个图像 Dialogue: 0,0:50:29.92,0:50:33.88,Default,,0,0,0,,也就是说你传给它一个矩形 它就会在其中绘图 Dialogue: 0,0:50:34.77,0:50:37.18,Default,,0,0,0,,如果我们在一个矩形中执行BESIDE操作 Dialogue: 0,0:50:38.58,0:50:40.12,Default,,0,0,0,,比如这个矩形 Dialogue: 0,0:50:41.50,0:50:42.74,Default,,0,0,0,,要做什么呢? Dialogue: 0,0:50:42.76,0:50:46.36,Default,,0,0,0,,这将把矩形切分为两部分 Dialogue: 0,0:50:49.29,0:50:51.57,Default,,0,0,0,,一部分比例是A 另一部分是1-A Dialogue: 0,0:50:52.65,0:50:55.12,Default,,0,0,0,,现在 我们就有了两个矩形 Dialogue: 0,0:51:02.34,0:51:06.54,Default,,0,0,0,,然后先让P1在这个矩形中绘制 Dialogue: 0,0:51:07.36,0:51:11.64,Default,,0,0,0,,然后让P2在这个矩形中绘制 Dialogue: 0,0:51:13.28,0:51:16.88,Default,,0,0,0,,BESIDE仅仅需要计算出这些矩形来 Dialogue: 0,0:51:17.36,0:51:23.97,Default,,0,0,0,,由于矩形是由原点、水平向量和竖直向量组成 Dialogue: 0,0:51:23.98,0:51:25.94,Default,,0,0,0,,BESIDE操作需要计算出这些要素 Dialogue: 0,0:51:27.37,0:51:32.29,Default,,0,0,0,,所以对第一个矩形来说 原点变成了矩形的原点 Dialogue: 0,0:51:33.64,0:51:37.80,Default,,0,0,0,,竖直向量与原矩形相同 不发生变化 Dialogue: 0,0:51:38.89,0:51:46.60,Default,,0,0,0,,水平向量是原始矩形的水平向量缩放A倍得到的 Dialogue: 0,0:51:47.49,0:51:48.90,Default,,0,0,0,,这就是第一个矩形 Dialogue: 0,0:51:49.46,0:51:52.69,Default,,0,0,0,,第二个矩形的原点是 Dialogue: 0,0:51:54.06,0:51:59.65,Default,,0,0,0,,原矩形的原点加上矩形的水平向量缩放A倍 Dialogue: 0,0:52:01.20,0:52:03.40,Default,,0,0,0,,第二个矩形的水平向量是 Dialogue: 0,0:52:03.77,0:52:06.04,Default,,0,0,0,,除去前一个矩形水平向量所余下的部分 Dialogue: 0,0:52:06.34,0:52:11.66,Default,,0,0,0,,也就是(1-A)*H H是原矩形的水平向量 Dialogue: 0,0:52:12.05,0:52:13.77,Default,,0,0,0,,它的竖直向量还是V Dialogue: 0,0:52:15.48,0:52:17.98,Default,,0,0,0,,基本上 BESIDE就是构造这两个矩形 Dialogue: 0,0:52:18.00,0:52:20.57,Default,,0,0,0,,但重要的是 一旦构造好这些矩形 Dialogue: 0,0:52:20.93,0:52:24.58,Default,,0,0,0,,它就能让P1、P2在正确的位置绘制 Dialogue: 0,0:52:24.62,0:52:26.18,Default,,0,0,0,,这就是BESIDE需要做的全部工作 Dialogue: 0,0:52:27.80,0:52:29.30,Default,,0,0,0,,我们看一下代码 Dialogue: 0,0:52:34.33,0:52:35.13,Default,,0,0,0,,这是BESIDE Dialogue: 0,0:52:39.64,0:52:46.44,Default,,0,0,0,,(BESIDE P1 P2 A) A是缩放比例 Dialogue: 0,0:52:47.84,0:52:53.64,Default,,0,0,0,,因为该过程返回图像 所以结果是一个以矩形为参数的过程 Dialogue: 0,0:52:55.49,0:52:56.56,Default,,0,0,0,,它做什么呢? Dialogue: 0,0:52:56.76,0:53:02.32,Default,,0,0,0,,它让P1在某个矩形中绘制 P2在另一个矩形中绘制 Dialogue: 0,0:53:03.21,0:53:04.46,Default,,0,0,0,,现在这些矩形又是什么呢? Dialogue: 0,0:53:04.46,0:53:05.48,Default,,0,0,0,,就在这里计算 Dialogue: 0,0:53:05.48,0:53:06.54,Default,,0,0,0,,它创建了一个矩形 Dialogue: 0,0:53:07.52,0:53:10.40,Default,,0,0,0,,用的是我刚才在黑板上写的几何公式 这是矩形的原点 Dialogue: 0,0:53:10.40,0:53:11.84,Default,,0,0,0,,矩形的水平向量 Dialogue: 0,0:53:11.84,0:53:13.44,Default,,0,0,0,,还有矩形的竖直向量 Dialogue: 0,0:53:13.97,0:53:14.81,Default,,0,0,0,,对于P2 Dialogue: 0,0:53:15.50,0:53:19.78,Default,,0,0,0,,矩形需要不同的原点 水平向量和竖直向量 Dialogue: 0,0:53:19.78,0:53:20.70,Default,,0,0,0,,但重要的是 Dialogue: 0,0:53:21.21,0:53:27.18,Default,,0,0,0,,BESIDE只是将这两个矩形分别传递给了P1和P2而已 Dialogue: 0,0:53:27.74,0:53:29.42,Default,,0,0,0,,这就是BESIDE所需要做的 Dialogue: 0,0:53:30.84,0:53:35.62,Default,,0,0,0,,好 ROTATE也很类似 Dialogue: 0,0:53:36.96,0:53:42.00,Default,,0,0,0,,假设我有一个图像A Dialogue: 0,0:53:42.97,0:53:46.12,Default,,0,0,0,,我想让它旋转90度 Dialogue: 0,0:53:46.37,0:53:51.92,Default,,0,0,0,,这意味着 给定这个矩形 Dialogue: 0,0:53:53.94,0:53:58.44,Default,,0,0,0,,它有原点、水平向量和竖直向量 Dialogue: 0,0:53:58.78,0:54:03.18,Default,,0,0,0,,现在假设已经有了这样的矩形 Dialogue: 0,0:54:03.74,0:54:09.12,Default,,0,0,0,,这个矩形的原点、水平向量和竖直向量在这里 Dialogue: 0,0:54:09.60,0:54:12.46,Default,,0,0,0,,然后在矩形里各自绘制自己 Dialogue: 0,0:54:13.26,0:54:15.04,Default,,0,0,0,,我们来看看代码 Dialogue: 0,0:54:17.02,0:54:19.85,Default,,0,0,0,,那么 ROTATE90过程 Dialogue: 0,0:54:20.61,0:54:22.96,Default,,0,0,0,,返回的也是一个以矩形为参数的过程 Dialogue: 0,0:54:23.25,0:54:26.12,Default,,0,0,0,,它就是将图像绘制在一个特定矩形中 Dialogue: 0,0:54:27.21,0:54:30.66,Default,,0,0,0,,这个几何公式就是这个矩形的变换规则 Dialogue: 0,0:54:30.66,0:54:33.84,Default,,0,0,0,,这句代码让矩形看起来像向侧面的 Dialogue: 0,0:54:33.86,0:54:36.52,Default,,0,0,0,,原点在别的地方 竖直向量在别的地方 Dialogue: 0,0:54:37.13,0:54:39.74,Default,,0,0,0,,水平向量在别的地方 竖直向量在别的地方 Dialogue: 0,0:54:46.76,0:54:49.90,Default,,0,0,0,,再次注意 这里的关键是 Dialogue: 0,0:54:50.53,0:55:00.97,Default,,0,0,0,,关键是使用过程来表示图像 使其自动地具有闭包性质 Dialogue: 0,0:55:01.74,0:55:05.22,Default,,0,0,0,,这是因为 实际上 BESIDE只是接受并使用P1 Dialogue: 0,0:55:05.22,0:55:09.40,Default,,0,0,0,,BESIDE并不关心它是一个基本图像还是一些线段 Dialogue: 0,0:55:09.61,0:55:12.69,Default,,0,0,0,,或者P1还是ABOVE、BESIDE、ROTATE等操作的结果 Dialogue: 0,0:55:12.72,0:55:16.08,Default,,0,0,0,,关于P1 BESIDE需要知道的就是 Dialogue: 0,0:55:16.29,0:55:19.73,Default,,0,0,0,,给P1传递一个矩形 就会导致某物的绘制 Dialogue: 0,0:55:21.04,0:55:25.98,Default,,0,0,0,,在这个层面上 BESIDE并不关心P1是如何完成绘制 Dialogue: 0,0:55:27.73,0:55:32.25,Default,,0,0,0,,我们使用过程来表示图像 以保持它的闭包性质 Dialogue: 0,0:55:35.64,0:55:40.81,Default,,0,0,0,,将图像实现为过程 使得组合的方法变得 Dialogue: 0,0:55:41.18,0:55:43.93,Default,,0,0,0,,变得简单而优雅 Dialogue: 0,0:55:45.92,0:55:48.22,Default,,0,0,0,,但这并不是点睛之笔 Dialogue: 0,0:55:49.28,0:55:53.52,Default,,0,0,0,,点睛之笔来自于这门语言中抽象的方法 Dialogue: 0,0:55:54.70,0:55:56.24,Default,,0,0,0,,我们做了些什么? Dialogue: 0,0:55:56.24,0:56:03.72,Default,,0,0,0,,我们把组合的方法实现为了过程 Dialogue: 0,0:56:05.85,0:56:09.38,Default,,0,0,0,,这也就意味着 当我们对这个语言进行抽象时 Dialogue: 0,0:56:10.17,0:56:15.69,Default,,0,0,0,,Lisp提供的 操作过程的一切方法 Dialogue: 0,0:56:16.33,0:56:21.45,Default,,0,0,0,,都可以自动地在这个图像语言中使用 Dialogue: 0,0:56:21.92,0:56:29.74,Default,,0,0,0,,与其用术语“这个语言以Lisp实现” — 虽然确实如此 Dialogue: 0,0:56:29.76,0:56:32.58,Default,,0,0,0,,我想描述为“这个语言嵌入于Lisp” Dialogue: 0,0:56:37.64,0:56:42.08,Default,,0,0,0,,也就是说 通过像这样将语言嵌入 Dialogue: 0,0:56:42.90,0:56:48.86,Default,,0,0,0,,可以以扩展的形式 自动地获得Lisp的所有力量 Dialogue: 0,0:56:50.06,0:56:51.68,Default,,0,0,0,,这又是什么意思呢? Dialogue: 0,0:56:51.97,0:57:02.94,Default,,0,0,0,,举个例子 假设我想用A B C D四副图像做东西 Dialogue: 0,0:57:03.76,0:57:07.06,Default,,0,0,0,,让它们呈现像这样的格局 Dialogue: 0,0:57:12.50,0:57:16.96,Default,,0,0,0,,可以将其称为FOUR-PICT格局 Dialogue: 0,0:57:16.96,0:57:17.70,Default,,0,0,0,,我该如何做呢? Dialogue: 0,0:57:17.70,0:57:18.68,Default,,0,0,0,,我可以很容易的做到这些 Dialogue: 0,0:57:18.68,0:57:23.33,Default,,0,0,0,,写个过程 让B和D做ABOVE Dialogue: 0,0:57:24.13,0:57:25.85,Default,,0,0,0,,A和C做ABOVE Dialogue: 0,0:57:26.09,0:57:27.70,Default,,0,0,0,,得到的结果做BESIDE Dialogue: 0,0:57:28.24,0:57:31.82,Default,,0,0,0,,我自然地拥有Lisp组合过程的能力 Dialogue: 0,0:57:32.92,0:57:35.82,Default,,0,0,0,,这不需要我为图像语言做些特殊处理 Dialogue: 0,0:57:35.82,0:57:39.92,Default,,0,0,0,,事实上 这些组合本身就是过程 Dialogue: 0,0:57:40.96,0:57:44.18,Default,,0,0,0,,假设我想做一些更复杂的事情 Dialogue: 0,0:57:44.18,0:57:46.50,Default,,0,0,0,,我想为这里的每一个传递一个参数 Dialogue: 0,0:57:46.52,0:57:50.08,Default,,0,0,0,,我可以独立地做旋转90度的操作 Dialogue: 0,0:57:50.41,0:57:52.64,Default,,0,0,0,,这只需要我在这个过程中加入一个参数 Dialogue: 0,0:57:53.17,0:57:54.56,Default,,0,0,0,,它自然而然就有了这样的功能 Dialogue: 0,0:57:54.80,0:57:57.84,Default,,0,0,0,,它自动地嵌入进去了 Dialogue: 0,0:57:58.16,0:58:05.36,Default,,0,0,0,,甚至 假设我想使用递归 Dialogue: 0,0:58:06.16,0:58:10.78,Default,,0,0,0,,我们看一下图像递归组合的方法 Dialogue: 0,0:58:10.78,0:58:14.64,Default,,0,0,0,,定义--看看你们能理解这个不 Dialogue: 0,0:58:14.69,0:58:18.97,Default,,0,0,0,,(DEFINE (RIGHT-PUSH PICT N A)) Dialogue: 0,0:58:22.84,0:58:29.80,Default,,0,0,0,,RIGHT-PUSH需要图片P 整数N和缩放因数A Dialogue: 0,0:58:31.46,0:58:41.22,Default,,0,0,0,,定义是:如果N为0 那么返回图像P Dialogue: 0,0:58:42.20,0:58:54.02,Default,,0,0,0,,否则 就-- 哦 这里是P Dialogue: 0,0:58:55.88,0:59:00.21,Default,,0,0,0,,否则 我用图形P做BESIDE操作 Dialogue: 0,0:59:00.92,0:59:18.30,Default,,0,0,0,,BESIDE的另一个操作数是(RIGHT-PUSH P (- N 1) A)的结果 Dialogue: 0,0:59:24.72,0:59:31.12,Default,,0,0,0,,如果N为0 就返回P 否则就对P进行A倍缩放 Dialogue: 0,0:59:31.12,0:59:32.80,Default,,0,0,0,,抱歉 我这里代码没对齐 Dialogue: 0,0:59:33.66,0:59:38.50,Default,,0,0,0,,递归地调用(RIGHT-PUSH P (- N 1) A) 将结果用BESIDE连接 Dialogue: 0,0:59:38.50,0:59:42.00,Default,,0,0,0,,这就是一种递归组合方法 Dialogue: 0,0:59:43.78,0:59:44.76,Default,,0,0,0,,调用的结果会是怎样的? Dialogue: 0,0:59:44.76,0:59:45.90,Default,,0,0,0,,我们来看看 Dialogue: 0,0:59:46.04,0:59:56.04,Default,,0,0,0,,这是(RIGHT-PUSH GEORGE 2 0.75)的结果 Dialogue: 0,0:59:59.26,1:00:00.72,Default,,0,0,0,,这个是从什么地方来的呢? Dialogue: 0,1:00:00.72,1:00:02.34,Default,,0,0,0,,我是如何想象出这些递归来的呢? Dialogue: 0,1:00:02.34,1:00:05.24,Default,,0,0,0,,答案是无意识的 绝对是无意识的 Dialogue: 0,1:00:05.24,1:00:09.80,Default,,0,0,0,,由于它们都是过程 而嵌入的目标系统中允许定义递归过程 Dialogue: 0,1:00:10.36,1:00:11.68,Default,,0,0,0,,我不必自己去做 Dialogue: 0,1:00:13.56,1:00:16.42,Default,,0,0,0,,当然 我们可以模仿这个方法做些更复杂的事 Dialogue: 0,1:00:16.42,1:00:18.21,Default,,0,0,0,,我可以定义做UP-PUSH的过程 Dialogue: 0,1:00:18.42,1:00:22.60,Default,,0,0,0,,对 它可以递归地把图片放在原来的上面 Dialogue: 0,1:00:22.60,1:00:26.54,Default,,0,0,0,,我也可以用这种策略来做些其它事 Dialogue: 0,1:00:26.56,1:00:28.85,Default,,0,0,0,,给定一个图像 Dialogue: 0,1:00:29.78,1:00:37.16,Default,,0,0,0,,然后递归地把它放在原图片的旁边和上面 Dialogue: 0,1:00:37.57,1:00:38.92,Default,,0,0,0,,这里再放一些别的 Dialogue: 0,1:00:39.52,1:00:41.82,Default,,0,0,0,,然后我把同样递归的图像放在这里 Dialogue: 0,1:00:42.36,1:00:44.20,Default,,0,0,0,,我可以用这个来终止 Dialogue: 0,1:00:45.40,1:00:52.50,Default,,0,0,0,,这个过程比RIGHT-PUSH复杂一点 但也不算太多 Dialogue: 0,1:00:53.64,1:00:58.14,Default,,0,0,0,,在BESIDE的基础上 我多加了一个ABOVE操作 Dialogue: 0,1:01:01.12,1:01:06.78,Default,,0,0,0,,如果我把它应用于四张放在一起的图像上 Dialogue: 0,1:01:07.53,1:01:08.65,Default,,0,0,0,,这样做当然没问题 Dialogue: 0,1:01:09.01,1:01:14.17,Default,,0,0,0,,我把它应用于我们之前定义的Q上 Dialogue: 0,1:01:15.97,1:01:18.73,Default,,0,0,0,,我得到的是这个玩意儿 Dialogue: 0,1:01:20.14,1:01:25.26,Default,,0,0,0,,"图像Q的方形极限" 做了两次 Dialogue: 0,1:01:28.18,1:01:32.25,Default,,0,0,0,,好 现在我们将其与Escher的"方形极限"对比一下 Dialogue: 0,1:01:32.88,1:01:34.53,Default,,0,0,0,,可以看到 这都是基于同样的思想 Dialogue: 0,1:01:34.74,1:01:36.94,Default,,0,0,0,,当然 Escher的图像更加漂亮一些 Dialogue: 0,1:01:36.94,1:01:44.04,Default,,0,0,0,,如果我们回过头审视George Dialogue: 0,1:01:44.38,1:01:47.37,Default,,0,0,0,,我最开始用的是非常随意的设计 Dialogue: 0,1:01:47.42,1:01:49.26,Default,,0,0,0,,用了George的图像 做了一些操作 Dialogue: 0,1:01:51.22,1:01:53.14,Default,,0,0,0,,我们再看看Escher的图片 Dialogue: 0,1:01:54.08,1:01:56.14,Default,,0,0,0,,Escher的图片不是随意设计的 Dialogue: 0,1:01:56.14,1:01:57.66,Default,,0,0,0,,这个图案非常精妙 Dialogue: 0,1:01:57.89,1:02:00.20,Default,,0,0,0,,当我们把鱼身 Dialogue: 0,1:02:01.82,1:02:04.97,Default,,0,0,0,,把鱼身旋转并放缩 就会优美地变成下一条鱼 Dialogue: 0,1:02:07.40,1:02:11.48,Default,,0,0,0,,当然我没有刻意处理过George Dialogue: 0,1:02:12.12,1:02:13.90,Default,,0,0,0,,就图像George来说 Dialogue: 0,1:02:15.41,1:02:18.64,Default,,0,0,0,,也有一些地方匹配 但不够好 比较随意 Dialogue: 0,1:02:18.64,1:02:21.53,Default,,0,0,0,,顺便说下 一个好的程序 Dialogue: 0,1:02:22.30,1:02:27.54,Default,,0,0,0,,应该有个过程 能接受像这里George一样的基本图像 Dialogue: 0,1:02:27.86,1:02:29.62,Default,,0,0,0,,然后调整其中的线段终点 Dialogue: 0,1:02:29.86,1:02:31.20,Default,,0,0,0,,这样可以得到一个好看的图像 Dialogue: 0,1:02:32.13,1:02:34.06,Default,,0,0,0,,在做“方形极限”应该注意这些 Dialogue: 0,1:02:34.68,1:02:36.30,Default,,0,0,0,,这是一个非常值得思考的事情 Dialogue: 0,1:02:38.08,1:02:39.72,Default,,0,0,0,,同时 我还可以进行组合 Dialogue: 0,1:02:39.72,1:02:41.04,Default,,0,0,0,,我们还可以使用递归过程 Dialogue: 0,1:02:41.04,1:02:43.48,Default,,0,0,0,,我们可以自然而然地做任何事情 Dialogue: 0,1:02:44.60,1:02:48.52,Default,,0,0,0,,重点在于 在语言中实际实现另一个语言 Dialogue: 0,1:02:48.69,1:02:50.44,Default,,0,0,0,,在语言中嵌入另一个语言的差异 Dialogue: 0,1:02:50.44,1:02:53.72,Default,,0,0,0,,这可以让你不丢失原有语言的能力 而Lisp强大之处在于 Dialogue: 0,1:02:54.76,1:02:57.62,Default,,0,0,0,,Lisp是一个强悍的语言 可以处理任何特定问题 Dialogue: 0,1:02:57.62,1:03:02.10,Default,,0,0,0,,把你想要的语言嵌入到Lisp中才是真的好 Dialogue: 0,1:03:02.10,1:03:05.44,Default,,0,0,0,,这才是这种设计方法的真正力量 Dialogue: 0,1:03:05.69,1:03:06.82,Default,,0,0,0,,我们可以深入一下 Dialogue: 0,1:03:06.82,1:03:08.81,Default,,0,0,0,,在Lisp中我们还可以做些其它的事 Dialogue: 0,1:03:09.21,1:03:17.52,Default,,0,0,0,,就是将通用方法抽象成高阶过程 Dialogue: 0,1:03:19.09,1:03:22.57,Default,,0,0,0,,在我画那些图像时 你们可能已经发现 Dialogue: 0,1:03:23.78,1:03:26.61,Default,,0,0,0,,RIGHT-PUSH和类似的过程 就是一直在上面放东西 Dialogue: 0,1:03:26.93,1:03:33.82,Default,,0,0,0,,而这个CORNER-PUSH则是一种一般性思想的泛化 Dialogue: 0,1:03:34.72,1:03:37.20,Default,,0,0,0,,为了演示并让大家熟悉 Dialogue: 0,1:03:37.98,1:03:40.65,Default,,0,0,0,,使用廊腰缦回的高阶过程 Dialogue: 0,1:03:41.12,1:03:47.24,Default,,0,0,0,,我给大家示范一下“递归地重复某种组合方法”的一般性思想 Dialogue: 0,1:03:48.30,1:03:50.70,Default,,0,0,0,,这个例子可以说明一切 Dialogue: 0,1:03:51.22,1:04:00.70,Default,,0,0,0,,我们可以定义一个依赖于具体组合方式的PUSH过程 Dialogue: 0,1:04:01.49,1:04:04.88,Default,,0,0,0,,COMB的取值可以是BESIDE或ABOVE等 Dialogue: 0,1:04:06.18,1:04:07.06,Default,,0,0,0,,过程的体是什么呢? Dialogue: 0,1:04:07.06,1:04:12.06,Default,,0,0,0,,它返回一个过程 想一想BESIDE实际上是什么 Dialogue: 0,1:04:13.22,1:04:15.18,Default,,0,0,0,,它接受一个图像 Dialogue: 0,1:04:15.96,1:04:18.08,Default,,0,0,0,,哦 它接受两个图像和一个缩放因数 Dialogue: 0,1:04:18.62,1:04:24.28,Default,,0,0,0,,利用这个过程 定义一个接受层数、图像和缩放因数的过程 Dialogue: 0,1:04:24.28,1:04:25.45,Default,,0,0,0,,我称之为RIGHT-PUSH Dialogue: 0,1:04:26.16,1:04:33.66,Default,,0,0,0,,这个过程接受 图像PICT 层数N和缩放因数A Dialogue: 0,1:04:36.16,1:04:39.12,Default,,0,0,0,,我要做一些重复操作 Dialogue: 0,1:04:39.45,1:04:46.62,Default,,0,0,0,,我会重复应用一个接受一个图像P的过程 Dialogue: 0,1:04:48.40,1:04:50.69,Default,,0,0,0,,并把组合的方式应用在 Dialogue: 0,1:04:51.20,1:04:59.08,Default,,0,0,0,,应用在图像PICT和在这里接受的图像P以及缩放因数A Dialogue: 0,1:05:02.26,1:05:07.28,Default,,0,0,0,,我要重复应用这个过程N次 Dialogue: 0,1:05:12.04,1:05:16.20,Default,,0,0,0,,我则是把这整个过程应用在原图片PICT上 Dialogue: 0,1:05:19.56,1:05:24.48,Default,,0,0,0,,虽然之前没提过 这里的REPEATED也是一个高阶过程 Dialogue: 0,1:05:24.53,1:05:28.34,Default,,0,0,0,,它接受一个过程P和一个数字N Dialogue: 0,1:05:29.54,1:05:34.29,Default,,0,0,0,,它返回另一个过程:将给定的过程P重复应用N次的过程 Dialogue: 0,1:05:36.04,1:05:39.30,Default,,0,0,0,,可能有些人已经在练习中编写过REPEATED了 Dialogue: 0,1:05:39.70,1:05:43.01,Default,,0,0,0,,如果还没做的话 这是理解和练习高阶过程的好机会 Dialogue: 0,1:05:43.84,1:05:46.90,Default,,0,0,0,,无论如何 我将把REPEATED过程的结果应用到PICT上 Dialogue: 0,1:05:49.46,1:05:52.38,Default,,0,0,0,,定义好PUSH后 这就 Dialogue: 0,1:05:53.12,1:05:57.73,Default,,0,0,0,,这就是从BESIDE、RIGHT-PUSH中总结出来的一般性思想 Dialogue: 0,1:05:59.01,1:06:13.17,Default,,0,0,0,,现在 我就可以把RIGHT-PUSH定义为 用BESIDE来做PUSH操作 Dialogue: 0,1:06:17.65,1:06:20.32,Default,,0,0,0,,我也可以把UP-PUSH定义为 用ABOVE来做PUSH操作 Dialogue: 0,1:06:20.34,1:06:25.48,Default,,0,0,0,,类似地 CORNER-PUSH就是用BESIDE和ABOVE的适当组合做PUSH操作 Dialogue: 0,1:06:25.49,1:06:26.70,Default,,0,0,0,,我可以用任何东西做PUSH操作 Dialogue: 0,1:06:28.26,1:06:34.76,Default,,0,0,0,,嗯 如果你还不太理解LAMBDA的话 可以参考这个例子 Dialogue: 0,1:06:38.98,1:06:41.00,Default,,0,0,0,,我们可以从这个例子中学到很多东西 Dialogue: 0,1:06:42.18,1:06:49.80,Default,,0,0,0,,我主要想要介绍的是在一个语言中嵌入另一个语言 Dialogue: 0,1:06:50.66,1:06:55.62,Default,,0,0,0,,这样 母体语言--本例中是Lisp--的所有能力 Dialogue: 0,1:06:55.92,1:07:00.28,Default,,0,0,0,,可以作为你所构建语言的一种扩展而取得 Dialogue: 0,1:07:00.98,1:07:04.00,Default,,0,0,0,,这个例子很好地展示了这点 Dialogue: 0,1:07:08.14,1:07:10.94,Default,,0,0,0,,另外 当我们回过头去思考 Dialogue: 0,1:07:10.94,1:07:12.28,Default,,0,0,0,,什么是过程 什么是数据 Dialogue: 0,1:07:12.28,1:07:16.20,Default,,0,0,0,,在这里 天啊 发生了什么 Dialogue: 0,1:07:16.20,1:07:19.66,Default,,0,0,0,,在这里 这是一个过程 它接受一个图像和一个参数 Dialogue: 0,1:07:19.66,1:07:20.36,Default,,0,0,0,,但是 什么是图像呢? Dialogue: 0,1:07:20.36,1:07:23.82,Default,,0,0,0,,请回想 图像本身 就是一个以矩形为参数的过程 Dialogue: 0,1:07:23.82,1:07:25.82,Default,,0,0,0,,这个矩形是某种抽象 Dialogue: 0,1:07:26.09,1:07:28.13,Default,,0,0,0,,我希望你们现在能彻底明白 Dialogue: 0,1:07:29.14,1:07:33.74,Default,,0,0,0,,系统中什么是过程 什么是数据 Dialogue: 0,1:07:33.74,1:07:34.78,Default,,0,0,0,,我们发现 它们没有任何区别 Dialogue: 0,1:07:35.49,1:07:36.44,Default,,0,0,0,,真的没有区别 Dialogue: 0,1:07:37.93,1:07:41.42,Default,,0,0,0,,你可以认为图像有时候是过程 有时候是数据 Dialogue: 0,1:07:41.84,1:07:44.90,Default,,0,0,0,,但是 这只是让你容易理解的一种方法 Dialogue: 0,1:07:44.90,1:07:47.30,Default,,0,0,0,,这有一定道理 也没有道理 Dialogue: 0,1:07:49.92,1:08:02.20,Default,,0,0,0,,关于系统的结构 一种更普遍的观点将其视作创建一种语言 Dialogue: 0,1:08:02.52,1:08:06.74,Default,,0,0,0,,将工程设计过程看作是创建一门语言 Dialogue: 0,1:08:07.84,1:08:13.97,Default,,0,0,0,,准确来说 是创建各种层次的语言 Dialogue: 0,1:08:14.77,1:08:20.01,Default,,0,0,0,,众所周知 有一种方法学 或者叫做“神话学” Dialogue: 0,1:08:20.74,1:08:24.90,Default,,0,0,0,,姑且叫做软件“工程” Dialogue: 0,1:08:25.21,1:08:28.04,Default,,0,0,0,,它声称 你要先计算出你的任务 Dialogue: 0,1:08:28.04,1:08:30.04,Default,,0,0,0,,精确且正确地计算出你的任务 Dialogue: 0,1:08:30.40,1:08:32.20,Default,,0,0,0,,一但你搞清楚要做的东西 Dialogue: 0,1:08:32.22,1:08:34.54,Default,,0,0,0,,你把它划分为三个子任务 Dialogue: 0,1:08:34.54,1:08:35.76,Default,,0,0,0,,然后你开始继续做-- Dialogue: 0,1:08:35.97,1:08:38.94,Default,,0,0,0,,你开始处理这个子任务 然后你明确它是什么 Dialogue: 0,1:08:38.94,1:08:43.04,Default,,0,0,0,,这个子问题就分裂成三个子任务 你把它们处理完 Dialogue: 0,1:08:43.04,1:08:47.32,Default,,0,0,0,,然后你先处理这两个任务 Dialogue: 0,1:08:47.32,1:08:51.10,Default,,0,0,0,,解决完子任务后 你后退到这里 处理第二个子任务 Dialogue: 0,1:08:51.10,1:08:53.40,Default,,0,0,0,,然后把它详细地实现出来 Dialogue: 0,1:08:53.40,1:08:57.64,Default,,0,0,0,,结束之后-- 你完成了这个美丽的大厦 Dialogue: 0,1:08:57.64,1:09:00.25,Default,,0,0,0,,你最后得到了一棵非凡的树 Dialogue: 0,1:09:00.89,1:09:08.24,Default,,0,0,0,,你把任务划分为子任务 子任务再划分为子任务 Dialogue: 0,1:09:09.88,1:09:15.02,Default,,0,0,0,,树中的每个结点都被严谨而准确地定义 Dialogue: 0,1:09:15.26,1:09:18.66,Default,,0,0,0,,为奇妙而精美的任务 以构建整栋大厦 Dialogue: 0,1:09:18.96,1:09:21.14,Default,,0,0,0,,这个就是所谓的“神话学” Dialogue: 0,1:09:21.14,1:09:25.92,Default,,0,0,0,,只有计算机科学家才可能相信你构建的复杂系统像这个样子 Dialogue: 0,1:09:27.48,1:09:32.80,Default,,0,0,0,,好了 我们用Henderson的例子来做对比 Dialogue: 0,1:09:32.80,1:09:34.30,Default,,0,0,0,,它的结构不是那样 Dialogue: 0,1:09:35.26,1:09:39.33,Default,,0,0,0,,事实是:这里有一个语言的层次序列 Dialogue: 0,1:09:41.06,1:09:42.05,Default,,0,0,0,,它是什么? Dialogue: 0,1:09:42.18,1:09:48.76,Default,,0,0,0,,这里有一层 允许我们构建基本图像 Dialogue: 0,1:09:51.69,1:09:56.24,Default,,0,0,0,,这个语言描述基本图像 Dialogue: 0,1:09:56.32,1:09:57.84,Default,,0,0,0,,我们并没有做过多地讨论 Dialogue: 0,1:09:58.22,1:09:59.58,Default,,0,0,0,,我们讨论了如何构造George Dialogue: 0,1:09:59.61,1:10:04.88,Default,,0,0,0,,这个语言是在单位正方形中讨论点、线和向量 Dialogue: 0,1:10:06.42,1:10:11.29,Default,,0,0,0,,而在这之上 Dialogue: 0,1:10:11.97,1:10:14.10,Default,,0,0,0,,这是讨论基本图像的语言 Dialogue: 0,1:10:17.08,1:10:20.36,Default,,0,0,0,,讨论在特定单位正方形中线段的构造 Dialogue: 0,1:10:21.40,1:10:23.80,Default,,0,0,0,,在这个上面是另一个完整的语言 Dialogue: 0,1:10:24.05,1:10:30.86,Default,,0,0,0,,关于几何组合子的语言 Dialogue: 0,1:10:32.66,1:10:36.62,Default,,0,0,0,,关于几何物件的位置 Dialogue: 0,1:10:38.77,1:10:46.50,Default,,0,0,0,,讨论像ABOVE、BESIDE、RIGHT-PUSH和ROTATE这样的东西 Dialogue: 0,1:10:48.04,1:10:55.70,Default,,0,0,0,,这些事情恰巧与我们在这个语言中谈论的事情有关 Dialogue: 0,1:10:58.57,1:11:00.93,Default,,0,0,0,,再细化一点 我们发现在这之上 Dialogue: 0,1:11:02.61,1:11:15.10,Default,,0,0,0,,还有一门语言 描述组合的模式 Dialogue: 0,1:11:21.25,1:11:22.44,Default,,0,0,0,,比如说PUSH Dialogue: 0,1:11:24.45,1:11:27.88,Default,,0,0,0,,也就是用一个放缩因子重复地做一件事儿 Dialogue: 0,1:11:28.38,1:11:31.28,Default,,0,0,0,,我们在那门语言中讨论的问题 Dialogue: 0,1:11:31.50,1:11:34.34,Default,,0,0,0,,正是我这里构建的东西 Dialogue: 0,1:11:36.30,1:11:42.76,Default,,0,0,0,,我们在每一层上所讨论的对象 Dialogue: 0,1:11:44.68,1:11:47.00,Default,,0,0,0,,都是前一个层次所建立的 Dialogue: 0,1:11:48.08,1:11:52.06,Default,,0,0,0,,这个和这个有什么区别呢? Dialogue: 0,1:11:53.34,1:11:54.18,Default,,0,0,0,,这是因为 Dialogue: 0,1:11:56.14,1:12:01.73,Default,,0,0,0,,实际上在这里 树的每一个结点 每一次分解 Dialogue: 0,1:12:02.14,1:12:05.25,Default,,0,0,0,,都是旨在分成确定的任务 Dialogue: 0,1:12:07.50,1:12:08.88,Default,,0,0,0,,而在另一个方案中 Dialogue: 0,1:12:09.21,1:12:14.80,Default,,0,0,0,,你在每个层级上的完完全全的语言层面的能力 Dialogue: 0,1:12:16.00,1:12:18.08,Default,,0,0,0,,这里的每一个层次 Dialogue: 0,1:12:20.24,1:12:22.72,Default,,0,0,0,,都不是被设计为完成一个特定任务 Dialogue: 0,1:12:23.14,1:12:26.17,Default,,0,0,0,,它被设计为讨论整个事情 Dialogue: 0,1:12:27.62,1:12:30.78,Default,,0,0,0,,这样设计导致的结果是: Dialogue: 0,1:12:31.14,1:12:35.58,Default,,0,0,0,,用这种设计方法更加健壮 Dialogue: 0,1:12:36.61,1:12:38.20,Default,,0,0,0,,我所谓的“健壮”是指 Dialogue: 0,1:12:38.44,1:12:41.24,Default,,0,0,0,,当你在描述中做一些改变 Dialogue: 0,1:12:42.70,1:12:48.04,Default,,0,0,0,,我们可以做出相应的改变 Dialogue: 0,1:12:49.22,1:12:52.60,Default,,0,0,0,,用上一层语言实现的方法改变即可 Dialogue: 0,1:12:54.29,1:12:56.58,Default,,0,0,0,,因为你让每个层次都是完全的 Dialogue: 0,1:12:56.62,1:12:59.66,Default,,0,0,0,,所以你不需要讨论像BESIDE这样的特定操作 Dialogue: 0,1:12:59.94,1:13:03.78,Default,,0,0,0,,你为表达这类事物创造了完备的词汇 Dialogue: 0,1:13:04.77,1:13:07.02,Default,,0,0,0,,所以当你轻微修改规格指标时 Dialogue: 0,1:13:07.02,1:13:11.38,Default,,0,0,0,,这种方法论可以捕捉并适应那些变化 Dialogue: 0,1:13:12.69,1:13:15.02,Default,,0,0,0,,然而这种设计却不够健壮 Dialogue: 0,1:13:15.02,1:13:17.08,Default,,0,0,0,,因为 如果我在这里改变一下 Dialogue: 0,1:13:17.53,1:13:21.69,Default,,0,0,0,,那可能会影响我划分这些东西的方式 严重地影响 Dialogue: 0,1:13:23.20,1:13:29.74,Default,,0,0,0,,分解观点的最大不同在于 按层次还是严格继承分解 Dialogue: 0,1:13:30.52,1:13:33.02,Default,,0,0,0,,不只是如此 当你有多个层次的语言时 Dialogue: 0,1:13:33.50,1:13:35.92,Default,,0,0,0,,你就有了不同的词汇储备 Dialogue: 0,1:13:36.45,1:13:38.74,Default,,0,0,0,,用于讨论不同层次上的设计 Dialogue: 0,1:13:38.74,1:13:40.92,Default,,0,0,0,,我们再回过头来看看George Dialogue: 0,1:13:41.90,1:13:44.08,Default,,0,0,0,,如果我想改变图像George Dialogue: 0,1:13:45.85,1:13:48.68,Default,,0,0,0,,我立马得到了一种不同的方式来描述变化 Dialogue: 0,1:13:48.68,1:13:56.08,Default,,0,0,0,,比如 我想在基本设计的层面上 移动某些向量的终点 Dialogue: 0,1:13:57.76,1:14:00.76,Default,,0,0,0,,我会在最底层讨论这个改变 Dialogue: 0,1:14:01.00,1:14:02.50,Default,,0,0,0,,我会另外指定终点位置 Dialogue: 0,1:14:03.34,1:14:07.98,Default,,0,0,0,,我也可以说 我想在这个小的重复元素上做文章 Dialogue: 0,1:14:09.10,1:14:10.94,Default,,0,0,0,,我可能想做些其它操作 Dialogue: 0,1:14:10.94,1:14:13.84,Default,,0,0,0,,我想在BESIDE中使用一个缩放因数 Dialogue: 0,1:14:13.84,1:14:19.34,Default,,0,0,0,,这个改变我会在更高的层次上讨论:在组合子的层次 Dialogue: 0,1:14:19.34,1:14:25.05,Default,,0,0,0,,我也可以改变图像的基本组合模式 Dialogue: 0,1:14:26.49,1:14:30.48,Default,,0,0,0,,做一些递归地分解 可能不会让它们填充满角落 Dialogue: 0,1:14:31.16,1:14:34.18,Default,,0,0,0,,而这样的一个变化 我会在最高层次讨论 Dialogue: 0,1:14:34.18,1:14:36.37,Default,,0,0,0,,正是因为我按这种结构组织系统 Dialogue: 0,1:14:36.52,1:14:39.62,Default,,0,0,0,,我有所有的词汇 可以用不同的方式描述变化 Dialogue: 0,1:14:39.65,1:14:42.48,Default,,0,0,0,,而且可以灵活地决定哪个更合适 Dialogue: 0,1:14:44.74,1:14:51.05,Default,,0,0,0,,这就是Lisp中不同于软件工程方法论的最大要点 Dialogue: 0,1:14:51.25,1:14:55.45,Default,,0,0,0,,它来自于这样一个观点:真正的设计过程 Dialogue: 0,1:14:56.12,1:14:59.62,Default,,0,0,0,,与其说是在设计程序 不如说是在设计语言 Dialogue: 0,1:14:59.62,1:15:01.09,Default,,0,0,0,,而这就是Lisp的力量 Dialogue: 0,1:15:02.21,1:15:03.61,Default,,0,0,0,,谢谢大家 下课 Dialogue: 0,1:15:05.69,1:15:23.37,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:15:05.69,1:15:23.37,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/FoOTOo/Learning-SICP ================================================ FILE: Ass/lec3a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: SICP ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Last Style Storage: Default Audio URI: G:\untitled\ref\lec3a_480_muxed.mp4 Video Zoom Percent: 0.625 Scroll Position: 507 Active Line: 512 Video File: G:\untitled\ref\lec3a_480_muxed.mp4 Video Aspect Ratio: c1.33333 Video Position: 18119 PlayResX: 640 PlayResY: 480 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:03.12,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP Group Dialogue: 0,0:00:04.40,0:00:08.02,Declare,,0,0,0,,{\an2\fad(500,500)}Translation && Timeline: Dysprosium / Savior Michael\NEncode && Effects: Dysprosium Dialogue: 0,0:00:08.06,0:00:12.16,Declare,,0,0,0,,{\an2\fad(500,500)}Credit: Prof. Qiu Zongyan Dialogue: 0,0:00:12.37,0:00:16.32,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson-Escher Example Dialogue: 0,0:00:20.94,0:00:23.86,EN,,0,0,0,,PROFESSOR: Well, last time we talked about compound data, Dialogue: 0,0:00:24.94,0:00:29.74,EN,,0,0,0,,and there were two main points to that business. Dialogue: 0,0:00:29.74,0:00:32.48,EN,,0,0,0,,First of all, there was a methodology of data abstraction, Dialogue: 0,0:00:32.94,0:00:39.10,EN,,0,0,0,,and the point of that was that you could isolate the way that data objects are used Dialogue: 0,0:00:40.06,0:00:41.50,EN,,0,0,0,,from the way that they're represented: Dialogue: 0,0:00:41.55,0:00:45.20,EN,,0,0,0,,this idea that there's this guy, George, and you go out make a contract with him; Dialogue: 0,0:00:45.20,0:00:47.48,EN,,0,0,0,,and it's his business to represent the data objects; Dialogue: 0,0:00:47.48,0:00:49.36,EN,,0,0,0,,and at the moment you are using them, Dialogue: 0,0:00:49.36,0:00:51.36,EN,,0,0,0,,you don't think about George's problem. Dialogue: 0,0:00:51.98,0:00:58.44,EN,,0,0,0,,And then secondly, there was this particular way that Lisp has of gluing together things Dialogue: 0,0:00:58.94,0:01:00.52,EN,,0,0,0,,to form objects called pairs, Dialogue: 0,0:01:00.52,0:01:03.54,EN,,0,0,0,,and that's done with cons, car and cdr. Dialogue: 0,0:01:03.54,0:01:07.16,EN,,0,0,0,,And the way that cons, car and cdr are implemented is basically irrelevant. Dialogue: 0,0:01:07.16,0:01:10.02,EN,,0,0,0,,That's sort of George's problem of how to build those things. Dialogue: 0,0:01:10.02,0:01:11.16,EN,,0,0,0,,It could be done as primitives. Dialogue: 0,0:01:11.16,0:01:13.80,EN,,0,0,0,,It could be done using procedures in some weird way, Dialogue: 0,0:01:13.80,0:01:15.22,EN,,0,0,0,,but we're not going to worry about that. Dialogue: 0,0:01:16.02,0:01:19.66,EN,,0,0,0,,And as an example, we looked at rational number arithmetic. Dialogue: 0,0:01:19.66,0:01:21.50,EN,,0,0,0,,We looked at vectors, Dialogue: 0,0:01:21.50,0:01:24.18,EN,,0,0,0,,and here's just a review of vectors. Dialogue: 0,0:01:24.18,0:01:27.64,EN,,0,0,0,,Here's an operation that takes the sum of of two vectors, Dialogue: 0,0:01:27.64,0:01:33.32,EN,,0,0,0,,so we want to add this vector, v1, and this vector, v2, and we get the sum. Dialogue: 0,0:01:34.46,0:01:40.84,EN,,0,0,0,,And the sum is the vector whose coordinates are the sum of the coordinates of the pieces you're adding. Dialogue: 0,0:01:41.28,0:01:45.66,EN,,0,0,0,,So I can say, to define make-vect, right, to add two vectors Dialogue: 0,0:01:45.66,0:01:51.72,EN,,0,0,0,,I make a vector, whose x coordinate is the sum of the two x coordinates, Dialogue: 0,0:01:52.10,0:01:54.82,EN,,0,0,0,,and whose y coordinate is the sum of the two y coordinates. Dialogue: 0,0:01:56.06,0:02:04.10,EN,,0,0,0,,And then similarly, we could have an operation that scales vectors, Dialogue: 0,0:02:04.94,0:02:12.66,EN,,0,0,0,,so here's a procedure scale that multiplies a vector, v, by some number, s. Dialogue: 0,0:02:13.08,0:02:16.14,EN,,0,0,0,,So here's v, v goes from there to there Dialogue: 0,0:02:16.32,0:02:20.22,EN,,0,0,0,,and I scale v, and I get a vector in the same direction that's longer. Dialogue: 0,0:02:21.56,0:02:24.26,EN,,0,0,0,,And again, to scale a vector, I multiply the successive coordinates. Dialogue: 0,0:02:24.26,0:02:30.22,EN,,0,0,0,,So I make a vector, whose x coordinate is the scale factor times the x coordinate Dialogue: 0,0:02:30.56,0:02:33.54,EN,,0,0,0,,and whose y coordinate is the scale factor times the y coordinate. Dialogue: 0,0:02:33.54,0:02:40.28,EN,,0,0,0,,So those are two operations that are implemented using the representation of vectors. Dialogue: 0,0:02:40.28,0:02:45.02,EN,,0,0,0,,And the representation of vectors, for instance, is something that we can build in terms of pairs. Dialogue: 0,0:02:45.34,0:02:51.28,EN,,0,0,0,,So George has gone out and implemented for us make-vector and x coordinate and y coordinate, Dialogue: 0,0:02:53.02,0:02:57.98,EN,,0,0,0,,and this could be done, for instance, using cons,car and cdr; Dialogue: 0,0:02:58.88,0:03:06.78,EN,,0,0,0,,and notice here, I wrote this in a slightly different way. Dialogue: 0,0:03:08.04,0:03:11.00,EN,,0,0,0,,The procedures we've seen before, I've said something like Dialogue: 0,0:03:11.14,0:03:16.22,EN,,0,0,0,,say, make-vector of x and y: cons of x and y. Dialogue: 0,0:03:16.22,0:03:17.98,EN,,0,0,0,,And here I just wrote make-vector cons. Dialogue: 0,0:03:17.98,0:03:20.48,EN,,0,0,0,,And that means something slightly different. Dialogue: 0,0:03:20.48,0:03:26.22,EN,,0,0,0,,Previously we'd say, define make-vector to be a procedure that takes two arguments, x and y, Dialogue: 0,0:03:26.22,0:03:28.04,EN,,0,0,0,,and does cons of x and y. Dialogue: 0,0:03:28.04,0:03:34.12,EN,,0,0,0,,And here I am saying define make-vector to be the thing that cons is, Dialogue: 0,0:03:35.18,0:03:39.66,EN,,0,0,0,,and that's almost the same as the other way we've been writing things. Dialogue: 0,0:03:39.66,0:03:46.58,EN,,0,0,0,,And I just want you to get used to the idea that procedures can be objects, and that you can name them. Dialogue: 0,0:03:48.70,0:03:51.80,EN,,0,0,0,,OK, well there's vector representation, and again, Dialogue: 0,0:03:51.80,0:03:55.68,EN,,0,0,0,,if that was all there was to it,this would all be pretty boring. Dialogue: 0,0:03:57.02,0:04:02.16,EN,,0,0,0,,And the point is, remember, that you can use cons to glue together not just numbers to form pairs, Dialogue: 0,0:04:02.16,0:04:04.16,EN,,0,0,0,,but to glue together arbitrary things. Dialogue: 0,0:04:05.20,0:04:11.60,EN,,0,0,0,,So for instance, if we'd like to represent a line segment, Dialogue: 0,0:04:11.60,0:04:15.64,EN,,0,0,0,,say the line segment that goes from a certain vector: Dialogue: 0,0:04:16.06,0:04:28.30,EN,,0,0,0,,say, the segment from the vector 2,3 to the point represented by the vector 5,1. Dialogue: 0,0:04:28.30,0:04:31.82,EN,,0,0,0,,If we want to represent that line segment, Dialogue: 0,0:04:33.26,0:04:36.20,EN,,0,0,0,,then we can build that as a pair of pairs. Dialogue: 0,0:04:40.72,0:04:42.94,EN,,0,0,0,,So again, we can represent line segments. Dialogue: 0,0:04:42.94,0:04:47.34,EN,,0,0,0,,We can make a constructor that makes a segment using cons, Dialogue: 0,0:04:47.98,0:04:51.60,EN,,0,0,0,,selects out the start of a segment, selects out the end point of the segment; Dialogue: 0,0:04:55.24,0:04:59.76,EN,,0,0,0,,and then if we actually look at that, if we peel away the abstraction layers, Dialogue: 0,0:04:59.88,0:05:02.10,EN,,0,0,0,,and see what's that really is a pair of pairs, Dialogue: 0,0:05:04.66,0:05:06.22,EN,,0,0,0,,we'd say well that's a pair. Dialogue: 0,0:05:06.22,0:05:08.22,EN,,0,0,0,,Here's the segment. Dialogue: 0,0:05:10.00,0:05:16.72,EN,,0,0,0,,It's car, right, it's car pointer is a pair, and it's cdr is also a pair, Dialogue: 0,0:05:18.32,0:05:25.54,EN,,0,0,0,,and then what the car is--here's the car, that itself is a pair of 2 and 3. Dialogue: 0,0:05:26.02,0:05:28.08,EN,,0,0,0,,And similarly the cdr is a pair of 2 and 3. Dialogue: 0,0:05:28.16,0:05:29.24,EN,,0,0,0,,And let me remind you again Dialogue: 0,0:05:29.32,0:05:33.46,EN,,0,0,0,,that a lot of people have some idea that if I'd taken this arrow and somehow Dialogue: 0,0:05:33.80,0:05:36.90,EN,,0,0,0,,written it to point down, that would mean something else. Dialogue: 0,0:05:36.98,0:05:38.28,EN,,0,0,0,,That's irrelevant. Dialogue: 0,0:05:38.58,0:05:43.90,EN,,0,0,0,,It's only how these are connected and not whether this arrow happens to go vertically or horizontally. Dialogue: 0,0:05:47.48,0:05:52.18,EN,,0,0,0,,And again just to remind you, there was this notion of closure. Dialogue: 0,0:05:52.94,0:06:05.62,EN,,0,0,0,,See, closure was the thing that allowed us to start building up complexity, that didn't trap us in pairs. Dialogue: 0,0:06:06.64,0:06:15.24,EN,,0,0,0,,Particularly what I mean is the things that we make, having combined things using cons to get a pair, Dialogue: 0,0:06:16.44,0:06:22.64,EN,,0,0,0,,those things themselves can be combined using cons to make more complicated things. Dialogue: 0,0:06:23.28,0:06:31.98,EN,,0,0,0,,Or as a mathematician might say, the set of data objects in Lisp is closed under the operation of forming pairs. Dialogue: 0,0:06:33.82,0:06:36.34,EN,,0,0,0,,That's the thing that allows us to build complexity. Dialogue: 0,0:06:36.34,0:06:38.04,EN,,0,0,0,,And that seems obvious, but remember Dialogue: 0,0:06:39.06,0:06:42.46,EN,,0,0,0,,a lot of the things in the computer languages that people use are not closed. Dialogue: 0,0:06:42.46,0:06:48.06,EN,,0,0,0,,So for example, forming arrays in Basic and Fortran is not a closed operation, Dialogue: 0,0:06:48.08,0:06:51.94,EN,,0,0,0,,because you can make an array of numbers or character strings or something, Dialogue: 0,0:06:52.04,0:06:54.18,EN,,0,0,0,,but you can't make an array of arrays. Dialogue: 0,0:06:54.64,0:06:56.68,EN,,0,0,0,,And when you look at means of combination Dialogue: 0,0:06:57.60,0:07:02.78,EN,,0,0,0,,you should be asking yourself whether things are closed under that means of combination. Dialogue: 0,0:07:05.06,0:07:08.26,EN,,0,0,0,,Well in any case, because we can form pairs of pairs, Dialogue: 0,0:07:08.86,0:07:12.78,EN,,0,0,0,,we can start using pairs to glue things together in all sorts of different ways. Dialogue: 0,0:07:14.02,0:07:18.26,EN,,0,0,0,,So for instance if I'd like to glue together the four things, 1, 2, 3 and 4, Dialogue: 0,0:07:18.26,0:07:19.82,EN,,0,0,0,,there are a lot of ways I can do it. Dialogue: 0,0:07:20.74,0:07:26.12,EN,,0,0,0,,I could, for example, like we did with that line segment, i could make a pair Dialogue: 0,0:07:29.02,0:07:36.88,EN,,0,0,0,,that had a 1 and a 2 and a 3 and a 4, right? Dialogue: 0,0:07:36.88,0:07:40.06,EN,,0,0,0,,Or if I liked, I could do something like this. Dialogue: 0,0:07:40.06,0:07:45.52,EN,,0,0,0,,I could make a pair, whose first thing is a pair, Dialogue: 0,0:07:46.44,0:07:53.20,EN,,0,0,0,,whose car is 1, and his cdr is itself a pair that has the 2 and the 3 Dialogue: 0,0:07:53.26,0:07:55.08,EN,,0,0,0,,and then I could put the 4 up here. Dialogue: 0,0:07:56.92,0:08:02.16,EN,,0,0,0,,So you see, there are a lot of different ways that I can start using pairs to glue things together, Dialogue: 0,0:08:02.16,0:08:07.74,EN,,0,0,0,,and so it'll be a good idea to establish some kind of conventions,right, Dialogue: 0,0:08:07.74,0:08:11.58,EN,,0,0,0,,that allow us to deal with this thing in some conventional way, Dialogue: 0,0:08:11.58,0:08:14.00,EN,,0,0,0,,so we're not constantly making an ad hoc choice. Dialogue: 0,0:08:15.94,0:08:19.04,EN,,0,0,0,,And Lisp has a particular convention Dialogue: 0,0:08:20.74,0:08:25.82,EN,,0,0,0,,for representing a sequence of things as, essentially, a chain of pairs, Dialogue: 0,0:08:26.78,0:08:28.18,EN,,0,0,0,,and that's called a List. Dialogue: 0,0:08:34.72,0:08:40.50,EN,,0,0,0,,And what a list is is essentially just a convention for representing a sequence. Dialogue: 0,0:08:40.70,0:08:47.38,EN,,0,0,0,,I would represent the sequence 1, 2, 3 and 4 by a sequence of pairs. Dialogue: 0,0:08:48.26,0:08:54.68,EN,,0,0,0,,I'd put 1 here and then the cdr of this would point to another pair Dialogue: 0,0:08:59.20,0:09:01.40,EN,,0,0,0,,whose car was the next thing in the sequence, Dialogue: 0,0:09:01.52,0:09:03.42,EN,,0,0,0,,and the cdr would point to another pair Dialogue: 0,0:09:05.44,0:09:07.30,EN,,0,0,0,,whose car was the next thing in the sequence-- Dialogue: 0,0:09:07.36,0:09:08.44,EN,,0,0,0,,so there's 3-- Dialogue: 0,0:09:08.44,0:09:09.74,EN,,0,0,0,,and then another one. Dialogue: 0,0:09:09.74,0:09:13.22,EN,,0,0,0,,So for each item in the sequence, I'll get a pair. Dialogue: 0,0:09:15.82,0:09:18.32,EN,,0,0,0,,And now there are no more, so I put a special marker Dialogue: 0,0:09:20.72,0:09:22.74,EN,,0,0,0,,that means there's nothing more in the List. Dialogue: 0,0:09:24.14,0:09:34.64,EN,,0,0,0,,OK, so that's a conventional way to glue things together if you want to represent a sequence, right. Dialogue: 0,0:09:34.64,0:09:37.98,EN,,0,0,0,,And what it is is a bunch of pairs, Dialogue: 0,0:09:39.40,0:09:44.80,EN,,0,0,0,,the successive cars of each pair are the items that you want to glue together, Dialogue: 0,0:09:46.00,0:09:48.46,EN,,0,0,0,,and the cdr pointer points to the next pair. Dialogue: 0,0:09:50.02,0:09:56.04,EN,,0,0,0,,Now if I actually wanted to construct that, what I would type into Lisp is this: Dialogue: 0,0:09:56.62,0:09:58.76,EN,,0,0,0,,I'd actually construct that as saying, well this thing is Dialogue: 0,0:09:59.22,0:10:15.28,EN,,0,0,0,,the cons of 1 onto the cons of 2 onto the cons of 3 onto the cons of 4 onto, well, this thing nil. Dialogue: 0,0:10:15.28,0:10:20.00,EN,,0,0,0,,And what nil is is a name for the end of List marker. Dialogue: 0,0:10:20.80,0:10:23.24,EN,,0,0,0,,It's a special name, which means this is the end of the List. Dialogue: 0,0:10:26.24,0:10:30.26,EN,,0,0,0,,OK, so that's how I would actually construct that. Dialogue: 0,0:10:37.54,0:10:41.40,EN,,0,0,0,,Of course, it's a terrible drag to constantly have to write something like Dialogue: 0,0:10:41.45,0:10:45.18,EN,,0,0,0,,the cons of 1 onto the cons of 2 onto the cons of 3, whenever you want to make this thing. Dialogue: 0,0:10:45.18,0:10:50.10,EN,,0,0,0,,So Lisp has an operation that's called LIST, Dialogue: 0,0:10:53.70,0:10:57.72,EN,,0,0,0,,and List is just an abbreviation for this nest of conses. Dialogue: 0,0:10:58.96,0:11:06.32,EN,,0,0,0,,So I could say, I could construct that by saying that is the List of 1, 2, 3 and 4. Dialogue: 0,0:11:07.78,0:11:11.74,EN,,0,0,0,,And all this is is another way, a piece of syntactic sugar, Dialogue: 0,0:11:11.94,0:11:14.76,EN,,0,0,0,,a more convenient way for writing that chain of conses-- Dialogue: 0,0:11:14.76,0:11:17.84,EN,,0,0,0,,cons of cons of cons of cons of cons of cons onto nil. Dialogue: 0,0:11:18.48,0:11:39.78,EN,,0,0,0,,So for example, I could build this thing and say, I'll define 1-TO-4 to be the List of 1, 2, 3 and 4. Dialogue: 0,0:11:47.96,0:11:53.02,EN,,0,0,0,,OK, well notice some of the consequences of using this convention. Dialogue: 0,0:11:53.80,0:11:56.92,EN,,0,0,0,,First of all if I have this List, this 1, 2, 3 and 4, Dialogue: 0,0:11:57.36,0:12:02.64,EN,,0,0,0,,the car of the whole thing is the first element in the List, right. Dialogue: 0,0:12:04.06,0:12:05.28,EN,,0,0,0,,How do I get 2? Dialogue: 0,0:12:05.28,0:12:23.94,EN,,0,0,0,,Well, 2 would be the car of the cdr of this thing 1-TO-4, it would be 2, right. Dialogue: 0,0:12:23.98,0:12:29.48,EN,,0,0,0,,I take this thing, I take the cdr of it, which is this much, Dialogue: 0,0:12:29.82,0:12:31.68,EN,,0,0,0,,and the car of that is 2, Dialogue: 0,0:12:32.58,0:12:47.42,EN,,0,0,0,,and then similarly, the car of the cdr of the cdr of 1-TO-4, cdr, cdr, car-- Dialogue: 0,0:12:47.42,0:12:51.36,EN,,0,0,0,,would give me 3, and so on. Dialogue: 0,0:12:52.68,0:12:55.84,EN,,0,0,0,,Let's take a look at that on the computer screen for a second. Dialogue: 0,0:12:57.50,0:13:11.18,EN,,0,0,0,,I could come up to List, and I could type define 1-TO-4 to be the List of 1, 2, 3 and 4, right. Dialogue: 0,0:13:13.78,0:13:21.28,EN,,0,0,0,,And I'll tell that to Lisp, and it says, fine, that's the definition of 1-TO-4. Dialogue: 0,0:13:22.30,0:13:36.74,EN,,0,0,0,,And I could say, for instance, what's the car of the cdr of the cdr of 1-TO-4, close paren, close paren. Dialogue: 0,0:13:38.34,0:13:42.42,EN,,0,0,0,,Right, so the car of the cdr of the cdr would be 3. Dialogue: 0,0:13:44.08,0:13:50.08,EN,,0,0,0,,Right, or I could say, what's 1-TO-4 itself. Dialogue: 0,0:13:51.26,0:13:57.22,EN,,0,0,0,,And you see what Lisp typed out is 1, 2, 3, 4, enclosed in parentheses, Dialogue: 0,0:13:57.22,0:14:02.12,EN,,0,0,0,,and this notation, typing the elements of the List enclosed in parentheses Dialogue: 0,0:14:02.12,0:14:08.90,EN,,0,0,0,,is Lisp's conventional way for printing back this chain of pairs that represents a sequence. Dialogue: 0,0:14:08.90,0:14:17.14,EN,,0,0,0,,So for example, if I said, what's the cdr of 1-TO-4, Dialogue: 0,0:14:19.30,0:14:21.12,EN,,0,0,0,,that's going to be the rest of the List. Dialogue: 0,0:14:21.32,0:14:26.96,EN,,0,0,0,,That's the thing pointed to by the first pair, which is, again, a sequence that starts off with 2. Dialogue: 0,0:14:28.52,0:14:37.74,EN,,0,0,0,,Or for example, I go off and say, what's the cdr of the cdr of 1-TO-4; Dialogue: 0,0:14:43.24,0:14:44.68,EN,,0,0,0,,then that's 3,4. Dialogue: 0,0:14:44.82,0:14:59.66,EN,,0,0,0,,Or if I say, what's the cdr of the cdr of the cdr of the cdr of 1-TO-4, Dialogue: 0,0:15:04.74,0:15:10.46,EN,,0,0,0,,and I'm down there looking at the end of List pointer itself, and Lisp prints that as just open paren, close paren. Dialogue: 0,0:15:10.96,0:15:13.48,EN,,0,0,0,,You can think of that as a List with nothing in there. Dialogue: 0,0:15:14.12,0:15:21.38,EN,,0,0,0,,All right, see at the end what I did there was I looked at the cdr of the cdr of the cdr of 1-TO-4, Dialogue: 0,0:15:21.42,0:15:25.20,EN,,0,0,0,,and I'm just left with the end of List pointer itself. Dialogue: 0,0:15:25.20,0:15:27.20,EN,,0,0,0,,And that gets printed as open close. Dialogue: 0,0:15:34.14,0:15:39.98,EN,,0,0,0,,All right, well that's a conventional way you can see for working down a List Dialogue: 0,0:15:41.50,0:15:43.44,EN,,0,0,0,,by taking successive cdrs of things. Dialogue: 0,0:15:43.44,0:15:45.00,EN,,0,0,0,,It's called cdring down a List. Dialogue: 0,0:15:46.64,0:15:49.78,EN,,0,0,0,,And of course it's pretty much of a drag to type all those cdrs by hand. Dialogue: 0,0:15:49.78,0:15:52.24,EN,,0,0,0,,You don't do that. You write procedures that do that. Dialogue: 0,0:15:52.96,0:15:59.10,EN,,0,0,0,,And in fact one very, very common thing to do in Lisp is to write procedures that, Dialogue: 0,0:15:59.85,0:16:06.54,EN,,0,0,0,,sort of, take a List of things and do something to every element in List, and return you a List of the results. Dialogue: 0,0:16:07.42,0:16:11.92,EN,,0,0,0,,So what I mean for example, is I might write a procedure called Scale-List, Dialogue: 0,0:16:16.80,0:16:25.24,EN,,0,0,0,,and Scale-List I might say I want to scale by 10 the entire List 1-TO-4, Dialogue: 0,0:16:26.66,0:16:35.32,EN,,0,0,0,,and that would return for me the List 10, 20, 30, 40. Dialogue: 0,0:16:38.25,0:16:40.25,EN,,0,0,0,,Right, it returns List, and Dialogue: 0,0:16:44.49,0:16:49.30,EN,,0,0,0,,well you can see that there's going to be some kind of recursive strategy for doing it. Dialogue: 0,0:16:49.30,0:16:51.30,EN,,0,0,0,,How would I actually write that procedure? Dialogue: 0,0:16:52.52,0:16:59.80,EN,,0,0,0,,The idea would be, well if you'd like to build up a List where you've multiplied every element by 10, Dialogue: 0,0:17:00.44,0:17:04.84,EN,,0,0,0,,what you'd say is well you imagine that you'd taken the rest of the List-- Dialogue: 0,0:17:05.86,0:17:08.42,EN,,0,0,0,,right, the thing represented by the cdr of the List, Dialogue: 0,0:17:08.42,0:17:14.16,EN,,0,0,0,,and suppose I'd already built a List where each of these was multiplied by 10-- Dialogue: 0,0:17:16.06,0:17:19.68,EN,,0,0,0,,that would be Scale-List of the cdr of the List. Dialogue: 0,0:17:20.12,0:17:23.82,EN,,0,0,0,,And then all I have to do is multiply the car of the List by 10, Dialogue: 0,0:17:24.89,0:17:27.24,EN,,0,0,0,,and then cons that onto the rest, and I'll get a List. Dialogue: 0,0:17:29.02,0:17:33.09,EN,,0,0,0,,Right and then similarly, to have scaled the cdr of the List, I'll scale the cdr of that Dialogue: 0,0:17:33.30,0:17:36.20,EN,,0,0,0,,cons onto that 2 multiplied by 10. Dialogue: 0,0:17:36.42,0:17:41.16,EN,,0,0,0,,And finally when I get all the way down to the end, and I only have this end of List pointer. Dialogue: 0,0:17:41.72,0:17:45.28,EN,,0,0,0,,All right, this thing whose name is nil-- well I just returned an end of List pointer. Dialogue: 0,0:17:45.54,0:17:47.68,EN,,0,0,0,,So there's a recursive strategy for doing that. Dialogue: 0,0:17:47.68,0:17:50.52,EN,,0,0,0,,Here's the actual procedure that does that. Dialogue: 0,0:17:50.96,0:17:55.04,EN,,0,0,0,,Right, this is an example of the general strategy of cdr-ing down a List and Dialogue: 0,0:17:55.66,0:17:58.24,EN,,0,0,0,,so called cons-ing up the result, right. Dialogue: 0,0:17:58.24,0:18:06.04,EN,,0,0,0,,So to Scale a List l by some scale factor s, what do I do? Dialogue: 0,0:18:06.04,0:18:10.40,EN,,0,0,0,,Well there's a test, and Lisp has the predicate called null. Dialogue: 0,0:18:10.40,0:18:13.22,EN,,0,0,0,,Null means is this thing the end of List pointer, Dialogue: 0,0:18:13.90,0:18:17.16,EN,,0,0,0,,or another way to think of that is are there any elements in this List, right. Dialogue: 0,0:18:18.17,0:18:23.00,EN,,0,0,0,,But in any case if I'm looking at the end of List pointer, then I just return the end of List pointer. Dialogue: 0,0:18:23.65,0:18:24.60,EN,,0,0,0,,I just return nil, Dialogue: 0,0:18:24.94,0:18:35.14,EN,,0,0,0,,otherwise I cons together the result of doing what I'm going to do to the first element in the List, Dialogue: 0,0:18:35.54,0:18:39.29,EN,,0,0,0,,namely taking the car of l and multiplying it by s, Dialogue: 0,0:18:40.36,0:18:46.34,EN,,0,0,0,,and I cons that onto recursively scaling the rest of the List. Dialogue: 0,0:18:49.98,0:18:52.18,EN,,0,0,0,,OK, so again, the general idea is that you Dialogue: 0,0:18:52.22,0:18:56.09,EN,,0,0,0,,you recursively do something to the rest of the List, to the cdr of the List, Dialogue: 0,0:18:56.48,0:19:01.16,EN,,0,0,0,,and then you cons that onto actually doing something to the first element of the List. Dialogue: 0,0:19:01.16,0:19:05.18,EN,,0,0,0,,When you get down to the end here, you return the end of List pointer, Dialogue: 0,0:19:07.34,0:19:11.36,EN,,0,0,0,,and that's a general pattern for doing something to a list. Dialogue: 0,0:19:14.05,0:19:19.52,EN,,0,0,0,,Well of course you should know by now that the very fact Dialogue: 0,0:19:19.53,0:19:22.62,EN,,0,0,0,,that there's a general pattern there means I shouldn't be writing this procedure at all. Dialogue: 0,0:19:22.62,0:19:24.90,EN,,0,0,0,,What I should do is write a procedure Dialogue: 0,0:19:24.90,0:19:26.32,EN,,0,0,0,,that's the general pattern itself Dialogue: 0,0:19:26.80,0:19:30.30,EN,,0,0,0,,that says, do something to everything in the List and define this thing in terms of that. Dialogue: 0,0:19:30.68,0:19:32.30,EN,,0,0,0,,Right, make some higher order procedure, Dialogue: 0,0:19:32.32,0:19:35.18,EN,,0,0,0,,and here's the higher order procedure that does that. It's called MAP, Dialogue: 0,0:19:36.73,0:19:43.17,EN,,0,0,0,,and what MAP does is it takes a List, takes a List l, and it takes a procedure p, Dialogue: 0,0:19:44.92,0:19:51.08,EN,,0,0,0,,and it returns the List of the elements gotten by applying p to each successive element in the List. Dialogue: 0,0:19:51.81,0:19:55.40,EN,,0,0,0,,All right, so p of e1, p of e2, p of en. Dialogue: 0,0:19:55.64,0:20:01.54,EN,,0,0,0,,Right, so I think of taking this List and transforming it by applying p to each element. Dialogue: 0,0:20:02.52,0:20:07.08,EN,,0,0,0,,And you see all this procedure is is exactly the general strategy I said. Dialogue: 0,0:20:07.08,0:20:09.08,EN,,0,0,0,,Instead of multiply by 10, it's do the procedure. Dialogue: 0,0:20:09.08,0:20:11.64,EN,,0,0,0,,If the List is empty, return nil. Dialogue: 0,0:20:11.86,0:20:16.60,EN,,0,0,0,,Otherwise, apply p to the first element of the List. Dialogue: 0,0:20:17.14,0:20:18.74,EN,,0,0,0,,Right, apply p to car of l, Dialogue: 0,0:20:19.30,0:20:25.40,EN,,0,0,0,,and cons that onto the result of applying p to everything in the cdr of the List, Dialogue: 0,0:20:25.61,0:20:28.84,EN,,0,0,0,,so that's a general procedure called MAP. Dialogue: 0,0:20:29.86,0:20:39.04,EN,,0,0,0,,And I could define Scale-List in terms of MAP. Dialogue: 0,0:20:39.04,0:20:41.04,EN,,0,0,0,,Let me show you that first. Dialogue: 0,0:20:43.46,0:20:52.50,EN,,0,0,0,,But I could say Scale-List is another way to define it is just MAP along the List by the procedure, Dialogue: 0,0:20:52.50,0:20:55.54,EN,,0,0,0,,which takes an item and multiplies it by s. Dialogue: 0,0:20:58.96,0:21:01.90,EN,,0,0,0,,Right, so this is really the way I should think about scaling the List, Dialogue: 0,0:21:02.12,0:21:07.40,EN,,0,0,0,,build that actual recursion into the general strategy, not to every particular procedure I write. Dialogue: 0,0:21:07.40,0:21:11.28,EN,,0,0,0,,And of course, one of the values of doing this is that you start to see commonality. Dialogue: 0,0:21:12.16,0:21:15.02,EN,,0,0,0,,Right, again you're capturing general patterns of usage. Dialogue: 0,0:21:15.96,0:21:31.18,EN,,0,0,0,,For instance, if I said MAP, the square procedure, down this List 1-TO-4, then I'd end up with 1, 4, 9 and 16. Dialogue: 0,0:21:32.48,0:21:37.17,EN,,0,0,0,,Right, or if I said MAP down this List, Dialogue: 0,0:21:37.57,0:21:46.32,EN,,0,0,0,,lambda of x plus x 10, if I MAP that down 1-TO-4, Dialogue: 0,0:21:49.68,0:21:52.86,EN,,0,0,0,,then I'd get the List where everything had 10 added to it: Dialogue: 0,0:21:53.34,0:21:58.17,EN,,0,0,0,,right, so I'd get 11,12, 13, 14. Dialogue: 0,0:22:00.56,0:22:05.76,EN,,0,0,0,,And you can see that's going to be a very, very common idea: doing something to every element in the List. Dialogue: 0,0:22:08.66,0:22:12.22,EN,,0,0,0,,One thing you might think about is writing MAP in an iterative style. Dialogue: 0,0:22:12.22,0:22:16.04,EN,,0,0,0,,The one I wrote happens to evolve a recursive process, Dialogue: 0,0:22:16.36,0:22:19.10,EN,,0,0,0,,but we could just as easily have made one that evolves an iterative process. Dialogue: 0,0:22:19.10,0:22:23.16,EN,,0,0,0,,But see the interesting thing about it is that once you start thinking in terms of MAP-- Dialogue: 0,0:22:24.02,0:22:29.00,EN,,0,0,0,,see, once you say scale is just MAP, you stop thinking about whether it's iterative or recursive, Dialogue: 0,0:22:29.00,0:22:31.82,EN,,0,0,0,,and you just say, well there's this aggregate, there's this List, Dialogue: 0,0:22:32.22,0:22:34.52,EN,,0,0,0,,and what I do is transform every item in the List, Dialogue: 0,0:22:34.56,0:22:38.36,EN,,0,0,0,,and I stop thinking about the particular control structure in order. Dialogue: 0,0:22:38.88,0:22:41.09,EN,,0,0,0,,That's a very, very important idea, Dialogue: 0,0:22:42.36,0:22:46.48,EN,,0,0,0,,and it, I guess it really comes out of APL. Dialogue: 0,0:22:46.48,0:22:49.10,EN,,0,0,0,,It's, sort of, the really important idea in APL Dialogue: 0,0:22:49.12,0:22:51.13,EN,,0,0,0,,that you stop thinking about control structures, Dialogue: 0,0:22:51.41,0:22:53.92,EN,,0,0,0,,and you start thinking about operations on aggregates, Dialogue: 0,0:22:55.01,0:23:00.01,EN,,0,0,0,,and then about halfway through this course,we'll see when we talk about something called stream processing, Dialogue: 0,0:23:00.26,0:23:02.64,EN,,0,0,0,,how that view of the world really comes into its glory. Dialogue: 0,0:23:02.64,0:23:05.30,EN,,0,0,0,,This is just us a, sort of, cute idea. Dialogue: 0,0:23:05.30,0:23:08.70,EN,,0,0,0,,But we'll see much more applications of that later on. Dialogue: 0,0:23:09.36,0:23:16.84,EN,,0,0,0,,Well let me mention that there's something that's very similar to MAP that's also a useful idea, and that's-- Dialogue: 0,0:23:17.56,0:23:22.54,EN,,0,0,0,,see, MAP says I take a List, I apply something to each item, Dialogue: 0,0:23:22.98,0:23:25.62,EN,,0,0,0,,and I return a List of the successive values. Dialogue: 0,0:23:25.98,0:23:28.69,EN,,0,0,0,,There's another thing I might do, which is very, very similar, Dialogue: 0,0:23:29.32,0:23:35.86,EN,,0,0,0,,which is take a List and some action you want to do and then do it to each item in the List in sequence. Dialogue: 0,0:23:36.29,0:23:39.40,EN,,0,0,0,,Don't make a List of the values, just do this particular action, Dialogue: 0,0:23:40.02,0:23:45.10,EN,,0,0,0,,and that's something that's very much like MAP. Dialogue: 0,0:23:45.10,0:23:46.02,EN,,0,0,0,,It's called for-each, Dialogue: 0,0:23:46.74,0:23:49.48,EN,,0,0,0,,and for-each takes a procedure and a List, Dialogue: 0,0:23:49.62,0:23:53.86,EN,,0,0,0,,and what it's going to do is do something to every item in the List. Dialogue: 0,0:23:55.16,0:23:58.53,EN,,0,0,0,,So basically what it does: it says if the List is not empty, Dialogue: 0,0:23:59.74,0:24:01.12,EN,,0,0,0,,if the List is not null, Dialogue: 0,0:24:01.90,0:24:06.25,EN,,0,0,0,,then what I do is, I apply my procedure to the first item in the List, Dialogue: 0,0:24:07.68,0:24:11.66,EN,,0,0,0,,and then I do this thing to the rest of the List. Dialogue: 0,0:24:12.44,0:24:15.25,EN,,0,0,0,,I apply for-each to the cdr of the List. Dialogue: 0,0:24:15.88,0:24:18.73,EN,,0,0,0,,All right, so I do it to the first of the List, do it to the rest of the List, Dialogue: 0,0:24:19.32,0:24:23.92,EN,,0,0,0,,and of course, when I call it recursively, that's going to do it to the rest of the rest of the List and so on. Dialogue: 0,0:24:23.92,0:24:28.12,EN,,0,0,0,,And finally, when I get done, I have to just do something to say I'm done, Dialogue: 0,0:24:28.16,0:24:32.40,EN,,0,0,0,,so we'll return the message "done." So that's very, very similar to MAP. Dialogue: 0,0:24:32.80,0:24:35.12,EN,,0,0,0,,It's mostly different in what it returns. Dialogue: 0,0:24:35.48,0:24:39.90,EN,,0,0,0,,And so for example, if I had some procedure that printed things on the screen, Dialogue: 0,0:24:40.56,0:24:45.81,EN,,0,0,0,,if I wanted to print everything in the List, I could say for-each, print this List. Dialogue: 0,0:24:46.78,0:24:51.33,EN,,0,0,0,,Or if I had a List of figures, and I wanted to draw them on the display, Dialogue: 0,0:24:51.62,0:24:54.86,EN,,0,0,0,,I could say for-each, display on the screen this figure. Dialogue: 0,0:24:58.18,0:24:59.32,EN,,0,0,0,,Take questions. Dialogue: 0,0:25:00.62,0:25:04.26,EN,,0,0,0,,AUDIENCE: Does it create a new copy with something done to it, Dialogue: 0,0:25:04.30,0:25:07.54,EN,,0,0,0,,unless you explicitly tell it to do that? Is that correct? Dialogue: 0,0:25:07.54,0:25:09.18,EN,,0,0,0,,PROFESSOR: Right. Ah. Dialogue: 0,0:25:09.93,0:25:10.94,EN,,0,0,0,,Yeah, that's right. Dialogue: 0,0:25:10.94,0:25:15.14,EN,,0,0,0,,For-each does not create a List. It just sort of does something. Dialogue: 0,0:25:15.14,0:25:17.29,EN,,0,0,0,,So if you have a bunch of things you want to do Dialogue: 0,0:25:18.02,0:25:21.56,EN,,0,0,0,,and you're not worried about values like printing something, or drawing something on the screen, Dialogue: 0,0:25:21.89,0:25:24.60,EN,,0,0,0,,or ringing the bell on the terminal,or for something, Dialogue: 0,0:25:24.60,0:25:27.64,EN,,0,0,0,,you can say for-each, you know, do this for-each of those things in the List, Dialogue: 0,0:25:28.21,0:25:32.42,EN,,0,0,0,,whereas MAP actually builds you this new collection of values that you might want to use. Dialogue: 0,0:25:32.42,0:25:34.16,EN,,0,0,0,,It's just a subtle difference between them. Dialogue: 0,0:25:34.16,0:25:36.30,EN,,0,0,0,,AUDIENCE: Could you write MAP using for-each, Dialogue: 0,0:25:36.32,0:25:40.16,EN,,0,0,0,,so that you did some sort of cons or something to build the List back up? Dialogue: 0,0:25:40.18,0:25:44.46,EN,,0,0,0,,PROFESSOR: Well, sort of. I mean, I probably could. Dialogue: 0,0:25:44.46,0:25:49.98,EN,,0,0,0,,I can't think of how to do it right offhand, but yeah, I could arrange something. Dialogue: 0,0:25:50.48,0:25:54.73,EN,,0,0,0,,AUDIENCE: The vital difference between MAP and for-each is one is recursive and the other is not Dialogue: 0,0:25:54.73,0:26:00.62,EN,,0,0,0,,in the sense you defined early yesterday, I believe. Dialogue: 0,0:26:01.24,0:26:03.86,EN,,0,0,0,,PROFESSOR: Yeah, about MAP and for-each and recursion. Dialogue: 0,0:26:03.86,0:26:05.48,EN,,0,0,0,,Yeah, that's a good point. Dialogue: 0,0:26:05.48,0:26:13.08,EN,,0,0,0,,For the MAP procedure I wrote, that happens to be a recursive process. Dialogue: 0,0:26:13.82,0:26:17.06,EN,,0,0,0,,And the reason for that is that when you've done this thing to the rest of the List, Dialogue: 0,0:26:17.08,0:26:20.96,EN,,0,0,0,,you're waiting for that value so that you can stick it on to the beginning of the List, Dialogue: 0,0:26:21.73,0:26:24.53,EN,,0,0,0,,whereas for-each doesn't really have any values to wait for. Dialogue: 0,0:26:24.84,0:26:26.66,EN,,0,0,0,,So that turns out to be an iterative process. Dialogue: 0,0:26:26.66,0:26:27.72,EN,,0,0,0,,That's not fundamental. Dialogue: 0,0:26:27.72,0:26:31.80,EN,,0,0,0,,I could have defined MAP so that it's evolved by an iterative process. Dialogue: 0,0:26:31.82,0:26:32.82,EN,,0,0,0,,I just didn't happen to. Dialogue: 0,0:26:34.24,0:26:42.90,EN,,0,0,0,,AUDIENCE: If you were to call for each with a List that had embedded Lists, I imagine it would work, right? Dialogue: 0,0:26:42.90,0:26:48.10,EN,,0,0,0,,It would give you the internal elements of each of those internal Lists? Dialogue: 0,0:26:48.70,0:26:50.40,EN,,0,0,0,,PROFESSOR: OK, the question is if I call Dialogue: 0,0:26:50.40,0:26:52.28,EN,,0,0,0,,for-each or map, for that matter Dialogue: 0,0:26:52.81,0:26:55.28,EN,,0,0,0,,with a List that had Lists in it Dialogue: 0,0:26:56.69,0:27:00.60,EN,,0,0,0,,although we haven't really looked at that yet--would that work. Dialogue: 0,0:27:01.02,0:27:06.56,EN,,0,0,0,,The answer is yes in the sense I mean work and no in the sense that you mean work, Dialogue: 0,0:27:06.86,0:27:10.65,EN,,0,0,0,,because all that-- see if I give you a List, Dialogue: 0,0:27:12.80,0:27:14.20,EN,,0,0,0,,where hanging off here is, Dialogue: 0,0:27:16.06,0:27:21.46,EN,,0,0,0,,you know, is something that's not a number, maybe another List or you know, another cons or something, Dialogue: 0,0:27:21.96,0:27:24.54,EN,,0,0,0,,for-each just says do something to each item in this List. Dialogue: 0,0:27:24.54,0:27:26.96,EN,,0,0,0,,It goes down successively looking at the cdrs. Dialogue: 0,0:27:26.96,0:27:27.20,EN,,0,0,0,,AUDIENCE: OK. Dialogue: 0,0:27:27.20,0:27:31.06,EN,,0,0,0,,PROFESSOR: And as far as it's concerned, the first item in this List is whatever is hanging off here. Dialogue: 0,0:27:31.06,0:27:31.65,EN,,0,0,0,,AUDIENCE: Mhm. Dialogue: 0,0:27:31.65,0:27:33.94,EN,,0,0,0,,PROFESSOR: That might or might not be the right thing. Dialogue: 0,0:27:33.94,0:27:35.57,EN,,0,0,0,,AUDIENCE: So it wouldn't go down into the-- Dialogue: 0,0:27:35.57,0:27:36.91,EN,,0,0,0,,PROFESSOR: Absolutely not. Dialogue: 0,0:27:36.91,0:27:38.51,EN,,0,0,0,,I could certainly write something else. Dialogue: 0,0:27:38.51,0:27:42.97,EN,,0,0,0,,There's another, what you're looking for is a common pattern of usage called tree recursion, Dialogue: 0,0:27:43.01,0:27:47.94,EN,,0,0,0,,where you take a List, and you actually go all the way down to the what's called the leaves of the tree. Dialogue: 0,0:27:47.94,0:27:51.05,EN,,0,0,0,,And you could write such a thing, but that's not for-each and it's not MAP. Dialogue: 0,0:27:52.42,0:27:55.05,EN,,0,0,0,,Remember, these things are really being very simple minded. Dialogue: 0,0:27:55.77,0:27:56.89,EN,,0,0,0,,OK, no more questions? Dialogue: 0,0:27:57.68,0:27:58.57,EN,,0,0,0,,All right, let's break. Dialogue: 0,0:27:59.11,0:28:10.99,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:28:11.46,0:28:14.29,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:28:14.32,0:28:17.52,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:28:27.38,0:28:34.22,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:28:34.86,0:28:38.58,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson Escher Example Dialogue: 0,0:28:41.94,0:28:48.65,EN,,0,0,0,,PROFESSOR: What I'd like to do now is spend the rest of this time talking about one example, Dialogue: 0,0:28:50.04,0:28:53.92,EN,,0,0,0,,and this example, I think, pretty much summarizes everything that we've done up until now: Dialogue: 0,0:28:54.74,0:28:56.29,EN,,0,0,0,,all right, and that's List structure Dialogue: 0,0:28:57.17,0:28:59.48,EN,,0,0,0,,and issues of abstraction, Dialogue: 0,0:28:59.54,0:29:00.82,EN,,0,0,0,,and representation Dialogue: 0,0:29:01.60,0:29:04.60,EN,,0,0,0,,and representation and capturing commonality with higher order procedures, Dialogue: 0,0:29:04.60,0:29:09.80,EN,,0,0,0,,and also is going to introduce something we haven't really talked about a lot yet-- what I said is the major third theme in this course: Dialogue: 0,0:29:09.85,0:29:13.46,EN,,0,0,0,,what I said is the major third theme in this course: Dialogue: 0,0:29:13.96,0:29:15.53,EN,,0,0,0,,meta-linguistic abstraction, Dialogue: 0,0:29:15.54,0:29:21.90,EN,,0,0,0,,which is the idea that one of the ways of tackling complexity in engineering design Dialogue: 0,0:29:22.86,0:29:25.80,EN,,0,0,0,,is to build a suitable powerful language. Dialogue: 0,0:29:28.17,0:29:34.74,EN,,0,0,0,,You might recall what I said was pretty much the very most important thing that we're going to tell you in this course is that Dialogue: 0,0:29:34.74,0:29:41.17,EN,,0,0,0,,when you think about a language, you think about it in terms of what are the primitives; Dialogue: 0,0:29:42.98,0:29:46.69,EN,,0,0,0,,what are the means of combination-- Dialogue: 0,0:29:49.72,0:29:52.80,EN,,0,0,0,,right, what are the things that allow you to build bigger things; Dialogue: 0,0:29:53.61,0:29:55.24,EN,,0,0,0,,and then what are the means of abstraction. Dialogue: 0,0:30:00.97,0:30:05.16,EN,,0,0,0,,How do you take those bigger things that you've built Dialogue: 0,0:30:05.56,0:30:07.97,EN,,0,0,0,,put black boxes around them Dialogue: 0,0:30:08.45,0:30:11.71,EN,,0,0,0,,and use them as elements in making something even more complicated? Dialogue: 0,0:30:13.53,0:30:18.72,EN,,0,0,0,,Now the particular language I'm going to talk about is an example Dialogue: 0,0:30:18.73,0:30:22.70,EN,,0,0,0,,that was made up by a friend of ours called Peter Henderson. Dialogue: 0,0:30:28.24,0:30:31.74,EN,,0,0,0,,Peter Henderson is at the University of Stirling in Scotland. Dialogue: 0,0:30:32.78,0:30:40.98,EN,,0,0,0,,And what this language is about is making figures that sort of look like this. Dialogue: 0,0:30:41.86,0:30:46.66,EN,,0,0,0,,This is this is a woodcut by Escher called "Square Limit." Dialogue: 0,0:30:49.33,0:30:57.94,EN,,0,0,0,,You, sort of, see it has this complicated, kind of, recursive, sort of, recursive kind of figure, Dialogue: 0,0:30:58.84,0:31:01.46,EN,,0,0,0,,where there's this fish pattern in the middle and things sort of Dialogue: 0,0:31:01.70,0:31:04.56,EN,,0,0,0,,bleed out smaller and smaller in self similar ways. Dialogue: 0,0:31:08.49,0:31:12.80,EN,,0,0,0,,Anyway, Peter Henderson's language was for describing figures that look like that Dialogue: 0,0:31:13.37,0:31:18.28,EN,,0,0,0,,and designing new ones that look like that and drawing them on a display screen. Dialogue: 0,0:31:20.24,0:31:27.48,EN,,0,0,0,,There's another theme that we'll see illustrated by this example, Dialogue: 0,0:31:28.09,0:31:32.02,EN,,0,0,0,,and that's the issue of what Gerry and I have already mentioned a lot: Dialogue: 0,0:31:32.02,0:31:36.17,EN,,0,0,0,,that there's no real difference, in some sense, between procedures and data. Dialogue: 0,0:31:37.26,0:31:42.40,EN,,0,0,0,,And anyway I hope by the end of this morning, if you're not already, Dialogue: 0,0:31:42.58,0:31:47.60,EN,,0,0,0,,you will be completely confused about what the difference between procedures and data are, Dialogue: 0,0:31:47.96,0:31:49.58,EN,,0,0,0,,if you're not confused about that already. Dialogue: 0,0:31:50.80,0:31:55.28,EN,,0,0,0,,Well in any case, let's start describing Peter's language. Dialogue: 0,0:31:55.28,0:31:57.26,EN,,0,0,0,,I should start by telling you what the primitives are. Dialogue: 0,0:31:58.29,0:32:00.92,EN,,0,0,0,,This language is very simple because there's only one primitive. Dialogue: 0,0:32:03.33,0:32:06.30,EN,,0,0,0,,A primitive is not quite what you think it is. Dialogue: 0,0:32:07.08,0:32:09.18,EN,,0,0,0,,There's only one primitive called a picture, Dialogue: 0,0:32:09.70,0:32:12.11,EN,,0,0,0,,and a picture is not quite what you think it is. Dialogue: 0,0:32:12.11,0:32:14.17,EN,,0,0,0,,Here's an example. Dialogue: 0,0:32:14.17,0:32:15.17,EN,,0,0,0,,This is a picture of George. Dialogue: 0,0:32:19.01,0:32:20.37,EN,,0,0,0,,The idea is that Dialogue: 0,0:32:22.33,0:32:24.57,EN,,0,0,0,,a picture in this language is going to be something Dialogue: 0,0:32:24.89,0:32:31.46,EN,,0,0,0,,that draws a figure scaled to fit a rectangle that you specify. Dialogue: 0,0:32:33.00,0:32:34.42,EN,,0,0,0,,So here you see emphasis line Dialogue: 0,0:32:34.42,0:32:37.70,EN,,0,0,0,,is outline of a rectangle, that's not really part of the picture, Dialogue: 0,0:32:40.49,0:32:47.17,EN,,0,0,0,,but the picture-- you'll give it a rectangle, and it will draw this figure scaled to fit the rectangle. Dialogue: 0,0:32:47.17,0:32:52.16,EN,,0,0,0,,So for example, there's George, and here, this is also George. Dialogue: 0,0:32:53.21,0:32:56.65,EN,,0,0,0,,It's the same picture, right, just scaled to fit a different rectangle. Dialogue: 0,0:32:57.40,0:32:59.28,EN,,0,0,0,,Here's George as a fat kid. Dialogue: 0,0:33:00.01,0:33:03.44,EN,,0,0,0,,That's the same George. Dialogue: 0,0:33:03.81,0:33:05.14,EN,,0,0,0,,It's all the same figure. Dialogue: 0,0:33:05.14,0:33:09.57,EN,,0,0,0,,All of these three things are the same picture in this language. Dialogue: 0,0:33:09.58,0:33:13.04,EN,,0,0,0,,I'm just giving it different rectangles to scale itself in. Dialogue: 0,0:33:16.08,0:33:20.65,EN,,0,0,0,,OK, those are the primitives. That is the primitive. Dialogue: 0,0:33:21.44,0:33:25.25,EN,,0,0,0,,Now let's start talking about the means of combination and the operations. Dialogue: 0,0:33:25.90,0:33:30.17,EN,,0,0,0,,There is, for example, an operation called Rotate. Dialogue: 0,0:33:31.09,0:33:33.66,EN,,0,0,0,,And what Rotate does is, if I have a picture, Dialogue: 0,0:33:35.37,0:33:39.93,EN,,0,0,0,,say a picture that draws an "A" in some rectangle that I give it, Dialogue: 0,0:33:41.84,0:33:45.73,EN,,0,0,0,,the Rotate of that--say the Rotate by 90 degrees would, Dialogue: 0,0:33:47.02,0:33:50.65,EN,,0,0,0,,if I give it a rectangle, draw the same image, Dialogue: 0,0:33:50.65,0:33:53.88,EN,,0,0,0,,but again, scaled to fit that rectangle. Dialogue: 0,0:33:56.11,0:33:58.34,EN,,0,0,0,,So that's Rotate by 90 degrees. Dialogue: 0,0:33:58.34,0:34:03.20,EN,,0,0,0,,There's another operation called Flip that can flip something, either horizontally or vertically. Dialogue: 0,0:34:04.77,0:34:06.00,EN,,0,0,0,,All right, so those are, sort of, operations, Dialogue: 0,0:34:06.01,0:34:10.40,EN,,0,0,0,,or you can think of those as means of combination of one element. Dialogue: 0,0:34:10.89,0:34:12.42,EN,,0,0,0,,I can put things together. Dialogue: 0,0:34:13.44,0:34:15.54,EN,,0,0,0,,There's a means of combination called Beside, Dialogue: 0,0:34:16.46,0:34:24.78,EN,,0,0,0,,and what Beside does: it'll take two pictures, let's say A and B-- Dialogue: 0,0:34:29.02,0:34:33.25,EN,,0,0,0,,and by picture I mean something that's going to draw an image in a specified rectangle-- Dialogue: 0,0:34:34.05,0:34:36.51,EN,,0,0,0,,and what Beside will do-- Dialogue: 0,0:34:37.85,0:34:44.08,EN,,0,0,0,,I have to say, Beside of A and B, the side of two pictures and some number, s. Dialogue: 0,0:34:45.34,0:34:48.08,EN,,0,0,0,,And s will be a number between zero and one. Dialogue: 0,0:34:50.51,0:34:52.57,EN,,0,0,0,,And Beside will draw a picture that looks like this. Dialogue: 0,0:34:52.57,0:34:56.71,EN,,0,0,0,,It will take the rectangle you give it and scale its base by s. Dialogue: 0,0:34:56.71,0:34:58.71,EN,,0,0,0,,Say s is 0.5. Dialogue: 0,0:35:00.18,0:35:07.17,EN,,0,0,0,,And then over here it will draw-- it'll put the first picture, and over here it'll put the second picture. Dialogue: 0,0:35:07.81,0:35:12.65,EN,,0,0,0,,and over here it'll put the second picture. Dialogue: 0,0:35:13.82,0:35:16.44,EN,,0,0,0,,Or for instance if I gave it a different value of s, Dialogue: 0,0:35:16.81,0:35:23.02,EN,,0,0,0,,Or for instance if I gave it a different value of s, if I said Beside with a 0.25, Dialogue: 0,0:35:25.94,0:35:29.09,EN,,0,0,0,,it would do the same thing, except the A would be much skinnier. Dialogue: 0,0:35:34.05,0:35:36.28,EN,,0,0,0,,So it would draw something like that. Dialogue: 0,0:35:37.82,0:35:40.29,EN,,0,0,0,,So there's a means of combination Beside, Dialogue: 0,0:35:40.68,0:35:46.05,EN,,0,0,0,,and similarly there's an Above, which does the same thing except it puts them vertically instead of horizontally. Dialogue: 0,0:35:47.84,0:35:48.89,EN,,0,0,0,,Well let's look at that. Dialogue: 0,0:35:50.74,0:35:56.00,EN,,0,0,0,,All right, there's George and his kid brother, Dialogue: 0,0:35:56.72,0:36:07.05,EN,,0,0,0,,which is, right, constructed by taking George and putting him Beside Dialogue: 0,0:36:10.36,0:36:14.42,EN,,0,0,0,,The Above, taking the empty picture, and there's a thing called the empty picture, Dialogue: 0,0:36:14.52,0:36:16.14,EN,,0,0,0,,which does the obvious thing-- Dialogue: 0,0:36:16.14,0:36:19.14,EN,,0,0,0,,putting the empty picture above a copy of George, Dialogue: 0,0:36:19.14,0:36:21.14,EN,,0,0,0,,and then putting that whole thing Beside George. Dialogue: 0,0:36:28.96,0:36:30.34,EN,,0,0,0,,Here's something called P which is, Dialogue: 0,0:36:31.10,0:36:39.04,EN,,0,0,0,,which is, again, George Beside Flipping George, Dialogue: 0,0:36:40.53,0:36:42.08,EN,,0,0,0,,I think, horizontally in this case, Dialogue: 0,0:36:42.37,0:36:44.80,EN,,0,0,0,,Rotating the whole result 180 degrees Dialogue: 0,0:36:45.80,0:36:50.82,EN,,0,0,0,,putting them Beside one another with the basic rectangle divided at 0.5, Dialogue: 0,0:36:52.56,0:36:53.90,EN,,0,0,0,,right, and I can call that P. Dialogue: 0,0:36:55.90,0:36:57.88,EN,,0,0,0,,And then I can take P, Dialogue: 0,0:36:59.21,0:37:04.96,EN,,0,0,0,,And then I can take P, and put it above the Flipped copy of itself, and I can call that Q. Dialogue: 0,0:37:09.20,0:37:13.26,EN,,0,0,0,,Notice how rapidly that we've built up complexity, Dialogue: 0,0:37:14.36,0:37:21.05,EN,,0,0,0,,just in, you know, 15 seconds, you've gotten from George to that thing Q. Why is that? Dialogue: 0,0:37:22.05,0:37:24.55,EN,,0,0,0,,How are how we able to do that so fast? Dialogue: 0,0:37:25.85,0:37:28.02,EN,,0,0,0,,The answer is the closure property. Dialogue: 0,0:37:28.69,0:37:32.98,EN,,0,0,0,,See, it's the fact that when I take a picture and put it Beside another picture, Dialogue: 0,0:37:34.30,0:37:35.29,EN,,0,0,0,,that's then, again, a picture Dialogue: 0,0:37:35.33,0:37:37.78,EN,,0,0,0,,that I can go and Rotate and Flip or put Above something else. Dialogue: 0,0:37:39.17,0:37:40.88,EN,,0,0,0,,Right, and when I take that element P, Dialogue: 0,0:37:40.89,0:37:44.88,EN,,0,0,0,,which is the Beside or the Flip or the Rotate of something, that's, again, a picture. Dialogue: 0,0:37:45.22,0:37:50.20,EN,,0,0,0,,Right, the world of pictures is closed under those means of combination. Dialogue: 0,0:37:50.77,0:37:52.24,EN,,0,0,0,,So whenever I have something, Dialogue: 0,0:37:52.48,0:37:55.17,EN,,0,0,0,,I can turn right around and use that as an element in something else. Dialogue: 0,0:37:56.33,0:37:58.52,EN,,0,0,0,,So maybe better than List and segments, Dialogue: 0,0:37:58.54,0:38:03.28,EN,,0,0,0,,that just gives you an image for how fast you can build up complexity, because operations are closed. Dialogue: 0,0:38:07.48,0:38:12.02,EN,,0,0,0,,OK, well before we go on with building more things, Dialogue: 0,0:38:12.04,0:38:14.77,EN,,0,0,0,,let's talk about how this language is actually implemented. Dialogue: 0,0:38:16.91,0:38:21.50,EN,,0,0,0,,The basic element that sits under the table here Dialogue: 0,0:38:21.93,0:38:24.52,EN,,0,0,0,,is a thing called a rectangle, Dialogue: 0,0:38:26.09,0:38:28.28,EN,,0,0,0,,and what a rectangle is going to be, Dialogue: 0,0:38:28.28,0:38:33.68,EN,,0,0,0,,it's a thing that specified by an origin Dialogue: 0,0:38:36.45,0:38:40.18,EN,,0,0,0,,that's going to be some vector that says where the rectangle starts. Dialogue: 0,0:38:40.18,0:38:42.29,EN,,0,0,0,,And then there's going to be some other vector Dialogue: 0,0:38:43.66,0:38:46.33,EN,,0,0,0,,that I'm going to call the horizontal part of the rectangle, Dialogue: 0,0:38:55.76,0:38:59.25,EN,,0,0,0,,and another vector called the vertical part of the rectangle. Dialogue: 0,0:39:00.49,0:39:02.68,EN,,0,0,0,,And those three pieces are the elements: Dialogue: 0,0:39:02.68,0:39:04.51,EN,,0,0,0,,where the lower vertex is, Dialogue: 0,0:39:04.93,0:39:09.97,EN,,0,0,0,,how you get to the next vertex over here, and how you get to the vertex over there. Dialogue: 0,0:39:09.97,0:39:12.37,EN,,0,0,0,,The three vectors specify a rectangle. Dialogue: 0,0:39:16.00,0:39:18.93,EN,,0,0,0,,Now to actually build rectangles, what I'll assume is Dialogue: 0,0:39:19.77,0:39:22.06,EN,,0,0,0,,that we have a constructor called "make rectangle," Dialogue: 0,0:39:23.01,0:39:24.26,EN,,0,0,0,,or "make-rect," Dialogue: 0,0:39:27.56,0:39:35.17,EN,,0,0,0,,and selectors for horiz and vert and origin Dialogue: 0,0:39:37.58,0:39:39.65,EN,,0,0,0,,that get out the pieces of that rectangle. Dialogue: 0,0:39:39.65,0:39:42.54,EN,,0,0,0,,And well, you know a lot of ways you can do this now. Dialogue: 0,0:39:42.54,0:39:47.62,EN,,0,0,0,,You can do it by using pairs in some way or other standard List or not. Dialogue: 0,0:39:47.62,0:39:51.40,EN,,0,0,0,,But in any case, the implementation of these things, that's George's problem. Dialogue: 0,0:39:51.40,0:39:53.17,EN,,0,0,0,,It's just a data representation problem. Dialogue: 0,0:39:53.17,0:39:55.47,EN,,0,0,0,,So let's assume we have these rectangles to work with. Dialogue: 0,0:39:59.05,0:40:05.08,EN,,0,0,0,,OK. Now the idea of this, remember what's got to happen. Dialogue: 0,0:40:05.08,0:40:08.22,EN,,0,0,0,,Somehow we have to worry about taking the figure Dialogue: 0,0:40:09.33,0:40:12.97,EN,,0,0,0,,and scaling it to fit some rectangle that you give it, Dialogue: 0,0:40:13.60,0:40:16.60,EN,,0,0,0,,that's the basic thing you have to arrange, Dialogue: 0,0:40:16.60,0:40:18.60,EN,,0,0,0,,that these pictures can do. Dialogue: 0,0:40:22.22,0:40:23.65,EN,,0,0,0,,How do we think about that? Dialogue: 0,0:40:23.65,0:40:27.08,EN,,0,0,0,,Well, one way to think about that is that any time I give you a rectangle, Dialogue: 0,0:40:35.68,0:40:38.68,EN,,0,0,0,,Any time I gave you a rectangle, that defines, Dialogue: 0,0:40:39.25,0:40:45.77,EN,,0,0,0,,that defines,in some sense, a transformation from the standard square into that rectangle. Dialogue: 0,0:40:45.77,0:40:46.54,EN,,0,0,0,,Let me say what I mean. Dialogue: 0,0:40:46.54,0:40:48.53,EN,,0,0,0,,By the standard square, I'll mean something, Dialogue: 0,0:40:49.04,0:40:59.04,EN,,0,0,0,,which is a square whose coordinates are 0,0, and 1,0, and 0,1 and 1,1. Dialogue: 0,0:41:01.40,0:41:05.72,EN,,0,0,0,,And there's some sort of the obvious scaling transformation, Dialogue: 0,0:41:06.12,0:41:10.22,EN,,0,0,0,,which maps this to that and this to that, Dialogue: 0,0:41:10.24,0:41:12.08,EN,,0,0,0,,and sort of, stretches everything uniformly. Dialogue: 0,0:41:12.17,0:41:18.25,EN,,0,0,0,,So we take a line segment like this Dialogue: 0,0:41:19.73,0:41:24.20,EN,,0,0,0,,and end up mapping it to a line segment like that, Dialogue: 0,0:41:26.20,0:41:32.68,EN,,0,0,0,,so some point (x,y) goes to some other point up there. Dialogue: 0,0:41:32.68,0:41:39.37,EN,,0,0,0,,And although it's not important, with a little vector algebra, you could write that formula. Dialogue: 0,0:41:39.37,0:41:43.18,EN,,0,0,0,,The thing that (x,y) goes to, the point that (x,y) goes to is Dialogue: 0,0:41:43.58,0:41:50.74,EN,,0,0,0,,gotten by taking the origin of the rectangle and then adding that as a vector to-- Dialogue: 0,0:41:51.16,0:41:55.48,EN,,0,0,0,,well, take x, the x coordinate, which is something between zero and one, Dialogue: 0,0:41:55.98,0:42:01.84,EN,,0,0,0,,multiply that by the horizontal vector of the rectangle; Dialogue: 0,0:42:07.62,0:42:11.00,EN,,0,0,0,,and take the y coordinate, which is also something between zero and one Dialogue: 0,0:42:11.38,0:42:16.28,EN,,0,0,0,,and multiply that by the vertical vector of the rectangle. Dialogue: 0,0:42:16.74,0:42:19.31,EN,,0,0,0,,That's just a little linear algebra. Dialogue: 0,0:42:19.31,0:42:23.48,EN,,0,0,0,,Anyway, that's the formula, which is the right obvious transformation Dialogue: 0,0:42:23.69,0:42:28.18,EN,,0,0,0,,that takes things into the unit square, into the interior of that rectangle. Dialogue: 0,0:42:31.34,0:42:34.02,EN,,0,0,0,,OK well, let's actually look at that as a procedure. Dialogue: 0,0:42:35.16,0:42:36.29,EN,,0,0,0,,So what we want is Dialogue: 0,0:42:37.80,0:42:40.82,EN,,0,0,0,,the thing which tells us that particular transformation Dialogue: 0,0:42:41.01,0:42:42.52,EN,,0,0,0,,that a rectangle defines. Dialogue: 0,0:42:43.80,0:42:45.22,EN,,0,0,0,,So here's the procedure. Dialogue: 0,0:42:45.22,0:42:47.22,EN,,0,0,0,,I'll call it coordinate-map. Dialogue: 0,0:42:47.77,0:42:52.00,EN,,0,0,0,,Coordinate-map is the thing that takes as its argument a rectangle Dialogue: 0,0:42:53.60,0:42:57.85,EN,,0,0,0,,and returns for you a procedure on points. Dialogue: 0,0:43:00.45,0:43:06.82,EN,,0,0,0,,Right, so for each rectangle you get a way of transforming a point (x,y) into that rectangle. Dialogue: 0,0:43:06.82,0:43:08.02,EN,,0,0,0,,And how do you get it? Dialogue: 0,0:43:08.02,0:43:10.92,EN,,0,0,0,,Well I just-- writing in Lisp what I wrote there on the blackboard-- Dialogue: 0,0:43:10.92,0:43:16.01,EN,,0,0,0,,I add to the origin of the rectangle Dialogue: 0,0:43:20.22,0:43:25.02,EN,,0,0,0,,the result of adding-- I take the horizontal part of the rectangle; Dialogue: 0,0:43:25.02,0:43:27.68,EN,,0,0,0,,I scale that by the x coordinate of the point. Dialogue: 0,0:43:29.65,0:43:32.62,EN,,0,0,0,,I take the vertical vector of the rectangle. Dialogue: 0,0:43:33.51,0:43:37.14,EN,,0,0,0,,I scale that by the y coordinate of the point, Dialogue: 0,0:43:37.14,0:43:39.14,EN,,0,0,0,,and then add all those three things up. Dialogue: 0,0:43:40.13,0:43:41.34,EN,,0,0,0,,That's the procedure. Dialogue: 0,0:43:41.34,0:43:44.54,EN,,0,0,0,,That is the procedure that I'm going to apply to a point. Dialogue: 0,0:43:46.54,0:43:52.17,EN,,0,0,0,,And this whole thing is generated for each rectangle. Dialogue: 0,0:43:52.17,0:43:57.25,EN,,0,0,0,,So any rectangle defines a Coordinate-MAP, which is a procedure on points. Dialogue: 0,0:44:06.66,0:44:10.42,EN,,0,0,0,,All right, so for example, George here, Dialogue: 0,0:44:11.36,0:44:16.34,EN,,0,0,0,,my original George, might have been something that I specified by segments in the unit square, Dialogue: 0,0:44:19.50,0:44:21.96,EN,,0,0,0,,and then for each rectangle I give this thing, Dialogue: 0,0:44:24.14,0:44:28.17,EN,,0,0,0,,I'm going to draw those segments inside that rectangle. Dialogue: 0,0:44:28.17,0:44:29.88,EN,,0,0,0,,How actually do I do that? Dialogue: 0,0:44:30.68,0:44:36.94,EN,,0,0,0,,Well I take each segment in my original reference George that was specified, Dialogue: 0,0:44:38.64,0:44:40.58,EN,,0,0,0,,and to each of the end points of those segments, Dialogue: 0,0:44:40.88,0:44:44.45,EN,,0,0,0,,I applied the COORDINATE-MAP of the particular rectangle I want to draw it in. Dialogue: 0,0:44:44.45,0:44:46.06,EN,,0,0,0,,So for example, this lower rectangle, Dialogue: 0,0:44:46.66,0:44:50.88,EN,,0,0,0,,this George as a fat kid rectangle, has its COORDINATE-MAP. Dialogue: 0,0:44:51.25,0:44:53.69,EN,,0,0,0,,And if I want to draw this image, Dialogue: 0,0:44:55.38,0:44:57.92,EN,,0,0,0,,And if I want to draw this image, what I do is for each segment here, say for this segment, Dialogue: 0,0:44:59.29,0:45:05.34,EN,,0,0,0,,I transformed that point by the coordinate MAP, transform that point by the coordinate MAP. Dialogue: 0,0:45:05.34,0:45:07.09,EN,,0,0,0,,That will give me this point and that point Dialogue: 0,0:45:07.38,0:45:08.94,EN,,0,0,0,,and draw the segment between them. Dialogue: 0,0:45:09.71,0:45:11.52,EN,,0,0,0,,Right, that's the idea. Dialogue: 0,0:45:12.66,0:45:14.78,EN,,0,0,0,,Right, and if I give it a different rectangle like this one, Dialogue: 0,0:45:14.80,0:45:15.76,EN,,0,0,0,,that's a different coordinate-MAP, Dialogue: 0,0:45:15.79,0:45:17.84,EN,,0,0,0,,so I get a different image of those line segments. Dialogue: 0,0:45:19.28,0:45:22.14,EN,,0,0,0,,Well how do we actually get a picture to start with? Dialogue: 0,0:45:22.14,0:45:26.52,EN,,0,0,0,,I can build a picture to start with out of a List of line segments initially. Dialogue: 0,0:45:27.61,0:45:32.20,EN,,0,0,0,,Here's a procedure that builds what I'll call a primitive picture, Dialogue: 0,0:45:33.48,0:45:37.17,EN,,0,0,0,,meaning one I, sort of, got that didn't come out of Beside or Rotate or something. Dialogue: 0,0:45:37.52,0:45:39.60,EN,,0,0,0,,It starts with a List of line segments, Dialogue: 0,0:45:42.94,0:45:44.04,EN,,0,0,0,,And now it does what I said. Dialogue: 0,0:45:44.04,0:45:45.58,EN,,0,0,0,,What's a picture have to be? Dialogue: 0,0:45:45.58,0:45:49.44,EN,,0,0,0,,First of all it's a procedure that's defined on rectangles. Dialogue: 0,0:45:51.70,0:45:53.00,EN,,0,0,0,,What does it do? Dialogue: 0,0:45:53.00,0:45:56.56,EN,,0,0,0,,It says for each-- this is going to be a List of line segments-- Dialogue: 0,0:45:57.66,0:46:03.38,EN,,0,0,0,,for each segment, for each s, which is a segment in this List of segments, Dialogue: 0,0:46:05.89,0:46:07.30,EN,,0,0,0,,well it draws a line. Dialogue: 0,0:46:07.30,0:46:08.82,EN,,0,0,0,,What line does it draw? Dialogue: 0,0:46:10.60,0:46:12.84,EN,,0,0,0,,It gets the start point of that segment, Dialogue: 0,0:46:15.22,0:46:17.94,EN,,0,0,0,,transforms that by the coordinate MAP of the rectangle. Dialogue: 0,0:46:19.54,0:46:21.76,EN,,0,0,0,,That's the first new point it wants to do. Dialogue: 0,0:46:21.76,0:46:26.32,EN,,0,0,0,,Then it takes the endpoint of the segment, transforms that by the coordinate MAP of the rectangle, Dialogue: 0,0:46:26.69,0:46:27.92,EN,,0,0,0,,and then draws a line between. Dialogue: 0,0:46:27.92,0:46:30.84,EN,,0,0,0,,Let's assume drawline is some primitive that's built into the system Dialogue: 0,0:46:31.09,0:46:33.22,EN,,0,0,0,,that actually draws a line on the display. Dialogue: 0,0:46:33.96,0:46:37.10,EN,,0,0,0,,All right, so it transforms the endpoints by the coordinate MAP of the rectangle, Dialogue: 0,0:46:37.13,0:46:38.20,EN,,0,0,0,,draws a line between them, Dialogue: 0,0:46:39.61,0:46:44.12,EN,,0,0,0,,does that for each s in this List of segments. Dialogue: 0,0:46:45.96,0:46:51.40,EN,,0,0,0,,And now remember again, a picture is a procedure that takes a rectangle as argument. Dialogue: 0,0:46:51.40,0:46:55.65,EN,,0,0,0,,So when you hand it a rectangle, this is what it does: draws those lines. Dialogue: 0,0:46:57.17,0:47:01.10,EN,,0,0,0,,All right, so there's-- how would I actually use this thing? Dialogue: 0,0:47:01.22,0:47:04.08,EN,,0,0,0,,Let's make it a little bit more concrete. Dialogue: 0,0:47:05.60,0:47:24.22,EN,,0,0,0,,Right, I would say for instance, define R to be make-rectangle of some stuff, Dialogue: 0,0:47:24.50,0:47:28.66,EN,,0,0,0,,and I'd have to specify some vectors here using make-vector. Dialogue: 0,0:47:29.84,0:47:46.18,EN,,0,0,0,,And then I could say, define say, G to be make-picture, and then some stuff. Dialogue: 0,0:47:46.68,0:47:55.28,EN,,0,0,0,,And what I'd have to specify here is a List of line segments, right, using make segment. Dialogue: 0,0:47:55.28,0:47:58.70,EN,,0,0,0,,Make-segment might be made out of vectors, and vectors might be made out of points. Dialogue: 0,0:47:59.50,0:48:04.60,EN,,0,0,0,,And then if I actually wanted to see the image of G inside a rectangle, Dialogue: 0,0:48:04.65,0:48:11.72,EN,,0,0,0,,well a picture is a procedure that takes a rectangle as argument. Dialogue: 0,0:48:12.06,0:48:16.37,EN,,0,0,0,,So if I then called G with an input of R, Dialogue: 0,0:48:17.96,0:48:23.25,EN,,0,0,0,,that would cause whatever image G is worrying about to be drawn inside the rectangle R. Dialogue: 0,0:48:23.62,0:48:25.62,EN,,0,0,0,,Right, so that's how you'd use that. Dialogue: 0,0:48:26.86,0:48:36.29,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:48:36.29,0:48:39.78,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:48:39.82,0:48:43.54,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:48:51.28,0:48:55.45,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:48:55.50,0:48:58.73,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:48:59.34,0:49:03.02,Declare,,0,0,0,,{\an2\fad(500,500)}Henderson Escher Example Dialogue: 0,0:49:07.72,0:49:12.48,EN,,0,0,0,,PROFESSOR: Well why is it that I say this example is nice? Dialogue: 0,0:49:12.48,0:49:13.74,EN,,0,0,0,,You probably don't think it's nice. Dialogue: 0,0:49:13.74,0:49:15.42,EN,,0,0,0,,You probably think it's more weird than nice. Dialogue: 0,0:49:15.42,0:49:20.92,EN,,0,0,0,,Right, representing these pictures as procedures, which do complicated things with rectangles. Dialogue: 0,0:49:20.92,0:49:22.72,EN,,0,0,0,,So why is it nice? Dialogue: 0,0:49:25.36,0:49:26.69,EN,,0,0,0,,The reason it's nice Dialogue: 0,0:49:27.22,0:49:30.40,EN,,0,0,0,,is that once you've implemented the primitives in this way, Dialogue: 0,0:49:30.97,0:49:35.20,EN,,0,0,0,,the means of combination just fall out by implementing procedures. Dialogue: 0,0:49:35.98,0:49:37.48,EN,,0,0,0,,Let me show you what I mean. Dialogue: 0,0:49:37.48,0:49:39.02,EN,,0,0,0,,Suppose we want to implement Beside. Dialogue: 0,0:49:41.56,0:49:47.36,EN,,0,0,0,,So I'd like to-- suppose I've got a picture. Let's call it P1. Dialogue: 0,0:49:47.36,0:49:50.62,EN,,0,0,0,,P1 is going to be-- and now remember what a picture really is. Dialogue: 0,0:49:50.62,0:49:54.82,EN,,0,0,0,,It's a thing that if you hand it some rectangle, Dialogue: 0,0:49:56.52,0:50:01.46,EN,,0,0,0,,it will cause an image to be drawn in whatever rectangle you hand it. Dialogue: 0,0:50:03.46,0:50:09.26,EN,,0,0,0,,And suppose P2 two is some other picture, and you hand that a rectangle. Dialogue: 0,0:50:09.74,0:50:12.44,EN,,0,0,0,,And whatever rectangle you hand it, it draws some picture. Dialogue: 0,0:50:14.84,0:50:26.60,EN,,0,0,0,,And now if I'd like to implement Beside of P1 and P2 with a scale factor A, Dialogue: 0,0:50:27.04,0:50:28.38,EN,,0,0,0,,well what does that have to be? Dialogue: 0,0:50:28.38,0:50:29.34,EN,,0,0,0,,That's gotta be a picture. Dialogue: 0,0:50:29.92,0:50:33.88,EN,,0,0,0,,It's gotta be a thing that you handed a rectangle and draw something in that rectangle. Dialogue: 0,0:50:34.77,0:50:37.18,EN,,0,0,0,,So if hand Beside this rectangle-- Dialogue: 0,0:50:38.58,0:50:40.12,EN,,0,0,0,,let's hand it a rectangle. Dialogue: 0,0:50:41.50,0:50:42.74,EN,,0,0,0,,Well what's it going to do? Dialogue: 0,0:50:42.76,0:50:46.36,EN,,0,0,0,,It's going to take this rectangle and split it into two Dialogue: 0,0:50:49.29,0:50:51.57,EN,,0,0,0,,at a ratio of A and one minus A. Dialogue: 0,0:50:52.65,0:50:55.12,EN,,0,0,0,,And it will say, oh sure, now I've got two rectangles. Dialogue: 0,0:51:02.34,0:51:06.54,EN,,0,0,0,,And now it goes off to P1 and says P1, well draw yourself in this rectangle, Dialogue: 0,0:51:07.36,0:51:11.64,EN,,0,0,0,,and goes off to P2, and says, P2, fine, draw yourself in this rectangle. Dialogue: 0,0:51:13.28,0:51:16.88,EN,,0,0,0,,The only computation it has to do is figure out what these rectangles are. Dialogue: 0,0:51:17.36,0:51:23.97,EN,,0,0,0,,Remember a rectangle is specified by an origin and a horizontal vector and a vertical vector. Dialogue: 0,0:51:23.98,0:51:25.94,EN,,0,0,0,,so it's got to figure out what these things are. Dialogue: 0,0:51:27.37,0:51:32.29,EN,,0,0,0,,So for this first rectangle, the origin turns out to be the origin of the original rectangle, Dialogue: 0,0:51:33.64,0:51:37.80,EN,,0,0,0,,and the vertical vector is the same as the vertical vector of the original rectangle. Dialogue: 0,0:51:38.89,0:51:46.60,EN,,0,0,0,,The horizontal vector is the horizontal vector of the original rectangle scaled by A. Dialogue: 0,0:51:47.49,0:51:48.90,EN,,0,0,0,,And that's the first rectangle. Dialogue: 0,0:51:49.46,0:51:52.69,EN,,0,0,0,,The second rectangle, the origin Dialogue: 0,0:51:54.06,0:51:59.65,EN,,0,0,0,,The second rectangle, the origin is the original origin plus that horizontal vector scaled by A. Dialogue: 0,0:52:01.20,0:52:03.40,EN,,0,0,0,,The horizontal vector of the second rectangle is Dialogue: 0,0:52:03.77,0:52:06.04,EN,,0,0,0,,the rest of the horizontal vector of the first one, Dialogue: 0,0:52:06.34,0:52:11.66,EN,,0,0,0,,which is 1 minus A times the original H, Dialogue: 0,0:52:12.05,0:52:13.77,EN,,0,0,0,,and the vertical vector is still v. Dialogue: 0,0:52:15.48,0:52:17.98,EN,,0,0,0,,But basically it goes and constructs these two rectangles, Dialogue: 0,0:52:18.00,0:52:20.57,EN,,0,0,0,,and the important point is having constructed the rectangles, Dialogue: 0,0:52:20.93,0:52:24.58,EN,,0,0,0,,it says OK, p1, you draw yourself in there, and p2, you draw yourself in there, Dialogue: 0,0:52:24.62,0:52:26.18,EN,,0,0,0,,and that's all Beside has to do. Dialogue: 0,0:52:27.80,0:52:29.30,EN,,0,0,0,,All right, let's look at that piece of code. Dialogue: 0,0:52:34.33,0:52:35.13,EN,,0,0,0,,Beside Dialogue: 0,0:52:39.64,0:52:46.44,EN,,0,0,0,,Beside of a picture and another picture with some scaling ratio Dialogue: 0,0:52:47.84,0:52:53.64,EN,,0,0,0,,is first of all, since it's a picture, a procedure that's going to take a rectangle as argument. Dialogue: 0,0:52:55.49,0:52:56.56,EN,,0,0,0,,What's it going to do? Dialogue: 0,0:52:56.76,0:53:02.32,EN,,0,0,0,,It says, p1 draw yourself in some rectangle and p2 draw yourself in some other rectangle. Dialogue: 0,0:53:03.21,0:53:04.46,EN,,0,0,0,,And now what are those rectangles? Dialogue: 0,0:53:04.46,0:53:05.48,EN,,0,0,0,,Well here's the computation. Dialogue: 0,0:53:05.48,0:53:06.54,EN,,0,0,0,,It makes a rectangle, Dialogue: 0,0:53:07.52,0:53:10.40,EN,,0,0,0,,and this is the algebra I just did on the board: the origin, something; Dialogue: 0,0:53:10.40,0:53:11.84,EN,,0,0,0,,the horizontal vector, something; Dialogue: 0,0:53:11.84,0:53:13.44,EN,,0,0,0,,and the vertical vector, something. Dialogue: 0,0:53:13.97,0:53:14.81,EN,,0,0,0,,For p2 Dialogue: 0,0:53:15.50,0:53:19.78,EN,,0,0,0,,And for p2, the rectangle it wants has some other origin and horizontal vector and vertical vector. Dialogue: 0,0:53:19.78,0:53:20.70,EN,,0,0,0,,But the important point Dialogue: 0,0:53:21.21,0:53:27.18,EN,,0,0,0,,is that all it's saying is, p1, go do your thing in one rectangle, and p2, go do your thing in another rectangle. Dialogue: 0,0:53:27.74,0:53:29.42,EN,,0,0,0,,That's all the Beside has to do. Dialogue: 0,0:53:30.84,0:53:35.62,EN,,0,0,0,,OK, similarly Rotate-- Dialogue: 0,0:53:36.96,0:53:42.00,EN,,0,0,0,,see if I have this picture A, Dialogue: 0,0:53:42.97,0:53:46.12,EN,,0,0,0,,and I want to look at say rotating A by 90 degrees, Dialogue: 0,0:53:46.37,0:53:51.92,EN,,0,0,0,,what that should mean is, well take this rectangle, Dialogue: 0,0:53:53.94,0:53:58.44,EN,,0,0,0,,which is origin and horizontal vector and vertical vector, Dialogue: 0,0:53:58.78,0:54:03.18,EN,,0,0,0,,and now pretend that it's really the rectangle that looks like this, Dialogue: 0,0:54:03.74,0:54:09.12,EN,,0,0,0,,which has an origin and a horizontal vector up here, and a vertical vector there, Dialogue: 0,0:54:09.60,0:54:12.46,EN,,0,0,0,,and now draw yourself with respect to that rectangle. Dialogue: 0,0:54:13.26,0:54:15.04,EN,,0,0,0,,Let me show you that as a procedure. Dialogue: 0,0:54:17.02,0:54:19.85,EN,,0,0,0,,All right, so we'll Rotate 90 of the picture, Dialogue: 0,0:54:20.61,0:54:22.96,EN,,0,0,0,,because again, a procedure for rectangle, Dialogue: 0,0:54:23.25,0:54:26.12,EN,,0,0,0,,which says, OK picture, draw yourself in some rectangle; Dialogue: 0,0:54:27.21,0:54:30.66,EN,,0,0,0,,and then this algebra is the transformation on the rectangle. Dialogue: 0,0:54:30.66,0:54:33.84,EN,,0,0,0,,It's the one which makes it look like the rectangle is sideways, Dialogue: 0,0:54:33.86,0:54:36.52,EN,,0,0,0,,the origin is someplace else and the vertical vector is someplace else, Dialogue: 0,0:54:37.13,0:54:39.74,EN,,0,0,0,,and the horizontal vector is someplace else, and vertical vector is someplace else. Dialogue: 0,0:54:46.76,0:54:49.90,EN,,0,0,0,,OK, again notice, the crucial thing that's going on here Dialogue: 0,0:54:50.53,0:55:00.97,EN,,0,0,0,,is you're using the representation of pictures as procedures to automatically get the closure property, Dialogue: 0,0:55:01.74,0:55:05.22,EN,,0,0,0,,because what happens is, Beside just has this thing p1. Dialogue: 0,0:55:05.22,0:55:09.40,EN,,0,0,0,,Beside doesn't care if that's a primitive picture or it's line segments Dialogue: 0,0:55:09.61,0:55:12.69,EN,,0,0,0,,if p1 is, itself, the result of doing Aboves or Besides or Rotates. Dialogue: 0,0:55:12.72,0:55:16.08,EN,,0,0,0,,All Beside has to know about, say, p1 Dialogue: 0,0:55:16.29,0:55:19.73,EN,,0,0,0,,p1 is that if you hand p1 a rectangle, it will cause something to be drawn. Dialogue: 0,0:55:21.04,0:55:25.98,EN,,0,0,0,,And above that level, Beside just doesn't-- it's none of its business how p1 accomplishes that drawing. Dialogue: 0,0:55:27.73,0:55:32.25,EN,,0,0,0,,All right, so you're using the procedural representation to ensure this closure. Dialogue: 0,0:55:35.64,0:55:40.81,EN,,0,0,0,,So implementing pictures as procedures makes these means of combination, Dialogue: 0,0:55:41.18,0:55:43.93,EN,,0,0,0,,both pretty simple and also, I think, elegant. Dialogue: 0,0:55:45.92,0:55:48.22,EN,,0,0,0,,But that's not the real punchline. Dialogue: 0,0:55:49.28,0:55:53.52,EN,,0,0,0,,The real punchline comes when you look at the means of abstraction in this language. Dialogue: 0,0:55:54.70,0:55:56.24,EN,,0,0,0,,Because what have we done? Dialogue: 0,0:55:56.24,0:56:03.72,EN,,0,0,0,,We've implemented the means of combination themselves as procedures. Dialogue: 0,0:56:05.85,0:56:09.38,EN,,0,0,0,,And what that means is that when we go to abstract in this language, Dialogue: 0,0:56:10.17,0:56:15.69,EN,,0,0,0,,everything that Lisp supplies us for manipulating procedures Dialogue: 0,0:56:16.33,0:56:21.45,EN,,0,0,0,,automatically available to do things in this picture language. Dialogue: 0,0:56:21.92,0:56:29.74,EN,,0,0,0,,The technical term I want to say is not only is this language implemented in Lisp, obviously it is, Dialogue: 0,0:56:29.76,0:56:32.58,EN,,0,0,0,,but the language is nicely embedded in Lisp. Dialogue: 0,0:56:37.64,0:56:42.08,EN,,0,0,0,,What I mean is by embedding the language in this way, Dialogue: 0,0:56:42.90,0:56:48.86,EN,,0,0,0,,all the power of Lisp is automatically available as an extension to whatever you want to do. Dialogue: 0,0:56:50.06,0:56:51.68,EN,,0,0,0,,And what do I mean by that? Dialogue: 0,0:56:51.97,0:57:02.94,EN,,0,0,0,,Example: say, suppose I want to make a thing that takes four pictures A, B, C and D, Dialogue: 0,0:57:03.76,0:57:07.06,EN,,0,0,0,,and makes a configuration that looks like this. Dialogue: 0,0:57:12.50,0:57:16.96,EN,,0,0,0,,Well you might call that, you know, four pictures or something, four-pict configuration. Dialogue: 0,0:57:16.96,0:57:17.70,EN,,0,0,0,,How do I do that? Dialogue: 0,0:57:17.70,0:57:18.68,EN,,0,0,0,,Well I can obviously do that. Dialogue: 0,0:57:18.68,0:57:23.33,EN,,0,0,0,,I just write a procedure that takes B above D Dialogue: 0,0:57:24.13,0:57:25.85,EN,,0,0,0,,and A above C Dialogue: 0,0:57:26.09,0:57:27.70,EN,,0,0,0,,and puts those things beside each other. Dialogue: 0,0:57:28.24,0:57:31.82,EN,,0,0,0,,So I automatically have Lisp's ability to do procedure composition. Dialogue: 0,0:57:32.92,0:57:35.82,EN,,0,0,0,,And I didn't have to make that specifically in the picture language. Dialogue: 0,0:57:35.82,0:57:39.92,EN,,0,0,0,,It's automatic from the fact that the means of combination are themselves procedures. Dialogue: 0,0:57:40.96,0:57:44.18,EN,,0,0,0,,Or suppose I wanted to do something a little bit more complicated. Dialogue: 0,0:57:44.18,0:57:46.50,EN,,0,0,0,,I wanted to put in a parameter so that for each of these, Dialogue: 0,0:57:46.52,0:57:50.08,EN,,0,0,0,,I could independently specify a rotation by 90 degrees. Dialogue: 0,0:57:50.41,0:57:52.64,EN,,0,0,0,,That's just putting a parameter in the procedure. Dialogue: 0,0:57:53.17,0:57:54.56,EN,,0,0,0,,It's automatically there. Dialogue: 0,0:57:54.80,0:57:57.84,EN,,0,0,0,,Right, it automatically comes from the embedding. Dialogue: 0,0:57:58.16,0:58:05.36,EN,,0,0,0,,Or even more, suppose I wanted to, you know, use recursion. Dialogue: 0,0:58:06.16,0:58:10.78,EN,,0,0,0,,Let's look at a recursive means of combination on pictures. Dialogue: 0,0:58:10.78,0:58:14.64,EN,,0,0,0,,I could say define-- let's see if you can figure out what this one is-- Dialogue: 0,0:58:14.69,0:58:18.97,EN,,0,0,0,,suppose I say define what it means to right-push a picture, Dialogue: 0,0:58:22.84,0:58:29.80,EN,,0,0,0,,right-push a picture and some integer N and some scale factor A. Dialogue: 0,0:58:31.46,0:58:41.22,EN,,0,0,0,,I'll define this to say if N equals 0, then the answer is the picture. Dialogue: 0,0:58:42.20,0:58:54.02,EN,,0,0,0,,Otherwise I'm going to put-- oops, name change: P. Dialogue: 0,0:58:55.88,0:59:00.21,EN,,0,0,0,,Otherwise, I'm going to take P and put it beside Dialogue: 0,0:59:00.92,0:59:18.30,EN,,0,0,0,,the results of recursively right-pushing P with N minus 1 and A and use a scale factor of A. OK, Dialogue: 0,0:59:24.72,0:59:31.12,EN,,0,0,0,,so if N 0 , it's P. Otherwise I put P with a scale factor of A-- Dialogue: 0,0:59:31.12,0:59:32.80,EN,,0,0,0,,I'm sorry I didn't align this right-- Dialogue: 0,0:59:33.66,0:59:38.50,EN,,0,0,0,,recursively beside the result of right-pushing P, N minus 1 times with a scale factor of A. Dialogue: 0,0:59:38.50,0:59:42.00,EN,,0,0,0,,There's a recursive means of combination. Dialogue: 0,0:59:43.78,0:59:44.76,EN,,0,0,0,,What's that look like? Dialogue: 0,0:59:44.76,0:59:45.90,EN,,0,0,0,,Well, here's what it looks like. Dialogue: 0,0:59:46.04,0:59:56.04,EN,,0,0,0,,There's George right-pushed against himself twice with a scale factor of 0.75. Dialogue: 0,0:59:59.26,1:00:00.72,EN,,0,0,0,,Where'd that come from? Dialogue: 0,1:00:00.72,1:00:02.34,EN,,0,0,0,,How did I get all this fancy recursion? Dialogue: 0,1:00:02.34,1:00:05.24,EN,,0,0,0,,And the answer is just automatic, absolutely automatic. Dialogue: 0,1:00:05.24,1:00:09.80,EN,,0,0,0,,Since these are procedures, the embedding says, well sure, I can define recursive procedures. Dialogue: 0,1:00:10.36,1:00:11.68,EN,,0,0,0,,I didn't have to arrange that. Dialogue: 0,1:00:13.56,1:00:16.42,EN,,0,0,0,,And of course, we can do more complicated things of the same sort. Dialogue: 0,1:00:16.42,1:00:18.21,EN,,0,0,0,,I could make something that does an up-push. Dialogue: 0,1:00:18.42,1:00:22.60,EN,,0,0,0,,Right, that sort of goes like this, by recursively putting something above. Dialogue: 0,1:00:22.60,1:00:26.54,EN,,0,0,0,,Or I could make something that, sort of, was this scheme. Dialogue: 0,1:00:26.56,1:00:28.85,EN,,0,0,0,,I might start out with a picture Dialogue: 0,1:00:29.78,1:00:37.16,EN,,0,0,0,,and then, sort of, recursively both push it aside and above Dialogue: 0,1:00:37.57,1:00:38.92,EN,,0,0,0,,and that might put something there. Dialogue: 0,1:00:39.52,1:00:41.82,EN,,0,0,0,,And then up here I put the same recursive thing, Dialogue: 0,1:00:42.36,1:00:44.20,EN,,0,0,0,,and I might end up with something like this. Dialogue: 0,1:00:45.40,1:00:52.50,EN,,0,0,0,,Right, so there's a procedure that's a little bit more complicated than right-push but not much. Dialogue: 0,1:00:53.64,1:00:58.14,EN,,0,0,0,,I just do an Above and a Beside, rather than just a Beside. Dialogue: 0,1:01:01.12,1:01:06.78,EN,,0,0,0,,Now if I take that and apply that with the idea of putting four pictures together, Dialogue: 0,1:01:07.53,1:01:08.65,EN,,0,0,0,,which I can surely do; Dialogue: 0,1:01:09.01,1:01:14.17,EN,,0,0,0,,and I go and I apply that to Q, which we defined before, right, Dialogue: 0,1:01:15.97,1:01:18.73,EN,,0,0,0,,what I end up with this is this thing, Dialogue: 0,1:01:20.14,1:01:25.26,EN,,0,0,0,,which is, sort of, the square limit of Q, done twice. Dialogue: 0,1:01:28.18,1:01:32.25,EN,,0,0,0,,Right, and then we can compare that with Escher's "Square Limit." Dialogue: 0,1:01:32.88,1:01:34.53,EN,,0,0,0,,And you see, it's sort of the same idea. Dialogue: 0,1:01:34.74,1:01:36.94,EN,,0,0,0,,Escher's is, of course, much, much prettier. Dialogue: 0,1:01:36.94,1:01:44.04,EN,,0,0,0,,If we go back and look at George, right, if we go look at George here-- Dialogue: 0,1:01:44.38,1:01:47.37,EN,,0,0,0,,see, I started with a fairly arbitrary design Dialogue: 0,1:01:47.42,1:01:49.26,EN,,0,0,0,,this picture of George and did things with it. Dialogue: 0,1:01:51.22,1:01:53.14,EN,,0,0,0,,Right, whereas if we go look at the Escher picture, right, Dialogue: 0,1:01:54.08,1:01:56.14,EN,,0,0,0,,the Escher picture is not an arbitrary design. Dialogue: 0,1:01:56.14,1:01:57.66,EN,,0,0,0,,It's this very, very clever thing, Dialogue: 0,1:01:57.89,1:02:00.20,EN,,0,0,0,,so that when you take this fish body Dialogue: 0,1:02:01.82,1:02:04.97,EN,,0,0,0,,and Rotate it and shrink it down, it bleeds into the next one really nicely. Dialogue: 0,1:02:07.40,1:02:11.48,EN,,0,0,0,,And of course with George, I didn't really do anything like that. Dialogue: 0,1:02:12.12,1:02:13.90,EN,,0,0,0,,So if we look at George, Dialogue: 0,1:02:15.41,1:02:18.64,EN,,0,0,0,,right, there's a little bit of match up, but not very nice, and it's pretty arbitrary. Dialogue: 0,1:02:18.64,1:02:21.53,EN,,0,0,0,,One very nice project, by the way, Dialogue: 0,1:02:22.30,1:02:27.54,EN,,0,0,0,,would be to write a procedure that could take some basic figure like this George thing Dialogue: 0,1:02:27.86,1:02:29.62,EN,,0,0,0,,and start moving the ends of the lines around, Dialogue: 0,1:02:29.86,1:02:31.20,EN,,0,0,0,,so you got a really nice one Dialogue: 0,1:02:32.13,1:02:34.06,EN,,0,0,0,,when you went and did that "Square Limit" process. Dialogue: 0,1:02:34.68,1:02:36.30,EN,,0,0,0,,That'd be a really nice thing to think about. Dialogue: 0,1:02:38.08,1:02:39.72,EN,,0,0,0,,Well so, we can combine things. Dialogue: 0,1:02:39.72,1:02:41.04,EN,,0,0,0,,We can recursive procedures. Dialogue: 0,1:02:41.04,1:02:43.48,EN,,0,0,0,,We can do all kinds of things, and that's all automatic. Dialogue: 0,1:02:44.60,1:02:48.52,EN,,0,0,0,,Right, the important point, the difference between merely implementing something in a language Dialogue: 0,1:02:48.69,1:02:50.44,EN,,0,0,0,,and embedding something in the language, Dialogue: 0,1:02:50.44,1:02:53.72,EN,,0,0,0,,so that you don't lose the original power of the language, and what Lisp is great at, Dialogue: 0,1:02:54.76,1:02:57.62,EN,,0,0,0,,see Lisp is a lousy language for doing any particular problem. Dialogue: 0,1:02:57.62,1:03:02.10,EN,,0,0,0,,What it's good for is figuring out the right language that you want and embedding that in Lisp. Dialogue: 0,1:03:02.10,1:03:05.44,EN,,0,0,0,,That's the real power of this approach to design. Dialogue: 0,1:03:05.69,1:03:06.82,EN,,0,0,0,,Of course, we can go further. Dialogue: 0,1:03:06.82,1:03:08.81,EN,,0,0,0,,See, you saw the other thing that we can do in Lisp Dialogue: 0,1:03:09.21,1:03:17.52,EN,,0,0,0,,is capture general methods of doing things as higher order procedures. Dialogue: 0,1:03:19.09,1:03:22.57,EN,,0,0,0,,And you probably just from me drawing it got the idea that right-push Dialogue: 0,1:03:23.78,1:03:26.61,EN,,0,0,0,,and the analogous thing where you push something up and up and up and up Dialogue: 0,1:03:26.93,1:03:33.82,EN,,0,0,0,,and this corner push thing are all generalizations of a common kind of idea. Dialogue: 0,1:03:34.72,1:03:37.20,EN,,0,0,0,,So just to illustrate and give you practice in looking at a Dialogue: 0,1:03:37.98,1:03:40.65,EN,,0,0,0,,at a fairly convoluted use of higher order procedures, Dialogue: 0,1:03:41.12,1:03:47.24,EN,,0,0,0,,let me show you the general idea of pushing some means of combination to recursively repeat it. Dialogue: 0,1:03:48.30,1:03:50.70,EN,,0,0,0,,So here's a good one to puzzle out. Dialogue: 0,1:03:51.22,1:04:00.70,EN,,0,0,0,,We'll define it what it means to push using a means of combination. Dialogue: 0,1:04:01.49,1:04:04.88,EN,,0,0,0,,Comb is going to be something like the Beside or Above. Dialogue: 0,1:04:06.18,1:04:07.06,EN,,0,0,0,,Well what's that going to be. Dialogue: 0,1:04:07.06,1:04:12.06,EN,,0,0,0,,That's going to be a procedure, remember what Beside actually was, right. Dialogue: 0,1:04:13.22,1:04:15.18,EN,,0,0,0,,It took a picture, Dialogue: 0,1:04:15.96,1:04:18.08,EN,,0,0,0,,took two pictures and a scale factor. Dialogue: 0,1:04:18.62,1:04:24.28,EN,,0,0,0,,Using that I produced something that took a level number and a picture and a scale factor, Dialogue: 0,1:04:24.28,1:04:25.45,EN,,0,0,0,,that I called right-push. Dialogue: 0,1:04:26.16,1:04:33.66,EN,,0,0,0,,So this is going to be something that takes a picture, a level number and a scale factor, and it's going to say-- Dialogue: 0,1:04:36.16,1:04:39.12,EN,,0,0,0,,I'm going to do some repeated operation. Dialogue: 0,1:04:39.45,1:04:46.62,EN,,0,0,0,,I'm going to repeatedly apply the procedure which takes a picture Dialogue: 0,1:04:48.40,1:04:50.69,EN,,0,0,0,,and applies the means of combination Dialogue: 0,1:04:51.20,1:04:59.08,EN,,0,0,0,,to the picture and the original picture and the one I took in here and the scale factor, Dialogue: 0,1:05:02.26,1:05:07.28,EN,,0,0,0,,and I do the thing which repeats this procedure N times, Dialogue: 0,1:05:12.04,1:05:16.20,EN,,0,0,0,,and I apply that whole thing to my original picture. Dialogue: 0,1:05:19.56,1:05:24.48,EN,,0,0,0,,Repeated here, in case you haven't seen it, is another higher order procedure Dialogue: 0,1:05:24.53,1:05:28.34,EN,,0,0,0,,that takes a procedure and a number Dialogue: 0,1:05:29.54,1:05:34.29,EN,,0,0,0,,and returns for you another procedure that applies this procedure N times. Dialogue: 0,1:05:36.04,1:05:39.30,EN,,0,0,0,,And I think some of you have already written repeated as an exercise, Dialogue: 0,1:05:39.70,1:05:43.01,EN,,0,0,0,,but if you haven't, it's a very good exercise in thinking about higher order procedures. Dialogue: 0,1:05:43.84,1:05:46.90,EN,,0,0,0,,But in any case, the result of this repeated is what I apply to picture. Dialogue: 0,1:05:49.46,1:05:52.38,EN,,0,0,0,,And having done that, that's going to capture the -- Dialogue: 0,1:05:53.12,1:05:57.73,EN,,0,0,0,,that is the thing, the way I got from the idea of Beside to the idea of right-push Dialogue: 0,1:05:59.01,1:06:13.17,EN,,0,0,0,,So having done that, I could say define right-push to be push of Beside. Dialogue: 0,1:06:17.65,1:06:20.32,EN,,0,0,0,,Or if I say, define up-push to be push of Above Dialogue: 0,1:06:20.34,1:06:25.48,EN,,0,0,0,,I'd get the analogous thing or define corner-push to be push of some appropriate thing that did both the Beside and Above, Dialogue: 0,1:06:25.49,1:06:26.70,EN,,0,0,0,,or I could push anything. Dialogue: 0,1:06:28.26,1:06:34.76,EN,,0,0,0,,Anyway this is, if you're having trouble with lambdas, this is an excellent exercise in figuring out what this means. Dialogue: 0,1:06:38.98,1:06:41.00,EN,,0,0,0,,OK, well there's a lot to learn from this example. Dialogue: 0,1:06:42.18,1:06:49.80,EN,,0,0,0,,The main point I've been welling on is the notion of nicely embedding a language inside another language. Dialogue: 0,1:06:50.66,1:06:55.62,EN,,0,0,0,,Right, so that all the power of this language like Lisp of the surrounding language Dialogue: 0,1:06:55.92,1:07:00.28,EN,,0,0,0,,is still accessible to you and appears as a natural extension of the language that you built. Dialogue: 0,1:07:00.98,1:07:04.00,EN,,0,0,0,,That's one thing that this example shows very well. Dialogue: 0,1:07:08.14,1:07:10.94,EN,,0,0,0,,Another thing is, if you go back and think about that, Dialogue: 0,1:07:10.94,1:07:12.28,EN,,0,0,0,,what's procedures and what's data. Dialogue: 0,1:07:12.28,1:07:16.20,EN,,0,0,0,,You know, by the time we get up to here, my God, what's going on. Dialogue: 0,1:07:16.20,1:07:19.66,EN,,0,0,0,,I mean, this is some procedure, and it takes a picture and an argument, Dialogue: 0,1:07:19.66,1:07:20.36,EN,,0,0,0,,and what's a picture. Dialogue: 0,1:07:20.36,1:07:23.82,EN,,0,0,0,,Well, a picture itself, as you remember, was a procedure, and that took a rectangle. Dialogue: 0,1:07:23.82,1:07:25.82,EN,,0,0,0,,And a rectangle is some abstraction. Dialogue: 0,1:07:26.09,1:07:28.13,EN,,0,0,0,,And I hope now that by now you're completely lost Dialogue: 0,1:07:29.14,1:07:33.74,EN,,0,0,0,,as to the question of what in the system is procedure and what's data. Dialogue: 0,1:07:33.74,1:07:34.78,EN,,0,0,0,,You see, there isn't any difference. Dialogue: 0,1:07:35.49,1:07:36.44,EN,,0,0,0,,There really isn't. Dialogue: 0,1:07:37.93,1:07:41.42,EN,,0,0,0,,And you might think of a picture sometimes as a procedure and sometimes as data, Dialogue: 0,1:07:41.84,1:07:44.90,EN,,0,0,0,,but that's just, sort of, you know, making you feel comfortable. Dialogue: 0,1:07:44.90,1:07:47.30,EN,,0,0,0,,It's really both in some sense or neither in some sense. Dialogue: 0,1:07:49.92,1:08:02.20,EN,,0,0,0,,OK, there's a more general point about the structure of the system as creating a language, Dialogue: 0,1:08:02.52,1:08:06.74,EN,,0,0,0,,viewing the engineering design process as one of creating language or Dialogue: 0,1:08:07.84,1:08:13.97,EN,,0,0,0,,or rather one of creating a sort of sequence of layers of language. Dialogue: 0,1:08:14.77,1:08:20.01,EN,,0,0,0,,You see, there's this methodology, or maybe I should say mythology, Dialogue: 0,1:08:20.74,1:08:24.90,EN,,0,0,0,,that's, sort of, charitably called software, quote, engineering. Dialogue: 0,1:08:25.21,1:08:28.04,EN,,0,0,0,,All right, and what does it say, it's says well, you go and you figure out your task, Dialogue: 0,1:08:28.04,1:08:30.04,EN,,0,0,0,,and you figure out exactly what you want to do. Dialogue: 0,1:08:30.40,1:08:32.20,EN,,0,0,0,,And once you figure out exactly what you want to do, Dialogue: 0,1:08:32.22,1:08:34.54,EN,,0,0,0,,you find out that it breaks out into three sub-tasks, Dialogue: 0,1:08:34.54,1:08:35.76,EN,,0,0,0,,and you go and you start working on-- Dialogue: 0,1:08:35.97,1:08:38.94,EN,,0,0,0,,and you work on this sub-task, and you figure out exactly what that is. Dialogue: 0,1:08:38.94,1:08:43.04,EN,,0,0,0,,And you find out that that breaks down into three sub-tasks, and you specify them completely, Dialogue: 0,1:08:43.04,1:08:47.32,EN,,0,0,0,,and you go and you work on those two, and you work on this sub-one, and you specify that exactly. Dialogue: 0,1:08:47.32,1:08:51.10,EN,,0,0,0,,And then finally when you're done, you come back way up here, and you work on your second sub-task, Dialogue: 0,1:08:51.10,1:08:53.40,EN,,0,0,0,,and specify that out and work it out. Dialogue: 0,1:08:53.40,1:08:57.64,EN,,0,0,0,,And then you end up with-- you end up at the end with this beautiful edifice. Dialogue: 0,1:08:57.64,1:09:00.25,EN,,0,0,0,,Right, you end up with a marvelous tree, Dialogue: 0,1:09:00.89,1:09:08.24,EN,,0,0,0,,that where you've broken your task into sub-tasks and broken each of these into sub-tasks and broken those into sub-tasks, right. Dialogue: 0,1:09:09.88,1:09:15.02,EN,,0,0,0,,And each of these nodes is exactly and precisely defined Dialogue: 0,1:09:15.26,1:09:18.66,EN,,0,0,0,,to do the wonderful, beautiful task to make it fit into the whole edifice Dialogue: 0,1:09:18.96,1:09:21.14,EN,,0,0,0,,Right, that's this mythology. Dialogue: 0,1:09:21.14,1:09:25.92,EN,,0,0,0,,See only a computer scientist could possibly believe that you build a complex system like that Dialogue: 0,1:09:27.48,1:09:32.80,EN,,0,0,0,,Right. Contrast that with this Henderson example. Dialogue: 0,1:09:32.80,1:09:34.30,EN,,0,0,0,,It didn't work like that. Dialogue: 0,1:09:35.26,1:09:39.33,EN,,0,0,0,,What happened was that there was a sequence of layers of language. Dialogue: 0,1:09:41.06,1:09:42.05,EN,,0,0,0,,What happened? Dialogue: 0,1:09:42.18,1:09:48.76,EN,,0,0,0,,There was a layer of a thing that allowed us to build primitive pictures. Dialogue: 0,1:09:51.69,1:09:56.24,EN,,0,0,0,,There's primitive pictures and that was a language. Dialogue: 0,1:09:56.32,1:09:57.84,EN,,0,0,0,,I didn't say much about it. Dialogue: 0,1:09:58.22,1:09:59.58,EN,,0,0,0,,We talked about how to construct George, Dialogue: 0,1:09:59.61,1:10:04.88,EN,,0,0,0,,but that was a language where you talked about vectors and line segments and points and where they sat in the unit square. Dialogue: 0,1:10:06.42,1:10:11.29,EN,,0,0,0,,And then on top of that, right, on top of that-- Dialogue: 0,1:10:11.97,1:10:14.10,EN,,0,0,0,,so this is the language of primitive pictures. Dialogue: 0,1:10:17.08,1:10:20.36,EN,,0,0,0,,Right, talking about line segments in particular pictures in the unit square. Dialogue: 0,1:10:21.40,1:10:23.80,EN,,0,0,0,,On top of that was a whole language. Dialogue: 0,1:10:24.05,1:10:30.86,EN,,0,0,0,,There was a language of geometric combinators, Dialogue: 0,1:10:32.66,1:10:36.62,EN,,0,0,0,,a language of geometric positions, Dialogue: 0,1:10:38.77,1:10:46.50,EN,,0,0,0,,which talks about things like Above and Beside and right-push and Rotate. Dialogue: 0,1:10:48.04,1:10:55.70,EN,,0,0,0,,And those things, sort of, happened with reference to the things that are talked about in this language. Dialogue: 0,1:10:58.57,1:11:00.93,EN,,0,0,0,,And then if we like, we saw that above that Dialogue: 0,1:11:02.61,1:11:15.10,EN,,0,0,0,,there was sort of a language of schemes of combination. Dialogue: 0,1:11:21.25,1:11:22.44,EN,,0,0,0,,For example, push, Dialogue: 0,1:11:24.45,1:11:27.88,EN,,0,0,0,,which talked about repeatedly doing something over with a scale factor. Dialogue: 0,1:11:28.38,1:11:31.28,EN,,0,0,0,,And the things that were being discussed in that language Dialogue: 0,1:11:31.50,1:11:34.34,EN,,0,0,0,,were, sort of, the things that happened down here. Dialogue: 0,1:11:36.30,1:11:42.76,EN,,0,0,0,,So what you have is, at each level, the objects that are being talked about Dialogue: 0,1:11:44.68,1:11:47.00,EN,,0,0,0,,are the things that were erected the previous level. Dialogue: 0,1:11:48.08,1:11:52.06,EN,,0,0,0,,What's the difference between this thing and this thing? Dialogue: 0,1:11:53.34,1:11:54.18,EN,,0,0,0,,The answer is Dialogue: 0,1:11:56.14,1:12:01.73,EN,,0,0,0,,that over here in the tree, each node, and in fact, each decomposition down here, Dialogue: 0,1:12:02.14,1:12:05.25,EN,,0,0,0,,is being designed to do a specific task, Dialogue: 0,1:12:07.50,1:12:08.88,EN,,0,0,0,,whereas in the other scheme, Dialogue: 0,1:12:09.21,1:12:14.80,EN,,0,0,0,,what you have is a full range of linguistic power at each level. Dialogue: 0,1:12:16.00,1:12:18.08,EN,,0,0,0,,See what's happening there, at any level, Dialogue: 0,1:12:20.24,1:12:22.72,EN,,0,0,0,,it's not being set up to do a particular task. Dialogue: 0,1:12:23.14,1:12:26.17,EN,,0,0,0,,It's being set up to talk about a whole range of things. Dialogue: 0,1:12:27.62,1:12:30.78,EN,,0,0,0,,The consequence of that for design Dialogue: 0,1:12:31.14,1:12:35.58,EN,,0,0,0,,is that something that's designed in that method is likely to be more robust, Dialogue: 0,1:12:36.61,1:12:38.20,EN,,0,0,0,,where by robust, I mean Dialogue: 0,1:12:38.44,1:12:41.24,EN,,0,0,0,,that if you go and make some change in your description, Dialogue: 0,1:12:42.70,1:12:48.04,EN,,0,0,0,,it's more likely to be captured by a corresponding change, Dialogue: 0,1:12:49.22,1:12:52.60,EN,,0,0,0,,in the way that the language is implemented at the next level up, Dialogue: 0,1:12:54.29,1:12:56.58,EN,,0,0,0,,right, because you've made these levels full. Dialogue: 0,1:12:56.62,1:12:59.66,EN,,0,0,0,,So you're not talking about a particular thing like Beside. Dialogue: 0,1:12:59.94,1:13:03.78,EN,,0,0,0,,You've given yourself a whole vocabulary to express things of that sort, Dialogue: 0,1:13:04.77,1:13:07.02,EN,,0,0,0,,so if you go and change your specifications a little bit, Dialogue: 0,1:13:07.02,1:13:11.38,EN,,0,0,0,,it's more likely that your methodology will able to adapt to capture that change, Dialogue: 0,1:13:12.69,1:13:15.02,EN,,0,0,0,,whereas a design like this is not going to be robust, Dialogue: 0,1:13:15.02,1:13:17.08,EN,,0,0,0,,because if I go and change something that's in here, Dialogue: 0,1:13:17.53,1:13:21.69,EN,,0,0,0,,that might affect the entire way that I decomposed everything down, further down the tree. Dialogue: 0,1:13:23.20,1:13:29.74,EN,,0,0,0,,Right, so very big difference in outlook in decomposition, levels of language rather than, sort of, a strict hierarchy. Dialogue: 0,1:13:30.52,1:13:33.02,EN,,0,0,0,,Not only that, but when you have levels of language Dialogue: 0,1:13:33.50,1:13:35.92,EN,,0,0,0,,you've given yourself a different vocabularies Dialogue: 0,1:13:36.45,1:13:38.74,EN,,0,0,0,,for talking about the design at different levels. Dialogue: 0,1:13:38.74,1:13:40.92,EN,,0,0,0,,So if we go back and look at George one last time, Dialogue: 0,1:13:41.90,1:13:44.08,EN,,0,0,0,,if I wanted to change this picture George, Dialogue: 0,1:13:45.85,1:13:48.68,EN,,0,0,0,,see suddenly I have a whole different ways of describing the change. Dialogue: 0,1:13:48.68,1:13:56.08,EN,,0,0,0,,Like for example, I may want to go to the basic primitive design and move the endpoint of some vector. Dialogue: 0,1:13:57.76,1:14:00.76,EN,,0,0,0,,That's a change that I would discuss at the lowest level. Dialogue: 0,1:14:01.00,1:14:02.50,EN,,0,0,0,,I would say the endpoint is somewhere else. Dialogue: 0,1:14:03.34,1:14:07.98,EN,,0,0,0,,Or I might come up and say, well the next thing I wanted to do, this little replicated element, Dialogue: 0,1:14:09.10,1:14:10.94,EN,,0,0,0,,I might want to do by something else. Dialogue: 0,1:14:10.94,1:14:13.84,EN,,0,0,0,,I might want to put a scale factor in that Beside. Dialogue: 0,1:14:13.84,1:14:19.34,EN,,0,0,0,,That's a change that I would discuss at the next level of design, the level of combinators. Dialogue: 0,1:14:19.34,1:14:25.05,EN,,0,0,0,,Or I might want to say, I might want to change the basic way that I took this pattern Dialogue: 0,1:14:26.49,1:14:30.48,EN,,0,0,0,,and made some recursive decomposition, maybe not bleeding out toward the corners or something else. Dialogue: 0,1:14:31.16,1:14:34.18,EN,,0,0,0,,That would be a change that I would discuss at the highest level. Dialogue: 0,1:14:34.18,1:14:36.37,EN,,0,0,0,,And because I've structured the system to be this way, Dialogue: 0,1:14:36.52,1:14:39.62,EN,,0,0,0,,I have all these vocabularies for talking about change in different ways Dialogue: 0,1:14:39.65,1:14:42.48,EN,,0,0,0,,and a lot of flexibility to decide which one's appropriate. Dialogue: 0,1:14:44.74,1:14:51.05,EN,,0,0,0,,OK, well that's sort of a big point about the difference in software methodology that comes out from Lisp, Dialogue: 0,1:14:51.25,1:14:55.45,EN,,0,0,0,,and it all comes again, out of the notion that really, the design process Dialogue: 0,1:14:56.12,1:14:59.62,EN,,0,0,0,,is not so much implementing programs as implementing languages. Dialogue: 0,1:14:59.62,1:15:01.09,EN,,0,0,0,,And that's really the power of Lisp. Dialogue: 0,1:15:02.21,1:15:03.61,EN,,0,0,0,,OK, thank you. Let's take a break. Dialogue: 0,1:15:05.69,1:15:23.37,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:15:05.69,1:15:23.37,Declare,,0,0,0,,{\an2\fad(500,500)}Project Repo\Nhttps://github.com/DeathKing/Learning-SICP Dialogue: 0,1:15:23.37,1:15:25.37,Default,,0,0,0,, ================================================ FILE: Ass/lec3b.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Last Style Storage: Default Scroll Position: 1174 Active Line: 1179 Video Zoom Percent: 0.625 Audio URI: G:\untitled\ref\lec3b_480_muxed2.mp4 Video File: G:\untitled\ref\lec3b_480_muxed2.mp4 Video Aspect Ratio: c1.33333 Video Position: 78794 PlayResX: 640 PlayResY: 480 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:19.10,0:00:23.41,EN,,0,0,0,,PROFESSOR: Well, Hal just told us how you build robust systems. Dialogue: 0,0:00:23.80,0:00:26.17,EN,,0,0,0,,The key idea was-- Dialogue: 0,0:00:26.81,0:00:30.20,EN,,0,0,0,,I'm sure that many of you don't really assimilate that yet-- Dialogue: 0,0:00:30.20,0:00:33.77,EN,,0,0,0,,but the key idea is that in order to make a system that's robust, Dialogue: 0,0:00:33.93,0:00:36.48,EN,,0,0,0,,it has to be insensitive to small changes, Dialogue: 0,0:00:36.60,0:00:37.37,EN,,0,0,0,,that is, Dialogue: 0,0:00:37.37,0:00:40.90,EN,,0,0,0,,a small change in the problem should lead to only a small change in the solution. Dialogue: 0,0:00:41.32,0:00:42.90,EN,,0,0,0,,There ought to be a continuity. Dialogue: 0,0:00:42.90,0:00:45.94,EN,,0,0,0,,The space of solutions ought to be continuous in this space of problems. Dialogue: 0,0:00:46.25,0:00:48.76,EN,,0,0,0,,The way he was explaining how to do that Dialogue: 0,0:00:49.46,0:00:54.78,EN,,0,0,0,,was instead of solving a particular problem at every level of decomposition of the problem at the subproblems, Dialogue: 0,0:00:55.08,0:00:56.78,EN,,0,0,0,,where you solve the class of problems, Dialogue: 0,0:00:56.78,0:01:00.40,EN,,0,0,0,,which are a neighborhood of the particular problem that you're trying to solve. Dialogue: 0,0:01:01.40,0:01:04.76,EN,,0,0,0,,The way you do that is by producing a language at that level of detail Dialogue: 0,0:01:04.76,0:01:10.33,EN,,0,0,0,,in which the solutions to that class of problems is representable in that language. Dialogue: 0,0:01:11.37,0:01:15.09,EN,,0,0,0,,Therefore when you change makes more changes to the problem you're trying to solve, Dialogue: 0,0:01:15.09,0:01:19.29,EN,,0,0,0,,you generally have to make only small local changes to the solution you've constructed, Dialogue: 0,0:01:19.29,0:01:22.26,EN,,0,0,0,,because at the level of detail you're working, Dialogue: 0,0:01:22.26,0:01:24.26,EN,,0,0,0,,there's a language where you can express Dialogue: 0,0:01:24.80,0:01:28.14,EN,,0,0,0,,the various solutions to alternate problems of the same type. Dialogue: 0,0:01:30.04,0:01:33.74,EN,,0,0,0,,Well that's the beginning of a very important idea, Dialogue: 0,0:01:34.40,0:01:38.61,EN,,0,0,0,,the most important perhaps idea that makes computer science more powerful Dialogue: 0,0:01:38.61,0:01:42.37,EN,,0,0,0,,than most of the other kinds of engineering disciplines we know about. Dialogue: 0,0:01:43.38,0:01:44.73,EN,,0,0,0,,What we've seen so far Dialogue: 0,0:01:44.73,0:01:48.78,EN,,0,0,0,,is sort of how to use embedding of languages. Dialogue: 0,0:01:49.26,0:01:53.36,EN,,0,0,0,,And, of course, the power of embedding languages partly comes from Dialogue: 0,0:01:54.12,0:01:56.86,EN,,0,0,0,,procedures like this one that I showed you yesterday. Dialogue: 0,0:01:57.37,0:02:02.13,EN,,0,0,0,,What you see here is the derivative program that we described yesterday. Dialogue: 0,0:02:02.13,0:02:05.92,EN,,0,0,0,,It's a procedure that takes a procedure as an argument Dialogue: 0,0:02:06.00,0:02:07.92,EN,,0,0,0,,and returns a procedure as a value. Dialogue: 0,0:02:09.61,0:02:12.65,EN,,0,0,0,,And using such things is very nice. Dialogue: 0,0:02:12.65,0:02:14.65,EN,,0,0,0,,You can make things like push combinators Dialogue: 0,0:02:14.65,0:02:16.86,EN,,0,0,0,,and all that sort of wonderful thing that you saw last time. Dialogue: 0,0:02:17.68,0:02:20.54,EN,,0,0,0,,However, now I'm going to really muddy the waters. Dialogue: 0,0:02:21.56,0:02:25.90,EN,,0,0,0,,See this confuses the issue of what's the procedure and what is data, Dialogue: 0,0:02:26.56,0:02:27.81,EN,,0,0,0,,but not very badly. Dialogue: 0,0:02:28.42,0:02:30.90,EN,,0,0,0,,What we really want to do is confuse it very badly. Dialogue: 0,0:02:31.18,0:02:32.44,EN,,0,0,0,,And the best way to do that Dialogue: 0,0:02:32.44,0:02:37.62,EN,,0,0,0,,is to get involved with the manipulation of the algebraic expressions that the procedures themselves are expressed in. Dialogue: 0,0:02:39.73,0:02:45.58,EN,,0,0,0,,So at this point, I want to talk about instead of things like on this slide, Dialogue: 0,0:02:45.89,0:02:49.72,EN,,0,0,0,,the derivative procedure being a thing that manipulates a procedure-- Dialogue: 0,0:02:49.72,0:02:51.94,EN,,0,0,0,,this is a numerical method you see here. Dialogue: 0,0:02:51.94,0:02:58.93,EN,,0,0,0,,And what you're seeing is a representation of the numerical approximationto the derivative. Dialogue: 0,0:02:59.29,0:03:00.44,EN,,0,0,0,,That's what's here. Dialogue: 0,0:03:00.86,0:03:04.93,EN,,0,0,0,,In fact what I'd like to talk about is instead things that look like this. Dialogue: 0,0:03:06.05,0:03:11.33,EN,,0,0,0,,And what we have here are rules from a calculus book. Dialogue: 0,0:03:12.09,0:03:16.17,EN,,0,0,0,,These are rules for finding the derivatives of the expressions Dialogue: 0,0:03:16.70,0:03:20.58,EN,,0,0,0,,that one might write in some algebraic language. Dialogue: 0,0:03:21.64,0:03:24.41,EN,,0,0,0,,It says things like a derivative of a constant is 0. Dialogue: 0,0:03:25.13,0:03:29.09,EN,,0,0,0,,The derivative of the valuable with respect to which you are taking the derivative is 1. Dialogue: 0,0:03:29.32,0:03:31.93,EN,,0,0,0,,The derivative of a constant times the function Dialogue: 0,0:03:32.09,0:03:34.37,EN,,0,0,0,,is the constant times the derivative of the function, Dialogue: 0,0:03:34.77,0:03:36.04,EN,,0,0,0,,and things like that. Dialogue: 0,0:03:38.05,0:03:41.38,EN,,0,0,0,,These are exact expressions. These are not numerical approximations. Dialogue: 0,0:03:42.96,0:03:44.52,EN,,0,0,0,,Can we make programs? Dialogue: 0,0:03:44.52,0:03:52.24,EN,,0,0,0,,And, in fact, it's very easy to make programs that manipulate these expressions. Dialogue: 0,0:03:56.38,0:03:59.52,EN,,0,0,0,,Well let's see. Let's look at these rules in some detail. Dialogue: 0,0:04:01.08,0:04:05.22,EN,,0,0,0,,You all have seen these rules in your elementary calculus class at one time or another. Dialogue: 0,0:04:05.98,0:04:12.12,EN,,0,0,0,,And you know from calculus that it's easy to produce derivatives of arbitrary expressions. Dialogue: 0,0:04:12.53,0:04:16.05,EN,,0,0,0,,You also know from your elementary calculus that it's hard to produce integrals. Dialogue: 0,0:04:16.98,0:04:19.37,EN,,0,0,0,,Yet integrals and derivatives are opposites of each other. Dialogue: 0,0:04:19.52,0:04:21.28,EN,,0,0,0,,They're inverse operations. Dialogue: 0,0:04:21.61,0:04:23.30,EN,,0,0,0,,And they have the same rules. Dialogue: 0,0:04:24.16,0:04:29.68,EN,,0,0,0,,What is special about these rules that makes it possible for one Dialogue: 0,0:04:29.68,0:04:33.65,EN,,0,0,0,,to produce derivatives easily and integrals why it's so hard? Dialogue: 0,0:04:34.85,0:04:36.98,EN,,0,0,0,,Let's think about that very simply. Dialogue: 0,0:04:37.40,0:04:38.38,EN,,0,0,0,,Look at these rules. Dialogue: 0,0:04:39.36,0:04:43.06,EN,,0,0,0,,Every one of these rules, when used in the direction for taking derivatives, Dialogue: 0,0:04:43.06,0:04:44.80,EN,,0,0,0,,which is in the direction of this arrow, Dialogue: 0,0:04:46.68,0:04:49.16,EN,,0,0,0,,the left side is matched against your expression, Dialogue: 0,0:04:49.16,0:04:53.05,EN,,0,0,0,,and the right side is the thing which is the derivative of that expression. Dialogue: 0,0:04:54.02,0:04:55.65,EN,,0,0,0,,The arrow is going that way. Dialogue: 0,0:04:57.37,0:05:00.45,EN,,0,0,0,,In each of these rules, Dialogue: 0,0:05:01.24,0:05:03.72,EN,,0,0,0,,the expressions on the right-hand side of the rule Dialogue: 0,0:05:03.72,0:05:06.56,EN,,0,0,0,,that are contained within derivatives are subexpressions, Dialogue: 0,0:05:06.56,0:05:10.29,EN,,0,0,0,,are proper subexpressions, of the expression on the left-hand side. Dialogue: 0,0:05:10.60,0:05:13.25,EN,,0,0,0,,So here we see the derivative of the sum, Dialogue: 0,0:05:13.92,0:05:16.13,EN,,0,0,0,,witch is the expression on the left-hand side Dialogue: 0,0:05:16.13,0:05:18.38,EN,,0,0,0,,is the sum of the derivatives of the pieces. Dialogue: 0,0:05:20.08,0:05:24.49,EN,,0,0,0,,So the rule of moving to the right are reduction rules. Dialogue: 0,0:05:25.02,0:05:26.61,EN,,0,0,0,,The problem becomes easier. Dialogue: 0,0:05:27.56,0:05:31.48,EN,,0,0,0,,I make, I turn a big complicated problem it's lots of smaller problems Dialogue: 0,0:05:32.44,0:05:35.76,EN,,0,0,0,,and then combine the results, a perfect place for recursion to work. Dialogue: 0,0:05:36.58,0:05:40.85,EN,,0,0,0,,If I'm going in the other direction like this, Dialogue: 0,0:05:41.81,0:05:45.13,EN,,0,0,0,,if I'm trying to produce integrals, well there are several problems you see here. Dialogue: 0,0:05:45.24,0:05:49.09,EN,,0,0,0,,First of all, if I try to integrate an expression like a sum, Dialogue: 0,0:05:49.21,0:05:50.81,EN,,0,0,0,,more than one rule matches. Dialogue: 0,0:05:50.81,0:05:52.10,EN,,0,0,0,,Here's one that matches. Dialogue: 0,0:05:52.48,0:05:53.65,EN,,0,0,0,,Here's one that matches. Dialogue: 0,0:05:54.81,0:05:57.09,EN,,0,0,0,,I don't know which one to take. And they may be different. Dialogue: 0,0:05:57.70,0:06:00.00,EN,,0,0,0,,I may get to explore different things. Dialogue: 0,0:06:00.25,0:06:03.64,EN,,0,0,0,,Also, the expressions become larger in that direction. Dialogue: 0,0:06:04.53,0:06:06.30,EN,,0,0,0,,And when the expressions become larger, Dialogue: 0,0:06:06.30,0:06:10.56,EN,,0,0,0,,then there's no guarantee that any particular path I choose will terminate, Dialogue: 0,0:06:10.94,0:06:13.46,EN,,0,0,0,,because we will only terminate by accidental cancellation. Dialogue: 0,0:06:14.24,0:06:18.05,EN,,0,0,0,,So that's why integrals are complicated searches and hard to do. Dialogue: 0,0:06:19.12,0:06:20.96,EN,,0,0,0,,Right now I don't want to do anything as hard as that. Dialogue: 0,0:06:21.49,0:06:23.06,EN,,0,0,0,,Let's work on derivatives for a while. Dialogue: 0,0:06:24.14,0:06:28.13,EN,,0,0,0,,Well, these rules are ones you know for the most part hopefully. Dialogue: 0,0:06:28.78,0:06:31.88,EN,,0,0,0,,So let's see if we can write a program which is these rules. Dialogue: 0,0:06:32.22,0:06:33.72,EN,,0,0,0,,And that should be very easy. Dialogue: 0,0:06:34.89,0:06:36.21,EN,,0,0,0,,Just write the program. Dialogue: 0,0:06:36.69,0:06:39.29,EN,,0,0,0,,See, because while I showed you is that it's a reduction rule, Dialogue: 0,0:06:39.29,0:06:41.29,EN,,0,0,0,,it's something appropriate for a recursion. Dialogue: 0,0:06:43.08,0:06:45.72,EN,,0,0,0,,And, of course, what we have for each of these rules is we have a case Dialogue: 0,0:06:46.66,0:06:47.78,EN,,0,0,0,,in some case analysis. Dialogue: 0,0:06:48.58,0:06:50.36,EN,,0,0,0,,So I'm just going to write this program down. Dialogue: 0,0:06:52.88,0:06:57.69,EN,,0,0,0,,Now, of course, I'm going to be saying something you have to believe. Right? Dialogue: 0,0:06:57.69,0:07:00.33,EN,,0,0,0,,What you have to believe is I can represent these algebraic expressions, Dialogue: 0,0:07:00.68,0:07:03.88,EN,,0,0,0,,that I can grab their parts, that I can put them together. Dialogue: 0,0:07:04.24,0:07:06.49,EN,,0,0,0,,We've invented list structures so that you can do that. Dialogue: 0,0:07:07.52,0:07:09.14,EN,,0,0,0,,But you don't want to worry about that now. Dialogue: 0,0:07:09.66,0:07:12.45,EN,,0,0,0,,Right now I'm going to write the program that encapsulates these rules Dialogue: 0,0:07:12.76,0:07:15.85,EN,,0,0,0,,independent of the representation of the algebraic expressions. Dialogue: 0,0:07:20.42,0:07:28.84,EN,,0,0,0,,You have a derivative of an expression with respect to a variable. Dialogue: 0,0:07:30.50,0:07:33.08,EN,,0,0,0,,This is a different thing than the derivative of the function. Dialogue: 0,0:07:34.82,0:07:38.61,EN,,0,0,0,,That's what we saw last time, that numerical approximation. Dialogue: 0,0:07:39.00,0:07:40.82,EN,,0,0,0,,It's something you can't open up a function. Dialogue: 0,0:07:40.82,0:07:41.89,EN,,0,0,0,,It's just the answers. Dialogue: 0,0:07:43.09,0:07:45.18,EN,,0,0,0,,The derivative of an expression is the way it's written. Dialogue: 0,0:07:45.74,0:07:47.85,EN,,0,0,0,,And therefore it's a syntactic phenomenon. Dialogue: 0,0:07:48.29,0:07:51.62,EN,,0,0,0,,And so a lot of what we're going to be doing today is worrying about syntax, Dialogue: 0,0:07:52.33,0:07:54.12,EN,,0,0,0,,syntax of expressions and things like that. Dialogue: 0,0:07:54.70,0:07:55.93,EN,,0,0,0,,Well, there's a case analysis. Dialogue: 0,0:07:57.50,0:08:01.08,EN,,0,0,0,,Anytime we do anything complicated thereby a recursion, Dialogue: 0,0:08:01.08,0:08:02.64,EN,,0,0,0,,we presumably need a case analysis. Dialogue: 0,0:08:03.62,0:08:05.16,EN,,0,0,0,,It's the essential way to begin. Dialogue: 0,0:08:05.16,0:08:07.40,EN,,0,0,0,,And that's usually a conditional of some large kind. Dialogue: 0,0:08:08.08,0:08:09.97,EN,,0,0,0,,Well, what are their possibilities? Dialogue: 0,0:08:09.97,0:08:12.53,EN,,0,0,0,,the first rule that you saw is this something a constant? Dialogue: 0,0:08:16.50,0:08:17.50,EN,,0,0,0,,And what I'm asking is, Dialogue: 0,0:08:17.50,0:08:22.22,EN,,0,0,0,,is the expression a constant with respect to the variable given? Dialogue: 0,0:08:24.90,0:08:27.08,EN,,0,0,0,,If so, the result is 0, Dialogue: 0,0:08:27.50,0:08:30.10,EN,,0,0,0,,because the derivative represents the rate of change of something. Dialogue: 0,0:08:31.76,0:08:32.65,EN,,0,0,0,,If, however, Dialogue: 0,0:08:32.89,0:08:40.69,EN,,0,0,0,,the expression that I'm taking the derivative of is the variable I'm varying, Dialogue: 0,0:08:41.72,0:08:50.42,EN,,0,0,0,,then this is the same variable, the expression var, Dialogue: 0,0:08:51.14,0:08:54.52,EN,,0,0,0,,then the rate of change of the expression with respect to the variable is 1. Dialogue: 0,0:08:55.50,0:08:56.54,EN,,0,0,0,,It's the same 1. Dialogue: 0,0:08:58.90,0:09:00.77,EN,,0,0,0,,Well now there are a couple of other possibilities. Dialogue: 0,0:09:01.33,0:09:03.14,EN,,0,0,0,,It could, for example, be a sum. Dialogue: 0,0:09:03.86,0:09:05.88,EN,,0,0,0,,Well, I don't know how I'm going to express sums yet. Dialogue: 0,0:09:06.09,0:09:08.25,EN,,0,0,0,,Actually I do. But I haven't told you yet. Dialogue: 0,0:09:10.34,0:09:11.78,EN,,0,0,0,,But is it a sum? Dialogue: 0,0:09:12.48,0:09:14.48,EN,,0,0,0,,I'm imagining that there's some way of telling. Dialogue: 0,0:09:15.30,0:09:19.44,EN,,0,0,0,,I'm doing a dispatch on the type of the expression here, Dialogue: 0,0:09:20.77,0:09:23.57,EN,,0,0,0,,absolutely essential in building languages. Dialogue: 0,0:09:24.72,0:09:26.37,EN,,0,0,0,,Cause languages are made out of different expressions. Dialogue: 0,0:09:26.48,0:09:27.54,EN,,0,0,0,,And soon we're going to see that Dialogue: 0,0:09:27.84,0:09:31.02,EN,,0,0,0,,in our more powerful methods of building languages on languages. Dialogue: 0,0:09:32.53,0:09:34.02,EN,,0,0,0,,Is an expression a sum? Dialogue: 0,0:09:35.45,0:09:38.82,EN,,0,0,0,,If it's a sum, well, we know the rule for derivative of the sum Dialogue: 0,0:09:38.82,0:09:41.33,EN,,0,0,0,,is the sum of the derivatives of the parts. Dialogue: 0,0:09:42.13,0:09:44.32,EN,,0,0,0,,One of them is called the addend and the other is the augend. Dialogue: 0,0:09:44.32,0:09:46.80,EN,,0,0,0,,But I don't have enough space on the blackboard to such long names. Dialogue: 0,0:09:46.80,0:09:48.40,EN,,0,0,0,,So I'll call them A1 and A2. Dialogue: 0,0:09:49.04,0:09:50.37,EN,,0,0,0,,I want to make a sum. Dialogue: 0,0:09:53.53,0:09:55.68,EN,,0,0,0,,Do you remember which is the sub for head or the menu end? Dialogue: 0,0:09:57.14,0:10:01.09,EN,,0,0,0,,Or was it the dividend and the divisor or something like that? Dialogue: 0,0:10:01.65,0:10:08.48,EN,,0,0,0,,Make sum of the derivative of the A1, I'll call it. Dialogue: 0,0:10:08.48,0:10:13.29,EN,,0,0,0,,It's the addend of the expression with respect to the variable, Dialogue: 0,0:10:14.84,0:10:22.76,EN,,0,0,0,,and the derivative of the A2 of the expression, Dialogue: 0,0:10:24.12,0:10:28.25,EN,,0,0,0,,those the two arguments, the addition. Respect to the variable. Dialogue: 0,0:10:32.36,0:10:34.93,EN,,0,0,0,,And another rule that we know is product rule, Dialogue: 0,0:10:35.20,0:10:37.44,EN,,0,0,0,,which is, if the expression is a product. Dialogue: 0,0:10:43.21,0:10:46.10,EN,,0,0,0,,By the way, it's a good idea when you're defining things, Dialogue: 0,0:10:46.96,0:10:48.32,EN,,0,0,0,,when you're defining predicates, Dialogue: 0,0:10:48.85,0:10:50.96,EN,,0,0,0,,to give them a name that ends in a question mark. Dialogue: 0,0:10:51.08,0:10:52.89,EN,,0,0,0,,This question mark doesn't mean anything. Dialogue: 0,0:10:53.10,0:10:54.50,EN,,0,0,0,,It's for us as an agreement. Dialogue: 0,0:10:54.61,0:10:58.94,EN,,0,0,0,,It's a conventional interface between humans so you can read my programs more easily. Dialogue: 0,0:11:00.05,0:11:01.96,EN,,0,0,0,,So I want you to, when you write programs, Dialogue: 0,0:11:01.96,0:11:03.73,EN,,0,0,0,,if you define a predicate procedure, Dialogue: 0,0:11:04.01,0:11:05.77,EN,,0,0,0,,that's something that returns true of false, Dialogue: 0,0:11:05.94,0:11:07.84,EN,,0,0,0,,it should have a name which ends in question mark. Dialogue: 0,0:11:08.02,0:11:10.34,EN,,0,0,0,,The lisp doesn't care. I care. Dialogue: 0,0:11:11.62,0:11:13.14,EN,,0,0,0,,I want to make a sum. Dialogue: 0,0:11:13.14,0:11:17.49,EN,,0,0,0,,Because the product, the derivative of a product is the sum Dialogue: 0,0:11:17.94,0:11:19.64,EN,,0,0,0,,of the first times the derivative of the second plus Dialogue: 0,0:11:19.66,0:11:20.70,EN,,0,0,0,,the second times the derivative of the first. Dialogue: 0,0:11:23.54,0:11:27.06,EN,,0,0,0,,Make a sum of two things, Dialogue: 0,0:11:29.64,0:11:38.33,EN,,0,0,0,,a product of, well, I'm going to say the M1 of the expression, Dialogue: 0,0:11:39.85,0:11:48.97,EN,,0,0,0,,and the derivative of the M2 of the expression with respect to the variable, Dialogue: 0,0:11:51.90,0:12:06.28,EN,,0,0,0,,and the product of the derivative of M1, Dialogue: 0,0:12:07.10,0:12:11.92,EN,,0,0,0,,the multiplier of the expression, with respect to the variable. Dialogue: 0,0:12:13.32,0:12:18.05,EN,,0,0,0,,And the product of that and the multiplicand, M2, of the expression. Dialogue: 0,0:12:20.64,0:12:24.89,EN,,0,0,0,,Make that product. Make the sum. Close that case. Dialogue: 0,0:12:24.96,0:12:28.02,EN,,0,0,0,,And, of course, I could add as many cases as I like here Dialogue: 0,0:12:28.32,0:12:30.82,EN,,0,0,0,,for a complete set of rules you might find in a calculus book. Dialogue: 0,0:12:34.80,0:12:39.45,EN,,0,0,0,,So this is what it takes to encapsulate those rules. Dialogue: 0,0:12:41.53,0:12:43.90,EN,,0,0,0,,And you see, you have to realize there's a lot of wishful thinking here. Dialogue: 0,0:12:44.54,0:12:47.56,EN,,0,0,0,,I haven't told you anything about how I'm going to make these representations. Dialogue: 0,0:12:48.46,0:12:51.92,EN,,0,0,0,,Now, once I've decided that this is my set of rules, Dialogue: 0,0:12:52.52,0:12:55.20,EN,,0,0,0,,I think it's time to play with the representation. Dialogue: 0,0:12:55.66,0:12:56.69,EN,,0,0,0,,Let's attack that. Dialogue: 0,0:12:57.96,0:13:00.00,EN,,0,0,0,,Well, first of all, I'm going to play a pun. Dialogue: 0,0:13:00.90,0:13:02.12,EN,,0,0,0,,It's an important pun. Dialogue: 0,0:13:02.74,0:13:06.56,EN,,0,0,0,,It's a key to a sort of powerful idea. Dialogue: 0,0:13:09.62,0:13:14.41,EN,,0,0,0,,If I want to represent sums, and products, and differences, and quotients, and things like that, Dialogue: 0,0:13:15.22,0:13:18.62,EN,,0,0,0,,why not use the same language as I'm writing my program in? Dialogue: 0,0:13:20.50,0:13:23.64,EN,,0,0,0,,I write my program it algebraic expressions that look like Dialogue: 0,0:13:23.98,0:13:30.45,EN,,0,0,0,,the sum of the product on a and the product of x and x, Dialogue: 0,0:13:32.60,0:13:33.80,EN,,0,0,0,,and things like that. Dialogue: 0,0:13:34.28,0:13:38.50,EN,,0,0,0,,And the product of b and x and c, whatever, Dialogue: 0,0:13:38.50,0:13:39.97,EN,,0,0,0,,make that a sum of the product. Dialogue: 0,0:13:40.77,0:13:44.09,EN,,0,0,0,,Right now I don't want to have procedures with unknown numbers of arguments, Dialogue: 0,0:13:44.93,0:13:48.46,EN,,0,0,0,,a product of b and x and c. Dialogue: 0,0:13:51.42,0:13:52.44,EN,,0,0,0,,This is list structure. Dialogue: 0,0:13:54.12,0:13:55.74,EN,,0,0,0,,And the reason why this is nice, Dialogue: 0,0:13:55.90,0:13:58.33,EN,,0,0,0,,is because any one of these objects has a property. Dialogue: 0,0:13:58.92,0:14:01.53,EN,,0,0,0,,I know where, know where the car is. Dialogue: 0,0:14:01.96,0:14:03.21,EN,,0,0,0,,The car is the operator. Dialogue: 0,0:14:03.92,0:14:06.38,EN,,0,0,0,,And the operands are the successive cdrs Dialogue: 0,0:14:07.22,0:14:10.36,EN,,0,0,0,,the successive cars of the cdrs of the list that this is. Dialogue: 0,0:14:12.48,0:14:13.88,EN,,0,0,0,,It makes it very convenient. Dialogue: 0,0:14:14.01,0:14:16.40,EN,,0,0,0,,Ir have to parse it. It's been done for me. Dialogue: 0,0:14:17.42,0:14:20.01,EN,,0,0,0,,I'm using the embedding in Lisp to advantage. Dialogue: 0,0:14:22.66,0:14:23.77,EN,,0,0,0,,So, for example, Dialogue: 0,0:14:25.08,0:14:33.97,EN,,0,0,0,,Let's start using list structure to write down the representation that I'm implicitly assuming here. Dialogue: 0,0:14:35.25,0:14:38.34,EN,,0,0,0,,Well I have to define various things that are implied in this representation. Dialogue: 0,0:14:38.54,0:14:40.90,EN,,0,0,0,,Like I have to find out how to do a constant, Dialogue: 0,0:14:41.21,0:14:42.30,EN,,0,0,0,,how you do same variable. Dialogue: 0,0:14:42.40,0:14:45.04,EN,,0,0,0,,Let's do those first. That's pretty easy enough. Dialogue: 0,0:14:45.78,0:14:47.70,EN,,0,0,0,,Now I'm going to be introducing lots of primitives here, Dialogue: 0,0:14:48.60,0:14:50.50,EN,,0,0,0,,because these are the primitives that come with list structure. Dialogue: 0,0:14:51.98,0:14:53.46,EN,,0,0,0,,OK, you define a constant. Dialogue: 0,0:15:02.25,0:15:04.29,EN,,0,0,0,,And what I mean by a constant, Dialogue: 0,0:15:04.29,0:15:07.73,EN,,0,0,0,,an expression is constant with respect to a variable. Dialogue: 0,0:15:09.05,0:15:11.60,EN,,0,0,0,,is that the expression is something simple. Dialogue: 0,0:15:11.60,0:15:14.46,EN,,0,0,0,,I can't take it into pieces, and yet it isn't that variable. Dialogue: 0,0:15:16.58,0:15:18.78,EN,,0,0,0,,I can't break it up, and yet it isn't that variable. Dialogue: 0,0:15:18.90,0:15:25.12,EN,,0,0,0,,That does not mean that there may be other expressions that are more complicated that are constants. Dialogue: 0,0:15:25.20,0:15:28.92,EN,,0,0,0,,It's just that I'm going to look at the primitive constants in this way. Dialogue: 0,0:15:29.74,0:15:33.41,EN,,0,0,0,,So what this is, is it says that's it's the and. Dialogue: 0,0:15:34.02,0:15:37.82,EN,,0,0,0,,I can combine predicate expressions which return true or false with and. Dialogue: 0,0:15:38.62,0:15:46.82,EN,,0,0,0,,Something atomic, The expression is atomic, meaning it cannot be broken into parts. Dialogue: 0,0:15:46.82,0:15:48.53,EN,,0,0,0,,It doesn't have a car and a cdr. Dialogue: 0,0:15:49.45,0:15:50.21,EN,,0,0,0,,It's not a list. Dialogue: 0,0:15:50.76,0:15:52.94,EN,,0,0,0,,And it's a special test built into the system. Dialogue: 0,0:15:53.97,0:16:04.66,EN,,0,0,0,,And it's not identically equal to that variable. Dialogue: 0,0:16:06.82,0:16:13.36,EN,,0,0,0,,I'm representing my variables by things that are symbols which cannot be broken into pieces, Dialogue: 0,0:16:13.90,0:16:17.22,EN,,0,0,0,,things like x, and y, things like this. Dialogue: 0,0:16:19.74,0:16:22.37,EN,,0,0,0,,Whereas, of course, something like this can be broken up into pieces. Dialogue: 0,0:16:24.74,0:16:46.40,EN,,0,0,0,,And the same variable of an expression with respect to a variable is, Dialogue: 0,0:16:46.40,0:16:48.40,EN,,0,0,0,,in fact, an atomic expression. Dialogue: 0,0:16:48.77,0:16:59.61,EN,,0,0,0,,I want to have an atomic expression, which is identical. Dialogue: 0,0:17:07.90,0:17:11.68,EN,,0,0,0,,I don't want to look inside this, this stuff anymore. Dialogue: 0,0:17:12.52,0:17:15.56,EN,,0,0,0,,These are primitive maybe. Dialogue: 0,0:17:15.77,0:17:17.08,EN,,0,0,0,,But it doesn't matter. Dialogue: 0,0:17:17.78,0:17:21.74,EN,,0,0,0,,I'm defining... I'm using things that are given to me with a language. Dialogue: 0,0:17:22.42,0:17:24.04,EN,,0,0,0,,I'm not terribly interest in them. Dialogue: 0,0:17:24.42,0:17:26.04,EN,,0,0,0,,Now how do we deal with sums? Dialogue: 0,0:17:26.60,0:17:28.80,EN,,0,0,0,,Ah, something very interesting will happen. Dialogue: 0,0:17:28.98,0:17:33.12,EN,,0,0,0,,A sum is something which is not atomic and begins with the plus symbol. Dialogue: 0,0:17:35.16,0:17:36.17,EN,,0,0,0,,That's what it means. Dialogue: 0,0:17:36.65,0:17:39.77,EN,,0,0,0,,So here, I will define. Dialogue: 0,0:17:45.46,0:17:57.77,EN,,0,0,0,,An expression is a sum if and it's not atomic Dialogue: 0,0:18:04.57,0:18:15.45,EN,,0,0,0,,and it's head, it's beginning, its car of the expression is the symbol plus. Dialogue: 0,0:18:19.74,0:18:24.04,EN,,0,0,0,,Now you're about to see something you haven't seen before, this quotation. Dialogue: 0,0:18:25.89,0:18:28.22,EN,,0,0,0,,Why do I have that quotation there? Dialogue: 0,0:18:29.48,0:18:30.52,EN,,0,0,0,,PROFESSOR: Say your name, Dialogue: 0,0:18:30.68,0:18:31.41,EN,,0,0,0,,AUDIENCE: Susanna. Dialogue: 0,0:18:31.41,0:18:32.01,EN,,0,0,0,,PROFESSOR: Louder. Dialogue: 0,0:18:32.01,0:18:32.72,EN,,0,0,0,,AUDIENCE: Susanna Dialogue: 0,0:18:33.25,0:18:34.21,EN,,0,0,0,,PROFESSOR: Say your name. Dialogue: 0,0:18:34.21,0:18:34.85,EN,,0,0,0,,AUDIENCE: Your name. Dialogue: 0,0:18:34.92,0:18:35.68,EN,,0,0,0,,PROFESSOR: Louder. Dialogue: 0,0:18:35.77,0:18:36.61,EN,,0,0,0,,AUDIENCE: Your name. Dialogue: 0,0:18:36.82,0:18:37.50,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:18:38.28,0:18:44.56,EN,,0,0,0,,What I'm showing you here is that the words of English are ambiguous. Dialogue: 0,0:18:45.50,0:18:50.76,EN,,0,0,0,,I was saying, say your name. Dialogue: 0,0:18:51.97,0:18:57.21,EN,,0,0,0,,I was also possibly saying say, your name. Dialogue: 0,0:19:00.72,0:19:02.98,EN,,0,0,0,,But that cannot be distinguished in speech. Dialogue: 0,0:19:03.89,0:19:08.01,EN,,0,0,0,,However, we do have a notation in writing, Dialogue: 0,0:19:08.18,0:19:12.46,EN,,0,0,0,,which is quotation for distinguishing these two possible meanings. Dialogue: 0,0:19:14.00,0:19:15.64,EN,,0,0,0,,In particular, over here, Dialogue: 0,0:19:16.49,0:19:20.84,EN,,0,0,0,,in Lisp we have a notation for distinguishing these meanings. Dialogue: 0,0:19:21.34,0:19:24.45,EN,,0,0,0,,If I were to just write a plus here, a plus symbol, Dialogue: 0,0:19:24.64,0:19:28.52,EN,,0,0,0,,I would be asking, is the first element of the expression, Dialogue: 0,0:19:29.06,0:19:33.61,EN,,0,0,0,,is the operator position of the expression, the addition operator? Dialogue: 0,0:19:34.65,0:19:35.54,EN,,0,0,0,,I don't know. Dialogue: 0,0:19:36.22,0:19:38.16,EN,,0,0,0,,I would have to have written the addition operator there, Dialogue: 0,0:19:39.37,0:19:40.44,EN,,0,0,0,,which I can't write. Dialogue: 0,0:19:41.34,0:19:45.88,EN,,0,0,0,,However, this way I'm asking, is this the symbolic object plus, Dialogue: 0,0:19:45.98,0:19:48.14,EN,,0,0,0,,which normally stands for the addition operator? Dialogue: 0,0:19:49.57,0:19:51.92,EN,,0,0,0,,That's what I want. That's the question I want to ask. Dialogue: 0,0:19:52.92,0:19:54.45,EN,,0,0,0,,Now before I go any further, Dialogue: 0,0:19:54.45,0:19:57.81,EN,,0,0,0,,I want to point out the quotation is a very complex concept, Dialogue: 0,0:19:58.85,0:20:01.84,EN,,0,0,0,,and adding it to a language causes a great deal of troubles. Dialogue: 0,0:20:03.57,0:20:05.04,EN,,0,0,0,,Consider the next slide. Dialogue: 0,0:20:06.38,0:20:09.49,EN,,0,0,0,,Here's a deduction which we should all agree with. Dialogue: 0,0:20:11.62,0:20:17.04,EN,,0,0,0,,We have, Alyssa is smart and Alyssa is George's mother. Dialogue: 0,0:20:17.40,0:20:20.60,EN,,0,0,0,,This is an equality, is. Dialogue: 0,0:20:22.13,0:20:26.30,EN,,0,0,0,,From those two, we can deduce that George's mother is smart. Dialogue: 0,0:20:27.32,0:20:33.16,EN,,0,0,0,,Because we can always substitute equals for equals in expressions. Dialogue: 0,0:20:34.09,0:20:35.16,EN,,0,0,0,,Or can we? Dialogue: 0,0:20:36.52,0:20:40.37,EN,,0,0,0,,Here's a case where we have "Chicago" has seven letters. Dialogue: 0,0:20:41.12,0:20:44.86,EN,,0,0,0,,The quotation means that I'm discussing the word Chicago, Dialogue: 0,0:20:44.86,0:20:46.86,EN,,0,0,0,,not what the word represents. Dialogue: 0,0:20:49.82,0:20:52.77,EN,,0,0,0,,Here I have that Chicago is the biggest city in Illinois. Dialogue: 0,0:20:54.61,0:20:55.80,EN,,0,0,0,,As a consequence of this, Dialogue: 0,0:20:55.80,0:20:59.09,EN,,0,0,0,,I would like to deduce that the biggest city in Illinois has seven letters. Dialogue: 0,0:20:59.32,0:21:01.06,EN,,0,0,0,,But that's manifestly false. Dialogue: 0,0:21:05.16,0:21:07.17,EN,,0,0,0,,Wow, it works. Dialogue: 0,0:21:09.29,0:21:12.24,EN,,0,0,0,,OK, so once we have things like that, Dialogue: 0,0:21:12.48,0:21:14.49,EN,,0,0,0,,our language gets much more complicated. Dialogue: 0,0:21:14.49,0:21:18.34,EN,,0,0,0,,Because it's no longer true that things we tend to like to do with languages, Dialogue: 0,0:21:18.34,0:21:20.76,EN,,0,0,0,,like substituting equals for equals and getting right answers, Dialogue: 0,0:21:21.29,0:21:23.50,EN,,0,0,0,,are going to work without being very careful. Dialogue: 0,0:21:24.49,0:21:27.34,EN,,0,0,0,,We can't substitute into what's called referentially opaque contexts, Dialogue: 0,0:21:27.89,0:21:32.64,EN,,0,0,0,,of which a quotation is the prototypical type of referentially opaque context. Dialogue: 0,0:21:33.17,0:21:35.28,EN,,0,0,0,,If you know what that means, you can consult a philosopher. Dialogue: 0,0:21:35.42,0:21:37.02,EN,,0,0,0,,Presumably there is one in the room. Dialogue: 0,0:21:37.53,0:21:41.32,EN,,0,0,0,,In any case, let's continue now, Dialogue: 0,0:21:41.32,0:21:44.98,EN,,0,0,0,,now that we at least have an operational understanding of a 2000-year-old issue Dialogue: 0,0:21:45.26,0:21:48.13,EN,,0,0,0,,that has to do with name, and mention, and all sorts of things like that. Dialogue: 0,0:21:52.32,0:22:01.60,EN,,0,0,0,,I have to define what I mean, how to make a sum of two things, an a1 and a2. Dialogue: 0,0:22:02.12,0:22:03.62,EN,,0,0,0,,And I'm going to do this very simply. Dialogue: 0,0:22:03.62,0:22:11.96,EN,,0,0,0,,It's a list of the symbol plus, and a1, and a2. Dialogue: 0,0:22:13.86,0:22:17.37,EN,,0,0,0,,And I can determine the first element. Dialogue: 0,0:22:21.84,0:22:25.32,EN,,0,0,0,,Define a1 to be cadr. Dialogue: 0,0:22:33.88,0:22:35.90,EN,,0,0,0,,I've just introduced another primitive. Dialogue: 0,0:22:36.17,0:22:39.10,EN,,0,0,0,,This is the car of the cdr of something. Dialogue: 0,0:22:39.80,0:22:44.53,EN,,0,0,0,,You might want to know why car and cdr are names of these primitives, Dialogue: 0,0:22:44.66,0:22:48.42,EN,,0,0,0,,and why they've survived, even though they're much better ideas like left and right. Dialogue: 0,0:22:48.76,0:22:50.44,EN,,0,0,0,,We could have called them things like that. Dialogue: 0,0:22:51.28,0:22:56.25,EN,,0,0,0,,Well, first of all, the names come from the fact that in the great past, when Lisp was invented, Dialogue: 0,0:22:56.36,0:23:00.80,EN,,0,0,0,,I suppose in '58 or something, it was on a 704 or something like that, Dialogue: 0,0:23:00.80,0:23:05.41,EN,,0,0,0,,which had a machine. It was a machine that had an address register and a decrement register. Dialogue: 0,0:23:05.41,0:23:08.17,EN,,0,0,0,,And these were the contents of the address register and the decrement register. Dialogue: 0,0:23:08.17,0:23:09.37,EN,,0,0,0,,So it's an historical accident. Dialogue: 0,0:23:09.64,0:23:11.28,EN,,0,0,0,,Now why have these names survived? Dialogue: 0,0:23:11.74,0:23:14.76,EN,,0,0,0,,It's because Lisp programmers like to talk to each other over the phone. Dialogue: 0,0:23:15.68,0:23:19.60,EN,,0,0,0,,And if you want to have a long sequence of cars and cdrs you might say, cdaddedr, Dialogue: 0,0:23:21.01,0:23:22.32,EN,,0,0,0,,which can be understood. Dialogue: 0,0:23:22.32,0:23:27.02,EN,,0,0,0,,But left of right or right of left is not so clear if you get good at it. Dialogue: 0,0:23:27.60,0:23:30.02,EN,,0,0,0,,So that's why we have these words. Dialogue: 0,0:23:30.54,0:23:34.14,EN,,0,0,0,,All of them up to four deep are defined typically in a Lisp system. Dialogue: 0,0:23:38.66,0:23:47.05,EN,,0,0,0,,A2 to be-- and, of course, you can see that if I looked at one of these expressions Dialogue: 0,0:23:47.36,0:23:52.14,EN,,0,0,0,,like the sum of 3 and 5, Dialogue: 0,0:23:52.58,0:24:10.45,EN,,0,0,0,,what that is is a list containing the symbol plus, and a number 3, and a number 5. Dialogue: 0,0:24:11.72,0:24:15.18,EN,,0,0,0,,Then the car is the symbol plus. Dialogue: 0,0:24:16.13,0:24:18.21,EN,,0,0,0,,The car of the cdr. Dialogue: 0,0:24:18.21,0:24:20.21,EN,,0,0,0,,Well I take the cdr and then I take the car. Dialogue: 0,0:24:20.21,0:24:22.21,EN,,0,0,0,,And that's how I get to the 3. That's the first argument. Dialogue: 0,0:24:22.52,0:24:25.69,EN,,0,0,0,,And the car of the cdr of the cdr gets me to this one, the 5. Dialogue: 0,0:24:28.69,0:24:33.66,EN,,0,0,0,,And similarly, of course, I can define what's going on with products. Dialogue: 0,0:24:35.22,0:24:36.56,EN,,0,0,0,,Let's do that very quickly. Dialogue: 0,0:24:48.97,0:24:50.64,EN,,0,0,0,,Is the expression a product? Dialogue: 0,0:24:51.05,0:24:54.69,EN,,0,0,0,,Yes if and if it's true, that's it's not atomic Dialogue: 0,0:25:01.41,0:25:14.14,EN,,0,0,0,,and it's EQ quote, the asterisk symbol, which is the operator for multiplication. Dialogue: 0,0:25:15.64,0:25:32.00,EN,,0,0,0,,Make product of an M1 and an M2 to be list, Dialogue: 0,0:25:34.42,0:25:39.30,EN,,0,0,0,,quote, the asterisk operation and M1 and M2. Dialogue: 0,0:25:40.82,0:25:56.81,EN,,0,0,0,,And I define M1 to be cadr and M2 to be caddr. Dialogue: 0,0:26:00.09,0:26:02.38,EN,,0,0,0,,You get to be a good Lisp programmer because you start talking that way. Dialogue: 0,0:26:02.53,0:26:05.53,EN,,0,0,0,,You can cdr thing down lists and cons them up and so on. Dialogue: 0,0:26:06.29,0:26:10.10,EN,,0,0,0,,Now, now that we have essentially a complete program for finding derivatives, Dialogue: 0,0:26:10.10,0:26:11.70,EN,,0,0,0,,you can add more rules if you like. Dialogue: 0,0:26:12.21,0:26:13.93,EN,,0,0,0,,What kind of behavior do we get out of it? Dialogue: 0,0:26:14.64,0:26:16.77,EN,,0,0,0,,I'll have to clear that x. Dialogue: 0,0:26:17.80,0:26:20.82,EN,,0,0,0,,Well, supposing I define foo here Dialogue: 0,0:26:22.16,0:26:30.38,EN,,0,0,0,,to be the sum of the product of ax square and bx plus c. Dialogue: 0,0:26:30.54,0:26:32.08,EN,,0,0,0,,That's the same thing we see here Dialogue: 0,0:26:32.08,0:26:36.36,EN,,0,0,0,,as the algebraic expression written in the more conventional notation over there. Dialogue: 0,0:26:37.84,0:26:41.60,EN,,0,0,0,,Well, the derivative of foo with respect to x, which we can see over here, Dialogue: 0,0:26:43.46,0:26:45.26,EN,,0,0,0,,is this horrible, horrendous mess. Dialogue: 0,0:26:46.16,0:26:49.22,EN,,0,0,0,,I would like it to be 2ax plus b. Dialogue: 0,0:26:50.68,0:26:53.44,EN,,0,0,0,,But it's not. It's equivalent to it. Dialogue: 0,0:26:54.58,0:26:55.22,EN,,0,0,0,,What is it? Dialogue: 0,0:26:55.97,0:26:59.96,EN,,0,0,0,,I have here, what do I have? Dialogue: 0,0:27:00.50,0:27:04.30,EN,,0,0,0,,I have the derivative of the product of x and x. Dialogue: 0,0:27:04.69,0:27:10.53,EN,,0,0,0,,Over here is, of course, the sum of x times 1 and 1 times x. Dialogue: 0,0:27:12.73,0:27:15.66,EN,,0,0,0,,Now, well, it's the first times the derivative of the second plus the second times the derivative of the first. It's right. Dialogue: 0,0:27:17.22,0:27:28.37,EN,,0,0,0,,That's 2x of course. a times 2x is 2ax plus 0X square doesn't count plus B over here plus a bunch of 0's. Dialogue: 0,0:27:28.96,0:27:30.12,EN,,0,0,0,,Well the answer is right. Dialogue: 0,0:27:30.12,0:27:35.14,EN,,0,0,0,,But I give people take off points on an exam for that, sadly enough. Dialogue: 0,0:27:35.56,0:27:37.26,EN,,0,0,0,,Let's worry about that in the next segment. Dialogue: 0,0:27:37.68,0:27:38.61,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:27:42.77,0:27:43.45,EN,,0,0,0,,Yes? Dialogue: 0,0:27:43.89,0:27:46.69,EN,,0,0,0,,AUDIENCE: If you had left the quote when you put the plus, Dialogue: 0,0:27:46.69,0:27:50.82,EN,,0,0,0,,then would that be referring to the procedure plus Dialogue: 0,0:27:50.82,0:27:55.42,EN,,0,0,0,,and could you do a comparison between that procedure and some other procedure if you wanted to? Dialogue: 0,0:27:56.16,0:27:57.08,EN,,0,0,0,,PROFESSOR: Yes. Good question. Dialogue: 0,0:27:57.45,0:28:02.26,EN,,0,0,0,,If I had left this quotation off at this point, Dialogue: 0,0:28:03.88,0:28:07.13,EN,,0,0,0,,Okay? If I had left that quotation off at that point, Dialogue: 0,0:28:07.33,0:28:14.20,EN,,0,0,0,,then I would be referring here to the procedure which is the thing that plus is defined to be. Dialogue: 0,0:28:15.38,0:28:24.88,EN,,0,0,0,,And indeed, I could compare some procedures with each other for identity. Dialogue: 0,0:28:24.88,0:28:27.45,EN,,0,0,0,,Now what that means is not clear right now. Dialogue: 0,0:28:27.85,0:28:29.37,EN,,0,0,0,,I don't like to think about it. Dialogue: 0,0:28:29.89,0:28:32.40,EN,,0,0,0,,Because I don't know exactly what it would need to compare procedures. Dialogue: 0,0:28:32.40,0:28:34.40,EN,,0,0,0,,There are reasons why that may make no sense at all. Dialogue: 0,0:28:35.52,0:28:37.53,EN,,0,0,0,,However, the symbols, we understand. Dialogue: 0,0:28:38.54,0:28:40.56,EN,,0,0,0,,And so that's why I put that quote in. Dialogue: 0,0:28:41.16,0:28:43.70,EN,,0,0,0,,I want to talk about the symbol that's apparent on the page. Dialogue: 0,0:28:46.16,0:28:46.92,EN,,0,0,0,,Any other questions? Dialogue: 0,0:28:48.52,0:28:51.86,EN,,0,0,0,,OK. Thank you. Let's take a break. Dialogue: 0,0:28:55.12,0:29:00.66,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:29:00.68,0:29:04.34,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:29:04.34,0:29:06.68,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:29:12.21,0:29:19.17,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:29:20.09,0:29:24.14,Declare,,0,0,0,,{\an2\fad(500,500)}Symbolic Differentiation: Quotation Dialogue: 0,0:29:29.86,0:29:30.92,EN,,0,0,0,,PROFESSOR: Well, let's see. Dialogue: 0,0:29:31.46,0:29:37.76,EN,,0,0,0,,We've just developed a fairly plausible program for computing the derivatives of algebraic expressions. Dialogue: 0,0:29:38.20,0:29:41.56,EN,,0,0,0,,It's an incomplete program, if you would like to add more rules. Dialogue: 0,0:29:42.13,0:29:47.74,EN,,0,0,0,,And perhaps you might extend it to deal with uses of addition with any number of arguments Dialogue: 0,0:29:47.76,0:29:49.70,EN,,0,0,0,,and multiplication with any of the number of arguments. Dialogue: 0,0:29:49.89,0:29:51.38,EN,,0,0,0,,And that's all rather easy. Dialogue: 0,0:29:52.73,0:29:56.93,EN,,0,0,0,,However, there was a little fly in that ointment. Dialogue: 0,0:29:57.48,0:30:02.37,EN,,0,0,0,,We go back to this slide. Dialogue: 0,0:30:02.94,0:30:08.60,EN,,0,0,0,,We see that the expressions that we get are rather bad. Dialogue: 0,0:30:08.88,0:30:11.01,EN,,0,0,0,,This is a rather bad expression. Dialogue: 0,0:30:11.46,0:30:13.10,EN,,0,0,0,,How do we get such an expression? Dialogue: 0,0:30:13.84,0:30:15.50,EN,,0,0,0,,Why do we have that expression? Dialogue: 0,0:30:16.84,0:30:18.74,EN,,0,0,0,,Let's look at this expression in some detail. Dialogue: 0,0:30:18.92,0:30:20.76,EN,,0,0,0,,Let's find out where all the pieces come from. Dialogue: 0,0:30:21.69,0:30:24.56,EN,,0,0,0,,As we see here, we have a sum-- Dialogue: 0,0:30:24.56,0:30:26.56,EN,,0,0,0,,just what I showed you at the end of the last time-- Dialogue: 0,0:30:27.12,0:30:29.09,EN,,0,0,0,,of X times 1 plus 1 time X. Dialogue: 0,0:30:29.58,0:30:31.38,EN,,0,0,0,,That is a derivative of this product. Dialogue: 0,0:30:32.52,0:30:36.41,EN,,0,0,0,,The product of a times that, where a does not depend upon x, Dialogue: 0,0:30:36.41,0:30:38.41,EN,,0,0,0,,and therefore is constant with respect to x, Dialogue: 0,0:30:39.04,0:30:44.53,EN,,0,0,0,,is this sum, which goes from here all the way through here and through here. Dialogue: 0,0:30:44.80,0:30:48.89,EN,,0,0,0,,Because it is the first thing times the derivative of the second Dialogue: 0,0:30:49.57,0:30:54.45,EN,,0,0,0,,plus the derivative of the first times the second Dialogue: 0,0:30:54.66,0:30:59.06,EN,,0,0,0,,as the program we wrote on the blackboard indicated we should do. Dialogue: 0,0:31:00.65,0:31:05.36,EN,,0,0,0,,And, of course, the product of bx over here Dialogue: 0,0:31:05.49,0:31:09.81,EN,,0,0,0,,manifests itself as B times 1 plus 0 times X Dialogue: 0,0:31:10.81,0:31:16.06,EN,,0,0,0,,because we see that B does not depend upon X. Dialogue: 0,0:31:16.46,0:31:18.56,EN,,0,0,0,,And so the derivative of B is this 0, Dialogue: 0,0:31:18.77,0:31:21.48,EN,,0,0,0,,and the derivative of X with respect itself is the 1. Dialogue: 0,0:31:23.06,0:31:28.64,EN,,0,0,0,,And, of course, the derivative of the sums over here turn into these two sums of the derivatives of the parts. Dialogue: 0,0:31:29.37,0:31:33.50,EN,,0,0,0,,So what we're seeing here is exactly the thing I was trying to tell you about Dialogue: 0,0:31:33.66,0:31:35.89,EN,,0,0,0,,with Fibonacci numbers a while ago, Dialogue: 0,0:31:37.77,0:31:39.49,EN,,0,0,0,,that the form of the process Dialogue: 0,0:31:41.38,0:31:46.44,EN,,0,0,0,,is expanded as low as from the local rules that you see in the procedure, Dialogue: 0,0:31:48.05,0:31:52.57,EN,,0,0,0,,that the procedure represents a set of local rules for the expansion of this process. Dialogue: 0,0:31:53.36,0:32:00.09,EN,,0,0,0,,And here, the process left behind some stuff, which is the answer. Dialogue: 0,0:32:00.25,0:32:06.26,EN,,0,0,0,,And it was constructed by the walk it takes of the tree structure, which is the expression. Dialogue: 0,0:32:08.41,0:32:12.61,EN,,0,0,0,,So every part in the answer we see here derives from some part of the problem. Dialogue: 0,0:32:14.46,0:32:17.78,EN,,0,0,0,,Now, we can look at, for example, the derivative of foo, Dialogue: 0,0:32:17.78,0:32:19.65,EN,,0,0,0,,which is ax square plus bx plus c, Dialogue: 0,0:32:19.84,0:32:23.05,EN,,0,0,0,,with respect to other things, like here, for example, Dialogue: 0,0:32:24.14,0:32:27.48,EN,,0,0,0,,we can see that the derivative of foo with respect to a. Dialogue: 0,0:32:28.10,0:32:31.77,EN,,0,0,0,,And it's very similar. It's, in fact, the identical algebraic expression, Dialogue: 0,0:32:32.45,0:32:35.24,EN,,0,0,0,,except for the fact that theses 0's and 1's are in different places. Dialogue: 0,0:32:36.06,0:32:38.60,EN,,0,0,0,,Because the only degree of freedom we have in this tree walk Dialogue: 0,0:32:38.97,0:32:43.85,EN,,0,0,0,,is what's constant with respect to the variable we're taking the derivative with respect to Dialogue: 0,0:32:44.28,0:32:45.81,EN,,0,0,0,,and what's the same variable. Dialogue: 0,0:32:48.26,0:32:52.09,EN,,0,0,0,,In other words, if we go back to this blackboard and we look, Dialogue: 0,0:32:52.65,0:32:57.49,EN,,0,0,0,,we have no choice what to do when we take the derivative of the sum or a product. Dialogue: 0,0:32:58.08,0:33:04.48,EN,,0,0,0,,The only interesting place here is, is the expression the variable, Dialogue: 0,0:33:04.80,0:33:10.10,EN,,0,0,0,,or is the expression a constant with respect to that variable for very, very small expressions? Dialogue: 0,0:33:10.36,0:33:12.41,EN,,0,0,0,,In which case we get various 1's and 0's, Dialogue: 0,0:33:12.69,0:33:14.49,EN,,0,0,0,,which if we go back to this slide, Dialogue: 0,0:33:15.12,0:33:18.16,EN,,0,0,0,,we can see that the 0's that appear here, for example, Dialogue: 0,0:33:18.37,0:33:22.74,EN,,0,0,0,,this 1 over here in derivative of foo with respect to A, Dialogue: 0,0:33:22.96,0:33:24.86,EN,,0,0,0,,which gets us an X square, Dialogue: 0,0:33:24.96,0:33:32.53,EN,,0,0,0,,because that 1 gets the multiply of X and X into the answer, that 1 is 0. Dialogue: 0,0:33:32.64,0:33:34.89,EN,,0,0,0,,Over here, we're not taking the derivative of foo with respect to c. Dialogue: 0,0:33:36.78,0:33:39.30,EN,,0,0,0,,But the shapes of these expressions are the same. Dialogue: 0,0:33:40.54,0:33:43.96,EN,,0,0,0,,See all those shapes. They're the same. Dialogue: 0,0:33:50.37,0:33:52.28,EN,,0,0,0,,Well is there anything wrong with our rules? Dialogue: 0,0:33:53.58,0:33:55.02,EN,,0,0,0,,No. They're the right rules. Dialogue: 0,0:33:56.12,0:33:57.77,EN,,0,0,0,,We've been through this one before. Dialogue: 0,0:33:58.06,0:34:03.53,EN,,0,0,0,,One of the things you're going to begin to discover is that there aren't too many good ideas. Dialogue: 0,0:34:06.32,0:34:09.74,EN,,0,0,0,,When we were looking at rational numbers yesterday, Dialogue: 0,0:34:12.12,0:34:14.48,EN,,0,0,0,,the problem was that we got 6/8 rather then 3/4. Dialogue: 0,0:34:14.97,0:34:16.49,EN,,0,0,0,,The answer was unsimplified. Dialogue: 0,0:34:18.09,0:34:20.90,EN,,0,0,0,,The problem, of course, is very similar. Dialogue: 0,0:34:21.18,0:34:25.41,EN,,0,0,0,,There are things I'd like to be identical by simplification that don't become identical. Dialogue: 0,0:34:27.57,0:34:31.89,EN,,0,0,0,,And yet the rules for doing addition a multiplication of rational numbers were correct. Dialogue: 0,0:34:33.97,0:34:37.41,EN,,0,0,0,,So the way we might solve this problem is do the thing we did last time, which always works. Dialogue: 0,0:34:37.78,0:34:39.89,EN,,0,0,0,,If something worked last time it ought to work again. Dialogue: 0,0:34:40.53,0:34:42.05,EN,,0,0,0,,It's changed representation. Dialogue: 0,0:34:43.13,0:34:46.44,EN,,0,0,0,,Perhaps in the representation we could put in a simplification step Dialogue: 0,0:34:47.88,0:34:49.78,EN,,0,0,0,,that produces a simplified representation. Dialogue: 0,0:34:50.17,0:34:51.73,EN,,0,0,0,,This may not always work, of course. Dialogue: 0,0:34:52.49,0:34:54.14,EN,,0,0,0,,I'm not trying to say that it always works. Dialogue: 0,0:34:55.12,0:35:00.44,EN,,0,0,0,,But it's one of the pieces of artillery we have in our war against complexity. Dialogue: 0,0:35:01.46,0:35:03.85,EN,,0,0,0,,You see, because we solved our problem very carefully. Dialogue: 0,0:35:04.30,0:35:07.20,EN,,0,0,0,,What we've done, is we've divided the world in several parts. Dialogue: 0,0:35:07.57,0:35:08.73,EN,,0,0,0,,There are derivatives rules Dialogue: 0,0:35:11.32,0:35:15.80,EN,,0,0,0,,and general rules for algebra of some sort at this level of detail. Dialogue: 0,0:35:16.38,0:35:21.22,EN,,0,0,0,,and i have an abstraction barrier. Dialogue: 0,0:35:22.48,0:35:33.49,EN,,0,0,0,,And i have the representation of the algebraic expressions, list structure. Dialogue: 0,0:35:37.33,0:35:42.56,EN,,0,0,0,,And in this barrier, I have the interface procedures. Dialogue: 0,0:35:43.25,0:35:49.82,EN,,0,0,0,,I have constant, and things like same-var. Dialogue: 0,0:35:54.60,0:35:58.72,EN,,0,0,0,,I have things like sum, make-sum. Dialogue: 0,0:36:02.22,0:36:05.57,EN,,0,0,0,,I have A1, A2. Dialogue: 0,0:36:06.60,0:36:08.58,EN,,0,0,0,,I have products and things like that, Dialogue: 0,0:36:08.74,0:36:11.90,EN,,0,0,0,,all the other things I might need for various kinds of algebraic expressions. Dialogue: 0,0:36:12.94,0:36:19.14,EN,,0,0,0,,Making this barrier allows me to arbitrarily change the representation Dialogue: 0,0:36:20.14,0:36:23.20,EN,,0,0,0,,without changing the rules that are written in terms of that representation. Dialogue: 0,0:36:25.04,0:36:29.08,EN,,0,0,0,,So if I can make the problem go away by changing representation, Dialogue: 0,0:36:30.38,0:36:34.52,EN,,0,0,0,,the composition of the problem into these two parts has helped me a great deal. Dialogue: 0,0:36:35.65,0:36:37.54,EN,,0,0,0,,So let's take a very simple case of this. Dialogue: 0,0:36:38.82,0:36:40.08,EN,,0,0,0,,What was one of the problems? Dialogue: 0,0:36:40.26,0:36:43.61,EN,,0,0,0,,Let's go back to this transparency again. Dialogue: 0,0:36:44.50,0:36:47.34,EN,,0,0,0,,And we see here, oh yes, there's horrible things Dialogue: 0,0:36:47.62,0:36:51.86,EN,,0,0,0,,like here is the sum of an expression and 0. Dialogue: 0,0:36:53.14,0:36:56.66,EN,,0,0,0,,Well that's no reason to think of it as anything other than the expression itself. Dialogue: 0,0:36:57.21,0:37:01.90,EN,,0,0,0,,Why should the summation operation have made up this edition? Dialogue: 0,0:37:03.38,0:37:04.57,EN,,0,0,0,,It can be smarter than that. Dialogue: 0,0:37:05.56,0:37:10.08,EN,,0,0,0,,Or here, for example, is a multiplication of something by 1. Dialogue: 0,0:37:11.16,0:37:12.29,EN,,0,0,0,,It's another thing like that. Dialogue: 0,0:37:12.86,0:37:15.68,EN,,0,0,0,,Or here is a product of something with 0, which is certainly 0. Dialogue: 0,0:37:17.86,0:37:19.52,EN,,0,0,0,,So we won't have to make this construction. Dialogue: 0,0:37:21.44,0:37:22.62,EN,,0,0,0,,So why don't we just do that? Dialogue: 0,0:37:23.66,0:37:27.96,EN,,0,0,0,,We need to change the way the representation works, almost here. Dialogue: 0,0:37:37.40,0:37:41.84,EN,,0,0,0,,Make-sum to be. Dialogue: 0,0:37:42.05,0:37:43.76,EN,,0,0,0,,Well, now it's not something so simple. Dialogue: 0,0:37:44.00,0:37:50.40,EN,,0,0,0,,I'm not going to make a list containing the symbol plus and things unless I need to. Dialogue: 0,0:37:51.72,0:37:53.05,EN,,0,0,0,,Well, what are the possibilities? Dialogue: 0,0:37:54.56,0:37:58.53,EN,,0,0,0,,If...I have some sort of cases here. Dialogue: 0,0:37:59.38,0:38:08.20,EN,,0,0,0,,If I have numbers, if a1 is a number-- Dialogue: 0,0:38:09.05,0:38:10.93,EN,,0,0,0,,and here's another primitive I've just introduced, Dialogue: 0,0:38:10.93,0:38:13.18,EN,,0,0,0,,it's possible to tell whether something's number-- Dialogue: 0,0:38:15.38,0:38:23.82,EN,,0,0,0,,and if number A2, meaning they're not symbolic expressions, Dialogue: 0,0:38:24.45,0:38:26.20,EN,,0,0,0,,then why not do the addition now? Dialogue: 0,0:38:26.45,0:38:29.92,EN,,0,0,0,,The result is just a plus of A1 and A2. Dialogue: 0,0:38:32.32,0:38:33.98,EN,,0,0,0,,I'm not asking if these represent numbers. Dialogue: 0,0:38:33.98,0:38:35.98,EN,,0,0,0,,Of course all of these symbols represent numbers. Dialogue: 0,0:38:37.33,0:38:41.22,EN,,0,0,0,,I'm talking about whether the one I've got is the number 3 right now. Dialogue: 0,0:38:43.40,0:38:44.40,EN,,0,0,0,,And, for example, Dialogue: 0,0:38:48.77,0:38:59.61,EN,,0,0,0,,supposing A1 is a number, and it's equal to 0, Dialogue: 0,0:39:04.20,0:39:06.38,EN,,0,0,0,,well then the answer is just A2. Dialogue: 0,0:39:06.93,0:39:08.68,EN,,0,0,0,,There is no reason to make anything up. Dialogue: 0,0:39:10.98,0:39:23.41,EN,,0,0,0,,And if A2 is a number, and equal A2 0, Dialogue: 0,0:39:27.16,0:39:28.90,EN,,0,0,0,,then the result is A1. Dialogue: 0,0:39:30.04,0:39:33.65,EN,,0,0,0,,And only if I can't figure out something better to do with this situation, Dialogue: 0,0:39:34.13,0:39:35.61,EN,,0,0,0,,well, I can construct a list. Dialogue: 0,0:39:37.86,0:39:42.86,EN,,0,0,0,,Otherwise I want the representation to be the list Dialogue: 0,0:39:44.13,0:39:52.33,EN,,0,0,0,,containing the quoted symbol plus, and A1, and A2. Dialogue: 0,0:39:58.66,0:40:01.65,EN,,0,0,0,,And, of course, a very similar thing can be done for products. Dialogue: 0,0:40:03.01,0:40:05.04,EN,,0,0,0,,And I think I'll avoid boring you with them. Dialogue: 0,0:40:05.44,0:40:07.24,EN,,0,0,0,,I was going to write it on the blackboard. Dialogue: 0,0:40:07.65,0:40:09.80,EN,,0,0,0,,I don't think it's necessary. You know what to do. Dialogue: 0,0:40:10.76,0:40:11.61,EN,,0,0,0,,It's very simple. Dialogue: 0,0:40:12.86,0:40:19.89,EN,,0,0,0,,But now, let's just see the kind of results we get out of changing our program in this way. Dialogue: 0,0:40:21.68,0:40:27.88,EN,,0,0,0,,Well, here's the derivatives after having just changed the constructors for expressions. Dialogue: 0,0:40:28.98,0:40:32.21,EN,,0,0,0,,The same foo, aX square plus bX plus c, Dialogue: 0,0:40:33.28,0:40:40.70,EN,,0,0,0,,and what I get is nothing more than the derivative of that is 2aX plus B. Dialogue: 0,0:40:40.70,0:40:42.10,EN,,0,0,0,,Well, it's not completely simplified. Dialogue: 0,0:40:42.60,0:40:44.53,EN,,0,0,0,,I would like to collect common terms and sums. Dialogue: 0,0:40:45.06,0:40:46.08,EN,,0,0,0,,Well, that's more work. Dialogue: 0,0:40:47.12,0:40:51.86,EN,,0,0,0,,And, of course, programs to do this sort of thing are huge and complicated. Dialogue: 0,0:40:52.28,0:40:55.28,EN,,0,0,0,,Algebraic simplification, it's a very complicated mess. Dialogue: 0,0:40:56.37,0:41:00.13,EN,,0,0,0,,There's a very famous program you may have heard of called Maxima developed at MIT in the past, Dialogue: 0,0:41:00.42,0:41:03.14,EN,,0,0,0,,which is 5,000 pages of Lisp code, Dialogue: 0,0:41:03.92,0:41:06.50,EN,,0,0,0,,mostly the algebraic simplification operations. Dialogue: 0,0:41:08.08,0:41:12.21,EN,,0,0,0,,There we see the derivative of foo. Dialogue: 0,0:41:12.21,0:41:16.86,EN,,0,0,0,,In fact, alias is something I wouldn't take off more than 1 point for on an elementary calculus class. Dialogue: 0,0:41:18.38,0:41:22.49,EN,,0,0,0,,And the derivative of foo with respect to a, well it's gone down to X times X, Dialogue: 0,0:41:22.80,0:41:23.80,EN,,0,0,0,,which isn't so bad. Dialogue: 0,0:41:24.74,0:41:27.53,EN,,0,0,0,,And the derivative of foo with respect to b is just X itself. Dialogue: 0,0:41:28.06,0:41:30.12,EN,,0,0,0,,And the derivative of foo with respect to c comes out 1. Dialogue: 0,0:41:30.70,0:41:32.04,EN,,0,0,0,,So I'm pretty pleased with this. Dialogue: 0,0:41:34.10,0:41:39.01,EN,,0,0,0,,What you've seen is, of course, a little bit contrived, carefully organized example Dialogue: 0,0:41:39.56,0:41:42.60,EN,,0,0,0,,to show you how we can manipulate algebraic expressions, Dialogue: 0,0:41:42.96,0:41:47.93,EN,,0,0,0,,how we do that abstractly in terms of abstract syntax rather than concrete syntax Dialogue: 0,0:41:49.21,0:41:56.29,EN,,0,0,0,,and how we can use the abstraction to control what goes on in building these expressions. Dialogue: 0,0:41:57.80,0:42:00.41,EN,,0,0,0,,But the real story isn't just such a simple thing as that. Dialogue: 0,0:42:01.00,0:42:04.45,EN,,0,0,0,,The real story is, in fact, that I'm manipulating these expressions. Dialogue: 0,0:42:04.45,0:42:06.72,EN,,0,0,0,,And the expressions are the same expressions-- Dialogue: 0,0:42:06.72,0:42:07.97,EN,,0,0,0,,going back to the slide-- Dialogue: 0,0:42:08.08,0:42:10.52,EN,,0,0,0,,as the ones that are Lisp expressions. Dialogue: 0,0:42:12.02,0:42:12.97,EN,,0,0,0,,There's a pun here. Dialogue: 0,0:42:13.82,0:42:21.49,EN,,0,0,0,,I've chosen my representation to be the same as the representation in my language of similar things. Dialogue: 0,0:42:22.89,0:42:26.52,EN,,0,0,0,,By doing so, I've invoked a necessity. Dialogue: 0,0:42:26.90,0:42:30.34,EN,,0,0,0,,I created the necessity to have things like quotation Dialogue: 0,0:42:30.97,0:42:38.17,EN,,0,0,0,,because of the fact that my language is capable of writing expressions that talk about expressions of the language. Dialogue: 0,0:42:39.76,0:42:43.22,EN,,0,0,0,,I need to have something that says, this is an expression I'm talking about Dialogue: 0,0:42:43.76,0:42:46.13,EN,,0,0,0,,rather than this expression is talking about something, Dialogue: 0,0:42:47.20,0:42:48.44,EN,,0,0,0,,and I want to talk about that. Dialogue: 0,0:42:51.34,0:42:55.36,EN,,0,0,0,,So quotation stops and says, I'm talking about this expression itself. Dialogue: 0,0:42:57.97,0:43:00.85,EN,,0,0,0,,Now, given that power, Dialogue: 0,0:43:01.58,0:43:03.82,EN,,0,0,0,,if I can manipulate expressions of the language, Dialogue: 0,0:43:04.80,0:43:09.00,EN,,0,0,0,,I can begin to build even much more powerful layers upon layers of languages. Dialogue: 0,0:43:09.77,0:43:12.64,EN,,0,0,0,,Because I can write languages that not only are embedded in Lisp Dialogue: 0,0:43:13.46,0:43:14.80,EN,,0,0,0,,or whatever language you start with, Dialogue: 0,0:43:15.26,0:43:17.76,EN,,0,0,0,,but languages that are completely different, Dialogue: 0,0:43:18.58,0:43:22.24,EN,,0,0,0,,that are just, if we say, interpreted in Lisp or something like that. Dialogue: 0,0:43:23.17,0:43:25.46,EN,,0,0,0,,We'll get to understand those words more in the future. Dialogue: 0,0:43:26.56,0:43:32.09,EN,,0,0,0,,But right now I just want to leave you with the fact that we've hit a line Dialogue: 0,0:43:32.36,0:43:34.98,EN,,0,0,0,,which gives us tremendous power. Dialogue: 0,0:43:36.00,0:43:37.82,EN,,0,0,0,,And this point we've bought a sledgehammer. Dialogue: 0,0:43:38.17,0:43:40.92,EN,,0,0,0,,We have to be careful to what flies when we apply it. Dialogue: 0,0:43:42.17,0:43:43.00,EN,,0,0,0,,Thank you. Dialogue: 0,0:00:00.00,0:00:02.32,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:02.57,0:00:11.10,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:02.57,0:00:11.10,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}字幕&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.57,0:00:11.10,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}后期&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.57,0:00:11.10,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.57,0:00:11.10,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:11.24,0:00:14.46,Declare,,0,0,0,,{\an2\fad(500,500)}符号化求导系统,引用 Dialogue: 0,0:00:19.10,0:00:23.41,Default,,0,0,0,,教授:嗯 Harold教授讲解了如何构造健壮的系统 Dialogue: 0,0:00:23.80,0:00:26.17,Default,,0,0,0,,关键点就是 Dialogue: 0,0:00:26.81,0:00:30.20,Default,,0,0,0,,我想你们大多还没吃透其中的要点 Dialogue: 0,0:00:30.20,0:00:33.77,Default,,0,0,0,,要点就是 为了让系统具有健壮性 Dialogue: 0,0:00:33.93,0:00:36.48,Default,,0,0,0,,应该让它对小变化不敏感 Dialogue: 0,0:00:36.60,0:00:37.37,Default,,0,0,0,,也就是说 Dialogue: 0,0:00:37.37,0:00:40.90,Default,,0,0,0,,问题中的小改变只会导致解决方案的小改动 Dialogue: 0,0:00:41.32,0:00:42.90,Default,,0,0,0,,系统应该是连续的 Dialogue: 0,0:00:42.90,0:00:45.94,Default,,0,0,0,,在问题空间中 解的空间是连续的 Dialogue: 0,0:00:46.25,0:00:48.76,Default,,0,0,0,,Harold教授给你们解释过 Dialogue: 0,0:00:49.46,0:00:54.78,Default,,0,0,0,,与其在问题分解出的子问题上 求解具体问题 Dialogue: 0,0:00:55.08,0:00:56.78,Default,,0,0,0,,你不如解决一类问题 Dialogue: 0,0:00:56.78,0:01:00.40,Default,,0,0,0,,也就是你想要解决的具体问题的“邻居” Dialogue: 0,0:01:01.40,0:01:04.76,Default,,0,0,0,,解决之道便是在该层次上构造一门语言 Dialogue: 0,0:01:04.76,0:01:10.33,Default,,0,0,0,,使得我们可以用这门语言来表述这类问题 Dialogue: 0,0:01:11.37,0:01:15.09,Default,,0,0,0,,因此 当着手解决的问题再发生变动时 Dialogue: 0,0:01:15.09,0:01:19.29,Default,,0,0,0,,通常 你只需要在已构造好的解决方案上做出微小改动 Dialogue: 0,0:01:19.29,0:01:22.26,Default,,0,0,0,,因为在你所考虑的层次上 Dialogue: 0,0:01:22.26,0:01:24.26,Default,,0,0,0,,有一门语言可以表达 Dialogue: 0,0:01:24.80,0:01:28.14,Default,,0,0,0,,类似问题的各种解法 Dialogue: 0,0:01:30.04,0:01:33.74,Default,,0,0,0,,呃... 这是一个重要思想的萌芽 Dialogue: 0,0:01:34.40,0:01:38.61,Default,,0,0,0,,该思想的重要性也使得计算机科学比 Dialogue: 0,0:01:38.61,0:01:42.37,Default,,0,0,0,,其它大多数工程学科还要强大 Dialogue: 0,0:01:43.38,0:01:44.73,Default,,0,0,0,,目前为止 我们学习的是 Dialogue: 0,0:01:44.73,0:01:48.78,Default,,0,0,0,,类似于 如何使用语言内置元素 Dialogue: 0,0:01:49.26,0:01:53.36,Default,,0,0,0,,当然 内置元素的力量一部分来源于 Dialogue: 0,0:01:54.12,0:01:56.86,Default,,0,0,0,,像这个一样的过程 我昨天给你们展示过了 Dialogue: 0,0:01:57.37,0:02:02.13,Default,,0,0,0,,这里 是一份求导程序 昨天给你们描述过了 Dialogue: 0,0:02:02.13,0:02:05.92,Default,,0,0,0,,这个过程以一个过程为参数 Dialogue: 0,0:02:06.00,0:02:07.92,Default,,0,0,0,,并返回一个过程 Dialogue: 0,0:02:09.61,0:02:12.65,Default,,0,0,0,,用这样的东西棒极了 Dialogue: 0,0:02:12.65,0:02:14.65,Default,,0,0,0,,你可以像创建PUSH组合子那样构造 Dialogue: 0,0:02:14.65,0:02:16.86,Default,,0,0,0,,可以像上节课看到的哪些奇妙东西那样 Dialogue: 0,0:02:17.68,0:02:20.54,Default,,0,0,0,,现在 我要来打个太极 Dialogue: 0,0:02:21.56,0:02:25.90,Default,,0,0,0,,这个程序混淆了过程和数据 Dialogue: 0,0:02:26.56,0:02:27.81,Default,,0,0,0,,虽然程度不算太重 Dialogue: 0,0:02:28.42,0:02:30.90,Default,,0,0,0,,而我们将要严重地混淆两者 Dialogue: 0,0:02:31.18,0:02:32.44,Default,,0,0,0,,最好的做法就是 Dialogue: 0,0:02:32.44,0:02:37.62,Default,,0,0,0,,参与到过程自身所描述的代数表达式的操作中 Dialogue: 0,0:02:39.73,0:02:45.58,Default,,0,0,0,,所以 这里我不会讨论这张幻灯片上的东西 Dialogue: 0,0:02:45.89,0:02:49.72,Default,,0,0,0,,一个通过操作过程的求导程序 Dialogue: 0,0:02:49.72,0:02:51.94,Default,,0,0,0,,这只是一个数值化方法而已 Dialogue: 0,0:02:51.94,0:02:58.93,Default,,0,0,0,,你们所看到的是 通过数值方法来近似的求导程序 Dialogue: 0,0:02:59.29,0:03:00.44,Default,,0,0,0,,也就是这里的东西了 Dialogue: 0,0:03:00.86,0:03:04.93,Default,,0,0,0,,事实上 我想讨论的是这些东西 Dialogue: 0,0:03:06.05,0:03:11.33,Default,,0,0,0,,这是一份从微积分书中摘录的法则 Dialogue: 0,0:03:12.09,0:03:16.17,Default,,0,0,0,,这对表达式求导的法则 Dialogue: 0,0:03:16.70,0:03:20.58,Default,,0,0,0,,只不过是用代数语言书写的 Dialogue: 0,0:03:21.64,0:03:24.41,Default,,0,0,0,,法则说 常数的导数是0 Dialogue: 0,0:03:25.13,0:03:29.09,Default,,0,0,0,,而代表你所讨论的那个数的变量导数为1 Dialogue: 0,0:03:29.32,0:03:31.93,Default,,0,0,0,,常数乘以函数的导数 Dialogue: 0,0:03:32.09,0:03:34.37,Default,,0,0,0,,其值是常数的值乘以函数导数的值 Dialogue: 0,0:03:34.77,0:03:36.04,Default,,0,0,0,,就是这个意思 Dialogue: 0,0:03:38.05,0:03:41.38,Default,,0,0,0,,这些都是精确的表达式 而非数值近似 Dialogue: 0,0:03:42.96,0:03:44.52,Default,,0,0,0,,我们还能编写程序吗? Dialogue: 0,0:03:44.52,0:03:52.24,Default,,0,0,0,,事实上 编写处理这些表达式的程序非常容易 Dialogue: 0,0:03:56.38,0:03:59.52,Default,,0,0,0,,让我们仔细地看看这些法则 Dialogue: 0,0:04:01.08,0:04:05.22,Default,,0,0,0,,你们曾经在初等微积分课上学过这些法则了 Dialogue: 0,0:04:05.98,0:04:12.12,Default,,0,0,0,,你们知道 微积分中对多元表达式求导很容易 Dialogue: 0,0:04:12.53,0:04:16.05,Default,,0,0,0,,在微积分课上 你们也知道计算积分不容易 Dialogue: 0,0:04:16.98,0:04:19.37,Default,,0,0,0,,虽然积分和求导相对 Dialogue: 0,0:04:19.52,0:04:21.28,Default,,0,0,0,,它俩互为逆运算 Dialogue: 0,0:04:21.61,0:04:23.30,Default,,0,0,0,,但它们有同样的法则 Dialogue: 0,0:04:24.16,0:04:29.68,Default,,0,0,0,,但这些法则中又有什么特殊的东西 Dialogue: 0,0:04:29.68,0:04:33.65,Default,,0,0,0,,使得求导容易 求积分就困难呢? Dialogue: 0,0:04:34.85,0:04:36.98,Default,,0,0,0,,我们浅显地想一想 Dialogue: 0,0:04:37.40,0:04:38.38,Default,,0,0,0,,仔细考察法则 Dialogue: 0,0:04:39.36,0:04:43.06,Default,,0,0,0,,对于每条法则来说 你求导数时的方向 Dialogue: 0,0:04:43.06,0:04:44.80,Default,,0,0,0,,这个箭头的方向 Dialogue: 0,0:04:46.68,0:04:49.16,Default,,0,0,0,,法则的左边与你的表达式相匹配 Dialogue: 0,0:04:49.16,0:04:53.05,Default,,0,0,0,,法则的右边就是表达式的导数 Dialogue: 0,0:04:54.02,0:04:55.65,Default,,0,0,0,,箭头是这个方向的 Dialogue: 0,0:04:57.37,0:05:00.45,Default,,0,0,0,,每条法则中 Dialogue: 0,0:05:01.24,0:05:03.72,Default,,0,0,0,,法则右边的表达式 Dialogue: 0,0:05:03.72,0:05:06.56,Default,,0,0,0,,都是求导过程中的子表达式 Dialogue: 0,0:05:06.56,0:05:10.29,Default,,0,0,0,,都是左边式子的合法子表达式 Dialogue: 0,0:05:10.60,0:05:13.25,Default,,0,0,0,,这里 我们发现 和的导数 Dialogue: 0,0:05:13.92,0:05:16.13,Default,,0,0,0,,也就是左边式子的导数 Dialogue: 0,0:05:16.13,0:05:18.38,Default,,0,0,0,,就是两部分导数之和 Dialogue: 0,0:05:20.08,0:05:24.49,Default,,0,0,0,,法则从左至右的方向是“归约规则” Dialogue: 0,0:05:25.02,0:05:26.61,Default,,0,0,0,,问题变简单了 Dialogue: 0,0:05:27.56,0:05:31.48,Default,,0,0,0,,我把一个复杂的问题 转化成了许多小点儿的问题 Dialogue: 0,0:05:32.44,0:05:35.76,Default,,0,0,0,,然后把结果组合起来 这里用递归可以完美地解决 Dialogue: 0,0:05:36.58,0:05:40.85,Default,,0,0,0,,但如果我从另外的方向来思考 Dialogue: 0,0:05:41.81,0:05:45.13,Default,,0,0,0,,如果我想求积分的话 你会发现有很多问题 Dialogue: 0,0:05:45.24,0:05:49.09,Default,,0,0,0,,就比如 如果我想求一个和的积分 Dialogue: 0,0:05:49.21,0:05:50.81,Default,,0,0,0,,就会匹配多条法则 Dialogue: 0,0:05:50.81,0:05:52.10,Default,,0,0,0,,这条匹配 Dialogue: 0,0:05:52.48,0:05:53.65,Default,,0,0,0,,这条也匹配 Dialogue: 0,0:05:54.81,0:05:57.09,Default,,0,0,0,,我不知道该用哪个——它们之间可能不一样 Dialogue: 0,0:05:57.70,0:06:00.00,Default,,0,0,0,,我得考察两者的不同之处 Dialogue: 0,0:06:00.25,0:06:03.64,Default,,0,0,0,,所以 在这个方向上 表达式变复杂了 Dialogue: 0,0:06:04.53,0:06:06.30,Default,,0,0,0,,当表达式变复杂时 Dialogue: 0,0:06:06.30,0:06:10.56,Default,,0,0,0,,就没法保证我所选的路径一定能终止了 Dialogue: 0,0:06:10.94,0:06:13.46,Default,,0,0,0,,因为唯一的可能是偶然的约分 Dialogue: 0,0:06:14.24,0:06:18.05,Default,,0,0,0,,这也就是为什么 积分是一种复杂的搜索 而难以完成 Dialogue: 0,0:06:19.12,0:06:20.96,Default,,0,0,0,,现在我不想处理这么复杂的东西 Dialogue: 0,0:06:21.49,0:06:23.06,Default,,0,0,0,,我们先来讨论求导数 Dialogue: 0,0:06:24.14,0:06:28.13,Default,,0,0,0,,好吧 我就假设你们都大致了解这些法则了 Dialogue: 0,0:06:28.78,0:06:31.88,Default,,0,0,0,,让我们来看看能不能用程序表达这些法则 Dialogue: 0,0:06:32.22,0:06:33.72,Default,,0,0,0,,这应该很容易 Dialogue: 0,0:06:34.89,0:06:36.21,Default,,0,0,0,,信手拈来 Dialogue: 0,0:06:36.69,0:06:39.29,Default,,0,0,0,,因为 我给你们展示的是“归约规则” Dialogue: 0,0:06:39.29,0:06:41.29,Default,,0,0,0,,这样用递归来编写会比较合适 Dialogue: 0,0:06:43.08,0:06:45.72,Default,,0,0,0,,当然 对每条法则来说就是一种情况 Dialogue: 0,0:06:46.66,0:06:47.78,Default,,0,0,0,,我们做“分情况分析” Dialogue: 0,0:06:48.58,0:06:50.36,Default,,0,0,0,,我就这么写了 Dialogue: 0,0:06:52.88,0:06:57.69,Default,,0,0,0,,当然 我得先让大家达成共识 对吧? Dialogue: 0,0:06:57.69,0:07:00.33,Default,,0,0,0,,你们应该意识到到我可以表示这些代数式 Dialogue: 0,0:07:00.68,0:07:03.88,Default,,0,0,0,,我可以从中抽取式子 也可以将它们组合起来 Dialogue: 0,0:07:04.24,0:07:06.49,Default,,0,0,0,,我们发明了表结构来解决这个问题 Dialogue: 0,0:07:07.52,0:07:09.14,Default,,0,0,0,,但现在我们不必关心 Dialogue: 0,0:07:09.66,0:07:12.45,Default,,0,0,0,,现在 我要编写一个程序来封装这些法则 Dialogue: 0,0:07:12.76,0:07:15.85,Default,,0,0,0,,但它不依赖于代数表达式的表示法 Dialogue: 0,0:07:20.42,0:07:28.84,Default,,0,0,0,,(DERIV EXP VAR)表示表达式EXP关于变量VAR的导数 Dialogue: 0,0:07:30.50,0:07:33.08,Default,,0,0,0,,这和函数的导数是不一样的 Dialogue: 0,0:07:34.82,0:07:38.61,Default,,0,0,0,,那个是我们上节课看到的数值近似 Dialogue: 0,0:07:39.00,0:07:40.82,Default,,0,0,0,,并不能看到函数内部 Dialogue: 0,0:07:40.82,0:07:41.89,Default,,0,0,0,,它只是一个数值 Dialogue: 0,0:07:43.09,0:07:45.18,Default,,0,0,0,,表达式的导数也是一个表达式 Dialogue: 0,0:07:45.74,0:07:47.85,Default,,0,0,0,,因此 这只是一个语法问题 Dialogue: 0,0:07:48.29,0:07:51.62,Default,,0,0,0,,我们今天要做的大多数工作 就是讨论语法 Dialogue: 0,0:07:52.33,0:07:54.12,Default,,0,0,0,,表达式的语法或类似 Dialogue: 0,0:07:54.70,0:07:55.93,Default,,0,0,0,,首先要做“分情况分析” Dialogue: 0,0:07:57.50,0:08:01.08,Default,,0,0,0,,任何时候我们处理复杂事物 需要递归求解时 Dialogue: 0,0:08:01.08,0:08:02.64,Default,,0,0,0,,我们很可能需要“按情况分析” Dialogue: 0,0:08:03.62,0:08:05.16,Default,,0,0,0,,通常都是这样开始的 Dialogue: 0,0:08:05.16,0:08:07.40,Default,,0,0,0,,复杂的问题都是用“按情况分析” Dialogue: 0,0:08:08.08,0:08:09.97,Default,,0,0,0,,那么 有哪些可能(的情况)呢? Dialogue: 0,0:08:09.97,0:08:12.53,Default,,0,0,0,,第一条法则说 如果你遇到一个常数 Dialogue: 0,0:08:16.50,0:08:17.50,Default,,0,0,0,,这里 我就是在判断 Dialogue: 0,0:08:17.50,0:08:22.22,Default,,0,0,0,,表达式EXP是否为给定变量VAR的常数(常量表达式) Dialogue: 0,0:08:24.90,0:08:27.08,Default,,0,0,0,,是的话 结果就是0 Dialogue: 0,0:08:27.50,0:08:30.10,Default,,0,0,0,,因为导数表征的是某物的变化率 Dialogue: 0,0:08:31.76,0:08:32.65,Default,,0,0,0,,然而 Dialogue: 0,0:08:32.89,0:08:40.69,Default,,0,0,0,,如果我求导的表达式 与我关心的变量有关 Dialogue: 0,0:08:41.72,0:08:50.42,Default,,0,0,0,,如果判定表达式和变量相同 Dialogue: 0,0:08:51.14,0:08:54.52,Default,,0,0,0,,那么关于变量VAR的表达式EXP的变化率就是1 Dialogue: 0,0:08:55.50,0:08:56.54,Default,,0,0,0,,它俩相同 结果是1 Dialogue: 0,0:08:58.90,0:09:00.77,Default,,0,0,0,,当然 还可能有其它的可能性 Dialogue: 0,0:09:01.33,0:09:03.14,Default,,0,0,0,,比如说 它可能是一个和式 Dialogue: 0,0:09:03.86,0:09:05.88,Default,,0,0,0,,呃 我现在还完全知道该如何表示和式 Dialogue: 0,0:09:06.09,0:09:08.25,Default,,0,0,0,,事实上我可以 只是我还没有告诉你们 Dialogue: 0,0:09:10.34,0:09:11.78,Default,,0,0,0,,如果表达式是和式 Dialogue: 0,0:09:12.48,0:09:14.48,Default,,0,0,0,,我就假想有一种方式可以判别(和式) Dialogue: 0,0:09:15.30,0:09:19.44,Default,,0,0,0,,这里 我要做一个表达式的类型分派 Dialogue: 0,0:09:20.77,0:09:23.57,Default,,0,0,0,,这是在构建语言时绝对必要的 Dialogue: 0,0:09:24.72,0:09:26.37,Default,,0,0,0,,因为语言由不同的表达式构成 Dialogue: 0,0:09:26.48,0:09:27.54,Default,,0,0,0,,我们马上就将看到 Dialogue: 0,0:09:27.84,0:09:31.02,Default,,0,0,0,,如何用更强大的方法 用语言去构建语言 Dialogue: 0,0:09:32.53,0:09:34.02,Default,,0,0,0,,表达式是和式吗? Dialogue: 0,0:09:35.45,0:09:38.82,Default,,0,0,0,,如果是的话 很好 我们已经知道和式的求导法则了 Dialogue: 0,0:09:38.82,0:09:41.33,Default,,0,0,0,,即是各部分导数之和 Dialogue: 0,0:09:42.13,0:09:44.32,Default,,0,0,0,,其中一个叫做加数 另一个叫做被加数 Dialogue: 0,0:09:44.32,0:09:46.80,Default,,0,0,0,,黑板上没那么多空间写这么长的名字了 Dialogue: 0,0:09:46.80,0:09:48.40,Default,,0,0,0,,我就姑且把它们叫做 A1和A2 Dialogue: 0,0:09:49.04,0:09:50.37,Default,,0,0,0,,把它们求和 Dialogue: 0,0:09:53.53,0:09:55.68,Default,,0,0,0,,(意义不明) Dialogue: 0,0:09:57.14,0:10:01.09,Default,,0,0,0,,是叫做被除数和除数一类的么? Dialogue: 0,0:10:01.65,0:10:08.48,Default,,0,0,0,,将A1的导数...加上 Dialogue: 0,0:10:08.48,0:10:13.29,Default,,0,0,0,,这是关于变量VAR的表达式的加数 Dialogue: 0,0:10:14.84,0:10:22.76,Default,,0,0,0,,与A2的导数相加 Dialogue: 0,0:10:24.12,0:10:28.25,Default,,0,0,0,,这两个参数的和 变量是VAR Dialogue: 0,0:10:32.36,0:10:34.93,Default,,0,0,0,,我们知道还有一条乘法的求导法则 Dialogue: 0,0:10:35.20,0:10:37.44,Default,,0,0,0,,也就是说 如果表达式是乘式 Dialogue: 0,0:10:43.21,0:10:46.10,Default,,0,0,0,,顺便说下 当你定义过程时 有个好习惯 Dialogue: 0,0:10:46.96,0:10:48.32,Default,,0,0,0,,就是在定义谓词时 Dialogue: 0,0:10:48.85,0:10:50.96,Default,,0,0,0,,将谓词名以问号结尾 Dialogue: 0,0:10:51.08,0:10:52.89,Default,,0,0,0,,问号本身不代表什么 Dialogue: 0,0:10:53.10,0:10:54.50,Default,,0,0,0,,但这是俗成的约定 Dialogue: 0,0:10:54.61,0:10:58.94,Default,,0,0,0,,这是人们之间约定的接口 以方便他人阅读你的脚本 Dialogue: 0,0:11:00.05,0:11:01.96,Default,,0,0,0,,我希望你在写程序的时候 Dialogue: 0,0:11:01.96,0:11:03.73,Default,,0,0,0,,当你定义谓词的时候 Dialogue: 0,0:11:04.01,0:11:05.77,Default,,0,0,0,,就是那些返回TRUE或FALSE的过程 Dialogue: 0,0:11:05.94,0:11:07.84,Default,,0,0,0,,你应该使它们的名字以问号结尾 Dialogue: 0,0:11:08.02,0:11:10.34,Default,,0,0,0,,这对Lisp无异 但对人类友好 Dialogue: 0,0:11:11.62,0:11:13.14,Default,,0,0,0,,我需要求和 Dialogue: 0,0:11:13.14,0:11:17.49,Default,,0,0,0,,因为积的导数就是... Dialogue: 0,0:11:17.94,0:11:19.64,Default,,0,0,0,,M1*DERIV(M2) Dialogue: 0,0:11:19.66,0:11:20.70,Default,,0,0,0,,+DERIV(M1)*M2 Dialogue: 0,0:11:23.54,0:11:27.06,Default,,0,0,0,,两者加起来 Dialogue: 0,0:11:29.64,0:11:38.33,Default,,0,0,0,,求积... 呃 就用表达式中的M1来表示(被乘数)好了 Dialogue: 0,0:11:39.85,0:11:48.97,Default,,0,0,0,,表达式中M2关于变量VAR的导数 Dialogue: 0,0:11:51.90,0:12:06.28,Default,,0,0,0,,以及 M1关于变量VAR的导数乘以 Dialogue: 0,0:12:07.10,0:12:11.92,Default,,0,0,0,,M1是这里的被乘数 Dialogue: 0,0:12:13.32,0:12:18.05,Default,,0,0,0,,乘数是表达式中的M2 Dialogue: 0,0:12:20.64,0:12:24.89,Default,,0,0,0,,求积完毕、求和完毕、乘式分析完毕 Dialogue: 0,0:12:24.96,0:12:28.02,Default,,0,0,0,,当然 在这里我可以添加更多的情况 Dialogue: 0,0:12:28.32,0:12:30.82,Default,,0,0,0,,微积分书中的完整法则 Dialogue: 0,0:12:34.80,0:12:39.45,Default,,0,0,0,,我们就是这么来封装这些法则的 Dialogue: 0,0:12:41.53,0:12:43.90,Default,,0,0,0,,如你所见 我们这里用到了大量的“按愿望思维” Dialogue: 0,0:12:44.54,0:12:47.56,Default,,0,0,0,,我们还没有说这些(表达式)是如何表示的 Dialogue: 0,0:12:48.46,0:12:51.92,Default,,0,0,0,,现在 一旦我将其定为我的一套法则 Dialogue: 0,0:12:52.52,0:12:55.20,Default,,0,0,0,,我想是时候考虑表示法了 Dialogue: 0,0:12:55.66,0:12:56.69,Default,,0,0,0,,我们来拿捏拿捏 Dialogue: 0,0:12:57.96,0:13:00.00,Default,,0,0,0,,首先 我要用到一种“双关”思想 Dialogue: 0,0:13:00.90,0:13:02.12,Default,,0,0,0,,这种“双关”思想非常重要 Dialogue: 0,0:13:02.74,0:13:06.56,Default,,0,0,0,,它是一种强有力思想的关键 Dialogue: 0,0:13:09.62,0:13:14.41,Default,,0,0,0,,如果我想表达诸如和、积、差、商的东西 Dialogue: 0,0:13:15.22,0:13:18.62,Default,,0,0,0,,为什么不用和我程序一样的语言呢? Dialogue: 0,0:13:20.50,0:13:23.64,Default,,0,0,0,,我程序中 代数表达式是形如 Dialogue: 0,0:13:23.98,0:13:30.45,Default,,0,0,0,,(+ (* A (* X X)) Dialogue: 0,0:13:32.60,0:13:33.80,Default,,0,0,0,,和与之类似的 Dialogue: 0,0:13:34.28,0:13:38.50,Default,,0,0,0,,(* B X)以及C Dialogue: 0,0:13:38.50,0:13:39.97,Default,,0,0,0,,把它们加起来 Dialogue: 0,0:13:40.77,0:13:44.09,Default,,0,0,0,,现在 我的过程还不能处理多元参数 Dialogue: 0,0:13:44.93,0:13:48.46,Default,,0,0,0,,(+ (* B X) C) Dialogue: 0,0:13:51.42,0:13:52.44,Default,,0,0,0,,这是表结构 Dialogue: 0,0:13:54.12,0:13:55.74,Default,,0,0,0,,这么做很棒 是因为 Dialogue: 0,0:13:55.90,0:13:58.33,Default,,0,0,0,,是因为这些对象都有一种性质 Dialogue: 0,0:13:58.92,0:14:01.53,Default,,0,0,0,,我知道它们的CAR部分是什么 Dialogue: 0,0:14:01.96,0:14:03.21,Default,,0,0,0,,CAR部分就是运算符 Dialogue: 0,0:14:03.92,0:14:06.38,Default,,0,0,0,,运算数是相继的CDR部分 Dialogue: 0,0:14:07.22,0:14:10.36,Default,,0,0,0,,也就是不断取表CDR部分的CAR部分 Dialogue: 0,0:14:12.48,0:14:13.88,Default,,0,0,0,,这样就使它很方便了 Dialogue: 0,0:14:14.01,0:14:16.40,Default,,0,0,0,,我需要去解析它 但它已经帮我完成了 Dialogue: 0,0:14:17.42,0:14:20.01,Default,,0,0,0,,我利用了Lisp中的内建元素 Dialogue: 0,0:14:22.66,0:14:23.77,Default,,0,0,0,,举个例子 Dialogue: 0,0:14:25.08,0:14:33.97,Default,,0,0,0,,我们用表结构来表示我所暗示的表示法吧! Dialogue: 0,0:14:35.25,0:14:38.34,Default,,0,0,0,,我需要定义一些东西 这都暗含在这种表示法中 Dialogue: 0,0:14:38.54,0:14:40.90,Default,,0,0,0,,比如如何判定是否为常量 Dialogue: 0,0:14:41.21,0:14:42.30,Default,,0,0,0,,又怎么判断是同一个变量 Dialogue: 0,0:14:42.40,0:14:45.04,Default,,0,0,0,,我们先完成这些吧 都相当简单 Dialogue: 0,0:14:45.78,0:14:47.70,Default,,0,0,0,,这里 我要介绍一些基本过程 Dialogue: 0,0:14:48.60,0:14:50.50,Default,,0,0,0,,因为它们都是与表结构相关的 Dialogue: 0,0:14:51.98,0:14:53.46,Default,,0,0,0,,CONSTANT?谓词定义为 Dialogue: 0,0:15:02.25,0:15:04.29,Default,,0,0,0,,我所谓的常量 Dialogue: 0,0:15:04.29,0:15:07.73,Default,,0,0,0,,表达式关于变量VAR是一个常量 Dialogue: 0,0:15:09.05,0:15:11.60,Default,,0,0,0,,是一些简单的表达式 Dialogue: 0,0:15:11.60,0:15:14.46,Default,,0,0,0,,我无法再细化它 但它也不是我们关心的变量 Dialogue: 0,0:15:16.58,0:15:18.78,Default,,0,0,0,,我无法分解它 但它也不是我们关心的变量 Dialogue: 0,0:15:18.90,0:15:25.12,Default,,0,0,0,,这也并不是说 一些复杂的表达式就不是常量表达式 Dialogue: 0,0:15:25.20,0:15:28.92,Default,,0,0,0,,我只是想用这种方式考察基本常量 Dialogue: 0,0:15:29.74,0:15:33.41,Default,,0,0,0,,因此 这个谓词是几个条件的合取 Dialogue: 0,0:15:34.02,0:15:37.82,Default,,0,0,0,,AND语句允许用户组合返回TRUE或者FALSE的谓词 Dialogue: 0,0:15:38.62,0:15:46.82,Default,,0,0,0,,表达式是原子的么?--原子表达式不可以再被细分 Dialogue: 0,0:15:46.82,0:15:48.53,Default,,0,0,0,,它没有CAR部分和CDR部分 Dialogue: 0,0:15:49.45,0:15:50.21,Default,,0,0,0,,它不是表 Dialogue: 0,0:15:50.76,0:15:52.94,Default,,0,0,0,,系统中内建有特殊测试 Dialogue: 0,0:15:53.97,0:16:04.66,Default,,0,0,0,,并且表达式EXP和变量VAR在EQ?的语义下不相等 Dialogue: 0,0:16:06.82,0:16:13.36,Default,,0,0,0,,我用不能被分解的符号来表示变量 Dialogue: 0,0:16:13.90,0:16:17.22,Default,,0,0,0,,比如'X 'Y 和像这样的 Dialogue: 0,0:16:19.74,0:16:22.37,Default,,0,0,0,,当然 像这样的组合式就可以再被细分 Dialogue: 0,0:16:24.74,0:16:46.40,Default,,0,0,0,,(SAME-VAR? EXP VAR)定义为 Dialogue: 0,0:16:46.40,0:16:48.40,Default,,0,0,0,,实际上 一条原子表达式…… Dialogue: 0,0:16:48.77,0:16:59.61,Default,,0,0,0,,该表达式与讨论变量相同 Dialogue: 0,0:17:07.90,0:17:11.68,Default,,0,0,0,,我不想深入讨论这些过程内部 Dialogue: 0,0:17:12.52,0:17:15.56,Default,,0,0,0,,把这些当作基本过程 Dialogue: 0,0:17:15.77,0:17:17.08,Default,,0,0,0,,这无关紧要 Dialogue: 0,0:17:17.78,0:17:21.74,Default,,0,0,0,,我用的是语言内置的功能 Dialogue: 0,0:17:22.42,0:17:24.04,Default,,0,0,0,,我并不关心这些(具体实现) Dialogue: 0,0:17:24.42,0:17:26.04,Default,,0,0,0,,现在 我们要如何处理和式呢? Dialogue: 0,0:17:26.60,0:17:28.80,Default,,0,0,0,,啊哈 好戏就要上演了 Dialogue: 0,0:17:28.98,0:17:33.12,Default,,0,0,0,,和式不是原子的 它以‘+’号打头 Dialogue: 0,0:17:35.16,0:17:36.17,Default,,0,0,0,,就是这个意思 Dialogue: 0,0:17:36.65,0:17:39.77,Default,,0,0,0,,这里 我定义 Dialogue: 0,0:17:45.46,0:17:57.77,Default,,0,0,0,,表达式为和式 当它不是原子表达式 Dialogue: 0,0:18:04.57,0:18:15.45,Default,,0,0,0,,并且它的开头 表达式的CAR部分是个‘+’号 Dialogue: 0,0:18:19.74,0:18:24.04,Default,,0,0,0,,我将要引入一个你们从未见过的东西--这个引号 Dialogue: 0,0:18:25.89,0:18:28.22,Default,,0,0,0,,我这里为什么要用引号呢? Dialogue: 0,0:18:29.48,0:18:30.52,Default,,0,0,0,,教授:说你的名字 Dialogue: 0,0:18:30.68,0:18:31.41,Default,,0,0,0,,观众:Susanna Dialogue: 0,0:18:31.41,0:18:32.01,Default,,0,0,0,,教授:大点声儿 Dialogue: 0,0:18:32.01,0:18:32.72,Default,,0,0,0,,观众:Susanna Dialogue: 0,0:18:33.25,0:18:34.21,Default,,0,0,0,,教授:说“你的名字” Dialogue: 0,0:18:34.21,0:18:34.85,Default,,0,0,0,,观众:“你的名字” Dialogue: 0,0:18:34.92,0:18:35.68,Default,,0,0,0,,教授:大点声儿 Dialogue: 0,0:18:35.77,0:18:36.61,Default,,0,0,0,,观众:“你的名字” Dialogue: 0,0:18:36.82,0:18:37.50,Default,,0,0,0,,教授:对了 Dialogue: 0,0:18:38.28,0:18:44.56,Default,,0,0,0,,在这里我想告诉大家 英语词汇是有歧义的 Dialogue: 0,0:18:45.50,0:18:50.76,Default,,0,0,0,,我可能说 “说你的名字” Dialogue: 0,0:18:51.97,0:18:57.21,Default,,0,0,0,,我也可能说 “说‘你的名字’” Dialogue: 0,0:19:00.72,0:19:02.98,Default,,0,0,0,,光从说话上还无法分辨 Dialogue: 0,0:19:03.89,0:19:08.01,Default,,0,0,0,,然而书面上 我们有专门的记号--引号 Dialogue: 0,0:19:08.18,0:19:12.46,Default,,0,0,0,,用来区别这两种可能的意思 Dialogue: 0,0:19:14.00,0:19:15.64,Default,,0,0,0,,具体来说 这里 Dialogue: 0,0:19:16.49,0:19:20.84,Default,,0,0,0,,在Lisp中有用于区别这些语义的记号 Dialogue: 0,0:19:21.34,0:19:24.45,Default,,0,0,0,,如果我只是写下一个加号 Dialogue: 0,0:19:24.64,0:19:28.52,Default,,0,0,0,,我会问系统 表达式的首元素 Dialogue: 0,0:19:29.06,0:19:33.61,Default,,0,0,0,,也就是表达式的运算符 是加运算符(一个过程)么? Dialogue: 0,0:19:34.65,0:19:35.54,Default,,0,0,0,,我并不知道 Dialogue: 0,0:19:36.22,0:19:38.16,Default,,0,0,0,,我本应该在那里写一个加运算符的 Dialogue: 0,0:19:39.37,0:19:40.44,Default,,0,0,0,,但我无法那样做 Dialogue: 0,0:19:41.34,0:19:45.88,Default,,0,0,0,,而这种方式则是问 这个符号对象是否为 Dialogue: 0,0:19:45.98,0:19:48.14,Default,,0,0,0,,代表加运算符的符号 Dialogue: 0,0:19:49.57,0:19:51.92,Default,,0,0,0,,这才是我想要问和知道的问题 Dialogue: 0,0:19:52.92,0:19:54.45,Default,,0,0,0,,在我们深入讨论之前 Dialogue: 0,0:19:54.45,0:19:57.81,Default,,0,0,0,,我想要指出 “引用”是一个复杂的概念 Dialogue: 0,0:19:58.85,0:20:01.84,Default,,0,0,0,,语言中引入这个概念将会造成许多麻烦 Dialogue: 0,0:20:03.57,0:20:05.04,Default,,0,0,0,,请看下面这张幻灯片 Dialogue: 0,0:20:06.38,0:20:09.49,Default,,0,0,0,,这里这个推论没有问题 Dialogue: 0,0:20:11.62,0:20:17.04,Default,,0,0,0,,这是说 Alyssa聪明而Alyssa是George的妈妈 Dialogue: 0,0:20:17.40,0:20:20.60,Default,,0,0,0,,通过IS建立了一个等式 Dialogue: 0,0:20:22.13,0:20:26.30,Default,,0,0,0,,我们可以从这两个陈述推论出 George妈妈很聪明 Dialogue: 0,0:20:27.32,0:20:33.16,Default,,0,0,0,,这是因为我们总可以在表达式中等价替换 Dialogue: 0,0:20:34.09,0:20:35.16,Default,,0,0,0,,真是这样吗? Dialogue: 0,0:20:36.52,0:20:40.37,Default,,0,0,0,,这个例子说 “Chicago”有七个字母 Dialogue: 0,0:20:41.12,0:20:44.86,Default,,0,0,0,,引用则是强调我讨论的是单词“Chicago” Dialogue: 0,0:20:44.86,0:20:46.86,Default,,0,0,0,,而不是单词所代表的意思 Dialogue: 0,0:20:49.82,0:20:52.77,Default,,0,0,0,,这里说 Chicago是Illinois州最大的城市 Dialogue: 0,0:20:54.61,0:20:55.80,Default,,0,0,0,,而(代换的)结果是…… Dialogue: 0,0:20:55.80,0:20:59.09,Default,,0,0,0,,我可能会得到 Illinois州最大的城市有七个字母 Dialogue: 0,0:20:59.32,0:21:01.06,Default,,0,0,0,,这显然是错的 Dialogue: 0,0:21:05.16,0:21:07.17,Default,,0,0,0,,喔!手写笔好使了 Dialogue: 0,0:21:09.29,0:21:12.24,Default,,0,0,0,,所以 一旦我们有了(引用)这样的东西 Dialogue: 0,0:21:12.48,0:21:14.49,Default,,0,0,0,,我们的语言就会变得复杂 Dialogue: 0,0:21:14.49,0:21:18.34,Default,,0,0,0,,因为我们对于语言的一些操作就不再正确 Dialogue: 0,0:21:18.34,0:21:20.76,Default,,0,0,0,,比如通过等价代换来得到正确答案 Dialogue: 0,0:21:21.29,0:21:23.50,Default,,0,0,0,,如果不小心地操作就会出错 Dialogue: 0,0:21:24.49,0:21:27.34,Default,,0,0,0,,在一个引用不透明的上下文中 我们无法进行代换 Dialogue: 0,0:21:27.89,0:21:32.64,Default,,0,0,0,,引用就是引用不透明上下文的典型 Dialogue: 0,0:21:33.17,0:21:35.28,Default,,0,0,0,,如果你知道那是什么意思……你可以成为一位哲学家 Dialogue: 0,0:21:35.42,0:21:37.02,Default,,0,0,0,,或许我们之中就有一位 Dialogue: 0,0:21:37.53,0:21:41.32,Default,,0,0,0,,言归正传 我们继续 Dialogue: 0,0:21:41.32,0:21:44.98,Default,,0,0,0,,现在我们对一个有2000年历史的问题至少有了操作上的理解 Dialogue: 0,0:21:45.26,0:21:48.13,Default,,0,0,0,,关于名称、提及和等等类似的问题 Dialogue: 0,0:21:52.32,0:22:01.60,Default,,0,0,0,,我得定义如何把两个数加起来 (DEFINE (MAKE-SUM A1 A2)) Dialogue: 0,0:22:02.12,0:22:03.62,Default,,0,0,0,,我简单实现一下 Dialogue: 0,0:22:03.62,0:22:11.96,Default,,0,0,0,,'+、A1、A2构成列表 Dialogue: 0,0:22:13.86,0:22:17.37,Default,,0,0,0,,我可以决定如何取出第一个元素 Dialogue: 0,0:22:21.84,0:22:25.32,Default,,0,0,0,,(DEFINE A1 CADR) Dialogue: 0,0:22:33.88,0:22:35.90,Default,,0,0,0,,这里又给大家介绍了一个基本过程 Dialogue: 0,0:22:36.17,0:22:39.10,Default,,0,0,0,,这个是取出某物CDR部分的CAR部分 Dialogue: 0,0:22:39.80,0:22:44.53,Default,,0,0,0,,大家或许会好奇 这些基本过程为什么叫做CAR和CDR Dialogue: 0,0:22:44.66,0:22:48.42,Default,,0,0,0,,而且传承了下来 尽管叫做LEFT和RIGHT会好一点 Dialogue: 0,0:22:48.76,0:22:50.44,Default,,0,0,0,,我们本可以那样叫的 Dialogue: 0,0:22:51.28,0:22:56.25,Default,,0,0,0,,呃 其实 这个名字来自于很久以前 当发明Lisp时 Dialogue: 0,0:22:56.36,0:23:00.80,Default,,0,0,0,,我想大概是58年的样子 是在类似于704之类的机子上实现的 Dialogue: 0,0:23:00.80,0:23:05.41,Default,,0,0,0,,这个机器有个地址寄存器和减量寄存器 Dialogue: 0,0:23:05.41,0:23:08.17,Default,,0,0,0,,而这些就是地址寄存器和减量寄存器的值 Dialogue: 0,0:23:08.17,0:23:09.37,Default,,0,0,0,,所以这是历史遗留问题 Dialogue: 0,0:23:09.64,0:23:11.28,Default,,0,0,0,,但是这些名字为什么又延续下来了呢? Dialogue: 0,0:23:11.74,0:23:14.76,Default,,0,0,0,,这是因为Lisp程序员喜欢用电话交流 Dialogue: 0,0:23:15.68,0:23:19.60,Default,,0,0,0,,要是你有一长串的CAR和CDR序列 你就可能说“CDADDEDR” Dialogue: 0,0:23:21.01,0:23:22.32,Default,,0,0,0,,这是可以理解的 Dialogue: 0,0:23:22.32,0:23:27.02,Default,,0,0,0,,但是左边的右边的右边的左边就不是那么清楚了 Dialogue: 0,0:23:27.60,0:23:30.02,Default,,0,0,0,,这就是我们为什么有这些黑话 Dialogue: 0,0:23:30.54,0:23:34.14,Default,,0,0,0,,典型的Lisp系统 默认定义到第四层 Dialogue: 0,0:23:38.66,0:23:47.05,Default,,0,0,0,,而定义A2为……当然 如果我们考察这些表达式中的一个 Dialogue: 0,0:23:47.36,0:23:52.14,Default,,0,0,0,,比如(+ 3 5) Dialogue: 0,0:23:52.58,0:24:10.45,Default,,0,0,0,,这个实际上是一个包含有'+、数3和数5的表 Dialogue: 0,0:24:11.72,0:24:15.18,Default,,0,0,0,,表的CAR部分是'+ Dialogue: 0,0:24:16.13,0:24:18.21,Default,,0,0,0,,CDR部分的CAR部分 Dialogue: 0,0:24:18.21,0:24:20.21,Default,,0,0,0,,也就是先取CDR部分 然后再取CAR部分 Dialogue: 0,0:24:20.21,0:24:22.21,Default,,0,0,0,,这就是我如何取得3的 也就是第一个参数 Dialogue: 0,0:24:22.52,0:24:25.69,Default,,0,0,0,,CDR的CDR部分的CAR部分 就是这个……数5 Dialogue: 0,0:24:28.69,0:24:33.66,Default,,0,0,0,,当然类似地 对于乘式我可以这样定义 Dialogue: 0,0:24:35.22,0:24:36.56,Default,,0,0,0,,我快速地演示一下 Dialogue: 0,0:24:48.97,0:24:50.64,Default,,0,0,0,,(DEFINE (PRODUCT? EXP)) Dialogue: 0,0:24:51.05,0:24:54.69,Default,,0,0,0,,如果它不是原子的 而且 Dialogue: 0,0:25:01.41,0:25:14.14,Default,,0,0,0,,EXP的CAR部分与用于表示乘法的符号'*在 EQ?的语义下相等 Dialogue: 0,0:25:15.64,0:25:32.00,Default,,0,0,0,,(DEFINE (MAKE-PRODUCT M1 M2)) Dialogue: 0,0:25:34.42,0:25:39.30,Default,,0,0,0,,(LIST '* M1 M2) Dialogue: 0,0:25:40.82,0:25:56.81,Default,,0,0,0,,并定义M1为CADR M2为CADDR Dialogue: 0,0:26:00.09,0:26:02.38,Default,,0,0,0,,当你说行话的时候 你就上道了 Dialogue: 0,0:26:02.53,0:26:05.53,Default,,0,0,0,,你可以取表的CDR 也可以把它们组合起来 Dialogue: 0,0:26:06.29,0:26:10.10,Default,,0,0,0,,现在 我们有了原理上完整的求导程序了 Dialogue: 0,0:26:10.10,0:26:11.70,Default,,0,0,0,,如果需要的话 你也可以添加更多的规则 Dialogue: 0,0:26:12.21,0:26:13.93,Default,,0,0,0,,它又要怎么用呢? Dialogue: 0,0:26:14.64,0:26:16.77,Default,,0,0,0,,我先把这个笔迹清了 Dialogue: 0,0:26:17.80,0:26:20.82,Default,,0,0,0,,恩 假设我在这里定义FOO为 Dialogue: 0,0:26:22.16,0:26:30.38,Default,,0,0,0,,定义FOO为A*X^2+B*X+C Dialogue: 0,0:26:30.54,0:26:32.08,Default,,0,0,0,,跟我们这里看到的是一样的 Dialogue: 0,0:26:32.08,0:26:36.36,Default,,0,0,0,,这里是用更习见的记号书写的代数表达式 Dialogue: 0,0:26:37.84,0:26:41.60,Default,,0,0,0,,那么 表达式FOO关于X的导数 结果在这里 Dialogue: 0,0:26:43.46,0:26:45.26,Default,,0,0,0,,真是乱得一团糟 Dialogue: 0,0:26:46.16,0:26:49.22,Default,,0,0,0,,我期望答案是2*A*X+B Dialogue: 0,0:26:50.68,0:26:53.44,Default,,0,0,0,,虽然与结果等价 但它并不是我们希望的结果 Dialogue: 0,0:26:54.58,0:26:55.22,Default,,0,0,0,,这是什么呢? Dialogue: 0,0:26:55.97,0:26:59.96,Default,,0,0,0,,我们最初有什么? Dialogue: 0,0:27:00.50,0:27:04.30,Default,,0,0,0,,我求X*X的导数 Dialogue: 0,0:27:04.69,0:27:10.53,Default,,0,0,0,,答案是X*1+1*X 这当然没错 Dialogue: 0,0:27:12.73,0:27:15.66,Default,,0,0,0,,这就是乘数的导数乘以被乘数加上乘数乘以被乘数的导数 Dialogue: 0,0:27:17.22,0:27:28.37,Default,,0,0,0,,那就是2X、A*2X就是2AX、0X^2省去 再加上0和这里的一大堆0 Dialogue: 0,0:27:28.96,0:27:30.12,Default,,0,0,0,,答案是对的 Dialogue: 0,0:27:30.12,0:27:35.14,Default,,0,0,0,,当我们还需要用户额外检验一下 真是糟糕投了 Dialogue: 0,0:27:35.56,0:27:37.26,Default,,0,0,0,,我们下一节再考虑这个内容 Dialogue: 0,0:27:37.68,0:27:38.61,Default,,0,0,0,,有疑问吗? Dialogue: 0,0:27:42.77,0:27:43.45,Default,,0,0,0,,请说 Dialogue: 0,0:27:43.89,0:27:46.69,Default,,0,0,0,,观众:写加号时不加引号 Dialogue: 0,0:27:46.69,0:27:50.82,Default,,0,0,0,,是表示引用加那个过程么? Dialogue: 0,0:27:50.82,0:27:55.42,Default,,0,0,0,,如果有需要的话 是否能在两个过程之间进行比较 Dialogue: 0,0:27:56.16,0:27:57.08,Default,,0,0,0,,教授:问得好! Dialogue: 0,0:27:57.45,0:28:02.26,Default,,0,0,0,,如果我这里不用左引号将这个引住 Dialogue: 0,0:28:03.88,0:28:07.13,Default,,0,0,0,,如果我这里不用引号 Dialogue: 0,0:28:07.33,0:28:14.20,Default,,0,0,0,,那么这里我就会引用定义好的加法过程 Dialogue: 0,0:28:15.38,0:28:24.88,Default,,0,0,0,,实际上 我可以比较两个过程是否同一 Dialogue: 0,0:28:24.88,0:28:27.45,Default,,0,0,0,,现在很难从语义上解释 Dialogue: 0,0:28:27.85,0:28:29.37,Default,,0,0,0,,我现在不想考虑这个问题 Dialogue: 0,0:28:29.89,0:28:32.40,Default,,0,0,0,,因为我不知道比较过程需要什么 Dialogue: 0,0:28:32.40,0:28:34.40,Default,,0,0,0,,这样做没有意义是有很多原因的 Dialogue: 0,0:28:35.52,0:28:37.53,Default,,0,0,0,,然而 这些符号我们是可以理解的 Dialogue: 0,0:28:38.54,0:28:40.56,Default,,0,0,0,,这也是我为什么我要将它们引住 Dialogue: 0,0:28:41.16,0:28:43.70,Default,,0,0,0,,我想讨论出现在这些代码中的符号 Dialogue: 0,0:28:46.16,0:28:46.92,Default,,0,0,0,,还有什么问题么? Dialogue: 0,0:28:48.52,0:28:51.86,Default,,0,0,0,,好吧 休息一下 谢谢大家 Dialogue: 0,0:28:55.12,0:29:00.66,Default,,0,0,0,,[音乐] Dialogue: 0,0:29:00.68,0:29:04.34,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:29:04.34,0:29:06.68,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:29:12.21,0:29:19.17,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:29:20.09,0:29:24.14,Declare,,0,0,0,,{\an2\fad(500,500)}符号化导数系统、引用 Dialogue: 0,0:29:29.86,0:29:30.92,Default,,0,0,0,,教授:好 我们继续 Dialogue: 0,0:29:31.46,0:29:37.76,Default,,0,0,0,,我们编写了一个貌似可行的代数表达式求导程序 Dialogue: 0,0:29:38.20,0:29:41.56,Default,,0,0,0,,这个程序是不完整的 你需要添加一些规则 Dialogue: 0,0:29:42.13,0:29:47.74,Default,,0,0,0,,你可能需要加强这个系统 使得它能够处理 Dialogue: 0,0:29:47.76,0:29:49.70,Default,,0,0,0,,多元加法和多元乘法 Dialogue: 0,0:29:49.89,0:29:51.38,Default,,0,0,0,,这些都相当简单 Dialogue: 0,0:29:52.73,0:29:56.93,Default,,0,0,0,,但这里面也有一些瑕疵 Dialogue: 0,0:29:57.48,0:30:02.37,Default,,0,0,0,,回到这张幻灯片来 Dialogue: 0,0:30:02.94,0:30:08.60,Default,,0,0,0,,我们发现 得到的表达式相当乱 Dialogue: 0,0:30:08.88,0:30:11.01,Default,,0,0,0,,这个表达式非常糟糕 Dialogue: 0,0:30:11.46,0:30:13.10,Default,,0,0,0,,我们是怎么得到这样的表达式的? Dialogue: 0,0:30:13.84,0:30:15.50,Default,,0,0,0,,为什么是这样呢? Dialogue: 0,0:30:16.84,0:30:18.74,Default,,0,0,0,,我们详细地分析一下这个表达式 Dialogue: 0,0:30:18.92,0:30:20.76,Default,,0,0,0,,找出这些片段都是出自哪里 Dialogue: 0,0:30:21.69,0:30:24.56,Default,,0,0,0,,如我们所见 这里的和式 Dialogue: 0,0:30:24.56,0:30:26.56,Default,,0,0,0,,也就是上一小节中给你们提到的 Dialogue: 0,0:30:27.12,0:30:29.09,Default,,0,0,0,,(+ (* X 1) (* 1 X)) Dialogue: 0,0:30:29.58,0:30:31.38,Default,,0,0,0,,是这个乘式的导数 Dialogue: 0,0:30:32.52,0:30:36.41,Default,,0,0,0,,也就是A乘上这个的积 这里A不是X的函数 Dialogue: 0,0:30:36.41,0:30:38.41,Default,,0,0,0,,因此A关于X是一个常数 Dialogue: 0,0:30:39.04,0:30:44.53,Default,,0,0,0,,导数为这个和式 从这里到这里 再到这里 Dialogue: 0,0:30:44.80,0:30:48.89,Default,,0,0,0,,因为这个是乘数乘以被乘数的导数 Dialogue: 0,0:30:49.57,0:30:54.45,Default,,0,0,0,,加上被乘数乘以乘数的导数 Dialogue: 0,0:30:54.66,0:30:59.06,Default,,0,0,0,,我们在黑板上的程序告诉我们确实是这样的 Dialogue: 0,0:31:00.65,0:31:05.36,Default,,0,0,0,,当然 这里B乘以X的积 Dialogue: 0,0:31:05.49,0:31:09.81,Default,,0,0,0,,被化成了 B*1+0*X Dialogue: 0,0:31:10.81,0:31:16.06,Default,,0,0,0,,因为B不是X的函数 Dialogue: 0,0:31:16.46,0:31:18.56,Default,,0,0,0,,因此B的导数为0 Dialogue: 0,0:31:18.77,0:31:21.48,Default,,0,0,0,,而X对自己求导则为1 Dialogue: 0,0:31:23.06,0:31:28.64,Default,,0,0,0,,这里的加法化成了 这两个导数的和 Dialogue: 0,0:31:29.37,0:31:33.50,Default,,0,0,0,,所以这里 我想告诉你和之前一样的东西 Dialogue: 0,0:31:33.66,0:31:35.89,Default,,0,0,0,,也就是在讲斐波那契数那时候 Dialogue: 0,0:31:37.77,0:31:39.49,Default,,0,0,0,,所谓的 “过程的形状” Dialogue: 0,0:31:41.38,0:31:46.44,Default,,0,0,0,,就是通过局部的规则向低层次展开 Dialogue: 0,0:31:48.05,0:31:52.57,Default,,0,0,0,,也就是过程代表了一系列用于演进过程局部规则 Dialogue: 0,0:31:53.36,0:32:00.09,Default,,0,0,0,,这里 过程还遗留了一些东西--也就是答案 Dialogue: 0,0:32:00.25,0:32:06.26,Default,,0,0,0,,这是通过遍历表达式的树结构构造出来的 Dialogue: 0,0:32:08.41,0:32:12.61,Default,,0,0,0,,答案中的每个部分对应问题中的某个部分 Dialogue: 0,0:32:14.46,0:32:17.78,Default,,0,0,0,,比如说 现在我们考察FOO的导数 Dialogue: 0,0:32:17.78,0:32:19.65,Default,,0,0,0,,也就是AX^2+BX+C Dialogue: 0,0:32:19.84,0:32:23.05,Default,,0,0,0,,并另令自变量 比如像这里 Dialogue: 0,0:32:24.14,0:32:27.48,Default,,0,0,0,,我们令A为自变量 求FOO的导数 Dialogue: 0,0:32:28.10,0:32:31.77,Default,,0,0,0,,这都非常相似 实际上 它们是同样的代数表达式 Dialogue: 0,0:32:32.45,0:32:35.24,Default,,0,0,0,,只是它们之中0和1的位置不一样罢了 Dialogue: 0,0:32:36.06,0:32:38.60,Default,,0,0,0,,这是因为在这个树结构的遍历中 Dialogue: 0,0:32:38.97,0:32:43.85,Default,,0,0,0,,只可能是CONSTANT?和SAME-VAR?会因变量的不同 Dialogue: 0,0:32:44.28,0:32:45.81,Default,,0,0,0,,而造成不同结果 Dialogue: 0,0:32:48.26,0:32:52.09,Default,,0,0,0,,回到黑板上来再看看 Dialogue: 0,0:32:52.65,0:32:57.49,Default,,0,0,0,,我们在求和式或乘式的导数时根本没有发挥的余地 Dialogue: 0,0:32:58.08,0:33:04.48,Default,,0,0,0,,真正可以做文章的地方 则是表达式和自变量 Dialogue: 0,0:33:04.80,0:33:10.10,Default,,0,0,0,,以及对于那些短小的表达式 是否为关于自变量的常量 Dialogue: 0,0:33:10.36,0:33:12.41,Default,,0,0,0,,就是这些地方导致了不同的0和1的产生 Dialogue: 0,0:33:12.69,0:33:14.49,Default,,0,0,0,,回过头来看这张幻灯 Dialogue: 0,0:33:15.12,0:33:18.16,Default,,0,0,0,,这里就出现了“0” Dialogue: 0,0:33:18.37,0:33:22.74,Default,,0,0,0,,这里是求FOO(A)的导数时得到的“1” Dialogue: 0,0:33:22.96,0:33:24.86,Default,,0,0,0,,我们得到了X^2 Dialogue: 0,0:33:24.96,0:33:32.53,Default,,0,0,0,,这个1是X*X关于X的导数 关于B求导时1变成了0 Dialogue: 0,0:33:32.64,0:33:34.89,Default,,0,0,0,,这里 我们求FOO关于C的导数 Dialogue: 0,0:33:36.78,0:33:39.30,Default,,0,0,0,,但是这些表达式的轮廓是一致的 Dialogue: 0,0:33:40.54,0:33:43.96,Default,,0,0,0,,看看这些轮廓 都是相同的 Dialogue: 0,0:33:50.37,0:33:52.28,Default,,0,0,0,,那么 难道是我们的规则出了问题? Dialogue: 0,0:33:53.58,0:33:55.02,Default,,0,0,0,,不 这些规则都对 Dialogue: 0,0:33:56.12,0:33:57.77,Default,,0,0,0,,我们曾经遇到过这种问题 Dialogue: 0,0:33:58.06,0:34:03.53,Default,,0,0,0,,你将会发现 这其中缺乏一些非常好的思想 Dialogue: 0,0:34:06.32,0:34:09.74,Default,,0,0,0,,昨天 我们在考察有理数时 Dialogue: 0,0:34:12.12,0:34:14.48,Default,,0,0,0,,想要得到3/4却得到6/8 Dialogue: 0,0:34:14.97,0:34:16.49,Default,,0,0,0,,答案没有化简 Dialogue: 0,0:34:18.09,0:34:20.90,Default,,0,0,0,,当然 当下的问题也非常类似 Dialogue: 0,0:34:21.18,0:34:25.41,Default,,0,0,0,,我想把不相同的表达式通过化简来使相同 Dialogue: 0,0:34:27.57,0:34:31.89,Default,,0,0,0,,当然 有理数加法和乘法的规则依然正确 Dialogue: 0,0:34:33.97,0:34:37.41,Default,,0,0,0,,因此这里 我们依葫芦画瓢 Dialogue: 0,0:34:37.78,0:34:39.89,Default,,0,0,0,,上次能行的办法 这次也没问题 Dialogue: 0,0:34:40.53,0:34:42.05,Default,,0,0,0,,也就是改换一下它的表示 Dialogue: 0,0:34:43.13,0:34:46.44,Default,,0,0,0,,或许在将其表示出来时我们可以进行 Dialogue: 0,0:34:47.88,0:34:49.78,Default,,0,0,0,,一步产生简化表示的步骤 Dialogue: 0,0:34:50.17,0:34:51.73,Default,,0,0,0,,当然啦 这也不是万用万灵 Dialogue: 0,0:34:52.49,0:34:54.14,Default,,0,0,0,,我也不想证明它是万能的 Dialogue: 0,0:34:55.12,0:35:00.44,Default,,0,0,0,,但这也是控制复杂度的一招妙计 Dialogue: 0,0:35:01.46,0:35:03.85,Default,,0,0,0,,我们小心翼翼地解决这些问题 Dialogue: 0,0:35:04.30,0:35:07.20,Default,,0,0,0,,我们所做的 就是把问题划分为几个部分 Dialogue: 0,0:35:07.57,0:35:08.73,Default,,0,0,0,,分别是求导规则 Dialogue: 0,0:35:11.32,0:35:15.80,Default,,0,0,0,,和在这种层面上的一般代数规则 Dialogue: 0,0:35:16.38,0:35:21.22,Default,,0,0,0,,然后就有一道抽象屏障 Dialogue: 0,0:35:22.48,0:35:33.49,Default,,0,0,0,,这里是代数表达式的表示--表结构 Dialogue: 0,0:35:37.33,0:35:42.56,Default,,0,0,0,,在这道屏障中 我定义了接口过程 Dialogue: 0,0:35:43.25,0:35:49.82,Default,,0,0,0,,比如 CONSTANT? SAME-VAR? Dialogue: 0,0:35:54.60,0:35:58.72,Default,,0,0,0,,又比如 SUM? MAKE-SUM Dialogue: 0,0:36:02.22,0:36:05.57,Default,,0,0,0,,还有 A1 A2 Dialogue: 0,0:36:06.60,0:36:08.58,Default,,0,0,0,,还有 PRODUCT? 之类的东西 Dialogue: 0,0:36:08.74,0:36:11.90,Default,,0,0,0,,我所需要的、针对各式代数表达式的东西 Dialogue: 0,0:36:12.94,0:36:19.14,Default,,0,0,0,,构筑这些屏障我可以随意地改换表示法 Dialogue: 0,0:36:20.14,0:36:23.20,Default,,0,0,0,,而不用改变在某种表示法下编写的规则 Dialogue: 0,0:36:25.04,0:36:29.08,Default,,0,0,0,,如果我能通过改变表示法来解决问题 Dialogue: 0,0:36:30.38,0:36:34.52,Default,,0,0,0,,那么把问题分解为两个部分则帮了我大忙 Dialogue: 0,0:36:35.65,0:36:37.54,Default,,0,0,0,,好吧 举一个非常简单的例子 Dialogue: 0,0:36:38.82,0:36:40.08,Default,,0,0,0,,我们的问题是什么? Dialogue: 0,0:36:40.26,0:36:43.61,Default,,0,0,0,,回到这张幻灯片来 Dialogue: 0,0:36:44.50,0:36:47.34,Default,,0,0,0,,看这里 哦 这相当糟糕 Dialogue: 0,0:36:47.62,0:36:51.86,Default,,0,0,0,,这里是一个表达式与“0”的和 Dialogue: 0,0:36:53.14,0:36:56.66,Default,,0,0,0,,毋庸置疑这应该是该表达式本身 Dialogue: 0,0:36:57.21,0:37:01.90,Default,,0,0,0,,为什么这里还会有加号? Dialogue: 0,0:37:03.38,0:37:04.57,Default,,0,0,0,,这其实可以更智能点 Dialogue: 0,0:37:05.56,0:37:10.08,Default,,0,0,0,,又比如说这里 是某表达式与“1”的积 Dialogue: 0,0:37:11.16,0:37:12.29,Default,,0,0,0,,这和之前一个道理 Dialogue: 0,0:37:12.86,0:37:15.68,Default,,0,0,0,,又像这里 与“0”相乘显然是“0” Dialogue: 0,0:37:17.86,0:37:19.52,Default,,0,0,0,,因此我们也不用去构造这些式子了 Dialogue: 0,0:37:21.44,0:37:22.62,Default,,0,0,0,,我们为什么不这么做呢? Dialogue: 0,0:37:23.66,0:37:27.96,Default,,0,0,0,,我们需要去修改表示法 基本上就是那里了 Dialogue: 0,0:37:37.40,0:37:41.84,Default,,0,0,0,,定义 MAKE-SUM 为 Dialogue: 0,0:37:42.05,0:37:43.76,Default,,0,0,0,,呃 现在就不是那么简单了 Dialogue: 0,0:37:44.00,0:37:50.40,Default,,0,0,0,,除非是有必要 否则我不会简单地把加号和式子组合成表 Dialogue: 0,0:37:51.72,0:37:53.05,Default,,0,0,0,,那么 还有哪些可能呢? Dialogue: 0,0:37:54.56,0:37:58.53,Default,,0,0,0,,如果……这里有一些可能的情况 Dialogue: 0,0:37:59.38,0:38:08.20,Default,,0,0,0,,如果都是数值的话 如果A1是数值的话 Dialogue: 0,0:38:09.05,0:38:10.93,Default,,0,0,0,,这个基本过程我刚刚提到过 Dialogue: 0,0:38:10.93,0:38:13.18,Default,,0,0,0,,也就是用来检测参数是否为数值 Dialogue: 0,0:38:15.38,0:38:23.82,Default,,0,0,0,,并且A2也是数值的话 也就是A2不是符号表达式 Dialogue: 0,0:38:24.45,0:38:26.20,Default,,0,0,0,,那么我们就直接把它们加起来 Dialogue: 0,0:38:26.45,0:38:29.92,Default,,0,0,0,,结果就是A1加上A2的和 Dialogue: 0,0:38:32.32,0:38:33.98,Default,,0,0,0,,我并不是检查它们代表数值 Dialogue: 0,0:38:33.98,0:38:35.98,Default,,0,0,0,,这里所有的符号都代表数值 Dialogue: 0,0:38:37.33,0:38:41.22,Default,,0,0,0,,就比如 我想要考察的是这个东西是否为数值3 Dialogue: 0,0:38:43.40,0:38:44.40,Default,,0,0,0,,另一种情况 Dialogue: 0,0:38:48.77,0:38:59.61,Default,,0,0,0,,假设A1是数值 并且为0 Dialogue: 0,0:39:04.20,0:39:06.38,Default,,0,0,0,,那么答案就是A2 Dialogue: 0,0:39:06.93,0:39:08.68,Default,,0,0,0,,不用再构造什么 Dialogue: 0,0:39:10.98,0:39:23.41,Default,,0,0,0,,如果A2是数值 并且为0 Dialogue: 0,0:39:27.16,0:39:28.90,Default,,0,0,0,,那么答案就是A1 Dialogue: 0,0:39:30.04,0:39:33.65,Default,,0,0,0,,如果没有比这些更好的情况 Dialogue: 0,0:39:34.13,0:39:35.61,Default,,0,0,0,,我就需要构造一个表 Dialogue: 0,0:39:37.86,0:39:42.86,Default,,0,0,0,,构造一个用于表示答案的表 Dialogue: 0,0:39:44.13,0:39:52.33,Default,,0,0,0,,其中有 '+、A1和A2 Dialogue: 0,0:39:58.66,0:40:01.65,Default,,0,0,0,,当然 积的导数也可以类比此法 Dialogue: 0,0:40:03.01,0:40:05.04,Default,,0,0,0,,这里 我就不细讲了 Dialogue: 0,0:40:05.44,0:40:07.24,Default,,0,0,0,,我就直接在黑板上写出结果 Dialogue: 0,0:40:07.65,0:40:09.80,Default,,0,0,0,,这并不是很重要 你们已经了解它的思想了 Dialogue: 0,0:40:10.76,0:40:11.61,Default,,0,0,0,,非常简明 Dialogue: 0,0:40:12.86,0:40:19.89,Default,,0,0,0,,现在 我们来看看用这种方式改造程序后 效果如何 Dialogue: 0,0:40:21.68,0:40:27.88,Default,,0,0,0,,哦 这是修改表达式构造函数后的求导结果 Dialogue: 0,0:40:28.98,0:40:32.21,Default,,0,0,0,,对同样地FOO求导:AX^2+BX+C Dialogue: 0,0:40:33.28,0:40:40.70,Default,,0,0,0,,我得到了 2AX+B Dialogue: 0,0:40:40.70,0:40:42.10,Default,,0,0,0,,虽然它并没有化到最简 Dialogue: 0,0:40:42.60,0:40:44.53,Default,,0,0,0,,我应该合并同类项和求和 Dialogue: 0,0:40:45.06,0:40:46.08,Default,,0,0,0,,但这又是另外一回事了 Dialogue: 0,0:40:47.12,0:40:51.86,Default,,0,0,0,,当然啦 完成这个功能的代码就大而复杂了 Dialogue: 0,0:40:52.28,0:40:55.28,Default,,0,0,0,,代数化简 是一项繁复的工作 Dialogue: 0,0:40:56.37,0:41:00.13,Default,,0,0,0,,你们可能听过MIT以前开发的一个非常出名的程序 MAXIMA Dialogue: 0,0:41:00.42,0:41:03.14,Default,,0,0,0,,它有5000页的LISP代码 Dialogue: 0,0:41:03.92,0:41:06.50,Default,,0,0,0,,大部分是代数化简的操作 Dialogue: 0,0:41:08.08,0:41:12.21,Default,,0,0,0,,这里是FOO的导数 Dialogue: 0,0:41:12.21,0:41:16.86,Default,,0,0,0,,要是我的话 我会在初等微积分课上讲讲“改换主变量”这个东西 Dialogue: 0,0:41:18.38,0:41:22.49,Default,,0,0,0,,以A为自变量 FOO的导数则是X*X Dialogue: 0,0:41:22.80,0:41:23.80,Default,,0,0,0,,看起来还不差 Dialogue: 0,0:41:24.74,0:41:27.53,Default,,0,0,0,,以B为自变量 FOO的导数则是X本身 Dialogue: 0,0:41:28.06,0:41:30.12,Default,,0,0,0,,以C为自变量 FOO的导数则为“1” Dialogue: 0,0:41:30.70,0:41:32.04,Default,,0,0,0,,我对这些结果很满意 Dialogue: 0,0:41:34.10,0:41:39.01,Default,,0,0,0,,你所看到的 都是精心设计、仔细规划的例子 Dialogue: 0,0:41:39.56,0:41:42.60,Default,,0,0,0,,用以展示如何操作代数表达式 Dialogue: 0,0:41:42.96,0:41:47.93,Default,,0,0,0,,我们如何不用具体的语法 而用抽象的语法抽象地进行 Dialogue: 0,0:41:49.21,0:41:56.29,Default,,0,0,0,,以及我们如何使用抽象屏障控制构造这些表达式 Dialogue: 0,0:41:57.80,0:42:00.41,Default,,0,0,0,,真正的奥义并不是如此的简单 Dialogue: 0,0:42:01.00,0:42:04.45,Default,,0,0,0,,实际上 真正的奥义在于我在操作这些表达式时 Dialogue: 0,0:42:04.45,0:42:06.72,Default,,0,0,0,,代数表达式和代码表达式-- Dialogue: 0,0:42:06.72,0:42:07.97,Default,,0,0,0,,回过头来看看幻灯片 Dialogue: 0,0:42:08.08,0:42:10.52,Default,,0,0,0,,都是同一种Lisp表达式 Dialogue: 0,0:42:12.02,0:42:12.97,Default,,0,0,0,,这样一语双关 一石二鸟 Dialogue: 0,0:42:13.82,0:42:21.49,Default,,0,0,0,,我用表示代码相同的方法来作为我的表示法 Dialogue: 0,0:42:22.89,0:42:26.52,Default,,0,0,0,,为了要这样做 我得付出点代价 Dialogue: 0,0:42:26.90,0:42:30.34,Default,,0,0,0,,我需要使用类似于“引用”的东西 Dialogue: 0,0:42:30.97,0:42:38.17,Default,,0,0,0,,这是因为 我的语言可以编写讨论语言表达式的表达式 Dialogue: 0,0:42:39.76,0:42:43.22,Default,,0,0,0,,我需要有某种东西指出 这个是我需要讨论的表达式 Dialogue: 0,0:42:43.76,0:42:46.13,Default,,0,0,0,,而不是说 (去求)这个表达式的值 Dialogue: 0,0:42:47.20,0:42:48.44,Default,,0,0,0,,我想要的是前者 Dialogue: 0,0:42:51.34,0:42:55.36,Default,,0,0,0,,引用阻止表达式被求值 其语义为“就是表达式本身” Dialogue: 0,0:42:57.97,0:43:00.85,Default,,0,0,0,,有了这种能力以后 Dialogue: 0,0:43:01.58,0:43:03.82,Default,,0,0,0,,如果我可以操作语言的表达式 Dialogue: 0,0:43:04.80,0:43:09.00,Default,,0,0,0,,我可以在语言层之上构建更加有力的层次 Dialogue: 0,0:43:09.77,0:43:12.64,Default,,0,0,0,,因为我可以编写不仅仅是内嵌于Lisp的语言 Dialogue: 0,0:43:13.46,0:43:14.80,Default,,0,0,0,,或者是其它的语言 Dialogue: 0,0:43:15.26,0:43:17.76,Default,,0,0,0,,我可以编写一种完全不同的语言 Dialogue: 0,0:43:18.58,0:43:22.24,Default,,0,0,0,,而其实质上则是被Lisp或其它语言所解释 Dialogue: 0,0:43:23.17,0:43:25.46,Default,,0,0,0,,我们以后还会对此有更深入的理解 Dialogue: 0,0:43:26.56,0:43:32.09,Default,,0,0,0,,我现在只是想让你们意识到 Dialogue: 0,0:43:32.36,0:43:34.98,Default,,0,0,0,,我们已经感触到了一种惊人的力量 Dialogue: 0,0:43:36.00,0:43:37.82,Default,,0,0,0,,现在我们有了方天画戟 Dialogue: 0,0:43:38.17,0:43:40.92,Default,,0,0,0,,当我们使用它时 也得万分小心 Dialogue: 0,0:43:42.17,0:43:43.00,Default,,0,0,0,,谢谢大家 Dialogue: 0,0:43:44.10,0:44:00.54,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:43:44.10,0:44:00.54,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec3b.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Last Style Storage: Default Scroll Position: 583 Active Line: 593 Video Zoom Percent: 0.625 Audio URI: G:\untitled\ref\lec3b_480_muxed2.mp4 Video File: G:\untitled\ref\lec3b_480_muxed2.mp4 Video Aspect Ratio: c1.33333 Video Position: 79137 PlayResX: 640 PlayResY: 480 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:02.32,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:02.57,0:00:06.01,Declare,,0,0,0,,{\an2\fad(500,500)}翻译&&时间轴:邓雄飞(Dysprosium)\N压制&&特效:邓雄飞(Dysprosium)\N校对:邓雄飞(Dysprosium) Dialogue: 0,0:00:06.06,0:00:08.97,Declare,,0,0,0,,{\an2\fad(500,500)}特别感谢:裘宗燕教授 Dialogue: 0,0:00:11.24,0:00:14.46,Declare,,0,0,0,,{\an2\fad(500,500)}符号化求导系统,引用 Dialogue: 0,0:00:19.10,0:00:23.41,Default,,0,0,0,,教授:嗯 Harold教授讲解了如何构造健壮的系统 Dialogue: 0,0:00:23.80,0:00:26.17,Default,,0,0,0,,关键点就是 Dialogue: 0,0:00:26.81,0:00:30.20,Default,,0,0,0,,我想你们大多还没吃透其中的要点 Dialogue: 0,0:00:30.20,0:00:33.77,Default,,0,0,0,,要点就是 为了让系统具有健壮性 Dialogue: 0,0:00:33.93,0:00:36.48,Default,,0,0,0,,应该让它对小变化不敏感 Dialogue: 0,0:00:36.60,0:00:37.37,Default,,0,0,0,,也就是说 Dialogue: 0,0:00:37.37,0:00:40.90,Default,,0,0,0,,问题中的小改变只会导致解决方案的小改动 Dialogue: 0,0:00:41.32,0:00:42.90,Default,,0,0,0,,系统应该是连续的 Dialogue: 0,0:00:42.90,0:00:45.94,Default,,0,0,0,,在问题空间中 解的空间是连续的 Dialogue: 0,0:00:46.25,0:00:48.76,Default,,0,0,0,,Harold教授给你们解释过 Dialogue: 0,0:00:49.46,0:00:54.78,Default,,0,0,0,,与其在问题分解出的子问题上 求解具体问题 Dialogue: 0,0:00:55.08,0:00:56.78,Default,,0,0,0,,你不如解决一类问题 Dialogue: 0,0:00:56.78,0:01:00.40,Default,,0,0,0,,也就是你想要解决的具体问题的“邻居” Dialogue: 0,0:01:01.40,0:01:04.76,Default,,0,0,0,,解决之道便是在该层次上构造一门语言 Dialogue: 0,0:01:04.76,0:01:10.33,Default,,0,0,0,,使得我们可以用这门语言来表述这类问题 Dialogue: 0,0:01:11.37,0:01:15.09,Default,,0,0,0,,因此 当着手解决的问题再发生变动时 Dialogue: 0,0:01:15.09,0:01:19.29,Default,,0,0,0,,通常 你只需要在已构造好的解决方案上做出微小改动 Dialogue: 0,0:01:19.29,0:01:22.26,Default,,0,0,0,,因为在你所考虑的层次上 Dialogue: 0,0:01:22.26,0:01:24.26,Default,,0,0,0,,有一门语言可以表达 Dialogue: 0,0:01:24.80,0:01:28.14,Default,,0,0,0,,类似问题的各种解法 Dialogue: 0,0:01:30.04,0:01:33.74,Default,,0,0,0,,呃... 这是一个重要思想的萌芽 Dialogue: 0,0:01:34.40,0:01:38.61,Default,,0,0,0,,该思想的重要性也使得计算机科学比 Dialogue: 0,0:01:38.61,0:01:42.37,Default,,0,0,0,,其它大多数工程学科还要强大 Dialogue: 0,0:01:43.38,0:01:44.73,Default,,0,0,0,,目前为止 我们学习的是 Dialogue: 0,0:01:44.73,0:01:48.78,Default,,0,0,0,,类似于 如何使用语言内置元素 Dialogue: 0,0:01:49.26,0:01:53.36,Default,,0,0,0,,当然 内置元素的力量一部分来源于 Dialogue: 0,0:01:54.12,0:01:56.86,Default,,0,0,0,,像这个一样的过程 我昨天给你们展示过了 Dialogue: 0,0:01:57.37,0:02:02.13,Default,,0,0,0,,这里 是一份求导程序 昨天给你们描述过了 Dialogue: 0,0:02:02.13,0:02:05.92,Default,,0,0,0,,这个过程以一个过程为参数 Dialogue: 0,0:02:06.00,0:02:07.92,Default,,0,0,0,,并返回一个过程 Dialogue: 0,0:02:09.61,0:02:12.65,Default,,0,0,0,,用这样的东西棒极了 Dialogue: 0,0:02:12.65,0:02:14.65,Default,,0,0,0,,你可以像创建PUSH组合子那样构造 Dialogue: 0,0:02:14.65,0:02:16.86,Default,,0,0,0,,可以像上节课看到的哪些奇妙东西那样 Dialogue: 0,0:02:17.68,0:02:20.54,Default,,0,0,0,,现在 我要来打个太极 Dialogue: 0,0:02:21.56,0:02:25.90,Default,,0,0,0,,这个程序混淆了过程和数据 Dialogue: 0,0:02:26.56,0:02:27.81,Default,,0,0,0,,虽然程度不算太重 Dialogue: 0,0:02:28.42,0:02:30.90,Default,,0,0,0,,而我们将要严重地混淆两者 Dialogue: 0,0:02:31.18,0:02:32.44,Default,,0,0,0,,最好的做法就是 Dialogue: 0,0:02:32.44,0:02:37.62,Default,,0,0,0,,参与到过程自身所描述的代数表达式的操作中 Dialogue: 0,0:02:39.73,0:02:45.58,Default,,0,0,0,,所以 这里我不会讨论这张幻灯片上的东西 Dialogue: 0,0:02:45.89,0:02:49.72,Default,,0,0,0,,一个通过操作过程的求导程序 Dialogue: 0,0:02:49.72,0:02:51.94,Default,,0,0,0,,这只是一个数值化方法而已 Dialogue: 0,0:02:51.94,0:02:58.93,Default,,0,0,0,,你们所看到的是 通过数值方法来近似的求导程序 Dialogue: 0,0:02:59.29,0:03:00.44,Default,,0,0,0,,也就是这里的东西了 Dialogue: 0,0:03:00.86,0:03:04.93,Default,,0,0,0,,事实上 我想讨论的是这些东西 Dialogue: 0,0:03:06.05,0:03:11.33,Default,,0,0,0,,这是一份从微积分书中摘录的法则 Dialogue: 0,0:03:12.09,0:03:16.17,Default,,0,0,0,,这对表达式求导的法则 Dialogue: 0,0:03:16.70,0:03:20.58,Default,,0,0,0,,只不过是用代数语言书写的 Dialogue: 0,0:03:21.64,0:03:24.41,Default,,0,0,0,,法则说 常数的导数是0 Dialogue: 0,0:03:25.13,0:03:29.09,Default,,0,0,0,,而代表你所讨论的那个数的变量导数为1 Dialogue: 0,0:03:29.32,0:03:31.93,Default,,0,0,0,,常数乘以函数的导数 Dialogue: 0,0:03:32.09,0:03:34.37,Default,,0,0,0,,其值是常数的值乘以函数导数的值 Dialogue: 0,0:03:34.77,0:03:36.04,Default,,0,0,0,,就是这个意思 Dialogue: 0,0:03:38.05,0:03:41.38,Default,,0,0,0,,这些都是精确的表达式 而非数值近似 Dialogue: 0,0:03:42.96,0:03:44.52,Default,,0,0,0,,我们还能编写程序吗? Dialogue: 0,0:03:44.52,0:03:52.24,Default,,0,0,0,,事实上 编写处理这些表达式的程序非常容易 Dialogue: 0,0:03:56.38,0:03:59.52,Default,,0,0,0,,让我们仔细地看看这些法则 Dialogue: 0,0:04:01.08,0:04:05.22,Default,,0,0,0,,你们曾经在初等微积分课上学过这些法则了 Dialogue: 0,0:04:05.98,0:04:12.12,Default,,0,0,0,,你们知道 微积分中对多元表达式求导很容易 Dialogue: 0,0:04:12.53,0:04:16.05,Default,,0,0,0,,在微积分课上 你们也知道计算积分不容易 Dialogue: 0,0:04:16.98,0:04:19.37,Default,,0,0,0,,虽然积分和求导相对 Dialogue: 0,0:04:19.52,0:04:21.28,Default,,0,0,0,,它俩互为逆运算 Dialogue: 0,0:04:21.61,0:04:23.30,Default,,0,0,0,,但它们有同样的法则 Dialogue: 0,0:04:24.16,0:04:29.68,Default,,0,0,0,,但这些法则中又有什么特殊的东西 Dialogue: 0,0:04:29.68,0:04:33.65,Default,,0,0,0,,使得求导容易 求积分就困难呢? Dialogue: 0,0:04:34.85,0:04:36.98,Default,,0,0,0,,我们浅显地想一想 Dialogue: 0,0:04:37.40,0:04:38.38,Default,,0,0,0,,仔细考察法则 Dialogue: 0,0:04:39.36,0:04:43.06,Default,,0,0,0,,对于每条法则来说 你求导数时的方向 Dialogue: 0,0:04:43.06,0:04:44.80,Default,,0,0,0,,这个箭头的方向 Dialogue: 0,0:04:46.68,0:04:49.16,Default,,0,0,0,,法则的左边与你的表达式相匹配 Dialogue: 0,0:04:49.16,0:04:53.05,Default,,0,0,0,,法则的右边就是表达式的导数 Dialogue: 0,0:04:54.02,0:04:55.65,Default,,0,0,0,,箭头是这个方向的 Dialogue: 0,0:04:57.37,0:05:00.45,Default,,0,0,0,,每条法则中 Dialogue: 0,0:05:01.24,0:05:03.72,Default,,0,0,0,,法则右边的表达式 Dialogue: 0,0:05:03.72,0:05:06.56,Default,,0,0,0,,都是求导过程中的子表达式 Dialogue: 0,0:05:06.56,0:05:10.29,Default,,0,0,0,,都是左边式子的合法子表达式 Dialogue: 0,0:05:10.60,0:05:13.25,Default,,0,0,0,,这里 我们发现 和的导数 Dialogue: 0,0:05:13.92,0:05:16.13,Default,,0,0,0,,也就是左边式子的导数 Dialogue: 0,0:05:16.13,0:05:18.38,Default,,0,0,0,,就是两部分导数之和 Dialogue: 0,0:05:20.08,0:05:24.49,Default,,0,0,0,,法则从左至右的方向是“归约规则” Dialogue: 0,0:05:25.02,0:05:26.61,Default,,0,0,0,,问题变简单了 Dialogue: 0,0:05:27.56,0:05:31.48,Default,,0,0,0,,我把一个复杂的问题 转化成了许多小点儿的问题 Dialogue: 0,0:05:32.44,0:05:35.76,Default,,0,0,0,,然后把结果组合起来 这里用递归可以完美地解决 Dialogue: 0,0:05:36.58,0:05:40.85,Default,,0,0,0,,但如果我从另外的方向来思考 Dialogue: 0,0:05:41.81,0:05:45.13,Default,,0,0,0,,如果我想求积分的话 你会发现有很多问题 Dialogue: 0,0:05:45.24,0:05:49.09,Default,,0,0,0,,就比如 如果我想求一个和的积分 Dialogue: 0,0:05:49.21,0:05:50.81,Default,,0,0,0,,就会匹配多条法则 Dialogue: 0,0:05:50.81,0:05:52.10,Default,,0,0,0,,这条匹配 Dialogue: 0,0:05:52.48,0:05:53.65,Default,,0,0,0,,这条也匹配 Dialogue: 0,0:05:54.81,0:05:57.09,Default,,0,0,0,,我不知道该用哪个——它们之间可能不一样 Dialogue: 0,0:05:57.70,0:06:00.00,Default,,0,0,0,,我得考察两者的不同之处 Dialogue: 0,0:06:00.25,0:06:03.64,Default,,0,0,0,,所以 在这个方向上 表达式变复杂了 Dialogue: 0,0:06:04.53,0:06:06.30,Default,,0,0,0,,当表达式变复杂时 Dialogue: 0,0:06:06.30,0:06:10.56,Default,,0,0,0,,就没法保证我所选的路径一定能终止了 Dialogue: 0,0:06:10.94,0:06:13.46,Default,,0,0,0,,因为唯一的可能是偶然的约分 Dialogue: 0,0:06:14.24,0:06:18.05,Default,,0,0,0,,这也就是为什么 积分是一种复杂的搜索 而难以完成 Dialogue: 0,0:06:19.12,0:06:20.96,Default,,0,0,0,,现在我不想处理这么复杂的东西 Dialogue: 0,0:06:21.49,0:06:23.06,Default,,0,0,0,,我们先来讨论求导数 Dialogue: 0,0:06:24.14,0:06:28.13,Default,,0,0,0,,好吧 我就假设你们都大致了解这些法则了 Dialogue: 0,0:06:28.78,0:06:31.88,Default,,0,0,0,,让我们来看看能不能用程序表达这些法则 Dialogue: 0,0:06:32.22,0:06:33.72,Default,,0,0,0,,这应该很容易 Dialogue: 0,0:06:34.89,0:06:36.21,Default,,0,0,0,,信手拈来 Dialogue: 0,0:06:36.69,0:06:39.29,Default,,0,0,0,,因为 我给你们展示的是“归约规则” Dialogue: 0,0:06:39.29,0:06:41.29,Default,,0,0,0,,这样用递归来编写会比较合适 Dialogue: 0,0:06:43.08,0:06:45.72,Default,,0,0,0,,当然 对每条法则来说就是一种情况 Dialogue: 0,0:06:46.66,0:06:47.78,Default,,0,0,0,,我们做“分情况分析” Dialogue: 0,0:06:48.58,0:06:50.36,Default,,0,0,0,,我就这么写了 Dialogue: 0,0:06:52.88,0:06:57.69,Default,,0,0,0,,当然 我得先让大家达成共识 对吧? Dialogue: 0,0:06:57.69,0:07:00.33,Default,,0,0,0,,你们应该意识到到我可以表示这些代数式 Dialogue: 0,0:07:00.68,0:07:03.88,Default,,0,0,0,,我可以从中抽取式子 也可以将它们组合起来 Dialogue: 0,0:07:04.24,0:07:06.49,Default,,0,0,0,,我们发明了表结构来解决这个问题 Dialogue: 0,0:07:07.52,0:07:09.14,Default,,0,0,0,,但现在我们不必关心 Dialogue: 0,0:07:09.66,0:07:12.45,Default,,0,0,0,,现在 我要编写一个程序来封装这些法则 Dialogue: 0,0:07:12.76,0:07:15.85,Default,,0,0,0,,但它不依赖于代数表达式的表示法 Dialogue: 0,0:07:20.42,0:07:28.84,Default,,0,0,0,,(DERIV EXP VAR)表示表达式EXP关于变量VAR的导数 Dialogue: 0,0:07:30.50,0:07:33.08,Default,,0,0,0,,这和函数的导数是不一样的 Dialogue: 0,0:07:34.82,0:07:38.61,Default,,0,0,0,,那个是我们上节课看到的数值近似 Dialogue: 0,0:07:39.00,0:07:40.82,Default,,0,0,0,,并不能看到函数内部 Dialogue: 0,0:07:40.82,0:07:41.89,Default,,0,0,0,,它只是一个数值 Dialogue: 0,0:07:43.09,0:07:45.18,Default,,0,0,0,,表达式的导数也是一个表达式 Dialogue: 0,0:07:45.74,0:07:47.85,Default,,0,0,0,,因此 这只是一个语法问题 Dialogue: 0,0:07:48.29,0:07:51.62,Default,,0,0,0,,我们今天要做的大多数工作 就是讨论语法 Dialogue: 0,0:07:52.33,0:07:54.12,Default,,0,0,0,,表达式的语法或类似 Dialogue: 0,0:07:54.70,0:07:55.93,Default,,0,0,0,,首先要做“分情况分析” Dialogue: 0,0:07:57.50,0:08:01.08,Default,,0,0,0,,任何时候我们处理复杂事物 需要递归求解时 Dialogue: 0,0:08:01.08,0:08:02.64,Default,,0,0,0,,我们很可能需要“按情况分析” Dialogue: 0,0:08:03.62,0:08:05.16,Default,,0,0,0,,通常都是这样开始的 Dialogue: 0,0:08:05.16,0:08:07.40,Default,,0,0,0,,复杂的问题都是用“按情况分析” Dialogue: 0,0:08:08.08,0:08:09.97,Default,,0,0,0,,那么 有哪些可能(的情况)呢? Dialogue: 0,0:08:09.97,0:08:12.53,Default,,0,0,0,,第一条法则说 如果你遇到一个常数 Dialogue: 0,0:08:16.50,0:08:17.50,Default,,0,0,0,,这里 我就是在判断 Dialogue: 0,0:08:17.50,0:08:22.22,Default,,0,0,0,,表达式EXP是否为给定变量VAR的常数(常量表达式) Dialogue: 0,0:08:24.90,0:08:27.08,Default,,0,0,0,,是的话 结果就是0 Dialogue: 0,0:08:27.50,0:08:30.10,Default,,0,0,0,,因为导数表征的是某物的变化率 Dialogue: 0,0:08:31.76,0:08:32.65,Default,,0,0,0,,然而 Dialogue: 0,0:08:32.89,0:08:40.69,Default,,0,0,0,,如果我求导的表达式 与我关心的变量有关 Dialogue: 0,0:08:41.72,0:08:50.42,Default,,0,0,0,,如果判定表达式和变量相同 Dialogue: 0,0:08:51.14,0:08:54.52,Default,,0,0,0,,那么关于变量VAR的表达式EXP的变化率就是1 Dialogue: 0,0:08:55.50,0:08:56.54,Default,,0,0,0,,它俩相同 结果是1 Dialogue: 0,0:08:58.90,0:09:00.77,Default,,0,0,0,,当然 还可能有其它的可能性 Dialogue: 0,0:09:01.33,0:09:03.14,Default,,0,0,0,,比如说 它可能是一个和式 Dialogue: 0,0:09:03.86,0:09:05.88,Default,,0,0,0,,呃 我现在还完全知道该如何表示和式 Dialogue: 0,0:09:06.09,0:09:08.25,Default,,0,0,0,,事实上我可以 只是我还没有告诉你们 Dialogue: 0,0:09:10.34,0:09:11.78,Default,,0,0,0,,如果表达式是和式 Dialogue: 0,0:09:12.48,0:09:14.48,Default,,0,0,0,,我就假想有一种方式可以判别(和式) Dialogue: 0,0:09:15.30,0:09:19.44,Default,,0,0,0,,这里 我要做一个表达式的类型分派 Dialogue: 0,0:09:20.77,0:09:23.57,Default,,0,0,0,,这是在构建语言时绝对必要的 Dialogue: 0,0:09:24.72,0:09:26.37,Default,,0,0,0,,因为语言由不同的表达式构成 Dialogue: 0,0:09:26.48,0:09:27.54,Default,,0,0,0,,我们马上就将看到 Dialogue: 0,0:09:27.84,0:09:31.02,Default,,0,0,0,,如何用更强大的方法 用语言去构建语言 Dialogue: 0,0:09:32.53,0:09:34.02,Default,,0,0,0,,表达式是和式吗? Dialogue: 0,0:09:35.45,0:09:38.82,Default,,0,0,0,,如果是的话 很好 我们已经知道和式的求导法则了 Dialogue: 0,0:09:38.82,0:09:41.33,Default,,0,0,0,,即是各部分导数之和 Dialogue: 0,0:09:42.13,0:09:44.32,Default,,0,0,0,,其中一个叫做加数 另一个叫做被加数 Dialogue: 0,0:09:44.32,0:09:46.80,Default,,0,0,0,,黑板上没那么多空间写这么长的名字了 Dialogue: 0,0:09:46.80,0:09:48.40,Default,,0,0,0,,我就姑且把它们叫做 A1和A2 Dialogue: 0,0:09:49.04,0:09:50.37,Default,,0,0,0,,把它们求和 Dialogue: 0,0:09:53.53,0:09:55.68,Default,,0,0,0,,(意义不明) Dialogue: 0,0:09:57.14,0:10:01.09,Default,,0,0,0,,是叫做被除数和除数一类的么? Dialogue: 0,0:10:01.65,0:10:08.48,Default,,0,0,0,,将A1的导数...加上 Dialogue: 0,0:10:08.48,0:10:13.29,Default,,0,0,0,,这是关于变量VAR的表达式的加数 Dialogue: 0,0:10:14.84,0:10:22.76,Default,,0,0,0,,与A2的导数相加 Dialogue: 0,0:10:24.12,0:10:28.25,Default,,0,0,0,,这两个参数的和 变量是VAR Dialogue: 0,0:10:32.36,0:10:34.93,Default,,0,0,0,,我们知道还有一条乘法的求导法则 Dialogue: 0,0:10:35.20,0:10:37.44,Default,,0,0,0,,也就是说 如果表达式是乘式 Dialogue: 0,0:10:43.21,0:10:46.10,Default,,0,0,0,,顺便说下 当你定义过程时 有个好习惯 Dialogue: 0,0:10:46.96,0:10:48.32,Default,,0,0,0,,就是在定义谓词时 Dialogue: 0,0:10:48.85,0:10:50.96,Default,,0,0,0,,将谓词名以问号结尾 Dialogue: 0,0:10:51.08,0:10:52.89,Default,,0,0,0,,问号本身不代表什么 Dialogue: 0,0:10:53.10,0:10:54.50,Default,,0,0,0,,但这是俗成的约定 Dialogue: 0,0:10:54.61,0:10:58.94,Default,,0,0,0,,这是人们之间约定的接口 以方便他人阅读你的脚本 Dialogue: 0,0:11:00.05,0:11:01.96,Default,,0,0,0,,我希望你在写程序的时候 Dialogue: 0,0:11:01.96,0:11:03.73,Default,,0,0,0,,当你定义谓词的时候 Dialogue: 0,0:11:04.01,0:11:05.77,Default,,0,0,0,,就是那些返回TRUE或FALSE的过程 Dialogue: 0,0:11:05.94,0:11:07.84,Default,,0,0,0,,你应该使它们的名字以问号结尾 Dialogue: 0,0:11:08.02,0:11:10.34,Default,,0,0,0,,这对Lisp无异 但对人类友好 Dialogue: 0,0:11:11.62,0:11:13.14,Default,,0,0,0,,我需要求和 Dialogue: 0,0:11:13.14,0:11:17.49,Default,,0,0,0,,因为积的导数就是... Dialogue: 0,0:11:17.94,0:11:19.64,Default,,0,0,0,,M1*DERIV(M2) Dialogue: 0,0:11:19.66,0:11:20.70,Default,,0,0,0,,+DERIV(M1)*M2 Dialogue: 0,0:11:23.54,0:11:27.06,Default,,0,0,0,,两者加起来 Dialogue: 0,0:11:29.64,0:11:38.33,Default,,0,0,0,,求积... 呃 就用表达式中的M1来表示(被乘数)好了 Dialogue: 0,0:11:39.85,0:11:48.97,Default,,0,0,0,,表达式中M2关于变量VAR的导数 Dialogue: 0,0:11:51.90,0:12:06.28,Default,,0,0,0,,以及 M1关于变量VAR的导数乘以 Dialogue: 0,0:12:07.10,0:12:11.92,Default,,0,0,0,,M1是这里的被乘数 Dialogue: 0,0:12:13.32,0:12:18.05,Default,,0,0,0,,乘数是表达式中的M2 Dialogue: 0,0:12:20.64,0:12:24.89,Default,,0,0,0,,求积完毕、求和完毕、乘式分析完毕 Dialogue: 0,0:12:24.96,0:12:28.02,Default,,0,0,0,,当然 在这里我可以添加更多的情况 Dialogue: 0,0:12:28.32,0:12:30.82,Default,,0,0,0,,微积分书中的完整法则 Dialogue: 0,0:12:34.80,0:12:39.45,Default,,0,0,0,,我们就是这么来封装这些法则的 Dialogue: 0,0:12:41.53,0:12:43.90,Default,,0,0,0,,如你所见 我们这里用到了大量的“按愿望思维” Dialogue: 0,0:12:44.54,0:12:47.56,Default,,0,0,0,,我们还没有说这些(表达式)是如何表示的 Dialogue: 0,0:12:48.46,0:12:51.92,Default,,0,0,0,,现在 一旦我将其定为我的一套法则 Dialogue: 0,0:12:52.52,0:12:55.20,Default,,0,0,0,,我想是时候考虑表示法了 Dialogue: 0,0:12:55.66,0:12:56.69,Default,,0,0,0,,我们来拿捏拿捏 Dialogue: 0,0:12:57.96,0:13:00.00,Default,,0,0,0,,首先 我要用到一种“双关”思想 Dialogue: 0,0:13:00.90,0:13:02.12,Default,,0,0,0,,这种“双关”思想非常重要 Dialogue: 0,0:13:02.74,0:13:06.56,Default,,0,0,0,,它是一种强有力思想的关键 Dialogue: 0,0:13:09.62,0:13:14.41,Default,,0,0,0,,如果我想表达诸如和、积、差、商的东西 Dialogue: 0,0:13:15.22,0:13:18.62,Default,,0,0,0,,为什么不用和我程序一样的语言呢? Dialogue: 0,0:13:20.50,0:13:23.64,Default,,0,0,0,,我程序中 代数表达式是形如 Dialogue: 0,0:13:23.98,0:13:30.45,Default,,0,0,0,,(+ (* A (* X X)) Dialogue: 0,0:13:32.60,0:13:33.80,Default,,0,0,0,,和与之类似的 Dialogue: 0,0:13:34.28,0:13:38.50,Default,,0,0,0,,(* B X)以及C Dialogue: 0,0:13:38.50,0:13:39.97,Default,,0,0,0,,把它们加起来 Dialogue: 0,0:13:40.77,0:13:44.09,Default,,0,0,0,,现在 我的过程还不能处理多元参数 Dialogue: 0,0:13:44.93,0:13:48.46,Default,,0,0,0,,(+ (* B X) C) Dialogue: 0,0:13:51.42,0:13:52.44,Default,,0,0,0,,这是表结构 Dialogue: 0,0:13:54.12,0:13:55.74,Default,,0,0,0,,这么做很棒 是因为 Dialogue: 0,0:13:55.90,0:13:58.33,Default,,0,0,0,,是因为这些对象都有一种性质 Dialogue: 0,0:13:58.92,0:14:01.53,Default,,0,0,0,,我知道它们的CAR部分是什么 Dialogue: 0,0:14:01.96,0:14:03.21,Default,,0,0,0,,CAR部分就是运算符 Dialogue: 0,0:14:03.92,0:14:06.38,Default,,0,0,0,,运算数是相继的CDR部分 Dialogue: 0,0:14:07.22,0:14:10.36,Default,,0,0,0,,也就是不断取表CDR部分的CAR部分 Dialogue: 0,0:14:12.48,0:14:13.88,Default,,0,0,0,,这样就使它很方便了 Dialogue: 0,0:14:14.01,0:14:16.40,Default,,0,0,0,,我需要去解析它 但它已经帮我完成了 Dialogue: 0,0:14:17.42,0:14:20.01,Default,,0,0,0,,我利用了Lisp中的内建元素 Dialogue: 0,0:14:22.66,0:14:23.77,Default,,0,0,0,,举个例子 Dialogue: 0,0:14:25.08,0:14:33.97,Default,,0,0,0,,我们用表结构来表示我所暗示的表示法吧! Dialogue: 0,0:14:35.25,0:14:38.34,Default,,0,0,0,,我需要定义一些东西 这都暗含在这种表示法中 Dialogue: 0,0:14:38.54,0:14:40.90,Default,,0,0,0,,比如如何判定是否为常量 Dialogue: 0,0:14:41.21,0:14:42.30,Default,,0,0,0,,又怎么判断是同一个变量 Dialogue: 0,0:14:42.40,0:14:45.04,Default,,0,0,0,,我们先完成这些吧 都相当简单 Dialogue: 0,0:14:45.78,0:14:47.70,Default,,0,0,0,,这里 我要介绍一些基本过程 Dialogue: 0,0:14:48.60,0:14:50.50,Default,,0,0,0,,因为它们都是与表结构相关的 Dialogue: 0,0:14:51.98,0:14:53.46,Default,,0,0,0,,CONSTANT?谓词定义为 Dialogue: 0,0:15:02.25,0:15:04.29,Default,,0,0,0,,我所谓的常量 Dialogue: 0,0:15:04.29,0:15:07.73,Default,,0,0,0,,表达式关于变量VAR是一个常量 Dialogue: 0,0:15:09.05,0:15:11.60,Default,,0,0,0,,是一些简单的表达式 Dialogue: 0,0:15:11.60,0:15:14.46,Default,,0,0,0,,我无法再细化它 但它也不是我们关心的变量 Dialogue: 0,0:15:16.58,0:15:18.78,Default,,0,0,0,,我无法分解它 但它也不是我们关心的变量 Dialogue: 0,0:15:18.90,0:15:25.12,Default,,0,0,0,,这也并不是说 一些复杂的表达式就不是常量表达式 Dialogue: 0,0:15:25.20,0:15:28.92,Default,,0,0,0,,我只是想用这种方式考察基本常量 Dialogue: 0,0:15:29.74,0:15:33.41,Default,,0,0,0,,因此 这个谓词是几个条件的合取 Dialogue: 0,0:15:34.02,0:15:37.82,Default,,0,0,0,,AND语句允许用户组合返回TRUE或者FALSE的谓词 Dialogue: 0,0:15:38.62,0:15:46.82,Default,,0,0,0,,表达式是原子的么?--原子表达式不可以再被细分 Dialogue: 0,0:15:46.82,0:15:48.53,Default,,0,0,0,,它没有CAR部分和CDR部分 Dialogue: 0,0:15:49.45,0:15:50.21,Default,,0,0,0,,它不是表 Dialogue: 0,0:15:50.76,0:15:52.94,Default,,0,0,0,,系统中内建有特殊测试 Dialogue: 0,0:15:53.97,0:16:04.66,Default,,0,0,0,,并且表达式EXP和变量VAR在EQ?的语义下不相等 Dialogue: 0,0:16:06.82,0:16:13.36,Default,,0,0,0,,我用不能被分解的符号来表示变量 Dialogue: 0,0:16:13.90,0:16:17.22,Default,,0,0,0,,比如'X 'Y 和像这样的 Dialogue: 0,0:16:19.74,0:16:22.37,Default,,0,0,0,,当然 像这样的组合式就可以再被细分 Dialogue: 0,0:16:24.74,0:16:46.40,Default,,0,0,0,,(SAME-VAR? EXP VAR)定义为 Dialogue: 0,0:16:46.40,0:16:48.40,Default,,0,0,0,,实际上 一条原子表达式…… Dialogue: 0,0:16:48.77,0:16:59.61,Default,,0,0,0,,该表达式与讨论变量相同 Dialogue: 0,0:17:07.90,0:17:11.68,Default,,0,0,0,,我不想深入讨论这些过程内部 Dialogue: 0,0:17:12.52,0:17:15.56,Default,,0,0,0,,把这些当作基本过程 Dialogue: 0,0:17:15.77,0:17:17.08,Default,,0,0,0,,这无关紧要 Dialogue: 0,0:17:17.78,0:17:21.74,Default,,0,0,0,,我用的是语言内置的功能 Dialogue: 0,0:17:22.42,0:17:24.04,Default,,0,0,0,,我并不关心这些(具体实现) Dialogue: 0,0:17:24.42,0:17:26.04,Default,,0,0,0,,现在 我们要如何处理和式呢? Dialogue: 0,0:17:26.60,0:17:28.80,Default,,0,0,0,,啊哈 好戏就要上演了 Dialogue: 0,0:17:28.98,0:17:33.12,Default,,0,0,0,,和式不是原子的 它以‘+’号打头 Dialogue: 0,0:17:35.16,0:17:36.17,Default,,0,0,0,,就是这个意思 Dialogue: 0,0:17:36.65,0:17:39.77,Default,,0,0,0,,这里 我定义 Dialogue: 0,0:17:45.46,0:17:57.77,Default,,0,0,0,,表达式为和式 当它不是原子表达式 Dialogue: 0,0:18:04.57,0:18:15.45,Default,,0,0,0,,并且它的开头 表达式的CAR部分是个‘+’号 Dialogue: 0,0:18:19.74,0:18:24.04,Default,,0,0,0,,我将要引入一个你们从未见过的东西--这个引号 Dialogue: 0,0:18:25.89,0:18:28.22,Default,,0,0,0,,我这里为什么要用引号呢? Dialogue: 0,0:18:29.48,0:18:30.52,Default,,0,0,0,,教授:说你的名字 Dialogue: 0,0:18:30.68,0:18:31.41,Default,,0,0,0,,观众:Susanna Dialogue: 0,0:18:31.41,0:18:32.01,Default,,0,0,0,,教授:大点声儿 Dialogue: 0,0:18:32.01,0:18:32.72,Default,,0,0,0,,观众:Susanna Dialogue: 0,0:18:33.25,0:18:34.21,Default,,0,0,0,,教授:说“你的名字” Dialogue: 0,0:18:34.21,0:18:34.85,Default,,0,0,0,,观众:“你的名字” Dialogue: 0,0:18:34.92,0:18:35.68,Default,,0,0,0,,教授:大点声儿 Dialogue: 0,0:18:35.77,0:18:36.61,Default,,0,0,0,,观众:“你的名字” Dialogue: 0,0:18:36.82,0:18:37.50,Default,,0,0,0,,教授:对了 Dialogue: 0,0:18:38.28,0:18:44.56,Default,,0,0,0,,在这里我想告诉大家 英语词汇是有歧义的 Dialogue: 0,0:18:45.50,0:18:50.76,Default,,0,0,0,,我可能说 “说你的名字” Dialogue: 0,0:18:51.97,0:18:57.21,Default,,0,0,0,,我也可能说 “说‘你的名字’” Dialogue: 0,0:19:00.72,0:19:02.98,Default,,0,0,0,,光从说话上还无法分辨 Dialogue: 0,0:19:03.89,0:19:08.01,Default,,0,0,0,,然而书面上 我们有专门的记号--引号 Dialogue: 0,0:19:08.18,0:19:12.46,Default,,0,0,0,,用来区别这两种可能的意思 Dialogue: 0,0:19:14.00,0:19:15.64,Default,,0,0,0,,具体来说 这里 Dialogue: 0,0:19:16.49,0:19:20.84,Default,,0,0,0,,在Lisp中有用于区别这些语义的记号 Dialogue: 0,0:19:21.34,0:19:24.45,Default,,0,0,0,,如果我只是写下一个加号 Dialogue: 0,0:19:24.64,0:19:28.52,Default,,0,0,0,,我会问系统 表达式的首元素 Dialogue: 0,0:19:29.06,0:19:33.61,Default,,0,0,0,,也就是表达式的运算符 是加运算符(一个过程)么? Dialogue: 0,0:19:34.65,0:19:35.54,Default,,0,0,0,,我并不知道 Dialogue: 0,0:19:36.22,0:19:38.16,Default,,0,0,0,,我本应该在那里写一个加运算符的 Dialogue: 0,0:19:39.37,0:19:40.44,Default,,0,0,0,,但我无法那样做 Dialogue: 0,0:19:41.34,0:19:45.88,Default,,0,0,0,,而这种方式则是问 这个符号对象是否为 Dialogue: 0,0:19:45.98,0:19:48.14,Default,,0,0,0,,代表加运算符的符号 Dialogue: 0,0:19:49.57,0:19:51.92,Default,,0,0,0,,这才是我想要问和知道的问题 Dialogue: 0,0:19:52.92,0:19:54.45,Default,,0,0,0,,在我们深入讨论之前 Dialogue: 0,0:19:54.45,0:19:57.81,Default,,0,0,0,,我想要指出 “引用”是一个复杂的概念 Dialogue: 0,0:19:58.85,0:20:01.84,Default,,0,0,0,,语言中引入这个概念将会造成许多麻烦 Dialogue: 0,0:20:03.57,0:20:05.04,Default,,0,0,0,,请看下面这张幻灯片 Dialogue: 0,0:20:06.38,0:20:09.49,Default,,0,0,0,,这里这个推论没有问题 Dialogue: 0,0:20:11.62,0:20:17.04,Default,,0,0,0,,这是说 Alyssa聪明而Alyssa是George的妈妈 Dialogue: 0,0:20:17.40,0:20:20.60,Default,,0,0,0,,通过IS建立了一个等式 Dialogue: 0,0:20:22.13,0:20:26.30,Default,,0,0,0,,我们可以从这两个陈述推论出 George妈妈很聪明 Dialogue: 0,0:20:27.32,0:20:33.16,Default,,0,0,0,,这是因为我们总可以在表达式中等价替换 Dialogue: 0,0:20:34.09,0:20:35.16,Default,,0,0,0,,真是这样吗? Dialogue: 0,0:20:36.52,0:20:40.37,Default,,0,0,0,,这个例子说 “Chicago”有七个字母 Dialogue: 0,0:20:41.12,0:20:44.86,Default,,0,0,0,,引用则是强调我讨论的是单词“Chicago” Dialogue: 0,0:20:44.86,0:20:46.86,Default,,0,0,0,,而不是单词所代表的意思 Dialogue: 0,0:20:49.82,0:20:52.77,Default,,0,0,0,,这里说 Chicago是Illinois州最大的城市 Dialogue: 0,0:20:54.61,0:20:55.80,Default,,0,0,0,,而(代换的)结果是…… Dialogue: 0,0:20:55.80,0:20:59.09,Default,,0,0,0,,我可能会得到 Illinois州最大的城市有七个字母 Dialogue: 0,0:20:59.32,0:21:01.06,Default,,0,0,0,,这显然是错的 Dialogue: 0,0:21:05.16,0:21:07.17,Default,,0,0,0,,喔!手写笔好使了 Dialogue: 0,0:21:09.29,0:21:12.24,Default,,0,0,0,,所以 一旦我们有了(引用)这样的东西 Dialogue: 0,0:21:12.48,0:21:14.49,Default,,0,0,0,,我们的语言就会变得复杂 Dialogue: 0,0:21:14.49,0:21:18.34,Default,,0,0,0,,因为我们对于语言的一些操作就不再正确 Dialogue: 0,0:21:18.34,0:21:20.76,Default,,0,0,0,,比如通过等价代换来得到正确答案 Dialogue: 0,0:21:21.29,0:21:23.50,Default,,0,0,0,,如果不小心地操作就会出错 Dialogue: 0,0:21:24.49,0:21:27.34,Default,,0,0,0,,在一个引用不透明的上下文中 我们无法进行代换 Dialogue: 0,0:21:27.89,0:21:32.64,Default,,0,0,0,,引用就是引用不透明上下文的典型 Dialogue: 0,0:21:33.17,0:21:35.28,Default,,0,0,0,,如果你知道那是什么意思……你可以成为一位哲学家 Dialogue: 0,0:21:35.42,0:21:37.02,Default,,0,0,0,,或许我们之中就有一位 Dialogue: 0,0:21:37.53,0:21:41.32,Default,,0,0,0,,言归正传 我们继续 Dialogue: 0,0:21:41.32,0:21:44.98,Default,,0,0,0,,现在我们对一个有2000年历史的问题至少有了操作上的理解 Dialogue: 0,0:21:45.26,0:21:48.13,Default,,0,0,0,,关于名称、提及和等等类似的问题 Dialogue: 0,0:21:52.32,0:22:01.60,Default,,0,0,0,,我得定义如何把两个数加起来 (DEFINE (MAKE-SUM A1 A2)) Dialogue: 0,0:22:02.12,0:22:03.62,Default,,0,0,0,,我简单实现一下 Dialogue: 0,0:22:03.62,0:22:11.96,Default,,0,0,0,,'+、A1、A2构成列表 Dialogue: 0,0:22:13.86,0:22:17.37,Default,,0,0,0,,我可以决定如何取出第一个元素 Dialogue: 0,0:22:21.84,0:22:25.32,Default,,0,0,0,,(DEFINE A1 CADR) Dialogue: 0,0:22:33.88,0:22:35.90,Default,,0,0,0,,这里又给大家介绍了一个基本过程 Dialogue: 0,0:22:36.17,0:22:39.10,Default,,0,0,0,,这个是取出某物CDR部分的CAR部分 Dialogue: 0,0:22:39.80,0:22:44.53,Default,,0,0,0,,大家或许会好奇 这些基本过程为什么叫做CAR和CDR Dialogue: 0,0:22:44.66,0:22:48.42,Default,,0,0,0,,而且传承了下来 尽管叫做LEFT和RIGHT会好一点 Dialogue: 0,0:22:48.76,0:22:50.44,Default,,0,0,0,,我们本可以那样叫的 Dialogue: 0,0:22:51.28,0:22:56.25,Default,,0,0,0,,呃 其实 这个名字来自于很久以前 当发明Lisp时 Dialogue: 0,0:22:56.36,0:23:00.80,Default,,0,0,0,,我想大概是58年的样子 是在类似于704之类的机子上实现的 Dialogue: 0,0:23:00.80,0:23:05.41,Default,,0,0,0,,这个机器有个地址寄存器和减量寄存器 Dialogue: 0,0:23:05.41,0:23:08.17,Default,,0,0,0,,而这些就是地址寄存器和减量寄存器的值 Dialogue: 0,0:23:08.17,0:23:09.37,Default,,0,0,0,,所以这是历史遗留问题 Dialogue: 0,0:23:09.64,0:23:11.28,Default,,0,0,0,,但是这些名字为什么又延续下来了呢? Dialogue: 0,0:23:11.74,0:23:14.76,Default,,0,0,0,,这是因为Lisp程序员喜欢用电话交流 Dialogue: 0,0:23:15.68,0:23:19.60,Default,,0,0,0,,要是你有一长串的CAR和CDR序列 你就可能说“CDADDEDR” Dialogue: 0,0:23:21.01,0:23:22.32,Default,,0,0,0,,这是可以理解的 Dialogue: 0,0:23:22.32,0:23:27.02,Default,,0,0,0,,但是左边的右边的右边的左边就不是那么清楚了 Dialogue: 0,0:23:27.60,0:23:30.02,Default,,0,0,0,,这就是我们为什么有这些黑话 Dialogue: 0,0:23:30.54,0:23:34.14,Default,,0,0,0,,典型的Lisp系统 默认定义到第四层 Dialogue: 0,0:23:38.66,0:23:47.05,Default,,0,0,0,,而定义A2为……当然 如果我们考察这些表达式中的一个 Dialogue: 0,0:23:47.36,0:23:52.14,Default,,0,0,0,,比如(+ 3 5) Dialogue: 0,0:23:52.58,0:24:10.45,Default,,0,0,0,,这个实际上是一个包含有'+、数3和数5的表 Dialogue: 0,0:24:11.72,0:24:15.18,Default,,0,0,0,,表的CAR部分是'+ Dialogue: 0,0:24:16.13,0:24:18.21,Default,,0,0,0,,CDR部分的CAR部分 Dialogue: 0,0:24:18.21,0:24:20.21,Default,,0,0,0,,也就是先取CDR部分 然后再取CAR部分 Dialogue: 0,0:24:20.21,0:24:22.21,Default,,0,0,0,,这就是我如何取得3的 也就是第一个参数 Dialogue: 0,0:24:22.52,0:24:25.69,Default,,0,0,0,,CDR的CDR部分的CAR部分 就是这个……数5 Dialogue: 0,0:24:28.69,0:24:33.66,Default,,0,0,0,,当然类似地 对于乘式我可以这样定义 Dialogue: 0,0:24:35.22,0:24:36.56,Default,,0,0,0,,我快速地演示一下 Dialogue: 0,0:24:48.97,0:24:50.64,Default,,0,0,0,,(DEFINE (PRODUCT? EXP)) Dialogue: 0,0:24:51.05,0:24:54.69,Default,,0,0,0,,如果它不是原子的 而且 Dialogue: 0,0:25:01.41,0:25:14.14,Default,,0,0,0,,EXP的CAR部分与用于表示乘法的符号'*在 EQ?的语义下相等 Dialogue: 0,0:25:15.64,0:25:32.00,Default,,0,0,0,,(DEFINE (MAKE-PRODUCT M1 M2)) Dialogue: 0,0:25:34.42,0:25:39.30,Default,,0,0,0,,(LIST '* M1 M2) Dialogue: 0,0:25:40.82,0:25:56.81,Default,,0,0,0,,并定义M1为CADR M2为CADDR Dialogue: 0,0:26:00.09,0:26:02.38,Default,,0,0,0,,当你说行话的时候 你就上道了 Dialogue: 0,0:26:02.53,0:26:05.53,Default,,0,0,0,,你可以取表的CDR 也可以把它们组合起来 Dialogue: 0,0:26:06.29,0:26:10.10,Default,,0,0,0,,现在 我们有了原理上完整的求导程序了 Dialogue: 0,0:26:10.10,0:26:11.70,Default,,0,0,0,,如果需要的话 你也可以添加更多的规则 Dialogue: 0,0:26:12.21,0:26:13.93,Default,,0,0,0,,它又要怎么用呢? Dialogue: 0,0:26:14.64,0:26:16.77,Default,,0,0,0,,我先把这个笔迹清了 Dialogue: 0,0:26:17.80,0:26:20.82,Default,,0,0,0,,恩 假设我在这里定义FOO为 Dialogue: 0,0:26:22.16,0:26:30.38,Default,,0,0,0,,定义FOO为A*X^2+B*X+C Dialogue: 0,0:26:30.54,0:26:32.08,Default,,0,0,0,,跟我们这里看到的是一样的 Dialogue: 0,0:26:32.08,0:26:36.36,Default,,0,0,0,,这里是用更习见的记号书写的代数表达式 Dialogue: 0,0:26:37.84,0:26:41.60,Default,,0,0,0,,那么 表达式FOO关于X的导数 结果在这里 Dialogue: 0,0:26:43.46,0:26:45.26,Default,,0,0,0,,真是乱得一团糟 Dialogue: 0,0:26:46.16,0:26:49.22,Default,,0,0,0,,我期望答案是2*A*X+B Dialogue: 0,0:26:50.68,0:26:53.44,Default,,0,0,0,,虽然与结果等价 但它并不是我们希望的结果 Dialogue: 0,0:26:54.58,0:26:55.22,Default,,0,0,0,,这是什么呢? Dialogue: 0,0:26:55.97,0:26:59.96,Default,,0,0,0,,我们最初有什么? Dialogue: 0,0:27:00.50,0:27:04.30,Default,,0,0,0,,我求X*X的导数 Dialogue: 0,0:27:04.69,0:27:10.53,Default,,0,0,0,,答案是X*1+1*X 这当然没错 Dialogue: 0,0:27:12.73,0:27:15.66,Default,,0,0,0,,这就是乘数的导数乘以被乘数加上乘数乘以被乘数的导数 Dialogue: 0,0:27:17.22,0:27:28.37,Default,,0,0,0,,那就是2X、A*2X就是2AX、0X^2省去 再加上0和这里的一大堆0 Dialogue: 0,0:27:28.96,0:27:30.12,Default,,0,0,0,,答案是对的 Dialogue: 0,0:27:30.12,0:27:35.14,Default,,0,0,0,,当我们还需要用户额外检验一下 真是糟糕投了 Dialogue: 0,0:27:35.56,0:27:37.26,Default,,0,0,0,,我们下一节再考虑这个内容 Dialogue: 0,0:27:37.68,0:27:38.61,Default,,0,0,0,,有疑问吗? Dialogue: 0,0:27:42.77,0:27:43.45,Default,,0,0,0,,请说 Dialogue: 0,0:27:43.89,0:27:46.69,Default,,0,0,0,,观众:写加号时不加引号 Dialogue: 0,0:27:46.69,0:27:50.82,Default,,0,0,0,,是表示引用加那个过程么? Dialogue: 0,0:27:50.82,0:27:55.42,Default,,0,0,0,,如果有需要的话 是否能在两个过程之间进行比较 Dialogue: 0,0:27:56.16,0:27:57.08,Default,,0,0,0,,教授:问得好! Dialogue: 0,0:27:57.45,0:28:02.26,Default,,0,0,0,,如果我这里不用左引号将这个引住 Dialogue: 0,0:28:03.88,0:28:07.13,Default,,0,0,0,,如果我这里不用引号 Dialogue: 0,0:28:07.33,0:28:14.20,Default,,0,0,0,,那么这里我就会引用定义好的加法过程 Dialogue: 0,0:28:15.38,0:28:24.88,Default,,0,0,0,,实际上 我可以比较两个过程是否同一 Dialogue: 0,0:28:24.88,0:28:27.45,Default,,0,0,0,,现在很难从语义上解释 Dialogue: 0,0:28:27.85,0:28:29.37,Default,,0,0,0,,我现在不想考虑这个问题 Dialogue: 0,0:28:29.89,0:28:32.40,Default,,0,0,0,,因为我不知道比较过程需要什么 Dialogue: 0,0:28:32.40,0:28:34.40,Default,,0,0,0,,这样做没有意义是有很多原因的 Dialogue: 0,0:28:35.52,0:28:37.53,Default,,0,0,0,,然而 这些符号我们是可以理解的 Dialogue: 0,0:28:38.54,0:28:40.56,Default,,0,0,0,,这也是我为什么我要将它们引住 Dialogue: 0,0:28:41.16,0:28:43.70,Default,,0,0,0,,我想讨论出现在这些代码中的符号 Dialogue: 0,0:28:46.16,0:28:46.92,Default,,0,0,0,,还有什么问题么? Dialogue: 0,0:28:48.52,0:28:51.86,Default,,0,0,0,,好吧 休息一下 谢谢大家 Dialogue: 0,0:28:55.12,0:29:00.66,Default,,0,0,0,,[音乐] Dialogue: 0,0:29:00.68,0:29:04.34,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:29:04.34,0:29:06.68,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:29:12.21,0:29:19.17,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:29:20.09,0:29:24.14,Declare,,0,0,0,,{\an2\fad(500,500)}符号化导数系统、引用 Dialogue: 0,0:29:29.86,0:29:30.92,Default,,0,0,0,,教授:好 我们继续 Dialogue: 0,0:29:31.46,0:29:37.76,Default,,0,0,0,,我们编写了一个貌似可行的代数表达式求导程序 Dialogue: 0,0:29:38.20,0:29:41.56,Default,,0,0,0,,这个程序是不完整的 你需要添加一些规则 Dialogue: 0,0:29:42.13,0:29:47.74,Default,,0,0,0,,你可能需要加强这个系统 使得它能够处理 Dialogue: 0,0:29:47.76,0:29:49.70,Default,,0,0,0,,多元加法和多元乘法 Dialogue: 0,0:29:49.89,0:29:51.38,Default,,0,0,0,,这些都相当简单 Dialogue: 0,0:29:52.73,0:29:56.93,Default,,0,0,0,,但这里面也有一些瑕疵 Dialogue: 0,0:29:57.48,0:30:02.37,Default,,0,0,0,,回到这张幻灯片来 Dialogue: 0,0:30:02.94,0:30:08.60,Default,,0,0,0,,我们发现 得到的表达式相当乱 Dialogue: 0,0:30:08.88,0:30:11.01,Default,,0,0,0,,这个表达式非常糟糕 Dialogue: 0,0:30:11.46,0:30:13.10,Default,,0,0,0,,我们是怎么得到这样的表达式的? Dialogue: 0,0:30:13.84,0:30:15.50,Default,,0,0,0,,为什么是这样呢? Dialogue: 0,0:30:16.84,0:30:18.74,Default,,0,0,0,,我们详细地分析一下这个表达式 Dialogue: 0,0:30:18.92,0:30:20.76,Default,,0,0,0,,找出这些片段都是出自哪里 Dialogue: 0,0:30:21.69,0:30:24.56,Default,,0,0,0,,如我们所见 这里的和式 Dialogue: 0,0:30:24.56,0:30:26.56,Default,,0,0,0,,也就是上一小节中给你们提到的 Dialogue: 0,0:30:27.12,0:30:29.09,Default,,0,0,0,,(+ (* X 1) (* 1 X)) Dialogue: 0,0:30:29.58,0:30:31.38,Default,,0,0,0,,是这个乘式的导数 Dialogue: 0,0:30:32.52,0:30:36.41,Default,,0,0,0,,也就是A乘上这个的积 这里A不是X的函数 Dialogue: 0,0:30:36.41,0:30:38.41,Default,,0,0,0,,因此A关于X是一个常数 Dialogue: 0,0:30:39.04,0:30:44.53,Default,,0,0,0,,导数为这个和式 从这里到这里 再到这里 Dialogue: 0,0:30:44.80,0:30:48.89,Default,,0,0,0,,因为这个是乘数乘以被乘数的导数 Dialogue: 0,0:30:49.57,0:30:54.45,Default,,0,0,0,,加上被乘数乘以乘数的导数 Dialogue: 0,0:30:54.66,0:30:59.06,Default,,0,0,0,,我们在黑板上的程序告诉我们确实是这样的 Dialogue: 0,0:31:00.65,0:31:05.36,Default,,0,0,0,,当然 这里B乘以X的积 Dialogue: 0,0:31:05.49,0:31:09.81,Default,,0,0,0,,被化成了 B*1+0*X Dialogue: 0,0:31:10.81,0:31:16.06,Default,,0,0,0,,因为B不是X的函数 Dialogue: 0,0:31:16.46,0:31:18.56,Default,,0,0,0,,因此B的导数为0 Dialogue: 0,0:31:18.77,0:31:21.48,Default,,0,0,0,,而X对自己求导则为1 Dialogue: 0,0:31:23.06,0:31:28.64,Default,,0,0,0,,这里的加法化成了 这两个导数的和 Dialogue: 0,0:31:29.37,0:31:33.50,Default,,0,0,0,,所以这里 我想告诉你和之前一样的东西 Dialogue: 0,0:31:33.66,0:31:35.89,Default,,0,0,0,,也就是在讲斐波那契数那时候 Dialogue: 0,0:31:37.77,0:31:39.49,Default,,0,0,0,,所谓的 “过程的形状” Dialogue: 0,0:31:41.38,0:31:46.44,Default,,0,0,0,,就是通过局部的规则向低层次展开 Dialogue: 0,0:31:48.05,0:31:52.57,Default,,0,0,0,,也就是过程代表了一系列用于演进过程局部规则 Dialogue: 0,0:31:53.36,0:32:00.09,Default,,0,0,0,,这里 过程还遗留了一些东西--也就是答案 Dialogue: 0,0:32:00.25,0:32:06.26,Default,,0,0,0,,这是通过遍历表达式的树结构构造出来的 Dialogue: 0,0:32:08.41,0:32:12.61,Default,,0,0,0,,答案中的每个部分对应问题中的某个部分 Dialogue: 0,0:32:14.46,0:32:17.78,Default,,0,0,0,,比如说 现在我们考察FOO的导数 Dialogue: 0,0:32:17.78,0:32:19.65,Default,,0,0,0,,也就是AX^2+BX+C Dialogue: 0,0:32:19.84,0:32:23.05,Default,,0,0,0,,并另令自变量 比如像这里 Dialogue: 0,0:32:24.14,0:32:27.48,Default,,0,0,0,,我们令A为自变量 求FOO的导数 Dialogue: 0,0:32:28.10,0:32:31.77,Default,,0,0,0,,这都非常相似 实际上 它们是同样的代数表达式 Dialogue: 0,0:32:32.45,0:32:35.24,Default,,0,0,0,,只是它们之中0和1的位置不一样罢了 Dialogue: 0,0:32:36.06,0:32:38.60,Default,,0,0,0,,这是因为在这个树结构的遍历中 Dialogue: 0,0:32:38.97,0:32:43.85,Default,,0,0,0,,只可能是CONSTANT?和SAME-VAR?会因变量的不同 Dialogue: 0,0:32:44.28,0:32:45.81,Default,,0,0,0,,而造成不同结果 Dialogue: 0,0:32:48.26,0:32:52.09,Default,,0,0,0,,回到黑板上来再看看 Dialogue: 0,0:32:52.65,0:32:57.49,Default,,0,0,0,,我们在求和式或乘式的导数时根本没有发挥的余地 Dialogue: 0,0:32:58.08,0:33:04.48,Default,,0,0,0,,真正可以做文章的地方 则是表达式和自变量 Dialogue: 0,0:33:04.80,0:33:10.10,Default,,0,0,0,,以及对于那些短小的表达式 是否为关于自变量的常量 Dialogue: 0,0:33:10.36,0:33:12.41,Default,,0,0,0,,就是这些地方导致了不同的0和1的产生 Dialogue: 0,0:33:12.69,0:33:14.49,Default,,0,0,0,,回过头来看这张幻灯 Dialogue: 0,0:33:15.12,0:33:18.16,Default,,0,0,0,,这里就出现了“0” Dialogue: 0,0:33:18.37,0:33:22.74,Default,,0,0,0,,这里是求FOO(A)的导数时得到的“1” Dialogue: 0,0:33:22.96,0:33:24.86,Default,,0,0,0,,我们得到了X^2 Dialogue: 0,0:33:24.96,0:33:32.53,Default,,0,0,0,,这个1是X*X关于X的导数 关于B求导时1变成了0 Dialogue: 0,0:33:32.64,0:33:34.89,Default,,0,0,0,,这里 我们求FOO关于C的导数 Dialogue: 0,0:33:36.78,0:33:39.30,Default,,0,0,0,,但是这些表达式的轮廓是一致的 Dialogue: 0,0:33:40.54,0:33:43.96,Default,,0,0,0,,看看这些轮廓 都是相同的 Dialogue: 0,0:33:50.37,0:33:52.28,Default,,0,0,0,,那么 难道是我们的规则出了问题? Dialogue: 0,0:33:53.58,0:33:55.02,Default,,0,0,0,,不 这些规则都对 Dialogue: 0,0:33:56.12,0:33:57.77,Default,,0,0,0,,我们曾经遇到过这种问题 Dialogue: 0,0:33:58.06,0:34:03.53,Default,,0,0,0,,你将会发现 这其中缺乏一些非常好的思想 Dialogue: 0,0:34:06.32,0:34:09.74,Default,,0,0,0,,昨天 我们在考察有理数时 Dialogue: 0,0:34:12.12,0:34:14.48,Default,,0,0,0,,想要得到3/4却得到6/8 Dialogue: 0,0:34:14.97,0:34:16.49,Default,,0,0,0,,答案没有化简 Dialogue: 0,0:34:18.09,0:34:20.90,Default,,0,0,0,,当然 当下的问题也非常类似 Dialogue: 0,0:34:21.18,0:34:25.41,Default,,0,0,0,,我想把不相同的表达式通过化简来使相同 Dialogue: 0,0:34:27.57,0:34:31.89,Default,,0,0,0,,当然 有理数加法和乘法的规则依然正确 Dialogue: 0,0:34:33.97,0:34:37.41,Default,,0,0,0,,因此这里 我们依葫芦画瓢 Dialogue: 0,0:34:37.78,0:34:39.89,Default,,0,0,0,,上次能行的办法 这次也没问题 Dialogue: 0,0:34:40.53,0:34:42.05,Default,,0,0,0,,也就是改换一下它的表示 Dialogue: 0,0:34:43.13,0:34:46.44,Default,,0,0,0,,或许在将其表示出来时我们可以进行 Dialogue: 0,0:34:47.88,0:34:49.78,Default,,0,0,0,,一步产生简化表示的步骤 Dialogue: 0,0:34:50.17,0:34:51.73,Default,,0,0,0,,当然啦 这也不是万用万灵 Dialogue: 0,0:34:52.49,0:34:54.14,Default,,0,0,0,,我也不想证明它是万能的 Dialogue: 0,0:34:55.12,0:35:00.44,Default,,0,0,0,,但这也是控制复杂度的一招妙计 Dialogue: 0,0:35:01.46,0:35:03.85,Default,,0,0,0,,我们小心翼翼地解决这些问题 Dialogue: 0,0:35:04.30,0:35:07.20,Default,,0,0,0,,我们所做的 就是把问题划分为几个部分 Dialogue: 0,0:35:07.57,0:35:08.73,Default,,0,0,0,,分别是求导规则 Dialogue: 0,0:35:11.32,0:35:15.80,Default,,0,0,0,,和在这种层面上的一般代数规则 Dialogue: 0,0:35:16.38,0:35:21.22,Default,,0,0,0,,然后就有一道抽象屏障 Dialogue: 0,0:35:22.48,0:35:33.49,Default,,0,0,0,,这里是代数表达式的表示--表结构 Dialogue: 0,0:35:37.33,0:35:42.56,Default,,0,0,0,,在这道屏障中 我定义了接口过程 Dialogue: 0,0:35:43.25,0:35:49.82,Default,,0,0,0,,比如 CONSTANT? SAME-VAR? Dialogue: 0,0:35:54.60,0:35:58.72,Default,,0,0,0,,又比如 SUM? MAKE-SUM Dialogue: 0,0:36:02.22,0:36:05.57,Default,,0,0,0,,还有 A1 A2 Dialogue: 0,0:36:06.60,0:36:08.58,Default,,0,0,0,,还有 PRODUCT? 之类的东西 Dialogue: 0,0:36:08.74,0:36:11.90,Default,,0,0,0,,我所需要的、针对各式代数表达式的东西 Dialogue: 0,0:36:12.94,0:36:19.14,Default,,0,0,0,,构筑这些屏障我可以随意地改换表示法 Dialogue: 0,0:36:20.14,0:36:23.20,Default,,0,0,0,,而不用改变在某种表示法下编写的规则 Dialogue: 0,0:36:25.04,0:36:29.08,Default,,0,0,0,,如果我能通过改变表示法来解决问题 Dialogue: 0,0:36:30.38,0:36:34.52,Default,,0,0,0,,那么把问题分解为两个部分则帮了我大忙 Dialogue: 0,0:36:35.65,0:36:37.54,Default,,0,0,0,,好吧 举一个非常简单的例子 Dialogue: 0,0:36:38.82,0:36:40.08,Default,,0,0,0,,我们的问题是什么? Dialogue: 0,0:36:40.26,0:36:43.61,Default,,0,0,0,,回到这张幻灯片来 Dialogue: 0,0:36:44.50,0:36:47.34,Default,,0,0,0,,看这里 哦 这相当糟糕 Dialogue: 0,0:36:47.62,0:36:51.86,Default,,0,0,0,,这里是一个表达式与“0”的和 Dialogue: 0,0:36:53.14,0:36:56.66,Default,,0,0,0,,毋庸置疑这应该是该表达式本身 Dialogue: 0,0:36:57.21,0:37:01.90,Default,,0,0,0,,为什么这里还会有加号? Dialogue: 0,0:37:03.38,0:37:04.57,Default,,0,0,0,,这其实可以更智能点 Dialogue: 0,0:37:05.56,0:37:10.08,Default,,0,0,0,,又比如说这里 是某表达式与“1”的积 Dialogue: 0,0:37:11.16,0:37:12.29,Default,,0,0,0,,这和之前一个道理 Dialogue: 0,0:37:12.86,0:37:15.68,Default,,0,0,0,,又像这里 与“0”相乘显然是“0” Dialogue: 0,0:37:17.86,0:37:19.52,Default,,0,0,0,,因此我们也不用去构造这些式子了 Dialogue: 0,0:37:21.44,0:37:22.62,Default,,0,0,0,,我们为什么不这么做呢? Dialogue: 0,0:37:23.66,0:37:27.96,Default,,0,0,0,,我们需要去修改表示法 基本上就是那里了 Dialogue: 0,0:37:37.40,0:37:41.84,Default,,0,0,0,,定义 MAKE-SUM 为 Dialogue: 0,0:37:42.05,0:37:43.76,Default,,0,0,0,,呃 现在就不是那么简单了 Dialogue: 0,0:37:44.00,0:37:50.40,Default,,0,0,0,,除非是有必要 否则我不会简单地把加号和式子组合成表 Dialogue: 0,0:37:51.72,0:37:53.05,Default,,0,0,0,,那么 还有哪些可能呢? Dialogue: 0,0:37:54.56,0:37:58.53,Default,,0,0,0,,如果……这里有一些可能的情况 Dialogue: 0,0:37:59.38,0:38:08.20,Default,,0,0,0,,如果都是数值的话 如果A1是数值的话 Dialogue: 0,0:38:09.05,0:38:10.93,Default,,0,0,0,,这个基本过程我刚刚提到过 Dialogue: 0,0:38:10.93,0:38:13.18,Default,,0,0,0,,也就是用来检测参数是否为数值 Dialogue: 0,0:38:15.38,0:38:23.82,Default,,0,0,0,,并且A2也是数值的话 也就是A2不是符号表达式 Dialogue: 0,0:38:24.45,0:38:26.20,Default,,0,0,0,,那么我们就直接把它们加起来 Dialogue: 0,0:38:26.45,0:38:29.92,Default,,0,0,0,,结果就是A1加上A2的和 Dialogue: 0,0:38:32.32,0:38:33.98,Default,,0,0,0,,我并不是检查它们代表数值 Dialogue: 0,0:38:33.98,0:38:35.98,Default,,0,0,0,,这里所有的符号都代表数值 Dialogue: 0,0:38:37.33,0:38:41.22,Default,,0,0,0,,就比如 我想要考察的是这个东西是否为数值3 Dialogue: 0,0:38:43.40,0:38:44.40,Default,,0,0,0,,另一种情况 Dialogue: 0,0:38:48.77,0:38:59.61,Default,,0,0,0,,假设A1是数值 并且为0 Dialogue: 0,0:39:04.20,0:39:06.38,Default,,0,0,0,,那么答案就是A2 Dialogue: 0,0:39:06.93,0:39:08.68,Default,,0,0,0,,不用再构造什么 Dialogue: 0,0:39:10.98,0:39:23.41,Default,,0,0,0,,如果A2是数值 并且为0 Dialogue: 0,0:39:27.16,0:39:28.90,Default,,0,0,0,,那么答案就是A1 Dialogue: 0,0:39:30.04,0:39:33.65,Default,,0,0,0,,如果没有比这些更好的情况 Dialogue: 0,0:39:34.13,0:39:35.61,Default,,0,0,0,,我就需要构造一个表 Dialogue: 0,0:39:37.86,0:39:42.86,Default,,0,0,0,,构造一个用于表示答案的表 Dialogue: 0,0:39:44.13,0:39:52.33,Default,,0,0,0,,其中有 '+、A1和A2 Dialogue: 0,0:39:58.66,0:40:01.65,Default,,0,0,0,,当然 积的导数也可以类比此法 Dialogue: 0,0:40:03.01,0:40:05.04,Default,,0,0,0,,这里 我就不细讲了 Dialogue: 0,0:40:05.44,0:40:07.24,Default,,0,0,0,,我就直接在黑板上写出结果 Dialogue: 0,0:40:07.65,0:40:09.80,Default,,0,0,0,,这并不是很重要 你们已经了解它的思想了 Dialogue: 0,0:40:10.76,0:40:11.61,Default,,0,0,0,,非常简明 Dialogue: 0,0:40:12.86,0:40:19.89,Default,,0,0,0,,现在 我们来看看用这种方式改造程序后 效果如何 Dialogue: 0,0:40:21.68,0:40:27.88,Default,,0,0,0,,哦 这是修改表达式构造函数后的求导结果 Dialogue: 0,0:40:28.98,0:40:32.21,Default,,0,0,0,,对同样地FOO求导:AX^2+BX+C Dialogue: 0,0:40:33.28,0:40:40.70,Default,,0,0,0,,我得到了 2AX+B Dialogue: 0,0:40:40.70,0:40:42.10,Default,,0,0,0,,虽然它并没有化到最简 Dialogue: 0,0:40:42.60,0:40:44.53,Default,,0,0,0,,我应该合并同类项和求和 Dialogue: 0,0:40:45.06,0:40:46.08,Default,,0,0,0,,但这又是另外一回事了 Dialogue: 0,0:40:47.12,0:40:51.86,Default,,0,0,0,,当然啦 完成这个功能的代码就大而复杂了 Dialogue: 0,0:40:52.28,0:40:55.28,Default,,0,0,0,,代数化简 是一项繁复的工作 Dialogue: 0,0:40:56.37,0:41:00.13,Default,,0,0,0,,你们可能听过MIT以前开发的一个非常出名的程序 MAXIMA Dialogue: 0,0:41:00.42,0:41:03.14,Default,,0,0,0,,它有5000页的LISP代码 Dialogue: 0,0:41:03.92,0:41:06.50,Default,,0,0,0,,大部分是代数化简的操作 Dialogue: 0,0:41:08.08,0:41:12.21,Default,,0,0,0,,这里是FOO的导数 Dialogue: 0,0:41:12.21,0:41:16.86,Default,,0,0,0,,要是我的话 我会在初等微积分课上讲讲“改换主变量”这个东西 Dialogue: 0,0:41:18.38,0:41:22.49,Default,,0,0,0,,以A为自变量 FOO的导数则是X*X Dialogue: 0,0:41:22.80,0:41:23.80,Default,,0,0,0,,看起来还不差 Dialogue: 0,0:41:24.74,0:41:27.53,Default,,0,0,0,,以B为自变量 FOO的导数则是X本身 Dialogue: 0,0:41:28.06,0:41:30.12,Default,,0,0,0,,以C为自变量 FOO的导数则为“1” Dialogue: 0,0:41:30.70,0:41:32.04,Default,,0,0,0,,我对这些结果很满意 Dialogue: 0,0:41:34.10,0:41:39.01,Default,,0,0,0,,你所看到的 都是精心设计、仔细规划的例子 Dialogue: 0,0:41:39.56,0:41:42.60,Default,,0,0,0,,用以展示如何操作代数表达式 Dialogue: 0,0:41:42.96,0:41:47.93,Default,,0,0,0,,我们如何不用具体的语法 而用抽象的语法抽象地进行 Dialogue: 0,0:41:49.21,0:41:56.29,Default,,0,0,0,,以及我们如何使用抽象屏障控制构造这些表达式 Dialogue: 0,0:41:57.80,0:42:00.41,Default,,0,0,0,,真正的奥义并不是如此的简单 Dialogue: 0,0:42:01.00,0:42:04.45,Default,,0,0,0,,实际上 真正的奥义在于我在操作这些表达式时 Dialogue: 0,0:42:04.45,0:42:06.72,Default,,0,0,0,,代数表达式和代码表达式-- Dialogue: 0,0:42:06.72,0:42:07.97,Default,,0,0,0,,回过头来看看幻灯片 Dialogue: 0,0:42:08.08,0:42:10.52,Default,,0,0,0,,都是同一种Lisp表达式 Dialogue: 0,0:42:12.02,0:42:12.97,Default,,0,0,0,,这样一语双关 一石二鸟 Dialogue: 0,0:42:13.82,0:42:21.49,Default,,0,0,0,,我用表示代码相同的方法来作为我的表示法 Dialogue: 0,0:42:22.89,0:42:26.52,Default,,0,0,0,,为了要这样做 我得付出点代价 Dialogue: 0,0:42:26.90,0:42:30.34,Default,,0,0,0,,我需要使用类似于“引用”的东西 Dialogue: 0,0:42:30.97,0:42:38.17,Default,,0,0,0,,这是因为 我的语言可以编写讨论语言表达式的表达式 Dialogue: 0,0:42:39.76,0:42:43.22,Default,,0,0,0,,我需要有某种东西指出 这个是我需要讨论的表达式 Dialogue: 0,0:42:43.76,0:42:46.13,Default,,0,0,0,,而不是说 (去求)这个表达式的值 Dialogue: 0,0:42:47.20,0:42:48.44,Default,,0,0,0,,我想要的是前者 Dialogue: 0,0:42:51.34,0:42:55.36,Default,,0,0,0,,引用阻止表达式被求值 其语义为“就是表达式本身” Dialogue: 0,0:42:57.97,0:43:00.85,Default,,0,0,0,,有了这种能力以后 Dialogue: 0,0:43:01.58,0:43:03.82,Default,,0,0,0,,如果我可以操作语言的表达式 Dialogue: 0,0:43:04.80,0:43:09.00,Default,,0,0,0,,我可以在语言层之上构建更加有力的层次 Dialogue: 0,0:43:09.77,0:43:12.64,Default,,0,0,0,,因为我可以编写不仅仅是内嵌于Lisp的语言 Dialogue: 0,0:43:13.46,0:43:14.80,Default,,0,0,0,,或者是其它的语言 Dialogue: 0,0:43:15.26,0:43:17.76,Default,,0,0,0,,我可以编写一种完全不同的语言 Dialogue: 0,0:43:18.58,0:43:22.24,Default,,0,0,0,,而其实质上则是被Lisp或其它语言所解释 Dialogue: 0,0:43:23.17,0:43:25.46,Default,,0,0,0,,我们以后还会对此有更深入的理解 Dialogue: 0,0:43:26.56,0:43:32.09,Default,,0,0,0,,我现在只是想让你们意识到 Dialogue: 0,0:43:32.36,0:43:34.98,Default,,0,0,0,,我们已经感触到了一种惊人的力量 Dialogue: 0,0:43:36.00,0:43:37.82,Default,,0,0,0,,现在我们有了方天画戟 Dialogue: 0,0:43:38.17,0:43:40.92,Default,,0,0,0,,当我们使用它时 也得万分小心 Dialogue: 0,0:43:42.17,0:43:43.00,Default,,0,0,0,,谢谢大家 Dialogue: 0,0:43:44.10,0:44:00.54,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:43:44.10,0:44:00.54,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec3b.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Last Style Storage: Default Scroll Position: 581 Active Line: 593 Video Zoom Percent: 0.625 Audio URI: G:\untitled\ref\lec3b_480_muxed2.mp4 Video File: G:\untitled\ref\lec3b_480_muxed2.mp4 Video Aspect Ratio: c1.33333 Video Position: 79137 PlayResX: 640 PlayResY: 480 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:02.32,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP Group Dialogue: 0,0:00:02.57,0:00:06.01,Declare,,0,0,0,,{\an2\fad(500,500)}Translation && Timeline: Dysprosium\NEncode && Effects: Dysprosium Dialogue: 0,0:00:06.06,0:00:08.97,Declare,,0,0,0,,{\an2\fad(500,500)}Credit: Prof. Qiu Zonyan Dialogue: 0,0:00:11.24,0:00:14.46,Declare,,0,0,0,,{\an2\fad(500,500)}Symbolic Differentiation: Quotation Dialogue: 0,0:00:19.10,0:00:23.41,EN,,0,0,0,,PROFESSOR: Well, Hal just told us how you build robust systems. Dialogue: 0,0:00:23.80,0:00:26.17,EN,,0,0,0,,The key idea was-- Dialogue: 0,0:00:26.81,0:00:30.20,EN,,0,0,0,,I'm sure that many of you don't really assimilate that yet-- Dialogue: 0,0:00:30.20,0:00:33.77,EN,,0,0,0,,but the key idea is that in order to make a system that's robust, Dialogue: 0,0:00:33.93,0:00:36.48,EN,,0,0,0,,it has to be insensitive to small changes, Dialogue: 0,0:00:36.60,0:00:37.37,EN,,0,0,0,,that is, Dialogue: 0,0:00:37.37,0:00:40.90,EN,,0,0,0,,a small change in the problem should lead to only a small change in the solution. Dialogue: 0,0:00:41.32,0:00:42.90,EN,,0,0,0,,There ought to be a continuity. Dialogue: 0,0:00:42.90,0:00:45.94,EN,,0,0,0,,The space of solutions ought to be continuous in this space of problems. Dialogue: 0,0:00:46.25,0:00:48.76,EN,,0,0,0,,The way he was explaining how to do that Dialogue: 0,0:00:49.46,0:00:54.78,EN,,0,0,0,,was instead of solving a particular problem at every level of decomposition of the problem at the subproblems, Dialogue: 0,0:00:55.08,0:00:56.78,EN,,0,0,0,,where you solve the class of problems, Dialogue: 0,0:00:56.78,0:01:00.40,EN,,0,0,0,,which are a neighborhood of the particular problem that you're trying to solve. Dialogue: 0,0:01:01.40,0:01:04.76,EN,,0,0,0,,The way you do that is by producing a language at that level of detail Dialogue: 0,0:01:04.76,0:01:10.33,EN,,0,0,0,,in which the solutions to that class of problems is representable in that language. Dialogue: 0,0:01:11.37,0:01:15.09,EN,,0,0,0,,Therefore when you change makes more changes to the problem you're trying to solve, Dialogue: 0,0:01:15.09,0:01:19.29,EN,,0,0,0,,you generally have to make only small local changes to the solution you've constructed, Dialogue: 0,0:01:19.29,0:01:22.26,EN,,0,0,0,,because at the level of detail you're working, Dialogue: 0,0:01:22.26,0:01:24.26,EN,,0,0,0,,there's a language where you can express Dialogue: 0,0:01:24.80,0:01:28.14,EN,,0,0,0,,the various solutions to alternate problems of the same type. Dialogue: 0,0:01:30.04,0:01:33.74,EN,,0,0,0,,Well that's the beginning of a very important idea, Dialogue: 0,0:01:34.40,0:01:38.61,EN,,0,0,0,,the most important perhaps idea that makes computer science more powerful Dialogue: 0,0:01:38.61,0:01:42.37,EN,,0,0,0,,than most of the other kinds of engineering disciplines we know about. Dialogue: 0,0:01:43.38,0:01:44.73,EN,,0,0,0,,What we've seen so far Dialogue: 0,0:01:44.73,0:01:48.78,EN,,0,0,0,,is sort of how to use embedding of languages. Dialogue: 0,0:01:49.26,0:01:53.36,EN,,0,0,0,,And, of course, the power of embedding languages partly comes from Dialogue: 0,0:01:54.12,0:01:56.86,EN,,0,0,0,,procedures like this one that I showed you yesterday. Dialogue: 0,0:01:57.37,0:02:02.13,EN,,0,0,0,,What you see here is the derivative program that we described yesterday. Dialogue: 0,0:02:02.13,0:02:05.92,EN,,0,0,0,,It's a procedure that takes a procedure as an argument Dialogue: 0,0:02:06.00,0:02:07.92,EN,,0,0,0,,and returns a procedure as a value. Dialogue: 0,0:02:09.61,0:02:12.65,EN,,0,0,0,,And using such things is very nice. Dialogue: 0,0:02:12.65,0:02:14.65,EN,,0,0,0,,You can make things like push combinators Dialogue: 0,0:02:14.65,0:02:16.86,EN,,0,0,0,,and all that sort of wonderful thing that you saw last time. Dialogue: 0,0:02:17.68,0:02:20.54,EN,,0,0,0,,However, now I'm going to really muddy the waters. Dialogue: 0,0:02:21.56,0:02:25.90,EN,,0,0,0,,See this confuses the issue of what's the procedure and what is data, Dialogue: 0,0:02:26.56,0:02:27.81,EN,,0,0,0,,but not very badly. Dialogue: 0,0:02:28.42,0:02:30.90,EN,,0,0,0,,What we really want to do is confuse it very badly. Dialogue: 0,0:02:31.18,0:02:32.44,EN,,0,0,0,,And the best way to do that Dialogue: 0,0:02:32.44,0:02:37.62,EN,,0,0,0,,is to get involved with the manipulation of the algebraic expressions that the procedures themselves are expressed in. Dialogue: 0,0:02:39.73,0:02:45.58,EN,,0,0,0,,So at this point, I want to talk about instead of things like on this slide, Dialogue: 0,0:02:45.89,0:02:49.72,EN,,0,0,0,,the derivative procedure being a thing that manipulates a procedure-- Dialogue: 0,0:02:49.72,0:02:51.94,EN,,0,0,0,,this is a numerical method you see here. Dialogue: 0,0:02:51.94,0:02:58.93,EN,,0,0,0,,And what you're seeing is a representation of the numerical approximationto the derivative. Dialogue: 0,0:02:59.29,0:03:00.44,EN,,0,0,0,,That's what's here. Dialogue: 0,0:03:00.86,0:03:04.93,EN,,0,0,0,,In fact what I'd like to talk about is instead things that look like this. Dialogue: 0,0:03:06.05,0:03:11.33,EN,,0,0,0,,And what we have here are rules from a calculus book. Dialogue: 0,0:03:12.09,0:03:16.17,EN,,0,0,0,,These are rules for finding the derivatives of the expressions Dialogue: 0,0:03:16.70,0:03:20.58,EN,,0,0,0,,that one might write in some algebraic language. Dialogue: 0,0:03:21.64,0:03:24.41,EN,,0,0,0,,It says things like a derivative of a constant is 0. Dialogue: 0,0:03:25.13,0:03:29.09,EN,,0,0,0,,The derivative of the valuable with respect to which you are taking the derivative is 1. Dialogue: 0,0:03:29.32,0:03:31.93,EN,,0,0,0,,The derivative of a constant times the function Dialogue: 0,0:03:32.09,0:03:34.37,EN,,0,0,0,,is the constant times the derivative of the function, Dialogue: 0,0:03:34.77,0:03:36.04,EN,,0,0,0,,and things like that. Dialogue: 0,0:03:38.05,0:03:41.38,EN,,0,0,0,,These are exact expressions. These are not numerical approximations. Dialogue: 0,0:03:42.96,0:03:44.52,EN,,0,0,0,,Can we make programs? Dialogue: 0,0:03:44.52,0:03:52.24,EN,,0,0,0,,And, in fact, it's very easy to make programs that manipulate these expressions. Dialogue: 0,0:03:56.38,0:03:59.52,EN,,0,0,0,,Well let's see. Let's look at these rules in some detail. Dialogue: 0,0:04:01.08,0:04:05.22,EN,,0,0,0,,You all have seen these rules in your elementary calculus class at one time or another. Dialogue: 0,0:04:05.98,0:04:12.12,EN,,0,0,0,,And you know from calculus that it's easy to produce derivatives of arbitrary expressions. Dialogue: 0,0:04:12.53,0:04:16.05,EN,,0,0,0,,You also know from your elementary calculus that it's hard to produce integrals. Dialogue: 0,0:04:16.98,0:04:19.37,EN,,0,0,0,,Yet integrals and derivatives are opposites of each other. Dialogue: 0,0:04:19.52,0:04:21.28,EN,,0,0,0,,They're inverse operations. Dialogue: 0,0:04:21.61,0:04:23.30,EN,,0,0,0,,And they have the same rules. Dialogue: 0,0:04:24.16,0:04:29.68,EN,,0,0,0,,What is special about these rules that makes it possible for one Dialogue: 0,0:04:29.68,0:04:33.65,EN,,0,0,0,,to produce derivatives easily and integrals why it's so hard? Dialogue: 0,0:04:34.85,0:04:36.98,EN,,0,0,0,,Let's think about that very simply. Dialogue: 0,0:04:37.40,0:04:38.38,EN,,0,0,0,,Look at these rules. Dialogue: 0,0:04:39.36,0:04:43.06,EN,,0,0,0,,Every one of these rules, when used in the direction for taking derivatives, Dialogue: 0,0:04:43.06,0:04:44.80,EN,,0,0,0,,which is in the direction of this arrow, Dialogue: 0,0:04:46.68,0:04:49.16,EN,,0,0,0,,the left side is matched against your expression, Dialogue: 0,0:04:49.16,0:04:53.05,EN,,0,0,0,,and the right side is the thing which is the derivative of that expression. Dialogue: 0,0:04:54.02,0:04:55.65,EN,,0,0,0,,The arrow is going that way. Dialogue: 0,0:04:57.37,0:05:00.45,EN,,0,0,0,,In each of these rules, Dialogue: 0,0:05:01.24,0:05:03.72,EN,,0,0,0,,the expressions on the right-hand side of the rule Dialogue: 0,0:05:03.72,0:05:06.56,EN,,0,0,0,,that are contained within derivatives are subexpressions, Dialogue: 0,0:05:06.56,0:05:10.29,EN,,0,0,0,,are proper subexpressions, of the expression on the left-hand side. Dialogue: 0,0:05:10.60,0:05:13.25,EN,,0,0,0,,So here we see the derivative of the sum, Dialogue: 0,0:05:13.92,0:05:16.13,EN,,0,0,0,,witch is the expression on the left-hand side Dialogue: 0,0:05:16.13,0:05:18.38,EN,,0,0,0,,is the sum of the derivatives of the pieces. Dialogue: 0,0:05:20.08,0:05:24.49,EN,,0,0,0,,So the rule of moving to the right are reduction rules. Dialogue: 0,0:05:25.02,0:05:26.61,EN,,0,0,0,,The problem becomes easier. Dialogue: 0,0:05:27.56,0:05:31.48,EN,,0,0,0,,I make, I turn a big complicated problem it's lots of smaller problems Dialogue: 0,0:05:32.44,0:05:35.76,EN,,0,0,0,,and then combine the results, a perfect place for recursion to work. Dialogue: 0,0:05:36.58,0:05:40.85,EN,,0,0,0,,If I'm going in the other direction like this, Dialogue: 0,0:05:41.81,0:05:45.13,EN,,0,0,0,,if I'm trying to produce integrals, well there are several problems you see here. Dialogue: 0,0:05:45.24,0:05:49.09,EN,,0,0,0,,First of all, if I try to integrate an expression like a sum, Dialogue: 0,0:05:49.21,0:05:50.81,EN,,0,0,0,,more than one rule matches. Dialogue: 0,0:05:50.81,0:05:52.10,EN,,0,0,0,,Here's one that matches. Dialogue: 0,0:05:52.48,0:05:53.65,EN,,0,0,0,,Here's one that matches. Dialogue: 0,0:05:54.81,0:05:57.09,EN,,0,0,0,,I don't know which one to take. And they may be different. Dialogue: 0,0:05:57.70,0:06:00.00,EN,,0,0,0,,I may get to explore different things. Dialogue: 0,0:06:00.25,0:06:03.64,EN,,0,0,0,,Also, the expressions become larger in that direction. Dialogue: 0,0:06:04.53,0:06:06.30,EN,,0,0,0,,And when the expressions become larger, Dialogue: 0,0:06:06.30,0:06:10.56,EN,,0,0,0,,then there's no guarantee that any particular path I choose will terminate, Dialogue: 0,0:06:10.94,0:06:13.46,EN,,0,0,0,,because we will only terminate by accidental cancellation. Dialogue: 0,0:06:14.24,0:06:18.05,EN,,0,0,0,,So that's why integrals are complicated searches and hard to do. Dialogue: 0,0:06:19.12,0:06:20.96,EN,,0,0,0,,Right now I don't want to do anything as hard as that. Dialogue: 0,0:06:21.49,0:06:23.06,EN,,0,0,0,,Let's work on derivatives for a while. Dialogue: 0,0:06:24.14,0:06:28.13,EN,,0,0,0,,Well, these rules are ones you know for the most part hopefully. Dialogue: 0,0:06:28.78,0:06:31.88,EN,,0,0,0,,So let's see if we can write a program which is these rules. Dialogue: 0,0:06:32.22,0:06:33.72,EN,,0,0,0,,And that should be very easy. Dialogue: 0,0:06:34.89,0:06:36.21,EN,,0,0,0,,Just write the program. Dialogue: 0,0:06:36.69,0:06:39.29,EN,,0,0,0,,See, because while I showed you is that it's a reduction rule, Dialogue: 0,0:06:39.29,0:06:41.29,EN,,0,0,0,,it's something appropriate for a recursion. Dialogue: 0,0:06:43.08,0:06:45.72,EN,,0,0,0,,And, of course, what we have for each of these rules is we have a case Dialogue: 0,0:06:46.66,0:06:47.78,EN,,0,0,0,,in some case analysis. Dialogue: 0,0:06:48.58,0:06:50.36,EN,,0,0,0,,So I'm just going to write this program down. Dialogue: 0,0:06:52.88,0:06:57.69,EN,,0,0,0,,Now, of course, I'm going to be saying something you have to believe. Right? Dialogue: 0,0:06:57.69,0:07:00.33,EN,,0,0,0,,What you have to believe is I can represent these algebraic expressions, Dialogue: 0,0:07:00.68,0:07:03.88,EN,,0,0,0,,that I can grab their parts, that I can put them together. Dialogue: 0,0:07:04.24,0:07:06.49,EN,,0,0,0,,We've invented list structures so that you can do that. Dialogue: 0,0:07:07.52,0:07:09.14,EN,,0,0,0,,But you don't want to worry about that now. Dialogue: 0,0:07:09.66,0:07:12.45,EN,,0,0,0,,Right now I'm going to write the program that encapsulates these rules Dialogue: 0,0:07:12.76,0:07:15.85,EN,,0,0,0,,independent of the representation of the algebraic expressions. Dialogue: 0,0:07:20.42,0:07:28.84,EN,,0,0,0,,You have a derivative of an expression with respect to a variable. Dialogue: 0,0:07:30.50,0:07:33.08,EN,,0,0,0,,This is a different thing than the derivative of the function. Dialogue: 0,0:07:34.82,0:07:38.61,EN,,0,0,0,,That's what we saw last time, that numerical approximation. Dialogue: 0,0:07:39.00,0:07:40.82,EN,,0,0,0,,It's something you can't open up a function. Dialogue: 0,0:07:40.82,0:07:41.89,EN,,0,0,0,,It's just the answers. Dialogue: 0,0:07:43.09,0:07:45.18,EN,,0,0,0,,The derivative of an expression is the way it's written. Dialogue: 0,0:07:45.74,0:07:47.85,EN,,0,0,0,,And therefore it's a syntactic phenomenon. Dialogue: 0,0:07:48.29,0:07:51.62,EN,,0,0,0,,And so a lot of what we're going to be doing today is worrying about syntax, Dialogue: 0,0:07:52.33,0:07:54.12,EN,,0,0,0,,syntax of expressions and things like that. Dialogue: 0,0:07:54.70,0:07:55.93,EN,,0,0,0,,Well, there's a case analysis. Dialogue: 0,0:07:57.50,0:08:01.08,EN,,0,0,0,,Anytime we do anything complicated thereby a recursion, Dialogue: 0,0:08:01.08,0:08:02.64,EN,,0,0,0,,we presumably need a case analysis. Dialogue: 0,0:08:03.62,0:08:05.16,EN,,0,0,0,,It's the essential way to begin. Dialogue: 0,0:08:05.16,0:08:07.40,EN,,0,0,0,,And that's usually a conditional of some large kind. Dialogue: 0,0:08:08.08,0:08:09.97,EN,,0,0,0,,Well, what are their possibilities? Dialogue: 0,0:08:09.97,0:08:12.53,EN,,0,0,0,,the first rule that you saw is this something a constant? Dialogue: 0,0:08:16.50,0:08:17.50,EN,,0,0,0,,And what I'm asking is, Dialogue: 0,0:08:17.50,0:08:22.22,EN,,0,0,0,,is the expression a constant with respect to the variable given? Dialogue: 0,0:08:24.90,0:08:27.08,EN,,0,0,0,,If so, the result is 0, Dialogue: 0,0:08:27.50,0:08:30.10,EN,,0,0,0,,because the derivative represents the rate of change of something. Dialogue: 0,0:08:31.76,0:08:32.65,EN,,0,0,0,,If, however, Dialogue: 0,0:08:32.89,0:08:40.69,EN,,0,0,0,,the expression that I'm taking the derivative of is the variable I'm varying, Dialogue: 0,0:08:41.72,0:08:50.42,EN,,0,0,0,,then this is the same variable, the expression var, Dialogue: 0,0:08:51.14,0:08:54.52,EN,,0,0,0,,then the rate of change of the expression with respect to the variable is 1. Dialogue: 0,0:08:55.50,0:08:56.54,EN,,0,0,0,,It's the same 1. Dialogue: 0,0:08:58.90,0:09:00.77,EN,,0,0,0,,Well now there are a couple of other possibilities. Dialogue: 0,0:09:01.33,0:09:03.14,EN,,0,0,0,,It could, for example, be a sum. Dialogue: 0,0:09:03.86,0:09:05.88,EN,,0,0,0,,Well, I don't know how I'm going to express sums yet. Dialogue: 0,0:09:06.09,0:09:08.25,EN,,0,0,0,,Actually I do. But I haven't told you yet. Dialogue: 0,0:09:10.34,0:09:11.78,EN,,0,0,0,,But is it a sum? Dialogue: 0,0:09:12.48,0:09:14.48,EN,,0,0,0,,I'm imagining that there's some way of telling. Dialogue: 0,0:09:15.30,0:09:19.44,EN,,0,0,0,,I'm doing a dispatch on the type of the expression here, Dialogue: 0,0:09:20.77,0:09:23.57,EN,,0,0,0,,absolutely essential in building languages. Dialogue: 0,0:09:24.72,0:09:26.37,EN,,0,0,0,,Cause languages are made out of different expressions. Dialogue: 0,0:09:26.48,0:09:27.54,EN,,0,0,0,,And soon we're going to see that Dialogue: 0,0:09:27.84,0:09:31.02,EN,,0,0,0,,in our more powerful methods of building languages on languages. Dialogue: 0,0:09:32.53,0:09:34.02,EN,,0,0,0,,Is an expression a sum? Dialogue: 0,0:09:35.45,0:09:38.82,EN,,0,0,0,,If it's a sum, well, we know the rule for derivative of the sum Dialogue: 0,0:09:38.82,0:09:41.33,EN,,0,0,0,,is the sum of the derivatives of the parts. Dialogue: 0,0:09:42.13,0:09:44.32,EN,,0,0,0,,One of them is called the addend and the other is the augend. Dialogue: 0,0:09:44.32,0:09:46.80,EN,,0,0,0,,But I don't have enough space on the blackboard to such long names. Dialogue: 0,0:09:46.80,0:09:48.40,EN,,0,0,0,,So I'll call them A1 and A2. Dialogue: 0,0:09:49.04,0:09:50.37,EN,,0,0,0,,I want to make a sum. Dialogue: 0,0:09:53.53,0:09:55.68,EN,,0,0,0,,Do you remember which is the sub for head or the menu end? Dialogue: 0,0:09:57.14,0:10:01.09,EN,,0,0,0,,Or was it the dividend and the divisor or something like that? Dialogue: 0,0:10:01.65,0:10:08.48,EN,,0,0,0,,Make sum of the derivative of the A1, I'll call it. Dialogue: 0,0:10:08.48,0:10:13.29,EN,,0,0,0,,It's the addend of the expression with respect to the variable, Dialogue: 0,0:10:14.84,0:10:22.76,EN,,0,0,0,,and the derivative of the A2 of the expression, Dialogue: 0,0:10:24.12,0:10:28.25,EN,,0,0,0,,those the two arguments, the addition. Respect to the variable. Dialogue: 0,0:10:32.36,0:10:34.93,EN,,0,0,0,,And another rule that we know is product rule, Dialogue: 0,0:10:35.20,0:10:37.44,EN,,0,0,0,,which is, if the expression is a product. Dialogue: 0,0:10:43.21,0:10:46.10,EN,,0,0,0,,By the way, it's a good idea when you're defining things, Dialogue: 0,0:10:46.96,0:10:48.32,EN,,0,0,0,,when you're defining predicates, Dialogue: 0,0:10:48.85,0:10:50.96,EN,,0,0,0,,to give them a name that ends in a question mark. Dialogue: 0,0:10:51.08,0:10:52.89,EN,,0,0,0,,This question mark doesn't mean anything. Dialogue: 0,0:10:53.10,0:10:54.50,EN,,0,0,0,,It's for us as an agreement. Dialogue: 0,0:10:54.61,0:10:58.94,EN,,0,0,0,,It's a conventional interface between humans so you can read my programs more easily. Dialogue: 0,0:11:00.05,0:11:01.96,EN,,0,0,0,,So I want you to, when you write programs, Dialogue: 0,0:11:01.96,0:11:03.73,EN,,0,0,0,,if you define a predicate procedure, Dialogue: 0,0:11:04.01,0:11:05.77,EN,,0,0,0,,that's something that returns true of false, Dialogue: 0,0:11:05.94,0:11:07.84,EN,,0,0,0,,it should have a name which ends in question mark. Dialogue: 0,0:11:08.02,0:11:10.34,EN,,0,0,0,,The lisp doesn't care. I care. Dialogue: 0,0:11:11.62,0:11:13.14,EN,,0,0,0,,I want to make a sum. Dialogue: 0,0:11:13.14,0:11:17.49,EN,,0,0,0,,Because the product, the derivative of a product is the sum Dialogue: 0,0:11:17.94,0:11:19.64,EN,,0,0,0,,of the first times the derivative of the second plus Dialogue: 0,0:11:19.66,0:11:20.70,EN,,0,0,0,,the second times the derivative of the first. Dialogue: 0,0:11:23.54,0:11:27.06,EN,,0,0,0,,Make a sum of two things, Dialogue: 0,0:11:29.64,0:11:38.33,EN,,0,0,0,,a product of, well, I'm going to say the M1 of the expression, Dialogue: 0,0:11:39.85,0:11:48.97,EN,,0,0,0,,and the derivative of the M2 of the expression with respect to the variable, Dialogue: 0,0:11:51.90,0:12:06.28,EN,,0,0,0,,and the product of the derivative of M1, Dialogue: 0,0:12:07.10,0:12:11.92,EN,,0,0,0,,the multiplier of the expression, with respect to the variable. Dialogue: 0,0:12:13.32,0:12:18.05,EN,,0,0,0,,And the product of that and the multiplicand, M2, of the expression. Dialogue: 0,0:12:20.64,0:12:24.89,EN,,0,0,0,,Make that product. Make the sum. Close that case. Dialogue: 0,0:12:24.96,0:12:28.02,EN,,0,0,0,,And, of course, I could add as many cases as I like here Dialogue: 0,0:12:28.32,0:12:30.82,EN,,0,0,0,,for a complete set of rules you might find in a calculus book. Dialogue: 0,0:12:34.80,0:12:39.45,EN,,0,0,0,,So this is what it takes to encapsulate those rules. Dialogue: 0,0:12:41.53,0:12:43.90,EN,,0,0,0,,And you see, you have to realize there's a lot of wishful thinking here. Dialogue: 0,0:12:44.54,0:12:47.56,EN,,0,0,0,,I haven't told you anything about how I'm going to make these representations. Dialogue: 0,0:12:48.46,0:12:51.92,EN,,0,0,0,,Now, once I've decided that this is my set of rules, Dialogue: 0,0:12:52.52,0:12:55.20,EN,,0,0,0,,I think it's time to play with the representation. Dialogue: 0,0:12:55.66,0:12:56.69,EN,,0,0,0,,Let's attack that. Dialogue: 0,0:12:57.96,0:13:00.00,EN,,0,0,0,,Well, first of all, I'm going to play a pun. Dialogue: 0,0:13:00.90,0:13:02.12,EN,,0,0,0,,It's an important pun. Dialogue: 0,0:13:02.74,0:13:06.56,EN,,0,0,0,,It's a key to a sort of powerful idea. Dialogue: 0,0:13:09.62,0:13:14.41,EN,,0,0,0,,If I want to represent sums, and products, and differences, and quotients, and things like that, Dialogue: 0,0:13:15.22,0:13:18.62,EN,,0,0,0,,why not use the same language as I'm writing my program in? Dialogue: 0,0:13:20.50,0:13:23.64,EN,,0,0,0,,I write my program it algebraic expressions that look like Dialogue: 0,0:13:23.98,0:13:30.45,EN,,0,0,0,,the sum of the product on a and the product of x and x, Dialogue: 0,0:13:32.60,0:13:33.80,EN,,0,0,0,,and things like that. Dialogue: 0,0:13:34.28,0:13:38.50,EN,,0,0,0,,And the product of b and x and c, whatever, Dialogue: 0,0:13:38.50,0:13:39.97,EN,,0,0,0,,make that a sum of the product. Dialogue: 0,0:13:40.77,0:13:44.09,EN,,0,0,0,,Right now I don't want to have procedures with unknown numbers of arguments, Dialogue: 0,0:13:44.93,0:13:48.46,EN,,0,0,0,,a product of b and x and c. Dialogue: 0,0:13:51.42,0:13:52.44,EN,,0,0,0,,This is list structure. Dialogue: 0,0:13:54.12,0:13:55.74,EN,,0,0,0,,And the reason why this is nice, Dialogue: 0,0:13:55.90,0:13:58.33,EN,,0,0,0,,is because any one of these objects has a property. Dialogue: 0,0:13:58.92,0:14:01.53,EN,,0,0,0,,I know where, know where the car is. Dialogue: 0,0:14:01.96,0:14:03.21,EN,,0,0,0,,The car is the operator. Dialogue: 0,0:14:03.92,0:14:06.38,EN,,0,0,0,,And the operands are the successive cdrs Dialogue: 0,0:14:07.22,0:14:10.36,EN,,0,0,0,,the successive cars of the cdrs of the list that this is. Dialogue: 0,0:14:12.48,0:14:13.88,EN,,0,0,0,,It makes it very convenient. Dialogue: 0,0:14:14.01,0:14:16.40,EN,,0,0,0,,Ir have to parse it. It's been done for me. Dialogue: 0,0:14:17.42,0:14:20.01,EN,,0,0,0,,I'm using the embedding in Lisp to advantage. Dialogue: 0,0:14:22.66,0:14:23.77,EN,,0,0,0,,So, for example, Dialogue: 0,0:14:25.08,0:14:33.97,EN,,0,0,0,,Let's start using list structure to write down the representation that I'm implicitly assuming here. Dialogue: 0,0:14:35.25,0:14:38.34,EN,,0,0,0,,Well I have to define various things that are implied in this representation. Dialogue: 0,0:14:38.54,0:14:40.90,EN,,0,0,0,,Like I have to find out how to do a constant, Dialogue: 0,0:14:41.21,0:14:42.30,EN,,0,0,0,,how you do same variable. Dialogue: 0,0:14:42.40,0:14:45.04,EN,,0,0,0,,Let's do those first. That's pretty easy enough. Dialogue: 0,0:14:45.78,0:14:47.70,EN,,0,0,0,,Now I'm going to be introducing lots of primitives here, Dialogue: 0,0:14:48.60,0:14:50.50,EN,,0,0,0,,because these are the primitives that come with list structure. Dialogue: 0,0:14:51.98,0:14:53.46,EN,,0,0,0,,OK, you define a constant. Dialogue: 0,0:15:02.25,0:15:04.29,EN,,0,0,0,,And what I mean by a constant, Dialogue: 0,0:15:04.29,0:15:07.73,EN,,0,0,0,,an expression is constant with respect to a variable. Dialogue: 0,0:15:09.05,0:15:11.60,EN,,0,0,0,,is that the expression is something simple. Dialogue: 0,0:15:11.60,0:15:14.46,EN,,0,0,0,,I can't take it into pieces, and yet it isn't that variable. Dialogue: 0,0:15:16.58,0:15:18.78,EN,,0,0,0,,I can't break it up, and yet it isn't that variable. Dialogue: 0,0:15:18.90,0:15:25.12,EN,,0,0,0,,That does not mean that there may be other expressions that are more complicated that are constants. Dialogue: 0,0:15:25.20,0:15:28.92,EN,,0,0,0,,It's just that I'm going to look at the primitive constants in this way. Dialogue: 0,0:15:29.74,0:15:33.41,EN,,0,0,0,,So what this is, is it says that's it's the and. Dialogue: 0,0:15:34.02,0:15:37.82,EN,,0,0,0,,I can combine predicate expressions which return true or false with and. Dialogue: 0,0:15:38.62,0:15:46.82,EN,,0,0,0,,Something atomic, The expression is atomic, meaning it cannot be broken into parts. Dialogue: 0,0:15:46.82,0:15:48.53,EN,,0,0,0,,It doesn't have a car and a cdr. Dialogue: 0,0:15:49.45,0:15:50.21,EN,,0,0,0,,It's not a list. Dialogue: 0,0:15:50.76,0:15:52.94,EN,,0,0,0,,And it's a special test built into the system. Dialogue: 0,0:15:53.97,0:16:04.66,EN,,0,0,0,,And it's not identically equal to that variable. Dialogue: 0,0:16:06.82,0:16:13.36,EN,,0,0,0,,I'm representing my variables by things that are symbols which cannot be broken into pieces, Dialogue: 0,0:16:13.90,0:16:17.22,EN,,0,0,0,,things like x, and y, things like this. Dialogue: 0,0:16:19.74,0:16:22.37,EN,,0,0,0,,Whereas, of course, something like this can be broken up into pieces. Dialogue: 0,0:16:24.74,0:16:46.40,EN,,0,0,0,,And the same variable of an expression with respect to a variable is, Dialogue: 0,0:16:46.40,0:16:48.40,EN,,0,0,0,,in fact, an atomic expression. Dialogue: 0,0:16:48.77,0:16:59.61,EN,,0,0,0,,I want to have an atomic expression, which is identical. Dialogue: 0,0:17:07.90,0:17:11.68,EN,,0,0,0,,I don't want to look inside this, this stuff anymore. Dialogue: 0,0:17:12.52,0:17:15.56,EN,,0,0,0,,These are primitive maybe. Dialogue: 0,0:17:15.77,0:17:17.08,EN,,0,0,0,,But it doesn't matter. Dialogue: 0,0:17:17.78,0:17:21.74,EN,,0,0,0,,I'm defining... I'm using things that are given to me with a language. Dialogue: 0,0:17:22.42,0:17:24.04,EN,,0,0,0,,I'm not terribly interest in them. Dialogue: 0,0:17:24.42,0:17:26.04,EN,,0,0,0,,Now how do we deal with sums? Dialogue: 0,0:17:26.60,0:17:28.80,EN,,0,0,0,,Ah, something very interesting will happen. Dialogue: 0,0:17:28.98,0:17:33.12,EN,,0,0,0,,A sum is something which is not atomic and begins with the plus symbol. Dialogue: 0,0:17:35.16,0:17:36.17,EN,,0,0,0,,That's what it means. Dialogue: 0,0:17:36.65,0:17:39.77,EN,,0,0,0,,So here, I will define. Dialogue: 0,0:17:45.46,0:17:57.77,EN,,0,0,0,,An expression is a sum if and it's not atomic Dialogue: 0,0:18:04.57,0:18:15.45,EN,,0,0,0,,and it's head, it's beginning, its car of the expression is the symbol plus. Dialogue: 0,0:18:19.74,0:18:24.04,EN,,0,0,0,,Now you're about to see something you haven't seen before, this quotation. Dialogue: 0,0:18:25.89,0:18:28.22,EN,,0,0,0,,Why do I have that quotation there? Dialogue: 0,0:18:29.48,0:18:30.52,EN,,0,0,0,,PROFESSOR: Say your name, Dialogue: 0,0:18:30.68,0:18:31.41,EN,,0,0,0,,AUDIENCE: Susanna. Dialogue: 0,0:18:31.41,0:18:32.01,EN,,0,0,0,,PROFESSOR: Louder. Dialogue: 0,0:18:32.01,0:18:32.72,EN,,0,0,0,,AUDIENCE: Susanna Dialogue: 0,0:18:33.25,0:18:34.21,EN,,0,0,0,,PROFESSOR: Say your name. Dialogue: 0,0:18:34.21,0:18:34.85,EN,,0,0,0,,AUDIENCE: Your name. Dialogue: 0,0:18:34.92,0:18:35.68,EN,,0,0,0,,PROFESSOR: Louder. Dialogue: 0,0:18:35.77,0:18:36.61,EN,,0,0,0,,AUDIENCE: Your name. Dialogue: 0,0:18:36.82,0:18:37.50,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:18:38.28,0:18:44.56,EN,,0,0,0,,What I'm showing you here is that the words of English are ambiguous. Dialogue: 0,0:18:45.50,0:18:50.76,EN,,0,0,0,,I was saying, say your name. Dialogue: 0,0:18:51.97,0:18:57.21,EN,,0,0,0,,I was also possibly saying say, your name. Dialogue: 0,0:19:00.72,0:19:02.98,EN,,0,0,0,,But that cannot be distinguished in speech. Dialogue: 0,0:19:03.89,0:19:08.01,EN,,0,0,0,,However, we do have a notation in writing, Dialogue: 0,0:19:08.18,0:19:12.46,EN,,0,0,0,,which is quotation for distinguishing these two possible meanings. Dialogue: 0,0:19:14.00,0:19:15.64,EN,,0,0,0,,In particular, over here, Dialogue: 0,0:19:16.49,0:19:20.84,EN,,0,0,0,,in Lisp we have a notation for distinguishing these meanings. Dialogue: 0,0:19:21.34,0:19:24.45,EN,,0,0,0,,If I were to just write a plus here, a plus symbol, Dialogue: 0,0:19:24.64,0:19:28.52,EN,,0,0,0,,I would be asking, is the first element of the expression, Dialogue: 0,0:19:29.06,0:19:33.61,EN,,0,0,0,,is the operator position of the expression, the addition operator? Dialogue: 0,0:19:34.65,0:19:35.54,EN,,0,0,0,,I don't know. Dialogue: 0,0:19:36.22,0:19:38.16,EN,,0,0,0,,I would have to have written the addition operator there, Dialogue: 0,0:19:39.37,0:19:40.44,EN,,0,0,0,,which I can't write. Dialogue: 0,0:19:41.34,0:19:45.88,EN,,0,0,0,,However, this way I'm asking, is this the symbolic object plus, Dialogue: 0,0:19:45.98,0:19:48.14,EN,,0,0,0,,which normally stands for the addition operator? Dialogue: 0,0:19:49.57,0:19:51.92,EN,,0,0,0,,That's what I want. That's the question I want to ask. Dialogue: 0,0:19:52.92,0:19:54.45,EN,,0,0,0,,Now before I go any further, Dialogue: 0,0:19:54.45,0:19:57.81,EN,,0,0,0,,I want to point out the quotation is a very complex concept, Dialogue: 0,0:19:58.85,0:20:01.84,EN,,0,0,0,,and adding it to a language causes a great deal of troubles. Dialogue: 0,0:20:03.57,0:20:05.04,EN,,0,0,0,,Consider the next slide. Dialogue: 0,0:20:06.38,0:20:09.49,EN,,0,0,0,,Here's a deduction which we should all agree with. Dialogue: 0,0:20:11.62,0:20:17.04,EN,,0,0,0,,We have, Alyssa is smart and Alyssa is George's mother. Dialogue: 0,0:20:17.40,0:20:20.60,EN,,0,0,0,,This is an equality, is. Dialogue: 0,0:20:22.13,0:20:26.30,EN,,0,0,0,,From those two, we can deduce that George's mother is smart. Dialogue: 0,0:20:27.32,0:20:33.16,EN,,0,0,0,,Because we can always substitute equals for equals in expressions. Dialogue: 0,0:20:34.09,0:20:35.16,EN,,0,0,0,,Or can we? Dialogue: 0,0:20:36.52,0:20:40.37,EN,,0,0,0,,Here's a case where we have "Chicago" has seven letters. Dialogue: 0,0:20:41.12,0:20:44.86,EN,,0,0,0,,The quotation means that I'm discussing the word Chicago, Dialogue: 0,0:20:44.86,0:20:46.86,EN,,0,0,0,,not what the word represents. Dialogue: 0,0:20:49.82,0:20:52.77,EN,,0,0,0,,Here I have that Chicago is the biggest city in Illinois. Dialogue: 0,0:20:54.61,0:20:55.80,EN,,0,0,0,,As a consequence of this, Dialogue: 0,0:20:55.80,0:20:59.09,EN,,0,0,0,,I would like to deduce that the biggest city in Illinois has seven letters. Dialogue: 0,0:20:59.32,0:21:01.06,EN,,0,0,0,,But that's manifestly false. Dialogue: 0,0:21:05.16,0:21:07.17,EN,,0,0,0,,Wow, it works. Dialogue: 0,0:21:09.29,0:21:12.24,EN,,0,0,0,,OK, so once we have things like that, Dialogue: 0,0:21:12.48,0:21:14.49,EN,,0,0,0,,our language gets much more complicated. Dialogue: 0,0:21:14.49,0:21:18.34,EN,,0,0,0,,Because it's no longer true that things we tend to like to do with languages, Dialogue: 0,0:21:18.34,0:21:20.76,EN,,0,0,0,,like substituting equals for equals and getting right answers, Dialogue: 0,0:21:21.29,0:21:23.50,EN,,0,0,0,,are going to work without being very careful. Dialogue: 0,0:21:24.49,0:21:27.34,EN,,0,0,0,,We can't substitute into what's called referentially opaque contexts, Dialogue: 0,0:21:27.89,0:21:32.64,EN,,0,0,0,,of which a quotation is the prototypical type of referentially opaque context. Dialogue: 0,0:21:33.17,0:21:35.28,EN,,0,0,0,,If you know what that means, you can consult a philosopher. Dialogue: 0,0:21:35.42,0:21:37.02,EN,,0,0,0,,Presumably there is one in the room. Dialogue: 0,0:21:37.53,0:21:41.32,EN,,0,0,0,,In any case, let's continue now, Dialogue: 0,0:21:41.32,0:21:44.98,EN,,0,0,0,,now that we at least have an operational understanding of a 2000-year-old issue Dialogue: 0,0:21:45.26,0:21:48.13,EN,,0,0,0,,that has to do with name, and mention, and all sorts of things like that. Dialogue: 0,0:21:52.32,0:22:01.60,EN,,0,0,0,,I have to define what I mean, how to make a sum of two things, an a1 and a2. Dialogue: 0,0:22:02.12,0:22:03.62,EN,,0,0,0,,And I'm going to do this very simply. Dialogue: 0,0:22:03.62,0:22:11.96,EN,,0,0,0,,It's a list of the symbol plus, and a1, and a2. Dialogue: 0,0:22:13.86,0:22:17.37,EN,,0,0,0,,And I can determine the first element. Dialogue: 0,0:22:21.84,0:22:25.32,EN,,0,0,0,,Define a1 to be cadr. Dialogue: 0,0:22:33.88,0:22:35.90,EN,,0,0,0,,I've just introduced another primitive. Dialogue: 0,0:22:36.17,0:22:39.10,EN,,0,0,0,,This is the car of the cdr of something. Dialogue: 0,0:22:39.80,0:22:44.53,EN,,0,0,0,,You might want to know why car and cdr are names of these primitives, Dialogue: 0,0:22:44.66,0:22:48.42,EN,,0,0,0,,and why they've survived, even though they're much better ideas like left and right. Dialogue: 0,0:22:48.76,0:22:50.44,EN,,0,0,0,,We could have called them things like that. Dialogue: 0,0:22:51.28,0:22:56.25,EN,,0,0,0,,Well, first of all, the names come from the fact that in the great past, when Lisp was invented, Dialogue: 0,0:22:56.36,0:23:00.80,EN,,0,0,0,,I suppose in '58 or something, it was on a 704 or something like that, Dialogue: 0,0:23:00.80,0:23:05.41,EN,,0,0,0,,which had a machine. It was a machine that had an address register and a decrement register. Dialogue: 0,0:23:05.41,0:23:08.17,EN,,0,0,0,,And these were the contents of the address register and the decrement register. Dialogue: 0,0:23:08.17,0:23:09.37,EN,,0,0,0,,So it's an historical accident. Dialogue: 0,0:23:09.64,0:23:11.28,EN,,0,0,0,,Now why have these names survived? Dialogue: 0,0:23:11.74,0:23:14.76,EN,,0,0,0,,It's because Lisp programmers like to talk to each other over the phone. Dialogue: 0,0:23:15.68,0:23:19.60,EN,,0,0,0,,And if you want to have a long sequence of cars and cdrs you might say, cdaddedr, Dialogue: 0,0:23:21.01,0:23:22.32,EN,,0,0,0,,which can be understood. Dialogue: 0,0:23:22.32,0:23:27.02,EN,,0,0,0,,But left of right or right of left is not so clear if you get good at it. Dialogue: 0,0:23:27.60,0:23:30.02,EN,,0,0,0,,So that's why we have these words. Dialogue: 0,0:23:30.54,0:23:34.14,EN,,0,0,0,,All of them up to four deep are defined typically in a Lisp system. Dialogue: 0,0:23:38.66,0:23:47.05,EN,,0,0,0,,A2 to be-- and, of course, you can see that if I looked at one of these expressions Dialogue: 0,0:23:47.36,0:23:52.14,EN,,0,0,0,,like the sum of 3 and 5, Dialogue: 0,0:23:52.58,0:24:10.45,EN,,0,0,0,,what that is is a list containing the symbol plus, and a number 3, and a number 5. Dialogue: 0,0:24:11.72,0:24:15.18,EN,,0,0,0,,Then the car is the symbol plus. Dialogue: 0,0:24:16.13,0:24:18.21,EN,,0,0,0,,The car of the cdr. Dialogue: 0,0:24:18.21,0:24:20.21,EN,,0,0,0,,Well I take the cdr and then I take the car. Dialogue: 0,0:24:20.21,0:24:22.21,EN,,0,0,0,,And that's how I get to the 3. That's the first argument. Dialogue: 0,0:24:22.52,0:24:25.69,EN,,0,0,0,,And the car of the cdr of the cdr gets me to this one, the 5. Dialogue: 0,0:24:28.69,0:24:33.66,EN,,0,0,0,,And similarly, of course, I can define what's going on with products. Dialogue: 0,0:24:35.22,0:24:36.56,EN,,0,0,0,,Let's do that very quickly. Dialogue: 0,0:24:48.97,0:24:50.64,EN,,0,0,0,,Is the expression a product? Dialogue: 0,0:24:51.05,0:24:54.69,EN,,0,0,0,,Yes if and if it's true, that's it's not atomic Dialogue: 0,0:25:01.41,0:25:14.14,EN,,0,0,0,,and it's EQ quote, the asterisk symbol, which is the operator for multiplication. Dialogue: 0,0:25:15.64,0:25:32.00,EN,,0,0,0,,Make product of an M1 and an M2 to be list, Dialogue: 0,0:25:34.42,0:25:39.30,EN,,0,0,0,,quote, the asterisk operation and M1 and M2. Dialogue: 0,0:25:40.82,0:25:56.81,EN,,0,0,0,,And I define M1 to be cadr and M2 to be caddr. Dialogue: 0,0:26:00.09,0:26:02.38,EN,,0,0,0,,You get to be a good Lisp programmer because you start talking that way. Dialogue: 0,0:26:02.53,0:26:05.53,EN,,0,0,0,,You can cdr thing down lists and cons them up and so on. Dialogue: 0,0:26:06.29,0:26:10.10,EN,,0,0,0,,Now, now that we have essentially a complete program for finding derivatives, Dialogue: 0,0:26:10.10,0:26:11.70,EN,,0,0,0,,you can add more rules if you like. Dialogue: 0,0:26:12.21,0:26:13.93,EN,,0,0,0,,What kind of behavior do we get out of it? Dialogue: 0,0:26:14.64,0:26:16.77,EN,,0,0,0,,I'll have to clear that x. Dialogue: 0,0:26:17.80,0:26:20.82,EN,,0,0,0,,Well, supposing I define foo here Dialogue: 0,0:26:22.16,0:26:30.38,EN,,0,0,0,,to be the sum of the product of ax square and bx plus c. Dialogue: 0,0:26:30.54,0:26:32.08,EN,,0,0,0,,That's the same thing we see here Dialogue: 0,0:26:32.08,0:26:36.36,EN,,0,0,0,,as the algebraic expression written in the more conventional notation over there. Dialogue: 0,0:26:37.84,0:26:41.60,EN,,0,0,0,,Well, the derivative of foo with respect to x, which we can see over here, Dialogue: 0,0:26:43.46,0:26:45.26,EN,,0,0,0,,is this horrible, horrendous mess. Dialogue: 0,0:26:46.16,0:26:49.22,EN,,0,0,0,,I would like it to be 2ax plus b. Dialogue: 0,0:26:50.68,0:26:53.44,EN,,0,0,0,,But it's not. It's equivalent to it. Dialogue: 0,0:26:54.58,0:26:55.22,EN,,0,0,0,,What is it? Dialogue: 0,0:26:55.97,0:26:59.96,EN,,0,0,0,,I have here, what do I have? Dialogue: 0,0:27:00.50,0:27:04.30,EN,,0,0,0,,I have the derivative of the product of x and x. Dialogue: 0,0:27:04.69,0:27:10.53,EN,,0,0,0,,Over here is, of course, the sum of x times 1 and 1 times x. Dialogue: 0,0:27:12.73,0:27:15.66,EN,,0,0,0,,Now, well, it's the first times the derivative of the second plus the second times the derivative of the first. It's right. Dialogue: 0,0:27:17.22,0:27:28.37,EN,,0,0,0,,That's 2x of course. a times 2x is 2ax plus 0X square doesn't count plus B over here plus a bunch of 0's. Dialogue: 0,0:27:28.96,0:27:30.12,EN,,0,0,0,,Well the answer is right. Dialogue: 0,0:27:30.12,0:27:35.14,EN,,0,0,0,,But I give people take off points on an exam for that, sadly enough. Dialogue: 0,0:27:35.56,0:27:37.26,EN,,0,0,0,,Let's worry about that in the next segment. Dialogue: 0,0:27:37.68,0:27:38.61,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:27:42.77,0:27:43.45,EN,,0,0,0,,Yes? Dialogue: 0,0:27:43.89,0:27:46.69,EN,,0,0,0,,AUDIENCE: If you had left the quote when you put the plus, Dialogue: 0,0:27:46.69,0:27:50.82,EN,,0,0,0,,then would that be referring to the procedure plus Dialogue: 0,0:27:50.82,0:27:55.42,EN,,0,0,0,,and could you do a comparison between that procedure and some other procedure if you wanted to? Dialogue: 0,0:27:56.16,0:27:57.08,EN,,0,0,0,,PROFESSOR: Yes. Good question. Dialogue: 0,0:27:57.45,0:28:02.26,EN,,0,0,0,,If I had left this quotation off at this point, Dialogue: 0,0:28:03.88,0:28:07.13,EN,,0,0,0,,Okay? If I had left that quotation off at that point, Dialogue: 0,0:28:07.33,0:28:14.20,EN,,0,0,0,,then I would be referring here to the procedure which is the thing that plus is defined to be. Dialogue: 0,0:28:15.38,0:28:24.88,EN,,0,0,0,,And indeed, I could compare some procedures with each other for identity. Dialogue: 0,0:28:24.88,0:28:27.45,EN,,0,0,0,,Now what that means is not clear right now. Dialogue: 0,0:28:27.85,0:28:29.37,EN,,0,0,0,,I don't like to think about it. Dialogue: 0,0:28:29.89,0:28:32.40,EN,,0,0,0,,Because I don't know exactly what it would need to compare procedures. Dialogue: 0,0:28:32.40,0:28:34.40,EN,,0,0,0,,There are reasons why that may make no sense at all. Dialogue: 0,0:28:35.52,0:28:37.53,EN,,0,0,0,,However, the symbols, we understand. Dialogue: 0,0:28:38.54,0:28:40.56,EN,,0,0,0,,And so that's why I put that quote in. Dialogue: 0,0:28:41.16,0:28:43.70,EN,,0,0,0,,I want to talk about the symbol that's apparent on the page. Dialogue: 0,0:28:46.16,0:28:46.92,EN,,0,0,0,,Any other questions? Dialogue: 0,0:28:48.52,0:28:51.86,EN,,0,0,0,,OK. Thank you. Let's take a break. Dialogue: 0,0:28:55.12,0:29:00.66,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:29:00.68,0:29:04.34,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:29:04.34,0:29:06.68,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:29:12.21,0:29:19.17,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:29:20.09,0:29:24.14,Declare,,0,0,0,,{\an2\fad(500,500)}Symbolic Differentiation: Quotation Dialogue: 0,0:29:29.86,0:29:30.92,EN,,0,0,0,,PROFESSOR: Well, let's see. Dialogue: 0,0:29:31.46,0:29:37.76,EN,,0,0,0,,We've just developed a fairly plausible program for computing the derivatives of algebraic expressions. Dialogue: 0,0:29:38.20,0:29:41.56,EN,,0,0,0,,It's an incomplete program, if you would like to add more rules. Dialogue: 0,0:29:42.13,0:29:47.74,EN,,0,0,0,,And perhaps you might extend it to deal with uses of addition with any number of arguments Dialogue: 0,0:29:47.76,0:29:49.70,EN,,0,0,0,,and multiplication with any of the number of arguments. Dialogue: 0,0:29:49.89,0:29:51.38,EN,,0,0,0,,And that's all rather easy. Dialogue: 0,0:29:52.73,0:29:56.93,EN,,0,0,0,,However, there was a little fly in that ointment. Dialogue: 0,0:29:57.48,0:30:02.37,EN,,0,0,0,,We go back to this slide. Dialogue: 0,0:30:02.94,0:30:08.60,EN,,0,0,0,,We see that the expressions that we get are rather bad. Dialogue: 0,0:30:08.88,0:30:11.01,EN,,0,0,0,,This is a rather bad expression. Dialogue: 0,0:30:11.46,0:30:13.10,EN,,0,0,0,,How do we get such an expression? Dialogue: 0,0:30:13.84,0:30:15.50,EN,,0,0,0,,Why do we have that expression? Dialogue: 0,0:30:16.84,0:30:18.74,EN,,0,0,0,,Let's look at this expression in some detail. Dialogue: 0,0:30:18.92,0:30:20.76,EN,,0,0,0,,Let's find out where all the pieces come from. Dialogue: 0,0:30:21.69,0:30:24.56,EN,,0,0,0,,As we see here, we have a sum-- Dialogue: 0,0:30:24.56,0:30:26.56,EN,,0,0,0,,just what I showed you at the end of the last time-- Dialogue: 0,0:30:27.12,0:30:29.09,EN,,0,0,0,,of X times 1 plus 1 time X. Dialogue: 0,0:30:29.58,0:30:31.38,EN,,0,0,0,,That is a derivative of this product. Dialogue: 0,0:30:32.52,0:30:36.41,EN,,0,0,0,,The product of a times that, where a does not depend upon x, Dialogue: 0,0:30:36.41,0:30:38.41,EN,,0,0,0,,and therefore is constant with respect to x, Dialogue: 0,0:30:39.04,0:30:44.53,EN,,0,0,0,,is this sum, which goes from here all the way through here and through here. Dialogue: 0,0:30:44.80,0:30:48.89,EN,,0,0,0,,Because it is the first thing times the derivative of the second Dialogue: 0,0:30:49.57,0:30:54.45,EN,,0,0,0,,plus the derivative of the first times the second Dialogue: 0,0:30:54.66,0:30:59.06,EN,,0,0,0,,as the program we wrote on the blackboard indicated we should do. Dialogue: 0,0:31:00.65,0:31:05.36,EN,,0,0,0,,And, of course, the product of bx over here Dialogue: 0,0:31:05.49,0:31:09.81,EN,,0,0,0,,manifests itself as B times 1 plus 0 times X Dialogue: 0,0:31:10.81,0:31:16.06,EN,,0,0,0,,because we see that B does not depend upon X. Dialogue: 0,0:31:16.46,0:31:18.56,EN,,0,0,0,,And so the derivative of B is this 0, Dialogue: 0,0:31:18.77,0:31:21.48,EN,,0,0,0,,and the derivative of X with respect itself is the 1. Dialogue: 0,0:31:23.06,0:31:28.64,EN,,0,0,0,,And, of course, the derivative of the sums over here turn into these two sums of the derivatives of the parts. Dialogue: 0,0:31:29.37,0:31:33.50,EN,,0,0,0,,So what we're seeing here is exactly the thing I was trying to tell you about Dialogue: 0,0:31:33.66,0:31:35.89,EN,,0,0,0,,with Fibonacci numbers a while ago, Dialogue: 0,0:31:37.77,0:31:39.49,EN,,0,0,0,,that the form of the process Dialogue: 0,0:31:41.38,0:31:46.44,EN,,0,0,0,,is expanded as low as from the local rules that you see in the procedure, Dialogue: 0,0:31:48.05,0:31:52.57,EN,,0,0,0,,that the procedure represents a set of local rules for the expansion of this process. Dialogue: 0,0:31:53.36,0:32:00.09,EN,,0,0,0,,And here, the process left behind some stuff, which is the answer. Dialogue: 0,0:32:00.25,0:32:06.26,EN,,0,0,0,,And it was constructed by the walk it takes of the tree structure, which is the expression. Dialogue: 0,0:32:08.41,0:32:12.61,EN,,0,0,0,,So every part in the answer we see here derives from some part of the problem. Dialogue: 0,0:32:14.46,0:32:17.78,EN,,0,0,0,,Now, we can look at, for example, the derivative of foo, Dialogue: 0,0:32:17.78,0:32:19.65,EN,,0,0,0,,which is ax square plus bx plus c, Dialogue: 0,0:32:19.84,0:32:23.05,EN,,0,0,0,,with respect to other things, like here, for example, Dialogue: 0,0:32:24.14,0:32:27.48,EN,,0,0,0,,we can see that the derivative of foo with respect to a. Dialogue: 0,0:32:28.10,0:32:31.77,EN,,0,0,0,,And it's very similar. It's, in fact, the identical algebraic expression, Dialogue: 0,0:32:32.45,0:32:35.24,EN,,0,0,0,,except for the fact that theses 0's and 1's are in different places. Dialogue: 0,0:32:36.06,0:32:38.60,EN,,0,0,0,,Because the only degree of freedom we have in this tree walk Dialogue: 0,0:32:38.97,0:32:43.85,EN,,0,0,0,,is what's constant with respect to the variable we're taking the derivative with respect to Dialogue: 0,0:32:44.28,0:32:45.81,EN,,0,0,0,,and what's the same variable. Dialogue: 0,0:32:48.26,0:32:52.09,EN,,0,0,0,,In other words, if we go back to this blackboard and we look, Dialogue: 0,0:32:52.65,0:32:57.49,EN,,0,0,0,,we have no choice what to do when we take the derivative of the sum or a product. Dialogue: 0,0:32:58.08,0:33:04.48,EN,,0,0,0,,The only interesting place here is, is the expression the variable, Dialogue: 0,0:33:04.80,0:33:10.10,EN,,0,0,0,,or is the expression a constant with respect to that variable for very, very small expressions? Dialogue: 0,0:33:10.36,0:33:12.41,EN,,0,0,0,,In which case we get various 1's and 0's, Dialogue: 0,0:33:12.69,0:33:14.49,EN,,0,0,0,,which if we go back to this slide, Dialogue: 0,0:33:15.12,0:33:18.16,EN,,0,0,0,,we can see that the 0's that appear here, for example, Dialogue: 0,0:33:18.37,0:33:22.74,EN,,0,0,0,,this 1 over here in derivative of foo with respect to A, Dialogue: 0,0:33:22.96,0:33:24.86,EN,,0,0,0,,which gets us an X square, Dialogue: 0,0:33:24.96,0:33:32.53,EN,,0,0,0,,because that 1 gets the multiply of X and X into the answer, that 1 is 0. Dialogue: 0,0:33:32.64,0:33:34.89,EN,,0,0,0,,Over here, we're not taking the derivative of foo with respect to c. Dialogue: 0,0:33:36.78,0:33:39.30,EN,,0,0,0,,But the shapes of these expressions are the same. Dialogue: 0,0:33:40.54,0:33:43.96,EN,,0,0,0,,See all those shapes. They're the same. Dialogue: 0,0:33:50.37,0:33:52.28,EN,,0,0,0,,Well is there anything wrong with our rules? Dialogue: 0,0:33:53.58,0:33:55.02,EN,,0,0,0,,No. They're the right rules. Dialogue: 0,0:33:56.12,0:33:57.77,EN,,0,0,0,,We've been through this one before. Dialogue: 0,0:33:58.06,0:34:03.53,EN,,0,0,0,,One of the things you're going to begin to discover is that there aren't too many good ideas. Dialogue: 0,0:34:06.32,0:34:09.74,EN,,0,0,0,,When we were looking at rational numbers yesterday, Dialogue: 0,0:34:12.12,0:34:14.48,EN,,0,0,0,,the problem was that we got 6/8 rather then 3/4. Dialogue: 0,0:34:14.97,0:34:16.49,EN,,0,0,0,,The answer was unsimplified. Dialogue: 0,0:34:18.09,0:34:20.90,EN,,0,0,0,,The problem, of course, is very similar. Dialogue: 0,0:34:21.18,0:34:25.41,EN,,0,0,0,,There are things I'd like to be identical by simplification that don't become identical. Dialogue: 0,0:34:27.57,0:34:31.89,EN,,0,0,0,,And yet the rules for doing addition a multiplication of rational numbers were correct. Dialogue: 0,0:34:33.97,0:34:37.41,EN,,0,0,0,,So the way we might solve this problem is do the thing we did last time, which always works. Dialogue: 0,0:34:37.78,0:34:39.89,EN,,0,0,0,,If something worked last time it ought to work again. Dialogue: 0,0:34:40.53,0:34:42.05,EN,,0,0,0,,It's changed representation. Dialogue: 0,0:34:43.13,0:34:46.44,EN,,0,0,0,,Perhaps in the representation we could put in a simplification step Dialogue: 0,0:34:47.88,0:34:49.78,EN,,0,0,0,,that produces a simplified representation. Dialogue: 0,0:34:50.17,0:34:51.73,EN,,0,0,0,,This may not always work, of course. Dialogue: 0,0:34:52.49,0:34:54.14,EN,,0,0,0,,I'm not trying to say that it always works. Dialogue: 0,0:34:55.12,0:35:00.44,EN,,0,0,0,,But it's one of the pieces of artillery we have in our war against complexity. Dialogue: 0,0:35:01.46,0:35:03.85,EN,,0,0,0,,You see, because we solved our problem very carefully. Dialogue: 0,0:35:04.30,0:35:07.20,EN,,0,0,0,,What we've done, is we've divided the world in several parts. Dialogue: 0,0:35:07.57,0:35:08.73,EN,,0,0,0,,There are derivatives rules Dialogue: 0,0:35:11.32,0:35:15.80,EN,,0,0,0,,and general rules for algebra of some sort at this level of detail. Dialogue: 0,0:35:16.38,0:35:21.22,EN,,0,0,0,,and i have an abstraction barrier. Dialogue: 0,0:35:22.48,0:35:33.49,EN,,0,0,0,,And i have the representation of the algebraic expressions, list structure. Dialogue: 0,0:35:37.33,0:35:42.56,EN,,0,0,0,,And in this barrier, I have the interface procedures. Dialogue: 0,0:35:43.25,0:35:49.82,EN,,0,0,0,,I have constant, and things like same-var. Dialogue: 0,0:35:54.60,0:35:58.72,EN,,0,0,0,,I have things like sum, make-sum. Dialogue: 0,0:36:02.22,0:36:05.57,EN,,0,0,0,,I have A1, A2. Dialogue: 0,0:36:06.60,0:36:08.58,EN,,0,0,0,,I have products and things like that, Dialogue: 0,0:36:08.74,0:36:11.90,EN,,0,0,0,,all the other things I might need for various kinds of algebraic expressions. Dialogue: 0,0:36:12.94,0:36:19.14,EN,,0,0,0,,Making this barrier allows me to arbitrarily change the representation Dialogue: 0,0:36:20.14,0:36:23.20,EN,,0,0,0,,without changing the rules that are written in terms of that representation. Dialogue: 0,0:36:25.04,0:36:29.08,EN,,0,0,0,,So if I can make the problem go away by changing representation, Dialogue: 0,0:36:30.38,0:36:34.52,EN,,0,0,0,,the composition of the problem into these two parts has helped me a great deal. Dialogue: 0,0:36:35.65,0:36:37.54,EN,,0,0,0,,So let's take a very simple case of this. Dialogue: 0,0:36:38.82,0:36:40.08,EN,,0,0,0,,What was one of the problems? Dialogue: 0,0:36:40.26,0:36:43.61,EN,,0,0,0,,Let's go back to this transparency again. Dialogue: 0,0:36:44.50,0:36:47.34,EN,,0,0,0,,And we see here, oh yes, there's horrible things Dialogue: 0,0:36:47.62,0:36:51.86,EN,,0,0,0,,like here is the sum of an expression and 0. Dialogue: 0,0:36:53.14,0:36:56.66,EN,,0,0,0,,Well that's no reason to think of it as anything other than the expression itself. Dialogue: 0,0:36:57.21,0:37:01.90,EN,,0,0,0,,Why should the summation operation have made up this edition? Dialogue: 0,0:37:03.38,0:37:04.57,EN,,0,0,0,,It can be smarter than that. Dialogue: 0,0:37:05.56,0:37:10.08,EN,,0,0,0,,Or here, for example, is a multiplication of something by 1. Dialogue: 0,0:37:11.16,0:37:12.29,EN,,0,0,0,,It's another thing like that. Dialogue: 0,0:37:12.86,0:37:15.68,EN,,0,0,0,,Or here is a product of something with 0, which is certainly 0. Dialogue: 0,0:37:17.86,0:37:19.52,EN,,0,0,0,,So we won't have to make this construction. Dialogue: 0,0:37:21.44,0:37:22.62,EN,,0,0,0,,So why don't we just do that? Dialogue: 0,0:37:23.66,0:37:27.96,EN,,0,0,0,,We need to change the way the representation works, almost here. Dialogue: 0,0:37:37.40,0:37:41.84,EN,,0,0,0,,Make-sum to be. Dialogue: 0,0:37:42.05,0:37:43.76,EN,,0,0,0,,Well, now it's not something so simple. Dialogue: 0,0:37:44.00,0:37:50.40,EN,,0,0,0,,I'm not going to make a list containing the symbol plus and things unless I need to. Dialogue: 0,0:37:51.72,0:37:53.05,EN,,0,0,0,,Well, what are the possibilities? Dialogue: 0,0:37:54.56,0:37:58.53,EN,,0,0,0,,If...I have some sort of cases here. Dialogue: 0,0:37:59.38,0:38:08.20,EN,,0,0,0,,If I have numbers, if a1 is a number-- Dialogue: 0,0:38:09.05,0:38:10.93,EN,,0,0,0,,and here's another primitive I've just introduced, Dialogue: 0,0:38:10.93,0:38:13.18,EN,,0,0,0,,it's possible to tell whether something's number-- Dialogue: 0,0:38:15.38,0:38:23.82,EN,,0,0,0,,and if number A2, meaning they're not symbolic expressions, Dialogue: 0,0:38:24.45,0:38:26.20,EN,,0,0,0,,then why not do the addition now? Dialogue: 0,0:38:26.45,0:38:29.92,EN,,0,0,0,,The result is just a plus of A1 and A2. Dialogue: 0,0:38:32.32,0:38:33.98,EN,,0,0,0,,I'm not asking if these represent numbers. Dialogue: 0,0:38:33.98,0:38:35.98,EN,,0,0,0,,Of course all of these symbols represent numbers. Dialogue: 0,0:38:37.33,0:38:41.22,EN,,0,0,0,,I'm talking about whether the one I've got is the number 3 right now. Dialogue: 0,0:38:43.40,0:38:44.40,EN,,0,0,0,,And, for example, Dialogue: 0,0:38:48.77,0:38:59.61,EN,,0,0,0,,supposing A1 is a number, and it's equal to 0, Dialogue: 0,0:39:04.20,0:39:06.38,EN,,0,0,0,,well then the answer is just A2. Dialogue: 0,0:39:06.93,0:39:08.68,EN,,0,0,0,,There is no reason to make anything up. Dialogue: 0,0:39:10.98,0:39:23.41,EN,,0,0,0,,And if A2 is a number, and equal A2 0, Dialogue: 0,0:39:27.16,0:39:28.90,EN,,0,0,0,,then the result is A1. Dialogue: 0,0:39:30.04,0:39:33.65,EN,,0,0,0,,And only if I can't figure out something better to do with this situation, Dialogue: 0,0:39:34.13,0:39:35.61,EN,,0,0,0,,well, I can construct a list. Dialogue: 0,0:39:37.86,0:39:42.86,EN,,0,0,0,,Otherwise I want the representation to be the list Dialogue: 0,0:39:44.13,0:39:52.33,EN,,0,0,0,,containing the quoted symbol plus, and A1, and A2. Dialogue: 0,0:39:58.66,0:40:01.65,EN,,0,0,0,,And, of course, a very similar thing can be done for products. Dialogue: 0,0:40:03.01,0:40:05.04,EN,,0,0,0,,And I think I'll avoid boring you with them. Dialogue: 0,0:40:05.44,0:40:07.24,EN,,0,0,0,,I was going to write it on the blackboard. Dialogue: 0,0:40:07.65,0:40:09.80,EN,,0,0,0,,I don't think it's necessary. You know what to do. Dialogue: 0,0:40:10.76,0:40:11.61,EN,,0,0,0,,It's very simple. Dialogue: 0,0:40:12.86,0:40:19.89,EN,,0,0,0,,But now, let's just see the kind of results we get out of changing our program in this way. Dialogue: 0,0:40:21.68,0:40:27.88,EN,,0,0,0,,Well, here's the derivatives after having just changed the constructors for expressions. Dialogue: 0,0:40:28.98,0:40:32.21,EN,,0,0,0,,The same foo, aX square plus bX plus c, Dialogue: 0,0:40:33.28,0:40:40.70,EN,,0,0,0,,and what I get is nothing more than the derivative of that is 2aX plus B. Dialogue: 0,0:40:40.70,0:40:42.10,EN,,0,0,0,,Well, it's not completely simplified. Dialogue: 0,0:40:42.60,0:40:44.53,EN,,0,0,0,,I would like to collect common terms and sums. Dialogue: 0,0:40:45.06,0:40:46.08,EN,,0,0,0,,Well, that's more work. Dialogue: 0,0:40:47.12,0:40:51.86,EN,,0,0,0,,And, of course, programs to do this sort of thing are huge and complicated. Dialogue: 0,0:40:52.28,0:40:55.28,EN,,0,0,0,,Algebraic simplification, it's a very complicated mess. Dialogue: 0,0:40:56.37,0:41:00.13,EN,,0,0,0,,There's a very famous program you may have heard of called Maxima developed at MIT in the past, Dialogue: 0,0:41:00.42,0:41:03.14,EN,,0,0,0,,which is 5,000 pages of Lisp code, Dialogue: 0,0:41:03.92,0:41:06.50,EN,,0,0,0,,mostly the algebraic simplification operations. Dialogue: 0,0:41:08.08,0:41:12.21,EN,,0,0,0,,There we see the derivative of foo. Dialogue: 0,0:41:12.21,0:41:16.86,EN,,0,0,0,,In fact, alias is something I wouldn't take off more than 1 point for on an elementary calculus class. Dialogue: 0,0:41:18.38,0:41:22.49,EN,,0,0,0,,And the derivative of foo with respect to a, well it's gone down to X times X, Dialogue: 0,0:41:22.80,0:41:23.80,EN,,0,0,0,,which isn't so bad. Dialogue: 0,0:41:24.74,0:41:27.53,EN,,0,0,0,,And the derivative of foo with respect to b is just X itself. Dialogue: 0,0:41:28.06,0:41:30.12,EN,,0,0,0,,And the derivative of foo with respect to c comes out 1. Dialogue: 0,0:41:30.70,0:41:32.04,EN,,0,0,0,,So I'm pretty pleased with this. Dialogue: 0,0:41:34.10,0:41:39.01,EN,,0,0,0,,What you've seen is, of course, a little bit contrived, carefully organized example Dialogue: 0,0:41:39.56,0:41:42.60,EN,,0,0,0,,to show you how we can manipulate algebraic expressions, Dialogue: 0,0:41:42.96,0:41:47.93,EN,,0,0,0,,how we do that abstractly in terms of abstract syntax rather than concrete syntax Dialogue: 0,0:41:49.21,0:41:56.29,EN,,0,0,0,,and how we can use the abstraction to control what goes on in building these expressions. Dialogue: 0,0:41:57.80,0:42:00.41,EN,,0,0,0,,But the real story isn't just such a simple thing as that. Dialogue: 0,0:42:01.00,0:42:04.45,EN,,0,0,0,,The real story is, in fact, that I'm manipulating these expressions. Dialogue: 0,0:42:04.45,0:42:06.72,EN,,0,0,0,,And the expressions are the same expressions-- Dialogue: 0,0:42:06.72,0:42:07.97,EN,,0,0,0,,going back to the slide-- Dialogue: 0,0:42:08.08,0:42:10.52,EN,,0,0,0,,as the ones that are Lisp expressions. Dialogue: 0,0:42:12.02,0:42:12.97,EN,,0,0,0,,There's a pun here. Dialogue: 0,0:42:13.82,0:42:21.49,EN,,0,0,0,,I've chosen my representation to be the same as the representation in my language of similar things. Dialogue: 0,0:42:22.89,0:42:26.52,EN,,0,0,0,,By doing so, I've invoked a necessity. Dialogue: 0,0:42:26.90,0:42:30.34,EN,,0,0,0,,I created the necessity to have things like quotation Dialogue: 0,0:42:30.97,0:42:38.17,EN,,0,0,0,,because of the fact that my language is capable of writing expressions that talk about expressions of the language. Dialogue: 0,0:42:39.76,0:42:43.22,EN,,0,0,0,,I need to have something that says, this is an expression I'm talking about Dialogue: 0,0:42:43.76,0:42:46.13,EN,,0,0,0,,rather than this expression is talking about something, Dialogue: 0,0:42:47.20,0:42:48.44,EN,,0,0,0,,and I want to talk about that. Dialogue: 0,0:42:51.34,0:42:55.36,EN,,0,0,0,,So quotation stops and says, I'm talking about this expression itself. Dialogue: 0,0:42:57.97,0:43:00.85,EN,,0,0,0,,Now, given that power, Dialogue: 0,0:43:01.58,0:43:03.82,EN,,0,0,0,,if I can manipulate expressions of the language, Dialogue: 0,0:43:04.80,0:43:09.00,EN,,0,0,0,,I can begin to build even much more powerful layers upon layers of languages. Dialogue: 0,0:43:09.77,0:43:12.64,EN,,0,0,0,,Because I can write languages that not only are embedded in Lisp Dialogue: 0,0:43:13.46,0:43:14.80,EN,,0,0,0,,or whatever language you start with, Dialogue: 0,0:43:15.26,0:43:17.76,EN,,0,0,0,,but languages that are completely different, Dialogue: 0,0:43:18.58,0:43:22.24,EN,,0,0,0,,that are just, if we say, interpreted in Lisp or something like that. Dialogue: 0,0:43:23.17,0:43:25.46,EN,,0,0,0,,We'll get to understand those words more in the future. Dialogue: 0,0:43:26.56,0:43:32.09,EN,,0,0,0,,But right now I just want to leave you with the fact that we've hit a line Dialogue: 0,0:43:32.36,0:43:34.98,EN,,0,0,0,,which gives us tremendous power. Dialogue: 0,0:43:36.00,0:43:37.82,EN,,0,0,0,,And this point we've bought a sledgehammer. Dialogue: 0,0:43:38.17,0:43:40.92,EN,,0,0,0,,We have to be careful to what flies when we apply it. Dialogue: 0,0:43:42.17,0:43:43.00,EN,,0,0,0,,Thank you. Dialogue: 0,0:43:44.10,0:44:00.54,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:43:44.10,0:44:00.54,Declare,,0,0,0,,{\an2\fad(500,500)}Project Repo\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec4a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: CHNENG Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Video Zoom Percent: 0.65 PlayResX: 640 PlayResY: 480 Scroll Position: 75 Active Line: 0 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:24.34,0:00:29.34,EN,,0,0,0,,PROFESSOR: Well, yesterday we learned a bit about symbolic manipulation, Dialogue: 0,0:00:29.92,0:00:35.12,EN,,0,0,0,,and we wrote a rather stylized program Dialogue: 0,0:00:35.15,0:00:38.97,EN,,0,0,0,,to implement a pile of calculus rule from the calculus book. Dialogue: 0,0:00:39.61,0:00:44.59,EN,,0,0,0,,Here on the transparencies, Dialogue: 0,0:00:44.96,0:00:48.81,EN,,0,0,0,,we see a bunch of calculus rules from such a book. Dialogue: 0,0:00:49.47,0:00:54.62,EN,,0,0,0,,And, of course, what we did is sort of translate these rules into the language of the computer. Dialogue: 0,0:00:55.14,0:00:58.85,EN,,0,0,0,,But, of course, that's a sort of funny strategy. Dialogue: 0,0:00:59.36,0:01:04.80,EN,,0,0,0,,Why should we have to translate these rules into the language of the computer? Dialogue: 0,0:01:05.00,0:01:06.27,EN,,0,0,0,,And what do I really mean by that? Dialogue: 0,0:01:06.62,0:01:11.02,EN,,0,0,0,,These are--the program we wrote yesterday was very stylized. Dialogue: 0,0:01:11.21,0:01:15.98,EN,,0,0,0,,It was a conditional, a dispatch on the type of the expression Dialogue: 0,0:01:16.38,0:01:18.48,EN,,0,0,0,,as observed by the rules. Dialogue: 0,0:01:19.68,0:01:21.55,EN,,0,0,0,,What we see here are rules that say Dialogue: 0,0:01:21.74,0:01:25.48,EN,,0,0,0,,if the object being the derivative is being taken of, Dialogue: 0,0:01:25.48,0:01:29.42,EN,,0,0,0,,if that expression is a constant, then do one thing. Dialogue: 0,0:01:29.42,0:01:31.37,EN,,0,0,0,,If it's a variable, do another thing. Dialogue: 0,0:01:31.60,0:01:35.56,EN,,0,0,0,,If it's a product of a constant times a variable, do something and so on. Dialogue: 0,0:01:36.00,0:01:38.96,EN,,0,0,0,,There's sort of a dispatch there on a type. Dialogue: 0,0:01:41.40,0:01:45.16,EN,,0,0,0,,Well, since it has such a stylized behavior and structure, Dialogue: 0,0:01:45.95,0:01:49.53,EN,,0,0,0,,is there some other way of writing this program that's more clear? Dialogue: 0,0:01:50.83,0:01:53.45,EN,,0,0,0,,Well, what's a rule, first of all, What are these rules? Dialogue: 0,0:01:55.56,0:01:58.50,EN,,0,0,0,,Let's think about that. Rules have parts. Dialogue: 0,0:01:58.94,0:02:02.35,EN,,0,0,0,,If you look at these rules in detail, Dialogue: 0,0:02:03.71,0:02:04.99,EN,,0,0,0,,what you see, for example, Dialogue: 0,0:02:05.12,0:02:09.69,EN,,0,0,0,,is the rule has a left-hand side and a right-hand side. Dialogue: 0,0:02:10.36,0:02:14.36,EN,,0,0,0,,Each of these rules has a left-hand side and the right-hand side. Dialogue: 0,0:02:15.15,0:02:20.30,EN,,0,0,0,,The left-hand side is somehow compared with the expression you're trying to take the derivative of. Dialogue: 0,0:02:21.52,0:02:25.10,EN,,0,0,0,,The right-hand side is the replacement for that expression. Dialogue: 0,0:02:28.49,0:02:33.10,EN,,0,0,0,,So all rules on this page are something like this. Dialogue: 0,0:02:36.51,0:02:38.06,EN,,0,0,0,,I have patterns, Dialogue: 0,0:02:41.48,0:02:48.30,EN,,0,0,0,,and somehow, I have to produce, given a pattern, a skeleton. Dialogue: 0,0:02:51.88,0:02:52.81,EN,,0,0,0,,This is a rule. Dialogue: 0,0:02:55.42,0:02:57.13,EN,,0,0,0,,A pattern is something that matches, Dialogue: 0,0:02:57.88,0:03:03.26,EN,,0,0,0,,and a skeleton is something you substitute into in order to get a new expression. Dialogue: 0,0:03:06.46,0:03:16.32,EN,,0,0,0,,So what that means is that the pattern is matched against the expression, which is the source expression. Dialogue: 0,0:03:23.72,0:03:28.51,EN,,0,0,0,,And the result of the application of the rule is to produce a new expression, Dialogue: 0,0:03:33.61,0:03:34.91,EN,,0,0,0,,which I'll call a target, Dialogue: 0,0:03:38.12,0:03:39.88,EN,,0,0,0,,by instantiation of a skeleton. Dialogue: 0,0:03:41.63,0:03:43.02,EN,,0,0,0,,That's called instantiation. Dialogue: 0,0:03:50.72,0:03:54.73,EN,,0,0,0,,So that is the process by which these rules are described. Dialogue: 0,0:03:55.69,0:03:57.26,EN,,0,0,0,,What I'd like to do today Dialogue: 0,0:03:58.73,0:04:01.08,EN,,0,0,0,,is build a language Dialogue: 0,0:04:02.20,0:04:05.48,EN,,0,0,0,,and a means of interpreting that language, a means of executing that language, Dialogue: 0,0:04:05.74,0:04:08.43,EN,,0,0,0,,where that language allows us to directly express these rules. Dialogue: 0,0:04:10.59,0:04:11.58,EN,,0,0,0,,And what we're going to do Dialogue: 0,0:04:11.58,0:04:17.56,EN,,0,0,0,,instead of bringing the rules to the level of the computer by writing a program that is those rules Dialogue: 0,0:04:18.38,0:04:21.56,EN,,0,0,0,,in the computer's language--at the moment, in a Lisp-- Dialogue: 0,0:04:22.16,0:04:24.49,EN,,0,0,0,,we're going to bring the computer to the level of us Dialogue: 0,0:04:25.48,0:04:29.15,EN,,0,0,0,,by writing a way by which the computer can understand rules of this sort. Dialogue: 0,0:04:30.91,0:04:34.76,EN,,0,0,0,,This is slightly emphasizing the idea that we had last time Dialogue: 0,0:04:35.44,0:04:39.36,EN,,0,0,0,,that we're trying to make a solution to a class of problems rather than a particular one. Dialogue: 0,0:04:39.77,0:04:46.72,EN,,0,0,0,,The problem is if I want to write rules for a different piece of mathematics, Dialogue: 0,0:04:48.24,0:04:51.39,EN,,0,0,0,,say, to simple algebraic simplification or something like that, Dialogue: 0,0:04:51.98,0:04:55.48,EN,,0,0,0,,or manipulation of trigonometric functions, Dialogue: 0,0:04:56.09,0:05:01.16,EN,,0,0,0,,I would have to write a different program in using yesterday's method. Dialogue: 0,0:05:01.16,0:05:05.42,EN,,0,0,0,,Whereas I would like to encapsulate all of the things that are common to both of those programs, Dialogue: 0,0:05:06.12,0:05:10.17,EN,,0,0,0,,meaning the idea of matching, instantiation, the control structure, Dialogue: 0,0:05:10.17,0:05:12.46,EN,,0,0,0,,which turns out to be very complicated for such a thing, Dialogue: 0,0:05:13.16,0:05:18.46,EN,,0,0,0,,I'd like to encapsulate that separately from the rules themselves. Dialogue: 0,0:05:20.06,0:05:22.60,EN,,0,0,0,,So let's look at, first of all, a representation. Dialogue: 0,0:05:22.62,0:05:24.09,EN,,0,0,0,,I'd like to use the overhead here. Dialogue: 0,0:05:24.67,0:05:25.60,EN,,0,0,0,,I'd like-- there it is. Dialogue: 0,0:05:26.25,0:05:32.27,EN,,0,0,0,,I'd like to look at a representation of the rules of calculus for derivatives Dialogue: 0,0:05:33.71,0:05:37.15,EN,,0,0,0,,in a sort of simple language that I'm writing right here. Dialogue: 0,0:05:38.11,0:05:43.29,EN,,0,0,0,,Now, I'm going to avoid--I'm going to avoid worrying about syntax. Dialogue: 0,0:05:44.28,0:05:49.28,EN,,0,0,0,,We can easily pretty this, and I'm not interested in making-- this is indeed ugly. Dialogue: 0,0:05:49.30,0:05:56.41,EN,,0,0,0,,This doesn't look like the beautiful text set dx by dt or something that I'd like to write, Dialogue: 0,0:05:56.76,0:05:58.12,EN,,0,0,0,,but that's not essential. Dialogue: 0,0:05:58.88,0:06:00.62,EN,,0,0,0,,That's sort of an accidental phenomenon. Dialogue: 0,0:06:01.00,0:06:04.44,EN,,0,0,0,,Here, we're just worrying about the fact that the structure of the rules Dialogue: 0,0:06:04.83,0:06:11.70,EN,,0,0,0,,is that there is a left-hand side here, represents the thing I want to match against the derivative expression. Dialogue: 0,0:06:11.80,0:06:13.56,EN,,0,0,0,,This is the representation I'm going to say Dialogue: 0,0:06:13.60,0:06:18.32,EN,,0,0,0,,for the derivative of a constant, which we will call c Dialogue: 0,0:06:18.84,0:06:21.20,EN,,0,0,0,,respect to the variable we will call v. Dialogue: 0,0:06:23.08,0:06:25.55,EN,,0,0,0,,And what we will get on the right-hand side is 0. Dialogue: 0,0:06:26.00,0:06:28.06,EN,,0,0,0,,So this represents a rule. Dialogue: 0,0:06:29.26,0:06:34.04,EN,,0,0,0,,The next rule will be the derivative of a variable, which we will call v Dialogue: 0,0:06:34.22,0:06:37.74,EN,,0,0,0,,respect to the same variable v, and we get a 1. Dialogue: 0,0:06:38.60,0:06:42.17,EN,,0,0,0,,However, if we have the derivative of a variable called u Dialogue: 0,0:06:42.41,0:06:44.84,EN,,0,0,0,,respect to a different variables v, Dialogue: 0,0:06:45.39,0:06:47.05,EN,,0,0,0,,we will get 0. Dialogue: 0,0:06:47.84,0:06:52.17,EN,,0,0,0,,I just want you look at these rules a little bit and see how they fit together. Dialogue: 0,0:06:52.51,0:06:54.30,EN,,0,0,0,,For example, over here, Dialogue: 0,0:06:54.73,0:07:01.90,EN,,0,0,0,,we're going to have the derivative of the sum of an expression called x1 and an expression called x2. Dialogue: 0,0:07:01.90,0:07:05.85,EN,,0,0,0,,These things that begin with question marks are called pattern variables Dialogue: 0,0:07:06.88,0:07:08.62,EN,,0,0,0,,in the language that we're inventing, Dialogue: 0,0:07:08.93,0:07:14.93,EN,,0,0,0,,and you see we're just making it up, so pattern variables for matching. Dialogue: 0,0:07:14.93,0:07:20.33,EN,,0,0,0,,And so in this-- here we have the derivative of the sum of the expression which we will call x1. Dialogue: 0,0:07:20.33,0:07:26.70,EN,,0,0,0,,And the expression we will call x2 with respect to the variable we call v will be-- here is the right-hand side: Dialogue: 0,0:07:26.70,0:07:32.76,EN,,0,0,0,,the sum of the derivative of that expression x1 with respect to v-- the right-hand side is the skeleton-- Dialogue: 0,0:07:33.82,0:07:37.10,EN,,0,0,0,,and the derivative of x2 with respect to v. Dialogue: 0,0:07:37.60,0:07:42.38,EN,,0,0,0,,Colons here will stand for substitution objects. Dialogue: 0,0:07:43.63,0:07:47.23,EN,,0,0,0,,They're--we'll call them skeleton evaluations. Dialogue: 0,0:07:48.51,0:07:53.07,EN,,0,0,0,,So let me put up here on the blackboard for a second some syntax Dialogue: 0,0:07:53.23,0:07:55.56,EN,,0,0,0,,so we'll know what's going on for this rule language. Dialogue: 0,0:07:56.68,0:07:59.88,EN,,0,0,0,,First of all, we're going to have to worry about the pattern matching. Dialogue: 0,0:08:06.04,0:08:13.12,EN,,0,0,0,,We're going to have things like a symbol like foo matches exactly itself. Dialogue: 0,0:08:23.52,0:08:31.34,EN,,0,0,0,,The expression f of a and b will be used to match any list Dialogue: 0,0:08:36.30,0:08:57.02,EN,,0,0,0,,whose first element is f, whose second element is a, and whose third element is b. Dialogue: 0,0:08:58.62,0:09:06.99,EN,,0,0,0,,Also, another thing we might have in a pattern is that--a question mark with some variable like x. Dialogue: 0,0:09:08.57,0:09:18.67,EN,,0,0,0,,And what that means, it says matches anything, which we will call x. Dialogue: 0,0:09:25.45,0:09:29.98,EN,,0,0,0,,Question mark c x will match only constants. Dialogue: 0,0:09:31.50,0:09:40.96,EN,,0,0,0,,So this is something which matches a constant called x. Dialogue: 0,0:09:44.56,0:09:57.07,EN,,0,0,0,,And question mark v x will match a variable, which we call x. Dialogue: 0,0:10:01.66,0:10:03.80,EN,,0,0,0,,This is sort of the language we're making up now. Dialogue: 0,0:10:04.19,0:10:09.40,EN,,0,0,0,,If I match two things against each other, then they are compared element by element Dialogue: 0,0:10:10.25,0:10:15.85,EN,,0,0,0,,But elements in the pattern may contain these syntactic variables, Dialogue: 0,0:10:17.07,0:10:20.43,EN,,0,0,0,,which will be used to match arbitrary objects. Dialogue: 0,0:10:22.12,0:10:29.28,EN,,0,0,0,,And we'll get that object as the value in the name x here, for example. Dialogue: 0,0:10:31.05,0:10:37.55,EN,,0,0,0,,Now, when we make skeletons for instantiation. Dialogue: 0,0:10:39.50,0:10:41.40,EN,,0,0,0,,Well, then we have things like this. Dialogue: 0,0:10:42.27,0:10:46.33,EN,,0,0,0,,foo, a symbol, instantiates to itself. Dialogue: 0,0:10:55.08,0:11:05.92,EN,,0,0,0,,Something which is a list like f of a and b, instantiates to-- Dialogue: 0,0:11:06.36,0:11:14.75,EN,,0,0,0,,well, f instantiates to a 3-list, a list of three elements, Dialogue: 0,0:11:15.55,0:11:33.37,EN,,0,0,0,,okay, which are the results of instantiating each of f, a, and b. Dialogue: 0,0:11:36.35,0:11:54.27,EN,,0,0,0,,And x well--we instantiate to the value of x as in the matched pattern. Dialogue: 0,0:12:03.05,0:12:10.08,EN,,0,0,0,,So going back to the overhead here, we see -- we see that all of those kinds of objects Dialogue: 0,0:12:10.78,0:12:16.06,EN,,0,0,0,,we see here a pattern variable which matches a constant, Dialogue: 0,0:12:16.56,0:12:19.02,EN,,0,0,0,,a pattern variable which matches a variable, Dialogue: 0,0:12:19.39,0:12:21.74,EN,,0,0,0,,a pattern variable which will match anything. Dialogue: 0,0:12:22.72,0:12:24.92,EN,,0,0,0,,And if we have two instances of the same name, Dialogue: 0,0:12:25.08,0:12:31.77,EN,,0,0,0,,like this is the derivative of the expression which is a variable only whose name will be v Dialogue: 0,0:12:32.86,0:12:36.30,EN,,0,0,0,,with respect to some arbitrary expression which we will call v, Dialogue: 0,0:12:36.41,0:12:38.01,EN,,0,0,0,,since this v appears twice, Dialogue: 0,0:12:38.65,0:12:41.07,EN,,0,0,0,,we're going to want that to mean they have to be the same. Dialogue: 0,0:12:42.68,0:12:45.00,EN,,0,0,0,,The only consistent match is that those are the same. Dialogue: 0,0:12:45.23,0:12:47.23,EN,,0,0,0,,So here, we're making up a language. Dialogue: 0,0:12:47.60,0:12:50.66,EN,,0,0,0,,And in fact, that's a very nice thing to be doing. Dialogue: 0,0:12:50.66,0:12:52.60,EN,,0,0,0,,It's so much fun to make up a language. Dialogue: 0,0:12:52.60,0:12:54.33,EN,,0,0,0,,And you do this all the time. Dialogue: 0,0:12:54.33,0:12:56.89,EN,,0,0,0,,And the really most powerful design things you ever do Dialogue: 0,0:12:57.23,0:13:00.20,EN,,0,0,0,,are sort of making up a language to solve problems like this. Dialogue: 0,0:13:02.06,0:13:05.34,EN,,0,0,0,,Now, here we go back here and look at some of these rules. Dialogue: 0,0:13:05.80,0:13:07.10,EN,,0,0,0,,Well, there's a whole set of them. Dialogue: 0,0:13:07.10,0:13:12.43,EN,,0,0,0,,I mean, there's one for addition and one for multiplication, just like we had before. Dialogue: 0,0:13:12.43,0:13:17.37,EN,,0,0,0,,The derivative of the product of x1 and x2 with respect to v is Dialogue: 0,0:13:17.68,0:13:26.52,EN,,0,0,0,,the sum of the product of x1 and the derivative x2 with respect to v and the product of the derivative of x1 and x2. Dialogue: 0,0:13:27.26,0:13:29.10,EN,,0,0,0,,And here we have exponentiation. Dialogue: 0,0:13:29.24,0:13:32.11,EN,,0,0,0,,And, of course, we run off the end down here. We get as many as we like. Dialogue: 0,0:13:32.70,0:13:39.10,EN,,0,0,0,,But the whole thing over here, I'm giving this--this list of rules the name "derivative rules." Dialogue: 0,0:13:40.40,0:13:44.33,EN,,0,0,0,,What would we do with such a thing once we have it? Dialogue: 0,0:13:45.40,0:13:47.84,EN,,0,0,0,,Well, one of the nicest ideas, first of all, Dialogue: 0,0:13:48.44,0:13:51.68,EN,,0,0,0,,is I'm going to write for you, and we're going to play with it all day. Dialogue: 0,0:13:52.28,0:13:57.37,EN,,0,0,0,,What I'm going to write for you is a program called simplifier, Dialogue: 0,0:13:57.82,0:13:59.47,EN,,0,0,0,,the general-purpose simplifier. Dialogue: 0,0:14:00.09,0:14:17.10,EN,,0,0,0,,And we're going to say something like define dsimp to be a simplifier of the derivative rules. Dialogue: 0,0:14:23.74,0:14:28.75,EN,,0,0,0,,And what simplifier is going to do is, given a set of rules, it will produce for me a procedure Dialogue: 0,0:14:29.32,0:14:34.59,EN,,0,0,0,,which will simplify expressions containing the things that are referred to by these rules. Dialogue: 0,0:14:37.39,0:14:43.93,EN,,0,0,0,,So here will be a procedure constructed for your purposes to simplify things with derivatives in them Dialogue: 0,0:14:44.59,0:14:49.56,EN,,0,0,0,,such that, after that, if we're typing at some Lisp system, and we get a prompt, Dialogue: 0,0:14:49.88,0:15:03.93,EN,,0,0,0,,and we say dsimp, for example, of the derivative of the sum of x and y with respect to x-- Dialogue: 0,0:15:06.99,0:15:10.97,EN,,0,0,0,,note the quote here because I'm talking about the expression which is the derivative-- Dialogue: 0,0:15:13.29,0:15:17.76,EN,,0,0,0,,then I will get back as a result plus 1 0. Dialogue: 0,0:15:19.96,0:15:24.60,EN,,0,0,0,,Because the derivative of x plus y is the derivative of x plus derivative y. Dialogue: 0,0:15:24.60,0:15:26.22,EN,,0,0,0,,The derivative of x with respect to x is 1. Dialogue: 0,0:15:26.38,0:15:27.82,EN,,0,0,0,,The derivative of y with respect to x is 0. Dialogue: 0,0:15:29.42,0:15:30.46,EN,,0,0,0,,It's not what we're going to get. Dialogue: 0,0:15:31.18,0:15:34.65,EN,,0,0,0,,I haven't put any simplification at that level-- algebraic simplification--yet. Dialogue: 0,0:15:36.16,0:15:41.53,EN,,0,0,0,,Of course, once we have such a thing, then we can--then we can look at other rules. Dialogue: 0,0:15:41.96,0:15:49.36,EN,,0,0,0,,So, for example, we can, if we go to the slide, OK? Dialogue: 0,0:15:49.36,0:15:54.12,EN,,0,0,0,,Here, for example, are other rules that we might have, algebraic manipulation rules, Dialogue: 0,0:15:56.00,0:15:58.38,EN,,0,0,0,,ones that would be used for simplifying algebraic expressions. Dialogue: 0,0:15:59.00,0:16:02.06,EN,,0,0,0,,For example, just looking at some of these, Dialogue: 0,0:16:03.04,0:16:09.20,EN,,0,0,0,,the left-hand side says any operator applied to a constant e1 and a constant e2 Dialogue: 0,0:16:09.32,0:16:14.51,EN,,0,0,0,,is the result of evaluating that operator on the constants e1 and e2. Dialogue: 0,0:16:15.88,0:16:21.56,EN,,0,0,0,,Or an operator, applied to e1, any expression e1 and a constant e2, Dialogue: 0,0:16:21.69,0:16:23.87,EN,,0,0,0,,is going to move the constant forward. Dialogue: 0,0:16:24.52,0:16:27.68,EN,,0,0,0,,So that'll turn into the operator with e2 followed by e1. Dialogue: 0,0:16:28.59,0:16:30.11,EN,,0,0,0,,Why I did that, I don't know. Dialogue: 0,0:16:30.22,0:16:33.16,EN,,0,0,0,,It wouldn't work if I had division, for example. Dialogue: 0,0:16:33.53,0:16:35.31,EN,,0,0,0,,So there's a bug in the rules, if you like. Dialogue: 0,0:16:36.67,0:16:40.86,EN,,0,0,0,,So the sum of 0 and e is e. Dialogue: 0,0:16:42.17,0:16:45.31,EN,,0,0,0,,The product of 1 and any expression e is e. Dialogue: 0,0:16:46.12,0:16:49.13,EN,,0,0,0,,The product of 0 and any expression e is 0. Dialogue: 0,0:16:49.33,0:16:52.72,EN,,0,0,0,,Just looking at some more of these rules, we could have arbitrarily complicated ones. Dialogue: 0,0:16:53.69,0:16:54.81,EN,,0,0,0,,We could have things like Dialogue: 0,0:16:55.36,0:17:01.69,EN,,0,0,0,,the product of the constant e1 and any constant e2 with e3 Dialogue: 0,0:17:02.35,0:17:11.96,EN,,0,0,0,,is the result of multiplying the result of multiplying now the constants e1 and e2 together and putting e3 there. Dialogue: 0,0:17:13.36,0:17:16.76,EN,,0,0,0,,So it says combine the constants that I had, Dialogue: 0,0:17:16.76,0:17:22.70,EN,,0,0,0,,which was if I had a product of e1 and e2 and e3 just multiply--I mean and e1 and e2 are both constants, multiply them. Dialogue: 0,0:17:23.84,0:17:25.48,EN,,0,0,0,,And you can make up the rules as you like. Dialogue: 0,0:17:25.79,0:17:26.94,EN,,0,0,0,,There are lots of them here. Dialogue: 0,0:17:27.42,0:17:31.04,EN,,0,0,0,,There are things as complicated, for example, as-- Dialogue: 0,0:17:31.26,0:17:33.93,EN,,0,0,0,,oh, I suppose down here some distributive law, you see. Dialogue: 0,0:17:33.93,0:17:38.57,EN,,0,0,0,,The product of any object c and the sum of d and e Dialogue: 0,0:17:39.02,0:17:43.66,EN,,0,0,0,,gives the result as the same as the sum of the product of c and d and the product of c and e. Dialogue: 0,0:17:45.31,0:17:48.67,EN,,0,0,0,,Now, what exactly these rules are doesn't very much interest me. Dialogue: 0,0:17:49.16,0:17:52.97,EN,,0,0,0,,We're going to be writing the language that will allow us to interpret these rules Dialogue: 0,0:17:55.50,0:17:57.48,EN,,0,0,0,,so that we can, in fact, make up whatever rules we like, Dialogue: 0,0:17:58.35,0:18:00.14,EN,,0,0,0,,another whole language of programming. Dialogue: 0,0:18:03.39,0:18:04.04,EN,,0,0,0,,Well, let's see. Dialogue: 0,0:18:05.18,0:18:06.96,EN,,0,0,0,,I haven't told you how we're going to do this. Dialogue: 0,0:18:07.53,0:18:10.06,EN,,0,0,0,,And, of course, for a while, we're going to work on that. Dialogue: 0,0:18:10.89,0:18:15.40,EN,,0,0,0,,But there's a real question of what is--what am I going to do at all at a large scale? Dialogue: 0,0:18:17.08,0:18:18.22,EN,,0,0,0,,How do these rules work? Dialogue: 0,0:18:19.00,0:18:25.45,EN,,0,0,0,,How is the simplifier program going to manipulate these rules with your expression to produce a reasonable answer? Dialogue: 0,0:18:26.22,0:18:29.85,EN,,0,0,0,,Well, first, I'd like to think about these rules as being some sort of deck of them. Dialogue: 0,0:18:32.52,0:18:34.22,EN,,0,0,0,,So here I have a whole bunch of rules, Dialogue: 0,0:18:42.09,0:18:44.49,EN,,0,0,0,,Each rule-- here's a rule-- Dialogue: 0,0:18:46.97,0:18:49.24,EN,,0,0,0,,has a pattern and a skeleton. Dialogue: 0,0:18:49.72,0:18:51.36,EN,,0,0,0,,I'm trying to make up a control structure for this. Dialogue: 0,0:18:53.37,0:18:56.56,EN,,0,0,0,,Now, what I have is a matcher, Dialogue: 0,0:19:00.99,0:19:03.76,EN,,0,0,0,,and I have something which is an instantiater. Dialogue: 0,0:19:09.66,0:19:12.94,EN,,0,0,0,,And I'm going to pass from the matcher to the instantiater Dialogue: 0,0:19:14.03,0:19:17.47,EN,,0,0,0,,some set of meaning for the pattern variables, Dialogue: 0,0:19:18.06,0:19:19.42,EN,,0,0,0,,a dictionary, I'll call it. Dialogue: 0,0:19:20.59,0:19:21.52,EN,,0,0,0,,A dictionary, Dialogue: 0,0:19:24.92,0:19:27.82,EN,,0,0,0,,which will say x was matched against the following subexpression Dialogue: 0,0:19:29.04,0:19:31.31,EN,,0,0,0,,and y was matched against another following subexpression. Dialogue: 0,0:19:32.25,0:19:36.35,EN,,0,0,0,,And from the instantiater, I will be making expressions,and they will go into the matcher. Dialogue: 0,0:19:37.16,0:19:38.36,EN,,0,0,0,,They will be expressions. Dialogue: 0,0:19:45.00,0:19:48.41,EN,,0,0,0,,And the patterns of the rules will be fed into the matcher, Dialogue: 0,0:19:49.24,0:19:54.40,EN,,0,0,0,,and the skeletons from the same rule will be fed into the instantiater. Dialogue: 0,0:19:55.21,0:19:56.62,EN,,0,0,0,,Now, this is a little complicated Dialogue: 0,0:19:57.12,0:19:59.53,EN,,0,0,0,,because when you have something like an algebraic expression, Dialogue: 0,0:20:00.44,0:20:03.60,EN,,0,0,0,,where some of the rules are intended to be able to allow you to substitute equal for equal. Dialogue: 0,0:20:04.24,0:20:05.87,EN,,0,0,0,,These are equal transformation rules. Dialogue: 0,0:20:06.88,0:20:09.29,EN,,0,0,0,,So all subexpressions of the expression should be looked at. Dialogue: 0,0:20:11.13,0:20:15.82,EN,,0,0,0,,You give it an expression, this thing, and the rules should be cycled around. Dialogue: 0,0:20:16.03,0:20:19.71,EN,,0,0,0,,First of all, for every subexpression of the expression you feed in, Dialogue: 0,0:20:20.22,0:20:22.83,EN,,0,0,0,,all of the rules must be tried and looked at. Dialogue: 0,0:20:24.33,0:20:27.07,EN,,0,0,0,,And if any rule matches, then this process occurs. Dialogue: 0,0:20:27.30,0:20:30.63,EN,,0,0,0,,The dictionary--the dictionary is to have some values in it. Dialogue: 0,0:20:30.63,0:20:33.39,EN,,0,0,0,,The instantiater makes a new expression, Dialogue: 0,0:20:33.90,0:20:39.10,EN,,0,0,0,,which is basically replaces that part of the expression that was matched in your original expression. Dialogue: 0,0:20:40.84,0:20:44.46,EN,,0,0,0,,And then, then, of course, we're going to recheck that, Dialogue: 0,0:20:44.75,0:20:48.11,EN,,0,0,0,,going to go around these rules again, seeing if that could be simplified further. Dialogue: 0,0:20:49.53,0:20:53.71,EN,,0,0,0,,And then, then we're going to do that for every subexpression until the thing no longer changes. Dialogue: 0,0:20:54.96,0:20:57.50,EN,,0,0,0,,You can think of this as sort of an organic process. Dialogue: 0,0:20:57.83,0:21:00.20,EN,,0,0,0,,You've got some sort of stew, right? Dialogue: 0,0:21:00.24,0:21:04.32,EN,,0,0,0,,You've got bacteria or something, or enzymes in some, in some gooey mess. Dialogue: 0,0:21:05.63,0:21:10.50,EN,,0,0,0,,And there's these--and these enzymes change things. Dialogue: 0,0:21:10.50,0:21:14.38,EN,,0,0,0,,They attach to your expression, change it, and then they go away. Dialogue: 0,0:21:15.28,0:21:17.83,EN,,0,0,0,,And they have to match. The key-in-lock phenomenon. Dialogue: 0,0:21:18.00,0:21:19.73,EN,,0,0,0,,They match, they change it, they go away. Dialogue: 0,0:21:19.73,0:21:21.68,EN,,0,0,0,,You can imagine it as a parallel process of some sort. Dialogue: 0,0:21:22.70,0:21:24.97,EN,,0,0,0,,So you stick an expression into this mess, Dialogue: 0,0:21:25.80,0:21:28.00,EN,,0,0,0,,and after a while, you take it out, and it's been simplified. Dialogue: 0,0:21:30.44,0:21:32.64,EN,,0,0,0,,And it just keeps changing until it no longer can be changed. Dialogue: 0,0:21:33.36,0:21:38.33,EN,,0,0,0,,But these enzymes can attach to any part of the, of the expression. Dialogue: 0,0:21:39.21,0:21:43.76,EN,,0,0,0,,OK, at this point, I'd like to stop and ask for questions. Dialogue: 0,0:21:44.92,0:21:45.36,EN,,0,0,0,,Yes. Dialogue: 0,0:21:45.43,0:21:52.76,EN,,0,0,0,,AUDIENCE: This implies that the matching program and the instantiation program are separate programs; is that right? Or is that-- they are. Dialogue: 0,0:21:52.76,0:21:53.85,EN,,0,0,0,,PROFESSOR: They're separate little pieces. Dialogue: 0,0:21:54.14,0:21:56.60,EN,,0,0,0,,They fit together in a larger structure. Dialogue: 0,0:21:57.26,0:21:59.13,EN,,0,0,0,,AUDIENCE: So I'm going through and matching Dialogue: 0,0:21:59.61,0:22:03.21,EN,,0,0,0,,and passing the information about what I matched to an instantiater, Dialogue: 0,0:22:03.39,0:22:06.03,EN,,0,0,0,,which makes the changes. And then I pass that back to the matcher? Dialogue: 0,0:22:06.11,0:22:08.49,EN,,0,0,0,,PROFESSOR: It won't make a change. It will make a new expression, Dialogue: 0,0:22:09.61,0:22:18.43,EN,,0,0,0,,which has, which has substituted the values of the pattern variable that were matched on the left-hand side for the variables that are mentioned, Dialogue: 0,0:22:18.99,0:22:23.80,EN,,0,0,0,,the skeleton variables or evaluation variables or whatever I called them, on the right-hand side. Dialogue: 0,0:22:25.20,0:22:27.08,EN,,0,0,0,,AUDIENCE: And then that's passed back into the matcher? Dialogue: 0,0:22:27.20,0:22:32.32,EN,,0,0,0,,PROFESSOR: Then this is going to go around again. This is going to go through this mess until it no longer changes. Dialogue: 0,0:22:33.31,0:22:37.00,EN,,0,0,0,,AUDIENCE: And it seems that there would be a danger of getting into a recursive loop. Dialogue: 0,0:22:37.20,0:22:42.00,EN,,0,0,0,,Yes, if you do not write your rules nicely, you are-- indeed, Dialogue: 0,0:22:42.00,0:22:45.53,EN,,0,0,0,,in any programming language you invent, if it's sufficiently powerful to do anything, Dialogue: 0,0:22:45.72,0:22:48.40,EN,,0,0,0,,you can write programs that will go into infinite loops. Dialogue: 0,0:22:49.37,0:22:55.07,EN,,0,0,0,,And indeed, writing a program for doing algebraic manipulation so on will produce infinite loops. Dialogue: 0,0:23:01.05,0:23:01.52,EN,,0,0,0,,Go ahead. Dialogue: 0,0:23:01.79,0:23:05.90,EN,,0,0,0,,AUDIENCE: Some language designers feel that this feature is so important Dialogue: 0,0:23:05.93,0:23:12.03,EN,,0,0,0,,that it should become part of the basic language, for example, scheme in this case. Dialogue: 0,0:23:12.03,0:23:13.96,EN,,0,0,0,,What are your thoughts on-- Dialogue: 0,0:23:13.96,0:23:15.08,EN,,0,0,0,,PROFESSOR: Which language feature? Dialogue: 0,0:23:15.79,0:23:17.26,EN,,0,0,0,,AUDIENCE: The pattern matching. Dialogue: 0,0:23:17.26,0:23:22.03,EN,,0,0,0,,It's all application of such rules should be-- Dialogue: 0,0:23:22.03,0:23:23.70,EN,,0,0,0,,PROFESSOR: Oh, you mean like Prolog? Dialogue: 0,0:23:23.70,0:23:26.60,EN,,0,0,0,,AUDIENCE: Like Prolog, but it becomes a more general-- Dialogue: 0,0:23:26.60,0:23:27.64,EN,,0,0,0,,PROFESSOR: It's possible. Dialogue: 0,0:23:28.46,0:23:32.30,EN,,0,0,0,,OK, I think my feeling about that is that Dialogue: 0,0:23:33.16,0:23:36.49,EN,,0,0,0,,I would like to teach you how to do it so you don't depend upon some language designer. Dialogue: 0,0:23:40.92,0:23:42.75,EN,,0,0,0,,PROFESSOR: You make it yourself. You can roll your own. Dialogue: 0,0:23:45.28,0:23:45.63,EN,,0,0,0,,Thank you. Dialogue: 0,0:23:45.63,0:23:50.63,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:23:50.63,0:23:53.13,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:23:53.13,0:23:55.63,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:24:00.32,0:24:06.76,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:24:07.07,0:24:10.52,Declare,,0,0,0,,{\an2\fad(500,500)}Pattern-matching: Rule-based Substitution Dialogue: 0,0:24:14.08,0:24:15.80,EN,,0,0,0,,Well, let's see. Dialogue: 0,0:24:15.80,0:24:17.21,EN,,0,0,0,,Now we have to tell you how it works. Dialogue: 0,0:24:20.00,0:24:24.11,EN,,0,0,0,,It conveniently breaks up into various pieces. Dialogue: 0,0:24:24.80,0:24:26.54,EN,,0,0,0,,I'd like to look now at the matcher. Dialogue: 0,0:24:28.72,0:24:31.42,EN,,0,0,0,,The matcher has the following basic structure. Dialogue: 0,0:24:32.86,0:24:45.12,EN,,0,0,0,,It's a box that takes as its input an expression and a pattern, Dialogue: 0,0:24:52.09,0:24:53.95,EN,,0,0,0,,and it turns out a dictionary. Dialogue: 0,0:25:01.71,0:25:08.67,EN,,0,0,0,,A dictionary, remember, is a mapping of pattern variables to the values that were found by matching, Dialogue: 0,0:25:09.15,0:25:11.05,EN,,0,0,0,,and it puts out another dictionary, Dialogue: 0,0:25:18.24,0:25:25.53,EN,,0,0,0,,which is the result of augmenting this dictionary by what was found in matching this expression against this pattern. Dialogue: 0,0:25:28.00,0:25:28.83,EN,,0,0,0,,So that's the matcher. Dialogue: 0,0:25:33.87,0:25:36.54,EN,,0,0,0,,Now, this is a rather complicated program, Dialogue: 0,0:25:37.20,0:25:41.58,EN,,0,0,0,,and we can look at it on the overhead over here and see, Dialogue: 0,0:25:41.98,0:25:43.87,EN,,0,0,0,,ha ha, it's very complicated. Dialogue: 0,0:25:44.43,0:25:45.87,EN,,0,0,0,,I just want you to look at the shape of it. Dialogue: 0,0:25:46.78,0:25:49.85,EN,,0,0,0,,It's too complicated to look at except in pieces. Dialogue: 0,0:25:51.72,0:25:59.24,EN,,0,0,0,,However, it's a fairly large, complicated program with a lot of sort of indented structure. Dialogue: 0,0:26:00.09,0:26:05.28,EN,,0,0,0,,At the largest scale-- you don't try to read those characters, but at the largest scale, Dialogue: 0,0:26:05.43,0:26:10.36,EN,,0,0,0,,you see that there is a case analysis, which is all these cases lined up. Dialogue: 0,0:26:12.09,0:26:16.19,EN,,0,0,0,,What we're now going to do is look at this in a bit more detail, Dialogue: 0,0:26:16.67,0:26:18.60,EN,,0,0,0,,attempting to understand how it works. Dialogue: 0,0:26:20.08,0:26:22.35,EN,,0,0,0,,Let's go now to the first slide, Dialogue: 0,0:26:23.55,0:26:27.93,EN,,0,0,0,,showing some of the structure of the matcher at a large scale. Dialogue: 0,0:26:28.81,0:26:36.33,EN,,0,0,0,,And we see that the matcher, the matcher takes as its input a pattern, an expression, and a dictionary. Dialogue: 0,0:26:38.57,0:26:40.40,EN,,0,0,0,,And there is a case analysis here, Dialogue: 0,0:26:41.24,0:26:45.61,EN,,0,0,0,,which is made out of several cases, some of which have been left out over here, Dialogue: 0,0:26:46.62,0:26:48.62,EN,,0,0,0,,and the general case, which I'd like you to see. Dialogue: 0,0:26:50.52,0:26:53.28,EN,,0,0,0,,Let's consider this general case. It's a very important pattern. Dialogue: 0,0:26:56.32,0:27:01.61,EN,,0,0,0,,The problem is that we have to examine two trees simultaneously. Dialogue: 0,0:27:02.50,0:27:08.03,EN,,0,0,0,,One of the trees is the tree of the expression, and the other is the tree of the pattern. Dialogue: 0,0:27:08.59,0:27:10.11,EN,,0,0,0,,We have to compare them with each other Dialogue: 0,0:27:11.37,0:27:16.38,EN,,0,0,0,,so that the subexpressions of the expression are matched against subexpressions of the pattern. Dialogue: 0,0:27:18.38,0:27:23.44,EN,,0,0,0,,Looking at that in a bit more detail, suppose I had a pattern, a pattern, Dialogue: 0,0:27:23.93,0:27:31.24,EN,,0,0,0,,which was the sum of the product of a thing which we will call x Dialogue: 0,0:27:32.44,0:27:35.53,EN,,0,0,0,,and a thing which we will call y, Dialogue: 0,0:27:39.12,0:27:42.04,EN,,0,0,0,,and the sum of that, and the same thing we call y. Dialogue: 0,0:27:45.21,0:27:47.53,EN,,0,0,0,,So we're looking for a sum of a product Dialogue: 0,0:27:48.99,0:27:54.78,EN,,0,0,0,,whose second--whose second argument is the same as the second argument of the sum. Dialogue: 0,0:27:57.02,0:27:58.84,EN,,0,0,0,,That's a thing you might be looking for. Dialogue: 0,0:27:59.60,0:28:02.04,EN,,0,0,0,,Well, that, as a pattern, looks like this. Dialogue: 0,0:28:03.02,0:28:04.01,EN,,0,0,0,,There is a tree, Dialogue: 0,0:28:04.94,0:28:06.25,EN,,0,0,0,,which consists of a sum, Dialogue: 0,0:28:08.08,0:28:20.25,EN,,0,0,0,,and a product with a pattern variable question mark x and question mark y, Dialogue: 0,0:28:21.36,0:28:22.73,EN,,0,0,0,,and question mark y, Dialogue: 0,0:28:24.92,0:28:26.94,EN,,0,0,0,,just looking at the same, just writing down the list structure in a different way. Dialogue: 0,0:28:28.75,0:28:31.76,EN,,0,0,0,,Now, suppose we were matching that against an expression which matches it, Dialogue: 0,0:28:32.49,0:28:39.85,EN,,0,0,0,,the product of 3 and x and, say, x. Dialogue: 0,0:28:42.41,0:28:43.36,EN,,0,0,0,,That's another tree. Dialogue: 0,0:28:44.33,0:28:56.06,EN,,0,0,0,,It's the sum of the product of 3 and x and of x. Dialogue: 0,0:28:59.44,0:29:03.02,EN,,0,0,0,,So what I want to do is traverse these two trees simultaneously. Dialogue: 0,0:29:04.41,0:29:07.82,EN,,0,0,0,,And what I'd like to do is walk them like this. Dialogue: 0,0:29:08.67,0:29:12.96,EN,,0,0,0,,I'm going to say are these the same? Dialogue: 0,0:29:12.96,0:29:14.32,EN,,0,0,0,,This is a complicated object. Dialogue: 0,0:29:15.21,0:29:17.26,EN,,0,0,0,,Let's look at the left branches. Dialogue: 0,0:29:17.26,0:29:18.14,EN,,0,0,0,,Well, that could be the car. Dialogue: 0,0:29:18.56,0:29:21.21,EN,,0,0,0,,How does that look? Oh yes, the plus looks just fine. Dialogue: 0,0:29:21.68,0:29:24.20,EN,,0,0,0,,But the next thing here is a complicated thing. Dialogue: 0,0:29:24.20,0:29:24.84,EN,,0,0,0,,Let's look at that. Dialogue: 0,0:29:25.20,0:29:26.80,EN,,0,0,0,,Oh yes, that's pretty fine, too. Dialogue: 0,0:29:26.80,0:29:27.79,EN,,0,0,0,,They're both asterisks. Dialogue: 0,0:29:28.51,0:29:30.24,EN,,0,0,0,,Now, whoops! Dialogue: 0,0:29:30.40,0:29:33.60,EN,,0,0,0,,My pattern variable, it matches against the 3. Dialogue: 0,0:29:34.27,0:29:35.92,EN,,0,0,0,,Remember, x equals 3 now. Dialogue: 0,0:29:36.36,0:29:37.37,EN,,0,0,0,,That's in my dictionary, Dialogue: 0,0:29:37.56,0:29:40.73,EN,,0,0,0,,and the dictionary's going to follow along with me: x equals three. Dialogue: 0,0:29:41.45,0:29:45.87,EN,,0,0,0,,Ah yes, x equals 3 and y equals x, different x. Dialogue: 0,0:29:46.83,0:29:51.20,EN,,0,0,0,,The pattern x is the expression x, the pattern y. Dialogue: 0,0:29:53.61,0:29:57.76,EN,,0,0,0,,Oh yes, the pattern variable y, I've already got a value for it. It's x. Dialogue: 0,0:29:58.36,0:30:00.06,EN,,0,0,0,,Is this an x? Oh yeah, sure it is. Dialogue: 0,0:30:00.06,0:30:00.75,EN,,0,0,0,,That's fine. Dialogue: 0,0:30:02.03,0:30:02.78,EN,,0,0,0,,Yep, done. Dialogue: 0,0:30:03.39,0:30:08.09,EN,,0,0,0,,I now have a dictionary, which I've accumulated by making this walk. Dialogue: 0,0:30:11.42,0:30:14.51,EN,,0,0,0,,Well, now let's look at this general case here and see how that works. Dialogue: 0,0:30:15.88,0:30:16.51,EN,,0,0,0,,Here we have it. Dialogue: 0,0:30:17.20,0:30:21.66,EN,,0,0,0,,I take in a pattern variable -- sorry -- a pattern, an expression, and a dictionary. Dialogue: 0,0:30:22.38,0:30:27.50,EN,,0,0,0,,And now I'm going to do a complicated thing here, which is the general case. Dialogue: 0,0:30:29.98,0:30:34.80,EN,,0,0,0,,The expression is made out of two parts: a left and a right half, in general. Dialogue: 0,0:30:35.45,0:30:38.81,EN,,0,0,0,,Anything that's complicated is made out of two pieces in a Lisp system. Dialogue: 0,0:30:40.03,0:30:41.23,EN,,0,0,0,,Well, now what do we have here? Dialogue: 0,0:30:41.88,0:30:48.84,EN,,0,0,0,,I'm going to match the car's of the two expressions against each other with respect to the dictionary I already have, Dialogue: 0,0:30:50.30,0:30:53.12,EN,,0,0,0,,producing a dictionary as its value, Dialogue: 0,0:30:54.14,0:30:57.26,EN,,0,0,0,,which I will then use for matching the cdr's against each other. Dialogue: 0,0:30:58.51,0:31:02.09,EN,,0,0,0,,So that's how the dictionary travels, threads the entire structure. Dialogue: 0,0:31:03.66,0:31:07.53,EN,,0,0,0,,And then the result of that is the dictionary for the match of the car and the cdr, Dialogue: 0,0:31:10.12,0:31:12.41,EN,,0,0,0,,and that's what's going to be returned as a value. Dialogue: 0,0:31:13.61,0:31:15.84,EN,,0,0,0,,Now, at any point, a match might fail. Dialogue: 0,0:31:16.62,0:31:18.20,EN,,0,0,0,,It may be the case, for example, Dialogue: 0,0:31:18.36,0:31:27.18,EN,,0,0,0,,if we go back and look at an expression that doesn't quite match, like supposing this was a 4. Dialogue: 0,0:31:29.13,0:31:34.81,EN,,0,0,0,,Well, now these two don't match any more, because the x that had to be -- Dialogue: 0,0:31:34.93,0:31:37.34,EN,,0,0,0,,sorry, the y that had to be x here Dialogue: 0,0:31:37.82,0:31:40.12,EN,,0,0,0,,and this y has to be 4. Dialogue: 0,0:31:40.53,0:31:43.52,EN,,0,0,0,,But x and 4 were not the same object syntactically. Dialogue: 0,0:31:44.59,0:31:48.81,EN,,0,0,0,,So this wouldn't match, and that would be rejected sometimes, so matches may fail. Dialogue: 0,0:31:50.19,0:31:56.08,EN,,0,0,0,,Now, of course, because this matcher takes the dictionary from the previous match as input, Dialogue: 0,0:31:56.52,0:31:58.28,EN,,0,0,0,,it must be able to propagate the failures. Dialogue: 0,0:31:58.57,0:32:01.04,EN,,0,0,0,,And so that's what the first clause of this conditional does. Dialogue: 0,0:32:03.61,0:32:08.19,EN,,0,0,0,,It's also true that if it turned out that the pattern was not atomic-- Dialogue: 0,0:32:08.50,0:32:11.45,EN,,0,0,0,,see, if the pattern was atomic, I'd go into this stuff, which we haven't looked at yet. Dialogue: 0,0:32:12.17,0:32:13.56,EN,,0,0,0,,But if the pattern is not atomic Dialogue: 0,0:32:15.05,0:32:19.23,EN,,0,0,0,,and the expression is atomic-- it's not made out of pieces-- Dialogue: 0,0:32:20.14,0:32:22.65,EN,,0,0,0,,then that must be a failure, and so we go over here. Dialogue: 0,0:32:23.64,0:32:30.78,EN,,0,0,0,,If the pattern is not atomic and the pattern is not a pattern variable--I have to remind myself of that-- then we go over here. Dialogue: 0,0:32:30.96,0:32:32.51,EN,,0,0,0,,So that's way, failures may occur. Dialogue: 0,0:32:35.26,0:32:39.12,EN,,0,0,0,,OK, so now let's look at the insides of this thing. Dialogue: 0,0:32:39.84,0:32:42.93,EN,,0,0,0,,Well, the first place to look is what happens if I have an atomic pattern? Dialogue: 0,0:32:42.93,0:32:43.90,EN,,0,0,0,,That's very simple. Dialogue: 0,0:32:43.90,0:32:46.50,EN,,0,0,0,,A pattern that's not made out of any pieces: foo. Dialogue: 0,0:32:47.37,0:32:48.54,EN,,0,0,0,,That's a nice atomic pattern. Dialogue: 0,0:32:49.16,0:32:51.24,EN,,0,0,0,,Well, here's what we see. Dialogue: 0,0:32:52.08,0:32:55.82,EN,,0,0,0,,If the pattern is atomic, then if the expression is atomic, Dialogue: 0,0:32:56.80,0:33:01.85,EN,,0,0,0,,then if they are the same thing, then the dictionary I get is the same one as I had before. Dialogue: 0,0:33:03.08,0:33:04.00,EN,,0,0,0,,Nothing's changed. Dialogue: 0,0:33:04.60,0:33:10.33,EN,,0,0,0,,It's just that I matched plus against plus, asterisk against asterisk, x against x. Dialogue: 0,0:33:11.42,0:33:12.33,EN,,0,0,0,,That's all fine. Dialogue: 0,0:33:13.07,0:33:16.81,EN,,0,0,0,,However, if the pattern is not the one which is the expression, Dialogue: 0,0:33:17.32,0:33:21.36,EN,,0,0,0,,if I have two separate atomic objects, then it was matching plus against asterisk, Dialogue: 0,0:33:22.44,0:33:23.40,EN,,0,0,0,,which case I fail. Dialogue: 0,0:33:25.60,0:33:34.56,EN,,0,0,0,,Or if it turns out that the pattern is atomic but the expression is complicated, it's not atomic, then I get a failure. Dialogue: 0,0:33:37.40,0:33:38.24,EN,,0,0,0,,That's very simple. Dialogue: 0,0:33:38.81,0:33:43.61,EN,,0,0,0,,Now, what about the various kinds of pattern variables? Dialogue: 0,0:33:44.09,0:33:46.54,EN,,0,0,0,,We had three kinds. I give them the names. Dialogue: 0,0:33:47.39,0:33:52.03,EN,,0,0,0,,They're arbitrary constants, arbitrary variables, and arbitrary expressions. Dialogue: 0,0:33:53.82,0:34:00.14,EN,,0,0,0,,A question mark x is an arbitrary expression. Dialogue: 0,0:34:01.18,0:34:04.54,EN,,0,0,0,,A question mark cx is an arbitrary constant, Dialogue: 0,0:34:04.73,0:34:07.29,EN,,0,0,0,,and a question mark vx is an arbitrary variable. Dialogue: 0,0:34:08.96,0:34:09.79,EN,,0,0,0,,Well, what do we do here? Dialogue: 0,0:34:10.51,0:34:16.94,EN,,0,0,0,,Looking at this, we see that if I have an arbitrary constant, if the pattern is an arbitrary constant, Dialogue: 0,0:34:17.53,0:34:20.57,EN,,0,0,0,,then it had better be the case that the expression had better be a constant. Dialogue: 0,0:34:21.48,0:34:23.53,EN,,0,0,0,,If the expression is not a constant, then that match fails. Dialogue: 0,0:34:23.83,0:34:27.50,EN,,0,0,0,,If it is a constant, however, then I wish to extend the dictionary. Dialogue: 0,0:34:27.50,0:34:29.69,EN,,0,0,0,,I wish to extend the dictionary Dialogue: 0,0:34:30.70,0:34:37.76,EN,,0,0,0,,with that pattern being remembered to be that expression using the old dictionary as a starting point. Dialogue: 0,0:34:41.16,0:34:42.75,EN,,0,0,0,,So really, for arbitrary variables, Dialogue: 0,0:34:43.72,0:34:47.46,EN,,0,0,0,,I have to check first if the expression is a variable by matching against. Dialogue: 0,0:34:47.46,0:34:50.09,EN,,0,0,0,,If so, it's worth extending the dictionary Dialogue: 0,0:34:50.38,0:34:54.65,EN,,0,0,0,,so the pattern is remembered to be matched against that expression, given the original dictionary, Dialogue: 0,0:34:55.28,0:34:56.70,EN,,0,0,0,,and this makes a new dictionary. Dialogue: 0,0:34:58.88,0:35:04.16,EN,,0,0,0,,Now, it has to check. There's a sorts of failure inside extend dictionary, which is that-- Dialogue: 0,0:35:04.16,0:35:07.50,EN,,0,0,0,,if one of these pattern variables already has a value Dialogue: 0,0:35:09.23,0:35:16.17,EN,,0,0,0,,and I'm trying to match the thing against something else which is not equivalent to the one that I've already matched it against once, Dialogue: 0,0:35:16.43,0:35:18.36,EN,,0,0,0,,then a failure will come flying out of here, too. Dialogue: 0,0:35:20.16,0:35:21.56,EN,,0,0,0,,And I will see that some time. Dialogue: 0,0:35:22.91,0:35:29.36,EN,,0,0,0,,And finally, an expression does not have to check anything syntactic about the expression that's being matched, Dialogue: 0,0:35:30.11,0:35:32.20,EN,,0,0,0,,so all it does is it's an extension of the dictionary. Dialogue: 0,0:35:34.76,0:35:38.32,EN,,0,0,0,,So you've just seen a complete, very simple matcher. Dialogue: 0,0:35:39.28,0:35:41.37,EN,,0,0,0,,Now, one of the things that's rather remarkable about this Dialogue: 0,0:35:41.66,0:35:45.12,EN,,0,0,0,,is people pay an awful lot of money these days for someone to make Dialogue: 0,0:35:45.46,0:35:47.52,EN,,0,0,0,,a, quote, AI expert system Dialogue: 0,0:35:48.40,0:35:52.03,EN,,0,0,0,,that has nothing more in it than a matcher and maybe an instantiater like this. Dialogue: 0,0:35:53.56,0:35:56.94,EN,,0,0,0,,But it's very easy to do, and now, of course, you can start up a little start-up company Dialogue: 0,0:35:57.42,0:36:01.72,EN,,0,0,0,,and make a couple of megabucks in the next week taking some people for a ride. Dialogue: 0,0:36:03.79,0:36:08.57,EN,,0,0,0,,I mean, 20 years ago, this was remarkable, this kind of program. Dialogue: 0,0:36:09.74,0:36:12.81,EN,,0,0,0,,But now, this is sort of easy. You can teach it to freshmen. Dialogue: 0,0:36:13.63,0:36:15.47,EN,,0,0,0,,Well, now there's an instantiater as well. Dialogue: 0,0:36:20.22,0:36:23.07,EN,,0,0,0,,The problem is they're all going off and making more money than I do. Alright? Dialogue: 0,0:36:24.97,0:36:26.59,EN,,0,0,0,,But that's always been true of universities. Dialogue: 0,0:36:27.10,0:36:39.42,EN,,0,0,0,,As expression, the purpose of the instantiater is to make expressions given a dictionary and a skeleton. Dialogue: 0,0:36:44.35,0:36:45.69,EN,,0,0,0,,And that's not very hard at all. Dialogue: 0,0:36:46.60,0:36:53.36,EN,,0,0,0,,We'll see that very simply in the next, the next slide here. Dialogue: 0,0:36:53.88,0:36:59.29,EN,,0,0,0,,To instantiate a skeleton, given a particular dictionary-- oh, this is easy. Dialogue: 0,0:36:59.68,0:37:03.29,EN,,0,0,0,,We're going to do a recursive tree walk over the skeleton. Dialogue: 0,0:37:04.08,0:37:08.33,EN,,0,0,0,,And for everything which is a skeleton variable-- I don't know, call it a skeleton evaluation. Dialogue: 0,0:37:08.41,0:37:11.42,EN,,0,0,0,,That's the name and the abstract syntax that I give it in this program: Dialogue: 0,0:37:11.60,0:37:16.46,EN,,0,0,0,,a skeleton evaluation, a thing beginning with a colon in the rules. Dialogue: 0,0:37:18.25,0:37:24.30,EN,,0,0,0,,For anything of that case, I'm going to look up the answer in the dictionary, and we'll worry about that in a second. Dialogue: 0,0:37:24.30,0:37:25.61,EN,,0,0,0,,Let's look at this as a whole. Dialogue: 0,0:37:27.77,0:37:31.80,EN,,0,0,0,,Here, I have-- I'm going to instantiate a skeleton, given a dictionary. Dialogue: 0,0:37:32.75,0:37:37.15,EN,,0,0,0,,Well, I'm going to define some internal loop right there, Dialogue: 0,0:37:38.14,0:37:39.85,EN,,0,0,0,,and it's going to do something very simple. Dialogue: 0,0:37:40.17,0:37:43.50,EN,,0,0,0,,Even if a skeleton--even if a skeleton is simple and atomic, Dialogue: 0,0:37:44.60,0:37:47.45,EN,,0,0,0,,in which case it's nothing more than giving the skeleton back as an answer, Dialogue: 0,0:37:48.84,0:37:51.87,EN,,0,0,0,,or in the general case, it's complicated, Dialogue: 0,0:37:52.60,0:37:59.40,EN,,0,0,0,,in which case I'm going to make up the expression which is the result of instantiating-- Dialogue: 0,0:37:59.40,0:38:04.25,EN,,0,0,0,,calling this loop recursively-- instantiating the car of the skeleton and the cdr. Dialogue: 0,0:38:04.89,0:38:06.24,EN,,0,0,0,,So here is a recursive tree walk. Dialogue: 0,0:38:08.41,0:38:14.36,EN,,0,0,0,,However, if it turns out to be a skeleton evaluation, a colon expression in the skeleton, Dialogue: 0,0:38:14.96,0:38:22.64,EN,,0,0,0,,then what I'm going to do is find the expression that's in the colon-- the CADR in this case. Dialogue: 0,0:38:22.81,0:38:26.25,EN,,0,0,0,,It's a piece of abstract syntax here, so I can change my representation of rules. Dialogue: 0,0:38:27.52,0:38:32.73,EN,,0,0,0,,I'm going to evaluate that relative to this dictionary, whatever evaluation means. Dialogue: 0,0:38:32.90,0:38:34.65,EN,,0,0,0,,We'll find out a lot about that sometime. Dialogue: 0,0:38:36.12,0:38:38.35,EN,,0,0,0,,And the result of that is my answer. Dialogue: 0,0:38:39.68,0:38:43.66,EN,,0,0,0,,so. I start up this loop-- here's my initialization-- by calling it with the whole skeleton, Dialogue: 0,0:38:44.44,0:38:47.04,EN,,0,0,0,,and this will just do a recursive decomposition into pieces. Dialogue: 0,0:38:49.63,0:38:56.48,EN,,0,0,0,,Now, one more little bit of detail is what happens inside evaluate? Dialogue: 0,0:38:57.18,0:38:59.07,EN,,0,0,0,,I can't tell you that in great detail. Dialogue: 0,0:38:59.98,0:39:01.34,EN,,0,0,0,,I'll tell you a little bit of it. Dialogue: 0,0:39:01.56,0:39:03.74,EN,,0,0,0,,Later, we're going to see--look into this in much more detail. Dialogue: 0,0:39:05.29,0:39:10.81,EN,,0,0,0,,To evaluate some form, some expression with respect to a dictionary, Dialogue: 0,0:39:11.90,0:39:14.17,EN,,0,0,0,,if the expression is an atomic object, well, Dialogue: 0,0:39:15.04,0:39:16.22,EN,,0,0,0,,I'm going to go look it up. Dialogue: 0,0:39:18.60,0:39:19.87,EN,,0,0,0,,Nothing very exciting there. Dialogue: 0,0:39:20.57,0:39:23.66,EN,,0,0,0,,Otherwise, I'm going to do something complicated here, Dialogue: 0,0:39:23.83,0:39:28.28,EN,,0,0,0,,which is I'm going to apply a procedure which is the result of looking up the operator part Dialogue: 0,0:39:29.44,0:39:31.68,EN,,0,0,0,,in something that we're going to find out about someday. Dialogue: 0,0:39:32.14,0:39:34.20,EN,,0,0,0,,I want you realize you're seeing magic now. Dialogue: 0,0:39:34.67,0:39:38.72,EN,,0,0,0,,This magic will become clear very soon, but not today. Dialogue: 0,0:39:40.00,0:39:46.51,EN,,0,0,0,,Then I'm looking at--looking up all the pieces, all the arguments to that in the dictionary. Dialogue: 0,0:39:48.56,0:39:50.88,EN,,0,0,0,,So I don't want you to look at this in detail. Dialogue: 0,0:39:51.44,0:39:53.44,EN,,0,0,0,,I want you to see that there's more going on here, Dialogue: 0,0:39:54.17,0:39:56.75,EN,,0,0,0,,and we're going to see more about this. Dialogue: 0,0:39:59.04,0:40:00.88,EN,,0,0,0,,But it's-- the magic is going to stop. Dialogue: 0,0:40:02.57,0:40:06.96,EN,,0,0,0,,This part has to do with Lisp, and it's the end of that. Dialogue: 0,0:40:10.25,0:40:13.56,EN,,0,0,0,,OK, so now we know about matching and instantiation. Dialogue: 0,0:40:15.05,0:40:16.60,EN,,0,0,0,,Are there any questions for this segment? Dialogue: 0,0:40:28.10,0:40:29.80,EN,,0,0,0,,AUDIENCE: I have a question. Dialogue: 0,0:40:29.80,0:40:30.43,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,0:40:30.43,0:40:32.56,EN,,0,0,0,,AUDIENCE: Is it possible to bring up a previous slide? Dialogue: 0,0:40:33.60,0:40:35.56,EN,,0,0,0,,It's about this define match pattern. Dialogue: 0,0:40:36.16,0:40:40.76,EN,,0,0,0,,PROFESSOR: Yes. You'd like to see the overall slide define match pattern. Dialogue: 0,0:40:40.76,0:40:43.06,EN,,0,0,0,,Can somebody put up the -- no, the overhead. Dialogue: 0,0:40:43.06,0:40:45.16,EN,,0,0,0,,That's the biggest scale one. Dialogue: 0,0:40:45.31,0:40:46.40,EN,,0,0,0,,What part would you like to see? Dialogue: 0,0:40:46.76,0:40:49.96,EN,,0,0,0,,AUDIENCE: Well, the top would be fine. Dialogue: 0,0:40:49.96,0:40:53.76,EN,,0,0,0,,Any of the parts where you're passing failed. Dialogue: 0,0:40:54.52,0:40:55.21,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,0:40:55.64,0:40:59.33,EN,,0,0,0,,AUDIENCE: The idea is to pass failed back to the dictionary; is that right? Dialogue: 0,0:40:59.33,0:41:04.25,EN,,0,0,0,,PROFESSOR: The dictionary is the answer to a match, right? Dialogue: 0,0:41:05.16,0:41:09.80,EN,,0,0,0,,And it is either some mapping Dialogue: 0,0:41:11.07,0:41:14.03,EN,,0,0,0,,or there's no match. It doesn't match. Dialogue: 0,0:41:14.46,0:41:14.97,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,0:41:15.26,0:41:17.83,EN,,0,0,0,,PROFESSOR: So what you're seeing over here is, in fact, Dialogue: 0,0:41:17.83,0:41:22.60,EN,,0,0,0,,because the fact that a match may have another match pass in the dictionary, Dialogue: 0,0:41:22.80,0:41:24.65,EN,,0,0,0,,as you see in the general case down here. Dialogue: 0,0:41:25.12,0:41:27.93,EN,,0,0,0,,Here's the general case where a match passes another match to the dictionary. Dialogue: 0,0:41:28.14,0:41:34.16,EN,,0,0,0,,When I match the cdr's, I match them in the dictionary that is resulting from matching the car's. Dialogue: 0,0:41:36.06,0:41:37.08,EN,,0,0,0,,OK, that's what I have here. Dialogue: 0,0:41:37.29,0:41:40.30,EN,,0,0,0,,So because of that, if the match of the car's fails, Dialogue: 0,0:41:41.23,0:41:45.44,EN,,0,0,0,,then it may be necessary that the match of the cdr's propagates that failure, Dialogue: 0,0:41:45.95,0:41:46.96,EN,,0,0,0,,and that's what the first line is. Dialogue: 0,0:41:48.26,0:41:51.73,EN,,0,0,0,,AUDIENCE: OK, well, I'm still unclear what matches-- Dialogue: 0,0:41:51.73,0:41:54.24,EN,,0,0,0,,what comes out of one instance of the match? Dialogue: 0,0:41:54.73,0:41:56.00,EN,,0,0,0,,PROFESSOR: One of two possibilities. Dialogue: 0,0:41:56.33,0:41:59.15,EN,,0,0,0,,Either the symbol failed, which means there is no match. Dialogue: 0,0:41:59.53,0:41:59.93,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,0:41:59.93,0:42:03.87,EN,,0,0,0,,PROFESSOR: Or some mapping, which is an abstract thing right now, Dialogue: 0,0:42:04.16,0:42:05.68,EN,,0,0,0,,and you should know about the structure of it, Dialogue: 0,0:42:06.49,0:42:13.96,EN,,0,0,0,,which relates the pattern variables to their values as picked up in the match. Dialogue: 0,0:42:14.68,0:42:16.70,EN,,0,0,0,,AUDIENCE: OK, so it is-- Dialogue: 0,0:42:16.80,0:42:18.57,EN,,0,0,0,,PROFESSOR: That's constructed by extend dictionary. Dialogue: 0,0:42:18.80,0:42:28.54,EN,,0,0,0,,AUDIENCE: So the recursive nature brings about the fact that if ever a failed gets passed out of any calling of match, Dialogue: 0,0:42:28.68,0:42:30.30,EN,,0,0,0,,then the first condition will pick it up-- Dialogue: 0,0:42:30.40,0:42:33.56,EN,,0,0,0,,PROFESSOR: And just propagate it along without any further ado, right. Dialogue: 0,0:42:33.56,0:42:34.83,EN,,0,0,0,,AUDIENCE: Oh, right. Dialogue: 0,0:42:35.50,0:42:37.36,EN,,0,0,0,,PROFESSOR: That's just the fastest way to get that failure out of there. Dialogue: 0,0:42:42.86,0:42:43.60,EN,,0,0,0,,Yes. Dialogue: 0,0:42:43.84,0:42:47.23,EN,,0,0,0,,AUDIENCE: If I don't fail, that means that I've matched a pattern, Dialogue: 0,0:42:47.84,0:42:53.00,EN,,0,0,0,,and I run the procedure extend dict and then pass in the pattern in the expression. Dialogue: 0,0:42:55.21,0:42:58.43,EN,,0,0,0,,But the substitution will not be made at that point; is that right? Dialogue: 0,0:42:58.43,0:42:59.03,EN,,0,0,0,,I'm just-- Dialogue: 0,0:42:59.03,0:42:59.46,EN,,0,0,0,,PROFESSOR: No, no. Dialogue: 0,0:42:59.46,0:43:02.40,EN,,0,0,0,,There's no substitution being there because there's no skeleton to be substituted in. Dialogue: 0,0:43:02.40,0:43:03.06,EN,,0,0,0,,AUDIENCE: Right. So Dialogue: 0,0:43:03.06,0:43:07.16,EN,,0,0,0,,PROFESSOR: All you've got there is we're making up the dictionary for later substitution. Dialogue: 0,0:43:08.25,0:43:12.43,EN,,0,0,0,,AUDIENCE: And what would the dictionary look like? Is it ordered pairs? Dialogue: 0,0:43:12.72,0:43:15.96,EN,,0,0,0,,PROFESSOR: Ahhhhh, That's--that's not told to you. Dialogue: 0,0:43:15.96,0:43:16.89,EN,,0,0,0,,We're being abstract. Dialogue: 0,0:43:17.06,0:43:17.56,EN,,0,0,0,,AUDIENCE: OK. Dialogue: 0,0:43:17.56,0:43:18.90,EN,,0,0,0,,PROFESSOR: Why do you want to know? Dialogue: 0,0:43:18.90,0:43:21.64,EN,,0,0,0,,What it is, it's a function. It's a function. Dialogue: 0,0:43:21.69,0:43:22.33,EN,,0,0,0,,AUDIENCE: Well, the reason I want to know is-- Dialogue: 0,0:43:22.33,0:43:24.17,EN,,0,0,0,,PROFESSOR: A function abstractly is a set of ordered pairs. Dialogue: 0,0:43:25.12,0:43:28.44,EN,,0,0,0,,It could be implemented as a set of list pairs. Dialogue: 0,0:43:29.06,0:43:32.43,EN,,0,0,0,,It could be implemented as some fancy table mechanism. Dialogue: 0,0:43:32.56,0:43:34.16,EN,,0,0,0,,It could be implemented as a function. Dialogue: 0,0:43:35.80,0:43:37.40,EN,,0,0,0,,And somehow, I'm building up a function. Dialogue: 0,0:43:39.02,0:43:39.87,EN,,0,0,0,,But I'm not telling you. Dialogue: 0,0:43:40.84,0:43:43.08,EN,,0,0,0,,That's up to George, who's going to build that later. Dialogue: 0,0:43:49.56,0:43:52.06,EN,,0,0,0,,I know you really badly want to write concrete things. Dialogue: 0,0:43:52.36,0:43:54.19,EN,,0,0,0,,I'm not going to let you do that. Dialogue: 0,0:43:54.43,0:43:59.23,EN,,0,0,0,,AUDIENCE: Well, let me at least ask, what is the important information there that's being passed to extend dict? Dialogue: 0,0:43:59.74,0:44:02.08,EN,,0,0,0,,I want to pass the pattern I found-- Dialogue: 0,0:44:02.73,0:44:04.83,EN,,0,0,0,,PROFESSOR: Yes. The pattern that's matched against the expression. Dialogue: 0,0:44:04.83,0:44:09.30,EN,,0,0,0,,You want to have the pattern, which happens to be in those cases pattern variables, right? Dialogue: 0,0:44:09.85,0:44:12.89,EN,,0,0,0,,All of those three cases for extend dict are pattern variables. Dialogue: 0,0:44:13.20,0:44:13.50,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,0:44:14.48,0:44:18.75,EN,,0,0,0,,PROFESSOR: So you have a pattern variable that is to be given a value in a dictionary. Dialogue: 0,0:44:19.45,0:44:22.11,EN,,0,0,0,,PROFESSOR: The value is the expression that it matched against. Dialogue: 0,0:44:23.31,0:44:29.63,EN,,0,0,0,,The dictionary is the set of things I've already figured out that I have memorized or learned. Dialogue: 0,0:44:30.54,0:44:34.41,EN,,0,0,0,,And I am going to make a new dictionary, which is extended from the original one Dialogue: 0,0:44:35.12,0:44:38.35,EN,,0,0,0,,by having that pattern variable have a value with the new dictionary. Dialogue: 0,0:44:39.98,0:44:43.73,EN,,0,0,0,,AUDIENCE: I guess what I don't understand is why can't the substitution be made right as soon as you find-- Dialogue: 0,0:44:43.73,0:44:44.80,EN,,0,0,0,,PROFESSOR: How do I know what I'm going to substitute? Dialogue: 0,0:44:44.81,0:44:46.62,EN,,0,0,0,,I don't know anything about this skeleton. Dialogue: 0,0:44:47.58,0:44:49.66,EN,,0,0,0,,This pattern, this matcher is an independent unit. Dialogue: 0,0:44:49.66,0:44:51.00,EN,,0,0,0,,AUDIENCE: Oh, I see. OK. Dialogue: 0,0:44:51.00,0:44:51.50,EN,,0,0,0,,PROFESSOR: Right? Dialogue: 0,0:44:51.50,0:44:51.90,EN,,0,0,0,,AUDIENCE: Yeah. Dialogue: 0,0:44:51.90,0:44:57.23,EN,,0,0,0,,PROFESSOR: I take the matcher. I apply the matcher. If it matches, then it was worth doing instantiation. Dialogue: 0,0:44:58.20,0:44:59.50,EN,,0,0,0,,AUDIENCE: OK, good. Dialogue: 0,0:45:00.54,0:45:03.88,EN,,0,0,0,,AUDIENCE: Can you just do that answer again using that example on the board? Dialogue: 0,0:45:04.89,0:45:06.93,EN,,0,0,0,,You know, what you just passed back to the matcher. Dialogue: 0,0:45:06.93,0:45:08.00,EN,,0,0,0,,PROFESSOR: Oh yes. OK, yes. Dialogue: 0,0:45:08.26,0:45:09.74,EN,,0,0,0,,You're looking at this example. Dialogue: 0,0:45:10.67,0:45:15.45,EN,,0,0,0,,At this point when I'm traversing this structure, I get to here: x. Dialogue: 0,0:45:16.67,0:45:20.54,EN,,0,0,0,,I have some dictionary, presumably an empty dictionary at this point if this is the whole expression. Dialogue: 0,0:45:21.56,0:45:25.36,EN,,0,0,0,,So I have an empty dictionary, and I've matched x against 3. Dialogue: 0,0:45:26.62,0:45:33.60,EN,,0,0,0,,So now, after this point,the dictionary contains x is 3, OK? Dialogue: 0,0:45:33.64,0:45:36.09,EN,,0,0,0,,Now, I continue walking along here. I see y. Dialogue: 0,0:45:36.89,0:45:39.20,EN,,0,0,0,,Now, this is a particular x, a pattern x. Dialogue: 0,0:45:39.79,0:45:41.37,EN,,0,0,0,,I see y, a pattern y. Dialogue: 0,0:45:42.17,0:45:47.74,EN,,0,0,0,,The dictionary says, oh yes, the pattern y is the symbol x Dialogue: 0,0:45:48.99,0:45:51.20,EN,,0,0,0,,because I've gota match there. Dialogue: 0,0:45:52.43,0:45:54.52,EN,,0,0,0,,So the dictionary now contains at this point two entries. Dialogue: 0,0:45:55.45,0:45:59.90,EN,,0,0,0,,The pattern x is 3, and the pattern y is the expression x. Dialogue: 0,0:46:01.95,0:46:04.11,EN,,0,0,0,,Now, I get that, I can walk along further. Dialogue: 0,0:46:04.23,0:46:07.45,EN,,0,0,0,,I say, oh, pattern y also wants to be 4. Dialogue: 0,0:46:08.06,0:46:10.65,EN,,0,0,0,,But that isn't possible, producing a failure. Dialogue: 0,0:46:14.30,0:46:15.48,EN,,0,0,0,,Thank you. Let's take a break. Dialogue: 0,0:46:16.76,0:46:25.02,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:46:25.07,0:46:27.45,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:46:27.47,0:46:30.00,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:46:48.19,0:46:54.75,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:46:55.20,0:46:58.04,Declare,,0,0,0,,{\an2\fad(500,500)}Pattern-matching: Rule-based Substitution Dialogue: 0,0:47:02.38,0:47:05.68,EN,,0,0,0,,OK, you're seeing your first very big and hairy program. Dialogue: 0,0:47:07.34,0:47:09.90,EN,,0,0,0,,Now, of course, one of the goals of this subject Dialogue: 0,0:47:09.90,0:47:12.97,EN,,0,0,0,,is to get you to be able to read something like this and not be afraid of it. Dialogue: 0,0:47:13.76,0:47:16.33,EN,,0,0,0,,This one's only about four pages of code. Dialogue: 0,0:47:17.08,0:47:19.23,EN,,0,0,0,,By the end of the subject, I hope a 50-page program Dialogue: 0,0:47:20.27,0:47:21.80,EN,,0,0,0,,will not look particularly frightening. Dialogue: 0,0:47:22.97,0:47:28.20,EN,,0,0,0,,But I don't expect-- and I don't want you to think that I expect you to be getting it as it's coming out. Dialogue: 0,0:47:29.20,0:47:31.70,EN,,0,0,0,,You're supposed to feel the flavor of this, OK? Dialogue: 0,0:47:31.70,0:47:34.83,EN,,0,0,0,,And then you're supposed to think about it because it is a big program. Dialogue: 0,0:47:35.32,0:47:38.92,EN,,0,0,0,,There's a lot of stuff inside this program. Dialogue: 0,0:47:41.24,0:47:46.03,EN,,0,0,0,,Now, I've told you about the language we're implementing, the pattern match substitution language. Dialogue: 0,0:47:46.81,0:47:47.64,EN,,0,0,0,,I showed you some rules. Dialogue: 0,0:47:48.36,0:47:51.24,EN,,0,0,0,,And I've told you about matching and instantiation, Dialogue: 0,0:47:51.55,0:47:53.32,EN,,0,0,0,,which are the two halves of how a rule works. Dialogue: 0,0:47:54.24,0:47:56.35,EN,,0,0,0,,Now we have to understand the control structure Dialogue: 0,0:47:56.86,0:48:00.32,EN,,0,0,0,,by which the rules are applied to the expressions Dialogue: 0,0:48:01.08,0:48:03.84,EN,,0,0,0,,so as to do algebraic simplification. Dialogue: 0,0:48:06.92,0:48:09.58,EN,,0,0,0,,Now, that's also a big complicated mess. Dialogue: 0,0:48:12.09,0:48:19.48,EN,,0,0,0,,The problem is that there is a variety of interlocking, interwoven loops, if you will, involved in this. Dialogue: 0,0:48:20.24,0:48:26.99,EN,,0,0,0,,For one thing, I have to apply-- I have to examine every subexpression of my expression that I'm trying to simplify. Dialogue: 0,0:48:29.00,0:48:29.93,EN,,0,0,0,,That we know how to do. Dialogue: 0,0:48:29.93,0:48:36.24,EN,,0,0,0,,It's a car cdr recursion of some sort, or something like that, and some sort of tree walk. Dialogue: 0,0:48:37.44,0:48:38.59,EN,,0,0,0,,And that's going to be happening. Dialogue: 0,0:48:38.84,0:48:42.46,EN,,0,0,0,,Now, for every such place, every node that I get to Dialogue: 0,0:48:43.47,0:48:48.76,EN,,0,0,0,,in doing my traversal of the expression I'm trying to simplify, Dialogue: 0,0:48:49.20,0:48:51.07,EN,,0,0,0,,I want to apply all of the rules. Dialogue: 0,0:48:53.42,0:48:55.08,EN,,0,0,0,,Every rule is going to look at every node. Dialogue: 0,0:48:56.00,0:48:57.92,EN,,0,0,0,,I'm going to rotate the rules around. Dialogue: 0,0:49:01.66,0:49:05.48,EN,,0,0,0,,Now, either a rule will or will not match. Dialogue: 0,0:49:07.50,0:49:10.62,EN,,0,0,0,,If the rule does not match, then it's not very interesting. Dialogue: 0,0:49:12.28,0:49:19.34,EN,,0,0,0,,If the rule does match, then I'm going to replace that node in the expression by an alternate expression. Dialogue: 0,0:49:20.08,0:49:22.89,EN,,0,0,0,,I'm actually going to make a new expression, which contains-- Dialogue: 0,0:49:23.55,0:49:28.65,EN,,0,0,0,,everything contains that new value, the result of substituting into the skeleton, Dialogue: 0,0:49:29.21,0:49:31.92,EN,,0,0,0,,instantiating the skeleton for that rule at this level. Dialogue: 0,0:49:32.72,0:49:37.37,EN,,0,0,0,,But no one knows whether that thing that I instantiated there is in simplified form. Dialogue: 0,0:49:38.75,0:49:43.82,EN,,0,0,0,,So we're going to have to simplify that, somehow to call the simplifier on the thing that I just constructed. Dialogue: 0,0:49:46.12,0:49:50.36,EN,,0,0,0,,And then when that's done, then I sort of can build that into the expression I want as my answer. Dialogue: 0,0:49:51.80,0:49:57.45,EN,,0,0,0,,Now, there is a basic idea here, which I will call a garbage- in, garbage-out simplifier. Dialogue: 0,0:50:01.47,0:50:02.75,EN,,0,0,0,,It's a kind of recursive simplifier. Dialogue: 0,0:50:03.58,0:50:08.84,EN,,0,0,0,,And what happens is the way simplify something is that simple objects like variables are simple. Dialogue: 0,0:50:10.78,0:50:13.28,EN,,0,0,0,,Compound objects, well, I don't know. Dialogue: 0,0:50:14.09,0:50:16.56,EN,,0,0,0,,What I'm going to do is I'm going to build up from simple objects, Dialogue: 0,0:50:16.86,0:50:21.23,EN,,0,0,0,,trying to make simple things by assuming that the pieces they're made out of are simple. Dialogue: 0,0:50:24.60,0:50:25.61,EN,,0,0,0,,That's what's happening here. Dialogue: 0,0:50:27.82,0:50:33.12,EN,,0,0,0,,Well, now, if we look at the first slide-- no, overhead, overhead. Dialogue: 0,0:50:33.88,0:50:37.13,EN,,0,0,0,,If we look at the overhead, we see a very complicated program like we saw before for the matcher, Dialogue: 0,0:50:37.53,0:50:39.95,EN,,0,0,0,,so complicated that you can't read it like that. Dialogue: 0,0:50:41.92,0:50:43.61,EN,,0,0,0,,I just want you to get the feel of the shape of it, Dialogue: 0,0:50:44.44,0:50:50.01,EN,,0,0,0,,and the shape of it is that this program has various subprograms in it. Dialogue: 0,0:50:52.11,0:50:57.56,EN,,0,0,0,,One of them--this part is the part for traversing the expression, Dialogue: 0,0:50:58.97,0:51:01.36,EN,,0,0,0,,and this part is the part for trying rules. Dialogue: 0,0:51:02.52,0:51:05.60,EN,,0,0,0,,Now, of course, we can look at that in some more detail. Dialogue: 0,0:51:06.89,0:51:11.80,EN,,0,0,0,,Let's look at--let's look at the first transparency, right? Dialogue: 0,0:51:13.40,0:51:17.36,EN,,0,0,0,,The simplifier is made out of several parts. Dialogue: 0,0:51:17.96,0:51:22.92,EN,,0,0,0,,Now, remember at the very beginning, the simplifier is the thing which takes a rules-- a set of rules Dialogue: 0,0:51:23.92,0:51:27.20,EN,,0,0,0,,and produces a program which will simplify it relative to them. Dialogue: 0,0:51:30.04,0:51:32.60,EN,,0,0,0,,So here we have our simplifier. Dialogue: 0,0:51:33.48,0:51:34.81,EN,,0,0,0,,It takes a rule set. Dialogue: 0,0:51:36.16,0:51:38.68,EN,,0,0,0,,And in the context where that rule set is defined, Dialogue: 0,0:51:39.24,0:51:41.48,EN,,0,0,0,,there are various other definitions that are done here. Dialogue: 0,0:51:42.33,0:51:46.20,EN,,0,0,0,,And then the result of this simplifier procedure is, Dialogue: 0,0:51:46.41,0:51:50.80,EN,,0,0,0,,in fact, one of the procedures that was defined. Simplify-exp. Dialogue: 0,0:51:52.46,0:51:57.71,EN,,0,0,0,,What I'm returning as the value of calling the simplifier on a set of rules Dialogue: 0,0:51:58.17,0:52:03.21,EN,,0,0,0,,is a procedure the simplify exp procedure, which is defined in that context, Dialogue: 0,0:52:05.23,0:52:08.83,EN,,0,0,0,,which is a simplification procedure appropriate for using those set of rules. Dialogue: 0,0:52:15.04,0:52:15.96,EN,,0,0,0,,That's what I have there. Dialogue: 0,0:52:17.45,0:52:21.79,EN,,0,0,0,,Now, the first two of these procedures, this one and this one, Dialogue: 0,0:52:22.48,0:52:25.74,EN,,0,0,0,,are together going to be the recursive traversal of an expression. Dialogue: 0,0:52:26.97,0:52:30.20,EN,,0,0,0,,This one is the general simplification for any expression, Dialogue: 0,0:52:30.94,0:52:33.23,EN,,0,0,0,,and this is the thing which simplifies a list of parts of an expression. Dialogue: 0,0:52:35.53,0:52:36.08,EN,,0,0,0,,Nothing more. Dialogue: 0,0:52:37.04,0:52:39.90,EN,,0,0,0,,For each of those, we're going to do something complicated, which involves trying the rules. Dialogue: 0,0:52:40.32,0:52:41.71,EN,,0,0,0,,Now, we should look at the various parts. Dialogue: 0,0:52:45.76,0:52:48.08,EN,,0,0,0,,Well let's look first at the recursive traversal of an expression. Dialogue: 0,0:52:48.57,0:52:51.68,EN,,0,0,0,,And this is done in a sort of simple way. Dialogue: 0,0:52:54.28,0:52:57.93,EN,,0,0,0,,This is a little nest of recursive procedures. Dialogue: 0,0:52:59.42,0:53:01.77,EN,,0,0,0,,And what we have here are two procedures-- Dialogue: 0,0:53:02.59,0:53:05.20,EN,,0,0,0,,one for simplifying an expression, Dialogue: 0,0:53:06.11,0:53:08.16,EN,,0,0,0,,and one for simplifying parts of an expression. Dialogue: 0,0:53:09.44,0:53:10.97,EN,,0,0,0,,And the way this works is very simple. Dialogue: 0,0:53:12.12,0:53:16.86,EN,,0,0,0,,If the expression I'm trying to simplify is a compound expression, Dialogue: 0,0:53:17.04,0:53:18.32,EN,,0,0,0,,I'm going to simplify all the parts of it. Dialogue: 0,0:53:19.95,0:53:22.32,EN,,0,0,0,,And that's calling--that procedure, simplify parts, Dialogue: 0,0:53:22.33,0:53:25.74,EN,,0,0,0,,is going to make up a new expression with all the parts simplified, Dialogue: 0,0:53:26.00,0:53:28.64,EN,,0,0,0,,which I'm then going to try the rules on over here. Dialogue: 0,0:53:30.86,0:53:34.22,EN,,0,0,0,,If it turns out that the expression is not compound, if it's simple, Dialogue: 0,0:53:34.76,0:53:37.13,EN,,0,0,0,,like just a symbol or something like pi, Dialogue: 0,0:53:38.16,0:53:39.79,EN,,0,0,0,,then in any case, I'm going to try the rules on it Dialogue: 0,0:53:40.03,0:53:47.56,EN,,0,0,0,,because it might be that I want in my set of rules to expand pi to 3.14159265358979,dot, dot, dot. Dialogue: 0,0:53:48.46,0:53:49.08,EN,,0,0,0,,But I may not. Dialogue: 0,0:53:50.11,0:53:51.52,EN,,0,0,0,,But there is no reason not to do it. Dialogue: 0,0:53:52.75,0:53:57.53,EN,,0,0,0,,Now, if I want to simplify the parts, well, that's easy too. Dialogue: 0,0:53:58.99,0:54:02.88,EN,,0,0,0,,Either the expression is an empty one, there's no more parts, Dialogue: 0,0:54:03.71,0:54:05.08,EN,,0,0,0,,in which case I have the empty expression. Dialogue: 0,0:54:05.72,0:54:10.52,EN,,0,0,0,,Otherwise, I'm going to make a new expression by cons, Dialogue: 0,0:54:11.21,0:54:14.27,EN,,0,0,0,,which is the result of simplifying the first part of the expression, the car, Dialogue: 0,0:54:15.42,0:54:17.39,EN,,0,0,0,,and simplifying the rest of the expression, which is the cdr. Dialogue: 0,0:54:21.08,0:54:23.88,EN,,0,0,0,,Now, the reason why I'm showing you this sort of stuff this way Dialogue: 0,0:54:24.88,0:54:30.12,EN,,0,0,0,,is because I want you get the feeling for the various patterns that are very important when writing programs. Dialogue: 0,0:54:32.20,0:54:34.00,EN,,0,0,0,,And this could be written a different way. Dialogue: 0,0:54:34.00,0:54:36.99,EN,,0,0,0,,There's another way to write simplified expressions so there would be only one of them. Dialogue: 0,0:54:37.72,0:54:39.63,EN,,0,0,0,,There would only be one little procedure here. Dialogue: 0,0:54:39.63,0:54:42.36,EN,,0,0,0,,Let me just write that on the blackboard to give you a feeling for that. Dialogue: 0,0:54:49.71,0:54:51.90,EN,,0,0,0,,This is in another idiom, if you will. Dialogue: 0,0:54:59.30,0:55:03.13,EN,,0,0,0,,To simplify an expression called exp, what am I going to do? Dialogue: 0,0:55:03.21,0:55:10.14,EN,,0,0,0,,I'm going to try the rules on the following situation. Dialogue: 0,0:55:11.12,0:55:15.72,EN,,0,0,0,,If-- on the following expression-- compound, just like we had before. Dialogue: 0,0:55:21.52,0:55:24.27,EN,,0,0,0,,If the expression is compound, well, what am I going to do? Dialogue: 0,0:55:24.53,0:55:25.40,EN,,0,0,0,,I'm going to simplify all the parts. Dialogue: 0,0:55:26.01,0:55:27.80,EN,,0,0,0,,But I already have a cdr recursion, Dialogue: 0,0:55:30.25,0:55:33.18,EN,,0,0,0,,common pattern of usage, which has been captured as a high-order procedure. Dialogue: 0,0:55:34.09,0:55:34.46,EN,,0,0,0,,It's called map. Dialogue: 0,0:55:36.08,0:55:36.88,EN,,0,0,0,,So I'll just write that here. Dialogue: 0,0:55:37.16,0:55:48.03,EN,,0,0,0,,Map simplify the expression, all the parts of the expression. Dialogue: 0,0:55:49.00,0:55:54.59,EN,,0,0,0,,This says apply the simplification operation, which is this one, every part of the expression, Dialogue: 0,0:55:55.34,0:55:57.34,EN,,0,0,0,,and then that cons those up into a list. Dialogue: 0,0:56:00.92,0:56:04.38,EN,,0,0,0,,It's every element of the list which the expression is assumed to be made out of, Dialogue: 0,0:56:05.45,0:56:08.23,EN,,0,0,0,,and otherwise, I have the expression. Dialogue: 0,0:56:09.05,0:56:12.36,EN,,0,0,0,,So I don't need the helper procedure, simplify parts, Dialogue: 0,0:56:12.64,0:56:13.48,EN,,0,0,0,,because that's really this. Dialogue: 0,0:56:15.47,0:56:17.05,EN,,0,0,0,,So sometimes, you just write it this way. Dialogue: 0,0:56:17.84,0:56:18.70,EN,,0,0,0,,It doesn't matter very much. Dialogue: 0,0:56:21.16,0:56:26.27,EN,,0,0,0,,Well, now let's take a look at-- let's just look at how you try rules. Dialogue: 0,0:56:27.70,0:56:31.60,EN,,0,0,0,,If you look at this slide, we see this is a complicated mess also. Dialogue: 0,0:56:33.68,0:56:35.28,EN,,0,0,0,,I'm trying rules on an expression. Dialogue: 0,0:56:36.36,0:56:39.96,EN,,0,0,0,,It turns out the expression I'm trying it on is some subexpression now of the expression I started with. Dialogue: 0,0:56:40.43,0:56:43.88,EN,,0,0,0,,Because the thing I just arranged allowed us to try every subexpression. Dialogue: 0,0:56:46.11,0:56:51.90,EN,,0,0,0,,So now here we're taking in a subexpression of the expression we started with. That's what this is. Dialogue: 0,0:56:52.49,0:56:57.71,EN,,0,0,0,,And what we're going to define here is a procedure called scan, which is going to try every rule. Dialogue: 0,0:56:58.72,0:57:00.33,EN,,0,0,0,,And we're going to start it up on the whole set of rules. Dialogue: 0,0:57:01.92,0:57:07.77,EN,,0,0,0,,This is going to go cdr-ing down the rules, if you will, looking for a rule to apply. Dialogue: 0,0:57:09.37,0:57:11.96,EN,,0,0,0,,And when it finds one, it'll do the job. Dialogue: 0,0:57:14.09,0:57:16.41,EN,,0,0,0,,Well, let's take a look at how try rules works. Dialogue: 0,0:57:17.74,0:57:21.02,EN,,0,0,0,,It's very simple: the scan rules. Scan rules, the way of scanning. Dialogue: 0,0:57:21.96,0:57:23.26,EN,,0,0,0,,Well, is it so simple? Dialogue: 0,0:57:23.26,0:57:24.51,EN,,0,0,0,,It's a big program, of course. Dialogue: 0,0:57:25.55,0:57:28.57,EN,,0,0,0,,We take a bunch of rules, which is a sublist of the list of rules. Dialogue: 0,0:57:30.75,0:57:35.13,EN,,0,0,0,,We've tried some of them already, and they've not been appropriate, so we get to some here. Dialogue: 0,0:57:35.87,0:57:36.30,EN,,0,0,0,,next one. Dialogue: 0,0:57:36.40,0:57:37.63,EN,,0,0,0,,If there are no more rules, Dialogue: 0,0:57:37.90,0:57:40.84,EN,,0,0,0,,well then, there's nothing I can do with this expression, and it's simplified. Dialogue: 0,0:57:42.35,0:57:47.26,EN,,0,0,0,,However, if it turns out that there are still rules to be done, Dialogue: 0,0:57:48.01,0:57:51.58,EN,,0,0,0,,then let's match the pattern of the first rule Dialogue: 0,0:57:52.20,0:57:55.40,EN,,0,0,0,,against the expression using the empty dictionary to start with Dialogue: 0,0:57:57.07,0:57:58.84,EN,,0,0,0,,and use that as the dictionary. Dialogue: 0,0:58:00.32,0:58:03.74,EN,,0,0,0,,If that happens to be a failure, try the rest of the rules. Dialogue: 0,0:58:06.68,0:58:07.52,EN,,0,0,0,,That's all it says here. Dialogue: 0,0:58:08.52,0:58:10.33,EN,,0,0,0,,How it says, it says discard that rule. Dialogue: 0,0:58:11.10,0:58:15.05,EN,,0,0,0,,Otherwise, well, I'm going to get the skeleton of the first rule, Dialogue: 0,0:58:15.34,0:58:17.40,EN,,0,0,0,,instantiate that relative to the dictionary, Dialogue: 0,0:58:17.93,0:58:20.80,EN,,0,0,0,,and simplify the result, and that's the expression I want. Dialogue: 0,0:58:24.20,0:58:25.96,EN,,0,0,0,,So although that was a complicated program, Dialogue: 0,0:58:26.25,0:58:28.72,EN,,0,0,0,,every complicated program is made out of a lot of simple pieces. Dialogue: 0,0:58:29.77,0:58:33.12,EN,,0,0,0,,Now, the pattern of recursions here is very complicated. Dialogue: 0,0:58:34.78,0:58:36.52,EN,,0,0,0,,And one of the most important things is not to think about that. Dialogue: 0,0:58:38.67,0:58:41.80,EN,,0,0,0,,If you try to think about the actual pattern by which this does something, Dialogue: 0,0:58:42.06,0:58:42.97,EN,,0,0,0,,you're going to get very confused. Dialogue: 0,0:58:45.31,0:58:45.71,EN,,0,0,0,,I would. Dialogue: 0,0:58:47.04,0:58:50.17,EN,,0,0,0,,This is not a matter. you can do this with practice. Dialogue: 0,0:58:51.52,0:58:52.46,EN,,0,0,0,,These patterns are hard. Dialogue: 0,0:58:54.17,0:58:55.42,EN,,0,0,0,,But you don't have to think about it. Dialogue: 0,0:58:55.83,0:58:59.72,EN,,0,0,0,,The key to this-- it's very good programming and very good design-- Dialogue: 0,0:58:59.74,0:59:00.97,EN,,0,0,0,,is to know what not to think about. Dialogue: 0,0:59:03.05,0:59:06.06,EN,,0,0,0,,The fact is, going back to this slide, Dialogue: 0,0:59:06.92,0:59:08.01,EN,,0,0,0,,I don't have to think about it Dialogue: 0,0:59:08.54,0:59:13.83,EN,,0,0,0,,because I have specifications in my mind for what simplify x does. Dialogue: 0,0:59:14.00,0:59:15.24,EN,,0,0,0,,I don't have to know how it does it. Dialogue: 0,0:59:17.08,0:59:21.24,EN,,0,0,0,,And it may, in fact, call scan somehow through try rules, which it does. Dialogue: 0,0:59:22.24,0:59:24.09,EN,,0,0,0,,And somehow, I've got another recursion going on here. Dialogue: 0,0:59:24.33,0:59:25.69,EN,,0,0,0,,But since I know that simplify exp Dialogue: 0,0:59:26.84,0:59:30.40,EN,,0,0,0,,is assumed by wishful thinking to produce the simplified result, Dialogue: 0,0:59:31.61,0:59:32.99,EN,,0,0,0,,then I don't have to think about it anymore. Dialogue: 0,0:59:33.43,0:59:34.83,EN,,0,0,0,,I've used it. Dialogue: 0,0:59:35.07,0:59:36.43,EN,,0,0,0,,I've used it in a reasonable way. Dialogue: 0,0:59:36.43,0:59:37.45,EN,,0,0,0,,I will get a reasonable answer. Dialogue: 0,0:59:39.95,0:59:42.57,EN,,0,0,0,,And you have to learn how to program that way-- with abandon. Dialogue: 0,0:59:47.56,0:59:49.05,EN,,0,0,0,,Well, there's very little left of this thing. Dialogue: 0,0:59:50.40,0:59:54.46,EN,,0,0,0,,All there is left is a few details associated with what a dictionary is. Dialogue: 0,0:59:55.08,0:59:58.32,EN,,0,0,0,,And those of you who've been itching to know what a dictionary is, Dialogue: 0,0:59:58.70,1:00:01.82,EN,,0,0,0,,well, I will flip it up and not tell you anything about it. Dialogue: 0,1:00:04.14,1:00:05.20,EN,,0,0,0,,Dictionaries are easy. Dialogue: 0,1:00:06.01,1:00:09.84,EN,,0,0,0,,It's represented in terms of something else called an A list, Dialogue: 0,1:00:10.65,1:00:16.04,EN,,0,0,0,,which is a particular pattern of usage for making tables in lists. Dialogue: 0,1:00:16.50,1:00:20.17,EN,,0,0,0,,They're easy. They're made out of pairs, as was asked a bit ago. Dialogue: 0,1:00:21.21,1:00:24.62,EN,,0,0,0,,And there are special procedures for dealing with such things called assq, Dialogue: 0,1:00:24.94,1:00:26.36,EN,,0,0,0,,and you can find them in manuals. Dialogue: 0,1:00:27.04,1:00:28.59,EN,,0,0,0,,I'm not terribly excited about it. Dialogue: 0,1:00:28.83,1:00:31.21,EN,,0,0,0,,The only interesting thing here in extend dictionary Dialogue: 0,1:00:31.48,1:00:36.94,EN,,0,0,0,,is I have to extend the dictionary with a pattern, a datum, and a dictionary. Dialogue: 0,1:00:37.42,1:00:42.38,EN,,0,0,0,,I wish that, this pattern is, in fact, at this point a pattern variable. Dialogue: 0,1:00:43.74,1:00:47.53,EN,,0,0,0,,And what do I want to do? I want to pull out the name of that pattern variable Dialogue: 0,1:00:48.16,1:00:49.42,EN,,0,0,0,,the pattern variable name, Dialogue: 0,1:00:50.44,1:00:53.71,EN,,0,0,0,,and I'm going to look up in the dictionary and see if it already has a value. Dialogue: 0,1:00:53.79,1:00:56.41,EN,,0,0,0,,If not, I'm going to add a new one in. Dialogue: 0,1:00:56.92,1:00:59.23,EN,,0,0,0,,If it does have one, if it has a value, Dialogue: 0,1:00:59.60,1:01:03.18,EN,,0,0,0,,then it had better be equal to the one that was already stored away. Dialogue: 0,1:01:03.88,1:01:06.54,EN,,0,0,0,,And if that's the case, the dictionary is what I expected it to be. Dialogue: 0,1:01:06.89,1:01:09.15,EN,,0,0,0,,Otherwise, I fail. Dialogue: 0,1:01:12.08,1:01:12.89,EN,,0,0,0,,So that's easy, too. Dialogue: 0,1:01:13.66,1:01:16.68,EN,,0,0,0,,If you open up any program, you're going to find inside of it lots of little pieces, Dialogue: 0,1:01:17.18,1:01:18.30,EN,,0,0,0,,all of which are easy. Dialogue: 0,1:01:20.04,1:01:21.29,EN,,0,0,0,,So at this point, I suppose, Dialogue: 0,1:01:21.60,1:01:25.68,EN,,0,0,0,,I've just told you some million-dollar valuable information. Dialogue: 0,1:01:28.41,1:01:30.96,EN,,0,0,0,,And I suppose at this point we're pretty much done with this program. Dialogue: 0,1:01:31.85,1:01:32.72,EN,,0,0,0,,I'd like to ask about questions. Dialogue: 0,1:01:34.27,1:01:38.16,EN,,0,0,0,,AUDIENCE: Yes, can you give me the words that describe the specification for a simplified expression? Dialogue: 0,1:01:38.72,1:01:39.02,EN,,0,0,0,,PROFESSOR: Sure. Dialogue: 0,1:01:39.85,1:01:44.33,EN,,0,0,0,,A simplified expression takes an expression and produces a simplified expression. Dialogue: 0,1:01:45.28,1:01:45.77,EN,,0,0,0,,That's it, OK? Dialogue: 0,1:01:48.11,1:01:50.27,EN,,0,0,0,,How it does it is very easy. Dialogue: 0,1:01:51.60,1:01:56.09,EN,,0,0,0,,In compound expressions, all the pieces are simplified, and then the rules are tried on the result. Dialogue: 0,1:01:56.89,1:01:58.49,EN,,0,0,0,,And for simple expressions, you just try all the rules. Dialogue: 0,1:01:59.52,1:02:02.11,EN,,0,0,0,,AUDIENCE: So an expression is simplified by virtue of the rules? Dialogue: 0,1:02:02.76,1:02:03.58,EN,,0,0,0,,PROFESSOR: That's, of course, true. Dialogue: 0,1:02:03.76,1:02:03.90,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,1:02:04.06,1:02:07.13,EN,,0,0,0,,PROFESSOR: And the way this works is that simplified expression, as you see here, Dialogue: 0,1:02:08.35,1:02:11.64,EN,,0,0,0,,what it does is it breaks the expression down into the smallest pieces, Dialogue: 0,1:02:12.60,1:02:17.29,EN,,0,0,0,,simplifies building up from the bottom using the rules to be the simplifier, Dialogue: 0,1:02:18.30,1:02:22.48,EN,,0,0,0,,to do the manipulations, and constructs a new expression as the result. Dialogue: 0,1:02:24.28,1:02:29.44,EN,,0,0,0,,Eventually, one of things you see is that the rules themselves, the try rules, Dialogue: 0,1:02:29.70,1:02:35.50,EN,,0,0,0,,call a simplified expression on the results when it changes something, the results of a match. Dialogue: 0,1:02:35.80,1:02:40.64,EN,,0,0,0,,I'm sorry, the results of instantiation of a skeleton for a rule that has matched. Dialogue: 0,1:02:42.00,1:02:47.36,EN,,0,0,0,,So the spec of a simplified expression is that any expression you put into it comes out simplified according to those rules. Dialogue: 0,1:02:49.84,1:02:50.76,EN,,0,0,0,,Thank you. Let's take a break. [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:06.19,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:06.45,0:00:14.22,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:06.45,0:00:14.22,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}字幕&时间轴\N邓雄飞 & S.Michael Dialogue: 0,0:00:06.45,0:00:14.22,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}后期&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:06.45,0:00:14.22,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:06.45,0:00:14.22,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:14.83,0:00:18.00,Declare,,0,0,0,,{\an2\fad(500,500)}模式匹配:基于规则的代换\N Pattern Matching: Rule-based Substitution Dialogue: 0,0:00:24.34,0:00:29.34,Default,,0,0,0,,教授:昨天 我们学习了一些符号操作 Dialogue: 0,0:00:29.92,0:00:35.12,Default,,0,0,0,,编写了一个非常典型的程序 Dialogue: 0,0:00:35.15,0:00:38.97,Default,,0,0,0,,来实现教材中的微积分规则 Dialogue: 0,0:00:39.61,0:00:44.59,Default,,0,0,0,,在这张幻灯片上 Dialogue: 0,0:00:44.96,0:00:48.81,Default,,0,0,0,,有一些从书中摘录的微积分规则 Dialogue: 0,0:00:49.47,0:00:54.62,Default,,0,0,0,,我们要把这些规则转化成计算机语言 Dialogue: 0,0:00:55.14,0:00:58.85,Default,,0,0,0,,当然 这种策略很有趣 Dialogue: 0,0:00:59.36,0:01:04.80,Default,,0,0,0,,但是我们为什么要把它们翻译成计算机语言呢? Dialogue: 0,0:01:05.00,0:01:06.27,Default,,0,0,0,,我的意思是--- Dialogue: 0,0:01:06.62,0:01:11.02,Default,,0,0,0,,我们昨天写的程序非常典型 Dialogue: 0,0:01:11.21,0:01:15.98,Default,,0,0,0,,它是一个按表达式类型做分派的分情况分析语句 Dialogue: 0,0:01:16.38,0:01:18.48,Default,,0,0,0,,规则就是这样的 Dialogue: 0,0:01:19.68,0:01:21.55,Default,,0,0,0,,这里的规则是说: Dialogue: 0,0:01:21.74,0:01:25.48,Default,,0,0,0,,我们考察的表达式如果是--- Dialogue: 0,0:01:25.48,0:01:29.42,Default,,0,0,0,,如果是常量 就做一些事情 Dialogue: 0,0:01:29.42,0:01:31.37,Default,,0,0,0,,如果是变量 就做另一件事情 Dialogue: 0,0:01:31.60,0:01:35.56,Default,,0,0,0,,如果它是常量乘以变量 就做另外的事 等等 Dialogue: 0,0:01:36.00,0:01:38.96,Default,,0,0,0,,这是一种按类型的分派 Dialogue: 0,0:01:41.40,0:01:45.16,Default,,0,0,0,,那么 既然它有如此典型的行为和结构 Dialogue: 0,0:01:45.95,0:01:49.53,Default,,0,0,0,,有没有其它方式把这个过程写得更加清晰? Dialogue: 0,0:01:50.83,0:01:53.45,Default,,0,0,0,,首先要解决的是 这些规则是什么? Dialogue: 0,0:01:55.56,0:01:58.50,Default,,0,0,0,,我们来好好想一下 规则有好几个部分 Dialogue: 0,0:01:58.94,0:02:02.35,Default,,0,0,0,,如果仔细观察这些规则 Dialogue: 0,0:02:03.71,0:02:04.99,Default,,0,0,0,,你就会发现 Dialogue: 0,0:02:05.12,0:02:09.69,Default,,0,0,0,,这些规则都有左右两部分 Dialogue: 0,0:02:10.36,0:02:14.36,Default,,0,0,0,,每一个规则都有左边部分和右边部分 Dialogue: 0,0:02:15.15,0:02:20.30,Default,,0,0,0,,左边部分用来与对被求导表达式做比较 Dialogue: 0,0:02:21.52,0:02:25.10,Default,,0,0,0,,右边部分用于替换原表达式 Dialogue: 0,0:02:28.49,0:02:33.10,Default,,0,0,0,,这张纸上的所有规则都可以描述成这样—— Dialogue: 0,0:02:36.51,0:02:38.06,Default,,0,0,0,,我们有许多模式 Dialogue: 0,0:02:41.48,0:02:48.30,Default,,0,0,0,,有时候 给定一个模式 我们需要为其生成一个骨架 Dialogue: 0,0:02:51.88,0:02:52.81,Default,,0,0,0,,这就是一个规则 Dialogue: 0,0:02:55.42,0:02:57.13,Default,,0,0,0,,模式是用于匹配的部分 Dialogue: 0,0:02:57.88,0:03:03.26,Default,,0,0,0,,将成功匹配的值代换到骨架里 就得到一个新的表达式 Dialogue: 0,0:03:06.46,0:03:16.32,Default,,0,0,0,,我的意思是:模式是用来匹配原表达式的 Dialogue: 0,0:03:23.72,0:03:28.51,Default,,0,0,0,,应用规则会产生一个新的表达式 Dialogue: 0,0:03:33.61,0:03:34.91,Default,,0,0,0,,我们称之为目标 Dialogue: 0,0:03:38.12,0:03:39.88,Default,,0,0,0,,这是通过骨架的实例化实现的 Dialogue: 0,0:03:41.63,0:03:43.02,Default,,0,0,0,,这个叫做实例化 Dialogue: 0,0:03:50.72,0:03:54.73,Default,,0,0,0,,这就是这些规则所描述的过程 Dialogue: 0,0:03:55.69,0:03:57.26,Default,,0,0,0,,今天我想要做的是 Dialogue: 0,0:03:58.73,0:04:01.08,Default,,0,0,0,,构建一种语言 Dialogue: 0,0:04:02.20,0:04:05.48,Default,,0,0,0,,以及它的解释与执行方法 Dialogue: 0,0:04:05.74,0:04:08.43,Default,,0,0,0,,使得这种语言可以直接表述这些规则 Dialogue: 0,0:04:10.59,0:04:11.58,Default,,0,0,0,,我们将要做的是 Dialogue: 0,0:04:11.58,0:04:17.56,Default,,0,0,0,,与其通过将规则翻译为程序 让计算机理解并执行 Dialogue: 0,0:04:18.38,0:04:21.56,Default,,0,0,0,,这里主要指 Lisp 程序 Dialogue: 0,0:04:22.16,0:04:24.49,Default,,0,0,0,,我们不如让计算机理解我们 Dialogue: 0,0:04:25.48,0:04:29.15,Default,,0,0,0,,我们可以写一些程序让计算机理解这些规则 Dialogue: 0,0:04:30.91,0:04:34.76,Default,,0,0,0,,这又稍微强调了上次的主旨 Dialogue: 0,0:04:35.44,0:04:39.36,Default,,0,0,0,,与其解决一个特定问题 不如解决一类问题 Dialogue: 0,0:04:39.77,0:04:46.72,Default,,0,0,0,,如果我为不同的数学运算写规则 Dialogue: 0,0:04:48.24,0:04:51.39,Default,,0,0,0,,比如简单代数的化简 Dialogue: 0,0:04:51.98,0:04:55.48,Default,,0,0,0,,或者三角函数运算 Dialogue: 0,0:04:56.09,0:05:01.16,Default,,0,0,0,,如果按照昨天的方法 我就得重新写个不同的程序 Dialogue: 0,0:05:01.16,0:05:05.42,Default,,0,0,0,,与之相反 我把程序中的共有逻辑给封装起来 Dialogue: 0,0:05:06.12,0:05:10.17,Default,,0,0,0,,也就是匹配、实例化等概念 还有控制结构 Dialogue: 0,0:05:10.17,0:05:12.46,Default,,0,0,0,,这都是非常复杂的事情 Dialogue: 0,0:05:13.16,0:05:18.46,Default,,0,0,0,,我想把它们从规则中分开 并封装 Dialogue: 0,0:05:20.06,0:05:22.60,Default,,0,0,0,,首先让我们看一下表示法 Dialogue: 0,0:05:22.62,0:05:24.09,Default,,0,0,0,,请大家看投影仪上的幻灯片 Dialogue: 0,0:05:24.67,0:05:25.60,Default,,0,0,0,,已经在这里了 Dialogue: 0,0:05:26.25,0:05:32.27,Default,,0,0,0,,我想要把求导的计算规则 Dialogue: 0,0:05:33.71,0:05:37.15,Default,,0,0,0,,表示为我这里写的一种简单语言 Dialogue: 0,0:05:38.11,0:05:43.29,Default,,0,0,0,,我会尽量避免去考虑语法 Dialogue: 0,0:05:44.28,0:05:49.28,Default,,0,0,0,,美化它很容易 虽然这个确实挺丑 但我并不关心 Dialogue: 0,0:05:49.30,0:05:56.41,Default,,0,0,0,,这确实不能像dx/dt那样表示 Dialogue: 0,0:05:56.76,0:05:58.12,Default,,0,0,0,,但这并不重要 Dialogue: 0,0:05:58.88,0:06:00.62,Default,,0,0,0,,这是一个偶然现象 Dialogue: 0,0:06:01.00,0:06:04.44,Default,,0,0,0,,这里 我只关心规则的结构 Dialogue: 0,0:06:04.83,0:06:11.70,Default,,0,0,0,,规则的左边部分代表了我想要匹配的求导表达式 Dialogue: 0,0:06:11.80,0:06:13.56,Default,,0,0,0,,这个表示是说 Dialogue: 0,0:06:13.60,0:06:18.32,Default,,0,0,0,,一个匹配常量的模式变量c Dialogue: 0,0:06:18.84,0:06:21.20,Default,,0,0,0,,关于匹配任意表达式的模式变量v求导 Dialogue: 0,0:06:23.08,0:06:25.55,Default,,0,0,0,,我们在右边部分得到的是0 Dialogue: 0,0:06:26.00,0:06:28.06,Default,,0,0,0,,这就代表了一个规则 Dialogue: 0,0:06:29.26,0:06:34.04,Default,,0,0,0,,下一条规则是 匹配变量的模式变量v Dialogue: 0,0:06:34.22,0:06:37.74,Default,,0,0,0,,对同一个模式变量求导 得到的结果是1 Dialogue: 0,0:06:38.60,0:06:42.17,Default,,0,0,0,,然而 如果一个匹配变量的模式变量u Dialogue: 0,0:06:42.41,0:06:44.84,Default,,0,0,0,,关于另一个模式变量v求导 Dialogue: 0,0:06:45.39,0:06:47.05,Default,,0,0,0,,那么 结果就是0 Dialogue: 0,0:06:47.84,0:06:52.17,Default,,0,0,0,,我想让大家看一下 这些规则是如何组织在一起的 Dialogue: 0,0:06:52.51,0:06:54.30,Default,,0,0,0,,比如说 在这里 Dialogue: 0,0:06:54.73,0:07:01.90,Default,,0,0,0,,我们要求表达式x1、x2之和的导数 Dialogue: 0,0:07:01.90,0:07:05.85,Default,,0,0,0,,在我们创造的这个语言中 Dialogue: 0,0:07:06.88,0:07:08.62,Default,,0,0,0,,以问号开头的叫模式变量 Dialogue: 0,0:07:08.93,0:07:14.93,Default,,0,0,0,,我们就像这样来构建这些用来匹配的模式变量 Dialogue: 0,0:07:14.93,0:07:20.33,Default,,0,0,0,,这里 表达式x1加上表达式x2 Dialogue: 0,0:07:20.33,0:07:26.70,Default,,0,0,0,,对变量v求导的结果等于右边这里的式子 Dialogue: 0,0:07:26.70,0:07:32.76,Default,,0,0,0,,右边的式子是一个骨架 表示表达式X1关于变量v求导 Dialogue: 0,0:07:33.82,0:07:37.10,Default,,0,0,0,,加上表达式X2对变量v求导的和 Dialogue: 0,0:07:37.60,0:07:42.38,Default,,0,0,0,,这里的冒号表示要代换的对象 Dialogue: 0,0:07:43.63,0:07:47.23,Default,,0,0,0,,我们将它们称作“骨架求值” Dialogue: 0,0:07:48.51,0:07:53.07,Default,,0,0,0,,让我在黑板上写一些语法 Dialogue: 0,0:07:53.23,0:07:55.56,Default,,0,0,0,,这样就能知道 在我们这门规则语言中会发生什么 Dialogue: 0,0:07:56.68,0:07:59.88,Default,,0,0,0,,首先我们要处理模式匹配问题 Dialogue: 0,0:08:06.04,0:08:13.12,Default,,0,0,0,,第一条规则是 形如foo这样的符号与其自身匹配 Dialogue: 0,0:08:23.52,0:08:31.34,Default,,0,0,0,,形如(f a b)的表达式 可以匹配这样的表 Dialogue: 0,0:08:36.30,0:08:57.02,Default,,0,0,0,,表的首元素是f、第二个元素是a、第三个元素是b Dialogue: 0,0:08:58.62,0:09:06.99,Default,,0,0,0,,另外 模式中可能还有形如(? x)这样的规则 Dialogue: 0,0:09:08.57,0:09:18.67,Default,,0,0,0,,这个规则可以匹配任意表达式 并将其称为x Dialogue: 0,0:09:25.45,0:09:29.98,Default,,0,0,0,,(?c x) 只匹配常量 Dialogue: 0,0:09:31.50,0:09:40.96,Default,,0,0,0,,并将匹配的常量记作x Dialogue: 0,0:09:44.56,0:09:57.07,Default,,0,0,0,,(?v x)匹配变量 并将匹配的变量记作x Dialogue: 0,0:10:01.66,0:10:03.80,Default,,0,0,0,,这就是我们正在构建的语言 Dialogue: 0,0:10:04.19,0:10:09.40,Default,,0,0,0,,两个对象的比较是基于元素与元素间的比较 Dialogue: 0,0:10:10.25,0:10:15.85,Default,,0,0,0,,模式中的元素可以包含这些语法变量、模式变量 Dialogue: 0,0:10:17.07,0:10:20.43,Default,,0,0,0,,它们可以用来匹配任意对象 Dialogue: 0,0:10:22.12,0:10:29.28,Default,,0,0,0,,这样 我就可以用x作为名字取得被匹配对象的值 Dialogue: 0,0:10:31.05,0:10:37.55,Default,,0,0,0,,现在 当我们为实例化准备骨架的时候 Dialogue: 0,0:10:39.50,0:10:41.40,Default,,0,0,0,,我们可能有这样的东西 Dialogue: 0,0:10:42.27,0:10:46.33,Default,,0,0,0,,符号foo实例化为它本身 Dialogue: 0,0:10:55.08,0:11:05.92,Default,,0,0,0,,形如(f a b)这样的表 实例化为 Dialogue: 0,0:11:06.36,0:11:14.75,Default,,0,0,0,,实例化为一个三元素表 Dialogue: 0,0:11:15.55,0:11:33.37,Default,,0,0,0,,其元素分别为f、a、b各自实例化后的结果 Dialogue: 0,0:11:36.35,0:11:54.27,Default,,0,0,0,,(: x) 会被实例化为x的值--也就是被匹配的模式 Dialogue: 0,0:12:03.05,0:12:10.08,Default,,0,0,0,,回头看看这里的幻灯片 我们发现这些都是对象 Dialogue: 0,0:12:10.78,0:12:16.06,Default,,0,0,0,,我们看到 这是一个用来匹配常量的模式变量 Dialogue: 0,0:12:16.56,0:12:19.02,Default,,0,0,0,,这是匹配变量的模式变量 Dialogue: 0,0:12:19.39,0:12:21.74,Default,,0,0,0,,这是匹配任意表达式的模式变量 Dialogue: 0,0:12:22.72,0:12:24.92,Default,,0,0,0,,如果我们有了名字一样的两个实例 Dialogue: 0,0:12:25.08,0:12:31.77,Default,,0,0,0,,想这个是被称作v的单变量表达式 Dialogue: 0,0:12:32.86,0:12:36.30,Default,,0,0,0,,关于一个称作v的任意表达式求导 Dialogue: 0,0:12:36.41,0:12:38.01,Default,,0,0,0,,因为这个v出现了两次 Dialogue: 0,0:12:38.65,0:12:41.07,Default,,0,0,0,,我们想约束它们相同 Dialogue: 0,0:12:42.68,0:12:45.00,Default,,0,0,0,,只有它俩完全一致才算是匹配 Dialogue: 0,0:12:45.23,0:12:47.23,Default,,0,0,0,,所以在这里我们在构建一个语言 Dialogue: 0,0:12:47.60,0:12:50.66,Default,,0,0,0,,事实上 这是一件非常好的事情 Dialogue: 0,0:12:50.66,0:12:52.60,Default,,0,0,0,,构建一个语言非常有趣 Dialogue: 0,0:12:52.60,0:12:54.33,Default,,0,0,0,,并且大家一直在做这些 Dialogue: 0,0:12:54.33,0:12:56.89,Default,,0,0,0,,大家做过的真正强大的设计 Dialogue: 0,0:12:57.23,0:13:00.20,Default,,0,0,0,,是构建一个语言来解决这样的问题 Dialogue: 0,0:13:02.06,0:13:05.34,Default,,0,0,0,,我们回头看看这些规则 Dialogue: 0,0:13:05.80,0:13:07.10,Default,,0,0,0,,这就是它们的全部 Dialogue: 0,0:13:07.10,0:13:12.43,Default,,0,0,0,,我们有加法、乘法 就像我们之前看到的一样 Dialogue: 0,0:13:12.43,0:13:17.37,Default,,0,0,0,,x1+x2 关于变量v的导数等于 Dialogue: 0,0:13:17.68,0:13:26.52,Default,,0,0,0,,x2对v求导乘以x1 加上 x1对v求导乘以x2 Dialogue: 0,0:13:27.26,0:13:29.10,Default,,0,0,0,,这是指数运算的求导规则 Dialogue: 0,0:13:29.24,0:13:32.11,Default,,0,0,0,,虽然这里展示完了所有的规则 但还可以按照我们意愿添加 Dialogue: 0,0:13:32.70,0:13:39.10,Default,,0,0,0,,我们在这里 建立了关于求导的规则列表 Dialogue: 0,0:13:40.40,0:13:44.33,Default,,0,0,0,,一旦我们有了这些 我们应该做什么呢? Dialogue: 0,0:13:45.40,0:13:47.84,Default,,0,0,0,,恩 我将给你们展示最好的思想之一 Dialogue: 0,0:13:48.44,0:13:51.68,Default,,0,0,0,,然后我们将花一整天来鼓捣它 Dialogue: 0,0:13:52.28,0:13:57.37,Default,,0,0,0,,我将向大家展示一个叫做simplifier的程序 Dialogue: 0,0:13:57.82,0:13:59.47,Default,,0,0,0,,一个通用的化简器 Dialogue: 0,0:14:00.09,0:14:17.10,Default,,0,0,0,,我们将求导规则deriv-rules送入simplifier从而产生dsimp Dialogue: 0,0:14:23.74,0:14:28.75,Default,,0,0,0,,传给simplifier过程一套规则 它会返回给我们一个过程 Dialogue: 0,0:14:29.32,0:14:34.59,Default,,0,0,0,,它根据这些规则对表达式进行化简 Dialogue: 0,0:14:37.39,0:14:43.93,Default,,0,0,0,,因此 这里会返回一个按照你制定的规则所构造的过程 Dialogue: 0,0:14:44.59,0:14:49.56,Default,,0,0,0,,使得在我们进入 Lisp 系统后 在命令提示符后面 Dialogue: 0,0:14:49.88,0:15:03.93,Default,,0,0,0,,输入 (DSIMP '(dd (+ x y) x)) Dialogue: 0,0:15:06.99,0:15:10.97,Default,,0,0,0,,注意这里的引号 因为我们讨论的是表达式的求导 Dialogue: 0,0:15:13.29,0:15:17.76,Default,,0,0,0,,然后我将得到结果 (+ 1 0) Dialogue: 0,0:15:19.96,0:15:24.60,Default,,0,0,0,,因为 (x+y)' = x' + y' Dialogue: 0,0:15:24.60,0:15:26.22,Default,,0,0,0,,x'=1 Dialogue: 0,0:15:26.38,0:15:27.82,Default,,0,0,0,,y'=0(关于x求导) Dialogue: 0,0:15:29.42,0:15:30.46,Default,,0,0,0,,这不是我想要的 Dialogue: 0,0:15:31.18,0:15:34.65,Default,,0,0,0,,我还没有在这里做代数化简 Dialogue: 0,0:15:36.16,0:15:41.53,Default,,0,0,0,,当然一旦我有了这个东西那么我们可以 -- 我们可以看看其它的规则 Dialogue: 0,0:15:41.96,0:15:49.36,Default,,0,0,0,,比如 我们看这张幻灯片 Dialogue: 0,0:15:49.36,0:15:54.12,Default,,0,0,0,,这里是其它的规则 代数操作规则 Dialogue: 0,0:15:56.00,0:15:58.38,Default,,0,0,0,,它们可以用来化简代数表达式 Dialogue: 0,0:15:59.00,0:16:02.06,Default,,0,0,0,,考察一下这些规则 Dialogue: 0,0:16:03.04,0:16:09.20,Default,,0,0,0,,这条规则的左部分是说 某个运算符应用到常量e1和常量e2上 Dialogue: 0,0:16:09.32,0:16:14.51,Default,,0,0,0,,其结果就是求(op e1 e2)的值 Dialogue: 0,0:16:15.88,0:16:21.56,Default,,0,0,0,,或者 当一个运算符应用在任意表达式e1和常量e2上 Dialogue: 0,0:16:21.69,0:16:23.87,Default,,0,0,0,,化简结果会把常量前置 Dialogue: 0,0:16:24.52,0:16:27.68,Default,,0,0,0,,这就变成了((: op) (: e2) (: e1)) Dialogue: 0,0:16:28.59,0:16:30.11,Default,,0,0,0,,为什么要这么做?我不知道 Dialogue: 0,0:16:30.22,0:16:33.16,Default,,0,0,0,,比如说 如果系统中有除法的话 这就不对 Dialogue: 0,0:16:33.53,0:16:35.31,Default,,0,0,0,,换句话说 规则有漏洞 Dialogue: 0,0:16:36.67,0:16:40.86,Default,,0,0,0,,所以0与任何表达式e的和 等于表达式e Dialogue: 0,0:16:42.17,0:16:45.31,Default,,0,0,0,,1乘以任何表达式e的结果是表达式e Dialogue: 0,0:16:46.12,0:16:49.13,Default,,0,0,0,,0乘以任何表达式e的结果是0 Dialogue: 0,0:16:49.33,0:16:52.72,Default,,0,0,0,,我们可以有任意复杂的规则 Dialogue: 0,0:16:53.69,0:16:54.81,Default,,0,0,0,,比如说 Dialogue: 0,0:16:55.36,0:17:01.69,Default,,0,0,0,,常量e1*(常量e2*任意表达式e3) Dialogue: 0,0:17:02.35,0:17:11.96,Default,,0,0,0,,可以化简为 (e1*e2)*e3 Dialogue: 0,0:17:13.36,0:17:16.76,Default,,0,0,0,,这个规则是说 先把常量组合起来 Dialogue: 0,0:17:16.76,0:17:22.70,Default,,0,0,0,,如果有形如 e1*(e2*e3) 的式子 而且e1 e2都是常量 就先把常量乘起来 Dialogue: 0,0:17:23.84,0:17:25.48,Default,,0,0,0,,你可以根据意愿来构建这些规则 Dialogue: 0,0:17:25.79,0:17:26.94,Default,,0,0,0,,这里还有很多规则 Dialogue: 0,0:17:27.42,0:17:31.04,Default,,0,0,0,,这些规则是很复杂的 比如-- Dialogue: 0,0:17:31.26,0:17:33.93,Default,,0,0,0,,请看 这条规则是分配律 Dialogue: 0,0:17:33.93,0:17:38.57,Default,,0,0,0,,任何表达式c乘以d和e Dialogue: 0,0:17:39.02,0:17:43.66,Default,,0,0,0,,等于 c与d的积加上c与e的积 Dialogue: 0,0:17:45.31,0:17:48.67,Default,,0,0,0,,我并不关心这些规则具体描述的什么 Dialogue: 0,0:17:49.16,0:17:52.97,Default,,0,0,0,,我们将要构建一种语言 用来解释这些规则 Dialogue: 0,0:17:55.50,0:17:57.48,Default,,0,0,0,,这样我们就可以按我们的意愿编写规则 Dialogue: 0,0:17:58.35,0:18:00.14,Default,,0,0,0,,这是另外一种程序设计语言 Dialogue: 0,0:18:03.39,0:18:04.04,Default,,0,0,0,,来看看 Dialogue: 0,0:18:05.18,0:18:06.96,Default,,0,0,0,,我还没告诉你我们要怎么做 Dialogue: 0,0:18:07.53,0:18:10.06,Default,,0,0,0,,当然我们马上就要讲了 Dialogue: 0,0:18:10.89,0:18:15.40,Default,,0,0,0,,但真正的问题是:宏观地看 我要做什么? Dialogue: 0,0:18:17.08,0:18:18.22,Default,,0,0,0,,这些规则是如何运作的? Dialogue: 0,0:18:19.00,0:18:25.45,Default,,0,0,0,,化简程序是如何用这些规则来输入的表达式 并返回一个合理的答案? Dialogue: 0,0:18:26.22,0:18:29.85,Default,,0,0,0,,首先 我认为我们有一大堆的规则 Dialogue: 0,0:18:32.52,0:18:34.22,Default,,0,0,0,,这里有全部的规则 Dialogue: 0,0:18:42.09,0:18:44.49,Default,,0,0,0,,这里的每一个规则 --- Dialogue: 0,0:18:46.97,0:18:49.24,Default,,0,0,0,,都有一个模式和一个骨架 Dialogue: 0,0:18:49.72,0:18:51.36,Default,,0,0,0,,我正在努力为它作一个控制结构 Dialogue: 0,0:18:53.37,0:18:56.56,Default,,0,0,0,,我有一个匹配器 Dialogue: 0,0:19:00.99,0:19:03.76,Default,,0,0,0,,还有一个实例化器 Dialogue: 0,0:19:09.66,0:19:12.94,Default,,0,0,0,,我将把一系列模式变量的值 Dialogue: 0,0:19:14.03,0:19:17.47,Default,,0,0,0,,从匹配器中传递到实例化器中 Dialogue: 0,0:19:18.06,0:19:19.42,Default,,0,0,0,,我把传递的东西叫做词典 Dialogue: 0,0:19:20.59,0:19:21.52,Default,,0,0,0,,传递一本词典 Dialogue: 0,0:19:24.92,0:19:27.82,Default,,0,0,0,,里面记载了:x匹配下列子表达式 Dialogue: 0,0:19:29.04,0:19:31.31,Default,,0,0,0,,而y匹配另一个子表达式 Dialogue: 0,0:19:32.25,0:19:36.35,Default,,0,0,0,,我会从实例化器中构造表达式 并送入匹配器 Dialogue: 0,0:19:37.16,0:19:38.36,Default,,0,0,0,,这些是表达式 Dialogue: 0,0:19:45.00,0:19:48.41,Default,,0,0,0,,这些规则的模式将要送进匹配器中 Dialogue: 0,0:19:49.24,0:19:54.40,Default,,0,0,0,,规则对应的骨架将要送进实例化器中 Dialogue: 0,0:19:55.21,0:19:56.62,Default,,0,0,0,,现在变得有点复杂了 Dialogue: 0,0:19:57.12,0:19:59.53,Default,,0,0,0,,因为当我们处理代数表达式时 Dialogue: 0,0:20:00.44,0:20:03.60,Default,,0,0,0,,有一些规则使你能够做等价代换 Dialogue: 0,0:20:04.24,0:20:05.87,Default,,0,0,0,,这些是等价代换规则 Dialogue: 0,0:20:06.88,0:20:09.29,Default,,0,0,0,,所以需要考察表达式的所有子表达式 Dialogue: 0,0:20:11.13,0:20:15.82,Default,,0,0,0,,给定一个表达式 这些规则应该被不断应用 Dialogue: 0,0:20:16.03,0:20:19.71,Default,,0,0,0,,首先 对于传入的表达式的每个子表达式 Dialogue: 0,0:20:20.22,0:20:22.83,Default,,0,0,0,,所有的规则都需要考察一次 Dialogue: 0,0:20:24.33,0:20:27.07,Default,,0,0,0,,如果有规则匹配成功 那么就会执行这个过程 Dialogue: 0,0:20:27.30,0:20:30.63,Default,,0,0,0,,传递一本存储值的词典 Dialogue: 0,0:20:30.63,0:20:33.39,Default,,0,0,0,,实例化器产生一个新的表达式 Dialogue: 0,0:20:33.90,0:20:39.10,Default,,0,0,0,,该表达式基本上只是替换了原表达式中匹配的部分 Dialogue: 0,0:20:40.84,0:20:44.46,Default,,0,0,0,,然后 我们要对它重新检查 Dialogue: 0,0:20:44.75,0:20:48.11,Default,,0,0,0,,重新考察这些规则 看看表达式是否可以更进一步化简 Dialogue: 0,0:20:49.53,0:20:53.71,Default,,0,0,0,,然后每一个子表达式这样做 直到没有任何变化为止 Dialogue: 0,0:20:54.96,0:20:57.50,Default,,0,0,0,,你可以把它想像成一个有机过程 Dialogue: 0,0:20:57.83,0:21:00.20,Default,,0,0,0,,我们有一锅炖汤 Dialogue: 0,0:21:00.24,0:21:04.32,Default,,0,0,0,,粘乎乎的汤里面有细菌 有酶 Dialogue: 0,0:21:05.63,0:21:10.50,Default,,0,0,0,,这些酶改变了汤 Dialogue: 0,0:21:10.50,0:21:14.38,Default,,0,0,0,,它们附着在你的表达式上 改变了它 然后就走了 Dialogue: 0,0:21:15.28,0:21:17.83,Default,,0,0,0,,就像钥匙和锁一样 它们需要配对 Dialogue: 0,0:21:18.00,0:21:19.73,Default,,0,0,0,,匹配 -- 改变 -- 然后离开 Dialogue: 0,0:21:19.73,0:21:21.68,Default,,0,0,0,,你可以将其想像成一种并行过程 Dialogue: 0,0:21:22.70,0:21:24.97,Default,,0,0,0,,所以你把一个表达式放到这锅“浓汤”中 Dialogue: 0,0:21:25.80,0:21:28.00,Default,,0,0,0,,过了会儿把它拿出来 它就被简化了 Dialogue: 0,0:21:30.44,0:21:32.64,Default,,0,0,0,,它会一直变化 直到不能再变化为止 Dialogue: 0,0:21:33.36,0:21:38.33,Default,,0,0,0,,但这些酶可以附着在表达式的任何部分 Dialogue: 0,0:21:39.21,0:21:43.76,Default,,0,0,0,,课先上到这里 有问题么? Dialogue: 0,0:21:44.92,0:21:45.36,Default,,0,0,0,,请讲 Dialogue: 0,0:21:45.43,0:21:52.76,Default,,0,0,0,,学生:匹配器和实例化器是两个独立的程序 是么? Dialogue: 0,0:21:52.76,0:21:53.85,Default,,0,0,0,,教授:他们被拆分成很多小片 Dialogue: 0,0:21:54.14,0:21:56.60,Default,,0,0,0,,然后在一个更大的结构中组合起来 Dialogue: 0,0:21:57.26,0:21:59.13,Default,,0,0,0,,学生:先扫描并匹配 Dialogue: 0,0:21:59.61,0:22:03.21,Default,,0,0,0,,并把匹配结果传递给实例化器 Dialogue: 0,0:22:03.39,0:22:06.03,Default,,0,0,0,,实例化器做出更改 并将其返回给匹配器 Dialogue: 0,0:22:06.11,0:22:08.49,Default,,0,0,0,,教授:不是直接更改 而是生成新的表达式 Dialogue: 0,0:22:09.61,0:22:18.43,Default,,0,0,0,,新表达式中的模式变量都被左边式子中所匹配的值所替换 Dialogue: 0,0:22:18.99,0:22:23.80,Default,,0,0,0,,也就是右边式子中的那些骨架变量 或者说求值变量 Dialogue: 0,0:22:25.20,0:22:27.08,Default,,0,0,0,,学生:然后它要回传给匹配器么? Dialogue: 0,0:22:27.20,0:22:32.32,Default,,0,0,0,,教授:然后要再进行一轮 直到表达式不再变化 Dialogue: 0,0:22:33.31,0:22:37.00,Default,,0,0,0,,学生:感觉这样递归循环似乎有些危险 Dialogue: 0,0:22:37.20,0:22:42.00,Default,,0,0,0,,教授:你说得很对 如果你定义的规则不好-- Dialogue: 0,0:22:42.00,0:22:45.53,Default,,0,0,0,,你发明的任何语言 如果它可以做任何事情 Dialogue: 0,0:22:45.72,0:22:48.40,Default,,0,0,0,,你就可能写出无限循环的程序 Dialogue: 0,0:22:49.37,0:22:55.07,Default,,0,0,0,,确实 诸如代数处理 这样的过程可能会产生无限循环 Dialogue: 0,0:23:01.05,0:23:01.52,Default,,0,0,0,,教授:请讲 Dialogue: 0,0:23:01.79,0:23:05.90,Default,,0,0,0,,学生:一些语言的设计者觉得这个特性非常重要 Dialogue: 0,0:23:05.93,0:23:12.03,Default,,0,0,0,,以至于它应该是语言的一部分 比如Scheme Dialogue: 0,0:23:12.03,0:23:13.96,Default,,0,0,0,,你的观点是-- Dialogue: 0,0:23:13.96,0:23:15.08,Default,,0,0,0,,老师:语言的什么特性? Dialogue: 0,0:23:15.79,0:23:17.26,Default,,0,0,0,,学生:模式匹配 Dialogue: 0,0:23:17.26,0:23:22.03,Default,,0,0,0,,所有应用的这些规则应该 --- Dialogue: 0,0:23:22.03,0:23:23.70,Default,,0,0,0,,教授:你是说像 Prolog 那样? Dialogue: 0,0:23:23.70,0:23:26.60,Default,,0,0,0,,学生:类似 Prolog 但更加通用的-- Dialogue: 0,0:23:26.60,0:23:27.64,Default,,0,0,0,,教授:这是可行的 Dialogue: 0,0:23:28.46,0:23:32.30,Default,,0,0,0,,好了 我是觉得吧…… 恩…… Dialogue: 0,0:23:33.16,0:23:36.49,Default,,0,0,0,,我可以教你怎么做 这样你就不用依靠语言的设计者 Dialogue: 0,0:23:40.92,0:23:42.75,Default,,0,0,0,,教授:我们可以自己来实现 Dialogue: 0,0:23:45.28,0:23:45.63,Default,,0,0,0,,下课 Dialogue: 0,0:23:45.63,0:23:50.63,Default,,0,0,0,,[音乐] Dialogue: 0,0:23:50.63,0:23:53.13,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:23:53.13,0:23:55.63,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:24:00.32,0:24:06.76,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:24:07.07,0:24:10.52,Declare,,0,0,0,,{\an2\fad(500,500)}模式匹配:基于规则的代换 Dialogue: 0,0:24:14.08,0:24:15.80,Default,,0,0,0,,好 上课 Dialogue: 0,0:24:15.80,0:24:17.21,Default,,0,0,0,,现在 我得告诉你们它是如何运作的 Dialogue: 0,0:24:20.00,0:24:24.11,Default,,0,0,0,,它很容易分成很多小份 Dialogue: 0,0:24:24.80,0:24:26.54,Default,,0,0,0,,现在 我们先看一下匹配器 Dialogue: 0,0:24:28.72,0:24:31.42,Default,,0,0,0,,匹配器的结构是像下面这样的 Dialogue: 0,0:24:32.86,0:24:45.12,Default,,0,0,0,,它是一个盒子 它的输入是一个表达式和一个模式 Dialogue: 0,0:24:52.09,0:24:53.95,Default,,0,0,0,,还有个输入是一本词典 Dialogue: 0,0:25:01.71,0:25:08.67,Default,,0,0,0,,要记住 词典把模式变量映射到匹配的值上 Dialogue: 0,0:25:09.15,0:25:11.05,Default,,0,0,0,,它的输出是另一本词典 Dialogue: 0,0:25:18.24,0:25:25.53,Default,,0,0,0,,除了旧词典中已有的内容 新词典中还产生的新的匹配 Dialogue: 0,0:25:28.00,0:25:28.83,Default,,0,0,0,,这就是匹配器 Dialogue: 0,0:25:33.87,0:25:36.54,Default,,0,0,0,,这是一个相当复杂的程序 Dialogue: 0,0:25:37.20,0:25:41.58,Default,,0,0,0,,请大家看看这里的投影 请看 Dialogue: 0,0:25:41.98,0:25:43.87,Default,,0,0,0,,哈哈 真是相当复杂 Dialogue: 0,0:25:44.43,0:25:45.87,Default,,0,0,0,,我只想让大家看一下它的轮廓 Dialogue: 0,0:25:46.78,0:25:49.85,Default,,0,0,0,,其实现细节太复杂了 Dialogue: 0,0:25:51.72,0:25:59.24,Default,,0,0,0,,然而 这是一个庞大的程序 它有很多这样的缩进的结构 Dialogue: 0,0:26:00.09,0:26:05.28,Default,,0,0,0,,在最外层 -- 不要去读这些代码 宏观地看 Dialogue: 0,0:26:05.43,0:26:10.36,Default,,0,0,0,,这里有一个分情况分析 而这些就是不同的情况 Dialogue: 0,0:26:12.09,0:26:16.19,Default,,0,0,0,,现在 我们将要深入细节 Dialogue: 0,0:26:16.67,0:26:18.60,Default,,0,0,0,,试图理解它是如何工作的 Dialogue: 0,0:26:20.08,0:26:22.35,Default,,0,0,0,,我们来看第一张幻灯片 Dialogue: 0,0:26:23.55,0:26:27.93,Default,,0,0,0,,它展示了匹配器的宏观结构 Dialogue: 0,0:26:28.81,0:26:36.33,Default,,0,0,0,,我们看到匹配器 它需要的参数有:模式、表达式和词典 Dialogue: 0,0:26:38.57,0:26:40.40,Default,,0,0,0,,这里是一个cond语句 Dialogue: 0,0:26:41.24,0:26:45.61,Default,,0,0,0,,它有许多不同情况 我们省略了一些代码 Dialogue: 0,0:26:46.62,0:26:48.62,Default,,0,0,0,,这个是我想让大家注意的 通用情况 Dialogue: 0,0:26:50.52,0:26:53.28,Default,,0,0,0,,考虑这个通用模式 它是个非常重要的模式 Dialogue: 0,0:26:56.32,0:27:01.61,Default,,0,0,0,,问题是我们需要同时地检查这两棵树 Dialogue: 0,0:27:02.50,0:27:08.03,Default,,0,0,0,,一棵树是表达式 另一棵树是模式 Dialogue: 0,0:27:08.59,0:27:10.11,Default,,0,0,0,,我们需要在它们之间进行匹配 Dialogue: 0,0:27:11.37,0:27:16.38,Default,,0,0,0,,使得表达式的子表达式会与模式的子表达式相匹配 Dialogue: 0,0:27:18.38,0:27:23.44,Default,,0,0,0,,我们深入研究一下 假设我有一个模式 Dialogue: 0,0:27:23.93,0:27:31.24,Default,,0,0,0,,这个是模式是 一个叫做x的表达式 乘以 Dialogue: 0,0:27:32.44,0:27:35.53,Default,,0,0,0,,乘以一个我们叫做y的表达式 Dialogue: 0,0:27:39.12,0:27:42.04,Default,,0,0,0,,再加上 刚才的表达式y 两个y必须是相同的表达式 Dialogue: 0,0:27:45.21,0:27:47.53,Default,,0,0,0,,我们在考察 乘式的和 Dialogue: 0,0:27:48.99,0:27:54.78,Default,,0,0,0,,其中 乘法和加法的第二个参数都是相同的 Dialogue: 0,0:27:57.02,0:27:58.84,Default,,0,0,0,,这是我们想要匹配像这样的表达式 Dialogue: 0,0:27:59.60,0:28:02.04,Default,,0,0,0,,它作为一个模式看起来像这个样子 Dialogue: 0,0:28:03.02,0:28:04.01,Default,,0,0,0,,这是一课树 Dialogue: 0,0:28:04.94,0:28:06.25,Default,,0,0,0,,它包含了一个加号 Dialogue: 0,0:28:08.08,0:28:20.25,Default,,0,0,0,,还有乘号 以及模式变量(? x)和(? y) Dialogue: 0,0:28:21.36,0:28:22.73,Default,,0,0,0,,还有模式变量(? y) Dialogue: 0,0:28:24.92,0:28:26.94,Default,,0,0,0,,这只是把表结构换了种写法 两者其实是一样的 Dialogue: 0,0:28:28.75,0:28:31.76,Default,,0,0,0,,我们先演示一个成功的匹配是如何运行的 Dialogue: 0,0:28:32.49,0:28:39.85,Default,,0,0,0,,这个模式匹配表达式 (+ (* 3 x) x) Dialogue: 0,0:28:42.41,0:28:43.36,Default,,0,0,0,,这是另一棵个树 Dialogue: 0,0:28:44.33,0:28:56.06,Default,,0,0,0,,它是3乘以x的积加上x Dialogue: 0,0:28:59.44,0:29:03.02,Default,,0,0,0,,所以我要做的是 同时遍历这两棵树 Dialogue: 0,0:29:04.41,0:29:07.82,Default,,0,0,0,,我想这样遍历它们 Dialogue: 0,0:29:08.67,0:29:12.96,Default,,0,0,0,,我会比较它们是否一样 Dialogue: 0,0:29:12.96,0:29:14.32,Default,,0,0,0,,这是一个复合对象 Dialogue: 0,0:29:15.21,0:29:17.26,Default,,0,0,0,,我们先看它的左分支 Dialogue: 0,0:29:17.26,0:29:18.14,Default,,0,0,0,,这可能是car部分 Dialogue: 0,0:29:18.56,0:29:21.21,Default,,0,0,0,,它们匹配吗?恩 两个加号成功匹配 Dialogue: 0,0:29:21.68,0:29:24.20,Default,,0,0,0,,但是下一个对象是复合的 Dialogue: 0,0:29:24.20,0:29:24.84,Default,,0,0,0,,我们看一下它 Dialogue: 0,0:29:25.20,0:29:26.80,Default,,0,0,0,,这个也匹配了 Dialogue: 0,0:29:26.80,0:29:27.79,Default,,0,0,0,,它们都是星号 Dialogue: 0,0:29:28.51,0:29:30.24,Default,,0,0,0,,现在……哦! Dialogue: 0,0:29:30.40,0:29:33.60,Default,,0,0,0,,这是模式变量 它和3相匹配 Dialogue: 0,0:29:34.27,0:29:35.92,Default,,0,0,0,,记住 现在x等于3 Dialogue: 0,0:29:36.36,0:29:37.37,Default,,0,0,0,,把它记录在词典中 Dialogue: 0,0:29:37.56,0:29:40.73,Default,,0,0,0,,遍历过程中 词典紧随着我们 并告诉我们:x等于3 Dialogue: 0,0:29:41.45,0:29:45.87,Default,,0,0,0,,x等于3 y等于x 但这两个是不同意义上的x Dialogue: 0,0:29:46.83,0:29:51.20,Default,,0,0,0,,那个是模式变量x 而这个是模式变量y匹配表达式x Dialogue: 0,0:29:53.61,0:29:57.76,Default,,0,0,0,,这是模式变量y 它已经有值了 并且值是x Dialogue: 0,0:29:58.36,0:30:00.06,Default,,0,0,0,,这是x么? 当然是 Dialogue: 0,0:30:00.06,0:30:00.75,Default,,0,0,0,,好的 Dialogue: 0,0:30:02.03,0:30:02.78,Default,,0,0,0,,完事儿了 Dialogue: 0,0:30:03.39,0:30:08.09,Default,,0,0,0,,现在 我有一本词典 它在遍历过程中不断积累 Dialogue: 0,0:30:11.42,0:30:14.51,Default,,0,0,0,,现在让我们看看这个一般情况 然后看看它如何工作 Dialogue: 0,0:30:15.88,0:30:16.51,Default,,0,0,0,,这里.. Dialogue: 0,0:30:17.20,0:30:21.66,Default,,0,0,0,,我传入一个模式 一个表达式 和一本词典 Dialogue: 0,0:30:22.38,0:30:27.50,Default,,0,0,0,,这里的情况比较复杂 -- 它是通用情况 Dialogue: 0,0:30:29.98,0:30:34.80,Default,,0,0,0,,一般来说 表达式由两部分组成:左部分和右部分 Dialogue: 0,0:30:35.45,0:30:38.81,Default,,0,0,0,,在Lisp系统中 复合对象都是由两部分组成的 Dialogue: 0,0:30:40.03,0:30:41.23,Default,,0,0,0,,现在我们有什么呢? Dialogue: 0,0:30:41.88,0:30:48.84,Default,,0,0,0,,我将会用已有的这本词典 继续匹配模式和表达式的car部分 Dialogue: 0,0:30:50.30,0:30:53.12,Default,,0,0,0,,这个匹配过程会产生一本新词典 Dialogue: 0,0:30:54.14,0:30:57.26,Default,,0,0,0,,我将用它来匹配它们的cdr部分 Dialogue: 0,0:30:58.51,0:31:02.09,Default,,0,0,0,,这就是词典是如何在整个结构中遍历、线索的 Dialogue: 0,0:31:03.66,0:31:07.53,Default,,0,0,0,,匹配完car和cdr部分后得到的词典 Dialogue: 0,0:31:10.12,0:31:12.41,Default,,0,0,0,,会作为值返回给上级 Dialogue: 0,0:31:13.61,0:31:15.84,Default,,0,0,0,,匹配可能会在任何一个地方失败 Dialogue: 0,0:31:16.62,0:31:18.20,Default,,0,0,0,,比如说 可能会有这种情况 Dialogue: 0,0:31:18.36,0:31:27.18,Default,,0,0,0,,我们回过头来把这里改成4 这样就不会完全匹配 Dialogue: 0,0:31:29.13,0:31:34.81,Default,,0,0,0,,现在这两个不再匹配了 因为x应该 Dialogue: 0,0:31:34.93,0:31:37.34,Default,,0,0,0,,不好意思 这个y是x Dialogue: 0,0:31:37.82,0:31:40.12,Default,,0,0,0,,但是这里的y却又是4 Dialogue: 0,0:31:40.53,0:31:43.52,Default,,0,0,0,,语法上来说 x和4显然不相同 Dialogue: 0,0:31:44.59,0:31:48.81,Default,,0,0,0,,所以这个不会匹配成功 它会拒绝 匹配会失败 Dialogue: 0,0:31:50.19,0:31:56.08,Default,,0,0,0,,那么 因为先前产生的词典会作为输入送入匹配器 Dialogue: 0,0:31:56.52,0:31:58.28,Default,,0,0,0,,所以它必须能够传播失败 Dialogue: 0,0:31:58.57,0:32:01.04,Default,,0,0,0,,第一条语句就是用来判断失败的 Dialogue: 0,0:32:03.61,0:32:08.19,Default,,0,0,0,,如果证实出来这个模式不是原子的--- Dialogue: 0,0:32:08.50,0:32:11.45,Default,,0,0,0,,如果模式是原子的 将进入这里 这里我们还没有讨论过 Dialogue: 0,0:32:12.17,0:32:13.56,Default,,0,0,0,,如果模式不是原子的 Dialogue: 0,0:32:15.05,0:32:19.23,Default,,0,0,0,,但表达式是原子--也就是它不由小部分组成 Dialogue: 0,0:32:20.14,0:32:22.65,Default,,0,0,0,,那么匹配必然失败 因此我们返回'failed Dialogue: 0,0:32:23.64,0:32:30.78,Default,,0,0,0,,整理下思路 如果这个模式既不是原子的又不是模式变量的话 程序会来到这里 Dialogue: 0,0:32:30.96,0:32:32.51,Default,,0,0,0,,这是会使匹配失败的情况 Dialogue: 0,0:32:35.26,0:32:39.12,Default,,0,0,0,,好 让我们看这个里面的东西 Dialogue: 0,0:32:39.84,0:32:42.93,Default,,0,0,0,,首先需要知道 如果用原子模式来进行匹配会发生什么? Dialogue: 0,0:32:42.93,0:32:43.90,Default,,0,0,0,,这简单 Dialogue: 0,0:32:43.90,0:32:46.50,Default,,0,0,0,,不是由其它模式构成的模式 比如:foo Dialogue: 0,0:32:47.37,0:32:48.54,Default,,0,0,0,,这是个非常好的原子模式 Dialogue: 0,0:32:49.16,0:32:51.24,Default,,0,0,0,,让我们来看看 Dialogue: 0,0:32:52.08,0:32:55.82,Default,,0,0,0,,如果模式是原子的 而且表达式也原子的话 Dialogue: 0,0:32:56.80,0:33:01.85,Default,,0,0,0,,并且如果它俩是同一个东西 那么词典就跟之前一样 Dialogue: 0,0:33:03.08,0:33:04.00,Default,,0,0,0,,没有变化 Dialogue: 0,0:33:04.60,0:33:10.33,Default,,0,0,0,,就像刚才 +匹配+ *匹配* x匹配x Dialogue: 0,0:33:11.42,0:33:12.33,Default,,0,0,0,,就是那样 Dialogue: 0,0:33:13.07,0:33:16.81,Default,,0,0,0,,然而 如何模式和表达式并不相同的话 Dialogue: 0,0:33:17.32,0:33:21.36,Default,,0,0,0,,如果这是两个不同的原子对象 比如+和*相匹配 Dialogue: 0,0:33:22.44,0:33:23.40,Default,,0,0,0,,这样就失败了 Dialogue: 0,0:33:25.60,0:33:34.56,Default,,0,0,0,,或者说 如果模式是原子 但表达式是复合 那么匹配失败 Dialogue: 0,0:33:37.40,0:33:38.24,Default,,0,0,0,,这很简单 Dialogue: 0,0:33:38.81,0:33:43.61,Default,,0,0,0,,那么 那些各种各样的模式变量又是怎么处理的呢? Dialogue: 0,0:33:44.09,0:33:46.54,Default,,0,0,0,,我们有三类被命名了的模式变量 Dialogue: 0,0:33:47.39,0:33:52.03,Default,,0,0,0,,它们分别用于匹配:任意常量 任意变量 任意表达式 Dialogue: 0,0:33:53.82,0:34:00.14,Default,,0,0,0,,(? x) 表示匹配任意表达式 Dialogue: 0,0:34:01.18,0:34:04.54,Default,,0,0,0,,(?c x) 表示匹配任意常量 Dialogue: 0,0:34:04.73,0:34:07.29,Default,,0,0,0,,(?v x) 表示匹配任意变量 Dialogue: 0,0:34:08.96,0:34:09.79,Default,,0,0,0,,好的 我们要做什么呢? Dialogue: 0,0:34:10.51,0:34:16.94,Default,,0,0,0,,看这里 如果模式表示的是匹配任意常量 Dialogue: 0,0:34:17.53,0:34:20.57,Default,,0,0,0,,那么待匹配的表达式最好是一个常量 Dialogue: 0,0:34:21.48,0:34:23.53,Default,,0,0,0,,不然的话 匹配就会失败 Dialogue: 0,0:34:23.83,0:34:27.50,Default,,0,0,0,,如果是一个常量 那么我就需要扩充词典 Dialogue: 0,0:34:27.50,0:34:29.69,Default,,0,0,0,,扩充词典的方法则是: Dialogue: 0,0:34:30.70,0:34:37.76,Default,,0,0,0,,在旧词典后 附加一对模式与表达式的配对 Dialogue: 0,0:34:41.16,0:34:42.75,Default,,0,0,0,,因此 如果是匹配任意变量 Dialogue: 0,0:34:43.72,0:34:47.46,Default,,0,0,0,,我得通过匹配来核查表达式是否是变量 Dialogue: 0,0:34:47.46,0:34:50.09,Default,,0,0,0,,如果是的话 我就扩充词典 Dialogue: 0,0:34:50.38,0:34:54.65,Default,,0,0,0,,现在在原有词典基础上 我们又多了一项模式与表达式的匹配 Dialogue: 0,0:34:55.28,0:34:56.70,Default,,0,0,0,,这个过程返回一本新的词典 Dialogue: 0,0:34:58.88,0:35:04.16,Default,,0,0,0,,在这个词典中也有很多失败 因此需要检查 Dialogue: 0,0:35:04.16,0:35:07.50,Default,,0,0,0,,就比如 模式变量已经有一个值了 Dialogue: 0,0:35:09.23,0:35:16.17,Default,,0,0,0,,但我又用它匹配一个跟之前匹配的表达式不相同的表达式的话 Dialogue: 0,0:35:16.43,0:35:18.36,Default,,0,0,0,,那么在这里也会立即产生失败 Dialogue: 0,0:35:20.16,0:35:21.56,Default,,0,0,0,,我们后面再讨论 Dialogue: 0,0:35:22.91,0:35:29.36,Default,,0,0,0,,最后 匹配任意的表达式不需要在语法范畴做什么检查 Dialogue: 0,0:35:30.11,0:35:32.20,Default,,0,0,0,,只用扩充词典就行了 Dialogue: 0,0:35:34.76,0:35:38.32,Default,,0,0,0,,这就是一个完整的简单的匹配器 Dialogue: 0,0:35:39.28,0:35:41.37,Default,,0,0,0,,非常具有讽刺意味的一点是 Dialogue: 0,0:35:41.66,0:35:45.12,Default,,0,0,0,,现在 人们花了大价钱来请一些人编写 Dialogue: 0,0:35:45.46,0:35:47.52,Default,,0,0,0,,所谓的 “人工智能专家系统” Dialogue: 0,0:35:48.40,0:35:52.03,Default,,0,0,0,,也不过是像这样的一个匹配器和实例化器罢了 Dialogue: 0,0:35:53.56,0:35:56.94,Default,,0,0,0,,这很容易做 现在你也可以创业开个小公司了 Dialogue: 0,0:35:57.42,0:36:01.72,Default,,0,0,0,,然后 第二周忽悠风投给你投个几百万 Dialogue: 0,0:36:03.79,0:36:08.57,Default,,0,0,0,,我是想说 这种程序放在20年前是非凡的 Dialogue: 0,0:36:09.74,0:36:12.81,Default,,0,0,0,,但放到现在 它就是小菜一碟了 大一新生也可以学 Dialogue: 0,0:36:13.63,0:36:15.47,Default,,0,0,0,,这里是一个实例化器 Dialogue: 0,0:36:20.22,0:36:23.07,Default,,0,0,0,,可问题是 他们都去了赚钱了 而且比我的还多 Dialogue: 0,0:36:24.97,0:36:26.59,Default,,0,0,0,,在大学中确实是这样 Dialogue: 0,0:36:27.10,0:36:39.42,Default,,0,0,0,,实例化是用来将给定的表达式、词典和骨架生成新的表达式的 Dialogue: 0,0:36:44.35,0:36:45.69,Default,,0,0,0,,这个不是很难 Dialogue: 0,0:36:46.60,0:36:53.36,Default,,0,0,0,,我们在下一张幻灯片中简单地看下 Dialogue: 0,0:36:53.88,0:36:59.29,Default,,0,0,0,,用一本给定的词典去实例化一个骨架 这很简单 Dialogue: 0,0:36:59.68,0:37:03.29,Default,,0,0,0,,我们要做的 就是对骨架递归地做树遍历 Dialogue: 0,0:37:04.08,0:37:08.33,Default,,0,0,0,,所有的骨架变量---我叫它“骨架求值” Dialogue: 0,0:37:08.41,0:37:11.42,Default,,0,0,0,,这是我在这个程序中定义的抽象语法 Dialogue: 0,0:37:11.60,0:37:16.46,Default,,0,0,0,,在规则中 以冒号打头的就是骨架求值 Dialogue: 0,0:37:18.25,0:37:24.30,Default,,0,0,0,,在那种情况下 我要在词典中找答案 我们待会儿再讨论 Dialogue: 0,0:37:24.30,0:37:25.61,Default,,0,0,0,,我们看整体 Dialogue: 0,0:37:27.77,0:37:31.80,Default,,0,0,0,,这个过程是用一本字典来实例化一个骨架 Dialogue: 0,0:37:32.75,0:37:37.15,Default,,0,0,0,,我在这里定义一个内部循环 Dialogue: 0,0:37:38.14,0:37:39.85,Default,,0,0,0,,它要做的事情很简单 Dialogue: 0,0:37:40.17,0:37:43.50,Default,,0,0,0,,如果这个骨架是原子的 Dialogue: 0,0:37:44.60,0:37:47.45,Default,,0,0,0,,这种情况 它直接返回一个骨架作为结果 Dialogue: 0,0:37:48.84,0:37:51.87,Default,,0,0,0,,或者在通常情况下它是复合的 Dialogue: 0,0:37:52.60,0:37:59.40,Default,,0,0,0,,这种情况下 我通过一些实例化的结果构造表达式 Dialogue: 0,0:37:59.40,0:38:04.25,Default,,0,0,0,,递归调用这个循环 不断实例化骨架的car和cdr部分 Dialogue: 0,0:38:04.89,0:38:06.24,Default,,0,0,0,,这就是树的递归遍历 Dialogue: 0,0:38:08.41,0:38:14.36,Default,,0,0,0,,如果在骨架中有冒号表达式 那么这就是一个骨架求值 Dialogue: 0,0:38:14.96,0:38:22.64,Default,,0,0,0,,那么要做的事情是:找到冒号引导的表达式 -- 本例中 也就是CADR部分 Dialogue: 0,0:38:22.81,0:38:26.25,Default,,0,0,0,,这些是抽象语法 因此我能改变规则的表示 Dialogue: 0,0:38:27.52,0:38:32.73,Default,,0,0,0,,先不管求值过程如何实现 总之我要用这本词典对表达式求值 Dialogue: 0,0:38:32.90,0:38:34.65,Default,,0,0,0,,我们以后再仔细讨论 Dialogue: 0,0:38:36.12,0:38:38.35,Default,,0,0,0,,求值的结果就是答案 Dialogue: 0,0:38:39.68,0:38:43.66,Default,,0,0,0,,这条初始化语句 通过给它传递整个骨架循环来启动它 Dialogue: 0,0:38:44.44,0:38:47.04,Default,,0,0,0,,这些调用又会被分成小块的递归调用 Dialogue: 0,0:38:49.63,0:38:56.48,Default,,0,0,0,,那么 求值过程里面发生了些什么 Dialogue: 0,0:38:57.18,0:38:59.07,Default,,0,0,0,,我无法详尽地给你们解释 Dialogue: 0,0:38:59.98,0:39:01.34,Default,,0,0,0,,我就大致说一下 Dialogue: 0,0:39:01.56,0:39:03.74,Default,,0,0,0,,之后 我们再深入地讨论 Dialogue: 0,0:39:05.29,0:39:10.81,Default,,0,0,0,,在一本词典的环境下 求值一个表达式 Dialogue: 0,0:39:11.90,0:39:14.17,Default,,0,0,0,,如果表达式是原子的 Dialogue: 0,0:39:15.04,0:39:16.22,Default,,0,0,0,,就在词典中进行查找 Dialogue: 0,0:39:18.60,0:39:19.87,Default,,0,0,0,,这没啥 Dialogue: 0,0:39:20.57,0:39:23.66,Default,,0,0,0,,难点在这里 Dialogue: 0,0:39:23.83,0:39:28.28,Default,,0,0,0,,我将要应用表达式的car部分对应的一个过程 Dialogue: 0,0:39:29.44,0:39:31.68,Default,,0,0,0,,这个过程是在“某个地方”查找得到的--我们以后讨论 Dialogue: 0,0:39:32.14,0:39:34.20,Default,,0,0,0,,我想请大家注意一下 这之中有一些“魔法” Dialogue: 0,0:39:34.67,0:39:38.72,Default,,0,0,0,,这个魔法将在不久后“施展”出来 但不是在今天 Dialogue: 0,0:39:40.00,0:39:46.51,Default,,0,0,0,,我们在词典中查找表达式剩余部分对应的值 Dialogue: 0,0:39:48.56,0:39:50.88,Default,,0,0,0,,我还不想让你们关注细节 Dialogue: 0,0:39:51.44,0:39:53.44,Default,,0,0,0,,我想让大家意识到这里还有很多代码 Dialogue: 0,0:39:54.17,0:39:56.75,Default,,0,0,0,,我们以后再详细讨论 Dialogue: 0,0:39:59.04,0:40:00.88,Default,,0,0,0,,但是 魔法就到此结束了 Dialogue: 0,0:40:02.57,0:40:06.96,Default,,0,0,0,,这部分利用Lisp的神奇力量 不过也就到此为止了 Dialogue: 0,0:40:10.25,0:40:13.56,Default,,0,0,0,,我们介绍了匹配和实例化 Dialogue: 0,0:40:15.05,0:40:16.60,Default,,0,0,0,,这一节有疑问么? Dialogue: 0,0:40:28.10,0:40:29.80,Default,,0,0,0,,学生:我有一个问题 Dialogue: 0,0:40:29.80,0:40:30.43,Default,,0,0,0,,教授:请讲 Dialogue: 0,0:40:30.43,0:40:32.56,Default,,0,0,0,,学生:您能切到前张幻灯片上吗? Dialogue: 0,0:40:33.60,0:40:35.56,Default,,0,0,0,,是关于定义匹配模式的 Dialogue: 0,0:40:36.16,0:40:40.76,Default,,0,0,0,,教授:好的 你想看定义匹配模式的全部的幻灯片 Dialogue: 0,0:40:40.76,0:40:43.06,Default,,0,0,0,,有人能帮我把投影仪--- Dialogue: 0,0:40:43.06,0:40:45.16,Default,,0,0,0,,这是最大的规模 Dialogue: 0,0:40:45.31,0:40:46.40,Default,,0,0,0,,你想看哪一部分? Dialogue: 0,0:40:46.76,0:40:49.96,Default,,0,0,0,,学生:呃 最上面吧 Dialogue: 0,0:40:49.96,0:40:53.76,Default,,0,0,0,,就是传递失败的那一部分 Dialogue: 0,0:40:54.52,0:40:55.21,Default,,0,0,0,,教授:恩 Dialogue: 0,0:40:55.64,0:40:59.33,Default,,0,0,0,,学生:基本的想法是把错误返回给词典 是么? Dialogue: 0,0:40:59.33,0:41:04.25,Default,,0,0,0,,教授:所谓的词典 就是所是匹配的答案 对吧? Dialogue: 0,0:41:05.16,0:41:09.80,Default,,0,0,0,,要么它是一些配对 Dialogue: 0,0:41:11.07,0:41:14.03,Default,,0,0,0,,要么根本就没有配对 Dialogue: 0,0:41:14.46,0:41:14.97,Default,,0,0,0,,学生:对 Dialogue: 0,0:41:15.26,0:41:17.83,Default,,0,0,0,,教授:这里 事实上 Dialogue: 0,0:41:17.83,0:41:22.60,Default,,0,0,0,,因为一个匹配过程会向另一个匹配过程传递词典 Dialogue: 0,0:41:22.80,0:41:24.65,Default,,0,0,0,,可以在这里的一般情况中看到 Dialogue: 0,0:41:25.12,0:41:27.93,Default,,0,0,0,,这是一个匹配过程传递词典到另一个匹配过程 Dialogue: 0,0:41:28.14,0:41:34.16,Default,,0,0,0,,我是用匹配car部分得到的词典来匹配cdr部分的 Dialogue: 0,0:41:36.06,0:41:37.08,Default,,0,0,0,,这里的代码就是这个意思 Dialogue: 0,0:41:37.29,0:41:40.30,Default,,0,0,0,,正因为如此 如果对car部分的匹配失败了 Dialogue: 0,0:41:41.23,0:41:45.44,Default,,0,0,0,,匹配cdr部分的时候就有必要传播失败 Dialogue: 0,0:41:45.95,0:41:46.96,Default,,0,0,0,,第一行就是用于传播失败 Dialogue: 0,0:41:48.26,0:41:51.73,Default,,0,0,0,,学生:好 但我还是不明白匹配 -- Dialogue: 0,0:41:51.73,0:41:54.24,Default,,0,0,0,,从匹配的实例出来的是什么? Dialogue: 0,0:41:54.73,0:41:56.00,Default,,0,0,0,,教授:有两种可能的情况 Dialogue: 0,0:41:56.33,0:41:59.15,Default,,0,0,0,,一种是符号'failed 意味匹配失败 Dialogue: 0,0:41:59.53,0:41:59.93,Default,,0,0,0,,学生:对 Dialogue: 0,0:41:59.93,0:42:03.87,Default,,0,0,0,,教授:或者是某种映射 -- 现在这还是一个抽象的东西 Dialogue: 0,0:42:04.16,0:42:05.68,Default,,0,0,0,,你需要知道它的结构 Dialogue: 0,0:42:06.49,0:42:13.96,Default,,0,0,0,,它们把匹配过程中 匹配成功的模式变量和值关联起来 Dialogue: 0,0:42:14.68,0:42:16.70,Default,,0,0,0,,学生:好 那么 Dialogue: 0,0:42:16.80,0:42:18.57,Default,,0,0,0,,教授:那是通过扩充词典实现的 Dialogue: 0,0:42:18.80,0:42:28.54,Default,,0,0,0,,学生:所以根据递归性质 如果匹配过程产生并传递了失败 Dialogue: 0,0:42:28.68,0:42:30.30,Default,,0,0,0,,那么第一种情况将捕获它 Dialogue: 0,0:42:30.40,0:42:33.56,Default,,0,0,0,,教授:并且传播它 不做任何其它处理 Dialogue: 0,0:42:33.56,0:42:34.83,Default,,0,0,0,,学生:哦 懂了 Dialogue: 0,0:42:35.50,0:42:37.36,Default,,0,0,0,,教授:这是传出失败最快的方法 Dialogue: 0,0:42:42.86,0:42:43.60,Default,,0,0,0,,请讲 Dialogue: 0,0:42:43.84,0:42:47.23,Default,,0,0,0,,学生:如果没有失败 那意味着我匹配了一个模式 Dialogue: 0,0:42:47.84,0:42:53.00,Default,,0,0,0,,我会扩充词典并且传递表达式中的模式 Dialogue: 0,0:42:55.21,0:42:58.43,Default,,0,0,0,,但是 代换并不是发生在这 对吧? Dialogue: 0,0:42:58.43,0:42:59.03,Default,,0,0,0,,是吧? Dialogue: 0,0:42:59.03,0:42:59.46,Default,,0,0,0,,教授:你是对的 Dialogue: 0,0:42:59.46,0:43:02.40,Default,,0,0,0,,这里没有可供代换的骨架 因此不会发生代换 Dialogue: 0,0:43:02.40,0:43:03.06,Default,,0,0,0,,学生:好 那么 Dialogue: 0,0:43:03.06,0:43:07.16,Default,,0,0,0,,教授:我们这里所做的 是为后面的代换准备词典 Dialogue: 0,0:43:08.25,0:43:12.43,Default,,0,0,0,,学生:词典的数据结构是什么呢?是有序对么? Dialogue: 0,0:43:12.72,0:43:15.96,Default,,0,0,0,,教授:那个 那个还没有告诉你 Dialogue: 0,0:43:15.96,0:43:16.89,Default,,0,0,0,,它还是一个抽象的东西 Dialogue: 0,0:43:17.06,0:43:17.56,Default,,0,0,0,,学生:哦 Dialogue: 0,0:43:17.56,0:43:18.90,Default,,0,0,0,,教授:你为什么要知道呢? Dialogue: 0,0:43:18.90,0:43:21.64,Default,,0,0,0,,它是一个函数 仅仅是一个函数 Dialogue: 0,0:43:21.69,0:43:22.33,Default,,0,0,0,,学生:我想知道它的原因是-- Dialogue: 0,0:43:22.33,0:43:24.17,Default,,0,0,0,,教授:这个抽象函数表现地像有序对 Dialogue: 0,0:43:25.12,0:43:28.44,Default,,0,0,0,,它可以用一系列的表通过链接来实现 Dialogue: 0,0:43:29.06,0:43:32.43,Default,,0,0,0,,它也可以用一些酷炫的表机制来实现 Dialogue: 0,0:43:32.56,0:43:34.16,Default,,0,0,0,,它也可以实现为一个函数 Dialogue: 0,0:43:35.80,0:43:37.40,Default,,0,0,0,,我可以把它写成一个函数 Dialogue: 0,0:43:39.02,0:43:39.87,Default,,0,0,0,,但我不会告诉你具体细节 Dialogue: 0,0:43:40.84,0:43:43.08,Default,,0,0,0,,这是George的事情 由他来构建这个结构 Dialogue: 0,0:43:49.56,0:43:52.06,Default,,0,0,0,,我知道 你特别想知道它的具体结构 Dialogue: 0,0:43:52.36,0:43:54.19,Default,,0,0,0,,但我不打算让你那么做 Dialogue: 0,0:43:54.43,0:43:59.23,Default,,0,0,0,,学生:恩 最后一个问题 扩充到词典中的重要信息是什么? Dialogue: 0,0:43:59.74,0:44:02.08,Default,,0,0,0,,我想 可能是匹配发现的模式 Dialogue: 0,0:44:02.73,0:44:04.83,Default,,0,0,0,,教授:是的 那些与表达式相匹配的模式 Dialogue: 0,0:44:04.83,0:44:09.30,Default,,0,0,0,,我们想要得到模式 只不过在本例中这些都是模式变量 对吧? Dialogue: 0,0:44:09.85,0:44:12.89,Default,,0,0,0,,这三种扩充词典的情况都是模式变量 Dialogue: 0,0:44:13.20,0:44:13.50,Default,,0,0,0,,学生:恩 Dialogue: 0,0:44:14.48,0:44:18.75,Default,,0,0,0,,教授:所以 在词典就有一个模式变量与一个值对应 Dialogue: 0,0:44:19.45,0:44:22.11,Default,,0,0,0,,这个值是所匹配的表达式 Dialogue: 0,0:44:23.31,0:44:29.63,Default,,0,0,0,,词典就是遍历过程中记录下来的所有匹配 Dialogue: 0,0:44:30.54,0:44:34.41,Default,,0,0,0,,我会以原有词典为基础 创建一本新词典 Dialogue: 0,0:44:35.12,0:44:38.35,Default,,0,0,0,,新增的内容就是新发现的匹配 Dialogue: 0,0:44:39.98,0:44:43.73,Default,,0,0,0,,学生:我不理解为什么不能在发现匹配后立即进行代换 Dialogue: 0,0:44:43.73,0:44:44.80,Default,,0,0,0,,教授:哦 那时候还不能代换 Dialogue: 0,0:44:44.81,0:44:46.62,Default,,0,0,0,,因为我不知道骨架啊! Dialogue: 0,0:44:47.58,0:44:49.66,Default,,0,0,0,,模式和匹配器都是独立的单元 Dialogue: 0,0:44:49.66,0:44:51.00,Default,,0,0,0,,学生:哦 我明白了 Dialogue: 0,0:44:51.00,0:44:51.50,Default,,0,0,0,,教授:懂了吧? Dialogue: 0,0:44:51.50,0:44:51.90,Default,,0,0,0,,学生:恩 Dialogue: 0,0:44:51.90,0:44:57.23,Default,,0,0,0,,教授:我用这个匹配器进行匹配 如果匹配了就可以实例化 Dialogue: 0,0:44:58.20,0:44:59.50,Default,,0,0,0,,学生:知道了 Dialogue: 0,0:45:00.54,0:45:03.88,Default,,0,0,0,,学生:您可以再求解一次黑板上的例子么 Dialogue: 0,0:45:04.89,0:45:06.93,Default,,0,0,0,,什么东西返回给了匹配器 Dialogue: 0,0:45:06.93,0:45:08.00,Default,,0,0,0,,教授:当然可以 Dialogue: 0,0:45:08.26,0:45:09.74,Default,,0,0,0,,来看这个例子 Dialogue: 0,0:45:10.67,0:45:15.45,Default,,0,0,0,,在这里当我遍历这个结构的时候 我遇到了(? x) Dialogue: 0,0:45:16.67,0:45:20.54,Default,,0,0,0,,我有一本词典 不过此时假设它是空的 Dialogue: 0,0:45:21.56,0:45:25.36,Default,,0,0,0,,一本空词典 然后我匹配到了x为3 Dialogue: 0,0:45:26.62,0:45:33.60,Default,,0,0,0,,从此以后 词典中就记录了 x与3匹配 对吧 Dialogue: 0,0:45:33.64,0:45:36.09,Default,,0,0,0,,继续遍历 然后遇到(? y) Dialogue: 0,0:45:36.89,0:45:39.20,Default,,0,0,0,,它是一个特殊的x 这是模式变量x Dialogue: 0,0:45:39.79,0:45:41.37,Default,,0,0,0,,我看到(? y) 模式变量y Dialogue: 0,0:45:42.17,0:45:47.74,Default,,0,0,0,,词典说 模式变量y的值是符号x Dialogue: 0,0:45:48.99,0:45:51.20,Default,,0,0,0,,因为这里已经匹配过了 Dialogue: 0,0:45:52.43,0:45:54.52,Default,,0,0,0,,所以此时 词典中包含两个条目 Dialogue: 0,0:45:55.45,0:45:59.90,Default,,0,0,0,,模式变量x是数字3 模式变量y是表达式x Dialogue: 0,0:46:01.95,0:46:04.11,Default,,0,0,0,,现在继续进行遍历 Dialogue: 0,0:46:04.23,0:46:07.45,Default,,0,0,0,,这里 模式变量y想要和4匹配 Dialogue: 0,0:46:08.06,0:46:10.65,Default,,0,0,0,,但是这个不可能 产生失败 Dialogue: 0,0:46:14.30,0:46:15.48,Default,,0,0,0,,谢谢 下课 Dialogue: 0,0:46:16.76,0:46:25.02,Default,,0,0,0,,[音乐] Dialogue: 0,0:46:25.07,0:46:27.45,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:46:27.47,0:46:30.00,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教 Dialogue: 0,0:46:48.19,0:46:54.75,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:46:55.20,0:46:58.04,Declare,,0,0,0,,{\an2\fad(500,500)}模式匹配:基于规则的代换 Dialogue: 0,0:47:02.38,0:47:05.68,Default,,0,0,0,,这是大家首次看到如此庞大而复杂的程序 Dialogue: 0,0:47:07.34,0:47:09.90,Default,,0,0,0,,当然 本项课程的目的之一就在于 Dialogue: 0,0:47:09.90,0:47:12.97,Default,,0,0,0,,是让大家可以读懂这么庞大的程序 而完全不用害怕它 Dialogue: 0,0:47:13.76,0:47:16.33,Default,,0,0,0,,这个程序仅仅只有4页代码而已 Dialogue: 0,0:47:17.08,0:47:19.23,Default,,0,0,0,,课程结业后 我希望就算是50页长的程序 Dialogue: 0,0:47:20.27,0:47:21.80,Default,,0,0,0,,也吓不倒你们 Dialogue: 0,0:47:22.97,0:47:28.20,Default,,0,0,0,,我不是说让你们“左耳朵进 右耳朵出”地读程序 Dialogue: 0,0:47:29.20,0:47:31.70,Default,,0,0,0,,你应该体会这个程序 Dialogue: 0,0:47:31.70,0:47:34.83,Default,,0,0,0,,然后好好思考 因为它是一个很大的程序 Dialogue: 0,0:47:35.32,0:47:38.92,Default,,0,0,0,,在这个程序中有很多东西 Dialogue: 0,0:47:41.24,0:47:46.03,Default,,0,0,0,,我已经介绍了我们正在实现的 -- 基于规则代换的模式匹配语言 Dialogue: 0,0:47:46.81,0:47:47.64,Default,,0,0,0,,给你们看了一些规则 Dialogue: 0,0:47:48.36,0:47:51.24,Default,,0,0,0,,我已经告诉大家匹配和实例化 Dialogue: 0,0:47:51.55,0:47:53.32,Default,,0,0,0,,它们是使规则生效的“阴阳两极” Dialogue: 0,0:47:54.24,0:47:56.35,Default,,0,0,0,,现在我们需要理解控制结构 Dialogue: 0,0:47:56.86,0:48:00.32,Default,,0,0,0,,就是这些规则是如何被用在表达式上 Dialogue: 0,0:48:01.08,0:48:03.84,Default,,0,0,0,,来指导代数化简的 Dialogue: 0,0:48:06.92,0:48:09.58,Default,,0,0,0,,这也是非常复杂的 Dialogue: 0,0:48:12.09,0:48:19.48,Default,,0,0,0,,其中有很多循环 相互交织 错综复杂 Dialogue: 0,0:48:20.24,0:48:26.99,Default,,0,0,0,,一方面 我不得不检查 待化简表达式的每个子表达式 Dialogue: 0,0:48:29.00,0:48:29.93,Default,,0,0,0,,我们已经讲过了 Dialogue: 0,0:48:29.93,0:48:36.24,Default,,0,0,0,,这是在car、cdr部分做某种树形递归 Dialogue: 0,0:48:37.44,0:48:38.59,Default,,0,0,0,,就是那样 Dialogue: 0,0:48:38.84,0:48:42.46,Default,,0,0,0,,现在 在我每个遍历到的结点上 Dialogue: 0,0:48:43.47,0:48:48.76,Default,,0,0,0,,也就是我想要化简的(子)表达式 Dialogue: 0,0:48:49.20,0:48:51.07,Default,,0,0,0,,我需要应用所有的规则 Dialogue: 0,0:48:53.42,0:48:55.08,Default,,0,0,0,,每个规则都需要检查每个节点 Dialogue: 0,0:48:56.00,0:48:57.92,Default,,0,0,0,,我一直在这些规则中打转(循环) Dialogue: 0,0:49:01.66,0:49:05.48,Default,,0,0,0,,一个规则可能匹配 也可能不匹配 Dialogue: 0,0:49:07.50,0:49:10.62,Default,,0,0,0,,如果规则不匹配 那我就不关心了 Dialogue: 0,0:49:12.28,0:49:19.34,Default,,0,0,0,,如果规则匹配了 我就在那个结点用另一个表达式替换这个表达式 Dialogue: 0,0:49:20.08,0:49:22.89,Default,,0,0,0,,实际上 我创建了一个新表达式 它包含 Dialogue: 0,0:49:23.55,0:49:28.65,Default,,0,0,0,,它包含了所有的东西 新的值代换入骨架后的结果 Dialogue: 0,0:49:29.21,0:49:31.92,Default,,0,0,0,,也就是 在该层次上 把规则所对应的骨架实例化的结果 Dialogue: 0,0:49:32.72,0:49:37.37,Default,,0,0,0,,但我并不知道我所实例化出来的东西 是否是简化形式 Dialogue: 0,0:49:38.75,0:49:43.82,Default,,0,0,0,,所以我要对我刚刚构建好的东西调用化简器来简化它 Dialogue: 0,0:49:46.12,0:49:50.36,Default,,0,0,0,,完成后 我就可以将其构建进我想要的表达式中作为答案 Dialogue: 0,0:49:51.80,0:49:57.45,Default,,0,0,0,,这里的基本思想是 我们定义一个 “废料进-废料出”的化简器 Dialogue: 0,0:50:01.47,0:50:02.75,Default,,0,0,0,,它是一种递归调用的化简器 Dialogue: 0,0:50:03.58,0:50:08.84,Default,,0,0,0,,化简方法是:基本对象 比如变量就是最简形式的了 Dialogue: 0,0:50:10.78,0:50:13.28,Default,,0,0,0,,复合对象 -- 呃 我也不知道 Dialogue: 0,0:50:14.09,0:50:16.56,Default,,0,0,0,,而我要从简单的对象入手 Dialogue: 0,0:50:16.86,0:50:21.23,Default,,0,0,0,,通过假设它们都是由小块的基本对象组成的 Dialogue: 0,0:50:24.60,0:50:25.61,Default,,0,0,0,,这就是思路 Dialogue: 0,0:50:27.82,0:50:33.12,Default,,0,0,0,,现在如果我们看第一张投影 Dialogue: 0,0:50:33.88,0:50:37.13,Default,,0,0,0,,我们看到一个非常复杂的程序 就像我们之前看到的匹配器一样 Dialogue: 0,0:50:37.53,0:50:39.95,Default,,0,0,0,,它太复杂了 没有必要仔细阅读它 Dialogue: 0,0:50:41.92,0:50:43.61,Default,,0,0,0,,我只想让大家感受一下它的轮廓 Dialogue: 0,0:50:44.44,0:50:50.01,Default,,0,0,0,,也就是这个程序里面有很多子程序 Dialogue: 0,0:50:52.11,0:50:57.56,Default,,0,0,0,,这部分用于遍历表达式 Dialogue: 0,0:50:58.97,0:51:01.36,Default,,0,0,0,,这部分用于尝试规则 Dialogue: 0,0:51:02.52,0:51:05.60,Default,,0,0,0,,当然 我们也可以看看细节 Dialogue: 0,0:51:06.89,0:51:11.80,Default,,0,0,0,,来看第一张幻灯片 Dialogue: 0,0:51:13.40,0:51:17.36,Default,,0,0,0,,化简器由数个部分组成 Dialogue: 0,0:51:17.96,0:51:22.92,Default,,0,0,0,,回想一下 化简器接收一系列的规则 Dialogue: 0,0:51:23.92,0:51:27.20,Default,,0,0,0,,并生成一个使用该规则进行化简的程序 Dialogue: 0,0:51:30.04,0:51:32.60,Default,,0,0,0,,化简器在这里定义 Dialogue: 0,0:51:33.48,0:51:34.81,Default,,0,0,0,,接受一个规则集合 Dialogue: 0,0:51:36.16,0:51:38.68,Default,,0,0,0,,在the-rules被定义的上下文中 Dialogue: 0,0:51:39.24,0:51:41.48,Default,,0,0,0,,还定义了很多其它东西 Dialogue: 0,0:51:42.33,0:51:46.20,Default,,0,0,0,,而simplifier过程的返回结果则是 Dialogue: 0,0:51:46.41,0:51:50.80,Default,,0,0,0,,是一个已经定义好的过程 -- simplify-exp Dialogue: 0,0:51:52.46,0:51:57.71,Default,,0,0,0,,调用 (simplifier the-rules) 的返回值是 Dialogue: 0,0:51:58.17,0:52:03.21,Default,,0,0,0,,返回值是一个过程 是在该上下文中定义的simplify-exp过程 Dialogue: 0,0:52:05.23,0:52:08.83,Default,,0,0,0,,这是一个利用这些给定规则进行化简的过程 Dialogue: 0,0:52:15.04,0:52:15.96,Default,,0,0,0,,定义就是这样的 Dialogue: 0,0:52:17.45,0:52:21.79,Default,,0,0,0,,这些过程的前两个 这个和这个 Dialogue: 0,0:52:22.48,0:52:25.74,Default,,0,0,0,,它们一起 递归地遍历一个表达式 Dialogue: 0,0:52:26.97,0:52:30.20,Default,,0,0,0,,这个是任何表达式的通用化简方法 Dialogue: 0,0:52:30.94,0:52:33.23,Default,,0,0,0,,而这个过程用于化简表达式的子部分 Dialogue: 0,0:52:35.53,0:52:36.08,Default,,0,0,0,,没别的了 Dialogue: 0,0:52:37.04,0:52:39.90,Default,,0,0,0,,每个过程中 我们会做些复杂操作 包括尝试这些规则 Dialogue: 0,0:52:40.32,0:52:41.71,Default,,0,0,0,,现在 我们看看这些过程 Dialogue: 0,0:52:45.76,0:52:48.08,Default,,0,0,0,,我们先来讨论一下表达式的递归遍历 Dialogue: 0,0:52:48.57,0:52:51.68,Default,,0,0,0,,这是用一种很简单的方法完成的 Dialogue: 0,0:52:54.28,0:52:57.93,Default,,0,0,0,,这是一个小型的、嵌套的递归过程 Dialogue: 0,0:52:59.42,0:53:01.77,Default,,0,0,0,,这里有两个过程 --- Dialogue: 0,0:53:02.59,0:53:05.20,Default,,0,0,0,,一个是对整个表达式化简 Dialogue: 0,0:53:06.11,0:53:08.16,Default,,0,0,0,,另一个是对表达式的某部分化简 Dialogue: 0,0:53:09.44,0:53:10.97,Default,,0,0,0,,它们的原理都很简单 Dialogue: 0,0:53:12.12,0:53:16.86,Default,,0,0,0,,如果我想要化简的表达式是复合表达式 Dialogue: 0,0:53:17.04,0:53:18.32,Default,,0,0,0,,那么就对每一个部分进行化简 Dialogue: 0,0:53:19.95,0:53:22.32,Default,,0,0,0,,调用simplify-parts这个过程 Dialogue: 0,0:53:22.33,0:53:25.74,Default,,0,0,0,,会构造一个新的表达式 其中各个部分都是化简过的 Dialogue: 0,0:53:26.00,0:53:28.64,Default,,0,0,0,,我会在这里尝试那些应用规则 Dialogue: 0,0:53:30.86,0:53:34.22,Default,,0,0,0,,如果表达式不是复合的 而是一些简单的表达式 Dialogue: 0,0:53:34.76,0:53:37.13,Default,,0,0,0,,比如说是符号 或者'pi Dialogue: 0,0:53:38.16,0:53:39.79,Default,,0,0,0,,无论如何 我都需要尝试应用这些规则 Dialogue: 0,0:53:40.03,0:53:47.56,Default,,0,0,0,,因为 因为可能有将pi扩展成3.14159265358979....这样的规则 Dialogue: 0,0:53:48.46,0:53:49.08,Default,,0,0,0,,也许我不会这样做 Dialogue: 0,0:53:50.11,0:53:51.52,Default,,0,0,0,,但是没有理由不这样做 Dialogue: 0,0:53:52.75,0:53:57.53,Default,,0,0,0,,现在如果我对表达式的各部分化简 那就很简单了 Dialogue: 0,0:53:58.99,0:54:02.88,Default,,0,0,0,,要么表达式是空的 它没有更多的部分了 Dialogue: 0,0:54:03.71,0:54:05.08,Default,,0,0,0,,这种情况我返回一个空表达式 Dialogue: 0,0:54:05.72,0:54:10.52,Default,,0,0,0,,否则 我用cons构建一个新的表达式 Dialogue: 0,0:54:11.21,0:54:14.27,Default,,0,0,0,,新表达式的car部分是原表达式car的化简结果 Dialogue: 0,0:54:15.42,0:54:17.39,Default,,0,0,0,,然后化简表达式的其它其他部分作为新表达式的cdr部分 Dialogue: 0,0:54:21.08,0:54:23.88,Default,,0,0,0,,我用这种方式向大家展示这些的原因是 Dialogue: 0,0:54:24.88,0:54:30.12,Default,,0,0,0,,我想让大家感受到 这些不同模式在编程时非常重要 Dialogue: 0,0:54:32.20,0:54:34.00,Default,,0,0,0,,这段程序我可以换种写法 Dialogue: 0,0:54:34.00,0:54:36.99,Default,,0,0,0,,还有一种化简表达式的方法 Dialogue: 0,0:54:37.72,0:54:39.63,Default,,0,0,0,,这仅仅是一个小程序 Dialogue: 0,0:54:39.63,0:54:42.36,Default,,0,0,0,,我把它写到黑板上 让大家感受一下 Dialogue: 0,0:54:49.71,0:54:51.90,Default,,0,0,0,,你可以用这种惯用法来写程序 Dialogue: 0,0:54:59.30,0:55:03.13,Default,,0,0,0,,那么 如何化简表达式exp呢? Dialogue: 0,0:55:03.21,0:55:10.14,Default,,0,0,0,,在以下几种情况下 调用try-rules Dialogue: 0,0:55:11.12,0:55:15.72,Default,,0,0,0,,就像之前一样 如果表达式是复合的 Dialogue: 0,0:55:21.52,0:55:24.27,Default,,0,0,0,,如果是复合的 我要怎么做呢? Dialogue: 0,0:55:24.53,0:55:25.40,Default,,0,0,0,,我要化简它的每个部分 Dialogue: 0,0:55:26.01,0:55:27.80,Default,,0,0,0,,但是我已经有对cdr部分递归的过程了 Dialogue: 0,0:55:30.25,0:55:33.18,Default,,0,0,0,,一个被封装成高阶过程的通用模式 Dialogue: 0,0:55:34.09,0:55:34.46,Default,,0,0,0,,也就是map过程 Dialogue: 0,0:55:36.08,0:55:36.88,Default,,0,0,0,,我在这里写出来 Dialogue: 0,0:55:37.16,0:55:48.03,Default,,0,0,0,,(map simplify-exp exp) Dialogue: 0,0:55:49.00,0:55:54.59,Default,,0,0,0,,这是说 把simplify-exp这个过程应用在表达式的每个部分 Dialogue: 0,0:55:55.34,0:55:57.34,Default,,0,0,0,,然后把结果用cons组合成表 Dialogue: 0,0:56:00.92,0:56:04.38,Default,,0,0,0,,所以表中的每个元素都是化简过的 Dialogue: 0,0:56:05.45,0:56:08.23,Default,,0,0,0,,不是复合表达式的话 就不用化简了 Dialogue: 0,0:56:09.05,0:56:12.36,Default,,0,0,0,,所以不需要再写一个辅助函数来化简各个部分 Dialogue: 0,0:56:12.64,0:56:13.48,Default,,0,0,0,,这句代码就够了 Dialogue: 0,0:56:15.47,0:56:17.05,Default,,0,0,0,,所以有时候可以这样写 Dialogue: 0,0:56:17.84,0:56:18.70,Default,,0,0,0,,这个无关紧要 Dialogue: 0,0:56:21.16,0:56:26.27,Default,,0,0,0,,好现在看一下 -- 如何尝试规则 Dialogue: 0,0:56:27.70,0:56:31.60,Default,,0,0,0,,这里 幻灯片上有一堆复杂的东西 Dialogue: 0,0:56:33.68,0:56:35.28,Default,,0,0,0,,我要尝试对一个表达式施用规则 Dialogue: 0,0:56:36.36,0:56:39.96,Default,,0,0,0,,我现在尝试的表达式是最初表达式的子表达式 Dialogue: 0,0:56:40.43,0:56:43.88,Default,,0,0,0,,这是因为我之前特意安排要求遍历所有子表达式 Dialogue: 0,0:56:46.11,0:56:51.90,Default,,0,0,0,,所以这里的exp 就是最初表达式的子表达式 Dialogue: 0,0:56:52.49,0:56:57.71,Default,,0,0,0,,这里我们定义一个scan的过程 它用来尝试每一个规则 Dialogue: 0,0:56:58.72,0:57:00.33,Default,,0,0,0,,我们会在整个规则中扫描 Dialogue: 0,0:57:01.92,0:57:07.77,Default,,0,0,0,,它会通过不断取cdr部分来遍历整个规则 查找一条规则来施用 Dialogue: 0,0:57:09.37,0:57:11.96,Default,,0,0,0,,当找到一条规则 它的任务就完成了 Dialogue: 0,0:57:14.09,0:57:16.41,Default,,0,0,0,,我们来看一下try-rules是如何工作的 Dialogue: 0,0:57:17.74,0:57:21.02,Default,,0,0,0,,非常简单:就是顺序地扫描规则表 Dialogue: 0,0:57:21.96,0:57:23.26,Default,,0,0,0,,它 真的简单吗? Dialogue: 0,0:57:23.26,0:57:24.51,Default,,0,0,0,,不 这是个很庞大的程序 Dialogue: 0,0:57:25.55,0:57:28.57,Default,,0,0,0,,接收的参数是一系列的规则--它们是整个规则表的子表 Dialogue: 0,0:57:30.75,0:57:35.13,Default,,0,0,0,,我们已经查找了其中的一些 但它们都不符合 所以试试剩下的 Dialogue: 0,0:57:35.87,0:57:36.30,Default,,0,0,0,,尝试下一条 Dialogue: 0,0:57:36.40,0:57:37.63,Default,,0,0,0,,如果所有规则都尝试完了 Dialogue: 0,0:57:37.90,0:57:40.84,Default,,0,0,0,,那么 我就不能再对这个表达式做什么了 它已经是最简了 Dialogue: 0,0:57:42.35,0:57:47.26,Default,,0,0,0,,然而 如果还有规则需要扫描 Dialogue: 0,0:57:48.01,0:57:51.58,Default,,0,0,0,,那么从一个空的词典开始 Dialogue: 0,0:57:52.20,0:57:55.40,Default,,0,0,0,,用规则表中的第一条规则对表达式进行模式匹配 Dialogue: 0,0:57:57.07,0:57:58.84,Default,,0,0,0,,将得到的结果作为新的词典 Dialogue: 0,0:58:00.32,0:58:03.74,Default,,0,0,0,,如果失败了 就尝试剩余规则 Dialogue: 0,0:58:06.68,0:58:07.52,Default,,0,0,0,,这句代码就是这个意思 Dialogue: 0,0:58:08.52,0:58:10.33,Default,,0,0,0,,也就是说 丢弃那条规则 Dialogue: 0,0:58:11.10,0:58:15.05,Default,,0,0,0,,成功的话 我将取出第一条规则对应的骨架 Dialogue: 0,0:58:15.34,0:58:17.40,Default,,0,0,0,,利用得到的词典 来将其实例化 Dialogue: 0,0:58:17.93,0:58:20.80,Default,,0,0,0,,然后对结果化简 就得到了我想要的表达式 Dialogue: 0,0:58:24.20,0:58:25.96,Default,,0,0,0,,虽然这是一个复杂的程序 Dialogue: 0,0:58:26.25,0:58:28.72,Default,,0,0,0,,但是每个复杂程序都是由许多简单部分组成的 Dialogue: 0,0:58:29.77,0:58:33.12,Default,,0,0,0,,这里的递归模式非常复杂 Dialogue: 0,0:58:34.78,0:58:36.52,Default,,0,0,0,,最重要的事情就是:不要去思考它 Dialogue: 0,0:58:38.67,0:58:41.80,Default,,0,0,0,,如果去思考它的实际行为 Dialogue: 0,0:58:42.06,0:58:42.97,Default,,0,0,0,,大家就会迷惑 Dialogue: 0,0:58:45.31,0:58:45.71,Default,,0,0,0,,就算是我也会 Dialogue: 0,0:58:47.04,0:58:50.17,Default,,0,0,0,,没关系 可以多加练习 Dialogue: 0,0:58:51.52,0:58:52.46,Default,,0,0,0,,这些模式非常难 Dialogue: 0,0:58:54.17,0:58:55.42,Default,,0,0,0,,但是大家不用考虑它 Dialogue: 0,0:58:55.83,0:58:59.72,Default,,0,0,0,,关键点就是 好的编程或设计方法需要 Dialogue: 0,0:58:59.74,0:59:00.97,Default,,0,0,0,,知道什么是不需要考虑的 Dialogue: 0,0:59:03.05,0:59:06.06,Default,,0,0,0,,回到这张幻灯片上 Dialogue: 0,0:59:06.92,0:59:08.01,Default,,0,0,0,,我不需要考虑它 Dialogue: 0,0:59:08.54,0:59:13.83,Default,,0,0,0,,是因为我规定了exp化简后的结果是什么样子 Dialogue: 0,0:59:14.00,0:59:15.24,Default,,0,0,0,,我不需要知道它是如何做的 Dialogue: 0,0:59:17.08,0:59:21.24,Default,,0,0,0,,它也许是像我们这里 又是scan 又是try-rule Dialogue: 0,0:59:22.24,0:59:24.09,Default,,0,0,0,,又或者在这里调用另一个递归程序 Dialogue: 0,0:59:24.33,0:59:25.69,Default,,0,0,0,,根据“按愿望思维” 因为我知道simplify-exp Dialogue: 0,0:59:26.84,0:59:30.40,Default,,0,0,0,,它会返回exp化简后的结果 Dialogue: 0,0:59:31.61,0:59:32.99,Default,,0,0,0,,那么我就不需要再考虑它的具体实现了 Dialogue: 0,0:59:33.43,0:59:34.83,Default,,0,0,0,,我直接使用它 Dialogue: 0,0:59:35.07,0:59:36.43,Default,,0,0,0,,我合情合理地使用它 Dialogue: 0,0:59:36.43,0:59:37.45,Default,,0,0,0,,就会得到正确的结果 Dialogue: 0,0:59:39.95,0:59:42.57,Default,,0,0,0,,我们必须学会这种程序设计方法 -- 学会放弃 Dialogue: 0,0:59:47.56,0:59:49.05,Default,,0,0,0,,这里还有一点剩余 Dialogue: 0,0:59:50.40,0:59:54.46,Default,,0,0,0,,这里还有一些词典方面的细节 Dialogue: 0,0:59:55.08,0:59:58.32,Default,,0,0,0,,你们想知道到底词典是什么 Dialogue: 0,0:59:58.70,1:00:01.82,Default,,0,0,0,,但是我会跳过它 无可奉告 Dialogue: 0,1:00:04.14,1:00:05.20,Default,,0,0,0,,词典很简单 Dialogue: 0,1:00:06.01,1:00:09.84,Default,,0,0,0,,它是用一种被称为关联表的东西来表示的 Dialogue: 0,1:00:10.65,1:00:16.04,Default,,0,0,0,,这是一种特殊使用模式 用来在线性表中存放二维表 Dialogue: 0,1:00:16.50,1:00:20.17,Default,,0,0,0,,它们很简单 由序对构成 之前已经有同学问过了 Dialogue: 0,1:00:21.21,1:00:24.62,Default,,0,0,0,,有个特殊的过程叫做assq 用来处理这些东西 Dialogue: 0,1:00:24.94,1:00:26.36,Default,,0,0,0,,手册里面有 Dialogue: 0,1:00:27.04,1:00:28.59,Default,,0,0,0,,这个都无关紧要 Dialogue: 0,1:00:28.83,1:00:31.21,Default,,0,0,0,,重要的是如何扩充词典 Dialogue: 0,1:00:31.48,1:00:36.94,Default,,0,0,0,,要用一个模式、模式对应的数据、一本旧词典来扩充 Dialogue: 0,1:00:37.42,1:00:42.38,Default,,0,0,0,,这个模式pat 实际上是一个模式变量 Dialogue: 0,1:00:43.74,1:00:47.53,Default,,0,0,0,,我要做什么呢?我先从模式中取出模式变量的名字 Dialogue: 0,1:00:48.16,1:00:49.42,Default,,0,0,0,,把它赋给变量name Dialogue: 0,1:00:50.44,1:00:53.71,Default,,0,0,0,,然后我按照这个名字在词典中查找是否有对应的值 Dialogue: 0,1:00:53.79,1:00:56.41,Default,,0,0,0,,如果没有 就将这对新的模式-值加入到词典中 Dialogue: 0,1:00:56.92,1:00:59.23,Default,,0,0,0,,如果已经存在一个这样名字的词条 并且有值 Dialogue: 0,1:00:59.60,1:01:03.18,Default,,0,0,0,,那dat的值最好跟已经存储的值相等 Dialogue: 0,1:01:03.88,1:01:06.54,Default,,0,0,0,,这是我心目中期待的情况 Dialogue: 0,1:01:06.89,1:01:09.15,Default,,0,0,0,,否则 置失败 Dialogue: 0,1:01:12.08,1:01:12.89,Default,,0,0,0,,所以它也很简单 Dialogue: 0,1:01:13.66,1:01:16.68,Default,,0,0,0,,打开任何一个程序 你会发现它们都是由数个个小部分组成 Dialogue: 0,1:01:17.18,1:01:18.30,Default,,0,0,0,,许多简单的小部分 Dialogue: 0,1:01:20.04,1:01:21.29,Default,,0,0,0,,我想 到目前为止 Dialogue: 0,1:01:21.60,1:01:25.68,Default,,0,0,0,,我已经告诉给你们价值百万的信息了 Dialogue: 0,1:01:28.41,1:01:30.96,Default,,0,0,0,,我想这个程序几乎已经讲完了 Dialogue: 0,1:01:31.85,1:01:32.72,Default,,0,0,0,,有什么问题么? Dialogue: 0,1:01:34.27,1:01:38.16,Default,,0,0,0,,学生:你描述一下 化简后的表达式的规范么? Dialogue: 0,1:01:38.72,1:01:39.02,Default,,0,0,0,,教授:好的 Dialogue: 0,1:01:39.85,1:01:44.33,Default,,0,0,0,,simplify-exp接收一个表达式 返回一个化简后的表达式 Dialogue: 0,1:01:45.28,1:01:45.77,Default,,0,0,0,,就是这样了 Dialogue: 0,1:01:48.11,1:01:50.27,Default,,0,0,0,,它的工作方式很简单 Dialogue: 0,1:01:51.60,1:01:56.09,Default,,0,0,0,,对于复合表达式 先化简各部分后 再尝试化简整体 Dialogue: 0,1:01:56.89,1:01:58.49,Default,,0,0,0,,原子表达式 就直接代规则化简 Dialogue: 0,1:01:59.52,1:02:02.11,Default,,0,0,0,,学生:是这些规则把表达式化简了么? Dialogue: 0,1:02:02.76,1:02:03.58,Default,,0,0,0,,教授:当然 Dialogue: 0,1:02:03.76,1:02:03.90,Default,,0,0,0,,学生:好 Dialogue: 0,1:02:04.06,1:02:07.13,Default,,0,0,0,,教授:它们像你在这里看到的一样化简表达式 Dialogue: 0,1:02:08.35,1:02:11.64,Default,,0,0,0,,它先把表达式划分为小块 Dialogue: 0,1:02:12.60,1:02:17.29,Default,,0,0,0,,在化简器中使用这些规则 自下而上化简并构造表达式 Dialogue: 0,1:02:18.30,1:02:22.48,Default,,0,0,0,,处理它们 构造一个新的表达式作为结果 Dialogue: 0,1:02:24.28,1:02:29.44,Default,,0,0,0,,最后再尝试调用这些规则化简 Dialogue: 0,1:02:29.70,1:02:35.50,Default,,0,0,0,,当匹配的结果发生变化时 -- 就调用simplify-exp化简它 Dialogue: 0,1:02:35.80,1:02:40.64,Default,,0,0,0,,哦 不对是 骨架的实例化结果发生改变时 Dialogue: 0,1:02:42.00,1:02:47.36,Default,,0,0,0,,所以 规范就是 任何传入的表达式通过这些规则生成化简后的表达式 Dialogue: 0,1:02:49.84,1:02:50.76,Default,,0,0,0,,谢谢大家 下课 Dialogue: 0,1:02:53.64,1:03:06.96,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:02:53.64,1:03:06.96,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec4a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: CHN Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Video Zoom Percent: 1 PlayResX: 640 PlayResY: 480 Scroll Position: 0 Active Line: 6 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:06.19,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:06.45,0:00:14.22,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:06.45,0:00:14.22,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}字幕&时间轴\N邓雄飞 & S.Michael Dialogue: 0,0:00:06.45,0:00:14.22,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}后期&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:06.45,0:00:14.22,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:06.45,0:00:14.22,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:14.83,0:00:18.00,Declare,,0,0,0,,{\an2\fad(500,500)}模式匹配:基于规则的代换 Dialogue: 0,0:00:24.34,0:00:29.34,Default,,0,0,0,,教授:昨天 我们学习了一些符号操作 Dialogue: 0,0:00:29.92,0:00:35.12,Default,,0,0,0,,编写了一个非常典型的程序 Dialogue: 0,0:00:35.15,0:00:38.97,Default,,0,0,0,,来实现教材中的微积分规则 Dialogue: 0,0:00:39.61,0:00:44.59,Default,,0,0,0,,在这张幻灯片上 Dialogue: 0,0:00:44.96,0:00:48.81,Default,,0,0,0,,有一些从书中摘录的微积分规则 Dialogue: 0,0:00:49.47,0:00:54.62,Default,,0,0,0,,我们要把这些规则转化成计算机语言 Dialogue: 0,0:00:55.14,0:00:58.85,Default,,0,0,0,,当然 这种策略很有趣 Dialogue: 0,0:00:59.36,0:01:04.80,Default,,0,0,0,,但是我们为什么要把它们翻译成计算机语言呢? Dialogue: 0,0:01:05.00,0:01:06.27,Default,,0,0,0,,我的意思是--- Dialogue: 0,0:01:06.62,0:01:11.02,Default,,0,0,0,,我们昨天写的程序非常典型 Dialogue: 0,0:01:11.21,0:01:15.98,Default,,0,0,0,,它是一个按表达式类型做分派的分情况分析语句 Dialogue: 0,0:01:16.38,0:01:18.48,Default,,0,0,0,,规则就是这样的 Dialogue: 0,0:01:19.68,0:01:21.55,Default,,0,0,0,,这里的规则是说: Dialogue: 0,0:01:21.74,0:01:25.48,Default,,0,0,0,,我们考察的表达式如果是--- Dialogue: 0,0:01:25.48,0:01:29.42,Default,,0,0,0,,如果是常量 就做一些事情 Dialogue: 0,0:01:29.42,0:01:31.37,Default,,0,0,0,,如果是变量 就做另一件事情 Dialogue: 0,0:01:31.60,0:01:35.56,Default,,0,0,0,,如果它是常量乘以变量 就做另外的事 等等 Dialogue: 0,0:01:36.00,0:01:38.96,Default,,0,0,0,,这是一种按类型的分派 Dialogue: 0,0:01:41.40,0:01:45.16,Default,,0,0,0,,那么 既然它有如此典型的行为和结构 Dialogue: 0,0:01:45.95,0:01:49.53,Default,,0,0,0,,有没有其它方式把这个过程写得更加清晰? Dialogue: 0,0:01:50.83,0:01:53.45,Default,,0,0,0,,首先要解决的是 这些规则是什么? Dialogue: 0,0:01:55.56,0:01:58.50,Default,,0,0,0,,我们来好好想一下 规则有好几个部分 Dialogue: 0,0:01:58.94,0:02:02.35,Default,,0,0,0,,如果仔细观察这些规则 Dialogue: 0,0:02:03.71,0:02:04.99,Default,,0,0,0,,你就会发现 Dialogue: 0,0:02:05.12,0:02:09.69,Default,,0,0,0,,这些规则都有左右两部分 Dialogue: 0,0:02:10.36,0:02:14.36,Default,,0,0,0,,每一个规则都有左边部分和右边部分 Dialogue: 0,0:02:15.15,0:02:20.30,Default,,0,0,0,,左边部分用来与对被求导表达式做比较 Dialogue: 0,0:02:21.52,0:02:25.10,Default,,0,0,0,,右边部分用于替换原表达式 Dialogue: 0,0:02:28.49,0:02:33.10,Default,,0,0,0,,这张纸上的所有规则都可以描述成这样—— Dialogue: 0,0:02:36.51,0:02:38.06,Default,,0,0,0,,我们有许多模式 Dialogue: 0,0:02:41.48,0:02:48.30,Default,,0,0,0,,有时候 给定一个模式 我们需要为其生成一个骨架 Dialogue: 0,0:02:51.88,0:02:52.81,Default,,0,0,0,,这就是一个规则 Dialogue: 0,0:02:55.42,0:02:57.13,Default,,0,0,0,,模式是用于匹配的部分 Dialogue: 0,0:02:57.88,0:03:03.26,Default,,0,0,0,,将成功匹配的值代换到骨架里 就得到一个新的表达式 Dialogue: 0,0:03:06.46,0:03:16.32,Default,,0,0,0,,我的意思是:模式是用来匹配原表达式的 Dialogue: 0,0:03:23.72,0:03:28.51,Default,,0,0,0,,应用规则会产生一个新的表达式 Dialogue: 0,0:03:33.61,0:03:34.91,Default,,0,0,0,,我们称之为目标 Dialogue: 0,0:03:38.12,0:03:39.88,Default,,0,0,0,,这是通过骨架的实例化实现的 Dialogue: 0,0:03:41.63,0:03:43.02,Default,,0,0,0,,这个叫做实例化 Dialogue: 0,0:03:50.72,0:03:54.73,Default,,0,0,0,,这就是这些规则所描述的过程 Dialogue: 0,0:03:55.69,0:03:57.26,Default,,0,0,0,,今天我想要做的是 Dialogue: 0,0:03:58.73,0:04:01.08,Default,,0,0,0,,构建一种语言 Dialogue: 0,0:04:02.20,0:04:05.48,Default,,0,0,0,,以及它的解释与执行方法 Dialogue: 0,0:04:05.74,0:04:08.43,Default,,0,0,0,,使得这种语言可以直接表述这些规则 Dialogue: 0,0:04:10.59,0:04:11.58,Default,,0,0,0,,我们将要做的是 Dialogue: 0,0:04:11.58,0:04:17.56,Default,,0,0,0,,与其通过将规则翻译为程序 让计算机理解并执行 Dialogue: 0,0:04:18.38,0:04:21.56,Default,,0,0,0,,这里主要指 Lisp 程序 Dialogue: 0,0:04:22.16,0:04:24.49,Default,,0,0,0,,我们不如让计算机理解我们 Dialogue: 0,0:04:25.48,0:04:29.15,Default,,0,0,0,,我们可以写一些程序让计算机理解这些规则 Dialogue: 0,0:04:30.91,0:04:34.76,Default,,0,0,0,,这又稍微强调了上次的主旨 Dialogue: 0,0:04:35.44,0:04:39.36,Default,,0,0,0,,与其解决一个特定问题 不如解决一类问题 Dialogue: 0,0:04:39.77,0:04:46.72,Default,,0,0,0,,如果我为不同的数学运算写规则 Dialogue: 0,0:04:48.24,0:04:51.39,Default,,0,0,0,,比如简单代数的化简 Dialogue: 0,0:04:51.98,0:04:55.48,Default,,0,0,0,,或者三角函数运算 Dialogue: 0,0:04:56.09,0:05:01.16,Default,,0,0,0,,如果按照昨天的方法 我就得重新写个不同的程序 Dialogue: 0,0:05:01.16,0:05:05.42,Default,,0,0,0,,与之相反 我把程序中的共有逻辑给封装起来 Dialogue: 0,0:05:06.12,0:05:10.17,Default,,0,0,0,,也就是匹配、实例化等概念 还有控制结构 Dialogue: 0,0:05:10.17,0:05:12.46,Default,,0,0,0,,这都是非常复杂的事情 Dialogue: 0,0:05:13.16,0:05:18.46,Default,,0,0,0,,我想把它们从规则中分开 并封装 Dialogue: 0,0:05:20.06,0:05:22.60,Default,,0,0,0,,首先让我们看一下表示法 Dialogue: 0,0:05:22.62,0:05:24.09,Default,,0,0,0,,请大家看投影仪上的幻灯片 Dialogue: 0,0:05:24.67,0:05:25.60,Default,,0,0,0,,已经在这里了 Dialogue: 0,0:05:26.25,0:05:32.27,Default,,0,0,0,,我想要把求导的计算规则 Dialogue: 0,0:05:33.71,0:05:37.15,Default,,0,0,0,,表示为我这里写的一种简单语言 Dialogue: 0,0:05:38.11,0:05:43.29,Default,,0,0,0,,我会尽量避免去考虑语法 Dialogue: 0,0:05:44.28,0:05:49.28,Default,,0,0,0,,美化它很容易 虽然这个确实挺丑 但我并不关心 Dialogue: 0,0:05:49.30,0:05:56.41,Default,,0,0,0,,这确实不能像dx/dt那样表示 Dialogue: 0,0:05:56.76,0:05:58.12,Default,,0,0,0,,但这并不重要 Dialogue: 0,0:05:58.88,0:06:00.62,Default,,0,0,0,,这是一个偶然现象 Dialogue: 0,0:06:01.00,0:06:04.44,Default,,0,0,0,,这里 我只关心规则的结构 Dialogue: 0,0:06:04.83,0:06:11.70,Default,,0,0,0,,规则的左边部分代表了我想要匹配的求导表达式 Dialogue: 0,0:06:11.80,0:06:13.56,Default,,0,0,0,,这个表示是说 Dialogue: 0,0:06:13.60,0:06:18.32,Default,,0,0,0,,一个匹配常量的模式变量c Dialogue: 0,0:06:18.84,0:06:21.20,Default,,0,0,0,,关于匹配任意表达式的模式变量v求导 Dialogue: 0,0:06:23.08,0:06:25.55,Default,,0,0,0,,我们在右边部分得到的是0 Dialogue: 0,0:06:26.00,0:06:28.06,Default,,0,0,0,,这就代表了一个规则 Dialogue: 0,0:06:29.26,0:06:34.04,Default,,0,0,0,,下一条规则是 匹配变量的模式变量v Dialogue: 0,0:06:34.22,0:06:37.74,Default,,0,0,0,,对同一个模式变量求导 得到的结果是1 Dialogue: 0,0:06:38.60,0:06:42.17,Default,,0,0,0,,然而 如果一个匹配变量的模式变量u Dialogue: 0,0:06:42.41,0:06:44.84,Default,,0,0,0,,关于另一个模式变量v求导 Dialogue: 0,0:06:45.39,0:06:47.05,Default,,0,0,0,,那么 结果就是0 Dialogue: 0,0:06:47.84,0:06:52.17,Default,,0,0,0,,我想让大家看一下 这些规则是如何组织在一起的 Dialogue: 0,0:06:52.51,0:06:54.30,Default,,0,0,0,,比如说 在这里 Dialogue: 0,0:06:54.73,0:07:01.90,Default,,0,0,0,,我们要求表达式x1、x2之和的导数 Dialogue: 0,0:07:01.90,0:07:05.85,Default,,0,0,0,,在我们创造的这个语言中 Dialogue: 0,0:07:06.88,0:07:08.62,Default,,0,0,0,,以问号开头的叫模式变量 Dialogue: 0,0:07:08.93,0:07:14.93,Default,,0,0,0,,我们就像这样来构建这些用来匹配的模式变量 Dialogue: 0,0:07:14.93,0:07:20.33,Default,,0,0,0,,这里 表达式x1加上表达式x2 Dialogue: 0,0:07:20.33,0:07:26.70,Default,,0,0,0,,对变量v求导的结果等于右边这里的式子 Dialogue: 0,0:07:26.70,0:07:32.76,Default,,0,0,0,,右边的式子是一个骨架 表示表达式X1关于变量v求导 Dialogue: 0,0:07:33.82,0:07:37.10,Default,,0,0,0,,加上表达式X2对变量v求导的和 Dialogue: 0,0:07:37.60,0:07:42.38,Default,,0,0,0,,这里的冒号表示要代换的对象 Dialogue: 0,0:07:43.63,0:07:47.23,Default,,0,0,0,,我们将它们称作“骨架求值” Dialogue: 0,0:07:48.51,0:07:53.07,Default,,0,0,0,,让我在黑板上写一些语法 Dialogue: 0,0:07:53.23,0:07:55.56,Default,,0,0,0,,这样就能知道 在我们这门规则语言中会发生什么 Dialogue: 0,0:07:56.68,0:07:59.88,Default,,0,0,0,,首先我们要处理模式匹配问题 Dialogue: 0,0:08:06.04,0:08:13.12,Default,,0,0,0,,第一条规则是 形如foo这样的符号与其自身匹配 Dialogue: 0,0:08:23.52,0:08:31.34,Default,,0,0,0,,形如(f a b)的表达式 可以匹配这样的表 Dialogue: 0,0:08:36.30,0:08:57.02,Default,,0,0,0,,表的首元素是f、第二个元素是a、第三个元素是b Dialogue: 0,0:08:58.62,0:09:06.99,Default,,0,0,0,,另外 模式中可能还有形如(? x)这样的规则 Dialogue: 0,0:09:08.57,0:09:18.67,Default,,0,0,0,,这个规则可以匹配任意表达式 并将其称为x Dialogue: 0,0:09:25.45,0:09:29.98,Default,,0,0,0,,(?c x) 只匹配常量 Dialogue: 0,0:09:31.50,0:09:40.96,Default,,0,0,0,,并将匹配的常量记作x Dialogue: 0,0:09:44.56,0:09:57.07,Default,,0,0,0,,(?v x)匹配变量 并将匹配的变量记作x Dialogue: 0,0:10:01.66,0:10:03.80,Default,,0,0,0,,这就是我们正在构建的语言 Dialogue: 0,0:10:04.19,0:10:09.40,Default,,0,0,0,,两个对象的比较是基于元素与元素间的比较 Dialogue: 0,0:10:10.25,0:10:15.85,Default,,0,0,0,,模式中的元素可以包含这些语法变量、模式变量 Dialogue: 0,0:10:17.07,0:10:20.43,Default,,0,0,0,,它们可以用来匹配任意对象 Dialogue: 0,0:10:22.12,0:10:29.28,Default,,0,0,0,,这样 我就可以用x作为名字取得被匹配对象的值 Dialogue: 0,0:10:31.05,0:10:37.55,Default,,0,0,0,,现在 当我们为实例化准备骨架的时候 Dialogue: 0,0:10:39.50,0:10:41.40,Default,,0,0,0,,我们可能有这样的东西 Dialogue: 0,0:10:42.27,0:10:46.33,Default,,0,0,0,,符号foo实例化为它本身 Dialogue: 0,0:10:55.08,0:11:05.92,Default,,0,0,0,,形如(f a b)这样的表 实例化为 Dialogue: 0,0:11:06.36,0:11:14.75,Default,,0,0,0,,实例化为一个三元素表 Dialogue: 0,0:11:15.55,0:11:33.37,Default,,0,0,0,,其元素分别为f、a、b各自实例化后的结果 Dialogue: 0,0:11:36.35,0:11:54.27,Default,,0,0,0,,(: x) 会被实例化为x的值--也就是被匹配的模式 Dialogue: 0,0:12:03.05,0:12:10.08,Default,,0,0,0,,回头看看这里的幻灯片 我们发现这些都是对象 Dialogue: 0,0:12:10.78,0:12:16.06,Default,,0,0,0,,我们看到 这是一个用来匹配常量的模式变量 Dialogue: 0,0:12:16.56,0:12:19.02,Default,,0,0,0,,这是匹配变量的模式变量 Dialogue: 0,0:12:19.39,0:12:21.74,Default,,0,0,0,,这是匹配任意表达式的模式变量 Dialogue: 0,0:12:22.72,0:12:24.92,Default,,0,0,0,,如果我们有了名字一样的两个实例 Dialogue: 0,0:12:25.08,0:12:31.77,Default,,0,0,0,,想这个是被称作v的单变量表达式 Dialogue: 0,0:12:32.86,0:12:36.30,Default,,0,0,0,,关于一个称作v的任意表达式求导 Dialogue: 0,0:12:36.41,0:12:38.01,Default,,0,0,0,,因为这个v出现了两次 Dialogue: 0,0:12:38.65,0:12:41.07,Default,,0,0,0,,我们想约束它们相同 Dialogue: 0,0:12:42.68,0:12:45.00,Default,,0,0,0,,只有它俩完全一致才算是匹配 Dialogue: 0,0:12:45.23,0:12:47.23,Default,,0,0,0,,所以在这里我们在构建一个语言 Dialogue: 0,0:12:47.60,0:12:50.66,Default,,0,0,0,,事实上 这是一件非常好的事情 Dialogue: 0,0:12:50.66,0:12:52.60,Default,,0,0,0,,构建一个语言非常有趣 Dialogue: 0,0:12:52.60,0:12:54.33,Default,,0,0,0,,并且大家一直在做这些 Dialogue: 0,0:12:54.33,0:12:56.89,Default,,0,0,0,,大家做过的真正强大的设计 Dialogue: 0,0:12:57.23,0:13:00.20,Default,,0,0,0,,是构建一个语言来解决这样的问题 Dialogue: 0,0:13:02.06,0:13:05.34,Default,,0,0,0,,我们回头看看这些规则 Dialogue: 0,0:13:05.80,0:13:07.10,Default,,0,0,0,,这就是它们的全部 Dialogue: 0,0:13:07.10,0:13:12.43,Default,,0,0,0,,我们有加法、乘法 就像我们之前看到的一样 Dialogue: 0,0:13:12.43,0:13:17.37,Default,,0,0,0,,x1+x2 关于变量v的导数等于 Dialogue: 0,0:13:17.68,0:13:26.52,Default,,0,0,0,,x2对v求导乘以x1 加上 x1对v求导乘以x2 Dialogue: 0,0:13:27.26,0:13:29.10,Default,,0,0,0,,这是指数运算的求导规则 Dialogue: 0,0:13:29.24,0:13:32.11,Default,,0,0,0,,虽然这里展示完了所有的规则 但还可以按照我们意愿添加 Dialogue: 0,0:13:32.70,0:13:39.10,Default,,0,0,0,,我们在这里 建立了关于求导的规则列表 Dialogue: 0,0:13:40.40,0:13:44.33,Default,,0,0,0,,一旦我们有了这些 我们应该做什么呢? Dialogue: 0,0:13:45.40,0:13:47.84,Default,,0,0,0,,恩 我将给你们展示最好的思想之一 Dialogue: 0,0:13:48.44,0:13:51.68,Default,,0,0,0,,然后我们将花一整天来鼓捣它 Dialogue: 0,0:13:52.28,0:13:57.37,Default,,0,0,0,,我将向大家展示一个叫做simplifier的程序 Dialogue: 0,0:13:57.82,0:13:59.47,Default,,0,0,0,,一个通用的化简器 Dialogue: 0,0:14:00.09,0:14:17.10,Default,,0,0,0,,我们将求导规则deriv-rules送入simplifier从而产生dsimp Dialogue: 0,0:14:23.74,0:14:28.75,Default,,0,0,0,,传给simplifier过程一套规则 它会返回给我们一个过程 Dialogue: 0,0:14:29.32,0:14:34.59,Default,,0,0,0,,它根据这些规则对表达式进行化简 Dialogue: 0,0:14:37.39,0:14:43.93,Default,,0,0,0,,因此 这里会返回一个按照你制定的规则所构造的过程 Dialogue: 0,0:14:44.59,0:14:49.56,Default,,0,0,0,,使得在我们进入 Lisp 系统后 在命令提示符后面 Dialogue: 0,0:14:49.88,0:15:03.93,Default,,0,0,0,,输入 (DSIMP '(dd (+ x y) x)) Dialogue: 0,0:15:06.99,0:15:10.97,Default,,0,0,0,,注意这里的引号 因为我们讨论的是表达式的求导 Dialogue: 0,0:15:13.29,0:15:17.76,Default,,0,0,0,,然后我将得到结果 (+ 1 0) Dialogue: 0,0:15:19.96,0:15:24.60,Default,,0,0,0,,因为 (x+y)' = x' + y' Dialogue: 0,0:15:24.60,0:15:26.22,Default,,0,0,0,,x'=1 Dialogue: 0,0:15:26.38,0:15:27.82,Default,,0,0,0,,y'=0(关于x求导) Dialogue: 0,0:15:29.42,0:15:30.46,Default,,0,0,0,,这不是我想要的 Dialogue: 0,0:15:31.18,0:15:34.65,Default,,0,0,0,,我还没有在这里做代数化简 Dialogue: 0,0:15:36.16,0:15:41.53,Default,,0,0,0,,当然一旦我有了这个东西那么我们可以 -- 我们可以看看其它的规则 Dialogue: 0,0:15:41.96,0:15:49.36,Default,,0,0,0,,比如 我们看这张幻灯片 Dialogue: 0,0:15:49.36,0:15:54.12,Default,,0,0,0,,这里是其它的规则 代数操作规则 Dialogue: 0,0:15:56.00,0:15:58.38,Default,,0,0,0,,它们可以用来化简代数表达式 Dialogue: 0,0:15:59.00,0:16:02.06,Default,,0,0,0,,考察一下这些规则 Dialogue: 0,0:16:03.04,0:16:09.20,Default,,0,0,0,,这条规则的左部分是说 某个运算符应用到常量e1和常量e2上 Dialogue: 0,0:16:09.32,0:16:14.51,Default,,0,0,0,,其结果就是求(op e1 e2)的值 Dialogue: 0,0:16:15.88,0:16:21.56,Default,,0,0,0,,或者 当一个运算符应用在任意表达式e1和常量e2上 Dialogue: 0,0:16:21.69,0:16:23.87,Default,,0,0,0,,化简结果会把常量前置 Dialogue: 0,0:16:24.52,0:16:27.68,Default,,0,0,0,,这就变成了((: op) (: e2) (: e1)) Dialogue: 0,0:16:28.59,0:16:30.11,Default,,0,0,0,,为什么要这么做?我不知道 Dialogue: 0,0:16:30.22,0:16:33.16,Default,,0,0,0,,比如说 如果系统中有除法的话 这就不对 Dialogue: 0,0:16:33.53,0:16:35.31,Default,,0,0,0,,换句话说 规则有漏洞 Dialogue: 0,0:16:36.67,0:16:40.86,Default,,0,0,0,,所以0与任何表达式e的和 等于表达式e Dialogue: 0,0:16:42.17,0:16:45.31,Default,,0,0,0,,1乘以任何表达式e的结果是表达式e Dialogue: 0,0:16:46.12,0:16:49.13,Default,,0,0,0,,0乘以任何表达式e的结果是0 Dialogue: 0,0:16:49.33,0:16:52.72,Default,,0,0,0,,我们可以有任意复杂的规则 Dialogue: 0,0:16:53.69,0:16:54.81,Default,,0,0,0,,比如说 Dialogue: 0,0:16:55.36,0:17:01.69,Default,,0,0,0,,常量e1*(常量e2*任意表达式e3) Dialogue: 0,0:17:02.35,0:17:11.96,Default,,0,0,0,,可以化简为 (e1*e2)*e3 Dialogue: 0,0:17:13.36,0:17:16.76,Default,,0,0,0,,这个规则是说 先把常量组合起来 Dialogue: 0,0:17:16.76,0:17:22.70,Default,,0,0,0,,如果有形如 e1*(e2*e3) 的式子 而且e1 e2都是常量 就先把常量乘起来 Dialogue: 0,0:17:23.84,0:17:25.48,Default,,0,0,0,,你可以根据意愿来构建这些规则 Dialogue: 0,0:17:25.79,0:17:26.94,Default,,0,0,0,,这里还有很多规则 Dialogue: 0,0:17:27.42,0:17:31.04,Default,,0,0,0,,这些规则是很复杂的 比如-- Dialogue: 0,0:17:31.26,0:17:33.93,Default,,0,0,0,,请看 这条规则是分配律 Dialogue: 0,0:17:33.93,0:17:38.57,Default,,0,0,0,,任何表达式c乘以d和e Dialogue: 0,0:17:39.02,0:17:43.66,Default,,0,0,0,,等于 c与d的积加上c与e的积 Dialogue: 0,0:17:45.31,0:17:48.67,Default,,0,0,0,,我并不关心这些规则具体描述的什么 Dialogue: 0,0:17:49.16,0:17:52.97,Default,,0,0,0,,我们将要构建一种语言 用来解释这些规则 Dialogue: 0,0:17:55.50,0:17:57.48,Default,,0,0,0,,这样我们就可以按我们的意愿编写规则 Dialogue: 0,0:17:58.35,0:18:00.14,Default,,0,0,0,,这是另外一种程序设计语言 Dialogue: 0,0:18:03.39,0:18:04.04,Default,,0,0,0,,来看看 Dialogue: 0,0:18:05.18,0:18:06.96,Default,,0,0,0,,我还没告诉你我们要怎么做 Dialogue: 0,0:18:07.53,0:18:10.06,Default,,0,0,0,,当然我们马上就要讲了 Dialogue: 0,0:18:10.89,0:18:15.40,Default,,0,0,0,,但真正的问题是:宏观地看 我要做什么? Dialogue: 0,0:18:17.08,0:18:18.22,Default,,0,0,0,,这些规则是如何运作的? Dialogue: 0,0:18:19.00,0:18:25.45,Default,,0,0,0,,化简程序是如何用这些规则来输入的表达式 并返回一个合理的答案? Dialogue: 0,0:18:26.22,0:18:29.85,Default,,0,0,0,,首先 我认为我们有一大堆的规则 Dialogue: 0,0:18:32.52,0:18:34.22,Default,,0,0,0,,这里有全部的规则 Dialogue: 0,0:18:42.09,0:18:44.49,Default,,0,0,0,,这里的每一个规则 --- Dialogue: 0,0:18:46.97,0:18:49.24,Default,,0,0,0,,都有一个模式和一个骨架 Dialogue: 0,0:18:49.72,0:18:51.36,Default,,0,0,0,,我正在努力为它作一个控制结构 Dialogue: 0,0:18:53.37,0:18:56.56,Default,,0,0,0,,我有一个匹配器 Dialogue: 0,0:19:00.99,0:19:03.76,Default,,0,0,0,,还有一个实例化器 Dialogue: 0,0:19:09.66,0:19:12.94,Default,,0,0,0,,我将把一系列模式变量的值 Dialogue: 0,0:19:14.03,0:19:17.47,Default,,0,0,0,,从匹配器中传递到实例化器中 Dialogue: 0,0:19:18.06,0:19:19.42,Default,,0,0,0,,我把传递的东西叫做词典 Dialogue: 0,0:19:20.59,0:19:21.52,Default,,0,0,0,,传递一本词典 Dialogue: 0,0:19:24.92,0:19:27.82,Default,,0,0,0,,里面记载了:x匹配下列子表达式 Dialogue: 0,0:19:29.04,0:19:31.31,Default,,0,0,0,,而y匹配另一个子表达式 Dialogue: 0,0:19:32.25,0:19:36.35,Default,,0,0,0,,我会从实例化器中构造表达式 并送入匹配器 Dialogue: 0,0:19:37.16,0:19:38.36,Default,,0,0,0,,这些是表达式 Dialogue: 0,0:19:45.00,0:19:48.41,Default,,0,0,0,,这些规则的模式将要送进匹配器中 Dialogue: 0,0:19:49.24,0:19:54.40,Default,,0,0,0,,规则对应的骨架将要送进实例化器中 Dialogue: 0,0:19:55.21,0:19:56.62,Default,,0,0,0,,现在变得有点复杂了 Dialogue: 0,0:19:57.12,0:19:59.53,Default,,0,0,0,,因为当我们处理代数表达式时 Dialogue: 0,0:20:00.44,0:20:03.60,Default,,0,0,0,,有一些规则使你能够做等价代换 Dialogue: 0,0:20:04.24,0:20:05.87,Default,,0,0,0,,这些是等价代换规则 Dialogue: 0,0:20:06.88,0:20:09.29,Default,,0,0,0,,所以需要考察表达式的所有子表达式 Dialogue: 0,0:20:11.13,0:20:15.82,Default,,0,0,0,,给定一个表达式 这些规则应该被不断应用 Dialogue: 0,0:20:16.03,0:20:19.71,Default,,0,0,0,,首先 对于传入的表达式的每个子表达式 Dialogue: 0,0:20:20.22,0:20:22.83,Default,,0,0,0,,所有的规则都需要考察一次 Dialogue: 0,0:20:24.33,0:20:27.07,Default,,0,0,0,,如果有规则匹配成功 那么就会执行这个过程 Dialogue: 0,0:20:27.30,0:20:30.63,Default,,0,0,0,,传递一本存储值的词典 Dialogue: 0,0:20:30.63,0:20:33.39,Default,,0,0,0,,实例化器产生一个新的表达式 Dialogue: 0,0:20:33.90,0:20:39.10,Default,,0,0,0,,该表达式基本上只是替换了原表达式中匹配的部分 Dialogue: 0,0:20:40.84,0:20:44.46,Default,,0,0,0,,然后 我们要对它重新检查 Dialogue: 0,0:20:44.75,0:20:48.11,Default,,0,0,0,,重新考察这些规则 看看表达式是否可以更进一步化简 Dialogue: 0,0:20:49.53,0:20:53.71,Default,,0,0,0,,然后每一个子表达式这样做 直到没有任何变化为止 Dialogue: 0,0:20:54.96,0:20:57.50,Default,,0,0,0,,你可以把它想像成一个有机过程 Dialogue: 0,0:20:57.83,0:21:00.20,Default,,0,0,0,,我们有一锅炖汤 Dialogue: 0,0:21:00.24,0:21:04.32,Default,,0,0,0,,粘乎乎的汤里面有细菌 有酶 Dialogue: 0,0:21:05.63,0:21:10.50,Default,,0,0,0,,这些酶改变了汤 Dialogue: 0,0:21:10.50,0:21:14.38,Default,,0,0,0,,它们附着在你的表达式上 改变了它 然后就走了 Dialogue: 0,0:21:15.28,0:21:17.83,Default,,0,0,0,,就像钥匙和锁一样 它们需要配对 Dialogue: 0,0:21:18.00,0:21:19.73,Default,,0,0,0,,匹配 -- 改变 -- 然后离开 Dialogue: 0,0:21:19.73,0:21:21.68,Default,,0,0,0,,你可以将其想像成一种并行过程 Dialogue: 0,0:21:22.70,0:21:24.97,Default,,0,0,0,,所以你把一个表达式放到这锅“浓汤”中 Dialogue: 0,0:21:25.80,0:21:28.00,Default,,0,0,0,,过了会儿把它拿出来 它就被简化了 Dialogue: 0,0:21:30.44,0:21:32.64,Default,,0,0,0,,它会一直变化 直到不能再变化为止 Dialogue: 0,0:21:33.36,0:21:38.33,Default,,0,0,0,,但这些酶可以附着在表达式的任何部分 Dialogue: 0,0:21:39.21,0:21:43.76,Default,,0,0,0,,课先上到这里 有问题么? Dialogue: 0,0:21:44.92,0:21:45.36,Default,,0,0,0,,请讲 Dialogue: 0,0:21:45.43,0:21:52.76,Default,,0,0,0,,学生:匹配器和实例化器是两个独立的程序 是么? Dialogue: 0,0:21:52.76,0:21:53.85,Default,,0,0,0,,教授:他们被拆分成很多小片 Dialogue: 0,0:21:54.14,0:21:56.60,Default,,0,0,0,,然后在一个更大的结构中组合起来 Dialogue: 0,0:21:57.26,0:21:59.13,Default,,0,0,0,,学生:先扫描并匹配 Dialogue: 0,0:21:59.61,0:22:03.21,Default,,0,0,0,,并把匹配结果传递给实例化器 Dialogue: 0,0:22:03.39,0:22:06.03,Default,,0,0,0,,实例化器做出更改 并将其返回给匹配器 Dialogue: 0,0:22:06.11,0:22:08.49,Default,,0,0,0,,教授:不是直接更改 而是生成新的表达式 Dialogue: 0,0:22:09.61,0:22:18.43,Default,,0,0,0,,新表达式中的模式变量都被左边式子中所匹配的值所替换 Dialogue: 0,0:22:18.99,0:22:23.80,Default,,0,0,0,,也就是右边式子中的那些骨架变量 或者说求值变量 Dialogue: 0,0:22:25.20,0:22:27.08,Default,,0,0,0,,学生:然后它要回传给匹配器么? Dialogue: 0,0:22:27.20,0:22:32.32,Default,,0,0,0,,教授:然后要再进行一轮 直到表达式不再变化 Dialogue: 0,0:22:33.31,0:22:37.00,Default,,0,0,0,,学生:感觉这样递归循环似乎有些危险 Dialogue: 0,0:22:37.20,0:22:42.00,Default,,0,0,0,,教授:你说得很对 如果你定义的规则不好-- Dialogue: 0,0:22:42.00,0:22:45.53,Default,,0,0,0,,你发明的任何语言 如果它可以做任何事情 Dialogue: 0,0:22:45.72,0:22:48.40,Default,,0,0,0,,你就可能写出无限循环的程序 Dialogue: 0,0:22:49.37,0:22:55.07,Default,,0,0,0,,确实 诸如代数处理 这样的过程可能会产生无限循环 Dialogue: 0,0:23:01.05,0:23:01.52,Default,,0,0,0,,教授:请讲 Dialogue: 0,0:23:01.79,0:23:05.90,Default,,0,0,0,,学生:一些语言的设计者觉得这个特性非常重要 Dialogue: 0,0:23:05.93,0:23:12.03,Default,,0,0,0,,以至于它应该是语言的一部分 比如Scheme Dialogue: 0,0:23:12.03,0:23:13.96,Default,,0,0,0,,你的观点是-- Dialogue: 0,0:23:13.96,0:23:15.08,Default,,0,0,0,,老师:语言的什么特性? Dialogue: 0,0:23:15.79,0:23:17.26,Default,,0,0,0,,学生:模式匹配 Dialogue: 0,0:23:17.26,0:23:22.03,Default,,0,0,0,,所有应用的这些规则应该 --- Dialogue: 0,0:23:22.03,0:23:23.70,Default,,0,0,0,,教授:你是说像 Prolog 那样? Dialogue: 0,0:23:23.70,0:23:26.60,Default,,0,0,0,,学生:类似 Prolog 但更加通用的-- Dialogue: 0,0:23:26.60,0:23:27.64,Default,,0,0,0,,教授:这是可行的 Dialogue: 0,0:23:28.46,0:23:32.30,Default,,0,0,0,,好了 我是觉得吧…… 恩…… Dialogue: 0,0:23:33.16,0:23:36.49,Default,,0,0,0,,我可以教你怎么做 这样你就不用依靠语言的设计者 Dialogue: 0,0:23:40.92,0:23:42.75,Default,,0,0,0,,教授:我们可以自己来实现 Dialogue: 0,0:23:45.28,0:23:45.63,Default,,0,0,0,,下课 Dialogue: 0,0:23:45.63,0:23:50.63,Default,,0,0,0,,[音乐] Dialogue: 0,0:23:50.63,0:23:53.13,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:23:53.13,0:23:55.63,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:24:00.32,0:24:06.76,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:24:07.07,0:24:10.52,Declare,,0,0,0,,{\an2\fad(500,500)}模式匹配:基于规则的代换 Dialogue: 0,0:24:14.08,0:24:15.80,Default,,0,0,0,,好 上课 Dialogue: 0,0:24:15.80,0:24:17.21,Default,,0,0,0,,现在 我得告诉你们它是如何运作的 Dialogue: 0,0:24:20.00,0:24:24.11,Default,,0,0,0,,它很容易分成很多小份 Dialogue: 0,0:24:24.80,0:24:26.54,Default,,0,0,0,,现在 我们先看一下匹配器 Dialogue: 0,0:24:28.72,0:24:31.42,Default,,0,0,0,,匹配器的结构是像下面这样的 Dialogue: 0,0:24:32.86,0:24:45.12,Default,,0,0,0,,它是一个盒子 它的输入是一个表达式和一个模式 Dialogue: 0,0:24:52.09,0:24:53.95,Default,,0,0,0,,还有个输入是一本词典 Dialogue: 0,0:25:01.71,0:25:08.67,Default,,0,0,0,,要记住 词典把模式变量映射到匹配的值上 Dialogue: 0,0:25:09.15,0:25:11.05,Default,,0,0,0,,它的输出是另一本词典 Dialogue: 0,0:25:18.24,0:25:25.53,Default,,0,0,0,,除了旧词典中已有的内容 新词典中还产生的新的匹配 Dialogue: 0,0:25:28.00,0:25:28.83,Default,,0,0,0,,这就是匹配器 Dialogue: 0,0:25:33.87,0:25:36.54,Default,,0,0,0,,这是一个相当复杂的程序 Dialogue: 0,0:25:37.20,0:25:41.58,Default,,0,0,0,,请大家看看这里的投影 请看 Dialogue: 0,0:25:41.98,0:25:43.87,Default,,0,0,0,,哈哈 真是相当复杂 Dialogue: 0,0:25:44.43,0:25:45.87,Default,,0,0,0,,我只想让大家看一下它的轮廓 Dialogue: 0,0:25:46.78,0:25:49.85,Default,,0,0,0,,其实现细节太复杂了 Dialogue: 0,0:25:51.72,0:25:59.24,Default,,0,0,0,,然而 这是一个庞大的程序 它有很多这样的缩进的结构 Dialogue: 0,0:26:00.09,0:26:05.28,Default,,0,0,0,,在最外层 -- 不要去读这些代码 宏观地看 Dialogue: 0,0:26:05.43,0:26:10.36,Default,,0,0,0,,这里有一个分情况分析 而这些就是不同的情况 Dialogue: 0,0:26:12.09,0:26:16.19,Default,,0,0,0,,现在 我们将要深入细节 Dialogue: 0,0:26:16.67,0:26:18.60,Default,,0,0,0,,试图理解它是如何工作的 Dialogue: 0,0:26:20.08,0:26:22.35,Default,,0,0,0,,我们来看第一张幻灯片 Dialogue: 0,0:26:23.55,0:26:27.93,Default,,0,0,0,,它展示了匹配器的宏观结构 Dialogue: 0,0:26:28.81,0:26:36.33,Default,,0,0,0,,我们看到匹配器 它需要的参数有:模式、表达式和词典 Dialogue: 0,0:26:38.57,0:26:40.40,Default,,0,0,0,,这里是一个cond语句 Dialogue: 0,0:26:41.24,0:26:45.61,Default,,0,0,0,,它有许多不同情况 我们省略了一些代码 Dialogue: 0,0:26:46.62,0:26:48.62,Default,,0,0,0,,这个是我想让大家注意的 通用情况 Dialogue: 0,0:26:50.52,0:26:53.28,Default,,0,0,0,,考虑这个通用模式 它是个非常重要的模式 Dialogue: 0,0:26:56.32,0:27:01.61,Default,,0,0,0,,问题是我们需要同时地检查这两棵树 Dialogue: 0,0:27:02.50,0:27:08.03,Default,,0,0,0,,一棵树是表达式 另一棵树是模式 Dialogue: 0,0:27:08.59,0:27:10.11,Default,,0,0,0,,我们需要在它们之间进行匹配 Dialogue: 0,0:27:11.37,0:27:16.38,Default,,0,0,0,,使得表达式的子表达式会与模式的子表达式相匹配 Dialogue: 0,0:27:18.38,0:27:23.44,Default,,0,0,0,,我们深入研究一下 假设我有一个模式 Dialogue: 0,0:27:23.93,0:27:31.24,Default,,0,0,0,,这个是模式是 一个叫做x的表达式 乘以 Dialogue: 0,0:27:32.44,0:27:35.53,Default,,0,0,0,,乘以一个我们叫做y的表达式 Dialogue: 0,0:27:39.12,0:27:42.04,Default,,0,0,0,,再加上 刚才的表达式y 两个y必须是相同的表达式 Dialogue: 0,0:27:45.21,0:27:47.53,Default,,0,0,0,,我们在考察 乘式的和 Dialogue: 0,0:27:48.99,0:27:54.78,Default,,0,0,0,,其中 乘法和加法的第二个参数都是相同的 Dialogue: 0,0:27:57.02,0:27:58.84,Default,,0,0,0,,这是我们想要匹配像这样的表达式 Dialogue: 0,0:27:59.60,0:28:02.04,Default,,0,0,0,,它作为一个模式看起来像这个样子 Dialogue: 0,0:28:03.02,0:28:04.01,Default,,0,0,0,,这是一课树 Dialogue: 0,0:28:04.94,0:28:06.25,Default,,0,0,0,,它包含了一个加号 Dialogue: 0,0:28:08.08,0:28:20.25,Default,,0,0,0,,还有乘号 以及模式变量(? x)和(? y) Dialogue: 0,0:28:21.36,0:28:22.73,Default,,0,0,0,,还有模式变量(? y) Dialogue: 0,0:28:24.92,0:28:26.94,Default,,0,0,0,,这只是把表结构换了种写法 两者其实是一样的 Dialogue: 0,0:28:28.75,0:28:31.76,Default,,0,0,0,,我们先演示一个成功的匹配是如何运行的 Dialogue: 0,0:28:32.49,0:28:39.85,Default,,0,0,0,,这个模式匹配表达式 (+ (* 3 x) x) Dialogue: 0,0:28:42.41,0:28:43.36,Default,,0,0,0,,这是另一棵个树 Dialogue: 0,0:28:44.33,0:28:56.06,Default,,0,0,0,,它是3乘以x的积加上x Dialogue: 0,0:28:59.44,0:29:03.02,Default,,0,0,0,,所以我要做的是 同时遍历这两棵树 Dialogue: 0,0:29:04.41,0:29:07.82,Default,,0,0,0,,我想这样遍历它们 Dialogue: 0,0:29:08.67,0:29:12.96,Default,,0,0,0,,我会比较它们是否一样 Dialogue: 0,0:29:12.96,0:29:14.32,Default,,0,0,0,,这是一个复合对象 Dialogue: 0,0:29:15.21,0:29:17.26,Default,,0,0,0,,我们先看它的左分支 Dialogue: 0,0:29:17.26,0:29:18.14,Default,,0,0,0,,这可能是car部分 Dialogue: 0,0:29:18.56,0:29:21.21,Default,,0,0,0,,它们匹配吗?恩 两个加号成功匹配 Dialogue: 0,0:29:21.68,0:29:24.20,Default,,0,0,0,,但是下一个对象是复合的 Dialogue: 0,0:29:24.20,0:29:24.84,Default,,0,0,0,,我们看一下它 Dialogue: 0,0:29:25.20,0:29:26.80,Default,,0,0,0,,这个也匹配了 Dialogue: 0,0:29:26.80,0:29:27.79,Default,,0,0,0,,它们都是星号 Dialogue: 0,0:29:28.51,0:29:30.24,Default,,0,0,0,,现在……哦! Dialogue: 0,0:29:30.40,0:29:33.60,Default,,0,0,0,,这是模式变量 它和3相匹配 Dialogue: 0,0:29:34.27,0:29:35.92,Default,,0,0,0,,记住 现在x等于3 Dialogue: 0,0:29:36.36,0:29:37.37,Default,,0,0,0,,把它记录在词典中 Dialogue: 0,0:29:37.56,0:29:40.73,Default,,0,0,0,,遍历过程中 词典紧随着我们 并告诉我们:x等于3 Dialogue: 0,0:29:41.45,0:29:45.87,Default,,0,0,0,,x等于3 y等于x 但这两个是不同意义上的x Dialogue: 0,0:29:46.83,0:29:51.20,Default,,0,0,0,,那个是模式变量x 而这个是模式变量y匹配表达式x Dialogue: 0,0:29:53.61,0:29:57.76,Default,,0,0,0,,这是模式变量y 它已经有值了 并且值是x Dialogue: 0,0:29:58.36,0:30:00.06,Default,,0,0,0,,这是x么? 当然是 Dialogue: 0,0:30:00.06,0:30:00.75,Default,,0,0,0,,好的 Dialogue: 0,0:30:02.03,0:30:02.78,Default,,0,0,0,,完事儿了 Dialogue: 0,0:30:03.39,0:30:08.09,Default,,0,0,0,,现在 我有一本词典 它在遍历过程中不断积累 Dialogue: 0,0:30:11.42,0:30:14.51,Default,,0,0,0,,现在让我们看看这个一般情况 然后看看它如何工作 Dialogue: 0,0:30:15.88,0:30:16.51,Default,,0,0,0,,这里.. Dialogue: 0,0:30:17.20,0:30:21.66,Default,,0,0,0,,我传入一个模式 一个表达式 和一本词典 Dialogue: 0,0:30:22.38,0:30:27.50,Default,,0,0,0,,这里的情况比较复杂 -- 它是通用情况 Dialogue: 0,0:30:29.98,0:30:34.80,Default,,0,0,0,,一般来说 表达式由两部分组成:左部分和右部分 Dialogue: 0,0:30:35.45,0:30:38.81,Default,,0,0,0,,在Lisp系统中 复合对象都是由两部分组成的 Dialogue: 0,0:30:40.03,0:30:41.23,Default,,0,0,0,,现在我们有什么呢? Dialogue: 0,0:30:41.88,0:30:48.84,Default,,0,0,0,,我将会用已有的这本词典 继续匹配模式和表达式的car部分 Dialogue: 0,0:30:50.30,0:30:53.12,Default,,0,0,0,,这个匹配过程会产生一本新词典 Dialogue: 0,0:30:54.14,0:30:57.26,Default,,0,0,0,,我将用它来匹配它们的cdr部分 Dialogue: 0,0:30:58.51,0:31:02.09,Default,,0,0,0,,这就是词典是如何在整个结构中遍历、线索的 Dialogue: 0,0:31:03.66,0:31:07.53,Default,,0,0,0,,匹配完car和cdr部分后得到的词典 Dialogue: 0,0:31:10.12,0:31:12.41,Default,,0,0,0,,会作为值返回给上级 Dialogue: 0,0:31:13.61,0:31:15.84,Default,,0,0,0,,匹配可能会在任何一个地方失败 Dialogue: 0,0:31:16.62,0:31:18.20,Default,,0,0,0,,比如说 可能会有这种情况 Dialogue: 0,0:31:18.36,0:31:27.18,Default,,0,0,0,,我们回过头来把这里改成4 这样就不会完全匹配 Dialogue: 0,0:31:29.13,0:31:34.81,Default,,0,0,0,,现在这两个不再匹配了 因为x应该 Dialogue: 0,0:31:34.93,0:31:37.34,Default,,0,0,0,,不好意思 这个y是x Dialogue: 0,0:31:37.82,0:31:40.12,Default,,0,0,0,,但是这里的y却又是4 Dialogue: 0,0:31:40.53,0:31:43.52,Default,,0,0,0,,语法上来说 x和4显然不相同 Dialogue: 0,0:31:44.59,0:31:48.81,Default,,0,0,0,,所以这个不会匹配成功 它会拒绝 匹配会失败 Dialogue: 0,0:31:50.19,0:31:56.08,Default,,0,0,0,,那么 因为先前产生的词典会作为输入送入匹配器 Dialogue: 0,0:31:56.52,0:31:58.28,Default,,0,0,0,,所以它必须能够传播失败 Dialogue: 0,0:31:58.57,0:32:01.04,Default,,0,0,0,,第一条语句就是用来判断失败的 Dialogue: 0,0:32:03.61,0:32:08.19,Default,,0,0,0,,如果证实出来这个模式不是原子的--- Dialogue: 0,0:32:08.50,0:32:11.45,Default,,0,0,0,,如果模式是原子的 将进入这里 这里我们还没有讨论过 Dialogue: 0,0:32:12.17,0:32:13.56,Default,,0,0,0,,如果模式不是原子的 Dialogue: 0,0:32:15.05,0:32:19.23,Default,,0,0,0,,但表达式是原子--也就是它不由小部分组成 Dialogue: 0,0:32:20.14,0:32:22.65,Default,,0,0,0,,那么匹配必然失败 因此我们返回'failed Dialogue: 0,0:32:23.64,0:32:30.78,Default,,0,0,0,,整理下思路 如果这个模式既不是原子的又不是模式变量的话 程序会来到这里 Dialogue: 0,0:32:30.96,0:32:32.51,Default,,0,0,0,,这是会使匹配失败的情况 Dialogue: 0,0:32:35.26,0:32:39.12,Default,,0,0,0,,好 让我们看这个里面的东西 Dialogue: 0,0:32:39.84,0:32:42.93,Default,,0,0,0,,首先需要知道 如果用原子模式来进行匹配会发生什么? Dialogue: 0,0:32:42.93,0:32:43.90,Default,,0,0,0,,这简单 Dialogue: 0,0:32:43.90,0:32:46.50,Default,,0,0,0,,不是由其它模式构成的模式 比如:foo Dialogue: 0,0:32:47.37,0:32:48.54,Default,,0,0,0,,这是个非常好的原子模式 Dialogue: 0,0:32:49.16,0:32:51.24,Default,,0,0,0,,让我们来看看 Dialogue: 0,0:32:52.08,0:32:55.82,Default,,0,0,0,,如果模式是原子的 而且表达式也原子的话 Dialogue: 0,0:32:56.80,0:33:01.85,Default,,0,0,0,,并且如果它俩是同一个东西 那么词典就跟之前一样 Dialogue: 0,0:33:03.08,0:33:04.00,Default,,0,0,0,,没有变化 Dialogue: 0,0:33:04.60,0:33:10.33,Default,,0,0,0,,就像刚才 +匹配+ *匹配* x匹配x Dialogue: 0,0:33:11.42,0:33:12.33,Default,,0,0,0,,就是那样 Dialogue: 0,0:33:13.07,0:33:16.81,Default,,0,0,0,,然而 如何模式和表达式并不相同的话 Dialogue: 0,0:33:17.32,0:33:21.36,Default,,0,0,0,,如果这是两个不同的原子对象 比如+和*相匹配 Dialogue: 0,0:33:22.44,0:33:23.40,Default,,0,0,0,,这样就失败了 Dialogue: 0,0:33:25.60,0:33:34.56,Default,,0,0,0,,或者说 如果模式是原子 但表达式是复合 那么匹配失败 Dialogue: 0,0:33:37.40,0:33:38.24,Default,,0,0,0,,这很简单 Dialogue: 0,0:33:38.81,0:33:43.61,Default,,0,0,0,,那么 那些各种各样的模式变量又是怎么处理的呢? Dialogue: 0,0:33:44.09,0:33:46.54,Default,,0,0,0,,我们有三类被命名了的模式变量 Dialogue: 0,0:33:47.39,0:33:52.03,Default,,0,0,0,,它们分别用于匹配:任意常量 任意变量 任意表达式 Dialogue: 0,0:33:53.82,0:34:00.14,Default,,0,0,0,,(? x) 表示匹配任意表达式 Dialogue: 0,0:34:01.18,0:34:04.54,Default,,0,0,0,,(?c x) 表示匹配任意常量 Dialogue: 0,0:34:04.73,0:34:07.29,Default,,0,0,0,,(?v x) 表示匹配任意变量 Dialogue: 0,0:34:08.96,0:34:09.79,Default,,0,0,0,,好的 我们要做什么呢? Dialogue: 0,0:34:10.51,0:34:16.94,Default,,0,0,0,,看这里 如果模式表示的是匹配任意常量 Dialogue: 0,0:34:17.53,0:34:20.57,Default,,0,0,0,,那么待匹配的表达式最好是一个常量 Dialogue: 0,0:34:21.48,0:34:23.53,Default,,0,0,0,,不然的话 匹配就会失败 Dialogue: 0,0:34:23.83,0:34:27.50,Default,,0,0,0,,如果是一个常量 那么我就需要扩充词典 Dialogue: 0,0:34:27.50,0:34:29.69,Default,,0,0,0,,扩充词典的方法则是: Dialogue: 0,0:34:30.70,0:34:37.76,Default,,0,0,0,,在旧词典后 附加一对模式与表达式的配对 Dialogue: 0,0:34:41.16,0:34:42.75,Default,,0,0,0,,因此 如果是匹配任意变量 Dialogue: 0,0:34:43.72,0:34:47.46,Default,,0,0,0,,我得通过匹配来核查表达式是否是变量 Dialogue: 0,0:34:47.46,0:34:50.09,Default,,0,0,0,,如果是的话 我就扩充词典 Dialogue: 0,0:34:50.38,0:34:54.65,Default,,0,0,0,,现在在原有词典基础上 我们又多了一项模式与表达式的匹配 Dialogue: 0,0:34:55.28,0:34:56.70,Default,,0,0,0,,这个过程返回一本新的词典 Dialogue: 0,0:34:58.88,0:35:04.16,Default,,0,0,0,,在这个词典中也有很多失败 因此需要检查 Dialogue: 0,0:35:04.16,0:35:07.50,Default,,0,0,0,,就比如 模式变量已经有一个值了 Dialogue: 0,0:35:09.23,0:35:16.17,Default,,0,0,0,,但我又用它匹配一个跟之前匹配的表达式不相同的表达式的话 Dialogue: 0,0:35:16.43,0:35:18.36,Default,,0,0,0,,那么在这里也会立即产生失败 Dialogue: 0,0:35:20.16,0:35:21.56,Default,,0,0,0,,我们后面再讨论 Dialogue: 0,0:35:22.91,0:35:29.36,Default,,0,0,0,,最后 匹配任意的表达式不需要在语法范畴做什么检查 Dialogue: 0,0:35:30.11,0:35:32.20,Default,,0,0,0,,只用扩充词典就行了 Dialogue: 0,0:35:34.76,0:35:38.32,Default,,0,0,0,,这就是一个完整的简单的匹配器 Dialogue: 0,0:35:39.28,0:35:41.37,Default,,0,0,0,,非常具有讽刺意味的一点是 Dialogue: 0,0:35:41.66,0:35:45.12,Default,,0,0,0,,现在 人们花了大价钱来请一些人编写 Dialogue: 0,0:35:45.46,0:35:47.52,Default,,0,0,0,,所谓的 “人工智能专家系统” Dialogue: 0,0:35:48.40,0:35:52.03,Default,,0,0,0,,也不过是像这样的一个匹配器和实例化器罢了 Dialogue: 0,0:35:53.56,0:35:56.94,Default,,0,0,0,,这很容易做 现在你也可以创业开个小公司了 Dialogue: 0,0:35:57.42,0:36:01.72,Default,,0,0,0,,然后 第二周忽悠风投给你投个几百万 Dialogue: 0,0:36:03.79,0:36:08.57,Default,,0,0,0,,我是想说 这种程序放在20年前是非凡的 Dialogue: 0,0:36:09.74,0:36:12.81,Default,,0,0,0,,但放到现在 它就是小菜一碟了 大一新生也可以学 Dialogue: 0,0:36:13.63,0:36:15.47,Default,,0,0,0,,这里是一个实例化器 Dialogue: 0,0:36:20.22,0:36:23.07,Default,,0,0,0,,可问题是 他们都去了赚钱了 而且比我的还多 Dialogue: 0,0:36:24.97,0:36:26.59,Default,,0,0,0,,在大学中确实是这样 Dialogue: 0,0:36:27.10,0:36:39.42,Default,,0,0,0,,实例化是用来将给定的表达式、词典和骨架生成新的表达式的 Dialogue: 0,0:36:44.35,0:36:45.69,Default,,0,0,0,,这个不是很难 Dialogue: 0,0:36:46.60,0:36:53.36,Default,,0,0,0,,我们在下一张幻灯片中简单地看下 Dialogue: 0,0:36:53.88,0:36:59.29,Default,,0,0,0,,用一本给定的词典去实例化一个骨架 这很简单 Dialogue: 0,0:36:59.68,0:37:03.29,Default,,0,0,0,,我们要做的 就是对骨架递归地做树遍历 Dialogue: 0,0:37:04.08,0:37:08.33,Default,,0,0,0,,所有的骨架变量---我叫它“骨架求值” Dialogue: 0,0:37:08.41,0:37:11.42,Default,,0,0,0,,这是我在这个程序中定义的抽象语法 Dialogue: 0,0:37:11.60,0:37:16.46,Default,,0,0,0,,在规则中 以冒号打头的就是骨架求值 Dialogue: 0,0:37:18.25,0:37:24.30,Default,,0,0,0,,在那种情况下 我要在词典中找答案 我们待会儿再讨论 Dialogue: 0,0:37:24.30,0:37:25.61,Default,,0,0,0,,我们看整体 Dialogue: 0,0:37:27.77,0:37:31.80,Default,,0,0,0,,这个过程是用一本字典来实例化一个骨架 Dialogue: 0,0:37:32.75,0:37:37.15,Default,,0,0,0,,我在这里定义一个内部循环 Dialogue: 0,0:37:38.14,0:37:39.85,Default,,0,0,0,,它要做的事情很简单 Dialogue: 0,0:37:40.17,0:37:43.50,Default,,0,0,0,,如果这个骨架是原子的 Dialogue: 0,0:37:44.60,0:37:47.45,Default,,0,0,0,,这种情况 它直接返回一个骨架作为结果 Dialogue: 0,0:37:48.84,0:37:51.87,Default,,0,0,0,,或者在通常情况下它是复合的 Dialogue: 0,0:37:52.60,0:37:59.40,Default,,0,0,0,,这种情况下 我通过一些实例化的结果构造表达式 Dialogue: 0,0:37:59.40,0:38:04.25,Default,,0,0,0,,递归调用这个循环 不断实例化骨架的car和cdr部分 Dialogue: 0,0:38:04.89,0:38:06.24,Default,,0,0,0,,这就是树的递归遍历 Dialogue: 0,0:38:08.41,0:38:14.36,Default,,0,0,0,,如果在骨架中有冒号表达式 那么这就是一个骨架求值 Dialogue: 0,0:38:14.96,0:38:22.64,Default,,0,0,0,,那么要做的事情是:找到冒号引导的表达式 -- 本例中 也就是CADR部分 Dialogue: 0,0:38:22.81,0:38:26.25,Default,,0,0,0,,这些是抽象语法 因此我能改变规则的表示 Dialogue: 0,0:38:27.52,0:38:32.73,Default,,0,0,0,,先不管求值过程如何实现 总之我要用这本词典对表达式求值 Dialogue: 0,0:38:32.90,0:38:34.65,Default,,0,0,0,,我们以后再仔细讨论 Dialogue: 0,0:38:36.12,0:38:38.35,Default,,0,0,0,,求值的结果就是答案 Dialogue: 0,0:38:39.68,0:38:43.66,Default,,0,0,0,,这条初始化语句 通过给它传递整个骨架循环来启动它 Dialogue: 0,0:38:44.44,0:38:47.04,Default,,0,0,0,,这些调用又会被分成小块的递归调用 Dialogue: 0,0:38:49.63,0:38:56.48,Default,,0,0,0,,那么 求值过程里面发生了些什么 Dialogue: 0,0:38:57.18,0:38:59.07,Default,,0,0,0,,我无法详尽地给你们解释 Dialogue: 0,0:38:59.98,0:39:01.34,Default,,0,0,0,,我就大致说一下 Dialogue: 0,0:39:01.56,0:39:03.74,Default,,0,0,0,,之后 我们再深入地讨论 Dialogue: 0,0:39:05.29,0:39:10.81,Default,,0,0,0,,在一本词典的环境下 求值一个表达式 Dialogue: 0,0:39:11.90,0:39:14.17,Default,,0,0,0,,如果表达式是原子的 Dialogue: 0,0:39:15.04,0:39:16.22,Default,,0,0,0,,就在词典中进行查找 Dialogue: 0,0:39:18.60,0:39:19.87,Default,,0,0,0,,这没啥 Dialogue: 0,0:39:20.57,0:39:23.66,Default,,0,0,0,,难点在这里 Dialogue: 0,0:39:23.83,0:39:28.28,Default,,0,0,0,,我将要应用表达式的car部分对应的一个过程 Dialogue: 0,0:39:29.44,0:39:31.68,Default,,0,0,0,,这个过程是在“某个地方”查找得到的--我们以后讨论 Dialogue: 0,0:39:32.14,0:39:34.20,Default,,0,0,0,,我想请大家注意一下 这之中有一些“魔法” Dialogue: 0,0:39:34.67,0:39:38.72,Default,,0,0,0,,这个魔法将在不久后“施展”出来 但不是在今天 Dialogue: 0,0:39:40.00,0:39:46.51,Default,,0,0,0,,我们在词典中查找表达式剩余部分对应的值 Dialogue: 0,0:39:48.56,0:39:50.88,Default,,0,0,0,,我还不想让你们关注细节 Dialogue: 0,0:39:51.44,0:39:53.44,Default,,0,0,0,,我想让大家意识到这里还有很多代码 Dialogue: 0,0:39:54.17,0:39:56.75,Default,,0,0,0,,我们以后再详细讨论 Dialogue: 0,0:39:59.04,0:40:00.88,Default,,0,0,0,,但是 魔法就到此结束了 Dialogue: 0,0:40:02.57,0:40:06.96,Default,,0,0,0,,这部分利用Lisp的神奇力量 不过也就到此为止了 Dialogue: 0,0:40:10.25,0:40:13.56,Default,,0,0,0,,我们介绍了匹配和实例化 Dialogue: 0,0:40:15.05,0:40:16.60,Default,,0,0,0,,这一节有疑问么? Dialogue: 0,0:40:28.10,0:40:29.80,Default,,0,0,0,,学生:我有一个问题 Dialogue: 0,0:40:29.80,0:40:30.43,Default,,0,0,0,,教授:请讲 Dialogue: 0,0:40:30.43,0:40:32.56,Default,,0,0,0,,学生:您能切到前张幻灯片上吗? Dialogue: 0,0:40:33.60,0:40:35.56,Default,,0,0,0,,是关于定义匹配模式的 Dialogue: 0,0:40:36.16,0:40:40.76,Default,,0,0,0,,教授:好的 你想看定义匹配模式的全部的幻灯片 Dialogue: 0,0:40:40.76,0:40:43.06,Default,,0,0,0,,有人能帮我把投影仪--- Dialogue: 0,0:40:43.06,0:40:45.16,Default,,0,0,0,,这是最大的规模 Dialogue: 0,0:40:45.31,0:40:46.40,Default,,0,0,0,,你想看哪一部分? Dialogue: 0,0:40:46.76,0:40:49.96,Default,,0,0,0,,学生:呃 最上面吧 Dialogue: 0,0:40:49.96,0:40:53.76,Default,,0,0,0,,就是传递失败的那一部分 Dialogue: 0,0:40:54.52,0:40:55.21,Default,,0,0,0,,教授:恩 Dialogue: 0,0:40:55.64,0:40:59.33,Default,,0,0,0,,学生:基本的想法是把错误返回给词典 是么? Dialogue: 0,0:40:59.33,0:41:04.25,Default,,0,0,0,,教授:所谓的词典 就是所是匹配的答案 对吧? Dialogue: 0,0:41:05.16,0:41:09.80,Default,,0,0,0,,要么它是一些配对 Dialogue: 0,0:41:11.07,0:41:14.03,Default,,0,0,0,,要么根本就没有配对 Dialogue: 0,0:41:14.46,0:41:14.97,Default,,0,0,0,,学生:对 Dialogue: 0,0:41:15.26,0:41:17.83,Default,,0,0,0,,教授:这里 事实上 Dialogue: 0,0:41:17.83,0:41:22.60,Default,,0,0,0,,因为一个匹配过程会向另一个匹配过程传递词典 Dialogue: 0,0:41:22.80,0:41:24.65,Default,,0,0,0,,可以在这里的一般情况中看到 Dialogue: 0,0:41:25.12,0:41:27.93,Default,,0,0,0,,这是一个匹配过程传递词典到另一个匹配过程 Dialogue: 0,0:41:28.14,0:41:34.16,Default,,0,0,0,,我是用匹配car部分得到的词典来匹配cdr部分的 Dialogue: 0,0:41:36.06,0:41:37.08,Default,,0,0,0,,这里的代码就是这个意思 Dialogue: 0,0:41:37.29,0:41:40.30,Default,,0,0,0,,正因为如此 如果对car部分的匹配失败了 Dialogue: 0,0:41:41.23,0:41:45.44,Default,,0,0,0,,匹配cdr部分的时候就有必要传播失败 Dialogue: 0,0:41:45.95,0:41:46.96,Default,,0,0,0,,第一行就是用于传播失败 Dialogue: 0,0:41:48.26,0:41:51.73,Default,,0,0,0,,学生:好 但我还是不明白匹配 -- Dialogue: 0,0:41:51.73,0:41:54.24,Default,,0,0,0,,从匹配的实例出来的是什么? Dialogue: 0,0:41:54.73,0:41:56.00,Default,,0,0,0,,教授:有两种可能的情况 Dialogue: 0,0:41:56.33,0:41:59.15,Default,,0,0,0,,一种是符号'failed 意味匹配失败 Dialogue: 0,0:41:59.53,0:41:59.93,Default,,0,0,0,,学生:对 Dialogue: 0,0:41:59.93,0:42:03.87,Default,,0,0,0,,教授:或者是某种映射 -- 现在这还是一个抽象的东西 Dialogue: 0,0:42:04.16,0:42:05.68,Default,,0,0,0,,你需要知道它的结构 Dialogue: 0,0:42:06.49,0:42:13.96,Default,,0,0,0,,它们把匹配过程中 匹配成功的模式变量和值关联起来 Dialogue: 0,0:42:14.68,0:42:16.70,Default,,0,0,0,,学生:好 那么 Dialogue: 0,0:42:16.80,0:42:18.57,Default,,0,0,0,,教授:那是通过扩充词典实现的 Dialogue: 0,0:42:18.80,0:42:28.54,Default,,0,0,0,,学生:所以根据递归性质 如果匹配过程产生并传递了失败 Dialogue: 0,0:42:28.68,0:42:30.30,Default,,0,0,0,,那么第一种情况将捕获它 Dialogue: 0,0:42:30.40,0:42:33.56,Default,,0,0,0,,教授:并且传播它 不做任何其它处理 Dialogue: 0,0:42:33.56,0:42:34.83,Default,,0,0,0,,学生:哦 懂了 Dialogue: 0,0:42:35.50,0:42:37.36,Default,,0,0,0,,教授:这是传出失败最快的方法 Dialogue: 0,0:42:42.86,0:42:43.60,Default,,0,0,0,,请讲 Dialogue: 0,0:42:43.84,0:42:47.23,Default,,0,0,0,,学生:如果没有失败 那意味着我匹配了一个模式 Dialogue: 0,0:42:47.84,0:42:53.00,Default,,0,0,0,,我会扩充词典并且传递表达式中的模式 Dialogue: 0,0:42:55.21,0:42:58.43,Default,,0,0,0,,但是 代换并不是发生在这 对吧? Dialogue: 0,0:42:58.43,0:42:59.03,Default,,0,0,0,,是吧? Dialogue: 0,0:42:59.03,0:42:59.46,Default,,0,0,0,,教授:你是对的 Dialogue: 0,0:42:59.46,0:43:02.40,Default,,0,0,0,,这里没有可供代换的骨架 因此不会发生代换 Dialogue: 0,0:43:02.40,0:43:03.06,Default,,0,0,0,,学生:好 那么 Dialogue: 0,0:43:03.06,0:43:07.16,Default,,0,0,0,,教授:我们这里所做的 是为后面的代换准备词典 Dialogue: 0,0:43:08.25,0:43:12.43,Default,,0,0,0,,学生:词典的数据结构是什么呢?是有序对么? Dialogue: 0,0:43:12.72,0:43:15.96,Default,,0,0,0,,教授:那个 那个还没有告诉你 Dialogue: 0,0:43:15.96,0:43:16.89,Default,,0,0,0,,它还是一个抽象的东西 Dialogue: 0,0:43:17.06,0:43:17.56,Default,,0,0,0,,学生:哦 Dialogue: 0,0:43:17.56,0:43:18.90,Default,,0,0,0,,教授:你为什么要知道呢? Dialogue: 0,0:43:18.90,0:43:21.64,Default,,0,0,0,,它是一个函数 仅仅是一个函数 Dialogue: 0,0:43:21.69,0:43:22.33,Default,,0,0,0,,学生:我想知道它的原因是-- Dialogue: 0,0:43:22.33,0:43:24.17,Default,,0,0,0,,教授:这个抽象函数表现地像有序对 Dialogue: 0,0:43:25.12,0:43:28.44,Default,,0,0,0,,它可以用一系列的表通过链接来实现 Dialogue: 0,0:43:29.06,0:43:32.43,Default,,0,0,0,,它也可以用一些酷炫的表机制来实现 Dialogue: 0,0:43:32.56,0:43:34.16,Default,,0,0,0,,它也可以实现为一个函数 Dialogue: 0,0:43:35.80,0:43:37.40,Default,,0,0,0,,我可以把它写成一个函数 Dialogue: 0,0:43:39.02,0:43:39.87,Default,,0,0,0,,但我不会告诉你具体细节 Dialogue: 0,0:43:40.84,0:43:43.08,Default,,0,0,0,,这是George的事情 由他来构建这个结构 Dialogue: 0,0:43:49.56,0:43:52.06,Default,,0,0,0,,我知道 你特别想知道它的具体结构 Dialogue: 0,0:43:52.36,0:43:54.19,Default,,0,0,0,,但我不打算让你那么做 Dialogue: 0,0:43:54.43,0:43:59.23,Default,,0,0,0,,学生:恩 最后一个问题 扩充到词典中的重要信息是什么? Dialogue: 0,0:43:59.74,0:44:02.08,Default,,0,0,0,,我想 可能是匹配发现的模式 Dialogue: 0,0:44:02.73,0:44:04.83,Default,,0,0,0,,教授:是的 那些与表达式相匹配的模式 Dialogue: 0,0:44:04.83,0:44:09.30,Default,,0,0,0,,我们想要得到模式 只不过在本例中这些都是模式变量 对吧? Dialogue: 0,0:44:09.85,0:44:12.89,Default,,0,0,0,,这三种扩充词典的情况都是模式变量 Dialogue: 0,0:44:13.20,0:44:13.50,Default,,0,0,0,,学生:恩 Dialogue: 0,0:44:14.48,0:44:18.75,Default,,0,0,0,,教授:所以 在词典就有一个模式变量与一个值对应 Dialogue: 0,0:44:19.45,0:44:22.11,Default,,0,0,0,,这个值是所匹配的表达式 Dialogue: 0,0:44:23.31,0:44:29.63,Default,,0,0,0,,词典就是遍历过程中记录下来的所有匹配 Dialogue: 0,0:44:30.54,0:44:34.41,Default,,0,0,0,,我会以原有词典为基础 创建一本新词典 Dialogue: 0,0:44:35.12,0:44:38.35,Default,,0,0,0,,新增的内容就是新发现的匹配 Dialogue: 0,0:44:39.98,0:44:43.73,Default,,0,0,0,,学生:我不理解为什么不能在发现匹配后立即进行代换 Dialogue: 0,0:44:43.73,0:44:44.80,Default,,0,0,0,,教授:哦 那时候还不能代换 Dialogue: 0,0:44:44.81,0:44:46.62,Default,,0,0,0,,因为我不知道骨架啊! Dialogue: 0,0:44:47.58,0:44:49.66,Default,,0,0,0,,模式和匹配器都是独立的单元 Dialogue: 0,0:44:49.66,0:44:51.00,Default,,0,0,0,,学生:哦 我明白了 Dialogue: 0,0:44:51.00,0:44:51.50,Default,,0,0,0,,教授:懂了吧? Dialogue: 0,0:44:51.50,0:44:51.90,Default,,0,0,0,,学生:恩 Dialogue: 0,0:44:51.90,0:44:57.23,Default,,0,0,0,,教授:我用这个匹配器进行匹配 如果匹配了就可以实例化 Dialogue: 0,0:44:58.20,0:44:59.50,Default,,0,0,0,,学生:知道了 Dialogue: 0,0:45:00.54,0:45:03.88,Default,,0,0,0,,学生:您可以再求解一次黑板上的例子么 Dialogue: 0,0:45:04.89,0:45:06.93,Default,,0,0,0,,什么东西返回给了匹配器 Dialogue: 0,0:45:06.93,0:45:08.00,Default,,0,0,0,,教授:当然可以 Dialogue: 0,0:45:08.26,0:45:09.74,Default,,0,0,0,,来看这个例子 Dialogue: 0,0:45:10.67,0:45:15.45,Default,,0,0,0,,在这里当我遍历这个结构的时候 我遇到了(? x) Dialogue: 0,0:45:16.67,0:45:20.54,Default,,0,0,0,,我有一本词典 不过此时假设它是空的 Dialogue: 0,0:45:21.56,0:45:25.36,Default,,0,0,0,,一本空词典 然后我匹配到了x为3 Dialogue: 0,0:45:26.62,0:45:33.60,Default,,0,0,0,,从此以后 词典中就记录了 x与3匹配 对吧 Dialogue: 0,0:45:33.64,0:45:36.09,Default,,0,0,0,,继续遍历 然后遇到(? y) Dialogue: 0,0:45:36.89,0:45:39.20,Default,,0,0,0,,它是一个特殊的x 这是模式变量x Dialogue: 0,0:45:39.79,0:45:41.37,Default,,0,0,0,,我看到(? y) 模式变量y Dialogue: 0,0:45:42.17,0:45:47.74,Default,,0,0,0,,词典说 模式变量y的值是符号x Dialogue: 0,0:45:48.99,0:45:51.20,Default,,0,0,0,,因为这里已经匹配过了 Dialogue: 0,0:45:52.43,0:45:54.52,Default,,0,0,0,,所以此时 词典中包含两个条目 Dialogue: 0,0:45:55.45,0:45:59.90,Default,,0,0,0,,模式变量x是数字3 模式变量y是表达式x Dialogue: 0,0:46:01.95,0:46:04.11,Default,,0,0,0,,现在继续进行遍历 Dialogue: 0,0:46:04.23,0:46:07.45,Default,,0,0,0,,这里 模式变量y想要和4匹配 Dialogue: 0,0:46:08.06,0:46:10.65,Default,,0,0,0,,但是这个不可能 产生失败 Dialogue: 0,0:46:14.30,0:46:15.48,Default,,0,0,0,,谢谢 下课 Dialogue: 0,0:46:16.76,0:46:25.02,Default,,0,0,0,,[音乐] Dialogue: 0,0:46:25.07,0:46:27.45,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:46:27.47,0:46:30.00,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教 Dialogue: 0,0:46:48.19,0:46:54.75,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:46:55.20,0:46:58.04,Declare,,0,0,0,,{\an2\fad(500,500)}模式匹配:基于规则的代换 Dialogue: 0,0:47:02.38,0:47:05.68,Default,,0,0,0,,这是大家首次看到如此庞大而复杂的程序 Dialogue: 0,0:47:07.34,0:47:09.90,Default,,0,0,0,,当然 本项课程的目的之一就在于 Dialogue: 0,0:47:09.90,0:47:12.97,Default,,0,0,0,,是让大家可以读懂这么庞大的程序 而完全不用害怕它 Dialogue: 0,0:47:13.76,0:47:16.33,Default,,0,0,0,,这个程序仅仅只有4页代码而已 Dialogue: 0,0:47:17.08,0:47:19.23,Default,,0,0,0,,课程结业后 我希望就算是50页长的程序 Dialogue: 0,0:47:20.27,0:47:21.80,Default,,0,0,0,,也吓不倒你们 Dialogue: 0,0:47:22.97,0:47:28.20,Default,,0,0,0,,我不是说让你们“左耳朵进 右耳朵出”地读程序 Dialogue: 0,0:47:29.20,0:47:31.70,Default,,0,0,0,,你应该体会这个程序 Dialogue: 0,0:47:31.70,0:47:34.83,Default,,0,0,0,,然后好好思考 因为它是一个很大的程序 Dialogue: 0,0:47:35.32,0:47:38.92,Default,,0,0,0,,在这个程序中有很多东西 Dialogue: 0,0:47:41.24,0:47:46.03,Default,,0,0,0,,我已经介绍了我们正在实现的 -- 基于规则代换的模式匹配语言 Dialogue: 0,0:47:46.81,0:47:47.64,Default,,0,0,0,,给你们看了一些规则 Dialogue: 0,0:47:48.36,0:47:51.24,Default,,0,0,0,,我已经告诉大家匹配和实例化 Dialogue: 0,0:47:51.55,0:47:53.32,Default,,0,0,0,,它们是使规则生效的“阴阳两极” Dialogue: 0,0:47:54.24,0:47:56.35,Default,,0,0,0,,现在我们需要理解控制结构 Dialogue: 0,0:47:56.86,0:48:00.32,Default,,0,0,0,,就是这些规则是如何被用在表达式上 Dialogue: 0,0:48:01.08,0:48:03.84,Default,,0,0,0,,来指导代数化简的 Dialogue: 0,0:48:06.92,0:48:09.58,Default,,0,0,0,,这也是非常复杂的 Dialogue: 0,0:48:12.09,0:48:19.48,Default,,0,0,0,,其中有很多循环 相互交织 错综复杂 Dialogue: 0,0:48:20.24,0:48:26.99,Default,,0,0,0,,一方面 我不得不检查 待化简表达式的每个子表达式 Dialogue: 0,0:48:29.00,0:48:29.93,Default,,0,0,0,,我们已经讲过了 Dialogue: 0,0:48:29.93,0:48:36.24,Default,,0,0,0,,这是在car、cdr部分做某种树形递归 Dialogue: 0,0:48:37.44,0:48:38.59,Default,,0,0,0,,就是那样 Dialogue: 0,0:48:38.84,0:48:42.46,Default,,0,0,0,,现在 在我每个遍历到的结点上 Dialogue: 0,0:48:43.47,0:48:48.76,Default,,0,0,0,,也就是我想要化简的(子)表达式 Dialogue: 0,0:48:49.20,0:48:51.07,Default,,0,0,0,,我需要应用所有的规则 Dialogue: 0,0:48:53.42,0:48:55.08,Default,,0,0,0,,每个规则都需要检查每个节点 Dialogue: 0,0:48:56.00,0:48:57.92,Default,,0,0,0,,我一直在这些规则中打转(循环) Dialogue: 0,0:49:01.66,0:49:05.48,Default,,0,0,0,,一个规则可能匹配 也可能不匹配 Dialogue: 0,0:49:07.50,0:49:10.62,Default,,0,0,0,,如果规则不匹配 那我就不关心了 Dialogue: 0,0:49:12.28,0:49:19.34,Default,,0,0,0,,如果规则匹配了 我就在那个结点用另一个表达式替换这个表达式 Dialogue: 0,0:49:20.08,0:49:22.89,Default,,0,0,0,,实际上 我创建了一个新表达式 它包含 Dialogue: 0,0:49:23.55,0:49:28.65,Default,,0,0,0,,它包含了所有的东西 新的值代换入骨架后的结果 Dialogue: 0,0:49:29.21,0:49:31.92,Default,,0,0,0,,也就是 在该层次上 把规则所对应的骨架实例化的结果 Dialogue: 0,0:49:32.72,0:49:37.37,Default,,0,0,0,,但我并不知道我所实例化出来的东西 是否是简化形式 Dialogue: 0,0:49:38.75,0:49:43.82,Default,,0,0,0,,所以我要对我刚刚构建好的东西调用化简器来简化它 Dialogue: 0,0:49:46.12,0:49:50.36,Default,,0,0,0,,完成后 我就可以将其构建进我想要的表达式中作为答案 Dialogue: 0,0:49:51.80,0:49:57.45,Default,,0,0,0,,这里的基本思想是 我们定义一个 “废料进-废料出”的化简器 Dialogue: 0,0:50:01.47,0:50:02.75,Default,,0,0,0,,它是一种递归调用的化简器 Dialogue: 0,0:50:03.58,0:50:08.84,Default,,0,0,0,,化简方法是:基本对象 比如变量就是最简形式的了 Dialogue: 0,0:50:10.78,0:50:13.28,Default,,0,0,0,,复合对象 -- 呃 我也不知道 Dialogue: 0,0:50:14.09,0:50:16.56,Default,,0,0,0,,而我要从简单的对象入手 Dialogue: 0,0:50:16.86,0:50:21.23,Default,,0,0,0,,通过假设它们都是由小块的基本对象组成的 Dialogue: 0,0:50:24.60,0:50:25.61,Default,,0,0,0,,这就是思路 Dialogue: 0,0:50:27.82,0:50:33.12,Default,,0,0,0,,现在如果我们看第一张投影 Dialogue: 0,0:50:33.88,0:50:37.13,Default,,0,0,0,,我们看到一个非常复杂的程序 就像我们之前看到的匹配器一样 Dialogue: 0,0:50:37.53,0:50:39.95,Default,,0,0,0,,它太复杂了 没有必要仔细阅读它 Dialogue: 0,0:50:41.92,0:50:43.61,Default,,0,0,0,,我只想让大家感受一下它的轮廓 Dialogue: 0,0:50:44.44,0:50:50.01,Default,,0,0,0,,也就是这个程序里面有很多子程序 Dialogue: 0,0:50:52.11,0:50:57.56,Default,,0,0,0,,这部分用于遍历表达式 Dialogue: 0,0:50:58.97,0:51:01.36,Default,,0,0,0,,这部分用于尝试规则 Dialogue: 0,0:51:02.52,0:51:05.60,Default,,0,0,0,,当然 我们也可以看看细节 Dialogue: 0,0:51:06.89,0:51:11.80,Default,,0,0,0,,来看第一张幻灯片 Dialogue: 0,0:51:13.40,0:51:17.36,Default,,0,0,0,,化简器由数个部分组成 Dialogue: 0,0:51:17.96,0:51:22.92,Default,,0,0,0,,回想一下 化简器接收一系列的规则 Dialogue: 0,0:51:23.92,0:51:27.20,Default,,0,0,0,,并生成一个使用该规则进行化简的程序 Dialogue: 0,0:51:30.04,0:51:32.60,Default,,0,0,0,,化简器在这里定义 Dialogue: 0,0:51:33.48,0:51:34.81,Default,,0,0,0,,接受一个规则集合 Dialogue: 0,0:51:36.16,0:51:38.68,Default,,0,0,0,,在the-rules被定义的上下文中 Dialogue: 0,0:51:39.24,0:51:41.48,Default,,0,0,0,,还定义了很多其它东西 Dialogue: 0,0:51:42.33,0:51:46.20,Default,,0,0,0,,而simplifier过程的返回结果则是 Dialogue: 0,0:51:46.41,0:51:50.80,Default,,0,0,0,,是一个已经定义好的过程 -- simplify-exp Dialogue: 0,0:51:52.46,0:51:57.71,Default,,0,0,0,,调用 (simplifier the-rules) 的返回值是 Dialogue: 0,0:51:58.17,0:52:03.21,Default,,0,0,0,,返回值是一个过程 是在该上下文中定义的simplify-exp过程 Dialogue: 0,0:52:05.23,0:52:08.83,Default,,0,0,0,,这是一个利用这些给定规则进行化简的过程 Dialogue: 0,0:52:15.04,0:52:15.96,Default,,0,0,0,,定义就是这样的 Dialogue: 0,0:52:17.45,0:52:21.79,Default,,0,0,0,,这些过程的前两个 这个和这个 Dialogue: 0,0:52:22.48,0:52:25.74,Default,,0,0,0,,它们一起 递归地遍历一个表达式 Dialogue: 0,0:52:26.97,0:52:30.20,Default,,0,0,0,,这个是任何表达式的通用化简方法 Dialogue: 0,0:52:30.94,0:52:33.23,Default,,0,0,0,,而这个过程用于化简表达式的子部分 Dialogue: 0,0:52:35.53,0:52:36.08,Default,,0,0,0,,没别的了 Dialogue: 0,0:52:37.04,0:52:39.90,Default,,0,0,0,,每个过程中 我们会做些复杂操作 包括尝试这些规则 Dialogue: 0,0:52:40.32,0:52:41.71,Default,,0,0,0,,现在 我们看看这些过程 Dialogue: 0,0:52:45.76,0:52:48.08,Default,,0,0,0,,我们先来讨论一下表达式的递归遍历 Dialogue: 0,0:52:48.57,0:52:51.68,Default,,0,0,0,,这是用一种很简单的方法完成的 Dialogue: 0,0:52:54.28,0:52:57.93,Default,,0,0,0,,这是一个小型的、嵌套的递归过程 Dialogue: 0,0:52:59.42,0:53:01.77,Default,,0,0,0,,这里有两个过程 --- Dialogue: 0,0:53:02.59,0:53:05.20,Default,,0,0,0,,一个是对整个表达式化简 Dialogue: 0,0:53:06.11,0:53:08.16,Default,,0,0,0,,另一个是对表达式的某部分化简 Dialogue: 0,0:53:09.44,0:53:10.97,Default,,0,0,0,,它们的原理都很简单 Dialogue: 0,0:53:12.12,0:53:16.86,Default,,0,0,0,,如果我想要化简的表达式是复合表达式 Dialogue: 0,0:53:17.04,0:53:18.32,Default,,0,0,0,,那么就对每一个部分进行化简 Dialogue: 0,0:53:19.95,0:53:22.32,Default,,0,0,0,,调用simplify-parts这个过程 Dialogue: 0,0:53:22.33,0:53:25.74,Default,,0,0,0,,会构造一个新的表达式 其中各个部分都是化简过的 Dialogue: 0,0:53:26.00,0:53:28.64,Default,,0,0,0,,我会在这里尝试那些应用规则 Dialogue: 0,0:53:30.86,0:53:34.22,Default,,0,0,0,,如果表达式不是复合的 而是一些简单的表达式 Dialogue: 0,0:53:34.76,0:53:37.13,Default,,0,0,0,,比如说是符号 或者'pi Dialogue: 0,0:53:38.16,0:53:39.79,Default,,0,0,0,,无论如何 我都需要尝试应用这些规则 Dialogue: 0,0:53:40.03,0:53:47.56,Default,,0,0,0,,因为 因为可能有将pi扩展成3.14159265358979....这样的规则 Dialogue: 0,0:53:48.46,0:53:49.08,Default,,0,0,0,,也许我不会这样做 Dialogue: 0,0:53:50.11,0:53:51.52,Default,,0,0,0,,但是没有理由不这样做 Dialogue: 0,0:53:52.75,0:53:57.53,Default,,0,0,0,,现在如果我对表达式的各部分化简 那就很简单了 Dialogue: 0,0:53:58.99,0:54:02.88,Default,,0,0,0,,要么表达式是空的 它没有更多的部分了 Dialogue: 0,0:54:03.71,0:54:05.08,Default,,0,0,0,,这种情况我返回一个空表达式 Dialogue: 0,0:54:05.72,0:54:10.52,Default,,0,0,0,,否则 我用cons构建一个新的表达式 Dialogue: 0,0:54:11.21,0:54:14.27,Default,,0,0,0,,新表达式的car部分是原表达式car的化简结果 Dialogue: 0,0:54:15.42,0:54:17.39,Default,,0,0,0,,然后化简表达式的其它其他部分作为新表达式的cdr部分 Dialogue: 0,0:54:21.08,0:54:23.88,Default,,0,0,0,,我用这种方式向大家展示这些的原因是 Dialogue: 0,0:54:24.88,0:54:30.12,Default,,0,0,0,,我想让大家感受到 这些不同模式在编程时非常重要 Dialogue: 0,0:54:32.20,0:54:34.00,Default,,0,0,0,,这段程序我可以换种写法 Dialogue: 0,0:54:34.00,0:54:36.99,Default,,0,0,0,,还有一种化简表达式的方法 Dialogue: 0,0:54:37.72,0:54:39.63,Default,,0,0,0,,这仅仅是一个小程序 Dialogue: 0,0:54:39.63,0:54:42.36,Default,,0,0,0,,我把它写到黑板上 让大家感受一下 Dialogue: 0,0:54:49.71,0:54:51.90,Default,,0,0,0,,你可以用这种惯用法来写程序 Dialogue: 0,0:54:59.30,0:55:03.13,Default,,0,0,0,,那么 如何化简表达式exp呢? Dialogue: 0,0:55:03.21,0:55:10.14,Default,,0,0,0,,在以下几种情况下 调用try-rules Dialogue: 0,0:55:11.12,0:55:15.72,Default,,0,0,0,,就像之前一样 如果表达式是复合的 Dialogue: 0,0:55:21.52,0:55:24.27,Default,,0,0,0,,如果是复合的 我要怎么做呢? Dialogue: 0,0:55:24.53,0:55:25.40,Default,,0,0,0,,我要化简它的每个部分 Dialogue: 0,0:55:26.01,0:55:27.80,Default,,0,0,0,,但是我已经有对cdr部分递归的过程了 Dialogue: 0,0:55:30.25,0:55:33.18,Default,,0,0,0,,一个被封装成高阶过程的通用模式 Dialogue: 0,0:55:34.09,0:55:34.46,Default,,0,0,0,,也就是map过程 Dialogue: 0,0:55:36.08,0:55:36.88,Default,,0,0,0,,我在这里写出来 Dialogue: 0,0:55:37.16,0:55:48.03,Default,,0,0,0,,(map simplify-exp exp) Dialogue: 0,0:55:49.00,0:55:54.59,Default,,0,0,0,,这是说 把simplify-exp这个过程应用在表达式的每个部分 Dialogue: 0,0:55:55.34,0:55:57.34,Default,,0,0,0,,然后把结果用cons组合成表 Dialogue: 0,0:56:00.92,0:56:04.38,Default,,0,0,0,,所以表中的每个元素都是化简过的 Dialogue: 0,0:56:05.45,0:56:08.23,Default,,0,0,0,,不是复合表达式的话 就不用化简了 Dialogue: 0,0:56:09.05,0:56:12.36,Default,,0,0,0,,所以不需要再写一个辅助函数来化简各个部分 Dialogue: 0,0:56:12.64,0:56:13.48,Default,,0,0,0,,这句代码就够了 Dialogue: 0,0:56:15.47,0:56:17.05,Default,,0,0,0,,所以有时候可以这样写 Dialogue: 0,0:56:17.84,0:56:18.70,Default,,0,0,0,,这个无关紧要 Dialogue: 0,0:56:21.16,0:56:26.27,Default,,0,0,0,,好现在看一下 -- 如何尝试规则 Dialogue: 0,0:56:27.70,0:56:31.60,Default,,0,0,0,,这里 幻灯片上有一堆复杂的东西 Dialogue: 0,0:56:33.68,0:56:35.28,Default,,0,0,0,,我要尝试对一个表达式施用规则 Dialogue: 0,0:56:36.36,0:56:39.96,Default,,0,0,0,,我现在尝试的表达式是最初表达式的子表达式 Dialogue: 0,0:56:40.43,0:56:43.88,Default,,0,0,0,,这是因为我之前特意安排要求遍历所有子表达式 Dialogue: 0,0:56:46.11,0:56:51.90,Default,,0,0,0,,所以这里的exp 就是最初表达式的子表达式 Dialogue: 0,0:56:52.49,0:56:57.71,Default,,0,0,0,,这里我们定义一个scan的过程 它用来尝试每一个规则 Dialogue: 0,0:56:58.72,0:57:00.33,Default,,0,0,0,,我们会在整个规则中扫描 Dialogue: 0,0:57:01.92,0:57:07.77,Default,,0,0,0,,它会通过不断取cdr部分来遍历整个规则 查找一条规则来施用 Dialogue: 0,0:57:09.37,0:57:11.96,Default,,0,0,0,,当找到一条规则 它的任务就完成了 Dialogue: 0,0:57:14.09,0:57:16.41,Default,,0,0,0,,我们来看一下try-rules是如何工作的 Dialogue: 0,0:57:17.74,0:57:21.02,Default,,0,0,0,,非常简单:就是顺序地扫描规则表 Dialogue: 0,0:57:21.96,0:57:23.26,Default,,0,0,0,,它 真的简单吗? Dialogue: 0,0:57:23.26,0:57:24.51,Default,,0,0,0,,不 这是个很庞大的程序 Dialogue: 0,0:57:25.55,0:57:28.57,Default,,0,0,0,,接收的参数是一系列的规则--它们是整个规则表的子表 Dialogue: 0,0:57:30.75,0:57:35.13,Default,,0,0,0,,我们已经查找了其中的一些 但它们都不符合 所以试试剩下的 Dialogue: 0,0:57:35.87,0:57:36.30,Default,,0,0,0,,尝试下一条 Dialogue: 0,0:57:36.40,0:57:37.63,Default,,0,0,0,,如果所有规则都尝试完了 Dialogue: 0,0:57:37.90,0:57:40.84,Default,,0,0,0,,那么 我就不能再对这个表达式做什么了 它已经是最简了 Dialogue: 0,0:57:42.35,0:57:47.26,Default,,0,0,0,,然而 如果还有规则需要扫描 Dialogue: 0,0:57:48.01,0:57:51.58,Default,,0,0,0,,那么从一个空的词典开始 Dialogue: 0,0:57:52.20,0:57:55.40,Default,,0,0,0,,用规则表中的第一条规则对表达式进行模式匹配 Dialogue: 0,0:57:57.07,0:57:58.84,Default,,0,0,0,,将得到的结果作为新的词典 Dialogue: 0,0:58:00.32,0:58:03.74,Default,,0,0,0,,如果失败了 就尝试剩余规则 Dialogue: 0,0:58:06.68,0:58:07.52,Default,,0,0,0,,这句代码就是这个意思 Dialogue: 0,0:58:08.52,0:58:10.33,Default,,0,0,0,,也就是说 丢弃那条规则 Dialogue: 0,0:58:11.10,0:58:15.05,Default,,0,0,0,,成功的话 我将取出第一条规则对应的骨架 Dialogue: 0,0:58:15.34,0:58:17.40,Default,,0,0,0,,利用得到的词典 来将其实例化 Dialogue: 0,0:58:17.93,0:58:20.80,Default,,0,0,0,,然后对结果化简 就得到了我想要的表达式 Dialogue: 0,0:58:24.20,0:58:25.96,Default,,0,0,0,,虽然这是一个复杂的程序 Dialogue: 0,0:58:26.25,0:58:28.72,Default,,0,0,0,,但是每个复杂程序都是由许多简单部分组成的 Dialogue: 0,0:58:29.77,0:58:33.12,Default,,0,0,0,,这里的递归模式非常复杂 Dialogue: 0,0:58:34.78,0:58:36.52,Default,,0,0,0,,最重要的事情就是:不要去思考它 Dialogue: 0,0:58:38.67,0:58:41.80,Default,,0,0,0,,如果去思考它的实际行为 Dialogue: 0,0:58:42.06,0:58:42.97,Default,,0,0,0,,大家就会迷惑 Dialogue: 0,0:58:45.31,0:58:45.71,Default,,0,0,0,,就算是我也会 Dialogue: 0,0:58:47.04,0:58:50.17,Default,,0,0,0,,没关系 可以多加练习 Dialogue: 0,0:58:51.52,0:58:52.46,Default,,0,0,0,,这些模式非常难 Dialogue: 0,0:58:54.17,0:58:55.42,Default,,0,0,0,,但是大家不用考虑它 Dialogue: 0,0:58:55.83,0:58:59.72,Default,,0,0,0,,关键点就是 好的编程或设计方法需要 Dialogue: 0,0:58:59.74,0:59:00.97,Default,,0,0,0,,知道什么是不需要考虑的 Dialogue: 0,0:59:03.05,0:59:06.06,Default,,0,0,0,,回到这张幻灯片上 Dialogue: 0,0:59:06.92,0:59:08.01,Default,,0,0,0,,我不需要考虑它 Dialogue: 0,0:59:08.54,0:59:13.83,Default,,0,0,0,,是因为我规定了exp化简后的结果是什么样子 Dialogue: 0,0:59:14.00,0:59:15.24,Default,,0,0,0,,我不需要知道它是如何做的 Dialogue: 0,0:59:17.08,0:59:21.24,Default,,0,0,0,,它也许是像我们这里 又是scan 又是try-rule Dialogue: 0,0:59:22.24,0:59:24.09,Default,,0,0,0,,又或者在这里调用另一个递归程序 Dialogue: 0,0:59:24.33,0:59:25.69,Default,,0,0,0,,根据“按愿望思维” 因为我知道simplify-exp Dialogue: 0,0:59:26.84,0:59:30.40,Default,,0,0,0,,它会返回exp化简后的结果 Dialogue: 0,0:59:31.61,0:59:32.99,Default,,0,0,0,,那么我就不需要再考虑它的具体实现了 Dialogue: 0,0:59:33.43,0:59:34.83,Default,,0,0,0,,我直接使用它 Dialogue: 0,0:59:35.07,0:59:36.43,Default,,0,0,0,,我合情合理地使用它 Dialogue: 0,0:59:36.43,0:59:37.45,Default,,0,0,0,,就会得到正确的结果 Dialogue: 0,0:59:39.95,0:59:42.57,Default,,0,0,0,,我们必须学会这种程序设计方法 -- 学会放弃 Dialogue: 0,0:59:47.56,0:59:49.05,Default,,0,0,0,,这里还有一点剩余 Dialogue: 0,0:59:50.40,0:59:54.46,Default,,0,0,0,,这里还有一些词典方面的细节 Dialogue: 0,0:59:55.08,0:59:58.32,Default,,0,0,0,,你们想知道到底词典是什么 Dialogue: 0,0:59:58.70,1:00:01.82,Default,,0,0,0,,但是我会跳过它 无可奉告 Dialogue: 0,1:00:04.14,1:00:05.20,Default,,0,0,0,,词典很简单 Dialogue: 0,1:00:06.01,1:00:09.84,Default,,0,0,0,,它是用一种被称为关联表的东西来表示的 Dialogue: 0,1:00:10.65,1:00:16.04,Default,,0,0,0,,这是一种特殊使用模式 用来在线性表中存放二维表 Dialogue: 0,1:00:16.50,1:00:20.17,Default,,0,0,0,,它们很简单 由序对构成 之前已经有同学问过了 Dialogue: 0,1:00:21.21,1:00:24.62,Default,,0,0,0,,有个特殊的过程叫做assq 用来处理这些东西 Dialogue: 0,1:00:24.94,1:00:26.36,Default,,0,0,0,,手册里面有 Dialogue: 0,1:00:27.04,1:00:28.59,Default,,0,0,0,,这个都无关紧要 Dialogue: 0,1:00:28.83,1:00:31.21,Default,,0,0,0,,重要的是如何扩充词典 Dialogue: 0,1:00:31.48,1:00:36.94,Default,,0,0,0,,要用一个模式、模式对应的数据、一本旧词典来扩充 Dialogue: 0,1:00:37.42,1:00:42.38,Default,,0,0,0,,这个模式pat 实际上是一个模式变量 Dialogue: 0,1:00:43.74,1:00:47.53,Default,,0,0,0,,我要做什么呢?我先从模式中取出模式变量的名字 Dialogue: 0,1:00:48.16,1:00:49.42,Default,,0,0,0,,把它赋给变量name Dialogue: 0,1:00:50.44,1:00:53.71,Default,,0,0,0,,然后我按照这个名字在词典中查找是否有对应的值 Dialogue: 0,1:00:53.79,1:00:56.41,Default,,0,0,0,,如果没有 就将这对新的模式-值加入到词典中 Dialogue: 0,1:00:56.92,1:00:59.23,Default,,0,0,0,,如果已经存在一个这样名字的词条 并且有值 Dialogue: 0,1:00:59.60,1:01:03.18,Default,,0,0,0,,那dat的值最好跟已经存储的值相等 Dialogue: 0,1:01:03.88,1:01:06.54,Default,,0,0,0,,这是我心目中期待的情况 Dialogue: 0,1:01:06.89,1:01:09.15,Default,,0,0,0,,否则 置失败 Dialogue: 0,1:01:12.08,1:01:12.89,Default,,0,0,0,,所以它也很简单 Dialogue: 0,1:01:13.66,1:01:16.68,Default,,0,0,0,,打开任何一个程序 你会发现它们都是由数个个小部分组成 Dialogue: 0,1:01:17.18,1:01:18.30,Default,,0,0,0,,许多简单的小部分 Dialogue: 0,1:01:20.04,1:01:21.29,Default,,0,0,0,,我想 到目前为止 Dialogue: 0,1:01:21.60,1:01:25.68,Default,,0,0,0,,我已经告诉给你们价值百万的信息了 Dialogue: 0,1:01:28.41,1:01:30.96,Default,,0,0,0,,我想这个程序几乎已经讲完了 Dialogue: 0,1:01:31.85,1:01:32.72,Default,,0,0,0,,有什么问题么? Dialogue: 0,1:01:34.27,1:01:38.16,Default,,0,0,0,,学生:你描述一下 化简后的表达式的规范么? Dialogue: 0,1:01:38.72,1:01:39.02,Default,,0,0,0,,教授:好的 Dialogue: 0,1:01:39.85,1:01:44.33,Default,,0,0,0,,simplify-exp接收一个表达式 返回一个化简后的表达式 Dialogue: 0,1:01:45.28,1:01:45.77,Default,,0,0,0,,就是这样了 Dialogue: 0,1:01:48.11,1:01:50.27,Default,,0,0,0,,它的工作方式很简单 Dialogue: 0,1:01:51.60,1:01:56.09,Default,,0,0,0,,对于复合表达式 先化简各部分后 再尝试化简整体 Dialogue: 0,1:01:56.89,1:01:58.49,Default,,0,0,0,,原子表达式 就直接代规则化简 Dialogue: 0,1:01:59.52,1:02:02.11,Default,,0,0,0,,学生:是这些规则把表达式化简了么? Dialogue: 0,1:02:02.76,1:02:03.58,Default,,0,0,0,,教授:当然 Dialogue: 0,1:02:03.76,1:02:03.90,Default,,0,0,0,,学生:好 Dialogue: 0,1:02:04.06,1:02:07.13,Default,,0,0,0,,教授:它们像你在这里看到的一样化简表达式 Dialogue: 0,1:02:08.35,1:02:11.64,Default,,0,0,0,,它先把表达式划分为小块 Dialogue: 0,1:02:12.60,1:02:17.29,Default,,0,0,0,,在化简器中使用这些规则 自下而上化简并构造表达式 Dialogue: 0,1:02:18.30,1:02:22.48,Default,,0,0,0,,处理它们 构造一个新的表达式作为结果 Dialogue: 0,1:02:24.28,1:02:29.44,Default,,0,0,0,,最后再尝试调用这些规则化简 Dialogue: 0,1:02:29.70,1:02:35.50,Default,,0,0,0,,当匹配的结果发生变化时 -- 就调用simplify-exp化简它 Dialogue: 0,1:02:35.80,1:02:40.64,Default,,0,0,0,,哦 不对是 骨架的实例化结果发生改变时 Dialogue: 0,1:02:42.00,1:02:47.36,Default,,0,0,0,,所以 规范就是 任何传入的表达式通过这些规则生成化简后的表达式 Dialogue: 0,1:02:49.84,1:02:50.76,Default,,0,0,0,,谢谢大家 下课 Dialogue: 0,1:02:53.64,1:03:06.96,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:02:53.64,1:03:06.96,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec4a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.0.4 ; http://www.aegisub.org/ Title: EN Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes Collisions: Normal Video Zoom Percent: 1 Scroll Position: 0 Active Line: 0 Video Zoom Percent: 0.65 PlayResX: 640 PlayResY: 480 YCbCr Matrix: TV.601 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:22.34,EN,,0,0,0,, Dialogue: 0,0:00:22.34,0:00:24.34,EN,,0,0,0,,Pattern-matching: Rule-based Substitution Dialogue: 0,0:00:24.34,0:00:29.34,EN,,0,0,0,,PROFESSOR: Well, yesterday we learned a bit about symbolic manipulation, Dialogue: 0,0:00:29.92,0:00:35.12,EN,,0,0,0,,and we wrote a rather stylized program Dialogue: 0,0:00:35.15,0:00:38.97,EN,,0,0,0,,to implement a pile of calculus rule from the calculus book. Dialogue: 0,0:00:39.61,0:00:44.59,EN,,0,0,0,,Here on the transparencies, Dialogue: 0,0:00:44.96,0:00:48.81,EN,,0,0,0,,we see a bunch of calculus rules from such a book. Dialogue: 0,0:00:49.47,0:00:54.62,EN,,0,0,0,,And, of course, what we did is sort of translate these rules into the language of the computer. Dialogue: 0,0:00:55.14,0:00:58.85,EN,,0,0,0,,But, of course, that's a sort of funny strategy. Dialogue: 0,0:00:59.36,0:01:04.80,EN,,0,0,0,,Why should we have to translate these rules into the language of the computer? Dialogue: 0,0:01:05.00,0:01:06.27,EN,,0,0,0,,And what do I really mean by that? Dialogue: 0,0:01:06.62,0:01:11.02,EN,,0,0,0,,These are--the program we wrote yesterday was very stylized. Dialogue: 0,0:01:11.21,0:01:15.98,EN,,0,0,0,,It was a conditional, a dispatch on the type of the expression Dialogue: 0,0:01:16.38,0:01:18.48,EN,,0,0,0,,as observed by the rules. Dialogue: 0,0:01:19.68,0:01:21.55,EN,,0,0,0,,What we see here are rules that say Dialogue: 0,0:01:21.74,0:01:25.48,EN,,0,0,0,,if the object being the derivative is being taken of, Dialogue: 0,0:01:25.48,0:01:29.42,EN,,0,0,0,,if that expression is a constant, then do one thing. Dialogue: 0,0:01:29.42,0:01:31.37,EN,,0,0,0,,If it's a variable, do another thing. Dialogue: 0,0:01:31.60,0:01:35.56,EN,,0,0,0,,If it's a product of a constant times a variable, do something and so on. Dialogue: 0,0:01:36.00,0:01:38.96,EN,,0,0,0,,There's sort of a dispatch there on a type. Dialogue: 0,0:01:41.40,0:01:45.16,EN,,0,0,0,,Well, since it has such a stylized behavior and structure, Dialogue: 0,0:01:45.95,0:01:49.53,EN,,0,0,0,,is there some other way of writing this program that's more clear? Dialogue: 0,0:01:50.83,0:01:53.45,EN,,0,0,0,,Well, what's a rule, first of all, What are these rules? Dialogue: 0,0:01:55.56,0:01:58.50,EN,,0,0,0,,Let's think about that. Rules have parts. Dialogue: 0,0:01:58.94,0:02:02.35,EN,,0,0,0,,If you look at these rules in detail, Dialogue: 0,0:02:03.71,0:02:04.99,EN,,0,0,0,,what you see, for example, Dialogue: 0,0:02:05.12,0:02:09.69,EN,,0,0,0,,is the rule has a left-hand side and a right-hand side. Dialogue: 0,0:02:10.36,0:02:14.36,EN,,0,0,0,,Each of these rules has a left-hand side and the right-hand side. Dialogue: 0,0:02:15.15,0:02:20.30,EN,,0,0,0,,The left-hand side is somehow compared with the expression you're trying to take the derivative of. Dialogue: 0,0:02:21.52,0:02:25.10,EN,,0,0,0,,The right-hand side is the replacement for that expression. Dialogue: 0,0:02:28.49,0:02:33.10,EN,,0,0,0,,So all rules on this page are something like this. Dialogue: 0,0:02:36.51,0:02:38.06,EN,,0,0,0,,I have patterns, Dialogue: 0,0:02:41.48,0:02:48.30,EN,,0,0,0,,and somehow, I have to produce, given a pattern, a skeleton. Dialogue: 0,0:02:51.88,0:02:52.81,EN,,0,0,0,,This is a rule. Dialogue: 0,0:02:55.42,0:02:57.13,EN,,0,0,0,,A pattern is something that matches, Dialogue: 0,0:02:57.88,0:03:03.26,EN,,0,0,0,,and a skeleton is something you substitute into in order to get a new expression. Dialogue: 0,0:03:06.46,0:03:16.32,EN,,0,0,0,,So what that means is that the pattern is matched against the expression, which is the source expression. Dialogue: 0,0:03:23.72,0:03:28.51,EN,,0,0,0,,And the result of the application of the rule is to produce a new expression, Dialogue: 0,0:03:33.61,0:03:34.91,EN,,0,0,0,,which I'll call a target, Dialogue: 0,0:03:38.12,0:03:39.88,EN,,0,0,0,,by instantiation of a skeleton. Dialogue: 0,0:03:41.63,0:03:43.02,EN,,0,0,0,,That's called instantiation. Dialogue: 0,0:03:50.72,0:03:54.73,EN,,0,0,0,,So that is the process by which these rules are described. Dialogue: 0,0:03:55.69,0:03:57.26,EN,,0,0,0,,What I'd like to do today Dialogue: 0,0:03:58.73,0:04:01.08,EN,,0,0,0,,is build a language Dialogue: 0,0:04:02.20,0:04:05.48,EN,,0,0,0,,and a means of interpreting that language, a means of executing that language, Dialogue: 0,0:04:05.74,0:04:08.43,EN,,0,0,0,,where that language allows us to directly express these rules. Dialogue: 0,0:04:10.59,0:04:11.58,EN,,0,0,0,,And what we're going to do Dialogue: 0,0:04:11.58,0:04:17.56,EN,,0,0,0,,instead of bringing the rules to the level of the computer by writing a program that is those rules Dialogue: 0,0:04:18.38,0:04:21.56,EN,,0,0,0,,in the computer's language--at the moment, in a Lisp-- Dialogue: 0,0:04:22.16,0:04:24.49,EN,,0,0,0,,we're going to bring the computer to the level of us Dialogue: 0,0:04:25.48,0:04:29.15,EN,,0,0,0,,by writing a way by which the computer can understand rules of this sort. Dialogue: 0,0:04:30.91,0:04:34.76,EN,,0,0,0,,This is slightly emphasizing the idea that we had last time Dialogue: 0,0:04:35.44,0:04:39.36,EN,,0,0,0,,that we're trying to make a solution to a class of problems rather than a particular one. Dialogue: 0,0:04:39.77,0:04:46.72,EN,,0,0,0,,The problem is if I want to write rules for a different piece of mathematics, Dialogue: 0,0:04:48.24,0:04:51.39,EN,,0,0,0,,say, to simple algebraic simplification or something like that, Dialogue: 0,0:04:51.98,0:04:55.48,EN,,0,0,0,,or manipulation of trigonometric functions, Dialogue: 0,0:04:56.09,0:05:01.16,EN,,0,0,0,,I would have to write a different program in using yesterday's method. Dialogue: 0,0:05:01.16,0:05:05.42,EN,,0,0,0,,Whereas I would like to encapsulate all of the things that are common to both of those programs, Dialogue: 0,0:05:06.12,0:05:10.17,EN,,0,0,0,,meaning the idea of matching, instantiation, the control structure, Dialogue: 0,0:05:10.17,0:05:12.46,EN,,0,0,0,,which turns out to be very complicated for such a thing, Dialogue: 0,0:05:13.16,0:05:18.46,EN,,0,0,0,,I'd like to encapsulate that separately from the rules themselves. Dialogue: 0,0:05:20.06,0:05:22.60,EN,,0,0,0,,So let's look at, first of all, a representation. Dialogue: 0,0:05:22.62,0:05:24.09,EN,,0,0,0,,I'd like to use the overhead here. Dialogue: 0,0:05:24.67,0:05:25.60,EN,,0,0,0,,I'd like-- there it is. Dialogue: 0,0:05:26.25,0:05:32.27,EN,,0,0,0,,I'd like to look at a representation of the rules of calculus for derivatives Dialogue: 0,0:05:33.71,0:05:37.15,EN,,0,0,0,,in a sort of simple language that I'm writing right here. Dialogue: 0,0:05:38.11,0:05:43.29,EN,,0,0,0,,Now, I'm going to avoid--I'm going to avoid worrying about syntax. Dialogue: 0,0:05:44.28,0:05:49.28,EN,,0,0,0,,We can easily pretty this, and I'm not interested in making-- this is indeed ugly. Dialogue: 0,0:05:49.30,0:05:56.41,EN,,0,0,0,,This doesn't look like the beautiful text set dx by dt or something that I'd like to write, Dialogue: 0,0:05:56.76,0:05:58.12,EN,,0,0,0,,but that's not essential. Dialogue: 0,0:05:58.88,0:06:00.62,EN,,0,0,0,,That's sort of an accidental phenomenon. Dialogue: 0,0:06:01.00,0:06:04.44,EN,,0,0,0,,Here, we're just worrying about the fact that the structure of the rules Dialogue: 0,0:06:04.83,0:06:11.70,EN,,0,0,0,,is that there is a left-hand side here, represents the thing I want to match against the derivative expression. Dialogue: 0,0:06:11.80,0:06:13.56,EN,,0,0,0,,This is the representation I'm going to say Dialogue: 0,0:06:13.60,0:06:18.32,EN,,0,0,0,,for the derivative of a constant, which we will call c Dialogue: 0,0:06:18.84,0:06:21.20,EN,,0,0,0,,respect to the variable we will call v. Dialogue: 0,0:06:23.08,0:06:25.55,EN,,0,0,0,,And what we will get on the right-hand side is 0. Dialogue: 0,0:06:26.00,0:06:28.06,EN,,0,0,0,,So this represents a rule. Dialogue: 0,0:06:29.26,0:06:34.04,EN,,0,0,0,,The next rule will be the derivative of a variable, which we will call v Dialogue: 0,0:06:34.22,0:06:37.74,EN,,0,0,0,,respect to the same variable v, and we get a 1. Dialogue: 0,0:06:38.60,0:06:42.17,EN,,0,0,0,,However, if we have the derivative of a variable called u Dialogue: 0,0:06:42.41,0:06:44.84,EN,,0,0,0,,respect to a different variables v, Dialogue: 0,0:06:45.39,0:06:47.05,EN,,0,0,0,,we will get 0. Dialogue: 0,0:06:47.84,0:06:52.17,EN,,0,0,0,,I just want you look at these rules a little bit and see how they fit together. Dialogue: 0,0:06:52.51,0:06:54.30,EN,,0,0,0,,For example, over here, Dialogue: 0,0:06:54.73,0:07:01.90,EN,,0,0,0,,we're going to have the derivative of the sum of an expression called x1 and an expression called x2. Dialogue: 0,0:07:01.90,0:07:05.85,EN,,0,0,0,,These things that begin with question marks are called pattern variables Dialogue: 0,0:07:06.88,0:07:08.62,EN,,0,0,0,,in the language that we're inventing, Dialogue: 0,0:07:08.93,0:07:14.93,EN,,0,0,0,,and you see we're just making it up, so pattern variables for matching. Dialogue: 0,0:07:14.93,0:07:20.33,EN,,0,0,0,,And so in this-- here we have the derivative of the sum of the expression which we will call x1. Dialogue: 0,0:07:20.33,0:07:26.70,EN,,0,0,0,,And the expression we will call x2 with respect to the variable we call v will be-- here is the right-hand side: Dialogue: 0,0:07:26.70,0:07:32.76,EN,,0,0,0,,the sum of the derivative of that expression x1 with respect to v-- the right-hand side is the skeleton-- Dialogue: 0,0:07:33.82,0:07:37.10,EN,,0,0,0,,and the derivative of x2 with respect to v. Dialogue: 0,0:07:37.60,0:07:42.38,EN,,0,0,0,,Colons here will stand for substitution objects. Dialogue: 0,0:07:43.63,0:07:47.23,EN,,0,0,0,,They're--we'll call them skeleton evaluations. Dialogue: 0,0:07:48.51,0:07:53.07,EN,,0,0,0,,So let me put up here on the blackboard for a second some syntax Dialogue: 0,0:07:53.23,0:07:55.56,EN,,0,0,0,,so we'll know what's going on for this rule language. Dialogue: 0,0:07:56.68,0:07:59.88,EN,,0,0,0,,First of all, we're going to have to worry about the pattern matching. Dialogue: 0,0:08:06.04,0:08:13.12,EN,,0,0,0,,We're going to have things like a symbol like foo matches exactly itself. Dialogue: 0,0:08:23.52,0:08:31.34,EN,,0,0,0,,The expression f of a and b will be used to match any list Dialogue: 0,0:08:36.30,0:08:57.02,EN,,0,0,0,,whose first element is f, whose second element is a, and whose third element is b. Dialogue: 0,0:08:58.62,0:09:06.99,EN,,0,0,0,,Also, another thing we might have in a pattern is that--a question mark with some variable like x. Dialogue: 0,0:09:08.57,0:09:18.67,EN,,0,0,0,,And what that means, it says matches anything, which we will call x. Dialogue: 0,0:09:25.45,0:09:29.98,EN,,0,0,0,,Question mark c x will match only constants. Dialogue: 0,0:09:31.50,0:09:40.96,EN,,0,0,0,,So this is something which matches a constant called x. Dialogue: 0,0:09:44.56,0:09:57.07,EN,,0,0,0,,And question mark v x will match a variable, which we call x. Dialogue: 0,0:10:01.66,0:10:03.80,EN,,0,0,0,,This is sort of the language we're making up now. Dialogue: 0,0:10:04.19,0:10:09.40,EN,,0,0,0,,If I match two things against each other, then they are compared element by element Dialogue: 0,0:10:10.25,0:10:15.85,EN,,0,0,0,,But elements in the pattern may contain these syntactic variables, Dialogue: 0,0:10:17.07,0:10:20.43,EN,,0,0,0,,which will be used to match arbitrary objects. Dialogue: 0,0:10:22.12,0:10:29.28,EN,,0,0,0,,And we'll get that object as the value in the name x here, for example. Dialogue: 0,0:10:31.05,0:10:37.55,EN,,0,0,0,,Now, when we make skeletons for instantiation. Dialogue: 0,0:10:39.50,0:10:41.40,EN,,0,0,0,,Well, then we have things like this. Dialogue: 0,0:10:42.27,0:10:46.33,EN,,0,0,0,,foo, a symbol, instantiates to itself. Dialogue: 0,0:10:55.08,0:11:05.92,EN,,0,0,0,,Something which is a list like f of a and b, instantiates to-- Dialogue: 0,0:11:06.36,0:11:14.75,EN,,0,0,0,,well, f instantiates to a 3-list, a list of three elements, Dialogue: 0,0:11:15.55,0:11:33.37,EN,,0,0,0,,okay, which are the results of instantiating each of f, a, and b. Dialogue: 0,0:11:36.35,0:11:54.27,EN,,0,0,0,,And x well--we instantiate to the value of x as in the matched pattern. Dialogue: 0,0:12:03.05,0:12:10.08,EN,,0,0,0,,So going back to the overhead here, we see -- we see that all of those kinds of objects Dialogue: 0,0:12:10.78,0:12:16.06,EN,,0,0,0,,we see here a pattern variable which matches a constant, Dialogue: 0,0:12:16.56,0:12:19.02,EN,,0,0,0,,a pattern variable which matches a variable, Dialogue: 0,0:12:19.39,0:12:21.74,EN,,0,0,0,,a pattern variable which will match anything. Dialogue: 0,0:12:22.72,0:12:24.92,EN,,0,0,0,,And if we have two instances of the same name, Dialogue: 0,0:12:25.08,0:12:31.77,EN,,0,0,0,,like this is the derivative of the expression which is a variable only whose name will be v Dialogue: 0,0:12:32.86,0:12:36.30,EN,,0,0,0,,with respect to some arbitrary expression which we will call v, Dialogue: 0,0:12:36.41,0:12:38.01,EN,,0,0,0,,since this v appears twice, Dialogue: 0,0:12:38.65,0:12:41.07,EN,,0,0,0,,we're going to want that to mean they have to be the same. Dialogue: 0,0:12:42.68,0:12:45.00,EN,,0,0,0,,The only consistent match is that those are the same. Dialogue: 0,0:12:45.23,0:12:47.23,EN,,0,0,0,,So here, we're making up a language. Dialogue: 0,0:12:47.60,0:12:50.66,EN,,0,0,0,,And in fact, that's a very nice thing to be doing. Dialogue: 0,0:12:50.66,0:12:52.60,EN,,0,0,0,,It's so much fun to make up a language. Dialogue: 0,0:12:52.60,0:12:54.33,EN,,0,0,0,,And you do this all the time. Dialogue: 0,0:12:54.33,0:12:56.89,EN,,0,0,0,,And the really most powerful design things you ever do Dialogue: 0,0:12:57.23,0:13:00.20,EN,,0,0,0,,are sort of making up a language to solve problems like this. Dialogue: 0,0:13:02.06,0:13:05.34,EN,,0,0,0,,Now, here we go back here and look at some of these rules. Dialogue: 0,0:13:05.80,0:13:07.10,EN,,0,0,0,,Well, there's a whole set of them. Dialogue: 0,0:13:07.10,0:13:12.43,EN,,0,0,0,,I mean, there's one for addition and one for multiplication, just like we had before. Dialogue: 0,0:13:12.43,0:13:17.37,EN,,0,0,0,,The derivative of the product of x1 and x2 with respect to v is Dialogue: 0,0:13:17.68,0:13:26.52,EN,,0,0,0,,the sum of the product of x1 and the derivative x2 with respect to v and the product of the derivative of x1 and x2. Dialogue: 0,0:13:27.26,0:13:29.10,EN,,0,0,0,,And here we have exponentiation. Dialogue: 0,0:13:29.24,0:13:32.11,EN,,0,0,0,,And, of course, we run off the end down here. We get as many as we like. Dialogue: 0,0:13:32.70,0:13:39.10,EN,,0,0,0,,But the whole thing over here, I'm giving this--this list of rules the name "derivative rules." Dialogue: 0,0:13:40.40,0:13:44.33,EN,,0,0,0,,What would we do with such a thing once we have it? Dialogue: 0,0:13:45.40,0:13:47.84,EN,,0,0,0,,Well, one of the nicest ideas, first of all, Dialogue: 0,0:13:48.44,0:13:51.68,EN,,0,0,0,,is I'm going to write for you, and we're going to play with it all day. Dialogue: 0,0:13:52.28,0:13:57.37,EN,,0,0,0,,What I'm going to write for you is a program called simplifier, Dialogue: 0,0:13:57.82,0:13:59.47,EN,,0,0,0,,the general-purpose simplifier. Dialogue: 0,0:14:00.09,0:14:17.10,EN,,0,0,0,,And we're going to say something like define dsimp to be a simplifier of the derivative rules. Dialogue: 0,0:14:23.74,0:14:28.75,EN,,0,0,0,,And what simplifier is going to do is, given a set of rules, it will produce for me a procedure Dialogue: 0,0:14:29.32,0:14:34.59,EN,,0,0,0,,which will simplify expressions containing the things that are referred to by these rules. Dialogue: 0,0:14:37.39,0:14:43.93,EN,,0,0,0,,So here will be a procedure constructed for your purposes to simplify things with derivatives in them Dialogue: 0,0:14:44.59,0:14:49.56,EN,,0,0,0,,such that, after that, if we're typing at some Lisp system, and we get a prompt, Dialogue: 0,0:14:49.88,0:15:03.93,EN,,0,0,0,,and we say dsimp, for example, of the derivative of the sum of x and y with respect to x-- Dialogue: 0,0:15:06.99,0:15:10.97,EN,,0,0,0,,note the quote here because I'm talking about the expression which is the derivative-- Dialogue: 0,0:15:13.29,0:15:17.76,EN,,0,0,0,,then I will get back as a result plus 1 0. Dialogue: 0,0:15:19.96,0:15:24.60,EN,,0,0,0,,Because the derivative of x plus y is the derivative of x plus derivative y. Dialogue: 0,0:15:24.60,0:15:26.22,EN,,0,0,0,,The derivative of x with respect to x is 1. Dialogue: 0,0:15:26.38,0:15:27.82,EN,,0,0,0,,The derivative of y with respect to x is 0. Dialogue: 0,0:15:29.42,0:15:30.46,EN,,0,0,0,,It's not what we're going to get. Dialogue: 0,0:15:31.18,0:15:34.65,EN,,0,0,0,,I haven't put any simplification at that level-- algebraic simplification--yet. Dialogue: 0,0:15:36.16,0:15:41.53,EN,,0,0,0,,Of course, once we have such a thing, then we can--then we can look at other rules. Dialogue: 0,0:15:41.96,0:15:49.36,EN,,0,0,0,,So, for example, we can, if we go to the slide, OK? Dialogue: 0,0:15:49.36,0:15:54.12,EN,,0,0,0,,Here, for example, are other rules that we might have, algebraic manipulation rules, Dialogue: 0,0:15:56.00,0:15:58.38,EN,,0,0,0,,ones that would be used for simplifying algebraic expressions. Dialogue: 0,0:15:59.00,0:16:02.06,EN,,0,0,0,,For example, just looking at some of these, Dialogue: 0,0:16:03.04,0:16:09.20,EN,,0,0,0,,the left-hand side says any operator applied to a constant e1 and a constant e2 Dialogue: 0,0:16:09.32,0:16:14.51,EN,,0,0,0,,is the result of evaluating that operator on the constants e1 and e2. Dialogue: 0,0:16:15.88,0:16:21.56,EN,,0,0,0,,Or an operator, applied to e1, any expression e1 and a constant e2, Dialogue: 0,0:16:21.69,0:16:23.87,EN,,0,0,0,,is going to move the constant forward. Dialogue: 0,0:16:24.52,0:16:27.68,EN,,0,0,0,,So that'll turn into the operator with e2 followed by e1. Dialogue: 0,0:16:28.59,0:16:30.11,EN,,0,0,0,,Why I did that, I don't know. Dialogue: 0,0:16:30.22,0:16:33.16,EN,,0,0,0,,It wouldn't work if I had division, for example. Dialogue: 0,0:16:33.53,0:16:35.31,EN,,0,0,0,,So there's a bug in the rules, if you like. Dialogue: 0,0:16:36.67,0:16:40.86,EN,,0,0,0,,So the sum of 0 and e is e. Dialogue: 0,0:16:42.17,0:16:45.31,EN,,0,0,0,,The product of 1 and any expression e is e. Dialogue: 0,0:16:46.12,0:16:49.13,EN,,0,0,0,,The product of 0 and any expression e is 0. Dialogue: 0,0:16:49.33,0:16:52.72,EN,,0,0,0,,Just looking at some more of these rules, we could have arbitrarily complicated ones. Dialogue: 0,0:16:53.69,0:16:54.81,EN,,0,0,0,,We could have things like Dialogue: 0,0:16:55.36,0:17:01.69,EN,,0,0,0,,the product of the constant e1 and any constant e2 with e3 Dialogue: 0,0:17:02.35,0:17:11.96,EN,,0,0,0,,is the result of multiplying the result of multiplying now the constants e1 and e2 together and putting e3 there. Dialogue: 0,0:17:13.36,0:17:16.76,EN,,0,0,0,,So it says combine the constants that I had, Dialogue: 0,0:17:16.76,0:17:22.70,EN,,0,0,0,,which was if I had a product of e1 and e2 and e3 just multiply--I mean and e1 and e2 are both constants, multiply them. Dialogue: 0,0:17:23.84,0:17:25.48,EN,,0,0,0,,And you can make up the rules as you like. Dialogue: 0,0:17:25.79,0:17:26.94,EN,,0,0,0,,There are lots of them here. Dialogue: 0,0:17:27.42,0:17:31.04,EN,,0,0,0,,There are things as complicated, for example, as-- Dialogue: 0,0:17:31.26,0:17:33.93,EN,,0,0,0,,oh, I suppose down here some distributive law, you see. Dialogue: 0,0:17:33.93,0:17:38.57,EN,,0,0,0,,The product of any object c and the sum of d and e Dialogue: 0,0:17:39.02,0:17:43.66,EN,,0,0,0,,gives the result as the same as the sum of the product of c and d and the product of c and e. Dialogue: 0,0:17:45.31,0:17:48.67,EN,,0,0,0,,Now, what exactly these rules are doesn't very much interest me. Dialogue: 0,0:17:49.16,0:17:52.97,EN,,0,0,0,,We're going to be writing the language that will allow us to interpret these rules Dialogue: 0,0:17:55.50,0:17:57.48,EN,,0,0,0,,so that we can, in fact, make up whatever rules we like, Dialogue: 0,0:17:58.35,0:18:00.14,EN,,0,0,0,,another whole language of programming. Dialogue: 0,0:18:03.39,0:18:04.04,EN,,0,0,0,,Well, let's see. Dialogue: 0,0:18:05.18,0:18:06.96,EN,,0,0,0,,I haven't told you how we're going to do this. Dialogue: 0,0:18:07.53,0:18:10.06,EN,,0,0,0,,And, of course, for a while, we're going to work on that. Dialogue: 0,0:18:10.89,0:18:15.40,EN,,0,0,0,,But there's a real question of what is--what am I going to do at all at a large scale? Dialogue: 0,0:18:17.08,0:18:18.22,EN,,0,0,0,,How do these rules work? Dialogue: 0,0:18:19.00,0:18:25.45,EN,,0,0,0,,How is the simplifier program going to manipulate these rules with your expression to produce a reasonable answer? Dialogue: 0,0:18:26.22,0:18:29.85,EN,,0,0,0,,Well, first, I'd like to think about these rules as being some sort of deck of them. Dialogue: 0,0:18:32.52,0:18:34.22,EN,,0,0,0,,So here I have a whole bunch of rules, Dialogue: 0,0:18:42.09,0:18:44.49,EN,,0,0,0,,Each rule-- here's a rule-- Dialogue: 0,0:18:46.97,0:18:49.24,EN,,0,0,0,,has a pattern and a skeleton. Dialogue: 0,0:18:49.72,0:18:51.36,EN,,0,0,0,,I'm trying to make up a control structure for this. Dialogue: 0,0:18:53.37,0:18:56.56,EN,,0,0,0,,Now, what I have is a matcher, Dialogue: 0,0:19:00.99,0:19:03.76,EN,,0,0,0,,and I have something which is an instantiater. Dialogue: 0,0:19:09.66,0:19:12.94,EN,,0,0,0,,And I'm going to pass from the matcher to the instantiater Dialogue: 0,0:19:14.03,0:19:17.47,EN,,0,0,0,,some set of meaning for the pattern variables, Dialogue: 0,0:19:18.06,0:19:19.42,EN,,0,0,0,,a dictionary, I'll call it. Dialogue: 0,0:19:20.59,0:19:21.52,EN,,0,0,0,,A dictionary, Dialogue: 0,0:19:24.92,0:19:27.82,EN,,0,0,0,,which will say x was matched against the following subexpression Dialogue: 0,0:19:29.04,0:19:31.31,EN,,0,0,0,,and y was matched against another following subexpression. Dialogue: 0,0:19:32.25,0:19:36.35,EN,,0,0,0,,And from the instantiater, I will be making expressions,and they will go into the matcher. Dialogue: 0,0:19:37.16,0:19:38.36,EN,,0,0,0,,They will be expressions. Dialogue: 0,0:19:45.00,0:19:48.41,EN,,0,0,0,,And the patterns of the rules will be fed into the matcher, Dialogue: 0,0:19:49.24,0:19:54.40,EN,,0,0,0,,and the skeletons from the same rule will be fed into the instantiater. Dialogue: 0,0:19:55.21,0:19:56.62,EN,,0,0,0,,Now, this is a little complicated Dialogue: 0,0:19:57.12,0:19:59.53,EN,,0,0,0,,because when you have something like an algebraic expression, Dialogue: 0,0:20:00.44,0:20:03.60,EN,,0,0,0,,where some of the rules are intended to be able to allow you to substitute equal for equal. Dialogue: 0,0:20:04.24,0:20:05.87,EN,,0,0,0,,These are equal transformation rules. Dialogue: 0,0:20:06.88,0:20:09.29,EN,,0,0,0,,So all subexpressions of the expression should be looked at. Dialogue: 0,0:20:11.13,0:20:15.82,EN,,0,0,0,,You give it an expression, this thing, and the rules should be cycled around. Dialogue: 0,0:20:16.03,0:20:19.71,EN,,0,0,0,,First of all, for every subexpression of the expression you feed in, Dialogue: 0,0:20:20.22,0:20:22.83,EN,,0,0,0,,all of the rules must be tried and looked at. Dialogue: 0,0:20:24.33,0:20:27.07,EN,,0,0,0,,And if any rule matches, then this process occurs. Dialogue: 0,0:20:27.30,0:20:30.63,EN,,0,0,0,,The dictionary--the dictionary is to have some values in it. Dialogue: 0,0:20:30.63,0:20:33.39,EN,,0,0,0,,The instantiater makes a new expression, Dialogue: 0,0:20:33.90,0:20:39.10,EN,,0,0,0,,which is basically replaces that part of the expression that was matched in your original expression. Dialogue: 0,0:20:40.84,0:20:44.46,EN,,0,0,0,,And then, then, of course, we're going to recheck that, Dialogue: 0,0:20:44.75,0:20:48.11,EN,,0,0,0,,going to go around these rules again, seeing if that could be simplified further. Dialogue: 0,0:20:49.53,0:20:53.71,EN,,0,0,0,,And then, then we're going to do that for every subexpression until the thing no longer changes. Dialogue: 0,0:20:54.96,0:20:57.50,EN,,0,0,0,,You can think of this as sort of an organic process. Dialogue: 0,0:20:57.83,0:21:00.20,EN,,0,0,0,,You've got some sort of stew, right? Dialogue: 0,0:21:00.24,0:21:04.32,EN,,0,0,0,,You've got bacteria or something, or enzymes in some, in some gooey mess. Dialogue: 0,0:21:05.63,0:21:10.50,EN,,0,0,0,,And there's these--and these enzymes change things. Dialogue: 0,0:21:10.50,0:21:14.38,EN,,0,0,0,,They attach to your expression, change it, and then they go away. Dialogue: 0,0:21:15.28,0:21:17.83,EN,,0,0,0,,And they have to match. The key-in-lock phenomenon. Dialogue: 0,0:21:18.00,0:21:19.73,EN,,0,0,0,,They match, they change it, they go away. Dialogue: 0,0:21:19.73,0:21:21.68,EN,,0,0,0,,You can imagine it as a parallel process of some sort. Dialogue: 0,0:21:22.70,0:21:24.97,EN,,0,0,0,,So you stick an expression into this mess, Dialogue: 0,0:21:25.80,0:21:28.00,EN,,0,0,0,,and after a while, you take it out, and it's been simplified. Dialogue: 0,0:21:30.44,0:21:32.64,EN,,0,0,0,,And it just keeps changing until it no longer can be changed. Dialogue: 0,0:21:33.36,0:21:38.33,EN,,0,0,0,,But these enzymes can attach to any part of the, of the expression. Dialogue: 0,0:21:39.21,0:21:43.76,EN,,0,0,0,,OK, at this point, I'd like to stop and ask for questions. Dialogue: 0,0:21:44.92,0:21:45.36,EN,,0,0,0,,Yes. Dialogue: 0,0:21:45.43,0:21:52.76,EN,,0,0,0,,AUDIENCE: This implies that the matching program and the instantiation program are separate programs; is that right? Or is that-- they are. Dialogue: 0,0:21:52.76,0:21:53.85,EN,,0,0,0,,PROFESSOR: They're separate little pieces. Dialogue: 0,0:21:54.14,0:21:56.60,EN,,0,0,0,,They fit together in a larger structure. Dialogue: 0,0:21:57.26,0:21:59.13,EN,,0,0,0,,AUDIENCE: So I'm going through and matching Dialogue: 0,0:21:59.61,0:22:03.21,EN,,0,0,0,,and passing the information about what I matched to an instantiater, Dialogue: 0,0:22:03.39,0:22:06.03,EN,,0,0,0,,which makes the changes. And then I pass that back to the matcher? Dialogue: 0,0:22:06.11,0:22:08.49,EN,,0,0,0,,PROFESSOR: It won't make a change. It will make a new expression, Dialogue: 0,0:22:09.61,0:22:18.43,EN,,0,0,0,,which has, which has substituted the values of the pattern variable that were matched on the left-hand side for the variables that are mentioned, Dialogue: 0,0:22:18.99,0:22:23.80,EN,,0,0,0,,the skeleton variables or evaluation variables or whatever I called them, on the right-hand side. Dialogue: 0,0:22:25.20,0:22:27.08,EN,,0,0,0,,AUDIENCE: And then that's passed back into the matcher? Dialogue: 0,0:22:27.20,0:22:32.32,EN,,0,0,0,,PROFESSOR: Then this is going to go around again. This is going to go through this mess until it no longer changes. Dialogue: 0,0:22:33.31,0:22:37.00,EN,,0,0,0,,AUDIENCE: And it seems that there would be a danger of getting into a recursive loop. Dialogue: 0,0:22:37.20,0:22:42.00,EN,,0,0,0,,Yes, if you do not write your rules nicely, you are-- indeed, Dialogue: 0,0:22:42.00,0:22:45.53,EN,,0,0,0,,in any programming language you invent, if it's sufficiently powerful to do anything, Dialogue: 0,0:22:45.72,0:22:48.40,EN,,0,0,0,,you can write programs that will go into infinite loops. Dialogue: 0,0:22:49.37,0:22:55.07,EN,,0,0,0,,And indeed, writing a program for doing algebraic manipulation so on will produce infinite loops. Dialogue: 0,0:23:01.05,0:23:01.52,EN,,0,0,0,,Go ahead. Dialogue: 0,0:23:01.79,0:23:05.90,EN,,0,0,0,,AUDIENCE: Some language designers feel that this feature is so important Dialogue: 0,0:23:05.93,0:23:12.03,EN,,0,0,0,,that it should become part of the basic language, for example, scheme in this case. Dialogue: 0,0:23:12.03,0:23:13.96,EN,,0,0,0,,What are your thoughts on-- Dialogue: 0,0:23:13.96,0:23:15.08,EN,,0,0,0,,PROFESSOR: Which language feature? Dialogue: 0,0:23:15.79,0:23:17.26,EN,,0,0,0,,AUDIENCE: The pattern matching. Dialogue: 0,0:23:17.26,0:23:22.03,EN,,0,0,0,,It's all application of such rules should be-- Dialogue: 0,0:23:22.03,0:23:23.70,EN,,0,0,0,,PROFESSOR: Oh, you mean like Prolog? Dialogue: 0,0:23:23.70,0:23:26.60,EN,,0,0,0,,AUDIENCE: Like Prolog, but it becomes a more general-- Dialogue: 0,0:23:26.60,0:23:27.64,EN,,0,0,0,,PROFESSOR: It's possible. Dialogue: 0,0:23:28.46,0:23:32.30,EN,,0,0,0,,OK, I think my feeling about that is that Dialogue: 0,0:23:33.16,0:23:36.49,EN,,0,0,0,,I would like to teach you how to do it so you don't depend upon some language designer. Dialogue: 0,0:23:40.92,0:23:42.75,EN,,0,0,0,,PROFESSOR: You make it yourself. You can roll your own. Dialogue: 0,0:23:45.28,0:23:45.63,EN,,0,0,0,,Thank you. Dialogue: 0,0:23:45.63,0:23:50.63,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:23:50.63,0:23:53.13,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:23:53.13,0:23:55.63,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:24:00.32,0:24:06.76,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:24:07.07,0:24:10.52,Declare,,0,0,0,,{\an2\fad(500,500)}Pattern-matching: Rule-based Substitution Dialogue: 0,0:24:14.08,0:24:15.80,EN,,0,0,0,,Well, let's see. Dialogue: 0,0:24:15.80,0:24:17.21,EN,,0,0,0,,Now we have to tell you how it works. Dialogue: 0,0:24:20.00,0:24:24.11,EN,,0,0,0,,It conveniently breaks up into various pieces. Dialogue: 0,0:24:24.80,0:24:26.54,EN,,0,0,0,,I'd like to look now at the matcher. Dialogue: 0,0:24:28.72,0:24:31.42,EN,,0,0,0,,The matcher has the following basic structure. Dialogue: 0,0:24:32.86,0:24:45.12,EN,,0,0,0,,It's a box that takes as its input an expression and a pattern, Dialogue: 0,0:24:52.09,0:24:53.95,EN,,0,0,0,,and it turns out a dictionary. Dialogue: 0,0:25:01.71,0:25:08.67,EN,,0,0,0,,A dictionary, remember, is a mapping of pattern variables to the values that were found by matching, Dialogue: 0,0:25:09.15,0:25:11.05,EN,,0,0,0,,and it puts out another dictionary, Dialogue: 0,0:25:18.24,0:25:25.53,EN,,0,0,0,,which is the result of augmenting this dictionary by what was found in matching this expression against this pattern. Dialogue: 0,0:25:28.00,0:25:28.83,EN,,0,0,0,,So that's the matcher. Dialogue: 0,0:25:33.87,0:25:36.54,EN,,0,0,0,,Now, this is a rather complicated program, Dialogue: 0,0:25:37.20,0:25:41.58,EN,,0,0,0,,and we can look at it on the overhead over here and see, Dialogue: 0,0:25:41.98,0:25:43.87,EN,,0,0,0,,ha ha, it's very complicated. Dialogue: 0,0:25:44.43,0:25:45.87,EN,,0,0,0,,I just want you to look at the shape of it. Dialogue: 0,0:25:46.78,0:25:49.85,EN,,0,0,0,,It's too complicated to look at except in pieces. Dialogue: 0,0:25:51.72,0:25:59.24,EN,,0,0,0,,However, it's a fairly large, complicated program with a lot of sort of indented structure. Dialogue: 0,0:26:00.09,0:26:05.28,EN,,0,0,0,,At the largest scale-- you don't try to read those characters, but at the largest scale, Dialogue: 0,0:26:05.43,0:26:10.36,EN,,0,0,0,,you see that there is a case analysis, which is all these cases lined up. Dialogue: 0,0:26:12.09,0:26:16.19,EN,,0,0,0,,What we're now going to do is look at this in a bit more detail, Dialogue: 0,0:26:16.67,0:26:18.60,EN,,0,0,0,,attempting to understand how it works. Dialogue: 0,0:26:20.08,0:26:22.35,EN,,0,0,0,,Let's go now to the first slide, Dialogue: 0,0:26:23.55,0:26:27.93,EN,,0,0,0,,showing some of the structure of the matcher at a large scale. Dialogue: 0,0:26:28.81,0:26:36.33,EN,,0,0,0,,And we see that the matcher, the matcher takes as its input a pattern, an expression, and a dictionary. Dialogue: 0,0:26:38.57,0:26:40.40,EN,,0,0,0,,And there is a case analysis here, Dialogue: 0,0:26:41.24,0:26:45.61,EN,,0,0,0,,which is made out of several cases, some of which have been left out over here, Dialogue: 0,0:26:46.62,0:26:48.62,EN,,0,0,0,,and the general case, which I'd like you to see. Dialogue: 0,0:26:50.52,0:26:53.28,EN,,0,0,0,,Let's consider this general case. It's a very important pattern. Dialogue: 0,0:26:56.32,0:27:01.61,EN,,0,0,0,,The problem is that we have to examine two trees simultaneously. Dialogue: 0,0:27:02.50,0:27:08.03,EN,,0,0,0,,One of the trees is the tree of the expression, and the other is the tree of the pattern. Dialogue: 0,0:27:08.59,0:27:10.11,EN,,0,0,0,,We have to compare them with each other Dialogue: 0,0:27:11.37,0:27:16.38,EN,,0,0,0,,so that the subexpressions of the expression are matched against subexpressions of the pattern. Dialogue: 0,0:27:18.38,0:27:23.44,EN,,0,0,0,,Looking at that in a bit more detail, suppose I had a pattern, a pattern, Dialogue: 0,0:27:23.93,0:27:31.24,EN,,0,0,0,,which was the sum of the product of a thing which we will call x Dialogue: 0,0:27:32.44,0:27:35.53,EN,,0,0,0,,and a thing which we will call y, Dialogue: 0,0:27:39.12,0:27:42.04,EN,,0,0,0,,and the sum of that, and the same thing we call y. Dialogue: 0,0:27:45.21,0:27:47.53,EN,,0,0,0,,So we're looking for a sum of a product Dialogue: 0,0:27:48.99,0:27:54.78,EN,,0,0,0,,whose second--whose second argument is the same as the second argument of the sum. Dialogue: 0,0:27:57.02,0:27:58.84,EN,,0,0,0,,That's a thing you might be looking for. Dialogue: 0,0:27:59.60,0:28:02.04,EN,,0,0,0,,Well, that, as a pattern, looks like this. Dialogue: 0,0:28:03.02,0:28:04.01,EN,,0,0,0,,There is a tree, Dialogue: 0,0:28:04.94,0:28:06.25,EN,,0,0,0,,which consists of a sum, Dialogue: 0,0:28:08.08,0:28:20.25,EN,,0,0,0,,and a product with a pattern variable question mark x and question mark y, Dialogue: 0,0:28:21.36,0:28:22.73,EN,,0,0,0,,and question mark y, Dialogue: 0,0:28:24.92,0:28:26.94,EN,,0,0,0,,just looking at the same, just writing down the list structure in a different way. Dialogue: 0,0:28:28.75,0:28:31.76,EN,,0,0,0,,Now, suppose we were matching that against an expression which matches it, Dialogue: 0,0:28:32.49,0:28:39.85,EN,,0,0,0,,the product of 3 and x and, say, x. Dialogue: 0,0:28:42.41,0:28:43.36,EN,,0,0,0,,That's another tree. Dialogue: 0,0:28:44.33,0:28:56.06,EN,,0,0,0,,It's the sum of the product of 3 and x and of x. Dialogue: 0,0:28:59.44,0:29:03.02,EN,,0,0,0,,So what I want to do is traverse these two trees simultaneously. Dialogue: 0,0:29:04.41,0:29:07.82,EN,,0,0,0,,And what I'd like to do is walk them like this. Dialogue: 0,0:29:08.67,0:29:12.96,EN,,0,0,0,,I'm going to say are these the same? Dialogue: 0,0:29:12.96,0:29:14.32,EN,,0,0,0,,This is a complicated object. Dialogue: 0,0:29:15.21,0:29:17.26,EN,,0,0,0,,Let's look at the left branches. Dialogue: 0,0:29:17.26,0:29:18.14,EN,,0,0,0,,Well, that could be the car. Dialogue: 0,0:29:18.56,0:29:21.21,EN,,0,0,0,,How does that look? Oh yes, the plus looks just fine. Dialogue: 0,0:29:21.68,0:29:24.20,EN,,0,0,0,,But the next thing here is a complicated thing. Dialogue: 0,0:29:24.20,0:29:24.84,EN,,0,0,0,,Let's look at that. Dialogue: 0,0:29:25.20,0:29:26.80,EN,,0,0,0,,Oh yes, that's pretty fine, too. Dialogue: 0,0:29:26.80,0:29:27.79,EN,,0,0,0,,They're both asterisks. Dialogue: 0,0:29:28.51,0:29:30.24,EN,,0,0,0,,Now, whoops! Dialogue: 0,0:29:30.40,0:29:33.60,EN,,0,0,0,,My pattern variable, it matches against the 3. Dialogue: 0,0:29:34.27,0:29:35.92,EN,,0,0,0,,Remember, x equals 3 now. Dialogue: 0,0:29:36.36,0:29:37.37,EN,,0,0,0,,That's in my dictionary, Dialogue: 0,0:29:37.56,0:29:40.73,EN,,0,0,0,,and the dictionary's going to follow along with me: x equals three. Dialogue: 0,0:29:41.45,0:29:45.87,EN,,0,0,0,,Ah yes, x equals 3 and y equals x, different x. Dialogue: 0,0:29:46.83,0:29:51.20,EN,,0,0,0,,The pattern x is the expression x, the pattern y. Dialogue: 0,0:29:53.61,0:29:57.76,EN,,0,0,0,,Oh yes, the pattern variable y, I've already got a value for it. It's x. Dialogue: 0,0:29:58.36,0:30:00.06,EN,,0,0,0,,Is this an x? Oh yeah, sure it is. Dialogue: 0,0:30:00.06,0:30:00.75,EN,,0,0,0,,That's fine. Dialogue: 0,0:30:02.03,0:30:02.78,EN,,0,0,0,,Yep, done. Dialogue: 0,0:30:03.39,0:30:08.09,EN,,0,0,0,,I now have a dictionary, which I've accumulated by making this walk. Dialogue: 0,0:30:11.42,0:30:14.51,EN,,0,0,0,,Well, now let's look at this general case here and see how that works. Dialogue: 0,0:30:15.88,0:30:16.51,EN,,0,0,0,,Here we have it. Dialogue: 0,0:30:17.20,0:30:21.66,EN,,0,0,0,,I take in a pattern variable -- sorry -- a pattern, an expression, and a dictionary. Dialogue: 0,0:30:22.38,0:30:27.50,EN,,0,0,0,,And now I'm going to do a complicated thing here, which is the general case. Dialogue: 0,0:30:29.98,0:30:34.80,EN,,0,0,0,,The expression is made out of two parts: a left and a right half, in general. Dialogue: 0,0:30:35.45,0:30:38.81,EN,,0,0,0,,Anything that's complicated is made out of two pieces in a Lisp system. Dialogue: 0,0:30:40.03,0:30:41.23,EN,,0,0,0,,Well, now what do we have here? Dialogue: 0,0:30:41.88,0:30:48.84,EN,,0,0,0,,I'm going to match the car's of the two expressions against each other with respect to the dictionary I already have, Dialogue: 0,0:30:50.30,0:30:53.12,EN,,0,0,0,,producing a dictionary as its value, Dialogue: 0,0:30:54.14,0:30:57.26,EN,,0,0,0,,which I will then use for matching the cdr's against each other. Dialogue: 0,0:30:58.51,0:31:02.09,EN,,0,0,0,,So that's how the dictionary travels, threads the entire structure. Dialogue: 0,0:31:03.66,0:31:07.53,EN,,0,0,0,,And then the result of that is the dictionary for the match of the car and the cdr, Dialogue: 0,0:31:10.12,0:31:12.41,EN,,0,0,0,,and that's what's going to be returned as a value. Dialogue: 0,0:31:13.61,0:31:15.84,EN,,0,0,0,,Now, at any point, a match might fail. Dialogue: 0,0:31:16.62,0:31:18.20,EN,,0,0,0,,It may be the case, for example, Dialogue: 0,0:31:18.36,0:31:27.18,EN,,0,0,0,,if we go back and look at an expression that doesn't quite match, like supposing this was a 4. Dialogue: 0,0:31:29.13,0:31:34.81,EN,,0,0,0,,Well, now these two don't match any more, because the x that had to be -- Dialogue: 0,0:31:34.93,0:31:37.34,EN,,0,0,0,,sorry, the y that had to be x here Dialogue: 0,0:31:37.82,0:31:40.12,EN,,0,0,0,,and this y has to be 4. Dialogue: 0,0:31:40.53,0:31:43.52,EN,,0,0,0,,But x and 4 were not the same object syntactically. Dialogue: 0,0:31:44.59,0:31:48.81,EN,,0,0,0,,So this wouldn't match, and that would be rejected sometimes, so matches may fail. Dialogue: 0,0:31:50.19,0:31:56.08,EN,,0,0,0,,Now, of course, because this matcher takes the dictionary from the previous match as input, Dialogue: 0,0:31:56.52,0:31:58.28,EN,,0,0,0,,it must be able to propagate the failures. Dialogue: 0,0:31:58.57,0:32:01.04,EN,,0,0,0,,And so that's what the first clause of this conditional does. Dialogue: 0,0:32:03.61,0:32:08.19,EN,,0,0,0,,It's also true that if it turned out that the pattern was not atomic-- Dialogue: 0,0:32:08.50,0:32:11.45,EN,,0,0,0,,see, if the pattern was atomic, I'd go into this stuff, which we haven't looked at yet. Dialogue: 0,0:32:12.17,0:32:13.56,EN,,0,0,0,,But if the pattern is not atomic Dialogue: 0,0:32:15.05,0:32:19.23,EN,,0,0,0,,and the expression is atomic-- it's not made out of pieces-- Dialogue: 0,0:32:20.14,0:32:22.65,EN,,0,0,0,,then that must be a failure, and so we go over here. Dialogue: 0,0:32:23.64,0:32:30.78,EN,,0,0,0,,If the pattern is not atomic and the pattern is not a pattern variable--I have to remind myself of that-- then we go over here. Dialogue: 0,0:32:30.96,0:32:32.51,EN,,0,0,0,,So that's way, failures may occur. Dialogue: 0,0:32:35.26,0:32:39.12,EN,,0,0,0,,OK, so now let's look at the insides of this thing. Dialogue: 0,0:32:39.84,0:32:42.93,EN,,0,0,0,,Well, the first place to look is what happens if I have an atomic pattern? Dialogue: 0,0:32:42.93,0:32:43.90,EN,,0,0,0,,That's very simple. Dialogue: 0,0:32:43.90,0:32:46.50,EN,,0,0,0,,A pattern that's not made out of any pieces: foo. Dialogue: 0,0:32:47.37,0:32:48.54,EN,,0,0,0,,That's a nice atomic pattern. Dialogue: 0,0:32:49.16,0:32:51.24,EN,,0,0,0,,Well, here's what we see. Dialogue: 0,0:32:52.08,0:32:55.82,EN,,0,0,0,,If the pattern is atomic, then if the expression is atomic, Dialogue: 0,0:32:56.80,0:33:01.85,EN,,0,0,0,,then if they are the same thing, then the dictionary I get is the same one as I had before. Dialogue: 0,0:33:03.08,0:33:04.00,EN,,0,0,0,,Nothing's changed. Dialogue: 0,0:33:04.60,0:33:10.33,EN,,0,0,0,,It's just that I matched plus against plus, asterisk against asterisk, x against x. Dialogue: 0,0:33:11.42,0:33:12.33,EN,,0,0,0,,That's all fine. Dialogue: 0,0:33:13.07,0:33:16.81,EN,,0,0,0,,However, if the pattern is not the one which is the expression, Dialogue: 0,0:33:17.32,0:33:21.36,EN,,0,0,0,,if I have two separate atomic objects, then it was matching plus against asterisk, Dialogue: 0,0:33:22.44,0:33:23.40,EN,,0,0,0,,which case I fail. Dialogue: 0,0:33:25.60,0:33:34.56,EN,,0,0,0,,Or if it turns out that the pattern is atomic but the expression is complicated, it's not atomic, then I get a failure. Dialogue: 0,0:33:37.40,0:33:38.24,EN,,0,0,0,,That's very simple. Dialogue: 0,0:33:38.81,0:33:43.61,EN,,0,0,0,,Now, what about the various kinds of pattern variables? Dialogue: 0,0:33:44.09,0:33:46.54,EN,,0,0,0,,We had three kinds. I give them the names. Dialogue: 0,0:33:47.39,0:33:52.03,EN,,0,0,0,,They're arbitrary constants, arbitrary variables, and arbitrary expressions. Dialogue: 0,0:33:53.82,0:34:00.14,EN,,0,0,0,,A question mark x is an arbitrary expression. Dialogue: 0,0:34:01.18,0:34:04.54,EN,,0,0,0,,A question mark cx is an arbitrary constant, Dialogue: 0,0:34:04.73,0:34:07.29,EN,,0,0,0,,and a question mark vx is an arbitrary variable. Dialogue: 0,0:34:08.96,0:34:09.79,EN,,0,0,0,,Well, what do we do here? Dialogue: 0,0:34:10.51,0:34:16.94,EN,,0,0,0,,Looking at this, we see that if I have an arbitrary constant, if the pattern is an arbitrary constant, Dialogue: 0,0:34:17.53,0:34:20.57,EN,,0,0,0,,then it had better be the case that the expression had better be a constant. Dialogue: 0,0:34:21.48,0:34:23.53,EN,,0,0,0,,If the expression is not a constant, then that match fails. Dialogue: 0,0:34:23.83,0:34:27.50,EN,,0,0,0,,If it is a constant, however, then I wish to extend the dictionary. Dialogue: 0,0:34:27.50,0:34:29.69,EN,,0,0,0,,I wish to extend the dictionary Dialogue: 0,0:34:30.70,0:34:37.76,EN,,0,0,0,,with that pattern being remembered to be that expression using the old dictionary as a starting point. Dialogue: 0,0:34:41.16,0:34:42.75,EN,,0,0,0,,So really, for arbitrary variables, Dialogue: 0,0:34:43.72,0:34:47.46,EN,,0,0,0,,I have to check first if the expression is a variable by matching against. Dialogue: 0,0:34:47.46,0:34:50.09,EN,,0,0,0,,If so, it's worth extending the dictionary Dialogue: 0,0:34:50.38,0:34:54.65,EN,,0,0,0,,so the pattern is remembered to be matched against that expression, given the original dictionary, Dialogue: 0,0:34:55.28,0:34:56.70,EN,,0,0,0,,and this makes a new dictionary. Dialogue: 0,0:34:58.88,0:35:04.16,EN,,0,0,0,,Now, it has to check. There's a sorts of failure inside extend dictionary, which is that-- Dialogue: 0,0:35:04.16,0:35:07.50,EN,,0,0,0,,if one of these pattern variables already has a value Dialogue: 0,0:35:09.23,0:35:16.17,EN,,0,0,0,,and I'm trying to match the thing against something else which is not equivalent to the one that I've already matched it against once, Dialogue: 0,0:35:16.43,0:35:18.36,EN,,0,0,0,,then a failure will come flying out of here, too. Dialogue: 0,0:35:20.16,0:35:21.56,EN,,0,0,0,,And I will see that some time. Dialogue: 0,0:35:22.91,0:35:29.36,EN,,0,0,0,,And finally, an expression does not have to check anything syntactic about the expression that's being matched, Dialogue: 0,0:35:30.11,0:35:32.20,EN,,0,0,0,,so all it does is it's an extension of the dictionary. Dialogue: 0,0:35:34.76,0:35:38.32,EN,,0,0,0,,So you've just seen a complete, very simple matcher. Dialogue: 0,0:35:39.28,0:35:41.37,EN,,0,0,0,,Now, one of the things that's rather remarkable about this Dialogue: 0,0:35:41.66,0:35:45.12,EN,,0,0,0,,is people pay an awful lot of money these days for someone to make Dialogue: 0,0:35:45.46,0:35:47.52,EN,,0,0,0,,a, quote, AI expert system Dialogue: 0,0:35:48.40,0:35:52.03,EN,,0,0,0,,that has nothing more in it than a matcher and maybe an instantiater like this. Dialogue: 0,0:35:53.56,0:35:56.94,EN,,0,0,0,,But it's very easy to do, and now, of course, you can start up a little start-up company Dialogue: 0,0:35:57.42,0:36:01.72,EN,,0,0,0,,and make a couple of megabucks in the next week taking some people for a ride. Dialogue: 0,0:36:03.79,0:36:08.57,EN,,0,0,0,,I mean, 20 years ago, this was remarkable, this kind of program. Dialogue: 0,0:36:09.74,0:36:12.81,EN,,0,0,0,,But now, this is sort of easy. You can teach it to freshmen. Dialogue: 0,0:36:13.63,0:36:15.47,EN,,0,0,0,,Well, now there's an instantiater as well. Dialogue: 0,0:36:20.22,0:36:23.07,EN,,0,0,0,,The problem is they're all going off and making more money than I do. Alright? Dialogue: 0,0:36:24.97,0:36:26.59,EN,,0,0,0,,But that's always been true of universities. Dialogue: 0,0:36:27.10,0:36:39.42,EN,,0,0,0,,As expression, the purpose of the instantiater is to make expressions given a dictionary and a skeleton. Dialogue: 0,0:36:44.35,0:36:45.69,EN,,0,0,0,,And that's not very hard at all. Dialogue: 0,0:36:46.60,0:36:53.36,EN,,0,0,0,,We'll see that very simply in the next, the next slide here. Dialogue: 0,0:36:53.88,0:36:59.29,EN,,0,0,0,,To instantiate a skeleton, given a particular dictionary-- oh, this is easy. Dialogue: 0,0:36:59.68,0:37:03.29,EN,,0,0,0,,We're going to do a recursive tree walk over the skeleton. Dialogue: 0,0:37:04.08,0:37:08.33,EN,,0,0,0,,And for everything which is a skeleton variable-- I don't know, call it a skeleton evaluation. Dialogue: 0,0:37:08.41,0:37:11.42,EN,,0,0,0,,That's the name and the abstract syntax that I give it in this program: Dialogue: 0,0:37:11.60,0:37:16.46,EN,,0,0,0,,a skeleton evaluation, a thing beginning with a colon in the rules. Dialogue: 0,0:37:18.25,0:37:24.30,EN,,0,0,0,,For anything of that case, I'm going to look up the answer in the dictionary, and we'll worry about that in a second. Dialogue: 0,0:37:24.30,0:37:25.61,EN,,0,0,0,,Let's look at this as a whole. Dialogue: 0,0:37:27.77,0:37:31.80,EN,,0,0,0,,Here, I have-- I'm going to instantiate a skeleton, given a dictionary. Dialogue: 0,0:37:32.75,0:37:37.15,EN,,0,0,0,,Well, I'm going to define some internal loop right there, Dialogue: 0,0:37:38.14,0:37:39.85,EN,,0,0,0,,and it's going to do something very simple. Dialogue: 0,0:37:40.17,0:37:43.50,EN,,0,0,0,,Even if a skeleton--even if a skeleton is simple and atomic, Dialogue: 0,0:37:44.60,0:37:47.45,EN,,0,0,0,,in which case it's nothing more than giving the skeleton back as an answer, Dialogue: 0,0:37:48.84,0:37:51.87,EN,,0,0,0,,or in the general case, it's complicated, Dialogue: 0,0:37:52.60,0:37:59.40,EN,,0,0,0,,in which case I'm going to make up the expression which is the result of instantiating-- Dialogue: 0,0:37:59.40,0:38:04.25,EN,,0,0,0,,calling this loop recursively-- instantiating the car of the skeleton and the cdr. Dialogue: 0,0:38:04.89,0:38:06.24,EN,,0,0,0,,So here is a recursive tree walk. Dialogue: 0,0:38:08.41,0:38:14.36,EN,,0,0,0,,However, if it turns out to be a skeleton evaluation, a colon expression in the skeleton, Dialogue: 0,0:38:14.96,0:38:22.64,EN,,0,0,0,,then what I'm going to do is find the expression that's in the colon-- the CADR in this case. Dialogue: 0,0:38:22.81,0:38:26.25,EN,,0,0,0,,It's a piece of abstract syntax here, so I can change my representation of rules. Dialogue: 0,0:38:27.52,0:38:32.73,EN,,0,0,0,,I'm going to evaluate that relative to this dictionary, whatever evaluation means. Dialogue: 0,0:38:32.90,0:38:34.65,EN,,0,0,0,,We'll find out a lot about that sometime. Dialogue: 0,0:38:36.12,0:38:38.35,EN,,0,0,0,,And the result of that is my answer. Dialogue: 0,0:38:39.68,0:38:43.66,EN,,0,0,0,,so. I start up this loop-- here's my initialization-- by calling it with the whole skeleton, Dialogue: 0,0:38:44.44,0:38:47.04,EN,,0,0,0,,and this will just do a recursive decomposition into pieces. Dialogue: 0,0:38:49.63,0:38:56.48,EN,,0,0,0,,Now, one more little bit of detail is what happens inside evaluate? Dialogue: 0,0:38:57.18,0:38:59.07,EN,,0,0,0,,I can't tell you that in great detail. Dialogue: 0,0:38:59.98,0:39:01.34,EN,,0,0,0,,I'll tell you a little bit of it. Dialogue: 0,0:39:01.56,0:39:03.74,EN,,0,0,0,,Later, we're going to see--look into this in much more detail. Dialogue: 0,0:39:05.29,0:39:10.81,EN,,0,0,0,,To evaluate some form, some expression with respect to a dictionary, Dialogue: 0,0:39:11.90,0:39:14.17,EN,,0,0,0,,if the expression is an atomic object, well, Dialogue: 0,0:39:15.04,0:39:16.22,EN,,0,0,0,,I'm going to go look it up. Dialogue: 0,0:39:18.60,0:39:19.87,EN,,0,0,0,,Nothing very exciting there. Dialogue: 0,0:39:20.57,0:39:23.66,EN,,0,0,0,,Otherwise, I'm going to do something complicated here, Dialogue: 0,0:39:23.83,0:39:28.28,EN,,0,0,0,,which is I'm going to apply a procedure which is the result of looking up the operator part Dialogue: 0,0:39:29.44,0:39:31.68,EN,,0,0,0,,in something that we're going to find out about someday. Dialogue: 0,0:39:32.14,0:39:34.20,EN,,0,0,0,,I want you realize you're seeing magic now. Dialogue: 0,0:39:34.67,0:39:38.72,EN,,0,0,0,,This magic will become clear very soon, but not today. Dialogue: 0,0:39:40.00,0:39:46.51,EN,,0,0,0,,Then I'm looking at--looking up all the pieces, all the arguments to that in the dictionary. Dialogue: 0,0:39:48.56,0:39:50.88,EN,,0,0,0,,So I don't want you to look at this in detail. Dialogue: 0,0:39:51.44,0:39:53.44,EN,,0,0,0,,I want you to see that there's more going on here, Dialogue: 0,0:39:54.17,0:39:56.75,EN,,0,0,0,,and we're going to see more about this. Dialogue: 0,0:39:59.04,0:40:00.88,EN,,0,0,0,,But it's-- the magic is going to stop. Dialogue: 0,0:40:02.57,0:40:06.96,EN,,0,0,0,,This part has to do with Lisp, and it's the end of that. Dialogue: 0,0:40:10.25,0:40:13.56,EN,,0,0,0,,OK, so now we know about matching and instantiation. Dialogue: 0,0:40:15.05,0:40:16.60,EN,,0,0,0,,Are there any questions for this segment? Dialogue: 0,0:40:28.10,0:40:29.80,EN,,0,0,0,,AUDIENCE: I have a question. Dialogue: 0,0:40:29.80,0:40:30.43,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,0:40:30.43,0:40:32.56,EN,,0,0,0,,AUDIENCE: Is it possible to bring up a previous slide? Dialogue: 0,0:40:33.60,0:40:35.56,EN,,0,0,0,,It's about this define match pattern. Dialogue: 0,0:40:36.16,0:40:40.76,EN,,0,0,0,,PROFESSOR: Yes. You'd like to see the overall slide define match pattern. Dialogue: 0,0:40:40.76,0:40:43.06,EN,,0,0,0,,Can somebody put up the -- no, the overhead. Dialogue: 0,0:40:43.06,0:40:45.16,EN,,0,0,0,,That's the biggest scale one. Dialogue: 0,0:40:45.31,0:40:46.40,EN,,0,0,0,,What part would you like to see? Dialogue: 0,0:40:46.76,0:40:49.96,EN,,0,0,0,,AUDIENCE: Well, the top would be fine. Dialogue: 0,0:40:49.96,0:40:53.76,EN,,0,0,0,,Any of the parts where you're passing failed. Dialogue: 0,0:40:54.52,0:40:55.21,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,0:40:55.64,0:40:59.33,EN,,0,0,0,,AUDIENCE: The idea is to pass failed back to the dictionary; is that right? Dialogue: 0,0:40:59.33,0:41:04.25,EN,,0,0,0,,PROFESSOR: The dictionary is the answer to a match, right? Dialogue: 0,0:41:05.16,0:41:09.80,EN,,0,0,0,,And it is either some mapping Dialogue: 0,0:41:11.07,0:41:14.03,EN,,0,0,0,,or there's no match. It doesn't match. Dialogue: 0,0:41:14.46,0:41:14.97,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,0:41:15.26,0:41:17.83,EN,,0,0,0,,PROFESSOR: So what you're seeing over here is, in fact, Dialogue: 0,0:41:17.83,0:41:22.60,EN,,0,0,0,,because the fact that a match may have another match pass in the dictionary, Dialogue: 0,0:41:22.80,0:41:24.65,EN,,0,0,0,,as you see in the general case down here. Dialogue: 0,0:41:25.12,0:41:27.93,EN,,0,0,0,,Here's the general case where a match passes another match to the dictionary. Dialogue: 0,0:41:28.14,0:41:34.16,EN,,0,0,0,,When I match the cdr's, I match them in the dictionary that is resulting from matching the car's. Dialogue: 0,0:41:36.06,0:41:37.08,EN,,0,0,0,,OK, that's what I have here. Dialogue: 0,0:41:37.29,0:41:40.30,EN,,0,0,0,,So because of that, if the match of the car's fails, Dialogue: 0,0:41:41.23,0:41:45.44,EN,,0,0,0,,then it may be necessary that the match of the cdr's propagates that failure, Dialogue: 0,0:41:45.95,0:41:46.96,EN,,0,0,0,,and that's what the first line is. Dialogue: 0,0:41:48.26,0:41:51.73,EN,,0,0,0,,AUDIENCE: OK, well, I'm still unclear what matches-- Dialogue: 0,0:41:51.73,0:41:54.24,EN,,0,0,0,,what comes out of one instance of the match? Dialogue: 0,0:41:54.73,0:41:56.00,EN,,0,0,0,,PROFESSOR: One of two possibilities. Dialogue: 0,0:41:56.33,0:41:59.15,EN,,0,0,0,,Either the symbol failed, which means there is no match. Dialogue: 0,0:41:59.53,0:41:59.93,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,0:41:59.93,0:42:03.87,EN,,0,0,0,,PROFESSOR: Or some mapping, which is an abstract thing right now, Dialogue: 0,0:42:04.16,0:42:05.68,EN,,0,0,0,,and you should know about the structure of it, Dialogue: 0,0:42:06.49,0:42:13.96,EN,,0,0,0,,which relates the pattern variables to their values as picked up in the match. Dialogue: 0,0:42:14.68,0:42:16.70,EN,,0,0,0,,AUDIENCE: OK, so it is-- Dialogue: 0,0:42:16.80,0:42:18.57,EN,,0,0,0,,PROFESSOR: That's constructed by extend dictionary. Dialogue: 0,0:42:18.80,0:42:28.54,EN,,0,0,0,,AUDIENCE: So the recursive nature brings about the fact that if ever a failed gets passed out of any calling of match, Dialogue: 0,0:42:28.68,0:42:30.30,EN,,0,0,0,,then the first condition will pick it up-- Dialogue: 0,0:42:30.40,0:42:33.56,EN,,0,0,0,,PROFESSOR: And just propagate it along without any further ado, right. Dialogue: 0,0:42:33.56,0:42:34.83,EN,,0,0,0,,AUDIENCE: Oh, right. Dialogue: 0,0:42:35.50,0:42:37.36,EN,,0,0,0,,PROFESSOR: That's just the fastest way to get that failure out of there. Dialogue: 0,0:42:42.86,0:42:43.60,EN,,0,0,0,,Yes. Dialogue: 0,0:42:43.84,0:42:47.23,EN,,0,0,0,,AUDIENCE: If I don't fail, that means that I've matched a pattern, Dialogue: 0,0:42:47.84,0:42:53.00,EN,,0,0,0,,and I run the procedure extend dict and then pass in the pattern in the expression. Dialogue: 0,0:42:55.21,0:42:58.43,EN,,0,0,0,,But the substitution will not be made at that point; is that right? Dialogue: 0,0:42:58.43,0:42:59.03,EN,,0,0,0,,I'm just-- Dialogue: 0,0:42:59.03,0:42:59.46,EN,,0,0,0,,PROFESSOR: No, no. Dialogue: 0,0:42:59.46,0:43:02.40,EN,,0,0,0,,There's no substitution being there because there's no skeleton to be substituted in. Dialogue: 0,0:43:02.40,0:43:03.06,EN,,0,0,0,,AUDIENCE: Right. So Dialogue: 0,0:43:03.06,0:43:07.16,EN,,0,0,0,,PROFESSOR: All you've got there is we're making up the dictionary for later substitution. Dialogue: 0,0:43:08.25,0:43:12.43,EN,,0,0,0,,AUDIENCE: And what would the dictionary look like? Is it ordered pairs? Dialogue: 0,0:43:12.72,0:43:15.96,EN,,0,0,0,,PROFESSOR: Ahhhhh, That's--that's not told to you. Dialogue: 0,0:43:15.96,0:43:16.89,EN,,0,0,0,,We're being abstract. Dialogue: 0,0:43:17.06,0:43:17.56,EN,,0,0,0,,AUDIENCE: OK. Dialogue: 0,0:43:17.56,0:43:18.90,EN,,0,0,0,,PROFESSOR: Why do you want to know? Dialogue: 0,0:43:18.90,0:43:21.64,EN,,0,0,0,,What it is, it's a function. It's a function. Dialogue: 0,0:43:21.69,0:43:22.33,EN,,0,0,0,,AUDIENCE: Well, the reason I want to know is-- Dialogue: 0,0:43:22.33,0:43:24.17,EN,,0,0,0,,PROFESSOR: A function abstractly is a set of ordered pairs. Dialogue: 0,0:43:25.12,0:43:28.44,EN,,0,0,0,,It could be implemented as a set of list pairs. Dialogue: 0,0:43:29.06,0:43:32.43,EN,,0,0,0,,It could be implemented as some fancy table mechanism. Dialogue: 0,0:43:32.56,0:43:34.16,EN,,0,0,0,,It could be implemented as a function. Dialogue: 0,0:43:35.80,0:43:37.40,EN,,0,0,0,,And somehow, I'm building up a function. Dialogue: 0,0:43:39.02,0:43:39.87,EN,,0,0,0,,But I'm not telling you. Dialogue: 0,0:43:40.84,0:43:43.08,EN,,0,0,0,,That's up to George, who's going to build that later. Dialogue: 0,0:43:49.56,0:43:52.06,EN,,0,0,0,,I know you really badly want to write concrete things. Dialogue: 0,0:43:52.36,0:43:54.19,EN,,0,0,0,,I'm not going to let you do that. Dialogue: 0,0:43:54.43,0:43:59.23,EN,,0,0,0,,AUDIENCE: Well, let me at least ask, what is the important information there that's being passed to extend dict? Dialogue: 0,0:43:59.74,0:44:02.08,EN,,0,0,0,,I want to pass the pattern I found-- Dialogue: 0,0:44:02.73,0:44:04.83,EN,,0,0,0,,PROFESSOR: Yes. The pattern that's matched against the expression. Dialogue: 0,0:44:04.83,0:44:09.30,EN,,0,0,0,,You want to have the pattern, which happens to be in those cases pattern variables, right? Dialogue: 0,0:44:09.85,0:44:12.89,EN,,0,0,0,,All of those three cases for extend dict are pattern variables. Dialogue: 0,0:44:13.20,0:44:13.50,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,0:44:14.48,0:44:18.75,EN,,0,0,0,,PROFESSOR: So you have a pattern variable that is to be given a value in a dictionary. Dialogue: 0,0:44:19.45,0:44:22.11,EN,,0,0,0,,PROFESSOR: The value is the expression that it matched against. Dialogue: 0,0:44:23.31,0:44:29.63,EN,,0,0,0,,The dictionary is the set of things I've already figured out that I have memorized or learned. Dialogue: 0,0:44:30.54,0:44:34.41,EN,,0,0,0,,And I am going to make a new dictionary, which is extended from the original one Dialogue: 0,0:44:35.12,0:44:38.35,EN,,0,0,0,,by having that pattern variable have a value with the new dictionary. Dialogue: 0,0:44:39.98,0:44:43.73,EN,,0,0,0,,AUDIENCE: I guess what I don't understand is why can't the substitution be made right as soon as you find-- Dialogue: 0,0:44:43.73,0:44:44.80,EN,,0,0,0,,PROFESSOR: How do I know what I'm going to substitute? Dialogue: 0,0:44:44.81,0:44:46.62,EN,,0,0,0,,I don't know anything about this skeleton. Dialogue: 0,0:44:47.58,0:44:49.66,EN,,0,0,0,,This pattern, this matcher is an independent unit. Dialogue: 0,0:44:49.66,0:44:51.00,EN,,0,0,0,,AUDIENCE: Oh, I see. OK. Dialogue: 0,0:44:51.00,0:44:51.50,EN,,0,0,0,,PROFESSOR: Right? Dialogue: 0,0:44:51.50,0:44:51.90,EN,,0,0,0,,AUDIENCE: Yeah. Dialogue: 0,0:44:51.90,0:44:57.23,EN,,0,0,0,,PROFESSOR: I take the matcher. I apply the matcher. If it matches, then it was worth doing instantiation. Dialogue: 0,0:44:58.20,0:44:59.50,EN,,0,0,0,,AUDIENCE: OK, good. Dialogue: 0,0:45:00.54,0:45:03.88,EN,,0,0,0,,AUDIENCE: Can you just do that answer again using that example on the board? Dialogue: 0,0:45:04.89,0:45:06.93,EN,,0,0,0,,You know, what you just passed back to the matcher. Dialogue: 0,0:45:06.93,0:45:08.00,EN,,0,0,0,,PROFESSOR: Oh yes. OK, yes. Dialogue: 0,0:45:08.26,0:45:09.74,EN,,0,0,0,,You're looking at this example. Dialogue: 0,0:45:10.67,0:45:15.45,EN,,0,0,0,,At this point when I'm traversing this structure, I get to here: x. Dialogue: 0,0:45:16.67,0:45:20.54,EN,,0,0,0,,I have some dictionary, presumably an empty dictionary at this point if this is the whole expression. Dialogue: 0,0:45:21.56,0:45:25.36,EN,,0,0,0,,So I have an empty dictionary, and I've matched x against 3. Dialogue: 0,0:45:26.62,0:45:33.60,EN,,0,0,0,,So now, after this point,the dictionary contains x is 3, OK? Dialogue: 0,0:45:33.64,0:45:36.09,EN,,0,0,0,,Now, I continue walking along here. I see y. Dialogue: 0,0:45:36.89,0:45:39.20,EN,,0,0,0,,Now, this is a particular x, a pattern x. Dialogue: 0,0:45:39.79,0:45:41.37,EN,,0,0,0,,I see y, a pattern y. Dialogue: 0,0:45:42.17,0:45:47.74,EN,,0,0,0,,The dictionary says, oh yes, the pattern y is the symbol x Dialogue: 0,0:45:48.99,0:45:51.20,EN,,0,0,0,,because I've gota match there. Dialogue: 0,0:45:52.43,0:45:54.52,EN,,0,0,0,,So the dictionary now contains at this point two entries. Dialogue: 0,0:45:55.45,0:45:59.90,EN,,0,0,0,,The pattern x is 3, and the pattern y is the expression x. Dialogue: 0,0:46:01.95,0:46:04.11,EN,,0,0,0,,Now, I get that, I can walk along further. Dialogue: 0,0:46:04.23,0:46:07.45,EN,,0,0,0,,I say, oh, pattern y also wants to be 4. Dialogue: 0,0:46:08.06,0:46:10.65,EN,,0,0,0,,But that isn't possible, producing a failure. Dialogue: 0,0:46:14.30,0:46:15.48,EN,,0,0,0,,Thank you. Let's take a break. Dialogue: 0,0:46:16.76,0:46:25.02,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:46:25.07,0:46:27.45,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:46:27.47,0:46:30.00,Declare,,0,0,0,,{\an2\fad(500,500)}By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:46:48.19,0:46:54.75,Declare,,0,0,0,,{\an2\fad(500,500)}The Structure And Interpretation of Computer Programs Dialogue: 0,0:46:55.20,0:46:58.04,Declare,,0,0,0,,{\an2\fad(500,500)}Pattern-matching: Rule-based Substitution Dialogue: 0,0:47:02.38,0:47:05.68,EN,,0,0,0,,OK, you're seeing your first very big and hairy program. Dialogue: 0,0:47:07.34,0:47:09.90,EN,,0,0,0,,Now, of course, one of the goals of this subject Dialogue: 0,0:47:09.90,0:47:12.97,EN,,0,0,0,,is to get you to be able to read something like this and not be afraid of it. Dialogue: 0,0:47:13.76,0:47:16.33,EN,,0,0,0,,This one's only about four pages of code. Dialogue: 0,0:47:17.08,0:47:19.23,EN,,0,0,0,,By the end of the subject, I hope a 50-page program Dialogue: 0,0:47:20.27,0:47:21.80,EN,,0,0,0,,will not look particularly frightening. Dialogue: 0,0:47:22.97,0:47:28.20,EN,,0,0,0,,But I don't expect-- and I don't want you to think that I expect you to be getting it as it's coming out. Dialogue: 0,0:47:29.20,0:47:31.70,EN,,0,0,0,,You're supposed to feel the flavor of this, OK? Dialogue: 0,0:47:31.70,0:47:34.83,EN,,0,0,0,,And then you're supposed to think about it because it is a big program. Dialogue: 0,0:47:35.32,0:47:38.92,EN,,0,0,0,,There's a lot of stuff inside this program. Dialogue: 0,0:47:41.24,0:47:46.03,EN,,0,0,0,,Now, I've told you about the language we're implementing, the pattern match substitution language. Dialogue: 0,0:47:46.81,0:47:47.64,EN,,0,0,0,,I showed you some rules. Dialogue: 0,0:47:48.36,0:47:51.24,EN,,0,0,0,,And I've told you about matching and instantiation, Dialogue: 0,0:47:51.55,0:47:53.32,EN,,0,0,0,,which are the two halves of how a rule works. Dialogue: 0,0:47:54.24,0:47:56.35,EN,,0,0,0,,Now we have to understand the control structure Dialogue: 0,0:47:56.86,0:48:00.32,EN,,0,0,0,,by which the rules are applied to the expressions Dialogue: 0,0:48:01.08,0:48:03.84,EN,,0,0,0,,so as to do algebraic simplification. Dialogue: 0,0:48:06.92,0:48:09.58,EN,,0,0,0,,Now, that's also a big complicated mess. Dialogue: 0,0:48:12.09,0:48:19.48,EN,,0,0,0,,The problem is that there is a variety of interlocking, interwoven loops, if you will, involved in this. Dialogue: 0,0:48:20.24,0:48:26.99,EN,,0,0,0,,For one thing, I have to apply-- I have to examine every subexpression of my expression that I'm trying to simplify. Dialogue: 0,0:48:29.00,0:48:29.93,EN,,0,0,0,,That we know how to do. Dialogue: 0,0:48:29.93,0:48:36.24,EN,,0,0,0,,It's a car cdr recursion of some sort, or something like that, and some sort of tree walk. Dialogue: 0,0:48:37.44,0:48:38.59,EN,,0,0,0,,And that's going to be happening. Dialogue: 0,0:48:38.84,0:48:42.46,EN,,0,0,0,,Now, for every such place, every node that I get to Dialogue: 0,0:48:43.47,0:48:48.76,EN,,0,0,0,,in doing my traversal of the expression I'm trying to simplify, Dialogue: 0,0:48:49.20,0:48:51.07,EN,,0,0,0,,I want to apply all of the rules. Dialogue: 0,0:48:53.42,0:48:55.08,EN,,0,0,0,,Every rule is going to look at every node. Dialogue: 0,0:48:56.00,0:48:57.92,EN,,0,0,0,,I'm going to rotate the rules around. Dialogue: 0,0:49:01.66,0:49:05.48,EN,,0,0,0,,Now, either a rule will or will not match. Dialogue: 0,0:49:07.50,0:49:10.62,EN,,0,0,0,,If the rule does not match, then it's not very interesting. Dialogue: 0,0:49:12.28,0:49:19.34,EN,,0,0,0,,If the rule does match, then I'm going to replace that node in the expression by an alternate expression. Dialogue: 0,0:49:20.08,0:49:22.89,EN,,0,0,0,,I'm actually going to make a new expression, which contains-- Dialogue: 0,0:49:23.55,0:49:28.65,EN,,0,0,0,,everything contains that new value, the result of substituting into the skeleton, Dialogue: 0,0:49:29.21,0:49:31.92,EN,,0,0,0,,instantiating the skeleton for that rule at this level. Dialogue: 0,0:49:32.72,0:49:37.37,EN,,0,0,0,,But no one knows whether that thing that I instantiated there is in simplified form. Dialogue: 0,0:49:38.75,0:49:43.82,EN,,0,0,0,,So we're going to have to simplify that, somehow to call the simplifier on the thing that I just constructed. Dialogue: 0,0:49:46.12,0:49:50.36,EN,,0,0,0,,And then when that's done, then I sort of can build that into the expression I want as my answer. Dialogue: 0,0:49:51.80,0:49:57.45,EN,,0,0,0,,Now, there is a basic idea here, which I will call a garbage- in, garbage-out simplifier. Dialogue: 0,0:50:01.47,0:50:02.75,EN,,0,0,0,,It's a kind of recursive simplifier. Dialogue: 0,0:50:03.58,0:50:08.84,EN,,0,0,0,,And what happens is the way simplify something is that simple objects like variables are simple. Dialogue: 0,0:50:10.78,0:50:13.28,EN,,0,0,0,,Compound objects, well, I don't know. Dialogue: 0,0:50:14.09,0:50:16.56,EN,,0,0,0,,What I'm going to do is I'm going to build up from simple objects, Dialogue: 0,0:50:16.86,0:50:21.23,EN,,0,0,0,,trying to make simple things by assuming that the pieces they're made out of are simple. Dialogue: 0,0:50:24.60,0:50:25.61,EN,,0,0,0,,That's what's happening here. Dialogue: 0,0:50:27.82,0:50:33.12,EN,,0,0,0,,Well, now, if we look at the first slide-- no, overhead, overhead. Dialogue: 0,0:50:33.88,0:50:37.13,EN,,0,0,0,,If we look at the overhead, we see a very complicated program like we saw before for the matcher, Dialogue: 0,0:50:37.53,0:50:39.95,EN,,0,0,0,,so complicated that you can't read it like that. Dialogue: 0,0:50:41.92,0:50:43.61,EN,,0,0,0,,I just want you to get the feel of the shape of it, Dialogue: 0,0:50:44.44,0:50:50.01,EN,,0,0,0,,and the shape of it is that this program has various subprograms in it. Dialogue: 0,0:50:52.11,0:50:57.56,EN,,0,0,0,,One of them--this part is the part for traversing the expression, Dialogue: 0,0:50:58.97,0:51:01.36,EN,,0,0,0,,and this part is the part for trying rules. Dialogue: 0,0:51:02.52,0:51:05.60,EN,,0,0,0,,Now, of course, we can look at that in some more detail. Dialogue: 0,0:51:06.89,0:51:11.80,EN,,0,0,0,,Let's look at--let's look at the first transparency, right? Dialogue: 0,0:51:13.40,0:51:17.36,EN,,0,0,0,,The simplifier is made out of several parts. Dialogue: 0,0:51:17.96,0:51:22.92,EN,,0,0,0,,Now, remember at the very beginning, the simplifier is the thing which takes a rules-- a set of rules Dialogue: 0,0:51:23.92,0:51:27.20,EN,,0,0,0,,and produces a program which will simplify it relative to them. Dialogue: 0,0:51:30.04,0:51:32.60,EN,,0,0,0,,So here we have our simplifier. Dialogue: 0,0:51:33.48,0:51:34.81,EN,,0,0,0,,It takes a rule set. Dialogue: 0,0:51:36.16,0:51:38.68,EN,,0,0,0,,And in the context where that rule set is defined, Dialogue: 0,0:51:39.24,0:51:41.48,EN,,0,0,0,,there are various other definitions that are done here. Dialogue: 0,0:51:42.33,0:51:46.20,EN,,0,0,0,,And then the result of this simplifier procedure is, Dialogue: 0,0:51:46.41,0:51:50.80,EN,,0,0,0,,in fact, one of the procedures that was defined. Simplify-exp. Dialogue: 0,0:51:52.46,0:51:57.71,EN,,0,0,0,,What I'm returning as the value of calling the simplifier on a set of rules Dialogue: 0,0:51:58.17,0:52:03.21,EN,,0,0,0,,is a procedure the simplify exp procedure, which is defined in that context, Dialogue: 0,0:52:05.23,0:52:08.83,EN,,0,0,0,,which is a simplification procedure appropriate for using those set of rules. Dialogue: 0,0:52:15.04,0:52:15.96,EN,,0,0,0,,That's what I have there. Dialogue: 0,0:52:17.45,0:52:21.79,EN,,0,0,0,,Now, the first two of these procedures, this one and this one, Dialogue: 0,0:52:22.48,0:52:25.74,EN,,0,0,0,,are together going to be the recursive traversal of an expression. Dialogue: 0,0:52:26.97,0:52:30.20,EN,,0,0,0,,This one is the general simplification for any expression, Dialogue: 0,0:52:30.94,0:52:33.23,EN,,0,0,0,,and this is the thing which simplifies a list of parts of an expression. Dialogue: 0,0:52:35.53,0:52:36.08,EN,,0,0,0,,Nothing more. Dialogue: 0,0:52:37.04,0:52:39.90,EN,,0,0,0,,For each of those, we're going to do something complicated, which involves trying the rules. Dialogue: 0,0:52:40.32,0:52:41.71,EN,,0,0,0,,Now, we should look at the various parts. Dialogue: 0,0:52:45.76,0:52:48.08,EN,,0,0,0,,Well let's look first at the recursive traversal of an expression. Dialogue: 0,0:52:48.57,0:52:51.68,EN,,0,0,0,,And this is done in a sort of simple way. Dialogue: 0,0:52:54.28,0:52:57.93,EN,,0,0,0,,This is a little nest of recursive procedures. Dialogue: 0,0:52:59.42,0:53:01.77,EN,,0,0,0,,And what we have here are two procedures-- Dialogue: 0,0:53:02.59,0:53:05.20,EN,,0,0,0,,one for simplifying an expression, Dialogue: 0,0:53:06.11,0:53:08.16,EN,,0,0,0,,and one for simplifying parts of an expression. Dialogue: 0,0:53:09.44,0:53:10.97,EN,,0,0,0,,And the way this works is very simple. Dialogue: 0,0:53:12.12,0:53:16.86,EN,,0,0,0,,If the expression I'm trying to simplify is a compound expression, Dialogue: 0,0:53:17.04,0:53:18.32,EN,,0,0,0,,I'm going to simplify all the parts of it. Dialogue: 0,0:53:19.95,0:53:22.32,EN,,0,0,0,,And that's calling--that procedure, simplify parts, Dialogue: 0,0:53:22.33,0:53:25.74,EN,,0,0,0,,is going to make up a new expression with all the parts simplified, Dialogue: 0,0:53:26.00,0:53:28.64,EN,,0,0,0,,which I'm then going to try the rules on over here. Dialogue: 0,0:53:30.86,0:53:34.22,EN,,0,0,0,,If it turns out that the expression is not compound, if it's simple, Dialogue: 0,0:53:34.76,0:53:37.13,EN,,0,0,0,,like just a symbol or something like pi, Dialogue: 0,0:53:38.16,0:53:39.79,EN,,0,0,0,,then in any case, I'm going to try the rules on it Dialogue: 0,0:53:40.03,0:53:47.56,EN,,0,0,0,,because it might be that I want in my set of rules to expand pi to 3.14159265358979,dot, dot, dot. Dialogue: 0,0:53:48.46,0:53:49.08,EN,,0,0,0,,But I may not. Dialogue: 0,0:53:50.11,0:53:51.52,EN,,0,0,0,,But there is no reason not to do it. Dialogue: 0,0:53:52.75,0:53:57.53,EN,,0,0,0,,Now, if I want to simplify the parts, well, that's easy too. Dialogue: 0,0:53:58.99,0:54:02.88,EN,,0,0,0,,Either the expression is an empty one, there's no more parts, Dialogue: 0,0:54:03.71,0:54:05.08,EN,,0,0,0,,in which case I have the empty expression. Dialogue: 0,0:54:05.72,0:54:10.52,EN,,0,0,0,,Otherwise, I'm going to make a new expression by cons, Dialogue: 0,0:54:11.21,0:54:14.27,EN,,0,0,0,,which is the result of simplifying the first part of the expression, the car, Dialogue: 0,0:54:15.42,0:54:17.39,EN,,0,0,0,,and simplifying the rest of the expression, which is the cdr. Dialogue: 0,0:54:21.08,0:54:23.88,EN,,0,0,0,,Now, the reason why I'm showing you this sort of stuff this way Dialogue: 0,0:54:24.88,0:54:30.12,EN,,0,0,0,,is because I want you get the feeling for the various patterns that are very important when writing programs. Dialogue: 0,0:54:32.20,0:54:34.00,EN,,0,0,0,,And this could be written a different way. Dialogue: 0,0:54:34.00,0:54:36.99,EN,,0,0,0,,There's another way to write simplified expressions so there would be only one of them. Dialogue: 0,0:54:37.72,0:54:39.63,EN,,0,0,0,,There would only be one little procedure here. Dialogue: 0,0:54:39.63,0:54:42.36,EN,,0,0,0,,Let me just write that on the blackboard to give you a feeling for that. Dialogue: 0,0:54:49.71,0:54:51.90,EN,,0,0,0,,This is in another idiom, if you will. Dialogue: 0,0:54:59.30,0:55:03.13,EN,,0,0,0,,To simplify an expression called exp, what am I going to do? Dialogue: 0,0:55:03.21,0:55:10.14,EN,,0,0,0,,I'm going to try the rules on the following situation. Dialogue: 0,0:55:11.12,0:55:15.72,EN,,0,0,0,,If-- on the following expression-- compound, just like we had before. Dialogue: 0,0:55:21.52,0:55:24.27,EN,,0,0,0,,If the expression is compound, well, what am I going to do? Dialogue: 0,0:55:24.53,0:55:25.40,EN,,0,0,0,,I'm going to simplify all the parts. Dialogue: 0,0:55:26.01,0:55:27.80,EN,,0,0,0,,But I already have a cdr recursion, Dialogue: 0,0:55:30.25,0:55:33.18,EN,,0,0,0,,common pattern of usage, which has been captured as a high-order procedure. Dialogue: 0,0:55:34.09,0:55:34.46,EN,,0,0,0,,It's called map. Dialogue: 0,0:55:36.08,0:55:36.88,EN,,0,0,0,,So I'll just write that here. Dialogue: 0,0:55:37.16,0:55:48.03,EN,,0,0,0,,Map simplify the expression, all the parts of the expression. Dialogue: 0,0:55:49.00,0:55:54.59,EN,,0,0,0,,This says apply the simplification operation, which is this one, every part of the expression, Dialogue: 0,0:55:55.34,0:55:57.34,EN,,0,0,0,,and then that cons those up into a list. Dialogue: 0,0:56:00.92,0:56:04.38,EN,,0,0,0,,It's every element of the list which the expression is assumed to be made out of, Dialogue: 0,0:56:05.45,0:56:08.23,EN,,0,0,0,,and otherwise, I have the expression. Dialogue: 0,0:56:09.05,0:56:12.36,EN,,0,0,0,,So I don't need the helper procedure, simplify parts, Dialogue: 0,0:56:12.64,0:56:13.48,EN,,0,0,0,,because that's really this. Dialogue: 0,0:56:15.47,0:56:17.05,EN,,0,0,0,,So sometimes, you just write it this way. Dialogue: 0,0:56:17.84,0:56:18.70,EN,,0,0,0,,It doesn't matter very much. Dialogue: 0,0:56:21.16,0:56:26.27,EN,,0,0,0,,Well, now let's take a look at-- let's just look at how you try rules. Dialogue: 0,0:56:27.70,0:56:31.60,EN,,0,0,0,,If you look at this slide, we see this is a complicated mess also. Dialogue: 0,0:56:33.68,0:56:35.28,EN,,0,0,0,,I'm trying rules on an expression. Dialogue: 0,0:56:36.36,0:56:39.96,EN,,0,0,0,,It turns out the expression I'm trying it on is some subexpression now of the expression I started with. Dialogue: 0,0:56:40.43,0:56:43.88,EN,,0,0,0,,Because the thing I just arranged allowed us to try every subexpression. Dialogue: 0,0:56:46.11,0:56:51.90,EN,,0,0,0,,So now here we're taking in a subexpression of the expression we started with. That's what this is. Dialogue: 0,0:56:52.49,0:56:57.71,EN,,0,0,0,,And what we're going to define here is a procedure called scan, which is going to try every rule. Dialogue: 0,0:56:58.72,0:57:00.33,EN,,0,0,0,,And we're going to start it up on the whole set of rules. Dialogue: 0,0:57:01.92,0:57:07.77,EN,,0,0,0,,This is going to go cdr-ing down the rules, if you will, looking for a rule to apply. Dialogue: 0,0:57:09.37,0:57:11.96,EN,,0,0,0,,And when it finds one, it'll do the job. Dialogue: 0,0:57:14.09,0:57:16.41,EN,,0,0,0,,Well, let's take a look at how try rules works. Dialogue: 0,0:57:17.74,0:57:21.02,EN,,0,0,0,,It's very simple: the scan rules. Scan rules, the way of scanning. Dialogue: 0,0:57:21.96,0:57:23.26,EN,,0,0,0,,Well, is it so simple? Dialogue: 0,0:57:23.26,0:57:24.51,EN,,0,0,0,,It's a big program, of course. Dialogue: 0,0:57:25.55,0:57:28.57,EN,,0,0,0,,We take a bunch of rules, which is a sublist of the list of rules. Dialogue: 0,0:57:30.75,0:57:35.13,EN,,0,0,0,,We've tried some of them already, and they've not been appropriate, so we get to some here. Dialogue: 0,0:57:35.87,0:57:36.30,EN,,0,0,0,,next one. Dialogue: 0,0:57:36.40,0:57:37.63,EN,,0,0,0,,If there are no more rules, Dialogue: 0,0:57:37.90,0:57:40.84,EN,,0,0,0,,well then, there's nothing I can do with this expression, and it's simplified. Dialogue: 0,0:57:42.35,0:57:47.26,EN,,0,0,0,,However, if it turns out that there are still rules to be done, Dialogue: 0,0:57:48.01,0:57:51.58,EN,,0,0,0,,then let's match the pattern of the first rule Dialogue: 0,0:57:52.20,0:57:55.40,EN,,0,0,0,,against the expression using the empty dictionary to start with Dialogue: 0,0:57:57.07,0:57:58.84,EN,,0,0,0,,and use that as the dictionary. Dialogue: 0,0:58:00.32,0:58:03.74,EN,,0,0,0,,If that happens to be a failure, try the rest of the rules. Dialogue: 0,0:58:06.68,0:58:07.52,EN,,0,0,0,,That's all it says here. Dialogue: 0,0:58:08.52,0:58:10.33,EN,,0,0,0,,How it says, it says discard that rule. Dialogue: 0,0:58:11.10,0:58:15.05,EN,,0,0,0,,Otherwise, well, I'm going to get the skeleton of the first rule, Dialogue: 0,0:58:15.34,0:58:17.40,EN,,0,0,0,,instantiate that relative to the dictionary, Dialogue: 0,0:58:17.93,0:58:20.80,EN,,0,0,0,,and simplify the result, and that's the expression I want. Dialogue: 0,0:58:24.20,0:58:25.96,EN,,0,0,0,,So although that was a complicated program, Dialogue: 0,0:58:26.25,0:58:28.72,EN,,0,0,0,,every complicated program is made out of a lot of simple pieces. Dialogue: 0,0:58:29.77,0:58:33.12,EN,,0,0,0,,Now, the pattern of recursions here is very complicated. Dialogue: 0,0:58:34.78,0:58:36.52,EN,,0,0,0,,And one of the most important things is not to think about that. Dialogue: 0,0:58:38.67,0:58:41.80,EN,,0,0,0,,If you try to think about the actual pattern by which this does something, Dialogue: 0,0:58:42.06,0:58:42.97,EN,,0,0,0,,you're going to get very confused. Dialogue: 0,0:58:45.31,0:58:45.71,EN,,0,0,0,,I would. Dialogue: 0,0:58:47.04,0:58:50.17,EN,,0,0,0,,This is not a matter. you can do this with practice. Dialogue: 0,0:58:51.52,0:58:52.46,EN,,0,0,0,,These patterns are hard. Dialogue: 0,0:58:54.17,0:58:55.42,EN,,0,0,0,,But you don't have to think about it. Dialogue: 0,0:58:55.83,0:58:59.72,EN,,0,0,0,,The key to this-- it's very good programming and very good design-- Dialogue: 0,0:58:59.74,0:59:00.97,EN,,0,0,0,,is to know what not to think about. Dialogue: 0,0:59:03.05,0:59:06.06,EN,,0,0,0,,The fact is, going back to this slide, Dialogue: 0,0:59:06.92,0:59:08.01,EN,,0,0,0,,I don't have to think about it Dialogue: 0,0:59:08.54,0:59:13.83,EN,,0,0,0,,because I have specifications in my mind for what simplify x does. Dialogue: 0,0:59:14.00,0:59:15.24,EN,,0,0,0,,I don't have to know how it does it. Dialogue: 0,0:59:17.08,0:59:21.24,EN,,0,0,0,,And it may, in fact, call scan somehow through try rules, which it does. Dialogue: 0,0:59:22.24,0:59:24.09,EN,,0,0,0,,And somehow, I've got another recursion going on here. Dialogue: 0,0:59:24.33,0:59:25.69,EN,,0,0,0,,But since I know that simplify exp Dialogue: 0,0:59:26.84,0:59:30.40,EN,,0,0,0,,is assumed by wishful thinking to produce the simplified result, Dialogue: 0,0:59:31.61,0:59:32.99,EN,,0,0,0,,then I don't have to think about it anymore. Dialogue: 0,0:59:33.43,0:59:34.83,EN,,0,0,0,,I've used it. Dialogue: 0,0:59:35.07,0:59:36.43,EN,,0,0,0,,I've used it in a reasonable way. Dialogue: 0,0:59:36.43,0:59:37.45,EN,,0,0,0,,I will get a reasonable answer. Dialogue: 0,0:59:39.95,0:59:42.57,EN,,0,0,0,,And you have to learn how to program that way-- with abandon. Dialogue: 0,0:59:47.56,0:59:49.05,EN,,0,0,0,,Well, there's very little left of this thing. Dialogue: 0,0:59:50.40,0:59:54.46,EN,,0,0,0,,All there is left is a few details associated with what a dictionary is. Dialogue: 0,0:59:55.08,0:59:58.32,EN,,0,0,0,,And those of you who've been itching to know what a dictionary is, Dialogue: 0,0:59:58.70,1:00:01.82,EN,,0,0,0,,well, I will flip it up and not tell you anything about it. Dialogue: 0,1:00:04.14,1:00:05.20,EN,,0,0,0,,Dictionaries are easy. Dialogue: 0,1:00:06.01,1:00:09.84,EN,,0,0,0,,It's represented in terms of something else called an A list, Dialogue: 0,1:00:10.65,1:00:16.04,EN,,0,0,0,,which is a particular pattern of usage for making tables in lists. Dialogue: 0,1:00:16.50,1:00:20.17,EN,,0,0,0,,They're easy. They're made out of pairs, as was asked a bit ago. Dialogue: 0,1:00:21.21,1:00:24.62,EN,,0,0,0,,And there are special procedures for dealing with such things called assq, Dialogue: 0,1:00:24.94,1:00:26.36,EN,,0,0,0,,and you can find them in manuals. Dialogue: 0,1:00:27.04,1:00:28.59,EN,,0,0,0,,I'm not terribly excited about it. Dialogue: 0,1:00:28.83,1:00:31.21,EN,,0,0,0,,The only interesting thing here in extend dictionary Dialogue: 0,1:00:31.48,1:00:36.94,EN,,0,0,0,,is I have to extend the dictionary with a pattern, a datum, and a dictionary. Dialogue: 0,1:00:37.42,1:00:42.38,EN,,0,0,0,,I wish that, this pattern is, in fact, at this point a pattern variable. Dialogue: 0,1:00:43.74,1:00:47.53,EN,,0,0,0,,And what do I want to do? I want to pull out the name of that pattern variable Dialogue: 0,1:00:48.16,1:00:49.42,EN,,0,0,0,,the pattern variable name, Dialogue: 0,1:00:50.44,1:00:53.71,EN,,0,0,0,,and I'm going to look up in the dictionary and see if it already has a value. Dialogue: 0,1:00:53.79,1:00:56.41,EN,,0,0,0,,If not, I'm going to add a new one in. Dialogue: 0,1:00:56.92,1:00:59.23,EN,,0,0,0,,If it does have one, if it has a value, Dialogue: 0,1:00:59.60,1:01:03.18,EN,,0,0,0,,then it had better be equal to the one that was already stored away. Dialogue: 0,1:01:03.88,1:01:06.54,EN,,0,0,0,,And if that's the case, the dictionary is what I expected it to be. Dialogue: 0,1:01:06.89,1:01:09.15,EN,,0,0,0,,Otherwise, I fail. Dialogue: 0,1:01:12.08,1:01:12.89,EN,,0,0,0,,So that's easy, too. Dialogue: 0,1:01:13.66,1:01:16.68,EN,,0,0,0,,If you open up any program, you're going to find inside of it lots of little pieces, Dialogue: 0,1:01:17.18,1:01:18.30,EN,,0,0,0,,all of which are easy. Dialogue: 0,1:01:20.04,1:01:21.29,EN,,0,0,0,,So at this point, I suppose, Dialogue: 0,1:01:21.60,1:01:25.68,EN,,0,0,0,,I've just told you some million-dollar valuable information. Dialogue: 0,1:01:28.41,1:01:30.96,EN,,0,0,0,,And I suppose at this point we're pretty much done with this program. Dialogue: 0,1:01:31.85,1:01:32.72,EN,,0,0,0,,I'd like to ask about questions. Dialogue: 0,1:01:34.27,1:01:38.16,EN,,0,0,0,,AUDIENCE: Yes, can you give me the words that describe the specification for a simplified expression? Dialogue: 0,1:01:38.72,1:01:39.02,EN,,0,0,0,,PROFESSOR: Sure. Dialogue: 0,1:01:39.85,1:01:44.33,EN,,0,0,0,,A simplified expression takes an expression and produces a simplified expression. Dialogue: 0,1:01:45.28,1:01:45.77,EN,,0,0,0,,That's it, OK? Dialogue: 0,1:01:48.11,1:01:50.27,EN,,0,0,0,,How it does it is very easy. Dialogue: 0,1:01:51.60,1:01:56.09,EN,,0,0,0,,In compound expressions, all the pieces are simplified, and then the rules are tried on the result. Dialogue: 0,1:01:56.89,1:01:58.49,EN,,0,0,0,,And for simple expressions, you just try all the rules. Dialogue: 0,1:01:59.52,1:02:02.11,EN,,0,0,0,,AUDIENCE: So an expression is simplified by virtue of the rules? Dialogue: 0,1:02:02.76,1:02:03.58,EN,,0,0,0,,PROFESSOR: That's, of course, true. Dialogue: 0,1:02:03.76,1:02:03.90,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,1:02:04.06,1:02:07.13,EN,,0,0,0,,PROFESSOR: And the way this works is that simplified expression, as you see here, Dialogue: 0,1:02:08.35,1:02:11.64,EN,,0,0,0,,what it does is it breaks the expression down into the smallest pieces, Dialogue: 0,1:02:12.60,1:02:17.29,EN,,0,0,0,,simplifies building up from the bottom using the rules to be the simplifier, Dialogue: 0,1:02:18.30,1:02:22.48,EN,,0,0,0,,to do the manipulations, and constructs a new expression as the result. Dialogue: 0,1:02:24.28,1:02:29.44,EN,,0,0,0,,Eventually, one of things you see is that the rules themselves, the try rules, Dialogue: 0,1:02:29.70,1:02:35.50,EN,,0,0,0,,call a simplified expression on the results when it changes something, the results of a match. Dialogue: 0,1:02:35.80,1:02:40.64,EN,,0,0,0,,I'm sorry, the results of instantiation of a skeleton for a rule that has matched. Dialogue: 0,1:02:42.00,1:02:47.36,EN,,0,0,0,,So the spec of a simplified expression is that any expression you put into it comes out simplified according to those rules. Dialogue: 0,1:02:49.84,1:02:50.76,EN,,0,0,0,,Thank you. Let's take a break. ================================================ FILE: Ass/lec4b.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 2664 Active Line: 2669 Video Position: 149956 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:11.40,0:00:16.50,EN,,0,0,0,,Generic Operators Dialogue: 0,0:00:20.18,0:00:21.84,EN,,0,0,0,,PROFESSOR: So far in this course we've been talking Dialogue: 0,0:00:21.84,0:00:23.78,EN,,0,0,0,,a lot about data abstraction. Dialogue: 0,0:00:23.78,0:00:27.15,EN,,0,0,0,,And remember the idea is that we build systems Dialogue: 0,0:00:27.74,0:00:32.56,EN,,0,0,0,,that have these horizontal barriers in them, these abstraction barriers Dialogue: 0,0:00:33.42,0:00:39.21,EN,,0,0,0,,that separate use, the way you might use some data object, Dialogue: 0,0:00:39.93,0:00:41.18,EN,,0,0,0,,from the way you might represent it. Dialogue: 0,0:00:49.40,0:00:52.03,EN,,0,0,0,,Or another way to think of that is up here you have the boss Dialogue: 0,0:00:52.11,0:00:55.50,EN,,0,0,0,,who's going to be using some sort of data object. Dialogue: 0,0:00:57.11,0:01:02.31,EN,,0,0,0,,And down here is George who's implemented it. Dialogue: 0,0:01:02.31,0:01:05.42,EN,,0,0,0,,Now this notion of separating use from representation Dialogue: 0,0:01:05.44,0:01:09.76,EN,,0,0,0,,so you can think about these two problems separately Dialogue: 0,0:01:10.60,0:01:14.76,EN,,0,0,0,,is a very,very powerful programming methodology, data abstraction. Dialogue: 0,0:01:15.93,0:01:18.81,EN,,0,0,0,,On the other hand, it's not really sufficient Dialogue: 0,0:01:19.56,0:01:21.84,EN,,0,0,0,,for really complex systems. Dialogue: 0,0:01:22.96,0:01:27.64,EN,,0,0,0,,And the problem with this is George. Dialogue: 0,0:01:28.64,0:01:32.09,EN,,0,0,0,,Or actually, the problem is that Dialogue: 0,0:01:32.09,0:01:32.78,EN,,0,0,0,,there are a lot of Georges. Dialogue: 0,0:01:34.63,0:01:35.39,EN,,0,0,0,,Let's be concrete. Dialogue: 0,0:01:35.39,0:01:39.18,EN,,0,0,0,,Let's suppose there is George,and there's also Martha. Dialogue: 0,0:01:41.19,0:01:44.22,EN,,0,0,0,,OK, now George and Martha are both working on this system, Dialogue: 0,0:01:46.04,0:01:47.29,EN,,0,0,0,,both designing representations, Dialogue: 0,0:01:48.41,0:01:50.67,EN,,0,0,0,,and absolutely are incompatible. Dialogue: 0,0:01:51.75,0:01:53.62,EN,,0,0,0,,They wouldn't cooperate on a representation Dialogue: 0,0:01:54.01,0:01:55.34,EN,,0,0,0,,under any circumstances. Dialogue: 0,0:01:57.48,0:01:59.72,EN,,0,0,0,,And the problem is you would like to have some system Dialogue: 0,0:02:00.06,0:02:02.60,EN,,0,0,0,,where both George and Martha are designing representations, Dialogue: 0,0:02:03.82,0:02:08.08,EN,,0,0,0,,and, yet, if you're above this abstraction barrier Dialogue: 0,0:02:09.40,0:02:11.04,EN,,0,0,0,,you don't want to have to worry about that, Dialogue: 0,0:02:11.66,0:02:14.18,EN,,0,0,0,,whether something is done by George or by Martha. Dialogue: 0,0:02:14.18,0:02:15.43,EN,,0,0,0,,And you don't want George and Martha to Dialogue: 0,0:02:15.43,0:02:16.48,EN,,0,0,0,,interfere with each other. Dialogue: 0,0:02:16.63,0:02:20.31,EN,,0,0,0,,Somehow in designing a system, you not only want these Dialogue: 0,0:02:20.31,0:02:23.84,EN,,0,0,0,,horizontal barriers, but you also want some kind of Dialogue: 0,0:02:25.82,0:02:30.64,EN,,0,0,0,,some kind of vertical barrier to keep George and Martha separate. Dialogue: 0,0:02:32.98,0:02:35.40,EN,,0,0,0,,Let me be a little bit more concrete. Dialogue: 0,0:02:36.56,0:02:40.54,EN,,0,0,0,,Imagine that you're thinking about personnel records Dialogue: 0,0:02:41.18,0:02:46.11,EN,,0,0,0,,for a large company with a lot of loosely linked divisions Dialogue: 0,0:02:47.90,0:02:49.71,EN,,0,0,0,,that don't cooperate very well either. Dialogue: 0,0:02:50.43,0:02:57.04,EN,,0,0,0,,And imagine even that this company is formed by merging a Dialogue: 0,0:02:57.04,0:02:59.45,EN,,0,0,0,,whole bunch of companies that already have their personnel Dialogue: 0,0:02:59.45,0:03:00.70,EN,,0,0,0,,record system set up. Dialogue: 0,0:03:03.25,0:03:06.57,EN,,0,0,0,,And imagine that once these divisions are all linked in Dialogue: 0,0:03:06.57,0:03:08.53,EN,,0,0,0,,some kind of very sophisticated satellite Dialogue: 0,0:03:08.53,0:03:10.52,EN,,0,0,0,,network, and all these databases are put together. Dialogue: 0,0:03:12.24,0:03:13.85,EN,,0,0,0,,And what you'd like to do Dialogue: 0,0:03:14.84,0:03:16.33,EN,,0,0,0,,is from any place in the company, Dialogue: 0,0:03:17.26,0:03:23.13,EN,,0,0,0,,to be able to say things like,oh, what's the name in a Dialogue: 0,0:03:23.13,0:03:23.87,EN,,0,0,0,,personnel record? Dialogue: 0,0:03:26.30,0:03:29.15,EN,,0,0,0,,Or, what's the job description in a personnel record? Dialogue: 0,0:03:30.54,0:03:34.40,EN,,0,0,0,,And not have to worry about the fact that each division Dialogue: 0,0:03:34.84,0:03:36.76,EN,,0,0,0,,obviously is going to have completely separate Dialogue: 0,0:03:36.76,0:03:39.37,EN,,0,0,0,,conventions for how you might implement these records. Dialogue: 0,0:03:41.58,0:03:43.26,EN,,0,0,0,,From this point you don't want to know about that. Dialogue: 0,0:03:44.96,0:03:47.92,EN,,0,0,0,,Well how could you possibly do that? Dialogue: 0,0:03:48.43,0:03:52.41,EN,,0,0,0,,One way, of course, is to send down an edict from somewhere Dialogue: 0,0:03:52.64,0:03:56.29,EN,,0,0,0,,that everybody has to change their format to some fixed Dialogue: 0,0:03:56.29,0:03:57.24,EN,,0,0,0,,compatible thing. Dialogue: 0,0:03:58.07,0:04:00.12,EN,,0,0,0,,That's what people often try, and of course it never works. Dialogue: 0,0:04:01.82,0:04:07.34,EN,,0,0,0,,Another thing that you might want to do is somehow arrange Dialogue: 0,0:04:08.33,0:04:09.90,EN,,0,0,0,,it so you can have these vertical barriers. Dialogue: 0,0:04:11.25,0:04:14.40,EN,,0,0,0,,So that when you ask for the name of a personnel record, Dialogue: 0,0:04:14.43,0:04:17.97,EN,,0,0,0,,somehow, whatever format it happens to be, name will Dialogue: 0,0:04:17.97,0:04:19.42,EN,,0,0,0,,figure out how to do the right thing. Dialogue: 0,0:04:22.73,0:04:25.53,EN,,0,0,0,,We want name to be, so-called, a generic operator. Dialogue: 0,0:04:26.26,0:04:30.06,EN,,0,0,0,,Generic operator means what it sort of precisely does depends Dialogue: 0,0:04:30.06,0:04:31.69,EN,,0,0,0,,on the kind of data that it's looking at. Dialogue: 0,0:04:33.65,0:04:36.62,EN,,0,0,0,,More than that, you'd like to design the system so that the Dialogue: 0,0:04:36.92,0:04:39.79,EN,,0,0,0,,next time a new division comes into the company Dialogue: 0,0:04:42.51,0:04:45.64,EN,,0,0,0,,they don't have to make any big changes in what they're already doing Dialogue: 0,0:04:45.64,0:04:50.11,EN,,0,0,0,,to link into this system, and the rest of the company Dialogue: 0,0:04:50.11,0:04:52.01,EN,,0,0,0,,doesn't have to make any big changes Dialogue: 0,0:04:52.27,0:04:53.93,EN,,0,0,0,,to admit their stuff to the system. Dialogue: 0,0:04:55.52,0:04:57.52,EN,,0,0,0,,So that's the problem you should be thinking about. Dialogue: 0,0:04:58.70,0:05:00.77,EN,,0,0,0,,Like it's sort of just your work. Dialogue: 0,0:05:00.77,0:05:03.77,EN,,0,0,0,,You want to be able to include new things by making minimal changes. Dialogue: 0,0:05:05.98,0:05:08.12,EN,,0,0,0,,OK, well that's the problem that we'll be talking about today. Dialogue: 0,0:05:09.44,0:05:14.22,EN,,0,0,0,,And you should have this sort of distributed personnel record system in your mind. Dialogue: 0,0:05:14.24,0:05:16.62,EN,,0,0,0,,But actually the one I'll be talking about is a problem Dialogue: 0,0:05:16.62,0:05:18.48,EN,,0,0,0,,that's a little bit more self-contained than that. Dialogue: 0,0:05:19.29,0:05:21.76,EN,,0,0,0,,that'll bring up the issues, I think, more clearly. Dialogue: 0,0:05:21.87,0:05:26.01,EN,,0,0,0,,That's the problem of doing a system that does arithmetic on complex numbers. Dialogue: 0,0:05:27.77,0:05:28.92,EN,,0,0,0,,So let's take a look here. Dialogue: 0,0:05:30.69,0:05:31.74,EN,,0,0,0,,Just as a little review, Dialogue: 0,0:05:32.04,0:05:33.53,EN,,0,0,0,,there are things called complex numbers. Dialogue: 0,0:05:35.25,0:05:38.22,EN,,0,0,0,,Complex number you can think of as a point in the plane, or z. Dialogue: 0,0:05:39.37,0:05:47.19,EN,,0,0,0,,And you can represent a point either by its real-part and its imaginary-part. Dialogue: 0,0:05:47.19,0:05:50.83,EN,,0,0,0,,So if this is z and its real-part is this much, Dialogue: 0,0:05:51.50,0:05:53.24,EN,,0,0,0,,and its imaginary-part is that much, Dialogue: 0,0:05:54.33,0:05:56.44,EN,,0,0,0,,and you write z equals x plus iy. Dialogue: 0,0:05:59.11,0:06:03.21,EN,,0,0,0,,Or another way to represent a complex number is by saying, Dialogue: 0,0:06:03.21,0:06:09.00,EN,,0,0,0,,what's the distance from the origin, and what's the angle? Dialogue: 0,0:06:11.32,0:06:16.67,EN,,0,0,0,,So that represents a complex number as its radius times an angle. Dialogue: 0,0:06:19.52,0:06:21.92,EN,,0,0,0,,This one's called -- the original one's called rectangular form, Dialogue: 0,0:06:22.59,0:06:25.45,EN,,0,0,0,,rectangular representation, real- and imaginary-part Dialogue: 0,0:06:26.20,0:06:30.04,EN,,0,0,0,,or polar representation magnitude and angle-- Dialogue: 0,0:06:30.04,0:06:31.48,EN,,0,0,0,,and if you know the real- and imaginary-part, Dialogue: 0,0:06:31.53,0:06:33.36,EN,,0,0,0,,you can figure out the magnitude and angle. Dialogue: 0,0:06:33.72,0:06:36.97,EN,,0,0,0,,If you know x and y, you can get r by this formula. Dialogue: 0,0:06:37.19,0:06:39.48,EN,,0,0,0,,Square root of sum of the squares, and you can get the Dialogue: 0,0:06:39.48,0:06:40.76,EN,,0,0,0,,angle as an arctangent. Dialogue: 0,0:06:41.42,0:06:44.42,EN,,0,0,0,,Or conversely, if you knew r and A you could Dialogue: 0,0:06:44.42,0:06:45.31,EN,,0,0,0,,figure out x and y. Dialogue: 0,0:06:45.80,0:06:49.43,EN,,0,0,0,,x is r times the cosine of A, and y is r times the sine of A. Dialogue: 0,0:06:51.34,0:06:53.66,EN,,0,0,0,,All right, so there's these two. They're complex numbers. Dialogue: 0,0:06:54.13,0:06:57.15,EN,,0,0,0,,You can think of them either in polar form or rectangular form. Dialogue: 0,0:06:57.15,0:06:58.12,EN,,0,0,0,,What we would like to do Dialogue: 0,0:06:58.32,0:07:01.32,EN,,0,0,0,,is make a system that does arithmetic on complex numbers. Dialogue: 0,0:07:03.95,0:07:05.12,EN,,0,0,0,,In other words, what we'd like-- Dialogue: 0,0:07:05.58,0:07:06.99,EN,,0,0,0,,just like the rational number example-- Dialogue: 0,0:07:07.38,0:07:10.20,EN,,0,0,0,,is to have some operations plus c, Dialogue: 0,0:07:10.73,0:07:13.90,EN,,0,0,0,,which is going to take two complex numbers and add them, subtract them, Dialogue: 0,0:07:14.35,0:07:16.94,EN,,0,0,0,,and multiply them, and divide them. Dialogue: 0,0:07:20.73,0:07:25.28,EN,,0,0,0,,OK, well there's little bit of mathematics behind it. Dialogue: 0,0:07:25.28,0:07:28.36,EN,,0,0,0,,What are the actual formulas for manipulating such things? Dialogue: 0,0:07:30.41,0:07:31.92,EN,,0,0,0,,And it's sort of not important where they come from, Dialogue: 0,0:07:34.00,0:07:35.79,EN,,0,0,0,,but just as an implementer let's see-- Dialogue: 0,0:07:35.80,0:07:37.95,EN,,0,0,0,,if you want to add two complex numbers it's pretty easy to Dialogue: 0,0:07:39.13,0:07:42.66,EN,,0,0,0,,it's pretty easy to get its real-part and its imaginary-part. Dialogue: 0,0:07:42.66,0:07:45.93,EN,,0,0,0,,The real-part of the sum of two complex numbers Dialogue: 0,0:07:47.72,0:07:49.72,EN,,0,0,0,,real-part of the z1 plus z2 Dialogue: 0,0:07:50.06,0:07:54.64,EN,,0,0,0,,is the real-part of z1 plus the real-part of z2. Dialogue: 0,0:07:57.82,0:08:01.60,EN,,0,0,0,,And the imaginary-part of z1 plus z2 Dialogue: 0,0:08:01.74,0:08:05.66,EN,,0,0,0,,is the imaginary part of z1 plus the imaginary part of z2. Dialogue: 0,0:08:07.41,0:08:09.48,EN,,0,0,0,,So it's pretty easy to add complex numbers. Dialogue: 0,0:08:09.48,0:08:10.99,EN,,0,0,0,,You just add the corresponding parts Dialogue: 0,0:08:11.31,0:08:13.18,EN,,0,0,0,,and make a new complex number with those parts. Dialogue: 0,0:08:13.37,0:08:14.73,EN,,0,0,0,,If you want to multiply them, Dialogue: 0,0:08:15.53,0:08:17.82,EN,,0,0,0,,it's kind of nice to do it in polar form. Dialogue: 0,0:08:17.82,0:08:20.38,EN,,0,0,0,,Because if you have two complex numbers, Dialogue: 0,0:08:20.40,0:08:26.54,EN,,0,0,0,,the magnitude of their product is here, the product of the magnitudes. Dialogue: 0,0:08:28.85,0:08:33.88,EN,,0,0,0,,And the angle of the product is the sum of the angles. Dialogue: 0,0:08:35.80,0:08:40.54,EN,,0,0,0,,So that's sort of mathematics that allows you to do arithmetic on complex numbers. Dialogue: 0,0:08:40.54,0:08:42.38,EN,,0,0,0,,Let's actually think about the implementation. Dialogue: 0,0:08:43.72,0:08:47.39,EN,,0,0,0,,Well we do it just like rational numbers. Dialogue: 0,0:08:49.84,0:08:53.47,EN,,0,0,0,,We come down, we assume we have some constructors and selectors. Dialogue: 0,0:08:53.76,0:08:54.52,EN,,0,0,0,,What would we like? Dialogue: 0,0:08:55.33,0:08:58.16,EN,,0,0,0,,Well let's assume that we make a data object cloud, Dialogue: 0,0:08:58.54,0:09:00.78,EN,,0,0,0,,which is a complex number that has some stuff in it, Dialogue: 0,0:09:01.79,0:09:04.67,EN,,0,0,0,,and that we can get out from a complex number the real-part, Dialogue: 0,0:09:05.52,0:09:09.64,EN,,0,0,0,,or the imaginary-part, or the magnitude, or the angle. Dialogue: 0,0:09:12.15,0:09:14.01,EN,,0,0,0,,We want some ways of making complex numbers-- Dialogue: 0,0:09:14.03,0:09:15.64,EN,,0,0,0,,not only selectors, but constructors. Dialogue: 0,0:09:16.80,0:09:19.52,EN,,0,0,0,,So we'll assume we have a thing called make-rectangular. Dialogue: 0,0:09:19.53,0:09:24.27,EN,,0,0,0,,What make-rectangular is going to do is take a real-part and Dialogue: 0,0:09:24.51,0:09:29.36,EN,,0,0,0,,an imaginary-part and construct a complex number with those parts. Dialogue: 0,0:09:31.92,0:09:35.01,EN,,0,0,0,,Similarly, we can have make-polar which will taking Dialogue: 0,0:09:35.01,0:09:37.85,EN,,0,0,0,,a magnitude and an angle, Dialogue: 0,0:09:40.83,0:09:43.90,EN,,0,0,0,,and construct a complex number which has that magnitude and angle. Dialogue: 0,0:09:44.68,0:09:45.46,EN,,0,0,0,,So here's a system. Dialogue: 0,0:09:45.46,0:09:47.77,EN,,0,0,0,,We'll have two constructors and four selectors. Dialogue: 0,0:09:48.91,0:09:55.15,EN,,0,0,0,,And now, just like before, in terms of that abstract data Dialogue: 0,0:09:55.15,0:09:59.22,EN,,0,0,0,,we'll go ahead and implement our complex number operations. Dialogue: 0,0:09:59.22,0:10:02.30,EN,,0,0,0,,And here you can see translated into Lisp code Dialogue: 0,0:10:03.23,0:10:07.47,EN,,0,0,0,,just the arithmetic formulas I put down before. Dialogue: 0,0:10:08.06,0:10:09.98,EN,,0,0,0,,If I want to add two complex numbers Dialogue: 0,0:10:11.76,0:10:15.56,EN,,0,0,0,,I will make a complex number out of its real- and imaginary-parts. Dialogue: 0,0:10:16.72,0:10:19.02,EN,,0,0,0,,The real part of the complex number I'm going to make Dialogue: 0,0:10:19.40,0:10:21.80,EN,,0,0,0,,is the sum of the real-parts. Dialogue: 0,0:10:23.31,0:10:25.37,EN,,0,0,0,,The imaginary part of the complex number I'm going to make Dialogue: 0,0:10:25.40,0:10:27.52,EN,,0,0,0,,is the sum of the imaginary-parts. Dialogue: 0,0:10:30.31,0:10:32.09,EN,,0,0,0,,I put those together, make a complex number. Dialogue: 0,0:10:32.16,0:10:34.44,EN,,0,0,0,,That's how I implement complex number addition. Dialogue: 0,0:10:35.78,0:10:38.49,EN,,0,0,0,,Subtraction is essentially the same. Dialogue: 0,0:10:39.65,0:10:42.97,EN,,0,0,0,,All I do is subtract the parts rather than add them. Dialogue: 0,0:10:45.14,0:10:47.07,EN,,0,0,0,,To multiply two complex numbers, Dialogue: 0,0:10:47.74,0:10:49.02,EN,,0,0,0,,I use the other formula. Dialogue: 0,0:10:49.27,0:10:53.84,EN,,0,0,0,,I'll make a complex number out of a magnitude and angle. Dialogue: 0,0:10:55.35,0:10:56.44,EN,,0,0,0,,The magnitude Dialogue: 0,0:10:56.65,0:11:00.97,EN,,0,0,0,,is going to be the product of the magnitudesof the two complex numbers I'm multiplying. Dialogue: 0,0:11:03.71,0:11:05.93,EN,,0,0,0,,And the angle is going to be the sum Dialogue: 0,0:11:06.16,0:11:08.51,EN,,0,0,0,,of the angles of the z1two complex numbers I'm multiplying. Dialogue: 0,0:11:09.62,0:11:10.96,EN,,0,0,0,,So there's multiplication. Dialogue: 0,0:11:11.23,0:11:12.25,EN,,0,0,0,,And then division, Dialogue: 0,0:11:14.27,0:11:15.90,EN,,0,0,0,,division is almost the same. Dialogue: 0,0:11:17.37,0:11:19.58,EN,,0,0,0,,Here I divide the magnitudes and subtract the angles. Dialogue: 0,0:11:28.36,0:11:30.46,EN,,0,0,0,,Now I've implemented the operations. Dialogue: 0,0:11:31.87,0:11:33.64,EN,,0,0,0,,And what do we do? Dialogue: 0,0:11:33.64,0:11:34.52,EN,,0,0,0,,We call on George. Dialogue: 0,0:11:36.06,0:11:38.79,EN,,0,0,0,,We've done the use, let's worry about the representation. Dialogue: 0,0:11:38.80,0:11:40.94,EN,,0,0,0,,We'll call on George and say to George, Dialogue: 0,0:11:40.97,0:11:43.61,EN,,0,0,0,,go ahead and build us a complex number representation. Dialogue: 0,0:11:45.25,0:11:47.44,EN,,0,0,0,,Well that's fine...ahhh Dialogue: 0,0:11:47.77,0:11:52.66,EN,,0,0,0,,George can say, we'll implement a complex number Dialogue: 0,0:11:52.66,0:11:57.15,EN,,0,0,0,,simply as a pair that has the real-part and the imaginary-part. Dialogue: 0,0:11:57.20,0:12:02.62,EN,,0,0,0,,So if I want to make a complex number with a certain real-part and an imaginary-part, Dialogue: 0,0:12:03.36,0:12:05.55,EN,,0,0,0,,I'll just use cons to form a pair, and that will-- Dialogue: 0,0:12:06.03,0:12:08.11,EN,,0,0,0,,that's George's representation of a complex number. Dialogue: 0,0:12:09.78,0:12:12.42,EN,,0,0,0,,So if I want to get out the real-part of something, I just Dialogue: 0,0:12:12.42,0:12:14.12,EN,,0,0,0,,extract the car, the first part. Dialogue: 0,0:12:14.35,0:12:16.67,EN,,0,0,0,,If I want to get the imaginary-part, I extract the cdr Dialogue: 0,0:12:19.64,0:12:21.77,EN,,0,0,0,,How do I deal with the magnitude and angle? Dialogue: 0,0:12:22.22,0:12:25.75,EN,,0,0,0,,Well if I want to extract the magnitude of one of these things Dialogue: 0,0:12:25.75,0:12:32.30,EN,,0,0,0,,I get the square root of the sum of the square of the car plus the square of the cdr. Dialogue: 0,0:12:33.79,0:12:39.26,EN,,0,0,0,,If I want to get the angle, I compute the arctangent of the cdr in the car. Dialogue: 0,0:12:39.53,0:12:42.86,EN,,0,0,0,,This is a lisp procedure for computing arctangent. Dialogue: 0,0:12:44.97,0:12:48.59,EN,,0,0,0,,And if somebody hands me a magnitude and an angle Dialogue: 0,0:12:48.94,0:12:50.56,EN,,0,0,0,,and says, make me a complex number,well I compute the Dialogue: 0,0:12:50.89,0:12:56.24,EN,,0,0,0,,well I compute the real-part and the imaginary-part, r * cosine of a and r * sine of a, Dialogue: 0,0:12:57.77,0:12:59.05,EN,,0,0,0,,and stick them together into a pair. Dialogue: 0,0:13:01.46,0:13:02.26,EN,,0,0,0,,OK so we're done. Dialogue: 0,0:13:02.26,0:13:04.75,EN,,0,0,0,,In fact, what I just did, conceptually, Dialogue: 0,0:13:06.89,0:13:09.37,EN,,0,0,0,,is absolutely no different from the rational number Dialogue: 0,0:13:10.60,0:13:12.44,EN,,0,0,0,,representation that we looked at last time. Dialogue: 0,0:13:12.75,0:13:13.91,EN,,0,0,0,,It's the same sort of idea. Dialogue: 0,0:13:13.91,0:13:16.28,EN,,0,0,0,,You implement the operators, you pick a representation. Dialogue: 0,0:13:18.07,0:13:18.65,EN,,0,0,0,,Nothing different. Dialogue: 0,0:13:20.07,0:13:21.56,EN,,0,0,0,,Now let's worry about Martha. Dialogue: 0,0:13:23.21,0:13:24.52,EN,,0,0,0,,See, Martha has a different idea. Dialogue: 0,0:13:26.67,0:13:28.57,EN,,0,0,0,,She doesn't want to represent a complex number Dialogue: 0,0:13:28.59,0:13:30.90,EN,,0,0,0,,as a pair of a real-part and an imaginary-part. Dialogue: 0,0:13:30.90,0:13:34.17,EN,,0,0,0,,What she would like to do is represent a complex number as Dialogue: 0,0:13:34.17,0:13:37.69,EN,,0,0,0,,a pair of a magnitude and an angle. Dialogue: 0,0:13:39.55,0:13:42.13,EN,,0,0,0,,So if instead of calling up George we ask Martha to design Dialogue: 0,0:13:42.13,0:13:43.74,EN,,0,0,0,,our representation, we get something like this. Dialogue: 0,0:13:44.57,0:13:47.16,EN,,0,0,0,,We get make-polar. Dialogue: 0,0:13:47.16,0:13:50.22,EN,,0,0,0,,Sure, if I give you a magnitude and an angle we're Dialogue: 0,0:13:50.22,0:13:53.07,EN,,0,0,0,,just going to form a pair that has magnitude and angle. Dialogue: 0,0:13:55.43,0:13:57.68,EN,,0,0,0,,If you want to extract the magnitude, that's easy. Dialogue: 0,0:13:58.24,0:13:59.37,EN,,0,0,0,,You just pull out the car or the pair. Dialogue: 0,0:13:59.78,0:14:02.67,EN,,0,0,0,,If you want to extract the angle, sure, that's easy. Dialogue: 0,0:14:02.67,0:14:03.63,EN,,0,0,0,,You just pull out the cdr. Dialogue: 0,0:14:04.81,0:14:07.02,EN,,0,0,0,,If you want to look for real-parts and imaginary-parts, Dialogue: 0,0:14:07.42,0:14:08.49,EN,,0,0,0,,well then you have to do some work. Dialogue: 0,0:14:08.88,0:14:14.58,EN,,0,0,0,,If you want the real-part, you have to get r cosine a. Dialogue: 0,0:14:14.58,0:14:19.99,EN,,0,0,0,,In other words, r, the car of the pair, times the cosine of Dialogue: 0,0:14:19.99,0:14:20.95,EN,,0,0,0,,the cdr of the pair. Dialogue: 0,0:14:20.95,0:14:26.23,EN,,0,0,0,,So this is r times the cosine of a, Dialogue: 0,0:14:26.54,0:14:27.48,EN,,0,0,0,,and that's the real-part. Dialogue: 0,0:14:28.33,0:14:31.40,EN,,0,0,0,,If you want to get the imaginary-part, it's r times the sine of a. Dialogue: 0,0:14:32.66,0:14:37.93,EN,,0,0,0,,And if I hand you a real-part and an imaginary-part and say, Dialogue: 0,0:14:37.93,0:14:42.03,EN,,0,0,0,,make me a complex number with that real-part and Dialogue: 0,0:14:42.03,0:14:44.17,EN,,0,0,0,,imaginary-part, well I figure out what the magnitude and Dialogue: 0,0:14:44.17,0:14:45.54,EN,,0,0,0,,angle should be. Dialogue: 0,0:14:45.54,0:14:47.85,EN,,0,0,0,,The magnitude's the square root of the sum of the squares Dialogue: 0,0:14:48.09,0:14:49.23,EN,,0,0,0,,and the angle's the arctangent. Dialogue: 0,0:14:49.23,0:14:50.22,EN,,0,0,0,,I put those together to make a pair. Dialogue: 0,0:14:52.09,0:14:54.17,EN,,0,0,0,,So there's Martha's idea. Dialogue: 0,0:14:56.69,0:14:57.37,EN,,0,0,0,,Well which is better? Dialogue: 0,0:14:59.68,0:15:03.15,EN,,0,0,0,,Well if you're doing a lot of additions, probably George's is better Dialogue: 0,0:15:03.16,0:15:05.61,EN,,0,0,0,,is better, because you're doing a lot of real-parts and imaginary-parts. Dialogue: 0,0:15:05.85,0:15:08.40,EN,,0,0,0,,If mostly you're going to be doing multiplications and divisions, Dialogue: 0,0:15:09.48,0:15:11.14,EN,,0,0,0,,then maybe Martha's idea is better. Dialogue: 0,0:15:11.14,0:15:14.84,EN,,0,0,0,,Or maybe, and this is the real point, you can't decide. Dialogue: 0,0:15:16.59,0:15:22.32,EN,,0,0,0,,Or maybe you just have to let them both hang around, for personality reasons. Dialogue: 0,0:15:23.48,0:15:26.76,EN,,0,0,0,,Maybe you just really can't ever decide what you would like. Dialogue: 0,0:15:28.56,0:15:32.32,EN,,0,0,0,,And again, what we would really like is a system that looks like this. Dialogue: 0,0:15:32.65,0:15:36.17,EN,,0,0,0,,That somehow there's George over here, who has built Dialogue: 0,0:15:36.83,0:15:39.64,EN,,0,0,0,,rectangular complex numbers. Dialogue: 0,0:15:41.47,0:15:44.25,EN,,0,0,0,,And Martha, who has polar complex numbers. Dialogue: 0,0:15:46.12,0:15:49.69,EN,,0,0,0,,And somehow we have operations Dialogue: 0,0:15:50.28,0:15:56.89,EN,,0,0,0,,that can add, and subtract, and multiply, and divide Dialogue: 0,0:15:57.56,0:15:58.76,EN,,0,0,0,,and it shouldn't matter Dialogue: 0,0:15:59.34,0:16:02.79,EN,,0,0,0,,that there are two incompatible representations of complex Dialogue: 0,0:16:02.79,0:16:03.98,EN,,0,0,0,,numbers floating around this system. Dialogue: 0,0:16:04.41,0:16:08.33,EN,,0,0,0,,In other words, not only like an abstraction barrier here Dialogue: 0,0:16:09.64,0:16:11.84,EN,,0,0,0,,that has things in it like a real-part, Dialogue: 0,0:16:15.77,0:16:21.71,EN,,0,0,0,,and an imaginary-part, and magnitude,and angle. Dialogue: 0,0:16:23.83,0:16:25.36,EN,,0,0,0,,So not only is there an abstraction barrier Dialogue: 0,0:16:25.39,0:16:28.38,EN,,0,0,0,,that hides the actual representation from us, Dialogue: 0,0:16:29.10,0:16:31.52,EN,,0,0,0,,but also there's some kind of vertical barrier here Dialogue: 0,0:16:32.19,0:16:35.02,EN,,0,0,0,,that allows both of these representations to exist Dialogue: 0,0:16:35.87,0:16:37.40,EN,,0,0,0,,without interfering with each other. Dialogue: 0,0:16:38.57,0:16:41.07,EN,,0,0,0,,The idea is that the things in here-- Dialogue: 0,0:16:41.90,0:16:44.12,EN,,0,0,0,,real-part, imaginary-part,magnitude, and angle-- Dialogue: 0,0:16:44.12,0:16:46.49,EN,,0,0,0,,will be generic operators. Dialogue: 0,0:16:47.31,0:16:49.45,EN,,0,0,0,,If you ask for the real-part, it will worry about Dialogue: 0,0:16:49.98,0:16:51.31,EN,,0,0,0,,what representation it's looking at. Dialogue: 0,0:16:53.88,0:16:55.10,EN,,0,0,0,,OK, well how can we do that? Dialogue: 0,0:16:56.84,0:16:59.23,EN,,0,0,0,,There's actually a really obvious idea, Dialogue: 0,0:16:59.84,0:17:01.68,EN,,0,0,0,,if you're used to thinking about complex numbers. Dialogue: 0,0:17:02.52,0:17:04.44,EN,,0,0,0,,If you're used to thinking about compound data. Dialogue: 0,0:17:06.33,0:17:10.99,EN,,0,0,0,,See, suppose you could just tell by looking at a complex number Dialogue: 0,0:17:12.17,0:17:13.95,EN,,0,0,0,,whether it was constructed by George or Martha. Dialogue: 0,0:17:15.79,0:17:18.90,EN,,0,0,0,,In other words, so it's not that what's floating around Dialogue: 0,0:17:18.90,0:17:20.91,EN,,0,0,0,,here are ordinary, just complex numbers, right? Dialogue: 0,0:17:20.91,0:17:22.94,EN,,0,0,0,,They're fancy, designer complex numbers. Dialogue: 0,0:17:24.39,0:17:28.04,EN,,0,0,0,,So you look at a complex numbers as it's not just a complex number Dialogue: 0,0:17:28.04,0:17:29.16,EN,,0,0,0,,it's got a label on it that says, Dialogue: 0,0:17:29.19,0:17:30.75,EN,,0,0,0,,that one is by Martha. Dialogue: 0,0:17:31.45,0:17:34.22,EN,,0,0,0,,Or this is a complex number by George. Dialogue: 0,0:17:34.48,0:17:35.39,EN,,0,0,0,,Right? They're signed. Dialogue: 0,0:17:36.86,0:17:40.15,EN,,0,0,0,,See, and then whenever we looked at a complex number we Dialogue: 0,0:17:40.15,0:17:45.48,EN,,0,0,0,,could just read the label, and then we'd know how you expect Dialogue: 0,0:17:45.80,0:17:46.72,EN,,0,0,0,,to operate on that. Dialogue: 0,0:17:48.03,0:17:51.19,EN,,0,0,0,,In other words, what we want is not just ordinary data objects. Dialogue: 0,0:17:51.19,0:17:54.37,EN,,0,0,0,,We want to introduce the notion of what's called typed data. Dialogue: 0,0:17:59.76,0:18:02.81,EN,,0,0,0,,Typed data means, again, there's some sort of cloud. Dialogue: 0,0:18:03.94,0:18:08.93,EN,,0,0,0,,And what it's got in it is an ordinary data object like Dialogue: 0,0:18:08.93,0:18:09.90,EN,,0,0,0,,we've been thinking about. Dialogue: 0,0:18:13.18,0:18:16.54,EN,,0,0,0,,Pulled out the contents, sort of the actual data. Dialogue: 0,0:18:19.32,0:18:21.56,EN,,0,0,0,,But also a thing called a type, Dialogue: 0,0:18:22.56,0:18:25.24,EN,,0,0,0,,but it's signed by either George or Martha. Dialogue: 0,0:18:25.99,0:18:28.27,EN,,0,0,0,,So we're going to go from regular data to type data. Dialogue: 0,0:18:31.95,0:18:32.71,EN,,0,0,0,,How do we build that? Dialogue: 0,0:18:32.71,0:18:33.50,EN,,0,0,0,,Well that's easy. Dialogue: 0,0:18:33.84,0:18:35.32,EN,,0,0,0,,We know how to build clouds. Dialogue: 0,0:18:35.80,0:18:36.88,EN,,0,0,0,,We can build them out of pairs. Dialogue: 0,0:18:37.92,0:18:41.82,EN,,0,0,0,,So here's a little representation that supports typed data. Dialogue: 0,0:18:43.51,0:18:49.64,EN,,0,0,0,,There's a thing called take a type and attach it to a piece of contents, Dialogue: 0,0:18:49.69,0:18:50.64,EN,,0,0,0,,and we just use cons. Dialogue: 0,0:18:51.64,0:18:54.11,EN,,0,0,0,,And if we have a piece of typed data, we can look at the type Dialogue: 0,0:18:55.21,0:18:56.00,EN,,0,0,0,,which is the car. Dialogue: 0,0:18:56.29,0:18:58.30,EN,,0,0,0,,We can look at the contents,which is the cdr. Dialogue: 0,0:18:59.96,0:19:04.28,EN,,0,0,0,,Now along with that, the way we use our type data will test, Dialogue: 0,0:19:05.29,0:19:07.26,EN,,0,0,0,,when we're given a piece of data, what type it is. Dialogue: 0,0:19:07.52,0:19:09.26,EN,,0,0,0,,So we have some type predicates with us. Dialogue: 0,0:19:10.51,0:19:13.73,EN,,0,0,0,,For example, to see whether a complex number is one of Dialogue: 0,0:19:13.73,0:19:16.86,EN,,0,0,0,,George's, whether it's rectangular, we just check to Dialogue: 0,0:19:16.86,0:19:21.85,EN,,0,0,0,,see if the type of that is the symbol rectangular, Dialogue: 0,0:19:23.68,0:19:25.05,EN,,0,0,0,,right? The symbol rectangular. Dialogue: 0,0:19:27.20,0:19:30.33,EN,,0,0,0,,And to check whether a complex number is one of Martha's, Dialogue: 0,0:19:30.33,0:19:33.42,EN,,0,0,0,,we check to see whether the type is the symbol polar. Dialogue: 0,0:19:36.46,0:19:39.21,EN,,0,0,0,,So that's a way to test what kind of number we're looking at. Dialogue: 0,0:19:40.75,0:19:42.81,EN,,0,0,0,,Now let's think about how we can use that to build the system. Dialogue: 0,0:19:43.87,0:19:46.73,EN,,0,0,0,,So let's suppose that George and Martha were off working separately, Dialogue: 0,0:19:47.36,0:19:52.64,EN,,0,0,0,,and each of them had designed their complex number representation packages. Dialogue: 0,0:19:52.64,0:19:58.52,EN,,0,0,0,,What do they have to do to become part of the system, Dialogue: 0,0:19:58.73,0:20:00.14,EN,,0,0,0,,to exist compatibly? Dialogue: 0,0:20:00.14,0:20:02.11,EN,,0,0,0,,Well it's really pretty easy. Dialogue: 0,0:20:02.72,0:20:04.51,EN,,0,0,0,,Remember, George had this package. Dialogue: 0,0:20:05.97,0:20:08.48,EN,,0,0,0,,Here's George's original package, or half of it. Dialogue: 0,0:20:08.98,0:20:11.15,EN,,0,0,0,,And underlined in red are the changes he has to make. Dialogue: 0,0:20:12.09,0:20:16.43,EN,,0,0,0,,So before, when George made a complex number out of an x and y Dialogue: 0,0:20:17.52,0:20:19.85,EN,,0,0,0,,he just put them together to make a pair. Dialogue: 0,0:20:20.93,0:20:23.39,EN,,0,0,0,,And the only difference is that now he signs them. Dialogue: 0,0:20:24.09,0:20:28.08,EN,,0,0,0,,He attaches the type, which is the symbol rectangular to that pair. Dialogue: 0,0:20:30.60,0:20:33.26,EN,,0,0,0,,Everything else George does is the same, except that-- Dialogue: 0,0:20:33.92,0:20:38.06,EN,,0,0,0,,see, George and Martha both have procedures named real-part and imaginary-part. Dialogue: 0,0:20:38.70,0:20:42.96,EN,,0,0,0,,So to allow them both to exist in the same Lisp environment, Dialogue: 0,0:20:44.22,0:20:45.92,EN,,0,0,0,,George had changed the names of his procedures. Dialogue: 0,0:20:45.92,0:20:49.14,EN,,0,0,0,,So we'll say, this is George's real-part procedure. Dialogue: 0,0:20:49.14,0:20:51.16,EN,,0,0,0,,It's the real-part-rectangular procedure, Dialogue: 0,0:20:51.48,0:20:54.06,EN,,0,0,0,,the imaginary-part-rectangular procedure. Dialogue: 0,0:20:55.42,0:20:57.24,EN,,0,0,0,,And then here's the rest of George's package. Dialogue: 0,0:20:59.13,0:21:02.06,EN,,0,0,0,,He'd had magnitude and angle, just renames them magnitude Dialogue: 0,0:21:02.06,0:21:04.16,EN,,0,0,0,,rectangular and angle rectangular. Dialogue: 0,0:21:06.08,0:21:07.96,EN,,0,0,0,,And Martha has to do basically the same thing. Dialogue: 0,0:21:09.86,0:21:16.22,EN,,0,0,0,,Martha previously, when she made a complex number out of a magnitude and angle, Dialogue: 0,0:21:18.14,0:21:19.27,EN,,0,0,0,,she just cons them. Dialogue: 0,0:21:19.27,0:21:20.86,EN,,0,0,0,,Now she attaches the type polar, Dialogue: 0,0:21:23.95,0:21:25.61,EN,,0,0,0,,and she changes the name Dialogue: 0,0:21:25.66,0:21:29.85,EN,,0,0,0,,so her real-part procedure won't conflict in name with George's. Dialogue: 0,0:21:30.71,0:21:32.99,EN,,0,0,0,,It's a real-part-polar,imaginary-part-polar, Dialogue: 0,0:21:34.54,0:21:38.06,EN,,0,0,0,,magnitude polar, and angle polar. Dialogue: 0,0:21:45.00,0:21:46.13,EN,,0,0,0,,Now we have the system. Dialogue: 0,0:21:46.13,0:21:47.92,EN,,0,0,0,,Right there's George and Martha. Dialogue: 0,0:21:49.16,0:21:51.68,EN,,0,0,0,,And now we've got to get some kind of manager to look at these types. Dialogue: 0,0:21:52.83,0:21:56.48,EN,,0,0,0,,How are these things actually going to work now Dialogue: 0,0:21:57.05,0:21:59.40,EN,,0,0,0,,that George and Martha have supplied us with typed data? Dialogue: 0,0:22:00.53,0:22:04.30,EN,,0,0,0,,Well what we have are a bunch of generic selectors. Dialogue: 0,0:22:05.26,0:22:10.63,EN,,0,0,0,,Generic selectors for complex numbers real-part,imaginary-part, magnitude, and angle. Dialogue: 0,0:22:14.14,0:22:15.40,EN,,0,0,0,,Let's look at them more closely. Dialogue: 0,0:22:17.93,0:22:19.00,EN,,0,0,0,,What does a real-part do? Dialogue: 0,0:22:19.31,0:22:22.76,EN,,0,0,0,,If I ask for the real part of a complex number, Dialogue: 0,0:22:24.07,0:22:24.91,EN,,0,0,0,,well I look at it. Dialogue: 0,0:22:25.80,0:22:26.69,EN,,0,0,0,,I look at its type. Dialogue: 0,0:22:26.69,0:22:28.12,EN,,0,0,0,,I say, is it rectangular? Dialogue: 0,0:22:31.02,0:22:35.36,EN,,0,0,0,,If so, I apply George's real part procedure Dialogue: 0,0:22:36.06,0:22:37.92,EN,,0,0,0,,to the contents of that complex number. Dialogue: 0,0:22:41.07,0:22:42.94,EN,,0,0,0,,This is a number that has a type on it. Dialogue: 0,0:22:43.72,0:22:47.66,EN,,0,0,0,,I strip off the type using contents and apply George's procedure. Dialogue: 0,0:22:50.70,0:22:52.86,EN,,0,0,0,,Or is this a polar complex number? Dialogue: 0,0:22:53.95,0:22:54.97,EN,,0,0,0,,If I want the real part, Dialogue: 0,0:22:55.45,0:22:58.78,EN,,0,0,0,,I apply Martha's real-part procedure to the contents of that number. Dialogue: 0,0:22:59.85,0:23:01.15,EN,,0,0,0,,So that's how real part works. Dialogue: 0,0:23:02.26,0:23:05.66,EN,,0,0,0,,And then similarly there's imaginary-part, which is almost the same. Dialogue: 0,0:23:06.51,0:23:09.60,EN,,0,0,0,,Right? It looks at the number and if it's rectangular, uses Dialogue: 0,0:23:09.60,0:23:11.13,EN,,0,0,0,,George's imaginary-part procedure. Dialogue: 0,0:23:11.13,0:23:12.83,EN,,0,0,0,,If it's polar, uses Martha's. Dialogue: 0,0:23:13.38,0:23:17.40,EN,,0,0,0,,And then there's a magnitude and an angle. Dialogue: 0,0:23:19.71,0:23:21.02,EN,,0,0,0,,So there's a system. Dialogue: 0,0:23:23.00,0:23:24.26,EN,,0,0,0,,Has three parts. Dialogue: 0,0:23:24.26,0:23:26.59,EN,,0,0,0,,There's sort of George, and Martha, and the manager. Dialogue: 0,0:23:26.76,0:23:28.97,EN,,0,0,0,,And that's how you get generic operators implemented. Dialogue: 0,0:23:28.97,0:23:32.92,EN,,0,0,0,,Let's look at just a simple example, just to pin it down. Dialogue: 0,0:23:33.50,0:23:35.12,EN,,0,0,0,,But exactly how this is going to work, Dialogue: 0,0:23:36.54,0:23:43.98,EN,,0,0,0,,suppose you're going to be looking at the complex number who's real-part is one, Dialogue: 0,0:23:44.52,0:23:46.09,EN,,0,0,0,,and who's imaginary-part is two. Dialogue: 0,0:23:46.09,0:23:48.44,EN,,0,0,0,,So that would be one plus 2i. Dialogue: 0,0:23:50.31,0:23:52.64,EN,,0,0,0,,What would happen is up here, Dialogue: 0,0:23:55.28,0:23:57.53,EN,,0,0,0,,up here above where the operations have to happen, Dialogue: 0,0:23:57.63,0:24:08.27,EN,,0,0,0,,that number would be represented as a pair of 1 and 2 together with type data. Dialogue: 0,0:24:10.48,0:24:11.39,EN,,0,0,0,,That would be the contents. Dialogue: 0,0:24:11.87,0:24:17.96,EN,,0,0,0,,And the whole data would be that thing with the symbol rectangular added onto that. Dialogue: 0,0:24:18.14,0:24:21.53,EN,,0,0,0,,And that's the way that complex number would exist in the system. Dialogue: 0,0:24:22.33,0:24:24.92,EN,,0,0,0,,When you went to take the real-part, Dialogue: 0,0:24:25.84,0:24:28.89,EN,,0,0,0,,the manager will look at this and say, oh it's one of George's. Dialogue: 0,0:24:30.27,0:24:31.53,EN,,0,0,0,,He'll strip off the type Dialogue: 0,0:24:33.34,0:24:36.91,EN,,0,0,0,,and hand down to George the pair 1, 2. Dialogue: 0,0:24:38.00,0:24:42.27,EN,,0,0,0,,And that's the kind of data that George developed his system to use. Dialogue: 0,0:24:44.36,0:24:45.92,EN,,0,0,0,,So it gets stripped down. Dialogue: 0,0:24:46.52,0:24:49.76,EN,,0,0,0,,Later on, if you ask George to construct a complex number, Dialogue: 0,0:24:51.24,0:24:54.56,EN,,0,0,0,,George would construct some complex number as a pair, Dialogue: 0,0:24:55.07,0:24:58.24,EN,,0,0,0,,and before he passes it back up through the manager would Dialogue: 0,0:24:59.42,0:25:01.13,EN,,0,0,0,,attach the type rectangular. Dialogue: 0,0:25:03.92,0:25:04.65,EN,,0,0,0,,So you see what happens. Dialogue: 0,0:25:04.65,0:25:05.85,EN,,0,0,0,,There's no confusion in this system. Dialogue: 0,0:25:05.85,0:25:10.84,EN,,0,0,0,,It doesn't matter in the least that the pair 1, 2 Dialogue: 0,0:25:13.50,0:25:15.75,EN,,0,0,0,,means something completely different in Martha's world. Dialogue: 0,0:25:15.75,0:25:18.44,EN,,0,0,0,,In Martha's world this pair means the complex number whose Dialogue: 0,0:25:18.44,0:25:20.78,EN,,0,0,0,,magnitude is 1 and whose angle is 2. Dialogue: 0,0:25:21.19,0:25:22.19,EN,,0,0,0,,And there's no confusion, Dialogue: 0,0:25:22.22,0:25:27.25,EN,,0,0,0,,because by the time any pair like this gets handed back through the manager to the Dialogue: 0,0:25:27.25,0:25:29.61,EN,,0,0,0,,main system it's going to have the type polar attached. Dialogue: 0,0:25:31.21,0:25:33.67,EN,,0,0,0,,Whereas this one would have the type rectangular attached. Dialogue: 0,0:25:36.93,0:25:37.90,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:25:40.77,0:25:55.55,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:25:55.69,0:25:57.77,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:25:57.77,0:25:59.76,EN,,0,0,0,,By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:26:05.21,0:26:11.95,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:26:12.84,0:26:16.75,EN,,0,0,0,,Generic Operators Dialogue: 0,0:26:20.21,0:26:24.15,EN,,0,0,0,,We just looked at a strategy for implementing generic operators. Dialogue: 0,0:26:24.15,0:26:31.40,EN,,0,0,0,,That strategy has a name: it's called dispatch on type. Dialogue: 0,0:26:34.31,0:26:39.36,EN,,0,0,0,,And the idea is that you break your system into a bunch of pieces. Dialogue: 0,0:26:39.36,0:26:42.67,EN,,0,0,0,,There's George and Martha, who are making representations, Dialogue: 0,0:26:43.37,0:26:44.38,EN,,0,0,0,,and then there's the manager. Dialogue: 0,0:26:46.12,0:26:48.06,EN,,0,0,0,,Looks at the types on the data Dialogue: 0,0:26:48.51,0:26:50.59,EN,,0,0,0,,and then dispatches them to the right person. Dialogue: 0,0:26:51.99,0:26:56.01,EN,,0,0,0,,Well what criticisms can we make of that as a system organization? Dialogue: 0,0:26:58.15,0:27:00.40,EN,,0,0,0,,Well first of all there was this little, annoying problem Dialogue: 0,0:27:00.40,0:27:03.05,EN,,0,0,0,,that George and Martha had to change the names of their procedures Dialogue: 0,0:27:04.00,0:27:05.95,EN,,0,0,0,,George originally had a real-part procedure, Dialogue: 0,0:27:05.98,0:27:08.28,EN,,0,0,0,,and he had to go name it real-part rectangular Dialogue: 0,0:27:08.30,0:27:10.83,EN,,0,0,0,,so it wouldn't interfere with Martha's real-part procedure, Dialogue: 0,0:27:10.84,0:27:12.76,EN,,0,0,0,,which is now named real-part-polar, Dialogue: 0,0:27:13.64,0:27:16.68,EN,,0,0,0,,so it wouldn't interfere with the manager's real-part procedure, who's now named real-part. Dialogue: 0,0:27:17.31,0:27:18.94,EN,,0,0,0,,That's kind of an annoying problem. Dialogue: 0,0:27:19.46,0:27:21.13,EN,,0,0,0,,But I'm not going to talk about that one now. Dialogue: 0,0:27:21.27,0:27:22.35,EN,,0,0,0,,We'll see later on Dialogue: 0,0:27:23.26,0:27:26.12,EN,,0,0,0,,when we think about the structure of Lisp names and environments Dialogue: 0,0:27:26.12,0:27:30.39,EN,,0,0,0,,that there really are ways to package all those so-called name spaces separately so they Dialogue: 0,0:27:30.39,0:27:31.56,EN,,0,0,0,,don't interfere with each other. Dialogue: 0,0:27:32.50,0:27:34.01,EN,,0,0,0,,Not going to think about that problem now. Dialogue: 0,0:27:35.72,0:27:38.19,EN,,0,0,0,,The problem that I actually want to focus on is Dialogue: 0,0:27:38.36,0:27:43.24,EN,,0,0,0,,what happens when you bring somebody new into the system. Dialogue: 0,0:27:44.51,0:27:45.32,EN,,0,0,0,,What has to happen? Dialogue: 0,0:27:45.32,0:27:46.81,EN,,0,0,0,,Well George and Martha don't care. Dialogue: 0,0:27:47.42,0:27:50.73,EN,,0,0,0,,George is sitting there in his rectangular world, Dialogue: 0,0:27:52.20,0:27:53.84,EN,,0,0,0,,has his procedures and his types. Dialogue: 0,0:27:54.09,0:27:55.74,EN,,0,0,0,,Martha sits in her polar world. Dialogue: 0,0:27:55.93,0:27:57.02,EN,,0,0,0,,She doesn't care. Dialogue: 0,0:27:59.38,0:28:00.54,EN,,0,0,0,,But let's look at the manager. Dialogue: 0,0:28:00.62,0:28:02.84,EN,,0,0,0,,What's the manager have to do? Dialogue: 0,0:28:03.18,0:28:06.20,EN,,0,0,0,,The manager comes through and had these operations. Dialogue: 0,0:28:07.36,0:28:09.04,EN,,0,0,0,,There was a test for rectangular Dialogue: 0,0:28:09.04,0:28:10.14,EN,,0,0,0,,and a test for polar. Dialogue: 0,0:28:10.14,0:28:14.91,EN,,0,0,0,,If Harry comes in with some new kind of complex number, Dialogue: 0,0:28:17.21,0:28:19.96,EN,,0,0,0,,and Harry has a new type, Harry type complex number, the Dialogue: 0,0:28:20.27,0:28:23.28,EN,,0,0,0,,manager has to go in and change all those procedures. Dialogue: 0,0:28:25.24,0:28:26.94,EN,,0,0,0,,So the inflexibility in the system, Dialogue: 0,0:28:26.96,0:28:32.41,EN,,0,0,0,,the place where work has to happen to accommodate change, is in the manager. Dialogue: 0,0:28:34.89,0:28:35.99,EN,,0,0,0,,That's pretty annoying. Dialogue: 0,0:28:35.99,0:28:37.21,EN,,0,0,0,,It's even more annoying Dialogue: 0,0:28:39.05,0:28:41.21,EN,,0,0,0,,It's even more annoying when you realize the manager's not doing anything Dialogue: 0,0:28:42.59,0:28:44.67,EN,,0,0,0,,The manager is just being a paper pusher. Dialogue: 0,0:28:45.84,0:28:51.13,EN,,0,0,0,,Let's look again at these programs. What are they doing? Dialogue: 0,0:28:51.76,0:28:52.72,EN,,0,0,0,,What does real-part do? Dialogue: 0,0:28:52.88,0:28:56.17,EN,,0,0,0,,Real-part says, oh, is it the kind of complex number that Dialogue: 0,0:28:56.17,0:28:57.00,EN,,0,0,0,,George can handle? Dialogue: 0,0:28:57.00,0:28:58.27,EN,,0,0,0,,If so, send it off to George. Dialogue: 0,0:28:59.41,0:29:01.76,EN,,0,0,0,,Is it the kind of complex number that Martha can handle? Dialogue: 0,0:29:01.82,0:29:04.06,EN,,0,0,0,,If so, send it off to Martha. Dialogue: 0,0:29:05.04,0:29:08.72,EN,,0,0,0,,So it's really annoying that the bottleneck in this system, Dialogue: 0,0:29:08.72,0:29:11.66,EN,,0,0,0,,the thing that's preventing flexibility and change, Dialogue: 0,0:29:12.09,0:29:14.36,EN,,0,0,0,,is completely in the bureaucracy. Dialogue: 0,0:29:15.00,0:29:17.02,EN,,0,0,0,,It's not in anybody who's doing any of the work. Dialogue: 0,0:29:19.70,0:29:21.80,EN,,0,0,0,,Not an uncommon situation, unfortunately. Dialogue: 0,0:29:23.18,0:29:24.41,EN,,0,0,0,,See, what's really going on-- Dialogue: 0,0:29:24.48,0:29:26.97,EN,,0,0,0,,abstractly in the system, there's a table. Dialogue: 0,0:29:28.10,0:29:30.08,EN,,0,0,0,,So what's really happening is somewhere there's a table. Dialogue: 0,0:29:30.84,0:29:33.64,EN,,0,0,0,,There're types. Dialogue: 0,0:29:34.40,0:29:38.96,EN,,0,0,0,,There's polar and rectangular. Dialogue: 0,0:29:41.55,0:29:43.02,EN,,0,0,0,,And Harry's may be over here. Dialogue: 0,0:29:44.38,0:29:46.56,EN,,0,0,0,,And there are operators. Dialogue: 0,0:29:48.05,0:29:58.24,EN,,0,0,0,,There's an operator like real-part. Or imaginary-part. Dialogue: 0,0:30:00.01,0:30:04.22,EN,,0,0,0,,Or a magnitude and angle. Dialogue: 0,0:30:05.83,0:30:18.97,EN,,0,0,0,,And sitting in this table are the right procedures. Dialogue: 0,0:30:19.28,0:30:21.99,EN,,0,0,0,,So sitting here for the type polar and real-part is Dialogue: 0,0:30:21.99,0:30:27.56,EN,,0,0,0,,Martha's procedure real-part-polar. Dialogue: 0,0:30:30.57,0:30:36.62,EN,,0,0,0,,And over here in the table is George's procedure real-part-rectangular. Dialogue: 0,0:30:37.74,0:30:43.07,EN,,0,0,0,,And over here would be, say, Martha's procedure magnitude-polar, Dialogue: 0,0:30:44.46,0:30:49.76,EN,,0,0,0,,and George's procedure magnitude-rectangular, right, and so on. Dialogue: 0,0:30:49.76,0:30:51.24,EN,,0,0,0,,The rest of this table's filled in. Dialogue: 0,0:30:52.39,0:30:54.26,EN,,0,0,0,,And that's really what's going on. Dialogue: 0,0:30:57.63,0:31:01.74,EN,,0,0,0,,So in some sense, all the manager is doing Dialogue: 0,0:31:02.11,0:31:04.11,EN,,0,0,0,,is acting as this table. Dialogue: 0,0:31:06.86,0:31:08.70,EN,,0,0,0,,Well how do we fix our system? Dialogue: 0,0:31:11.74,0:31:13.77,EN,,0,0,0,,Well, how do you fix bureaucracies a lot of the time? Dialogue: 0,0:31:13.77,0:31:15.44,EN,,0,0,0,,What you do is you get rid of the manager. Dialogue: 0,0:31:16.01,0:31:19.55,EN,,0,0,0,,We just take the manager and replace him by a computer. Dialogue: 0,0:31:20.17,0:31:21.76,EN,,0,0,0,,We're going to automate him out of existence. Dialogue: 0,0:31:23.32,0:31:26.57,EN,,0,0,0,,Namely, instead of having the manager who basically consults this table, Dialogue: 0,0:31:27.45,0:31:29.32,EN,,0,0,0,,we'll have our system use the table directly. Dialogue: 0,0:31:31.02,0:31:32.11,EN,,0,0,0,,What do I mean by that? Dialogue: 0,0:31:32.11,0:31:36.19,EN,,0,0,0,,Let's assume, again using data abstraction, Dialogue: 0,0:31:37.71,0:31:40.40,EN,,0,0,0,,that we have some kind of data structure that's a table. Dialogue: 0,0:31:40.88,0:31:43.61,EN,,0,0,0,,And we have ways of sticking things in and ways of getting things out. Dialogue: 0,0:31:44.35,0:31:49.04,EN,,0,0,0,,And to be explicit, let me assume that there's an operation called "put." Dialogue: 0,0:31:50.30,0:31:58.32,EN,,0,0,0,,And put is going to take, case two things I'll call "keys." key1 and key2. Dialogue: 0,0:32:00.13,0:32:00.99,EN,,0,0,0,,And a value. Dialogue: 0,0:32:06.20,0:32:11.12,EN,,0,0,0,,And that stores the value in the table under key1 and key2. Dialogue: 0,0:32:11.49,0:32:13.16,EN,,0,0,0,,And then we'll assume there's a thing called "get," Dialogue: 0,0:32:15.23,0:32:18.72,EN,,0,0,0,,such that if later on I say, get me what's in the table Dialogue: 0,0:32:19.40,0:32:22.76,EN,,0,0,0,,stored under key1 and key2, Dialogue: 0,0:32:23.40,0:32:25.39,EN,,0,0,0,,it'll retrieve whatever value was stored there. Dialogue: 0,0:32:26.73,0:32:29.44,EN,,0,0,0,,And let's not worry about how tables are implemented. Dialogue: 0,0:32:30.00,0:32:32.52,EN,,0,0,0,,That's yet another data abstraction, George's problem. Dialogue: 0,0:32:33.06,0:32:34.36,EN,,0,0,0,,And maybe we'll see later-- Dialogue: 0,0:32:34.70,0:32:36.97,EN,,0,0,0,,talk about how you might actually build tables in Lisp. Dialogue: 0,0:32:40.71,0:32:45.50,EN,,0,0,0,,Well given this organization,what did George and Martha have to do? Dialogue: 0,0:32:47.38,0:32:49.07,EN,,0,0,0,,Well when they build their system, Dialogue: 0,0:32:49.13,0:32:51.08,EN,,0,0,0,,they each have the responsibility Dialogue: 0,0:32:51.44,0:32:53.82,EN,,0,0,0,,to set up their appropriate column in the table. Dialogue: 0,0:32:55.21,0:32:57.47,EN,,0,0,0,,So what George does, for example, Dialogue: 0,0:32:59.79,0:33:02.06,EN,,0,0,0,,when he defines his procedures all he has to do Dialogue: 0,0:33:02.27,0:33:07.99,EN,,0,0,0,,is go off and put into the table under the type-rectangular. Dialogue: 0,0:33:09.82,0:33:12.12,EN,,0,0,0,,And the name of the operation is real-part, Dialogue: 0,0:33:13.31,0:33:15.26,EN,,0,0,0,,his procedure real-part-rectangular. Dialogue: 0,0:33:16.25,0:33:17.78,EN,,0,0,0,,So notice what's going into this table. Dialogue: 0,0:33:17.78,0:33:22.10,EN,,0,0,0,,The two keys here are symbols, rectangular and real-part. Dialogue: 0,0:33:22.10,0:33:22.75,EN,,0,0,0,,That's the quote. Dialogue: 0,0:33:24.40,0:33:26.75,EN,,0,0,0,,And what's going into the table is the actual Dialogue: 0,0:33:26.84,0:33:29.21,EN,,0,0,0,,procedure that he wrote, real-part rectangular. Dialogue: 0,0:33:31.85,0:33:34.30,EN,,0,0,0,,And then puts an imaginary part into the table, Dialogue: 0,0:33:34.59,0:33:37.80,EN,,0,0,0,,filed under the keys rectangular and imaginary-part, Dialogue: 0,0:33:38.62,0:33:42.88,EN,,0,0,0,,and magnitude under the keys rectangular magnitude, Dialogue: 0,0:33:43.61,0:33:45.20,EN,,0,0,0,,angle under rectangular-angle. Dialogue: 0,0:33:47.04,0:33:50.84,EN,,0,0,0,,Okay? So that's what George has to do to be part of this system. Dialogue: 0,0:33:54.42,0:33:58.86,EN,,0,0,0,,Martha similarly sets up the column and the table under polar. Dialogue: 0,0:33:59.43,0:34:00.65,EN,,0,0,0,,Polar and real-part. Dialogue: 0,0:34:01.69,0:34:03.58,EN,,0,0,0,,Right? Is the procedure real-part-polar? Dialogue: 0,0:34:04.34,0:34:07.29,EN,,0,0,0,,And imaginary-part, and magnitude, and angle. Dialogue: 0,0:34:08.91,0:34:11.40,EN,,0,0,0,,So this is what Martha has to do to be part of the system. Dialogue: 0,0:34:11.40,0:34:13.55,EN,,0,0,0,,Everyone who makes a representation has the Dialogue: 0,0:34:13.55,0:34:17.63,EN,,0,0,0,,responsibility for setting up a column in the table. Dialogue: 0,0:34:17.76,0:34:19.90,EN,,0,0,0,,And what does Harry do when Harry comes in with his Dialogue: 0,0:34:19.90,0:34:21.80,EN,,0,0,0,,brilliant idea for implementing complex numbers? Dialogue: 0,0:34:21.80,0:34:23.96,EN,,0,0,0,,Well he makes whatever procedure he wants and Dialogue: 0,0:34:24.04,0:34:26.52,EN,,0,0,0,,builds a new column in this table. Dialogue: 0,0:34:28.55,0:34:30.04,EN,,0,0,0,,OK, well what happened to the manager? Dialogue: 0,0:34:31.33,0:34:34.61,EN,,0,0,0,,The manager has been automated out of existence and is Dialogue: 0,0:34:34.61,0:34:37.11,EN,,0,0,0,,replaced by a procedure called operate. Dialogue: 0,0:34:37.11,0:34:39.55,EN,,0,0,0,,And this is the key procedure in the whole system. Dialogue: 0,0:34:40.38,0:34:45.92,EN,,0,0,0,,Let's say define operate. Dialogue: 0,0:34:51.06,0:34:56.09,EN,,0,0,0,,Operate is going to take an operation that you want to do, Dialogue: 0,0:34:57.75,0:34:58.88,EN,,0,0,0,,the name of an operation, Dialogue: 0,0:34:59.20,0:35:03.28,EN,,0,0,0,,and an object that you would like to apply that operation to. Dialogue: 0,0:35:04.21,0:35:09.76,EN,,0,0,0,,So for example, the real-part of some particular complex number, what does it do? Dialogue: 0,0:35:09.95,0:35:11.90,EN,,0,0,0,,Well the first thing it does, it looks in the table. Dialogue: 0,0:35:12.64,0:35:13.87,EN,,0,0,0,,Goes into the table Dialogue: 0,0:35:14.80,0:35:22.56,EN,,0,0,0,,and tries to find a procedure that's stored in the table. Dialogue: 0,0:35:23.15,0:35:24.80,EN,,0,0,0,,So it gets from the table, Dialogue: 0,0:35:25.50,0:35:33.92,EN,,0,0,0,,using as keys the type of the object and the operator, Dialogue: 0,0:35:38.92,0:35:40.14,EN,,0,0,0,,but looks on the table and sees Dialogue: 0,0:35:40.38,0:35:42.72,EN,,0,0,0,,what's stored under the type of the object and the operator Dialogue: 0,0:35:42.89,0:35:44.35,EN,,0,0,0,,sees if anything's stored. Dialogue: 0,0:35:44.44,0:35:45.93,EN,,0,0,0,,Let's assume that get is implemented. Dialogue: 0,0:35:45.93,0:35:47.72,EN,,0,0,0,,So if nothing is stored there, Dialogue: 0,0:35:48.11,0:35:51.79,EN,,0,0,0,,it'll return a nil, return the empty list. Dialogue: 0,0:35:52.67,0:35:55.39,EN,,0,0,0,,So it says, if there's actually something stored there, Dialogue: 0,0:35:56.62,0:36:00.43,EN,,0,0,0,,if the procedure here is not no, Dialogue: 0,0:36:03.15,0:36:07.12,EN,,0,0,0,,then it'll take the procedure that it found in the table Dialogue: 0,0:36:09.79,0:36:15.00,EN,,0,0,0,,procedure that it found in the table and apply it to the contents of the object. Dialogue: 0,0:36:18.25,0:36:20.40,EN,,0,0,0,,And otherwise if there was nothing stored there, Dialogue: 0,0:36:20.67,0:36:22.51,EN,,0,0,0,,it'll-- well we can decide. Dialogue: 0,0:36:22.81,0:36:27.12,EN,,0,0,0,,In this case let's have it put out an error message saying, undefined operator. Dialogue: 0,0:36:28.48,0:36:30.24,EN,,0,0,0,,No operator for this type. Dialogue: 0,0:36:33.07,0:36:34.72,EN,,0,0,0,,Or some appropriate error message. Dialogue: 0,0:36:39.07,0:36:39.48,EN,,0,0,0,,OK? Dialogue: 0,0:36:39.72,0:36:41.04,EN,,0,0,0,,And that replaces the manager. Dialogue: 0,0:36:41.89,0:36:42.91,EN,,0,0,0,,How do we really use it? Dialogue: 0,0:36:43.96,0:36:49.80,EN,,0,0,0,,Well what we say is we'll go off and define our generic selectors using operate. Dialogue: 0,0:36:50.04,0:36:56.75,EN,,0,0,0,,We'll say that the real-part of an object is found by Dialogue: 0,0:36:57.14,0:37:05.66,EN,,0,0,0,,operating on the object with the name of the operation being real-part. Dialogue: 0,0:37:08.07,0:37:12.22,EN,,0,0,0,,And then similarly, imaginary-part is operate using the name imaginary-part Dialogue: 0,0:37:12.22,0:37:13.98,EN,,0,0,0,,and magnitude and angle. Dialogue: 0,0:37:15.36,0:37:17.43,EN,,0,0,0,,That's our implementation. Dialogue: 0,0:37:17.43,0:37:20.48,EN,,0,0,0,,That plus the type plus the operate procedure. Dialogue: 0,0:37:21.33,0:37:24.00,EN,,0,0,0,,And the table effectively replaces what the manager used to do. Dialogue: 0,0:37:24.06,0:37:27.69,EN,,0,0,0,,Let's just go through that slowly to show you what's going on. Dialogue: 0,0:37:27.90,0:37:33.00,EN,,0,0,0,,Suppose I have one of Martha's complex numbers. Dialogue: 0,0:37:33.53,0:37:38.80,EN,,0,0,0,,It's got magnitude 1 and angle 2. Dialogue: 0,0:37:39.10,0:37:40.22,EN,,0,0,0,,And it's one of Martha's. Dialogue: 0,0:37:40.22,0:37:45.45,EN,,0,0,0,,So it's labeled here, polar. Dialogue: 0,0:37:47.24,0:37:48.00,EN,,0,0,0,,Let's call that z. Dialogue: 0,0:37:48.00,0:37:48.91,EN,,0,0,0,,Suppose that's z. Dialogue: 0,0:37:51.77,0:37:54.46,EN,,0,0,0,,And suppose with this implementation someone comes up Dialogue: 0,0:37:54.80,0:37:57.92,EN,,0,0,0,,asks for the real-part of z. Dialogue: 0,0:38:04.87,0:38:07.96,EN,,0,0,0,,Well real-part now is defined in terms of operate. Dialogue: 0,0:38:09.16,0:38:10.57,EN,,0,0,0,,So that's equivalent to saying Dialogue: 0,0:38:12.09,0:38:24.81,EN,,0,0,0,,operate with the name of the operator being real-part, the symbol real-part on z. Dialogue: 0,0:38:27.06,0:38:28.09,EN,,0,0,0,,And now operate comes. Dialogue: 0,0:38:28.09,0:38:29.24,EN,,0,0,0,,It's going to look in the table, Dialogue: 0,0:38:31.04,0:38:34.36,EN,,0,0,0,,and it's going to try and find something stored under-- Dialogue: 0,0:38:39.00,0:38:46.22,EN,,0,0,0,,the operation is going to apply by looking in the table under the type of the object. Dialogue: 0,0:38:46.72,0:38:48.22,EN,,0,0,0,,And the type of z is polar. Dialogue: 0,0:38:48.79,0:38:51.37,EN,,0,0,0,,So it's going to look and say, can I get using polar? Dialogue: 0,0:38:52.99,0:38:58.57,EN,,0,0,0,,And the operation name, which was real-part. Dialogue: 0,0:39:05.96,0:39:13.63,EN,,0,0,0,,It's going to look in there and apply that to the contents of z. Dialogue: 0,0:39:14.83,0:39:17.13,EN,,0,0,0,,What's that is if everything was set up correctly, Dialogue: 0,0:39:17.74,0:39:21.70,EN,,0,0,0,,this thing is the procedure that Martha put there. Dialogue: 0,0:39:21.70,0:39:22.95,EN,,0,0,0,,This is real-part-polar. Dialogue: 0,0:39:31.05,0:39:35.13,EN,,0,0,0,,And this is z without its type. Dialogue: 0,0:39:35.44,0:39:38.94,EN,,0,0,0,,The thing that Martha originally designed those procedures to work on, Dialogue: 0,0:39:39.40,0:39:40.43,EN,,0,0,0,,which is 1, 2. Dialogue: 0,0:39:43.71,0:39:45.87,EN,,0,0,0,,And so operate sort of does uniformly Dialogue: 0,0:39:46.46,0:39:48.89,EN,,0,0,0,,what the manager used to do sort of all over the system. Dialogue: 0,0:39:49.45,0:39:52.59,EN,,0,0,0,,It finds the right thing, looks in the table, strips off the type, Dialogue: 0,0:39:53.58,0:39:57.52,EN,,0,0,0,,and passes it down into the person who handles it. Dialogue: 0,0:39:58.88,0:40:05.48,EN,,0,0,0,,This is another, and, you can see, more flexible for most purposes, Dialogue: 0,0:40:06.22,0:40:08.04,EN,,0,0,0,,way of implementing generic operators. Dialogue: 0,0:40:08.08,0:40:15.69,EN,,0,0,0,,And it's called data-directed programming. Dialogue: 0,0:40:20.35,0:40:21.96,EN,,0,0,0,,And the idea of that is Dialogue: 0,0:40:23.42,0:40:25.55,EN,,0,0,0,,And the idea of that is in some sense the data objects themselves, Dialogue: 0,0:40:26.04,0:40:28.35,EN,,0,0,0,,those little complex numbers that are floating around the system, Dialogue: 0,0:40:28.73,0:40:33.16,EN,,0,0,0,,are carrying with them the information about how you should operate on them. Dialogue: 0,0:40:35.74,0:40:36.78,EN,,0,0,0,,Let's break for questions. Dialogue: 0,0:40:41.00,0:40:41.24,EN,,0,0,0,,Yes. Dialogue: 0,0:40:41.24,0:40:43.39,EN,,0,0,0,,AUDIENCE: What do you have stored in that data object? Dialogue: 0,0:40:43.39,0:40:47.10,EN,,0,0,0,,You have the data itself, you have its type, Dialogue: 0,0:40:47.10,0:40:49.60,EN,,0,0,0,,the operations for that type? Dialogue: 0,0:40:49.69,0:40:53.08,EN,,0,0,0,,Or where are the operations that you found? Dialogue: 0,0:40:53.60,0:40:54.17,EN,,0,0,0,,PROFESSOR: OK, let me-- Dialogue: 0,0:40:54.98,0:40:56.50,EN,,0,0,0,,yeah, that's a good question. Dialogue: 0,0:40:56.50,0:41:00.46,EN,,0,0,0,,Because it raises other possibilities of how you might do it. Dialogue: 0,0:41:00.75,0:41:02.48,EN,,0,0,0,,And of course there are a lot of possibilities. Dialogue: 0,0:41:04.20,0:41:06.14,EN,,0,0,0,,In this particular implementation, Dialogue: 0,0:41:06.24,0:41:09.72,EN,,0,0,0,,what's sitting in this data object, for example, Dialogue: 0,0:41:10.44,0:41:13.45,EN,,0,0,0,,is the data itself-- which in this case is a pair of 1 and 2-- Dialogue: 0,0:41:14.98,0:41:16.55,EN,,0,0,0,,and also a symbol. Dialogue: 0,0:41:16.55,0:41:19.07,EN,,0,0,0,,This is the symbol, the word P-O-L-A-R, Dialogue: 0,0:41:20.60,0:41:22.33,EN,,0,0,0,,And that what's sitting in this data object. Dialogue: 0,0:41:24.24,0:41:26.69,EN,,0,0,0,,OK, where are the operations themselves? Dialogue: 0,0:41:26.69,0:41:29.00,EN,,0,0,0,,The operations are sitting in the table. Dialogue: 0,0:41:29.85,0:41:31.07,EN,,0,0,0,,So in this table, Dialogue: 0,0:41:32.30,0:41:36.46,EN,,0,0,0,,the rows and columns of the table are labeled by symbols. Dialogue: 0,0:41:38.23,0:41:40.08,EN,,0,0,0,,So when I store something in this table, Dialogue: 0,0:41:40.09,0:41:47.02,EN,,0,0,0,,the key might be the symbol polar and the symbol magnitude. Dialogue: 0,0:41:48.24,0:41:51.31,EN,,0,0,0,,And I think by writing it this way I've been very confusing. Dialogue: 0,0:41:51.31,0:41:52.70,EN,,0,0,0,,Because what's really sitting here isn't-- Dialogue: 0,0:41:53.16,0:41:54.57,EN,,0,0,0,,when I wrote magnitude polar, Dialogue: 0,0:41:57.04,0:41:59.23,EN,,0,0,0,,what I mean is the procedure magnitude polar. Dialogue: 0,0:41:59.85,0:42:01.85,EN,,0,0,0,,And probably what I really should have written-- Dialogue: 0,0:42:02.58,0:42:04.20,EN,,0,0,0,,except it's too small for me to write Dialogue: 0,0:42:04.20,0:42:05.07,EN,,0,0,0,,in this little space-- Dialogue: 0,0:42:05.58,0:42:08.92,EN,,0,0,0,,is something like lambda of z, Dialogue: 0,0:42:10.60,0:42:12.75,EN,,0,0,0,,the thing that Martha wrote to implement. Dialogue: 0,0:42:14.71,0:42:15.72,EN,,0,0,0,,And then you can see from that, Dialogue: 0,0:42:15.74,0:42:17.44,EN,,0,0,0,,there's another way that I alluded to Dialogue: 0,0:42:17.71,0:42:19.82,EN,,0,0,0,,of solving this name conflict problem Dialogue: 0,0:42:20.04,0:42:23.15,EN,,0,0,0,,which is that George and Martha never have to name their procedures at all. Dialogue: 0,0:42:23.15,0:42:25.37,EN,,0,0,0,,They can just stick the lambda, the lambda... Dialogue: 0,0:42:25.39,0:42:28.12,EN,,0,0,0,,the anonymous things generated by lambda directly into the table. Dialogue: 0,0:42:28.66,0:42:31.76,EN,,0,0,0,,There's also another thing that your question raises, Dialogue: 0,0:42:32.35,0:42:34.06,EN,,0,0,0,,is the possibility that maybe Dialogue: 0,0:42:34.83,0:42:37.92,EN,,0,0,0,,what I would like somehow is to store in this data object Dialogue: 0,0:42:37.95,0:42:39.48,EN,,0,0,0,,not the symbol P-O-L-A-R but Dialogue: 0,0:42:39.93,0:42:42.35,EN,,0,0,0,,maybe actually all the operations themselves. Dialogue: 0,0:42:43.90,0:42:45.63,EN,,0,0,0,,And that's another way to organize the system, Dialogue: 0,0:42:45.66,0:42:46.60,EN,,0,0,0,,called message passing. Dialogue: 0,0:42:48.65,0:42:49.92,EN,,0,0,0,,So there are a lot of ways you can do it. Dialogue: 0,0:42:54.64,0:42:58.04,EN,,0,0,0,,AUDIENCE: Therefore if Martha and George had used the same Dialogue: 0,0:42:58.04,0:43:01.23,EN,,0,0,0,,procedure names, it would be OK because it wouldn't look Dialogue: 0,0:43:01.23,0:43:02.56,EN,,0,0,0,,it wouldn't look into it Dialogue: 0,0:43:02.56,0:43:04.68,EN,,0,0,0,,PROFESSOR: That's right.That's right. Dialogue: 0,0:43:04.80,0:43:07.85,EN,,0,0,0,,See, they wouldn't even have to name their procedures at all. Dialogue: 0,0:43:08.04,0:43:09.36,EN,,0,0,0,,What George and Martha could writ --, Dialogue: 0,0:43:09.50,0:43:10.62,EN,,0,0,0,,what George could have written Dialogue: 0,0:43:10.83,0:43:15.28,EN,,0,0,0,,instead of saying put in the table under rectangular- and real-part, Dialogue: 0,0:43:16.22,0:43:17.98,EN,,0,0,0,,the procedure real-part rectangular, Dialogue: 0,0:43:18.03,0:43:21.15,EN,,0,0,0,,George could have written put under rectangular real-part, Dialogue: 0,0:43:21.24,0:43:23.69,EN,,0,0,0,,lambda of z, such and such, such and such, Dialogue: 0,0:43:24.54,0:43:26.84,EN,,0,0,0,,And the system would work completely the same. Dialogue: 0,0:43:27.33,0:43:29.24,EN,,0,0,0,,AUDIENCE: My question is, Martha could put Dialogue: 0,0:43:29.84,0:43:33.60,EN,,0,0,0,,could have put key1 key2 real-part, Dialogue: 0,0:43:33.95,0:43:37.64,EN,,0,0,0,,and George could have put key1 key2 real-part, Dialogue: 0,0:43:37.96,0:43:39.60,EN,,0,0,0,,and as long as they defined them differently Dialogue: 0,0:43:39.80,0:43:41.26,EN,,0,0,0,,they wouldn't have had any conflicts, right? Dialogue: 0,0:43:41.29,0:43:43.80,EN,,0,0,0,,PROFESSOR: Yes, that would all be OK except for the fact Dialogue: 0,0:43:44.97,0:43:47.13,EN,,0,0,0,,that if you imagine George and Martha typing at the same Dialogue: 0,0:43:47.13,0:43:49.20,EN,,0,0,0,,console with the same meanings for all their names, Dialogue: 0,0:43:49.82,0:43:51.23,EN,,0,0,0,,and it would get confused by real-part, Dialogue: 0,0:43:51.24,0:43:52.80,EN,,0,0,0,,but there are ways to arrange that, too. Dialogue: 0,0:43:52.80,0:43:54.80,EN,,0,0,0,,And in principle you're absolutely right. Dialogue: 0,0:43:54.98,0:43:56.29,EN,,0,0,0,,If their names didn't conflict-- Dialogue: 0,0:43:56.29,0:43:58.19,EN,,0,0,0,,it's the objects that go in the table, not the names. Dialogue: 0,0:44:08.20,0:44:09.05,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:44:12.91,0:44:20.48,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:44:20.96,0:44:23.29,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:44:23.45,0:44:25.29,EN,,0,0,0,,By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:44:57.42,0:45:05.07,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:45:05.47,0:45:09.24,EN,,0,0,0,,Generic Operators Dialogue: 0,0:45:12.88,0:45:16.88,EN,,0,0,0,,RPOFESSOR: All right, well we just looked at data-directed programming Dialogue: 0,0:45:17.68,0:45:22.84,EN,,0,0,0,,as a way of implementing a system that does arithmetic on complex numbers. Dialogue: 0,0:45:27.60,0:45:32.48,EN,,0,0,0,,So I had these operations in it called plus C and minus C, Dialogue: 0,0:45:32.88,0:45:37.24,EN,,0,0,0,,and multiply, and divide,and maybe some others. Dialogue: 0,0:45:38.23,0:45:45.72,EN,,0,0,0,,And that sat on top of-- and this is the key point-- Dialogue: 0,0:45:45.74,0:45:49.60,EN,,0,0,0,,sat on top of two different representations. Dialogue: 0,0:45:50.34,0:45:55.44,EN,,0,0,0,,A rectangular package here, and a polar package. Dialogue: 0,0:45:58.14,0:45:59.15,EN,,0,0,0,,And maybe some more. Dialogue: 0,0:45:59.15,0:46:02.80,EN,,0,0,0,,And we saw that the whole idea is that maybe some more are now very easy to add. Dialogue: 0,0:46:04.67,0:46:08.35,EN,,0,0,0,,But that doesn't really show the power of this methodology. Dialogue: 0,0:46:08.90,0:46:10.15,EN,,0,0,0,,Shows you what's going on. Dialogue: 0,0:46:10.15,0:46:12.33,EN,,0,0,0,,The power of the methodology only becomes apparent Dialogue: 0,0:46:12.94,0:46:15.79,EN,,0,0,0,,when you start embedding this in some more complex system. Dialogue: 0,0:46:16.17,0:46:17.74,EN,,0,0,0,,So let... What I'm going to do now Dialogue: 0,0:46:17.87,0:46:20.01,EN,,0,0,0,,is embed this in some more complex system. Dialogue: 0,0:46:20.25,0:46:25.28,EN,,0,0,0,,Let's assume that what we really have is a general kind of arithmetic system. Dialogue: 0,0:46:25.28,0:46:27.24,EN,,0,0,0,,So called generic arithmetic system. Dialogue: 0,0:46:27.24,0:46:28.54,EN,,0,0,0,,And at the top level here, Dialogue: 0,0:46:30.76,0:46:35.92,EN,,0,0,0,,somebody can say add twothings, or subtract two things, Dialogue: 0,0:46:37.45,0:46:41.05,EN,,0,0,0,,or multiply two things, or divide two things. Dialogue: 0,0:46:44.14,0:46:46.52,EN,,0,0,0,,And underneath that there's an abstraction barrier. Dialogue: 0,0:46:47.93,0:46:49.15,EN,,0,0,0,,And underneath this barrier, Dialogue: 0,0:46:49.50,0:46:52.48,EN,,0,0,0,,is, say, a complex arithmetic package. Dialogue: 0,0:46:53.02,0:46:54.96,EN,,0,0,0,,And you can say, add two complex numbers. Dialogue: 0,0:46:55.04,0:46:58.83,EN,,0,0,0,,Or you might also have--remember we did a rational number package Dialogue: 0,0:46:58.88,0:46:59.93,EN,,0,0,0,,you might have that sitting there. Dialogue: 0,0:47:00.19,0:47:01.72,EN,,0,0,0,,And there might be a rational thing. Dialogue: 0,0:47:04.76,0:47:06.22,EN,,0,0,0,,And the rational number package, Dialogue: 0,0:47:07.16,0:47:14.75,EN,,0,0,0,,well, has the things we implemented. Plus rat, and times rat, and so on. Dialogue: 0,0:47:15.39,0:47:17.01,EN,,0,0,0,,Or you might have ordinary Lisp numbers. Dialogue: 0,0:47:17.01,0:47:18.99,EN,,0,0,0,,You might say add three and four. Dialogue: 0,0:47:19.42,0:47:20.94,EN,,0,0,0,,So we might have ordinary numbers, Dialogue: 0,0:47:28.28,0:47:34.67,EN,,0,0,0,,in which case we have the Lisp supplied plus, and minus, and times, and slash. Dialogue: 0,0:47:36.67,0:47:39.12,EN,,0,0,0,,OK, so we might imagine this complex number system Dialogue: 0,0:47:39.44,0:47:44.44,EN,,0,0,0,,sitting in a more complicated generic operator structure at the next level up. Dialogue: 0,0:47:47.73,0:47:48.73,EN,,0,0,0,,Well how can we make that? Dialogue: 0,0:47:49.05,0:47:52.32,EN,,0,0,0,,We already have the idea, we're just going to do it again. Dialogue: 0,0:47:52.78,0:47:54.72,EN,,0,0,0,,We've implemented a rational number package. Dialogue: 0,0:47:54.72,0:47:56.89,EN,,0,0,0,,Let's look at how it has to be changed. Dialogue: 0,0:48:01.48,0:48:03.40,EN,,0,0,0,,In fact, at this level it doesn't have to be changed at all. Dialogue: 0,0:48:03.73,0:48:05.88,EN,,0,0,0,,This is exactly the code that we wrote last time. Dialogue: 0,0:48:07.18,0:48:08.97,EN,,0,0,0,,To add two rational numbers, Dialogue: 0,0:48:09.85,0:48:10.91,EN,,0,0,0,,remember there was this formula. Dialogue: 0,0:48:11.14,0:48:13.37,EN,,0,0,0,,You make a rational number whose numerator-- Dialogue: 0,0:48:13.98,0:48:17.56,EN,,0,0,0,,is the numerator of the first times the denominator of the second Dialogue: 0,0:48:17.93,0:48:21.52,EN,,0,0,0,,plus the denominator of the first times the numerator of the second. Dialogue: 0,0:48:21.52,0:48:23.79,EN,,0,0,0,,And who's denominator is the product of the denominators. Dialogue: 0,0:48:25.76,0:48:29.07,EN,,0,0,0,,And minus rat, and star rat, and slash rat. Dialogue: 0,0:48:30.36,0:48:35.12,EN,,0,0,0,,And this is exactly the rational number package that we made before. Dialogue: 0,0:48:36.31,0:48:38.89,EN,,0,0,0,,We're ignoring the GCD problem,but let's not worry about that. Dialogue: 0,0:48:39.08,0:48:42.59,EN,,0,0,0,,How do we install... As implementers of this rational number package, Dialogue: 0,0:48:42.80,0:48:45.10,EN,,0,0,0,,how do we install it in the generic arithmetic system? Dialogue: 0,0:48:45.57,0:48:46.22,EN,,0,0,0,,Well that's easy. Dialogue: 0,0:48:47.29,0:48:51.56,EN,,0,0,0,,Go off... There's only one thing we have to do differently. Dialogue: 0,0:48:51.84,0:48:55.71,EN,,0,0,0,,Whereas previously we said that to make a rational number Dialogue: 0,0:48:56.27,0:48:59.98,EN,,0,0,0,,you built a pair of the numerator and denominator, Dialogue: 0,0:49:00.96,0:49:03.20,EN,,0,0,0,,here we'll not only build the pair, but we'll sign it. Dialogue: 0,0:49:03.30,0:49:04.56,EN,,0,0,0,,We'll attach the type rational. Dialogue: 0,0:49:06.36,0:49:08.09,EN,,0,0,0,,That's the only thing we have to do different, Dialogue: 0,0:49:08.56,0:49:10.09,EN,,0,0,0,,make it a typed data object. Dialogue: 0,0:49:12.38,0:49:14.08,EN,,0,0,0,,And now we'll stick our operations in the table. Dialogue: 0,0:49:14.36,0:49:18.20,EN,,0,0,0,,We'll put under the symbol rational and the operation add Dialogue: 0,0:49:18.92,0:49:20.25,EN,,0,0,0,,our procedure -- +rat. Dialogue: 0,0:49:21.82,0:49:23.24,EN,,0,0,0,,And, again, note this is a symbol. Dialogue: 0,0:49:23.74,0:49:23.93,EN,,0,0,0,,Right? Dialogue: 0,0:49:24.03,0:49:25.29,EN,,0,0,0,,Quote, and quote, Dialogue: 0,0:49:25.31,0:49:28.01,EN,,0,0,0,,but the actual thing we're putting in the table is the procedure. Dialogue: 0,0:49:29.82,0:49:31.77,EN,,0,0,0,,And for how to subtract, Dialogue: 0,0:49:31.79,0:49:36.81,EN,,0,0,0,,well you subtract rationals with minus rat. Dialogue: 0,0:49:38.27,0:49:40.24,EN,,0,0,0,,And multiply, and divide. Dialogue: 0,0:49:41.09,0:49:43.64,EN,,0,0,0,,And that is exactly and precisely what we have to do Dialogue: 0,0:49:44.14,0:49:46.97,EN,,0,0,0,,to fit inside this generic arithmetic system. Dialogue: 0,0:49:48.51,0:49:49.88,EN,,0,0,0,,Well how does the whole thing work? Dialogue: 0,0:49:51.56,0:49:58.40,EN,,0,0,0,,See, what we want to do is have some generic operators. Dialogue: 0,0:49:59.34,0:50:02.80,EN,,0,0,0,,Right? Have add and sub and mul and div be generic operators. Dialogue: 0,0:50:03.99,0:50:17.36,EN,,0,0,0,,So we're going to define add and say, to add x and y, Dialogue: 0,0:50:18.62,0:50:22.12,EN,,0,0,0,,that will be operate-- Dialogue: 0,0:50:26.08,0:50:27.49,EN,,0,0,0,,we were going to call it operate-2. Dialogue: 0,0:50:27.49,0:50:30.78,EN,,0,0,0,,This is our operator procedure, but set up for two arguments Dialogue: 0,0:50:31.60,0:50:35.84,EN,,0,0,0,,using add on x and y. Dialogue: 0,0:50:37.60,0:50:39.76,EN,,0,0,0,,And so this is the analog to operate. Dialogue: 0,0:50:40.42,0:50:41.68,EN,,0,0,0,,Let's look at the code for a second. Dialogue: 0,0:50:41.68,0:50:42.93,EN,,0,0,0,,It's almost like operate. Dialogue: 0,0:50:45.79,0:50:52.49,EN,,0,0,0,,Right? To operate with some operator on an argument1 and an argument2 Dialogue: 0,0:50:55.04,0:50:56.65,EN,,0,0,0,,well the first thing we're going to do is check Dialogue: 0,0:50:56.83,0:51:00.73,EN,,0,0,0,,and see if the two arguments have the same type. Dialogue: 0,0:51:01.90,0:51:02.96,EN,,0,0,0,,So we'll say, Dialogue: 0,0:51:02.99,0:51:07.77,EN,,0,0,0,,is the type of the first argument the same as the type of the second argument? Dialogue: 0,0:51:10.35,0:51:13.36,EN,,0,0,0,,And if they're not, if they're not Dialogue: 0,0:51:13.58,0:51:15.63,EN,,0,0,0,,we'll go off and complain, and say, that's an error. Dialogue: 0,0:51:15.67,0:51:16.67,EN,,0,0,0,,We don't know how to do that. Dialogue: 0,0:51:19.14,0:51:20.49,EN,,0,0,0,,If they do have the same type, Dialogue: 0,0:51:20.51,0:51:22.08,EN,,0,0,0,,we'll do exactly what we did before. Dialogue: 0,0:51:22.08,0:51:26.46,EN,,0,0,0,,We'll go look and filed under the type of the argument-- Dialogue: 0,0:51:26.76,0:51:29.61,EN,,0,0,0,,arg 1 and arg 2 have the same type, so it doesn't matter. Dialogue: 0,0:51:30.42,0:51:32.59,EN,,0,0,0,,So we'll look in the table, find the procedure. Dialogue: 0,0:51:33.64,0:51:35.87,EN,,0,0,0,,If there is a procedure there, Dialogue: 0,0:51:37.53,0:51:41.74,EN,,0,0,0,,then we'll apply it to the contents of the arg1 and the contents of arg2. Dialogue: 0,0:51:43.03,0:51:44.76,EN,,0,0,0,,And otherwise we'll say, error. Dialogue: 0,0:51:44.76,0:51:45.72,EN,,0,0,0,,Undefined operator. Dialogue: 0,0:51:46.89,0:51:48.16,EN,,0,0,0,,And so there's operate-2. Dialogue: 0,0:51:51.72,0:51:54.03,EN,,0,0,0,,And that's all we have to do. Dialogue: 0,0:51:55.16,0:51:57.45,EN,,0,0,0,,We just built the complex number package before. Dialogue: 0,0:51:57.64,0:52:01.00,EN,,0,0,0,,How do we embed that complex number package in this generic system? Dialogue: 0,0:52:02.14,0:52:02.91,EN,,0,0,0,,Almost the same. Dialogue: 0,0:52:06.41,0:52:08.59,EN,,0,0,0,,We make a procedure called make-complex Dialogue: 0,0:52:09.95,0:52:12.81,EN,,0,0,0,,that takes whatever George and Martha hand to us Dialogue: 0,0:52:13.64,0:52:15.00,EN,,0,0,0,,and add the type complex. Dialogue: 0,0:52:18.17,0:52:23.87,EN,,0,0,0,,And then we say, to add complex numbers, plus complex, Dialogue: 0,0:52:25.84,0:52:28.78,EN,,0,0,0,,we use our internal procedure, plus c, Dialogue: 0,0:52:30.78,0:52:32.24,EN,,0,0,0,,and attach a type, Dialogue: 0,0:52:32.24,0:52:33.42,EN,,0,0,0,,make that a complex number. Dialogue: 0,0:52:37.68,0:52:42.52,EN,,0,0,0,,So our original package had names plus c and minus c Dialogue: 0,0:52:42.68,0:52:44.75,EN,,0,0,0,,that we're using to communicate with George and Martha. Dialogue: 0,0:52:45.25,0:52:47.39,EN,,0,0,0,,And then to communicate with the outside world, Dialogue: 0,0:52:47.40,0:52:53.04,EN,,0,0,0,,we have a thing called plus-complex and minus-complex. Dialogue: 0,0:52:55.92,0:52:56.53,EN,,0,0,0,,And so on. Dialogue: 0,0:52:56.53,0:52:59.98,EN,,0,0,0,,And the only difference is that these return values that are typed Dialogue: 0,0:53:01.12,0:53:02.41,EN,,0,0,0,,So they can be looked at up here. Dialogue: 0,0:53:02.85,0:53:05.02,EN,,0,0,0,,And these are internal operations. Dialogue: 0,0:53:09.25,0:53:10.68,EN,,0,0,0,,Let's go look at that slide again. Dialogue: 0,0:53:10.68,0:53:13.04,EN,,0,0,0,,There's one more thing we do. Dialogue: 0,0:53:13.74,0:53:15.61,EN,,0,0,0,,After defining plus-complex, Dialogue: 0,0:53:15.68,0:53:20.52,EN,,0,0,0,,we put under the type complex and the symbol add, Dialogue: 0,0:53:21.31,0:53:22.75,EN,,0,0,0,,that procedure plus complex. Dialogue: 0,0:53:23.20,0:53:26.75,EN,,0,0,0,,And then similarly for subtracting complex numbers, Dialogue: 0,0:53:27.13,0:53:29.13,EN,,0,0,0,,and multiplying them, and dividing them. Dialogue: 0,0:53:31.70,0:53:33.48,EN,,0,0,0,,OK, how do we install ordinary numbers? Dialogue: 0,0:53:35.25,0:53:36.12,EN,,0,0,0,,Exactly the same way. Dialogue: 0,0:53:38.16,0:53:41.36,EN,,0,0,0,,Come off and say, well we'll make a thing called make-number Dialogue: 0,0:53:44.34,0:53:48.11,EN,,0,0,0,,Make-number takes a number and attaches a type, Dialogue: 0,0:53:48.14,0:53:49.29,EN,,0,0,0,,which is the symbol number. Dialogue: 0,0:53:50.26,0:53:52.11,EN,,0,0,0,,We build a procedure called plus-number, Dialogue: 0,0:53:52.92,0:53:58.75,EN,,0,0,0,,which is simply, add the two things using the ordinary addition, Dialogue: 0,0:53:58.92,0:54:00.78,EN,,0,0,0,,because in this case we're talking about ordinary numbers, Dialogue: 0,0:54:01.31,0:54:03.10,EN,,0,0,0,,and attach a type to it and make that a number. Dialogue: 0,0:54:04.51,0:54:08.09,EN,,0,0,0,,And then we put into the table under the symbol number Dialogue: 0,0:54:08.59,0:54:11.00,EN,,0,0,0,,and the operation add, this procedure plus-number, Dialogue: 0,0:54:12.30,0:54:16.16,EN,,0,0,0,,and then the same thing for subtracting, and multiplying, and dividing. Dialogue: 0,0:54:22.67,0:54:26.06,EN,,0,0,0,,Let's look at an example, just to make it clear. Dialogue: 0,0:54:26.06,0:54:28.75,EN,,0,0,0,,Suppose, for instance, Dialogue: 0,0:54:32.28,0:54:34.15,EN,,0,0,0,,I'm going to perform the operation. Dialogue: 0,0:54:34.15,0:54:38.22,EN,,0,0,0,,So I sit up here and I'm going to perform the operation, Dialogue: 0,0:54:38.22,0:54:40.46,EN,,0,0,0,,which looks like multiplying two complex numbers. Dialogue: 0,0:54:40.93,0:54:48.64,EN,,0,0,0,,So I would multiply, say, 3 plus 4i and 2 plus 6i. Dialogue: 0,0:54:50.17,0:54:52.60,EN,,0,0,0,,And that's something that I might want to take hand that to mul. Dialogue: 0,0:54:52.84,0:54:55.76,EN,,0,0,0,,I'll write mul as my generic operator here. Dialogue: 0,0:54:57.17,0:54:57.98,EN,,0,0,0,,How's that going to work? Dialogue: 0,0:54:58.28,0:55:04.60,EN,,0,0,0,,Well 3 plus 4i, say, sits in the system at this level Dialogue: 0,0:55:04.83,0:55:06.11,EN,,0,0,0,,as something that looks like this. Dialogue: 0,0:55:06.25,0:55:07.52,EN,,0,0,0,,Let's say it was one of George's. Dialogue: 0,0:55:08.28,0:55:14.97,EN,,0,0,0,,So it would have a 3 and a 4. Dialogue: 0,0:55:18.49,0:55:20.97,EN,,0,0,0,,And attached to that would be George's type, Dialogue: 0,0:55:24.33,0:55:28.32,EN,,0,0,0,,which says rectangular, it came from George. Dialogue: 0,0:55:29.51,0:55:30.57,EN,,0,0,0,,And attached to that-- Dialogue: 0,0:55:31.23,0:55:35.79,EN,,0,0,0,,and this itself would be the data view from the next level up Dialogue: 0,0:55:36.19,0:55:36.78,EN,,0,0,0,,which it is-- Dialogue: 0,0:55:37.93,0:55:39.96,EN,,0,0,0,,so that itself would be a type-data object Dialogue: 0,0:55:40.60,0:55:41.80,EN,,0,0,0,,which would say complex. Dialogue: 0,0:55:44.82,0:55:47.31,EN,,0,0,0,,So that's what this object would look like Dialogue: 0,0:55:48.64,0:55:50.24,EN,,0,0,0,,up here at the very highest level, Dialogue: 0,0:55:50.68,0:55:53.56,EN,,0,0,0,,where the really super-generic operations are looking at it. Dialogue: 0,0:55:55.56,0:55:58.72,EN,,0,0,0,,Now what happens, mul eventually's going to come along Dialogue: 0,0:55:58.84,0:56:00.40,EN,,0,0,0,,and say, oh,what's it's type? Dialogue: 0,0:56:00.48,0:56:01.48,EN,,0,0,0,,It's type is complex. Dialogue: 0,0:56:04.27,0:56:06.46,EN,,0,0,0,,Go through to operate-2 and say, Dialogue: 0,0:56:06.46,0:56:09.72,EN,,0,0,0,,oh, what I want to do is apply what's in the table, Dialogue: 0,0:56:09.72,0:56:13.04,EN,,0,0,0,,which is going to be the procedure star complex, Dialogue: 0,0:56:15.08,0:56:17.76,EN,,0,0,0,,on this thing with the type stripped off. Dialogue: 0,0:56:17.95,0:56:19.28,EN,,0,0,0,,So it's going to strip off the type, Dialogue: 0,0:56:19.93,0:56:24.24,EN,,0,0,0,,take that much, and send that down into the complex world. Dialogue: 0,0:56:26.70,0:56:28.73,EN,,0,0,0,,The complex world looks at its operations and says, Dialogue: 0,0:56:28.76,0:56:30.56,EN,,0,0,0,,oh, I have to apply star c. Dialogue: 0,0:56:31.28,0:56:32.14,EN,,0,0,0,,Star c might say, Dialogue: 0,0:56:32.22,0:56:37.20,EN,,0,0,0,,at some point I want to look at the magnitude of this object that it's in, that it's got. Dialogue: 0,0:56:39.42,0:56:40.16,EN,,0,0,0,,And they'll say, oh, it's Dialogue: 0,0:56:40.16,0:56:41.71,EN,,0,0,0,,rectangular, it's one of George's. Dialogue: 0,0:56:41.87,0:56:44.41,EN,,0,0,0,,So it'll then strip off the next version of type, Dialogue: 0,0:56:46.91,0:56:49.80,EN,,0,0,0,,and hand that down to George to take the magnitude of. Dialogue: 0,0:56:52.16,0:56:53.13,EN,,0,0,0,,So you see what's going on Dialogue: 0,0:56:53.44,0:56:56.99,EN,,0,0,0,,is that there are these chains of types. Dialogue: 0,0:56:59.32,0:57:01.50,EN,,0,0,0,,And the length of the chain is sort of the number of levels Dialogue: 0,0:57:01.53,0:57:03.13,EN,,0,0,0,,that you're going to be going up in this table. Dialogue: 0,0:57:05.09,0:57:05.96,EN,,0,0,0,,And what a type tells you, Dialogue: 0,0:57:05.96,0:57:10.84,EN,,0,0,0,,every time you have a vertical barrier in this table, Dialogue: 0,0:57:11.05,0:57:14.06,EN,,0,0,0,,where there's some ambiguity about where you should go down to the next level, Dialogue: 0,0:57:14.41,0:57:15.85,EN,,0,0,0,,the type is telling you where to go. Dialogue: 0,0:57:17.44,0:57:18.83,EN,,0,0,0,,And then everybody at the bottom, Dialogue: 0,0:57:18.97,0:57:20.67,EN,,0,0,0,,as they construct data and filter it up, Dialogue: 0,0:57:21.12,0:57:22.81,EN,,0,0,0,,they stick their type back on. Dialogue: 0,0:57:25.35,0:57:30.75,EN,,0,0,0,,So that's the general structure of the system. Dialogue: 0,0:57:33.41,0:57:33.77,EN,,0,0,0,,OK. Dialogue: 0,0:57:34.82,0:57:35.68,EN,,0,0,0,,Now that we've got this, Dialogue: 0,0:57:37.56,0:57:39.44,EN,,0,0,0,,let's go and make this thing even more complex. Dialogue: 0,0:57:41.89,0:57:46.54,EN,,0,0,0,,Let's talk about adding to the system not only these kinds of numbers Dialogue: 0,0:57:46.60,0:57:51.15,EN,,0,0,0,,numbers, but it's also meaningful to start talking about adding polynomials. Dialogue: 0,0:57:51.51,0:57:52.97,EN,,0,0,0,,Might do arithmetic on polynomials. Dialogue: 0,0:57:53.36,0:58:03.71,EN,,0,0,0,,Like we could have x to the fifteenth plus 2x to the seventh plus 5. Dialogue: 0,0:58:04.48,0:58:05.84,EN,,0,0,0,,That might be some polynomial. Dialogue: 0,0:58:06.38,0:58:07.93,EN,,0,0,0,,And if we have two such gadgets Dialogue: 0,0:58:07.93,0:58:09.48,EN,,0,0,0,,we can add them or multiply them. Dialogue: 0,0:58:10.53,0:58:11.79,EN,,0,0,0,,Let's not worry about dividing them. Dialogue: 0,0:58:12.14,0:58:14.67,EN,,0,0,0,,Just add them, multiply them, then we'll subtract them. Dialogue: 0,0:58:15.55,0:58:17.16,EN,,0,0,0,,Auhhh...What do we have to do? Well Dialogue: 0,0:58:18.52,0:58:20.76,EN,,0,0,0,,let's think about how we might represent a polynomial. Dialogue: 0,0:58:21.83,0:58:23.55,EN,,0,0,0,,It's going to be some typed data object. Dialogue: 0,0:58:24.73,0:58:27.55,EN,,0,0,0,,So let's say a polynomial to this system Dialogue: 0,0:58:28.54,0:58:31.68,EN,,0,0,0,,might look like a thing that starts with the type polynomial. Dialogue: 0,0:58:32.00,0:58:34.55,EN,,0,0,0,,And then maybe it says the next thing is what variable its in. Dialogue: 0,0:58:34.55,0:58:37.69,EN,,0,0,0,,So I might say I'm a polynomial in the variable x. Dialogue: 0,0:58:38.96,0:58:41.39,EN,,0,0,0,,And then it'll have some information about what the terms are. Dialogue: 0,0:58:42.25,0:58:44.16,EN,,0,0,0,,And there're just tons of ways to do this, Dialogue: 0,0:58:44.25,0:58:47.63,EN,,0,0,0,,but one way is to say we're going to have a thing called a term-list. Dialogue: 0,0:58:51.52,0:58:52.24,EN,,0,0,0,,And a term-list-- Dialogue: 0,0:58:53.70,0:58:55.61,EN,,0,0,0,,well, in our case we'll use something that looks like this. Dialogue: 0,0:58:56.36,0:58:59.68,EN,,0,0,0,,We'll make it a bunch of pairs which have an order in a coefficient Dialogue: 0,0:58:59.69,0:59:05.80,EN,,0,0,0,,So this polynomial would be represented by this term-list. Dialogue: 0,0:59:09.42,0:59:10.68,EN,,0,0,0,,And what that means is that Dialogue: 0,0:59:11.48,0:59:19.71,EN,,0,0,0,,this polynomial starts off with a term of order 15 and coefficient 1. Dialogue: 0,0:59:23.82,0:59:27.50,EN,,0,0,0,,And the next thing in it is a term of order 7 and coefficient 2, Dialogue: 0,0:59:27.53,0:59:30.49,EN,,0,0,0,,a term of order 0, which is constant in coefficient 5 Dialogue: 0,0:59:31.45,0:59:34.16,EN,,0,0,0,,And there are lots and lots of ways, Dialogue: 0,0:59:34.25,0:59:35.96,EN,,0,0,0,,and lots and lots of trade-offs Dialogue: 0,0:59:36.01,0:59:39.10,EN,,0,0,0,,when you really think about making algebraic manipulation packages Dialogue: 0,0:59:39.44,0:59:41.73,EN,,0,0,0,,that exactly how you should represent these things. Dialogue: 0,0:59:42.01,0:59:43.68,EN,,0,0,0,,But this is a fairly standard one. Dialogue: 0,0:59:44.18,0:59:45.55,EN,,0,0,0,,It's useful in a lot of contexts. Dialogue: 0,0:59:47.77,0:59:50.99,EN,,0,0,0,,OK, well how do we implement our polynomial arithmetic? Dialogue: 0,0:59:53.47,0:59:54.96,EN,,0,0,0,,Let's start out. Dialogue: 0,0:59:57.95,1:00:00.28,EN,,0,0,0,,What we'll do to make a polynomial-- Dialogue: 0,1:00:00.76,1:00:04.12,EN,,0,0,0,,we'll first have a way to make polynomials. Dialogue: 0,1:00:05.69,1:00:10.28,EN,,0,0,0,,We're going to make a polynomial out of variable like x and term-list. Dialogue: 0,1:00:11.24,1:00:14.09,EN,,0,0,0,,And all that does is we'll package them together someway. Dialogue: 0,1:00:14.30,1:00:19.40,EN,,0,0,0,,We'll put the variable together with the term list using cons Dialogue: 0,1:00:19.82,1:00:21.74,EN,,0,0,0,,and then attached to that the type polynomial. Dialogue: 0,1:00:26.27,1:00:27.77,EN,,0,0,0,,OK, how do we add two polynomials? Dialogue: 0,1:00:29.28,1:00:31.85,EN,,0,0,0,,To add a polynomial, p1 and p2, Dialogue: 0,1:00:32.68,1:00:35.18,EN,,0,0,0,,and then just for simplicity let's say we Dialogue: 0,1:00:35.37,1:00:37.15,EN,,0,0,0,,we will only add things in the same variable. Dialogue: 0,1:00:37.38,1:00:39.28,EN,,0,0,0,,So if they have the same variable, Dialogue: 0,1:00:39.69,1:00:42.57,EN,,0,0,0,,and same variable here is going to be some selector we write, Dialogue: 0,1:00:42.96,1:00:44.38,EN,,0,0,0,,whose details we don't care about. Dialogue: 0,1:00:45.15,1:00:47.04,EN,,0,0,0,,If the two polynomials have the same variable, Dialogue: 0,1:00:48.03,1:00:48.81,EN,,0,0,0,,then we'll do something. Dialogue: 0,1:00:48.81,1:00:51.26,EN,,0,0,0,,If they don't have the same variable, we'll give an error, Dialogue: 0,1:00:52.35,1:00:54.01,EN,,0,0,0,,polynomials not in the same variable. Dialogue: 0,1:00:55.48,1:00:57.37,EN,,0,0,0,,And if they do have the same variable, Dialogue: 0,1:00:57.60,1:00:59.18,EN,,0,0,0,,what we'll do is we'll make a polynomial Dialogue: 0,1:00:59.80,1:01:01.85,EN,,0,0,0,,whose variable is whatever that variable is, Dialogue: 0,1:01:03.15,1:01:06.56,EN,,0,0,0,,and whose term-list is something we'll call sum-terms. Dialogue: 0,1:01:07.48,1:01:09.80,EN,,0,0,0,,Plus terms will add the two term lists. Dialogue: 0,1:01:10.17,1:01:12.01,EN,,0,0,0,,So we'll add the two term lists to the polynomial. Dialogue: 0,1:01:13.50,1:01:14.51,EN,,0,0,0,,That'll give us a term-list. Dialogue: 0,1:01:15.00,1:01:20.01,EN,,0,0,0,,We'll add on, we'll say it's a polynomial in the variable with that term-list. Dialogue: 0,1:01:20.68,1:01:21.79,EN,,0,0,0,,That's plus poly. Dialogue: 0,1:01:22.55,1:01:27.00,EN,,0,0,0,,And then we're going to put in our table under the type polynomial Dialogue: 0,1:01:28.24,1:01:30.14,EN,,0,0,0,,add them using plus poly. Dialogue: 0,1:01:30.52,1:01:31.75,EN,,0,0,0,,And of course we really haven't done much. Dialogue: 0,1:01:31.75,1:01:35.31,EN,,0,0,0,,What we've really done is pushed all the work onto this thing, +terms Dialogue: 0,1:01:35.79,1:01:37.02,EN,,0,0,0,,which is supposed to add term-lists. Dialogue: 0,1:01:37.74,1:01:39.16,EN,,0,0,0,,Let's look at that. Dialogue: 0,1:01:39.18,1:01:48.03,EN,,0,0,0,,Here's an overview of how we might add two term-lists. Dialogue: 0,1:01:48.90,1:01:51.74,EN,,0,0,0,,So L1 and L2 were going to be two term-lists. Dialogue: 0,1:01:52.00,1:01:54.81,EN,,0,0,0,,And a term-list is a bunch of pairs, coefficient in order. Dialogue: 0,1:01:55.70,1:01:56.95,EN,,0,0,0,,And it's a big case analysis. Dialogue: 0,1:01:59.86,1:02:04.14,EN,,0,0,0,,And the first thing we'll check for and see if there are any terms Dialogue: 0,1:02:05.39,1:02:07.55,EN,,0,0,0,,We're going to recursively work down these term-lists Dialogue: 0,1:02:08.16,1:02:11.74,EN,,0,0,0,,so eventually we'll get to a place where either L1 or L2 might be empty. Dialogue: 0,1:02:12.27,1:02:14.35,EN,,0,0,0,,And if either one is empty, Dialogue: 0,1:02:14.52,1:02:15.85,EN,,0,0,0,,our answer will be the other one. Dialogue: 0,1:02:15.85,1:02:19.55,EN,,0,0,0,,So if L1 is empty we'll return L2, Dialogue: 0,1:02:19.63,1:02:21.71,EN,,0,0,0,,and if L2 is empty we'll return L1. Dialogue: 0,1:02:23.26,1:02:25.76,EN,,0,0,0,,Otherwise there are sort of three interesting cases. Dialogue: 0,1:02:27.22,1:02:27.98,EN,,0,0,0,,What we're going to do is Dialogue: 0,1:02:29.08,1:02:31.05,EN,,0,0,0,,grab the first term in each of those lists, Dialogue: 0,1:02:33.50,1:02:36.04,EN,,0,0,0,,Right? Called t1 and t2. Dialogue: 0,1:02:37.66,1:02:39.05,EN,,0,0,0,,And we're going to look at three cases, Dialogue: 0,1:02:39.60,1:02:45.68,EN,,0,0,0,,depending on whether the order of t1 is greater than the order of t2, Dialogue: 0,1:02:47.23,1:02:50.59,EN,,0,0,0,,or less than t2, or the same. Dialogue: 0,1:02:53.28,1:02:54.91,EN,,0,0,0,,Those are the three cases we're going to look at. Dialogue: 0,1:02:54.91,1:02:55.84,EN,,0,0,0,,Let's look at this case. Dialogue: 0,1:02:58.64,1:03:01.31,EN,,0,0,0,,If the order of t1 is greater than the order of t2, Dialogue: 0,1:03:03.40,1:03:04.70,EN,,0,0,0,,then what that means is that Dialogue: 0,1:03:06.06,1:03:09.96,EN,,0,0,0,,then what that means is that our answer is going to start with this term of the order of t1. Dialogue: 0,1:03:11.56,1:03:13.80,EN,,0,0,0,,Because it won't combine with any lower order terms. Dialogue: 0,1:03:14.17,1:03:16.19,EN,,0,0,0,,So what we do is add the lower order terms. Dialogue: 0,1:03:16.76,1:03:18.25,EN,,0,0,0,,We recursively add Dialogue: 0,1:03:19.71,1:03:25.07,EN,,0,0,0,,together all the terms in the rest of the term-list in L1 and L2. Dialogue: 0,1:03:27.13,1:03:29.32,EN,,0,0,0,,That's going to be the lower order terms of the answer. Dialogue: 0,1:03:30.12,1:03:32.48,EN,,0,0,0,,And then we're going to adjoin to that the highest order term. Dialogue: 0,1:03:33.18,1:03:35.45,EN,,0,0,0,,And I'm using here a whole bunch of procedures I haven't defined Dialogue: 0,1:03:35.47,1:03:37.55,EN,,0,0,0,,like a adjoin-term, and rest-terms, Dialogue: 0,1:03:38.48,1:03:40.17,EN,,0,0,0,,and selectors that get order. Dialogue: 0,1:03:41.15,1:03:42.78,EN,,0,0,0,,But you can imagine what those are. Dialogue: 0,1:03:44.44,1:03:48.76,EN,,0,0,0,,Right? So if the first term-list has a higher order than the second Dialogue: 0,1:03:48.78,1:03:51.08,EN,,0,0,0,,we recursively add all the lower terms Dialogue: 0,1:03:51.28,1:03:53.42,EN,,0,0,0,,and then stick on that last term. Dialogue: 0,1:03:55.54,1:03:56.75,EN,,0,0,0,,The other case, the same way. Dialogue: 0,1:03:56.89,1:04:00.28,EN,,0,0,0,,If the first term has a smaller order, Dialogue: 0,1:04:00.54,1:04:08.36,EN,,0,0,0,,well then we add we add the first term-list and the rest of the terms in the second one Dialogue: 0,1:04:08.62,1:04:12.65,EN,,0,0,0,,and adjoin on this highest order term. Dialogue: 0,1:04:14.57,1:04:15.96,EN,,0,0,0,,So so far nothing's much happened, Dialogue: 0,1:04:15.96,1:04:19.40,EN,,0,0,0,,we've just sort of pushed this thing off into adding lower order terms. Dialogue: 0,1:04:19.47,1:04:21.96,EN,,0,0,0,,The last case where you actually get to a coefficients Dialogue: 0,1:04:22.57,1:04:25.18,EN,,0,0,0,,that you have to add, this will be the case where the orders are equal. Dialogue: 0,1:04:27.24,1:04:30.99,EN,,0,0,0,,What we do is, well again recursively add the lower order terms. Dialogue: 0,1:04:31.00,1:04:32.83,EN,,0,0,0,,But now we have to really combine something. Dialogue: 0,1:04:33.46,1:04:36.35,EN,,0,0,0,,What we do is we make a term Dialogue: 0,1:04:37.31,1:04:39.93,EN,,0,0,0,,whose order is the order of the term we're looking at. Dialogue: 0,1:04:40.82,1:04:42.72,EN,,0,0,0,,By now t1 and t2 have the same order. Dialogue: 0,1:04:44.32,1:04:44.99,EN,,0,0,0,,That's its order. Dialogue: 0,1:04:45.09,1:04:52.33,EN,,0,0,0,,And its coefficient is gotten by adding the coefficient of t1 and the coefficient of t2. Dialogue: 0,1:04:55.79,1:04:59.64,EN,,0,0,0,,There's... This is a big recursive working down of terms, Dialogue: 0,1:04:59.68,1:05:03.61,EN,,0,0,0,,but really there's only one interesting symbol in this procedure, Dialogue: 0,1:05:04.25,1:05:05.69,EN,,0,0,0,,only one interesting idea. Dialogue: 0,1:05:05.90,1:05:08.50,EN,,0,0,0,,The interesting idea is this add. Dialogue: 0,1:05:12.39,1:05:14.80,EN,,0,0,0,,And the reason that's interesting is because Dialogue: 0,1:05:15.42,1:05:17.37,EN,,0,0,0,,something completely wonderful just happened. Dialogue: 0,1:05:18.22,1:05:21.37,EN,,0,0,0,,We reduced adding polynomials, Dialogue: 0,1:05:22.56,1:05:26.46,EN,,0,0,0,,not to sort of plus, but to the generic add. Dialogue: 0,1:05:28.82,1:05:32.28,EN,,0,0,0,,In other words, by implementing it that way, Dialogue: 0,1:05:32.89,1:05:34.68,EN,,0,0,0,,not only do we have our system Dialogue: 0,1:05:35.92,1:05:41.66,EN,,0,0,0,,where we can have rational numbers, or complex numbers, or ordinary numbers, Dialogue: 0,1:05:41.85,1:05:43.82,EN,,0,0,0,,we've just added on polynomials. Dialogue: 0,1:05:48.52,1:05:51.13,EN,,0,0,0,,But the coefficients of the polynomials Dialogue: 0,1:05:51.24,1:05:52.86,EN,,0,0,0,,can be anything that the system can add. Dialogue: 0,1:05:53.59,1:05:56.73,EN,,0,0,0,,So these could be polynomials whose coefficient Dialogue: 0,1:05:57.20,1:06:01.20,EN,,0,0,0,,are rational numbers or complex numbers, Dialogue: 0,1:06:02.76,1:06:06.99,EN,,0,0,0,,which in turn could be either rectangular, or polar, Dialogue: 0,1:06:09.12,1:06:11.39,EN,,0,0,0,,or ordinary numbers. Dialogue: 0,1:06:18.97,1:06:21.21,EN,,0,0,0,,Rignt? So what I mean precisely is Dialogue: 0,1:06:22.06,1:06:24.35,EN,,0,0,0,,our system right now automatically Dialogue: 0,1:06:26.60,1:06:31.50,EN,,0,0,0,,can handle things like adding together polynomials that have this form Dialogue: 0,1:06:31.53,1:06:39.69,EN,,0,0,0,,2/3 of x squared plus 5/17 x plus 11/4. Dialogue: 0,1:06:40.94,1:06:43.48,EN,,0,0,0,,Or automatically handle polynomials that look like Dialogue: 0,1:06:43.82,1:06:52.57,EN,,0,0,0,,3 plus 2i times x to the fifth plus 4 plus 7i, or something. Dialogue: 0,1:06:53.88,1:06:56.21,EN,,0,0,0,,Right? You can automatically handle those things. Dialogue: 0,1:06:56.21,1:06:57.07,EN,,0,0,0,,Why is that? Dialogue: 0,1:06:57.82,1:07:01.50,EN,,0,0,0,,That's merely because, or profoundly because Dialogue: 0,1:07:02.17,1:07:05.93,EN,,0,0,0,,we reduced adding polynomials to adding their coefficients. Dialogue: 0,1:07:06.79,1:07:10.22,EN,,0,0,0,,And adding coefficients was done by the generic add operator Dialogue: 0,1:07:11.08,1:07:12.94,EN,,0,0,0,,which said, I don't care what your types are Dialogue: 0,1:07:12.96,1:07:14.08,EN,,0,0,0,,as long as I know how to add you. Dialogue: 0,1:07:15.23,1:07:18.86,EN,,0,0,0,,So automatically for free we get the ability to handle that. Dialogue: 0,1:07:20.65,1:07:22.04,EN,,0,0,0,,What's even better than that, Dialogue: 0,1:07:24.51,1:07:26.52,EN,,0,0,0,,one of the things we did Dialogue: 0,1:07:27.20,1:07:30.52,EN,,0,0,0,,we put into the table that the way you add polynomials Dialogue: 0,1:07:31.28,1:07:32.52,EN,,0,0,0,,is using plus poly. Dialogue: 0,1:07:34.66,1:07:38.65,EN,,0,0,0,,That means that polynomials themselves are things that can be added. Dialogue: 0,1:07:39.42,1:07:42.11,EN,,0,0,0,,So for instance let me write one here. Dialogue: 0,1:07:43.18,1:07:46.19,EN,,0,0,0,,Here is... Here's a polynomial. Dialogue: 0,1:07:50.56,1:07:52.41,EN,,0,0,0,,So this gadget here I'm writing up, Dialogue: 0,1:07:54.12,1:07:58.46,EN,,0,0,0,,this is a polynomial in y Dialogue: 0,1:08:01.07,1:08:04.69,EN,,0,0,0,,whose coefficients are polynomials in x. Dialogue: 0,1:08:08.61,1:08:11.12,EN,,0,0,0,,So you see, simply by saying, Dialogue: 0,1:08:11.76,1:08:14.06,EN,,0,0,0,,polynomials are themselves things that can be added, Dialogue: 0,1:08:14.41,1:08:17.90,EN,,0,0,0,,we can go off and say, well not only can we deal with rationals, Dialogue: 0,1:08:18.27,1:08:20.33,EN,,0,0,0,,or complex, or ordinary numbers, Dialogue: 0,1:08:20.35,1:08:21.77,EN,,0,0,0,,but we can deal with polynomials Dialogue: 0,1:08:22.09,1:08:25.39,EN,,0,0,0,,whose coefficients are rationals, or complex, or ordinary numbers, Dialogue: 0,1:08:25.50,1:08:27.52,EN,,0,0,0,,or polynomials Dialogue: 0,1:08:29.15,1:08:30.96,EN,,0,0,0,,whose coefficients are rationals, Dialogue: 0,1:08:31.69,1:08:36.76,EN,,0,0,0,,or complex, rectangular, polar, or ordinary numbers, Dialogue: 0,1:08:36.94,1:08:41.13,EN,,0,0,0,,or ordinary numbers, or polynomials whose coefficients are rationals, Dialogue: 0,1:08:41.80,1:08:43.32,EN,,0,0,0,,complex, or ordinary numbers. Dialogue: 0,1:08:43.67,1:08:45.21,EN,,0,0,0,,And so on, and so on, and so on. Dialogue: 0,1:08:45.95,1:08:47.55,EN,,0,0,0,,So this is sort of an infinite Dialogue: 0,1:08:48.49,1:08:52.88,EN,,0,0,0,,or maybe a recursive tower of types that we've built up. Dialogue: 0,1:08:53.88,1:08:57.12,EN,,0,0,0,,And it's all exactly from that one little symbol, A-D-D. Dialogue: 0,1:08:57.61,1:09:00.49,EN,,0,0,0,,Writing "add" instead of "plus" in the polynomial thing. Dialogue: 0,1:09:02.27,1:09:03.77,EN,,0,0,0,,Slightly different way to think about it Dialogue: 0,1:09:03.95,1:09:07.74,EN,,0,0,0,,is that polynomials are a constructor for types. Dialogue: 0,1:09:08.74,1:09:11.20,EN,,0,0,0,,Namely you give it a type, like integer, Dialogue: 0,1:09:11.48,1:09:15.74,EN,,0,0,0,,and it returns for you polynomials in x whose coefficients are integers. Dialogue: 0,1:09:16.27,1:09:17.72,EN,,0,0,0,,And the important thing about Dialogue: 0,1:09:18.65,1:09:20.73,EN,,0,0,0,,is that is that the operations on polynomials Dialogue: 0,1:09:21.28,1:09:23.37,EN,,0,0,0,,reduce to the operations on the coefficients. Dialogue: 0,1:09:23.39,1:09:24.96,EN,,0,0,0,,And there are a lot of things like that. Dialogue: 0,1:09:25.84,1:09:27.92,EN,,0,0,0,,So for example, let's go back and rational numbers. Dialogue: 0,1:09:28.87,1:09:32.65,EN,,0,0,0,,We thought about rational numbers as an integer over an integer Dialogue: 0,1:09:32.67,1:09:35.66,EN,,0,0,0,,but there's the general notion of a rational object. Dialogue: 0,1:09:36.24,1:09:42.03,EN,,0,0,0,,Like we might think about 3x plus 7 over x squared plus 1. Dialogue: 0,1:09:43.07,1:09:48.86,EN,,0,0,0,,That's general rational object whose numerator and denominator are polynomials. Dialogue: 0,1:09:50.31,1:09:52.41,EN,,0,0,0,,And to add two of them we use the same formula, Dialogue: 0,1:09:52.44,1:09:55.40,EN,,0,0,0,,numerator times denominator plus denominator times numerator Dialogue: 0,1:09:55.72,1:09:56.99,EN,,0,0,0,,over product of denominators. Dialogue: 0,1:09:57.29,1:09:59.37,EN,,0,0,0,,How could we install that in our system? Dialogue: 0,1:09:59.39,1:10:02.97,EN,,0,0,0,,Well here's our original rational number arithmetic package. Dialogue: 0,1:10:04.25,1:10:08.24,EN,,0,0,0,,And all we have to do in order to make the entire system Dialogue: 0,1:10:08.28,1:10:11.58,EN,,0,0,0,,continue working with general rational objects, Dialogue: 0,1:10:11.85,1:10:16.44,EN,,0,0,0,,is replace these particular pluses and stars by the generic operator. Dialogue: 0,1:10:16.48,1:10:19.18,EN,,0,0,0,,So if we simply change that procedure to this one, Dialogue: 0,1:10:19.71,1:10:22.04,EN,,0,0,0,,here we've changed plus and star to add a mul, Dialogue: 0,1:10:22.88,1:10:24.48,EN,,0,0,0,,those are absolutely the only change, Dialogue: 0,1:10:24.84,1:10:26.03,EN,,0,0,0,,then suddenly Dialogue: 0,1:10:27.52,1:10:31.40,EN,,0,0,0,,our entire system can start talking about objects that look like this. Dialogue: 0,1:10:33.72,1:10:38.27,EN,,0,0,0,,So for example, here is a rational object Dialogue: 0,1:10:39.18,1:10:44.86,EN,,0,0,0,,whose numerator is a polynomial in x whose coefficients are rational numbers. Dialogue: 0,1:10:47.02,1:10:49.56,EN,,0,0,0,,Or here is a rational object Dialogue: 0,1:10:51.10,1:10:54.43,EN,,0,0,0,,whose numerator is polynomials in x Dialogue: 0,1:10:55.15,1:10:58.19,EN,,0,0,0,,whose coefficients are rational objects Dialogue: 0,1:10:59.77,1:11:01.53,EN,,0,0,0,,constructed out of complex numbers. Dialogue: 0,1:11:03.39,1:11:04.85,EN,,0,0,0,,And then there are a lot of other things like that. Dialogue: 0,1:11:04.85,1:11:08.68,EN,,0,0,0,,See, whenever you have a thing where the operations reduce to operations on the pieces, Dialogue: 0,1:11:08.89,1:11:10.00,EN,,0,0,0,,another example would be Dialogue: 0,1:11:10.28,1:11:11.42,EN,,0,0,0,,two by two matrices. Dialogue: 0,1:11:12.31,1:11:15.44,EN,,0,0,0,,I have the idea, there might be a matrix here Dialogue: 0,1:11:16.43,1:11:18.33,EN,,0,0,0,,of general things that I don't care about. Dialogue: 0,1:11:18.72,1:11:20.14,EN,,0,0,0,,But if I add two of them, Dialogue: 0,1:11:22.33,1:11:25.18,EN,,0,0,0,,the answer over here is gotten by Dialogue: 0,1:11:25.18,1:11:28.14,EN,,0,0,0,,adding this one and that one,however they like to add. Dialogue: 0,1:11:29.03,1:11:31.11,EN,,0,0,0,,So I can implement that the same way. Dialogue: 0,1:11:31.11,1:11:31.71,EN,,0,0,0,,And if I do that, Dialogue: 0,1:11:31.96,1:11:34.60,EN,,0,0,0,,then again suddenly my system can start handling things like this. Dialogue: 0,1:11:35.29,1:11:39.18,EN,,0,0,0,,So here's a matrix whose elements happen to be-- Dialogue: 0,1:11:39.46,1:11:42.16,EN,,0,0,0,,we'll say this element here is a rational object Dialogue: 0,1:11:43.10,1:11:45.15,EN,,0,0,0,,whose numerator and denominators are polynomials. Dialogue: 0,1:11:47.02,1:11:49.56,EN,,0,0,0,,Right? And all that comes for free. Dialogue: 0,1:11:51.28,1:11:53.82,EN,,0,0,0,,Right? What's really going on here? Dialogue: 0,1:11:53.92,1:11:56.17,EN,,0,0,0,,What's really going on is Dialogue: 0,1:11:57.68,1:12:02.44,EN,,0,0,0,,getting rid of who's sitting there poking his nose into who everybody's business is. Dialogue: 0,1:12:03.12,1:12:06.19,EN,,0,0,0,,We built a system that has decentralized control. Dialogue: 0,1:12:14.78,1:12:18.34,EN,,0,0,0,,So when you come into and no one's poking around saying, Dialogue: 0,1:12:18.35,1:12:22.30,EN,,0,0,0,,gee, are you in the official list of people who can be added? Dialogue: 0,1:12:22.44,1:12:26.22,EN,,0,0,0,,Rather you say, well go off and add yourself how your parts like to be added. Dialogue: 0,1:12:27.81,1:12:31.03,EN,,0,0,0,,And the result of that is you can get this very, very, very Dialogue: 0,1:12:31.03,1:12:33.87,EN,,0,0,0,,complex hierarchy where a lot of things just get done and Dialogue: 0,1:12:33.87,1:12:35.55,EN,,0,0,0,,rooted to the right place automatically. Dialogue: 0,1:12:37.00,1:12:37.79,EN,,0,0,0,,Let's stop for questions. Dialogue: 0,1:12:40.38,1:12:42.32,EN,,0,0,0,,AUDIENCE: You say you get this for free. Dialogue: 0,1:12:42.35,1:12:45.82,EN,,0,0,0,,Um..... One thing that strikes me is that now you've lost Dialogue: 0,1:12:46.48,1:12:50.91,EN,,0,0,0,,kind of the cleanness of the break between what's on top and what's underneath. Dialogue: 0,1:12:50.91,1:12:52.77,EN,,0,0,0,,In other words, now you're defining some of the Dialogue: 0,1:12:52.77,1:12:56.08,EN,,0,0,0,,lower-level procedures in terms of things above their own line. Dialogue: 0,1:12:56.61,1:12:59.45,EN,,0,0,0,,Isn't that dangerous? Dialogue: 0,1:13:00.35,1:13:04.49,EN,,0,0,0,,Or, if nothing more, a little less structured? Dialogue: 0,1:13:05.44,1:13:05.95,EN,,0,0,0,,PROFESSOR: No, I-- Dialogue: 0,1:13:06.41,1:13:07.77,EN,,0,0,0,,the question is whether that's less structured. Dialogue: 0,1:13:07.77,1:13:08.69,EN,,0,0,0,,Depends on what you mean by structure. Dialogue: 0,1:13:08.69,1:13:10.17,EN,,0,0,0,,All this is doing is recursion. Dialogue: 0,1:13:11.05,1:13:18.80,EN,,0,0,0,,See, it's saying that the way you add these guys is to use that. Dialogue: 0,1:13:19.15,1:13:21.37,EN,,0,0,0,,And that's not less structured, it's just a recursive structure. Dialogue: 0,1:13:22.70,1:13:24.99,EN,,0,0,0,,So I don't think it's particularly any less clean. Dialogue: 0,1:13:24.99,1:13:28.16,EN,,0,0,0,,AUDIENCE: Now when you want to change the multiplier or the add operator Dialogue: 0,1:13:29.34,1:13:31.38,EN,,0,0,0,,suddenly you've got tremendous consequences Dialogue: 0,1:13:31.38,1:13:34.27,EN,,0,0,0,,underneath that you're not even sure the extent of. Dialogue: 0,1:13:34.48,1:13:36.44,EN,,0,0,0,,PROFESSOR: That's right, but it depends what you mean. Dialogue: 0,1:13:37.08,1:13:38.47,EN,,0,0,0,,See, this goes both ways. Dialogue: 0,1:13:39.10,1:13:43.24,EN,,0,0,0,,Um....What would be a good example? Dialogue: 0,1:13:44.69,1:13:47.50,EN,,0,0,0,,I ignored greatest common divisor, for instance. Dialogue: 0,1:13:47.77,1:13:50.08,EN,,0,0,0,,I ignored that problem just to keep the example simple. Dialogue: 0,1:13:50.28,1:13:56.92,EN,,0,0,0,,But if I suddenly decided that plus rat here Dialogue: 0,1:13:57.82,1:14:01.69,EN,,0,0,0,,should do a GCD computation and install that, Dialogue: 0,1:14:03.34,1:14:07.87,EN,,0,0,0,,then that immediately becomes available to all of these, to that guy, and that guy, Dialogue: 0,1:14:08.03,1:14:10.08,EN,,0,0,0,,and that guy, and all the way down. Dialogue: 0,1:14:11.56,1:14:13.89,EN,,0,0,0,,So it depends what you mean by the coherence of your system. Dialogue: 0,1:14:13.89,1:14:17.03,EN,,0,0,0,,It's certainly true that you might want to have a special Dialogue: 0,1:14:17.03,1:14:19.56,EN,,0,0,0,,different one that didn't filter down through the coefficients Dialogue: 0,1:14:19.61,1:14:22.97,EN,,0,0,0,,but the nice thing about this particular example is that mostly you do. Dialogue: 0,1:14:25.44,1:14:27.63,EN,,0,0,0,,AUDIENCE: Isn't that the problem, I think, that you're Dialogue: 0,1:14:27.63,1:14:32.95,EN,,0,0,0,,getting to tied in with the fact that the structuring, the Dialogue: 0,1:14:32.95,1:14:36.33,EN,,0,0,0,,recursiveness of that structuring there is actually Dialogue: 0,1:14:36.33,1:14:40.34,EN,,0,0,0,,in execution as opposed to just definition of the actual Dialogue: 0,1:14:40.34,1:14:41.16,EN,,0,0,0,,types themselves? Dialogue: 0,1:14:44.68,1:14:46.12,EN,,0,0,0,,PROFESSOR: I think I understand the question. Dialogue: 0,1:14:46.12,1:14:47.80,EN,,0,0,0,,The point is that these types evolve Dialogue: 0,1:14:47.82,1:14:50.40,EN,,0,0,0,,and get more and more complex as the thing's actually running. Dialogue: 0,1:14:50.40,1:14:50.73,EN,,0,0,0,,Is that what-- Dialogue: 0,1:14:50.73,1:14:50.99,EN,,0,0,0,,AUDIENCE: Yap. Dialogue: 0,1:14:50.99,1:14:51.79,EN,,0,0,0,,As it's running. Dialogue: 0,1:14:52.09,1:14:54.18,EN,,0,0,0,,AUDIENCE: As opposed to the basic definitions. Dialogue: 0,1:14:54.18,1:14:54.83,EN,,0,0,0,,PROFESSOR: Right. There's... Dialogue: 0,1:14:54.83,1:14:56.70,EN,,0,0,0,,The type structure is sort of recursive. Dialogue: 0,1:14:57.21,1:15:00.22,EN,,0,0,0,,It's not that you can make this finite list of the Dialogue: 0,1:15:01.58,1:15:04.85,EN,,0,0,0,,actual things they might look like before the system runs. Dialogue: 0,1:15:04.85,1:15:05.79,EN,,0,0,0,,It's something that evolves. Dialogue: 0,1:15:06.78,1:15:08.64,EN,,0,0,0,,So if you want to specify that system, Dialogue: 0,1:15:08.67,1:15:10.96,EN,,0,0,0,,you have to do in some other way than by this finite list. Dialogue: 0,1:15:11.00,1:15:13.18,EN,,0,0,0,,You have to do it by a recursive structure. Dialogue: 0,1:15:13.67,1:15:17.90,EN,,0,0,0,,AUDIENCE: Because the basic structure of the types is pretty clean and simple. Dialogue: 0,1:15:17.90,1:15:18.19,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,1:15:20.40,1:15:20.75,EN,,0,0,0,,Yes? Dialogue: 0,1:15:21.46,1:15:22.87,EN,,0,0,0,,AUDIENCE: I have a question. Dialogue: 0,1:15:22.87,1:15:25.68,EN,,0,0,0,,I understand once you have your data structure set up, Dialogue: 0,1:15:25.71,1:15:28.73,EN,,0,0,0,,how it pulls off complex and passes that down, Dialogue: 0,1:15:28.73,1:15:30.64,EN,,0,0,0,,and then pulls off rect, passes that down. Dialogue: 0,1:15:30.64,1:15:33.95,EN,,0,0,0,,But if you're just a user and you don't know anything about rect or polar or whatever, Dialogue: 0,1:15:34.25,1:15:36.04,EN,,0,0,0,,how do you initially set up that data structure Dialogue: 0,1:15:36.09,1:15:38.08,EN,,0,0,0,,so that everything goes to the right spot? Dialogue: 0,1:15:38.09,1:15:41.00,EN,,0,0,0,,If I just have the equation over there on the left Dialogue: 0,1:15:41.02,1:15:42.50,EN,,0,0,0,,And I just want to add, multiply complex numbers-- Dialogue: 0,1:15:42.50,1:15:43.64,EN,,0,0,0,,PROFESSOR: Well that's the wonderful thing. Dialogue: 0,1:15:43.64,1:15:45.26,EN,,0,0,0,,If you're just a user you say "mul." Dialogue: 0,1:15:47.73,1:15:49.95,EN,,0,0,0,,AUDIENCE: And it figures out that I mean complex numbers? Dialogue: 0,1:15:49.96,1:15:51.23,EN,,0,0,0,,Or how do I tell it that I want-- Dialogue: 0,1:15:51.26,1:15:53.05,EN,,0,0,0,,PROFESSOR: Well you're going to have in your hands complex numbers. Dialogue: 0,1:15:53.05,1:15:56.30,EN,,0,0,0,,See what you would have at some level, as a real user, Dialogue: 0,1:15:56.32,1:15:58.14,EN,,0,0,0,,is a constructor for complex numbers. Dialogue: 0,1:15:58.37,1:15:59.55,EN,,0,0,0,,AUDIENCE: So then I have to make complex numbers? Dialogue: 0,1:15:59.56,1:16:00.35,EN,,0,0,0,,PROFESSOR: So you have to make them. Dialogue: 0,1:16:00.35,1:16:04.01,EN,,0,0,0,,What you would probably have as a user is some little thing in the reader loop, Dialogue: 0,1:16:04.65,1:16:07.56,EN,,0,0,0,,which would give you some plausible way Dialogue: 0,1:16:07.56,1:16:08.86,EN,,0,0,0,,to type in a complex number, Dialogue: 0,1:16:09.31,1:16:11.00,EN,,0,0,0,,in however whatever format you like. Dialogue: 0,1:16:11.59,1:16:14.36,EN,,0,0,0,,Or it might be that you're never typing them in. Dialogue: 0,1:16:14.36,1:16:16.17,EN,,0,0,0,,Someone's just handing you a complex number. Dialogue: 0,1:16:16.78,1:16:19.82,EN,,0,0,0,,AUDIENCE: OK, so if I had a complex number that had a polynomial in it, Dialogue: 0,1:16:19.82,1:16:21.96,EN,,0,0,0,,I'd have to make my polynomial and then make my complex number. Dialogue: 0,1:16:21.96,1:16:23.96,EN,,0,0,0,,PROFESSOR: Right if you wanted it constructed from scratch. Dialogue: 0,1:16:24.28,1:16:25.71,EN,,0,0,0,,At some point you construct them from scratch. Dialogue: 0,1:16:25.71,1:16:27.05,EN,,0,0,0,,But what you don't have to know of that Dialogue: 0,1:16:27.28,1:16:30.32,EN,,0,0,0,,is when you have the object you can just say "mul." And it'll multiply. Dialogue: 0,1:16:32.78,1:16:32.99,EN,,0,0,0,,Yeah? Dialogue: 0,1:16:33.27,1:16:35.76,EN,,0,0,0,,AUDIENCE: I think the question that was being posed here is, Dialogue: 0,1:16:36.45,1:16:40.01,EN,,0,0,0,,say if I want to change my presentation of complexes, Dialogue: 0,1:16:40.03,1:16:41.44,EN,,0,0,0,,or some operation of complex, Dialogue: 0,1:16:41.52,1:16:47.10,EN,,0,0,0,,how much real code I will have to gets around with, Dialogue: 0,1:16:47.15,1:16:51.26,EN,,0,0,0,,or change to change it in one specific operation? Dialogue: 0,1:16:52.27,1:16:53.49,EN,,0,0,0,,PROFESSOR: [UNINTELLIGIBLE] what you have to change. Dialogue: 0,1:16:53.49,1:16:54.99,EN,,0,0,0,,And the point is that you only have to change Dialogue: 0,1:16:55.39,1:16:56.07,EN,,0,0,0,,what you're changing. Dialogue: 0,1:16:56.07,1:17:00.04,EN,,0,0,0,,See if Martha decides that she would rather-- Dialogue: 0,1:17:00.32,1:17:01.23,EN,,0,0,0,,let's see something silly-- Dialogue: 0,1:17:01.44,1:17:02.91,EN,,0,0,0,,like change the order in the pair. Dialogue: 0,1:17:04.04,1:17:08.72,EN,,0,0,0,,Like angle and magnitude in the other order, Dialogue: 0,1:17:09.39,1:17:10.80,EN,,0,0,0,,she just makes that change locally. Dialogue: 0,1:17:10.97,1:17:13.29,EN,,0,0,0,,And the whole thing will propagate through the system in the right way. Dialogue: 0,1:17:14.79,1:17:18.76,EN,,0,0,0,,Or if suddenly you said, gee, I have another representation for rationals. Dialogue: 0,1:17:19.70,1:17:23.90,EN,,0,0,0,,And I'm going to stick it here, by filing those operations in the table. Dialogue: 0,1:17:24.82,1:17:27.22,EN,,0,0,0,,Then suddenly all of these polynomials whose coefficients Dialogue: 0,1:17:27.22,1:17:29.10,EN,,0,0,0,,are coefficients of coefficients, or whatever, Dialogue: 0,1:17:29.24,1:17:32.40,EN,,0,0,0,,also can automatically have available that representation. Dialogue: 0,1:17:32.70,1:17:34.67,EN,,0,0,0,,That's the power of this particular one. Dialogue: 0,1:17:36.11,1:17:38.70,EN,,0,0,0,,AUDIENCE: I'm not sure if I can even pose an intelligent sounding question. Dialogue: 0,1:17:38.70,1:17:42.38,EN,,0,0,0,,But somehow this whole thing went really nicely Dialogue: 0,1:17:42.54,1:17:45.88,EN,,0,0,0,,to this beautiful finish where all the things seemed to fall into place. Dialogue: 0,1:17:46.72,1:17:48.67,EN,,0,0,0,,And sort of seemed a little contrived. Dialogue: 0,1:17:50.93,1:17:52.52,EN,,0,0,0,,That's all for the sake, I'm sure, of teaching. Dialogue: 0,1:17:52.56,1:17:54.65,EN,,0,0,0,,I doubt that the guys who first did this-- Dialogue: 0,1:17:55.10,1:17:55.85,EN,,0,0,0,,and I could be wrong-- Dialogue: 0,1:17:56.60,1:17:59.72,EN,,0,0,0,,figured it all out so that when they just all put it all together, Dialogue: 0,1:17:59.77,1:18:03.93,EN,,0,0,0,,you could all of the sudden, blam, do any kind of arithmetic on any kind of object. Dialogue: 0,1:18:04.86,1:18:07.20,EN,,0,0,0,,It seems like maybe they had to play with it for a while Dialogue: 0,1:18:07.93,1:18:10.62,EN,,0,0,0,,and had to bash it and rework it. Dialogue: 0,1:18:11.80,1:18:14.12,EN,,0,0,0,,And it seems like that's the kind of problem we're really Dialogue: 0,1:18:14.12,1:18:16.94,EN,,0,0,0,,faced with we start trying to design a really complex system Dialogue: 0,1:18:17.31,1:18:20.35,EN,,0,0,0,,is having lots of different kinds of parts and not even knowing Dialogue: 0,1:18:21.08,1:18:24.62,EN,,0,0,0,,what kinds of operations we're going to want to do on those parts. Dialogue: 0,1:18:24.62,1:18:26.54,EN,,0,0,0,,How to organize the operations in this nice way Dialogue: 0,1:18:26.56,1:18:29.63,EN,,0,0,0,,so that no matter what you do, when you start putting them together Dialogue: 0,1:18:29.63,1:18:31.39,EN,,0,0,0,,everything starts falling out for free. Dialogue: 0,1:18:31.70,1:18:34.34,EN,,0,0,0,,PROFESSOR: OK, well that's certainly a very intelligent question... Um Dialogue: 0,1:18:35.10,1:18:39.52,EN,,0,0,0,,Um....One part is this is a very good methodology Dialogue: 0,1:18:39.87,1:18:43.88,EN,,0,0,0,,that people have discovered a lot coming from symbolic algebra. Dialogue: 0,1:18:44.59,1:18:45.90,EN,,0,0,0,,Because there are a lot of complications. Dialogue: 0,1:18:47.59,1:18:50.71,EN,,0,0,0,,To allow you to implement these things before you decide Dialogue: 0,1:18:50.71,1:18:52.89,EN,,0,0,0,,what you want all the operations to be, and all of that. Dialogue: 0,1:18:53.31,1:18:57.72,EN,,0,0,0,,So in some sense it's an answer that people have discovered by wading through this stuff. Dialogue: 0,1:18:58.56,1:19:00.75,EN,,0,0,0,,In another sense, it is a very contrived example. Dialogue: 0,1:19:02.16,1:19:06.24,EN,,0,0,0,,AUDIENCE: It seems like to be able to do this you do have to Dialogue: 0,1:19:06.24,1:19:09.01,EN,,0,0,0,,wade through it for a certain amount of time before you can become good at it. Dialogue: 0,1:19:09.01,1:19:11.88,EN,,0,0,0,,PROFESSOR: Let me show you how terribly contrived this is. Dialogue: 0,1:19:12.22,1:19:14.13,EN,,0,0,0,,So you can write all these wonderful things. Dialogue: 0,1:19:14.13,1:19:16.25,EN,,0,0,0,,But the system that I wrote here, Dialogue: 0,1:19:17.02,1:19:18.96,EN,,0,0,0,,and if we had another half an hour to give this lecture Dialogue: 0,1:19:19.31,1:19:20.46,EN,,0,0,0,,I would have given this part of it, Dialogue: 0,1:19:20.81,1:19:23.02,EN,,0,0,0,,which says, notice that it breaks down Dialogue: 0,1:19:23.20,1:19:29.31,EN,,0,0,0,,if I tell it to do something as foolish as add 3 plus 7/2. Dialogue: 0,1:19:30.88,1:19:33.42,EN,,0,0,0,,Because what will happen is you'll get to operate-2, Dialogue: 0,1:19:33.80,1:19:35.95,EN,,0,0,0,,and operate-2 will say, oh this is type number, Dialogue: 0,1:19:36.18,1:19:37.37,EN,,0,0,0,,and that's type rational. Dialogue: 0,1:19:37.56,1:19:38.81,EN,,0,0,0,,I don't know how to add them. Dialogue: 0,1:19:41.53,1:19:44.30,EN,,0,0,0,,So you'd like the system at least to be able to say something like, Dialogue: 0,1:19:45.88,1:19:47.34,EN,,0,0,0,,gee,before you do that Dialogue: 0,1:19:48.59,1:19:50.24,EN,,0,0,0,,change that to 3/1. Dialogue: 0,1:19:50.48,1:19:53.21,EN,,0,0,0,,Turn it into a rational number, hand that to the rational package. Dialogue: 0,1:19:54.86,1:19:58.70,EN,,0,0,0,,That's the thing I didn't talk about in this lecture. Dialogue: 0,1:19:58.73,1:20:00.88,EN,,0,0,0,,It's a little bit in the book,which talks about the problem Dialogue: 0,1:20:00.88,1:20:01.95,EN,,0,0,0,,of what's called coercion. Dialogue: 0,1:20:03.39,1:20:05.15,EN,,0,0,0,,Where you wanted-- Dialogue: 0,1:20:05.31,1:20:08.89,EN,,0,0,0,,see, having so carefully set up all of these types as distinct objects Dialogue: 0,1:20:08.91,1:20:12.17,EN,,0,0,0,,a lot of times you want to also put in knowledge Dialogue: 0,1:20:12.40,1:20:17.98,EN,,0,0,0,,about how to view an ordinary number as a kind of rational. Dialogue: 0,1:20:19.11,1:20:21.29,EN,,0,0,0,,Or view an ordinary number as a kind of complex. Dialogue: 0,1:20:21.62,1:20:25.16,EN,,0,0,0,,That's where the complexity in the system really starts happening Dialogue: 0,1:20:25.76,1:20:28.12,EN,,0,0,0,,where you talk about, see where do I put that knowledge? Dialogue: 0,1:20:28.42,1:20:32.19,EN,,0,0,0,,Is it rational to know that ordinary numbers might be pieces of cons of them? Dialogue: 0,1:20:33.13,1:20:36.38,EN,,0,0,0,,Or they're terrible, terrible examples, like Dialogue: 0,1:20:38.14,1:20:47.48,EN,,0,0,0,,if I might want to add a complex number to a rational number. Dialogue: 0,1:20:49.87,1:20:50.76,EN,,0,0,0,,Bad example. Dialogue: 0,1:20:50.76,1:20:51.58,EN,,0,0,0,,5/7. Dialogue: 0,1:20:53.86,1:20:55.72,EN,,0,0,0,,Then somebody's got to know that Dialogue: 0,1:20:56.06,1:20:58.16,EN,,0,0,0,,I have to convert these to another type, Dialogue: 0,1:20:58.20,1:21:00.65,EN,,0,0,0,,which is complex numbers whose parts might be rationals. Dialogue: 0,1:21:01.54,1:21:02.68,EN,,0,0,0,,And who worries about that? Dialogue: 0,1:21:02.68,1:21:03.95,EN,,0,0,0,,Does complex worry about that? Dialogue: 0,1:21:03.95,1:21:05.03,EN,,0,0,0,,Does rational worry about that? Dialogue: 0,1:21:05.24,1:21:06.22,EN,,0,0,0,,Does plus worry about that? Dialogue: 0,1:21:06.90,1:21:08.52,EN,,0,0,0,,That's where the real complexity comes in. Dialogue: 0,1:21:08.52,1:21:11.38,EN,,0,0,0,,And that's where it's pretty well sorted out. Dialogue: 0,1:21:11.38,1:21:14.12,EN,,0,0,0,,And a lot of, in fact, all of this message passing stuff Dialogue: 0,1:21:14.64,1:21:16.54,EN,,0,0,0,,was motivated by problems like this. Dialogue: 0,1:21:18.46,1:21:20.89,EN,,0,0,0,,And when you really push it, people are-- Dialogue: 0,1:21:20.91,1:21:24.76,EN,,0,0,0,,somehow the algebraic manipulation problem seems to be so complex Dialogue: 0,1:21:25.18,1:21:27.41,EN,,0,0,0,,that the people who are always at the edge of it are exactly in Dialogue: 0,1:21:27.41,1:21:28.05,EN,,0,0,0,,the state you said. Dialogue: 0,1:21:28.05,1:21:29.71,EN,,0,0,0,,They're wading through this thing, mucking around, Dialogue: 0,1:21:29.72,1:21:31.37,EN,,0,0,0,,seeing what they use, trying to distill stuff. Dialogue: 0,1:21:34.20,1:21:37.76,EN,,0,0,0,,AUDIENCE: I just want to come back to this issue of complexity once more. Dialogue: 0,1:21:38.41,1:21:44.55,EN,,0,0,0,,Um... It certainly seems to be true that you have a great deal of Dialogue: 0,1:21:44.55,1:21:48.32,EN,,0,0,0,,flexibility in altering the lower level kinds of things. Dialogue: 0,1:21:49.71,1:21:53.40,EN,,0,0,0,,But it is true that you are, in a sense, Dialogue: 0,1:21:53.44,1:21:55.26,EN,,0,0,0,,freezing higher level operations. Dialogue: 0,1:21:55.45,1:21:58.51,EN,,0,0,0,,Or at least if you change them you don't know where all of Dialogue: 0,1:21:58.51,1:22:02.06,EN,,0,0,0,,the changes are going to show up, or how they are. Dialogue: 0,1:22:02.20,1:22:04.22,EN,,0,0,0,,PROFESSOR: OK, that's an extremely good question. Dialogue: 0,1:22:04.68,1:22:05.87,EN,,0,0,0,,What I have to do is, Dialogue: 0,1:22:08.68,1:22:10.84,EN,,0,0,0,,if I decide there's a new general operation Dialogue: 0,1:22:11.45,1:22:13.07,EN,,0,0,0,,called equality test, Dialogue: 0,1:22:14.96,1:22:17.15,EN,,0,0,0,,then all of these people have to decide Dialogue: 0,1:22:18.22,1:22:22.54,EN,,0,0,0,,whether or not they would like to have an equality test by looking in the table. Dialogue: 0,1:22:24.65,1:22:26.84,EN,,0,0,0,,There're ways to decentralize it even more. Dialogue: 0,1:22:27.87,1:22:30.70,EN,,0,0,0,,That's what I sort of hinted at last time, where I said Dialogue: 0,1:22:31.08,1:22:33.26,EN,,0,0,0,,you could not only have this type as a symbol, Dialogue: 0,1:22:33.40,1:22:38.70,EN,,0,0,0,,but you actually might store in each object the operations that it knows of that. Dialogue: 0,1:22:40.45,1:22:43.90,EN,,0,0,0,,So you might have things like greatest common divisor, Dialogue: 0,1:22:44.43,1:22:46.81,EN,,0,0,0,,which is a thing here which is defined only for integers, Dialogue: 0,1:22:47.40,1:22:49.21,EN,,0,0,0,,and not in general for rational numbers. Dialogue: 0,1:22:51.03,1:22:53.11,EN,,0,0,0,,So it might be a very, very fragmented system. Dialogue: 0,1:22:53.11,1:22:55.66,EN,,0,0,0,,And then depending on where you want your flexibility, Dialogue: 0,1:22:56.22,1:22:59.02,EN,,0,0,0,,You...there's a whole spectrum of places that you can build that in. Dialogue: 0,1:22:59.96,1:23:02.56,EN,,0,0,0,,But you're pointing at the place where this starts being weak, Dialogue: 0,1:23:02.60,1:23:06.37,EN,,0,0,0,,that there has to be some agreement on top here about these general operations. Dialogue: 0,1:23:06.37,1:23:07.82,EN,,0,0,0,,Or at least people have to think about them. Dialogue: 0,1:23:08.39,1:23:10.72,EN,,0,0,0,,Or you might decide, you might have a table that's very sparse Dialogue: 0,1:23:10.75,1:23:11.96,EN,,0,0,0,,that only has a few things in it. Dialogue: 0,1:23:14.01,1:23:15.49,EN,,0,0,0,,But there are lot of ways to play that game. Dialogue: 0,1:23:19.78,1:23:20.43,EN,,0,0,0,,OK, thank you. Dialogue: 0,0:00:00.00,0:00:02.25,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:04.33,0:00:10.35,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:04.33,0:00:10.35,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.33,0:00:10.35,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N刘殊君(rtmagic) Dialogue: 0,0:00:04.33,0:00:10.35,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:04.33,0:00:10.35,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:11.40,0:00:16.50,Declare,,0,0,0,,{\an2\fad(500,500)}通用运算符 Dialogue: 0,0:00:20.18,0:00:21.84,Default,,0,0,0,,教授:到目前为止 我们已经进行了很多 Dialogue: 0,0:00:21.84,0:00:23.78,Default,,0,0,0,,关于数据抽象的讨论 Dialogue: 0,0:00:23.78,0:00:27.15,Default,,0,0,0,,关键理念就是在构造系统的时候 Dialogue: 0,0:00:27.74,0:00:32.56,Default,,0,0,0,,在其中加入水平的抽象屏障 这些抽象屏障 Dialogue: 0,0:00:33.42,0:00:39.21,Default,,0,0,0,,把你使用一个数据对象的方式 Dialogue: 0,0:00:39.93,0:00:41.18,Default,,0,0,0,,和表示它的方式区分开来 Dialogue: 0,0:00:49.40,0:00:52.03,Default,,0,0,0,,或者可以这样理解它 在上层有一个老板 Dialogue: 0,0:00:52.11,0:00:55.50,Default,,0,0,0,,想要调用某种数据对象 Dialogue: 0,0:00:57.11,0:01:02.31,Default,,0,0,0,,而在下层 George负责它的具体实现 Dialogue: 0,0:01:02.31,0:01:05.42,Default,,0,0,0,,这种把使用与表示分离的想法 Dialogue: 0,0:01:05.44,0:01:09.76,Default,,0,0,0,,可以让你分开考虑这两个问题 Dialogue: 0,0:01:10.60,0:01:14.76,Default,,0,0,0,,这是一种非常强大的编程的方法论 -- 数据抽象 Dialogue: 0,0:01:15.93,0:01:18.81,Default,,0,0,0,,但另一方面 数据抽象在那些真正复杂的系统上 Dialogue: 0,0:01:19.56,0:01:21.84,Default,,0,0,0,,并不是很有效 Dialogue: 0,0:01:22.96,0:01:27.64,Default,,0,0,0,,这个问题就出在George这里 Dialogue: 0,0:01:28.64,0:01:32.09,Default,,0,0,0,,或者说 实际上 问题就在于 Dialogue: 0,0:01:32.09,0:01:32.78,Default,,0,0,0,,现在有太多的George Dialogue: 0,0:01:34.63,0:01:35.39,Default,,0,0,0,,具体地说 Dialogue: 0,0:01:35.39,0:01:39.18,Default,,0,0,0,,假设现在有George和Martha两个人 Dialogue: 0,0:01:41.19,0:01:44.22,Default,,0,0,0,,他们都是这个系统的开发人员 Dialogue: 0,0:01:46.04,0:01:47.29,Default,,0,0,0,,都在设计数据的表示方法 Dialogue: 0,0:01:48.41,0:01:50.67,Default,,0,0,0,,而且他们完全合不来 Dialogue: 0,0:01:51.75,0:01:53.62,Default,,0,0,0,,他们不会合作开发同一种表示方法 Dialogue: 0,0:01:54.01,0:01:55.34,Default,,0,0,0,,永远也不会 Dialogue: 0,0:01:57.48,0:01:59.72,Default,,0,0,0,,现在的问题是 假设你想要这样一个系统 Dialogue: 0,0:02:00.06,0:02:02.60,Default,,0,0,0,,在这个系统中George和Martha都为它设计了数据表示方法 Dialogue: 0,0:02:03.82,0:02:08.08,Default,,0,0,0,,但是如果你在高于这个抽象屏障的层面思考 Dialogue: 0,0:02:09.40,0:02:11.04,Default,,0,0,0,,你就不用去操心这些事情 Dialogue: 0,0:02:11.66,0:02:14.18,Default,,0,0,0,,不用操心 某个东西是到底是George做的还是Martha做的 Dialogue: 0,0:02:14.18,0:02:15.43,Default,,0,0,0,,同时你也不想让George和Martha Dialogue: 0,0:02:15.43,0:02:16.48,Default,,0,0,0,,妨碍彼此的工作 Dialogue: 0,0:02:16.63,0:02:20.31,Default,,0,0,0,,你在设计系统的时候 不仅仅需要这些 Dialogue: 0,0:02:20.31,0:02:23.84,Default,,0,0,0,,水平的抽象屏障 同时也想设置一道 Dialogue: 0,0:02:25.82,0:02:30.64,Default,,0,0,0,,垂直的屏障 -- 来把George和Martha分离开 Dialogue: 0,0:02:32.98,0:02:35.40,Default,,0,0,0,,我们来说得再具体一点 Dialogue: 0,0:02:36.56,0:02:40.54,Default,,0,0,0,,想象一个很大的公司的人事记录 Dialogue: 0,0:02:41.18,0:02:46.11,Default,,0,0,0,,这个公司里有很多部门没什么联系 Dialogue: 0,0:02:47.90,0:02:49.71,Default,,0,0,0,,并且部门之间合作得也不太好 Dialogue: 0,0:02:50.43,0:02:57.04,Default,,0,0,0,,甚至还可以想象这个大公司就是由 Dialogue: 0,0:02:57.04,0:02:59.45,Default,,0,0,0,,很多公司组成的 而且每个公司 Dialogue: 0,0:02:59.45,0:03:00.70,Default,,0,0,0,,都有自己的一套人事记录 Dialogue: 0,0:03:03.25,0:03:06.57,Default,,0,0,0,,想象一下突然有一天 这些部门 Dialogue: 0,0:03:06.57,0:03:08.53,Default,,0,0,0,,被一种神奇的卫星网络连接起来 Dialogue: 0,0:03:08.53,0:03:10.52,Default,,0,0,0,,它们各自的数据库都被放到了一起 Dialogue: 0,0:03:12.24,0:03:13.85,Default,,0,0,0,,现在你想要 Dialogue: 0,0:03:14.84,0:03:16.33,Default,,0,0,0,,在公司的任何地方 Dialogue: 0,0:03:17.26,0:03:23.13,Default,,0,0,0,,都能够知道 哦 某一条人事记录里的 Dialogue: 0,0:03:23.13,0:03:23.87,Default,,0,0,0,,“姓名”是什么 Dialogue: 0,0:03:26.30,0:03:29.15,Default,,0,0,0,,或者一条记录里的“工作”是什么 Dialogue: 0,0:03:30.54,0:03:34.40,Default,,0,0,0,,同时又不需要担心每一个部门 Dialogue: 0,0:03:34.84,0:03:36.76,Default,,0,0,0,,对于人事记录的格式 Dialogue: 0,0:03:36.76,0:03:39.37,Default,,0,0,0,,有着完全不同的习惯 Dialogue: 0,0:03:41.58,0:03:43.26,Default,,0,0,0,,从你的视角上你不想去了解这些东西 Dialogue: 0,0:03:44.96,0:03:47.92,Default,,0,0,0,,那么怎么才能做到这样呢? Dialogue: 0,0:03:48.43,0:03:52.41,Default,,0,0,0,,当然 一种方法是下发一个告示 Dialogue: 0,0:03:52.64,0:03:56.29,Default,,0,0,0,,来通知所有人把他们的记录格式 Dialogue: 0,0:03:56.29,0:03:57.24,Default,,0,0,0,,都改成某种标准的格式 Dialogue: 0,0:03:58.07,0:04:00.12,Default,,0,0,0,,人们经常这样做 但都没有成功 Dialogue: 0,0:04:01.82,0:04:07.34,Default,,0,0,0,,另一个办法则是重新安排这些记录 Dialogue: 0,0:04:08.33,0:04:09.90,Default,,0,0,0,,让它们中间有这种垂直的抽象屏障 Dialogue: 0,0:04:11.25,0:04:14.40,Default,,0,0,0,,当你查询一份人事档案里的姓名的时候 Dialogue: 0,0:04:14.43,0:04:17.97,Default,,0,0,0,,不管它是什么格式 name这个过程都能设法 Dialogue: 0,0:04:17.97,0:04:19.42,Default,,0,0,0,,搞清楚怎么正确地完成这件事 Dialogue: 0,0:04:22.73,0:04:25.53,Default,,0,0,0,,我们把name叫做一个 所谓的“通用运算符” Dialogue: 0,0:04:26.26,0:04:30.06,Default,,0,0,0,,通用运算符意味着它会根据数据的种类 Dialogue: 0,0:04:30.06,0:04:31.69,Default,,0,0,0,,准确地做出对应的操作 Dialogue: 0,0:04:33.65,0:04:36.62,Default,,0,0,0,,更进一步讲 你想让这个系统在 Dialogue: 0,0:04:36.92,0:04:39.79,Default,,0,0,0,,下次公司里多了一个新的人员划分的时候 Dialogue: 0,0:04:42.51,0:04:45.64,Default,,0,0,0,,人们连接系统的方法不会有很大的变化 Dialogue: 0,0:04:45.64,0:04:50.11,Default,,0,0,0,,并且公司里剩下的部门 Dialogue: 0,0:04:50.11,0:04:52.01,Default,,0,0,0,,要把它们的人员记录添加到这个系统 Dialogue: 0,0:04:52.27,0:04:53.93,Default,,0,0,0,,也不需要做什么大的修改 Dialogue: 0,0:04:55.52,0:04:57.52,Default,,0,0,0,,那么这就是你应该考虑的问题 Dialogue: 0,0:04:58.70,0:05:00.77,Default,,0,0,0,,或者这就是你的工作 Dialogue: 0,0:05:00.77,0:05:03.77,Default,,0,0,0,,要让系统可以用最少的改动来拥抱变化 Dialogue: 0,0:05:05.98,0:05:08.12,Default,,0,0,0,,这就是我们今天要讨论的问题 Dialogue: 0,0:05:09.44,0:05:14.22,Default,,0,0,0,,你脑子里应该有这个分布式的人事档案系统 Dialogue: 0,0:05:14.24,0:05:16.62,Default,,0,0,0,,但是实际上 我今天要讨论的是一个 Dialogue: 0,0:05:16.62,0:05:18.48,Default,,0,0,0,,比那要更加自成体系的问题 Dialogue: 0,0:05:19.29,0:05:21.76,Default,,0,0,0,,我觉得用它可以把事情说得更清楚一点 Dialogue: 0,0:05:21.87,0:05:26.01,Default,,0,0,0,,我们要讨论的是 复数域上的算术系统 Dialogue: 0,0:05:27.77,0:05:28.92,Default,,0,0,0,,我们来看看这个系统 Dialogue: 0,0:05:30.69,0:05:31.74,Default,,0,0,0,,来复习一下 Dialogue: 0,0:05:32.04,0:05:33.53,Default,,0,0,0,,什么是“复数” Dialogue: 0,0:05:35.25,0:05:38.22,Default,,0,0,0,,复数z可以看做复平面上的一点 Dialogue: 0,0:05:39.37,0:05:47.19,Default,,0,0,0,,我们将复数表示为实数部分和虚数部分 Dialogue: 0,0:05:47.19,0:05:50.83,Default,,0,0,0,,所以如果这个是复数z 它的实部是这么多 Dialogue: 0,0:05:51.50,0:05:53.24,Default,,0,0,0,,它的虚部是那么多 Dialogue: 0,0:05:54.33,0:05:56.44,Default,,0,0,0,,我们就可以记z=x+iy Dialogue: 0,0:05:59.11,0:06:03.21,Default,,0,0,0,,还有另一种方法来表示一个复数 比如说 Dialogue: 0,0:06:03.21,0:06:09.00,Default,,0,0,0,,这个点与原点的距离是多少 在原点的什么角度上 Dialogue: 0,0:06:11.32,0:06:16.67,Default,,0,0,0,,像这样 复数也可以表示为半径乘以一个角度 Dialogue: 0,0:06:19.52,0:06:21.92,Default,,0,0,0,,第一种表示法称为 直角坐标系表示 Dialogue: 0,0:06:22.59,0:06:25.45,Default,,0,0,0,,或者说实部-虚部表示 Dialogue: 0,0:06:26.20,0:06:30.04,Default,,0,0,0,,而后一种是用模和辐角两部分的极坐标表示 Dialogue: 0,0:06:30.04,0:06:31.48,Default,,0,0,0,,并且如果你知道了一个复数的实部和虚部 Dialogue: 0,0:06:31.53,0:06:33.36,Default,,0,0,0,,你就能计算出它的模和辐角 Dialogue: 0,0:06:33.72,0:06:36.97,Default,,0,0,0,,如果知道了x和y 就能用这个式子算出r Dialogue: 0,0:06:37.19,0:06:39.48,Default,,0,0,0,,等于两个数平方和的平方根 然后就可以 Dialogue: 0,0:06:39.48,0:06:40.76,Default,,0,0,0,,用反三角函数算出辐角的值 Dialogue: 0,0:06:41.42,0:06:44.42,Default,,0,0,0,,或者反过来 如果你知道了r和A Dialogue: 0,0:06:44.42,0:06:45.31,Default,,0,0,0,,你也能计算出x和y Dialogue: 0,0:06:45.80,0:06:49.43,Default,,0,0,0,,x=r·cos(A) y=r·sin(A) Dialogue: 0,0:06:51.34,0:06:53.66,Default,,0,0,0,,这是表示复数的两种不同方法 Dialogue: 0,0:06:54.13,0:06:57.15,Default,,0,0,0,,分别是极坐标形式和直角坐标形式 Dialogue: 0,0:06:57.15,0:06:58.12,Default,,0,0,0,,我们要设计的是 Dialogue: 0,0:06:58.32,0:07:01.32,Default,,0,0,0,,一个复数域上的算术系统 Dialogue: 0,0:07:03.95,0:07:05.12,Default,,0,0,0,,换句话讲 我们要 Dialogue: 0,0:07:05.58,0:07:06.99,Default,,0,0,0,,就像之前课上有理数运算的例子一样 Dialogue: 0,0:07:07.38,0:07:10.20,Default,,0,0,0,,是构造一个叫做+c的操作 Dialogue: 0,0:07:10.73,0:07:13.90,Default,,0,0,0,,它将两个复数然后把它们相加、相减 Dialogue: 0,0:07:14.35,0:07:16.94,Default,,0,0,0,,相乘或者相除 Dialogue: 0,0:07:20.73,0:07:25.28,Default,,0,0,0,,那么我们要用到一点点数学 Dialogue: 0,0:07:25.28,0:07:28.36,Default,,0,0,0,,对它们进行操作的具体的算式是什么 Dialogue: 0,0:07:30.41,0:07:31.92,Default,,0,0,0,,它们是怎么得出来的 并不重要 Dialogue: 0,0:07:34.00,0:07:35.79,Default,,0,0,0,,我们只是用它们实现运算 Dialogue: 0,0:07:35.80,0:07:37.95,Default,,0,0,0,,如果想要把两个复数相加 Dialogue: 0,0:07:39.13,0:07:42.66,Default,,0,0,0,,可以很容易地获取它们的实部和虚部 Dialogue: 0,0:07:42.66,0:07:45.93,Default,,0,0,0,,两个复数的和的实部 Dialogue: 0,0:07:47.72,0:07:49.72,Default,,0,0,0,,z1+z2的实部 Dialogue: 0,0:07:50.06,0:07:54.64,Default,,0,0,0,,就是z1的实部加上z2的实部 Dialogue: 0,0:07:57.82,0:08:01.60,Default,,0,0,0,,然后z1+z2的虚部也就是 Dialogue: 0,0:08:01.74,0:08:05.66,Default,,0,0,0,,z1的虚部加上z2的虚部 Dialogue: 0,0:08:07.41,0:08:09.48,Default,,0,0,0,,所以复数相加是非常简单的事情 Dialogue: 0,0:08:09.48,0:08:10.99,Default,,0,0,0,,你只要把各个部分分别加起来 Dialogue: 0,0:08:11.31,0:08:13.18,Default,,0,0,0,,然后用结果构建一个新的复数 Dialogue: 0,0:08:13.37,0:08:14.73,Default,,0,0,0,,如果你想要让复数相乘 Dialogue: 0,0:08:15.53,0:08:17.82,Default,,0,0,0,,那么在极坐标下运算会方便很多 Dialogue: 0,0:08:17.82,0:08:20.38,Default,,0,0,0,,因为对于两个复数 Dialogue: 0,0:08:20.40,0:08:26.54,Default,,0,0,0,,两复数积之模 就是它们各自的模的乘积 Dialogue: 0,0:08:28.85,0:08:33.88,Default,,0,0,0,,它们的积的辐角 就是两个辐角的和 Dialogue: 0,0:08:35.80,0:08:40.54,Default,,0,0,0,,这就是复数域上的运算所需的数学知识 Dialogue: 0,0:08:40.54,0:08:42.38,Default,,0,0,0,,我们来想一想具体的实现 Dialogue: 0,0:08:43.72,0:08:47.39,Default,,0,0,0,,我们就像之前运算有理数那样做 Dialogue: 0,0:08:49.84,0:08:53.47,Default,,0,0,0,,来到底层 假设有一些构造函数和选择函数 Dialogue: 0,0:08:53.76,0:08:54.52,Default,,0,0,0,,它们应该是什么样子呢 Dialogue: 0,0:08:55.33,0:08:58.16,Default,,0,0,0,,假设我们制造了一些表示数据对象的“云彩” Dialogue: 0,0:08:58.54,0:09:00.78,Default,,0,0,0,,也就是用某种形式表示的复数 Dialogue: 0,0:09:01.79,0:09:04.67,Default,,0,0,0,,我们能从这个复数中得到它的实部 Dialogue: 0,0:09:05.52,0:09:09.64,Default,,0,0,0,,可以获得 虚部、模、或者辐角 Dialogue: 0,0:09:12.15,0:09:14.01,Default,,0,0,0,,然后我们需要一种方法来构造复数 Dialogue: 0,0:09:14.03,0:09:15.64,Default,,0,0,0,,不仅要有选择函数 还要有构造函数 Dialogue: 0,0:09:16.80,0:09:19.52,Default,,0,0,0,,那么假设我们有一个叫做make-rectangular的过程 Dialogue: 0,0:09:19.53,0:09:24.27,Default,,0,0,0,,这个过程的功能是接受一个实部 Dialogue: 0,0:09:24.51,0:09:29.36,Default,,0,0,0,,和一个虚部 然后把这两个部分组合成一个复数 Dialogue: 0,0:09:31.92,0:09:35.01,Default,,0,0,0,,同样我们也可以构造一个make-polar过程 Dialogue: 0,0:09:35.01,0:09:37.85,Default,,0,0,0,,它接受一个模和一个辐角 Dialogue: 0,0:09:40.83,0:09:43.90,Default,,0,0,0,,然后用这两个值 组成一个复数 Dialogue: 0,0:09:44.68,0:09:45.46,Default,,0,0,0,,那么这个系统 Dialogue: 0,0:09:45.46,0:09:47.77,Default,,0,0,0,,里面会有两个构造函数和四个选择函数 Dialogue: 0,0:09:48.91,0:09:55.15,Default,,0,0,0,,现在 就像之前课程中那样 我们基于这个抽象的数据结构 Dialogue: 0,0:09:55.15,0:09:59.22,Default,,0,0,0,,继续实现复数的各种运算 Dialogue: 0,0:09:59.22,0:10:02.30,Default,,0,0,0,,而这些Lisp代码 Dialogue: 0,0:10:03.23,0:10:07.47,Default,,0,0,0,,是从我之前写的算术公式“翻译”而来的 Dialogue: 0,0:10:08.06,0:10:09.98,Default,,0,0,0,,如果我想把两个复数相加 Dialogue: 0,0:10:11.76,0:10:15.56,Default,,0,0,0,,我就要用一个实部和一个虚部构造一个复数 Dialogue: 0,0:10:16.72,0:10:19.02,Default,,0,0,0,,这个新的复数的实部是 Dialogue: 0,0:10:19.40,0:10:21.80,Default,,0,0,0,,两个复数的实部的和 Dialogue: 0,0:10:23.31,0:10:25.37,Default,,0,0,0,,它的虚数部分是 Dialogue: 0,0:10:25.40,0:10:27.52,Default,,0,0,0,,两个复数的虚部的和 Dialogue: 0,0:10:30.31,0:10:32.09,Default,,0,0,0,,我把它们放到一起 构造出一个复数 Dialogue: 0,0:10:32.16,0:10:34.44,Default,,0,0,0,,这就是实现复数加法的方法 Dialogue: 0,0:10:35.78,0:10:38.49,Default,,0,0,0,,减法实际上是一样的 Dialogue: 0,0:10:39.65,0:10:42.97,Default,,0,0,0,,只需要把各个部分相加变成把它们相减 Dialogue: 0,0:10:45.14,0:10:47.07,Default,,0,0,0,,要把两个复数相乘 Dialogue: 0,0:10:47.74,0:10:49.02,Default,,0,0,0,,要用另外一个式子 Dialogue: 0,0:10:49.27,0:10:53.84,Default,,0,0,0,,我会用一个模和一个辐角来构造一个复数 Dialogue: 0,0:10:55.35,0:10:56.44,Default,,0,0,0,,z1*z2的模 Dialogue: 0,0:10:56.65,0:11:00.97,Default,,0,0,0,,就是z1的模乘以z2的模 Dialogue: 0,0:11:03.71,0:11:05.93,Default,,0,0,0,,而z1*z2的辐角则是 Dialogue: 0,0:11:06.16,0:11:08.51,Default,,0,0,0,,z1的辐角加上z2的辐角 Dialogue: 0,0:11:09.62,0:11:10.96,Default,,0,0,0,,那么这就是乘法的实现 Dialogue: 0,0:11:11.23,0:11:12.25,Default,,0,0,0,,然后是除法 Dialogue: 0,0:11:14.27,0:11:15.90,Default,,0,0,0,,除法和乘法几乎是一样的 Dialogue: 0,0:11:17.37,0:11:19.58,Default,,0,0,0,,我只要把两个模相除 把辐角相减就可以了 Dialogue: 0,0:11:28.36,0:11:30.46,Default,,0,0,0,,现在我已经实现了各种运算 Dialogue: 0,0:11:31.87,0:11:33.64,Default,,0,0,0,,然后我们做什么 Dialogue: 0,0:11:33.64,0:11:34.52,Default,,0,0,0,,我们把George叫来 Dialogue: 0,0:11:36.06,0:11:38.79,Default,,0,0,0,,我们完成了“使用”的部分 现在应该考虑“表示”了 Dialogue: 0,0:11:38.80,0:11:40.94,Default,,0,0,0,,我们叫来George然后对他说 Dialogue: 0,0:11:40.97,0:11:43.61,Default,,0,0,0,,“为我们设计一个一套复数的表示方法” Dialogue: 0,0:11:45.25,0:11:47.44,Default,,0,0,0,,很好 Dialogue: 0,0:11:47.77,0:11:52.66,Default,,0,0,0,,George可能会说 我们把一个复数 Dialogue: 0,0:11:52.66,0:11:57.15,Default,,0,0,0,,实现为 一个由实部和虚部组成的序对 Dialogue: 0,0:11:57.20,0:12:02.62,Default,,0,0,0,,那么如果我想用某个实部和虚部来构造复数 Dialogue: 0,0:12:03.36,0:12:05.55,Default,,0,0,0,,我只需要把它们cons起来即可 这样可以-- Dialogue: 0,0:12:06.03,0:12:08.11,Default,,0,0,0,,这就是George表示复数的方法 Dialogue: 0,0:12:09.78,0:12:12.42,Default,,0,0,0,,那么如果我想获得它的实部 我只需要 Dialogue: 0,0:12:12.42,0:12:14.12,Default,,0,0,0,,提取出序对的car部分 -- 它的首部分 Dialogue: 0,0:12:14.35,0:12:16.67,Default,,0,0,0,,如果我想要得到虚部 我就提取出它的cdr部分 Dialogue: 0,0:12:19.64,0:12:21.77,Default,,0,0,0,,那对于模和辐角 又该如何取得呢? Dialogue: 0,0:12:22.22,0:12:25.75,Default,,0,0,0,,如果我想取得某个复数的模 Dialogue: 0,0:12:25.75,0:12:32.30,Default,,0,0,0,,我需要计算该复数car与cdr的平方和的算术平方根 Dialogue: 0,0:12:33.79,0:12:39.26,Default,,0,0,0,,如果我想得到辐角 我就计算它的cdr与car比值的反正切 Dialogue: 0,0:12:39.53,0:12:42.86,Default,,0,0,0,,这个Lisp过程用于计算反正切 Dialogue: 0,0:12:44.97,0:12:48.59,Default,,0,0,0,,要是有人给我一个模和辐角 Dialogue: 0,0:12:48.94,0:12:50.56,Default,,0,0,0,,并说:“给我构造一个复数” Dialogue: 0,0:12:50.89,0:12:56.24,Default,,0,0,0,,用它们计算出实部 r*cos(a) 和虚部 r*sin(a) Dialogue: 0,0:12:57.77,0:12:59.05,Default,,0,0,0,,连接成一个序对就行了 Dialogue: 0,0:13:01.46,0:13:02.26,Default,,0,0,0,,完成了 Dialogue: 0,0:13:02.26,0:13:04.75,Default,,0,0,0,,实际上我做的事情 在概念上讲 Dialogue: 0,0:13:06.89,0:13:09.37,Default,,0,0,0,,和我们之前提过的有理数的表示 Dialogue: 0,0:13:10.60,0:13:12.44,Default,,0,0,0,,是完全没有区别的 Dialogue: 0,0:13:12.75,0:13:13.91,Default,,0,0,0,,它们的思想相同 Dialogue: 0,0:13:13.91,0:13:16.28,Default,,0,0,0,,实现具体过程 选择一种表示方法 Dialogue: 0,0:13:18.07,0:13:18.65,Default,,0,0,0,,没有什么不同 Dialogue: 0,0:13:20.07,0:13:21.56,Default,,0,0,0,,现在我们来关心一下Martha Dialogue: 0,0:13:23.21,0:13:24.52,Default,,0,0,0,,嗯 Martha的想法不太一样 Dialogue: 0,0:13:26.67,0:13:28.57,Default,,0,0,0,,她不想把复数表示成 Dialogue: 0,0:13:28.59,0:13:30.90,Default,,0,0,0,,由实部和虚部组成的序对 Dialogue: 0,0:13:30.90,0:13:34.17,Default,,0,0,0,,她比较喜欢把它们表示成 Dialogue: 0,0:13:34.17,0:13:37.69,Default,,0,0,0,,由模和辐角组成的序对 Dialogue: 0,0:13:39.55,0:13:42.13,Default,,0,0,0,,那么如果我们没有让George而是让Martha Dialogue: 0,0:13:42.13,0:13:43.74,Default,,0,0,0,,来设计复数的表示方法 我们就会得到这样的东西 Dialogue: 0,0:13:44.57,0:13:47.16,Default,,0,0,0,,有一个make-polar过程 Dialogue: 0,0:13:47.16,0:13:50.22,Default,,0,0,0,,当然了 有了一个模和一个辐角之后 Dialogue: 0,0:13:50.22,0:13:53.07,Default,,0,0,0,,我们只要把它们组合成一个序对就行了 Dialogue: 0,0:13:55.43,0:13:57.68,Default,,0,0,0,,如果你想取得复数的模 那很简单 Dialogue: 0,0:13:58.24,0:13:59.37,Default,,0,0,0,,你只需要取序对的car部分即可 Dialogue: 0,0:13:59.78,0:14:02.67,Default,,0,0,0,,当然 想取得复数的辐角 那也很简单 Dialogue: 0,0:14:02.67,0:14:03.63,Default,,0,0,0,,只需取cdr部分即可 Dialogue: 0,0:14:04.81,0:14:07.02,Default,,0,0,0,,但是如果你想要获得实部和虚部 Dialogue: 0,0:14:07.42,0:14:08.49,Default,,0,0,0,,那就得费点力气 Dialogue: 0,0:14:08.88,0:14:14.58,Default,,0,0,0,,想得到实部 你就得计算r*cos(a) Dialogue: 0,0:14:14.58,0:14:19.99,Default,,0,0,0,,换句话讲 用序对的car部分去乘以 Dialogue: 0,0:14:19.99,0:14:20.95,Default,,0,0,0,,cdr部分的余弦值 Dialogue: 0,0:14:20.95,0:14:26.23,Default,,0,0,0,,然后你就算出了r*cos(a) Dialogue: 0,0:14:26.54,0:14:27.48,Default,,0,0,0,,这就是这个复数的实部 Dialogue: 0,0:14:28.33,0:14:31.40,Default,,0,0,0,,要是想算出它的虚部 用r乘以sin(a)就可以了 Dialogue: 0,0:14:32.66,0:14:37.93,Default,,0,0,0,,现在如果我给你一个实部和虚部 然后说 Dialogue: 0,0:14:37.93,0:14:42.03,Default,,0,0,0,,用它们给我构造一个复数 Dialogue: 0,0:14:42.03,0:14:44.17,Default,,0,0,0,,那就要先算出 Dialogue: 0,0:14:44.17,0:14:45.54,Default,,0,0,0,,模和辐角是多少 Dialogue: 0,0:14:45.54,0:14:47.85,Default,,0,0,0,,模是实部和虚部的平方和的算术平方根 Dialogue: 0,0:14:48.09,0:14:49.23,Default,,0,0,0,,辐角是这个反正切 Dialogue: 0,0:14:49.23,0:14:50.22,Default,,0,0,0,,我用这两个数构造一个序对 Dialogue: 0,0:14:52.09,0:14:54.17,Default,,0,0,0,,以上就是Martha的想法 Dialogue: 0,0:14:56.69,0:14:57.37,Default,,0,0,0,,那么哪种比较好呢? Dialogue: 0,0:14:59.68,0:15:03.15,Default,,0,0,0,,如果你需要做很多加法 那么George的比较好 Dialogue: 0,0:15:03.16,0:15:05.61,Default,,0,0,0,,因为你总是要用到复数的实部和虚部 Dialogue: 0,0:15:05.85,0:15:08.40,Default,,0,0,0,,如果你大多数时间都是在做乘法 Dialogue: 0,0:15:09.48,0:15:11.14,Default,,0,0,0,,那可能Martha的办法就要好一些 Dialogue: 0,0:15:11.14,0:15:14.84,Default,,0,0,0,,又或者 -- 这就是问题所在了 -- 你决定不了 Dialogue: 0,0:15:16.59,0:15:22.32,Default,,0,0,0,,或者出于某些个人原因 你想让它们同时存在 Dialogue: 0,0:15:23.48,0:15:26.76,Default,,0,0,0,,也可能你是真的无法决定你更喜欢哪种表示法 Dialogue: 0,0:15:28.56,0:15:32.32,Default,,0,0,0,,回到这个话题 我们真正想要的是这样一个系统 Dialogue: 0,0:15:32.65,0:15:36.17,Default,,0,0,0,,这里面 既有George 他实现了 Dialogue: 0,0:15:36.83,0:15:39.64,Default,,0,0,0,,复数的直角坐标表示 Dialogue: 0,0:15:41.47,0:15:44.25,Default,,0,0,0,,又有Martha 她实现了复数的极坐标表示 Dialogue: 0,0:15:46.12,0:15:49.69,Default,,0,0,0,,然后我们有各种运算 Dialogue: 0,0:15:50.28,0:15:56.89,Default,,0,0,0,,用来对复数进行加减乘除 Dialogue: 0,0:15:57.56,0:15:58.76,Default,,0,0,0,,那么这些运算 Dialogue: 0,0:15:59.34,0:16:02.79,Default,,0,0,0,,不应该被系统中同时存在的两种 Dialogue: 0,0:16:02.79,0:16:03.98,Default,,0,0,0,,互不兼容的复数表示方法影响 Dialogue: 0,0:16:04.41,0:16:08.33,Default,,0,0,0,,或者说 我们不光有像这样的一个抽象屏障 Dialogue: 0,0:16:09.64,0:16:11.84,Default,,0,0,0,,它里面有real-part Dialogue: 0,0:16:15.77,0:16:21.71,Default,,0,0,0,,还有 IMAG-PART、MAG 和 ANG 等几个过程 Dialogue: 0,0:16:23.83,0:16:25.36,Default,,0,0,0,,不光有一层抽象屏障 Dialogue: 0,0:16:25.39,0:16:28.38,Default,,0,0,0,,把实际的数据表示隐藏起来 Dialogue: 0,0:16:29.10,0:16:31.52,Default,,0,0,0,,还有一层垂直的屏障 Dialogue: 0,0:16:32.19,0:16:35.02,Default,,0,0,0,,容许不同的表示方法彼此共存 Dialogue: 0,0:16:35.87,0:16:37.40,Default,,0,0,0,,而不互相干预 Dialogue: 0,0:16:38.57,0:16:41.07,Default,,0,0,0,,我们的想法是把这些东西 Dialogue: 0,0:16:41.90,0:16:44.12,Default,,0,0,0,,REAL-PART、IMAG-PART、MAG、ANG 这些过程 Dialogue: 0,0:16:44.12,0:16:46.49,Default,,0,0,0,,设计成通用运算符 Dialogue: 0,0:16:47.31,0:16:49.45,Default,,0,0,0,,如果你调用real-part过程 它就会判断 Dialogue: 0,0:16:49.98,0:16:51.31,Default,,0,0,0,,要在哪一种表示方法中寻找它 Dialogue: 0,0:16:53.88,0:16:55.10,Default,,0,0,0,,那么我们怎么做到这一点呢 Dialogue: 0,0:16:56.84,0:16:59.23,Default,,0,0,0,,实际上有一个很容易想到的办法 Dialogue: 0,0:16:59.84,0:17:01.68,Default,,0,0,0,,如果你习惯了思考复数的模式 Dialogue: 0,0:17:02.52,0:17:04.44,Default,,0,0,0,,如果你已经习惯了复合数据的思想 Dialogue: 0,0:17:06.33,0:17:10.99,Default,,0,0,0,,假设你只要观察一个复数 Dialogue: 0,0:17:12.17,0:17:13.95,Default,,0,0,0,,就能看出它是被George还是Martha构造出来的 Dialogue: 0,0:17:15.79,0:17:18.90,Default,,0,0,0,,换句话说 在你眼前漂浮的这些东西 Dialogue: 0,0:17:18.90,0:17:20.91,Default,,0,0,0,,不是普通的复数 对吗? Dialogue: 0,0:17:20.91,0:17:22.94,Default,,0,0,0,,它们是被某个设计者“构想”出来的 Dialogue: 0,0:17:24.39,0:17:28.04,Default,,0,0,0,,当考察一个复数 我们会发现它“不仅仅”是个复数 Dialogue: 0,0:17:28.04,0:17:29.16,Default,,0,0,0,,它上面有一个标签 Dialogue: 0,0:17:29.19,0:17:30.75,Default,,0,0,0,,写着这个是由Martha制造的 Dialogue: 0,0:17:31.45,0:17:34.22,Default,,0,0,0,,或者这个是由George制造的 Dialogue: 0,0:17:34.48,0:17:35.39,Default,,0,0,0,,对吧?它们被签了名字 Dialogue: 0,0:17:36.86,0:17:40.15,Default,,0,0,0,,在这之后 无论何时我们看见一个复数 Dialogue: 0,0:17:40.15,0:17:45.48,Default,,0,0,0,,我们只要看它的标签 然后我们就能知道 Dialogue: 0,0:17:45.80,0:17:46.72,Default,,0,0,0,,应该怎么对它进行运算 Dialogue: 0,0:17:48.03,0:17:51.19,Default,,0,0,0,,或者说 我们想要的不只是普通的数据对象 Dialogue: 0,0:17:51.19,0:17:54.37,Default,,0,0,0,,我们引入一个概念:带类型的数据 Dialogue: 0,0:17:59.76,0:18:02.81,Default,,0,0,0,,带类型的数据就意味着 这里有一朵“云彩” Dialogue: 0,0:18:03.94,0:18:08.93,Default,,0,0,0,,它里面有我们之前所说的那种 Dialogue: 0,0:18:08.93,0:18:09.90,Default,,0,0,0,,普通的数据对象 Dialogue: 0,0:18:13.18,0:18:16.54,Default,,0,0,0,,这是它的内容 就是实际的数据 Dialogue: 0,0:18:19.32,0:18:21.56,Default,,0,0,0,,它里面还有一个叫做类型的东西 Dialogue: 0,0:18:22.56,0:18:25.24,Default,,0,0,0,,被George或者Martha签了名 Dialogue: 0,0:18:25.99,0:18:28.27,Default,,0,0,0,,那么我们现在就要从无类型的数据进入带类型数据的领域 Dialogue: 0,0:18:31.95,0:18:32.71,Default,,0,0,0,,我们怎么构造它 Dialogue: 0,0:18:32.71,0:18:33.50,Default,,0,0,0,,那很简单 Dialogue: 0,0:18:33.84,0:18:35.32,Default,,0,0,0,,我们知道怎么构造“云彩” Dialogue: 0,0:18:35.80,0:18:36.88,Default,,0,0,0,,我们用序对来组成它们 Dialogue: 0,0:18:37.92,0:18:41.82,Default,,0,0,0,,那么我们就有了一种方法来表示带类型的数据 Dialogue: 0,0:18:43.51,0:18:49.64,Default,,0,0,0,,这种方法叫做 把类型附加到内容上 Dialogue: 0,0:18:49.69,0:18:50.64,Default,,0,0,0,,用cons就可以做到 Dialogue: 0,0:18:51.64,0:18:54.11,Default,,0,0,0,,然后面对一个带类型的数据 我们就可以知道它的类型 Dialogue: 0,0:18:55.21,0:18:56.00,Default,,0,0,0,,也就是序对的car部分 Dialogue: 0,0:18:56.29,0:18:58.30,Default,,0,0,0,,我们也可以知道它的具体内容 就是它的cdr部分 Dialogue: 0,0:18:59.96,0:19:04.28,Default,,0,0,0,,我们用这种方法使用带类型的数据 Dialogue: 0,0:19:05.29,0:19:07.26,Default,,0,0,0,,面对一段类型数据就能知道它是什么类型 Dialogue: 0,0:19:07.52,0:19:09.26,Default,,0,0,0,,那么我们现在有了几种判断类型的谓词 Dialogue: 0,0:19:10.51,0:19:13.73,Default,,0,0,0,,举例来讲 想要知道一个复数 Dialogue: 0,0:19:13.73,0:19:16.86,Default,,0,0,0,,是不是George构造的 是不是直角坐标表示的 我们只需要看 Dialogue: 0,0:19:16.86,0:19:21.85,Default,,0,0,0,,它的“类型”是不是rectangular这个符号 Dialogue: 0,0:19:23.68,0:19:25.05,Default,,0,0,0,,对吧?检查 rectangular 符号 Dialogue: 0,0:19:27.20,0:19:30.33,Default,,0,0,0,,同理 想要知道一个复数是不是Martha构造的 Dialogue: 0,0:19:30.33,0:19:33.42,Default,,0,0,0,,我们就看它的“类型”是不是polar这个符号 Dialogue: 0,0:19:36.46,0:19:39.21,Default,,0,0,0,,那么这就是一种识别数字的类型的方法 Dialogue: 0,0:19:40.75,0:19:42.81,Default,,0,0,0,,现在来想想 怎么用这种方法来构建系统 Dialogue: 0,0:19:43.87,0:19:46.73,Default,,0,0,0,,我们假设George和Martha分别在做各自的工作 Dialogue: 0,0:19:47.36,0:19:52.64,Default,,0,0,0,,每一个人都设计了他们的复数表示程序包 Dialogue: 0,0:19:52.64,0:19:58.52,Default,,0,0,0,,他们怎么让自己的东西成为系统的一部分 Dialogue: 0,0:19:58.73,0:20:00.14,Default,,0,0,0,,和对方友好共存呢 Dialogue: 0,0:20:00.14,0:20:02.11,Default,,0,0,0,,那其实非常简单 Dialogue: 0,0:20:02.72,0:20:04.51,Default,,0,0,0,,回忆一下 George做了这个程序包 Dialogue: 0,0:20:05.97,0:20:08.48,Default,,0,0,0,,这就是George的程序包 或者说它的一部分 Dialogue: 0,0:20:08.98,0:20:11.15,Default,,0,0,0,,然后红色下划线标出的部分是他需要做的修改 Dialogue: 0,0:20:12.09,0:20:16.43,Default,,0,0,0,,之前 当George用x和y构建了一个复数的时候 Dialogue: 0,0:20:17.52,0:20:19.85,Default,,0,0,0,,他只是把它们组合成一个序对 Dialogue: 0,0:20:20.93,0:20:23.39,Default,,0,0,0,,现在唯一不同的地方是 他给它们打了标签 Dialogue: 0,0:20:24.09,0:20:28.08,Default,,0,0,0,,他把类型 -- 也就是 rectangular符号 -- 附加到这个序对上面 Dialogue: 0,0:20:30.60,0:20:33.26,Default,,0,0,0,,剩下的事情都和之前一样 除了一点 Dialogue: 0,0:20:33.92,0:20:38.06,Default,,0,0,0,,就是George和Martha的程序都有叫做real-part和imaginary-part的过程 Dialogue: 0,0:20:38.70,0:20:42.96,Default,,0,0,0,,为了这些过程存在于在同一个Lisp环境中 Dialogue: 0,0:20:44.22,0:20:45.92,Default,,0,0,0,,George就要修改他的过程名字 Dialogue: 0,0:20:45.92,0:20:49.14,Default,,0,0,0,,那么我们说 这是George的real-part过程 Dialogue: 0,0:20:49.14,0:20:51.16,Default,,0,0,0,,叫做real-part-rectangular过程 Dialogue: 0,0:20:51.48,0:20:54.06,Default,,0,0,0,,还有 imag-part-rectangular过程 Dialogue: 0,0:20:55.42,0:20:57.24,Default,,0,0,0,,那么这里是George的程序包剩下的部分 Dialogue: 0,0:20:59.13,0:21:02.06,Default,,0,0,0,,他已经有了magnitude和angle过程 只要把它们改名 Dialogue: 0,0:21:02.06,0:21:04.16,Default,,0,0,0,,叫magnitude-rectangular和angle-rectangular就好了 Dialogue: 0,0:21:06.08,0:21:07.96,Default,,0,0,0,,Martha要做的事情基本相同 Dialogue: 0,0:21:09.86,0:21:16.22,Default,,0,0,0,,在这之前 当她用模和辐角构造复数的时候 Dialogue: 0,0:21:18.14,0:21:19.27,Default,,0,0,0,,她只是把这两个东西cons起来 Dialogue: 0,0:21:19.27,0:21:20.86,Default,,0,0,0,,现在她额外附加类型 polar Dialogue: 0,0:21:23.95,0:21:25.61,Default,,0,0,0,,然后修改过程的名字 Dialogue: 0,0:21:25.66,0:21:29.85,Default,,0,0,0,,来避免保证她的real-part过程和George的产生冲突 Dialogue: 0,0:21:30.71,0:21:32.99,Default,,0,0,0,,分别改为real-part-polar和imaginary-part-polar Dialogue: 0,0:21:34.54,0:21:38.06,Default,,0,0,0,,magnitude-polar和angle-polar这四个过程 Dialogue: 0,0:21:45.00,0:21:46.13,Default,,0,0,0,,现在我们的系统 Dialogue: 0,0:21:46.13,0:21:47.92,Default,,0,0,0,,在它里面既有George又有Martha Dialogue: 0,0:21:49.16,0:21:51.68,Default,,0,0,0,,然后现在我们需要一个经理来对类型进行判断 Dialogue: 0,0:21:52.83,0:21:56.48,Default,,0,0,0,,那么在George和Martha给我们提供了类型数据之后 Dialogue: 0,0:21:57.05,0:21:59.40,Default,,0,0,0,,这个系统现在怎么工作呢? Dialogue: 0,0:22:00.53,0:22:04.30,Default,,0,0,0,,我们手里有的 是一堆通用选择函数 Dialogue: 0,0:22:05.26,0:22:10.63,Default,,0,0,0,,用于复数的通用选择函数比如 real-part、imag-part、magnitude和angle等 Dialogue: 0,0:22:14.14,0:22:15.40,Default,,0,0,0,,让我们更进一步观察它们 Dialogue: 0,0:22:17.93,0:22:19.00,Default,,0,0,0,,real-part过程应该做什么 Dialogue: 0,0:22:19.31,0:22:22.76,Default,,0,0,0,,如果我想得到一个复数的实部 Dialogue: 0,0:22:24.07,0:22:24.91,Default,,0,0,0,,那么我先要观察它 Dialogue: 0,0:22:25.80,0:22:26.69,Default,,0,0,0,,我观察它的类型 Dialogue: 0,0:22:26.69,0:22:28.12,Default,,0,0,0,,考虑它是用直角坐标表示的吗 Dialogue: 0,0:22:31.02,0:22:35.36,Default,,0,0,0,,如果是的话 我就对这个复数的"内容"部分 Dialogue: 0,0:22:36.06,0:22:37.92,Default,,0,0,0,,调用George的real-part过程 Dialogue: 0,0:22:41.07,0:22:42.94,Default,,0,0,0,,这是一个带有类型的数字 Dialogue: 0,0:22:43.72,0:22:47.66,Default,,0,0,0,,我用contents过程剥掉类型 并且对它应用George的过程 Dialogue: 0,0:22:50.70,0:22:52.86,Default,,0,0,0,,那如果是一个用极坐标表示的复数呢? Dialogue: 0,0:22:53.95,0:22:54.97,Default,,0,0,0,,如果我想要得到它的实部 Dialogue: 0,0:22:55.45,0:22:58.78,Default,,0,0,0,,我就把Martha的real-part过程应用在这个数的内容上 Dialogue: 0,0:22:59.85,0:23:01.15,Default,,0,0,0,,这就是real-part工作的方式 Dialogue: 0,0:23:02.26,0:23:05.66,Default,,0,0,0,,还有类似的imag-part过程 几乎是一样的 Dialogue: 0,0:23:06.51,0:23:09.60,Default,,0,0,0,,它先观察这个数字 它是直角坐标表示的 Dialogue: 0,0:23:09.60,0:23:11.13,Default,,0,0,0,,就调用George的imaginary-part过程 Dialogue: 0,0:23:11.13,0:23:12.83,Default,,0,0,0,,是极坐标表示的 就用Martha的过程 Dialogue: 0,0:23:13.38,0:23:17.40,Default,,0,0,0,,同理也可以构造出magnitude和angle两个过程 Dialogue: 0,0:23:19.71,0:23:21.02,Default,,0,0,0,,我们的系统是这个样子 Dialogue: 0,0:23:23.00,0:23:24.26,Default,,0,0,0,,它里面有三个部分 Dialogue: 0,0:23:24.26,0:23:26.59,Default,,0,0,0,,有George、Martha和一个经理 Dialogue: 0,0:23:26.76,0:23:28.97,Default,,0,0,0,,这就是实现通用操作符的方法 Dialogue: 0,0:23:28.97,0:23:32.92,Default,,0,0,0,,为了把它说清楚 我们举一个简单的实例 Dialogue: 0,0:23:33.50,0:23:35.12,Default,,0,0,0,,但是准确描述了它工作的方式 Dialogue: 0,0:23:36.54,0:23:43.98,Default,,0,0,0,,假设你现在 面对一个实部是1 Dialogue: 0,0:23:44.52,0:23:46.09,Default,,0,0,0,,虚部是2的复数 Dialogue: 0,0:23:46.09,0:23:48.44,Default,,0,0,0,,也就是1+2i Dialogue: 0,0:23:50.31,0:23:52.64,Default,,0,0,0,,现在在这里 Dialogue: 0,0:23:55.28,0:23:57.53,Default,,0,0,0,,在操作发生的上层 Dialogue: 0,0:23:57.63,0:24:08.27,Default,,0,0,0,,复数被表示成一个由1和2组成的序对加上类型信息 Dialogue: 0,0:24:10.48,0:24:11.39,Default,,0,0,0,,(1和2)是内容 Dialogue: 0,0:24:11.87,0:24:17.96,Default,,0,0,0,,整个的数据就是在那之上加上一个rectangular符号 Dialogue: 0,0:24:18.14,0:24:21.53,Default,,0,0,0,,这就是复数在这个系统里存在的形式 Dialogue: 0,0:24:22.33,0:24:24.92,Default,,0,0,0,,你要调取real-part的时候 Dialogue: 0,0:24:25.84,0:24:28.89,Default,,0,0,0,,经理会检查这个数然后说 这是George构造的数字 Dialogue: 0,0:24:30.27,0:24:31.53,Default,,0,0,0,,他会先把类型拿掉 Dialogue: 0,0:24:33.34,0:24:36.91,Default,,0,0,0,,然后把 (1,2) 这个序对传递给George Dialogue: 0,0:24:38.00,0:24:42.27,Default,,0,0,0,,这是George的系统可以直接处理的数据 Dialogue: 0,0:24:44.36,0:24:45.92,Default,,0,0,0,,那么它被拆了出来 Dialogue: 0,0:24:46.52,0:24:49.76,Default,,0,0,0,,之后 如果你让George构造一个复数 Dialogue: 0,0:24:51.24,0:24:54.56,Default,,0,0,0,,George就会把它构造成序对 Dialogue: 0,0:24:55.07,0:24:58.24,Default,,0,0,0,,在数据被传递到上层之前 Dialogue: 0,0:24:59.42,0:25:01.13,Default,,0,0,0,,经理会再给它加上rectangular类型 Dialogue: 0,0:25:03.92,0:25:04.65,Default,,0,0,0,,看这个过程 Dialogue: 0,0:25:04.65,0:25:05.85,Default,,0,0,0,,这个系统不会发生混乱 Dialogue: 0,0:25:05.85,0:25:10.84,Default,,0,0,0,,就算在Martha的世界里 序对(1 2)的含义完全不同 Dialogue: 0,0:25:13.50,0:25:15.75,Default,,0,0,0,,也并没有什么影响 Dialogue: 0,0:25:15.75,0:25:18.44,Default,,0,0,0,,在Martha的世界里这个序对代表了 Dialogue: 0,0:25:18.44,0:25:20.78,Default,,0,0,0,,一个模为1 辐角为2的复数 Dialogue: 0,0:25:21.19,0:25:22.19,Default,,0,0,0,,但是这并不会造成混乱 Dialogue: 0,0:25:22.22,0:25:27.25,Default,,0,0,0,,因为每当有一个这样的序对经由经理之手 Dialogue: 0,0:25:27.25,0:25:29.61,Default,,0,0,0,,被交给主系统的时候 它都会被附加上polar的类型标志 Dialogue: 0,0:25:31.21,0:25:33.67,Default,,0,0,0,,而这个就会被贴上rectangular类型的标签 Dialogue: 0,0:25:36.93,0:25:37.90,Default,,0,0,0,,好 我们休息一下 Dialogue: 0,0:25:40.77,0:25:55.55,Default,,0,0,0,,[音乐] Dialogue: 0,0:25:55.69,0:25:57.77,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:25:57.77,0:25:59.76,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:26:05.21,0:26:11.95,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:26:12.84,0:26:16.75,Declare,,0,0,0,,{\an2\fad(500,500)}通用运算符 Dialogue: 0,0:26:20.21,0:26:24.15,Default,,0,0,0,,我们刚刚提出了一种实现通用运算符的策略 Dialogue: 0,0:26:24.15,0:26:31.40,Default,,0,0,0,,这种策略有一个名字 叫做“基于类型的分派” Dialogue: 0,0:26:34.31,0:26:39.36,Default,,0,0,0,,它的想法就是你要把你的系统分成很多小块 Dialogue: 0,0:26:39.36,0:26:42.67,Default,,0,0,0,,里面有George和Martha在设计表示方法 Dialogue: 0,0:26:43.37,0:26:44.38,Default,,0,0,0,,还有一个经理 Dialogue: 0,0:26:46.12,0:26:48.06,Default,,0,0,0,,负责去看数据上的类型是什么 Dialogue: 0,0:26:48.51,0:26:50.59,Default,,0,0,0,,然后分派给正确的人去处理 Dialogue: 0,0:26:51.99,0:26:56.01,Default,,0,0,0,,这种组织系统的方法有什么缺点呢? Dialogue: 0,0:26:58.15,0:27:00.40,Default,,0,0,0,,首先 有个小小的烦人的问题 Dialogue: 0,0:27:00.40,0:27:03.05,Default,,0,0,0,,George和Martha需要修改他们的过程的名字 Dialogue: 0,0:27:04.00,0:27:05.95,Default,,0,0,0,,George一开始写了一个real-part过程 Dialogue: 0,0:27:05.98,0:27:08.28,Default,,0,0,0,,现在他必须把它的名字改成real-part-rectangular Dialogue: 0,0:27:08.30,0:27:10.83,Default,,0,0,0,,才能让它不与Martha的real-part过程相互冲突 Dialogue: 0,0:27:10.84,0:27:12.76,Default,,0,0,0,,而Martha的过程现在改叫real-part-polar Dialogue: 0,0:27:13.64,0:27:16.68,Default,,0,0,0,,这是为了不和经理的那个叫做real-part的过程发生冲突 Dialogue: 0,0:27:17.31,0:27:18.94,Default,,0,0,0,,这个问题确实很恼人 Dialogue: 0,0:27:19.46,0:27:21.13,Default,,0,0,0,,但是我现在暂时不讨论这个问题 Dialogue: 0,0:27:21.27,0:27:22.35,Default,,0,0,0,,我们稍后将会看到 Dialogue: 0,0:27:23.26,0:27:26.12,Default,,0,0,0,,在讨论到Lisp名称与环境的结构的时候 Dialogue: 0,0:27:26.12,0:27:30.39,Default,,0,0,0,,我们会有方法把这些所谓的命名空间分开来封装 Dialogue: 0,0:27:30.39,0:27:31.56,Default,,0,0,0,,然后它们就不会互相影响了 Dialogue: 0,0:27:32.50,0:27:34.01,Default,,0,0,0,,现在我们暂时不去考虑这个问题 Dialogue: 0,0:27:35.72,0:27:38.19,Default,,0,0,0,,我现在想关注的问题是 Dialogue: 0,0:27:38.36,0:27:43.24,Default,,0,0,0,,你把一个新人招纳进系统之中会发生什么 Dialogue: 0,0:27:44.51,0:27:45.32,Default,,0,0,0,,会发生什么? Dialogue: 0,0:27:45.32,0:27:46.81,Default,,0,0,0,,George和Martha并不关心 Dialogue: 0,0:27:47.42,0:27:50.73,Default,,0,0,0,,George在他的直角坐标世界里 Dialogue: 0,0:27:52.20,0:27:53.84,Default,,0,0,0,,坐拥着他的过程和数据类型 Dialogue: 0,0:27:54.09,0:27:55.74,Default,,0,0,0,,而Martha待在她的极坐标世界中 Dialogue: 0,0:27:55.93,0:27:57.02,Default,,0,0,0,,不问世事 Dialogue: 0,0:27:59.38,0:28:00.54,Default,,0,0,0,,但是经理呢? Dialogue: 0,0:28:00.62,0:28:02.84,Default,,0,0,0,,经理需要做什么? Dialogue: 0,0:28:03.18,0:28:06.20,Default,,0,0,0,,现在经理带着他的运算来了 Dialogue: 0,0:28:07.36,0:28:09.04,Default,,0,0,0,,有直角坐标的判断 Dialogue: 0,0:28:09.04,0:28:10.14,Default,,0,0,0,,和极坐标的判断过程 Dialogue: 0,0:28:10.14,0:28:14.91,Default,,0,0,0,,如果Harry带着某种新型的复数表示方法 进入这个系统 Dialogue: 0,0:28:17.21,0:28:19.96,Default,,0,0,0,,同时带来了一个新的类型--Harry型复数 Dialogue: 0,0:28:20.27,0:28:23.28,Default,,0,0,0,,经理就需要修改他所有的过程 Dialogue: 0,0:28:25.24,0:28:26.94,Default,,0,0,0,,所以这个系统的不灵活之处 Dialogue: 0,0:28:26.96,0:28:32.41,Default,,0,0,0,,也就是需要大量工作才能适应变化的地方 就在这个经理身上 Dialogue: 0,0:28:34.89,0:28:35.99,Default,,0,0,0,,那是非常恼人的事情 Dialogue: 0,0:28:35.99,0:28:37.21,Default,,0,0,0,,更恼人的是 Dialogue: 0,0:28:39.05,0:28:41.21,Default,,0,0,0,,你意识到这个经理实际上什么也不做 Dialogue: 0,0:28:42.59,0:28:44.67,Default,,0,0,0,,这个经理只负责“传递公文”而已 Dialogue: 0,0:28:45.84,0:28:51.13,Default,,0,0,0,,我们再来看看这些程序 它们在做什么 Dialogue: 0,0:28:51.76,0:28:52.72,Default,,0,0,0,,real-part过程在做什么 Dialogue: 0,0:28:52.88,0:28:56.17,Default,,0,0,0,,这个过程说 哦 这个复数是 Dialogue: 0,0:28:56.17,0:28:57.00,Default,,0,0,0,,George会处理的那一种吗 Dialogue: 0,0:28:57.00,0:28:58.27,Default,,0,0,0,,如果是的话 好 把它交给George处理 Dialogue: 0,0:28:59.41,0:29:01.76,Default,,0,0,0,,它是Martha能操作的那一种吗 Dialogue: 0,0:29:01.82,0:29:04.06,Default,,0,0,0,,是的话 把它交给Martha处理 Dialogue: 0,0:29:05.04,0:29:08.72,Default,,0,0,0,,这个系统真正恼人之处 也就是这个系统的瓶颈 Dialogue: 0,0:29:08.72,0:29:11.66,Default,,0,0,0,,它降低灵活性 阻碍变化 Dialogue: 0,0:29:12.09,0:29:14.36,Default,,0,0,0,,完全是一种的官僚主义 Dialogue: 0,0:29:15.00,0:29:17.02,Default,,0,0,0,,而不是任何做实事的人 Dialogue: 0,0:29:19.70,0:29:21.80,Default,,0,0,0,,很可惜这种情况经常发生 Dialogue: 0,0:29:23.18,0:29:24.41,Default,,0,0,0,,实际上发生的事情是 Dialogue: 0,0:29:24.48,0:29:26.97,Default,,0,0,0,,在系统中 有一张抽象的表格 Dialogue: 0,0:29:28.10,0:29:30.08,Default,,0,0,0,,实际发生的事情是 有这样一张表格 Dialogue: 0,0:29:30.84,0:29:33.64,Default,,0,0,0,,其中有各种类型 Dialogue: 0,0:29:34.40,0:29:38.96,Default,,0,0,0,,有polar和rectangular Dialogue: 0,0:29:41.55,0:29:43.02,Default,,0,0,0,,可能Harry也在这里 Dialogue: 0,0:29:44.38,0:29:46.56,Default,,0,0,0,,然后这里是各种运算符 Dialogue: 0,0:29:48.05,0:29:58.24,Default,,0,0,0,,各种运算符 比如real-part和imag-part Dialogue: 0,0:30:00.01,0:30:04.22,Default,,0,0,0,,还有magnitude、angle这些运算符 Dialogue: 0,0:30:05.83,0:30:18.97,Default,,0,0,0,,单元格中对应的是相应过程 Dialogue: 0,0:30:19.28,0:30:21.99,Default,,0,0,0,,那么填在这里 负责polar类型的real-part过程的是 Dialogue: 0,0:30:21.99,0:30:27.56,Default,,0,0,0,,Martha的real-part-polar过程 Dialogue: 0,0:30:30.57,0:30:36.62,Default,,0,0,0,,然后在这里是George的real-part-rectangular过程 Dialogue: 0,0:30:37.74,0:30:43.07,Default,,0,0,0,,然后这里是Martha的magnitude-polar过程 Dialogue: 0,0:30:44.46,0:30:49.76,Default,,0,0,0,,然后是George的magnitude-rectangular过程 等等等等 Dialogue: 0,0:30:49.76,0:30:51.24,Default,,0,0,0,,剩下的单元格也像这样填好 Dialogue: 0,0:30:52.39,0:30:54.26,Default,,0,0,0,,这就是实际上发生的事情 Dialogue: 0,0:30:57.63,0:31:01.74,Default,,0,0,0,,从某种意义上讲 经理做的事情就是 Dialogue: 0,0:31:02.11,0:31:04.11,Default,,0,0,0,,去扮演这张表格 Dialogue: 0,0:31:06.86,0:31:08.70,Default,,0,0,0,,那我们怎么去修补这个系统呢 Dialogue: 0,0:31:11.74,0:31:13.77,Default,,0,0,0,,怎么去消灭这种官僚主义? Dialogue: 0,0:31:13.77,0:31:15.44,Default,,0,0,0,,你要做的就是让这个经理走人 Dialogue: 0,0:31:16.01,0:31:19.55,Default,,0,0,0,,我们用一台计算机来代替他 Dialogue: 0,0:31:20.17,0:31:21.76,Default,,0,0,0,,我们要让自动操作抹掉他存在的意义 Dialogue: 0,0:31:23.32,0:31:26.57,Default,,0,0,0,,也就是说 我们不用这个经理去查阅这个表格 Dialogue: 0,0:31:27.45,0:31:29.32,Default,,0,0,0,,而是让我们的系统直接去查阅它 Dialogue: 0,0:31:31.02,0:31:32.11,Default,,0,0,0,,这是什么意思呢? Dialogue: 0,0:31:32.11,0:31:36.19,Default,,0,0,0,,我们来假设 还是用数据抽象的观点 Dialogue: 0,0:31:37.71,0:31:40.40,Default,,0,0,0,,我们有这样一种表格数据结构 Dialogue: 0,0:31:40.88,0:31:43.61,Default,,0,0,0,,而且我们还有把东西填进去和从中删除的方法 Dialogue: 0,0:31:44.35,0:31:49.04,Default,,0,0,0,,为了把话说清楚 我们假设现在有一个叫put的方法 Dialogue: 0,0:31:50.30,0:31:58.32,Default,,0,0,0,,本例中put方法接受两个参数 -- 我们称其为“关键字” -- key1和key2 Dialogue: 0,0:32:00.13,0:32:00.99,Default,,0,0,0,,还有接受一个值 Dialogue: 0,0:32:06.20,0:32:11.12,Default,,0,0,0,,put过程把value存放在表格key1和key2对应的格子里 Dialogue: 0,0:32:11.49,0:32:13.16,Default,,0,0,0,,然后我们假设有另一个叫get的过程 Dialogue: 0,0:32:15.23,0:32:18.72,Default,,0,0,0,,它是这样的一个东西 如果我说把表格里 Dialogue: 0,0:32:19.40,0:32:22.76,Default,,0,0,0,,存储在key1和key2对应的格子中的数据给我 Dialogue: 0,0:32:23.40,0:32:25.39,Default,,0,0,0,,它会把存储在那里的东西返回给我 Dialogue: 0,0:32:26.73,0:32:29.44,Default,,0,0,0,,我们先不要担心这个表格怎么实现 Dialogue: 0,0:32:30.00,0:32:32.52,Default,,0,0,0,,那又是另一个数据抽象了 是George需要考虑的问题 Dialogue: 0,0:32:33.06,0:32:34.36,Default,,0,0,0,,也许稍后我们还会看到 Dialogue: 0,0:32:34.70,0:32:36.97,Default,,0,0,0,,我们还会讨论怎么用Lisp建立这个表格 Dialogue: 0,0:32:40.71,0:32:45.50,Default,,0,0,0,,我们有了这个组织结构 George和Martha需要做什么呢? Dialogue: 0,0:32:47.38,0:32:49.07,Default,,0,0,0,,当他们构建自己的系统的时候 Dialogue: 0,0:32:49.13,0:32:51.08,Default,,0,0,0,,都有责任在表格里 Dialogue: 0,0:32:51.44,0:32:53.82,Default,,0,0,0,,正确地添加上自己的那一列 Dialogue: 0,0:32:55.21,0:32:57.47,Default,,0,0,0,,比如说 对于George Dialogue: 0,0:32:59.79,0:33:02.06,Default,,0,0,0,,当他定义过程的时候 他需要做的就是 Dialogue: 0,0:33:02.27,0:33:07.99,Default,,0,0,0,,把它们放进表格中的rectangular类型的那一列下面 Dialogue: 0,0:33:09.82,0:33:12.12,Default,,0,0,0,,然后操作的名字是real-part Dialogue: 0,0:33:13.31,0:33:15.26,Default,,0,0,0,,放入他的real-part-rectangular过程 Dialogue: 0,0:33:16.25,0:33:17.78,Default,,0,0,0,,注意有什么被放到了表格里 Dialogue: 0,0:33:17.78,0:33:22.10,Default,,0,0,0,,这里的两个key是这两个符号:rectangular和real-part Dialogue: 0,0:33:22.10,0:33:22.75,Default,,0,0,0,,这是引用 Dialogue: 0,0:33:24.40,0:33:26.75,Default,,0,0,0,,要被填到表里的东西 Dialogue: 0,0:33:26.84,0:33:29.21,Default,,0,0,0,,是他编写的real-part-rectangular过程 Dialogue: 0,0:33:31.85,0:33:34.30,Default,,0,0,0,,然后把这个获取虚部的过程也放进表里 Dialogue: 0,0:33:34.59,0:33:37.80,Default,,0,0,0,,分类到rectangular和imag-part两个关键字之下 Dialogue: 0,0:33:38.62,0:33:42.88,Default,,0,0,0,,获取模值的过程放到rectangular和magnitude下面 Dialogue: 0,0:33:43.61,0:33:45.20,Default,,0,0,0,,获取辐角的过程放到rectangular和angle下面 Dialogue: 0,0:33:47.04,0:33:50.84,Default,,0,0,0,,George作为系统的一部分 就要做以上这些事情 Dialogue: 0,0:33:54.42,0:33:58.86,Default,,0,0,0,,Martha用同样的方法填好表格中关于polar的这一列 Dialogue: 0,0:33:59.43,0:34:00.65,Default,,0,0,0,,在polar和real-part对应的这一栏 Dialogue: 0,0:34:01.69,0:34:03.58,Default,,0,0,0,,应该填的过程是real-part-polar是吧? Dialogue: 0,0:34:04.34,0:34:07.29,Default,,0,0,0,,然后分别是imag-part、magnitude和angle过程 Dialogue: 0,0:34:08.91,0:34:11.40,Default,,0,0,0,,Martha想要加入系统当中就要做这些事情 Dialogue: 0,0:34:11.40,0:34:13.55,Default,,0,0,0,,每个设计了数据表示的人 Dialogue: 0,0:34:13.55,0:34:17.63,Default,,0,0,0,,都必须在表格里设置自己的一列 Dialogue: 0,0:34:17.76,0:34:19.90,Default,,0,0,0,,那么Harry带着他的绝妙的复数实现方法 Dialogue: 0,0:34:19.90,0:34:21.80,Default,,0,0,0,,过来的时候 他需要做什么呢 Dialogue: 0,0:34:21.80,0:34:23.96,Default,,0,0,0,,他先把过程写好 Dialogue: 0,0:34:24.04,0:34:26.52,Default,,0,0,0,,然后在表格里再建立一列 Dialogue: 0,0:34:28.55,0:34:30.04,Default,,0,0,0,,那么现在经理怎么样了呢 Dialogue: 0,0:34:31.33,0:34:34.61,Default,,0,0,0,,经理的存在被自动操作所取代 Dialogue: 0,0:34:34.61,0:34:37.11,Default,,0,0,0,,被一个叫做operate的过程代替 Dialogue: 0,0:34:37.11,0:34:39.55,Default,,0,0,0,,这是这个系统最关键的一个过程 Dialogue: 0,0:34:40.38,0:34:45.92,Default,,0,0,0,,(define operate Dialogue: 0,0:34:51.06,0:34:56.09,Default,,0,0,0,,Operate过程接收你想要采取的运算 Dialogue: 0,0:34:57.75,0:34:58.88,Default,,0,0,0,,应该说是这个运算的名字 Dialogue: 0,0:34:59.20,0:35:03.28,Default,,0,0,0,,和被运算的对象 Dialogue: 0,0:35:04.21,0:35:09.76,Default,,0,0,0,,那么举例来说 对一个复数调用real-part operate过程会做什么呢 Dialogue: 0,0:35:09.95,0:35:11.90,Default,,0,0,0,,它要做的第一件事就是去查表 Dialogue: 0,0:35:12.64,0:35:13.87,Default,,0,0,0,,它查询这个表格 Dialogue: 0,0:35:14.80,0:35:22.56,Default,,0,0,0,,试图去找到存储在表格里的一个过程 Dialogue: 0,0:35:23.15,0:35:24.80,Default,,0,0,0,,所以它要对表格调用get过程 Dialogue: 0,0:35:25.50,0:35:33.92,Default,,0,0,0,,用对象的类型和运算的名称作为关键字进行检索 Dialogue: 0,0:35:38.92,0:35:40.14,Default,,0,0,0,,这样就可以知道在表格中 Dialogue: 0,0:35:40.38,0:35:42.72,Default,,0,0,0,,与数据的类型和要进行的运算相对应的是什么了 Dialogue: 0,0:35:42.89,0:35:44.35,Default,,0,0,0,,对应的这一格里填了什么东西 Dialogue: 0,0:35:44.44,0:35:45.93,Default,,0,0,0,,我们假设get过程已经被实现好了 Dialogue: 0,0:35:45.93,0:35:47.72,Default,,0,0,0,,所以如果在那一格什么也没有 Dialogue: 0,0:35:48.11,0:35:51.79,Default,,0,0,0,,它就会返回一个空表 Dialogue: 0,0:35:52.67,0:35:55.39,Default,,0,0,0,,如果那里确实有什么东西 Dialogue: 0,0:35:56.62,0:36:00.43,Default,,0,0,0,,如果存储有这样的一个过程 Dialogue: 0,0:36:03.15,0:36:07.12,Default,,0,0,0,,那么就会把在表格里找到的这个过程 Dialogue: 0,0:36:09.79,0:36:15.00,Default,,0,0,0,,应用到对象的具体内容上去 Dialogue: 0,0:36:18.25,0:36:20.40,Default,,0,0,0,,如果那里没有东西的话 Dialogue: 0,0:36:20.67,0:36:22.51,Default,,0,0,0,,它就会 -- 我们可以决定 Dialogue: 0,0:36:22.81,0:36:27.12,Default,,0,0,0,,本例中 我们让它输出一个错误消息:“未定义的运算符” Dialogue: 0,0:36:28.48,0:36:30.24,Default,,0,0,0,,没有支持这种类型的运算符 Dialogue: 0,0:36:33.07,0:36:34.72,Default,,0,0,0,,或者其它合适的错误信息 Dialogue: 0,0:36:39.07,0:36:39.48,Default,,0,0,0,,对吧? Dialogue: 0,0:36:39.72,0:36:41.04,Default,,0,0,0,,这个东西替代了经理 Dialogue: 0,0:36:41.89,0:36:42.91,Default,,0,0,0,,我们怎么去使用它呢 Dialogue: 0,0:36:43.96,0:36:49.80,Default,,0,0,0,,我们的想法是用operate过程来定义通用选择函数 Dialogue: 0,0:36:50.04,0:36:56.75,Default,,0,0,0,,我们可以说一个对象的real-part Dialogue: 0,0:36:57.14,0:37:05.66,Default,,0,0,0,,是这个对象被operate应用了叫做real-part的运算后得到的结果 Dialogue: 0,0:37:08.07,0:37:12.22,Default,,0,0,0,,那么类似地 imag-part是operate对obj应用imag-part运算 Dialogue: 0,0:37:12.22,0:37:13.98,Default,,0,0,0,,magnitude和angle同理 Dialogue: 0,0:37:15.36,0:37:17.43,Default,,0,0,0,,这就是我们的实现方法 Dialogue: 0,0:37:17.43,0:37:20.48,Default,,0,0,0,,由它们加上类型再加上operate过程组成 Dialogue: 0,0:37:21.33,0:37:24.00,Default,,0,0,0,,这个表格现在就有效地完成了之前经理的工作 Dialogue: 0,0:37:24.06,0:37:27.69,Default,,0,0,0,,我们来梳理一下在这个过程中发生的事情 Dialogue: 0,0:37:27.90,0:37:33.00,Default,,0,0,0,,假设我有一个由Martha构造的复数 Dialogue: 0,0:37:33.53,0:37:38.80,Default,,0,0,0,,它的模值是1 辐角是2 Dialogue: 0,0:37:39.10,0:37:40.22,Default,,0,0,0,,它是由Martha构造的 Dialogue: 0,0:37:40.22,0:37:45.45,Default,,0,0,0,,所以它被贴上了polar的标签 Dialogue: 0,0:37:47.24,0:37:48.00,Default,,0,0,0,,我们叫它z Dialogue: 0,0:37:48.00,0:37:48.91,Default,,0,0,0,,假设这就是z Dialogue: 0,0:37:51.77,0:37:54.46,Default,,0,0,0,,然后假设在这种实现方法下 Dialogue: 0,0:37:54.80,0:37:57.92,Default,,0,0,0,,有人想要取z的实部 Dialogue: 0,0:38:04.87,0:38:07.96,Default,,0,0,0,,由于real-part现在是用operate来定义的 Dialogue: 0,0:38:09.16,0:38:10.57,Default,,0,0,0,,这就等同于说 Dialogue: 0,0:38:12.09,0:38:24.81,Default,,0,0,0,,调用 (operate 'real-part z) Dialogue: 0,0:38:27.06,0:38:28.09,Default,,0,0,0,,然后operate过程 Dialogue: 0,0:38:28.09,0:38:29.24,Default,,0,0,0,,就会去查询表格 Dialogue: 0,0:38:31.04,0:38:34.36,Default,,0,0,0,,然后试图去寻找在表格里存放的 Dialogue: 0,0:38:39.00,0:38:46.22,Default,,0,0,0,,查询表格中与对象的类型相对应的一列 Dialogue: 0,0:38:46.72,0:38:48.22,Default,,0,0,0,,那么z的类型是polar Dialogue: 0,0:38:48.79,0:38:51.37,Default,,0,0,0,,所以它就要说 我用polar作为关键字查表 Dialogue: 0,0:38:52.99,0:38:58.57,Default,,0,0,0,,然后运算的名称是real-part Dialogue: 0,0:39:05.96,0:39:13.63,Default,,0,0,0,,它查询对应的过程 然后应用到z的内容上去 Dialogue: 0,0:39:14.83,0:39:17.13,Default,,0,0,0,,如果所有东西都安排妥当的话 Dialogue: 0,0:39:17.74,0:39:21.70,Default,,0,0,0,,如果它找到的过程就是Martha编写的过程 Dialogue: 0,0:39:21.70,0:39:22.95,Default,,0,0,0,,也就是real-part-polar Dialogue: 0,0:39:31.05,0:39:35.13,Default,,0,0,0,,然后这就是z去掉类型之后的东西 Dialogue: 0,0:39:35.44,0:39:38.94,Default,,0,0,0,,是Martha最初设计的数据表示 Dialogue: 0,0:39:39.40,0:39:40.43,Default,,0,0,0,,也就是这里的(1 2) Dialogue: 0,0:39:43.71,0:39:45.87,Default,,0,0,0,,所以说在整个系统中 operate过程 Dialogue: 0,0:39:46.46,0:39:48.89,Default,,0,0,0,,和之前的经理做的事情没什么区别 Dialogue: 0,0:39:49.45,0:39:52.59,Default,,0,0,0,,它通过查询表格找到正确的东西 然后剥离类型 Dialogue: 0,0:39:53.58,0:39:57.52,Default,,0,0,0,,然后把它传递给能够处理它的人 Dialogue: 0,0:39:58.88,0:40:05.48,Default,,0,0,0,,你会发现 这是另一种 在大多数情况下 Dialogue: 0,0:40:06.22,0:40:08.04,Default,,0,0,0,,更灵活地实现通用运算符的方法 Dialogue: 0,0:40:08.08,0:40:15.69,Default,,0,0,0,,我们把它叫做“数据导向编程” Dialogue: 0,0:40:20.35,0:40:21.96,Default,,0,0,0,,其理念是 Dialogue: 0,0:40:23.42,0:40:25.55,Default,,0,0,0,,在某种意义上 这些数据对象本身 Dialogue: 0,0:40:26.04,0:40:28.35,Default,,0,0,0,,这些充斥在系统中的复数 Dialogue: 0,0:40:28.73,0:40:33.16,Default,,0,0,0,,它们自身就携带着 关于应该怎么去操作它们的信息 Dialogue: 0,0:40:35.74,0:40:36.78,Default,,0,0,0,,有什么疑问吗? Dialogue: 0,0:40:41.00,0:40:41.24,Default,,0,0,0,,请说 Dialogue: 0,0:40:41.24,0:40:43.39,Default,,0,0,0,,学生:你在那个数据对象里存储的是什么呢 Dialogue: 0,0:40:43.39,0:40:47.10,Default,,0,0,0,,这里面有这个数据本身 还有它的类型 Dialogue: 0,0:40:47.10,0:40:49.60,Default,,0,0,0,,还有该与该类型对应的运算 Dialogue: 0,0:40:49.69,0:40:53.08,Default,,0,0,0,,或者说那些运算是存储在哪里呢? Dialogue: 0,0:40:53.60,0:40:54.17,Default,,0,0,0,,教授:好 让我-- Dialogue: 0,0:40:54.98,0:40:56.50,Default,,0,0,0,,恩 这是一个好问题 Dialogue: 0,0:40:56.50,0:41:00.46,Default,,0,0,0,,通过它暗示了实现我们目标的 其它可行方法 Dialogue: 0,0:41:00.75,0:41:02.48,Default,,0,0,0,,当然可能的方法有很多 Dialogue: 0,0:41:04.20,0:41:06.14,Default,,0,0,0,,在这个特定的实现当中 Dialogue: 0,0:41:06.24,0:41:09.72,Default,,0,0,0,,在这个数据对象里放着 Dialogue: 0,0:41:10.44,0:41:13.45,Default,,0,0,0,,就是数据本身 本例中是序对(1, 2) Dialogue: 0,0:41:14.98,0:41:16.55,Default,,0,0,0,,和一个符号 Dialogue: 0,0:41:16.55,0:41:19.07,Default,,0,0,0,,就是这个符号 单词P-O-L-A-R Dialogue: 0,0:41:20.60,0:41:22.33,Default,,0,0,0,,这些就是这个数据对象里面的东西 Dialogue: 0,0:41:24.24,0:41:26.69,Default,,0,0,0,,那么这些运算又是存放在哪里的呢? Dialogue: 0,0:41:26.69,0:41:29.00,Default,,0,0,0,,那些运算在表格里 Dialogue: 0,0:41:29.85,0:41:31.07,Default,,0,0,0,,在这个表格里 Dialogue: 0,0:41:32.30,0:41:36.46,Default,,0,0,0,,所有行和列的名字都是符号 Dialogue: 0,0:41:38.23,0:41:40.08,Default,,0,0,0,,所以当我往里面存什么东西的时候 Dialogue: 0,0:41:40.09,0:41:47.02,Default,,0,0,0,,可以以符号polar或符号magnitude作为关键字 Dialogue: 0,0:41:48.24,0:41:51.31,Default,,0,0,0,,我这样写 可能让你们感到困惑了 Dialogue: 0,0:41:51.31,0:41:52.70,Default,,0,0,0,,因为在这里面放的并不是 Dialogue: 0,0:41:53.16,0:41:54.57,Default,,0,0,0,,当我写下mag-polar的时候 Dialogue: 0,0:41:57.04,0:41:59.23,Default,,0,0,0,,我指的是那个叫mag-polar的过程 Dialogue: 0,0:41:59.85,0:42:01.85,Default,,0,0,0,,可能 我本来应该在这里写上 Dialogue: 0,0:42:02.58,0:42:04.20,Default,,0,0,0,,但是这里空间太小了 Dialogue: 0,0:42:04.20,0:42:05.07,Default,,0,0,0,,我写不下 Dialogue: 0,0:42:05.58,0:42:08.92,Default,,0,0,0,,应该写成lambda(z) Dialogue: 0,0:42:10.60,0:42:12.75,Default,,0,0,0,,然后调用Martha实现的过程 Dialogue: 0,0:42:14.71,0:42:15.72,Default,,0,0,0,,你也可以从这里看出 Dialogue: 0,0:42:15.74,0:42:17.44,Default,,0,0,0,,我已经暗示了另一种方法 Dialogue: 0,0:42:17.71,0:42:19.82,Default,,0,0,0,,来解决名字冲突的问题 Dialogue: 0,0:42:20.04,0:42:23.15,Default,,0,0,0,,那就是George和Martha根本不用给他们的过程起名字 Dialogue: 0,0:42:23.15,0:42:25.37,Default,,0,0,0,,可以直接把由lambda定义的 Dialogue: 0,0:42:25.39,0:42:28.12,Default,,0,0,0,,由lambda定义的匿名函数放进表格里 Dialogue: 0,0:42:28.66,0:42:31.76,Default,,0,0,0,,你的问题还引出了另一种可能性 Dialogue: 0,0:42:32.35,0:42:34.06,Default,,0,0,0,,也就是 Dialogue: 0,0:42:34.83,0:42:37.92,Default,,0,0,0,,可能我在这个数据对象里存储的 Dialogue: 0,0:42:37.95,0:42:39.48,Default,,0,0,0,,不是符号POLAR Dialogue: 0,0:42:39.93,0:42:42.35,Default,,0,0,0,,也许是这些运算本身 Dialogue: 0,0:42:43.90,0:42:45.63,Default,,0,0,0,,这是组织系统的另一种方法 Dialogue: 0,0:42:45.66,0:42:46.60,Default,,0,0,0,,叫做“消息传递” Dialogue: 0,0:42:48.65,0:42:49.92,Default,,0,0,0,,它们都殊途同归 Dialogue: 0,0:42:54.64,0:42:58.04,Default,,0,0,0,,学生:所以说如果Martha和George Dialogue: 0,0:42:58.04,0:43:01.23,Default,,0,0,0,,用了相同的过程名字也没什么问题 Dialogue: 0,0:43:01.23,0:43:02.56,Default,,0,0,0,,[听不清] Dialogue: 0,0:43:02.56,0:43:04.68,Default,,0,0,0,,教授:对 你说得很对 Dialogue: 0,0:43:04.80,0:43:07.85,Default,,0,0,0,,看 他们甚至根本不需要给他们的过程命名 Dialogue: 0,0:43:08.04,0:43:09.36,Default,,0,0,0,,George和Martha可以 -- Dialogue: 0,0:43:09.50,0:43:10.62,Default,,0,0,0,,George可以这么来做 Dialogue: 0,0:43:10.83,0:43:15.28,Default,,0,0,0,,与其在rectangular和real-part对应的格子里放 Dialogue: 0,0:43:16.22,0:43:17.98,Default,,0,0,0,,存放real-part-rectangular这个过程 Dialogue: 0,0:43:18.03,0:43:21.15,Default,,0,0,0,,George可以在rectangular和real-part对应的格子里放 Dialogue: 0,0:43:21.24,0:43:23.69,Default,,0,0,0,,放一个lambda(z) 然后什么什么 Dialogue: 0,0:43:24.54,0:43:26.84,Default,,0,0,0,,整个系统会以完全相同的方式工作 Dialogue: 0,0:43:27.33,0:43:29.24,Default,,0,0,0,,学生:我的问题是 就算Martha在 Dialogue: 0,0:43:29.84,0:43:33.60,Default,,0,0,0,,Martha在key1和key2对应的格子里放了real-part过程 Dialogue: 0,0:43:33.95,0:43:37.64,Default,,0,0,0,,George也在key1和key2下放了一个real-part过程 Dialogue: 0,0:43:37.96,0:43:39.60,Default,,0,0,0,,只要两个过程的定义不一样 Dialogue: 0,0:43:39.80,0:43:41.26,Default,,0,0,0,,它们就不会发生任何冲突 对吗? Dialogue: 0,0:43:41.29,0:43:43.80,Default,,0,0,0,,教授:对的 这完全没有问题 Dialogue: 0,0:43:44.97,0:43:47.13,Default,,0,0,0,,除非你说的是George和Martha在同一个终端上工作 Dialogue: 0,0:43:47.13,0:43:49.20,Default,,0,0,0,,并且他们两个人起的所有名字的含义全部相同 Dialogue: 0,0:43:49.82,0:43:51.23,Default,,0,0,0,,那么同样的real-part就会造成困扰 Dialogue: 0,0:43:51.24,0:43:52.80,Default,,0,0,0,,但是就算是这种情况也有办法解决 Dialogue: 0,0:43:52.80,0:43:54.80,Default,,0,0,0,,从原则上讲你说的完全正确 Dialogue: 0,0:43:54.98,0:43:56.29,Default,,0,0,0,,如果它们的名字不互相冲突的话 Dialogue: 0,0:43:56.29,0:43:58.19,Default,,0,0,0,,被填到表里的是对象本身 而不是它们的名字 Dialogue: 0,0:44:08.20,0:44:09.05,Default,,0,0,0,,好 我们休息一下 Dialogue: 0,0:44:12.91,0:44:20.48,Default,,0,0,0,,[音乐] Dialogue: 0,0:44:20.96,0:44:23.29,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:44:23.45,0:44:25.29,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:44:57.42,0:45:05.07,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:45:05.47,0:45:09.24,Declare,,0,0,0,,{\an2\fad(500,500)}通用运算符 Dialogue: 0,0:45:12.88,0:45:16.88,Default,,0,0,0,,教授:好的 我们刚刚讲了一个数据导向编程的例子 Dialogue: 0,0:45:17.68,0:45:22.84,Default,,0,0,0,,我们将其用于实现一个复数域上的算术系统 Dialogue: 0,0:45:27.60,0:45:32.48,Default,,0,0,0,,我已经在里面实现了 +c -c 这些运算 Dialogue: 0,0:45:32.88,0:45:37.24,Default,,0,0,0,,*c \c 还有其它的一些过程 Dialogue: 0,0:45:38.23,0:45:45.72,Default,,0,0,0,,这些过程存在于上层 -- 这是关键之处 Dialogue: 0,0:45:45.74,0:45:49.60,Default,,0,0,0,,它们存在于两种不同表示方式的上层 Dialogue: 0,0:45:50.34,0:45:55.44,Default,,0,0,0,,这是一个直角坐标程序包 这里一个极坐标程序包 Dialogue: 0,0:45:58.14,0:45:59.15,Default,,0,0,0,,可能还有其它的东西 Dialogue: 0,0:45:59.15,0:46:02.80,Default,,0,0,0,,关键理念就是 “其它的东西”可以很容易地添加上去 Dialogue: 0,0:46:04.67,0:46:08.35,Default,,0,0,0,,但是这并没有真正体现出这种方法学的威力 Dialogue: 0,0:46:08.90,0:46:10.15,Default,,0,0,0,,我们看看发生了什么 Dialogue: 0,0:46:10.15,0:46:12.33,Default,,0,0,0,,这个方法的威力 只有当你 Dialogue: 0,0:46:12.94,0:46:15.79,Default,,0,0,0,,当你把它嵌入于一些更复杂的系统中时才会显现 Dialogue: 0,0:46:16.17,0:46:17.74,Default,,0,0,0,,我现在要做的就是 Dialogue: 0,0:46:17.87,0:46:20.01,Default,,0,0,0,,把它嵌入一个更复杂的系统中 Dialogue: 0,0:46:20.25,0:46:25.28,Default,,0,0,0,,假设我们已经有了一个通用算术系统 Dialogue: 0,0:46:25.28,0:46:27.24,Default,,0,0,0,,所谓的“通用算术系统” Dialogue: 0,0:46:27.24,0:46:28.54,Default,,0,0,0,,然后在系统的最顶层 Dialogue: 0,0:46:30.76,0:46:35.92,Default,,0,0,0,,用户可以命令它把两个东西相加 或者相减 Dialogue: 0,0:46:37.45,0:46:41.05,Default,,0,0,0,,或者让两数相乘、相除 Dialogue: 0,0:46:44.14,0:46:46.52,Default,,0,0,0,,然后在它们下面是一个抽象屏障 Dialogue: 0,0:46:47.93,0:46:49.15,Default,,0,0,0,,抽象屏障的下层 Dialogue: 0,0:46:49.50,0:46:52.48,Default,,0,0,0,,是一个复数域算术程序包 Dialogue: 0,0:46:53.02,0:46:54.96,Default,,0,0,0,,然后你可以让它把两个复数相加 Dialogue: 0,0:46:55.04,0:46:58.83,Default,,0,0,0,,或者你还可以把 有理数域算术程序包 Dialogue: 0,0:46:58.88,0:46:59.93,Default,,0,0,0,,给安装进来 Dialogue: 0,0:47:00.19,0:47:01.72,Default,,0,0,0,,可以放进去有理数 Dialogue: 0,0:47:04.76,0:47:06.22,Default,,0,0,0,,然后有理数程序包里面 Dialogue: 0,0:47:07.16,0:47:14.75,Default,,0,0,0,,有我们实现的 +rat、*rat等等的这些过程 Dialogue: 0,0:47:15.39,0:47:17.01,Default,,0,0,0,,或者你还可以加上通常的Lisp算术系统 Dialogue: 0,0:47:17.01,0:47:18.99,Default,,0,0,0,,你可以让它把3和4加起来 Dialogue: 0,0:47:19.42,0:47:20.94,Default,,0,0,0,,那么我们在这个系统里加入通常的算术系统 Dialogue: 0,0:47:28.28,0:47:34.67,Default,,0,0,0,,其中有Lisp自带的 + - * / Dialogue: 0,0:47:36.67,0:47:39.12,Default,,0,0,0,,总而言之 我们可以想象这个复数系统 Dialogue: 0,0:47:39.44,0:47:44.44,Default,,0,0,0,,存在于一个更加复杂的通用运算系统里面 Dialogue: 0,0:47:47.73,0:47:48.73,Default,,0,0,0,,我们怎么才能做到呢 Dialogue: 0,0:47:49.05,0:47:52.32,Default,,0,0,0,,我们已经有了想法 只要再一次应用它就可以了 Dialogue: 0,0:47:52.78,0:47:54.72,Default,,0,0,0,,我们已经实现了一个有理数程序包 Dialogue: 0,0:47:54.72,0:47:56.89,Default,,0,0,0,,那么我们来看看应该怎么修改它 Dialogue: 0,0:48:01.48,0:48:03.40,Default,,0,0,0,,实际上 在这个层面 它根本就不需要修改 Dialogue: 0,0:48:03.73,0:48:05.88,Default,,0,0,0,,这完全就是我们上次写的那些代码 Dialogue: 0,0:48:07.18,0:48:08.97,Default,,0,0,0,,要把两个有理数相加 Dialogue: 0,0:48:09.85,0:48:10.91,Default,,0,0,0,,回忆一下 我们要用到这个公式 Dialogue: 0,0:48:11.14,0:48:13.37,Default,,0,0,0,,构造一个有理数 它的分子是 Dialogue: 0,0:48:13.98,0:48:17.56,Default,,0,0,0,,x的分子乘以y的分母 Dialogue: 0,0:48:17.93,0:48:21.52,Default,,0,0,0,,加上 x的分母乘以y的分子 Dialogue: 0,0:48:21.52,0:48:23.79,Default,,0,0,0,,而结果的分母是 x的分母乘y的分母 Dialogue: 0,0:48:25.76,0:48:29.07,Default,,0,0,0,,然后是-rat、*rat、/rat这些过程 Dialogue: 0,0:48:30.36,0:48:35.12,Default,,0,0,0,,这就是我们之前写的那个有理数程序包 Dialogue: 0,0:48:36.31,0:48:38.89,Default,,0,0,0,,我们忽略最大公约数的问题 先不去考虑那个 Dialogue: 0,0:48:39.08,0:48:42.59,Default,,0,0,0,,作为这个有理数包的实现人员 Dialogue: 0,0:48:42.80,0:48:45.10,Default,,0,0,0,,怎么把它安装到我们的通用运算系统中呢? Dialogue: 0,0:48:45.57,0:48:46.22,Default,,0,0,0,,那很简单 Dialogue: 0,0:48:47.29,0:48:51.56,Default,,0,0,0,,我们要做的事只有一件和之前不同 Dialogue: 0,0:48:51.84,0:48:55.71,Default,,0,0,0,,在之前我们说构造一个有理数 Dialogue: 0,0:48:56.27,0:48:59.98,Default,,0,0,0,,就是构造一个由分子分母组成的序对 Dialogue: 0,0:49:00.96,0:49:03.20,Default,,0,0,0,,现在我们不光构造这个序对 还要给它贴上标签 Dialogue: 0,0:49:03.30,0:49:04.56,Default,,0,0,0,,给它加上rational类型 Dialogue: 0,0:49:06.36,0:49:08.09,Default,,0,0,0,,这就是唯一的不同之处 Dialogue: 0,0:49:08.56,0:49:10.09,Default,,0,0,0,,把它变成带类型的数据 Dialogue: 0,0:49:12.38,0:49:14.08,Default,,0,0,0,,现在 我们要把运算放进表格里 Dialogue: 0,0:49:14.36,0:49:18.20,Default,,0,0,0,,我们在rational符号和add运算对应的格子里 Dialogue: 0,0:49:18.92,0:49:20.25,Default,,0,0,0,,放进我们的+rat过程 Dialogue: 0,0:49:21.82,0:49:23.24,Default,,0,0,0,,再次强调 这是一个符号 Dialogue: 0,0:49:23.74,0:49:23.93,Default,,0,0,0,,看到了么? Dialogue: 0,0:49:24.03,0:49:25.29,Default,,0,0,0,,这是引用 这也是引用 Dialogue: 0,0:49:25.31,0:49:28.01,Default,,0,0,0,,但是实际上放进表里的是+rat过程本身 Dialogue: 0,0:49:29.82,0:49:31.77,Default,,0,0,0,,然后怎么做减法 Dialogue: 0,0:49:31.79,0:49:36.81,Default,,0,0,0,,我们用-rat过程做减法 Dialogue: 0,0:49:38.27,0:49:40.24,Default,,0,0,0,,然后是乘法和除法 Dialogue: 0,0:49:41.09,0:49:43.64,Default,,0,0,0,,这些步骤精准地描述了 我们该怎么做 Dialogue: 0,0:49:44.14,0:49:46.97,Default,,0,0,0,,来兼容这个通用算术系统 Dialogue: 0,0:49:48.51,0:49:49.88,Default,,0,0,0,,那么整个系统怎么工作呢 Dialogue: 0,0:49:51.56,0:49:58.40,Default,,0,0,0,,我们想实现的是通用运算符 Dialogue: 0,0:49:59.34,0:50:02.80,Default,,0,0,0,,为了让add、sub、mul和div变成通用运算符 Dialogue: 0,0:50:03.99,0:50:17.36,Default,,0,0,0,,所以我们要把add过程定义为 (ADD X Y)就是 Dialogue: 0,0:50:18.62,0:50:22.12,Default,,0,0,0,,就是调用operate过程 Dialogue: 0,0:50:26.08,0:50:27.49,Default,,0,0,0,,我们把这个叫做operate-2 Dialogue: 0,0:50:27.49,0:50:30.78,Default,,0,0,0,,这是我们的操作过程 但是要接收两个参数 Dialogue: 0,0:50:31.60,0:50:35.84,Default,,0,0,0,,对它们应用add 把它们加起来 Dialogue: 0,0:50:37.60,0:50:39.76,Default,,0,0,0,,这是和operate类似的一个东西 Dialogue: 0,0:50:40.42,0:50:41.68,Default,,0,0,0,,我们再看看这个代码 Dialogue: 0,0:50:41.68,0:50:42.93,Default,,0,0,0,,它和operate很相似 Dialogue: 0,0:50:45.79,0:50:52.49,Default,,0,0,0,,为了将运算符运用在两个参数arg1和arg2上 Dialogue: 0,0:50:55.04,0:50:56.65,Default,,0,0,0,,首要任务是 Dialogue: 0,0:50:56.83,0:51:00.73,Default,,0,0,0,,检查这两个参数的类型是否相同 Dialogue: 0,0:51:01.90,0:51:02.96,Default,,0,0,0,,所以我们要问 Dialogue: 0,0:51:02.99,0:51:07.77,Default,,0,0,0,,第一个参数的类型和第二个的类型一样吗? Dialogue: 0,0:51:10.35,0:51:13.36,Default,,0,0,0,,如果不一样 Dialogue: 0,0:51:13.58,0:51:15.63,Default,,0,0,0,,我们就停止运行 然后抛出错误 Dialogue: 0,0:51:15.67,0:51:16.67,Default,,0,0,0,,我们不知道怎么对它们进行运算 Dialogue: 0,0:51:19.14,0:51:20.49,Default,,0,0,0,,如果它们的类型确实是相同的 Dialogue: 0,0:51:20.51,0:51:22.08,Default,,0,0,0,,那就和之前一样了 Dialogue: 0,0:51:22.08,0:51:26.46,Default,,0,0,0,,我们会查询在参数的类型对应的 Dialogue: 0,0:51:26.76,0:51:29.61,Default,,0,0,0,,参数1和参数2是同样的类型 知道一个就可以 Dialogue: 0,0:51:30.42,0:51:32.59,Default,,0,0,0,,我们到表格里去查找对应的过程 Dialogue: 0,0:51:33.64,0:51:35.87,Default,,0,0,0,,如果找到这样一个过程 Dialogue: 0,0:51:37.53,0:51:41.74,Default,,0,0,0,,我们就将其应用在参数1和参数2的内容上 Dialogue: 0,0:51:43.03,0:51:44.76,Default,,0,0,0,,如果是其它情况 就报错 Dialogue: 0,0:51:44.76,0:51:45.72,Default,,0,0,0,,“未定义运算符” Dialogue: 0,0:51:46.89,0:51:48.16,Default,,0,0,0,,这就是operate-2过程 Dialogue: 0,0:51:51.72,0:51:54.03,Default,,0,0,0,,这就是我们要做的全部事情 Dialogue: 0,0:51:55.16,0:51:57.45,Default,,0,0,0,,我们刚刚才写好了一个复数运算包 Dialogue: 0,0:51:57.64,0:52:01.00,Default,,0,0,0,,那么怎么把它放进这个通用系统里面呢? Dialogue: 0,0:52:02.14,0:52:02.91,Default,,0,0,0,,方法几乎是一样的 Dialogue: 0,0:52:06.41,0:52:08.59,Default,,0,0,0,,我们构造一个叫做make-complex的过程 Dialogue: 0,0:52:09.95,0:52:12.81,Default,,0,0,0,,它把George和Martha给我们的东西 Dialogue: 0,0:52:13.64,0:52:15.00,Default,,0,0,0,,贴上complex的类型标志 Dialogue: 0,0:52:18.17,0:52:23.87,Default,,0,0,0,,然后我们说 要把复数相加 这个+complex过程 Dialogue: 0,0:52:25.84,0:52:28.78,Default,,0,0,0,,用我们的内部过程 +c Dialogue: 0,0:52:30.78,0:52:32.24,Default,,0,0,0,,把结果加上类型 Dialogue: 0,0:52:32.24,0:52:33.42,Default,,0,0,0,,让它变成复数类型 Dialogue: 0,0:52:37.68,0:52:42.52,Default,,0,0,0,,那么我们的包里原来有+c和-c这两个过程 Dialogue: 0,0:52:42.68,0:52:44.75,Default,,0,0,0,,用来和George和Martha通信 Dialogue: 0,0:52:45.25,0:52:47.39,Default,,0,0,0,,然后为了与外部通信 Dialogue: 0,0:52:47.40,0:52:53.04,Default,,0,0,0,,我们还有+complex和-complex Dialogue: 0,0:52:55.92,0:52:56.53,Default,,0,0,0,,等等 Dialogue: 0,0:52:56.53,0:52:59.98,Default,,0,0,0,,它们唯一的不同就在于:后者的返回的是带类型的值 Dialogue: 0,0:53:01.12,0:53:02.41,Default,,0,0,0,,它们可以在这里被查询 Dialogue: 0,0:53:02.85,0:53:05.02,Default,,0,0,0,,而这些是内部过程 Dialogue: 0,0:53:09.25,0:53:10.68,Default,,0,0,0,,我们再来看那个幻灯片 Dialogue: 0,0:53:10.68,0:53:13.04,Default,,0,0,0,,我们还有一件事要做 Dialogue: 0,0:53:13.74,0:53:15.61,Default,,0,0,0,,在定义了+complex之后 Dialogue: 0,0:53:15.68,0:53:20.52,Default,,0,0,0,,我们在complex类型和add符号对应的格子中 Dialogue: 0,0:53:21.31,0:53:22.75,Default,,0,0,0,,填上过程+complex Dialogue: 0,0:53:23.20,0:53:26.75,Default,,0,0,0,,对于-complex也类似 Dialogue: 0,0:53:27.13,0:53:29.13,Default,,0,0,0,,*complex和/complex亦如此 Dialogue: 0,0:53:31.70,0:53:33.48,Default,,0,0,0,,那我们怎么安装寻常算术呢? Dialogue: 0,0:53:35.25,0:53:36.12,Default,,0,0,0,,方法还是一样的 Dialogue: 0,0:53:38.16,0:53:41.36,Default,,0,0,0,,我们会写一个叫做make-number的过程 Dialogue: 0,0:53:44.34,0:53:48.11,Default,,0,0,0,,make-number接收一个数 然后给它加上类型 Dialogue: 0,0:53:48.14,0:53:49.29,Default,,0,0,0,,也就是符号number Dialogue: 0,0:53:50.26,0:53:52.11,Default,,0,0,0,,我们构造一个过程叫做+number Dialogue: 0,0:53:52.92,0:53:58.75,Default,,0,0,0,,用Lisp自带的加法把两个数加起来 Dialogue: 0,0:53:58.92,0:54:00.78,Default,,0,0,0,,因为我们现在讨论的是寻常算术 Dialogue: 0,0:54:01.31,0:54:03.10,Default,,0,0,0,,给它加上类型 让它变成number类型 Dialogue: 0,0:54:04.51,0:54:08.09,Default,,0,0,0,,然后我们把+number过程放到 Dialogue: 0,0:54:08.59,0:54:11.00,Default,,0,0,0,,表格里number和add对应的的格子中 Dialogue: 0,0:54:12.30,0:54:16.16,Default,,0,0,0,,再用相同的方法把减法 乘法 除法也放进去 Dialogue: 0,0:54:22.67,0:54:26.06,Default,,0,0,0,,我们举一个例子 就看得清楚一点 Dialogue: 0,0:54:26.06,0:54:28.75,Default,,0,0,0,,假设 比如说 Dialogue: 0,0:54:32.28,0:54:34.15,Default,,0,0,0,,我要执行这个运算 Dialogue: 0,0:54:34.15,0:54:38.22,Default,,0,0,0,,好 现在我要执行一个运算 Dialogue: 0,0:54:38.22,0:54:40.46,Default,,0,0,0,,比如说我把两个复数乘起来 Dialogue: 0,0:54:40.93,0:54:48.64,Default,,0,0,0,,把3+4i和2+6i乘起来 Dialogue: 0,0:54:50.17,0:54:52.60,Default,,0,0,0,,这就是我调用mul过程要传入的参数 Dialogue: 0,0:54:52.84,0:54:55.76,Default,,0,0,0,,这里就代表通用运算符mul Dialogue: 0,0:54:57.17,0:54:57.98,Default,,0,0,0,,那么它怎么工作呢 Dialogue: 0,0:54:58.28,0:55:04.60,Default,,0,0,0,,我们讲3+4i 在整个系统里 Dialogue: 0,0:55:04.83,0:55:06.11,Default,,0,0,0,,处于这样的一个位置 Dialogue: 0,0:55:06.25,0:55:07.52,Default,,0,0,0,,假设它是George那种方法表示的 Dialogue: 0,0:55:08.28,0:55:14.97,Default,,0,0,0,,所以它的内部有一个3和一个4 Dialogue: 0,0:55:18.49,0:55:20.97,Default,,0,0,0,,这上面还贴着George的类型标志 Dialogue: 0,0:55:24.33,0:55:28.32,Default,,0,0,0,,是他构造的rectangular类型 Dialogue: 0,0:55:29.51,0:55:30.57,Default,,0,0,0,,又附加在那上面的 Dialogue: 0,0:55:31.23,0:55:35.79,Default,,0,0,0,,从更上一层的视角来看这一段数据 Dialogue: 0,0:55:36.19,0:55:36.78,Default,,0,0,0,,它又是一个 Dialogue: 0,0:55:37.93,0:55:39.96,Default,,0,0,0,,这整个又是一个带类型的数据 Dialogue: 0,0:55:40.60,0:55:41.80,Default,,0,0,0,,它的类型是complex Dialogue: 0,0:55:44.82,0:55:47.31,Default,,0,0,0,,那么这就是这个对象 Dialogue: 0,0:55:48.64,0:55:50.24,Default,,0,0,0,,在最高层视角中的样子 Dialogue: 0,0:55:50.68,0:55:53.56,Default,,0,0,0,,那些通用运算符看到的对象 就是这样的 Dialogue: 0,0:55:55.56,0:55:58.72,Default,,0,0,0,,现在 mul过程会过来问 Dialogue: 0,0:55:58.84,0:56:00.40,Default,,0,0,0,,它的类型是什么? Dialogue: 0,0:56:00.48,0:56:01.48,Default,,0,0,0,,它的类型是complex Dialogue: 0,0:56:04.27,0:56:06.46,Default,,0,0,0,,然后运行到operate-2 然后说 Dialogue: 0,0:56:06.46,0:56:09.72,Default,,0,0,0,,啊 我想要把表格里的过程 Dialogue: 0,0:56:09.72,0:56:13.04,Default,,0,0,0,,也就是*complex这个过程 Dialogue: 0,0:56:15.08,0:56:17.76,Default,,0,0,0,,应用到 将其类型剥离之后的结果上去 Dialogue: 0,0:56:17.95,0:56:19.28,Default,,0,0,0,,所以它会把类型剥下来 Dialogue: 0,0:56:19.93,0:56:24.24,Default,,0,0,0,,把剩下的东西传递给复数的世界 Dialogue: 0,0:56:26.70,0:56:28.73,Default,,0,0,0,,复数的世界看了看它有的运算操作 然后说 Dialogue: 0,0:56:28.76,0:56:30.56,Default,,0,0,0,,“我得调用*c这个过程” Dialogue: 0,0:56:31.28,0:56:32.14,Default,,0,0,0,,然后*c过程说 Dialogue: 0,0:56:32.22,0:56:37.20,Default,,0,0,0,,我想知道这个东西的模值是多少 Dialogue: 0,0:56:39.42,0:56:40.16,Default,,0,0,0,,然后它们会说 啊 Dialogue: 0,0:56:40.16,0:56:41.71,Default,,0,0,0,,它是直角坐标表示的 是George的东西 Dialogue: 0,0:56:41.87,0:56:44.41,Default,,0,0,0,,所以它们又剥掉了一个类型 Dialogue: 0,0:56:46.91,0:56:49.80,Default,,0,0,0,,然后把内容交给George 让他提取出它的模值 Dialogue: 0,0:56:52.16,0:56:53.13,Default,,0,0,0,,那么我们看到 Dialogue: 0,0:56:53.44,0:56:56.99,Default,,0,0,0,,这其中有一条由类型构成的链条 Dialogue: 0,0:56:59.32,0:57:01.50,Default,,0,0,0,,这个链条的长度就是你要 Dialogue: 0,0:57:01.53,0:57:03.13,Default,,0,0,0,,在这个表格里上升的层数 Dialogue: 0,0:57:05.09,0:57:05.96,Default,,0,0,0,,类型的作用则是 Dialogue: 0,0:57:05.96,0:57:10.84,Default,,0,0,0,,每当我们在表格中遇到一道垂直屏障时 Dialogue: 0,0:57:11.05,0:57:14.06,Default,,0,0,0,,你不知道该如何抉择时 Dialogue: 0,0:57:14.41,0:57:15.85,Default,,0,0,0,,类型就会给你指路 Dialogue: 0,0:57:17.44,0:57:18.83,Default,,0,0,0,,然后最底层的过程 Dialogue: 0,0:57:18.97,0:57:20.67,Default,,0,0,0,,它们构造数据结构 对数据进行筛选之后 Dialogue: 0,0:57:21.12,0:57:22.81,Default,,0,0,0,,再把类型贴回去 Dialogue: 0,0:57:25.35,0:57:30.75,Default,,0,0,0,,这就是整个系统的总体结构 Dialogue: 0,0:57:33.41,0:57:33.77,Default,,0,0,0,,好 Dialogue: 0,0:57:34.82,0:57:35.68,Default,,0,0,0,,明白了这个之后 Dialogue: 0,0:57:37.56,0:57:39.44,Default,,0,0,0,,我们再让这个系统变得更加复杂 Dialogue: 0,0:57:41.89,0:57:46.54,Default,,0,0,0,,我们这次不光要在系统里添加新的数域 Dialogue: 0,0:57:46.60,0:57:51.15,Default,,0,0,0,,我们也来讨论一下怎么把多项式也加进去 Dialogue: 0,0:57:51.51,0:57:52.97,Default,,0,0,0,,让它能做多项式算术 Dialogue: 0,0:57:53.36,0:58:03.71,Default,,0,0,0,,比如我们可以计算x^15+2x^7+5 Dialogue: 0,0:58:04.48,0:58:05.84,Default,,0,0,0,,像这样的多项式 Dialogue: 0,0:58:06.38,0:58:07.93,Default,,0,0,0,,如果有两个这样的东西 Dialogue: 0,0:58:07.93,0:58:09.48,Default,,0,0,0,,我们可以把它们相加或者相乘 Dialogue: 0,0:58:10.53,0:58:11.79,Default,,0,0,0,,先不管相除的问题 Dialogue: 0,0:58:12.14,0:58:14.67,Default,,0,0,0,,只考虑相加相乘和相减 Dialogue: 0,0:58:15.55,0:58:17.16,Default,,0,0,0,,我们需要做什么 Dialogue: 0,0:58:18.52,0:58:20.76,Default,,0,0,0,,我们先来想想怎么表示一个多项式 Dialogue: 0,0:58:21.83,0:58:23.55,Default,,0,0,0,,它也是一种带类型的数据 Dialogue: 0,0:58:24.73,0:58:27.55,Default,,0,0,0,,这个系统里的一个多项式 Dialogue: 0,0:58:28.54,0:58:31.68,Default,,0,0,0,,应该是带有polynomial类型的对象 Dialogue: 0,0:58:32.00,0:58:34.55,Default,,0,0,0,,接下来它可能要问这个多项式的变量是哪个 Dialogue: 0,0:58:34.55,0:58:37.69,Default,,0,0,0,,比如这是一个以x为变量的多项式 Dialogue: 0,0:58:38.96,0:58:41.39,Default,,0,0,0,,然后 多项式内还有各项的信息 Dialogue: 0,0:58:42.25,0:58:44.16,Default,,0,0,0,,有很多种方法来实现 Dialogue: 0,0:58:44.25,0:58:47.63,Default,,0,0,0,,我们采用的方法是构造一个“项表” Dialogue: 0,0:58:51.52,0:58:52.24,Default,,0,0,0,,所谓的“项表” Dialogue: 0,0:58:53.70,0:58:55.61,Default,,0,0,0,,本例中 我们用的是类似这样的东西 Dialogue: 0,0:58:56.36,0:58:59.68,Default,,0,0,0,,我们把它写成一系列 按次数排列的序对 Dialogue: 0,0:58:59.69,0:59:05.80,Default,,0,0,0,,那么这个项表就能表示这个多项式了 Dialogue: 0,0:59:09.42,0:59:10.68,Default,,0,0,0,,它的意义是 Dialogue: 0,0:59:11.48,0:59:19.71,Default,,0,0,0,,这个多项式第一项的次数是15 系数是1 Dialogue: 0,0:59:23.82,0:59:27.50,Default,,0,0,0,,然后下一项的次数是7 系数是2 Dialogue: 0,0:59:27.53,0:59:30.49,Default,,0,0,0,,再下一项是一个常数 它次数是0 系数是5 Dialogue: 0,0:59:31.45,0:59:34.16,Default,,0,0,0,,实际上有很多很多种方法 Dialogue: 0,0:59:34.25,0:59:35.96,Default,,0,0,0,,也有很多很多的取舍 Dialogue: 0,0:59:36.01,0:59:39.10,Default,,0,0,0,,在你认真思考如何实现代数操作程序包时 Dialogue: 0,0:59:39.44,0:59:41.73,Default,,0,0,0,,你该如何表示这些东西 Dialogue: 0,0:59:42.01,0:59:43.68,Default,,0,0,0,,但是我们这种是比较标准的一种 Dialogue: 0,0:59:44.18,0:59:45.55,Default,,0,0,0,,它适用于很多情况 Dialogue: 0,0:59:47.77,0:59:50.99,Default,,0,0,0,,好 那么我们怎么实现我们的多项式算术呢 Dialogue: 0,0:59:53.47,0:59:54.96,Default,,0,0,0,,现在开始着手做这个事情 Dialogue: 0,0:59:57.95,1:00:00.28,Default,,0,0,0,,构造一个多项式 首先要 Dialogue: 0,1:00:00.76,1:00:04.12,Default,,0,0,0,,首先我们得找一个办法来构造多项式 Dialogue: 0,1:00:05.69,1:00:10.28,Default,,0,0,0,,我们可以用一个变量 比如x和一个项表来构造它们 Dialogue: 0,1:00:11.24,1:00:14.09,Default,,0,0,0,,我们要用某种方法把它们包装起来 Dialogue: 0,1:00:14.30,1:00:19.40,Default,,0,0,0,,我们可以用cons把变量和项表组合起来 Dialogue: 0,1:00:19.82,1:00:21.74,Default,,0,0,0,,然后把这个序对加上polynomial的类型标志 Dialogue: 0,1:00:26.27,1:00:27.77,Default,,0,0,0,,那我们怎么处理多项式相加呢? Dialogue: 0,1:00:29.28,1:00:31.85,Default,,0,0,0,,要相加两个多项式 p1和p2 Dialogue: 0,1:00:32.68,1:00:35.18,Default,,0,0,0,,为了简化问题 假设我们 Dialogue: 0,1:00:35.37,1:00:37.15,Default,,0,0,0,,我们只相加变量相同的两个式子 Dialogue: 0,1:00:37.38,1:00:39.28,Default,,0,0,0,,那么如果它们的变量相同 Dialogue: 0,1:00:39.69,1:00:42.57,Default,,0,0,0,,是否相同交由我们编写的选择函数判断 Dialogue: 0,1:00:42.96,1:00:44.38,Default,,0,0,0,,我们不必在意它的细节 Dialogue: 0,1:00:45.15,1:00:47.04,Default,,0,0,0,,如果两个多项式的变量相同 Dialogue: 0,1:00:48.03,1:00:48.81,Default,,0,0,0,,我们就继续运算 Dialogue: 0,1:00:48.81,1:00:51.26,Default,,0,0,0,,如果它们的变量不相同 我们返回一个错误 Dialogue: 0,1:00:52.35,1:00:54.01,Default,,0,0,0,,“两个多项式的变量不相同” Dialogue: 0,1:00:55.48,1:00:57.37,Default,,0,0,0,,如果它们的变量确实是相同 Dialogue: 0,1:00:57.60,1:00:59.18,Default,,0,0,0,,我们就要构造一个新的多项式 Dialogue: 0,1:00:59.80,1:01:01.85,Default,,0,0,0,,它的变量即是原式的变量 Dialogue: 0,1:01:03.15,1:01:06.56,Default,,0,0,0,,它的项表则由过程+terms产生 Dialogue: 0,1:01:07.48,1:01:09.80,Default,,0,0,0,,+terms过程会把两个项表加起来 Dialogue: 0,1:01:10.17,1:01:12.01,Default,,0,0,0,,所以我们要把两个多项式的项表合起来 Dialogue: 0,1:01:13.50,1:01:14.51,Default,,0,0,0,,该过程即可返回一个项表 Dialogue: 0,1:01:15.00,1:01:20.01,Default,,0,0,0,,我们将变量和得到的项表构造成新的多项式 Dialogue: 0,1:01:20.68,1:01:21.79,Default,,0,0,0,,这就是+poly过程 Dialogue: 0,1:01:22.55,1:01:27.00,Default,,0,0,0,,然后我们要把这个过程放进表格中polynomial那一栏 Dialogue: 0,1:01:28.24,1:01:30.14,Default,,0,0,0,,用+poly实现add操作 Dialogue: 0,1:01:30.52,1:01:31.75,Default,,0,0,0,,当然实际上没做多少事情 Dialogue: 0,1:01:31.75,1:01:35.31,Default,,0,0,0,,我们只是把所有的工作压到+terms的头上 Dialogue: 0,1:01:35.79,1:01:37.02,Default,,0,0,0,,它会负责把项表相加起来 Dialogue: 0,1:01:37.74,1:01:39.16,Default,,0,0,0,,我们看看这个过程 Dialogue: 0,1:01:39.18,1:01:48.03,Default,,0,0,0,,这是+terms过程的大概结构 Dialogue: 0,1:01:48.90,1:01:51.74,Default,,0,0,0,,L1和L2是两个项表 Dialogue: 0,1:01:52.00,1:01:54.81,Default,,0,0,0,,所谓“项表”即是按每项次数排序的序对 Dialogue: 0,1:01:55.70,1:01:56.95,Default,,0,0,0,,这里有一个大的分情况分析 Dialogue: 0,1:01:59.86,1:02:04.14,Default,,0,0,0,,首先 我们要检查项表是否为空 Dialogue: 0,1:02:05.39,1:02:07.55,Default,,0,0,0,,我们对项表做递归下降处理 Dialogue: 0,1:02:08.16,1:02:11.74,Default,,0,0,0,,最终下降到 L1或L2为空 Dialogue: 0,1:02:12.27,1:02:14.35,Default,,0,0,0,,只要其中有一个为空 Dialogue: 0,1:02:14.52,1:02:15.85,Default,,0,0,0,,我们的答案就是剩下的另一个 Dialogue: 0,1:02:15.85,1:02:19.55,Default,,0,0,0,,就是说如果L1是空表 我们就返回L2 Dialogue: 0,1:02:19.63,1:02:21.71,Default,,0,0,0,,L2是空表的话就返回L1 Dialogue: 0,1:02:23.26,1:02:25.76,Default,,0,0,0,,除此之外还有三种情况 Dialogue: 0,1:02:27.22,1:02:27.98,Default,,0,0,0,,我们要做的是 Dialogue: 0,1:02:29.08,1:02:31.05,Default,,0,0,0,,取表中的第一项 Dialogue: 0,1:02:33.50,1:02:36.04,Default,,0,0,0,,记为t1和t2 Dialogue: 0,1:02:37.66,1:02:39.05,Default,,0,0,0,,我们来分析一下这三种情况 Dialogue: 0,1:02:39.60,1:02:45.68,Default,,0,0,0,,分别是t1的次数大于t2的 Dialogue: 0,1:02:47.23,1:02:50.59,Default,,0,0,0,,小于t2的 或者等于t2的 Dialogue: 0,1:02:53.28,1:02:54.91,Default,,0,0,0,,这就是我们要判断的三种情况 Dialogue: 0,1:02:54.91,1:02:55.84,Default,,0,0,0,,先看看这一种 Dialogue: 0,1:02:58.64,1:03:01.31,Default,,0,0,0,,如果t1的次数比t2的次数要高 Dialogue: 0,1:03:03.40,1:03:04.70,Default,,0,0,0,,就意味着 Dialogue: 0,1:03:06.06,1:03:09.96,Default,,0,0,0,,答案的第一项的次数就是t1的次数 Dialogue: 0,1:03:11.56,1:03:13.80,Default,,0,0,0,,因为高次项不会和任何低次项相加 Dialogue: 0,1:03:14.17,1:03:16.19,Default,,0,0,0,,那么我们只需要把低次的项加起来 Dialogue: 0,1:03:16.76,1:03:18.25,Default,,0,0,0,,我们递归地把 Dialogue: 0,1:03:19.71,1:03:25.07,Default,,0,0,0,,把L1和L2两个项表里剩下的项相加 Dialogue: 0,1:03:27.13,1:03:29.32,Default,,0,0,0,,作为我们的答案中低次项 Dialogue: 0,1:03:30.12,1:03:32.48,Default,,0,0,0,,然后我们把它们和最高次的项连接起来 Dialogue: 0,1:03:33.18,1:03:35.45,Default,,0,0,0,,这里 我用了一对还未定义的过程 Dialogue: 0,1:03:35.47,1:03:37.55,Default,,0,0,0,,比如adjoin-term、rest-terms Dialogue: 0,1:03:38.48,1:03:40.17,Default,,0,0,0,,还有获取次数的选择函数 Dialogue: 0,1:03:41.15,1:03:42.78,Default,,0,0,0,,但是你可以想象它们是什么样子的 Dialogue: 0,1:03:44.44,1:03:48.76,Default,,0,0,0,,那么如果第一个项表的次数比第二个要高 Dialogue: 0,1:03:48.78,1:03:51.08,Default,,0,0,0,,我们就递归地把所有的低次的项相加 Dialogue: 0,1:03:51.28,1:03:53.42,Default,,0,0,0,,再和最高次项连接起来 Dialogue: 0,1:03:55.54,1:03:56.75,Default,,0,0,0,,其它情况也是一样的 Dialogue: 0,1:03:56.89,1:04:00.28,Default,,0,0,0,,如果第一个多项式次数比较低 Dialogue: 0,1:04:00.54,1:04:08.36,Default,,0,0,0,,我们就把整个第一个多项式和第二个多项式低次的项相加 Dialogue: 0,1:04:08.62,1:04:12.65,Default,,0,0,0,,然后把结果再和最高次项连起来 Dialogue: 0,1:04:14.57,1:04:15.96,Default,,0,0,0,,到现在也没多少复杂的事情 Dialogue: 0,1:04:15.96,1:04:19.40,Default,,0,0,0,,把问题变成 让低次数的项相加 Dialogue: 0,1:04:19.47,1:04:21.96,Default,,0,0,0,,还有最后一种情况是 两个多项式的次数一样 Dialogue: 0,1:04:22.57,1:04:25.18,Default,,0,0,0,,你必须要把它们的系数加起来 因为它们是同类项 Dialogue: 0,1:04:27.24,1:04:30.99,Default,,0,0,0,,我们的应对方法仍然是 递归地把低次项相加 Dialogue: 0,1:04:31.00,1:04:32.83,Default,,0,0,0,,但现在我们需要合并一些项了 Dialogue: 0,1:04:33.46,1:04:36.35,Default,,0,0,0,,我们构造一个项 Dialogue: 0,1:04:37.31,1:04:39.93,Default,,0,0,0,,其次数为我们正在处理的那一项的次数 Dialogue: 0,1:04:40.82,1:04:42.72,Default,,0,0,0,,因为现在t1和t2的次数是相同的 Dialogue: 0,1:04:44.32,1:04:44.99,Default,,0,0,0,,确定好次数了 Dialogue: 0,1:04:45.09,1:04:52.33,Default,,0,0,0,,而它的系数是t1和t2系数之和 Dialogue: 0,1:04:55.79,1:04:59.64,Default,,0,0,0,,这是一个庞大的递归过程 Dialogue: 0,1:04:59.68,1:05:03.61,Default,,0,0,0,,但其中只有一个符号值得玩味 Dialogue: 0,1:05:04.25,1:05:05.69,Default,,0,0,0,,它蕴含了重要的思想 Dialogue: 0,1:05:05.90,1:05:08.50,Default,,0,0,0,,那就是这个ADD过程 Dialogue: 0,1:05:12.39,1:05:14.80,Default,,0,0,0,,说它有趣是因为 Dialogue: 0,1:05:15.42,1:05:17.37,Default,,0,0,0,,有一件好事发生 Dialogue: 0,1:05:18.22,1:05:21.37,Default,,0,0,0,,我们没有把多项式加法 Dialogue: 0,1:05:22.56,1:05:26.46,Default,,0,0,0,,归约为某种加法 而是归约为通用运算符ADD Dialogue: 0,1:05:28.82,1:05:32.28,Default,,0,0,0,,换句话说 用这种方法实现它之后 Dialogue: 0,1:05:32.89,1:05:34.68,Default,,0,0,0,,我们的系统就不光有 Dialogue: 0,1:05:35.92,1:05:41.66,Default,,0,0,0,,有理数、复数还有寻常算术 Dialogue: 0,1:05:41.85,1:05:43.82,Default,,0,0,0,,我们同时也让它支持多项式运算了 Dialogue: 0,1:05:48.52,1:05:51.13,Default,,0,0,0,,而多项式的系数可以是 Dialogue: 0,1:05:51.24,1:05:52.86,Default,,0,0,0,,这个系统能够相加的任何东西 Dialogue: 0,1:05:53.59,1:05:56.73,Default,,0,0,0,,也就是说多项式的系数 Dialogue: 0,1:05:57.20,1:06:01.20,Default,,0,0,0,,有理数或者复数 Dialogue: 0,1:06:02.76,1:06:06.99,Default,,0,0,0,,复数同时可支持直角坐标形式和极坐标形式 Dialogue: 0,1:06:09.12,1:06:11.39,Default,,0,0,0,,系数还可以是寻常的数字 Dialogue: 0,1:06:18.97,1:06:21.21,Default,,0,0,0,,我想说的是 Dialogue: 0,1:06:22.06,1:06:24.35,Default,,0,0,0,,我们的系统现在可以自动地 Dialogue: 0,1:06:26.60,1:06:31.50,Default,,0,0,0,,处理像这样的式子 Dialogue: 0,1:06:31.53,1:06:39.69,Default,,0,0,0,,比如2/3x^2+5/17x+11/4这样的式子 Dialogue: 0,1:06:40.94,1:06:43.48,Default,,0,0,0,,也可以自动处理像是 Dialogue: 0,1:06:43.82,1:06:52.57,Default,,0,0,0,,(3+2i)x^5+(4+7i)这样的式子 Dialogue: 0,1:06:53.88,1:06:56.21,Default,,0,0,0,,系统可以自动处理这些运算 Dialogue: 0,1:06:56.21,1:06:57.07,Default,,0,0,0,,为什么呢? Dialogue: 0,1:06:57.82,1:07:01.50,Default,,0,0,0,,仅仅是因为 或者说深层次的原因是 Dialogue: 0,1:07:02.17,1:07:05.93,Default,,0,0,0,,我们把多项式相加归约成了把它们的系数相加 Dialogue: 0,1:07:06.79,1:07:10.22,Default,,0,0,0,,而系数的相加是由通用运算符ADD完成的 Dialogue: 0,1:07:11.08,1:07:12.94,Default,,0,0,0,,它说:“我不管你的数据类型是什么” Dialogue: 0,1:07:12.96,1:07:14.08,Default,,0,0,0,,“只要我能够处理就行” Dialogue: 0,1:07:15.23,1:07:18.86,Default,,0,0,0,,于是我们就“免费”获得了处理这些东西的功能 Dialogue: 0,1:07:20.65,1:07:22.04,Default,,0,0,0,,更神奇的是 Dialogue: 0,1:07:24.51,1:07:26.52,Default,,0,0,0,,我们曾把 Dialogue: 0,1:07:27.20,1:07:30.52,Default,,0,0,0,,我们放入表格中 用于处理多项式加法 Dialogue: 0,1:07:31.28,1:07:32.52,Default,,0,0,0,,是用的+poly过程 Dialogue: 0,1:07:34.66,1:07:38.65,Default,,0,0,0,,这就意味着ADD过程也可以处理多项式了 Dialogue: 0,1:07:39.42,1:07:42.11,Default,,0,0,0,,我举个例子 Dialogue: 0,1:07:43.18,1:07:46.19,Default,,0,0,0,,这是一个多项式 Dialogue: 0,1:07:50.56,1:07:52.41,Default,,0,0,0,,我正在写的这个东西 Dialogue: 0,1:07:54.12,1:07:58.46,Default,,0,0,0,,它是一个以y作为变量的多项式 Dialogue: 0,1:08:01.07,1:08:04.69,Default,,0,0,0,,每项的系数是以x作为变量的多项式 Dialogue: 0,1:08:08.61,1:08:11.12,Default,,0,0,0,,你将看到 Dialogue: 0,1:08:11.76,1:08:14.06,Default,,0,0,0,,由于 “ADD过程能够处理多项式” Dialogue: 0,1:08:14.41,1:08:17.90,Default,,0,0,0,,我们可以说 我们的系统现在不光能运算有理数 Dialogue: 0,1:08:18.27,1:08:20.33,Default,,0,0,0,,复数和一般数字 Dialogue: 0,1:08:20.35,1:08:21.77,Default,,0,0,0,,我们还可以处理多项式 Dialogue: 0,1:08:22.09,1:08:25.39,Default,,0,0,0,,多项式的系数可以是有理数、复数、一般数字 Dialogue: 0,1:08:25.50,1:08:27.52,Default,,0,0,0,,甚至是多项式 Dialogue: 0,1:08:29.15,1:08:30.96,Default,,0,0,0,,作为系数的多项式 其系数还可以是有理数 Dialogue: 0,1:08:31.69,1:08:36.76,Default,,0,0,0,,复数(直角或极坐标形式)或一般数字 Dialogue: 0,1:08:36.94,1:08:41.13,Default,,0,0,0,,甚至还可以是系数为有理数的多项式 Dialogue: 0,1:08:41.80,1:08:43.32,Default,,0,0,0,,系数为复数、一般数字的多项式 Dialogue: 0,1:08:43.67,1:08:45.21,Default,,0,0,0,,以此类推 Dialogue: 0,1:08:45.95,1:08:47.55,Default,,0,0,0,,我们构造出了一座无限延伸的 Dialogue: 0,1:08:48.49,1:08:52.88,Default,,0,0,0,,或者说是递归的类型高塔 Dialogue: 0,1:08:53.88,1:08:57.12,Default,,0,0,0,,这一切都来源于那个小小的符号:A-D-D Dialogue: 0,1:08:57.61,1:09:00.49,Default,,0,0,0,,来源于在多项式程序里 用“ADD”来代替“+” Dialogue: 0,1:09:02.27,1:09:03.77,Default,,0,0,0,,换一种方式来理解它就是 Dialogue: 0,1:09:03.95,1:09:07.74,Default,,0,0,0,,多项式也是一种类型的构造函数 Dialogue: 0,1:09:08.74,1:09:11.20,Default,,0,0,0,,也就是说你传递给它一个类型 比如整型 Dialogue: 0,1:09:11.48,1:09:15.74,Default,,0,0,0,,然后它就返回一个以整数作为系数的多项式 Dialogue: 0,1:09:16.27,1:09:17.72,Default,,0,0,0,,过程中很重要的一点是 Dialogue: 0,1:09:18.65,1:09:20.73,Default,,0,0,0,,就是多项式上的运算 Dialogue: 0,1:09:21.28,1:09:23.37,Default,,0,0,0,,归约成了关于系数的运算 Dialogue: 0,1:09:23.39,1:09:24.96,Default,,0,0,0,,很多地方都与这里类似 Dialogue: 0,1:09:25.84,1:09:27.92,Default,,0,0,0,,比如 我们再回头看看有理数 Dialogue: 0,1:09:28.87,1:09:32.65,Default,,0,0,0,,我们之前把有理数看做 一个整数在另一个上面 Dialogue: 0,1:09:32.67,1:09:35.66,Default,,0,0,0,,但这并不是关于有理式的一般性记号 Dialogue: 0,1:09:36.24,1:09:42.03,Default,,0,0,0,,比如我们也可以把3x+7放在上面 x^2+1放在下面 Dialogue: 0,1:09:43.07,1:09:48.86,Default,,0,0,0,,这是一个分子分母都是多项式的广义有理式 Dialogue: 0,1:09:50.31,1:09:52.41,Default,,0,0,0,,有理式相加 和有理数相加一样 Dialogue: 0,1:09:52.44,1:09:55.40,Default,,0,0,0,,分子乘分母 加 分母乘分子 结果作为分子 Dialogue: 0,1:09:55.72,1:09:56.99,Default,,0,0,0,,两个分母相乘 结果作为分母 Dialogue: 0,1:09:57.29,1:09:59.37,Default,,0,0,0,,怎么把它安装到我们的系统中呢? Dialogue: 0,1:09:59.39,1:10:02.97,Default,,0,0,0,,这是我们原来的有理数算术程序包 Dialogue: 0,1:10:04.25,1:10:08.24,Default,,0,0,0,,为了让这个系统能够 Dialogue: 0,1:10:08.28,1:10:11.58,Default,,0,0,0,,支持广义有理式的运算 Dialogue: 0,1:10:11.85,1:10:16.44,Default,,0,0,0,,我们把特定的加法和乘法过程 都改成通用运算符 Dialogue: 0,1:10:16.48,1:10:19.18,Default,,0,0,0,,所以如果我们把原来那个过程变成这个过程 Dialogue: 0,1:10:19.71,1:10:22.04,Default,,0,0,0,,把+和*换成ADD和MUL Dialogue: 0,1:10:22.88,1:10:24.48,Default,,0,0,0,,这些是唯一的改动 Dialogue: 0,1:10:24.84,1:10:26.03,Default,,0,0,0,,然后霎时间 Dialogue: 0,1:10:27.52,1:10:31.40,Default,,0,0,0,,我们的整个系统 就知道怎么运算这样的东西了 Dialogue: 0,1:10:33.72,1:10:38.27,Default,,0,0,0,,比如说 这里的这个有理式 Dialogue: 0,1:10:39.18,1:10:44.86,Default,,0,0,0,,它的分子是一个系数是有理数的、关于x的多项式 Dialogue: 0,1:10:47.02,1:10:49.56,Default,,0,0,0,,而这个有理式 Dialogue: 0,1:10:51.10,1:10:54.43,Default,,0,0,0,,它的分子是关于x的多项式 Dialogue: 0,1:10:55.15,1:10:58.19,Default,,0,0,0,,多项式的系数又是有理式 Dialogue: 0,1:10:59.77,1:11:01.53,Default,,0,0,0,,有理式又由复数组成 Dialogue: 0,1:11:03.39,1:11:04.85,Default,,0,0,0,,或者别的像这样的东西 Dialogue: 0,1:11:04.85,1:11:08.68,Default,,0,0,0,,看 只要能够归约成针对各部分的运算 Dialogue: 0,1:11:08.89,1:11:10.00,Default,,0,0,0,,另一个例子是 Dialogue: 0,1:11:10.28,1:11:11.42,Default,,0,0,0,,2*2的矩阵 Dialogue: 0,1:11:12.31,1:11:15.44,Default,,0,0,0,,假如有这样一个矩阵形式的东西 Dialogue: 0,1:11:16.43,1:11:18.33,Default,,0,0,0,,不管它里面是什么 Dialogue: 0,1:11:18.72,1:11:20.14,Default,,0,0,0,,但是如果我对两个这种东西调用ADD Dialogue: 0,1:11:22.33,1:11:25.18,Default,,0,0,0,,答案就是 Dialogue: 0,1:11:25.18,1:11:28.14,Default,,0,0,0,,把这个和这个相加 而矩阵是怎么相加的 Dialogue: 0,1:11:29.03,1:11:31.11,Default,,0,0,0,,那么我可以用同样的方法实现 Dialogue: 0,1:11:31.11,1:11:31.71,Default,,0,0,0,,如果我这么做了 Dialogue: 0,1:11:31.96,1:11:34.60,Default,,0,0,0,,整个系统就马上可以处理像这样的东西了 Dialogue: 0,1:11:35.29,1:11:39.18,Default,,0,0,0,,比如说一个矩阵 它的元素都是 Dialogue: 0,1:11:39.46,1:11:42.16,Default,,0,0,0,,它的元素是一个有理式 Dialogue: 0,1:11:43.10,1:11:45.15,Default,,0,0,0,,这个有理式的分子分母都是多项式 Dialogue: 0,1:11:47.02,1:11:49.56,Default,,0,0,0,,我们自然而然地获得了这些功能 Dialogue: 0,1:11:51.28,1:11:53.82,Default,,0,0,0,,整个过程中发生了什么? Dialogue: 0,1:11:53.92,1:11:56.17,Default,,0,0,0,,真正发生的是 Dialogue: 0,1:11:57.68,1:12:02.44,Default,,0,0,0,,我们摆脱了凡事都想插一手的经理 Dialogue: 0,1:12:03.12,1:12:06.19,Default,,0,0,0,,我们构造了一个“控制去中心化”的系统 Dialogue: 0,1:12:14.78,1:12:18.34,Default,,0,0,0,,你进入这个系统的时候 不会有人一边闲逛一边说 Dialogue: 0,1:12:18.35,1:12:22.30,Default,,0,0,0,,我看看官方列表中ADD是否能够处理你 Dialogue: 0,1:12:22.44,1:12:26.22,Default,,0,0,0,,你直接就可以用正确的方法 把你和别的东西加起来 Dialogue: 0,1:12:27.81,1:12:31.03,Default,,0,0,0,,这么做的好处就是 就连这种非常非常 Dialogue: 0,1:12:31.03,1:12:33.87,Default,,0,0,0,,复杂的分层对象也可以被分解后 Dialogue: 0,1:12:33.87,1:12:35.55,Default,,0,0,0,,自动放到正确的地方去处理 Dialogue: 0,1:12:37.00,1:12:37.79,Default,,0,0,0,,有什么问题吗? Dialogue: 0,1:12:40.38,1:12:42.32,Default,,0,0,0,,学生:你说你“免费”获得了这些功能 Dialogue: 0,1:12:42.35,1:12:45.82,Default,,0,0,0,,但是我在意的是你现在丢掉了 Dialogue: 0,1:12:46.48,1:12:50.91,Default,,0,0,0,,某种上下层之间的清楚界限 Dialogue: 0,1:12:50.91,1:12:52.77,Default,,0,0,0,,或者说 现在你是在用 Dialogue: 0,1:12:52.77,1:12:56.08,Default,,0,0,0,,上层的东西来定义下层的过程 Dialogue: 0,1:12:56.61,1:12:59.45,Default,,0,0,0,,这不是很危险吗? Dialogue: 0,1:13:00.35,1:13:04.49,Default,,0,0,0,,或者说 结构会变得混乱? Dialogue: 0,1:13:05.44,1:13:05.95,Default,,0,0,0,,教授:不 我-- Dialogue: 0,1:13:06.41,1:13:07.77,Default,,0,0,0,,你问它的结构是否混乱 Dialogue: 0,1:13:07.77,1:13:08.69,Default,,0,0,0,,这得要看你说的“结构”是指什么 Dialogue: 0,1:13:08.69,1:13:10.17,Default,,0,0,0,,整个过程里我们都在做递归 Dialogue: 0,1:13:11.05,1:13:18.80,Default,,0,0,0,,看 就是说要把这些东西相加就要用到这个过程 Dialogue: 0,1:13:19.15,1:13:21.37,Default,,0,0,0,,它是一种递归结构 并不混乱 Dialogue: 0,1:13:22.70,1:13:24.99,Default,,0,0,0,,所以我不认为它不清楚 Dialogue: 0,1:13:24.99,1:13:28.16,Default,,0,0,0,,学生:那么当你修改乘法或加法运算时 Dialogue: 0,1:13:29.34,1:13:31.38,Default,,0,0,0,,可能会导致 Dialogue: 0,1:13:31.38,1:13:34.27,Default,,0,0,0,,无法预测的灾难性后果 Dialogue: 0,1:13:34.48,1:13:36.44,Default,,0,0,0,,教授:你说得对 但是那要看你的意思是什么 Dialogue: 0,1:13:37.08,1:13:38.47,Default,,0,0,0,,从两个角度来讨论 Dialogue: 0,1:13:39.10,1:13:43.24,Default,,0,0,0,,举个什么例子好呢? Dialogue: 0,1:13:44.69,1:13:47.50,Default,,0,0,0,,比如说 之前我忽略了GCD运算 Dialogue: 0,1:13:47.77,1:13:50.08,Default,,0,0,0,,我们忽略了它 是为了简化我们的例子 Dialogue: 0,1:13:50.28,1:13:56.92,Default,,0,0,0,,但是如果突然我觉得 这里的+rat Dialogue: 0,1:13:57.82,1:14:01.69,Default,,0,0,0,,应该把结果约分 然后把这个功能安装到程序里 Dialogue: 0,1:14:03.34,1:14:07.87,Default,,0,0,0,,那么这个功能一旦安装 就立刻可以被所有过程调用 Dialogue: 0,1:14:08.03,1:14:10.08,Default,,0,0,0,,被这个或者那个 所有的这些 Dialogue: 0,1:14:11.56,1:14:13.89,Default,,0,0,0,,这取决于你系统的相干性(耦合度) Dialogue: 0,1:14:13.89,1:14:17.03,Default,,0,0,0,,确实你可能想设计一个 Dialogue: 0,1:14:17.03,1:14:19.56,Default,,0,0,0,,不这样递归下降的程序 Dialogue: 0,1:14:19.61,1:14:22.97,Default,,0,0,0,,但是我举这个例子的好处 就在于我们通常都是这么做的 Dialogue: 0,1:14:25.44,1:14:27.63,Default,,0,0,0,,学生:是不是有一个问题 我想 Dialogue: 0,1:14:27.63,1:14:32.95,Default,,0,0,0,,就是你会被这个结构捆绑起来 Dialogue: 0,1:14:32.95,1:14:36.33,Default,,0,0,0,,这个递归的结构是实际上被执行了的 Dialogue: 0,1:14:36.33,1:14:40.34,Default,,0,0,0,,而不是仅仅是为了定义类型的需要 Dialogue: 0,1:14:40.34,1:14:41.16,Default,,0,0,0,,被这个事实所束缚 Dialogue: 0,1:14:44.68,1:14:46.12,Default,,0,0,0,,教授:我大概明白你的意思 Dialogue: 0,1:14:46.12,1:14:47.80,Default,,0,0,0,,你是想说在这个系统投入运行之后 Dialogue: 0,1:14:47.82,1:14:50.40,Default,,0,0,0,,这些类型还会变得越来越复杂 Dialogue: 0,1:14:50.40,1:14:50.73,Default,,0,0,0,,你是不是想…… Dialogue: 0,1:14:50.73,1:14:50.99,Default,,0,0,0,,学生:对 Dialogue: 0,1:14:50.99,1:14:51.79,Default,,0,0,0,,在它投入运行之后 Dialogue: 0,1:14:52.09,1:14:54.18,Default,,0,0,0,,学生:而不是作为基本的定义 Dialogue: 0,1:14:54.18,1:14:54.83,Default,,0,0,0,,教授:对 Dialogue: 0,1:14:54.83,1:14:56.70,Default,,0,0,0,,我们的类型结构可以说就是递归的 Dialogue: 0,1:14:57.21,1:15:00.22,Default,,0,0,0,,它并不是一个 可以在系统投入运行之前 Dialogue: 0,1:15:01.58,1:15:04.85,Default,,0,0,0,,就能把要用到的东西全部包括的列表 Dialogue: 0,1:15:04.85,1:15:05.79,Default,,0,0,0,,它是一个不断演进的东西 Dialogue: 0,1:15:06.78,1:15:08.64,Default,,0,0,0,,所以如果你想要定制这个系统 Dialogue: 0,1:15:08.67,1:15:10.96,Default,,0,0,0,,你就不能通过有限的表 Dialogue: 0,1:15:11.00,1:15:13.18,Default,,0,0,0,,你需要用一个递归结构实现它 Dialogue: 0,1:15:13.67,1:15:17.90,Default,,0,0,0,,学生:因为类型的基本结构是相当简单而明了的 Dialogue: 0,1:15:17.90,1:15:18.19,Default,,0,0,0,,教授:对 Dialogue: 0,1:15:20.40,1:15:20.75,Default,,0,0,0,,嗯? Dialogue: 0,1:15:21.46,1:15:22.87,Default,,0,0,0,,学生:我有一个问题 Dialogue: 0,1:15:22.87,1:15:25.68,Default,,0,0,0,,我明白一旦你的数据结构被设计好之后 Dialogue: 0,1:15:25.71,1:15:28.73,Default,,0,0,0,,它是怎么把complex标志拿掉 把它传递给下层 Dialogue: 0,1:15:28.73,1:15:30.64,Default,,0,0,0,,然后把rect类型拿掉 再传递给下层 Dialogue: 0,1:15:30.64,1:15:33.95,Default,,0,0,0,,但是如果你只是一个用户 并不知道什么rect或者polar类型 Dialogue: 0,1:15:34.25,1:15:36.04,Default,,0,0,0,,你怎么知道如何去设置这个数据结构 Dialogue: 0,1:15:36.09,1:15:38.08,Default,,0,0,0,,让所有东西正常运转呢 Dialogue: 0,1:15:38.09,1:15:41.00,Default,,0,0,0,,如果我只知道左边的这个算式 Dialogue: 0,1:15:41.02,1:15:42.50,Default,,0,0,0,,我只是想把复数加起来或者乘起来 Dialogue: 0,1:15:42.50,1:15:43.64,Default,,0,0,0,,教授:这就是它神奇的地方 Dialogue: 0,1:15:43.64,1:15:45.26,Default,,0,0,0,,如果你是一个用户 直接调用mul就可以了 Dialogue: 0,1:15:47.73,1:15:49.95,Default,,0,0,0,,学生:然后它就能明白我要计算的是复数? Dialogue: 0,1:15:49.96,1:15:51.23,Default,,0,0,0,,或者我怎么告诉它我想—— Dialogue: 0,1:15:51.26,1:15:53.05,Default,,0,0,0,,教授:只要你给它的是复数它就能明白 Dialogue: 0,1:15:53.05,1:15:56.30,Default,,0,0,0,,作为这个系统的用户 Dialogue: 0,1:15:56.32,1:15:58.14,Default,,0,0,0,,你能使用的是复数的构造函数 Dialogue: 0,1:15:58.37,1:15:59.55,Default,,0,0,0,,学生:那么我需要自己构造复数了? Dialogue: 0,1:15:59.56,1:16:00.35,Default,,0,0,0,,教授:那么你需要自己构造它们 Dialogue: 0,1:16:00.35,1:16:04.01,Default,,0,0,0,,作为用户 你可能只能够操作命令行 Dialogue: 0,1:16:04.65,1:16:07.56,Default,,0,0,0,,它会给你提供一些合理的方法 Dialogue: 0,1:16:07.56,1:16:08.86,Default,,0,0,0,,来输入复数 Dialogue: 0,1:16:09.31,1:16:11.00,Default,,0,0,0,,让你用你喜欢的格式输入 Dialogue: 0,1:16:11.59,1:16:14.36,Default,,0,0,0,,也可能你根本就不用输入它们 Dialogue: 0,1:16:14.36,1:16:16.17,Default,,0,0,0,,只是别人给你一个复数让你计算 Dialogue: 0,1:16:16.78,1:16:19.82,Default,,0,0,0,,学生:好 那么如果我有一个含有多项式的复数 Dialogue: 0,1:16:19.82,1:16:21.96,Default,,0,0,0,,我就要先构造这个多项式 然后再构造我的复数 Dialogue: 0,1:16:21.96,1:16:23.96,Default,,0,0,0,,教授:如果你是从零开始构造它的话 是这样的 Dialogue: 0,1:16:24.28,1:16:25.71,Default,,0,0,0,,可以说你是在从零开始构造 Dialogue: 0,1:16:25.71,1:16:27.05,Default,,0,0,0,,而你只要有了要计算的东西 Dialogue: 0,1:16:27.28,1:16:30.32,Default,,0,0,0,,可以直接调用mul运算 然后它们就会被乘起来 Dialogue: 0,1:16:32.78,1:16:32.99,Default,,0,0,0,,说吧 Dialogue: 0,1:16:33.27,1:16:35.76,Default,,0,0,0,,学生:我想提一个问题 就是…… Dialogue: 0,1:16:36.45,1:16:40.01,Default,,0,0,0,,比如说我想修改我的复数表示方法 Dialogue: 0,1:16:40.03,1:16:41.44,Default,,0,0,0,,或者复数的某些运算 Dialogue: 0,1:16:41.52,1:16:47.10,Default,,0,0,0,,为了修改一个特定的运算 Dialogue: 0,1:16:47.15,1:16:51.26,Default,,0,0,0,,我得考虑多少代码? Dialogue: 0,1:16:52.27,1:16:53.49,Default,,0,0,0,,教授:得看你想要修改什么 Dialogue: 0,1:16:53.49,1:16:54.99,Default,,0,0,0,,重点在于你只需要改 Dialogue: 0,1:16:55.39,1:16:56.07,Default,,0,0,0,,你想改的那一部分 Dialogue: 0,1:16:56.07,1:17:00.04,Default,,0,0,0,,想象一下如果Martha决定她 Dialogue: 0,1:17:00.32,1:17:01.23,Default,,0,0,0,,举个不太好的例子 Dialogue: 0,1:17:01.44,1:17:02.91,Default,,0,0,0,,比如把序对中两个数的顺序调换 Dialogue: 0,1:17:04.04,1:17:08.72,Default,,0,0,0,,把模和辐角的顺序反过来 Dialogue: 0,1:17:09.39,1:17:10.80,Default,,0,0,0,,她只做了局部的修改 Dialogue: 0,1:17:10.97,1:17:13.29,Default,,0,0,0,,那么这个改动会准确无误地扩散到整个系统里 Dialogue: 0,1:17:14.79,1:17:18.76,Default,,0,0,0,,或者突然你说 我有另一种方法来表示有理数 Dialogue: 0,1:17:19.70,1:17:23.90,Default,,0,0,0,,我就得不断地在表格中添加运算 Dialogue: 0,1:17:24.82,1:17:27.22,Default,,0,0,0,,那么突然之间所有的多项式 Dialogue: 0,1:17:27.22,1:17:29.10,Default,,0,0,0,,它们的系数和系数的系数 或者什么东西 Dialogue: 0,1:17:29.24,1:17:32.40,Default,,0,0,0,,都自动支持用这种表示方法来表示了 Dialogue: 0,1:17:32.70,1:17:34.67,Default,,0,0,0,,这就是我们这种设计的威力 Dialogue: 0,1:17:36.11,1:17:38.70,Default,,0,0,0,,学生:我提的这个问题可能听起来比较蠢 Dialogue: 0,1:17:38.70,1:17:42.38,Default,,0,0,0,,整个这个系统看起来 Dialogue: 0,1:17:42.54,1:17:45.88,Default,,0,0,0,,非常完美 所有的东西都各就各位 Dialogue: 0,1:17:46.72,1:17:48.67,Default,,0,0,0,,完美得有点出乎意料 Dialogue: 0,1:17:50.93,1:17:52.52,Default,,0,0,0,,我相信 这都是为了教学方便 Dialogue: 0,1:17:52.56,1:17:54.65,Default,,0,0,0,,我怀疑的是首先发明了这种做法的人 Dialogue: 0,1:17:55.10,1:17:55.85,Default,,0,0,0,,我可能说得不对 Dialogue: 0,1:17:56.60,1:17:59.72,Default,,0,0,0,,难道一下子就搞清楚了所有这些东西一起 Dialogue: 0,1:17:59.77,1:18:03.93,Default,,0,0,0,,只要把这些放在一起 你就突然可以对各种对象做各种运算 Dialogue: 0,1:18:04.86,1:18:07.20,Default,,0,0,0,,我觉得他们应该研究了很长时间 Dialogue: 0,1:18:07.93,1:18:10.62,Default,,0,0,0,,不断地推倒重来 Dialogue: 0,1:18:11.80,1:18:14.12,Default,,0,0,0,,然后我觉得 当我们设计一个非常复杂的系统 Dialogue: 0,1:18:14.12,1:18:16.94,Default,,0,0,0,,我们也要面对这样的问题 Dialogue: 0,1:18:17.31,1:18:20.35,Default,,0,0,0,,就是有太多各种各样的部件 我们甚至不知道 Dialogue: 0,1:18:21.08,1:18:24.62,Default,,0,0,0,,我们甚至不知道要对这些部件做什么样的操作 Dialogue: 0,1:18:24.62,1:18:26.54,Default,,0,0,0,,在这种时候我怎么用这种良好的方法组织操作 Dialogue: 0,1:18:26.56,1:18:29.63,Default,,0,0,0,,才能获得这种 不管怎样只要把它们放在一起 Dialogue: 0,1:18:29.63,1:18:31.39,Default,,0,0,0,,所有事情就正常运转 这样的效果呢 Dialogue: 0,1:18:31.70,1:18:34.34,Default,,0,0,0,,教授:很好 这确实是一个非常聪明的问题 Dialogue: 0,1:18:35.10,1:18:39.52,Default,,0,0,0,,要说的一点是我们这种方法论 Dialogue: 0,1:18:39.87,1:18:43.88,Default,,0,0,0,,受到了符号代数的很多启发 Dialogue: 0,1:18:44.59,1:18:45.90,Default,,0,0,0,,符号代数相当繁复 Dialogue: 0,1:18:47.59,1:18:50.71,Default,,0,0,0,,允许你在决定各种运算是什么样子之前 Dialogue: 0,1:18:50.71,1:18:52.89,Default,,0,0,0,,来实现这个系统 Dialogue: 0,1:18:53.31,1:18:57.72,Default,,0,0,0,,所以从某种意义上讲 这是人们在这方面长期探索之后得出的答案 Dialogue: 0,1:18:58.56,1:19:00.75,Default,,0,0,0,,从另一个角度来说 这确实是精心设计的例子 Dialogue: 0,1:19:02.16,1:19:06.24,Default,,0,0,0,,学生:看上去想要设计出这样的系统 Dialogue: 0,1:19:06.24,1:19:09.01,Default,,0,0,0,,一开始先要研究一段时间然后才能变熟练 Dialogue: 0,1:19:09.01,1:19:11.88,Default,,0,0,0,,教授:我给你看看这个东西是多么的勉强 Dialogue: 0,1:19:12.22,1:19:14.13,Default,,0,0,0,,你现在可以写下所有的这些程序 Dialogue: 0,1:19:14.13,1:19:16.25,Default,,0,0,0,,但是我写在这里的这个系统 Dialogue: 0,1:19:17.02,1:19:18.96,Default,,0,0,0,,如果允许我拖堂半小时的话 Dialogue: 0,1:19:19.31,1:19:20.46,Default,,0,0,0,,我会给大家讲 Dialogue: 0,1:19:20.81,1:19:23.02,Default,,0,0,0,,如果我让它做一个错误操作 Dialogue: 0,1:19:23.20,1:19:29.31,Default,,0,0,0,,比如一个愚蠢的命令 用3加上7/2 它就会崩溃 Dialogue: 0,1:19:30.88,1:19:33.42,Default,,0,0,0,,因为程序首先会调用operate-2这个过程 Dialogue: 0,1:19:33.80,1:19:35.95,Default,,0,0,0,,然后operate-2会说 这个是数字类型 Dialogue: 0,1:19:36.18,1:19:37.37,Default,,0,0,0,,那个是有理数类型 Dialogue: 0,1:19:37.56,1:19:38.81,Default,,0,0,0,,我不知道怎么把它们加起来 Dialogue: 0,1:19:41.53,1:19:44.30,Default,,0,0,0,,那么你想让这个系统至少能够 Dialogue: 0,1:19:45.88,1:19:47.34,Default,,0,0,0,,比如说 在做这个操作之前 Dialogue: 0,1:19:48.59,1:19:50.24,Default,,0,0,0,,把3提升为3/1 Dialogue: 0,1:19:50.48,1:19:53.21,Default,,0,0,0,,把它变成一个有理数 然后交给有理数程序包来处理 Dialogue: 0,1:19:54.86,1:19:58.70,Default,,0,0,0,,课堂上我们来不及讲这个问题了 Dialogue: 0,1:19:58.73,1:20:00.88,Default,,0,0,0,,书里面讨论了这个问题 Dialogue: 0,1:20:00.88,1:20:01.95,Default,,0,0,0,,叫做“类型转换” Dialogue: 0,1:20:03.39,1:20:05.15,Default,,0,0,0,,你想要的是 Dialogue: 0,1:20:05.31,1:20:08.89,Default,,0,0,0,,看 我们小心翼翼地把对象按类型分好类 Dialogue: 0,1:20:08.91,1:20:12.17,Default,,0,0,0,,但是有时你也想让它 Dialogue: 0,1:20:12.40,1:20:17.98,Default,,0,0,0,,知道怎么把一个普通的数字当成有理数 Dialogue: 0,1:20:19.11,1:20:21.29,Default,,0,0,0,,或者把普通的数字当成复数 Dialogue: 0,1:20:21.62,1:20:25.16,Default,,0,0,0,,到那个时候系统就开始变得复杂了 Dialogue: 0,1:20:25.76,1:20:28.12,Default,,0,0,0,,就是你去思考 我应该把这些知识放在哪里的时候 Dialogue: 0,1:20:28.42,1:20:32.19,Default,,0,0,0,,是应该让有理数知道它们是由普通的数字构成的吗? Dialogue: 0,1:20:33.13,1:20:36.38,Default,,0,0,0,,或者我们举一个更加糟糕的例子 Dialogue: 0,1:20:38.14,1:20:47.48,Default,,0,0,0,,比如说我想要把一个复数加到有理数上去 Dialogue: 0,1:20:49.87,1:20:50.76,Default,,0,0,0,,这个不好 Dialogue: 0,1:20:50.76,1:20:51.58,Default,,0,0,0,,5/7 Dialogue: 0,1:20:53.86,1:20:55.72,Default,,0,0,0,,然后整个系统里必须有人知道 Dialogue: 0,1:20:56.06,1:20:58.16,Default,,0,0,0,,他需要把这个东西变成另一种类型 Dialogue: 0,1:20:58.20,1:21:00.65,Default,,0,0,0,,要把它变成一部分是有理数的复数 Dialogue: 0,1:21:01.54,1:21:02.68,Default,,0,0,0,,那么谁应该去操心这个事情呢 Dialogue: 0,1:21:02.68,1:21:03.95,Default,,0,0,0,,是complex程序包吗? Dialogue: 0,1:21:03.95,1:21:05.03,Default,,0,0,0,,是rational程序包吗? Dialogue: 0,1:21:05.24,1:21:06.22,Default,,0,0,0,,还是plus过程要考虑这个问题? Dialogue: 0,1:21:06.90,1:21:08.52,Default,,0,0,0,,这就是体现复杂性的地方 Dialogue: 0,1:21:08.52,1:21:11.38,Default,,0,0,0,,也是这个问题的特别之处 Dialogue: 0,1:21:11.38,1:21:14.12,Default,,0,0,0,,同时很多的 实际上是所有的这样的“消息传递”的想法 Dialogue: 0,1:21:14.64,1:21:16.54,Default,,0,0,0,,都是被这样的问题启发的 Dialogue: 0,1:21:18.46,1:21:20.89,Default,,0,0,0,,当你真正深入进去 Dialogue: 0,1:21:20.91,1:21:24.76,Default,,0,0,0,,人们发现 代数操作的问题是如此复杂 Dialogue: 0,1:21:25.18,1:21:27.41,Default,,0,0,0,,而那些一直围绕它们工作的人们 确实就处在 Dialogue: 0,1:21:27.41,1:21:28.05,Default,,0,0,0,,你说的那种状态 Dialogue: 0,1:21:28.05,1:21:29.71,Default,,0,0,0,,他们在这些问题里艰难跋涉 时不时陷进泥里 Dialogue: 0,1:21:29.72,1:21:31.37,Default,,0,0,0,,寻找好用的工具 并试着提炼一种通用方法 Dialogue: 0,1:21:34.20,1:21:37.76,Default,,0,0,0,,学生:我想再一次回到这个复杂度的问题上来 Dialogue: 0,1:21:38.41,1:21:44.55,Default,,0,0,0,,在修改底层过程的时候 这个系统 Dialogue: 0,1:21:44.55,1:21:48.32,Default,,0,0,0,,毫无疑问 体现了非常大的灵活性 Dialogue: 0,1:21:49.71,1:21:53.40,Default,,0,0,0,,但是确实 在某种意义上讲 Dialogue: 0,1:21:53.44,1:21:55.26,Default,,0,0,0,,冻结了高层运算 Dialogue: 0,1:21:55.45,1:21:58.51,Default,,0,0,0,,或者至少如果你修改它们 你不知道 Dialogue: 0,1:21:58.51,1:22:02.06,Default,,0,0,0,,改动会体现在哪里 会怎么体现出来 Dialogue: 0,1:22:02.20,1:22:04.22,Default,,0,0,0,,教授:这个问题真是不能再好了 Dialogue: 0,1:22:04.68,1:22:05.87,Default,,0,0,0,,我要做的事情就是 Dialogue: 0,1:22:08.68,1:22:10.84,Default,,0,0,0,,如果我决定添加一个通用操作 Dialogue: 0,1:22:11.45,1:22:13.07,Default,,0,0,0,,比如equality-test Dialogue: 0,1:22:14.96,1:22:17.15,Default,,0,0,0,,那么系统中的其它人就要查表格 Dialogue: 0,1:22:18.22,1:22:22.54,Default,,0,0,0,,来看他们需不需要支持equality-test Dialogue: 0,1:22:24.65,1:22:26.84,Default,,0,0,0,,我们可以让它变得更加去中心化 Dialogue: 0,1:22:27.87,1:22:30.70,Default,,0,0,0,,这就是之前我提示了很多次的事情 Dialogue: 0,1:22:31.08,1:22:33.26,Default,,0,0,0,,你不但可以通过给对象添加符号标签来体现类型 Dialogue: 0,1:22:33.40,1:22:38.70,Default,,0,0,0,,而是把每一类对象接受的运算也保存在里面 Dialogue: 0,1:22:40.45,1:22:43.90,Default,,0,0,0,,那么你可以添加一个 比如说最大公约数过程 Dialogue: 0,1:22:44.43,1:22:46.81,Default,,0,0,0,,它只能计算整数 Dialogue: 0,1:22:47.40,1:22:49.21,Default,,0,0,0,,而不是对所有有理数都通用 Dialogue: 0,1:22:51.03,1:22:53.11,Default,,0,0,0,,所以这个系统可能是非常非常碎片化的 Dialogue: 0,1:22:53.11,1:22:55.66,Default,,0,0,0,,取决于你想让哪一部分比较灵活 Dialogue: 0,1:22:56.22,1:22:59.02,Default,,0,0,0,,有一系列的地方让你把这个东西放进去 Dialogue: 0,1:22:59.96,1:23:02.56,Default,,0,0,0,,但是你也指出了这种设计的弱点 Dialogue: 0,1:23:02.60,1:23:06.37,Default,,0,0,0,,就是必须在顶层 对于这些通用运算符有一些约定 Dialogue: 0,1:23:06.37,1:23:07.82,Default,,0,0,0,,或者至少人们要考虑这件事情 Dialogue: 0,1:23:08.39,1:23:10.72,Default,,0,0,0,,或者你可以决定 把这个表格设计得非常稀疏 Dialogue: 0,1:23:10.75,1:23:11.96,Default,,0,0,0,,里面只放很少的一点东西 Dialogue: 0,1:23:14.01,1:23:15.49,Default,,0,0,0,,这个游戏有很多种玩法 Dialogue: 0,1:23:19.78,1:23:20.43,Default,,0,0,0,,谢谢大家 Dialogue: 0,1:23:23.53,1:23:36.56,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:23:23.53,1:23:36.56,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec4b.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Last Style Storage: Default Audio File: ../../../../Movies/SICP480p/lec4b_480_muxed.mp4 Video File: ../../../../Movies/SICP480p/lec4b_480_muxed.mp4 Video AR Mode: 4 Video AR Value: 1.333333 Video Zoom Percent: 2.000000 Active Line: 6 Video Position: 690 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:02.25,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:04.33,0:00:10.35,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:04.33,0:00:10.35,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.33,0:00:10.35,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N刘殊君(rtmagic) Dialogue: 0,0:00:04.33,0:00:10.35,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:04.33,0:00:10.35,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:11.40,0:00:16.50,Declare,,0,0,0,,{\an2\fad(500,500)}通用运算符 Dialogue: 0,0:00:20.18,0:00:21.84,Default,,0,0,0,,教授:到目前为止 我们已经进行了很多 Dialogue: 0,0:00:21.84,0:00:23.78,Default,,0,0,0,,关于数据抽象的讨论 Dialogue: 0,0:00:23.78,0:00:27.15,Default,,0,0,0,,关键理念就是在构造系统的时候 Dialogue: 0,0:00:27.74,0:00:32.56,Default,,0,0,0,,在其中加入水平的抽象屏障 这些抽象屏障 Dialogue: 0,0:00:33.42,0:00:39.21,Default,,0,0,0,,把你使用一个数据对象的方式 Dialogue: 0,0:00:39.93,0:00:41.18,Default,,0,0,0,,和表示它的方式区分开来 Dialogue: 0,0:00:49.40,0:00:52.03,Default,,0,0,0,,或者可以这样理解它 在上层有一个老板 Dialogue: 0,0:00:52.11,0:00:55.50,Default,,0,0,0,,想要调用某种数据对象 Dialogue: 0,0:00:57.11,0:01:02.31,Default,,0,0,0,,而在下层 George负责它的具体实现 Dialogue: 0,0:01:02.31,0:01:05.42,Default,,0,0,0,,这种把使用与表示分离的想法 Dialogue: 0,0:01:05.44,0:01:09.76,Default,,0,0,0,,可以让你分开考虑这两个问题 Dialogue: 0,0:01:10.60,0:01:14.76,Default,,0,0,0,,这是一种非常强大的编程的方法论 -- 数据抽象 Dialogue: 0,0:01:15.93,0:01:18.81,Default,,0,0,0,,但另一方面 数据抽象在那些真正复杂的系统上 Dialogue: 0,0:01:19.56,0:01:21.84,Default,,0,0,0,,并不是很有效 Dialogue: 0,0:01:22.96,0:01:27.64,Default,,0,0,0,,这个问题就出在George这里 Dialogue: 0,0:01:28.64,0:01:32.09,Default,,0,0,0,,或者说 实际上 问题就在于 Dialogue: 0,0:01:32.09,0:01:32.78,Default,,0,0,0,,现在有太多的George Dialogue: 0,0:01:34.63,0:01:35.39,Default,,0,0,0,,具体地说 Dialogue: 0,0:01:35.39,0:01:39.18,Default,,0,0,0,,假设现在有George和Martha两个人 Dialogue: 0,0:01:41.19,0:01:44.22,Default,,0,0,0,,他们都是这个系统的开发人员 Dialogue: 0,0:01:46.04,0:01:47.29,Default,,0,0,0,,都在设计数据的表示方法 Dialogue: 0,0:01:48.41,0:01:50.67,Default,,0,0,0,,而且他们完全合不来 Dialogue: 0,0:01:51.75,0:01:53.62,Default,,0,0,0,,他们不会合作开发同一种表示方法 Dialogue: 0,0:01:54.01,0:01:55.34,Default,,0,0,0,,永远也不会 Dialogue: 0,0:01:57.48,0:01:59.72,Default,,0,0,0,,现在的问题是 假设你想要这样一个系统 Dialogue: 0,0:02:00.06,0:02:02.60,Default,,0,0,0,,在这个系统中George和Martha都为它设计了数据表示方法 Dialogue: 0,0:02:03.82,0:02:08.08,Default,,0,0,0,,但是如果你在高于这个抽象屏障的层面思考 Dialogue: 0,0:02:09.40,0:02:11.04,Default,,0,0,0,,你就不用去操心这些事情 Dialogue: 0,0:02:11.66,0:02:14.18,Default,,0,0,0,,不用操心 某个东西是到底是George做的还是Martha做的 Dialogue: 0,0:02:14.18,0:02:15.43,Default,,0,0,0,,同时你也不想让George和Martha Dialogue: 0,0:02:15.43,0:02:16.48,Default,,0,0,0,,妨碍彼此的工作 Dialogue: 0,0:02:16.63,0:02:20.31,Default,,0,0,0,,你在设计系统的时候 不仅仅需要这些 Dialogue: 0,0:02:20.31,0:02:23.84,Default,,0,0,0,,水平的抽象屏障 同时也想设置一道 Dialogue: 0,0:02:25.82,0:02:30.64,Default,,0,0,0,,垂直的屏障 -- 来把George和Martha分离开 Dialogue: 0,0:02:32.98,0:02:35.40,Default,,0,0,0,,我们来说得再具体一点 Dialogue: 0,0:02:36.56,0:02:40.54,Default,,0,0,0,,想象一个很大的公司的人事记录 Dialogue: 0,0:02:41.18,0:02:46.11,Default,,0,0,0,,这个公司里有很多部门没什么联系 Dialogue: 0,0:02:47.90,0:02:49.71,Default,,0,0,0,,并且部门之间合作得也不太好 Dialogue: 0,0:02:50.43,0:02:57.04,Default,,0,0,0,,甚至还可以想象这个大公司就是由 Dialogue: 0,0:02:57.04,0:02:59.45,Default,,0,0,0,,很多公司组成的 而且每个公司 Dialogue: 0,0:02:59.45,0:03:00.70,Default,,0,0,0,,都有自己的一套人事记录 Dialogue: 0,0:03:03.25,0:03:06.57,Default,,0,0,0,,想象一下突然有一天 这些部门 Dialogue: 0,0:03:06.57,0:03:08.53,Default,,0,0,0,,被一种神奇的卫星网络连接起来 Dialogue: 0,0:03:08.53,0:03:10.52,Default,,0,0,0,,它们各自的数据库都被放到了一起 Dialogue: 0,0:03:12.24,0:03:13.85,Default,,0,0,0,,现在你想要 Dialogue: 0,0:03:14.84,0:03:16.33,Default,,0,0,0,,在公司的任何地方 Dialogue: 0,0:03:17.26,0:03:23.13,Default,,0,0,0,,都能够知道 哦 某一条人事记录里的 Dialogue: 0,0:03:23.13,0:03:23.87,Default,,0,0,0,,“姓名”是什么 Dialogue: 0,0:03:26.30,0:03:29.15,Default,,0,0,0,,或者一条记录里的“工作”是什么 Dialogue: 0,0:03:30.54,0:03:34.40,Default,,0,0,0,,同时又不需要担心每一个部门 Dialogue: 0,0:03:34.84,0:03:36.76,Default,,0,0,0,,对于人事记录的格式 Dialogue: 0,0:03:36.76,0:03:39.37,Default,,0,0,0,,有着完全不同的习惯 Dialogue: 0,0:03:41.58,0:03:43.26,Default,,0,0,0,,从你的视角上你不想去了解这些东西 Dialogue: 0,0:03:44.96,0:03:47.92,Default,,0,0,0,,那么怎么才能做到这样呢? Dialogue: 0,0:03:48.43,0:03:52.41,Default,,0,0,0,,当然 一种方法是下发一个告示 Dialogue: 0,0:03:52.64,0:03:56.29,Default,,0,0,0,,来通知所有人把他们的记录格式 Dialogue: 0,0:03:56.29,0:03:57.24,Default,,0,0,0,,都改成某种标准的格式 Dialogue: 0,0:03:58.07,0:04:00.12,Default,,0,0,0,,人们经常这样做 但都没有成功 Dialogue: 0,0:04:01.82,0:04:07.34,Default,,0,0,0,,另一个办法则是重新安排这些记录 Dialogue: 0,0:04:08.33,0:04:09.90,Default,,0,0,0,,让它们中间有这种垂直的抽象屏障 Dialogue: 0,0:04:11.25,0:04:14.40,Default,,0,0,0,,当你查询一份人事档案里的姓名的时候 Dialogue: 0,0:04:14.43,0:04:17.97,Default,,0,0,0,,不管它是什么格式 name这个过程都能设法 Dialogue: 0,0:04:17.97,0:04:19.42,Default,,0,0,0,,搞清楚怎么正确地完成这件事 Dialogue: 0,0:04:22.73,0:04:25.53,Default,,0,0,0,,我们把name叫做一个 所谓的“通用运算符” Dialogue: 0,0:04:26.26,0:04:30.06,Default,,0,0,0,,通用运算符意味着它会根据数据的种类 Dialogue: 0,0:04:30.06,0:04:31.69,Default,,0,0,0,,准确地做出对应的操作 Dialogue: 0,0:04:33.65,0:04:36.62,Default,,0,0,0,,更进一步讲 你想让这个系统在 Dialogue: 0,0:04:36.92,0:04:39.79,Default,,0,0,0,,下次公司里多了一个新的人员划分的时候 Dialogue: 0,0:04:42.51,0:04:45.64,Default,,0,0,0,,人们连接系统的方法不会有很大的变化 Dialogue: 0,0:04:45.64,0:04:50.11,Default,,0,0,0,,并且公司里剩下的部门 Dialogue: 0,0:04:50.11,0:04:52.01,Default,,0,0,0,,要把它们的人员记录添加到这个系统 Dialogue: 0,0:04:52.27,0:04:53.93,Default,,0,0,0,,也不需要做什么大的修改 Dialogue: 0,0:04:55.52,0:04:57.52,Default,,0,0,0,,那么这就是你应该考虑的问题 Dialogue: 0,0:04:58.70,0:05:00.77,Default,,0,0,0,,或者这就是你的工作 Dialogue: 0,0:05:00.77,0:05:03.77,Default,,0,0,0,,要让系统可以用最少的改动来拥抱变化 Dialogue: 0,0:05:05.98,0:05:08.12,Default,,0,0,0,,这就是我们今天要讨论的问题 Dialogue: 0,0:05:09.44,0:05:14.22,Default,,0,0,0,,你脑子里应该有这个分布式的人事档案系统 Dialogue: 0,0:05:14.24,0:05:16.62,Default,,0,0,0,,但是实际上 我今天要讨论的是一个 Dialogue: 0,0:05:16.62,0:05:18.48,Default,,0,0,0,,比那要更加自成体系的问题 Dialogue: 0,0:05:19.29,0:05:21.76,Default,,0,0,0,,我觉得用它可以把事情说得更清楚一点 Dialogue: 0,0:05:21.87,0:05:26.01,Default,,0,0,0,,我们要讨论的是 复数域上的算术系统 Dialogue: 0,0:05:27.77,0:05:28.92,Default,,0,0,0,,我们来看看这个系统 Dialogue: 0,0:05:30.69,0:05:31.74,Default,,0,0,0,,来复习一下 Dialogue: 0,0:05:32.04,0:05:33.53,Default,,0,0,0,,什么是“复数” Dialogue: 0,0:05:35.25,0:05:38.22,Default,,0,0,0,,复数z可以看做复平面上的一点 Dialogue: 0,0:05:39.37,0:05:47.19,Default,,0,0,0,,我们将复数表示为实数部分和虚数部分 Dialogue: 0,0:05:47.19,0:05:50.83,Default,,0,0,0,,所以如果这个是复数z 它的实部是这么多 Dialogue: 0,0:05:51.50,0:05:53.24,Default,,0,0,0,,它的虚部是那么多 Dialogue: 0,0:05:54.33,0:05:56.44,Default,,0,0,0,,我们就可以记z=x+iy Dialogue: 0,0:05:59.11,0:06:03.21,Default,,0,0,0,,还有另一种方法来表示一个复数 比如说 Dialogue: 0,0:06:03.21,0:06:09.00,Default,,0,0,0,,这个点与原点的距离是多少 在原点的什么角度上 Dialogue: 0,0:06:11.32,0:06:16.67,Default,,0,0,0,,像这样 复数也可以表示为半径乘以一个角度 Dialogue: 0,0:06:19.52,0:06:21.92,Default,,0,0,0,,第一种表示法称为 直角坐标系表示 Dialogue: 0,0:06:22.59,0:06:25.45,Default,,0,0,0,,或者说实部-虚部表示 Dialogue: 0,0:06:26.20,0:06:30.04,Default,,0,0,0,,而后一种是用模和辐角两部分的极坐标表示 Dialogue: 0,0:06:30.04,0:06:31.48,Default,,0,0,0,,并且如果你知道了一个复数的实部和虚部 Dialogue: 0,0:06:31.53,0:06:33.36,Default,,0,0,0,,你就能计算出它的模和辐角 Dialogue: 0,0:06:33.72,0:06:36.97,Default,,0,0,0,,如果知道了x和y 就能用这个式子算出r Dialogue: 0,0:06:37.19,0:06:39.48,Default,,0,0,0,,等于两个数平方和的平方根 然后就可以 Dialogue: 0,0:06:39.48,0:06:40.76,Default,,0,0,0,,用反三角函数算出辐角的值 Dialogue: 0,0:06:41.42,0:06:44.42,Default,,0,0,0,,或者反过来 如果你知道了r和A Dialogue: 0,0:06:44.42,0:06:45.31,Default,,0,0,0,,你也能计算出x和y Dialogue: 0,0:06:45.80,0:06:49.43,Default,,0,0,0,,x=r·cos(A) y=r·sin(A) Dialogue: 0,0:06:51.34,0:06:53.66,Default,,0,0,0,,这是表示复数的两种不同方法 Dialogue: 0,0:06:54.13,0:06:57.15,Default,,0,0,0,,分别是极坐标形式和直角坐标形式 Dialogue: 0,0:06:57.15,0:06:58.12,Default,,0,0,0,,我们要设计的是 Dialogue: 0,0:06:58.32,0:07:01.32,Default,,0,0,0,,一个复数域上的算术系统 Dialogue: 0,0:07:03.95,0:07:05.12,Default,,0,0,0,,换句话讲 我们要 Dialogue: 0,0:07:05.58,0:07:06.99,Default,,0,0,0,,就像之前课上有理数运算的例子一样 Dialogue: 0,0:07:07.38,0:07:10.20,Default,,0,0,0,,是构造一个叫做+c的操作 Dialogue: 0,0:07:10.73,0:07:13.90,Default,,0,0,0,,它将两个复数然后把它们相加、相减 Dialogue: 0,0:07:14.35,0:07:16.94,Default,,0,0,0,,相乘或者相除 Dialogue: 0,0:07:20.73,0:07:25.28,Default,,0,0,0,,那么我们要用到一点点数学 Dialogue: 0,0:07:25.28,0:07:28.36,Default,,0,0,0,,对它们进行操作的具体的算式是什么 Dialogue: 0,0:07:30.41,0:07:31.92,Default,,0,0,0,,它们是怎么得出来的 并不重要 Dialogue: 0,0:07:34.00,0:07:35.79,Default,,0,0,0,,我们只是用它们实现运算 Dialogue: 0,0:07:35.80,0:07:37.95,Default,,0,0,0,,如果想要把两个复数相加 Dialogue: 0,0:07:39.13,0:07:42.66,Default,,0,0,0,,可以很容易地获取它们的实部和虚部 Dialogue: 0,0:07:42.66,0:07:45.93,Default,,0,0,0,,两个复数的和的实部 Dialogue: 0,0:07:47.72,0:07:49.72,Default,,0,0,0,,z1+z2的实部 Dialogue: 0,0:07:50.06,0:07:54.64,Default,,0,0,0,,就是z1的实部加上z2的实部 Dialogue: 0,0:07:57.82,0:08:01.60,Default,,0,0,0,,然后z1+z2的虚部也就是 Dialogue: 0,0:08:01.74,0:08:05.66,Default,,0,0,0,,z1的虚部加上z2的虚部 Dialogue: 0,0:08:07.41,0:08:09.48,Default,,0,0,0,,所以复数相加是非常简单的事情 Dialogue: 0,0:08:09.48,0:08:10.99,Default,,0,0,0,,你只要把各个部分分别加起来 Dialogue: 0,0:08:11.31,0:08:13.18,Default,,0,0,0,,然后用结果构建一个新的复数 Dialogue: 0,0:08:13.37,0:08:14.73,Default,,0,0,0,,如果你想要让复数相乘 Dialogue: 0,0:08:15.53,0:08:17.82,Default,,0,0,0,,那么在极坐标下运算会方便很多 Dialogue: 0,0:08:17.82,0:08:20.38,Default,,0,0,0,,因为对于两个复数 Dialogue: 0,0:08:20.40,0:08:26.54,Default,,0,0,0,,两复数积之模 就是它们各自的模的乘积 Dialogue: 0,0:08:28.85,0:08:33.88,Default,,0,0,0,,它们的积的辐角 就是两个辐角的和 Dialogue: 0,0:08:35.80,0:08:40.54,Default,,0,0,0,,这就是复数域上的运算所需的数学知识 Dialogue: 0,0:08:40.54,0:08:42.38,Default,,0,0,0,,我们来想一想具体的实现 Dialogue: 0,0:08:43.72,0:08:47.39,Default,,0,0,0,,我们就像之前运算有理数那样做 Dialogue: 0,0:08:49.84,0:08:53.47,Default,,0,0,0,,来到底层 假设有一些构造函数和选择函数 Dialogue: 0,0:08:53.76,0:08:54.52,Default,,0,0,0,,它们应该是什么样子呢 Dialogue: 0,0:08:55.33,0:08:58.16,Default,,0,0,0,,假设我们制造了一些表示数据对象的“云彩” Dialogue: 0,0:08:58.54,0:09:00.78,Default,,0,0,0,,也就是用某种形式表示的复数 Dialogue: 0,0:09:01.79,0:09:04.67,Default,,0,0,0,,我们能从这个复数中得到它的实部 Dialogue: 0,0:09:05.52,0:09:09.64,Default,,0,0,0,,可以获得 虚部、模、或者辐角 Dialogue: 0,0:09:12.15,0:09:14.01,Default,,0,0,0,,然后我们需要一种方法来构造复数 Dialogue: 0,0:09:14.03,0:09:15.64,Default,,0,0,0,,不仅要有选择函数 还要有构造函数 Dialogue: 0,0:09:16.80,0:09:19.52,Default,,0,0,0,,那么假设我们有一个叫做make-rectangular的过程 Dialogue: 0,0:09:19.53,0:09:24.27,Default,,0,0,0,,这个过程的功能是接受一个实部 Dialogue: 0,0:09:24.51,0:09:29.36,Default,,0,0,0,,和一个虚部 然后把这两个部分组合成一个复数 Dialogue: 0,0:09:31.92,0:09:35.01,Default,,0,0,0,,同样我们也可以构造一个make-polar过程 Dialogue: 0,0:09:35.01,0:09:37.85,Default,,0,0,0,,它接受一个模和一个辐角 Dialogue: 0,0:09:40.83,0:09:43.90,Default,,0,0,0,,然后用这两个值 组成一个复数 Dialogue: 0,0:09:44.68,0:09:45.46,Default,,0,0,0,,那么这个系统 Dialogue: 0,0:09:45.46,0:09:47.77,Default,,0,0,0,,里面会有两个构造函数和四个选择函数 Dialogue: 0,0:09:48.91,0:09:55.15,Default,,0,0,0,,现在 就像之前课程中那样 我们基于这个抽象的数据结构 Dialogue: 0,0:09:55.15,0:09:59.22,Default,,0,0,0,,继续实现复数的各种运算 Dialogue: 0,0:09:59.22,0:10:02.30,Default,,0,0,0,,而这些Lisp代码 Dialogue: 0,0:10:03.23,0:10:07.47,Default,,0,0,0,,是从我之前写的算术公式“翻译”而来的 Dialogue: 0,0:10:08.06,0:10:09.98,Default,,0,0,0,,如果我想把两个复数相加 Dialogue: 0,0:10:11.76,0:10:15.56,Default,,0,0,0,,我就要用一个实部和一个虚部构造一个复数 Dialogue: 0,0:10:16.72,0:10:19.02,Default,,0,0,0,,这个新的复数的实部是 Dialogue: 0,0:10:19.40,0:10:21.80,Default,,0,0,0,,两个复数的实部的和 Dialogue: 0,0:10:23.31,0:10:25.37,Default,,0,0,0,,它的虚数部分是 Dialogue: 0,0:10:25.40,0:10:27.52,Default,,0,0,0,,两个复数的虚部的和 Dialogue: 0,0:10:30.31,0:10:32.09,Default,,0,0,0,,我把它们放到一起 构造出一个复数 Dialogue: 0,0:10:32.16,0:10:34.44,Default,,0,0,0,,这就是实现复数加法的方法 Dialogue: 0,0:10:35.78,0:10:38.49,Default,,0,0,0,,减法实际上是一样的 Dialogue: 0,0:10:39.65,0:10:42.97,Default,,0,0,0,,只需要把各个部分相加变成把它们相减 Dialogue: 0,0:10:45.14,0:10:47.07,Default,,0,0,0,,要把两个复数相乘 Dialogue: 0,0:10:47.74,0:10:49.02,Default,,0,0,0,,要用另外一个式子 Dialogue: 0,0:10:49.27,0:10:53.84,Default,,0,0,0,,我会用一个模和一个辐角来构造一个复数 Dialogue: 0,0:10:55.35,0:10:56.44,Default,,0,0,0,,z1*z2的模 Dialogue: 0,0:10:56.65,0:11:00.97,Default,,0,0,0,,就是z1的模乘以z2的模 Dialogue: 0,0:11:03.71,0:11:05.93,Default,,0,0,0,,而z1*z2的辐角则是 Dialogue: 0,0:11:06.16,0:11:08.51,Default,,0,0,0,,z1的辐角加上z2的辐角 Dialogue: 0,0:11:09.62,0:11:10.96,Default,,0,0,0,,那么这就是乘法的实现 Dialogue: 0,0:11:11.23,0:11:12.25,Default,,0,0,0,,然后是除法 Dialogue: 0,0:11:14.27,0:11:15.90,Default,,0,0,0,,除法和乘法几乎是一样的 Dialogue: 0,0:11:17.37,0:11:19.58,Default,,0,0,0,,我只要把两个模相除 把辐角相减就可以了 Dialogue: 0,0:11:28.36,0:11:30.46,Default,,0,0,0,,现在我已经实现了各种运算 Dialogue: 0,0:11:31.87,0:11:33.64,Default,,0,0,0,,然后我们做什么 Dialogue: 0,0:11:33.64,0:11:34.52,Default,,0,0,0,,我们把George叫来 Dialogue: 0,0:11:36.06,0:11:38.79,Default,,0,0,0,,我们完成了“使用”的部分 现在应该考虑“表示”了 Dialogue: 0,0:11:38.80,0:11:40.94,Default,,0,0,0,,我们叫来George然后对他说 Dialogue: 0,0:11:40.97,0:11:43.61,Default,,0,0,0,,“为我们设计一个一套复数的表示方法” Dialogue: 0,0:11:45.25,0:11:47.44,Default,,0,0,0,,很好 Dialogue: 0,0:11:47.77,0:11:52.66,Default,,0,0,0,,George可能会说 我们把一个复数 Dialogue: 0,0:11:52.66,0:11:57.15,Default,,0,0,0,,实现为 一个由实部和虚部组成的序对 Dialogue: 0,0:11:57.20,0:12:02.62,Default,,0,0,0,,那么如果我想用某个实部和虚部来构造复数 Dialogue: 0,0:12:03.36,0:12:05.55,Default,,0,0,0,,我只需要把它们cons起来即可 这样可以-- Dialogue: 0,0:12:06.03,0:12:08.11,Default,,0,0,0,,这就是George表示复数的方法 Dialogue: 0,0:12:09.78,0:12:12.42,Default,,0,0,0,,那么如果我想获得它的实部 我只需要 Dialogue: 0,0:12:12.42,0:12:14.12,Default,,0,0,0,,提取出序对的car部分 -- 它的首部分 Dialogue: 0,0:12:14.35,0:12:16.67,Default,,0,0,0,,如果我想要得到虚部 我就提取出它的cdr部分 Dialogue: 0,0:12:19.64,0:12:21.77,Default,,0,0,0,,那对于模和辐角 又该如何取得呢? Dialogue: 0,0:12:22.22,0:12:25.75,Default,,0,0,0,,如果我想取得某个复数的模 Dialogue: 0,0:12:25.75,0:12:32.30,Default,,0,0,0,,我需要计算该复数car与cdr的平方和的算术平方根 Dialogue: 0,0:12:33.79,0:12:39.26,Default,,0,0,0,,如果我想得到辐角 我就计算它的cdr与car比值的反正切 Dialogue: 0,0:12:39.53,0:12:42.86,Default,,0,0,0,,这个Lisp过程用于计算反正切 Dialogue: 0,0:12:44.97,0:12:48.59,Default,,0,0,0,,要是有人给我一个模和辐角 Dialogue: 0,0:12:48.94,0:12:50.56,Default,,0,0,0,,并说:“给我构造一个复数” Dialogue: 0,0:12:50.89,0:12:56.24,Default,,0,0,0,,用它们计算出实部 r*cos(a) 和虚部 r*sin(a) Dialogue: 0,0:12:57.77,0:12:59.05,Default,,0,0,0,,连接成一个序对就行了 Dialogue: 0,0:13:01.46,0:13:02.26,Default,,0,0,0,,完成了 Dialogue: 0,0:13:02.26,0:13:04.75,Default,,0,0,0,,实际上我做的事情 在概念上讲 Dialogue: 0,0:13:06.89,0:13:09.37,Default,,0,0,0,,和我们之前提过的有理数的表示 Dialogue: 0,0:13:10.60,0:13:12.44,Default,,0,0,0,,是完全没有区别的 Dialogue: 0,0:13:12.75,0:13:13.91,Default,,0,0,0,,它们的思想相同 Dialogue: 0,0:13:13.91,0:13:16.28,Default,,0,0,0,,实现具体过程 选择一种表示方法 Dialogue: 0,0:13:18.07,0:13:18.65,Default,,0,0,0,,没有什么不同 Dialogue: 0,0:13:20.07,0:13:21.56,Default,,0,0,0,,现在我们来关心一下Martha Dialogue: 0,0:13:23.21,0:13:24.52,Default,,0,0,0,,嗯 Martha的想法不太一样 Dialogue: 0,0:13:26.67,0:13:28.57,Default,,0,0,0,,她不想把复数表示成 Dialogue: 0,0:13:28.59,0:13:30.90,Default,,0,0,0,,由实部和虚部组成的序对 Dialogue: 0,0:13:30.90,0:13:34.17,Default,,0,0,0,,她比较喜欢把它们表示成 Dialogue: 0,0:13:34.17,0:13:37.69,Default,,0,0,0,,由模和辐角组成的序对 Dialogue: 0,0:13:39.55,0:13:42.13,Default,,0,0,0,,那么如果我们没有让George而是让Martha Dialogue: 0,0:13:42.13,0:13:43.74,Default,,0,0,0,,来设计复数的表示方法 我们就会得到这样的东西 Dialogue: 0,0:13:44.57,0:13:47.16,Default,,0,0,0,,有一个make-polar过程 Dialogue: 0,0:13:47.16,0:13:50.22,Default,,0,0,0,,当然了 有了一个模和一个辐角之后 Dialogue: 0,0:13:50.22,0:13:53.07,Default,,0,0,0,,我们只要把它们组合成一个序对就行了 Dialogue: 0,0:13:55.43,0:13:57.68,Default,,0,0,0,,如果你想取得复数的模 那很简单 Dialogue: 0,0:13:58.24,0:13:59.37,Default,,0,0,0,,你只需要取序对的car部分即可 Dialogue: 0,0:13:59.78,0:14:02.67,Default,,0,0,0,,当然 想取得复数的辐角 那也很简单 Dialogue: 0,0:14:02.67,0:14:03.63,Default,,0,0,0,,只需取cdr部分即可 Dialogue: 0,0:14:04.81,0:14:07.02,Default,,0,0,0,,但是如果你想要获得实部和虚部 Dialogue: 0,0:14:07.42,0:14:08.49,Default,,0,0,0,,那就得费点力气 Dialogue: 0,0:14:08.88,0:14:14.58,Default,,0,0,0,,想得到实部 你就得计算r*cos(a) Dialogue: 0,0:14:14.58,0:14:19.99,Default,,0,0,0,,换句话讲 用序对的car部分去乘以 Dialogue: 0,0:14:19.99,0:14:20.95,Default,,0,0,0,,cdr部分的余弦值 Dialogue: 0,0:14:20.95,0:14:26.23,Default,,0,0,0,,然后你就算出了r*cos(a) Dialogue: 0,0:14:26.54,0:14:27.48,Default,,0,0,0,,这就是这个复数的实部 Dialogue: 0,0:14:28.33,0:14:31.40,Default,,0,0,0,,要是想算出它的虚部 用r乘以sin(a)就可以了 Dialogue: 0,0:14:32.66,0:14:37.93,Default,,0,0,0,,现在如果我给你一个实部和虚部 然后说 Dialogue: 0,0:14:37.93,0:14:42.03,Default,,0,0,0,,用它们给我构造一个复数 Dialogue: 0,0:14:42.03,0:14:44.17,Default,,0,0,0,,那就要先算出 Dialogue: 0,0:14:44.17,0:14:45.54,Default,,0,0,0,,模和辐角是多少 Dialogue: 0,0:14:45.54,0:14:47.85,Default,,0,0,0,,模是实部和虚部的平方和的算术平方根 Dialogue: 0,0:14:48.09,0:14:49.23,Default,,0,0,0,,辐角是这个反正切 Dialogue: 0,0:14:49.23,0:14:50.22,Default,,0,0,0,,我用这两个数构造一个序对 Dialogue: 0,0:14:52.09,0:14:54.17,Default,,0,0,0,,以上就是Martha的想法 Dialogue: 0,0:14:56.69,0:14:57.37,Default,,0,0,0,,那么哪种比较好呢? Dialogue: 0,0:14:59.68,0:15:03.15,Default,,0,0,0,,如果你需要做很多加法 那么George的比较好 Dialogue: 0,0:15:03.16,0:15:05.61,Default,,0,0,0,,因为你总是要用到复数的实部和虚部 Dialogue: 0,0:15:05.85,0:15:08.40,Default,,0,0,0,,如果你大多数时间都是在做乘法 Dialogue: 0,0:15:09.48,0:15:11.14,Default,,0,0,0,,那可能Martha的办法就要好一些 Dialogue: 0,0:15:11.14,0:15:14.84,Default,,0,0,0,,又或者 -- 这就是问题所在了 -- 你决定不了 Dialogue: 0,0:15:16.59,0:15:22.32,Default,,0,0,0,,或者出于某些个人原因 你想让它们同时存在 Dialogue: 0,0:15:23.48,0:15:26.76,Default,,0,0,0,,也可能你是真的无法决定你更喜欢哪种表示法 Dialogue: 0,0:15:28.56,0:15:32.32,Default,,0,0,0,,回到这个话题 我们真正想要的是这样一个系统 Dialogue: 0,0:15:32.65,0:15:36.17,Default,,0,0,0,,这里面 既有George 他实现了 Dialogue: 0,0:15:36.83,0:15:39.64,Default,,0,0,0,,复数的直角坐标表示 Dialogue: 0,0:15:41.47,0:15:44.25,Default,,0,0,0,,又有Martha 她实现了复数的极坐标表示 Dialogue: 0,0:15:46.12,0:15:49.69,Default,,0,0,0,,然后我们有各种运算 Dialogue: 0,0:15:50.28,0:15:56.89,Default,,0,0,0,,用来对复数进行加减乘除 Dialogue: 0,0:15:57.56,0:15:58.76,Default,,0,0,0,,那么这些运算 Dialogue: 0,0:15:59.34,0:16:02.79,Default,,0,0,0,,不应该被系统中同时存在的两种 Dialogue: 0,0:16:02.79,0:16:03.98,Default,,0,0,0,,互不兼容的复数表示方法影响 Dialogue: 0,0:16:04.41,0:16:08.33,Default,,0,0,0,,或者说 我们不光有像这样的一个抽象屏障 Dialogue: 0,0:16:09.64,0:16:11.84,Default,,0,0,0,,它里面有real-part Dialogue: 0,0:16:15.77,0:16:21.71,Default,,0,0,0,,还有 IMAG-PART、MAG 和 ANG 等几个过程 Dialogue: 0,0:16:23.83,0:16:25.36,Default,,0,0,0,,不光有一层抽象屏障 Dialogue: 0,0:16:25.39,0:16:28.38,Default,,0,0,0,,把实际的数据表示隐藏起来 Dialogue: 0,0:16:29.10,0:16:31.52,Default,,0,0,0,,还有一层垂直的屏障 Dialogue: 0,0:16:32.19,0:16:35.02,Default,,0,0,0,,容许不同的表示方法彼此共存 Dialogue: 0,0:16:35.87,0:16:37.40,Default,,0,0,0,,而不互相干预 Dialogue: 0,0:16:38.57,0:16:41.07,Default,,0,0,0,,我们的想法是把这些东西 Dialogue: 0,0:16:41.90,0:16:44.12,Default,,0,0,0,,REAL-PART、IMAG-PART、MAG、ANG 这些过程 Dialogue: 0,0:16:44.12,0:16:46.49,Default,,0,0,0,,设计成通用运算符 Dialogue: 0,0:16:47.31,0:16:49.45,Default,,0,0,0,,如果你调用real-part过程 它就会判断 Dialogue: 0,0:16:49.98,0:16:51.31,Default,,0,0,0,,要在哪一种表示方法中寻找它 Dialogue: 0,0:16:53.88,0:16:55.10,Default,,0,0,0,,那么我们怎么做到这一点呢 Dialogue: 0,0:16:56.84,0:16:59.23,Default,,0,0,0,,实际上有一个很容易想到的办法 Dialogue: 0,0:16:59.84,0:17:01.68,Default,,0,0,0,,如果你习惯了思考复数的模式 Dialogue: 0,0:17:02.52,0:17:04.44,Default,,0,0,0,,如果你已经习惯了复合数据的思想 Dialogue: 0,0:17:06.33,0:17:10.99,Default,,0,0,0,,假设你只要观察一个复数 Dialogue: 0,0:17:12.17,0:17:13.95,Default,,0,0,0,,就能看出它是被George还是Martha构造出来的 Dialogue: 0,0:17:15.79,0:17:18.90,Default,,0,0,0,,换句话说 在你眼前漂浮的这些东西 Dialogue: 0,0:17:18.90,0:17:20.91,Default,,0,0,0,,不是普通的复数 对吗? Dialogue: 0,0:17:20.91,0:17:22.94,Default,,0,0,0,,它们是被某个设计者“构想”出来的 Dialogue: 0,0:17:24.39,0:17:28.04,Default,,0,0,0,,当考察一个复数 我们会发现它“不仅仅”是个复数 Dialogue: 0,0:17:28.04,0:17:29.16,Default,,0,0,0,,它上面有一个标签 Dialogue: 0,0:17:29.19,0:17:30.75,Default,,0,0,0,,写着这个是由Martha制造的 Dialogue: 0,0:17:31.45,0:17:34.22,Default,,0,0,0,,或者这个是由George制造的 Dialogue: 0,0:17:34.48,0:17:35.39,Default,,0,0,0,,对吧?它们被签了名字 Dialogue: 0,0:17:36.86,0:17:40.15,Default,,0,0,0,,在这之后 无论何时我们看见一个复数 Dialogue: 0,0:17:40.15,0:17:45.48,Default,,0,0,0,,我们只要看它的标签 然后我们就能知道 Dialogue: 0,0:17:45.80,0:17:46.72,Default,,0,0,0,,应该怎么对它进行运算 Dialogue: 0,0:17:48.03,0:17:51.19,Default,,0,0,0,,或者说 我们想要的不只是普通的数据对象 Dialogue: 0,0:17:51.19,0:17:54.37,Default,,0,0,0,,我们引入一个概念:带类型的数据 Dialogue: 0,0:17:59.76,0:18:02.81,Default,,0,0,0,,带类型的数据就意味着 这里有一朵“云彩” Dialogue: 0,0:18:03.94,0:18:08.93,Default,,0,0,0,,它里面有我们之前所说的那种 Dialogue: 0,0:18:08.93,0:18:09.90,Default,,0,0,0,,普通的数据对象 Dialogue: 0,0:18:13.18,0:18:16.54,Default,,0,0,0,,这是它的内容 就是实际的数据 Dialogue: 0,0:18:19.32,0:18:21.56,Default,,0,0,0,,它里面还有一个叫做类型的东西 Dialogue: 0,0:18:22.56,0:18:25.24,Default,,0,0,0,,被George或者Martha签了名 Dialogue: 0,0:18:25.99,0:18:28.27,Default,,0,0,0,,那么我们现在就要从无类型的数据进入带类型数据的领域 Dialogue: 0,0:18:31.95,0:18:32.71,Default,,0,0,0,,我们怎么构造它 Dialogue: 0,0:18:32.71,0:18:33.50,Default,,0,0,0,,那很简单 Dialogue: 0,0:18:33.84,0:18:35.32,Default,,0,0,0,,我们知道怎么构造“云彩” Dialogue: 0,0:18:35.80,0:18:36.88,Default,,0,0,0,,我们用序对来组成它们 Dialogue: 0,0:18:37.92,0:18:41.82,Default,,0,0,0,,那么我们就有了一种方法来表示带类型的数据 Dialogue: 0,0:18:43.51,0:18:49.64,Default,,0,0,0,,这种方法叫做 把类型附加到内容上 Dialogue: 0,0:18:49.69,0:18:50.64,Default,,0,0,0,,用cons就可以做到 Dialogue: 0,0:18:51.64,0:18:54.11,Default,,0,0,0,,然后面对一个带类型的数据 我们就可以知道它的类型 Dialogue: 0,0:18:55.21,0:18:56.00,Default,,0,0,0,,也就是序对的car部分 Dialogue: 0,0:18:56.29,0:18:58.30,Default,,0,0,0,,我们也可以知道它的具体内容 就是它的cdr部分 Dialogue: 0,0:18:59.96,0:19:04.28,Default,,0,0,0,,我们用这种方法使用带类型的数据 Dialogue: 0,0:19:05.29,0:19:07.26,Default,,0,0,0,,面对一段类型数据就能知道它是什么类型 Dialogue: 0,0:19:07.52,0:19:09.26,Default,,0,0,0,,那么我们现在有了几种判断类型的谓词 Dialogue: 0,0:19:10.51,0:19:13.73,Default,,0,0,0,,举例来讲 想要知道一个复数 Dialogue: 0,0:19:13.73,0:19:16.86,Default,,0,0,0,,是不是George构造的 是不是直角坐标表示的 我们只需要看 Dialogue: 0,0:19:16.86,0:19:21.85,Default,,0,0,0,,它的“类型”是不是rectangular这个符号 Dialogue: 0,0:19:23.68,0:19:25.05,Default,,0,0,0,,对吧?检查 rectangular 符号 Dialogue: 0,0:19:27.20,0:19:30.33,Default,,0,0,0,,同理 想要知道一个复数是不是Martha构造的 Dialogue: 0,0:19:30.33,0:19:33.42,Default,,0,0,0,,我们就看它的“类型”是不是polar这个符号 Dialogue: 0,0:19:36.46,0:19:39.21,Default,,0,0,0,,那么这就是一种识别数字的类型的方法 Dialogue: 0,0:19:40.75,0:19:42.81,Default,,0,0,0,,现在来想想 怎么用这种方法来构建系统 Dialogue: 0,0:19:43.87,0:19:46.73,Default,,0,0,0,,我们假设George和Martha分别在做各自的工作 Dialogue: 0,0:19:47.36,0:19:52.64,Default,,0,0,0,,每一个人都设计了他们的复数表示程序包 Dialogue: 0,0:19:52.64,0:19:58.52,Default,,0,0,0,,他们怎么让自己的东西成为系统的一部分 Dialogue: 0,0:19:58.73,0:20:00.14,Default,,0,0,0,,和对方友好共存呢 Dialogue: 0,0:20:00.14,0:20:02.11,Default,,0,0,0,,那其实非常简单 Dialogue: 0,0:20:02.72,0:20:04.51,Default,,0,0,0,,回忆一下 George做了这个程序包 Dialogue: 0,0:20:05.97,0:20:08.48,Default,,0,0,0,,这就是George的程序包 或者说它的一部分 Dialogue: 0,0:20:08.98,0:20:11.15,Default,,0,0,0,,然后红色下划线标出的部分是他需要做的修改 Dialogue: 0,0:20:12.09,0:20:16.43,Default,,0,0,0,,之前 当George用x和y构建了一个复数的时候 Dialogue: 0,0:20:17.52,0:20:19.85,Default,,0,0,0,,他只是把它们组合成一个序对 Dialogue: 0,0:20:20.93,0:20:23.39,Default,,0,0,0,,现在唯一不同的地方是 他给它们打了标签 Dialogue: 0,0:20:24.09,0:20:28.08,Default,,0,0,0,,他把类型 -- 也就是 rectangular符号 -- 附加到这个序对上面 Dialogue: 0,0:20:30.60,0:20:33.26,Default,,0,0,0,,剩下的事情都和之前一样 除了一点 Dialogue: 0,0:20:33.92,0:20:38.06,Default,,0,0,0,,就是George和Martha的程序都有叫做real-part和imaginary-part的过程 Dialogue: 0,0:20:38.70,0:20:42.96,Default,,0,0,0,,为了这些过程存在于在同一个Lisp环境中 Dialogue: 0,0:20:44.22,0:20:45.92,Default,,0,0,0,,George就要修改他的过程名字 Dialogue: 0,0:20:45.92,0:20:49.14,Default,,0,0,0,,那么我们说 这是George的real-part过程 Dialogue: 0,0:20:49.14,0:20:51.16,Default,,0,0,0,,叫做real-part-rectangular过程 Dialogue: 0,0:20:51.48,0:20:54.06,Default,,0,0,0,,还有 imag-part-rectangular过程 Dialogue: 0,0:20:55.42,0:20:57.24,Default,,0,0,0,,那么这里是George的程序包剩下的部分 Dialogue: 0,0:20:59.13,0:21:02.06,Default,,0,0,0,,他已经有了magnitude和angle过程 只要把它们改名 Dialogue: 0,0:21:02.06,0:21:04.16,Default,,0,0,0,,叫magnitude-rectangular和angle-rectangular就好了 Dialogue: 0,0:21:06.08,0:21:07.96,Default,,0,0,0,,Martha要做的事情基本相同 Dialogue: 0,0:21:09.86,0:21:16.22,Default,,0,0,0,,在这之前 当她用模和辐角构造复数的时候 Dialogue: 0,0:21:18.14,0:21:19.27,Default,,0,0,0,,她只是把这两个东西cons起来 Dialogue: 0,0:21:19.27,0:21:20.86,Default,,0,0,0,,现在她额外附加类型 polar Dialogue: 0,0:21:23.95,0:21:25.61,Default,,0,0,0,,然后修改过程的名字 Dialogue: 0,0:21:25.66,0:21:29.85,Default,,0,0,0,,来避免保证她的real-part过程和George的产生冲突 Dialogue: 0,0:21:30.71,0:21:32.99,Default,,0,0,0,,分别改为real-part-polar和imaginary-part-polar Dialogue: 0,0:21:34.54,0:21:38.06,Default,,0,0,0,,magnitude-polar和angle-polar这四个过程 Dialogue: 0,0:21:45.00,0:21:46.13,Default,,0,0,0,,现在我们的系统 Dialogue: 0,0:21:46.13,0:21:47.92,Default,,0,0,0,,在它里面既有George又有Martha Dialogue: 0,0:21:49.16,0:21:51.68,Default,,0,0,0,,然后现在我们需要一个经理来对类型进行判断 Dialogue: 0,0:21:52.83,0:21:56.48,Default,,0,0,0,,那么在George和Martha给我们提供了类型数据之后 Dialogue: 0,0:21:57.05,0:21:59.40,Default,,0,0,0,,这个系统现在怎么工作呢? Dialogue: 0,0:22:00.53,0:22:04.30,Default,,0,0,0,,我们手里有的 是一堆通用选择函数 Dialogue: 0,0:22:05.26,0:22:10.63,Default,,0,0,0,,用于复数的通用选择函数比如 real-part、imag-part、magnitude和angle等 Dialogue: 0,0:22:14.14,0:22:15.40,Default,,0,0,0,,让我们更进一步观察它们 Dialogue: 0,0:22:17.93,0:22:19.00,Default,,0,0,0,,real-part过程应该做什么 Dialogue: 0,0:22:19.31,0:22:22.76,Default,,0,0,0,,如果我想得到一个复数的实部 Dialogue: 0,0:22:24.07,0:22:24.91,Default,,0,0,0,,那么我先要观察它 Dialogue: 0,0:22:25.80,0:22:26.69,Default,,0,0,0,,我观察它的类型 Dialogue: 0,0:22:26.69,0:22:28.12,Default,,0,0,0,,考虑它是用直角坐标表示的吗 Dialogue: 0,0:22:31.02,0:22:35.36,Default,,0,0,0,,如果是的话 我就对这个复数的"内容"部分 Dialogue: 0,0:22:36.06,0:22:37.92,Default,,0,0,0,,调用George的real-part过程 Dialogue: 0,0:22:41.07,0:22:42.94,Default,,0,0,0,,这是一个带有类型的数字 Dialogue: 0,0:22:43.72,0:22:47.66,Default,,0,0,0,,我用contents过程剥掉类型 并且对它应用George的过程 Dialogue: 0,0:22:50.70,0:22:52.86,Default,,0,0,0,,那如果是一个用极坐标表示的复数呢? Dialogue: 0,0:22:53.95,0:22:54.97,Default,,0,0,0,,如果我想要得到它的实部 Dialogue: 0,0:22:55.45,0:22:58.78,Default,,0,0,0,,我就把Martha的real-part过程应用在这个数的内容上 Dialogue: 0,0:22:59.85,0:23:01.15,Default,,0,0,0,,这就是real-part工作的方式 Dialogue: 0,0:23:02.26,0:23:05.66,Default,,0,0,0,,还有类似的imag-part过程 几乎是一样的 Dialogue: 0,0:23:06.51,0:23:09.60,Default,,0,0,0,,它先观察这个数字 它是直角坐标表示的 Dialogue: 0,0:23:09.60,0:23:11.13,Default,,0,0,0,,就调用George的imaginary-part过程 Dialogue: 0,0:23:11.13,0:23:12.83,Default,,0,0,0,,是极坐标表示的 就用Martha的过程 Dialogue: 0,0:23:13.38,0:23:17.40,Default,,0,0,0,,同理也可以构造出magnitude和angle两个过程 Dialogue: 0,0:23:19.71,0:23:21.02,Default,,0,0,0,,我们的系统是这个样子 Dialogue: 0,0:23:23.00,0:23:24.26,Default,,0,0,0,,它里面有三个部分 Dialogue: 0,0:23:24.26,0:23:26.59,Default,,0,0,0,,有George、Martha和一个经理 Dialogue: 0,0:23:26.76,0:23:28.97,Default,,0,0,0,,这就是实现通用操作符的方法 Dialogue: 0,0:23:28.97,0:23:32.92,Default,,0,0,0,,为了把它说清楚 我们举一个简单的实例 Dialogue: 0,0:23:33.50,0:23:35.12,Default,,0,0,0,,但是准确描述了它工作的方式 Dialogue: 0,0:23:36.54,0:23:43.98,Default,,0,0,0,,假设你现在 面对一个实部是1 Dialogue: 0,0:23:44.52,0:23:46.09,Default,,0,0,0,,虚部是2的复数 Dialogue: 0,0:23:46.09,0:23:48.44,Default,,0,0,0,,也就是1+2i Dialogue: 0,0:23:50.31,0:23:52.64,Default,,0,0,0,,现在在这里 Dialogue: 0,0:23:55.28,0:23:57.53,Default,,0,0,0,,在操作发生的上层 Dialogue: 0,0:23:57.63,0:24:08.27,Default,,0,0,0,,复数被表示成一个由1和2组成的序对加上类型信息 Dialogue: 0,0:24:10.48,0:24:11.39,Default,,0,0,0,,(1和2)是内容 Dialogue: 0,0:24:11.87,0:24:17.96,Default,,0,0,0,,整个的数据就是在那之上加上一个rectangular符号 Dialogue: 0,0:24:18.14,0:24:21.53,Default,,0,0,0,,这就是复数在这个系统里存在的形式 Dialogue: 0,0:24:22.33,0:24:24.92,Default,,0,0,0,,你要调取real-part的时候 Dialogue: 0,0:24:25.84,0:24:28.89,Default,,0,0,0,,经理会检查这个数然后说 这是George构造的数字 Dialogue: 0,0:24:30.27,0:24:31.53,Default,,0,0,0,,他会先把类型拿掉 Dialogue: 0,0:24:33.34,0:24:36.91,Default,,0,0,0,,然后把 (1,2) 这个序对传递给George Dialogue: 0,0:24:38.00,0:24:42.27,Default,,0,0,0,,这是George的系统可以直接处理的数据 Dialogue: 0,0:24:44.36,0:24:45.92,Default,,0,0,0,,那么它被拆了出来 Dialogue: 0,0:24:46.52,0:24:49.76,Default,,0,0,0,,之后 如果你让George构造一个复数 Dialogue: 0,0:24:51.24,0:24:54.56,Default,,0,0,0,,George就会把它构造成序对 Dialogue: 0,0:24:55.07,0:24:58.24,Default,,0,0,0,,在数据被传递到上层之前 Dialogue: 0,0:24:59.42,0:25:01.13,Default,,0,0,0,,经理会再给它加上rectangular类型 Dialogue: 0,0:25:03.92,0:25:04.65,Default,,0,0,0,,看这个过程 Dialogue: 0,0:25:04.65,0:25:05.85,Default,,0,0,0,,这个系统不会发生混乱 Dialogue: 0,0:25:05.85,0:25:10.84,Default,,0,0,0,,就算在Martha的世界里 序对(1 2)的含义完全不同 Dialogue: 0,0:25:13.50,0:25:15.75,Default,,0,0,0,,也并没有什么影响 Dialogue: 0,0:25:15.75,0:25:18.44,Default,,0,0,0,,在Martha的世界里这个序对代表了 Dialogue: 0,0:25:18.44,0:25:20.78,Default,,0,0,0,,一个模为1 辐角为2的复数 Dialogue: 0,0:25:21.19,0:25:22.19,Default,,0,0,0,,但是这并不会造成混乱 Dialogue: 0,0:25:22.22,0:25:27.25,Default,,0,0,0,,因为每当有一个这样的序对经由经理之手 Dialogue: 0,0:25:27.25,0:25:29.61,Default,,0,0,0,,被交给主系统的时候 它都会被附加上polar的类型标志 Dialogue: 0,0:25:31.21,0:25:33.67,Default,,0,0,0,,而这个就会被贴上rectangular类型的标签 Dialogue: 0,0:25:36.93,0:25:37.90,Default,,0,0,0,,好 我们休息一下 Dialogue: 0,0:25:40.77,0:25:55.55,Default,,0,0,0,,[音乐] Dialogue: 0,0:25:55.69,0:25:57.77,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:25:57.77,0:25:59.76,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:26:05.21,0:26:11.95,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:26:12.84,0:26:16.75,Declare,,0,0,0,,{\an2\fad(500,500)}通用运算符 Dialogue: 0,0:26:20.21,0:26:24.15,Default,,0,0,0,,我们刚刚提出了一种实现通用运算符的策略 Dialogue: 0,0:26:24.15,0:26:31.40,Default,,0,0,0,,这种策略有一个名字 叫做“基于类型的分派” Dialogue: 0,0:26:34.31,0:26:39.36,Default,,0,0,0,,它的想法就是你要把你的系统分成很多小块 Dialogue: 0,0:26:39.36,0:26:42.67,Default,,0,0,0,,里面有George和Martha在设计表示方法 Dialogue: 0,0:26:43.37,0:26:44.38,Default,,0,0,0,,还有一个经理 Dialogue: 0,0:26:46.12,0:26:48.06,Default,,0,0,0,,负责去看数据上的类型是什么 Dialogue: 0,0:26:48.51,0:26:50.59,Default,,0,0,0,,然后分派给正确的人去处理 Dialogue: 0,0:26:51.99,0:26:56.01,Default,,0,0,0,,这种组织系统的方法有什么缺点呢? Dialogue: 0,0:26:58.15,0:27:00.40,Default,,0,0,0,,首先 有个小小的烦人的问题 Dialogue: 0,0:27:00.40,0:27:03.05,Default,,0,0,0,,George和Martha需要修改他们的过程的名字 Dialogue: 0,0:27:04.00,0:27:05.95,Default,,0,0,0,,George一开始写了一个real-part过程 Dialogue: 0,0:27:05.98,0:27:08.28,Default,,0,0,0,,现在他必须把它的名字改成real-part-rectangular Dialogue: 0,0:27:08.30,0:27:10.83,Default,,0,0,0,,才能让它不与Martha的real-part过程相互冲突 Dialogue: 0,0:27:10.84,0:27:12.76,Default,,0,0,0,,而Martha的过程现在改叫real-part-polar Dialogue: 0,0:27:13.64,0:27:16.68,Default,,0,0,0,,这是为了不和经理的那个叫做real-part的过程发生冲突 Dialogue: 0,0:27:17.31,0:27:18.94,Default,,0,0,0,,这个问题确实很恼人 Dialogue: 0,0:27:19.46,0:27:21.13,Default,,0,0,0,,但是我现在暂时不讨论这个问题 Dialogue: 0,0:27:21.27,0:27:22.35,Default,,0,0,0,,我们稍后将会看到 Dialogue: 0,0:27:23.26,0:27:26.12,Default,,0,0,0,,在讨论到Lisp名称与环境的结构的时候 Dialogue: 0,0:27:26.12,0:27:30.39,Default,,0,0,0,,我们会有方法把这些所谓的命名空间分开来封装 Dialogue: 0,0:27:30.39,0:27:31.56,Default,,0,0,0,,然后它们就不会互相影响了 Dialogue: 0,0:27:32.50,0:27:34.01,Default,,0,0,0,,现在我们暂时不去考虑这个问题 Dialogue: 0,0:27:35.72,0:27:38.19,Default,,0,0,0,,我现在想关注的问题是 Dialogue: 0,0:27:38.36,0:27:43.24,Default,,0,0,0,,你把一个新人招纳进系统之中会发生什么 Dialogue: 0,0:27:44.51,0:27:45.32,Default,,0,0,0,,会发生什么? Dialogue: 0,0:27:45.32,0:27:46.81,Default,,0,0,0,,George和Martha并不关心 Dialogue: 0,0:27:47.42,0:27:50.73,Default,,0,0,0,,George在他的直角坐标世界里 Dialogue: 0,0:27:52.20,0:27:53.84,Default,,0,0,0,,坐拥着他的过程和数据类型 Dialogue: 0,0:27:54.09,0:27:55.74,Default,,0,0,0,,而Martha待在她的极坐标世界中 Dialogue: 0,0:27:55.93,0:27:57.02,Default,,0,0,0,,不问世事 Dialogue: 0,0:27:59.38,0:28:00.54,Default,,0,0,0,,但是经理呢? Dialogue: 0,0:28:00.62,0:28:02.84,Default,,0,0,0,,经理需要做什么? Dialogue: 0,0:28:03.18,0:28:06.20,Default,,0,0,0,,现在经理带着他的运算来了 Dialogue: 0,0:28:07.36,0:28:09.04,Default,,0,0,0,,有直角坐标的判断 Dialogue: 0,0:28:09.04,0:28:10.14,Default,,0,0,0,,和极坐标的判断过程 Dialogue: 0,0:28:10.14,0:28:14.91,Default,,0,0,0,,如果Harry带着某种新型的复数表示方法 进入这个系统 Dialogue: 0,0:28:17.21,0:28:19.96,Default,,0,0,0,,同时带来了一个新的类型--Harry型复数 Dialogue: 0,0:28:20.27,0:28:23.28,Default,,0,0,0,,经理就需要修改他所有的过程 Dialogue: 0,0:28:25.24,0:28:26.94,Default,,0,0,0,,所以这个系统的不灵活之处 Dialogue: 0,0:28:26.96,0:28:32.41,Default,,0,0,0,,也就是需要大量工作才能适应变化的地方 就在这个经理身上 Dialogue: 0,0:28:34.89,0:28:35.99,Default,,0,0,0,,那是非常恼人的事情 Dialogue: 0,0:28:35.99,0:28:37.21,Default,,0,0,0,,更恼人的是 Dialogue: 0,0:28:39.05,0:28:41.21,Default,,0,0,0,,你意识到这个经理实际上什么也不做 Dialogue: 0,0:28:42.59,0:28:44.67,Default,,0,0,0,,这个经理只负责“传递公文”而已 Dialogue: 0,0:28:45.84,0:28:51.13,Default,,0,0,0,,我们再来看看这些程序 它们在做什么 Dialogue: 0,0:28:51.76,0:28:52.72,Default,,0,0,0,,real-part过程在做什么 Dialogue: 0,0:28:52.88,0:28:56.17,Default,,0,0,0,,这个过程说 哦 这个复数是 Dialogue: 0,0:28:56.17,0:28:57.00,Default,,0,0,0,,George会处理的那一种吗 Dialogue: 0,0:28:57.00,0:28:58.27,Default,,0,0,0,,如果是的话 好 把它交给George处理 Dialogue: 0,0:28:59.41,0:29:01.76,Default,,0,0,0,,它是Martha能操作的那一种吗 Dialogue: 0,0:29:01.82,0:29:04.06,Default,,0,0,0,,是的话 把它交给Martha处理 Dialogue: 0,0:29:05.04,0:29:08.72,Default,,0,0,0,,这个系统真正恼人之处 也就是这个系统的瓶颈 Dialogue: 0,0:29:08.72,0:29:11.66,Default,,0,0,0,,它降低灵活性 阻碍变化 Dialogue: 0,0:29:12.09,0:29:14.36,Default,,0,0,0,,完全是一种的官僚主义 Dialogue: 0,0:29:15.00,0:29:17.02,Default,,0,0,0,,而不是任何做实事的人 Dialogue: 0,0:29:19.70,0:29:21.80,Default,,0,0,0,,很可惜这种情况经常发生 Dialogue: 0,0:29:23.18,0:29:24.41,Default,,0,0,0,,实际上发生的事情是 Dialogue: 0,0:29:24.48,0:29:26.97,Default,,0,0,0,,在系统中 有一张抽象的表格 Dialogue: 0,0:29:28.10,0:29:30.08,Default,,0,0,0,,实际发生的事情是 有这样一张表格 Dialogue: 0,0:29:30.84,0:29:33.64,Default,,0,0,0,,其中有各种类型 Dialogue: 0,0:29:34.40,0:29:38.96,Default,,0,0,0,,有polar和rectangular Dialogue: 0,0:29:41.55,0:29:43.02,Default,,0,0,0,,可能Harry也在这里 Dialogue: 0,0:29:44.38,0:29:46.56,Default,,0,0,0,,然后这里是各种运算符 Dialogue: 0,0:29:48.05,0:29:58.24,Default,,0,0,0,,各种运算符 比如real-part和imag-part Dialogue: 0,0:30:00.01,0:30:04.22,Default,,0,0,0,,还有magnitude、angle这些运算符 Dialogue: 0,0:30:05.83,0:30:18.97,Default,,0,0,0,,单元格中对应的是相应过程 Dialogue: 0,0:30:19.28,0:30:21.99,Default,,0,0,0,,那么填在这里 负责polar类型的real-part过程的是 Dialogue: 0,0:30:21.99,0:30:27.56,Default,,0,0,0,,Martha的real-part-polar过程 Dialogue: 0,0:30:30.57,0:30:36.62,Default,,0,0,0,,然后在这里是George的real-part-rectangular过程 Dialogue: 0,0:30:37.74,0:30:43.07,Default,,0,0,0,,然后这里是Martha的magnitude-polar过程 Dialogue: 0,0:30:44.46,0:30:49.76,Default,,0,0,0,,然后是George的magnitude-rectangular过程 等等等等 Dialogue: 0,0:30:49.76,0:30:51.24,Default,,0,0,0,,剩下的单元格也像这样填好 Dialogue: 0,0:30:52.39,0:30:54.26,Default,,0,0,0,,这就是实际上发生的事情 Dialogue: 0,0:30:57.63,0:31:01.74,Default,,0,0,0,,从某种意义上讲 经理做的事情就是 Dialogue: 0,0:31:02.11,0:31:04.11,Default,,0,0,0,,去扮演这张表格 Dialogue: 0,0:31:06.86,0:31:08.70,Default,,0,0,0,,那我们怎么去修补这个系统呢 Dialogue: 0,0:31:11.74,0:31:13.77,Default,,0,0,0,,怎么去消灭这种官僚主义? Dialogue: 0,0:31:13.77,0:31:15.44,Default,,0,0,0,,你要做的就是让这个经理走人 Dialogue: 0,0:31:16.01,0:31:19.55,Default,,0,0,0,,我们用一台计算机来代替他 Dialogue: 0,0:31:20.17,0:31:21.76,Default,,0,0,0,,我们要让自动操作抹掉他存在的意义 Dialogue: 0,0:31:23.32,0:31:26.57,Default,,0,0,0,,也就是说 我们不用这个经理去查阅这个表格 Dialogue: 0,0:31:27.45,0:31:29.32,Default,,0,0,0,,而是让我们的系统直接去查阅它 Dialogue: 0,0:31:31.02,0:31:32.11,Default,,0,0,0,,这是什么意思呢? Dialogue: 0,0:31:32.11,0:31:36.19,Default,,0,0,0,,我们来假设 还是用数据抽象的观点 Dialogue: 0,0:31:37.71,0:31:40.40,Default,,0,0,0,,我们有这样一种表格数据结构 Dialogue: 0,0:31:40.88,0:31:43.61,Default,,0,0,0,,而且我们还有把东西填进去和从中删除的方法 Dialogue: 0,0:31:44.35,0:31:49.04,Default,,0,0,0,,为了把话说清楚 我们假设现在有一个叫put的方法 Dialogue: 0,0:31:50.30,0:31:58.32,Default,,0,0,0,,本例中put方法接受两个参数 -- 我们称其为“关键字” -- key1和key2 Dialogue: 0,0:32:00.13,0:32:00.99,Default,,0,0,0,,还有接受一个值 Dialogue: 0,0:32:06.20,0:32:11.12,Default,,0,0,0,,put过程把value存放在表格key1和key2对应的格子里 Dialogue: 0,0:32:11.49,0:32:13.16,Default,,0,0,0,,然后我们假设有另一个叫get的过程 Dialogue: 0,0:32:15.23,0:32:18.72,Default,,0,0,0,,它是这样的一个东西 如果我说把表格里 Dialogue: 0,0:32:19.40,0:32:22.76,Default,,0,0,0,,存储在key1和key2对应的格子中的数据给我 Dialogue: 0,0:32:23.40,0:32:25.39,Default,,0,0,0,,它会把存储在那里的东西返回给我 Dialogue: 0,0:32:26.73,0:32:29.44,Default,,0,0,0,,我们先不要担心这个表格怎么实现 Dialogue: 0,0:32:30.00,0:32:32.52,Default,,0,0,0,,那又是另一个数据抽象了 是George需要考虑的问题 Dialogue: 0,0:32:33.06,0:32:34.36,Default,,0,0,0,,也许稍后我们还会看到 Dialogue: 0,0:32:34.70,0:32:36.97,Default,,0,0,0,,我们还会讨论怎么用Lisp建立这个表格 Dialogue: 0,0:32:40.71,0:32:45.50,Default,,0,0,0,,我们有了这个组织结构 George和Martha需要做什么呢? Dialogue: 0,0:32:47.38,0:32:49.07,Default,,0,0,0,,当他们构建自己的系统的时候 Dialogue: 0,0:32:49.13,0:32:51.08,Default,,0,0,0,,都有责任在表格里 Dialogue: 0,0:32:51.44,0:32:53.82,Default,,0,0,0,,正确地添加上自己的那一列 Dialogue: 0,0:32:55.21,0:32:57.47,Default,,0,0,0,,比如说 对于George Dialogue: 0,0:32:59.79,0:33:02.06,Default,,0,0,0,,当他定义过程的时候 他需要做的就是 Dialogue: 0,0:33:02.27,0:33:07.99,Default,,0,0,0,,把它们放进表格中的rectangular类型的那一列下面 Dialogue: 0,0:33:09.82,0:33:12.12,Default,,0,0,0,,然后操作的名字是real-part Dialogue: 0,0:33:13.31,0:33:15.26,Default,,0,0,0,,放入他的real-part-rectangular过程 Dialogue: 0,0:33:16.25,0:33:17.78,Default,,0,0,0,,注意有什么被放到了表格里 Dialogue: 0,0:33:17.78,0:33:22.10,Default,,0,0,0,,这里的两个key是这两个符号:rectangular和real-part Dialogue: 0,0:33:22.10,0:33:22.75,Default,,0,0,0,,这是引用 Dialogue: 0,0:33:24.40,0:33:26.75,Default,,0,0,0,,要被填到表里的东西 Dialogue: 0,0:33:26.84,0:33:29.21,Default,,0,0,0,,是他编写的real-part-rectangular过程 Dialogue: 0,0:33:31.85,0:33:34.30,Default,,0,0,0,,然后把这个获取虚部的过程也放进表里 Dialogue: 0,0:33:34.59,0:33:37.80,Default,,0,0,0,,分类到rectangular和imag-part两个关键字之下 Dialogue: 0,0:33:38.62,0:33:42.88,Default,,0,0,0,,获取模值的过程放到rectangular和magnitude下面 Dialogue: 0,0:33:43.61,0:33:45.20,Default,,0,0,0,,获取辐角的过程放到rectangular和angle下面 Dialogue: 0,0:33:47.04,0:33:50.84,Default,,0,0,0,,George作为系统的一部分 就要做以上这些事情 Dialogue: 0,0:33:54.42,0:33:58.86,Default,,0,0,0,,Martha用同样的方法填好表格中关于polar的这一列 Dialogue: 0,0:33:59.43,0:34:00.65,Default,,0,0,0,,在polar和real-part对应的这一栏 Dialogue: 0,0:34:01.69,0:34:03.58,Default,,0,0,0,,应该填的过程是real-part-polar是吧? Dialogue: 0,0:34:04.34,0:34:07.29,Default,,0,0,0,,然后分别是imag-part、magnitude和angle过程 Dialogue: 0,0:34:08.91,0:34:11.40,Default,,0,0,0,,Martha想要加入系统当中就要做这些事情 Dialogue: 0,0:34:11.40,0:34:13.55,Default,,0,0,0,,每个设计了数据表示的人 Dialogue: 0,0:34:13.55,0:34:17.63,Default,,0,0,0,,都必须在表格里设置自己的一列 Dialogue: 0,0:34:17.76,0:34:19.90,Default,,0,0,0,,那么Harry带着他的绝妙的复数实现方法 Dialogue: 0,0:34:19.90,0:34:21.80,Default,,0,0,0,,过来的时候 他需要做什么呢 Dialogue: 0,0:34:21.80,0:34:23.96,Default,,0,0,0,,他先把过程写好 Dialogue: 0,0:34:24.04,0:34:26.52,Default,,0,0,0,,然后在表格里再建立一列 Dialogue: 0,0:34:28.55,0:34:30.04,Default,,0,0,0,,那么现在经理怎么样了呢 Dialogue: 0,0:34:31.33,0:34:34.61,Default,,0,0,0,,经理的存在被自动操作所取代 Dialogue: 0,0:34:34.61,0:34:37.11,Default,,0,0,0,,被一个叫做operate的过程代替 Dialogue: 0,0:34:37.11,0:34:39.55,Default,,0,0,0,,这是这个系统最关键的一个过程 Dialogue: 0,0:34:40.38,0:34:45.92,Default,,0,0,0,,(define operate Dialogue: 0,0:34:51.06,0:34:56.09,Default,,0,0,0,,Operate过程接收你想要采取的运算 Dialogue: 0,0:34:57.75,0:34:58.88,Default,,0,0,0,,应该说是这个运算的名字 Dialogue: 0,0:34:59.20,0:35:03.28,Default,,0,0,0,,和被运算的对象 Dialogue: 0,0:35:04.21,0:35:09.76,Default,,0,0,0,,那么举例来说 对一个复数调用real-part operate过程会做什么呢 Dialogue: 0,0:35:09.95,0:35:11.90,Default,,0,0,0,,它要做的第一件事就是去查表 Dialogue: 0,0:35:12.64,0:35:13.87,Default,,0,0,0,,它查询这个表格 Dialogue: 0,0:35:14.80,0:35:22.56,Default,,0,0,0,,试图去找到存储在表格里的一个过程 Dialogue: 0,0:35:23.15,0:35:24.80,Default,,0,0,0,,所以它要对表格调用get过程 Dialogue: 0,0:35:25.50,0:35:33.92,Default,,0,0,0,,用对象的类型和运算的名称作为关键字进行检索 Dialogue: 0,0:35:38.92,0:35:40.14,Default,,0,0,0,,这样就可以知道在表格中 Dialogue: 0,0:35:40.38,0:35:42.72,Default,,0,0,0,,与数据的类型和要进行的运算相对应的是什么了 Dialogue: 0,0:35:42.89,0:35:44.35,Default,,0,0,0,,对应的这一格里填了什么东西 Dialogue: 0,0:35:44.44,0:35:45.93,Default,,0,0,0,,我们假设get过程已经被实现好了 Dialogue: 0,0:35:45.93,0:35:47.72,Default,,0,0,0,,所以如果在那一格什么也没有 Dialogue: 0,0:35:48.11,0:35:51.79,Default,,0,0,0,,它就会返回一个空表 Dialogue: 0,0:35:52.67,0:35:55.39,Default,,0,0,0,,如果那里确实有什么东西 Dialogue: 0,0:35:56.62,0:36:00.43,Default,,0,0,0,,如果存储有这样的一个过程 Dialogue: 0,0:36:03.15,0:36:07.12,Default,,0,0,0,,那么就会把在表格里找到的这个过程 Dialogue: 0,0:36:09.79,0:36:15.00,Default,,0,0,0,,应用到对象的具体内容上去 Dialogue: 0,0:36:18.25,0:36:20.40,Default,,0,0,0,,如果那里没有东西的话 Dialogue: 0,0:36:20.67,0:36:22.51,Default,,0,0,0,,它就会 -- 我们可以决定 Dialogue: 0,0:36:22.81,0:36:27.12,Default,,0,0,0,,本例中 我们让它输出一个错误消息:“未定义的运算符” Dialogue: 0,0:36:28.48,0:36:30.24,Default,,0,0,0,,没有支持这种类型的运算符 Dialogue: 0,0:36:33.07,0:36:34.72,Default,,0,0,0,,或者其它合适的错误信息 Dialogue: 0,0:36:39.07,0:36:39.48,Default,,0,0,0,,对吧? Dialogue: 0,0:36:39.72,0:36:41.04,Default,,0,0,0,,这个东西替代了经理 Dialogue: 0,0:36:41.89,0:36:42.91,Default,,0,0,0,,我们怎么去使用它呢 Dialogue: 0,0:36:43.96,0:36:49.80,Default,,0,0,0,,我们的想法是用operate过程来定义通用选择函数 Dialogue: 0,0:36:50.04,0:36:56.75,Default,,0,0,0,,我们可以说一个对象的real-part Dialogue: 0,0:36:57.14,0:37:05.66,Default,,0,0,0,,是这个对象被operate应用了叫做real-part的运算后得到的结果 Dialogue: 0,0:37:08.07,0:37:12.22,Default,,0,0,0,,那么类似地 imag-part是operate对obj应用imag-part运算 Dialogue: 0,0:37:12.22,0:37:13.98,Default,,0,0,0,,magnitude和angle同理 Dialogue: 0,0:37:15.36,0:37:17.43,Default,,0,0,0,,这就是我们的实现方法 Dialogue: 0,0:37:17.43,0:37:20.48,Default,,0,0,0,,由它们加上类型再加上operate过程组成 Dialogue: 0,0:37:21.33,0:37:24.00,Default,,0,0,0,,这个表格现在就有效地完成了之前经理的工作 Dialogue: 0,0:37:24.06,0:37:27.69,Default,,0,0,0,,我们来梳理一下在这个过程中发生的事情 Dialogue: 0,0:37:27.90,0:37:33.00,Default,,0,0,0,,假设我有一个由Martha构造的复数 Dialogue: 0,0:37:33.53,0:37:38.80,Default,,0,0,0,,它的模值是1 辐角是2 Dialogue: 0,0:37:39.10,0:37:40.22,Default,,0,0,0,,它是由Martha构造的 Dialogue: 0,0:37:40.22,0:37:45.45,Default,,0,0,0,,所以它被贴上了polar的标签 Dialogue: 0,0:37:47.24,0:37:48.00,Default,,0,0,0,,我们叫它z Dialogue: 0,0:37:48.00,0:37:48.91,Default,,0,0,0,,假设这就是z Dialogue: 0,0:37:51.77,0:37:54.46,Default,,0,0,0,,然后假设在这种实现方法下 Dialogue: 0,0:37:54.80,0:37:57.92,Default,,0,0,0,,有人想要取z的实部 Dialogue: 0,0:38:04.87,0:38:07.96,Default,,0,0,0,,由于real-part现在是用operate来定义的 Dialogue: 0,0:38:09.16,0:38:10.57,Default,,0,0,0,,这就等同于说 Dialogue: 0,0:38:12.09,0:38:24.81,Default,,0,0,0,,调用 (operate 'real-part z) Dialogue: 0,0:38:27.06,0:38:28.09,Default,,0,0,0,,然后operate过程 Dialogue: 0,0:38:28.09,0:38:29.24,Default,,0,0,0,,就会去查询表格 Dialogue: 0,0:38:31.04,0:38:34.36,Default,,0,0,0,,然后试图去寻找在表格里存放的 Dialogue: 0,0:38:39.00,0:38:46.22,Default,,0,0,0,,查询表格中与对象的类型相对应的一列 Dialogue: 0,0:38:46.72,0:38:48.22,Default,,0,0,0,,那么z的类型是polar Dialogue: 0,0:38:48.79,0:38:51.37,Default,,0,0,0,,所以它就要说 我用polar作为关键字查表 Dialogue: 0,0:38:52.99,0:38:58.57,Default,,0,0,0,,然后运算的名称是real-part Dialogue: 0,0:39:05.96,0:39:13.63,Default,,0,0,0,,它查询对应的过程 然后应用到z的内容上去 Dialogue: 0,0:39:14.83,0:39:17.13,Default,,0,0,0,,如果所有东西都安排妥当的话 Dialogue: 0,0:39:17.74,0:39:21.70,Default,,0,0,0,,如果它找到的过程就是Martha编写的过程 Dialogue: 0,0:39:21.70,0:39:22.95,Default,,0,0,0,,也就是real-part-polar Dialogue: 0,0:39:31.05,0:39:35.13,Default,,0,0,0,,然后这就是z去掉类型之后的东西 Dialogue: 0,0:39:35.44,0:39:38.94,Default,,0,0,0,,是Martha最初设计的数据表示 Dialogue: 0,0:39:39.40,0:39:40.43,Default,,0,0,0,,也就是这里的(1 2) Dialogue: 0,0:39:43.71,0:39:45.87,Default,,0,0,0,,所以说在整个系统中 operate过程 Dialogue: 0,0:39:46.46,0:39:48.89,Default,,0,0,0,,和之前的经理做的事情没什么区别 Dialogue: 0,0:39:49.45,0:39:52.59,Default,,0,0,0,,它通过查询表格找到正确的东西 然后剥离类型 Dialogue: 0,0:39:53.58,0:39:57.52,Default,,0,0,0,,然后把它传递给能够处理它的人 Dialogue: 0,0:39:58.88,0:40:05.48,Default,,0,0,0,,你会发现 这是另一种 在大多数情况下 Dialogue: 0,0:40:06.22,0:40:08.04,Default,,0,0,0,,更灵活地实现通用运算符的方法 Dialogue: 0,0:40:08.08,0:40:15.69,Default,,0,0,0,,我们把它叫做“数据导向编程” Dialogue: 0,0:40:20.35,0:40:21.96,Default,,0,0,0,,其理念是 Dialogue: 0,0:40:23.42,0:40:25.55,Default,,0,0,0,,在某种意义上 这些数据对象本身 Dialogue: 0,0:40:26.04,0:40:28.35,Default,,0,0,0,,这些充斥在系统中的复数 Dialogue: 0,0:40:28.73,0:40:33.16,Default,,0,0,0,,它们自身就携带着 关于应该怎么去操作它们的信息 Dialogue: 0,0:40:35.74,0:40:36.78,Default,,0,0,0,,有什么疑问吗? Dialogue: 0,0:40:41.00,0:40:41.24,Default,,0,0,0,,请说 Dialogue: 0,0:40:41.24,0:40:43.39,Default,,0,0,0,,学生:你在那个数据对象里存储的是什么呢 Dialogue: 0,0:40:43.39,0:40:47.10,Default,,0,0,0,,这里面有这个数据本身 还有它的类型 Dialogue: 0,0:40:47.10,0:40:49.60,Default,,0,0,0,,还有该与该类型对应的运算 Dialogue: 0,0:40:49.69,0:40:53.08,Default,,0,0,0,,或者说那些运算是存储在哪里呢? Dialogue: 0,0:40:53.60,0:40:54.17,Default,,0,0,0,,教授:好 让我-- Dialogue: 0,0:40:54.98,0:40:56.50,Default,,0,0,0,,恩 这是一个好问题 Dialogue: 0,0:40:56.50,0:41:00.46,Default,,0,0,0,,通过它暗示了实现我们目标的 其它可行方法 Dialogue: 0,0:41:00.75,0:41:02.48,Default,,0,0,0,,当然可能的方法有很多 Dialogue: 0,0:41:04.20,0:41:06.14,Default,,0,0,0,,在这个特定的实现当中 Dialogue: 0,0:41:06.24,0:41:09.72,Default,,0,0,0,,在这个数据对象里放着 Dialogue: 0,0:41:10.44,0:41:13.45,Default,,0,0,0,,就是数据本身 本例中是序对(1, 2) Dialogue: 0,0:41:14.98,0:41:16.55,Default,,0,0,0,,和一个符号 Dialogue: 0,0:41:16.55,0:41:19.07,Default,,0,0,0,,就是这个符号 单词P-O-L-A-R Dialogue: 0,0:41:20.60,0:41:22.33,Default,,0,0,0,,这些就是这个数据对象里面的东西 Dialogue: 0,0:41:24.24,0:41:26.69,Default,,0,0,0,,那么这些运算又是存放在哪里的呢? Dialogue: 0,0:41:26.69,0:41:29.00,Default,,0,0,0,,那些运算在表格里 Dialogue: 0,0:41:29.85,0:41:31.07,Default,,0,0,0,,在这个表格里 Dialogue: 0,0:41:32.30,0:41:36.46,Default,,0,0,0,,所有行和列的名字都是符号 Dialogue: 0,0:41:38.23,0:41:40.08,Default,,0,0,0,,所以当我往里面存什么东西的时候 Dialogue: 0,0:41:40.09,0:41:47.02,Default,,0,0,0,,可以以符号polar或符号magnitude作为关键字 Dialogue: 0,0:41:48.24,0:41:51.31,Default,,0,0,0,,我这样写 可能让你们感到困惑了 Dialogue: 0,0:41:51.31,0:41:52.70,Default,,0,0,0,,因为在这里面放的并不是 Dialogue: 0,0:41:53.16,0:41:54.57,Default,,0,0,0,,当我写下mag-polar的时候 Dialogue: 0,0:41:57.04,0:41:59.23,Default,,0,0,0,,我指的是那个叫mag-polar的过程 Dialogue: 0,0:41:59.85,0:42:01.85,Default,,0,0,0,,可能 我本来应该在这里写上 Dialogue: 0,0:42:02.58,0:42:04.20,Default,,0,0,0,,但是这里空间太小了 Dialogue: 0,0:42:04.20,0:42:05.07,Default,,0,0,0,,我写不下 Dialogue: 0,0:42:05.58,0:42:08.92,Default,,0,0,0,,应该写成lambda(z) Dialogue: 0,0:42:10.60,0:42:12.75,Default,,0,0,0,,然后调用Martha实现的过程 Dialogue: 0,0:42:14.71,0:42:15.72,Default,,0,0,0,,你也可以从这里看出 Dialogue: 0,0:42:15.74,0:42:17.44,Default,,0,0,0,,我已经暗示了另一种方法 Dialogue: 0,0:42:17.71,0:42:19.82,Default,,0,0,0,,来解决名字冲突的问题 Dialogue: 0,0:42:20.04,0:42:23.15,Default,,0,0,0,,那就是George和Martha根本不用给他们的过程起名字 Dialogue: 0,0:42:23.15,0:42:25.37,Default,,0,0,0,,可以直接把由lambda定义的 Dialogue: 0,0:42:25.39,0:42:28.12,Default,,0,0,0,,由lambda定义的匿名函数放进表格里 Dialogue: 0,0:42:28.66,0:42:31.76,Default,,0,0,0,,你的问题还引出了另一种可能性 Dialogue: 0,0:42:32.35,0:42:34.06,Default,,0,0,0,,也就是 Dialogue: 0,0:42:34.83,0:42:37.92,Default,,0,0,0,,可能我在这个数据对象里存储的 Dialogue: 0,0:42:37.95,0:42:39.48,Default,,0,0,0,,不是符号POLAR Dialogue: 0,0:42:39.93,0:42:42.35,Default,,0,0,0,,也许是这些运算本身 Dialogue: 0,0:42:43.90,0:42:45.63,Default,,0,0,0,,这是组织系统的另一种方法 Dialogue: 0,0:42:45.66,0:42:46.60,Default,,0,0,0,,叫做“消息传递” Dialogue: 0,0:42:48.65,0:42:49.92,Default,,0,0,0,,它们都殊途同归 Dialogue: 0,0:42:54.64,0:42:58.04,Default,,0,0,0,,学生:所以说如果Martha和George Dialogue: 0,0:42:58.04,0:43:01.23,Default,,0,0,0,,用了相同的过程名字也没什么问题 Dialogue: 0,0:43:01.23,0:43:02.56,Default,,0,0,0,,[听不清] Dialogue: 0,0:43:02.56,0:43:04.68,Default,,0,0,0,,教授:对 你说得很对 Dialogue: 0,0:43:04.80,0:43:07.85,Default,,0,0,0,,看 他们甚至根本不需要给他们的过程命名 Dialogue: 0,0:43:08.04,0:43:09.36,Default,,0,0,0,,George和Martha可以 -- Dialogue: 0,0:43:09.50,0:43:10.62,Default,,0,0,0,,George可以这么来做 Dialogue: 0,0:43:10.83,0:43:15.28,Default,,0,0,0,,与其在rectangular和real-part对应的格子里放 Dialogue: 0,0:43:16.22,0:43:17.98,Default,,0,0,0,,存放real-part-rectangular这个过程 Dialogue: 0,0:43:18.03,0:43:21.15,Default,,0,0,0,,George可以在rectangular和real-part对应的格子里放 Dialogue: 0,0:43:21.24,0:43:23.69,Default,,0,0,0,,放一个lambda(z) 然后什么什么 Dialogue: 0,0:43:24.54,0:43:26.84,Default,,0,0,0,,整个系统会以完全相同的方式工作 Dialogue: 0,0:43:27.33,0:43:29.24,Default,,0,0,0,,学生:我的问题是 就算Martha在 Dialogue: 0,0:43:29.84,0:43:33.60,Default,,0,0,0,,Martha在key1和key2对应的格子里放了real-part过程 Dialogue: 0,0:43:33.95,0:43:37.64,Default,,0,0,0,,George也在key1和key2下放了一个real-part过程 Dialogue: 0,0:43:37.96,0:43:39.60,Default,,0,0,0,,只要两个过程的定义不一样 Dialogue: 0,0:43:39.80,0:43:41.26,Default,,0,0,0,,它们就不会发生任何冲突 对吗? Dialogue: 0,0:43:41.29,0:43:43.80,Default,,0,0,0,,教授:对的 这完全没有问题 Dialogue: 0,0:43:44.97,0:43:47.13,Default,,0,0,0,,除非你说的是George和Martha在同一个终端上工作 Dialogue: 0,0:43:47.13,0:43:49.20,Default,,0,0,0,,并且他们两个人起的所有名字的含义全部相同 Dialogue: 0,0:43:49.82,0:43:51.23,Default,,0,0,0,,那么同样的real-part就会造成困扰 Dialogue: 0,0:43:51.24,0:43:52.80,Default,,0,0,0,,但是就算是这种情况也有办法解决 Dialogue: 0,0:43:52.80,0:43:54.80,Default,,0,0,0,,从原则上讲你说的完全正确 Dialogue: 0,0:43:54.98,0:43:56.29,Default,,0,0,0,,如果它们的名字不互相冲突的话 Dialogue: 0,0:43:56.29,0:43:58.19,Default,,0,0,0,,被填到表里的是对象本身 而不是它们的名字 Dialogue: 0,0:44:08.20,0:44:09.05,Default,,0,0,0,,好 我们休息一下 Dialogue: 0,0:44:12.91,0:44:20.48,Default,,0,0,0,,[音乐] Dialogue: 0,0:44:20.96,0:44:23.29,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:44:23.45,0:44:25.29,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:44:57.42,0:45:05.07,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:45:05.47,0:45:09.24,Declare,,0,0,0,,{\an2\fad(500,500)}通用运算符 Dialogue: 0,0:45:12.88,0:45:16.88,Default,,0,0,0,,教授:好的 我们刚刚讲了一个数据导向编程的例子 Dialogue: 0,0:45:17.68,0:45:22.84,Default,,0,0,0,,我们将其用于实现一个复数域上的算术系统 Dialogue: 0,0:45:27.60,0:45:32.48,Default,,0,0,0,,我已经在里面实现了 +c -c 这些运算 Dialogue: 0,0:45:32.88,0:45:37.24,Default,,0,0,0,,*c \c 还有其它的一些过程 Dialogue: 0,0:45:38.23,0:45:45.72,Default,,0,0,0,,这些过程存在于上层 -- 这是关键之处 Dialogue: 0,0:45:45.74,0:45:49.60,Default,,0,0,0,,它们存在于两种不同表示方式的上层 Dialogue: 0,0:45:50.34,0:45:55.44,Default,,0,0,0,,这是一个直角坐标程序包 这里一个极坐标程序包 Dialogue: 0,0:45:58.14,0:45:59.15,Default,,0,0,0,,可能还有其它的东西 Dialogue: 0,0:45:59.15,0:46:02.80,Default,,0,0,0,,关键理念就是 “其它的东西”可以很容易地添加上去 Dialogue: 0,0:46:04.67,0:46:08.35,Default,,0,0,0,,但是这并没有真正体现出这种方法学的威力 Dialogue: 0,0:46:08.90,0:46:10.15,Default,,0,0,0,,我们看看发生了什么 Dialogue: 0,0:46:10.15,0:46:12.33,Default,,0,0,0,,这个方法的威力 只有当你 Dialogue: 0,0:46:12.94,0:46:15.79,Default,,0,0,0,,当你把它嵌入于一些更复杂的系统中时才会显现 Dialogue: 0,0:46:16.17,0:46:17.74,Default,,0,0,0,,我现在要做的就是 Dialogue: 0,0:46:17.87,0:46:20.01,Default,,0,0,0,,把它嵌入一个更复杂的系统中 Dialogue: 0,0:46:20.25,0:46:25.28,Default,,0,0,0,,假设我们已经有了一个通用算术系统 Dialogue: 0,0:46:25.28,0:46:27.24,Default,,0,0,0,,所谓的“通用算术系统” Dialogue: 0,0:46:27.24,0:46:28.54,Default,,0,0,0,,然后在系统的最顶层 Dialogue: 0,0:46:30.76,0:46:35.92,Default,,0,0,0,,用户可以命令它把两个东西相加 或者相减 Dialogue: 0,0:46:37.45,0:46:41.05,Default,,0,0,0,,或者让两数相乘、相除 Dialogue: 0,0:46:44.14,0:46:46.52,Default,,0,0,0,,然后在它们下面是一个抽象屏障 Dialogue: 0,0:46:47.93,0:46:49.15,Default,,0,0,0,,抽象屏障的下层 Dialogue: 0,0:46:49.50,0:46:52.48,Default,,0,0,0,,是一个复数域算术程序包 Dialogue: 0,0:46:53.02,0:46:54.96,Default,,0,0,0,,然后你可以让它把两个复数相加 Dialogue: 0,0:46:55.04,0:46:58.83,Default,,0,0,0,,或者你还可以把 有理数域算术程序包 Dialogue: 0,0:46:58.88,0:46:59.93,Default,,0,0,0,,给安装进来 Dialogue: 0,0:47:00.19,0:47:01.72,Default,,0,0,0,,可以放进去有理数 Dialogue: 0,0:47:04.76,0:47:06.22,Default,,0,0,0,,然后有理数程序包里面 Dialogue: 0,0:47:07.16,0:47:14.75,Default,,0,0,0,,有我们实现的 +rat、*rat等等的这些过程 Dialogue: 0,0:47:15.39,0:47:17.01,Default,,0,0,0,,或者你还可以加上通常的Lisp算术系统 Dialogue: 0,0:47:17.01,0:47:18.99,Default,,0,0,0,,你可以让它把3和4加起来 Dialogue: 0,0:47:19.42,0:47:20.94,Default,,0,0,0,,那么我们在这个系统里加入通常的算术系统 Dialogue: 0,0:47:28.28,0:47:34.67,Default,,0,0,0,,其中有Lisp自带的 + - * / Dialogue: 0,0:47:36.67,0:47:39.12,Default,,0,0,0,,总而言之 我们可以想象这个复数系统 Dialogue: 0,0:47:39.44,0:47:44.44,Default,,0,0,0,,存在于一个更加复杂的通用运算系统里面 Dialogue: 0,0:47:47.73,0:47:48.73,Default,,0,0,0,,我们怎么才能做到呢 Dialogue: 0,0:47:49.05,0:47:52.32,Default,,0,0,0,,我们已经有了想法 只要再一次应用它就可以了 Dialogue: 0,0:47:52.78,0:47:54.72,Default,,0,0,0,,我们已经实现了一个有理数程序包 Dialogue: 0,0:47:54.72,0:47:56.89,Default,,0,0,0,,那么我们来看看应该怎么修改它 Dialogue: 0,0:48:01.48,0:48:03.40,Default,,0,0,0,,实际上 在这个层面 它根本就不需要修改 Dialogue: 0,0:48:03.73,0:48:05.88,Default,,0,0,0,,这完全就是我们上次写的那些代码 Dialogue: 0,0:48:07.18,0:48:08.97,Default,,0,0,0,,要把两个有理数相加 Dialogue: 0,0:48:09.85,0:48:10.91,Default,,0,0,0,,回忆一下 我们要用到这个公式 Dialogue: 0,0:48:11.14,0:48:13.37,Default,,0,0,0,,构造一个有理数 它的分子是 Dialogue: 0,0:48:13.98,0:48:17.56,Default,,0,0,0,,x的分子乘以y的分母 Dialogue: 0,0:48:17.93,0:48:21.52,Default,,0,0,0,,加上 x的分母乘以y的分子 Dialogue: 0,0:48:21.52,0:48:23.79,Default,,0,0,0,,而结果的分母是 x的分母乘y的分母 Dialogue: 0,0:48:25.76,0:48:29.07,Default,,0,0,0,,然后是-rat、*rat、/rat这些过程 Dialogue: 0,0:48:30.36,0:48:35.12,Default,,0,0,0,,这就是我们之前写的那个有理数程序包 Dialogue: 0,0:48:36.31,0:48:38.89,Default,,0,0,0,,我们忽略最大公约数的问题 先不去考虑那个 Dialogue: 0,0:48:39.08,0:48:42.59,Default,,0,0,0,,作为这个有理数包的实现人员 Dialogue: 0,0:48:42.80,0:48:45.10,Default,,0,0,0,,怎么把它安装到我们的通用运算系统中呢? Dialogue: 0,0:48:45.57,0:48:46.22,Default,,0,0,0,,那很简单 Dialogue: 0,0:48:47.29,0:48:51.56,Default,,0,0,0,,我们要做的事只有一件和之前不同 Dialogue: 0,0:48:51.84,0:48:55.71,Default,,0,0,0,,在之前我们说构造一个有理数 Dialogue: 0,0:48:56.27,0:48:59.98,Default,,0,0,0,,就是构造一个由分子分母组成的序对 Dialogue: 0,0:49:00.96,0:49:03.20,Default,,0,0,0,,现在我们不光构造这个序对 还要给它贴上标签 Dialogue: 0,0:49:03.30,0:49:04.56,Default,,0,0,0,,给它加上rational类型 Dialogue: 0,0:49:06.36,0:49:08.09,Default,,0,0,0,,这就是唯一的不同之处 Dialogue: 0,0:49:08.56,0:49:10.09,Default,,0,0,0,,把它变成带类型的数据 Dialogue: 0,0:49:12.38,0:49:14.08,Default,,0,0,0,,现在 我们要把运算放进表格里 Dialogue: 0,0:49:14.36,0:49:18.20,Default,,0,0,0,,我们在rational符号和add运算对应的格子里 Dialogue: 0,0:49:18.92,0:49:20.25,Default,,0,0,0,,放进我们的+rat过程 Dialogue: 0,0:49:21.82,0:49:23.24,Default,,0,0,0,,再次强调 这是一个符号 Dialogue: 0,0:49:23.74,0:49:23.93,Default,,0,0,0,,看到了么? Dialogue: 0,0:49:24.03,0:49:25.29,Default,,0,0,0,,这是引用 这也是引用 Dialogue: 0,0:49:25.31,0:49:28.01,Default,,0,0,0,,但是实际上放进表里的是+rat过程本身 Dialogue: 0,0:49:29.82,0:49:31.77,Default,,0,0,0,,然后怎么做减法 Dialogue: 0,0:49:31.79,0:49:36.81,Default,,0,0,0,,我们用-rat过程做减法 Dialogue: 0,0:49:38.27,0:49:40.24,Default,,0,0,0,,然后是乘法和除法 Dialogue: 0,0:49:41.09,0:49:43.64,Default,,0,0,0,,这些步骤精准地描述了 我们该怎么做 Dialogue: 0,0:49:44.14,0:49:46.97,Default,,0,0,0,,来兼容这个通用算术系统 Dialogue: 0,0:49:48.51,0:49:49.88,Default,,0,0,0,,那么整个系统怎么工作呢 Dialogue: 0,0:49:51.56,0:49:58.40,Default,,0,0,0,,我们想实现的是通用运算符 Dialogue: 0,0:49:59.34,0:50:02.80,Default,,0,0,0,,为了让add、sub、mul和div变成通用运算符 Dialogue: 0,0:50:03.99,0:50:17.36,Default,,0,0,0,,所以我们要把add过程定义为 (ADD X Y)就是 Dialogue: 0,0:50:18.62,0:50:22.12,Default,,0,0,0,,就是调用operate过程 Dialogue: 0,0:50:26.08,0:50:27.49,Default,,0,0,0,,我们把这个叫做operate-2 Dialogue: 0,0:50:27.49,0:50:30.78,Default,,0,0,0,,这是我们的操作过程 但是要接收两个参数 Dialogue: 0,0:50:31.60,0:50:35.84,Default,,0,0,0,,对它们应用add 把它们加起来 Dialogue: 0,0:50:37.60,0:50:39.76,Default,,0,0,0,,这是和operate类似的一个东西 Dialogue: 0,0:50:40.42,0:50:41.68,Default,,0,0,0,,我们再看看这个代码 Dialogue: 0,0:50:41.68,0:50:42.93,Default,,0,0,0,,它和operate很相似 Dialogue: 0,0:50:45.79,0:50:52.49,Default,,0,0,0,,为了将运算符运用在两个参数arg1和arg2上 Dialogue: 0,0:50:55.04,0:50:56.65,Default,,0,0,0,,首要任务是 Dialogue: 0,0:50:56.83,0:51:00.73,Default,,0,0,0,,检查这两个参数的类型是否相同 Dialogue: 0,0:51:01.90,0:51:02.96,Default,,0,0,0,,所以我们要问 Dialogue: 0,0:51:02.99,0:51:07.77,Default,,0,0,0,,第一个参数的类型和第二个的类型一样吗? Dialogue: 0,0:51:10.35,0:51:13.36,Default,,0,0,0,,如果不一样 Dialogue: 0,0:51:13.58,0:51:15.63,Default,,0,0,0,,我们就停止运行 然后抛出错误 Dialogue: 0,0:51:15.67,0:51:16.67,Default,,0,0,0,,我们不知道怎么对它们进行运算 Dialogue: 0,0:51:19.14,0:51:20.49,Default,,0,0,0,,如果它们的类型确实是相同的 Dialogue: 0,0:51:20.51,0:51:22.08,Default,,0,0,0,,那就和之前一样了 Dialogue: 0,0:51:22.08,0:51:26.46,Default,,0,0,0,,我们会查询在参数的类型对应的 Dialogue: 0,0:51:26.76,0:51:29.61,Default,,0,0,0,,参数1和参数2是同样的类型 知道一个就可以 Dialogue: 0,0:51:30.42,0:51:32.59,Default,,0,0,0,,我们到表格里去查找对应的过程 Dialogue: 0,0:51:33.64,0:51:35.87,Default,,0,0,0,,如果找到这样一个过程 Dialogue: 0,0:51:37.53,0:51:41.74,Default,,0,0,0,,我们就将其应用在参数1和参数2的内容上 Dialogue: 0,0:51:43.03,0:51:44.76,Default,,0,0,0,,如果是其它情况 就报错 Dialogue: 0,0:51:44.76,0:51:45.72,Default,,0,0,0,,“未定义运算符” Dialogue: 0,0:51:46.89,0:51:48.16,Default,,0,0,0,,这就是operate-2过程 Dialogue: 0,0:51:51.72,0:51:54.03,Default,,0,0,0,,这就是我们要做的全部事情 Dialogue: 0,0:51:55.16,0:51:57.45,Default,,0,0,0,,我们刚刚才写好了一个复数运算包 Dialogue: 0,0:51:57.64,0:52:01.00,Default,,0,0,0,,那么怎么把它放进这个通用系统里面呢? Dialogue: 0,0:52:02.14,0:52:02.91,Default,,0,0,0,,方法几乎是一样的 Dialogue: 0,0:52:06.41,0:52:08.59,Default,,0,0,0,,我们构造一个叫做make-complex的过程 Dialogue: 0,0:52:09.95,0:52:12.81,Default,,0,0,0,,它把George和Martha给我们的东西 Dialogue: 0,0:52:13.64,0:52:15.00,Default,,0,0,0,,贴上complex的类型标志 Dialogue: 0,0:52:18.17,0:52:23.87,Default,,0,0,0,,然后我们说 要把复数相加 这个+complex过程 Dialogue: 0,0:52:25.84,0:52:28.78,Default,,0,0,0,,用我们的内部过程 +c Dialogue: 0,0:52:30.78,0:52:32.24,Default,,0,0,0,,把结果加上类型 Dialogue: 0,0:52:32.24,0:52:33.42,Default,,0,0,0,,让它变成复数类型 Dialogue: 0,0:52:37.68,0:52:42.52,Default,,0,0,0,,那么我们的包里原来有+c和-c这两个过程 Dialogue: 0,0:52:42.68,0:52:44.75,Default,,0,0,0,,用来和George和Martha通信 Dialogue: 0,0:52:45.25,0:52:47.39,Default,,0,0,0,,然后为了与外部通信 Dialogue: 0,0:52:47.40,0:52:53.04,Default,,0,0,0,,我们还有+complex和-complex Dialogue: 0,0:52:55.92,0:52:56.53,Default,,0,0,0,,等等 Dialogue: 0,0:52:56.53,0:52:59.98,Default,,0,0,0,,它们唯一的不同就在于:后者的返回的是带类型的值 Dialogue: 0,0:53:01.12,0:53:02.41,Default,,0,0,0,,它们可以在这里被查询 Dialogue: 0,0:53:02.85,0:53:05.02,Default,,0,0,0,,而这些是内部过程 Dialogue: 0,0:53:09.25,0:53:10.68,Default,,0,0,0,,我们再来看那个幻灯片 Dialogue: 0,0:53:10.68,0:53:13.04,Default,,0,0,0,,我们还有一件事要做 Dialogue: 0,0:53:13.74,0:53:15.61,Default,,0,0,0,,在定义了+complex之后 Dialogue: 0,0:53:15.68,0:53:20.52,Default,,0,0,0,,我们在complex类型和add符号对应的格子中 Dialogue: 0,0:53:21.31,0:53:22.75,Default,,0,0,0,,填上过程+complex Dialogue: 0,0:53:23.20,0:53:26.75,Default,,0,0,0,,对于-complex也类似 Dialogue: 0,0:53:27.13,0:53:29.13,Default,,0,0,0,,*complex和/complex亦如此 Dialogue: 0,0:53:31.70,0:53:33.48,Default,,0,0,0,,那我们怎么安装寻常算术呢? Dialogue: 0,0:53:35.25,0:53:36.12,Default,,0,0,0,,方法还是一样的 Dialogue: 0,0:53:38.16,0:53:41.36,Default,,0,0,0,,我们会写一个叫做make-number的过程 Dialogue: 0,0:53:44.34,0:53:48.11,Default,,0,0,0,,make-number接收一个数 然后给它加上类型 Dialogue: 0,0:53:48.14,0:53:49.29,Default,,0,0,0,,也就是符号number Dialogue: 0,0:53:50.26,0:53:52.11,Default,,0,0,0,,我们构造一个过程叫做+number Dialogue: 0,0:53:52.92,0:53:58.75,Default,,0,0,0,,用Lisp自带的加法把两个数加起来 Dialogue: 0,0:53:58.92,0:54:00.78,Default,,0,0,0,,因为我们现在讨论的是寻常算术 Dialogue: 0,0:54:01.31,0:54:03.10,Default,,0,0,0,,给它加上类型 让它变成number类型 Dialogue: 0,0:54:04.51,0:54:08.09,Default,,0,0,0,,然后我们把+number过程放到 Dialogue: 0,0:54:08.59,0:54:11.00,Default,,0,0,0,,表格里number和add对应的的格子中 Dialogue: 0,0:54:12.30,0:54:16.16,Default,,0,0,0,,再用相同的方法把减法 乘法 除法也放进去 Dialogue: 0,0:54:22.67,0:54:26.06,Default,,0,0,0,,我们举一个例子 就看得清楚一点 Dialogue: 0,0:54:26.06,0:54:28.75,Default,,0,0,0,,假设 比如说 Dialogue: 0,0:54:32.28,0:54:34.15,Default,,0,0,0,,我要执行这个运算 Dialogue: 0,0:54:34.15,0:54:38.22,Default,,0,0,0,,好 现在我要执行一个运算 Dialogue: 0,0:54:38.22,0:54:40.46,Default,,0,0,0,,比如说我把两个复数乘起来 Dialogue: 0,0:54:40.93,0:54:48.64,Default,,0,0,0,,把3+4i和2+6i乘起来 Dialogue: 0,0:54:50.17,0:54:52.60,Default,,0,0,0,,这就是我调用mul过程要传入的参数 Dialogue: 0,0:54:52.84,0:54:55.76,Default,,0,0,0,,这里就代表通用运算符mul Dialogue: 0,0:54:57.17,0:54:57.98,Default,,0,0,0,,那么它怎么工作呢 Dialogue: 0,0:54:58.28,0:55:04.60,Default,,0,0,0,,我们讲3+4i 在整个系统里 Dialogue: 0,0:55:04.83,0:55:06.11,Default,,0,0,0,,处于这样的一个位置 Dialogue: 0,0:55:06.25,0:55:07.52,Default,,0,0,0,,假设它是George那种方法表示的 Dialogue: 0,0:55:08.28,0:55:14.97,Default,,0,0,0,,所以它的内部有一个3和一个4 Dialogue: 0,0:55:18.49,0:55:20.97,Default,,0,0,0,,这上面还贴着George的类型标志 Dialogue: 0,0:55:24.33,0:55:28.32,Default,,0,0,0,,是他构造的rectangular类型 Dialogue: 0,0:55:29.51,0:55:30.57,Default,,0,0,0,,又附加在那上面的 Dialogue: 0,0:55:31.23,0:55:35.79,Default,,0,0,0,,从更上一层的视角来看这一段数据 Dialogue: 0,0:55:36.19,0:55:36.78,Default,,0,0,0,,它又是一个 Dialogue: 0,0:55:37.93,0:55:39.96,Default,,0,0,0,,这整个又是一个带类型的数据 Dialogue: 0,0:55:40.60,0:55:41.80,Default,,0,0,0,,它的类型是complex Dialogue: 0,0:55:44.82,0:55:47.31,Default,,0,0,0,,那么这就是这个对象 Dialogue: 0,0:55:48.64,0:55:50.24,Default,,0,0,0,,在最高层视角中的样子 Dialogue: 0,0:55:50.68,0:55:53.56,Default,,0,0,0,,那些通用运算符看到的对象 就是这样的 Dialogue: 0,0:55:55.56,0:55:58.72,Default,,0,0,0,,现在 mul过程会过来问 Dialogue: 0,0:55:58.84,0:56:00.40,Default,,0,0,0,,它的类型是什么? Dialogue: 0,0:56:00.48,0:56:01.48,Default,,0,0,0,,它的类型是complex Dialogue: 0,0:56:04.27,0:56:06.46,Default,,0,0,0,,然后运行到operate-2 然后说 Dialogue: 0,0:56:06.46,0:56:09.72,Default,,0,0,0,,啊 我想要把表格里的过程 Dialogue: 0,0:56:09.72,0:56:13.04,Default,,0,0,0,,也就是*complex这个过程 Dialogue: 0,0:56:15.08,0:56:17.76,Default,,0,0,0,,应用到 将其类型剥离之后的结果上去 Dialogue: 0,0:56:17.95,0:56:19.28,Default,,0,0,0,,所以它会把类型剥下来 Dialogue: 0,0:56:19.93,0:56:24.24,Default,,0,0,0,,把剩下的东西传递给复数的世界 Dialogue: 0,0:56:26.70,0:56:28.73,Default,,0,0,0,,复数的世界看了看它有的运算操作 然后说 Dialogue: 0,0:56:28.76,0:56:30.56,Default,,0,0,0,,“我得调用*c这个过程” Dialogue: 0,0:56:31.28,0:56:32.14,Default,,0,0,0,,然后*c过程说 Dialogue: 0,0:56:32.22,0:56:37.20,Default,,0,0,0,,我想知道这个东西的模值是多少 Dialogue: 0,0:56:39.42,0:56:40.16,Default,,0,0,0,,然后它们会说 啊 Dialogue: 0,0:56:40.16,0:56:41.71,Default,,0,0,0,,它是直角坐标表示的 是George的东西 Dialogue: 0,0:56:41.87,0:56:44.41,Default,,0,0,0,,所以它们又剥掉了一个类型 Dialogue: 0,0:56:46.91,0:56:49.80,Default,,0,0,0,,然后把内容交给George 让他提取出它的模值 Dialogue: 0,0:56:52.16,0:56:53.13,Default,,0,0,0,,那么我们看到 Dialogue: 0,0:56:53.44,0:56:56.99,Default,,0,0,0,,这其中有一条由类型构成的链条 Dialogue: 0,0:56:59.32,0:57:01.50,Default,,0,0,0,,这个链条的长度就是你要 Dialogue: 0,0:57:01.53,0:57:03.13,Default,,0,0,0,,在这个表格里上升的层数 Dialogue: 0,0:57:05.09,0:57:05.96,Default,,0,0,0,,类型的作用则是 Dialogue: 0,0:57:05.96,0:57:10.84,Default,,0,0,0,,每当我们在表格中遇到一道垂直屏障时 Dialogue: 0,0:57:11.05,0:57:14.06,Default,,0,0,0,,你不知道该如何抉择时 Dialogue: 0,0:57:14.41,0:57:15.85,Default,,0,0,0,,类型就会给你指路 Dialogue: 0,0:57:17.44,0:57:18.83,Default,,0,0,0,,然后最底层的过程 Dialogue: 0,0:57:18.97,0:57:20.67,Default,,0,0,0,,它们构造数据结构 对数据进行筛选之后 Dialogue: 0,0:57:21.12,0:57:22.81,Default,,0,0,0,,再把类型贴回去 Dialogue: 0,0:57:25.35,0:57:30.75,Default,,0,0,0,,这就是整个系统的总体结构 Dialogue: 0,0:57:33.41,0:57:33.77,Default,,0,0,0,,好 Dialogue: 0,0:57:34.82,0:57:35.68,Default,,0,0,0,,明白了这个之后 Dialogue: 0,0:57:37.56,0:57:39.44,Default,,0,0,0,,我们再让这个系统变得更加复杂 Dialogue: 0,0:57:41.89,0:57:46.54,Default,,0,0,0,,我们这次不光要在系统里添加新的数域 Dialogue: 0,0:57:46.60,0:57:51.15,Default,,0,0,0,,我们也来讨论一下怎么把多项式也加进去 Dialogue: 0,0:57:51.51,0:57:52.97,Default,,0,0,0,,让它能做多项式算术 Dialogue: 0,0:57:53.36,0:58:03.71,Default,,0,0,0,,比如我们可以计算x^15+2x^7+5 Dialogue: 0,0:58:04.48,0:58:05.84,Default,,0,0,0,,像这样的多项式 Dialogue: 0,0:58:06.38,0:58:07.93,Default,,0,0,0,,如果有两个这样的东西 Dialogue: 0,0:58:07.93,0:58:09.48,Default,,0,0,0,,我们可以把它们相加或者相乘 Dialogue: 0,0:58:10.53,0:58:11.79,Default,,0,0,0,,先不管相除的问题 Dialogue: 0,0:58:12.14,0:58:14.67,Default,,0,0,0,,只考虑相加相乘和相减 Dialogue: 0,0:58:15.55,0:58:17.16,Default,,0,0,0,,我们需要做什么 Dialogue: 0,0:58:18.52,0:58:20.76,Default,,0,0,0,,我们先来想想怎么表示一个多项式 Dialogue: 0,0:58:21.83,0:58:23.55,Default,,0,0,0,,它也是一种带类型的数据 Dialogue: 0,0:58:24.73,0:58:27.55,Default,,0,0,0,,这个系统里的一个多项式 Dialogue: 0,0:58:28.54,0:58:31.68,Default,,0,0,0,,应该是带有polynomial类型的对象 Dialogue: 0,0:58:32.00,0:58:34.55,Default,,0,0,0,,接下来它可能要问这个多项式的变量是哪个 Dialogue: 0,0:58:34.55,0:58:37.69,Default,,0,0,0,,比如这是一个以x为变量的多项式 Dialogue: 0,0:58:38.96,0:58:41.39,Default,,0,0,0,,然后 多项式内还有各项的信息 Dialogue: 0,0:58:42.25,0:58:44.16,Default,,0,0,0,,有很多种方法来实现 Dialogue: 0,0:58:44.25,0:58:47.63,Default,,0,0,0,,我们采用的方法是构造一个“项表” Dialogue: 0,0:58:51.52,0:58:52.24,Default,,0,0,0,,所谓的“项表” Dialogue: 0,0:58:53.70,0:58:55.61,Default,,0,0,0,,本例中 我们用的是类似这样的东西 Dialogue: 0,0:58:56.36,0:58:59.68,Default,,0,0,0,,我们把它写成一系列 按次数排列的序对 Dialogue: 0,0:58:59.69,0:59:05.80,Default,,0,0,0,,那么这个项表就能表示这个多项式了 Dialogue: 0,0:59:09.42,0:59:10.68,Default,,0,0,0,,它的意义是 Dialogue: 0,0:59:11.48,0:59:19.71,Default,,0,0,0,,这个多项式第一项的次数是15 系数是1 Dialogue: 0,0:59:23.82,0:59:27.50,Default,,0,0,0,,然后下一项的次数是7 系数是2 Dialogue: 0,0:59:27.53,0:59:30.49,Default,,0,0,0,,再下一项是一个常数 它次数是0 系数是5 Dialogue: 0,0:59:31.45,0:59:34.16,Default,,0,0,0,,实际上有很多很多种方法 Dialogue: 0,0:59:34.25,0:59:35.96,Default,,0,0,0,,也有很多很多的取舍 Dialogue: 0,0:59:36.01,0:59:39.10,Default,,0,0,0,,在你认真思考如何实现代数操作程序包时 Dialogue: 0,0:59:39.44,0:59:41.73,Default,,0,0,0,,你该如何表示这些东西 Dialogue: 0,0:59:42.01,0:59:43.68,Default,,0,0,0,,但是我们这种是比较标准的一种 Dialogue: 0,0:59:44.18,0:59:45.55,Default,,0,0,0,,它适用于很多情况 Dialogue: 0,0:59:47.77,0:59:50.99,Default,,0,0,0,,好 那么我们怎么实现我们的多项式算术呢 Dialogue: 0,0:59:53.47,0:59:54.96,Default,,0,0,0,,现在开始着手做这个事情 Dialogue: 0,0:59:57.95,1:00:00.28,Default,,0,0,0,,构造一个多项式 首先要 Dialogue: 0,1:00:00.76,1:00:04.12,Default,,0,0,0,,首先我们得找一个办法来构造多项式 Dialogue: 0,1:00:05.69,1:00:10.28,Default,,0,0,0,,我们可以用一个变量 比如x和一个项表来构造它们 Dialogue: 0,1:00:11.24,1:00:14.09,Default,,0,0,0,,我们要用某种方法把它们包装起来 Dialogue: 0,1:00:14.30,1:00:19.40,Default,,0,0,0,,我们可以用cons把变量和项表组合起来 Dialogue: 0,1:00:19.82,1:00:21.74,Default,,0,0,0,,然后把这个序对加上polynomial的类型标志 Dialogue: 0,1:00:26.27,1:00:27.77,Default,,0,0,0,,那我们怎么处理多项式相加呢? Dialogue: 0,1:00:29.28,1:00:31.85,Default,,0,0,0,,要相加两个多项式 p1和p2 Dialogue: 0,1:00:32.68,1:00:35.18,Default,,0,0,0,,为了简化问题 假设我们 Dialogue: 0,1:00:35.37,1:00:37.15,Default,,0,0,0,,我们只相加变量相同的两个式子 Dialogue: 0,1:00:37.38,1:00:39.28,Default,,0,0,0,,那么如果它们的变量相同 Dialogue: 0,1:00:39.69,1:00:42.57,Default,,0,0,0,,是否相同交由我们编写的选择函数判断 Dialogue: 0,1:00:42.96,1:00:44.38,Default,,0,0,0,,我们不必在意它的细节 Dialogue: 0,1:00:45.15,1:00:47.04,Default,,0,0,0,,如果两个多项式的变量相同 Dialogue: 0,1:00:48.03,1:00:48.81,Default,,0,0,0,,我们就继续运算 Dialogue: 0,1:00:48.81,1:00:51.26,Default,,0,0,0,,如果它们的变量不相同 我们返回一个错误 Dialogue: 0,1:00:52.35,1:00:54.01,Default,,0,0,0,,“两个多项式的变量不相同” Dialogue: 0,1:00:55.48,1:00:57.37,Default,,0,0,0,,如果它们的变量确实是相同 Dialogue: 0,1:00:57.60,1:00:59.18,Default,,0,0,0,,我们就要构造一个新的多项式 Dialogue: 0,1:00:59.80,1:01:01.85,Default,,0,0,0,,它的变量即是原式的变量 Dialogue: 0,1:01:03.15,1:01:06.56,Default,,0,0,0,,它的项表则由过程+terms产生 Dialogue: 0,1:01:07.48,1:01:09.80,Default,,0,0,0,,+terms过程会把两个项表加起来 Dialogue: 0,1:01:10.17,1:01:12.01,Default,,0,0,0,,所以我们要把两个多项式的项表合起来 Dialogue: 0,1:01:13.50,1:01:14.51,Default,,0,0,0,,该过程即可返回一个项表 Dialogue: 0,1:01:15.00,1:01:20.01,Default,,0,0,0,,我们将变量和得到的项表构造成新的多项式 Dialogue: 0,1:01:20.68,1:01:21.79,Default,,0,0,0,,这就是+poly过程 Dialogue: 0,1:01:22.55,1:01:27.00,Default,,0,0,0,,然后我们要把这个过程放进表格中polynomial那一栏 Dialogue: 0,1:01:28.24,1:01:30.14,Default,,0,0,0,,用+poly实现add操作 Dialogue: 0,1:01:30.52,1:01:31.75,Default,,0,0,0,,当然实际上没做多少事情 Dialogue: 0,1:01:31.75,1:01:35.31,Default,,0,0,0,,我们只是把所有的工作压到+terms的头上 Dialogue: 0,1:01:35.79,1:01:37.02,Default,,0,0,0,,它会负责把项表相加起来 Dialogue: 0,1:01:37.74,1:01:39.16,Default,,0,0,0,,我们看看这个过程 Dialogue: 0,1:01:39.18,1:01:48.03,Default,,0,0,0,,这是+terms过程的大概结构 Dialogue: 0,1:01:48.90,1:01:51.74,Default,,0,0,0,,L1和L2是两个项表 Dialogue: 0,1:01:52.00,1:01:54.81,Default,,0,0,0,,所谓“项表”即是按每项次数排序的序对 Dialogue: 0,1:01:55.70,1:01:56.95,Default,,0,0,0,,这里有一个大的分情况分析 Dialogue: 0,1:01:59.86,1:02:04.14,Default,,0,0,0,,首先 我们要检查项表是否为空 Dialogue: 0,1:02:05.39,1:02:07.55,Default,,0,0,0,,我们对项表做递归下降处理 Dialogue: 0,1:02:08.16,1:02:11.74,Default,,0,0,0,,最终下降到 L1或L2为空 Dialogue: 0,1:02:12.27,1:02:14.35,Default,,0,0,0,,只要其中有一个为空 Dialogue: 0,1:02:14.52,1:02:15.85,Default,,0,0,0,,我们的答案就是剩下的另一个 Dialogue: 0,1:02:15.85,1:02:19.55,Default,,0,0,0,,就是说如果L1是空表 我们就返回L2 Dialogue: 0,1:02:19.63,1:02:21.71,Default,,0,0,0,,L2是空表的话就返回L1 Dialogue: 0,1:02:23.26,1:02:25.76,Default,,0,0,0,,除此之外还有三种情况 Dialogue: 0,1:02:27.22,1:02:27.98,Default,,0,0,0,,我们要做的是 Dialogue: 0,1:02:29.08,1:02:31.05,Default,,0,0,0,,取表中的第一项 Dialogue: 0,1:02:33.50,1:02:36.04,Default,,0,0,0,,记为t1和t2 Dialogue: 0,1:02:37.66,1:02:39.05,Default,,0,0,0,,我们来分析一下这三种情况 Dialogue: 0,1:02:39.60,1:02:45.68,Default,,0,0,0,,分别是t1的次数大于t2的 Dialogue: 0,1:02:47.23,1:02:50.59,Default,,0,0,0,,小于t2的 或者等于t2的 Dialogue: 0,1:02:53.28,1:02:54.91,Default,,0,0,0,,这就是我们要判断的三种情况 Dialogue: 0,1:02:54.91,1:02:55.84,Default,,0,0,0,,先看看这一种 Dialogue: 0,1:02:58.64,1:03:01.31,Default,,0,0,0,,如果t1的次数比t2的次数要高 Dialogue: 0,1:03:03.40,1:03:04.70,Default,,0,0,0,,就意味着 Dialogue: 0,1:03:06.06,1:03:09.96,Default,,0,0,0,,答案的第一项的次数就是t1的次数 Dialogue: 0,1:03:11.56,1:03:13.80,Default,,0,0,0,,因为高次项不会和任何低次项相加 Dialogue: 0,1:03:14.17,1:03:16.19,Default,,0,0,0,,那么我们只需要把低次的项加起来 Dialogue: 0,1:03:16.76,1:03:18.25,Default,,0,0,0,,我们递归地把 Dialogue: 0,1:03:19.71,1:03:25.07,Default,,0,0,0,,把L1和L2两个项表里剩下的项相加 Dialogue: 0,1:03:27.13,1:03:29.32,Default,,0,0,0,,作为我们的答案中低次项 Dialogue: 0,1:03:30.12,1:03:32.48,Default,,0,0,0,,然后我们把它们和最高次的项连接起来 Dialogue: 0,1:03:33.18,1:03:35.45,Default,,0,0,0,,这里 我用了一对还未定义的过程 Dialogue: 0,1:03:35.47,1:03:37.55,Default,,0,0,0,,比如adjoin-term、rest-terms Dialogue: 0,1:03:38.48,1:03:40.17,Default,,0,0,0,,还有获取次数的选择函数 Dialogue: 0,1:03:41.15,1:03:42.78,Default,,0,0,0,,但是你可以想象它们是什么样子的 Dialogue: 0,1:03:44.44,1:03:48.76,Default,,0,0,0,,那么如果第一个项表的次数比第二个要高 Dialogue: 0,1:03:48.78,1:03:51.08,Default,,0,0,0,,我们就递归地把所有的低次的项相加 Dialogue: 0,1:03:51.28,1:03:53.42,Default,,0,0,0,,再和最高次项连接起来 Dialogue: 0,1:03:55.54,1:03:56.75,Default,,0,0,0,,其它情况也是一样的 Dialogue: 0,1:03:56.89,1:04:00.28,Default,,0,0,0,,如果第一个多项式次数比较低 Dialogue: 0,1:04:00.54,1:04:08.36,Default,,0,0,0,,我们就把整个第一个多项式和第二个多项式低次的项相加 Dialogue: 0,1:04:08.62,1:04:12.65,Default,,0,0,0,,然后把结果再和最高次项连起来 Dialogue: 0,1:04:14.57,1:04:15.96,Default,,0,0,0,,到现在也没多少复杂的事情 Dialogue: 0,1:04:15.96,1:04:19.40,Default,,0,0,0,,把问题变成 让低次数的项相加 Dialogue: 0,1:04:19.47,1:04:21.96,Default,,0,0,0,,还有最后一种情况是 两个多项式的次数一样 Dialogue: 0,1:04:22.57,1:04:25.18,Default,,0,0,0,,你必须要把它们的系数加起来 因为它们是同类项 Dialogue: 0,1:04:27.24,1:04:30.99,Default,,0,0,0,,我们的应对方法仍然是 递归地把低次项相加 Dialogue: 0,1:04:31.00,1:04:32.83,Default,,0,0,0,,但现在我们需要合并一些项了 Dialogue: 0,1:04:33.46,1:04:36.35,Default,,0,0,0,,我们构造一个项 Dialogue: 0,1:04:37.31,1:04:39.93,Default,,0,0,0,,其次数为我们正在处理的那一项的次数 Dialogue: 0,1:04:40.82,1:04:42.72,Default,,0,0,0,,因为现在t1和t2的次数是相同的 Dialogue: 0,1:04:44.32,1:04:44.99,Default,,0,0,0,,确定好次数了 Dialogue: 0,1:04:45.09,1:04:52.33,Default,,0,0,0,,而它的系数是t1和t2系数之和 Dialogue: 0,1:04:55.79,1:04:59.64,Default,,0,0,0,,这是一个庞大的递归过程 Dialogue: 0,1:04:59.68,1:05:03.61,Default,,0,0,0,,但其中只有一个符号值得玩味 Dialogue: 0,1:05:04.25,1:05:05.69,Default,,0,0,0,,它蕴含了重要的思想 Dialogue: 0,1:05:05.90,1:05:08.50,Default,,0,0,0,,那就是这个ADD过程 Dialogue: 0,1:05:12.39,1:05:14.80,Default,,0,0,0,,说它有趣是因为 Dialogue: 0,1:05:15.42,1:05:17.37,Default,,0,0,0,,有一件好事发生 Dialogue: 0,1:05:18.22,1:05:21.37,Default,,0,0,0,,我们没有把多项式加法 Dialogue: 0,1:05:22.56,1:05:26.46,Default,,0,0,0,,归约为某种加法 而是归约为通用运算符ADD Dialogue: 0,1:05:28.82,1:05:32.28,Default,,0,0,0,,换句话说 用这种方法实现它之后 Dialogue: 0,1:05:32.89,1:05:34.68,Default,,0,0,0,,我们的系统就不光有 Dialogue: 0,1:05:35.92,1:05:41.66,Default,,0,0,0,,有理数、复数还有寻常算术 Dialogue: 0,1:05:41.85,1:05:43.82,Default,,0,0,0,,我们同时也让它支持多项式运算了 Dialogue: 0,1:05:48.52,1:05:51.13,Default,,0,0,0,,而多项式的系数可以是 Dialogue: 0,1:05:51.24,1:05:52.86,Default,,0,0,0,,这个系统能够相加的任何东西 Dialogue: 0,1:05:53.59,1:05:56.73,Default,,0,0,0,,也就是说多项式的系数 Dialogue: 0,1:05:57.20,1:06:01.20,Default,,0,0,0,,有理数或者复数 Dialogue: 0,1:06:02.76,1:06:06.99,Default,,0,0,0,,复数同时可支持直角坐标形式和极坐标形式 Dialogue: 0,1:06:09.12,1:06:11.39,Default,,0,0,0,,系数还可以是寻常的数字 Dialogue: 0,1:06:18.97,1:06:21.21,Default,,0,0,0,,我想说的是 Dialogue: 0,1:06:22.06,1:06:24.35,Default,,0,0,0,,我们的系统现在可以自动地 Dialogue: 0,1:06:26.60,1:06:31.50,Default,,0,0,0,,处理像这样的式子 Dialogue: 0,1:06:31.53,1:06:39.69,Default,,0,0,0,,比如2/3x^2+5/17x+11/4这样的式子 Dialogue: 0,1:06:40.94,1:06:43.48,Default,,0,0,0,,也可以自动处理像是 Dialogue: 0,1:06:43.82,1:06:52.57,Default,,0,0,0,,(3+2i)x^5+(4+7i)这样的式子 Dialogue: 0,1:06:53.88,1:06:56.21,Default,,0,0,0,,系统可以自动处理这些运算 Dialogue: 0,1:06:56.21,1:06:57.07,Default,,0,0,0,,为什么呢? Dialogue: 0,1:06:57.82,1:07:01.50,Default,,0,0,0,,仅仅是因为 或者说深层次的原因是 Dialogue: 0,1:07:02.17,1:07:05.93,Default,,0,0,0,,我们把多项式相加归约成了把它们的系数相加 Dialogue: 0,1:07:06.79,1:07:10.22,Default,,0,0,0,,而系数的相加是由通用运算符ADD完成的 Dialogue: 0,1:07:11.08,1:07:12.94,Default,,0,0,0,,它说:“我不管你的数据类型是什么” Dialogue: 0,1:07:12.96,1:07:14.08,Default,,0,0,0,,“只要我能够处理就行” Dialogue: 0,1:07:15.23,1:07:18.86,Default,,0,0,0,,于是我们就“免费”获得了处理这些东西的功能 Dialogue: 0,1:07:20.65,1:07:22.04,Default,,0,0,0,,更神奇的是 Dialogue: 0,1:07:24.51,1:07:26.52,Default,,0,0,0,,我们曾把 Dialogue: 0,1:07:27.20,1:07:30.52,Default,,0,0,0,,我们放入表格中 用于处理多项式加法 Dialogue: 0,1:07:31.28,1:07:32.52,Default,,0,0,0,,是用的+poly过程 Dialogue: 0,1:07:34.66,1:07:38.65,Default,,0,0,0,,这就意味着ADD过程也可以处理多项式了 Dialogue: 0,1:07:39.42,1:07:42.11,Default,,0,0,0,,我举个例子 Dialogue: 0,1:07:43.18,1:07:46.19,Default,,0,0,0,,这是一个多项式 Dialogue: 0,1:07:50.56,1:07:52.41,Default,,0,0,0,,我正在写的这个东西 Dialogue: 0,1:07:54.12,1:07:58.46,Default,,0,0,0,,它是一个以y作为变量的多项式 Dialogue: 0,1:08:01.07,1:08:04.69,Default,,0,0,0,,每项的系数是以x作为变量的多项式 Dialogue: 0,1:08:08.61,1:08:11.12,Default,,0,0,0,,你将看到 Dialogue: 0,1:08:11.76,1:08:14.06,Default,,0,0,0,,由于 “ADD过程能够处理多项式” Dialogue: 0,1:08:14.41,1:08:17.90,Default,,0,0,0,,我们可以说 我们的系统现在不光能运算有理数 Dialogue: 0,1:08:18.27,1:08:20.33,Default,,0,0,0,,复数和一般数字 Dialogue: 0,1:08:20.35,1:08:21.77,Default,,0,0,0,,我们还可以处理多项式 Dialogue: 0,1:08:22.09,1:08:25.39,Default,,0,0,0,,多项式的系数可以是有理数、复数、一般数字 Dialogue: 0,1:08:25.50,1:08:27.52,Default,,0,0,0,,甚至是多项式 Dialogue: 0,1:08:29.15,1:08:30.96,Default,,0,0,0,,作为系数的多项式 其系数还可以是有理数 Dialogue: 0,1:08:31.69,1:08:36.76,Default,,0,0,0,,复数(直角或极坐标形式)或一般数字 Dialogue: 0,1:08:36.94,1:08:41.13,Default,,0,0,0,,甚至还可以是系数为有理数的多项式 Dialogue: 0,1:08:41.80,1:08:43.32,Default,,0,0,0,,系数为复数、一般数字的多项式 Dialogue: 0,1:08:43.67,1:08:45.21,Default,,0,0,0,,以此类推 Dialogue: 0,1:08:45.95,1:08:47.55,Default,,0,0,0,,我们构造出了一座无限延伸的 Dialogue: 0,1:08:48.49,1:08:52.88,Default,,0,0,0,,或者说是递归的类型高塔 Dialogue: 0,1:08:53.88,1:08:57.12,Default,,0,0,0,,这一切都来源于那个小小的符号:A-D-D Dialogue: 0,1:08:57.61,1:09:00.49,Default,,0,0,0,,来源于在多项式程序里 用“ADD”来代替“+” Dialogue: 0,1:09:02.27,1:09:03.77,Default,,0,0,0,,换一种方式来理解它就是 Dialogue: 0,1:09:03.95,1:09:07.74,Default,,0,0,0,,多项式也是一种类型的构造函数 Dialogue: 0,1:09:08.74,1:09:11.20,Default,,0,0,0,,也就是说你传递给它一个类型 比如整型 Dialogue: 0,1:09:11.48,1:09:15.74,Default,,0,0,0,,然后它就返回一个以整数作为系数的多项式 Dialogue: 0,1:09:16.27,1:09:17.72,Default,,0,0,0,,过程中很重要的一点是 Dialogue: 0,1:09:18.65,1:09:20.73,Default,,0,0,0,,就是多项式上的运算 Dialogue: 0,1:09:21.28,1:09:23.37,Default,,0,0,0,,归约成了关于系数的运算 Dialogue: 0,1:09:23.39,1:09:24.96,Default,,0,0,0,,很多地方都与这里类似 Dialogue: 0,1:09:25.84,1:09:27.92,Default,,0,0,0,,比如 我们再回头看看有理数 Dialogue: 0,1:09:28.87,1:09:32.65,Default,,0,0,0,,我们之前把有理数看做 一个整数在另一个上面 Dialogue: 0,1:09:32.67,1:09:35.66,Default,,0,0,0,,但这并不是关于有理式的一般性记号 Dialogue: 0,1:09:36.24,1:09:42.03,Default,,0,0,0,,比如我们也可以把3x+7放在上面 x^2+1放在下面 Dialogue: 0,1:09:43.07,1:09:48.86,Default,,0,0,0,,这是一个分子分母都是多项式的广义有理式 Dialogue: 0,1:09:50.31,1:09:52.41,Default,,0,0,0,,有理式相加 和有理数相加一样 Dialogue: 0,1:09:52.44,1:09:55.40,Default,,0,0,0,,分子乘分母 加 分母乘分子 结果作为分子 Dialogue: 0,1:09:55.72,1:09:56.99,Default,,0,0,0,,两个分母相乘 结果作为分母 Dialogue: 0,1:09:57.29,1:09:59.37,Default,,0,0,0,,怎么把它安装到我们的系统中呢? Dialogue: 0,1:09:59.39,1:10:02.97,Default,,0,0,0,,这是我们原来的有理数算术程序包 Dialogue: 0,1:10:04.25,1:10:08.24,Default,,0,0,0,,为了让这个系统能够 Dialogue: 0,1:10:08.28,1:10:11.58,Default,,0,0,0,,支持广义有理式的运算 Dialogue: 0,1:10:11.85,1:10:16.44,Default,,0,0,0,,我们把特定的加法和乘法过程 都改成通用运算符 Dialogue: 0,1:10:16.48,1:10:19.18,Default,,0,0,0,,所以如果我们把原来那个过程变成这个过程 Dialogue: 0,1:10:19.71,1:10:22.04,Default,,0,0,0,,把+和*换成ADD和MUL Dialogue: 0,1:10:22.88,1:10:24.48,Default,,0,0,0,,这些是唯一的改动 Dialogue: 0,1:10:24.84,1:10:26.03,Default,,0,0,0,,然后霎时间 Dialogue: 0,1:10:27.52,1:10:31.40,Default,,0,0,0,,我们的整个系统 就知道怎么运算这样的东西了 Dialogue: 0,1:10:33.72,1:10:38.27,Default,,0,0,0,,比如说 这里的这个有理式 Dialogue: 0,1:10:39.18,1:10:44.86,Default,,0,0,0,,它的分子是一个系数是有理数的、关于x的多项式 Dialogue: 0,1:10:47.02,1:10:49.56,Default,,0,0,0,,而这个有理式 Dialogue: 0,1:10:51.10,1:10:54.43,Default,,0,0,0,,它的分子是关于x的多项式 Dialogue: 0,1:10:55.15,1:10:58.19,Default,,0,0,0,,多项式的系数又是有理式 Dialogue: 0,1:10:59.77,1:11:01.53,Default,,0,0,0,,有理式又由复数组成 Dialogue: 0,1:11:03.39,1:11:04.85,Default,,0,0,0,,或者别的像这样的东西 Dialogue: 0,1:11:04.85,1:11:08.68,Default,,0,0,0,,看 只要能够归约成针对各部分的运算 Dialogue: 0,1:11:08.89,1:11:10.00,Default,,0,0,0,,另一个例子是 Dialogue: 0,1:11:10.28,1:11:11.42,Default,,0,0,0,,2*2的矩阵 Dialogue: 0,1:11:12.31,1:11:15.44,Default,,0,0,0,,假如有这样一个矩阵形式的东西 Dialogue: 0,1:11:16.43,1:11:18.33,Default,,0,0,0,,不管它里面是什么 Dialogue: 0,1:11:18.72,1:11:20.14,Default,,0,0,0,,但是如果我对两个这种东西调用ADD Dialogue: 0,1:11:22.33,1:11:25.18,Default,,0,0,0,,答案就是 Dialogue: 0,1:11:25.18,1:11:28.14,Default,,0,0,0,,把这个和这个相加 而矩阵是怎么相加的 Dialogue: 0,1:11:29.03,1:11:31.11,Default,,0,0,0,,那么我可以用同样的方法实现 Dialogue: 0,1:11:31.11,1:11:31.71,Default,,0,0,0,,如果我这么做了 Dialogue: 0,1:11:31.96,1:11:34.60,Default,,0,0,0,,整个系统就马上可以处理像这样的东西了 Dialogue: 0,1:11:35.29,1:11:39.18,Default,,0,0,0,,比如说一个矩阵 它的元素都是 Dialogue: 0,1:11:39.46,1:11:42.16,Default,,0,0,0,,它的元素是一个有理式 Dialogue: 0,1:11:43.10,1:11:45.15,Default,,0,0,0,,这个有理式的分子分母都是多项式 Dialogue: 0,1:11:47.02,1:11:49.56,Default,,0,0,0,,我们自然而然地获得了这些功能 Dialogue: 0,1:11:51.28,1:11:53.82,Default,,0,0,0,,整个过程中发生了什么? Dialogue: 0,1:11:53.92,1:11:56.17,Default,,0,0,0,,真正发生的是 Dialogue: 0,1:11:57.68,1:12:02.44,Default,,0,0,0,,我们摆脱了凡事都想插一手的经理 Dialogue: 0,1:12:03.12,1:12:06.19,Default,,0,0,0,,我们构造了一个“控制去中心化”的系统 Dialogue: 0,1:12:14.78,1:12:18.34,Default,,0,0,0,,你进入这个系统的时候 不会有人一边闲逛一边说 Dialogue: 0,1:12:18.35,1:12:22.30,Default,,0,0,0,,我看看官方列表中ADD是否能够处理你 Dialogue: 0,1:12:22.44,1:12:26.22,Default,,0,0,0,,你直接就可以用正确的方法 把你和别的东西加起来 Dialogue: 0,1:12:27.81,1:12:31.03,Default,,0,0,0,,这么做的好处就是 就连这种非常非常 Dialogue: 0,1:12:31.03,1:12:33.87,Default,,0,0,0,,复杂的分层对象也可以被分解后 Dialogue: 0,1:12:33.87,1:12:35.55,Default,,0,0,0,,自动放到正确的地方去处理 Dialogue: 0,1:12:37.00,1:12:37.79,Default,,0,0,0,,有什么问题吗? Dialogue: 0,1:12:40.38,1:12:42.32,Default,,0,0,0,,学生:你说你“免费”获得了这些功能 Dialogue: 0,1:12:42.35,1:12:45.82,Default,,0,0,0,,但是我在意的是你现在丢掉了 Dialogue: 0,1:12:46.48,1:12:50.91,Default,,0,0,0,,某种上下层之间的清楚界限 Dialogue: 0,1:12:50.91,1:12:52.77,Default,,0,0,0,,或者说 现在你是在用 Dialogue: 0,1:12:52.77,1:12:56.08,Default,,0,0,0,,上层的东西来定义下层的过程 Dialogue: 0,1:12:56.61,1:12:59.45,Default,,0,0,0,,这不是很危险吗? Dialogue: 0,1:13:00.35,1:13:04.49,Default,,0,0,0,,或者说 结构会变得混乱? Dialogue: 0,1:13:05.44,1:13:05.95,Default,,0,0,0,,教授:不 我-- Dialogue: 0,1:13:06.41,1:13:07.77,Default,,0,0,0,,你问它的结构是否混乱 Dialogue: 0,1:13:07.77,1:13:08.69,Default,,0,0,0,,这得要看你说的“结构”是指什么 Dialogue: 0,1:13:08.69,1:13:10.17,Default,,0,0,0,,整个过程里我们都在做递归 Dialogue: 0,1:13:11.05,1:13:18.80,Default,,0,0,0,,看 就是说要把这些东西相加就要用到这个过程 Dialogue: 0,1:13:19.15,1:13:21.37,Default,,0,0,0,,它是一种递归结构 并不混乱 Dialogue: 0,1:13:22.70,1:13:24.99,Default,,0,0,0,,所以我不认为它不清楚 Dialogue: 0,1:13:24.99,1:13:28.16,Default,,0,0,0,,学生:那么当你修改乘法或加法运算时 Dialogue: 0,1:13:29.34,1:13:31.38,Default,,0,0,0,,可能会导致 Dialogue: 0,1:13:31.38,1:13:34.27,Default,,0,0,0,,无法预测的灾难性后果 Dialogue: 0,1:13:34.48,1:13:36.44,Default,,0,0,0,,教授:你说得对 但是那要看你的意思是什么 Dialogue: 0,1:13:37.08,1:13:38.47,Default,,0,0,0,,从两个角度来讨论 Dialogue: 0,1:13:39.10,1:13:43.24,Default,,0,0,0,,举个什么例子好呢? Dialogue: 0,1:13:44.69,1:13:47.50,Default,,0,0,0,,比如说 之前我忽略了GCD运算 Dialogue: 0,1:13:47.77,1:13:50.08,Default,,0,0,0,,我们忽略了它 是为了简化我们的例子 Dialogue: 0,1:13:50.28,1:13:56.92,Default,,0,0,0,,但是如果突然我觉得 这里的+rat Dialogue: 0,1:13:57.82,1:14:01.69,Default,,0,0,0,,应该把结果约分 然后把这个功能安装到程序里 Dialogue: 0,1:14:03.34,1:14:07.87,Default,,0,0,0,,那么这个功能一旦安装 就立刻可以被所有过程调用 Dialogue: 0,1:14:08.03,1:14:10.08,Default,,0,0,0,,被这个或者那个 所有的这些 Dialogue: 0,1:14:11.56,1:14:13.89,Default,,0,0,0,,这取决于你系统的相干性(耦合度) Dialogue: 0,1:14:13.89,1:14:17.03,Default,,0,0,0,,确实你可能想设计一个 Dialogue: 0,1:14:17.03,1:14:19.56,Default,,0,0,0,,不这样递归下降的程序 Dialogue: 0,1:14:19.61,1:14:22.97,Default,,0,0,0,,但是我举这个例子的好处 就在于我们通常都是这么做的 Dialogue: 0,1:14:25.44,1:14:27.63,Default,,0,0,0,,学生:是不是有一个问题 我想 Dialogue: 0,1:14:27.63,1:14:32.95,Default,,0,0,0,,就是你会被这个结构捆绑起来 Dialogue: 0,1:14:32.95,1:14:36.33,Default,,0,0,0,,这个递归的结构是实际上被执行了的 Dialogue: 0,1:14:36.33,1:14:40.34,Default,,0,0,0,,而不是仅仅是为了定义类型的需要 Dialogue: 0,1:14:40.34,1:14:41.16,Default,,0,0,0,,被这个事实所束缚 Dialogue: 0,1:14:44.68,1:14:46.12,Default,,0,0,0,,教授:我大概明白你的意思 Dialogue: 0,1:14:46.12,1:14:47.80,Default,,0,0,0,,你是想说在这个系统投入运行之后 Dialogue: 0,1:14:47.82,1:14:50.40,Default,,0,0,0,,这些类型还会变得越来越复杂 Dialogue: 0,1:14:50.40,1:14:50.73,Default,,0,0,0,,你是不是想…… Dialogue: 0,1:14:50.73,1:14:50.99,Default,,0,0,0,,学生:对 Dialogue: 0,1:14:50.99,1:14:51.79,Default,,0,0,0,,在它投入运行之后 Dialogue: 0,1:14:52.09,1:14:54.18,Default,,0,0,0,,学生:而不是作为基本的定义 Dialogue: 0,1:14:54.18,1:14:54.83,Default,,0,0,0,,教授:对 Dialogue: 0,1:14:54.83,1:14:56.70,Default,,0,0,0,,我们的类型结构可以说就是递归的 Dialogue: 0,1:14:57.21,1:15:00.22,Default,,0,0,0,,它并不是一个 可以在系统投入运行之前 Dialogue: 0,1:15:01.58,1:15:04.85,Default,,0,0,0,,就能把要用到的东西全部包括的列表 Dialogue: 0,1:15:04.85,1:15:05.79,Default,,0,0,0,,它是一个不断演进的东西 Dialogue: 0,1:15:06.78,1:15:08.64,Default,,0,0,0,,所以如果你想要定制这个系统 Dialogue: 0,1:15:08.67,1:15:10.96,Default,,0,0,0,,你就不能通过有限的表 Dialogue: 0,1:15:11.00,1:15:13.18,Default,,0,0,0,,你需要用一个递归结构实现它 Dialogue: 0,1:15:13.67,1:15:17.90,Default,,0,0,0,,学生:因为类型的基本结构是相当简单而明了的 Dialogue: 0,1:15:17.90,1:15:18.19,Default,,0,0,0,,教授:对 Dialogue: 0,1:15:20.40,1:15:20.75,Default,,0,0,0,,嗯? Dialogue: 0,1:15:21.46,1:15:22.87,Default,,0,0,0,,学生:我有一个问题 Dialogue: 0,1:15:22.87,1:15:25.68,Default,,0,0,0,,我明白一旦你的数据结构被设计好之后 Dialogue: 0,1:15:25.71,1:15:28.73,Default,,0,0,0,,它是怎么把complex标志拿掉 把它传递给下层 Dialogue: 0,1:15:28.73,1:15:30.64,Default,,0,0,0,,然后把rect类型拿掉 再传递给下层 Dialogue: 0,1:15:30.64,1:15:33.95,Default,,0,0,0,,但是如果你只是一个用户 并不知道什么rect或者polar类型 Dialogue: 0,1:15:34.25,1:15:36.04,Default,,0,0,0,,你怎么知道如何去设置这个数据结构 Dialogue: 0,1:15:36.09,1:15:38.08,Default,,0,0,0,,让所有东西正常运转呢 Dialogue: 0,1:15:38.09,1:15:41.00,Default,,0,0,0,,如果我只知道左边的这个算式 Dialogue: 0,1:15:41.02,1:15:42.50,Default,,0,0,0,,我只是想把复数加起来或者乘起来 Dialogue: 0,1:15:42.50,1:15:43.64,Default,,0,0,0,,教授:这就是它神奇的地方 Dialogue: 0,1:15:43.64,1:15:45.26,Default,,0,0,0,,如果你是一个用户 直接调用mul就可以了 Dialogue: 0,1:15:47.73,1:15:49.95,Default,,0,0,0,,学生:然后它就能明白我要计算的是复数? Dialogue: 0,1:15:49.96,1:15:51.23,Default,,0,0,0,,或者我怎么告诉它我想—— Dialogue: 0,1:15:51.26,1:15:53.05,Default,,0,0,0,,教授:只要你给它的是复数它就能明白 Dialogue: 0,1:15:53.05,1:15:56.30,Default,,0,0,0,,作为这个系统的用户 Dialogue: 0,1:15:56.32,1:15:58.14,Default,,0,0,0,,你能使用的是复数的构造函数 Dialogue: 0,1:15:58.37,1:15:59.55,Default,,0,0,0,,学生:那么我需要自己构造复数了? Dialogue: 0,1:15:59.56,1:16:00.35,Default,,0,0,0,,教授:那么你需要自己构造它们 Dialogue: 0,1:16:00.35,1:16:04.01,Default,,0,0,0,,作为用户 你可能只能够操作命令行 Dialogue: 0,1:16:04.65,1:16:07.56,Default,,0,0,0,,它会给你提供一些合理的方法 Dialogue: 0,1:16:07.56,1:16:08.86,Default,,0,0,0,,来输入复数 Dialogue: 0,1:16:09.31,1:16:11.00,Default,,0,0,0,,让你用你喜欢的格式输入 Dialogue: 0,1:16:11.59,1:16:14.36,Default,,0,0,0,,也可能你根本就不用输入它们 Dialogue: 0,1:16:14.36,1:16:16.17,Default,,0,0,0,,只是别人给你一个复数让你计算 Dialogue: 0,1:16:16.78,1:16:19.82,Default,,0,0,0,,学生:好 那么如果我有一个含有多项式的复数 Dialogue: 0,1:16:19.82,1:16:21.96,Default,,0,0,0,,我就要先构造这个多项式 然后再构造我的复数 Dialogue: 0,1:16:21.96,1:16:23.96,Default,,0,0,0,,教授:如果你是从零开始构造它的话 是这样的 Dialogue: 0,1:16:24.28,1:16:25.71,Default,,0,0,0,,可以说你是在从零开始构造 Dialogue: 0,1:16:25.71,1:16:27.05,Default,,0,0,0,,而你只要有了要计算的东西 Dialogue: 0,1:16:27.28,1:16:30.32,Default,,0,0,0,,可以直接调用mul运算 然后它们就会被乘起来 Dialogue: 0,1:16:32.78,1:16:32.99,Default,,0,0,0,,说吧 Dialogue: 0,1:16:33.27,1:16:35.76,Default,,0,0,0,,学生:我想提一个问题 就是…… Dialogue: 0,1:16:36.45,1:16:40.01,Default,,0,0,0,,比如说我想修改我的复数表示方法 Dialogue: 0,1:16:40.03,1:16:41.44,Default,,0,0,0,,或者复数的某些运算 Dialogue: 0,1:16:41.52,1:16:47.10,Default,,0,0,0,,为了修改一个特定的运算 Dialogue: 0,1:16:47.15,1:16:51.26,Default,,0,0,0,,我得考虑多少代码? Dialogue: 0,1:16:52.27,1:16:53.49,Default,,0,0,0,,教授:得看你想要修改什么 Dialogue: 0,1:16:53.49,1:16:54.99,Default,,0,0,0,,重点在于你只需要改 Dialogue: 0,1:16:55.39,1:16:56.07,Default,,0,0,0,,你想改的那一部分 Dialogue: 0,1:16:56.07,1:17:00.04,Default,,0,0,0,,想象一下如果Martha决定她 Dialogue: 0,1:17:00.32,1:17:01.23,Default,,0,0,0,,举个不太好的例子 Dialogue: 0,1:17:01.44,1:17:02.91,Default,,0,0,0,,比如把序对中两个数的顺序调换 Dialogue: 0,1:17:04.04,1:17:08.72,Default,,0,0,0,,把模和辐角的顺序反过来 Dialogue: 0,1:17:09.39,1:17:10.80,Default,,0,0,0,,她只做了局部的修改 Dialogue: 0,1:17:10.97,1:17:13.29,Default,,0,0,0,,那么这个改动会准确无误地扩散到整个系统里 Dialogue: 0,1:17:14.79,1:17:18.76,Default,,0,0,0,,或者突然你说 我有另一种方法来表示有理数 Dialogue: 0,1:17:19.70,1:17:23.90,Default,,0,0,0,,我就得不断地在表格中添加运算 Dialogue: 0,1:17:24.82,1:17:27.22,Default,,0,0,0,,那么突然之间所有的多项式 Dialogue: 0,1:17:27.22,1:17:29.10,Default,,0,0,0,,它们的系数和系数的系数 或者什么东西 Dialogue: 0,1:17:29.24,1:17:32.40,Default,,0,0,0,,都自动支持用这种表示方法来表示了 Dialogue: 0,1:17:32.70,1:17:34.67,Default,,0,0,0,,这就是我们这种设计的威力 Dialogue: 0,1:17:36.11,1:17:38.70,Default,,0,0,0,,学生:我提的这个问题可能听起来比较蠢 Dialogue: 0,1:17:38.70,1:17:42.38,Default,,0,0,0,,整个这个系统看起来 Dialogue: 0,1:17:42.54,1:17:45.88,Default,,0,0,0,,非常完美 所有的东西都各就各位 Dialogue: 0,1:17:46.72,1:17:48.67,Default,,0,0,0,,完美得有点出乎意料 Dialogue: 0,1:17:50.93,1:17:52.52,Default,,0,0,0,,我相信 这都是为了教学方便 Dialogue: 0,1:17:52.56,1:17:54.65,Default,,0,0,0,,我怀疑的是首先发明了这种做法的人 Dialogue: 0,1:17:55.10,1:17:55.85,Default,,0,0,0,,我可能说得不对 Dialogue: 0,1:17:56.60,1:17:59.72,Default,,0,0,0,,难道一下子就搞清楚了所有这些东西一起 Dialogue: 0,1:17:59.77,1:18:03.93,Default,,0,0,0,,只要把这些放在一起 你就突然可以对各种对象做各种运算 Dialogue: 0,1:18:04.86,1:18:07.20,Default,,0,0,0,,我觉得他们应该研究了很长时间 Dialogue: 0,1:18:07.93,1:18:10.62,Default,,0,0,0,,不断地推倒重来 Dialogue: 0,1:18:11.80,1:18:14.12,Default,,0,0,0,,然后我觉得 当我们设计一个非常复杂的系统 Dialogue: 0,1:18:14.12,1:18:16.94,Default,,0,0,0,,我们也要面对这样的问题 Dialogue: 0,1:18:17.31,1:18:20.35,Default,,0,0,0,,就是有太多各种各样的部件 我们甚至不知道 Dialogue: 0,1:18:21.08,1:18:24.62,Default,,0,0,0,,我们甚至不知道要对这些部件做什么样的操作 Dialogue: 0,1:18:24.62,1:18:26.54,Default,,0,0,0,,在这种时候我怎么用这种良好的方法组织操作 Dialogue: 0,1:18:26.56,1:18:29.63,Default,,0,0,0,,才能获得这种 不管怎样只要把它们放在一起 Dialogue: 0,1:18:29.63,1:18:31.39,Default,,0,0,0,,所有事情就正常运转 这样的效果呢 Dialogue: 0,1:18:31.70,1:18:34.34,Default,,0,0,0,,教授:很好 这确实是一个非常聪明的问题 Dialogue: 0,1:18:35.10,1:18:39.52,Default,,0,0,0,,要说的一点是我们这种方法论 Dialogue: 0,1:18:39.87,1:18:43.88,Default,,0,0,0,,受到了符号代数的很多启发 Dialogue: 0,1:18:44.59,1:18:45.90,Default,,0,0,0,,符号代数相当繁复 Dialogue: 0,1:18:47.59,1:18:50.71,Default,,0,0,0,,允许你在决定各种运算是什么样子之前 Dialogue: 0,1:18:50.71,1:18:52.89,Default,,0,0,0,,来实现这个系统 Dialogue: 0,1:18:53.31,1:18:57.72,Default,,0,0,0,,所以从某种意义上讲 这是人们在这方面长期探索之后得出的答案 Dialogue: 0,1:18:58.56,1:19:00.75,Default,,0,0,0,,从另一个角度来说 这确实是精心设计的例子 Dialogue: 0,1:19:02.16,1:19:06.24,Default,,0,0,0,,学生:看上去想要设计出这样的系统 Dialogue: 0,1:19:06.24,1:19:09.01,Default,,0,0,0,,一开始先要研究一段时间然后才能变熟练 Dialogue: 0,1:19:09.01,1:19:11.88,Default,,0,0,0,,教授:我给你看看这个东西是多么的勉强 Dialogue: 0,1:19:12.22,1:19:14.13,Default,,0,0,0,,你现在可以写下所有的这些程序 Dialogue: 0,1:19:14.13,1:19:16.25,Default,,0,0,0,,但是我写在这里的这个系统 Dialogue: 0,1:19:17.02,1:19:18.96,Default,,0,0,0,,如果允许我拖堂半小时的话 Dialogue: 0,1:19:19.31,1:19:20.46,Default,,0,0,0,,我会给大家讲 Dialogue: 0,1:19:20.81,1:19:23.02,Default,,0,0,0,,如果我让它做一个错误操作 Dialogue: 0,1:19:23.20,1:19:29.31,Default,,0,0,0,,比如一个愚蠢的命令 用3加上7/2 它就会崩溃 Dialogue: 0,1:19:30.88,1:19:33.42,Default,,0,0,0,,因为程序首先会调用operate-2这个过程 Dialogue: 0,1:19:33.80,1:19:35.95,Default,,0,0,0,,然后operate-2会说 这个是数字类型 Dialogue: 0,1:19:36.18,1:19:37.37,Default,,0,0,0,,那个是有理数类型 Dialogue: 0,1:19:37.56,1:19:38.81,Default,,0,0,0,,我不知道怎么把它们加起来 Dialogue: 0,1:19:41.53,1:19:44.30,Default,,0,0,0,,那么你想让这个系统至少能够 Dialogue: 0,1:19:45.88,1:19:47.34,Default,,0,0,0,,比如说 在做这个操作之前 Dialogue: 0,1:19:48.59,1:19:50.24,Default,,0,0,0,,把3提升为3/1 Dialogue: 0,1:19:50.48,1:19:53.21,Default,,0,0,0,,把它变成一个有理数 然后交给有理数程序包来处理 Dialogue: 0,1:19:54.86,1:19:58.70,Default,,0,0,0,,课堂上我们来不及讲这个问题了 Dialogue: 0,1:19:58.73,1:20:00.88,Default,,0,0,0,,书里面讨论了这个问题 Dialogue: 0,1:20:00.88,1:20:01.95,Default,,0,0,0,,叫做“类型转换” Dialogue: 0,1:20:03.39,1:20:05.15,Default,,0,0,0,,你想要的是 Dialogue: 0,1:20:05.31,1:20:08.89,Default,,0,0,0,,看 我们小心翼翼地把对象按类型分好类 Dialogue: 0,1:20:08.91,1:20:12.17,Default,,0,0,0,,但是有时你也想让它 Dialogue: 0,1:20:12.40,1:20:17.98,Default,,0,0,0,,知道怎么把一个普通的数字当成有理数 Dialogue: 0,1:20:19.11,1:20:21.29,Default,,0,0,0,,或者把普通的数字当成复数 Dialogue: 0,1:20:21.62,1:20:25.16,Default,,0,0,0,,到那个时候系统就开始变得复杂了 Dialogue: 0,1:20:25.76,1:20:28.12,Default,,0,0,0,,就是你去思考 我应该把这些知识放在哪里的时候 Dialogue: 0,1:20:28.42,1:20:32.19,Default,,0,0,0,,是应该让有理数知道它们是由普通的数字构成的吗? Dialogue: 0,1:20:33.13,1:20:36.38,Default,,0,0,0,,或者我们举一个更加糟糕的例子 Dialogue: 0,1:20:38.14,1:20:47.48,Default,,0,0,0,,比如说我想要把一个复数加到有理数上去 Dialogue: 0,1:20:49.87,1:20:50.76,Default,,0,0,0,,这个不好 Dialogue: 0,1:20:50.76,1:20:51.58,Default,,0,0,0,,5/7 Dialogue: 0,1:20:53.86,1:20:55.72,Default,,0,0,0,,然后整个系统里必须有人知道 Dialogue: 0,1:20:56.06,1:20:58.16,Default,,0,0,0,,他需要把这个东西变成另一种类型 Dialogue: 0,1:20:58.20,1:21:00.65,Default,,0,0,0,,要把它变成一部分是有理数的复数 Dialogue: 0,1:21:01.54,1:21:02.68,Default,,0,0,0,,那么谁应该去操心这个事情呢 Dialogue: 0,1:21:02.68,1:21:03.95,Default,,0,0,0,,是complex程序包吗? Dialogue: 0,1:21:03.95,1:21:05.03,Default,,0,0,0,,是rational程序包吗? Dialogue: 0,1:21:05.24,1:21:06.22,Default,,0,0,0,,还是plus过程要考虑这个问题? Dialogue: 0,1:21:06.90,1:21:08.52,Default,,0,0,0,,这就是体现复杂性的地方 Dialogue: 0,1:21:08.52,1:21:11.38,Default,,0,0,0,,也是这个问题的特别之处 Dialogue: 0,1:21:11.38,1:21:14.12,Default,,0,0,0,,同时很多的 实际上是所有的这样的“消息传递”的想法 Dialogue: 0,1:21:14.64,1:21:16.54,Default,,0,0,0,,都是被这样的问题启发的 Dialogue: 0,1:21:18.46,1:21:20.89,Default,,0,0,0,,当你真正深入进去 Dialogue: 0,1:21:20.91,1:21:24.76,Default,,0,0,0,,人们发现 代数操作的问题是如此复杂 Dialogue: 0,1:21:25.18,1:21:27.41,Default,,0,0,0,,而那些一直围绕它们工作的人们 确实就处在 Dialogue: 0,1:21:27.41,1:21:28.05,Default,,0,0,0,,你说的那种状态 Dialogue: 0,1:21:28.05,1:21:29.71,Default,,0,0,0,,他们在这些问题里艰难跋涉 时不时陷进泥里 Dialogue: 0,1:21:29.72,1:21:31.37,Default,,0,0,0,,寻找好用的工具 并试着提炼一种通用方法 Dialogue: 0,1:21:34.20,1:21:37.76,Default,,0,0,0,,学生:我想再一次回到这个复杂度的问题上来 Dialogue: 0,1:21:38.41,1:21:44.55,Default,,0,0,0,,在修改底层过程的时候 这个系统 Dialogue: 0,1:21:44.55,1:21:48.32,Default,,0,0,0,,毫无疑问 体现了非常大的灵活性 Dialogue: 0,1:21:49.71,1:21:53.40,Default,,0,0,0,,但是确实 在某种意义上讲 Dialogue: 0,1:21:53.44,1:21:55.26,Default,,0,0,0,,冻结了高层运算 Dialogue: 0,1:21:55.45,1:21:58.51,Default,,0,0,0,,或者至少如果你修改它们 你不知道 Dialogue: 0,1:21:58.51,1:22:02.06,Default,,0,0,0,,改动会体现在哪里 会怎么体现出来 Dialogue: 0,1:22:02.20,1:22:04.22,Default,,0,0,0,,教授:这个问题真是不能再好了 Dialogue: 0,1:22:04.68,1:22:05.87,Default,,0,0,0,,我要做的事情就是 Dialogue: 0,1:22:08.68,1:22:10.84,Default,,0,0,0,,如果我决定添加一个通用操作 Dialogue: 0,1:22:11.45,1:22:13.07,Default,,0,0,0,,比如equality-test Dialogue: 0,1:22:14.96,1:22:17.15,Default,,0,0,0,,那么系统中的其它人就要查表格 Dialogue: 0,1:22:18.22,1:22:22.54,Default,,0,0,0,,来看他们需不需要支持equality-test Dialogue: 0,1:22:24.65,1:22:26.84,Default,,0,0,0,,我们可以让它变得更加去中心化 Dialogue: 0,1:22:27.87,1:22:30.70,Default,,0,0,0,,这就是之前我提示了很多次的事情 Dialogue: 0,1:22:31.08,1:22:33.26,Default,,0,0,0,,你不但可以通过给对象添加符号标签来体现类型 Dialogue: 0,1:22:33.40,1:22:38.70,Default,,0,0,0,,而是把每一类对象接受的运算也保存在里面 Dialogue: 0,1:22:40.45,1:22:43.90,Default,,0,0,0,,那么你可以添加一个 比如说最大公约数过程 Dialogue: 0,1:22:44.43,1:22:46.81,Default,,0,0,0,,它只能计算整数 Dialogue: 0,1:22:47.40,1:22:49.21,Default,,0,0,0,,而不是对所有有理数都通用 Dialogue: 0,1:22:51.03,1:22:53.11,Default,,0,0,0,,所以这个系统可能是非常非常碎片化的 Dialogue: 0,1:22:53.11,1:22:55.66,Default,,0,0,0,,取决于你想让哪一部分比较灵活 Dialogue: 0,1:22:56.22,1:22:59.02,Default,,0,0,0,,有一系列的地方让你把这个东西放进去 Dialogue: 0,1:22:59.96,1:23:02.56,Default,,0,0,0,,但是你也指出了这种设计的弱点 Dialogue: 0,1:23:02.60,1:23:06.37,Default,,0,0,0,,就是必须在顶层 对于这些通用运算符有一些约定 Dialogue: 0,1:23:06.37,1:23:07.82,Default,,0,0,0,,或者至少人们要考虑这件事情 Dialogue: 0,1:23:08.39,1:23:10.72,Default,,0,0,0,,或者你可以决定 把这个表格设计得非常稀疏 Dialogue: 0,1:23:10.75,1:23:11.96,Default,,0,0,0,,里面只放很少的一点东西 Dialogue: 0,1:23:14.01,1:23:15.49,Default,,0,0,0,,这个游戏有很多种玩法 Dialogue: 0,1:23:19.78,1:23:20.43,Default,,0,0,0,,谢谢大家 Dialogue: 0,1:23:23.53,1:23:36.56,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:23:23.53,1:23:36.56,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec4b.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:11.40,0:00:16.50,EN,,0,0,0,,Generic Operators Dialogue: 0,0:00:20.18,0:00:21.84,EN,,0,0,0,,PROFESSOR: So far in this course we've been talking Dialogue: 0,0:00:21.84,0:00:23.78,EN,,0,0,0,,a lot about data abstraction. Dialogue: 0,0:00:23.78,0:00:27.15,EN,,0,0,0,,And remember the idea is that we build systems Dialogue: 0,0:00:27.74,0:00:32.56,EN,,0,0,0,,that have these horizontal barriers in them, these abstraction barriers Dialogue: 0,0:00:33.42,0:00:39.21,EN,,0,0,0,,that separate use, the way you might use some data object, Dialogue: 0,0:00:39.93,0:00:41.18,EN,,0,0,0,,from the way you might represent it. Dialogue: 0,0:00:49.40,0:00:52.03,EN,,0,0,0,,Or another way to think of that is up here you have the boss Dialogue: 0,0:00:52.11,0:00:55.50,EN,,0,0,0,,who's going to be using some sort of data object. Dialogue: 0,0:00:57.11,0:01:02.31,EN,,0,0,0,,And down here is George who's implemented it. Dialogue: 0,0:01:02.31,0:01:05.42,EN,,0,0,0,,Now this notion of separating use from representation Dialogue: 0,0:01:05.44,0:01:09.76,EN,,0,0,0,,so you can think about these two problems separately Dialogue: 0,0:01:10.60,0:01:14.76,EN,,0,0,0,,is a very,very powerful programming methodology, data abstraction. Dialogue: 0,0:01:15.93,0:01:18.81,EN,,0,0,0,,On the other hand, it's not really sufficient Dialogue: 0,0:01:19.56,0:01:21.84,EN,,0,0,0,,for really complex systems. Dialogue: 0,0:01:22.96,0:01:27.64,EN,,0,0,0,,And the problem with this is George. Dialogue: 0,0:01:28.64,0:01:32.09,EN,,0,0,0,,Or actually, the problem is that Dialogue: 0,0:01:32.09,0:01:32.78,EN,,0,0,0,,there are a lot of Georges. Dialogue: 0,0:01:34.63,0:01:35.39,EN,,0,0,0,,Let's be concrete. Dialogue: 0,0:01:35.39,0:01:39.18,EN,,0,0,0,,Let's suppose there is George,and there's also Martha. Dialogue: 0,0:01:41.19,0:01:44.22,EN,,0,0,0,,OK, now George and Martha are both working on this system, Dialogue: 0,0:01:46.04,0:01:47.29,EN,,0,0,0,,both designing representations, Dialogue: 0,0:01:48.41,0:01:50.67,EN,,0,0,0,,and absolutely are incompatible. Dialogue: 0,0:01:51.75,0:01:53.62,EN,,0,0,0,,They wouldn't cooperate on a representation Dialogue: 0,0:01:54.01,0:01:55.34,EN,,0,0,0,,under any circumstances. Dialogue: 0,0:01:57.48,0:01:59.72,EN,,0,0,0,,And the problem is you would like to have some system Dialogue: 0,0:02:00.06,0:02:02.60,EN,,0,0,0,,where both George and Martha are designing representations, Dialogue: 0,0:02:03.82,0:02:08.08,EN,,0,0,0,,and, yet, if you're above this abstraction barrier Dialogue: 0,0:02:09.40,0:02:11.04,EN,,0,0,0,,you don't want to have to worry about that, Dialogue: 0,0:02:11.66,0:02:14.18,EN,,0,0,0,,whether something is done by George or by Martha. Dialogue: 0,0:02:14.18,0:02:15.43,EN,,0,0,0,,And you don't want George and Martha to Dialogue: 0,0:02:15.43,0:02:16.48,EN,,0,0,0,,interfere with each other. Dialogue: 0,0:02:16.63,0:02:20.31,EN,,0,0,0,,Somehow in designing a system, you not only want these Dialogue: 0,0:02:20.31,0:02:23.84,EN,,0,0,0,,horizontal barriers, but you also want some kind of Dialogue: 0,0:02:25.82,0:02:30.64,EN,,0,0,0,,some kind of vertical barrier to keep George and Martha separate. Dialogue: 0,0:02:32.98,0:02:35.40,EN,,0,0,0,,Let me be a little bit more concrete. Dialogue: 0,0:02:36.56,0:02:40.54,EN,,0,0,0,,Imagine that you're thinking about personnel records Dialogue: 0,0:02:41.18,0:02:46.11,EN,,0,0,0,,for a large company with a lot of loosely linked divisions Dialogue: 0,0:02:47.90,0:02:49.71,EN,,0,0,0,,that don't cooperate very well either. Dialogue: 0,0:02:50.43,0:02:57.04,EN,,0,0,0,,And imagine even that this company is formed by merging a Dialogue: 0,0:02:57.04,0:02:59.45,EN,,0,0,0,,whole bunch of companies that already have their personnel Dialogue: 0,0:02:59.45,0:03:00.70,EN,,0,0,0,,record system set up. Dialogue: 0,0:03:03.25,0:03:06.57,EN,,0,0,0,,And imagine that once these divisions are all linked in Dialogue: 0,0:03:06.57,0:03:08.53,EN,,0,0,0,,some kind of very sophisticated satellite Dialogue: 0,0:03:08.53,0:03:10.52,EN,,0,0,0,,network, and all these databases are put together. Dialogue: 0,0:03:12.24,0:03:13.85,EN,,0,0,0,,And what you'd like to do Dialogue: 0,0:03:14.84,0:03:16.33,EN,,0,0,0,,is from any place in the company, Dialogue: 0,0:03:17.26,0:03:23.13,EN,,0,0,0,,to be able to say things like,oh, what's the name in a Dialogue: 0,0:03:23.13,0:03:23.87,EN,,0,0,0,,personnel record? Dialogue: 0,0:03:26.30,0:03:29.15,EN,,0,0,0,,Or, what's the job description in a personnel record? Dialogue: 0,0:03:30.54,0:03:34.40,EN,,0,0,0,,And not have to worry about the fact that each division Dialogue: 0,0:03:34.84,0:03:36.76,EN,,0,0,0,,obviously is going to have completely separate Dialogue: 0,0:03:36.76,0:03:39.37,EN,,0,0,0,,conventions for how you might implement these records. Dialogue: 0,0:03:41.58,0:03:43.26,EN,,0,0,0,,From this point you don't want to know about that. Dialogue: 0,0:03:44.96,0:03:47.92,EN,,0,0,0,,Well how could you possibly do that? Dialogue: 0,0:03:48.43,0:03:52.41,EN,,0,0,0,,One way, of course, is to send down an edict from somewhere Dialogue: 0,0:03:52.64,0:03:56.29,EN,,0,0,0,,that everybody has to change their format to some fixed Dialogue: 0,0:03:56.29,0:03:57.24,EN,,0,0,0,,compatible thing. Dialogue: 0,0:03:58.07,0:04:00.12,EN,,0,0,0,,That's what people often try, and of course it never works. Dialogue: 0,0:04:01.82,0:04:07.34,EN,,0,0,0,,Another thing that you might want to do is somehow arrange Dialogue: 0,0:04:08.33,0:04:09.90,EN,,0,0,0,,it so you can have these vertical barriers. Dialogue: 0,0:04:11.25,0:04:14.40,EN,,0,0,0,,So that when you ask for the name of a personnel record, Dialogue: 0,0:04:14.43,0:04:17.97,EN,,0,0,0,,somehow, whatever format it happens to be, name will Dialogue: 0,0:04:17.97,0:04:19.42,EN,,0,0,0,,figure out how to do the right thing. Dialogue: 0,0:04:22.73,0:04:25.53,EN,,0,0,0,,We want name to be, so-called, a generic operator. Dialogue: 0,0:04:26.26,0:04:30.06,EN,,0,0,0,,Generic operator means what it sort of precisely does depends Dialogue: 0,0:04:30.06,0:04:31.69,EN,,0,0,0,,on the kind of data that it's looking at. Dialogue: 0,0:04:33.65,0:04:36.62,EN,,0,0,0,,More than that, you'd like to design the system so that the Dialogue: 0,0:04:36.92,0:04:39.79,EN,,0,0,0,,next time a new division comes into the company Dialogue: 0,0:04:42.51,0:04:45.64,EN,,0,0,0,,they don't have to make any big changes in what they're already doing Dialogue: 0,0:04:45.64,0:04:50.11,EN,,0,0,0,,to link into this system, and the rest of the company Dialogue: 0,0:04:50.11,0:04:52.01,EN,,0,0,0,,doesn't have to make any big changes Dialogue: 0,0:04:52.27,0:04:53.93,EN,,0,0,0,,to admit their stuff to the system. Dialogue: 0,0:04:55.52,0:04:57.52,EN,,0,0,0,,So that's the problem you should be thinking about. Dialogue: 0,0:04:58.70,0:05:00.77,EN,,0,0,0,,Like it's sort of just your work. Dialogue: 0,0:05:00.77,0:05:03.77,EN,,0,0,0,,You want to be able to include new things by making minimal changes. Dialogue: 0,0:05:05.98,0:05:08.12,EN,,0,0,0,,OK, well that's the problem that we'll be talking about today. Dialogue: 0,0:05:09.44,0:05:14.22,EN,,0,0,0,,And you should have this sort of distributed personnel record system in your mind. Dialogue: 0,0:05:14.24,0:05:16.62,EN,,0,0,0,,But actually the one I'll be talking about is a problem Dialogue: 0,0:05:16.62,0:05:18.48,EN,,0,0,0,,that's a little bit more self-contained than that. Dialogue: 0,0:05:19.29,0:05:21.76,EN,,0,0,0,,that'll bring up the issues, I think, more clearly. Dialogue: 0,0:05:21.87,0:05:26.01,EN,,0,0,0,,That's the problem of doing a system that does arithmetic on complex numbers. Dialogue: 0,0:05:27.77,0:05:28.92,EN,,0,0,0,,So let's take a look here. Dialogue: 0,0:05:30.69,0:05:31.74,EN,,0,0,0,,Just as a little review, Dialogue: 0,0:05:32.04,0:05:33.53,EN,,0,0,0,,there are things called complex numbers. Dialogue: 0,0:05:35.25,0:05:38.22,EN,,0,0,0,,Complex number you can think of as a point in the plane, or z. Dialogue: 0,0:05:39.37,0:05:47.19,EN,,0,0,0,,And you can represent a point either by its real-part and its imaginary-part. Dialogue: 0,0:05:47.19,0:05:50.83,EN,,0,0,0,,So if this is z and its real-part is this much, Dialogue: 0,0:05:51.50,0:05:53.24,EN,,0,0,0,,and its imaginary-part is that much, Dialogue: 0,0:05:54.33,0:05:56.44,EN,,0,0,0,,and you write z equals x plus iy. Dialogue: 0,0:05:59.11,0:06:03.21,EN,,0,0,0,,Or another way to represent a complex number is by saying, Dialogue: 0,0:06:03.21,0:06:09.00,EN,,0,0,0,,what's the distance from the origin, and what's the angle? Dialogue: 0,0:06:11.32,0:06:16.67,EN,,0,0,0,,So that represents a complex number as its radius times an angle. Dialogue: 0,0:06:19.52,0:06:21.92,EN,,0,0,0,,This one's called -- the original one's called rectangular form, Dialogue: 0,0:06:22.59,0:06:25.45,EN,,0,0,0,,rectangular representation, real- and imaginary-part Dialogue: 0,0:06:26.20,0:06:30.04,EN,,0,0,0,,or polar representation magnitude and angle-- Dialogue: 0,0:06:30.04,0:06:31.48,EN,,0,0,0,,and if you know the real- and imaginary-part, Dialogue: 0,0:06:31.53,0:06:33.36,EN,,0,0,0,,you can figure out the magnitude and angle. Dialogue: 0,0:06:33.72,0:06:36.97,EN,,0,0,0,,If you know x and y, you can get r by this formula. Dialogue: 0,0:06:37.19,0:06:39.48,EN,,0,0,0,,Square root of sum of the squares, and you can get the Dialogue: 0,0:06:39.48,0:06:40.76,EN,,0,0,0,,angle as an arctangent. Dialogue: 0,0:06:41.42,0:06:44.42,EN,,0,0,0,,Or conversely, if you knew r and A you could Dialogue: 0,0:06:44.42,0:06:45.31,EN,,0,0,0,,figure out x and y. Dialogue: 0,0:06:45.80,0:06:49.43,EN,,0,0,0,,x is r times the cosine of A, and y is r times the sine of A. Dialogue: 0,0:06:51.34,0:06:53.66,EN,,0,0,0,,All right, so there's these two. They're complex numbers. Dialogue: 0,0:06:54.13,0:06:57.15,EN,,0,0,0,,You can think of them either in polar form or rectangular form. Dialogue: 0,0:06:57.15,0:06:58.12,EN,,0,0,0,,What we would like to do Dialogue: 0,0:06:58.32,0:07:01.32,EN,,0,0,0,,is make a system that does arithmetic on complex numbers. Dialogue: 0,0:07:03.95,0:07:05.12,EN,,0,0,0,,In other words, what we'd like-- Dialogue: 0,0:07:05.58,0:07:06.99,EN,,0,0,0,,just like the rational number example-- Dialogue: 0,0:07:07.38,0:07:10.20,EN,,0,0,0,,is to have some operations plus c, Dialogue: 0,0:07:10.73,0:07:13.90,EN,,0,0,0,,which is going to take two complex numbers and add them, subtract them, Dialogue: 0,0:07:14.35,0:07:16.94,EN,,0,0,0,,and multiply them, and divide them. Dialogue: 0,0:07:20.73,0:07:25.28,EN,,0,0,0,,OK, well there's little bit of mathematics behind it. Dialogue: 0,0:07:25.28,0:07:28.36,EN,,0,0,0,,What are the actual formulas for manipulating such things? Dialogue: 0,0:07:30.41,0:07:31.92,EN,,0,0,0,,And it's sort of not important where they come from, Dialogue: 0,0:07:34.00,0:07:35.79,EN,,0,0,0,,but just as an implementer let's see-- Dialogue: 0,0:07:35.80,0:07:37.95,EN,,0,0,0,,if you want to add two complex numbers it's pretty easy to Dialogue: 0,0:07:39.13,0:07:42.66,EN,,0,0,0,,it's pretty easy to get its real-part and its imaginary-part. Dialogue: 0,0:07:42.66,0:07:45.93,EN,,0,0,0,,The real-part of the sum of two complex numbers Dialogue: 0,0:07:47.72,0:07:49.72,EN,,0,0,0,,real-part of the z1 plus z2 Dialogue: 0,0:07:50.06,0:07:54.64,EN,,0,0,0,,is the real-part of z1 plus the real-part of z2. Dialogue: 0,0:07:57.82,0:08:01.60,EN,,0,0,0,,And the imaginary-part of z1 plus z2 Dialogue: 0,0:08:01.74,0:08:05.66,EN,,0,0,0,,is the imaginary part of z1 plus the imaginary part of z2. Dialogue: 0,0:08:07.41,0:08:09.48,EN,,0,0,0,,So it's pretty easy to add complex numbers. Dialogue: 0,0:08:09.48,0:08:10.99,EN,,0,0,0,,You just add the corresponding parts Dialogue: 0,0:08:11.31,0:08:13.18,EN,,0,0,0,,and make a new complex number with those parts. Dialogue: 0,0:08:13.37,0:08:14.73,EN,,0,0,0,,If you want to multiply them, Dialogue: 0,0:08:15.53,0:08:17.82,EN,,0,0,0,,it's kind of nice to do it in polar form. Dialogue: 0,0:08:17.82,0:08:20.38,EN,,0,0,0,,Because if you have two complex numbers, Dialogue: 0,0:08:20.40,0:08:26.54,EN,,0,0,0,,the magnitude of their product is here, the product of the magnitudes. Dialogue: 0,0:08:28.85,0:08:33.88,EN,,0,0,0,,And the angle of the product is the sum of the angles. Dialogue: 0,0:08:35.80,0:08:40.54,EN,,0,0,0,,So that's sort of mathematics that allows you to do arithmetic on complex numbers. Dialogue: 0,0:08:40.54,0:08:42.38,EN,,0,0,0,,Let's actually think about the implementation. Dialogue: 0,0:08:43.72,0:08:47.39,EN,,0,0,0,,Well we do it just like rational numbers. Dialogue: 0,0:08:49.84,0:08:53.47,EN,,0,0,0,,We come down, we assume we have some constructors and selectors. Dialogue: 0,0:08:53.76,0:08:54.52,EN,,0,0,0,,What would we like? Dialogue: 0,0:08:55.33,0:08:58.16,EN,,0,0,0,,Well let's assume that we make a data object cloud, Dialogue: 0,0:08:58.54,0:09:00.78,EN,,0,0,0,,which is a complex number that has some stuff in it, Dialogue: 0,0:09:01.79,0:09:04.67,EN,,0,0,0,,and that we can get out from a complex number the real-part, Dialogue: 0,0:09:05.52,0:09:09.64,EN,,0,0,0,,or the imaginary-part, or the magnitude, or the angle. Dialogue: 0,0:09:12.15,0:09:14.01,EN,,0,0,0,,We want some ways of making complex numbers-- Dialogue: 0,0:09:14.03,0:09:15.64,EN,,0,0,0,,not only selectors, but constructors. Dialogue: 0,0:09:16.80,0:09:19.52,EN,,0,0,0,,So we'll assume we have a thing called make-rectangular. Dialogue: 0,0:09:19.53,0:09:24.27,EN,,0,0,0,,What make-rectangular is going to do is take a real-part and Dialogue: 0,0:09:24.51,0:09:29.36,EN,,0,0,0,,an imaginary-part and construct a complex number with those parts. Dialogue: 0,0:09:31.92,0:09:35.01,EN,,0,0,0,,Similarly, we can have make-polar which will taking Dialogue: 0,0:09:35.01,0:09:37.85,EN,,0,0,0,,a magnitude and an angle, Dialogue: 0,0:09:40.83,0:09:43.90,EN,,0,0,0,,and construct a complex number which has that magnitude and angle. Dialogue: 0,0:09:44.68,0:09:45.46,EN,,0,0,0,,So here's a system. Dialogue: 0,0:09:45.46,0:09:47.77,EN,,0,0,0,,We'll have two constructors and four selectors. Dialogue: 0,0:09:48.91,0:09:55.15,EN,,0,0,0,,And now, just like before, in terms of that abstract data Dialogue: 0,0:09:55.15,0:09:59.22,EN,,0,0,0,,we'll go ahead and implement our complex number operations. Dialogue: 0,0:09:59.22,0:10:02.30,EN,,0,0,0,,And here you can see translated into Lisp code Dialogue: 0,0:10:03.23,0:10:07.47,EN,,0,0,0,,just the arithmetic formulas I put down before. Dialogue: 0,0:10:08.06,0:10:09.98,EN,,0,0,0,,If I want to add two complex numbers Dialogue: 0,0:10:11.76,0:10:15.56,EN,,0,0,0,,I will make a complex number out of its real- and imaginary-parts. Dialogue: 0,0:10:16.72,0:10:19.02,EN,,0,0,0,,The real part of the complex number I'm going to make Dialogue: 0,0:10:19.40,0:10:21.80,EN,,0,0,0,,is the sum of the real-parts. Dialogue: 0,0:10:23.31,0:10:25.37,EN,,0,0,0,,The imaginary part of the complex number I'm going to make Dialogue: 0,0:10:25.40,0:10:27.52,EN,,0,0,0,,is the sum of the imaginary-parts. Dialogue: 0,0:10:30.31,0:10:32.09,EN,,0,0,0,,I put those together, make a complex number. Dialogue: 0,0:10:32.16,0:10:34.44,EN,,0,0,0,,That's how I implement complex number addition. Dialogue: 0,0:10:35.78,0:10:38.49,EN,,0,0,0,,Subtraction is essentially the same. Dialogue: 0,0:10:39.65,0:10:42.97,EN,,0,0,0,,All I do is subtract the parts rather than add them. Dialogue: 0,0:10:45.14,0:10:47.07,EN,,0,0,0,,To multiply two complex numbers, Dialogue: 0,0:10:47.74,0:10:49.02,EN,,0,0,0,,I use the other formula. Dialogue: 0,0:10:49.27,0:10:53.84,EN,,0,0,0,,I'll make a complex number out of a magnitude and angle. Dialogue: 0,0:10:55.35,0:10:56.44,EN,,0,0,0,,The magnitude Dialogue: 0,0:10:56.65,0:11:00.97,EN,,0,0,0,,is going to be the product of the magnitudesof the two complex numbers I'm multiplying. Dialogue: 0,0:11:03.71,0:11:05.93,EN,,0,0,0,,And the angle is going to be the sum Dialogue: 0,0:11:06.16,0:11:08.51,EN,,0,0,0,,of the angles of the z1two complex numbers I'm multiplying. Dialogue: 0,0:11:09.62,0:11:10.96,EN,,0,0,0,,So there's multiplication. Dialogue: 0,0:11:11.23,0:11:12.25,EN,,0,0,0,,And then division, Dialogue: 0,0:11:14.27,0:11:15.90,EN,,0,0,0,,division is almost the same. Dialogue: 0,0:11:17.37,0:11:19.58,EN,,0,0,0,,Here I divide the magnitudes and subtract the angles. Dialogue: 0,0:11:28.36,0:11:30.46,EN,,0,0,0,,Now I've implemented the operations. Dialogue: 0,0:11:31.87,0:11:33.64,EN,,0,0,0,,And what do we do? Dialogue: 0,0:11:33.64,0:11:34.52,EN,,0,0,0,,We call on George. Dialogue: 0,0:11:36.06,0:11:38.79,EN,,0,0,0,,We've done the use, let's worry about the representation. Dialogue: 0,0:11:38.80,0:11:40.94,EN,,0,0,0,,We'll call on George and say to George, Dialogue: 0,0:11:40.97,0:11:43.61,EN,,0,0,0,,go ahead and build us a complex number representation. Dialogue: 0,0:11:45.25,0:11:47.44,EN,,0,0,0,,Well that's fine...ahhh Dialogue: 0,0:11:47.77,0:11:52.66,EN,,0,0,0,,George can say, we'll implement a complex number Dialogue: 0,0:11:52.66,0:11:57.15,EN,,0,0,0,,simply as a pair that has the real-part and the imaginary-part. Dialogue: 0,0:11:57.20,0:12:02.62,EN,,0,0,0,,So if I want to make a complex number with a certain real-part and an imaginary-part, Dialogue: 0,0:12:03.36,0:12:05.55,EN,,0,0,0,,I'll just use cons to form a pair, and that will-- Dialogue: 0,0:12:06.03,0:12:08.11,EN,,0,0,0,,that's George's representation of a complex number. Dialogue: 0,0:12:09.78,0:12:12.42,EN,,0,0,0,,So if I want to get out the real-part of something, I just Dialogue: 0,0:12:12.42,0:12:14.12,EN,,0,0,0,,extract the car, the first part. Dialogue: 0,0:12:14.35,0:12:16.67,EN,,0,0,0,,If I want to get the imaginary-part, I extract the cdr Dialogue: 0,0:12:19.64,0:12:21.77,EN,,0,0,0,,How do I deal with the magnitude and angle? Dialogue: 0,0:12:22.22,0:12:25.75,EN,,0,0,0,,Well if I want to extract the magnitude of one of these things Dialogue: 0,0:12:25.75,0:12:32.30,EN,,0,0,0,,I get the square root of the sum of the square of the car plus the square of the cdr. Dialogue: 0,0:12:33.79,0:12:39.26,EN,,0,0,0,,If I want to get the angle, I compute the arctangent of the cdr in the car. Dialogue: 0,0:12:39.53,0:12:42.86,EN,,0,0,0,,This is a lisp procedure for computing arctangent. Dialogue: 0,0:12:44.97,0:12:48.59,EN,,0,0,0,,And if somebody hands me a magnitude and an angle Dialogue: 0,0:12:48.94,0:12:50.56,EN,,0,0,0,,and says, make me a complex number,well I compute the Dialogue: 0,0:12:50.89,0:12:56.24,EN,,0,0,0,,well I compute the real-part and the imaginary-part, r * cosine of a and r * sine of a, Dialogue: 0,0:12:57.77,0:12:59.05,EN,,0,0,0,,and stick them together into a pair. Dialogue: 0,0:13:01.46,0:13:02.26,EN,,0,0,0,,OK so we're done. Dialogue: 0,0:13:02.26,0:13:04.75,EN,,0,0,0,,In fact, what I just did, conceptually, Dialogue: 0,0:13:06.89,0:13:09.37,EN,,0,0,0,,is absolutely no different from the rational number Dialogue: 0,0:13:10.60,0:13:12.44,EN,,0,0,0,,representation that we looked at last time. Dialogue: 0,0:13:12.75,0:13:13.91,EN,,0,0,0,,It's the same sort of idea. Dialogue: 0,0:13:13.91,0:13:16.28,EN,,0,0,0,,You implement the operators, you pick a representation. Dialogue: 0,0:13:18.07,0:13:18.65,EN,,0,0,0,,Nothing different. Dialogue: 0,0:13:20.07,0:13:21.56,EN,,0,0,0,,Now let's worry about Martha. Dialogue: 0,0:13:23.21,0:13:24.52,EN,,0,0,0,,See, Martha has a different idea. Dialogue: 0,0:13:26.67,0:13:28.57,EN,,0,0,0,,She doesn't want to represent a complex number Dialogue: 0,0:13:28.59,0:13:30.90,EN,,0,0,0,,as a pair of a real-part and an imaginary-part. Dialogue: 0,0:13:30.90,0:13:34.17,EN,,0,0,0,,What she would like to do is represent a complex number as Dialogue: 0,0:13:34.17,0:13:37.69,EN,,0,0,0,,a pair of a magnitude and an angle. Dialogue: 0,0:13:39.55,0:13:42.13,EN,,0,0,0,,So if instead of calling up George we ask Martha to design Dialogue: 0,0:13:42.13,0:13:43.74,EN,,0,0,0,,our representation, we get something like this. Dialogue: 0,0:13:44.57,0:13:47.16,EN,,0,0,0,,We get make-polar. Dialogue: 0,0:13:47.16,0:13:50.22,EN,,0,0,0,,Sure, if I give you a magnitude and an angle we're Dialogue: 0,0:13:50.22,0:13:53.07,EN,,0,0,0,,just going to form a pair that has magnitude and angle. Dialogue: 0,0:13:55.43,0:13:57.68,EN,,0,0,0,,If you want to extract the magnitude, that's easy. Dialogue: 0,0:13:58.24,0:13:59.37,EN,,0,0,0,,You just pull out the car or the pair. Dialogue: 0,0:13:59.78,0:14:02.67,EN,,0,0,0,,If you want to extract the angle, sure, that's easy. Dialogue: 0,0:14:02.67,0:14:03.63,EN,,0,0,0,,You just pull out the cdr. Dialogue: 0,0:14:04.81,0:14:07.02,EN,,0,0,0,,If you want to look for real-parts and imaginary-parts, Dialogue: 0,0:14:07.42,0:14:08.49,EN,,0,0,0,,well then you have to do some work. Dialogue: 0,0:14:08.88,0:14:14.58,EN,,0,0,0,,If you want the real-part, you have to get r cosine a. Dialogue: 0,0:14:14.58,0:14:19.99,EN,,0,0,0,,In other words, r, the car of the pair, times the cosine of Dialogue: 0,0:14:19.99,0:14:20.95,EN,,0,0,0,,the cdr of the pair. Dialogue: 0,0:14:20.95,0:14:26.23,EN,,0,0,0,,So this is r times the cosine of a, Dialogue: 0,0:14:26.54,0:14:27.48,EN,,0,0,0,,and that's the real-part. Dialogue: 0,0:14:28.33,0:14:31.40,EN,,0,0,0,,If you want to get the imaginary-part, it's r times the sine of a. Dialogue: 0,0:14:32.66,0:14:37.93,EN,,0,0,0,,And if I hand you a real-part and an imaginary-part and say, Dialogue: 0,0:14:37.93,0:14:42.03,EN,,0,0,0,,make me a complex number with that real-part and Dialogue: 0,0:14:42.03,0:14:44.17,EN,,0,0,0,,imaginary-part, well I figure out what the magnitude and Dialogue: 0,0:14:44.17,0:14:45.54,EN,,0,0,0,,angle should be. Dialogue: 0,0:14:45.54,0:14:47.85,EN,,0,0,0,,The magnitude's the square root of the sum of the squares Dialogue: 0,0:14:48.09,0:14:49.23,EN,,0,0,0,,and the angle's the arctangent. Dialogue: 0,0:14:49.23,0:14:50.22,EN,,0,0,0,,I put those together to make a pair. Dialogue: 0,0:14:52.09,0:14:54.17,EN,,0,0,0,,So there's Martha's idea. Dialogue: 0,0:14:56.69,0:14:57.37,EN,,0,0,0,,Well which is better? Dialogue: 0,0:14:59.68,0:15:03.15,EN,,0,0,0,,Well if you're doing a lot of additions, probably George's is better Dialogue: 0,0:15:03.16,0:15:05.61,EN,,0,0,0,,is better, because you're doing a lot of real-parts and imaginary-parts. Dialogue: 0,0:15:05.85,0:15:08.40,EN,,0,0,0,,If mostly you're going to be doing multiplications and divisions, Dialogue: 0,0:15:09.48,0:15:11.14,EN,,0,0,0,,then maybe Martha's idea is better. Dialogue: 0,0:15:11.14,0:15:14.84,EN,,0,0,0,,Or maybe, and this is the real point, you can't decide. Dialogue: 0,0:15:16.59,0:15:22.32,EN,,0,0,0,,Or maybe you just have to let them both hang around, for personality reasons. Dialogue: 0,0:15:23.48,0:15:26.76,EN,,0,0,0,,Maybe you just really can't ever decide what you would like. Dialogue: 0,0:15:28.56,0:15:32.32,EN,,0,0,0,,And again, what we would really like is a system that looks like this. Dialogue: 0,0:15:32.65,0:15:36.17,EN,,0,0,0,,That somehow there's George over here, who has built Dialogue: 0,0:15:36.83,0:15:39.64,EN,,0,0,0,,rectangular complex numbers. Dialogue: 0,0:15:41.47,0:15:44.25,EN,,0,0,0,,And Martha, who has polar complex numbers. Dialogue: 0,0:15:46.12,0:15:49.69,EN,,0,0,0,,And somehow we have operations Dialogue: 0,0:15:50.28,0:15:56.89,EN,,0,0,0,,that can add, and subtract, and multiply, and divide Dialogue: 0,0:15:57.56,0:15:58.76,EN,,0,0,0,,and it shouldn't matter Dialogue: 0,0:15:59.34,0:16:02.79,EN,,0,0,0,,that there are two incompatible representations of complex Dialogue: 0,0:16:02.79,0:16:03.98,EN,,0,0,0,,numbers floating around this system. Dialogue: 0,0:16:04.41,0:16:08.33,EN,,0,0,0,,In other words, not only like an abstraction barrier here Dialogue: 0,0:16:09.64,0:16:11.84,EN,,0,0,0,,that has things in it like a real-part, Dialogue: 0,0:16:15.77,0:16:21.71,EN,,0,0,0,,and an imaginary-part, and magnitude,and angle. Dialogue: 0,0:16:23.83,0:16:25.36,EN,,0,0,0,,So not only is there an abstraction barrier Dialogue: 0,0:16:25.39,0:16:28.38,EN,,0,0,0,,that hides the actual representation from us, Dialogue: 0,0:16:29.10,0:16:31.52,EN,,0,0,0,,but also there's some kind of vertical barrier here Dialogue: 0,0:16:32.19,0:16:35.02,EN,,0,0,0,,that allows both of these representations to exist Dialogue: 0,0:16:35.87,0:16:37.40,EN,,0,0,0,,without interfering with each other. Dialogue: 0,0:16:38.57,0:16:41.07,EN,,0,0,0,,The idea is that the things in here-- Dialogue: 0,0:16:41.90,0:16:44.12,EN,,0,0,0,,real-part, imaginary-part,magnitude, and angle-- Dialogue: 0,0:16:44.12,0:16:46.49,EN,,0,0,0,,will be generic operators. Dialogue: 0,0:16:47.31,0:16:49.45,EN,,0,0,0,,If you ask for the real-part, it will worry about Dialogue: 0,0:16:49.98,0:16:51.31,EN,,0,0,0,,what representation it's looking at. Dialogue: 0,0:16:53.88,0:16:55.10,EN,,0,0,0,,OK, well how can we do that? Dialogue: 0,0:16:56.84,0:16:59.23,EN,,0,0,0,,There's actually a really obvious idea, Dialogue: 0,0:16:59.84,0:17:01.68,EN,,0,0,0,,if you're used to thinking about complex numbers. Dialogue: 0,0:17:02.52,0:17:04.44,EN,,0,0,0,,If you're used to thinking about compound data. Dialogue: 0,0:17:06.33,0:17:10.99,EN,,0,0,0,,See, suppose you could just tell by looking at a complex number Dialogue: 0,0:17:12.17,0:17:13.95,EN,,0,0,0,,whether it was constructed by George or Martha. Dialogue: 0,0:17:15.79,0:17:18.90,EN,,0,0,0,,In other words, so it's not that what's floating around Dialogue: 0,0:17:18.90,0:17:20.91,EN,,0,0,0,,here are ordinary, just complex numbers, right? Dialogue: 0,0:17:20.91,0:17:22.94,EN,,0,0,0,,They're fancy, designer complex numbers. Dialogue: 0,0:17:24.39,0:17:28.04,EN,,0,0,0,,So you look at a complex numbers as it's not just a complex number Dialogue: 0,0:17:28.04,0:17:29.16,EN,,0,0,0,,it's got a label on it that says, Dialogue: 0,0:17:29.19,0:17:30.75,EN,,0,0,0,,that one is by Martha. Dialogue: 0,0:17:31.45,0:17:34.22,EN,,0,0,0,,Or this is a complex number by George. Dialogue: 0,0:17:34.48,0:17:35.39,EN,,0,0,0,,Right? They're signed. Dialogue: 0,0:17:36.86,0:17:40.15,EN,,0,0,0,,See, and then whenever we looked at a complex number we Dialogue: 0,0:17:40.15,0:17:45.48,EN,,0,0,0,,could just read the label, and then we'd know how you expect Dialogue: 0,0:17:45.80,0:17:46.72,EN,,0,0,0,,to operate on that. Dialogue: 0,0:17:48.03,0:17:51.19,EN,,0,0,0,,In other words, what we want is not just ordinary data objects. Dialogue: 0,0:17:51.19,0:17:54.37,EN,,0,0,0,,We want to introduce the notion of what's called typed data. Dialogue: 0,0:17:59.76,0:18:02.81,EN,,0,0,0,,Typed data means, again, there's some sort of cloud. Dialogue: 0,0:18:03.94,0:18:08.93,EN,,0,0,0,,And what it's got in it is an ordinary data object like Dialogue: 0,0:18:08.93,0:18:09.90,EN,,0,0,0,,we've been thinking about. Dialogue: 0,0:18:13.18,0:18:16.54,EN,,0,0,0,,Pulled out the contents, sort of the actual data. Dialogue: 0,0:18:19.32,0:18:21.56,EN,,0,0,0,,But also a thing called a type, Dialogue: 0,0:18:22.56,0:18:25.24,EN,,0,0,0,,but it's signed by either George or Martha. Dialogue: 0,0:18:25.99,0:18:28.27,EN,,0,0,0,,So we're going to go from regular data to type data. Dialogue: 0,0:18:31.95,0:18:32.71,EN,,0,0,0,,How do we build that? Dialogue: 0,0:18:32.71,0:18:33.50,EN,,0,0,0,,Well that's easy. Dialogue: 0,0:18:33.84,0:18:35.32,EN,,0,0,0,,We know how to build clouds. Dialogue: 0,0:18:35.80,0:18:36.88,EN,,0,0,0,,We can build them out of pairs. Dialogue: 0,0:18:37.92,0:18:41.82,EN,,0,0,0,,So here's a little representation that supports typed data. Dialogue: 0,0:18:43.51,0:18:49.64,EN,,0,0,0,,There's a thing called take a type and attach it to a piece of contents, Dialogue: 0,0:18:49.69,0:18:50.64,EN,,0,0,0,,and we just use cons. Dialogue: 0,0:18:51.64,0:18:54.11,EN,,0,0,0,,And if we have a piece of typed data, we can look at the type Dialogue: 0,0:18:55.21,0:18:56.00,EN,,0,0,0,,which is the car. Dialogue: 0,0:18:56.29,0:18:58.30,EN,,0,0,0,,We can look at the contents,which is the cdr. Dialogue: 0,0:18:59.96,0:19:04.28,EN,,0,0,0,,Now along with that, the way we use our type data will test, Dialogue: 0,0:19:05.29,0:19:07.26,EN,,0,0,0,,when we're given a piece of data, what type it is. Dialogue: 0,0:19:07.52,0:19:09.26,EN,,0,0,0,,So we have some type predicates with us. Dialogue: 0,0:19:10.51,0:19:13.73,EN,,0,0,0,,For example, to see whether a complex number is one of Dialogue: 0,0:19:13.73,0:19:16.86,EN,,0,0,0,,George's, whether it's rectangular, we just check to Dialogue: 0,0:19:16.86,0:19:21.85,EN,,0,0,0,,see if the type of that is the symbol rectangular, Dialogue: 0,0:19:23.68,0:19:25.05,EN,,0,0,0,,right? The symbol rectangular. Dialogue: 0,0:19:27.20,0:19:30.33,EN,,0,0,0,,And to check whether a complex number is one of Martha's, Dialogue: 0,0:19:30.33,0:19:33.42,EN,,0,0,0,,we check to see whether the type is the symbol polar. Dialogue: 0,0:19:36.46,0:19:39.21,EN,,0,0,0,,So that's a way to test what kind of number we're looking at. Dialogue: 0,0:19:40.75,0:19:42.81,EN,,0,0,0,,Now let's think about how we can use that to build the system. Dialogue: 0,0:19:43.87,0:19:46.73,EN,,0,0,0,,So let's suppose that George and Martha were off working separately, Dialogue: 0,0:19:47.36,0:19:52.64,EN,,0,0,0,,and each of them had designed their complex number representation packages. Dialogue: 0,0:19:52.64,0:19:58.52,EN,,0,0,0,,What do they have to do to become part of the system, Dialogue: 0,0:19:58.73,0:20:00.14,EN,,0,0,0,,to exist compatibly? Dialogue: 0,0:20:00.14,0:20:02.11,EN,,0,0,0,,Well it's really pretty easy. Dialogue: 0,0:20:02.72,0:20:04.51,EN,,0,0,0,,Remember, George had this package. Dialogue: 0,0:20:05.97,0:20:08.48,EN,,0,0,0,,Here's George's original package, or half of it. Dialogue: 0,0:20:08.98,0:20:11.15,EN,,0,0,0,,And underlined in red are the changes he has to make. Dialogue: 0,0:20:12.09,0:20:16.43,EN,,0,0,0,,So before, when George made a complex number out of an x and y Dialogue: 0,0:20:17.52,0:20:19.85,EN,,0,0,0,,he just put them together to make a pair. Dialogue: 0,0:20:20.93,0:20:23.39,EN,,0,0,0,,And the only difference is that now he signs them. Dialogue: 0,0:20:24.09,0:20:28.08,EN,,0,0,0,,He attaches the type, which is the symbol rectangular to that pair. Dialogue: 0,0:20:30.60,0:20:33.26,EN,,0,0,0,,Everything else George does is the same, except that-- Dialogue: 0,0:20:33.92,0:20:38.06,EN,,0,0,0,,see, George and Martha both have procedures named real-part and imaginary-part. Dialogue: 0,0:20:38.70,0:20:42.96,EN,,0,0,0,,So to allow them both to exist in the same Lisp environment, Dialogue: 0,0:20:44.22,0:20:45.92,EN,,0,0,0,,George had changed the names of his procedures. Dialogue: 0,0:20:45.92,0:20:49.14,EN,,0,0,0,,So we'll say, this is George's real-part procedure. Dialogue: 0,0:20:49.14,0:20:51.16,EN,,0,0,0,,It's the real-part-rectangular procedure, Dialogue: 0,0:20:51.48,0:20:54.06,EN,,0,0,0,,the imaginary-part-rectangular procedure. Dialogue: 0,0:20:55.42,0:20:57.24,EN,,0,0,0,,And then here's the rest of George's package. Dialogue: 0,0:20:59.13,0:21:02.06,EN,,0,0,0,,He'd had magnitude and angle, just renames them magnitude Dialogue: 0,0:21:02.06,0:21:04.16,EN,,0,0,0,,rectangular and angle rectangular. Dialogue: 0,0:21:06.08,0:21:07.96,EN,,0,0,0,,And Martha has to do basically the same thing. Dialogue: 0,0:21:09.86,0:21:16.22,EN,,0,0,0,,Martha previously, when she made a complex number out of a magnitude and angle, Dialogue: 0,0:21:18.14,0:21:19.27,EN,,0,0,0,,she just cons them. Dialogue: 0,0:21:19.27,0:21:20.86,EN,,0,0,0,,Now she attaches the type polar, Dialogue: 0,0:21:23.95,0:21:25.61,EN,,0,0,0,,and she changes the name Dialogue: 0,0:21:25.66,0:21:29.85,EN,,0,0,0,,so her real-part procedure won't conflict in name with George's. Dialogue: 0,0:21:30.71,0:21:32.99,EN,,0,0,0,,It's a real-part-polar,imaginary-part-polar, Dialogue: 0,0:21:34.54,0:21:38.06,EN,,0,0,0,,magnitude polar, and angle polar. Dialogue: 0,0:21:45.00,0:21:46.13,EN,,0,0,0,,Now we have the system. Dialogue: 0,0:21:46.13,0:21:47.92,EN,,0,0,0,,Right there's George and Martha. Dialogue: 0,0:21:49.16,0:21:51.68,EN,,0,0,0,,And now we've got to get some kind of manager to look at these types. Dialogue: 0,0:21:52.83,0:21:56.48,EN,,0,0,0,,How are these things actually going to work now Dialogue: 0,0:21:57.05,0:21:59.40,EN,,0,0,0,,that George and Martha have supplied us with typed data? Dialogue: 0,0:22:00.53,0:22:04.30,EN,,0,0,0,,Well what we have are a bunch of generic selectors. Dialogue: 0,0:22:05.26,0:22:10.63,EN,,0,0,0,,Generic selectors for complex numbers real-part,imaginary-part, magnitude, and angle. Dialogue: 0,0:22:14.14,0:22:15.40,EN,,0,0,0,,Let's look at them more closely. Dialogue: 0,0:22:17.93,0:22:19.00,EN,,0,0,0,,What does a real-part do? Dialogue: 0,0:22:19.31,0:22:22.76,EN,,0,0,0,,If I ask for the real part of a complex number, Dialogue: 0,0:22:24.07,0:22:24.91,EN,,0,0,0,,well I look at it. Dialogue: 0,0:22:25.80,0:22:26.69,EN,,0,0,0,,I look at its type. Dialogue: 0,0:22:26.69,0:22:28.12,EN,,0,0,0,,I say, is it rectangular? Dialogue: 0,0:22:31.02,0:22:35.36,EN,,0,0,0,,If so, I apply George's real part procedure Dialogue: 0,0:22:36.06,0:22:37.92,EN,,0,0,0,,to the contents of that complex number. Dialogue: 0,0:22:41.07,0:22:42.94,EN,,0,0,0,,This is a number that has a type on it. Dialogue: 0,0:22:43.72,0:22:47.66,EN,,0,0,0,,I strip off the type using contents and apply George's procedure. Dialogue: 0,0:22:50.70,0:22:52.86,EN,,0,0,0,,Or is this a polar complex number? Dialogue: 0,0:22:53.95,0:22:54.97,EN,,0,0,0,,If I want the real part, Dialogue: 0,0:22:55.45,0:22:58.78,EN,,0,0,0,,I apply Martha's real-part procedure to the contents of that number. Dialogue: 0,0:22:59.85,0:23:01.15,EN,,0,0,0,,So that's how real part works. Dialogue: 0,0:23:02.26,0:23:05.66,EN,,0,0,0,,And then similarly there's imaginary-part, which is almost the same. Dialogue: 0,0:23:06.51,0:23:09.60,EN,,0,0,0,,Right? It looks at the number and if it's rectangular, uses Dialogue: 0,0:23:09.60,0:23:11.13,EN,,0,0,0,,George's imaginary-part procedure. Dialogue: 0,0:23:11.13,0:23:12.83,EN,,0,0,0,,If it's polar, uses Martha's. Dialogue: 0,0:23:13.38,0:23:17.40,EN,,0,0,0,,And then there's a magnitude and an angle. Dialogue: 0,0:23:19.71,0:23:21.02,EN,,0,0,0,,So there's a system. Dialogue: 0,0:23:23.00,0:23:24.26,EN,,0,0,0,,Has three parts. Dialogue: 0,0:23:24.26,0:23:26.59,EN,,0,0,0,,There's sort of George, and Martha, and the manager. Dialogue: 0,0:23:26.76,0:23:28.97,EN,,0,0,0,,And that's how you get generic operators implemented. Dialogue: 0,0:23:28.97,0:23:32.92,EN,,0,0,0,,Let's look at just a simple example, just to pin it down. Dialogue: 0,0:23:33.50,0:23:35.12,EN,,0,0,0,,But exactly how this is going to work, Dialogue: 0,0:23:36.54,0:23:43.98,EN,,0,0,0,,suppose you're going to be looking at the complex number who's real-part is one, Dialogue: 0,0:23:44.52,0:23:46.09,EN,,0,0,0,,and who's imaginary-part is two. Dialogue: 0,0:23:46.09,0:23:48.44,EN,,0,0,0,,So that would be one plus 2i. Dialogue: 0,0:23:50.31,0:23:52.64,EN,,0,0,0,,What would happen is up here, Dialogue: 0,0:23:55.28,0:23:57.53,EN,,0,0,0,,up here above where the operations have to happen, Dialogue: 0,0:23:57.63,0:24:08.27,EN,,0,0,0,,that number would be represented as a pair of 1 and 2 together with type data. Dialogue: 0,0:24:10.48,0:24:11.39,EN,,0,0,0,,That would be the contents. Dialogue: 0,0:24:11.87,0:24:17.96,EN,,0,0,0,,And the whole data would be that thing with the symbol rectangular added onto that. Dialogue: 0,0:24:18.14,0:24:21.53,EN,,0,0,0,,And that's the way that complex number would exist in the system. Dialogue: 0,0:24:22.33,0:24:24.92,EN,,0,0,0,,When you went to take the real-part, Dialogue: 0,0:24:25.84,0:24:28.89,EN,,0,0,0,,the manager will look at this and say, oh it's one of George's. Dialogue: 0,0:24:30.27,0:24:31.53,EN,,0,0,0,,He'll strip off the type Dialogue: 0,0:24:33.34,0:24:36.91,EN,,0,0,0,,and hand down to George the pair 1, 2. Dialogue: 0,0:24:38.00,0:24:42.27,EN,,0,0,0,,And that's the kind of data that George developed his system to use. Dialogue: 0,0:24:44.36,0:24:45.92,EN,,0,0,0,,So it gets stripped down. Dialogue: 0,0:24:46.52,0:24:49.76,EN,,0,0,0,,Later on, if you ask George to construct a complex number, Dialogue: 0,0:24:51.24,0:24:54.56,EN,,0,0,0,,George would construct some complex number as a pair, Dialogue: 0,0:24:55.07,0:24:58.24,EN,,0,0,0,,and before he passes it back up through the manager would Dialogue: 0,0:24:59.42,0:25:01.13,EN,,0,0,0,,attach the type rectangular. Dialogue: 0,0:25:03.92,0:25:04.65,EN,,0,0,0,,So you see what happens. Dialogue: 0,0:25:04.65,0:25:05.85,EN,,0,0,0,,There's no confusion in this system. Dialogue: 0,0:25:05.85,0:25:10.84,EN,,0,0,0,,It doesn't matter in the least that the pair 1, 2 Dialogue: 0,0:25:13.50,0:25:15.75,EN,,0,0,0,,means something completely different in Martha's world. Dialogue: 0,0:25:15.75,0:25:18.44,EN,,0,0,0,,In Martha's world this pair means the complex number whose Dialogue: 0,0:25:18.44,0:25:20.78,EN,,0,0,0,,magnitude is 1 and whose angle is 2. Dialogue: 0,0:25:21.19,0:25:22.19,EN,,0,0,0,,And there's no confusion, Dialogue: 0,0:25:22.22,0:25:27.25,EN,,0,0,0,,because by the time any pair like this gets handed back through the manager to the Dialogue: 0,0:25:27.25,0:25:29.61,EN,,0,0,0,,main system it's going to have the type polar attached. Dialogue: 0,0:25:31.21,0:25:33.67,EN,,0,0,0,,Whereas this one would have the type rectangular attached. Dialogue: 0,0:25:36.93,0:25:37.90,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:25:40.77,0:25:55.55,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:25:55.69,0:25:57.77,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:25:57.77,0:25:59.76,EN,,0,0,0,,By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:26:05.21,0:26:11.95,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:26:12.84,0:26:16.75,EN,,0,0,0,,Generic Operators Dialogue: 0,0:26:20.21,0:26:24.15,EN,,0,0,0,,We just looked at a strategy for implementing generic operators. Dialogue: 0,0:26:24.15,0:26:31.40,EN,,0,0,0,,That strategy has a name: it's called dispatch on type. Dialogue: 0,0:26:34.31,0:26:39.36,EN,,0,0,0,,And the idea is that you break your system into a bunch of pieces. Dialogue: 0,0:26:39.36,0:26:42.67,EN,,0,0,0,,There's George and Martha, who are making representations, Dialogue: 0,0:26:43.37,0:26:44.38,EN,,0,0,0,,and then there's the manager. Dialogue: 0,0:26:46.12,0:26:48.06,EN,,0,0,0,,Looks at the types on the data Dialogue: 0,0:26:48.51,0:26:50.59,EN,,0,0,0,,and then dispatches them to the right person. Dialogue: 0,0:26:51.99,0:26:56.01,EN,,0,0,0,,Well what criticisms can we make of that as a system organization? Dialogue: 0,0:26:58.15,0:27:00.40,EN,,0,0,0,,Well first of all there was this little, annoying problem Dialogue: 0,0:27:00.40,0:27:03.05,EN,,0,0,0,,that George and Martha had to change the names of their procedures Dialogue: 0,0:27:04.00,0:27:05.95,EN,,0,0,0,,George originally had a real-part procedure, Dialogue: 0,0:27:05.98,0:27:08.28,EN,,0,0,0,,and he had to go name it real-part rectangular Dialogue: 0,0:27:08.30,0:27:10.83,EN,,0,0,0,,so it wouldn't interfere with Martha's real-part procedure, Dialogue: 0,0:27:10.84,0:27:12.76,EN,,0,0,0,,which is now named real-part-polar, Dialogue: 0,0:27:13.64,0:27:16.68,EN,,0,0,0,,so it wouldn't interfere with the manager's real-part procedure, who's now named real-part. Dialogue: 0,0:27:17.31,0:27:18.94,EN,,0,0,0,,That's kind of an annoying problem. Dialogue: 0,0:27:19.46,0:27:21.13,EN,,0,0,0,,But I'm not going to talk about that one now. Dialogue: 0,0:27:21.27,0:27:22.35,EN,,0,0,0,,We'll see later on Dialogue: 0,0:27:23.26,0:27:26.12,EN,,0,0,0,,when we think about the structure of Lisp names and environments Dialogue: 0,0:27:26.12,0:27:30.39,EN,,0,0,0,,that there really are ways to package all those so-called name spaces separately so they Dialogue: 0,0:27:30.39,0:27:31.56,EN,,0,0,0,,don't interfere with each other. Dialogue: 0,0:27:32.50,0:27:34.01,EN,,0,0,0,,Not going to think about that problem now. Dialogue: 0,0:27:35.72,0:27:38.19,EN,,0,0,0,,The problem that I actually want to focus on is Dialogue: 0,0:27:38.36,0:27:43.24,EN,,0,0,0,,what happens when you bring somebody new into the system. Dialogue: 0,0:27:44.51,0:27:45.32,EN,,0,0,0,,What has to happen? Dialogue: 0,0:27:45.32,0:27:46.81,EN,,0,0,0,,Well George and Martha don't care. Dialogue: 0,0:27:47.42,0:27:50.73,EN,,0,0,0,,George is sitting there in his rectangular world, Dialogue: 0,0:27:52.20,0:27:53.84,EN,,0,0,0,,has his procedures and his types. Dialogue: 0,0:27:54.09,0:27:55.74,EN,,0,0,0,,Martha sits in her polar world. Dialogue: 0,0:27:55.93,0:27:57.02,EN,,0,0,0,,She doesn't care. Dialogue: 0,0:27:59.38,0:28:00.54,EN,,0,0,0,,But let's look at the manager. Dialogue: 0,0:28:00.62,0:28:02.84,EN,,0,0,0,,What's the manager have to do? Dialogue: 0,0:28:03.18,0:28:06.20,EN,,0,0,0,,The manager comes through and had these operations. Dialogue: 0,0:28:07.36,0:28:09.04,EN,,0,0,0,,There was a test for rectangular Dialogue: 0,0:28:09.04,0:28:10.14,EN,,0,0,0,,and a test for polar. Dialogue: 0,0:28:10.14,0:28:14.91,EN,,0,0,0,,If Harry comes in with some new kind of complex number, Dialogue: 0,0:28:17.21,0:28:19.96,EN,,0,0,0,,and Harry has a new type, Harry type complex number, the Dialogue: 0,0:28:20.27,0:28:23.28,EN,,0,0,0,,manager has to go in and change all those procedures. Dialogue: 0,0:28:25.24,0:28:26.94,EN,,0,0,0,,So the inflexibility in the system, Dialogue: 0,0:28:26.96,0:28:32.41,EN,,0,0,0,,the place where work has to happen to accommodate change, is in the manager. Dialogue: 0,0:28:34.89,0:28:35.99,EN,,0,0,0,,That's pretty annoying. Dialogue: 0,0:28:35.99,0:28:37.21,EN,,0,0,0,,It's even more annoying Dialogue: 0,0:28:39.05,0:28:41.21,EN,,0,0,0,,It's even more annoying when you realize the manager's not doing anything Dialogue: 0,0:28:42.59,0:28:44.67,EN,,0,0,0,,The manager is just being a paper pusher. Dialogue: 0,0:28:45.84,0:28:51.13,EN,,0,0,0,,Let's look again at these programs. What are they doing? Dialogue: 0,0:28:51.76,0:28:52.72,EN,,0,0,0,,What does real-part do? Dialogue: 0,0:28:52.88,0:28:56.17,EN,,0,0,0,,Real-part says, oh, is it the kind of complex number that Dialogue: 0,0:28:56.17,0:28:57.00,EN,,0,0,0,,George can handle? Dialogue: 0,0:28:57.00,0:28:58.27,EN,,0,0,0,,If so, send it off to George. Dialogue: 0,0:28:59.41,0:29:01.76,EN,,0,0,0,,Is it the kind of complex number that Martha can handle? Dialogue: 0,0:29:01.82,0:29:04.06,EN,,0,0,0,,If so, send it off to Martha. Dialogue: 0,0:29:05.04,0:29:08.72,EN,,0,0,0,,So it's really annoying that the bottleneck in this system, Dialogue: 0,0:29:08.72,0:29:11.66,EN,,0,0,0,,the thing that's preventing flexibility and change, Dialogue: 0,0:29:12.09,0:29:14.36,EN,,0,0,0,,is completely in the bureaucracy. Dialogue: 0,0:29:15.00,0:29:17.02,EN,,0,0,0,,It's not in anybody who's doing any of the work. Dialogue: 0,0:29:19.70,0:29:21.80,EN,,0,0,0,,Not an uncommon situation, unfortunately. Dialogue: 0,0:29:23.18,0:29:24.41,EN,,0,0,0,,See, what's really going on-- Dialogue: 0,0:29:24.48,0:29:26.97,EN,,0,0,0,,abstractly in the system, there's a table. Dialogue: 0,0:29:28.10,0:29:30.08,EN,,0,0,0,,So what's really happening is somewhere there's a table. Dialogue: 0,0:29:30.84,0:29:33.64,EN,,0,0,0,,There're types. Dialogue: 0,0:29:34.40,0:29:38.96,EN,,0,0,0,,There's polar and rectangular. Dialogue: 0,0:29:41.55,0:29:43.02,EN,,0,0,0,,And Harry's may be over here. Dialogue: 0,0:29:44.38,0:29:46.56,EN,,0,0,0,,And there are operators. Dialogue: 0,0:29:48.05,0:29:58.24,EN,,0,0,0,,There's an operator like real-part. Or imaginary-part. Dialogue: 0,0:30:00.01,0:30:04.22,EN,,0,0,0,,Or a magnitude and angle. Dialogue: 0,0:30:05.83,0:30:18.97,EN,,0,0,0,,And sitting in this table are the right procedures. Dialogue: 0,0:30:19.28,0:30:21.99,EN,,0,0,0,,So sitting here for the type polar and real-part is Dialogue: 0,0:30:21.99,0:30:27.56,EN,,0,0,0,,Martha's procedure real-part-polar. Dialogue: 0,0:30:30.57,0:30:36.62,EN,,0,0,0,,And over here in the table is George's procedure real-part-rectangular. Dialogue: 0,0:30:37.74,0:30:43.07,EN,,0,0,0,,And over here would be, say, Martha's procedure magnitude-polar, Dialogue: 0,0:30:44.46,0:30:49.76,EN,,0,0,0,,and George's procedure magnitude-rectangular, right, and so on. Dialogue: 0,0:30:49.76,0:30:51.24,EN,,0,0,0,,The rest of this table's filled in. Dialogue: 0,0:30:52.39,0:30:54.26,EN,,0,0,0,,And that's really what's going on. Dialogue: 0,0:30:57.63,0:31:01.74,EN,,0,0,0,,So in some sense, all the manager is doing Dialogue: 0,0:31:02.11,0:31:04.11,EN,,0,0,0,,is acting as this table. Dialogue: 0,0:31:06.86,0:31:08.70,EN,,0,0,0,,Well how do we fix our system? Dialogue: 0,0:31:11.74,0:31:13.77,EN,,0,0,0,,Well, how do you fix bureaucracies a lot of the time? Dialogue: 0,0:31:13.77,0:31:15.44,EN,,0,0,0,,What you do is you get rid of the manager. Dialogue: 0,0:31:16.01,0:31:19.55,EN,,0,0,0,,We just take the manager and replace him by a computer. Dialogue: 0,0:31:20.17,0:31:21.76,EN,,0,0,0,,We're going to automate him out of existence. Dialogue: 0,0:31:23.32,0:31:26.57,EN,,0,0,0,,Namely, instead of having the manager who basically consults this table, Dialogue: 0,0:31:27.45,0:31:29.32,EN,,0,0,0,,we'll have our system use the table directly. Dialogue: 0,0:31:31.02,0:31:32.11,EN,,0,0,0,,What do I mean by that? Dialogue: 0,0:31:32.11,0:31:36.19,EN,,0,0,0,,Let's assume, again using data abstraction, Dialogue: 0,0:31:37.71,0:31:40.40,EN,,0,0,0,,that we have some kind of data structure that's a table. Dialogue: 0,0:31:40.88,0:31:43.61,EN,,0,0,0,,And we have ways of sticking things in and ways of getting things out. Dialogue: 0,0:31:44.35,0:31:49.04,EN,,0,0,0,,And to be explicit, let me assume that there's an operation called "put." Dialogue: 0,0:31:50.30,0:31:58.32,EN,,0,0,0,,And put is going to take, case two things I'll call "keys." key1 and key2. Dialogue: 0,0:32:00.13,0:32:00.99,EN,,0,0,0,,And a value. Dialogue: 0,0:32:06.20,0:32:11.12,EN,,0,0,0,,And that stores the value in the table under key1 and key2. Dialogue: 0,0:32:11.49,0:32:13.16,EN,,0,0,0,,And then we'll assume there's a thing called "get," Dialogue: 0,0:32:15.23,0:32:18.72,EN,,0,0,0,,such that if later on I say, get me what's in the table Dialogue: 0,0:32:19.40,0:32:22.76,EN,,0,0,0,,stored under key1 and key2, Dialogue: 0,0:32:23.40,0:32:25.39,EN,,0,0,0,,it'll retrieve whatever value was stored there. Dialogue: 0,0:32:26.73,0:32:29.44,EN,,0,0,0,,And let's not worry about how tables are implemented. Dialogue: 0,0:32:30.00,0:32:32.52,EN,,0,0,0,,That's yet another data abstraction, George's problem. Dialogue: 0,0:32:33.06,0:32:34.36,EN,,0,0,0,,And maybe we'll see later-- Dialogue: 0,0:32:34.70,0:32:36.97,EN,,0,0,0,,talk about how you might actually build tables in Lisp. Dialogue: 0,0:32:40.71,0:32:45.50,EN,,0,0,0,,Well given this organization,what did George and Martha have to do? Dialogue: 0,0:32:47.38,0:32:49.07,EN,,0,0,0,,Well when they build their system, Dialogue: 0,0:32:49.13,0:32:51.08,EN,,0,0,0,,they each have the responsibility Dialogue: 0,0:32:51.44,0:32:53.82,EN,,0,0,0,,to set up their appropriate column in the table. Dialogue: 0,0:32:55.21,0:32:57.47,EN,,0,0,0,,So what George does, for example, Dialogue: 0,0:32:59.79,0:33:02.06,EN,,0,0,0,,when he defines his procedures all he has to do Dialogue: 0,0:33:02.27,0:33:07.99,EN,,0,0,0,,is go off and put into the table under the type-rectangular. Dialogue: 0,0:33:09.82,0:33:12.12,EN,,0,0,0,,And the name of the operation is real-part, Dialogue: 0,0:33:13.31,0:33:15.26,EN,,0,0,0,,his procedure real-part-rectangular. Dialogue: 0,0:33:16.25,0:33:17.78,EN,,0,0,0,,So notice what's going into this table. Dialogue: 0,0:33:17.78,0:33:22.10,EN,,0,0,0,,The two keys here are symbols, rectangular and real-part. Dialogue: 0,0:33:22.10,0:33:22.75,EN,,0,0,0,,That's the quote. Dialogue: 0,0:33:24.40,0:33:26.75,EN,,0,0,0,,And what's going into the table is the actual Dialogue: 0,0:33:26.84,0:33:29.21,EN,,0,0,0,,procedure that he wrote, real-part rectangular. Dialogue: 0,0:33:31.85,0:33:34.30,EN,,0,0,0,,And then puts an imaginary part into the table, Dialogue: 0,0:33:34.59,0:33:37.80,EN,,0,0,0,,filed under the keys rectangular and imaginary-part, Dialogue: 0,0:33:38.62,0:33:42.88,EN,,0,0,0,,and magnitude under the keys rectangular magnitude, Dialogue: 0,0:33:43.61,0:33:45.20,EN,,0,0,0,,angle under rectangular-angle. Dialogue: 0,0:33:47.04,0:33:50.84,EN,,0,0,0,,Okay? So that's what George has to do to be part of this system. Dialogue: 0,0:33:54.42,0:33:58.86,EN,,0,0,0,,Martha similarly sets up the column and the table under polar. Dialogue: 0,0:33:59.43,0:34:00.65,EN,,0,0,0,,Polar and real-part. Dialogue: 0,0:34:01.69,0:34:03.58,EN,,0,0,0,,Right? Is the procedure real-part-polar? Dialogue: 0,0:34:04.34,0:34:07.29,EN,,0,0,0,,And imaginary-part, and magnitude, and angle. Dialogue: 0,0:34:08.91,0:34:11.40,EN,,0,0,0,,So this is what Martha has to do to be part of the system. Dialogue: 0,0:34:11.40,0:34:13.55,EN,,0,0,0,,Everyone who makes a representation has the Dialogue: 0,0:34:13.55,0:34:17.63,EN,,0,0,0,,responsibility for setting up a column in the table. Dialogue: 0,0:34:17.76,0:34:19.90,EN,,0,0,0,,And what does Harry do when Harry comes in with his Dialogue: 0,0:34:19.90,0:34:21.80,EN,,0,0,0,,brilliant idea for implementing complex numbers? Dialogue: 0,0:34:21.80,0:34:23.96,EN,,0,0,0,,Well he makes whatever procedure he wants and Dialogue: 0,0:34:24.04,0:34:26.52,EN,,0,0,0,,builds a new column in this table. Dialogue: 0,0:34:28.55,0:34:30.04,EN,,0,0,0,,OK, well what happened to the manager? Dialogue: 0,0:34:31.33,0:34:34.61,EN,,0,0,0,,The manager has been automated out of existence and is Dialogue: 0,0:34:34.61,0:34:37.11,EN,,0,0,0,,replaced by a procedure called operate. Dialogue: 0,0:34:37.11,0:34:39.55,EN,,0,0,0,,And this is the key procedure in the whole system. Dialogue: 0,0:34:40.38,0:34:45.92,EN,,0,0,0,,Let's say define operate. Dialogue: 0,0:34:51.06,0:34:56.09,EN,,0,0,0,,Operate is going to take an operation that you want to do, Dialogue: 0,0:34:57.75,0:34:58.88,EN,,0,0,0,,the name of an operation, Dialogue: 0,0:34:59.20,0:35:03.28,EN,,0,0,0,,and an object that you would like to apply that operation to. Dialogue: 0,0:35:04.21,0:35:09.76,EN,,0,0,0,,So for example, the real-part of some particular complex number, what does it do? Dialogue: 0,0:35:09.95,0:35:11.90,EN,,0,0,0,,Well the first thing it does, it looks in the table. Dialogue: 0,0:35:12.64,0:35:13.87,EN,,0,0,0,,Goes into the table Dialogue: 0,0:35:14.80,0:35:22.56,EN,,0,0,0,,and tries to find a procedure that's stored in the table. Dialogue: 0,0:35:23.15,0:35:24.80,EN,,0,0,0,,So it gets from the table, Dialogue: 0,0:35:25.50,0:35:33.92,EN,,0,0,0,,using as keys the type of the object and the operator, Dialogue: 0,0:35:38.92,0:35:40.14,EN,,0,0,0,,but looks on the table and sees Dialogue: 0,0:35:40.38,0:35:42.72,EN,,0,0,0,,what's stored under the type of the object and the operator Dialogue: 0,0:35:42.89,0:35:44.35,EN,,0,0,0,,sees if anything's stored. Dialogue: 0,0:35:44.44,0:35:45.93,EN,,0,0,0,,Let's assume that get is implemented. Dialogue: 0,0:35:45.93,0:35:47.72,EN,,0,0,0,,So if nothing is stored there, Dialogue: 0,0:35:48.11,0:35:51.79,EN,,0,0,0,,it'll return a nil, return the empty list. Dialogue: 0,0:35:52.67,0:35:55.39,EN,,0,0,0,,So it says, if there's actually something stored there, Dialogue: 0,0:35:56.62,0:36:00.43,EN,,0,0,0,,if the procedure here is not no, Dialogue: 0,0:36:03.15,0:36:07.12,EN,,0,0,0,,then it'll take the procedure that it found in the table Dialogue: 0,0:36:09.79,0:36:15.00,EN,,0,0,0,,procedure that it found in the table and apply it to the contents of the object. Dialogue: 0,0:36:18.25,0:36:20.40,EN,,0,0,0,,And otherwise if there was nothing stored there, Dialogue: 0,0:36:20.67,0:36:22.51,EN,,0,0,0,,it'll-- well we can decide. Dialogue: 0,0:36:22.81,0:36:27.12,EN,,0,0,0,,In this case let's have it put out an error message saying, undefined operator. Dialogue: 0,0:36:28.48,0:36:30.24,EN,,0,0,0,,No operator for this type. Dialogue: 0,0:36:33.07,0:36:34.72,EN,,0,0,0,,Or some appropriate error message. Dialogue: 0,0:36:39.07,0:36:39.48,EN,,0,0,0,,OK? Dialogue: 0,0:36:39.72,0:36:41.04,EN,,0,0,0,,And that replaces the manager. Dialogue: 0,0:36:41.89,0:36:42.91,EN,,0,0,0,,How do we really use it? Dialogue: 0,0:36:43.96,0:36:49.80,EN,,0,0,0,,Well what we say is we'll go off and define our generic selectors using operate. Dialogue: 0,0:36:50.04,0:36:56.75,EN,,0,0,0,,We'll say that the real-part of an object is found by Dialogue: 0,0:36:57.14,0:37:05.66,EN,,0,0,0,,operating on the object with the name of the operation being real-part. Dialogue: 0,0:37:08.07,0:37:12.22,EN,,0,0,0,,And then similarly, imaginary-part is operate using the name imaginary-part Dialogue: 0,0:37:12.22,0:37:13.98,EN,,0,0,0,,and magnitude and angle. Dialogue: 0,0:37:15.36,0:37:17.43,EN,,0,0,0,,That's our implementation. Dialogue: 0,0:37:17.43,0:37:20.48,EN,,0,0,0,,That plus the type plus the operate procedure. Dialogue: 0,0:37:21.33,0:37:24.00,EN,,0,0,0,,And the table effectively replaces what the manager used to do. Dialogue: 0,0:37:24.06,0:37:27.69,EN,,0,0,0,,Let's just go through that slowly to show you what's going on. Dialogue: 0,0:37:27.90,0:37:33.00,EN,,0,0,0,,Suppose I have one of Martha's complex numbers. Dialogue: 0,0:37:33.53,0:37:38.80,EN,,0,0,0,,It's got magnitude 1 and angle 2. Dialogue: 0,0:37:39.10,0:37:40.22,EN,,0,0,0,,And it's one of Martha's. Dialogue: 0,0:37:40.22,0:37:45.45,EN,,0,0,0,,So it's labeled here, polar. Dialogue: 0,0:37:47.24,0:37:48.00,EN,,0,0,0,,Let's call that z. Dialogue: 0,0:37:48.00,0:37:48.91,EN,,0,0,0,,Suppose that's z. Dialogue: 0,0:37:51.77,0:37:54.46,EN,,0,0,0,,And suppose with this implementation someone comes up Dialogue: 0,0:37:54.80,0:37:57.92,EN,,0,0,0,,asks for the real-part of z. Dialogue: 0,0:38:04.87,0:38:07.96,EN,,0,0,0,,Well real-part now is defined in terms of operate. Dialogue: 0,0:38:09.16,0:38:10.57,EN,,0,0,0,,So that's equivalent to saying Dialogue: 0,0:38:12.09,0:38:24.81,EN,,0,0,0,,operate with the name of the operator being real-part, the symbol real-part on z. Dialogue: 0,0:38:27.06,0:38:28.09,EN,,0,0,0,,And now operate comes. Dialogue: 0,0:38:28.09,0:38:29.24,EN,,0,0,0,,It's going to look in the table, Dialogue: 0,0:38:31.04,0:38:34.36,EN,,0,0,0,,and it's going to try and find something stored under-- Dialogue: 0,0:38:39.00,0:38:46.22,EN,,0,0,0,,the operation is going to apply by looking in the table under the type of the object. Dialogue: 0,0:38:46.72,0:38:48.22,EN,,0,0,0,,And the type of z is polar. Dialogue: 0,0:38:48.79,0:38:51.37,EN,,0,0,0,,So it's going to look and say, can I get using polar? Dialogue: 0,0:38:52.99,0:38:58.57,EN,,0,0,0,,And the operation name, which was real-part. Dialogue: 0,0:39:05.96,0:39:13.63,EN,,0,0,0,,It's going to look in there and apply that to the contents of z. Dialogue: 0,0:39:14.83,0:39:17.13,EN,,0,0,0,,What's that is if everything was set up correctly, Dialogue: 0,0:39:17.74,0:39:21.70,EN,,0,0,0,,this thing is the procedure that Martha put there. Dialogue: 0,0:39:21.70,0:39:22.95,EN,,0,0,0,,This is real-part-polar. Dialogue: 0,0:39:31.05,0:39:35.13,EN,,0,0,0,,And this is z without its type. Dialogue: 0,0:39:35.44,0:39:38.94,EN,,0,0,0,,The thing that Martha originally designed those procedures to work on, Dialogue: 0,0:39:39.40,0:39:40.43,EN,,0,0,0,,which is 1, 2. Dialogue: 0,0:39:43.71,0:39:45.87,EN,,0,0,0,,And so operate sort of does uniformly Dialogue: 0,0:39:46.46,0:39:48.89,EN,,0,0,0,,what the manager used to do sort of all over the system. Dialogue: 0,0:39:49.45,0:39:52.59,EN,,0,0,0,,It finds the right thing, looks in the table, strips off the type, Dialogue: 0,0:39:53.58,0:39:57.52,EN,,0,0,0,,and passes it down into the person who handles it. Dialogue: 0,0:39:58.88,0:40:05.48,EN,,0,0,0,,This is another, and, you can see, more flexible for most purposes, Dialogue: 0,0:40:06.22,0:40:08.04,EN,,0,0,0,,way of implementing generic operators. Dialogue: 0,0:40:08.08,0:40:15.69,EN,,0,0,0,,And it's called data-directed programming. Dialogue: 0,0:40:20.35,0:40:21.96,EN,,0,0,0,,And the idea of that is Dialogue: 0,0:40:23.42,0:40:25.55,EN,,0,0,0,,And the idea of that is in some sense the data objects themselves, Dialogue: 0,0:40:26.04,0:40:28.35,EN,,0,0,0,,those little complex numbers that are floating around the system, Dialogue: 0,0:40:28.73,0:40:33.16,EN,,0,0,0,,are carrying with them the information about how you should operate on them. Dialogue: 0,0:40:35.74,0:40:36.78,EN,,0,0,0,,Let's break for questions. Dialogue: 0,0:40:41.00,0:40:41.24,EN,,0,0,0,,Yes. Dialogue: 0,0:40:41.24,0:40:43.39,EN,,0,0,0,,AUDIENCE: What do you have stored in that data object? Dialogue: 0,0:40:43.39,0:40:47.10,EN,,0,0,0,,You have the data itself, you have its type, Dialogue: 0,0:40:47.10,0:40:49.60,EN,,0,0,0,,the operations for that type? Dialogue: 0,0:40:49.69,0:40:53.08,EN,,0,0,0,,Or where are the operations that you found? Dialogue: 0,0:40:53.60,0:40:54.17,EN,,0,0,0,,PROFESSOR: OK, let me-- Dialogue: 0,0:40:54.98,0:40:56.50,EN,,0,0,0,,yeah, that's a good question. Dialogue: 0,0:40:56.50,0:41:00.46,EN,,0,0,0,,Because it raises other possibilities of how you might do it. Dialogue: 0,0:41:00.75,0:41:02.48,EN,,0,0,0,,And of course there are a lot of possibilities. Dialogue: 0,0:41:04.20,0:41:06.14,EN,,0,0,0,,In this particular implementation, Dialogue: 0,0:41:06.24,0:41:09.72,EN,,0,0,0,,what's sitting in this data object, for example, Dialogue: 0,0:41:10.44,0:41:13.45,EN,,0,0,0,,is the data itself-- which in this case is a pair of 1 and 2-- Dialogue: 0,0:41:14.98,0:41:16.55,EN,,0,0,0,,and also a symbol. Dialogue: 0,0:41:16.55,0:41:19.07,EN,,0,0,0,,This is the symbol, the word P-O-L-A-R, Dialogue: 0,0:41:20.60,0:41:22.33,EN,,0,0,0,,And that what's sitting in this data object. Dialogue: 0,0:41:24.24,0:41:26.69,EN,,0,0,0,,OK, where are the operations themselves? Dialogue: 0,0:41:26.69,0:41:29.00,EN,,0,0,0,,The operations are sitting in the table. Dialogue: 0,0:41:29.85,0:41:31.07,EN,,0,0,0,,So in this table, Dialogue: 0,0:41:32.30,0:41:36.46,EN,,0,0,0,,the rows and columns of the table are labeled by symbols. Dialogue: 0,0:41:38.23,0:41:40.08,EN,,0,0,0,,So when I store something in this table, Dialogue: 0,0:41:40.09,0:41:47.02,EN,,0,0,0,,the key might be the symbol polar and the symbol magnitude. Dialogue: 0,0:41:48.24,0:41:51.31,EN,,0,0,0,,And I think by writing it this way I've been very confusing. Dialogue: 0,0:41:51.31,0:41:52.70,EN,,0,0,0,,Because what's really sitting here isn't-- Dialogue: 0,0:41:53.16,0:41:54.57,EN,,0,0,0,,when I wrote magnitude polar, Dialogue: 0,0:41:57.04,0:41:59.23,EN,,0,0,0,,what I mean is the procedure magnitude polar. Dialogue: 0,0:41:59.85,0:42:01.85,EN,,0,0,0,,And probably what I really should have written-- Dialogue: 0,0:42:02.58,0:42:04.20,EN,,0,0,0,,except it's too small for me to write Dialogue: 0,0:42:04.20,0:42:05.07,EN,,0,0,0,,in this little space-- Dialogue: 0,0:42:05.58,0:42:08.92,EN,,0,0,0,,is something like lambda of z, Dialogue: 0,0:42:10.60,0:42:12.75,EN,,0,0,0,,the thing that Martha wrote to implement. Dialogue: 0,0:42:14.71,0:42:15.72,EN,,0,0,0,,And then you can see from that, Dialogue: 0,0:42:15.74,0:42:17.44,EN,,0,0,0,,there's another way that I alluded to Dialogue: 0,0:42:17.71,0:42:19.82,EN,,0,0,0,,of solving this name conflict problem Dialogue: 0,0:42:20.04,0:42:23.15,EN,,0,0,0,,which is that George and Martha never have to name their procedures at all. Dialogue: 0,0:42:23.15,0:42:25.37,EN,,0,0,0,,They can just stick the lambda, the lambda... Dialogue: 0,0:42:25.39,0:42:28.12,EN,,0,0,0,,the anonymous things generated by lambda directly into the table. Dialogue: 0,0:42:28.66,0:42:31.76,EN,,0,0,0,,There's also another thing that your question raises, Dialogue: 0,0:42:32.35,0:42:34.06,EN,,0,0,0,,is the possibility that maybe Dialogue: 0,0:42:34.83,0:42:37.92,EN,,0,0,0,,what I would like somehow is to store in this data object Dialogue: 0,0:42:37.95,0:42:39.48,EN,,0,0,0,,not the symbol P-O-L-A-R but Dialogue: 0,0:42:39.93,0:42:42.35,EN,,0,0,0,,maybe actually all the operations themselves. Dialogue: 0,0:42:43.90,0:42:45.63,EN,,0,0,0,,And that's another way to organize the system, Dialogue: 0,0:42:45.66,0:42:46.60,EN,,0,0,0,,called message passing. Dialogue: 0,0:42:48.65,0:42:49.92,EN,,0,0,0,,So there are a lot of ways you can do it. Dialogue: 0,0:42:54.64,0:42:58.04,EN,,0,0,0,,AUDIENCE: Therefore if Martha and George had used the same Dialogue: 0,0:42:58.04,0:43:01.23,EN,,0,0,0,,procedure names, it would be OK because it wouldn't look Dialogue: 0,0:43:01.23,0:43:02.56,EN,,0,0,0,,it wouldn't look into it Dialogue: 0,0:43:02.56,0:43:04.68,EN,,0,0,0,,PROFESSOR: That's right.That's right. Dialogue: 0,0:43:04.80,0:43:07.85,EN,,0,0,0,,See, they wouldn't even have to name their procedures at all. Dialogue: 0,0:43:08.04,0:43:09.36,EN,,0,0,0,,What George and Martha could writ --, Dialogue: 0,0:43:09.50,0:43:10.62,EN,,0,0,0,,what George could have written Dialogue: 0,0:43:10.83,0:43:15.28,EN,,0,0,0,,instead of saying put in the table under rectangular- and real-part, Dialogue: 0,0:43:16.22,0:43:17.98,EN,,0,0,0,,the procedure real-part rectangular, Dialogue: 0,0:43:18.03,0:43:21.15,EN,,0,0,0,,George could have written put under rectangular real-part, Dialogue: 0,0:43:21.24,0:43:23.69,EN,,0,0,0,,lambda of z, such and such, such and such, Dialogue: 0,0:43:24.54,0:43:26.84,EN,,0,0,0,,And the system would work completely the same. Dialogue: 0,0:43:27.33,0:43:29.24,EN,,0,0,0,,AUDIENCE: My question is, Martha could put Dialogue: 0,0:43:29.84,0:43:33.60,EN,,0,0,0,,could have put key1 key2 real-part, Dialogue: 0,0:43:33.95,0:43:37.64,EN,,0,0,0,,and George could have put key1 key2 real-part, Dialogue: 0,0:43:37.96,0:43:39.60,EN,,0,0,0,,and as long as they defined them differently Dialogue: 0,0:43:39.80,0:43:41.26,EN,,0,0,0,,they wouldn't have had any conflicts, right? Dialogue: 0,0:43:41.29,0:43:43.80,EN,,0,0,0,,PROFESSOR: Yes, that would all be OK except for the fact Dialogue: 0,0:43:44.97,0:43:47.13,EN,,0,0,0,,that if you imagine George and Martha typing at the same Dialogue: 0,0:43:47.13,0:43:49.20,EN,,0,0,0,,console with the same meanings for all their names, Dialogue: 0,0:43:49.82,0:43:51.23,EN,,0,0,0,,and it would get confused by real-part, Dialogue: 0,0:43:51.24,0:43:52.80,EN,,0,0,0,,but there are ways to arrange that, too. Dialogue: 0,0:43:52.80,0:43:54.80,EN,,0,0,0,,And in principle you're absolutely right. Dialogue: 0,0:43:54.98,0:43:56.29,EN,,0,0,0,,If their names didn't conflict-- Dialogue: 0,0:43:56.29,0:43:58.19,EN,,0,0,0,,it's the objects that go in the table, not the names. Dialogue: 0,0:44:08.20,0:44:09.05,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:44:12.91,0:44:20.48,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:44:20.96,0:44:23.29,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:44:23.45,0:44:25.29,EN,,0,0,0,,By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:44:57.42,0:45:05.07,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:45:05.47,0:45:09.24,EN,,0,0,0,,Generic Operators Dialogue: 0,0:45:12.88,0:45:16.88,EN,,0,0,0,,RPOFESSOR: All right, well we just looked at data-directed programming Dialogue: 0,0:45:17.68,0:45:22.84,EN,,0,0,0,,as a way of implementing a system that does arithmetic on complex numbers. Dialogue: 0,0:45:27.60,0:45:32.48,EN,,0,0,0,,So I had these operations in it called plus C and minus C, Dialogue: 0,0:45:32.88,0:45:37.24,EN,,0,0,0,,and multiply, and divide,and maybe some others. Dialogue: 0,0:45:38.23,0:45:45.72,EN,,0,0,0,,And that sat on top of-- and this is the key point-- Dialogue: 0,0:45:45.74,0:45:49.60,EN,,0,0,0,,sat on top of two different representations. Dialogue: 0,0:45:50.34,0:45:55.44,EN,,0,0,0,,A rectangular package here, and a polar package. Dialogue: 0,0:45:58.14,0:45:59.15,EN,,0,0,0,,And maybe some more. Dialogue: 0,0:45:59.15,0:46:02.80,EN,,0,0,0,,And we saw that the whole idea is that maybe some more are now very easy to add. Dialogue: 0,0:46:04.67,0:46:08.35,EN,,0,0,0,,But that doesn't really show the power of this methodology. Dialogue: 0,0:46:08.90,0:46:10.15,EN,,0,0,0,,Shows you what's going on. Dialogue: 0,0:46:10.15,0:46:12.33,EN,,0,0,0,,The power of the methodology only becomes apparent Dialogue: 0,0:46:12.94,0:46:15.79,EN,,0,0,0,,when you start embedding this in some more complex system. Dialogue: 0,0:46:16.17,0:46:17.74,EN,,0,0,0,,So let... What I'm going to do now Dialogue: 0,0:46:17.87,0:46:20.01,EN,,0,0,0,,is embed this in some more complex system. Dialogue: 0,0:46:20.25,0:46:25.28,EN,,0,0,0,,Let's assume that what we really have is a general kind of arithmetic system. Dialogue: 0,0:46:25.28,0:46:27.24,EN,,0,0,0,,So called generic arithmetic system. Dialogue: 0,0:46:27.24,0:46:28.54,EN,,0,0,0,,And at the top level here, Dialogue: 0,0:46:30.76,0:46:35.92,EN,,0,0,0,,somebody can say add twothings, or subtract two things, Dialogue: 0,0:46:37.45,0:46:41.05,EN,,0,0,0,,or multiply two things, or divide two things. Dialogue: 0,0:46:44.14,0:46:46.52,EN,,0,0,0,,And underneath that there's an abstraction barrier. Dialogue: 0,0:46:47.93,0:46:49.15,EN,,0,0,0,,And underneath this barrier, Dialogue: 0,0:46:49.50,0:46:52.48,EN,,0,0,0,,is, say, a complex arithmetic package. Dialogue: 0,0:46:53.02,0:46:54.96,EN,,0,0,0,,And you can say, add two complex numbers. Dialogue: 0,0:46:55.04,0:46:58.83,EN,,0,0,0,,Or you might also have--remember we did a rational number package Dialogue: 0,0:46:58.88,0:46:59.93,EN,,0,0,0,,you might have that sitting there. Dialogue: 0,0:47:00.19,0:47:01.72,EN,,0,0,0,,And there might be a rational thing. Dialogue: 0,0:47:04.76,0:47:06.22,EN,,0,0,0,,And the rational number package, Dialogue: 0,0:47:07.16,0:47:14.75,EN,,0,0,0,,well, has the things we implemented. Plus rat, and times rat, and so on. Dialogue: 0,0:47:15.39,0:47:17.01,EN,,0,0,0,,Or you might have ordinary Lisp numbers. Dialogue: 0,0:47:17.01,0:47:18.99,EN,,0,0,0,,You might say add three and four. Dialogue: 0,0:47:19.42,0:47:20.94,EN,,0,0,0,,So we might have ordinary numbers, Dialogue: 0,0:47:28.28,0:47:34.67,EN,,0,0,0,,in which case we have the Lisp supplied plus, and minus, and times, and slash. Dialogue: 0,0:47:36.67,0:47:39.12,EN,,0,0,0,,OK, so we might imagine this complex number system Dialogue: 0,0:47:39.44,0:47:44.44,EN,,0,0,0,,sitting in a more complicated generic operator structure at the next level up. Dialogue: 0,0:47:47.73,0:47:48.73,EN,,0,0,0,,Well how can we make that? Dialogue: 0,0:47:49.05,0:47:52.32,EN,,0,0,0,,We already have the idea, we're just going to do it again. Dialogue: 0,0:47:52.78,0:47:54.72,EN,,0,0,0,,We've implemented a rational number package. Dialogue: 0,0:47:54.72,0:47:56.89,EN,,0,0,0,,Let's look at how it has to be changed. Dialogue: 0,0:48:01.48,0:48:03.40,EN,,0,0,0,,In fact, at this level it doesn't have to be changed at all. Dialogue: 0,0:48:03.73,0:48:05.88,EN,,0,0,0,,This is exactly the code that we wrote last time. Dialogue: 0,0:48:07.18,0:48:08.97,EN,,0,0,0,,To add two rational numbers, Dialogue: 0,0:48:09.85,0:48:10.91,EN,,0,0,0,,remember there was this formula. Dialogue: 0,0:48:11.14,0:48:13.37,EN,,0,0,0,,You make a rational number whose numerator-- Dialogue: 0,0:48:13.98,0:48:17.56,EN,,0,0,0,,is the numerator of the first times the denominator of the second Dialogue: 0,0:48:17.93,0:48:21.52,EN,,0,0,0,,plus the denominator of the first times the numerator of the second. Dialogue: 0,0:48:21.52,0:48:23.79,EN,,0,0,0,,And who's denominator is the product of the denominators. Dialogue: 0,0:48:25.76,0:48:29.07,EN,,0,0,0,,And minus rat, and star rat, and slash rat. Dialogue: 0,0:48:30.36,0:48:35.12,EN,,0,0,0,,And this is exactly the rational number package that we made before. Dialogue: 0,0:48:36.31,0:48:38.89,EN,,0,0,0,,We're ignoring the GCD problem,but let's not worry about that. Dialogue: 0,0:48:39.08,0:48:42.59,EN,,0,0,0,,How do we install... As implementers of this rational number package, Dialogue: 0,0:48:42.80,0:48:45.10,EN,,0,0,0,,how do we install it in the generic arithmetic system? Dialogue: 0,0:48:45.57,0:48:46.22,EN,,0,0,0,,Well that's easy. Dialogue: 0,0:48:47.29,0:48:51.56,EN,,0,0,0,,Go off... There's only one thing we have to do differently. Dialogue: 0,0:48:51.84,0:48:55.71,EN,,0,0,0,,Whereas previously we said that to make a rational number Dialogue: 0,0:48:56.27,0:48:59.98,EN,,0,0,0,,you built a pair of the numerator and denominator, Dialogue: 0,0:49:00.96,0:49:03.20,EN,,0,0,0,,here we'll not only build the pair, but we'll sign it. Dialogue: 0,0:49:03.30,0:49:04.56,EN,,0,0,0,,We'll attach the type rational. Dialogue: 0,0:49:06.36,0:49:08.09,EN,,0,0,0,,That's the only thing we have to do different, Dialogue: 0,0:49:08.56,0:49:10.09,EN,,0,0,0,,make it a typed data object. Dialogue: 0,0:49:12.38,0:49:14.08,EN,,0,0,0,,And now we'll stick our operations in the table. Dialogue: 0,0:49:14.36,0:49:18.20,EN,,0,0,0,,We'll put under the symbol rational and the operation add Dialogue: 0,0:49:18.92,0:49:20.25,EN,,0,0,0,,our procedure -- +rat. Dialogue: 0,0:49:21.82,0:49:23.24,EN,,0,0,0,,And, again, note this is a symbol. Dialogue: 0,0:49:23.74,0:49:23.93,EN,,0,0,0,,Right? Dialogue: 0,0:49:24.03,0:49:25.29,EN,,0,0,0,,Quote, and quote, Dialogue: 0,0:49:25.31,0:49:28.01,EN,,0,0,0,,but the actual thing we're putting in the table is the procedure. Dialogue: 0,0:49:29.82,0:49:31.77,EN,,0,0,0,,And for how to subtract, Dialogue: 0,0:49:31.79,0:49:36.81,EN,,0,0,0,,well you subtract rationals with minus rat. Dialogue: 0,0:49:38.27,0:49:40.24,EN,,0,0,0,,And multiply, and divide. Dialogue: 0,0:49:41.09,0:49:43.64,EN,,0,0,0,,And that is exactly and precisely what we have to do Dialogue: 0,0:49:44.14,0:49:46.97,EN,,0,0,0,,to fit inside this generic arithmetic system. Dialogue: 0,0:49:48.51,0:49:49.88,EN,,0,0,0,,Well how does the whole thing work? Dialogue: 0,0:49:51.56,0:49:58.40,EN,,0,0,0,,See, what we want to do is have some generic operators. Dialogue: 0,0:49:59.34,0:50:02.80,EN,,0,0,0,,Right? Have add and sub and mul and div be generic operators. Dialogue: 0,0:50:03.99,0:50:17.36,EN,,0,0,0,,So we're going to define add and say, to add x and y, Dialogue: 0,0:50:18.62,0:50:22.12,EN,,0,0,0,,that will be operate-- Dialogue: 0,0:50:26.08,0:50:27.49,EN,,0,0,0,,we were going to call it operate-2. Dialogue: 0,0:50:27.49,0:50:30.78,EN,,0,0,0,,This is our operator procedure, but set up for two arguments Dialogue: 0,0:50:31.60,0:50:35.84,EN,,0,0,0,,using add on x and y. Dialogue: 0,0:50:37.60,0:50:39.76,EN,,0,0,0,,And so this is the analog to operate. Dialogue: 0,0:50:40.42,0:50:41.68,EN,,0,0,0,,Let's look at the code for a second. Dialogue: 0,0:50:41.68,0:50:42.93,EN,,0,0,0,,It's almost like operate. Dialogue: 0,0:50:45.79,0:50:52.49,EN,,0,0,0,,Right? To operate with some operator on an argument1 and an argument2 Dialogue: 0,0:50:55.04,0:50:56.65,EN,,0,0,0,,well the first thing we're going to do is check Dialogue: 0,0:50:56.83,0:51:00.73,EN,,0,0,0,,and see if the two arguments have the same type. Dialogue: 0,0:51:01.90,0:51:02.96,EN,,0,0,0,,So we'll say, Dialogue: 0,0:51:02.99,0:51:07.77,EN,,0,0,0,,is the type of the first argument the same as the type of the second argument? Dialogue: 0,0:51:10.35,0:51:13.36,EN,,0,0,0,,And if they're not, if they're not Dialogue: 0,0:51:13.58,0:51:15.63,EN,,0,0,0,,we'll go off and complain, and say, that's an error. Dialogue: 0,0:51:15.67,0:51:16.67,EN,,0,0,0,,We don't know how to do that. Dialogue: 0,0:51:19.14,0:51:20.49,EN,,0,0,0,,If they do have the same type, Dialogue: 0,0:51:20.51,0:51:22.08,EN,,0,0,0,,we'll do exactly what we did before. Dialogue: 0,0:51:22.08,0:51:26.46,EN,,0,0,0,,We'll go look and filed under the type of the argument-- Dialogue: 0,0:51:26.76,0:51:29.61,EN,,0,0,0,,arg 1 and arg 2 have the same type, so it doesn't matter. Dialogue: 0,0:51:30.42,0:51:32.59,EN,,0,0,0,,So we'll look in the table, find the procedure. Dialogue: 0,0:51:33.64,0:51:35.87,EN,,0,0,0,,If there is a procedure there, Dialogue: 0,0:51:37.53,0:51:41.74,EN,,0,0,0,,then we'll apply it to the contents of the arg1 and the contents of arg2. Dialogue: 0,0:51:43.03,0:51:44.76,EN,,0,0,0,,And otherwise we'll say, error. Dialogue: 0,0:51:44.76,0:51:45.72,EN,,0,0,0,,Undefined operator. Dialogue: 0,0:51:46.89,0:51:48.16,EN,,0,0,0,,And so there's operate-2. Dialogue: 0,0:51:51.72,0:51:54.03,EN,,0,0,0,,And that's all we have to do. Dialogue: 0,0:51:55.16,0:51:57.45,EN,,0,0,0,,We just built the complex number package before. Dialogue: 0,0:51:57.64,0:52:01.00,EN,,0,0,0,,How do we embed that complex number package in this generic system? Dialogue: 0,0:52:02.14,0:52:02.91,EN,,0,0,0,,Almost the same. Dialogue: 0,0:52:06.41,0:52:08.59,EN,,0,0,0,,We make a procedure called make-complex Dialogue: 0,0:52:09.95,0:52:12.81,EN,,0,0,0,,that takes whatever George and Martha hand to us Dialogue: 0,0:52:13.64,0:52:15.00,EN,,0,0,0,,and add the type complex. Dialogue: 0,0:52:18.17,0:52:23.87,EN,,0,0,0,,And then we say, to add complex numbers, plus complex, Dialogue: 0,0:52:25.84,0:52:28.78,EN,,0,0,0,,we use our internal procedure, plus c, Dialogue: 0,0:52:30.78,0:52:32.24,EN,,0,0,0,,and attach a type, Dialogue: 0,0:52:32.24,0:52:33.42,EN,,0,0,0,,make that a complex number. Dialogue: 0,0:52:37.68,0:52:42.52,EN,,0,0,0,,So our original package had names plus c and minus c Dialogue: 0,0:52:42.68,0:52:44.75,EN,,0,0,0,,that we're using to communicate with George and Martha. Dialogue: 0,0:52:45.25,0:52:47.39,EN,,0,0,0,,And then to communicate with the outside world, Dialogue: 0,0:52:47.40,0:52:53.04,EN,,0,0,0,,we have a thing called plus-complex and minus-complex. Dialogue: 0,0:52:55.92,0:52:56.53,EN,,0,0,0,,And so on. Dialogue: 0,0:52:56.53,0:52:59.98,EN,,0,0,0,,And the only difference is that these return values that are typed Dialogue: 0,0:53:01.12,0:53:02.41,EN,,0,0,0,,So they can be looked at up here. Dialogue: 0,0:53:02.85,0:53:05.02,EN,,0,0,0,,And these are internal operations. Dialogue: 0,0:53:09.25,0:53:10.68,EN,,0,0,0,,Let's go look at that slide again. Dialogue: 0,0:53:10.68,0:53:13.04,EN,,0,0,0,,There's one more thing we do. Dialogue: 0,0:53:13.74,0:53:15.61,EN,,0,0,0,,After defining plus-complex, Dialogue: 0,0:53:15.68,0:53:20.52,EN,,0,0,0,,we put under the type complex and the symbol add, Dialogue: 0,0:53:21.31,0:53:22.75,EN,,0,0,0,,that procedure plus complex. Dialogue: 0,0:53:23.20,0:53:26.75,EN,,0,0,0,,And then similarly for subtracting complex numbers, Dialogue: 0,0:53:27.13,0:53:29.13,EN,,0,0,0,,and multiplying them, and dividing them. Dialogue: 0,0:53:31.70,0:53:33.48,EN,,0,0,0,,OK, how do we install ordinary numbers? Dialogue: 0,0:53:35.25,0:53:36.12,EN,,0,0,0,,Exactly the same way. Dialogue: 0,0:53:38.16,0:53:41.36,EN,,0,0,0,,Come off and say, well we'll make a thing called make-number Dialogue: 0,0:53:44.34,0:53:48.11,EN,,0,0,0,,Make-number takes a number and attaches a type, Dialogue: 0,0:53:48.14,0:53:49.29,EN,,0,0,0,,which is the symbol number. Dialogue: 0,0:53:50.26,0:53:52.11,EN,,0,0,0,,We build a procedure called plus-number, Dialogue: 0,0:53:52.92,0:53:58.75,EN,,0,0,0,,which is simply, add the two things using the ordinary addition, Dialogue: 0,0:53:58.92,0:54:00.78,EN,,0,0,0,,because in this case we're talking about ordinary numbers, Dialogue: 0,0:54:01.31,0:54:03.10,EN,,0,0,0,,and attach a type to it and make that a number. Dialogue: 0,0:54:04.51,0:54:08.09,EN,,0,0,0,,And then we put into the table under the symbol number Dialogue: 0,0:54:08.59,0:54:11.00,EN,,0,0,0,,and the operation add, this procedure plus-number, Dialogue: 0,0:54:12.30,0:54:16.16,EN,,0,0,0,,and then the same thing for subtracting, and multiplying, and dividing. Dialogue: 0,0:54:22.67,0:54:26.06,EN,,0,0,0,,Let's look at an example, just to make it clear. Dialogue: 0,0:54:26.06,0:54:28.75,EN,,0,0,0,,Suppose, for instance, Dialogue: 0,0:54:32.28,0:54:34.15,EN,,0,0,0,,I'm going to perform the operation. Dialogue: 0,0:54:34.15,0:54:38.22,EN,,0,0,0,,So I sit up here and I'm going to perform the operation, Dialogue: 0,0:54:38.22,0:54:40.46,EN,,0,0,0,,which looks like multiplying two complex numbers. Dialogue: 0,0:54:40.93,0:54:48.64,EN,,0,0,0,,So I would multiply, say, 3 plus 4i and 2 plus 6i. Dialogue: 0,0:54:50.17,0:54:52.60,EN,,0,0,0,,And that's something that I might want to take hand that to mul. Dialogue: 0,0:54:52.84,0:54:55.76,EN,,0,0,0,,I'll write mul as my generic operator here. Dialogue: 0,0:54:57.17,0:54:57.98,EN,,0,0,0,,How's that going to work? Dialogue: 0,0:54:58.28,0:55:04.60,EN,,0,0,0,,Well 3 plus 4i, say, sits in the system at this level Dialogue: 0,0:55:04.83,0:55:06.11,EN,,0,0,0,,as something that looks like this. Dialogue: 0,0:55:06.25,0:55:07.52,EN,,0,0,0,,Let's say it was one of George's. Dialogue: 0,0:55:08.28,0:55:14.97,EN,,0,0,0,,So it would have a 3 and a 4. Dialogue: 0,0:55:18.49,0:55:20.97,EN,,0,0,0,,And attached to that would be George's type, Dialogue: 0,0:55:24.33,0:55:28.32,EN,,0,0,0,,which says rectangular, it came from George. Dialogue: 0,0:55:29.51,0:55:30.57,EN,,0,0,0,,And attached to that-- Dialogue: 0,0:55:31.23,0:55:35.79,EN,,0,0,0,,and this itself would be the data view from the next level up Dialogue: 0,0:55:36.19,0:55:36.78,EN,,0,0,0,,which it is-- Dialogue: 0,0:55:37.93,0:55:39.96,EN,,0,0,0,,so that itself would be a type-data object Dialogue: 0,0:55:40.60,0:55:41.80,EN,,0,0,0,,which would say complex. Dialogue: 0,0:55:44.82,0:55:47.31,EN,,0,0,0,,So that's what this object would look like Dialogue: 0,0:55:48.64,0:55:50.24,EN,,0,0,0,,up here at the very highest level, Dialogue: 0,0:55:50.68,0:55:53.56,EN,,0,0,0,,where the really super-generic operations are looking at it. Dialogue: 0,0:55:55.56,0:55:58.72,EN,,0,0,0,,Now what happens, mul eventually's going to come along Dialogue: 0,0:55:58.84,0:56:00.40,EN,,0,0,0,,and say, oh,what's it's type? Dialogue: 0,0:56:00.48,0:56:01.48,EN,,0,0,0,,It's type is complex. Dialogue: 0,0:56:04.27,0:56:06.46,EN,,0,0,0,,Go through to operate-2 and say, Dialogue: 0,0:56:06.46,0:56:09.72,EN,,0,0,0,,oh, what I want to do is apply what's in the table, Dialogue: 0,0:56:09.72,0:56:13.04,EN,,0,0,0,,which is going to be the procedure star complex, Dialogue: 0,0:56:15.08,0:56:17.76,EN,,0,0,0,,on this thing with the type stripped off. Dialogue: 0,0:56:17.95,0:56:19.28,EN,,0,0,0,,So it's going to strip off the type, Dialogue: 0,0:56:19.93,0:56:24.24,EN,,0,0,0,,take that much, and send that down into the complex world. Dialogue: 0,0:56:26.70,0:56:28.73,EN,,0,0,0,,The complex world looks at its operations and says, Dialogue: 0,0:56:28.76,0:56:30.56,EN,,0,0,0,,oh, I have to apply star c. Dialogue: 0,0:56:31.28,0:56:32.14,EN,,0,0,0,,Star c might say, Dialogue: 0,0:56:32.22,0:56:37.20,EN,,0,0,0,,at some point I want to look at the magnitude of this object that it's in, that it's got. Dialogue: 0,0:56:39.42,0:56:40.16,EN,,0,0,0,,And they'll say, oh, it's Dialogue: 0,0:56:40.16,0:56:41.71,EN,,0,0,0,,rectangular, it's one of George's. Dialogue: 0,0:56:41.87,0:56:44.41,EN,,0,0,0,,So it'll then strip off the next version of type, Dialogue: 0,0:56:46.91,0:56:49.80,EN,,0,0,0,,and hand that down to George to take the magnitude of. Dialogue: 0,0:56:52.16,0:56:53.13,EN,,0,0,0,,So you see what's going on Dialogue: 0,0:56:53.44,0:56:56.99,EN,,0,0,0,,is that there are these chains of types. Dialogue: 0,0:56:59.32,0:57:01.50,EN,,0,0,0,,And the length of the chain is sort of the number of levels Dialogue: 0,0:57:01.53,0:57:03.13,EN,,0,0,0,,that you're going to be going up in this table. Dialogue: 0,0:57:05.09,0:57:05.96,EN,,0,0,0,,And what a type tells you, Dialogue: 0,0:57:05.96,0:57:10.84,EN,,0,0,0,,every time you have a vertical barrier in this table, Dialogue: 0,0:57:11.05,0:57:14.06,EN,,0,0,0,,where there's some ambiguity about where you should go down to the next level, Dialogue: 0,0:57:14.41,0:57:15.85,EN,,0,0,0,,the type is telling you where to go. Dialogue: 0,0:57:17.44,0:57:18.83,EN,,0,0,0,,And then everybody at the bottom, Dialogue: 0,0:57:18.97,0:57:20.67,EN,,0,0,0,,as they construct data and filter it up, Dialogue: 0,0:57:21.12,0:57:22.81,EN,,0,0,0,,they stick their type back on. Dialogue: 0,0:57:25.35,0:57:30.75,EN,,0,0,0,,So that's the general structure of the system. Dialogue: 0,0:57:33.41,0:57:33.77,EN,,0,0,0,,OK. Dialogue: 0,0:57:34.82,0:57:35.68,EN,,0,0,0,,Now that we've got this, Dialogue: 0,0:57:37.56,0:57:39.44,EN,,0,0,0,,let's go and make this thing even more complex. Dialogue: 0,0:57:41.89,0:57:46.54,EN,,0,0,0,,Let's talk about adding to the system not only these kinds of numbers Dialogue: 0,0:57:46.60,0:57:51.15,EN,,0,0,0,,numbers, but it's also meaningful to start talking about adding polynomials. Dialogue: 0,0:57:51.51,0:57:52.97,EN,,0,0,0,,Might do arithmetic on polynomials. Dialogue: 0,0:57:53.36,0:58:03.71,EN,,0,0,0,,Like we could have x to the fifteenth plus 2x to the seventh plus 5. Dialogue: 0,0:58:04.48,0:58:05.84,EN,,0,0,0,,That might be some polynomial. Dialogue: 0,0:58:06.38,0:58:07.93,EN,,0,0,0,,And if we have two such gadgets Dialogue: 0,0:58:07.93,0:58:09.48,EN,,0,0,0,,we can add them or multiply them. Dialogue: 0,0:58:10.53,0:58:11.79,EN,,0,0,0,,Let's not worry about dividing them. Dialogue: 0,0:58:12.14,0:58:14.67,EN,,0,0,0,,Just add them, multiply them, then we'll subtract them. Dialogue: 0,0:58:15.55,0:58:17.16,EN,,0,0,0,,Auhhh...What do we have to do? Well Dialogue: 0,0:58:18.52,0:58:20.76,EN,,0,0,0,,let's think about how we might represent a polynomial. Dialogue: 0,0:58:21.83,0:58:23.55,EN,,0,0,0,,It's going to be some typed data object. Dialogue: 0,0:58:24.73,0:58:27.55,EN,,0,0,0,,So let's say a polynomial to this system Dialogue: 0,0:58:28.54,0:58:31.68,EN,,0,0,0,,might look like a thing that starts with the type polynomial. Dialogue: 0,0:58:32.00,0:58:34.55,EN,,0,0,0,,And then maybe it says the next thing is what variable its in. Dialogue: 0,0:58:34.55,0:58:37.69,EN,,0,0,0,,So I might say I'm a polynomial in the variable x. Dialogue: 0,0:58:38.96,0:58:41.39,EN,,0,0,0,,And then it'll have some information about what the terms are. Dialogue: 0,0:58:42.25,0:58:44.16,EN,,0,0,0,,And there're just tons of ways to do this, Dialogue: 0,0:58:44.25,0:58:47.63,EN,,0,0,0,,but one way is to say we're going to have a thing called a term-list. Dialogue: 0,0:58:51.52,0:58:52.24,EN,,0,0,0,,And a term-list-- Dialogue: 0,0:58:53.70,0:58:55.61,EN,,0,0,0,,well, in our case we'll use something that looks like this. Dialogue: 0,0:58:56.36,0:58:59.68,EN,,0,0,0,,We'll make it a bunch of pairs which have an order in a coefficient Dialogue: 0,0:58:59.69,0:59:05.80,EN,,0,0,0,,So this polynomial would be represented by this term-list. Dialogue: 0,0:59:09.42,0:59:10.68,EN,,0,0,0,,And what that means is that Dialogue: 0,0:59:11.48,0:59:19.71,EN,,0,0,0,,this polynomial starts off with a term of order 15 and coefficient 1. Dialogue: 0,0:59:23.82,0:59:27.50,EN,,0,0,0,,And the next thing in it is a term of order 7 and coefficient 2, Dialogue: 0,0:59:27.53,0:59:30.49,EN,,0,0,0,,a term of order 0, which is constant in coefficient 5 Dialogue: 0,0:59:31.45,0:59:34.16,EN,,0,0,0,,And there are lots and lots of ways, Dialogue: 0,0:59:34.25,0:59:35.96,EN,,0,0,0,,and lots and lots of trade-offs Dialogue: 0,0:59:36.01,0:59:39.10,EN,,0,0,0,,when you really think about making algebraic manipulation packages Dialogue: 0,0:59:39.44,0:59:41.73,EN,,0,0,0,,that exactly how you should represent these things. Dialogue: 0,0:59:42.01,0:59:43.68,EN,,0,0,0,,But this is a fairly standard one. Dialogue: 0,0:59:44.18,0:59:45.55,EN,,0,0,0,,It's useful in a lot of contexts. Dialogue: 0,0:59:47.77,0:59:50.99,EN,,0,0,0,,OK, well how do we implement our polynomial arithmetic? Dialogue: 0,0:59:53.47,0:59:54.96,EN,,0,0,0,,Let's start out. Dialogue: 0,0:59:57.95,1:00:00.28,EN,,0,0,0,,What we'll do to make a polynomial-- Dialogue: 0,1:00:00.76,1:00:04.12,EN,,0,0,0,,we'll first have a way to make polynomials. Dialogue: 0,1:00:05.69,1:00:10.28,EN,,0,0,0,,We're going to make a polynomial out of variable like x and term-list. Dialogue: 0,1:00:11.24,1:00:14.09,EN,,0,0,0,,And all that does is we'll package them together someway. Dialogue: 0,1:00:14.30,1:00:19.40,EN,,0,0,0,,We'll put the variable together with the term list using cons Dialogue: 0,1:00:19.82,1:00:21.74,EN,,0,0,0,,and then attached to that the type polynomial. Dialogue: 0,1:00:26.27,1:00:27.77,EN,,0,0,0,,OK, how do we add two polynomials? Dialogue: 0,1:00:29.28,1:00:31.85,EN,,0,0,0,,To add a polynomial, p1 and p2, Dialogue: 0,1:00:32.68,1:00:35.18,EN,,0,0,0,,and then just for simplicity let's say we Dialogue: 0,1:00:35.37,1:00:37.15,EN,,0,0,0,,we will only add things in the same variable. Dialogue: 0,1:00:37.38,1:00:39.28,EN,,0,0,0,,So if they have the same variable, Dialogue: 0,1:00:39.69,1:00:42.57,EN,,0,0,0,,and same variable here is going to be some selector we write, Dialogue: 0,1:00:42.96,1:00:44.38,EN,,0,0,0,,whose details we don't care about. Dialogue: 0,1:00:45.15,1:00:47.04,EN,,0,0,0,,If the two polynomials have the same variable, Dialogue: 0,1:00:48.03,1:00:48.81,EN,,0,0,0,,then we'll do something. Dialogue: 0,1:00:48.81,1:00:51.26,EN,,0,0,0,,If they don't have the same variable, we'll give an error, Dialogue: 0,1:00:52.35,1:00:54.01,EN,,0,0,0,,polynomials not in the same variable. Dialogue: 0,1:00:55.48,1:00:57.37,EN,,0,0,0,,And if they do have the same variable, Dialogue: 0,1:00:57.60,1:00:59.18,EN,,0,0,0,,what we'll do is we'll make a polynomial Dialogue: 0,1:00:59.80,1:01:01.85,EN,,0,0,0,,whose variable is whatever that variable is, Dialogue: 0,1:01:03.15,1:01:06.56,EN,,0,0,0,,and whose term-list is something we'll call sum-terms. Dialogue: 0,1:01:07.48,1:01:09.80,EN,,0,0,0,,Plus terms will add the two term lists. Dialogue: 0,1:01:10.17,1:01:12.01,EN,,0,0,0,,So we'll add the two term lists to the polynomial. Dialogue: 0,1:01:13.50,1:01:14.51,EN,,0,0,0,,That'll give us a term-list. Dialogue: 0,1:01:15.00,1:01:20.01,EN,,0,0,0,,We'll add on, we'll say it's a polynomial in the variable with that term-list. Dialogue: 0,1:01:20.68,1:01:21.79,EN,,0,0,0,,That's plus poly. Dialogue: 0,1:01:22.55,1:01:27.00,EN,,0,0,0,,And then we're going to put in our table under the type polynomial Dialogue: 0,1:01:28.24,1:01:30.14,EN,,0,0,0,,add them using plus poly. Dialogue: 0,1:01:30.52,1:01:31.75,EN,,0,0,0,,And of course we really haven't done much. Dialogue: 0,1:01:31.75,1:01:35.31,EN,,0,0,0,,What we've really done is pushed all the work onto this thing, +terms Dialogue: 0,1:01:35.79,1:01:37.02,EN,,0,0,0,,which is supposed to add term-lists. Dialogue: 0,1:01:37.74,1:01:39.16,EN,,0,0,0,,Let's look at that. Dialogue: 0,1:01:39.18,1:01:48.03,EN,,0,0,0,,Here's an overview of how we might add two term-lists. Dialogue: 0,1:01:48.90,1:01:51.74,EN,,0,0,0,,So L1 and L2 were going to be two term-lists. Dialogue: 0,1:01:52.00,1:01:54.81,EN,,0,0,0,,And a term-list is a bunch of pairs, coefficient in order. Dialogue: 0,1:01:55.70,1:01:56.95,EN,,0,0,0,,And it's a big case analysis. Dialogue: 0,1:01:59.86,1:02:04.14,EN,,0,0,0,,And the first thing we'll check for and see if there are any terms Dialogue: 0,1:02:05.39,1:02:07.55,EN,,0,0,0,,We're going to recursively work down these term-lists Dialogue: 0,1:02:08.16,1:02:11.74,EN,,0,0,0,,so eventually we'll get to a place where either L1 or L2 might be empty. Dialogue: 0,1:02:12.27,1:02:14.35,EN,,0,0,0,,And if either one is empty, Dialogue: 0,1:02:14.52,1:02:15.85,EN,,0,0,0,,our answer will be the other one. Dialogue: 0,1:02:15.85,1:02:19.55,EN,,0,0,0,,So if L1 is empty we'll return L2, Dialogue: 0,1:02:19.63,1:02:21.71,EN,,0,0,0,,and if L2 is empty we'll return L1. Dialogue: 0,1:02:23.26,1:02:25.76,EN,,0,0,0,,Otherwise there are sort of three interesting cases. Dialogue: 0,1:02:27.22,1:02:27.98,EN,,0,0,0,,What we're going to do is Dialogue: 0,1:02:29.08,1:02:31.05,EN,,0,0,0,,grab the first term in each of those lists, Dialogue: 0,1:02:33.50,1:02:36.04,EN,,0,0,0,,Right? Called t1 and t2. Dialogue: 0,1:02:37.66,1:02:39.05,EN,,0,0,0,,And we're going to look at three cases, Dialogue: 0,1:02:39.60,1:02:45.68,EN,,0,0,0,,depending on whether the order of t1 is greater than the order of t2, Dialogue: 0,1:02:47.23,1:02:50.59,EN,,0,0,0,,or less than t2, or the same. Dialogue: 0,1:02:53.28,1:02:54.91,EN,,0,0,0,,Those are the three cases we're going to look at. Dialogue: 0,1:02:54.91,1:02:55.84,EN,,0,0,0,,Let's look at this case. Dialogue: 0,1:02:58.64,1:03:01.31,EN,,0,0,0,,If the order of t1 is greater than the order of t2, Dialogue: 0,1:03:03.40,1:03:04.70,EN,,0,0,0,,then what that means is that Dialogue: 0,1:03:06.06,1:03:09.96,EN,,0,0,0,,then what that means is that our answer is going to start with this term of the order of t1. Dialogue: 0,1:03:11.56,1:03:13.80,EN,,0,0,0,,Because it won't combine with any lower order terms. Dialogue: 0,1:03:14.17,1:03:16.19,EN,,0,0,0,,So what we do is add the lower order terms. Dialogue: 0,1:03:16.76,1:03:18.25,EN,,0,0,0,,We recursively add Dialogue: 0,1:03:19.71,1:03:25.07,EN,,0,0,0,,together all the terms in the rest of the term-list in L1 and L2. Dialogue: 0,1:03:27.13,1:03:29.32,EN,,0,0,0,,That's going to be the lower order terms of the answer. Dialogue: 0,1:03:30.12,1:03:32.48,EN,,0,0,0,,And then we're going to adjoin to that the highest order term. Dialogue: 0,1:03:33.18,1:03:35.45,EN,,0,0,0,,And I'm using here a whole bunch of procedures I haven't defined Dialogue: 0,1:03:35.47,1:03:37.55,EN,,0,0,0,,like a adjoin-term, and rest-terms, Dialogue: 0,1:03:38.48,1:03:40.17,EN,,0,0,0,,and selectors that get order. Dialogue: 0,1:03:41.15,1:03:42.78,EN,,0,0,0,,But you can imagine what those are. Dialogue: 0,1:03:44.44,1:03:48.76,EN,,0,0,0,,Right? So if the first term-list has a higher order than the second Dialogue: 0,1:03:48.78,1:03:51.08,EN,,0,0,0,,we recursively add all the lower terms Dialogue: 0,1:03:51.28,1:03:53.42,EN,,0,0,0,,and then stick on that last term. Dialogue: 0,1:03:55.54,1:03:56.75,EN,,0,0,0,,The other case, the same way. Dialogue: 0,1:03:56.89,1:04:00.28,EN,,0,0,0,,If the first term has a smaller order, Dialogue: 0,1:04:00.54,1:04:08.36,EN,,0,0,0,,well then we add we add the first term-list and the rest of the terms in the second one Dialogue: 0,1:04:08.62,1:04:12.65,EN,,0,0,0,,and adjoin on this highest order term. Dialogue: 0,1:04:14.57,1:04:15.96,EN,,0,0,0,,So so far nothing's much happened, Dialogue: 0,1:04:15.96,1:04:19.40,EN,,0,0,0,,we've just sort of pushed this thing off into adding lower order terms. Dialogue: 0,1:04:19.47,1:04:21.96,EN,,0,0,0,,The last case where you actually get to a coefficients Dialogue: 0,1:04:22.57,1:04:25.18,EN,,0,0,0,,that you have to add, this will be the case where the orders are equal. Dialogue: 0,1:04:27.24,1:04:30.99,EN,,0,0,0,,What we do is, well again recursively add the lower order terms. Dialogue: 0,1:04:31.00,1:04:32.83,EN,,0,0,0,,But now we have to really combine something. Dialogue: 0,1:04:33.46,1:04:36.35,EN,,0,0,0,,What we do is we make a term Dialogue: 0,1:04:37.31,1:04:39.93,EN,,0,0,0,,whose order is the order of the term we're looking at. Dialogue: 0,1:04:40.82,1:04:42.72,EN,,0,0,0,,By now t1 and t2 have the same order. Dialogue: 0,1:04:44.32,1:04:44.99,EN,,0,0,0,,That's its order. Dialogue: 0,1:04:45.09,1:04:52.33,EN,,0,0,0,,And its coefficient is gotten by adding the coefficient of t1 and the coefficient of t2. Dialogue: 0,1:04:55.79,1:04:59.64,EN,,0,0,0,,There's... This is a big recursive working down of terms, Dialogue: 0,1:04:59.68,1:05:03.61,EN,,0,0,0,,but really there's only one interesting symbol in this procedure, Dialogue: 0,1:05:04.25,1:05:05.69,EN,,0,0,0,,only one interesting idea. Dialogue: 0,1:05:05.90,1:05:08.50,EN,,0,0,0,,The interesting idea is this add. Dialogue: 0,1:05:12.39,1:05:14.80,EN,,0,0,0,,And the reason that's interesting is because Dialogue: 0,1:05:15.42,1:05:17.37,EN,,0,0,0,,something completely wonderful just happened. Dialogue: 0,1:05:18.22,1:05:21.37,EN,,0,0,0,,We reduced adding polynomials, Dialogue: 0,1:05:22.56,1:05:26.46,EN,,0,0,0,,not to sort of plus, but to the generic add. Dialogue: 0,1:05:28.82,1:05:32.28,EN,,0,0,0,,In other words, by implementing it that way, Dialogue: 0,1:05:32.89,1:05:34.68,EN,,0,0,0,,not only do we have our system Dialogue: 0,1:05:35.92,1:05:41.66,EN,,0,0,0,,where we can have rational numbers, or complex numbers, or ordinary numbers, Dialogue: 0,1:05:41.85,1:05:43.82,EN,,0,0,0,,we've just added on polynomials. Dialogue: 0,1:05:48.52,1:05:51.13,EN,,0,0,0,,But the coefficients of the polynomials Dialogue: 0,1:05:51.24,1:05:52.86,EN,,0,0,0,,can be anything that the system can add. Dialogue: 0,1:05:53.59,1:05:56.73,EN,,0,0,0,,So these could be polynomials whose coefficient Dialogue: 0,1:05:57.20,1:06:01.20,EN,,0,0,0,,are rational numbers or complex numbers, Dialogue: 0,1:06:02.76,1:06:06.99,EN,,0,0,0,,which in turn could be either rectangular, or polar, Dialogue: 0,1:06:09.12,1:06:11.39,EN,,0,0,0,,or ordinary numbers. Dialogue: 0,1:06:18.97,1:06:21.21,EN,,0,0,0,,Rignt? So what I mean precisely is Dialogue: 0,1:06:22.06,1:06:24.35,EN,,0,0,0,,our system right now automatically Dialogue: 0,1:06:26.60,1:06:31.50,EN,,0,0,0,,can handle things like adding together polynomials that have this form Dialogue: 0,1:06:31.53,1:06:39.69,EN,,0,0,0,,2/3 of x squared plus 5/17 x plus 11/4. Dialogue: 0,1:06:40.94,1:06:43.48,EN,,0,0,0,,Or automatically handle polynomials that look like Dialogue: 0,1:06:43.82,1:06:52.57,EN,,0,0,0,,3 plus 2i times x to the fifth plus 4 plus 7i, or something. Dialogue: 0,1:06:53.88,1:06:56.21,EN,,0,0,0,,Right? You can automatically handle those things. Dialogue: 0,1:06:56.21,1:06:57.07,EN,,0,0,0,,Why is that? Dialogue: 0,1:06:57.82,1:07:01.50,EN,,0,0,0,,That's merely because, or profoundly because Dialogue: 0,1:07:02.17,1:07:05.93,EN,,0,0,0,,we reduced adding polynomials to adding their coefficients. Dialogue: 0,1:07:06.79,1:07:10.22,EN,,0,0,0,,And adding coefficients was done by the generic add operator Dialogue: 0,1:07:11.08,1:07:12.94,EN,,0,0,0,,which said, I don't care what your types are Dialogue: 0,1:07:12.96,1:07:14.08,EN,,0,0,0,,as long as I know how to add you. Dialogue: 0,1:07:15.23,1:07:18.86,EN,,0,0,0,,So automatically for free we get the ability to handle that. Dialogue: 0,1:07:20.65,1:07:22.04,EN,,0,0,0,,What's even better than that, Dialogue: 0,1:07:24.51,1:07:26.52,EN,,0,0,0,,one of the things we did Dialogue: 0,1:07:27.20,1:07:30.52,EN,,0,0,0,,we put into the table that the way you add polynomials Dialogue: 0,1:07:31.28,1:07:32.52,EN,,0,0,0,,is using plus poly. Dialogue: 0,1:07:34.66,1:07:38.65,EN,,0,0,0,,That means that polynomials themselves are things that can be added. Dialogue: 0,1:07:39.42,1:07:42.11,EN,,0,0,0,,So for instance let me write one here. Dialogue: 0,1:07:43.18,1:07:46.19,EN,,0,0,0,,Here is... Here's a polynomial. Dialogue: 0,1:07:50.56,1:07:52.41,EN,,0,0,0,,So this gadget here I'm writing up, Dialogue: 0,1:07:54.12,1:07:58.46,EN,,0,0,0,,this is a polynomial in y Dialogue: 0,1:08:01.07,1:08:04.69,EN,,0,0,0,,whose coefficients are polynomials in x. Dialogue: 0,1:08:08.61,1:08:11.12,EN,,0,0,0,,So you see, simply by saying, Dialogue: 0,1:08:11.76,1:08:14.06,EN,,0,0,0,,polynomials are themselves things that can be added, Dialogue: 0,1:08:14.41,1:08:17.90,EN,,0,0,0,,we can go off and say, well not only can we deal with rationals, Dialogue: 0,1:08:18.27,1:08:20.33,EN,,0,0,0,,or complex, or ordinary numbers, Dialogue: 0,1:08:20.35,1:08:21.77,EN,,0,0,0,,but we can deal with polynomials Dialogue: 0,1:08:22.09,1:08:25.39,EN,,0,0,0,,whose coefficients are rationals, or complex, or ordinary numbers, Dialogue: 0,1:08:25.50,1:08:27.52,EN,,0,0,0,,or polynomials Dialogue: 0,1:08:29.15,1:08:30.96,EN,,0,0,0,,whose coefficients are rationals, Dialogue: 0,1:08:31.69,1:08:36.76,EN,,0,0,0,,or complex, rectangular, polar, or ordinary numbers, Dialogue: 0,1:08:36.94,1:08:41.13,EN,,0,0,0,,or ordinary numbers, or polynomials whose coefficients are rationals, Dialogue: 0,1:08:41.80,1:08:43.32,EN,,0,0,0,,complex, or ordinary numbers. Dialogue: 0,1:08:43.67,1:08:45.21,EN,,0,0,0,,And so on, and so on, and so on. Dialogue: 0,1:08:45.95,1:08:47.55,EN,,0,0,0,,So this is sort of an infinite Dialogue: 0,1:08:48.49,1:08:52.88,EN,,0,0,0,,or maybe a recursive tower of types that we've built up. Dialogue: 0,1:08:53.88,1:08:57.12,EN,,0,0,0,,And it's all exactly from that one little symbol, A-D-D. Dialogue: 0,1:08:57.61,1:09:00.49,EN,,0,0,0,,Writing "add" instead of "plus" in the polynomial thing. Dialogue: 0,1:09:02.27,1:09:03.77,EN,,0,0,0,,Slightly different way to think about it Dialogue: 0,1:09:03.95,1:09:07.74,EN,,0,0,0,,is that polynomials are a constructor for types. Dialogue: 0,1:09:08.74,1:09:11.20,EN,,0,0,0,,Namely you give it a type, like integer, Dialogue: 0,1:09:11.48,1:09:15.74,EN,,0,0,0,,and it returns for you polynomials in x whose coefficients are integers. Dialogue: 0,1:09:16.27,1:09:17.72,EN,,0,0,0,,And the important thing about Dialogue: 0,1:09:18.65,1:09:20.73,EN,,0,0,0,,is that is that the operations on polynomials Dialogue: 0,1:09:21.28,1:09:23.37,EN,,0,0,0,,reduce to the operations on the coefficients. Dialogue: 0,1:09:23.39,1:09:24.96,EN,,0,0,0,,And there are a lot of things like that. Dialogue: 0,1:09:25.84,1:09:27.92,EN,,0,0,0,,So for example, let's go back and rational numbers. Dialogue: 0,1:09:28.87,1:09:32.65,EN,,0,0,0,,We thought about rational numbers as an integer over an integer Dialogue: 0,1:09:32.67,1:09:35.66,EN,,0,0,0,,but there's the general notion of a rational object. Dialogue: 0,1:09:36.24,1:09:42.03,EN,,0,0,0,,Like we might think about 3x plus 7 over x squared plus 1. Dialogue: 0,1:09:43.07,1:09:48.86,EN,,0,0,0,,That's general rational object whose numerator and denominator are polynomials. Dialogue: 0,1:09:50.31,1:09:52.41,EN,,0,0,0,,And to add two of them we use the same formula, Dialogue: 0,1:09:52.44,1:09:55.40,EN,,0,0,0,,numerator times denominator plus denominator times numerator Dialogue: 0,1:09:55.72,1:09:56.99,EN,,0,0,0,,over product of denominators. Dialogue: 0,1:09:57.29,1:09:59.37,EN,,0,0,0,,How could we install that in our system? Dialogue: 0,1:09:59.39,1:10:02.97,EN,,0,0,0,,Well here's our original rational number arithmetic package. Dialogue: 0,1:10:04.25,1:10:08.24,EN,,0,0,0,,And all we have to do in order to make the entire system Dialogue: 0,1:10:08.28,1:10:11.58,EN,,0,0,0,,continue working with general rational objects, Dialogue: 0,1:10:11.85,1:10:16.44,EN,,0,0,0,,is replace these particular pluses and stars by the generic operator. Dialogue: 0,1:10:16.48,1:10:19.18,EN,,0,0,0,,So if we simply change that procedure to this one, Dialogue: 0,1:10:19.71,1:10:22.04,EN,,0,0,0,,here we've changed plus and star to add a mul, Dialogue: 0,1:10:22.88,1:10:24.48,EN,,0,0,0,,those are absolutely the only change, Dialogue: 0,1:10:24.84,1:10:26.03,EN,,0,0,0,,then suddenly Dialogue: 0,1:10:27.52,1:10:31.40,EN,,0,0,0,,our entire system can start talking about objects that look like this. Dialogue: 0,1:10:33.72,1:10:38.27,EN,,0,0,0,,So for example, here is a rational object Dialogue: 0,1:10:39.18,1:10:44.86,EN,,0,0,0,,whose numerator is a polynomial in x whose coefficients are rational numbers. Dialogue: 0,1:10:47.02,1:10:49.56,EN,,0,0,0,,Or here is a rational object Dialogue: 0,1:10:51.10,1:10:54.43,EN,,0,0,0,,whose numerator is polynomials in x Dialogue: 0,1:10:55.15,1:10:58.19,EN,,0,0,0,,whose coefficients are rational objects Dialogue: 0,1:10:59.77,1:11:01.53,EN,,0,0,0,,constructed out of complex numbers. Dialogue: 0,1:11:03.39,1:11:04.85,EN,,0,0,0,,And then there are a lot of other things like that. Dialogue: 0,1:11:04.85,1:11:08.68,EN,,0,0,0,,See, whenever you have a thing where the operations reduce to operations on the pieces, Dialogue: 0,1:11:08.89,1:11:10.00,EN,,0,0,0,,another example would be Dialogue: 0,1:11:10.28,1:11:11.42,EN,,0,0,0,,two by two matrices. Dialogue: 0,1:11:12.31,1:11:15.44,EN,,0,0,0,,I have the idea, there might be a matrix here Dialogue: 0,1:11:16.43,1:11:18.33,EN,,0,0,0,,of general things that I don't care about. Dialogue: 0,1:11:18.72,1:11:20.14,EN,,0,0,0,,But if I add two of them, Dialogue: 0,1:11:22.33,1:11:25.18,EN,,0,0,0,,the answer over here is gotten by Dialogue: 0,1:11:25.18,1:11:28.14,EN,,0,0,0,,adding this one and that one,however they like to add. Dialogue: 0,1:11:29.03,1:11:31.11,EN,,0,0,0,,So I can implement that the same way. Dialogue: 0,1:11:31.11,1:11:31.71,EN,,0,0,0,,And if I do that, Dialogue: 0,1:11:31.96,1:11:34.60,EN,,0,0,0,,then again suddenly my system can start handling things like this. Dialogue: 0,1:11:35.29,1:11:39.18,EN,,0,0,0,,So here's a matrix whose elements happen to be-- Dialogue: 0,1:11:39.46,1:11:42.16,EN,,0,0,0,,we'll say this element here is a rational object Dialogue: 0,1:11:43.10,1:11:45.15,EN,,0,0,0,,whose numerator and denominators are polynomials. Dialogue: 0,1:11:47.02,1:11:49.56,EN,,0,0,0,,Right? And all that comes for free. Dialogue: 0,1:11:51.28,1:11:53.82,EN,,0,0,0,,Right? What's really going on here? Dialogue: 0,1:11:53.92,1:11:56.17,EN,,0,0,0,,What's really going on is Dialogue: 0,1:11:57.68,1:12:02.44,EN,,0,0,0,,getting rid of who's sitting there poking his nose into who everybody's business is. Dialogue: 0,1:12:03.12,1:12:06.19,EN,,0,0,0,,We built a system that has decentralized control. Dialogue: 0,1:12:14.78,1:12:18.34,EN,,0,0,0,,So when you come into and no one's poking around saying, Dialogue: 0,1:12:18.35,1:12:22.30,EN,,0,0,0,,gee, are you in the official list of people who can be added? Dialogue: 0,1:12:22.44,1:12:26.22,EN,,0,0,0,,Rather you say, well go off and add yourself how your parts like to be added. Dialogue: 0,1:12:27.81,1:12:31.03,EN,,0,0,0,,And the result of that is you can get this very, very, very Dialogue: 0,1:12:31.03,1:12:33.87,EN,,0,0,0,,complex hierarchy where a lot of things just get done and Dialogue: 0,1:12:33.87,1:12:35.55,EN,,0,0,0,,rooted to the right place automatically. Dialogue: 0,1:12:37.00,1:12:37.79,EN,,0,0,0,,Let's stop for questions. Dialogue: 0,1:12:40.38,1:12:42.32,EN,,0,0,0,,AUDIENCE: You say you get this for free. Dialogue: 0,1:12:42.35,1:12:45.82,EN,,0,0,0,,Um..... One thing that strikes me is that now you've lost Dialogue: 0,1:12:46.48,1:12:50.91,EN,,0,0,0,,kind of the cleanness of the break between what's on top and what's underneath. Dialogue: 0,1:12:50.91,1:12:52.77,EN,,0,0,0,,In other words, now you're defining some of the Dialogue: 0,1:12:52.77,1:12:56.08,EN,,0,0,0,,lower-level procedures in terms of things above their own line. Dialogue: 0,1:12:56.61,1:12:59.45,EN,,0,0,0,,Isn't that dangerous? Dialogue: 0,1:13:00.35,1:13:04.49,EN,,0,0,0,,Or, if nothing more, a little less structured? Dialogue: 0,1:13:05.44,1:13:05.95,EN,,0,0,0,,PROFESSOR: No, I-- Dialogue: 0,1:13:06.41,1:13:07.77,EN,,0,0,0,,the question is whether that's less structured. Dialogue: 0,1:13:07.77,1:13:08.69,EN,,0,0,0,,Depends on what you mean by structure. Dialogue: 0,1:13:08.69,1:13:10.17,EN,,0,0,0,,All this is doing is recursion. Dialogue: 0,1:13:11.05,1:13:18.80,EN,,0,0,0,,See, it's saying that the way you add these guys is to use that. Dialogue: 0,1:13:19.15,1:13:21.37,EN,,0,0,0,,And that's not less structured, it's just a recursive structure. Dialogue: 0,1:13:22.70,1:13:24.99,EN,,0,0,0,,So I don't think it's particularly any less clean. Dialogue: 0,1:13:24.99,1:13:28.16,EN,,0,0,0,,AUDIENCE: Now when you want to change the multiplier or the add operator Dialogue: 0,1:13:29.34,1:13:31.38,EN,,0,0,0,,suddenly you've got tremendous consequences Dialogue: 0,1:13:31.38,1:13:34.27,EN,,0,0,0,,underneath that you're not even sure the extent of. Dialogue: 0,1:13:34.48,1:13:36.44,EN,,0,0,0,,PROFESSOR: That's right, but it depends what you mean. Dialogue: 0,1:13:37.08,1:13:38.47,EN,,0,0,0,,See, this goes both ways. Dialogue: 0,1:13:39.10,1:13:43.24,EN,,0,0,0,,Um....What would be a good example? Dialogue: 0,1:13:44.69,1:13:47.50,EN,,0,0,0,,I ignored greatest common divisor, for instance. Dialogue: 0,1:13:47.77,1:13:50.08,EN,,0,0,0,,I ignored that problem just to keep the example simple. Dialogue: 0,1:13:50.28,1:13:56.92,EN,,0,0,0,,But if I suddenly decided that plus rat here Dialogue: 0,1:13:57.82,1:14:01.69,EN,,0,0,0,,should do a GCD computation and install that, Dialogue: 0,1:14:03.34,1:14:07.87,EN,,0,0,0,,then that immediately becomes available to all of these, to that guy, and that guy, Dialogue: 0,1:14:08.03,1:14:10.08,EN,,0,0,0,,and that guy, and all the way down. Dialogue: 0,1:14:11.56,1:14:13.89,EN,,0,0,0,,So it depends what you mean by the coherence of your system. Dialogue: 0,1:14:13.89,1:14:17.03,EN,,0,0,0,,It's certainly true that you might want to have a special Dialogue: 0,1:14:17.03,1:14:19.56,EN,,0,0,0,,different one that didn't filter down through the coefficients Dialogue: 0,1:14:19.61,1:14:22.97,EN,,0,0,0,,but the nice thing about this particular example is that mostly you do. Dialogue: 0,1:14:25.44,1:14:27.63,EN,,0,0,0,,AUDIENCE: Isn't that the problem, I think, that you're Dialogue: 0,1:14:27.63,1:14:32.95,EN,,0,0,0,,getting to tied in with the fact that the structuring, the Dialogue: 0,1:14:32.95,1:14:36.33,EN,,0,0,0,,recursiveness of that structuring there is actually Dialogue: 0,1:14:36.33,1:14:40.34,EN,,0,0,0,,in execution as opposed to just definition of the actual Dialogue: 0,1:14:40.34,1:14:41.16,EN,,0,0,0,,types themselves? Dialogue: 0,1:14:44.68,1:14:46.12,EN,,0,0,0,,PROFESSOR: I think I understand the question. Dialogue: 0,1:14:46.12,1:14:47.80,EN,,0,0,0,,The point is that these types evolve Dialogue: 0,1:14:47.82,1:14:50.40,EN,,0,0,0,,and get more and more complex as the thing's actually running. Dialogue: 0,1:14:50.40,1:14:50.73,EN,,0,0,0,,Is that what-- Dialogue: 0,1:14:50.73,1:14:50.99,EN,,0,0,0,,AUDIENCE: Yap. Dialogue: 0,1:14:50.99,1:14:51.79,EN,,0,0,0,,As it's running. Dialogue: 0,1:14:52.09,1:14:54.18,EN,,0,0,0,,AUDIENCE: As opposed to the basic definitions. Dialogue: 0,1:14:54.18,1:14:54.83,EN,,0,0,0,,PROFESSOR: Right. There's... Dialogue: 0,1:14:54.83,1:14:56.70,EN,,0,0,0,,The type structure is sort of recursive. Dialogue: 0,1:14:57.21,1:15:00.22,EN,,0,0,0,,It's not that you can make this finite list of the Dialogue: 0,1:15:01.58,1:15:04.85,EN,,0,0,0,,actual things they might look like before the system runs. Dialogue: 0,1:15:04.85,1:15:05.79,EN,,0,0,0,,It's something that evolves. Dialogue: 0,1:15:06.78,1:15:08.64,EN,,0,0,0,,So if you want to specify that system, Dialogue: 0,1:15:08.67,1:15:10.96,EN,,0,0,0,,you have to do in some other way than by this finite list. Dialogue: 0,1:15:11.00,1:15:13.18,EN,,0,0,0,,You have to do it by a recursive structure. Dialogue: 0,1:15:13.67,1:15:17.90,EN,,0,0,0,,AUDIENCE: Because the basic structure of the types is pretty clean and simple. Dialogue: 0,1:15:17.90,1:15:18.19,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,1:15:20.40,1:15:20.75,EN,,0,0,0,,Yes? Dialogue: 0,1:15:21.46,1:15:22.87,EN,,0,0,0,,AUDIENCE: I have a question. Dialogue: 0,1:15:22.87,1:15:25.68,EN,,0,0,0,,I understand once you have your data structure set up, Dialogue: 0,1:15:25.71,1:15:28.73,EN,,0,0,0,,how it pulls off complex and passes that down, Dialogue: 0,1:15:28.73,1:15:30.64,EN,,0,0,0,,and then pulls off rect, passes that down. Dialogue: 0,1:15:30.64,1:15:33.95,EN,,0,0,0,,But if you're just a user and you don't know anything about rect or polar or whatever, Dialogue: 0,1:15:34.25,1:15:36.04,EN,,0,0,0,,how do you initially set up that data structure Dialogue: 0,1:15:36.09,1:15:38.08,EN,,0,0,0,,so that everything goes to the right spot? Dialogue: 0,1:15:38.09,1:15:41.00,EN,,0,0,0,,If I just have the equation over there on the left Dialogue: 0,1:15:41.02,1:15:42.50,EN,,0,0,0,,And I just want to add, multiply complex numbers-- Dialogue: 0,1:15:42.50,1:15:43.64,EN,,0,0,0,,PROFESSOR: Well that's the wonderful thing. Dialogue: 0,1:15:43.64,1:15:45.26,EN,,0,0,0,,If you're just a user you say "mul." Dialogue: 0,1:15:47.73,1:15:49.95,EN,,0,0,0,,AUDIENCE: And it figures out that I mean complex numbers? Dialogue: 0,1:15:49.96,1:15:51.23,EN,,0,0,0,,Or how do I tell it that I want-- Dialogue: 0,1:15:51.26,1:15:53.05,EN,,0,0,0,,PROFESSOR: Well you're going to have in your hands complex numbers. Dialogue: 0,1:15:53.05,1:15:56.30,EN,,0,0,0,,See what you would have at some level, as a real user, Dialogue: 0,1:15:56.32,1:15:58.14,EN,,0,0,0,,is a constructor for complex numbers. Dialogue: 0,1:15:58.37,1:15:59.55,EN,,0,0,0,,AUDIENCE: So then I have to make complex numbers? Dialogue: 0,1:15:59.56,1:16:00.35,EN,,0,0,0,,PROFESSOR: So you have to make them. Dialogue: 0,1:16:00.35,1:16:04.01,EN,,0,0,0,,What you would probably have as a user is some little thing in the reader loop, Dialogue: 0,1:16:04.65,1:16:07.56,EN,,0,0,0,,which would give you some plausible way Dialogue: 0,1:16:07.56,1:16:08.86,EN,,0,0,0,,to type in a complex number, Dialogue: 0,1:16:09.31,1:16:11.00,EN,,0,0,0,,in however whatever format you like. Dialogue: 0,1:16:11.59,1:16:14.36,EN,,0,0,0,,Or it might be that you're never typing them in. Dialogue: 0,1:16:14.36,1:16:16.17,EN,,0,0,0,,Someone's just handing you a complex number. Dialogue: 0,1:16:16.78,1:16:19.82,EN,,0,0,0,,AUDIENCE: OK, so if I had a complex number that had a polynomial in it, Dialogue: 0,1:16:19.82,1:16:21.96,EN,,0,0,0,,I'd have to make my polynomial and then make my complex number. Dialogue: 0,1:16:21.96,1:16:23.96,EN,,0,0,0,,PROFESSOR: Right if you wanted it constructed from scratch. Dialogue: 0,1:16:24.28,1:16:25.71,EN,,0,0,0,,At some point you construct them from scratch. Dialogue: 0,1:16:25.71,1:16:27.05,EN,,0,0,0,,But what you don't have to know of that Dialogue: 0,1:16:27.28,1:16:30.32,EN,,0,0,0,,is when you have the object you can just say "mul." And it'll multiply. Dialogue: 0,1:16:32.78,1:16:32.99,EN,,0,0,0,,Yeah? Dialogue: 0,1:16:33.27,1:16:35.76,EN,,0,0,0,,AUDIENCE: I think the question that was being posed here is, Dialogue: 0,1:16:36.45,1:16:40.01,EN,,0,0,0,,say if I want to change my presentation of complexes, Dialogue: 0,1:16:40.03,1:16:41.44,EN,,0,0,0,,or some operation of complex, Dialogue: 0,1:16:41.52,1:16:47.10,EN,,0,0,0,,how much real code I will have to gets around with, Dialogue: 0,1:16:47.15,1:16:51.26,EN,,0,0,0,,or change to change it in one specific operation? Dialogue: 0,1:16:52.27,1:16:53.49,EN,,0,0,0,,PROFESSOR: [UNINTELLIGIBLE] what you have to change. Dialogue: 0,1:16:53.49,1:16:54.99,EN,,0,0,0,,And the point is that you only have to change Dialogue: 0,1:16:55.39,1:16:56.07,EN,,0,0,0,,what you're changing. Dialogue: 0,1:16:56.07,1:17:00.04,EN,,0,0,0,,See if Martha decides that she would rather-- Dialogue: 0,1:17:00.32,1:17:01.23,EN,,0,0,0,,let's see something silly-- Dialogue: 0,1:17:01.44,1:17:02.91,EN,,0,0,0,,like change the order in the pair. Dialogue: 0,1:17:04.04,1:17:08.72,EN,,0,0,0,,Like angle and magnitude in the other order, Dialogue: 0,1:17:09.39,1:17:10.80,EN,,0,0,0,,she just makes that change locally. Dialogue: 0,1:17:10.97,1:17:13.29,EN,,0,0,0,,And the whole thing will propagate through the system in the right way. Dialogue: 0,1:17:14.79,1:17:18.76,EN,,0,0,0,,Or if suddenly you said, gee, I have another representation for rationals. Dialogue: 0,1:17:19.70,1:17:23.90,EN,,0,0,0,,And I'm going to stick it here, by filing those operations in the table. Dialogue: 0,1:17:24.82,1:17:27.22,EN,,0,0,0,,Then suddenly all of these polynomials whose coefficients Dialogue: 0,1:17:27.22,1:17:29.10,EN,,0,0,0,,are coefficients of coefficients, or whatever, Dialogue: 0,1:17:29.24,1:17:32.40,EN,,0,0,0,,also can automatically have available that representation. Dialogue: 0,1:17:32.70,1:17:34.67,EN,,0,0,0,,That's the power of this particular one. Dialogue: 0,1:17:36.11,1:17:38.70,EN,,0,0,0,,AUDIENCE: I'm not sure if I can even pose an intelligent sounding question. Dialogue: 0,1:17:38.70,1:17:42.38,EN,,0,0,0,,But somehow this whole thing went really nicely Dialogue: 0,1:17:42.54,1:17:45.88,EN,,0,0,0,,to this beautiful finish where all the things seemed to fall into place. Dialogue: 0,1:17:46.72,1:17:48.67,EN,,0,0,0,,And sort of seemed a little contrived. Dialogue: 0,1:17:50.93,1:17:52.52,EN,,0,0,0,,That's all for the sake, I'm sure, of teaching. Dialogue: 0,1:17:52.56,1:17:54.65,EN,,0,0,0,,I doubt that the guys who first did this-- Dialogue: 0,1:17:55.10,1:17:55.85,EN,,0,0,0,,and I could be wrong-- Dialogue: 0,1:17:56.60,1:17:59.72,EN,,0,0,0,,figured it all out so that when they just all put it all together, Dialogue: 0,1:17:59.77,1:18:03.93,EN,,0,0,0,,you could all of the sudden, blam, do any kind of arithmetic on any kind of object. Dialogue: 0,1:18:04.86,1:18:07.20,EN,,0,0,0,,It seems like maybe they had to play with it for a while Dialogue: 0,1:18:07.93,1:18:10.62,EN,,0,0,0,,and had to bash it and rework it. Dialogue: 0,1:18:11.80,1:18:14.12,EN,,0,0,0,,And it seems like that's the kind of problem we're really Dialogue: 0,1:18:14.12,1:18:16.94,EN,,0,0,0,,faced with we start trying to design a really complex system Dialogue: 0,1:18:17.31,1:18:20.35,EN,,0,0,0,,is having lots of different kinds of parts and not even knowing Dialogue: 0,1:18:21.08,1:18:24.62,EN,,0,0,0,,what kinds of operations we're going to want to do on those parts. Dialogue: 0,1:18:24.62,1:18:26.54,EN,,0,0,0,,How to organize the operations in this nice way Dialogue: 0,1:18:26.56,1:18:29.63,EN,,0,0,0,,so that no matter what you do, when you start putting them together Dialogue: 0,1:18:29.63,1:18:31.39,EN,,0,0,0,,everything starts falling out for free. Dialogue: 0,1:18:31.70,1:18:34.34,EN,,0,0,0,,PROFESSOR: OK, well that's certainly a very intelligent question... Um Dialogue: 0,1:18:35.10,1:18:39.52,EN,,0,0,0,,Um....One part is this is a very good methodology Dialogue: 0,1:18:39.87,1:18:43.88,EN,,0,0,0,,that people have discovered a lot coming from symbolic algebra. Dialogue: 0,1:18:44.59,1:18:45.90,EN,,0,0,0,,Because there are a lot of complications. Dialogue: 0,1:18:47.59,1:18:50.71,EN,,0,0,0,,To allow you to implement these things before you decide Dialogue: 0,1:18:50.71,1:18:52.89,EN,,0,0,0,,what you want all the operations to be, and all of that. Dialogue: 0,1:18:53.31,1:18:57.72,EN,,0,0,0,,So in some sense it's an answer that people have discovered by wading through this stuff. Dialogue: 0,1:18:58.56,1:19:00.75,EN,,0,0,0,,In another sense, it is a very contrived example. Dialogue: 0,1:19:02.16,1:19:06.24,EN,,0,0,0,,AUDIENCE: It seems like to be able to do this you do have to Dialogue: 0,1:19:06.24,1:19:09.01,EN,,0,0,0,,wade through it for a certain amount of time before you can become good at it. Dialogue: 0,1:19:09.01,1:19:11.88,EN,,0,0,0,,PROFESSOR: Let me show you how terribly contrived this is. Dialogue: 0,1:19:12.22,1:19:14.13,EN,,0,0,0,,So you can write all these wonderful things. Dialogue: 0,1:19:14.13,1:19:16.25,EN,,0,0,0,,But the system that I wrote here, Dialogue: 0,1:19:17.02,1:19:18.96,EN,,0,0,0,,and if we had another half an hour to give this lecture Dialogue: 0,1:19:19.31,1:19:20.46,EN,,0,0,0,,I would have given this part of it, Dialogue: 0,1:19:20.81,1:19:23.02,EN,,0,0,0,,which says, notice that it breaks down Dialogue: 0,1:19:23.20,1:19:29.31,EN,,0,0,0,,if I tell it to do something as foolish as add 3 plus 7/2. Dialogue: 0,1:19:30.88,1:19:33.42,EN,,0,0,0,,Because what will happen is you'll get to operate-2, Dialogue: 0,1:19:33.80,1:19:35.95,EN,,0,0,0,,and operate-2 will say, oh this is type number, Dialogue: 0,1:19:36.18,1:19:37.37,EN,,0,0,0,,and that's type rational. Dialogue: 0,1:19:37.56,1:19:38.81,EN,,0,0,0,,I don't know how to add them. Dialogue: 0,1:19:41.53,1:19:44.30,EN,,0,0,0,,So you'd like the system at least to be able to say something like, Dialogue: 0,1:19:45.88,1:19:47.34,EN,,0,0,0,,gee,before you do that Dialogue: 0,1:19:48.59,1:19:50.24,EN,,0,0,0,,change that to 3/1. Dialogue: 0,1:19:50.48,1:19:53.21,EN,,0,0,0,,Turn it into a rational number, hand that to the rational package. Dialogue: 0,1:19:54.86,1:19:58.70,EN,,0,0,0,,That's the thing I didn't talk about in this lecture. Dialogue: 0,1:19:58.73,1:20:00.88,EN,,0,0,0,,It's a little bit in the book,which talks about the problem Dialogue: 0,1:20:00.88,1:20:01.95,EN,,0,0,0,,of what's called coercion. Dialogue: 0,1:20:03.39,1:20:05.15,EN,,0,0,0,,Where you wanted-- Dialogue: 0,1:20:05.31,1:20:08.89,EN,,0,0,0,,see, having so carefully set up all of these types as distinct objects Dialogue: 0,1:20:08.91,1:20:12.17,EN,,0,0,0,,a lot of times you want to also put in knowledge Dialogue: 0,1:20:12.40,1:20:17.98,EN,,0,0,0,,about how to view an ordinary number as a kind of rational. Dialogue: 0,1:20:19.11,1:20:21.29,EN,,0,0,0,,Or view an ordinary number as a kind of complex. Dialogue: 0,1:20:21.62,1:20:25.16,EN,,0,0,0,,That's where the complexity in the system really starts happening Dialogue: 0,1:20:25.76,1:20:28.12,EN,,0,0,0,,where you talk about, see where do I put that knowledge? Dialogue: 0,1:20:28.42,1:20:32.19,EN,,0,0,0,,Is it rational to know that ordinary numbers might be pieces of cons of them? Dialogue: 0,1:20:33.13,1:20:36.38,EN,,0,0,0,,Or they're terrible, terrible examples, like Dialogue: 0,1:20:38.14,1:20:47.48,EN,,0,0,0,,if I might want to add a complex number to a rational number. Dialogue: 0,1:20:49.87,1:20:50.76,EN,,0,0,0,,Bad example. Dialogue: 0,1:20:50.76,1:20:51.58,EN,,0,0,0,,5/7. Dialogue: 0,1:20:53.86,1:20:55.72,EN,,0,0,0,,Then somebody's got to know that Dialogue: 0,1:20:56.06,1:20:58.16,EN,,0,0,0,,I have to convert these to another type, Dialogue: 0,1:20:58.20,1:21:00.65,EN,,0,0,0,,which is complex numbers whose parts might be rationals. Dialogue: 0,1:21:01.54,1:21:02.68,EN,,0,0,0,,And who worries about that? Dialogue: 0,1:21:02.68,1:21:03.95,EN,,0,0,0,,Does complex worry about that? Dialogue: 0,1:21:03.95,1:21:05.03,EN,,0,0,0,,Does rational worry about that? Dialogue: 0,1:21:05.24,1:21:06.22,EN,,0,0,0,,Does plus worry about that? Dialogue: 0,1:21:06.90,1:21:08.52,EN,,0,0,0,,That's where the real complexity comes in. Dialogue: 0,1:21:08.52,1:21:11.38,EN,,0,0,0,,And that's where it's pretty well sorted out. Dialogue: 0,1:21:11.38,1:21:14.12,EN,,0,0,0,,And a lot of, in fact, all of this message passing stuff Dialogue: 0,1:21:14.64,1:21:16.54,EN,,0,0,0,,was motivated by problems like this. Dialogue: 0,1:21:18.46,1:21:20.89,EN,,0,0,0,,And when you really push it, people are-- Dialogue: 0,1:21:20.91,1:21:24.76,EN,,0,0,0,,somehow the algebraic manipulation problem seems to be so complex Dialogue: 0,1:21:25.18,1:21:27.41,EN,,0,0,0,,that the people who are always at the edge of it are exactly in Dialogue: 0,1:21:27.41,1:21:28.05,EN,,0,0,0,,the state you said. Dialogue: 0,1:21:28.05,1:21:29.71,EN,,0,0,0,,They're wading through this thing, mucking around, Dialogue: 0,1:21:29.72,1:21:31.37,EN,,0,0,0,,seeing what they use, trying to distill stuff. Dialogue: 0,1:21:34.20,1:21:37.76,EN,,0,0,0,,AUDIENCE: I just want to come back to this issue of complexity once more. Dialogue: 0,1:21:38.41,1:21:44.55,EN,,0,0,0,,Um... It certainly seems to be true that you have a great deal of Dialogue: 0,1:21:44.55,1:21:48.32,EN,,0,0,0,,flexibility in altering the lower level kinds of things. Dialogue: 0,1:21:49.71,1:21:53.40,EN,,0,0,0,,But it is true that you are, in a sense, Dialogue: 0,1:21:53.44,1:21:55.26,EN,,0,0,0,,freezing higher level operations. Dialogue: 0,1:21:55.45,1:21:58.51,EN,,0,0,0,,Or at least if you change them you don't know where all of Dialogue: 0,1:21:58.51,1:22:02.06,EN,,0,0,0,,the changes are going to show up, or how they are. Dialogue: 0,1:22:02.20,1:22:04.22,EN,,0,0,0,,PROFESSOR: OK, that's an extremely good question. Dialogue: 0,1:22:04.68,1:22:05.87,EN,,0,0,0,,What I have to do is, Dialogue: 0,1:22:08.68,1:22:10.84,EN,,0,0,0,,if I decide there's a new general operation Dialogue: 0,1:22:11.45,1:22:13.07,EN,,0,0,0,,called equality test, Dialogue: 0,1:22:14.96,1:22:17.15,EN,,0,0,0,,then all of these people have to decide Dialogue: 0,1:22:18.22,1:22:22.54,EN,,0,0,0,,whether or not they would like to have an equality test by looking in the table. Dialogue: 0,1:22:24.65,1:22:26.84,EN,,0,0,0,,There're ways to decentralize it even more. Dialogue: 0,1:22:27.87,1:22:30.70,EN,,0,0,0,,That's what I sort of hinted at last time, where I said Dialogue: 0,1:22:31.08,1:22:33.26,EN,,0,0,0,,you could not only have this type as a symbol, Dialogue: 0,1:22:33.40,1:22:38.70,EN,,0,0,0,,but you actually might store in each object the operations that it knows of that. Dialogue: 0,1:22:40.45,1:22:43.90,EN,,0,0,0,,So you might have things like greatest common divisor, Dialogue: 0,1:22:44.43,1:22:46.81,EN,,0,0,0,,which is a thing here which is defined only for integers, Dialogue: 0,1:22:47.40,1:22:49.21,EN,,0,0,0,,and not in general for rational numbers. Dialogue: 0,1:22:51.03,1:22:53.11,EN,,0,0,0,,So it might be a very, very fragmented system. Dialogue: 0,1:22:53.11,1:22:55.66,EN,,0,0,0,,And then depending on where you want your flexibility, Dialogue: 0,1:22:56.22,1:22:59.02,EN,,0,0,0,,You...there's a whole spectrum of places that you can build that in. Dialogue: 0,1:22:59.96,1:23:02.56,EN,,0,0,0,,But you're pointing at the place where this starts being weak, Dialogue: 0,1:23:02.60,1:23:06.37,EN,,0,0,0,,that there has to be some agreement on top here about these general operations. Dialogue: 0,1:23:06.37,1:23:07.82,EN,,0,0,0,,Or at least people have to think about them. Dialogue: 0,1:23:08.39,1:23:10.72,EN,,0,0,0,,Or you might decide, you might have a table that's very sparse Dialogue: 0,1:23:10.75,1:23:11.96,EN,,0,0,0,,that only has a few things in it. Dialogue: 0,1:23:14.01,1:23:15.49,EN,,0,0,0,,But there are lot of ways to play that game. Dialogue: 0,1:23:19.78,1:23:20.43,EN,,0,0,0,,OK, thank you. Dialogue: 0,1:23:23.53,1:23:36.56,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:23:23.53,1:23:36.56,Declare,,0,0,0,,{\an2\fad(500,500)}https://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec5a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 1338 Active Line: 1344 Video Position: 9363 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:18.31,0:00:22.00,EN,,0,0,0,,PROFESSOR: Well, so far we've invented enough programming Dialogue: 0,0:00:22.25,0:00:24.06,EN,,0,0,0,,to do some very complicated things. Dialogue: 0,0:00:24.76,0:00:29.66,EN,,0,0,0,,And you surely learned a lot about programming at this point. Dialogue: 0,0:00:29.66,0:00:31.48,EN,,0,0,0,,You've learned almost all the most important tricks Dialogue: 0,0:00:31.86,0:00:35.87,EN,,0,0,0,,that usually don't get taught to people until they have had a lot of experience. Dialogue: 0,0:00:36.41,0:00:40.08,EN,,0,0,0,,For example, data directed programming is a major trick, Dialogue: 0,0:00:40.75,0:00:43.15,EN,,0,0,0,,and yesterday you also saw an interpreted language. Dialogue: 0,0:00:45.02,0:00:48.46,EN,,0,0,0,,We did this all in a computer language, Dialogue: 0,0:00:48.54,0:00:49.63,EN,,0,0,0,,at this point, Dialogue: 0,0:00:49.88,0:00:51.95,EN,,0,0,0,,where there was no assignment statement. Dialogue: 0,0:00:53.77,0:00:58.17,EN,,0,0,0,,And presumably, for those of you who've seen your Basic or Pascal or whatever, Dialogue: 0,0:00:58.68,0:01:01.23,EN,,0,0,0,,that's usually considered the most important thing. Dialogue: 0,0:01:01.79,0:01:03.82,EN,,0,0,0,,Well today, we're going to do something horrible. Dialogue: 0,0:01:03.82,0:01:05.45,EN,,0,0,0,,We're going to add an assignment statement. Dialogue: 0,0:01:07.21,0:01:09.14,EN,,0,0,0,,And since we can do all these wonderful things without it, Dialogue: 0,0:01:09.14,0:01:10.17,EN,,0,0,0,,why should we add it? Dialogue: 0,0:01:10.99,0:01:12.43,EN,,0,0,0,,An important thing to understand it Dialogue: 0,0:01:12.46,0:01:15.71,EN,,0,0,0,,is that today we're going to first of all, have a rule, Dialogue: 0,0:01:16.48,0:01:17.93,EN,,0,0,0,,which is going to always be obeyed, Dialogue: 0,0:01:17.93,0:01:20.80,EN,,0,0,0,,which is the only reason we ever add a feature to our language Dialogue: 0,0:01:21.53,0:01:23.14,EN,,0,0,0,,is because there is a good reason. Dialogue: 0,0:01:23.93,0:01:27.28,EN,,0,0,0,,And the good reason is going to boil down to the ability, Dialogue: 0,0:01:27.42,0:01:31.51,EN,,0,0,0,,you now get an ability to break a problem into pieces that are different sets of pieces Dialogue: 0,0:01:31.51,0:01:33.44,EN,,0,0,0,,then you could have broken it down without that, Dialogue: 0,0:01:34.38,0:01:36.16,EN,,0,0,0,,give you another means of decomposition. Dialogue: 0,0:01:38.30,0:01:39.45,EN,,0,0,0,,However, let's just start. Dialogue: 0,0:01:39.45,0:01:41.88,EN,,0,0,0,,Let me quick begin by reviewing Dialogue: 0,0:01:41.88,0:01:47.37,EN,,0,0,0,,the kind of language that we have now. Dialogue: 0,0:01:48.16,0:01:50.44,EN,,0,0,0,,We've been writing what's called functional programs. Dialogue: 0,0:01:51.21,0:01:52.52,EN,,0,0,0,,And functional programs Dialogue: 0,0:01:53.04,0:01:57.95,EN,,0,0,0,,are a kind of encoding of mathematical truths. Dialogue: 0,0:01:58.88,0:02:00.51,EN,,0,0,0,,For example, when we look at Dialogue: 0,0:02:00.51,0:02:04.09,EN,,0,0,0,,the factorial procedure that you see on the slide here, Dialogue: 0,0:02:05.07,0:02:06.62,EN,,0,0,0,,it's basically two clauses. Dialogue: 0,0:02:06.99,0:02:08.64,EN,,0,0,0,,If n is one, the result is one, Dialogue: 0,0:02:08.64,0:02:11.20,EN,,0,0,0,,otherwise n times factorial n minus one. Dialogue: 0,0:02:11.20,0:02:12.33,EN,,0,0,0,,That's factorial of n. Dialogue: 0,0:02:12.89,0:02:14.27,EN,,0,0,0,,Well, that is factorial of n. Dialogue: 0,0:02:14.83,0:02:16.87,EN,,0,0,0,,And written down in some other obscure notation Dialogue: 0,0:02:16.87,0:02:19.32,EN,,0,0,0,,that you might have learned in calculus classes, Dialogue: 0,0:02:20.30,0:02:22.11,EN,,0,0,0,,Ahh.. mathematical logic, Dialogue: 0,0:02:22.11,0:02:26.36,EN,,0,0,0,,what you see there is if n equals one, Dialogue: 0,0:02:27.13,0:02:29.90,EN,,0,0,0,,for the result of n factorial is one, otherwise, Dialogue: 0,0:02:29.90,0:02:32.56,EN,,0,0,0,,greater than one, n factorial is n times n minus one factorial. Dialogue: 0,0:02:32.56,0:02:33.55,EN,,0,0,0,,True statements, Dialogue: 0,0:02:34.92,0:02:36.70,EN,,0,0,0,,that's the kind of language we've been using. Dialogue: 0,0:02:37.00,0:02:39.23,EN,,0,0,0,,And whenever we have true statements of that sort, Dialogue: 0,0:02:39.53,0:02:46.65,EN,,0,0,0,,there is a kind of, a way of understanding how they work Dialogue: 0,0:02:47.40,0:02:51.12,EN,,0,0,0,,which is that such processes can be evolved by substitution. Dialogue: 0,0:02:51.29,0:02:53.71,EN,,0,0,0,,And so we see on the second slide here, Dialogue: 0,0:02:54.99,0:02:58.81,EN,,0,0,0,,that the way we understand the execution Dialogue: 0,0:02:58.83,0:03:03.50,EN,,0,0,0,,implied by those statements in arranged in that order, Dialogue: 0,0:03:04.04,0:03:07.76,EN,,0,0,0,,is that you do successive substitutions of arguments Dialogue: 0,0:03:07.87,0:03:10.88,EN,,0,0,0,,for formal parameters in the body of a procedure. Dialogue: 0,0:03:12.00,0:03:14.51,EN,,0,0,0,,This is basically a sequence of equalities. Dialogue: 0,0:03:14.61,0:03:17.25,EN,,0,0,0,,Factorial four is four times factorial three. Dialogue: 0,0:03:17.25,0:03:20.05,EN,,0,0,0,,That is four times three times factorial of two Dialogue: 0,0:03:20.05,0:03:21.01,EN,,0,0,0,,and so on. Dialogue: 0,0:03:21.23,0:03:23.87,EN,,0,0,0,,We're always preserving truth. Dialogue: 0,0:03:25.23,0:03:28.84,EN,,0,0,0,,Even though we're talking about true statements, Dialogue: 0,0:03:28.84,0:03:31.96,EN,,0,0,0,,there might be more than one organization of these true statements Dialogue: 0,0:03:31.96,0:03:35.12,EN,,0,0,0,,to describe the computation of a particular function, Dialogue: 0,0:03:36.32,0:03:38.42,EN,,0,0,0,,the computation of the value of a particular function. Dialogue: 0,0:03:38.42,0:03:40.92,EN,,0,0,0,,So, for example, looking at the next one here. Dialogue: 0,0:03:41.48,0:03:49.02,EN,,0,0,0,,Here is a way of looking at the sum of n and m. Dialogue: 0,0:03:49.53,0:03:52.04,EN,,0,0,0,,And we did this one by a recursive process. Dialogue: 0,0:03:52.89,0:03:58.16,EN,,0,0,0,,It's the increment of the sum of the decrement of n and m. Dialogue: 0,0:04:00.08,0:04:05.62,EN,,0,0,0,,And, of course, there is some piece of mathematical logic here that describes that. Dialogue: 0,0:04:06.17,0:04:10.49,EN,,0,0,0,,It's the increment of the sum of the decrement of n and m, Dialogue: 0,0:04:11.40,0:04:12.22,EN,,0,0,0,,just like that. Dialogue: 0,0:04:13.10,0:04:16.40,EN,,0,0,0,,So there's nothing particularly magic about that. Dialogue: 0,0:04:16.41,0:04:20.01,EN,,0,0,0,,And, of course, if we can also look at an iterative process for the same, Dialogue: 0,0:04:20.19,0:04:24.92,EN,,0,0,0,,a program that evolves an iterative process, for the same function. Dialogue: 0,0:04:25.26,0:04:27.56,EN,,0,0,0,,These are two things that compute the same answer. Dialogue: 0,0:04:30.08,0:04:34.83,EN,,0,0,0,,And we have equivalent mathematical truths that are arranged there. Dialogue: 0,0:04:36.65,0:04:39.93,EN,,0,0,0,,And just the way you arrange those truths determine the particular process. Dialogue: 0,0:04:40.30,0:04:43.42,EN,,0,0,0,,In the way choose and arrange them determines the process that's evolved. Dialogue: 0,0:04:44.33,0:04:48.60,EN,,0,0,0,,So we have the flexibility of talking about both the function to be computed, Dialogue: 0,0:04:48.60,0:04:50.19,EN,,0,0,0,,and the method by which it's computed. Dialogue: 0,0:04:50.60,0:04:52.60,EN,,0,0,0,,So it's not clear we need more. Dialogue: 0,0:04:53.61,0:04:55.50,EN,,0,0,0,,However, today I'm going to this awful thing. Dialogue: 0,0:04:55.50,0:04:58.43,EN,,0,0,0,,I'm going to introduce this assignment operation. Dialogue: 0,0:04:58.89,0:05:00.41,EN,,0,0,0,,Now, what is this? Dialogue: 0,0:05:02.89,0:05:09.22,EN,,0,0,0,,Well, first of all, there is going to be another kind of kind of statement, if you will, Dialogue: 0,0:05:09.22,0:05:10.84,EN,,0,0,0,,in a programming language called Set! Dialogue: 0,0:05:12.41,0:05:15.96,EN,,0,0,0,,And SET! -- Things that do things like assignment, Dialogue: 0,0:05:15.96,0:05:15.98,EN,,0,0,0,, Dialogue: 0,0:05:15.98,0:05:17.85,EN,,0,0,0,,I'm going to put exclamation points after. Dialogue: 0,0:05:18.51,0:05:20.96,EN,,0,0,0,,We'll talk about what that means in a second. Dialogue: 0,0:05:20.96,0:05:23.01,EN,,0,0,0,,The exclamation point, again like question mark, Dialogue: 0,0:05:23.01,0:05:25.88,EN,,0,0,0,,is an arbitrary thing we attach to the symbol which is the name, Dialogue: 0,0:05:25.88,0:05:27.88,EN,,0,0,0,,has no significance to the system. Dialogue: 0,0:05:28.08,0:05:30.21,EN,,0,0,0,,The only significance is to me and you Dialogue: 0,0:05:30.40,0:05:34.41,EN,,0,0,0,,to alert you that this is an assignment of some sort. Dialogue: 0,0:05:35.88,0:05:40.06,EN,,0,0,0,,But we're going to set a variable to a value. Dialogue: 0,0:05:43.74,0:05:45.13,EN,,0,0,0,,And what that's going to mean Dialogue: 0,0:05:45.13,0:05:48.28,EN,,0,0,0,,is that there is a time at which something happens. Dialogue: 0,0:05:48.65,0:05:49.61,EN,,0,0,0,,Here's a time. Dialogue: 0,0:05:49.86,0:05:52.14,EN,,0,0,0,,If I have time going this way, Dialogue: 0,0:05:53.50,0:05:54.82,EN,,0,0,0,,it's a time axis. Dialogue: 0,0:05:55.00,0:05:57.82,EN,,0,0,0,,Time progresses by walking down the page. Dialogue: 0,0:05:58.70,0:06:00.92,EN,,0,0,0,,Then an assignment is the first thing we have Dialogue: 0,0:06:00.92,0:06:04.30,EN,,0,0,0,,that produces the difference between a before and an after. Dialogue: 0,0:06:06.59,0:06:08.72,EN,,0,0,0,,All the other programs that we've written, Dialogue: 0,0:06:09.18,0:06:10.68,EN,,0,0,0,,that have no assignments in them, Dialogue: 0,0:06:10.68,0:06:13.12,EN,,0,0,0,,the order in which they were evaluated didn't matter. Dialogue: 0,0:06:14.70,0:06:15.96,EN,,0,0,0,,But assignment is special, Dialogue: 0,0:06:15.96,0:06:17.69,EN,,0,0,0,,it produces a moment in time. Dialogue: 0,0:06:17.96,0:06:24.73,EN,,0,0,0,,So there is a moment before the set occurs and after, Dialogue: 0,0:06:27.61,0:06:32.70,EN,,0,0,0,,such that after this moment in time, Dialogue: 0,0:06:33.60,0:06:43.76,EN,,0,0,0,,the variable has the value, value. Dialogue: 0,0:06:49.23,0:06:51.50,EN,,0,0,0,,Independent of what value it had before, Dialogue: 0,0:06:52.80,0:06:55.79,EN,,0,0,0,,set! changes the value of the variable. Dialogue: 0,0:06:57.69,0:06:58.75,EN,,0,0,0,,Until this moment, Dialogue: 0,0:06:58.75,0:07:01.50,EN,,0,0,0,,we had nothing that changed. Dialogue: 0,0:07:03.21,0:07:04.11,EN,,0,0,0,,So, for example, Dialogue: 0,0:07:04.84,0:07:06.23,EN,,0,0,0,,one of the things we can think of Dialogue: 0,0:07:06.23,0:07:09.42,EN,,0,0,0,,is that the procedures we write for something like factorial Dialogue: 0,0:07:09.64,0:07:12.75,EN,,0,0,0,,are in fact pretty much identical to the function factorial. Dialogue: 0,0:07:13.77,0:07:16.44,EN,,0,0,0,,Factorial of four, if I write fact4, Dialogue: 0,0:07:17.23,0:07:19.15,EN,,0,0,0,,independent of what context it's in, Dialogue: 0,0:07:19.69,0:07:21.29,EN,,0,0,0,,and independent of how many times I write it, Dialogue: 0,0:07:21.29,0:07:22.35,EN,,0,0,0,,I always get the same answer. Dialogue: 0,0:07:23.29,0:07:24.12,EN,,0,0,0,,It's always 24. Dialogue: 0,0:07:25.37,0:07:28.92,EN,,0,0,0,,It's a unique map from the argument to the answer. Dialogue: 0,0:07:30.30,0:07:32.65,EN,,0,0,0,,And all the programs we've written so far are like that. Dialogue: 0,0:07:33.52,0:07:36.03,EN,,0,0,0,,However, once I have assignment, that isn't true. Dialogue: 0,0:07:36.96,0:07:38.16,EN,,0,0,0,,So, for example, Dialogue: 0,0:07:39.18,0:07:48.52,EN,,0,0,0,,if I were to define count to be one. Dialogue: 0,0:07:50.00,0:07:52.41,EN,,0,0,0,,And then I'm going to define also a procedure, Dialogue: 0,0:07:55.16,0:07:56.83,EN,,0,0,0,,a simple procedure called demo, Dialogue: 0,0:07:59.52,0:08:03.84,EN,,0,0,0,,which takes argument x and does the following operations. Dialogue: 0,0:08:03.84,0:08:09.62,EN,,0,0,0,,It first sets x to x plus one. Dialogue: 0,0:08:09.62,0:08:11.77,EN,,0,0,0,,My gosh, this looksjust like FORTRAN, right-- Dialogue: 0,0:08:13.16,0:08:14.17,EN,,0,0,0,,in a funny syntax. Dialogue: 0,0:08:16.80,0:08:21.37,EN,,0,0,0,,And then add to x count, Dialogue: 0,0:08:22.14,0:08:24.14,EN,,0,0,0,,Oh, I just made a mistake. Dialogue: 0,0:08:24.38,0:08:25.23,EN,,0,0,0,,I want to say, Dialogue: 0,0:08:25.47,0:08:27.12,EN,,0,0,0,,set! count to one plus count. Dialogue: 0,0:08:30.37,0:08:31.79,EN,,0,0,0,,It's this thing defined here. Dialogue: 0,0:08:34.41,0:08:36.51,EN,,0,0,0,,And then add and said plus x count. Dialogue: 0,0:08:40.35,0:08:42.06,EN,,0,0,0,,Then I can try this procedure. Dialogue: 0,0:08:42.48,0:08:43.20,EN,,0,0,0,,Let's run it. Dialogue: 0,0:08:43.92,0:08:47.22,EN,,0,0,0,,So, suppose I get a prompt and I say, Dialogue: 0,0:08:47.48,0:08:48.68,EN,,0,0,0,,demo 3 Dialogue: 0,0:08:52.19,0:08:53.20,EN,,0,0,0,,Well, what happens here? Dialogue: 0,0:08:53.74,0:08:55.28,EN,,0,0,0,,The first thing that happens Dialogue: 0,0:08:55.53,0:08:56.89,EN,,0,0,0,,is count is currently one. Dialogue: 0,0:08:56.89,0:08:58.40,EN,,0,0,0,,Currently, there is a time. Dialogue: 0,0:08:59.12,0:09:00.29,EN,,0,0,0,,We're talking about time. Dialogue: 0,0:09:00.62,0:09:01.74,EN,,0,0,0,,x gets three. Dialogue: 0,0:09:02.92,0:09:04.03,EN,,0,0,0,,At this moment, Dialogue: 0,0:09:04.67,0:09:07.53,EN,,0,0,0,,I say, oh yes, count is incremented, so count is two. Dialogue: 0,0:09:09.02,0:09:10.44,EN,,0,0,0,,two plus three is five. Dialogue: 0,0:09:10.80,0:09:12.43,EN,,0,0,0,,So the answer I get out is five. Dialogue: 0,0:09:14.48,0:09:21.58,EN,,0,0,0,,Then I say, demo of say, three again. Dialogue: 0,0:09:23.60,0:09:24.56,EN,,0,0,0,,Okay, What do I get? Dialogue: 0,0:09:24.83,0:09:27.40,EN,,0,0,0,,Well, now count is two, it's not one anymore, Dialogue: 0,0:09:28.91,0:09:30.35,EN,,0,0,0,,because I have incremented it. Dialogue: 0,0:09:30.92,0:09:32.64,EN,,0,0,0,,But now I go through this process, Dialogue: 0,0:09:32.72,0:09:33.66,EN,,0,0,0,,three goes into x, Dialogue: 0,0:09:34.17,0:09:37.40,EN,,0,0,0,,count becomes one plus count, so that's three now. Dialogue: 0,0:09:38.08,0:09:39.62,EN,,0,0,0,,The sum of those two is six, Dialogue: 0,0:09:39.62,0:09:40.94,EN,,0,0,0,,so the answer is six. Dialogue: 0,0:09:41.92,0:09:43.03,EN,,0,0,0,,And what we see Dialogue: 0,0:09:43.03,0:09:44.72,EN,,0,0,0,,is the same expression Dialogue: 0,0:09:45.08,0:09:46.64,EN,,0,0,0,,leads to two different answers, Dialogue: 0,0:09:48.75,0:09:49.96,EN,,0,0,0,,depending upon time. Dialogue: 0,0:09:52.08,0:09:53.74,EN,,0,0,0,,So demo is not a function, Dialogue: 0,0:09:54.17,0:09:56.12,EN,,0,0,0,,does not compute a mathematical function. Dialogue: 0,0:09:59.88,0:10:02.09,EN,,0,0,0,,In fact, you could also see why now, of course, Dialogue: 0,0:10:02.84,0:10:06.41,EN,,0,0,0,,this is the first place where the substitution model isn't going to work. Dialogue: 0,0:10:07.72,0:10:09.55,EN,,0,0,0,,This kills the substitution model dead. Dialogue: 0,0:10:11.28,0:10:13.82,EN,,0,0,0,,You know, with quotation there were some little problems Dialogue: 0,0:10:13.85,0:10:17.18,EN,,0,0,0,,that a philosopher might notice with substitutions, Dialogue: 0,0:10:17.18,0:10:19.87,EN,,0,0,0,,because you have to worry about what deductions you can make Dialogue: 0,0:10:20.91,0:10:22.12,EN,,0,0,0,,when you substitute into quotes, Dialogue: 0,0:10:22.34,0:10:23.92,EN,,0,0,0,,if you're allowed to do that at all. Dialogue: 0,0:10:25.08,0:10:25.60,EN,,0,0,0,,But Dialogue: 0,0:10:26.06,0:10:28.00,EN,,0,0,0,,here the substitution model is dead, Dialogue: 0,0:10:28.11,0:10:29.40,EN,,0,0,0,,can't do anything at all. Dialogue: 0,0:10:29.64,0:10:30.57,EN,,0,0,0,,Because, Dialogue: 0,0:10:30.57,0:10:35.85,EN,,0,0,0,,Supposing I wanted to use a substitution model to consider substituting for count? Dialogue: 0,0:10:37.10,0:10:41.16,EN,,0,0,0,,Well, my gosh, if I substitute for here and here, Dialogue: 0,0:10:41.69,0:10:42.96,EN,,0,0,0,,they're different ones. Dialogue: 0,0:10:44.44,0:10:45.96,EN,,0,0,0,,It's not the same count any more. Dialogue: 0,0:10:46.48,0:10:47.64,EN,,0,0,0,,I get the wrong answer. Dialogue: 0,0:10:47.97,0:10:50.14,EN,,0,0,0,,The substitution model is a static phenomenon Dialogue: 0,0:10:51.18,0:10:52.56,EN,,0,0,0,,describes things that are true Dialogue: 0,0:10:53.93,0:10:55.29,EN,,0,0,0,,and not things that change. Dialogue: 0,0:10:55.50,0:10:57.04,EN,,0,0,0,,Here, we have truths that change. Dialogue: 0,0:11:00.60,0:11:06.74,EN,,0,0,0,,OK, Well, before I give you any understanding of this, Dialogue: 0,0:11:06.74,0:11:07.79,EN,,0,0,0,,this is very bad. Dialogue: 0,0:11:07.79,0:11:09.72,EN,,0,0,0,,Now, we've lost our model of computation. Dialogue: 0,0:11:10.28,0:11:10.80,EN,,0,0,0,,And, Dialogue: 0,0:11:11.48,0:11:13.69,EN,,0,0,0,,pretty soon, I'm going to have to build you a new model of computation. Dialogue: 0,0:11:14.66,0:11:17.87,EN,,0,0,0,,But ours plays with this, just now, in an informal sense. Dialogue: 0,0:11:18.56,0:11:20.16,EN,,0,0,0,,Of course, what you already see Dialogue: 0,0:11:20.51,0:11:22.70,EN,,0,0,0,,is that when I have something like assignment, Dialogue: 0,0:11:23.12,0:11:24.51,EN,,0,0,0,,the model that we're going to need Dialogue: 0,0:11:24.51,0:11:26.89,EN,,0,0,0,,is different from the model that we had before Dialogue: 0,0:11:26.89,0:11:30.93,EN,,0,0,0,,in that, the variables, those symbols like count, or x Dialogue: 0,0:11:30.93,0:11:34.07,EN,,0,0,0,,are no longer going to refer to the values they have, Dialogue: 0,0:11:34.07,0:11:37.31,EN,,0,0,0,,but rather to some sort of place where the value restored. Dialogue: 0,0:11:37.68,0:11:39.47,EN,,0,0,0,,We're going to have to think that way for a while. Dialogue: 0,0:11:40.20,0:11:42.11,EN,,0,0,0,,And it's going to be a very bad thing Dialogue: 0,0:11:42.11,0:11:43.47,EN,,0,0,0,,and cause a lot of trouble. Dialogue: 0,0:11:44.49,0:11:48.25,EN,,0,0,0,,And so, as I said, the very fact that we're inventing this bad thing, Dialogue: 0,0:11:48.25,0:11:50.09,EN,,0,0,0,,means that there had better be a good reason for it, Dialogue: 0,0:11:50.37,0:11:52.86,EN,,0,0,0,,otherwise, just a waste of time and a lot of effort. Dialogue: 0,0:11:53.39,0:11:55.55,EN,,0,0,0,,Let's just look at some of it just to play. Dialogue: 0,0:11:55.88,0:11:58.59,EN,,0,0,0,,Supposing we write down the functional version, Dialogue: 0,0:11:58.59,0:12:00.48,EN,,0,0,0,,functional meaning in the old style, Dialogue: 0,0:12:01.37,0:12:04.60,EN,,0,0,0,,of factorial by an iterative process. Dialogue: 0,0:12:09.59,0:12:13.28,EN,,0,0,0,,Factorial of n. Dialogue: 0,0:12:18.38,0:12:24.35,EN,,0,0,0,,we're going to iterate of m and i, Dialogue: 0,0:12:26.12,0:12:33.13,EN,,0,0,0,,which says if i is greater than n, Dialogue: 0,0:12:33.77,0:12:35.51,EN,,0,0,0,,then the result is m, Dialogue: 0,0:12:36.30,0:12:37.39,EN,,0,0,0,,otherwise, Dialogue: 0,0:12:39.79,0:12:46.82,EN,,0,0,0,,the result of iterating the product of i and m. Dialogue: 0,0:12:46.82,0:12:49.95,EN,,0,0,0,,So m is going to be the product that I'm accumulating. Dialogue: 0,0:12:51.58,0:12:52.62,EN,,0,0,0,,m is the product. Dialogue: 0,0:12:57.97,0:13:00.17,EN,,0,0,0,,And the count I'm going to increase by one. Dialogue: 0,0:13:04.62,0:13:10.97,EN,,0,0,0,,Plus, ITER, ELSE, COND, define. Dialogue: 0,0:13:11.95,0:13:13.04,EN,,0,0,0,,I'm going to start this up. Dialogue: 0,0:13:17.16,0:13:19.79,EN,,0,0,0,,And these days, you should have no trouble reading something like this. Dialogue: 0,0:13:20.86,0:13:25.15,EN,,0,0,0,,What I have here is a product there being accumulated and a counter. Dialogue: 0,0:13:26.48,0:13:28.46,EN,,0,0,0,,I start them up both at one. Dialogue: 0,0:13:28.89,0:13:30.92,EN,,0,0,0,,I'm going to buzz the counter up, Dialogue: 0,0:13:30.92,0:13:33.12,EN,,0,0,0,,i goes to i plus one every time around. Dialogue: 0,0:13:34.56,0:13:37.47,EN,,0,0,0,,But that's only way our putting a time on the process, Dialogue: 0,0:13:38.48,0:13:40.04,EN,,0,0,0,,each of this is just a set of truths, Dialogue: 0,0:13:40.49,0:13:41.34,EN,,0,0,0,,true rules. Dialogue: 0,0:13:42.81,0:13:46.13,EN,,0,0,0,,And m is going to get a new values of i and m, Dialogue: 0,0:13:46.13,0:13:47.82,EN,,0,0,0,,i times m each time around, Dialogue: 0,0:13:48.68,0:13:50.48,EN,,0,0,0,,and eventually i is going to be bigger than n, Dialogue: 0,0:13:50.49,0:13:52.06,EN,,0,0,0,,in which case, the answer's going to be m. Dialogue: 0,0:13:52.67,0:13:54.80,EN,,0,0,0,,Now, I'm speaking to you, use time in this. Dialogue: 0,0:13:55.68,0:13:57.45,EN,,0,0,0,,That's just because I know how the computer works. Dialogue: 0,0:13:58.25,0:13:59.24,EN,,0,0,0,,But I didn't have to. Dialogue: 0,0:13:59.26,0:14:02.30,EN,,0,0,0,,This could be a purely mathematical description at this point, Dialogue: 0,0:14:02.30,0:14:03.74,EN,,0,0,0,,because substitution will work for this. Dialogue: 0,0:14:05.10,0:14:08.14,EN,,0,0,0,,But let's set right down a similar sort of program, Dialogue: 0,0:14:08.30,0:14:09.95,EN,,0,0,0,,using the same algorithm, Dialogue: 0,0:14:10.73,0:14:12.11,EN,,0,0,0,,but with assignments. Dialogue: 0,0:14:15.69,0:14:17.16,EN,,0,0,0,,So this is called the functional version. Dialogue: 0,0:14:23.72,0:14:25.56,EN,,0,0,0,,I want to write down an imperative version. Dialogue: 0,0:14:34.48,0:14:35.39,EN,,0,0,0,,Factorial of n. Dialogue: 0,0:14:35.92,0:14:37.74,EN,,0,0,0,,I'm going to create my two variables. Dialogue: 0,0:14:40.16,0:14:45.53,EN,,0,0,0,,Let i initialize itself to one, Dialogue: 0,0:14:46.32,0:14:49.77,EN,,0,0,0,,and m be initialized to one, similar. Dialogue: 0,0:14:51.15,0:14:52.19,EN,,0,0,0,,We'll create a loop Dialogue: 0,0:14:59.31,0:15:07.27,EN,,0,0,0,,which has COND greater than i, and if i is greater than n, we're done. Dialogue: 0,0:15:07.27,0:15:08.87,EN,,0,0,0,,And the result is m, Dialogue: 0,0:15:08.87,0:15:10.38,EN,,0,0,0,,the product I'm accumulating. Dialogue: 0,0:15:10.87,0:15:11.77,EN,,0,0,0,,Otherwise, Dialogue: 0,0:15:15.52,0:15:17.40,EN,,0,0,0,,I'm going to write down three things to do. Dialogue: 0,0:15:19.26,0:15:27.05,EN,,0,0,0,,I'm going to set! m to the product of i and m, Dialogue: 0,0:15:29.36,0:15:35.20,EN,,0,0,0,,set! i to the sum of i and one, Dialogue: 0,0:15:37.85,0:15:39.31,EN,,0,0,0,,and go around the loop again. Dialogue: 0,0:15:40.41,0:15:43.02,EN,,0,0,0,,Looks very familiar to you FORTRAN programmers. Dialogue: 0,0:15:44.73,0:15:46.64,EN,,0,0,0,,ELSE, COND, define, Dialogue: 0,0:15:46.64,0:15:47.88,EN,,0,0,0,,funny syntax though. Dialogue: 0,0:15:51.13,0:15:52.27,EN,,0,0,0,,Start the loop up, Dialogue: 0,0:15:56.10,0:15:57.56,EN,,0,0,0,,and that's the program. Dialogue: 0,0:15:59.15,0:16:00.52,EN,,0,0,0,,Now, this program, Dialogue: 0,0:16:01.31,0:16:02.49,EN,,0,0,0,,how do we think about it? Dialogue: 0,0:16:02.71,0:16:04.25,EN,,0,0,0,,Well, let's just say what we're seeing here. Dialogue: 0,0:16:04.84,0:16:07.47,EN,,0,0,0,,There are two local variables, i and m, Dialogue: 0,0:16:07.47,0:16:09.02,EN,,0,0,0,,that have been initialized to one. Dialogue: 0,0:16:10.72,0:16:13.89,EN,,0,0,0,,Every time around the loop, I test to see if i is greater than n, Dialogue: 0,0:16:13.89,0:16:15.08,EN,,0,0,0,,which is the input argument, Dialogue: 0,0:16:15.30,0:16:18.14,EN,,0,0,0,,and if so, the result is the product being accumulated in m. Dialogue: 0,0:16:19.16,0:16:21.21,EN,,0,0,0,,However, if it's not the end of the loop, Dialogue: 0,0:16:21.21,0:16:22.89,EN,,0,0,0,,if I'm not done, Dialogue: 0,0:16:23.64,0:16:25.55,EN,,0,0,0,,then what I'm going to do is change the product Dialogue: 0,0:16:25.84,0:16:28.38,EN,,0,0,0,,to be the result of multiplying i times the current product. Dialogue: 0,0:16:29.04,0:16:30.68,EN,,0,0,0,,Which is sort of what we were doing here. Dialogue: 0,0:16:31.42,0:16:32.68,EN,,0,0,0,,Except here I wasn't changing. Dialogue: 0,0:16:33.63,0:16:35.77,EN,,0,0,0,,I was making another copy, Dialogue: 0,0:16:36.81,0:16:42.04,EN,,0,0,0,,because the substitution model says, you copy the body of the procedure Dialogue: 0,0:16:43.08,0:16:45.88,EN,,0,0,0,,with the arguments substituted for the formal parameters. Dialogue: 0,0:16:46.72,0:16:48.42,EN,,0,0,0,,Here I'm not worried about copying, Dialogue: 0,0:16:48.42,0:16:50.52,EN,,0,0,0,,here I've changed the value of m. Dialogue: 0,0:16:51.80,0:16:55.12,EN,,0,0,0,,I also then change the value of i to i plus one, Dialogue: 0,0:16:55.61,0:16:56.96,EN,,0,0,0,,and go buzzing around. Dialogue: 0,0:16:58.22,0:17:00.08,EN,,0,0,0,,Seems like essentially the same program, Dialogue: 0,0:17:00.96,0:17:02.84,EN,,0,0,0,,but there are some ways of making errors here Dialogue: 0,0:17:02.84,0:17:05.50,EN,,0,0,0,,that didn't exist until today. Dialogue: 0,0:17:06.14,0:17:07.02,EN,,0,0,0,,For example, Dialogue: 0,0:17:07.45,0:17:09.40,EN,,0,0,0,,if I were to do the horrible thing Dialogue: 0,0:17:10.04,0:17:12.14,EN,,0,0,0,,of not being careful in writing my program Dialogue: 0,0:17:12.64,0:17:16.08,EN,,0,0,0,,and interchange those two assignments, Dialogue: 0,0:17:17.10,0:17:18.91,EN,,0,0,0,,the program wouldn't compute the same function. Dialogue: 0,0:17:20.33,0:17:22.87,EN,,0,0,0,,I get a timing error because there's a dependency Dialogue: 0,0:17:22.87,0:17:27.22,EN,,0,0,0,,that m depends upon having the last value of i. Dialogue: 0,0:17:27.34,0:17:28.92,EN,,0,0,0,,If I try change i first, Dialogue: 0,0:17:31.31,0:17:33.77,EN,,0,0,0,,then I've got the wrong value of i when I multiply by m. Dialogue: 0,0:17:35.96,0:17:38.38,EN,,0,0,0,,It's a bug that wasn't available until this moment, Dialogue: 0,0:17:38.38,0:17:40.59,EN,,0,0,0,,until we introduced something that had time in it. Dialogue: 0,0:17:43.44,0:17:44.30,EN,,0,0,0,,So, as I said, Dialogue: 0,0:17:45.53,0:17:47.39,EN,,0,0,0,,first we need a new model of computation, Dialogue: 0,0:17:47.39,0:17:50.86,EN,,0,0,0,,and second, we have to be damn good reason for doing this kind of ugly thing. Dialogue: 0,0:17:52.72,0:17:53.74,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:17:58.83,0:18:00.22,EN,,0,0,0,,Speak loudly, David Dialogue: 0,0:18:00.40,0:18:03.47,EN,,0,0,0,,AUDIENCE: I'm confused about, we've introduced set now, Dialogue: 0,0:18:03.90,0:18:06.36,EN,,0,0,0,,but we had let before and define before. Dialogue: 0,0:18:06.89,0:18:09.70,EN,,0,0,0,,I'm confused about the difference between the three. Dialogue: 0,0:18:09.70,0:18:13.25,EN,,0,0,0,,Wouldn't define work in the same situation as set! Dialogue: 0,0:18:13.98,0:18:14.83,EN,,0,0,0,,if you introduced it a bit? Dialogue: 0,0:18:14.83,0:18:19.31,EN,,0,0,0,,PROFESSOR: No, define is intended for setting something once the first time, Dialogue: 0,0:18:19.31,0:18:21.36,EN,,0,0,0,,for making it, OK? Dialogue: 0,0:18:22.08,0:18:24.70,EN,,0,0,0,,You've never seen me write on a blackboard Dialogue: 0,0:18:25.60,0:18:26.94,EN,,0,0,0,,two defines in a row Dialogue: 0,0:18:27.08,0:18:32.08,EN,,0,0,0,,whose intention was to change the old value of some variable to a new one. Dialogue: 0,0:18:32.08,0:18:34.51,EN,,0,0,0,,AUDIENCE: Is that by convention or-- Dialogue: 0,0:18:34.51,0:18:36.35,EN,,0,0,0,,PROFESSOR: No, it's intention. Dialogue: 0,0:18:36.35,0:18:38.92,EN,,0,0,0,,Okay? The answer is, Dialogue: 0,0:18:39.69,0:18:40.84,EN,,0,0,0,,that, for example, Dialogue: 0,0:18:40.84,0:18:42.27,EN,,0,0,0,,internal to a procedure, Dialogue: 0,0:18:43.20,0:18:45.92,EN,,0,0,0,,two defines in a row are illegal, Dialogue: 0,0:18:46.68,0:18:48.57,EN,,0,0,0,,two defines in a row of the same variable. Dialogue: 0,0:18:50.24,0:18:51.74,EN,,0,0,0,,x can't be defined twice. Dialogue: 0,0:18:51.74,0:18:55.20,EN,,0,0,0,,Whether or not a system catches that error is a different question, Dialogue: 0,0:18:55.93,0:18:57.88,EN,,0,0,0,,but I legislate to you Dialogue: 0,0:18:58.12,0:19:00.64,EN,,0,0,0,,that define happens once on anything. Dialogue: 0,0:19:00.73,0:19:02.64,EN,,0,0,0,,Now, indeed, in interactive debugging, Dialogue: 0,0:19:03.37,0:19:07.48,EN,,0,0,0,,we intend that you interacting with your computer will redefine things, Dialogue: 0,0:19:08.19,0:19:11.21,EN,,0,0,0,,and so there's a special exception made for interactive debugging. Dialogue: 0,0:19:11.82,0:19:16.48,EN,,0,0,0,,But define is intended to mean to set up something Dialogue: 0,0:19:18.14,0:19:20.96,EN,,0,0,0,,which will be forever that value after that point. Dialogue: 0,0:19:22.05,0:19:24.54,EN,,0,0,0,,It's as if all the defines were done at the beginning. Dialogue: 0,0:19:26.09,0:19:30.92,EN,,0,0,0,,In fact, the only legal place to put a define in Scheme internal to a procedure Dialogue: 0,0:19:31.02,0:19:33.36,EN,,0,0,0,,is just at the beginning of a lambda expression, Dialogue: 0,0:19:34.47,0:19:37.66,EN,,0,0,0,,which is the beginning of the body of a procedure. Dialogue: 0,0:19:40.40,0:19:45.80,EN,,0,0,0,,Now, let of course does nothing like either of that. Dialogue: 0,0:19:48.09,0:19:49.55,EN,,0,0,0,,I mean, if you look at what's happening with a let, Dialogue: 0,0:19:50.17,0:19:52.13,EN,,0,0,0,,this happens again exactly once. Dialogue: 0,0:19:52.13,0:19:55.82,EN,,0,0,0,,It sets up a context where i and m are values one and one. Dialogue: 0,0:19:56.83,0:20:00.57,EN,,0,0,0,,That context exists throughout this scope, Dialogue: 0,0:20:01.31,0:20:02.80,EN,,0,0,0,,this region of the program. Dialogue: 0,0:20:04.99,0:20:10.12,EN,,0,0,0,,However, you don't think of that let as setting i again. Dialogue: 0,0:20:11.04,0:20:12.16,EN,,0,0,0,,It doesn't change it. Dialogue: 0,0:20:12.16,0:20:14.01,EN,,0,0,0,,i never changes because of the let. Dialogue: 0,0:20:15.28,0:20:16.81,EN,,0,0,0,,i gets created because of let. Dialogue: 0,0:20:18.51,0:20:19.29,EN,,0,0,0,,In fact, Dialogue: 0,0:20:19.73,0:20:21.42,EN,,0,0,0,,the let is a very simple idea. Dialogue: 0,0:20:22.24,0:20:23.59,EN,,0,0,0,,Let does nothing more, Dialogue: 0,0:20:23.59,0:20:31.62,EN,,0,0,0,,Let a variable one to have value one Dialogue: 0,0:20:31.62,0:20:33.50,EN,,0,0,0,,I'll write this down a little bit more neatly; Dialogue: 0,0:20:37.16,0:20:43.73,EN,,0,0,0,,Let's write, var one have value, the value of expression e1, Dialogue: 0,0:20:43.73,0:20:47.36,EN,,0,0,0,,and variable two, have this value of the expression e2, Dialogue: 0,0:20:48.14,0:20:49.74,EN,,0,0,0,,in an expression e3, Dialogue: 0,0:20:51.60,0:21:05.80,EN,,0,0,0,,is the same thing as a procedure of var one and var two, the formal parameters, Dialogue: 0,0:21:06.94,0:21:08.96,EN,,0,0,0,,and e3 being the body, Dialogue: 0,0:21:10.91,0:21:14.00,EN,,0,0,0,,where var one is bound to the value of e1, Dialogue: 0,0:21:14.27,0:21:16.91,EN,,0,0,0,,and var two gets the value of e2. Dialogue: 0,0:21:19.53,0:21:23.26,EN,,0,0,0,,So this is, in fact, a perfectly understandable thing from a substitution point of view. Dialogue: 0,0:21:24.89,0:21:27.95,EN,,0,0,0,,This is really the same expression written in two different ways. Dialogue: 0,0:21:31.69,0:21:33.50,EN,,0,0,0,,In fact, the way the actual system works Dialogue: 0,0:21:33.63,0:21:35.82,EN,,0,0,0,,is this gets translated into this before anything happens. Dialogue: 0,0:21:37.64,0:21:41.77,EN,,0,0,0,,AUDIENCE: OK, I'm still unclear as then what makes the difference between a let and a define. They could-- Dialogue: 0,0:21:41.77,0:21:44.30,EN,,0,0,0,,PROFESSOR: A define is a syntactic sugar, Dialogue: 0,0:21:44.62,0:21:49.10,EN,,0,0,0,,whereby, essentially a bunch of variables get created by lets and then set up once. Dialogue: 0,0:21:57.10,0:21:59.74,EN,,0,0,0,,OK, time for the first break, I think. Thank you. Dialogue: 0,0:22:02.52,0:22:12.84,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:23:04.28,0:23:06.11,EN,,0,0,0,,Well let's see. Dialogue: 0,0:23:06.44,0:23:09.08,EN,,0,0,0,,I now have to rebuild the model of computation, Dialogue: 0,0:23:09.77,0:23:14.16,EN,,0,0,0,,so you understand how some such mechanical mechanism could work Dialogue: 0,0:23:14.91,0:23:16.46,EN,,0,0,0,,that can do what we've just talked about. Dialogue: 0,0:23:17.53,0:23:21.39,EN,,0,0,0,,I just recently destroyed your substitution model. Dialogue: 0,0:23:22.62,0:23:26.03,EN,,0,0,0,,Unfortunately, this model is significantly more complicated than the substitution model. Dialogue: 0,0:23:26.62,0:23:27.93,EN,,0,0,0,,It's called the environment model. Dialogue: 0,0:23:29.02,0:23:31.20,EN,,0,0,0,,And I'm going to have to introduce some terminology, Dialogue: 0,0:23:32.03,0:23:34.51,EN,,0,0,0,,which is very good terminology for you to know anyway. Dialogue: 0,0:23:34.51,0:23:35.74,EN,,0,0,0,,It's about names. Dialogue: 0,0:23:36.51,0:23:39.63,EN,,0,0,0,,And we're going to give names to the kinds of names things have Dialogue: 0,0:23:40.00,0:23:41.31,EN,,0,0,0,,and the way those names are used. Dialogue: 0,0:23:42.48,0:23:47.94,EN,,0,0,0,,So this is a meta-description, if you will. Dialogue: 0,0:23:48.56,0:23:50.85,EN,,0,0,0,,Anyway, there is a pile of an unfortunate terminology here, Dialogue: 0,0:23:50.85,0:23:53.76,EN,,0,0,0,,but we're going to need this to understand what's called the environment model. Dialogue: 0,0:23:54.70,0:23:57.53,EN,,0,0,0,,We're about to do a little bit of boring, dog-work here. Dialogue: 0,0:23:58.04,0:24:01.58,EN,,0,0,0,,Let's look at the first transparency. Dialogue: 0,0:24:02.25,0:24:06.97,EN,,0,0,0,,And we see a description of a word called bound. Dialogue: 0,0:24:08.80,0:24:11.00,EN,,0,0,0,,And we're going to say that a variable, v, Dialogue: 0,0:24:11.00,0:24:12.91,EN,,0,0,0,,is bound in an expression, e, Dialogue: 0,0:24:13.41,0:24:21.52,EN,,0,0,0,,if the meaning of e is unchanged by the uniform replacement of a variable w, Dialogue: 0,0:24:21.56,0:24:24.28,EN,,0,0,0,,not occurrent if for every occurrence of v in e. Dialogue: 0,0:24:25.69,0:24:27.00,EN,,0,0,0,,Now that's a long sentence, Dialogue: 0,0:24:27.37,0:24:29.96,EN,,0,0,0,,so, I think, I'm going to have to say a little bit about that Dialogue: 0,0:24:29.98,0:24:32.62,EN,,0,0,0,,before we even fool around at all here. Dialogue: 0,0:24:33.42,0:24:35.28,EN,,0,0,0,,Bound variables we're talking about here. Dialogue: 0,0:24:44.16,0:24:45.56,EN,,0,0,0,,And you've seen lots of them. Dialogue: 0,0:24:46.07,0:24:48.17,EN,,0,0,0,,You may not know that you've seen lots of them. Dialogue: 0,0:24:48.24,0:24:52.24,EN,,0,0,0,,Well, I suppose in your logic, you saw a logical variables like, Dialogue: 0,0:24:53.27,0:25:00.11,EN,,0,0,0,,for every x there exists a y such that p is true of x and y from your calculus class. Dialogue: 0,0:25:02.88,0:25:05.82,EN,,0,0,0,,This variable, x, and this variable, y, are bound, Dialogue: 0,0:25:07.08,0:25:07.92,EN,,0,0,0,,because, Dialogue: 0,0:25:08.33,0:25:09.98,EN,,0,0,0,,the meaning of this expression Dialogue: 0,0:25:09.98,0:25:15.61,EN,,0,0,0,,does not depend upon the particular letters I used to describe x and y. Dialogue: 0,0:25:16.49,0:25:19.18,EN,,0,0,0,,If I were to change the w for x, Dialogue: 0,0:25:19.84,0:25:25.68,EN,,0,0,0,,then said for every w there exists a y such that p is true of w and y, Dialogue: 0,0:25:25.98,0:25:27.08,EN,,0,0,0,,it would be the same sentence. Dialogue: 0,0:25:29.44,0:25:30.34,EN,,0,0,0,,That's what it means. Dialogue: 0,0:25:30.34,0:25:34.89,EN,,0,0,0,,Or another case of this that you've seen is integral say, Dialogue: 0,0:25:35.40,0:25:42.65,EN,,0,0,0,,from 0 to one of dx over one plus x square. Dialogue: 0,0:25:46.03,0:25:47.92,EN,,0,0,0,,Well that's something you see all the time. Dialogue: 0,0:25:47.92,0:25:50.92,EN,,0,0,0,,And this x is a bound variable. Dialogue: 0,0:25:52.06,0:25:53.79,EN,,0,0,0,,If I change that to a t, Dialogue: 0,0:25:54.15,0:25:56.25,EN,,0,0,0,,the expression is still the same thing. Dialogue: 0,0:25:58.06,0:26:02.76,EN,,0,0,0,,This is a 1/4 of the arctan of one or something here, something like that. Dialogue: 0,0:26:04.70,0:26:06.01,EN,,0,0,0,,Yes, that's the arctan of one. Dialogue: 0,0:26:06.62,0:26:08.76,EN,,0,0,0,,So bound variables are actually fairly common, Dialogue: 0,0:26:09.08,0:26:12.36,EN,,0,0,0,,for those of you who have played a bit with mathematics. Dialogue: 0,0:26:13.26,0:26:17.47,EN,,0,0,0,,Well, let's go into the programming world. Dialogue: 0,0:26:19.02,0:26:21.36,EN,,0,0,0,,Instead of the quantifier being something like, Dialogue: 0,0:26:22.03,0:26:24.06,EN,,0,0,0,,for every, or there exists, or integral, Dialogue: 0,0:26:24.06,0:26:26.43,EN,,0,0,0,,a quantifier is a symbol that binds a variable. Dialogue: 0,0:26:27.47,0:26:28.99,EN,,0,0,0,,And we are going to use the quantifier lambda Dialogue: 0,0:26:29.79,0:26:31.80,EN,,0,0,0,,as being the essential thing that binds variables. Dialogue: 0,0:26:33.80,0:26:36.12,EN,,0,0,0,,And so we have some nice examples here Dialogue: 0,0:26:36.59,0:26:44.14,EN,,0,0,0,,like that procedure of one argument y which does the following thing. Dialogue: 0,0:26:44.14,0:26:46.96,EN,,0,0,0,,It calls the procedure of one argument x, Dialogue: 0,0:26:47.87,0:26:51.13,EN,,0,0,0,,which multiplies x by y, Dialogue: 0,0:26:52.88,0:26:54.52,EN,,0,0,0,,and applies that to three. Dialogue: 0,0:26:58.76,0:27:01.66,EN,,0,0,0,,That procedure has the property there of two bound variables in it, Dialogue: 0,0:27:02.01,0:27:02.92,EN,,0,0,0,,x and y Dialogue: 0,0:27:04.83,0:27:07.47,EN,,0,0,0,,This quantifier, lambda here, binds this y, Dialogue: 0,0:27:07.91,0:27:10.78,EN,,0,0,0,,and this quantifier, lambda, binds that x. Dialogue: 0,0:27:12.11,0:27:17.05,EN,,0,0,0,,Because, if I were to take an arbitrary symbol does not occur in this expression like w Dialogue: 0,0:27:17.98,0:27:21.04,EN,,0,0,0,,and replace all y's with w's in this expression, Dialogue: 0,0:27:21.36,0:27:22.75,EN,,0,0,0,,the expression is still the same, Dialogue: 0,0:27:23.66,0:27:24.80,EN,,0,0,0,,the same procedure. Dialogue: 0,0:27:26.22,0:27:27.41,EN,,0,0,0,,And this is an important idea. Dialogue: 0,0:27:27.41,0:27:29.64,EN,,0,0,0,,The reason why we had such things like that Dialogue: 0,0:27:30.20,0:27:31.41,EN,,0,0,0,,is a kind of modularity. Dialogue: 0,0:27:31.41,0:27:32.86,EN,,0,0,0,,If two people are writing programs, Dialogue: 0,0:27:34.03,0:27:35.26,EN,,0,0,0,,and they work together, Dialogue: 0,0:27:35.26,0:27:40.56,EN,,0,0,0,,it shouldn't matter what names they use internal to their own little machines that they're building. Dialogue: 0,0:27:42.83,0:27:44.67,EN,,0,0,0,,And so, what I'm really telling you there, Dialogue: 0,0:27:45.44,0:27:46.75,EN,,0,0,0,,is that, for example, Dialogue: 0,0:27:46.84,0:27:51.26,EN,,0,0,0,,this is equivalent to that procedure of one argument y which Dialogue: 0,0:27:52.35,0:27:59.23,EN,,0,0,0,,uses that procedure of one argument z which multiplies z by y. Dialogue: 0,0:28:01.64,0:28:03.53,EN,,0,0,0,,Because nobody cares what I used in here. Dialogue: 0,0:28:06.36,0:28:07.24,EN,,0,0,0,,It's a nice example. Dialogue: 0,0:28:08.84,0:28:09.85,EN,,0,0,0,,On the other hand, Dialogue: 0,0:28:11.07,0:28:14.33,EN,,0,0,0,,I have some variables that are not bound. Dialogue: 0,0:28:15.23,0:28:15.96,EN,,0,0,0,,And example, Dialogue: 0,0:28:20.27,0:28:21.76,EN,,0,0,0,,that procedure of one argument x Dialogue: 0,0:28:22.09,0:28:25.04,EN,,0,0,0,,which multiplies x by y Dialogue: 0,0:28:27.28,0:28:28.16,EN,,0,0,0,,In this case, Dialogue: 0,0:28:29.45,0:28:30.75,EN,,0,0,0,,y is not bound. Dialogue: 0,0:28:32.46,0:28:34.27,EN,,0,0,0,,Supposing y had the value three, Dialogue: 0,0:28:35.26,0:28:36.80,EN,,0,0,0,,and z had the value four, Dialogue: 0,0:28:38.83,0:28:44.27,EN,,0,0,0,,then this procedure would be the thing that multiplies its argument by three. Dialogue: 0,0:28:44.86,0:28:47.39,EN,,0,0,0,,If I were to replace every instance of y with z, Dialogue: 0,0:28:47.52,0:28:51.96,EN,,0,0,0,,I would have a different procedure which multiplies every argument that's given by four. Dialogue: 0,0:28:53.87,0:28:56.40,EN,,0,0,0,,And, in fact, we have a name for such a variable. Dialogue: 0,0:28:57.76,0:29:04.01,EN,,0,0,0,,Here, we say that a variable, v, is free in the expression, e, Dialogue: 0,0:29:04.01,0:29:09.42,EN,,0,0,0,,if the meaning of the expression, e, is changed by the uniform replacement of a variable, w, not occurring in e, Dialogue: 0,0:29:09.58,0:29:11.15,EN,,0,0,0,,for every occurrence of v and e. Dialogue: 0,0:29:13.26,0:29:13.71,EN,,0,0,0,,So, Dialogue: 0,0:29:14.49,0:29:22.76,EN,,0,0,0,,So that's why this variable over here, y, is a free variable. Dialogue: 0,0:29:29.16,0:29:32.27,EN,,0,0,0,,And so free variables in this expression-- Dialogue: 0,0:29:33.76,0:29:35.18,EN,,0,0,0,,And other examples of that is that Dialogue: 0,0:29:36.17,0:29:39.32,EN,,0,0,0,,is that procedure of one argument y, Dialogue: 0,0:29:40.43,0:29:42.00,EN,,0,0,0,,which is just what we had before, Dialogue: 0,0:29:42.27,0:29:44.60,EN,,0,0,0,,which uses that procedure of one argument x Dialogue: 0,0:29:45.08,0:29:48.54,EN,,0,0,0,,that multiplies x by y-- Dialogue: 0,0:29:51.40,0:29:52.65,EN,,0,0,0,,use that on three. Dialogue: 0,0:29:57.24,0:30:00.35,EN,,0,0,0,,This procedure has a free variable in it Dialogue: 0,0:30:00.92,0:30:01.98,EN,,0,0,0,,which is asterisk. Dialogue: 0,0:30:05.00,0:30:05.89,EN,,0,0,0,,See, because, Dialogue: 0,0:30:05.89,0:30:08.08,EN,,0,0,0,,if that has a normal meaning of multiplication, Dialogue: 0,0:30:09.44,0:30:12.78,EN,,0,0,0,,then if I were to replace uniformly all asterisks with pluses, Dialogue: 0,0:30:14.25,0:30:16.38,EN,,0,0,0,,then the meaning of this expression would change. Dialogue: 0,0:30:19.34,0:30:20.76,EN,,0,0,0,,That's what you mean by a free variable. Dialogue: 0,0:30:22.68,0:30:24.81,EN,,0,0,0,,So, so far you've learned some logician words Dialogue: 0,0:30:25.64,0:30:27.58,EN,,0,0,0,,which describe the way names are used. Dialogue: 0,0:30:28.94,0:30:31.26,EN,,0,0,0,,Now, we have to do a little bit more playing around here, Dialogue: 0,0:30:32.96,0:30:33.72,EN,,0,0,0,,a little bit more. Dialogue: 0,0:30:35.13,0:30:36.22,EN,,0,0,0,,I want to tell you about Dialogue: 0,0:30:36.81,0:30:39.76,EN,,0,0,0,,about the regions are over which variables are defined. Dialogue: 0,0:30:42.17,0:30:42.88,EN,,0,0,0,,You see, Dialogue: 0,0:30:43.37,0:30:45.69,EN,,0,0,0,,we've been very informal about this up till now, Dialogue: 0,0:30:46.33,0:30:50.16,EN,,0,0,0,,and, of course, many of you have probably understood very clearly or most of you, Dialogue: 0,0:30:50.36,0:30:52.84,EN,,0,0,0,,that the x that's being declared here Dialogue: 0,0:30:53.64,0:30:55.18,EN,,0,0,0,,is defined only in here. Dialogue: 0,0:30:58.28,0:31:00.91,EN,,0,0,0,,This x is the defined only in here, Dialogue: 0,0:31:01.61,0:31:04.33,EN,,0,0,0,,and this y is defined only in here. Dialogue: 0,0:31:07.10,0:31:09.16,EN,,0,0,0,,We have a name for such an idea. It's called a scope. Dialogue: 0,0:31:11.61,0:31:13.58,EN,,0,0,0,,And let me give you another piece of terminology. Dialogue: 0,0:31:14.70,0:31:15.77,EN,,0,0,0,,It's a long story. Dialogue: 0,0:31:15.96,0:31:17.64,EN,,0,0,0,,If x is a bound variable in e, Dialogue: 0,0:31:18.16,0:31:20.24,EN,,0,0,0,,then there is a lambda expression where it is bound. Dialogue: 0,0:31:20.89,0:31:24.91,EN,,0,0,0,,So the only way you can get a bound variable ultimately is by lambda expression. Dialogue: 0,0:31:24.91,0:31:25.96,EN,,0,0,0,,Then you may worry, Dialogue: 0,0:31:26.22,0:31:29.05,EN,,0,0,0,,does define quite an exception to this? Dialogue: 0,0:31:29.64,0:31:32.92,EN,,0,0,0,,And it turns out, we could always arrange things so you don't need any defines. Dialogue: 0,0:31:32.92,0:31:33.96,EN,,0,0,0,,And we'll see that in a while. Dialogue: 0,0:31:34.24,0:31:35.72,EN,,0,0,0,,It's a very magical thing. Dialogue: 0,0:31:36.54,0:31:38.40,EN,,0,0,0,,So define really can go away. Dialogue: 0,0:31:38.68,0:31:41.55,EN,,0,0,0,,The really, only thing that makes names is lambda . Dialogue: 0,0:31:42.64,0:31:43.40,EN,,0,0,0,,That's its job. Dialogue: 0,0:31:44.30,0:31:46.23,EN,,0,0,0,,And what's so amazing about a lot of things Dialogue: 0,0:31:46.23,0:31:47.87,EN,,0,0,0,,is you can compute with only lambda. Dialogue: 0,0:31:48.73,0:31:49.58,EN,,0,0,0,,But, in any case, Dialogue: 0,0:31:51.74,0:31:55.76,EN,,0,0,0,,a lambda expression has a place where it declares a variable. Dialogue: 0,0:31:55.76,0:31:57.10,EN,,0,0,0,,We call it the formal parameter list Dialogue: 0,0:31:58.94,0:32:00.56,EN,,0,0,0,,and we say or the bound variable list. Dialogue: 0,0:32:01.26,0:32:04.51,EN,,0,0,0,,We say that the lambda expression binds -- so it's a verb Dialogue: 0,0:32:05.02,0:32:07.34,EN,,0,0,0,,--binds the variables declared in it's bound variable list. Dialogue: 0,0:32:08.59,0:32:12.48,EN,,0,0,0,,In addition, those parts of the expression where the variable is defined, Dialogue: 0,0:32:13.23,0:32:15.23,EN,,0,0,0,,which was declared by some declaration Dialogue: 0,0:32:15.56,0:32:19.26,EN,,0,0,0,,is called the scope of that variable. Dialogue: 0,0:32:20.44,0:32:21.92,EN,,0,0,0,,So these are scopes. Dialogue: 0,0:32:22.25,0:32:23.68,EN,,0,0,0,,This is the scope of y. Dialogue: 0,0:32:27.16,0:32:28.54,EN,,0,0,0,,And this is the scope of x-- Dialogue: 0,0:32:33.10,0:32:34.03,EN,,0,0,0,,that sort of thing. Dialogue: 0,0:32:41.32,0:32:42.08,EN,,0,0,0,,OK, Dialogue: 0,0:32:43.93,0:32:45.63,EN,,0,0,0,,well, now we have enough terminology Dialogue: 0,0:32:46.60,0:32:51.76,EN,,0,0,0,,to begin to understand how to make a new model for computation Dialogue: 0,0:32:51.96,0:32:53.77,EN,,0,0,0,,because the key thing going on here Dialogue: 0,0:32:54.94,0:32:57.00,EN,,0,0,0,,is that we destroyed the substitution model, Dialogue: 0,0:32:57.18,0:32:58.38,EN,,0,0,0,,and we now have to have a model Dialogue: 0,0:32:58.62,0:33:02.32,EN,,0,0,0,,that represents the names as referring to places. Dialogue: 0,0:33:03.93,0:33:05.34,EN,,0,0,0,,Because if we are going to change something, Dialogue: 0,0:33:05.98,0:33:07.47,EN,,0,0,0,,then we have a place where it's stored. Dialogue: 0,0:33:09.56,0:33:10.35,EN,,0,0,0,,You see, Dialogue: 0,0:33:10.83,0:33:13.31,EN,,0,0,0,,if a name only refers to a value, Dialogue: 0,0:33:14.04,0:33:16.36,EN,,0,0,0,,and if I tried to change the name's meaning, Dialogue: 0,0:33:16.73,0:33:20.32,EN,,0,0,0,,well, that's not clear. Dialogue: 0,0:33:20.32,0:33:24.68,EN,,0,0,0,,There's nothing that is the place that that name referred to. Dialogue: 0,0:33:24.99,0:33:25.80,EN,,0,0,0,,How am I really saying it? Dialogue: 0,0:33:25.92,0:33:29.54,EN,,0,0,0,,There're nothing shared among all of the instances of that name. Dialogue: 0,0:33:29.87,0:33:31.68,EN,,0,0,0,,And what we really mean, by a name, Dialogue: 0,0:33:31.68,0:33:32.97,EN,,0,0,0,,is that we find something out. Dialogue: 0,0:33:34.33,0:33:36.36,EN,,0,0,0,,We've given something a name, and you have it, Dialogue: 0,0:33:36.73,0:33:39.06,EN,,0,0,0,,and you have it, because I'm given you a reference to it, Dialogue: 0,0:33:39.06,0:33:40.44,EN,,0,0,0,,and I've given you a reference to it. Dialogue: 0,0:33:41.02,0:33:42.30,EN,,0,0,0,,And we'll see a lot about that. Dialogue: 0,0:33:43.61,0:33:45.21,EN,,0,0,0,,So let me tell you about environments. Dialogue: 0,0:33:46.19,0:33:48.76,EN,,0,0,0,,I need the overhead projection machine, Dialogue: 0,0:33:49.31,0:33:49.98,EN,,0,0,0,,thank you. Dialogue: 0,0:33:52.19,0:33:53.02,EN,,0,0,0,,And so here Dialogue: 0,0:33:55.48,0:34:00.40,EN,,0,0,0,,is a bunch of environment structures. Dialogue: 0,0:34:01.53,0:34:05.76,EN,,0,0,0,,An environment is a way of doing substitutions virtually. Dialogue: 0,0:34:06.38,0:34:07.89,EN,,0,0,0,,It represents a place Dialogue: 0,0:34:07.89,0:34:11.39,EN,,0,0,0,,where something is stored which is the substitutions that you haven't done. Dialogue: 0,0:34:13.34,0:34:16.50,EN,,0,0,0,,It's a place where everything accumulates, Dialogue: 0,0:34:16.50,0:34:21.13,EN,,0,0,0,,where the names of the variables are associated with the values they have Dialogue: 0,0:34:21.79,0:34:22.56,EN,,0,0,0,,such that, Dialogue: 0,0:34:22.75,0:34:25.90,EN,,0,0,0,,when you say, what dose this name mean, Dialogue: 0,0:34:25.90,0:34:27.40,EN,,0,0,0,,you look it up in an environment. Dialogue: 0,0:34:28.08,0:34:29.48,EN,,0,0,0,,So an environment is a function, Dialogue: 0,0:34:30.80,0:34:31.48,EN,,0,0,0,,or a table, Dialogue: 0,0:34:32.22,0:34:33.24,EN,,0,0,0,,or something like that. Dialogue: 0,0:34:33.24,0:34:34.89,EN,,0,0,0,,But it's a structured sort of table. Dialogue: 0,0:34:35.76,0:34:37.39,EN,,0,0,0,,It's made out of things called frames. Dialogue: 0,0:34:41.13,0:34:44.46,EN,,0,0,0,,Frames are pieces of environment, Dialogue: 0,0:34:44.89,0:34:46.01,EN,,0,0,0,,and they are chained together, Dialogue: 0,0:34:47.07,0:34:48.19,EN,,0,0,0,,in some nice ways, Dialogue: 0,0:34:49.00,0:34:52.09,EN,,0,0,0,,by what's called parent links or something like that. Dialogue: 0,0:34:54.03,0:34:55.02,EN,,0,0,0,,So here, Dialogue: 0,0:34:55.64,0:34:57.62,EN,,0,0,0,,we have an environment structure Dialogue: 0,0:34:57.62,0:35:04.22,EN,,0,0,0,,consisting of three environments, basically, A, B, and C. Dialogue: 0,0:35:05.10,0:35:07.63,EN,,0,0,0,,d is also an environment, but it's the same one, Dialogue: 0,0:35:08.88,0:35:10.17,EN,,0,0,0,,they share. Dialogue: 0,0:35:11.45,0:35:13.96,EN,,0,0,0,,And that's the essence of assignment. Dialogue: 0,0:35:14.40,0:35:16.10,EN,,0,0,0,,If I change a variable, Dialogue: 0,0:35:16.10,0:35:19.80,EN,,0,0,0,,a value of a valuable that lives here, like that one, Dialogue: 0,0:35:19.80,0:35:23.50,EN,,0,0,0,,it should be visible from all places that you're looking at it from. Dialogue: 0,0:35:23.50,0:35:24.84,EN,,0,0,0,,Take this one, x. Dialogue: 0,0:35:24.84,0:35:28.19,EN,,0,0,0,,If I change the x to four, Dialogue: 0,0:35:28.19,0:35:30.19,EN,,0,0,0,,it's visible from other places. Dialogue: 0,0:35:30.19,0:35:32.19,EN,,0,0,0,,But I'm not going to worry about that right now. Dialogue: 0,0:35:32.19,0:35:33.84,EN,,0,0,0,,We're going to talk a lot about that in a little while. Dialogue: 0,0:35:34.56,0:35:35.53,EN,,0,0,0,,What do we have here? Dialogue: 0,0:35:36.76,0:35:38.84,EN,,0,0,0,,Well, these are called frames. Here is a frame, Dialogue: 0,0:35:39.40,0:35:40.38,EN,,0,0,0,,here's a frame Dialogue: 0,0:35:40.76,0:35:41.84,EN,,0,0,0,,and here's a frame. Dialogue: 0,0:35:43.18,0:35:45.20,EN,,0,0,0,,A is an environment which consists of Dialogue: 0,0:35:45.20,0:35:47.82,EN,,0,0,0,,the table label which is frame two, Dialogue: 0,0:35:48.36,0:35:51.05,EN,,0,0,0,,followed by the table labeled frame one. Dialogue: 0,0:35:52.52,0:35:54.60,EN,,0,0,0,,And, in this environment, Dialogue: 0,0:35:54.99,0:35:59.68,EN,,0,0,0,,in C, this environment, frame two, Dialogue: 0,0:36:00.48,0:36:03.26,EN,,0,0,0,,uh....x and y are bound. Dialogue: 0,0:36:04.06,0:36:04.78,EN,,0,0,0,,They have values. Dialogue: 0,0:36:05.26,0:36:07.18,EN,,0,0,0,,Sorry, in frame one Dialogue: 0,0:36:07.18,0:36:08.28,EN,,0,0,0,,In frame two, Dialogue: 0,0:36:09.72,0:36:10.83,EN,,0,0,0,,z is bound, Dialogue: 0,0:36:10.99,0:36:12.17,EN,,0,0,0,,and x is bound, Dialogue: 0,0:36:12.44,0:36:13.69,EN,,0,0,0,,and y is bound, Dialogue: 0,0:36:15.24,0:36:17.40,EN,,0,0,0,,but the value of x that we see, Dialogue: 0,0:36:17.42,0:36:19.04,EN,,0,0,0,,looking from this point of view, Dialogue: 0,0:36:20.01,0:36:21.74,EN,,0,0,0,,is this x. It's x is seven, Dialogue: 0,0:36:22.36,0:36:24.84,EN,,0,0,0,,rather than this one which is three. Dialogue: 0,0:36:24.84,0:36:27.61,EN,,0,0,0,,We say that this x shadows this x. Dialogue: 0,0:36:31.05,0:36:32.49,EN,,0,0,0,,From environment three-- Dialogue: 0,0:36:33.44,0:36:34.45,EN,,0,0,0,,from frame three, Dialogue: 0,0:36:34.45,0:36:35.73,EN,,0,0,0,,from environment b, Dialogue: 0,0:36:35.73,0:36:37.18,EN,,0,0,0,,which refers to frame three, Dialogue: 0,0:36:37.45,0:36:42.12,EN,,0,0,0,,we have variables m and y bound and also x. Dialogue: 0,0:36:44.84,0:36:46.97,EN,,0,0,0,,This y shadow this one. Dialogue: 0,0:36:48.65,0:36:51.00,EN,,0,0,0,,So the value, looking from this point of view, Dialogue: 0,0:36:51.10,0:36:52.65,EN,,0,0,0,,of y is two. Dialogue: 0,0:36:53.45,0:36:55.28,EN,,0,0,0,,The value for looking from this point of view Dialogue: 0,0:36:55.28,0:36:58.64,EN,,0,0,0,,and m is one. And the value, looking from this point of view, of x is three. Dialogue: 0,0:37:02.22,0:37:03.15,EN,,0,0,0,,So there we have Dialogue: 0,0:37:03.15,0:37:05.52,EN,,0,0,0,,a very simple environment structure made out of frames. Dialogue: 0,0:37:06.38,0:37:09.80,EN,,0,0,0,,These correspond to the applications of procedures. Dialogue: 0,0:37:10.94,0:37:12.17,EN,,0,0,0,,And we'll see that in a second. Dialogue: 0,0:37:14.41,0:37:17.60,EN,,0,0,0,,So now I have to make you some other nice little structure that we build. Dialogue: 0,0:37:20.75,0:37:21.71,EN,,0,0,0,,Next slide, Dialogue: 0,0:37:22.14,0:37:24.36,EN,,0,0,0,,we see an object, Dialogue: 0,0:37:24.84,0:37:26.54,EN,,0,0,0,,which I'm going to draw procedures. Dialogue: 0,0:37:27.93,0:37:28.94,EN,,0,0,0,,This is a procedure. Dialogue: 0,0:37:30.11,0:37:31.90,EN,,0,0,0,,A procedure is made out of two parts. Dialogue: 0,0:37:33.10,0:37:34.80,EN,,0,0,0,,It's sort of like a cons. Dialogue: 0,0:37:37.21,0:37:38.38,EN,,0,0,0,,However, it's the two parts. Dialogue: 0,0:37:40.84,0:37:44.72,EN,,0,0,0,,The first part refers to some code, Dialogue: 0,0:37:45.69,0:37:46.94,EN,,0,0,0,,something that can be executed, Dialogue: 0,0:37:47.42,0:37:50.00,EN,,0,0,0,,a set of instructions, if you will. You can think of it that way. Dialogue: 0,0:37:50.68,0:37:52.83,EN,,0,0,0,,And the second part is the environment. Dialogue: 0,0:37:53.88,0:37:55.50,EN,,0,0,0,,The procedure is the whole thing. Dialogue: 0,0:37:57.16,0:37:58.40,EN,,0,0,0,,And we're going to have to use this Dialogue: 0,0:37:58.71,0:38:05.16,EN,,0,0,0,,to capture the values of the free variables that occur in the procedure. Dialogue: 0,0:38:06.17,0:38:08.09,EN,,0,0,0,,If a variable occurs in the procedure Dialogue: 0,0:38:08.11,0:38:09.92,EN,,0,0,0,,it's either bound in that procedure or free. Dialogue: 0,0:38:11.10,0:38:11.96,EN,,0,0,0,,If it's bound, Dialogue: 0,0:38:12.57,0:38:14.56,EN,,0,0,0,,then the value will somehow be easy to find. Dialogue: 0,0:38:16.11,0:38:18.64,EN,,0,0,0,,It will be in some easy environment to get at. Dialogue: 0,0:38:18.91,0:38:19.87,EN,,0,0,0,,If it's free, Dialogue: 0,0:38:20.86,0:38:23.02,EN,,0,0,0,,we're going to have to have something that goes with the procedure Dialogue: 0,0:38:23.02,0:38:24.81,EN,,0,0,0,,that says where we'll go look for its value. Dialogue: 0,0:38:27.05,0:38:29.21,EN,,0,0,0,,And the reasons why are not obvious yet, Dialogue: 0,0:38:29.21,0:38:30.60,EN,,0,0,0,,but will be soon. Dialogue: 0,0:38:32.32,0:38:34.97,EN,,0,0,0,,So here's a procedure object. It's a composite object Dialogue: 0,0:38:35.34,0:38:41.64,EN,,0,0,0,,consisting of a piece of code and a environment structure. Dialogue: 0,0:38:42.72,0:38:45.50,EN,,0,0,0,,Now I will tell you the new rules, the complete new rules, Dialogue: 0,0:38:46.41,0:38:47.47,EN,,0,0,0,,for evaluation. Dialogue: 0,0:38:50.54,0:38:52.20,EN,,0,0,0,,The first rule is-- there's only two of them. Dialogue: 0,0:38:53.20,0:38:55.39,EN,,0,0,0,,These correspond to the substitution model rules. Dialogue: 0,0:38:57.26,0:38:59.32,EN,,0,0,0,,And the first one has to do with Dialogue: 0,0:38:59.66,0:39:02.78,EN,,0,0,0,,how do you apply a procedure to its arguments? Dialogue: 0,0:39:05.28,0:39:08.54,EN,,0,0,0,,Okay, And a procedural object is applied to a set of arguments Dialogue: 0,0:39:08.96,0:39:10.43,EN,,0,0,0,,by constructing a new frame. Dialogue: 0,0:39:11.31,0:39:15.76,EN,,0,0,0,,That frame will contain the mapping of the former parameters to the actual parameters Dialogue: 0,0:39:15.83,0:39:19.48,EN,,0,0,0,,of the arguments that were supplied in the call. Dialogue: 0,0:39:21.42,0:39:22.20,EN,,0,0,0,,As you know, Dialogue: 0,0:39:22.31,0:39:26.94,EN,,0,0,0,,when we make up a call to a procedure like lambda x times x y, Dialogue: 0,0:39:26.94,0:39:29.13,EN,,0,0,0,,and we call that with the argument three, Dialogue: 0,0:39:30.19,0:39:32.75,EN,,0,0,0,,then we're going to need some mapping of x to three. Dialogue: 0,0:39:34.19,0:39:37.39,EN,,0,0,0,,It's the same thing as later substituting, if you will Dialogue: 0,0:39:38.27,0:39:40.30,EN,,0,0,0,,the three for the x in the old model. Dialogue: 0,0:39:42.00,0:39:44.80,EN,,0,0,0,,So I'm going to build a frame which contains x equals three Dialogue: 0,0:39:45.15,0:39:46.60,EN,,0,0,0,,as the information in that frame. Dialogue: 0,0:39:49.12,0:39:49.71,EN,,0,0,0,,Now, Dialogue: 0,0:39:50.33,0:39:53.31,EN,,0,0,0,,the body of the procedure will then have to be evaluated which is this, Dialogue: 0,0:39:54.16,0:39:56.44,EN,,0,0,0,,and will be evaluated in an environment Dialogue: 0,0:39:57.80,0:40:08.03,EN,,0,0,0,,which is constructed by adjoining the new frame that we just made Dialogue: 0,0:40:08.54,0:40:11.69,EN,,0,0,0,,to the environment which was part of the procedure that we applied. Dialogue: 0,0:40:13.15,0:40:15.77,EN,,0,0,0,,So I'm going to make a little example of that here. Dialogue: 0,0:40:19.20,0:40:24.12,EN,,0,0,0,,Supposing I have some environment. Dialogue: 0,0:40:25.15,0:40:27.23,EN,,0,0,0,,Here's a frame which represents it. Dialogue: 0,0:40:27.96,0:40:32.19,EN,,0,0,0,,And some procedure-- which I'm going to draw with circles here because it's easier than little triangles-- Dialogue: 0,0:40:33.04,0:40:36.36,EN,,0,0,0,,Ummm.. sorry, those are rhombuses, Dialogue: 0,0:40:37.66,0:40:40.78,EN,,0,0,0,,rhomboidal little pieces of fruit jelly or something. Dialogue: 0,0:40:42.68,0:40:45.32,EN,,0,0,0,,So here's a procedure which takes this environment. Dialogue: 0,0:40:45.95,0:40:48.16,EN,,0,0,0,,And the procedure has a piece of code, Dialogue: 0,0:40:48.16,0:40:49.68,EN,,0,0,0,,which is a lambda expression, Dialogue: 0,0:40:50.12,0:40:51.69,EN,,0,0,0,,which binds x and y Dialogue: 0,0:40:53.15,0:40:56.43,EN,,0,0,0,,and then executes an expression, e. Dialogue: 0,0:40:57.93,0:40:58.99,EN,,0,0,0,,And this is the procedure. Dialogue: 0,0:40:59.56,0:41:00.57,EN,,0,0,0,,We'll call it p. Dialogue: 0,0:41:01.44,0:41:05.79,EN,,0,0,0,,I wish to apply that procedure to three and four. Dialogue: 0,0:41:06.38,0:41:08.36,EN,,0,0,0,,So I want to do p of three and four. Dialogue: 0,0:41:09.76,0:41:12.17,EN,,0,0,0,,What I'm going to do, of course, is make a new frame. Dialogue: 0,0:41:13.15,0:41:14.12,EN,,0,0,0,,I build a frame Dialogue: 0,0:41:15.24,0:41:18.28,EN,,0,0,0,,which contains x equals three, Dialogue: 0,0:41:18.84,0:41:20.51,EN,,0,0,0,,and y equals four. Dialogue: 0,0:41:21.69,0:41:23.48,EN,,0,0,0,,I'm going to connect that frame Dialogue: 0,0:41:24.27,0:41:25.37,EN,,0,0,0,,to this frame over here. Dialogue: 0,0:41:27.63,0:41:28.99,EN,,0,0,0,,And then this environment, Dialogue: 0,0:41:29.68,0:41:30.97,EN,,0,0,0,,with I will call b, Dialogue: 0,0:41:31.55,0:41:35.02,EN,,0,0,0,,is the environment in which I will evaluate the body of e. Dialogue: 0,0:41:39.88,0:41:40.33,EN,,0,0,0,,Now, Dialogue: 0,0:41:41.95,0:41:45.04,EN,,0,0,0,,e may contain references to x and y and other things. Dialogue: 0,0:41:46.84,0:41:49.95,EN,,0,0,0,,x and y will have values right here. Dialogue: 0,0:41:50.70,0:41:52.52,EN,,0,0,0,,Other things will have their values here. Dialogue: 0,0:41:55.05,0:41:56.25,EN,,0,0,0,,How do we get this frame? Dialogue: 0,0:41:57.26,0:41:59.26,EN,,0,0,0,,That we do by the construction of procedures Dialogue: 0,0:41:59.61,0:42:00.60,EN,,0,0,0,,which is the other rule. Dialogue: 0,0:42:02.03,0:42:04.40,EN,,0,0,0,,And I think that's the next slide. Dialogue: 0,0:42:05.34,0:42:06.12,EN,,0,0,0,,Rule two, Dialogue: 0,0:42:07.80,0:42:09.90,EN,,0,0,0,,when a lambda expression is evaluated, Dialogue: 0,0:42:09.90,0:42:11.76,EN,,0,0,0,,relative to a particular environment-- Dialogue: 0,0:42:14.19,0:42:14.40,EN,,0,0,0,,See, Dialogue: 0,0:42:15.04,0:42:18.12,EN,,0,0,0,,the way I get a procedure is by evaluating the lambda expression. Dialogue: 0,0:42:18.19,0:42:19.36,EN,,0,0,0,,Here's a lambda expression. Dialogue: 0,0:42:20.04,0:42:21.12,EN,,0,0,0,,By evaluating it, Dialogue: 0,0:42:21.90,0:42:23.96,EN,,0,0,0,,I get a procedure which I can apply to three. Dialogue: 0,0:42:25.08,0:42:26.65,EN,,0,0,0,,Now this lambda expression Dialogue: 0,0:42:26.65,0:42:30.38,EN,,0,0,0,,is evaluated in an environment where y is defined. Dialogue: 0,0:42:31.84,0:42:35.84,EN,,0,0,0,,And I want the body of this which contains a free version of y. Dialogue: 0,0:42:36.39,0:42:38.36,EN,,0,0,0,,y is free in here, Dialogue: 0,0:42:38.72,0:42:40.38,EN,,0,0,0,,it's bound over the whole thing, Dialogue: 0,0:42:41.36,0:42:42.75,EN,,0,0,0,,but it's free over here. Dialogue: 0,0:42:43.32,0:42:46.24,EN,,0,0,0,,I want that y to be this one. Dialogue: 0,0:42:47.44,0:42:55.13,EN,,0,0,0,,I evaluate this body of this procedure in the environment where y was created. Dialogue: 0,0:42:55.32,0:42:58.40,EN,,0,0,0,,That's this kind of thing, because that was done by application. Dialogue: 0,0:42:59.00,0:42:59.63,EN,,0,0,0,,Now, Dialogue: 0,0:43:00.24,0:43:02.60,EN,,0,0,0,,if I ever want to look up the value of y, Dialogue: 0,0:43:03.10,0:43:04.09,EN,,0,0,0,,I have to know where it is. Dialogue: 0,0:43:04.54,0:43:06.42,EN,,0,0,0,,Therefore, this procedural was created, Dialogue: 0,0:43:06.42,0:43:10.06,EN,,0,0,0,,the creation of the procedure which is the result of evaluating that lambda expression Dialogue: 0,0:43:10.06,0:43:16.33,EN,,0,0,0,,had better capture a pointer or remember the frame in which y was bound. Dialogue: 0,0:43:17.92,0:43:19.76,EN,,0,0,0,,So that's what this rule is telling us. Dialogue: 0,0:43:22.11,0:43:23.13,EN,,0,0,0,,So, for example, Dialogue: 0,0:43:24.44,0:43:29.32,EN,,0,0,0,,if I happen to be evaluating a lambda expression, Dialogue: 0,0:43:30.89,0:43:33.32,EN,,0,0,0,,lambda expression in e, Dialogue: 0,0:43:34.04,0:43:40.46,EN,,0,0,0,,lambda of say, x and y, let's call it g in e, Dialogue: 0,0:43:41.08,0:43:42.36,EN,,0,0,0,,evaluating that. Dialogue: 0,0:43:42.97,0:43:46.17,EN,,0,0,0,,all that means is I now construct a procedure object. Dialogue: 0,0:43:47.10,0:43:48.28,EN,,0,0,0,,e is some environment. Dialogue: 0,0:43:48.84,0:43:50.94,EN,,0,0,0,,e is something which has a pointer to it. Dialogue: 0,0:43:51.79,0:43:56.68,EN,,0,0,0,,I construct a procedure object that points up to that environment, Dialogue: 0,0:43:58.56,0:44:00.11,EN,,0,0,0,,where the code of that Dialogue: 0,0:44:00.54,0:44:03.24,EN,,0,0,0,,is a lambda expression or whatever that translates into. Dialogue: 0,0:44:06.24,0:44:07.56,EN,,0,0,0,,And this is the procedure. Dialogue: 0,0:44:12.38,0:44:14.70,EN,,0,0,0,,So this produces for me-- this -- this Dialogue: 0,0:44:14.94,0:44:16.37,EN,,0,0,0,,this object here, Dialogue: 0,0:44:16.37,0:44:18.12,EN,,0,0,0,,this environment pointer, Dialogue: 0,0:44:18.37,0:44:22.52,EN,,0,0,0,,captures the place where this lambda expression was evaluated, Dialogue: 0,0:44:22.62,0:44:24.59,EN,,0,0,0,,where the definition was used, Dialogue: 0,0:44:25.58,0:44:27.40,EN,,0,0,0,,where the definition was used to make a procedure, Dialogue: 0,0:44:30.32,0:44:31.47,EN,,0,0,0,,to make the procedure. Dialogue: 0,0:44:32.89,0:44:36.30,EN,,0,0,0,,So it picks up the environment from the place where that procedure was defined, Dialogue: 0,0:44:37.42,0:44:38.92,EN,,0,0,0,,stores it in the procedure itself, Dialogue: 0,0:44:39.60,0:44:40.97,EN,,0,0,0,,and then when the procedure is used, Dialogue: 0,0:44:41.32,0:44:43.47,EN,,0,0,0,,the environment where it was defined is extended Dialogue: 0,0:44:43.98,0:44:45.07,EN,,0,0,0,,with the new frame. Dialogue: 0,0:44:48.72,0:44:52.33,EN,,0,0,0,,So this gives us a locus for putting where a variable has a value. Dialogue: 0,0:44:53.04,0:44:53.96,EN,,0,0,0,,And, for example, Dialogue: 0,0:44:53.96,0:44:56.81,EN,,0,0,0,,if there are lots of guys pointing in at that environment, Dialogue: 0,0:44:57.74,0:45:00.33,EN,,0,0,0,,then they share that place. Dialogue: 0,0:45:01.20,0:45:02.52,EN,,0,0,0,,And we'll see more of that shortly. Dialogue: 0,0:45:04.01,0:45:05.34,EN,,0,0,0,,Well, now you have a new model Dialogue: 0,0:45:06.38,0:45:09.92,EN,,0,0,0,,for understanding the execution of programs. Dialogue: 0,0:45:11.36,0:45:12.78,EN,,0,0,0,,I suppose I'll take questions now, Dialogue: 0,0:45:13.10,0:45:14.96,EN,,0,0,0,,and then we'll go on and use that for something. Dialogue: 0,0:45:18.19,0:45:19.52,EN,,0,0,0,,AUDIENCE: Is it right to say then, Dialogue: 0,0:45:19.52,0:45:23.96,EN,,0,0,0,,the environment is that linked chain of frames starting with-- Dialogue: 0,0:45:23.96,0:45:25.10,EN,,0,0,0,,PROFESSOR: That's right. Dialogue: 0,0:45:25.48,0:45:26.64,EN,,0,0,0,,AUDIENCE: working all the way back? Dialogue: 0,0:45:27.71,0:45:31.45,EN,,0,0,0,,PROFESSOR: Yes, the environment is a sequence of frames linked together. Dialogue: 0,0:45:32.43,0:45:35.47,EN,,0,0,0,,And the way I like to think about it, it's the pointer to the first one, Dialogue: 0,0:45:36.88,0:45:38.72,EN,,0,0,0,,because once you've got that you've got them all. Dialogue: 0,0:45:43.96,0:45:44.65,EN,,0,0,0,,Anybody else? Dialogue: 0,0:45:45.20,0:45:49.36,EN,,0,0,0,,AUDIENCE: Is it possible to evaluate a procedure or to define a procedure in two different environments Dialogue: 0,0:45:49.36,0:45:53.20,EN,,0,0,0,,such that it will behave differently, and have pointers to both-- Dialogue: 0,0:45:53.20,0:45:55.77,EN,,0,0,0,,PROFESSOR: Oh, yes. The same procedure is not going to have two different environments. Dialogue: 0,0:45:56.90,0:45:59.02,EN,,0,0,0,,The same code, Dialogue: 0,0:45:59.02,0:46:00.82,EN,,0,0,0,,the same lambda expression Dialogue: 0,0:46:00.82,0:46:03.72,EN,,0,0,0,,can be evaluated in two environments producing two different procedures. Dialogue: 0,0:46:06.03,0:46:07.18,EN,,0,0,0,,Each procedure-- Dialogue: 0,0:46:07.18,0:46:09.95,EN,,0,0,0,,AUDIENCE: Their definition has the same name. Their operation-- Dialogue: 0,0:46:09.95,0:46:11.92,EN,,0,0,0,,PROFESSOR: The definition is written the same, with the same characters. Dialogue: 0,0:46:12.56,0:46:14.62,EN,,0,0,0,,I can evaluate that set of characters, Dialogue: 0,0:46:14.93,0:46:18.14,EN,,0,0,0,,whatever, that list structure that defines, Dialogue: 0,0:46:18.22,0:46:20.41,EN,,0,0,0,,that is the textual representation. Dialogue: 0,0:46:20.91,0:46:24.86,EN,,0,0,0,,I can evaluate that in two different environments producing two different procedures. Dialogue: 0,0:46:25.55,0:46:26.84,EN,,0,0,0,,Each of those procedures Dialogue: 0,0:46:27.56,0:46:32.19,EN,,0,0,0,,has its own local sets of variables, Dialogue: 0,0:46:32.34,0:46:33.45,EN,,0,0,0,,and we'll see that right now. Dialogue: 0,0:46:36.70,0:46:37.36,EN,,0,0,0,,Anybody else? Dialogue: 0,0:46:42.60,0:46:44.03,EN,,0,0,0,,OK, thank you. Let's take a break. Dialogue: 0,0:46:47.98,0:46:57.61,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:47:22.67,0:47:25.69,EN,,0,0,0,,Well, now I've done this terrible thing to you. Dialogue: 0,0:47:26.56,0:47:30.54,EN,,0,0,0,,I've introduced a very complicated thing, Dialogue: 0,0:47:32.76,0:47:33.42,EN,,0,0,0,,assignment, Dialogue: 0,0:47:34.51,0:47:38.08,EN,,0,0,0,,which destroys most of the interesting mathematical properties of our programs. Dialogue: 0,0:47:41.07,0:47:42.46,EN,,0,0,0,,Why should I have done this? Dialogue: 0,0:47:43.18,0:47:45.02,EN,,0,0,0,,What possible good could this do? Dialogue: 0,0:47:46.51,0:47:48.86,EN,,0,0,0,,Clearly not a nice thing, Dialogue: 0,0:47:49.60,0:47:51.23,EN,,0,0,0,,so I better have a good excuse. Dialogue: 0,0:47:52.83,0:47:54.80,EN,,0,0,0,,Well, let's do a little bit of playing, Dialogue: 0,0:47:54.80,0:47:58.35,EN,,0,0,0,,first of all, with some very interesting programs that have assignment. Dialogue: 0,0:47:58.81,0:48:00.88,EN,,0,0,0,,Understand something special about them Dialogue: 0,0:48:01.42,0:48:02.83,EN,,0,0,0,,that makes them somewhat valuable. Dialogue: 0,0:48:04.96,0:48:06.70,EN,,0,0,0,,Start with a very simple program Dialogue: 0,0:48:07.69,0:48:09.28,EN,,0,0,0,,I'm going to call make-counter. Dialogue: 0,0:48:10.48,0:48:18.19,EN,,0,0,0,,I'm going to define make-counter Dialogue: 0,0:48:24.17,0:48:28.12,EN,,0,0,0,,to be a procedure of one argument n Dialogue: 0,0:48:29.23,0:48:32.94,EN,,0,0,0,,which returns as its value a procedure of no arguments-- Dialogue: 0,0:48:34.36,0:48:36.03,EN,,0,0,0,,a procedure that produces a procedure-- Dialogue: 0,0:48:36.84,0:48:44.35,EN,,0,0,0,,which sets n to the increment of n Dialogue: 0,0:48:47.88,0:48:49.77,EN,,0,0,0,,and returns that value of n. Dialogue: 0,0:48:55.37,0:48:57.54,EN,,0,0,0,,Now we're going to investigate the behavior of this. Dialogue: 0,0:48:57.54,0:48:59.02,EN,,0,0,0,,It's a sort of interesting thing. Dialogue: 0,0:48:59.82,0:49:01.45,EN,,0,0,0,,In order to investigate the behavior, Dialogue: 0,0:49:01.45,0:49:03.08,EN,,0,0,0,,I have to make an environment model, Dialogue: 0,0:49:04.11,0:49:05.98,EN,,0,0,0,,because we can't understand this any other way. Dialogue: 0,0:49:08.65,0:49:09.63,EN,,0,0,0,,So let's just do that. Dialogue: 0,0:49:10.00,0:49:12.86,EN,,0,0,0,,We start out with some sort of-- Dialogue: 0,0:49:13.24,0:49:15.90,EN,,0,0,0,,let's say there is a global environment that the machine is born with. Dialogue: 0,0:49:16.13,0:49:17.12,EN,,0,0,0,,Global we'll call it. Dialogue: 0,0:49:20.03,0:49:24.25,EN,,0,0,0,,And it's going to have in it a bunch of initial things. Dialogue: 0,0:49:24.44,0:49:25.60,EN,,0,0,0,,We all know what it's got. Dialogue: 0,0:49:25.72,0:49:30.88,EN,,0,0,0,,It's got things in it like say, plus, and times, Dialogue: 0,0:49:32.24,0:49:37.26,EN,,0,0,0,,and quotient, and difference, and CAR, Dialogue: 0,0:49:38.70,0:49:39.74,EN,,0,0,0,,and etcetera, Dialogue: 0,0:49:41.45,0:49:42.48,EN,,0,0,0,,lots of things. Dialogue: 0,0:49:42.88,0:49:43.98,EN,,0,0,0,,I don't know what they are, Dialogue: 0,0:49:44.42,0:49:45.55,EN,,0,0,0,,some various squiggles Dialogue: 0,0:49:46.08,0:49:48.88,EN,,0,0,0,,that are the things the machine is born with. Dialogue: 0,0:49:51.21,0:49:53.23,EN,,0,0,0,,And by doing the definition here, Dialogue: 0,0:49:54.68,0:49:55.76,EN,,0,0,0,,what I plan to do-- Dialogue: 0,0:49:56.32,0:49:57.31,EN,,0,0,0,,Well, what am I doing? Dialogue: 0,0:49:57.31,0:49:59.58,EN,,0,0,0,,I'm doing this relative to the global environment. Dialogue: 0,0:49:59.72,0:50:01.29,EN,,0,0,0,,So here's my environment pointer. Dialogue: 0,0:50:03.72,0:50:06.70,EN,,0,0,0,,In order to do that I have to evaluate this lambda expression. Dialogue: 0,0:50:08.35,0:50:10.01,EN,,0,0,0,,That means I make a procedure object. Dialogue: 0,0:50:11.50,0:50:13.26,EN,,0,0,0,,So I'm going to make a procedure object here. Dialogue: 0,0:50:17.36,0:50:18.68,EN,,0,0,0,,And the procedure object has, Dialogue: 0,0:50:18.72,0:50:20.49,EN,,0,0,0,,as the place it's defined, Dialogue: 0,0:50:21.16,0:50:22.35,EN,,0,0,0,,the global environment. Dialogue: 0,0:50:24.06,0:50:25.79,EN,,0,0,0,,The procedure object contains Dialogue: 0,0:50:28.16,0:50:31.47,EN,,0,0,0,,some code that represents a procedure of one argument n Dialogue: 0,0:50:31.96,0:50:35.34,EN,,0,0,0,,which returns a procedure of no arguments which does something. Dialogue: 0,0:50:38.24,0:50:43.28,EN,,0,0,0,,And the define is a way of changing this environment, Dialogue: 0,0:50:44.32,0:50:46.73,EN,,0,0,0,,so that I now add to it a make-counter, Dialogue: 0,0:50:52.28,0:50:55.05,EN,,0,0,0,,a special rule for the special thing defined. Dialogue: 0,0:50:55.82,0:50:56.94,EN,,0,0,0,,But what that is, Dialogue: 0,0:50:58.94,0:51:01.96,EN,,0,0,0,,is it gives me that pointer to that procedure. Dialogue: 0,0:51:03.82,0:51:06.32,EN,,0,0,0,,So now the global environment contains make-counter as well. Dialogue: 0,0:51:09.28,0:51:11.21,EN,,0,0,0,,Now, we're going to do some operations. Dialogue: 0,0:51:11.87,0:51:13.50,EN,,0,0,0,,I'm going to use this to make some counters. Dialogue: 0,0:51:14.99,0:51:16.20,EN,,0,0,0,,We'll see what a counter is. Dialogue: 0,0:51:17.12,0:51:18.51,EN,,0,0,0,,So let's define Dialogue: 0,0:51:23.32,0:51:26.65,EN,,0,0,0,,c1 to be a counter beginning at 0. Dialogue: 0,0:51:35.72,0:51:38.38,EN,,0,0,0,,Well, we know how to do this now, according to the model. Dialogue: 0,0:51:39.63,0:51:44.33,EN,,0,0,0,,I have to evaluate the expression make-counter in the global environment, Dialogue: 0,0:51:45.40,0:51:46.27,EN,,0,0,0,,make-counter of 0. Dialogue: 0,0:51:47.80,0:51:51.10,EN,,0,0,0,,Well, I look up make-counter and see that it's a procedure. Dialogue: 0,0:51:53.61,0:51:55.29,EN,,0,0,0,,I'm going to have to apply that procedure. Dialogue: 0,0:51:56.22,0:51:57.74,EN,,0,0,0,,The way I apply the procedure Dialogue: 0,0:51:58.43,0:51:59.96,EN,,0,0,0,,is by constructing a frame. Dialogue: 0,0:52:01.80,0:52:03.79,EN,,0,0,0,,Okay? So I construct a frame Dialogue: 0,0:52:06.59,0:52:10.44,EN,,0,0,0,,which has a value for n in it Dialogue: 0,0:52:11.77,0:52:12.64,EN,,0,0,0,,which is 0 Dialogue: 0,0:52:14.00,0:52:15.34,EN,,0,0,0,,and the parent environment Dialogue: 0,0:52:15.87,0:52:19.32,EN,,0,0,0,,is the one which is the environment of definition of make-counter. Dialogue: 0,0:52:23.93,0:52:28.36,EN,,0,0,0,,So I've made an environment by applying make-counter to 0. Dialogue: 0,0:52:31.45,0:52:34.40,EN,,0,0,0,,Now, I have to evaluate the body of make-counter, Dialogue: 0,0:52:34.41,0:52:37.72,EN,,0,0,0,,which is this lambda expression, in that environment. Dialogue: 0,0:52:40.64,0:52:42.30,EN,,0,0,0,,Well evaluating this body, Dialogue: 0,0:52:42.76,0:52:44.59,EN,,0,0,0,,this body is a lambda expression. Dialogue: 0,0:52:46.28,0:52:48.86,EN,,0,0,0,,Evaluate a lambda expression means make a procedure object. Dialogue: 0,0:52:49.56,0:52:51.00,EN,,0,0,0,,So I'm going to make a procedure object. Dialogue: 0,0:52:56.76,0:52:58.29,EN,,0,0,0,,And that procedure object has Dialogue: 0,0:52:58.29,0:53:00.46,EN,,0,0,0,,the environment it was defined in being that, Dialogue: 0,0:53:04.20,0:53:05.88,EN,,0,0,0,,where n was defined to be 0. Dialogue: 0,0:53:07.68,0:53:08.80,EN,,0,0,0,,And it has some code, Dialogue: 0,0:53:08.83,0:53:11.37,EN,,0,0,0,,which is the procedure of no arguments Dialogue: 0,0:53:11.40,0:53:15.28,EN,,0,0,0,,which does something, then sets something, Dialogue: 0,0:53:15.28,0:53:16.73,EN,,0,0,0,,and returns n. Dialogue: 0,0:53:17.88,0:53:18.81,EN,,0,0,0,,And this thing Dialogue: 0,0:53:19.42,0:53:21.23,EN,,0,0,0,,is going to be the object, Dialogue: 0,0:53:21.92,0:53:24.67,EN,,0,0,0,,which in the global environment, will have the name c1. Dialogue: 0,0:53:26.12,0:53:28.33,EN,,0,0,0,,So we construct a name here, c1, Dialogue: 0,0:53:28.64,0:53:32.14,EN,,0,0,0,,and say that equals that. Dialogue: 0,0:53:35.48,0:53:37.36,EN,,0,0,0,,Now, but also make another counter, Dialogue: 0,0:53:43.04,0:53:45.13,EN,,0,0,0,,c2 to be make-counter Dialogue: 0,0:53:50.94,0:53:52.19,EN,,0,0,0,,say, starting with 10. Dialogue: 0,0:53:54.25,0:53:55.90,EN,,0,0,0,,Then I do essentially the same thing. Dialogue: 0,0:53:56.64,0:54:00.40,EN,,0,0,0,,I apply the make-counter procedure, which I got from here, Dialogue: 0,0:54:00.99,0:54:04.52,EN,,0,0,0,,to make another frame with n being 10. Dialogue: 0,0:54:05.63,0:54:09.18,EN,,0,0,0,,That frame has the global environment as its parent. Dialogue: 0,0:54:10.04,0:54:11.80,EN,,0,0,0,,I then construct a procedure Dialogue: 0,0:54:13.04,0:54:17.63,EN,,0,0,0,,which has that as it's frame of definition. Dialogue: 0,0:54:18.27,0:54:21.66,EN,,0,0,0,,The code of it is Dialogue: 0,0:54:21.80,0:54:24.38,EN,,0,0,0,,the procedure of no arguments which does something. Dialogue: 0,0:54:25.54,0:54:28.60,EN,,0,0,0,,And it does a set, and so on. Dialogue: 0,0:54:28.60,0:54:31.22,EN,,0,0,0,,And n comes out. Okay? Dialogue: 0,0:54:31.45,0:54:34.83,EN,,0,0,0,,And c2 is this. Dialogue: 0,0:54:36.88,0:54:39.32,EN,,0,0,0,,Well, you're already beginning to see something fairly interesting. Dialogue: 0,0:54:40.17,0:54:41.92,EN,,0,0,0,,There are two n's here. Dialogue: 0,0:54:42.92,0:54:44.19,EN,,0,0,0,,They are not one n. Dialogue: 0,0:54:46.14,0:54:48.16,EN,,0,0,0,,Each time I called make-counter, Dialogue: 0,0:54:48.64,0:54:50.25,EN,,0,0,0,,I made another instance of n. Dialogue: 0,0:54:52.62,0:54:54.40,EN,,0,0,0,,These are distinct and separate from each other. Dialogue: 0,0:54:57.79,0:55:00.28,EN,,0,0,0,,Now, let's do some execution, use those counters. Dialogue: 0,0:55:05.92,0:55:15.00,EN,,0,0,0,,Well, what happens if I say, c1 at this point? Dialogue: 0,0:55:15.84,0:55:17.34,EN,,0,0,0,,Well, I go over here, Dialogue: 0,0:55:17.56,0:55:19.98,EN,,0,0,0,,and I say, oh yes, c1 is a procedure. Dialogue: 0,0:55:20.64,0:55:22.78,EN,,0,0,0,,I'm going to call this procedure on no arguments, Dialogue: 0,0:55:23.16,0:55:24.96,EN,,0,0,0,,but it has no parameters. Dialogue: 0,0:55:24.96,0:55:25.63,EN,,0,0,0,,That's right. Dialogue: 0,0:55:26.97,0:55:27.84,EN,,0,0,0,,What's its body? Dialogue: 0,0:55:27.96,0:55:30.02,EN,,0,0,0,,Well, I have to look over here, because I didn't write it down. Dialogue: 0,0:55:30.02,0:55:32.65,EN,,0,0,0,,It said, set n to one plus n Dialogue: 0,0:55:33.80,0:55:34.89,EN,,0,0,0,,and return n, Dialogue: 0,0:55:37.12,0:55:38.12,EN,,0,0,0,,increment n. Dialogue: 0,0:55:38.97,0:55:41.60,EN,,0,0,0,,Well, the n it says is this one. Dialogue: 0,0:55:43.08,0:55:44.60,EN,,0,0,0,,So I increment that n. Dialogue: 0,0:55:45.80,0:55:47.00,EN,,0,0,0,,That becomes one, Dialogue: 0,0:55:48.64,0:55:50.24,EN,,0,0,0,,and I return the value one. Dialogue: 0,0:55:53.13,0:55:56.49,EN,,0,0,0,,Supposing I then called c2. Dialogue: 0,0:55:58.38,0:55:59.20,EN,,0,0,0,,Well, what do I do? Dialogue: 0,0:55:59.23,0:56:03.33,EN,,0,0,0,,I say c2 is this procedure which does the same thing, Dialogue: 0,0:56:03.33,0:56:04.48,EN,,0,0,0,,but here's the n. Dialogue: 0,0:56:05.33,0:56:06.57,EN,,0,0,0,,It becomes 11. Dialogue: 0,0:56:10.97,0:56:14.59,EN,,0,0,0,,And so I have an 11 which is the value. Dialogue: 0,0:56:15.92,0:56:18.32,EN,,0,0,0,,I then can say, let's try c1 again. Dialogue: 0,0:56:20.91,0:56:22.56,EN,,0,0,0,,hum, c1 is this, Dialogue: 0,0:56:23.28,0:56:24.16,EN,,0,0,0,,that's two, Dialogue: 0,0:56:27.24,0:56:28.30,EN,,0,0,0,,so the answer is two. Dialogue: 0,0:56:29.66,0:56:30.75,EN,,0,0,0,,And c2 Dialogue: 0,0:56:33.37,0:56:35.31,EN,,0,0,0,,gives me a 12 by the same method, Dialogue: 0,0:56:35.74,0:56:37.55,EN,,0,0,0,,by walking down here looking at that Dialogue: 0,0:56:37.55,0:56:39.28,EN,,0,0,0,,and saying, here's the n, I'm incrementing. Dialogue: 0,0:56:41.64,0:56:43.68,EN,,0,0,0,,So what I have are computational objects. Dialogue: 0,0:56:45.21,0:56:46.86,EN,,0,0,0,,There are two counters, Dialogue: 0,0:56:48.96,0:56:51.02,EN,,0,0,0,,each with its own independent local state. Dialogue: 0,0:56:55.48,0:56:56.62,EN,,0,0,0,,Let's talk about this a little. Dialogue: 0,0:56:56.64,0:56:58.52,EN,,0,0,0,,This is a strange thing. Dialogue: 0,0:57:01.12,0:57:02.22,EN,,0,0,0,,What's an object? Dialogue: 0,0:57:04.11,0:57:06.12,EN,,0,0,0,,It's not at all obvious what an object is. Dialogue: 0,0:57:07.55,0:57:09.45,EN,,0,0,0,,We like to think about objects, Dialogue: 0,0:57:11.24,0:57:13.32,EN,,0,0,0,,because it's economical to think that way. Dialogue: 0,0:57:14.62,0:57:17.28,EN,,0,0,0,,It's an intellectual economy. Dialogue: 0,0:57:18.57,0:57:19.61,EN,,0,0,0,,I am an object. Dialogue: 0,0:57:20.99,0:57:22.30,EN,,0,0,0,,You are an object. Dialogue: 0,0:57:23.55,0:57:25.29,EN,,0,0,0,,We are not the same object. Dialogue: 0,0:57:27.52,0:57:29.64,EN,,0,0,0,,I can divide the world into two parts, Dialogue: 0,0:57:29.92,0:57:31.85,EN,,0,0,0,,me and you, Dialogue: 0,0:57:31.92,0:57:33.31,EN,,0,0,0,,and there's other things as well, Dialogue: 0,0:57:34.70,0:57:35.26,EN,,0,0,0,,such that Dialogue: 0,0:57:35.44,0:57:39.50,EN,,0,0,0,,most of the things I might want to discuss about my workings Dialogue: 0,0:57:39.68,0:57:40.89,EN,,0,0,0,,do not involve you, Dialogue: 0,0:57:41.39,0:57:44.67,EN,,0,0,0,,and most of the things I want to discuss about your workings don't involve me. Dialogue: 0,0:57:45.66,0:57:46.94,EN,,0,0,0,,I have a blood pressure, Dialogue: 0,0:57:47.50,0:57:48.38,EN,,0,0,0,,a temperature, Dialogue: 0,0:57:49.36,0:57:51.48,EN,,0,0,0,,a respiration rate, Dialogue: 0,0:57:53.34,0:57:54.99,EN,,0,0,0,,certain amount of sugar in my blood, Dialogue: 0,0:57:56.11,0:57:59.34,EN,,0,0,0,,and numerous, thousands, of state variables-- millions actually, Dialogue: 0,0:57:59.37,0:58:00.65,EN,,0,0,0,,or I don't know how many-- Dialogue: 0,0:58:00.93,0:58:03.48,EN,,0,0,0,,huge numbers of state variables in the physical sense Dialogue: 0,0:58:04.91,0:58:07.12,EN,,0,0,0,,which represent the state of me as a particle, Dialogue: 0,0:58:09.15,0:58:10.64,EN,,0,0,0,,and you have gazillions of them as well. Dialogue: 0,0:58:12.68,0:58:14.94,EN,,0,0,0,,And most of mine are uncoupled to most of yours. Dialogue: 0,0:58:17.31,0:58:19.50,EN,,0,0,0,,So we can compute the properties of me Dialogue: 0,0:58:20.56,0:58:22.83,EN,,0,0,0,,without worrying too much about the properties of you. Dialogue: 0,0:58:23.82,0:58:25.77,EN,,0,0,0,,If we had to work about both of us together, Dialogue: 0,0:58:25.96,0:58:27.82,EN,,0,0,0,,than the number of states that we have to consider Dialogue: 0,0:58:27.82,0:58:30.01,EN,,0,0,0,,is the product of the number of states you have and the number of states I have. Dialogue: 0,0:58:30.52,0:58:32.11,EN,,0,0,0,,But this way it's almost a sum. Dialogue: 0,0:58:32.65,0:58:35.34,EN,,0,0,0,,Now, indeed there are forces that couple us. Dialogue: 0,0:58:36.00,0:58:37.95,EN,,0,0,0,,I'm talking to you and your state changes. Dialogue: 0,0:58:38.44,0:58:40.09,EN,,0,0,0,,I'm looking at you and my state changes. Dialogue: 0,0:58:41.72,0:58:44.08,EN,,0,0,0,,Some of my state variables, a very few of them, Dialogue: 0,0:58:44.33,0:58:46.07,EN,,0,0,0,,therefore, are coupled to yours. Dialogue: 0,0:58:46.07,0:58:47.80,EN,,0,0,0,,If you were to suddenly yell very loud, Dialogue: 0,0:58:47.80,0:58:48.88,EN,,0,0,0,,my blood pressure would go up. Dialogue: 0,0:58:54.30,0:58:56.86,EN,,0,0,0,,However, and it may not be always appropriate Dialogue: 0,0:58:57.17,0:59:01.16,EN,,0,0,0,,to think about the world as being made out of independent states and independent particles. Dialogue: 0,0:59:02.12,0:59:04.46,EN,,0,0,0,,Lots of the bugs that occur in things like quantum mechanics, Dialogue: 0,0:59:05.23,0:59:08.70,EN,,0,0,0,,or the bugs in our minds that occur when we think about things like quantum mechanics, Dialogue: 0,0:59:08.89,0:59:10.97,EN,,0,0,0,,are due the fact that we are trying to think about things Dialogue: 0,0:59:10.97,0:59:12.96,EN,,0,0,0,,being broken up into independent pieces, Dialogue: 0,0:59:13.58,0:59:17.32,EN,,0,0,0,,when in fact there's more coupling than we see on the surface, Dialogue: 0,0:59:18.01,0:59:19.44,EN,,0,0,0,,or that we want to believe in, Dialogue: 0,0:59:19.61,0:59:21.69,EN,,0,0,0,,because we want to compute efficiently and effectively. Dialogue: 0,0:59:22.19,0:59:23.82,EN,,0,0,0,,We've been trained to think that way. Dialogue: 0,0:59:29.76,0:59:30.51,EN,,0,0,0,,Well, let's see. Dialogue: 0,0:59:31.50,0:59:33.44,EN,,0,0,0,,How would we know if we had objects at all? Dialogue: 0,0:59:35.12,0:59:37.34,EN,,0,0,0,,How can we tell if we have objects? Dialogue: 0,0:59:37.64,0:59:41.45,EN,,0,0,0,,Consider some possible optical illusions. Dialogue: 0,0:59:42.46,0:59:43.13,EN,,0,0,0,,This could be done. Dialogue: 0,0:59:45.04,0:59:47.69,EN,,0,0,0,,These pieces of chalk are not appropriately identical, Dialogue: 0,0:59:47.76,0:59:50.20,EN,,0,0,0,,but supposing you couldn't tell the difference of them by looking at them. Dialogue: 0,0:59:52.04,0:59:53.32,EN,,0,0,0,,Well, there's a possibility Dialogue: 0,0:59:53.32,0:59:55.16,EN,,0,0,0,,that this all a game I'm playing with mirrors. Dialogue: 0,0:59:56.07,0:59:57.60,EN,,0,0,0,,It's really the same piece of chalk, Dialogue: 0,0:59:59.36,1:00:00.48,EN,,0,0,0,,but you're seeing two of them. Dialogue: 0,1:00:01.61,1:00:03.87,EN,,0,0,0,,How would you know if you're seeing one or two? Dialogue: 0,1:00:05.04,1:00:06.70,EN,,0,0,0,,Well, there's only one way I know. Dialogue: 0,1:00:07.37,1:00:08.94,EN,,0,0,0,,You grab one of them and change it Dialogue: 0,1:00:09.45,1:00:10.67,EN,,0,0,0,,and see if the other one changed. Dialogue: 0,1:00:14.01,1:00:14.67,EN,,0,0,0,,And it didn't, Dialogue: 0,1:00:15.50,1:00:16.14,EN,,0,0,0,,so there's two of them. Dialogue: 0,1:00:19.50,1:00:20.16,EN,,0,0,0,,And, on the other hand, Dialogue: 0,1:00:20.17,1:00:22.20,EN,,0,0,0,,there is some other screwy properties of things like that. Dialogue: 0,1:00:22.57,1:00:24.01,EN,,0,0,0,,Like, how do we know if something changed? Dialogue: 0,1:00:25.00,1:00:27.93,EN,,0,0,0,,We have to look at it before and after the change. Dialogue: 0,1:00:28.65,1:00:30.02,EN,,0,0,0,,The change is an assignment, Dialogue: 0,1:00:30.02,1:00:31.45,EN,,0,0,0,,it's a moment in time. Dialogue: 0,1:00:32.14,1:00:34.60,EN,,0,0,0,,But that means we have to know it was the same one that we're looking at. Dialogue: 0,1:00:36.51,1:00:38.84,EN,,0,0,0,,So some very strange, and unusual, Dialogue: 0,1:00:38.84,1:00:40.38,EN,,0,0,0,,and obscure, and -- I don't understand Dialogue: 0,1:00:40.84,1:00:43.52,EN,,0,0,0,,the problems associated with assignment, Dialogue: 0,1:00:44.45,1:00:46.28,EN,,0,0,0,,and change, and objects. Dialogue: 0,1:00:47.29,1:00:48.99,EN,,0,0,0,,These could get very, very bad. Dialogue: 0,1:00:51.40,1:00:52.12,EN,,0,0,0,,For example, Dialogue: 0,1:00:53.31,1:00:55.60,EN,,0,0,0,,here I am, I am a particular person, Dialogue: 0,1:00:56.16,1:00:57.72,EN,,0,0,0,,a particular object, okay? Dialogue: 0,1:00:57.96,1:00:59.31,EN,,0,0,0,,Now, I can take out my knife, Dialogue: 0,1:01:00.68,1:01:01.77,EN,,0,0,0,,and cut my fingernail. Dialogue: 0,1:01:01.89,1:01:04.81,EN,,0,0,0,,Alright? A piece of my fingernail has fallen off onto the table. Dialogue: 0,1:01:05.93,1:01:10.16,EN,,0,0,0,,I believe I am the same person I was a second ago, Dialogue: 0,1:01:10.97,1:01:12.81,EN,,0,0,0,,but I'm not physically the same in the slightest. Dialogue: 0,1:01:14.46,1:01:15.43,EN,,0,0,0,,I have changed. Dialogue: 0,1:01:15.58,1:01:16.65,EN,,0,0,0,,Why am I the same? Dialogue: 0,1:01:18.11,1:01:19.40,EN,,0,0,0,,What is the identity of me? Dialogue: 0,1:01:20.96,1:01:23.50,EN,,0,0,0,,I don't know...Okay? Dialogue: 0,1:01:25.05,1:01:27.88,EN,,0,0,0,,Except for the fact that I have some sort of identity. Dialogue: 0,1:01:29.71,1:01:33.04,EN,,0,0,0,,And so, I think by introducing assignment and objects, Dialogue: 0,1:01:33.64,1:01:38.28,EN,,0,0,0,,we have opened ourselves up to all the horrible questions of philosophy Dialogue: 0,1:01:38.41,1:01:42.24,EN,,0,0,0,,that have been plaguing philosophers for some thousands of years about this sort of thing. Dialogue: 0,1:01:43.42,1:01:44.99,EN,,0,0,0,,It's why mathematics is a lot cleaner. Dialogue: 0,1:01:45.69,1:01:50.24,EN,,0,0,0,,Let's look at the best things I know to say about actions and identity. Dialogue: 0,1:01:52.44,1:01:55.39,EN,,0,0,0,,We say that an action, a, had an effect on an object, x, Dialogue: 0,1:01:55.77,1:01:56.70,EN,,0,0,0,,or equivalently, Dialogue: 0,1:01:56.92,1:01:58.41,EN,,0,0,0,,that x was changed by a, Dialogue: 0,1:01:58.89,1:02:01.66,EN,,0,0,0,,if some property, p, which was true of x before a, Dialogue: 0,1:02:01.87,1:02:03.76,EN,,0,0,0,,became false of x after a. Dialogue: 0,1:02:04.99,1:02:05.63,EN,,0,0,0,,That's test. Dialogue: 0,1:02:06.62,1:02:09.66,EN,,0,0,0,,It still means I have to have the x before and after. Dialogue: 0,1:02:10.91,1:02:12.54,EN,,0,0,0,,Or, the other way of saying this is, Dialogue: 0,1:02:12.94,1:02:14.94,EN,,0,0,0,,we say that two objects x and y are the same for any action Dialogue: 0,1:02:14.97,1:02:17.93,EN,,0,0,0,,which has an effect on x has the same effect on y Dialogue: 0,1:02:19.63,1:02:21.39,EN,,0,0,0,,However, objects are very useful, Dialogue: 0,1:02:21.44,1:02:23.18,EN,,0,0,0,,as I said, for intellectual economy. Dialogue: 0,1:02:24.64,1:02:27.12,EN,,0,0,0,,One of the things that's incredibly useful about them, Dialogue: 0,1:02:28.27,1:02:29.44,EN,,0,0,0,,is that the world Dialogue: 0,1:02:30.78,1:02:34.80,EN,,0,0,0,,is made out of independent objects with independent local state. Dialogue: 0,1:02:35.00,1:02:37.28,EN,,0,0,0,,We like to think that way, although it isn't completely true. Dialogue: 0,1:02:39.68,1:02:42.03,EN,,0,0,0,,When we want to make very complicated programs Dialogue: 0,1:02:42.03,1:02:43.26,EN,,0,0,0,,that deal with such a world, Dialogue: 0,1:02:43.98,1:02:46.44,EN,,0,0,0,,if we want those programs to be understandable by us Dialogue: 0,1:02:46.91,1:02:48.14,EN,,0,0,0,,and also to be changeable, Dialogue: 0,1:02:48.73,1:02:51.12,EN,,0,0,0,,so that if we change the world we change the program only a little bit, Dialogue: 0,1:02:51.39,1:02:53.70,EN,,0,0,0,,then we want there to be connections, isomorphism, Dialogue: 0,1:02:53.82,1:02:56.88,EN,,0,0,0,,between the objects in the world and the objects in our mental model. Dialogue: 0,1:02:58.76,1:03:01.44,EN,,0,0,0,,The modularity of the world can give us the modularity in our programming. Dialogue: 0,1:03:02.41,1:03:05.36,EN,,0,0,0,,So we invent things called object-oriented programming and things like that Dialogue: 0,1:03:05.88,1:03:08.36,EN,,0,0,0,,to provide us with that power. Dialogue: 0,1:03:10.06,1:03:10.94,EN,,0,0,0,,But it's even easier. Dialogue: 0,1:03:10.94,1:03:12.25,EN,,0,0,0,,Let's play a little game. Dialogue: 0,1:03:12.27,1:03:13.18,EN,,0,0,0,,I want to play a little game, Dialogue: 0,1:03:13.39,1:03:15.77,EN,,0,0,0,,show you an even easier example Dialogue: 0,1:03:16.00,1:03:21.74,EN,,0,0,0,,or where modularity can be enhanced by using an assignment statement, judiciously. Dialogue: 0,1:03:22.86,1:03:25.35,EN,,0,0,0,,One thing I want to enforce and impress on you, Dialogue: 0,1:03:25.45,1:03:27.44,EN,,0,0,0,,is don't use assignment statements the way Dialogue: 0,1:03:27.45,1:03:29.79,EN,,0,0,0,,you use it in FORTRAN or Basic or something or Pascal, Dialogue: 0,1:03:30.00,1:03:31.71,EN,,0,0,0,,to do the things you don't have to do with it. Dialogue: 0,1:03:34.04,1:03:36.62,EN,,0,0,0,,It's not the right way to think for most things. Dialogue: 0,1:03:36.97,1:03:38.28,EN,,0,0,0,,Sometimes it's essential, Dialogue: 0,1:03:38.68,1:03:39.69,EN,,0,0,0,,or maybe it's essential. Dialogue: 0,1:03:39.69,1:03:40.97,EN,,0,0,0,,We'll see more about that too. Dialogue: 0,1:03:42.24,1:03:44.22,EN,,0,0,0,,OK, let me show you a fun game here. Dialogue: 0,1:03:47.61,1:03:49.42,EN,,0,0,0,,There was a mathematician Dialogue: 0,1:03:49.68,1:03:53.69,EN,,0,0,0,,by the name of Cesaro--or Cesaro, Cesaro I suppose it is-- Dialogue: 0,1:03:54.48,1:03:57.45,EN,,0,0,0,,who figured out a clever way of computing pi. Dialogue: 0,1:03:58.38,1:04:04.30,EN,,0,0,0,,It turns out that if I take two random numbers Dialogue: 0,1:04:05.24,1:04:06.94,EN,,0,0,0,,two integers at random, Dialogue: 0,1:04:07.74,1:04:09.48,EN,,0,0,0,,and compute the greatest common divisor, Dialogue: 0,1:04:10.94,1:04:13.24,EN,,0,0,0,,their greatest common divisor is either one or it's not one. Dialogue: 0,1:04:13.84,1:04:15.64,EN,,0,0,0,,If it's one, then they have no common divisors. Dialogue: 0,1:04:18.14,1:04:20.68,EN,,0,0,0,,If their greatest common divisor is one-- Dialogue: 0,1:04:21.12,1:04:23.09,EN,,0,0,0,,the probability that two random numbers, Dialogue: 0,1:04:23.09,1:04:26.38,EN,,0,0,0,,two numbers chosen at random, has as greatest common divisor one Dialogue: 0,1:04:26.58,1:04:27.82,EN,,0,0,0,,is related to pi. Dialogue: 0,1:04:29.32,1:04:30.11,EN,,0,0,0,,In fact-- Dialogue: 0,1:04:31.11,1:04:32.33,EN,,0,0,0,,yes, it's very strange-- Dialogue: 0,1:04:32.94,1:04:34.41,EN,,0,0,0,,of course there are other ways of computing pi, Dialogue: 0,1:04:34.41,1:04:38.94,EN,,0,0,0,,like dropping pins on flags, and things like that, and sort of the same kind of thing. Dialogue: 0,1:04:40.19,1:04:48.97,EN,,0,0,0,,So the probability of that the GCD of number one and number two, Dialogue: 0,1:04:49.44,1:04:51.02,EN,,0,0,0,,two random numbers chosen, Dialogue: 0,1:04:51.71,1:04:53.66,EN,,0,0,0,,is 6 over pi squared. Dialogue: 0,1:04:55.61,1:04:56.83,EN,,0,0,0,,I'm not going to try to prove that. Dialogue: 0,1:04:57.15,1:04:59.64,EN,,0,0,0,,It's actually not too hard and sort of fun. Dialogue: 0,1:05:01.07,1:05:03.05,EN,,0,0,0,,How would we estimate such probability? Dialogue: 0,1:05:03.53,1:05:06.46,EN,,0,0,0,,Well, the way we do that, the way we estimate the probabilities, Dialogue: 0,1:05:07.23,1:05:08.65,EN,,0,0,0,,is by doing lots of experiments, Dialogue: 0,1:05:09.20,1:05:12.01,EN,,0,0,0,,and then computing the ratios of the ones that come out one way Dialogue: 0,1:05:12.01,1:05:13.58,EN,,0,0,0,,to the total number of experiments we do. Dialogue: 0,1:05:16.32,1:05:17.28,EN,,0,0,0,,It's called Monte Carlo, Dialogue: 0,1:05:18.04,1:05:22.38,EN,,0,0,0,,and it's useful in other contexts for doing things like integrals where you have lots and lots of variables-- Dialogue: 0,1:05:22.94,1:05:25.28,EN,,0,0,0,,the space which is limiting the dimensions you are doing you integral in. Dialogue: 0,1:05:26.27,1:05:28.70,EN,,0,0,0,,But going back to here, Dialogue: 0,1:05:29.76,1:05:31.72,EN,,0,0,0,,Let's look at this slide, Dialogue: 0,1:05:33.96,1:05:36.92,EN,,0,0,0,,We can use Cesaro's method for estimating pi Dialogue: 0,1:05:37.19,1:05:43.18,EN,,0,0,0,,with n trials by taking the square root of six over a Monte Carlo, Dialogue: 0,1:05:43.29,1:05:46.46,EN,,0,0,0,,a Monte Carlo experiment with n trials, Dialogue: 0,1:05:46.80,1:05:50.38,EN,,0,0,0,,with n trials using Cesaro's experiment, Dialogue: 0,1:05:51.37,1:05:57.56,EN,,0,0,0,,where Cesaro's experiment is the test of whether the GCD of two random numbers-- Dialogue: 0,1:05:58.96,1:06:01.60,EN,,0,0,0,,And you can see that I've already got some assignments in here, Dialogue: 0,1:06:01.84,1:06:03.13,EN,,0,0,0,,just by what I wrote. Dialogue: 0,1:06:04.04,1:06:07.49,EN,,0,0,0,,The fact that this word rand, in parentheses, Dialogue: 0,1:06:07.49,1:06:09.09,EN,,0,0,0,,therefore, that procedure call, Dialogue: 0,1:06:09.09,1:06:11.39,EN,,0,0,0,,yields a different value than this one, Dialogue: 0,1:06:11.39,1:06:13.72,EN,,0,0,0,,at least that's what I'm assuming by writing this this way, Dialogue: 0,1:06:14.62,1:06:16.75,EN,,0,0,0,,indicates that this is not a function, Dialogue: 0,1:06:18.20,1:06:20.57,EN,,0,0,0,,that there's internal state in it which is changing. Dialogue: 0,1:06:22.27,1:06:28.64,EN,,0,0,0,,If the GCD of those two random numbers is equal to one, Dialogue: 0,1:06:28.64,1:06:29.79,EN,,0,0,0,,that's the experiment. Dialogue: 0,1:06:31.48,1:06:35.18,EN,,0,0,0,,So here I have an experimental method for estimating the value of pi. Dialogue: 0,1:06:36.51,1:06:39.72,EN,,0,0,0,,Where, I can easily divide this problem into two parts. Dialogue: 0,1:06:40.02,1:06:44.70,EN,,0,0,0,,One is the specific Monte Carlo experiment of Cesaro, which you just saw, Dialogue: 0,1:06:44.99,1:06:48.56,EN,,0,0,0,,and the other is the general technique of doing Monte Carlo experiments. Dialogue: 0,1:06:49.16,1:06:50.27,EN,,0,0,0,,And that's what this is. Dialogue: 0,1:06:51.04,1:06:55.47,EN,,0,0,0,,If I want to do Monte Carlo experiments with n trials, Dialogue: 0,1:06:55.67,1:06:58.36,EN,,0,0,0,,a certain number of trials, and a particular experiment, Dialogue: 0,1:06:59.31,1:07:00.33,EN,,0,0,0,,the way I do that Dialogue: 0,1:07:00.84,1:07:02.70,EN,,0,0,0,,is I make a little iterative procedure Dialogue: 0,1:07:03.31,1:07:07.26,EN,,0,0,0,,which has variable the number of trials remaining and the number trials that have been passed, Dialogue: 0,1:07:08.35,1:07:09.44,EN,,0,0,0,,that I've gotten true. Dialogue: 0,1:07:10.13,1:07:12.21,EN,,0,0,0,,And if the number remaining is 0, Dialogue: 0,1:07:12.21,1:07:15.36,EN,,0,0,0,,then the answer is the number past divided by this whole number of trials, Dialogue: 0,1:07:16.04,1:07:17.52,EN,,0,0,0,,was the estimate of the probability. Dialogue: 0,1:07:19.07,1:07:20.04,EN,,0,0,0,,And if it's not, Dialogue: 0,1:07:20.04,1:07:22.08,EN,,0,0,0,,if I have more trials to do, Dialogue: 0,1:07:22.08,1:07:23.82,EN,,0,0,0,,then let's do one. We do an experiment. Dialogue: 0,1:07:23.85,1:07:27.30,EN,,0,0,0,,We call the procedure which is experiment on no arguments. Dialogue: 0,1:07:27.30,1:07:28.43,EN,,0,0,0,,We do the experiment Dialogue: 0,1:07:29.10,1:07:30.64,EN,,0,0,0,,and then, if that turned out to be true, Dialogue: 0,1:07:30.82,1:07:32.25,EN,,0,0,0,,we go around the loop Dialogue: 0,1:07:32.62,1:07:35.42,EN,,0,0,0,,decrementing the number of experiments we have to do by one Dialogue: 0,1:07:35.70,1:07:37.48,EN,,0,0,0,,and incrementing the number that were passed. Dialogue: 0,1:07:38.57,1:07:40.11,EN,,0,0,0,,And if the experiment was false, Dialogue: 0,1:07:40.41,1:07:42.25,EN,,0,0,0,,we just go around the loop Dialogue: 0,1:07:42.32,1:07:44.38,EN,,0,0,0,,decrementing the number of experiments remaining Dialogue: 0,1:07:44.44,1:07:46.60,EN,,0,0,0,,and keeping the number passed the same. Dialogue: 0,1:07:48.76,1:07:54.59,EN,,0,0,0,,We start this up iterating over the total number of trials with 0 experiments past. Dialogue: 0,1:07:55.42,1:07:57.10,EN,,0,0,0,,A very elegant little program. Dialogue: 0,1:07:57.74,1:08:00.55,EN,,0,0,0,,And I don't have to just do this with Cesaro's experiment, Dialogue: 0,1:08:00.55,1:08:02.73,EN,,0,0,0,,it could be lots of Monte Carlo experiments I might do. Dialogue: 0,1:08:03.36,1:08:07.12,EN,,0,0,0,,Of course, this depends upon the existence of some sort of random number generator. Dialogue: 0,1:08:07.34,1:08:10.99,EN,,0,0,0,,And random number generators generally look something like this. Dialogue: 0,1:08:13.60,1:08:16.32,EN,,0,0,0,,There is a random number generator-- Dialogue: 0,1:08:17.42,1:08:25.21,EN,,0,0,0,,is in fact a procedure which is going to do something just like the counter. Dialogue: 0,1:08:25.61,1:08:27.52,EN,,0,0,0,,It's going to update an x Dialogue: 0,1:08:28.33,1:08:31.82,EN,,0,0,0,,to the result of applying some function to x, Dialogue: 0,1:08:32.20,1:08:35.28,EN,,0,0,0,,where this function is some screwy kind of function Dialogue: 0,1:08:35.39,1:08:40.16,EN,,0,0,0,,that you might find out in Knuth's books on the details of programming. Dialogue: 0,1:08:41.56,1:08:45.75,EN,,0,0,0,,He does these wonderful books that are full of the details of programming, Dialogue: 0,1:08:45.75,1:08:48.52,EN,,0,0,0,,because I can't remember how to make a random number generator, Dialogue: 0,1:08:48.63,1:08:50.62,EN,,0,0,0,,but I can look it up there, and I can find out. Dialogue: 0,1:08:51.64,1:08:54.01,EN,,0,0,0,,And then, eventually, I return the value of x Dialogue: 0,1:08:54.08,1:08:57.40,EN,,0,0,0,,which is the state variable internal to the random number generator. Dialogue: 0,1:08:58.28,1:09:00.75,EN,,0,0,0,,That state variable is initialized somehow, Dialogue: 0,1:09:01.32,1:09:02.24,EN,,0,0,0,,and has a value. Dialogue: 0,1:09:03.39,1:09:08.11,EN,,0,0,0,,And this procedure is defined in the context where that variable is bound Dialogue: 0,1:09:10.41,1:09:15.26,EN,,0,0,0,,So this is a hidden piece of local state that you see here. Dialogue: 0,1:09:15.87,1:09:20.24,EN,,0,0,0,,And this procedure is defined in that context. Dialogue: 0,1:09:21.56,1:09:23.66,EN,,0,0,0,,Now, that's a very simple thing to do. Dialogue: 0,1:09:24.88,1:09:25.79,EN,,0,0,0,,And it's very nice. Dialogue: 0,1:09:25.99,1:09:27.77,EN,,0,0,0,,Supposing, I didn't want to use assignments. Dialogue: 0,1:09:29.10,1:09:31.47,EN,,0,0,0,,Supposing, I wanted to write this program without assignments. Dialogue: 0,1:09:32.73,1:09:33.93,EN,,0,0,0,,What problems would I have? Dialogue: 0,1:09:35.52,1:09:37.40,EN,,0,0,0,,Well, let's see. Dialogue: 0,1:09:37.82,1:09:41.10,EN,,0,0,0,,I'd like to use the overhead machine here, Dialogue: 0,1:09:42.06,1:09:42.70,EN,,0,0,0,,thank you. Dialogue: 0,1:09:43.47,1:09:47.66,EN,,0,0,0,,First of all, let's look at the whole thing. It's a big story. Right? Dialogue: 0,1:09:48.01,1:09:49.90,EN,,0,0,0,,Unfortunately, which tells you there is something wrong. Dialogue: 0,1:09:50.96,1:09:52.75,EN,,0,0,0,,It's at least that big, Dialogue: 0,1:09:53.42,1:09:54.60,EN,,0,0,0,,and it's monolithic. Dialogue: 0,1:09:56.76,1:10:00.12,EN,,0,0,0,,You don't have to understand or look at the text there right now Dialogue: 0,1:10:00.12,1:10:01.39,EN,,0,0,0,,to see that it's monolithic. Dialogue: 0,1:10:01.92,1:10:04.89,EN,,0,0,0,,It isn't a thing which is Cesaro's experiment. Dialogue: 0,1:10:04.89,1:10:07.90,EN,,0,0,0,,It's not pulled out from the Monte Carlo process. Dialogue: 0,1:10:09.87,1:10:11.84,EN,,0,0,0,,It's not separated. Let's look why. Dialogue: 0,1:10:14.22,1:10:15.85,EN,,0,0,0,,Remember, the constraint here Dialogue: 0,1:10:15.85,1:10:17.87,EN,,0,0,0,,is that every procedure Dialogue: 0,1:10:18.69,1:10:22.20,EN,,0,0,0,,return the same value for the same arguments. Dialogue: 0,1:10:22.97,1:10:24.75,EN,,0,0,0,,Every procedure represents a function. Dialogue: 0,1:10:26.92,1:10:28.50,EN,,0,0,0,,That's a different kind of constraint. Dialogue: 0,1:10:28.50,1:10:31.21,EN,,0,0,0,,Because when I have assignments, I can change some internal state variable. Dialogue: 0,1:10:31.74,1:10:34.03,EN,,0,0,0,,So let's see how that causes things to go wrong. Dialogue: 0,1:10:35.04,1:10:36.14,EN,,0,0,0,,Well, start at the beginning. Dialogue: 0,1:10:37.50,1:10:41.92,EN,,0,0,0,,Ah...The estimate of pi looks sort of the same. Dialogue: 0,1:10:42.66,1:10:45.88,EN,,0,0,0,,What I'm doing is I take the square root Dialogue: 0,1:10:46.35,1:10:50.22,EN,,0,0,0,,of six over the random GCD test applied to n Dialogue: 0,1:10:50.74,1:10:51.93,EN,,0,0,0,,whereas that's what this is. Dialogue: 0,1:10:52.96,1:10:55.20,EN,,0,0,0,,But here, we are beginning to see something funny. Dialogue: 0,1:10:55.20,1:10:57.93,EN,,0,0,0,,The random GCD test of a certain number of trials Dialogue: 0,1:10:58.32,1:10:59.98,EN,,0,0,0,,is just like we had before, Dialogue: 0,1:11:00.46,1:11:04.66,EN,,0,0,0,,an iteration on the number of trials remaining, Dialogue: 0,1:11:04.66,1:11:06.80,EN,,0,0,0,,the number of trials that have been passed, Dialogue: 0,1:11:08.27,1:11:09.71,EN,,0,0,0,,and another variable x. Dialogue: 0,1:11:10.75,1:11:11.76,EN,,0,0,0,,What's that x? Dialogue: 0,1:11:12.33,1:11:15.20,EN,,0,0,0,,That x is the state of the random number generator. Dialogue: 0,1:11:19.00,1:11:21.16,EN,,0,0,0,,And it is now going to be used here. Dialogue: 0,1:11:21.16,1:11:23.79,EN,,0,0,0,,The same random update function that I have over here Dialogue: 0,1:11:23.79,1:11:27.15,EN,,0,0,0,,is the one I would have used in a random number generator if I were building it the other way, Dialogue: 0,1:11:27.71,1:11:29.32,EN,,0,0,0,,the one I get out of Knuth's books. Dialogue: 0,1:11:31.56,1:11:33.36,EN,,0,0,0,,x is going to get transformed into x1, Dialogue: 0,1:11:33.37,1:11:34.36,EN,,0,0,0,,I need two random numbers. Dialogue: 0,1:11:34.81,1:11:36.92,EN,,0,0,0,,And x1 is going to get transformed into x2, Dialogue: 0,1:11:37.26,1:11:38.44,EN,,0,0,0,,I have two random numbers. Dialogue: 0,1:11:39.50,1:11:42.14,EN,,0,0,0,,I then have to do exactly what I did before. Dialogue: 0,1:11:42.52,1:11:44.19,EN,,0,0,0,,I take the GCD of x1 x2. Dialogue: 0,1:11:44.22,1:11:47.15,EN,,0,0,0,,If that's one, then I go around the loop with X2 being the next value of x. Dialogue: 0,1:11:54.78,1:11:55.98,EN,,0,0,0,,You see what's happened here Dialogue: 0,1:11:56.88,1:11:58.70,EN,,0,0,0,,is that the state of the random number generator Dialogue: 0,1:11:58.73,1:12:01.70,EN,,0,0,0,,is no longer confined to the insides of the random number generator. Dialogue: 0,1:12:01.80,1:12:02.73,EN,,0,0,0,,It has leaked out. Dialogue: 0,1:12:03.33,1:12:05.50,EN,,0,0,0,,It has leaked out into my procedure Dialogue: 0,1:12:05.50,1:12:10.08,EN,,0,0,0,,that does the Monte Carlo experiment. Dialogue: 0,1:12:10.70,1:12:11.87,EN,,0,0,0,,But what's worse than that, Dialogue: 0,1:12:11.87,1:12:16.24,EN,,0,0,0,,is it's also, because it was contained inside my experiment itself, Cesaro, Dialogue: 0,1:12:16.78,1:12:19.48,EN,,0,0,0,,It leaked out that two. Because Cesaro called twice, Dialogue: 0,1:12:20.86,1:12:22.47,EN,,0,0,0,,has to have a different value each time, Dialogue: 0,1:12:22.47,1:12:25.16,EN,,0,0,0,,if I going to have a legitimate experimental test. Dialogue: 0,1:12:26.32,1:12:28.32,EN,,0,0,0,,So Cesaro can't be a function either, Dialogue: 0,1:12:31.04,1:12:35.69,EN,,0,0,0,,unless I pass it the seed of the random number generator that is going to go wandering around. Dialogue: 0,1:12:36.52,1:12:39.37,EN,,0,0,0,,So unfortunately, the seed of random number generator Dialogue: 0,1:12:39.37,1:12:42.77,EN,,0,0,0,,has leaked out into Cesaro, from the random number generator, Dialogue: 0,1:12:42.88,1:12:45.16,EN,,0,0,0,,that's leaked into the Monte Carlo experiment. Dialogue: 0,1:12:45.64,1:12:49.12,EN,,0,0,0,,And, unfortunately, my Monte Carlo experiment here is no longer general. Dialogue: 0,1:12:50.25,1:12:51.80,EN,,0,0,0,,The Monte Carlo experiment here Dialogue: 0,1:12:52.03,1:12:54.73,EN,,0,0,0,,knows how many random numbers I need to do the experiment. Dialogue: 0,1:12:58.96,1:12:59.74,EN,,0,0,0,,That's sort of horrible. Dialogue: 0,1:13:00.08,1:13:02.54,EN,,0,0,0,,I lost an ability to decompose a problem into pieces, Dialogue: 0,1:13:03.44,1:13:09.12,EN,,0,0,0,,because I wasn't willing to accept the little loop of information, Dialogue: 0,1:13:09.50,1:13:12.43,EN,,0,0,0,,the feedback process, Dialogue: 0,1:13:12.88,1:13:15.94,EN,,0,0,0,,that happens inside the random number generator before Dialogue: 0,1:13:15.94,1:13:21.21,EN,,0,0,0,,that was made by having an assignment to a state variable that was confined to the random number generator. Dialogue: 0,1:13:22.92,1:13:25.48,EN,,0,0,0,,So the fact that the random number generator is an object, Dialogue: 0,1:13:25.92,1:13:27.37,EN,,0,0,0,,with an internal state variable, Dialogue: 0,1:13:28.06,1:13:29.36,EN,,0,0,0,,it's affected by nothing, Dialogue: 0,1:13:29.37,1:13:31.60,EN,,0,0,0,,but it'll give you something, and it will apply it's force to you, Dialogue: 0,1:13:32.80,1:13:34.28,EN,,0,0,0,,that was what we're missing now. Dialogue: 0,1:13:38.00,1:13:40.73,EN,,0,0,0,,OK, well I think we've seen Dialogue: 0,1:13:40.73,1:13:42.30,EN,,0,0,0,,enough reason for doing this, Dialogue: 0,1:13:42.83,1:13:45.24,EN,,0,0,0,,and it all sort of looks very wonderful. Dialogue: 0,1:13:45.38,1:13:50.70,EN,,0,0,0,,Wouldn't it be nice if assignment was a good thing Dialogue: 0,1:13:51.74,1:13:53.04,EN,,0,0,0,,and maybe it's worth it, Dialogue: 0,1:13:53.28,1:13:54.14,EN,,0,0,0,,but I'm not sure. Dialogue: 0,1:13:55.34,1:13:57.04,EN,,0,0,0,,As Mr. Gilbert and Sullivan said, Dialogue: 0,1:13:57.04,1:13:58.51,EN,,0,0,0,,things are seldom what they seem, Dialogue: 0,1:13:58.51,1:14:00.35,EN,,0,0,0,,skim milk masquerades as cream. Dialogue: 0,1:14:01.87,1:14:03.90,EN,,0,0,0,,Are there any questions? Dialogue: 0,1:14:16.97,1:14:18.30,EN,,0,0,0,,Are there any philosophers here? Dialogue: 0,1:14:20.06,1:14:22.03,EN,,0,0,0,,Anybody want to argue about objects? Dialogue: 0,1:14:24.32,1:14:25.50,EN,,0,0,0,,You're just floored, right? Dialogue: 0,1:14:29.72,1:14:30.72,EN,,0,0,0,,And you haven't done your homework yet. Dialogue: 0,1:14:30.73,1:14:32.00,EN,,0,0,0,,You haven't come up with a good question. Dialogue: 0,1:14:36.35,1:14:37.44,EN,,0,0,0,,Oh, well. Dialogue: 0,1:14:39.97,1:14:42.33,EN,,0,0,0,,Sure, thank you. Let's take the long break now. Dialogue: 0,0:00:00.00,0:00:01.96,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:01.98,0:00:09.55,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:01.98,0:00:09.55,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:01.98,0:00:09.55,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:01.98,0:00:09.55,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N杨启钊(windfarer) Dialogue: 0,0:00:01.98,0:00:09.55,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:09.92,0:00:13.63,Declare,,0,0,0,,{\an2\fad(500,500)}赋值、状态和副作用 Dialogue: 0,0:00:18.31,0:00:22.00,Default,,0,0,0,,教授:到目前为止 我们已经教了很多编程技巧 Dialogue: 0,0:00:22.25,0:00:24.06,Default,,0,0,0,,来编写复杂程序了 Dialogue: 0,0:00:24.76,0:00:29.66,Default,,0,0,0,,并且 到目前为止 关于编程你们学到了很多 Dialogue: 0,0:00:29.66,0:00:31.48,Default,,0,0,0,,你们已经学习了几乎所有的 Dialogue: 0,0:00:31.86,0:00:35.87,Default,,0,0,0,,那些拥有大量经验的人 才能领悟的技巧 Dialogue: 0,0:00:36.41,0:00:40.08,Default,,0,0,0,,例如 数据导向编程就是一个主要的技巧 Dialogue: 0,0:00:40.75,0:00:43.15,Default,,0,0,0,,昨天 你们也学习了一种解释型语言 Dialogue: 0,0:00:45.02,0:00:48.46,Default,,0,0,0,,我们所做的这一切 Dialogue: 0,0:00:48.54,0:00:49.63,Default,,0,0,0,,目前来讲 Dialogue: 0,0:00:49.88,0:00:51.95,Default,,0,0,0,,都是在一种没有赋值语句的计算机语言中完成的 Dialogue: 0,0:00:53.77,0:00:58.17,Default,,0,0,0,,对于你们中用过Basic或者Pascal的人 Dialogue: 0,0:00:58.68,0:01:01.23,Default,,0,0,0,,可能会认为“赋值”是最重要的东西 Dialogue: 0,0:01:01.79,0:01:03.82,Default,,0,0,0,,今天我们将要做一些糟糕的事情 Dialogue: 0,0:01:03.82,0:01:05.45,Default,,0,0,0,,我们要把赋值语句加进来 Dialogue: 0,0:01:07.21,0:01:09.14,Default,,0,0,0,,既然在没有赋值语句的时候 我们都可以很好地完成工作 Dialogue: 0,0:01:09.14,0:01:10.17,Default,,0,0,0,,为什么我们还要把它加进来呢? Dialogue: 0,0:01:10.99,0:01:12.43,Default,,0,0,0,,为了理解它 Dialogue: 0,0:01:12.46,0:01:15.71,Default,,0,0,0,,我们今天首先要定下一个规则 Dialogue: 0,0:01:16.48,0:01:17.93,Default,,0,0,0,,而我们将一直遵守这个规则 Dialogue: 0,0:01:17.93,0:01:20.80,Default,,0,0,0,,这是我们为语言引入新的特性的唯一原因 Dialogue: 0,0:01:21.53,0:01:23.14,Default,,0,0,0,,是因为我们有一个好的理由 Dialogue: 0,0:01:23.93,0:01:27.28,Default,,0,0,0,,好的理由归结为能力 Dialogue: 0,0:01:27.42,0:01:31.51,Default,,0,0,0,,你现在获得了把问题分解为不同部分的能力 Dialogue: 0,0:01:31.51,0:01:33.44,Default,,0,0,0,,在没有相关能力之前可不行 Dialogue: 0,0:01:34.38,0:01:36.16,Default,,0,0,0,,这让你有用来分解问题的另外方法 Dialogue: 0,0:01:38.30,0:01:39.45,Default,,0,0,0,,我们这就开始 Dialogue: 0,0:01:39.45,0:01:41.88,Default,,0,0,0,,从回顾我们的 Dialogue: 0,0:01:41.88,0:01:47.37,Default,,0,0,0,,现在已经有的这种语言出发 Dialogue: 0,0:01:48.16,0:01:50.44,Default,,0,0,0,,我们之前写的是所谓的函数式程序 Dialogue: 0,0:01:51.21,0:01:52.52,Default,,0,0,0,,函数式程序 Dialogue: 0,0:01:53.04,0:01:57.95,Default,,0,0,0,,是一种对数学事实的编码 Dialogue: 0,0:01:58.88,0:02:00.51,Default,,0,0,0,,例如 当我们看到 Dialogue: 0,0:02:00.51,0:02:04.09,Default,,0,0,0,,像幻灯片上这样阶乘过程时 Dialogue: 0,0:02:05.07,0:02:06.62,Default,,0,0,0,,基本上是两个子句 Dialogue: 0,0:02:06.99,0:02:08.64,Default,,0,0,0,,如果n是1 则结果是1 Dialogue: 0,0:02:08.64,0:02:11.20,Default,,0,0,0,,否则返回n乘以n-1的阶乘 Dialogue: 0,0:02:11.20,0:02:12.33,Default,,0,0,0,,这是n的阶乘 Dialogue: 0,0:02:12.89,0:02:14.27,Default,,0,0,0,,它就是阶乘函数 Dialogue: 0,0:02:14.83,0:02:16.87,Default,,0,0,0,,如果用一些其他的记号 Dialogue: 0,0:02:16.87,0:02:19.32,Default,,0,0,0,,那些你在微积分课堂上学到的晦涩的符号来写 Dialogue: 0,0:02:20.30,0:02:22.11,Default,,0,0,0,,用数理逻辑来写 Dialogue: 0,0:02:22.11,0:02:26.36,Default,,0,0,0,,如果n等于1 Dialogue: 0,0:02:27.13,0:02:29.90,Default,,0,0,0,,那么n的阶乘结果是1 否则 Dialogue: 0,0:02:29.90,0:02:32.56,Default,,0,0,0,,如果n大于1 则n的阶乘就是n * (n-1)! Dialogue: 0,0:02:32.56,0:02:33.55,Default,,0,0,0,,数学事实 Dialogue: 0,0:02:34.92,0:02:36.70,Default,,0,0,0,,就是我们一直使用的那种语言 Dialogue: 0,0:02:37.00,0:02:39.23,Default,,0,0,0,,无论何时 我们遇到了这样的数学事实 Dialogue: 0,0:02:39.53,0:02:46.65,Default,,0,0,0,,有一种理解它们工作原理的方法 Dialogue: 0,0:02:47.40,0:02:51.12,Default,,0,0,0,,就是这些过程可以由代换演算而来 Dialogue: 0,0:02:51.29,0:02:53.71,Default,,0,0,0,,来看第二张幻灯片 Dialogue: 0,0:02:54.99,0:02:58.81,Default,,0,0,0,,我们理解执行的过程 Dialogue: 0,0:02:58.83,0:03:03.50,Default,,0,0,0,,隐含在表达式的顺序中 Dialogue: 0,0:03:04.04,0:03:07.76,Default,,0,0,0,,也就是你不断地将实际参数 Dialogue: 0,0:03:07.87,0:03:10.88,Default,,0,0,0,,代换到程序体的形式参数中 Dialogue: 0,0:03:12.00,0:03:14.51,Default,,0,0,0,,这些基本上是一系列的等价代换 Dialogue: 0,0:03:14.61,0:03:17.25,Default,,0,0,0,,4的阶乘是4乘以3的阶乘 Dialogue: 0,0:03:17.25,0:03:20.05,Default,,0,0,0,,也就是4乘以3乘以2的阶乘 Dialogue: 0,0:03:20.05,0:03:21.01,Default,,0,0,0,,以此类推 Dialogue: 0,0:03:21.23,0:03:23.87,Default,,0,0,0,,我们总是保持数学事实成立 Dialogue: 0,0:03:25.23,0:03:28.84,Default,,0,0,0,,尽管我们正在讨论数学事实 Dialogue: 0,0:03:28.84,0:03:31.96,Default,,0,0,0,,可能有多种数学事实的组织方式 Dialogue: 0,0:03:31.96,0:03:35.12,Default,,0,0,0,,用来描述一个特定的函数的计算 Dialogue: 0,0:03:36.32,0:03:38.42,Default,,0,0,0,,这个特定的函数的值的计算 Dialogue: 0,0:03:38.42,0:03:40.92,Default,,0,0,0,,所以 让我来看下这里的例子 Dialogue: 0,0:03:41.48,0:03:49.02,Default,,0,0,0,,这有一个计算m与n之和的方法 Dialogue: 0,0:03:49.53,0:03:52.04,Default,,0,0,0,,我们使用一个递归的过程来完成 Dialogue: 0,0:03:52.89,0:03:58.16,Default,,0,0,0,,也就是(1+ (+ (-1+ n) m)) Dialogue: 0,0:04:00.08,0:04:05.62,Default,,0,0,0,,当然 这里也有相应的数理逻辑 解释了这个方法 Dialogue: 0,0:04:06.17,0:04:10.49,Default,,0,0,0,,也就是((n-1)+m)+1 Dialogue: 0,0:04:11.40,0:04:12.22,Default,,0,0,0,,跟之前那个一样 Dialogue: 0,0:04:13.10,0:04:16.40,Default,,0,0,0,,所以这儿并没有什么特殊的魔法 Dialogue: 0,0:04:16.41,0:04:20.01,Default,,0,0,0,,当然 如果我们可以再来看一个相同的迭代过程 Dialogue: 0,0:04:20.19,0:04:24.92,Default,,0,0,0,,计算同样的函数 但是进行逐步迭代的程序 Dialogue: 0,0:04:25.26,0:04:27.56,Default,,0,0,0,,这两个程序将得到同样的结果 Dialogue: 0,0:04:30.08,0:04:34.83,Default,,0,0,0,,我们就可以认为这两个程序在数学上是等效的 Dialogue: 0,0:04:36.65,0:04:39.93,Default,,0,0,0,,你对这些数学事实的排序 决定了具体(计算)过程 Dialogue: 0,0:04:40.30,0:04:43.42,Default,,0,0,0,,我们对于这些数学事实的排序和选择 决定了过程发展的方式 Dialogue: 0,0:04:44.33,0:04:48.60,Default,,0,0,0,,因此我们可以灵活地讨论待计算的函数 Dialogue: 0,0:04:48.60,0:04:50.19,Default,,0,0,0,,以及计算该函数的所用的方法 Dialogue: 0,0:04:50.60,0:04:52.60,Default,,0,0,0,,这并不清晰 我们需要再深入一些 Dialogue: 0,0:04:53.61,0:04:55.50,Default,,0,0,0,,然而 今天我要来讲这个糟糕的东西 Dialogue: 0,0:04:55.50,0:04:58.43,Default,,0,0,0,,我要给大家介绍赋值操作 Dialogue: 0,0:04:58.89,0:05:00.41,Default,,0,0,0,,这是什么? Dialogue: 0,0:05:02.89,0:05:09.22,Default,,0,0,0,,首先 在编程语言中有另一种语句 Dialogue: 0,0:05:09.22,0:05:10.84,Default,,0,0,0,,这种语句叫做SET! Dialogue: 0,0:05:12.41,0:05:15.96,Default,,0,0,0,,具有赋值操作的语句 Dialogue: 0,0:05:15.98,0:05:17.85,Default,,0,0,0,,我都会在后面加上一个感叹号 Dialogue: 0,0:05:18.51,0:05:20.96,Default,,0,0,0,,这个感叹号代表什么意思呢? Dialogue: 0,0:05:20.96,0:05:23.01,Default,,0,0,0,,这个感叹号 与问号类似 Dialogue: 0,0:05:23.01,0:05:25.88,Default,,0,0,0,,是我们给名字随意加的符号 Dialogue: 0,0:05:25.88,0:05:27.88,Default,,0,0,0,,它对于系统来说没有意义 Dialogue: 0,0:05:28.08,0:05:30.21,Default,,0,0,0,,它唯一的意义就是告诉我们 Dialogue: 0,0:05:30.40,0:05:34.41,Default,,0,0,0,,注意这里是某种赋值操作 Dialogue: 0,0:05:35.88,0:05:40.06,Default,,0,0,0,,但是我们要给某个变量赋一个值 Dialogue: 0,0:05:43.74,0:05:45.13,Default,,0,0,0,,这意味着 Dialogue: 0,0:05:45.13,0:05:48.28,Default,,0,0,0,,在某个时间点发生了一些事情 Dialogue: 0,0:05:48.65,0:05:49.61,Default,,0,0,0,,这是一个时间点 Dialogue: 0,0:05:49.86,0:05:52.14,Default,,0,0,0,,如果时间以这个方向流动 Dialogue: 0,0:05:53.50,0:05:54.82,Default,,0,0,0,,这是个时间轴 Dialogue: 0,0:05:55.00,0:05:57.82,Default,,0,0,0,,时间在平面上由上到下地流逝 Dialogue: 0,0:05:58.70,0:06:00.92,Default,,0,0,0,,赋值是第一个 Dialogue: 0,0:06:00.92,0:06:04.30,Default,,0,0,0,,使过去和未来之间产生差别的事物 Dialogue: 0,0:06:06.59,0:06:08.72,Default,,0,0,0,,我们之前写的所有程序 Dialogue: 0,0:06:09.18,0:06:10.68,Default,,0,0,0,,都不包含赋值 Dialogue: 0,0:06:10.68,0:06:13.12,Default,,0,0,0,,这些程序以怎样的顺序进行执行都没关系 Dialogue: 0,0:06:14.70,0:06:15.96,Default,,0,0,0,,但是赋值比较特殊 Dialogue: 0,0:06:15.96,0:06:17.69,Default,,0,0,0,,它使时间中产生了一个时间点 Dialogue: 0,0:06:17.96,0:06:24.73,Default,,0,0,0,,因此在SET!出现之前和之后中间有一个时间点 Dialogue: 0,0:06:27.61,0:06:32.70,Default,,0,0,0,,使得在这个时间点之后 Dialogue: 0,0:06:33.60,0:06:43.76,Default,,0,0,0,,变量有了一个值 即VALUE Dialogue: 0,0:06:49.23,0:06:51.50,Default,,0,0,0,,与这个变量之前的值无关 Dialogue: 0,0:06:52.80,0:06:55.79,Default,,0,0,0,,SET!改变了它的值 Dialogue: 0,0:06:57.69,0:06:58.75,Default,,0,0,0,,在此之前 Dialogue: 0,0:06:58.75,0:07:01.50,Default,,0,0,0,,什么都没有发生改变 Dialogue: 0,0:07:03.21,0:07:04.11,Default,,0,0,0,,举例来说 Dialogue: 0,0:07:04.84,0:07:06.23,Default,,0,0,0,,我们可以想到的一件事是 Dialogue: 0,0:07:06.23,0:07:09.42,Default,,0,0,0,,我们写的一些过程 比如阶乘的程序 Dialogue: 0,0:07:09.64,0:07:12.75,Default,,0,0,0,,事实上与数学中的阶乘函数完全相同 Dialogue: 0,0:07:13.77,0:07:16.44,Default,,0,0,0,,比如说4的阶乘 如果我写FACT(4) Dialogue: 0,0:07:17.23,0:07:19.15,Default,,0,0,0,,无论它的上下文是怎样的 Dialogue: 0,0:07:19.69,0:07:21.29,Default,,0,0,0,,无论我写几遍 Dialogue: 0,0:07:21.29,0:07:22.35,Default,,0,0,0,,我总能得到同样的结果 Dialogue: 0,0:07:23.29,0:07:24.12,Default,,0,0,0,,结果永远是24 Dialogue: 0,0:07:25.37,0:07:28.92,Default,,0,0,0,,它是参数到到结果的唯一映射 Dialogue: 0,0:07:30.30,0:07:32.65,Default,,0,0,0,,迄今为止 我们之前写的所有程序都是这样的 Dialogue: 0,0:07:33.52,0:07:36.03,Default,,0,0,0,,然而 当引入赋值后 一切就不同了 Dialogue: 0,0:07:36.96,0:07:38.16,Default,,0,0,0,,举个例子 Dialogue: 0,0:07:39.18,0:07:48.52,Default,,0,0,0,,如果我将COUNT定义为1 Dialogue: 0,0:07:50.00,0:07:52.41,Default,,0,0,0,,然后定义一个过程 Dialogue: 0,0:07:55.16,0:07:56.83,Default,,0,0,0,,一个叫做DEMO的简单过程 Dialogue: 0,0:07:59.52,0:08:03.84,Default,,0,0,0,,它接受参数X 并执行下面的操作 Dialogue: 0,0:08:03.84,0:08:09.62,Default,,0,0,0,,首先将X修改为X+1 Dialogue: 0,0:08:09.62,0:08:11.77,Default,,0,0,0,,我的天啊! 这看起来就像FORTRAN是吧? Dialogue: 0,0:08:13.16,0:08:14.17,Default,,0,0,0,,只是用了些有趣的语法 Dialogue: 0,0:08:16.80,0:08:21.37,Default,,0,0,0,,然后返回(+ X COUNT) Dialogue: 0,0:08:22.14,0:08:24.14,Default,,0,0,0,,哦 我刚犯了个错 Dialogue: 0,0:08:24.38,0:08:25.23,Default,,0,0,0,,我的意思是 Dialogue: 0,0:08:25.47,0:08:27.12,Default,,0,0,0,,(SET! COUNT (1+ COUNT)) Dialogue: 0,0:08:30.37,0:08:31.79,Default,,0,0,0,,就是我在这里定义的这个 Dialogue: 0,0:08:34.41,0:08:36.51,Default,,0,0,0,,然后X和COUNT相加 Dialogue: 0,0:08:40.35,0:08:42.06,Default,,0,0,0,,然后就可以试着运行这个过程了 Dialogue: 0,0:08:42.48,0:08:43.20,Default,,0,0,0,,让我们运行它 Dialogue: 0,0:08:43.92,0:08:47.22,Default,,0,0,0,,假设我可以输入 Dialogue: 0,0:08:47.48,0:08:48.68,Default,,0,0,0,,输入(DEMO 3) Dialogue: 0,0:08:52.19,0:08:53.20,Default,,0,0,0,,这里发生了什么? Dialogue: 0,0:08:53.74,0:08:55.28,Default,,0,0,0,,发生的第一件事情是 Dialogue: 0,0:08:55.53,0:08:56.89,Default,,0,0,0,,COUNT现在是1 Dialogue: 0,0:08:56.89,0:08:58.40,Default,,0,0,0,,现在 这是一个时间点 Dialogue: 0,0:08:59.12,0:09:00.29,Default,,0,0,0,,我们在讨论时间点 Dialogue: 0,0:09:00.62,0:09:01.74,Default,,0,0,0,,X的值为3 Dialogue: 0,0:09:02.92,0:09:04.03,Default,,0,0,0,,在这个时刻 Dialogue: 0,0:09:04.67,0:09:07.53,Default,,0,0,0,,COUNT增加了 所以COUNT是2 Dialogue: 0,0:09:09.02,0:09:10.44,Default,,0,0,0,,2加3等于5 Dialogue: 0,0:09:10.80,0:09:12.43,Default,,0,0,0,,所以结果是5 Dialogue: 0,0:09:14.48,0:09:21.58,Default,,0,0,0,,然后我再一次 输入(DEMO 3) Dialogue: 0,0:09:23.60,0:09:24.56,Default,,0,0,0,,结果是什么? Dialogue: 0,0:09:24.83,0:09:27.40,Default,,0,0,0,,现在COUNT是2 它不再是1了 Dialogue: 0,0:09:28.91,0:09:30.35,Default,,0,0,0,,因为我让COUNT加1了 Dialogue: 0,0:09:30.92,0:09:32.64,Default,,0,0,0,,但现在我执行这个过程 Dialogue: 0,0:09:32.72,0:09:33.66,Default,,0,0,0,,X的值为3 Dialogue: 0,0:09:34.17,0:09:37.40,Default,,0,0,0,,COUNT变为1+COUNT 因此现在是3了 Dialogue: 0,0:09:38.08,0:09:39.62,Default,,0,0,0,,这两个相加是6 Dialogue: 0,0:09:39.62,0:09:40.94,Default,,0,0,0,,所以结果是6 Dialogue: 0,0:09:41.92,0:09:43.03,Default,,0,0,0,,我们可以发现 Dialogue: 0,0:09:43.03,0:09:44.72,Default,,0,0,0,,同样的表达式 Dialogue: 0,0:09:45.08,0:09:46.64,Default,,0,0,0,,因为时间节点的不同 Dialogue: 0,0:09:48.75,0:09:49.96,Default,,0,0,0,,得到了不同的结果 Dialogue: 0,0:09:52.08,0:09:53.74,Default,,0,0,0,,所以DEMO不是函数 Dialogue: 0,0:09:54.17,0:09:56.12,Default,,0,0,0,,或者说它并没有计算一个数学意义上的函数 Dialogue: 0,0:09:59.88,0:10:02.09,Default,,0,0,0,,事实上 你可以知道这是为什么 Dialogue: 0,0:10:02.84,0:10:06.41,Default,,0,0,0,,因为这里是第一处代换模型失效的地方 Dialogue: 0,0:10:07.72,0:10:09.55,Default,,0,0,0,,它给代换模型判了死刑 Dialogue: 0,0:10:11.28,0:10:13.82,Default,,0,0,0,,有些关于引用的一些小问题 Dialogue: 0,0:10:13.85,0:10:17.18,Default,,0,0,0,,哲学家可能注意到 特别是与代换有关时 Dialogue: 0,0:10:17.18,0:10:19.87,Default,,0,0,0,,因为当你在引用中进行代换时 Dialogue: 0,0:10:20.91,0:10:22.12,Default,,0,0,0,,需要考虑你可以得到什么样的推论 Dialogue: 0,0:10:22.34,0:10:23.92,Default,,0,0,0,,如果你能够使用代换的话 Dialogue: 0,0:10:25.08,0:10:25.60,Default,,0,0,0,,但是 Dialogue: 0,0:10:26.06,0:10:28.00,Default,,0,0,0,,在这里代换模型已经失效了 Dialogue: 0,0:10:28.11,0:10:29.40,Default,,0,0,0,,它什么也不能做了 Dialogue: 0,0:10:29.64,0:10:30.57,Default,,0,0,0,,因为 Dialogue: 0,0:10:30.57,0:10:35.85,Default,,0,0,0,,假设我想用代换模型来考虑COUNT的代换 Dialogue: 0,0:10:37.10,0:10:41.16,Default,,0,0,0,,如果我在这里和这里进行代换 Dialogue: 0,0:10:41.69,0:10:42.96,Default,,0,0,0,,它们是不同的 Dialogue: 0,0:10:44.44,0:10:45.96,Default,,0,0,0,,它不再是同一个COUNT了 Dialogue: 0,0:10:46.48,0:10:47.64,Default,,0,0,0,,我得到了错误的结果 Dialogue: 0,0:10:47.97,0:10:50.14,Default,,0,0,0,,代换模型是一个静态的现象 Dialogue: 0,0:10:51.18,0:10:52.56,Default,,0,0,0,,它描述的事实 Dialogue: 0,0:10:53.93,0:10:55.29,Default,,0,0,0,,而不是变动 Dialogue: 0,0:10:55.50,0:10:57.04,Default,,0,0,0,,这里 我们的事实变动了 Dialogue: 0,0:11:00.60,0:11:06.74,Default,,0,0,0,,那么 在我给出任何解释之前 Dialogue: 0,0:11:06.74,0:11:07.79,Default,,0,0,0,,这很糟糕 Dialogue: 0,0:11:07.79,0:11:09.72,Default,,0,0,0,,我们失去了我们的计算模型 Dialogue: 0,0:11:10.28,0:11:10.80,Default,,0,0,0,,并且 Dialogue: 0,0:11:11.48,0:11:13.69,Default,,0,0,0,,很快 我将不得不构建一个新的计算模型 Dialogue: 0,0:11:14.66,0:11:17.87,Default,,0,0,0,,我们现在的讨论 还是从一个不严谨的角度进行的 Dialogue: 0,0:11:18.56,0:11:20.16,Default,,0,0,0,,当然 你们已经看到的是 Dialogue: 0,0:11:20.51,0:11:22.70,Default,,0,0,0,,当我做一些像赋值之类的事情时 Dialogue: 0,0:11:23.12,0:11:24.51,Default,,0,0,0,,我们所需要的模型 Dialogue: 0,0:11:24.51,0:11:26.89,Default,,0,0,0,,与我们之前模型不同 Dialogue: 0,0:11:26.89,0:11:30.93,Default,,0,0,0,,在这个的模型中 像COUNT或X这样的符号 Dialogue: 0,0:11:30.93,0:11:34.07,Default,,0,0,0,,不再关联于它们的值 Dialogue: 0,0:11:34.07,0:11:37.31,Default,,0,0,0,,而是关联于某个储存这些值的地方 Dialogue: 0,0:11:37.68,0:11:39.47,Default,,0,0,0,,我们将花些时间来适应这种思想 Dialogue: 0,0:11:40.20,0:11:42.11,Default,,0,0,0,,这将是一个很糟糕的事情 Dialogue: 0,0:11:42.11,0:11:43.47,Default,,0,0,0,,并且会造成很多麻烦 Dialogue: 0,0:11:44.49,0:11:48.25,Default,,0,0,0,,所以 就像我说的 若非理由周全 Dialogue: 0,0:11:48.25,0:11:50.09,Default,,0,0,0,,不然绝不要发明这种糟糕的东西 Dialogue: 0,0:11:50.37,0:11:52.86,Default,,0,0,0,,否则 就是劳神费力 Dialogue: 0,0:11:53.39,0:11:55.55,Default,,0,0,0,,让我们看看一些可以讨论的东西 Dialogue: 0,0:11:55.88,0:11:58.59,Default,,0,0,0,,假设我们写了函数式版本的阶乘函数 Dialogue: 0,0:11:58.59,0:12:00.48,Default,,0,0,0,,我们以前的就是“函数式”风格 Dialogue: 0,0:12:01.37,0:12:04.60,Default,,0,0,0,,具有迭代计算过程的阶乘函数 Dialogue: 0,0:12:09.59,0:12:13.28,Default,,0,0,0,,N的阶乘 Dialogue: 0,0:12:18.38,0:12:24.35,Default,,0,0,0,,我们要(ITER M I) Dialogue: 0,0:12:26.12,0:12:33.13,Default,,0,0,0,,就是说如果I大于N Dialogue: 0,0:12:33.77,0:12:35.51,Default,,0,0,0,,则结果是M Dialogue: 0,0:12:36.30,0:12:37.39,Default,,0,0,0,,否则 Dialogue: 0,0:12:39.79,0:12:46.82,Default,,0,0,0,,结果是(ITER (* I M)) Dialogue: 0,0:12:46.82,0:12:49.95,Default,,0,0,0,,所以M将是我累积的结果 Dialogue: 0,0:12:51.58,0:12:52.62,Default,,0,0,0,,M就是这个乘积[注:此处教授笔误] Dialogue: 0,0:12:57.97,0:13:00.17,Default,,0,0,0,,然后我要把COUNT加1 Dialogue: 0,0:13:04.62,0:13:10.97,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:13:11.95,0:13:13.04,Default,,0,0,0,,我在这里启动这个内部过程 Dialogue: 0,0:13:17.16,0:13:19.79,Default,,0,0,0,,对于这种代码 我想大家早已驾轻就熟了 Dialogue: 0,0:13:20.86,0:13:25.15,Default,,0,0,0,,这里是一个累积的乘积 和一个计数器 Dialogue: 0,0:13:26.48,0:13:28.46,Default,,0,0,0,,我让它们都从1开始 Dialogue: 0,0:13:28.89,0:13:30.92,Default,,0,0,0,,我将不断让计数器增加 Dialogue: 0,0:13:30.92,0:13:33.12,Default,,0,0,0,,每一轮I变成I+1 Dialogue: 0,0:13:34.56,0:13:37.47,Default,,0,0,0,,这是我们在这个过程中设置时间的唯一方法 Dialogue: 0,0:13:38.48,0:13:40.04,Default,,0,0,0,,这些都是一系列的事实 Dialogue: 0,0:13:40.49,0:13:41.34,Default,,0,0,0,,真实的规则 Dialogue: 0,0:13:42.81,0:13:46.13,Default,,0,0,0,,M将获得一个新的值 就是I乘M Dialogue: 0,0:13:46.13,0:13:47.82,Default,,0,0,0,,每一轮I乘以M Dialogue: 0,0:13:48.68,0:13:50.48,Default,,0,0,0,,最终I将大于N Dialogue: 0,0:13:50.49,0:13:52.06,Default,,0,0,0,,在这种情况下 结果就是M Dialogue: 0,0:13:52.67,0:13:54.80,Default,,0,0,0,,我给你们讲课的时候 用到了“时间”这个概念 Dialogue: 0,0:13:55.68,0:13:57.45,Default,,0,0,0,,那是因为我知道计算机是怎么工作的 Dialogue: 0,0:13:58.25,0:13:59.24,Default,,0,0,0,,但是我没必要这么做 Dialogue: 0,0:13:59.26,0:14:02.30,Default,,0,0,0,,这完全可以有一个纯数学的解释 Dialogue: 0,0:14:02.30,0:14:03.74,Default,,0,0,0,,因为在这里代换可以工作 Dialogue: 0,0:14:05.10,0:14:08.14,Default,,0,0,0,,但是我们写一个类似的程序 Dialogue: 0,0:14:08.30,0:14:09.95,Default,,0,0,0,,使用相同的算法 Dialogue: 0,0:14:10.73,0:14:12.11,Default,,0,0,0,,但使用了赋值 Dialogue: 0,0:14:15.69,0:14:17.16,Default,,0,0,0,,所以这个叫做函数式版本 Dialogue: 0,0:14:23.72,0:14:25.56,Default,,0,0,0,,我想写个命令式的版本的 Dialogue: 0,0:14:34.48,0:14:35.39,Default,,0,0,0,,N的阶乘 Dialogue: 0,0:14:35.92,0:14:37.74,Default,,0,0,0,,我要创建两个变量 Dialogue: 0,0:14:40.16,0:14:45.53,Default,,0,0,0,,把I的值初始化为1 Dialogue: 0,0:14:46.32,0:14:49.77,Default,,0,0,0,,M也初始化为1 Dialogue: 0,0:14:51.15,0:14:52.19,Default,,0,0,0,,我们创建一个循环 Dialogue: 0,0:14:59.31,0:15:07.27,Default,,0,0,0,,如果I比N大 循环结束 Dialogue: 0,0:15:07.27,0:15:08.87,Default,,0,0,0,,结果是M Dialogue: 0,0:15:08.87,0:15:10.38,Default,,0,0,0,,也就是我累积的乘积 Dialogue: 0,0:15:10.87,0:15:11.77,Default,,0,0,0,,否则 Dialogue: 0,0:15:15.52,0:15:17.40,Default,,0,0,0,,我接下来要做三件事 Dialogue: 0,0:15:19.26,0:15:27.05,Default,,0,0,0,,我要把M赋值为I*M Dialogue: 0,0:15:29.36,0:15:35.20,Default,,0,0,0,,把I赋值为I+1 Dialogue: 0,0:15:37.85,0:15:39.31,Default,,0,0,0,,然后继续循环 Dialogue: 0,0:15:40.41,0:15:43.02,Default,,0,0,0,,你们中的FORTRAN程序员应该觉得眼熟 Dialogue: 0,0:15:44.73,0:15:46.64,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:15:46.64,0:15:47.88,Default,,0,0,0,,就是这种语法有点陌生 Dialogue: 0,0:15:51.13,0:15:52.27,Default,,0,0,0,,启动循环 Dialogue: 0,0:15:56.10,0:15:57.56,Default,,0,0,0,,程序就写完了 Dialogue: 0,0:15:59.15,0:16:00.52,Default,,0,0,0,,那么 这个程序 Dialogue: 0,0:16:01.31,0:16:02.49,Default,,0,0,0,,我们应该怎么思考它呢? Dialogue: 0,0:16:02.71,0:16:04.25,Default,,0,0,0,,先来看看这里是什么 Dialogue: 0,0:16:04.84,0:16:07.47,Default,,0,0,0,,这里有两个局部变量 I和M Dialogue: 0,0:16:07.47,0:16:09.02,Default,,0,0,0,,它们都被初始化为1 Dialogue: 0,0:16:10.72,0:16:13.89,Default,,0,0,0,,在每一次循环里 我检测I是否大于N Dialogue: 0,0:16:13.89,0:16:15.08,Default,,0,0,0,,就是我们传入的参数 Dialogue: 0,0:16:15.30,0:16:18.14,Default,,0,0,0,,如果成立的话 结果就是M中所累积的乘积 Dialogue: 0,0:16:19.16,0:16:21.21,Default,,0,0,0,,然而 如果循环没有结束 Dialogue: 0,0:16:21.21,0:16:22.89,Default,,0,0,0,,如果我们的工作没有结束 Dialogue: 0,0:16:23.64,0:16:25.55,Default,,0,0,0,,则我们要把乘积 Dialogue: 0,0:16:25.84,0:16:28.38,Default,,0,0,0,,变为i与当前乘积的结果 Dialogue: 0,0:16:29.04,0:16:30.68,Default,,0,0,0,,就是我们在这里做过的事情 Dialogue: 0,0:16:31.42,0:16:32.68,Default,,0,0,0,,除了这里我没有改动 Dialogue: 0,0:16:33.63,0:16:35.77,Default,,0,0,0,,我创建了一个复本 Dialogue: 0,0:16:36.81,0:16:42.04,Default,,0,0,0,,因为代换模型就是你复制过程的体 Dialogue: 0,0:16:43.08,0:16:45.88,Default,,0,0,0,,并用实际参数代换形式参数 Dialogue: 0,0:16:46.72,0:16:48.42,Default,,0,0,0,,这里 我考虑的不是副本 Dialogue: 0,0:16:48.42,0:16:50.52,Default,,0,0,0,,在这里 我已经改变了M的值 Dialogue: 0,0:16:51.80,0:16:55.12,Default,,0,0,0,,我也把I的值变成了I+1 Dialogue: 0,0:16:55.61,0:16:56.96,Default,,0,0,0,,然后继续循环 Dialogue: 0,0:16:58.22,0:17:00.08,Default,,0,0,0,,看起来是一样的程序 Dialogue: 0,0:17:00.96,0:17:02.84,Default,,0,0,0,,在今天引入赋值之后 Dialogue: 0,0:17:02.84,0:17:05.50,Default,,0,0,0,,我们在这里有很多种方式犯错 Dialogue: 0,0:17:06.14,0:17:07.02,Default,,0,0,0,,例如 Dialogue: 0,0:17:07.45,0:17:09.40,Default,,0,0,0,,如果我在赋值的时候 Dialogue: 0,0:17:10.04,0:17:12.14,Default,,0,0,0,,没有小心地写程序 Dialogue: 0,0:17:12.64,0:17:16.08,Default,,0,0,0,,把两个赋值的顺序调换了 Dialogue: 0,0:17:17.10,0:17:18.91,Default,,0,0,0,,程序计算的就不是相同的函数了 Dialogue: 0,0:17:20.33,0:17:22.87,Default,,0,0,0,,我得到了一个时间错误 因为这儿有个依赖关系 Dialogue: 0,0:17:22.87,0:17:27.22,Default,,0,0,0,,因为M依赖于I上一次的值 Dialogue: 0,0:17:27.34,0:17:28.92,Default,,0,0,0,,如果我先改变I的值 Dialogue: 0,0:17:31.31,0:17:33.77,Default,,0,0,0,,就会在乘以M的时候 得到错误的I值 Dialogue: 0,0:17:35.96,0:17:38.38,Default,,0,0,0,,没有赋值的话不会存在这样的BUG Dialogue: 0,0:17:38.38,0:17:40.59,Default,,0,0,0,,这是由于我们引入了某些包含时间的东西造成的 Dialogue: 0,0:17:43.44,0:17:44.30,Default,,0,0,0,,如我所说的 Dialogue: 0,0:17:45.53,0:17:47.39,Default,,0,0,0,,首先 我们需要一个新的计算模型 Dialogue: 0,0:17:47.39,0:17:50.86,Default,,0,0,0,,然后 需要有一个非常好的理由来支持我们做如此丑陋的事 Dialogue: 0,0:17:52.72,0:17:53.74,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:17:58.83,0:18:00.22,Default,,0,0,0,,David 大点儿声说 Dialogue: 0,0:18:00.40,0:18:03.47,Default,,0,0,0,,学生:现在 我们引入了SET! Dialogue: 0,0:18:03.90,0:18:06.36,Default,,0,0,0,,但是之前我们已经有LET和DEFINE了 Dialogue: 0,0:18:06.89,0:18:09.70,Default,,0,0,0,,我不太清楚它们的区别 Dialogue: 0,0:18:09.70,0:18:13.25,Default,,0,0,0,,DEFINE不能像SET!一样用吗? Dialogue: 0,0:18:13.98,0:18:14.83,Default,,0,0,0,,请详细讲讲 Dialogue: 0,0:18:14.83,0:18:19.31,Default,,0,0,0,,教授:不 DEFINE用于创建并初始化 Dialogue: 0,0:18:19.31,0:18:21.36,Default,,0,0,0,,为了创建它 Dialogue: 0,0:18:22.08,0:18:24.70,Default,,0,0,0,,你永远也不会见到我在黑板上 Dialogue: 0,0:18:25.60,0:18:26.94,Default,,0,0,0,,在同一行写两个DEFINE Dialogue: 0,0:18:27.08,0:18:32.08,Default,,0,0,0,,只是为了让某个变量的旧值变成一个新的值 Dialogue: 0,0:18:32.08,0:18:34.51,Default,,0,0,0,,学生:这是一个约定俗成的规矩 还是-- Dialogue: 0,0:18:34.51,0:18:36.35,Default,,0,0,0,,教授:不 这是有意为之的 Dialogue: 0,0:18:36.35,0:18:38.92,Default,,0,0,0,,答案是 Dialogue: 0,0:18:39.69,0:18:40.84,Default,,0,0,0,,举个例子 Dialogue: 0,0:18:40.84,0:18:42.27,Default,,0,0,0,,在一个过程内部 Dialogue: 0,0:18:43.20,0:18:45.92,Default,,0,0,0,,两个DEFINE写在一行里是非法的 Dialogue: 0,0:18:46.68,0:18:48.57,Default,,0,0,0,,对于同一个变量DEFINE两次是非法的 Dialogue: 0,0:18:50.24,0:18:51.74,Default,,0,0,0,,X不能被DEFINE两次 Dialogue: 0,0:18:51.74,0:18:55.20,Default,,0,0,0,,而系统会不会捕获这个错误 就是另一个问题了 Dialogue: 0,0:18:55.93,0:18:57.88,Default,,0,0,0,,但是我定下规矩 Dialogue: 0,0:18:58.12,0:19:00.64,Default,,0,0,0,,任何东西都只能DEFINE一次 Dialogue: 0,0:19:00.73,0:19:02.64,Default,,0,0,0,,确实 在交互式调试中 Dialogue: 0,0:19:03.37,0:19:07.48,Default,,0,0,0,,我们打算让你与计算机交互时可以重新DEFINE一些东西 Dialogue: 0,0:19:08.19,0:19:11.21,Default,,0,0,0,,所以交互式调试时产生的是一个特殊的异常 Dialogue: 0,0:19:11.82,0:19:16.48,Default,,0,0,0,,但是DEFINE的意思是建立某些东西 Dialogue: 0,0:19:18.14,0:19:20.96,Default,,0,0,0,,在那个时间点后 它的值是永远不变的 Dialogue: 0,0:19:22.05,0:19:24.54,Default,,0,0,0,,好像所有的DEFINE都是在最开始完成的 Dialogue: 0,0:19:26.09,0:19:30.92,Default,,0,0,0,,事实上 在Scheme过程中 DEFINE的唯一合法使用地方 Dialogue: 0,0:19:31.02,0:19:33.36,Default,,0,0,0,,就是在LAMBDA表达式的开始 Dialogue: 0,0:19:34.47,0:19:37.66,Default,,0,0,0,,也就是过程体的开始 Dialogue: 0,0:19:40.40,0:19:45.80,Default,,0,0,0,,LET当然与那个不一样 Dialogue: 0,0:19:48.09,0:19:49.55,Default,,0,0,0,,如果你想知道LET发生了什么 Dialogue: 0,0:19:50.17,0:19:52.13,Default,,0,0,0,,LET只会绑定一次 Dialogue: 0,0:19:52.13,0:19:55.82,Default,,0,0,0,,它建立了一个I和M的值分别为1的上下文 Dialogue: 0,0:19:56.83,0:20:00.57,Default,,0,0,0,,这个上下文存在于整个作用域中 Dialogue: 0,0:20:01.31,0:20:02.80,Default,,0,0,0,,也就是这个程序范围 Dialogue: 0,0:20:04.99,0:20:10.12,Default,,0,0,0,,然而 你不会认为LET再次设置了I的值 Dialogue: 0,0:20:11.04,0:20:12.16,Default,,0,0,0,,它没有改变I的值 Dialogue: 0,0:20:12.16,0:20:14.01,Default,,0,0,0,,因为LET的作用 I将永远不会变化 Dialogue: 0,0:20:15.28,0:20:16.81,Default,,0,0,0,,因为LET的作用 I才被创建 Dialogue: 0,0:20:18.51,0:20:19.29,Default,,0,0,0,,实际上 Dialogue: 0,0:20:19.73,0:20:21.42,Default,,0,0,0,,LET是一个非常简单的想法 Dialogue: 0,0:20:22.24,0:20:23.59,Default,,0,0,0,,LET不会做别的事情 Dialogue: 0,0:20:23.59,0:20:31.62,Default,,0,0,0,,LET的语义是…… Dialogue: 0,0:20:31.62,0:20:33.50,Default,,0,0,0,,我把它写得更准确点 Dialogue: 0,0:20:37.16,0:20:43.73,Default,,0,0,0,,表达式 (var1 e1) Dialogue: 0,0:20:43.73,0:20:47.36,Default,,0,0,0,,还有(var2 e2) Dialogue: 0,0:20:48.14,0:20:49.74,Default,,0,0,0,,在表达式e3中 Dialogue: 0,0:20:51.60,0:21:05.80,Default,,0,0,0,,与一个以var1和var2为形式参数的过程一样 Dialogue: 0,0:21:06.94,0:21:08.96,Default,,0,0,0,,e3成为过程的体 Dialogue: 0,0:21:10.91,0:21:14.00,Default,,0,0,0,,在这里 var1与e1的值绑定 Dialogue: 0,0:21:14.27,0:21:16.91,Default,,0,0,0,,var2与e2的值绑定 Dialogue: 0,0:21:19.53,0:21:23.26,Default,,0,0,0,,所以实际上 这是一个从代换的角度来看很容易理解的东西 Dialogue: 0,0:21:24.89,0:21:27.95,Default,,0,0,0,,其实就是同一个表达式的两种不同的写法 Dialogue: 0,0:21:31.69,0:21:33.50,Default,,0,0,0,,事实上 系统真正的工作方式 Dialogue: 0,0:21:33.63,0:21:35.82,Default,,0,0,0,,就是在运行之前把代码翻译成这种形式 Dialogue: 0,0:21:37.64,0:21:41.77,Default,,0,0,0,,学生:我还是不清楚是什么造成了LET和DEFINE之间的区别 Dialogue: 0,0:21:41.77,0:21:44.30,Default,,0,0,0,,教授:DEFINE就是个语法糖 Dialogue: 0,0:21:44.62,0:21:49.10,Default,,0,0,0,,本质上来说 是通过LET创建一系列变量 然后给它们一次性赋值 Dialogue: 0,0:21:57.10,0:21:59.74,Default,,0,0,0,,好吧 我们休息一会 Dialogue: 0,0:22:02.52,0:22:12.84,Default,,0,0,0,,[音乐] Dialogue: 0,0:22:12.84,0:22:17.84,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:22:48.81,0:22:52.67,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:22:52.67,0:22:56.52,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:22:56.52,0:23:00.59,Declare,,0,0,0,,{\an2\fad(500,500)}赋值、状态和副作用 Dialogue: 0,0:23:04.28,0:23:06.11,Default,,0,0,0,,看 Dialogue: 0,0:23:06.44,0:23:09.08,Default,,0,0,0,,现在 我不得不重建计算模型 Dialogue: 0,0:23:09.77,0:23:14.16,Default,,0,0,0,,使得你能够明白那些机制是如何运作的 Dialogue: 0,0:23:14.91,0:23:16.46,Default,,0,0,0,,来完成我们刚才说的那些工作 Dialogue: 0,0:23:17.53,0:23:21.39,Default,,0,0,0,,我刚刚摧毁了你们的代换模型 Dialogue: 0,0:23:22.62,0:23:26.03,Default,,0,0,0,,不幸的是 这个模型比代换模型要复杂得多 Dialogue: 0,0:23:26.62,0:23:27.93,Default,,0,0,0,,这个模型叫环境模型 Dialogue: 0,0:23:29.02,0:23:31.20,Default,,0,0,0,,我即将介绍一些术语 Dialogue: 0,0:23:32.03,0:23:34.51,Default,,0,0,0,,无论如何 你知道这些术语都是很好的 Dialogue: 0,0:23:34.51,0:23:35.74,Default,,0,0,0,,它是关于名字的 Dialogue: 0,0:23:36.51,0:23:39.63,Default,,0,0,0,,我们要给事物的各种名字 Dialogue: 0,0:23:40.00,0:23:41.31,Default,,0,0,0,,和名字的使用途径以名字 Dialogue: 0,0:23:42.48,0:23:47.94,Default,,0,0,0,,如果硬要说的话 这是一个元描述 Dialogue: 0,0:23:48.56,0:23:50.85,Default,,0,0,0,,总之 这里面有一堆糟糕的术语 Dialogue: 0,0:23:50.85,0:23:53.76,Default,,0,0,0,,但我们需要利用它们来理解所谓的“环境模型” Dialogue: 0,0:23:54.70,0:23:57.53,Default,,0,0,0,,我们可能要做一点无聊的事情了 Dialogue: 0,0:23:58.04,0:24:01.58,Default,,0,0,0,,我们来看第一张张幻灯片 Dialogue: 0,0:24:02.25,0:24:06.97,Default,,0,0,0,,我们看到了术语“约束”的解释 Dialogue: 0,0:24:08.80,0:24:11.00,Default,,0,0,0,,我们会说一个变量V Dialogue: 0,0:24:11.00,0:24:12.91,Default,,0,0,0,,被约束在表达式E中 Dialogue: 0,0:24:13.41,0:24:21.52,Default,,0,0,0,,如果用一个没有出现在E中的变量W 对变量V统一换名 Dialogue: 0,0:24:21.56,0:24:24.28,Default,,0,0,0,,表达式语义没有发生改变 Dialogue: 0,0:24:25.69,0:24:27.00,Default,,0,0,0,,这个解释很长 Dialogue: 0,0:24:27.37,0:24:29.96,Default,,0,0,0,,在我们在被搞糊涂之前 Dialogue: 0,0:24:29.98,0:24:32.62,Default,,0,0,0,,我应该再多解释下 Dialogue: 0,0:24:33.42,0:24:35.28,Default,,0,0,0,,我们这里讨论的约束变量 Dialogue: 0,0:24:44.16,0:24:45.56,Default,,0,0,0,,你们已经看到它们很多次了 Dialogue: 0,0:24:46.07,0:24:48.17,Default,,0,0,0,,只是你们可能还没意识到 Dialogue: 0,0:24:48.24,0:24:52.24,Default,,0,0,0,,在逻辑学中 你们看到一个逻辑变量 Dialogue: 0,0:24:53.27,0:25:00.11,Default,,0,0,0,,就像微积分课上的 对于任意任何X 存在一个Y 使得P为真 Dialogue: 0,0:25:02.88,0:25:05.82,Default,,0,0,0,,这个变量X 这个变量Y 它们是约束变量 Dialogue: 0,0:25:07.08,0:25:07.92,Default,,0,0,0,,因为 Dialogue: 0,0:25:08.33,0:25:09.98,Default,,0,0,0,,这个表达式的含义 Dialogue: 0,0:25:09.98,0:25:15.61,Default,,0,0,0,,不取决于我用来描述X和Y的具体字母 Dialogue: 0,0:25:16.49,0:25:19.18,Default,,0,0,0,,如果我用W替换X Dialogue: 0,0:25:19.84,0:25:25.68,Default,,0,0,0,,则可以说对于任意W 存在一个Y使得P为真 Dialogue: 0,0:25:25.98,0:25:27.08,Default,,0,0,0,,它们其实是同一句话 Dialogue: 0,0:25:29.44,0:25:30.34,Default,,0,0,0,,就是这个意思 Dialogue: 0,0:25:30.34,0:25:34.89,Default,,0,0,0,,又或者说 你们看到这样一个积分 Dialogue: 0,0:25:35.40,0:25:42.65,Default,,0,0,0,,对dx/(1+x^2)从0到1积分 Dialogue: 0,0:25:46.03,0:25:47.92,Default,,0,0,0,,这就是你们经常见到的那种东西 Dialogue: 0,0:25:47.92,0:25:50.92,Default,,0,0,0,,这个x是一个约束变量 Dialogue: 0,0:25:52.06,0:25:53.79,Default,,0,0,0,,如果我把它换成t Dialogue: 0,0:25:54.15,0:25:56.25,Default,,0,0,0,,这个表达式其实没有变化 Dialogue: 0,0:25:58.06,0:26:02.76,Default,,0,0,0,,就是arctan(1)/4之类的 Dialogue: 0,0:26:04.70,0:26:06.01,Default,,0,0,0,,是的 就是arctan(1) Dialogue: 0,0:26:06.62,0:26:08.76,Default,,0,0,0,,所以约束变量事实上很常见 Dialogue: 0,0:26:09.08,0:26:12.36,Default,,0,0,0,,如果你们接触过一些数学的话 Dialogue: 0,0:26:13.26,0:26:17.47,Default,,0,0,0,,好 让我们来到编程的世界 Dialogue: 0,0:26:19.02,0:26:21.36,Default,,0,0,0,,现在量词不再是 Dialogue: 0,0:26:22.03,0:26:24.06,Default,,0,0,0,,所有、存在和积分 Dialogue: 0,0:26:24.06,0:26:26.43,Default,,0,0,0,,我们有一个符号作为量词 用于约束变量 Dialogue: 0,0:26:27.47,0:26:28.99,Default,,0,0,0,,我们要使用量词LAMBDA Dialogue: 0,0:26:29.79,0:26:31.80,Default,,0,0,0,,作为约束变量的一个必要的东西 Dialogue: 0,0:26:33.80,0:26:36.12,Default,,0,0,0,,我们有一个极好的例子 Dialogue: 0,0:26:36.59,0:26:44.14,Default,,0,0,0,,对于以Y为参数的过程 做了以下的事情 Dialogue: 0,0:26:44.14,0:26:46.96,Default,,0,0,0,,它调用一个含单个参数X的过程 Dialogue: 0,0:26:47.87,0:26:51.13,Default,,0,0,0,,该过程 将X乘以Y Dialogue: 0,0:26:52.88,0:26:54.52,Default,,0,0,0,,并应用于3 Dialogue: 0,0:26:58.76,0:27:01.66,Default,,0,0,0,,这个过程中包含两个约束变量 Dialogue: 0,0:27:02.01,0:27:02.92,Default,,0,0,0,,X和Y Dialogue: 0,0:27:04.83,0:27:07.47,Default,,0,0,0,,这个LAMBDA量词 约束了这个Y Dialogue: 0,0:27:07.91,0:27:10.78,Default,,0,0,0,,这个LAMBDA量词 约束了这个X Dialogue: 0,0:27:12.11,0:27:17.05,Default,,0,0,0,,因为 如果我用了一个没有出现在表达式中的任意符号 如W Dialogue: 0,0:27:17.98,0:27:21.04,Default,,0,0,0,,用W替换表达式中的所有Y Dialogue: 0,0:27:21.36,0:27:22.75,Default,,0,0,0,,这个表达式仍与原来的相同 Dialogue: 0,0:27:23.66,0:27:24.80,Default,,0,0,0,,是相同的过程 Dialogue: 0,0:27:26.22,0:27:27.41,Default,,0,0,0,,这是一个重要的想法 Dialogue: 0,0:27:27.41,0:27:29.64,Default,,0,0,0,,我们有这种东西的原因 Dialogue: 0,0:27:30.20,0:27:31.41,Default,,0,0,0,,这是一种模块性 Dialogue: 0,0:27:31.41,0:27:32.86,Default,,0,0,0,,如果有两个人写程序 Dialogue: 0,0:27:34.03,0:27:35.26,Default,,0,0,0,,并且他们在合作编程 Dialogue: 0,0:27:35.26,0:27:40.56,Default,,0,0,0,,在他们自己构建的小项目里用什么命名都没有关系 Dialogue: 0,0:27:42.83,0:27:44.67,Default,,0,0,0,,所以 实际上我想告诉你们 Dialogue: 0,0:27:45.44,0:27:46.75,Default,,0,0,0,,例如 Dialogue: 0,0:27:46.84,0:27:51.26,Default,,0,0,0,,这个表达式等于 以Y为参数的过程 Dialogue: 0,0:27:52.35,0:27:59.23,Default,,0,0,0,,使用这个对于一个参数Z的过程 这个过程将Z乘以Y Dialogue: 0,0:28:01.64,0:28:03.53,Default,,0,0,0,,因为没人关心我在这用什么 Dialogue: 0,0:28:06.36,0:28:07.24,Default,,0,0,0,,这是一个极好的例子 Dialogue: 0,0:28:08.84,0:28:09.85,Default,,0,0,0,,另一方面 Dialogue: 0,0:28:11.07,0:28:14.33,Default,,0,0,0,,我有一些未被约束的变量 Dialogue: 0,0:28:15.23,0:28:15.96,Default,,0,0,0,,举个例子 Dialogue: 0,0:28:20.27,0:28:21.76,Default,,0,0,0,,这个对于一个以X为参数的过程 Dialogue: 0,0:28:22.09,0:28:25.04,Default,,0,0,0,,将X乘以Y Dialogue: 0,0:28:27.28,0:28:28.16,Default,,0,0,0,,在这个例子中 Dialogue: 0,0:28:29.45,0:28:30.75,Default,,0,0,0,,y没有被约束 Dialogue: 0,0:28:32.46,0:28:34.27,Default,,0,0,0,,假设Y的值是3 Dialogue: 0,0:28:35.26,0:28:36.80,Default,,0,0,0,,Z的值是4 Dialogue: 0,0:28:38.83,0:28:44.27,Default,,0,0,0,,那么这个过程就是把它的参数乘以3 Dialogue: 0,0:28:44.86,0:28:47.39,Default,,0,0,0,,如果我把所有的y都用z来代替 Dialogue: 0,0:28:47.52,0:28:51.96,Default,,0,0,0,,我将得到一个完全不同的过程 它会把参数乘以4 Dialogue: 0,0:28:53.87,0:28:56.40,Default,,0,0,0,,事实上 我们给这类变量取了个名字 Dialogue: 0,0:28:57.76,0:29:04.01,Default,,0,0,0,,我们把表达式E中的变量V叫做自由变量 Dialogue: 0,0:29:04.01,0:29:09.42,Default,,0,0,0,,如果用没有出现在E中的变量W统一替换E中所有的V Dialogue: 0,0:29:09.58,0:29:11.15,Default,,0,0,0,,使得表达式E的含义发生了改变 Dialogue: 0,0:29:13.26,0:29:13.71,Default,,0,0,0,,所以 Dialogue: 0,0:29:14.49,0:29:22.76,Default,,0,0,0,,所以这就是为什么这个变量Y 是一个自由变量 Dialogue: 0,0:29:29.16,0:29:32.27,Default,,0,0,0,,所以 这个表达式里的自由变量 Dialogue: 0,0:29:33.76,0:29:35.18,Default,,0,0,0,,另一个例子是 Dialogue: 0,0:29:36.17,0:29:39.32,Default,,0,0,0,,对于一个以Y为参数的过程 Dialogue: 0,0:29:40.43,0:29:42.00,Default,,0,0,0,,就像我们之前的那个一样 Dialogue: 0,0:29:42.27,0:29:44.60,Default,,0,0,0,,调用以X为参数的过程 Dialogue: 0,0:29:45.08,0:29:48.54,Default,,0,0,0,,将X与Y相乘-- Dialogue: 0,0:29:51.40,0:29:52.65,Default,,0,0,0,,并应用于3 Dialogue: 0,0:29:57.24,0:30:00.35,Default,,0,0,0,,这个过程中有一个自由变量 Dialogue: 0,0:30:00.92,0:30:01.98,Default,,0,0,0,,也就是这个星号 Dialogue: 0,0:30:05.00,0:30:05.89,Default,,0,0,0,,因为 Dialogue: 0,0:30:05.89,0:30:08.08,Default,,0,0,0,,如果它表示正常意义的乘法 Dialogue: 0,0:30:09.44,0:30:12.78,Default,,0,0,0,,如果我统一地用加号来代替星号 Dialogue: 0,0:30:14.25,0:30:16.38,Default,,0,0,0,,这个表达式的含义就变了 Dialogue: 0,0:30:19.34,0:30:20.76,Default,,0,0,0,,这就是自由变量的意思 Dialogue: 0,0:30:22.68,0:30:24.81,Default,,0,0,0,,现在 你们已经学到了一些逻辑学术语 Dialogue: 0,0:30:25.64,0:30:27.58,Default,,0,0,0,,用它们可以解释名字的用法 Dialogue: 0,0:30:28.94,0:30:31.26,Default,,0,0,0,,我们要需要更进一步深入 Dialogue: 0,0:30:32.96,0:30:33.72,Default,,0,0,0,,再多了解一些 Dialogue: 0,0:30:35.13,0:30:36.22,Default,,0,0,0,,我想给你们讲讲 Dialogue: 0,0:30:36.81,0:30:39.76,Default,,0,0,0,,变量被定义的区域 Dialogue: 0,0:30:42.17,0:30:42.88,Default,,0,0,0,,你瞧 Dialogue: 0,0:30:43.37,0:30:45.69,Default,,0,0,0,,目前为止 我们已经相当不正式了 Dialogue: 0,0:30:46.33,0:30:50.16,Default,,0,0,0,,当然 你们中的一些 或者大部分人可能已经理解得很透彻了 Dialogue: 0,0:30:50.36,0:30:52.84,Default,,0,0,0,,在这里被声明的X Dialogue: 0,0:30:53.64,0:30:55.18,Default,,0,0,0,,只被定义在这里 Dialogue: 0,0:30:58.28,0:31:00.91,Default,,0,0,0,,这个X 只被定义在这里 Dialogue: 0,0:31:01.61,0:31:04.33,Default,,0,0,0,,这个Y 只被定义在这里 Dialogue: 0,0:31:07.10,0:31:09.16,Default,,0,0,0,,我们给这个概念取了个名字 叫“作用域” Dialogue: 0,0:31:11.61,0:31:13.58,Default,,0,0,0,,我给你们再讲个术语 Dialogue: 0,0:31:14.70,0:31:15.77,Default,,0,0,0,,这个就比较复杂 Dialogue: 0,0:31:15.96,0:31:17.64,Default,,0,0,0,,如果X是E中的一个约束变量 Dialogue: 0,0:31:18.16,0:31:20.24,Default,,0,0,0,,那么它是约束于一个LAMBDA表达式中 Dialogue: 0,0:31:20.89,0:31:24.91,Default,,0,0,0,,LAMBDA表达式是约束变量的唯一方式 Dialogue: 0,0:31:24.91,0:31:25.96,Default,,0,0,0,,你可能会担心 Dialogue: 0,0:31:26.22,0:31:29.05,Default,,0,0,0,,DEFINE是它的一个例外吗? Dialogue: 0,0:31:29.64,0:31:32.92,Default,,0,0,0,,事实证明 通过巧妙安排 我们可以避免使用DEFINE Dialogue: 0,0:31:32.92,0:31:33.96,Default,,0,0,0,,一会我们就能看到了 Dialogue: 0,0:31:34.24,0:31:35.72,Default,,0,0,0,,它一个非常神奇的东西 Dialogue: 0,0:31:36.54,0:31:38.40,Default,,0,0,0,,所以我们完全不需要DEFINE Dialogue: 0,0:31:38.68,0:31:41.55,Default,,0,0,0,,实际上 唯一能创建名字的东西是LAMBDA Dialogue: 0,0:31:42.64,0:31:43.40,Default,,0,0,0,,这就是它的职责 Dialogue: 0,0:31:44.30,0:31:46.23,Default,,0,0,0,,多么的令人惊奇 Dialogue: 0,0:31:46.23,0:31:47.87,Default,,0,0,0,,很多东西你只凭借LAMBDA就可以计算 Dialogue: 0,0:31:48.73,0:31:49.58,Default,,0,0,0,,但是 在任何情况下 Dialogue: 0,0:31:51.74,0:31:55.76,Default,,0,0,0,,一个LAMBDA表达式有一个地方来声明变量 Dialogue: 0,0:31:55.76,0:31:57.10,Default,,0,0,0,,我们把它称为形式参数表 Dialogue: 0,0:31:58.94,0:32:00.56,Default,,0,0,0,,或者叫 约束变量表 Dialogue: 0,0:32:01.26,0:32:04.51,Default,,0,0,0,,我们说LAMBDA表达式约束了--这是一个动词 Dialogue: 0,0:32:05.02,0:32:07.34,Default,,0,0,0,,--约束了在约束变量表里声明的变量 Dialogue: 0,0:32:08.59,0:32:12.48,Default,,0,0,0,,另外 表达式中定义变量的那些部分 Dialogue: 0,0:32:13.23,0:32:15.23,Default,,0,0,0,,是被一些声明所声明的 Dialogue: 0,0:32:15.56,0:32:19.26,Default,,0,0,0,,这些部分被叫做变量的作用域 Dialogue: 0,0:32:20.44,0:32:21.92,Default,,0,0,0,,所以 这些是作用域 Dialogue: 0,0:32:22.25,0:32:23.68,Default,,0,0,0,,这是Y的作用域 Dialogue: 0,0:32:27.16,0:32:28.54,Default,,0,0,0,,这是X的作用域-- Dialogue: 0,0:32:33.10,0:32:34.03,Default,,0,0,0,,以此类推 Dialogue: 0,0:32:41.32,0:32:42.08,Default,,0,0,0,,好 Dialogue: 0,0:32:43.93,0:32:45.63,Default,,0,0,0,,现在我们有了足够多的术语 Dialogue: 0,0:32:46.60,0:32:51.76,Default,,0,0,0,,可以开始理解如何建立一个新的计算模型了 Dialogue: 0,0:32:51.96,0:32:53.77,Default,,0,0,0,,因为 这里很重要的一点是 Dialogue: 0,0:32:54.94,0:32:57.00,Default,,0,0,0,,我们摧毁了代换模型 Dialogue: 0,0:32:57.18,0:32:58.38,Default,,0,0,0,,我们现在不得不需要一个模型 Dialogue: 0,0:32:58.62,0:33:02.32,Default,,0,0,0,,来体现表示名字被关联到某些地方 Dialogue: 0,0:33:03.93,0:33:05.34,Default,,0,0,0,,因为 如果我们要改变某个东西 Dialogue: 0,0:33:05.98,0:33:07.47,Default,,0,0,0,,我们就需要一个存它的地方 Dialogue: 0,0:33:09.56,0:33:10.35,Default,,0,0,0,,请想一想 Dialogue: 0,0:33:10.83,0:33:13.31,Default,,0,0,0,,如果一个名字只是关联于一个值 Dialogue: 0,0:33:14.04,0:33:16.36,Default,,0,0,0,,如果我试图改变这个名字的含义 Dialogue: 0,0:33:16.73,0:33:20.32,Default,,0,0,0,,这不怎么明确 Dialogue: 0,0:33:20.32,0:33:24.68,Default,,0,0,0,,因为没有名字可以关联的地方 Dialogue: 0,0:33:24.99,0:33:25.80,Default,,0,0,0,,该怎么解释呢…… Dialogue: 0,0:33:25.92,0:33:29.54,Default,,0,0,0,,也就是名字的所有实例之间没有共享任何东西 Dialogue: 0,0:33:29.87,0:33:31.68,Default,,0,0,0,,也就是说 对于一个名字 Dialogue: 0,0:33:31.68,0:33:32.97,Default,,0,0,0,,是用来让我们找到某些东西的 Dialogue: 0,0:33:34.33,0:33:36.36,Default,,0,0,0,,我们把名字给某个东西 然后你拿到了它 Dialogue: 0,0:33:36.73,0:33:39.06,Default,,0,0,0,,你能得到它 是因为我给了你一个它的引用 Dialogue: 0,0:33:39.06,0:33:40.44,Default,,0,0,0,,我把对它的引用给了你 Dialogue: 0,0:33:41.02,0:33:42.30,Default,,0,0,0,,我们会看到很多相关的例子 Dialogue: 0,0:33:43.61,0:33:45.21,Default,,0,0,0,,让我们继续学习“环境” Dialogue: 0,0:33:46.19,0:33:48.76,Default,,0,0,0,,我需要用一下头顶上的投影仪 Dialogue: 0,0:33:49.31,0:33:49.98,Default,,0,0,0,,谢谢你 Dialogue: 0,0:33:52.19,0:33:53.02,Default,,0,0,0,,这里 Dialogue: 0,0:33:55.48,0:34:00.40,Default,,0,0,0,,是一堆环境结构 Dialogue: 0,0:34:01.53,0:34:05.76,Default,,0,0,0,,环境就是执行虚拟的代换的一种方法 Dialogue: 0,0:34:06.38,0:34:07.89,Default,,0,0,0,,它代表了一个地方 Dialogue: 0,0:34:07.89,0:34:11.39,Default,,0,0,0,,是存储你的未完成的代换的地方 Dialogue: 0,0:34:13.34,0:34:16.50,Default,,0,0,0,,它是一个积累各种东西的地方 Dialogue: 0,0:34:16.50,0:34:21.13,Default,,0,0,0,,在那里 变量的名字与值关联在一起 Dialogue: 0,0:34:21.79,0:34:22.56,Default,,0,0,0,,使得 Dialogue: 0,0:34:22.75,0:34:25.90,Default,,0,0,0,,当你问某个名字是什么意思的时候 Dialogue: 0,0:34:25.90,0:34:27.40,Default,,0,0,0,,你要在一个环境中寻找答案 Dialogue: 0,0:34:28.08,0:34:29.48,Default,,0,0,0,,所以环境是一个函数 Dialogue: 0,0:34:30.80,0:34:31.48,Default,,0,0,0,,或一张表 Dialogue: 0,0:34:32.22,0:34:33.24,Default,,0,0,0,,或类似的东西 Dialogue: 0,0:34:33.24,0:34:34.89,Default,,0,0,0,,但它是一种结构化的表 Dialogue: 0,0:34:35.76,0:34:37.39,Default,,0,0,0,,它是由框架构成 Dialogue: 0,0:34:41.13,0:34:44.46,Default,,0,0,0,,框架是环境的一部分 Dialogue: 0,0:34:44.89,0:34:46.01,Default,,0,0,0,,它们被链接在一起 Dialogue: 0,0:34:47.07,0:34:48.19,Default,,0,0,0,,以某种很好的方式 Dialogue: 0,0:34:49.00,0:34:52.09,Default,,0,0,0,,用一种叫做父链接之类的东西 Dialogue: 0,0:34:54.03,0:34:55.02,Default,,0,0,0,,这里 Dialogue: 0,0:34:55.64,0:34:57.62,Default,,0,0,0,,有一个环境结构 Dialogue: 0,0:34:57.62,0:35:04.22,Default,,0,0,0,,它由三个环境组成 分别是A B和C Dialogue: 0,0:35:05.10,0:35:07.63,Default,,0,0,0,,D也是环境 但它和C是一样的 Dialogue: 0,0:35:08.88,0:35:10.17,Default,,0,0,0,,它们共享了同一个环境 Dialogue: 0,0:35:11.45,0:35:13.96,Default,,0,0,0,,那就是赋值的本质所在 Dialogue: 0,0:35:14.40,0:35:16.10,Default,,0,0,0,,如果我改变了一个变量 Dialogue: 0,0:35:16.10,0:35:19.80,Default,,0,0,0,,比如改变这个变量的值 Dialogue: 0,0:35:19.80,0:35:23.50,Default,,0,0,0,,那么它将在所有地方都可见 Dialogue: 0,0:35:23.50,0:35:24.84,Default,,0,0,0,,用x来举例 Dialogue: 0,0:35:24.84,0:35:28.19,Default,,0,0,0,,如果我将X改为4 Dialogue: 0,0:35:28.19,0:35:30.19,Default,,0,0,0,,在其他地方也是可见的 Dialogue: 0,0:35:30.19,0:35:32.19,Default,,0,0,0,,但是我们现在不去关心这个 Dialogue: 0,0:35:32.19,0:35:33.84,Default,,0,0,0,,过一会儿会详细讨论这个问题 Dialogue: 0,0:35:34.56,0:35:35.53,Default,,0,0,0,,这里有什么? Dialogue: 0,0:35:36.76,0:35:38.84,Default,,0,0,0,,这些叫做框架 这是一个框架 Dialogue: 0,0:35:39.40,0:35:40.38,Default,,0,0,0,,这是一个框架 Dialogue: 0,0:35:40.76,0:35:41.84,Default,,0,0,0,,这也是一个框架 Dialogue: 0,0:35:43.18,0:35:45.20,Default,,0,0,0,,A是一个环境 Dialogue: 0,0:35:45.20,0:35:47.82,Default,,0,0,0,,它由框架II Dialogue: 0,0:35:48.36,0:35:51.05,Default,,0,0,0,,和框架I组成 Dialogue: 0,0:35:52.52,0:35:54.60,Default,,0,0,0,,在这个环境中 Dialogue: 0,0:35:54.99,0:35:59.68,Default,,0,0,0,,在环境C中 在框架II中 Dialogue: 0,0:36:00.48,0:36:03.26,Default,,0,0,0,,X和Y是被约束的 Dialogue: 0,0:36:04.06,0:36:04.78,Default,,0,0,0,,它们具有值 Dialogue: 0,0:36:05.26,0:36:07.18,Default,,0,0,0,,对不起 是在框架I中 Dialogue: 0,0:36:07.18,0:36:08.28,Default,,0,0,0,,而在框架II中 Dialogue: 0,0:36:09.72,0:36:10.83,Default,,0,0,0,,Z被约束 Dialogue: 0,0:36:10.99,0:36:12.17,Default,,0,0,0,,X被约束 Dialogue: 0,0:36:12.44,0:36:13.69,Default,,0,0,0,,并且Y也是被约束的 Dialogue: 0,0:36:15.24,0:36:17.40,Default,,0,0,0,,但是我们看到的X的值 Dialogue: 0,0:36:17.42,0:36:19.04,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:36:20.01,0:36:21.74,Default,,0,0,0,,是这个X 它的值是7 Dialogue: 0,0:36:22.36,0:36:24.84,Default,,0,0,0,,而不是这个值为3的X Dialogue: 0,0:36:24.84,0:36:27.61,Default,,0,0,0,,我们称之为 这个X遮蔽了这个X Dialogue: 0,0:36:31.05,0:36:32.49,Default,,0,0,0,,从环境III Dialogue: 0,0:36:33.44,0:36:34.45,Default,,0,0,0,,从框架III Dialogue: 0,0:36:34.45,0:36:35.73,Default,,0,0,0,,从环境B Dialogue: 0,0:36:35.73,0:36:37.18,Default,,0,0,0,,它引用了框架III Dialogue: 0,0:36:37.45,0:36:42.12,Default,,0,0,0,,变量M和Y被约束 X也被约束 Dialogue: 0,0:36:44.84,0:36:46.97,Default,,0,0,0,,这个Y遮蔽了这个Y Dialogue: 0,0:36:48.65,0:36:51.00,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:36:51.10,0:36:52.65,Default,,0,0,0,,Y的值是2 Dialogue: 0,0:36:53.45,0:36:55.28,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:36:55.28,0:36:58.64,Default,,0,0,0,,M的值是1 X的值是3 Dialogue: 0,0:37:02.22,0:37:03.15,Default,,0,0,0,,所以 我们有了一个 Dialogue: 0,0:37:03.15,0:37:05.52,Default,,0,0,0,,由框架构成的非常简单的环境结构 Dialogue: 0,0:37:06.38,0:37:09.80,Default,,0,0,0,,它们与过程的应用相一致 Dialogue: 0,0:37:10.94,0:37:12.17,Default,,0,0,0,,我们马上就会看到 Dialogue: 0,0:37:14.41,0:37:17.60,Default,,0,0,0,,现在要给你们看看我们构建的一些其他的很好的小结构 Dialogue: 0,0:37:20.75,0:37:21.71,Default,,0,0,0,,下一张幻灯片 Dialogue: 0,0:37:22.14,0:37:24.36,Default,,0,0,0,,我们可以看到一个对象 Dialogue: 0,0:37:24.84,0:37:26.54,Default,,0,0,0,,我描绘的是一个过程的图像 Dialogue: 0,0:37:27.93,0:37:28.94,Default,,0,0,0,,这是一个过程 Dialogue: 0,0:37:30.11,0:37:31.90,Default,,0,0,0,,过程由两个部分组成 Dialogue: 0,0:37:33.10,0:37:34.80,Default,,0,0,0,,这有点像CONS Dialogue: 0,0:37:37.21,0:37:38.38,Default,,0,0,0,,不管怎样 它有两个部分 Dialogue: 0,0:37:40.84,0:37:44.72,Default,,0,0,0,,第一个部分指向一些代码 Dialogue: 0,0:37:45.69,0:37:46.94,Default,,0,0,0,,这些代码将会被执行 Dialogue: 0,0:37:47.42,0:37:50.00,Default,,0,0,0,,你可以把它视作一组指令 Dialogue: 0,0:37:50.68,0:37:52.83,Default,,0,0,0,,第二部分是环境 Dialogue: 0,0:37:53.88,0:37:55.50,Default,,0,0,0,,这就是过程的全部了 Dialogue: 0,0:37:57.16,0:37:58.40,Default,,0,0,0,,我们要用它 Dialogue: 0,0:37:58.71,0:38:05.16,Default,,0,0,0,,来捕获出现在过程中的自由变量的值 Dialogue: 0,0:38:06.17,0:38:08.09,Default,,0,0,0,,如果变量出现在过程中 Dialogue: 0,0:38:08.11,0:38:09.92,Default,,0,0,0,,它不是被约束的就是自由的 Dialogue: 0,0:38:11.10,0:38:11.96,Default,,0,0,0,,如果它是被约束的 Dialogue: 0,0:38:12.57,0:38:14.56,Default,,0,0,0,,则它的值将很容易被找到 Dialogue: 0,0:38:16.11,0:38:18.64,Default,,0,0,0,,它将存在于某个很容易找到的环境中 Dialogue: 0,0:38:18.91,0:38:19.87,Default,,0,0,0,,如果它是自由的 Dialogue: 0,0:38:20.86,0:38:23.02,Default,,0,0,0,,我们就必须在过程中放入一些东西 Dialogue: 0,0:38:23.02,0:38:24.81,Default,,0,0,0,,用来指导我们查询自由变量的值 Dialogue: 0,0:38:27.05,0:38:29.21,Default,,0,0,0,,相关理由目前还不清楚 Dialogue: 0,0:38:29.21,0:38:30.60,Default,,0,0,0,,但很快就要真相大白了 Dialogue: 0,0:38:32.32,0:38:34.97,Default,,0,0,0,,这里有一个对象 它是个复合对象 Dialogue: 0,0:38:35.34,0:38:41.64,Default,,0,0,0,,由一些代码和一个环境结构组成 Dialogue: 0,0:38:42.72,0:38:45.50,Default,,0,0,0,,现在我要告诉你们一些全新的规则 Dialogue: 0,0:38:46.41,0:38:47.47,Default,,0,0,0,,关于执行的规则 Dialogue: 0,0:38:50.54,0:38:52.20,Default,,0,0,0,,仅有的两条规则的第一条是-- Dialogue: 0,0:38:53.20,0:38:55.39,Default,,0,0,0,,这些规则与代换模型规则相对应 Dialogue: 0,0:38:57.26,0:38:59.32,Default,,0,0,0,,第一条规则是用来解决 Dialogue: 0,0:38:59.66,0:39:02.78,Default,,0,0,0,,如何把一个过程 应用到参数上的问题 Dialogue: 0,0:39:05.28,0:39:08.54,Default,,0,0,0,,程序对象被应用于一组参数 Dialogue: 0,0:39:08.96,0:39:10.43,Default,,0,0,0,,是通过构建一个新的框架来完成 Dialogue: 0,0:39:11.31,0:39:15.76,Default,,0,0,0,,那个框架将包含形式参数 Dialogue: 0,0:39:15.83,0:39:19.48,Default,,0,0,0,,到调用中使用的实际参数的映射 Dialogue: 0,0:39:21.42,0:39:22.20,Default,,0,0,0,,如你所知 Dialogue: 0,0:39:22.31,0:39:26.94,Default,,0,0,0,,当我们调用一个过程 如(LAMBDA (X) (* X Y)) Dialogue: 0,0:39:26.94,0:39:29.13,Default,,0,0,0,,然后我们以3为参数调用它 Dialogue: 0,0:39:30.19,0:39:32.75,Default,,0,0,0,,那么我们需要某个从X到3的映射 Dialogue: 0,0:39:34.19,0:39:37.39,Default,,0,0,0,,你可以把它想做是代换的一种 Dialogue: 0,0:39:38.27,0:39:40.30,Default,,0,0,0,,在旧的模型中 用3代换X Dialogue: 0,0:39:42.00,0:39:44.80,Default,,0,0,0,,所以我要建立一个框架 Dialogue: 0,0:39:45.15,0:39:46.60,Default,,0,0,0,,在框架中包含X等于3的这个信息 Dialogue: 0,0:39:49.12,0:39:49.71,Default,,0,0,0,,现在 Dialogue: 0,0:39:50.33,0:39:53.31,Default,,0,0,0,,过程的体即将被执行 Dialogue: 0,0:39:54.16,0:39:56.44,Default,,0,0,0,,它将在一个环境中执行 Dialogue: 0,0:39:57.80,0:40:08.03,Default,,0,0,0,,这个环境是由我们创建的新框架邻接组合而成 Dialogue: 0,0:40:08.54,0:40:11.69,Default,,0,0,0,,它是我们所应用的过程的一部分 Dialogue: 0,0:40:13.15,0:40:15.77,Default,,0,0,0,,所以 举个例子 Dialogue: 0,0:40:19.20,0:40:24.12,Default,,0,0,0,,假设我有一些环境 Dialogue: 0,0:40:25.15,0:40:27.23,Default,,0,0,0,,画个方框代表它 Dialogue: 0,0:40:27.96,0:40:32.19,Default,,0,0,0,,以及一些过程--我画圆来代表它们 因为这比小三角形好画-- Dialogue: 0,0:40:33.04,0:40:36.36,Default,,0,0,0,,抱歉 是菱形 Dialogue: 0,0:40:37.66,0:40:40.78,Default,,0,0,0,,小块菱形的果冻之类的东西 Dialogue: 0,0:40:42.68,0:40:45.32,Default,,0,0,0,,这有一个使用这个环境的过程 Dialogue: 0,0:40:45.95,0:40:48.16,Default,,0,0,0,,这个过程有一些代码 Dialogue: 0,0:40:48.16,0:40:49.68,Default,,0,0,0,,是一个LAMBDA表达式 Dialogue: 0,0:40:50.12,0:40:51.69,Default,,0,0,0,,约束了X和Y Dialogue: 0,0:40:53.15,0:40:56.43,Default,,0,0,0,,然后执行了表达式E Dialogue: 0,0:40:57.93,0:40:58.99,Default,,0,0,0,,这个过程就是这样的 Dialogue: 0,0:40:59.56,0:41:00.57,Default,,0,0,0,,我们叫它P Dialogue: 0,0:41:01.44,0:41:05.79,Default,,0,0,0,,我希望将这个过程应用于3和4 Dialogue: 0,0:41:06.38,0:41:08.36,Default,,0,0,0,,所以我在这写(P 3 4) Dialogue: 0,0:41:09.76,0:41:12.17,Default,,0,0,0,,我要做的事情则是 创建一个新的框架 Dialogue: 0,0:41:13.15,0:41:14.12,Default,,0,0,0,,创建一个框架 Dialogue: 0,0:41:15.24,0:41:18.28,Default,,0,0,0,,框架中X等于3 Dialogue: 0,0:41:18.84,0:41:20.51,Default,,0,0,0,,而Y等于4 Dialogue: 0,0:41:21.69,0:41:23.48,Default,,0,0,0,,我要把这个框架 Dialogue: 0,0:41:24.27,0:41:25.37,Default,,0,0,0,,连接到这一个框架上 Dialogue: 0,0:41:27.63,0:41:28.99,Default,,0,0,0,,对于这个环境 Dialogue: 0,0:41:29.68,0:41:30.97,Default,,0,0,0,,我把它叫做B Dialogue: 0,0:41:31.55,0:41:35.02,Default,,0,0,0,,我会在这个环境中求值E的体 Dialogue: 0,0:41:39.88,0:41:40.33,Default,,0,0,0,,现在 Dialogue: 0,0:41:41.95,0:41:45.04,Default,,0,0,0,,E可能包含了X和Y的引用以及一些别的东西 Dialogue: 0,0:41:46.84,0:41:49.95,Default,,0,0,0,,X和Y的值在这里 Dialogue: 0,0:41:50.70,0:41:52.52,Default,,0,0,0,,其他的变量的值在这里 Dialogue: 0,0:41:55.05,0:41:56.25,Default,,0,0,0,,怎样才能获取这个框架呢? Dialogue: 0,0:41:57.26,0:41:59.26,Default,,0,0,0,,我们通过过程构建来完成 Dialogue: 0,0:41:59.61,0:42:00.60,Default,,0,0,0,,这就是另一条规则了 Dialogue: 0,0:42:02.03,0:42:04.40,Default,,0,0,0,,请看下一张幻灯片 Dialogue: 0,0:42:05.34,0:42:06.12,Default,,0,0,0,,规则二 Dialogue: 0,0:42:07.80,0:42:09.90,Default,,0,0,0,,当一个LAMBDA表达式被求值时 Dialogue: 0,0:42:09.90,0:42:11.76,Default,,0,0,0,,相对于某个特定的环境-- Dialogue: 0,0:42:14.19,0:42:14.40,Default,,0,0,0,,例如 Dialogue: 0,0:42:15.04,0:42:18.12,Default,,0,0,0,,获取一个过程的方式就是求值一个LAMBDA表达式 Dialogue: 0,0:42:18.19,0:42:19.36,Default,,0,0,0,,这里有一个LAMBDA表达式 Dialogue: 0,0:42:20.04,0:42:21.12,Default,,0,0,0,,通过对它求值 Dialogue: 0,0:42:21.90,0:42:23.96,Default,,0,0,0,,我获得了一个可以应用于3的过程 Dialogue: 0,0:42:25.08,0:42:26.65,Default,,0,0,0,,现在这个LAMBDA表达式 Dialogue: 0,0:42:26.65,0:42:30.38,Default,,0,0,0,,在一个Y已被定义的环境中执行 Dialogue: 0,0:42:31.84,0:42:35.84,Default,,0,0,0,,我希望这个过程的体中包括的Y是自由的 Dialogue: 0,0:42:36.39,0:42:38.36,Default,,0,0,0,,在这里面 Y是自由的 Dialogue: 0,0:42:38.72,0:42:40.38,Default,,0,0,0,,但是在整个的表达式中却是被约束的 Dialogue: 0,0:42:41.36,0:42:42.75,Default,,0,0,0,,而在这里是自由的 Dialogue: 0,0:42:43.32,0:42:46.24,Default,,0,0,0,,我想让这两个Y指称同一个Y Dialogue: 0,0:42:47.44,0:42:55.13,Default,,0,0,0,,我在Y被创建的环境中求值这个过程的体 Dialogue: 0,0:42:55.32,0:42:58.40,Default,,0,0,0,,就像这个一样 因为那是通过应用完成的 Dialogue: 0,0:42:59.00,0:42:59.63,Default,,0,0,0,,现在 Dialogue: 0,0:43:00.24,0:43:02.60,Default,,0,0,0,,如果我还想查找Y的值 Dialogue: 0,0:43:03.10,0:43:04.09,Default,,0,0,0,,我就必须知道它在哪 Dialogue: 0,0:43:04.54,0:43:06.42,Default,,0,0,0,,因此 这个过程在被创建时 Dialogue: 0,0:43:06.42,0:43:10.06,Default,,0,0,0,,过程的创建 也就是对LAMBDA表达式求值的结果 Dialogue: 0,0:43:10.06,0:43:16.33,Default,,0,0,0,,最好是获取一个指针或记住Y被约束在哪个框架中 Dialogue: 0,0:43:17.92,0:43:19.76,Default,,0,0,0,,这就是这个规则的内容 Dialogue: 0,0:43:22.11,0:43:23.13,Default,,0,0,0,,那么 举个例子 Dialogue: 0,0:43:24.44,0:43:29.32,Default,,0,0,0,,如果我恰好求值了一个LAMBDA表达式 Dialogue: 0,0:43:30.89,0:43:33.32,Default,,0,0,0,,在E中的LAMBDA表达式 Dialogue: 0,0:43:34.04,0:43:40.46,Default,,0,0,0,,在E中求值(LAMBDA (X Y) G) Dialogue: 0,0:43:41.08,0:43:42.36,Default,,0,0,0,,对其求值 Dialogue: 0,0:43:42.97,0:43:46.17,Default,,0,0,0,,这些事的意义就是我现在构建了一个过程对象 Dialogue: 0,0:43:47.10,0:43:48.28,Default,,0,0,0,,E是某个环境 Dialogue: 0,0:43:48.84,0:43:50.94,Default,,0,0,0,,有个指针指向E Dialogue: 0,0:43:51.79,0:43:56.68,Default,,0,0,0,,我构建了一个过程对象指向了这个环境 Dialogue: 0,0:43:58.56,0:44:00.11,Default,,0,0,0,,它的代码 Dialogue: 0,0:44:00.54,0:44:03.24,Default,,0,0,0,,是一个LAMBDA表达式 或者是某种中间代码 Dialogue: 0,0:44:06.24,0:44:07.56,Default,,0,0,0,,而这就是一个过程 Dialogue: 0,0:44:12.38,0:44:14.70,Default,,0,0,0,,它为我生成了这个和这个 Dialogue: 0,0:44:14.94,0:44:16.37,Default,,0,0,0,,这个对象 Dialogue: 0,0:44:16.37,0:44:18.12,Default,,0,0,0,,这个环境指针 Dialogue: 0,0:44:18.37,0:44:22.52,Default,,0,0,0,,获取了求值LAMBDA表达式时的环境 Dialogue: 0,0:44:22.62,0:44:24.59,Default,,0,0,0,,定义所使用的环境 Dialogue: 0,0:44:25.58,0:44:27.40,Default,,0,0,0,,创建一个过程时的定义所用的环境 Dialogue: 0,0:44:30.32,0:44:31.47,Default,,0,0,0,,从而创建了过程 Dialogue: 0,0:44:32.89,0:44:36.30,Default,,0,0,0,,所以 它将环境从定义过程的地方取出 Dialogue: 0,0:44:37.42,0:44:38.92,Default,,0,0,0,,将它保存在过程自己内部 Dialogue: 0,0:44:39.60,0:44:40.97,Default,,0,0,0,,之后当过程被调用时 Dialogue: 0,0:44:41.32,0:44:43.47,Default,,0,0,0,,它在被定义时的环境 Dialogue: 0,0:44:43.98,0:44:45.07,Default,,0,0,0,,将由新的框架扩充 Dialogue: 0,0:44:48.72,0:44:52.33,Default,,0,0,0,,这给了我们一个放置有值的变量的地方 Dialogue: 0,0:44:53.04,0:44:53.96,Default,,0,0,0,,举个例子 Dialogue: 0,0:44:53.96,0:44:56.81,Default,,0,0,0,,如果有很多东西指向那这个环境 Dialogue: 0,0:44:57.74,0:45:00.33,Default,,0,0,0,,它们就会共享这个环境 Dialogue: 0,0:45:01.20,0:45:02.52,Default,,0,0,0,,我们很快将会见到 Dialogue: 0,0:45:04.01,0:45:05.34,Default,,0,0,0,,现在你们有了一个新模型 Dialogue: 0,0:45:06.38,0:45:09.92,Default,,0,0,0,,我们用它来理解程序的执行 Dialogue: 0,0:45:11.36,0:45:12.78,Default,,0,0,0,,我觉得现在我应该解答一些问题了 Dialogue: 0,0:45:13.10,0:45:14.96,Default,,0,0,0,,之后我们再继续 Dialogue: 0,0:45:18.19,0:45:19.52,Default,,0,0,0,,学生:这么说是对的吗? Dialogue: 0,0:45:19.52,0:45:23.96,Default,,0,0,0,,环境就是一些被连接在一起的框架 Dialogue: 0,0:45:23.96,0:45:25.10,Default,,0,0,0,,教授:对 Dialogue: 0,0:45:25.48,0:45:26.64,Default,,0,0,0,,学生:通过它能够访问所有的框架? Dialogue: 0,0:45:27.71,0:45:31.45,Default,,0,0,0,,教授:是的 环境是一系列被连接在一起的框架 Dialogue: 0,0:45:32.43,0:45:35.47,Default,,0,0,0,,我对它的理解是 它是指向第一个框架的指针 Dialogue: 0,0:45:36.88,0:45:38.72,Default,,0,0,0,,因为一旦你获得了它 你就能拿到所有的框架 Dialogue: 0,0:45:43.96,0:45:44.65,Default,,0,0,0,,还有谁有问题吗? Dialogue: 0,0:45:45.20,0:45:49.36,Default,,0,0,0,,学生:有可能在两个不同的环境中定义或求值一个过程 Dialogue: 0,0:45:49.36,0:45:53.20,Default,,0,0,0,,使得它有不同的行为 并且有指向两个环境的指针-- Dialogue: 0,0:45:53.20,0:45:55.77,Default,,0,0,0,,教授:噢 是的 同一个过程不会有两个不同环境 Dialogue: 0,0:45:56.90,0:45:59.02,Default,,0,0,0,,同样的代码 Dialogue: 0,0:45:59.02,0:46:00.82,Default,,0,0,0,,比如同样的LAMBDA表达式 Dialogue: 0,0:46:00.82,0:46:03.72,Default,,0,0,0,,再不同的环境下求值可能产生不同的过程 Dialogue: 0,0:46:06.03,0:46:07.18,Default,,0,0,0,,每个过程-- Dialogue: 0,0:46:07.18,0:46:09.95,Default,,0,0,0,,学生:它们的定义有同样的名字 它们的运算-- Dialogue: 0,0:46:09.95,0:46:11.92,Default,,0,0,0,,教授:它们定义是写起来是一样的 使用同样的字母 Dialogue: 0,0:46:12.56,0:46:14.62,Default,,0,0,0,,我能求值那一组字母 Dialogue: 0,0:46:14.93,0:46:18.14,Default,,0,0,0,,或定义的表结构之类的东西 Dialogue: 0,0:46:18.22,0:46:20.41,Default,,0,0,0,,那只是文本表示 Dialogue: 0,0:46:20.91,0:46:24.86,Default,,0,0,0,,我可以在两个不同环境种对它求值 产生两个不同的过程 Dialogue: 0,0:46:25.55,0:46:26.84,Default,,0,0,0,,每一个过程 Dialogue: 0,0:46:27.56,0:46:32.19,Default,,0,0,0,,有它们自己的一组局部变量 Dialogue: 0,0:46:32.34,0:46:33.45,Default,,0,0,0,,我们很快就会看到 Dialogue: 0,0:46:36.70,0:46:37.36,Default,,0,0,0,,还有问题吗? Dialogue: 0,0:46:42.60,0:46:44.03,Default,,0,0,0,,好 谢谢大家 我们休息一会 Dialogue: 0,0:46:47.98,0:46:57.61,Default,,0,0,0,,[音乐] Dialogue: 0,0:46:57.61,0:47:02.03,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:47:05.98,0:47:09.69,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:47:09.69,0:47:13.44,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:47:13.47,0:47:18.84,Declare,,0,0,0,,{\an2\fad(500,500)}赋值、状态和副作用 Dialogue: 0,0:47:22.67,0:47:25.69,Default,,0,0,0,,现在 我已经对你们做了一件非常糟糕的事儿 Dialogue: 0,0:47:26.56,0:47:30.54,Default,,0,0,0,,我引入了一个非常复杂的东西 Dialogue: 0,0:47:32.76,0:47:33.42,Default,,0,0,0,,赋值 Dialogue: 0,0:47:34.51,0:47:38.08,Default,,0,0,0,,它摧毁了我们程序中大部分的 有趣的数学特性 Dialogue: 0,0:47:41.07,0:47:42.46,Default,,0,0,0,,我为什么要做这件事呢 Dialogue: 0,0:47:43.18,0:47:45.02,Default,,0,0,0,,这样做可能有什么好处吗? Dialogue: 0,0:47:46.51,0:47:48.86,Default,,0,0,0,,很明显 这不是一个什么好东西 Dialogue: 0,0:47:49.60,0:47:51.23,Default,,0,0,0,,因此我最好有一个好的理由 Dialogue: 0,0:47:52.83,0:47:54.80,Default,,0,0,0,,让我们来小小地玩一下 Dialogue: 0,0:47:54.80,0:47:58.35,Default,,0,0,0,,首先 我们写些非常有趣的带赋值的程序 Dialogue: 0,0:47:58.81,0:48:00.88,Default,,0,0,0,,来理解它们的特殊之处 Dialogue: 0,0:48:01.42,0:48:02.83,Default,,0,0,0,,这些特殊之处使赋值变得有价值 Dialogue: 0,0:48:04.96,0:48:06.70,Default,,0,0,0,,我们从一个非常简单的程序开始 Dialogue: 0,0:48:07.69,0:48:09.28,Default,,0,0,0,,我把这个程序叫做MAKE-COUNTER Dialogue: 0,0:48:10.48,0:48:18.19,Default,,0,0,0,,我要把它定义为 Dialogue: 0,0:48:24.17,0:48:28.12,Default,,0,0,0,,接受一个参数N的过程 Dialogue: 0,0:48:29.23,0:48:32.94,Default,,0,0,0,,并且它的返回值是一个没有参数的过程-- Dialogue: 0,0:48:34.36,0:48:36.03,Default,,0,0,0,,一个生成过程的过程-- Dialogue: 0,0:48:36.84,0:48:44.35,Default,,0,0,0,,这个过程把N的值设为N+1 Dialogue: 0,0:48:47.88,0:48:49.77,Default,,0,0,0,,并且返回N的值 Dialogue: 0,0:48:55.37,0:48:57.54,Default,,0,0,0,,现在 我们要研究它的行为 Dialogue: 0,0:48:57.54,0:48:59.02,Default,,0,0,0,,它很有趣 Dialogue: 0,0:48:59.82,0:49:01.45,Default,,0,0,0,,为了研究它的行为 Dialogue: 0,0:49:01.45,0:49:03.08,Default,,0,0,0,,我需要建立一个环境模型 Dialogue: 0,0:49:04.11,0:49:05.98,Default,,0,0,0,,因为我们不能通过其他的方式来理解它 Dialogue: 0,0:49:08.65,0:49:09.63,Default,,0,0,0,,所以我们开始吧 Dialogue: 0,0:49:10.00,0:49:12.86,Default,,0,0,0,,我们从这里开始 Dialogue: 0,0:49:13.24,0:49:15.90,Default,,0,0,0,,假设机器天生就有一个全局环境 Dialogue: 0,0:49:16.13,0:49:17.12,Default,,0,0,0,,我们把它叫做Global Dialogue: 0,0:49:20.03,0:49:24.25,Default,,0,0,0,,它内部有一堆初始化的东西 Dialogue: 0,0:49:24.44,0:49:25.60,Default,,0,0,0,,我们都知道它里面有什么 Dialogue: 0,0:49:25.72,0:49:30.88,Default,,0,0,0,,这里面有+和* Dialogue: 0,0:49:32.24,0:49:37.26,Default,,0,0,0,,/ -和CAR Dialogue: 0,0:49:38.70,0:49:39.74,Default,,0,0,0,,以此类推 Dialogue: 0,0:49:41.45,0:49:42.48,Default,,0,0,0,,有很多东西 Dialogue: 0,0:49:42.88,0:49:43.98,Default,,0,0,0,,我不知道它们是什么 Dialogue: 0,0:49:44.42,0:49:45.55,Default,,0,0,0,,一些乱七八糟的符号 Dialogue: 0,0:49:46.08,0:49:48.88,Default,,0,0,0,,机器一开始就有这些特性 Dialogue: 0,0:49:51.21,0:49:53.23,Default,,0,0,0,,通过在这做定义 Dialogue: 0,0:49:54.68,0:49:55.76,Default,,0,0,0,,我要做的是-- Dialogue: 0,0:49:56.32,0:49:57.31,Default,,0,0,0,,我在干什么呢? Dialogue: 0,0:49:57.31,0:49:59.58,Default,,0,0,0,,我要把它关联到全局环境上 Dialogue: 0,0:49:59.72,0:50:01.29,Default,,0,0,0,,这是我的环境指针 Dialogue: 0,0:50:03.72,0:50:06.70,Default,,0,0,0,,为了达到那个目的 我要求值这个LAMBDA表达式 Dialogue: 0,0:50:08.35,0:50:10.01,Default,,0,0,0,,这意味着我创建了一个过程对象 Dialogue: 0,0:50:11.50,0:50:13.26,Default,,0,0,0,,所以 我要在这创建一个过程对象 Dialogue: 0,0:50:17.36,0:50:18.68,Default,,0,0,0,,这个过程对象 Dialogue: 0,0:50:18.72,0:50:20.49,Default,,0,0,0,,由于在它被定义的地方 Dialogue: 0,0:50:21.16,0:50:22.35,Default,,0,0,0,,有一个全局的环境 Dialogue: 0,0:50:24.06,0:50:25.79,Default,,0,0,0,,这个过程对象包括了 Dialogue: 0,0:50:28.16,0:50:31.47,Default,,0,0,0,,以N为参数的过程的代码 Dialogue: 0,0:50:31.96,0:50:35.34,Default,,0,0,0,,它返回一个不接受参数的过程 Dialogue: 0,0:50:38.24,0:50:43.28,Default,,0,0,0,,DEFINE是一种改变环境的方法 Dialogue: 0,0:50:44.32,0:50:46.73,Default,,0,0,0,,所以我把MAKE-COUNTER加入全局环境中 Dialogue: 0,0:50:52.28,0:50:55.05,Default,,0,0,0,,这是对于特殊的东西定义的一个特殊的规则 Dialogue: 0,0:50:55.82,0:50:56.94,Default,,0,0,0,,但它其实是 Dialogue: 0,0:50:58.94,0:51:01.96,Default,,0,0,0,,它给了我们一个指针 指向那个过程 Dialogue: 0,0:51:03.82,0:51:06.32,Default,,0,0,0,,所以现在全局环境中也有了MAKE-COUNTER Dialogue: 0,0:51:09.28,0:51:11.21,Default,,0,0,0,,现在 我们要进行一些操作 Dialogue: 0,0:51:11.87,0:51:13.50,Default,,0,0,0,,我要用它来创建一些计数器 Dialogue: 0,0:51:14.99,0:51:16.20,Default,,0,0,0,,我们来看看计数器是什么 Dialogue: 0,0:51:17.12,0:51:18.51,Default,,0,0,0,,所以我们定义 Dialogue: 0,0:51:23.32,0:51:26.65,Default,,0,0,0,,C1为一个从0开始的计数器 Dialogue: 0,0:51:35.72,0:51:38.38,Default,,0,0,0,,根据模型 我们知道如何做这个了 Dialogue: 0,0:51:39.63,0:51:44.33,Default,,0,0,0,,我需要在全局环境中求值这个表达式 Dialogue: 0,0:51:45.40,0:51:46.27,Default,,0,0,0,,(MAKE-COUNTER 0) Dialogue: 0,0:51:47.80,0:51:51.10,Default,,0,0,0,,我查找MAKE-COUNTER 发现它是一个过程 Dialogue: 0,0:51:53.61,0:51:55.29,Default,,0,0,0,,我将要应用这个过程 Dialogue: 0,0:51:56.22,0:51:57.74,Default,,0,0,0,,应用这个过程的方式 Dialogue: 0,0:51:58.43,0:51:59.96,Default,,0,0,0,,就是构建一个框架 Dialogue: 0,0:52:01.80,0:52:03.79,Default,,0,0,0,,所以我构建了一个框架 Dialogue: 0,0:52:06.59,0:52:10.44,Default,,0,0,0,,它内部有一个N的值 Dialogue: 0,0:52:11.77,0:52:12.64,Default,,0,0,0,,这个值是0 Dialogue: 0,0:52:14.00,0:52:15.34,Default,,0,0,0,,它的父环境 Dialogue: 0,0:52:15.87,0:52:19.32,Default,,0,0,0,,就是定义MAKE-COUNTER时的环境 Dialogue: 0,0:52:23.93,0:52:28.36,Default,,0,0,0,,所以我已经通过将MAKE-COUNTER应用于0上 而创建了一个环境 Dialogue: 0,0:52:31.45,0:52:34.40,Default,,0,0,0,,现在 我需要求值MAKE-COUNTER的体 Dialogue: 0,0:52:34.41,0:52:37.72,Default,,0,0,0,,就是那个环境中的LAMBDA表达式 Dialogue: 0,0:52:40.64,0:52:42.30,Default,,0,0,0,,求值这个体 Dialogue: 0,0:52:42.76,0:52:44.59,Default,,0,0,0,,它是一个LAMBDA表达式 Dialogue: 0,0:52:46.28,0:52:48.86,Default,,0,0,0,,对LAMBDA表达式求值 意味着创建一个过程对象 Dialogue: 0,0:52:49.56,0:52:51.00,Default,,0,0,0,,所以我将创建一个过程对象 Dialogue: 0,0:52:56.76,0:52:58.29,Default,,0,0,0,,这个过程对象 Dialogue: 0,0:52:58.29,0:53:00.46,Default,,0,0,0,,拥有一个环境 Dialogue: 0,0:53:04.20,0:53:05.88,Default,,0,0,0,,在这个环境中N被定义为0 Dialogue: 0,0:53:07.68,0:53:08.80,Default,,0,0,0,,它有一些代码 Dialogue: 0,0:53:08.83,0:53:11.37,Default,,0,0,0,,这个过程不需要参数 Dialogue: 0,0:53:11.40,0:53:15.28,Default,,0,0,0,,该过程进行一些处理 然后进行赋值 Dialogue: 0,0:53:15.28,0:53:16.73,Default,,0,0,0,,并返回N Dialogue: 0,0:53:17.88,0:53:18.81,Default,,0,0,0,,这个东西 Dialogue: 0,0:53:19.42,0:53:21.23,Default,,0,0,0,,将成为一个对象 Dialogue: 0,0:53:21.92,0:53:24.67,Default,,0,0,0,,在全局环境中 它的名字是C1 Dialogue: 0,0:53:26.12,0:53:28.33,Default,,0,0,0,,所以我们在这建立一个名字 C1 Dialogue: 0,0:53:28.64,0:53:32.14,Default,,0,0,0,,并且说C1等于这个过程 Dialogue: 0,0:53:35.48,0:53:37.36,Default,,0,0,0,,现在 再来创建另一个计数器 Dialogue: 0,0:53:43.04,0:53:45.13,Default,,0,0,0,,通过MAKE-COUNTER创建c2 Dialogue: 0,0:53:50.94,0:53:52.19,Default,,0,0,0,,让它从10开始 Dialogue: 0,0:53:54.25,0:53:55.90,Default,,0,0,0,,然后我执行同样的步骤 Dialogue: 0,0:53:56.64,0:54:00.40,Default,,0,0,0,,我应用这个MAKE-COUNTER过程 Dialogue: 0,0:54:00.99,0:54:04.52,Default,,0,0,0,,建立另一个框架 其中N等于10 Dialogue: 0,0:54:05.63,0:54:09.18,Default,,0,0,0,,全局环境作为它的父环境 Dialogue: 0,0:54:10.04,0:54:11.80,Default,,0,0,0,,然后我构建一个过程 Dialogue: 0,0:54:13.04,0:54:17.63,Default,,0,0,0,,以这个框架作为它定义的环境 Dialogue: 0,0:54:18.27,0:54:21.66,Default,,0,0,0,,它的代码是 Dialogue: 0,0:54:21.80,0:54:24.38,Default,,0,0,0,,完成一些操作的无参过程 Dialogue: 0,0:54:25.54,0:54:28.60,Default,,0,0,0,,然后进行赋值 等等 Dialogue: 0,0:54:28.60,0:54:31.22,Default,,0,0,0,,然后返回N Dialogue: 0,0:54:31.45,0:54:34.83,Default,,0,0,0,,这就是C2 Dialogue: 0,0:54:36.88,0:54:39.32,Default,,0,0,0,,好 你们应该发现 某些东西开始变得有趣了 Dialogue: 0,0:54:40.17,0:54:41.92,Default,,0,0,0,,这里有两个N Dialogue: 0,0:54:42.92,0:54:44.19,Default,,0,0,0,,它们不是同一个N Dialogue: 0,0:54:46.14,0:54:48.16,Default,,0,0,0,,我每次调用MAKE-COUNTER的时候 Dialogue: 0,0:54:48.64,0:54:50.25,Default,,0,0,0,,我就创建了另一个N的实例 Dialogue: 0,0:54:52.62,0:54:54.40,Default,,0,0,0,,它们彼此独立 没有关联 Dialogue: 0,0:54:57.79,0:55:00.28,Default,,0,0,0,,现在 我们来使用一下这些计数器 Dialogue: 0,0:55:05.92,0:55:15.00,Default,,0,0,0,,如果此时 我调用C1 会发生什么? Dialogue: 0,0:55:15.84,0:55:17.34,Default,,0,0,0,,我会在这里查找 Dialogue: 0,0:55:17.56,0:55:19.98,Default,,0,0,0,,发现C1是一个过程 Dialogue: 0,0:55:20.64,0:55:22.78,Default,,0,0,0,,我要不带参数地调用这个过程 Dialogue: 0,0:55:23.16,0:55:24.96,Default,,0,0,0,,因为它不需要参数 Dialogue: 0,0:55:24.96,0:55:25.63,Default,,0,0,0,,对吧? Dialogue: 0,0:55:26.97,0:55:27.84,Default,,0,0,0,,它的体是什么呢? Dialogue: 0,0:55:27.96,0:55:30.02,Default,,0,0,0,,我得来这里解释 因为我没有给誊过来 Dialogue: 0,0:55:30.02,0:55:32.65,Default,,0,0,0,,这个过程体是将N赋值为N+1 Dialogue: 0,0:55:33.80,0:55:34.89,Default,,0,0,0,,并且返回N Dialogue: 0,0:55:37.12,0:55:38.12,Default,,0,0,0,,就是把N增大1 Dialogue: 0,0:55:38.97,0:55:41.60,Default,,0,0,0,,它的N指的是这个 Dialogue: 0,0:55:43.08,0:55:44.60,Default,,0,0,0,,所以我把这个n增大1 Dialogue: 0,0:55:45.80,0:55:47.00,Default,,0,0,0,,它变成了1 Dialogue: 0,0:55:48.64,0:55:50.24,Default,,0,0,0,,然后返回了1 Dialogue: 0,0:55:53.13,0:55:56.49,Default,,0,0,0,,之后我调用C2 Dialogue: 0,0:55:58.38,0:55:59.20,Default,,0,0,0,,我会做什么? Dialogue: 0,0:55:59.23,0:56:03.33,Default,,0,0,0,,C2是相同的过程 Dialogue: 0,0:56:03.33,0:56:04.48,Default,,0,0,0,,但这个N Dialogue: 0,0:56:05.33,0:56:06.57,Default,,0,0,0,,它变成了11 Dialogue: 0,0:56:10.97,0:56:14.59,Default,,0,0,0,,所以返回值是11 Dialogue: 0,0:56:15.92,0:56:18.32,Default,,0,0,0,,然后我们再来调用一下C1 Dialogue: 0,0:56:20.91,0:56:22.56,Default,,0,0,0,,C1是这个 Dialogue: 0,0:56:23.28,0:56:24.16,Default,,0,0,0,,它是2 Dialogue: 0,0:56:27.24,0:56:28.30,Default,,0,0,0,,所以结果是2 Dialogue: 0,0:56:29.66,0:56:30.75,Default,,0,0,0,,然后调用C2 Dialogue: 0,0:56:33.37,0:56:35.31,Default,,0,0,0,,然后C2通过同样的方法 返回了12 Dialogue: 0,0:56:35.74,0:56:37.55,Default,,0,0,0,,它在这里进行查找 Dialogue: 0,0:56:37.55,0:56:39.28,Default,,0,0,0,,发现了N 并把它加1 Dialogue: 0,0:56:41.64,0:56:43.68,Default,,0,0,0,,我拥有的是可计算的对象 Dialogue: 0,0:56:45.21,0:56:46.86,Default,,0,0,0,,它们是两个计数器 Dialogue: 0,0:56:48.96,0:56:51.02,Default,,0,0,0,,每一个都有各自独立的局部状态 Dialogue: 0,0:56:55.48,0:56:56.62,Default,,0,0,0,,我们再进一步 Dialogue: 0,0:56:56.64,0:56:58.52,Default,,0,0,0,,这是个奇怪的东西 Dialogue: 0,0:57:01.12,0:57:02.22,Default,,0,0,0,,什么是对象? Dialogue: 0,0:57:04.11,0:57:06.12,Default,,0,0,0,,这个概念并不明确 Dialogue: 0,0:57:07.55,0:57:09.45,Default,,0,0,0,,我们倾向于以对象的角度思考 Dialogue: 0,0:57:11.24,0:57:13.32,Default,,0,0,0,,因为这样思考比较经济 Dialogue: 0,0:57:14.62,0:57:17.28,Default,,0,0,0,,这是一种智力上的经济 Dialogue: 0,0:57:18.57,0:57:19.61,Default,,0,0,0,,我是一个对象 Dialogue: 0,0:57:20.99,0:57:22.30,Default,,0,0,0,,你也是一个对象 Dialogue: 0,0:57:23.55,0:57:25.29,Default,,0,0,0,,但我们不是同一个对象 Dialogue: 0,0:57:27.52,0:57:29.64,Default,,0,0,0,,我可以把世界分为两部分 Dialogue: 0,0:57:29.92,0:57:31.85,Default,,0,0,0,,我和你 Dialogue: 0,0:57:31.92,0:57:33.31,Default,,0,0,0,,以及其它的东西 Dialogue: 0,0:57:34.70,0:57:35.26,Default,,0,0,0,,使得 Dialogue: 0,0:57:35.44,0:57:39.50,Default,,0,0,0,,大多数对于我的讨论 Dialogue: 0,0:57:39.68,0:57:40.89,Default,,0,0,0,,不会影响到你 Dialogue: 0,0:57:41.39,0:57:44.67,Default,,0,0,0,,大多数对于你的讨论不会牵涉到我 Dialogue: 0,0:57:45.66,0:57:46.94,Default,,0,0,0,,我有血压 Dialogue: 0,0:57:47.50,0:57:48.38,Default,,0,0,0,,体温 Dialogue: 0,0:57:49.36,0:57:51.48,Default,,0,0,0,,呼吸频率 Dialogue: 0,0:57:53.34,0:57:54.99,Default,,0,0,0,,血液中有确定的血糖值 Dialogue: 0,0:57:56.11,0:57:59.34,Default,,0,0,0,,数不清的 数以千计的状态变量--上百万实际上 Dialogue: 0,0:57:59.37,0:58:00.65,Default,,0,0,0,,我不知道具体有多少 Dialogue: 0,0:58:00.93,0:58:03.48,Default,,0,0,0,,以物理学观点 我拥有大量的状态变量 Dialogue: 0,0:58:04.91,0:58:07.12,Default,,0,0,0,,如果将我视为一个粒子的话 Dialogue: 0,0:58:09.15,0:58:10.64,Default,,0,0,0,,你也有许许多多这样的变量 Dialogue: 0,0:58:12.68,0:58:14.94,Default,,0,0,0,,我们的大多数变量之间是好无联系的 Dialogue: 0,0:58:17.31,0:58:19.50,Default,,0,0,0,,所以可以计算我的属性 Dialogue: 0,0:58:20.56,0:58:22.83,Default,,0,0,0,,而不用太担心你的属性 Dialogue: 0,0:58:23.82,0:58:25.77,Default,,0,0,0,,如果把我们两个放在一起计算 Dialogue: 0,0:58:25.96,0:58:27.82,Default,,0,0,0,,那么我们需要考虑的状态的数量 Dialogue: 0,0:58:27.82,0:58:30.01,Default,,0,0,0,,就是你与我的状态的数量的乘积 Dialogue: 0,0:58:30.52,0:58:32.11,Default,,0,0,0,,按对象解耦的话 则只需考虑你我状态之和 Dialogue: 0,0:58:32.65,0:58:35.34,Default,,0,0,0,,然而 实际上有一种力量把我们耦合起来 Dialogue: 0,0:58:36.00,0:58:37.95,Default,,0,0,0,,我对你讲话 你的状态就变了 Dialogue: 0,0:58:38.44,0:58:40.09,Default,,0,0,0,,我看着你 我的状态就变了 Dialogue: 0,0:58:41.72,0:58:44.08,Default,,0,0,0,,因此 我的变量中的一小部分 Dialogue: 0,0:58:44.33,0:58:46.07,Default,,0,0,0,,与你的一些变量是耦合的 Dialogue: 0,0:58:46.07,0:58:47.80,Default,,0,0,0,,如果你突然大喊大叫 Dialogue: 0,0:58:47.80,0:58:48.88,Default,,0,0,0,,我的血压就会升高 Dialogue: 0,0:58:54.30,0:58:56.86,Default,,0,0,0,,然而 将世界看作是由独立的变量 Dialogue: 0,0:58:57.17,0:59:01.16,Default,,0,0,0,,和独立的粒子组成的是不恰当的 Dialogue: 0,0:59:02.12,0:59:04.46,Default,,0,0,0,,在像量子力学这样的东西里存在大量的BUG Dialogue: 0,0:59:05.23,0:59:08.70,Default,,0,0,0,,或者当我们思考像量子力学之类的东西的时候 会在我们的脑海中产生bug Dialogue: 0,0:59:08.89,0:59:10.97,Default,,0,0,0,,这是由于 当我们思考事物时 Dialogue: 0,0:59:10.97,0:59:12.96,Default,,0,0,0,,会去将事物分解为相互独立的部分来看待 Dialogue: 0,0:59:13.58,0:59:17.32,Default,,0,0,0,,而事实上事物的耦合程度 远远大于在表面所看到的 Dialogue: 0,0:59:18.01,0:59:19.44,Default,,0,0,0,,即便这样 我们仍像那样思考 Dialogue: 0,0:59:19.61,0:59:21.69,Default,,0,0,0,,是因为我们希望高效并且有效的进行计算 Dialogue: 0,0:59:22.19,0:59:23.82,Default,,0,0,0,,我们被培养成以那种方式进行思考 Dialogue: 0,0:59:29.76,0:59:30.51,Default,,0,0,0,,大家看 Dialogue: 0,0:59:31.50,0:59:33.44,Default,,0,0,0,,我们如何才能知道我们是否有对象? Dialogue: 0,0:59:35.12,0:59:37.34,Default,,0,0,0,,如果我们有对象 应该如何分辨呢? Dialogue: 0,0:59:37.64,0:59:41.45,Default,,0,0,0,,通过思考一些光学现象 Dialogue: 0,0:59:42.46,0:59:43.13,Default,,0,0,0,,就能解答这个问题 Dialogue: 0,0:59:45.04,0:59:47.69,Default,,0,0,0,,这几截粉笔不完全相同 Dialogue: 0,0:59:47.76,0:59:50.20,Default,,0,0,0,,但假设 只通过观察是无法区分它们的 Dialogue: 0,0:59:52.04,0:59:53.32,Default,,0,0,0,,有一种可能 Dialogue: 0,0:59:53.32,0:59:55.16,Default,,0,0,0,,是这一切都是我们与镜子的游戏 Dialogue: 0,0:59:56.07,0:59:57.60,Default,,0,0,0,,它们真的是同一截粉笔 Dialogue: 0,0:59:59.36,1:00:00.48,Default,,0,0,0,,但你看到了两个 Dialogue: 0,1:00:01.61,1:00:03.87,Default,,0,0,0,,你怎么知道你看到的是一个还是两个呢? Dialogue: 0,1:00:05.04,1:00:06.70,Default,,0,0,0,,我只知道有一种方法可以确定 Dialogue: 0,1:00:07.37,1:00:08.94,Default,,0,0,0,,抓起其中一个并且改变它 Dialogue: 0,1:00:09.45,1:00:10.67,Default,,0,0,0,,然后看看另一个有没有跟着变化 Dialogue: 0,1:00:14.01,1:00:14.67,Default,,0,0,0,,而另一个没有变化 Dialogue: 0,1:00:15.50,1:00:16.14,Default,,0,0,0,,所以它们是两截不同粉笔 Dialogue: 0,1:00:19.50,1:00:20.16,Default,,0,0,0,,另一方面 Dialogue: 0,1:00:20.17,1:00:22.20,Default,,0,0,0,,事物还有一些其它的类似的纠结属性 Dialogue: 0,1:00:22.57,1:00:24.01,Default,,0,0,0,,例如 我们怎么才知道某个东西是否改变了呢? Dialogue: 0,1:00:25.00,1:00:27.93,Default,,0,0,0,,我们需要在它改变之前和之后进行观察 Dialogue: 0,1:00:28.65,1:00:30.02,Default,,0,0,0,,改变就是赋值 Dialogue: 0,1:00:30.02,1:00:31.45,Default,,0,0,0,,它是时间中的一个时刻 Dialogue: 0,1:00:32.14,1:00:34.60,Default,,0,0,0,,但是那意味着我们需要知道 我们看到的是否是同一个 Dialogue: 0,1:00:36.51,1:00:38.84,Default,,0,0,0,,所以一些东西非常奇怪 Dialogue: 0,1:00:38.84,1:00:40.38,Default,,0,0,0,,不同寻常并且晦涩难懂 Dialogue: 0,1:00:40.84,1:00:43.52,Default,,0,0,0,,并且我不理解与赋值 Dialogue: 0,1:00:44.45,1:00:46.28,Default,,0,0,0,,变化以及对象有关的问题 Dialogue: 0,1:00:47.29,1:00:48.99,Default,,0,0,0,,这些东西可能变得非常非常糟糕 Dialogue: 0,1:00:51.40,1:00:52.12,Default,,0,0,0,,例如 Dialogue: 0,1:00:53.31,1:00:55.60,Default,,0,0,0,,我 一个特定的人 Dialogue: 0,1:00:56.16,1:00:57.72,Default,,0,0,0,,一个特定的对象 Dialogue: 0,1:00:57.96,1:00:59.31,Default,,0,0,0,,现在 我可以拿出小刀 Dialogue: 0,1:01:00.68,1:01:01.77,Default,,0,0,0,,切下一片我的指甲 Dialogue: 0,1:01:01.89,1:01:04.81,Default,,0,0,0,,一片指甲掉在了桌子上 Dialogue: 0,1:01:05.93,1:01:10.16,Default,,0,0,0,,我相信自己和一秒钟之前的自己 是同一个人 Dialogue: 0,1:01:10.97,1:01:12.81,Default,,0,0,0,,但在物理上并不是分毫不差 Dialogue: 0,1:01:14.46,1:01:15.43,Default,,0,0,0,,我已经改变了 Dialogue: 0,1:01:15.58,1:01:16.65,Default,,0,0,0,,为什么我还是同一个人呢? Dialogue: 0,1:01:18.11,1:01:19.40,Default,,0,0,0,,什么能认定我的身份呢? Dialogue: 0,1:01:20.96,1:01:23.50,Default,,0,0,0,,我不知道 Dialogue: 0,1:01:25.05,1:01:27.88,Default,,0,0,0,,除非我有某种特征 Dialogue: 0,1:01:29.71,1:01:33.04,Default,,0,0,0,,我觉得 由于引入赋值和对象 Dialogue: 0,1:01:33.64,1:01:38.28,Default,,0,0,0,,我们不得不去面对这种 Dialogue: 0,1:01:38.41,1:01:42.24,Default,,0,0,0,,困扰了哲学家们上千年的哲学问题 Dialogue: 0,1:01:43.42,1:01:44.99,Default,,0,0,0,,这也是相比之下 为什么数学清晰得多 Dialogue: 0,1:01:45.69,1:01:50.24,Default,,0,0,0,,我将尽我所能地向大家阐述关于动作和身份的理解 Dialogue: 0,1:01:52.44,1:01:55.39,Default,,0,0,0,,我们说动作A 对于对于某个对象X有影响 Dialogue: 0,1:01:55.77,1:01:56.70,Default,,0,0,0,,换句话说 Dialogue: 0,1:01:56.92,1:01:58.41,Default,,0,0,0,,X被A改变 Dialogue: 0,1:01:58.89,1:02:01.66,Default,,0,0,0,,如果某个属性P 在P作用于X之前为真 Dialogue: 0,1:02:01.87,1:02:03.76,Default,,0,0,0,,在A作用于X之后为假 Dialogue: 0,1:02:04.99,1:02:05.63,Default,,0,0,0,,那是个测试 Dialogue: 0,1:02:06.62,1:02:09.66,Default,,0,0,0,,这也意味着 我必须有变动前和变动后的X Dialogue: 0,1:02:10.91,1:02:12.54,Default,,0,0,0,,或者 换句话说 Dialogue: 0,1:02:12.94,1:02:14.94,Default,,0,0,0,,我们说对任一动作 两个对象X和Y是同一个对象 Dialogue: 0,1:02:14.97,1:02:17.93,Default,,0,0,0,,当且仅当 该动作对X、Y有同样的影响 Dialogue: 0,1:02:19.63,1:02:21.39,Default,,0,0,0,,然而 就像我说的 Dialogue: 0,1:02:21.44,1:02:23.18,Default,,0,0,0,,对象在智力经济上是非常有用的 Dialogue: 0,1:02:24.64,1:02:27.12,Default,,0,0,0,,对于它们来说非常有用的东西之一 Dialogue: 0,1:02:28.27,1:02:29.44,Default,,0,0,0,,就是对于这个世界 Dialogue: 0,1:02:30.78,1:02:34.80,Default,,0,0,0,,我们习惯于把它认为是由带有独立状态的独立对象所构成的 Dialogue: 0,1:02:35.00,1:02:37.28,Default,,0,0,0,,虽然那并不完全正确 但我们喜欢以那样的的方式来思考 Dialogue: 0,1:02:39.68,1:02:42.03,Default,,0,0,0,,当我们要写一个非常复杂的程序 Dialogue: 0,1:02:42.03,1:02:43.26,Default,,0,0,0,,来应对这样一个世界时 Dialogue: 0,1:02:43.98,1:02:46.44,Default,,0,0,0,,如果我们希望这些程序可以被我们理解 Dialogue: 0,1:02:46.91,1:02:48.14,Default,,0,0,0,,并且也是可修改的 Dialogue: 0,1:02:48.73,1:02:51.12,Default,,0,0,0,,那么如果世界改变了 我们只需要稍微改动一下程序 Dialogue: 0,1:02:51.39,1:02:53.70,Default,,0,0,0,,我们希望建立一种联系 一种同构 Dialogue: 0,1:02:53.82,1:02:56.88,Default,,0,0,0,,建立在真实世界的对象与我们脑海中的对象之间 Dialogue: 0,1:02:58.76,1:03:01.44,Default,,0,0,0,,世界的模块化 使我们的程序得以模块化 Dialogue: 0,1:03:02.41,1:03:05.36,Default,,0,0,0,,所以我们发明了面向对象编程 Dialogue: 0,1:03:05.88,1:03:08.36,Default,,0,0,0,,使我们获得那样的力量 Dialogue: 0,1:03:10.06,1:03:10.94,Default,,0,0,0,,但是 它甚至更简单 Dialogue: 0,1:03:10.94,1:03:12.25,Default,,0,0,0,,让我们玩一个小游戏 Dialogue: 0,1:03:12.27,1:03:13.18,Default,,0,0,0,,我想通过这个游戏 Dialogue: 0,1:03:13.39,1:03:15.77,Default,,0,0,0,,给你展示一个更简单的例子 Dialogue: 0,1:03:16.00,1:03:21.74,Default,,0,0,0,,来说明谨慎地使用赋值语句 可以增强模块性 Dialogue: 0,1:03:22.86,1:03:25.35,Default,,0,0,0,,有一件事 我想让你牢牢地铭记 Dialogue: 0,1:03:25.45,1:03:27.44,Default,,0,0,0,,就是不要像在FORTRAN Basic Dialogue: 0,1:03:27.45,1:03:29.79,Default,,0,0,0,,或者Pascal里一样使用赋值语句 Dialogue: 0,1:03:30.00,1:03:31.71,Default,,0,0,0,,你不那样做 也能达到目的 Dialogue: 0,1:03:34.04,1:03:36.62,Default,,0,0,0,,这不是思考大多数事情的正确方式 Dialogue: 0,1:03:36.97,1:03:38.28,Default,,0,0,0,,有些时候它是必要的 Dialogue: 0,1:03:38.68,1:03:39.69,Default,,0,0,0,,或者可能是必要的 Dialogue: 0,1:03:39.69,1:03:40.97,Default,,0,0,0,,我们一会更深入地去研究 Dialogue: 0,1:03:42.24,1:03:44.22,Default,,0,0,0,,我要给你展示一个有趣的游戏 Dialogue: 0,1:03:47.61,1:03:49.42,Default,,0,0,0,,从前有一个数学家 Dialogue: 0,1:03:49.68,1:03:53.69,Default,,0,0,0,,叫做Cesaro Dialogue: 0,1:03:54.48,1:03:57.45,Default,,0,0,0,,他发现了一个计算pi的巧妙方法 Dialogue: 0,1:03:58.38,1:04:04.30,Default,,0,0,0,,这个方法是说 如果我有两个随机数 Dialogue: 0,1:04:05.24,1:04:06.94,Default,,0,0,0,,两个随机的整数 Dialogue: 0,1:04:07.74,1:04:09.48,Default,,0,0,0,,计算它们的最大公约数 Dialogue: 0,1:04:10.94,1:04:13.24,Default,,0,0,0,,结果可能是1 或者不是1 Dialogue: 0,1:04:13.84,1:04:15.64,Default,,0,0,0,,如果是1 它们没有公约数 Dialogue: 0,1:04:18.14,1:04:20.68,Default,,0,0,0,,如果它们的最大公约数是1 Dialogue: 0,1:04:21.12,1:04:23.09,Default,,0,0,0,,这两个随机数 Dialogue: 0,1:04:23.09,1:04:26.38,Default,,0,0,0,,两个随机生成的数 最大公约数为1的概率 Dialogue: 0,1:04:26.58,1:04:27.82,Default,,0,0,0,,与pi有关系 Dialogue: 0,1:04:29.32,1:04:30.11,Default,,0,0,0,,事实上 Dialogue: 0,1:04:31.11,1:04:32.33,Default,,0,0,0,,是的 这很奇怪 Dialogue: 0,1:04:32.94,1:04:34.41,Default,,0,0,0,,当然有其他计算pi的方法 Dialogue: 0,1:04:34.41,1:04:38.94,Default,,0,0,0,,像投针法之类的的方法 Dialogue: 0,1:04:40.19,1:04:48.97,Default,,0,0,0,,N1和N2的最大公约数是1的概率为 Dialogue: 0,1:04:49.44,1:04:51.02,Default,,0,0,0,,N1、N2是随机选取的两个数 Dialogue: 0,1:04:51.71,1:04:53.66,Default,,0,0,0,,是6/pi^2 Dialogue: 0,1:04:55.61,1:04:56.83,Default,,0,0,0,,我不准备证明这个 Dialogue: 0,1:04:57.15,1:04:59.64,Default,,0,0,0,,事实上这不难 并且有些有趣 Dialogue: 0,1:05:01.07,1:05:03.05,Default,,0,0,0,,我们要怎样估算这个概率呢? Dialogue: 0,1:05:03.53,1:05:06.46,Default,,0,0,0,,我们估算概率的方法则是 Dialogue: 0,1:05:07.23,1:05:08.65,Default,,0,0,0,,是做大量的实验 Dialogue: 0,1:05:09.20,1:05:12.01,Default,,0,0,0,,去计算成功的试验 Dialogue: 0,1:05:12.01,1:05:13.58,Default,,0,0,0,,与试验总次数的比率 Dialogue: 0,1:05:16.32,1:05:17.28,Default,,0,0,0,,这种方法叫做蒙特卡罗方法 Dialogue: 0,1:05:18.04,1:05:22.38,Default,,0,0,0,,它也可以用于计算包含大量变量的积分 Dialogue: 0,1:05:22.94,1:05:25.28,Default,,0,0,0,,其中积分的面积是限定的 Dialogue: 0,1:05:26.27,1:05:28.70,Default,,0,0,0,,回到这里 Dialogue: 0,1:05:29.76,1:05:31.72,Default,,0,0,0,,我们来看看这张幻灯片 Dialogue: 0,1:05:33.96,1:05:36.92,Default,,0,0,0,,我们可以用Cesaro的方法来估算pi的值 Dialogue: 0,1:05:37.19,1:05:43.18,Default,,0,0,0,,通过N次试验 取结果的六分之一 开根号 Dialogue: 0,1:05:43.29,1:05:46.46,Default,,0,0,0,,用蒙特卡罗方法 Dialogue: 0,1:05:46.80,1:05:50.38,Default,,0,0,0,,进行了N次Cesaro实验 Dialogue: 0,1:05:51.37,1:05:57.56,Default,,0,0,0,,这个实验是关于两个随机数的最大公约数的-- Dialogue: 0,1:05:58.96,1:06:01.60,Default,,0,0,0,,你可以看到 我已经在这里进行了一些赋值 Dialogue: 0,1:06:01.84,1:06:03.13,Default,,0,0,0,,就像我写的这样 Dialogue: 0,1:06:04.04,1:06:07.49,Default,,0,0,0,,这个在括号中的RAND Dialogue: 0,1:06:07.49,1:06:09.09,Default,,0,0,0,,这个过程调用 Dialogue: 0,1:06:09.09,1:06:11.39,Default,,0,0,0,,生成了一个与这个RAND不同的值 Dialogue: 0,1:06:11.39,1:06:13.72,Default,,0,0,0,,至少是我写的这样所假设的 Dialogue: 0,1:06:14.62,1:06:16.75,Default,,0,0,0,,这表明这不是一个函数 Dialogue: 0,1:06:18.20,1:06:20.57,Default,,0,0,0,,这里面会有一个不断改变内部状态 Dialogue: 0,1:06:22.27,1:06:28.64,Default,,0,0,0,,如果两个随机数的最大公约数等于1 Dialogue: 0,1:06:28.64,1:06:29.79,Default,,0,0,0,,这就是整个实验过程 Dialogue: 0,1:06:31.48,1:06:35.18,Default,,0,0,0,,那么我有了一个实验方法 用来估算pi的值 Dialogue: 0,1:06:36.51,1:06:39.72,Default,,0,0,0,,我可以轻松地将这个问题分为两个部分 Dialogue: 0,1:06:40.02,1:06:44.70,Default,,0,0,0,,一部分是使用蒙特卡罗方法进行特定的Cesaro实验 就像你刚才看到那个 Dialogue: 0,1:06:44.99,1:06:48.56,Default,,0,0,0,,另一部分就是一般性蒙特卡罗方法的实现 Dialogue: 0,1:06:49.16,1:06:50.27,Default,,0,0,0,,就是这个 Dialogue: 0,1:06:51.04,1:06:55.47,Default,,0,0,0,,如果我想进行N次蒙特卡罗试验 Dialogue: 0,1:06:55.67,1:06:58.36,Default,,0,0,0,,即一个确定的试验次数 和一个确定的实验 Dialogue: 0,1:06:59.31,1:07:00.33,Default,,0,0,0,,我进行实验的方法就是 Dialogue: 0,1:07:00.84,1:07:02.70,Default,,0,0,0,,构建一个迭代过程 Dialogue: 0,1:07:03.31,1:07:07.26,Default,,0,0,0,,这个过程有两个变量 分别是试验的剩余次数和通过次数 Dialogue: 0,1:07:08.35,1:07:09.44,Default,,0,0,0,,也就是实验结果为真的次数 Dialogue: 0,1:07:10.13,1:07:12.21,Default,,0,0,0,,如果剩余次数为0 Dialogue: 0,1:07:12.21,1:07:15.36,Default,,0,0,0,,结果就是通过的次数除以总次数 Dialogue: 0,1:07:16.04,1:07:17.52,Default,,0,0,0,,也就是该概率的估算值 Dialogue: 0,1:07:19.07,1:07:20.04,Default,,0,0,0,,如果剩余次数不是0 Dialogue: 0,1:07:20.04,1:07:22.08,Default,,0,0,0,,如果还有试验要做 Dialogue: 0,1:07:22.08,1:07:23.82,Default,,0,0,0,,那么接下来我们就进行一次试验 Dialogue: 0,1:07:23.85,1:07:27.30,Default,,0,0,0,,我们调用一次没有参数的实验的过程 Dialogue: 0,1:07:27.30,1:07:28.43,Default,,0,0,0,,我们进行这个试验 Dialogue: 0,1:07:29.10,1:07:30.64,Default,,0,0,0,,如果实验结果为真 Dialogue: 0,1:07:30.82,1:07:32.25,Default,,0,0,0,,我们继续循环 Dialogue: 0,1:07:32.62,1:07:35.42,Default,,0,0,0,,试验剩余次数减1 Dialogue: 0,1:07:35.70,1:07:37.48,Default,,0,0,0,,将试验通过次数加1 Dialogue: 0,1:07:38.57,1:07:40.11,Default,,0,0,0,,如果试验的结果为假 Dialogue: 0,1:07:40.41,1:07:42.25,Default,,0,0,0,,我们继续循环 Dialogue: 0,1:07:42.32,1:07:44.38,Default,,0,0,0,,剩余试验次数减1 Dialogue: 0,1:07:44.44,1:07:46.60,Default,,0,0,0,,试验通过次数保持不变 Dialogue: 0,1:07:48.76,1:07:54.59,Default,,0,0,0,,我们以TRIAL为剩余次数 以0为通过次数 开始迭代 Dialogue: 0,1:07:55.42,1:07:57.10,Default,,0,0,0,,多么简洁的小程序啊 Dialogue: 0,1:07:57.74,1:08:00.55,Default,,0,0,0,,我不一定非要进行Cesaro的实验 Dialogue: 0,1:08:00.55,1:08:02.73,Default,,0,0,0,,它可以用来进行很多种蒙特卡罗实验 Dialogue: 0,1:08:03.36,1:08:07.12,Default,,0,0,0,,当然 它依赖于某种随机数生成器的存在 Dialogue: 0,1:08:07.34,1:08:10.99,Default,,0,0,0,,随机数生成器通常是像这种的东西 Dialogue: 0,1:08:13.60,1:08:16.32,Default,,0,0,0,,这是一个随机数生成器-- Dialogue: 0,1:08:17.42,1:08:25.21,Default,,0,0,0,,它实际上就是一个过程 具体行为跟计数器有些相似 Dialogue: 0,1:08:25.61,1:08:27.52,Default,,0,0,0,,它会把X的值更新为 Dialogue: 0,1:08:28.33,1:08:31.82,Default,,0,0,0,,将某个函数应用于X的结果 Dialogue: 0,1:08:32.20,1:08:35.28,Default,,0,0,0,,而这类古怪的函数 Dialogue: 0,1:08:35.39,1:08:40.16,Default,,0,0,0,,你可以在Kunth写的关于编程细节的书中找到 Dialogue: 0,1:08:41.56,1:08:45.75,Default,,0,0,0,,他写的书绝妙而充满了编程细节 Dialogue: 0,1:08:45.75,1:08:48.52,Default,,0,0,0,,虽然我记不住随机数生成器该怎样写 Dialogue: 0,1:08:48.63,1:08:50.62,Default,,0,0,0,,但我可以在书里找出一个来用 Dialogue: 0,1:08:51.64,1:08:54.01,Default,,0,0,0,,最后 我返回了X的值 Dialogue: 0,1:08:54.08,1:08:57.40,Default,,0,0,0,,也就是随机数生成器的内部状态变量 Dialogue: 0,1:08:58.28,1:09:00.75,Default,,0,0,0,,这个状态变量以某种方式被初始化 Dialogue: 0,1:09:01.32,1:09:02.24,Default,,0,0,0,,从而获得了一个值 Dialogue: 0,1:09:03.39,1:09:08.11,Default,,0,0,0,,这个过程被定义在那个变量被约束的上下文中 Dialogue: 0,1:09:10.41,1:09:15.26,Default,,0,0,0,,所以你在这看到的 是一个隐藏的局部状态 Dialogue: 0,1:09:15.87,1:09:20.24,Default,,0,0,0,,这个过程定义在那个上下文中 Dialogue: 0,1:09:21.56,1:09:23.66,Default,,0,0,0,,这样做起来非常容易 Dialogue: 0,1:09:24.88,1:09:25.79,Default,,0,0,0,,而且结果也非常好 Dialogue: 0,1:09:25.99,1:09:27.77,Default,,0,0,0,,设想 我不想用赋值 Dialogue: 0,1:09:29.10,1:09:31.47,Default,,0,0,0,,假设我想写一个不带赋值的程序 Dialogue: 0,1:09:32.73,1:09:33.93,Default,,0,0,0,,我将遇到什么困难? Dialogue: 0,1:09:35.52,1:09:37.40,Default,,0,0,0,,让我们来看看 Dialogue: 0,1:09:37.82,1:09:41.10,Default,,0,0,0,,我要用一下头顶上的投影仪了 Dialogue: 0,1:09:42.06,1:09:42.70,Default,,0,0,0,,多谢 Dialogue: 0,1:09:43.47,1:09:47.66,Default,,0,0,0,,首先 我们来整体看一下 这是一个很庞大的东西 Dialogue: 0,1:09:48.01,1:09:49.90,Default,,0,0,0,,它告诉你有某些东西出了问题 Dialogue: 0,1:09:50.96,1:09:52.75,Default,,0,0,0,,毕竟有这么大一堆东西呢 Dialogue: 0,1:09:53.42,1:09:54.60,Default,,0,0,0,,庞大而单一 Dialogue: 0,1:09:56.76,1:10:00.12,Default,,0,0,0,,你不需要现在去理解或看这里的文本 Dialogue: 0,1:10:00.12,1:10:01.39,Default,,0,0,0,,就把它们看做一个整体 Dialogue: 0,1:10:01.92,1:10:04.89,Default,,0,0,0,,它不是Cesaro的实验 Dialogue: 0,1:10:04.89,1:10:07.90,Default,,0,0,0,,它不是从蒙特卡罗过程中抽取出来的 Dialogue: 0,1:10:09.87,1:10:11.84,Default,,0,0,0,,它不是分离的 让我们来看看为什么 Dialogue: 0,1:10:14.22,1:10:15.85,Default,,0,0,0,,记住 这里的约束是 Dialogue: 0,1:10:15.85,1:10:17.87,Default,,0,0,0,,每个过程 Dialogue: 0,1:10:18.69,1:10:22.20,Default,,0,0,0,,对于同样的参数 将返回同样的值 Dialogue: 0,1:10:22.97,1:10:24.75,Default,,0,0,0,,每个过程就是一个函数 Dialogue: 0,1:10:26.92,1:10:28.50,Default,,0,0,0,,那是另一种约束 Dialogue: 0,1:10:28.50,1:10:31.21,Default,,0,0,0,,因为当我赋值时 我可以改变一些内部状态变量 Dialogue: 0,1:10:31.74,1:10:34.03,Default,,0,0,0,,所以让我们来看看它是怎么出错的 Dialogue: 0,1:10:35.04,1:10:36.14,Default,,0,0,0,,我们从头开始 Dialogue: 0,1:10:37.50,1:10:41.92,Default,,0,0,0,,估算pi的过程看起来是一样的 Dialogue: 0,1:10:42.66,1:10:45.88,Default,,0,0,0,,我取RAMDOM-GCD-TEST应用于N Dialogue: 0,1:10:46.35,1:10:50.22,Default,,0,0,0,,的结果分之6的平方根 Dialogue: 0,1:10:50.74,1:10:51.93,Default,,0,0,0,,就是这个 Dialogue: 0,1:10:52.96,1:10:55.20,Default,,0,0,0,,在这里 我们开始看到了一些有趣的东西 Dialogue: 0,1:10:55.20,1:10:57.93,Default,,0,0,0,,对于以TRAILS为参数的RANDOM-GCD-TEST过程 Dialogue: 0,1:10:58.32,1:10:59.98,Default,,0,0,0,,就像我们之前做的一样 Dialogue: 0,1:11:00.46,1:11:04.66,Default,,0,0,0,,是一个以剩余次数 Dialogue: 0,1:11:04.66,1:11:06.80,Default,,0,0,0,,通过次数 Dialogue: 0,1:11:08.27,1:11:09.71,Default,,0,0,0,,另一个变量X为基准的迭代 Dialogue: 0,1:11:10.75,1:11:11.76,Default,,0,0,0,,这个X是什么? Dialogue: 0,1:11:12.33,1:11:15.20,Default,,0,0,0,,X是随机数发生器的状态 Dialogue: 0,1:11:19.00,1:11:21.16,Default,,0,0,0,,它会在这里被使用 Dialogue: 0,1:11:21.16,1:11:23.79,Default,,0,0,0,,这里的同样的随机更新函数 Dialogue: 0,1:11:23.79,1:11:27.15,Default,,0,0,0,,来自于一个我另外写的随机数发生器 Dialogue: 0,1:11:27.71,1:11:29.32,Default,,0,0,0,,或者从Knuth的书中找一个 Dialogue: 0,1:11:31.56,1:11:33.36,Default,,0,0,0,,X将转化为X1 Dialogue: 0,1:11:33.37,1:11:34.36,Default,,0,0,0,,但我需要两个随机数 Dialogue: 0,1:11:34.81,1:11:36.92,Default,,0,0,0,,X1将被转化为X2 Dialogue: 0,1:11:37.26,1:11:38.44,Default,,0,0,0,,我有两个随机数 Dialogue: 0,1:11:39.50,1:11:42.14,Default,,0,0,0,,然后进行和之前一样的步骤 Dialogue: 0,1:11:42.52,1:11:44.19,Default,,0,0,0,,取X1和X2的最大公约数 Dialogue: 0,1:11:44.22,1:11:47.15,Default,,0,0,0,,如果结果是1 则将X2作为下一个X的值继续循环 Dialogue: 0,1:11:54.78,1:11:55.98,Default,,0,0,0,,这里所发生的 Dialogue: 0,1:11:56.88,1:11:58.70,Default,,0,0,0,,随机数发生器的状态 Dialogue: 0,1:11:58.73,1:12:01.70,Default,,0,0,0,,不再被限制于其内部 Dialogue: 0,1:12:01.80,1:12:02.73,Default,,0,0,0,,它已经暴露了出来 Dialogue: 0,1:12:03.33,1:12:05.50,Default,,0,0,0,,它已经被暴露在 Dialogue: 0,1:12:05.50,1:12:10.08,Default,,0,0,0,,我们的的蒙特卡罗实验的过程中 Dialogue: 0,1:12:10.70,1:12:11.87,Default,,0,0,0,,但比那更糟糕的是 Dialogue: 0,1:12:11.87,1:12:16.24,Default,,0,0,0,,同样的 因为它也被包含在我们的Cesaro实验中 Dialogue: 0,1:12:16.78,1:12:19.48,Default,,0,0,0,,它被暴露了两次 因为Cesaro被调用了两次 Dialogue: 0,1:12:20.86,1:12:22.47,Default,,0,0,0,,每次有不同的值 Dialogue: 0,1:12:22.47,1:12:25.16,Default,,0,0,0,,如果我要进行一个合理的实验的话 Dialogue: 0,1:12:26.32,1:12:28.32,Default,,0,0,0,,所以Cesaro也不能成为函数了 Dialogue: 0,1:12:31.04,1:12:35.69,Default,,0,0,0,,除非我把随机数发生器的种子传给它 Dialogue: 0,1:12:36.52,1:12:39.37,Default,,0,0,0,,所以很不幸 随机数发生器的种子 Dialogue: 0,1:12:39.37,1:12:42.77,Default,,0,0,0,,从随机数发生器中暴露到了Cesaro内部 Dialogue: 0,1:12:42.88,1:12:45.16,Default,,0,0,0,,被暴露在蒙特卡罗实验中 Dialogue: 0,1:12:45.64,1:12:49.12,Default,,0,0,0,,很不幸 这里的蒙特卡罗实验不再是通用的了 Dialogue: 0,1:12:50.25,1:12:51.80,Default,,0,0,0,,这里的蒙特卡罗实验 Dialogue: 0,1:12:52.03,1:12:54.73,Default,,0,0,0,,知道了我在实验中需要多少个随机数 Dialogue: 0,1:12:58.96,1:12:59.74,Default,,0,0,0,,这真的很糟糕 Dialogue: 0,1:13:00.08,1:13:02.54,Default,,0,0,0,,我失去了将问题分解开来的能力 Dialogue: 0,1:13:03.44,1:13:09.12,Default,,0,0,0,,因为我不愿意接受信息的循环 Dialogue: 0,1:13:09.50,1:13:12.43,Default,,0,0,0,,反馈的过程 Dialogue: 0,1:13:12.88,1:13:15.94,Default,,0,0,0,,这之前都是发生在随机数发生器内部 Dialogue: 0,1:13:15.94,1:13:21.21,Default,,0,0,0,,也就是赋值给一个限制在随机数生成器内部的状态变量 Dialogue: 0,1:13:22.92,1:13:25.48,Default,,0,0,0,,所以实际上 随机数发生器是一个对象 Dialogue: 0,1:13:25.92,1:13:27.37,Default,,0,0,0,,它有一个内部状态变量 Dialogue: 0,1:13:28.06,1:13:29.36,Default,,0,0,0,,它不受任何东西影响 Dialogue: 0,1:13:29.37,1:13:31.60,Default,,0,0,0,,但是它会给你某些东西 把它的力量赐予你 Dialogue: 0,1:13:32.80,1:13:34.28,Default,,0,0,0,,那是我们现在缺少的 Dialogue: 0,1:13:38.00,1:13:40.73,Default,,0,0,0,,好 我认为我已经知道了 Dialogue: 0,1:13:40.73,1:13:42.30,Default,,0,0,0,,引入赋值的充分理由 Dialogue: 0,1:13:42.83,1:13:45.24,Default,,0,0,0,,并且一些看起来很圆满 Dialogue: 0,1:13:45.38,1:13:50.70,Default,,0,0,0,,如果赋值是一个好东西 Dialogue: 0,1:13:51.74,1:13:53.04,Default,,0,0,0,,并且赋值是值得的 这不是很好吗? Dialogue: 0,1:13:53.28,1:13:54.14,Default,,0,0,0,,我不是很确定 Dialogue: 0,1:13:55.34,1:13:57.04,Default,,0,0,0,,Mr. Gilbert和Sullivan说过 Dialogue: 0,1:13:57.04,1:13:58.51,Default,,0,0,0,,事物往往不像表面看到的那样 Dialogue: 0,1:13:58.51,1:14:00.35,Default,,0,0,0,,脱脂牛奶也能装成奶油 Dialogue: 0,1:14:01.87,1:14:03.90,Default,,0,0,0,,谁有什么问题吗? Dialogue: 0,1:14:16.97,1:14:18.30,Default,,0,0,0,,在座的有哲学家吗? Dialogue: 0,1:14:20.06,1:14:22.03,Default,,0,0,0,,有人想要讨论有关“对象”的问题吗? Dialogue: 0,1:14:24.32,1:14:25.50,Default,,0,0,0,,你们已经一头雾水了是吧? Dialogue: 0,1:14:29.72,1:14:30.72,Default,,0,0,0,,你们还没有完成家庭作业呢 Dialogue: 0,1:14:30.73,1:14:32.00,Default,,0,0,0,,你们需要提一个好问题 Dialogue: 0,1:14:36.35,1:14:37.44,Default,,0,0,0,,好了 Dialogue: 0,1:14:39.97,1:14:42.33,Default,,0,0,0,,感谢你们 我们下课吧 Dialogue: 0,1:14:47.90,1:15:05.69,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:14:47.90,1:15:05.69,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec5a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 89 Active Line: 93 Video Position: 9470 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:01.96,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:01.98,0:00:09.55,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:01.98,0:00:09.55,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:01.98,0:00:09.55,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:01.98,0:00:09.55,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N杨启钊(windfarer) Dialogue: 0,0:00:01.98,0:00:09.55,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:09.92,0:00:13.63,Declare,,0,0,0,,{\an2\fad(500,500)}赋值、状态和副作用 Dialogue: 0,0:00:18.31,0:00:22.00,Default,,0,0,0,,教授:到目前为止 我们已经教了很多编程技巧 Dialogue: 0,0:00:22.25,0:00:24.06,Default,,0,0,0,,来编写复杂程序了 Dialogue: 0,0:00:24.76,0:00:29.66,Default,,0,0,0,,并且 到目前为止 关于编程你们学到了很多 Dialogue: 0,0:00:29.66,0:00:31.48,Default,,0,0,0,,你们已经学习了几乎所有的 Dialogue: 0,0:00:31.86,0:00:35.87,Default,,0,0,0,,那些拥有大量经验的人 才能领悟的技巧 Dialogue: 0,0:00:36.41,0:00:40.08,Default,,0,0,0,,例如 数据导向编程就是一个主要的技巧 Dialogue: 0,0:00:40.75,0:00:43.15,Default,,0,0,0,,昨天 你们也学习了一种解释型语言 Dialogue: 0,0:00:45.02,0:00:48.46,Default,,0,0,0,,我们所做的这一切 Dialogue: 0,0:00:48.54,0:00:49.63,Default,,0,0,0,,目前来讲 Dialogue: 0,0:00:49.88,0:00:51.95,Default,,0,0,0,,都是在一种没有赋值语句的计算机语言中完成的 Dialogue: 0,0:00:53.77,0:00:58.17,Default,,0,0,0,,对于你们中用过Basic或者Pascal的人 Dialogue: 0,0:00:58.68,0:01:01.23,Default,,0,0,0,,可能会认为“赋值”是最重要的东西 Dialogue: 0,0:01:01.79,0:01:03.82,Default,,0,0,0,,今天我们将要做一些糟糕的事情 Dialogue: 0,0:01:03.82,0:01:05.45,Default,,0,0,0,,我们要把赋值语句加进来 Dialogue: 0,0:01:07.21,0:01:09.14,Default,,0,0,0,,既然在没有赋值语句的时候 我们都可以很好地完成工作 Dialogue: 0,0:01:09.14,0:01:10.17,Default,,0,0,0,,为什么我们还要把它加进来呢? Dialogue: 0,0:01:10.99,0:01:12.43,Default,,0,0,0,,为了理解它 Dialogue: 0,0:01:12.46,0:01:15.71,Default,,0,0,0,,我们今天首先要定下一个规则 Dialogue: 0,0:01:16.48,0:01:17.93,Default,,0,0,0,,而我们将一直遵守这个规则 Dialogue: 0,0:01:17.93,0:01:20.80,Default,,0,0,0,,这是我们为语言引入新的特性的唯一原因 Dialogue: 0,0:01:21.53,0:01:23.14,Default,,0,0,0,,是因为我们有一个好的理由 Dialogue: 0,0:01:23.93,0:01:27.28,Default,,0,0,0,,好的理由归结为能力 Dialogue: 0,0:01:27.42,0:01:31.51,Default,,0,0,0,,你现在获得了把问题分解为不同部分的能力 Dialogue: 0,0:01:31.51,0:01:33.44,Default,,0,0,0,,在没有相关能力之前可不行 Dialogue: 0,0:01:34.38,0:01:36.16,Default,,0,0,0,,这让你有用来分解问题的另外方法 Dialogue: 0,0:01:38.30,0:01:39.45,Default,,0,0,0,,我们这就开始 Dialogue: 0,0:01:39.45,0:01:41.88,Default,,0,0,0,,从回顾我们的 Dialogue: 0,0:01:41.88,0:01:47.37,Default,,0,0,0,,现在已经有的这种语言出发 Dialogue: 0,0:01:48.16,0:01:50.44,Default,,0,0,0,,我们之前写的是所谓的函数式程序 Dialogue: 0,0:01:51.21,0:01:52.52,Default,,0,0,0,,函数式程序 Dialogue: 0,0:01:53.04,0:01:57.95,Default,,0,0,0,,是一种对数学事实的编码 Dialogue: 0,0:01:58.88,0:02:00.51,Default,,0,0,0,,例如 当我们看到 Dialogue: 0,0:02:00.51,0:02:04.09,Default,,0,0,0,,像幻灯片上这样阶乘过程时 Dialogue: 0,0:02:05.07,0:02:06.62,Default,,0,0,0,,基本上是两个子句 Dialogue: 0,0:02:06.99,0:02:08.64,Default,,0,0,0,,如果n是1 则结果是1 Dialogue: 0,0:02:08.64,0:02:11.20,Default,,0,0,0,,否则返回n乘以n-1的阶乘 Dialogue: 0,0:02:11.20,0:02:12.33,Default,,0,0,0,,这是n的阶乘 Dialogue: 0,0:02:12.89,0:02:14.27,Default,,0,0,0,,它就是阶乘函数 Dialogue: 0,0:02:14.83,0:02:16.87,Default,,0,0,0,,如果用一些其他的记号 Dialogue: 0,0:02:16.87,0:02:19.32,Default,,0,0,0,,那些你在微积分课堂上学到的晦涩的符号来写 Dialogue: 0,0:02:20.30,0:02:22.11,Default,,0,0,0,,用数理逻辑来写 Dialogue: 0,0:02:22.11,0:02:26.36,Default,,0,0,0,,如果n等于1 Dialogue: 0,0:02:27.13,0:02:29.90,Default,,0,0,0,,那么n的阶乘结果是1 否则 Dialogue: 0,0:02:29.90,0:02:32.56,Default,,0,0,0,,如果n大于1 则n的阶乘就是n * (n-1)! Dialogue: 0,0:02:32.56,0:02:33.55,Default,,0,0,0,,数学事实 Dialogue: 0,0:02:34.92,0:02:36.70,Default,,0,0,0,,就是我们一直使用的那种语言 Dialogue: 0,0:02:37.00,0:02:39.23,Default,,0,0,0,,无论何时 我们遇到了这样的数学事实 Dialogue: 0,0:02:39.53,0:02:46.65,Default,,0,0,0,,有一种理解它们工作原理的方法 Dialogue: 0,0:02:47.40,0:02:51.12,Default,,0,0,0,,就是这些过程可以由代换演算而来 Dialogue: 0,0:02:51.29,0:02:53.71,Default,,0,0,0,,来看第二张幻灯片 Dialogue: 0,0:02:54.99,0:02:58.81,Default,,0,0,0,,我们理解执行的过程 Dialogue: 0,0:02:58.83,0:03:03.50,Default,,0,0,0,,隐含在表达式的顺序中 Dialogue: 0,0:03:04.04,0:03:07.76,Default,,0,0,0,,也就是你不断地将实际参数 Dialogue: 0,0:03:07.87,0:03:10.88,Default,,0,0,0,,代换到程序体的形式参数中 Dialogue: 0,0:03:12.00,0:03:14.51,Default,,0,0,0,,这些基本上是一系列的等价代换 Dialogue: 0,0:03:14.61,0:03:17.25,Default,,0,0,0,,4的阶乘是4乘以3的阶乘 Dialogue: 0,0:03:17.25,0:03:20.05,Default,,0,0,0,,也就是4乘以3乘以2的阶乘 Dialogue: 0,0:03:20.05,0:03:21.01,Default,,0,0,0,,以此类推 Dialogue: 0,0:03:21.23,0:03:23.87,Default,,0,0,0,,我们总是保持数学事实成立 Dialogue: 0,0:03:25.23,0:03:28.84,Default,,0,0,0,,尽管我们正在讨论数学事实 Dialogue: 0,0:03:28.84,0:03:31.96,Default,,0,0,0,,可能有多种数学事实的组织方式 Dialogue: 0,0:03:31.96,0:03:35.12,Default,,0,0,0,,用来描述一个特定的函数的计算 Dialogue: 0,0:03:36.32,0:03:38.42,Default,,0,0,0,,这个特定的函数的值的计算 Dialogue: 0,0:03:38.42,0:03:40.92,Default,,0,0,0,,所以 让我来看下这里的例子 Dialogue: 0,0:03:41.48,0:03:49.02,Default,,0,0,0,,这有一个计算m与n之和的方法 Dialogue: 0,0:03:49.53,0:03:52.04,Default,,0,0,0,,我们使用一个递归的过程来完成 Dialogue: 0,0:03:52.89,0:03:58.16,Default,,0,0,0,,也就是(1+ (+ (-1+ n) m)) Dialogue: 0,0:04:00.08,0:04:05.62,Default,,0,0,0,,当然 这里也有相应的数理逻辑 解释了这个方法 Dialogue: 0,0:04:06.17,0:04:10.49,Default,,0,0,0,,也就是((n-1)+m)+1 Dialogue: 0,0:04:11.40,0:04:12.22,Default,,0,0,0,,跟之前那个一样 Dialogue: 0,0:04:13.10,0:04:16.40,Default,,0,0,0,,所以这儿并没有什么特殊的魔法 Dialogue: 0,0:04:16.41,0:04:20.01,Default,,0,0,0,,当然 如果我们可以再来看一个相同的迭代过程 Dialogue: 0,0:04:20.19,0:04:24.92,Default,,0,0,0,,计算同样的函数 但是进行逐步迭代的程序 Dialogue: 0,0:04:25.26,0:04:27.56,Default,,0,0,0,,这两个程序将得到同样的结果 Dialogue: 0,0:04:30.08,0:04:34.83,Default,,0,0,0,,我们就可以认为这两个程序在数学上是等效的 Dialogue: 0,0:04:36.65,0:04:39.93,Default,,0,0,0,,你对这些数学事实的排序 决定了具体(计算)过程 Dialogue: 0,0:04:40.30,0:04:43.42,Default,,0,0,0,,我们对于这些数学事实的排序和选择 决定了过程发展的方式 Dialogue: 0,0:04:44.33,0:04:48.60,Default,,0,0,0,,因此我们可以灵活地讨论待计算的函数 Dialogue: 0,0:04:48.60,0:04:50.19,Default,,0,0,0,,以及计算该函数的所用的方法 Dialogue: 0,0:04:50.60,0:04:52.60,Default,,0,0,0,,这并不清晰 我们需要再深入一些 Dialogue: 0,0:04:53.61,0:04:55.50,Default,,0,0,0,,然而 今天我要来讲这个糟糕的东西 Dialogue: 0,0:04:55.50,0:04:58.43,Default,,0,0,0,,我要给大家介绍赋值操作 Dialogue: 0,0:04:58.89,0:05:00.41,Default,,0,0,0,,这是什么? Dialogue: 0,0:05:02.89,0:05:09.22,Default,,0,0,0,,首先 在编程语言中有另一种语句 Dialogue: 0,0:05:09.22,0:05:10.84,Default,,0,0,0,,这种语句叫做SET! Dialogue: 0,0:05:12.41,0:05:15.96,Default,,0,0,0,,具有赋值操作的语句 Dialogue: 0,0:05:15.98,0:05:17.85,Default,,0,0,0,,我都会在后面加上一个感叹号 Dialogue: 0,0:05:18.51,0:05:20.96,Default,,0,0,0,,这个感叹号代表什么意思呢? Dialogue: 0,0:05:20.96,0:05:23.01,Default,,0,0,0,,这个感叹号 与问号类似 Dialogue: 0,0:05:23.01,0:05:25.88,Default,,0,0,0,,是我们给名字随意加的符号 Dialogue: 0,0:05:25.88,0:05:27.88,Default,,0,0,0,,它对于系统来说没有意义 Dialogue: 0,0:05:28.08,0:05:30.21,Default,,0,0,0,,它唯一的意义就是告诉我们 Dialogue: 0,0:05:30.40,0:05:34.41,Default,,0,0,0,,注意这里是某种赋值操作 Dialogue: 0,0:05:35.88,0:05:40.06,Default,,0,0,0,,但是我们要给某个变量赋一个值 Dialogue: 0,0:05:43.74,0:05:45.13,Default,,0,0,0,,这意味着 Dialogue: 0,0:05:45.13,0:05:48.28,Default,,0,0,0,,在某个时间点发生了一些事情 Dialogue: 0,0:05:48.65,0:05:49.61,Default,,0,0,0,,这是一个时间点 Dialogue: 0,0:05:49.86,0:05:52.14,Default,,0,0,0,,如果时间以这个方向流动 Dialogue: 0,0:05:53.50,0:05:54.82,Default,,0,0,0,,这是个时间轴 Dialogue: 0,0:05:55.00,0:05:57.82,Default,,0,0,0,,时间在平面上由上到下地流逝 Dialogue: 0,0:05:58.70,0:06:00.92,Default,,0,0,0,,赋值是第一个 Dialogue: 0,0:06:00.92,0:06:04.30,Default,,0,0,0,,使过去和未来之间产生差别的事物 Dialogue: 0,0:06:06.59,0:06:08.72,Default,,0,0,0,,我们之前写的所有程序 Dialogue: 0,0:06:09.18,0:06:10.68,Default,,0,0,0,,都不包含赋值 Dialogue: 0,0:06:10.68,0:06:13.12,Default,,0,0,0,,这些程序以怎样的顺序进行执行都没关系 Dialogue: 0,0:06:14.70,0:06:15.96,Default,,0,0,0,,但是赋值比较特殊 Dialogue: 0,0:06:15.96,0:06:17.69,Default,,0,0,0,,它使时间中产生了一个时间点 Dialogue: 0,0:06:17.96,0:06:24.73,Default,,0,0,0,,因此在SET!出现之前和之后中间有一个时间点 Dialogue: 0,0:06:27.61,0:06:32.70,Default,,0,0,0,,使得在这个时间点之后 Dialogue: 0,0:06:33.60,0:06:43.76,Default,,0,0,0,,变量有了一个值 即VALUE Dialogue: 0,0:06:49.23,0:06:51.50,Default,,0,0,0,,与这个变量之前的值无关 Dialogue: 0,0:06:52.80,0:06:55.79,Default,,0,0,0,,SET!改变了它的值 Dialogue: 0,0:06:57.69,0:06:58.75,Default,,0,0,0,,在此之前 Dialogue: 0,0:06:58.75,0:07:01.50,Default,,0,0,0,,什么都没有发生改变 Dialogue: 0,0:07:03.21,0:07:04.11,Default,,0,0,0,,举例来说 Dialogue: 0,0:07:04.84,0:07:06.23,Default,,0,0,0,,我们可以想到的一件事是 Dialogue: 0,0:07:06.23,0:07:09.42,Default,,0,0,0,,我们写的一些过程 比如阶乘的程序 Dialogue: 0,0:07:09.64,0:07:12.75,Default,,0,0,0,,事实上与数学中的阶乘函数完全相同 Dialogue: 0,0:07:13.77,0:07:16.44,Default,,0,0,0,,比如说4的阶乘 如果我写FACT(4) Dialogue: 0,0:07:17.23,0:07:19.15,Default,,0,0,0,,无论它的上下文是怎样的 Dialogue: 0,0:07:19.69,0:07:21.29,Default,,0,0,0,,无论我写几遍 Dialogue: 0,0:07:21.29,0:07:22.35,Default,,0,0,0,,我总能得到同样的结果 Dialogue: 0,0:07:23.29,0:07:24.12,Default,,0,0,0,,结果永远是24 Dialogue: 0,0:07:25.37,0:07:28.92,Default,,0,0,0,,它是参数到到结果的唯一映射 Dialogue: 0,0:07:30.30,0:07:32.65,Default,,0,0,0,,迄今为止 我们之前写的所有程序都是这样的 Dialogue: 0,0:07:33.52,0:07:36.03,Default,,0,0,0,,然而 当引入赋值后 一切就不同了 Dialogue: 0,0:07:36.96,0:07:38.16,Default,,0,0,0,,举个例子 Dialogue: 0,0:07:39.18,0:07:48.52,Default,,0,0,0,,如果我将COUNT定义为1 Dialogue: 0,0:07:50.00,0:07:52.41,Default,,0,0,0,,然后定义一个过程 Dialogue: 0,0:07:55.16,0:07:56.83,Default,,0,0,0,,一个叫做DEMO的简单过程 Dialogue: 0,0:07:59.52,0:08:03.84,Default,,0,0,0,,它接受参数X 并执行下面的操作 Dialogue: 0,0:08:03.84,0:08:09.62,Default,,0,0,0,,首先将X修改为X+1 Dialogue: 0,0:08:09.62,0:08:11.77,Default,,0,0,0,,我的天啊! 这看起来就像FORTRAN是吧? Dialogue: 0,0:08:13.16,0:08:14.17,Default,,0,0,0,,只是用了些有趣的语法 Dialogue: 0,0:08:16.80,0:08:21.37,Default,,0,0,0,,然后返回(+ X COUNT) Dialogue: 0,0:08:22.14,0:08:24.14,Default,,0,0,0,,哦 我刚犯了个错 Dialogue: 0,0:08:24.38,0:08:25.23,Default,,0,0,0,,我的意思是 Dialogue: 0,0:08:25.47,0:08:27.12,Default,,0,0,0,,(SET! COUNT (1+ COUNT)) Dialogue: 0,0:08:30.37,0:08:31.79,Default,,0,0,0,,就是我在这里定义的这个 Dialogue: 0,0:08:34.41,0:08:36.51,Default,,0,0,0,,然后X和COUNT相加 Dialogue: 0,0:08:40.35,0:08:42.06,Default,,0,0,0,,然后就可以试着运行这个过程了 Dialogue: 0,0:08:42.48,0:08:43.20,Default,,0,0,0,,让我们运行它 Dialogue: 0,0:08:43.92,0:08:47.22,Default,,0,0,0,,假设我可以输入 Dialogue: 0,0:08:47.48,0:08:48.68,Default,,0,0,0,,输入(DEMO 3) Dialogue: 0,0:08:52.19,0:08:53.20,Default,,0,0,0,,这里发生了什么? Dialogue: 0,0:08:53.74,0:08:55.28,Default,,0,0,0,,发生的第一件事情是 Dialogue: 0,0:08:55.53,0:08:56.89,Default,,0,0,0,,COUNT现在是1 Dialogue: 0,0:08:56.89,0:08:58.40,Default,,0,0,0,,现在 这是一个时间点 Dialogue: 0,0:08:59.12,0:09:00.29,Default,,0,0,0,,我们在讨论时间点 Dialogue: 0,0:09:00.62,0:09:01.74,Default,,0,0,0,,X的值为3 Dialogue: 0,0:09:02.92,0:09:04.03,Default,,0,0,0,,在这个时刻 Dialogue: 0,0:09:04.67,0:09:07.53,Default,,0,0,0,,COUNT增加了 所以COUNT是2 Dialogue: 0,0:09:09.02,0:09:10.44,Default,,0,0,0,,2加3等于5 Dialogue: 0,0:09:10.80,0:09:12.43,Default,,0,0,0,,所以结果是5 Dialogue: 0,0:09:14.48,0:09:21.58,Default,,0,0,0,,然后我再一次 输入(DEMO 3) Dialogue: 0,0:09:23.60,0:09:24.56,Default,,0,0,0,,结果是什么? Dialogue: 0,0:09:24.83,0:09:27.40,Default,,0,0,0,,现在COUNT是2 它不再是1了 Dialogue: 0,0:09:28.91,0:09:30.35,Default,,0,0,0,,因为我让COUNT加1了 Dialogue: 0,0:09:30.92,0:09:32.64,Default,,0,0,0,,但现在我执行这个过程 Dialogue: 0,0:09:32.72,0:09:33.66,Default,,0,0,0,,X的值为3 Dialogue: 0,0:09:34.17,0:09:37.40,Default,,0,0,0,,COUNT变为1+COUNT 因此现在是3了 Dialogue: 0,0:09:38.08,0:09:39.62,Default,,0,0,0,,这两个相加是6 Dialogue: 0,0:09:39.62,0:09:40.94,Default,,0,0,0,,所以结果是6 Dialogue: 0,0:09:41.92,0:09:43.03,Default,,0,0,0,,我们可以发现 Dialogue: 0,0:09:43.03,0:09:44.72,Default,,0,0,0,,同样的表达式 Dialogue: 0,0:09:45.08,0:09:46.64,Default,,0,0,0,,因为时间节点的不同 Dialogue: 0,0:09:48.75,0:09:49.96,Default,,0,0,0,,得到了不同的结果 Dialogue: 0,0:09:52.08,0:09:53.74,Default,,0,0,0,,所以DEMO不是函数 Dialogue: 0,0:09:54.17,0:09:56.12,Default,,0,0,0,,或者说它并没有计算一个数学意义上的函数 Dialogue: 0,0:09:59.88,0:10:02.09,Default,,0,0,0,,事实上 你可以知道这是为什么 Dialogue: 0,0:10:02.84,0:10:06.41,Default,,0,0,0,,因为这里是第一处代换模型失效的地方 Dialogue: 0,0:10:07.72,0:10:09.55,Default,,0,0,0,,它给代换模型判了死刑 Dialogue: 0,0:10:11.28,0:10:13.82,Default,,0,0,0,,有些关于引用的一些小问题 Dialogue: 0,0:10:13.85,0:10:17.18,Default,,0,0,0,,哲学家可能注意到 特别是与代换有关时 Dialogue: 0,0:10:17.18,0:10:19.87,Default,,0,0,0,,因为当你在引用中进行代换时 Dialogue: 0,0:10:20.91,0:10:22.12,Default,,0,0,0,,需要考虑你可以得到什么样的推论 Dialogue: 0,0:10:22.34,0:10:23.92,Default,,0,0,0,,如果你能够使用代换的话 Dialogue: 0,0:10:25.08,0:10:25.60,Default,,0,0,0,,但是 Dialogue: 0,0:10:26.06,0:10:28.00,Default,,0,0,0,,在这里代换模型已经失效了 Dialogue: 0,0:10:28.11,0:10:29.40,Default,,0,0,0,,它什么也不能做了 Dialogue: 0,0:10:29.64,0:10:30.57,Default,,0,0,0,,因为 Dialogue: 0,0:10:30.57,0:10:35.85,Default,,0,0,0,,假设我想用代换模型来考虑COUNT的代换 Dialogue: 0,0:10:37.10,0:10:41.16,Default,,0,0,0,,如果我在这里和这里进行代换 Dialogue: 0,0:10:41.69,0:10:42.96,Default,,0,0,0,,它们是不同的 Dialogue: 0,0:10:44.44,0:10:45.96,Default,,0,0,0,,它不再是同一个COUNT了 Dialogue: 0,0:10:46.48,0:10:47.64,Default,,0,0,0,,我得到了错误的结果 Dialogue: 0,0:10:47.97,0:10:50.14,Default,,0,0,0,,代换模型是一个静态的现象 Dialogue: 0,0:10:51.18,0:10:52.56,Default,,0,0,0,,它描述的事实 Dialogue: 0,0:10:53.93,0:10:55.29,Default,,0,0,0,,而不是变动 Dialogue: 0,0:10:55.50,0:10:57.04,Default,,0,0,0,,这里 我们的事实变动了 Dialogue: 0,0:11:00.60,0:11:06.74,Default,,0,0,0,,那么 在我给出任何解释之前 Dialogue: 0,0:11:06.74,0:11:07.79,Default,,0,0,0,,这很糟糕 Dialogue: 0,0:11:07.79,0:11:09.72,Default,,0,0,0,,我们失去了我们的计算模型 Dialogue: 0,0:11:10.28,0:11:10.80,Default,,0,0,0,,并且 Dialogue: 0,0:11:11.48,0:11:13.69,Default,,0,0,0,,很快 我将不得不构建一个新的计算模型 Dialogue: 0,0:11:14.66,0:11:17.87,Default,,0,0,0,,我们现在的讨论 还是从一个不严谨的角度进行的 Dialogue: 0,0:11:18.56,0:11:20.16,Default,,0,0,0,,当然 你们已经看到的是 Dialogue: 0,0:11:20.51,0:11:22.70,Default,,0,0,0,,当我做一些像赋值之类的事情时 Dialogue: 0,0:11:23.12,0:11:24.51,Default,,0,0,0,,我们所需要的模型 Dialogue: 0,0:11:24.51,0:11:26.89,Default,,0,0,0,,与我们之前模型不同 Dialogue: 0,0:11:26.89,0:11:30.93,Default,,0,0,0,,在这个的模型中 像COUNT或X这样的符号 Dialogue: 0,0:11:30.93,0:11:34.07,Default,,0,0,0,,不再关联于它们的值 Dialogue: 0,0:11:34.07,0:11:37.31,Default,,0,0,0,,而是关联于某个储存这些值的地方 Dialogue: 0,0:11:37.68,0:11:39.47,Default,,0,0,0,,我们将花些时间来适应这种思想 Dialogue: 0,0:11:40.20,0:11:42.11,Default,,0,0,0,,这将是一个很糟糕的事情 Dialogue: 0,0:11:42.11,0:11:43.47,Default,,0,0,0,,并且会造成很多麻烦 Dialogue: 0,0:11:44.49,0:11:48.25,Default,,0,0,0,,所以 就像我说的 若非理由周全 Dialogue: 0,0:11:48.25,0:11:50.09,Default,,0,0,0,,不然绝不要发明这种糟糕的东西 Dialogue: 0,0:11:50.37,0:11:52.86,Default,,0,0,0,,否则 就是劳神费力 Dialogue: 0,0:11:53.39,0:11:55.55,Default,,0,0,0,,让我们看看一些可以讨论的东西 Dialogue: 0,0:11:55.88,0:11:58.59,Default,,0,0,0,,假设我们写了函数式版本的阶乘函数 Dialogue: 0,0:11:58.59,0:12:00.48,Default,,0,0,0,,我们以前的就是“函数式”风格 Dialogue: 0,0:12:01.37,0:12:04.60,Default,,0,0,0,,具有迭代计算过程的阶乘函数 Dialogue: 0,0:12:09.59,0:12:13.28,Default,,0,0,0,,N的阶乘 Dialogue: 0,0:12:18.38,0:12:24.35,Default,,0,0,0,,我们要(ITER M I) Dialogue: 0,0:12:26.12,0:12:33.13,Default,,0,0,0,,就是说如果I大于N Dialogue: 0,0:12:33.77,0:12:35.51,Default,,0,0,0,,则结果是M Dialogue: 0,0:12:36.30,0:12:37.39,Default,,0,0,0,,否则 Dialogue: 0,0:12:39.79,0:12:46.82,Default,,0,0,0,,结果是(ITER (* I M)) Dialogue: 0,0:12:46.82,0:12:49.95,Default,,0,0,0,,所以M将是我累积的结果 Dialogue: 0,0:12:51.58,0:12:52.62,Default,,0,0,0,,M就是这个乘积[注:此处教授笔误] Dialogue: 0,0:12:57.97,0:13:00.17,Default,,0,0,0,,然后我要把COUNT加1 Dialogue: 0,0:13:04.62,0:13:10.97,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:13:11.95,0:13:13.04,Default,,0,0,0,,我在这里启动这个内部过程 Dialogue: 0,0:13:17.16,0:13:19.79,Default,,0,0,0,,对于这种代码 我想大家早已驾轻就熟了 Dialogue: 0,0:13:20.86,0:13:25.15,Default,,0,0,0,,这里是一个累积的乘积 和一个计数器 Dialogue: 0,0:13:26.48,0:13:28.46,Default,,0,0,0,,我让它们都从1开始 Dialogue: 0,0:13:28.89,0:13:30.92,Default,,0,0,0,,我将不断让计数器增加 Dialogue: 0,0:13:30.92,0:13:33.12,Default,,0,0,0,,每一轮I变成I+1 Dialogue: 0,0:13:34.56,0:13:37.47,Default,,0,0,0,,这是我们在这个过程中设置时间的唯一方法 Dialogue: 0,0:13:38.48,0:13:40.04,Default,,0,0,0,,这些都是一系列的事实 Dialogue: 0,0:13:40.49,0:13:41.34,Default,,0,0,0,,真实的规则 Dialogue: 0,0:13:42.81,0:13:46.13,Default,,0,0,0,,M将获得一个新的值 就是I乘M Dialogue: 0,0:13:46.13,0:13:47.82,Default,,0,0,0,,每一轮I乘以M Dialogue: 0,0:13:48.68,0:13:50.48,Default,,0,0,0,,最终I将大于N Dialogue: 0,0:13:50.49,0:13:52.06,Default,,0,0,0,,在这种情况下 结果就是M Dialogue: 0,0:13:52.67,0:13:54.80,Default,,0,0,0,,我给你们讲课的时候 用到了“时间”这个概念 Dialogue: 0,0:13:55.68,0:13:57.45,Default,,0,0,0,,那是因为我知道计算机是怎么工作的 Dialogue: 0,0:13:58.25,0:13:59.24,Default,,0,0,0,,但是我没必要这么做 Dialogue: 0,0:13:59.26,0:14:02.30,Default,,0,0,0,,这完全可以有一个纯数学的解释 Dialogue: 0,0:14:02.30,0:14:03.74,Default,,0,0,0,,因为在这里代换可以工作 Dialogue: 0,0:14:05.10,0:14:08.14,Default,,0,0,0,,但是我们写一个类似的程序 Dialogue: 0,0:14:08.30,0:14:09.95,Default,,0,0,0,,使用相同的算法 Dialogue: 0,0:14:10.73,0:14:12.11,Default,,0,0,0,,但使用了赋值 Dialogue: 0,0:14:15.69,0:14:17.16,Default,,0,0,0,,所以这个叫做函数式版本 Dialogue: 0,0:14:23.72,0:14:25.56,Default,,0,0,0,,我想写个命令式的版本的 Dialogue: 0,0:14:34.48,0:14:35.39,Default,,0,0,0,,N的阶乘 Dialogue: 0,0:14:35.92,0:14:37.74,Default,,0,0,0,,我要创建两个变量 Dialogue: 0,0:14:40.16,0:14:45.53,Default,,0,0,0,,把I的值初始化为1 Dialogue: 0,0:14:46.32,0:14:49.77,Default,,0,0,0,,M也初始化为1 Dialogue: 0,0:14:51.15,0:14:52.19,Default,,0,0,0,,我们创建一个循环 Dialogue: 0,0:14:59.31,0:15:07.27,Default,,0,0,0,,如果I比N大 循环结束 Dialogue: 0,0:15:07.27,0:15:08.87,Default,,0,0,0,,结果是M Dialogue: 0,0:15:08.87,0:15:10.38,Default,,0,0,0,,也就是我累积的乘积 Dialogue: 0,0:15:10.87,0:15:11.77,Default,,0,0,0,,否则 Dialogue: 0,0:15:15.52,0:15:17.40,Default,,0,0,0,,我接下来要做三件事 Dialogue: 0,0:15:19.26,0:15:27.05,Default,,0,0,0,,我要把M赋值为I*M Dialogue: 0,0:15:29.36,0:15:35.20,Default,,0,0,0,,把I赋值为I+1 Dialogue: 0,0:15:37.85,0:15:39.31,Default,,0,0,0,,然后继续循环 Dialogue: 0,0:15:40.41,0:15:43.02,Default,,0,0,0,,你们中的FORTRAN程序员应该觉得眼熟 Dialogue: 0,0:15:44.73,0:15:46.64,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:15:46.64,0:15:47.88,Default,,0,0,0,,就是这种语法有点陌生 Dialogue: 0,0:15:51.13,0:15:52.27,Default,,0,0,0,,启动循环 Dialogue: 0,0:15:56.10,0:15:57.56,Default,,0,0,0,,程序就写完了 Dialogue: 0,0:15:59.15,0:16:00.52,Default,,0,0,0,,那么 这个程序 Dialogue: 0,0:16:01.31,0:16:02.49,Default,,0,0,0,,我们应该怎么思考它呢? Dialogue: 0,0:16:02.71,0:16:04.25,Default,,0,0,0,,先来看看这里是什么 Dialogue: 0,0:16:04.84,0:16:07.47,Default,,0,0,0,,这里有两个局部变量 I和M Dialogue: 0,0:16:07.47,0:16:09.02,Default,,0,0,0,,它们都被初始化为1 Dialogue: 0,0:16:10.72,0:16:13.89,Default,,0,0,0,,在每一次循环里 我检测I是否大于N Dialogue: 0,0:16:13.89,0:16:15.08,Default,,0,0,0,,就是我们传入的参数 Dialogue: 0,0:16:15.30,0:16:18.14,Default,,0,0,0,,如果成立的话 结果就是M中所累积的乘积 Dialogue: 0,0:16:19.16,0:16:21.21,Default,,0,0,0,,然而 如果循环没有结束 Dialogue: 0,0:16:21.21,0:16:22.89,Default,,0,0,0,,如果我们的工作没有结束 Dialogue: 0,0:16:23.64,0:16:25.55,Default,,0,0,0,,则我们要把乘积 Dialogue: 0,0:16:25.84,0:16:28.38,Default,,0,0,0,,变为i与当前乘积的结果 Dialogue: 0,0:16:29.04,0:16:30.68,Default,,0,0,0,,就是我们在这里做过的事情 Dialogue: 0,0:16:31.42,0:16:32.68,Default,,0,0,0,,除了这里我没有改动 Dialogue: 0,0:16:33.63,0:16:35.77,Default,,0,0,0,,我创建了一个复本 Dialogue: 0,0:16:36.81,0:16:42.04,Default,,0,0,0,,因为代换模型就是你复制过程的体 Dialogue: 0,0:16:43.08,0:16:45.88,Default,,0,0,0,,并用实际参数代换形式参数 Dialogue: 0,0:16:46.72,0:16:48.42,Default,,0,0,0,,这里 我考虑的不是副本 Dialogue: 0,0:16:48.42,0:16:50.52,Default,,0,0,0,,在这里 我已经改变了M的值 Dialogue: 0,0:16:51.80,0:16:55.12,Default,,0,0,0,,我也把I的值变成了I+1 Dialogue: 0,0:16:55.61,0:16:56.96,Default,,0,0,0,,然后继续循环 Dialogue: 0,0:16:58.22,0:17:00.08,Default,,0,0,0,,看起来是一样的程序 Dialogue: 0,0:17:00.96,0:17:02.84,Default,,0,0,0,,在今天引入赋值之后 Dialogue: 0,0:17:02.84,0:17:05.50,Default,,0,0,0,,我们在这里有很多种方式犯错 Dialogue: 0,0:17:06.14,0:17:07.02,Default,,0,0,0,,例如 Dialogue: 0,0:17:07.45,0:17:09.40,Default,,0,0,0,,如果我在赋值的时候 Dialogue: 0,0:17:10.04,0:17:12.14,Default,,0,0,0,,没有小心地写程序 Dialogue: 0,0:17:12.64,0:17:16.08,Default,,0,0,0,,把两个赋值的顺序调换了 Dialogue: 0,0:17:17.10,0:17:18.91,Default,,0,0,0,,程序计算的就不是相同的函数了 Dialogue: 0,0:17:20.33,0:17:22.87,Default,,0,0,0,,我得到了一个时间错误 因为这儿有个依赖关系 Dialogue: 0,0:17:22.87,0:17:27.22,Default,,0,0,0,,因为M依赖于I上一次的值 Dialogue: 0,0:17:27.34,0:17:28.92,Default,,0,0,0,,如果我先改变I的值 Dialogue: 0,0:17:31.31,0:17:33.77,Default,,0,0,0,,就会在乘以M的时候 得到错误的I值 Dialogue: 0,0:17:35.96,0:17:38.38,Default,,0,0,0,,没有赋值的话不会存在这样的BUG Dialogue: 0,0:17:38.38,0:17:40.59,Default,,0,0,0,,这是由于我们引入了某些包含时间的东西造成的 Dialogue: 0,0:17:43.44,0:17:44.30,Default,,0,0,0,,如我所说的 Dialogue: 0,0:17:45.53,0:17:47.39,Default,,0,0,0,,首先 我们需要一个新的计算模型 Dialogue: 0,0:17:47.39,0:17:50.86,Default,,0,0,0,,然后 需要有一个非常好的理由来支持我们做如此丑陋的事 Dialogue: 0,0:17:52.72,0:17:53.74,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:17:58.83,0:18:00.22,Default,,0,0,0,,David 大点儿声说 Dialogue: 0,0:18:00.40,0:18:03.47,Default,,0,0,0,,学生:现在 我们引入了SET! Dialogue: 0,0:18:03.90,0:18:06.36,Default,,0,0,0,,但是之前我们已经有LET和DEFINE了 Dialogue: 0,0:18:06.89,0:18:09.70,Default,,0,0,0,,我不太清楚它们的区别 Dialogue: 0,0:18:09.70,0:18:13.25,Default,,0,0,0,,DEFINE不能像SET!一样用吗? Dialogue: 0,0:18:13.98,0:18:14.83,Default,,0,0,0,,请详细讲讲 Dialogue: 0,0:18:14.83,0:18:19.31,Default,,0,0,0,,教授:不 DEFINE用于创建并初始化 Dialogue: 0,0:18:19.31,0:18:21.36,Default,,0,0,0,,为了创建它 Dialogue: 0,0:18:22.08,0:18:24.70,Default,,0,0,0,,你永远也不会见到我在黑板上 Dialogue: 0,0:18:25.60,0:18:26.94,Default,,0,0,0,,在同一行写两个DEFINE Dialogue: 0,0:18:27.08,0:18:32.08,Default,,0,0,0,,只是为了让某个变量的旧值变成一个新的值 Dialogue: 0,0:18:32.08,0:18:34.51,Default,,0,0,0,,学生:这是一个约定俗成的规矩 还是-- Dialogue: 0,0:18:34.51,0:18:36.35,Default,,0,0,0,,教授:不 这是有意为之的 Dialogue: 0,0:18:36.35,0:18:38.92,Default,,0,0,0,,答案是 Dialogue: 0,0:18:39.69,0:18:40.84,Default,,0,0,0,,举个例子 Dialogue: 0,0:18:40.84,0:18:42.27,Default,,0,0,0,,在一个过程内部 Dialogue: 0,0:18:43.20,0:18:45.92,Default,,0,0,0,,两个DEFINE写在一行里是非法的 Dialogue: 0,0:18:46.68,0:18:48.57,Default,,0,0,0,,对于同一个变量DEFINE两次是非法的 Dialogue: 0,0:18:50.24,0:18:51.74,Default,,0,0,0,,X不能被DEFINE两次 Dialogue: 0,0:18:51.74,0:18:55.20,Default,,0,0,0,,而系统会不会捕获这个错误 就是另一个问题了 Dialogue: 0,0:18:55.93,0:18:57.88,Default,,0,0,0,,但是我定下规矩 Dialogue: 0,0:18:58.12,0:19:00.64,Default,,0,0,0,,任何东西都只能DEFINE一次 Dialogue: 0,0:19:00.73,0:19:02.64,Default,,0,0,0,,确实 在交互式调试中 Dialogue: 0,0:19:03.37,0:19:07.48,Default,,0,0,0,,我们打算让你与计算机交互时可以重新DEFINE一些东西 Dialogue: 0,0:19:08.19,0:19:11.21,Default,,0,0,0,,所以交互式调试时产生的是一个特殊的异常 Dialogue: 0,0:19:11.82,0:19:16.48,Default,,0,0,0,,但是DEFINE的意思是建立某些东西 Dialogue: 0,0:19:18.14,0:19:20.96,Default,,0,0,0,,在那个时间点后 它的值是永远不变的 Dialogue: 0,0:19:22.05,0:19:24.54,Default,,0,0,0,,好像所有的DEFINE都是在最开始完成的 Dialogue: 0,0:19:26.09,0:19:30.92,Default,,0,0,0,,事实上 在Scheme过程中 DEFINE的唯一合法使用地方 Dialogue: 0,0:19:31.02,0:19:33.36,Default,,0,0,0,,就是在LAMBDA表达式的开始 Dialogue: 0,0:19:34.47,0:19:37.66,Default,,0,0,0,,也就是过程体的开始 Dialogue: 0,0:19:40.40,0:19:45.80,Default,,0,0,0,,LET当然与那个不一样 Dialogue: 0,0:19:48.09,0:19:49.55,Default,,0,0,0,,如果你想知道LET发生了什么 Dialogue: 0,0:19:50.17,0:19:52.13,Default,,0,0,0,,LET只会绑定一次 Dialogue: 0,0:19:52.13,0:19:55.82,Default,,0,0,0,,它建立了一个I和M的值分别为1的上下文 Dialogue: 0,0:19:56.83,0:20:00.57,Default,,0,0,0,,这个上下文存在于整个作用域中 Dialogue: 0,0:20:01.31,0:20:02.80,Default,,0,0,0,,也就是这个程序范围 Dialogue: 0,0:20:04.99,0:20:10.12,Default,,0,0,0,,然而 你不会认为LET再次设置了I的值 Dialogue: 0,0:20:11.04,0:20:12.16,Default,,0,0,0,,它没有改变I的值 Dialogue: 0,0:20:12.16,0:20:14.01,Default,,0,0,0,,因为LET的作用 I将永远不会变化 Dialogue: 0,0:20:15.28,0:20:16.81,Default,,0,0,0,,因为LET的作用 I才被创建 Dialogue: 0,0:20:18.51,0:20:19.29,Default,,0,0,0,,实际上 Dialogue: 0,0:20:19.73,0:20:21.42,Default,,0,0,0,,LET是一个非常简单的想法 Dialogue: 0,0:20:22.24,0:20:23.59,Default,,0,0,0,,LET不会做别的事情 Dialogue: 0,0:20:23.59,0:20:31.62,Default,,0,0,0,,LET的语义是…… Dialogue: 0,0:20:31.62,0:20:33.50,Default,,0,0,0,,我把它写得更准确点 Dialogue: 0,0:20:37.16,0:20:43.73,Default,,0,0,0,,表达式 (var1 e1) Dialogue: 0,0:20:43.73,0:20:47.36,Default,,0,0,0,,还有(var2 e2) Dialogue: 0,0:20:48.14,0:20:49.74,Default,,0,0,0,,在表达式e3中 Dialogue: 0,0:20:51.60,0:21:05.80,Default,,0,0,0,,与一个以var1和var2为形式参数的过程一样 Dialogue: 0,0:21:06.94,0:21:08.96,Default,,0,0,0,,e3成为过程的体 Dialogue: 0,0:21:10.91,0:21:14.00,Default,,0,0,0,,在这里 var1与e1的值绑定 Dialogue: 0,0:21:14.27,0:21:16.91,Default,,0,0,0,,var2与e2的值绑定 Dialogue: 0,0:21:19.53,0:21:23.26,Default,,0,0,0,,所以实际上 这是一个从代换的角度来看很容易理解的东西 Dialogue: 0,0:21:24.89,0:21:27.95,Default,,0,0,0,,其实就是同一个表达式的两种不同的写法 Dialogue: 0,0:21:31.69,0:21:33.50,Default,,0,0,0,,事实上 系统真正的工作方式 Dialogue: 0,0:21:33.63,0:21:35.82,Default,,0,0,0,,就是在运行之前把代码翻译成这种形式 Dialogue: 0,0:21:37.64,0:21:41.77,Default,,0,0,0,,学生:我还是不清楚是什么造成了LET和DEFINE之间的区别 Dialogue: 0,0:21:41.77,0:21:44.30,Default,,0,0,0,,教授:DEFINE就是个语法糖 Dialogue: 0,0:21:44.62,0:21:49.10,Default,,0,0,0,,本质上来说 是通过LET创建一系列变量 然后给它们一次性赋值 Dialogue: 0,0:21:57.10,0:21:59.74,Default,,0,0,0,,好吧 我们休息一会 Dialogue: 0,0:22:02.52,0:22:12.84,Default,,0,0,0,,[音乐] Dialogue: 0,0:22:12.84,0:22:17.84,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:22:48.81,0:22:52.67,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:22:52.67,0:22:56.52,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:22:56.52,0:23:00.59,Declare,,0,0,0,,{\an2\fad(500,500)}赋值、状态和副作用 Dialogue: 0,0:23:04.28,0:23:06.11,Default,,0,0,0,,看 Dialogue: 0,0:23:06.44,0:23:09.08,Default,,0,0,0,,现在 我不得不重建计算模型 Dialogue: 0,0:23:09.77,0:23:14.16,Default,,0,0,0,,使得你能够明白那些机制是如何运作的 Dialogue: 0,0:23:14.91,0:23:16.46,Default,,0,0,0,,来完成我们刚才说的那些工作 Dialogue: 0,0:23:17.53,0:23:21.39,Default,,0,0,0,,我刚刚摧毁了你们的代换模型 Dialogue: 0,0:23:22.62,0:23:26.03,Default,,0,0,0,,不幸的是 这个模型比代换模型要复杂得多 Dialogue: 0,0:23:26.62,0:23:27.93,Default,,0,0,0,,这个模型叫环境模型 Dialogue: 0,0:23:29.02,0:23:31.20,Default,,0,0,0,,我即将介绍一些术语 Dialogue: 0,0:23:32.03,0:23:34.51,Default,,0,0,0,,无论如何 你知道这些术语都是很好的 Dialogue: 0,0:23:34.51,0:23:35.74,Default,,0,0,0,,它是关于名字的 Dialogue: 0,0:23:36.51,0:23:39.63,Default,,0,0,0,,我们要给事物的各种名字 Dialogue: 0,0:23:40.00,0:23:41.31,Default,,0,0,0,,和名字的使用途径以名字 Dialogue: 0,0:23:42.48,0:23:47.94,Default,,0,0,0,,如果硬要说的话 这是一个元描述 Dialogue: 0,0:23:48.56,0:23:50.85,Default,,0,0,0,,总之 这里面有一堆糟糕的术语 Dialogue: 0,0:23:50.85,0:23:53.76,Default,,0,0,0,,但我们需要利用它们来理解所谓的“环境模型” Dialogue: 0,0:23:54.70,0:23:57.53,Default,,0,0,0,,我们可能要做一点无聊的事情了 Dialogue: 0,0:23:58.04,0:24:01.58,Default,,0,0,0,,我们来看第一张张幻灯片 Dialogue: 0,0:24:02.25,0:24:06.97,Default,,0,0,0,,我们看到了术语“约束”的解释 Dialogue: 0,0:24:08.80,0:24:11.00,Default,,0,0,0,,我们会说一个变量V Dialogue: 0,0:24:11.00,0:24:12.91,Default,,0,0,0,,被约束在表达式E中 Dialogue: 0,0:24:13.41,0:24:21.52,Default,,0,0,0,,如果用一个没有出现在E中的变量W 对变量V统一换名 Dialogue: 0,0:24:21.56,0:24:24.28,Default,,0,0,0,,表达式语义没有发生改变 Dialogue: 0,0:24:25.69,0:24:27.00,Default,,0,0,0,,这个解释很长 Dialogue: 0,0:24:27.37,0:24:29.96,Default,,0,0,0,,在我们在被搞糊涂之前 Dialogue: 0,0:24:29.98,0:24:32.62,Default,,0,0,0,,我应该再多解释下 Dialogue: 0,0:24:33.42,0:24:35.28,Default,,0,0,0,,我们这里讨论的约束变量 Dialogue: 0,0:24:44.16,0:24:45.56,Default,,0,0,0,,你们已经看到它们很多次了 Dialogue: 0,0:24:46.07,0:24:48.17,Default,,0,0,0,,只是你们可能还没意识到 Dialogue: 0,0:24:48.24,0:24:52.24,Default,,0,0,0,,在逻辑学中 你们看到一个逻辑变量 Dialogue: 0,0:24:53.27,0:25:00.11,Default,,0,0,0,,就像微积分课上的 对于任意任何X 存在一个Y 使得P为真 Dialogue: 0,0:25:02.88,0:25:05.82,Default,,0,0,0,,这个变量X 这个变量Y 它们是约束变量 Dialogue: 0,0:25:07.08,0:25:07.92,Default,,0,0,0,,因为 Dialogue: 0,0:25:08.33,0:25:09.98,Default,,0,0,0,,这个表达式的含义 Dialogue: 0,0:25:09.98,0:25:15.61,Default,,0,0,0,,不取决于我用来描述X和Y的具体字母 Dialogue: 0,0:25:16.49,0:25:19.18,Default,,0,0,0,,如果我用W替换X Dialogue: 0,0:25:19.84,0:25:25.68,Default,,0,0,0,,则可以说对于任意W 存在一个Y使得P为真 Dialogue: 0,0:25:25.98,0:25:27.08,Default,,0,0,0,,它们其实是同一句话 Dialogue: 0,0:25:29.44,0:25:30.34,Default,,0,0,0,,就是这个意思 Dialogue: 0,0:25:30.34,0:25:34.89,Default,,0,0,0,,又或者说 你们看到这样一个积分 Dialogue: 0,0:25:35.40,0:25:42.65,Default,,0,0,0,,对dx/(1+x^2)从0到1积分 Dialogue: 0,0:25:46.03,0:25:47.92,Default,,0,0,0,,这就是你们经常见到的那种东西 Dialogue: 0,0:25:47.92,0:25:50.92,Default,,0,0,0,,这个x是一个约束变量 Dialogue: 0,0:25:52.06,0:25:53.79,Default,,0,0,0,,如果我把它换成t Dialogue: 0,0:25:54.15,0:25:56.25,Default,,0,0,0,,这个表达式其实没有变化 Dialogue: 0,0:25:58.06,0:26:02.76,Default,,0,0,0,,就是arctan(1)/4之类的 Dialogue: 0,0:26:04.70,0:26:06.01,Default,,0,0,0,,是的 就是arctan(1) Dialogue: 0,0:26:06.62,0:26:08.76,Default,,0,0,0,,所以约束变量事实上很常见 Dialogue: 0,0:26:09.08,0:26:12.36,Default,,0,0,0,,如果你们接触过一些数学的话 Dialogue: 0,0:26:13.26,0:26:17.47,Default,,0,0,0,,好 让我们来到编程的世界 Dialogue: 0,0:26:19.02,0:26:21.36,Default,,0,0,0,,现在量词不再是 Dialogue: 0,0:26:22.03,0:26:24.06,Default,,0,0,0,,所有、存在和积分 Dialogue: 0,0:26:24.06,0:26:26.43,Default,,0,0,0,,我们有一个符号作为量词 用于约束变量 Dialogue: 0,0:26:27.47,0:26:28.99,Default,,0,0,0,,我们要使用量词LAMBDA Dialogue: 0,0:26:29.79,0:26:31.80,Default,,0,0,0,,作为约束变量的一个必要的东西 Dialogue: 0,0:26:33.80,0:26:36.12,Default,,0,0,0,,我们有一个极好的例子 Dialogue: 0,0:26:36.59,0:26:44.14,Default,,0,0,0,,对于以Y为参数的过程 做了以下的事情 Dialogue: 0,0:26:44.14,0:26:46.96,Default,,0,0,0,,它调用一个含单个参数X的过程 Dialogue: 0,0:26:47.87,0:26:51.13,Default,,0,0,0,,该过程 将X乘以Y Dialogue: 0,0:26:52.88,0:26:54.52,Default,,0,0,0,,并应用于3 Dialogue: 0,0:26:58.76,0:27:01.66,Default,,0,0,0,,这个过程中包含两个约束变量 Dialogue: 0,0:27:02.01,0:27:02.92,Default,,0,0,0,,X和Y Dialogue: 0,0:27:04.83,0:27:07.47,Default,,0,0,0,,这个LAMBDA量词 约束了这个Y Dialogue: 0,0:27:07.91,0:27:10.78,Default,,0,0,0,,这个LAMBDA量词 约束了这个X Dialogue: 0,0:27:12.11,0:27:17.05,Default,,0,0,0,,因为 如果我用了一个没有出现在表达式中的任意符号 如W Dialogue: 0,0:27:17.98,0:27:21.04,Default,,0,0,0,,用W替换表达式中的所有Y Dialogue: 0,0:27:21.36,0:27:22.75,Default,,0,0,0,,这个表达式仍与原来的相同 Dialogue: 0,0:27:23.66,0:27:24.80,Default,,0,0,0,,是相同的过程 Dialogue: 0,0:27:26.22,0:27:27.41,Default,,0,0,0,,这是一个重要的想法 Dialogue: 0,0:27:27.41,0:27:29.64,Default,,0,0,0,,我们有这种东西的原因 Dialogue: 0,0:27:30.20,0:27:31.41,Default,,0,0,0,,这是一种模块性 Dialogue: 0,0:27:31.41,0:27:32.86,Default,,0,0,0,,如果有两个人写程序 Dialogue: 0,0:27:34.03,0:27:35.26,Default,,0,0,0,,并且他们在合作编程 Dialogue: 0,0:27:35.26,0:27:40.56,Default,,0,0,0,,在他们自己构建的小项目里用什么命名都没有关系 Dialogue: 0,0:27:42.83,0:27:44.67,Default,,0,0,0,,所以 实际上我想告诉你们 Dialogue: 0,0:27:45.44,0:27:46.75,Default,,0,0,0,,例如 Dialogue: 0,0:27:46.84,0:27:51.26,Default,,0,0,0,,这个表达式等于 以Y为参数的过程 Dialogue: 0,0:27:52.35,0:27:59.23,Default,,0,0,0,,使用这个对于一个参数Z的过程 这个过程将Z乘以Y Dialogue: 0,0:28:01.64,0:28:03.53,Default,,0,0,0,,因为没人关心我在这用什么 Dialogue: 0,0:28:06.36,0:28:07.24,Default,,0,0,0,,这是一个极好的例子 Dialogue: 0,0:28:08.84,0:28:09.85,Default,,0,0,0,,另一方面 Dialogue: 0,0:28:11.07,0:28:14.33,Default,,0,0,0,,我有一些未被约束的变量 Dialogue: 0,0:28:15.23,0:28:15.96,Default,,0,0,0,,举个例子 Dialogue: 0,0:28:20.27,0:28:21.76,Default,,0,0,0,,这个对于一个以X为参数的过程 Dialogue: 0,0:28:22.09,0:28:25.04,Default,,0,0,0,,将X乘以Y Dialogue: 0,0:28:27.28,0:28:28.16,Default,,0,0,0,,在这个例子中 Dialogue: 0,0:28:29.45,0:28:30.75,Default,,0,0,0,,y没有被约束 Dialogue: 0,0:28:32.46,0:28:34.27,Default,,0,0,0,,假设Y的值是3 Dialogue: 0,0:28:35.26,0:28:36.80,Default,,0,0,0,,Z的值是4 Dialogue: 0,0:28:38.83,0:28:44.27,Default,,0,0,0,,那么这个过程就是把它的参数乘以3 Dialogue: 0,0:28:44.86,0:28:47.39,Default,,0,0,0,,如果我把所有的y都用z来代替 Dialogue: 0,0:28:47.52,0:28:51.96,Default,,0,0,0,,我将得到一个完全不同的过程 它会把参数乘以4 Dialogue: 0,0:28:53.87,0:28:56.40,Default,,0,0,0,,事实上 我们给这类变量取了个名字 Dialogue: 0,0:28:57.76,0:29:04.01,Default,,0,0,0,,我们把表达式E中的变量V叫做自由变量 Dialogue: 0,0:29:04.01,0:29:09.42,Default,,0,0,0,,如果用没有出现在E中的变量W统一替换E中所有的V Dialogue: 0,0:29:09.58,0:29:11.15,Default,,0,0,0,,使得表达式E的含义发生了改变 Dialogue: 0,0:29:13.26,0:29:13.71,Default,,0,0,0,,所以 Dialogue: 0,0:29:14.49,0:29:22.76,Default,,0,0,0,,所以这就是为什么这个变量Y 是一个自由变量 Dialogue: 0,0:29:29.16,0:29:32.27,Default,,0,0,0,,所以 这个表达式里的自由变量 Dialogue: 0,0:29:33.76,0:29:35.18,Default,,0,0,0,,另一个例子是 Dialogue: 0,0:29:36.17,0:29:39.32,Default,,0,0,0,,对于一个以Y为参数的过程 Dialogue: 0,0:29:40.43,0:29:42.00,Default,,0,0,0,,就像我们之前的那个一样 Dialogue: 0,0:29:42.27,0:29:44.60,Default,,0,0,0,,调用以X为参数的过程 Dialogue: 0,0:29:45.08,0:29:48.54,Default,,0,0,0,,将X与Y相乘-- Dialogue: 0,0:29:51.40,0:29:52.65,Default,,0,0,0,,并应用于3 Dialogue: 0,0:29:57.24,0:30:00.35,Default,,0,0,0,,这个过程中有一个自由变量 Dialogue: 0,0:30:00.92,0:30:01.98,Default,,0,0,0,,也就是这个星号 Dialogue: 0,0:30:05.00,0:30:05.89,Default,,0,0,0,,因为 Dialogue: 0,0:30:05.89,0:30:08.08,Default,,0,0,0,,如果它表示正常意义的乘法 Dialogue: 0,0:30:09.44,0:30:12.78,Default,,0,0,0,,如果我统一地用加号来代替星号 Dialogue: 0,0:30:14.25,0:30:16.38,Default,,0,0,0,,这个表达式的含义就变了 Dialogue: 0,0:30:19.34,0:30:20.76,Default,,0,0,0,,这就是自由变量的意思 Dialogue: 0,0:30:22.68,0:30:24.81,Default,,0,0,0,,现在 你们已经学到了一些逻辑学术语 Dialogue: 0,0:30:25.64,0:30:27.58,Default,,0,0,0,,用它们可以解释名字的用法 Dialogue: 0,0:30:28.94,0:30:31.26,Default,,0,0,0,,我们要需要更进一步深入 Dialogue: 0,0:30:32.96,0:30:33.72,Default,,0,0,0,,再多了解一些 Dialogue: 0,0:30:35.13,0:30:36.22,Default,,0,0,0,,我想给你们讲讲 Dialogue: 0,0:30:36.81,0:30:39.76,Default,,0,0,0,,变量被定义的区域 Dialogue: 0,0:30:42.17,0:30:42.88,Default,,0,0,0,,你瞧 Dialogue: 0,0:30:43.37,0:30:45.69,Default,,0,0,0,,目前为止 我们已经相当不正式了 Dialogue: 0,0:30:46.33,0:30:50.16,Default,,0,0,0,,当然 你们中的一些 或者大部分人可能已经理解得很透彻了 Dialogue: 0,0:30:50.36,0:30:52.84,Default,,0,0,0,,在这里被声明的X Dialogue: 0,0:30:53.64,0:30:55.18,Default,,0,0,0,,只被定义在这里 Dialogue: 0,0:30:58.28,0:31:00.91,Default,,0,0,0,,这个X 只被定义在这里 Dialogue: 0,0:31:01.61,0:31:04.33,Default,,0,0,0,,这个Y 只被定义在这里 Dialogue: 0,0:31:07.10,0:31:09.16,Default,,0,0,0,,我们给这个概念取了个名字 叫“作用域” Dialogue: 0,0:31:11.61,0:31:13.58,Default,,0,0,0,,我给你们再讲个术语 Dialogue: 0,0:31:14.70,0:31:15.77,Default,,0,0,0,,这个就比较复杂 Dialogue: 0,0:31:15.96,0:31:17.64,Default,,0,0,0,,如果X是E中的一个约束变量 Dialogue: 0,0:31:18.16,0:31:20.24,Default,,0,0,0,,那么它是约束于一个LAMBDA表达式中 Dialogue: 0,0:31:20.89,0:31:24.91,Default,,0,0,0,,LAMBDA表达式是约束变量的唯一方式 Dialogue: 0,0:31:24.91,0:31:25.96,Default,,0,0,0,,你可能会担心 Dialogue: 0,0:31:26.22,0:31:29.05,Default,,0,0,0,,DEFINE是它的一个例外吗? Dialogue: 0,0:31:29.64,0:31:32.92,Default,,0,0,0,,事实证明 通过巧妙安排 我们可以避免使用DEFINE Dialogue: 0,0:31:32.92,0:31:33.96,Default,,0,0,0,,一会我们就能看到了 Dialogue: 0,0:31:34.24,0:31:35.72,Default,,0,0,0,,它一个非常神奇的东西 Dialogue: 0,0:31:36.54,0:31:38.40,Default,,0,0,0,,所以我们完全不需要DEFINE Dialogue: 0,0:31:38.68,0:31:41.55,Default,,0,0,0,,实际上 唯一能创建名字的东西是LAMBDA Dialogue: 0,0:31:42.64,0:31:43.40,Default,,0,0,0,,这就是它的职责 Dialogue: 0,0:31:44.30,0:31:46.23,Default,,0,0,0,,多么的令人惊奇 Dialogue: 0,0:31:46.23,0:31:47.87,Default,,0,0,0,,很多东西你只凭借LAMBDA就可以计算 Dialogue: 0,0:31:48.73,0:31:49.58,Default,,0,0,0,,但是 在任何情况下 Dialogue: 0,0:31:51.74,0:31:55.76,Default,,0,0,0,,一个LAMBDA表达式有一个地方来声明变量 Dialogue: 0,0:31:55.76,0:31:57.10,Default,,0,0,0,,我们把它称为形式参数表 Dialogue: 0,0:31:58.94,0:32:00.56,Default,,0,0,0,,或者叫 约束变量表 Dialogue: 0,0:32:01.26,0:32:04.51,Default,,0,0,0,,我们说LAMBDA表达式约束了--这是一个动词 Dialogue: 0,0:32:05.02,0:32:07.34,Default,,0,0,0,,--约束了在约束变量表里声明的变量 Dialogue: 0,0:32:08.59,0:32:12.48,Default,,0,0,0,,另外 表达式中定义变量的那些部分 Dialogue: 0,0:32:13.23,0:32:15.23,Default,,0,0,0,,是被一些声明所声明的 Dialogue: 0,0:32:15.56,0:32:19.26,Default,,0,0,0,,这些部分被叫做变量的作用域 Dialogue: 0,0:32:20.44,0:32:21.92,Default,,0,0,0,,所以 这些是作用域 Dialogue: 0,0:32:22.25,0:32:23.68,Default,,0,0,0,,这是Y的作用域 Dialogue: 0,0:32:27.16,0:32:28.54,Default,,0,0,0,,这是X的作用域-- Dialogue: 0,0:32:33.10,0:32:34.03,Default,,0,0,0,,以此类推 Dialogue: 0,0:32:41.32,0:32:42.08,Default,,0,0,0,,好 Dialogue: 0,0:32:43.93,0:32:45.63,Default,,0,0,0,,现在我们有了足够多的术语 Dialogue: 0,0:32:46.60,0:32:51.76,Default,,0,0,0,,可以开始理解如何建立一个新的计算模型了 Dialogue: 0,0:32:51.96,0:32:53.77,Default,,0,0,0,,因为 这里很重要的一点是 Dialogue: 0,0:32:54.94,0:32:57.00,Default,,0,0,0,,我们摧毁了代换模型 Dialogue: 0,0:32:57.18,0:32:58.38,Default,,0,0,0,,我们现在不得不需要一个模型 Dialogue: 0,0:32:58.62,0:33:02.32,Default,,0,0,0,,来体现表示名字被关联到某些地方 Dialogue: 0,0:33:03.93,0:33:05.34,Default,,0,0,0,,因为 如果我们要改变某个东西 Dialogue: 0,0:33:05.98,0:33:07.47,Default,,0,0,0,,我们就需要一个存它的地方 Dialogue: 0,0:33:09.56,0:33:10.35,Default,,0,0,0,,请想一想 Dialogue: 0,0:33:10.83,0:33:13.31,Default,,0,0,0,,如果一个名字只是关联于一个值 Dialogue: 0,0:33:14.04,0:33:16.36,Default,,0,0,0,,如果我试图改变这个名字的含义 Dialogue: 0,0:33:16.73,0:33:20.32,Default,,0,0,0,,这不怎么明确 Dialogue: 0,0:33:20.32,0:33:24.68,Default,,0,0,0,,因为没有名字可以关联的地方 Dialogue: 0,0:33:24.99,0:33:25.80,Default,,0,0,0,,该怎么解释呢…… Dialogue: 0,0:33:25.92,0:33:29.54,Default,,0,0,0,,也就是名字的所有实例之间没有共享任何东西 Dialogue: 0,0:33:29.87,0:33:31.68,Default,,0,0,0,,也就是说 对于一个名字 Dialogue: 0,0:33:31.68,0:33:32.97,Default,,0,0,0,,是用来让我们找到某些东西的 Dialogue: 0,0:33:34.33,0:33:36.36,Default,,0,0,0,,我们把名字给某个东西 然后你拿到了它 Dialogue: 0,0:33:36.73,0:33:39.06,Default,,0,0,0,,你能得到它 是因为我给了你一个它的引用 Dialogue: 0,0:33:39.06,0:33:40.44,Default,,0,0,0,,我把对它的引用给了你 Dialogue: 0,0:33:41.02,0:33:42.30,Default,,0,0,0,,我们会看到很多相关的例子 Dialogue: 0,0:33:43.61,0:33:45.21,Default,,0,0,0,,让我们继续学习“环境” Dialogue: 0,0:33:46.19,0:33:48.76,Default,,0,0,0,,我需要用一下头顶上的投影仪 Dialogue: 0,0:33:49.31,0:33:49.98,Default,,0,0,0,,谢谢你 Dialogue: 0,0:33:52.19,0:33:53.02,Default,,0,0,0,,这里 Dialogue: 0,0:33:55.48,0:34:00.40,Default,,0,0,0,,是一堆环境结构 Dialogue: 0,0:34:01.53,0:34:05.76,Default,,0,0,0,,环境就是执行虚拟的代换的一种方法 Dialogue: 0,0:34:06.38,0:34:07.89,Default,,0,0,0,,它代表了一个地方 Dialogue: 0,0:34:07.89,0:34:11.39,Default,,0,0,0,,是存储你的未完成的代换的地方 Dialogue: 0,0:34:13.34,0:34:16.50,Default,,0,0,0,,它是一个积累各种东西的地方 Dialogue: 0,0:34:16.50,0:34:21.13,Default,,0,0,0,,在那里 变量的名字与值关联在一起 Dialogue: 0,0:34:21.79,0:34:22.56,Default,,0,0,0,,使得 Dialogue: 0,0:34:22.75,0:34:25.90,Default,,0,0,0,,当你问某个名字是什么意思的时候 Dialogue: 0,0:34:25.90,0:34:27.40,Default,,0,0,0,,你要在一个环境中寻找答案 Dialogue: 0,0:34:28.08,0:34:29.48,Default,,0,0,0,,所以环境是一个函数 Dialogue: 0,0:34:30.80,0:34:31.48,Default,,0,0,0,,或一张表 Dialogue: 0,0:34:32.22,0:34:33.24,Default,,0,0,0,,或类似的东西 Dialogue: 0,0:34:33.24,0:34:34.89,Default,,0,0,0,,但它是一种结构化的表 Dialogue: 0,0:34:35.76,0:34:37.39,Default,,0,0,0,,它是由框架构成 Dialogue: 0,0:34:41.13,0:34:44.46,Default,,0,0,0,,框架是环境的一部分 Dialogue: 0,0:34:44.89,0:34:46.01,Default,,0,0,0,,它们被链接在一起 Dialogue: 0,0:34:47.07,0:34:48.19,Default,,0,0,0,,以某种很好的方式 Dialogue: 0,0:34:49.00,0:34:52.09,Default,,0,0,0,,用一种叫做父链接之类的东西 Dialogue: 0,0:34:54.03,0:34:55.02,Default,,0,0,0,,这里 Dialogue: 0,0:34:55.64,0:34:57.62,Default,,0,0,0,,有一个环境结构 Dialogue: 0,0:34:57.62,0:35:04.22,Default,,0,0,0,,它由三个环境组成 分别是A B和C Dialogue: 0,0:35:05.10,0:35:07.63,Default,,0,0,0,,D也是环境 但它和C是一样的 Dialogue: 0,0:35:08.88,0:35:10.17,Default,,0,0,0,,它们共享了同一个环境 Dialogue: 0,0:35:11.45,0:35:13.96,Default,,0,0,0,,那就是赋值的本质所在 Dialogue: 0,0:35:14.40,0:35:16.10,Default,,0,0,0,,如果我改变了一个变量 Dialogue: 0,0:35:16.10,0:35:19.80,Default,,0,0,0,,比如改变这个变量的值 Dialogue: 0,0:35:19.80,0:35:23.50,Default,,0,0,0,,那么它将在所有地方都可见 Dialogue: 0,0:35:23.50,0:35:24.84,Default,,0,0,0,,用x来举例 Dialogue: 0,0:35:24.84,0:35:28.19,Default,,0,0,0,,如果我将X改为4 Dialogue: 0,0:35:28.19,0:35:30.19,Default,,0,0,0,,在其他地方也是可见的 Dialogue: 0,0:35:30.19,0:35:32.19,Default,,0,0,0,,但是我们现在不去关心这个 Dialogue: 0,0:35:32.19,0:35:33.84,Default,,0,0,0,,过一会儿会详细讨论这个问题 Dialogue: 0,0:35:34.56,0:35:35.53,Default,,0,0,0,,这里有什么? Dialogue: 0,0:35:36.76,0:35:38.84,Default,,0,0,0,,这些叫做框架 这是一个框架 Dialogue: 0,0:35:39.40,0:35:40.38,Default,,0,0,0,,这是一个框架 Dialogue: 0,0:35:40.76,0:35:41.84,Default,,0,0,0,,这也是一个框架 Dialogue: 0,0:35:43.18,0:35:45.20,Default,,0,0,0,,A是一个环境 Dialogue: 0,0:35:45.20,0:35:47.82,Default,,0,0,0,,它由框架II Dialogue: 0,0:35:48.36,0:35:51.05,Default,,0,0,0,,和框架I组成 Dialogue: 0,0:35:52.52,0:35:54.60,Default,,0,0,0,,在这个环境中 Dialogue: 0,0:35:54.99,0:35:59.68,Default,,0,0,0,,在环境C中 在框架II中 Dialogue: 0,0:36:00.48,0:36:03.26,Default,,0,0,0,,X和Y是被约束的 Dialogue: 0,0:36:04.06,0:36:04.78,Default,,0,0,0,,它们具有值 Dialogue: 0,0:36:05.26,0:36:07.18,Default,,0,0,0,,对不起 是在框架I中 Dialogue: 0,0:36:07.18,0:36:08.28,Default,,0,0,0,,而在框架II中 Dialogue: 0,0:36:09.72,0:36:10.83,Default,,0,0,0,,Z被约束 Dialogue: 0,0:36:10.99,0:36:12.17,Default,,0,0,0,,X被约束 Dialogue: 0,0:36:12.44,0:36:13.69,Default,,0,0,0,,并且Y也是被约束的 Dialogue: 0,0:36:15.24,0:36:17.40,Default,,0,0,0,,但是我们看到的X的值 Dialogue: 0,0:36:17.42,0:36:19.04,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:36:20.01,0:36:21.74,Default,,0,0,0,,是这个X 它的值是7 Dialogue: 0,0:36:22.36,0:36:24.84,Default,,0,0,0,,而不是这个值为3的X Dialogue: 0,0:36:24.84,0:36:27.61,Default,,0,0,0,,我们称之为 这个X遮蔽了这个X Dialogue: 0,0:36:31.05,0:36:32.49,Default,,0,0,0,,从环境III Dialogue: 0,0:36:33.44,0:36:34.45,Default,,0,0,0,,从框架III Dialogue: 0,0:36:34.45,0:36:35.73,Default,,0,0,0,,从环境B Dialogue: 0,0:36:35.73,0:36:37.18,Default,,0,0,0,,它引用了框架III Dialogue: 0,0:36:37.45,0:36:42.12,Default,,0,0,0,,变量M和Y被约束 X也被约束 Dialogue: 0,0:36:44.84,0:36:46.97,Default,,0,0,0,,这个Y遮蔽了这个Y Dialogue: 0,0:36:48.65,0:36:51.00,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:36:51.10,0:36:52.65,Default,,0,0,0,,Y的值是2 Dialogue: 0,0:36:53.45,0:36:55.28,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:36:55.28,0:36:58.64,Default,,0,0,0,,M的值是1 X的值是3 Dialogue: 0,0:37:02.22,0:37:03.15,Default,,0,0,0,,所以 我们有了一个 Dialogue: 0,0:37:03.15,0:37:05.52,Default,,0,0,0,,由框架构成的非常简单的环境结构 Dialogue: 0,0:37:06.38,0:37:09.80,Default,,0,0,0,,它们与过程的应用相一致 Dialogue: 0,0:37:10.94,0:37:12.17,Default,,0,0,0,,我们马上就会看到 Dialogue: 0,0:37:14.41,0:37:17.60,Default,,0,0,0,,现在要给你们看看我们构建的一些其他的很好的小结构 Dialogue: 0,0:37:20.75,0:37:21.71,Default,,0,0,0,,下一张幻灯片 Dialogue: 0,0:37:22.14,0:37:24.36,Default,,0,0,0,,我们可以看到一个对象 Dialogue: 0,0:37:24.84,0:37:26.54,Default,,0,0,0,,我描绘的是一个过程的图像 Dialogue: 0,0:37:27.93,0:37:28.94,Default,,0,0,0,,这是一个过程 Dialogue: 0,0:37:30.11,0:37:31.90,Default,,0,0,0,,过程由两个部分组成 Dialogue: 0,0:37:33.10,0:37:34.80,Default,,0,0,0,,这有点像CONS Dialogue: 0,0:37:37.21,0:37:38.38,Default,,0,0,0,,不管怎样 它有两个部分 Dialogue: 0,0:37:40.84,0:37:44.72,Default,,0,0,0,,第一个部分指向一些代码 Dialogue: 0,0:37:45.69,0:37:46.94,Default,,0,0,0,,这些代码将会被执行 Dialogue: 0,0:37:47.42,0:37:50.00,Default,,0,0,0,,你可以把它视作一组指令 Dialogue: 0,0:37:50.68,0:37:52.83,Default,,0,0,0,,第二部分是环境 Dialogue: 0,0:37:53.88,0:37:55.50,Default,,0,0,0,,这就是过程的全部了 Dialogue: 0,0:37:57.16,0:37:58.40,Default,,0,0,0,,我们要用它 Dialogue: 0,0:37:58.71,0:38:05.16,Default,,0,0,0,,来捕获出现在过程中的自由变量的值 Dialogue: 0,0:38:06.17,0:38:08.09,Default,,0,0,0,,如果变量出现在过程中 Dialogue: 0,0:38:08.11,0:38:09.92,Default,,0,0,0,,它不是被约束的就是自由的 Dialogue: 0,0:38:11.10,0:38:11.96,Default,,0,0,0,,如果它是被约束的 Dialogue: 0,0:38:12.57,0:38:14.56,Default,,0,0,0,,则它的值将很容易被找到 Dialogue: 0,0:38:16.11,0:38:18.64,Default,,0,0,0,,它将存在于某个很容易找到的环境中 Dialogue: 0,0:38:18.91,0:38:19.87,Default,,0,0,0,,如果它是自由的 Dialogue: 0,0:38:20.86,0:38:23.02,Default,,0,0,0,,我们就必须在过程中放入一些东西 Dialogue: 0,0:38:23.02,0:38:24.81,Default,,0,0,0,,用来指导我们查询自由变量的值 Dialogue: 0,0:38:27.05,0:38:29.21,Default,,0,0,0,,相关理由目前还不清楚 Dialogue: 0,0:38:29.21,0:38:30.60,Default,,0,0,0,,但很快就要真相大白了 Dialogue: 0,0:38:32.32,0:38:34.97,Default,,0,0,0,,这里有一个对象 它是个复合对象 Dialogue: 0,0:38:35.34,0:38:41.64,Default,,0,0,0,,由一些代码和一个环境结构组成 Dialogue: 0,0:38:42.72,0:38:45.50,Default,,0,0,0,,现在我要告诉你们一些全新的规则 Dialogue: 0,0:38:46.41,0:38:47.47,Default,,0,0,0,,关于执行的规则 Dialogue: 0,0:38:50.54,0:38:52.20,Default,,0,0,0,,仅有的两条规则的第一条是-- Dialogue: 0,0:38:53.20,0:38:55.39,Default,,0,0,0,,这些规则与代换模型规则相对应 Dialogue: 0,0:38:57.26,0:38:59.32,Default,,0,0,0,,第一条规则是用来解决 Dialogue: 0,0:38:59.66,0:39:02.78,Default,,0,0,0,,如何把一个过程 应用到参数上的问题 Dialogue: 0,0:39:05.28,0:39:08.54,Default,,0,0,0,,程序对象被应用于一组参数 Dialogue: 0,0:39:08.96,0:39:10.43,Default,,0,0,0,,是通过构建一个新的框架来完成 Dialogue: 0,0:39:11.31,0:39:15.76,Default,,0,0,0,,那个框架将包含形式参数 Dialogue: 0,0:39:15.83,0:39:19.48,Default,,0,0,0,,到调用中使用的实际参数的映射 Dialogue: 0,0:39:21.42,0:39:22.20,Default,,0,0,0,,如你所知 Dialogue: 0,0:39:22.31,0:39:26.94,Default,,0,0,0,,当我们调用一个过程 如(LAMBDA (X) (* X Y)) Dialogue: 0,0:39:26.94,0:39:29.13,Default,,0,0,0,,然后我们以3为参数调用它 Dialogue: 0,0:39:30.19,0:39:32.75,Default,,0,0,0,,那么我们需要某个从X到3的映射 Dialogue: 0,0:39:34.19,0:39:37.39,Default,,0,0,0,,你可以把它想做是代换的一种 Dialogue: 0,0:39:38.27,0:39:40.30,Default,,0,0,0,,在旧的模型中 用3代换X Dialogue: 0,0:39:42.00,0:39:44.80,Default,,0,0,0,,所以我要建立一个框架 Dialogue: 0,0:39:45.15,0:39:46.60,Default,,0,0,0,,在框架中包含X等于3的这个信息 Dialogue: 0,0:39:49.12,0:39:49.71,Default,,0,0,0,,现在 Dialogue: 0,0:39:50.33,0:39:53.31,Default,,0,0,0,,过程的体即将被执行 Dialogue: 0,0:39:54.16,0:39:56.44,Default,,0,0,0,,它将在一个环境中执行 Dialogue: 0,0:39:57.80,0:40:08.03,Default,,0,0,0,,这个环境是由我们创建的新框架邻接组合而成 Dialogue: 0,0:40:08.54,0:40:11.69,Default,,0,0,0,,它是我们所应用的过程的一部分 Dialogue: 0,0:40:13.15,0:40:15.77,Default,,0,0,0,,所以 举个例子 Dialogue: 0,0:40:19.20,0:40:24.12,Default,,0,0,0,,假设我有一些环境 Dialogue: 0,0:40:25.15,0:40:27.23,Default,,0,0,0,,画个方框代表它 Dialogue: 0,0:40:27.96,0:40:32.19,Default,,0,0,0,,以及一些过程--我画圆来代表它们 因为这比小三角形好画-- Dialogue: 0,0:40:33.04,0:40:36.36,Default,,0,0,0,,抱歉 是菱形 Dialogue: 0,0:40:37.66,0:40:40.78,Default,,0,0,0,,小块菱形的果冻之类的东西 Dialogue: 0,0:40:42.68,0:40:45.32,Default,,0,0,0,,这有一个使用这个环境的过程 Dialogue: 0,0:40:45.95,0:40:48.16,Default,,0,0,0,,这个过程有一些代码 Dialogue: 0,0:40:48.16,0:40:49.68,Default,,0,0,0,,是一个LAMBDA表达式 Dialogue: 0,0:40:50.12,0:40:51.69,Default,,0,0,0,,约束了X和Y Dialogue: 0,0:40:53.15,0:40:56.43,Default,,0,0,0,,然后执行了表达式E Dialogue: 0,0:40:57.93,0:40:58.99,Default,,0,0,0,,这个过程就是这样的 Dialogue: 0,0:40:59.56,0:41:00.57,Default,,0,0,0,,我们叫它P Dialogue: 0,0:41:01.44,0:41:05.79,Default,,0,0,0,,我希望将这个过程应用于3和4 Dialogue: 0,0:41:06.38,0:41:08.36,Default,,0,0,0,,所以我在这写(P 3 4) Dialogue: 0,0:41:09.76,0:41:12.17,Default,,0,0,0,,我要做的事情则是 创建一个新的框架 Dialogue: 0,0:41:13.15,0:41:14.12,Default,,0,0,0,,创建一个框架 Dialogue: 0,0:41:15.24,0:41:18.28,Default,,0,0,0,,框架中X等于3 Dialogue: 0,0:41:18.84,0:41:20.51,Default,,0,0,0,,而Y等于4 Dialogue: 0,0:41:21.69,0:41:23.48,Default,,0,0,0,,我要把这个框架 Dialogue: 0,0:41:24.27,0:41:25.37,Default,,0,0,0,,连接到这一个框架上 Dialogue: 0,0:41:27.63,0:41:28.99,Default,,0,0,0,,对于这个环境 Dialogue: 0,0:41:29.68,0:41:30.97,Default,,0,0,0,,我把它叫做B Dialogue: 0,0:41:31.55,0:41:35.02,Default,,0,0,0,,我会在这个环境中求值E的体 Dialogue: 0,0:41:39.88,0:41:40.33,Default,,0,0,0,,现在 Dialogue: 0,0:41:41.95,0:41:45.04,Default,,0,0,0,,E可能包含了X和Y的引用以及一些别的东西 Dialogue: 0,0:41:46.84,0:41:49.95,Default,,0,0,0,,X和Y的值在这里 Dialogue: 0,0:41:50.70,0:41:52.52,Default,,0,0,0,,其他的变量的值在这里 Dialogue: 0,0:41:55.05,0:41:56.25,Default,,0,0,0,,怎样才能获取这个框架呢? Dialogue: 0,0:41:57.26,0:41:59.26,Default,,0,0,0,,我们通过过程构建来完成 Dialogue: 0,0:41:59.61,0:42:00.60,Default,,0,0,0,,这就是另一条规则了 Dialogue: 0,0:42:02.03,0:42:04.40,Default,,0,0,0,,请看下一张幻灯片 Dialogue: 0,0:42:05.34,0:42:06.12,Default,,0,0,0,,规则二 Dialogue: 0,0:42:07.80,0:42:09.90,Default,,0,0,0,,当一个LAMBDA表达式被求值时 Dialogue: 0,0:42:09.90,0:42:11.76,Default,,0,0,0,,相对于某个特定的环境-- Dialogue: 0,0:42:14.19,0:42:14.40,Default,,0,0,0,,例如 Dialogue: 0,0:42:15.04,0:42:18.12,Default,,0,0,0,,获取一个过程的方式就是求值一个LAMBDA表达式 Dialogue: 0,0:42:18.19,0:42:19.36,Default,,0,0,0,,这里有一个LAMBDA表达式 Dialogue: 0,0:42:20.04,0:42:21.12,Default,,0,0,0,,通过对它求值 Dialogue: 0,0:42:21.90,0:42:23.96,Default,,0,0,0,,我获得了一个可以应用于3的过程 Dialogue: 0,0:42:25.08,0:42:26.65,Default,,0,0,0,,现在这个LAMBDA表达式 Dialogue: 0,0:42:26.65,0:42:30.38,Default,,0,0,0,,在一个Y已被定义的环境中执行 Dialogue: 0,0:42:31.84,0:42:35.84,Default,,0,0,0,,我希望这个过程的体中包括的Y是自由的 Dialogue: 0,0:42:36.39,0:42:38.36,Default,,0,0,0,,在这里面 Y是自由的 Dialogue: 0,0:42:38.72,0:42:40.38,Default,,0,0,0,,但是在整个的表达式中却是被约束的 Dialogue: 0,0:42:41.36,0:42:42.75,Default,,0,0,0,,而在这里是自由的 Dialogue: 0,0:42:43.32,0:42:46.24,Default,,0,0,0,,我想让这两个Y指称同一个Y Dialogue: 0,0:42:47.44,0:42:55.13,Default,,0,0,0,,我在Y被创建的环境中求值这个过程的体 Dialogue: 0,0:42:55.32,0:42:58.40,Default,,0,0,0,,就像这个一样 因为那是通过应用完成的 Dialogue: 0,0:42:59.00,0:42:59.63,Default,,0,0,0,,现在 Dialogue: 0,0:43:00.24,0:43:02.60,Default,,0,0,0,,如果我还想查找Y的值 Dialogue: 0,0:43:03.10,0:43:04.09,Default,,0,0,0,,我就必须知道它在哪 Dialogue: 0,0:43:04.54,0:43:06.42,Default,,0,0,0,,因此 这个过程在被创建时 Dialogue: 0,0:43:06.42,0:43:10.06,Default,,0,0,0,,过程的创建 也就是对LAMBDA表达式求值的结果 Dialogue: 0,0:43:10.06,0:43:16.33,Default,,0,0,0,,最好是获取一个指针或记住Y被约束在哪个框架中 Dialogue: 0,0:43:17.92,0:43:19.76,Default,,0,0,0,,这就是这个规则的内容 Dialogue: 0,0:43:22.11,0:43:23.13,Default,,0,0,0,,那么 举个例子 Dialogue: 0,0:43:24.44,0:43:29.32,Default,,0,0,0,,如果我恰好求值了一个LAMBDA表达式 Dialogue: 0,0:43:30.89,0:43:33.32,Default,,0,0,0,,在E中的LAMBDA表达式 Dialogue: 0,0:43:34.04,0:43:40.46,Default,,0,0,0,,在E中求值(LAMBDA (X Y) G) Dialogue: 0,0:43:41.08,0:43:42.36,Default,,0,0,0,,对其求值 Dialogue: 0,0:43:42.97,0:43:46.17,Default,,0,0,0,,这些事的意义就是我现在构建了一个过程对象 Dialogue: 0,0:43:47.10,0:43:48.28,Default,,0,0,0,,E是某个环境 Dialogue: 0,0:43:48.84,0:43:50.94,Default,,0,0,0,,有个指针指向E Dialogue: 0,0:43:51.79,0:43:56.68,Default,,0,0,0,,我构建了一个过程对象指向了这个环境 Dialogue: 0,0:43:58.56,0:44:00.11,Default,,0,0,0,,它的代码 Dialogue: 0,0:44:00.54,0:44:03.24,Default,,0,0,0,,是一个LAMBDA表达式 或者是某种中间代码 Dialogue: 0,0:44:06.24,0:44:07.56,Default,,0,0,0,,而这就是一个过程 Dialogue: 0,0:44:12.38,0:44:14.70,Default,,0,0,0,,它为我生成了这个和这个 Dialogue: 0,0:44:14.94,0:44:16.37,Default,,0,0,0,,这个对象 Dialogue: 0,0:44:16.37,0:44:18.12,Default,,0,0,0,,这个环境指针 Dialogue: 0,0:44:18.37,0:44:22.52,Default,,0,0,0,,获取了求值LAMBDA表达式时的环境 Dialogue: 0,0:44:22.62,0:44:24.59,Default,,0,0,0,,定义所使用的环境 Dialogue: 0,0:44:25.58,0:44:27.40,Default,,0,0,0,,创建一个过程时的定义所用的环境 Dialogue: 0,0:44:30.32,0:44:31.47,Default,,0,0,0,,从而创建了过程 Dialogue: 0,0:44:32.89,0:44:36.30,Default,,0,0,0,,所以 它将环境从定义过程的地方取出 Dialogue: 0,0:44:37.42,0:44:38.92,Default,,0,0,0,,将它保存在过程自己内部 Dialogue: 0,0:44:39.60,0:44:40.97,Default,,0,0,0,,之后当过程被调用时 Dialogue: 0,0:44:41.32,0:44:43.47,Default,,0,0,0,,它在被定义时的环境 Dialogue: 0,0:44:43.98,0:44:45.07,Default,,0,0,0,,将由新的框架扩充 Dialogue: 0,0:44:48.72,0:44:52.33,Default,,0,0,0,,这给了我们一个放置有值的变量的地方 Dialogue: 0,0:44:53.04,0:44:53.96,Default,,0,0,0,,举个例子 Dialogue: 0,0:44:53.96,0:44:56.81,Default,,0,0,0,,如果有很多东西指向那这个环境 Dialogue: 0,0:44:57.74,0:45:00.33,Default,,0,0,0,,它们就会共享这个环境 Dialogue: 0,0:45:01.20,0:45:02.52,Default,,0,0,0,,我们很快将会见到 Dialogue: 0,0:45:04.01,0:45:05.34,Default,,0,0,0,,现在你们有了一个新模型 Dialogue: 0,0:45:06.38,0:45:09.92,Default,,0,0,0,,我们用它来理解程序的执行 Dialogue: 0,0:45:11.36,0:45:12.78,Default,,0,0,0,,我觉得现在我应该解答一些问题了 Dialogue: 0,0:45:13.10,0:45:14.96,Default,,0,0,0,,之后我们再继续 Dialogue: 0,0:45:18.19,0:45:19.52,Default,,0,0,0,,学生:这么说是对的吗? Dialogue: 0,0:45:19.52,0:45:23.96,Default,,0,0,0,,环境就是一些被连接在一起的框架 Dialogue: 0,0:45:23.96,0:45:25.10,Default,,0,0,0,,教授:对 Dialogue: 0,0:45:25.48,0:45:26.64,Default,,0,0,0,,学生:通过它能够访问所有的框架? Dialogue: 0,0:45:27.71,0:45:31.45,Default,,0,0,0,,教授:是的 环境是一系列被连接在一起的框架 Dialogue: 0,0:45:32.43,0:45:35.47,Default,,0,0,0,,我对它的理解是 它是指向第一个框架的指针 Dialogue: 0,0:45:36.88,0:45:38.72,Default,,0,0,0,,因为一旦你获得了它 你就能拿到所有的框架 Dialogue: 0,0:45:43.96,0:45:44.65,Default,,0,0,0,,还有谁有问题吗? Dialogue: 0,0:45:45.20,0:45:49.36,Default,,0,0,0,,学生:有可能在两个不同的环境中定义或求值一个过程 Dialogue: 0,0:45:49.36,0:45:53.20,Default,,0,0,0,,使得它有不同的行为 并且有指向两个环境的指针-- Dialogue: 0,0:45:53.20,0:45:55.77,Default,,0,0,0,,教授:噢 是的 同一个过程不会有两个不同环境 Dialogue: 0,0:45:56.90,0:45:59.02,Default,,0,0,0,,同样的代码 Dialogue: 0,0:45:59.02,0:46:00.82,Default,,0,0,0,,比如同样的LAMBDA表达式 Dialogue: 0,0:46:00.82,0:46:03.72,Default,,0,0,0,,再不同的环境下求值可能产生不同的过程 Dialogue: 0,0:46:06.03,0:46:07.18,Default,,0,0,0,,每个过程-- Dialogue: 0,0:46:07.18,0:46:09.95,Default,,0,0,0,,学生:它们的定义有同样的名字 它们的运算-- Dialogue: 0,0:46:09.95,0:46:11.92,Default,,0,0,0,,教授:它们定义是写起来是一样的 使用同样的字母 Dialogue: 0,0:46:12.56,0:46:14.62,Default,,0,0,0,,我能求值那一组字母 Dialogue: 0,0:46:14.93,0:46:18.14,Default,,0,0,0,,或定义的表结构之类的东西 Dialogue: 0,0:46:18.22,0:46:20.41,Default,,0,0,0,,那只是文本表示 Dialogue: 0,0:46:20.91,0:46:24.86,Default,,0,0,0,,我可以在两个不同环境种对它求值 产生两个不同的过程 Dialogue: 0,0:46:25.55,0:46:26.84,Default,,0,0,0,,每一个过程 Dialogue: 0,0:46:27.56,0:46:32.19,Default,,0,0,0,,有它们自己的一组局部变量 Dialogue: 0,0:46:32.34,0:46:33.45,Default,,0,0,0,,我们很快就会看到 Dialogue: 0,0:46:36.70,0:46:37.36,Default,,0,0,0,,还有问题吗? Dialogue: 0,0:46:42.60,0:46:44.03,Default,,0,0,0,,好 谢谢大家 我们休息一会 Dialogue: 0,0:46:47.98,0:46:57.61,Default,,0,0,0,,[音乐] Dialogue: 0,0:46:57.61,0:47:02.03,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:47:05.98,0:47:09.69,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:47:09.69,0:47:13.44,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:47:13.47,0:47:18.84,Declare,,0,0,0,,{\an2\fad(500,500)}赋值、状态和副作用 Dialogue: 0,0:47:22.67,0:47:25.69,Default,,0,0,0,,现在 我已经对你们做了一件非常糟糕的事儿 Dialogue: 0,0:47:26.56,0:47:30.54,Default,,0,0,0,,我引入了一个非常复杂的东西 Dialogue: 0,0:47:32.76,0:47:33.42,Default,,0,0,0,,赋值 Dialogue: 0,0:47:34.51,0:47:38.08,Default,,0,0,0,,它摧毁了我们程序中大部分的 有趣的数学特性 Dialogue: 0,0:47:41.07,0:47:42.46,Default,,0,0,0,,我为什么要做这件事呢 Dialogue: 0,0:47:43.18,0:47:45.02,Default,,0,0,0,,这样做可能有什么好处吗? Dialogue: 0,0:47:46.51,0:47:48.86,Default,,0,0,0,,很明显 这不是一个什么好东西 Dialogue: 0,0:47:49.60,0:47:51.23,Default,,0,0,0,,因此我最好有一个好的理由 Dialogue: 0,0:47:52.83,0:47:54.80,Default,,0,0,0,,让我们来小小地玩一下 Dialogue: 0,0:47:54.80,0:47:58.35,Default,,0,0,0,,首先 我们写些非常有趣的带赋值的程序 Dialogue: 0,0:47:58.81,0:48:00.88,Default,,0,0,0,,来理解它们的特殊之处 Dialogue: 0,0:48:01.42,0:48:02.83,Default,,0,0,0,,这些特殊之处使赋值变得有价值 Dialogue: 0,0:48:04.96,0:48:06.70,Default,,0,0,0,,我们从一个非常简单的程序开始 Dialogue: 0,0:48:07.69,0:48:09.28,Default,,0,0,0,,我把这个程序叫做MAKE-COUNTER Dialogue: 0,0:48:10.48,0:48:18.19,Default,,0,0,0,,我要把它定义为 Dialogue: 0,0:48:24.17,0:48:28.12,Default,,0,0,0,,接受一个参数N的过程 Dialogue: 0,0:48:29.23,0:48:32.94,Default,,0,0,0,,并且它的返回值是一个没有参数的过程-- Dialogue: 0,0:48:34.36,0:48:36.03,Default,,0,0,0,,一个生成过程的过程-- Dialogue: 0,0:48:36.84,0:48:44.35,Default,,0,0,0,,这个过程把N的值设为N+1 Dialogue: 0,0:48:47.88,0:48:49.77,Default,,0,0,0,,并且返回N的值 Dialogue: 0,0:48:55.37,0:48:57.54,Default,,0,0,0,,现在 我们要研究它的行为 Dialogue: 0,0:48:57.54,0:48:59.02,Default,,0,0,0,,它很有趣 Dialogue: 0,0:48:59.82,0:49:01.45,Default,,0,0,0,,为了研究它的行为 Dialogue: 0,0:49:01.45,0:49:03.08,Default,,0,0,0,,我需要建立一个环境模型 Dialogue: 0,0:49:04.11,0:49:05.98,Default,,0,0,0,,因为我们不能通过其他的方式来理解它 Dialogue: 0,0:49:08.65,0:49:09.63,Default,,0,0,0,,所以我们开始吧 Dialogue: 0,0:49:10.00,0:49:12.86,Default,,0,0,0,,我们从这里开始 Dialogue: 0,0:49:13.24,0:49:15.90,Default,,0,0,0,,假设机器天生就有一个全局环境 Dialogue: 0,0:49:16.13,0:49:17.12,Default,,0,0,0,,我们把它叫做Global Dialogue: 0,0:49:20.03,0:49:24.25,Default,,0,0,0,,它内部有一堆初始化的东西 Dialogue: 0,0:49:24.44,0:49:25.60,Default,,0,0,0,,我们都知道它里面有什么 Dialogue: 0,0:49:25.72,0:49:30.88,Default,,0,0,0,,这里面有+和* Dialogue: 0,0:49:32.24,0:49:37.26,Default,,0,0,0,,/ -和CAR Dialogue: 0,0:49:38.70,0:49:39.74,Default,,0,0,0,,以此类推 Dialogue: 0,0:49:41.45,0:49:42.48,Default,,0,0,0,,有很多东西 Dialogue: 0,0:49:42.88,0:49:43.98,Default,,0,0,0,,我不知道它们是什么 Dialogue: 0,0:49:44.42,0:49:45.55,Default,,0,0,0,,一些乱七八糟的符号 Dialogue: 0,0:49:46.08,0:49:48.88,Default,,0,0,0,,机器一开始就有这些特性 Dialogue: 0,0:49:51.21,0:49:53.23,Default,,0,0,0,,通过在这做定义 Dialogue: 0,0:49:54.68,0:49:55.76,Default,,0,0,0,,我要做的是-- Dialogue: 0,0:49:56.32,0:49:57.31,Default,,0,0,0,,我在干什么呢? Dialogue: 0,0:49:57.31,0:49:59.58,Default,,0,0,0,,我要把它关联到全局环境上 Dialogue: 0,0:49:59.72,0:50:01.29,Default,,0,0,0,,这是我的环境指针 Dialogue: 0,0:50:03.72,0:50:06.70,Default,,0,0,0,,为了达到那个目的 我要求值这个LAMBDA表达式 Dialogue: 0,0:50:08.35,0:50:10.01,Default,,0,0,0,,这意味着我创建了一个过程对象 Dialogue: 0,0:50:11.50,0:50:13.26,Default,,0,0,0,,所以 我要在这创建一个过程对象 Dialogue: 0,0:50:17.36,0:50:18.68,Default,,0,0,0,,这个过程对象 Dialogue: 0,0:50:18.72,0:50:20.49,Default,,0,0,0,,由于在它被定义的地方 Dialogue: 0,0:50:21.16,0:50:22.35,Default,,0,0,0,,有一个全局的环境 Dialogue: 0,0:50:24.06,0:50:25.79,Default,,0,0,0,,这个过程对象包括了 Dialogue: 0,0:50:28.16,0:50:31.47,Default,,0,0,0,,以N为参数的过程的代码 Dialogue: 0,0:50:31.96,0:50:35.34,Default,,0,0,0,,它返回一个不接受参数的过程 Dialogue: 0,0:50:38.24,0:50:43.28,Default,,0,0,0,,DEFINE是一种改变环境的方法 Dialogue: 0,0:50:44.32,0:50:46.73,Default,,0,0,0,,所以我把MAKE-COUNTER加入全局环境中 Dialogue: 0,0:50:52.28,0:50:55.05,Default,,0,0,0,,这是对于特殊的东西定义的一个特殊的规则 Dialogue: 0,0:50:55.82,0:50:56.94,Default,,0,0,0,,但它其实是 Dialogue: 0,0:50:58.94,0:51:01.96,Default,,0,0,0,,它给了我们一个指针 指向那个过程 Dialogue: 0,0:51:03.82,0:51:06.32,Default,,0,0,0,,所以现在全局环境中也有了MAKE-COUNTER Dialogue: 0,0:51:09.28,0:51:11.21,Default,,0,0,0,,现在 我们要进行一些操作 Dialogue: 0,0:51:11.87,0:51:13.50,Default,,0,0,0,,我要用它来创建一些计数器 Dialogue: 0,0:51:14.99,0:51:16.20,Default,,0,0,0,,我们来看看计数器是什么 Dialogue: 0,0:51:17.12,0:51:18.51,Default,,0,0,0,,所以我们定义 Dialogue: 0,0:51:23.32,0:51:26.65,Default,,0,0,0,,C1为一个从0开始的计数器 Dialogue: 0,0:51:35.72,0:51:38.38,Default,,0,0,0,,根据模型 我们知道如何做这个了 Dialogue: 0,0:51:39.63,0:51:44.33,Default,,0,0,0,,我需要在全局环境中求值这个表达式 Dialogue: 0,0:51:45.40,0:51:46.27,Default,,0,0,0,,(MAKE-COUNTER 0) Dialogue: 0,0:51:47.80,0:51:51.10,Default,,0,0,0,,我查找MAKE-COUNTER 发现它是一个过程 Dialogue: 0,0:51:53.61,0:51:55.29,Default,,0,0,0,,我将要应用这个过程 Dialogue: 0,0:51:56.22,0:51:57.74,Default,,0,0,0,,应用这个过程的方式 Dialogue: 0,0:51:58.43,0:51:59.96,Default,,0,0,0,,就是构建一个框架 Dialogue: 0,0:52:01.80,0:52:03.79,Default,,0,0,0,,所以我构建了一个框架 Dialogue: 0,0:52:06.59,0:52:10.44,Default,,0,0,0,,它内部有一个N的值 Dialogue: 0,0:52:11.77,0:52:12.64,Default,,0,0,0,,这个值是0 Dialogue: 0,0:52:14.00,0:52:15.34,Default,,0,0,0,,它的父环境 Dialogue: 0,0:52:15.87,0:52:19.32,Default,,0,0,0,,就是定义MAKE-COUNTER时的环境 Dialogue: 0,0:52:23.93,0:52:28.36,Default,,0,0,0,,所以我已经通过将MAKE-COUNTER应用于0上 而创建了一个环境 Dialogue: 0,0:52:31.45,0:52:34.40,Default,,0,0,0,,现在 我需要求值MAKE-COUNTER的体 Dialogue: 0,0:52:34.41,0:52:37.72,Default,,0,0,0,,就是那个环境中的LAMBDA表达式 Dialogue: 0,0:52:40.64,0:52:42.30,Default,,0,0,0,,求值这个体 Dialogue: 0,0:52:42.76,0:52:44.59,Default,,0,0,0,,它是一个LAMBDA表达式 Dialogue: 0,0:52:46.28,0:52:48.86,Default,,0,0,0,,对LAMBDA表达式求值 意味着创建一个过程对象 Dialogue: 0,0:52:49.56,0:52:51.00,Default,,0,0,0,,所以我将创建一个过程对象 Dialogue: 0,0:52:56.76,0:52:58.29,Default,,0,0,0,,这个过程对象 Dialogue: 0,0:52:58.29,0:53:00.46,Default,,0,0,0,,拥有一个环境 Dialogue: 0,0:53:04.20,0:53:05.88,Default,,0,0,0,,在这个环境中N被定义为0 Dialogue: 0,0:53:07.68,0:53:08.80,Default,,0,0,0,,它有一些代码 Dialogue: 0,0:53:08.83,0:53:11.37,Default,,0,0,0,,这个过程不需要参数 Dialogue: 0,0:53:11.40,0:53:15.28,Default,,0,0,0,,该过程进行一些处理 然后进行赋值 Dialogue: 0,0:53:15.28,0:53:16.73,Default,,0,0,0,,并返回N Dialogue: 0,0:53:17.88,0:53:18.81,Default,,0,0,0,,这个东西 Dialogue: 0,0:53:19.42,0:53:21.23,Default,,0,0,0,,将成为一个对象 Dialogue: 0,0:53:21.92,0:53:24.67,Default,,0,0,0,,在全局环境中 它的名字是C1 Dialogue: 0,0:53:26.12,0:53:28.33,Default,,0,0,0,,所以我们在这建立一个名字 C1 Dialogue: 0,0:53:28.64,0:53:32.14,Default,,0,0,0,,并且说C1等于这个过程 Dialogue: 0,0:53:35.48,0:53:37.36,Default,,0,0,0,,现在 再来创建另一个计数器 Dialogue: 0,0:53:43.04,0:53:45.13,Default,,0,0,0,,通过MAKE-COUNTER创建c2 Dialogue: 0,0:53:50.94,0:53:52.19,Default,,0,0,0,,让它从10开始 Dialogue: 0,0:53:54.25,0:53:55.90,Default,,0,0,0,,然后我执行同样的步骤 Dialogue: 0,0:53:56.64,0:54:00.40,Default,,0,0,0,,我应用这个MAKE-COUNTER过程 Dialogue: 0,0:54:00.99,0:54:04.52,Default,,0,0,0,,建立另一个框架 其中N等于10 Dialogue: 0,0:54:05.63,0:54:09.18,Default,,0,0,0,,全局环境作为它的父环境 Dialogue: 0,0:54:10.04,0:54:11.80,Default,,0,0,0,,然后我构建一个过程 Dialogue: 0,0:54:13.04,0:54:17.63,Default,,0,0,0,,以这个框架作为它定义的环境 Dialogue: 0,0:54:18.27,0:54:21.66,Default,,0,0,0,,它的代码是 Dialogue: 0,0:54:21.80,0:54:24.38,Default,,0,0,0,,完成一些操作的无参过程 Dialogue: 0,0:54:25.54,0:54:28.60,Default,,0,0,0,,然后进行赋值 等等 Dialogue: 0,0:54:28.60,0:54:31.22,Default,,0,0,0,,然后返回N Dialogue: 0,0:54:31.45,0:54:34.83,Default,,0,0,0,,这就是C2 Dialogue: 0,0:54:36.88,0:54:39.32,Default,,0,0,0,,好 你们应该发现 某些东西开始变得有趣了 Dialogue: 0,0:54:40.17,0:54:41.92,Default,,0,0,0,,这里有两个N Dialogue: 0,0:54:42.92,0:54:44.19,Default,,0,0,0,,它们不是同一个N Dialogue: 0,0:54:46.14,0:54:48.16,Default,,0,0,0,,我每次调用MAKE-COUNTER的时候 Dialogue: 0,0:54:48.64,0:54:50.25,Default,,0,0,0,,我就创建了另一个N的实例 Dialogue: 0,0:54:52.62,0:54:54.40,Default,,0,0,0,,它们彼此独立 没有关联 Dialogue: 0,0:54:57.79,0:55:00.28,Default,,0,0,0,,现在 我们来使用一下这些计数器 Dialogue: 0,0:55:05.92,0:55:15.00,Default,,0,0,0,,如果此时 我调用C1 会发生什么? Dialogue: 0,0:55:15.84,0:55:17.34,Default,,0,0,0,,我会在这里查找 Dialogue: 0,0:55:17.56,0:55:19.98,Default,,0,0,0,,发现C1是一个过程 Dialogue: 0,0:55:20.64,0:55:22.78,Default,,0,0,0,,我要不带参数地调用这个过程 Dialogue: 0,0:55:23.16,0:55:24.96,Default,,0,0,0,,因为它不需要参数 Dialogue: 0,0:55:24.96,0:55:25.63,Default,,0,0,0,,对吧? Dialogue: 0,0:55:26.97,0:55:27.84,Default,,0,0,0,,它的体是什么呢? Dialogue: 0,0:55:27.96,0:55:30.02,Default,,0,0,0,,我得来这里解释 因为我没有给誊过来 Dialogue: 0,0:55:30.02,0:55:32.65,Default,,0,0,0,,这个过程体是将N赋值为N+1 Dialogue: 0,0:55:33.80,0:55:34.89,Default,,0,0,0,,并且返回N Dialogue: 0,0:55:37.12,0:55:38.12,Default,,0,0,0,,就是把N增大1 Dialogue: 0,0:55:38.97,0:55:41.60,Default,,0,0,0,,它的N指的是这个 Dialogue: 0,0:55:43.08,0:55:44.60,Default,,0,0,0,,所以我把这个n增大1 Dialogue: 0,0:55:45.80,0:55:47.00,Default,,0,0,0,,它变成了1 Dialogue: 0,0:55:48.64,0:55:50.24,Default,,0,0,0,,然后返回了1 Dialogue: 0,0:55:53.13,0:55:56.49,Default,,0,0,0,,之后我调用C2 Dialogue: 0,0:55:58.38,0:55:59.20,Default,,0,0,0,,我会做什么? Dialogue: 0,0:55:59.23,0:56:03.33,Default,,0,0,0,,C2是相同的过程 Dialogue: 0,0:56:03.33,0:56:04.48,Default,,0,0,0,,但这个N Dialogue: 0,0:56:05.33,0:56:06.57,Default,,0,0,0,,它变成了11 Dialogue: 0,0:56:10.97,0:56:14.59,Default,,0,0,0,,所以返回值是11 Dialogue: 0,0:56:15.92,0:56:18.32,Default,,0,0,0,,然后我们再来调用一下C1 Dialogue: 0,0:56:20.91,0:56:22.56,Default,,0,0,0,,C1是这个 Dialogue: 0,0:56:23.28,0:56:24.16,Default,,0,0,0,,它是2 Dialogue: 0,0:56:27.24,0:56:28.30,Default,,0,0,0,,所以结果是2 Dialogue: 0,0:56:29.66,0:56:30.75,Default,,0,0,0,,然后调用C2 Dialogue: 0,0:56:33.37,0:56:35.31,Default,,0,0,0,,然后C2通过同样的方法 返回了12 Dialogue: 0,0:56:35.74,0:56:37.55,Default,,0,0,0,,它在这里进行查找 Dialogue: 0,0:56:37.55,0:56:39.28,Default,,0,0,0,,发现了N 并把它加1 Dialogue: 0,0:56:41.64,0:56:43.68,Default,,0,0,0,,我拥有的是可计算的对象 Dialogue: 0,0:56:45.21,0:56:46.86,Default,,0,0,0,,它们是两个计数器 Dialogue: 0,0:56:48.96,0:56:51.02,Default,,0,0,0,,每一个都有各自独立的局部状态 Dialogue: 0,0:56:55.48,0:56:56.62,Default,,0,0,0,,我们再进一步 Dialogue: 0,0:56:56.64,0:56:58.52,Default,,0,0,0,,这是个奇怪的东西 Dialogue: 0,0:57:01.12,0:57:02.22,Default,,0,0,0,,什么是对象? Dialogue: 0,0:57:04.11,0:57:06.12,Default,,0,0,0,,这个概念并不明确 Dialogue: 0,0:57:07.55,0:57:09.45,Default,,0,0,0,,我们倾向于以对象的角度思考 Dialogue: 0,0:57:11.24,0:57:13.32,Default,,0,0,0,,因为这样思考比较经济 Dialogue: 0,0:57:14.62,0:57:17.28,Default,,0,0,0,,这是一种智力上的经济 Dialogue: 0,0:57:18.57,0:57:19.61,Default,,0,0,0,,我是一个对象 Dialogue: 0,0:57:20.99,0:57:22.30,Default,,0,0,0,,你也是一个对象 Dialogue: 0,0:57:23.55,0:57:25.29,Default,,0,0,0,,但我们不是同一个对象 Dialogue: 0,0:57:27.52,0:57:29.64,Default,,0,0,0,,我可以把世界分为两部分 Dialogue: 0,0:57:29.92,0:57:31.85,Default,,0,0,0,,我和你 Dialogue: 0,0:57:31.92,0:57:33.31,Default,,0,0,0,,以及其它的东西 Dialogue: 0,0:57:34.70,0:57:35.26,Default,,0,0,0,,使得 Dialogue: 0,0:57:35.44,0:57:39.50,Default,,0,0,0,,大多数对于我的讨论 Dialogue: 0,0:57:39.68,0:57:40.89,Default,,0,0,0,,不会影响到你 Dialogue: 0,0:57:41.39,0:57:44.67,Default,,0,0,0,,大多数对于你的讨论不会牵涉到我 Dialogue: 0,0:57:45.66,0:57:46.94,Default,,0,0,0,,我有血压 Dialogue: 0,0:57:47.50,0:57:48.38,Default,,0,0,0,,体温 Dialogue: 0,0:57:49.36,0:57:51.48,Default,,0,0,0,,呼吸频率 Dialogue: 0,0:57:53.34,0:57:54.99,Default,,0,0,0,,血液中有确定的血糖值 Dialogue: 0,0:57:56.11,0:57:59.34,Default,,0,0,0,,数不清的 数以千计的状态变量--上百万实际上 Dialogue: 0,0:57:59.37,0:58:00.65,Default,,0,0,0,,我不知道具体有多少 Dialogue: 0,0:58:00.93,0:58:03.48,Default,,0,0,0,,以物理学观点 我拥有大量的状态变量 Dialogue: 0,0:58:04.91,0:58:07.12,Default,,0,0,0,,如果将我视为一个粒子的话 Dialogue: 0,0:58:09.15,0:58:10.64,Default,,0,0,0,,你也有许许多多这样的变量 Dialogue: 0,0:58:12.68,0:58:14.94,Default,,0,0,0,,我们的大多数变量之间是好无联系的 Dialogue: 0,0:58:17.31,0:58:19.50,Default,,0,0,0,,所以可以计算我的属性 Dialogue: 0,0:58:20.56,0:58:22.83,Default,,0,0,0,,而不用太担心你的属性 Dialogue: 0,0:58:23.82,0:58:25.77,Default,,0,0,0,,如果把我们两个放在一起计算 Dialogue: 0,0:58:25.96,0:58:27.82,Default,,0,0,0,,那么我们需要考虑的状态的数量 Dialogue: 0,0:58:27.82,0:58:30.01,Default,,0,0,0,,就是你与我的状态的数量的乘积 Dialogue: 0,0:58:30.52,0:58:32.11,Default,,0,0,0,,按对象解耦的话 则只需考虑你我状态之和 Dialogue: 0,0:58:32.65,0:58:35.34,Default,,0,0,0,,然而 实际上有一种力量把我们耦合起来 Dialogue: 0,0:58:36.00,0:58:37.95,Default,,0,0,0,,我对你讲话 你的状态就变了 Dialogue: 0,0:58:38.44,0:58:40.09,Default,,0,0,0,,我看着你 我的状态就变了 Dialogue: 0,0:58:41.72,0:58:44.08,Default,,0,0,0,,因此 我的变量中的一小部分 Dialogue: 0,0:58:44.33,0:58:46.07,Default,,0,0,0,,与你的一些变量是耦合的 Dialogue: 0,0:58:46.07,0:58:47.80,Default,,0,0,0,,如果你突然大喊大叫 Dialogue: 0,0:58:47.80,0:58:48.88,Default,,0,0,0,,我的血压就会升高 Dialogue: 0,0:58:54.30,0:58:56.86,Default,,0,0,0,,然而 将世界看作是由独立的变量 Dialogue: 0,0:58:57.17,0:59:01.16,Default,,0,0,0,,和独立的粒子组成的是不恰当的 Dialogue: 0,0:59:02.12,0:59:04.46,Default,,0,0,0,,在像量子力学这样的东西里存在大量的BUG Dialogue: 0,0:59:05.23,0:59:08.70,Default,,0,0,0,,或者当我们思考像量子力学之类的东西的时候 会在我们的脑海中产生bug Dialogue: 0,0:59:08.89,0:59:10.97,Default,,0,0,0,,这是由于 当我们思考事物时 Dialogue: 0,0:59:10.97,0:59:12.96,Default,,0,0,0,,会去将事物分解为相互独立的部分来看待 Dialogue: 0,0:59:13.58,0:59:17.32,Default,,0,0,0,,而事实上事物的耦合程度 远远大于在表面所看到的 Dialogue: 0,0:59:18.01,0:59:19.44,Default,,0,0,0,,即便这样 我们仍像那样思考 Dialogue: 0,0:59:19.61,0:59:21.69,Default,,0,0,0,,是因为我们希望高效并且有效的进行计算 Dialogue: 0,0:59:22.19,0:59:23.82,Default,,0,0,0,,我们被培养成以那种方式进行思考 Dialogue: 0,0:59:29.76,0:59:30.51,Default,,0,0,0,,大家看 Dialogue: 0,0:59:31.50,0:59:33.44,Default,,0,0,0,,我们如何才能知道我们是否有对象? Dialogue: 0,0:59:35.12,0:59:37.34,Default,,0,0,0,,如果我们有对象 应该如何分辨呢? Dialogue: 0,0:59:37.64,0:59:41.45,Default,,0,0,0,,通过思考一些光学现象 Dialogue: 0,0:59:42.46,0:59:43.13,Default,,0,0,0,,就能解答这个问题 Dialogue: 0,0:59:45.04,0:59:47.69,Default,,0,0,0,,这几截粉笔不完全相同 Dialogue: 0,0:59:47.76,0:59:50.20,Default,,0,0,0,,但假设 只通过观察是无法区分它们的 Dialogue: 0,0:59:52.04,0:59:53.32,Default,,0,0,0,,有一种可能 Dialogue: 0,0:59:53.32,0:59:55.16,Default,,0,0,0,,是这一切都是我们与镜子的游戏 Dialogue: 0,0:59:56.07,0:59:57.60,Default,,0,0,0,,它们真的是同一截粉笔 Dialogue: 0,0:59:59.36,1:00:00.48,Default,,0,0,0,,但你看到了两个 Dialogue: 0,1:00:01.61,1:00:03.87,Default,,0,0,0,,你怎么知道你看到的是一个还是两个呢? Dialogue: 0,1:00:05.04,1:00:06.70,Default,,0,0,0,,我只知道有一种方法可以确定 Dialogue: 0,1:00:07.37,1:00:08.94,Default,,0,0,0,,抓起其中一个并且改变它 Dialogue: 0,1:00:09.45,1:00:10.67,Default,,0,0,0,,然后看看另一个有没有跟着变化 Dialogue: 0,1:00:14.01,1:00:14.67,Default,,0,0,0,,而另一个没有变化 Dialogue: 0,1:00:15.50,1:00:16.14,Default,,0,0,0,,所以它们是两截不同粉笔 Dialogue: 0,1:00:19.50,1:00:20.16,Default,,0,0,0,,另一方面 Dialogue: 0,1:00:20.17,1:00:22.20,Default,,0,0,0,,事物还有一些其它的类似的纠结属性 Dialogue: 0,1:00:22.57,1:00:24.01,Default,,0,0,0,,例如 我们怎么才知道某个东西是否改变了呢? Dialogue: 0,1:00:25.00,1:00:27.93,Default,,0,0,0,,我们需要在它改变之前和之后进行观察 Dialogue: 0,1:00:28.65,1:00:30.02,Default,,0,0,0,,改变就是赋值 Dialogue: 0,1:00:30.02,1:00:31.45,Default,,0,0,0,,它是时间中的一个时刻 Dialogue: 0,1:00:32.14,1:00:34.60,Default,,0,0,0,,但是那意味着我们需要知道 我们看到的是否是同一个 Dialogue: 0,1:00:36.51,1:00:38.84,Default,,0,0,0,,所以一些东西非常奇怪 Dialogue: 0,1:00:38.84,1:00:40.38,Default,,0,0,0,,不同寻常并且晦涩难懂 Dialogue: 0,1:00:40.84,1:00:43.52,Default,,0,0,0,,并且我不理解与赋值 Dialogue: 0,1:00:44.45,1:00:46.28,Default,,0,0,0,,变化以及对象有关的问题 Dialogue: 0,1:00:47.29,1:00:48.99,Default,,0,0,0,,这些东西可能变得非常非常糟糕 Dialogue: 0,1:00:51.40,1:00:52.12,Default,,0,0,0,,例如 Dialogue: 0,1:00:53.31,1:00:55.60,Default,,0,0,0,,我 一个特定的人 Dialogue: 0,1:00:56.16,1:00:57.72,Default,,0,0,0,,一个特定的对象 Dialogue: 0,1:00:57.96,1:00:59.31,Default,,0,0,0,,现在 我可以拿出小刀 Dialogue: 0,1:01:00.68,1:01:01.77,Default,,0,0,0,,切下一片我的指甲 Dialogue: 0,1:01:01.89,1:01:04.81,Default,,0,0,0,,一片指甲掉在了桌子上 Dialogue: 0,1:01:05.93,1:01:10.16,Default,,0,0,0,,我相信自己和一秒钟之前的自己 是同一个人 Dialogue: 0,1:01:10.97,1:01:12.81,Default,,0,0,0,,但在物理上并不是分毫不差 Dialogue: 0,1:01:14.46,1:01:15.43,Default,,0,0,0,,我已经改变了 Dialogue: 0,1:01:15.58,1:01:16.65,Default,,0,0,0,,为什么我还是同一个人呢? Dialogue: 0,1:01:18.11,1:01:19.40,Default,,0,0,0,,什么能认定我的身份呢? Dialogue: 0,1:01:20.96,1:01:23.50,Default,,0,0,0,,我不知道 Dialogue: 0,1:01:25.05,1:01:27.88,Default,,0,0,0,,除非我有某种特征 Dialogue: 0,1:01:29.71,1:01:33.04,Default,,0,0,0,,我觉得 由于引入赋值和对象 Dialogue: 0,1:01:33.64,1:01:38.28,Default,,0,0,0,,我们不得不去面对这种 Dialogue: 0,1:01:38.41,1:01:42.24,Default,,0,0,0,,困扰了哲学家们上千年的哲学问题 Dialogue: 0,1:01:43.42,1:01:44.99,Default,,0,0,0,,这也是相比之下 为什么数学清晰得多 Dialogue: 0,1:01:45.69,1:01:50.24,Default,,0,0,0,,我将尽我所能地向大家阐述关于动作和身份的理解 Dialogue: 0,1:01:52.44,1:01:55.39,Default,,0,0,0,,我们说动作A 对于对于某个对象X有影响 Dialogue: 0,1:01:55.77,1:01:56.70,Default,,0,0,0,,换句话说 Dialogue: 0,1:01:56.92,1:01:58.41,Default,,0,0,0,,X被A改变 Dialogue: 0,1:01:58.89,1:02:01.66,Default,,0,0,0,,如果某个属性P 在P作用于X之前为真 Dialogue: 0,1:02:01.87,1:02:03.76,Default,,0,0,0,,在A作用于X之后为假 Dialogue: 0,1:02:04.99,1:02:05.63,Default,,0,0,0,,那是个测试 Dialogue: 0,1:02:06.62,1:02:09.66,Default,,0,0,0,,这也意味着 我必须有变动前和变动后的X Dialogue: 0,1:02:10.91,1:02:12.54,Default,,0,0,0,,或者 换句话说 Dialogue: 0,1:02:12.94,1:02:14.94,Default,,0,0,0,,我们说对任一动作 两个对象X和Y是同一个对象 Dialogue: 0,1:02:14.97,1:02:17.93,Default,,0,0,0,,当且仅当 该动作对X、Y有同样的影响 Dialogue: 0,1:02:19.63,1:02:21.39,Default,,0,0,0,,然而 就像我说的 Dialogue: 0,1:02:21.44,1:02:23.18,Default,,0,0,0,,对象在智力经济上是非常有用的 Dialogue: 0,1:02:24.64,1:02:27.12,Default,,0,0,0,,对于它们来说非常有用的东西之一 Dialogue: 0,1:02:28.27,1:02:29.44,Default,,0,0,0,,就是对于这个世界 Dialogue: 0,1:02:30.78,1:02:34.80,Default,,0,0,0,,我们习惯于把它认为是由带有独立状态的独立对象所构成的 Dialogue: 0,1:02:35.00,1:02:37.28,Default,,0,0,0,,虽然那并不完全正确 但我们喜欢以那样的的方式来思考 Dialogue: 0,1:02:39.68,1:02:42.03,Default,,0,0,0,,当我们要写一个非常复杂的程序 Dialogue: 0,1:02:42.03,1:02:43.26,Default,,0,0,0,,来应对这样一个世界时 Dialogue: 0,1:02:43.98,1:02:46.44,Default,,0,0,0,,如果我们希望这些程序可以被我们理解 Dialogue: 0,1:02:46.91,1:02:48.14,Default,,0,0,0,,并且也是可修改的 Dialogue: 0,1:02:48.73,1:02:51.12,Default,,0,0,0,,那么如果世界改变了 我们只需要稍微改动一下程序 Dialogue: 0,1:02:51.39,1:02:53.70,Default,,0,0,0,,我们希望建立一种联系 一种同构 Dialogue: 0,1:02:53.82,1:02:56.88,Default,,0,0,0,,建立在真实世界的对象与我们脑海中的对象之间 Dialogue: 0,1:02:58.76,1:03:01.44,Default,,0,0,0,,世界的模块化 使我们的程序得以模块化 Dialogue: 0,1:03:02.41,1:03:05.36,Default,,0,0,0,,所以我们发明了面向对象编程 Dialogue: 0,1:03:05.88,1:03:08.36,Default,,0,0,0,,使我们获得那样的力量 Dialogue: 0,1:03:10.06,1:03:10.94,Default,,0,0,0,,但是 它甚至更简单 Dialogue: 0,1:03:10.94,1:03:12.25,Default,,0,0,0,,让我们玩一个小游戏 Dialogue: 0,1:03:12.27,1:03:13.18,Default,,0,0,0,,我想通过这个游戏 Dialogue: 0,1:03:13.39,1:03:15.77,Default,,0,0,0,,给你展示一个更简单的例子 Dialogue: 0,1:03:16.00,1:03:21.74,Default,,0,0,0,,来说明谨慎地使用赋值语句 可以增强模块性 Dialogue: 0,1:03:22.86,1:03:25.35,Default,,0,0,0,,有一件事 我想让你牢牢地铭记 Dialogue: 0,1:03:25.45,1:03:27.44,Default,,0,0,0,,就是不要像在FORTRAN Basic Dialogue: 0,1:03:27.45,1:03:29.79,Default,,0,0,0,,或者Pascal里一样使用赋值语句 Dialogue: 0,1:03:30.00,1:03:31.71,Default,,0,0,0,,你不那样做 也能达到目的 Dialogue: 0,1:03:34.04,1:03:36.62,Default,,0,0,0,,这不是思考大多数事情的正确方式 Dialogue: 0,1:03:36.97,1:03:38.28,Default,,0,0,0,,有些时候它是必要的 Dialogue: 0,1:03:38.68,1:03:39.69,Default,,0,0,0,,或者可能是必要的 Dialogue: 0,1:03:39.69,1:03:40.97,Default,,0,0,0,,我们一会更深入地去研究 Dialogue: 0,1:03:42.24,1:03:44.22,Default,,0,0,0,,我要给你展示一个有趣的游戏 Dialogue: 0,1:03:47.61,1:03:49.42,Default,,0,0,0,,从前有一个数学家 Dialogue: 0,1:03:49.68,1:03:53.69,Default,,0,0,0,,叫做Cesaro Dialogue: 0,1:03:54.48,1:03:57.45,Default,,0,0,0,,他发现了一个计算pi的巧妙方法 Dialogue: 0,1:03:58.38,1:04:04.30,Default,,0,0,0,,这个方法是说 如果我有两个随机数 Dialogue: 0,1:04:05.24,1:04:06.94,Default,,0,0,0,,两个随机的整数 Dialogue: 0,1:04:07.74,1:04:09.48,Default,,0,0,0,,计算它们的最大公约数 Dialogue: 0,1:04:10.94,1:04:13.24,Default,,0,0,0,,结果可能是1 或者不是1 Dialogue: 0,1:04:13.84,1:04:15.64,Default,,0,0,0,,如果是1 它们没有公约数 Dialogue: 0,1:04:18.14,1:04:20.68,Default,,0,0,0,,如果它们的最大公约数是1 Dialogue: 0,1:04:21.12,1:04:23.09,Default,,0,0,0,,这两个随机数 Dialogue: 0,1:04:23.09,1:04:26.38,Default,,0,0,0,,两个随机生成的数 最大公约数为1的概率 Dialogue: 0,1:04:26.58,1:04:27.82,Default,,0,0,0,,与pi有关系 Dialogue: 0,1:04:29.32,1:04:30.11,Default,,0,0,0,,事实上 Dialogue: 0,1:04:31.11,1:04:32.33,Default,,0,0,0,,是的 这很奇怪 Dialogue: 0,1:04:32.94,1:04:34.41,Default,,0,0,0,,当然有其他计算pi的方法 Dialogue: 0,1:04:34.41,1:04:38.94,Default,,0,0,0,,像投针法之类的的方法 Dialogue: 0,1:04:40.19,1:04:48.97,Default,,0,0,0,,N1和N2的最大公约数是1的概率为 Dialogue: 0,1:04:49.44,1:04:51.02,Default,,0,0,0,,N1、N2是随机选取的两个数 Dialogue: 0,1:04:51.71,1:04:53.66,Default,,0,0,0,,是6/pi^2 Dialogue: 0,1:04:55.61,1:04:56.83,Default,,0,0,0,,我不准备证明这个 Dialogue: 0,1:04:57.15,1:04:59.64,Default,,0,0,0,,事实上这不难 并且有些有趣 Dialogue: 0,1:05:01.07,1:05:03.05,Default,,0,0,0,,我们要怎样估算这个概率呢? Dialogue: 0,1:05:03.53,1:05:06.46,Default,,0,0,0,,我们估算概率的方法则是 Dialogue: 0,1:05:07.23,1:05:08.65,Default,,0,0,0,,是做大量的实验 Dialogue: 0,1:05:09.20,1:05:12.01,Default,,0,0,0,,去计算成功的试验 Dialogue: 0,1:05:12.01,1:05:13.58,Default,,0,0,0,,与试验总次数的比率 Dialogue: 0,1:05:16.32,1:05:17.28,Default,,0,0,0,,这种方法叫做蒙特卡罗方法 Dialogue: 0,1:05:18.04,1:05:22.38,Default,,0,0,0,,它也可以用于计算包含大量变量的积分 Dialogue: 0,1:05:22.94,1:05:25.28,Default,,0,0,0,,其中积分的面积是限定的 Dialogue: 0,1:05:26.27,1:05:28.70,Default,,0,0,0,,回到这里 Dialogue: 0,1:05:29.76,1:05:31.72,Default,,0,0,0,,我们来看看这张幻灯片 Dialogue: 0,1:05:33.96,1:05:36.92,Default,,0,0,0,,我们可以用Cesaro的方法来估算pi的值 Dialogue: 0,1:05:37.19,1:05:43.18,Default,,0,0,0,,通过N次试验 取结果的六分之一 开根号 Dialogue: 0,1:05:43.29,1:05:46.46,Default,,0,0,0,,用蒙特卡罗方法 Dialogue: 0,1:05:46.80,1:05:50.38,Default,,0,0,0,,进行了N次Cesaro实验 Dialogue: 0,1:05:51.37,1:05:57.56,Default,,0,0,0,,这个实验是关于两个随机数的最大公约数的-- Dialogue: 0,1:05:58.96,1:06:01.60,Default,,0,0,0,,你可以看到 我已经在这里进行了一些赋值 Dialogue: 0,1:06:01.84,1:06:03.13,Default,,0,0,0,,就像我写的这样 Dialogue: 0,1:06:04.04,1:06:07.49,Default,,0,0,0,,这个在括号中的RAND Dialogue: 0,1:06:07.49,1:06:09.09,Default,,0,0,0,,这个过程调用 Dialogue: 0,1:06:09.09,1:06:11.39,Default,,0,0,0,,生成了一个与这个RAND不同的值 Dialogue: 0,1:06:11.39,1:06:13.72,Default,,0,0,0,,至少是我写的这样所假设的 Dialogue: 0,1:06:14.62,1:06:16.75,Default,,0,0,0,,这表明这不是一个函数 Dialogue: 0,1:06:18.20,1:06:20.57,Default,,0,0,0,,这里面会有一个不断改变内部状态 Dialogue: 0,1:06:22.27,1:06:28.64,Default,,0,0,0,,如果两个随机数的最大公约数等于1 Dialogue: 0,1:06:28.64,1:06:29.79,Default,,0,0,0,,这就是整个实验过程 Dialogue: 0,1:06:31.48,1:06:35.18,Default,,0,0,0,,那么我有了一个实验方法 用来估算pi的值 Dialogue: 0,1:06:36.51,1:06:39.72,Default,,0,0,0,,我可以轻松地将这个问题分为两个部分 Dialogue: 0,1:06:40.02,1:06:44.70,Default,,0,0,0,,一部分是使用蒙特卡罗方法进行特定的Cesaro实验 就像你刚才看到那个 Dialogue: 0,1:06:44.99,1:06:48.56,Default,,0,0,0,,另一部分就是一般性蒙特卡罗方法的实现 Dialogue: 0,1:06:49.16,1:06:50.27,Default,,0,0,0,,就是这个 Dialogue: 0,1:06:51.04,1:06:55.47,Default,,0,0,0,,如果我想进行N次蒙特卡罗试验 Dialogue: 0,1:06:55.67,1:06:58.36,Default,,0,0,0,,即一个确定的试验次数 和一个确定的实验 Dialogue: 0,1:06:59.31,1:07:00.33,Default,,0,0,0,,我进行实验的方法就是 Dialogue: 0,1:07:00.84,1:07:02.70,Default,,0,0,0,,构建一个迭代过程 Dialogue: 0,1:07:03.31,1:07:07.26,Default,,0,0,0,,这个过程有两个变量 分别是试验的剩余次数和通过次数 Dialogue: 0,1:07:08.35,1:07:09.44,Default,,0,0,0,,也就是实验结果为真的次数 Dialogue: 0,1:07:10.13,1:07:12.21,Default,,0,0,0,,如果剩余次数为0 Dialogue: 0,1:07:12.21,1:07:15.36,Default,,0,0,0,,结果就是通过的次数除以总次数 Dialogue: 0,1:07:16.04,1:07:17.52,Default,,0,0,0,,也就是该概率的估算值 Dialogue: 0,1:07:19.07,1:07:20.04,Default,,0,0,0,,如果剩余次数不是0 Dialogue: 0,1:07:20.04,1:07:22.08,Default,,0,0,0,,如果还有试验要做 Dialogue: 0,1:07:22.08,1:07:23.82,Default,,0,0,0,,那么接下来我们就进行一次试验 Dialogue: 0,1:07:23.85,1:07:27.30,Default,,0,0,0,,我们调用一次没有参数的实验的过程 Dialogue: 0,1:07:27.30,1:07:28.43,Default,,0,0,0,,我们进行这个试验 Dialogue: 0,1:07:29.10,1:07:30.64,Default,,0,0,0,,如果实验结果为真 Dialogue: 0,1:07:30.82,1:07:32.25,Default,,0,0,0,,我们继续循环 Dialogue: 0,1:07:32.62,1:07:35.42,Default,,0,0,0,,试验剩余次数减1 Dialogue: 0,1:07:35.70,1:07:37.48,Default,,0,0,0,,将试验通过次数加1 Dialogue: 0,1:07:38.57,1:07:40.11,Default,,0,0,0,,如果试验的结果为假 Dialogue: 0,1:07:40.41,1:07:42.25,Default,,0,0,0,,我们继续循环 Dialogue: 0,1:07:42.32,1:07:44.38,Default,,0,0,0,,剩余试验次数减1 Dialogue: 0,1:07:44.44,1:07:46.60,Default,,0,0,0,,试验通过次数保持不变 Dialogue: 0,1:07:48.76,1:07:54.59,Default,,0,0,0,,我们以TRIAL为剩余次数 以0为通过次数 开始迭代 Dialogue: 0,1:07:55.42,1:07:57.10,Default,,0,0,0,,多么简洁的小程序啊 Dialogue: 0,1:07:57.74,1:08:00.55,Default,,0,0,0,,我不一定非要进行Cesaro的实验 Dialogue: 0,1:08:00.55,1:08:02.73,Default,,0,0,0,,它可以用来进行很多种蒙特卡罗实验 Dialogue: 0,1:08:03.36,1:08:07.12,Default,,0,0,0,,当然 它依赖于某种随机数生成器的存在 Dialogue: 0,1:08:07.34,1:08:10.99,Default,,0,0,0,,随机数生成器通常是像这种的东西 Dialogue: 0,1:08:13.60,1:08:16.32,Default,,0,0,0,,这是一个随机数生成器-- Dialogue: 0,1:08:17.42,1:08:25.21,Default,,0,0,0,,它实际上就是一个过程 具体行为跟计数器有些相似 Dialogue: 0,1:08:25.61,1:08:27.52,Default,,0,0,0,,它会把X的值更新为 Dialogue: 0,1:08:28.33,1:08:31.82,Default,,0,0,0,,将某个函数应用于X的结果 Dialogue: 0,1:08:32.20,1:08:35.28,Default,,0,0,0,,而这类古怪的函数 Dialogue: 0,1:08:35.39,1:08:40.16,Default,,0,0,0,,你可以在Kunth写的关于编程细节的书中找到 Dialogue: 0,1:08:41.56,1:08:45.75,Default,,0,0,0,,他写的书绝妙而充满了编程细节 Dialogue: 0,1:08:45.75,1:08:48.52,Default,,0,0,0,,虽然我记不住随机数生成器该怎样写 Dialogue: 0,1:08:48.63,1:08:50.62,Default,,0,0,0,,但我可以在书里找出一个来用 Dialogue: 0,1:08:51.64,1:08:54.01,Default,,0,0,0,,最后 我返回了X的值 Dialogue: 0,1:08:54.08,1:08:57.40,Default,,0,0,0,,也就是随机数生成器的内部状态变量 Dialogue: 0,1:08:58.28,1:09:00.75,Default,,0,0,0,,这个状态变量以某种方式被初始化 Dialogue: 0,1:09:01.32,1:09:02.24,Default,,0,0,0,,从而获得了一个值 Dialogue: 0,1:09:03.39,1:09:08.11,Default,,0,0,0,,这个过程被定义在那个变量被约束的上下文中 Dialogue: 0,1:09:10.41,1:09:15.26,Default,,0,0,0,,所以你在这看到的 是一个隐藏的局部状态 Dialogue: 0,1:09:15.87,1:09:20.24,Default,,0,0,0,,这个过程定义在那个上下文中 Dialogue: 0,1:09:21.56,1:09:23.66,Default,,0,0,0,,这样做起来非常容易 Dialogue: 0,1:09:24.88,1:09:25.79,Default,,0,0,0,,而且结果也非常好 Dialogue: 0,1:09:25.99,1:09:27.77,Default,,0,0,0,,设想 我不想用赋值 Dialogue: 0,1:09:29.10,1:09:31.47,Default,,0,0,0,,假设我想写一个不带赋值的程序 Dialogue: 0,1:09:32.73,1:09:33.93,Default,,0,0,0,,我将遇到什么困难? Dialogue: 0,1:09:35.52,1:09:37.40,Default,,0,0,0,,让我们来看看 Dialogue: 0,1:09:37.82,1:09:41.10,Default,,0,0,0,,我要用一下头顶上的投影仪了 Dialogue: 0,1:09:42.06,1:09:42.70,Default,,0,0,0,,多谢 Dialogue: 0,1:09:43.47,1:09:47.66,Default,,0,0,0,,首先 我们来整体看一下 这是一个很庞大的东西 Dialogue: 0,1:09:48.01,1:09:49.90,Default,,0,0,0,,它告诉你有某些东西出了问题 Dialogue: 0,1:09:50.96,1:09:52.75,Default,,0,0,0,,毕竟有这么大一堆东西呢 Dialogue: 0,1:09:53.42,1:09:54.60,Default,,0,0,0,,庞大而单一 Dialogue: 0,1:09:56.76,1:10:00.12,Default,,0,0,0,,你不需要现在去理解或看这里的文本 Dialogue: 0,1:10:00.12,1:10:01.39,Default,,0,0,0,,就把它们看做一个整体 Dialogue: 0,1:10:01.92,1:10:04.89,Default,,0,0,0,,它不是Cesaro的实验 Dialogue: 0,1:10:04.89,1:10:07.90,Default,,0,0,0,,它不是从蒙特卡罗过程中抽取出来的 Dialogue: 0,1:10:09.87,1:10:11.84,Default,,0,0,0,,它不是分离的 让我们来看看为什么 Dialogue: 0,1:10:14.22,1:10:15.85,Default,,0,0,0,,记住 这里的约束是 Dialogue: 0,1:10:15.85,1:10:17.87,Default,,0,0,0,,每个过程 Dialogue: 0,1:10:18.69,1:10:22.20,Default,,0,0,0,,对于同样的参数 将返回同样的值 Dialogue: 0,1:10:22.97,1:10:24.75,Default,,0,0,0,,每个过程就是一个函数 Dialogue: 0,1:10:26.92,1:10:28.50,Default,,0,0,0,,那是另一种约束 Dialogue: 0,1:10:28.50,1:10:31.21,Default,,0,0,0,,因为当我赋值时 我可以改变一些内部状态变量 Dialogue: 0,1:10:31.74,1:10:34.03,Default,,0,0,0,,所以让我们来看看它是怎么出错的 Dialogue: 0,1:10:35.04,1:10:36.14,Default,,0,0,0,,我们从头开始 Dialogue: 0,1:10:37.50,1:10:41.92,Default,,0,0,0,,估算pi的过程看起来是一样的 Dialogue: 0,1:10:42.66,1:10:45.88,Default,,0,0,0,,我取RAMDOM-GCD-TEST应用于N Dialogue: 0,1:10:46.35,1:10:50.22,Default,,0,0,0,,的结果分之6的平方根 Dialogue: 0,1:10:50.74,1:10:51.93,Default,,0,0,0,,就是这个 Dialogue: 0,1:10:52.96,1:10:55.20,Default,,0,0,0,,在这里 我们开始看到了一些有趣的东西 Dialogue: 0,1:10:55.20,1:10:57.93,Default,,0,0,0,,对于以TRAILS为参数的RANDOM-GCD-TEST过程 Dialogue: 0,1:10:58.32,1:10:59.98,Default,,0,0,0,,就像我们之前做的一样 Dialogue: 0,1:11:00.46,1:11:04.66,Default,,0,0,0,,是一个以剩余次数 Dialogue: 0,1:11:04.66,1:11:06.80,Default,,0,0,0,,通过次数 Dialogue: 0,1:11:08.27,1:11:09.71,Default,,0,0,0,,另一个变量X为基准的迭代 Dialogue: 0,1:11:10.75,1:11:11.76,Default,,0,0,0,,这个X是什么? Dialogue: 0,1:11:12.33,1:11:15.20,Default,,0,0,0,,X是随机数发生器的状态 Dialogue: 0,1:11:19.00,1:11:21.16,Default,,0,0,0,,它会在这里被使用 Dialogue: 0,1:11:21.16,1:11:23.79,Default,,0,0,0,,这里的同样的随机更新函数 Dialogue: 0,1:11:23.79,1:11:27.15,Default,,0,0,0,,来自于一个我另外写的随机数发生器 Dialogue: 0,1:11:27.71,1:11:29.32,Default,,0,0,0,,或者从Knuth的书中找一个 Dialogue: 0,1:11:31.56,1:11:33.36,Default,,0,0,0,,X将转化为X1 Dialogue: 0,1:11:33.37,1:11:34.36,Default,,0,0,0,,但我需要两个随机数 Dialogue: 0,1:11:34.81,1:11:36.92,Default,,0,0,0,,X1将被转化为X2 Dialogue: 0,1:11:37.26,1:11:38.44,Default,,0,0,0,,我有两个随机数 Dialogue: 0,1:11:39.50,1:11:42.14,Default,,0,0,0,,然后进行和之前一样的步骤 Dialogue: 0,1:11:42.52,1:11:44.19,Default,,0,0,0,,取X1和X2的最大公约数 Dialogue: 0,1:11:44.22,1:11:47.15,Default,,0,0,0,,如果结果是1 则将X2作为下一个X的值继续循环 Dialogue: 0,1:11:54.78,1:11:55.98,Default,,0,0,0,,这里所发生的 Dialogue: 0,1:11:56.88,1:11:58.70,Default,,0,0,0,,随机数发生器的状态 Dialogue: 0,1:11:58.73,1:12:01.70,Default,,0,0,0,,不再被限制于其内部 Dialogue: 0,1:12:01.80,1:12:02.73,Default,,0,0,0,,它已经暴露了出来 Dialogue: 0,1:12:03.33,1:12:05.50,Default,,0,0,0,,它已经被暴露在 Dialogue: 0,1:12:05.50,1:12:10.08,Default,,0,0,0,,我们的的蒙特卡罗实验的过程中 Dialogue: 0,1:12:10.70,1:12:11.87,Default,,0,0,0,,但比那更糟糕的是 Dialogue: 0,1:12:11.87,1:12:16.24,Default,,0,0,0,,同样的 因为它也被包含在我们的Cesaro实验中 Dialogue: 0,1:12:16.78,1:12:19.48,Default,,0,0,0,,它被暴露了两次 因为Cesaro被调用了两次 Dialogue: 0,1:12:20.86,1:12:22.47,Default,,0,0,0,,每次有不同的值 Dialogue: 0,1:12:22.47,1:12:25.16,Default,,0,0,0,,如果我要进行一个合理的实验的话 Dialogue: 0,1:12:26.32,1:12:28.32,Default,,0,0,0,,所以Cesaro也不能成为函数了 Dialogue: 0,1:12:31.04,1:12:35.69,Default,,0,0,0,,除非我把随机数发生器的种子传给它 Dialogue: 0,1:12:36.52,1:12:39.37,Default,,0,0,0,,所以很不幸 随机数发生器的种子 Dialogue: 0,1:12:39.37,1:12:42.77,Default,,0,0,0,,从随机数发生器中暴露到了Cesaro内部 Dialogue: 0,1:12:42.88,1:12:45.16,Default,,0,0,0,,被暴露在蒙特卡罗实验中 Dialogue: 0,1:12:45.64,1:12:49.12,Default,,0,0,0,,很不幸 这里的蒙特卡罗实验不再是通用的了 Dialogue: 0,1:12:50.25,1:12:51.80,Default,,0,0,0,,这里的蒙特卡罗实验 Dialogue: 0,1:12:52.03,1:12:54.73,Default,,0,0,0,,知道了我在实验中需要多少个随机数 Dialogue: 0,1:12:58.96,1:12:59.74,Default,,0,0,0,,这真的很糟糕 Dialogue: 0,1:13:00.08,1:13:02.54,Default,,0,0,0,,我失去了将问题分解开来的能力 Dialogue: 0,1:13:03.44,1:13:09.12,Default,,0,0,0,,因为我不愿意接受信息的循环 Dialogue: 0,1:13:09.50,1:13:12.43,Default,,0,0,0,,反馈的过程 Dialogue: 0,1:13:12.88,1:13:15.94,Default,,0,0,0,,这之前都是发生在随机数发生器内部 Dialogue: 0,1:13:15.94,1:13:21.21,Default,,0,0,0,,也就是赋值给一个限制在随机数生成器内部的状态变量 Dialogue: 0,1:13:22.92,1:13:25.48,Default,,0,0,0,,所以实际上 随机数发生器是一个对象 Dialogue: 0,1:13:25.92,1:13:27.37,Default,,0,0,0,,它有一个内部状态变量 Dialogue: 0,1:13:28.06,1:13:29.36,Default,,0,0,0,,它不受任何东西影响 Dialogue: 0,1:13:29.37,1:13:31.60,Default,,0,0,0,,但是它会给你某些东西 把它的力量赐予你 Dialogue: 0,1:13:32.80,1:13:34.28,Default,,0,0,0,,那是我们现在缺少的 Dialogue: 0,1:13:38.00,1:13:40.73,Default,,0,0,0,,好 我认为我已经知道了 Dialogue: 0,1:13:40.73,1:13:42.30,Default,,0,0,0,,引入赋值的充分理由 Dialogue: 0,1:13:42.83,1:13:45.24,Default,,0,0,0,,并且一些看起来很圆满 Dialogue: 0,1:13:45.38,1:13:50.70,Default,,0,0,0,,如果赋值是一个好东西 Dialogue: 0,1:13:51.74,1:13:53.04,Default,,0,0,0,,并且赋值是值得的 这不是很好吗? Dialogue: 0,1:13:53.28,1:13:54.14,Default,,0,0,0,,我不是很确定 Dialogue: 0,1:13:55.34,1:13:57.04,Default,,0,0,0,,Mr. Gilbert和Sullivan说过 Dialogue: 0,1:13:57.04,1:13:58.51,Default,,0,0,0,,事物往往不像表面看到的那样 Dialogue: 0,1:13:58.51,1:14:00.35,Default,,0,0,0,,脱脂牛奶也能装成奶油 Dialogue: 0,1:14:01.87,1:14:03.90,Default,,0,0,0,,谁有什么问题吗? Dialogue: 0,1:14:16.97,1:14:18.30,Default,,0,0,0,,在座的有哲学家吗? Dialogue: 0,1:14:20.06,1:14:22.03,Default,,0,0,0,,有人想要讨论有关“对象”的问题吗? Dialogue: 0,1:14:24.32,1:14:25.50,Default,,0,0,0,,你们已经一头雾水了是吧? Dialogue: 0,1:14:29.72,1:14:30.72,Default,,0,0,0,,你们还没有完成家庭作业呢 Dialogue: 0,1:14:30.73,1:14:32.00,Default,,0,0,0,,你们需要提一个好问题 Dialogue: 0,1:14:36.35,1:14:37.44,Default,,0,0,0,,好了 Dialogue: 0,1:14:39.97,1:14:42.33,Default,,0,0,0,,感谢你们 我们下课吧 Dialogue: 0,1:14:47.90,1:15:05.69,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:14:47.90,1:15:05.69,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec5a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: EN Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 1252 Active Line: 1262 Video Position: 134759 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:09.92,0:00:13.63,EN,,0,0,0,,Assignment, State, and Side-effects Dialogue: 0,0:00:18.31,0:00:22.00,EN,,0,0,0,,PROFESSOR: Well, so far we've invented enough programming Dialogue: 0,0:00:22.25,0:00:24.06,EN,,0,0,0,,to do some very complicated things. Dialogue: 0,0:00:24.76,0:00:29.66,EN,,0,0,0,,And you surely learned a lot about programming at this point. Dialogue: 0,0:00:29.66,0:00:31.48,EN,,0,0,0,,You've learned almost all the most important tricks Dialogue: 0,0:00:31.86,0:00:35.87,EN,,0,0,0,,that usually don't get taught to people until they have had a lot of experience. Dialogue: 0,0:00:36.41,0:00:40.08,EN,,0,0,0,,For example, data directed programming is a major trick, Dialogue: 0,0:00:40.75,0:00:43.15,EN,,0,0,0,,and yesterday you also saw an interpreted language. Dialogue: 0,0:00:45.02,0:00:48.46,EN,,0,0,0,,We did this all in a computer language, Dialogue: 0,0:00:48.54,0:00:49.63,EN,,0,0,0,,at this point, Dialogue: 0,0:00:49.88,0:00:51.95,EN,,0,0,0,,where there was no assignment statement. Dialogue: 0,0:00:53.77,0:00:58.17,EN,,0,0,0,,And presumably, for those of you who've seen your Basic or Pascal or whatever, Dialogue: 0,0:00:58.68,0:01:01.23,EN,,0,0,0,,that's usually considered the most important thing. Dialogue: 0,0:01:01.79,0:01:03.82,EN,,0,0,0,,Well today, we're going to do something horrible. Dialogue: 0,0:01:03.82,0:01:05.45,EN,,0,0,0,,We're going to add an assignment statement. Dialogue: 0,0:01:07.21,0:01:09.14,EN,,0,0,0,,And since we can do all these wonderful things without it, Dialogue: 0,0:01:09.14,0:01:10.17,EN,,0,0,0,,why should we add it? Dialogue: 0,0:01:10.99,0:01:12.43,EN,,0,0,0,,An important thing to understand it Dialogue: 0,0:01:12.46,0:01:15.71,EN,,0,0,0,,is that today we're going to first of all, have a rule, Dialogue: 0,0:01:16.48,0:01:17.93,EN,,0,0,0,,which is going to always be obeyed, Dialogue: 0,0:01:17.93,0:01:20.80,EN,,0,0,0,,which is the only reason we ever add a feature to our language Dialogue: 0,0:01:21.53,0:01:23.14,EN,,0,0,0,,is because there is a good reason. Dialogue: 0,0:01:23.93,0:01:27.28,EN,,0,0,0,,And the good reason is going to boil down to the ability, Dialogue: 0,0:01:27.42,0:01:31.51,EN,,0,0,0,,you now get an ability to break a problem into pieces that are different sets of pieces Dialogue: 0,0:01:31.51,0:01:33.44,EN,,0,0,0,,then you could have broken it down without that, Dialogue: 0,0:01:34.38,0:01:36.16,EN,,0,0,0,,give you another means of decomposition. Dialogue: 0,0:01:38.30,0:01:39.45,EN,,0,0,0,,However, let's just start. Dialogue: 0,0:01:39.45,0:01:41.88,EN,,0,0,0,,Let me quick begin by reviewing Dialogue: 0,0:01:41.88,0:01:47.37,EN,,0,0,0,,the kind of language that we have now. Dialogue: 0,0:01:48.16,0:01:50.44,EN,,0,0,0,,We've been writing what's called functional programs. Dialogue: 0,0:01:51.21,0:01:52.52,EN,,0,0,0,,And functional programs Dialogue: 0,0:01:53.04,0:01:57.95,EN,,0,0,0,,are a kind of encoding of mathematical truths. Dialogue: 0,0:01:58.88,0:02:00.51,EN,,0,0,0,,For example, when we look at Dialogue: 0,0:02:00.51,0:02:04.09,EN,,0,0,0,,the factorial procedure that you see on the slide here, Dialogue: 0,0:02:05.07,0:02:06.62,EN,,0,0,0,,it's basically two clauses. Dialogue: 0,0:02:06.99,0:02:08.64,EN,,0,0,0,,If n is one, the result is one, Dialogue: 0,0:02:08.64,0:02:11.20,EN,,0,0,0,,otherwise n times factorial n minus one. Dialogue: 0,0:02:11.20,0:02:12.33,EN,,0,0,0,,That's factorial of n. Dialogue: 0,0:02:12.89,0:02:14.27,EN,,0,0,0,,Well, that is factorial of n. Dialogue: 0,0:02:14.83,0:02:16.87,EN,,0,0,0,,And written down in some other obscure notation Dialogue: 0,0:02:16.87,0:02:19.32,EN,,0,0,0,,that you might have learned in calculus classes, Dialogue: 0,0:02:20.30,0:02:22.11,EN,,0,0,0,,Ahh.. mathematical logic, Dialogue: 0,0:02:22.11,0:02:26.36,EN,,0,0,0,,what you see there is if n equals one, Dialogue: 0,0:02:27.13,0:02:29.90,EN,,0,0,0,,for the result of n factorial is one, otherwise, Dialogue: 0,0:02:29.90,0:02:32.56,EN,,0,0,0,,greater than one, n factorial is n times n minus one factorial. Dialogue: 0,0:02:32.56,0:02:33.55,EN,,0,0,0,,True statements, Dialogue: 0,0:02:34.92,0:02:36.70,EN,,0,0,0,,that's the kind of language we've been using. Dialogue: 0,0:02:37.00,0:02:39.23,EN,,0,0,0,,And whenever we have true statements of that sort, Dialogue: 0,0:02:39.53,0:02:46.65,EN,,0,0,0,,there is a kind of, a way of understanding how they work Dialogue: 0,0:02:47.40,0:02:51.12,EN,,0,0,0,,which is that such processes can be evolved by substitution. Dialogue: 0,0:02:51.29,0:02:53.71,EN,,0,0,0,,And so we see on the second slide here, Dialogue: 0,0:02:54.99,0:02:58.81,EN,,0,0,0,,that the way we understand the execution Dialogue: 0,0:02:58.83,0:03:03.50,EN,,0,0,0,,implied by those statements in arranged in that order, Dialogue: 0,0:03:04.04,0:03:07.76,EN,,0,0,0,,is that you do successive substitutions of arguments Dialogue: 0,0:03:07.87,0:03:10.88,EN,,0,0,0,,for formal parameters in the body of a procedure. Dialogue: 0,0:03:12.00,0:03:14.51,EN,,0,0,0,,This is basically a sequence of equalities. Dialogue: 0,0:03:14.61,0:03:17.25,EN,,0,0,0,,Factorial four is four times factorial three. Dialogue: 0,0:03:17.25,0:03:20.05,EN,,0,0,0,,That is four times three times factorial of two Dialogue: 0,0:03:20.05,0:03:21.01,EN,,0,0,0,,and so on. Dialogue: 0,0:03:21.23,0:03:23.87,EN,,0,0,0,,We're always preserving truth. Dialogue: 0,0:03:25.23,0:03:28.84,EN,,0,0,0,,Even though we're talking about true statements, Dialogue: 0,0:03:28.84,0:03:31.96,EN,,0,0,0,,there might be more than one organization of these true statements Dialogue: 0,0:03:31.96,0:03:35.12,EN,,0,0,0,,to describe the computation of a particular function, Dialogue: 0,0:03:36.32,0:03:38.42,EN,,0,0,0,,the computation of the value of a particular function. Dialogue: 0,0:03:38.42,0:03:40.92,EN,,0,0,0,,So, for example, looking at the next one here. Dialogue: 0,0:03:41.48,0:03:49.02,EN,,0,0,0,,Here is a way of looking at the sum of n and m. Dialogue: 0,0:03:49.53,0:03:52.04,EN,,0,0,0,,And we did this one by a recursive process. Dialogue: 0,0:03:52.89,0:03:58.16,EN,,0,0,0,,It's the increment of the sum of the decrement of n and m. Dialogue: 0,0:04:00.08,0:04:05.62,EN,,0,0,0,,And, of course, there is some piece of mathematical logic here that describes that. Dialogue: 0,0:04:06.17,0:04:10.49,EN,,0,0,0,,It's the increment of the sum of the decrement of n and m, Dialogue: 0,0:04:11.40,0:04:12.22,EN,,0,0,0,,just like that. Dialogue: 0,0:04:13.10,0:04:16.40,EN,,0,0,0,,So there's nothing particularly magic about that. Dialogue: 0,0:04:16.41,0:04:20.01,EN,,0,0,0,,And, of course, if we can also look at an iterative process for the same, Dialogue: 0,0:04:20.19,0:04:24.92,EN,,0,0,0,,a program that evolves an iterative process, for the same function. Dialogue: 0,0:04:25.26,0:04:27.56,EN,,0,0,0,,These are two things that compute the same answer. Dialogue: 0,0:04:30.08,0:04:34.83,EN,,0,0,0,,And we have equivalent mathematical truths that are arranged there. Dialogue: 0,0:04:36.65,0:04:39.93,EN,,0,0,0,,And just the way you arrange those truths determine the particular process. Dialogue: 0,0:04:40.30,0:04:43.42,EN,,0,0,0,,In the way choose and arrange them determines the process that's evolved. Dialogue: 0,0:04:44.33,0:04:48.60,EN,,0,0,0,,So we have the flexibility of talking about both the function to be computed, Dialogue: 0,0:04:48.60,0:04:50.19,EN,,0,0,0,,and the method by which it's computed. Dialogue: 0,0:04:50.60,0:04:52.60,EN,,0,0,0,,So it's not clear we need more. Dialogue: 0,0:04:53.61,0:04:55.50,EN,,0,0,0,,However, today I'm going to this awful thing. Dialogue: 0,0:04:55.50,0:04:58.43,EN,,0,0,0,,I'm going to introduce this assignment operation. Dialogue: 0,0:04:58.89,0:05:00.41,EN,,0,0,0,,Now, what is this? Dialogue: 0,0:05:02.89,0:05:09.22,EN,,0,0,0,,Well, first of all, there is going to be another kind of kind of statement, if you will, Dialogue: 0,0:05:09.22,0:05:10.84,EN,,0,0,0,,in a programming language called Set! Dialogue: 0,0:05:12.41,0:05:15.96,EN,,0,0,0,,And SET! -- Things that do things like assignment, Dialogue: 0,0:05:15.96,0:05:15.98,EN,,0,0,0,, Dialogue: 0,0:05:15.98,0:05:17.85,EN,,0,0,0,,I'm going to put exclamation points after. Dialogue: 0,0:05:18.51,0:05:20.96,EN,,0,0,0,,We'll talk about what that means in a second. Dialogue: 0,0:05:20.96,0:05:23.01,EN,,0,0,0,,The exclamation point, again like question mark, Dialogue: 0,0:05:23.01,0:05:25.88,EN,,0,0,0,,is an arbitrary thing we attach to the symbol which is the name, Dialogue: 0,0:05:25.88,0:05:27.88,EN,,0,0,0,,has no significance to the system. Dialogue: 0,0:05:28.08,0:05:30.21,EN,,0,0,0,,The only significance is to me and you Dialogue: 0,0:05:30.40,0:05:34.41,EN,,0,0,0,,to alert you that this is an assignment of some sort. Dialogue: 0,0:05:35.88,0:05:40.06,EN,,0,0,0,,But we're going to set a variable to a value. Dialogue: 0,0:05:43.74,0:05:45.13,EN,,0,0,0,,And what that's going to mean Dialogue: 0,0:05:45.13,0:05:48.28,EN,,0,0,0,,is that there is a time at which something happens. Dialogue: 0,0:05:48.65,0:05:49.61,EN,,0,0,0,,Here's a time. Dialogue: 0,0:05:49.86,0:05:52.14,EN,,0,0,0,,If I have time going this way, Dialogue: 0,0:05:53.50,0:05:54.82,EN,,0,0,0,,it's a time axis. Dialogue: 0,0:05:55.00,0:05:57.82,EN,,0,0,0,,Time progresses by walking down the page. Dialogue: 0,0:05:58.70,0:06:00.92,EN,,0,0,0,,Then an assignment is the first thing we have Dialogue: 0,0:06:00.92,0:06:04.30,EN,,0,0,0,,that produces the difference between a before and an after. Dialogue: 0,0:06:06.59,0:06:08.72,EN,,0,0,0,,All the other programs that we've written, Dialogue: 0,0:06:09.18,0:06:10.68,EN,,0,0,0,,that have no assignments in them, Dialogue: 0,0:06:10.68,0:06:13.12,EN,,0,0,0,,the order in which they were evaluated didn't matter. Dialogue: 0,0:06:14.70,0:06:15.96,EN,,0,0,0,,But assignment is special, Dialogue: 0,0:06:15.96,0:06:17.69,EN,,0,0,0,,it produces a moment in time. Dialogue: 0,0:06:17.96,0:06:24.73,EN,,0,0,0,,So there is a moment before the set occurs and after, Dialogue: 0,0:06:27.61,0:06:32.70,EN,,0,0,0,,such that after this moment in time, Dialogue: 0,0:06:33.60,0:06:43.76,EN,,0,0,0,,the variable has the value, value. Dialogue: 0,0:06:49.23,0:06:51.50,EN,,0,0,0,,Independent of what value it had before, Dialogue: 0,0:06:52.80,0:06:55.79,EN,,0,0,0,,set! changes the value of the variable. Dialogue: 0,0:06:57.69,0:06:58.75,EN,,0,0,0,,Until this moment, Dialogue: 0,0:06:58.75,0:07:01.50,EN,,0,0,0,,we had nothing that changed. Dialogue: 0,0:07:03.21,0:07:04.11,EN,,0,0,0,,So, for example, Dialogue: 0,0:07:04.84,0:07:06.23,EN,,0,0,0,,one of the things we can think of Dialogue: 0,0:07:06.23,0:07:09.42,EN,,0,0,0,,is that the procedures we write for something like factorial Dialogue: 0,0:07:09.64,0:07:12.75,EN,,0,0,0,,are in fact pretty much identical to the function factorial. Dialogue: 0,0:07:13.77,0:07:16.44,EN,,0,0,0,,Factorial of four, if I write fact4, Dialogue: 0,0:07:17.23,0:07:19.15,EN,,0,0,0,,independent of what context it's in, Dialogue: 0,0:07:19.69,0:07:21.29,EN,,0,0,0,,and independent of how many times I write it, Dialogue: 0,0:07:21.29,0:07:22.35,EN,,0,0,0,,I always get the same answer. Dialogue: 0,0:07:23.29,0:07:24.12,EN,,0,0,0,,It's always 24. Dialogue: 0,0:07:25.37,0:07:28.92,EN,,0,0,0,,It's a unique map from the argument to the answer. Dialogue: 0,0:07:30.30,0:07:32.65,EN,,0,0,0,,And all the programs we've written so far are like that. Dialogue: 0,0:07:33.52,0:07:36.03,EN,,0,0,0,,However, once I have assignment, that isn't true. Dialogue: 0,0:07:36.96,0:07:38.16,EN,,0,0,0,,So, for example, Dialogue: 0,0:07:39.18,0:07:48.52,EN,,0,0,0,,if I were to define count to be one. Dialogue: 0,0:07:50.00,0:07:52.41,EN,,0,0,0,,And then I'm going to define also a procedure, Dialogue: 0,0:07:55.16,0:07:56.83,EN,,0,0,0,,a simple procedure called demo, Dialogue: 0,0:07:59.52,0:08:03.84,EN,,0,0,0,,which takes argument x and does the following operations. Dialogue: 0,0:08:03.84,0:08:09.62,EN,,0,0,0,,It first sets x to x plus one. Dialogue: 0,0:08:09.62,0:08:11.77,EN,,0,0,0,,My gosh, this looksjust like FORTRAN, right-- Dialogue: 0,0:08:13.16,0:08:14.17,EN,,0,0,0,,in a funny syntax. Dialogue: 0,0:08:16.80,0:08:21.37,EN,,0,0,0,,And then add to x count, Dialogue: 0,0:08:22.14,0:08:24.14,EN,,0,0,0,,Oh, I just made a mistake. Dialogue: 0,0:08:24.38,0:08:25.23,EN,,0,0,0,,I want to say, Dialogue: 0,0:08:25.47,0:08:27.12,EN,,0,0,0,,set! count to one plus count. Dialogue: 0,0:08:30.37,0:08:31.79,EN,,0,0,0,,It's this thing defined here. Dialogue: 0,0:08:34.41,0:08:36.51,EN,,0,0,0,,And then add and said plus x count. Dialogue: 0,0:08:40.35,0:08:42.06,EN,,0,0,0,,Then I can try this procedure. Dialogue: 0,0:08:42.48,0:08:43.20,EN,,0,0,0,,Let's run it. Dialogue: 0,0:08:43.92,0:08:47.22,EN,,0,0,0,,So, suppose I get a prompt and I say, Dialogue: 0,0:08:47.48,0:08:48.68,EN,,0,0,0,,demo 3 Dialogue: 0,0:08:52.19,0:08:53.20,EN,,0,0,0,,Well, what happens here? Dialogue: 0,0:08:53.74,0:08:55.28,EN,,0,0,0,,The first thing that happens Dialogue: 0,0:08:55.53,0:08:56.89,EN,,0,0,0,,is count is currently one. Dialogue: 0,0:08:56.89,0:08:58.40,EN,,0,0,0,,Currently, there is a time. Dialogue: 0,0:08:59.12,0:09:00.29,EN,,0,0,0,,We're talking about time. Dialogue: 0,0:09:00.62,0:09:01.74,EN,,0,0,0,,x gets three. Dialogue: 0,0:09:02.92,0:09:04.03,EN,,0,0,0,,At this moment, Dialogue: 0,0:09:04.67,0:09:07.53,EN,,0,0,0,,I say, oh yes, count is incremented, so count is two. Dialogue: 0,0:09:09.02,0:09:10.44,EN,,0,0,0,,two plus three is five. Dialogue: 0,0:09:10.80,0:09:12.43,EN,,0,0,0,,So the answer I get out is five. Dialogue: 0,0:09:14.48,0:09:21.58,EN,,0,0,0,,Then I say, demo of say, three again. Dialogue: 0,0:09:23.60,0:09:24.56,EN,,0,0,0,,Okay, What do I get? Dialogue: 0,0:09:24.83,0:09:27.40,EN,,0,0,0,,Well, now count is two, it's not one anymore, Dialogue: 0,0:09:28.91,0:09:30.35,EN,,0,0,0,,because I have incremented it. Dialogue: 0,0:09:30.92,0:09:32.64,EN,,0,0,0,,But now I go through this process, Dialogue: 0,0:09:32.72,0:09:33.66,EN,,0,0,0,,three goes into x, Dialogue: 0,0:09:34.17,0:09:37.40,EN,,0,0,0,,count becomes one plus count, so that's three now. Dialogue: 0,0:09:38.08,0:09:39.62,EN,,0,0,0,,The sum of those two is six, Dialogue: 0,0:09:39.62,0:09:40.94,EN,,0,0,0,,so the answer is six. Dialogue: 0,0:09:41.92,0:09:43.03,EN,,0,0,0,,And what we see Dialogue: 0,0:09:43.03,0:09:44.72,EN,,0,0,0,,is the same expression Dialogue: 0,0:09:45.08,0:09:46.64,EN,,0,0,0,,leads to two different answers, Dialogue: 0,0:09:48.75,0:09:49.96,EN,,0,0,0,,depending upon time. Dialogue: 0,0:09:52.08,0:09:53.74,EN,,0,0,0,,So demo is not a function, Dialogue: 0,0:09:54.17,0:09:56.12,EN,,0,0,0,,does not compute a mathematical function. Dialogue: 0,0:09:59.88,0:10:02.09,EN,,0,0,0,,In fact, you could also see why now, of course, Dialogue: 0,0:10:02.84,0:10:06.41,EN,,0,0,0,,this is the first place where the substitution model isn't going to work. Dialogue: 0,0:10:07.72,0:10:09.55,EN,,0,0,0,,This kills the substitution model dead. Dialogue: 0,0:10:11.28,0:10:13.82,EN,,0,0,0,,You know, with quotation there were some little problems Dialogue: 0,0:10:13.85,0:10:17.18,EN,,0,0,0,,that a philosopher might notice with substitutions, Dialogue: 0,0:10:17.18,0:10:19.87,EN,,0,0,0,,because you have to worry about what deductions you can make Dialogue: 0,0:10:20.91,0:10:22.12,EN,,0,0,0,,when you substitute into quotes, Dialogue: 0,0:10:22.34,0:10:23.92,EN,,0,0,0,,if you're allowed to do that at all. Dialogue: 0,0:10:25.08,0:10:25.60,EN,,0,0,0,,But Dialogue: 0,0:10:26.06,0:10:28.00,EN,,0,0,0,,here the substitution model is dead, Dialogue: 0,0:10:28.11,0:10:29.40,EN,,0,0,0,,can't do anything at all. Dialogue: 0,0:10:29.64,0:10:30.57,EN,,0,0,0,,Because, Dialogue: 0,0:10:30.57,0:10:35.85,EN,,0,0,0,,Supposing I wanted to use a substitution model to consider substituting for count? Dialogue: 0,0:10:37.10,0:10:41.16,EN,,0,0,0,,Well, my gosh, if I substitute for here and here, Dialogue: 0,0:10:41.69,0:10:42.96,EN,,0,0,0,,they're different ones. Dialogue: 0,0:10:44.44,0:10:45.96,EN,,0,0,0,,It's not the same count any more. Dialogue: 0,0:10:46.48,0:10:47.64,EN,,0,0,0,,I get the wrong answer. Dialogue: 0,0:10:47.97,0:10:50.14,EN,,0,0,0,,The substitution model is a static phenomenon Dialogue: 0,0:10:51.18,0:10:52.56,EN,,0,0,0,,describes things that are true Dialogue: 0,0:10:53.93,0:10:55.29,EN,,0,0,0,,and not things that change. Dialogue: 0,0:10:55.50,0:10:57.04,EN,,0,0,0,,Here, we have truths that change. Dialogue: 0,0:11:00.60,0:11:06.74,EN,,0,0,0,,OK, Well, before I give you any understanding of this, Dialogue: 0,0:11:06.74,0:11:07.79,EN,,0,0,0,,this is very bad. Dialogue: 0,0:11:07.79,0:11:09.72,EN,,0,0,0,,Now, we've lost our model of computation. Dialogue: 0,0:11:10.28,0:11:10.80,EN,,0,0,0,,And, Dialogue: 0,0:11:11.48,0:11:13.69,EN,,0,0,0,,pretty soon, I'm going to have to build you a new model of computation. Dialogue: 0,0:11:14.66,0:11:17.87,EN,,0,0,0,,But ours plays with this, just now, in an informal sense. Dialogue: 0,0:11:18.56,0:11:20.16,EN,,0,0,0,,Of course, what you already see Dialogue: 0,0:11:20.51,0:11:22.70,EN,,0,0,0,,is that when I have something like assignment, Dialogue: 0,0:11:23.12,0:11:24.51,EN,,0,0,0,,the model that we're going to need Dialogue: 0,0:11:24.51,0:11:26.89,EN,,0,0,0,,is different from the model that we had before Dialogue: 0,0:11:26.89,0:11:30.93,EN,,0,0,0,,in that, the variables, those symbols like count, or x Dialogue: 0,0:11:30.93,0:11:34.07,EN,,0,0,0,,are no longer going to refer to the values they have, Dialogue: 0,0:11:34.07,0:11:37.31,EN,,0,0,0,,but rather to some sort of place where the value restored. Dialogue: 0,0:11:37.68,0:11:39.47,EN,,0,0,0,,We're going to have to think that way for a while. Dialogue: 0,0:11:40.20,0:11:42.11,EN,,0,0,0,,And it's going to be a very bad thing Dialogue: 0,0:11:42.11,0:11:43.47,EN,,0,0,0,,and cause a lot of trouble. Dialogue: 0,0:11:44.49,0:11:48.25,EN,,0,0,0,,And so, as I said, the very fact that we're inventing this bad thing, Dialogue: 0,0:11:48.25,0:11:50.09,EN,,0,0,0,,means that there had better be a good reason for it, Dialogue: 0,0:11:50.37,0:11:52.86,EN,,0,0,0,,otherwise, just a waste of time and a lot of effort. Dialogue: 0,0:11:53.39,0:11:55.55,EN,,0,0,0,,Let's just look at some of it just to play. Dialogue: 0,0:11:55.88,0:11:58.59,EN,,0,0,0,,Supposing we write down the functional version, Dialogue: 0,0:11:58.59,0:12:00.48,EN,,0,0,0,,functional meaning in the old style, Dialogue: 0,0:12:01.37,0:12:04.60,EN,,0,0,0,,of factorial by an iterative process. Dialogue: 0,0:12:09.59,0:12:13.28,EN,,0,0,0,,Factorial of n. Dialogue: 0,0:12:18.38,0:12:24.35,EN,,0,0,0,,we're going to iterate of m and i, Dialogue: 0,0:12:26.12,0:12:33.13,EN,,0,0,0,,which says if i is greater than n, Dialogue: 0,0:12:33.77,0:12:35.51,EN,,0,0,0,,then the result is m, Dialogue: 0,0:12:36.30,0:12:37.39,EN,,0,0,0,,otherwise, Dialogue: 0,0:12:39.79,0:12:46.82,EN,,0,0,0,,the result of iterating the product of i and m. Dialogue: 0,0:12:46.82,0:12:49.95,EN,,0,0,0,,So m is going to be the product that I'm accumulating. Dialogue: 0,0:12:51.58,0:12:52.62,EN,,0,0,0,,m is the product. Dialogue: 0,0:12:57.97,0:13:00.17,EN,,0,0,0,,And the count I'm going to increase by one. Dialogue: 0,0:13:04.62,0:13:10.97,EN,,0,0,0,,Plus, ITER, ELSE, COND, define. Dialogue: 0,0:13:11.95,0:13:13.04,EN,,0,0,0,,I'm going to start this up. Dialogue: 0,0:13:17.16,0:13:19.79,EN,,0,0,0,,And these days, you should have no trouble reading something like this. Dialogue: 0,0:13:20.86,0:13:25.15,EN,,0,0,0,,What I have here is a product there being accumulated and a counter. Dialogue: 0,0:13:26.48,0:13:28.46,EN,,0,0,0,,I start them up both at one. Dialogue: 0,0:13:28.89,0:13:30.92,EN,,0,0,0,,I'm going to buzz the counter up, Dialogue: 0,0:13:30.92,0:13:33.12,EN,,0,0,0,,i goes to i plus one every time around. Dialogue: 0,0:13:34.56,0:13:37.47,EN,,0,0,0,,But that's only way our putting a time on the process, Dialogue: 0,0:13:38.48,0:13:40.04,EN,,0,0,0,,each of this is just a set of truths, Dialogue: 0,0:13:40.49,0:13:41.34,EN,,0,0,0,,true rules. Dialogue: 0,0:13:42.81,0:13:46.13,EN,,0,0,0,,And m is going to get a new values of i and m, Dialogue: 0,0:13:46.13,0:13:47.82,EN,,0,0,0,,i times m each time around, Dialogue: 0,0:13:48.68,0:13:50.48,EN,,0,0,0,,and eventually i is going to be bigger than n, Dialogue: 0,0:13:50.49,0:13:52.06,EN,,0,0,0,,in which case, the answer's going to be m. Dialogue: 0,0:13:52.67,0:13:54.80,EN,,0,0,0,,Now, I'm speaking to you, use time in this. Dialogue: 0,0:13:55.68,0:13:57.45,EN,,0,0,0,,That's just because I know how the computer works. Dialogue: 0,0:13:58.25,0:13:59.24,EN,,0,0,0,,But I didn't have to. Dialogue: 0,0:13:59.26,0:14:02.30,EN,,0,0,0,,This could be a purely mathematical description at this point, Dialogue: 0,0:14:02.30,0:14:03.74,EN,,0,0,0,,because substitution will work for this. Dialogue: 0,0:14:05.10,0:14:08.14,EN,,0,0,0,,But let's set right down a similar sort of program, Dialogue: 0,0:14:08.30,0:14:09.95,EN,,0,0,0,,using the same algorithm, Dialogue: 0,0:14:10.73,0:14:12.11,EN,,0,0,0,,but with assignments. Dialogue: 0,0:14:15.69,0:14:17.16,EN,,0,0,0,,So this is called the functional version. Dialogue: 0,0:14:23.72,0:14:25.56,EN,,0,0,0,,I want to write down an imperative version. Dialogue: 0,0:14:34.48,0:14:35.39,EN,,0,0,0,,Factorial of n. Dialogue: 0,0:14:35.92,0:14:37.74,EN,,0,0,0,,I'm going to create my two variables. Dialogue: 0,0:14:40.16,0:14:45.53,EN,,0,0,0,,Let i initialize itself to one, Dialogue: 0,0:14:46.32,0:14:49.77,EN,,0,0,0,,and m be initialized to one, similar. Dialogue: 0,0:14:51.15,0:14:52.19,EN,,0,0,0,,We'll create a loop Dialogue: 0,0:14:59.31,0:15:07.27,EN,,0,0,0,,which has COND greater than i, and if i is greater than n, we're done. Dialogue: 0,0:15:07.27,0:15:08.87,EN,,0,0,0,,And the result is m, Dialogue: 0,0:15:08.87,0:15:10.38,EN,,0,0,0,,the product I'm accumulating. Dialogue: 0,0:15:10.87,0:15:11.77,EN,,0,0,0,,Otherwise, Dialogue: 0,0:15:15.52,0:15:17.40,EN,,0,0,0,,I'm going to write down three things to do. Dialogue: 0,0:15:19.26,0:15:27.05,EN,,0,0,0,,I'm going to set! m to the product of i and m, Dialogue: 0,0:15:29.36,0:15:35.20,EN,,0,0,0,,set! i to the sum of i and one, Dialogue: 0,0:15:37.85,0:15:39.31,EN,,0,0,0,,and go around the loop again. Dialogue: 0,0:15:40.41,0:15:43.02,EN,,0,0,0,,Looks very familiar to you FORTRAN programmers. Dialogue: 0,0:15:44.73,0:15:46.64,EN,,0,0,0,,ELSE, COND, define, Dialogue: 0,0:15:46.64,0:15:47.88,EN,,0,0,0,,funny syntax though. Dialogue: 0,0:15:51.13,0:15:52.27,EN,,0,0,0,,Start the loop up, Dialogue: 0,0:15:56.10,0:15:57.56,EN,,0,0,0,,and that's the program. Dialogue: 0,0:15:59.15,0:16:00.52,EN,,0,0,0,,Now, this program, Dialogue: 0,0:16:01.31,0:16:02.49,EN,,0,0,0,,how do we think about it? Dialogue: 0,0:16:02.71,0:16:04.25,EN,,0,0,0,,Well, let's just say what we're seeing here. Dialogue: 0,0:16:04.84,0:16:07.47,EN,,0,0,0,,There are two local variables, i and m, Dialogue: 0,0:16:07.47,0:16:09.02,EN,,0,0,0,,that have been initialized to one. Dialogue: 0,0:16:10.72,0:16:13.89,EN,,0,0,0,,Every time around the loop, I test to see if i is greater than n, Dialogue: 0,0:16:13.89,0:16:15.08,EN,,0,0,0,,which is the input argument, Dialogue: 0,0:16:15.30,0:16:18.14,EN,,0,0,0,,and if so, the result is the product being accumulated in m. Dialogue: 0,0:16:19.16,0:16:21.21,EN,,0,0,0,,However, if it's not the end of the loop, Dialogue: 0,0:16:21.21,0:16:22.89,EN,,0,0,0,,if I'm not done, Dialogue: 0,0:16:23.64,0:16:25.55,EN,,0,0,0,,then what I'm going to do is change the product Dialogue: 0,0:16:25.84,0:16:28.38,EN,,0,0,0,,to be the result of multiplying i times the current product. Dialogue: 0,0:16:29.04,0:16:30.68,EN,,0,0,0,,Which is sort of what we were doing here. Dialogue: 0,0:16:31.42,0:16:32.68,EN,,0,0,0,,Except here I wasn't changing. Dialogue: 0,0:16:33.63,0:16:35.77,EN,,0,0,0,,I was making another copy, Dialogue: 0,0:16:36.81,0:16:42.04,EN,,0,0,0,,because the substitution model says, you copy the body of the procedure Dialogue: 0,0:16:43.08,0:16:45.88,EN,,0,0,0,,with the arguments substituted for the formal parameters. Dialogue: 0,0:16:46.72,0:16:48.42,EN,,0,0,0,,Here I'm not worried about copying, Dialogue: 0,0:16:48.42,0:16:50.52,EN,,0,0,0,,here I've changed the value of m. Dialogue: 0,0:16:51.80,0:16:55.12,EN,,0,0,0,,I also then change the value of i to i plus one, Dialogue: 0,0:16:55.61,0:16:56.96,EN,,0,0,0,,and go buzzing around. Dialogue: 0,0:16:58.22,0:17:00.08,EN,,0,0,0,,Seems like essentially the same program, Dialogue: 0,0:17:00.96,0:17:02.84,EN,,0,0,0,,but there are some ways of making errors here Dialogue: 0,0:17:02.84,0:17:05.50,EN,,0,0,0,,that didn't exist until today. Dialogue: 0,0:17:06.14,0:17:07.02,EN,,0,0,0,,For example, Dialogue: 0,0:17:07.45,0:17:09.40,EN,,0,0,0,,if I were to do the horrible thing Dialogue: 0,0:17:10.04,0:17:12.14,EN,,0,0,0,,of not being careful in writing my program Dialogue: 0,0:17:12.64,0:17:16.08,EN,,0,0,0,,and interchange those two assignments, Dialogue: 0,0:17:17.10,0:17:18.91,EN,,0,0,0,,the program wouldn't compute the same function. Dialogue: 0,0:17:20.33,0:17:22.87,EN,,0,0,0,,I get a timing error because there's a dependency Dialogue: 0,0:17:22.87,0:17:27.22,EN,,0,0,0,,that m depends upon having the last value of i. Dialogue: 0,0:17:27.34,0:17:28.92,EN,,0,0,0,,If I try change i first, Dialogue: 0,0:17:31.31,0:17:33.77,EN,,0,0,0,,then I've got the wrong value of i when I multiply by m. Dialogue: 0,0:17:35.96,0:17:38.38,EN,,0,0,0,,It's a bug that wasn't available until this moment, Dialogue: 0,0:17:38.38,0:17:40.59,EN,,0,0,0,,until we introduced something that had time in it. Dialogue: 0,0:17:43.44,0:17:44.30,EN,,0,0,0,,So, as I said, Dialogue: 0,0:17:45.53,0:17:47.39,EN,,0,0,0,,first we need a new model of computation, Dialogue: 0,0:17:47.39,0:17:50.86,EN,,0,0,0,,and second, we have to be damn good reason for doing this kind of ugly thing. Dialogue: 0,0:17:52.72,0:17:53.74,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:17:58.83,0:18:00.22,EN,,0,0,0,,Speak loudly, David Dialogue: 0,0:18:00.40,0:18:03.47,EN,,0,0,0,,AUDIENCE: I'm confused about, we've introduced set now, Dialogue: 0,0:18:03.90,0:18:06.36,EN,,0,0,0,,but we had let before and define before. Dialogue: 0,0:18:06.89,0:18:09.70,EN,,0,0,0,,I'm confused about the difference between the three. Dialogue: 0,0:18:09.70,0:18:13.25,EN,,0,0,0,,Wouldn't define work in the same situation as set! Dialogue: 0,0:18:13.98,0:18:14.83,EN,,0,0,0,,if you introduced it a bit? Dialogue: 0,0:18:14.83,0:18:19.31,EN,,0,0,0,,PROFESSOR: No, define is intended for setting something once the first time, Dialogue: 0,0:18:19.31,0:18:21.36,EN,,0,0,0,,for making it, OK? Dialogue: 0,0:18:22.08,0:18:24.70,EN,,0,0,0,,You've never seen me write on a blackboard Dialogue: 0,0:18:25.60,0:18:26.94,EN,,0,0,0,,two defines in a row Dialogue: 0,0:18:27.08,0:18:32.08,EN,,0,0,0,,whose intention was to change the old value of some variable to a new one. Dialogue: 0,0:18:32.08,0:18:34.51,EN,,0,0,0,,AUDIENCE: Is that by convention or-- Dialogue: 0,0:18:34.51,0:18:36.35,EN,,0,0,0,,PROFESSOR: No, it's intention. Dialogue: 0,0:18:36.35,0:18:38.92,EN,,0,0,0,,Okay? The answer is, Dialogue: 0,0:18:39.69,0:18:40.84,EN,,0,0,0,,that, for example, Dialogue: 0,0:18:40.84,0:18:42.27,EN,,0,0,0,,internal to a procedure, Dialogue: 0,0:18:43.20,0:18:45.92,EN,,0,0,0,,two defines in a row are illegal, Dialogue: 0,0:18:46.68,0:18:48.57,EN,,0,0,0,,two defines in a row of the same variable. Dialogue: 0,0:18:50.24,0:18:51.74,EN,,0,0,0,,x can't be defined twice. Dialogue: 0,0:18:51.74,0:18:55.20,EN,,0,0,0,,Whether or not a system catches that error is a different question, Dialogue: 0,0:18:55.93,0:18:57.88,EN,,0,0,0,,but I legislate to you Dialogue: 0,0:18:58.12,0:19:00.64,EN,,0,0,0,,that define happens once on anything. Dialogue: 0,0:19:00.73,0:19:02.64,EN,,0,0,0,,Now, indeed, in interactive debugging, Dialogue: 0,0:19:03.37,0:19:07.48,EN,,0,0,0,,we intend that you interacting with your computer will redefine things, Dialogue: 0,0:19:08.19,0:19:11.21,EN,,0,0,0,,and so there's a special exception made for interactive debugging. Dialogue: 0,0:19:11.82,0:19:16.48,EN,,0,0,0,,But define is intended to mean to set up something Dialogue: 0,0:19:18.14,0:19:20.96,EN,,0,0,0,,which will be forever that value after that point. Dialogue: 0,0:19:22.05,0:19:24.54,EN,,0,0,0,,It's as if all the defines were done at the beginning. Dialogue: 0,0:19:26.09,0:19:30.92,EN,,0,0,0,,In fact, the only legal place to put a define in Scheme internal to a procedure Dialogue: 0,0:19:31.02,0:19:33.36,EN,,0,0,0,,is just at the beginning of a lambda expression, Dialogue: 0,0:19:34.47,0:19:37.66,EN,,0,0,0,,which is the beginning of the body of a procedure. Dialogue: 0,0:19:40.40,0:19:45.80,EN,,0,0,0,,Now, let of course does nothing like either of that. Dialogue: 0,0:19:48.09,0:19:49.55,EN,,0,0,0,,I mean, if you look at what's happening with a let, Dialogue: 0,0:19:50.17,0:19:52.13,EN,,0,0,0,,this happens again exactly once. Dialogue: 0,0:19:52.13,0:19:55.82,EN,,0,0,0,,It sets up a context where i and m are values one and one. Dialogue: 0,0:19:56.83,0:20:00.57,EN,,0,0,0,,That context exists throughout this scope, Dialogue: 0,0:20:01.31,0:20:02.80,EN,,0,0,0,,this region of the program. Dialogue: 0,0:20:04.99,0:20:10.12,EN,,0,0,0,,However, you don't think of that let as setting i again. Dialogue: 0,0:20:11.04,0:20:12.16,EN,,0,0,0,,It doesn't change it. Dialogue: 0,0:20:12.16,0:20:14.01,EN,,0,0,0,,i never changes because of the let. Dialogue: 0,0:20:15.28,0:20:16.81,EN,,0,0,0,,i gets created because of let. Dialogue: 0,0:20:18.51,0:20:19.29,EN,,0,0,0,,In fact, Dialogue: 0,0:20:19.73,0:20:21.42,EN,,0,0,0,,the let is a very simple idea. Dialogue: 0,0:20:22.24,0:20:23.59,EN,,0,0,0,,Let does nothing more, Dialogue: 0,0:20:23.59,0:20:31.62,EN,,0,0,0,,Let a variable one to have value one Dialogue: 0,0:20:31.62,0:20:33.50,EN,,0,0,0,,I'll write this down a little bit more neatly; Dialogue: 0,0:20:37.16,0:20:43.73,EN,,0,0,0,,Let's write, var one have value, the value of expression e1, Dialogue: 0,0:20:43.73,0:20:47.36,EN,,0,0,0,,and variable two, have this value of the expression e2, Dialogue: 0,0:20:48.14,0:20:49.74,EN,,0,0,0,,in an expression e3, Dialogue: 0,0:20:51.60,0:21:05.80,EN,,0,0,0,,is the same thing as a procedure of var one and var two, the formal parameters, Dialogue: 0,0:21:06.94,0:21:08.96,EN,,0,0,0,,and e3 being the body, Dialogue: 0,0:21:10.91,0:21:14.00,EN,,0,0,0,,where var one is bound to the value of e1, Dialogue: 0,0:21:14.27,0:21:16.91,EN,,0,0,0,,and var two gets the value of e2. Dialogue: 0,0:21:19.53,0:21:23.26,EN,,0,0,0,,So this is, in fact, a perfectly understandable thing from a substitution point of view. Dialogue: 0,0:21:24.89,0:21:27.95,EN,,0,0,0,,This is really the same expression written in two different ways. Dialogue: 0,0:21:31.69,0:21:33.50,EN,,0,0,0,,In fact, the way the actual system works Dialogue: 0,0:21:33.63,0:21:35.82,EN,,0,0,0,,is this gets translated into this before anything happens. Dialogue: 0,0:21:37.64,0:21:41.77,EN,,0,0,0,,AUDIENCE: OK, I'm still unclear as then what makes the difference between a let and a define. They could-- Dialogue: 0,0:21:41.77,0:21:44.30,EN,,0,0,0,,PROFESSOR: A define is a syntactic sugar, Dialogue: 0,0:21:44.62,0:21:49.10,EN,,0,0,0,,whereby, essentially a bunch of variables get created by lets and then set up once. Dialogue: 0,0:21:57.10,0:21:59.74,EN,,0,0,0,,OK, time for the first break, I think. Thank you. Dialogue: 0,0:22:02.52,0:22:12.84,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:22:12.84,0:22:17.84,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:22:48.81,0:22:52.67,EN,,0,0,0,,By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:22:52.67,0:22:56.52,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:22:56.52,0:23:00.59,EN,,0,0,0,,Assignment, State, and Side-effects Dialogue: 0,0:23:04.28,0:23:06.11,EN,,0,0,0,,Well let's see. Dialogue: 0,0:23:06.44,0:23:09.08,EN,,0,0,0,,I now have to rebuild the model of computation, Dialogue: 0,0:23:09.77,0:23:14.16,EN,,0,0,0,,so you understand how some such mechanical mechanism could work Dialogue: 0,0:23:14.91,0:23:16.46,EN,,0,0,0,,that can do what we've just talked about. Dialogue: 0,0:23:17.53,0:23:21.39,EN,,0,0,0,,I just recently destroyed your substitution model. Dialogue: 0,0:23:22.62,0:23:26.03,EN,,0,0,0,,Unfortunately, this model is significantly more complicated than the substitution model. Dialogue: 0,0:23:26.62,0:23:27.93,EN,,0,0,0,,It's called the environment model. Dialogue: 0,0:23:29.02,0:23:31.20,EN,,0,0,0,,And I'm going to have to introduce some terminology, Dialogue: 0,0:23:32.03,0:23:34.51,EN,,0,0,0,,which is very good terminology for you to know anyway. Dialogue: 0,0:23:34.51,0:23:35.74,EN,,0,0,0,,It's about names. Dialogue: 0,0:23:36.51,0:23:39.63,EN,,0,0,0,,And we're going to give names to the kinds of names things have Dialogue: 0,0:23:40.00,0:23:41.31,EN,,0,0,0,,and the way those names are used. Dialogue: 0,0:23:42.48,0:23:47.94,EN,,0,0,0,,So this is a meta-description, if you will. Dialogue: 0,0:23:48.56,0:23:50.85,EN,,0,0,0,,Anyway, there is a pile of an unfortunate terminology here, Dialogue: 0,0:23:50.85,0:23:53.76,EN,,0,0,0,,but we're going to need this to understand what's called the environment model. Dialogue: 0,0:23:54.70,0:23:57.53,EN,,0,0,0,,We're about to do a little bit of boring, dog-work here. Dialogue: 0,0:23:58.04,0:24:01.58,EN,,0,0,0,,Let's look at the first transparency. Dialogue: 0,0:24:02.25,0:24:06.97,EN,,0,0,0,,And we see a description of a word called bound. Dialogue: 0,0:24:08.80,0:24:11.00,EN,,0,0,0,,And we're going to say that a variable, v, Dialogue: 0,0:24:11.00,0:24:12.91,EN,,0,0,0,,is bound in an expression, e, Dialogue: 0,0:24:13.41,0:24:21.52,EN,,0,0,0,,if the meaning of e is unchanged by the uniform replacement of a variable w, Dialogue: 0,0:24:21.56,0:24:24.28,EN,,0,0,0,,not occurrent if for every occurrence of v in e. Dialogue: 0,0:24:25.69,0:24:27.00,EN,,0,0,0,,Now that's a long sentence, Dialogue: 0,0:24:27.37,0:24:29.96,EN,,0,0,0,,so, I think, I'm going to have to say a little bit about that Dialogue: 0,0:24:29.98,0:24:32.62,EN,,0,0,0,,before we even fool around at all here. Dialogue: 0,0:24:33.42,0:24:35.28,EN,,0,0,0,,Bound variables we're talking about here. Dialogue: 0,0:24:44.16,0:24:45.56,EN,,0,0,0,,And you've seen lots of them. Dialogue: 0,0:24:46.07,0:24:48.17,EN,,0,0,0,,You may not know that you've seen lots of them. Dialogue: 0,0:24:48.24,0:24:52.24,EN,,0,0,0,,Well, I suppose in your logic, you saw a logical variables like, Dialogue: 0,0:24:53.27,0:25:00.11,EN,,0,0,0,,for every x there exists a y such that p is true of x and y from your calculus class. Dialogue: 0,0:25:02.88,0:25:05.82,EN,,0,0,0,,This variable, x, and this variable, y, are bound, Dialogue: 0,0:25:07.08,0:25:07.92,EN,,0,0,0,,because, Dialogue: 0,0:25:08.33,0:25:09.98,EN,,0,0,0,,the meaning of this expression Dialogue: 0,0:25:09.98,0:25:15.61,EN,,0,0,0,,does not depend upon the particular letters I used to describe x and y. Dialogue: 0,0:25:16.49,0:25:19.18,EN,,0,0,0,,If I were to change the w for x, Dialogue: 0,0:25:19.84,0:25:25.68,EN,,0,0,0,,then said for every w there exists a y such that p is true of w and y, Dialogue: 0,0:25:25.98,0:25:27.08,EN,,0,0,0,,it would be the same sentence. Dialogue: 0,0:25:29.44,0:25:30.34,EN,,0,0,0,,That's what it means. Dialogue: 0,0:25:30.34,0:25:34.89,EN,,0,0,0,,Or another case of this that you've seen is integral say, Dialogue: 0,0:25:35.40,0:25:42.65,EN,,0,0,0,,from 0 to one of dx over one plus x square. Dialogue: 0,0:25:46.03,0:25:47.92,EN,,0,0,0,,Well that's something you see all the time. Dialogue: 0,0:25:47.92,0:25:50.92,EN,,0,0,0,,And this x is a bound variable. Dialogue: 0,0:25:52.06,0:25:53.79,EN,,0,0,0,,If I change that to a t, Dialogue: 0,0:25:54.15,0:25:56.25,EN,,0,0,0,,the expression is still the same thing. Dialogue: 0,0:25:58.06,0:26:02.76,EN,,0,0,0,,This is a 1/4 of the arctan of one or something here, something like that. Dialogue: 0,0:26:04.70,0:26:06.01,EN,,0,0,0,,Yes, that's the arctan of one. Dialogue: 0,0:26:06.62,0:26:08.76,EN,,0,0,0,,So bound variables are actually fairly common, Dialogue: 0,0:26:09.08,0:26:12.36,EN,,0,0,0,,for those of you who have played a bit with mathematics. Dialogue: 0,0:26:13.26,0:26:17.47,EN,,0,0,0,,Well, let's go into the programming world. Dialogue: 0,0:26:19.02,0:26:21.36,EN,,0,0,0,,Instead of the quantifier being something like, Dialogue: 0,0:26:22.03,0:26:24.06,EN,,0,0,0,,for every, or there exists, or integral, Dialogue: 0,0:26:24.06,0:26:26.43,EN,,0,0,0,,a quantifier is a symbol that binds a variable. Dialogue: 0,0:26:27.47,0:26:28.99,EN,,0,0,0,,And we are going to use the quantifier lambda Dialogue: 0,0:26:29.79,0:26:31.80,EN,,0,0,0,,as being the essential thing that binds variables. Dialogue: 0,0:26:33.80,0:26:36.12,EN,,0,0,0,,And so we have some nice examples here Dialogue: 0,0:26:36.59,0:26:44.14,EN,,0,0,0,,like that procedure of one argument y which does the following thing. Dialogue: 0,0:26:44.14,0:26:46.96,EN,,0,0,0,,It calls the procedure of one argument x, Dialogue: 0,0:26:47.87,0:26:51.13,EN,,0,0,0,,which multiplies x by y, Dialogue: 0,0:26:52.88,0:26:54.52,EN,,0,0,0,,and applies that to three. Dialogue: 0,0:26:58.76,0:27:01.66,EN,,0,0,0,,That procedure has the property there of two bound variables in it, Dialogue: 0,0:27:02.01,0:27:02.92,EN,,0,0,0,,x and y Dialogue: 0,0:27:04.83,0:27:07.47,EN,,0,0,0,,This quantifier, lambda here, binds this y, Dialogue: 0,0:27:07.91,0:27:10.78,EN,,0,0,0,,and this quantifier, lambda, binds that x. Dialogue: 0,0:27:12.11,0:27:17.05,EN,,0,0,0,,Because, if I were to take an arbitrary symbol does not occur in this expression like w Dialogue: 0,0:27:17.98,0:27:21.04,EN,,0,0,0,,and replace all y's with w's in this expression, Dialogue: 0,0:27:21.36,0:27:22.75,EN,,0,0,0,,the expression is still the same, Dialogue: 0,0:27:23.66,0:27:24.80,EN,,0,0,0,,the same procedure. Dialogue: 0,0:27:26.22,0:27:27.41,EN,,0,0,0,,And this is an important idea. Dialogue: 0,0:27:27.41,0:27:29.64,EN,,0,0,0,,The reason why we had such things like that Dialogue: 0,0:27:30.20,0:27:31.41,EN,,0,0,0,,is a kind of modularity. Dialogue: 0,0:27:31.41,0:27:32.86,EN,,0,0,0,,If two people are writing programs, Dialogue: 0,0:27:34.03,0:27:35.26,EN,,0,0,0,,and they work together, Dialogue: 0,0:27:35.26,0:27:40.56,EN,,0,0,0,,it shouldn't matter what names they use internal to their own little machines that they're building. Dialogue: 0,0:27:42.83,0:27:44.67,EN,,0,0,0,,And so, what I'm really telling you there, Dialogue: 0,0:27:45.44,0:27:46.75,EN,,0,0,0,,is that, for example, Dialogue: 0,0:27:46.84,0:27:51.26,EN,,0,0,0,,this is equivalent to that procedure of one argument y which Dialogue: 0,0:27:52.35,0:27:59.23,EN,,0,0,0,,uses that procedure of one argument z which multiplies z by y. Dialogue: 0,0:28:01.64,0:28:03.53,EN,,0,0,0,,Because nobody cares what I used in here. Dialogue: 0,0:28:06.36,0:28:07.24,EN,,0,0,0,,It's a nice example. Dialogue: 0,0:28:08.84,0:28:09.85,EN,,0,0,0,,On the other hand, Dialogue: 0,0:28:11.07,0:28:14.33,EN,,0,0,0,,I have some variables that are not bound. Dialogue: 0,0:28:15.23,0:28:15.96,EN,,0,0,0,,And example, Dialogue: 0,0:28:20.27,0:28:21.76,EN,,0,0,0,,that procedure of one argument x Dialogue: 0,0:28:22.09,0:28:25.04,EN,,0,0,0,,which multiplies x by y Dialogue: 0,0:28:27.28,0:28:28.16,EN,,0,0,0,,In this case, Dialogue: 0,0:28:29.45,0:28:30.75,EN,,0,0,0,,y is not bound. Dialogue: 0,0:28:32.46,0:28:34.27,EN,,0,0,0,,Supposing y had the value three, Dialogue: 0,0:28:35.26,0:28:36.80,EN,,0,0,0,,and z had the value four, Dialogue: 0,0:28:38.83,0:28:44.27,EN,,0,0,0,,then this procedure would be the thing that multiplies its argument by three. Dialogue: 0,0:28:44.86,0:28:47.39,EN,,0,0,0,,If I were to replace every instance of y with z, Dialogue: 0,0:28:47.52,0:28:51.96,EN,,0,0,0,,I would have a different procedure which multiplies every argument that's given by four. Dialogue: 0,0:28:53.87,0:28:56.40,EN,,0,0,0,,And, in fact, we have a name for such a variable. Dialogue: 0,0:28:57.76,0:29:04.01,EN,,0,0,0,,Here, we say that a variable, v, is free in the expression, e, Dialogue: 0,0:29:04.01,0:29:09.42,EN,,0,0,0,,if the meaning of the expression, e, is changed by the uniform replacement of a variable, w, not occurring in e, Dialogue: 0,0:29:09.58,0:29:11.15,EN,,0,0,0,,for every occurrence of v and e. Dialogue: 0,0:29:13.26,0:29:13.71,EN,,0,0,0,,So, Dialogue: 0,0:29:14.49,0:29:22.76,EN,,0,0,0,,So that's why this variable over here, y, is a free variable. Dialogue: 0,0:29:29.16,0:29:32.27,EN,,0,0,0,,And so free variables in this expression-- Dialogue: 0,0:29:33.76,0:29:35.18,EN,,0,0,0,,And other examples of that is that Dialogue: 0,0:29:36.17,0:29:39.32,EN,,0,0,0,,is that procedure of one argument y, Dialogue: 0,0:29:40.43,0:29:42.00,EN,,0,0,0,,which is just what we had before, Dialogue: 0,0:29:42.27,0:29:44.60,EN,,0,0,0,,which uses that procedure of one argument x Dialogue: 0,0:29:45.08,0:29:48.54,EN,,0,0,0,,that multiplies x by y-- Dialogue: 0,0:29:51.40,0:29:52.65,EN,,0,0,0,,use that on three. Dialogue: 0,0:29:57.24,0:30:00.35,EN,,0,0,0,,This procedure has a free variable in it Dialogue: 0,0:30:00.92,0:30:01.98,EN,,0,0,0,,which is asterisk. Dialogue: 0,0:30:05.00,0:30:05.89,EN,,0,0,0,,See, because, Dialogue: 0,0:30:05.89,0:30:08.08,EN,,0,0,0,,if that has a normal meaning of multiplication, Dialogue: 0,0:30:09.44,0:30:12.78,EN,,0,0,0,,then if I were to replace uniformly all asterisks with pluses, Dialogue: 0,0:30:14.25,0:30:16.38,EN,,0,0,0,,then the meaning of this expression would change. Dialogue: 0,0:30:19.34,0:30:20.76,EN,,0,0,0,,That's what you mean by a free variable. Dialogue: 0,0:30:22.68,0:30:24.81,EN,,0,0,0,,So, so far you've learned some logician words Dialogue: 0,0:30:25.64,0:30:27.58,EN,,0,0,0,,which describe the way names are used. Dialogue: 0,0:30:28.94,0:30:31.26,EN,,0,0,0,,Now, we have to do a little bit more playing around here, Dialogue: 0,0:30:32.96,0:30:33.72,EN,,0,0,0,,a little bit more. Dialogue: 0,0:30:35.13,0:30:36.22,EN,,0,0,0,,I want to tell you about Dialogue: 0,0:30:36.81,0:30:39.76,EN,,0,0,0,,about the regions are over which variables are defined. Dialogue: 0,0:30:42.17,0:30:42.88,EN,,0,0,0,,You see, Dialogue: 0,0:30:43.37,0:30:45.69,EN,,0,0,0,,we've been very informal about this up till now, Dialogue: 0,0:30:46.33,0:30:50.16,EN,,0,0,0,,and, of course, many of you have probably understood very clearly or most of you, Dialogue: 0,0:30:50.36,0:30:52.84,EN,,0,0,0,,that the x that's being declared here Dialogue: 0,0:30:53.64,0:30:55.18,EN,,0,0,0,,is defined only in here. Dialogue: 0,0:30:58.28,0:31:00.91,EN,,0,0,0,,This x is the defined only in here, Dialogue: 0,0:31:01.61,0:31:04.33,EN,,0,0,0,,and this y is defined only in here. Dialogue: 0,0:31:07.10,0:31:09.16,EN,,0,0,0,,We have a name for such an idea. It's called a scope. Dialogue: 0,0:31:11.61,0:31:13.58,EN,,0,0,0,,And let me give you another piece of terminology. Dialogue: 0,0:31:14.70,0:31:15.77,EN,,0,0,0,,It's a long story. Dialogue: 0,0:31:15.96,0:31:17.64,EN,,0,0,0,,If x is a bound variable in e, Dialogue: 0,0:31:18.16,0:31:20.24,EN,,0,0,0,,then there is a lambda expression where it is bound. Dialogue: 0,0:31:20.89,0:31:24.91,EN,,0,0,0,,So the only way you can get a bound variable ultimately is by lambda expression. Dialogue: 0,0:31:24.91,0:31:25.96,EN,,0,0,0,,Then you may worry, Dialogue: 0,0:31:26.22,0:31:29.05,EN,,0,0,0,,does define quite an exception to this? Dialogue: 0,0:31:29.64,0:31:32.92,EN,,0,0,0,,And it turns out, we could always arrange things so you don't need any defines. Dialogue: 0,0:31:32.92,0:31:33.96,EN,,0,0,0,,And we'll see that in a while. Dialogue: 0,0:31:34.24,0:31:35.72,EN,,0,0,0,,It's a very magical thing. Dialogue: 0,0:31:36.54,0:31:38.40,EN,,0,0,0,,So define really can go away. Dialogue: 0,0:31:38.68,0:31:41.55,EN,,0,0,0,,The really, only thing that makes names is lambda . Dialogue: 0,0:31:42.64,0:31:43.40,EN,,0,0,0,,That's its job. Dialogue: 0,0:31:44.30,0:31:46.23,EN,,0,0,0,,And what's so amazing about a lot of things Dialogue: 0,0:31:46.23,0:31:47.87,EN,,0,0,0,,is you can compute with only lambda. Dialogue: 0,0:31:48.73,0:31:49.58,EN,,0,0,0,,But, in any case, Dialogue: 0,0:31:51.74,0:31:55.76,EN,,0,0,0,,a lambda expression has a place where it declares a variable. Dialogue: 0,0:31:55.76,0:31:57.10,EN,,0,0,0,,We call it the formal parameter list Dialogue: 0,0:31:58.94,0:32:00.56,EN,,0,0,0,,and we say or the bound variable list. Dialogue: 0,0:32:01.26,0:32:04.51,EN,,0,0,0,,We say that the lambda expression binds -- so it's a verb Dialogue: 0,0:32:05.02,0:32:07.34,EN,,0,0,0,,--binds the variables declared in it's bound variable list. Dialogue: 0,0:32:08.59,0:32:12.48,EN,,0,0,0,,In addition, those parts of the expression where the variable is defined, Dialogue: 0,0:32:13.23,0:32:15.23,EN,,0,0,0,,which was declared by some declaration Dialogue: 0,0:32:15.56,0:32:19.26,EN,,0,0,0,,is called the scope of that variable. Dialogue: 0,0:32:20.44,0:32:21.92,EN,,0,0,0,,So these are scopes. Dialogue: 0,0:32:22.25,0:32:23.68,EN,,0,0,0,,This is the scope of y. Dialogue: 0,0:32:27.16,0:32:28.54,EN,,0,0,0,,And this is the scope of x-- Dialogue: 0,0:32:33.10,0:32:34.03,EN,,0,0,0,,that sort of thing. Dialogue: 0,0:32:41.32,0:32:42.08,EN,,0,0,0,,OK, Dialogue: 0,0:32:43.93,0:32:45.63,EN,,0,0,0,,well, now we have enough terminology Dialogue: 0,0:32:46.60,0:32:51.76,EN,,0,0,0,,to begin to understand how to make a new model for computation Dialogue: 0,0:32:51.96,0:32:53.77,EN,,0,0,0,,because the key thing going on here Dialogue: 0,0:32:54.94,0:32:57.00,EN,,0,0,0,,is that we destroyed the substitution model, Dialogue: 0,0:32:57.18,0:32:58.38,EN,,0,0,0,,and we now have to have a model Dialogue: 0,0:32:58.62,0:33:02.32,EN,,0,0,0,,that represents the names as referring to places. Dialogue: 0,0:33:03.93,0:33:05.34,EN,,0,0,0,,Because if we are going to change something, Dialogue: 0,0:33:05.98,0:33:07.47,EN,,0,0,0,,then we have a place where it's stored. Dialogue: 0,0:33:09.56,0:33:10.35,EN,,0,0,0,,You see, Dialogue: 0,0:33:10.83,0:33:13.31,EN,,0,0,0,,if a name only refers to a value, Dialogue: 0,0:33:14.04,0:33:16.36,EN,,0,0,0,,and if I tried to change the name's meaning, Dialogue: 0,0:33:16.73,0:33:20.32,EN,,0,0,0,,well, that's not clear. Dialogue: 0,0:33:20.32,0:33:24.68,EN,,0,0,0,,There's nothing that is the place that that name referred to. Dialogue: 0,0:33:24.99,0:33:25.80,EN,,0,0,0,,How am I really saying it? Dialogue: 0,0:33:25.92,0:33:29.54,EN,,0,0,0,,There're nothing shared among all of the instances of that name. Dialogue: 0,0:33:29.87,0:33:31.68,EN,,0,0,0,,And what we really mean, by a name, Dialogue: 0,0:33:31.68,0:33:32.97,EN,,0,0,0,,is that we find something out. Dialogue: 0,0:33:34.33,0:33:36.36,EN,,0,0,0,,We've given something a name, and you have it, Dialogue: 0,0:33:36.73,0:33:39.06,EN,,0,0,0,,and you have it, because I'm given you a reference to it, Dialogue: 0,0:33:39.06,0:33:40.44,EN,,0,0,0,,and I've given you a reference to it. Dialogue: 0,0:33:41.02,0:33:42.30,EN,,0,0,0,,And we'll see a lot about that. Dialogue: 0,0:33:43.61,0:33:45.21,EN,,0,0,0,,So let me tell you about environments. Dialogue: 0,0:33:46.19,0:33:48.76,EN,,0,0,0,,I need the overhead projection machine, Dialogue: 0,0:33:49.31,0:33:49.98,EN,,0,0,0,,thank you. Dialogue: 0,0:33:52.19,0:33:53.02,EN,,0,0,0,,And so here Dialogue: 0,0:33:55.48,0:34:00.40,EN,,0,0,0,,is a bunch of environment structures. Dialogue: 0,0:34:01.53,0:34:05.76,EN,,0,0,0,,An environment is a way of doing substitutions virtually. Dialogue: 0,0:34:06.38,0:34:07.89,EN,,0,0,0,,It represents a place Dialogue: 0,0:34:07.89,0:34:11.39,EN,,0,0,0,,where something is stored which is the substitutions that you haven't done. Dialogue: 0,0:34:13.34,0:34:16.50,EN,,0,0,0,,It's a place where everything accumulates, Dialogue: 0,0:34:16.50,0:34:21.13,EN,,0,0,0,,where the names of the variables are associated with the values they have Dialogue: 0,0:34:21.79,0:34:22.56,EN,,0,0,0,,such that, Dialogue: 0,0:34:22.75,0:34:25.90,EN,,0,0,0,,when you say, what dose this name mean, Dialogue: 0,0:34:25.90,0:34:27.40,EN,,0,0,0,,you look it up in an environment. Dialogue: 0,0:34:28.08,0:34:29.48,EN,,0,0,0,,So an environment is a function, Dialogue: 0,0:34:30.80,0:34:31.48,EN,,0,0,0,,or a table, Dialogue: 0,0:34:32.22,0:34:33.24,EN,,0,0,0,,or something like that. Dialogue: 0,0:34:33.24,0:34:34.89,EN,,0,0,0,,But it's a structured sort of table. Dialogue: 0,0:34:35.76,0:34:37.39,EN,,0,0,0,,It's made out of things called frames. Dialogue: 0,0:34:41.13,0:34:44.46,EN,,0,0,0,,Frames are pieces of environment, Dialogue: 0,0:34:44.89,0:34:46.01,EN,,0,0,0,,and they are chained together, Dialogue: 0,0:34:47.07,0:34:48.19,EN,,0,0,0,,in some nice ways, Dialogue: 0,0:34:49.00,0:34:52.09,EN,,0,0,0,,by what's called parent links or something like that. Dialogue: 0,0:34:54.03,0:34:55.02,EN,,0,0,0,,So here, Dialogue: 0,0:34:55.64,0:34:57.62,EN,,0,0,0,,we have an environment structure Dialogue: 0,0:34:57.62,0:35:04.22,EN,,0,0,0,,consisting of three environments, basically, A, B, and C. Dialogue: 0,0:35:05.10,0:35:07.63,EN,,0,0,0,,d is also an environment, but it's the same one, Dialogue: 0,0:35:08.88,0:35:10.17,EN,,0,0,0,,they share. Dialogue: 0,0:35:11.45,0:35:13.96,EN,,0,0,0,,And that's the essence of assignment. Dialogue: 0,0:35:14.40,0:35:16.10,EN,,0,0,0,,If I change a variable, Dialogue: 0,0:35:16.10,0:35:19.80,EN,,0,0,0,,a value of a valuable that lives here, like that one, Dialogue: 0,0:35:19.80,0:35:23.50,EN,,0,0,0,,it should be visible from all places that you're looking at it from. Dialogue: 0,0:35:23.50,0:35:24.84,EN,,0,0,0,,Take this one, x. Dialogue: 0,0:35:24.84,0:35:28.19,EN,,0,0,0,,If I change the x to four, Dialogue: 0,0:35:28.19,0:35:30.19,EN,,0,0,0,,it's visible from other places. Dialogue: 0,0:35:30.19,0:35:32.19,EN,,0,0,0,,But I'm not going to worry about that right now. Dialogue: 0,0:35:32.19,0:35:33.84,EN,,0,0,0,,We're going to talk a lot about that in a little while. Dialogue: 0,0:35:34.56,0:35:35.53,EN,,0,0,0,,What do we have here? Dialogue: 0,0:35:36.76,0:35:38.84,EN,,0,0,0,,Well, these are called frames. Here is a frame, Dialogue: 0,0:35:39.40,0:35:40.38,EN,,0,0,0,,here's a frame Dialogue: 0,0:35:40.76,0:35:41.84,EN,,0,0,0,,and here's a frame. Dialogue: 0,0:35:43.18,0:35:45.20,EN,,0,0,0,,A is an environment which consists of Dialogue: 0,0:35:45.20,0:35:47.82,EN,,0,0,0,,the table label which is frame two, Dialogue: 0,0:35:48.36,0:35:51.05,EN,,0,0,0,,followed by the table labeled frame one. Dialogue: 0,0:35:52.52,0:35:54.60,EN,,0,0,0,,And, in this environment, Dialogue: 0,0:35:54.99,0:35:59.68,EN,,0,0,0,,in C, this environment, frame two, Dialogue: 0,0:36:00.48,0:36:03.26,EN,,0,0,0,,uh....x and y are bound. Dialogue: 0,0:36:04.06,0:36:04.78,EN,,0,0,0,,They have values. Dialogue: 0,0:36:05.26,0:36:07.18,EN,,0,0,0,,Sorry, in frame one Dialogue: 0,0:36:07.18,0:36:08.28,EN,,0,0,0,,In frame two, Dialogue: 0,0:36:09.72,0:36:10.83,EN,,0,0,0,,z is bound, Dialogue: 0,0:36:10.99,0:36:12.17,EN,,0,0,0,,and x is bound, Dialogue: 0,0:36:12.44,0:36:13.69,EN,,0,0,0,,and y is bound, Dialogue: 0,0:36:15.24,0:36:17.40,EN,,0,0,0,,but the value of x that we see, Dialogue: 0,0:36:17.42,0:36:19.04,EN,,0,0,0,,looking from this point of view, Dialogue: 0,0:36:20.01,0:36:21.74,EN,,0,0,0,,is this x. It's x is seven, Dialogue: 0,0:36:22.36,0:36:24.84,EN,,0,0,0,,rather than this one which is three. Dialogue: 0,0:36:24.84,0:36:27.61,EN,,0,0,0,,We say that this x shadows this x. Dialogue: 0,0:36:31.05,0:36:32.49,EN,,0,0,0,,From environment three-- Dialogue: 0,0:36:33.44,0:36:34.45,EN,,0,0,0,,from frame three, Dialogue: 0,0:36:34.45,0:36:35.73,EN,,0,0,0,,from environment b, Dialogue: 0,0:36:35.73,0:36:37.18,EN,,0,0,0,,which refers to frame three, Dialogue: 0,0:36:37.45,0:36:42.12,EN,,0,0,0,,we have variables m and y bound and also x. Dialogue: 0,0:36:44.84,0:36:46.97,EN,,0,0,0,,This y shadow this one. Dialogue: 0,0:36:48.65,0:36:51.00,EN,,0,0,0,,So the value, looking from this point of view, Dialogue: 0,0:36:51.10,0:36:52.65,EN,,0,0,0,,of y is two. Dialogue: 0,0:36:53.45,0:36:55.28,EN,,0,0,0,,The value for looking from this point of view Dialogue: 0,0:36:55.28,0:36:58.64,EN,,0,0,0,,and m is one. And the value, looking from this point of view, of x is three. Dialogue: 0,0:37:02.22,0:37:03.15,EN,,0,0,0,,So there we have Dialogue: 0,0:37:03.15,0:37:05.52,EN,,0,0,0,,a very simple environment structure made out of frames. Dialogue: 0,0:37:06.38,0:37:09.80,EN,,0,0,0,,These correspond to the applications of procedures. Dialogue: 0,0:37:10.94,0:37:12.17,EN,,0,0,0,,And we'll see that in a second. Dialogue: 0,0:37:14.41,0:37:17.60,EN,,0,0,0,,So now I have to make you some other nice little structure that we build. Dialogue: 0,0:37:20.75,0:37:21.71,EN,,0,0,0,,Next slide, Dialogue: 0,0:37:22.14,0:37:24.36,EN,,0,0,0,,we see an object, Dialogue: 0,0:37:24.84,0:37:26.54,EN,,0,0,0,,which I'm going to draw procedures. Dialogue: 0,0:37:27.93,0:37:28.94,EN,,0,0,0,,This is a procedure. Dialogue: 0,0:37:30.11,0:37:31.90,EN,,0,0,0,,A procedure is made out of two parts. Dialogue: 0,0:37:33.10,0:37:34.80,EN,,0,0,0,,It's sort of like a cons. Dialogue: 0,0:37:37.21,0:37:38.38,EN,,0,0,0,,However, it's the two parts. Dialogue: 0,0:37:40.84,0:37:44.72,EN,,0,0,0,,The first part refers to some code, Dialogue: 0,0:37:45.69,0:37:46.94,EN,,0,0,0,,something that can be executed, Dialogue: 0,0:37:47.42,0:37:50.00,EN,,0,0,0,,a set of instructions, if you will. You can think of it that way. Dialogue: 0,0:37:50.68,0:37:52.83,EN,,0,0,0,,And the second part is the environment. Dialogue: 0,0:37:53.88,0:37:55.50,EN,,0,0,0,,The procedure is the whole thing. Dialogue: 0,0:37:57.16,0:37:58.40,EN,,0,0,0,,And we're going to have to use this Dialogue: 0,0:37:58.71,0:38:05.16,EN,,0,0,0,,to capture the values of the free variables that occur in the procedure. Dialogue: 0,0:38:06.17,0:38:08.09,EN,,0,0,0,,If a variable occurs in the procedure Dialogue: 0,0:38:08.11,0:38:09.92,EN,,0,0,0,,it's either bound in that procedure or free. Dialogue: 0,0:38:11.10,0:38:11.96,EN,,0,0,0,,If it's bound, Dialogue: 0,0:38:12.57,0:38:14.56,EN,,0,0,0,,then the value will somehow be easy to find. Dialogue: 0,0:38:16.11,0:38:18.64,EN,,0,0,0,,It will be in some easy environment to get at. Dialogue: 0,0:38:18.91,0:38:19.87,EN,,0,0,0,,If it's free, Dialogue: 0,0:38:20.86,0:38:23.02,EN,,0,0,0,,we're going to have to have something that goes with the procedure Dialogue: 0,0:38:23.02,0:38:24.81,EN,,0,0,0,,that says where we'll go look for its value. Dialogue: 0,0:38:27.05,0:38:29.21,EN,,0,0,0,,And the reasons why are not obvious yet, Dialogue: 0,0:38:29.21,0:38:30.60,EN,,0,0,0,,but will be soon. Dialogue: 0,0:38:32.32,0:38:34.97,EN,,0,0,0,,So here's a procedure object. It's a composite object Dialogue: 0,0:38:35.34,0:38:41.64,EN,,0,0,0,,consisting of a piece of code and a environment structure. Dialogue: 0,0:38:42.72,0:38:45.50,EN,,0,0,0,,Now I will tell you the new rules, the complete new rules, Dialogue: 0,0:38:46.41,0:38:47.47,EN,,0,0,0,,for evaluation. Dialogue: 0,0:38:50.54,0:38:52.20,EN,,0,0,0,,The first rule is-- there's only two of them. Dialogue: 0,0:38:53.20,0:38:55.39,EN,,0,0,0,,These correspond to the substitution model rules. Dialogue: 0,0:38:57.26,0:38:59.32,EN,,0,0,0,,And the first one has to do with Dialogue: 0,0:38:59.66,0:39:02.78,EN,,0,0,0,,how do you apply a procedure to its arguments? Dialogue: 0,0:39:05.28,0:39:08.54,EN,,0,0,0,,Okay, And a procedural object is applied to a set of arguments Dialogue: 0,0:39:08.96,0:39:10.43,EN,,0,0,0,,by constructing a new frame. Dialogue: 0,0:39:11.31,0:39:15.76,EN,,0,0,0,,That frame will contain the mapping of the former parameters to the actual parameters Dialogue: 0,0:39:15.83,0:39:19.48,EN,,0,0,0,,of the arguments that were supplied in the call. Dialogue: 0,0:39:21.42,0:39:22.20,EN,,0,0,0,,As you know, Dialogue: 0,0:39:22.31,0:39:26.94,EN,,0,0,0,,when we make up a call to a procedure like lambda x times x y, Dialogue: 0,0:39:26.94,0:39:29.13,EN,,0,0,0,,and we call that with the argument three, Dialogue: 0,0:39:30.19,0:39:32.75,EN,,0,0,0,,then we're going to need some mapping of x to three. Dialogue: 0,0:39:34.19,0:39:37.39,EN,,0,0,0,,It's the same thing as later substituting, if you will Dialogue: 0,0:39:38.27,0:39:40.30,EN,,0,0,0,,the three for the x in the old model. Dialogue: 0,0:39:42.00,0:39:44.80,EN,,0,0,0,,So I'm going to build a frame which contains x equals three Dialogue: 0,0:39:45.15,0:39:46.60,EN,,0,0,0,,as the information in that frame. Dialogue: 0,0:39:49.12,0:39:49.71,EN,,0,0,0,,Now, Dialogue: 0,0:39:50.33,0:39:53.31,EN,,0,0,0,,the body of the procedure will then have to be evaluated which is this, Dialogue: 0,0:39:54.16,0:39:56.44,EN,,0,0,0,,and will be evaluated in an environment Dialogue: 0,0:39:57.80,0:40:08.03,EN,,0,0,0,,which is constructed by adjoining the new frame that we just made Dialogue: 0,0:40:08.54,0:40:11.69,EN,,0,0,0,,to the environment which was part of the procedure that we applied. Dialogue: 0,0:40:13.15,0:40:15.77,EN,,0,0,0,,So I'm going to make a little example of that here. Dialogue: 0,0:40:19.20,0:40:24.12,EN,,0,0,0,,Supposing I have some environment. Dialogue: 0,0:40:25.15,0:40:27.23,EN,,0,0,0,,Here's a frame which represents it. Dialogue: 0,0:40:27.96,0:40:32.19,EN,,0,0,0,,And some procedure-- which I'm going to draw with circles here because it's easier than little triangles-- Dialogue: 0,0:40:33.04,0:40:36.36,EN,,0,0,0,,Ummm.. sorry, those are rhombuses, Dialogue: 0,0:40:37.66,0:40:40.78,EN,,0,0,0,,rhomboidal little pieces of fruit jelly or something. Dialogue: 0,0:40:42.68,0:40:45.32,EN,,0,0,0,,So here's a procedure which takes this environment. Dialogue: 0,0:40:45.95,0:40:48.16,EN,,0,0,0,,And the procedure has a piece of code, Dialogue: 0,0:40:48.16,0:40:49.68,EN,,0,0,0,,which is a lambda expression, Dialogue: 0,0:40:50.12,0:40:51.69,EN,,0,0,0,,which binds x and y Dialogue: 0,0:40:53.15,0:40:56.43,EN,,0,0,0,,and then executes an expression, e. Dialogue: 0,0:40:57.93,0:40:58.99,EN,,0,0,0,,And this is the procedure. Dialogue: 0,0:40:59.56,0:41:00.57,EN,,0,0,0,,We'll call it p. Dialogue: 0,0:41:01.44,0:41:05.79,EN,,0,0,0,,I wish to apply that procedure to three and four. Dialogue: 0,0:41:06.38,0:41:08.36,EN,,0,0,0,,So I want to do p of three and four. Dialogue: 0,0:41:09.76,0:41:12.17,EN,,0,0,0,,What I'm going to do, of course, is make a new frame. Dialogue: 0,0:41:13.15,0:41:14.12,EN,,0,0,0,,I build a frame Dialogue: 0,0:41:15.24,0:41:18.28,EN,,0,0,0,,which contains x equals three, Dialogue: 0,0:41:18.84,0:41:20.51,EN,,0,0,0,,and y equals four. Dialogue: 0,0:41:21.69,0:41:23.48,EN,,0,0,0,,I'm going to connect that frame Dialogue: 0,0:41:24.27,0:41:25.37,EN,,0,0,0,,to this frame over here. Dialogue: 0,0:41:27.63,0:41:28.99,EN,,0,0,0,,And then this environment, Dialogue: 0,0:41:29.68,0:41:30.97,EN,,0,0,0,,with I will call b, Dialogue: 0,0:41:31.55,0:41:35.02,EN,,0,0,0,,is the environment in which I will evaluate the body of e. Dialogue: 0,0:41:39.88,0:41:40.33,EN,,0,0,0,,Now, Dialogue: 0,0:41:41.95,0:41:45.04,EN,,0,0,0,,e may contain references to x and y and other things. Dialogue: 0,0:41:46.84,0:41:49.95,EN,,0,0,0,,x and y will have values right here. Dialogue: 0,0:41:50.70,0:41:52.52,EN,,0,0,0,,Other things will have their values here. Dialogue: 0,0:41:55.05,0:41:56.25,EN,,0,0,0,,How do we get this frame? Dialogue: 0,0:41:57.26,0:41:59.26,EN,,0,0,0,,That we do by the construction of procedures Dialogue: 0,0:41:59.61,0:42:00.60,EN,,0,0,0,,which is the other rule. Dialogue: 0,0:42:02.03,0:42:04.40,EN,,0,0,0,,And I think that's the next slide. Dialogue: 0,0:42:05.34,0:42:06.12,EN,,0,0,0,,Rule two, Dialogue: 0,0:42:07.80,0:42:09.90,EN,,0,0,0,,when a lambda expression is evaluated, Dialogue: 0,0:42:09.90,0:42:11.76,EN,,0,0,0,,relative to a particular environment-- Dialogue: 0,0:42:14.19,0:42:14.40,EN,,0,0,0,,See, Dialogue: 0,0:42:15.04,0:42:18.12,EN,,0,0,0,,the way I get a procedure is by evaluating the lambda expression. Dialogue: 0,0:42:18.19,0:42:19.36,EN,,0,0,0,,Here's a lambda expression. Dialogue: 0,0:42:20.04,0:42:21.12,EN,,0,0,0,,By evaluating it, Dialogue: 0,0:42:21.90,0:42:23.96,EN,,0,0,0,,I get a procedure which I can apply to three. Dialogue: 0,0:42:25.08,0:42:26.65,EN,,0,0,0,,Now this lambda expression Dialogue: 0,0:42:26.65,0:42:30.38,EN,,0,0,0,,is evaluated in an environment where y is defined. Dialogue: 0,0:42:31.84,0:42:35.84,EN,,0,0,0,,And I want the body of this which contains a free version of y. Dialogue: 0,0:42:36.39,0:42:38.36,EN,,0,0,0,,y is free in here, Dialogue: 0,0:42:38.72,0:42:40.38,EN,,0,0,0,,it's bound over the whole thing, Dialogue: 0,0:42:41.36,0:42:42.75,EN,,0,0,0,,but it's free over here. Dialogue: 0,0:42:43.32,0:42:46.24,EN,,0,0,0,,I want that y to be this one. Dialogue: 0,0:42:47.44,0:42:55.13,EN,,0,0,0,,I evaluate this body of this procedure in the environment where y was created. Dialogue: 0,0:42:55.32,0:42:58.40,EN,,0,0,0,,That's this kind of thing, because that was done by application. Dialogue: 0,0:42:59.00,0:42:59.63,EN,,0,0,0,,Now, Dialogue: 0,0:43:00.24,0:43:02.60,EN,,0,0,0,,if I ever want to look up the value of y, Dialogue: 0,0:43:03.10,0:43:04.09,EN,,0,0,0,,I have to know where it is. Dialogue: 0,0:43:04.54,0:43:06.42,EN,,0,0,0,,Therefore, this procedural was created, Dialogue: 0,0:43:06.42,0:43:10.06,EN,,0,0,0,,the creation of the procedure which is the result of evaluating that lambda expression Dialogue: 0,0:43:10.06,0:43:16.33,EN,,0,0,0,,had better capture a pointer or remember the frame in which y was bound. Dialogue: 0,0:43:17.92,0:43:19.76,EN,,0,0,0,,So that's what this rule is telling us. Dialogue: 0,0:43:22.11,0:43:23.13,EN,,0,0,0,,So, for example, Dialogue: 0,0:43:24.44,0:43:29.32,EN,,0,0,0,,if I happen to be evaluating a lambda expression, Dialogue: 0,0:43:30.89,0:43:33.32,EN,,0,0,0,,lambda expression in e, Dialogue: 0,0:43:34.04,0:43:40.46,EN,,0,0,0,,lambda of say, x and y, let's call it g in e, Dialogue: 0,0:43:41.08,0:43:42.36,EN,,0,0,0,,evaluating that. Dialogue: 0,0:43:42.97,0:43:46.17,EN,,0,0,0,,all that means is I now construct a procedure object. Dialogue: 0,0:43:47.10,0:43:48.28,EN,,0,0,0,,e is some environment. Dialogue: 0,0:43:48.84,0:43:50.94,EN,,0,0,0,,e is something which has a pointer to it. Dialogue: 0,0:43:51.79,0:43:56.68,EN,,0,0,0,,I construct a procedure object that points up to that environment, Dialogue: 0,0:43:58.56,0:44:00.11,EN,,0,0,0,,where the code of that Dialogue: 0,0:44:00.54,0:44:03.24,EN,,0,0,0,,is a lambda expression or whatever that translates into. Dialogue: 0,0:44:06.24,0:44:07.56,EN,,0,0,0,,And this is the procedure. Dialogue: 0,0:44:12.38,0:44:14.70,EN,,0,0,0,,So this produces for me-- this -- this Dialogue: 0,0:44:14.94,0:44:16.37,EN,,0,0,0,,this object here, Dialogue: 0,0:44:16.37,0:44:18.12,EN,,0,0,0,,this environment pointer, Dialogue: 0,0:44:18.37,0:44:22.52,EN,,0,0,0,,captures the place where this lambda expression was evaluated, Dialogue: 0,0:44:22.62,0:44:24.59,EN,,0,0,0,,where the definition was used, Dialogue: 0,0:44:25.58,0:44:27.40,EN,,0,0,0,,where the definition was used to make a procedure, Dialogue: 0,0:44:30.32,0:44:31.47,EN,,0,0,0,,to make the procedure. Dialogue: 0,0:44:32.89,0:44:36.30,EN,,0,0,0,,So it picks up the environment from the place where that procedure was defined, Dialogue: 0,0:44:37.42,0:44:38.92,EN,,0,0,0,,stores it in the procedure itself, Dialogue: 0,0:44:39.60,0:44:40.97,EN,,0,0,0,,and then when the procedure is used, Dialogue: 0,0:44:41.32,0:44:43.47,EN,,0,0,0,,the environment where it was defined is extended Dialogue: 0,0:44:43.98,0:44:45.07,EN,,0,0,0,,with the new frame. Dialogue: 0,0:44:48.72,0:44:52.33,EN,,0,0,0,,So this gives us a locus for putting where a variable has a value. Dialogue: 0,0:44:53.04,0:44:53.96,EN,,0,0,0,,And, for example, Dialogue: 0,0:44:53.96,0:44:56.81,EN,,0,0,0,,if there are lots of guys pointing in at that environment, Dialogue: 0,0:44:57.74,0:45:00.33,EN,,0,0,0,,then they share that place. Dialogue: 0,0:45:01.20,0:45:02.52,EN,,0,0,0,,And we'll see more of that shortly. Dialogue: 0,0:45:04.01,0:45:05.34,EN,,0,0,0,,Well, now you have a new model Dialogue: 0,0:45:06.38,0:45:09.92,EN,,0,0,0,,for understanding the execution of programs. Dialogue: 0,0:45:11.36,0:45:12.78,EN,,0,0,0,,I suppose I'll take questions now, Dialogue: 0,0:45:13.10,0:45:14.96,EN,,0,0,0,,and then we'll go on and use that for something. Dialogue: 0,0:45:18.19,0:45:19.52,EN,,0,0,0,,AUDIENCE: Is it right to say then, Dialogue: 0,0:45:19.52,0:45:23.96,EN,,0,0,0,,the environment is that linked chain of frames starting with-- Dialogue: 0,0:45:23.96,0:45:25.10,EN,,0,0,0,,PROFESSOR: That's right. Dialogue: 0,0:45:25.48,0:45:26.64,EN,,0,0,0,,AUDIENCE: working all the way back? Dialogue: 0,0:45:27.71,0:45:31.45,EN,,0,0,0,,PROFESSOR: Yes, the environment is a sequence of frames linked together. Dialogue: 0,0:45:32.43,0:45:35.47,EN,,0,0,0,,And the way I like to think about it, it's the pointer to the first one, Dialogue: 0,0:45:36.88,0:45:38.72,EN,,0,0,0,,because once you've got that you've got them all. Dialogue: 0,0:45:43.96,0:45:44.65,EN,,0,0,0,,Anybody else? Dialogue: 0,0:45:45.20,0:45:49.36,EN,,0,0,0,,AUDIENCE: Is it possible to evaluate a procedure or to define a procedure in two different environments Dialogue: 0,0:45:49.36,0:45:53.20,EN,,0,0,0,,such that it will behave differently, and have pointers to both-- Dialogue: 0,0:45:53.20,0:45:55.77,EN,,0,0,0,,PROFESSOR: Oh, yes. The same procedure is not going to have two different environments. Dialogue: 0,0:45:56.90,0:45:59.02,EN,,0,0,0,,The same code, Dialogue: 0,0:45:59.02,0:46:00.82,EN,,0,0,0,,the same lambda expression Dialogue: 0,0:46:00.82,0:46:03.72,EN,,0,0,0,,can be evaluated in two environments producing two different procedures. Dialogue: 0,0:46:06.03,0:46:07.18,EN,,0,0,0,,Each procedure-- Dialogue: 0,0:46:07.18,0:46:09.95,EN,,0,0,0,,AUDIENCE: Their definition has the same name. Their operation-- Dialogue: 0,0:46:09.95,0:46:11.92,EN,,0,0,0,,PROFESSOR: The definition is written the same, with the same characters. Dialogue: 0,0:46:12.56,0:46:14.62,EN,,0,0,0,,I can evaluate that set of characters, Dialogue: 0,0:46:14.93,0:46:18.14,EN,,0,0,0,,whatever, that list structure that defines, Dialogue: 0,0:46:18.22,0:46:20.41,EN,,0,0,0,,that is the textual representation. Dialogue: 0,0:46:20.91,0:46:24.86,EN,,0,0,0,,I can evaluate that in two different environments producing two different procedures. Dialogue: 0,0:46:25.55,0:46:26.84,EN,,0,0,0,,Each of those procedures Dialogue: 0,0:46:27.56,0:46:32.19,EN,,0,0,0,,has its own local sets of variables, Dialogue: 0,0:46:32.34,0:46:33.45,EN,,0,0,0,,and we'll see that right now. Dialogue: 0,0:46:36.70,0:46:37.36,EN,,0,0,0,,Anybody else? Dialogue: 0,0:46:42.60,0:46:44.03,EN,,0,0,0,,OK, thank you. Let's take a break. Dialogue: 0,0:46:47.98,0:46:57.61,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:46:57.61,0:47:02.03,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:47:05.98,0:47:09.69,EN,,0,0,0,,By: Prof. Harold Abelson && Gerald Jay Sussman Dialogue: 0,0:47:09.69,0:47:13.44,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:47:13.47,0:47:18.84,EN,,0,0,0,,Assignment, State, and Side-effects Dialogue: 0,0:47:22.67,0:47:25.69,EN,,0,0,0,,Well, now I've done this terrible thing to you. Dialogue: 0,0:47:26.56,0:47:30.54,EN,,0,0,0,,I've introduced a very complicated thing, Dialogue: 0,0:47:32.76,0:47:33.42,EN,,0,0,0,,assignment, Dialogue: 0,0:47:34.51,0:47:38.08,EN,,0,0,0,,which destroys most of the interesting mathematical properties of our programs. Dialogue: 0,0:47:41.07,0:47:42.46,EN,,0,0,0,,Why should I have done this? Dialogue: 0,0:47:43.18,0:47:45.02,EN,,0,0,0,,What possible good could this do? Dialogue: 0,0:47:46.51,0:47:48.86,EN,,0,0,0,,Clearly not a nice thing, Dialogue: 0,0:47:49.60,0:47:51.23,EN,,0,0,0,,so I better have a good excuse. Dialogue: 0,0:47:52.83,0:47:54.80,EN,,0,0,0,,Well, let's do a little bit of playing, Dialogue: 0,0:47:54.80,0:47:58.35,EN,,0,0,0,,first of all, with some very interesting programs that have assignment. Dialogue: 0,0:47:58.81,0:48:00.88,EN,,0,0,0,,Understand something special about them Dialogue: 0,0:48:01.42,0:48:02.83,EN,,0,0,0,,that makes them somewhat valuable. Dialogue: 0,0:48:04.96,0:48:06.70,EN,,0,0,0,,Start with a very simple program Dialogue: 0,0:48:07.69,0:48:09.28,EN,,0,0,0,,I'm going to call make-counter. Dialogue: 0,0:48:10.48,0:48:18.19,EN,,0,0,0,,I'm going to define make-counter Dialogue: 0,0:48:24.17,0:48:28.12,EN,,0,0,0,,to be a procedure of one argument n Dialogue: 0,0:48:29.23,0:48:32.94,EN,,0,0,0,,which returns as its value a procedure of no arguments-- Dialogue: 0,0:48:34.36,0:48:36.03,EN,,0,0,0,,a procedure that produces a procedure-- Dialogue: 0,0:48:36.84,0:48:44.35,EN,,0,0,0,,which sets n to the increment of n Dialogue: 0,0:48:47.88,0:48:49.77,EN,,0,0,0,,and returns that value of n. Dialogue: 0,0:48:55.37,0:48:57.54,EN,,0,0,0,,Now we're going to investigate the behavior of this. Dialogue: 0,0:48:57.54,0:48:59.02,EN,,0,0,0,,It's a sort of interesting thing. Dialogue: 0,0:48:59.82,0:49:01.45,EN,,0,0,0,,In order to investigate the behavior, Dialogue: 0,0:49:01.45,0:49:03.08,EN,,0,0,0,,I have to make an environment model, Dialogue: 0,0:49:04.11,0:49:05.98,EN,,0,0,0,,because we can't understand this any other way. Dialogue: 0,0:49:08.65,0:49:09.63,EN,,0,0,0,,So let's just do that. Dialogue: 0,0:49:10.00,0:49:12.86,EN,,0,0,0,,We start out with some sort of-- Dialogue: 0,0:49:13.24,0:49:15.90,EN,,0,0,0,,let's say there is a global environment that the machine is born with. Dialogue: 0,0:49:16.13,0:49:17.12,EN,,0,0,0,,Global we'll call it. Dialogue: 0,0:49:20.03,0:49:24.25,EN,,0,0,0,,And it's going to have in it a bunch of initial things. Dialogue: 0,0:49:24.44,0:49:25.60,EN,,0,0,0,,We all know what it's got. Dialogue: 0,0:49:25.72,0:49:30.88,EN,,0,0,0,,It's got things in it like say, plus, and times, Dialogue: 0,0:49:32.24,0:49:37.26,EN,,0,0,0,,and quotient, and difference, and CAR, Dialogue: 0,0:49:38.70,0:49:39.74,EN,,0,0,0,,and etcetera, Dialogue: 0,0:49:41.45,0:49:42.48,EN,,0,0,0,,lots of things. Dialogue: 0,0:49:42.88,0:49:43.98,EN,,0,0,0,,I don't know what they are, Dialogue: 0,0:49:44.42,0:49:45.55,EN,,0,0,0,,some various squiggles Dialogue: 0,0:49:46.08,0:49:48.88,EN,,0,0,0,,that are the things the machine is born with. Dialogue: 0,0:49:51.21,0:49:53.23,EN,,0,0,0,,And by doing the definition here, Dialogue: 0,0:49:54.68,0:49:55.76,EN,,0,0,0,,what I plan to do-- Dialogue: 0,0:49:56.32,0:49:57.31,EN,,0,0,0,,Well, what am I doing? Dialogue: 0,0:49:57.31,0:49:59.58,EN,,0,0,0,,I'm doing this relative to the global environment. Dialogue: 0,0:49:59.72,0:50:01.29,EN,,0,0,0,,So here's my environment pointer. Dialogue: 0,0:50:03.72,0:50:06.70,EN,,0,0,0,,In order to do that I have to evaluate this lambda expression. Dialogue: 0,0:50:08.35,0:50:10.01,EN,,0,0,0,,That means I make a procedure object. Dialogue: 0,0:50:11.50,0:50:13.26,EN,,0,0,0,,So I'm going to make a procedure object here. Dialogue: 0,0:50:17.36,0:50:18.68,EN,,0,0,0,,And the procedure object has, Dialogue: 0,0:50:18.72,0:50:20.49,EN,,0,0,0,,as the place it's defined, Dialogue: 0,0:50:21.16,0:50:22.35,EN,,0,0,0,,the global environment. Dialogue: 0,0:50:24.06,0:50:25.79,EN,,0,0,0,,The procedure object contains Dialogue: 0,0:50:28.16,0:50:31.47,EN,,0,0,0,,some code that represents a procedure of one argument n Dialogue: 0,0:50:31.96,0:50:35.34,EN,,0,0,0,,which returns a procedure of no arguments which does something. Dialogue: 0,0:50:38.24,0:50:43.28,EN,,0,0,0,,And the define is a way of changing this environment, Dialogue: 0,0:50:44.32,0:50:46.73,EN,,0,0,0,,so that I now add to it a make-counter, Dialogue: 0,0:50:52.28,0:50:55.05,EN,,0,0,0,,a special rule for the special thing defined. Dialogue: 0,0:50:55.82,0:50:56.94,EN,,0,0,0,,But what that is, Dialogue: 0,0:50:58.94,0:51:01.96,EN,,0,0,0,,is it gives me that pointer to that procedure. Dialogue: 0,0:51:03.82,0:51:06.32,EN,,0,0,0,,So now the global environment contains make-counter as well. Dialogue: 0,0:51:09.28,0:51:11.21,EN,,0,0,0,,Now, we're going to do some operations. Dialogue: 0,0:51:11.87,0:51:13.50,EN,,0,0,0,,I'm going to use this to make some counters. Dialogue: 0,0:51:14.99,0:51:16.20,EN,,0,0,0,,We'll see what a counter is. Dialogue: 0,0:51:17.12,0:51:18.51,EN,,0,0,0,,So let's define Dialogue: 0,0:51:23.32,0:51:26.65,EN,,0,0,0,,c1 to be a counter beginning at 0. Dialogue: 0,0:51:35.72,0:51:38.38,EN,,0,0,0,,Well, we know how to do this now, according to the model. Dialogue: 0,0:51:39.63,0:51:44.33,EN,,0,0,0,,I have to evaluate the expression make-counter in the global environment, Dialogue: 0,0:51:45.40,0:51:46.27,EN,,0,0,0,,make-counter of 0. Dialogue: 0,0:51:47.80,0:51:51.10,EN,,0,0,0,,Well, I look up make-counter and see that it's a procedure. Dialogue: 0,0:51:53.61,0:51:55.29,EN,,0,0,0,,I'm going to have to apply that procedure. Dialogue: 0,0:51:56.22,0:51:57.74,EN,,0,0,0,,The way I apply the procedure Dialogue: 0,0:51:58.43,0:51:59.96,EN,,0,0,0,,is by constructing a frame. Dialogue: 0,0:52:01.80,0:52:03.79,EN,,0,0,0,,Okay? So I construct a frame Dialogue: 0,0:52:06.59,0:52:10.44,EN,,0,0,0,,which has a value for n in it Dialogue: 0,0:52:11.77,0:52:12.64,EN,,0,0,0,,which is 0 Dialogue: 0,0:52:14.00,0:52:15.34,EN,,0,0,0,,and the parent environment Dialogue: 0,0:52:15.87,0:52:19.32,EN,,0,0,0,,is the one which is the environment of definition of make-counter. Dialogue: 0,0:52:23.93,0:52:28.36,EN,,0,0,0,,So I've made an environment by applying make-counter to 0. Dialogue: 0,0:52:31.45,0:52:34.40,EN,,0,0,0,,Now, I have to evaluate the body of make-counter, Dialogue: 0,0:52:34.41,0:52:37.72,EN,,0,0,0,,which is this lambda expression, in that environment. Dialogue: 0,0:52:40.64,0:52:42.30,EN,,0,0,0,,Well evaluating this body, Dialogue: 0,0:52:42.76,0:52:44.59,EN,,0,0,0,,this body is a lambda expression. Dialogue: 0,0:52:46.28,0:52:48.86,EN,,0,0,0,,Evaluate a lambda expression means make a procedure object. Dialogue: 0,0:52:49.56,0:52:51.00,EN,,0,0,0,,So I'm going to make a procedure object. Dialogue: 0,0:52:56.76,0:52:58.29,EN,,0,0,0,,And that procedure object has Dialogue: 0,0:52:58.29,0:53:00.46,EN,,0,0,0,,the environment it was defined in being that, Dialogue: 0,0:53:04.20,0:53:05.88,EN,,0,0,0,,where n was defined to be 0. Dialogue: 0,0:53:07.68,0:53:08.80,EN,,0,0,0,,And it has some code, Dialogue: 0,0:53:08.83,0:53:11.37,EN,,0,0,0,,which is the procedure of no arguments Dialogue: 0,0:53:11.40,0:53:15.28,EN,,0,0,0,,which does something, then sets something, Dialogue: 0,0:53:15.28,0:53:16.73,EN,,0,0,0,,and returns n. Dialogue: 0,0:53:17.88,0:53:18.81,EN,,0,0,0,,And this thing Dialogue: 0,0:53:19.42,0:53:21.23,EN,,0,0,0,,is going to be the object, Dialogue: 0,0:53:21.92,0:53:24.67,EN,,0,0,0,,which in the global environment, will have the name c1. Dialogue: 0,0:53:26.12,0:53:28.33,EN,,0,0,0,,So we construct a name here, c1, Dialogue: 0,0:53:28.64,0:53:32.14,EN,,0,0,0,,and say that equals that. Dialogue: 0,0:53:35.48,0:53:37.36,EN,,0,0,0,,Now, but also make another counter, Dialogue: 0,0:53:43.04,0:53:45.13,EN,,0,0,0,,c2 to be make-counter Dialogue: 0,0:53:50.94,0:53:52.19,EN,,0,0,0,,say, starting with 10. Dialogue: 0,0:53:54.25,0:53:55.90,EN,,0,0,0,,Then I do essentially the same thing. Dialogue: 0,0:53:56.64,0:54:00.40,EN,,0,0,0,,I apply the make-counter procedure, which I got from here, Dialogue: 0,0:54:00.99,0:54:04.52,EN,,0,0,0,,to make another frame with n being 10. Dialogue: 0,0:54:05.63,0:54:09.18,EN,,0,0,0,,That frame has the global environment as its parent. Dialogue: 0,0:54:10.04,0:54:11.80,EN,,0,0,0,,I then construct a procedure Dialogue: 0,0:54:13.04,0:54:17.63,EN,,0,0,0,,which has that as it's frame of definition. Dialogue: 0,0:54:18.27,0:54:21.66,EN,,0,0,0,,The code of it is Dialogue: 0,0:54:21.80,0:54:24.38,EN,,0,0,0,,the procedure of no arguments which does something. Dialogue: 0,0:54:25.54,0:54:28.60,EN,,0,0,0,,And it does a set, and so on. Dialogue: 0,0:54:28.60,0:54:31.22,EN,,0,0,0,,And n comes out. Okay? Dialogue: 0,0:54:31.45,0:54:34.83,EN,,0,0,0,,And c2 is this. Dialogue: 0,0:54:36.88,0:54:39.32,EN,,0,0,0,,Well, you're already beginning to see something fairly interesting. Dialogue: 0,0:54:40.17,0:54:41.92,EN,,0,0,0,,There are two n's here. Dialogue: 0,0:54:42.92,0:54:44.19,EN,,0,0,0,,They are not one n. Dialogue: 0,0:54:46.14,0:54:48.16,EN,,0,0,0,,Each time I called make-counter, Dialogue: 0,0:54:48.64,0:54:50.25,EN,,0,0,0,,I made another instance of n. Dialogue: 0,0:54:52.62,0:54:54.40,EN,,0,0,0,,These are distinct and separate from each other. Dialogue: 0,0:54:57.79,0:55:00.28,EN,,0,0,0,,Now, let's do some execution, use those counters. Dialogue: 0,0:55:05.92,0:55:15.00,EN,,0,0,0,,Well, what happens if I say, c1 at this point? Dialogue: 0,0:55:15.84,0:55:17.34,EN,,0,0,0,,Well, I go over here, Dialogue: 0,0:55:17.56,0:55:19.98,EN,,0,0,0,,and I say, oh yes, c1 is a procedure. Dialogue: 0,0:55:20.64,0:55:22.78,EN,,0,0,0,,I'm going to call this procedure on no arguments, Dialogue: 0,0:55:23.16,0:55:24.96,EN,,0,0,0,,but it has no parameters. Dialogue: 0,0:55:24.96,0:55:25.63,EN,,0,0,0,,That's right. Dialogue: 0,0:55:26.97,0:55:27.84,EN,,0,0,0,,What's its body? Dialogue: 0,0:55:27.96,0:55:30.02,EN,,0,0,0,,Well, I have to look over here, because I didn't write it down. Dialogue: 0,0:55:30.02,0:55:32.65,EN,,0,0,0,,It said, set n to one plus n Dialogue: 0,0:55:33.80,0:55:34.89,EN,,0,0,0,,and return n, Dialogue: 0,0:55:37.12,0:55:38.12,EN,,0,0,0,,increment n. Dialogue: 0,0:55:38.97,0:55:41.60,EN,,0,0,0,,Well, the n it says is this one. Dialogue: 0,0:55:43.08,0:55:44.60,EN,,0,0,0,,So I increment that n. Dialogue: 0,0:55:45.80,0:55:47.00,EN,,0,0,0,,That becomes one, Dialogue: 0,0:55:48.64,0:55:50.24,EN,,0,0,0,,and I return the value one. Dialogue: 0,0:55:53.13,0:55:56.49,EN,,0,0,0,,Supposing I then called c2. Dialogue: 0,0:55:58.38,0:55:59.20,EN,,0,0,0,,Well, what do I do? Dialogue: 0,0:55:59.23,0:56:03.33,EN,,0,0,0,,I say c2 is this procedure which does the same thing, Dialogue: 0,0:56:03.33,0:56:04.48,EN,,0,0,0,,but here's the n. Dialogue: 0,0:56:05.33,0:56:06.57,EN,,0,0,0,,It becomes 11. Dialogue: 0,0:56:10.97,0:56:14.59,EN,,0,0,0,,And so I have an 11 which is the value. Dialogue: 0,0:56:15.92,0:56:18.32,EN,,0,0,0,,I then can say, let's try c1 again. Dialogue: 0,0:56:20.91,0:56:22.56,EN,,0,0,0,,hum, c1 is this, Dialogue: 0,0:56:23.28,0:56:24.16,EN,,0,0,0,,that's two, Dialogue: 0,0:56:27.24,0:56:28.30,EN,,0,0,0,,so the answer is two. Dialogue: 0,0:56:29.66,0:56:30.75,EN,,0,0,0,,And c2 Dialogue: 0,0:56:33.37,0:56:35.31,EN,,0,0,0,,gives me a 12 by the same method, Dialogue: 0,0:56:35.74,0:56:37.55,EN,,0,0,0,,by walking down here looking at that Dialogue: 0,0:56:37.55,0:56:39.28,EN,,0,0,0,,and saying, here's the n, I'm incrementing. Dialogue: 0,0:56:41.64,0:56:43.68,EN,,0,0,0,,So what I have are computational objects. Dialogue: 0,0:56:45.21,0:56:46.86,EN,,0,0,0,,There are two counters, Dialogue: 0,0:56:48.96,0:56:51.02,EN,,0,0,0,,each with its own independent local state. Dialogue: 0,0:56:55.48,0:56:56.62,EN,,0,0,0,,Let's talk about this a little. Dialogue: 0,0:56:56.64,0:56:58.52,EN,,0,0,0,,This is a strange thing. Dialogue: 0,0:57:01.12,0:57:02.22,EN,,0,0,0,,What's an object? Dialogue: 0,0:57:04.11,0:57:06.12,EN,,0,0,0,,It's not at all obvious what an object is. Dialogue: 0,0:57:07.55,0:57:09.45,EN,,0,0,0,,We like to think about objects, Dialogue: 0,0:57:11.24,0:57:13.32,EN,,0,0,0,,because it's economical to think that way. Dialogue: 0,0:57:14.62,0:57:17.28,EN,,0,0,0,,It's an intellectual economy. Dialogue: 0,0:57:18.57,0:57:19.61,EN,,0,0,0,,I am an object. Dialogue: 0,0:57:20.99,0:57:22.30,EN,,0,0,0,,You are an object. Dialogue: 0,0:57:23.55,0:57:25.29,EN,,0,0,0,,We are not the same object. Dialogue: 0,0:57:27.52,0:57:29.64,EN,,0,0,0,,I can divide the world into two parts, Dialogue: 0,0:57:29.92,0:57:31.85,EN,,0,0,0,,me and you, Dialogue: 0,0:57:31.92,0:57:33.31,EN,,0,0,0,,and there's other things as well, Dialogue: 0,0:57:34.70,0:57:35.26,EN,,0,0,0,,such that Dialogue: 0,0:57:35.44,0:57:39.50,EN,,0,0,0,,most of the things I might want to discuss about my workings Dialogue: 0,0:57:39.68,0:57:40.89,EN,,0,0,0,,do not involve you, Dialogue: 0,0:57:41.39,0:57:44.67,EN,,0,0,0,,and most of the things I want to discuss about your workings don't involve me. Dialogue: 0,0:57:45.66,0:57:46.94,EN,,0,0,0,,I have a blood pressure, Dialogue: 0,0:57:47.50,0:57:48.38,EN,,0,0,0,,a temperature, Dialogue: 0,0:57:49.36,0:57:51.48,EN,,0,0,0,,a respiration rate, Dialogue: 0,0:57:53.34,0:57:54.99,EN,,0,0,0,,certain amount of sugar in my blood, Dialogue: 0,0:57:56.11,0:57:59.34,EN,,0,0,0,,and numerous, thousands, of state variables-- millions actually, Dialogue: 0,0:57:59.37,0:58:00.65,EN,,0,0,0,,or I don't know how many-- Dialogue: 0,0:58:00.93,0:58:03.48,EN,,0,0,0,,huge numbers of state variables in the physical sense Dialogue: 0,0:58:04.91,0:58:07.12,EN,,0,0,0,,which represent the state of me as a particle, Dialogue: 0,0:58:09.15,0:58:10.64,EN,,0,0,0,,and you have gazillions of them as well. Dialogue: 0,0:58:12.68,0:58:14.94,EN,,0,0,0,,And most of mine are uncoupled to most of yours. Dialogue: 0,0:58:17.31,0:58:19.50,EN,,0,0,0,,So we can compute the properties of me Dialogue: 0,0:58:20.56,0:58:22.83,EN,,0,0,0,,without worrying too much about the properties of you. Dialogue: 0,0:58:23.82,0:58:25.77,EN,,0,0,0,,If we had to work about both of us together, Dialogue: 0,0:58:25.96,0:58:27.82,EN,,0,0,0,,than the number of states that we have to consider Dialogue: 0,0:58:27.82,0:58:30.01,EN,,0,0,0,,is the product of the number of states you have and the number of states I have. Dialogue: 0,0:58:30.52,0:58:32.11,EN,,0,0,0,,But this way it's almost a sum. Dialogue: 0,0:58:32.65,0:58:35.34,EN,,0,0,0,,Now, indeed there are forces that couple us. Dialogue: 0,0:58:36.00,0:58:37.95,EN,,0,0,0,,I'm talking to you and your state changes. Dialogue: 0,0:58:38.44,0:58:40.09,EN,,0,0,0,,I'm looking at you and my state changes. Dialogue: 0,0:58:41.72,0:58:44.08,EN,,0,0,0,,Some of my state variables, a very few of them, Dialogue: 0,0:58:44.33,0:58:46.07,EN,,0,0,0,,therefore, are coupled to yours. Dialogue: 0,0:58:46.07,0:58:47.80,EN,,0,0,0,,If you were to suddenly yell very loud, Dialogue: 0,0:58:47.80,0:58:48.88,EN,,0,0,0,,my blood pressure would go up. Dialogue: 0,0:58:54.30,0:58:56.86,EN,,0,0,0,,However, and it may not be always appropriate Dialogue: 0,0:58:57.17,0:59:01.16,EN,,0,0,0,,to think about the world as being made out of independent states and independent particles. Dialogue: 0,0:59:02.12,0:59:04.46,EN,,0,0,0,,Lots of the bugs that occur in things like quantum mechanics, Dialogue: 0,0:59:05.23,0:59:08.70,EN,,0,0,0,,or the bugs in our minds that occur when we think about things like quantum mechanics, Dialogue: 0,0:59:08.89,0:59:10.97,EN,,0,0,0,,are due the fact that we are trying to think about things Dialogue: 0,0:59:10.97,0:59:12.96,EN,,0,0,0,,being broken up into independent pieces, Dialogue: 0,0:59:13.58,0:59:17.32,EN,,0,0,0,,when in fact there's more coupling than we see on the surface, Dialogue: 0,0:59:18.01,0:59:19.44,EN,,0,0,0,,or that we want to believe in, Dialogue: 0,0:59:19.61,0:59:21.69,EN,,0,0,0,,because we want to compute efficiently and effectively. Dialogue: 0,0:59:22.19,0:59:23.82,EN,,0,0,0,,We've been trained to think that way. Dialogue: 0,0:59:29.76,0:59:30.51,EN,,0,0,0,,Well, let's see. Dialogue: 0,0:59:31.50,0:59:33.44,EN,,0,0,0,,How would we know if we had objects at all? Dialogue: 0,0:59:35.12,0:59:37.34,EN,,0,0,0,,How can we tell if we have objects? Dialogue: 0,0:59:37.64,0:59:41.45,EN,,0,0,0,,Consider some possible optical illusions. Dialogue: 0,0:59:42.46,0:59:43.13,EN,,0,0,0,,This could be done. Dialogue: 0,0:59:45.04,0:59:47.69,EN,,0,0,0,,These pieces of chalk are not appropriately identical, Dialogue: 0,0:59:47.76,0:59:50.20,EN,,0,0,0,,but supposing you couldn't tell the difference of them by looking at them. Dialogue: 0,0:59:52.04,0:59:53.32,EN,,0,0,0,,Well, there's a possibility Dialogue: 0,0:59:53.32,0:59:55.16,EN,,0,0,0,,that this all a game I'm playing with mirrors. Dialogue: 0,0:59:56.07,0:59:57.60,EN,,0,0,0,,It's really the same piece of chalk, Dialogue: 0,0:59:59.36,1:00:00.48,EN,,0,0,0,,but you're seeing two of them. Dialogue: 0,1:00:01.61,1:00:03.87,EN,,0,0,0,,How would you know if you're seeing one or two? Dialogue: 0,1:00:05.04,1:00:06.70,EN,,0,0,0,,Well, there's only one way I know. Dialogue: 0,1:00:07.37,1:00:08.94,EN,,0,0,0,,You grab one of them and change it Dialogue: 0,1:00:09.45,1:00:10.67,EN,,0,0,0,,and see if the other one changed. Dialogue: 0,1:00:14.01,1:00:14.67,EN,,0,0,0,,And it didn't, Dialogue: 0,1:00:15.50,1:00:16.14,EN,,0,0,0,,so there's two of them. Dialogue: 0,1:00:19.50,1:00:20.16,EN,,0,0,0,,And, on the other hand, Dialogue: 0,1:00:20.17,1:00:22.20,EN,,0,0,0,,there is some other screwy properties of things like that. Dialogue: 0,1:00:22.57,1:00:24.01,EN,,0,0,0,,Like, how do we know if something changed? Dialogue: 0,1:00:25.00,1:00:27.93,EN,,0,0,0,,We have to look at it before and after the change. Dialogue: 0,1:00:28.65,1:00:30.02,EN,,0,0,0,,The change is an assignment, Dialogue: 0,1:00:30.02,1:00:31.45,EN,,0,0,0,,it's a moment in time. Dialogue: 0,1:00:32.14,1:00:34.60,EN,,0,0,0,,But that means we have to know it was the same one that we're looking at. Dialogue: 0,1:00:36.51,1:00:38.84,EN,,0,0,0,,So some very strange, and unusual, Dialogue: 0,1:00:38.84,1:00:40.38,EN,,0,0,0,,and obscure, and -- I don't understand Dialogue: 0,1:00:40.84,1:00:43.52,EN,,0,0,0,,the problems associated with assignment, Dialogue: 0,1:00:44.45,1:00:46.28,EN,,0,0,0,,and change, and objects. Dialogue: 0,1:00:47.29,1:00:48.99,EN,,0,0,0,,These could get very, very bad. Dialogue: 0,1:00:51.40,1:00:52.12,EN,,0,0,0,,For example, Dialogue: 0,1:00:53.31,1:00:55.60,EN,,0,0,0,,here I am, I am a particular person, Dialogue: 0,1:00:56.16,1:00:57.72,EN,,0,0,0,,a particular object, okay? Dialogue: 0,1:00:57.96,1:00:59.31,EN,,0,0,0,,Now, I can take out my knife, Dialogue: 0,1:01:00.68,1:01:01.77,EN,,0,0,0,,and cut my fingernail. Dialogue: 0,1:01:01.89,1:01:04.81,EN,,0,0,0,,Alright? A piece of my fingernail has fallen off onto the table. Dialogue: 0,1:01:05.93,1:01:10.16,EN,,0,0,0,,I believe I am the same person I was a second ago, Dialogue: 0,1:01:10.97,1:01:12.81,EN,,0,0,0,,but I'm not physically the same in the slightest. Dialogue: 0,1:01:14.46,1:01:15.43,EN,,0,0,0,,I have changed. Dialogue: 0,1:01:15.58,1:01:16.65,EN,,0,0,0,,Why am I the same? Dialogue: 0,1:01:18.11,1:01:19.40,EN,,0,0,0,,What is the identity of me? Dialogue: 0,1:01:20.96,1:01:23.50,EN,,0,0,0,,I don't know...Okay? Dialogue: 0,1:01:25.05,1:01:27.88,EN,,0,0,0,,Except for the fact that I have some sort of identity. Dialogue: 0,1:01:29.71,1:01:33.04,EN,,0,0,0,,And so, I think by introducing assignment and objects, Dialogue: 0,1:01:33.64,1:01:38.28,EN,,0,0,0,,we have opened ourselves up to all the horrible questions of philosophy Dialogue: 0,1:01:38.41,1:01:42.24,EN,,0,0,0,,that have been plaguing philosophers for some thousands of years about this sort of thing. Dialogue: 0,1:01:43.42,1:01:44.99,EN,,0,0,0,,It's why mathematics is a lot cleaner. Dialogue: 0,1:01:45.69,1:01:50.24,EN,,0,0,0,,Let's look at the best things I know to say about actions and identity. Dialogue: 0,1:01:52.44,1:01:55.39,EN,,0,0,0,,We say that an action, a, had an effect on an object, x, Dialogue: 0,1:01:55.77,1:01:56.70,EN,,0,0,0,,or equivalently, Dialogue: 0,1:01:56.92,1:01:58.41,EN,,0,0,0,,that x was changed by a, Dialogue: 0,1:01:58.89,1:02:01.66,EN,,0,0,0,,if some property, p, which was true of x before a, Dialogue: 0,1:02:01.87,1:02:03.76,EN,,0,0,0,,became false of x after a. Dialogue: 0,1:02:04.99,1:02:05.63,EN,,0,0,0,,That's test. Dialogue: 0,1:02:06.62,1:02:09.66,EN,,0,0,0,,It still means I have to have the x before and after. Dialogue: 0,1:02:10.91,1:02:12.54,EN,,0,0,0,,Or, the other way of saying this is, Dialogue: 0,1:02:12.94,1:02:14.94,EN,,0,0,0,,we say that two objects x and y are the same for any action Dialogue: 0,1:02:14.97,1:02:17.93,EN,,0,0,0,,which has an effect on x has the same effect on y Dialogue: 0,1:02:19.63,1:02:21.39,EN,,0,0,0,,However, objects are very useful, Dialogue: 0,1:02:21.44,1:02:23.18,EN,,0,0,0,,as I said, for intellectual economy. Dialogue: 0,1:02:24.64,1:02:27.12,EN,,0,0,0,,One of the things that's incredibly useful about them, Dialogue: 0,1:02:28.27,1:02:29.44,EN,,0,0,0,,is that the world Dialogue: 0,1:02:30.78,1:02:34.80,EN,,0,0,0,,is made out of independent objects with independent local state. Dialogue: 0,1:02:35.00,1:02:37.28,EN,,0,0,0,,We like to think that way, although it isn't completely true. Dialogue: 0,1:02:39.68,1:02:42.03,EN,,0,0,0,,When we want to make very complicated programs Dialogue: 0,1:02:42.03,1:02:43.26,EN,,0,0,0,,that deal with such a world, Dialogue: 0,1:02:43.98,1:02:46.44,EN,,0,0,0,,if we want those programs to be understandable by us Dialogue: 0,1:02:46.91,1:02:48.14,EN,,0,0,0,,and also to be changeable, Dialogue: 0,1:02:48.73,1:02:51.12,EN,,0,0,0,,so that if we change the world we change the program only a little bit, Dialogue: 0,1:02:51.39,1:02:53.70,EN,,0,0,0,,then we want there to be connections, isomorphism, Dialogue: 0,1:02:53.82,1:02:56.88,EN,,0,0,0,,between the objects in the world and the objects in our mental model. Dialogue: 0,1:02:58.76,1:03:01.44,EN,,0,0,0,,The modularity of the world can give us the modularity in our programming. Dialogue: 0,1:03:02.41,1:03:05.36,EN,,0,0,0,,So we invent things called object-oriented programming and things like that Dialogue: 0,1:03:05.88,1:03:08.36,EN,,0,0,0,,to provide us with that power. Dialogue: 0,1:03:10.06,1:03:10.94,EN,,0,0,0,,But it's even easier. Dialogue: 0,1:03:10.94,1:03:12.25,EN,,0,0,0,,Let's play a little game. Dialogue: 0,1:03:12.27,1:03:13.18,EN,,0,0,0,,I want to play a little game, Dialogue: 0,1:03:13.39,1:03:15.77,EN,,0,0,0,,show you an even easier example Dialogue: 0,1:03:16.00,1:03:21.74,EN,,0,0,0,,or where modularity can be enhanced by using an assignment statement, judiciously. Dialogue: 0,1:03:22.86,1:03:25.35,EN,,0,0,0,,One thing I want to enforce and impress on you, Dialogue: 0,1:03:25.45,1:03:27.44,EN,,0,0,0,,is don't use assignment statements the way Dialogue: 0,1:03:27.45,1:03:29.79,EN,,0,0,0,,you use it in FORTRAN or Basic or something or Pascal, Dialogue: 0,1:03:30.00,1:03:31.71,EN,,0,0,0,,to do the things you don't have to do with it. Dialogue: 0,1:03:34.04,1:03:36.62,EN,,0,0,0,,It's not the right way to think for most things. Dialogue: 0,1:03:36.97,1:03:38.28,EN,,0,0,0,,Sometimes it's essential, Dialogue: 0,1:03:38.68,1:03:39.69,EN,,0,0,0,,or maybe it's essential. Dialogue: 0,1:03:39.69,1:03:40.97,EN,,0,0,0,,We'll see more about that too. Dialogue: 0,1:03:42.24,1:03:44.22,EN,,0,0,0,,OK, let me show you a fun game here. Dialogue: 0,1:03:47.61,1:03:49.42,EN,,0,0,0,,There was a mathematician Dialogue: 0,1:03:49.68,1:03:53.69,EN,,0,0,0,,by the name of Cesaro--or Cesaro, Cesaro I suppose it is-- Dialogue: 0,1:03:54.48,1:03:57.45,EN,,0,0,0,,who figured out a clever way of computing pi. Dialogue: 0,1:03:58.38,1:04:04.30,EN,,0,0,0,,It turns out that if I take two random numbers Dialogue: 0,1:04:05.24,1:04:06.94,EN,,0,0,0,,two integers at random, Dialogue: 0,1:04:07.74,1:04:09.48,EN,,0,0,0,,and compute the greatest common divisor, Dialogue: 0,1:04:10.94,1:04:13.24,EN,,0,0,0,,their greatest common divisor is either one or it's not one. Dialogue: 0,1:04:13.84,1:04:15.64,EN,,0,0,0,,If it's one, then they have no common divisors. Dialogue: 0,1:04:18.14,1:04:20.68,EN,,0,0,0,,If their greatest common divisor is one-- Dialogue: 0,1:04:21.12,1:04:23.09,EN,,0,0,0,,the probability that two random numbers, Dialogue: 0,1:04:23.09,1:04:26.38,EN,,0,0,0,,two numbers chosen at random, has as greatest common divisor one Dialogue: 0,1:04:26.58,1:04:27.82,EN,,0,0,0,,is related to pi. Dialogue: 0,1:04:29.32,1:04:30.11,EN,,0,0,0,,In fact-- Dialogue: 0,1:04:31.11,1:04:32.33,EN,,0,0,0,,yes, it's very strange-- Dialogue: 0,1:04:32.94,1:04:34.41,EN,,0,0,0,,of course there are other ways of computing pi, Dialogue: 0,1:04:34.41,1:04:38.94,EN,,0,0,0,,like dropping pins on flags, and things like that, and sort of the same kind of thing. Dialogue: 0,1:04:40.19,1:04:48.97,EN,,0,0,0,,So the probability of that the GCD of number one and number two, Dialogue: 0,1:04:49.44,1:04:51.02,EN,,0,0,0,,two random numbers chosen, Dialogue: 0,1:04:51.71,1:04:53.66,EN,,0,0,0,,is 6 over pi squared. Dialogue: 0,1:04:55.61,1:04:56.83,EN,,0,0,0,,I'm not going to try to prove that. Dialogue: 0,1:04:57.15,1:04:59.64,EN,,0,0,0,,It's actually not too hard and sort of fun. Dialogue: 0,1:05:01.07,1:05:03.05,EN,,0,0,0,,How would we estimate such probability? Dialogue: 0,1:05:03.53,1:05:06.46,EN,,0,0,0,,Well, the way we do that, the way we estimate the probabilities, Dialogue: 0,1:05:07.23,1:05:08.65,EN,,0,0,0,,is by doing lots of experiments, Dialogue: 0,1:05:09.20,1:05:12.01,EN,,0,0,0,,and then computing the ratios of the ones that come out one way Dialogue: 0,1:05:12.01,1:05:13.58,EN,,0,0,0,,to the total number of experiments we do. Dialogue: 0,1:05:16.32,1:05:17.28,EN,,0,0,0,,It's called Monte Carlo, Dialogue: 0,1:05:18.04,1:05:22.38,EN,,0,0,0,,and it's useful in other contexts for doing things like integrals where you have lots and lots of variables-- Dialogue: 0,1:05:22.94,1:05:25.28,EN,,0,0,0,,the space which is limiting the dimensions you are doing you integral in. Dialogue: 0,1:05:26.27,1:05:28.70,EN,,0,0,0,,But going back to here, Dialogue: 0,1:05:29.76,1:05:31.72,EN,,0,0,0,,Let's look at this slide, Dialogue: 0,1:05:33.96,1:05:36.92,EN,,0,0,0,,We can use Cesaro's method for estimating pi Dialogue: 0,1:05:37.19,1:05:43.18,EN,,0,0,0,,with n trials by taking the square root of six over a Monte Carlo, Dialogue: 0,1:05:43.29,1:05:46.46,EN,,0,0,0,,a Monte Carlo experiment with n trials, Dialogue: 0,1:05:46.80,1:05:50.38,EN,,0,0,0,,with n trials using Cesaro's experiment, Dialogue: 0,1:05:51.37,1:05:57.56,EN,,0,0,0,,where Cesaro's experiment is the test of whether the GCD of two random numbers-- Dialogue: 0,1:05:58.96,1:06:01.60,EN,,0,0,0,,And you can see that I've already got some assignments in here, Dialogue: 0,1:06:01.84,1:06:03.13,EN,,0,0,0,,just by what I wrote. Dialogue: 0,1:06:04.04,1:06:07.49,EN,,0,0,0,,The fact that this word rand, in parentheses, Dialogue: 0,1:06:07.49,1:06:09.09,EN,,0,0,0,,therefore, that procedure call, Dialogue: 0,1:06:09.09,1:06:11.39,EN,,0,0,0,,yields a different value than this one, Dialogue: 0,1:06:11.39,1:06:13.72,EN,,0,0,0,,at least that's what I'm assuming by writing this this way, Dialogue: 0,1:06:14.62,1:06:16.75,EN,,0,0,0,,indicates that this is not a function, Dialogue: 0,1:06:18.20,1:06:20.57,EN,,0,0,0,,that there's internal state in it which is changing. Dialogue: 0,1:06:22.27,1:06:28.64,EN,,0,0,0,,If the GCD of those two random numbers is equal to one, Dialogue: 0,1:06:28.64,1:06:29.79,EN,,0,0,0,,that's the experiment. Dialogue: 0,1:06:31.48,1:06:35.18,EN,,0,0,0,,So here I have an experimental method for estimating the value of pi. Dialogue: 0,1:06:36.51,1:06:39.72,EN,,0,0,0,,Where, I can easily divide this problem into two parts. Dialogue: 0,1:06:40.02,1:06:44.70,EN,,0,0,0,,One is the specific Monte Carlo experiment of Cesaro, which you just saw, Dialogue: 0,1:06:44.99,1:06:48.56,EN,,0,0,0,,and the other is the general technique of doing Monte Carlo experiments. Dialogue: 0,1:06:49.16,1:06:50.27,EN,,0,0,0,,And that's what this is. Dialogue: 0,1:06:51.04,1:06:55.47,EN,,0,0,0,,If I want to do Monte Carlo experiments with n trials, Dialogue: 0,1:06:55.67,1:06:58.36,EN,,0,0,0,,a certain number of trials, and a particular experiment, Dialogue: 0,1:06:59.31,1:07:00.33,EN,,0,0,0,,the way I do that Dialogue: 0,1:07:00.84,1:07:02.70,EN,,0,0,0,,is I make a little iterative procedure Dialogue: 0,1:07:03.31,1:07:07.26,EN,,0,0,0,,which has variable the number of trials remaining and the number trials that have been passed, Dialogue: 0,1:07:08.35,1:07:09.44,EN,,0,0,0,,that I've gotten true. Dialogue: 0,1:07:10.13,1:07:12.21,EN,,0,0,0,,And if the number remaining is 0, Dialogue: 0,1:07:12.21,1:07:15.36,EN,,0,0,0,,then the answer is the number past divided by this whole number of trials, Dialogue: 0,1:07:16.04,1:07:17.52,EN,,0,0,0,,was the estimate of the probability. Dialogue: 0,1:07:19.07,1:07:20.04,EN,,0,0,0,,And if it's not, Dialogue: 0,1:07:20.04,1:07:22.08,EN,,0,0,0,,if I have more trials to do, Dialogue: 0,1:07:22.08,1:07:23.82,EN,,0,0,0,,then let's do one. We do an experiment. Dialogue: 0,1:07:23.85,1:07:27.30,EN,,0,0,0,,We call the procedure which is experiment on no arguments. Dialogue: 0,1:07:27.30,1:07:28.43,EN,,0,0,0,,We do the experiment Dialogue: 0,1:07:29.10,1:07:30.64,EN,,0,0,0,,and then, if that turned out to be true, Dialogue: 0,1:07:30.82,1:07:32.25,EN,,0,0,0,,we go around the loop Dialogue: 0,1:07:32.62,1:07:35.42,EN,,0,0,0,,decrementing the number of experiments we have to do by one Dialogue: 0,1:07:35.70,1:07:37.48,EN,,0,0,0,,and incrementing the number that were passed. Dialogue: 0,1:07:38.57,1:07:40.11,EN,,0,0,0,,And if the experiment was false, Dialogue: 0,1:07:40.41,1:07:42.25,EN,,0,0,0,,we just go around the loop Dialogue: 0,1:07:42.32,1:07:44.38,EN,,0,0,0,,decrementing the number of experiments remaining Dialogue: 0,1:07:44.44,1:07:46.60,EN,,0,0,0,,and keeping the number passed the same. Dialogue: 0,1:07:48.76,1:07:54.59,EN,,0,0,0,,We start this up iterating over the total number of trials with 0 experiments past. Dialogue: 0,1:07:55.42,1:07:57.10,EN,,0,0,0,,A very elegant little program. Dialogue: 0,1:07:57.74,1:08:00.55,EN,,0,0,0,,And I don't have to just do this with Cesaro's experiment, Dialogue: 0,1:08:00.55,1:08:02.73,EN,,0,0,0,,it could be lots of Monte Carlo experiments I might do. Dialogue: 0,1:08:03.36,1:08:07.12,EN,,0,0,0,,Of course, this depends upon the existence of some sort of random number generator. Dialogue: 0,1:08:07.34,1:08:10.99,EN,,0,0,0,,And random number generators generally look something like this. Dialogue: 0,1:08:13.60,1:08:16.32,EN,,0,0,0,,There is a random number generator-- Dialogue: 0,1:08:17.42,1:08:25.21,EN,,0,0,0,,is in fact a procedure which is going to do something just like the counter. Dialogue: 0,1:08:25.61,1:08:27.52,EN,,0,0,0,,It's going to update an x Dialogue: 0,1:08:28.33,1:08:31.82,EN,,0,0,0,,to the result of applying some function to x, Dialogue: 0,1:08:32.20,1:08:35.28,EN,,0,0,0,,where this function is some screwy kind of function Dialogue: 0,1:08:35.39,1:08:40.16,EN,,0,0,0,,that you might find out in Knuth's books on the details of programming. Dialogue: 0,1:08:41.56,1:08:45.75,EN,,0,0,0,,He does these wonderful books that are full of the details of programming, Dialogue: 0,1:08:45.75,1:08:48.52,EN,,0,0,0,,because I can't remember how to make a random number generator, Dialogue: 0,1:08:48.63,1:08:50.62,EN,,0,0,0,,but I can look it up there, and I can find out. Dialogue: 0,1:08:51.64,1:08:54.01,EN,,0,0,0,,And then, eventually, I return the value of x Dialogue: 0,1:08:54.08,1:08:57.40,EN,,0,0,0,,which is the state variable internal to the random number generator. Dialogue: 0,1:08:58.28,1:09:00.75,EN,,0,0,0,,That state variable is initialized somehow, Dialogue: 0,1:09:01.32,1:09:02.24,EN,,0,0,0,,and has a value. Dialogue: 0,1:09:03.39,1:09:08.11,EN,,0,0,0,,And this procedure is defined in the context where that variable is bound Dialogue: 0,1:09:10.41,1:09:15.26,EN,,0,0,0,,So this is a hidden piece of local state that you see here. Dialogue: 0,1:09:15.87,1:09:20.24,EN,,0,0,0,,And this procedure is defined in that context. Dialogue: 0,1:09:21.56,1:09:23.66,EN,,0,0,0,,Now, that's a very simple thing to do. Dialogue: 0,1:09:24.88,1:09:25.79,EN,,0,0,0,,And it's very nice. Dialogue: 0,1:09:25.99,1:09:27.77,EN,,0,0,0,,Supposing, I didn't want to use assignments. Dialogue: 0,1:09:29.10,1:09:31.47,EN,,0,0,0,,Supposing, I wanted to write this program without assignments. Dialogue: 0,1:09:32.73,1:09:33.93,EN,,0,0,0,,What problems would I have? Dialogue: 0,1:09:35.52,1:09:37.40,EN,,0,0,0,,Well, let's see. Dialogue: 0,1:09:37.82,1:09:41.10,EN,,0,0,0,,I'd like to use the overhead machine here, Dialogue: 0,1:09:42.06,1:09:42.70,EN,,0,0,0,,thank you. Dialogue: 0,1:09:43.47,1:09:47.66,EN,,0,0,0,,First of all, let's look at the whole thing. It's a big story. Right? Dialogue: 0,1:09:48.01,1:09:49.90,EN,,0,0,0,,Unfortunately, which tells you there is something wrong. Dialogue: 0,1:09:50.96,1:09:52.75,EN,,0,0,0,,It's at least that big, Dialogue: 0,1:09:53.42,1:09:54.60,EN,,0,0,0,,and it's monolithic. Dialogue: 0,1:09:56.76,1:10:00.12,EN,,0,0,0,,You don't have to understand or look at the text there right now Dialogue: 0,1:10:00.12,1:10:01.39,EN,,0,0,0,,to see that it's monolithic. Dialogue: 0,1:10:01.92,1:10:04.89,EN,,0,0,0,,It isn't a thing which is Cesaro's experiment. Dialogue: 0,1:10:04.89,1:10:07.90,EN,,0,0,0,,It's not pulled out from the Monte Carlo process. Dialogue: 0,1:10:09.87,1:10:11.84,EN,,0,0,0,,It's not separated. Let's look why. Dialogue: 0,1:10:14.22,1:10:15.85,EN,,0,0,0,,Remember, the constraint here Dialogue: 0,1:10:15.85,1:10:17.87,EN,,0,0,0,,is that every procedure Dialogue: 0,1:10:18.69,1:10:22.20,EN,,0,0,0,,return the same value for the same arguments. Dialogue: 0,1:10:22.97,1:10:24.75,EN,,0,0,0,,Every procedure represents a function. Dialogue: 0,1:10:26.92,1:10:28.50,EN,,0,0,0,,That's a different kind of constraint. Dialogue: 0,1:10:28.50,1:10:31.21,EN,,0,0,0,,Because when I have assignments, I can change some internal state variable. Dialogue: 0,1:10:31.74,1:10:34.03,EN,,0,0,0,,So let's see how that causes things to go wrong. Dialogue: 0,1:10:35.04,1:10:36.14,EN,,0,0,0,,Well, start at the beginning. Dialogue: 0,1:10:37.50,1:10:41.92,EN,,0,0,0,,Ah...The estimate of pi looks sort of the same. Dialogue: 0,1:10:42.66,1:10:45.88,EN,,0,0,0,,What I'm doing is I take the square root Dialogue: 0,1:10:46.35,1:10:50.22,EN,,0,0,0,,of six over the random GCD test applied to n Dialogue: 0,1:10:50.74,1:10:51.93,EN,,0,0,0,,whereas that's what this is. Dialogue: 0,1:10:52.96,1:10:55.20,EN,,0,0,0,,But here, we are beginning to see something funny. Dialogue: 0,1:10:55.20,1:10:57.93,EN,,0,0,0,,The random GCD test of a certain number of trials Dialogue: 0,1:10:58.32,1:10:59.98,EN,,0,0,0,,is just like we had before, Dialogue: 0,1:11:00.46,1:11:04.66,EN,,0,0,0,,an iteration on the number of trials remaining, Dialogue: 0,1:11:04.66,1:11:06.80,EN,,0,0,0,,the number of trials that have been passed, Dialogue: 0,1:11:08.27,1:11:09.71,EN,,0,0,0,,and another variable x. Dialogue: 0,1:11:10.75,1:11:11.76,EN,,0,0,0,,What's that x? Dialogue: 0,1:11:12.33,1:11:15.20,EN,,0,0,0,,That x is the state of the random number generator. Dialogue: 0,1:11:19.00,1:11:21.16,EN,,0,0,0,,And it is now going to be used here. Dialogue: 0,1:11:21.16,1:11:23.79,EN,,0,0,0,,The same random update function that I have over here Dialogue: 0,1:11:23.79,1:11:27.15,EN,,0,0,0,,is the one I would have used in a random number generator if I were building it the other way, Dialogue: 0,1:11:27.71,1:11:29.32,EN,,0,0,0,,the one I get out of Knuth's books. Dialogue: 0,1:11:31.56,1:11:33.36,EN,,0,0,0,,x is going to get transformed into x1, Dialogue: 0,1:11:33.37,1:11:34.36,EN,,0,0,0,,I need two random numbers. Dialogue: 0,1:11:34.81,1:11:36.92,EN,,0,0,0,,And x1 is going to get transformed into x2, Dialogue: 0,1:11:37.26,1:11:38.44,EN,,0,0,0,,I have two random numbers. Dialogue: 0,1:11:39.50,1:11:42.14,EN,,0,0,0,,I then have to do exactly what I did before. Dialogue: 0,1:11:42.52,1:11:44.19,EN,,0,0,0,,I take the GCD of x1 x2. Dialogue: 0,1:11:44.22,1:11:47.15,EN,,0,0,0,,If that's one, then I go around the loop with X2 being the next value of x. Dialogue: 0,1:11:54.78,1:11:55.98,EN,,0,0,0,,You see what's happened here Dialogue: 0,1:11:56.88,1:11:58.70,EN,,0,0,0,,is that the state of the random number generator Dialogue: 0,1:11:58.73,1:12:01.70,EN,,0,0,0,,is no longer confined to the insides of the random number generator. Dialogue: 0,1:12:01.80,1:12:02.73,EN,,0,0,0,,It has leaked out. Dialogue: 0,1:12:03.33,1:12:05.50,EN,,0,0,0,,It has leaked out into my procedure Dialogue: 0,1:12:05.50,1:12:10.08,EN,,0,0,0,,that does the Monte Carlo experiment. Dialogue: 0,1:12:10.70,1:12:11.87,EN,,0,0,0,,But what's worse than that, Dialogue: 0,1:12:11.87,1:12:16.24,EN,,0,0,0,,is it's also, because it was contained inside my experiment itself, Cesaro, Dialogue: 0,1:12:16.78,1:12:19.48,EN,,0,0,0,,It leaked out that two. Because Cesaro called twice, Dialogue: 0,1:12:20.86,1:12:22.47,EN,,0,0,0,,has to have a different value each time, Dialogue: 0,1:12:22.47,1:12:25.16,EN,,0,0,0,,if I going to have a legitimate experimental test. Dialogue: 0,1:12:26.32,1:12:28.32,EN,,0,0,0,,So Cesaro can't be a function either, Dialogue: 0,1:12:31.04,1:12:35.69,EN,,0,0,0,,unless I pass it the seed of the random number generator that is going to go wandering around. Dialogue: 0,1:12:36.52,1:12:39.37,EN,,0,0,0,,So unfortunately, the seed of random number generator Dialogue: 0,1:12:39.37,1:12:42.77,EN,,0,0,0,,has leaked out into Cesaro, from the random number generator, Dialogue: 0,1:12:42.88,1:12:45.16,EN,,0,0,0,,that's leaked into the Monte Carlo experiment. Dialogue: 0,1:12:45.64,1:12:49.12,EN,,0,0,0,,And, unfortunately, my Monte Carlo experiment here is no longer general. Dialogue: 0,1:12:50.25,1:12:51.80,EN,,0,0,0,,The Monte Carlo experiment here Dialogue: 0,1:12:52.03,1:12:54.73,EN,,0,0,0,,knows how many random numbers I need to do the experiment. Dialogue: 0,1:12:58.96,1:12:59.74,EN,,0,0,0,,That's sort of horrible. Dialogue: 0,1:13:00.08,1:13:02.54,EN,,0,0,0,,I lost an ability to decompose a problem into pieces, Dialogue: 0,1:13:03.44,1:13:09.12,EN,,0,0,0,,because I wasn't willing to accept the little loop of information, Dialogue: 0,1:13:09.50,1:13:12.43,EN,,0,0,0,,the feedback process, Dialogue: 0,1:13:12.88,1:13:15.94,EN,,0,0,0,,that happens inside the random number generator before Dialogue: 0,1:13:15.94,1:13:21.21,EN,,0,0,0,,that was made by having an assignment to a state variable that was confined to the random number generator. Dialogue: 0,1:13:22.92,1:13:25.48,EN,,0,0,0,,So the fact that the random number generator is an object, Dialogue: 0,1:13:25.92,1:13:27.37,EN,,0,0,0,,with an internal state variable, Dialogue: 0,1:13:28.06,1:13:29.36,EN,,0,0,0,,it's affected by nothing, Dialogue: 0,1:13:29.37,1:13:31.60,EN,,0,0,0,,but it'll give you something, and it will apply it's force to you, Dialogue: 0,1:13:32.80,1:13:34.28,EN,,0,0,0,,that was what we're missing now. Dialogue: 0,1:13:38.00,1:13:40.73,EN,,0,0,0,,OK, well I think we've seen Dialogue: 0,1:13:40.73,1:13:42.30,EN,,0,0,0,,enough reason for doing this, Dialogue: 0,1:13:42.83,1:13:45.24,EN,,0,0,0,,and it all sort of looks very wonderful. Dialogue: 0,1:13:45.38,1:13:50.70,EN,,0,0,0,,Wouldn't it be nice if assignment was a good thing Dialogue: 0,1:13:51.74,1:13:53.04,EN,,0,0,0,,and maybe it's worth it, Dialogue: 0,1:13:53.28,1:13:54.14,EN,,0,0,0,,but I'm not sure. Dialogue: 0,1:13:55.34,1:13:57.04,EN,,0,0,0,,As Mr. Gilbert and Sullivan said, Dialogue: 0,1:13:57.04,1:13:58.51,EN,,0,0,0,,things are seldom what they seem, Dialogue: 0,1:13:58.51,1:14:00.35,EN,,0,0,0,,skim milk masquerades as cream. Dialogue: 0,1:14:01.87,1:14:03.90,EN,,0,0,0,,Are there any questions? Dialogue: 0,1:14:16.97,1:14:18.30,EN,,0,0,0,,Are there any philosophers here? Dialogue: 0,1:14:20.06,1:14:22.03,EN,,0,0,0,,Anybody want to argue about objects? Dialogue: 0,1:14:24.32,1:14:25.50,EN,,0,0,0,,You're just floored, right? Dialogue: 0,1:14:29.72,1:14:30.72,EN,,0,0,0,,And you haven't done your homework yet. Dialogue: 0,1:14:30.73,1:14:32.00,EN,,0,0,0,,You haven't come up with a good question. Dialogue: 0,1:14:36.35,1:14:37.44,EN,,0,0,0,,Oh, well. Dialogue: 0,1:14:39.97,1:14:42.33,EN,,0,0,0,,Sure, thank you. Let's take the long break now. Dialogue: 0,1:14:47.90,1:14:56.41,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:14:56.44,1:15:05.69,Declare,,0,0,0,,{\an2\fad(500,500)}https://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec5b.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: EN Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Video Position: 1 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:21.17,0:00:24.12,EN,,0,0,0,,PROFESSOR: Well, now that we've given you some power Dialogue: 0,0:00:24.43,0:00:27.40,EN,,0,0,0,,to make independent local state and to model objects, Dialogue: 0,0:00:28.33,0:00:32.67,EN,,0,0,0,,I thought we'd do a bit of programming of a very complicated kind, Dialogue: 0,0:00:34.03,0:00:36.36,EN,,0,0,0,,just to illustrate what you can do with this sort of thing. Dialogue: 0,0:00:40.43,0:00:43.48,EN,,0,0,0,,I suppose, as I said, we were motivated by physical systems Dialogue: 0,0:00:44.11,0:00:46.25,EN,,0,0,0,,the ways we like to think about physical systems, Dialogue: 0,0:00:46.99,0:00:51.08,EN,,0,0,0,,which is that there are these things that the world is made out of. Dialogue: 0,0:00:52.06,0:00:55.98,EN,,0,0,0,,And each of these things has particular independent local state, Dialogue: 0,0:00:57.24,0:00:59.87,EN,,0,0,0,,and therefore it is a thing. That's what makes it a thing. Dialogue: 0,0:01:01.28,0:01:04.27,EN,,0,0,0,,And then we're going to say that in the model in the world Dialogue: 0,0:01:04.28,0:01:09.90,EN,,0,0,0,,we have a world and a model in our minds and in the computer of that world. Dialogue: 0,0:01:10.94,0:01:12.54,EN,,0,0,0,,And what I want to make is a correspondence Dialogue: 0,0:01:12.78,0:01:15.21,EN,,0,0,0,,between the objects in the world and the objects in the computer, Dialogue: 0,0:01:15.87,0:01:17.74,EN,,0,0,0,,the relationships between the objects in the world Dialogue: 0,0:01:17.96,0:01:21.72,EN,,0,0,0,,and the relationships between those same obj...--the model objects in the computer, Dialogue: 0,0:01:23.18,0:01:25.52,EN,,0,0,0,,and the functions that relate things in the Dialogue: 0,0:01:25.93,0:01:28.11,EN,,0,0,0,,to the functions that relate things in the computer. Dialogue: 0,0:01:30.84,0:01:33.82,EN,,0,0,0,,This buys us modularity. Dialogue: 0,0:01:34.74,0:01:36.75,EN,,0,0,0,,If we really believe the world is like that, Dialogue: 0,0:01:37.36,0:01:38.72,EN,,0,0,0,,that it's made out of these little pieces, Dialogue: 0,0:01:39.20,0:01:41.47,EN,,0,0,0,,and of course we could arrange our world to be like that, Dialogue: 0,0:01:42.03,0:01:43.95,EN,,0,0,0,,we could only model those things that are like that, Dialogue: 0,0:01:45.45,0:01:49.02,EN,,0,0,0,,then we can inherit the modularity in the world into our programming. Dialogue: 0,0:01:50.45,0:01:53.58,EN,,0,0,0,,That's why we would invent some of this object-oriented programming. Dialogue: 0,0:01:55.42,0:01:58.19,EN,,0,0,0,,Well, let's take the best kind of objects I know. Dialogue: 0,0:01:58.89,0:02:04.17,EN,,0,0,0,,They're completely--they're completely wonderful: electrical systems. Dialogue: 0,0:02:06.40,0:02:12.99,EN,,0,0,0,,Electrical systems really are the physicist's best, best objects. Dialogue: 0,0:02:14.22,0:02:16.76,EN,,0,0,0,,You see over here I have some piece of machinery. Dialogue: 0,0:02:17.12,0:02:18.28,EN,,0,0,0,,Right here's a piece of machinery. Dialogue: 0,0:02:20.04,0:02:22.88,EN,,0,0,0,,And it's got an electrical wire connecting Dialogue: 0,0:02:23.66,0:02:26.40,EN,,0,0,0,,one part of the machinery with another part of the machinery. Dialogue: 0,0:02:27.56,0:02:30.86,EN,,0,0,0,,And one of the wonderful properties of the electrical world Dialogue: 0,0:02:31.64,0:02:33.12,EN,,0,0,0,,is that I can say this is an object, Dialogue: 0,0:02:34.01,0:02:34.97,EN,,0,0,0,,and this is an object, Dialogue: 0,0:02:35.71,0:02:37.53,EN,,0,0,0,,and they're-- the connection between them is clear. Dialogue: 0,0:02:38.24,0:02:43.32,EN,,0,0,0,,In principle, there is no connection that I didn't describe with these wires. Dialogue: 0,0:02:44.74,0:02:46.12,EN,,0,0,0,,Let's say if I have light bulbs, Dialogue: 0,0:02:46.52,0:02:50.32,EN,,0,0,0,,Let's say if I have light bulbs, a light bulb and a power supply that's plugged into the outlet. Dialogue: 0,0:02:51.63,0:02:53.53,EN,,0,0,0,,Then the connection is perfectly clear. Dialogue: 0,0:02:53.62,0:02:55.42,EN,,0,0,0,,There's no other connections that we know of. Dialogue: 0,0:02:56.22,0:03:02.33,EN,,0,0,0,,If I were to tie a knot in the wire that connects the light bulb to the power supply, Dialogue: 0,0:03:02.68,0:03:03.64,EN,,0,0,0,,the light remains lit up. Dialogue: 0,0:03:04.04,0:03:04.76,EN,,0,0,0,,It doesn't care. Dialogue: 0,0:03:07.44,0:03:12.40,EN,,0,0,0,,That the way the physics is arranged is such that the connection can be made abstract, Dialogue: 0,0:03:13.08,0:03:15.27,EN,,0,0,0,,at least for low frequencies and things like that. Dialogue: 0,0:03:17.84,0:03:20.88,EN,,0,0,0,,So in fact, we have captured all of the connections there really are. Dialogue: 0,0:03:22.35,0:03:23.87,EN,,0,0,0,,Well, as you can go one step further Dialogue: 0,0:03:23.90,0:03:27.31,EN,,0,0,0,,and talk about the most abstract types of electrical systems we have, Dialogue: 0,0:03:27.85,0:03:29.42,EN,,0,0,0,,digital to dual circuits. Dialogue: 0,0:03:31.69,0:03:33.66,EN,,0,0,0,,And here there are certain kinds of objects. Dialogue: 0,0:03:34.64,0:03:40.12,EN,,0,0,0,,For example, in digital circuits we have things like inverters. Dialogue: 0,0:03:41.39,0:03:42.78,EN,,0,0,0,,We have things like and-gates. Dialogue: 0,0:03:43.99,0:03:45.40,EN,,0,0,0,,We have things like or-gates. Dialogue: 0,0:03:47.21,0:03:50.12,EN,,0,0,0,,We connect them together by sort-of wires Dialogue: 0,0:03:52.00,0:03:54.94,EN,,0,0,0,,which represent abstract signals. Dialogue: 0,0:03:55.61,0:03:57.18,EN,,0,0,0,,We don't really care as physical variables Dialogue: 0,0:03:57.21,0:03:59.72,EN,,0,0,0,,whether these are voltages or currents or some combination Dialogue: 0,0:04:00.01,0:04:03.44,EN,,0,0,0,,or water, water pressure. Dialogue: 0,0:04:05.20,0:04:07.32,EN,,0,0,0,,These abstract variables represent certain signals. Dialogue: 0,0:04:09.42,0:04:12.89,EN,,0,0,0,,And we build systems by wiring these things together with wires. Dialogue: 0,0:04:14.07,0:04:16.22,EN,,0,0,0,,So today what I'm going to show you, right now, Dialogue: 0,0:04:17.63,0:04:20.17,EN,,0,0,0,,we're going to build up an invented language in Lisp, Dialogue: 0,0:04:22.14,0:04:25.08,EN,,0,0,0,,embedded in the same sense that Henderson's picture language was embedded, Dialogue: 0,0:04:26.16,0:04:27.32,EN,,0,0,0,,which is not the same sense Dialogue: 0,0:04:27.88,0:04:31.61,EN,,0,0,0,,as the language of pattern match and substitution was done yesterday. Dialogue: 0,0:04:32.80,0:04:36.30,EN,,0,0,0,,The pattern match substitution language was interpreted by a Lisp program. Dialogue: 0,0:04:38.16,0:04:40.52,EN,,0,0,0,,But the embedding of Henderson's program Dialogue: 0,0:04:40.56,0:04:44.27,EN,,0,0,0,,is that we just build up more and more procedures that encapsulate the structure we want. Dialogue: 0,0:04:45.48,0:04:46.75,EN,,0,0,0,,So for example here, Dialogue: 0,0:04:47.72,0:04:50.64,EN,,0,0,0,,I'm going to have some various primitive kinds of objects, as you see, Dialogue: 0,0:04:51.05,0:04:52.12,EN,,0,0,0,,that one and that one. Dialogue: 0,0:04:53.50,0:04:55.18,EN,,0,0,0,,I'm going to use wires to combine them. Dialogue: 0,0:04:55.98,0:04:59.37,EN,,0,0,0,,The way I represent attaching-- I can make wires. Dialogue: 0,0:04:59.87,0:05:01.24,EN,,0,0,0,,So let's say A is a wire. Dialogue: 0,0:05:01.74,0:05:02.69,EN,,0,0,0,,And B is a wire. Dialogue: 0,0:05:02.69,0:05:03.46,EN,,0,0,0,,And C is a wire. Dialogue: 0,0:05:03.46,0:05:04.23,EN,,0,0,0,,And D is a wire. Dialogue: 0,0:05:04.23,0:05:04.83,EN,,0,0,0,,And E is wire. Dialogue: 0,0:05:04.83,0:05:05.64,EN,,0,0,0,,And S is a wire. Dialogue: 0,0:05:06.88,0:05:12.75,EN,,0,0,0,,Well, an or-gate that has both inputs, the inputs being A and B, Dialogue: 0,0:05:13.16,0:05:14.75,EN,,0,0,0,,and the output being wire D, Dialogue: 0,0:05:15.07,0:05:16.12,EN,,0,0,0,,you notate like this. Dialogue: 0,0:05:18.14,0:05:22.14,EN,,0,0,0,,An and-gate, which has inputs A and B and output C, Dialogue: 0,0:05:22.22,0:05:23.24,EN,,0,0,0,,we notate like that. Dialogue: 0,0:05:24.82,0:05:28.46,EN,,0,0,0,,By making such a sequence of declarations, Dialogue: 0,0:05:29.29,0:05:31.64,EN,,0,0,0,,I can wire together an arbitrary circuit. Dialogue: 0,0:05:32.75,0:05:34.64,EN,,0,0,0,,So I've just told you a set of primitives Dialogue: 0,0:05:35.31,0:05:38.51,EN,,0,0,0,,and means of combination for building digital circuits, Dialogue: 0,0:05:40.09,0:05:43.04,EN,,0,0,0,,when I need more in a real language than abstraction. Dialogue: 0,0:05:43.69,0:05:52.24,EN,,0,0,0,,And so for example, here I have--here I have a half adder. Dialogue: 0,0:05:52.67,0:05:55.55,EN,,0,0,0,,It's something you all know if you've done any digital design. Dialogue: 0,0:05:56.93,0:06:00.44,EN,,0,0,0,,It's used for adding numbers together on A and B Dialogue: 0,0:06:00.62,0:06:02.12,EN,,0,0,0,,and putting out a sum and a carry. Dialogue: 0,0:06:04.35,0:06:06.80,EN,,0,0,0,,And in fact, the wiring diagram is exactly what I told you. Dialogue: 0,0:06:07.45,0:06:10.99,EN,,0,0,0,,A half adder with things that come out of the box-- Dialogue: 0,0:06:11.13,0:06:14.11,EN,,0,0,0,,you see the box, the boundary, the abstraction is always a box. Dialogue: 0,0:06:14.79,0:06:19.70,EN,,0,0,0,,And there are things that come out of it, A, B, S, and C. Dialogue: 0,0:06:19.70,0:06:21.79,EN,,0,0,0,,Those are the declared variables-- Dialogue: 0,0:06:23.39,0:06:26.25,EN,,0,0,0,,declared variables of a lambda expression, Dialogue: 0,0:06:26.28,0:06:28.01,EN,,0,0,0,,which is the one that defines half adder. Dialogue: 0,0:06:31.40,0:06:35.96,EN,,0,0,0,,And internal to that, I make up some more wires, D and E, Dialogue: 0,0:06:36.00,0:06:37.44,EN,,0,0,0,,which I'm going to use for the interconnect-- Dialogue: 0,0:06:37.74,0:06:40.40,EN,,0,0,0,,here E is this one and D is this wire, Dialogue: 0,0:06:41.32,0:06:43.50,EN,,0,0,0,,the interconnect that doesn't come through the walls of the box-- Dialogue: 0,0:06:45.05,0:06:46.83,EN,,0,0,0,,and wire things together as you just saw. Dialogue: 0,0:06:48.79,0:06:50.89,EN,,0,0,0,,And the nice thing about this that I've just shown you Dialogue: 0,0:06:51.05,0:06:53.02,EN,,0,0,0,,this language is hierarchical in the right way. Dialogue: 0,0:06:53.85,0:06:55.71,EN,,0,0,0,,If a language isn't hierarchical in the right way, Dialogue: 0,0:06:55.95,0:06:59.96,EN,,0,0,0,,if it turns out that a compound object doesn't look like a primitive, Dialogue: 0,0:07:00.38,0:07:01.53,EN,,0,0,0,,there's something wrong with the language-- Dialogue: 0,0:07:02.59,0:07:04.22,EN,,0,0,0,,at least the way I feel about that. Dialogue: 0,0:07:06.41,0:07:09.58,EN,,0,0,0,,So here we have--here, instead of starting with mathematical functions, Dialogue: 0,0:07:09.60,0:07:11.12,EN,,0,0,0,,or things that compute mathematical functions, Dialogue: 0,0:07:11.15,0:07:12.65,EN,,0,0,0,,which is what we've been doing up until now, Dialogue: 0,0:07:13.85,0:07:16.65,EN,,0,0,0,,instead of starting with things that look like mathematical functions, Dialogue: 0,0:07:16.67,0:07:17.63,EN,,0,0,0,,or compute such things, Dialogue: 0,0:07:17.85,0:07:20.88,EN,,0,0,0,,we are starting with things that are electrical objects Dialogue: 0,0:07:21.04,0:07:22.64,EN,,0,0,0,,and we build up more electrical objects. Dialogue: 0,0:07:23.35,0:07:28.83,EN,,0,0,0,,And the glue we're using is basically the Lisp structure: lambdas. Dialogue: 0,0:07:30.38,0:07:32.93,EN,,0,0,0,,Lambda is the ultimate glue, if you will. Dialogue: 0,0:07:33.32,0:07:36.35,EN,,0,0,0,,And of course, half adder itself can be used Dialogue: 0,0:07:37.64,0:07:41.04,EN,,0,0,0,,in a more complicated abstraction called a full adder, Dialogue: 0,0:07:41.60,0:07:45.05,EN,,0,0,0,,which in fact involves two half adders, as you see here, Dialogue: 0,0:07:45.47,0:07:47.87,EN,,0,0,0,,hooked together with some extra wires, Dialogue: 0,0:07:48.08,0:07:51.29,EN,,0,0,0,,that you see here, S, C1, and C2, and an or-gate, Dialogue: 0,0:07:52.19,0:07:53.60,EN,,0,0,0,,to manufacture a full adder, Dialogue: 0,0:07:53.87,0:08:00.78,EN,,0,0,0,,which takes a input number, another input number, a carry in, Dialogue: 0,0:08:01.36,0:08:04.17,EN,,0,0,0,,and produces output, a sum and a carry out. Dialogue: 0,0:08:05.90,0:08:10.70,EN,,0,0,0,,And out of full adders, you can make real adder chains and big adders. Dialogue: 0,0:08:12.99,0:08:14.83,EN,,0,0,0,,So we have here a language so far Dialogue: 0,0:08:16.06,0:08:21.76,EN,,0,0,0,,That has primitives, means of combination, and means of abstraction to real language. Dialogue: 0,0:08:22.27,0:08:23.36,EN,,0,0,0,,Now, how are we going to implement this? Dialogue: 0,0:08:25.00,0:08:26.84,EN,,0,0,0,,Well, let's do it easily. Dialogue: 0,0:08:27.07,0:08:27.96,EN,,0,0,0,,Let's look at the primitives. Dialogue: 0,0:08:28.12,0:08:30.11,EN,,0,0,0,,The only problem is we have to implement the primitives. Dialogue: 0,0:08:31.16,0:08:32.56,EN,,0,0,0,,Nothing else has to be implemented, Dialogue: 0,0:08:33.74,0:08:38.00,EN,,0,0,0,,because we're picking up the means of combination and abstraction from Lisp, Dialogue: 0,0:08:39.96,0:08:41.88,EN,,0,0,0,,inheriting them in the embedding. Dialogue: 0,0:08:43.77,0:08:45.44,EN,,0,0,0,,OK, so let's look at a particular primitive. Dialogue: 0,0:08:45.86,0:08:47.40,EN,,0,0,0,,An inverter is a nice one. Dialogue: 0,0:08:51.54,0:08:54.67,EN,,0,0,0,,Now, inverter has two wires coming in, an in and an out. Dialogue: 0,0:08:57.31,0:09:02.62,EN,,0,0,0,,And somehow, it's going to have to know what to do when a signal comes in. Dialogue: 0,0:09:04.30,0:09:07.00,EN,,0,0,0,,So somehow it's going to have to tell its input wire-- Dialogue: 0,0:09:07.64,0:09:10.14,EN,,0,0,0,,and now we're going to talk about objects Dialogue: 0,0:09:10.44,0:09:12.41,EN,,0,0,0,,and we're going to see this in a little more detail soon-- Dialogue: 0,0:09:13.23,0:09:14.84,EN,,0,0,0,,but it's going to have to tell its input wire Dialogue: 0,0:09:15.82,0:09:18.48,EN,,0,0,0,,that when you change, tell me. Dialogue: 0,0:09:20.12,0:09:22.11,EN,,0,0,0,,So this object, the object which is the inverter Dialogue: 0,0:09:22.41,0:09:24.38,EN,,0,0,0,,has to tell the object which is the input wire, Dialogue: 0,0:09:25.13,0:09:26.40,EN,,0,0,0,,hi, my name is George. Dialogue: 0,0:09:26.87,0:09:31.02,EN,,0,0,0,,And my, my job is to do something with results when you change. Dialogue: 0,0:09:31.72,0:09:34.19,EN,,0,0,0,,So when you change, you get a change, tell me about it. Dialogue: 0,0:09:34.73,0:09:35.72,EN,,0,0,0,,Because I've got to do something with that. Dialogue: 0,0:09:36.88,0:09:40.30,EN,,0,0,0,,Well, that's done down here by adding an action on the input wire called invert-in, Dialogue: 0,0:09:41.40,0:09:44.64,EN,,0,0,0,,Well, that's done down here by adding an action on the input wire called invert-in, Dialogue: 0,0:09:45.07,0:09:46.94,EN,,0,0,0,,where invert-in is defined over here Dialogue: 0,0:09:47.05,0:09:48.76,EN,,0,0,0,,to be a procedure of no arguments, Dialogue: 0,0:09:49.98,0:09:54.59,EN,,0,0,0,,which gets the logical not of the signal on the input wire. Dialogue: 0,0:09:56.06,0:09:58.64,EN,,0,0,0,,And after some delay, which is the inverter delay, Dialogue: 0,0:09:59.26,0:10:01.15,EN,,0,0,0,,all these electrical objects have delays, Dialogue: 0,0:10:02.88,0:10:04.46,EN,,0,0,0,,we'll do the following thing-- Dialogue: 0,0:10:04.67,0:10:07.14,EN,,0,0,0,,set the signal on the output wire to the new value. Dialogue: 0,0:10:10.16,0:10:11.36,EN,,0,0,0,,A very simple program. Dialogue: 0,0:10:12.40,0:10:15.28,EN,,0,0,0,,Now, you have to imagine that the output wire has to be sensitive Dialogue: 0,0:10:15.77,0:10:18.27,EN,,0,0,0,,and know that when its signal changes, Dialogue: 0,0:10:19.28,0:10:21.15,EN,,0,0,0,,it may have to tell other guys, Dialogue: 0,0:10:21.79,0:10:24.78,EN,,0,0,0,,Hi, wake up. My value has changed. Dialogue: 0,0:10:26.05,0:10:30.14,EN,,0,0,0,,So when you hook together inverter with an and-gate or something like that, Dialogue: 0,0:10:30.46,0:10:32.20,EN,,0,0,0,,there has to be a lot of communication going on Dialogue: 0,0:10:32.86,0:10:35.07,EN,,0,0,0,,to make sure that the signal propagates right. Dialogue: 0,0:10:36.81,0:10:38.62,EN,,0,0,0,,And down here is nothing very exciting. Dialogue: 0,0:10:38.62,0:10:40.72,EN,,0,0,0,,This is just the definition of logical not Dialogue: 0,0:10:40.72,0:10:45.24,EN,,0,0,0,,for some particular representations of the logical values-- 1, 0 in this case. Dialogue: 0,0:10:46.73,0:10:49.16,EN,,0,0,0,,And we can look at things more complicated like and-gates. Dialogue: 0,0:10:49.78,0:10:55.80,EN,,0,0,0,,And-gates take two inputs, A1 and A2, we'll call them, and produce an output. Dialogue: 0,0:10:56.73,0:11:00.64,EN,,0,0,0,,But the structure of the and-gate is identical to the one we just saw. Dialogue: 0,0:11:00.86,0:11:03.44,EN,,0,0,0,,There's one called an and-action procedure that's defined, Dialogue: 0,0:11:04.52,0:11:09.07,EN,,0,0,0,,which is the thing that gets called when an input is changed. Dialogue: 0,0:11:10.91,0:11:12.88,EN,,0,0,0,,And what it does, of course, is nothing more than Dialogue: 0,0:11:12.91,0:11:15.37,EN,,0,0,0,,compute the logical and of the signals on the inputs. Dialogue: 0,0:11:16.19,0:11:18.76,EN,,0,0,0,,And after some delay, called the and-gate-delay, Dialogue: 0,0:11:20.46,0:11:24.36,EN,,0,0,0,,calls this procedure, which sets a signal on the output to a new value. Dialogue: 0,0:11:25.47,0:11:28.35,EN,,0,0,0,,Now, how I implement these things is all wishful thinking. Dialogue: 0,0:11:28.35,0:11:31.08,EN,,0,0,0,,As you see here, I have an assignment operation. Dialogue: 0,0:11:32.02,0:11:32.78,EN,,0,0,0,,It's not set. Dialogue: 0,0:11:34.57,0:11:36.78,EN,,0,0,0,,It's a derived assignment operation in the same way Dialogue: 0,0:11:36.78,0:11:38.73,EN,,0,0,0,,we had functions that were derived from CAR and CDR. Dialogue: 0,0:11:40.80,0:11:44.81,EN,,0,0,0,,So I, by convention, label that with an exclamation point. Dialogue: 0,0:11:46.34,0:11:49.18,EN,,0,0,0,,And over here, you see there's an add-action!, Dialogue: 0,0:11:49.44,0:11:54.67,EN,,0,0,0,,which is to inform the wire, called A1 locally in this and-gate, Dialogue: 0,0:11:55.63,0:11:58.68,EN,,0,0,0,,to call the and-action-procedure when it gets changed, Dialogue: 0,0:11:59.58,0:12:02.91,EN,,0,0,0,,and the wire A2 to call the and-action procedure when it gets changed. Dialogue: 0,0:12:06.31,0:12:07.23,EN,,0,0,0,,All very simple. Dialogue: 0,0:12:09.96,0:12:12.09,EN,,0,0,0,,Well, let's talk a little bit about this communication Dialogue: 0,0:12:12.70,0:12:16.12,EN,,0,0,0,,that must occur between these various parts. Dialogue: 0,0:12:18.54,0:12:19.66,EN,,0,0,0,,Suppose, for example, Dialogue: 0,0:12:23.12,0:12:24.27,EN,,0,0,0,,I have a very simple circuit Dialogue: 0,0:12:24.27,0:12:30.46,EN,,0,0,0,,which contains and-gate with wires a and b. Dialogue: 0,0:12:31.92,0:12:38.00,EN,,0,0,0,,And that connects through a wire called c to an inverter Dialogue: 0,0:12:39.72,0:12:41.53,EN,,0,0,0,,which has a wire output called d. Dialogue: 0,0:12:44.20,0:12:47.34,EN,,0,0,0,,What are the comput...--here's the physical world. Dialogue: 0,0:12:47.36,0:12:49.02,EN,,0,0,0,,It's an abstraction of the physical world. Dialogue: 0,0:12:49.86,0:12:53.40,EN,,0,0,0,,Now I can buy these out of little pieces that you get at Radio Shack for a few cents. Dialogue: 0,0:12:54.88,0:12:56.32,EN,,0,0,0,,And there are boxes that act like this, Dialogue: 0,0:12:57.16,0:13:00.22,EN,,0,0,0,,which have little numbers on them like LS04 or something. Dialogue: 0,0:13:01.53,0:13:08.16,EN,,0,0,0,,Now supposing I were to try to say what's the computational model. Dialogue: 0,0:13:09.01,0:13:10.94,EN,,0,0,0,,What is the thing that corresponds to that, Dialogue: 0,0:13:11.13,0:13:14.09,EN,,0,0,0,,that part of reality in the mind of us and in the computer? Dialogue: 0,0:13:15.85,0:13:19.13,EN,,0,0,0,,Well, I have to assign for every object in the world an object in the computer, Dialogue: 0,0:13:19.79,0:13:24.27,EN,,0,0,0,,and for every relationship in the world between them a relationship in the computer. Dialogue: 0,0:13:26.06,0:13:26.80,EN,,0,0,0,,That's my goal. Dialogue: 0,0:13:28.56,0:13:29.45,EN,,0,0,0,,So let's do that. Dialogue: 0,0:13:30.90,0:13:34.20,EN,,0,0,0,,Well, I have some sort of thing called the signal, A. Dialogue: 0,0:13:35.71,0:13:36.94,EN,,0,0,0,,This is A. It's a signal. Dialogue: 0,0:13:37.94,0:13:39.32,EN,,0,0,0,,It's a cloudy thing like that. Dialogue: 0,0:13:39.90,0:13:42.80,EN,,0,0,0,,And I have another one down here which I'm going to call B. Dialogue: 0,0:13:46.68,0:13:47.47,EN,,0,0,0,,It's another signal. Dialogue: 0,0:13:49.14,0:13:50.91,EN,,0,0,0,,Now this signal--these two signals Dialogue: 0,0:13:51.10,0:13:52.81,EN,,0,0,0,,are somehow going to have to hook together Dialogue: 0,0:13:53.72,0:13:58.75,EN,,0,0,0,,into a box, let's call it this, which is the and-gate, action procedure. Dialogue: 0,0:14:00.32,0:14:02.04,EN,,0,0,0,,That's the and-gate's action procedure. Dialogue: 0,0:14:07.66,0:14:08.59,EN,,0,0,0,,And it's going to produce Dialogue: 0,0:14:09.15,0:14:13.29,EN,,0,0,0,,well, it's going to interact with a signal object, which we call C-- Dialogue: 0,0:14:16.22,0:14:18.88,EN,,0,0,0,,a wire object, excuse me, we call C. Dialogue: 0,0:14:20.59,0:14:26.28,EN,,0,0,0,,this is going to put out again, or connect to, another action procedure Dialogue: 0,0:14:26.28,0:14:30.33,EN,,0,0,0,,which is one associated with the inverter in the world, not. Dialogue: 0,0:14:32.86,0:14:40.65,EN,,0,0,0,,And I'm going to have another--another wire, which we'll call D. Dialogue: 0,0:14:42.97,0:14:45.29,EN,,0,0,0,,So here's my layout of stuff. Dialogue: 0,0:14:46.00,0:14:49.44,EN,,0,0,0,,Now we have to say what's inside them and what they have to know to compute. Dialogue: 0,0:14:51.50,0:14:53.69,EN,,0,0,0,,Well, every--every one of these wires has to know Dialogue: 0,0:14:53.69,0:14:56.36,EN,,0,0,0,,what the value of the signal that's on that wire is. Dialogue: 0,0:14:57.34,0:15:00.00,EN,,0,0,0,,So there's going to be some variable inside here, we'll call it signal. Dialogue: 0,0:15:02.97,0:15:04.04,EN,,0,0,0,,And he owns a value. Dialogue: 0,0:15:05.68,0:15:07.74,EN,,0,0,0,,So there must be some environment associated with this. Dialogue: 0,0:15:08.89,0:15:11.34,EN,,0,0,0,,And for each one of these, there must be an environment that binds signal. Dialogue: 0,0:15:15.40,0:15:16.88,EN,,0,0,0,,And there must be a signal here, therefore. Dialogue: 0,0:15:19.40,0:15:21.92,EN,,0,0,0,,And presumably, signal's a value that's either 1 or 0, Dialogue: 0,0:15:22.81,0:15:23.48,EN,,0,0,0,,and signal. Dialogue: 0,0:15:28.00,0:15:30.56,EN,,0,0,0,,Now, we also have to have some Dialogue: 0,0:15:31.26,0:15:34.11,EN,,0,0,0,,list of people to inform if the signal here changes. Dialogue: 0,0:15:36.66,0:15:37.66,EN,,0,0,0,,We're going to have to inform this. Dialogue: 0,0:15:39.30,0:15:43.96,EN,,0,0,0,,So I've got that list. We'll call it the Action Procedures, AP. Dialogue: 0,0:15:44.50,0:15:45.60,EN,,0,0,0,,And it's presumably a list. Dialogue: 0,0:15:46.44,0:15:49.00,EN,,0,0,0,,But the first thing on the list, in this case, is this guy. Dialogue: 0,0:15:50.50,0:15:54.81,EN,,0,0,0,,And the action procedures of this one happens to have some list of stuff. Dialogue: 0,0:15:54.81,0:15:58.17,EN,,0,0,0,,There might be other people who are sharing A, who are looking at it. Dialogue: 0,0:15:59.02,0:16:01.31,EN,,0,0,0,,So there might be other guys on this list, like Dialogue: 0,0:16:01.72,0:16:03.23,EN,,0,0,0,,like somebody over there that we don't know about. Dialogue: 0,0:16:03.63,0:16:04.88,EN,,0,0,0,,It's the other guy attached to A. Dialogue: 0,0:16:07.20,0:16:09.64,EN,,0,0,0,,And the action procedure here also has to point to that, Dialogue: 0,0:16:11.12,0:16:12.40,EN,,0,0,0,,the list of action procedures. Dialogue: 0,0:16:13.07,0:16:16.35,EN,,0,0,0,,And of course, that means this one, its action procedures Dialogue: 0,0:16:16.78,0:16:18.53,EN,,0,0,0,,has to point up to here. Dialogue: 0,0:16:18.53,0:16:20.89,EN,,0,0,0,,This is the things-- the people it has to inform. Dialogue: 0,0:16:21.77,0:16:23.18,EN,,0,0,0,,And this guy has some too. Dialogue: 0,0:16:24.28,0:16:25.24,EN,,0,0,0,,But I don't know what they are Dialogue: 0,0:16:25.26,0:16:26.65,EN,,0,0,0,,because I didn't draw it in my diagram. Dialogue: 0,0:16:27.19,0:16:28.36,EN,,0,0,0,,It's the things connected to D. Dialogue: 0,0:16:30.32,0:16:32.62,EN,,0,0,0,,Now, it's also the case Dialogue: 0,0:16:33.80,0:16:36.96,EN,,0,0,0,,that when the and-action procedure is awakened, Dialogue: 0,0:16:37.02,0:16:41.31,EN,,0,0,0,,saying one of the people who know that you've told Dialogue: 0,0:16:41.45,0:16:44.84,EN,,0,0,0,,one of the people you've told to wake you up if their signal changes, Dialogue: 0,0:16:46.97,0:16:48.81,EN,,0,0,0,,you have to go look and ask them what's their signal Dialogue: 0,0:16:49.32,0:16:52.25,EN,,0,0,0,,so you can do the and, and produce a signal for this one. Dialogue: 0,0:16:57.09,0:16:58.75,EN,,0,0,0,,So there has to be, for example, Dialogue: 0,0:16:58.84,0:17:03.00,EN,,0,0,0,,information here saying A1, my A1 is this guy, Dialogue: 0,0:17:03.90,0:17:06.48,EN,,0,0,0,,my A1 is this guy, and my A2 is this guy. Dialogue: 0,0:17:08.93,0:17:09.98,EN,,0,0,0,,And not only that, Dialogue: 0,0:17:11.79,0:17:15.20,EN,,0,0,0,,when I do my and, I'm going to have to tell this guy something. Dialogue: 0,0:17:16.30,0:17:21.05,EN,,0,0,0,,So I need an output-- being this guy. Dialogue: 0,0:17:25.80,0:17:30.03,EN,,0,0,0,,And similarly, this guy's going to have a thing called the input Dialogue: 0,0:17:32.38,0:17:34.92,EN,,0,0,0,,that he interrogates to find out Dialogue: 0,0:17:36.75,0:17:38.64,EN,,0,0,0,,what the value of the signal on the input is, Dialogue: 0,0:17:38.64,0:17:40.09,EN,,0,0,0,,when the signal wakes up and says, I've changed, Dialogue: 0,0:17:41.05,0:17:43.47,EN,,0,0,0,,and sends a message this way saying, I've changed. Dialogue: 0,0:17:43.52,0:17:45.53,EN,,0,0,0,,This guy says, OK, what's your value now? Dialogue: 0,0:17:46.90,0:17:50.12,EN,,0,0,0,,When he gets that value, then he's going to have to say, Dialogue: 0,0:17:50.14,0:17:55.86,EN,,0,0,0,,OK, output changes this guy, changes this guy. Dialogue: 0,0:18:00.60,0:18:01.24,EN,,0,0,0,,And so on. Dialogue: 0,0:18:02.84,0:18:04.56,EN,,0,0,0,,And so I have to have at least that much connected-ness. Dialogue: 0,0:18:06.24,0:18:09.23,EN,,0,0,0,,Now, let's go back and look, for example, at the and-gate. Dialogue: 0,0:18:10.26,0:18:12.09,EN,,0,0,0,,Here we are back on this slide. Dialogue: 0,0:18:13.67,0:18:15.04,EN,,0,0,0,,And we can see some of these parts. Dialogue: 0,0:18:16.04,0:18:19.32,EN,,0,0,0,,For any particular and-gate, there is an A1, there is an A2, and the output. Dialogue: 0,0:18:21.03,0:18:23.53,EN,,0,0,0,,And those are, those are Dialogue: 0,0:18:25.08,0:18:28.16,EN,,0,0,0,,an environment that was created at the--those produce a frame Dialogue: 0,0:18:28.41,0:18:31.24,EN,,0,0,0,,at the time and-gate was called, Dialogue: 0,0:18:33.31,0:18:35.90,EN,,0,0,0,,A frame where A1, A2, and output are-- Dialogue: 0,0:18:36.67,0:18:39.20,EN,,0,0,0,,have as their values, they're bound to Dialogue: 0,0:18:39.60,0:18:44.25,EN,,0,0,0,,the wires which, they are--which were passed in. Dialogue: 0,0:18:46.24,0:18:47.31,EN,,0,0,0,,In that environment, Dialogue: 0,0:18:47.74,0:18:49.85,EN,,0,0,0,,I constructed a procedure Dialogue: 0,0:18:50.97,0:18:53.68,EN,,0,0,0,,this one right there. Dialogue: 0,0:18:54.59,0:18:57.31,EN,,0,0,0,,And-action-procedure was constructed in that environment. Dialogue: 0,0:18:58.35,0:19:00.70,EN,,0,0,0,,That was the result of evaluating a lambda expression. Dialogue: 0,0:19:01.62,0:19:05.48,EN,,0,0,0,,So it hangs onto the frame where these were defined. Dialogue: 0,0:19:07.16,0:19:09.34,EN,,0,0,0,,Local--part of its local state is that. Dialogue: 0,0:19:11.70,0:19:13.47,EN,,0,0,0,,The and-action-procedure, therefore, has Dialogue: 0,0:19:13.64,0:19:16.94,EN,,0,0,0,,access to A1, A2, and output as we see here. Dialogue: 0,0:19:17.31,0:19:19.64,EN,,0,0,0,,A1, A2, and output. Dialogue: 0,0:19:22.36,0:19:23.95,EN,,0,0,0,,Now, we haven't looked inside of a wire yet. Dialogue: 0,0:19:26.03,0:19:26.99,EN,,0,0,0,,That's all that remains. Dialogue: 0,0:19:29.03,0:19:29.92,EN,,0,0,0,,Let's look at a wire. Dialogue: 0,0:19:33.52,0:19:36.25,EN,,0,0,0,,Like the overhead, very good. Dialogue: 0,0:19:39.50,0:19:42.56,EN,,0,0,0,,Well, the wire, again, is a, is a somewhat complicated mess. Dialogue: 0,0:19:43.09,0:19:44.64,EN,,0,0,0,,Ooh, wrong one. Dialogue: 0,0:19:47.05,0:19:48.75,EN,,0,0,0,,It's a big complicated mess, like that. Dialogue: 0,0:19:50.06,0:19:53.10,EN,,0,0,0,,But let's look at it in detail and see what's going on. Dialogue: 0,0:19:54.72,0:19:56.67,EN,,0,0,0,,Well, the wire is one of these. Dialogue: 0,0:19:57.76,0:20:03.52,EN,,0,0,0,,And it has to have two things that are part of it, that it's state. Dialogue: 0,0:20:05.01,0:20:07.39,EN,,0,0,0,,One of them is the signal we see here. Dialogue: 0,0:20:07.45,0:20:10.06,EN,,0,0,0,,Heres, when we call make-wire to make a wire, Dialogue: 0,0:20:10.46,0:20:13.02,EN,,0,0,0,,then the first thing we do is we create some variables Dialogue: 0,0:20:14.94,0:20:16.08,EN,,0,0,0,,which are the signal Dialogue: 0,0:20:17.10,0:20:19.29,EN,,0,0,0,,and the action procedures for this wire. Dialogue: 0,0:20:22.32,0:20:23.44,EN,,0,0,0,,And in that context, Dialogue: 0,0:20:23.76,0:20:27.04,EN,,0,0,0,,we define various functions--or procedures, excuse me, procedures. Dialogue: 0,0:20:27.84,0:20:31.15,EN,,0,0,0,,One of them is called set-my-signal to a new value. Dialogue: 0,0:20:32.85,0:20:37.42,EN,,0,0,0,,And what that does is takes a new value in. Dialogue: 0,0:20:37.93,0:20:40.36,EN,,0,0,0,,If that's equal to my current value of my signal, I'm done. Dialogue: 0,0:20:40.36,0:20:42.62,EN,,0,0,0,,Otherwise, I set the signal to the new value Dialogue: 0,0:20:42.75,0:20:44.60,EN,,0,0,0,,and call each of the action procedures Dialogue: 0,0:20:46.52,0:20:52.51,EN,,0,0,0,,that I've been, that I've been--what's the right word? -- introduced to. Dialogue: 0,0:20:54.63,0:21:01.53,EN,,0,0,0,,I get introduced when the and-gate was applied to me. Dialogue: 0,0:21:04.13,0:21:05.60,EN,,0,0,0,,By add action procedure at the bottom. Dialogue: 0,0:21:07.41,0:21:10.80,EN,,0,0,0,,Also, I have to define a way of accepting an action procedure-- Dialogue: 0,0:21:10.81,0:21:11.82,EN,,0,0,0,,which is what you see here--- Dialogue: 0,0:21:12.80,0:21:15.13,EN,,0,0,0,,which increments my action procedures Dialogue: 0,0:21:15.56,0:21:21.63,EN,,0,0,0,,using set to the result of CONSing up a new process--a procedure, Dialogue: 0,0:21:21.79,0:21:24.25,EN,,0,0,0,,which is passed to me, on to my actions procedures list. Dialogue: 0,0:21:25.40,0:21:27.58,EN,,0,0,0,,And for technical reasons, I have to call that procedure one. Dialogue: 0,0:21:27.78,0:21:29.20,EN,,0,0,0,,So I'm not going to tell you anything about that, Dialogue: 0,0:21:29.39,0:21:33.15,EN,,0,0,0,,that has to do with event-driven simulations and getting them started, Dialogue: 0,0:21:34.59,0:21:36.00,EN,,0,0,0,,which takes a little bit of thinking. Dialogue: 0,0:21:36.95,0:21:39.40,EN,,0,0,0,,And finally, I'm going to define a thing called the dispatcher, Dialogue: 0,0:21:39.96,0:21:43.58,EN,,0,0,0,,which is a way of passing a message to a wire, Dialogue: 0,0:21:45.37,0:21:48.65,EN,,0,0,0,,which is going to be used to extract from it various information, Dialogue: 0,0:21:49.07,0:21:51.48,EN,,0,0,0,,like what is the current signal value? Dialogue: 0,0:21:53.82,0:21:55.66,EN,,0,0,0,,What is the method of setting your signal? Dialogue: 0,0:21:57.18,0:21:58.28,EN,,0,0,0,,I want to get that out of it. Dialogue: 0,0:22:00.10,0:22:02.60,EN,,0,0,0,,How do I--how do I add another action procedure? Dialogue: 0,0:22:05.51,0:22:09.36,EN,,0,0,0,,And I'm going to return that dispatch, that procedure as a value. Dialogue: 0,0:22:09.94,0:22:11.87,EN,,0,0,0,,So the wire that I've constructed Dialogue: 0,0:22:12.00,0:22:13.55,EN,,0,0,0,,is a message accepting object Dialogue: 0,0:22:14.25,0:22:16.01,EN,,0,0,0,,which accepts a message like, like Dialogue: 0,0:22:16.44,0:22:18.36,EN,,0,0,0,,what's your method of adding action procedures? Dialogue: 0,0:22:19.92,0:22:21.00,EN,,0,0,0,,That it'll give me a procedure, Dialogue: 0,0:22:21.64,0:22:23.05,EN,,0,0,0,,which is the add action procedure, Dialogue: 0,0:22:23.07,0:22:26.54,EN,,0,0,0,,which I can then apply to an action procedure Dialogue: 0,0:22:27.05,0:22:29.01,EN,,0,0,0,,to create another action procedure in the wire. Dialogue: 0,0:22:31.62,0:22:32.82,EN,,0,0,0,,So that's a permission. Dialogue: 0,0:22:33.20,0:22:36.08,EN,,0,0,0,,So it's given me permission to change your action procedures. Dialogue: 0,0:22:37.82,0:22:40.16,EN,,0,0,0,,And in fact, you can see that over here. Dialogue: 0,0:22:41.71,0:22:42.32,EN,,0,0,0,,Next slide. Dialogue: 0,0:22:43.53,0:22:43.82,EN,,0,0,0,,Ah. Dialogue: 0,0:22:47.76,0:22:49.12,EN,,0,0,0,,This is nothing very interesting. Dialogue: 0,0:22:49.12,0:22:50.65,EN,,0,0,0,,The call each of the action procedures Dialogue: 0,0:22:50.89,0:22:52.57,EN,,0,0,0,,is just a CDRing down a list. Dialogue: 0,0:22:52.73,0:22:54.60,EN,,0,0,0,,And I'm not going to even talk about that anymore. Dialogue: 0,0:22:54.99,0:22:56.25,EN,,0,0,0,,We're too advanced for that. Dialogue: 0,0:22:57.56,0:23:00.67,EN,,0,0,0,,However, if I want to get a signal from a wire, Dialogue: 0,0:23:01.02,0:23:02.54,EN,,0,0,0,,I ask the wire-- which is, Dialogue: 0,0:23:02.54,0:23:03.09,EN,,0,0,0,,what is the wire? Dialogue: 0,0:23:03.09,0:23:05.40,EN,,0,0,0,,The wire is the dispatch returned by creating the wire. Dialogue: 0,0:23:05.86,0:23:06.48,EN,,0,0,0,,It's a procedure. Dialogue: 0,0:23:06.83,0:23:12.27,EN,,0,0,0,,I call that dispatch on the message get-signal. Dialogue: 0,0:23:12.91,0:23:15.40,EN,,0,0,0,,And what I should expect to get is a method of getting a signal. Dialogue: 0,0:23:16.90,0:23:17.96,EN,,0,0,0,,Or actually, I get the signal. Dialogue: 0,0:23:19.22,0:23:20.52,EN,,0,0,0,,If I want to set a signal, Dialogue: 0,0:23:22.65,0:23:23.96,EN,,0,0,0,,I want to change a signal, Dialogue: 0,0:23:24.51,0:23:26.76,EN,,0,0,0,,then what I'm going to do Dialogue: 0,0:23:26.92,0:23:29.69,EN,,0,0,0,,is take a wire as an argument and a new value for the signal, Dialogue: 0,0:23:30.01,0:23:32.43,EN,,0,0,0,,I would ask the wire for permission to set the signal Dialogue: 0,0:23:32.84,0:23:37.61,EN,,0,0,0,,and use that permission, which is a procedure, on the new value. Dialogue: 0,0:23:38.70,0:23:40.51,EN,,0,0,0,,And if we go back to the overhead here, Dialogue: 0,0:23:41.64,0:23:43.24,EN,,0,0,0,,Okay, thank you, Dialogue: 0,0:23:44.20,0:23:45.63,EN,,0,0,0,,we go back to the overhead here, Dialogue: 0,0:23:45.92,0:23:48.75,EN,,0,0,0,,we see that the method-- if I ask for the method of setting the signal, Dialogue: 0,0:23:49.34,0:23:50.44,EN,,0,0,0,,that's over here, Dialogue: 0,0:23:52.25,0:23:55.69,EN,,0,0,0,,it's set-my-signal, a procedure that's defined inside the wire, Dialogue: 0,0:23:56.25,0:23:57.69,EN,,0,0,0,,which if we look over here Dialogue: 0,0:23:58.72,0:23:59.74,EN,,0,0,0,,is the thing that says Dialogue: 0,0:24:00.43,0:24:02.68,EN,,0,0,0,,set my internal value called the signal, Dialogue: 0,0:24:02.73,0:24:05.50,EN,,0,0,0,,my internal variable, which is the signal, Dialogue: 0,0:24:07.61,0:24:10.03,EN,,0,0,0,,to the new value, which is passed to me as an argument, Dialogue: 0,0:24:10.78,0:24:13.01,EN,,0,0,0,,and then call each of the action procedures waking them up. Dialogue: 0,0:24:16.34,0:24:16.99,EN,,0,0,0,,Very simple. Dialogue: 0,0:24:19.24,0:24:20.76,EN,,0,0,0,,Ok, Going back to that slide, Dialogue: 0,0:24:22.48,0:24:24.32,EN,,0,0,0,,we also have the one last thing-- Dialogue: 0,0:24:24.36,0:24:27.31,EN,,0,0,0,,which I suppose now you can easily work out for yourself-- Dialogue: 0,0:24:27.77,0:24:29.15,EN,,0,0,0,,is the way you add an action. Dialogue: 0,0:24:30.10,0:24:35.18,EN,,0,0,0,,You take a wire--a wire and an action procedure. Dialogue: 0,0:24:36.47,0:24:39.31,EN,,0,0,0,,And I ask the wire for permission to add an action. Dialogue: 0,0:24:40.05,0:24:44.22,EN,,0,0,0,,Getting that permission, I use that permission to give it an action procedure. Dialogue: 0,0:24:45.84,0:24:47.08,EN,,0,0,0,,So that's a real object. Dialogue: 0,0:24:48.57,0:24:50.32,EN,,0,0,0,,There's a few more details about this. Dialogue: 0,0:24:52.46,0:24:58.39,EN,,0,0,0,,For example, how am I going to control this thing? Dialogue: 0,0:24:58.39,0:24:59.69,EN,,0,0,0,,How do I do these delays? Dialogue: 0,0:25:00.99,0:25:02.54,EN,,0,0,0,,Okay? Let's look at that for a second. Dialogue: 0,0:25:05.50,0:25:07.98,EN,,0,0,0,,The next one here. Dialogue: 0,0:25:08.36,0:25:08.88,EN,,0,0,0,,Let's see. Dialogue: 0,0:25:09.57,0:25:14.17,EN,,0,0,0,,We know when we looked at the and-gate or the not-gate Dialogue: 0,0:25:15.31,0:25:17.00,EN,,0,0,0,,that when a signal changed on the input, Dialogue: 0,0:25:17.24,0:25:18.19,EN,,0,0,0,,there was a delay. Dialogue: 0,0:25:18.77,0:25:21.24,EN,,0,0,0,,And then it was going to call the procedure, Dialogue: 0,0:25:21.63,0:25:23.00,EN,,0,0,0,,which was going to change the output. Dialogue: 0,0:25:26.04,0:25:27.92,EN,,0,0,0,,Well, how are we going to do this? Dialogue: 0,0:25:28.12,0:25:29.92,EN,,0,0,0,,We're going to make up some mechanism, Dialogue: 0,0:25:30.30,0:25:32.00,EN,,0,0,0,,a fairly complicated mechanism at that, Dialogue: 0,0:25:32.33,0:25:33.76,EN,,0,0,0,,which we're going to have to be very careful about. Dialogue: 0,0:25:34.72,0:25:37.23,EN,,0,0,0,,But after a delay, we're going to do an action. Dialogue: 0,0:25:37.39,0:25:38.12,EN,,0,0,0,,A delay is a number, Dialogue: 0,0:25:38.16,0:25:39.23,EN,,0,0,0,,and an action is a procedure. Dialogue: 0,0:25:40.59,0:25:43.72,EN,,0,0,0,,What that's going to be is they're going to have a special structure called an agenda, Dialogue: 0,0:25:45.50,0:25:48.80,EN,,0,0,0,,which is a thing that organizes time and actions. Dialogue: 0,0:25:49.51,0:25:50.88,EN,,0,0,0,,And we're going to see that in a while. Dialogue: 0,0:25:50.88,0:25:52.54,EN,,0,0,0,,I don't want to get into that right now. Dialogue: 0,0:25:53.07,0:25:58.28,EN,,0,0,0,,But the agenda has a moment at which--at which something happens. Dialogue: 0,0:25:59.13,0:26:02.46,EN,,0,0,0,,We're setting up for later at some moment, Dialogue: 0,0:26:02.51,0:26:05.68,EN,,0,0,0,,which is the sum of the time, which is the delay time plus the current time, Dialogue: 0,0:26:05.69,0:26:07.13,EN,,0,0,0,,which the agenda thinks is now. Dialogue: 0,0:26:09.02,0:26:10.56,EN,,0,0,0,,We're going to set up to do this action, Dialogue: 0,0:26:11.02,0:26:12.40,EN,,0,0,0,,and add that to the agenda. Dialogue: 0,0:26:15.28,0:26:18.03,EN,,0,0,0,,And the way this machine will now run is very simple. Dialogue: 0,0:26:18.66,0:26:21.48,EN,,0,0,0,,We have a thing called propagate, which is the way things run. Dialogue: 0,0:26:22.71,0:26:25.95,EN,,0,0,0,,If the agenda is empty, we're done--if there's nothing more to be done. Dialogue: 0,0:26:27.44,0:26:28.16,EN,,0,0,0,,Otherwise, Dialogue: 0,0:26:29.76,0:26:31.53,EN,,0,0,0,,we're going to take the first item off the agenda, Dialogue: 0,0:26:31.71,0:26:33.34,EN,,0,0,0,,and that's a procedure of no arguments. Dialogue: 0,0:26:34.20,0:26:36.03,EN,,0,0,0,,So that we're going to see extra parentheses here. Dialogue: 0,0:26:36.03,0:26:37.85,EN,,0,0,0,,We call that on no arguments. Dialogue: 0,0:26:39.19,0:26:40.17,EN,,0,0,0,,That takes the action. Dialogue: 0,0:26:42.20,0:26:44.17,EN,,0,0,0,,Then we remove that first item from the agenda, Dialogue: 0,0:26:44.59,0:26:46.14,EN,,0,0,0,,and we go around the propagation loop. Dialogue: 0,0:26:48.91,0:26:50.75,EN,,0,0,0,,So that's the overall structure of this thing. Dialogue: 0,0:26:53.38,0:26:55.93,EN,,0,0,0,,Now, there's a, a few other things we can look at. Dialogue: 0,0:26:57.43,0:27:00.01,EN,,0,0,0,,And then we're going to look into the agenda a little while from now. Dialogue: 0,0:27:00.57,0:27:01.55,EN,,0,0,0,,Now the overhead again. Dialogue: 0,0:27:02.80,0:27:04.67,EN,,0,0,0,,Well, in order to set this thing going, Dialogue: 0,0:27:04.67,0:27:07.41,EN,,0,0,0,,I just want to show you some behavior out of this simulator. Dialogue: 0,0:27:07.85,0:27:09.93,EN,,0,0,0,,By the way, you may think this simulator is very simple, Dialogue: 0,0:27:10.40,0:27:12.01,EN,,0,0,0,,and probably too simple to be useful. Dialogue: 0,0:27:12.57,0:27:13.76,EN,,0,0,0,,The fact of the matter is Dialogue: 0,0:27:13.98,0:27:15.39,EN,,0,0,0,,that this simulator has been used Dialogue: 0,0:27:15.72,0:27:17.44,EN,,0,0,0,,to manufacture a fairly large computer. Dialogue: 0,0:27:18.68,0:27:20.64,EN,,0,0,0,,So this is a real live example. Dialogue: 0,0:27:22.36,0:27:24.06,EN,,0,0,0,,Actually, not exactly this simulator, Dialogue: 0,0:27:24.06,0:27:25.39,EN,,0,0,0,,because I'll tell you the difference. Dialogue: 0,0:27:25.84,0:27:28.70,EN,,0,0,0,,The difference is that there were many more different kinds of primitives. Dialogue: 0,0:27:29.82,0:27:32.22,EN,,0,0,0,,There's not just the word inverter or and-gate. Dialogue: 0,0:27:33.20,0:27:35.72,EN,,0,0,0,,There were things like edge-triggered, Dialogue: 0,0:27:36.25,0:27:39.88,EN,,0,0,0,,flip-flops, and latches Dialogue: 0,0:27:40.70,0:27:44.52,EN,,0,0,0,,transparent latches, and adders, and things like that. Dialogue: 0,0:27:45.17,0:27:47.31,EN,,0,0,0,,And the difficulty with that Dialogue: 0,0:27:47.45,0:27:50.86,EN,,0,0,0,,is there's pages and pages of the definitions of all these primitives Dialogue: 0,0:27:51.20,0:27:52.89,EN,,0,0,0,,with numbers like LS04. Dialogue: 0,0:27:54.69,0:27:56.74,EN,,0,0,0,,And then there's many more parameters for them. Dialogue: 0,0:27:56.74,0:27:57.98,EN,,0,0,0,,It's not just one delay. Dialogue: 0,0:27:58.48,0:28:00.81,EN,,0,0,0,,There's things like set up times and hold times and all that. Dialogue: 0,0:28:01.22,0:28:03.40,EN,,0,0,0,,But with the exception of that part of the complexity, Dialogue: 0,0:28:03.82,0:28:08.20,EN,,0,0,0,,the structure of the simulator that we use for building a real computer, Dialogue: 0,0:28:09.08,0:28:12.89,EN,,0,0,0,,that works is exactly what you're seeing here. Dialogue: 0,0:28:15.11,0:28:19.27,EN,,0,0,0,,Well in any case, what we have here is a few simple things. Dialogue: 0,0:28:19.27,0:28:22.59,EN,,0,0,0,,Like, there's inverter delays being set up and making a new agenda. Dialogue: 0,0:28:23.03,0:28:25.52,EN,,0,0,0,,And then we can make some inputs. Dialogue: 0,0:28:26.03,0:28:29.18,EN,,0,0,0,,Ok? There's input-1, input-2, a sum and a carry, which are wires. Dialogue: 0,0:28:29.46,0:28:31.88,EN,,0,0,0,,I'm going to put a special kind of object called a probe Dialogue: 0,0:28:32.51,0:28:34.64,EN,,0,0,0,,onto, onto some of the wires, Dialogue: 0,0:28:34.97,0:28:36.24,EN,,0,0,0,,onto sum and onto carry. Dialogue: 0,0:28:37.23,0:28:40.56,EN,,0,0,0,,A probe is a, can object that has the property Dialogue: 0,0:28:40.70,0:28:43.60,EN,,0,0,0,,that when you change a wire it's attached to, Dialogue: 0,0:28:43.72,0:28:44.83,EN,,0,0,0,,it types out a message. Dialogue: 0,0:28:46.12,0:28:46.92,EN,,0,0,0,,It's an easy thing to do. Dialogue: 0,0:28:48.44,0:28:49.52,EN,,0,0,0,,And then once we have that, Dialogue: 0,0:28:49.55,0:28:51.45,EN,,0,0,0,,of course, then when you put the probe on, Dialogue: 0,0:28:51.45,0:28:52.41,EN,,0,0,0,,the first thing it does, it says, Dialogue: 0,0:28:52.67,0:28:56.01,EN,,0,0,0,,the current value of the sum at time 0 is 0 Dialogue: 0,0:28:57.29,0:28:58.43,EN,,0,0,0,,And because I just noticed it. Dialogue: 0,0:28:59.40,0:29:04.75,EN,,0,0,0,,And the value of the carry at time 0, this is the time, is 0. Dialogue: 0,0:29:06.04,0:29:09.28,EN,,0,0,0,,And then we go off and we build some structure. Dialogue: 0,0:29:09.62,0:29:12.28,EN,,0,0,0,,Like, we can build a structure here that says Dialogue: 0,0:29:14.06,0:29:18.20,EN,,0,0,0,,you have a half-adder on input-1, input-2, sum, and carry. Dialogue: 0,0:29:18.42,0:29:20.42,EN,,0,0,0,,And we're going to set the signal on input-1 to 1. Dialogue: 0,0:29:20.62,0:29:21.72,EN,,0,0,0,,We do some propagation. Dialogue: 0,0:29:21.88,0:29:22.84,EN,,0,0,0,,At time 8, Dialogue: 0,0:29:23.90,0:29:26.12,EN,,0,0,0,,which you could see going through this thing if you wanted to, Dialogue: 0,0:29:26.52,0:29:29.20,EN,,0,0,0,,the new value of sum became 1. Dialogue: 0,0:29:29.52,0:29:30.44,EN,,0,0,0,,And the thing says I'm done. Dialogue: 0,0:29:31.16,0:29:32.25,EN,,0,0,0,,That wasn't very interesting. Dialogue: 0,0:29:32.63,0:29:33.90,EN,,0,0,0,,But we can send it some more signals. Dialogue: 0,0:29:34.06,0:29:36.73,EN,,0,0,0,,Like, we set-signal on input-2 to be one. Dialogue: 0,0:29:36.89,0:29:38.09,EN,,0,0,0,,And at that time if we propagate, Dialogue: 0,0:29:38.36,0:29:39.95,EN,,0,0,0,,then it carried at 11, Dialogue: 0,0:29:40.12,0:29:41.42,EN,,0,0,0,,the carry becomes 1, Dialogue: 0,0:29:41.55,0:29:44.19,EN,,0,0,0,,and at 16, the sum's new value becomes 0. Dialogue: 0,0:29:45.39,0:29:48.99,EN,,0,0,0,,And you might want to work out that, if you like, about the digital circuitry. Dialogue: 0,0:29:48.99,0:29:50.12,EN,,0,0,0,,It's true, and it works. Dialogue: 0,0:29:50.62,0:29:51.53,EN,,0,0,0,,And it's not very interesting. Dialogue: 0,0:29:51.53,0:29:54.12,EN,,0,0,0,,But that's the kind of behavior we get out of this thing. Dialogue: 0,0:30:01.83,0:30:03.29,EN,,0,0,0,,So what I've shown you right now Dialogue: 0,0:30:03.48,0:30:05.52,EN,,0,0,0,,is a large-scale picture, Dialogue: 0,0:30:06.60,0:30:08.56,EN,,0,0,0,,how you, at a bigger, big scale, Dialogue: 0,0:30:08.72,0:30:12.04,EN,,0,0,0,,you implement an event-driven simulation of some sort. Dialogue: 0,0:30:13.29,0:30:14.56,EN,,0,0,0,,And how you might organize it Dialogue: 0,0:30:14.88,0:30:16.70,EN,,0,0,0,,to have nice hierarchical structure Dialogue: 0,0:30:16.99,0:30:21.00,EN,,0,0,0,,allowing you to build abstract boxes that you can instantiate. Dialogue: 0,0:30:21.56,0:30:24.96,EN,,0,0,0,,But I haven't told you any of the details about how this agenda and things like that work. Dialogue: 0,0:30:25.78,0:30:26.54,EN,,0,0,0,,That we'll do next. Dialogue: 0,0:30:28.63,0:30:32.94,EN,,0,0,0,,And that's going to involve change and mutation of data and things like that. Dialogue: 0,0:30:34.31,0:30:35.86,EN,,0,0,0,,Are there any questions now, before I go on? Dialogue: 0,0:30:47.16,0:30:48.24,EN,,0,0,0,,Thank you. Let's take a break. Dialogue: 0,0:30:50.24,0:31:00.62,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:31:28.94,0:31:35.06,EN,,0,0,0,,Well, we've been making a simulation. Dialogue: 0,0:31:35.39,0:31:37.77,EN,,0,0,0,,And the simulation is an event-driven simulation Dialogue: 0,0:31:38.17,0:31:42.75,EN,,0,0,0,,where the objects in the world are the objects in the computer. Dialogue: 0,0:31:43.92,0:31:47.28,EN,,0,0,0,,And the changes of state that are happening in the world in time Dialogue: 0,0:31:47.98,0:31:50.83,EN,,0,0,0,,are organized to be time in the computer, Dialogue: 0,0:31:52.99,0:31:56.04,EN,,0,0,0,,so that if something happens after something else in the world, Dialogue: 0,0:31:56.46,0:31:57.96,EN,,0,0,0,,then we have it happen after, Dialogue: 0,0:31:58.89,0:32:02.25,EN,,0,0,0,,after the corresponding events happen in the same order in the computer. Dialogue: 0,0:32:04.42,0:32:07.16,EN,,0,0,0,,That's where we have assignments, when we make that alignment. Dialogue: 0,0:32:08.22,0:32:11.21,EN,,0,0,0,,Right now I want to show you a way of organizing time, Dialogue: 0,0:32:11.80,0:32:14.86,EN,,0,0,0,,which is an agenda or priority queue, it's sometimes called. Dialogue: 0,0:32:16.04,0:32:18.57,EN,,0,0,0,,We'll do some--we'll do a little bit of just understanding Dialogue: 0,0:32:18.62,0:32:21.00,EN,,0,0,0,,what are the things we need to be able to do to make agendas. Dialogue: 0,0:32:28.33,0:32:31.28,EN,,0,0,0,,And so we're going to have--and so right now over here, I'm going to write down a bunch Dialogue: 0,0:32:31.39,0:32:33.88,EN,,0,0,0,,of primitive operations for manipulating agendas. Dialogue: 0,0:32:35.96,0:32:37.95,EN,,0,0,0,,I'm not going to show you the code for them Dialogue: 0,0:32:38.14,0:32:39.58,EN,,0,0,0,,because they're all very simple, Dialogue: 0,0:32:40.32,0:32:42.60,EN,,0,0,0,,Iand you've got listings of all that anyway. Dialogue: 0,0:32:43.68,0:32:44.38,EN,,0,0,0,,So what do we have? Dialogue: 0,0:32:44.38,0:32:53.50,EN,,0,0,0,,We have things like make-agenda which produces a new agenda. Dialogue: 0,0:32:57.36,0:33:01.77,EN,,0,0,0,,We can ask--we get the current-time of an agenda, Dialogue: 0,0:33:07.47,0:33:12.80,EN,,0,0,0,,of an agenda, which gives me a number, a time. Dialogue: 0,0:33:16.99,0:33:21.37,EN,,0,0,0,,We can get--we can ask whether an agenda is empty, empty-agenda. Dialogue: 0,0:33:30.20,0:33:32.57,EN,,0,0,0,,And that produces either a true or a false. Dialogue: 0,0:33:42.72,0:33:44.72,EN,,0,0,0,,We can add an object to an agenda. Dialogue: 0,0:33:52.71,0:33:56.06,EN,,0,0,0,,Actually, what we add to an agenda is an operation--an action to be done. Dialogue: 0,0:33:56.91,0:33:58.14,EN,,0,0,0,,And that takes a time, Dialogue: 0,0:33:59.63,0:34:00.56,EN,,0,0,0,,the action itself, Dialogue: 0,0:34:02.86,0:34:04.64,EN,,0,0,0,,and the agenda I want to add it to. Dialogue: 0,0:34:07.58,0:34:10.25,EN,,0,0,0,,OK? That inserts it in the appropriate place in the agenda. Dialogue: 0,0:34:10.71,0:34:12.73,EN,,0,0,0,,I can get the first item off an agenda, Dialogue: 0,0:34:14.24,0:34:15.39,EN,,0,0,0,,the first thing I have to do, Dialogue: 0,0:34:21.84,0:34:23.84,EN,,0,0,0,,which is going to give me an action. Dialogue: 0,0:34:26.46,0:34:28.73,EN,,0,0,0,,And I can remove the first item from an agenda. Dialogue: 0,0:34:29.54,0:34:31.16,EN,,0,0,0,,That's what I have to be able to do with agendas. Dialogue: 0,0:34:31.40,0:34:33.02,EN,,0,0,0,,That is a big complicated mess. Dialogue: 0,0:34:42.53,0:34:43.36,EN,,0,0,0,,From an agenda. Dialogue: 0,0:34:45.98,0:34:49.85,EN,,0,0,0,,Well, let's see how we can organize this thing as a data structure a bit. Dialogue: 0,0:34:52.96,0:34:56.04,EN,,0,0,0,,Well, an agenda is going to be some kind of list. Dialogue: 0,0:34:58.43,0:35:01.20,EN,,0,0,0,,And it's going to be a list that I'm going to have to be able to modify. Dialogue: 0,0:35:01.57,0:35:04.03,EN,,0,0,0,,So we have to talk about modifying of lists, Dialogue: 0,0:35:05.80,0:35:06.89,EN,,0,0,0,,because I'm going to add things to it, Dialogue: 0,0:35:07.77,0:35:10.27,EN,,0,0,0,,and delete things from it, and things like that. Dialogue: 0,0:35:11.07,0:35:12.51,EN,,0,0,0,,It's organized by time. Dialogue: 0,0:35:13.82,0:35:15.57,EN,,0,0,0,,It's probably good to keep it in sorted order. Dialogue: 0,0:35:18.33,0:35:20.88,EN,,0,0,0,,But sometimes there are lots of things that happen at the same time Dialogue: 0,0:35:22.04,0:35:23.42,EN,,0,0,0,,approximate same time. Dialogue: 0,0:35:23.80,0:35:24.72,EN,,0,0,0,,What I have to do is say, Dialogue: 0,0:35:24.91,0:35:27.52,EN,,0,0,0,,group things by the time at which they're supposed to happen. Dialogue: 0,0:35:29.04,0:35:31.61,EN,,0,0,0,,So I'm going to make an agenda as a list of segments. Dialogue: 0,0:35:32.78,0:35:35.69,EN,,0,0,0,,And so I'm going to draw you a data structure for an agenda, Dialogue: 0,0:35:36.68,0:35:37.93,EN,,0,0,0,,a perfectly reasonable one. Dialogue: 0,0:35:39.62,0:35:40.49,EN,,0,0,0,,Here's an agenda. Dialogue: 0,0:35:41.11,0:35:42.87,EN,,0,0,0,,It's a thing that begins with a name. Dialogue: 0,0:35:47.85,0:35:50.19,EN,,0,0,0,,I'm going to do it right now out of list structure. Dialogue: 0,0:35:52.60,0:35:53.39,EN,,0,0,0,,It's got a header. Dialogue: 0,0:35:54.14,0:35:55.44,EN,,0,0,0,,There's a reason for the header. Dialogue: 0,0:35:55.84,0:35:57.63,EN,,0,0,0,,We're going to see the reason soon. Dialogue: 0,0:36:00.68,0:36:03.40,EN,,0,0,0,,And it will have a segment. We will have-- Dialogue: 0,0:36:03.96,0:36:05.62,EN,,0,0,0,,It will have--it will be a list of segments. Dialogue: 0,0:36:08.31,0:36:10.54,EN,,0,0,0,,Supposing this agenda has two segments, Dialogue: 0,0:36:11.58,0:36:15.07,EN,,0,0,0,,OK, they're the car's-- successive car's of this list. Dialogue: 0,0:36:16.41,0:36:20.57,EN,,0,0,0,,Each segment is going to have a time-- Dialogue: 0,0:36:24.20,0:36:26.64,EN,,0,0,0,,say for example, 10-- Dialogue: 0,0:36:26.83,0:36:30.51,EN,,0,0,0,,that says that the things that happen in this segment are at time 10. Dialogue: 0,0:36:33.16,0:36:36.52,EN,,0,0,0,,And what I'm going to have in here is another data structure Dialogue: 0,0:36:36.56,0:36:38.01,EN,,0,0,0,,which I'm not going to describe, Dialogue: 0,0:36:38.49,0:36:41.08,EN,,0,0,0,,which is a queue of things to do at time 10. Dialogue: 0,0:36:42.24,0:36:43.33,EN,,0,0,0,,It's a queue. Dialogue: 0,0:36:43.33,0:36:44.70,EN,,0,0,0,,And we'll talk about that in a second. Dialogue: 0,0:36:45.20,0:36:50.35,EN,,0,0,0,,But abstractly, the queue is just a list of things to do at a particular time. Dialogue: 0,0:36:50.40,0:36:52.04,EN,,0,0,0,,And I can add things to a queue. Dialogue: 0,0:36:53.10,0:36:53.80,EN,,0,0,0,,This is a queue. Dialogue: 0,0:36:56.14,0:36:59.11,EN,,0,0,0,,There's a time, there's a segment. Dialogue: 0,0:37:03.23,0:37:06.36,EN,,0,0,0,,Now, I may have another segment in this agenda. Dialogue: 0,0:37:08.94,0:37:11.20,EN,,0,0,0,,Supposing this is stuff that happens at time 30. Dialogue: 0,0:37:13.50,0:37:15.92,EN,,0,0,0,,It has, of course, another queue Dialogue: 0,0:37:16.92,0:37:20.24,EN,,0,0,0,,of things that are queued up to be done at time 30. Dialogue: 0,0:37:23.21,0:37:25.66,EN,,0,0,0,,Well, there are various things I have to be able to do to an agenda. Dialogue: 0,0:37:27.09,0:37:29.20,EN,,0,0,0,,Supposing I want to add to an agenda Dialogue: 0,0:37:29.47,0:37:31.61,EN,,0,0,0,,another thing to be done at time 10. Dialogue: 0,0:37:33.03,0:37:34.16,EN,,0,0,0,,Well, that's not very hard. Dialogue: 0,0:37:34.70,0:37:38.65,EN,,0,0,0,,I'm going to walk down here, looking for the segment of time 10. Dialogue: 0,0:37:39.73,0:37:42.14,EN,,0,0,0,,It is possible that there is no segment of time 10. Dialogue: 0,0:37:42.93,0:37:44.56,EN,,0,0,0,,We'll cover that case in a second. Dialogue: 0,0:37:45.42,0:37:47.56,EN,,0,0,0,,But if I find a segment of time 10, Dialogue: 0,0:37:47.87,0:37:50.43,EN,,0,0,0,,then if I want to add another thing to be done at time 10, Dialogue: 0,0:37:50.56,0:37:52.16,EN,,0,0,0,,I just increase that queue-- Dialogue: 0,0:37:53.85,0:37:56.22,EN,,0,0,0,,"just increase" isn't such an obvious idea. Dialogue: 0,0:37:56.57,0:37:59.26,EN,,0,0,0,,But I increase the things to be done at that time. Dialogue: 0,0:38:01.43,0:38:04.25,EN,,0,0,0,,Now, supposing I want to add something to be done at time 20. Dialogue: 0,0:38:05.31,0:38:07.90,EN,,0,0,0,,There is no segment for time 20. Dialogue: 0,0:38:08.99,0:38:10.64,EN,,0,0,0,,I'm going to have to create a new segment. Dialogue: 0,0:38:11.34,0:38:15.64,EN,,0,0,0,,I want my time 20 segment to exist between time 10 and time 30. Dialogue: 0,0:38:17.61,0:38:19.32,EN,,0,0,0,,Well, that takes a little work. Dialogue: 0,0:38:20.17,0:38:21.52,EN,,0,0,0,,I'm going to have to do a CONS. Dialogue: 0,0:38:24.26,0:38:29.94,EN,,0,0,0,,I'm going to have to make a new element of the agenda list--list of segments. Dialogue: 0,0:38:33.60,0:38:34.81,EN,,0,0,0,,I'm going to have to change. Dialogue: 0,0:38:35.40,0:38:36.30,EN,,0,0,0,,Here's change. Dialogue: 0,0:38:37.54,0:38:42.80,EN,,0,0,0,,I'm going to have to change the CDR of the CDR of the agenda Dialogue: 0,0:38:44.88,0:38:49.45,EN,,0,0,0,,point that a new CONS of the new segment Dialogue: 0,0:38:50.11,0:38:54.65,EN,,0,0,0,,and the CDR of the CDR of the CDR of the agenda, the CD-D-D-DR. Dialogue: 0,0:38:57.18,0:39:01.88,EN,,0,0,0,,And this is going to have a new segment now of time 20 Dialogue: 0,0:39:02.30,0:39:03.72,EN,,0,0,0,,with its own queue, Dialogue: 0,0:39:04.84,0:39:06.29,EN,,0,0,0,,which now has one element in it. Dialogue: 0,0:39:10.73,0:39:12.52,EN,,0,0,0,,If I wanted to add something at the end, Dialogue: 0,0:39:12.54,0:39:15.87,EN,,0,0,0,,I'm going to have to replace the CDR of this, Dialogue: 0,0:39:16.99,0:39:19.21,EN,,0,0,0,,of this list with something. Dialogue: 0,0:39:20.59,0:39:23.31,EN,,0,0,0,,We're have to change that piece of data structure. Dialogue: 0,0:39:24.04,0:39:25.79,EN,,0,0,0,,So I'm going to need new primitives for doing this. Dialogue: 0,0:39:27.21,0:39:28.62,EN,,0,0,0,,But I'm just showing you why I need them. Dialogue: 0,0:39:29.44,0:39:33.88,EN,,0,0,0,,And finally, if I wanted to add a thing to be done at time 5, Dialogue: 0,0:39:37.12,0:39:39.20,EN,,0,0,0,,I'm going to have to change this one, Dialogue: 0,0:39:40.81,0:39:42.12,EN,,0,0,0,,because I'm going to have to add it in over here, Dialogue: 0,0:39:43.29,0:39:46.22,EN,,0,0,0,,which is why I planned ahead and had a header cell, Dialogue: 0,0:39:47.56,0:39:48.59,EN,,0,0,0,,which has a place. Dialogue: 0,0:39:49.40,0:39:52.11,EN,,0,0,0,,If I'm going to change things, I have to have places for the change. Dialogue: 0,0:39:53.88,0:39:56.56,EN,,0,0,0,,I have to have a place to make the change. Dialogue: 0,0:39:58.60,0:40:02.54,EN,,0,0,0,,If I remove things from the agenda, that's not so hard. Dialogue: 0,0:40:02.54,0:40:04.62,EN,,0,0,0,,Removing them from the beginning is pretty easy, Dialogue: 0,0:40:04.92,0:40:06.14,EN,,0,0,0,,which is the only case I have. Dialogue: 0,0:40:06.49,0:40:10.19,EN,,0,0,0,,I can go looking for the first, the first segment. Dialogue: 0,0:40:11.22,0:40:14.00,EN,,0,0,0,,I see if it has a non-empty queue. Dialogue: 0,0:40:14.81,0:40:16.17,EN,,0,0,0,,If it has a non-empty queue, Dialogue: 0,0:40:16.32,0:40:18.62,EN,,0,0,0,,well, I'm going to delete one element from the queue Dialogue: 0,0:40:19.21,0:40:19.74,EN,,0,0,0,,like that. Dialogue: 0,0:40:20.10,0:40:21.92,EN,,0,0,0,,If the queue ever becomes empty, Dialogue: 0,0:40:22.64,0:40:24.22,EN,,0,0,0,,then I have to delete the whole segment. Dialogue: 0,0:40:24.22,0:40:26.49,EN,,0,0,0,,And then this, this changes to point to here. Dialogue: 0,0:40:28.22,0:40:31.08,EN,,0,0,0,,So it's quite a complicated data structure manipulation going on, Dialogue: 0,0:40:32.25,0:40:35.37,EN,,0,0,0,,the details of which are not really very exciting. Dialogue: 0,0:40:36.44,0:40:38.48,EN,,0,0,0,,Now, let's talk about queues. Dialogue: 0,0:40:38.92,0:40:39.76,EN,,0,0,0,,They're similar. Dialogue: 0,0:40:41.16,0:40:43.52,EN,,0,0,0,,Because each of these agendas has a queue in it. Dialogue: 0,0:40:44.34,0:40:45.02,EN,,0,0,0,,What's a queue? Dialogue: 0,0:40:49.47,0:40:51.85,EN,,0,0,0,,A queue is going to have the following primitive operations. Dialogue: 0,0:40:52.78,0:41:02.17,EN,,0,0,0,,To make a queue, this gives me a new queue. Dialogue: 0,0:41:07.77,0:41:17.10,EN,,0,0,0,,I'm going to have to be able to insert into a queue a new item. Dialogue: 0,0:41:24.51,0:41:28.65,EN,,0,0,0,,I'm going to have to be able to delete from a queue the first item in the queue. Dialogue: 0,0:41:40.44,0:41:52.04,EN,,0,0,0,,And I want to be able to get the first thing in the queue from some queue. Dialogue: 0,0:41:53.13,0:41:55.14,EN,,0,0,0,,I also have to be able to test whether a queue is empty. Dialogue: 0,0:42:07.11,0:42:08.70,EN,,0,0,0,,And when you invent things like this, Dialogue: 0,0:42:09.02,0:42:10.44,EN,,0,0,0,,I want you to be very careful Dialogue: 0,0:42:10.64,0:42:14.09,EN,,0,0,0,,to use the kinds of conventions I use for naming things. Dialogue: 0,0:42:15.12,0:42:19.15,EN,,0,0,0,,Notice that I'm careful to say these change something and that tests it. Dialogue: 0,0:42:19.87,0:42:21.85,EN,,0,0,0,,And presumably, I did the same thing over here. Dialogue: 0,0:42:24.65,0:42:26.96,EN,,0,0,0,,OK, and there should be an empty test over here. Dialogue: 0,0:42:29.24,0:42:30.72,EN,,0,0,0,,OK, well, how would I make a queue? Dialogue: 0,0:42:31.72,0:42:34.11,EN,,0,0,0,,A queue wants to be something I can add to at the end of, Dialogue: 0,0:42:35.12,0:42:36.83,EN,,0,0,0,,and pick up the thing at the beginning of. Dialogue: 0,0:42:37.84,0:42:40.51,EN,,0,0,0,,I should be able to delete from the beginning and add to the end. Dialogue: 0,0:42:41.23,0:42:43.24,EN,,0,0,0,,Well, I'm going to show you a very simple structure for that. Dialogue: 0,0:42:43.88,0:42:45.72,EN,,0,0,0,,We can make this out of CONSes as well. Dialogue: 0,0:42:47.08,0:42:47.79,EN,,0,0,0,,Here's a queue. Dialogue: 0,0:42:49.91,0:42:52.36,EN,,0,0,0,,It has--it has a queue header, Dialogue: 0,0:42:53.58,0:42:54.92,EN,,0,0,0,,which contains two parts-- Dialogue: 0,0:42:55.28,0:42:56.25,EN,,0,0,0,,a front pointer Dialogue: 0,0:42:58.78,0:42:59.82,EN,,0,0,0,,and a rear pointer. Dialogue: 0,0:43:03.12,0:43:06.33,EN,,0,0,0,,And here I have a queue with two items in it. Dialogue: 0,0:43:09.13,0:43:12.09,EN,,0,0,0,,The first item, I don't know, it's perhaps a 1. Dialogue: 0,0:43:12.46,0:43:16.53,EN,,0,0,0,,And the second item, I don't know, let's give it a 2. Dialogue: 0,0:43:21.40,0:43:23.52,EN,,0,0,0,,The reason why I want two pointers in here, Dialogue: 0,0:43:24.09,0:43:25.61,EN,,0,0,0,,a front pointer and a rear pointer, Dialogue: 0,0:43:25.72,0:43:27.10,EN,,0,0,0,,is so I can add to the end Dialogue: 0,0:43:27.48,0:43:29.45,EN,,0,0,0,,without having to chase down from the beginning. Dialogue: 0,0:43:31.85,0:43:34.80,EN,,0,0,0,,So for example, if I wanted to add one more item to this queue, Dialogue: 0,0:43:35.26,0:43:41.02,EN,,0,0,0,,if I want to add on another item to be worried about later, Dialogue: 0,0:43:41.08,0:43:42.40,EN,,0,0,0,,all I have to do is make a CONS, Dialogue: 0,0:43:43.47,0:43:46.59,EN,,0,0,0,,which contains that item, say a 3. Dialogue: 0,0:43:47.53,0:43:51.34,EN,,0,0,0,,That's for inserting 3 into the queue. Dialogue: 0,0:43:51.52,0:43:53.77,EN,,0,0,0,,Then I have to change this pointer here Dialogue: 0,0:43:56.94,0:43:58.76,EN,,0,0,0,,Okay? to here. Dialogue: 0,0:44:00.10,0:44:04.32,EN,,0,0,0,,And I have to change this one to point to the new rear. Dialogue: 0,0:44:09.12,0:44:12.68,EN,,0,0,0,,If I wish to take the first element of the queue, the first item, Dialogue: 0,0:44:12.96,0:44:17.12,EN,,0,0,0,,I just go chasing down the front pointer until I find the first one and pick it up. Dialogue: 0,0:44:18.89,0:44:23.26,EN,,0,0,0,,If I wish to delete the first item from the queue, delete-queue, Dialogue: 0,0:44:24.14,0:44:26.35,EN,,0,0,0,,all I do is move the front pointer along this way. Dialogue: 0,0:44:27.71,0:44:29.31,EN,,0,0,0,,The new front of the queue is now this. Dialogue: 0,0:44:31.70,0:44:33.13,EN,,0,0,0,,So queues are very simple too. Dialogue: 0,0:44:34.48,0:44:35.76,EN,,0,0,0,,So what you see now Dialogue: 0,0:44:37.24,0:44:40.83,EN,,0,0,0,,is that I need a certain number of new primitive operations. Dialogue: 0,0:44:41.48,0:44:42.56,EN,,0,0,0,,And I'm going to give them some names. Dialogue: 0,0:44:42.99,0:44:46.28,EN,,0,0,0,,And then we're going to look into how they work, and how they're used. Dialogue: 0,0:44:47.35,0:44:55.04,EN,,0,0,0,,We have set the CAR of some pair, Dialogue: 0,0:44:55.88,0:44:59.36,EN,,0,0,0,,or a thing produced by CONSing, to a new value. Dialogue: 0,0:45:02.37,0:45:09.92,EN,,0,0,0,,And set the CDR of a pair to a new value. Dialogue: 0,0:45:13.02,0:45:14.78,EN,,0,0,0,,And then we're going to look into how they work. Dialogue: 0,0:45:16.03,0:45:20.51,EN,,0,0,0,,I needed setting CAR over here to delete the first element of the queue. Dialogue: 0,0:45:20.96,0:45:22.52,EN,,0,0,0,,This is the CAR, and I had to set it. Dialogue: 0,0:45:23.47,0:45:24.96,EN,,0,0,0,,I had to be able to set the CDR Dialogue: 0,0:45:25.28,0:45:27.08,EN,,0,0,0,,to be able to move the rear pointer, Dialogue: 0,0:45:27.21,0:45:28.76,EN,,0,0,0,,or to be able to increment the queue here. Dialogue: 0,0:45:30.16,0:45:31.60,EN,,0,0,0,,All of the operations I did Dialogue: 0,0:45:31.90,0:45:35.90,EN,,0,0,0,,were made out of those that I just showed you on the, on the last blackboard. Dialogue: 0,0:45:38.17,0:45:40.14,EN,,0,0,0,,Good. Let's pause the time, and take a little break then. Dialogue: 0,0:45:41.24,0:45:52.67,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:46:38.81,0:46:43.53,EN,,0,0,0,,When we originally introduced pairs made out of CONS, made by CONS, Dialogue: 0,0:46:44.57,0:46:46.80,EN,,0,0,0,,we only said a few axioms about them, Dialogue: 0,0:46:48.09,0:46:50.76,EN,,0,0,0,,which were of the form-- what were they-- Dialogue: 0,0:46:52.28,0:47:03.64,EN,,0,0,0,,for all X and Y, the CAR of the CONS of X and Y is X Dialogue: 0,0:47:05.31,0:47:12.92,EN,,0,0,0,,and Y is X and the CDR of the CONS of X and Y is Y. Dialogue: 0,0:47:14.80,0:47:20.00,EN,,0,0,0,,Now, these say nothing about whether a CONS has an identity like a person. Dialogue: 0,0:47:21.85,0:47:25.58,EN,,0,0,0,,In fact, all they say is something sort of abstract, Dialogue: 0,0:47:25.74,0:47:27.95,EN,,0,0,0,,that a CONS is the parts it's made out of. Dialogue: 0,0:47:29.74,0:47:33.18,EN,,0,0,0,,And of course, two things are made out of the same parts, they're the same, Dialogue: 0,0:47:33.93,0:47:35.71,EN,,0,0,0,,at least from the point of view of these axioms. Dialogue: 0,0:47:37.32,0:47:39.21,EN,,0,0,0,,But by introducing assignment-- Dialogue: 0,0:47:39.84,0:47:42.32,EN,,0,0,0,,in fact, mutable data is a kind of assignment, Dialogue: 0,0:47:42.88,0:47:44.43,EN,,0,0,0,,we have a set CAR and a set CDR-- Dialogue: 0,0:47:45.55,0:47:48.94,EN,,0,0,0,,by introducing those, these axioms no longer tell the whole story. Dialogue: 0,0:47:49.83,0:47:52.03,EN,,0,0,0,,And they're still true if written exactly like this. Dialogue: 0,0:47:53.25,0:47:54.94,EN,,0,0,0,,But they don't tell the whole story. Dialogue: 0,0:47:56.07,0:48:01.68,EN,,0,0,0,,Because if I'm going to set a particular CAR in a particular CONS, Dialogue: 0,0:48:03.02,0:48:04.03,EN,,0,0,0,,the questions are, Dialogue: 0,0:48:04.24,0:48:08.64,EN,,0,0,0,,well, is that setting all CARs and all CONSes of the same two things or not? Dialogue: 0,0:48:10.09,0:48:13.04,EN,,0,0,0,,If I--if we use CONSes to make up things like rational numbers, Dialogue: 0,0:48:14.86,0:48:17.10,EN,,0,0,0,,or things like 3 over 4, Dialogue: 0,0:48:17.34,0:48:20.25,EN,,0,0,0,,supposing I had two three-fourths. Dialogue: 0,0:48:21.57,0:48:22.75,EN,,0,0,0,,Are they the same one-- Dialogue: 0,0:48:24.06,0:48:24.89,EN,,0,0,0,,or are they different? Dialogue: 0,0:48:25.34,0:48:26.96,EN,,0,0,0,,Well, in the case of numbers, it doesn't matter. Dialogue: 0,0:48:27.86,0:48:30.49,EN,,0,0,0,,Because there's no meaning to changing the denominator of a number. Dialogue: 0,0:48:33.02,0:48:35.32,EN,,0,0,0,,What you could do is make a number which has a different denominator. Dialogue: 0,0:48:36.84,0:48:39.88,EN,,0,0,0,,But the concept of changing a number which has to have a different denominator Dialogue: 0,0:48:40.00,0:48:43.58,EN,,0,0,0,,is sort of a very weird, and sort of not supported by what you think of as mathematics. Dialogue: 0,0:48:44.77,0:48:47.40,EN,,0,0,0,,However, when these CONSes represent things in the physical world, Dialogue: 0,0:48:48.97,0:48:50.43,EN,,0,0,0,,then changing something like the CAR Dialogue: 0,0:48:50.60,0:48:52.20,EN,,0,0,0,,like removing a piece of the fingernail. Dialogue: 0,0:48:53.69,0:48:56.56,EN,,0,0,0,,And so CONSes have an identity. Dialogue: 0,0:48:57.77,0:48:59.92,EN,,0,0,0,,Let me show you what I mean about identity, first of all. Dialogue: 0,0:49:01.28,0:49:03.05,EN,,0,0,0,,Let's do some little example here. Dialogue: 0,0:49:04.32,0:49:15.20,EN,,0,0,0,,Supposing I define A to the CONS of 1 and 2. Dialogue: 0,0:49:18.32,0:49:19.76,EN,,0,0,0,,Well, what that means, first of all, Dialogue: 0,0:49:20.67,0:49:25.20,EN,,0,0,0,,is that somewhere in some environment I've made a symbol A Dialogue: 0,0:49:25.96,0:49:28.67,EN,,0,0,0,,to have a value which is a pair Dialogue: 0,0:49:29.47,0:49:34.06,EN,,0,0,0,,consisting of pointers to a 1 and a pointer to a 2, Dialogue: 0,0:49:35.34,0:49:36.16,EN,,0,0,0,,just like that. Dialogue: 0,0:49:38.12,0:49:39.60,EN,,0,0,0,,Now, supposing I also say Dialogue: 0,0:49:40.22,0:49:47.58,EN,,0,0,0,,define B to be the CONS-- Dialogue: 0,0:49:53.88,0:49:56.81,EN,,0,0,0,,it doesn't matter, but I like it better, it's prettier-- Dialogue: 0,0:49:57.63,0:49:59.88,EN,,0,0,0,,of A and A. Dialogue: 0,0:50:03.97,0:50:06.03,EN,,0,0,0,,Well, first of all, I'm using the name A twice. Dialogue: 0,0:50:07.84,0:50:10.57,EN,,0,0,0,,At this moment, I'm going to think of CONSes as having identity. Dialogue: 0,0:50:11.30,0:50:12.64,EN,,0,0,0,,This is the same one. Dialogue: 0,0:50:13.69,0:50:14.81,EN,,0,0,0,,And so what that means Dialogue: 0,0:50:15.29,0:50:17.61,EN,,0,0,0,,is I make another pair, Dialogue: 0,0:50:18.81,0:50:20.20,EN,,0,0,0,,which I'm going to call B. Dialogue: 0,0:50:22.38,0:50:27.60,EN,,0,0,0,,And it contains two pointers to A. Dialogue: 0,0:50:28.92,0:50:32.20,EN,,0,0,0,,At this point, I have three names for this object. Dialogue: 0,0:50:33.10,0:50:34.16,EN,,0,0,0,,A is its name. Dialogue: 0,0:50:34.88,0:50:36.46,EN,,0,0,0,,The CAR of B is its name. Dialogue: 0,0:50:37.23,0:50:38.86,EN,,0,0,0,,And the CDR of B is its name. Dialogue: 0,0:50:39.36,0:50:41.15,EN,,0,0,0,,It has several aliases, they're called. Dialogue: 0,0:50:44.23,0:50:49.28,EN,,0,0,0,,Now, supposing I do something like set-the-CAR, Dialogue: 0,0:50:53.77,0:51:08.38,EN,,0,0,0,,the CAR of the CAR of B to 3. Dialogue: 0,0:51:12.75,0:51:17.45,EN,,0,0,0,,What that means is I find the CAR of B, that's this. Dialogue: 0,0:51:17.83,0:51:20.93,EN,,0,0,0,,I set the CAR of that to be 3, changing this. Dialogue: 0,0:51:24.76,0:51:25.69,EN,,0,0,0,,I've changed A. Dialogue: 0,0:51:27.24,0:51:33.64,EN,,0,0,0,,If I were to ask what's the CAR of A--of A now? Dialogue: 0,0:51:35.34,0:51:37.56,EN,,0,0,0,,I would get out 3, Dialogue: 0,0:51:38.68,0:51:43.39,EN,,0,0,0,,even though here we see that A was the CONS of 1 and 2. Dialogue: 0,0:51:45.29,0:51:47.44,EN,,0,0,0,,I caused A to change by changing B. Dialogue: 0,0:51:48.56,0:51:49.64,EN,,0,0,0,,There is sharing here. Dialogue: 0,0:51:52.25,0:51:53.47,EN,,0,0,0,,That's sometimes what we want. Dialogue: 0,0:51:54.24,0:51:56.12,EN,,0,0,0,,Surely in the queues and things like that, Dialogue: 0,0:51:56.24,0:52:02.38,EN,,0,0,0,,that's exactly what we defined our--organized our data structures to facilitate-- sharing. Dialogue: 0,0:52:04.35,0:52:05.66,EN,,0,0,0,,But inadvertent sharing, Dialogue: 0,0:52:07.76,0:52:09.72,EN,,0,0,0,,unanticipated interactions between objects, Dialogue: 0,0:52:10.78,0:52:14.08,EN,,0,0,0,,is the source of most of the bugs that occur in complicated programs. Dialogue: 0,0:52:15.44,0:52:21.66,EN,,0,0,0,,So by introducing this possibility of things having identity and sharing Dialogue: 0,0:52:21.87,0:52:23.76,EN,,0,0,0,,and having multiple names for the same thing, Dialogue: 0,0:52:24.08,0:52:25.05,EN,,0,0,0,,we get a lot of power. Dialogue: 0,0:52:25.13,0:52:28.46,EN,,0,0,0,,But we're going to pay for it with lots of complexity and bugs. Dialogue: 0,0:52:32.19,0:52:36.24,EN,,0,0,0,,So also, for example, if I just looked at this just to drive that home, Dialogue: 0,0:52:37.10,0:52:39.87,EN,,0,0,0,,the CADR of B, Dialogue: 0,0:52:42.46,0:52:46.56,EN,,0,0,0,,which has nothing to do with even the CAR of B, apparently. Dialogue: 0,0:52:46.88,0:52:49.02,EN,,0,0,0,,The CADR of B, what's that? Dialogue: 0,0:52:49.35,0:52:53.56,EN,,0,0,0,,Take that CDR of B and now take the CAR of that. Dialogue: 0,0:52:53.56,0:52:54.86,EN,,0,0,0,,Oh, that's 3 also. Dialogue: 0,0:52:56.48,0:53:00.43,EN,,0,0,0,,So I can have non-local interactions by sharing. Dialogue: 0,0:53:01.12,0:53:02.48,EN,,0,0,0,,And I have to be very careful of that. Dialogue: 0,0:53:06.64,0:53:12.64,EN,,0,0,0,,Well, so far, of course, it seems I've introduced several different assignment operators-- Dialogue: 0,0:53:13.18,0:53:17.61,EN,,0,0,0,,set, set CAR, set CDR. Dialogue: 0,0:53:18.51,0:53:21.39,EN,,0,0,0,,Well, maybe I should just get rid of set CAR and set CDR. Maybe they're not worthwhile. Dialogue: 0,0:53:22.82,0:53:23.66,EN,,0,0,0,,Well, the answer is Dialogue: 0,0:53:24.12,0:53:26.11,EN,,0,0,0,,that once you let the camel's nose into the tent, Dialogue: 0,0:53:26.24,0:53:27.34,EN,,0,0,0,,the rest of him follows. Dialogue: 0,0:53:30.16,0:53:31.26,EN,,0,0,0,,All I have to have is set, Dialogue: 0,0:53:31.61,0:53:35.85,EN,,0,0,0,,and I can make all of the--all of the bad things that can happen. Dialogue: 0,0:53:38.55,0:53:39.80,EN,,0,0,0,,Let's play with that a little bit. Dialogue: 0,0:53:40.69,0:53:43.72,EN,,0,0,0,,A couple of days ago, when we introduced compound data, Dialogue: 0,0:53:45.13,0:53:51.20,EN,,0,0,0,,you saw Hal show you a definition of CONS in terms of a message acceptor. Dialogue: 0,0:53:52.48,0:53:56.06,EN,,0,0,0,,I'm going to show you even a more horrible thing, Dialogue: 0,0:53:57.13,0:54:00.04,EN,,0,0,0,,a definition of CONS in terms of nothing but air, Dialogue: 0,0:54:02.56,0:54:03.02,EN,,0,0,0,,hot air. Dialogue: 0,0:54:04.44,0:54:08.12,EN,,0,0,0,,What is the definition of CONS, of the old functional kind, Dialogue: 0,0:54:09.26,0:54:11.66,EN,,0,0,0,,in terms of purely lambdic expressions, Dialogue: 0,0:54:13.39,0:54:14.40,EN,,0,0,0,,procedures? Dialogue: 0,0:54:17.39,0:54:19.66,EN,,0,0,0,,Because I'm going to then modify this definition Dialogue: 0,0:54:20.30,0:54:23.16,EN,,0,0,0,,to get assignment to be only one kind of assignment, Dialogue: 0,0:54:24.28,0:54:27.93,EN,,0,0,0,,to get rid of the set CAR and set CDR in terms of set. Dialogue: 0,0:54:28.58,0:54:37.39,EN,,0,0,0,,So what if I define CONS of X and Y Dialogue: 0,0:54:38.91,0:54:42.56,EN,,0,0,0,,to be a procedure of one argument called a message M, Dialogue: 0,0:54:43.39,0:54:46.32,EN,,0,0,0,,which calls that message on X and Y? Dialogue: 0,0:54:51.12,0:54:53.10,EN,,0,0,0,,This idea was invented by Alonzo Church, Dialogue: 0,0:54:53.77,0:54:55.72,EN,,0,0,0,,who was the greatest programmer of the 20th century, Dialogue: 0,0:54:55.79,0:54:57.15,EN,,0,0,0,,although he never saw a computer. Dialogue: 0,0:54:57.87,0:54:59.13,EN,,0,0,0,,It was done in the 1930s. Dialogue: 0,0:54:59.42,0:55:02.22,EN,,0,0,0,,He was a logician, I suppose at Princeton at the time. Dialogue: 0,0:55:08.66,0:55:10.43,EN,,0,0,0,,Define CAR of X Dialogue: 0,0:55:13.10,0:55:16.92,EN,,0,0,0,,to be the result of applying X to that procedure of two arguments, Dialogue: 0,0:55:17.15,0:55:20.60,EN,,0,0,0,,A and D, which selects A. Dialogue: 0,0:55:23.71,0:55:24.97,EN,,0,0,0,,I will define CDR of X Dialogue: 0,0:55:33.10,0:55:34.78,EN,,0,0,0,,to be that procedure, Dialogue: 0,0:55:35.08,0:55:40.25,EN,,0,0,0,,to be the result of applying X to that procedure of A and D, Dialogue: 0,0:55:40.92,0:55:42.04,EN,,0,0,0,,which selects D. Dialogue: 0,0:55:46.67,0:55:49.88,EN,,0,0,0,,Now, you may not recognize this as CAR, CDR, and CONS. Dialogue: 0,0:55:50.51,0:55:53.61,EN,,0,0,0,,But I'm going to demonstrate to you that it satisfies the original axioms Dialogue: 0,0:55:54.11,0:55:54.81,EN,,0,0,0,,just once. Dialogue: 0,0:55:55.61,0:55:57.56,EN,,0,0,0,,And then we're going to do some playing of games. Dialogue: 0,0:55:58.29,0:56:06.27,EN,,0,0,0,,Consider the problem CAR of CONS of, say, 35 and 47. Dialogue: 0,0:56:09.93,0:56:10.96,EN,,0,0,0,,Well, what is that? Dialogue: 0,0:56:11.12,0:56:15.24,EN,,0,0,0,,It is the result of taking car of the result of substituting 35 and 47 Dialogue: 0,0:56:15.37,0:56:18.20,EN,,0,0,0,,X and Y in the body of this. Dialogue: 0,0:56:19.71,0:56:20.69,EN,,0,0,0,,Well, that's easy enough. Dialogue: 0,0:56:20.69,0:56:30.88,EN,,0,0,0,,That's CAR of the result of substituting into lambda of M, M of 35 and 47. Dialogue: 0,0:56:35.53,0:56:39.36,EN,,0,0,0,,Well, what this is, is the result of substituting this object Dialogue: 0,0:56:39.44,0:56:41.85,EN,,0,0,0,,for X in the body of that. Dialogue: 0,0:56:42.83,0:56:47.66,EN,,0,0,0,,So that's just lambda of M-- Dialogue: 0,0:56:48.33,0:56:52.19,EN,,0,0,0,,that's substituted, because this object is being substituted for X, Dialogue: 0,0:56:52.88,0:56:54.35,EN,,0,0,0,,which is the beginning of a list, Dialogue: 0,0:56:54.88,0:57:00.32,EN,,0,0,0,,lambda of M-- M of 35 and 47, Dialogue: 0,0:57:03.10,0:57:07.31,EN,,0,0,0,,applied to that procedure of A and D, Dialogue: 0,0:57:07.48,0:57:08.67,EN,,0,0,0,,which gives me A. Dialogue: 0,0:57:10.91,0:57:14.62,EN,,0,0,0,,Well, that's the result of substituting this for M here. Dialogue: 0,0:57:15.96,0:57:21.71,EN,,0,0,0,,So that's the same thing as lambda of A, D, A, Dialogue: 0,0:57:22.22,0:57:24.84,EN,,0,0,0,,applied to 35 and 47. Dialogue: 0,0:57:26.33,0:57:27.37,EN,,0,0,0,,Oh, well that's 35. Dialogue: 0,0:57:27.40,0:57:31.21,EN,,0,0,0,,That's substituting 35 for A and for 47 for D in A. Dialogue: 0,0:57:35.60,0:57:37.24,EN,,0,0,0,,So I don't need any data at all. Dialogue: 0,0:57:37.88,0:57:38.75,EN,,0,0,0,,not even numbers. Dialogue: 0,0:57:40.92,0:57:42.64,EN,,0,0,0,,This is Alonso Church's hack. Dialogue: 0,0:57:52.42,0:57:56.17,EN,,0,0,0,,Well, now we're going to do something nasty to him. Dialogue: 0,0:57:56.76,0:57:58.49,EN,,0,0,0,,Being a logician, he wouldn't like this. Dialogue: 0,0:57:59.20,0:58:01.96,EN,,0,0,0,,But as programmers, let's look at the overhead. Dialogue: 0,0:58:03.26,0:58:04.16,EN,,0,0,0,,And here we go. Dialogue: 0,0:58:05.39,0:58:07.58,EN,,0,0,0,,I'm going to change the definition of CONS. Dialogue: 0,0:58:09.57,0:58:12.35,EN,,0,0,0,,It's almost the same as Alonzo Church's, but not quite. Dialogue: 0,0:58:14.41,0:58:15.50,EN,,0,0,0,,What do we have here? Dialogue: 0,0:58:16.07,0:58:18.72,EN,,0,0,0,,The CONS of two arguments, X and Y, Dialogue: 0,0:58:19.50,0:58:22.51,EN,,0,0,0,,is going to be that procedure of one argument M, Dialogue: 0,0:58:23.39,0:58:25.64,EN,,0,0,0,,which supplies M to X and Y as before, Dialogue: 0,0:58:26.19,0:58:29.29,EN,,0,0,0,,but also to two permissions, Dialogue: 0,0:58:30.17,0:58:32.01,EN,,0,0,0,,the permission to set X to N Dialogue: 0,0:58:32.60,0:58:34.40,EN,,0,0,0,,and the permission to set Y to N, Dialogue: 0,0:58:34.44,0:58:35.68,EN,,0,0,0,,given that I have an N. Dialogue: 0,0:58:40.94,0:58:44.72,EN,,0,0,0,,So besides the things that I had here in Church's definition, Dialogue: 0,0:58:45.72,0:58:51.66,EN,,0,0,0,,what I have is that the thing that CONS returns Dialogue: 0,0:58:52.12,0:58:53.82,EN,,0,0,0,,will apply its argument Dialogue: 0,0:58:54.91,0:58:59.44,EN,,0,0,0,,to not just the values of the X and Y that the CONS is made of, Dialogue: 0,0:58:59.69,0:59:03.58,EN,,0,0,0,,but also permissions to set X and Y to new values. Dialogue: 0,0:59:06.54,0:59:08.08,EN,,0,0,0,,Now, of course, just as before, Dialogue: 0,0:59:08.83,0:59:10.51,EN,,0,0,0,,CAR is exactly the same. Dialogue: 0,0:59:11.69,0:59:14.36,EN,,0,0,0,,The CAR of X is nothing more than applying X, Dialogue: 0,0:59:14.54,0:59:16.00,EN,,0,0,0,,as in Church's definition, Dialogue: 0,0:59:16.86,0:59:19.00,EN,,0,0,0,,to a procedure, in this case, of four arguments, Dialogue: 0,0:59:19.29,0:59:21.04,EN,,0,0,0,,which selects out the first one. Dialogue: 0,0:59:22.54,0:59:24.16,EN,,0,0,0,,And just as we did before, Dialogue: 0,0:59:25.42,0:59:26.96,EN,,0,0,0,,that will be the value of X Dialogue: 0,0:59:29.04,0:59:35.40,EN,,0,0,0,,that was contained in the procedure which is the result of evaluating this lambda expression Dialogue: 0,0:59:35.45,0:59:37.84,EN,,0,0,0,,in the environment where X and Y are defined over here. Dialogue: 0,0:59:41.94,0:59:43.15,EN,,0,0,0,,That's the value of CONS. Dialogue: 0,0:59:45.64,0:59:47.53,EN,,0,0,0,,Now, however, the exciting part. Dialogue: 0,0:59:47.73,0:59:48.96,EN,,0,0,0,,CDR, of course, is the same. Dialogue: 0,0:59:49.39,0:59:50.35,EN,,0,0,0,,The exciting part, Dialogue: 0,0:59:51.23,0:59:52.52,EN,,0,0,0,,set CAR and set CDR. Dialogue: 0,0:59:53.45,0:59:55.52,EN,,0,0,0,,Well, they're nothing very complicated anymore. Dialogue: 0,0:59:55.80,1:00:00.64,EN,,0,0,0,,Set CAR of a CONS X to a new value Y Dialogue: 0,1:00:01.63,1:00:03.85,EN,,0,0,0,,is nothing more than applying that CONS, Dialogue: 0,1:00:04.11,1:00:06.76,EN,,0,0,0,,which is the procedure of four--the procedure of one argument Dialogue: 0,1:00:07.69,1:00:09.80,EN,,0,0,0,,which applies its argument to four things, Dialogue: 0,1:00:11.24,1:00:15.85,EN,,0,0,0,,to a procedure which is of four arguments-- Dialogue: 0,1:00:16.00,1:00:18.08,EN,,0,0,0,,the value of X, the value of Y, Dialogue: 0,1:00:18.32,1:00:20.54,EN,,0,0,0,,permission to set X, the permission to set Y-- Dialogue: 0,1:00:21.32,1:00:26.09,EN,,0,0,0,,and using it--using that permission to set X to the new value. Dialogue: 0,1:00:31.65,1:00:33.54,EN,,0,0,0,,And similarly, set-cdr is the same thing. Dialogue: 0,1:00:36.25,1:00:39.44,EN,,0,0,0,,So what you've just seen is that I didn't introduce any new primitives at all. Dialogue: 0,1:00:40.11,1:00:44.36,EN,,0,0,0,,I mean, Whether or not I want to implement it this way is a matter of engineering. Dialogue: 0,1:00:45.34,1:00:47.39,EN,,0,0,0,,And the answer is of course I don't implement it this way Dialogue: 0,1:00:48.09,1:00:49.63,EN,,0,0,0,,for reasons that have to do with engineering. Dialogue: 0,1:00:51.68,1:00:53.40,EN,,0,0,0,,However in principle, logically, Dialogue: 0,1:00:54.28,1:00:56.43,EN,,0,0,0,,I introduced one assignment operator, Dialogue: 0,1:00:56.96,1:00:58.76,EN,,0,0,0,,I've assigned--I've introduced them all. Dialogue: 0,1:01:05.42,1:01:06.67,EN,,0,0,0,,Are there any questions? Dialogue: 0,1:01:09.20,1:01:10.89,EN,,0,0,0,,Yes, David. Dialogue: 0,1:01:12.04,1:01:15.64,EN,,0,0,0,,AUDIENCE: I can follow you up until you get--I can follow all of that. Dialogue: 0,1:01:15.64,1:01:17.61,EN,,0,0,0,,But when we bring in the permissions, Dialogue: 0,1:01:18.14,1:01:21.64,EN,,0,0,0,,defining CONS in terms of the lambda N, Dialogue: 0,1:01:21.80,1:01:24.21,EN,,0,0,0,,I don't follow where N gets passed. Dialogue: 0,1:01:24.21,1:01:25.69,EN,,0,0,0,,PROFESSOR: Oh, I'm sorry. I'll show you. Dialogue: 0,1:01:26.34,1:01:27.05,EN,,0,0,0,,Let's follow it. Dialogue: 0,1:01:27.36,1:01:29.07,EN,,0,0,0,,Of course, we could do it on the blackboard. Dialogue: 0,1:01:29.18,1:01:30.17,EN,,0,0,0,,It's not so hard. Dialogue: 0,1:01:30.17,1:01:31.47,EN,,0,0,0,,But it's also easy here. Dialogue: 0,1:01:32.45,1:01:35.79,EN,,0,0,0,,Supposing I wish to set-cdr of X to Y. Dialogue: 0,1:01:37.79,1:01:39.66,EN,,0,0,0,,See that right there. set cdr x to y Dialogue: 0,1:01:40.36,1:01:41.92,EN,,0,0,0,,X is presumably a CONS, Dialogue: 0,1:01:43.31,1:01:45.24,EN,,0,0,0,,a thing resulting from evaluating CONS. Dialogue: 0,1:01:45.88,1:01:46.35,EN,,0,0,0,,right? Dialogue: 0,1:01:46.89,1:01:49.96,EN,,0,0,0,,Therefore X comes from a place over here, Dialogue: 0,1:01:52.57,1:01:56.49,EN,,0,0,0,,that that X is of the result of evaluating this lambda expression. Dialogue: 0,1:01:58.11,1:01:58.49,EN,,0,0,0,,Right? Dialogue: 0,1:01:59.38,1:02:01.63,EN,,0,0,0,,That when I evaluated that lambda expression, Dialogue: 0,1:02:04.01,1:02:08.76,EN,,0,0,0,,I evaluated it in an environment where the arguments to CONS were defined. Dialogue: 0,1:02:11.75,1:02:15.18,EN,,0,0,0,,That means that as free variables in this lambda expression, Dialogue: 0,1:02:16.25,1:02:18.68,EN,,0,0,0,,there is the--there are in the frame, Dialogue: 0,1:02:18.72,1:02:22.44,EN,,0,0,0,,which is the parent frame of this lambda expression, Dialogue: 0,1:02:23.23,1:02:25.82,EN,,0,0,0,,the procedure resulting from this lambda expression, Dialogue: 0,1:02:26.65,1:02:28.51,EN,,0,0,0,,X and Y have places. Dialogue: 0,1:02:29.25,1:02:30.83,EN,,0,0,0,,And it's possible to set them. Dialogue: 0,1:02:31.91,1:02:36.08,EN,,0,0,0,,I set them to an N, which is the argument of the permission. Dialogue: 0,1:02:37.26,1:02:39.31,EN,,0,0,0,,The permission is a procedure Dialogue: 0,1:02:41.40,1:02:43.18,EN,,0,0,0,,which is passed to M, Dialogue: 0,1:02:43.29,1:02:46.51,EN,,0,0,0,,which is the argument that the CONS object gets passed. Dialogue: 0,1:02:47.94,1:02:50.91,EN,,0,0,0,,Now, let's go back here in the set-cdr Dialogue: 0,1:02:52.11,1:02:55.42,EN,,0,0,0,,The CONS object, which is the first argument of set-cdr Dialogue: 0,1:02:56.12,1:02:57.48,EN,,0,0,0,,gets passed an argument. Dialogue: 0,1:02:59.77,1:03:02.22,EN,,0,0,0,,That--there's a procedure of four things, indeed, Dialogue: 0,1:03:02.32,1:03:04.65,EN,,0,0,0,,because that's the same thing as this M over here, Dialogue: 0,1:03:04.99,1:03:06.56,EN,,0,0,0,,which is applied to four objects. Dialogue: 0,1:03:07.92,1:03:13.34,EN,,0,0,0,,The object over here, SD, is, in fact, this permission. Dialogue: 0,1:03:15.47,1:03:19.93,EN,,0,0,0,,When I use SD, I apply it to Y, right there. Dialogue: 0,1:03:22.91,1:03:24.04,EN,,0,0,0,,So that comes from this. Dialogue: 0,1:03:25.37,1:03:26.92,EN,,0,0,0,,AUDIENCE: So what do you-- Dialogue: 0,1:03:27.00,1:03:32.19,EN,,0,0,0,,PROFESSOR: So to finish that, the N that was here is the Y which is here. Dialogue: 0,1:03:34.04,1:03:34.52,EN,,0,0,0,,How's that? Dialogue: 0,1:03:34.81,1:03:35.75,EN,,0,0,0,,AUDIENCE: Right, OK. Dialogue: 0,1:03:35.75,1:03:37.29,EN,,0,0,0,,Now, when you do a set-cdr, Dialogue: 0,1:03:39.07,1:03:41.97,EN,,0,0,0,,X is the value the CDR is going to become. Dialogue: 0,1:03:41.97,1:03:44.03,EN,,0,0,0,,PROFESSOR: The X over here. Dialogue: 0,1:03:44.96,1:03:46.20,EN,,0,0,0,,I'm sorry, that's not true. Dialogue: 0,1:03:46.20,1:03:48.33,EN,,0,0,0,,The X is--set-cdr has two arguments-- Dialogue: 0,1:03:48.91,1:03:50.36,EN,,0,0,0,,The CONS I'm changing Dialogue: 0,1:03:51.34,1:03:53.93,EN,,0,0,0,,and the value I'm changing it to. Dialogue: 0,1:03:56.15,1:03:58.32,EN,,0,0,0,,So you have them backwards, that's all. Dialogue: 0,1:04:02.17,1:04:03.16,EN,,0,0,0,,Are there any other questions? Dialogue: 0,1:04:07.88,1:04:08.64,EN,,0,0,0,,Well, thank you. Dialogue: 0,1:04:08.64,1:04:09.52,EN,,0,0,0,,It's time for lunch. Dialogue: 0,0:00:00.01,0:00:02.46,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N张大伟\N(DreamAndDead) Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:10.10,0:00:14.60,Declare,,0,0,0,,{\an2\fad(500,500)}计算对象 Dialogue: 0,0:00:21.17,0:00:24.12,Default,,0,0,0,,现在我们已经学习了 Dialogue: 0,0:00:24.43,0:00:27.40,Default,,0,0,0,,如何创建局部状态和如何建模对象 Dialogue: 0,0:00:28.33,0:00:32.67,Default,,0,0,0,,我想我们应该找点复杂的东西 Dialogue: 0,0:00:34.03,0:00:36.36,Default,,0,0,0,,来实践一下学过的这些知识 Dialogue: 0,0:00:40.43,0:00:43.48,Default,,0,0,0,,我可以这么说 假设我们处在现实世界中 Dialogue: 0,0:00:44.11,0:00:46.25,Default,,0,0,0,,我们把这个世界看作是 Dialogue: 0,0:00:46.99,0:00:51.08,Default,,0,0,0,,由许多的事物构成的 Dialogue: 0,0:00:52.06,0:00:55.98,Default,,0,0,0,,每个事物都有其独立的局部状态 Dialogue: 0,0:00:57.24,0:00:59.87,Default,,0,0,0,,正是这些独立的状态使其成为事物 Dialogue: 0,0:01:01.28,0:01:04.27,Default,,0,0,0,,因此我们说 在这个世界的模型中 Dialogue: 0,0:01:04.28,0:01:09.90,Default,,0,0,0,,我们在大脑中和计算机中对那个世界建模 Dialogue: 0,0:01:10.94,0:01:12.54,Default,,0,0,0,,我想要建立一种对应关系 Dialogue: 0,0:01:12.78,0:01:15.21,Default,,0,0,0,,把现实世界和计算机中的对象联系起来 Dialogue: 0,0:01:15.87,0:01:17.74,Default,,0,0,0,,把现实世界中对象间的关系 Dialogue: 0,0:01:17.96,0:01:21.72,Default,,0,0,0,,与计算机中的模型对象间的关系 对应起来 Dialogue: 0,0:01:23.18,0:01:25.52,Default,,0,0,0,,把现实世界中关联对象的函数 Dialogue: 0,0:01:25.93,0:01:28.11,Default,,0,0,0,,与计算机中的函数 对应起来 Dialogue: 0,0:01:30.84,0:01:33.82,Default,,0,0,0,,这让我们获得了模块性 Dialogue: 0,0:01:34.74,0:01:36.75,Default,,0,0,0,,如果我们认为现实世界是像那样的 Dialogue: 0,0:01:37.36,0:01:38.72,Default,,0,0,0,,也就是由许多小的事物构成的 Dialogue: 0,0:01:39.20,0:01:41.47,Default,,0,0,0,,当然 我们可以把世界安排成那样 Dialogue: 0,0:01:42.03,0:01:43.95,Default,,0,0,0,,我们只能对像那样的事物建模 Dialogue: 0,0:01:45.45,0:01:49.02,Default,,0,0,0,,这样 我们的程序就可以从现实世界中继承模块化 Dialogue: 0,0:01:50.45,0:01:53.58,Default,,0,0,0,,这就是发明面向对象编程的初衷 Dialogue: 0,0:01:55.42,0:01:58.19,Default,,0,0,0,,我所见过的最完美的对象(系统) Dialogue: 0,0:01:58.89,0:02:04.17,Default,,0,0,0,,电气系统 就是非常非常完美的对象系统 Dialogue: 0,0:02:06.40,0:02:12.99,Default,,0,0,0,,电气系统真的是物理学家构造的非常非常好的一种对象 Dialogue: 0,0:02:14.22,0:02:16.76,Default,,0,0,0,,这里 我有一些机器零件 Dialogue: 0,0:02:17.12,0:02:18.28,Default,,0,0,0,,就是这些零件 Dialogue: 0,0:02:20.04,0:02:22.88,Default,,0,0,0,,有一个电线连接起了 Dialogue: 0,0:02:23.66,0:02:26.40,Default,,0,0,0,,零件的两个部分 Dialogue: 0,0:02:27.56,0:02:30.86,Default,,0,0,0,,电气世界中 有一个非常棒的特性 Dialogue: 0,0:02:31.64,0:02:33.12,Default,,0,0,0,,就是我可以说这是一个对象 Dialogue: 0,0:02:34.01,0:02:34.97,Default,,0,0,0,,这又是一个对象 Dialogue: 0,0:02:35.71,0:02:37.53,Default,,0,0,0,,它们间的关联一目了然 Dialogue: 0,0:02:38.24,0:02:43.32,Default,,0,0,0,,而且 如果我没有用电线连接 它们便没有关联 Dialogue: 0,0:02:44.74,0:02:46.12,Default,,0,0,0,,比如我有一个灯泡 Dialogue: 0,0:02:46.52,0:02:50.32,Default,,0,0,0,,一个灯泡和一个已经接在插座上的电源 Dialogue: 0,0:02:51.63,0:02:53.53,Default,,0,0,0,,关联非常明了 Dialogue: 0,0:02:53.62,0:02:55.42,Default,,0,0,0,,这就是已知所有的连接方式了 Dialogue: 0,0:02:56.22,0:03:02.33,Default,,0,0,0,,就算我把连接电灯和电源的电线打个结 Dialogue: 0,0:03:02.68,0:03:03.64,Default,,0,0,0,,灯仍然是亮的 Dialogue: 0,0:03:04.04,0:03:04.76,Default,,0,0,0,,没什么影响 Dialogue: 0,0:03:07.44,0:03:12.40,Default,,0,0,0,,物理学上这样安排 可以使连接变成抽象的 Dialogue: 0,0:03:13.08,0:03:15.27,Default,,0,0,0,,至少在低频状态下是可以的 Dialogue: 0,0:03:17.84,0:03:20.88,Default,,0,0,0,,而且这就是全部的关联方式了 Dialogue: 0,0:03:22.35,0:03:23.87,Default,,0,0,0,,当然 我们来进一步 Dialogue: 0,0:03:23.90,0:03:27.31,Default,,0,0,0,,讨论一种在电气系统中最为广泛的抽象 Dialogue: 0,0:03:27.85,0:03:29.42,Default,,0,0,0,,数字电路 Dialogue: 0,0:03:31.69,0:03:33.66,Default,,0,0,0,,这里有一些对象 Dialogue: 0,0:03:34.64,0:03:40.12,Default,,0,0,0,,例如 在数字电路里中 我们有非门 Dialogue: 0,0:03:41.39,0:03:42.78,Default,,0,0,0,,有与门 Dialogue: 0,0:03:43.99,0:03:45.40,Default,,0,0,0,,还有或门 Dialogue: 0,0:03:47.21,0:03:50.12,Default,,0,0,0,,我们用一种特殊的“电线” 把它们连接起来 Dialogue: 0,0:03:52.00,0:03:54.94,Default,,0,0,0,,这些“电线”代表抽象信号 Dialogue: 0,0:03:55.61,0:03:57.18,Default,,0,0,0,,我们不关心具体的物理因素 Dialogue: 0,0:03:57.21,0:03:59.72,Default,,0,0,0,,像电压、电流或者组合因素等 Dialogue: 0,0:04:00.01,0:04:03.44,Default,,0,0,0,,又或者是水压 等等 Dialogue: 0,0:04:05.20,0:04:07.32,Default,,0,0,0,,这些抽象变量代表某类信号 Dialogue: 0,0:04:09.42,0:04:12.89,Default,,0,0,0,,我们用电路连接元件 构建系统 Dialogue: 0,0:04:14.07,0:04:16.22,Default,,0,0,0,,现在 我要向你们介绍一门新的语言 Dialogue: 0,0:04:17.63,0:04:20.17,Default,,0,0,0,,我们要构建一门内嵌于Lisp中的语言 Dialogue: 0,0:04:22.14,0:04:25.08,Default,,0,0,0,,这是一种内部DSL 是类似于之前讲过的图形语言那种 Dialogue: 0,0:04:26.16,0:04:27.32,Default,,0,0,0,,而不是昨天那种 Dialogue: 0,0:04:27.88,0:04:31.61,Default,,0,0,0,,那种模式匹配语言 -- 那是外部DSL Dialogue: 0,0:04:32.80,0:04:36.30,Default,,0,0,0,,模式匹配语言是由Lisp程序所解释的 Dialogue: 0,0:04:38.16,0:04:40.52,Default,,0,0,0,,而之前那种图形语言 Dialogue: 0,0:04:40.56,0:04:44.27,Default,,0,0,0,,是在Lisp中构造我们想要的过程 来封装图形结构 Dialogue: 0,0:04:45.48,0:04:46.75,Default,,0,0,0,,举例来说 Dialogue: 0,0:04:47.72,0:04:50.64,Default,,0,0,0,,首先我要有一些基本对象 Dialogue: 0,0:04:51.05,0:04:52.12,Default,,0,0,0,,比如这个和这个 Dialogue: 0,0:04:53.50,0:04:55.18,Default,,0,0,0,,然后用电线去组合它们 Dialogue: 0,0:04:55.98,0:04:59.37,Default,,0,0,0,,我用(MAKE-WIRE)来构造一个电线 Dialogue: 0,0:04:59.87,0:05:01.24,Default,,0,0,0,,A就代表了一根电线 Dialogue: 0,0:05:01.74,0:05:02.69,Default,,0,0,0,,B也是 Dialogue: 0,0:05:02.69,0:05:03.46,Default,,0,0,0,,C也是 Dialogue: 0,0:05:03.46,0:05:04.23,Default,,0,0,0,,D也是 Dialogue: 0,0:05:04.23,0:05:04.83,Default,,0,0,0,,还有E Dialogue: 0,0:05:04.83,0:05:05.64,Default,,0,0,0,,S也是 Dialogue: 0,0:05:06.88,0:05:12.75,Default,,0,0,0,,而或门有两个输入 分别是A和B Dialogue: 0,0:05:13.16,0:05:14.75,Default,,0,0,0,,它的输出是D Dialogue: 0,0:05:15.07,0:05:16.12,Default,,0,0,0,,我们用这样的记号来表示 Dialogue: 0,0:05:18.14,0:05:22.14,Default,,0,0,0,,与门 输入是A和B 输出是C Dialogue: 0,0:05:22.22,0:05:23.24,Default,,0,0,0,,我们这样表示 Dialogue: 0,0:05:24.82,0:05:28.46,Default,,0,0,0,,通过一系列像这样的声明 Dialogue: 0,0:05:29.29,0:05:31.64,Default,,0,0,0,,我可以组合出任意的电路 Dialogue: 0,0:05:32.75,0:05:34.64,Default,,0,0,0,,我已经告诉了你们创建数字电路 Dialogue: 0,0:05:35.31,0:05:38.51,Default,,0,0,0,,的基本元素和组合方法了 Dialogue: 0,0:05:40.09,0:05:43.04,Default,,0,0,0,,然后就该说抽象的方法了 Dialogue: 0,0:05:43.69,0:05:52.24,Default,,0,0,0,,举例来说 这是一个半加器 Dialogue: 0,0:05:52.67,0:05:55.55,Default,,0,0,0,,如果你学过电路设计肯定知道这个东西 Dialogue: 0,0:05:56.93,0:06:00.44,Default,,0,0,0,,输入两个数A和B Dialogue: 0,0:06:00.62,0:06:02.12,Default,,0,0,0,,输出两者之和以及进位 Dialogue: 0,0:06:04.35,0:06:06.80,Default,,0,0,0,,事实上 完全可以用我刚刚说的来组合电路 Dialogue: 0,0:06:07.45,0:06:10.99,Default,,0,0,0,,盒子外面 半加器盒子的外面有一些接口 Dialogue: 0,0:06:11.13,0:06:14.11,Default,,0,0,0,,这些盒子的边界 我们总是抽象成盒子 Dialogue: 0,0:06:14.79,0:06:19.70,Default,,0,0,0,,从盒子里引出A、B、S、C四根线 Dialogue: 0,0:06:19.70,0:06:21.79,Default,,0,0,0,,这些是已经声明了的变量 Dialogue: 0,0:06:23.39,0:06:26.25,Default,,0,0,0,,由LAMBDA表达式声明的几个变量 Dialogue: 0,0:06:26.28,0:06:28.01,Default,,0,0,0,,定义了这个半加器 Dialogue: 0,0:06:31.40,0:06:35.96,Default,,0,0,0,,在盒子的内部 我构造了电线D和E Dialogue: 0,0:06:36.00,0:06:37.44,Default,,0,0,0,,这是为了连接内部结构 Dialogue: 0,0:06:37.74,0:06:40.40,Default,,0,0,0,,这条是E 这条是D Dialogue: 0,0:06:41.32,0:06:43.50,Default,,0,0,0,,内部连接的线路并没有引出盒子之外 Dialogue: 0,0:06:45.05,0:06:46.83,Default,,0,0,0,,就像电路图那样连起来 Dialogue: 0,0:06:48.79,0:06:50.89,Default,,0,0,0,,大家可以看得出来 Dialogue: 0,0:06:51.05,0:06:53.02,Default,,0,0,0,,这个语言非常有层次性 Dialogue: 0,0:06:53.85,0:06:55.71,Default,,0,0,0,,如果一门语言没有层次性 Dialogue: 0,0:06:55.95,0:06:59.96,Default,,0,0,0,,如果你不能把一个复合对象当成基本对象来使用 Dialogue: 0,0:07:00.38,0:07:01.53,Default,,0,0,0,,这门语言肯定是有问题的 Dialogue: 0,0:07:02.59,0:07:04.22,Default,,0,0,0,,至少我是这么认为的 Dialogue: 0,0:07:06.41,0:07:09.58,Default,,0,0,0,,之前 我们都是在研究数学函数 Dialogue: 0,0:07:09.60,0:07:11.12,Default,,0,0,0,,或者是计算数学函数的东西 Dialogue: 0,0:07:11.15,0:07:12.65,Default,,0,0,0,,这些都是我们之前研究的东西 Dialogue: 0,0:07:13.85,0:07:16.65,Default,,0,0,0,,而我们现在 Dialogue: 0,0:07:16.67,0:07:17.63,Default,,0,0,0,,不这么做了 Dialogue: 0,0:07:17.85,0:07:20.88,Default,,0,0,0,,我们从一些电气对象开始 Dialogue: 0,0:07:21.04,0:07:22.64,Default,,0,0,0,,构建更多的对象 Dialogue: 0,0:07:23.35,0:07:28.83,Default,,0,0,0,,我们用Lisp里的LAMBDA将其粘合起来 Dialogue: 0,0:07:30.38,0:07:32.93,Default,,0,0,0,,“LAMBDA: 终极之粘合剂” Dialogue: 0,0:07:33.32,0:07:36.35,Default,,0,0,0,,当然 半加器可以用于 Dialogue: 0,0:07:37.64,0:07:41.04,Default,,0,0,0,,构造一种更复杂的抽象结构 -- 全加器 Dialogue: 0,0:07:41.60,0:07:45.05,Default,,0,0,0,,如这里所示 全加器由两个半加器构成 Dialogue: 0,0:07:45.47,0:07:47.87,Default,,0,0,0,,用一些额外的电线连接起来 Dialogue: 0,0:07:48.08,0:07:51.29,Default,,0,0,0,,就像这里所示的S、C1、C2以及一个或门 Dialogue: 0,0:07:52.19,0:07:53.60,Default,,0,0,0,,而对于一个全加器 Dialogue: 0,0:07:53.87,0:08:00.78,Default,,0,0,0,,它的输入有:两个待加的数 一个进位值 Dialogue: 0,0:08:01.36,0:08:04.17,Default,,0,0,0,,输出是:两数之和以及进位 Dialogue: 0,0:08:05.90,0:08:10.70,Default,,0,0,0,,构建好全加器以后 还可以把它们链起来组成更大的加法器 Dialogue: 0,0:08:12.99,0:08:14.83,Default,,0,0,0,,现在我们有了一门完整的语言 Dialogue: 0,0:08:16.06,0:08:21.76,Default,,0,0,0,,它有基本元素、组合方法以及抽象方法 Dialogue: 0,0:08:22.27,0:08:23.36,Default,,0,0,0,,现在 我们怎样实现这门语言? Dialogue: 0,0:08:25.00,0:08:26.84,Default,,0,0,0,,其实并不难 Dialogue: 0,0:08:27.07,0:08:27.96,Default,,0,0,0,,首先来看基本元素 Dialogue: 0,0:08:28.12,0:08:30.11,Default,,0,0,0,,这是唯一的问题 Dialogue: 0,0:08:31.16,0:08:32.56,Default,,0,0,0,,不需要再做其它事情了 Dialogue: 0,0:08:33.74,0:08:38.00,Default,,0,0,0,,因为我们直接借用了Lisp中的组合方法以及抽象方法 Dialogue: 0,0:08:39.96,0:08:41.88,Default,,0,0,0,,我们的语言 继承自Lisp并内嵌于其中 Dialogue: 0,0:08:43.77,0:08:45.44,Default,,0,0,0,,好 我们先来看一个基本元素 Dialogue: 0,0:08:45.86,0:08:47.40,Default,,0,0,0,,就拿非门来说吧 Dialogue: 0,0:08:51.54,0:08:54.67,Default,,0,0,0,,非门有两个引脚 分别是输入和输出 Dialogue: 0,0:08:57.31,0:09:02.62,Default,,0,0,0,,它要对输入信号做出响应 Dialogue: 0,0:09:04.30,0:09:07.00,Default,,0,0,0,,它需要对输入电线说 -- Dialogue: 0,0:09:07.64,0:09:10.14,Default,,0,0,0,,我们现在把它们视作对象 Dialogue: 0,0:09:10.44,0:09:12.41,Default,,0,0,0,,其具体细节我们稍后讨论 Dialogue: 0,0:09:13.23,0:09:14.84,Default,,0,0,0,,它对其输入电线的说 Dialogue: 0,0:09:15.82,0:09:18.48,Default,,0,0,0,,“当你的值变发生改变时 告诉我一声” Dialogue: 0,0:09:20.12,0:09:22.11,Default,,0,0,0,,所以非门这个对象 Dialogue: 0,0:09:22.41,0:09:24.38,Default,,0,0,0,,会对输入电线这个对象说 -- Dialogue: 0,0:09:25.13,0:09:26.40,Default,,0,0,0,,“Hi 我是George” Dialogue: 0,0:09:26.87,0:09:31.02,Default,,0,0,0,,“我的工作就是 对你的变化做出响应” Dialogue: 0,0:09:31.72,0:09:34.19,Default,,0,0,0,,“所以当你变化的时候 告诉我一声” Dialogue: 0,0:09:34.73,0:09:35.72,Default,,0,0,0,,“这样我才能进一步的处理” Dialogue: 0,0:09:36.88,0:09:40.30,Default,,0,0,0,,这是通过在这里 在输入电线上 Dialogue: 0,0:09:41.40,0:09:44.64,Default,,0,0,0,,添加一个叫做INVERT-IN的动作来实现的 Dialogue: 0,0:09:45.07,0:09:46.94,Default,,0,0,0,,INVERT-IN在这里定义 Dialogue: 0,0:09:47.05,0:09:48.76,Default,,0,0,0,,它是一个无参过程 Dialogue: 0,0:09:49.98,0:09:54.59,Default,,0,0,0,,它将线路上的信号逻辑取反 Dialogue: 0,0:09:56.06,0:09:58.64,Default,,0,0,0,,经过一段时长为INVERTER-DELAT的延时以后 -- Dialogue: 0,0:09:59.26,0:10:01.15,Default,,0,0,0,,每个电路对象都有延时 -- Dialogue: 0,0:10:02.88,0:10:04.46,Default,,0,0,0,,然后我们会 -- Dialogue: 0,0:10:04.67,0:10:07.14,Default,,0,0,0,,我们再把输出设置为新的值 Dialogue: 0,0:10:10.16,0:10:11.36,Default,,0,0,0,,非常简单 Dialogue: 0,0:10:12.40,0:10:15.28,Default,,0,0,0,,你可以想象输出电线也同样是信号敏感的 Dialogue: 0,0:10:15.77,0:10:18.27,Default,,0,0,0,,当信号改变的时候 Dialogue: 0,0:10:19.28,0:10:21.15,Default,,0,0,0,,它会“告知”其它对象 Dialogue: 0,0:10:21.79,0:10:24.78,Default,,0,0,0,,“快醒醒!我的值已经改变啦” Dialogue: 0,0:10:26.05,0:10:30.14,Default,,0,0,0,,所以当你把非门和与门或者元件连在一起的时候 Dialogue: 0,0:10:30.46,0:10:32.20,Default,,0,0,0,,它们之间将会有大量的通信 Dialogue: 0,0:10:32.86,0:10:35.07,Default,,0,0,0,,以确保信号正确地传播 Dialogue: 0,0:10:36.81,0:10:38.62,Default,,0,0,0,,到目前为止 没什么新奇的东西 Dialogue: 0,0:10:38.62,0:10:40.72,Default,,0,0,0,,我们只是针对某个特定的表示法 Dialogue: 0,0:10:40.72,0:10:45.24,Default,,0,0,0,,也就是这个例子中的1、0 -- 实现了LOGICAL-NOT而已 Dialogue: 0,0:10:46.73,0:10:49.16,Default,,0,0,0,,与门就相对复杂一些 Dialogue: 0,0:10:49.78,0:10:55.80,Default,,0,0,0,,与门有两个输入A1和A2 输出是OUTPUT Dialogue: 0,0:10:56.73,0:11:00.64,Default,,0,0,0,,但是其结构和非门没有什么大的不同 Dialogue: 0,0:11:00.86,0:11:03.44,Default,,0,0,0,,只不过是 当输入信号改变的时候 Dialogue: 0,0:11:04.52,0:11:09.07,Default,,0,0,0,,与门调用的是AND-ACTION过程罢了 Dialogue: 0,0:11:10.91,0:11:12.88,Default,,0,0,0,,当然 它所做的只是 Dialogue: 0,0:11:12.91,0:11:15.37,Default,,0,0,0,,对输入信号进行逻辑“与”运算 Dialogue: 0,0:11:16.19,0:11:18.76,Default,,0,0,0,,在经过AND-GATE-DELAY的延时之后 Dialogue: 0,0:11:20.46,0:11:24.36,Default,,0,0,0,,调用这个过程 更新输出信号值 Dialogue: 0,0:11:25.47,0:11:28.35,Default,,0,0,0,,那么 我们如何用“按愿望思维”来构造这一切呢? Dialogue: 0,0:11:28.35,0:11:31.08,Default,,0,0,0,,如大家所见 这里有一个赋值运算 Dialogue: 0,0:11:32.02,0:11:32.78,Default,,0,0,0,,但并不是SET! Dialogue: 0,0:11:34.57,0:11:36.78,Default,,0,0,0,,这是一个派生出来的运算 Dialogue: 0,0:11:36.78,0:11:38.73,Default,,0,0,0,,就像可以从CAR和CDR派生出其它函数一样 Dialogue: 0,0:11:40.80,0:11:44.81,Default,,0,0,0,,因此 按照约定 我加上“!”(表示这个过程有副作用) Dialogue: 0,0:11:46.34,0:11:49.18,Default,,0,0,0,,这里有个过程ADD-ACTION! Dialogue: 0,0:11:49.44,0:11:54.67,Default,,0,0,0,,它用来提醒与门中的局部线路A1 Dialogue: 0,0:11:55.63,0:11:58.68,Default,,0,0,0,,当它改变的时候记得执行过程AND-ACTION-PROCEDURE Dialogue: 0,0:11:59.58,0:12:02.91,Default,,0,0,0,,A2也是一样 Dialogue: 0,0:12:06.31,0:12:07.23,Default,,0,0,0,,非常简单 Dialogue: 0,0:12:09.96,0:12:12.09,Default,,0,0,0,,现在我们再来看看 Dialogue: 0,0:12:12.70,0:12:16.12,Default,,0,0,0,,各部分间是如何通信的 Dialogue: 0,0:12:18.54,0:12:19.66,Default,,0,0,0,,例如 Dialogue: 0,0:12:23.12,0:12:24.27,Default,,0,0,0,,有一个非常简单的电路 Dialogue: 0,0:12:24.27,0:12:30.46,Default,,0,0,0,,它有一个与门 带有两个输入A、B Dialogue: 0,0:12:31.92,0:12:38.00,Default,,0,0,0,,与门通过电线C跟非门相连 Dialogue: 0,0:12:39.72,0:12:41.53,Default,,0,0,0,,非门的输出是D Dialogue: 0,0:12:44.20,0:12:47.34,Default,,0,0,0,,这就是物理世界 Dialogue: 0,0:12:47.36,0:12:49.02,Default,,0,0,0,,一个对物理世界的抽象 Dialogue: 0,0:12:49.86,0:12:53.40,Default,,0,0,0,,要不了几分钱就可以从Radio Shack买到这些元件 Dialogue: 0,0:12:54.88,0:12:56.32,Default,,0,0,0,,那些元件的作用和画在这里的差不多 Dialogue: 0,0:12:57.16,0:13:00.22,Default,,0,0,0,,元件上都标有类似于LS04的标签 Dialogue: 0,0:13:01.53,0:13:08.16,Default,,0,0,0,,现在来看其中的计算模型 Dialogue: 0,0:13:09.01,0:13:10.94,Default,,0,0,0,,它又对应着什么 Dialogue: 0,0:13:11.13,0:13:14.09,Default,,0,0,0,,计算机中的对象对应着我们思维中的什么 Dialogue: 0,0:13:15.85,0:13:19.13,Default,,0,0,0,,我需要把现实世界中的每个对象与计算机中的对应起来 Dialogue: 0,0:13:19.79,0:13:24.27,Default,,0,0,0,,把两个世界中对象之间的关系也对应起来 Dialogue: 0,0:13:26.06,0:13:26.80,Default,,0,0,0,,这是我的目标 Dialogue: 0,0:13:28.56,0:13:29.45,Default,,0,0,0,,让我们来看看怎么做 Dialogue: 0,0:13:30.90,0:13:34.20,Default,,0,0,0,,这一团东西代表信号A Dialogue: 0,0:13:35.71,0:13:36.94,Default,,0,0,0,,这是信号A Dialogue: 0,0:13:37.94,0:13:39.32,Default,,0,0,0,,画得像一团云 Dialogue: 0,0:13:39.90,0:13:42.80,Default,,0,0,0,,再画另一个信号 -- B Dialogue: 0,0:13:46.68,0:13:47.47,Default,,0,0,0,,它是另一个信号 Dialogue: 0,0:13:49.14,0:13:50.91,Default,,0,0,0,,这两个信号 Dialogue: 0,0:13:51.10,0:13:52.81,Default,,0,0,0,,要通过某种方式连在一起 Dialogue: 0,0:13:53.72,0:13:58.75,Default,,0,0,0,,连在这个盒子上 -- 这就代表与门 Dialogue: 0,0:14:00.32,0:14:02.04,Default,,0,0,0,,这就是与门的动作过程 Dialogue: 0,0:14:07.66,0:14:08.59,Default,,0,0,0,,它将产生 Dialogue: 0,0:14:09.15,0:14:13.29,Default,,0,0,0,,它将与另外一个称作C的信号对象交互 Dialogue: 0,0:14:16.22,0:14:18.88,Default,,0,0,0,,哦 说错了 是一条电线C Dialogue: 0,0:14:20.59,0:14:26.28,Default,,0,0,0,,这跟电线 又将连在另一个动作过程上 Dialogue: 0,0:14:26.28,0:14:30.33,Default,,0,0,0,,在我们的电气世界中 这个过程跟一个非门关联 Dialogue: 0,0:14:32.86,0:14:40.65,Default,,0,0,0,,我还有另外一根电线 -- D Dialogue: 0,0:14:42.97,0:14:45.29,Default,,0,0,0,,整体布局就是这样 Dialogue: 0,0:14:46.00,0:14:49.44,Default,,0,0,0,,现在必须来研究它们 有关计算的内部机制了 Dialogue: 0,0:14:51.50,0:14:53.69,Default,,0,0,0,,每一跟电线都必须知道 Dialogue: 0,0:14:53.69,0:14:56.36,Default,,0,0,0,,自己承载的信号是什么 Dialogue: 0,0:14:57.34,0:15:00.00,Default,,0,0,0,,我们用变量SIGNAL来表示 Dialogue: 0,0:15:02.97,0:15:04.04,Default,,0,0,0,,SIGNAL的值就是信号 Dialogue: 0,0:15:05.68,0:15:07.74,Default,,0,0,0,,也不要忘了它所关联的环境 Dialogue: 0,0:15:08.89,0:15:11.34,Default,,0,0,0,,对于每个元件来说 一定有一个环境绑定了信号 Dialogue: 0,0:15:15.40,0:15:16.88,Default,,0,0,0,,因此 这里也有一个SIGNAL变量 Dialogue: 0,0:15:19.40,0:15:21.92,Default,,0,0,0,,SIGNAL的值不是0就是1 Dialogue: 0,0:15:22.81,0:15:23.48,Default,,0,0,0,,这儿也有个SIGNAL Dialogue: 0,0:15:28.00,0:15:30.56,Default,,0,0,0,,现在 一旦这里的信号改变 Dialogue: 0,0:15:31.26,0:15:34.11,Default,,0,0,0,,我们需要通知一系列的对象 Dialogue: 0,0:15:36.66,0:15:37.66,Default,,0,0,0,,我们得通知这个与门 Dialogue: 0,0:15:39.30,0:15:43.96,Default,,0,0,0,,这里有个表 我们把它叫做AP Dialogue: 0,0:15:44.50,0:15:45.60,Default,,0,0,0,,它可能是一个表 Dialogue: 0,0:15:46.44,0:15:49.00,Default,,0,0,0,,在本例中 表里面的第一项条目是这个东西 Dialogue: 0,0:15:50.50,0:15:54.81,Default,,0,0,0,,这个元件也有一个称为AP的表 Dialogue: 0,0:15:54.81,0:15:58.17,Default,,0,0,0,,也可能有一些其它对象 时刻等待着A来通知“它们” Dialogue: 0,0:15:59.02,0:16:01.31,Default,,0,0,0,,所以这里可能有其它对象 比如 Dialogue: 0,0:16:01.72,0:16:03.23,Default,,0,0,0,,一些其它我们不知道的对象 Dialogue: 0,0:16:03.63,0:16:04.88,Default,,0,0,0,,这些是与A连接的其它对象 Dialogue: 0,0:16:07.20,0:16:09.64,Default,,0,0,0,,这里的AP表 Dialogue: 0,0:16:11.12,0:16:12.40,Default,,0,0,0,,也指向这个与门 Dialogue: 0,0:16:13.07,0:16:16.35,Default,,0,0,0,,相类似的 这里的AP表 Dialogue: 0,0:16:16.78,0:16:18.53,Default,,0,0,0,,也要指向这里 Dialogue: 0,0:16:18.53,0:16:20.89,Default,,0,0,0,,这里是C要通知的元件 Dialogue: 0,0:16:21.77,0:16:23.18,Default,,0,0,0,,D也一样 Dialogue: 0,0:16:24.28,0:16:25.24,Default,,0,0,0,,但是我不知道它要通知谁 Dialogue: 0,0:16:25.26,0:16:26.65,Default,,0,0,0,,因为我的图中没有画出来 Dialogue: 0,0:16:27.19,0:16:28.36,Default,,0,0,0,,可能是和D连接起来的其它元件 Dialogue: 0,0:16:30.32,0:16:32.62,Default,,0,0,0,,同样的 Dialogue: 0,0:16:33.80,0:16:36.96,Default,,0,0,0,,当AND-ACTION过程被唤醒时 Dialogue: 0,0:16:37.02,0:16:41.31,Default,,0,0,0,,也就是说 之前你拜托某人将你唤醒 Dialogue: 0,0:16:41.45,0:16:44.84,Default,,0,0,0,,你拜托它们 当它们的信号发生改变时通知你 Dialogue: 0,0:16:46.97,0:16:48.81,Default,,0,0,0,,你得去检查它的信号是什么 Dialogue: 0,0:16:49.32,0:16:52.25,Default,,0,0,0,,这样你就可以计算逻辑与 输出信号给下一个元件 Dialogue: 0,0:16:57.09,0:16:58.75,Default,,0,0,0,,所里 这里就必须要有 Dialogue: 0,0:16:58.84,0:17:03.00,Default,,0,0,0,,有信息说 A1是这个元件 Dialogue: 0,0:17:03.90,0:17:06.48,Default,,0,0,0,,A2就是这个元件 Dialogue: 0,0:17:08.93,0:17:09.98,Default,,0,0,0,,不只是这样 Dialogue: 0,0:17:11.79,0:17:15.20,Default,,0,0,0,,当我在计算逻辑与时 我还得告诉这个元件一些信息 Dialogue: 0,0:17:16.30,0:17:21.05,Default,,0,0,0,,还有一个输出 输出给这个元件 Dialogue: 0,0:17:25.80,0:17:30.03,Default,,0,0,0,,同样地 非门也有一个输入 Dialogue: 0,0:17:32.38,0:17:34.92,Default,,0,0,0,,当信号被唤醒并告知它信号被修改时 Dialogue: 0,0:17:36.75,0:17:38.64,Default,,0,0,0,,非门会询问该信号 Dialogue: 0,0:17:38.64,0:17:40.09,Default,,0,0,0,,你的值是什么 Dialogue: 0,0:17:41.05,0:17:43.47,Default,,0,0,0,,信号通过像这样发消息 告知“信号已改变” Dialogue: 0,0:17:43.52,0:17:45.53,Default,,0,0,0,,它就反过来查询这个新的信号值 Dialogue: 0,0:17:46.90,0:17:50.12,Default,,0,0,0,,取到值之后 它将会 Dialogue: 0,0:17:50.14,0:17:55.86,Default,,0,0,0,,计算输出 并改变这个信号的值 Dialogue: 0,0:18:00.60,0:18:01.24,Default,,0,0,0,,以此类推 Dialogue: 0,0:18:02.84,0:18:04.56,Default,,0,0,0,,因此我也必须有这么多的连接 Dialogue: 0,0:18:06.24,0:18:09.23,Default,,0,0,0,,现在我们回头观察一下 这个与门 Dialogue: 0,0:18:10.26,0:18:12.09,Default,,0,0,0,,回到这张幻灯片 Dialogue: 0,0:18:13.67,0:18:15.04,Default,,0,0,0,,这几个部分的内容 Dialogue: 0,0:18:16.04,0:18:19.32,Default,,0,0,0,,对每个与门 都有A1、A2两个输入 一个OUTPUT输出 Dialogue: 0,0:18:21.03,0:18:23.53,Default,,0,0,0,,这些都是 Dialogue: 0,0:18:25.08,0:18:28.16,Default,,0,0,0,,在AND-GATE被调用时的环境中 Dialogue: 0,0:18:28.41,0:18:31.24,Default,,0,0,0,,这些参数创建了一个框架 Dialogue: 0,0:18:33.31,0:18:35.90,Default,,0,0,0,,这个框架用来存放A1、A2和OUTPUT的值 Dialogue: 0,0:18:36.67,0:18:39.20,Default,,0,0,0,,它们都要与电线相绑定 Dialogue: 0,0:18:39.60,0:18:44.25,Default,,0,0,0,,这些电线就是通过参数传进来的 Dialogue: 0,0:18:46.24,0:18:47.31,Default,,0,0,0,,在这个环境下 Dialogue: 0,0:18:47.74,0:18:49.85,Default,,0,0,0,,我构建一个过程 Dialogue: 0,0:18:50.97,0:18:53.68,Default,,0,0,0,,就在这里 Dialogue: 0,0:18:54.59,0:18:57.31,Default,,0,0,0,,在该环境下定义的AND-ACTION-PROCEDURE Dialogue: 0,0:18:58.35,0:19:00.70,Default,,0,0,0,,这个实际上是对一个LAMBDA表达式求值 Dialogue: 0,0:19:01.62,0:19:05.48,Default,,0,0,0,,它跟求值该LAMBDA表达式时的环境相绑定 Dialogue: 0,0:19:07.16,0:19:09.34,Default,,0,0,0,,找到它的局部环境 Dialogue: 0,0:19:11.70,0:19:13.47,Default,,0,0,0,,因此AND-ACTION-PROCEDURE过程能够 Dialogue: 0,0:19:13.64,0:19:16.94,Default,,0,0,0,,存取这里看到的A1、A2和OUTPUT Dialogue: 0,0:19:17.31,0:19:19.64,Default,,0,0,0,,A1、A2、OUTPUT Dialogue: 0,0:19:22.36,0:19:23.95,Default,,0,0,0,,我们还没有深入探索“电线”的内部结构 Dialogue: 0,0:19:26.03,0:19:26.99,Default,,0,0,0,,那是仅剩的部分 Dialogue: 0,0:19:29.03,0:19:29.92,Default,,0,0,0,,来看看“电线” Dialogue: 0,0:19:33.52,0:19:36.25,Default,,0,0,0,,麻烦请开一下投影仪 Dialogue: 0,0:19:39.50,0:19:42.56,Default,,0,0,0,,“电线”是有那么一点复杂 Dialogue: 0,0:19:43.09,0:19:44.64,Default,,0,0,0,,哦 摁错了 Dialogue: 0,0:19:47.05,0:19:48.75,Default,,0,0,0,,是非常复杂 像这样 Dialogue: 0,0:19:50.06,0:19:53.10,Default,,0,0,0,,但是还是来看一下 到底是什么 Dialogue: 0,0:19:54.72,0:19:56.67,Default,,0,0,0,,“电线”是这样的一种东西 Dialogue: 0,0:19:57.76,0:20:03.52,Default,,0,0,0,,有两个主要部分 都是它的状态 Dialogue: 0,0:20:05.01,0:20:07.39,Default,,0,0,0,,我们这里看到的 一个是信号值 Dialogue: 0,0:20:07.45,0:20:10.06,Default,,0,0,0,,这里 当我们调用MAKE-WIRE创建一条电线时 Dialogue: 0,0:20:10.46,0:20:13.02,Default,,0,0,0,,我们首先要创建一些变量 Dialogue: 0,0:20:14.94,0:20:16.08,Default,,0,0,0,,分别是这条电线的 Dialogue: 0,0:20:17.10,0:20:19.29,Default,,0,0,0,,SIGNAL和ACTION-PROCS Dialogue: 0,0:20:22.32,0:20:23.44,Default,,0,0,0,,在这个上下文中 Dialogue: 0,0:20:23.76,0:20:27.04,Default,,0,0,0,,我们定义了一系列的过程 Dialogue: 0,0:20:27.84,0:20:31.15,Default,,0,0,0,,其中一个是(SET-MY-SIGNAL! NEW) Dialogue: 0,0:20:32.85,0:20:37.42,Default,,0,0,0,,它所做的只是 取一个新值NEW Dialogue: 0,0:20:37.93,0:20:40.36,Default,,0,0,0,,如果NEW和SIGNAL一样 信号没有变化 就没必要做什么了 Dialogue: 0,0:20:40.36,0:20:42.62,Default,,0,0,0,,否则 把SIGNAL的值赋值为NEW Dialogue: 0,0:20:42.75,0:20:44.60,Default,,0,0,0,,再调用ACTION-PROCS里的所有过程 Dialogue: 0,0:20:46.52,0:20:52.51,Default,,0,0,0,,那些我之前引入的过程 Dialogue: 0,0:20:54.63,0:21:01.53,Default,,0,0,0,,也就是我在定义与门时就定义的过程 Dialogue: 0,0:21:04.13,0:21:05.60,Default,,0,0,0,,是在代码最后调用ADD-ACTION-PROCEDURE实现的 Dialogue: 0,0:21:07.41,0:21:10.80,Default,,0,0,0,,然后 我还得定义一个过程 用来接受动作 Dialogue: 0,0:21:10.81,0:21:11.82,Default,,0,0,0,,也就是这段代码 Dialogue: 0,0:21:12.80,0:21:15.13,Default,,0,0,0,,它增加了AP表 Dialogue: 0,0:21:15.56,0:21:21.63,Default,,0,0,0,,这是通过使用SET!将PROC与旧的AP表CONS起来实现的 Dialogue: 0,0:21:21.79,0:21:24.25,Default,,0,0,0,,而这个PROC是作为参数传递进来的 Dialogue: 0,0:21:25.40,0:21:27.58,Default,,0,0,0,,由于技术原因 最后还要再运行一次PROC Dialogue: 0,0:21:27.78,0:21:29.20,Default,,0,0,0,,我不会再对此详细展开 Dialogue: 0,0:21:29.39,0:21:33.15,Default,,0,0,0,,这是一种事件驱动的模拟 Dialogue: 0,0:21:34.59,0:21:36.00,Default,,0,0,0,,要想把这个讲清楚还是得花点时间 Dialogue: 0,0:21:36.95,0:21:39.40,Default,,0,0,0,,最后 我还要定义一个“分派器” Dialogue: 0,0:21:39.96,0:21:43.58,Default,,0,0,0,,这是一种将消息分派给电线的方法 Dialogue: 0,0:21:45.37,0:21:48.65,Default,,0,0,0,,它将用于从中抽取出不同的信息 Dialogue: 0,0:21:49.07,0:21:51.48,Default,,0,0,0,,比如这里 当前的信号值是多少? Dialogue: 0,0:21:53.82,0:21:55.66,Default,,0,0,0,,设置新信号值的方法是什么? Dialogue: 0,0:21:57.18,0:21:58.28,Default,,0,0,0,,我想要这个方法 Dialogue: 0,0:22:00.10,0:22:02.60,Default,,0,0,0,,我怎么样去添加另外的动作过程呢? Dialogue: 0,0:22:05.51,0:22:09.36,Default,,0,0,0,,最后 以DISPATCH过程为返回值返回 Dialogue: 0,0:22:09.94,0:22:11.87,Default,,0,0,0,,因此 我所构造的电线 Dialogue: 0,0:22:12.00,0:22:13.55,Default,,0,0,0,,是一种可以接收消息的对象 Dialogue: 0,0:22:14.25,0:22:16.01,Default,,0,0,0,,它接收的消息类似于 Dialogue: 0,0:22:16.44,0:22:18.36,Default,,0,0,0,,“你的哪个方法可以用来添加动作过程?” Dialogue: 0,0:22:19.92,0:22:21.00,Default,,0,0,0,,它返回一个过程 Dialogue: 0,0:22:21.64,0:22:23.05,Default,,0,0,0,,它返回ADD-ACTION-PROCUDURE Dialogue: 0,0:22:23.07,0:22:26.54,Default,,0,0,0,,我可以将其应用在一个动作过程上 Dialogue: 0,0:22:27.05,0:22:29.01,Default,,0,0,0,,从而实现将一个动作过程加入电线的AP表中 Dialogue: 0,0:22:31.62,0:22:32.82,Default,,0,0,0,,这是一种“许可” Dialogue: 0,0:22:33.20,0:22:36.08,Default,,0,0,0,,使得你可以去修改自身的AP表 Dialogue: 0,0:22:37.82,0:22:40.16,Default,,0,0,0,,实际上 你可以在这里看到 Dialogue: 0,0:22:41.71,0:22:42.32,Default,,0,0,0,,下一张幻灯片 Dialogue: 0,0:22:43.53,0:22:43.82,Default,,0,0,0,,噢 Dialogue: 0,0:22:47.76,0:22:49.12,Default,,0,0,0,,没什么有意思的 Dialogue: 0,0:22:49.12,0:22:50.65,Default,,0,0,0,,CALL-EACH调用每个动作过程 Dialogue: 0,0:22:50.89,0:22:52.57,Default,,0,0,0,,这只是对一个表不断做CDR Dialogue: 0,0:22:52.73,0:22:54.60,Default,,0,0,0,,没什么好说的 Dialogue: 0,0:22:54.99,0:22:56.25,Default,,0,0,0,,我们早就知道了 Dialogue: 0,0:22:57.56,0:23:00.67,Default,,0,0,0,,然而 如果我想知道线路上的信号值 Dialogue: 0,0:23:01.02,0:23:02.54,Default,,0,0,0,,我询问该线路:你的 -- Dialogue: 0,0:23:02.54,0:23:03.09,Default,,0,0,0,,回想一下 什么是线路? Dialogue: 0,0:23:03.09,0:23:05.40,Default,,0,0,0,,线路对象只是在创建它时所返回的分派过程而已 Dialogue: 0,0:23:05.86,0:23:06.48,Default,,0,0,0,,只是一个过程 Dialogue: 0,0:23:06.83,0:23:12.27,Default,,0,0,0,,我向该分派器发送一个消息'GET-SIGNAL Dialogue: 0,0:23:12.91,0:23:15.40,Default,,0,0,0,,实际得到的是一个方法 用于取得线路信号值 Dialogue: 0,0:23:16.90,0:23:17.96,Default,,0,0,0,,进一步 我就可以得到信号值 Dialogue: 0,0:23:19.22,0:23:20.52,Default,,0,0,0,,如果我想要设置一个信号值 Dialogue: 0,0:23:22.65,0:23:23.96,Default,,0,0,0,,我想要改变一个信号值 Dialogue: 0,0:23:24.51,0:23:26.76,Default,,0,0,0,,我要做的是 Dialogue: 0,0:23:26.92,0:23:29.69,Default,,0,0,0,,以一个线路和信号的新值作为参数 Dialogue: 0,0:23:30.01,0:23:32.43,Default,,0,0,0,,我向线路请求许可 来设置它的信号值 Dialogue: 0,0:23:32.84,0:23:37.61,Default,,0,0,0,,我会用该许可 -- 也就是一个过程 -- 应用在一个新值上 Dialogue: 0,0:23:38.70,0:23:40.51,Default,,0,0,0,,我们再过来看投影 Dialogue: 0,0:23:41.64,0:23:43.24,Default,,0,0,0,,好的 谢谢 Dialogue: 0,0:23:44.20,0:23:45.63,Default,,0,0,0,,我们看这里的投影 Dialogue: 0,0:23:45.92,0:23:48.75,Default,,0,0,0,,我们看到 如果我请求设置信号的方法 Dialogue: 0,0:23:49.34,0:23:50.44,Default,,0,0,0,,也就是这段代码 Dialogue: 0,0:23:52.25,0:23:55.69,Default,,0,0,0,,返回的是一个定义在线路内部的SET-MY-SIGNAL!方法 Dialogue: 0,0:23:56.25,0:23:57.69,Default,,0,0,0,,回过头来看它的定义 Dialogue: 0,0:23:58.72,0:23:59.74,Default,,0,0,0,,它的定义是 Dialogue: 0,0:24:00.43,0:24:02.68,Default,,0,0,0,,将我的一个内部变量SIGNAL的值设为 Dialogue: 0,0:24:02.73,0:24:05.50,Default,,0,0,0,,这个内部变量 用于存储信号值 Dialogue: 0,0:24:07.61,0:24:10.03,Default,,0,0,0,,将其值设为通过参数传递的NEW Dialogue: 0,0:24:10.78,0:24:13.01,Default,,0,0,0,,然后调用AP表中的过程 来唤醒它们 Dialogue: 0,0:24:16.34,0:24:16.99,Default,,0,0,0,,非常简单 Dialogue: 0,0:24:19.24,0:24:20.76,Default,,0,0,0,,回头来看刚才的幻灯片 Dialogue: 0,0:24:22.48,0:24:24.32,Default,,0,0,0,,还有最后一点 Dialogue: 0,0:24:24.36,0:24:27.31,Default,,0,0,0,,我想你们现在应该很轻易地就能理解了 Dialogue: 0,0:24:27.77,0:24:29.15,Default,,0,0,0,,关于我们如何添加新的动作过程 Dialogue: 0,0:24:30.10,0:24:35.18,Default,,0,0,0,,我们需要WIRE和ACTION-PROC两个参数 Dialogue: 0,0:24:36.47,0:24:39.31,Default,,0,0,0,,然后请求添加动作过程的许可 Dialogue: 0,0:24:40.05,0:24:44.22,Default,,0,0,0,,得到许可后 用该许可去添加新的动作过程 Dialogue: 0,0:24:45.84,0:24:47.08,Default,,0,0,0,,所以 这确实是一个“对象” Dialogue: 0,0:24:48.57,0:24:50.32,Default,,0,0,0,,还有些细节 Dialogue: 0,0:24:52.46,0:24:58.39,Default,,0,0,0,,比如 我怎么来控制它? Dialogue: 0,0:24:58.39,0:24:59.69,Default,,0,0,0,,这些延时怎么实现? Dialogue: 0,0:25:00.99,0:25:02.54,Default,,0,0,0,,我们来快速过一遍 Dialogue: 0,0:25:05.50,0:25:07.98,Default,,0,0,0,,下一张 Dialogue: 0,0:25:08.36,0:25:08.88,Default,,0,0,0,,我们来看看 Dialogue: 0,0:25:09.57,0:25:14.17,Default,,0,0,0,,我们细看与门、或门的定义 Dialogue: 0,0:25:15.31,0:25:17.00,Default,,0,0,0,,会发现当输入信号改变时 Dialogue: 0,0:25:17.24,0:25:18.19,Default,,0,0,0,,会有“延时” Dialogue: 0,0:25:18.77,0:25:21.24,Default,,0,0,0,,然后它将调用过程 Dialogue: 0,0:25:21.63,0:25:23.00,Default,,0,0,0,,来改变输出 Dialogue: 0,0:25:26.04,0:25:27.92,Default,,0,0,0,,这个要如何实现? Dialogue: 0,0:25:28.12,0:25:29.92,Default,,0,0,0,,我们将要建立一种机制 Dialogue: 0,0:25:30.30,0:25:32.00,Default,,0,0,0,,一种相当复杂的机制 Dialogue: 0,0:25:32.33,0:25:33.76,Default,,0,0,0,,我们得非常细心地来看 Dialogue: 0,0:25:34.72,0:25:37.23,Default,,0,0,0,,一段延时之后 我们将执行一个动作 Dialogue: 0,0:25:37.39,0:25:38.12,Default,,0,0,0,,DELAY是一个数 Dialogue: 0,0:25:38.16,0:25:39.23,Default,,0,0,0,,而ACTION是一个过程 Dialogue: 0,0:25:40.59,0:25:43.72,Default,,0,0,0,,我们引入一种称为THE-AGENDA的特殊数据结构 Dialogue: 0,0:25:45.50,0:25:48.80,Default,,0,0,0,,用于组织时间与动作 Dialogue: 0,0:25:49.51,0:25:50.88,Default,,0,0,0,,一会儿再来仔细研究 Dialogue: 0,0:25:50.88,0:25:52.54,Default,,0,0,0,,先把这里说完 Dialogue: 0,0:25:53.07,0:25:58.28,Default,,0,0,0,,THE-AGENDA将记录执行动作的时刻 Dialogue: 0,0:25:59.13,0:26:02.46,Default,,0,0,0,,我们把它设定在未来的某个时刻 Dialogue: 0,0:26:02.51,0:26:05.68,Default,,0,0,0,,也就是在CURRENT-TIME加上DELAT的时刻 Dialogue: 0,0:26:05.69,0:26:07.13,Default,,0,0,0,,触发关联的动作 Dialogue: 0,0:26:09.02,0:26:10.56,Default,,0,0,0,,我们把准备好要执行的动作 Dialogue: 0,0:26:11.02,0:26:12.40,Default,,0,0,0,,添加入THE-AGENDA中 Dialogue: 0,0:26:15.28,0:26:18.03,Default,,0,0,0,,要使这个“机器”运行起来并不困难 Dialogue: 0,0:26:18.66,0:26:21.48,Default,,0,0,0,,我们利用这个PROPAGATE过程来完成这件事 Dialogue: 0,0:26:22.71,0:26:25.95,Default,,0,0,0,,如果THE-AGENDA为空 就没有要做的 Dialogue: 0,0:26:27.44,0:26:28.16,Default,,0,0,0,,否则 Dialogue: 0,0:26:29.76,0:26:31.53,Default,,0,0,0,,我们就取出THE-AGENDA的第一个元素 Dialogue: 0,0:26:31.71,0:26:33.34,Default,,0,0,0,,它是一个无参过程 Dialogue: 0,0:26:34.20,0:26:36.03,Default,,0,0,0,,所以这里有额外的括号 Dialogue: 0,0:26:36.03,0:26:37.85,Default,,0,0,0,,我们对其进行无参调用 Dialogue: 0,0:26:39.19,0:26:40.17,Default,,0,0,0,,这就执行了之前存入的动作 Dialogue: 0,0:26:42.20,0:26:44.17,Default,,0,0,0,,然后我们从THE-AGENDA中删除第一个元素 Dialogue: 0,0:26:44.59,0:26:46.14,Default,,0,0,0,,然后再进入传播循环 Dialogue: 0,0:26:48.91,0:26:50.75,Default,,0,0,0,,这就是整体的结构 Dialogue: 0,0:26:53.38,0:26:55.93,Default,,0,0,0,,还有点其它的 Dialogue: 0,0:26:57.43,0:27:00.01,Default,,0,0,0,,现在 我们来看看THE-AGENDA的内部结构 Dialogue: 0,0:27:00.57,0:27:01.55,Default,,0,0,0,,请看投影仪 Dialogue: 0,0:27:02.80,0:27:04.67,Default,,0,0,0,,该如何使用这个玩意儿呢? Dialogue: 0,0:27:04.67,0:27:07.41,Default,,0,0,0,,我需要给你们说明下这个模拟器的用法 Dialogue: 0,0:27:07.85,0:27:09.93,Default,,0,0,0,,你们可能觉得这个模拟器太简陋了 Dialogue: 0,0:27:10.40,0:27:12.01,Default,,0,0,0,,甚至你们认为它根本没什么用 Dialogue: 0,0:27:12.57,0:27:13.76,Default,,0,0,0,,而实际上是 Dialogue: 0,0:27:13.98,0:27:15.39,Default,,0,0,0,,这样的模拟器曾被用于 Dialogue: 0,0:27:15.72,0:27:17.44,Default,,0,0,0,,操纵相当大型的计算机 Dialogue: 0,0:27:18.68,0:27:20.64,Default,,0,0,0,,那是一个真实的事例 Dialogue: 0,0:27:22.36,0:27:24.06,Default,,0,0,0,,当然 并不完全是这里的这个模拟器 Dialogue: 0,0:27:24.06,0:27:25.39,Default,,0,0,0,,我会告诉你它们的区别 Dialogue: 0,0:27:25.84,0:27:28.70,Default,,0,0,0,,区别就是 操纵大型机的模拟器有更多的基本元素 Dialogue: 0,0:27:29.82,0:27:32.22,Default,,0,0,0,,不只是有非门 与门之类的 Dialogue: 0,0:27:33.20,0:27:35.72,Default,,0,0,0,,还有边缘触发器 Dialogue: 0,0:27:36.25,0:27:39.88,Default,,0,0,0,,翻转触发器 锁存器 Dialogue: 0,0:27:40.70,0:27:44.52,Default,,0,0,0,,电平触发器 加法器等等之类的 Dialogue: 0,0:27:45.17,0:27:47.31,Default,,0,0,0,,困难之处在于 Dialogue: 0,0:27:47.45,0:27:50.86,Default,,0,0,0,,就在于需要很多页的文档 Dialogue: 0,0:27:51.20,0:27:52.89,Default,,0,0,0,,来描述这些基本元素 Dialogue: 0,0:27:54.69,0:27:56.74,Default,,0,0,0,,同时它们还有很多的参数 Dialogue: 0,0:27:56.74,0:27:57.98,Default,,0,0,0,,不是只有一个延时这么简单 Dialogue: 0,0:27:58.48,0:28:00.81,Default,,0,0,0,,还有建立时间 维持时间之类的 Dialogue: 0,0:28:01.22,0:28:03.40,Default,,0,0,0,,但是 如果不算上那部分的复杂度 Dialogue: 0,0:28:03.82,0:28:08.20,Default,,0,0,0,,我们用来构建真实计算机的模拟器的结构 Dialogue: 0,0:28:09.08,0:28:12.89,Default,,0,0,0,,跟你们在这里看到的的是一致的 Dialogue: 0,0:28:15.11,0:28:19.27,Default,,0,0,0,,无论如何 这里都是一些简单的东西 Dialogue: 0,0:28:19.27,0:28:22.59,Default,,0,0,0,,像这个 设置非门的延时时间 构建一个 AGENDA Dialogue: 0,0:28:23.03,0:28:25.52,Default,,0,0,0,,我们可以构建一些输入(线路) Dialogue: 0,0:28:26.03,0:28:29.18,Default,,0,0,0,,这里的四条线路分别是:INPUT-1、INPUT-2、SUM和CARRY Dialogue: 0,0:28:29.46,0:28:31.88,Default,,0,0,0,,我将要放置一种被称为“探针”的特殊对象 Dialogue: 0,0:28:32.51,0:28:34.64,Default,,0,0,0,,放在一些线路上 Dialogue: 0,0:28:34.97,0:28:36.24,Default,,0,0,0,,放在SUM和CARRY上 Dialogue: 0,0:28:37.23,0:28:40.56,Default,,0,0,0,,探针是一种对象 它可以 -- Dialogue: 0,0:28:40.70,0:28:43.60,Default,,0,0,0,,当你改变它所附着线路的信号时 Dialogue: 0,0:28:43.72,0:28:44.83,Default,,0,0,0,,它会输出一条消息 Dialogue: 0,0:28:46.12,0:28:46.92,Default,,0,0,0,,这很容易实现 Dialogue: 0,0:28:48.44,0:28:49.52,Default,,0,0,0,,一旦我们设置好它们 Dialogue: 0,0:28:49.55,0:28:51.45,Default,,0,0,0,,当你在放置探针的时候 Dialogue: 0,0:28:51.45,0:28:52.41,Default,,0,0,0,,它首先会输出 Dialogue: 0,0:28:52.67,0:28:56.01,Default,,0,0,0,,SUM在0时刻的值为0 Dialogue: 0,0:28:57.29,0:28:58.43,Default,,0,0,0,,这个我已经注意到了 Dialogue: 0,0:28:59.40,0:29:04.75,Default,,0,0,0,,CARRY在0时刻的值也是0 Dialogue: 0,0:29:06.04,0:29:09.28,Default,,0,0,0,,我们继续来构建更多结构 Dialogue: 0,0:29:09.62,0:29:12.28,Default,,0,0,0,,比如 可以像这里一样构建一种结构 Dialogue: 0,0:29:14.06,0:29:18.20,Default,,0,0,0,,用INPUT-1、INPUT-2、SUM和CARRY组成一个半加器 Dialogue: 0,0:29:18.42,0:29:20.42,Default,,0,0,0,,然后我们把INPUT-1上的信号变为1 Dialogue: 0,0:29:20.62,0:29:21.72,Default,,0,0,0,,然后开始传播 Dialogue: 0,0:29:21.88,0:29:22.84,Default,,0,0,0,,在时刻8的时候 Dialogue: 0,0:29:23.90,0:29:26.12,Default,,0,0,0,,如果你想的话 也可以单步跟踪传播过程 Dialogue: 0,0:29:26.52,0:29:29.20,Default,,0,0,0,,SUM的值变为1 Dialogue: 0,0:29:29.52,0:29:30.44,Default,,0,0,0,,然后就结束了 Dialogue: 0,0:29:31.16,0:29:32.25,Default,,0,0,0,,好像没什么意思 Dialogue: 0,0:29:32.63,0:29:33.90,Default,,0,0,0,,我们还可以设置信号 Dialogue: 0,0:29:34.06,0:29:36.73,Default,,0,0,0,,把INPUT-2也变为1 Dialogue: 0,0:29:36.89,0:29:38.09,Default,,0,0,0,,如果再进行传播 Dialogue: 0,0:29:38.36,0:29:39.95,Default,,0,0,0,,在时刻11 Dialogue: 0,0:29:40.12,0:29:41.42,Default,,0,0,0,,CARRY变为1 Dialogue: 0,0:29:41.55,0:29:44.19,Default,,0,0,0,,在时刻16 SUM变为0 Dialogue: 0,0:29:45.39,0:29:48.99,Default,,0,0,0,,如果你仔细研究那个电路图 Dialogue: 0,0:29:48.99,0:29:50.12,Default,,0,0,0,,它确实是这个结果 Dialogue: 0,0:29:50.62,0:29:51.53,Default,,0,0,0,,也并没有什么特别的 Dialogue: 0,0:29:51.53,0:29:54.12,Default,,0,0,0,,但是却清楚地表明了这一些都是如何运作的 Dialogue: 0,0:30:01.83,0:30:03.29,Default,,0,0,0,,我现在给你们展示的是 Dialogue: 0,0:30:03.48,0:30:05.52,Default,,0,0,0,,一种宏观的图景 Dialogue: 0,0:30:06.60,0:30:08.56,Default,,0,0,0,,你如何在一个很大的规模中 Dialogue: 0,0:30:08.72,0:30:12.04,Default,,0,0,0,,你何去实现某种事件驱动的模拟 Dialogue: 0,0:30:13.29,0:30:14.56,Default,,0,0,0,,你应该如何去组织 Dialogue: 0,0:30:14.88,0:30:16.70,Default,,0,0,0,,来获得良好的层次性结构 Dialogue: 0,0:30:16.99,0:30:21.00,Default,,0,0,0,,使得你可以构建可具体化的抽象盒子 Dialogue: 0,0:30:21.56,0:30:24.96,Default,,0,0,0,,但我还没有告诉你AGENDA是如何运作的 Dialogue: 0,0:30:25.78,0:30:26.54,Default,,0,0,0,,下一小节再说 Dialogue: 0,0:30:28.63,0:30:32.94,Default,,0,0,0,,这将涉及到一些关于数据变化之类的事情 Dialogue: 0,0:30:34.31,0:30:35.86,Default,,0,0,0,,在我继续之前 有什么问题吗? Dialogue: 0,0:30:47.16,0:30:48.24,Default,,0,0,0,,没有的话 那就休息一下 Dialogue: 0,0:30:50.24,0:31:00.62,Default,,0,0,0,,[音乐] Dialogue: 0,0:31:00.62,0:31:06.00,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:31:11.23,0:31:17.69,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:31:17.76,0:31:21.34,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:31:21.34,0:31:25.18,Declare,,0,0,0,,{\an2\fad(500,500)}计算对象 Dialogue: 0,0:31:28.94,0:31:35.06,Default,,0,0,0,,我们已经做了一个模拟器 Dialogue: 0,0:31:35.39,0:31:37.77,Default,,0,0,0,,这是一种事件驱动的模拟 Dialogue: 0,0:31:38.17,0:31:42.75,Default,,0,0,0,,其中 计算机中的对象与现实中的对象一一对应 Dialogue: 0,0:31:43.92,0:31:47.28,Default,,0,0,0,,现实世界中按时发生的状态改变 Dialogue: 0,0:31:47.98,0:31:50.83,Default,,0,0,0,,被组织成了计算机中的时间 Dialogue: 0,0:31:52.99,0:31:56.04,Default,,0,0,0,,如果现实中某件事后于另一件事发生 Dialogue: 0,0:31:56.46,0:31:57.96,Default,,0,0,0,,那么在计算机中 Dialogue: 0,0:31:58.89,0:32:02.25,Default,,0,0,0,,两个事件也保持同样的先后顺序发生 Dialogue: 0,0:32:04.42,0:32:07.16,Default,,0,0,0,,排列这些时间 就是我们要用到赋值的地方 Dialogue: 0,0:32:08.22,0:32:11.21,Default,,0,0,0,,现在我要介绍一种方法来组织时间 Dialogue: 0,0:32:11.80,0:32:14.86,Default,,0,0,0,,AGENDA -- 或者有时候所谓的“优先队列” Dialogue: 0,0:32:16.04,0:32:18.57,Default,,0,0,0,,我们首先需要认识到 Dialogue: 0,0:32:18.62,0:32:21.00,Default,,0,0,0,,为了创建AGENDA 我们需要些什么东西? Dialogue: 0,0:32:28.33,0:32:31.28,Default,,0,0,0,,首先我要在这里写下一些 Dialogue: 0,0:32:31.39,0:32:33.88,Default,,0,0,0,,用于操作AGENDA的基本运算 Dialogue: 0,0:32:35.96,0:32:37.95,Default,,0,0,0,,我不会给出具体代码 Dialogue: 0,0:32:38.14,0:32:39.58,Default,,0,0,0,,因为它们都非常简单 Dialogue: 0,0:32:40.32,0:32:42.60,Default,,0,0,0,,而且你们手上也有 Dialogue: 0,0:32:43.68,0:32:44.38,Default,,0,0,0,,有哪些运算呢? Dialogue: 0,0:32:44.38,0:32:53.50,Default,,0,0,0,,MAKE-AGENDA可以新建一个AGENDA Dialogue: 0,0:32:57.36,0:33:01.77,Default,,0,0,0,,CURRENT-TIME可以获得一个AGENDA的当前时间 Dialogue: 0,0:33:07.47,0:33:12.80,Default,,0,0,0,,返回一个数 -- 也就是当前时间 Dialogue: 0,0:33:16.99,0:33:21.37,Default,,0,0,0,,EMPTY-AGENDA?可用于判断一个AGENDA是否为空 Dialogue: 0,0:33:30.20,0:33:32.57,Default,,0,0,0,,返回TRUE或FALSE Dialogue: 0,0:33:42.72,0:33:44.72,Default,,0,0,0,,我们也可以向AGENDA中添加对象 Dialogue: 0,0:33:52.71,0:33:56.06,Default,,0,0,0,,实际上 向AGENDA中添加的是一个运算 -- 或者说是需要完成的操作 Dialogue: 0,0:33:56.91,0:33:58.14,Default,,0,0,0,,它需要时间TIME Dialogue: 0,0:33:59.63,0:34:00.56,Default,,0,0,0,,待添加的动作ACTION Dialogue: 0,0:34:02.86,0:34:04.64,Default,,0,0,0,,以及AGENDA本身 Dialogue: 0,0:34:07.58,0:34:10.25,Default,,0,0,0,,它把ACTION 放入AGENDA中合适的地方 Dialogue: 0,0:34:10.71,0:34:12.73,Default,,0,0,0,,FIRST-ITEM用于从AGENDA取出第一个事项 Dialogue: 0,0:34:14.24,0:34:15.39,Default,,0,0,0,,那是我首先需要做的事情 Dialogue: 0,0:34:21.84,0:34:23.84,Default,,0,0,0,,该事项是一个动作 Dialogue: 0,0:34:26.46,0:34:28.73,Default,,0,0,0,,我还可以把第一个事项从AGENDA中移除 Dialogue: 0,0:34:29.54,0:34:31.16,Default,,0,0,0,,这是操作AGENDA的一个必要运算 Dialogue: 0,0:34:31.40,0:34:33.02,Default,,0,0,0,,这个运算实现起来非常繁杂 Dialogue: 0,0:34:42.53,0:34:43.36,Default,,0,0,0,,从AGENDA中移除 Dialogue: 0,0:34:45.98,0:34:49.85,Default,,0,0,0,,现在我们来看如何具体组织数据结构 Dialogue: 0,0:34:52.96,0:34:56.04,Default,,0,0,0,,AGENDA应该是一种表 Dialogue: 0,0:34:58.43,0:35:01.20,Default,,0,0,0,,一种可修改的表 Dialogue: 0,0:35:01.57,0:35:04.03,Default,,0,0,0,,因为我们要向其中添加元素 Dialogue: 0,0:35:05.80,0:35:06.89,Default,,0,0,0,,删除元素等等 Dialogue: 0,0:35:07.77,0:35:10.27,Default,,0,0,0,,所以我们需要一种可修改的表 Dialogue: 0,0:35:11.07,0:35:12.51,Default,,0,0,0,,它通过时间组织起来 Dialogue: 0,0:35:13.82,0:35:15.57,Default,,0,0,0,,让它有序 也许会有益处 Dialogue: 0,0:35:18.33,0:35:20.88,Default,,0,0,0,,但是也有可能同一时间会发生很多事 Dialogue: 0,0:35:22.04,0:35:23.42,Default,,0,0,0,,或者说几乎同时 Dialogue: 0,0:35:23.80,0:35:24.72,Default,,0,0,0,,因此我们需要 Dialogue: 0,0:35:24.91,0:35:27.52,Default,,0,0,0,,把它们按发生时间为事件分组 Dialogue: 0,0:35:29.04,0:35:31.61,Default,,0,0,0,,所以我要把AGENDA组织成由SEGMENT构成的表 Dialogue: 0,0:35:32.78,0:35:35.69,Default,,0,0,0,,我来画一下这个结构 Dialogue: 0,0:35:36.68,0:35:37.93,Default,,0,0,0,,方便理解 Dialogue: 0,0:35:39.62,0:35:40.49,Default,,0,0,0,,这是一个AGENDA Dialogue: 0,0:35:41.11,0:35:42.87,Default,,0,0,0,,以一个名字开始 Dialogue: 0,0:35:47.85,0:35:50.19,Default,,0,0,0,,我把它画在表结构的外部 Dialogue: 0,0:35:52.60,0:35:53.39,Default,,0,0,0,,这是它的头部 Dialogue: 0,0:35:54.14,0:35:55.44,Default,,0,0,0,,这个头部的存在也是很必要的 Dialogue: 0,0:35:55.84,0:35:57.63,Default,,0,0,0,,待会你就会知道 Dialogue: 0,0:36:00.68,0:36:03.40,Default,,0,0,0,,再画一个SEGMENT Dialogue: 0,0:36:03.96,0:36:05.62,Default,,0,0,0,,这是一个由SEGMENT构成的表 Dialogue: 0,0:36:08.31,0:36:10.54,Default,,0,0,0,,假设这个AGENDA有两个SEGMENT Dialogue: 0,0:36:11.58,0:36:15.07,Default,,0,0,0,,不断对这个表取CAR即可得到 Dialogue: 0,0:36:16.41,0:36:20.57,Default,,0,0,0,,每个SEGMENT都有一个时间 Dialogue: 0,0:36:24.20,0:36:26.64,Default,,0,0,0,,比如说这里是10 Dialogue: 0,0:36:26.83,0:36:30.51,Default,,0,0,0,,也就是说 这个SEGMENT里的事件发生在10时刻 Dialogue: 0,0:36:33.16,0:36:36.52,Default,,0,0,0,,这里是另外一种数据结构 Dialogue: 0,0:36:36.56,0:36:38.01,Default,,0,0,0,,我先不具体描述 Dialogue: 0,0:36:38.49,0:36:41.08,Default,,0,0,0,,它是一个队列 表示在10时刻要做的事 Dialogue: 0,0:36:42.24,0:36:43.33,Default,,0,0,0,,它是一个队列 Dialogue: 0,0:36:43.33,0:36:44.70,Default,,0,0,0,,一会儿再细说 Dialogue: 0,0:36:45.20,0:36:50.35,Default,,0,0,0,,不过抽象地看 队列就是一系列在固定时间要做的事 Dialogue: 0,0:36:50.40,0:36:52.04,Default,,0,0,0,,我可以向其中添加其它要做的事 Dialogue: 0,0:36:53.10,0:36:53.80,Default,,0,0,0,,这是一个队列 Dialogue: 0,0:36:56.14,0:36:59.11,Default,,0,0,0,,这个是时间 这个是SEGMENT Dialogue: 0,0:37:03.23,0:37:06.36,Default,,0,0,0,,在这个AGENDA中 还有另一个SEGMENT Dialogue: 0,0:37:08.94,0:37:11.20,Default,,0,0,0,,假设它在30时刻发生 Dialogue: 0,0:37:13.50,0:37:15.92,Default,,0,0,0,,类似地 它也有一个队列 Dialogue: 0,0:37:16.92,0:37:20.24,Default,,0,0,0,,里面是在30时刻要去做的事 Dialogue: 0,0:37:23.21,0:37:25.66,Default,,0,0,0,,当然 我们的AGENDA还需要支持其它操作 Dialogue: 0,0:37:27.09,0:37:29.20,Default,,0,0,0,,假设我想将一个在10时刻发生的事 Dialogue: 0,0:37:29.47,0:37:31.61,Default,,0,0,0,,添加到AGENDA中 Dialogue: 0,0:37:33.03,0:37:34.16,Default,,0,0,0,,这并不难 Dialogue: 0,0:37:34.70,0:37:38.65,Default,,0,0,0,,我遍历到这里 找到时刻是10的SEGMENT Dialogue: 0,0:37:39.73,0:37:42.14,Default,,0,0,0,,这样的SEGMENT也可能不存在 Dialogue: 0,0:37:42.93,0:37:44.56,Default,,0,0,0,,一会儿再考虑这种情况 Dialogue: 0,0:37:45.42,0:37:47.56,Default,,0,0,0,,如果我找到了时刻为10的SEGMENT Dialogue: 0,0:37:47.87,0:37:50.43,Default,,0,0,0,,如果我想要把一个事情放入其中 Dialogue: 0,0:37:50.56,0:37:52.16,Default,,0,0,0,,我只要增加该队列即可 Dialogue: 0,0:37:53.85,0:37:56.22,Default,,0,0,0,,这个说起来倒是很容易 Dialogue: 0,0:37:56.57,0:37:59.26,Default,,0,0,0,,我在这里添加需要在那时做的事 Dialogue: 0,0:38:01.43,0:38:04.25,Default,,0,0,0,,现在 假设我想在时刻20做点什么 Dialogue: 0,0:38:05.31,0:38:07.90,Default,,0,0,0,,然而并没有时刻是20的SEGMENT Dialogue: 0,0:38:08.99,0:38:10.64,Default,,0,0,0,,我不得不构造一个新的SEGMENT Dialogue: 0,0:38:11.34,0:38:15.64,Default,,0,0,0,,我想把这个SEGMENT 放在10与30之间 Dialogue: 0,0:38:17.61,0:38:19.32,Default,,0,0,0,,这着实要花点功夫 Dialogue: 0,0:38:20.17,0:38:21.52,Default,,0,0,0,,先用CONS Dialogue: 0,0:38:24.26,0:38:29.94,Default,,0,0,0,,我要为这个AGENDA构建一个新的SEGMENT Dialogue: 0,0:38:33.60,0:38:34.81,Default,,0,0,0,,这里的连接必须要变 Dialogue: 0,0:38:35.40,0:38:36.30,Default,,0,0,0,,就像这样 Dialogue: 0,0:38:37.54,0:38:42.80,Default,,0,0,0,,我将要修改AGENDA的CDR部分的CDR部分 Dialogue: 0,0:38:44.88,0:38:49.45,Default,,0,0,0,,让它指向一个新的CONS单元 Dialogue: 0,0:38:50.11,0:38:54.65,Default,,0,0,0,,由一个新的SEGMENT和AGENDA的CDDDDR部分所构成的单元 Dialogue: 0,0:38:57.18,0:39:01.88,Default,,0,0,0,,我们有一个发生在20时刻的新的SEGMENT Dialogue: 0,0:39:02.30,0:39:03.72,Default,,0,0,0,,它自己维护了一个队列 Dialogue: 0,0:39:04.84,0:39:06.29,Default,,0,0,0,,这个队列中只有一个元素 Dialogue: 0,0:39:10.73,0:39:12.52,Default,,0,0,0,,如果我想在后面添加点什么 Dialogue: 0,0:39:12.54,0:39:15.87,Default,,0,0,0,,我就需要替换这个东西的CDR部分 Dialogue: 0,0:39:16.99,0:39:19.21,Default,,0,0,0,,替换掉这个表的CDR部分 Dialogue: 0,0:39:20.59,0:39:23.31,Default,,0,0,0,,我们就对该数据结构进行修改 Dialogue: 0,0:39:24.04,0:39:25.79,Default,,0,0,0,,因此我需要新的基本运算 Dialogue: 0,0:39:27.21,0:39:28.62,Default,,0,0,0,,因为原有的基础运算达不到这一点 Dialogue: 0,0:39:29.44,0:39:33.88,Default,,0,0,0,,如果我想在5时刻做点什么事 Dialogue: 0,0:39:37.12,0:39:39.20,Default,,0,0,0,,我就得去修改这个东西 Dialogue: 0,0:39:40.81,0:39:42.12,Default,,0,0,0,,因为我得添加到这里 Dialogue: 0,0:39:43.29,0:39:46.22,Default,,0,0,0,,这也就是我预留了一个“头”序对的原因 Dialogue: 0,0:39:47.56,0:39:48.59,Default,,0,0,0,,它预留了空间 Dialogue: 0,0:39:49.40,0:39:52.11,Default,,0,0,0,,我需要有空间去做改变 Dialogue: 0,0:39:53.88,0:39:56.56,Default,,0,0,0,,需要有存储空间 去改变 Dialogue: 0,0:39:58.60,0:40:02.54,Default,,0,0,0,,从AGENDA中删除东西并不困难 Dialogue: 0,0:40:02.54,0:40:04.62,Default,,0,0,0,,移除第一个元素相当容易 Dialogue: 0,0:40:04.92,0:40:06.14,Default,,0,0,0,,这也是我需要考虑的唯一情况 Dialogue: 0,0:40:06.49,0:40:10.19,Default,,0,0,0,,我可以先找到第一个SEGMENT Dialogue: 0,0:40:11.22,0:40:14.00,Default,,0,0,0,,先判断它的队列是否为空 Dialogue: 0,0:40:14.81,0:40:16.17,Default,,0,0,0,,如果队列不是空的 Dialogue: 0,0:40:16.32,0:40:18.62,Default,,0,0,0,,那么 我就会把元素从中删除 Dialogue: 0,0:40:19.21,0:40:19.74,Default,,0,0,0,,像这样 Dialogue: 0,0:40:20.10,0:40:21.92,Default,,0,0,0,,如果这时队列变为空的 Dialogue: 0,0:40:22.64,0:40:24.22,Default,,0,0,0,,就还要继续把SEGMENT删掉 Dialogue: 0,0:40:24.22,0:40:26.49,Default,,0,0,0,,然后 让这个单元指向这里 Dialogue: 0,0:40:28.22,0:40:31.08,Default,,0,0,0,,这个数据结构操作起来很复杂 Dialogue: 0,0:40:32.25,0:40:35.37,Default,,0,0,0,,它的具体实现也不是很有趣 Dialogue: 0,0:40:36.44,0:40:38.48,Default,,0,0,0,,现在我们来探讨一下队列 Dialogue: 0,0:40:38.92,0:40:39.76,Default,,0,0,0,,它们很相似 Dialogue: 0,0:40:41.16,0:40:43.52,Default,,0,0,0,,每一个AGENDA都有一个队列 Dialogue: 0,0:40:44.34,0:40:45.02,Default,,0,0,0,,队列是什么? Dialogue: 0,0:40:49.47,0:40:51.85,Default,,0,0,0,,队列能够进行下述基本运算: Dialogue: 0,0:40:52.78,0:41:02.17,Default,,0,0,0,,MAKE-QUEUE构建一个新队列 Dialogue: 0,0:41:07.77,0:41:17.10,Default,,0,0,0,,INSERT-QUEUE!向队列中插入新元素 Dialogue: 0,0:41:24.51,0:41:28.65,Default,,0,0,0,,DELETE-QUEUE!从队列中删除元素 Dialogue: 0,0:41:40.44,0:41:52.04,Default,,0,0,0,,FRONT-QUEUE查看队列中第一个元素 Dialogue: 0,0:41:53.13,0:41:55.14,Default,,0,0,0,,还需要检测队列是否为空 Dialogue: 0,0:42:07.11,0:42:08.70,Default,,0,0,0,,当你定义像这样的运算时 Dialogue: 0,0:42:09.02,0:42:10.44,Default,,0,0,0,,我希望你能够注意 Dialogue: 0,0:42:10.64,0:42:14.09,Default,,0,0,0,,按照我这样的习惯去为它们命名 Dialogue: 0,0:42:15.12,0:42:19.15,Default,,0,0,0,,“!”表示操作具有副作用 “?”代表定义谓词 Dialogue: 0,0:42:19.87,0:42:21.85,Default,,0,0,0,,就比如说 这里应该加上一个“!” Dialogue: 0,0:42:24.65,0:42:26.96,Default,,0,0,0,,嗯 空检测谓词的“?”也不要遗漏了 Dialogue: 0,0:42:29.24,0:42:30.72,Default,,0,0,0,,那么 我要如何构建一个队列呢? Dialogue: 0,0:42:31.72,0:42:34.11,Default,,0,0,0,,队列是一种 可以向其尾部添加东西 Dialogue: 0,0:42:35.12,0:42:36.83,Default,,0,0,0,,也可以从前面取出东西的结构 Dialogue: 0,0:42:37.84,0:42:40.51,Default,,0,0,0,,我可以从队列头删除元素 向队列尾添加元素 Dialogue: 0,0:42:41.23,0:42:43.24,Default,,0,0,0,,我可以用一种很简单的结构来实现 Dialogue: 0,0:42:43.88,0:42:45.72,Default,,0,0,0,,我们当然可以使用CONS来构造 Dialogue: 0,0:42:47.08,0:42:47.79,Default,,0,0,0,,这是一个队列 Dialogue: 0,0:42:49.91,0:42:52.36,Default,,0,0,0,,它有一个队列头 Dialogue: 0,0:42:53.58,0:42:54.92,Default,,0,0,0,,它包含两个部分 Dialogue: 0,0:42:55.28,0:42:56.25,Default,,0,0,0,,其中一个是头指针 Dialogue: 0,0:42:58.78,0:42:59.82,Default,,0,0,0,,另一个是尾指针 Dialogue: 0,0:43:03.12,0:43:06.33,Default,,0,0,0,,假设我有一个包含两个元素的队列 Dialogue: 0,0:43:09.13,0:43:12.09,Default,,0,0,0,,假设第一个元素是1 Dialogue: 0,0:43:12.46,0:43:16.53,Default,,0,0,0,,而第二个元素假定是2 Dialogue: 0,0:43:21.40,0:43:23.52,Default,,0,0,0,,我之所以要在这里设置两个指针 Dialogue: 0,0:43:24.09,0:43:25.61,Default,,0,0,0,,一个头指针和一个尾指针 Dialogue: 0,0:43:25.72,0:43:27.10,Default,,0,0,0,,这样 当向尾部添加元素的时候 Dialogue: 0,0:43:27.48,0:43:29.45,Default,,0,0,0,,就不用从最开始开始遍历 Dialogue: 0,0:43:31.85,0:43:34.80,Default,,0,0,0,,例如 我想要向队列添加入一个新元素 Dialogue: 0,0:43:35.26,0:43:41.02,Default,,0,0,0,,如果想添加一个稍后使用的元素 Dialogue: 0,0:43:41.08,0:43:42.40,Default,,0,0,0,,只需要先用CONS构建一个序对 Dialogue: 0,0:43:43.47,0:43:46.59,Default,,0,0,0,,假设它包含一个值 -- 3 Dialogue: 0,0:43:47.53,0:43:51.34,Default,,0,0,0,,再添加到队列里 Dialogue: 0,0:43:51.52,0:43:53.77,Default,,0,0,0,,这里就需要把这个元素CDR部分的指针 Dialogue: 0,0:43:56.94,0:43:58.76,Default,,0,0,0,,指向这个元素 Dialogue: 0,0:44:00.10,0:44:04.32,Default,,0,0,0,,同时也更新尾指针 让它指向新的地方 Dialogue: 0,0:44:09.12,0:44:12.68,Default,,0,0,0,,如果我想查看队列的第一个元素 Dialogue: 0,0:44:12.96,0:44:17.12,Default,,0,0,0,,我只需要通过头指针去寻找 即可轻松找到 Dialogue: 0,0:44:18.89,0:44:23.26,Default,,0,0,0,,如果我想调用DELETE-QUEUE删除元素 Dialogue: 0,0:44:24.14,0:44:26.35,Default,,0,0,0,,只需要把头指针向后移到就行 Dialogue: 0,0:44:27.71,0:44:29.31,Default,,0,0,0,,新的头指针指向这里 Dialogue: 0,0:44:31.70,0:44:33.13,Default,,0,0,0,,就是这么简单 Dialogue: 0,0:44:34.48,0:44:35.76,Default,,0,0,0,,为了实现这些操作 Dialogue: 0,0:44:37.24,0:44:40.83,Default,,0,0,0,,我们还需要一些新的基本运算 Dialogue: 0,0:44:41.48,0:44:42.56,Default,,0,0,0,,我先列出它们的名字 Dialogue: 0,0:44:42.99,0:44:46.28,Default,,0,0,0,,然后我们再来看 它们的原理和使用方法 Dialogue: 0,0:44:47.35,0:44:55.04,Default,,0,0,0,,SET-CAR!能够为序对的CAR部分 Dialogue: 0,0:44:55.88,0:44:59.36,Default,,0,0,0,,赋予一个新的值 Dialogue: 0,0:45:02.37,0:45:09.92,Default,,0,0,0,,SET-CDR!可以为序对的CDR部分赋新值 Dialogue: 0,0:45:13.02,0:45:14.78,Default,,0,0,0,,现在来看看它们到底做了什么 Dialogue: 0,0:45:16.03,0:45:20.51,Default,,0,0,0,,为了删除队列中的第一个元素 我需要修改这里的CAR部分 Dialogue: 0,0:45:20.96,0:45:22.52,Default,,0,0,0,,这是CAR部分 我需要修改它的值 Dialogue: 0,0:45:23.47,0:45:24.96,Default,,0,0,0,,我需要能够修改CDR部分 Dialogue: 0,0:45:25.28,0:45:27.08,Default,,0,0,0,,以便我能够移动尾指针 Dialogue: 0,0:45:27.21,0:45:28.76,Default,,0,0,0,,也使得我能够扩充队列 Dialogue: 0,0:45:30.16,0:45:31.60,Default,,0,0,0,,之前介绍的所有运算 Dialogue: 0,0:45:31.90,0:45:35.90,Default,,0,0,0,,上一块黑板上的所有东西 都是基于这些运算的 Dialogue: 0,0:45:38.17,0:45:40.14,Default,,0,0,0,,先讲到这里 大家休息一下 Dialogue: 0,0:45:41.24,0:45:52.67,Default,,0,0,0,,[音乐] Dialogue: 0,0:45:52.67,0:45:57.84,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:46:18.64,0:46:22.80,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:46:22.80,0:46:27.15,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:46:27.16,0:46:30.76,Declare,,0,0,0,,{\an2\fad(500,500)}计算对象 Dialogue: 0,0:46:38.81,0:46:43.53,Default,,0,0,0,,最初 我们说序对是通过CONS构造而来的 Dialogue: 0,0:46:44.57,0:46:46.80,Default,,0,0,0,,我们提到了几条公理 Dialogue: 0,0:46:48.09,0:46:50.76,Default,,0,0,0,,它们是怎样的呢? 它们是形如 -- Dialogue: 0,0:46:52.28,0:47:03.64,Default,,0,0,0,,对于任意的X和Y (CAR (CONS X Y)) = X Dialogue: 0,0:47:05.31,0:47:12.92,Default,,0,0,0,,以及 (CDR (CONS X Y)) = Y Dialogue: 0,0:47:14.80,0:47:20.00,Default,,0,0,0,,但是 它们并没有陈述CONS单元 是否有像人一样的“身份” Dialogue: 0,0:47:21.85,0:47:25.58,Default,,0,0,0,,实际上 它描述的是一种抽象 Dialogue: 0,0:47:25.74,0:47:27.95,Default,,0,0,0,,也就是CONS是由几个部分组成 Dialogue: 0,0:47:29.74,0:47:33.18,Default,,0,0,0,,如果两个CONS组成部分相同的 它俩则是同样的 Dialogue: 0,0:47:33.93,0:47:35.71,Default,,0,0,0,,至少从这些公理来看是这样的 Dialogue: 0,0:47:37.32,0:47:39.21,Default,,0,0,0,,但是引入了赋值以后 Dialogue: 0,0:47:39.84,0:47:42.32,Default,,0,0,0,,实际上 可变数据就是一种赋值 Dialogue: 0,0:47:42.88,0:47:44.43,Default,,0,0,0,,我们有SET-CAR!和SET-CDR! Dialogue: 0,0:47:45.55,0:47:48.94,Default,,0,0,0,,引入这些运算后 这些公理就不完整了 Dialogue: 0,0:47:49.83,0:47:52.03,Default,,0,0,0,,但是这里写的也是对的 Dialogue: 0,0:47:53.25,0:47:54.94,Default,,0,0,0,,只不过描述的不再完整 Dialogue: 0,0:47:56.07,0:48:01.68,Default,,0,0,0,,因为如果我要修改一个特定的CONS的CAR部分 Dialogue: 0,0:48:03.02,0:48:04.03,Default,,0,0,0,,问题是 Dialogue: 0,0:48:04.24,0:48:08.64,Default,,0,0,0,,我会同时修改到相同CONS单元的CAR部分么? Dialogue: 0,0:48:10.09,0:48:13.04,Default,,0,0,0,,假如我用CONS来构建有理数 Dialogue: 0,0:48:14.86,0:48:17.10,Default,,0,0,0,,比如说3/4 Dialogue: 0,0:48:17.34,0:48:20.25,Default,,0,0,0,,假设我有两个3/4 Dialogue: 0,0:48:21.57,0:48:22.75,Default,,0,0,0,,这两个一样吗? Dialogue: 0,0:48:24.06,0:48:24.89,Default,,0,0,0,,或者又不一样? Dialogue: 0,0:48:25.34,0:48:26.96,Default,,0,0,0,,当然 对于数字来说 这并不重要 Dialogue: 0,0:48:27.86,0:48:30.49,Default,,0,0,0,,修改一个数的分母并没有数学意义 Dialogue: 0,0:48:33.02,0:48:35.32,Default,,0,0,0,,我们只能够说创建一个数 具有不同的分母 Dialogue: 0,0:48:36.84,0:48:39.88,Default,,0,0,0,,而直接修改一个数的分母这种观念 Dialogue: 0,0:48:40.00,0:48:43.58,Default,,0,0,0,,在数学意义上是一种非常奇怪而不受支持的行为 Dialogue: 0,0:48:44.77,0:48:47.40,Default,,0,0,0,,然而 当这些CONS单元表示的是现实世界中的事物 Dialogue: 0,0:48:48.97,0:48:50.43,Default,,0,0,0,,那么修改它的CAR部分 Dialogue: 0,0:48:50.60,0:48:52.20,Default,,0,0,0,,就像除掉指甲壳的一块一样 Dialogue: 0,0:48:53.69,0:48:56.56,Default,,0,0,0,,所以 每一个CONS都有自己的“身份” Dialogue: 0,0:48:57.77,0:48:59.92,Default,,0,0,0,,我来先说明“身份”是什么意思 Dialogue: 0,0:49:01.28,0:49:03.05,Default,,0,0,0,,来看些例子 Dialogue: 0,0:49:04.32,0:49:15.20,Default,,0,0,0,,假如(DEFINE A (CONS 1 2)) Dialogue: 0,0:49:18.32,0:49:19.76,Default,,0,0,0,,这是代表什么呢? 首先 Dialogue: 0,0:49:20.67,0:49:25.20,Default,,0,0,0,,这是说我在某个环境中创建了符号A Dialogue: 0,0:49:25.96,0:49:28.67,Default,,0,0,0,,而它的值是一个序对 Dialogue: 0,0:49:29.47,0:49:34.06,Default,,0,0,0,,这个序对由两个分别指向1和2的指针组成 Dialogue: 0,0:49:35.34,0:49:36.16,Default,,0,0,0,,就像这样 Dialogue: 0,0:49:38.12,0:49:39.60,Default,,0,0,0,,又假设 Dialogue: 0,0:49:40.22,0:49:47.58,Default,,0,0,0,,(DEFINE B (CONS A A)) Dialogue: 0,0:49:53.88,0:49:56.81,Default,,0,0,0,,虽然无所谓 不过我还是更喜欢用大写 Dialogue: 0,0:49:57.63,0:49:59.88,Default,,0,0,0,,(DEFINE B (CONS A A)) Dialogue: 0,0:50:03.97,0:50:06.03,Default,,0,0,0,,这里用了两次A Dialogue: 0,0:50:07.84,0:50:10.57,Default,,0,0,0,,现在就要考虑序对的身份问题了 Dialogue: 0,0:50:11.30,0:50:12.64,Default,,0,0,0,,这两个A是同一个东西 Dialogue: 0,0:50:13.69,0:50:14.81,Default,,0,0,0,,这也就是说 Dialogue: 0,0:50:15.29,0:50:17.61,Default,,0,0,0,,我创建了另一个序对 Dialogue: 0,0:50:18.81,0:50:20.20,Default,,0,0,0,,我把它记作B Dialogue: 0,0:50:22.38,0:50:27.60,Default,,0,0,0,,它由两个指向A的指针组成 Dialogue: 0,0:50:28.92,0:50:32.20,Default,,0,0,0,,对于这个对象来说 此时我有三个名字来指称它 Dialogue: 0,0:50:33.10,0:50:34.16,Default,,0,0,0,,A是一个 Dialogue: 0,0:50:34.88,0:50:36.46,Default,,0,0,0,,(CAR B)是一个 Dialogue: 0,0:50:37.23,0:50:38.86,Default,,0,0,0,,(CDR B)也是一个 Dialogue: 0,0:50:39.36,0:50:41.15,Default,,0,0,0,,都是这个序对的别名 Dialogue: 0,0:50:44.23,0:50:49.28,Default,,0,0,0,,假设现在我要执行 Dialogue: 0,0:50:53.77,0:51:08.38,Default,,0,0,0,,(SET-CAR! (CAR B) 3) Dialogue: 0,0:51:12.75,0:51:17.45,Default,,0,0,0,,我先去找B的CAR部分 也就是它 Dialogue: 0,0:51:17.83,0:51:20.93,Default,,0,0,0,,再修改它的CAR部分 修改为3 Dialogue: 0,0:51:24.76,0:51:25.69,Default,,0,0,0,,这样我也就修改了A Dialogue: 0,0:51:27.24,0:51:33.64,Default,,0,0,0,,如果我问 现在A的CAR部分是多少 Dialogue: 0,0:51:35.34,0:51:37.56,Default,,0,0,0,,结果是3 Dialogue: 0,0:51:38.68,0:51:43.39,Default,,0,0,0,,尽管在这里 A是由1和2构成的序对 Dialogue: 0,0:51:45.29,0:51:47.44,Default,,0,0,0,,我通过改变B而改变了A Dialogue: 0,0:51:48.56,0:51:49.64,Default,,0,0,0,,它们之间存在共享 Dialogue: 0,0:51:52.25,0:51:53.47,Default,,0,0,0,,有时候我们需要这样的结构 Dialogue: 0,0:51:54.24,0:51:56.12,Default,,0,0,0,,当然 在类似于队列这类的数据结构中 Dialogue: 0,0:51:56.24,0:52:02.38,Default,,0,0,0,,我们正是这样来定义、组织数据结果来获得数据共享的 Dialogue: 0,0:52:04.35,0:52:05.66,Default,,0,0,0,,但是有一些非预期的共享 Dialogue: 0,0:52:07.76,0:52:09.72,Default,,0,0,0,,对象间的非预期交互 Dialogue: 0,0:52:10.78,0:52:14.08,Default,,0,0,0,,是大型程序中产生的BUG的主要来源 Dialogue: 0,0:52:15.44,0:52:21.66,Default,,0,0,0,,通过使对象具有“身份”、允许共享 Dialogue: 0,0:52:21.87,0:52:23.76,Default,,0,0,0,,给同一个对象取多个别名 Dialogue: 0,0:52:24.08,0:52:25.05,Default,,0,0,0,,我们获得了强大的能力 Dialogue: 0,0:52:25.13,0:52:28.46,Default,,0,0,0,,但是同时也为此引出的BUG和复杂度而付出代价 Dialogue: 0,0:52:32.19,0:52:36.24,Default,,0,0,0,,为了把这个讲透彻一点 我们再举一个例子 Dialogue: 0,0:52:37.10,0:52:39.87,Default,,0,0,0,,比如(CADR B) Dialogue: 0,0:52:42.46,0:52:46.56,Default,,0,0,0,,看起来和(CAR B)没有一点关系 Dialogue: 0,0:52:46.88,0:52:49.02,Default,,0,0,0,,但是它的值是什么? Dialogue: 0,0:52:49.35,0:52:53.56,Default,,0,0,0,,先取B的CDR部分 再取结果的CAR部分 Dialogue: 0,0:52:53.56,0:52:54.86,Default,,0,0,0,,哦 还是3 Dialogue: 0,0:52:56.48,0:53:00.43,Default,,0,0,0,,有了共享这样的机制 局部的含义也不是那么清楚了 Dialogue: 0,0:53:01.12,0:53:02.48,Default,,0,0,0,,所以我们要非常小心的操作 Dialogue: 0,0:53:06.64,0:53:12.64,Default,,0,0,0,,目前为止 我已经介绍了好几个赋值运算 Dialogue: 0,0:53:13.18,0:53:17.61,Default,,0,0,0,,比如SET!、SET-CAR!、SET-CDR! Dialogue: 0,0:53:18.51,0:53:21.39,Default,,0,0,0,,或许我应该不用SET-CAR!、SET-CDR! 它们引入太多问题了 Dialogue: 0,0:53:22.82,0:53:23.66,Default,,0,0,0,,而事实则是 Dialogue: 0,0:53:24.12,0:53:26.11,Default,,0,0,0,,一旦把骆驼的鼻子牵进帐篷 Dialogue: 0,0:53:26.24,0:53:27.34,Default,,0,0,0,,它的身体可就自己跟进来了 Dialogue: 0,0:53:30.16,0:53:31.26,Default,,0,0,0,,只要有SET! Dialogue: 0,0:53:31.61,0:53:35.85,Default,,0,0,0,,这些糟糕的东西都可能发生 Dialogue: 0,0:53:38.55,0:53:39.80,Default,,0,0,0,,我们来分析一下 Dialogue: 0,0:53:40.69,0:53:43.72,Default,,0,0,0,,前些日子 讲到复合数据的时候 Dialogue: 0,0:53:45.13,0:53:51.20,Default,,0,0,0,,哈罗德教授向你们展示了 用消息接收的方式来定义CONS Dialogue: 0,0:53:52.48,0:53:56.06,Default,,0,0,0,,我将给你们展示一种更加糟糕的方式 Dialogue: 0,0:53:57.13,0:54:00.04,Default,,0,0,0,,凭“空”定义CONS Dialogue: 0,0:54:02.56,0:54:03.02,Default,,0,0,0,,“什么”都不用 Dialogue: 0,0:54:04.44,0:54:08.12,Default,,0,0,0,,用传统的函数式的方法如何定义CONS呢? Dialogue: 0,0:54:09.26,0:54:11.66,Default,,0,0,0,,纯粹只用LAMBDA表达式 Dialogue: 0,0:54:13.39,0:54:14.40,Default,,0,0,0,,把序对表示成过程 Dialogue: 0,0:54:17.39,0:54:19.66,Default,,0,0,0,,现在我要修改这个定义 Dialogue: 0,0:54:20.30,0:54:23.16,Default,,0,0,0,,使得只具有一种赋值 Dialogue: 0,0:54:24.28,0:54:27.93,Default,,0,0,0,,用SET!来代替SET-CAR!和SET-CDR! Dialogue: 0,0:54:28.58,0:54:37.39,Default,,0,0,0,,如果我把CONS定义为 Dialogue: 0,0:54:38.91,0:54:42.56,Default,,0,0,0,,定义为一个过程 该过程接收参数M Dialogue: 0,0:54:43.39,0:54:46.32,Default,,0,0,0,,该过程将M应用在X与Y上 Dialogue: 0,0:54:51.12,0:54:53.10,Default,,0,0,0,,这是阿隆佐·丘奇发明的方法 Dialogue: 0,0:54:53.77,0:54:55.72,Default,,0,0,0,,他是20世纪最伟大的程序员 Dialogue: 0,0:54:55.79,0:54:57.15,Default,,0,0,0,,尽管当时电脑还没有被发明 Dialogue: 0,0:54:57.87,0:54:59.13,Default,,0,0,0,,但他在20世纪30年代就提出了这个方法 Dialogue: 0,0:54:59.42,0:55:02.22,Default,,0,0,0,,他是一个逻辑学家 在普林斯顿大学做研究 Dialogue: 0,0:55:08.66,0:55:10.43,Default,,0,0,0,,定义(CAR X)为 Dialogue: 0,0:55:13.10,0:55:16.92,Default,,0,0,0,,把X应用在一个二元过程上 Dialogue: 0,0:55:17.15,0:55:20.60,Default,,0,0,0,,参数分别是A和D 而结果是选出A Dialogue: 0,0:55:23.71,0:55:24.97,Default,,0,0,0,,而(CDR X)则是 Dialogue: 0,0:55:33.10,0:55:34.78,Default,,0,0,0,,这样的一个过程 Dialogue: 0,0:55:35.08,0:55:40.25,Default,,0,0,0,,把X应用在一个参数分别是A和D的过程上 Dialogue: 0,0:55:40.92,0:55:42.04,Default,,0,0,0,,该过程选择出D Dialogue: 0,0:55:46.67,0:55:49.88,Default,,0,0,0,,可能你们还没意识到这些就是CAR、CDR和CONS Dialogue: 0,0:55:50.51,0:55:53.61,Default,,0,0,0,,但我将要给你们演示它符合之前的公理 Dialogue: 0,0:55:54.11,0:55:54.81,Default,,0,0,0,,举一个例子 Dialogue: 0,0:55:55.61,0:55:57.56,Default,,0,0,0,,我们来看一下 Dialogue: 0,0:55:58.29,0:56:06.27,Default,,0,0,0,,考虑一下语句语句(CAR (CONS 35 47)) Dialogue: 0,0:56:09.93,0:56:10.96,Default,,0,0,0,,它的结果是多少呢? Dialogue: 0,0:56:11.12,0:56:15.24,Default,,0,0,0,,它是通过把35和47代换进 Dialogue: 0,0:56:15.37,0:56:18.20,Default,,0,0,0,,语句体中的X和Y得到的 Dialogue: 0,0:56:19.71,0:56:20.69,Default,,0,0,0,,非常容易 Dialogue: 0,0:56:20.69,0:56:30.88,Default,,0,0,0,,就得到了语句(CAR (LAMBDA (M) (M 35 47))) Dialogue: 0,0:56:35.53,0:56:39.36,Default,,0,0,0,,这个的结果是把这个对象 Dialogue: 0,0:56:39.44,0:56:41.85,Default,,0,0,0,,代换进这里的X而得到的 Dialogue: 0,0:56:42.83,0:56:47.66,Default,,0,0,0,,代换的结果是((LAMBDA (M -- Dialogue: 0,0:56:48.33,0:56:52.19,Default,,0,0,0,,用这个对象代换这里的X Dialogue: 0,0:56:52.88,0:56:54.35,Default,,0,0,0,,这是表的头部 Dialogue: 0,0:56:54.88,0:57:00.32,Default,,0,0,0,,体的部分是(M 35 47) Dialogue: 0,0:57:03.10,0:57:07.31,Default,,0,0,0,,把它应用于一个参数分别的A和D的过程上 Dialogue: 0,0:57:07.48,0:57:08.67,Default,,0,0,0,,后者返回参数A Dialogue: 0,0:57:10.91,0:57:14.62,Default,,0,0,0,,然后我们用这个来代换这里的M Dialogue: 0,0:57:15.96,0:57:21.71,Default,,0,0,0,,这个就相当于把(LAMBDA (A D) A) Dialogue: 0,0:57:22.22,0:57:24.84,Default,,0,0,0,,应用在35和47上 Dialogue: 0,0:57:26.33,0:57:27.37,Default,,0,0,0,,结果就是35 Dialogue: 0,0:57:27.40,0:57:31.21,Default,,0,0,0,,它就是用35和47分别代换A、D 最后返回A Dialogue: 0,0:57:35.60,0:57:37.24,Default,,0,0,0,,所以我根本不需要任何数据 Dialogue: 0,0:57:37.88,0:57:38.75,Default,,0,0,0,,甚至连数字都不需要 Dialogue: 0,0:57:40.92,0:57:42.64,Default,,0,0,0,,这就是 阿隆佐·邱奇的技巧 Dialogue: 0,0:57:52.42,0:57:56.17,Default,,0,0,0,,现在呢我们来对这个定义做点修改 Dialogue: 0,0:57:56.76,0:57:58.49,Default,,0,0,0,,作为逻辑学家 他可能会不太开心 Dialogue: 0,0:57:59.20,0:58:01.96,Default,,0,0,0,,但作为程序员 -- 请看投影仪 Dialogue: 0,0:58:03.26,0:58:04.16,Default,,0,0,0,,我们来看看 Dialogue: 0,0:58:05.39,0:58:07.58,Default,,0,0,0,,我修改了CONS的定义 Dialogue: 0,0:58:09.57,0:58:12.35,Default,,0,0,0,,和丘奇的定义很相似 但是不完全相同 Dialogue: 0,0:58:14.41,0:58:15.50,Default,,0,0,0,,具体到底是什么? Dialogue: 0,0:58:16.07,0:58:18.72,Default,,0,0,0,,CONS有两个参数:X和Y Dialogue: 0,0:58:19.50,0:58:22.51,Default,,0,0,0,,但它返回一个参数为M的过程 Dialogue: 0,0:58:23.39,0:58:25.64,Default,,0,0,0,,跟之前一样M会应用于X和Y上 Dialogue: 0,0:58:26.19,0:58:29.29,Default,,0,0,0,,但它额外还有两个“许可” Dialogue: 0,0:58:30.17,0:58:32.01,Default,,0,0,0,,其中一个是把X赋值为N Dialogue: 0,0:58:32.60,0:58:34.40,Default,,0,0,0,,另一个则是把Y赋值为N Dialogue: 0,0:58:34.44,0:58:35.68,Default,,0,0,0,,只要我提供了相应的N Dialogue: 0,0:58:40.94,0:58:44.72,Default,,0,0,0,,所以出了邱奇原本的定义之外 Dialogue: 0,0:58:45.72,0:58:51.66,Default,,0,0,0,,最大的不同在于CONS的返回值 Dialogue: 0,0:58:52.12,0:58:53.82,Default,,0,0,0,,不单会把它的参数应用于 Dialogue: 0,0:58:54.91,0:58:59.44,Default,,0,0,0,,用于构成序对的X和Y之上 Dialogue: 0,0:58:59.69,0:59:03.58,Default,,0,0,0,,它还有用于为X和Y赋值的两个“许可” Dialogue: 0,0:59:06.54,0:59:08.08,Default,,0,0,0,,当然 就如之前一样 Dialogue: 0,0:59:08.83,0:59:10.51,Default,,0,0,0,,CAR看起来也很相似 Dialogue: 0,0:59:11.69,0:59:14.36,Default,,0,0,0,,就像邱奇定义的那样 Dialogue: 0,0:59:14.54,0:59:16.00,Default,,0,0,0,,(CAR X)只不过是把X应用在 Dialogue: 0,0:59:16.86,0:59:19.00,Default,,0,0,0,,过程上 -- 本例中是四个参数 Dialogue: 0,0:59:19.29,0:59:21.04,Default,,0,0,0,,然后从中选出第一个 Dialogue: 0,0:59:22.54,0:59:24.16,Default,,0,0,0,,这就和之前一样 Dialogue: 0,0:59:25.42,0:59:26.96,Default,,0,0,0,,结果将会返回X Dialogue: 0,0:59:29.04,0:59:35.40,Default,,0,0,0,,X的值被包含在求值这个LAMBDA表达式所产生的过程中 Dialogue: 0,0:59:35.45,0:59:37.84,Default,,0,0,0,,X和Y的值也是在这个环境中定义的 Dialogue: 0,0:59:41.94,0:59:43.15,Default,,0,0,0,,这是我们对CONS的定义 Dialogue: 0,0:59:45.64,0:59:47.53,Default,,0,0,0,,那么 激动人心的地方来了 Dialogue: 0,0:59:47.73,0:59:48.96,Default,,0,0,0,,当然CDR的定义也类似 Dialogue: 0,0:59:49.39,0:59:50.35,Default,,0,0,0,,激动人心的地方 Dialogue: 0,0:59:51.23,0:59:52.52,Default,,0,0,0,,SET-CAR!和SET-CDR!的实现 Dialogue: 0,0:59:53.45,0:59:55.52,Default,,0,0,0,,说实话 它们也不是特别复杂 Dialogue: 0,0:59:55.80,1:00:00.64,Default,,0,0,0,,语句(SET-CAR! X Y) Dialogue: 0,1:00:01.63,1:00:03.85,Default,,0,0,0,,无非就是把序对X应用于 Dialogue: 0,1:00:04.11,1:00:06.76,Default,,0,0,0,,注意X是一个一元过程 Dialogue: 0,1:00:07.69,1:00:09.80,Default,,0,0,0,,该过程的体是将参数应用在四个对象上 Dialogue: 0,1:00:11.24,1:00:15.85,Default,,0,0,0,,我们把X应用于一个四元过程上 Dialogue: 0,1:00:16.00,1:00:18.08,Default,,0,0,0,,X的值、Y的值 Dialogue: 0,1:00:18.32,1:00:20.54,Default,,0,0,0,,修改X的许可、修改Y的许可 Dialogue: 0,1:00:21.32,1:00:26.09,Default,,0,0,0,,语句的体则是用相应的许可 将X设置为新的值 Dialogue: 0,1:00:31.65,1:00:33.54,Default,,0,0,0,,当然SET-CDR!和它类似 Dialogue: 0,1:00:36.25,1:00:39.44,Default,,0,0,0,,你也看到了 我这里并没有引入新的基本运算 Dialogue: 0,1:00:40.11,1:00:44.36,Default,,0,0,0,,具体要不要这样来实现是一个工程性问题 Dialogue: 0,1:00:45.34,1:00:47.39,Default,,0,0,0,,当然出于工程上的考量 Dialogue: 0,1:00:48.09,1:00:49.63,Default,,0,0,0,,我不会这样来实现 Dialogue: 0,1:00:51.68,1:00:53.40,Default,,0,0,0,,但是从原理上来说 Dialogue: 0,1:00:54.28,1:00:56.43,Default,,0,0,0,,一旦引入了赋值运算 Dialogue: 0,1:00:56.96,1:00:58.76,Default,,0,0,0,,我就可以进行各种各样的赋值运算了 Dialogue: 0,1:01:05.42,1:01:06.67,Default,,0,0,0,,有什么问题吗? Dialogue: 0,1:01:09.20,1:01:10.89,Default,,0,0,0,,请讲 Dialogue: 0,1:01:12.04,1:01:15.64,Default,,0,0,0,,我可以跟的上你的思路 直到 -- Dialogue: 0,1:01:15.64,1:01:17.61,Default,,0,0,0,,在许可那里 Dialogue: 0,1:01:18.14,1:01:21.64,Default,,0,0,0,,我们把CONS定义为一个参数为N的过程 Dialogue: 0,1:01:21.80,1:01:24.21,Default,,0,0,0,,我不知道这个参数是什么时候传进来的 Dialogue: 0,1:01:24.21,1:01:25.69,Default,,0,0,0,,教授:哦 抱歉 我给你演示一下 Dialogue: 0,1:01:26.34,1:01:27.05,Default,,0,0,0,,我们来推演一下 Dialogue: 0,1:01:27.36,1:01:29.07,Default,,0,0,0,,虽然在黑板上推演更清晰 Dialogue: 0,1:01:29.18,1:01:30.17,Default,,0,0,0,,但这并不难懂 Dialogue: 0,1:01:30.17,1:01:31.47,Default,,0,0,0,,我就将就用投影仪了 Dialogue: 0,1:01:32.45,1:01:35.79,Default,,0,0,0,,调用(SET-CDR! X Y)会发生什么呢? Dialogue: 0,1:01:37.79,1:01:39.66,Default,,0,0,0,,就在这里(SET-CDR! X Y) Dialogue: 0,1:01:40.36,1:01:41.92,Default,,0,0,0,,X可能是一个序对 Dialogue: 0,1:01:43.31,1:01:45.24,Default,,0,0,0,,或者说对一个CONS表达式求值得到的结果 Dialogue: 0,1:01:45.88,1:01:46.35,Default,,0,0,0,,能跟上吧? Dialogue: 0,1:01:46.89,1:01:49.96,Default,,0,0,0,,也就是说 X是由这里的代码构造出来的 Dialogue: 0,1:01:52.57,1:01:56.49,Default,,0,0,0,,这里的X是求值这个LAMBDA表达式得到的 Dialogue: 0,1:01:58.11,1:01:58.49,Default,,0,0,0,,对吧 Dialogue: 0,1:01:59.38,1:02:01.63,Default,,0,0,0,,因此当我对这个LAMBDA表达式求值时 Dialogue: 0,1:02:04.01,1:02:08.76,Default,,0,0,0,,我是在定义CONS时的一个环境里求值的 Dialogue: 0,1:02:11.75,1:02:15.18,Default,,0,0,0,,这也就是说 作为LAMBDA表达式中的自由变量 Dialogue: 0,1:02:16.25,1:02:18.68,Default,,0,0,0,,X和Y都存储一个框架中 Dialogue: 0,1:02:18.72,1:02:22.44,Default,,0,0,0,,也就是这整个LAMBDA表达式的父框架 Dialogue: 0,1:02:23.23,1:02:25.82,Default,,0,0,0,,因此在这个LAMBDA语句中 Dialogue: 0,1:02:26.65,1:02:28.51,Default,,0,0,0,,X和Y都有存储空间 Dialogue: 0,1:02:29.25,1:02:30.83,Default,,0,0,0,,也可以对它们赋值 Dialogue: 0,1:02:31.91,1:02:36.08,Default,,0,0,0,,这里赋值为N是通过参数来传递的 Dialogue: 0,1:02:37.26,1:02:39.31,Default,,0,0,0,,“许可”就是一个过程 Dialogue: 0,1:02:41.40,1:02:43.18,Default,,0,0,0,,它将作为M的一个参数 Dialogue: 0,1:02:43.29,1:02:46.51,Default,,0,0,0,,它实际上是CONS生成的对象的一部分 Dialogue: 0,1:02:47.94,1:02:50.91,Default,,0,0,0,,我们再来看看SET-CDR! Dialogue: 0,1:02:52.11,1:02:55.42,Default,,0,0,0,,SET-CDR!的第一个参数X是一个序对 Dialogue: 0,1:02:56.12,1:02:57.48,Default,,0,0,0,,被传递了一个参数 Dialogue: 0,1:02:59.77,1:03:02.22,Default,,0,0,0,,这个是一个四元过程 Dialogue: 0,1:03:02.32,1:03:04.65,Default,,0,0,0,,这是因为 它要作为这里的M Dialogue: 0,1:03:04.99,1:03:06.56,Default,,0,0,0,,要应用在四个对象上 Dialogue: 0,1:03:07.92,1:03:13.34,Default,,0,0,0,,这边的这个SD 就对应于这个过程 Dialogue: 0,1:03:15.47,1:03:19.93,Default,,0,0,0,,当我执行SD 把它应用于Y Dialogue: 0,1:03:22.91,1:03:24.04,Default,,0,0,0,,这个Y是这里传过来的 Dialogue: 0,1:03:25.37,1:03:26.92,Default,,0,0,0,,学生:那-- Dialogue: 0,1:03:27.00,1:03:32.19,Default,,0,0,0,,教授:所以说 这里的N就对应于这里的Y Dialogue: 0,1:03:34.04,1:03:34.52,Default,,0,0,0,,明白了吧 Dialogue: 0,1:03:34.81,1:03:35.75,Default,,0,0,0,,了解了 Dialogue: 0,1:03:35.75,1:03:37.29,Default,,0,0,0,,当你执行SET-CDR!的时候 Dialogue: 0,1:03:39.07,1:03:41.97,Default,,0,0,0,,X是CDR部分要赋值的新值 Dialogue: 0,1:03:41.97,1:03:44.03,Default,,0,0,0,,教授:这里的X Dialogue: 0,1:03:44.96,1:03:46.20,Default,,0,0,0,,哦 指错了 Dialogue: 0,1:03:46.20,1:03:48.33,Default,,0,0,0,,这里的X是指 -- SET-CDR!有两个参数 Dialogue: 0,1:03:48.91,1:03:50.36,Default,,0,0,0,,一个是被修改的序对 Dialogue: 0,1:03:51.34,1:03:53.93,Default,,0,0,0,,还有就是新值 Dialogue: 0,1:03:56.15,1:03:58.32,Default,,0,0,0,,你可以代换回去看看 就很清楚了 Dialogue: 0,1:04:02.17,1:04:03.16,Default,,0,0,0,,还有什么问题吗? Dialogue: 0,1:04:07.88,1:04:08.64,Default,,0,0,0,,好的 Dialogue: 0,1:04:08.64,1:04:09.52,Default,,0,0,0,,这节课就到这里 Dialogue: 0,1:04:10.44,1:04:28.73,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:04:10.44,1:04:28.73,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec5b.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 974 Video Position: 116001 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.01,0:00:02.46,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N张大伟\N(DreamAndDead) Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:10.10,0:00:14.60,Declare,,0,0,0,,{\an2\fad(500,500)}计算对象 Dialogue: 0,0:00:21.17,0:00:24.12,Default,,0,0,0,,现在我们已经学习了 Dialogue: 0,0:00:24.43,0:00:27.40,Default,,0,0,0,,如何创建局部状态和如何建模对象 Dialogue: 0,0:00:28.33,0:00:32.67,Default,,0,0,0,,我想我们应该找点复杂的东西 Dialogue: 0,0:00:34.03,0:00:36.36,Default,,0,0,0,,来实践一下学过的这些知识 Dialogue: 0,0:00:40.43,0:00:43.48,Default,,0,0,0,,我可以这么说 假设我们处在现实世界中 Dialogue: 0,0:00:44.11,0:00:46.25,Default,,0,0,0,,我们把这个世界看作是 Dialogue: 0,0:00:46.99,0:00:51.08,Default,,0,0,0,,由许多的事物构成的 Dialogue: 0,0:00:52.06,0:00:55.98,Default,,0,0,0,,每个事物都有其独立的局部状态 Dialogue: 0,0:00:57.24,0:00:59.87,Default,,0,0,0,,正是这些独立的状态使其成为事物 Dialogue: 0,0:01:01.28,0:01:04.27,Default,,0,0,0,,因此我们说 在这个世界的模型中 Dialogue: 0,0:01:04.28,0:01:09.90,Default,,0,0,0,,我们在大脑中和计算机中对那个世界建模 Dialogue: 0,0:01:10.94,0:01:12.54,Default,,0,0,0,,我想要建立一种对应关系 Dialogue: 0,0:01:12.78,0:01:15.21,Default,,0,0,0,,把现实世界和计算机中的对象联系起来 Dialogue: 0,0:01:15.87,0:01:17.74,Default,,0,0,0,,把现实世界中对象间的关系 Dialogue: 0,0:01:17.96,0:01:21.72,Default,,0,0,0,,与计算机中的模型对象间的关系 对应起来 Dialogue: 0,0:01:23.18,0:01:25.52,Default,,0,0,0,,把现实世界中关联对象的函数 Dialogue: 0,0:01:25.93,0:01:28.11,Default,,0,0,0,,与计算机中的函数 对应起来 Dialogue: 0,0:01:30.84,0:01:33.82,Default,,0,0,0,,这让我们获得了模块性 Dialogue: 0,0:01:34.74,0:01:36.75,Default,,0,0,0,,如果我们认为现实世界是像那样的 Dialogue: 0,0:01:37.36,0:01:38.72,Default,,0,0,0,,也就是由许多小的事物构成的 Dialogue: 0,0:01:39.20,0:01:41.47,Default,,0,0,0,,当然 我们可以把世界安排成那样 Dialogue: 0,0:01:42.03,0:01:43.95,Default,,0,0,0,,我们只能对像那样的事物建模 Dialogue: 0,0:01:45.45,0:01:49.02,Default,,0,0,0,,这样 我们的程序就可以从现实世界中继承模块化 Dialogue: 0,0:01:50.45,0:01:53.58,Default,,0,0,0,,这就是发明面向对象编程的初衷 Dialogue: 0,0:01:55.42,0:01:58.19,Default,,0,0,0,,我所见过的最完美的对象(系统) Dialogue: 0,0:01:58.89,0:02:04.17,Default,,0,0,0,,电气系统 就是非常非常完美的对象系统 Dialogue: 0,0:02:06.40,0:02:12.99,Default,,0,0,0,,电气系统真的是物理学家构造的非常非常好的一种对象 Dialogue: 0,0:02:14.22,0:02:16.76,Default,,0,0,0,,这里 我有一些机器零件 Dialogue: 0,0:02:17.12,0:02:18.28,Default,,0,0,0,,就是这些零件 Dialogue: 0,0:02:20.04,0:02:22.88,Default,,0,0,0,,有一个电线连接起了 Dialogue: 0,0:02:23.66,0:02:26.40,Default,,0,0,0,,零件的两个部分 Dialogue: 0,0:02:27.56,0:02:30.86,Default,,0,0,0,,电气世界中 有一个非常棒的特性 Dialogue: 0,0:02:31.64,0:02:33.12,Default,,0,0,0,,就是我可以说这是一个对象 Dialogue: 0,0:02:34.01,0:02:34.97,Default,,0,0,0,,这又是一个对象 Dialogue: 0,0:02:35.71,0:02:37.53,Default,,0,0,0,,它们间的关联一目了然 Dialogue: 0,0:02:38.24,0:02:43.32,Default,,0,0,0,,而且 如果我没有用电线连接 它们便没有关联 Dialogue: 0,0:02:44.74,0:02:46.12,Default,,0,0,0,,比如我有一个灯泡 Dialogue: 0,0:02:46.52,0:02:50.32,Default,,0,0,0,,一个灯泡和一个已经接在插座上的电源 Dialogue: 0,0:02:51.63,0:02:53.53,Default,,0,0,0,,关联非常明了 Dialogue: 0,0:02:53.62,0:02:55.42,Default,,0,0,0,,这就是已知所有的连接方式了 Dialogue: 0,0:02:56.22,0:03:02.33,Default,,0,0,0,,就算我把连接电灯和电源的电线打个结 Dialogue: 0,0:03:02.68,0:03:03.64,Default,,0,0,0,,灯仍然是亮的 Dialogue: 0,0:03:04.04,0:03:04.76,Default,,0,0,0,,没什么影响 Dialogue: 0,0:03:07.44,0:03:12.40,Default,,0,0,0,,物理学上这样安排 可以使连接变成抽象的 Dialogue: 0,0:03:13.08,0:03:15.27,Default,,0,0,0,,至少在低频状态下是可以的 Dialogue: 0,0:03:17.84,0:03:20.88,Default,,0,0,0,,而且这就是全部的关联方式了 Dialogue: 0,0:03:22.35,0:03:23.87,Default,,0,0,0,,当然 我们来进一步 Dialogue: 0,0:03:23.90,0:03:27.31,Default,,0,0,0,,讨论一种在电气系统中最为广泛的抽象 Dialogue: 0,0:03:27.85,0:03:29.42,Default,,0,0,0,,数字电路 Dialogue: 0,0:03:31.69,0:03:33.66,Default,,0,0,0,,这里有一些对象 Dialogue: 0,0:03:34.64,0:03:40.12,Default,,0,0,0,,例如 在数字电路里中 我们有非门 Dialogue: 0,0:03:41.39,0:03:42.78,Default,,0,0,0,,有与门 Dialogue: 0,0:03:43.99,0:03:45.40,Default,,0,0,0,,还有或门 Dialogue: 0,0:03:47.21,0:03:50.12,Default,,0,0,0,,我们用一种特殊的“电线” 把它们连接起来 Dialogue: 0,0:03:52.00,0:03:54.94,Default,,0,0,0,,这些“电线”代表抽象信号 Dialogue: 0,0:03:55.61,0:03:57.18,Default,,0,0,0,,我们不关心具体的物理因素 Dialogue: 0,0:03:57.21,0:03:59.72,Default,,0,0,0,,像电压、电流或者组合因素等 Dialogue: 0,0:04:00.01,0:04:03.44,Default,,0,0,0,,又或者是水压 等等 Dialogue: 0,0:04:05.20,0:04:07.32,Default,,0,0,0,,这些抽象变量代表某类信号 Dialogue: 0,0:04:09.42,0:04:12.89,Default,,0,0,0,,我们用电路连接元件 构建系统 Dialogue: 0,0:04:14.07,0:04:16.22,Default,,0,0,0,,现在 我要向你们介绍一门新的语言 Dialogue: 0,0:04:17.63,0:04:20.17,Default,,0,0,0,,我们要构建一门内嵌于Lisp中的语言 Dialogue: 0,0:04:22.14,0:04:25.08,Default,,0,0,0,,这是一种内部DSL 是类似于之前讲过的图形语言那种 Dialogue: 0,0:04:26.16,0:04:27.32,Default,,0,0,0,,而不是昨天那种 Dialogue: 0,0:04:27.88,0:04:31.61,Default,,0,0,0,,那种模式匹配语言 -- 那是外部DSL Dialogue: 0,0:04:32.80,0:04:36.30,Default,,0,0,0,,模式匹配语言是由Lisp程序所解释的 Dialogue: 0,0:04:38.16,0:04:40.52,Default,,0,0,0,,而之前那种图形语言 Dialogue: 0,0:04:40.56,0:04:44.27,Default,,0,0,0,,是在Lisp中构造我们想要的过程 来封装图形结构 Dialogue: 0,0:04:45.48,0:04:46.75,Default,,0,0,0,,举例来说 Dialogue: 0,0:04:47.72,0:04:50.64,Default,,0,0,0,,首先我要有一些基本对象 Dialogue: 0,0:04:51.05,0:04:52.12,Default,,0,0,0,,比如这个和这个 Dialogue: 0,0:04:53.50,0:04:55.18,Default,,0,0,0,,然后用电线去组合它们 Dialogue: 0,0:04:55.98,0:04:59.37,Default,,0,0,0,,我用(MAKE-WIRE)来构造一个电线 Dialogue: 0,0:04:59.87,0:05:01.24,Default,,0,0,0,,A就代表了一根电线 Dialogue: 0,0:05:01.74,0:05:02.69,Default,,0,0,0,,B也是 Dialogue: 0,0:05:02.69,0:05:03.46,Default,,0,0,0,,C也是 Dialogue: 0,0:05:03.46,0:05:04.23,Default,,0,0,0,,D也是 Dialogue: 0,0:05:04.23,0:05:04.83,Default,,0,0,0,,还有E Dialogue: 0,0:05:04.83,0:05:05.64,Default,,0,0,0,,S也是 Dialogue: 0,0:05:06.88,0:05:12.75,Default,,0,0,0,,而或门有两个输入 分别是A和B Dialogue: 0,0:05:13.16,0:05:14.75,Default,,0,0,0,,它的输出是D Dialogue: 0,0:05:15.07,0:05:16.12,Default,,0,0,0,,我们用这样的记号来表示 Dialogue: 0,0:05:18.14,0:05:22.14,Default,,0,0,0,,与门 输入是A和B 输出是C Dialogue: 0,0:05:22.22,0:05:23.24,Default,,0,0,0,,我们这样表示 Dialogue: 0,0:05:24.82,0:05:28.46,Default,,0,0,0,,通过一系列像这样的声明 Dialogue: 0,0:05:29.29,0:05:31.64,Default,,0,0,0,,我可以组合出任意的电路 Dialogue: 0,0:05:32.75,0:05:34.64,Default,,0,0,0,,我已经告诉了你们创建数字电路 Dialogue: 0,0:05:35.31,0:05:38.51,Default,,0,0,0,,的基本元素和组合方法了 Dialogue: 0,0:05:40.09,0:05:43.04,Default,,0,0,0,,然后就该说抽象的方法了 Dialogue: 0,0:05:43.69,0:05:52.24,Default,,0,0,0,,举例来说 这是一个半加器 Dialogue: 0,0:05:52.67,0:05:55.55,Default,,0,0,0,,如果你学过电路设计肯定知道这个东西 Dialogue: 0,0:05:56.93,0:06:00.44,Default,,0,0,0,,输入两个数A和B Dialogue: 0,0:06:00.62,0:06:02.12,Default,,0,0,0,,输出两者之和以及进位 Dialogue: 0,0:06:04.35,0:06:06.80,Default,,0,0,0,,事实上 完全可以用我刚刚说的来组合电路 Dialogue: 0,0:06:07.45,0:06:10.99,Default,,0,0,0,,盒子外面 半加器盒子的外面有一些接口 Dialogue: 0,0:06:11.13,0:06:14.11,Default,,0,0,0,,这些盒子的边界 我们总是抽象成盒子 Dialogue: 0,0:06:14.79,0:06:19.70,Default,,0,0,0,,从盒子里引出A、B、S、C四根线 Dialogue: 0,0:06:19.70,0:06:21.79,Default,,0,0,0,,这些是已经声明了的变量 Dialogue: 0,0:06:23.39,0:06:26.25,Default,,0,0,0,,由LAMBDA表达式声明的几个变量 Dialogue: 0,0:06:26.28,0:06:28.01,Default,,0,0,0,,定义了这个半加器 Dialogue: 0,0:06:31.40,0:06:35.96,Default,,0,0,0,,在盒子的内部 我构造了电线D和E Dialogue: 0,0:06:36.00,0:06:37.44,Default,,0,0,0,,这是为了连接内部结构 Dialogue: 0,0:06:37.74,0:06:40.40,Default,,0,0,0,,这条是E 这条是D Dialogue: 0,0:06:41.32,0:06:43.50,Default,,0,0,0,,内部连接的线路并没有引出盒子之外 Dialogue: 0,0:06:45.05,0:06:46.83,Default,,0,0,0,,就像电路图那样连起来 Dialogue: 0,0:06:48.79,0:06:50.89,Default,,0,0,0,,大家可以看得出来 Dialogue: 0,0:06:51.05,0:06:53.02,Default,,0,0,0,,这个语言非常有层次性 Dialogue: 0,0:06:53.85,0:06:55.71,Default,,0,0,0,,如果一门语言没有层次性 Dialogue: 0,0:06:55.95,0:06:59.96,Default,,0,0,0,,如果你不能把一个复合对象当成基本对象来使用 Dialogue: 0,0:07:00.38,0:07:01.53,Default,,0,0,0,,这门语言肯定是有问题的 Dialogue: 0,0:07:02.59,0:07:04.22,Default,,0,0,0,,至少我是这么认为的 Dialogue: 0,0:07:06.41,0:07:09.58,Default,,0,0,0,,之前 我们都是在研究数学函数 Dialogue: 0,0:07:09.60,0:07:11.12,Default,,0,0,0,,或者是计算数学函数的东西 Dialogue: 0,0:07:11.15,0:07:12.65,Default,,0,0,0,,这些都是我们之前研究的东西 Dialogue: 0,0:07:13.85,0:07:16.65,Default,,0,0,0,,而我们现在 Dialogue: 0,0:07:16.67,0:07:17.63,Default,,0,0,0,,不这么做了 Dialogue: 0,0:07:17.85,0:07:20.88,Default,,0,0,0,,我们从一些电气对象开始 Dialogue: 0,0:07:21.04,0:07:22.64,Default,,0,0,0,,构建更多的对象 Dialogue: 0,0:07:23.35,0:07:28.83,Default,,0,0,0,,我们用Lisp里的LAMBDA将其粘合起来 Dialogue: 0,0:07:30.38,0:07:32.93,Default,,0,0,0,,“LAMBDA: 终极之粘合剂” Dialogue: 0,0:07:33.32,0:07:36.35,Default,,0,0,0,,当然 半加器可以用于 Dialogue: 0,0:07:37.64,0:07:41.04,Default,,0,0,0,,构造一种更复杂的抽象结构 -- 全加器 Dialogue: 0,0:07:41.60,0:07:45.05,Default,,0,0,0,,如这里所示 全加器由两个半加器构成 Dialogue: 0,0:07:45.47,0:07:47.87,Default,,0,0,0,,用一些额外的电线连接起来 Dialogue: 0,0:07:48.08,0:07:51.29,Default,,0,0,0,,就像这里所示的S、C1、C2以及一个或门 Dialogue: 0,0:07:52.19,0:07:53.60,Default,,0,0,0,,而对于一个全加器 Dialogue: 0,0:07:53.87,0:08:00.78,Default,,0,0,0,,它的输入有:两个待加的数 一个进位值 Dialogue: 0,0:08:01.36,0:08:04.17,Default,,0,0,0,,输出是:两数之和以及进位 Dialogue: 0,0:08:05.90,0:08:10.70,Default,,0,0,0,,构建好全加器以后 还可以把它们链起来组成更大的加法器 Dialogue: 0,0:08:12.99,0:08:14.83,Default,,0,0,0,,现在我们有了一门完整的语言 Dialogue: 0,0:08:16.06,0:08:21.76,Default,,0,0,0,,它有基本元素、组合方法以及抽象方法 Dialogue: 0,0:08:22.27,0:08:23.36,Default,,0,0,0,,现在 我们怎样实现这门语言? Dialogue: 0,0:08:25.00,0:08:26.84,Default,,0,0,0,,其实并不难 Dialogue: 0,0:08:27.07,0:08:27.96,Default,,0,0,0,,首先来看基本元素 Dialogue: 0,0:08:28.12,0:08:30.11,Default,,0,0,0,,这是唯一的问题 Dialogue: 0,0:08:31.16,0:08:32.56,Default,,0,0,0,,不需要再做其它事情了 Dialogue: 0,0:08:33.74,0:08:38.00,Default,,0,0,0,,因为我们直接借用了Lisp中的组合方法以及抽象方法 Dialogue: 0,0:08:39.96,0:08:41.88,Default,,0,0,0,,我们的语言 继承自Lisp并内嵌于其中 Dialogue: 0,0:08:43.77,0:08:45.44,Default,,0,0,0,,好 我们先来看一个基本元素 Dialogue: 0,0:08:45.86,0:08:47.40,Default,,0,0,0,,就拿非门来说吧 Dialogue: 0,0:08:51.54,0:08:54.67,Default,,0,0,0,,非门有两个引脚 分别是输入和输出 Dialogue: 0,0:08:57.31,0:09:02.62,Default,,0,0,0,,它要对输入信号做出响应 Dialogue: 0,0:09:04.30,0:09:07.00,Default,,0,0,0,,它需要对输入电线说 -- Dialogue: 0,0:09:07.64,0:09:10.14,Default,,0,0,0,,我们现在把它们视作对象 Dialogue: 0,0:09:10.44,0:09:12.41,Default,,0,0,0,,其具体细节我们稍后讨论 Dialogue: 0,0:09:13.23,0:09:14.84,Default,,0,0,0,,它对其输入电线的说 Dialogue: 0,0:09:15.82,0:09:18.48,Default,,0,0,0,,“当你的值变发生改变时 告诉我一声” Dialogue: 0,0:09:20.12,0:09:22.11,Default,,0,0,0,,所以非门这个对象 Dialogue: 0,0:09:22.41,0:09:24.38,Default,,0,0,0,,会对输入电线这个对象说 -- Dialogue: 0,0:09:25.13,0:09:26.40,Default,,0,0,0,,“Hi 我是George” Dialogue: 0,0:09:26.87,0:09:31.02,Default,,0,0,0,,“我的工作就是 对你的变化做出响应” Dialogue: 0,0:09:31.72,0:09:34.19,Default,,0,0,0,,“所以当你变化的时候 告诉我一声” Dialogue: 0,0:09:34.73,0:09:35.72,Default,,0,0,0,,“这样我才能进一步的处理” Dialogue: 0,0:09:36.88,0:09:40.30,Default,,0,0,0,,这是通过在这里 在输入电线上 Dialogue: 0,0:09:41.40,0:09:44.64,Default,,0,0,0,,添加一个叫做INVERT-IN的动作来实现的 Dialogue: 0,0:09:45.07,0:09:46.94,Default,,0,0,0,,INVERT-IN在这里定义 Dialogue: 0,0:09:47.05,0:09:48.76,Default,,0,0,0,,它是一个无参过程 Dialogue: 0,0:09:49.98,0:09:54.59,Default,,0,0,0,,它将线路上的信号逻辑取反 Dialogue: 0,0:09:56.06,0:09:58.64,Default,,0,0,0,,经过一段时长为INVERTER-DELAT的延时以后 -- Dialogue: 0,0:09:59.26,0:10:01.15,Default,,0,0,0,,每个电路对象都有延时 -- Dialogue: 0,0:10:02.88,0:10:04.46,Default,,0,0,0,,然后我们会 -- Dialogue: 0,0:10:04.67,0:10:07.14,Default,,0,0,0,,我们再把输出设置为新的值 Dialogue: 0,0:10:10.16,0:10:11.36,Default,,0,0,0,,非常简单 Dialogue: 0,0:10:12.40,0:10:15.28,Default,,0,0,0,,你可以想象输出电线也同样是信号敏感的 Dialogue: 0,0:10:15.77,0:10:18.27,Default,,0,0,0,,当信号改变的时候 Dialogue: 0,0:10:19.28,0:10:21.15,Default,,0,0,0,,它会“告知”其它对象 Dialogue: 0,0:10:21.79,0:10:24.78,Default,,0,0,0,,“快醒醒!我的值已经改变啦” Dialogue: 0,0:10:26.05,0:10:30.14,Default,,0,0,0,,所以当你把非门和与门或者元件连在一起的时候 Dialogue: 0,0:10:30.46,0:10:32.20,Default,,0,0,0,,它们之间将会有大量的通信 Dialogue: 0,0:10:32.86,0:10:35.07,Default,,0,0,0,,以确保信号正确地传播 Dialogue: 0,0:10:36.81,0:10:38.62,Default,,0,0,0,,到目前为止 没什么新奇的东西 Dialogue: 0,0:10:38.62,0:10:40.72,Default,,0,0,0,,我们只是针对某个特定的表示法 Dialogue: 0,0:10:40.72,0:10:45.24,Default,,0,0,0,,也就是这个例子中的1、0 -- 实现了LOGICAL-NOT而已 Dialogue: 0,0:10:46.73,0:10:49.16,Default,,0,0,0,,与门就相对复杂一些 Dialogue: 0,0:10:49.78,0:10:55.80,Default,,0,0,0,,与门有两个输入A1和A2 输出是OUTPUT Dialogue: 0,0:10:56.73,0:11:00.64,Default,,0,0,0,,但是其结构和非门没有什么大的不同 Dialogue: 0,0:11:00.86,0:11:03.44,Default,,0,0,0,,只不过是 当输入信号改变的时候 Dialogue: 0,0:11:04.52,0:11:09.07,Default,,0,0,0,,与门调用的是AND-ACTION过程罢了 Dialogue: 0,0:11:10.91,0:11:12.88,Default,,0,0,0,,当然 它所做的只是 Dialogue: 0,0:11:12.91,0:11:15.37,Default,,0,0,0,,对输入信号进行逻辑“与”运算 Dialogue: 0,0:11:16.19,0:11:18.76,Default,,0,0,0,,在经过AND-GATE-DELAY的延时之后 Dialogue: 0,0:11:20.46,0:11:24.36,Default,,0,0,0,,调用这个过程 更新输出信号值 Dialogue: 0,0:11:25.47,0:11:28.35,Default,,0,0,0,,那么 我们如何用“按愿望思维”来构造这一切呢? Dialogue: 0,0:11:28.35,0:11:31.08,Default,,0,0,0,,如大家所见 这里有一个赋值运算 Dialogue: 0,0:11:32.02,0:11:32.78,Default,,0,0,0,,但并不是SET! Dialogue: 0,0:11:34.57,0:11:36.78,Default,,0,0,0,,这是一个派生出来的运算 Dialogue: 0,0:11:36.78,0:11:38.73,Default,,0,0,0,,就像可以从CAR和CDR派生出其它函数一样 Dialogue: 0,0:11:40.80,0:11:44.81,Default,,0,0,0,,因此 按照约定 我加上“!”(表示这个过程有副作用) Dialogue: 0,0:11:46.34,0:11:49.18,Default,,0,0,0,,这里有个过程ADD-ACTION! Dialogue: 0,0:11:49.44,0:11:54.67,Default,,0,0,0,,它用来提醒与门中的局部线路A1 Dialogue: 0,0:11:55.63,0:11:58.68,Default,,0,0,0,,当它改变的时候记得执行过程AND-ACTION-PROCEDURE Dialogue: 0,0:11:59.58,0:12:02.91,Default,,0,0,0,,A2也是一样 Dialogue: 0,0:12:06.31,0:12:07.23,Default,,0,0,0,,非常简单 Dialogue: 0,0:12:09.96,0:12:12.09,Default,,0,0,0,,现在我们再来看看 Dialogue: 0,0:12:12.70,0:12:16.12,Default,,0,0,0,,各部分间是如何通信的 Dialogue: 0,0:12:18.54,0:12:19.66,Default,,0,0,0,,例如 Dialogue: 0,0:12:23.12,0:12:24.27,Default,,0,0,0,,有一个非常简单的电路 Dialogue: 0,0:12:24.27,0:12:30.46,Default,,0,0,0,,它有一个与门 带有两个输入A、B Dialogue: 0,0:12:31.92,0:12:38.00,Default,,0,0,0,,与门通过电线C跟非门相连 Dialogue: 0,0:12:39.72,0:12:41.53,Default,,0,0,0,,非门的输出是D Dialogue: 0,0:12:44.20,0:12:47.34,Default,,0,0,0,,这就是物理世界 Dialogue: 0,0:12:47.36,0:12:49.02,Default,,0,0,0,,一个对物理世界的抽象 Dialogue: 0,0:12:49.86,0:12:53.40,Default,,0,0,0,,要不了几分钱就可以从Radio Shack买到这些元件 Dialogue: 0,0:12:54.88,0:12:56.32,Default,,0,0,0,,那些元件的作用和画在这里的差不多 Dialogue: 0,0:12:57.16,0:13:00.22,Default,,0,0,0,,元件上都标有类似于LS04的标签 Dialogue: 0,0:13:01.53,0:13:08.16,Default,,0,0,0,,现在来看其中的计算模型 Dialogue: 0,0:13:09.01,0:13:10.94,Default,,0,0,0,,它又对应着什么 Dialogue: 0,0:13:11.13,0:13:14.09,Default,,0,0,0,,计算机中的对象对应着我们思维中的什么 Dialogue: 0,0:13:15.85,0:13:19.13,Default,,0,0,0,,我需要把现实世界中的每个对象与计算机中的对应起来 Dialogue: 0,0:13:19.79,0:13:24.27,Default,,0,0,0,,把两个世界中对象之间的关系也对应起来 Dialogue: 0,0:13:26.06,0:13:26.80,Default,,0,0,0,,这是我的目标 Dialogue: 0,0:13:28.56,0:13:29.45,Default,,0,0,0,,让我们来看看怎么做 Dialogue: 0,0:13:30.90,0:13:34.20,Default,,0,0,0,,这一团东西代表信号A Dialogue: 0,0:13:35.71,0:13:36.94,Default,,0,0,0,,这是信号A Dialogue: 0,0:13:37.94,0:13:39.32,Default,,0,0,0,,画得像一团云 Dialogue: 0,0:13:39.90,0:13:42.80,Default,,0,0,0,,再画另一个信号 -- B Dialogue: 0,0:13:46.68,0:13:47.47,Default,,0,0,0,,它是另一个信号 Dialogue: 0,0:13:49.14,0:13:50.91,Default,,0,0,0,,这两个信号 Dialogue: 0,0:13:51.10,0:13:52.81,Default,,0,0,0,,要通过某种方式连在一起 Dialogue: 0,0:13:53.72,0:13:58.75,Default,,0,0,0,,连在这个盒子上 -- 这就代表与门 Dialogue: 0,0:14:00.32,0:14:02.04,Default,,0,0,0,,这就是与门的动作过程 Dialogue: 0,0:14:07.66,0:14:08.59,Default,,0,0,0,,它将产生 Dialogue: 0,0:14:09.15,0:14:13.29,Default,,0,0,0,,它将与另外一个称作C的信号对象交互 Dialogue: 0,0:14:16.22,0:14:18.88,Default,,0,0,0,,哦 说错了 是一条电线C Dialogue: 0,0:14:20.59,0:14:26.28,Default,,0,0,0,,这跟电线 又将连在另一个动作过程上 Dialogue: 0,0:14:26.28,0:14:30.33,Default,,0,0,0,,在我们的电气世界中 这个过程跟一个非门关联 Dialogue: 0,0:14:32.86,0:14:40.65,Default,,0,0,0,,我还有另外一根电线 -- D Dialogue: 0,0:14:42.97,0:14:45.29,Default,,0,0,0,,整体布局就是这样 Dialogue: 0,0:14:46.00,0:14:49.44,Default,,0,0,0,,现在必须来研究它们 有关计算的内部机制了 Dialogue: 0,0:14:51.50,0:14:53.69,Default,,0,0,0,,每一跟电线都必须知道 Dialogue: 0,0:14:53.69,0:14:56.36,Default,,0,0,0,,自己承载的信号是什么 Dialogue: 0,0:14:57.34,0:15:00.00,Default,,0,0,0,,我们用变量SIGNAL来表示 Dialogue: 0,0:15:02.97,0:15:04.04,Default,,0,0,0,,SIGNAL的值就是信号 Dialogue: 0,0:15:05.68,0:15:07.74,Default,,0,0,0,,也不要忘了它所关联的环境 Dialogue: 0,0:15:08.89,0:15:11.34,Default,,0,0,0,,对于每个元件来说 一定有一个环境绑定了信号 Dialogue: 0,0:15:15.40,0:15:16.88,Default,,0,0,0,,因此 这里也有一个SIGNAL变量 Dialogue: 0,0:15:19.40,0:15:21.92,Default,,0,0,0,,SIGNAL的值不是0就是1 Dialogue: 0,0:15:22.81,0:15:23.48,Default,,0,0,0,,这儿也有个SIGNAL Dialogue: 0,0:15:28.00,0:15:30.56,Default,,0,0,0,,现在 一旦这里的信号改变 Dialogue: 0,0:15:31.26,0:15:34.11,Default,,0,0,0,,我们需要通知一系列的对象 Dialogue: 0,0:15:36.66,0:15:37.66,Default,,0,0,0,,我们得通知这个与门 Dialogue: 0,0:15:39.30,0:15:43.96,Default,,0,0,0,,这里有个表 我们把它叫做AP Dialogue: 0,0:15:44.50,0:15:45.60,Default,,0,0,0,,它可能是一个表 Dialogue: 0,0:15:46.44,0:15:49.00,Default,,0,0,0,,在本例中 表里面的第一项条目是这个东西 Dialogue: 0,0:15:50.50,0:15:54.81,Default,,0,0,0,,这个元件也有一个称为AP的表 Dialogue: 0,0:15:54.81,0:15:58.17,Default,,0,0,0,,也可能有一些其它对象 时刻等待着A来通知“它们” Dialogue: 0,0:15:59.02,0:16:01.31,Default,,0,0,0,,所以这里可能有其它对象 比如 Dialogue: 0,0:16:01.72,0:16:03.23,Default,,0,0,0,,一些其它我们不知道的对象 Dialogue: 0,0:16:03.63,0:16:04.88,Default,,0,0,0,,这些是与A连接的其它对象 Dialogue: 0,0:16:07.20,0:16:09.64,Default,,0,0,0,,这里的AP表 Dialogue: 0,0:16:11.12,0:16:12.40,Default,,0,0,0,,也指向这个与门 Dialogue: 0,0:16:13.07,0:16:16.35,Default,,0,0,0,,相类似的 这里的AP表 Dialogue: 0,0:16:16.78,0:16:18.53,Default,,0,0,0,,也要指向这里 Dialogue: 0,0:16:18.53,0:16:20.89,Default,,0,0,0,,这里是C要通知的元件 Dialogue: 0,0:16:21.77,0:16:23.18,Default,,0,0,0,,D也一样 Dialogue: 0,0:16:24.28,0:16:25.24,Default,,0,0,0,,但是我不知道它要通知谁 Dialogue: 0,0:16:25.26,0:16:26.65,Default,,0,0,0,,因为我的图中没有画出来 Dialogue: 0,0:16:27.19,0:16:28.36,Default,,0,0,0,,可能是和D连接起来的其它元件 Dialogue: 0,0:16:30.32,0:16:32.62,Default,,0,0,0,,同样的 Dialogue: 0,0:16:33.80,0:16:36.96,Default,,0,0,0,,当AND-ACTION过程被唤醒时 Dialogue: 0,0:16:37.02,0:16:41.31,Default,,0,0,0,,也就是说 之前你拜托某人将你唤醒 Dialogue: 0,0:16:41.45,0:16:44.84,Default,,0,0,0,,你拜托它们 当它们的信号发生改变时通知你 Dialogue: 0,0:16:46.97,0:16:48.81,Default,,0,0,0,,你得去检查它的信号是什么 Dialogue: 0,0:16:49.32,0:16:52.25,Default,,0,0,0,,这样你就可以计算逻辑与 输出信号给下一个元件 Dialogue: 0,0:16:57.09,0:16:58.75,Default,,0,0,0,,所里 这里就必须要有 Dialogue: 0,0:16:58.84,0:17:03.00,Default,,0,0,0,,有信息说 A1是这个元件 Dialogue: 0,0:17:03.90,0:17:06.48,Default,,0,0,0,,A2就是这个元件 Dialogue: 0,0:17:08.93,0:17:09.98,Default,,0,0,0,,不只是这样 Dialogue: 0,0:17:11.79,0:17:15.20,Default,,0,0,0,,当我在计算逻辑与时 我还得告诉这个元件一些信息 Dialogue: 0,0:17:16.30,0:17:21.05,Default,,0,0,0,,还有一个输出 输出给这个元件 Dialogue: 0,0:17:25.80,0:17:30.03,Default,,0,0,0,,同样地 非门也有一个输入 Dialogue: 0,0:17:32.38,0:17:34.92,Default,,0,0,0,,当信号被唤醒并告知它信号被修改时 Dialogue: 0,0:17:36.75,0:17:38.64,Default,,0,0,0,,非门会询问该信号 Dialogue: 0,0:17:38.64,0:17:40.09,Default,,0,0,0,,你的值是什么 Dialogue: 0,0:17:41.05,0:17:43.47,Default,,0,0,0,,信号通过像这样发消息 告知“信号已改变” Dialogue: 0,0:17:43.52,0:17:45.53,Default,,0,0,0,,它就反过来查询这个新的信号值 Dialogue: 0,0:17:46.90,0:17:50.12,Default,,0,0,0,,取到值之后 它将会 Dialogue: 0,0:17:50.14,0:17:55.86,Default,,0,0,0,,计算输出 并改变这个信号的值 Dialogue: 0,0:18:00.60,0:18:01.24,Default,,0,0,0,,以此类推 Dialogue: 0,0:18:02.84,0:18:04.56,Default,,0,0,0,,因此我也必须有这么多的连接 Dialogue: 0,0:18:06.24,0:18:09.23,Default,,0,0,0,,现在我们回头观察一下 这个与门 Dialogue: 0,0:18:10.26,0:18:12.09,Default,,0,0,0,,回到这张幻灯片 Dialogue: 0,0:18:13.67,0:18:15.04,Default,,0,0,0,,这几个部分的内容 Dialogue: 0,0:18:16.04,0:18:19.32,Default,,0,0,0,,对每个与门 都有A1、A2两个输入 一个OUTPUT输出 Dialogue: 0,0:18:21.03,0:18:23.53,Default,,0,0,0,,这些都是 Dialogue: 0,0:18:25.08,0:18:28.16,Default,,0,0,0,,在AND-GATE被调用时的环境中 Dialogue: 0,0:18:28.41,0:18:31.24,Default,,0,0,0,,这些参数创建了一个框架 Dialogue: 0,0:18:33.31,0:18:35.90,Default,,0,0,0,,这个框架用来存放A1、A2和OUTPUT的值 Dialogue: 0,0:18:36.67,0:18:39.20,Default,,0,0,0,,它们都要与电线相绑定 Dialogue: 0,0:18:39.60,0:18:44.25,Default,,0,0,0,,这些电线就是通过参数传进来的 Dialogue: 0,0:18:46.24,0:18:47.31,Default,,0,0,0,,在这个环境下 Dialogue: 0,0:18:47.74,0:18:49.85,Default,,0,0,0,,我构建一个过程 Dialogue: 0,0:18:50.97,0:18:53.68,Default,,0,0,0,,就在这里 Dialogue: 0,0:18:54.59,0:18:57.31,Default,,0,0,0,,在该环境下定义的AND-ACTION-PROCEDURE Dialogue: 0,0:18:58.35,0:19:00.70,Default,,0,0,0,,这个实际上是对一个LAMBDA表达式求值 Dialogue: 0,0:19:01.62,0:19:05.48,Default,,0,0,0,,它跟求值该LAMBDA表达式时的环境相绑定 Dialogue: 0,0:19:07.16,0:19:09.34,Default,,0,0,0,,找到它的局部环境 Dialogue: 0,0:19:11.70,0:19:13.47,Default,,0,0,0,,因此AND-ACTION-PROCEDURE过程能够 Dialogue: 0,0:19:13.64,0:19:16.94,Default,,0,0,0,,存取这里看到的A1、A2和OUTPUT Dialogue: 0,0:19:17.31,0:19:19.64,Default,,0,0,0,,A1、A2、OUTPUT Dialogue: 0,0:19:22.36,0:19:23.95,Default,,0,0,0,,我们还没有深入探索“电线”的内部结构 Dialogue: 0,0:19:26.03,0:19:26.99,Default,,0,0,0,,那是仅剩的部分 Dialogue: 0,0:19:29.03,0:19:29.92,Default,,0,0,0,,来看看“电线” Dialogue: 0,0:19:33.52,0:19:36.25,Default,,0,0,0,,麻烦请开一下投影仪 Dialogue: 0,0:19:39.50,0:19:42.56,Default,,0,0,0,,“电线”是有那么一点复杂 Dialogue: 0,0:19:43.09,0:19:44.64,Default,,0,0,0,,哦 摁错了 Dialogue: 0,0:19:47.05,0:19:48.75,Default,,0,0,0,,是非常复杂 像这样 Dialogue: 0,0:19:50.06,0:19:53.10,Default,,0,0,0,,但是还是来看一下 到底是什么 Dialogue: 0,0:19:54.72,0:19:56.67,Default,,0,0,0,,“电线”是这样的一种东西 Dialogue: 0,0:19:57.76,0:20:03.52,Default,,0,0,0,,有两个主要部分 都是它的状态 Dialogue: 0,0:20:05.01,0:20:07.39,Default,,0,0,0,,我们这里看到的 一个是信号值 Dialogue: 0,0:20:07.45,0:20:10.06,Default,,0,0,0,,这里 当我们调用MAKE-WIRE创建一条电线时 Dialogue: 0,0:20:10.46,0:20:13.02,Default,,0,0,0,,我们首先要创建一些变量 Dialogue: 0,0:20:14.94,0:20:16.08,Default,,0,0,0,,分别是这条电线的 Dialogue: 0,0:20:17.10,0:20:19.29,Default,,0,0,0,,SIGNAL和ACTION-PROCS Dialogue: 0,0:20:22.32,0:20:23.44,Default,,0,0,0,,在这个上下文中 Dialogue: 0,0:20:23.76,0:20:27.04,Default,,0,0,0,,我们定义了一系列的过程 Dialogue: 0,0:20:27.84,0:20:31.15,Default,,0,0,0,,其中一个是(SET-MY-SIGNAL! NEW) Dialogue: 0,0:20:32.85,0:20:37.42,Default,,0,0,0,,它所做的只是 取一个新值NEW Dialogue: 0,0:20:37.93,0:20:40.36,Default,,0,0,0,,如果NEW和SIGNAL一样 信号没有变化 就没必要做什么了 Dialogue: 0,0:20:40.36,0:20:42.62,Default,,0,0,0,,否则 把SIGNAL的值赋值为NEW Dialogue: 0,0:20:42.75,0:20:44.60,Default,,0,0,0,,再调用ACTION-PROCS里的所有过程 Dialogue: 0,0:20:46.52,0:20:52.51,Default,,0,0,0,,那些我之前引入的过程 Dialogue: 0,0:20:54.63,0:21:01.53,Default,,0,0,0,,也就是我在定义与门时就定义的过程 Dialogue: 0,0:21:04.13,0:21:05.60,Default,,0,0,0,,是在代码最后调用ADD-ACTION-PROCEDURE实现的 Dialogue: 0,0:21:07.41,0:21:10.80,Default,,0,0,0,,然后 我还得定义一个过程 用来接受动作 Dialogue: 0,0:21:10.81,0:21:11.82,Default,,0,0,0,,也就是这段代码 Dialogue: 0,0:21:12.80,0:21:15.13,Default,,0,0,0,,它增加了AP表 Dialogue: 0,0:21:15.56,0:21:21.63,Default,,0,0,0,,这是通过使用SET!将PROC与旧的AP表CONS起来实现的 Dialogue: 0,0:21:21.79,0:21:24.25,Default,,0,0,0,,而这个PROC是作为参数传递进来的 Dialogue: 0,0:21:25.40,0:21:27.58,Default,,0,0,0,,由于技术原因 最后还要再运行一次PROC Dialogue: 0,0:21:27.78,0:21:29.20,Default,,0,0,0,,我不会再对此详细展开 Dialogue: 0,0:21:29.39,0:21:33.15,Default,,0,0,0,,这是一种事件驱动的模拟 Dialogue: 0,0:21:34.59,0:21:36.00,Default,,0,0,0,,要想把这个讲清楚还是得花点时间 Dialogue: 0,0:21:36.95,0:21:39.40,Default,,0,0,0,,最后 我还要定义一个“分派器” Dialogue: 0,0:21:39.96,0:21:43.58,Default,,0,0,0,,这是一种将消息分派给电线的方法 Dialogue: 0,0:21:45.37,0:21:48.65,Default,,0,0,0,,它将用于从中抽取出不同的信息 Dialogue: 0,0:21:49.07,0:21:51.48,Default,,0,0,0,,比如这里 当前的信号值是多少? Dialogue: 0,0:21:53.82,0:21:55.66,Default,,0,0,0,,设置新信号值的方法是什么? Dialogue: 0,0:21:57.18,0:21:58.28,Default,,0,0,0,,我想要这个方法 Dialogue: 0,0:22:00.10,0:22:02.60,Default,,0,0,0,,我怎么样去添加另外的动作过程呢? Dialogue: 0,0:22:05.51,0:22:09.36,Default,,0,0,0,,最后 以DISPATCH过程为返回值返回 Dialogue: 0,0:22:09.94,0:22:11.87,Default,,0,0,0,,因此 我所构造的电线 Dialogue: 0,0:22:12.00,0:22:13.55,Default,,0,0,0,,是一种可以接收消息的对象 Dialogue: 0,0:22:14.25,0:22:16.01,Default,,0,0,0,,它接收的消息类似于 Dialogue: 0,0:22:16.44,0:22:18.36,Default,,0,0,0,,“你的哪个方法可以用来添加动作过程?” Dialogue: 0,0:22:19.92,0:22:21.00,Default,,0,0,0,,它返回一个过程 Dialogue: 0,0:22:21.64,0:22:23.05,Default,,0,0,0,,它返回ADD-ACTION-PROCUDURE Dialogue: 0,0:22:23.07,0:22:26.54,Default,,0,0,0,,我可以将其应用在一个动作过程上 Dialogue: 0,0:22:27.05,0:22:29.01,Default,,0,0,0,,从而实现将一个动作过程加入电线的AP表中 Dialogue: 0,0:22:31.62,0:22:32.82,Default,,0,0,0,,这是一种“许可” Dialogue: 0,0:22:33.20,0:22:36.08,Default,,0,0,0,,使得你可以去修改自身的AP表 Dialogue: 0,0:22:37.82,0:22:40.16,Default,,0,0,0,,实际上 你可以在这里看到 Dialogue: 0,0:22:41.71,0:22:42.32,Default,,0,0,0,,下一张幻灯片 Dialogue: 0,0:22:43.53,0:22:43.82,Default,,0,0,0,,噢 Dialogue: 0,0:22:47.76,0:22:49.12,Default,,0,0,0,,没什么有意思的 Dialogue: 0,0:22:49.12,0:22:50.65,Default,,0,0,0,,CALL-EACH调用每个动作过程 Dialogue: 0,0:22:50.89,0:22:52.57,Default,,0,0,0,,这只是对一个表不断做CDR Dialogue: 0,0:22:52.73,0:22:54.60,Default,,0,0,0,,没什么好说的 Dialogue: 0,0:22:54.99,0:22:56.25,Default,,0,0,0,,我们早就知道了 Dialogue: 0,0:22:57.56,0:23:00.67,Default,,0,0,0,,然而 如果我想知道线路上的信号值 Dialogue: 0,0:23:01.02,0:23:02.54,Default,,0,0,0,,我询问该线路:你的 -- Dialogue: 0,0:23:02.54,0:23:03.09,Default,,0,0,0,,回想一下 什么是线路? Dialogue: 0,0:23:03.09,0:23:05.40,Default,,0,0,0,,线路对象只是在创建它时所返回的分派过程而已 Dialogue: 0,0:23:05.86,0:23:06.48,Default,,0,0,0,,只是一个过程 Dialogue: 0,0:23:06.83,0:23:12.27,Default,,0,0,0,,我向该分派器发送一个消息'GET-SIGNAL Dialogue: 0,0:23:12.91,0:23:15.40,Default,,0,0,0,,实际得到的是一个方法 用于取得线路信号值 Dialogue: 0,0:23:16.90,0:23:17.96,Default,,0,0,0,,进一步 我就可以得到信号值 Dialogue: 0,0:23:19.22,0:23:20.52,Default,,0,0,0,,如果我想要设置一个信号值 Dialogue: 0,0:23:22.65,0:23:23.96,Default,,0,0,0,,我想要改变一个信号值 Dialogue: 0,0:23:24.51,0:23:26.76,Default,,0,0,0,,我要做的是 Dialogue: 0,0:23:26.92,0:23:29.69,Default,,0,0,0,,以一个线路和信号的新值作为参数 Dialogue: 0,0:23:30.01,0:23:32.43,Default,,0,0,0,,我向线路请求许可 来设置它的信号值 Dialogue: 0,0:23:32.84,0:23:37.61,Default,,0,0,0,,我会用该许可 -- 也就是一个过程 -- 应用在一个新值上 Dialogue: 0,0:23:38.70,0:23:40.51,Default,,0,0,0,,我们再过来看投影 Dialogue: 0,0:23:41.64,0:23:43.24,Default,,0,0,0,,好的 谢谢 Dialogue: 0,0:23:44.20,0:23:45.63,Default,,0,0,0,,我们看这里的投影 Dialogue: 0,0:23:45.92,0:23:48.75,Default,,0,0,0,,我们看到 如果我请求设置信号的方法 Dialogue: 0,0:23:49.34,0:23:50.44,Default,,0,0,0,,也就是这段代码 Dialogue: 0,0:23:52.25,0:23:55.69,Default,,0,0,0,,返回的是一个定义在线路内部的SET-MY-SIGNAL!方法 Dialogue: 0,0:23:56.25,0:23:57.69,Default,,0,0,0,,回过头来看它的定义 Dialogue: 0,0:23:58.72,0:23:59.74,Default,,0,0,0,,它的定义是 Dialogue: 0,0:24:00.43,0:24:02.68,Default,,0,0,0,,将我的一个内部变量SIGNAL的值设为 Dialogue: 0,0:24:02.73,0:24:05.50,Default,,0,0,0,,这个内部变量 用于存储信号值 Dialogue: 0,0:24:07.61,0:24:10.03,Default,,0,0,0,,将其值设为通过参数传递的NEW Dialogue: 0,0:24:10.78,0:24:13.01,Default,,0,0,0,,然后调用AP表中的过程 来唤醒它们 Dialogue: 0,0:24:16.34,0:24:16.99,Default,,0,0,0,,非常简单 Dialogue: 0,0:24:19.24,0:24:20.76,Default,,0,0,0,,回头来看刚才的幻灯片 Dialogue: 0,0:24:22.48,0:24:24.32,Default,,0,0,0,,还有最后一点 Dialogue: 0,0:24:24.36,0:24:27.31,Default,,0,0,0,,我想你们现在应该很轻易地就能理解了 Dialogue: 0,0:24:27.77,0:24:29.15,Default,,0,0,0,,关于我们如何添加新的动作过程 Dialogue: 0,0:24:30.10,0:24:35.18,Default,,0,0,0,,我们需要WIRE和ACTION-PROC两个参数 Dialogue: 0,0:24:36.47,0:24:39.31,Default,,0,0,0,,然后请求添加动作过程的许可 Dialogue: 0,0:24:40.05,0:24:44.22,Default,,0,0,0,,得到许可后 用该许可去添加新的动作过程 Dialogue: 0,0:24:45.84,0:24:47.08,Default,,0,0,0,,所以 这确实是一个“对象” Dialogue: 0,0:24:48.57,0:24:50.32,Default,,0,0,0,,还有些细节 Dialogue: 0,0:24:52.46,0:24:58.39,Default,,0,0,0,,比如 我怎么来控制它? Dialogue: 0,0:24:58.39,0:24:59.69,Default,,0,0,0,,这些延时怎么实现? Dialogue: 0,0:25:00.99,0:25:02.54,Default,,0,0,0,,我们来快速过一遍 Dialogue: 0,0:25:05.50,0:25:07.98,Default,,0,0,0,,下一张 Dialogue: 0,0:25:08.36,0:25:08.88,Default,,0,0,0,,我们来看看 Dialogue: 0,0:25:09.57,0:25:14.17,Default,,0,0,0,,我们细看与门、或门的定义 Dialogue: 0,0:25:15.31,0:25:17.00,Default,,0,0,0,,会发现当输入信号改变时 Dialogue: 0,0:25:17.24,0:25:18.19,Default,,0,0,0,,会有“延时” Dialogue: 0,0:25:18.77,0:25:21.24,Default,,0,0,0,,然后它将调用过程 Dialogue: 0,0:25:21.63,0:25:23.00,Default,,0,0,0,,来改变输出 Dialogue: 0,0:25:26.04,0:25:27.92,Default,,0,0,0,,这个要如何实现? Dialogue: 0,0:25:28.12,0:25:29.92,Default,,0,0,0,,我们将要建立一种机制 Dialogue: 0,0:25:30.30,0:25:32.00,Default,,0,0,0,,一种相当复杂的机制 Dialogue: 0,0:25:32.33,0:25:33.76,Default,,0,0,0,,我们得非常细心地来看 Dialogue: 0,0:25:34.72,0:25:37.23,Default,,0,0,0,,一段延时之后 我们将执行一个动作 Dialogue: 0,0:25:37.39,0:25:38.12,Default,,0,0,0,,DELAY是一个数 Dialogue: 0,0:25:38.16,0:25:39.23,Default,,0,0,0,,而ACTION是一个过程 Dialogue: 0,0:25:40.59,0:25:43.72,Default,,0,0,0,,我们引入一种称为THE-AGENDA的特殊数据结构 Dialogue: 0,0:25:45.50,0:25:48.80,Default,,0,0,0,,用于组织时间与动作 Dialogue: 0,0:25:49.51,0:25:50.88,Default,,0,0,0,,一会儿再来仔细研究 Dialogue: 0,0:25:50.88,0:25:52.54,Default,,0,0,0,,先把这里说完 Dialogue: 0,0:25:53.07,0:25:58.28,Default,,0,0,0,,THE-AGENDA将记录执行动作的时刻 Dialogue: 0,0:25:59.13,0:26:02.46,Default,,0,0,0,,我们把它设定在未来的某个时刻 Dialogue: 0,0:26:02.51,0:26:05.68,Default,,0,0,0,,也就是在CURRENT-TIME加上DELAT的时刻 Dialogue: 0,0:26:05.69,0:26:07.13,Default,,0,0,0,,触发关联的动作 Dialogue: 0,0:26:09.02,0:26:10.56,Default,,0,0,0,,我们把准备好要执行的动作 Dialogue: 0,0:26:11.02,0:26:12.40,Default,,0,0,0,,添加入THE-AGENDA中 Dialogue: 0,0:26:15.28,0:26:18.03,Default,,0,0,0,,要使这个“机器”运行起来并不困难 Dialogue: 0,0:26:18.66,0:26:21.48,Default,,0,0,0,,我们利用这个PROPAGATE过程来完成这件事 Dialogue: 0,0:26:22.71,0:26:25.95,Default,,0,0,0,,如果THE-AGENDA为空 就没有要做的 Dialogue: 0,0:26:27.44,0:26:28.16,Default,,0,0,0,,否则 Dialogue: 0,0:26:29.76,0:26:31.53,Default,,0,0,0,,我们就取出THE-AGENDA的第一个元素 Dialogue: 0,0:26:31.71,0:26:33.34,Default,,0,0,0,,它是一个无参过程 Dialogue: 0,0:26:34.20,0:26:36.03,Default,,0,0,0,,所以这里有额外的括号 Dialogue: 0,0:26:36.03,0:26:37.85,Default,,0,0,0,,我们对其进行无参调用 Dialogue: 0,0:26:39.19,0:26:40.17,Default,,0,0,0,,这就执行了之前存入的动作 Dialogue: 0,0:26:42.20,0:26:44.17,Default,,0,0,0,,然后我们从THE-AGENDA中删除第一个元素 Dialogue: 0,0:26:44.59,0:26:46.14,Default,,0,0,0,,然后再进入传播循环 Dialogue: 0,0:26:48.91,0:26:50.75,Default,,0,0,0,,这就是整体的结构 Dialogue: 0,0:26:53.38,0:26:55.93,Default,,0,0,0,,还有点其它的 Dialogue: 0,0:26:57.43,0:27:00.01,Default,,0,0,0,,现在 我们来看看THE-AGENDA的内部结构 Dialogue: 0,0:27:00.57,0:27:01.55,Default,,0,0,0,,请看投影仪 Dialogue: 0,0:27:02.80,0:27:04.67,Default,,0,0,0,,该如何使用这个玩意儿呢? Dialogue: 0,0:27:04.67,0:27:07.41,Default,,0,0,0,,我需要给你们说明下这个模拟器的用法 Dialogue: 0,0:27:07.85,0:27:09.93,Default,,0,0,0,,你们可能觉得这个模拟器太简陋了 Dialogue: 0,0:27:10.40,0:27:12.01,Default,,0,0,0,,甚至你们认为它根本没什么用 Dialogue: 0,0:27:12.57,0:27:13.76,Default,,0,0,0,,而实际上是 Dialogue: 0,0:27:13.98,0:27:15.39,Default,,0,0,0,,这样的模拟器曾被用于 Dialogue: 0,0:27:15.72,0:27:17.44,Default,,0,0,0,,操纵相当大型的计算机 Dialogue: 0,0:27:18.68,0:27:20.64,Default,,0,0,0,,那是一个真实的事例 Dialogue: 0,0:27:22.36,0:27:24.06,Default,,0,0,0,,当然 并不完全是这里的这个模拟器 Dialogue: 0,0:27:24.06,0:27:25.39,Default,,0,0,0,,我会告诉你它们的区别 Dialogue: 0,0:27:25.84,0:27:28.70,Default,,0,0,0,,区别就是 操纵大型机的模拟器有更多的基本元素 Dialogue: 0,0:27:29.82,0:27:32.22,Default,,0,0,0,,不只是有非门 与门之类的 Dialogue: 0,0:27:33.20,0:27:35.72,Default,,0,0,0,,还有边缘触发器 Dialogue: 0,0:27:36.25,0:27:39.88,Default,,0,0,0,,翻转触发器 锁存器 Dialogue: 0,0:27:40.70,0:27:44.52,Default,,0,0,0,,电平触发器 加法器等等之类的 Dialogue: 0,0:27:45.17,0:27:47.31,Default,,0,0,0,,困难之处在于 Dialogue: 0,0:27:47.45,0:27:50.86,Default,,0,0,0,,就在于需要很多页的文档 Dialogue: 0,0:27:51.20,0:27:52.89,Default,,0,0,0,,来描述这些基本元素 Dialogue: 0,0:27:54.69,0:27:56.74,Default,,0,0,0,,同时它们还有很多的参数 Dialogue: 0,0:27:56.74,0:27:57.98,Default,,0,0,0,,不是只有一个延时这么简单 Dialogue: 0,0:27:58.48,0:28:00.81,Default,,0,0,0,,还有建立时间 维持时间之类的 Dialogue: 0,0:28:01.22,0:28:03.40,Default,,0,0,0,,但是 如果不算上那部分的复杂度 Dialogue: 0,0:28:03.82,0:28:08.20,Default,,0,0,0,,我们用来构建真实计算机的模拟器的结构 Dialogue: 0,0:28:09.08,0:28:12.89,Default,,0,0,0,,跟你们在这里看到的的是一致的 Dialogue: 0,0:28:15.11,0:28:19.27,Default,,0,0,0,,无论如何 这里都是一些简单的东西 Dialogue: 0,0:28:19.27,0:28:22.59,Default,,0,0,0,,像这个 设置非门的延时时间 构建一个 AGENDA Dialogue: 0,0:28:23.03,0:28:25.52,Default,,0,0,0,,我们可以构建一些输入(线路) Dialogue: 0,0:28:26.03,0:28:29.18,Default,,0,0,0,,这里的四条线路分别是:INPUT-1、INPUT-2、SUM和CARRY Dialogue: 0,0:28:29.46,0:28:31.88,Default,,0,0,0,,我将要放置一种被称为“探针”的特殊对象 Dialogue: 0,0:28:32.51,0:28:34.64,Default,,0,0,0,,放在一些线路上 Dialogue: 0,0:28:34.97,0:28:36.24,Default,,0,0,0,,放在SUM和CARRY上 Dialogue: 0,0:28:37.23,0:28:40.56,Default,,0,0,0,,探针是一种对象 它可以 -- Dialogue: 0,0:28:40.70,0:28:43.60,Default,,0,0,0,,当你改变它所附着线路的信号时 Dialogue: 0,0:28:43.72,0:28:44.83,Default,,0,0,0,,它会输出一条消息 Dialogue: 0,0:28:46.12,0:28:46.92,Default,,0,0,0,,这很容易实现 Dialogue: 0,0:28:48.44,0:28:49.52,Default,,0,0,0,,一旦我们设置好它们 Dialogue: 0,0:28:49.55,0:28:51.45,Default,,0,0,0,,当你在放置探针的时候 Dialogue: 0,0:28:51.45,0:28:52.41,Default,,0,0,0,,它首先会输出 Dialogue: 0,0:28:52.67,0:28:56.01,Default,,0,0,0,,SUM在0时刻的值为0 Dialogue: 0,0:28:57.29,0:28:58.43,Default,,0,0,0,,这个我已经注意到了 Dialogue: 0,0:28:59.40,0:29:04.75,Default,,0,0,0,,CARRY在0时刻的值也是0 Dialogue: 0,0:29:06.04,0:29:09.28,Default,,0,0,0,,我们继续来构建更多结构 Dialogue: 0,0:29:09.62,0:29:12.28,Default,,0,0,0,,比如 可以像这里一样构建一种结构 Dialogue: 0,0:29:14.06,0:29:18.20,Default,,0,0,0,,用INPUT-1、INPUT-2、SUM和CARRY组成一个半加器 Dialogue: 0,0:29:18.42,0:29:20.42,Default,,0,0,0,,然后我们把INPUT-1上的信号变为1 Dialogue: 0,0:29:20.62,0:29:21.72,Default,,0,0,0,,然后开始传播 Dialogue: 0,0:29:21.88,0:29:22.84,Default,,0,0,0,,在时刻8的时候 Dialogue: 0,0:29:23.90,0:29:26.12,Default,,0,0,0,,如果你想的话 也可以单步跟踪传播过程 Dialogue: 0,0:29:26.52,0:29:29.20,Default,,0,0,0,,SUM的值变为1 Dialogue: 0,0:29:29.52,0:29:30.44,Default,,0,0,0,,然后就结束了 Dialogue: 0,0:29:31.16,0:29:32.25,Default,,0,0,0,,好像没什么意思 Dialogue: 0,0:29:32.63,0:29:33.90,Default,,0,0,0,,我们还可以设置信号 Dialogue: 0,0:29:34.06,0:29:36.73,Default,,0,0,0,,把INPUT-2也变为1 Dialogue: 0,0:29:36.89,0:29:38.09,Default,,0,0,0,,如果再进行传播 Dialogue: 0,0:29:38.36,0:29:39.95,Default,,0,0,0,,在时刻11 Dialogue: 0,0:29:40.12,0:29:41.42,Default,,0,0,0,,CARRY变为1 Dialogue: 0,0:29:41.55,0:29:44.19,Default,,0,0,0,,在时刻16 SUM变为0 Dialogue: 0,0:29:45.39,0:29:48.99,Default,,0,0,0,,如果你仔细研究那个电路图 Dialogue: 0,0:29:48.99,0:29:50.12,Default,,0,0,0,,它确实是这个结果 Dialogue: 0,0:29:50.62,0:29:51.53,Default,,0,0,0,,也并没有什么特别的 Dialogue: 0,0:29:51.53,0:29:54.12,Default,,0,0,0,,但是却清楚地表明了这一些都是如何运作的 Dialogue: 0,0:30:01.83,0:30:03.29,Default,,0,0,0,,我现在给你们展示的是 Dialogue: 0,0:30:03.48,0:30:05.52,Default,,0,0,0,,一种宏观的图景 Dialogue: 0,0:30:06.60,0:30:08.56,Default,,0,0,0,,你如何在一个很大的规模中 Dialogue: 0,0:30:08.72,0:30:12.04,Default,,0,0,0,,你何去实现某种事件驱动的模拟 Dialogue: 0,0:30:13.29,0:30:14.56,Default,,0,0,0,,你应该如何去组织 Dialogue: 0,0:30:14.88,0:30:16.70,Default,,0,0,0,,来获得良好的层次性结构 Dialogue: 0,0:30:16.99,0:30:21.00,Default,,0,0,0,,使得你可以构建可具体化的抽象盒子 Dialogue: 0,0:30:21.56,0:30:24.96,Default,,0,0,0,,但我还没有告诉你AGENDA是如何运作的 Dialogue: 0,0:30:25.78,0:30:26.54,Default,,0,0,0,,下一小节再说 Dialogue: 0,0:30:28.63,0:30:32.94,Default,,0,0,0,,这将涉及到一些关于数据变化之类的事情 Dialogue: 0,0:30:34.31,0:30:35.86,Default,,0,0,0,,在我继续之前 有什么问题吗? Dialogue: 0,0:30:47.16,0:30:48.24,Default,,0,0,0,,没有的话 那就休息一下 Dialogue: 0,0:30:50.24,0:31:00.62,Default,,0,0,0,,[音乐] Dialogue: 0,0:31:00.62,0:31:06.00,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:31:11.23,0:31:17.69,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:31:17.76,0:31:21.34,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:31:21.34,0:31:25.18,Declare,,0,0,0,,{\an2\fad(500,500)}计算对象 Dialogue: 0,0:31:28.94,0:31:35.06,Default,,0,0,0,,我们已经做了一个模拟器 Dialogue: 0,0:31:35.39,0:31:37.77,Default,,0,0,0,,这是一种事件驱动的模拟 Dialogue: 0,0:31:38.17,0:31:42.75,Default,,0,0,0,,其中 计算机中的对象与现实中的对象一一对应 Dialogue: 0,0:31:43.92,0:31:47.28,Default,,0,0,0,,现实世界中按时发生的状态改变 Dialogue: 0,0:31:47.98,0:31:50.83,Default,,0,0,0,,被组织成了计算机中的时间 Dialogue: 0,0:31:52.99,0:31:56.04,Default,,0,0,0,,如果现实中某件事后于另一件事发生 Dialogue: 0,0:31:56.46,0:31:57.96,Default,,0,0,0,,那么在计算机中 Dialogue: 0,0:31:58.89,0:32:02.25,Default,,0,0,0,,两个事件也保持同样的先后顺序发生 Dialogue: 0,0:32:04.42,0:32:07.16,Default,,0,0,0,,排列这些时间 就是我们要用到赋值的地方 Dialogue: 0,0:32:08.22,0:32:11.21,Default,,0,0,0,,现在我要介绍一种方法来组织时间 Dialogue: 0,0:32:11.80,0:32:14.86,Default,,0,0,0,,AGENDA -- 或者有时候所谓的“优先队列” Dialogue: 0,0:32:16.04,0:32:18.57,Default,,0,0,0,,我们首先需要认识到 Dialogue: 0,0:32:18.62,0:32:21.00,Default,,0,0,0,,为了创建AGENDA 我们需要些什么东西? Dialogue: 0,0:32:28.33,0:32:31.28,Default,,0,0,0,,首先我要在这里写下一些 Dialogue: 0,0:32:31.39,0:32:33.88,Default,,0,0,0,,用于操作AGENDA的基本运算 Dialogue: 0,0:32:35.96,0:32:37.95,Default,,0,0,0,,我不会给出具体代码 Dialogue: 0,0:32:38.14,0:32:39.58,Default,,0,0,0,,因为它们都非常简单 Dialogue: 0,0:32:40.32,0:32:42.60,Default,,0,0,0,,而且你们手上也有 Dialogue: 0,0:32:43.68,0:32:44.38,Default,,0,0,0,,有哪些运算呢? Dialogue: 0,0:32:44.38,0:32:53.50,Default,,0,0,0,,MAKE-AGENDA可以新建一个AGENDA Dialogue: 0,0:32:57.36,0:33:01.77,Default,,0,0,0,,CURRENT-TIME可以获得一个AGENDA的当前时间 Dialogue: 0,0:33:07.47,0:33:12.80,Default,,0,0,0,,返回一个数 -- 也就是当前时间 Dialogue: 0,0:33:16.99,0:33:21.37,Default,,0,0,0,,EMPTY-AGENDA?可用于判断一个AGENDA是否为空 Dialogue: 0,0:33:30.20,0:33:32.57,Default,,0,0,0,,返回TRUE或FALSE Dialogue: 0,0:33:42.72,0:33:44.72,Default,,0,0,0,,我们也可以向AGENDA中添加对象 Dialogue: 0,0:33:52.71,0:33:56.06,Default,,0,0,0,,实际上 向AGENDA中添加的是一个运算 -- 或者说是需要完成的操作 Dialogue: 0,0:33:56.91,0:33:58.14,Default,,0,0,0,,它需要时间TIME Dialogue: 0,0:33:59.63,0:34:00.56,Default,,0,0,0,,待添加的动作ACTION Dialogue: 0,0:34:02.86,0:34:04.64,Default,,0,0,0,,以及AGENDA本身 Dialogue: 0,0:34:07.58,0:34:10.25,Default,,0,0,0,,它把ACTION 放入AGENDA中合适的地方 Dialogue: 0,0:34:10.71,0:34:12.73,Default,,0,0,0,,FIRST-ITEM用于从AGENDA取出第一个事项 Dialogue: 0,0:34:14.24,0:34:15.39,Default,,0,0,0,,那是我首先需要做的事情 Dialogue: 0,0:34:21.84,0:34:23.84,Default,,0,0,0,,该事项是一个动作 Dialogue: 0,0:34:26.46,0:34:28.73,Default,,0,0,0,,我还可以把第一个事项从AGENDA中移除 Dialogue: 0,0:34:29.54,0:34:31.16,Default,,0,0,0,,这是操作AGENDA的一个必要运算 Dialogue: 0,0:34:31.40,0:34:33.02,Default,,0,0,0,,这个运算实现起来非常繁杂 Dialogue: 0,0:34:42.53,0:34:43.36,Default,,0,0,0,,从AGENDA中移除 Dialogue: 0,0:34:45.98,0:34:49.85,Default,,0,0,0,,现在我们来看如何具体组织数据结构 Dialogue: 0,0:34:52.96,0:34:56.04,Default,,0,0,0,,AGENDA应该是一种表 Dialogue: 0,0:34:58.43,0:35:01.20,Default,,0,0,0,,一种可修改的表 Dialogue: 0,0:35:01.57,0:35:04.03,Default,,0,0,0,,因为我们要向其中添加元素 Dialogue: 0,0:35:05.80,0:35:06.89,Default,,0,0,0,,删除元素等等 Dialogue: 0,0:35:07.77,0:35:10.27,Default,,0,0,0,,所以我们需要一种可修改的表 Dialogue: 0,0:35:11.07,0:35:12.51,Default,,0,0,0,,它通过时间组织起来 Dialogue: 0,0:35:13.82,0:35:15.57,Default,,0,0,0,,让它有序 也许会有益处 Dialogue: 0,0:35:18.33,0:35:20.88,Default,,0,0,0,,但是也有可能同一时间会发生很多事 Dialogue: 0,0:35:22.04,0:35:23.42,Default,,0,0,0,,或者说几乎同时 Dialogue: 0,0:35:23.80,0:35:24.72,Default,,0,0,0,,因此我们需要 Dialogue: 0,0:35:24.91,0:35:27.52,Default,,0,0,0,,把它们按发生时间为事件分组 Dialogue: 0,0:35:29.04,0:35:31.61,Default,,0,0,0,,所以我要把AGENDA组织成由SEGMENT构成的表 Dialogue: 0,0:35:32.78,0:35:35.69,Default,,0,0,0,,我来画一下这个结构 Dialogue: 0,0:35:36.68,0:35:37.93,Default,,0,0,0,,方便理解 Dialogue: 0,0:35:39.62,0:35:40.49,Default,,0,0,0,,这是一个AGENDA Dialogue: 0,0:35:41.11,0:35:42.87,Default,,0,0,0,,以一个名字开始 Dialogue: 0,0:35:47.85,0:35:50.19,Default,,0,0,0,,我把它画在表结构的外部 Dialogue: 0,0:35:52.60,0:35:53.39,Default,,0,0,0,,这是它的头部 Dialogue: 0,0:35:54.14,0:35:55.44,Default,,0,0,0,,这个头部的存在也是很必要的 Dialogue: 0,0:35:55.84,0:35:57.63,Default,,0,0,0,,待会你就会知道 Dialogue: 0,0:36:00.68,0:36:03.40,Default,,0,0,0,,再画一个SEGMENT Dialogue: 0,0:36:03.96,0:36:05.62,Default,,0,0,0,,这是一个由SEGMENT构成的表 Dialogue: 0,0:36:08.31,0:36:10.54,Default,,0,0,0,,假设这个AGENDA有两个SEGMENT Dialogue: 0,0:36:11.58,0:36:15.07,Default,,0,0,0,,不断对这个表取CAR即可得到 Dialogue: 0,0:36:16.41,0:36:20.57,Default,,0,0,0,,每个SEGMENT都有一个时间 Dialogue: 0,0:36:24.20,0:36:26.64,Default,,0,0,0,,比如说这里是10 Dialogue: 0,0:36:26.83,0:36:30.51,Default,,0,0,0,,也就是说 这个SEGMENT里的事件发生在10时刻 Dialogue: 0,0:36:33.16,0:36:36.52,Default,,0,0,0,,这里是另外一种数据结构 Dialogue: 0,0:36:36.56,0:36:38.01,Default,,0,0,0,,我先不具体描述 Dialogue: 0,0:36:38.49,0:36:41.08,Default,,0,0,0,,它是一个队列 表示在10时刻要做的事 Dialogue: 0,0:36:42.24,0:36:43.33,Default,,0,0,0,,它是一个队列 Dialogue: 0,0:36:43.33,0:36:44.70,Default,,0,0,0,,一会儿再细说 Dialogue: 0,0:36:45.20,0:36:50.35,Default,,0,0,0,,不过抽象地看 队列就是一系列在固定时间要做的事 Dialogue: 0,0:36:50.40,0:36:52.04,Default,,0,0,0,,我可以向其中添加其它要做的事 Dialogue: 0,0:36:53.10,0:36:53.80,Default,,0,0,0,,这是一个队列 Dialogue: 0,0:36:56.14,0:36:59.11,Default,,0,0,0,,这个是时间 这个是SEGMENT Dialogue: 0,0:37:03.23,0:37:06.36,Default,,0,0,0,,在这个AGENDA中 还有另一个SEGMENT Dialogue: 0,0:37:08.94,0:37:11.20,Default,,0,0,0,,假设它在30时刻发生 Dialogue: 0,0:37:13.50,0:37:15.92,Default,,0,0,0,,类似地 它也有一个队列 Dialogue: 0,0:37:16.92,0:37:20.24,Default,,0,0,0,,里面是在30时刻要去做的事 Dialogue: 0,0:37:23.21,0:37:25.66,Default,,0,0,0,,当然 我们的AGENDA还需要支持其它操作 Dialogue: 0,0:37:27.09,0:37:29.20,Default,,0,0,0,,假设我想将一个在10时刻发生的事 Dialogue: 0,0:37:29.47,0:37:31.61,Default,,0,0,0,,添加到AGENDA中 Dialogue: 0,0:37:33.03,0:37:34.16,Default,,0,0,0,,这并不难 Dialogue: 0,0:37:34.70,0:37:38.65,Default,,0,0,0,,我遍历到这里 找到时刻是10的SEGMENT Dialogue: 0,0:37:39.73,0:37:42.14,Default,,0,0,0,,这样的SEGMENT也可能不存在 Dialogue: 0,0:37:42.93,0:37:44.56,Default,,0,0,0,,一会儿再考虑这种情况 Dialogue: 0,0:37:45.42,0:37:47.56,Default,,0,0,0,,如果我找到了时刻为10的SEGMENT Dialogue: 0,0:37:47.87,0:37:50.43,Default,,0,0,0,,如果我想要把一个事情放入其中 Dialogue: 0,0:37:50.56,0:37:52.16,Default,,0,0,0,,我只要增加该队列即可 Dialogue: 0,0:37:53.85,0:37:56.22,Default,,0,0,0,,这个说起来倒是很容易 Dialogue: 0,0:37:56.57,0:37:59.26,Default,,0,0,0,,我在这里添加需要在那时做的事 Dialogue: 0,0:38:01.43,0:38:04.25,Default,,0,0,0,,现在 假设我想在时刻20做点什么 Dialogue: 0,0:38:05.31,0:38:07.90,Default,,0,0,0,,然而并没有时刻是20的SEGMENT Dialogue: 0,0:38:08.99,0:38:10.64,Default,,0,0,0,,我不得不构造一个新的SEGMENT Dialogue: 0,0:38:11.34,0:38:15.64,Default,,0,0,0,,我想把这个SEGMENT 放在10与30之间 Dialogue: 0,0:38:17.61,0:38:19.32,Default,,0,0,0,,这着实要花点功夫 Dialogue: 0,0:38:20.17,0:38:21.52,Default,,0,0,0,,先用CONS Dialogue: 0,0:38:24.26,0:38:29.94,Default,,0,0,0,,我要为这个AGENDA构建一个新的SEGMENT Dialogue: 0,0:38:33.60,0:38:34.81,Default,,0,0,0,,这里的连接必须要变 Dialogue: 0,0:38:35.40,0:38:36.30,Default,,0,0,0,,就像这样 Dialogue: 0,0:38:37.54,0:38:42.80,Default,,0,0,0,,我将要修改AGENDA的CDR部分的CDR部分 Dialogue: 0,0:38:44.88,0:38:49.45,Default,,0,0,0,,让它指向一个新的CONS单元 Dialogue: 0,0:38:50.11,0:38:54.65,Default,,0,0,0,,由一个新的SEGMENT和AGENDA的CDDDDR部分所构成的单元 Dialogue: 0,0:38:57.18,0:39:01.88,Default,,0,0,0,,我们有一个发生在20时刻的新的SEGMENT Dialogue: 0,0:39:02.30,0:39:03.72,Default,,0,0,0,,它自己维护了一个队列 Dialogue: 0,0:39:04.84,0:39:06.29,Default,,0,0,0,,这个队列中只有一个元素 Dialogue: 0,0:39:10.73,0:39:12.52,Default,,0,0,0,,如果我想在后面添加点什么 Dialogue: 0,0:39:12.54,0:39:15.87,Default,,0,0,0,,我就需要替换这个东西的CDR部分 Dialogue: 0,0:39:16.99,0:39:19.21,Default,,0,0,0,,替换掉这个表的CDR部分 Dialogue: 0,0:39:20.59,0:39:23.31,Default,,0,0,0,,我们就对该数据结构进行修改 Dialogue: 0,0:39:24.04,0:39:25.79,Default,,0,0,0,,因此我需要新的基本运算 Dialogue: 0,0:39:27.21,0:39:28.62,Default,,0,0,0,,因为原有的基础运算达不到这一点 Dialogue: 0,0:39:29.44,0:39:33.88,Default,,0,0,0,,如果我想在5时刻做点什么事 Dialogue: 0,0:39:37.12,0:39:39.20,Default,,0,0,0,,我就得去修改这个东西 Dialogue: 0,0:39:40.81,0:39:42.12,Default,,0,0,0,,因为我得添加到这里 Dialogue: 0,0:39:43.29,0:39:46.22,Default,,0,0,0,,这也就是我预留了一个“头”序对的原因 Dialogue: 0,0:39:47.56,0:39:48.59,Default,,0,0,0,,它预留了空间 Dialogue: 0,0:39:49.40,0:39:52.11,Default,,0,0,0,,我需要有空间去做改变 Dialogue: 0,0:39:53.88,0:39:56.56,Default,,0,0,0,,需要有存储空间 去改变 Dialogue: 0,0:39:58.60,0:40:02.54,Default,,0,0,0,,从AGENDA中删除东西并不困难 Dialogue: 0,0:40:02.54,0:40:04.62,Default,,0,0,0,,移除第一个元素相当容易 Dialogue: 0,0:40:04.92,0:40:06.14,Default,,0,0,0,,这也是我需要考虑的唯一情况 Dialogue: 0,0:40:06.49,0:40:10.19,Default,,0,0,0,,我可以先找到第一个SEGMENT Dialogue: 0,0:40:11.22,0:40:14.00,Default,,0,0,0,,先判断它的队列是否为空 Dialogue: 0,0:40:14.81,0:40:16.17,Default,,0,0,0,,如果队列不是空的 Dialogue: 0,0:40:16.32,0:40:18.62,Default,,0,0,0,,那么 我就会把元素从中删除 Dialogue: 0,0:40:19.21,0:40:19.74,Default,,0,0,0,,像这样 Dialogue: 0,0:40:20.10,0:40:21.92,Default,,0,0,0,,如果这时队列变为空的 Dialogue: 0,0:40:22.64,0:40:24.22,Default,,0,0,0,,就还要继续把SEGMENT删掉 Dialogue: 0,0:40:24.22,0:40:26.49,Default,,0,0,0,,然后 让这个单元指向这里 Dialogue: 0,0:40:28.22,0:40:31.08,Default,,0,0,0,,这个数据结构操作起来很复杂 Dialogue: 0,0:40:32.25,0:40:35.37,Default,,0,0,0,,它的具体实现也不是很有趣 Dialogue: 0,0:40:36.44,0:40:38.48,Default,,0,0,0,,现在我们来探讨一下队列 Dialogue: 0,0:40:38.92,0:40:39.76,Default,,0,0,0,,它们很相似 Dialogue: 0,0:40:41.16,0:40:43.52,Default,,0,0,0,,每一个AGENDA都有一个队列 Dialogue: 0,0:40:44.34,0:40:45.02,Default,,0,0,0,,队列是什么? Dialogue: 0,0:40:49.47,0:40:51.85,Default,,0,0,0,,队列能够进行下述基本运算: Dialogue: 0,0:40:52.78,0:41:02.17,Default,,0,0,0,,MAKE-QUEUE构建一个新队列 Dialogue: 0,0:41:07.77,0:41:17.10,Default,,0,0,0,,INSERT-QUEUE!向队列中插入新元素 Dialogue: 0,0:41:24.51,0:41:28.65,Default,,0,0,0,,DELETE-QUEUE!从队列中删除元素 Dialogue: 0,0:41:40.44,0:41:52.04,Default,,0,0,0,,FRONT-QUEUE查看队列中第一个元素 Dialogue: 0,0:41:53.13,0:41:55.14,Default,,0,0,0,,还需要检测队列是否为空 Dialogue: 0,0:42:07.11,0:42:08.70,Default,,0,0,0,,当你定义像这样的运算时 Dialogue: 0,0:42:09.02,0:42:10.44,Default,,0,0,0,,我希望你能够注意 Dialogue: 0,0:42:10.64,0:42:14.09,Default,,0,0,0,,按照我这样的习惯去为它们命名 Dialogue: 0,0:42:15.12,0:42:19.15,Default,,0,0,0,,“!”表示操作具有副作用 “?”代表定义谓词 Dialogue: 0,0:42:19.87,0:42:21.85,Default,,0,0,0,,就比如说 这里应该加上一个“!” Dialogue: 0,0:42:24.65,0:42:26.96,Default,,0,0,0,,嗯 空检测谓词的“?”也不要遗漏了 Dialogue: 0,0:42:29.24,0:42:30.72,Default,,0,0,0,,那么 我要如何构建一个队列呢? Dialogue: 0,0:42:31.72,0:42:34.11,Default,,0,0,0,,队列是一种 可以向其尾部添加东西 Dialogue: 0,0:42:35.12,0:42:36.83,Default,,0,0,0,,也可以从前面取出东西的结构 Dialogue: 0,0:42:37.84,0:42:40.51,Default,,0,0,0,,我可以从队列头删除元素 向队列尾添加元素 Dialogue: 0,0:42:41.23,0:42:43.24,Default,,0,0,0,,我可以用一种很简单的结构来实现 Dialogue: 0,0:42:43.88,0:42:45.72,Default,,0,0,0,,我们当然可以使用CONS来构造 Dialogue: 0,0:42:47.08,0:42:47.79,Default,,0,0,0,,这是一个队列 Dialogue: 0,0:42:49.91,0:42:52.36,Default,,0,0,0,,它有一个队列头 Dialogue: 0,0:42:53.58,0:42:54.92,Default,,0,0,0,,它包含两个部分 Dialogue: 0,0:42:55.28,0:42:56.25,Default,,0,0,0,,其中一个是头指针 Dialogue: 0,0:42:58.78,0:42:59.82,Default,,0,0,0,,另一个是尾指针 Dialogue: 0,0:43:03.12,0:43:06.33,Default,,0,0,0,,假设我有一个包含两个元素的队列 Dialogue: 0,0:43:09.13,0:43:12.09,Default,,0,0,0,,假设第一个元素是1 Dialogue: 0,0:43:12.46,0:43:16.53,Default,,0,0,0,,而第二个元素假定是2 Dialogue: 0,0:43:21.40,0:43:23.52,Default,,0,0,0,,我之所以要在这里设置两个指针 Dialogue: 0,0:43:24.09,0:43:25.61,Default,,0,0,0,,一个头指针和一个尾指针 Dialogue: 0,0:43:25.72,0:43:27.10,Default,,0,0,0,,这样 当向尾部添加元素的时候 Dialogue: 0,0:43:27.48,0:43:29.45,Default,,0,0,0,,就不用从最开始开始遍历 Dialogue: 0,0:43:31.85,0:43:34.80,Default,,0,0,0,,例如 我想要向队列添加入一个新元素 Dialogue: 0,0:43:35.26,0:43:41.02,Default,,0,0,0,,如果想添加一个稍后使用的元素 Dialogue: 0,0:43:41.08,0:43:42.40,Default,,0,0,0,,只需要先用CONS构建一个序对 Dialogue: 0,0:43:43.47,0:43:46.59,Default,,0,0,0,,假设它包含一个值 -- 3 Dialogue: 0,0:43:47.53,0:43:51.34,Default,,0,0,0,,再添加到队列里 Dialogue: 0,0:43:51.52,0:43:53.77,Default,,0,0,0,,这里就需要把这个元素CDR部分的指针 Dialogue: 0,0:43:56.94,0:43:58.76,Default,,0,0,0,,指向这个元素 Dialogue: 0,0:44:00.10,0:44:04.32,Default,,0,0,0,,同时也更新尾指针 让它指向新的地方 Dialogue: 0,0:44:09.12,0:44:12.68,Default,,0,0,0,,如果我想查看队列的第一个元素 Dialogue: 0,0:44:12.96,0:44:17.12,Default,,0,0,0,,我只需要通过头指针去寻找 即可轻松找到 Dialogue: 0,0:44:18.89,0:44:23.26,Default,,0,0,0,,如果我想调用DELETE-QUEUE删除元素 Dialogue: 0,0:44:24.14,0:44:26.35,Default,,0,0,0,,只需要把头指针向后移到就行 Dialogue: 0,0:44:27.71,0:44:29.31,Default,,0,0,0,,新的头指针指向这里 Dialogue: 0,0:44:31.70,0:44:33.13,Default,,0,0,0,,就是这么简单 Dialogue: 0,0:44:34.48,0:44:35.76,Default,,0,0,0,,为了实现这些操作 Dialogue: 0,0:44:37.24,0:44:40.83,Default,,0,0,0,,我们还需要一些新的基本运算 Dialogue: 0,0:44:41.48,0:44:42.56,Default,,0,0,0,,我先列出它们的名字 Dialogue: 0,0:44:42.99,0:44:46.28,Default,,0,0,0,,然后我们再来看 它们的原理和使用方法 Dialogue: 0,0:44:47.35,0:44:55.04,Default,,0,0,0,,SET-CAR!能够为序对的CAR部分 Dialogue: 0,0:44:55.88,0:44:59.36,Default,,0,0,0,,赋予一个新的值 Dialogue: 0,0:45:02.37,0:45:09.92,Default,,0,0,0,,SET-CDR!可以为序对的CDR部分赋新值 Dialogue: 0,0:45:13.02,0:45:14.78,Default,,0,0,0,,现在来看看它们到底做了什么 Dialogue: 0,0:45:16.03,0:45:20.51,Default,,0,0,0,,为了删除队列中的第一个元素 我需要修改这里的CAR部分 Dialogue: 0,0:45:20.96,0:45:22.52,Default,,0,0,0,,这是CAR部分 我需要修改它的值 Dialogue: 0,0:45:23.47,0:45:24.96,Default,,0,0,0,,我需要能够修改CDR部分 Dialogue: 0,0:45:25.28,0:45:27.08,Default,,0,0,0,,以便我能够移动尾指针 Dialogue: 0,0:45:27.21,0:45:28.76,Default,,0,0,0,,也使得我能够扩充队列 Dialogue: 0,0:45:30.16,0:45:31.60,Default,,0,0,0,,之前介绍的所有运算 Dialogue: 0,0:45:31.90,0:45:35.90,Default,,0,0,0,,上一块黑板上的所有东西 都是基于这些运算的 Dialogue: 0,0:45:38.17,0:45:40.14,Default,,0,0,0,,先讲到这里 大家休息一下 Dialogue: 0,0:45:41.24,0:45:52.67,Default,,0,0,0,,[音乐] Dialogue: 0,0:45:52.67,0:45:57.84,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:46:18.64,0:46:22.80,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:46:22.80,0:46:27.15,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:46:27.16,0:46:30.76,Declare,,0,0,0,,{\an2\fad(500,500)}计算对象 Dialogue: 0,0:46:38.81,0:46:43.53,Default,,0,0,0,,最初 我们说序对是通过CONS构造而来的 Dialogue: 0,0:46:44.57,0:46:46.80,Default,,0,0,0,,我们提到了几条公理 Dialogue: 0,0:46:48.09,0:46:50.76,Default,,0,0,0,,它们是怎样的呢? 它们是形如 -- Dialogue: 0,0:46:52.28,0:47:03.64,Default,,0,0,0,,对于任意的X和Y (CAR (CONS X Y)) = X Dialogue: 0,0:47:05.31,0:47:12.92,Default,,0,0,0,,以及 (CDR (CONS X Y)) = Y Dialogue: 0,0:47:14.80,0:47:20.00,Default,,0,0,0,,但是 它们并没有陈述CONS单元 是否有像人一样的“身份” Dialogue: 0,0:47:21.85,0:47:25.58,Default,,0,0,0,,实际上 它描述的是一种抽象 Dialogue: 0,0:47:25.74,0:47:27.95,Default,,0,0,0,,也就是CONS是由几个部分组成 Dialogue: 0,0:47:29.74,0:47:33.18,Default,,0,0,0,,如果两个CONS组成部分相同的 它俩则是同样的 Dialogue: 0,0:47:33.93,0:47:35.71,Default,,0,0,0,,至少从这些公理来看是这样的 Dialogue: 0,0:47:37.32,0:47:39.21,Default,,0,0,0,,但是引入了赋值以后 Dialogue: 0,0:47:39.84,0:47:42.32,Default,,0,0,0,,实际上 可变数据就是一种赋值 Dialogue: 0,0:47:42.88,0:47:44.43,Default,,0,0,0,,我们有SET-CAR!和SET-CDR! Dialogue: 0,0:47:45.55,0:47:48.94,Default,,0,0,0,,引入这些运算后 这些公理就不完整了 Dialogue: 0,0:47:49.83,0:47:52.03,Default,,0,0,0,,但是这里写的也是对的 Dialogue: 0,0:47:53.25,0:47:54.94,Default,,0,0,0,,只不过描述的不再完整 Dialogue: 0,0:47:56.07,0:48:01.68,Default,,0,0,0,,因为如果我要修改一个特定的CONS的CAR部分 Dialogue: 0,0:48:03.02,0:48:04.03,Default,,0,0,0,,问题是 Dialogue: 0,0:48:04.24,0:48:08.64,Default,,0,0,0,,我会同时修改到相同CONS单元的CAR部分么? Dialogue: 0,0:48:10.09,0:48:13.04,Default,,0,0,0,,假如我用CONS来构建有理数 Dialogue: 0,0:48:14.86,0:48:17.10,Default,,0,0,0,,比如说3/4 Dialogue: 0,0:48:17.34,0:48:20.25,Default,,0,0,0,,假设我有两个3/4 Dialogue: 0,0:48:21.57,0:48:22.75,Default,,0,0,0,,这两个一样吗? Dialogue: 0,0:48:24.06,0:48:24.89,Default,,0,0,0,,或者又不一样? Dialogue: 0,0:48:25.34,0:48:26.96,Default,,0,0,0,,当然 对于数字来说 这并不重要 Dialogue: 0,0:48:27.86,0:48:30.49,Default,,0,0,0,,修改一个数的分母并没有数学意义 Dialogue: 0,0:48:33.02,0:48:35.32,Default,,0,0,0,,我们只能够说创建一个数 具有不同的分母 Dialogue: 0,0:48:36.84,0:48:39.88,Default,,0,0,0,,而直接修改一个数的分母这种观念 Dialogue: 0,0:48:40.00,0:48:43.58,Default,,0,0,0,,在数学意义上是一种非常奇怪而不受支持的行为 Dialogue: 0,0:48:44.77,0:48:47.40,Default,,0,0,0,,然而 当这些CONS单元表示的是现实世界中的事物 Dialogue: 0,0:48:48.97,0:48:50.43,Default,,0,0,0,,那么修改它的CAR部分 Dialogue: 0,0:48:50.60,0:48:52.20,Default,,0,0,0,,就像除掉指甲壳的一块一样 Dialogue: 0,0:48:53.69,0:48:56.56,Default,,0,0,0,,所以 每一个CONS都有自己的“身份” Dialogue: 0,0:48:57.77,0:48:59.92,Default,,0,0,0,,我来先说明“身份”是什么意思 Dialogue: 0,0:49:01.28,0:49:03.05,Default,,0,0,0,,来看些例子 Dialogue: 0,0:49:04.32,0:49:15.20,Default,,0,0,0,,假如(DEFINE A (CONS 1 2)) Dialogue: 0,0:49:18.32,0:49:19.76,Default,,0,0,0,,这是代表什么呢? 首先 Dialogue: 0,0:49:20.67,0:49:25.20,Default,,0,0,0,,这是说我在某个环境中创建了符号A Dialogue: 0,0:49:25.96,0:49:28.67,Default,,0,0,0,,而它的值是一个序对 Dialogue: 0,0:49:29.47,0:49:34.06,Default,,0,0,0,,这个序对由两个分别指向1和2的指针组成 Dialogue: 0,0:49:35.34,0:49:36.16,Default,,0,0,0,,就像这样 Dialogue: 0,0:49:38.12,0:49:39.60,Default,,0,0,0,,又假设 Dialogue: 0,0:49:40.22,0:49:47.58,Default,,0,0,0,,(DEFINE B (CONS A A)) Dialogue: 0,0:49:53.88,0:49:56.81,Default,,0,0,0,,虽然无所谓 不过我还是更喜欢用大写 Dialogue: 0,0:49:57.63,0:49:59.88,Default,,0,0,0,,(DEFINE B (CONS A A)) Dialogue: 0,0:50:03.97,0:50:06.03,Default,,0,0,0,,这里用了两次A Dialogue: 0,0:50:07.84,0:50:10.57,Default,,0,0,0,,现在就要考虑序对的身份问题了 Dialogue: 0,0:50:11.30,0:50:12.64,Default,,0,0,0,,这两个A是同一个东西 Dialogue: 0,0:50:13.69,0:50:14.81,Default,,0,0,0,,这也就是说 Dialogue: 0,0:50:15.29,0:50:17.61,Default,,0,0,0,,我创建了另一个序对 Dialogue: 0,0:50:18.81,0:50:20.20,Default,,0,0,0,,我把它记作B Dialogue: 0,0:50:22.38,0:50:27.60,Default,,0,0,0,,它由两个指向A的指针组成 Dialogue: 0,0:50:28.92,0:50:32.20,Default,,0,0,0,,对于这个对象来说 此时我有三个名字来指称它 Dialogue: 0,0:50:33.10,0:50:34.16,Default,,0,0,0,,A是一个 Dialogue: 0,0:50:34.88,0:50:36.46,Default,,0,0,0,,(CAR B)是一个 Dialogue: 0,0:50:37.23,0:50:38.86,Default,,0,0,0,,(CDR B)也是一个 Dialogue: 0,0:50:39.36,0:50:41.15,Default,,0,0,0,,都是这个序对的别名 Dialogue: 0,0:50:44.23,0:50:49.28,Default,,0,0,0,,假设现在我要执行 Dialogue: 0,0:50:53.77,0:51:08.38,Default,,0,0,0,,(SET-CAR! (CAR B) 3) Dialogue: 0,0:51:12.75,0:51:17.45,Default,,0,0,0,,我先去找B的CAR部分 也就是它 Dialogue: 0,0:51:17.83,0:51:20.93,Default,,0,0,0,,再修改它的CAR部分 修改为3 Dialogue: 0,0:51:24.76,0:51:25.69,Default,,0,0,0,,这样我也就修改了A Dialogue: 0,0:51:27.24,0:51:33.64,Default,,0,0,0,,如果我问 现在A的CAR部分是多少 Dialogue: 0,0:51:35.34,0:51:37.56,Default,,0,0,0,,结果是3 Dialogue: 0,0:51:38.68,0:51:43.39,Default,,0,0,0,,尽管在这里 A是由1和2构成的序对 Dialogue: 0,0:51:45.29,0:51:47.44,Default,,0,0,0,,我通过改变B而改变了A Dialogue: 0,0:51:48.56,0:51:49.64,Default,,0,0,0,,它们之间存在共享 Dialogue: 0,0:51:52.25,0:51:53.47,Default,,0,0,0,,有时候我们需要这样的结构 Dialogue: 0,0:51:54.24,0:51:56.12,Default,,0,0,0,,当然 在类似于队列这类的数据结构中 Dialogue: 0,0:51:56.24,0:52:02.38,Default,,0,0,0,,我们正是这样来定义、组织数据结果来获得数据共享的 Dialogue: 0,0:52:04.35,0:52:05.66,Default,,0,0,0,,但是有一些非预期的共享 Dialogue: 0,0:52:07.76,0:52:09.72,Default,,0,0,0,,对象间的非预期交互 Dialogue: 0,0:52:10.78,0:52:14.08,Default,,0,0,0,,是大型程序中产生的BUG的主要来源 Dialogue: 0,0:52:15.44,0:52:21.66,Default,,0,0,0,,通过使对象具有“身份”、允许共享 Dialogue: 0,0:52:21.87,0:52:23.76,Default,,0,0,0,,给同一个对象取多个别名 Dialogue: 0,0:52:24.08,0:52:25.05,Default,,0,0,0,,我们获得了强大的能力 Dialogue: 0,0:52:25.13,0:52:28.46,Default,,0,0,0,,但是同时也为此引出的BUG和复杂度而付出代价 Dialogue: 0,0:52:32.19,0:52:36.24,Default,,0,0,0,,为了把这个讲透彻一点 我们再举一个例子 Dialogue: 0,0:52:37.10,0:52:39.87,Default,,0,0,0,,比如(CADR B) Dialogue: 0,0:52:42.46,0:52:46.56,Default,,0,0,0,,看起来和(CAR B)没有一点关系 Dialogue: 0,0:52:46.88,0:52:49.02,Default,,0,0,0,,但是它的值是什么? Dialogue: 0,0:52:49.35,0:52:53.56,Default,,0,0,0,,先取B的CDR部分 再取结果的CAR部分 Dialogue: 0,0:52:53.56,0:52:54.86,Default,,0,0,0,,哦 还是3 Dialogue: 0,0:52:56.48,0:53:00.43,Default,,0,0,0,,有了共享这样的机制 局部的含义也不是那么清楚了 Dialogue: 0,0:53:01.12,0:53:02.48,Default,,0,0,0,,所以我们要非常小心的操作 Dialogue: 0,0:53:06.64,0:53:12.64,Default,,0,0,0,,目前为止 我已经介绍了好几个赋值运算 Dialogue: 0,0:53:13.18,0:53:17.61,Default,,0,0,0,,比如SET!、SET-CAR!、SET-CDR! Dialogue: 0,0:53:18.51,0:53:21.39,Default,,0,0,0,,或许我应该不用SET-CAR!、SET-CDR! 它们引入太多问题了 Dialogue: 0,0:53:22.82,0:53:23.66,Default,,0,0,0,,而事实则是 Dialogue: 0,0:53:24.12,0:53:26.11,Default,,0,0,0,,一旦把骆驼的鼻子牵进帐篷 Dialogue: 0,0:53:26.24,0:53:27.34,Default,,0,0,0,,它的身体可就自己跟进来了 Dialogue: 0,0:53:30.16,0:53:31.26,Default,,0,0,0,,只要有SET! Dialogue: 0,0:53:31.61,0:53:35.85,Default,,0,0,0,,这些糟糕的东西都可能发生 Dialogue: 0,0:53:38.55,0:53:39.80,Default,,0,0,0,,我们来分析一下 Dialogue: 0,0:53:40.69,0:53:43.72,Default,,0,0,0,,前些日子 讲到复合数据的时候 Dialogue: 0,0:53:45.13,0:53:51.20,Default,,0,0,0,,哈罗德教授向你们展示了 用消息接收的方式来定义CONS Dialogue: 0,0:53:52.48,0:53:56.06,Default,,0,0,0,,我将给你们展示一种更加糟糕的方式 Dialogue: 0,0:53:57.13,0:54:00.04,Default,,0,0,0,,凭“空”定义CONS Dialogue: 0,0:54:02.56,0:54:03.02,Default,,0,0,0,,“什么”都不用 Dialogue: 0,0:54:04.44,0:54:08.12,Default,,0,0,0,,用传统的函数式的方法如何定义CONS呢? Dialogue: 0,0:54:09.26,0:54:11.66,Default,,0,0,0,,纯粹只用LAMBDA表达式 Dialogue: 0,0:54:13.39,0:54:14.40,Default,,0,0,0,,把序对表示成过程 Dialogue: 0,0:54:17.39,0:54:19.66,Default,,0,0,0,,现在我要修改这个定义 Dialogue: 0,0:54:20.30,0:54:23.16,Default,,0,0,0,,使得只具有一种赋值 Dialogue: 0,0:54:24.28,0:54:27.93,Default,,0,0,0,,用SET!来代替SET-CAR!和SET-CDR! Dialogue: 0,0:54:28.58,0:54:37.39,Default,,0,0,0,,如果我把CONS定义为 Dialogue: 0,0:54:38.91,0:54:42.56,Default,,0,0,0,,定义为一个过程 该过程接收参数M Dialogue: 0,0:54:43.39,0:54:46.32,Default,,0,0,0,,该过程将M应用在X与Y上 Dialogue: 0,0:54:51.12,0:54:53.10,Default,,0,0,0,,这是阿隆佐·丘奇发明的方法 Dialogue: 0,0:54:53.77,0:54:55.72,Default,,0,0,0,,他是20世纪最伟大的程序员 Dialogue: 0,0:54:55.79,0:54:57.15,Default,,0,0,0,,尽管当时电脑还没有被发明 Dialogue: 0,0:54:57.87,0:54:59.13,Default,,0,0,0,,但他在20世纪30年代就提出了这个方法 Dialogue: 0,0:54:59.42,0:55:02.22,Default,,0,0,0,,他是一个逻辑学家 在普林斯顿大学做研究 Dialogue: 0,0:55:08.66,0:55:10.43,Default,,0,0,0,,定义(CAR X)为 Dialogue: 0,0:55:13.10,0:55:16.92,Default,,0,0,0,,把X应用在一个二元过程上 Dialogue: 0,0:55:17.15,0:55:20.60,Default,,0,0,0,,参数分别是A和D 而结果是选出A Dialogue: 0,0:55:23.71,0:55:24.97,Default,,0,0,0,,而(CDR X)则是 Dialogue: 0,0:55:33.10,0:55:34.78,Default,,0,0,0,,这样的一个过程 Dialogue: 0,0:55:35.08,0:55:40.25,Default,,0,0,0,,把X应用在一个参数分别是A和D的过程上 Dialogue: 0,0:55:40.92,0:55:42.04,Default,,0,0,0,,该过程选择出D Dialogue: 0,0:55:46.67,0:55:49.88,Default,,0,0,0,,可能你们还没意识到这些就是CAR、CDR和CONS Dialogue: 0,0:55:50.51,0:55:53.61,Default,,0,0,0,,但我将要给你们演示它符合之前的公理 Dialogue: 0,0:55:54.11,0:55:54.81,Default,,0,0,0,,举一个例子 Dialogue: 0,0:55:55.61,0:55:57.56,Default,,0,0,0,,我们来看一下 Dialogue: 0,0:55:58.29,0:56:06.27,Default,,0,0,0,,考虑一下语句语句(CAR (CONS 35 47)) Dialogue: 0,0:56:09.93,0:56:10.96,Default,,0,0,0,,它的结果是多少呢? Dialogue: 0,0:56:11.12,0:56:15.24,Default,,0,0,0,,它是通过把35和47代换进 Dialogue: 0,0:56:15.37,0:56:18.20,Default,,0,0,0,,语句体中的X和Y得到的 Dialogue: 0,0:56:19.71,0:56:20.69,Default,,0,0,0,,非常容易 Dialogue: 0,0:56:20.69,0:56:30.88,Default,,0,0,0,,就得到了语句(CAR (LAMBDA (M) (M 35 47))) Dialogue: 0,0:56:35.53,0:56:39.36,Default,,0,0,0,,这个的结果是把这个对象 Dialogue: 0,0:56:39.44,0:56:41.85,Default,,0,0,0,,代换进这里的X而得到的 Dialogue: 0,0:56:42.83,0:56:47.66,Default,,0,0,0,,代换的结果是((LAMBDA (M -- Dialogue: 0,0:56:48.33,0:56:52.19,Default,,0,0,0,,用这个对象代换这里的X Dialogue: 0,0:56:52.88,0:56:54.35,Default,,0,0,0,,这是表的头部 Dialogue: 0,0:56:54.88,0:57:00.32,Default,,0,0,0,,体的部分是(M 35 47) Dialogue: 0,0:57:03.10,0:57:07.31,Default,,0,0,0,,把它应用于一个参数分别的A和D的过程上 Dialogue: 0,0:57:07.48,0:57:08.67,Default,,0,0,0,,后者返回参数A Dialogue: 0,0:57:10.91,0:57:14.62,Default,,0,0,0,,然后我们用这个来代换这里的M Dialogue: 0,0:57:15.96,0:57:21.71,Default,,0,0,0,,这个就相当于把(LAMBDA (A D) A) Dialogue: 0,0:57:22.22,0:57:24.84,Default,,0,0,0,,应用在35和47上 Dialogue: 0,0:57:26.33,0:57:27.37,Default,,0,0,0,,结果就是35 Dialogue: 0,0:57:27.40,0:57:31.21,Default,,0,0,0,,它就是用35和47分别代换A、D 最后返回A Dialogue: 0,0:57:35.60,0:57:37.24,Default,,0,0,0,,所以我根本不需要任何数据 Dialogue: 0,0:57:37.88,0:57:38.75,Default,,0,0,0,,甚至连数字都不需要 Dialogue: 0,0:57:40.92,0:57:42.64,Default,,0,0,0,,这就是 阿隆佐·邱奇的技巧 Dialogue: 0,0:57:52.42,0:57:56.17,Default,,0,0,0,,现在呢我们来对这个定义做点修改 Dialogue: 0,0:57:56.76,0:57:58.49,Default,,0,0,0,,作为逻辑学家 他可能会不太开心 Dialogue: 0,0:57:59.20,0:58:01.96,Default,,0,0,0,,但作为程序员 -- 请看投影仪 Dialogue: 0,0:58:03.26,0:58:04.16,Default,,0,0,0,,我们来看看 Dialogue: 0,0:58:05.39,0:58:07.58,Default,,0,0,0,,我修改了CONS的定义 Dialogue: 0,0:58:09.57,0:58:12.35,Default,,0,0,0,,和丘奇的定义很相似 但是不完全相同 Dialogue: 0,0:58:14.41,0:58:15.50,Default,,0,0,0,,具体到底是什么? Dialogue: 0,0:58:16.07,0:58:18.72,Default,,0,0,0,,CONS有两个参数:X和Y Dialogue: 0,0:58:19.50,0:58:22.51,Default,,0,0,0,,但它返回一个参数为M的过程 Dialogue: 0,0:58:23.39,0:58:25.64,Default,,0,0,0,,跟之前一样M会应用于X和Y上 Dialogue: 0,0:58:26.19,0:58:29.29,Default,,0,0,0,,但它额外还有两个“许可” Dialogue: 0,0:58:30.17,0:58:32.01,Default,,0,0,0,,其中一个是把X赋值为N Dialogue: 0,0:58:32.60,0:58:34.40,Default,,0,0,0,,另一个则是把Y赋值为N Dialogue: 0,0:58:34.44,0:58:35.68,Default,,0,0,0,,只要我提供了相应的N Dialogue: 0,0:58:40.94,0:58:44.72,Default,,0,0,0,,所以出了邱奇原本的定义之外 Dialogue: 0,0:58:45.72,0:58:51.66,Default,,0,0,0,,最大的不同在于CONS的返回值 Dialogue: 0,0:58:52.12,0:58:53.82,Default,,0,0,0,,不单会把它的参数应用于 Dialogue: 0,0:58:54.91,0:58:59.44,Default,,0,0,0,,用于构成序对的X和Y之上 Dialogue: 0,0:58:59.69,0:59:03.58,Default,,0,0,0,,它还有用于为X和Y赋值的两个“许可” Dialogue: 0,0:59:06.54,0:59:08.08,Default,,0,0,0,,当然 就如之前一样 Dialogue: 0,0:59:08.83,0:59:10.51,Default,,0,0,0,,CAR看起来也很相似 Dialogue: 0,0:59:11.69,0:59:14.36,Default,,0,0,0,,就像邱奇定义的那样 Dialogue: 0,0:59:14.54,0:59:16.00,Default,,0,0,0,,(CAR X)只不过是把X应用在 Dialogue: 0,0:59:16.86,0:59:19.00,Default,,0,0,0,,过程上 -- 本例中是四个参数 Dialogue: 0,0:59:19.29,0:59:21.04,Default,,0,0,0,,然后从中选出第一个 Dialogue: 0,0:59:22.54,0:59:24.16,Default,,0,0,0,,这就和之前一样 Dialogue: 0,0:59:25.42,0:59:26.96,Default,,0,0,0,,结果将会返回X Dialogue: 0,0:59:29.04,0:59:35.40,Default,,0,0,0,,X的值被包含在求值这个LAMBDA表达式所产生的过程中 Dialogue: 0,0:59:35.45,0:59:37.84,Default,,0,0,0,,X和Y的值也是在这个环境中定义的 Dialogue: 0,0:59:41.94,0:59:43.15,Default,,0,0,0,,这是我们对CONS的定义 Dialogue: 0,0:59:45.64,0:59:47.53,Default,,0,0,0,,那么 激动人心的地方来了 Dialogue: 0,0:59:47.73,0:59:48.96,Default,,0,0,0,,当然CDR的定义也类似 Dialogue: 0,0:59:49.39,0:59:50.35,Default,,0,0,0,,激动人心的地方 Dialogue: 0,0:59:51.23,0:59:52.52,Default,,0,0,0,,SET-CAR!和SET-CDR!的实现 Dialogue: 0,0:59:53.45,0:59:55.52,Default,,0,0,0,,说实话 它们也不是特别复杂 Dialogue: 0,0:59:55.80,1:00:00.64,Default,,0,0,0,,语句(SET-CAR! X Y) Dialogue: 0,1:00:01.63,1:00:03.85,Default,,0,0,0,,无非就是把序对X应用于 Dialogue: 0,1:00:04.11,1:00:06.76,Default,,0,0,0,,注意X是一个一元过程 Dialogue: 0,1:00:07.69,1:00:09.80,Default,,0,0,0,,该过程的体是将参数应用在四个对象上 Dialogue: 0,1:00:11.24,1:00:15.85,Default,,0,0,0,,我们把X应用于一个四元过程上 Dialogue: 0,1:00:16.00,1:00:18.08,Default,,0,0,0,,X的值、Y的值 Dialogue: 0,1:00:18.32,1:00:20.54,Default,,0,0,0,,修改X的许可、修改Y的许可 Dialogue: 0,1:00:21.32,1:00:26.09,Default,,0,0,0,,语句的体则是用相应的许可 将X设置为新的值 Dialogue: 0,1:00:31.65,1:00:33.54,Default,,0,0,0,,当然SET-CDR!和它类似 Dialogue: 0,1:00:36.25,1:00:39.44,Default,,0,0,0,,你也看到了 我这里并没有引入新的基本运算 Dialogue: 0,1:00:40.11,1:00:44.36,Default,,0,0,0,,具体要不要这样来实现是一个工程性问题 Dialogue: 0,1:00:45.34,1:00:47.39,Default,,0,0,0,,当然出于工程上的考量 Dialogue: 0,1:00:48.09,1:00:49.63,Default,,0,0,0,,我不会这样来实现 Dialogue: 0,1:00:51.68,1:00:53.40,Default,,0,0,0,,但是从原理上来说 Dialogue: 0,1:00:54.28,1:00:56.43,Default,,0,0,0,,一旦引入了赋值运算 Dialogue: 0,1:00:56.96,1:00:58.76,Default,,0,0,0,,我就可以进行各种各样的赋值运算了 Dialogue: 0,1:01:05.42,1:01:06.67,Default,,0,0,0,,有什么问题吗? Dialogue: 0,1:01:09.20,1:01:10.89,Default,,0,0,0,,请讲 Dialogue: 0,1:01:12.04,1:01:15.64,Default,,0,0,0,,我可以跟的上你的思路 直到 -- Dialogue: 0,1:01:15.64,1:01:17.61,Default,,0,0,0,,在许可那里 Dialogue: 0,1:01:18.14,1:01:21.64,Default,,0,0,0,,我们把CONS定义为一个参数为N的过程 Dialogue: 0,1:01:21.80,1:01:24.21,Default,,0,0,0,,我不知道这个参数是什么时候传进来的 Dialogue: 0,1:01:24.21,1:01:25.69,Default,,0,0,0,,教授:哦 抱歉 我给你演示一下 Dialogue: 0,1:01:26.34,1:01:27.05,Default,,0,0,0,,我们来推演一下 Dialogue: 0,1:01:27.36,1:01:29.07,Default,,0,0,0,,虽然在黑板上推演更清晰 Dialogue: 0,1:01:29.18,1:01:30.17,Default,,0,0,0,,但这并不难懂 Dialogue: 0,1:01:30.17,1:01:31.47,Default,,0,0,0,,我就将就用投影仪了 Dialogue: 0,1:01:32.45,1:01:35.79,Default,,0,0,0,,调用(SET-CDR! X Y)会发生什么呢? Dialogue: 0,1:01:37.79,1:01:39.66,Default,,0,0,0,,就在这里(SET-CDR! X Y) Dialogue: 0,1:01:40.36,1:01:41.92,Default,,0,0,0,,X可能是一个序对 Dialogue: 0,1:01:43.31,1:01:45.24,Default,,0,0,0,,或者说对一个CONS表达式求值得到的结果 Dialogue: 0,1:01:45.88,1:01:46.35,Default,,0,0,0,,能跟上吧? Dialogue: 0,1:01:46.89,1:01:49.96,Default,,0,0,0,,也就是说 X是由这里的代码构造出来的 Dialogue: 0,1:01:52.57,1:01:56.49,Default,,0,0,0,,这里的X是求值这个LAMBDA表达式得到的 Dialogue: 0,1:01:58.11,1:01:58.49,Default,,0,0,0,,对吧 Dialogue: 0,1:01:59.38,1:02:01.63,Default,,0,0,0,,因此当我对这个LAMBDA表达式求值时 Dialogue: 0,1:02:04.01,1:02:08.76,Default,,0,0,0,,我是在定义CONS时的一个环境里求值的 Dialogue: 0,1:02:11.75,1:02:15.18,Default,,0,0,0,,这也就是说 作为LAMBDA表达式中的自由变量 Dialogue: 0,1:02:16.25,1:02:18.68,Default,,0,0,0,,X和Y都存储一个框架中 Dialogue: 0,1:02:18.72,1:02:22.44,Default,,0,0,0,,也就是这整个LAMBDA表达式的父框架 Dialogue: 0,1:02:23.23,1:02:25.82,Default,,0,0,0,,因此在这个LAMBDA语句中 Dialogue: 0,1:02:26.65,1:02:28.51,Default,,0,0,0,,X和Y都有存储空间 Dialogue: 0,1:02:29.25,1:02:30.83,Default,,0,0,0,,也可以对它们赋值 Dialogue: 0,1:02:31.91,1:02:36.08,Default,,0,0,0,,这里赋值为N是通过参数来传递的 Dialogue: 0,1:02:37.26,1:02:39.31,Default,,0,0,0,,“许可”就是一个过程 Dialogue: 0,1:02:41.40,1:02:43.18,Default,,0,0,0,,它将作为M的一个参数 Dialogue: 0,1:02:43.29,1:02:46.51,Default,,0,0,0,,它实际上是CONS生成的对象的一部分 Dialogue: 0,1:02:47.94,1:02:50.91,Default,,0,0,0,,我们再来看看SET-CDR! Dialogue: 0,1:02:52.11,1:02:55.42,Default,,0,0,0,,SET-CDR!的第一个参数X是一个序对 Dialogue: 0,1:02:56.12,1:02:57.48,Default,,0,0,0,,被传递了一个参数 Dialogue: 0,1:02:59.77,1:03:02.22,Default,,0,0,0,,这个是一个四元过程 Dialogue: 0,1:03:02.32,1:03:04.65,Default,,0,0,0,,这是因为 它要作为这里的M Dialogue: 0,1:03:04.99,1:03:06.56,Default,,0,0,0,,要应用在四个对象上 Dialogue: 0,1:03:07.92,1:03:13.34,Default,,0,0,0,,这边的这个SD 就对应于这个过程 Dialogue: 0,1:03:15.47,1:03:19.93,Default,,0,0,0,,当我执行SD 把它应用于Y Dialogue: 0,1:03:22.91,1:03:24.04,Default,,0,0,0,,这个Y是这里传过来的 Dialogue: 0,1:03:25.37,1:03:26.92,Default,,0,0,0,,学生:那-- Dialogue: 0,1:03:27.00,1:03:32.19,Default,,0,0,0,,教授:所以说 这里的N就对应于这里的Y Dialogue: 0,1:03:34.04,1:03:34.52,Default,,0,0,0,,明白了吧 Dialogue: 0,1:03:34.81,1:03:35.75,Default,,0,0,0,,了解了 Dialogue: 0,1:03:35.75,1:03:37.29,Default,,0,0,0,,当你执行SET-CDR!的时候 Dialogue: 0,1:03:39.07,1:03:41.97,Default,,0,0,0,,X是CDR部分要赋值的新值 Dialogue: 0,1:03:41.97,1:03:44.03,Default,,0,0,0,,教授:这里的X Dialogue: 0,1:03:44.96,1:03:46.20,Default,,0,0,0,,哦 指错了 Dialogue: 0,1:03:46.20,1:03:48.33,Default,,0,0,0,,这里的X是指 -- SET-CDR!有两个参数 Dialogue: 0,1:03:48.91,1:03:50.36,Default,,0,0,0,,一个是被修改的序对 Dialogue: 0,1:03:51.34,1:03:53.93,Default,,0,0,0,,还有就是新值 Dialogue: 0,1:03:56.15,1:03:58.32,Default,,0,0,0,,你可以代换回去看看 就很清楚了 Dialogue: 0,1:04:02.17,1:04:03.16,Default,,0,0,0,,还有什么问题吗? Dialogue: 0,1:04:07.88,1:04:08.64,Default,,0,0,0,,好的 Dialogue: 0,1:04:08.64,1:04:09.52,Default,,0,0,0,,这节课就到这里 Dialogue: 0,1:04:10.44,1:04:28.73,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:04:10.44,1:04:28.73,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec5b.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: EN Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Video Position: 1 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:10.10,0:00:14.60,EN,,0,0,0,,Computational Objects Dialogue: 0,0:00:21.17,0:00:24.12,EN,,0,0,0,,PROFESSOR: Well, now that we've given you some power Dialogue: 0,0:00:24.43,0:00:27.40,EN,,0,0,0,,to make independent local state and to model objects, Dialogue: 0,0:00:28.33,0:00:32.67,EN,,0,0,0,,I thought we'd do a bit of programming of a very complicated kind, Dialogue: 0,0:00:34.03,0:00:36.36,EN,,0,0,0,,just to illustrate what you can do with this sort of thing. Dialogue: 0,0:00:40.43,0:00:43.48,EN,,0,0,0,,I suppose, as I said, we were motivated by physical systems Dialogue: 0,0:00:44.11,0:00:46.25,EN,,0,0,0,,the ways we like to think about physical systems, Dialogue: 0,0:00:46.99,0:00:51.08,EN,,0,0,0,,which is that there are these things that the world is made out of. Dialogue: 0,0:00:52.06,0:00:55.98,EN,,0,0,0,,And each of these things has particular independent local state, Dialogue: 0,0:00:57.24,0:00:59.87,EN,,0,0,0,,and therefore it is a thing. That's what makes it a thing. Dialogue: 0,0:01:01.28,0:01:04.27,EN,,0,0,0,,And then we're going to say that in the model in the world Dialogue: 0,0:01:04.28,0:01:09.90,EN,,0,0,0,,we have a world and a model in our minds and in the computer of that world. Dialogue: 0,0:01:10.94,0:01:12.54,EN,,0,0,0,,And what I want to make is a correspondence Dialogue: 0,0:01:12.78,0:01:15.21,EN,,0,0,0,,between the objects in the world and the objects in the computer, Dialogue: 0,0:01:15.87,0:01:17.74,EN,,0,0,0,,the relationships between the objects in the world Dialogue: 0,0:01:17.96,0:01:21.72,EN,,0,0,0,,and the relationships between those same obj...--the model objects in the computer, Dialogue: 0,0:01:23.18,0:01:25.52,EN,,0,0,0,,and the functions that relate things in the Dialogue: 0,0:01:25.93,0:01:28.11,EN,,0,0,0,,to the functions that relate things in the computer. Dialogue: 0,0:01:30.84,0:01:33.82,EN,,0,0,0,,This buys us modularity. Dialogue: 0,0:01:34.74,0:01:36.75,EN,,0,0,0,,If we really believe the world is like that, Dialogue: 0,0:01:37.36,0:01:38.72,EN,,0,0,0,,that it's made out of these little pieces, Dialogue: 0,0:01:39.20,0:01:41.47,EN,,0,0,0,,and of course we could arrange our world to be like that, Dialogue: 0,0:01:42.03,0:01:43.95,EN,,0,0,0,,we could only model those things that are like that, Dialogue: 0,0:01:45.45,0:01:49.02,EN,,0,0,0,,then we can inherit the modularity in the world into our programming. Dialogue: 0,0:01:50.45,0:01:53.58,EN,,0,0,0,,That's why we would invent some of this object-oriented programming. Dialogue: 0,0:01:55.42,0:01:58.19,EN,,0,0,0,,Well, let's take the best kind of objects I know. Dialogue: 0,0:01:58.89,0:02:04.17,EN,,0,0,0,,They're completely--they're completely wonderful: electrical systems. Dialogue: 0,0:02:06.40,0:02:12.99,EN,,0,0,0,,Electrical systems really are the physicist's best, best objects. Dialogue: 0,0:02:14.22,0:02:16.76,EN,,0,0,0,,You see over here I have some piece of machinery. Dialogue: 0,0:02:17.12,0:02:18.28,EN,,0,0,0,,Right here's a piece of machinery. Dialogue: 0,0:02:20.04,0:02:22.88,EN,,0,0,0,,And it's got an electrical wire connecting Dialogue: 0,0:02:23.66,0:02:26.40,EN,,0,0,0,,one part of the machinery with another part of the machinery. Dialogue: 0,0:02:27.56,0:02:30.86,EN,,0,0,0,,And one of the wonderful properties of the electrical world Dialogue: 0,0:02:31.64,0:02:33.12,EN,,0,0,0,,is that I can say this is an object, Dialogue: 0,0:02:34.01,0:02:34.97,EN,,0,0,0,,and this is an object, Dialogue: 0,0:02:35.71,0:02:37.53,EN,,0,0,0,,and they're-- the connection between them is clear. Dialogue: 0,0:02:38.24,0:02:43.32,EN,,0,0,0,,In principle, there is no connection that I didn't describe with these wires. Dialogue: 0,0:02:44.74,0:02:46.12,EN,,0,0,0,,Let's say if I have light bulbs, Dialogue: 0,0:02:46.52,0:02:50.32,EN,,0,0,0,,Let's say if I have light bulbs, a light bulb and a power supply that's plugged into the outlet. Dialogue: 0,0:02:51.63,0:02:53.53,EN,,0,0,0,,Then the connection is perfectly clear. Dialogue: 0,0:02:53.62,0:02:55.42,EN,,0,0,0,,There's no other connections that we know of. Dialogue: 0,0:02:56.22,0:03:02.33,EN,,0,0,0,,If I were to tie a knot in the wire that connects the light bulb to the power supply, Dialogue: 0,0:03:02.68,0:03:03.64,EN,,0,0,0,,the light remains lit up. Dialogue: 0,0:03:04.04,0:03:04.76,EN,,0,0,0,,It doesn't care. Dialogue: 0,0:03:07.44,0:03:12.40,EN,,0,0,0,,That the way the physics is arranged is such that the connection can be made abstract, Dialogue: 0,0:03:13.08,0:03:15.27,EN,,0,0,0,,at least for low frequencies and things like that. Dialogue: 0,0:03:17.84,0:03:20.88,EN,,0,0,0,,So in fact, we have captured all of the connections there really are. Dialogue: 0,0:03:22.35,0:03:23.87,EN,,0,0,0,,Well, as you can go one step further Dialogue: 0,0:03:23.90,0:03:27.31,EN,,0,0,0,,and talk about the most abstract types of electrical systems we have, Dialogue: 0,0:03:27.85,0:03:29.42,EN,,0,0,0,,digital to dual circuits. Dialogue: 0,0:03:31.69,0:03:33.66,EN,,0,0,0,,And here there are certain kinds of objects. Dialogue: 0,0:03:34.64,0:03:40.12,EN,,0,0,0,,For example, in digital circuits we have things like inverters. Dialogue: 0,0:03:41.39,0:03:42.78,EN,,0,0,0,,We have things like and-gates. Dialogue: 0,0:03:43.99,0:03:45.40,EN,,0,0,0,,We have things like or-gates. Dialogue: 0,0:03:47.21,0:03:50.12,EN,,0,0,0,,We connect them together by sort-of wires Dialogue: 0,0:03:52.00,0:03:54.94,EN,,0,0,0,,which represent abstract signals. Dialogue: 0,0:03:55.61,0:03:57.18,EN,,0,0,0,,We don't really care as physical variables Dialogue: 0,0:03:57.21,0:03:59.72,EN,,0,0,0,,whether these are voltages or currents or some combination Dialogue: 0,0:04:00.01,0:04:03.44,EN,,0,0,0,,or water, water pressure. Dialogue: 0,0:04:05.20,0:04:07.32,EN,,0,0,0,,These abstract variables represent certain signals. Dialogue: 0,0:04:09.42,0:04:12.89,EN,,0,0,0,,And we build systems by wiring these things together with wires. Dialogue: 0,0:04:14.07,0:04:16.22,EN,,0,0,0,,So today what I'm going to show you, right now, Dialogue: 0,0:04:17.63,0:04:20.17,EN,,0,0,0,,we're going to build up an invented language in Lisp, Dialogue: 0,0:04:22.14,0:04:25.08,EN,,0,0,0,,embedded in the same sense that Henderson's picture language was embedded, Dialogue: 0,0:04:26.16,0:04:27.32,EN,,0,0,0,,which is not the same sense Dialogue: 0,0:04:27.88,0:04:31.61,EN,,0,0,0,,as the language of pattern match and substitution was done yesterday. Dialogue: 0,0:04:32.80,0:04:36.30,EN,,0,0,0,,The pattern match substitution language was interpreted by a Lisp program. Dialogue: 0,0:04:38.16,0:04:40.52,EN,,0,0,0,,But the embedding of Henderson's program Dialogue: 0,0:04:40.56,0:04:44.27,EN,,0,0,0,,is that we just build up more and more procedures that encapsulate the structure we want. Dialogue: 0,0:04:45.48,0:04:46.75,EN,,0,0,0,,So for example here, Dialogue: 0,0:04:47.72,0:04:50.64,EN,,0,0,0,,I'm going to have some various primitive kinds of objects, as you see, Dialogue: 0,0:04:51.05,0:04:52.12,EN,,0,0,0,,that one and that one. Dialogue: 0,0:04:53.50,0:04:55.18,EN,,0,0,0,,I'm going to use wires to combine them. Dialogue: 0,0:04:55.98,0:04:59.37,EN,,0,0,0,,The way I represent attaching-- I can make wires. Dialogue: 0,0:04:59.87,0:05:01.24,EN,,0,0,0,,So let's say A is a wire. Dialogue: 0,0:05:01.74,0:05:02.69,EN,,0,0,0,,And B is a wire. Dialogue: 0,0:05:02.69,0:05:03.46,EN,,0,0,0,,And C is a wire. Dialogue: 0,0:05:03.46,0:05:04.23,EN,,0,0,0,,And D is a wire. Dialogue: 0,0:05:04.23,0:05:04.83,EN,,0,0,0,,And E is wire. Dialogue: 0,0:05:04.83,0:05:05.64,EN,,0,0,0,,And S is a wire. Dialogue: 0,0:05:06.88,0:05:12.75,EN,,0,0,0,,Well, an or-gate that has both inputs, the inputs being A and B, Dialogue: 0,0:05:13.16,0:05:14.75,EN,,0,0,0,,and the output being wire D, Dialogue: 0,0:05:15.07,0:05:16.12,EN,,0,0,0,,you notate like this. Dialogue: 0,0:05:18.14,0:05:22.14,EN,,0,0,0,,An and-gate, which has inputs A and B and output C, Dialogue: 0,0:05:22.22,0:05:23.24,EN,,0,0,0,,we notate like that. Dialogue: 0,0:05:24.82,0:05:28.46,EN,,0,0,0,,By making such a sequence of declarations, Dialogue: 0,0:05:29.29,0:05:31.64,EN,,0,0,0,,I can wire together an arbitrary circuit. Dialogue: 0,0:05:32.75,0:05:34.64,EN,,0,0,0,,So I've just told you a set of primitives Dialogue: 0,0:05:35.31,0:05:38.51,EN,,0,0,0,,and means of combination for building digital circuits, Dialogue: 0,0:05:40.09,0:05:43.04,EN,,0,0,0,,when I need more in a real language than abstraction. Dialogue: 0,0:05:43.69,0:05:52.24,EN,,0,0,0,,And so for example, here I have--here I have a half adder. Dialogue: 0,0:05:52.67,0:05:55.55,EN,,0,0,0,,It's something you all know if you've done any digital design. Dialogue: 0,0:05:56.93,0:06:00.44,EN,,0,0,0,,It's used for adding numbers together on A and B Dialogue: 0,0:06:00.62,0:06:02.12,EN,,0,0,0,,and putting out a sum and a carry. Dialogue: 0,0:06:04.35,0:06:06.80,EN,,0,0,0,,And in fact, the wiring diagram is exactly what I told you. Dialogue: 0,0:06:07.45,0:06:10.99,EN,,0,0,0,,A half adder with things that come out of the box-- Dialogue: 0,0:06:11.13,0:06:14.11,EN,,0,0,0,,you see the box, the boundary, the abstraction is always a box. Dialogue: 0,0:06:14.79,0:06:19.70,EN,,0,0,0,,And there are things that come out of it, A, B, S, and C. Dialogue: 0,0:06:19.70,0:06:21.79,EN,,0,0,0,,Those are the declared variables-- Dialogue: 0,0:06:23.39,0:06:26.25,EN,,0,0,0,,declared variables of a lambda expression, Dialogue: 0,0:06:26.28,0:06:28.01,EN,,0,0,0,,which is the one that defines half adder. Dialogue: 0,0:06:31.40,0:06:35.96,EN,,0,0,0,,And internal to that, I make up some more wires, D and E, Dialogue: 0,0:06:36.00,0:06:37.44,EN,,0,0,0,,which I'm going to use for the interconnect-- Dialogue: 0,0:06:37.74,0:06:40.40,EN,,0,0,0,,here E is this one and D is this wire, Dialogue: 0,0:06:41.32,0:06:43.50,EN,,0,0,0,,the interconnect that doesn't come through the walls of the box-- Dialogue: 0,0:06:45.05,0:06:46.83,EN,,0,0,0,,and wire things together as you just saw. Dialogue: 0,0:06:48.79,0:06:50.89,EN,,0,0,0,,And the nice thing about this that I've just shown you Dialogue: 0,0:06:51.05,0:06:53.02,EN,,0,0,0,,this language is hierarchical in the right way. Dialogue: 0,0:06:53.85,0:06:55.71,EN,,0,0,0,,If a language isn't hierarchical in the right way, Dialogue: 0,0:06:55.95,0:06:59.96,EN,,0,0,0,,if it turns out that a compound object doesn't look like a primitive, Dialogue: 0,0:07:00.38,0:07:01.53,EN,,0,0,0,,there's something wrong with the language-- Dialogue: 0,0:07:02.59,0:07:04.22,EN,,0,0,0,,at least the way I feel about that. Dialogue: 0,0:07:06.41,0:07:09.58,EN,,0,0,0,,So here we have--here, instead of starting with mathematical functions, Dialogue: 0,0:07:09.60,0:07:11.12,EN,,0,0,0,,or things that compute mathematical functions, Dialogue: 0,0:07:11.15,0:07:12.65,EN,,0,0,0,,which is what we've been doing up until now, Dialogue: 0,0:07:13.85,0:07:16.65,EN,,0,0,0,,instead of starting with things that look like mathematical functions, Dialogue: 0,0:07:16.67,0:07:17.63,EN,,0,0,0,,or compute such things, Dialogue: 0,0:07:17.85,0:07:20.88,EN,,0,0,0,,we are starting with things that are electrical objects Dialogue: 0,0:07:21.04,0:07:22.64,EN,,0,0,0,,and we build up more electrical objects. Dialogue: 0,0:07:23.35,0:07:28.83,EN,,0,0,0,,And the glue we're using is basically the Lisp structure: lambdas. Dialogue: 0,0:07:30.38,0:07:32.93,EN,,0,0,0,,Lambda is the ultimate glue, if you will. Dialogue: 0,0:07:33.32,0:07:36.35,EN,,0,0,0,,And of course, half adder itself can be used Dialogue: 0,0:07:37.64,0:07:41.04,EN,,0,0,0,,in a more complicated abstraction called a full adder, Dialogue: 0,0:07:41.60,0:07:45.05,EN,,0,0,0,,which in fact involves two half adders, as you see here, Dialogue: 0,0:07:45.47,0:07:47.87,EN,,0,0,0,,hooked together with some extra wires, Dialogue: 0,0:07:48.08,0:07:51.29,EN,,0,0,0,,that you see here, S, C1, and C2, and an or-gate, Dialogue: 0,0:07:52.19,0:07:53.60,EN,,0,0,0,,to manufacture a full adder, Dialogue: 0,0:07:53.87,0:08:00.78,EN,,0,0,0,,which takes a input number, another input number, a carry in, Dialogue: 0,0:08:01.36,0:08:04.17,EN,,0,0,0,,and produces output, a sum and a carry out. Dialogue: 0,0:08:05.90,0:08:10.70,EN,,0,0,0,,And out of full adders, you can make real adder chains and big adders. Dialogue: 0,0:08:12.99,0:08:14.83,EN,,0,0,0,,So we have here a language so far Dialogue: 0,0:08:16.06,0:08:21.76,EN,,0,0,0,,That has primitives, means of combination, and means of abstraction to real language. Dialogue: 0,0:08:22.27,0:08:23.36,EN,,0,0,0,,Now, how are we going to implement this? Dialogue: 0,0:08:25.00,0:08:26.84,EN,,0,0,0,,Well, let's do it easily. Dialogue: 0,0:08:27.07,0:08:27.96,EN,,0,0,0,,Let's look at the primitives. Dialogue: 0,0:08:28.12,0:08:30.11,EN,,0,0,0,,The only problem is we have to implement the primitives. Dialogue: 0,0:08:31.16,0:08:32.56,EN,,0,0,0,,Nothing else has to be implemented, Dialogue: 0,0:08:33.74,0:08:38.00,EN,,0,0,0,,because we're picking up the means of combination and abstraction from Lisp, Dialogue: 0,0:08:39.96,0:08:41.88,EN,,0,0,0,,inheriting them in the embedding. Dialogue: 0,0:08:43.77,0:08:45.44,EN,,0,0,0,,OK, so let's look at a particular primitive. Dialogue: 0,0:08:45.86,0:08:47.40,EN,,0,0,0,,An inverter is a nice one. Dialogue: 0,0:08:51.54,0:08:54.67,EN,,0,0,0,,Now, inverter has two wires coming in, an in and an out. Dialogue: 0,0:08:57.31,0:09:02.62,EN,,0,0,0,,And somehow, it's going to have to know what to do when a signal comes in. Dialogue: 0,0:09:04.30,0:09:07.00,EN,,0,0,0,,So somehow it's going to have to tell its input wire-- Dialogue: 0,0:09:07.64,0:09:10.14,EN,,0,0,0,,and now we're going to talk about objects Dialogue: 0,0:09:10.44,0:09:12.41,EN,,0,0,0,,and we're going to see this in a little more detail soon-- Dialogue: 0,0:09:13.23,0:09:14.84,EN,,0,0,0,,but it's going to have to tell its input wire Dialogue: 0,0:09:15.82,0:09:18.48,EN,,0,0,0,,that when you change, tell me. Dialogue: 0,0:09:20.12,0:09:22.11,EN,,0,0,0,,So this object, the object which is the inverter Dialogue: 0,0:09:22.41,0:09:24.38,EN,,0,0,0,,has to tell the object which is the input wire, Dialogue: 0,0:09:25.13,0:09:26.40,EN,,0,0,0,,hi, my name is George. Dialogue: 0,0:09:26.87,0:09:31.02,EN,,0,0,0,,And my, my job is to do something with results when you change. Dialogue: 0,0:09:31.72,0:09:34.19,EN,,0,0,0,,So when you change, you get a change, tell me about it. Dialogue: 0,0:09:34.73,0:09:35.72,EN,,0,0,0,,Because I've got to do something with that. Dialogue: 0,0:09:36.88,0:09:40.30,EN,,0,0,0,,Well, that's done down here by adding an action on the input wire called invert-in, Dialogue: 0,0:09:41.40,0:09:44.64,EN,,0,0,0,,Well, that's done down here by adding an action on the input wire called invert-in, Dialogue: 0,0:09:45.07,0:09:46.94,EN,,0,0,0,,where invert-in is defined over here Dialogue: 0,0:09:47.05,0:09:48.76,EN,,0,0,0,,to be a procedure of no arguments, Dialogue: 0,0:09:49.98,0:09:54.59,EN,,0,0,0,,which gets the logical not of the signal on the input wire. Dialogue: 0,0:09:56.06,0:09:58.64,EN,,0,0,0,,And after some delay, which is the inverter delay, Dialogue: 0,0:09:59.26,0:10:01.15,EN,,0,0,0,,all these electrical objects have delays, Dialogue: 0,0:10:02.88,0:10:04.46,EN,,0,0,0,,we'll do the following thing-- Dialogue: 0,0:10:04.67,0:10:07.14,EN,,0,0,0,,set the signal on the output wire to the new value. Dialogue: 0,0:10:10.16,0:10:11.36,EN,,0,0,0,,A very simple program. Dialogue: 0,0:10:12.40,0:10:15.28,EN,,0,0,0,,Now, you have to imagine that the output wire has to be sensitive Dialogue: 0,0:10:15.77,0:10:18.27,EN,,0,0,0,,and know that when its signal changes, Dialogue: 0,0:10:19.28,0:10:21.15,EN,,0,0,0,,it may have to tell other guys, Dialogue: 0,0:10:21.79,0:10:24.78,EN,,0,0,0,,Hi, wake up. My value has changed. Dialogue: 0,0:10:26.05,0:10:30.14,EN,,0,0,0,,So when you hook together inverter with an and-gate or something like that, Dialogue: 0,0:10:30.46,0:10:32.20,EN,,0,0,0,,there has to be a lot of communication going on Dialogue: 0,0:10:32.86,0:10:35.07,EN,,0,0,0,,to make sure that the signal propagates right. Dialogue: 0,0:10:36.81,0:10:38.62,EN,,0,0,0,,And down here is nothing very exciting. Dialogue: 0,0:10:38.62,0:10:40.72,EN,,0,0,0,,This is just the definition of logical not Dialogue: 0,0:10:40.72,0:10:45.24,EN,,0,0,0,,for some particular representations of the logical values-- 1, 0 in this case. Dialogue: 0,0:10:46.73,0:10:49.16,EN,,0,0,0,,And we can look at things more complicated like and-gates. Dialogue: 0,0:10:49.78,0:10:55.80,EN,,0,0,0,,And-gates take two inputs, A1 and A2, we'll call them, and produce an output. Dialogue: 0,0:10:56.73,0:11:00.64,EN,,0,0,0,,But the structure of the and-gate is identical to the one we just saw. Dialogue: 0,0:11:00.86,0:11:03.44,EN,,0,0,0,,There's one called an and-action procedure that's defined, Dialogue: 0,0:11:04.52,0:11:09.07,EN,,0,0,0,,which is the thing that gets called when an input is changed. Dialogue: 0,0:11:10.91,0:11:12.88,EN,,0,0,0,,And what it does, of course, is nothing more than Dialogue: 0,0:11:12.91,0:11:15.37,EN,,0,0,0,,compute the logical and of the signals on the inputs. Dialogue: 0,0:11:16.19,0:11:18.76,EN,,0,0,0,,And after some delay, called the and-gate-delay, Dialogue: 0,0:11:20.46,0:11:24.36,EN,,0,0,0,,calls this procedure, which sets a signal on the output to a new value. Dialogue: 0,0:11:25.47,0:11:28.35,EN,,0,0,0,,Now, how I implement these things is all wishful thinking. Dialogue: 0,0:11:28.35,0:11:31.08,EN,,0,0,0,,As you see here, I have an assignment operation. Dialogue: 0,0:11:32.02,0:11:32.78,EN,,0,0,0,,It's not set. Dialogue: 0,0:11:34.57,0:11:36.78,EN,,0,0,0,,It's a derived assignment operation in the same way Dialogue: 0,0:11:36.78,0:11:38.73,EN,,0,0,0,,we had functions that were derived from CAR and CDR. Dialogue: 0,0:11:40.80,0:11:44.81,EN,,0,0,0,,So I, by convention, label that with an exclamation point. Dialogue: 0,0:11:46.34,0:11:49.18,EN,,0,0,0,,And over here, you see there's an add-action!, Dialogue: 0,0:11:49.44,0:11:54.67,EN,,0,0,0,,which is to inform the wire, called A1 locally in this and-gate, Dialogue: 0,0:11:55.63,0:11:58.68,EN,,0,0,0,,to call the and-action-procedure when it gets changed, Dialogue: 0,0:11:59.58,0:12:02.91,EN,,0,0,0,,and the wire A2 to call the and-action procedure when it gets changed. Dialogue: 0,0:12:06.31,0:12:07.23,EN,,0,0,0,,All very simple. Dialogue: 0,0:12:09.96,0:12:12.09,EN,,0,0,0,,Well, let's talk a little bit about this communication Dialogue: 0,0:12:12.70,0:12:16.12,EN,,0,0,0,,that must occur between these various parts. Dialogue: 0,0:12:18.54,0:12:19.66,EN,,0,0,0,,Suppose, for example, Dialogue: 0,0:12:23.12,0:12:24.27,EN,,0,0,0,,I have a very simple circuit Dialogue: 0,0:12:24.27,0:12:30.46,EN,,0,0,0,,which contains and-gate with wires a and b. Dialogue: 0,0:12:31.92,0:12:38.00,EN,,0,0,0,,And that connects through a wire called c to an inverter Dialogue: 0,0:12:39.72,0:12:41.53,EN,,0,0,0,,which has a wire output called d. Dialogue: 0,0:12:44.20,0:12:47.34,EN,,0,0,0,,What are the comput...--here's the physical world. Dialogue: 0,0:12:47.36,0:12:49.02,EN,,0,0,0,,It's an abstraction of the physical world. Dialogue: 0,0:12:49.86,0:12:53.40,EN,,0,0,0,,Now I can buy these out of little pieces that you get at Radio Shack for a few cents. Dialogue: 0,0:12:54.88,0:12:56.32,EN,,0,0,0,,And there are boxes that act like this, Dialogue: 0,0:12:57.16,0:13:00.22,EN,,0,0,0,,which have little numbers on them like LS04 or something. Dialogue: 0,0:13:01.53,0:13:08.16,EN,,0,0,0,,Now supposing I were to try to say what's the computational model. Dialogue: 0,0:13:09.01,0:13:10.94,EN,,0,0,0,,What is the thing that corresponds to that, Dialogue: 0,0:13:11.13,0:13:14.09,EN,,0,0,0,,that part of reality in the mind of us and in the computer? Dialogue: 0,0:13:15.85,0:13:19.13,EN,,0,0,0,,Well, I have to assign for every object in the world an object in the computer, Dialogue: 0,0:13:19.79,0:13:24.27,EN,,0,0,0,,and for every relationship in the world between them a relationship in the computer. Dialogue: 0,0:13:26.06,0:13:26.80,EN,,0,0,0,,That's my goal. Dialogue: 0,0:13:28.56,0:13:29.45,EN,,0,0,0,,So let's do that. Dialogue: 0,0:13:30.90,0:13:34.20,EN,,0,0,0,,Well, I have some sort of thing called the signal, A. Dialogue: 0,0:13:35.71,0:13:36.94,EN,,0,0,0,,This is A. It's a signal. Dialogue: 0,0:13:37.94,0:13:39.32,EN,,0,0,0,,It's a cloudy thing like that. Dialogue: 0,0:13:39.90,0:13:42.80,EN,,0,0,0,,And I have another one down here which I'm going to call B. Dialogue: 0,0:13:46.68,0:13:47.47,EN,,0,0,0,,It's another signal. Dialogue: 0,0:13:49.14,0:13:50.91,EN,,0,0,0,,Now this signal--these two signals Dialogue: 0,0:13:51.10,0:13:52.81,EN,,0,0,0,,are somehow going to have to hook together Dialogue: 0,0:13:53.72,0:13:58.75,EN,,0,0,0,,into a box, let's call it this, which is the and-gate, action procedure. Dialogue: 0,0:14:00.32,0:14:02.04,EN,,0,0,0,,That's the and-gate's action procedure. Dialogue: 0,0:14:07.66,0:14:08.59,EN,,0,0,0,,And it's going to produce Dialogue: 0,0:14:09.15,0:14:13.29,EN,,0,0,0,,well, it's going to interact with a signal object, which we call C-- Dialogue: 0,0:14:16.22,0:14:18.88,EN,,0,0,0,,a wire object, excuse me, we call C. Dialogue: 0,0:14:20.59,0:14:26.28,EN,,0,0,0,,this is going to put out again, or connect to, another action procedure Dialogue: 0,0:14:26.28,0:14:30.33,EN,,0,0,0,,which is one associated with the inverter in the world, not. Dialogue: 0,0:14:32.86,0:14:40.65,EN,,0,0,0,,And I'm going to have another--another wire, which we'll call D. Dialogue: 0,0:14:42.97,0:14:45.29,EN,,0,0,0,,So here's my layout of stuff. Dialogue: 0,0:14:46.00,0:14:49.44,EN,,0,0,0,,Now we have to say what's inside them and what they have to know to compute. Dialogue: 0,0:14:51.50,0:14:53.69,EN,,0,0,0,,Well, every--every one of these wires has to know Dialogue: 0,0:14:53.69,0:14:56.36,EN,,0,0,0,,what the value of the signal that's on that wire is. Dialogue: 0,0:14:57.34,0:15:00.00,EN,,0,0,0,,So there's going to be some variable inside here, we'll call it signal. Dialogue: 0,0:15:02.97,0:15:04.04,EN,,0,0,0,,And he owns a value. Dialogue: 0,0:15:05.68,0:15:07.74,EN,,0,0,0,,So there must be some environment associated with this. Dialogue: 0,0:15:08.89,0:15:11.34,EN,,0,0,0,,And for each one of these, there must be an environment that binds signal. Dialogue: 0,0:15:15.40,0:15:16.88,EN,,0,0,0,,And there must be a signal here, therefore. Dialogue: 0,0:15:19.40,0:15:21.92,EN,,0,0,0,,And presumably, signal's a value that's either 1 or 0, Dialogue: 0,0:15:22.81,0:15:23.48,EN,,0,0,0,,and signal. Dialogue: 0,0:15:28.00,0:15:30.56,EN,,0,0,0,,Now, we also have to have some Dialogue: 0,0:15:31.26,0:15:34.11,EN,,0,0,0,,list of people to inform if the signal here changes. Dialogue: 0,0:15:36.66,0:15:37.66,EN,,0,0,0,,We're going to have to inform this. Dialogue: 0,0:15:39.30,0:15:43.96,EN,,0,0,0,,So I've got that list. We'll call it the Action Procedures, AP. Dialogue: 0,0:15:44.50,0:15:45.60,EN,,0,0,0,,And it's presumably a list. Dialogue: 0,0:15:46.44,0:15:49.00,EN,,0,0,0,,But the first thing on the list, in this case, is this guy. Dialogue: 0,0:15:50.50,0:15:54.81,EN,,0,0,0,,And the action procedures of this one happens to have some list of stuff. Dialogue: 0,0:15:54.81,0:15:58.17,EN,,0,0,0,,There might be other people who are sharing A, who are looking at it. Dialogue: 0,0:15:59.02,0:16:01.31,EN,,0,0,0,,So there might be other guys on this list, like Dialogue: 0,0:16:01.72,0:16:03.23,EN,,0,0,0,,like somebody over there that we don't know about. Dialogue: 0,0:16:03.63,0:16:04.88,EN,,0,0,0,,It's the other guy attached to A. Dialogue: 0,0:16:07.20,0:16:09.64,EN,,0,0,0,,And the action procedure here also has to point to that, Dialogue: 0,0:16:11.12,0:16:12.40,EN,,0,0,0,,the list of action procedures. Dialogue: 0,0:16:13.07,0:16:16.35,EN,,0,0,0,,And of course, that means this one, its action procedures Dialogue: 0,0:16:16.78,0:16:18.53,EN,,0,0,0,,has to point up to here. Dialogue: 0,0:16:18.53,0:16:20.89,EN,,0,0,0,,This is the things-- the people it has to inform. Dialogue: 0,0:16:21.77,0:16:23.18,EN,,0,0,0,,And this guy has some too. Dialogue: 0,0:16:24.28,0:16:25.24,EN,,0,0,0,,But I don't know what they are Dialogue: 0,0:16:25.26,0:16:26.65,EN,,0,0,0,,because I didn't draw it in my diagram. Dialogue: 0,0:16:27.19,0:16:28.36,EN,,0,0,0,,It's the things connected to D. Dialogue: 0,0:16:30.32,0:16:32.62,EN,,0,0,0,,Now, it's also the case Dialogue: 0,0:16:33.80,0:16:36.96,EN,,0,0,0,,that when the and-action procedure is awakened, Dialogue: 0,0:16:37.02,0:16:41.31,EN,,0,0,0,,saying one of the people who know that you've told Dialogue: 0,0:16:41.45,0:16:44.84,EN,,0,0,0,,one of the people you've told to wake you up if their signal changes, Dialogue: 0,0:16:46.97,0:16:48.81,EN,,0,0,0,,you have to go look and ask them what's their signal Dialogue: 0,0:16:49.32,0:16:52.25,EN,,0,0,0,,so you can do the and, and produce a signal for this one. Dialogue: 0,0:16:57.09,0:16:58.75,EN,,0,0,0,,So there has to be, for example, Dialogue: 0,0:16:58.84,0:17:03.00,EN,,0,0,0,,information here saying A1, my A1 is this guy, Dialogue: 0,0:17:03.90,0:17:06.48,EN,,0,0,0,,my A1 is this guy, and my A2 is this guy. Dialogue: 0,0:17:08.93,0:17:09.98,EN,,0,0,0,,And not only that, Dialogue: 0,0:17:11.79,0:17:15.20,EN,,0,0,0,,when I do my and, I'm going to have to tell this guy something. Dialogue: 0,0:17:16.30,0:17:21.05,EN,,0,0,0,,So I need an output-- being this guy. Dialogue: 0,0:17:25.80,0:17:30.03,EN,,0,0,0,,And similarly, this guy's going to have a thing called the input Dialogue: 0,0:17:32.38,0:17:34.92,EN,,0,0,0,,that he interrogates to find out Dialogue: 0,0:17:36.75,0:17:38.64,EN,,0,0,0,,what the value of the signal on the input is, Dialogue: 0,0:17:38.64,0:17:40.09,EN,,0,0,0,,when the signal wakes up and says, I've changed, Dialogue: 0,0:17:41.05,0:17:43.47,EN,,0,0,0,,and sends a message this way saying, I've changed. Dialogue: 0,0:17:43.52,0:17:45.53,EN,,0,0,0,,This guy says, OK, what's your value now? Dialogue: 0,0:17:46.90,0:17:50.12,EN,,0,0,0,,When he gets that value, then he's going to have to say, Dialogue: 0,0:17:50.14,0:17:55.86,EN,,0,0,0,,OK, output changes this guy, changes this guy. Dialogue: 0,0:18:00.60,0:18:01.24,EN,,0,0,0,,And so on. Dialogue: 0,0:18:02.84,0:18:04.56,EN,,0,0,0,,And so I have to have at least that much connected-ness. Dialogue: 0,0:18:06.24,0:18:09.23,EN,,0,0,0,,Now, let's go back and look, for example, at the and-gate. Dialogue: 0,0:18:10.26,0:18:12.09,EN,,0,0,0,,Here we are back on this slide. Dialogue: 0,0:18:13.67,0:18:15.04,EN,,0,0,0,,And we can see some of these parts. Dialogue: 0,0:18:16.04,0:18:19.32,EN,,0,0,0,,For any particular and-gate, there is an A1, there is an A2, and the output. Dialogue: 0,0:18:21.03,0:18:23.53,EN,,0,0,0,,And those are, those are Dialogue: 0,0:18:25.08,0:18:28.16,EN,,0,0,0,,an environment that was created at the--those produce a frame Dialogue: 0,0:18:28.41,0:18:31.24,EN,,0,0,0,,at the time and-gate was called, Dialogue: 0,0:18:33.31,0:18:35.90,EN,,0,0,0,,A frame where A1, A2, and output are-- Dialogue: 0,0:18:36.67,0:18:39.20,EN,,0,0,0,,have as their values, they're bound to Dialogue: 0,0:18:39.60,0:18:44.25,EN,,0,0,0,,the wires which, they are--which were passed in. Dialogue: 0,0:18:46.24,0:18:47.31,EN,,0,0,0,,In that environment, Dialogue: 0,0:18:47.74,0:18:49.85,EN,,0,0,0,,I constructed a procedure Dialogue: 0,0:18:50.97,0:18:53.68,EN,,0,0,0,,this one right there. Dialogue: 0,0:18:54.59,0:18:57.31,EN,,0,0,0,,And-action-procedure was constructed in that environment. Dialogue: 0,0:18:58.35,0:19:00.70,EN,,0,0,0,,That was the result of evaluating a lambda expression. Dialogue: 0,0:19:01.62,0:19:05.48,EN,,0,0,0,,So it hangs onto the frame where these were defined. Dialogue: 0,0:19:07.16,0:19:09.34,EN,,0,0,0,,Local--part of its local state is that. Dialogue: 0,0:19:11.70,0:19:13.47,EN,,0,0,0,,The and-action-procedure, therefore, has Dialogue: 0,0:19:13.64,0:19:16.94,EN,,0,0,0,,access to A1, A2, and output as we see here. Dialogue: 0,0:19:17.31,0:19:19.64,EN,,0,0,0,,A1, A2, and output. Dialogue: 0,0:19:22.36,0:19:23.95,EN,,0,0,0,,Now, we haven't looked inside of a wire yet. Dialogue: 0,0:19:26.03,0:19:26.99,EN,,0,0,0,,That's all that remains. Dialogue: 0,0:19:29.03,0:19:29.92,EN,,0,0,0,,Let's look at a wire. Dialogue: 0,0:19:33.52,0:19:36.25,EN,,0,0,0,,Like the overhead, very good. Dialogue: 0,0:19:39.50,0:19:42.56,EN,,0,0,0,,Well, the wire, again, is a, is a somewhat complicated mess. Dialogue: 0,0:19:43.09,0:19:44.64,EN,,0,0,0,,Ooh, wrong one. Dialogue: 0,0:19:47.05,0:19:48.75,EN,,0,0,0,,It's a big complicated mess, like that. Dialogue: 0,0:19:50.06,0:19:53.10,EN,,0,0,0,,But let's look at it in detail and see what's going on. Dialogue: 0,0:19:54.72,0:19:56.67,EN,,0,0,0,,Well, the wire is one of these. Dialogue: 0,0:19:57.76,0:20:03.52,EN,,0,0,0,,And it has to have two things that are part of it, that it's state. Dialogue: 0,0:20:05.01,0:20:07.39,EN,,0,0,0,,One of them is the signal we see here. Dialogue: 0,0:20:07.45,0:20:10.06,EN,,0,0,0,,Heres, when we call make-wire to make a wire, Dialogue: 0,0:20:10.46,0:20:13.02,EN,,0,0,0,,then the first thing we do is we create some variables Dialogue: 0,0:20:14.94,0:20:16.08,EN,,0,0,0,,which are the signal Dialogue: 0,0:20:17.10,0:20:19.29,EN,,0,0,0,,and the action procedures for this wire. Dialogue: 0,0:20:22.32,0:20:23.44,EN,,0,0,0,,And in that context, Dialogue: 0,0:20:23.76,0:20:27.04,EN,,0,0,0,,we define various functions--or procedures, excuse me, procedures. Dialogue: 0,0:20:27.84,0:20:31.15,EN,,0,0,0,,One of them is called set-my-signal to a new value. Dialogue: 0,0:20:32.85,0:20:37.42,EN,,0,0,0,,And what that does is takes a new value in. Dialogue: 0,0:20:37.93,0:20:40.36,EN,,0,0,0,,If that's equal to my current value of my signal, I'm done. Dialogue: 0,0:20:40.36,0:20:42.62,EN,,0,0,0,,Otherwise, I set the signal to the new value Dialogue: 0,0:20:42.75,0:20:44.60,EN,,0,0,0,,and call each of the action procedures Dialogue: 0,0:20:46.52,0:20:52.51,EN,,0,0,0,,that I've been, that I've been--what's the right word? -- introduced to. Dialogue: 0,0:20:54.63,0:21:01.53,EN,,0,0,0,,I get introduced when the and-gate was applied to me. Dialogue: 0,0:21:04.13,0:21:05.60,EN,,0,0,0,,By add action procedure at the bottom. Dialogue: 0,0:21:07.41,0:21:10.80,EN,,0,0,0,,Also, I have to define a way of accepting an action procedure-- Dialogue: 0,0:21:10.81,0:21:11.82,EN,,0,0,0,,which is what you see here--- Dialogue: 0,0:21:12.80,0:21:15.13,EN,,0,0,0,,which increments my action procedures Dialogue: 0,0:21:15.56,0:21:21.63,EN,,0,0,0,,using set to the result of CONSing up a new process--a procedure, Dialogue: 0,0:21:21.79,0:21:24.25,EN,,0,0,0,,which is passed to me, on to my actions procedures list. Dialogue: 0,0:21:25.40,0:21:27.58,EN,,0,0,0,,And for technical reasons, I have to call that procedure one. Dialogue: 0,0:21:27.78,0:21:29.20,EN,,0,0,0,,So I'm not going to tell you anything about that, Dialogue: 0,0:21:29.39,0:21:33.15,EN,,0,0,0,,that has to do with event-driven simulations and getting them started, Dialogue: 0,0:21:34.59,0:21:36.00,EN,,0,0,0,,which takes a little bit of thinking. Dialogue: 0,0:21:36.95,0:21:39.40,EN,,0,0,0,,And finally, I'm going to define a thing called the dispatcher, Dialogue: 0,0:21:39.96,0:21:43.58,EN,,0,0,0,,which is a way of passing a message to a wire, Dialogue: 0,0:21:45.37,0:21:48.65,EN,,0,0,0,,which is going to be used to extract from it various information, Dialogue: 0,0:21:49.07,0:21:51.48,EN,,0,0,0,,like what is the current signal value? Dialogue: 0,0:21:53.82,0:21:55.66,EN,,0,0,0,,What is the method of setting your signal? Dialogue: 0,0:21:57.18,0:21:58.28,EN,,0,0,0,,I want to get that out of it. Dialogue: 0,0:22:00.10,0:22:02.60,EN,,0,0,0,,How do I--how do I add another action procedure? Dialogue: 0,0:22:05.51,0:22:09.36,EN,,0,0,0,,And I'm going to return that dispatch, that procedure as a value. Dialogue: 0,0:22:09.94,0:22:11.87,EN,,0,0,0,,So the wire that I've constructed Dialogue: 0,0:22:12.00,0:22:13.55,EN,,0,0,0,,is a message accepting object Dialogue: 0,0:22:14.25,0:22:16.01,EN,,0,0,0,,which accepts a message like, like Dialogue: 0,0:22:16.44,0:22:18.36,EN,,0,0,0,,what's your method of adding action procedures? Dialogue: 0,0:22:19.92,0:22:21.00,EN,,0,0,0,,That it'll give me a procedure, Dialogue: 0,0:22:21.64,0:22:23.05,EN,,0,0,0,,which is the add action procedure, Dialogue: 0,0:22:23.07,0:22:26.54,EN,,0,0,0,,which I can then apply to an action procedure Dialogue: 0,0:22:27.05,0:22:29.01,EN,,0,0,0,,to create another action procedure in the wire. Dialogue: 0,0:22:31.62,0:22:32.82,EN,,0,0,0,,So that's a permission. Dialogue: 0,0:22:33.20,0:22:36.08,EN,,0,0,0,,So it's given me permission to change your action procedures. Dialogue: 0,0:22:37.82,0:22:40.16,EN,,0,0,0,,And in fact, you can see that over here. Dialogue: 0,0:22:41.71,0:22:42.32,EN,,0,0,0,,Next slide. Dialogue: 0,0:22:43.53,0:22:43.82,EN,,0,0,0,,Ah. Dialogue: 0,0:22:47.76,0:22:49.12,EN,,0,0,0,,This is nothing very interesting. Dialogue: 0,0:22:49.12,0:22:50.65,EN,,0,0,0,,The call each of the action procedures Dialogue: 0,0:22:50.89,0:22:52.57,EN,,0,0,0,,is just a CDRing down a list. Dialogue: 0,0:22:52.73,0:22:54.60,EN,,0,0,0,,And I'm not going to even talk about that anymore. Dialogue: 0,0:22:54.99,0:22:56.25,EN,,0,0,0,,We're too advanced for that. Dialogue: 0,0:22:57.56,0:23:00.67,EN,,0,0,0,,However, if I want to get a signal from a wire, Dialogue: 0,0:23:01.02,0:23:02.54,EN,,0,0,0,,I ask the wire-- which is, Dialogue: 0,0:23:02.54,0:23:03.09,EN,,0,0,0,,what is the wire? Dialogue: 0,0:23:03.09,0:23:05.40,EN,,0,0,0,,The wire is the dispatch returned by creating the wire. Dialogue: 0,0:23:05.86,0:23:06.48,EN,,0,0,0,,It's a procedure. Dialogue: 0,0:23:06.83,0:23:12.27,EN,,0,0,0,,I call that dispatch on the message get-signal. Dialogue: 0,0:23:12.91,0:23:15.40,EN,,0,0,0,,And what I should expect to get is a method of getting a signal. Dialogue: 0,0:23:16.90,0:23:17.96,EN,,0,0,0,,Or actually, I get the signal. Dialogue: 0,0:23:19.22,0:23:20.52,EN,,0,0,0,,If I want to set a signal, Dialogue: 0,0:23:22.65,0:23:23.96,EN,,0,0,0,,I want to change a signal, Dialogue: 0,0:23:24.51,0:23:26.76,EN,,0,0,0,,then what I'm going to do Dialogue: 0,0:23:26.92,0:23:29.69,EN,,0,0,0,,is take a wire as an argument and a new value for the signal, Dialogue: 0,0:23:30.01,0:23:32.43,EN,,0,0,0,,I would ask the wire for permission to set the signal Dialogue: 0,0:23:32.84,0:23:37.61,EN,,0,0,0,,and use that permission, which is a procedure, on the new value. Dialogue: 0,0:23:38.70,0:23:40.51,EN,,0,0,0,,And if we go back to the overhead here, Dialogue: 0,0:23:41.64,0:23:43.24,EN,,0,0,0,,Okay, thank you, Dialogue: 0,0:23:44.20,0:23:45.63,EN,,0,0,0,,we go back to the overhead here, Dialogue: 0,0:23:45.92,0:23:48.75,EN,,0,0,0,,we see that the method-- if I ask for the method of setting the signal, Dialogue: 0,0:23:49.34,0:23:50.44,EN,,0,0,0,,that's over here, Dialogue: 0,0:23:52.25,0:23:55.69,EN,,0,0,0,,it's set-my-signal, a procedure that's defined inside the wire, Dialogue: 0,0:23:56.25,0:23:57.69,EN,,0,0,0,,which if we look over here Dialogue: 0,0:23:58.72,0:23:59.74,EN,,0,0,0,,is the thing that says Dialogue: 0,0:24:00.43,0:24:02.68,EN,,0,0,0,,set my internal value called the signal, Dialogue: 0,0:24:02.73,0:24:05.50,EN,,0,0,0,,my internal variable, which is the signal, Dialogue: 0,0:24:07.61,0:24:10.03,EN,,0,0,0,,to the new value, which is passed to me as an argument, Dialogue: 0,0:24:10.78,0:24:13.01,EN,,0,0,0,,and then call each of the action procedures waking them up. Dialogue: 0,0:24:16.34,0:24:16.99,EN,,0,0,0,,Very simple. Dialogue: 0,0:24:19.24,0:24:20.76,EN,,0,0,0,,Ok, Going back to that slide, Dialogue: 0,0:24:22.48,0:24:24.32,EN,,0,0,0,,we also have the one last thing-- Dialogue: 0,0:24:24.36,0:24:27.31,EN,,0,0,0,,which I suppose now you can easily work out for yourself-- Dialogue: 0,0:24:27.77,0:24:29.15,EN,,0,0,0,,is the way you add an action. Dialogue: 0,0:24:30.10,0:24:35.18,EN,,0,0,0,,You take a wire--a wire and an action procedure. Dialogue: 0,0:24:36.47,0:24:39.31,EN,,0,0,0,,And I ask the wire for permission to add an action. Dialogue: 0,0:24:40.05,0:24:44.22,EN,,0,0,0,,Getting that permission, I use that permission to give it an action procedure. Dialogue: 0,0:24:45.84,0:24:47.08,EN,,0,0,0,,So that's a real object. Dialogue: 0,0:24:48.57,0:24:50.32,EN,,0,0,0,,There's a few more details about this. Dialogue: 0,0:24:52.46,0:24:58.39,EN,,0,0,0,,For example, how am I going to control this thing? Dialogue: 0,0:24:58.39,0:24:59.69,EN,,0,0,0,,How do I do these delays? Dialogue: 0,0:25:00.99,0:25:02.54,EN,,0,0,0,,Okay? Let's look at that for a second. Dialogue: 0,0:25:05.50,0:25:07.98,EN,,0,0,0,,The next one here. Dialogue: 0,0:25:08.36,0:25:08.88,EN,,0,0,0,,Let's see. Dialogue: 0,0:25:09.57,0:25:14.17,EN,,0,0,0,,We know when we looked at the and-gate or the not-gate Dialogue: 0,0:25:15.31,0:25:17.00,EN,,0,0,0,,that when a signal changed on the input, Dialogue: 0,0:25:17.24,0:25:18.19,EN,,0,0,0,,there was a delay. Dialogue: 0,0:25:18.77,0:25:21.24,EN,,0,0,0,,And then it was going to call the procedure, Dialogue: 0,0:25:21.63,0:25:23.00,EN,,0,0,0,,which was going to change the output. Dialogue: 0,0:25:26.04,0:25:27.92,EN,,0,0,0,,Well, how are we going to do this? Dialogue: 0,0:25:28.12,0:25:29.92,EN,,0,0,0,,We're going to make up some mechanism, Dialogue: 0,0:25:30.30,0:25:32.00,EN,,0,0,0,,a fairly complicated mechanism at that, Dialogue: 0,0:25:32.33,0:25:33.76,EN,,0,0,0,,which we're going to have to be very careful about. Dialogue: 0,0:25:34.72,0:25:37.23,EN,,0,0,0,,But after a delay, we're going to do an action. Dialogue: 0,0:25:37.39,0:25:38.12,EN,,0,0,0,,A delay is a number, Dialogue: 0,0:25:38.16,0:25:39.23,EN,,0,0,0,,and an action is a procedure. Dialogue: 0,0:25:40.59,0:25:43.72,EN,,0,0,0,,What that's going to be is they're going to have a special structure called an agenda, Dialogue: 0,0:25:45.50,0:25:48.80,EN,,0,0,0,,which is a thing that organizes time and actions. Dialogue: 0,0:25:49.51,0:25:50.88,EN,,0,0,0,,And we're going to see that in a while. Dialogue: 0,0:25:50.88,0:25:52.54,EN,,0,0,0,,I don't want to get into that right now. Dialogue: 0,0:25:53.07,0:25:58.28,EN,,0,0,0,,But the agenda has a moment at which--at which something happens. Dialogue: 0,0:25:59.13,0:26:02.46,EN,,0,0,0,,We're setting up for later at some moment, Dialogue: 0,0:26:02.51,0:26:05.68,EN,,0,0,0,,which is the sum of the time, which is the delay time plus the current time, Dialogue: 0,0:26:05.69,0:26:07.13,EN,,0,0,0,,which the agenda thinks is now. Dialogue: 0,0:26:09.02,0:26:10.56,EN,,0,0,0,,We're going to set up to do this action, Dialogue: 0,0:26:11.02,0:26:12.40,EN,,0,0,0,,and add that to the agenda. Dialogue: 0,0:26:15.28,0:26:18.03,EN,,0,0,0,,And the way this machine will now run is very simple. Dialogue: 0,0:26:18.66,0:26:21.48,EN,,0,0,0,,We have a thing called propagate, which is the way things run. Dialogue: 0,0:26:22.71,0:26:25.95,EN,,0,0,0,,If the agenda is empty, we're done--if there's nothing more to be done. Dialogue: 0,0:26:27.44,0:26:28.16,EN,,0,0,0,,Otherwise, Dialogue: 0,0:26:29.76,0:26:31.53,EN,,0,0,0,,we're going to take the first item off the agenda, Dialogue: 0,0:26:31.71,0:26:33.34,EN,,0,0,0,,and that's a procedure of no arguments. Dialogue: 0,0:26:34.20,0:26:36.03,EN,,0,0,0,,So that we're going to see extra parentheses here. Dialogue: 0,0:26:36.03,0:26:37.85,EN,,0,0,0,,We call that on no arguments. Dialogue: 0,0:26:39.19,0:26:40.17,EN,,0,0,0,,That takes the action. Dialogue: 0,0:26:42.20,0:26:44.17,EN,,0,0,0,,Then we remove that first item from the agenda, Dialogue: 0,0:26:44.59,0:26:46.14,EN,,0,0,0,,and we go around the propagation loop. Dialogue: 0,0:26:48.91,0:26:50.75,EN,,0,0,0,,So that's the overall structure of this thing. Dialogue: 0,0:26:53.38,0:26:55.93,EN,,0,0,0,,Now, there's a, a few other things we can look at. Dialogue: 0,0:26:57.43,0:27:00.01,EN,,0,0,0,,And then we're going to look into the agenda a little while from now. Dialogue: 0,0:27:00.57,0:27:01.55,EN,,0,0,0,,Now the overhead again. Dialogue: 0,0:27:02.80,0:27:04.67,EN,,0,0,0,,Well, in order to set this thing going, Dialogue: 0,0:27:04.67,0:27:07.41,EN,,0,0,0,,I just want to show you some behavior out of this simulator. Dialogue: 0,0:27:07.85,0:27:09.93,EN,,0,0,0,,By the way, you may think this simulator is very simple, Dialogue: 0,0:27:10.40,0:27:12.01,EN,,0,0,0,,and probably too simple to be useful. Dialogue: 0,0:27:12.57,0:27:13.76,EN,,0,0,0,,The fact of the matter is Dialogue: 0,0:27:13.98,0:27:15.39,EN,,0,0,0,,that this simulator has been used Dialogue: 0,0:27:15.72,0:27:17.44,EN,,0,0,0,,to manufacture a fairly large computer. Dialogue: 0,0:27:18.68,0:27:20.64,EN,,0,0,0,,So this is a real live example. Dialogue: 0,0:27:22.36,0:27:24.06,EN,,0,0,0,,Actually, not exactly this simulator, Dialogue: 0,0:27:24.06,0:27:25.39,EN,,0,0,0,,because I'll tell you the difference. Dialogue: 0,0:27:25.84,0:27:28.70,EN,,0,0,0,,The difference is that there were many more different kinds of primitives. Dialogue: 0,0:27:29.82,0:27:32.22,EN,,0,0,0,,There's not just the word inverter or and-gate. Dialogue: 0,0:27:33.20,0:27:35.72,EN,,0,0,0,,There were things like edge-triggered, Dialogue: 0,0:27:36.25,0:27:39.88,EN,,0,0,0,,flip-flops, and latches Dialogue: 0,0:27:40.70,0:27:44.52,EN,,0,0,0,,transparent latches, and adders, and things like that. Dialogue: 0,0:27:45.17,0:27:47.31,EN,,0,0,0,,And the difficulty with that Dialogue: 0,0:27:47.45,0:27:50.86,EN,,0,0,0,,is there's pages and pages of the definitions of all these primitives Dialogue: 0,0:27:51.20,0:27:52.89,EN,,0,0,0,,with numbers like LS04. Dialogue: 0,0:27:54.69,0:27:56.74,EN,,0,0,0,,And then there's many more parameters for them. Dialogue: 0,0:27:56.74,0:27:57.98,EN,,0,0,0,,It's not just one delay. Dialogue: 0,0:27:58.48,0:28:00.81,EN,,0,0,0,,There's things like set up times and hold times and all that. Dialogue: 0,0:28:01.22,0:28:03.40,EN,,0,0,0,,But with the exception of that part of the complexity, Dialogue: 0,0:28:03.82,0:28:08.20,EN,,0,0,0,,the structure of the simulator that we use for building a real computer, Dialogue: 0,0:28:09.08,0:28:12.89,EN,,0,0,0,,that works is exactly what you're seeing here. Dialogue: 0,0:28:15.11,0:28:19.27,EN,,0,0,0,,Well in any case, what we have here is a few simple things. Dialogue: 0,0:28:19.27,0:28:22.59,EN,,0,0,0,,Like, there's inverter delays being set up and making a new agenda. Dialogue: 0,0:28:23.03,0:28:25.52,EN,,0,0,0,,And then we can make some inputs. Dialogue: 0,0:28:26.03,0:28:29.18,EN,,0,0,0,,Ok? There's input-1, input-2, a sum and a carry, which are wires. Dialogue: 0,0:28:29.46,0:28:31.88,EN,,0,0,0,,I'm going to put a special kind of object called a probe Dialogue: 0,0:28:32.51,0:28:34.64,EN,,0,0,0,,onto, onto some of the wires, Dialogue: 0,0:28:34.97,0:28:36.24,EN,,0,0,0,,onto sum and onto carry. Dialogue: 0,0:28:37.23,0:28:40.56,EN,,0,0,0,,A probe is a, can object that has the property Dialogue: 0,0:28:40.70,0:28:43.60,EN,,0,0,0,,that when you change a wire it's attached to, Dialogue: 0,0:28:43.72,0:28:44.83,EN,,0,0,0,,it types out a message. Dialogue: 0,0:28:46.12,0:28:46.92,EN,,0,0,0,,It's an easy thing to do. Dialogue: 0,0:28:48.44,0:28:49.52,EN,,0,0,0,,And then once we have that, Dialogue: 0,0:28:49.55,0:28:51.45,EN,,0,0,0,,of course, then when you put the probe on, Dialogue: 0,0:28:51.45,0:28:52.41,EN,,0,0,0,,the first thing it does, it says, Dialogue: 0,0:28:52.67,0:28:56.01,EN,,0,0,0,,the current value of the sum at time 0 is 0 Dialogue: 0,0:28:57.29,0:28:58.43,EN,,0,0,0,,And because I just noticed it. Dialogue: 0,0:28:59.40,0:29:04.75,EN,,0,0,0,,And the value of the carry at time 0, this is the time, is 0. Dialogue: 0,0:29:06.04,0:29:09.28,EN,,0,0,0,,And then we go off and we build some structure. Dialogue: 0,0:29:09.62,0:29:12.28,EN,,0,0,0,,Like, we can build a structure here that says Dialogue: 0,0:29:14.06,0:29:18.20,EN,,0,0,0,,you have a half-adder on input-1, input-2, sum, and carry. Dialogue: 0,0:29:18.42,0:29:20.42,EN,,0,0,0,,And we're going to set the signal on input-1 to 1. Dialogue: 0,0:29:20.62,0:29:21.72,EN,,0,0,0,,We do some propagation. Dialogue: 0,0:29:21.88,0:29:22.84,EN,,0,0,0,,At time 8, Dialogue: 0,0:29:23.90,0:29:26.12,EN,,0,0,0,,which you could see going through this thing if you wanted to, Dialogue: 0,0:29:26.52,0:29:29.20,EN,,0,0,0,,the new value of sum became 1. Dialogue: 0,0:29:29.52,0:29:30.44,EN,,0,0,0,,And the thing says I'm done. Dialogue: 0,0:29:31.16,0:29:32.25,EN,,0,0,0,,That wasn't very interesting. Dialogue: 0,0:29:32.63,0:29:33.90,EN,,0,0,0,,But we can send it some more signals. Dialogue: 0,0:29:34.06,0:29:36.73,EN,,0,0,0,,Like, we set-signal on input-2 to be one. Dialogue: 0,0:29:36.89,0:29:38.09,EN,,0,0,0,,And at that time if we propagate, Dialogue: 0,0:29:38.36,0:29:39.95,EN,,0,0,0,,then it carried at 11, Dialogue: 0,0:29:40.12,0:29:41.42,EN,,0,0,0,,the carry becomes 1, Dialogue: 0,0:29:41.55,0:29:44.19,EN,,0,0,0,,and at 16, the sum's new value becomes 0. Dialogue: 0,0:29:45.39,0:29:48.99,EN,,0,0,0,,And you might want to work out that, if you like, about the digital circuitry. Dialogue: 0,0:29:48.99,0:29:50.12,EN,,0,0,0,,It's true, and it works. Dialogue: 0,0:29:50.62,0:29:51.53,EN,,0,0,0,,And it's not very interesting. Dialogue: 0,0:29:51.53,0:29:54.12,EN,,0,0,0,,But that's the kind of behavior we get out of this thing. Dialogue: 0,0:30:01.83,0:30:03.29,EN,,0,0,0,,So what I've shown you right now Dialogue: 0,0:30:03.48,0:30:05.52,EN,,0,0,0,,is a large-scale picture, Dialogue: 0,0:30:06.60,0:30:08.56,EN,,0,0,0,,how you, at a bigger, big scale, Dialogue: 0,0:30:08.72,0:30:12.04,EN,,0,0,0,,you implement an event-driven simulation of some sort. Dialogue: 0,0:30:13.29,0:30:14.56,EN,,0,0,0,,And how you might organize it Dialogue: 0,0:30:14.88,0:30:16.70,EN,,0,0,0,,to have nice hierarchical structure Dialogue: 0,0:30:16.99,0:30:21.00,EN,,0,0,0,,allowing you to build abstract boxes that you can instantiate. Dialogue: 0,0:30:21.56,0:30:24.96,EN,,0,0,0,,But I haven't told you any of the details about how this agenda and things like that work. Dialogue: 0,0:30:25.78,0:30:26.54,EN,,0,0,0,,That we'll do next. Dialogue: 0,0:30:28.63,0:30:32.94,EN,,0,0,0,,And that's going to involve change and mutation of data and things like that. Dialogue: 0,0:30:34.31,0:30:35.86,EN,,0,0,0,,Are there any questions now, before I go on? Dialogue: 0,0:30:47.16,0:30:48.24,EN,,0,0,0,,Thank you. Let's take a break. Dialogue: 0,0:30:50.24,0:31:00.62,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:31:28.94,0:31:35.06,EN,,0,0,0,,Well, we've been making a simulation. Dialogue: 0,0:31:35.39,0:31:37.77,EN,,0,0,0,,And the simulation is an event-driven simulation Dialogue: 0,0:31:38.17,0:31:42.75,EN,,0,0,0,,where the objects in the world are the objects in the computer. Dialogue: 0,0:31:43.92,0:31:47.28,EN,,0,0,0,,And the changes of state that are happening in the world in time Dialogue: 0,0:31:47.98,0:31:50.83,EN,,0,0,0,,are organized to be time in the computer, Dialogue: 0,0:31:52.99,0:31:56.04,EN,,0,0,0,,so that if something happens after something else in the world, Dialogue: 0,0:31:56.46,0:31:57.96,EN,,0,0,0,,then we have it happen after, Dialogue: 0,0:31:58.89,0:32:02.25,EN,,0,0,0,,after the corresponding events happen in the same order in the computer. Dialogue: 0,0:32:04.42,0:32:07.16,EN,,0,0,0,,That's where we have assignments, when we make that alignment. Dialogue: 0,0:32:08.22,0:32:11.21,EN,,0,0,0,,Right now I want to show you a way of organizing time, Dialogue: 0,0:32:11.80,0:32:14.86,EN,,0,0,0,,which is an agenda or priority queue, it's sometimes called. Dialogue: 0,0:32:16.04,0:32:18.57,EN,,0,0,0,,We'll do some--we'll do a little bit of just understanding Dialogue: 0,0:32:18.62,0:32:21.00,EN,,0,0,0,,what are the things we need to be able to do to make agendas. Dialogue: 0,0:32:28.33,0:32:31.28,EN,,0,0,0,,And so we're going to have--and so right now over here, I'm going to write down a bunch Dialogue: 0,0:32:31.39,0:32:33.88,EN,,0,0,0,,of primitive operations for manipulating agendas. Dialogue: 0,0:32:35.96,0:32:37.95,EN,,0,0,0,,I'm not going to show you the code for them Dialogue: 0,0:32:38.14,0:32:39.58,EN,,0,0,0,,because they're all very simple, Dialogue: 0,0:32:40.32,0:32:42.60,EN,,0,0,0,,Iand you've got listings of all that anyway. Dialogue: 0,0:32:43.68,0:32:44.38,EN,,0,0,0,,So what do we have? Dialogue: 0,0:32:44.38,0:32:53.50,EN,,0,0,0,,We have things like make-agenda which produces a new agenda. Dialogue: 0,0:32:57.36,0:33:01.77,EN,,0,0,0,,We can ask--we get the current-time of an agenda, Dialogue: 0,0:33:07.47,0:33:12.80,EN,,0,0,0,,of an agenda, which gives me a number, a time. Dialogue: 0,0:33:16.99,0:33:21.37,EN,,0,0,0,,We can get--we can ask whether an agenda is empty, empty-agenda. Dialogue: 0,0:33:30.20,0:33:32.57,EN,,0,0,0,,And that produces either a true or a false. Dialogue: 0,0:33:42.72,0:33:44.72,EN,,0,0,0,,We can add an object to an agenda. Dialogue: 0,0:33:52.71,0:33:56.06,EN,,0,0,0,,Actually, what we add to an agenda is an operation--an action to be done. Dialogue: 0,0:33:56.91,0:33:58.14,EN,,0,0,0,,And that takes a time, Dialogue: 0,0:33:59.63,0:34:00.56,EN,,0,0,0,,the action itself, Dialogue: 0,0:34:02.86,0:34:04.64,EN,,0,0,0,,and the agenda I want to add it to. Dialogue: 0,0:34:07.58,0:34:10.25,EN,,0,0,0,,OK? That inserts it in the appropriate place in the agenda. Dialogue: 0,0:34:10.71,0:34:12.73,EN,,0,0,0,,I can get the first item off an agenda, Dialogue: 0,0:34:14.24,0:34:15.39,EN,,0,0,0,,the first thing I have to do, Dialogue: 0,0:34:21.84,0:34:23.84,EN,,0,0,0,,which is going to give me an action. Dialogue: 0,0:34:26.46,0:34:28.73,EN,,0,0,0,,And I can remove the first item from an agenda. Dialogue: 0,0:34:29.54,0:34:31.16,EN,,0,0,0,,That's what I have to be able to do with agendas. Dialogue: 0,0:34:31.40,0:34:33.02,EN,,0,0,0,,That is a big complicated mess. Dialogue: 0,0:34:42.53,0:34:43.36,EN,,0,0,0,,From an agenda. Dialogue: 0,0:34:45.98,0:34:49.85,EN,,0,0,0,,Well, let's see how we can organize this thing as a data structure a bit. Dialogue: 0,0:34:52.96,0:34:56.04,EN,,0,0,0,,Well, an agenda is going to be some kind of list. Dialogue: 0,0:34:58.43,0:35:01.20,EN,,0,0,0,,And it's going to be a list that I'm going to have to be able to modify. Dialogue: 0,0:35:01.57,0:35:04.03,EN,,0,0,0,,So we have to talk about modifying of lists, Dialogue: 0,0:35:05.80,0:35:06.89,EN,,0,0,0,,because I'm going to add things to it, Dialogue: 0,0:35:07.77,0:35:10.27,EN,,0,0,0,,and delete things from it, and things like that. Dialogue: 0,0:35:11.07,0:35:12.51,EN,,0,0,0,,It's organized by time. Dialogue: 0,0:35:13.82,0:35:15.57,EN,,0,0,0,,It's probably good to keep it in sorted order. Dialogue: 0,0:35:18.33,0:35:20.88,EN,,0,0,0,,But sometimes there are lots of things that happen at the same time Dialogue: 0,0:35:22.04,0:35:23.42,EN,,0,0,0,,approximate same time. Dialogue: 0,0:35:23.80,0:35:24.72,EN,,0,0,0,,What I have to do is say, Dialogue: 0,0:35:24.91,0:35:27.52,EN,,0,0,0,,group things by the time at which they're supposed to happen. Dialogue: 0,0:35:29.04,0:35:31.61,EN,,0,0,0,,So I'm going to make an agenda as a list of segments. Dialogue: 0,0:35:32.78,0:35:35.69,EN,,0,0,0,,And so I'm going to draw you a data structure for an agenda, Dialogue: 0,0:35:36.68,0:35:37.93,EN,,0,0,0,,a perfectly reasonable one. Dialogue: 0,0:35:39.62,0:35:40.49,EN,,0,0,0,,Here's an agenda. Dialogue: 0,0:35:41.11,0:35:42.87,EN,,0,0,0,,It's a thing that begins with a name. Dialogue: 0,0:35:47.85,0:35:50.19,EN,,0,0,0,,I'm going to do it right now out of list structure. Dialogue: 0,0:35:52.60,0:35:53.39,EN,,0,0,0,,It's got a header. Dialogue: 0,0:35:54.14,0:35:55.44,EN,,0,0,0,,There's a reason for the header. Dialogue: 0,0:35:55.84,0:35:57.63,EN,,0,0,0,,We're going to see the reason soon. Dialogue: 0,0:36:00.68,0:36:03.40,EN,,0,0,0,,And it will have a segment. We will have-- Dialogue: 0,0:36:03.96,0:36:05.62,EN,,0,0,0,,It will have--it will be a list of segments. Dialogue: 0,0:36:08.31,0:36:10.54,EN,,0,0,0,,Supposing this agenda has two segments, Dialogue: 0,0:36:11.58,0:36:15.07,EN,,0,0,0,,OK, they're the car's-- successive car's of this list. Dialogue: 0,0:36:16.41,0:36:20.57,EN,,0,0,0,,Each segment is going to have a time-- Dialogue: 0,0:36:24.20,0:36:26.64,EN,,0,0,0,,say for example, 10-- Dialogue: 0,0:36:26.83,0:36:30.51,EN,,0,0,0,,that says that the things that happen in this segment are at time 10. Dialogue: 0,0:36:33.16,0:36:36.52,EN,,0,0,0,,And what I'm going to have in here is another data structure Dialogue: 0,0:36:36.56,0:36:38.01,EN,,0,0,0,,which I'm not going to describe, Dialogue: 0,0:36:38.49,0:36:41.08,EN,,0,0,0,,which is a queue of things to do at time 10. Dialogue: 0,0:36:42.24,0:36:43.33,EN,,0,0,0,,It's a queue. Dialogue: 0,0:36:43.33,0:36:44.70,EN,,0,0,0,,And we'll talk about that in a second. Dialogue: 0,0:36:45.20,0:36:50.35,EN,,0,0,0,,But abstractly, the queue is just a list of things to do at a particular time. Dialogue: 0,0:36:50.40,0:36:52.04,EN,,0,0,0,,And I can add things to a queue. Dialogue: 0,0:36:53.10,0:36:53.80,EN,,0,0,0,,This is a queue. Dialogue: 0,0:36:56.14,0:36:59.11,EN,,0,0,0,,There's a time, there's a segment. Dialogue: 0,0:37:03.23,0:37:06.36,EN,,0,0,0,,Now, I may have another segment in this agenda. Dialogue: 0,0:37:08.94,0:37:11.20,EN,,0,0,0,,Supposing this is stuff that happens at time 30. Dialogue: 0,0:37:13.50,0:37:15.92,EN,,0,0,0,,It has, of course, another queue Dialogue: 0,0:37:16.92,0:37:20.24,EN,,0,0,0,,of things that are queued up to be done at time 30. Dialogue: 0,0:37:23.21,0:37:25.66,EN,,0,0,0,,Well, there are various things I have to be able to do to an agenda. Dialogue: 0,0:37:27.09,0:37:29.20,EN,,0,0,0,,Supposing I want to add to an agenda Dialogue: 0,0:37:29.47,0:37:31.61,EN,,0,0,0,,another thing to be done at time 10. Dialogue: 0,0:37:33.03,0:37:34.16,EN,,0,0,0,,Well, that's not very hard. Dialogue: 0,0:37:34.70,0:37:38.65,EN,,0,0,0,,I'm going to walk down here, looking for the segment of time 10. Dialogue: 0,0:37:39.73,0:37:42.14,EN,,0,0,0,,It is possible that there is no segment of time 10. Dialogue: 0,0:37:42.93,0:37:44.56,EN,,0,0,0,,We'll cover that case in a second. Dialogue: 0,0:37:45.42,0:37:47.56,EN,,0,0,0,,But if I find a segment of time 10, Dialogue: 0,0:37:47.87,0:37:50.43,EN,,0,0,0,,then if I want to add another thing to be done at time 10, Dialogue: 0,0:37:50.56,0:37:52.16,EN,,0,0,0,,I just increase that queue-- Dialogue: 0,0:37:53.85,0:37:56.22,EN,,0,0,0,,"just increase" isn't such an obvious idea. Dialogue: 0,0:37:56.57,0:37:59.26,EN,,0,0,0,,But I increase the things to be done at that time. Dialogue: 0,0:38:01.43,0:38:04.25,EN,,0,0,0,,Now, supposing I want to add something to be done at time 20. Dialogue: 0,0:38:05.31,0:38:07.90,EN,,0,0,0,,There is no segment for time 20. Dialogue: 0,0:38:08.99,0:38:10.64,EN,,0,0,0,,I'm going to have to create a new segment. Dialogue: 0,0:38:11.34,0:38:15.64,EN,,0,0,0,,I want my time 20 segment to exist between time 10 and time 30. Dialogue: 0,0:38:17.61,0:38:19.32,EN,,0,0,0,,Well, that takes a little work. Dialogue: 0,0:38:20.17,0:38:21.52,EN,,0,0,0,,I'm going to have to do a CONS. Dialogue: 0,0:38:24.26,0:38:29.94,EN,,0,0,0,,I'm going to have to make a new element of the agenda list--list of segments. Dialogue: 0,0:38:33.60,0:38:34.81,EN,,0,0,0,,I'm going to have to change. Dialogue: 0,0:38:35.40,0:38:36.30,EN,,0,0,0,,Here's change. Dialogue: 0,0:38:37.54,0:38:42.80,EN,,0,0,0,,I'm going to have to change the CDR of the CDR of the agenda Dialogue: 0,0:38:44.88,0:38:49.45,EN,,0,0,0,,point that a new CONS of the new segment Dialogue: 0,0:38:50.11,0:38:54.65,EN,,0,0,0,,and the CDR of the CDR of the CDR of the agenda, the CD-D-D-DR. Dialogue: 0,0:38:57.18,0:39:01.88,EN,,0,0,0,,And this is going to have a new segment now of time 20 Dialogue: 0,0:39:02.30,0:39:03.72,EN,,0,0,0,,with its own queue, Dialogue: 0,0:39:04.84,0:39:06.29,EN,,0,0,0,,which now has one element in it. Dialogue: 0,0:39:10.73,0:39:12.52,EN,,0,0,0,,If I wanted to add something at the end, Dialogue: 0,0:39:12.54,0:39:15.87,EN,,0,0,0,,I'm going to have to replace the CDR of this, Dialogue: 0,0:39:16.99,0:39:19.21,EN,,0,0,0,,of this list with something. Dialogue: 0,0:39:20.59,0:39:23.31,EN,,0,0,0,,We're have to change that piece of data structure. Dialogue: 0,0:39:24.04,0:39:25.79,EN,,0,0,0,,So I'm going to need new primitives for doing this. Dialogue: 0,0:39:27.21,0:39:28.62,EN,,0,0,0,,But I'm just showing you why I need them. Dialogue: 0,0:39:29.44,0:39:33.88,EN,,0,0,0,,And finally, if I wanted to add a thing to be done at time 5, Dialogue: 0,0:39:37.12,0:39:39.20,EN,,0,0,0,,I'm going to have to change this one, Dialogue: 0,0:39:40.81,0:39:42.12,EN,,0,0,0,,because I'm going to have to add it in over here, Dialogue: 0,0:39:43.29,0:39:46.22,EN,,0,0,0,,which is why I planned ahead and had a header cell, Dialogue: 0,0:39:47.56,0:39:48.59,EN,,0,0,0,,which has a place. Dialogue: 0,0:39:49.40,0:39:52.11,EN,,0,0,0,,If I'm going to change things, I have to have places for the change. Dialogue: 0,0:39:53.88,0:39:56.56,EN,,0,0,0,,I have to have a place to make the change. Dialogue: 0,0:39:58.60,0:40:02.54,EN,,0,0,0,,If I remove things from the agenda, that's not so hard. Dialogue: 0,0:40:02.54,0:40:04.62,EN,,0,0,0,,Removing them from the beginning is pretty easy, Dialogue: 0,0:40:04.92,0:40:06.14,EN,,0,0,0,,which is the only case I have. Dialogue: 0,0:40:06.49,0:40:10.19,EN,,0,0,0,,I can go looking for the first, the first segment. Dialogue: 0,0:40:11.22,0:40:14.00,EN,,0,0,0,,I see if it has a non-empty queue. Dialogue: 0,0:40:14.81,0:40:16.17,EN,,0,0,0,,If it has a non-empty queue, Dialogue: 0,0:40:16.32,0:40:18.62,EN,,0,0,0,,well, I'm going to delete one element from the queue Dialogue: 0,0:40:19.21,0:40:19.74,EN,,0,0,0,,like that. Dialogue: 0,0:40:20.10,0:40:21.92,EN,,0,0,0,,If the queue ever becomes empty, Dialogue: 0,0:40:22.64,0:40:24.22,EN,,0,0,0,,then I have to delete the whole segment. Dialogue: 0,0:40:24.22,0:40:26.49,EN,,0,0,0,,And then this, this changes to point to here. Dialogue: 0,0:40:28.22,0:40:31.08,EN,,0,0,0,,So it's quite a complicated data structure manipulation going on, Dialogue: 0,0:40:32.25,0:40:35.37,EN,,0,0,0,,the details of which are not really very exciting. Dialogue: 0,0:40:36.44,0:40:38.48,EN,,0,0,0,,Now, let's talk about queues. Dialogue: 0,0:40:38.92,0:40:39.76,EN,,0,0,0,,They're similar. Dialogue: 0,0:40:41.16,0:40:43.52,EN,,0,0,0,,Because each of these agendas has a queue in it. Dialogue: 0,0:40:44.34,0:40:45.02,EN,,0,0,0,,What's a queue? Dialogue: 0,0:40:49.47,0:40:51.85,EN,,0,0,0,,A queue is going to have the following primitive operations. Dialogue: 0,0:40:52.78,0:41:02.17,EN,,0,0,0,,To make a queue, this gives me a new queue. Dialogue: 0,0:41:07.77,0:41:17.10,EN,,0,0,0,,I'm going to have to be able to insert into a queue a new item. Dialogue: 0,0:41:24.51,0:41:28.65,EN,,0,0,0,,I'm going to have to be able to delete from a queue the first item in the queue. Dialogue: 0,0:41:40.44,0:41:52.04,EN,,0,0,0,,And I want to be able to get the first thing in the queue from some queue. Dialogue: 0,0:41:53.13,0:41:55.14,EN,,0,0,0,,I also have to be able to test whether a queue is empty. Dialogue: 0,0:42:07.11,0:42:08.70,EN,,0,0,0,,And when you invent things like this, Dialogue: 0,0:42:09.02,0:42:10.44,EN,,0,0,0,,I want you to be very careful Dialogue: 0,0:42:10.64,0:42:14.09,EN,,0,0,0,,to use the kinds of conventions I use for naming things. Dialogue: 0,0:42:15.12,0:42:19.15,EN,,0,0,0,,Notice that I'm careful to say these change something and that tests it. Dialogue: 0,0:42:19.87,0:42:21.85,EN,,0,0,0,,And presumably, I did the same thing over here. Dialogue: 0,0:42:24.65,0:42:26.96,EN,,0,0,0,,OK, and there should be an empty test over here. Dialogue: 0,0:42:29.24,0:42:30.72,EN,,0,0,0,,OK, well, how would I make a queue? Dialogue: 0,0:42:31.72,0:42:34.11,EN,,0,0,0,,A queue wants to be something I can add to at the end of, Dialogue: 0,0:42:35.12,0:42:36.83,EN,,0,0,0,,and pick up the thing at the beginning of. Dialogue: 0,0:42:37.84,0:42:40.51,EN,,0,0,0,,I should be able to delete from the beginning and add to the end. Dialogue: 0,0:42:41.23,0:42:43.24,EN,,0,0,0,,Well, I'm going to show you a very simple structure for that. Dialogue: 0,0:42:43.88,0:42:45.72,EN,,0,0,0,,We can make this out of CONSes as well. Dialogue: 0,0:42:47.08,0:42:47.79,EN,,0,0,0,,Here's a queue. Dialogue: 0,0:42:49.91,0:42:52.36,EN,,0,0,0,,It has--it has a queue header, Dialogue: 0,0:42:53.58,0:42:54.92,EN,,0,0,0,,which contains two parts-- Dialogue: 0,0:42:55.28,0:42:56.25,EN,,0,0,0,,a front pointer Dialogue: 0,0:42:58.78,0:42:59.82,EN,,0,0,0,,and a rear pointer. Dialogue: 0,0:43:03.12,0:43:06.33,EN,,0,0,0,,And here I have a queue with two items in it. Dialogue: 0,0:43:09.13,0:43:12.09,EN,,0,0,0,,The first item, I don't know, it's perhaps a 1. Dialogue: 0,0:43:12.46,0:43:16.53,EN,,0,0,0,,And the second item, I don't know, let's give it a 2. Dialogue: 0,0:43:21.40,0:43:23.52,EN,,0,0,0,,The reason why I want two pointers in here, Dialogue: 0,0:43:24.09,0:43:25.61,EN,,0,0,0,,a front pointer and a rear pointer, Dialogue: 0,0:43:25.72,0:43:27.10,EN,,0,0,0,,is so I can add to the end Dialogue: 0,0:43:27.48,0:43:29.45,EN,,0,0,0,,without having to chase down from the beginning. Dialogue: 0,0:43:31.85,0:43:34.80,EN,,0,0,0,,So for example, if I wanted to add one more item to this queue, Dialogue: 0,0:43:35.26,0:43:41.02,EN,,0,0,0,,if I want to add on another item to be worried about later, Dialogue: 0,0:43:41.08,0:43:42.40,EN,,0,0,0,,all I have to do is make a CONS, Dialogue: 0,0:43:43.47,0:43:46.59,EN,,0,0,0,,which contains that item, say a 3. Dialogue: 0,0:43:47.53,0:43:51.34,EN,,0,0,0,,That's for inserting 3 into the queue. Dialogue: 0,0:43:51.52,0:43:53.77,EN,,0,0,0,,Then I have to change this pointer here Dialogue: 0,0:43:56.94,0:43:58.76,EN,,0,0,0,,Okay? to here. Dialogue: 0,0:44:00.10,0:44:04.32,EN,,0,0,0,,And I have to change this one to point to the new rear. Dialogue: 0,0:44:09.12,0:44:12.68,EN,,0,0,0,,If I wish to take the first element of the queue, the first item, Dialogue: 0,0:44:12.96,0:44:17.12,EN,,0,0,0,,I just go chasing down the front pointer until I find the first one and pick it up. Dialogue: 0,0:44:18.89,0:44:23.26,EN,,0,0,0,,If I wish to delete the first item from the queue, delete-queue, Dialogue: 0,0:44:24.14,0:44:26.35,EN,,0,0,0,,all I do is move the front pointer along this way. Dialogue: 0,0:44:27.71,0:44:29.31,EN,,0,0,0,,The new front of the queue is now this. Dialogue: 0,0:44:31.70,0:44:33.13,EN,,0,0,0,,So queues are very simple too. Dialogue: 0,0:44:34.48,0:44:35.76,EN,,0,0,0,,So what you see now Dialogue: 0,0:44:37.24,0:44:40.83,EN,,0,0,0,,is that I need a certain number of new primitive operations. Dialogue: 0,0:44:41.48,0:44:42.56,EN,,0,0,0,,And I'm going to give them some names. Dialogue: 0,0:44:42.99,0:44:46.28,EN,,0,0,0,,And then we're going to look into how they work, and how they're used. Dialogue: 0,0:44:47.35,0:44:55.04,EN,,0,0,0,,We have set the CAR of some pair, Dialogue: 0,0:44:55.88,0:44:59.36,EN,,0,0,0,,or a thing produced by CONSing, to a new value. Dialogue: 0,0:45:02.37,0:45:09.92,EN,,0,0,0,,And set the CDR of a pair to a new value. Dialogue: 0,0:45:13.02,0:45:14.78,EN,,0,0,0,,And then we're going to look into how they work. Dialogue: 0,0:45:16.03,0:45:20.51,EN,,0,0,0,,I needed setting CAR over here to delete the first element of the queue. Dialogue: 0,0:45:20.96,0:45:22.52,EN,,0,0,0,,This is the CAR, and I had to set it. Dialogue: 0,0:45:23.47,0:45:24.96,EN,,0,0,0,,I had to be able to set the CDR Dialogue: 0,0:45:25.28,0:45:27.08,EN,,0,0,0,,to be able to move the rear pointer, Dialogue: 0,0:45:27.21,0:45:28.76,EN,,0,0,0,,or to be able to increment the queue here. Dialogue: 0,0:45:30.16,0:45:31.60,EN,,0,0,0,,All of the operations I did Dialogue: 0,0:45:31.90,0:45:35.90,EN,,0,0,0,,were made out of those that I just showed you on the, on the last blackboard. Dialogue: 0,0:45:38.17,0:45:40.14,EN,,0,0,0,,Good. Let's pause the time, and take a little break then. Dialogue: 0,0:45:41.24,0:45:52.67,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:46:38.81,0:46:43.53,EN,,0,0,0,,When we originally introduced pairs made out of CONS, made by CONS, Dialogue: 0,0:46:44.57,0:46:46.80,EN,,0,0,0,,we only said a few axioms about them, Dialogue: 0,0:46:48.09,0:46:50.76,EN,,0,0,0,,which were of the form-- what were they-- Dialogue: 0,0:46:52.28,0:47:03.64,EN,,0,0,0,,for all X and Y, the CAR of the CONS of X and Y is X Dialogue: 0,0:47:05.31,0:47:12.92,EN,,0,0,0,,and Y is X and the CDR of the CONS of X and Y is Y. Dialogue: 0,0:47:14.80,0:47:20.00,EN,,0,0,0,,Now, these say nothing about whether a CONS has an identity like a person. Dialogue: 0,0:47:21.85,0:47:25.58,EN,,0,0,0,,In fact, all they say is something sort of abstract, Dialogue: 0,0:47:25.74,0:47:27.95,EN,,0,0,0,,that a CONS is the parts it's made out of. Dialogue: 0,0:47:29.74,0:47:33.18,EN,,0,0,0,,And of course, two things are made out of the same parts, they're the same, Dialogue: 0,0:47:33.93,0:47:35.71,EN,,0,0,0,,at least from the point of view of these axioms. Dialogue: 0,0:47:37.32,0:47:39.21,EN,,0,0,0,,But by introducing assignment-- Dialogue: 0,0:47:39.84,0:47:42.32,EN,,0,0,0,,in fact, mutable data is a kind of assignment, Dialogue: 0,0:47:42.88,0:47:44.43,EN,,0,0,0,,we have a set CAR and a set CDR-- Dialogue: 0,0:47:45.55,0:47:48.94,EN,,0,0,0,,by introducing those, these axioms no longer tell the whole story. Dialogue: 0,0:47:49.83,0:47:52.03,EN,,0,0,0,,And they're still true if written exactly like this. Dialogue: 0,0:47:53.25,0:47:54.94,EN,,0,0,0,,But they don't tell the whole story. Dialogue: 0,0:47:56.07,0:48:01.68,EN,,0,0,0,,Because if I'm going to set a particular CAR in a particular CONS, Dialogue: 0,0:48:03.02,0:48:04.03,EN,,0,0,0,,the questions are, Dialogue: 0,0:48:04.24,0:48:08.64,EN,,0,0,0,,well, is that setting all CARs and all CONSes of the same two things or not? Dialogue: 0,0:48:10.09,0:48:13.04,EN,,0,0,0,,If I--if we use CONSes to make up things like rational numbers, Dialogue: 0,0:48:14.86,0:48:17.10,EN,,0,0,0,,or things like 3 over 4, Dialogue: 0,0:48:17.34,0:48:20.25,EN,,0,0,0,,supposing I had two three-fourths. Dialogue: 0,0:48:21.57,0:48:22.75,EN,,0,0,0,,Are they the same one-- Dialogue: 0,0:48:24.06,0:48:24.89,EN,,0,0,0,,or are they different? Dialogue: 0,0:48:25.34,0:48:26.96,EN,,0,0,0,,Well, in the case of numbers, it doesn't matter. Dialogue: 0,0:48:27.86,0:48:30.49,EN,,0,0,0,,Because there's no meaning to changing the denominator of a number. Dialogue: 0,0:48:33.02,0:48:35.32,EN,,0,0,0,,What you could do is make a number which has a different denominator. Dialogue: 0,0:48:36.84,0:48:39.88,EN,,0,0,0,,But the concept of changing a number which has to have a different denominator Dialogue: 0,0:48:40.00,0:48:43.58,EN,,0,0,0,,is sort of a very weird, and sort of not supported by what you think of as mathematics. Dialogue: 0,0:48:44.77,0:48:47.40,EN,,0,0,0,,However, when these CONSes represent things in the physical world, Dialogue: 0,0:48:48.97,0:48:50.43,EN,,0,0,0,,then changing something like the CAR Dialogue: 0,0:48:50.60,0:48:52.20,EN,,0,0,0,,like removing a piece of the fingernail. Dialogue: 0,0:48:53.69,0:48:56.56,EN,,0,0,0,,And so CONSes have an identity. Dialogue: 0,0:48:57.77,0:48:59.92,EN,,0,0,0,,Let me show you what I mean about identity, first of all. Dialogue: 0,0:49:01.28,0:49:03.05,EN,,0,0,0,,Let's do some little example here. Dialogue: 0,0:49:04.32,0:49:15.20,EN,,0,0,0,,Supposing I define A to the CONS of 1 and 2. Dialogue: 0,0:49:18.32,0:49:19.76,EN,,0,0,0,,Well, what that means, first of all, Dialogue: 0,0:49:20.67,0:49:25.20,EN,,0,0,0,,is that somewhere in some environment I've made a symbol A Dialogue: 0,0:49:25.96,0:49:28.67,EN,,0,0,0,,to have a value which is a pair Dialogue: 0,0:49:29.47,0:49:34.06,EN,,0,0,0,,consisting of pointers to a 1 and a pointer to a 2, Dialogue: 0,0:49:35.34,0:49:36.16,EN,,0,0,0,,just like that. Dialogue: 0,0:49:38.12,0:49:39.60,EN,,0,0,0,,Now, supposing I also say Dialogue: 0,0:49:40.22,0:49:47.58,EN,,0,0,0,,define B to be the CONS-- Dialogue: 0,0:49:53.88,0:49:56.81,EN,,0,0,0,,it doesn't matter, but I like it better, it's prettier-- Dialogue: 0,0:49:57.63,0:49:59.88,EN,,0,0,0,,of A and A. Dialogue: 0,0:50:03.97,0:50:06.03,EN,,0,0,0,,Well, first of all, I'm using the name A twice. Dialogue: 0,0:50:07.84,0:50:10.57,EN,,0,0,0,,At this moment, I'm going to think of CONSes as having identity. Dialogue: 0,0:50:11.30,0:50:12.64,EN,,0,0,0,,This is the same one. Dialogue: 0,0:50:13.69,0:50:14.81,EN,,0,0,0,,And so what that means Dialogue: 0,0:50:15.29,0:50:17.61,EN,,0,0,0,,is I make another pair, Dialogue: 0,0:50:18.81,0:50:20.20,EN,,0,0,0,,which I'm going to call B. Dialogue: 0,0:50:22.38,0:50:27.60,EN,,0,0,0,,And it contains two pointers to A. Dialogue: 0,0:50:28.92,0:50:32.20,EN,,0,0,0,,At this point, I have three names for this object. Dialogue: 0,0:50:33.10,0:50:34.16,EN,,0,0,0,,A is its name. Dialogue: 0,0:50:34.88,0:50:36.46,EN,,0,0,0,,The CAR of B is its name. Dialogue: 0,0:50:37.23,0:50:38.86,EN,,0,0,0,,And the CDR of B is its name. Dialogue: 0,0:50:39.36,0:50:41.15,EN,,0,0,0,,It has several aliases, they're called. Dialogue: 0,0:50:44.23,0:50:49.28,EN,,0,0,0,,Now, supposing I do something like set-the-CAR, Dialogue: 0,0:50:53.77,0:51:08.38,EN,,0,0,0,,the CAR of the CAR of B to 3. Dialogue: 0,0:51:12.75,0:51:17.45,EN,,0,0,0,,What that means is I find the CAR of B, that's this. Dialogue: 0,0:51:17.83,0:51:20.93,EN,,0,0,0,,I set the CAR of that to be 3, changing this. Dialogue: 0,0:51:24.76,0:51:25.69,EN,,0,0,0,,I've changed A. Dialogue: 0,0:51:27.24,0:51:33.64,EN,,0,0,0,,If I were to ask what's the CAR of A--of A now? Dialogue: 0,0:51:35.34,0:51:37.56,EN,,0,0,0,,I would get out 3, Dialogue: 0,0:51:38.68,0:51:43.39,EN,,0,0,0,,even though here we see that A was the CONS of 1 and 2. Dialogue: 0,0:51:45.29,0:51:47.44,EN,,0,0,0,,I caused A to change by changing B. Dialogue: 0,0:51:48.56,0:51:49.64,EN,,0,0,0,,There is sharing here. Dialogue: 0,0:51:52.25,0:51:53.47,EN,,0,0,0,,That's sometimes what we want. Dialogue: 0,0:51:54.24,0:51:56.12,EN,,0,0,0,,Surely in the queues and things like that, Dialogue: 0,0:51:56.24,0:52:02.38,EN,,0,0,0,,that's exactly what we defined our--organized our data structures to facilitate-- sharing. Dialogue: 0,0:52:04.35,0:52:05.66,EN,,0,0,0,,But inadvertent sharing, Dialogue: 0,0:52:07.76,0:52:09.72,EN,,0,0,0,,unanticipated interactions between objects, Dialogue: 0,0:52:10.78,0:52:14.08,EN,,0,0,0,,is the source of most of the bugs that occur in complicated programs. Dialogue: 0,0:52:15.44,0:52:21.66,EN,,0,0,0,,So by introducing this possibility of things having identity and sharing Dialogue: 0,0:52:21.87,0:52:23.76,EN,,0,0,0,,and having multiple names for the same thing, Dialogue: 0,0:52:24.08,0:52:25.05,EN,,0,0,0,,we get a lot of power. Dialogue: 0,0:52:25.13,0:52:28.46,EN,,0,0,0,,But we're going to pay for it with lots of complexity and bugs. Dialogue: 0,0:52:32.19,0:52:36.24,EN,,0,0,0,,So also, for example, if I just looked at this just to drive that home, Dialogue: 0,0:52:37.10,0:52:39.87,EN,,0,0,0,,the CADR of B, Dialogue: 0,0:52:42.46,0:52:46.56,EN,,0,0,0,,which has nothing to do with even the CAR of B, apparently. Dialogue: 0,0:52:46.88,0:52:49.02,EN,,0,0,0,,The CADR of B, what's that? Dialogue: 0,0:52:49.35,0:52:53.56,EN,,0,0,0,,Take that CDR of B and now take the CAR of that. Dialogue: 0,0:52:53.56,0:52:54.86,EN,,0,0,0,,Oh, that's 3 also. Dialogue: 0,0:52:56.48,0:53:00.43,EN,,0,0,0,,So I can have non-local interactions by sharing. Dialogue: 0,0:53:01.12,0:53:02.48,EN,,0,0,0,,And I have to be very careful of that. Dialogue: 0,0:53:06.64,0:53:12.64,EN,,0,0,0,,Well, so far, of course, it seems I've introduced several different assignment operators-- Dialogue: 0,0:53:13.18,0:53:17.61,EN,,0,0,0,,set, set CAR, set CDR. Dialogue: 0,0:53:18.51,0:53:21.39,EN,,0,0,0,,Well, maybe I should just get rid of set CAR and set CDR. Maybe they're not worthwhile. Dialogue: 0,0:53:22.82,0:53:23.66,EN,,0,0,0,,Well, the answer is Dialogue: 0,0:53:24.12,0:53:26.11,EN,,0,0,0,,that once you let the camel's nose into the tent, Dialogue: 0,0:53:26.24,0:53:27.34,EN,,0,0,0,,the rest of him follows. Dialogue: 0,0:53:30.16,0:53:31.26,EN,,0,0,0,,All I have to have is set, Dialogue: 0,0:53:31.61,0:53:35.85,EN,,0,0,0,,and I can make all of the--all of the bad things that can happen. Dialogue: 0,0:53:38.55,0:53:39.80,EN,,0,0,0,,Let's play with that a little bit. Dialogue: 0,0:53:40.69,0:53:43.72,EN,,0,0,0,,A couple of days ago, when we introduced compound data, Dialogue: 0,0:53:45.13,0:53:51.20,EN,,0,0,0,,you saw Hal show you a definition of CONS in terms of a message acceptor. Dialogue: 0,0:53:52.48,0:53:56.06,EN,,0,0,0,,I'm going to show you even a more horrible thing, Dialogue: 0,0:53:57.13,0:54:00.04,EN,,0,0,0,,a definition of CONS in terms of nothing but air, Dialogue: 0,0:54:02.56,0:54:03.02,EN,,0,0,0,,hot air. Dialogue: 0,0:54:04.44,0:54:08.12,EN,,0,0,0,,What is the definition of CONS, of the old functional kind, Dialogue: 0,0:54:09.26,0:54:11.66,EN,,0,0,0,,in terms of purely lambdic expressions, Dialogue: 0,0:54:13.39,0:54:14.40,EN,,0,0,0,,procedures? Dialogue: 0,0:54:17.39,0:54:19.66,EN,,0,0,0,,Because I'm going to then modify this definition Dialogue: 0,0:54:20.30,0:54:23.16,EN,,0,0,0,,to get assignment to be only one kind of assignment, Dialogue: 0,0:54:24.28,0:54:27.93,EN,,0,0,0,,to get rid of the set CAR and set CDR in terms of set. Dialogue: 0,0:54:28.58,0:54:37.39,EN,,0,0,0,,So what if I define CONS of X and Y Dialogue: 0,0:54:38.91,0:54:42.56,EN,,0,0,0,,to be a procedure of one argument called a message M, Dialogue: 0,0:54:43.39,0:54:46.32,EN,,0,0,0,,which calls that message on X and Y? Dialogue: 0,0:54:51.12,0:54:53.10,EN,,0,0,0,,This idea was invented by Alonzo Church, Dialogue: 0,0:54:53.77,0:54:55.72,EN,,0,0,0,,who was the greatest programmer of the 20th century, Dialogue: 0,0:54:55.79,0:54:57.15,EN,,0,0,0,,although he never saw a computer. Dialogue: 0,0:54:57.87,0:54:59.13,EN,,0,0,0,,It was done in the 1930s. Dialogue: 0,0:54:59.42,0:55:02.22,EN,,0,0,0,,He was a logician, I suppose at Princeton at the time. Dialogue: 0,0:55:08.66,0:55:10.43,EN,,0,0,0,,Define CAR of X Dialogue: 0,0:55:13.10,0:55:16.92,EN,,0,0,0,,to be the result of applying X to that procedure of two arguments, Dialogue: 0,0:55:17.15,0:55:20.60,EN,,0,0,0,,A and D, which selects A. Dialogue: 0,0:55:23.71,0:55:24.97,EN,,0,0,0,,I will define CDR of X Dialogue: 0,0:55:33.10,0:55:34.78,EN,,0,0,0,,to be that procedure, Dialogue: 0,0:55:35.08,0:55:40.25,EN,,0,0,0,,to be the result of applying X to that procedure of A and D, Dialogue: 0,0:55:40.92,0:55:42.04,EN,,0,0,0,,which selects D. Dialogue: 0,0:55:46.67,0:55:49.88,EN,,0,0,0,,Now, you may not recognize this as CAR, CDR, and CONS. Dialogue: 0,0:55:50.51,0:55:53.61,EN,,0,0,0,,But I'm going to demonstrate to you that it satisfies the original axioms Dialogue: 0,0:55:54.11,0:55:54.81,EN,,0,0,0,,just once. Dialogue: 0,0:55:55.61,0:55:57.56,EN,,0,0,0,,And then we're going to do some playing of games. Dialogue: 0,0:55:58.29,0:56:06.27,EN,,0,0,0,,Consider the problem CAR of CONS of, say, 35 and 47. Dialogue: 0,0:56:09.93,0:56:10.96,EN,,0,0,0,,Well, what is that? Dialogue: 0,0:56:11.12,0:56:15.24,EN,,0,0,0,,It is the result of taking car of the result of substituting 35 and 47 Dialogue: 0,0:56:15.37,0:56:18.20,EN,,0,0,0,,X and Y in the body of this. Dialogue: 0,0:56:19.71,0:56:20.69,EN,,0,0,0,,Well, that's easy enough. Dialogue: 0,0:56:20.69,0:56:30.88,EN,,0,0,0,,That's CAR of the result of substituting into lambda of M, M of 35 and 47. Dialogue: 0,0:56:35.53,0:56:39.36,EN,,0,0,0,,Well, what this is, is the result of substituting this object Dialogue: 0,0:56:39.44,0:56:41.85,EN,,0,0,0,,for X in the body of that. Dialogue: 0,0:56:42.83,0:56:47.66,EN,,0,0,0,,So that's just lambda of M-- Dialogue: 0,0:56:48.33,0:56:52.19,EN,,0,0,0,,that's substituted, because this object is being substituted for X, Dialogue: 0,0:56:52.88,0:56:54.35,EN,,0,0,0,,which is the beginning of a list, Dialogue: 0,0:56:54.88,0:57:00.32,EN,,0,0,0,,lambda of M-- M of 35 and 47, Dialogue: 0,0:57:03.10,0:57:07.31,EN,,0,0,0,,applied to that procedure of A and D, Dialogue: 0,0:57:07.48,0:57:08.67,EN,,0,0,0,,which gives me A. Dialogue: 0,0:57:10.91,0:57:14.62,EN,,0,0,0,,Well, that's the result of substituting this for M here. Dialogue: 0,0:57:15.96,0:57:21.71,EN,,0,0,0,,So that's the same thing as lambda of A, D, A, Dialogue: 0,0:57:22.22,0:57:24.84,EN,,0,0,0,,applied to 35 and 47. Dialogue: 0,0:57:26.33,0:57:27.37,EN,,0,0,0,,Oh, well that's 35. Dialogue: 0,0:57:27.40,0:57:31.21,EN,,0,0,0,,That's substituting 35 for A and for 47 for D in A. Dialogue: 0,0:57:35.60,0:57:37.24,EN,,0,0,0,,So I don't need any data at all. Dialogue: 0,0:57:37.88,0:57:38.75,EN,,0,0,0,,not even numbers. Dialogue: 0,0:57:40.92,0:57:42.64,EN,,0,0,0,,This is Alonso Church's hack. Dialogue: 0,0:57:52.42,0:57:56.17,EN,,0,0,0,,Well, now we're going to do something nasty to him. Dialogue: 0,0:57:56.76,0:57:58.49,EN,,0,0,0,,Being a logician, he wouldn't like this. Dialogue: 0,0:57:59.20,0:58:01.96,EN,,0,0,0,,But as programmers, let's look at the overhead. Dialogue: 0,0:58:03.26,0:58:04.16,EN,,0,0,0,,And here we go. Dialogue: 0,0:58:05.39,0:58:07.58,EN,,0,0,0,,I'm going to change the definition of CONS. Dialogue: 0,0:58:09.57,0:58:12.35,EN,,0,0,0,,It's almost the same as Alonzo Church's, but not quite. Dialogue: 0,0:58:14.41,0:58:15.50,EN,,0,0,0,,What do we have here? Dialogue: 0,0:58:16.07,0:58:18.72,EN,,0,0,0,,The CONS of two arguments, X and Y, Dialogue: 0,0:58:19.50,0:58:22.51,EN,,0,0,0,,is going to be that procedure of one argument M, Dialogue: 0,0:58:23.39,0:58:25.64,EN,,0,0,0,,which supplies M to X and Y as before, Dialogue: 0,0:58:26.19,0:58:29.29,EN,,0,0,0,,but also to two permissions, Dialogue: 0,0:58:30.17,0:58:32.01,EN,,0,0,0,,the permission to set X to N Dialogue: 0,0:58:32.60,0:58:34.40,EN,,0,0,0,,and the permission to set Y to N, Dialogue: 0,0:58:34.44,0:58:35.68,EN,,0,0,0,,given that I have an N. Dialogue: 0,0:58:40.94,0:58:44.72,EN,,0,0,0,,So besides the things that I had here in Church's definition, Dialogue: 0,0:58:45.72,0:58:51.66,EN,,0,0,0,,what I have is that the thing that CONS returns Dialogue: 0,0:58:52.12,0:58:53.82,EN,,0,0,0,,will apply its argument Dialogue: 0,0:58:54.91,0:58:59.44,EN,,0,0,0,,to not just the values of the X and Y that the CONS is made of, Dialogue: 0,0:58:59.69,0:59:03.58,EN,,0,0,0,,but also permissions to set X and Y to new values. Dialogue: 0,0:59:06.54,0:59:08.08,EN,,0,0,0,,Now, of course, just as before, Dialogue: 0,0:59:08.83,0:59:10.51,EN,,0,0,0,,CAR is exactly the same. Dialogue: 0,0:59:11.69,0:59:14.36,EN,,0,0,0,,The CAR of X is nothing more than applying X, Dialogue: 0,0:59:14.54,0:59:16.00,EN,,0,0,0,,as in Church's definition, Dialogue: 0,0:59:16.86,0:59:19.00,EN,,0,0,0,,to a procedure, in this case, of four arguments, Dialogue: 0,0:59:19.29,0:59:21.04,EN,,0,0,0,,which selects out the first one. Dialogue: 0,0:59:22.54,0:59:24.16,EN,,0,0,0,,And just as we did before, Dialogue: 0,0:59:25.42,0:59:26.96,EN,,0,0,0,,that will be the value of X Dialogue: 0,0:59:29.04,0:59:35.40,EN,,0,0,0,,that was contained in the procedure which is the result of evaluating this lambda expression Dialogue: 0,0:59:35.45,0:59:37.84,EN,,0,0,0,,in the environment where X and Y are defined over here. Dialogue: 0,0:59:41.94,0:59:43.15,EN,,0,0,0,,That's the value of CONS. Dialogue: 0,0:59:45.64,0:59:47.53,EN,,0,0,0,,Now, however, the exciting part. Dialogue: 0,0:59:47.73,0:59:48.96,EN,,0,0,0,,CDR, of course, is the same. Dialogue: 0,0:59:49.39,0:59:50.35,EN,,0,0,0,,The exciting part, Dialogue: 0,0:59:51.23,0:59:52.52,EN,,0,0,0,,set CAR and set CDR. Dialogue: 0,0:59:53.45,0:59:55.52,EN,,0,0,0,,Well, they're nothing very complicated anymore. Dialogue: 0,0:59:55.80,1:00:00.64,EN,,0,0,0,,Set CAR of a CONS X to a new value Y Dialogue: 0,1:00:01.63,1:00:03.85,EN,,0,0,0,,is nothing more than applying that CONS, Dialogue: 0,1:00:04.11,1:00:06.76,EN,,0,0,0,,which is the procedure of four--the procedure of one argument Dialogue: 0,1:00:07.69,1:00:09.80,EN,,0,0,0,,which applies its argument to four things, Dialogue: 0,1:00:11.24,1:00:15.85,EN,,0,0,0,,to a procedure which is of four arguments-- Dialogue: 0,1:00:16.00,1:00:18.08,EN,,0,0,0,,the value of X, the value of Y, Dialogue: 0,1:00:18.32,1:00:20.54,EN,,0,0,0,,permission to set X, the permission to set Y-- Dialogue: 0,1:00:21.32,1:00:26.09,EN,,0,0,0,,and using it--using that permission to set X to the new value. Dialogue: 0,1:00:31.65,1:00:33.54,EN,,0,0,0,,And similarly, set-cdr is the same thing. Dialogue: 0,1:00:36.25,1:00:39.44,EN,,0,0,0,,So what you've just seen is that I didn't introduce any new primitives at all. Dialogue: 0,1:00:40.11,1:00:44.36,EN,,0,0,0,,I mean, Whether or not I want to implement it this way is a matter of engineering. Dialogue: 0,1:00:45.34,1:00:47.39,EN,,0,0,0,,And the answer is of course I don't implement it this way Dialogue: 0,1:00:48.09,1:00:49.63,EN,,0,0,0,,for reasons that have to do with engineering. Dialogue: 0,1:00:51.68,1:00:53.40,EN,,0,0,0,,However in principle, logically, Dialogue: 0,1:00:54.28,1:00:56.43,EN,,0,0,0,,I introduced one assignment operator, Dialogue: 0,1:00:56.96,1:00:58.76,EN,,0,0,0,,I've assigned--I've introduced them all. Dialogue: 0,1:01:05.42,1:01:06.67,EN,,0,0,0,,Are there any questions? Dialogue: 0,1:01:09.20,1:01:10.89,EN,,0,0,0,,Yes, David. Dialogue: 0,1:01:12.04,1:01:15.64,EN,,0,0,0,,AUDIENCE: I can follow you up until you get--I can follow all of that. Dialogue: 0,1:01:15.64,1:01:17.61,EN,,0,0,0,,But when we bring in the permissions, Dialogue: 0,1:01:18.14,1:01:21.64,EN,,0,0,0,,defining CONS in terms of the lambda N, Dialogue: 0,1:01:21.80,1:01:24.21,EN,,0,0,0,,I don't follow where N gets passed. Dialogue: 0,1:01:24.21,1:01:25.69,EN,,0,0,0,,PROFESSOR: Oh, I'm sorry. I'll show you. Dialogue: 0,1:01:26.34,1:01:27.05,EN,,0,0,0,,Let's follow it. Dialogue: 0,1:01:27.36,1:01:29.07,EN,,0,0,0,,Of course, we could do it on the blackboard. Dialogue: 0,1:01:29.18,1:01:30.17,EN,,0,0,0,,It's not so hard. Dialogue: 0,1:01:30.17,1:01:31.47,EN,,0,0,0,,But it's also easy here. Dialogue: 0,1:01:32.45,1:01:35.79,EN,,0,0,0,,Supposing I wish to set-cdr of X to Y. Dialogue: 0,1:01:37.79,1:01:39.66,EN,,0,0,0,,See that right there. set cdr x to y Dialogue: 0,1:01:40.36,1:01:41.92,EN,,0,0,0,,X is presumably a CONS, Dialogue: 0,1:01:43.31,1:01:45.24,EN,,0,0,0,,a thing resulting from evaluating CONS. Dialogue: 0,1:01:45.88,1:01:46.35,EN,,0,0,0,,right? Dialogue: 0,1:01:46.89,1:01:49.96,EN,,0,0,0,,Therefore X comes from a place over here, Dialogue: 0,1:01:52.57,1:01:56.49,EN,,0,0,0,,that that X is of the result of evaluating this lambda expression. Dialogue: 0,1:01:58.11,1:01:58.49,EN,,0,0,0,,Right? Dialogue: 0,1:01:59.38,1:02:01.63,EN,,0,0,0,,That when I evaluated that lambda expression, Dialogue: 0,1:02:04.01,1:02:08.76,EN,,0,0,0,,I evaluated it in an environment where the arguments to CONS were defined. Dialogue: 0,1:02:11.75,1:02:15.18,EN,,0,0,0,,That means that as free variables in this lambda expression, Dialogue: 0,1:02:16.25,1:02:18.68,EN,,0,0,0,,there is the--there are in the frame, Dialogue: 0,1:02:18.72,1:02:22.44,EN,,0,0,0,,which is the parent frame of this lambda expression, Dialogue: 0,1:02:23.23,1:02:25.82,EN,,0,0,0,,the procedure resulting from this lambda expression, Dialogue: 0,1:02:26.65,1:02:28.51,EN,,0,0,0,,X and Y have places. Dialogue: 0,1:02:29.25,1:02:30.83,EN,,0,0,0,,And it's possible to set them. Dialogue: 0,1:02:31.91,1:02:36.08,EN,,0,0,0,,I set them to an N, which is the argument of the permission. Dialogue: 0,1:02:37.26,1:02:39.31,EN,,0,0,0,,The permission is a procedure Dialogue: 0,1:02:41.40,1:02:43.18,EN,,0,0,0,,which is passed to M, Dialogue: 0,1:02:43.29,1:02:46.51,EN,,0,0,0,,which is the argument that the CONS object gets passed. Dialogue: 0,1:02:47.94,1:02:50.91,EN,,0,0,0,,Now, let's go back here in the set-cdr Dialogue: 0,1:02:52.11,1:02:55.42,EN,,0,0,0,,The CONS object, which is the first argument of set-cdr Dialogue: 0,1:02:56.12,1:02:57.48,EN,,0,0,0,,gets passed an argument. Dialogue: 0,1:02:59.77,1:03:02.22,EN,,0,0,0,,That--there's a procedure of four things, indeed, Dialogue: 0,1:03:02.32,1:03:04.65,EN,,0,0,0,,because that's the same thing as this M over here, Dialogue: 0,1:03:04.99,1:03:06.56,EN,,0,0,0,,which is applied to four objects. Dialogue: 0,1:03:07.92,1:03:13.34,EN,,0,0,0,,The object over here, SD, is, in fact, this permission. Dialogue: 0,1:03:15.47,1:03:19.93,EN,,0,0,0,,When I use SD, I apply it to Y, right there. Dialogue: 0,1:03:22.91,1:03:24.04,EN,,0,0,0,,So that comes from this. Dialogue: 0,1:03:25.37,1:03:26.92,EN,,0,0,0,,AUDIENCE: So what do you-- Dialogue: 0,1:03:27.00,1:03:32.19,EN,,0,0,0,,PROFESSOR: So to finish that, the N that was here is the Y which is here. Dialogue: 0,1:03:34.04,1:03:34.52,EN,,0,0,0,,How's that? Dialogue: 0,1:03:34.81,1:03:35.75,EN,,0,0,0,,AUDIENCE: Right, OK. Dialogue: 0,1:03:35.75,1:03:37.29,EN,,0,0,0,,Now, when you do a set-cdr, Dialogue: 0,1:03:39.07,1:03:41.97,EN,,0,0,0,,X is the value the CDR is going to become. Dialogue: 0,1:03:41.97,1:03:44.03,EN,,0,0,0,,PROFESSOR: The X over here. Dialogue: 0,1:03:44.96,1:03:46.20,EN,,0,0,0,,I'm sorry, that's not true. Dialogue: 0,1:03:46.20,1:03:48.33,EN,,0,0,0,,The X is--set-cdr has two arguments-- Dialogue: 0,1:03:48.91,1:03:50.36,EN,,0,0,0,,The CONS I'm changing Dialogue: 0,1:03:51.34,1:03:53.93,EN,,0,0,0,,and the value I'm changing it to. Dialogue: 0,1:03:56.15,1:03:58.32,EN,,0,0,0,,So you have them backwards, that's all. Dialogue: 0,1:04:02.17,1:04:03.16,EN,,0,0,0,,Are there any other questions? Dialogue: 0,1:04:07.88,1:04:08.64,EN,,0,0,0,,Well, thank you. Dialogue: 0,1:04:08.64,1:04:09.52,EN,,0,0,0,,It's time for lunch. Dialogue: 0,1:04:10.44,1:04:28.73,Declare,,0,0,0,,{\fad(500,500)}http://ocw.mit.edu Dialogue: 0,1:04:10.44,1:04:28.73,Declare,,0,0,0,,{\an2\fad(500,500)}https://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec6a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: EN Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Audio File: ../../../../Movies/lec6a_480_muxed.mp4 Video File: ../../../../Movies/lec6a_480_muxed.mp4 Video AR Mode: 4 Video AR Value: 1.333333 Video Zoom Percent: 2.000000 Video Position: 556 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:18.55,0:00:21.84,EN,,0,0,0,,PROFESSOR: Well, last time Gerry really let the cat out of the bag. Dialogue: 0,0:00:22.49,0:00:24.60,EN,,0,0,0,,He introduced the idea of assignment. Dialogue: 0,0:00:26.35,0:00:33.61,EN,,0,0,0,,Assignment and state. Dialogue: 0,0:00:37.48,0:00:40.03,EN,,0,0,0,,And as we started to see, the implications Dialogue: 0,0:00:40.72,0:00:43.16,EN,,0,0,0,,of introducing assignment and state into the language Dialogue: 0,0:00:43.16,0:00:44.41,EN,,0,0,0,,are absolutely frightening. Dialogue: 0,0:00:45.08,0:00:48.62,EN,,0,0,0,,First of all, the substitution model of evaluation breaks down. Dialogue: 0,0:00:49.13,0:00:52.48,EN,,0,0,0,,And we have to use this much more complicated environment model Dialogue: 0,0:00:52.48,0:00:54.27,EN,,0,0,0,,this very mechanistic thing with diagrams, Dialogue: 0,0:00:54.28,0:00:57.24,EN,,0,0,0,,even to say what statements in the programming language mean. Dialogue: 0,0:00:58.46,0:01:00.12,EN,,0,0,0,,And that's not a mere technical point. Dialogue: 0,0:01:00.26,0:01:03.28,EN,,0,0,0,,See, it's not that we had this particular substitution model and, Dialogue: 0,0:01:03.60,0:01:05.68,EN,,0,0,0,,well, it doesn't quite work, so we have to do something else. Dialogue: 0,0:01:05.71,0:01:09.79,EN,,0,0,0,,It's that nothing like the substitution model can work. Dialogue: 0,0:01:10.73,0:01:13.32,EN,,0,0,0,,Because suddenly, a variable Dialogue: 0,0:01:14.12,0:01:16.92,EN,,0,0,0,,is not just something that stands for a value. Dialogue: 0,0:01:17.95,0:01:21.76,EN,,0,0,0,,A variable now has to somehow specify a place Dialogue: 0,0:01:22.40,0:01:23.34,EN,,0,0,0,,that holds a value. Dialogue: 0,0:01:23.63,0:01:26.14,EN,,0,0,0,,And the value that's in that place can change. Dialogue: 0,0:01:30.28,0:01:34.09,EN,,0,0,0,,Or for instance, an expression like f of x Dialogue: 0,0:01:37.36,0:01:39.64,EN,,0,0,0,,might have a side effect in it. Dialogue: 0,0:01:40.41,0:01:42.60,EN,,0,0,0,,So if we say f of x and it has some value, Dialogue: 0,0:01:43.18,0:01:45.34,EN,,0,0,0,,and then later we say f of x again, Dialogue: 0,0:01:47.24,0:01:48.43,EN,,0,0,0,,we might get a different value Dialogue: 0,0:01:48.86,0:01:49.74,EN,,0,0,0,,depending on the order. Dialogue: 0,0:01:49.76,0:01:52.14,EN,,0,0,0,,So suddenly, we have to think not only about values Dialogue: 0,0:01:52.52,0:01:53.60,EN,,0,0,0,,but about time. Dialogue: 0,0:01:57.97,0:01:59.98,EN,,0,0,0,,And then things like pairs Dialogue: 0,0:02:00.65,0:02:02.52,EN,,0,0,0,,are no longer just their CARs and their CDRs. Dialogue: 0,0:02:02.52,0:02:05.61,EN,,0,0,0,,A pair now is not quite its CAR and its CDR. Dialogue: 0,0:02:05.80,0:02:07.05,EN,,0,0,0,,It's rather its identity. Dialogue: 0,0:02:08.44,0:02:11.65,EN,,0,0,0,,So a pair has identity. Dialogue: 0,0:02:11.65,0:02:12.59,EN,,0,0,0,,It's an object. Dialogue: 0,0:02:21.33,0:02:25.15,EN,,0,0,0,,And two pairs that have the same CAR and CDR Dialogue: 0,0:02:25.40,0:02:27.05,EN,,0,0,0,,well, might be the same or different, Dialogue: 0,0:02:27.87,0:02:30.51,EN,,0,0,0,,because suddenly we have to worry about sharing. Dialogue: 0,0:02:34.96,0:02:39.45,EN,,0,0,0,,So all of these things enter as soon as we introduce assignment. Dialogue: 0,0:02:40.48,0:02:43.98,EN,,0,0,0,,See, this is a really far cry from where we started with substitution. Dialogue: 0,0:02:45.04,0:02:48.91,EN,,0,0,0,,It's a technically harder way of looking at things Dialogue: 0,0:02:48.94,0:02:53.45,EN,,0,0,0,,because we have to think more mechanistically about our programming language. Dialogue: 0,0:02:53.47,0:02:55.34,EN,,0,0,0,,We can't just think about it as mathematics. Dialogue: 0,0:02:55.71,0:02:58.60,EN,,0,0,0,,It's philosophically harder, Dialogue: 0,0:02:59.15,0:03:00.65,EN,,0,0,0,,because suddenly there are all these funny issues Dialogue: 0,0:03:00.67,0:03:02.38,EN,,0,0,0,,what does it mean that something changes Dialogue: 0,0:03:02.38,0:03:03.77,EN,,0,0,0,,or that two things are the same. Dialogue: 0,0:03:03.84,0:03:06.83,EN,,0,0,0,,And also, it's programming harder, because Dialogue: 0,0:03:07.47,0:03:08.54,EN,,0,0,0,,as Gerry showed last time, Dialogue: 0,0:03:08.56,0:03:12.20,EN,,0,0,0,,there are all these bugs having to do with bad sequencing and aliasing Dialogue: 0,0:03:12.22,0:03:16.19,EN,,0,0,0,,that just don't exist in a language where we don't worry about objects. Dialogue: 0,0:03:18.21,0:03:21.20,EN,,0,0,0,,Well, how'd we get into this mess? Dialogue: 0,0:03:24.01,0:03:27.20,EN,,0,0,0,,Remember what we did, the reason we got into this is Dialogue: 0,0:03:27.40,0:03:31.47,EN,,0,0,0,,because we were looking to build modular systems. Dialogue: 0,0:03:35.15,0:03:37.69,EN,,0,0,0,,We wanted to build systems that Dialogue: 0,0:03:38.09,0:03:41.04,EN,,0,0,0,,that fall apart into chunks that seem natural. Dialogue: 0,0:03:42.76,0:03:43.82,EN,,0,0,0,,So for instance, Dialogue: 0,0:03:44.06,0:03:46.11,EN,,0,0,0,,we want to take a random number generator Dialogue: 0,0:03:46.22,0:03:49.40,EN,,0,0,0,,and package up the state of that random number generator inside of it Dialogue: 0,0:03:50.25,0:03:53.71,EN,,0,0,0,,so that we can separate the idea of picking random numbers Dialogue: 0,0:03:54.65,0:03:57.79,EN,,0,0,0,,from the general Monte Carlo strategy of estimating something Dialogue: 0,0:03:58.65,0:04:01.52,EN,,0,0,0,,and separate that from the particular way that you Dialogue: 0,0:04:01.90,0:04:05.74,EN,,0,0,0,,work with random numbers in that formula developed by Cesaro for pi. Dialogue: 0,0:04:06.80,0:04:07.92,EN,,0,0,0,,And similarly, Dialogue: 0,0:04:09.61,0:04:11.74,EN,,0,0,0,,when we go off and construct some models of things, Dialogue: 0,0:04:12.35,0:04:16.01,EN,,0,0,0,,Ah, if we go off and model a system that we see in the real world, Dialogue: 0,0:04:17.31,0:04:19.42,EN,,0,0,0,,we'd like our program to break into natural pieces, Dialogue: 0,0:04:19.44,0:04:20.52,EN,,0,0,0,,pieces that mirror Dialogue: 0,0:04:21.05,0:04:23.16,EN,,0,0,0,,the parts of the system that we see in the real world. Dialogue: 0,0:04:24.90,0:04:27.56,EN,,0,0,0,,So for example, if we look at a digital circuit, Dialogue: 0,0:04:28.36,0:04:29.18,EN,,0,0,0,,we say, gee, Dialogue: 0,0:04:30.44,0:04:31.44,EN,,0,0,0,,there's a circuit Dialogue: 0,0:04:32.08,0:04:35.16,EN,,0,0,0,,and it has a piece and it has another piece. Dialogue: 0,0:04:40.10,0:04:43.58,EN,,0,0,0,,And these different pieces sort of have identity. Dialogue: 0,0:04:43.58,0:04:44.59,EN,,0,0,0,,They have state. Dialogue: 0,0:04:45.55,0:04:47.13,EN,,0,0,0,,And the state sits on these wires. Dialogue: 0,0:04:48.58,0:04:50.22,EN,,0,0,0,,And we think of this piece as an object Dialogue: 0,0:04:50.49,0:04:51.93,EN,,0,0,0,,that's different from that as an object. Dialogue: 0,0:04:52.54,0:04:53.85,EN,,0,0,0,,And when we watch the system change, Dialogue: 0,0:04:53.87,0:04:55.40,EN,,0,0,0,,we think about a signal coming in here Dialogue: 0,0:04:55.63,0:04:58.41,EN,,0,0,0,,changing a state that might be here and going here Dialogue: 0,0:04:58.67,0:05:00.75,EN,,0,0,0,,and interacting with a state that might be stored there, Dialogue: 0,0:05:01.24,0:05:02.17,EN,,0,0,0,,and so on and so on. Dialogue: 0,0:05:06.86,0:05:11.24,EN,,0,0,0,,So what we'd like is we'd like to build in the computer Dialogue: 0,0:05:12.76,0:05:14.36,EN,,0,0,0,,systems that fall into pieces Dialogue: 0,0:05:14.68,0:05:17.87,EN,,0,0,0,,that fall into pieces that mirror our view of reality, Dialogue: 0,0:05:17.88,0:05:19.87,EN,,0,0,0,,of the way that the actual systems we're modeling Dialogue: 0,0:05:19.88,0:05:20.91,EN,,0,0,0,,seem to fall into pieces. Dialogue: 0,0:05:23.20,0:05:23.48,EN,,0,0,0,,Well, Dialogue: 0,0:05:25.74,0:05:28.99,EN,,0,0,0,,maybe the reason that building systems like this Dialogue: 0,0:05:28.99,0:05:31.50,EN,,0,0,0,,seems to introduce such technical complications Dialogue: 0,0:05:31.52,0:05:32.75,EN,,0,0,0,,has nothing to do with computers. Dialogue: 0,0:05:33.61,0:05:35.60,EN,,0,0,0,,See, maybe the real reason Dialogue: 0,0:05:36.70,0:05:38.65,EN,,0,0,0,,that we pay such a price to write programs Dialogue: 0,0:05:38.67,0:05:40.94,EN,,0,0,0,,that mirror our view of reality Dialogue: 0,0:05:41.52,0:05:43.13,EN,,0,0,0,,is that we have the wrong view of reality. Dialogue: 0,0:05:44.55,0:05:46.75,EN,,0,0,0,,See, maybe time is just an illusion, Dialogue: 0,0:05:47.26,0:05:48.60,EN,,0,0,0,,and nothing ever changes. Dialogue: 0,0:05:50.15,0:05:51.71,EN,,0,0,0,,See, for example, if I take this chalk, Dialogue: 0,0:05:52.44,0:05:53.77,EN,,0,0,0,,and we say, gee, this is an object Dialogue: 0,0:05:54.01,0:05:54.99,EN,,0,0,0,,and it has a state. Dialogue: 0,0:05:55.82,0:05:59.29,EN,,0,0,0,,At each moment it has a position and a velocity. Dialogue: 0,0:05:59.71,0:06:01.48,EN,,0,0,0,,And if we do something, that state can change. Dialogue: 0,0:06:04.34,0:06:07.37,EN,,0,0,0,,But if you studied any relativity, for instance, Dialogue: 0,0:06:07.74,0:06:09.71,EN,,0,0,0,,you know that you don't think of the path of that chalk Dialogue: 0,0:06:09.72,0:06:11.34,EN,,0,0,0,,as something that goes on instant by instant. Dialogue: 0,0:06:11.34,0:06:14.38,EN,,0,0,0,,It's more insightful to think of that whole chalk's existence Dialogue: 0,0:06:14.41,0:06:15.64,EN,,0,0,0,,as a path in space-time. Dialogue: 0,0:06:16.02,0:06:17.37,EN,,0,0,0,,that's all splayed out. Dialogue: 0,0:06:17.87,0:06:19.84,EN,,0,0,0,,There aren't individual positions and velocities. Dialogue: 0,0:06:19.84,0:06:23.80,EN,,0,0,0,,There's just its unchanging existence in space-time. Dialogue: 0,0:06:24.64,0:06:26.51,EN,,0,0,0,,Similarly, if we look at this electrical system, Dialogue: 0,0:06:27.69,0:06:30.43,EN,,0,0,0,,if we imagine this electrical system is implementing Dialogue: 0,0:06:30.59,0:06:33.96,EN,,0,0,0,,sort of signal processing system, Dialogue: 0,0:06:34.36,0:06:36.68,EN,,0,0,0,,the signal processing engineer who put that thing together Dialogue: 0,0:06:36.75,0:06:38.60,EN,,0,0,0,,doesn't think of it as, well, Dialogue: 0,0:06:38.96,0:06:41.40,EN,,0,0,0,,at each instance there's a voltage coming in. Dialogue: 0,0:06:41.49,0:06:43.16,EN,,0,0,0,,And that translates into something. Dialogue: 0,0:06:43.34,0:06:45.52,EN,,0,0,0,,And that affects the state over here, Dialogue: 0,0:06:45.53,0:06:46.81,EN,,0,0,0,,which changes the state over here. Dialogue: 0,0:06:46.81,0:06:50.11,EN,,0,0,0,,Nobody putting together a signal processing system thinks about it like that. Dialogue: 0,0:06:50.42,0:06:51.84,EN,,0,0,0,,Instead, you say there's this signal Dialogue: 0,0:06:54.04,0:06:58.06,EN,,0,0,0,,that's splayed out over time. Dialogue: 0,0:06:58.06,0:06:59.48,EN,,0,0,0,,And if this is acting as a filter, Dialogue: 0,0:07:00.20,0:07:04.04,EN,,0,0,0,,this whole thing transforms this whole thing Dialogue: 0,0:07:04.28,0:07:07.04,EN,,0,0,0,,for some sort of other output. Dialogue: 0,0:07:09.57,0:07:11.28,EN,,0,0,0,,You don't think of it as what's happening Dialogue: 0,0:07:11.28,0:07:13.29,EN,,0,0,0,,instant by instant as the state of these things. Dialogue: 0,0:07:14.16,0:07:17.32,EN,,0,0,0,,And somehow you think of this box as a whole thing, Dialogue: 0,0:07:17.32,0:07:20.16,EN,,0,0,0,,not as little pieces sending messages of state Dialogue: 0,0:07:20.40,0:07:21.96,EN,,0,0,0,,to each other at particular instants. Dialogue: 0,0:07:28.25,0:07:29.36,EN,,0,0,0,,Well, today we're going to look at Dialogue: 0,0:07:29.39,0:07:31.13,EN,,0,0,0,,another way to decompose systems Dialogue: 0,0:07:31.36,0:07:35.45,EN,,0,0,0,,that's more like the signal processing engineer's view of the world Dialogue: 0,0:07:35.69,0:07:38.96,EN,,0,0,0,,than it is like thinking about objects that communicate sending messages. Dialogue: 0,0:07:41.13,0:07:43.74,EN,,0,0,0,,That's called stream processing. Dialogue: 0,0:07:54.57,0:07:58.96,EN,,0,0,0,,And we're going to start by showing Dialogue: 0,0:08:00.59,0:08:04.16,EN,,0,0,0,,by showing how we can make our programs more uniform Dialogue: 0,0:08:05.15,0:08:06.54,EN,,0,0,0,,and see a lot more commonality Dialogue: 0,0:08:06.65,0:08:09.88,EN,,0,0,0,,if we throw out of these programs Dialogue: 0,0:08:10.81,0:08:12.30,EN,,0,0,0,,what you might say is a Dialogue: 0,0:08:12.35,0:08:15.12,EN,,0,0,0,,inordinate concern with worrying about time. Dialogue: 0,0:08:16.89,0:08:20.22,EN,,0,0,0,,Let me start by comparing two procedures. Dialogue: 0,0:08:23.55,0:08:25.69,EN,,0,0,0,,The first one does this. Dialogue: 0,0:08:25.69,0:08:27.77,EN,,0,0,0,,We imagine that there's a tree. Dialogue: 0,0:08:30.40,0:08:32.14,EN,,0,0,0,,Say there's a tree of integers. Dialogue: 0,0:08:33.28,0:08:34.42,EN,,0,0,0,,It's a binary tree. Dialogue: 0,0:08:36.12,0:08:36.97,EN,,0,0,0,,Say 1. Dialogue: 0,0:08:39.10,0:08:40.23,EN,,0,0,0,,So it looks like this. Dialogue: 0,0:08:40.23,0:08:42.92,EN,,0,0,0,,And there's integers in each of the nodes. Dialogue: 0,0:08:45.18,0:08:47.80,EN,,0,0,0,,And what we would like to compute is Dialogue: 0,0:08:48.67,0:08:51.56,EN,,0,0,0,,for each odd number sitting here, Dialogue: 0,0:08:52.30,0:08:55.10,EN,,0,0,0,,we'd like to find the square and then sum up all those squares. Dialogue: 0,0:08:57.05,0:08:59.48,EN,,0,0,0,,Well, that should be a familiar kind of thing. Dialogue: 0,0:08:59.48,0:09:01.95,EN,,0,0,0,,There's a recursive strategy for doing it. Dialogue: 0,0:09:02.93,0:09:04.35,EN,,0,0,0,,We look at each leaf, and either Dialogue: 0,0:09:04.56,0:09:06.68,EN,,0,0,0,,it's going to contribute the square of the number if it's odd Dialogue: 0,0:09:06.70,0:09:07.77,EN,,0,0,0,,or 0 if it's even. Dialogue: 0,0:09:08.68,0:09:12.11,EN,,0,0,0,,And then recursively, we can say at each tree Dialogue: 0,0:09:12.65,0:09:13.84,EN,,0,0,0,,the sum of all of them is Dialogue: 0,0:09:13.92,0:09:15.93,EN,,0,0,0,,the sum coming from the right branch and the left branch, Dialogue: 0,0:09:16.25,0:09:17.64,EN,,0,0,0,,and recursively down through the nodes. Dialogue: 0,0:09:17.64,0:09:18.70,EN,,0,0,0,,And that's a familiar way of Dialogue: 0,0:09:19.26,0:09:20.36,EN,,0,0,0,,thinking about programming. Dialogue: 0,0:09:20.36,0:09:22.59,EN,,0,0,0,,Let's actually look at that on the slide. Dialogue: 0,0:09:23.82,0:09:26.75,EN,,0,0,0,,We say to sum the odd squares in a tree, Dialogue: 0,0:09:27.37,0:09:29.36,EN,,0,0,0,,there's a test. Either it's a leaf node, Dialogue: 0,0:09:29.82,0:09:31.95,EN,,0,0,0,,and we're going to check to see if it's an integer, Dialogue: 0,0:09:32.88,0:09:36.38,EN,,0,0,0,,and then either it's odd, in which we take the square, or else it's 0. Dialogue: 0,0:09:37.16,0:09:38.99,EN,,0,0,0,,And then the sum of the whole thing Dialogue: 0,0:09:39.21,0:09:42.12,EN,,0,0,0,,is the sum coming from the left branch and the right branch. Dialogue: 0,0:09:46.34,0:09:50.56,EN,,0,0,0,,OK, well, let me contrast that with a second problem. Dialogue: 0,0:09:51.56,0:09:53.68,EN,,0,0,0,,Suppose I give you an integer n, Dialogue: 0,0:09:54.73,0:09:57.88,EN,,0,0,0,,and then some function to compute of the first of each integer Dialogue: 0,0:09:57.93,0:09:58.83,EN,,0,0,0,,1 through n. Dialogue: 0,0:09:59.10,0:10:01.08,EN,,0,0,0,,And then I want to collect together in a list Dialogue: 0,0:10:01.28,0:10:04.65,EN,,0,0,0,,all those function values that satisfy some property. Dialogue: 0,0:10:05.60,0:10:06.88,EN,,0,0,0,,That's a general kind of thing. Dialogue: 0,0:10:06.88,0:10:07.98,EN,,0,0,0,,Let's say to be specific, Dialogue: 0,0:10:08.62,0:10:10.48,EN,,0,0,0,,let's imagine that for each integer, k, Dialogue: 0,0:10:10.65,0:10:12.51,EN,,0,0,0,,we're going to compute the k Fibonacci number. Dialogue: 0,0:10:14.21,0:10:16.27,EN,,0,0,0,,And then we'll see which of those are odd Dialogue: 0,0:10:16.83,0:10:18.40,EN,,0,0,0,,and assemble those into a list. Dialogue: 0,0:10:19.05,0:10:20.71,EN,,0,0,0,,So here's a procedure that does that. Dialogue: 0,0:10:23.73,0:10:26.24,EN,,0,0,0,,Find the odd Fibonacci numbers among the first n. Dialogue: 0,0:10:26.24,0:10:28.91,EN,,0,0,0,,And here is a standard loop the way we've been writing it. Dialogue: 0,0:10:28.91,0:10:29.82,EN,,0,0,0,,This is a recursion. Dialogue: 0,0:10:30.80,0:10:31.79,EN,,0,0,0,,It's a loop on k, Dialogue: 0,0:10:32.03,0:10:34.35,EN,,0,0,0,,and says if k is bigger than n, it's the empty list. Dialogue: 0,0:10:35.13,0:10:37.36,EN,,0,0,0,,Otherwise we compute the k-th Fibonacci number, Dialogue: 0,0:10:37.44,0:10:38.06,EN,,0,0,0,,call that f. Dialogue: 0,0:10:40.37,0:10:42.84,EN,,0,0,0,,If it's odd, we CONS it on Dialogue: 0,0:10:43.76,0:10:46.01,EN,,0,0,0,,to the list starting with the next one. Dialogue: 0,0:10:47.69,0:10:50.12,EN,,0,0,0,,And otherwise, we just take the next one. Dialogue: 0,0:10:50.73,0:10:53.00,EN,,0,0,0,,And this is the standard way we've been writing iterative loops. Dialogue: 0,0:10:53.00,0:10:55.56,EN,,0,0,0,,And we start off calling that loop with 1. Dialogue: 0,0:10:57.58,0:11:00.06,EN,,0,0,0,,OK, so there are two procedures. Dialogue: 0,0:11:01.60,0:11:02.90,EN,,0,0,0,,Those procedures look very different. Dialogue: 0,0:11:02.90,0:11:04.20,EN,,0,0,0,,They have very different structures. Dialogue: 0,0:11:04.25,0:11:06.89,EN,,0,0,0,,Yet from a certain point of view, Dialogue: 0,0:11:06.92,0:11:09.61,EN,,0,0,0,,those procedures are really doing very much the same thing. Dialogue: 0,0:11:11.33,0:11:14.67,EN,,0,0,0,,So if I was talking like a signal processing engineer, Dialogue: 0,0:11:14.70,0:11:16.81,EN,,0,0,0,,what I might say Dialogue: 0,0:11:18.24,0:11:26.76,EN,,0,0,0,,the first procedure enumerates the leaves of a tree. Dialogue: 0,0:11:31.16,0:11:34.56,EN,,0,0,0,,And then we can think of a signal coming out of that, which is all the leaves. Dialogue: 0,0:11:35.33,0:11:43.39,EN,,0,0,0,,We'll filter them to see which ones are odd, Dialogue: 0,0:11:43.58,0:11:44.94,EN,,0,0,0,,put them through some kind of filter. Dialogue: 0,0:11:45.19,0:11:47.79,EN,,0,0,0,,We'll then put them through a kind of transducer. Dialogue: 0,0:11:49.20,0:11:51.69,EN,,0,0,0,,And for each one of those things, we'll take the square. Dialogue: 0,0:11:54.44,0:11:57.44,EN,,0,0,0,,And then we'll accumulate all of those. Dialogue: 0,0:11:58.29,0:12:00.04,EN,,0,0,0,,We'll accumulate them by sticking them together Dialogue: 0,0:12:00.35,0:12:03.37,EN,,0,0,0,,with addition starting from 0. Dialogue: 0,0:12:07.14,0:12:08.21,EN,,0,0,0,,That's the first program. Dialogue: 0,0:12:08.21,0:12:09.18,EN,,0,0,0,,The second program, Dialogue: 0,0:12:09.24,0:12:11.21,EN,,0,0,0,,I can describe in a very, very similar way. Dialogue: 0,0:12:11.78,0:12:13.42,EN,,0,0,0,,I'll say, we'll enumerate Dialogue: 0,0:12:15.80,0:12:19.10,EN,,0,0,0,,the numbers on this interval, for the interval 1 through n. Dialogue: 0,0:12:22.50,0:12:24.40,EN,,0,0,0,,We'll, for each one, Dialogue: 0,0:12:25.45,0:12:26.92,EN,,0,0,0,,compute the Fibonacci number, Dialogue: 0,0:12:27.79,0:12:29.27,EN,,0,0,0,,put them through a transducer. Dialogue: 0,0:12:29.27,0:12:30.78,EN,,0,0,0,,We'll then take the result of that, Dialogue: 0,0:12:31.31,0:12:34.20,EN,,0,0,0,,and we'll filter it for oddness. Dialogue: 0,0:12:36.27,0:12:39.24,EN,,0,0,0,,And then we'll take those and put them into an accumulator. Dialogue: 0,0:12:39.35,0:12:40.56,EN,,0,0,0,,This time we'll build up a list, Dialogue: 0,0:12:40.78,0:12:42.17,EN,,0,0,0,,so we'll accumulate with CONS Dialogue: 0,0:12:42.59,0:12:43.77,EN,,0,0,0,,starting from the empty list. Dialogue: 0,0:12:47.11,0:12:49.80,EN,,0,0,0,,So this way of looking at the program Dialogue: 0,0:12:49.85,0:12:51.84,EN,,0,0,0,,makes the two seem very, very similar. Dialogue: 0,0:12:51.90,0:12:52.84,EN,,0,0,0,,The problem is Dialogue: 0,0:12:53.20,0:12:56.49,EN,,0,0,0,,that that commonality is completely obscured Dialogue: 0,0:12:56.64,0:12:58.05,EN,,0,0,0,,when we look at the procedures we wrote. Dialogue: 0,0:12:58.05,0:13:01.44,EN,,0,0,0,,Let's go back and look at some odd squares again, Dialogue: 0,0:13:02.22,0:13:04.64,EN,,0,0,0,,and say things like, where's the enumerator? Dialogue: 0,0:13:06.35,0:13:08.14,EN,,0,0,0,,Where's the enumerator in this program? Dialogue: 0,0:13:08.14,0:13:10.52,EN,,0,0,0,,Well, it's not in one place. Dialogue: 0,0:13:11.02,0:13:15.47,EN,,0,0,0,,It's a little bit in this leaf-node test, Dialogue: 0,0:13:16.43,0:13:17.16,EN,,0,0,0,,which is going to stop. Dialogue: 0,0:13:17.16,0:13:20.06,EN,,0,0,0,,It's a little bit in the recursive structure of the thing itself. Dialogue: 0,0:13:23.15,0:13:24.12,EN,,0,0,0,,Where's the accumulator? Dialogue: 0,0:13:24.12,0:13:25.68,EN,,0,0,0,,The accumulator isn't in one place either. Dialogue: 0,0:13:25.68,0:13:30.73,EN,,0,0,0,,It's partly in this 0 and partly in this plus. Dialogue: 0,0:13:32.00,0:13:34.51,EN,,0,0,0,,Right? It's not there as a thing that we can look at. Dialogue: 0,0:13:34.51,0:13:39.05,EN,,0,0,0,,Similarly, if we look at odd Fibs, Dialogue: 0,0:13:39.05,0:13:42.80,EN,,0,0,0,,that's also, in some sense, an enumerator and an accumulator, Dialogue: 0,0:13:42.80,0:13:44.01,EN,,0,0,0,,but it looks very different. Dialogue: 0,0:13:44.62,0:13:50.09,EN,,0,0,0,,Because partly, the enumerator is here in this greater than sign in the test. Dialogue: 0,0:13:50.38,0:13:52.84,EN,,0,0,0,,And partly it's in this whole recursive structure in the loop, Dialogue: 0,0:13:53.18,0:13:54.24,EN,,0,0,0,,and the way that we call it. Dialogue: 0,0:13:55.68,0:13:56.32,EN,,0,0,0,,And then similarly, Dialogue: 0,0:13:56.52,0:13:58.76,EN,,0,0,0,,that's also mixed up in there with the accumulator, Dialogue: 0,0:13:58.91,0:14:00.12,EN,,0,0,0,,which is partly over there Dialogue: 0,0:14:00.41,0:14:01.40,EN,,0,0,0,,and partly over there. Dialogue: 0,0:14:03.60,0:14:06.08,EN,,0,0,0,,So these very, very natural pieces, Dialogue: 0,0:14:08.73,0:14:12.65,EN,,0,0,0,,these very natural boxes here don't appear in our programs. Dialogue: 0,0:14:13.26,0:14:14.36,EN,,0,0,0,,Because they're kind of mixed up. Dialogue: 0,0:14:14.36,0:14:16.29,EN,,0,0,0,,The programs don't chop things up in the right way. Dialogue: 0,0:14:19.45,0:14:22.17,EN,,0,0,0,,Going back to this fundamental principle of computer science Dialogue: 0,0:14:22.19,0:14:23.63,EN,,0,0,0,,that in order to control something, Dialogue: 0,0:14:23.63,0:14:24.96,EN,,0,0,0,,you need the name of it, Dialogue: 0,0:14:25.80,0:14:28.44,EN,,0,0,0,,we don't really have control over thinking about things this way Dialogue: 0,0:14:28.67,0:14:31.06,EN,,0,0,0,,because we don't have our hands in them explicitly. Dialogue: 0,0:14:31.06,0:14:33.80,EN,,0,0,0,,We don't have a good language for talking about them. Dialogue: 0,0:14:35.42,0:14:38.86,EN,,0,0,0,,Well, let's invent an appropriate language Dialogue: 0,0:14:42.52,0:14:44.04,EN,,0,0,0,,in which we can build these pieces. Dialogue: 0,0:14:44.78,0:14:47.21,EN,,0,0,0,,The key to the language is these guys, Dialogue: 0,0:14:47.21,0:14:49.71,EN,,0,0,0,,is what is these things I called signals? Dialogue: 0,0:14:50.48,0:14:53.32,EN,,0,0,0,,What are these things that are flying on the arrows between the boxes? Dialogue: 0,0:14:56.88,0:14:57.71,EN,,0,0,0,,Well, those things Dialogue: 0,0:14:59.85,0:15:03.52,EN,,0,0,0,,are going to be data structures called streams. Dialogue: 0,0:15:03.79,0:15:05.87,EN,,0,0,0,,That's going to be the key to inventing this language. Dialogue: 0,0:15:07.98,0:15:08.51,EN,,0,0,0,,What's a stream? Dialogue: 0,0:15:08.52,0:15:11.50,EN,,0,0,0,,Well, a stream is, like anything else, a data abstraction. Dialogue: 0,0:15:12.22,0:15:15.82,EN,,0,0,0,,So I should tell you what its selectors and constructors are. Dialogue: 0,0:15:16.87,0:15:19.48,EN,,0,0,0,,For a stream, we're going to have one constructor Dialogue: 0,0:15:19.98,0:15:21.43,EN,,0,0,0,,that's called CONS-stream. Dialogue: 0,0:15:25.69,0:15:28.11,EN,,0,0,0,,CONS-stream is going to put two things together Dialogue: 0,0:15:28.59,0:15:30.22,EN,,0,0,0,,to form a thing called a stream. Dialogue: 0,0:15:32.04,0:15:33.85,EN,,0,0,0,,And then to extract things from the stream, Dialogue: 0,0:15:33.98,0:15:36.11,EN,,0,0,0,,we're going to have a selector called the head of the stream. Dialogue: 0,0:15:38.01,0:15:38.86,EN,,0,0,0,,So if I have a stream, Dialogue: 0,0:15:39.00,0:15:40.41,EN,,0,0,0,,I can take its head Dialogue: 0,0:15:41.13,0:15:42.38,EN,,0,0,0,,or I can take its tail. Dialogue: 0,0:15:44.72,0:15:47.42,EN,,0,0,0,,And remember, I have to tell you George's contract Dialogue: 0,0:15:48.24,0:15:52.70,EN,,0,0,0,,to tell you what the axioms are that relate these. Dialogue: 0,0:15:53.44,0:16:00.17,EN,,0,0,0,,And it's going to be for any x and y, Dialogue: 0,0:16:03.40,0:16:05.44,EN,,0,0,0,,if I form the CONS-stream and take the head, Dialogue: 0,0:16:05.69,0:16:11.96,EN,,0,0,0,,the head of CONS-stream of x and y Dialogue: 0,0:16:13.29,0:16:14.52,EN,,0,0,0,,is going to be x Dialogue: 0,0:16:16.14,0:16:27.45,EN,,0,0,0,,and the tail of CONS-stream of x and y is going to be y. Dialogue: 0,0:16:28.44,0:16:34.75,EN,,0,0,0,,So those are the constructor, two selectors for streams, and an axiom. Dialogue: 0,0:16:34.75,0:16:35.85,EN,,0,0,0,,There's something fishy here. Dialogue: 0,0:16:36.98,0:16:39.00,EN,,0,0,0,,So you might notice that these are exactly Dialogue: 0,0:16:40.19,0:16:42.08,EN,,0,0,0,,the axioms for CONS, CAR, and CDR. Dialogue: 0,0:16:43.63,0:16:46.56,EN,,0,0,0,,So if I said instead of writing CONS-stream I wrote CONS Dialogue: 0,0:16:47.10,0:16:49.80,EN,,0,0,0,,and I said head was the CAR and tail was the CDR, Dialogue: 0,0:16:50.76,0:16:52.81,EN,,0,0,0,,those are exactly the axioms for pairs. Dialogue: 0,0:16:52.81,0:16:54.32,EN,,0,0,0,,And in fact, there's another thing here. Dialogue: 0,0:16:55.13,0:16:56.80,EN,,0,0,0,,We're going to have a thing called the-empty-stream Dialogue: 0,0:17:02.80,0:17:04.04,EN,,0,0,0,,which is like the-empty-list. Dialogue: 0,0:17:08.31,0:17:10.03,EN,,0,0,0,,So why am I introducing this terminology? Dialogue: 0,0:17:10.03,0:17:12.12,EN,,0,0,0,,Why don't I just keep talking about pairs and lists? Dialogue: 0,0:17:12.78,0:17:13.79,EN,,0,0,0,,Well, we'll see. Dialogue: 0,0:17:15.51,0:17:18.24,EN,,0,0,0,,For now, if you like, why don't you just pretend Dialogue: 0,0:17:18.30,0:17:21.56,EN,,0,0,0,,that streams really are just a terminology for lists. Dialogue: 0,0:17:21.56,0:17:22.99,EN,,0,0,0,,And we'll see in a little while why Dialogue: 0,0:17:23.61,0:17:26.09,EN,,0,0,0,,why we want to keep this extra abstraction layer Dialogue: 0,0:17:26.83,0:17:28.15,EN,,0,0,0,,and not just call them lists. Dialogue: 0,0:17:32.30,0:17:33.72,EN,,0,0,0,,OK, now that we have streams, Dialogue: 0,0:17:33.74,0:17:35.85,EN,,0,0,0,,we can start constructing the pieces of the language Dialogue: 0,0:17:37.04,0:17:38.17,EN,,0,0,0,,to operate on streams. Dialogue: 0,0:17:38.75,0:17:42.12,EN,,0,0,0,,And there are a whole bunch of very useful things that we could start making. Dialogue: 0,0:17:42.12,0:17:42.81,EN,,0,0,0,,For instance, Dialogue: 0,0:17:44.89,0:17:49.79,EN,,0,0,0,,we'll make our map box to take a stream, s, Dialogue: 0,0:17:54.80,0:17:56.62,EN,,0,0,0,,and a procedure, Dialogue: 0,0:17:57.80,0:17:59.21,EN,,0,0,0,,and to generate a new stream Dialogue: 0,0:18:00.14,0:18:02.28,EN,,0,0,0,,which has as its elements Dialogue: 0,0:18:02.28,0:18:04.88,EN,,0,0,0,,the procedure applied to all the successive elements of s. Dialogue: 0,0:18:05.87,0:18:07.40,EN,,0,0,0,,In fact, we've seen this before. Dialogue: 0,0:18:07.40,0:18:10.24,EN,,0,0,0,,This is the procedure map that we did with lists. Dialogue: 0,0:18:10.95,0:18:12.60,EN,,0,0,0,,And you see it's exactly map, Dialogue: 0,0:18:12.60,0:18:14.65,EN,,0,0,0,,except we're testing for empty-stream. Dialogue: 0,0:18:14.65,0:18:15.56,EN,,0,0,0,,Oh, I forgot to mention that. Dialogue: 0,0:18:15.56,0:18:17.15,EN,,0,0,0,,Empty-stream is like the null test. Dialogue: 0,0:18:18.03,0:18:20.48,EN,,0,0,0,,So if it's empty, we generate the empty stream. Dialogue: 0,0:18:20.51,0:18:22.28,EN,,0,0,0,,Otherwise, we form a new stream Dialogue: 0,0:18:23.52,0:18:27.18,EN,,0,0,0,,whose first element is the procedure applied to the head of the stream, Dialogue: 0,0:18:28.51,0:18:29.32,EN,,0,0,0,,and whose rest Dialogue: 0,0:18:29.60,0:18:32.43,EN,,0,0,0,,is gotten by mapping along with the procedure down the tail of the stream. Dialogue: 0,0:18:33.14,0:18:35.90,EN,,0,0,0,,So that looks exactly like the map procedure we looked at before. Dialogue: 0,0:18:37.03,0:18:38.20,EN,,0,0,0,,Here's another useful thing. Dialogue: 0,0:18:38.35,0:18:40.46,EN,,0,0,0,,Filter, this is our filter box. Dialogue: 0,0:18:40.46,0:18:43.89,EN,,0,0,0,,We're going to have a predicate and a stream. Dialogue: 0,0:18:43.89,0:18:45.08,EN,,0,0,0,,We're going to make a new stream Dialogue: 0,0:18:45.80,0:18:48.17,EN,,0,0,0,,consists of all the elements of the original one that satisfy the predicate. Dialogue: 0,0:18:48.33,0:18:49.48,EN,,0,0,0,,that satisfy the predicate. Dialogue: 0,0:18:50.38,0:18:51.31,EN,,0,0,0,,That's case analysis. Dialogue: 0,0:18:51.32,0:18:52.73,EN,,0,0,0,,When there's nothing in the stream, Dialogue: 0,0:18:53.04,0:18:54.22,EN,,0,0,0,,we return the empty stream. Dialogue: 0,0:18:56.28,0:18:59.18,EN,,0,0,0,,We test the predicate on the head of the stream. Dialogue: 0,0:19:00.06,0:19:01.04,EN,,0,0,0,,And if it's true, Dialogue: 0,0:19:01.53,0:19:02.83,EN,,0,0,0,,we add the head of the stream onto the result Dialogue: 0,0:19:03.02,0:19:06.22,EN,,0,0,0,,the result of filtering the tail of the stream. Dialogue: 0,0:19:08.22,0:19:10.04,EN,,0,0,0,,And otherwise, if that predicate was false, Dialogue: 0,0:19:10.49,0:19:11.98,EN,,0,0,0,,we just filter the tail of the stream. Dialogue: 0,0:19:13.50,0:19:14.46,EN,,0,0,0,,Right, so there's filter. Dialogue: 0,0:19:16.59,0:19:18.56,EN,,0,0,0,,Let me run through a couple more rather quickly. Dialogue: 0,0:19:18.56,0:19:20.70,EN,,0,0,0,,They're all in the book and you can look at them. Dialogue: 0,0:19:20.88,0:19:21.80,EN,,0,0,0,,Let me just flash through. Dialogue: 0,0:19:22.11,0:19:22.94,EN,,0,0,0,,Here's accumulate. Dialogue: 0,0:19:23.26,0:19:26.92,EN,,0,0,0,,Accumulate takes a way of combining things Dialogue: 0,0:19:27.36,0:19:29.05,EN,,0,0,0,,an initial value in a stream Dialogue: 0,0:19:29.96,0:19:31.13,EN,,0,0,0,,and sticks them all together. Dialogue: 0,0:19:31.56,0:19:33.69,EN,,0,0,0,,If the stream's empty, it's just the initial value. Dialogue: 0,0:19:33.97,0:19:36.20,EN,,0,0,0,,Otherwise, we combine the head of the stream Dialogue: 0,0:19:36.32,0:19:37.82,EN,,0,0,0,,with the result of accumulating Dialogue: 0,0:19:38.01,0:19:40.24,EN,,0,0,0,,the tail of the stream starting from the initial value. Dialogue: 0,0:19:40.90,0:19:42.83,EN,,0,0,0,,So that's what I'd use to add up everything in the stream. Dialogue: 0,0:19:42.83,0:19:43.98,EN,,0,0,0,,I'd accumulate with plus. Dialogue: 0,0:19:45.83,0:19:47.56,EN,,0,0,0,,How would I enumerate the leaves of a tree? Dialogue: 0,0:19:48.06,0:19:52.89,EN,,0,0,0,,Well, if the tree is just a leaf itself, Dialogue: 0,0:19:53.79,0:19:55.90,EN,,0,0,0,,I make something which only has that node in it. Dialogue: 0,0:19:56.64,0:19:59.32,EN,,0,0,0,,Otherwise, I append together the stuff of enumerating Dialogue: 0,0:19:59.61,0:20:02.35,EN,,0,0,0,,the left branch and the right branch. Dialogue: 0,0:20:04.34,0:20:08.32,EN,,0,0,0,,And then append here is like the ordinary append on lists. Dialogue: 0,0:20:13.19,0:20:13.85,EN,,0,0,0,,You can look at that. Dialogue: 0,0:20:13.85,0:20:17.53,EN,,0,0,0,,That's analogous to the ordinary procedure for appending two lists. Dialogue: 0,0:20:18.91,0:20:20.60,EN,,0,0,0,,Ah... How would I enumerate an interval? Dialogue: 0,0:20:21.96,0:20:23.77,EN,,0,0,0,,This will take two integers, low and high, Dialogue: 0,0:20:23.88,0:20:27.00,EN,,0,0,0,,and generate a stream of the integers going from low to high. Dialogue: 0,0:20:28.32,0:20:29.88,EN,,0,0,0,,And we can make a whole bunch of pieces. Dialogue: 0,0:20:31.89,0:20:34.48,EN,,0,0,0,,So that's a little language of talking about streams. Dialogue: 0,0:20:34.49,0:20:35.32,EN,,0,0,0,,Once we have streams, Dialogue: 0,0:20:35.32,0:20:37.67,EN,,0,0,0,,we can build things for manipulating them. Dialogue: 0,0:20:37.67,0:20:39.04,EN,,0,0,0,,Again, we're making a language. Dialogue: 0,0:20:40.20,0:20:42.22,EN,,0,0,0,,And now we can start expressing things in this language. Dialogue: 0,0:20:43.06,0:20:47.31,EN,,0,0,0,,Here's our original procedure for summing the odd squares in a tree. Dialogue: 0,0:20:47.31,0:20:52.62,EN,,0,0,0,,And you'll notice it looks exactly now like the block diagram, Dialogue: 0,0:20:52.64,0:20:54.59,EN,,0,0,0,,like the signal processing block diagram. Dialogue: 0,0:20:54.59,0:20:57.53,EN,,0,0,0,,So to sum the odd squares in a tree, Dialogue: 0,0:20:58.06,0:21:00.80,EN,,0,0,0,,we enumerate the leaves of the tree. Dialogue: 0,0:21:01.32,0:21:03.72,EN,,0,0,0,,We filter that for oddness. Dialogue: 0,0:21:04.83,0:21:06.54,EN,,0,0,0,,We map that for squareness. Dialogue: 0,0:21:09.32,0:21:13.34,EN,,0,0,0,,And we accumulate the result of that using addition, starting from 0. Dialogue: 0,0:21:14.76,0:21:17.20,EN,,0,0,0,,So we can see the pieces that we wanted. Dialogue: 0,0:21:17.29,0:21:19.36,EN,,0,0,0,,Similarly, the Fibonacci one, Dialogue: 0,0:21:20.04,0:21:21.88,EN,,0,0,0,,how do we get the odd Fibs? Dialogue: 0,0:21:22.05,0:21:24.57,EN,,0,0,0,,Well, we enumerate the interval from 1 to n, Dialogue: 0,0:21:26.32,0:21:28.64,EN,,0,0,0,,we map along that, Dialogue: 0,0:21:28.99,0:21:30.70,EN,,0,0,0,,computing the Fibonacci of each one. Dialogue: 0,0:21:30.92,0:21:33.79,EN,,0,0,0,,We filter the result of those for oddness. Dialogue: 0,0:21:34.81,0:21:36.64,EN,,0,0,0,,And we accumulate all of that stuff Dialogue: 0,0:21:36.88,0:21:39.12,EN,,0,0,0,,using CONS starting from the empty-list. Dialogue: 0,0:21:43.65,0:21:47.53,EN,,0,0,0,,OK, what's the advantage of this? Dialogue: 0,0:21:47.68,0:21:48.59,EN,,0,0,0,,Well, for one thing, Dialogue: 0,0:21:48.68,0:21:51.15,EN,,0,0,0,,we now have pieces that we can start mixing and matching. Dialogue: 0,0:21:51.88,0:21:52.64,EN,,0,0,0,,So for instance, Dialogue: 0,0:21:52.91,0:21:55.08,EN,,0,0,0,,if I wanted to change this, if I wanted to ah... Dialogue: 0,0:21:58.19,0:22:00.32,EN,,0,0,0,,compute the squares of the integers and then filter them, Dialogue: 0,0:22:00.33,0:22:01.34,EN,,0,0,0,,all I need to do Dialogue: 0,0:22:01.90,0:22:03.64,EN,,0,0,0,,is pick up a standard piece like this Dialogue: 0,0:22:03.68,0:22:05.40,EN,,0,0,0,,it's a map square and put it in. Dialogue: 0,0:22:06.57,0:22:07.60,EN,,0,0,0,,Or if we wanted to do Dialogue: 0,0:22:07.69,0:22:11.45,EN,,0,0,0,,this whole Fibonacci computation on the leaves of a tree Dialogue: 0,0:22:11.58,0:22:12.36,EN,,0,0,0,,rather than a sequence, Dialogue: 0,0:22:12.38,0:22:13.24,EN,,0,0,0,,all I need to do Dialogue: 0,0:22:13.40,0:22:15.93,EN,,0,0,0,,is replace this enumerator with that one. Dialogue: 0,0:22:18.03,0:22:19.82,EN,,0,0,0,,See, the advantage of this stream processing Dialogue: 0,0:22:20.24,0:22:21.53,EN,,0,0,0,,is that we're establishing-- Dialogue: 0,0:22:22.36,0:22:24.96,EN,,0,0,0,,this is one of the big themes of the course-- Dialogue: 0,0:22:25.29,0:22:27.48,EN,,0,0,0,,we're establishing conventional interfaces Dialogue: 0,0:22:32.89,0:22:37.15,EN,,0,0,0,,conventional interfaces that allow us to glue things together. Dialogue: 0,0:22:38.30,0:22:39.55,EN,,0,0,0,,Things like map and filter Dialogue: 0,0:22:39.79,0:22:41.64,EN,,0,0,0,,are a standard set of components Dialogue: 0,0:22:41.68,0:22:44.76,EN,,0,0,0,,that we can start using for pasting together programs in all sorts of ways. Dialogue: 0,0:22:45.75,0:22:48.81,EN,,0,0,0,,It allows us to see the commonality of programs. Dialogue: 0,0:22:49.95,0:22:50.92,EN,,0,0,0,,I just ought to mention, Dialogue: 0,0:22:51.08,0:22:53.07,EN,,0,0,0,,I've only showed you two procedures. Dialogue: 0,0:22:53.86,0:22:55.16,EN,,0,0,0,,But let me emphasize Dialogue: 0,0:22:55.20,0:22:57.77,EN,,0,0,0,,that this way of putting things together Dialogue: 0,0:22:57.80,0:23:01.00,EN,,0,0,0,,with maps, filters, and accumulators is very, very general. Dialogue: 0,0:23:01.41,0:23:07.28,EN,,0,0,0,,It's the generate and test paradigm for programs. Dialogue: 0,0:23:07.77,0:23:09.10,EN,,0,0,0,,And as an example of that, Dialogue: 0,0:23:09.39,0:23:12.94,EN,,0,0,0,,Richard Waters, who was at MIT when he was a graduate student, Dialogue: 0,0:23:12.96,0:23:15.26,EN,,0,0,0,,as part of his thesis research went and analyzed Dialogue: 0,0:23:15.80,0:23:19.21,EN,,0,0,0,,a large chunk of the IBM scientific subroutine library, Dialogue: 0,0:23:19.82,0:23:23.31,EN,,0,0,0,,and discovered that about 60% of the programs in it Dialogue: 0,0:23:24.06,0:23:28.25,EN,,0,0,0,,could be expressed exactly in terms using no more than what we've put here-- Dialogue: 0,0:23:28.86,0:23:30.17,EN,,0,0,0,,map, filter, and accumulate. Dialogue: 0,0:23:30.57,0:23:31.50,EN,,0,0,0,,All right, let's take a break. Dialogue: 0,0:23:36.59,0:23:37.12,EN,,0,0,0,,Questions? Dialogue: 0,0:23:41.18,0:23:42.89,EN,,0,0,0,,AUDIENCE: It seems like the essence of this whole thing Dialogue: 0,0:23:42.89,0:23:45.96,EN,,0,0,0,,is just that you have a very uniform, simple data structure Dialogue: 0,0:23:46.25,0:23:47.66,EN,,0,0,0,,to work with, the stream. Dialogue: 0,0:23:48.38,0:23:48.92,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:23:48.92,0:23:50.38,EN,,0,0,0,,The essence is that you, again, Dialogue: 0,0:23:50.40,0:23:53.07,EN,,0,0,0,,it's this sense of conventional interfaces. Dialogue: 0,0:23:53.71,0:23:55.61,EN,,0,0,0,,So you can start putting a lot of things together. Dialogue: 0,0:23:56.01,0:23:58.78,EN,,0,0,0,,And the stream is as you say, Dialogue: 0,0:23:58.78,0:24:00.89,EN,,0,0,0,,the uniform data structure that supports that. Dialogue: 0,0:24:00.89,0:24:02.84,EN,,0,0,0,,This is very much like APL, by the way. Dialogue: 0,0:24:03.60,0:24:05.21,EN,,0,0,0,,APL is very much the same idea, Dialogue: 0,0:24:05.21,0:24:06.96,EN,,0,0,0,,except in APL, instead of this stream, Dialogue: 0,0:24:07.13,0:24:08.44,EN,,0,0,0,,you have arrays and vectors. Dialogue: 0,0:24:09.56,0:24:14.48,EN,,0,0,0,,And a lot of the power of APL is exactly the same reason of the power of this. Dialogue: 0,0:24:19.91,0:24:20.91,EN,,0,0,0,,OK, thank you. Dialogue: 0,0:24:20.91,0:24:21.66,EN,,0,0,0,,Let's take a break. Dialogue: 0,0:24:21.66,0:24:30.35,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:24:57.47,0:24:57.61,EN,,0,0,0,,All right. Dialogue: 0,0:24:57.61,0:24:58.59,EN,,0,0,0,,We've been looking at Dialogue: 0,0:25:00.54,0:25:03.20,EN,,0,0,0,,at ways of organizing computations using streams. Dialogue: 0,0:25:03.85,0:25:05.47,EN,,0,0,0,,But what I want to do now is just show you two Dialogue: 0,0:25:05.93,0:25:09.12,EN,,0,0,0,,somewhat more complicated examples of that. Dialogue: 0,0:25:10.84,0:25:14.12,EN,,0,0,0,,Let's start by thinking about the following Dialogue: 0,0:25:14.20,0:25:16.81,EN,,0,0,0,,kind of utility procedure that will come in useful. Dialogue: 0,0:25:16.81,0:25:18.09,EN,,0,0,0,,Suppose I've got a stream. Dialogue: 0,0:25:19.96,0:25:23.15,EN,,0,0,0,,And the elements of this stream are themselves streams. Dialogue: 0,0:25:23.98,0:25:26.53,EN,,0,0,0,,So the first thing might be 1, 2, 3. Dialogue: 0,0:25:32.72,0:25:33.88,EN,,0,0,0,,So I've got a stream. Dialogue: 0,0:25:33.88,0:25:40.10,EN,,0,0,0,,And each element of the stream is itself a stream. Dialogue: 0,0:25:40.97,0:25:43.42,EN,,0,0,0,,And what I'd like to do is build a stream Dialogue: 0,0:25:43.64,0:25:46.75,EN,,0,0,0,,that sort of collects together all of the elements, Dialogue: 0,0:25:46.76,0:25:49.24,EN,,0,0,0,,pulls all of the elements out of these sub-streams Dialogue: 0,0:25:50.11,0:25:51.82,EN,,0,0,0,,and strings them all together in one thing. Dialogue: 0,0:25:52.27,0:25:55.61,EN,,0,0,0,,So just to show you the use of this language, how easy it is, Dialogue: 0,0:25:56.11,0:25:57.10,EN,,0,0,0,,call that flatten. Dialogue: 0,0:25:57.95,0:26:10.64,EN,,0,0,0,,And I can define to flatten this stream of streams. Dialogue: 0,0:26:12.89,0:26:13.80,EN,,0,0,0,,Well, what is that? Dialogue: 0,0:26:13.96,0:26:16.24,EN,,0,0,0,,That's just an accumulation. Dialogue: 0,0:26:16.32,0:26:25.05,EN,,0,0,0,,I want to accumulate using append, Dialogue: 0,0:26:25.07,0:26:26.45,EN,,0,0,0,,by successively appending. Dialogue: 0,0:26:26.73,0:26:29.29,EN,,0,0,0,,So I accumulate using append streams, Dialogue: 0,0:26:35.90,0:26:48.20,EN,,0,0,0,,starting with the-empty-stream down that stream of streams. Dialogue: 0,0:26:54.84,0:26:55.84,EN,,0,0,0,,OK, so there's an example of Dialogue: 0,0:26:56.92,0:26:59.23,EN,,0,0,0,,how you can start using these higher order things Dialogue: 0,0:26:59.60,0:27:00.83,EN,,0,0,0,,to do some interesting operations. Dialogue: 0,0:27:00.83,0:27:05.10,EN,,0,0,0,,In fact, there's another useful thing that I want to do. Dialogue: 0,0:27:05.10,0:27:07.05,EN,,0,0,0,,I want to define a procedure called flat-map, Dialogue: 0,0:27:17.18,0:27:20.59,EN,,0,0,0,,flat map of some function and a stream. Dialogue: 0,0:27:21.84,0:27:25.72,EN,,0,0,0,,And what this is going to do is s will be a stream of elements. Dialogue: 0,0:27:25.72,0:27:27.69,EN,,0,0,0,,f is going to be a function Dialogue: 0,0:27:27.72,0:27:30.62,EN,,0,0,0,,for each element in the stream produces another stream. Dialogue: 0,0:27:31.95,0:27:34.52,EN,,0,0,0,,And what I want to do is take all of the elements and all of those streams Dialogue: 0,0:27:35.00,0:27:36.00,EN,,0,0,0,,and combine them together. Dialogue: 0,0:27:36.00,0:27:49.13,EN,,0,0,0,,So that's just going to be the flatten of map f down s. Dialogue: 0,0:27:51.20,0:27:53.04,EN,,0,0,0,,Each time I apply f to an element of s, Dialogue: 0,0:27:53.05,0:27:53.85,EN,,0,0,0,,I get a stream. Dialogue: 0,0:27:54.29,0:27:55.24,EN,,0,0,0,,If I map it all the way down, Dialogue: 0,0:27:55.24,0:27:56.27,EN,,0,0,0,,I get a stream of streams, Dialogue: 0,0:27:56.46,0:27:57.42,EN,,0,0,0,,and I'll flatten that. Dialogue: 0,0:27:58.67,0:28:02.64,EN,,0,0,0,,Well, I want to use that to show you a Dialogue: 0,0:28:03.87,0:28:05.84,EN,,0,0,0,,a new way to do a familiar kind of problem. Dialogue: 0,0:28:06.51,0:28:12.27,EN,,0,0,0,,The problem's going to be like a lot of problems you've seen, Dialogue: 0,0:28:12.28,0:28:13.96,EN,,0,0,0,,although maybe not this particular one. Dialogue: 0,0:28:14.19,0:28:15.49,EN,,0,0,0,,I'm going to give you an integer, n. Dialogue: 0,0:28:18.68,0:28:19.93,EN,,0,0,0,,And the problem is going to be Dialogue: 0,0:28:21.20,0:28:31.53,EN,,0,0,0,,find all pairs and integers i and j, Dialogue: 0,0:28:32.30,0:28:39.96,EN,,0,0,0,,between 0 and i, with j less than i, up to n, Dialogue: 0,0:28:42.33,0:28:52.03,EN,,0,0,0,,such that i plus j is prime. Dialogue: 0,0:28:55.74,0:28:57.92,EN,,0,0,0,,So for example, if n equals 6, Dialogue: 0,0:28:59.74,0:29:00.78,EN,,0,0,0,,let's make a little table here, Dialogue: 0,0:29:01.55,0:29:06.67,EN,,0,0,0,,i and j and i plus j. Dialogue: 0,0:29:09.70,0:29:14.91,EN,,0,0,0,,So for, say, i equals 2 and j equals 1, I'd get 3. Dialogue: 0,0:29:15.52,0:29:20.38,EN,,0,0,0,,And for i equals 3, I could have j equals 2, and that would be 5. Dialogue: 0,0:29:21.21,0:29:26.51,EN,,0,0,0,,And 4 and 1 would be 5 and so on, Dialogue: 0,0:29:26.92,0:29:28.11,EN,,0,0,0,,up until i goes to 6. Dialogue: 0,0:29:28.40,0:29:32.54,EN,,0,0,0,,And what I'd like to return is to produce a stream Dialogue: 0,0:29:33.20,0:29:37.04,EN,,0,0,0,,all the triples like this, let's say i, j, and i plus j. Dialogue: 0,0:29:37.66,0:29:39.55,EN,,0,0,0,,So for each n, I want to generate this stream. Dialogue: 0,0:29:40.97,0:29:43.68,EN,,0,0,0,,OK, well, that's easy. Dialogue: 0,0:29:43.68,0:29:44.35,EN,,0,0,0,,Let's build it up. Dialogue: 0,0:29:47.23,0:29:48.22,EN,,0,0,0,,We start like this. Dialogue: 0,0:29:50.15,0:29:54.25,EN,,0,0,0,,We're going to say for each i, for each i Dialogue: 0,0:29:55.24,0:29:56.44,EN,,0,0,0,,we're going to generate a stream. Dialogue: 0,0:29:57.00,0:29:58.59,EN,,0,0,0,,For each i in the interval 1 through n, Dialogue: 0,0:29:58.59,0:29:59.76,EN,,0,0,0,,we're going to generate a stream. Dialogue: 0,0:30:00.66,0:30:01.80,EN,,0,0,0,,What's that stream going to be? Dialogue: 0,0:30:02.23,0:30:04.04,EN,,0,0,0,,We're going to start by generating all the pairs. Dialogue: 0,0:30:04.18,0:30:07.55,EN,,0,0,0,,So for each i, we're going to generate, Dialogue: 0,0:30:08.43,0:30:14.52,EN,,0,0,0,,for each j in the interval 1 to i minus 1, Dialogue: 0,0:30:16.91,0:30:17.98,EN,,0,0,0,,we'll generate the pair, Dialogue: 0,0:30:18.35,0:30:20.71,EN,,0,0,0,,or the list with two elements i and j. Dialogue: 0,0:30:23.78,0:30:27.10,EN,,0,0,0,,So we map along the interval, Dialogue: 0,0:30:28.60,0:30:29.74,EN,,0,0,0,,generating the pairs. Dialogue: 0,0:30:31.07,0:30:33.17,EN,,0,0,0,,And for each i, that generates a stream of pairs. Dialogue: 0,0:30:33.40,0:30:34.49,EN,,0,0,0,,And we flatmap it. Dialogue: 0,0:30:34.59,0:30:36.20,EN,,0,0,0,,Now we have all the pairs i and j, Dialogue: 0,0:30:36.81,0:30:38.08,EN,,0,0,0,,such that i is less than j. Dialogue: 0,0:30:38.73,0:30:39.85,EN,,0,0,0,,So that builds that. Dialogue: 0,0:30:39.85,0:30:40.76,EN,,0,0,0,,Now we're got to test them. Dialogue: 0,0:30:42.99,0:30:45.84,EN,,0,0,0,,Well, we take that thing we just built, the flatmap, Dialogue: 0,0:30:46.94,0:30:51.37,EN,,0,0,0,,and we filter it to see whether the i-- see, we had an i and a j. Dialogue: 0,0:30:51.66,0:30:54.17,EN,,0,0,0,,i was the first thing in the list, Dialogue: 0,0:30:54.30,0:30:55.60,EN,,0,0,0,,j was the second thing in the list. Dialogue: 0,0:30:57.21,0:31:00.01,EN,,0,0,0,,So we have a predicate which says in that list of two elements Dialogue: 0,0:31:00.22,0:31:02.00,EN,,0,0,0,,is the sum of the CAR and the CDR prime. Dialogue: 0,0:31:02.07,0:31:05.52,EN,,0,0,0,,And we filter that collection of pairs we just built. Dialogue: 0,0:31:06.54,0:31:07.85,EN,,0,0,0,,So those are the pairs we want. Dialogue: 0,0:31:09.42,0:31:10.24,EN,,0,0,0,,Now we go ahead Dialogue: 0,0:31:10.88,0:31:13.10,EN,,0,0,0,,Now we go ahead and we take the result of that filter Dialogue: 0,0:31:13.26,0:31:19.05,EN,,0,0,0,,we map along it, generating the list i and j and i plus j. Dialogue: 0,0:31:19.61,0:31:21.39,EN,,0,0,0,,And that's our procedure prime-sum-pairs. Dialogue: 0,0:31:22.57,0:31:24.76,EN,,0,0,0,,Ok, and then just to flash it up, here's the whole procedure. Dialogue: 0,0:31:28.08,0:31:30.97,EN,,0,0,0,,A map, a filter, a flatmap. Dialogue: 0,0:31:34.85,0:31:35.66,EN,,0,0,0,,There's the whole thing, Dialogue: 0,0:31:35.66,0:31:37.12,EN,,0,0,0,,even though this isn't particularly readable. Dialogue: 0,0:31:37.42,0:31:38.94,EN,,0,0,0,,It's just expanding that flatmap. Dialogue: 0,0:31:39.84,0:31:40.88,EN,,0,0,0,,So there's an example Dialogue: 0,0:31:43.28,0:31:45.00,EN,,0,0,0,,which illustrates the general point Dialogue: 0,0:31:45.12,0:31:46.30,EN,,0,0,0,,that nested loops Dialogue: 0,0:31:47.66,0:31:50.09,EN,,0,0,0,,in this procedure start looking like compositions of Dialogue: 0,0:31:50.11,0:31:52.81,EN,,0,0,0,,flatmaps of flatmaps of flatmaps of maps and things. Dialogue: 0,0:31:54.27,0:31:57.61,EN,,0,0,0,,So not only can we enumerate individual things, Dialogue: 0,0:31:57.61,0:31:58.81,EN,,0,0,0,,but by using flatmaps, Dialogue: 0,0:31:59.12,0:32:02.24,EN,,0,0,0,,we can do what would correspond to nested loops in most other languages. Dialogue: 0,0:32:03.23,0:32:03.76,EN,,0,0,0,,Of course, Dialogue: 0,0:32:04.91,0:32:08.03,EN,,0,0,0,,it's pretty awful to keep writing these flatmaps of flatmaps of flatmaps. Dialogue: 0,0:32:08.41,0:32:13.00,EN,,0,0,0,,Prime-sum-pairs you saw looked fairly complicated, Dialogue: 0,0:32:13.56,0:32:15.28,EN,,0,0,0,,even though the individual pieces were easy. Dialogue: 0,0:32:15.48,0:32:17.13,EN,,0,0,0,,So what you can do, if you like, Dialogue: 0,0:32:17.15,0:32:20.12,EN,,0,0,0,,is introduced some syntactic sugar that's called collect. Dialogue: 0,0:32:21.04,0:32:22.68,EN,,0,0,0,,And collect is just an abbreviation Dialogue: 0,0:32:22.91,0:32:26.16,EN,,0,0,0,,for that nest of flatmaps and filters arranged in that particular way. Dialogue: 0,0:32:26.16,0:32:28.60,EN,,0,0,0,,Here's prime-sum-pairs again, written using collect. Dialogue: 0,0:32:29.45,0:32:36.27,EN,,0,0,0,,It says to find all those pairs, I'm going to collect together a result, Dialogue: 0,0:32:36.52,0:32:39.20,EN,,0,0,0,,which is the list i, j, and i plus j, Dialogue: 0,0:32:40.84,0:32:45.39,EN,,0,0,0,,that's going to be generated as i runs through the interval from 1 to n Dialogue: 0,0:32:47.44,0:32:52.32,EN,,0,0,0,,and as j runs through the interval from 1 to i minus 1 Dialogue: 0,0:32:54.16,0:32:56.54,EN,,0,0,0,,such that i plus j is prime. Dialogue: 0,0:32:58.04,0:33:00.32,EN,,0,0,0,,So I'm not going to say what collect does in general. Dialogue: 0,0:33:00.69,0:33:02.75,EN,,0,0,0,,You can look at that by looking at it in the book. Dialogue: 0,0:33:03.42,0:33:05.45,EN,,0,0,0,,But pretty much, you can see that the pieces of this Dialogue: 0,0:33:05.84,0:33:08.60,EN,,0,0,0,,are the pieces of that original procedure I wrote. Dialogue: 0,0:33:08.82,0:33:11.40,EN,,0,0,0,,And this collect is just some syntactic sugar Dialogue: 0,0:33:11.44,0:33:14.80,EN,,0,0,0,,for automatically generating that nest of flatmaps and flatmaps. Dialogue: 0,0:33:16.31,0:33:20.33,EN,,0,0,0,,OK, well, let me do one more example Dialogue: 0,0:33:20.67,0:33:22.00,EN,,0,0,0,,that shows you the same kind of thing. Dialogue: 0,0:33:22.12,0:33:23.53,EN,,0,0,0,,Here's a very famous problem Dialogue: 0,0:33:24.70,0:33:28.75,EN,,0,0,0,,that's used to illustrate a lot of so-called backtracking computer algorithms Dialogue: 0,0:33:28.76,0:33:30.20,EN,,0,0,0,,This is the eight queens problem. Dialogue: 0,0:33:30.20,0:33:31.08,EN,,0,0,0,,This is a chess board. Dialogue: 0,0:33:32.37,0:33:33.64,EN,,0,0,0,,And the eight queens problem says, Dialogue: 0,0:33:33.64,0:33:35.85,EN,,0,0,0,,find a way to put down eight queens on a chess board Dialogue: 0,0:33:36.44,0:33:38.00,EN,,0,0,0,,so that no two are attacking each other. Dialogue: 0,0:33:38.00,0:33:40.60,EN,,0,0,0,,And here's a particular solution to the eight queens problem. Dialogue: 0,0:33:41.21,0:33:43.68,EN,,0,0,0,,So I have to make sure to put down queens Dialogue: 0,0:33:43.71,0:33:46.80,EN,,0,0,0,,no two are in the same row or the same column Dialogue: 0,0:33:47.72,0:33:49.47,EN,,0,0,0,,or sit along the same diagonal. Dialogue: 0,0:33:51.41,0:33:56.40,EN,,0,0,0,,Now, there's sort of a standard way of doing that. Dialogue: 0,0:33:59.74,0:34:01.48,EN,,0,0,0,,Well, first we need to do is Dialogue: 0,0:34:02.54,0:34:04.62,EN,,0,0,0,,below the surface, at George's level. Dialogue: 0,0:34:04.94,0:34:08.09,EN,,0,0,0,,We have to find some way to represent a board, and represent positions. Dialogue: 0,0:34:08.09,0:34:09.52,EN,,0,0,0,,And we'll not worry about that. Dialogue: 0,0:34:09.80,0:34:12.78,EN,,0,0,0,,But let's assume that there's a predicate called safe. Dialogue: 0,0:34:16.14,0:34:17.55,EN,,0,0,0,,And what safe is going to do Dialogue: 0,0:34:17.96,0:34:20.84,EN,,0,0,0,,is going to say given that I have a bunch of queens down on the chess board, Dialogue: 0,0:34:21.36,0:34:24.54,EN,,0,0,0,,is it OK to put a queen in this particular spot? Dialogue: 0,0:34:25.40,0:34:31.26,EN,,0,0,0,,So safe is going to take a row and a column. Dialogue: 0,0:34:32.76,0:34:35.47,EN,,0,0,0,,That's going to be a place where I'm going to try and put down the next queen, Dialogue: 0,0:34:36.06,0:34:42.76,EN,,0,0,0,,and the rest of positions. Dialogue: 0,0:34:45.58,0:34:46.75,EN,,0,0,0,,And what safe will say Dialogue: 0,0:34:46.86,0:34:51.68,EN,,0,0,0,,is given that I already have queens down in these positions, Dialogue: 0,0:34:53.02,0:34:54.76,EN,,0,0,0,,is it safe to put another queen down Dialogue: 0,0:34:55.10,0:34:57.20,EN,,0,0,0,,in that row and that column? Dialogue: 0,0:34:58.30,0:34:59.36,EN,,0,0,0,,And let's not worry about that. Dialogue: 0,0:34:59.36,0:35:01.38,EN,,0,0,0,,That's George's problem. and it's not hard to write. Dialogue: 0,0:35:01.38,0:35:06.27,EN,,0,0,0,,You just have to check whether this thing contains any things Dialogue: 0,0:35:06.30,0:35:08.52,EN,,0,0,0,,on that row or that column or in that diagonal. Dialogue: 0,0:35:10.53,0:35:13.12,EN,,0,0,0,,Now, how would you organize the program given that? Dialogue: 0,0:35:13.84,0:35:17.21,EN,,0,0,0,,And there's sort of a traditional way to organize it Dialogue: 0,0:35:17.93,0:35:18.97,EN,,0,0,0,,called backtracking. Dialogue: 0,0:35:20.52,0:35:23.21,EN,,0,0,0,,And it says, well, let's start off Dialogue: 0,0:35:25.13,0:35:28.88,EN,,0,0,0,,let's think about all the ways of putting the first queen down Dialogue: 0,0:35:30.04,0:35:31.34,EN,,0,0,0,,in the first column. Dialogue: 0,0:35:31.45,0:35:32.24,EN,,0,0,0,,There are eight ways. Dialogue: 0,0:35:32.58,0:35:35.00,EN,,0,0,0,,Well, let's say try the first column. Dialogue: 0,0:35:35.88,0:35:37.30,EN,,0,0,0,,Try column 1, row 1. Dialogue: 0,0:35:37.30,0:35:38.70,EN,,0,0,0,,These branches are going to represent Dialogue: 0,0:35:40.17,0:35:41.88,EN,,0,0,0,,the possibilities at each level. Dialogue: 0,0:35:43.36,0:35:45.53,EN,,0,0,0,,So I'll try and put a queen down in the first column. Dialogue: 0,0:35:46.14,0:35:47.74,EN,,0,0,0,,And now given that it's in the first column, Dialogue: 0,0:35:47.77,0:35:49.98,EN,,0,0,0,,I'll try and put the next queen down in the first column. Dialogue: 0,0:35:50.60,0:35:52.17,EN,,0,0,0,,That's no good, they're both... Dialogue: 0,0:35:53.31,0:35:54.60,EN,,0,0,0,,I'll try and put the first queen, Dialogue: 0,0:35:54.86,0:35:56.80,EN,,0,0,0,,the one in the first column, down in the first row. Dialogue: 0,0:35:56.92,0:35:57.47,EN,,0,0,0,,I'm sorry. Dialogue: 0,0:35:59.05,0:36:01.39,EN,,0,0,0,,And then given that, we'll put the next queen down in the first row. Dialogue: 0,0:36:01.39,0:36:02.09,EN,,0,0,0,,And that's no good. Dialogue: 0,0:36:02.09,0:36:03.18,EN,,0,0,0,,So I'll back up to here. Dialogue: 0,0:36:04.20,0:36:04.72,EN,,0,0,0,,And I'll say, Dialogue: 0,0:36:04.83,0:36:06.86,EN,,0,0,0,,oh, can I put the first queen down in the second row? Dialogue: 0,0:36:07.32,0:36:08.38,EN,,0,0,0,,Well, that's no good. Dialogue: 0,0:36:08.55,0:36:09.76,EN,,0,0,0,,Oh, can I put it down in the third row? Dialogue: 0,0:36:09.76,0:36:10.52,EN,,0,0,0,,Well, that's good. Dialogue: 0,0:36:12.79,0:36:15.13,EN,,0,0,0,,Well, now can I put the next queen down in the first column? Dialogue: 0,0:36:15.38,0:36:17.82,EN,,0,0,0,,Well, I can't visualize this chess board anymore, Dialogue: 0,0:36:17.82,0:36:18.86,EN,,0,0,0,,but I think that's right. Dialogue: 0,0:36:19.19,0:36:20.45,EN,,0,0,0,,And I try the next one. Dialogue: 0,0:36:20.45,0:36:24.17,EN,,0,0,0,,And at each place, I go as far down this tree as I can. Dialogue: 0,0:36:24.54,0:36:25.64,EN,,0,0,0,,And I back up. Dialogue: 0,0:36:25.64,0:36:28.97,EN,,0,0,0,,If I get down to here and find no possibilities below there, Dialogue: 0,0:36:29.00,0:36:30.12,EN,,0,0,0,,I back all the way up to here, Dialogue: 0,0:36:30.28,0:36:32.44,EN,,0,0,0,,and now start again generating this sub-tree. Dialogue: 0,0:36:33.26,0:36:34.32,EN,,0,0,0,,And I sort of walk around. Dialogue: 0,0:36:35.05,0:36:37.26,EN,,0,0,0,,And finally, if I ever manage to get all the way down, Dialogue: 0,0:36:37.72,0:36:38.59,EN,,0,0,0,,I've found a solution. Dialogue: 0,0:36:39.82,0:36:41.98,EN,,0,0,0,,So that's a typical sort of Dialogue: 0,0:36:43.12,0:36:45.93,EN,,0,0,0,,paradigm that's used a lot in AI programming. Dialogue: 0,0:36:45.93,0:36:47.30,EN,,0,0,0,,It's called backtracking search. Dialogue: 0,0:36:57.47,0:37:03.04,EN,,0,0,0,,And it's really unnecessary. Dialogue: 0,0:37:03.86,0:37:06.55,EN,,0,0,0,,You saw me get confused when I was visualizing this thing. Dialogue: 0,0:37:06.81,0:37:08.25,EN,,0,0,0,,And you sort of see the complication. Dialogue: 0,0:37:08.55,0:37:10.76,EN,,0,0,0,,This is a complicated thing to say. Dialogue: 0,0:37:10.76,0:37:11.82,EN,,0,0,0,,Why is it complicated? Dialogue: 0,0:37:12.39,0:37:13.29,EN,,0,0,0,,Its because somehow Dialogue: 0,0:37:13.53,0:37:17.39,EN,,0,0,0,,this program is too inordinately concerned with time. Dialogue: 0,0:37:18.58,0:37:20.43,EN,,0,0,0,,It's too much-- I try this one, and I try this one, Dialogue: 0,0:37:20.49,0:37:22.38,EN,,0,0,0,,and I go back to the last possibility. Dialogue: 0,0:37:22.89,0:37:24.34,EN,,0,0,0,,And that's a complicated thing. Dialogue: 0,0:37:24.34,0:37:26.36,EN,,0,0,0,,If I stop worrying about time so much, Dialogue: 0,0:37:28.04,0:37:29.76,EN,,0,0,0,,then there's a much simpler way to describe this. Dialogue: 0,0:37:31.20,0:37:32.36,EN,,0,0,0,,It says, let's imagine Dialogue: 0,0:37:33.31,0:37:36.57,EN,,0,0,0,,that I have in my hands Dialogue: 0,0:37:38.32,0:37:42.16,EN,,0,0,0,,the tree down to k minus 1 levels. Dialogue: 0,0:37:43.40,0:37:46.32,EN,,0,0,0,,See, suppose I had in my hands all possible ways Dialogue: 0,0:37:48.09,0:37:52.19,EN,,0,0,0,,to solve... to put down queens in the first k columns. Dialogue: 0,0:37:53.56,0:37:54.61,EN,,0,0,0,,Suppose I just had that. Dialogue: 0,0:37:54.61,0:37:55.79,EN,,0,0,0,,Let's not worry about how we get it. Dialogue: 0,0:37:57.07,0:37:59.20,EN,,0,0,0,,Well, then, how do I extend that? Dialogue: 0,0:37:59.20,0:38:02.16,EN,,0,0,0,,How do I find all possible ways to put down queens in the next column? Dialogue: 0,0:38:02.48,0:38:03.13,EN,,0,0,0,,It's really easy. Dialogue: 0,0:38:03.62,0:38:06.41,EN,,0,0,0,,For each of these positions I have, Dialogue: 0,0:38:07.82,0:38:13.96,EN,,0,0,0,,I enjoin, I think about putting down a queen in each row Dialogue: 0,0:38:15.08,0:38:16.16,EN,,0,0,0,,to make the next thing. Dialogue: 0,0:38:16.16,0:38:17.29,EN,,0,0,0,,And then for each one I put down, Dialogue: 0,0:38:17.44,0:38:19.71,EN,,0,0,0,,I filter those by the ones that are safe. Dialogue: 0,0:38:21.80,0:38:22.99,EN,,0,0,0,,So instead of thinking about Dialogue: 0,0:38:22.99,0:38:24.67,EN,,0,0,0,,this tree as generated step by step, Dialogue: 0,0:38:24.94,0:38:26.86,EN,,0,0,0,,I say, suppose I had it all there. Dialogue: 0,0:38:29.68,0:38:32.41,EN,,0,0,0,,And to extend it from level k minus 1 to level k, Dialogue: 0,0:38:32.64,0:38:36.24,EN,,0,0,0,,I just need to extend each thing in all possible ways Dialogue: 0,0:38:36.48,0:38:37.80,EN,,0,0,0,,and only keep the ones that are safe. Dialogue: 0,0:38:37.80,0:38:39.23,EN,,0,0,0,,And that will give me the tree to level k. Dialogue: 0,0:38:39.30,0:38:40.67,EN,,0,0,0,,And that's a recursive strategy Dialogue: 0,0:38:40.89,0:38:42.17,EN,,0,0,0,,for solving the eight queens problem. Dialogue: 0,0:38:44.53,0:38:45.34,EN,,0,0,0,,All right, well, let's look at it. Dialogue: 0,0:38:50.33,0:38:52.68,EN,,0,0,0,,To solve the eight queens problem Dialogue: 0,0:38:53.00,0:38:55.53,EN,,0,0,0,,on a board of some specified size, Dialogue: 0,0:38:58.92,0:39:01.03,EN,,0,0,0,,we write a sub-procedure called fill-columns. Dialogue: 0,0:39:01.13,0:39:04.86,EN,,0,0,0,,Fill-columns is going to put down queens up through column k. Dialogue: 0,0:39:06.35,0:39:07.70,EN,,0,0,0,,And here's the pattern of the recursion. Dialogue: 0,0:39:07.70,0:39:10.92,EN,,0,0,0,,I'm going to call fill-columns with the size eventually. Dialogue: 0,0:39:12.99,0:39:15.28,EN,,0,0,0,,So fill-columns says how to put down queens safely Dialogue: 0,0:39:15.29,0:39:17.16,EN,,0,0,0,,safely in the first k columns of this chess board Dialogue: 0,0:39:17.20,0:39:19.58,EN,,0,0,0,,with a size number of rows in it. Dialogue: 0,0:39:20.36,0:39:21.64,EN,,0,0,0,,If k is equal to 0, Dialogue: 0,0:39:22.27,0:39:23.60,EN,,0,0,0,,well, then I don't have to put anything down. Dialogue: 0,0:39:23.94,0:39:25.93,EN,,0,0,0,,So my solution is just an empty chess board. Dialogue: 0,0:39:26.71,0:39:28.07,EN,,0,0,0,,Otherwise, I'm going to do some stuff. Dialogue: 0,0:39:28.35,0:39:29.44,EN,,0,0,0,,And I'm going to use collect. Dialogue: 0,0:39:30.81,0:39:31.77,EN,,0,0,0,,And here's the collect. Dialogue: 0,0:39:34.33,0:39:41.91,EN,,0,0,0,,I find all ways to put down queens in the first k minus 1 columns. Dialogue: 0,0:39:42.19,0:39:43.32,EN,,0,0,0,,And this was just what I set for. Dialogue: 0,0:39:43.32,0:39:46.36,EN,,0,0,0,,Imagine I have this tree down to k minus 1 levels. Dialogue: 0,0:39:48.88,0:39:52.11,EN,,0,0,0,,And then I find all ways of trying a row, Dialogue: 0,0:39:52.52,0:39:54.13,EN,,0,0,0,,that's just each of the possible rows. Dialogue: 0,0:39:54.13,0:39:55.04,EN,,0,0,0,,They're size rows, Dialogue: 0,0:39:55.31,0:39:56.49,EN,,0,0,0,,so that's enumerate interval. Dialogue: 0,0:39:58.04,0:39:59.79,EN,,0,0,0,,And now what I do is I collect together Dialogue: 0,0:40:03.15,0:40:05.82,EN,,0,0,0,,the new row I'm going to try and column k Dialogue: 0,0:40:07.95,0:40:08.95,EN,,0,0,0,,with the rest of the queens. Dialogue: 0,0:40:08.95,0:40:10.09,EN,,0,0,0,,I adjoin a position. Dialogue: 0,0:40:10.20,0:40:11.29,EN,,0,0,0,,This is George's problem. Dialogue: 0,0:40:11.29,0:40:12.75,EN,,0,0,0,,An adjoined position is like safe. Dialogue: 0,0:40:13.64,0:40:15.28,EN,,0,0,0,,It's a thing that takes a row Dialogue: 0,0:40:15.50,0:40:17.04,EN,,0,0,0,,and a column and the rest of the positions Dialogue: 0,0:40:17.07,0:40:19.02,EN,,0,0,0,,and makes a new position collection. Dialogue: 0,0:40:19.66,0:40:25.77,EN,,0,0,0,,So I adjoin a position of a new row and a new column Dialogue: 0,0:40:26.06,0:40:27.68,EN,,0,0,0,,to the rest of the queens, Dialogue: 0,0:40:28.57,0:40:29.76,EN,,0,0,0,,where the rest of the queens Dialogue: 0,0:40:29.92,0:40:31.45,EN,,0,0,0,,runs through all possible ways Dialogue: 0,0:40:31.87,0:40:34.16,EN,,0,0,0,,of solving the problem in k minus 1 columns. Dialogue: 0,0:40:34.62,0:40:37.04,EN,,0,0,0,,And the new row runs through all possible rows Dialogue: 0,0:40:37.85,0:40:40.76,EN,,0,0,0,,such that it was safe to put one there. Dialogue: 0,0:40:43.24,0:40:44.70,EN,,0,0,0,,And that's the whole program. Dialogue: 0,0:40:46.33,0:40:47.31,EN,,0,0,0,,There's the whole procedure. Dialogue: 0,0:40:49.84,0:40:52.43,EN,,0,0,0,,Not only that, that doesn't just solve the eight queens problem, Dialogue: 0,0:40:53.42,0:40:56.68,EN,,0,0,0,,Right? It gives you all solutions to the eight queens problem. Dialogue: 0,0:40:56.68,0:40:58.48,EN,,0,0,0,,When you're done, you have a stream. Dialogue: 0,0:40:58.48,0:41:01.90,EN,,0,0,0,,And the elements of that stream are all possible ways of solving that problem. Dialogue: 0,0:41:05.31,0:41:06.26,EN,,0,0,0,,Why is that simpler? Dialogue: 0,0:41:06.26,0:41:08.54,EN,,0,0,0,,Well, we threw away the whole idea that Dialogue: 0,0:41:08.88,0:41:11.52,EN,,0,0,0,,is some process that happens in time with state. Dialogue: 0,0:41:12.72,0:41:14.42,EN,,0,0,0,,And we just said it's a whole collection of stuff. Dialogue: 0,0:41:14.94,0:41:16.00,EN,,0,0,0,,And that's why it's simpler. Dialogue: 0,0:41:18.00,0:41:20.11,EN,,0,0,0,,Right? We've changed our view. Dialogue: 0,0:41:20.11,0:41:22.59,EN,,0,0,0,,Remember, that's where we started today. Dialogue: 0,0:41:22.82,0:41:26.23,EN,,0,0,0,,We've changed our view of what it is we're trying to model. Dialogue: 0,0:41:26.23,0:41:29.20,EN,,0,0,0,,we stop modeling things that evolve in time Dialogue: 0,0:41:29.37,0:41:31.31,EN,,0,0,0,,have steps and have state. Dialogue: 0,0:41:31.75,0:41:33.79,EN,,0,0,0,,And instead, we're trying to model this global thing Dialogue: 0,0:41:33.80,0:41:35.93,EN,,0,0,0,,like the whole flight of the chalk, Dialogue: 0,0:41:36.28,0:41:38.88,EN,,0,0,0,,rather than its state at each instant. Dialogue: 0,0:41:40.75,0:41:41.44,EN,,0,0,0,,Any questions? Dialogue: 0,0:41:44.08,0:41:46.20,EN,,0,0,0,,AUDIENCE: It looks to me like backtracking would be Dialogue: 0,0:41:46.22,0:41:48.96,EN,,0,0,0,,searching for the first solution it can find, Dialogue: 0,0:41:49.31,0:41:51.48,EN,,0,0,0,,whereas this recursive search Dialogue: 0,0:41:51.48,0:41:53.26,EN,,0,0,0,,would be looking for all solutions. Dialogue: 0,0:41:53.32,0:41:53.60,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:41:54.03,0:41:55.26,EN,,0,0,0,,AUDIENCE: And it seems that Dialogue: 0,0:41:55.26,0:41:57.92,EN,,0,0,0,,if you have a large enough area to search, Dialogue: 0,0:41:57.92,0:42:00.92,EN,,0,0,0,,that the second is going to become impossible. Dialogue: 0,0:42:01.36,0:42:05.93,EN,,0,0,0,,PROFESSOR: OK, the answer to that question Dialogue: 0,0:42:07.13,0:42:08.44,EN,,0,0,0,,is the whole rest of this lecture. Dialogue: 0,0:42:08.57,0:42:10.54,EN,,0,0,0,,It's exactly the right question. Dialogue: 0,0:42:13.87,0:42:15.74,EN,,0,0,0,,And without trying to anticipate the lecture too much, Dialogue: 0,0:42:15.96,0:42:19.23,EN,,0,0,0,,you should start being suspicious at this point, Dialogue: 0,0:42:19.84,0:42:21.84,EN,,0,0,0,,and exactly those kinds of suspicions. Isn't it? Dialogue: 0,0:42:22.22,0:42:24.51,EN,,0,0,0,,It's wonderful, but isn't it so terribly inefficient? Dialogue: 0,0:42:24.83,0:42:26.03,EN,,0,0,0,,That's where we're going. Dialogue: 0,0:42:28.10,0:42:30.02,EN,,0,0,0,,So I won't answer now, but I'll answer later. Dialogue: 0,0:42:33.35,0:42:34.60,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:42:34.60,0:42:44.51,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:43:29.65,0:43:33.76,EN,,0,0,0,,Well, by now you should be starting to get suspicious. Dialogue: 0,0:43:35.60,0:43:39.26,EN,,0,0,0,,See, I've showed your this simple, elegant Dialogue: 0,0:43:40.51,0:43:42.28,EN,,0,0,0,,of putting programs together, Dialogue: 0,0:43:42.86,0:43:46.91,EN,,0,0,0,,very unlike these other traditional programs Dialogue: 0,0:43:46.92,0:43:48.19,EN,,0,0,0,,that sum the odd squares Dialogue: 0,0:43:48.72,0:43:51.32,EN,,0,0,0,,or compute the odd Fibonacci numbers. Dialogue: 0,0:43:53.74,0:43:55.48,EN,,0,0,0,,Very unlike these programs that mix up Dialogue: 0,0:43:55.85,0:43:58.84,EN,,0,0,0,,the enumerator and the filter and the accumulator. Dialogue: 0,0:44:00.44,0:44:01.82,EN,,0,0,0,,And by mixing it up, Dialogue: 0,0:44:02.20,0:44:04.59,EN,,0,0,0,,we don't have all of these wonderful Dialogue: 0,0:44:04.62,0:44:07.34,EN,,0,0,0,,conceptual advantages of these streams pieces, Dialogue: 0,0:44:07.82,0:44:09.53,EN,,0,0,0,,these wonderful mix and match components Dialogue: 0,0:44:09.55,0:44:11.77,EN,,0,0,0,,for putting together lots and lots of programs. Dialogue: 0,0:44:13.80,0:44:14.25,EN,,0,0,0,,On the other hand, Dialogue: 0,0:44:14.28,0:44:16.88,EN,,0,0,0,,most of the programs you've seen look like these ugly ones. Dialogue: 0,0:44:18.34,0:44:18.94,EN,,0,0,0,,Why's that? Dialogue: 0,0:44:19.20,0:44:20.59,EN,,0,0,0,,Can it possibly be Dialogue: 0,0:44:21.16,0:44:24.30,EN,,0,0,0,,that computer scientists are so obtuse Dialogue: 0,0:44:25.42,0:44:26.44,EN,,0,0,0,,that they don't notice Dialogue: 0,0:44:27.07,0:44:28.75,EN,,0,0,0,,that if you'd merely did this thing, Dialogue: 0,0:44:29.63,0:44:31.93,EN,,0,0,0,,then you can get this great programming elegance? Dialogue: 0,0:44:33.62,0:44:34.78,EN,,0,0,0,,There's got to be a catch. Dialogue: 0,0:44:36.76,0:44:39.05,EN,,0,0,0,,And it's actually pretty easy to see what the catch is. Dialogue: 0,0:44:39.51,0:44:41.74,EN,,0,0,0,,Let's think about the following problem. Dialogue: 0,0:44:42.03,0:44:45.47,EN,,0,0,0,,Suppose I tell you to find the second prime Dialogue: 0,0:44:46.16,0:44:48.16,EN,,0,0,0,,between 10,000 and 1 million, Dialogue: 0,0:44:49.12,0:44:50.56,EN,,0,0,0,,or if your computer's larger, Dialogue: 0,0:44:50.59,0:44:53.05,EN,,0,0,0,,say between 10,000 and 100 billion, or something. Dialogue: 0,0:44:54.32,0:44:55.45,EN,,0,0,0,,And you say, oh, that's easy. Dialogue: 0,0:44:55.47,0:44:56.65,EN,,0,0,0,,I can do that with a stream. Dialogue: 0,0:44:57.08,0:44:59.87,EN,,0,0,0,,All I do is I enumerate Dialogue: 0,0:45:00.57,0:45:02.89,EN,,0,0,0,,the interval from 10,000 to 1 million. Dialogue: 0,0:45:04.16,0:45:06.51,EN,,0,0,0,,So I get all those integers from 10,000 to 1 million. Dialogue: 0,0:45:06.80,0:45:08.64,EN,,0,0,0,,I filter them for prime-ness, Dialogue: 0,0:45:09.39,0:45:11.10,EN,,0,0,0,,so test all of them and see if they're prime. Dialogue: 0,0:45:11.76,0:45:12.83,EN,,0,0,0,,And I take the second element. Dialogue: 0,0:45:12.84,0:45:14.04,EN,,0,0,0,,Right? That's the head of the tail. Dialogue: 0,0:45:15.79,0:45:17.38,EN,,0,0,0,,OK? Well, that's clearly pretty ridiculous. Dialogue: 0,0:45:21.66,0:45:23.20,EN,,0,0,0,,We'd not even have room in the machine Dialogue: 0,0:45:23.58,0:45:25.24,EN,,0,0,0,,Right? To store the integers in the first place, Dialogue: 0,0:45:25.28,0:45:26.35,EN,,0,0,0,,much less to test them. Dialogue: 0,0:45:27.04,0:45:28.64,EN,,0,0,0,,And then I only want the second one. Dialogue: 0,0:45:29.81,0:45:34.94,EN,,0,0,0,,See, the power of this traditional programming style Dialogue: 0,0:45:36.43,0:45:37.68,EN,,0,0,0,,is exactly its weakness, Dialogue: 0,0:45:37.96,0:45:38.94,EN,,0,0,0,,that we're mixing up Dialogue: 0,0:45:39.61,0:45:43.50,EN,,0,0,0,,the enumerating and the testing and the accumulating. Dialogue: 0,0:45:44.88,0:45:46.46,EN,,0,0,0,,Right? We sort of don't do it all. Dialogue: 0,0:45:46.67,0:45:49.18,EN,,0,0,0,,So by the actual... so the very thing Dialogue: 0,0:45:49.45,0:45:51.74,EN,,0,0,0,,makes it conceptually ugly Dialogue: 0,0:45:52.20,0:45:53.80,EN,,0,0,0,,is the very thing that makes it efficient. Dialogue: 0,0:45:54.91,0:45:55.84,EN,,0,0,0,,Right? It's this mixing up. Dialogue: 0,0:45:57.80,0:45:59.34,EN,,0,0,0,,So it seems that all I've done this morning so far Dialogue: 0,0:45:59.34,0:46:00.42,EN,,0,0,0,,is just confuse you. Dialogue: 0,0:46:00.42,0:46:03.10,EN,,0,0,0,,I showed you this wonderful way that programming might work, Dialogue: 0,0:46:03.10,0:46:03.96,EN,,0,0,0,,except that it doesn't. Dialogue: 0,0:46:05.84,0:46:08.32,EN,,0,0,0,,Well, here's where the wonderful thing happens. Dialogue: 0,0:46:09.04,0:46:10.57,EN,,0,0,0,,It turns out in this game Dialogue: 0,0:46:11.21,0:46:13.84,EN,,0,0,0,,that we really can have our cake and eat it too. Dialogue: 0,0:46:14.87,0:46:16.11,EN,,0,0,0,,And what I mean by that Dialogue: 0,0:46:18.09,0:46:21.15,EN,,0,0,0,,is that we really can write stream programs Dialogue: 0,0:46:21.16,0:46:22.48,EN,,0,0,0,,exactly like the ones I wrote Dialogue: 0,0:46:23.55,0:46:27.74,EN,,0,0,0,,and arrange things so that when the machine actually runs, Dialogue: 0,0:46:28.33,0:46:31.52,EN,,0,0,0,,it's as efficient as running this traditional programming style Dialogue: 0,0:46:31.71,0:46:34.28,EN,,0,0,0,,that mixes up the generation and the test. Dialogue: 0,0:46:36.16,0:46:38.80,EN,,0,0,0,,Well, that sounds pretty magic. Dialogue: 0,0:46:40.77,0:46:41.82,EN,,0,0,0,,The key to this Dialogue: 0,0:46:42.00,0:46:43.69,EN,,0,0,0,,is that streams are not lists. Dialogue: 0,0:46:48.09,0:46:49.79,EN,,0,0,0,,We'll see this carefully in a second, but for now, Dialogue: 0,0:46:49.80,0:46:51.77,EN,,0,0,0,,let's take a look at that slide again. Dialogue: 0,0:46:52.24,0:46:53.80,EN,,0,0,0,,The image you should have here Dialogue: 0,0:46:53.84,0:46:55.58,EN,,0,0,0,,of this signal processing system Dialogue: 0,0:46:57.26,0:46:58.72,EN,,0,0,0,,is that what's going to happen Dialogue: 0,0:46:59.13,0:47:00.92,EN,,0,0,0,,is there's sort of this box Dialogue: 0,0:47:01.18,0:47:03.58,EN,,0,0,0,,that has the integers sitting in it. Dialogue: 0,0:47:05.36,0:47:06.40,EN,,0,0,0,,And there's this filter Dialogue: 0,0:47:07.45,0:47:09.37,EN,,0,0,0,,that's connected to it and it's tugging on them. Dialogue: 0,0:47:10.94,0:47:13.15,EN,,0,0,0,,And then there's someone who's tugging on this stuff Dialogue: 0,0:47:13.31,0:47:14.91,EN,,0,0,0,,saying what comes out of the filter. Dialogue: 0,0:47:16.79,0:47:18.70,EN,,0,0,0,,And the image you should have is that Dialogue: 0,0:47:18.99,0:47:20.72,EN,,0,0,0,,someone says, well, what's the first prime, Dialogue: 0,0:47:22.67,0:47:24.14,EN,,0,0,0,,and tugs on this filter. Dialogue: 0,0:47:24.59,0:47:26.12,EN,,0,0,0,,And the filter tugs on the integers. Dialogue: 0,0:47:28.02,0:47:29.15,EN,,0,0,0,,And you look only at that much, Dialogue: 0,0:47:29.16,0:47:30.93,EN,,0,0,0,,and then say, oh, I really wanted the second one. Dialogue: 0,0:47:30.93,0:47:31.95,EN,,0,0,0,,What's the second prime? Dialogue: 0,0:47:33.71,0:47:35.37,EN,,0,0,0,,And that no other computation Dialogue: 0,0:47:35.37,0:47:36.64,EN,,0,0,0,,no computation gets done Dialogue: 0,0:47:36.64,0:47:38.32,EN,,0,0,0,,except when you tug on these things. Dialogue: 0,0:47:40.50,0:47:41.41,EN,,0,0,0,,Let me try that again. Dialogue: 0,0:47:41.41,0:47:43.88,EN,,0,0,0,,This is a little device. Dialogue: 0,0:47:43.90,0:47:44.97,EN,,0,0,0,,This is a little stream machine Dialogue: 0,0:47:45.50,0:47:46.83,EN,,0,0,0,,invented by Eric Grimson Dialogue: 0,0:47:47.60,0:47:49.24,EN,,0,0,0,,who's been teaching this course at MIT. Dialogue: 0,0:47:49.83,0:47:52.51,EN,,0,0,0,,And the image is ... here's a stream of stuff, Dialogue: 0,0:47:52.54,0:47:53.82,EN,,0,0,0,,like a whole bunch of the integers. Dialogue: 0,0:47:54.78,0:47:56.33,EN,,0,0,0,,And here's some processing elements. Dialogue: 0,0:47:58.70,0:48:02.60,EN,,0,0,0,,And if, say, it's filter of filter of map, or something. Dialogue: 0,0:48:03.98,0:48:09.18,EN,,0,0,0,,And if I really tried to implement that with streams as lists, Dialogue: 0,0:48:09.24,0:48:11.26,EN,,0,0,0,,what I'd say is, well, I've got this list of things, Dialogue: 0,0:48:11.47,0:48:12.67,EN,,0,0,0,,and now I do the first filter. Dialogue: 0,0:48:12.67,0:48:14.07,EN,,0,0,0,,So I sort of do all this processing. Dialogue: 0,0:48:14.88,0:48:15.77,EN,,0,0,0,,And I take this Dialogue: 0,0:48:16.32,0:48:19.21,EN,,0,0,0,,and I process and I process and I process and I process. Dialogue: 0,0:48:19.61,0:48:21.05,EN,,0,0,0,,And now I'm got this new stream. Dialogue: 0,0:48:21.63,0:48:24.07,EN,,0,0,0,,Right? Now I take that result in my hand someplace. Dialogue: 0,0:48:24.07,0:48:25.26,EN,,0,0,0,,And I put that through the second one. Dialogue: 0,0:48:25.56,0:48:26.94,EN,,0,0,0,,And I process the whole thing. Dialogue: 0,0:48:28.27,0:48:29.51,EN,,0,0,0,,And there's this new stream. Dialogue: 0,0:48:32.13,0:48:33.36,EN,,0,0,0,,And then I take the result Dialogue: 0,0:48:34.28,0:48:36.36,EN,,0,0,0,,and I put it all the way through this one the same way. Dialogue: 0,0:48:36.36,0:48:40.99,EN,,0,0,0,,That's what would happen to these stream programs Dialogue: 0,0:48:41.69,0:48:42.97,EN,,0,0,0,,if streams were just lists. Dialogue: 0,0:48:43.86,0:48:45.64,EN,,0,0,0,,But in fact, streams aren't lists, they're streams. Dialogue: 0,0:48:45.82,0:48:48.11,EN,,0,0,0,,And the image you should have is something a little bit more like this. Dialogue: 0,0:48:50.23,0:48:52.52,EN,,0,0,0,,I've got these gadgets connected up Dialogue: 0,0:48:55.26,0:48:56.76,EN,,0,0,0,,by this data that's flowing out of them. Dialogue: 0,0:49:00.33,0:49:02.30,EN,,0,0,0,,And here's my original source of the streams. Dialogue: 0,0:49:02.32,0:49:02.92,EN,,0,0,0,,It might be Dialogue: 0,0:49:04.19,0:49:05.72,EN,,0,0,0,,starting to generate the integers. Dialogue: 0,0:49:05.98,0:49:07.39,EN,,0,0,0,,And now, what happens if I want a result? Dialogue: 0,0:49:07.58,0:49:08.91,EN,,0,0,0,,I tug on the end here. Dialogue: 0,0:49:10.20,0:49:11.07,EN,,0,0,0,,And this element says, Dialogue: 0,0:49:11.08,0:49:12.20,EN,,0,0,0,,gee, I need some more data. Dialogue: 0,0:49:13.09,0:49:15.52,EN,,0,0,0,,So it's sort of, this one comes here and tugs on that one. Dialogue: 0,0:49:15.83,0:49:17.39,EN,,0,0,0,,And it says, gee, I need some more data. Dialogue: 0,0:49:17.89,0:49:19.56,EN,,0,0,0,,And this one tugs on this thing, Dialogue: 0,0:49:19.56,0:49:20.28,EN,,0,0,0,,which might be a filter, Dialogue: 0,0:49:20.28,0:49:21.40,EN,,0,0,0,,and says, gee, I need some more data. Dialogue: 0,0:49:21.64,0:49:23.15,EN,,0,0,0,,And only as much of this Dialogue: 0,0:49:23.53,0:49:25.56,EN,,0,0,0,,thing at the end here gets generated as I tugged. Dialogue: 0,0:49:25.78,0:49:28.30,EN,,0,0,0,,And only as much of this stuff goes through the processing units Dialogue: 0,0:49:28.56,0:49:29.98,EN,,0,0,0,,as I'm pulling on the end I need. Dialogue: 0,0:49:30.76,0:49:32.09,EN,,0,0,0,,That's the image you should have Dialogue: 0,0:49:32.80,0:49:34.38,EN,,0,0,0,,of the difference between implementing Dialogue: 0,0:49:34.56,0:49:35.92,EN,,0,0,0,,what we're actually going to do Dialogue: 0,0:49:36.16,0:49:37.50,EN,,0,0,0,,and if streams were lists. Dialogue: 0,0:49:40.78,0:49:42.14,EN,,0,0,0,,Well, how do we make this thing? Dialogue: 0,0:49:42.35,0:49:43.32,EN,,0,0,0,,I hope you have the image. Dialogue: 0,0:49:43.40,0:49:44.52,EN,,0,0,0,,The trick is how to make it. Dialogue: 0,0:49:47.93,0:49:50.32,EN,,0,0,0,,We want to arrange for a stream Dialogue: 0,0:49:50.41,0:49:51.58,EN,,0,0,0,,to be a data structure Dialogue: 0,0:49:52.00,0:49:54.22,EN,,0,0,0,,that sorts of computes itself incrementally, Dialogue: 0,0:49:54.22,0:49:56.22,EN,,0,0,0,,sort of on-demand data structure. Dialogue: 0,0:49:58.96,0:50:00.51,EN,,0,0,0,,Right? And the basic idea Dialogue: 0,0:50:00.97,0:50:02.70,EN,,0,0,0,,is again, one of the very basic ideas Dialogue: 0,0:50:02.72,0:50:04.12,EN,,0,0,0,,that we're seeing throughout the whole course. Dialogue: 0,0:50:04.49,0:50:05.00,EN,,0,0,0,,And that is Dialogue: 0,0:50:05.52,0:50:06.97,EN,,0,0,0,,that there's not a firm distinction Dialogue: 0,0:50:06.99,0:50:08.44,EN,,0,0,0,,between programs and data. Dialogue: 0,0:50:09.24,0:50:10.54,EN,,0,0,0,,So what a stream is going to be Dialogue: 0,0:50:10.59,0:50:13.40,EN,,0,0,0,,is simultaneously this data structure that you think of, Dialogue: 0,0:50:13.45,0:50:15.92,EN,,0,0,0,,like the stream of the leaves of this tree. Dialogue: 0,0:50:16.86,0:50:17.85,EN,,0,0,0,,But at the same time, Dialogue: 0,0:50:17.85,0:50:19.32,EN,,0,0,0,,it's going to be a very clever procedure Dialogue: 0,0:50:20.24,0:50:22.22,EN,,0,0,0,,that has the method of computing in it. Dialogue: 0,0:50:23.74,0:50:25.93,EN,,0,0,0,,Well, let me try this. Dialogue: 0,0:50:25.93,0:50:26.62,EN,,0,0,0,,It's going to turn out Dialogue: 0,0:50:26.80,0:50:28.33,EN,,0,0,0,,that we don't need any more mechanism. Dialogue: 0,0:50:28.46,0:50:29.87,EN,,0,0,0,,We already have everything we need Dialogue: 0,0:50:30.14,0:50:30.99,EN,,0,0,0,,simply from the fact Dialogue: 0,0:50:31.02,0:50:33.93,EN,,0,0,0,,that we know how to handle procedures as first-class objects. Dialogue: 0,0:50:35.46,0:50:36.88,EN,,0,0,0,,Well, let's go back to the key. Dialogue: 0,0:50:36.88,0:50:39.03,EN,,0,0,0,,The key is, remember, we had these operations. Dialogue: 0,0:50:39.03,0:50:47.52,EN,,0,0,0,,CONS-stream and head and tail. Dialogue: 0,0:50:48.08,0:50:49.36,EN,,0,0,0,,When I started, I said Dialogue: 0,0:50:49.92,0:50:51.36,EN,,0,0,0,,you can think about this as CONS Dialogue: 0,0:50:51.40,0:50:52.62,EN,,0,0,0,,and think about this as CAR Dialogue: 0,0:50:52.62,0:50:53.52,EN,,0,0,0,,and think about that as CDR Dialogue: 0,0:50:53.55,0:50:54.16,EN,,0,0,0,,but it's not. Dialogue: 0,0:50:55.08,0:50:56.32,EN,,0,0,0,,Now, let's look at what they really are. Dialogue: 0,0:50:57.71,0:51:05.84,EN,,0,0,0,,Well, CONS-stream of x and y Dialogue: 0,0:51:07.48,0:51:17.79,EN,,0,0,0,,is going to be an abbreviation for the following thing. Dialogue: 0,0:51:19.54,0:51:28.32,EN,,0,0,0,,CONS form a pair, ordinary CONS, of x to a thing called delay of y. Dialogue: 0,0:51:31.68,0:51:33.53,EN,,0,0,0,,And before I explain that, let me go and write the rest. Dialogue: 0,0:51:34.52,0:51:35.53,EN,,0,0,0,,The head of a stream Dialogue: 0,0:51:38.09,0:51:39.79,EN,,0,0,0,,is going to be just the CAR. Dialogue: 0,0:51:42.38,0:51:44.25,EN,,0,0,0,,And the tail of a stream Dialogue: 0,0:51:46.68,0:51:54.60,EN,,0,0,0,,is going to be a thing called force the CDR of the stream. Dialogue: 0,0:51:56.12,0:51:57.04,EN,,0,0,0,,Now let me explain this. Dialogue: 0,0:51:58.06,0:51:59.88,EN,,0,0,0,,Delay is going to be a special magic thing. Dialogue: 0,0:52:01.42,0:52:02.33,EN,,0,0,0,,What delay does Dialogue: 0,0:52:03.85,0:52:05.31,EN,,0,0,0,,is take an expression Dialogue: 0,0:52:05.50,0:52:06.86,EN,,0,0,0,,and produce a promise Dialogue: 0,0:52:07.12,0:52:09.15,EN,,0,0,0,,to compute that expression when you ask for it. Dialogue: 0,0:52:10.60,0:52:11.98,EN,,0,0,0,,It doesn't do any computation here. Dialogue: 0,0:52:11.98,0:52:14.32,EN,,0,0,0,,Just sort of... It just gives you a rain check. Dialogue: 0,0:52:14.82,0:52:16.20,EN,,0,0,0,,It produces a promise. Dialogue: 0,0:52:17.11,0:52:18.20,EN,,0,0,0,,And CONS-stream says Dialogue: 0,0:52:18.81,0:52:21.96,EN,,0,0,0,,I'm going to put together in a pair x Dialogue: 0,0:52:23.31,0:52:25.36,EN,,0,0,0,,and a promise to compute y. Dialogue: 0,0:52:28.23,0:52:28.99,EN,,0,0,0,,Now, if I want the head, Dialogue: 0,0:52:28.99,0:52:30.75,EN,,0,0,0,,that's just the CAR that I put in the pair. Dialogue: 0,0:52:31.84,0:52:33.71,EN,,0,0,0,,And the key is that the tail is going to be-- Dialogue: 0,0:52:34.62,0:52:36.65,EN,,0,0,0,,force calls in that promise. Dialogue: 0,0:52:38.22,0:52:39.88,EN,,0,0,0,,Force -- Tail says, well, Dialogue: 0,0:52:40.03,0:52:41.02,EN,,0,0,0,,well, take that promise Dialogue: 0,0:52:41.85,0:52:44.52,EN,,0,0,0,,and now call in that promise. Dialogue: 0,0:52:44.56,0:52:46.03,EN,,0,0,0,,And then we compute that thing. Dialogue: 0,0:52:47.69,0:52:48.72,EN,,0,0,0,,That's how this is going to work. Dialogue: 0,0:52:48.74,0:52:51.55,EN,,0,0,0,,That's what CONS-stream, head, and tail really are. Dialogue: 0,0:52:54.60,0:52:55.57,EN,,0,0,0,,Now, let's see how this works. Dialogue: 0,0:52:55.57,0:52:57.50,EN,,0,0,0,,And we'll go through this fairly carefully. Let's -- Dialogue: 0,0:52:58.76,0:53:00.62,EN,,0,0,0,,We're going to see how this Dialogue: 0,0:53:01.32,0:53:03.66,EN,,0,0,0,,example of computing the second prime Dialogue: 0,0:53:05.50,0:53:07.16,EN,,0,0,0,,right? between 10,000 and a million. Dialogue: 0,0:53:08.65,0:53:12.03,EN,,0,0,0,,OK, so we start off and we have this expression. Dialogue: 0,0:53:15.36,0:53:16.62,EN,,0,0,0,,Right? The second prime-- Dialogue: 0,0:53:16.64,0:53:21.90,EN,,0,0,0,,the head of the tail of the result of filtering for primality Dialogue: 0,0:53:22.83,0:53:25.31,EN,,0,0,0,,the integers between 10,000 and 1 million. Dialogue: 0,0:53:26.71,0:53:27.61,EN,,0,0,0,,Now, what is that? Dialogue: 0,0:53:28.40,0:53:29.20,EN,,0,0,0,,What that is, Dialogue: 0,0:53:31.63,0:53:34.17,EN,,0,0,0,,that interval between 10,000 and 1 million, Dialogue: 0,0:53:35.72,0:53:37.32,EN,,0,0,0,,well, if you trace through enumerate interval, Dialogue: 0,0:53:37.34,0:53:38.78,EN,,0,0,0,,there builds a CONS-stream. Dialogue: 0,0:53:39.92,0:53:41.39,EN,,0,0,0,,And the CONS-stream is Dialogue: 0,0:53:41.96,0:53:43.61,EN,,0,0,0,,the CONS of 10,000 Dialogue: 0,0:53:44.51,0:53:48.92,EN,,0,0,0,,to a promise to compute the integers between 10,001 and 1 million. Dialogue: 0,0:53:54.00,0:53:55.75,EN,,0,0,0,,Okay? So that's what this expression is. Dialogue: 0,0:53:55.75,0:53:57.32,EN,,0,0,0,,Here I'm using the substitution model. Dialogue: 0,0:53:57.64,0:53:59.32,EN,,0,0,0,,And we can use the substitution model Dialogue: 0,0:53:59.34,0:54:01.01,EN,,0,0,0,,because we don't have side effects and state. Dialogue: 0,0:54:03.56,0:54:06.38,EN,,0,0,0,,Okay? So I have CONS of 10,000 Dialogue: 0,0:54:06.41,0:54:08.27,EN,,0,0,0,,to a promise to compute the rest of the integers. Dialogue: 0,0:54:08.32,0:54:10.49,EN,,0,0,0,,So only one integer, so far, got enumerated. Dialogue: 0,0:54:14.38,0:54:16.96,EN,,0,0,0,,Well, I'm going to filter that thing for primality. Dialogue: 0,0:54:19.44,0:54:21.90,EN,,0,0,0,,Again, you go back and look at the filter code. Dialogue: 0,0:54:22.36,0:54:24.46,EN,,0,0,0,,What the filter will first do is test the head. Dialogue: 0,0:54:25.46,0:54:28.25,EN,,0,0,0,,So in this case, the filter will test 10,000 Dialogue: 0,0:54:30.30,0:54:32.97,EN,,0,0,0,,oh, 10,000's not prime. Dialogue: 0,0:54:33.50,0:54:35.85,EN,,0,0,0,,Therefore, what I have to do recursively Dialogue: 0,0:54:36.25,0:54:37.39,EN,,0,0,0,,is filter the tail. Dialogue: 0,0:54:39.22,0:54:40.14,EN,,0,0,0,,And what's the tail of it, Dialogue: 0,0:54:40.16,0:54:43.76,EN,,0,0,0,,well, that's the tail of this pair with a promise in it. Dialogue: 0,0:54:46.34,0:54:48.06,EN,,0,0,0,,Tail now comes in and says, Dialogue: 0,0:54:48.28,0:54:49.50,EN,,0,0,0,,well, I'm going to force that. Dialogue: 0,0:54:49.68,0:54:50.94,EN,,0,0,0,,I'm going to force that promise, Dialogue: 0,0:54:52.30,0:54:54.36,EN,,0,0,0,,which means now I'm going to compute Dialogue: 0,0:54:55.58,0:54:57.96,EN,,0,0,0,,the integers between 10,001 and 1 million. Dialogue: 0,0:55:00.80,0:55:02.97,EN,,0,0,0,,OK? So this filter now is looking at that. Dialogue: 0,0:55:07.81,0:55:08.92,EN,,0,0,0,,That enumerate itself, Dialogue: 0,0:55:08.94,0:55:11.23,EN,,0,0,0,,now we're back in the original enumerate situation. Dialogue: 0,0:55:11.96,0:55:13.00,EN,,0,0,0,,The enumerate is Dialogue: 0,0:55:14.12,0:55:16.44,EN,,0,0,0,,CONS of the first thing, 10,001, Dialogue: 0,0:55:16.60,0:55:18.20,EN,,0,0,0,,onto a promise to compute the rest. Dialogue: 0,0:55:19.74,0:55:22.75,EN,,0,0,0,,So now the primality filter is going to go look at 10,001. Dialogue: 0,0:55:23.23,0:55:25.12,EN,,0,0,0,,It's going to decide if it likes that or not. Dialogue: 0,0:55:25.12,0:55:27.08,EN,,0,0,0,,It turns out 10,001 isn't prime. Dialogue: 0,0:55:27.55,0:55:29.61,EN,,0,0,0,,So it'll force it again and again and again. Dialogue: 0,0:55:32.92,0:55:35.80,EN,,0,0,0,,And finally, I think the first prime it hits is 10,009. Dialogue: 0,0:55:37.10,0:55:38.33,EN,,0,0,0,,And at that point, it'll stop. Dialogue: 0,0:55:40.84,0:55:41.93,EN,,0,0,0,,And that will be the first prime, Dialogue: 0,0:55:41.96,0:55:43.48,EN,,0,0,0,,and then eventually, it'll need the second prime. Dialogue: 0,0:55:45.24,0:55:46.84,EN,,0,0,0,,So at that point, it will go again. Dialogue: 0,0:55:47.03,0:55:48.25,EN,,0,0,0,,So you see what happens is that Dialogue: 0,0:55:48.52,0:55:50.49,EN,,0,0,0,,no more gets generated Dialogue: 0,0:55:51.85,0:55:52.91,EN,,0,0,0,,than you actually need. Dialogue: 0,0:55:56.48,0:55:59.92,EN,,0,0,0,,That enumerator is not going to generate any more integers Dialogue: 0,0:56:00.12,0:56:01.45,EN,,0,0,0,,than the filter asks it for Dialogue: 0,0:56:01.47,0:56:03.45,EN,,0,0,0,,as it's pulling in things to check for primality. Dialogue: 0,0:56:04.70,0:56:06.51,EN,,0,0,0,,And the filter is not going to generate Dialogue: 0,0:56:06.54,0:56:08.04,EN,,0,0,0,,any more stuff than you ask it for, Dialogue: 0,0:56:08.06,0:56:09.10,EN,,0,0,0,,which is the head of the tail. Dialogue: 0,0:56:11.61,0:56:13.26,EN,,0,0,0,,You see, what's happened is Dialogue: 0,0:56:14.70,0:56:18.24,EN,,0,0,0,,we've put that mixing of generation and test Dialogue: 0,0:56:18.67,0:56:20.65,EN,,0,0,0,,into what actually happens in the computer, Dialogue: 0,0:56:21.52,0:56:22.67,EN,,0,0,0,,even though Dialogue: 0,0:56:23.18,0:56:25.63,EN,,0,0,0,,that's not apparently what's happening from looking at our programs. Dialogue: 0,0:56:28.12,0:56:29.40,EN,,0,0,0,,OK, well, that seemed easy. Dialogue: 0,0:56:30.23,0:56:32.67,EN,,0,0,0,,All of this mechanism got put into this magic delay. Dialogue: 0,0:56:33.68,0:56:35.66,EN,,0,0,0,,So you're saying, gee, that must be where the magic is. Dialogue: 0,0:56:36.90,0:56:38.57,EN,,0,0,0,,But see there's no magic there either. Dialogue: 0,0:56:39.07,0:56:39.98,EN,,0,0,0,,You know what delay is. Dialogue: 0,0:56:40.61,0:56:45.07,EN,,0,0,0,,Delay on some expression Dialogue: 0,0:56:48.25,0:56:50.04,EN,,0,0,0,,is just an abbreviation for-- Dialogue: 0,0:56:53.36,0:56:55.63,EN,,0,0,0,,well, what's a promise to compute an expression? Dialogue: 0,0:56:56.49,0:57:01.12,EN,,0,0,0,,Lambda of nil, procedure of no arguments, which is that expression. Dialogue: 0,0:57:02.83,0:57:03.84,EN,,0,0,0,,Right? That's what a procedure is. Dialogue: 0,0:57:03.98,0:57:05.53,EN,,0,0,0,,It says I'm going to compute an expression. Dialogue: 0,0:57:06.05,0:57:06.73,EN,,0,0,0,,What's force? Dialogue: 0,0:57:07.34,0:57:10.80,EN,,0,0,0,,Right, how do I take up a promise? Dialogue: 0,0:57:10.80,0:57:14.11,EN,,0,0,0,,Well, force of some procedure, a promise, Dialogue: 0,0:57:14.78,0:57:15.40,EN,,0,0,0,,is just run it. Dialogue: 0,0:57:19.23,0:57:19.56,EN,,0,0,0,,Done. Dialogue: 0,0:57:20.24,0:57:21.37,EN,,0,0,0,,So there's no magic there at all. Dialogue: 0,0:57:23.52,0:57:24.24,EN,,0,0,0,,Well, what have we done? Dialogue: 0,0:57:26.44,0:57:27.50,EN,,0,0,0,,We said the old style, Dialogue: 0,0:57:28.14,0:57:30.81,EN,,0,0,0,,traditional style of programming is more efficient. Dialogue: 0,0:57:30.96,0:57:33.92,EN,,0,0,0,,And the stream thing is more perspicacious. Dialogue: 0,0:57:35.50,0:57:38.72,EN,,0,0,0,,And we managed to make the stream procedures Dialogue: 0,0:57:38.81,0:57:43.23,EN,,0,0,0,,run like the other procedures by using delay. Dialogue: 0,0:57:43.35,0:57:46.43,EN,,0,0,0,,And the thing that delay did for us was to de-couple Dialogue: 0,0:57:46.68,0:57:50.40,EN,,0,0,0,,the apparent order of events in our programs Dialogue: 0,0:57:51.21,0:57:53.84,EN,,0,0,0,,from the actual order of events that happened in the machine. Dialogue: 0,0:57:54.44,0:57:55.93,EN,,0,0,0,,That's really what delay is doing. Dialogue: 0,0:57:57.15,0:57:58.29,EN,,0,0,0,,That's exactly the whole point. Dialogue: 0,0:57:58.29,0:58:01.92,EN,,0,0,0,,We've given up, right, we've given up the idea Dialogue: 0,0:58:02.30,0:58:04.17,EN,,0,0,0,,that our procedures, as they run, Dialogue: 0,0:58:04.67,0:58:05.95,EN,,0,0,0,,or as we look at them, Dialogue: 0,0:58:06.33,0:58:08.25,EN,,0,0,0,,mirror some clear notion of time. Dialogue: 0,0:58:09.45,0:58:10.57,EN,,0,0,0,,And by giving that up, Dialogue: 0,0:58:11.21,0:58:13.32,EN,,0,0,0,,we give delay the freedom to arrange the order Dialogue: 0,0:58:13.34,0:58:15.20,EN,,0,0,0,,of events in the computation the way it likes. Dialogue: 0,0:58:16.69,0:58:17.61,EN,,0,0,0,,That's the whole idea. Dialogue: 0,0:58:17.61,0:58:19.45,EN,,0,0,0,,We de-couple the apparent order Dialogue: 0,0:58:19.95,0:58:21.13,EN,,0,0,0,,of events in our programs Dialogue: 0,0:58:21.16,0:58:22.89,EN,,0,0,0,,from the actual order of events in the computer. Dialogue: 0,0:58:24.09,0:58:25.77,EN,,0,0,0,,OK, well there's one more detail. Dialogue: 0,0:58:25.77,0:58:27.21,EN,,0,0,0,,It's just a technical detail, Dialogue: 0,0:58:27.21,0:58:28.43,EN,,0,0,0,,but it's actually an important one. Dialogue: 0,0:58:29.73,0:58:32.01,EN,,0,0,0,,As you run through these recursive programs unwinding, Dialogue: 0,0:58:32.16,0:58:33.58,EN,,0,0,0,,you'll see a lot of things that look like Dialogue: 0,0:58:33.64,0:58:37.87,EN,,0,0,0,,tail of the tail of the tail. Dialogue: 0,0:58:39.20,0:58:41.02,EN,,0,0,0,,Right. That's the kind of thing that would happen Dialogue: 0,0:58:41.02,0:58:42.88,EN,,0,0,0,,as I go CONSing down a stream all the way. Dialogue: 0,0:58:43.86,0:58:46.09,EN,,0,0,0,,And if each time I'm doing that, Dialogue: 0,0:58:46.14,0:58:47.58,EN,,0,0,0,,each time to compute a tail, Dialogue: 0,0:58:48.22,0:58:50.88,EN,,0,0,0,,I evaluate a procedure Dialogue: 0,0:58:51.07,0:58:53.07,EN,,0,0,0,,which then has to go re-compute its tail, Dialogue: 0,0:58:53.10,0:58:55.40,EN,,0,0,0,,and re-compute its tail and recompute its tail each time, Dialogue: 0,0:58:55.50,0:58:56.88,EN,,0,0,0,,you can see that's very inefficient Dialogue: 0,0:58:57.77,0:59:00.56,EN,,0,0,0,,compared to just having a list where the elements are all there, Dialogue: 0,0:59:01.16,0:59:04.00,EN,,0,0,0,,and I don't have to re-compute each tail every time I get the next tail. Dialogue: 0,0:59:05.29,0:59:08.28,EN,,0,0,0,,So there's one little hack Dialogue: 0,0:59:09.66,0:59:13.13,EN,,0,0,0,,to slightly change the abbreviation, change what delay is Dialogue: 0,0:59:14.96,0:59:18.20,EN,,0,0,0,,and make it a thing which is-- I'll write it this way. Dialogue: 0,0:59:19.68,0:59:22.04,EN,,0,0,0,,Delay -- The actual implementation, Dialogue: 0,0:59:24.52,0:59:27.93,EN,,0,0,0,,delay is an abbreviation for this thing, Dialogue: 0,0:59:28.11,0:59:30.86,EN,,0,0,0,,memo-proc of a procedure. Dialogue: 0,0:59:31.00,0:59:34.06,EN,,0,0,0,,Memo-proc is a special thing that transforms a procedure. Dialogue: 0,0:59:35.15,0:59:37.80,EN,,0,0,0,,What it does is it takes a procedure of no arguments Dialogue: 0,0:59:39.02,0:59:41.05,EN,,0,0,0,,and it transforms it into a procedure Dialogue: 0,0:59:41.36,0:59:43.55,EN,,0,0,0,,that'll only have to do its computation once. Dialogue: 0,0:59:45.10,0:59:47.45,EN,,0,0,0,,And what I mean by that is, you give it a procedure. Dialogue: 0,0:59:48.70,0:59:50.86,EN,,0,0,0,,The result of memo-proc will be a new procedure, Dialogue: 0,0:59:51.39,0:59:53.00,EN,,0,0,0,,which the first time you call it, Dialogue: 0,0:59:53.71,0:59:55.07,EN,,0,0,0,,will run the original procedure, Dialogue: 0,0:59:55.31,0:59:56.91,EN,,0,0,0,,remember what result it got, Dialogue: 0,0:59:58.56,1:00:00.68,EN,,0,0,0,,and then from ever on after, when you call it, Dialogue: 0,1:00:00.68,1:00:02.17,EN,,0,0,0,,it just won't have to do the computation. Dialogue: 0,1:00:02.19,1:00:04.43,EN,,0,0,0,,It will have cached that result someplace. Dialogue: 0,1:00:05.20,1:00:06.92,EN,,0,0,0,,And here's an implementation of memo-proc. Dialogue: 0,1:00:11.21,1:00:12.71,EN,,0,0,0,,Once you have the idea, it's easy to implement. Dialogue: 0,1:00:12.71,1:00:16.76,EN,,0,0,0,,Memo-proc is this little thing that has two little flags in there. Dialogue: 0,1:00:17.39,1:00:19.20,EN,,0,0,0,,It says, have I already been run? Dialogue: 0,1:00:20.32,1:00:22.48,EN,,0,0,0,,And initially it says, no, I haven't already been run. Dialogue: 0,1:00:23.62,1:00:27.04,EN,,0,0,0,,And what was the result I got the last time I was run? Dialogue: 0,1:00:29.07,1:00:31.07,EN,,0,0,0,,So memo-proc takes a procedure called proc, Dialogue: 0,1:00:31.56,1:00:34.01,EN,,0,0,0,,and it returns a new procedure of no arguments. Dialogue: 0,1:00:34.36,1:00:36.38,EN,,0,0,0,,Proc is supposed to be a procedure of no arguments. Dialogue: 0,1:00:38.61,1:00:41.37,EN,,0,0,0,,And it says, oh, if I'm not already run, Dialogue: 0,1:00:42.59,1:00:44.06,EN,,0,0,0,,then I'm going to do a sequence of things. Dialogue: 0,1:00:44.43,1:00:46.56,EN,,0,0,0,,I'm going to compute proc, Dialogue: 0,1:00:47.50,1:00:48.45,EN,,0,0,0,,I'm going to save that. Dialogue: 0,1:00:48.45,1:00:50.48,EN,,0,0,0,,I'm going to stash that in the variable result. Dialogue: 0,1:00:51.14,1:00:53.90,EN,,0,0,0,,I'm going to make a note to myself that I've already been run, Dialogue: 0,1:00:54.28,1:00:55.47,EN,,0,0,0,,and then I'll return the result. Dialogue: 0,1:00:56.61,1:00:59.01,EN,,0,0,0,,So that's if you compute it if it's not already run. Dialogue: 0,1:00:59.01,1:01:01.88,EN,,0,0,0,,If you call it and it's already been run, it just returns the result. Dialogue: 0,1:01:03.42,1:01:07.12,EN,,0,0,0,,So that's a little clever hack called memoization. Dialogue: 0,1:01:08.40,1:01:09.13,EN,,0,0,0,,And in this case, Dialogue: 0,1:01:10.35,1:01:14.14,EN,,0,0,0,,it short circuits having to re-compute the tail of the tail of the tail of the tail of the tail. Dialogue: 0,1:01:15.27,1:01:17.81,EN,,0,0,0,,So there isn't even that kind of inefficiency. Dialogue: 0,1:01:17.81,1:01:18.72,EN,,0,0,0,,And in fact, the streams Dialogue: 0,1:01:19.20,1:01:22.75,EN,,0,0,0,,will run with pretty much the same efficiency as the other programs precisely. Dialogue: 0,1:01:24.01,1:01:26.20,EN,,0,0,0,,And remember, again, the whole idea of this Dialogue: 0,1:01:27.48,1:01:28.60,EN,,0,0,0,,is that we've used Dialogue: 0,1:01:29.26,1:01:32.40,EN,,0,0,0,,the fact that there's no really good dividing line Dialogue: 0,1:01:32.41,1:01:33.61,EN,,0,0,0,,between procedures and data. Dialogue: 0,1:01:33.61,1:01:35.61,EN,,0,0,0,,We've written data structures that, in fact, Dialogue: 0,1:01:36.00,1:01:37.31,EN,,0,0,0,,are sort of like procedures. Dialogue: 0,1:01:38.76,1:01:40.73,EN,,0,0,0,,And what that's allowed us to do Dialogue: 0,1:01:41.58,1:01:46.54,EN,,0,0,0,,is take an example of a common control structure, Dialogue: 0,1:01:46.68,1:01:48.91,EN,,0,0,0,,in this place iteration. Dialogue: 0,1:01:49.62,1:01:51.05,EN,,0,0,0,,And we've built a data structure Dialogue: 0,1:01:51.32,1:01:52.84,EN,,0,0,0,,which, since itself is a procedure, Dialogue: 0,1:01:52.86,1:01:55.12,EN,,0,0,0,,kind of has this iteration control structure in it. Dialogue: 0,1:01:55.79,1:01:57.13,EN,,0,0,0,,And that's really what streams are. Dialogue: 0,1:01:58.91,1:01:59.76,EN,,0,0,0,,OK, questions? Dialogue: 0,1:02:03.95,1:02:05.84,EN,,0,0,0,,AUDIENCE: Your description of tail-tail-tail, Dialogue: 0,1:02:05.85,1:02:07.16,EN,,0,0,0,,if I understand it correctly, Dialogue: 0,1:02:07.28,1:02:10.76,EN,,0,0,0,,force is actually execution of a procedure, Dialogue: 0,1:02:10.78,1:02:12.83,EN,,0,0,0,,if it's done without this memo-proc thing. Dialogue: 0,1:02:12.89,1:02:13.15,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,1:02:13.44,1:02:16.38,EN,,0,0,0,,AUDIENCE: And you implied that memo-proc gets around that problem. Dialogue: 0,1:02:16.38,1:02:18.73,EN,,0,0,0,,Doesn't it only get around it if Dialogue: 0,1:02:19.34,1:02:22.19,EN,,0,0,0,,tail-tail-tail is always executing exactly the same-- Dialogue: 0,1:02:22.41,1:02:23.91,EN,,0,0,0,,PROFESSOR: Oh, that's-- sure. Dialogue: 0,1:02:23.91,1:02:25.84,EN,,0,0,0,,AUDIENCE: I guess I missed that point. Dialogue: 0,1:02:26.05,1:02:27.21,EN,,0,0,0,,PROFESSOR: Oh, sure. I mean the point is-- yeah. Dialogue: 0,1:02:31.12,1:02:33.64,EN,,0,0,0,,Yeah, I mean I have to do a computation to get the answer. Dialogue: 0,1:02:34.09,1:02:36.76,EN,,0,0,0,,But the point is, once I've found the tail of the stream, Dialogue: 0,1:02:37.58,1:02:38.70,EN,,0,0,0,,to get the tail of the tail, Dialogue: 0,1:02:38.70,1:02:40.51,EN,,0,0,0,,I shouldn't have had to re-compute the first tail. Dialogue: 0,1:02:42.98,1:02:44.32,EN,,0,0,0,,See, and if I didn't use memo-proc, Dialogue: 0,1:02:44.35,1:02:46.09,EN,,0,0,0,,that re-computation would have been done. Dialogue: 0,1:02:46.46,1:02:47.13,EN,,0,0,0,,AUDIENCE: I understand now. Dialogue: 0,1:02:50.83,1:02:52.56,EN,,0,0,0,,AUDIENCE: In one of your examples, you mentioned that Dialogue: 0,1:02:52.60,1:02:54.22,EN,,0,0,0,,we were able to use the substitution model Dialogue: 0,1:02:54.22,1:02:56.11,EN,,0,0,0,,because there are no side effects. Dialogue: 0,1:02:56.83,1:03:00.73,EN,,0,0,0,,What if we had a signal processing unit-- Dialogue: 0,1:03:00.78,1:03:02.03,EN,,0,0,0,,if we had a side effect, Dialogue: 0,1:03:02.04,1:03:03.04,EN,,0,0,0,,if we had a state? Dialogue: 0,1:03:03.62,1:03:06.84,EN,,0,0,0,,Could we still practically build the stream model? Dialogue: 0,1:03:08.46,1:03:10.59,EN,,0,0,0,,PROFESSOR: Hum... Maybe, That's a hard question. Dialogue: 0,1:03:11.20,1:03:13.42,EN,,0,0,0,,I'm going to talk a little bit later about the places where Dialogue: 0,1:03:14.36,1:03:18.24,EN,,0,0,0,,where substitution and side effects don't really mix very well. Dialogue: 0,1:03:18.96,1:03:20.48,EN,,0,0,0,,But in general, I think the answer is Dialogue: 0,1:03:20.49,1:03:21.63,EN,,0,0,0,,unless you're very careful, Dialogue: 0,1:03:21.90,1:03:24.46,EN,,0,0,0,,any amount of side effect is going to mess up everything. Dialogue: 0,1:03:35.04,1:03:38.25,EN,,0,0,0,,AUDIENCE: Sorry, I didn't quite understand the memo-proc operation. Uh... Dialogue: 0,1:03:39.68,1:03:41.12,EN,,0,0,0,,When do you execute the lambda? Dialogue: 0,1:03:41.99,1:03:43.21,EN,,0,0,0,,In other words, Dialogue: 0,1:03:43.68,1:03:45.15,EN,,0,0,0,,when memo-proc is executed, Dialogue: 0,1:03:45.18,1:03:47.71,EN,,0,0,0,,just this lambda expression is being generated. Dialogue: 0,1:03:48.01,1:03:49.68,EN,,0,0,0,,But it's not clear to me when it's executed. Dialogue: 0,1:03:50.39,1:03:51.12,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,1:03:51.35,1:03:52.68,EN,,0,0,0,,What memo-proc does-- remember, Dialogue: 0,1:03:53.07,1:03:55.85,EN,,0,0,0,,the thing that's going into memo-proc, the thing proc, Dialogue: 0,1:03:56.38,1:03:57.93,EN,,0,0,0,,is a procedure of no arguments. Dialogue: 0,1:03:57.93,1:03:59.05,EN,,0,0,0,,And someday, you're going to call it. Dialogue: 0,1:04:00.39,1:04:02.75,EN,,0,0,0,,Memo-proc translates that procedure Dialogue: 0,1:04:02.75,1:04:04.56,EN,,0,0,0,,into another procedure of no arguments, Dialogue: 0,1:04:04.59,1:04:05.80,EN,,0,0,0,,which someday you're going to call. Dialogue: 0,1:04:06.62,1:04:07.42,EN,,0,0,0,,That's that lambda. Dialogue: 0,1:04:09.89,1:04:14.08,EN,,0,0,0,,So here, where I initially built as my Dialogue: 0,1:04:15.85,1:04:17.92,EN,,0,0,0,,I built as my tail of the stream, Dialogue: 0,1:04:18.30,1:04:20.48,EN,,0,0,0,,say, this procedure of no arguments, Dialogue: 0,1:04:20.51,1:04:21.61,EN,,0,0,0,,which someday I'll call. Dialogue: 0,1:04:24.10,1:04:28.01,EN,,0,0,0,,Instead, I'm going to have the tail of the stream be memo-proc of it, Dialogue: 0,1:04:28.12,1:04:29.24,EN,,0,0,0,,which someday I'll call. Dialogue: 0,1:04:30.65,1:04:31.90,EN,,0,0,0,,So that lambda of nil, Dialogue: 0,1:04:32.03,1:04:36.06,EN,,0,0,0,,that gets called when you call the memo-proc, Dialogue: 0,1:04:38.97,1:04:40.96,EN,,0,0,0,,when you call the result of that memo-proc, Dialogue: 0,1:04:40.97,1:04:42.28,EN,,0,0,0,,which would be ordinarily Dialogue: 0,1:04:42.36,1:04:45.76,EN,,0,0,0,,when you would have called the original thing that you set it. Dialogue: 0,1:04:47.64,1:04:48.86,EN,,0,0,0,,AUDIENCE: OK, my ask is Dialogue: 0,1:04:48.86,1:04:50.86,EN,,0,0,0,,I had a feeling that when you call memo-proc, Dialogue: 0,1:04:50.86,1:04:52.30,EN,,0,0,0,,you just return this lambda. Dialogue: 0,1:04:52.61,1:04:53.07,EN,,0,0,0,,PROFESSOR: That's right. Dialogue: 0,1:04:53.77,1:04:58.10,EN,,0,0,0,,When you call memo-proc, you return the lambda. Dialogue: 0,1:04:58.10,1:04:59.84,EN,,0,0,0,,You never evaluate the expression at all, Dialogue: 0,1:04:59.87,1:05:02.27,EN,,0,0,0,,until the first time that you would have evaluated it. Dialogue: 0,1:05:07.76,1:05:09.10,EN,,0,0,0,,AUDIENCE: Do I understand it right Dialogue: 0,1:05:09.18,1:05:11.40,EN,,0,0,0,,you actually have to build the list up, Dialogue: 0,1:05:11.47,1:05:14.17,EN,,0,0,0,,but the elements of the list don't get evaluated? Dialogue: 0,1:05:14.24,1:05:15.63,EN,,0,0,0,,The expressions don't get evaluated? Dialogue: 0,1:05:15.63,1:05:18.54,EN,,0,0,0,,But at each stage, you actually are building a list. Dialogue: 0,1:05:18.54,1:05:20.70,EN,,0,0,0,,PROFESSOR: That's-- I really should have said this. Dialogue: 0,1:05:20.70,1:05:22.27,EN,,0,0,0,,That's a really good point. Dialogue: 0,1:05:22.27,1:05:23.18,EN,,0,0,0,,No, it's not quite right. Dialogue: 0,1:05:23.66,1:05:25.08,EN,,0,0,0,,See, cause what happens is this. Dialogue: 0,1:05:25.08,1:05:26.35,EN,,0,0,0,,Let me draw this as pairs. Dialogue: 0,1:05:26.89,1:05:28.03,EN,,0,0,0,,Suppose I'm going to make a big stream, Dialogue: 0,1:05:28.96,1:05:30.12,EN,,0,0,0,,like enumerate interval, Dialogue: 0,1:05:30.32,1:05:31.48,EN,,0,0,0,,1 through 1 billion. Dialogue: 0,1:05:32.74,1:05:35.74,EN,,0,0,0,,What that is, is a pair Dialogue: 0,1:05:39.34,1:05:43.36,EN,,0,0,0,,a 1 and a promise. Dialogue: 0,1:05:46.73,1:05:47.89,EN,,0,0,0,,That's exactly what it is. Dialogue: 0,1:05:47.89,1:05:48.76,EN,,0,0,0,,Nothing got built up. Dialogue: 0,1:05:51.60,1:05:53.29,EN,,0,0,0,,When I go and force this, Dialogue: 0,1:05:54.51,1:05:56.37,EN,,0,0,0,,and see, what happens? Dialogue: 0,1:05:56.37,1:05:59.66,EN,,0,0,0,,Well, this thing is now also recursively a CONS. Dialogue: 0,1:06:00.53,1:06:02.16,EN,,0,0,0,,So that this promise now is Dialogue: 0,1:06:04.62,1:06:08.96,EN,,0,0,0,,the next thing, which is a 2 and a promise to do more. Dialogue: 0,1:06:11.35,1:06:12.73,EN,,0,0,0,,And so on and so on and so on. Dialogue: 0,1:06:14.47,1:06:17.63,EN,,0,0,0,,So nothing gets built up until you walk down the stream. Dialogue: 0,1:06:18.20,1:06:19.58,EN,,0,0,0,,Because what's sitting here is not the list, Dialogue: 0,1:06:20.03,1:06:21.48,EN,,0,0,0,,but a promise to generate the list. Dialogue: 0,1:06:23.39,1:06:25.50,EN,,0,0,0,,And by promise, technically I mean procedure. Dialogue: 0,1:06:27.80,1:06:29.10,EN,,0,0,0,,So it doesn't get built up. Dialogue: 0,1:06:30.76,1:06:32.72,EN,,0,0,0,,Yeah, I should have said that before that. Dialogue: 0,1:06:34.28,1:06:35.34,EN,,0,0,0,,OK. That you. Let's take a break. Dialogue: 0,0:00:00.01,0:00:02.46,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N张大伟\N(DreamAndDead) Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:10.10,0:00:14.60,Declare,,0,0,0,,{\an2\fad(500,500)}流 I Dialogue: 0,0:00:18.55,0:00:21.84,Default,,0,0,0,,上次Gerry教授揭晓了秘密 Dialogue: 0,0:00:22.49,0:00:24.60,Default,,0,0,0,,他介绍了赋值的概念 Dialogue: 0,0:00:26.35,0:00:33.61,Default,,0,0,0,,赋值与状态 Dialogue: 0,0:00:37.48,0:00:40.03,Default,,0,0,0,,正如我们所见 Dialogue: 0,0:00:40.72,0:00:43.16,Default,,0,0,0,,将赋值和状态引入到语言中 Dialogue: 0,0:00:43.16,0:00:44.41,Default,,0,0,0,,后果相当糟糕 Dialogue: 0,0:00:45.08,0:00:48.62,Default,,0,0,0,,首先 代换模型不再能够描述求值过程了 Dialogue: 0,0:00:49.13,0:00:52.48,Default,,0,0,0,,为了解释程序中语句的语义 Dialogue: 0,0:00:52.48,0:00:54.27,Default,,0,0,0,,我们不得不使用更复杂的环境模型 Dialogue: 0,0:00:54.28,0:00:57.24,Default,,0,0,0,,也就是一种跟图表相关的非常机械的东西 Dialogue: 0,0:00:58.46,0:01:00.12,Default,,0,0,0,,并且 这不单纯地是一个技术上的问题 Dialogue: 0,0:01:00.26,0:01:03.28,Default,,0,0,0,,并不是因为代换模型在这里不怎么有效 Dialogue: 0,0:01:03.60,0:01:05.68,Default,,0,0,0,,所以我们得想些其它办法 Dialogue: 0,0:01:05.71,0:01:09.79,Default,,0,0,0,,而是代换模型这类机制都不再起效 Dialogue: 0,0:01:10.73,0:01:13.32,Default,,0,0,0,,这是因为突然间 一个变量 Dialogue: 0,0:01:14.12,0:01:16.92,Default,,0,0,0,,不再是代表着一个值了 Dialogue: 0,0:01:17.95,0:01:21.76,Default,,0,0,0,,现在 变量用于指明一个位置 Dialogue: 0,0:01:22.40,0:01:23.34,Default,,0,0,0,,一个存放值的位置 Dialogue: 0,0:01:23.63,0:01:26.14,Default,,0,0,0,,并且 这个位置的值可以发生改变 Dialogue: 0,0:01:30.28,0:01:34.09,Default,,0,0,0,,比如像 (F X) 这样的表达式 Dialogue: 0,0:01:37.36,0:01:39.64,Default,,0,0,0,,就可能含有副作用 Dialogue: 0,0:01:40.41,0:01:42.60,Default,,0,0,0,,如果我们执行 (F X) 得到某个值 Dialogue: 0,0:01:43.18,0:01:45.34,Default,,0,0,0,,之后我们再次执行 (F X) Dialogue: 0,0:01:47.24,0:01:48.43,Default,,0,0,0,,可能因为求值的顺序 Dialogue: 0,0:01:48.86,0:01:49.74,Default,,0,0,0,,而得到不同的值 Dialogue: 0,0:01:49.76,0:01:52.14,Default,,0,0,0,,所以突然间 我们不能仅仅关注于值 Dialogue: 0,0:01:52.52,0:01:53.60,Default,,0,0,0,,也要关注时序 Dialogue: 0,0:01:57.97,0:01:59.98,Default,,0,0,0,,序对也不仅仅 Dialogue: 0,0:02:00.65,0:02:02.52,Default,,0,0,0,,只是它的CAR和CDR部分 Dialogue: 0,0:02:02.52,0:02:05.61,Default,,0,0,0,,不是作为CAR部分和CDR部分的别称 Dialogue: 0,0:02:05.80,0:02:07.05,Default,,0,0,0,,它也有自己的“身份” Dialogue: 0,0:02:08.44,0:02:11.65,Default,,0,0,0,,序对具有“身份” Dialogue: 0,0:02:11.65,0:02:12.59,Default,,0,0,0,,它是一个对象 Dialogue: 0,0:02:21.33,0:02:25.15,Default,,0,0,0,,两个具有相同CAR和CDR部分的序对 Dialogue: 0,0:02:25.40,0:02:27.05,Default,,0,0,0,,可能相同也可能不同 Dialogue: 0,0:02:27.87,0:02:30.51,Default,,0,0,0,,因为这之中可能存在“共享” Dialogue: 0,0:02:34.96,0:02:39.45,Default,,0,0,0,,一引入赋值 这些就变成要考虑的问题了 Dialogue: 0,0:02:40.48,0:02:43.98,Default,,0,0,0,,确实 这和我们说讲代换的时候差别悬殊 Dialogue: 0,0:02:45.04,0:02:48.91,Default,,0,0,0,,技术上来看 我们思考起来更加困难了 Dialogue: 0,0:02:48.94,0:02:53.45,Default,,0,0,0,,因为我们必须相当机械地思考程序语言 Dialogue: 0,0:02:53.47,0:02:55.34,Default,,0,0,0,,而不能仅仅用数学的方式来思考 Dialogue: 0,0:02:55.71,0:02:58.60,Default,,0,0,0,,我们也会遇到哲学问题 Dialogue: 0,0:02:59.15,0:03:00.65,Default,,0,0,0,,我们会被这样的问题所困扰: Dialogue: 0,0:03:00.67,0:03:02.38,Default,,0,0,0,,事物的“改变”指的是什么? Dialogue: 0,0:03:02.38,0:03:03.77,Default,,0,0,0,,两个事物“同一”又如何判别? Dialogue: 0,0:03:03.84,0:03:06.83,Default,,0,0,0,,并且 这也会给我们编程带来困扰 Dialogue: 0,0:03:07.47,0:03:08.54,Default,,0,0,0,,正如 Sussman 教授上节课中讲的那样 Dialogue: 0,0:03:08.56,0:03:12.20,Default,,0,0,0,,错误的表达式顺序和别名会产生BUG Dialogue: 0,0:03:12.22,0:03:16.19,Default,,0,0,0,,这些问题在不需要考虑“对象”的语言中 是不存在的 Dialogue: 0,0:03:18.21,0:03:21.20,Default,,0,0,0,,我们是怎样陷入这样的困境的呢? Dialogue: 0,0:03:24.01,0:03:27.20,Default,,0,0,0,,我们这样做的原因在于 Dialogue: 0,0:03:27.40,0:03:31.47,Default,,0,0,0,,我们想要构造模块化的系统 Dialogue: 0,0:03:35.15,0:03:37.69,Default,,0,0,0,,我们想把系统划分为 Dialogue: 0,0:03:38.09,0:03:41.04,Default,,0,0,0,,数个自然组合的小块 Dialogue: 0,0:03:42.76,0:03:43.82,Default,,0,0,0,,举例来说 Dialogue: 0,0:03:44.06,0:03:46.11,Default,,0,0,0,,我们想要构造一个随机数发生器 Dialogue: 0,0:03:46.22,0:03:49.40,Default,,0,0,0,,把该发生器的内部状态封装起来 Dialogue: 0,0:03:50.25,0:03:53.71,Default,,0,0,0,,这样我们就可以把选取随机数 Dialogue: 0,0:03:54.65,0:03:57.79,Default,,0,0,0,,和用于估计的蒙特卡洛方法分离开来 Dialogue: 0,0:03:58.65,0:04:01.52,Default,,0,0,0,,进一步地把它同由 Ceraso 发明的 Dialogue: 0,0:04:01.90,0:04:05.74,Default,,0,0,0,,求取 π 的公式分离开 Dialogue: 0,0:04:06.80,0:04:07.92,Default,,0,0,0,,相似地 Dialogue: 0,0:04:09.61,0:04:11.74,Default,,0,0,0,,当我们着手构建事物的模型时 Dialogue: 0,0:04:12.35,0:04:16.01,Default,,0,0,0,,我们去构建现实世界中事物的模型 Dialogue: 0,0:04:17.31,0:04:19.42,Default,,0,0,0,,我们想把程序组织成许多自然部分 Dialogue: 0,0:04:19.44,0:04:20.52,Default,,0,0,0,,这些部分就是 Dialogue: 0,0:04:21.05,0:04:23.16,Default,,0,0,0,,现实事物的镜像 Dialogue: 0,0:04:24.90,0:04:27.56,Default,,0,0,0,,举个例子 对于一个数字电路 Dialogue: 0,0:04:28.36,0:04:29.18,Default,,0,0,0,,我们会说 Dialogue: 0,0:04:30.44,0:04:31.44,Default,,0,0,0,,这儿有一个电路 Dialogue: 0,0:04:32.08,0:04:35.16,Default,,0,0,0,,它有一个这样的元件 有一个那样的元件 Dialogue: 0,0:04:40.10,0:04:43.58,Default,,0,0,0,,这些元件都有不同的“身份” Dialogue: 0,0:04:43.58,0:04:44.59,Default,,0,0,0,,它们都有各自的状态 Dialogue: 0,0:04:45.55,0:04:47.13,Default,,0,0,0,,状态附着在电路上 Dialogue: 0,0:04:48.58,0:04:50.22,Default,,0,0,0,,我们认为这个元件是一个对象 Dialogue: 0,0:04:50.49,0:04:51.93,Default,,0,0,0,,这个元件又是另外一个不同的对象 Dialogue: 0,0:04:52.54,0:04:53.85,Default,,0,0,0,,当我们观察到系统发生了变化 Dialogue: 0,0:04:53.87,0:04:55.40,Default,,0,0,0,,信号从这里传递过来 Dialogue: 0,0:04:55.63,0:04:58.41,Default,,0,0,0,,改变了可能存放在这里的状态 并向这里继续传播 Dialogue: 0,0:04:58.67,0:05:00.75,Default,,0,0,0,,和一个存储在这里的状态交互 Dialogue: 0,0:05:01.24,0:05:02.17,Default,,0,0,0,,依此类推 Dialogue: 0,0:05:06.86,0:05:11.24,Default,,0,0,0,,我们想要在计算机中 Dialogue: 0,0:05:12.76,0:05:14.36,Default,,0,0,0,,构建模块化的系统 Dialogue: 0,0:05:14.68,0:05:17.87,Default,,0,0,0,,来反映我们对现实的看法 Dialogue: 0,0:05:17.88,0:05:19.87,Default,,0,0,0,,根据我们正在建模的实际系统 Dialogue: 0,0:05:19.88,0:05:20.91,Default,,0,0,0,,来划分子系统 Dialogue: 0,0:05:23.20,0:05:23.48,Default,,0,0,0,,然而 Dialogue: 0,0:05:25.74,0:05:28.99,Default,,0,0,0,,构建像这样的系统 Dialogue: 0,0:05:28.99,0:05:31.50,Default,,0,0,0,,看起来带来了不少技术上的麻烦 Dialogue: 0,0:05:31.52,0:05:32.75,Default,,0,0,0,,但这不是计算机造成的 Dialogue: 0,0:05:33.61,0:05:35.60,Default,,0,0,0,,或许 真正拖累我们 Dialogue: 0,0:05:36.70,0:05:38.65,Default,,0,0,0,,让我们花了那么大的功夫 Dialogue: 0,0:05:38.67,0:05:40.94,Default,,0,0,0,,才让程序反映现实世界的原因 Dialogue: 0,0:05:41.52,0:05:43.13,Default,,0,0,0,,是我们对现实世界的认识出了错 Dialogue: 0,0:05:44.55,0:05:46.75,Default,,0,0,0,,或许时间只是幻觉 Dialogue: 0,0:05:47.26,0:05:48.60,Default,,0,0,0,,什么都没有改变 Dialogue: 0,0:05:50.15,0:05:51.71,Default,,0,0,0,,就拿这个粉笔来说 Dialogue: 0,0:05:52.44,0:05:53.77,Default,,0,0,0,,我们认为它是一个对象 Dialogue: 0,0:05:54.01,0:05:54.99,Default,,0,0,0,,它有自己的状态 Dialogue: 0,0:05:55.82,0:05:59.29,Default,,0,0,0,,每时每刻 它都有一个位置和速度 Dialogue: 0,0:05:59.71,0:06:01.48,Default,,0,0,0,,如果我们做点什么 就可以改变它的状态 Dialogue: 0,0:06:04.34,0:06:07.37,Default,,0,0,0,,但是你如果了解一点相对性的概念 Dialogue: 0,0:06:07.74,0:06:09.71,Default,,0,0,0,,你可能会认为粉笔的路径 Dialogue: 0,0:06:09.72,0:06:11.34,Default,,0,0,0,,不是许多瞬时的离散点 Dialogue: 0,0:06:11.34,0:06:14.38,Default,,0,0,0,,一种深刻的见解是把整个粉笔的存在看作 Dialogue: 0,0:06:14.41,0:06:15.64,Default,,0,0,0,,时空中的路径 Dialogue: 0,0:06:16.02,0:06:17.37,Default,,0,0,0,,全部都展开了 Dialogue: 0,0:06:17.87,0:06:19.84,Default,,0,0,0,,没有单独的位置与速度 Dialogue: 0,0:06:19.84,0:06:23.80,Default,,0,0,0,,在时空中的存在是不会发生改变的 Dialogue: 0,0:06:24.64,0:06:26.51,Default,,0,0,0,,相似地 如果我们来考察这个电气系统 Dialogue: 0,0:06:27.69,0:06:30.43,Default,,0,0,0,,我们假设这个系统实现的是 Dialogue: 0,0:06:30.59,0:06:33.96,Default,,0,0,0,,某种信号处理系统 Dialogue: 0,0:06:34.36,0:06:36.68,Default,,0,0,0,,把这些元件组合在一起的工程师 Dialogue: 0,0:06:36.75,0:06:38.60,Default,,0,0,0,,也不会把它们看作 Dialogue: 0,0:06:38.96,0:06:41.40,Default,,0,0,0,,电压施加于每个独立的元件 Dialogue: 0,0:06:41.49,0:06:43.16,Default,,0,0,0,,转换成了某种东西 Dialogue: 0,0:06:43.34,0:06:45.52,Default,,0,0,0,,影响了这里的状态 Dialogue: 0,0:06:45.53,0:06:46.81,Default,,0,0,0,,还改变了那里的状态 Dialogue: 0,0:06:46.81,0:06:50.11,Default,,0,0,0,,没有一个做信号处理的会这样想 Dialogue: 0,0:06:50.42,0:06:51.84,Default,,0,0,0,,相反 你会说 Dialogue: 0,0:06:54.04,0:06:58.06,Default,,0,0,0,,这里有一个在时间上伸展的信号 Dialogue: 0,0:06:58.06,0:06:59.48,Default,,0,0,0,,如果把这个看作一个滤波器 Dialogue: 0,0:07:00.20,0:07:04.04,Default,,0,0,0,,这个滤波器会把整个信号转化成 Dialogue: 0,0:07:04.28,0:07:07.04,Default,,0,0,0,,不同的输出信号 Dialogue: 0,0:07:09.57,0:07:11.28,Default,,0,0,0,,你们不要把这些东西的状态 Dialogue: 0,0:07:11.28,0:07:13.29,Default,,0,0,0,,想象成在许多瞬间接连发生 Dialogue: 0,0:07:14.16,0:07:17.32,Default,,0,0,0,,我们把这个盒子看作一个整体 Dialogue: 0,0:07:17.32,0:07:20.16,Default,,0,0,0,,而不是在一个特定的瞬间 Dialogue: 0,0:07:20.40,0:07:21.96,Default,,0,0,0,,互相发送状态信息的小系统 Dialogue: 0,0:07:28.25,0:07:29.36,Default,,0,0,0,,今天我们将介绍 Dialogue: 0,0:07:29.39,0:07:31.13,Default,,0,0,0,,另一种分解系统的方法 Dialogue: 0,0:07:31.36,0:07:35.45,Default,,0,0,0,,站在信号工程师的角度去看待现实世界 Dialogue: 0,0:07:35.69,0:07:38.96,Default,,0,0,0,,而不再认为对象间通过消息传递来通信 Dialogue: 0,0:07:41.13,0:07:43.74,Default,,0,0,0,,它被称为“流处理” Dialogue: 0,0:07:54.57,0:07:58.96,Default,,0,0,0,,我们打算展示 Dialogue: 0,0:08:00.59,0:08:04.16,Default,,0,0,0,,如何让我们的程序变得更加统一 Dialogue: 0,0:08:05.15,0:08:06.54,Default,,0,0,0,,从中看到更多的共性 Dialogue: 0,0:08:06.65,0:08:09.88,Default,,0,0,0,,如果我们跳出这些程序 Dialogue: 0,0:08:10.81,0:08:12.30,Default,,0,0,0,,我们会发现 Dialogue: 0,0:08:12.35,0:08:15.12,Default,,0,0,0,,我们对时序的考虑过度了 Dialogue: 0,0:08:16.89,0:08:20.22,Default,,0,0,0,,我们先来对比两个过程 Dialogue: 0,0:08:23.55,0:08:25.69,Default,,0,0,0,,第一个是这样 Dialogue: 0,0:08:25.69,0:08:27.77,Default,,0,0,0,,想像这有一个树 Dialogue: 0,0:08:30.40,0:08:32.14,Default,,0,0,0,,一个由整数构成的树 Dialogue: 0,0:08:33.28,0:08:34.42,Default,,0,0,0,,一个二叉树 Dialogue: 0,0:08:36.12,0:08:36.97,Default,,0,0,0,,这里是1 Dialogue: 0,0:08:39.10,0:08:40.23,Default,,0,0,0,,看起来就像这样 Dialogue: 0,0:08:40.23,0:08:42.92,Default,,0,0,0,,在每个节点上都有一个整数 Dialogue: 0,0:08:45.18,0:08:47.80,Default,,0,0,0,,我们想计算 Dialogue: 0,0:08:48.67,0:08:51.56,Default,,0,0,0,,对这个树中所有的奇数 Dialogue: 0,0:08:52.30,0:08:55.10,Default,,0,0,0,,计算它们的平方和 Dialogue: 0,0:08:57.05,0:08:59.48,Default,,0,0,0,,我们对这类问题很熟悉 Dialogue: 0,0:08:59.48,0:09:01.95,Default,,0,0,0,,有一种递归策略求解它 Dialogue: 0,0:09:02.93,0:09:04.35,Default,,0,0,0,,观察每个叶子节点 Dialogue: 0,0:09:04.56,0:09:06.68,Default,,0,0,0,,如果是奇数我们就求它的平方 并加和 Dialogue: 0,0:09:06.70,0:09:07.77,Default,,0,0,0,,如果是偶数 就是0 Dialogue: 0,0:09:08.68,0:09:12.11,Default,,0,0,0,,递归地看 对于每一颗树 我们可以说 Dialogue: 0,0:09:12.65,0:09:13.84,Default,,0,0,0,,它的平方和等于 Dialogue: 0,0:09:13.92,0:09:15.93,Default,,0,0,0,,右子树的平方和 加上左子树的平方和 Dialogue: 0,0:09:16.25,0:09:17.64,Default,,0,0,0,,就这样沿着节点递归下去 Dialogue: 0,0:09:17.64,0:09:18.70,Default,,0,0,0,,我们已经很熟悉 Dialogue: 0,0:09:19.26,0:09:20.36,Default,,0,0,0,,这种程序设计的思考方式了 Dialogue: 0,0:09:20.36,0:09:22.59,Default,,0,0,0,,我们来幻灯片上看一下 Dialogue: 0,0:09:23.82,0:09:26.75,Default,,0,0,0,,为了计算一棵树中奇数的平方和 Dialogue: 0,0:09:27.37,0:09:29.36,Default,,0,0,0,,我们先要判断它是否是一个叶子节点 Dialogue: 0,0:09:29.82,0:09:31.95,Default,,0,0,0,,判断方法则是考察该节点是否为整数 Dialogue: 0,0:09:32.88,0:09:36.38,Default,,0,0,0,,继而判断其奇偶性 以及是否应该求取平方并加和 Dialogue: 0,0:09:37.16,0:09:38.99,Default,,0,0,0,,然后 整个的解就是 Dialogue: 0,0:09:39.21,0:09:42.12,Default,,0,0,0,,左、右子树解的总和 Dialogue: 0,0:09:46.34,0:09:50.56,Default,,0,0,0,,好的 让我们再来和下面一个问题对比一下 Dialogue: 0,0:09:51.56,0:09:53.68,Default,,0,0,0,,假如给你一个整数N Dialogue: 0,0:09:54.73,0:09:57.88,Default,,0,0,0,,再给定一个函数 把它应用在 Dialogue: 0,0:09:57.93,0:09:58.83,Default,,0,0,0,,1到N的每一个数上 Dialogue: 0,0:09:59.10,0:10:01.08,Default,,0,0,0,,我想把其中的一些值收集成一个表 Dialogue: 0,0:10:01.28,0:10:04.65,Default,,0,0,0,,那些满足某种属性的函数值 Dialogue: 0,0:10:05.60,0:10:06.88,Default,,0,0,0,,这是种一般性的说法 Dialogue: 0,0:10:06.88,0:10:07.98,Default,,0,0,0,,说得更具体一点 Dialogue: 0,0:10:08.62,0:10:10.48,Default,,0,0,0,,假设对于每个整数K Dialogue: 0,0:10:10.65,0:10:12.51,Default,,0,0,0,,计算第K个斐波那契数 Dialogue: 0,0:10:14.21,0:10:16.27,Default,,0,0,0,,然后挑出其中的奇数 Dialogue: 0,0:10:16.83,0:10:18.40,Default,,0,0,0,,并把它们组成一个表 Dialogue: 0,0:10:19.05,0:10:20.71,Default,,0,0,0,,这个过程是这样的 Dialogue: 0,0:10:23.73,0:10:26.24,Default,,0,0,0,,寻找前N个斐波那契数中的奇数 Dialogue: 0,0:10:26.24,0:10:28.91,Default,,0,0,0,,这里是我们一直以来采用的循环方法 Dialogue: 0,0:10:28.91,0:10:29.82,Default,,0,0,0,,用到了递归 Dialogue: 0,0:10:30.80,0:10:31.79,Default,,0,0,0,,以K为循环变量 Dialogue: 0,0:10:32.03,0:10:34.35,Default,,0,0,0,,如果K大于N 返回空表 Dialogue: 0,0:10:35.13,0:10:37.36,Default,,0,0,0,,否则计算第K个斐波那契数 Dialogue: 0,0:10:37.44,0:10:38.06,Default,,0,0,0,,将其与变量F绑定 Dialogue: 0,0:10:40.37,0:10:42.84,Default,,0,0,0,,如果是奇数 我们把它与 Dialogue: 0,0:10:43.76,0:10:46.01,Default,,0,0,0,,从K+1计算得到的表相连接 Dialogue: 0,0:10:47.69,0:10:50.12,Default,,0,0,0,,否则 我们只取从K+1计算得到的结果 Dialogue: 0,0:10:50.73,0:10:53.00,Default,,0,0,0,,这是迭代式循环的标准写法 Dialogue: 0,0:10:53.00,0:10:55.56,Default,,0,0,0,,我们以1为初值 启动这个循环 Dialogue: 0,0:10:57.58,0:11:00.06,Default,,0,0,0,,好的 就是这两个过程 Dialogue: 0,0:11:01.60,0:11:02.90,Default,,0,0,0,,它们看起来非常不同 Dialogue: 0,0:11:02.90,0:11:04.20,Default,,0,0,0,,完全不同的结构 Dialogue: 0,0:11:04.25,0:11:06.89,Default,,0,0,0,,然而 从一个特定的角度来看 Dialogue: 0,0:11:06.92,0:11:09.61,Default,,0,0,0,,两个过程做的事情是一样的 Dialogue: 0,0:11:11.33,0:11:14.67,Default,,0,0,0,,如果我是一个信号处理工程师 Dialogue: 0,0:11:14.70,0:11:16.81,Default,,0,0,0,,我可能会说 Dialogue: 0,0:11:18.24,0:11:26.76,Default,,0,0,0,,第一个过程枚举了树的叶节点 Dialogue: 0,0:11:31.16,0:11:34.56,Default,,0,0,0,,可以认为是信号从一个全是叶节点的地方输出 Dialogue: 0,0:11:35.33,0:11:43.39,Default,,0,0,0,,我们想要过滤出其中的奇数 Dialogue: 0,0:11:43.58,0:11:44.94,Default,,0,0,0,,把它们放入某种滤波器中 Dialogue: 0,0:11:45.19,0:11:47.79,Default,,0,0,0,,然后再把它们放入某种换能器 Dialogue: 0,0:11:49.20,0:11:51.69,Default,,0,0,0,,对每一个输出 我们对其取平方 Dialogue: 0,0:11:54.44,0:11:57.44,Default,,0,0,0,,最后把结果累积在一起 Dialogue: 0,0:11:58.29,0:12:00.04,Default,,0,0,0,,我们以0为初值 Dialogue: 0,0:12:00.35,0:12:03.37,Default,,0,0,0,,通过加法把它们累积起来 Dialogue: 0,0:12:07.14,0:12:08.21,Default,,0,0,0,,这是第一个程序 Dialogue: 0,0:12:08.21,0:12:09.18,Default,,0,0,0,,对于第二个程序 Dialogue: 0,0:12:09.24,0:12:11.21,Default,,0,0,0,,我也可以用一种非常类似的方法来描述 Dialogue: 0,0:12:11.78,0:12:13.42,Default,,0,0,0,,我们枚举 Dialogue: 0,0:12:15.80,0:12:19.10,Default,,0,0,0,,从1到N这个区间上的数 Dialogue: 0,0:12:22.50,0:12:24.40,Default,,0,0,0,,对于每个数 Dialogue: 0,0:12:25.45,0:12:26.92,Default,,0,0,0,,计算对应的斐波那契数 Dialogue: 0,0:12:27.79,0:12:29.27,Default,,0,0,0,,再放入一个换能器 Dialogue: 0,0:12:29.27,0:12:30.78,Default,,0,0,0,,对于输出的结果 Dialogue: 0,0:12:31.31,0:12:34.20,Default,,0,0,0,,再通过奇偶性进行过滤 Dialogue: 0,0:12:36.27,0:12:39.24,Default,,0,0,0,,最后 我们将这些放入累积函数 Dialogue: 0,0:12:39.35,0:12:40.56,Default,,0,0,0,,这次我们要累积出一个表 Dialogue: 0,0:12:40.78,0:12:42.17,Default,,0,0,0,,所以我们用CONS来做积累 Dialogue: 0,0:12:42.59,0:12:43.77,Default,,0,0,0,,以空表为初始值 Dialogue: 0,0:12:47.11,0:12:49.80,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:12:49.85,0:12:51.84,Default,,0,0,0,,这两个程序真的是太相似了 Dialogue: 0,0:12:51.90,0:12:52.84,Default,,0,0,0,,问题在于 Dialogue: 0,0:12:53.20,0:12:56.49,Default,,0,0,0,,两个程序的写法导致 Dialogue: 0,0:12:56.64,0:12:58.05,Default,,0,0,0,,我们看不出其中的共性 Dialogue: 0,0:12:58.05,0:13:01.44,Default,,0,0,0,,再回头来看奇数平方和的问题 Dialogue: 0,0:13:02.22,0:13:04.64,Default,,0,0,0,,问题来了 哪个是枚举函数呢? Dialogue: 0,0:13:06.35,0:13:08.14,Default,,0,0,0,,程序中哪一部分有枚举的作用? Dialogue: 0,0:13:08.14,0:13:10.52,Default,,0,0,0,,枚举不是仅仅在一个地方表现出来的 Dialogue: 0,0:13:11.02,0:13:15.47,Default,,0,0,0,,在叶子节点的判断处存在一部分 Dialogue: 0,0:13:16.43,0:13:17.16,Default,,0,0,0,,在这个判断循环终止的地方 Dialogue: 0,0:13:17.16,0:13:20.06,Default,,0,0,0,,也下面的递归结构中也有体现 Dialogue: 0,0:13:23.15,0:13:24.12,Default,,0,0,0,,累积函数又在哪儿呢? Dialogue: 0,0:13:24.12,0:13:25.68,Default,,0,0,0,,它也不只在一个地方 Dialogue: 0,0:13:25.68,0:13:30.73,Default,,0,0,0,,它在 0 和 + 这两个地方分别体现出来 Dialogue: 0,0:13:32.00,0:13:34.51,Default,,0,0,0,,累积函数分散在过程的每个部分 Dialogue: 0,0:13:34.51,0:13:39.05,Default,,0,0,0,,相似地 我们来观察奇数斐波那契数的例子 Dialogue: 0,0:13:39.05,0:13:42.80,Default,,0,0,0,,某种意义上 程序中也存在枚举函数与累积函数 Dialogue: 0,0:13:42.80,0:13:44.01,Default,,0,0,0,,但看起来非常不同 Dialogue: 0,0:13:44.62,0:13:50.09,Default,,0,0,0,,枚举部分地表现在(> k n)的判断中 Dialogue: 0,0:13:50.38,0:13:52.84,Default,,0,0,0,,部分地表现在下面的递归调用中 Dialogue: 0,0:13:53.18,0:13:54.24,Default,,0,0,0,,还有就是启动循环的地方 Dialogue: 0,0:13:55.68,0:13:56.32,Default,,0,0,0,,同样地 Dialogue: 0,0:13:56.52,0:13:58.76,Default,,0,0,0,,其中也混杂了累积函数 Dialogue: 0,0:13:58.91,0:14:00.12,Default,,0,0,0,,分别在这里 Dialogue: 0,0:14:00.41,0:14:01.40,Default,,0,0,0,,和这里 Dialogue: 0,0:14:03.60,0:14:06.08,Default,,0,0,0,,所以这些非常自然的部分 Dialogue: 0,0:14:08.73,0:14:12.65,Default,,0,0,0,,我们之前画的那些方框在程序中完全看不出来 Dialogue: 0,0:14:13.26,0:14:14.36,Default,,0,0,0,,因为它们混杂在一起了 Dialogue: 0,0:14:14.36,0:14:16.29,Default,,0,0,0,,这些程序并没有很好地对问题进行切分 Dialogue: 0,0:14:19.45,0:14:22.17,Default,,0,0,0,,回到计算机科学的基本原理上来 Dialogue: 0,0:14:22.19,0:14:23.63,Default,,0,0,0,,为了控制某种东西 Dialogue: 0,0:14:23.63,0:14:24.96,Default,,0,0,0,,你需要它的名字 Dialogue: 0,0:14:25.80,0:14:28.44,Default,,0,0,0,,我们还没有很好地掌握按这种方式来思考 Dialogue: 0,0:14:28.67,0:14:31.06,Default,,0,0,0,,这是因为我们没有显式地操作它们的手段 Dialogue: 0,0:14:31.06,0:14:33.80,Default,,0,0,0,,我们没有一门好的语言来讨论它们 Dialogue: 0,0:14:35.42,0:14:38.86,Default,,0,0,0,,好吧 我们来创造一门合适的语言 Dialogue: 0,0:14:42.52,0:14:44.04,Default,,0,0,0,,用它来构建这些器件 Dialogue: 0,0:14:44.78,0:14:47.21,Default,,0,0,0,,这种语言的关键在于 Dialogue: 0,0:14:47.21,0:14:49.71,Default,,0,0,0,,这些叫作信号的东西到底是什么? Dialogue: 0,0:14:50.48,0:14:53.32,Default,,0,0,0,,这些沿着箭头传递的是什么? Dialogue: 0,0:14:56.88,0:14:57.71,Default,,0,0,0,,这些东西 Dialogue: 0,0:14:59.85,0:15:03.52,Default,,0,0,0,,是一种称作“流”的数据结构 Dialogue: 0,0:15:03.79,0:15:05.87,Default,,0,0,0,,这也是发明这门语言的关键 Dialogue: 0,0:15:07.98,0:15:08.51,Default,,0,0,0,,“流”是什么东西呢? Dialogue: 0,0:15:08.52,0:15:11.50,Default,,0,0,0,,和其它的东西一样 “流”是一种数据抽象 Dialogue: 0,0:15:12.22,0:15:15.82,Default,,0,0,0,,所以 我先说明它的选择函数与构造函数分别是什么 Dialogue: 0,0:15:16.87,0:15:19.48,Default,,0,0,0,,对于流结构 我们有一个构造函数 Dialogue: 0,0:15:19.98,0:15:21.43,Default,,0,0,0,,我们称其为CONS-STREAM Dialogue: 0,0:15:25.69,0:15:28.11,Default,,0,0,0,,CONS-STREAM把两个事物放在一起 Dialogue: 0,0:15:28.59,0:15:30.22,Default,,0,0,0,,构造出一个流 Dialogue: 0,0:15:32.04,0:15:33.85,Default,,0,0,0,,选择函数叫作HEAD Dialogue: 0,0:15:33.98,0:15:36.11,Default,,0,0,0,,用于从流中提取数据 Dialogue: 0,0:15:38.01,0:15:38.86,Default,,0,0,0,,如果我有一个流 Dialogue: 0,0:15:39.00,0:15:40.41,Default,,0,0,0,,我可以取它的头部 Dialogue: 0,0:15:41.13,0:15:42.38,Default,,0,0,0,,也可以取它的尾部 Dialogue: 0,0:15:44.72,0:15:47.42,Default,,0,0,0,,我把和George的约定告诉你 Dialogue: 0,0:15:48.24,0:15:52.70,Default,,0,0,0,,让你们知道和这个相关的公理 Dialogue: 0,0:15:53.44,0:16:00.17,Default,,0,0,0,,对于任何的X与Y Dialogue: 0,0:16:03.40,0:16:05.44,Default,,0,0,0,,如果我把它们构造成一个流 并取其头部 Dialogue: 0,0:16:05.69,0:16:11.96,Default,,0,0,0,,(HEAD (CONS-STREAM X Y)) Dialogue: 0,0:16:13.29,0:16:14.52,Default,,0,0,0,,结果就是X Dialogue: 0,0:16:16.14,0:16:27.45,Default,,0,0,0,,(TAIL (CONS-STREAM X Y)) = Y Dialogue: 0,0:16:28.44,0:16:34.75,Default,,0,0,0,,一个构造函数 两个选择函数 一个公理 就是这些 Dialogue: 0,0:16:34.75,0:16:35.85,Default,,0,0,0,,这里有点可疑 Dialogue: 0,0:16:36.98,0:16:39.00,Default,,0,0,0,,你可能注意到了 Dialogue: 0,0:16:40.19,0:16:42.08,Default,,0,0,0,,这些就是CONS、CAR和CDR的公理 Dialogue: 0,0:16:43.63,0:16:46.56,Default,,0,0,0,,把CONS-STREAM换成CONS Dialogue: 0,0:16:47.10,0:16:49.80,Default,,0,0,0,,HEAD换成CAR TAIL换成CDR Dialogue: 0,0:16:50.76,0:16:52.81,Default,,0,0,0,,这些就是序对的公理 Dialogue: 0,0:16:52.81,0:16:54.32,Default,,0,0,0,,事实上 还有另一个东西 Dialogue: 0,0:16:55.13,0:16:56.80,Default,,0,0,0,,我们有一个叫THE-EMPTY-STREAM(空流)的东西 Dialogue: 0,0:17:02.80,0:17:04.04,Default,,0,0,0,,像空表一样 Dialogue: 0,0:17:08.31,0:17:10.03,Default,,0,0,0,,为什么我要引入这个术语呢? Dialogue: 0,0:17:10.03,0:17:12.12,Default,,0,0,0,,为什么我不继续使用序对与表呢? Dialogue: 0,0:17:12.78,0:17:13.79,Default,,0,0,0,,后面我们就知道了 Dialogue: 0,0:17:15.51,0:17:18.24,Default,,0,0,0,,暂时地 你们可以把术语“流” Dialogue: 0,0:17:18.30,0:17:21.56,Default,,0,0,0,,当作“表”的另一种说法 Dialogue: 0,0:17:21.56,0:17:22.99,Default,,0,0,0,,一会儿我们就会知道 为什么 Dialogue: 0,0:17:23.61,0:17:26.09,Default,,0,0,0,,为什么我们需要这个额外的抽象层 Dialogue: 0,0:17:26.83,0:17:28.15,Default,,0,0,0,,而不是继续把它看做表 Dialogue: 0,0:17:32.30,0:17:33.72,Default,,0,0,0,,好的 有了流之后 Dialogue: 0,0:17:33.74,0:17:35.85,Default,,0,0,0,,我们就开始构建语言的部件了 Dialogue: 0,0:17:37.04,0:17:38.17,Default,,0,0,0,,用它来操作流 Dialogue: 0,0:17:38.75,0:17:42.12,Default,,0,0,0,,我们可以构建出太多有用的东西了 Dialogue: 0,0:17:42.12,0:17:42.81,Default,,0,0,0,,举例来说 Dialogue: 0,0:17:44.89,0:17:49.79,Default,,0,0,0,,我们构建MAP-STREAM 它的一个参数是流S Dialogue: 0,0:17:54.80,0:17:56.62,Default,,0,0,0,,以及一个过程 Dialogue: 0,0:17:57.80,0:17:59.21,Default,,0,0,0,,它会生成一个新的流 Dialogue: 0,0:18:00.14,0:18:02.28,Default,,0,0,0,,它的构成元素是 Dialogue: 0,0:18:02.28,0:18:04.88,Default,,0,0,0,,将PROC应用到S的后续元素得到的结果 Dialogue: 0,0:18:05.87,0:18:07.40,Default,,0,0,0,,我们以前见过类似的 Dialogue: 0,0:18:07.40,0:18:10.24,Default,,0,0,0,,就是以前在表上定义的MAP过程 Dialogue: 0,0:18:10.95,0:18:12.60,Default,,0,0,0,,除了判断EMPTY-STREAM的部分 Dialogue: 0,0:18:12.60,0:18:14.65,Default,,0,0,0,,完全就和MAP一样 Dialogue: 0,0:18:14.65,0:18:15.56,Default,,0,0,0,,哦 我忘了说了 Dialogue: 0,0:18:15.56,0:18:17.15,Default,,0,0,0,,EMPTY-STREAM?就和NULL?差不多 Dialogue: 0,0:18:18.03,0:18:20.48,Default,,0,0,0,,如果是空的 就返回一个空的流 Dialogue: 0,0:18:20.51,0:18:22.28,Default,,0,0,0,,否则 就生成一个新的流 Dialogue: 0,0:18:23.52,0:18:27.18,Default,,0,0,0,,其第一个元素是PROC应用在流头部的结果 Dialogue: 0,0:18:28.51,0:18:29.32,Default,,0,0,0,,剩下的是 Dialogue: 0,0:18:29.60,0:18:32.43,Default,,0,0,0,,是MAP-STREAM对流尾部应用的结果 Dialogue: 0,0:18:33.14,0:18:35.90,Default,,0,0,0,,太像我们之前讲的MAP了 Dialogue: 0,0:18:37.03,0:18:38.20,Default,,0,0,0,,还有一个有用的函数 Dialogue: 0,0:18:38.35,0:18:40.46,Default,,0,0,0,,过滤函数 就是那个用来过滤的盒子 Dialogue: 0,0:18:40.46,0:18:43.89,Default,,0,0,0,,以一个谓词和一个流作为参数 Dialogue: 0,0:18:43.89,0:18:45.08,Default,,0,0,0,,它将生成一个新的流 Dialogue: 0,0:18:45.80,0:18:48.17,Default,,0,0,0,,包含了在流S中所有 Dialogue: 0,0:18:48.33,0:18:49.48,Default,,0,0,0,,满足谓词PRED的元素 Dialogue: 0,0:18:50.38,0:18:51.31,Default,,0,0,0,,这是一个“按条件分析语句” Dialogue: 0,0:18:51.32,0:18:52.73,Default,,0,0,0,,如果流是空的 Dialogue: 0,0:18:53.04,0:18:54.22,Default,,0,0,0,,就返回一个空流 Dialogue: 0,0:18:56.28,0:18:59.18,Default,,0,0,0,,这里 用谓词来判断流的头元素 Dialogue: 0,0:19:00.06,0:19:01.04,Default,,0,0,0,,如果为真 Dialogue: 0,0:19:01.53,0:19:02.83,Default,,0,0,0,,就把这个元素 Dialogue: 0,0:19:03.02,0:19:06.22,Default,,0,0,0,,和过滤流的尾元素得到的结果连接在一起 Dialogue: 0,0:19:08.22,0:19:10.04,Default,,0,0,0,,否则 如果谓词判断为假 Dialogue: 0,0:19:10.49,0:19:11.98,Default,,0,0,0,,就只返回过滤流的尾元素的结果 Dialogue: 0,0:19:13.50,0:19:14.46,Default,,0,0,0,,这就是过滤函数的原理 Dialogue: 0,0:19:16.59,0:19:18.56,Default,,0,0,0,,剩下的我快速过一遍 Dialogue: 0,0:19:18.56,0:19:20.70,Default,,0,0,0,,这些在书上都有 你们可以自己看 Dialogue: 0,0:19:20.88,0:19:21.80,Default,,0,0,0,,来马上过一遍 Dialogue: 0,0:19:22.11,0:19:22.94,Default,,0,0,0,,过程ACCUMULATE Dialogue: 0,0:19:23.26,0:19:26.92,Default,,0,0,0,,ACCUMULATE的参数有:一个组合函数 Dialogue: 0,0:19:27.36,0:19:29.05,Default,,0,0,0,,一个初始值和一个流 Dialogue: 0,0:19:29.96,0:19:31.13,Default,,0,0,0,,将它们组合在一起 Dialogue: 0,0:19:31.56,0:19:33.69,Default,,0,0,0,,如果流为空 返回初始值 Dialogue: 0,0:19:33.97,0:19:36.20,Default,,0,0,0,,否则 我们就把流头部 Dialogue: 0,0:19:36.32,0:19:37.82,Default,,0,0,0,,和流尾部做ACCUMLATE的结果 Dialogue: 0,0:19:38.01,0:19:40.24,Default,,0,0,0,,组合起来 Dialogue: 0,0:19:40.90,0:19:42.83,Default,,0,0,0,,这就是把流中元素累积在一起的方法 Dialogue: 0,0:19:42.83,0:19:43.98,Default,,0,0,0,,我会用加法来累积 Dialogue: 0,0:19:45.83,0:19:47.56,Default,,0,0,0,,如何枚举树上的叶节点呢? Dialogue: 0,0:19:48.06,0:19:52.89,Default,,0,0,0,,如果这个树只是一个叶节点 Dialogue: 0,0:19:53.79,0:19:55.90,Default,,0,0,0,,我就构造一个只含有一个叶子节点的流 Dialogue: 0,0:19:56.64,0:19:59.32,Default,,0,0,0,,否则的话 我就把 Dialogue: 0,0:19:59.61,0:20:02.35,Default,,0,0,0,,左、右子树枚举的结果合并起来 Dialogue: 0,0:20:04.34,0:20:08.32,Default,,0,0,0,,这里的APPEND-STREAM跟表上的APPEND类似 Dialogue: 0,0:20:13.19,0:20:13.85,Default,,0,0,0,,再来看这个 Dialogue: 0,0:20:13.85,0:20:17.53,Default,,0,0,0,,这跟和合并两个表的过程太相似了 Dialogue: 0,0:20:18.91,0:20:20.60,Default,,0,0,0,,如何枚举一个区间呢? Dialogue: 0,0:20:21.96,0:20:23.77,Default,,0,0,0,,它有两个参数 LOW和HIGH Dialogue: 0,0:20:23.88,0:20:27.00,Default,,0,0,0,,生成一个包含从LOW到HIGH的所有整数的流 Dialogue: 0,0:20:28.32,0:20:29.88,Default,,0,0,0,,由此 我们就可以构造一大堆的元件 Dialogue: 0,0:20:31.89,0:20:34.48,Default,,0,0,0,,这就是一门用来讨论流的小型语言 Dialogue: 0,0:20:34.49,0:20:35.32,Default,,0,0,0,,当我们有了流 Dialogue: 0,0:20:35.32,0:20:37.67,Default,,0,0,0,,就可以构建用于操作它们的过程 Dialogue: 0,0:20:37.67,0:20:39.04,Default,,0,0,0,,请注意 我们正在构建一门语言 Dialogue: 0,0:20:40.20,0:20:42.22,Default,,0,0,0,,现在 我们可以用这门语言来表达我们的想法 Dialogue: 0,0:20:43.06,0:20:47.31,Default,,0,0,0,,这个原始过程是累加树中奇数的平方的 Dialogue: 0,0:20:47.31,0:20:52.62,Default,,0,0,0,,现在你会发现 它和那些方块图如出一辙 Dialogue: 0,0:20:52.64,0:20:54.59,Default,,0,0,0,,跟我们的信号处理方块图相吻合 Dialogue: 0,0:20:54.59,0:20:57.53,Default,,0,0,0,,要计算树上奇数平方和 Dialogue: 0,0:20:58.06,0:21:00.80,Default,,0,0,0,,先枚举树上的叶子节点 Dialogue: 0,0:21:01.32,0:21:03.72,Default,,0,0,0,,过滤出奇数 Dialogue: 0,0:21:04.83,0:21:06.54,Default,,0,0,0,,再用平方来做映射 Dialogue: 0,0:21:09.32,0:21:13.34,Default,,0,0,0,,最后用加法来累积 初始值是0 Dialogue: 0,0:21:14.76,0:21:17.20,Default,,0,0,0,,这样我们就可以看到需要的片段 Dialogue: 0,0:21:17.29,0:21:19.36,Default,,0,0,0,,类似地 斐波那契数的那个问题 Dialogue: 0,0:21:20.04,0:21:21.88,Default,,0,0,0,,我们如何获得奇斐波那契数呢? Dialogue: 0,0:21:22.05,0:21:24.57,Default,,0,0,0,,从1到N枚举整数 Dialogue: 0,0:21:26.32,0:21:28.64,Default,,0,0,0,,再把FIB过程映射到上面 Dialogue: 0,0:21:28.99,0:21:30.70,Default,,0,0,0,,用来求取每项斐波那契数 Dialogue: 0,0:21:30.92,0:21:33.79,Default,,0,0,0,,过滤出奇数的部分 Dialogue: 0,0:21:34.81,0:21:36.64,Default,,0,0,0,,最后 以空表为初始值 Dialogue: 0,0:21:36.88,0:21:39.12,Default,,0,0,0,,用CONS将它们积累起来 Dialogue: 0,0:21:43.65,0:21:47.53,Default,,0,0,0,,那么 这么做有什么优势呢? Dialogue: 0,0:21:47.68,0:21:48.59,Default,,0,0,0,,首先一点 Dialogue: 0,0:21:48.68,0:21:51.15,Default,,0,0,0,,我们现在有可以用来混搭的元件了 Dialogue: 0,0:21:51.88,0:21:52.64,Default,,0,0,0,,比如说 Dialogue: 0,0:21:52.91,0:21:55.08,Default,,0,0,0,,如果我想把这里改变一下 Dialogue: 0,0:21:58.19,0:22:00.32,Default,,0,0,0,,想要计算整数的平方再进行过滤 Dialogue: 0,0:22:00.33,0:22:01.34,Default,,0,0,0,,我只需要 Dialogue: 0,0:22:01.90,0:22:03.64,Default,,0,0,0,,拿个像这里的MAP SQUARE这样的元件 Dialogue: 0,0:22:03.68,0:22:05.40,Default,,0,0,0,,放进去就行了 Dialogue: 0,0:22:06.57,0:22:07.60,Default,,0,0,0,,又或者 如果我们想 Dialogue: 0,0:22:07.69,0:22:11.45,Default,,0,0,0,,寻找树的叶节点对应的斐波那契数 Dialogue: 0,0:22:11.58,0:22:12.36,Default,,0,0,0,,而不是一个序列所对应的 Dialogue: 0,0:22:12.38,0:22:13.24,Default,,0,0,0,,我只需要 Dialogue: 0,0:22:13.40,0:22:15.93,Default,,0,0,0,,用这个枚举函数替换这个枚举函数 Dialogue: 0,0:22:18.03,0:22:19.82,Default,,0,0,0,,看到了吧 流处理的优势就是 Dialogue: 0,0:22:20.24,0:22:21.53,Default,,0,0,0,,我们建立了 -- Dialogue: 0,0:22:22.36,0:22:24.96,Default,,0,0,0,,这也是本课中的一个重要主题 -- Dialogue: 0,0:22:25.29,0:22:27.48,Default,,0,0,0,,我们建立了一个约定的接口 Dialogue: 0,0:22:32.89,0:22:37.15,Default,,0,0,0,,约定的接口可以让我们把事物粘合起来 Dialogue: 0,0:22:38.30,0:22:39.55,Default,,0,0,0,,像MAP和FILTER这样的东西 Dialogue: 0,0:22:39.79,0:22:41.64,Default,,0,0,0,,可以作为一组标准的组件 Dialogue: 0,0:22:41.68,0:22:44.76,Default,,0,0,0,,我们可以拿过来随意组合去构造程序 Dialogue: 0,0:22:45.75,0:22:48.81,Default,,0,0,0,,它让我们看到了程序的共性 Dialogue: 0,0:22:49.95,0:22:50.92,Default,,0,0,0,,虽然在这里 Dialogue: 0,0:22:51.08,0:22:53.07,Default,,0,0,0,,我只是给你们演示了两个过程而已 Dialogue: 0,0:22:53.86,0:22:55.16,Default,,0,0,0,,但是我要告诉你 Dialogue: 0,0:22:55.20,0:22:57.77,Default,,0,0,0,,像这种用MAP、FILTER和ACCUMULATE Dialogue: 0,0:22:57.80,0:23:01.00,Default,,0,0,0,,组合起来构建程序的方式是非常非常通用的 Dialogue: 0,0:23:01.41,0:23:07.28,Default,,0,0,0,,这是一种“生成-测试”的编程范式 Dialogue: 0,0:23:07.77,0:23:09.10,Default,,0,0,0,,举例来看 Dialogue: 0,0:23:09.39,0:23:12.94,Default,,0,0,0,,Richarc Waters -- MIT的一名硕士生 Dialogue: 0,0:23:12.96,0:23:15.26,Default,,0,0,0,,他的学位论文的一部分调研了 Dialogue: 0,0:23:15.80,0:23:19.21,Default,,0,0,0,,IBM的科学计算程序库的主要代码 Dialogue: 0,0:23:19.82,0:23:23.31,Default,,0,0,0,,发现其中60%的程序 Dialogue: 0,0:23:24.06,0:23:28.25,Default,,0,0,0,,都可以用这样的范式来准确的表示出来 Dialogue: 0,0:23:28.86,0:23:30.17,Default,,0,0,0,,只用MAP、FILTER和ACCUMULATE Dialogue: 0,0:23:30.57,0:23:31.50,Default,,0,0,0,,好 让我们休息一会 Dialogue: 0,0:23:36.59,0:23:37.12,Default,,0,0,0,,有问题吗? Dialogue: 0,0:23:41.18,0:23:42.89,Default,,0,0,0,,学生:整件事情的本质好像只是 Dialogue: 0,0:23:42.89,0:23:45.96,Default,,0,0,0,,因为你用了一个统一、简单的数据结构 Dialogue: 0,0:23:46.25,0:23:47.66,Default,,0,0,0,,也就是流 Dialogue: 0,0:23:48.38,0:23:48.92,Default,,0,0,0,,教授:对 Dialogue: 0,0:23:48.92,0:23:50.38,Default,,0,0,0,,本质就是 Dialogue: 0,0:23:50.40,0:23:53.07,Default,,0,0,0,,用这种约定的接口 Dialogue: 0,0:23:53.71,0:23:55.61,Default,,0,0,0,,因此你可以把许多东西组合起来 Dialogue: 0,0:23:56.01,0:23:58.78,Default,,0,0,0,,流只是 就像你说的 Dialogue: 0,0:23:58.78,0:24:00.89,Default,,0,0,0,,只是一种可以支持那样操作的统一的数据结构而已 Dialogue: 0,0:24:00.89,0:24:02.84,Default,,0,0,0,,顺便说下 这非常像APL Dialogue: 0,0:24:03.60,0:24:05.21,Default,,0,0,0,,APL有着非常相似的思想 Dialogue: 0,0:24:05.21,0:24:06.96,Default,,0,0,0,,只是在APL中使用的不是流 Dialogue: 0,0:24:07.13,0:24:08.44,Default,,0,0,0,,而是使用数组和向量 Dialogue: 0,0:24:09.56,0:24:14.48,Default,,0,0,0,,而且APL的威力就在于此 Dialogue: 0,0:24:19.91,0:24:20.91,Default,,0,0,0,,好吧 谢谢 Dialogue: 0,0:24:20.91,0:24:21.66,Default,,0,0,0,,休息一下 Dialogue: 0,0:24:21.66,0:24:30.35,Default,,0,0,0,,[音乐] Dialogue: 0,0:24:30.44,0:24:35.77,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:24:41.00,0:24:45.39,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:24:45.42,0:24:47.96,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:24:47.98,0:24:52.70,Declare,,0,0,0,,{\an2\fad(500,500)}流 I Dialogue: 0,0:24:57.47,0:24:57.61,Default,,0,0,0,,好的 Dialogue: 0,0:24:57.61,0:24:58.59,Default,,0,0,0,,我们已经见识过了 Dialogue: 0,0:25:00.54,0:25:03.20,Default,,0,0,0,,如何用流来组织计算过程 Dialogue: 0,0:25:03.85,0:25:05.47,Default,,0,0,0,,但是现在我想要给你们再演示两个 Dialogue: 0,0:25:05.93,0:25:09.12,Default,,0,0,0,,更复杂的例子 Dialogue: 0,0:25:10.84,0:25:14.12,Default,,0,0,0,,我们先来考虑一下 Dialogue: 0,0:25:14.20,0:25:16.81,Default,,0,0,0,,这样一种有用的过程 Dialogue: 0,0:25:16.81,0:25:18.09,Default,,0,0,0,,假设我有一个流 Dialogue: 0,0:25:19.96,0:25:23.15,Default,,0,0,0,,流中的元素本身就是一个流 Dialogue: 0,0:25:23.98,0:25:26.53,Default,,0,0,0,,一开始是1、2、3 Dialogue: 0,0:25:32.72,0:25:33.88,Default,,0,0,0,,就是这样的一个流 Dialogue: 0,0:25:33.88,0:25:40.10,Default,,0,0,0,,流中的元素也是一个流 Dialogue: 0,0:25:40.97,0:25:43.42,Default,,0,0,0,,而我想要构建出一个流 Dialogue: 0,0:25:43.64,0:25:46.75,Default,,0,0,0,,用来收集所有的元素 Dialogue: 0,0:25:46.76,0:25:49.24,Default,,0,0,0,,把所有元素从子流中提取出来 Dialogue: 0,0:25:50.11,0:25:51.82,Default,,0,0,0,,最后把它们串接在一起 Dialogue: 0,0:25:52.27,0:25:55.61,Default,,0,0,0,,为了凸显使用这门语言多么简单 Dialogue: 0,0:25:56.11,0:25:57.10,Default,,0,0,0,,我们来定义这个FLATTEN过程 Dialogue: 0,0:25:57.95,0:26:10.64,Default,,0,0,0,,FLATTEN过程的参数是由流构成的流 Dialogue: 0,0:26:12.89,0:26:13.80,Default,,0,0,0,,那么 具体定义是怎样的呢? Dialogue: 0,0:26:13.96,0:26:16.24,Default,,0,0,0,,它只是一个累积 Dialogue: 0,0:26:16.32,0:26:25.05,Default,,0,0,0,,我想用APPEND来做累积 Dialogue: 0,0:26:25.07,0:26:26.45,Default,,0,0,0,,也就是不断地做APPEND Dialogue: 0,0:26:26.73,0:26:29.29,Default,,0,0,0,,所以我用APPEND-STREAM做累积 Dialogue: 0,0:26:35.90,0:26:48.20,Default,,0,0,0,,以THE-EMPTY-STREAM为初始值 累积这个流 Dialogue: 0,0:26:54.84,0:26:55.84,Default,,0,0,0,,这个例子告诉我们 Dialogue: 0,0:26:56.92,0:26:59.23,Default,,0,0,0,,你可以使用这些高阶过程 Dialogue: 0,0:26:59.60,0:27:00.83,Default,,0,0,0,,来做一些有趣的运算 Dialogue: 0,0:27:00.83,0:27:05.10,Default,,0,0,0,,事实上 我还想定义另一个实用过程 Dialogue: 0,0:27:05.10,0:27:07.05,Default,,0,0,0,,定义一个过程FLAT-MAP Dialogue: 0,0:27:17.18,0:27:20.59,Default,,0,0,0,,它以一个过程和一个流为参数 Dialogue: 0,0:27:21.84,0:27:25.72,Default,,0,0,0,,其中S是一个流 Dialogue: 0,0:27:25.72,0:27:27.69,Default,,0,0,0,,F是一个过程 Dialogue: 0,0:27:27.72,0:27:30.62,Default,,0,0,0,,它作用于流中的每个元素 并产生一个新的流 Dialogue: 0,0:27:31.95,0:27:34.52,Default,,0,0,0,,我想从这些流中取出所有的元素 Dialogue: 0,0:27:35.00,0:27:36.00,Default,,0,0,0,,并把它们组合在一起 Dialogue: 0,0:27:36.00,0:27:49.13,Default,,0,0,0,,所以对应的代码就是 (FLATTEN (MAP F S)) Dialogue: 0,0:27:51.20,0:27:53.04,Default,,0,0,0,,每当我将F应用在S的某个元素上 Dialogue: 0,0:27:53.05,0:27:53.85,Default,,0,0,0,,我得到了一个流 Dialogue: 0,0:27:54.29,0:27:55.24,Default,,0,0,0,,执行完这条MAP语句后 Dialogue: 0,0:27:55.24,0:27:56.27,Default,,0,0,0,,我得到了一个由流构成的流 Dialogue: 0,0:27:56.46,0:27:57.42,Default,,0,0,0,,再把它进行FLATTEN Dialogue: 0,0:27:58.67,0:28:02.64,Default,,0,0,0,,我想再使用这种方式 Dialogue: 0,0:28:03.87,0:28:05.84,Default,,0,0,0,,来解决另一个大家很熟悉的问题 Dialogue: 0,0:28:06.51,0:28:12.27,Default,,0,0,0,,这个问题和我们以前遇到过的许多问题一样 Dialogue: 0,0:28:12.28,0:28:13.96,Default,,0,0,0,,只是有些变型 Dialogue: 0,0:28:14.19,0:28:15.49,Default,,0,0,0,,给定整数N Dialogue: 0,0:28:18.68,0:28:19.93,Default,,0,0,0,,我们的问题是 Dialogue: 0,0:28:21.20,0:28:31.53,Default,,0,0,0,,找出所有的整数序对(I, J) Dialogue: 0,0:28:32.30,0:28:39.96,Default,,0,0,0,,其中 0 < J < I <= N Dialogue: 0,0:28:42.33,0:28:52.03,Default,,0,0,0,,使得 I+J 是一个质数 Dialogue: 0,0:28:55.74,0:28:57.92,Default,,0,0,0,,如果N=6 Dialogue: 0,0:28:59.74,0:29:00.78,Default,,0,0,0,,我在这儿画个小表格 Dialogue: 0,0:29:01.55,0:29:06.67,Default,,0,0,0,,表头是I、J和I+J Dialogue: 0,0:29:09.70,0:29:14.91,Default,,0,0,0,,比如说I=2 J=1 那么I+J就是3 Dialogue: 0,0:29:15.52,0:29:20.38,Default,,0,0,0,,然后I=3 J=2 那么I+J就是5 Dialogue: 0,0:29:21.21,0:29:26.51,Default,,0,0,0,,I=4 J=1 I+J=5也是一样的 等等 Dialogue: 0,0:29:26.92,0:29:28.11,Default,,0,0,0,,直到I到了6就终止了 Dialogue: 0,0:29:28.40,0:29:32.54,Default,,0,0,0,,我想要这个过程产生并返回这样的一个流 Dialogue: 0,0:29:33.20,0:29:37.04,Default,,0,0,0,,就是像 (I, J, I+J) 这样的三元组组成的流 Dialogue: 0,0:29:37.66,0:29:39.55,Default,,0,0,0,,对于每个整数N 我想得到一个这样流 Dialogue: 0,0:29:40.97,0:29:43.68,Default,,0,0,0,,听起来很简单 Dialogue: 0,0:29:43.68,0:29:44.35,Default,,0,0,0,,我们做做看 Dialogue: 0,0:29:47.23,0:29:48.22,Default,,0,0,0,,先这样开始 Dialogue: 0,0:29:50.15,0:29:54.25,Default,,0,0,0,,对于每一个整数 I Dialogue: 0,0:29:55.24,0:29:56.44,Default,,0,0,0,,生成一个流 Dialogue: 0,0:29:57.00,0:29:58.59,Default,,0,0,0,,对于I从1取到N Dialogue: 0,0:29:58.59,0:29:59.76,Default,,0,0,0,,每个I都生成一个流 Dialogue: 0,0:30:00.66,0:30:01.80,Default,,0,0,0,,这个流将会是什么样子? Dialogue: 0,0:30:02.23,0:30:04.04,Default,,0,0,0,,我们先生成所有的序对 Dialogue: 0,0:30:04.18,0:30:07.55,Default,,0,0,0,,对于每个I 我们先生成 Dialogue: 0,0:30:08.43,0:30:14.52,Default,,0,0,0,,对于每个从1取到I-1的J Dialogue: 0,0:30:16.91,0:30:17.98,Default,,0,0,0,,我们先生成序对 Dialogue: 0,0:30:18.35,0:30:20.71,Default,,0,0,0,,也就是只含有I和J的表 Dialogue: 0,0:30:23.78,0:30:27.10,Default,,0,0,0,,因此我们对整个区间做映射 Dialogue: 0,0:30:28.60,0:30:29.74,Default,,0,0,0,,生成序对 Dialogue: 0,0:30:31.07,0:30:33.17,Default,,0,0,0,,对于每个I 都生成一个序对流 Dialogue: 0,0:30:33.40,0:30:34.49,Default,,0,0,0,,最后进行FLATMAP Dialogue: 0,0:30:34.59,0:30:36.20,Default,,0,0,0,,这样我们就生成了所有的(I, J)序对 Dialogue: 0,0:30:36.81,0:30:38.08,Default,,0,0,0,,其中I <= J Dialogue: 0,0:30:38.73,0:30:39.85,Default,,0,0,0,,就是这样 Dialogue: 0,0:30:39.85,0:30:40.76,Default,,0,0,0,,紧接着就是过滤 Dialogue: 0,0:30:42.99,0:30:45.84,Default,,0,0,0,,我们对刚才FLATMAP得到的东西 Dialogue: 0,0:30:46.94,0:30:51.37,Default,,0,0,0,,我们以I -- 这里分别是 I 和 J Dialogue: 0,0:30:51.66,0:30:54.17,Default,,0,0,0,,I是表的第一个元素 Dialogue: 0,0:30:54.30,0:30:55.60,Default,,0,0,0,,J是第二个 Dialogue: 0,0:30:57.21,0:31:00.01,Default,,0,0,0,,我们用一个谓词来判断 表中的两个元素 Dialogue: 0,0:31:00.22,0:31:02.00,Default,,0,0,0,,也就是表的CAR部分与CDR部分之和 是否为质数 Dialogue: 0,0:31:02.07,0:31:05.52,Default,,0,0,0,,用这个谓词来过滤刚刚收集起来的表 Dialogue: 0,0:31:06.54,0:31:07.85,Default,,0,0,0,,就得到了我们想要的表 Dialogue: 0,0:31:09.42,0:31:10.24,Default,,0,0,0,,然后我们继续 Dialogue: 0,0:31:10.88,0:31:13.10,Default,,0,0,0,,把过滤得到的结果 再次进行MAP操作 Dialogue: 0,0:31:13.26,0:31:19.05,Default,,0,0,0,,用来生成 I、J 和 I+J 构成的表 Dialogue: 0,0:31:19.61,0:31:21.39,Default,,0,0,0,,这就是过程 PRIME-SUM-PAIRS Dialogue: 0,0:31:22.57,0:31:24.76,Default,,0,0,0,,最后只需要过一遍 这就是整个过程 Dialogue: 0,0:31:28.08,0:31:30.97,Default,,0,0,0,,一个MAP、一个FILTER 以及一个FLATMAP Dialogue: 0,0:31:34.85,0:31:35.66,Default,,0,0,0,,所有的东西都在这里了 Dialogue: 0,0:31:35.66,0:31:37.12,Default,,0,0,0,,尽管可读性不是那么好 Dialogue: 0,0:31:37.42,0:31:38.94,Default,,0,0,0,,我们只是把中间过程展开了 Dialogue: 0,0:31:39.84,0:31:40.88,Default,,0,0,0,,这个例子 Dialogue: 0,0:31:43.28,0:31:45.00,Default,,0,0,0,,向我们展示了 Dialogue: 0,0:31:45.12,0:31:46.30,Default,,0,0,0,,嵌套循环 Dialogue: 0,0:31:47.66,0:31:50.09,Default,,0,0,0,,在这个过程中 它看起来就像 Dialogue: 0,0:31:50.11,0:31:52.81,Default,,0,0,0,,各种嵌套的MAP和FLATMAP的组合 Dialogue: 0,0:31:54.27,0:31:57.61,Default,,0,0,0,,所以我们不仅仅可以枚举单个个体 Dialogue: 0,0:31:57.61,0:31:58.81,Default,,0,0,0,,通过使用FLATMAP Dialogue: 0,0:31:59.12,0:32:02.24,Default,,0,0,0,,我们可以实现其它语言中的嵌套循环 Dialogue: 0,0:32:03.23,0:32:03.76,Default,,0,0,0,,当然 Dialogue: 0,0:32:04.91,0:32:08.03,Default,,0,0,0,,重复写这些FLATMAP很烦人 Dialogue: 0,0:32:08.41,0:32:13.00,Default,,0,0,0,,尽管PRIME-SUM-PAIRS其中单独的部分很容易 Dialogue: 0,0:32:13.56,0:32:15.28,Default,,0,0,0,,但整体看起来还是十分复杂 Dialogue: 0,0:32:15.48,0:32:17.13,Default,,0,0,0,,如果你愿意的话 可以 Dialogue: 0,0:32:17.15,0:32:20.12,Default,,0,0,0,,引进一个叫COLLECT的语法糖衣 Dialogue: 0,0:32:21.04,0:32:22.68,Default,,0,0,0,,COLLECT只是一个缩写 Dialogue: 0,0:32:22.91,0:32:26.16,Default,,0,0,0,,用来代表特定顺序的FLATMAP和FILTER操作 Dialogue: 0,0:32:26.16,0:32:28.60,Default,,0,0,0,,这里我们用COLLECT把PRIME-SUM-PAIRS写一遍 Dialogue: 0,0:32:29.45,0:32:36.27,Default,,0,0,0,,PRIME-SUM-PAIRS过程需要收集这样一个东西 Dialogue: 0,0:32:36.52,0:32:39.20,Default,,0,0,0,,它的元素是形如(I, J, I+J)这样的表 Dialogue: 0,0:32:40.84,0:32:45.39,Default,,0,0,0,,而这将通过I从1取到N Dialogue: 0,0:32:47.44,0:32:52.32,Default,,0,0,0,,同时J要从1取到I-1来产生 Dialogue: 0,0:32:54.16,0:32:56.54,Default,,0,0,0,,并且要满足I+J是质数 Dialogue: 0,0:32:58.04,0:33:00.32,Default,,0,0,0,,课堂上我就不讲解如何定义COLLECT了 Dialogue: 0,0:33:00.69,0:33:02.75,Default,,0,0,0,,书上面有 Dialogue: 0,0:33:03.42,0:33:05.45,Default,,0,0,0,,不过你可以清楚地看到 这些代码片段 Dialogue: 0,0:33:05.84,0:33:08.60,Default,,0,0,0,,就是我原先写的过程中的片段 Dialogue: 0,0:33:08.82,0:33:11.40,Default,,0,0,0,,COLLECT过程只是一个语法糖衣 Dialogue: 0,0:33:11.44,0:33:14.80,Default,,0,0,0,,用来自动生成嵌套FLATMAP Dialogue: 0,0:33:16.31,0:33:20.33,Default,,0,0,0,,好的 我们再来看另一个例子 Dialogue: 0,0:33:20.67,0:33:22.00,Default,,0,0,0,,也展示了同样的道理 Dialogue: 0,0:33:22.12,0:33:23.53,Default,,0,0,0,,这是一个非常著名的问题 Dialogue: 0,0:33:24.70,0:33:28.75,Default,,0,0,0,,经常用来演示所谓的“回溯”算法 Dialogue: 0,0:33:28.76,0:33:30.20,Default,,0,0,0,,这就是“八皇后问题” Dialogue: 0,0:33:30.20,0:33:31.08,Default,,0,0,0,,这是一个棋盘 Dialogue: 0,0:33:32.37,0:33:33.64,Default,,0,0,0,,八皇后问题要求我们 Dialogue: 0,0:33:33.64,0:33:35.85,Default,,0,0,0,,找到一种将八个皇后放到棋盘上的摆法 Dialogue: 0,0:33:36.44,0:33:38.00,Default,,0,0,0,,使得任意的两个皇后不会相互攻击 Dialogue: 0,0:33:38.00,0:33:40.60,Default,,0,0,0,,这里给出了一个解法 Dialogue: 0,0:33:41.21,0:33:43.68,Default,,0,0,0,,我需要保证摆放好后 Dialogue: 0,0:33:43.71,0:33:46.80,Default,,0,0,0,,任意两个皇后不在同一行或同一列上 Dialogue: 0,0:33:47.72,0:33:49.47,Default,,0,0,0,,也不在同一对角线上 Dialogue: 0,0:33:51.41,0:33:56.40,Default,,0,0,0,,有一个解决这个问题的标准解法 Dialogue: 0,0:33:59.74,0:34:01.48,Default,,0,0,0,,首先我们要做是 Dialogue: 0,0:34:02.54,0:34:04.62,Default,,0,0,0,,进入底层 站在George的层面 Dialogue: 0,0:34:04.94,0:34:08.09,Default,,0,0,0,,找到一种表示棋盘与位置的方式 Dialogue: 0,0:34:08.09,0:34:09.52,Default,,0,0,0,,这个并不需要太担心 Dialogue: 0,0:34:09.80,0:34:12.78,Default,,0,0,0,,假设我们有一个谓词SAFE? Dialogue: 0,0:34:16.14,0:34:17.55,Default,,0,0,0,,SAFE?判断的是 Dialogue: 0,0:34:17.96,0:34:20.84,Default,,0,0,0,,假如一些皇后已经放在棋盘上 Dialogue: 0,0:34:21.36,0:34:24.54,Default,,0,0,0,,在这个点再放置一个皇后是否是安全? Dialogue: 0,0:34:25.40,0:34:31.26,Default,,0,0,0,,所以SAFE?的参数分别为ROW和COLUMN Dialogue: 0,0:34:32.76,0:34:35.47,Default,,0,0,0,,我将尝试把下一个皇后放在那个地方 Dialogue: 0,0:34:36.06,0:34:42.76,Default,,0,0,0,,另外一个参数是剩下的位置 Dialogue: 0,0:34:45.58,0:34:46.75,Default,,0,0,0,,SAFE?要判断的是 Dialogue: 0,0:34:46.86,0:34:51.68,Default,,0,0,0,,在这些位置已经放置了皇后的情况下 Dialogue: 0,0:34:53.02,0:34:54.76,Default,,0,0,0,,在这行这列放置皇后 Dialogue: 0,0:34:55.10,0:34:57.20,Default,,0,0,0,,是否安全 Dialogue: 0,0:34:58.30,0:34:59.36,Default,,0,0,0,,不用过分深究这个 Dialogue: 0,0:34:59.36,0:35:01.38,Default,,0,0,0,,那是George的问题 也不难写出来 Dialogue: 0,0:35:01.38,0:35:06.27,Default,,0,0,0,,只需要检测该行、该列 Dialogue: 0,0:35:06.30,0:35:08.52,Default,,0,0,0,,以及对角线上是否有东西即可 Dialogue: 0,0:35:10.53,0:35:13.12,Default,,0,0,0,,那么 有了这个过程后 我们的程序该如何组织呢? Dialogue: 0,0:35:13.84,0:35:17.21,Default,,0,0,0,,有一种传统的方式 Dialogue: 0,0:35:17.93,0:35:18.97,Default,,0,0,0,,我们称为“回溯” Dialogue: 0,0:35:20.52,0:35:23.21,Default,,0,0,0,,首先让我们来考虑 Dialogue: 0,0:35:25.13,0:35:28.88,Default,,0,0,0,,把第一个皇后放在第一列的 Dialogue: 0,0:35:30.04,0:35:31.34,Default,,0,0,0,,所有方式 Dialogue: 0,0:35:31.45,0:35:32.24,Default,,0,0,0,,有8种 Dialogue: 0,0:35:32.58,0:35:35.00,Default,,0,0,0,,先试下第一列 Dialogue: 0,0:35:35.88,0:35:37.30,Default,,0,0,0,,第一行第一列 Dialogue: 0,0:35:37.30,0:35:38.70,Default,,0,0,0,,每个分支都代表了 Dialogue: 0,0:35:40.17,0:35:41.88,Default,,0,0,0,,在每一个层次的可能解 Dialogue: 0,0:35:43.36,0:35:45.53,Default,,0,0,0,,我试着把皇后放在第一列 Dialogue: 0,0:35:46.14,0:35:47.74,Default,,0,0,0,,现在 我在第一列放置好一个皇后以后 Dialogue: 0,0:35:47.77,0:35:49.98,Default,,0,0,0,,我又尝试在第一列放置下一个皇后 Dialogue: 0,0:35:50.60,0:35:52.17,Default,,0,0,0,,并不成功 它们都…… Dialogue: 0,0:35:53.31,0:35:54.60,Default,,0,0,0,,我尝试把第一个皇后 Dialogue: 0,0:35:54.86,0:35:56.80,Default,,0,0,0,,把在第一列上的那个皇后 放在第一行 Dialogue: 0,0:35:56.92,0:35:57.47,Default,,0,0,0,,不好意思 Dialogue: 0,0:35:59.05,0:36:01.39,Default,,0,0,0,,放好后 我们再把下一个皇后放在第一行 Dialogue: 0,0:36:01.39,0:36:02.09,Default,,0,0,0,,这不行 Dialogue: 0,0:36:02.09,0:36:03.18,Default,,0,0,0,,所以又回到这里 Dialogue: 0,0:36:04.20,0:36:04.72,Default,,0,0,0,,然后再考虑 Dialogue: 0,0:36:04.83,0:36:06.86,Default,,0,0,0,,我们把这个皇后放在第二行吗? Dialogue: 0,0:36:07.32,0:36:08.38,Default,,0,0,0,,然而也不行 Dialogue: 0,0:36:08.55,0:36:09.76,Default,,0,0,0,,那么放在第三行呢? Dialogue: 0,0:36:09.76,0:36:10.52,Default,,0,0,0,,这样可以 Dialogue: 0,0:36:12.79,0:36:15.13,Default,,0,0,0,,下一个皇后可以放在第一列吗? Dialogue: 0,0:36:15.38,0:36:17.82,Default,,0,0,0,,我不能再画更多的棋盘了 Dialogue: 0,0:36:17.82,0:36:18.86,Default,,0,0,0,,但我先假设这个可行 Dialogue: 0,0:36:19.19,0:36:20.45,Default,,0,0,0,,我尝试下一个 Dialogue: 0,0:36:20.45,0:36:24.17,Default,,0,0,0,,在每一个地方 尽可能的沿着树往下 Dialogue: 0,0:36:24.54,0:36:25.64,Default,,0,0,0,,然后回退 Dialogue: 0,0:36:25.64,0:36:28.97,Default,,0,0,0,,如果我从这里往下走 发现下面不可能有解 Dialogue: 0,0:36:29.00,0:36:30.12,Default,,0,0,0,,我就回溯到这里来 Dialogue: 0,0:36:30.28,0:36:32.44,Default,,0,0,0,,然后开始生成这个子树 Dialogue: 0,0:36:33.26,0:36:34.32,Default,,0,0,0,,我就像这样遍历 Dialogue: 0,0:36:35.05,0:36:37.26,Default,,0,0,0,,最后 一路求解下来 Dialogue: 0,0:36:37.72,0:36:38.59,Default,,0,0,0,,就会得到答案 Dialogue: 0,0:36:39.82,0:36:41.98,Default,,0,0,0,,这种典型的范式 Dialogue: 0,0:36:43.12,0:36:45.93,Default,,0,0,0,,之前被广泛地使用在人工智能编程中 Dialogue: 0,0:36:45.93,0:36:47.30,Default,,0,0,0,,术语叫做 “回溯搜索” Dialogue: 0,0:36:57.47,0:37:03.04,Default,,0,0,0,,这真的没有必要 Dialogue: 0,0:37:03.86,0:37:06.55,Default,,0,0,0,,你们也发现了 我在可视化这个过程时也犯了迷糊 Dialogue: 0,0:37:06.81,0:37:08.25,Default,,0,0,0,,你们也看到了复杂程度 Dialogue: 0,0:37:08.55,0:37:10.76,Default,,0,0,0,,而且这种复杂还很难描述 Dialogue: 0,0:37:10.76,0:37:11.82,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:37:12.39,0:37:13.29,Default,,0,0,0,,这是因为 Dialogue: 0,0:37:13.53,0:37:17.39,Default,,0,0,0,,这是因为这程序过分地关注于时间了 Dialogue: 0,0:37:18.58,0:37:20.43,Default,,0,0,0,,这之中太多 -- 先试试这个 再试试这个 Dialogue: 0,0:37:20.49,0:37:22.38,Default,,0,0,0,,再回到上一个可行的地方 -- 这种操作太多了 Dialogue: 0,0:37:22.89,0:37:24.34,Default,,0,0,0,,这很复杂 Dialogue: 0,0:37:24.34,0:37:26.36,Default,,0,0,0,,如果我们不再如此关注时间 Dialogue: 0,0:37:28.04,0:37:29.76,Default,,0,0,0,,就有一个更简单的方式来描述 Dialogue: 0,0:37:31.20,0:37:32.36,Default,,0,0,0,,让我们来想象一下 Dialogue: 0,0:37:33.31,0:37:36.57,Default,,0,0,0,,现在我有 Dialogue: 0,0:37:38.32,0:37:42.16,Default,,0,0,0,,有一个高达K-1层的树 Dialogue: 0,0:37:43.40,0:37:46.32,Default,,0,0,0,,假设我已经有了 Dialogue: 0,0:37:48.09,0:37:52.19,Default,,0,0,0,,把皇后放在前K列的所有解法 Dialogue: 0,0:37:53.56,0:37:54.61,Default,,0,0,0,,假设是这样 Dialogue: 0,0:37:54.61,0:37:55.79,Default,,0,0,0,,不要担心我是怎么得到的 Dialogue: 0,0:37:57.07,0:37:59.20,Default,,0,0,0,,现在 如何扩充下去呢? Dialogue: 0,0:37:59.20,0:38:02.16,Default,,0,0,0,,怎样找到在下一列中放皇后的所有可行方法? Dialogue: 0,0:38:02.48,0:38:03.13,Default,,0,0,0,,很简单 Dialogue: 0,0:38:03.62,0:38:06.41,Default,,0,0,0,,对于已有的位置 Dialogue: 0,0:38:07.82,0:38:13.96,Default,,0,0,0,,我考虑把下一个皇后放在每一行上 Dialogue: 0,0:38:15.08,0:38:16.16,Default,,0,0,0,,来构建出下一步的棋局 Dialogue: 0,0:38:16.16,0:38:17.29,Default,,0,0,0,,然后 把所有放置的位置 Dialogue: 0,0:38:17.44,0:38:19.71,Default,,0,0,0,,用SAFE?进行过滤 Dialogue: 0,0:38:21.80,0:38:22.99,Default,,0,0,0,,不像之前那样 Dialogue: 0,0:38:22.99,0:38:24.67,Default,,0,0,0,,把这个树看做是逐步生成的 Dialogue: 0,0:38:24.94,0:38:26.86,Default,,0,0,0,,我们假设所有的东西都生成好了 Dialogue: 0,0:38:29.68,0:38:32.41,Default,,0,0,0,,为了从K-1层扩展到K层 Dialogue: 0,0:38:32.64,0:38:36.24,Default,,0,0,0,,我只需要扩展所有可能的放置方法 Dialogue: 0,0:38:36.48,0:38:37.80,Default,,0,0,0,,最后保留安全的排列 Dialogue: 0,0:38:37.80,0:38:39.23,Default,,0,0,0,,就得到一个K层树的结果 Dialogue: 0,0:38:39.30,0:38:40.67,Default,,0,0,0,,这是解决八皇后问题 Dialogue: 0,0:38:40.89,0:38:42.17,Default,,0,0,0,,的一个递归策略 Dialogue: 0,0:38:44.53,0:38:45.34,Default,,0,0,0,,好的 我们来看看 Dialogue: 0,0:38:50.33,0:38:52.68,Default,,0,0,0,,我们编写子过程FILL-COLS Dialogue: 0,0:38:53.00,0:38:55.53,Default,,0,0,0,,来解决在一个特定大小棋盘上的 Dialogue: 0,0:38:58.92,0:39:01.03,Default,,0,0,0,,八皇后问题 Dialogue: 0,0:39:01.13,0:39:04.86,Default,,0,0,0,,这个过程会把皇后放置到K个列中 Dialogue: 0,0:39:06.35,0:39:07.70,Default,,0,0,0,,这是递归的模式 Dialogue: 0,0:39:07.70,0:39:10.92,Default,,0,0,0,,最后会以棋盘的大小为参数 调用FILL-COLS Dialogue: 0,0:39:12.99,0:39:15.28,Default,,0,0,0,,FILL-COLS是用来说明 Dialogue: 0,0:39:15.29,0:39:17.16,Default,,0,0,0,,如何安全地把皇后放置在 Dialogue: 0,0:39:17.20,0:39:19.58,Default,,0,0,0,,具有SIZE行的棋盘的前K列 Dialogue: 0,0:39:20.36,0:39:21.64,Default,,0,0,0,,如果K是0 Dialogue: 0,0:39:22.27,0:39:23.60,Default,,0,0,0,,就不用做什么 Dialogue: 0,0:39:23.94,0:39:25.93,Default,,0,0,0,,结果是一个空棋盘 Dialogue: 0,0:39:26.71,0:39:28.07,Default,,0,0,0,,否则就做点别的 Dialogue: 0,0:39:28.35,0:39:29.44,Default,,0,0,0,,这里将要使用COLLECT Dialogue: 0,0:39:30.81,0:39:31.77,Default,,0,0,0,,完整的代码在这里 Dialogue: 0,0:39:34.33,0:39:41.91,Default,,0,0,0,,我找到了所有在前K-1列中放皇后的方法 Dialogue: 0,0:39:42.19,0:39:43.32,Default,,0,0,0,,这是我所假设的 Dialogue: 0,0:39:43.32,0:39:46.36,Default,,0,0,0,,想像这棵树下降到K-1层 Dialogue: 0,0:39:48.88,0:39:52.11,Default,,0,0,0,,然后我尝试每一行 Dialogue: 0,0:39:52.52,0:39:54.13,Default,,0,0,0,,尝试每一个可行的行 Dialogue: 0,0:39:54.13,0:39:55.04,Default,,0,0,0,,总共SIZE行 Dialogue: 0,0:39:55.31,0:39:56.49,Default,,0,0,0,,这里枚举了所有行数 Dialogue: 0,0:39:58.04,0:39:59.79,Default,,0,0,0,,现在要做的是 Dialogue: 0,0:40:03.15,0:40:05.82,Default,,0,0,0,,把我将要尝试的新行和第K列 Dialogue: 0,0:40:07.95,0:40:08.95,Default,,0,0,0,,收集起来 Dialogue: 0,0:40:08.95,0:40:10.09,Default,,0,0,0,,我邻接一个位置 Dialogue: 0,0:40:10.20,0:40:11.29,Default,,0,0,0,,这是George的问题了 Dialogue: 0,0:40:11.29,0:40:12.75,Default,,0,0,0,,实现ADJOIN-POSITION和SAFE?都是George的工作 Dialogue: 0,0:40:13.64,0:40:15.28,Default,,0,0,0,,这个过程需要的参数有 Dialogue: 0,0:40:15.50,0:40:17.04,Default,,0,0,0,,ROW、COL以及REST-OF-POS Dialogue: 0,0:40:17.07,0:40:19.02,Default,,0,0,0,,然后返回位置的集合 Dialogue: 0,0:40:19.66,0:40:25.77,Default,,0,0,0,,我把新的行和列 Dialogue: 0,0:40:26.06,0:40:27.68,Default,,0,0,0,,和剩下的皇后邻接起来 Dialogue: 0,0:40:28.57,0:40:29.76,Default,,0,0,0,,那些剩下的皇后 Dialogue: 0,0:40:29.92,0:40:31.45,Default,,0,0,0,,会尝试所有的 Dialogue: 0,0:40:31.87,0:40:34.16,Default,,0,0,0,,放置在K-1列中的可行解 Dialogue: 0,0:40:34.62,0:40:37.04,Default,,0,0,0,,新的行遍历了所有的可能性 Dialogue: 0,0:40:37.85,0:40:40.76,Default,,0,0,0,,过滤出安全的位置 Dialogue: 0,0:40:43.24,0:40:44.70,Default,,0,0,0,,这就是整个程序了 Dialogue: 0,0:40:46.33,0:40:47.31,Default,,0,0,0,,整个过程 Dialogue: 0,0:40:49.84,0:40:52.43,Default,,0,0,0,,它不仅找到了八皇后的问题的解 Dialogue: 0,0:40:53.42,0:40:56.68,Default,,0,0,0,,它还给出了所有的解 Dialogue: 0,0:40:56.68,0:40:58.48,Default,,0,0,0,,运行结束之后 就得到一个流 Dialogue: 0,0:40:58.48,0:41:01.90,Default,,0,0,0,,流中的元素是所有的解 Dialogue: 0,0:41:05.31,0:41:06.26,Default,,0,0,0,,为什么这个更简单一点呢? Dialogue: 0,0:41:06.26,0:41:08.54,Default,,0,0,0,,我们完全没有把这个当做 Dialogue: 0,0:41:08.88,0:41:11.52,Default,,0,0,0,,按时间发生的、具有状态的过程 Dialogue: 0,0:41:12.72,0:41:14.42,Default,,0,0,0,,我们只说 这是一些东西的集合 Dialogue: 0,0:41:14.94,0:41:16.00,Default,,0,0,0,,这是它更加简单的原因 Dialogue: 0,0:41:18.00,0:41:20.11,Default,,0,0,0,,我们已经转变了观念 Dialogue: 0,0:41:20.11,0:41:22.59,Default,,0,0,0,,还记得吗 这节课开始我们就讲过 Dialogue: 0,0:41:22.82,0:41:26.23,Default,,0,0,0,,我们转变了建模的观念 Dialogue: 0,0:41:26.23,0:41:29.20,Default,,0,0,0,,我们不再把事物看做按时间演进 Dialogue: 0,0:41:29.37,0:41:31.31,Default,,0,0,0,,也不再具有不同的阶段与状态 Dialogue: 0,0:41:31.75,0:41:33.79,Default,,0,0,0,,取而代之的是 我们对全局进行建模 Dialogue: 0,0:41:33.80,0:41:35.93,Default,,0,0,0,,我们关注粉笔的整个飞行过程 Dialogue: 0,0:41:36.28,0:41:38.88,Default,,0,0,0,,而不是专注于每个瞬时状态 Dialogue: 0,0:41:40.75,0:41:41.44,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:41:44.08,0:41:46.20,Default,,0,0,0,,学生:在我看来回溯会 Dialogue: 0,0:41:46.22,0:41:48.96,Default,,0,0,0,,搜索到它所能找到的第一个解 Dialogue: 0,0:41:49.31,0:41:51.48,Default,,0,0,0,,而这个递归搜索 Dialogue: 0,0:41:51.48,0:41:53.26,Default,,0,0,0,,会去寻找所有的解 Dialogue: 0,0:41:53.32,0:41:53.60,Default,,0,0,0,,教授:是这样的 Dialogue: 0,0:41:54.03,0:41:55.26,Default,,0,0,0,,学生:但问题是 Dialogue: 0,0:41:55.26,0:41:57.92,Default,,0,0,0,,如果需要搜索的空间足够的大 Dialogue: 0,0:41:57.92,0:42:00.92,Default,,0,0,0,,第二种搜索方式就会变得不现实 Dialogue: 0,0:42:01.36,0:42:05.93,Default,,0,0,0,,教授:呃 这个问题其实是 Dialogue: 0,0:42:07.13,0:42:08.44,Default,,0,0,0,,这一节课剩下的内容 Dialogue: 0,0:42:08.57,0:42:10.54,Default,,0,0,0,,这个问题很好 Dialogue: 0,0:42:13.87,0:42:15.74,Default,,0,0,0,,先不要尝试去预知后面的课 Dialogue: 0,0:42:15.96,0:42:19.23,Default,,0,0,0,,只是在现在 你们要保持谨慎 Dialogue: 0,0:42:19.84,0:42:21.84,Default,,0,0,0,,这里确实有点奇怪 难道不是么? Dialogue: 0,0:42:22.22,0:42:24.51,Default,,0,0,0,,尽管这个看起来不错 但是难道它不低效吗? Dialogue: 0,0:42:24.83,0:42:26.03,Default,,0,0,0,,这是我们待会儿要解决的问题 Dialogue: 0,0:42:28.10,0:42:30.02,Default,,0,0,0,,就让我们稍后来揭晓秘密吧 Dialogue: 0,0:42:33.35,0:42:34.60,Default,,0,0,0,,好吧 休息一下 Dialogue: 0,0:42:34.60,0:42:44.51,Default,,0,0,0,,[音乐] Dialogue: 0,0:42:44.51,0:42:49.04,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:43:10.57,0:43:17.05,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:43:17.05,0:43:21.21,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:43:21.21,0:43:25.21,Declare,,0,0,0,,{\an2\fad(500,500)} I Dialogue: 0,0:43:29.65,0:43:33.76,Default,,0,0,0,,你可能现在开始怀疑了 Dialogue: 0,0:43:35.60,0:43:39.26,Default,,0,0,0,,我已经展示了这种简单而优雅的 Dialogue: 0,0:43:40.51,0:43:42.28,Default,,0,0,0,,组合程序的方法 Dialogue: 0,0:43:42.86,0:43:46.91,Default,,0,0,0,,这跟那些传统程序非常不同 Dialogue: 0,0:43:46.92,0:43:48.19,Default,,0,0,0,,那些求奇数的平方和 Dialogue: 0,0:43:48.72,0:43:51.32,Default,,0,0,0,,或者求奇数项斐波那契数之类的程序 Dialogue: 0,0:43:53.74,0:43:55.48,Default,,0,0,0,,也不像那些混合了 Dialogue: 0,0:43:55.85,0:43:58.84,Default,,0,0,0,,枚举函数、过滤函数和累积函数的程序 Dialogue: 0,0:44:00.44,0:44:01.82,Default,,0,0,0,,通过把它们混合起来 Dialogue: 0,0:44:02.20,0:44:04.59,Default,,0,0,0,,通过这种混搭式的 Dialogue: 0,0:44:04.62,0:44:07.34,Default,,0,0,0,,组合程序的方法 Dialogue: 0,0:44:07.82,0:44:09.53,Default,,0,0,0,,我们并没有获得 Dialogue: 0,0:44:09.55,0:44:11.77,Default,,0,0,0,,流式程序设计的理论优势 Dialogue: 0,0:44:13.80,0:44:14.25,Default,,0,0,0,,另一方面 Dialogue: 0,0:44:14.28,0:44:16.88,Default,,0,0,0,,你们所见过的大多数程序是那种丑陋的风格 Dialogue: 0,0:44:18.34,0:44:18.94,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:44:19.20,0:44:20.59,Default,,0,0,0,,难道计算机科学家们 Dialogue: 0,0:44:21.16,0:44:24.30,Default,,0,0,0,,愚蠢得无以复加 Dialogue: 0,0:44:25.42,0:44:26.44,Default,,0,0,0,,以至于他们没有注意到这个现象么? Dialogue: 0,0:44:27.07,0:44:28.75,Default,,0,0,0,,如果你仅仅只是做了这些事 Dialogue: 0,0:44:29.63,0:44:31.93,Default,,0,0,0,,你就能让程序变得极其优雅么? Dialogue: 0,0:44:33.62,0:44:34.78,Default,,0,0,0,,肯定有什么缺陷 Dialogue: 0,0:44:36.76,0:44:39.05,Default,,0,0,0,,事实上这一缺陷也很容易发现 Dialogue: 0,0:44:39.51,0:44:41.74,Default,,0,0,0,,我们来看看接下来的这个问题 Dialogue: 0,0:44:42.03,0:44:45.47,Default,,0,0,0,,假设我让你去找 Dialogue: 0,0:44:46.16,0:44:48.16,Default,,0,0,0,,1,000到1,000,000之间的第二个素数 Dialogue: 0,0:44:49.12,0:44:50.56,Default,,0,0,0,,如果你的计算机性能更强劲的话 Dialogue: 0,0:44:50.59,0:44:53.05,Default,,0,0,0,,或者可以去找10,000到100,000,000之间的 Dialogue: 0,0:44:54.32,0:44:55.45,Default,,0,0,0,,你可能觉得这很容易 Dialogue: 0,0:44:55.47,0:44:56.65,Default,,0,0,0,,我可以用流来解决 Dialogue: 0,0:44:57.08,0:44:59.87,Default,,0,0,0,,我需要做的就是 Dialogue: 0,0:45:00.57,0:45:02.89,Default,,0,0,0,,从10,000枚举到1,000,000 Dialogue: 0,0:45:04.16,0:45:06.51,Default,,0,0,0,,我就获得了从10,000到1,000,000的所有整数 Dialogue: 0,0:45:06.80,0:45:08.64,Default,,0,0,0,,我过滤出所有的质数 Dialogue: 0,0:45:09.39,0:45:11.10,Default,,0,0,0,,也就是对这些数做素性检测 Dialogue: 0,0:45:11.76,0:45:12.83,Default,,0,0,0,,然后从中取出第二个元素 Dialogue: 0,0:45:12.84,0:45:14.04,Default,,0,0,0,,也就是 TAIL的HEAD部分 Dialogue: 0,0:45:15.79,0:45:17.38,Default,,0,0,0,,这显然是非常荒谬的 Dialogue: 0,0:45:21.66,0:45:23.20,Default,,0,0,0,,我们的机器没有这么大的空间 Dialogue: 0,0:45:23.58,0:45:25.24,Default,,0,0,0,,来存放这些整数 Dialogue: 0,0:45:25.28,0:45:26.35,Default,,0,0,0,,更别说来测试它们了 Dialogue: 0,0:45:27.04,0:45:28.64,Default,,0,0,0,,而且我也只是取第二个数而已 Dialogue: 0,0:45:29.81,0:45:34.94,Default,,0,0,0,,这种传统程序设计风格的威力 Dialogue: 0,0:45:36.43,0:45:37.68,Default,,0,0,0,,(虽然)也正是其弱点 Dialogue: 0,0:45:37.96,0:45:38.94,Default,,0,0,0,,这种程序设计风格 Dialogue: 0,0:45:39.61,0:45:43.50,Default,,0,0,0,,混合了枚举、测试以及累积 Dialogue: 0,0:45:44.88,0:45:46.46,Default,,0,0,0,,我们不需要做全部的事 Dialogue: 0,0:45:46.67,0:45:49.18,Default,,0,0,0,,所以说 实际上这是这种 Dialogue: 0,0:45:49.45,0:45:51.74,Default,,0,0,0,,概念上丑陋的风格 Dialogue: 0,0:45:52.20,0:45:53.80,Default,,0,0,0,,正是让它运行起来高效 Dialogue: 0,0:45:54.91,0:45:55.84,Default,,0,0,0,,就是像这样来混合 Dialogue: 0,0:45:57.80,0:45:59.34,Default,,0,0,0,,我今天一早上所做的好像都是在 Dialogue: 0,0:45:59.34,0:46:00.42,Default,,0,0,0,,把你们搞糊涂一样 Dialogue: 0,0:46:00.42,0:46:03.10,Default,,0,0,0,,我为你们展示了一种貌似可行的优雅程序设计方法 Dialogue: 0,0:46:03.10,0:46:03.96,Default,,0,0,0,,但它却不可行 Dialogue: 0,0:46:05.84,0:46:08.32,Default,,0,0,0,,但是 接下来就是见证奇迹的时刻 Dialogue: 0,0:46:09.04,0:46:10.57,Default,,0,0,0,,结果却是 这个游戏里 Dialogue: 0,0:46:11.21,0:46:13.84,Default,,0,0,0,,我们真的可以得到蛋糕并吃掉它 Dialogue: 0,0:46:14.87,0:46:16.11,Default,,0,0,0,,我的意思是 Dialogue: 0,0:46:18.09,0:46:21.15,Default,,0,0,0,,我们完全可以用流来组织程序 Dialogue: 0,0:46:21.16,0:46:22.48,Default,,0,0,0,,就像我之前编写的那样 Dialogue: 0,0:46:23.55,0:46:27.74,Default,,0,0,0,,以至于当机器真正运行的时候 Dialogue: 0,0:46:28.33,0:46:31.52,Default,,0,0,0,,它可以和传统风格的程序一样高效 Dialogue: 0,0:46:31.71,0:46:34.28,Default,,0,0,0,,那些混合了生成与测试的程序 Dialogue: 0,0:46:36.16,0:46:38.80,Default,,0,0,0,,听起来不可思议 Dialogue: 0,0:46:40.77,0:46:41.82,Default,,0,0,0,,关键在就于 Dialogue: 0,0:46:42.00,0:46:43.69,Default,,0,0,0,,流不是表 Dialogue: 0,0:46:48.09,0:46:49.79,Default,,0,0,0,,一会儿我们就会看到 但是现在 Dialogue: 0,0:46:49.80,0:46:51.77,Default,,0,0,0,,先让我们来看看幻灯片 Dialogue: 0,0:46:52.24,0:46:53.80,Default,,0,0,0,,你们对这个 Dialogue: 0,0:46:53.84,0:46:55.58,Default,,0,0,0,,信号处理系统的印象是 Dialogue: 0,0:46:57.26,0:46:58.72,Default,,0,0,0,,你们认为要发生的是 Dialogue: 0,0:46:59.13,0:47:00.92,Default,,0,0,0,,在这类盒子中 Dialogue: 0,0:47:01.18,0:47:03.58,Default,,0,0,0,,事先产生好了整数 Dialogue: 0,0:47:05.36,0:47:06.40,Default,,0,0,0,,这里有个过滤函数 Dialogue: 0,0:47:07.45,0:47:09.37,Default,,0,0,0,,它和那个盒子相连 并从中拉取东西 Dialogue: 0,0:47:10.94,0:47:13.15,Default,,0,0,0,,这里还有人从这整个系统中 Dialogue: 0,0:47:13.31,0:47:14.91,Default,,0,0,0,,拉取东西 Dialogue: 0,0:47:16.79,0:47:18.70,Default,,0,0,0,,你们应该这么来理解: Dialogue: 0,0:47:18.99,0:47:20.72,Default,,0,0,0,,有人想要得到第一个质数 Dialogue: 0,0:47:22.67,0:47:24.14,Default,,0,0,0,,他从这个过滤函数这儿拉取 Dialogue: 0,0:47:24.59,0:47:26.12,Default,,0,0,0,,FILTER从枚举函数中去拉取 Dialogue: 0,0:47:28.02,0:47:29.15,Default,,0,0,0,,你只需要在固定范围内寻找 Dialogue: 0,0:47:29.16,0:47:30.93,Default,,0,0,0,,然后从里面取出第二个数 Dialogue: 0,0:47:30.93,0:47:31.95,Default,,0,0,0,,第二个质数是多少? Dialogue: 0,0:47:33.71,0:47:35.37,Default,,0,0,0,,没有额外的计算 Dialogue: 0,0:47:35.37,0:47:36.64,Default,,0,0,0,,只要你不去拉取东西 Dialogue: 0,0:47:36.64,0:47:38.32,Default,,0,0,0,,就不会产生进行额外计算 Dialogue: 0,0:47:40.50,0:47:41.41,Default,,0,0,0,,我来用实物演示一下 Dialogue: 0,0:47:41.41,0:47:43.88,Default,,0,0,0,,这个小设备 Dialogue: 0,0:47:43.90,0:47:44.97,Default,,0,0,0,,这是个小型的流机器 Dialogue: 0,0:47:45.50,0:47:46.83,Default,,0,0,0,,这是Eric Grimson发明的 Dialogue: 0,0:47:47.60,0:47:49.24,Default,,0,0,0,,他也在MIT教这门课 Dialogue: 0,0:47:49.83,0:47:52.51,Default,,0,0,0,,实际的流程是 -- 这里有某种流 Dialogue: 0,0:47:52.54,0:47:53.82,Default,,0,0,0,,就像一串整数一样 Dialogue: 0,0:47:54.78,0:47:56.33,Default,,0,0,0,,这些是一些处理单元 Dialogue: 0,0:47:58.70,0:48:02.60,Default,,0,0,0,,就像是FILTER、MAP之类的东西 Dialogue: 0,0:48:03.98,0:48:09.18,Default,,0,0,0,,如果我把流实现为表 来进行处理 Dialogue: 0,0:48:09.24,0:48:11.26,Default,,0,0,0,,我拥有的是一个表 Dialogue: 0,0:48:11.47,0:48:12.67,Default,,0,0,0,,现在 我先执行第一个过滤函数 Dialogue: 0,0:48:12.67,0:48:14.07,Default,,0,0,0,,我像这样完全处理 Dialogue: 0,0:48:14.88,0:48:15.77,Default,,0,0,0,,针对这个流 Dialogue: 0,0:48:16.32,0:48:19.21,Default,,0,0,0,,不断地处理、处理、处理、处理 Dialogue: 0,0:48:19.61,0:48:21.05,Default,,0,0,0,,然后得到一个新的流 Dialogue: 0,0:48:21.63,0:48:24.07,Default,,0,0,0,,现在 我把得到的结果拿在我手中 Dialogue: 0,0:48:24.07,0:48:25.26,Default,,0,0,0,,然后把它放进第二个 Dialogue: 0,0:48:25.56,0:48:26.94,Default,,0,0,0,,又处理了全部的流 Dialogue: 0,0:48:28.27,0:48:29.51,Default,,0,0,0,,得到一个新流 Dialogue: 0,0:48:32.13,0:48:33.36,Default,,0,0,0,,然后我再把结果 Dialogue: 0,0:48:34.28,0:48:36.36,Default,,0,0,0,,用相同的方式再次处理 Dialogue: 0,0:48:36.36,0:48:40.99,Default,,0,0,0,,如果仅仅把流当做表的话 Dialogue: 0,0:48:41.69,0:48:42.97,Default,,0,0,0,,计算的过程就是这样的 Dialogue: 0,0:48:43.86,0:48:45.64,Default,,0,0,0,,但是事实上 流不是表 流就是流 Dialogue: 0,0:48:45.82,0:48:48.11,Default,,0,0,0,,而你们应该这样来想像 Dialogue: 0,0:48:50.23,0:48:52.52,Default,,0,0,0,,我把这些小玩意连接起来 Dialogue: 0,0:48:55.26,0:48:56.76,Default,,0,0,0,,数据在其中流动 Dialogue: 0,0:49:00.33,0:49:02.30,Default,,0,0,0,,这里是流的源头 Dialogue: 0,0:49:02.32,0:49:02.92,Default,,0,0,0,,它可能在 Dialogue: 0,0:49:04.19,0:49:05.72,Default,,0,0,0,,产生一些整数 Dialogue: 0,0:49:05.98,0:49:07.39,Default,,0,0,0,,如果我想要拉取一个结果 会发生什么? Dialogue: 0,0:49:07.58,0:49:08.91,Default,,0,0,0,,我从尾部这里拉取 Dialogue: 0,0:49:10.20,0:49:11.07,Default,,0,0,0,,而这个单元会说 Dialogue: 0,0:49:11.08,0:49:12.20,Default,,0,0,0,,我需要更多的数据 Dialogue: 0,0:49:13.09,0:49:15.52,Default,,0,0,0,,所以 它就到这个单元去拉取数据 Dialogue: 0,0:49:15.83,0:49:17.39,Default,,0,0,0,,它说:“我需要更多的数据” Dialogue: 0,0:49:17.89,0:49:19.56,Default,,0,0,0,,然后这个又从下一个单元拉取 Dialogue: 0,0:49:19.56,0:49:20.28,Default,,0,0,0,,可能是一个过滤函数 Dialogue: 0,0:49:20.28,0:49:21.40,Default,,0,0,0,,从它那里取得更多数据 Dialogue: 0,0:49:21.64,0:49:23.15,Default,,0,0,0,,我在这一端拉取数据时 Dialogue: 0,0:49:23.53,0:49:25.56,Default,,0,0,0,,只会生成这么多的数据 Dialogue: 0,0:49:25.78,0:49:28.30,Default,,0,0,0,,我在另一端请求一定量的数据时 Dialogue: 0,0:49:28.56,0:49:29.98,Default,,0,0,0,,只有相当数量的数据被生成并处理 Dialogue: 0,0:49:30.76,0:49:32.09,Default,,0,0,0,,这就是你们需要知道的 Dialogue: 0,0:49:32.80,0:49:34.38,Default,,0,0,0,,把流实现为表 Dialogue: 0,0:49:34.56,0:49:35.92,Default,,0,0,0,,和流真实的工作方式 Dialogue: 0,0:49:36.16,0:49:37.50,Default,,0,0,0,,的区别 Dialogue: 0,0:49:40.78,0:49:42.14,Default,,0,0,0,,那么 到底怎么来实现呢? Dialogue: 0,0:49:42.35,0:49:43.32,Default,,0,0,0,,知道了流的真实工作方式 Dialogue: 0,0:49:43.40,0:49:44.52,Default,,0,0,0,,构造流有什么窍门呢? Dialogue: 0,0:49:47.93,0:49:50.32,Default,,0,0,0,,我们想要把流组织成 Dialogue: 0,0:49:50.41,0:49:51.58,Default,,0,0,0,,一种数据结构 Dialogue: 0,0:49:52.00,0:49:54.22,Default,,0,0,0,,它能够增量式地计算自己 Dialogue: 0,0:49:54.22,0:49:56.22,Default,,0,0,0,,一种“按需”数据结构 Dialogue: 0,0:49:58.96,0:50:00.51,Default,,0,0,0,,基本思想在于 Dialogue: 0,0:50:00.97,0:50:02.70,Default,,0,0,0,,再次强调 这是贯穿整个课程的 Dialogue: 0,0:50:02.72,0:50:04.12,Default,,0,0,0,,几大基本思想之一 Dialogue: 0,0:50:04.49,0:50:05.00,Default,,0,0,0,,这就是 Dialogue: 0,0:50:05.52,0:50:06.97,Default,,0,0,0,,数据与过程之间 Dialogue: 0,0:50:06.99,0:50:08.44,Default,,0,0,0,,并没有绝对的界限 Dialogue: 0,0:50:09.24,0:50:10.54,Default,,0,0,0,,流会是这样的一种结构 Dialogue: 0,0:50:10.59,0:50:13.40,Default,,0,0,0,,它既是一种传统意义上的“数据结构” Dialogue: 0,0:50:13.45,0:50:15.92,Default,,0,0,0,,比如树的叶子结点组成的流 Dialogue: 0,0:50:16.86,0:50:17.85,Default,,0,0,0,,但是同时 Dialogue: 0,0:50:17.85,0:50:19.32,Default,,0,0,0,,它又是一种非常聪明的过程 Dialogue: 0,0:50:20.24,0:50:22.22,Default,,0,0,0,,它包含了如何计算的方法 Dialogue: 0,0:50:23.74,0:50:25.93,Default,,0,0,0,,好吧 实际来看一下 Dialogue: 0,0:50:25.93,0:50:26.62,Default,,0,0,0,,事实上 Dialogue: 0,0:50:26.80,0:50:28.33,Default,,0,0,0,,我们不需要其它的机制 Dialogue: 0,0:50:28.46,0:50:29.87,Default,,0,0,0,,我们已经有了所需要的一切东西 Dialogue: 0,0:50:30.14,0:50:30.99,Default,,0,0,0,,这是因为 Dialogue: 0,0:50:31.02,0:50:33.93,Default,,0,0,0,,我们已经能够 把过程当作第一级对象来处理了 Dialogue: 0,0:50:35.46,0:50:36.88,Default,,0,0,0,,来看看这个关键之处 Dialogue: 0,0:50:36.88,0:50:39.03,Default,,0,0,0,,关键在于 -- 回想一下 我们有这些运算 Dialogue: 0,0:50:39.03,0:50:47.52,Default,,0,0,0,,CONS-STREAM、HEAD和TAIL Dialogue: 0,0:50:48.08,0:50:49.36,Default,,0,0,0,,刚开始的时候我说 Dialogue: 0,0:50:49.92,0:50:51.36,Default,,0,0,0,,你们可以把这个看作CONS Dialogue: 0,0:50:51.40,0:50:52.62,Default,,0,0,0,,把HEAD看作CAR Dialogue: 0,0:50:52.62,0:50:53.52,Default,,0,0,0,,把TAIL看作CDR Dialogue: 0,0:50:53.55,0:50:54.16,Default,,0,0,0,,事实上没这么简单 Dialogue: 0,0:50:55.08,0:50:56.32,Default,,0,0,0,,现在 来看看它们到底是什么 Dialogue: 0,0:50:57.71,0:51:05.84,Default,,0,0,0,,(CONS-STREAM X Y) Dialogue: 0,0:51:07.48,0:51:17.79,Default,,0,0,0,,是这个东西的缩写形式 Dialogue: 0,0:51:19.54,0:51:28.32,Default,,0,0,0,,(CONS X (DELAY Y)) Dialogue: 0,0:51:31.68,0:51:33.53,Default,,0,0,0,,我先把它们写完再来解释 Dialogue: 0,0:51:34.52,0:51:35.53,Default,,0,0,0,,而(HEAD S) Dialogue: 0,0:51:38.09,0:51:39.79,Default,,0,0,0,,就是 (CAR S) Dialogue: 0,0:51:42.38,0:51:44.25,Default,,0,0,0,,而(TAIL S) Dialogue: 0,0:51:46.68,0:51:54.60,Default,,0,0,0,,则是(FORCE (CDR S)) Dialogue: 0,0:51:56.12,0:51:57.04,Default,,0,0,0,,我来解释一下 Dialogue: 0,0:51:58.06,0:51:59.88,Default,,0,0,0,,DELAY是一个特殊而神奇的东西 Dialogue: 0,0:52:01.42,0:52:02.33,Default,,0,0,0,,DELAY所做是 Dialogue: 0,0:52:03.85,0:52:05.31,Default,,0,0,0,,取一个表达式 Dialogue: 0,0:52:05.50,0:52:06.86,Default,,0,0,0,,然后产生一个PROMISE Dialogue: 0,0:52:07.12,0:52:09.15,Default,,0,0,0,,在你有需要时 这个PROMISE会计算那个表达式 Dialogue: 0,0:52:10.60,0:52:11.98,Default,,0,0,0,,但在此时没有做任何计算 Dialogue: 0,0:52:11.98,0:52:14.32,Default,,0,0,0,,只是一个延期的PROMISE Dialogue: 0,0:52:14.82,0:52:16.20,Default,,0,0,0,,承诺要做这样的事 Dialogue: 0,0:52:17.11,0:52:18.20,Default,,0,0,0,,CONS-STREAM所做的就是 Dialogue: 0,0:52:18.81,0:52:21.96,Default,,0,0,0,,把X和一个计算Y的PROMISE Dialogue: 0,0:52:23.31,0:52:25.36,Default,,0,0,0,,放在在一个序对里 Dialogue: 0,0:52:28.23,0:52:28.99,Default,,0,0,0,,如果我需要头部分 Dialogue: 0,0:52:28.99,0:52:30.75,Default,,0,0,0,,那么就是这个序对的CAR部分 Dialogue: 0,0:52:31.84,0:52:33.71,Default,,0,0,0,,关键在于 它的尾部分 Dialogue: 0,0:52:34.62,0:52:36.65,Default,,0,0,0,,强制会调用该PROMISE Dialogue: 0,0:52:38.22,0:52:39.88,Default,,0,0,0,,而TAIL会说 Dialogue: 0,0:52:40.03,0:52:41.02,Default,,0,0,0,,好吧 取出该PROMISE Dialogue: 0,0:52:41.85,0:52:44.52,Default,,0,0,0,,然后调用该PROMISE Dialogue: 0,0:52:44.56,0:52:46.03,Default,,0,0,0,,这才开始实际的计算 Dialogue: 0,0:52:47.69,0:52:48.72,Default,,0,0,0,,这就是它的实际工作方式 Dialogue: 0,0:52:48.74,0:52:51.55,Default,,0,0,0,,这就是CONS-STREAM、HEAD和TAIL的真正定义 Dialogue: 0,0:52:54.60,0:52:55.57,Default,,0,0,0,,具体演示一下 Dialogue: 0,0:52:55.57,0:52:57.50,Default,,0,0,0,,我们小心翼翼地来审查一遍 Dialogue: 0,0:52:58.76,0:53:00.62,Default,,0,0,0,,现在从计算10,000到1,000,000中的 Dialogue: 0,0:53:01.32,0:53:03.66,Default,,0,0,0,,第二个质数这个实例来看 Dialogue: 0,0:53:05.50,0:53:07.16,Default,,0,0,0,,看看是怎么运行的 Dialogue: 0,0:53:08.65,0:53:12.03,Default,,0,0,0,,好的 我们从这个表达式开始 Dialogue: 0,0:53:15.36,0:53:16.62,Default,,0,0,0,,第二个质数就是 Dialogue: 0,0:53:16.64,0:53:21.90,Default,,0,0,0,,就是(HEAD (TAIL (FILTER PRIME? ... ))) Dialogue: 0,0:53:22.83,0:53:25.31,Default,,0,0,0,,枚举的范围是(E-I 10000 1000000) Dialogue: 0,0:53:26.71,0:53:27.61,Default,,0,0,0,,这是什么呢? Dialogue: 0,0:53:28.40,0:53:29.20,Default,,0,0,0,,那就是 Dialogue: 0,0:53:31.63,0:53:34.17,Default,,0,0,0,,枚举的这个10,000至1,000,000的区间 Dialogue: 0,0:53:35.72,0:53:37.32,Default,,0,0,0,,如果你追踪这个枚举区间 Dialogue: 0,0:53:37.34,0:53:38.78,Default,,0,0,0,,会发现它构造了一个流 Dialogue: 0,0:53:39.92,0:53:41.39,Default,,0,0,0,,CONS-STREAM实际代换过来是 Dialogue: 0,0:53:41.96,0:53:43.61,Default,,0,0,0,,把10,000 Dialogue: 0,0:53:44.51,0:53:48.92,Default,,0,0,0,,和一个计算10,001到1,000,000之间整数的PROMISE结合起来 Dialogue: 0,0:53:54.00,0:53:55.75,Default,,0,0,0,,这也就是上面这个表达式 Dialogue: 0,0:53:55.75,0:53:57.32,Default,,0,0,0,,现在我使用代换模型 Dialogue: 0,0:53:57.64,0:53:59.32,Default,,0,0,0,,我们可以用代换模型的原因是 Dialogue: 0,0:53:59.34,0:54:01.01,Default,,0,0,0,,这里并没有涉及状态和副作用 Dialogue: 0,0:54:03.56,0:54:06.38,Default,,0,0,0,,所以我有10,000 Dialogue: 0,0:54:06.41,0:54:08.27,Default,,0,0,0,,和一个计算剩余整数构成的流 Dialogue: 0,0:54:08.32,0:54:10.49,Default,,0,0,0,,而到现在为止 只有一个整数被枚举了出来 Dialogue: 0,0:54:14.38,0:54:16.96,Default,,0,0,0,,然后过滤函数会对它做素性测试 Dialogue: 0,0:54:19.44,0:54:21.90,Default,,0,0,0,,我们再来仔细看看过滤函数的代码 Dialogue: 0,0:54:22.36,0:54:24.46,Default,,0,0,0,,过滤函数首先测试流的首部分 Dialogue: 0,0:54:25.46,0:54:28.25,Default,,0,0,0,,这里 过滤函数会测试10,000 Dialogue: 0,0:54:30.30,0:54:32.97,Default,,0,0,0,,然后输出:10,000不是质数 Dialogue: 0,0:54:33.50,0:54:35.85,Default,,0,0,0,,因此我只需要 Dialogue: 0,0:54:36.25,0:54:37.39,Default,,0,0,0,,递归地过滤尾部分 Dialogue: 0,0:54:39.22,0:54:40.14,Default,,0,0,0,,尾部分是什么呢? Dialogue: 0,0:54:40.16,0:54:43.76,Default,,0,0,0,,就是这个流的尾部分 -- 一个PROMISE Dialogue: 0,0:54:46.34,0:54:48.06,Default,,0,0,0,,我们进入到尾部分 Dialogue: 0,0:54:48.28,0:54:49.50,Default,,0,0,0,,强制(计算)该PROMISE Dialogue: 0,0:54:49.68,0:54:50.94,Default,,0,0,0,,我强制计算该PROMISE Dialogue: 0,0:54:52.30,0:54:54.36,Default,,0,0,0,,这就意味着 我现在要 Dialogue: 0,0:54:55.58,0:54:57.96,Default,,0,0,0,,枚举10,001到1,000,000之间的整数 Dialogue: 0,0:55:00.80,0:55:02.97,Default,,0,0,0,,现在 过滤函数处理的是这个东西 Dialogue: 0,0:55:07.81,0:55:08.92,Default,,0,0,0,,这个枚举函数枚举了它自己 Dialogue: 0,0:55:08.94,0:55:11.23,Default,,0,0,0,,我们又回到了最初那种枚举情况 Dialogue: 0,0:55:11.96,0:55:13.00,Default,,0,0,0,,我们的枚举函数的 Dialogue: 0,0:55:14.12,0:55:16.44,Default,,0,0,0,,首部分是整数10,001 Dialogue: 0,0:55:16.60,0:55:18.20,Default,,0,0,0,,尾部分是计算剩余部分的PROMISE Dialogue: 0,0:55:19.74,0:55:22.75,Default,,0,0,0,,因此现在素性过滤函数将会测试10,001 Dialogue: 0,0:55:23.23,0:55:25.12,Default,,0,0,0,,开始判断它是不是质数 Dialogue: 0,0:55:25.12,0:55:27.08,Default,,0,0,0,,结果10,001不是质数 Dialogue: 0,0:55:27.55,0:55:29.61,Default,,0,0,0,,然后再不断地强制求值PROMISE Dialogue: 0,0:55:32.92,0:55:35.80,Default,,0,0,0,,最后 我觉得它找到的第一个质数可能是10,009 Dialogue: 0,0:55:37.10,0:55:38.33,Default,,0,0,0,,它会在这个时候停止 Dialogue: 0,0:55:40.84,0:55:41.93,Default,,0,0,0,,这只是第一个质数 Dialogue: 0,0:55:41.96,0:55:43.48,Default,,0,0,0,,然而 我们需要的是第二个 Dialogue: 0,0:55:45.24,0:55:46.84,Default,,0,0,0,,所以 这时它又启动了 Dialogue: 0,0:55:47.03,0:55:48.25,Default,,0,0,0,,你会发现 Dialogue: 0,0:55:48.52,0:55:50.49,Default,,0,0,0,,你需要多少 Dialogue: 0,0:55:51.85,0:55:52.91,Default,,0,0,0,,它就只会生成多少 Dialogue: 0,0:55:56.48,0:55:59.92,Default,,0,0,0,,枚举函数生成整数的数量 Dialogue: 0,0:56:00.12,0:56:01.45,Default,,0,0,0,,不会比过滤函数所要求的多 Dialogue: 0,0:56:01.47,0:56:03.45,Default,,0,0,0,,因为它只是取一部分数来做素性测试 Dialogue: 0,0:56:04.70,0:56:06.51,Default,,0,0,0,,过滤函数也不会生成 Dialogue: 0,0:56:06.54,0:56:08.04,Default,,0,0,0,,比你的要求更多的东西 Dialogue: 0,0:56:08.06,0:56:09.10,Default,,0,0,0,,也就是尾部分的首部分 Dialogue: 0,0:56:11.61,0:56:13.26,Default,,0,0,0,,你们看 Dialogue: 0,0:56:14.70,0:56:18.24,Default,,0,0,0,,我们把计算机运行中实际进行的 Dialogue: 0,0:56:18.67,0:56:20.65,Default,,0,0,0,,生成与测试的过程 混合在了一起 Dialogue: 0,0:56:21.52,0:56:22.67,Default,,0,0,0,,尽管 Dialogue: 0,0:56:23.18,0:56:25.63,Default,,0,0,0,,我们的程序“看起来”显然不是这样 Dialogue: 0,0:56:28.12,0:56:29.40,Default,,0,0,0,,看起来都很简单 Dialogue: 0,0:56:30.23,0:56:32.67,Default,,0,0,0,,这种机制的神奇之处在于DELAY Dialogue: 0,0:56:33.68,0:56:35.66,Default,,0,0,0,,所以你也许会说 这全是因为DELAY很强大 Dialogue: 0,0:56:36.90,0:56:38.57,Default,,0,0,0,,但其实并不是 Dialogue: 0,0:56:39.07,0:56:39.98,Default,,0,0,0,,DELAY其实很简单 Dialogue: 0,0:56:40.61,0:56:45.07,Default,,0,0,0,,(DELAY ) Dialogue: 0,0:56:48.25,0:56:50.04,Default,,0,0,0,,只是一个缩略表达 Dialogue: 0,0:56:53.36,0:56:55.63,Default,,0,0,0,,它是-- 创建一个用于计算表达式的PROMISE Dialogue: 0,0:56:56.49,0:57:01.12,Default,,0,0,0,,(LAMBDA () ) 这样的一个表达式 Dialogue: 0,0:57:02.83,0:57:03.84,Default,,0,0,0,,这就是整个过程 Dialogue: 0,0:57:03.98,0:57:05.53,Default,,0,0,0,,这个PROMISE将要计算表达式 Dialogue: 0,0:57:06.05,0:57:06.73,Default,,0,0,0,,FORCE过程又是什么? Dialogue: 0,0:57:07.34,0:57:10.80,Default,,0,0,0,,如何处理这个PROMISE Dialogue: 0,0:57:10.80,0:57:14.11,Default,,0,0,0,,FROCE一个PROMISE -- 也就是某个过程 Dialogue: 0,0:57:14.78,0:57:15.40,Default,,0,0,0,,只是简单地运行它 Dialogue: 0,0:57:19.23,0:57:19.56,Default,,0,0,0,,就是这样 Dialogue: 0,0:57:20.24,0:57:21.37,Default,,0,0,0,,所以这里并没有什么魔法 Dialogue: 0,0:57:23.52,0:57:24.24,Default,,0,0,0,,总结一下 我们都干了些什么? Dialogue: 0,0:57:26.44,0:57:27.50,Default,,0,0,0,,我们说 Dialogue: 0,0:57:28.14,0:57:30.81,Default,,0,0,0,,传统的编程方式更有效 Dialogue: 0,0:57:30.96,0:57:33.92,Default,,0,0,0,,而流程序却更加清晰 Dialogue: 0,0:57:35.50,0:57:38.72,Default,,0,0,0,,我们设法用DELAY Dialogue: 0,0:57:38.81,0:57:43.23,Default,,0,0,0,,使流程序和其它过程一样高效 Dialogue: 0,0:57:43.35,0:57:46.43,Default,,0,0,0,,DELAY所做的就是把 Dialogue: 0,0:57:46.68,0:57:50.40,Default,,0,0,0,,我们程序中 事件发生的逻辑顺序 Dialogue: 0,0:57:51.21,0:57:53.84,Default,,0,0,0,,和机器中 事件发生的实际顺序 解耦开来 Dialogue: 0,0:57:54.44,0:57:55.93,Default,,0,0,0,,这是DELAY的实质作用 Dialogue: 0,0:57:57.15,0:57:58.29,Default,,0,0,0,,也是全部的重点 Dialogue: 0,0:57:58.29,0:58:01.92,Default,,0,0,0,,我们放弃了那种想法 Dialogue: 0,0:58:02.30,0:58:04.17,Default,,0,0,0,,即程序的运行 Dialogue: 0,0:58:04.67,0:58:05.95,Default,,0,0,0,,或者源码的编排 Dialogue: 0,0:58:06.33,0:58:08.25,Default,,0,0,0,,反映了时间的明确概念 Dialogue: 0,0:58:09.45,0:58:10.57,Default,,0,0,0,,一旦放弃了这种想法 Dialogue: 0,0:58:11.21,0:58:13.32,Default,,0,0,0,,我们能使用DELAY Dialogue: 0,0:58:13.34,0:58:15.20,Default,,0,0,0,,自由地安排计算顺序 Dialogue: 0,0:58:16.69,0:58:17.61,Default,,0,0,0,,整个思想就是这样 Dialogue: 0,0:58:17.61,0:58:19.45,Default,,0,0,0,,我们解耦了 Dialogue: 0,0:58:19.95,0:58:21.13,Default,,0,0,0,,程序的逻辑顺序 Dialogue: 0,0:58:21.16,0:58:22.89,Default,,0,0,0,,和其实际运行的顺序 Dialogue: 0,0:58:24.09,0:58:25.77,Default,,0,0,0,,对了 还有一个细节 Dialogue: 0,0:58:25.77,0:58:27.21,Default,,0,0,0,,一个技术性的细节 Dialogue: 0,0:58:27.21,0:58:28.43,Default,,0,0,0,,但是也非常重要 Dialogue: 0,0:58:29.73,0:58:32.01,Default,,0,0,0,,当你们运行这些递归程序的时候 Dialogue: 0,0:58:32.16,0:58:33.58,Default,,0,0,0,,你会看到很多像是 Dialogue: 0,0:58:33.64,0:58:37.87,Default,,0,0,0,,(TAIL (TAIL (TAIL ... 这样的东西 Dialogue: 0,0:58:39.20,0:58:41.02,Default,,0,0,0,,如果流是通过嵌套的CONS构造起来的 Dialogue: 0,0:58:41.02,0:58:42.88,Default,,0,0,0,,就会出现这种情况 Dialogue: 0,0:58:43.86,0:58:46.09,Default,,0,0,0,,如果我每次都要执行一次 Dialogue: 0,0:58:46.14,0:58:47.58,Default,,0,0,0,,如果我每次都要计算TAIL Dialogue: 0,0:58:48.22,0:58:50.88,Default,,0,0,0,,我对一个过程求值 Dialogue: 0,0:58:51.07,0:58:53.07,Default,,0,0,0,,这个过程又将重新计算它的TAIL Dialogue: 0,0:58:53.10,0:58:55.40,Default,,0,0,0,,它的TAIL又将重新计算TAIL的TAIL Dialogue: 0,0:58:55.50,0:58:56.88,Default,,0,0,0,,你们可以发现这非常低效 Dialogue: 0,0:58:57.77,0:59:00.56,Default,,0,0,0,,尤其是跟已经存放了所有元素的表相比 Dialogue: 0,0:59:01.16,0:59:04.00,Default,,0,0,0,,因为那样 在取得下一个TAIL的时候不需要重新计算 Dialogue: 0,0:59:05.29,0:59:08.28,Default,,0,0,0,,因此 这里有一个小技巧 Dialogue: 0,0:59:09.66,0:59:13.13,Default,,0,0,0,,通过稍微修改DELAY的定义 Dialogue: 0,0:59:14.96,0:59:18.20,Default,,0,0,0,,就可以让整件事变得 -- 我先写一下 Dialogue: 0,0:59:19.68,0:59:22.04,Default,,0,0,0,,DELAY实际的实现是 Dialogue: 0,0:59:24.52,0:59:27.93,Default,,0,0,0,,(DELAY )是这样一个表达式的简写 Dialogue: 0,0:59:28.11,0:59:30.86,Default,,0,0,0,,(MEMO-PROC (LAMBDA () )) Dialogue: 0,0:59:31.00,0:59:34.06,Default,,0,0,0,,MEMO-PROC是一个可以改变过程的特殊过程 Dialogue: 0,0:59:35.15,0:59:37.80,Default,,0,0,0,,它接受一个无参过程 Dialogue: 0,0:59:39.02,0:59:41.05,Default,,0,0,0,,并把该过程变为 Dialogue: 0,0:59:41.36,0:59:43.55,Default,,0,0,0,,只需要执行一次计算的过程 Dialogue: 0,0:59:45.10,0:59:47.45,Default,,0,0,0,,我们意思是 你给它一个过程 Dialogue: 0,0:59:48.70,0:59:50.86,Default,,0,0,0,,MEMO-PROC返回一个新的过程 Dialogue: 0,0:59:51.39,0:59:53.00,Default,,0,0,0,,当你首次调用这个新过程 Dialogue: 0,0:59:53.71,0:59:55.07,Default,,0,0,0,,它会运行原始过程 Dialogue: 0,0:59:55.31,0:59:56.91,Default,,0,0,0,,并记下结果 Dialogue: 0,0:59:58.56,1:00:00.68,Default,,0,0,0,,从那之后 每次你再运行这个过程 Dialogue: 0,1:00:00.68,1:00:02.17,Default,,0,0,0,,就不用再计算了 Dialogue: 0,1:00:02.19,1:00:04.43,Default,,0,0,0,,它会把结果存储在一个地方 Dialogue: 0,1:00:05.20,1:00:06.92,Default,,0,0,0,,可以这样来实现MEMO-PROC Dialogue: 0,1:00:11.21,1:00:12.71,Default,,0,0,0,,一旦你了解怎么做 实现就很容易了 Dialogue: 0,1:00:12.71,1:00:16.76,Default,,0,0,0,,MEMO-PROC中有两个标记变量 Dialogue: 0,1:00:17.39,1:00:19.20,Default,,0,0,0,,ALREADY-RUN?用于记录是否运行过 Dialogue: 0,1:00:20.32,1:00:22.48,Default,,0,0,0,,初始值是NIL 指示没运行过 Dialogue: 0,1:00:23.62,1:00:27.04,Default,,0,0,0,,RESULT用于存储上一次计算的结果 Dialogue: 0,1:00:29.07,1:00:31.07,Default,,0,0,0,,MEMO-PROC接收一个过程PROC Dialogue: 0,1:00:31.56,1:00:34.01,Default,,0,0,0,,返回一个新的无参过程 Dialogue: 0,1:00:34.36,1:00:36.38,Default,,0,0,0,,PROC也是一个无参过程 Dialogue: 0,1:00:38.61,1:00:41.37,Default,,0,0,0,,它会判断 -- 如果没有运行过 Dialogue: 0,1:00:42.59,1:00:44.06,Default,,0,0,0,,就进行一系列的运算 Dialogue: 0,1:00:44.43,1:00:46.56,Default,,0,0,0,,先计算PROC Dialogue: 0,1:00:47.50,1:00:48.45,Default,,0,0,0,,然后存储它的值 Dialogue: 0,1:00:48.45,1:00:50.48,Default,,0,0,0,,存储在变量RESULT中 Dialogue: 0,1:00:51.14,1:00:53.90,Default,,0,0,0,,然后对ALREADY-RUN?赋值 提醒自己已经运行过了 Dialogue: 0,1:00:54.28,1:00:55.47,Default,,0,0,0,,最后返回RESULT Dialogue: 0,1:00:56.61,1:00:59.01,Default,,0,0,0,,所以之前如果没运行过 就执行一次计算 Dialogue: 0,1:00:59.01,1:01:01.88,Default,,0,0,0,,当你调用它 但已经运行过了 就直接返回结果 Dialogue: 0,1:01:03.42,1:01:07.12,Default,,0,0,0,,这种聪明的小技巧被称作“记忆化” Dialogue: 0,1:01:08.40,1:01:09.13,Default,,0,0,0,,这样的话 Dialogue: 0,1:01:10.35,1:01:14.14,Default,,0,0,0,,就不会重复的计算TAIL了 Dialogue: 0,1:01:15.27,1:01:17.81,Default,,0,0,0,,不再那样的没效率了 Dialogue: 0,1:01:17.81,1:01:18.72,Default,,0,0,0,,事实上 流式程序设计 Dialogue: 0,1:01:19.20,1:01:22.75,Default,,0,0,0,,甚至和传统的那种程序一样有效 Dialogue: 0,1:01:24.01,1:01:26.20,Default,,0,0,0,,再强调一下 整个的思想在于 Dialogue: 0,1:01:27.48,1:01:28.60,Default,,0,0,0,,我们已经讲过 Dialogue: 0,1:01:29.26,1:01:32.40,Default,,0,0,0,,过程与数据之间 Dialogue: 0,1:01:32.41,1:01:33.61,Default,,0,0,0,,没有一个明确的分界线 Dialogue: 0,1:01:33.61,1:01:35.61,Default,,0,0,0,,事实上 我们把数据结构组织得 Dialogue: 0,1:01:36.00,1:01:37.31,Default,,0,0,0,,像一个过程 Dialogue: 0,1:01:38.76,1:01:40.73,Default,,0,0,0,,它使得我们能够 Dialogue: 0,1:01:41.58,1:01:46.54,Default,,0,0,0,,可以实现一种常见的控制结构 Dialogue: 0,1:01:46.68,1:01:48.91,Default,,0,0,0,,在本例中是迭代 Dialogue: 0,1:01:49.62,1:01:51.05,Default,,0,0,0,,我们创建了一种数据结构 Dialogue: 0,1:01:51.32,1:01:52.84,Default,,0,0,0,,由于这种数据结构本身是一个过程 Dialogue: 0,1:01:52.86,1:01:55.12,Default,,0,0,0,,它其中就可以有某种控制结构 Dialogue: 0,1:01:55.79,1:01:57.13,Default,,0,0,0,,这就是流的实质 Dialogue: 0,1:01:58.91,1:01:59.76,Default,,0,0,0,,好 大家有什么问题吗? Dialogue: 0,1:02:03.95,1:02:05.84,Default,,0,0,0,,学生:你刚才说(TAIL (TAIL (TAIL ... Dialogue: 0,1:02:05.85,1:02:07.16,Default,,0,0,0,,如果我没理解错的话 Dialogue: 0,1:02:07.28,1:02:10.76,Default,,0,0,0,,没有没有MEMO-PROC的话 Dialogue: 0,1:02:10.78,1:02:12.83,Default,,0,0,0,,FORCE实际上执行了一个过程 Dialogue: 0,1:02:12.89,1:02:13.15,Default,,0,0,0,,教授:是的 Dialogue: 0,1:02:13.44,1:02:16.38,Default,,0,0,0,,学生:你说使用那个MEMO-PROC就不会有那样的问题 Dialogue: 0,1:02:16.38,1:02:18.73,Default,,0,0,0,,这难道不需要保证 Dialogue: 0,1:02:19.34,1:02:22.19,Default,,0,0,0,,(TAIL (TAIL (TAIL 每次的计算结构都是一致的么? Dialogue: 0,1:02:22.41,1:02:23.91,Default,,0,0,0,,教授:哦 当然 Dialogue: 0,1:02:23.91,1:02:25.84,Default,,0,0,0,,学生:我可能是漏了什么知识点 Dialogue: 0,1:02:26.05,1:02:27.21,Default,,0,0,0,,教授:你说得很对 这里 -- Dialogue: 0,1:02:31.12,1:02:33.64,Default,,0,0,0,,首先 为了获得结果需要进行一次计算 Dialogue: 0,1:02:34.09,1:02:36.76,Default,,0,0,0,,关键在于 一旦得到 (TAIL STREAM) Dialogue: 0,1:02:37.58,1:02:38.70,Default,,0,0,0,,再计算 (TAIL (TAIL STREAM)) 的时候 Dialogue: 0,1:02:38.70,1:02:40.51,Default,,0,0,0,,就不用再计算最内部的TAIL了 Dialogue: 0,1:02:42.98,1:02:44.32,Default,,0,0,0,,明白了吧 如果我没有用MEMO-PROC Dialogue: 0,1:02:44.35,1:02:46.09,Default,,0,0,0,,还要再计算一遍 (TAIL STREAM) Dialogue: 0,1:02:46.46,1:02:47.13,Default,,0,0,0,,学生:明白了 Dialogue: 0,1:02:50.83,1:02:52.56,Default,,0,0,0,,学生:之前的例子中你提到过 Dialogue: 0,1:02:52.60,1:02:54.22,Default,,0,0,0,,我们之所以可以使用代换模型 Dialogue: 0,1:02:54.22,1:02:56.11,Default,,0,0,0,,是因为这里没有副作用 Dialogue: 0,1:02:56.83,1:03:00.73,Default,,0,0,0,,如果我们的信号处理单元 Dialogue: 0,1:03:00.78,1:03:02.03,Default,,0,0,0,,具有副作用 Dialogue: 0,1:03:02.04,1:03:03.04,Default,,0,0,0,,具有内部状态 Dialogue: 0,1:03:03.62,1:03:06.84,Default,,0,0,0,,我们还有效地构建流模型么? Dialogue: 0,1:03:08.46,1:03:10.59,Default,,0,0,0,,教授:可能吧 这是一个很困难的问题 Dialogue: 0,1:03:11.20,1:03:13.42,Default,,0,0,0,,关于代换模型和副作用并不是很兼容这一点 Dialogue: 0,1:03:14.36,1:03:18.24,Default,,0,0,0,,我以后会稍稍地讲解一下 Dialogue: 0,1:03:18.96,1:03:20.48,Default,,0,0,0,,但大体来说 我认为 Dialogue: 0,1:03:20.49,1:03:21.63,Default,,0,0,0,,除非你非常小心 Dialogue: 0,1:03:21.90,1:03:24.46,Default,,0,0,0,,否则副作用会把一切弄得很糟糕 Dialogue: 0,1:03:35.04,1:03:38.25,Default,,0,0,0,,学生:我不是很理解MEMO-PROC这个过程 Dialogue: 0,1:03:39.68,1:03:41.12,Default,,0,0,0,,你是什么时候执行那个LAMBDA的? Dialogue: 0,1:03:41.99,1:03:43.21,Default,,0,0,0,,换句话说 Dialogue: 0,1:03:43.68,1:03:45.15,Default,,0,0,0,,当MEMO-PROC执行的时候 Dialogue: 0,1:03:45.18,1:03:47.71,Default,,0,0,0,,只生成了LAMBDA表达式 Dialogue: 0,1:03:48.01,1:03:49.68,Default,,0,0,0,,但我不太清楚它是什么时候被执行的 Dialogue: 0,1:03:50.39,1:03:51.12,Default,,0,0,0,,教授:好的 Dialogue: 0,1:03:51.35,1:03:52.68,Default,,0,0,0,,MEMO-PROC所做的 -- Dialogue: 0,1:03:53.07,1:03:55.85,Default,,0,0,0,,MEMO-PROC的一个参数是PROC Dialogue: 0,1:03:56.38,1:03:57.93,Default,,0,0,0,,一个没有参数的过程 Dialogue: 0,1:03:57.93,1:03:59.05,Default,,0,0,0,,某个时刻 你会调用它 Dialogue: 0,1:04:00.39,1:04:02.75,Default,,0,0,0,,MEMO-PROC把该过程转化为 Dialogue: 0,1:04:02.75,1:04:04.56,Default,,0,0,0,,另一个无参过程 Dialogue: 0,1:04:04.59,1:04:05.80,Default,,0,0,0,,某个时刻你会调用到它 Dialogue: 0,1:04:06.62,1:04:07.42,Default,,0,0,0,,LAMBDA语句做的是这个 Dialogue: 0,1:04:09.89,1:04:14.08,Default,,0,0,0,,所以在这里 我最初构造 Dialogue: 0,1:04:15.85,1:04:17.92,Default,,0,0,0,,构造流的TAIL的时候 Dialogue: 0,1:04:18.30,1:04:20.48,Default,,0,0,0,,这里的这个无参过程 Dialogue: 0,1:04:20.51,1:04:21.61,Default,,0,0,0,,会在之后的某个时刻调用 Dialogue: 0,1:04:24.10,1:04:28.01,Default,,0,0,0,,相对应的 我要对(TAIL STREAM)调用MEMO-PROC Dialogue: 0,1:04:28.12,1:04:29.24,Default,,0,0,0,,以后我会调用生成的过程 Dialogue: 0,1:04:30.65,1:04:31.90,Default,,0,0,0,,所以这个无参的LAMBDA Dialogue: 0,1:04:32.03,1:04:36.06,Default,,0,0,0,,是当你在调用MEMO-PROC时调用的 Dialogue: 0,1:04:38.97,1:04:40.96,Default,,0,0,0,,当你调用MEMP-PROC返回的过程时 Dialogue: 0,1:04:40.97,1:04:42.28,Default,,0,0,0,,也就会像通常的过程调用那样 Dialogue: 0,1:04:42.36,1:04:45.76,Default,,0,0,0,,调用你最初设定的那个函数 Dialogue: 0,1:04:47.64,1:04:48.86,Default,,0,0,0,,学生:我想问的是 Dialogue: 0,1:04:48.86,1:04:50.86,Default,,0,0,0,,当你调用MEMO-PROC的时候 Dialogue: 0,1:04:50.86,1:04:52.30,Default,,0,0,0,,你返回了这个LAMBDA Dialogue: 0,1:04:52.61,1:04:53.07,Default,,0,0,0,,教授:是的 Dialogue: 0,1:04:53.77,1:04:58.10,Default,,0,0,0,,你调用MEMO-PROC的时候 返回了一个LAMBDA Dialogue: 0,1:04:58.10,1:04:59.84,Default,,0,0,0,,直到你第一次需要执行它的时候 Dialogue: 0,1:04:59.87,1:05:02.27,Default,,0,0,0,,你才去求值 Dialogue: 0,1:05:07.76,1:05:09.10,Default,,0,0,0,,学生:我这样理解对吗? Dialogue: 0,1:05:09.18,1:05:11.40,Default,,0,0,0,,你构造了一个表 Dialogue: 0,1:05:11.47,1:05:14.17,Default,,0,0,0,,但表中的元素还没有被求值 Dialogue: 0,1:05:14.24,1:05:15.63,Default,,0,0,0,,表达式没有被求值? Dialogue: 0,1:05:15.63,1:05:18.54,Default,,0,0,0,,但在每个阶段 你还是构造了一个表 Dialogue: 0,1:05:18.54,1:05:20.70,Default,,0,0,0,,教授:啊 我应该这样说 Dialogue: 0,1:05:20.70,1:05:22.27,Default,,0,0,0,,这个想法很好 Dialogue: 0,1:05:22.27,1:05:23.18,Default,,0,0,0,,但是 也不全对 Dialogue: 0,1:05:23.66,1:05:25.08,Default,,0,0,0,,因为实际发生的事情是这样的 Dialogue: 0,1:05:25.08,1:05:26.35,Default,,0,0,0,,我先把这个画成序对 Dialogue: 0,1:05:26.89,1:05:28.03,Default,,0,0,0,,假设我要构造一个特别大的流 Dialogue: 0,1:05:28.96,1:05:30.12,Default,,0,0,0,,比如枚举一段区间 Dialogue: 0,1:05:30.32,1:05:31.48,Default,,0,0,0,,从1到1,000,000,000 Dialogue: 0,1:05:32.74,1:05:35.74,Default,,0,0,0,,这实际上是一个序对 Dialogue: 0,1:05:39.34,1:05:43.36,Default,,0,0,0,,由1和一个PROMISE组成 Dialogue: 0,1:05:46.73,1:05:47.89,Default,,0,0,0,,就是这样 Dialogue: 0,1:05:47.89,1:05:48.76,Default,,0,0,0,,什么都没有构造 Dialogue: 0,1:05:51.60,1:05:53.29,Default,,0,0,0,,当我继续FORCE这个PROMISE Dialogue: 0,1:05:54.51,1:05:56.37,Default,,0,0,0,,再来看看 会发生什么 Dialogue: 0,1:05:56.37,1:05:59.66,Default,,0,0,0,,这个东西现在就成为了一个递归CONS Dialogue: 0,1:06:00.53,1:06:02.16,Default,,0,0,0,,所以这个PROMISE现在就变成了 Dialogue: 0,1:06:04.62,1:06:08.96,Default,,0,0,0,,一个2和做更多事情的PROMISE Dialogue: 0,1:06:11.35,1:06:12.73,Default,,0,0,0,,一直这样下去 Dialogue: 0,1:06:14.47,1:06:17.63,Default,,0,0,0,,直到你走完整个流才完整地构建了一个表 Dialogue: 0,1:06:18.20,1:06:19.58,Default,,0,0,0,,因为这个东西不是表 Dialogue: 0,1:06:20.03,1:06:21.48,Default,,0,0,0,,只是一个生成表的PROMISE Dialogue: 0,1:06:23.39,1:06:25.50,Default,,0,0,0,,技术上来说 PROMISE就是一个过程 Dialogue: 0,1:06:27.80,1:06:29.10,Default,,0,0,0,,因此并没有直接构造好一个表 Dialogue: 0,1:06:30.76,1:06:32.72,Default,,0,0,0,,我应该早点说的 Dialogue: 0,1:06:34.28,1:06:35.34,Default,,0,0,0,,好吧 就到这里 下课 Dialogue: 0,1:06:35.82,1:06:51.15,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:06:35.82,1:06:51.15,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec6a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.01,0:00:02.46,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N张大伟\N(DreamAndDead) Dialogue: 0,0:00:02.60,0:00:10.00,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:10.10,0:00:14.60,Declare,,0,0,0,,{\an2\fad(500,500)}流 I Dialogue: 0,0:00:18.55,0:00:21.84,Default,,0,0,0,,上次Gerry教授揭晓了秘密 Dialogue: 0,0:00:22.49,0:00:24.60,Default,,0,0,0,,他介绍了赋值的概念 Dialogue: 0,0:00:26.35,0:00:33.61,Default,,0,0,0,,赋值与状态 Dialogue: 0,0:00:37.48,0:00:40.03,Default,,0,0,0,,正如我们所见 Dialogue: 0,0:00:40.72,0:00:43.16,Default,,0,0,0,,将赋值和状态引入到语言中 Dialogue: 0,0:00:43.16,0:00:44.41,Default,,0,0,0,,后果相当糟糕 Dialogue: 0,0:00:45.08,0:00:48.62,Default,,0,0,0,,首先 代换模型不再能够描述求值过程了 Dialogue: 0,0:00:49.13,0:00:52.48,Default,,0,0,0,,为了解释程序中语句的语义 Dialogue: 0,0:00:52.48,0:00:54.27,Default,,0,0,0,,我们不得不使用更复杂的环境模型 Dialogue: 0,0:00:54.28,0:00:57.24,Default,,0,0,0,,也就是一种跟图表相关的非常机械的东西 Dialogue: 0,0:00:58.46,0:01:00.12,Default,,0,0,0,,并且 这不单纯地是一个技术上的问题 Dialogue: 0,0:01:00.26,0:01:03.28,Default,,0,0,0,,并不是因为代换模型在这里不怎么有效 Dialogue: 0,0:01:03.60,0:01:05.68,Default,,0,0,0,,所以我们得想些其它办法 Dialogue: 0,0:01:05.71,0:01:09.79,Default,,0,0,0,,而是代换模型这类机制都不再起效 Dialogue: 0,0:01:10.73,0:01:13.32,Default,,0,0,0,,这是因为突然间 一个变量 Dialogue: 0,0:01:14.12,0:01:16.92,Default,,0,0,0,,不再是代表着一个值了 Dialogue: 0,0:01:17.95,0:01:21.76,Default,,0,0,0,,现在 变量用于指明一个位置 Dialogue: 0,0:01:22.40,0:01:23.34,Default,,0,0,0,,一个存放值的位置 Dialogue: 0,0:01:23.63,0:01:26.14,Default,,0,0,0,,并且 这个位置的值可以发生改变 Dialogue: 0,0:01:30.28,0:01:34.09,Default,,0,0,0,,比如像 (F X) 这样的表达式 Dialogue: 0,0:01:37.36,0:01:39.64,Default,,0,0,0,,就可能含有副作用 Dialogue: 0,0:01:40.41,0:01:42.60,Default,,0,0,0,,如果我们执行 (F X) 得到某个值 Dialogue: 0,0:01:43.18,0:01:45.34,Default,,0,0,0,,之后我们再次执行 (F X) Dialogue: 0,0:01:47.24,0:01:48.43,Default,,0,0,0,,可能因为求值的顺序 Dialogue: 0,0:01:48.86,0:01:49.74,Default,,0,0,0,,而得到不同的值 Dialogue: 0,0:01:49.76,0:01:52.14,Default,,0,0,0,,所以突然间 我们不能仅仅关注于值 Dialogue: 0,0:01:52.52,0:01:53.60,Default,,0,0,0,,也要关注时序 Dialogue: 0,0:01:57.97,0:01:59.98,Default,,0,0,0,,序对也不仅仅 Dialogue: 0,0:02:00.65,0:02:02.52,Default,,0,0,0,,只是它的CAR和CDR部分 Dialogue: 0,0:02:02.52,0:02:05.61,Default,,0,0,0,,不是作为CAR部分和CDR部分的别称 Dialogue: 0,0:02:05.80,0:02:07.05,Default,,0,0,0,,它也有自己的“身份” Dialogue: 0,0:02:08.44,0:02:11.65,Default,,0,0,0,,序对具有“身份” Dialogue: 0,0:02:11.65,0:02:12.59,Default,,0,0,0,,它是一个对象 Dialogue: 0,0:02:21.33,0:02:25.15,Default,,0,0,0,,两个具有相同CAR和CDR部分的序对 Dialogue: 0,0:02:25.40,0:02:27.05,Default,,0,0,0,,可能相同也可能不同 Dialogue: 0,0:02:27.87,0:02:30.51,Default,,0,0,0,,因为这之中可能存在“共享” Dialogue: 0,0:02:34.96,0:02:39.45,Default,,0,0,0,,一引入赋值 这些就变成要考虑的问题了 Dialogue: 0,0:02:40.48,0:02:43.98,Default,,0,0,0,,确实 这和我们说讲代换的时候差别悬殊 Dialogue: 0,0:02:45.04,0:02:48.91,Default,,0,0,0,,技术上来看 我们思考起来更加困难了 Dialogue: 0,0:02:48.94,0:02:53.45,Default,,0,0,0,,因为我们必须相当机械地思考程序语言 Dialogue: 0,0:02:53.47,0:02:55.34,Default,,0,0,0,,而不能仅仅用数学的方式来思考 Dialogue: 0,0:02:55.71,0:02:58.60,Default,,0,0,0,,我们也会遇到哲学问题 Dialogue: 0,0:02:59.15,0:03:00.65,Default,,0,0,0,,我们会被这样的问题所困扰: Dialogue: 0,0:03:00.67,0:03:02.38,Default,,0,0,0,,事物的“改变”指的是什么? Dialogue: 0,0:03:02.38,0:03:03.77,Default,,0,0,0,,两个事物“同一”又如何判别? Dialogue: 0,0:03:03.84,0:03:06.83,Default,,0,0,0,,并且 这也会给我们编程带来困扰 Dialogue: 0,0:03:07.47,0:03:08.54,Default,,0,0,0,,正如 Sussman 教授上节课中讲的那样 Dialogue: 0,0:03:08.56,0:03:12.20,Default,,0,0,0,,错误的表达式顺序和别名会产生BUG Dialogue: 0,0:03:12.22,0:03:16.19,Default,,0,0,0,,这些问题在不需要考虑“对象”的语言中 是不存在的 Dialogue: 0,0:03:18.21,0:03:21.20,Default,,0,0,0,,我们是怎样陷入这样的困境的呢? Dialogue: 0,0:03:24.01,0:03:27.20,Default,,0,0,0,,我们这样做的原因在于 Dialogue: 0,0:03:27.40,0:03:31.47,Default,,0,0,0,,我们想要构造模块化的系统 Dialogue: 0,0:03:35.15,0:03:37.69,Default,,0,0,0,,我们想把系统划分为 Dialogue: 0,0:03:38.09,0:03:41.04,Default,,0,0,0,,数个自然组合的小块 Dialogue: 0,0:03:42.76,0:03:43.82,Default,,0,0,0,,举例来说 Dialogue: 0,0:03:44.06,0:03:46.11,Default,,0,0,0,,我们想要构造一个随机数发生器 Dialogue: 0,0:03:46.22,0:03:49.40,Default,,0,0,0,,把该发生器的内部状态封装起来 Dialogue: 0,0:03:50.25,0:03:53.71,Default,,0,0,0,,这样我们就可以把选取随机数 Dialogue: 0,0:03:54.65,0:03:57.79,Default,,0,0,0,,和用于估计的蒙特卡洛方法分离开来 Dialogue: 0,0:03:58.65,0:04:01.52,Default,,0,0,0,,进一步地把它同由 Ceraso 发明的 Dialogue: 0,0:04:01.90,0:04:05.74,Default,,0,0,0,,求取 π 的公式分离开 Dialogue: 0,0:04:06.80,0:04:07.92,Default,,0,0,0,,相似地 Dialogue: 0,0:04:09.61,0:04:11.74,Default,,0,0,0,,当我们着手构建事物的模型时 Dialogue: 0,0:04:12.35,0:04:16.01,Default,,0,0,0,,我们去构建现实世界中事物的模型 Dialogue: 0,0:04:17.31,0:04:19.42,Default,,0,0,0,,我们想把程序组织成许多自然部分 Dialogue: 0,0:04:19.44,0:04:20.52,Default,,0,0,0,,这些部分就是 Dialogue: 0,0:04:21.05,0:04:23.16,Default,,0,0,0,,现实事物的镜像 Dialogue: 0,0:04:24.90,0:04:27.56,Default,,0,0,0,,举个例子 对于一个数字电路 Dialogue: 0,0:04:28.36,0:04:29.18,Default,,0,0,0,,我们会说 Dialogue: 0,0:04:30.44,0:04:31.44,Default,,0,0,0,,这儿有一个电路 Dialogue: 0,0:04:32.08,0:04:35.16,Default,,0,0,0,,它有一个这样的元件 有一个那样的元件 Dialogue: 0,0:04:40.10,0:04:43.58,Default,,0,0,0,,这些元件都有不同的“身份” Dialogue: 0,0:04:43.58,0:04:44.59,Default,,0,0,0,,它们都有各自的状态 Dialogue: 0,0:04:45.55,0:04:47.13,Default,,0,0,0,,状态附着在电路上 Dialogue: 0,0:04:48.58,0:04:50.22,Default,,0,0,0,,我们认为这个元件是一个对象 Dialogue: 0,0:04:50.49,0:04:51.93,Default,,0,0,0,,这个元件又是另外一个不同的对象 Dialogue: 0,0:04:52.54,0:04:53.85,Default,,0,0,0,,当我们观察到系统发生了变化 Dialogue: 0,0:04:53.87,0:04:55.40,Default,,0,0,0,,信号从这里传递过来 Dialogue: 0,0:04:55.63,0:04:58.41,Default,,0,0,0,,改变了可能存放在这里的状态 并向这里继续传播 Dialogue: 0,0:04:58.67,0:05:00.75,Default,,0,0,0,,和一个存储在这里的状态交互 Dialogue: 0,0:05:01.24,0:05:02.17,Default,,0,0,0,,依此类推 Dialogue: 0,0:05:06.86,0:05:11.24,Default,,0,0,0,,我们想要在计算机中 Dialogue: 0,0:05:12.76,0:05:14.36,Default,,0,0,0,,构建模块化的系统 Dialogue: 0,0:05:14.68,0:05:17.87,Default,,0,0,0,,来反映我们对现实的看法 Dialogue: 0,0:05:17.88,0:05:19.87,Default,,0,0,0,,根据我们正在建模的实际系统 Dialogue: 0,0:05:19.88,0:05:20.91,Default,,0,0,0,,来划分子系统 Dialogue: 0,0:05:23.20,0:05:23.48,Default,,0,0,0,,然而 Dialogue: 0,0:05:25.74,0:05:28.99,Default,,0,0,0,,构建像这样的系统 Dialogue: 0,0:05:28.99,0:05:31.50,Default,,0,0,0,,看起来带来了不少技术上的麻烦 Dialogue: 0,0:05:31.52,0:05:32.75,Default,,0,0,0,,但这不是计算机造成的 Dialogue: 0,0:05:33.61,0:05:35.60,Default,,0,0,0,,或许 真正拖累我们 Dialogue: 0,0:05:36.70,0:05:38.65,Default,,0,0,0,,让我们花了那么大的功夫 Dialogue: 0,0:05:38.67,0:05:40.94,Default,,0,0,0,,才让程序反映现实世界的原因 Dialogue: 0,0:05:41.52,0:05:43.13,Default,,0,0,0,,是我们对现实世界的认识出了错 Dialogue: 0,0:05:44.55,0:05:46.75,Default,,0,0,0,,或许时间只是幻觉 Dialogue: 0,0:05:47.26,0:05:48.60,Default,,0,0,0,,什么都没有改变 Dialogue: 0,0:05:50.15,0:05:51.71,Default,,0,0,0,,就拿这个粉笔来说 Dialogue: 0,0:05:52.44,0:05:53.77,Default,,0,0,0,,我们认为它是一个对象 Dialogue: 0,0:05:54.01,0:05:54.99,Default,,0,0,0,,它有自己的状态 Dialogue: 0,0:05:55.82,0:05:59.29,Default,,0,0,0,,每时每刻 它都有一个位置和速度 Dialogue: 0,0:05:59.71,0:06:01.48,Default,,0,0,0,,如果我们做点什么 就可以改变它的状态 Dialogue: 0,0:06:04.34,0:06:07.37,Default,,0,0,0,,但是你如果了解一点相对性的概念 Dialogue: 0,0:06:07.74,0:06:09.71,Default,,0,0,0,,你可能会认为粉笔的路径 Dialogue: 0,0:06:09.72,0:06:11.34,Default,,0,0,0,,不是许多瞬时的离散点 Dialogue: 0,0:06:11.34,0:06:14.38,Default,,0,0,0,,一种深刻的见解是把整个粉笔的存在看作 Dialogue: 0,0:06:14.41,0:06:15.64,Default,,0,0,0,,时空中的路径 Dialogue: 0,0:06:16.02,0:06:17.37,Default,,0,0,0,,全部都展开了 Dialogue: 0,0:06:17.87,0:06:19.84,Default,,0,0,0,,没有单独的位置与速度 Dialogue: 0,0:06:19.84,0:06:23.80,Default,,0,0,0,,在时空中的存在是不会发生改变的 Dialogue: 0,0:06:24.64,0:06:26.51,Default,,0,0,0,,相似地 如果我们来考察这个电气系统 Dialogue: 0,0:06:27.69,0:06:30.43,Default,,0,0,0,,我们假设这个系统实现的是 Dialogue: 0,0:06:30.59,0:06:33.96,Default,,0,0,0,,某种信号处理系统 Dialogue: 0,0:06:34.36,0:06:36.68,Default,,0,0,0,,把这些元件组合在一起的工程师 Dialogue: 0,0:06:36.75,0:06:38.60,Default,,0,0,0,,也不会把它们看作 Dialogue: 0,0:06:38.96,0:06:41.40,Default,,0,0,0,,电压施加于每个独立的元件 Dialogue: 0,0:06:41.49,0:06:43.16,Default,,0,0,0,,转换成了某种东西 Dialogue: 0,0:06:43.34,0:06:45.52,Default,,0,0,0,,影响了这里的状态 Dialogue: 0,0:06:45.53,0:06:46.81,Default,,0,0,0,,还改变了那里的状态 Dialogue: 0,0:06:46.81,0:06:50.11,Default,,0,0,0,,没有一个做信号处理的会这样想 Dialogue: 0,0:06:50.42,0:06:51.84,Default,,0,0,0,,相反 你会说 Dialogue: 0,0:06:54.04,0:06:58.06,Default,,0,0,0,,这里有一个在时间上伸展的信号 Dialogue: 0,0:06:58.06,0:06:59.48,Default,,0,0,0,,如果把这个看作一个滤波器 Dialogue: 0,0:07:00.20,0:07:04.04,Default,,0,0,0,,这个滤波器会把整个信号转化成 Dialogue: 0,0:07:04.28,0:07:07.04,Default,,0,0,0,,不同的输出信号 Dialogue: 0,0:07:09.57,0:07:11.28,Default,,0,0,0,,你们不要把这些东西的状态 Dialogue: 0,0:07:11.28,0:07:13.29,Default,,0,0,0,,想象成在许多瞬间接连发生 Dialogue: 0,0:07:14.16,0:07:17.32,Default,,0,0,0,,我们把这个盒子看作一个整体 Dialogue: 0,0:07:17.32,0:07:20.16,Default,,0,0,0,,而不是在一个特定的瞬间 Dialogue: 0,0:07:20.40,0:07:21.96,Default,,0,0,0,,互相发送状态信息的小系统 Dialogue: 0,0:07:28.25,0:07:29.36,Default,,0,0,0,,今天我们将介绍 Dialogue: 0,0:07:29.39,0:07:31.13,Default,,0,0,0,,另一种分解系统的方法 Dialogue: 0,0:07:31.36,0:07:35.45,Default,,0,0,0,,站在信号工程师的角度去看待现实世界 Dialogue: 0,0:07:35.69,0:07:38.96,Default,,0,0,0,,而不再认为对象间通过消息传递来通信 Dialogue: 0,0:07:41.13,0:07:43.74,Default,,0,0,0,,它被称为“流处理” Dialogue: 0,0:07:54.57,0:07:58.96,Default,,0,0,0,,我们打算展示 Dialogue: 0,0:08:00.59,0:08:04.16,Default,,0,0,0,,如何让我们的程序变得更加统一 Dialogue: 0,0:08:05.15,0:08:06.54,Default,,0,0,0,,从中看到更多的共性 Dialogue: 0,0:08:06.65,0:08:09.88,Default,,0,0,0,,如果我们跳出这些程序 Dialogue: 0,0:08:10.81,0:08:12.30,Default,,0,0,0,,我们会发现 Dialogue: 0,0:08:12.35,0:08:15.12,Default,,0,0,0,,我们对时序的考虑过度了 Dialogue: 0,0:08:16.89,0:08:20.22,Default,,0,0,0,,我们先来对比两个过程 Dialogue: 0,0:08:23.55,0:08:25.69,Default,,0,0,0,,第一个是这样 Dialogue: 0,0:08:25.69,0:08:27.77,Default,,0,0,0,,想像这有一个树 Dialogue: 0,0:08:30.40,0:08:32.14,Default,,0,0,0,,一个由整数构成的树 Dialogue: 0,0:08:33.28,0:08:34.42,Default,,0,0,0,,一个二叉树 Dialogue: 0,0:08:36.12,0:08:36.97,Default,,0,0,0,,这里是1 Dialogue: 0,0:08:39.10,0:08:40.23,Default,,0,0,0,,看起来就像这样 Dialogue: 0,0:08:40.23,0:08:42.92,Default,,0,0,0,,在每个节点上都有一个整数 Dialogue: 0,0:08:45.18,0:08:47.80,Default,,0,0,0,,我们想计算 Dialogue: 0,0:08:48.67,0:08:51.56,Default,,0,0,0,,对这个树中所有的奇数 Dialogue: 0,0:08:52.30,0:08:55.10,Default,,0,0,0,,计算它们的平方和 Dialogue: 0,0:08:57.05,0:08:59.48,Default,,0,0,0,,我们对这类问题很熟悉 Dialogue: 0,0:08:59.48,0:09:01.95,Default,,0,0,0,,有一种递归策略求解它 Dialogue: 0,0:09:02.93,0:09:04.35,Default,,0,0,0,,观察每个叶子节点 Dialogue: 0,0:09:04.56,0:09:06.68,Default,,0,0,0,,如果是奇数我们就求它的平方 并加和 Dialogue: 0,0:09:06.70,0:09:07.77,Default,,0,0,0,,如果是偶数 就是0 Dialogue: 0,0:09:08.68,0:09:12.11,Default,,0,0,0,,递归地看 对于每一颗树 我们可以说 Dialogue: 0,0:09:12.65,0:09:13.84,Default,,0,0,0,,它的平方和等于 Dialogue: 0,0:09:13.92,0:09:15.93,Default,,0,0,0,,右子树的平方和 加上左子树的平方和 Dialogue: 0,0:09:16.25,0:09:17.64,Default,,0,0,0,,就这样沿着节点递归下去 Dialogue: 0,0:09:17.64,0:09:18.70,Default,,0,0,0,,我们已经很熟悉 Dialogue: 0,0:09:19.26,0:09:20.36,Default,,0,0,0,,这种程序设计的思考方式了 Dialogue: 0,0:09:20.36,0:09:22.59,Default,,0,0,0,,我们来幻灯片上看一下 Dialogue: 0,0:09:23.82,0:09:26.75,Default,,0,0,0,,为了计算一棵树中奇数的平方和 Dialogue: 0,0:09:27.37,0:09:29.36,Default,,0,0,0,,我们先要判断它是否是一个叶子节点 Dialogue: 0,0:09:29.82,0:09:31.95,Default,,0,0,0,,判断方法则是考察该节点是否为整数 Dialogue: 0,0:09:32.88,0:09:36.38,Default,,0,0,0,,继而判断其奇偶性 以及是否应该求取平方并加和 Dialogue: 0,0:09:37.16,0:09:38.99,Default,,0,0,0,,然后 整个的解就是 Dialogue: 0,0:09:39.21,0:09:42.12,Default,,0,0,0,,左、右子树解的总和 Dialogue: 0,0:09:46.34,0:09:50.56,Default,,0,0,0,,好的 让我们再来和下面一个问题对比一下 Dialogue: 0,0:09:51.56,0:09:53.68,Default,,0,0,0,,假如给你一个整数N Dialogue: 0,0:09:54.73,0:09:57.88,Default,,0,0,0,,再给定一个函数 把它应用在 Dialogue: 0,0:09:57.93,0:09:58.83,Default,,0,0,0,,1到N的每一个数上 Dialogue: 0,0:09:59.10,0:10:01.08,Default,,0,0,0,,我想把其中的一些值收集成一个表 Dialogue: 0,0:10:01.28,0:10:04.65,Default,,0,0,0,,那些满足某种属性的函数值 Dialogue: 0,0:10:05.60,0:10:06.88,Default,,0,0,0,,这是种一般性的说法 Dialogue: 0,0:10:06.88,0:10:07.98,Default,,0,0,0,,说得更具体一点 Dialogue: 0,0:10:08.62,0:10:10.48,Default,,0,0,0,,假设对于每个整数K Dialogue: 0,0:10:10.65,0:10:12.51,Default,,0,0,0,,计算第K个斐波那契数 Dialogue: 0,0:10:14.21,0:10:16.27,Default,,0,0,0,,然后挑出其中的奇数 Dialogue: 0,0:10:16.83,0:10:18.40,Default,,0,0,0,,并把它们组成一个表 Dialogue: 0,0:10:19.05,0:10:20.71,Default,,0,0,0,,这个过程是这样的 Dialogue: 0,0:10:23.73,0:10:26.24,Default,,0,0,0,,寻找前N个斐波那契数中的奇数 Dialogue: 0,0:10:26.24,0:10:28.91,Default,,0,0,0,,这里是我们一直以来采用的循环方法 Dialogue: 0,0:10:28.91,0:10:29.82,Default,,0,0,0,,用到了递归 Dialogue: 0,0:10:30.80,0:10:31.79,Default,,0,0,0,,以K为循环变量 Dialogue: 0,0:10:32.03,0:10:34.35,Default,,0,0,0,,如果K大于N 返回空表 Dialogue: 0,0:10:35.13,0:10:37.36,Default,,0,0,0,,否则计算第K个斐波那契数 Dialogue: 0,0:10:37.44,0:10:38.06,Default,,0,0,0,,将其与变量F绑定 Dialogue: 0,0:10:40.37,0:10:42.84,Default,,0,0,0,,如果是奇数 我们把它与 Dialogue: 0,0:10:43.76,0:10:46.01,Default,,0,0,0,,从K+1计算得到的表相连接 Dialogue: 0,0:10:47.69,0:10:50.12,Default,,0,0,0,,否则 我们只取从K+1计算得到的结果 Dialogue: 0,0:10:50.73,0:10:53.00,Default,,0,0,0,,这是迭代式循环的标准写法 Dialogue: 0,0:10:53.00,0:10:55.56,Default,,0,0,0,,我们以1为初值 启动这个循环 Dialogue: 0,0:10:57.58,0:11:00.06,Default,,0,0,0,,好的 就是这两个过程 Dialogue: 0,0:11:01.60,0:11:02.90,Default,,0,0,0,,它们看起来非常不同 Dialogue: 0,0:11:02.90,0:11:04.20,Default,,0,0,0,,完全不同的结构 Dialogue: 0,0:11:04.25,0:11:06.89,Default,,0,0,0,,然而 从一个特定的角度来看 Dialogue: 0,0:11:06.92,0:11:09.61,Default,,0,0,0,,两个过程做的事情是一样的 Dialogue: 0,0:11:11.33,0:11:14.67,Default,,0,0,0,,如果我是一个信号处理工程师 Dialogue: 0,0:11:14.70,0:11:16.81,Default,,0,0,0,,我可能会说 Dialogue: 0,0:11:18.24,0:11:26.76,Default,,0,0,0,,第一个过程枚举了树的叶节点 Dialogue: 0,0:11:31.16,0:11:34.56,Default,,0,0,0,,可以认为是信号从一个全是叶节点的地方输出 Dialogue: 0,0:11:35.33,0:11:43.39,Default,,0,0,0,,我们想要过滤出其中的奇数 Dialogue: 0,0:11:43.58,0:11:44.94,Default,,0,0,0,,把它们放入某种滤波器中 Dialogue: 0,0:11:45.19,0:11:47.79,Default,,0,0,0,,然后再把它们放入某种换能器 Dialogue: 0,0:11:49.20,0:11:51.69,Default,,0,0,0,,对每一个输出 我们对其取平方 Dialogue: 0,0:11:54.44,0:11:57.44,Default,,0,0,0,,最后把结果累积在一起 Dialogue: 0,0:11:58.29,0:12:00.04,Default,,0,0,0,,我们以0为初值 Dialogue: 0,0:12:00.35,0:12:03.37,Default,,0,0,0,,通过加法把它们累积起来 Dialogue: 0,0:12:07.14,0:12:08.21,Default,,0,0,0,,这是第一个程序 Dialogue: 0,0:12:08.21,0:12:09.18,Default,,0,0,0,,对于第二个程序 Dialogue: 0,0:12:09.24,0:12:11.21,Default,,0,0,0,,我也可以用一种非常类似的方法来描述 Dialogue: 0,0:12:11.78,0:12:13.42,Default,,0,0,0,,我们枚举 Dialogue: 0,0:12:15.80,0:12:19.10,Default,,0,0,0,,从1到N这个区间上的数 Dialogue: 0,0:12:22.50,0:12:24.40,Default,,0,0,0,,对于每个数 Dialogue: 0,0:12:25.45,0:12:26.92,Default,,0,0,0,,计算对应的斐波那契数 Dialogue: 0,0:12:27.79,0:12:29.27,Default,,0,0,0,,再放入一个换能器 Dialogue: 0,0:12:29.27,0:12:30.78,Default,,0,0,0,,对于输出的结果 Dialogue: 0,0:12:31.31,0:12:34.20,Default,,0,0,0,,再通过奇偶性进行过滤 Dialogue: 0,0:12:36.27,0:12:39.24,Default,,0,0,0,,最后 我们将这些放入累积函数 Dialogue: 0,0:12:39.35,0:12:40.56,Default,,0,0,0,,这次我们要累积出一个表 Dialogue: 0,0:12:40.78,0:12:42.17,Default,,0,0,0,,所以我们用CONS来做积累 Dialogue: 0,0:12:42.59,0:12:43.77,Default,,0,0,0,,以空表为初始值 Dialogue: 0,0:12:47.11,0:12:49.80,Default,,0,0,0,,从这个角度来看 Dialogue: 0,0:12:49.85,0:12:51.84,Default,,0,0,0,,这两个程序真的是太相似了 Dialogue: 0,0:12:51.90,0:12:52.84,Default,,0,0,0,,问题在于 Dialogue: 0,0:12:53.20,0:12:56.49,Default,,0,0,0,,两个程序的写法导致 Dialogue: 0,0:12:56.64,0:12:58.05,Default,,0,0,0,,我们看不出其中的共性 Dialogue: 0,0:12:58.05,0:13:01.44,Default,,0,0,0,,再回头来看奇数平方和的问题 Dialogue: 0,0:13:02.22,0:13:04.64,Default,,0,0,0,,问题来了 哪个是枚举函数呢? Dialogue: 0,0:13:06.35,0:13:08.14,Default,,0,0,0,,程序中哪一部分有枚举的作用? Dialogue: 0,0:13:08.14,0:13:10.52,Default,,0,0,0,,枚举不是仅仅在一个地方表现出来的 Dialogue: 0,0:13:11.02,0:13:15.47,Default,,0,0,0,,在叶子节点的判断处存在一部分 Dialogue: 0,0:13:16.43,0:13:17.16,Default,,0,0,0,,在这个判断循环终止的地方 Dialogue: 0,0:13:17.16,0:13:20.06,Default,,0,0,0,,也下面的递归结构中也有体现 Dialogue: 0,0:13:23.15,0:13:24.12,Default,,0,0,0,,累积函数又在哪儿呢? Dialogue: 0,0:13:24.12,0:13:25.68,Default,,0,0,0,,它也不只在一个地方 Dialogue: 0,0:13:25.68,0:13:30.73,Default,,0,0,0,,它在 0 和 + 这两个地方分别体现出来 Dialogue: 0,0:13:32.00,0:13:34.51,Default,,0,0,0,,累积函数分散在过程的每个部分 Dialogue: 0,0:13:34.51,0:13:39.05,Default,,0,0,0,,相似地 我们来观察奇数斐波那契数的例子 Dialogue: 0,0:13:39.05,0:13:42.80,Default,,0,0,0,,某种意义上 程序中也存在枚举函数与累积函数 Dialogue: 0,0:13:42.80,0:13:44.01,Default,,0,0,0,,但看起来非常不同 Dialogue: 0,0:13:44.62,0:13:50.09,Default,,0,0,0,,枚举部分地表现在(> k n)的判断中 Dialogue: 0,0:13:50.38,0:13:52.84,Default,,0,0,0,,部分地表现在下面的递归调用中 Dialogue: 0,0:13:53.18,0:13:54.24,Default,,0,0,0,,还有就是启动循环的地方 Dialogue: 0,0:13:55.68,0:13:56.32,Default,,0,0,0,,同样地 Dialogue: 0,0:13:56.52,0:13:58.76,Default,,0,0,0,,其中也混杂了累积函数 Dialogue: 0,0:13:58.91,0:14:00.12,Default,,0,0,0,,分别在这里 Dialogue: 0,0:14:00.41,0:14:01.40,Default,,0,0,0,,和这里 Dialogue: 0,0:14:03.60,0:14:06.08,Default,,0,0,0,,所以这些非常自然的部分 Dialogue: 0,0:14:08.73,0:14:12.65,Default,,0,0,0,,我们之前画的那些方框在程序中完全看不出来 Dialogue: 0,0:14:13.26,0:14:14.36,Default,,0,0,0,,因为它们混杂在一起了 Dialogue: 0,0:14:14.36,0:14:16.29,Default,,0,0,0,,这些程序并没有很好地对问题进行切分 Dialogue: 0,0:14:19.45,0:14:22.17,Default,,0,0,0,,回到计算机科学的基本原理上来 Dialogue: 0,0:14:22.19,0:14:23.63,Default,,0,0,0,,为了控制某种东西 Dialogue: 0,0:14:23.63,0:14:24.96,Default,,0,0,0,,你需要它的名字 Dialogue: 0,0:14:25.80,0:14:28.44,Default,,0,0,0,,我们还没有很好地掌握按这种方式来思考 Dialogue: 0,0:14:28.67,0:14:31.06,Default,,0,0,0,,这是因为我们没有显式地操作它们的手段 Dialogue: 0,0:14:31.06,0:14:33.80,Default,,0,0,0,,我们没有一门好的语言来讨论它们 Dialogue: 0,0:14:35.42,0:14:38.86,Default,,0,0,0,,好吧 我们来创造一门合适的语言 Dialogue: 0,0:14:42.52,0:14:44.04,Default,,0,0,0,,用它来构建这些器件 Dialogue: 0,0:14:44.78,0:14:47.21,Default,,0,0,0,,这种语言的关键在于 Dialogue: 0,0:14:47.21,0:14:49.71,Default,,0,0,0,,这些叫作信号的东西到底是什么? Dialogue: 0,0:14:50.48,0:14:53.32,Default,,0,0,0,,这些沿着箭头传递的是什么? Dialogue: 0,0:14:56.88,0:14:57.71,Default,,0,0,0,,这些东西 Dialogue: 0,0:14:59.85,0:15:03.52,Default,,0,0,0,,是一种称作“流”的数据结构 Dialogue: 0,0:15:03.79,0:15:05.87,Default,,0,0,0,,这也是发明这门语言的关键 Dialogue: 0,0:15:07.98,0:15:08.51,Default,,0,0,0,,“流”是什么东西呢? Dialogue: 0,0:15:08.52,0:15:11.50,Default,,0,0,0,,和其它的东西一样 “流”是一种数据抽象 Dialogue: 0,0:15:12.22,0:15:15.82,Default,,0,0,0,,所以 我先说明它的选择函数与构造函数分别是什么 Dialogue: 0,0:15:16.87,0:15:19.48,Default,,0,0,0,,对于流结构 我们有一个构造函数 Dialogue: 0,0:15:19.98,0:15:21.43,Default,,0,0,0,,我们称其为CONS-STREAM Dialogue: 0,0:15:25.69,0:15:28.11,Default,,0,0,0,,CONS-STREAM把两个事物放在一起 Dialogue: 0,0:15:28.59,0:15:30.22,Default,,0,0,0,,构造出一个流 Dialogue: 0,0:15:32.04,0:15:33.85,Default,,0,0,0,,选择函数叫作HEAD Dialogue: 0,0:15:33.98,0:15:36.11,Default,,0,0,0,,用于从流中提取数据 Dialogue: 0,0:15:38.01,0:15:38.86,Default,,0,0,0,,如果我有一个流 Dialogue: 0,0:15:39.00,0:15:40.41,Default,,0,0,0,,我可以取它的头部 Dialogue: 0,0:15:41.13,0:15:42.38,Default,,0,0,0,,也可以取它的尾部 Dialogue: 0,0:15:44.72,0:15:47.42,Default,,0,0,0,,我把和George的约定告诉你 Dialogue: 0,0:15:48.24,0:15:52.70,Default,,0,0,0,,让你们知道和这个相关的公理 Dialogue: 0,0:15:53.44,0:16:00.17,Default,,0,0,0,,对于任何的X与Y Dialogue: 0,0:16:03.40,0:16:05.44,Default,,0,0,0,,如果我把它们构造成一个流 并取其头部 Dialogue: 0,0:16:05.69,0:16:11.96,Default,,0,0,0,,(HEAD (CONS-STREAM X Y)) Dialogue: 0,0:16:13.29,0:16:14.52,Default,,0,0,0,,结果就是X Dialogue: 0,0:16:16.14,0:16:27.45,Default,,0,0,0,,(TAIL (CONS-STREAM X Y)) = Y Dialogue: 0,0:16:28.44,0:16:34.75,Default,,0,0,0,,一个构造函数 两个选择函数 一个公理 就是这些 Dialogue: 0,0:16:34.75,0:16:35.85,Default,,0,0,0,,这里有点可疑 Dialogue: 0,0:16:36.98,0:16:39.00,Default,,0,0,0,,你可能注意到了 Dialogue: 0,0:16:40.19,0:16:42.08,Default,,0,0,0,,这些就是CONS、CAR和CDR的公理 Dialogue: 0,0:16:43.63,0:16:46.56,Default,,0,0,0,,把CONS-STREAM换成CONS Dialogue: 0,0:16:47.10,0:16:49.80,Default,,0,0,0,,HEAD换成CAR TAIL换成CDR Dialogue: 0,0:16:50.76,0:16:52.81,Default,,0,0,0,,这些就是序对的公理 Dialogue: 0,0:16:52.81,0:16:54.32,Default,,0,0,0,,事实上 还有另一个东西 Dialogue: 0,0:16:55.13,0:16:56.80,Default,,0,0,0,,我们有一个叫THE-EMPTY-STREAM(空流)的东西 Dialogue: 0,0:17:02.80,0:17:04.04,Default,,0,0,0,,像空表一样 Dialogue: 0,0:17:08.31,0:17:10.03,Default,,0,0,0,,为什么我要引入这个术语呢? Dialogue: 0,0:17:10.03,0:17:12.12,Default,,0,0,0,,为什么我不继续使用序对与表呢? Dialogue: 0,0:17:12.78,0:17:13.79,Default,,0,0,0,,后面我们就知道了 Dialogue: 0,0:17:15.51,0:17:18.24,Default,,0,0,0,,暂时地 你们可以把术语“流” Dialogue: 0,0:17:18.30,0:17:21.56,Default,,0,0,0,,当作“表”的另一种说法 Dialogue: 0,0:17:21.56,0:17:22.99,Default,,0,0,0,,一会儿我们就会知道 为什么 Dialogue: 0,0:17:23.61,0:17:26.09,Default,,0,0,0,,为什么我们需要这个额外的抽象层 Dialogue: 0,0:17:26.83,0:17:28.15,Default,,0,0,0,,而不是继续把它看做表 Dialogue: 0,0:17:32.30,0:17:33.72,Default,,0,0,0,,好的 有了流之后 Dialogue: 0,0:17:33.74,0:17:35.85,Default,,0,0,0,,我们就开始构建语言的部件了 Dialogue: 0,0:17:37.04,0:17:38.17,Default,,0,0,0,,用它来操作流 Dialogue: 0,0:17:38.75,0:17:42.12,Default,,0,0,0,,我们可以构建出太多有用的东西了 Dialogue: 0,0:17:42.12,0:17:42.81,Default,,0,0,0,,举例来说 Dialogue: 0,0:17:44.89,0:17:49.79,Default,,0,0,0,,我们构建MAP-STREAM 它的一个参数是流S Dialogue: 0,0:17:54.80,0:17:56.62,Default,,0,0,0,,以及一个过程 Dialogue: 0,0:17:57.80,0:17:59.21,Default,,0,0,0,,它会生成一个新的流 Dialogue: 0,0:18:00.14,0:18:02.28,Default,,0,0,0,,它的构成元素是 Dialogue: 0,0:18:02.28,0:18:04.88,Default,,0,0,0,,将PROC应用到S的后续元素得到的结果 Dialogue: 0,0:18:05.87,0:18:07.40,Default,,0,0,0,,我们以前见过类似的 Dialogue: 0,0:18:07.40,0:18:10.24,Default,,0,0,0,,就是以前在表上定义的MAP过程 Dialogue: 0,0:18:10.95,0:18:12.60,Default,,0,0,0,,除了判断EMPTY-STREAM的部分 Dialogue: 0,0:18:12.60,0:18:14.65,Default,,0,0,0,,完全就和MAP一样 Dialogue: 0,0:18:14.65,0:18:15.56,Default,,0,0,0,,哦 我忘了说了 Dialogue: 0,0:18:15.56,0:18:17.15,Default,,0,0,0,,EMPTY-STREAM?就和NULL?差不多 Dialogue: 0,0:18:18.03,0:18:20.48,Default,,0,0,0,,如果是空的 就返回一个空的流 Dialogue: 0,0:18:20.51,0:18:22.28,Default,,0,0,0,,否则 就生成一个新的流 Dialogue: 0,0:18:23.52,0:18:27.18,Default,,0,0,0,,其第一个元素是PROC应用在流头部的结果 Dialogue: 0,0:18:28.51,0:18:29.32,Default,,0,0,0,,剩下的是 Dialogue: 0,0:18:29.60,0:18:32.43,Default,,0,0,0,,是MAP-STREAM对流尾部应用的结果 Dialogue: 0,0:18:33.14,0:18:35.90,Default,,0,0,0,,太像我们之前讲的MAP了 Dialogue: 0,0:18:37.03,0:18:38.20,Default,,0,0,0,,还有一个有用的函数 Dialogue: 0,0:18:38.35,0:18:40.46,Default,,0,0,0,,过滤函数 就是那个用来过滤的盒子 Dialogue: 0,0:18:40.46,0:18:43.89,Default,,0,0,0,,以一个谓词和一个流作为参数 Dialogue: 0,0:18:43.89,0:18:45.08,Default,,0,0,0,,它将生成一个新的流 Dialogue: 0,0:18:45.80,0:18:48.17,Default,,0,0,0,,包含了在流S中所有 Dialogue: 0,0:18:48.33,0:18:49.48,Default,,0,0,0,,满足谓词PRED的元素 Dialogue: 0,0:18:50.38,0:18:51.31,Default,,0,0,0,,这是一个“按条件分析语句” Dialogue: 0,0:18:51.32,0:18:52.73,Default,,0,0,0,,如果流是空的 Dialogue: 0,0:18:53.04,0:18:54.22,Default,,0,0,0,,就返回一个空流 Dialogue: 0,0:18:56.28,0:18:59.18,Default,,0,0,0,,这里 用谓词来判断流的头元素 Dialogue: 0,0:19:00.06,0:19:01.04,Default,,0,0,0,,如果为真 Dialogue: 0,0:19:01.53,0:19:02.83,Default,,0,0,0,,就把这个元素 Dialogue: 0,0:19:03.02,0:19:06.22,Default,,0,0,0,,和过滤流的尾元素得到的结果连接在一起 Dialogue: 0,0:19:08.22,0:19:10.04,Default,,0,0,0,,否则 如果谓词判断为假 Dialogue: 0,0:19:10.49,0:19:11.98,Default,,0,0,0,,就只返回过滤流的尾元素的结果 Dialogue: 0,0:19:13.50,0:19:14.46,Default,,0,0,0,,这就是过滤函数的原理 Dialogue: 0,0:19:16.59,0:19:18.56,Default,,0,0,0,,剩下的我快速过一遍 Dialogue: 0,0:19:18.56,0:19:20.70,Default,,0,0,0,,这些在书上都有 你们可以自己看 Dialogue: 0,0:19:20.88,0:19:21.80,Default,,0,0,0,,来马上过一遍 Dialogue: 0,0:19:22.11,0:19:22.94,Default,,0,0,0,,过程ACCUMULATE Dialogue: 0,0:19:23.26,0:19:26.92,Default,,0,0,0,,ACCUMULATE的参数有:一个组合函数 Dialogue: 0,0:19:27.36,0:19:29.05,Default,,0,0,0,,一个初始值和一个流 Dialogue: 0,0:19:29.96,0:19:31.13,Default,,0,0,0,,将它们组合在一起 Dialogue: 0,0:19:31.56,0:19:33.69,Default,,0,0,0,,如果流为空 返回初始值 Dialogue: 0,0:19:33.97,0:19:36.20,Default,,0,0,0,,否则 我们就把流头部 Dialogue: 0,0:19:36.32,0:19:37.82,Default,,0,0,0,,和流尾部做ACCUMLATE的结果 Dialogue: 0,0:19:38.01,0:19:40.24,Default,,0,0,0,,组合起来 Dialogue: 0,0:19:40.90,0:19:42.83,Default,,0,0,0,,这就是把流中元素累积在一起的方法 Dialogue: 0,0:19:42.83,0:19:43.98,Default,,0,0,0,,我会用加法来累积 Dialogue: 0,0:19:45.83,0:19:47.56,Default,,0,0,0,,如何枚举树上的叶节点呢? Dialogue: 0,0:19:48.06,0:19:52.89,Default,,0,0,0,,如果这个树只是一个叶节点 Dialogue: 0,0:19:53.79,0:19:55.90,Default,,0,0,0,,我就构造一个只含有一个叶子节点的流 Dialogue: 0,0:19:56.64,0:19:59.32,Default,,0,0,0,,否则的话 我就把 Dialogue: 0,0:19:59.61,0:20:02.35,Default,,0,0,0,,左、右子树枚举的结果合并起来 Dialogue: 0,0:20:04.34,0:20:08.32,Default,,0,0,0,,这里的APPEND-STREAM跟表上的APPEND类似 Dialogue: 0,0:20:13.19,0:20:13.85,Default,,0,0,0,,再来看这个 Dialogue: 0,0:20:13.85,0:20:17.53,Default,,0,0,0,,这跟和合并两个表的过程太相似了 Dialogue: 0,0:20:18.91,0:20:20.60,Default,,0,0,0,,如何枚举一个区间呢? Dialogue: 0,0:20:21.96,0:20:23.77,Default,,0,0,0,,它有两个参数 LOW和HIGH Dialogue: 0,0:20:23.88,0:20:27.00,Default,,0,0,0,,生成一个包含从LOW到HIGH的所有整数的流 Dialogue: 0,0:20:28.32,0:20:29.88,Default,,0,0,0,,由此 我们就可以构造一大堆的元件 Dialogue: 0,0:20:31.89,0:20:34.48,Default,,0,0,0,,这就是一门用来讨论流的小型语言 Dialogue: 0,0:20:34.49,0:20:35.32,Default,,0,0,0,,当我们有了流 Dialogue: 0,0:20:35.32,0:20:37.67,Default,,0,0,0,,就可以构建用于操作它们的过程 Dialogue: 0,0:20:37.67,0:20:39.04,Default,,0,0,0,,请注意 我们正在构建一门语言 Dialogue: 0,0:20:40.20,0:20:42.22,Default,,0,0,0,,现在 我们可以用这门语言来表达我们的想法 Dialogue: 0,0:20:43.06,0:20:47.31,Default,,0,0,0,,这个原始过程是累加树中奇数的平方的 Dialogue: 0,0:20:47.31,0:20:52.62,Default,,0,0,0,,现在你会发现 它和那些方块图如出一辙 Dialogue: 0,0:20:52.64,0:20:54.59,Default,,0,0,0,,跟我们的信号处理方块图相吻合 Dialogue: 0,0:20:54.59,0:20:57.53,Default,,0,0,0,,要计算树上奇数平方和 Dialogue: 0,0:20:58.06,0:21:00.80,Default,,0,0,0,,先枚举树上的叶子节点 Dialogue: 0,0:21:01.32,0:21:03.72,Default,,0,0,0,,过滤出奇数 Dialogue: 0,0:21:04.83,0:21:06.54,Default,,0,0,0,,再用平方来做映射 Dialogue: 0,0:21:09.32,0:21:13.34,Default,,0,0,0,,最后用加法来累积 初始值是0 Dialogue: 0,0:21:14.76,0:21:17.20,Default,,0,0,0,,这样我们就可以看到需要的片段 Dialogue: 0,0:21:17.29,0:21:19.36,Default,,0,0,0,,类似地 斐波那契数的那个问题 Dialogue: 0,0:21:20.04,0:21:21.88,Default,,0,0,0,,我们如何获得奇斐波那契数呢? Dialogue: 0,0:21:22.05,0:21:24.57,Default,,0,0,0,,从1到N枚举整数 Dialogue: 0,0:21:26.32,0:21:28.64,Default,,0,0,0,,再把FIB过程映射到上面 Dialogue: 0,0:21:28.99,0:21:30.70,Default,,0,0,0,,用来求取每项斐波那契数 Dialogue: 0,0:21:30.92,0:21:33.79,Default,,0,0,0,,过滤出奇数的部分 Dialogue: 0,0:21:34.81,0:21:36.64,Default,,0,0,0,,最后 以空表为初始值 Dialogue: 0,0:21:36.88,0:21:39.12,Default,,0,0,0,,用CONS将它们积累起来 Dialogue: 0,0:21:43.65,0:21:47.53,Default,,0,0,0,,那么 这么做有什么优势呢? Dialogue: 0,0:21:47.68,0:21:48.59,Default,,0,0,0,,首先一点 Dialogue: 0,0:21:48.68,0:21:51.15,Default,,0,0,0,,我们现在有可以用来混搭的元件了 Dialogue: 0,0:21:51.88,0:21:52.64,Default,,0,0,0,,比如说 Dialogue: 0,0:21:52.91,0:21:55.08,Default,,0,0,0,,如果我想把这里改变一下 Dialogue: 0,0:21:58.19,0:22:00.32,Default,,0,0,0,,想要计算整数的平方再进行过滤 Dialogue: 0,0:22:00.33,0:22:01.34,Default,,0,0,0,,我只需要 Dialogue: 0,0:22:01.90,0:22:03.64,Default,,0,0,0,,拿个像这里的MAP SQUARE这样的元件 Dialogue: 0,0:22:03.68,0:22:05.40,Default,,0,0,0,,放进去就行了 Dialogue: 0,0:22:06.57,0:22:07.60,Default,,0,0,0,,又或者 如果我们想 Dialogue: 0,0:22:07.69,0:22:11.45,Default,,0,0,0,,寻找树的叶节点对应的斐波那契数 Dialogue: 0,0:22:11.58,0:22:12.36,Default,,0,0,0,,而不是一个序列所对应的 Dialogue: 0,0:22:12.38,0:22:13.24,Default,,0,0,0,,我只需要 Dialogue: 0,0:22:13.40,0:22:15.93,Default,,0,0,0,,用这个枚举函数替换这个枚举函数 Dialogue: 0,0:22:18.03,0:22:19.82,Default,,0,0,0,,看到了吧 流处理的优势就是 Dialogue: 0,0:22:20.24,0:22:21.53,Default,,0,0,0,,我们建立了 -- Dialogue: 0,0:22:22.36,0:22:24.96,Default,,0,0,0,,这也是本课中的一个重要主题 -- Dialogue: 0,0:22:25.29,0:22:27.48,Default,,0,0,0,,我们建立了一个约定的接口 Dialogue: 0,0:22:32.89,0:22:37.15,Default,,0,0,0,,约定的接口可以让我们把事物粘合起来 Dialogue: 0,0:22:38.30,0:22:39.55,Default,,0,0,0,,像MAP和FILTER这样的东西 Dialogue: 0,0:22:39.79,0:22:41.64,Default,,0,0,0,,可以作为一组标准的组件 Dialogue: 0,0:22:41.68,0:22:44.76,Default,,0,0,0,,我们可以拿过来随意组合去构造程序 Dialogue: 0,0:22:45.75,0:22:48.81,Default,,0,0,0,,它让我们看到了程序的共性 Dialogue: 0,0:22:49.95,0:22:50.92,Default,,0,0,0,,虽然在这里 Dialogue: 0,0:22:51.08,0:22:53.07,Default,,0,0,0,,我只是给你们演示了两个过程而已 Dialogue: 0,0:22:53.86,0:22:55.16,Default,,0,0,0,,但是我要告诉你 Dialogue: 0,0:22:55.20,0:22:57.77,Default,,0,0,0,,像这种用MAP、FILTER和ACCUMULATE Dialogue: 0,0:22:57.80,0:23:01.00,Default,,0,0,0,,组合起来构建程序的方式是非常非常通用的 Dialogue: 0,0:23:01.41,0:23:07.28,Default,,0,0,0,,这是一种“生成-测试”的编程范式 Dialogue: 0,0:23:07.77,0:23:09.10,Default,,0,0,0,,举例来看 Dialogue: 0,0:23:09.39,0:23:12.94,Default,,0,0,0,,Richarc Waters -- MIT的一名硕士生 Dialogue: 0,0:23:12.96,0:23:15.26,Default,,0,0,0,,他的学位论文的一部分调研了 Dialogue: 0,0:23:15.80,0:23:19.21,Default,,0,0,0,,IBM的科学计算程序库的主要代码 Dialogue: 0,0:23:19.82,0:23:23.31,Default,,0,0,0,,发现其中60%的程序 Dialogue: 0,0:23:24.06,0:23:28.25,Default,,0,0,0,,都可以用这样的范式来准确的表示出来 Dialogue: 0,0:23:28.86,0:23:30.17,Default,,0,0,0,,只用MAP、FILTER和ACCUMULATE Dialogue: 0,0:23:30.57,0:23:31.50,Default,,0,0,0,,好 让我们休息一会 Dialogue: 0,0:23:36.59,0:23:37.12,Default,,0,0,0,,有问题吗? Dialogue: 0,0:23:41.18,0:23:42.89,Default,,0,0,0,,学生:整件事情的本质好像只是 Dialogue: 0,0:23:42.89,0:23:45.96,Default,,0,0,0,,因为你用了一个统一、简单的数据结构 Dialogue: 0,0:23:46.25,0:23:47.66,Default,,0,0,0,,也就是流 Dialogue: 0,0:23:48.38,0:23:48.92,Default,,0,0,0,,教授:对 Dialogue: 0,0:23:48.92,0:23:50.38,Default,,0,0,0,,本质就是 Dialogue: 0,0:23:50.40,0:23:53.07,Default,,0,0,0,,用这种约定的接口 Dialogue: 0,0:23:53.71,0:23:55.61,Default,,0,0,0,,因此你可以把许多东西组合起来 Dialogue: 0,0:23:56.01,0:23:58.78,Default,,0,0,0,,流只是 就像你说的 Dialogue: 0,0:23:58.78,0:24:00.89,Default,,0,0,0,,只是一种可以支持那样操作的统一的数据结构而已 Dialogue: 0,0:24:00.89,0:24:02.84,Default,,0,0,0,,顺便说下 这非常像APL Dialogue: 0,0:24:03.60,0:24:05.21,Default,,0,0,0,,APL有着非常相似的思想 Dialogue: 0,0:24:05.21,0:24:06.96,Default,,0,0,0,,只是在APL中使用的不是流 Dialogue: 0,0:24:07.13,0:24:08.44,Default,,0,0,0,,而是使用数组和向量 Dialogue: 0,0:24:09.56,0:24:14.48,Default,,0,0,0,,而且APL的威力就在于此 Dialogue: 0,0:24:19.91,0:24:20.91,Default,,0,0,0,,好吧 谢谢 Dialogue: 0,0:24:20.91,0:24:21.66,Default,,0,0,0,,休息一下 Dialogue: 0,0:24:21.66,0:24:30.35,Default,,0,0,0,,[音乐] Dialogue: 0,0:24:30.44,0:24:35.77,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:24:41.00,0:24:45.39,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:24:45.42,0:24:47.96,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:24:47.98,0:24:52.70,Declare,,0,0,0,,{\an2\fad(500,500)}流 I Dialogue: 0,0:24:57.47,0:24:57.61,Default,,0,0,0,,好的 Dialogue: 0,0:24:57.61,0:24:58.59,Default,,0,0,0,,我们已经见识过了 Dialogue: 0,0:25:00.54,0:25:03.20,Default,,0,0,0,,如何用流来组织计算过程 Dialogue: 0,0:25:03.85,0:25:05.47,Default,,0,0,0,,但是现在我想要给你们再演示两个 Dialogue: 0,0:25:05.93,0:25:09.12,Default,,0,0,0,,更复杂的例子 Dialogue: 0,0:25:10.84,0:25:14.12,Default,,0,0,0,,我们先来考虑一下 Dialogue: 0,0:25:14.20,0:25:16.81,Default,,0,0,0,,这样一种有用的过程 Dialogue: 0,0:25:16.81,0:25:18.09,Default,,0,0,0,,假设我有一个流 Dialogue: 0,0:25:19.96,0:25:23.15,Default,,0,0,0,,流中的元素本身就是一个流 Dialogue: 0,0:25:23.98,0:25:26.53,Default,,0,0,0,,一开始是1、2、3 Dialogue: 0,0:25:32.72,0:25:33.88,Default,,0,0,0,,就是这样的一个流 Dialogue: 0,0:25:33.88,0:25:40.10,Default,,0,0,0,,流中的元素也是一个流 Dialogue: 0,0:25:40.97,0:25:43.42,Default,,0,0,0,,而我想要构建出一个流 Dialogue: 0,0:25:43.64,0:25:46.75,Default,,0,0,0,,用来收集所有的元素 Dialogue: 0,0:25:46.76,0:25:49.24,Default,,0,0,0,,把所有元素从子流中提取出来 Dialogue: 0,0:25:50.11,0:25:51.82,Default,,0,0,0,,最后把它们串接在一起 Dialogue: 0,0:25:52.27,0:25:55.61,Default,,0,0,0,,为了凸显使用这门语言多么简单 Dialogue: 0,0:25:56.11,0:25:57.10,Default,,0,0,0,,我们来定义这个FLATTEN过程 Dialogue: 0,0:25:57.95,0:26:10.64,Default,,0,0,0,,FLATTEN过程的参数是由流构成的流 Dialogue: 0,0:26:12.89,0:26:13.80,Default,,0,0,0,,那么 具体定义是怎样的呢? Dialogue: 0,0:26:13.96,0:26:16.24,Default,,0,0,0,,它只是一个累积 Dialogue: 0,0:26:16.32,0:26:25.05,Default,,0,0,0,,我想用APPEND来做累积 Dialogue: 0,0:26:25.07,0:26:26.45,Default,,0,0,0,,也就是不断地做APPEND Dialogue: 0,0:26:26.73,0:26:29.29,Default,,0,0,0,,所以我用APPEND-STREAM做累积 Dialogue: 0,0:26:35.90,0:26:48.20,Default,,0,0,0,,以THE-EMPTY-STREAM为初始值 累积这个流 Dialogue: 0,0:26:54.84,0:26:55.84,Default,,0,0,0,,这个例子告诉我们 Dialogue: 0,0:26:56.92,0:26:59.23,Default,,0,0,0,,你可以使用这些高阶过程 Dialogue: 0,0:26:59.60,0:27:00.83,Default,,0,0,0,,来做一些有趣的运算 Dialogue: 0,0:27:00.83,0:27:05.10,Default,,0,0,0,,事实上 我还想定义另一个实用过程 Dialogue: 0,0:27:05.10,0:27:07.05,Default,,0,0,0,,定义一个过程FLAT-MAP Dialogue: 0,0:27:17.18,0:27:20.59,Default,,0,0,0,,它以一个过程和一个流为参数 Dialogue: 0,0:27:21.84,0:27:25.72,Default,,0,0,0,,其中S是一个流 Dialogue: 0,0:27:25.72,0:27:27.69,Default,,0,0,0,,F是一个过程 Dialogue: 0,0:27:27.72,0:27:30.62,Default,,0,0,0,,它作用于流中的每个元素 并产生一个新的流 Dialogue: 0,0:27:31.95,0:27:34.52,Default,,0,0,0,,我想从这些流中取出所有的元素 Dialogue: 0,0:27:35.00,0:27:36.00,Default,,0,0,0,,并把它们组合在一起 Dialogue: 0,0:27:36.00,0:27:49.13,Default,,0,0,0,,所以对应的代码就是 (FLATTEN (MAP F S)) Dialogue: 0,0:27:51.20,0:27:53.04,Default,,0,0,0,,每当我将F应用在S的某个元素上 Dialogue: 0,0:27:53.05,0:27:53.85,Default,,0,0,0,,我得到了一个流 Dialogue: 0,0:27:54.29,0:27:55.24,Default,,0,0,0,,执行完这条MAP语句后 Dialogue: 0,0:27:55.24,0:27:56.27,Default,,0,0,0,,我得到了一个由流构成的流 Dialogue: 0,0:27:56.46,0:27:57.42,Default,,0,0,0,,再把它进行FLATTEN Dialogue: 0,0:27:58.67,0:28:02.64,Default,,0,0,0,,我想再使用这种方式 Dialogue: 0,0:28:03.87,0:28:05.84,Default,,0,0,0,,来解决另一个大家很熟悉的问题 Dialogue: 0,0:28:06.51,0:28:12.27,Default,,0,0,0,,这个问题和我们以前遇到过的许多问题一样 Dialogue: 0,0:28:12.28,0:28:13.96,Default,,0,0,0,,只是有些变型 Dialogue: 0,0:28:14.19,0:28:15.49,Default,,0,0,0,,给定整数N Dialogue: 0,0:28:18.68,0:28:19.93,Default,,0,0,0,,我们的问题是 Dialogue: 0,0:28:21.20,0:28:31.53,Default,,0,0,0,,找出所有的整数序对(I, J) Dialogue: 0,0:28:32.30,0:28:39.96,Default,,0,0,0,,其中 0 < J < I <= N Dialogue: 0,0:28:42.33,0:28:52.03,Default,,0,0,0,,使得 I+J 是一个质数 Dialogue: 0,0:28:55.74,0:28:57.92,Default,,0,0,0,,如果N=6 Dialogue: 0,0:28:59.74,0:29:00.78,Default,,0,0,0,,我在这儿画个小表格 Dialogue: 0,0:29:01.55,0:29:06.67,Default,,0,0,0,,表头是I、J和I+J Dialogue: 0,0:29:09.70,0:29:14.91,Default,,0,0,0,,比如说I=2 J=1 那么I+J就是3 Dialogue: 0,0:29:15.52,0:29:20.38,Default,,0,0,0,,然后I=3 J=2 那么I+J就是5 Dialogue: 0,0:29:21.21,0:29:26.51,Default,,0,0,0,,I=4 J=1 I+J=5也是一样的 等等 Dialogue: 0,0:29:26.92,0:29:28.11,Default,,0,0,0,,直到I到了6就终止了 Dialogue: 0,0:29:28.40,0:29:32.54,Default,,0,0,0,,我想要这个过程产生并返回这样的一个流 Dialogue: 0,0:29:33.20,0:29:37.04,Default,,0,0,0,,就是像 (I, J, I+J) 这样的三元组组成的流 Dialogue: 0,0:29:37.66,0:29:39.55,Default,,0,0,0,,对于每个整数N 我想得到一个这样流 Dialogue: 0,0:29:40.97,0:29:43.68,Default,,0,0,0,,听起来很简单 Dialogue: 0,0:29:43.68,0:29:44.35,Default,,0,0,0,,我们做做看 Dialogue: 0,0:29:47.23,0:29:48.22,Default,,0,0,0,,先这样开始 Dialogue: 0,0:29:50.15,0:29:54.25,Default,,0,0,0,,对于每一个整数 I Dialogue: 0,0:29:55.24,0:29:56.44,Default,,0,0,0,,生成一个流 Dialogue: 0,0:29:57.00,0:29:58.59,Default,,0,0,0,,对于I从1取到N Dialogue: 0,0:29:58.59,0:29:59.76,Default,,0,0,0,,每个I都生成一个流 Dialogue: 0,0:30:00.66,0:30:01.80,Default,,0,0,0,,这个流将会是什么样子? Dialogue: 0,0:30:02.23,0:30:04.04,Default,,0,0,0,,我们先生成所有的序对 Dialogue: 0,0:30:04.18,0:30:07.55,Default,,0,0,0,,对于每个I 我们先生成 Dialogue: 0,0:30:08.43,0:30:14.52,Default,,0,0,0,,对于每个从1取到I-1的J Dialogue: 0,0:30:16.91,0:30:17.98,Default,,0,0,0,,我们先生成序对 Dialogue: 0,0:30:18.35,0:30:20.71,Default,,0,0,0,,也就是只含有I和J的表 Dialogue: 0,0:30:23.78,0:30:27.10,Default,,0,0,0,,因此我们对整个区间做映射 Dialogue: 0,0:30:28.60,0:30:29.74,Default,,0,0,0,,生成序对 Dialogue: 0,0:30:31.07,0:30:33.17,Default,,0,0,0,,对于每个I 都生成一个序对流 Dialogue: 0,0:30:33.40,0:30:34.49,Default,,0,0,0,,最后进行FLATMAP Dialogue: 0,0:30:34.59,0:30:36.20,Default,,0,0,0,,这样我们就生成了所有的(I, J)序对 Dialogue: 0,0:30:36.81,0:30:38.08,Default,,0,0,0,,其中I <= J Dialogue: 0,0:30:38.73,0:30:39.85,Default,,0,0,0,,就是这样 Dialogue: 0,0:30:39.85,0:30:40.76,Default,,0,0,0,,紧接着就是过滤 Dialogue: 0,0:30:42.99,0:30:45.84,Default,,0,0,0,,我们对刚才FLATMAP得到的东西 Dialogue: 0,0:30:46.94,0:30:51.37,Default,,0,0,0,,我们以I -- 这里分别是 I 和 J Dialogue: 0,0:30:51.66,0:30:54.17,Default,,0,0,0,,I是表的第一个元素 Dialogue: 0,0:30:54.30,0:30:55.60,Default,,0,0,0,,J是第二个 Dialogue: 0,0:30:57.21,0:31:00.01,Default,,0,0,0,,我们用一个谓词来判断 表中的两个元素 Dialogue: 0,0:31:00.22,0:31:02.00,Default,,0,0,0,,也就是表的CAR部分与CDR部分之和 是否为质数 Dialogue: 0,0:31:02.07,0:31:05.52,Default,,0,0,0,,用这个谓词来过滤刚刚收集起来的表 Dialogue: 0,0:31:06.54,0:31:07.85,Default,,0,0,0,,就得到了我们想要的表 Dialogue: 0,0:31:09.42,0:31:10.24,Default,,0,0,0,,然后我们继续 Dialogue: 0,0:31:10.88,0:31:13.10,Default,,0,0,0,,把过滤得到的结果 再次进行MAP操作 Dialogue: 0,0:31:13.26,0:31:19.05,Default,,0,0,0,,用来生成 I、J 和 I+J 构成的表 Dialogue: 0,0:31:19.61,0:31:21.39,Default,,0,0,0,,这就是过程 PRIME-SUM-PAIRS Dialogue: 0,0:31:22.57,0:31:24.76,Default,,0,0,0,,最后只需要过一遍 这就是整个过程 Dialogue: 0,0:31:28.08,0:31:30.97,Default,,0,0,0,,一个MAP、一个FILTER 以及一个FLATMAP Dialogue: 0,0:31:34.85,0:31:35.66,Default,,0,0,0,,所有的东西都在这里了 Dialogue: 0,0:31:35.66,0:31:37.12,Default,,0,0,0,,尽管可读性不是那么好 Dialogue: 0,0:31:37.42,0:31:38.94,Default,,0,0,0,,我们只是把中间过程展开了 Dialogue: 0,0:31:39.84,0:31:40.88,Default,,0,0,0,,这个例子 Dialogue: 0,0:31:43.28,0:31:45.00,Default,,0,0,0,,向我们展示了 Dialogue: 0,0:31:45.12,0:31:46.30,Default,,0,0,0,,嵌套循环 Dialogue: 0,0:31:47.66,0:31:50.09,Default,,0,0,0,,在这个过程中 它看起来就像 Dialogue: 0,0:31:50.11,0:31:52.81,Default,,0,0,0,,各种嵌套的MAP和FLATMAP的组合 Dialogue: 0,0:31:54.27,0:31:57.61,Default,,0,0,0,,所以我们不仅仅可以枚举单个个体 Dialogue: 0,0:31:57.61,0:31:58.81,Default,,0,0,0,,通过使用FLATMAP Dialogue: 0,0:31:59.12,0:32:02.24,Default,,0,0,0,,我们可以实现其它语言中的嵌套循环 Dialogue: 0,0:32:03.23,0:32:03.76,Default,,0,0,0,,当然 Dialogue: 0,0:32:04.91,0:32:08.03,Default,,0,0,0,,重复写这些FLATMAP很烦人 Dialogue: 0,0:32:08.41,0:32:13.00,Default,,0,0,0,,尽管PRIME-SUM-PAIRS其中单独的部分很容易 Dialogue: 0,0:32:13.56,0:32:15.28,Default,,0,0,0,,但整体看起来还是十分复杂 Dialogue: 0,0:32:15.48,0:32:17.13,Default,,0,0,0,,如果你愿意的话 可以 Dialogue: 0,0:32:17.15,0:32:20.12,Default,,0,0,0,,引进一个叫COLLECT的语法糖衣 Dialogue: 0,0:32:21.04,0:32:22.68,Default,,0,0,0,,COLLECT只是一个缩写 Dialogue: 0,0:32:22.91,0:32:26.16,Default,,0,0,0,,用来代表特定顺序的FLATMAP和FILTER操作 Dialogue: 0,0:32:26.16,0:32:28.60,Default,,0,0,0,,这里我们用COLLECT把PRIME-SUM-PAIRS写一遍 Dialogue: 0,0:32:29.45,0:32:36.27,Default,,0,0,0,,PRIME-SUM-PAIRS过程需要收集这样一个东西 Dialogue: 0,0:32:36.52,0:32:39.20,Default,,0,0,0,,它的元素是形如(I, J, I+J)这样的表 Dialogue: 0,0:32:40.84,0:32:45.39,Default,,0,0,0,,而这将通过I从1取到N Dialogue: 0,0:32:47.44,0:32:52.32,Default,,0,0,0,,同时J要从1取到I-1来产生 Dialogue: 0,0:32:54.16,0:32:56.54,Default,,0,0,0,,并且要满足I+J是质数 Dialogue: 0,0:32:58.04,0:33:00.32,Default,,0,0,0,,课堂上我就不讲解如何定义COLLECT了 Dialogue: 0,0:33:00.69,0:33:02.75,Default,,0,0,0,,书上面有 Dialogue: 0,0:33:03.42,0:33:05.45,Default,,0,0,0,,不过你可以清楚地看到 这些代码片段 Dialogue: 0,0:33:05.84,0:33:08.60,Default,,0,0,0,,就是我原先写的过程中的片段 Dialogue: 0,0:33:08.82,0:33:11.40,Default,,0,0,0,,COLLECT过程只是一个语法糖衣 Dialogue: 0,0:33:11.44,0:33:14.80,Default,,0,0,0,,用来自动生成嵌套FLATMAP Dialogue: 0,0:33:16.31,0:33:20.33,Default,,0,0,0,,好的 我们再来看另一个例子 Dialogue: 0,0:33:20.67,0:33:22.00,Default,,0,0,0,,也展示了同样的道理 Dialogue: 0,0:33:22.12,0:33:23.53,Default,,0,0,0,,这是一个非常著名的问题 Dialogue: 0,0:33:24.70,0:33:28.75,Default,,0,0,0,,经常用来演示所谓的“回溯”算法 Dialogue: 0,0:33:28.76,0:33:30.20,Default,,0,0,0,,这就是“八皇后问题” Dialogue: 0,0:33:30.20,0:33:31.08,Default,,0,0,0,,这是一个棋盘 Dialogue: 0,0:33:32.37,0:33:33.64,Default,,0,0,0,,八皇后问题要求我们 Dialogue: 0,0:33:33.64,0:33:35.85,Default,,0,0,0,,找到一种将八个皇后放到棋盘上的摆法 Dialogue: 0,0:33:36.44,0:33:38.00,Default,,0,0,0,,使得任意的两个皇后不会相互攻击 Dialogue: 0,0:33:38.00,0:33:40.60,Default,,0,0,0,,这里给出了一个解法 Dialogue: 0,0:33:41.21,0:33:43.68,Default,,0,0,0,,我需要保证摆放好后 Dialogue: 0,0:33:43.71,0:33:46.80,Default,,0,0,0,,任意两个皇后不在同一行或同一列上 Dialogue: 0,0:33:47.72,0:33:49.47,Default,,0,0,0,,也不在同一对角线上 Dialogue: 0,0:33:51.41,0:33:56.40,Default,,0,0,0,,有一个解决这个问题的标准解法 Dialogue: 0,0:33:59.74,0:34:01.48,Default,,0,0,0,,首先我们要做是 Dialogue: 0,0:34:02.54,0:34:04.62,Default,,0,0,0,,进入底层 站在George的层面 Dialogue: 0,0:34:04.94,0:34:08.09,Default,,0,0,0,,找到一种表示棋盘与位置的方式 Dialogue: 0,0:34:08.09,0:34:09.52,Default,,0,0,0,,这个并不需要太担心 Dialogue: 0,0:34:09.80,0:34:12.78,Default,,0,0,0,,假设我们有一个谓词SAFE? Dialogue: 0,0:34:16.14,0:34:17.55,Default,,0,0,0,,SAFE?判断的是 Dialogue: 0,0:34:17.96,0:34:20.84,Default,,0,0,0,,假如一些皇后已经放在棋盘上 Dialogue: 0,0:34:21.36,0:34:24.54,Default,,0,0,0,,在这个点再放置一个皇后是否是安全? Dialogue: 0,0:34:25.40,0:34:31.26,Default,,0,0,0,,所以SAFE?的参数分别为ROW和COLUMN Dialogue: 0,0:34:32.76,0:34:35.47,Default,,0,0,0,,我将尝试把下一个皇后放在那个地方 Dialogue: 0,0:34:36.06,0:34:42.76,Default,,0,0,0,,另外一个参数是剩下的位置 Dialogue: 0,0:34:45.58,0:34:46.75,Default,,0,0,0,,SAFE?要判断的是 Dialogue: 0,0:34:46.86,0:34:51.68,Default,,0,0,0,,在这些位置已经放置了皇后的情况下 Dialogue: 0,0:34:53.02,0:34:54.76,Default,,0,0,0,,在这行这列放置皇后 Dialogue: 0,0:34:55.10,0:34:57.20,Default,,0,0,0,,是否安全 Dialogue: 0,0:34:58.30,0:34:59.36,Default,,0,0,0,,不用过分深究这个 Dialogue: 0,0:34:59.36,0:35:01.38,Default,,0,0,0,,那是George的问题 也不难写出来 Dialogue: 0,0:35:01.38,0:35:06.27,Default,,0,0,0,,只需要检测该行、该列 Dialogue: 0,0:35:06.30,0:35:08.52,Default,,0,0,0,,以及对角线上是否有东西即可 Dialogue: 0,0:35:10.53,0:35:13.12,Default,,0,0,0,,那么 有了这个过程后 我们的程序该如何组织呢? Dialogue: 0,0:35:13.84,0:35:17.21,Default,,0,0,0,,有一种传统的方式 Dialogue: 0,0:35:17.93,0:35:18.97,Default,,0,0,0,,我们称为“回溯” Dialogue: 0,0:35:20.52,0:35:23.21,Default,,0,0,0,,首先让我们来考虑 Dialogue: 0,0:35:25.13,0:35:28.88,Default,,0,0,0,,把第一个皇后放在第一列的 Dialogue: 0,0:35:30.04,0:35:31.34,Default,,0,0,0,,所有方式 Dialogue: 0,0:35:31.45,0:35:32.24,Default,,0,0,0,,有8种 Dialogue: 0,0:35:32.58,0:35:35.00,Default,,0,0,0,,先试下第一列 Dialogue: 0,0:35:35.88,0:35:37.30,Default,,0,0,0,,第一行第一列 Dialogue: 0,0:35:37.30,0:35:38.70,Default,,0,0,0,,每个分支都代表了 Dialogue: 0,0:35:40.17,0:35:41.88,Default,,0,0,0,,在每一个层次的可能解 Dialogue: 0,0:35:43.36,0:35:45.53,Default,,0,0,0,,我试着把皇后放在第一列 Dialogue: 0,0:35:46.14,0:35:47.74,Default,,0,0,0,,现在 我在第一列放置好一个皇后以后 Dialogue: 0,0:35:47.77,0:35:49.98,Default,,0,0,0,,我又尝试在第一列放置下一个皇后 Dialogue: 0,0:35:50.60,0:35:52.17,Default,,0,0,0,,并不成功 它们都…… Dialogue: 0,0:35:53.31,0:35:54.60,Default,,0,0,0,,我尝试把第一个皇后 Dialogue: 0,0:35:54.86,0:35:56.80,Default,,0,0,0,,把在第一列上的那个皇后 放在第一行 Dialogue: 0,0:35:56.92,0:35:57.47,Default,,0,0,0,,不好意思 Dialogue: 0,0:35:59.05,0:36:01.39,Default,,0,0,0,,放好后 我们再把下一个皇后放在第一行 Dialogue: 0,0:36:01.39,0:36:02.09,Default,,0,0,0,,这不行 Dialogue: 0,0:36:02.09,0:36:03.18,Default,,0,0,0,,所以又回到这里 Dialogue: 0,0:36:04.20,0:36:04.72,Default,,0,0,0,,然后再考虑 Dialogue: 0,0:36:04.83,0:36:06.86,Default,,0,0,0,,我们把这个皇后放在第二行吗? Dialogue: 0,0:36:07.32,0:36:08.38,Default,,0,0,0,,然而也不行 Dialogue: 0,0:36:08.55,0:36:09.76,Default,,0,0,0,,那么放在第三行呢? Dialogue: 0,0:36:09.76,0:36:10.52,Default,,0,0,0,,这样可以 Dialogue: 0,0:36:12.79,0:36:15.13,Default,,0,0,0,,下一个皇后可以放在第一列吗? Dialogue: 0,0:36:15.38,0:36:17.82,Default,,0,0,0,,我不能再画更多的棋盘了 Dialogue: 0,0:36:17.82,0:36:18.86,Default,,0,0,0,,但我先假设这个可行 Dialogue: 0,0:36:19.19,0:36:20.45,Default,,0,0,0,,我尝试下一个 Dialogue: 0,0:36:20.45,0:36:24.17,Default,,0,0,0,,在每一个地方 尽可能的沿着树往下 Dialogue: 0,0:36:24.54,0:36:25.64,Default,,0,0,0,,然后回退 Dialogue: 0,0:36:25.64,0:36:28.97,Default,,0,0,0,,如果我从这里往下走 发现下面不可能有解 Dialogue: 0,0:36:29.00,0:36:30.12,Default,,0,0,0,,我就回溯到这里来 Dialogue: 0,0:36:30.28,0:36:32.44,Default,,0,0,0,,然后开始生成这个子树 Dialogue: 0,0:36:33.26,0:36:34.32,Default,,0,0,0,,我就像这样遍历 Dialogue: 0,0:36:35.05,0:36:37.26,Default,,0,0,0,,最后 一路求解下来 Dialogue: 0,0:36:37.72,0:36:38.59,Default,,0,0,0,,就会得到答案 Dialogue: 0,0:36:39.82,0:36:41.98,Default,,0,0,0,,这种典型的范式 Dialogue: 0,0:36:43.12,0:36:45.93,Default,,0,0,0,,之前被广泛地使用在人工智能编程中 Dialogue: 0,0:36:45.93,0:36:47.30,Default,,0,0,0,,术语叫做 “回溯搜索” Dialogue: 0,0:36:57.47,0:37:03.04,Default,,0,0,0,,这真的没有必要 Dialogue: 0,0:37:03.86,0:37:06.55,Default,,0,0,0,,你们也发现了 我在可视化这个过程时也犯了迷糊 Dialogue: 0,0:37:06.81,0:37:08.25,Default,,0,0,0,,你们也看到了复杂程度 Dialogue: 0,0:37:08.55,0:37:10.76,Default,,0,0,0,,而且这种复杂还很难描述 Dialogue: 0,0:37:10.76,0:37:11.82,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:37:12.39,0:37:13.29,Default,,0,0,0,,这是因为 Dialogue: 0,0:37:13.53,0:37:17.39,Default,,0,0,0,,这是因为这程序过分地关注于时间了 Dialogue: 0,0:37:18.58,0:37:20.43,Default,,0,0,0,,这之中太多 -- 先试试这个 再试试这个 Dialogue: 0,0:37:20.49,0:37:22.38,Default,,0,0,0,,再回到上一个可行的地方 -- 这种操作太多了 Dialogue: 0,0:37:22.89,0:37:24.34,Default,,0,0,0,,这很复杂 Dialogue: 0,0:37:24.34,0:37:26.36,Default,,0,0,0,,如果我们不再如此关注时间 Dialogue: 0,0:37:28.04,0:37:29.76,Default,,0,0,0,,就有一个更简单的方式来描述 Dialogue: 0,0:37:31.20,0:37:32.36,Default,,0,0,0,,让我们来想象一下 Dialogue: 0,0:37:33.31,0:37:36.57,Default,,0,0,0,,现在我有 Dialogue: 0,0:37:38.32,0:37:42.16,Default,,0,0,0,,有一个高达K-1层的树 Dialogue: 0,0:37:43.40,0:37:46.32,Default,,0,0,0,,假设我已经有了 Dialogue: 0,0:37:48.09,0:37:52.19,Default,,0,0,0,,把皇后放在前K列的所有解法 Dialogue: 0,0:37:53.56,0:37:54.61,Default,,0,0,0,,假设是这样 Dialogue: 0,0:37:54.61,0:37:55.79,Default,,0,0,0,,不要担心我是怎么得到的 Dialogue: 0,0:37:57.07,0:37:59.20,Default,,0,0,0,,现在 如何扩充下去呢? Dialogue: 0,0:37:59.20,0:38:02.16,Default,,0,0,0,,怎样找到在下一列中放皇后的所有可行方法? Dialogue: 0,0:38:02.48,0:38:03.13,Default,,0,0,0,,很简单 Dialogue: 0,0:38:03.62,0:38:06.41,Default,,0,0,0,,对于已有的位置 Dialogue: 0,0:38:07.82,0:38:13.96,Default,,0,0,0,,我考虑把下一个皇后放在每一行上 Dialogue: 0,0:38:15.08,0:38:16.16,Default,,0,0,0,,来构建出下一步的棋局 Dialogue: 0,0:38:16.16,0:38:17.29,Default,,0,0,0,,然后 把所有放置的位置 Dialogue: 0,0:38:17.44,0:38:19.71,Default,,0,0,0,,用SAFE?进行过滤 Dialogue: 0,0:38:21.80,0:38:22.99,Default,,0,0,0,,不像之前那样 Dialogue: 0,0:38:22.99,0:38:24.67,Default,,0,0,0,,把这个树看做是逐步生成的 Dialogue: 0,0:38:24.94,0:38:26.86,Default,,0,0,0,,我们假设所有的东西都生成好了 Dialogue: 0,0:38:29.68,0:38:32.41,Default,,0,0,0,,为了从K-1层扩展到K层 Dialogue: 0,0:38:32.64,0:38:36.24,Default,,0,0,0,,我只需要扩展所有可能的放置方法 Dialogue: 0,0:38:36.48,0:38:37.80,Default,,0,0,0,,最后保留安全的排列 Dialogue: 0,0:38:37.80,0:38:39.23,Default,,0,0,0,,就得到一个K层树的结果 Dialogue: 0,0:38:39.30,0:38:40.67,Default,,0,0,0,,这是解决八皇后问题 Dialogue: 0,0:38:40.89,0:38:42.17,Default,,0,0,0,,的一个递归策略 Dialogue: 0,0:38:44.53,0:38:45.34,Default,,0,0,0,,好的 我们来看看 Dialogue: 0,0:38:50.33,0:38:52.68,Default,,0,0,0,,我们编写子过程FILL-COLS Dialogue: 0,0:38:53.00,0:38:55.53,Default,,0,0,0,,来解决在一个特定大小棋盘上的 Dialogue: 0,0:38:58.92,0:39:01.03,Default,,0,0,0,,八皇后问题 Dialogue: 0,0:39:01.13,0:39:04.86,Default,,0,0,0,,这个过程会把皇后放置到K个列中 Dialogue: 0,0:39:06.35,0:39:07.70,Default,,0,0,0,,这是递归的模式 Dialogue: 0,0:39:07.70,0:39:10.92,Default,,0,0,0,,最后会以棋盘的大小为参数 调用FILL-COLS Dialogue: 0,0:39:12.99,0:39:15.28,Default,,0,0,0,,FILL-COLS是用来说明 Dialogue: 0,0:39:15.29,0:39:17.16,Default,,0,0,0,,如何安全地把皇后放置在 Dialogue: 0,0:39:17.20,0:39:19.58,Default,,0,0,0,,具有SIZE行的棋盘的前K列 Dialogue: 0,0:39:20.36,0:39:21.64,Default,,0,0,0,,如果K是0 Dialogue: 0,0:39:22.27,0:39:23.60,Default,,0,0,0,,就不用做什么 Dialogue: 0,0:39:23.94,0:39:25.93,Default,,0,0,0,,结果是一个空棋盘 Dialogue: 0,0:39:26.71,0:39:28.07,Default,,0,0,0,,否则就做点别的 Dialogue: 0,0:39:28.35,0:39:29.44,Default,,0,0,0,,这里将要使用COLLECT Dialogue: 0,0:39:30.81,0:39:31.77,Default,,0,0,0,,完整的代码在这里 Dialogue: 0,0:39:34.33,0:39:41.91,Default,,0,0,0,,我找到了所有在前K-1列中放皇后的方法 Dialogue: 0,0:39:42.19,0:39:43.32,Default,,0,0,0,,这是我所假设的 Dialogue: 0,0:39:43.32,0:39:46.36,Default,,0,0,0,,想像这棵树下降到K-1层 Dialogue: 0,0:39:48.88,0:39:52.11,Default,,0,0,0,,然后我尝试每一行 Dialogue: 0,0:39:52.52,0:39:54.13,Default,,0,0,0,,尝试每一个可行的行 Dialogue: 0,0:39:54.13,0:39:55.04,Default,,0,0,0,,总共SIZE行 Dialogue: 0,0:39:55.31,0:39:56.49,Default,,0,0,0,,这里枚举了所有行数 Dialogue: 0,0:39:58.04,0:39:59.79,Default,,0,0,0,,现在要做的是 Dialogue: 0,0:40:03.15,0:40:05.82,Default,,0,0,0,,把我将要尝试的新行和第K列 Dialogue: 0,0:40:07.95,0:40:08.95,Default,,0,0,0,,收集起来 Dialogue: 0,0:40:08.95,0:40:10.09,Default,,0,0,0,,我邻接一个位置 Dialogue: 0,0:40:10.20,0:40:11.29,Default,,0,0,0,,这是George的问题了 Dialogue: 0,0:40:11.29,0:40:12.75,Default,,0,0,0,,实现ADJOIN-POSITION和SAFE?都是George的工作 Dialogue: 0,0:40:13.64,0:40:15.28,Default,,0,0,0,,这个过程需要的参数有 Dialogue: 0,0:40:15.50,0:40:17.04,Default,,0,0,0,,ROW、COL以及REST-OF-POS Dialogue: 0,0:40:17.07,0:40:19.02,Default,,0,0,0,,然后返回位置的集合 Dialogue: 0,0:40:19.66,0:40:25.77,Default,,0,0,0,,我把新的行和列 Dialogue: 0,0:40:26.06,0:40:27.68,Default,,0,0,0,,和剩下的皇后邻接起来 Dialogue: 0,0:40:28.57,0:40:29.76,Default,,0,0,0,,那些剩下的皇后 Dialogue: 0,0:40:29.92,0:40:31.45,Default,,0,0,0,,会尝试所有的 Dialogue: 0,0:40:31.87,0:40:34.16,Default,,0,0,0,,放置在K-1列中的可行解 Dialogue: 0,0:40:34.62,0:40:37.04,Default,,0,0,0,,新的行遍历了所有的可能性 Dialogue: 0,0:40:37.85,0:40:40.76,Default,,0,0,0,,过滤出安全的位置 Dialogue: 0,0:40:43.24,0:40:44.70,Default,,0,0,0,,这就是整个程序了 Dialogue: 0,0:40:46.33,0:40:47.31,Default,,0,0,0,,整个过程 Dialogue: 0,0:40:49.84,0:40:52.43,Default,,0,0,0,,它不仅找到了八皇后的问题的解 Dialogue: 0,0:40:53.42,0:40:56.68,Default,,0,0,0,,它还给出了所有的解 Dialogue: 0,0:40:56.68,0:40:58.48,Default,,0,0,0,,运行结束之后 就得到一个流 Dialogue: 0,0:40:58.48,0:41:01.90,Default,,0,0,0,,流中的元素是所有的解 Dialogue: 0,0:41:05.31,0:41:06.26,Default,,0,0,0,,为什么这个更简单一点呢? Dialogue: 0,0:41:06.26,0:41:08.54,Default,,0,0,0,,我们完全没有把这个当做 Dialogue: 0,0:41:08.88,0:41:11.52,Default,,0,0,0,,按时间发生的、具有状态的过程 Dialogue: 0,0:41:12.72,0:41:14.42,Default,,0,0,0,,我们只说 这是一些东西的集合 Dialogue: 0,0:41:14.94,0:41:16.00,Default,,0,0,0,,这是它更加简单的原因 Dialogue: 0,0:41:18.00,0:41:20.11,Default,,0,0,0,,我们已经转变了观念 Dialogue: 0,0:41:20.11,0:41:22.59,Default,,0,0,0,,还记得吗 这节课开始我们就讲过 Dialogue: 0,0:41:22.82,0:41:26.23,Default,,0,0,0,,我们转变了建模的观念 Dialogue: 0,0:41:26.23,0:41:29.20,Default,,0,0,0,,我们不再把事物看做按时间演进 Dialogue: 0,0:41:29.37,0:41:31.31,Default,,0,0,0,,也不再具有不同的阶段与状态 Dialogue: 0,0:41:31.75,0:41:33.79,Default,,0,0,0,,取而代之的是 我们对全局进行建模 Dialogue: 0,0:41:33.80,0:41:35.93,Default,,0,0,0,,我们关注粉笔的整个飞行过程 Dialogue: 0,0:41:36.28,0:41:38.88,Default,,0,0,0,,而不是专注于每个瞬时状态 Dialogue: 0,0:41:40.75,0:41:41.44,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:41:44.08,0:41:46.20,Default,,0,0,0,,学生:在我看来回溯会 Dialogue: 0,0:41:46.22,0:41:48.96,Default,,0,0,0,,搜索到它所能找到的第一个解 Dialogue: 0,0:41:49.31,0:41:51.48,Default,,0,0,0,,而这个递归搜索 Dialogue: 0,0:41:51.48,0:41:53.26,Default,,0,0,0,,会去寻找所有的解 Dialogue: 0,0:41:53.32,0:41:53.60,Default,,0,0,0,,教授:是这样的 Dialogue: 0,0:41:54.03,0:41:55.26,Default,,0,0,0,,学生:但问题是 Dialogue: 0,0:41:55.26,0:41:57.92,Default,,0,0,0,,如果需要搜索的空间足够的大 Dialogue: 0,0:41:57.92,0:42:00.92,Default,,0,0,0,,第二种搜索方式就会变得不现实 Dialogue: 0,0:42:01.36,0:42:05.93,Default,,0,0,0,,教授:呃 这个问题其实是 Dialogue: 0,0:42:07.13,0:42:08.44,Default,,0,0,0,,这一节课剩下的内容 Dialogue: 0,0:42:08.57,0:42:10.54,Default,,0,0,0,,这个问题很好 Dialogue: 0,0:42:13.87,0:42:15.74,Default,,0,0,0,,先不要尝试去预知后面的课 Dialogue: 0,0:42:15.96,0:42:19.23,Default,,0,0,0,,只是在现在 你们要保持谨慎 Dialogue: 0,0:42:19.84,0:42:21.84,Default,,0,0,0,,这里确实有点奇怪 难道不是么? Dialogue: 0,0:42:22.22,0:42:24.51,Default,,0,0,0,,尽管这个看起来不错 但是难道它不低效吗? Dialogue: 0,0:42:24.83,0:42:26.03,Default,,0,0,0,,这是我们待会儿要解决的问题 Dialogue: 0,0:42:28.10,0:42:30.02,Default,,0,0,0,,就让我们稍后来揭晓秘密吧 Dialogue: 0,0:42:33.35,0:42:34.60,Default,,0,0,0,,好吧 休息一下 Dialogue: 0,0:42:34.60,0:42:44.51,Default,,0,0,0,,[音乐] Dialogue: 0,0:42:44.51,0:42:49.04,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:43:10.57,0:43:17.05,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:43:17.05,0:43:21.21,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:43:21.21,0:43:25.21,Declare,,0,0,0,,{\an2\fad(500,500)} 流 I Dialogue: 0,0:43:29.65,0:43:33.76,Default,,0,0,0,,你可能现在开始怀疑了 Dialogue: 0,0:43:35.60,0:43:39.26,Default,,0,0,0,,我已经展示了这种简单而优雅的 Dialogue: 0,0:43:40.51,0:43:42.28,Default,,0,0,0,,组合程序的方法 Dialogue: 0,0:43:42.86,0:43:46.91,Default,,0,0,0,,这跟那些传统程序非常不同 Dialogue: 0,0:43:46.92,0:43:48.19,Default,,0,0,0,,那些求奇数的平方和 Dialogue: 0,0:43:48.72,0:43:51.32,Default,,0,0,0,,或者求奇数项斐波那契数之类的程序 Dialogue: 0,0:43:53.74,0:43:55.48,Default,,0,0,0,,也不像那些混合了 Dialogue: 0,0:43:55.85,0:43:58.84,Default,,0,0,0,,枚举函数、过滤函数和累积函数的程序 Dialogue: 0,0:44:00.44,0:44:01.82,Default,,0,0,0,,通过把它们混合起来 Dialogue: 0,0:44:02.20,0:44:04.59,Default,,0,0,0,,通过这种混搭式的 Dialogue: 0,0:44:04.62,0:44:07.34,Default,,0,0,0,,组合程序的方法 Dialogue: 0,0:44:07.82,0:44:09.53,Default,,0,0,0,,我们并没有获得 Dialogue: 0,0:44:09.55,0:44:11.77,Default,,0,0,0,,流式程序设计的理论优势 Dialogue: 0,0:44:13.80,0:44:14.25,Default,,0,0,0,,另一方面 Dialogue: 0,0:44:14.28,0:44:16.88,Default,,0,0,0,,你们所见过的大多数程序是那种丑陋的风格 Dialogue: 0,0:44:18.34,0:44:18.94,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:44:19.20,0:44:20.59,Default,,0,0,0,,难道计算机科学家们 Dialogue: 0,0:44:21.16,0:44:24.30,Default,,0,0,0,,愚蠢得无以复加 Dialogue: 0,0:44:25.42,0:44:26.44,Default,,0,0,0,,以至于他们没有注意到这个现象么? Dialogue: 0,0:44:27.07,0:44:28.75,Default,,0,0,0,,如果你仅仅只是做了这些事 Dialogue: 0,0:44:29.63,0:44:31.93,Default,,0,0,0,,你就能让程序变得极其优雅么? Dialogue: 0,0:44:33.62,0:44:34.78,Default,,0,0,0,,肯定有什么缺陷 Dialogue: 0,0:44:36.76,0:44:39.05,Default,,0,0,0,,事实上这一缺陷也很容易发现 Dialogue: 0,0:44:39.51,0:44:41.74,Default,,0,0,0,,我们来看看接下来的这个问题 Dialogue: 0,0:44:42.03,0:44:45.47,Default,,0,0,0,,假设我让你去找 Dialogue: 0,0:44:46.16,0:44:48.16,Default,,0,0,0,,1,000到1,000,000之间的第二个素数 Dialogue: 0,0:44:49.12,0:44:50.56,Default,,0,0,0,,如果你的计算机性能更强劲的话 Dialogue: 0,0:44:50.59,0:44:53.05,Default,,0,0,0,,或者可以去找10,000到100,000,000之间的 Dialogue: 0,0:44:54.32,0:44:55.45,Default,,0,0,0,,你可能觉得这很容易 Dialogue: 0,0:44:55.47,0:44:56.65,Default,,0,0,0,,我可以用流来解决 Dialogue: 0,0:44:57.08,0:44:59.87,Default,,0,0,0,,我需要做的就是 Dialogue: 0,0:45:00.57,0:45:02.89,Default,,0,0,0,,从10,000枚举到1,000,000 Dialogue: 0,0:45:04.16,0:45:06.51,Default,,0,0,0,,我就获得了从10,000到1,000,000的所有整数 Dialogue: 0,0:45:06.80,0:45:08.64,Default,,0,0,0,,我过滤出所有的质数 Dialogue: 0,0:45:09.39,0:45:11.10,Default,,0,0,0,,也就是对这些数做素性检测 Dialogue: 0,0:45:11.76,0:45:12.83,Default,,0,0,0,,然后从中取出第二个元素 Dialogue: 0,0:45:12.84,0:45:14.04,Default,,0,0,0,,也就是 TAIL的HEAD部分 Dialogue: 0,0:45:15.79,0:45:17.38,Default,,0,0,0,,这显然是非常荒谬的 Dialogue: 0,0:45:21.66,0:45:23.20,Default,,0,0,0,,我们的机器没有这么大的空间 Dialogue: 0,0:45:23.58,0:45:25.24,Default,,0,0,0,,来存放这些整数 Dialogue: 0,0:45:25.28,0:45:26.35,Default,,0,0,0,,更别说来测试它们了 Dialogue: 0,0:45:27.04,0:45:28.64,Default,,0,0,0,,而且我也只是取第二个数而已 Dialogue: 0,0:45:29.81,0:45:34.94,Default,,0,0,0,,这种传统程序设计风格的威力 Dialogue: 0,0:45:36.43,0:45:37.68,Default,,0,0,0,,(虽然)也正是其弱点 Dialogue: 0,0:45:37.96,0:45:38.94,Default,,0,0,0,,这种程序设计风格 Dialogue: 0,0:45:39.61,0:45:43.50,Default,,0,0,0,,混合了枚举、测试以及累积 Dialogue: 0,0:45:44.88,0:45:46.46,Default,,0,0,0,,我们不需要做全部的事 Dialogue: 0,0:45:46.67,0:45:49.18,Default,,0,0,0,,所以说 实际上这是这种 Dialogue: 0,0:45:49.45,0:45:51.74,Default,,0,0,0,,概念上丑陋的风格 Dialogue: 0,0:45:52.20,0:45:53.80,Default,,0,0,0,,正是让它运行起来高效 Dialogue: 0,0:45:54.91,0:45:55.84,Default,,0,0,0,,就是像这样来混合 Dialogue: 0,0:45:57.80,0:45:59.34,Default,,0,0,0,,我今天一早上所做的好像都是在 Dialogue: 0,0:45:59.34,0:46:00.42,Default,,0,0,0,,把你们搞糊涂一样 Dialogue: 0,0:46:00.42,0:46:03.10,Default,,0,0,0,,我为你们展示了一种貌似可行的优雅程序设计方法 Dialogue: 0,0:46:03.10,0:46:03.96,Default,,0,0,0,,但它却不可行 Dialogue: 0,0:46:05.84,0:46:08.32,Default,,0,0,0,,但是 接下来就是见证奇迹的时刻 Dialogue: 0,0:46:09.04,0:46:10.57,Default,,0,0,0,,结果却是 这个游戏里 Dialogue: 0,0:46:11.21,0:46:13.84,Default,,0,0,0,,我们真的可以得到蛋糕并吃掉它 Dialogue: 0,0:46:14.87,0:46:16.11,Default,,0,0,0,,我的意思是 Dialogue: 0,0:46:18.09,0:46:21.15,Default,,0,0,0,,我们完全可以用流来组织程序 Dialogue: 0,0:46:21.16,0:46:22.48,Default,,0,0,0,,就像我之前编写的那样 Dialogue: 0,0:46:23.55,0:46:27.74,Default,,0,0,0,,以至于当机器真正运行的时候 Dialogue: 0,0:46:28.33,0:46:31.52,Default,,0,0,0,,它可以和传统风格的程序一样高效 Dialogue: 0,0:46:31.71,0:46:34.28,Default,,0,0,0,,那些混合了生成与测试的程序 Dialogue: 0,0:46:36.16,0:46:38.80,Default,,0,0,0,,听起来不可思议 Dialogue: 0,0:46:40.77,0:46:41.82,Default,,0,0,0,,关键在就于 Dialogue: 0,0:46:42.00,0:46:43.69,Default,,0,0,0,,流不是表 Dialogue: 0,0:46:48.09,0:46:49.79,Default,,0,0,0,,一会儿我们就会看到 但是现在 Dialogue: 0,0:46:49.80,0:46:51.77,Default,,0,0,0,,先让我们来看看幻灯片 Dialogue: 0,0:46:52.24,0:46:53.80,Default,,0,0,0,,你们对这个 Dialogue: 0,0:46:53.84,0:46:55.58,Default,,0,0,0,,信号处理系统的印象是 Dialogue: 0,0:46:57.26,0:46:58.72,Default,,0,0,0,,你们认为要发生的是 Dialogue: 0,0:46:59.13,0:47:00.92,Default,,0,0,0,,在这类盒子中 Dialogue: 0,0:47:01.18,0:47:03.58,Default,,0,0,0,,事先产生好了整数 Dialogue: 0,0:47:05.36,0:47:06.40,Default,,0,0,0,,这里有个过滤函数 Dialogue: 0,0:47:07.45,0:47:09.37,Default,,0,0,0,,它和那个盒子相连 并从中拉取东西 Dialogue: 0,0:47:10.94,0:47:13.15,Default,,0,0,0,,这里还有人从这整个系统中 Dialogue: 0,0:47:13.31,0:47:14.91,Default,,0,0,0,,拉取东西 Dialogue: 0,0:47:16.79,0:47:18.70,Default,,0,0,0,,你们应该这么来理解: Dialogue: 0,0:47:18.99,0:47:20.72,Default,,0,0,0,,有人想要得到第一个质数 Dialogue: 0,0:47:22.67,0:47:24.14,Default,,0,0,0,,他从这个过滤函数这儿拉取 Dialogue: 0,0:47:24.59,0:47:26.12,Default,,0,0,0,,FILTER从枚举函数中去拉取 Dialogue: 0,0:47:28.02,0:47:29.15,Default,,0,0,0,,你只需要在固定范围内寻找 Dialogue: 0,0:47:29.16,0:47:30.93,Default,,0,0,0,,然后从里面取出第二个数 Dialogue: 0,0:47:30.93,0:47:31.95,Default,,0,0,0,,第二个质数是多少? Dialogue: 0,0:47:33.71,0:47:35.37,Default,,0,0,0,,没有额外的计算 Dialogue: 0,0:47:35.37,0:47:36.64,Default,,0,0,0,,只要你不去拉取东西 Dialogue: 0,0:47:36.64,0:47:38.32,Default,,0,0,0,,就不会产生进行额外计算 Dialogue: 0,0:47:40.50,0:47:41.41,Default,,0,0,0,,我来用实物演示一下 Dialogue: 0,0:47:41.41,0:47:43.88,Default,,0,0,0,,这个小设备 Dialogue: 0,0:47:43.90,0:47:44.97,Default,,0,0,0,,这是个小型的流机器 Dialogue: 0,0:47:45.50,0:47:46.83,Default,,0,0,0,,这是Eric Grimson发明的 Dialogue: 0,0:47:47.60,0:47:49.24,Default,,0,0,0,,他也在MIT教这门课 Dialogue: 0,0:47:49.83,0:47:52.51,Default,,0,0,0,,实际的流程是 -- 这里有某种流 Dialogue: 0,0:47:52.54,0:47:53.82,Default,,0,0,0,,就像一串整数一样 Dialogue: 0,0:47:54.78,0:47:56.33,Default,,0,0,0,,这些是一些处理单元 Dialogue: 0,0:47:58.70,0:48:02.60,Default,,0,0,0,,就像是FILTER、MAP之类的东西 Dialogue: 0,0:48:03.98,0:48:09.18,Default,,0,0,0,,如果我把流实现为表 来进行处理 Dialogue: 0,0:48:09.24,0:48:11.26,Default,,0,0,0,,我拥有的是一个表 Dialogue: 0,0:48:11.47,0:48:12.67,Default,,0,0,0,,现在 我先执行第一个过滤函数 Dialogue: 0,0:48:12.67,0:48:14.07,Default,,0,0,0,,我像这样完全处理 Dialogue: 0,0:48:14.88,0:48:15.77,Default,,0,0,0,,针对这个流 Dialogue: 0,0:48:16.32,0:48:19.21,Default,,0,0,0,,不断地处理、处理、处理、处理 Dialogue: 0,0:48:19.61,0:48:21.05,Default,,0,0,0,,然后得到一个新的流 Dialogue: 0,0:48:21.63,0:48:24.07,Default,,0,0,0,,现在 我把得到的结果拿在我手中 Dialogue: 0,0:48:24.07,0:48:25.26,Default,,0,0,0,,然后把它放进第二个 Dialogue: 0,0:48:25.56,0:48:26.94,Default,,0,0,0,,又处理了全部的流 Dialogue: 0,0:48:28.27,0:48:29.51,Default,,0,0,0,,得到一个新流 Dialogue: 0,0:48:32.13,0:48:33.36,Default,,0,0,0,,然后我再把结果 Dialogue: 0,0:48:34.28,0:48:36.36,Default,,0,0,0,,用相同的方式再次处理 Dialogue: 0,0:48:36.36,0:48:40.99,Default,,0,0,0,,如果仅仅把流当做表的话 Dialogue: 0,0:48:41.69,0:48:42.97,Default,,0,0,0,,计算的过程就是这样的 Dialogue: 0,0:48:43.86,0:48:45.64,Default,,0,0,0,,但是事实上 流不是表 流就是流 Dialogue: 0,0:48:45.82,0:48:48.11,Default,,0,0,0,,而你们应该这样来想像 Dialogue: 0,0:48:50.23,0:48:52.52,Default,,0,0,0,,我把这些小玩意连接起来 Dialogue: 0,0:48:55.26,0:48:56.76,Default,,0,0,0,,数据在其中流动 Dialogue: 0,0:49:00.33,0:49:02.30,Default,,0,0,0,,这里是流的源头 Dialogue: 0,0:49:02.32,0:49:02.92,Default,,0,0,0,,它可能在 Dialogue: 0,0:49:04.19,0:49:05.72,Default,,0,0,0,,产生一些整数 Dialogue: 0,0:49:05.98,0:49:07.39,Default,,0,0,0,,如果我想要拉取一个结果 会发生什么? Dialogue: 0,0:49:07.58,0:49:08.91,Default,,0,0,0,,我从尾部这里拉取 Dialogue: 0,0:49:10.20,0:49:11.07,Default,,0,0,0,,而这个单元会说 Dialogue: 0,0:49:11.08,0:49:12.20,Default,,0,0,0,,我需要更多的数据 Dialogue: 0,0:49:13.09,0:49:15.52,Default,,0,0,0,,所以 它就到这个单元去拉取数据 Dialogue: 0,0:49:15.83,0:49:17.39,Default,,0,0,0,,它说:“我需要更多的数据” Dialogue: 0,0:49:17.89,0:49:19.56,Default,,0,0,0,,然后这个又从下一个单元拉取 Dialogue: 0,0:49:19.56,0:49:20.28,Default,,0,0,0,,可能是一个过滤函数 Dialogue: 0,0:49:20.28,0:49:21.40,Default,,0,0,0,,从它那里取得更多数据 Dialogue: 0,0:49:21.64,0:49:23.15,Default,,0,0,0,,我在这一端拉取数据时 Dialogue: 0,0:49:23.53,0:49:25.56,Default,,0,0,0,,只会生成这么多的数据 Dialogue: 0,0:49:25.78,0:49:28.30,Default,,0,0,0,,我在另一端请求一定量的数据时 Dialogue: 0,0:49:28.56,0:49:29.98,Default,,0,0,0,,只有相当数量的数据被生成并处理 Dialogue: 0,0:49:30.76,0:49:32.09,Default,,0,0,0,,这就是你们需要知道的 Dialogue: 0,0:49:32.80,0:49:34.38,Default,,0,0,0,,把流实现为表 Dialogue: 0,0:49:34.56,0:49:35.92,Default,,0,0,0,,和流真实的工作方式 Dialogue: 0,0:49:36.16,0:49:37.50,Default,,0,0,0,,的区别 Dialogue: 0,0:49:40.78,0:49:42.14,Default,,0,0,0,,那么 到底怎么来实现呢? Dialogue: 0,0:49:42.35,0:49:43.32,Default,,0,0,0,,知道了流的真实工作方式 Dialogue: 0,0:49:43.40,0:49:44.52,Default,,0,0,0,,构造流有什么窍门呢? Dialogue: 0,0:49:47.93,0:49:50.32,Default,,0,0,0,,我们想要把流组织成 Dialogue: 0,0:49:50.41,0:49:51.58,Default,,0,0,0,,一种数据结构 Dialogue: 0,0:49:52.00,0:49:54.22,Default,,0,0,0,,它能够增量式地计算自己 Dialogue: 0,0:49:54.22,0:49:56.22,Default,,0,0,0,,一种“按需”数据结构 Dialogue: 0,0:49:58.96,0:50:00.51,Default,,0,0,0,,基本思想在于 Dialogue: 0,0:50:00.97,0:50:02.70,Default,,0,0,0,,再次强调 这是贯穿整个课程的 Dialogue: 0,0:50:02.72,0:50:04.12,Default,,0,0,0,,几大基本思想之一 Dialogue: 0,0:50:04.49,0:50:05.00,Default,,0,0,0,,这就是 Dialogue: 0,0:50:05.52,0:50:06.97,Default,,0,0,0,,数据与过程之间 Dialogue: 0,0:50:06.99,0:50:08.44,Default,,0,0,0,,并没有绝对的界限 Dialogue: 0,0:50:09.24,0:50:10.54,Default,,0,0,0,,流会是这样的一种结构 Dialogue: 0,0:50:10.59,0:50:13.40,Default,,0,0,0,,它既是一种传统意义上的“数据结构” Dialogue: 0,0:50:13.45,0:50:15.92,Default,,0,0,0,,比如树的叶子结点组成的流 Dialogue: 0,0:50:16.86,0:50:17.85,Default,,0,0,0,,但是同时 Dialogue: 0,0:50:17.85,0:50:19.32,Default,,0,0,0,,它又是一种非常聪明的过程 Dialogue: 0,0:50:20.24,0:50:22.22,Default,,0,0,0,,它包含了如何计算的方法 Dialogue: 0,0:50:23.74,0:50:25.93,Default,,0,0,0,,好吧 实际来看一下 Dialogue: 0,0:50:25.93,0:50:26.62,Default,,0,0,0,,事实上 Dialogue: 0,0:50:26.80,0:50:28.33,Default,,0,0,0,,我们不需要其它的机制 Dialogue: 0,0:50:28.46,0:50:29.87,Default,,0,0,0,,我们已经有了所需要的一切东西 Dialogue: 0,0:50:30.14,0:50:30.99,Default,,0,0,0,,这是因为 Dialogue: 0,0:50:31.02,0:50:33.93,Default,,0,0,0,,我们已经能够 把过程当作第一级对象来处理了 Dialogue: 0,0:50:35.46,0:50:36.88,Default,,0,0,0,,来看看这个关键之处 Dialogue: 0,0:50:36.88,0:50:39.03,Default,,0,0,0,,关键在于 -- 回想一下 我们有这些运算 Dialogue: 0,0:50:39.03,0:50:47.52,Default,,0,0,0,,CONS-STREAM、HEAD和TAIL Dialogue: 0,0:50:48.08,0:50:49.36,Default,,0,0,0,,刚开始的时候我说 Dialogue: 0,0:50:49.92,0:50:51.36,Default,,0,0,0,,你们可以把这个看作CONS Dialogue: 0,0:50:51.40,0:50:52.62,Default,,0,0,0,,把HEAD看作CAR Dialogue: 0,0:50:52.62,0:50:53.52,Default,,0,0,0,,把TAIL看作CDR Dialogue: 0,0:50:53.55,0:50:54.16,Default,,0,0,0,,事实上没这么简单 Dialogue: 0,0:50:55.08,0:50:56.32,Default,,0,0,0,,现在 来看看它们到底是什么 Dialogue: 0,0:50:57.71,0:51:05.84,Default,,0,0,0,,(CONS-STREAM X Y) Dialogue: 0,0:51:07.48,0:51:17.79,Default,,0,0,0,,是这个东西的缩写形式 Dialogue: 0,0:51:19.54,0:51:28.32,Default,,0,0,0,,(CONS X (DELAY Y)) Dialogue: 0,0:51:31.68,0:51:33.53,Default,,0,0,0,,我先把它们写完再来解释 Dialogue: 0,0:51:34.52,0:51:35.53,Default,,0,0,0,,而(HEAD S) Dialogue: 0,0:51:38.09,0:51:39.79,Default,,0,0,0,,就是 (CAR S) Dialogue: 0,0:51:42.38,0:51:44.25,Default,,0,0,0,,而(TAIL S) Dialogue: 0,0:51:46.68,0:51:54.60,Default,,0,0,0,,则是(FORCE (CDR S)) Dialogue: 0,0:51:56.12,0:51:57.04,Default,,0,0,0,,我来解释一下 Dialogue: 0,0:51:58.06,0:51:59.88,Default,,0,0,0,,DELAY是一个特殊而神奇的东西 Dialogue: 0,0:52:01.42,0:52:02.33,Default,,0,0,0,,DELAY所做是 Dialogue: 0,0:52:03.85,0:52:05.31,Default,,0,0,0,,取一个表达式 Dialogue: 0,0:52:05.50,0:52:06.86,Default,,0,0,0,,然后产生一个PROMISE Dialogue: 0,0:52:07.12,0:52:09.15,Default,,0,0,0,,在你有需要时 这个PROMISE会计算那个表达式 Dialogue: 0,0:52:10.60,0:52:11.98,Default,,0,0,0,,但在此时没有做任何计算 Dialogue: 0,0:52:11.98,0:52:14.32,Default,,0,0,0,,只是一个延期的PROMISE Dialogue: 0,0:52:14.82,0:52:16.20,Default,,0,0,0,,承诺要做这样的事 Dialogue: 0,0:52:17.11,0:52:18.20,Default,,0,0,0,,CONS-STREAM所做的就是 Dialogue: 0,0:52:18.81,0:52:21.96,Default,,0,0,0,,把X和一个计算Y的PROMISE Dialogue: 0,0:52:23.31,0:52:25.36,Default,,0,0,0,,放在在一个序对里 Dialogue: 0,0:52:28.23,0:52:28.99,Default,,0,0,0,,如果我需要头部分 Dialogue: 0,0:52:28.99,0:52:30.75,Default,,0,0,0,,那么就是这个序对的CAR部分 Dialogue: 0,0:52:31.84,0:52:33.71,Default,,0,0,0,,关键在于 它的尾部分 Dialogue: 0,0:52:34.62,0:52:36.65,Default,,0,0,0,,强制会调用该PROMISE Dialogue: 0,0:52:38.22,0:52:39.88,Default,,0,0,0,,而TAIL会说 Dialogue: 0,0:52:40.03,0:52:41.02,Default,,0,0,0,,好吧 取出该PROMISE Dialogue: 0,0:52:41.85,0:52:44.52,Default,,0,0,0,,然后调用该PROMISE Dialogue: 0,0:52:44.56,0:52:46.03,Default,,0,0,0,,这才开始实际的计算 Dialogue: 0,0:52:47.69,0:52:48.72,Default,,0,0,0,,这就是它的实际工作方式 Dialogue: 0,0:52:48.74,0:52:51.55,Default,,0,0,0,,这就是CONS-STREAM、HEAD和TAIL的真正定义 Dialogue: 0,0:52:54.60,0:52:55.57,Default,,0,0,0,,具体演示一下 Dialogue: 0,0:52:55.57,0:52:57.50,Default,,0,0,0,,我们小心翼翼地来审查一遍 Dialogue: 0,0:52:58.76,0:53:00.62,Default,,0,0,0,,现在从计算10,000到1,000,000中的 Dialogue: 0,0:53:01.32,0:53:03.66,Default,,0,0,0,,第二个质数这个实例来看 Dialogue: 0,0:53:05.50,0:53:07.16,Default,,0,0,0,,看看是怎么运行的 Dialogue: 0,0:53:08.65,0:53:12.03,Default,,0,0,0,,好的 我们从这个表达式开始 Dialogue: 0,0:53:15.36,0:53:16.62,Default,,0,0,0,,第二个质数就是 Dialogue: 0,0:53:16.64,0:53:21.90,Default,,0,0,0,,就是(HEAD (TAIL (FILTER PRIME? ... ))) Dialogue: 0,0:53:22.83,0:53:25.31,Default,,0,0,0,,枚举的范围是(E-I 10000 1000000) Dialogue: 0,0:53:26.71,0:53:27.61,Default,,0,0,0,,这是什么呢? Dialogue: 0,0:53:28.40,0:53:29.20,Default,,0,0,0,,那就是 Dialogue: 0,0:53:31.63,0:53:34.17,Default,,0,0,0,,枚举的这个10,000至1,000,000的区间 Dialogue: 0,0:53:35.72,0:53:37.32,Default,,0,0,0,,如果你追踪这个枚举区间 Dialogue: 0,0:53:37.34,0:53:38.78,Default,,0,0,0,,会发现它构造了一个流 Dialogue: 0,0:53:39.92,0:53:41.39,Default,,0,0,0,,CONS-STREAM实际代换过来是 Dialogue: 0,0:53:41.96,0:53:43.61,Default,,0,0,0,,把10,000 Dialogue: 0,0:53:44.51,0:53:48.92,Default,,0,0,0,,和一个计算10,001到1,000,000之间整数的PROMISE结合起来 Dialogue: 0,0:53:54.00,0:53:55.75,Default,,0,0,0,,这也就是上面这个表达式 Dialogue: 0,0:53:55.75,0:53:57.32,Default,,0,0,0,,现在我使用代换模型 Dialogue: 0,0:53:57.64,0:53:59.32,Default,,0,0,0,,我们可以用代换模型的原因是 Dialogue: 0,0:53:59.34,0:54:01.01,Default,,0,0,0,,这里并没有涉及状态和副作用 Dialogue: 0,0:54:03.56,0:54:06.38,Default,,0,0,0,,所以我有10,000 Dialogue: 0,0:54:06.41,0:54:08.27,Default,,0,0,0,,和一个计算剩余整数构成的流 Dialogue: 0,0:54:08.32,0:54:10.49,Default,,0,0,0,,而到现在为止 只有一个整数被枚举了出来 Dialogue: 0,0:54:14.38,0:54:16.96,Default,,0,0,0,,然后过滤函数会对它做素性测试 Dialogue: 0,0:54:19.44,0:54:21.90,Default,,0,0,0,,我们再来仔细看看过滤函数的代码 Dialogue: 0,0:54:22.36,0:54:24.46,Default,,0,0,0,,过滤函数首先测试流的首部分 Dialogue: 0,0:54:25.46,0:54:28.25,Default,,0,0,0,,这里 过滤函数会测试10,000 Dialogue: 0,0:54:30.30,0:54:32.97,Default,,0,0,0,,然后输出:10,000不是质数 Dialogue: 0,0:54:33.50,0:54:35.85,Default,,0,0,0,,因此我只需要 Dialogue: 0,0:54:36.25,0:54:37.39,Default,,0,0,0,,递归地过滤尾部分 Dialogue: 0,0:54:39.22,0:54:40.14,Default,,0,0,0,,尾部分是什么呢? Dialogue: 0,0:54:40.16,0:54:43.76,Default,,0,0,0,,就是这个流的尾部分 -- 一个PROMISE Dialogue: 0,0:54:46.34,0:54:48.06,Default,,0,0,0,,我们进入到尾部分 Dialogue: 0,0:54:48.28,0:54:49.50,Default,,0,0,0,,强制(计算)该PROMISE Dialogue: 0,0:54:49.68,0:54:50.94,Default,,0,0,0,,我强制计算该PROMISE Dialogue: 0,0:54:52.30,0:54:54.36,Default,,0,0,0,,这就意味着 我现在要 Dialogue: 0,0:54:55.58,0:54:57.96,Default,,0,0,0,,枚举10,001到1,000,000之间的整数 Dialogue: 0,0:55:00.80,0:55:02.97,Default,,0,0,0,,现在 过滤函数处理的是这个东西 Dialogue: 0,0:55:07.81,0:55:08.92,Default,,0,0,0,,这个枚举函数枚举了它自己 Dialogue: 0,0:55:08.94,0:55:11.23,Default,,0,0,0,,我们又回到了最初那种枚举情况 Dialogue: 0,0:55:11.96,0:55:13.00,Default,,0,0,0,,我们的枚举函数的 Dialogue: 0,0:55:14.12,0:55:16.44,Default,,0,0,0,,首部分是整数10,001 Dialogue: 0,0:55:16.60,0:55:18.20,Default,,0,0,0,,尾部分是计算剩余部分的PROMISE Dialogue: 0,0:55:19.74,0:55:22.75,Default,,0,0,0,,因此现在素性过滤函数将会测试10,001 Dialogue: 0,0:55:23.23,0:55:25.12,Default,,0,0,0,,开始判断它是不是质数 Dialogue: 0,0:55:25.12,0:55:27.08,Default,,0,0,0,,结果10,001不是质数 Dialogue: 0,0:55:27.55,0:55:29.61,Default,,0,0,0,,然后再不断地强制求值PROMISE Dialogue: 0,0:55:32.92,0:55:35.80,Default,,0,0,0,,最后 我觉得它找到的第一个质数可能是10,009 Dialogue: 0,0:55:37.10,0:55:38.33,Default,,0,0,0,,它会在这个时候停止 Dialogue: 0,0:55:40.84,0:55:41.93,Default,,0,0,0,,这只是第一个质数 Dialogue: 0,0:55:41.96,0:55:43.48,Default,,0,0,0,,然而 我们需要的是第二个 Dialogue: 0,0:55:45.24,0:55:46.84,Default,,0,0,0,,所以 这时它又启动了 Dialogue: 0,0:55:47.03,0:55:48.25,Default,,0,0,0,,你会发现 Dialogue: 0,0:55:48.52,0:55:50.49,Default,,0,0,0,,你需要多少 Dialogue: 0,0:55:51.85,0:55:52.91,Default,,0,0,0,,它就只会生成多少 Dialogue: 0,0:55:56.48,0:55:59.92,Default,,0,0,0,,枚举函数生成整数的数量 Dialogue: 0,0:56:00.12,0:56:01.45,Default,,0,0,0,,不会比过滤函数所要求的多 Dialogue: 0,0:56:01.47,0:56:03.45,Default,,0,0,0,,因为它只是取一部分数来做素性测试 Dialogue: 0,0:56:04.70,0:56:06.51,Default,,0,0,0,,过滤函数也不会生成 Dialogue: 0,0:56:06.54,0:56:08.04,Default,,0,0,0,,比你的要求更多的东西 Dialogue: 0,0:56:08.06,0:56:09.10,Default,,0,0,0,,也就是尾部分的首部分 Dialogue: 0,0:56:11.61,0:56:13.26,Default,,0,0,0,,你们看 Dialogue: 0,0:56:14.70,0:56:18.24,Default,,0,0,0,,我们把计算机运行中实际进行的 Dialogue: 0,0:56:18.67,0:56:20.65,Default,,0,0,0,,生成与测试的过程 混合在了一起 Dialogue: 0,0:56:21.52,0:56:22.67,Default,,0,0,0,,尽管 Dialogue: 0,0:56:23.18,0:56:25.63,Default,,0,0,0,,我们的程序“看起来”显然不是这样 Dialogue: 0,0:56:28.12,0:56:29.40,Default,,0,0,0,,看起来都很简单 Dialogue: 0,0:56:30.23,0:56:32.67,Default,,0,0,0,,这种机制的神奇之处在于DELAY Dialogue: 0,0:56:33.68,0:56:35.66,Default,,0,0,0,,所以你也许会说 这全是因为DELAY很强大 Dialogue: 0,0:56:36.90,0:56:38.57,Default,,0,0,0,,但其实并不是 Dialogue: 0,0:56:39.07,0:56:39.98,Default,,0,0,0,,DELAY其实很简单 Dialogue: 0,0:56:40.61,0:56:45.07,Default,,0,0,0,,(DELAY ) Dialogue: 0,0:56:48.25,0:56:50.04,Default,,0,0,0,,只是一个缩略表达 Dialogue: 0,0:56:53.36,0:56:55.63,Default,,0,0,0,,它是-- 创建一个用于计算表达式的PROMISE Dialogue: 0,0:56:56.49,0:57:01.12,Default,,0,0,0,,(LAMBDA () ) 这样的一个表达式 Dialogue: 0,0:57:02.83,0:57:03.84,Default,,0,0,0,,这就是整个过程 Dialogue: 0,0:57:03.98,0:57:05.53,Default,,0,0,0,,这个PROMISE将要计算表达式 Dialogue: 0,0:57:06.05,0:57:06.73,Default,,0,0,0,,FORCE过程又是什么? Dialogue: 0,0:57:07.34,0:57:10.80,Default,,0,0,0,,如何处理这个PROMISE Dialogue: 0,0:57:10.80,0:57:14.11,Default,,0,0,0,,FROCE一个PROMISE -- 也就是某个过程 Dialogue: 0,0:57:14.78,0:57:15.40,Default,,0,0,0,,只是简单地运行它 Dialogue: 0,0:57:19.23,0:57:19.56,Default,,0,0,0,,就是这样 Dialogue: 0,0:57:20.24,0:57:21.37,Default,,0,0,0,,所以这里并没有什么魔法 Dialogue: 0,0:57:23.52,0:57:24.24,Default,,0,0,0,,总结一下 我们都干了些什么? Dialogue: 0,0:57:26.44,0:57:27.50,Default,,0,0,0,,我们说 Dialogue: 0,0:57:28.14,0:57:30.81,Default,,0,0,0,,传统的编程方式更有效 Dialogue: 0,0:57:30.96,0:57:33.92,Default,,0,0,0,,而流程序却更加清晰 Dialogue: 0,0:57:35.50,0:57:38.72,Default,,0,0,0,,我们设法用DELAY Dialogue: 0,0:57:38.81,0:57:43.23,Default,,0,0,0,,使流程序和其它过程一样高效 Dialogue: 0,0:57:43.35,0:57:46.43,Default,,0,0,0,,DELAY所做的就是把 Dialogue: 0,0:57:46.68,0:57:50.40,Default,,0,0,0,,我们程序中 事件发生的逻辑顺序 Dialogue: 0,0:57:51.21,0:57:53.84,Default,,0,0,0,,和机器中 事件发生的实际顺序 解耦开来 Dialogue: 0,0:57:54.44,0:57:55.93,Default,,0,0,0,,这是DELAY的实质作用 Dialogue: 0,0:57:57.15,0:57:58.29,Default,,0,0,0,,也是全部的重点 Dialogue: 0,0:57:58.29,0:58:01.92,Default,,0,0,0,,我们放弃了那种想法 Dialogue: 0,0:58:02.30,0:58:04.17,Default,,0,0,0,,即程序的运行 Dialogue: 0,0:58:04.67,0:58:05.95,Default,,0,0,0,,或者源码的编排 Dialogue: 0,0:58:06.33,0:58:08.25,Default,,0,0,0,,反映了时间的明确概念 Dialogue: 0,0:58:09.45,0:58:10.57,Default,,0,0,0,,一旦放弃了这种想法 Dialogue: 0,0:58:11.21,0:58:13.32,Default,,0,0,0,,我们能使用DELAY Dialogue: 0,0:58:13.34,0:58:15.20,Default,,0,0,0,,自由地安排计算顺序 Dialogue: 0,0:58:16.69,0:58:17.61,Default,,0,0,0,,整个思想就是这样 Dialogue: 0,0:58:17.61,0:58:19.45,Default,,0,0,0,,我们解耦了 Dialogue: 0,0:58:19.95,0:58:21.13,Default,,0,0,0,,程序的逻辑顺序 Dialogue: 0,0:58:21.16,0:58:22.89,Default,,0,0,0,,和其实际运行的顺序 Dialogue: 0,0:58:24.09,0:58:25.77,Default,,0,0,0,,对了 还有一个细节 Dialogue: 0,0:58:25.77,0:58:27.21,Default,,0,0,0,,一个技术性的细节 Dialogue: 0,0:58:27.21,0:58:28.43,Default,,0,0,0,,但是也非常重要 Dialogue: 0,0:58:29.73,0:58:32.01,Default,,0,0,0,,当你们运行这些递归程序的时候 Dialogue: 0,0:58:32.16,0:58:33.58,Default,,0,0,0,,你会看到很多像是 Dialogue: 0,0:58:33.64,0:58:37.87,Default,,0,0,0,,(TAIL (TAIL (TAIL ... 这样的东西 Dialogue: 0,0:58:39.20,0:58:41.02,Default,,0,0,0,,如果流是通过嵌套的CONS构造起来的 Dialogue: 0,0:58:41.02,0:58:42.88,Default,,0,0,0,,就会出现这种情况 Dialogue: 0,0:58:43.86,0:58:46.09,Default,,0,0,0,,如果我每次都要执行一次 Dialogue: 0,0:58:46.14,0:58:47.58,Default,,0,0,0,,如果我每次都要计算TAIL Dialogue: 0,0:58:48.22,0:58:50.88,Default,,0,0,0,,我对一个过程求值 Dialogue: 0,0:58:51.07,0:58:53.07,Default,,0,0,0,,这个过程又将重新计算它的TAIL Dialogue: 0,0:58:53.10,0:58:55.40,Default,,0,0,0,,它的TAIL又将重新计算TAIL的TAIL Dialogue: 0,0:58:55.50,0:58:56.88,Default,,0,0,0,,你们可以发现这非常低效 Dialogue: 0,0:58:57.77,0:59:00.56,Default,,0,0,0,,尤其是跟已经存放了所有元素的表相比 Dialogue: 0,0:59:01.16,0:59:04.00,Default,,0,0,0,,因为那样 在取得下一个TAIL的时候不需要重新计算 Dialogue: 0,0:59:05.29,0:59:08.28,Default,,0,0,0,,因此 这里有一个小技巧 Dialogue: 0,0:59:09.66,0:59:13.13,Default,,0,0,0,,通过稍微修改DELAY的定义 Dialogue: 0,0:59:14.96,0:59:18.20,Default,,0,0,0,,就可以让整件事变得 -- 我先写一下 Dialogue: 0,0:59:19.68,0:59:22.04,Default,,0,0,0,,DELAY实际的实现是 Dialogue: 0,0:59:24.52,0:59:27.93,Default,,0,0,0,,(DELAY )是这样一个表达式的简写 Dialogue: 0,0:59:28.11,0:59:30.86,Default,,0,0,0,,(MEMO-PROC (LAMBDA () )) Dialogue: 0,0:59:31.00,0:59:34.06,Default,,0,0,0,,MEMO-PROC是一个可以改变过程的特殊过程 Dialogue: 0,0:59:35.15,0:59:37.80,Default,,0,0,0,,它接受一个无参过程 Dialogue: 0,0:59:39.02,0:59:41.05,Default,,0,0,0,,并把该过程变为 Dialogue: 0,0:59:41.36,0:59:43.55,Default,,0,0,0,,只需要执行一次计算的过程 Dialogue: 0,0:59:45.10,0:59:47.45,Default,,0,0,0,,我们意思是 你给它一个过程 Dialogue: 0,0:59:48.70,0:59:50.86,Default,,0,0,0,,MEMO-PROC返回一个新的过程 Dialogue: 0,0:59:51.39,0:59:53.00,Default,,0,0,0,,当你首次调用这个新过程 Dialogue: 0,0:59:53.71,0:59:55.07,Default,,0,0,0,,它会运行原始过程 Dialogue: 0,0:59:55.31,0:59:56.91,Default,,0,0,0,,并记下结果 Dialogue: 0,0:59:58.56,1:00:00.68,Default,,0,0,0,,从那之后 每次你再运行这个过程 Dialogue: 0,1:00:00.68,1:00:02.17,Default,,0,0,0,,就不用再计算了 Dialogue: 0,1:00:02.19,1:00:04.43,Default,,0,0,0,,它会把结果存储在一个地方 Dialogue: 0,1:00:05.20,1:00:06.92,Default,,0,0,0,,可以这样来实现MEMO-PROC Dialogue: 0,1:00:11.21,1:00:12.71,Default,,0,0,0,,一旦你了解怎么做 实现就很容易了 Dialogue: 0,1:00:12.71,1:00:16.76,Default,,0,0,0,,MEMO-PROC中有两个标记变量 Dialogue: 0,1:00:17.39,1:00:19.20,Default,,0,0,0,,ALREADY-RUN?用于记录是否运行过 Dialogue: 0,1:00:20.32,1:00:22.48,Default,,0,0,0,,初始值是NIL 指示没运行过 Dialogue: 0,1:00:23.62,1:00:27.04,Default,,0,0,0,,RESULT用于存储上一次计算的结果 Dialogue: 0,1:00:29.07,1:00:31.07,Default,,0,0,0,,MEMO-PROC接收一个过程PROC Dialogue: 0,1:00:31.56,1:00:34.01,Default,,0,0,0,,返回一个新的无参过程 Dialogue: 0,1:00:34.36,1:00:36.38,Default,,0,0,0,,PROC也是一个无参过程 Dialogue: 0,1:00:38.61,1:00:41.37,Default,,0,0,0,,它会判断 -- 如果没有运行过 Dialogue: 0,1:00:42.59,1:00:44.06,Default,,0,0,0,,就进行一系列的运算 Dialogue: 0,1:00:44.43,1:00:46.56,Default,,0,0,0,,先计算PROC Dialogue: 0,1:00:47.50,1:00:48.45,Default,,0,0,0,,然后存储它的值 Dialogue: 0,1:00:48.45,1:00:50.48,Default,,0,0,0,,存储在变量RESULT中 Dialogue: 0,1:00:51.14,1:00:53.90,Default,,0,0,0,,然后对ALREADY-RUN?赋值 提醒自己已经运行过了 Dialogue: 0,1:00:54.28,1:00:55.47,Default,,0,0,0,,最后返回RESULT Dialogue: 0,1:00:56.61,1:00:59.01,Default,,0,0,0,,所以之前如果没运行过 就执行一次计算 Dialogue: 0,1:00:59.01,1:01:01.88,Default,,0,0,0,,当你调用它 但已经运行过了 就直接返回结果 Dialogue: 0,1:01:03.42,1:01:07.12,Default,,0,0,0,,这种聪明的小技巧被称作“记忆化” Dialogue: 0,1:01:08.40,1:01:09.13,Default,,0,0,0,,这样的话 Dialogue: 0,1:01:10.35,1:01:14.14,Default,,0,0,0,,就不会重复的计算TAIL了 Dialogue: 0,1:01:15.27,1:01:17.81,Default,,0,0,0,,不再那样的没效率了 Dialogue: 0,1:01:17.81,1:01:18.72,Default,,0,0,0,,事实上 流式程序设计 Dialogue: 0,1:01:19.20,1:01:22.75,Default,,0,0,0,,甚至和传统的那种程序一样有效 Dialogue: 0,1:01:24.01,1:01:26.20,Default,,0,0,0,,再强调一下 整个的思想在于 Dialogue: 0,1:01:27.48,1:01:28.60,Default,,0,0,0,,我们已经讲过 Dialogue: 0,1:01:29.26,1:01:32.40,Default,,0,0,0,,过程与数据之间 Dialogue: 0,1:01:32.41,1:01:33.61,Default,,0,0,0,,没有一个明确的分界线 Dialogue: 0,1:01:33.61,1:01:35.61,Default,,0,0,0,,事实上 我们把数据结构组织得 Dialogue: 0,1:01:36.00,1:01:37.31,Default,,0,0,0,,像一个过程 Dialogue: 0,1:01:38.76,1:01:40.73,Default,,0,0,0,,它使得我们能够 Dialogue: 0,1:01:41.58,1:01:46.54,Default,,0,0,0,,可以实现一种常见的控制结构 Dialogue: 0,1:01:46.68,1:01:48.91,Default,,0,0,0,,在本例中是迭代 Dialogue: 0,1:01:49.62,1:01:51.05,Default,,0,0,0,,我们创建了一种数据结构 Dialogue: 0,1:01:51.32,1:01:52.84,Default,,0,0,0,,由于这种数据结构本身是一个过程 Dialogue: 0,1:01:52.86,1:01:55.12,Default,,0,0,0,,它其中就可以有某种控制结构 Dialogue: 0,1:01:55.79,1:01:57.13,Default,,0,0,0,,这就是流的实质 Dialogue: 0,1:01:58.91,1:01:59.76,Default,,0,0,0,,好 大家有什么问题吗? Dialogue: 0,1:02:03.95,1:02:05.84,Default,,0,0,0,,学生:你刚才说(TAIL (TAIL (TAIL ... Dialogue: 0,1:02:05.85,1:02:07.16,Default,,0,0,0,,如果我没理解错的话 Dialogue: 0,1:02:07.28,1:02:10.76,Default,,0,0,0,,没有没有MEMO-PROC的话 Dialogue: 0,1:02:10.78,1:02:12.83,Default,,0,0,0,,FORCE实际上执行了一个过程 Dialogue: 0,1:02:12.89,1:02:13.15,Default,,0,0,0,,教授:是的 Dialogue: 0,1:02:13.44,1:02:16.38,Default,,0,0,0,,学生:你说使用那个MEMO-PROC就不会有那样的问题 Dialogue: 0,1:02:16.38,1:02:18.73,Default,,0,0,0,,这难道不需要保证 Dialogue: 0,1:02:19.34,1:02:22.19,Default,,0,0,0,,(TAIL (TAIL (TAIL 每次的计算结构都是一致的么? Dialogue: 0,1:02:22.41,1:02:23.91,Default,,0,0,0,,教授:哦 当然 Dialogue: 0,1:02:23.91,1:02:25.84,Default,,0,0,0,,学生:我可能是漏了什么知识点 Dialogue: 0,1:02:26.05,1:02:27.21,Default,,0,0,0,,教授:你说得很对 这里 -- Dialogue: 0,1:02:31.12,1:02:33.64,Default,,0,0,0,,首先 为了获得结果需要进行一次计算 Dialogue: 0,1:02:34.09,1:02:36.76,Default,,0,0,0,,关键在于 一旦得到 (TAIL STREAM) Dialogue: 0,1:02:37.58,1:02:38.70,Default,,0,0,0,,再计算 (TAIL (TAIL STREAM)) 的时候 Dialogue: 0,1:02:38.70,1:02:40.51,Default,,0,0,0,,就不用再计算最内部的TAIL了 Dialogue: 0,1:02:42.98,1:02:44.32,Default,,0,0,0,,明白了吧 如果我没有用MEMO-PROC Dialogue: 0,1:02:44.35,1:02:46.09,Default,,0,0,0,,还要再计算一遍 (TAIL STREAM) Dialogue: 0,1:02:46.46,1:02:47.13,Default,,0,0,0,,学生:明白了 Dialogue: 0,1:02:50.83,1:02:52.56,Default,,0,0,0,,学生:之前的例子中你提到过 Dialogue: 0,1:02:52.60,1:02:54.22,Default,,0,0,0,,我们之所以可以使用代换模型 Dialogue: 0,1:02:54.22,1:02:56.11,Default,,0,0,0,,是因为这里没有副作用 Dialogue: 0,1:02:56.83,1:03:00.73,Default,,0,0,0,,如果我们的信号处理单元 Dialogue: 0,1:03:00.78,1:03:02.03,Default,,0,0,0,,具有副作用 Dialogue: 0,1:03:02.04,1:03:03.04,Default,,0,0,0,,具有内部状态 Dialogue: 0,1:03:03.62,1:03:06.84,Default,,0,0,0,,我们还有效地构建流模型么? Dialogue: 0,1:03:08.46,1:03:10.59,Default,,0,0,0,,教授:可能吧 这是一个很困难的问题 Dialogue: 0,1:03:11.20,1:03:13.42,Default,,0,0,0,,关于代换模型和副作用并不是很兼容这一点 Dialogue: 0,1:03:14.36,1:03:18.24,Default,,0,0,0,,我以后会稍稍地讲解一下 Dialogue: 0,1:03:18.96,1:03:20.48,Default,,0,0,0,,但大体来说 我认为 Dialogue: 0,1:03:20.49,1:03:21.63,Default,,0,0,0,,除非你非常小心 Dialogue: 0,1:03:21.90,1:03:24.46,Default,,0,0,0,,否则副作用会把一切弄得很糟糕 Dialogue: 0,1:03:35.04,1:03:38.25,Default,,0,0,0,,学生:我不是很理解MEMO-PROC这个过程 Dialogue: 0,1:03:39.68,1:03:41.12,Default,,0,0,0,,你是什么时候执行那个LAMBDA的? Dialogue: 0,1:03:41.99,1:03:43.21,Default,,0,0,0,,换句话说 Dialogue: 0,1:03:43.68,1:03:45.15,Default,,0,0,0,,当MEMO-PROC执行的时候 Dialogue: 0,1:03:45.18,1:03:47.71,Default,,0,0,0,,只生成了LAMBDA表达式 Dialogue: 0,1:03:48.01,1:03:49.68,Default,,0,0,0,,但我不太清楚它是什么时候被执行的 Dialogue: 0,1:03:50.39,1:03:51.12,Default,,0,0,0,,教授:好的 Dialogue: 0,1:03:51.35,1:03:52.68,Default,,0,0,0,,MEMO-PROC所做的 -- Dialogue: 0,1:03:53.07,1:03:55.85,Default,,0,0,0,,MEMO-PROC的一个参数是PROC Dialogue: 0,1:03:56.38,1:03:57.93,Default,,0,0,0,,一个没有参数的过程 Dialogue: 0,1:03:57.93,1:03:59.05,Default,,0,0,0,,某个时刻 你会调用它 Dialogue: 0,1:04:00.39,1:04:02.75,Default,,0,0,0,,MEMO-PROC把该过程转化为 Dialogue: 0,1:04:02.75,1:04:04.56,Default,,0,0,0,,另一个无参过程 Dialogue: 0,1:04:04.59,1:04:05.80,Default,,0,0,0,,某个时刻你会调用到它 Dialogue: 0,1:04:06.62,1:04:07.42,Default,,0,0,0,,LAMBDA语句做的是这个 Dialogue: 0,1:04:09.89,1:04:14.08,Default,,0,0,0,,所以在这里 我最初构造 Dialogue: 0,1:04:15.85,1:04:17.92,Default,,0,0,0,,构造流的TAIL的时候 Dialogue: 0,1:04:18.30,1:04:20.48,Default,,0,0,0,,这里的这个无参过程 Dialogue: 0,1:04:20.51,1:04:21.61,Default,,0,0,0,,会在之后的某个时刻调用 Dialogue: 0,1:04:24.10,1:04:28.01,Default,,0,0,0,,相对应的 我要对(TAIL STREAM)调用MEMO-PROC Dialogue: 0,1:04:28.12,1:04:29.24,Default,,0,0,0,,以后我会调用生成的过程 Dialogue: 0,1:04:30.65,1:04:31.90,Default,,0,0,0,,所以这个无参的LAMBDA Dialogue: 0,1:04:32.03,1:04:36.06,Default,,0,0,0,,是当你在调用MEMO-PROC时调用的 Dialogue: 0,1:04:38.97,1:04:40.96,Default,,0,0,0,,当你调用MEMP-PROC返回的过程时 Dialogue: 0,1:04:40.97,1:04:42.28,Default,,0,0,0,,也就会像通常的过程调用那样 Dialogue: 0,1:04:42.36,1:04:45.76,Default,,0,0,0,,调用你最初设定的那个函数 Dialogue: 0,1:04:47.64,1:04:48.86,Default,,0,0,0,,学生:我想问的是 Dialogue: 0,1:04:48.86,1:04:50.86,Default,,0,0,0,,当你调用MEMO-PROC的时候 Dialogue: 0,1:04:50.86,1:04:52.30,Default,,0,0,0,,你返回了这个LAMBDA Dialogue: 0,1:04:52.61,1:04:53.07,Default,,0,0,0,,教授:是的 Dialogue: 0,1:04:53.77,1:04:58.10,Default,,0,0,0,,你调用MEMO-PROC的时候 返回了一个LAMBDA Dialogue: 0,1:04:58.10,1:04:59.84,Default,,0,0,0,,直到你第一次需要执行它的时候 Dialogue: 0,1:04:59.87,1:05:02.27,Default,,0,0,0,,你才去求值 Dialogue: 0,1:05:07.76,1:05:09.10,Default,,0,0,0,,学生:我这样理解对吗? Dialogue: 0,1:05:09.18,1:05:11.40,Default,,0,0,0,,你构造了一个表 Dialogue: 0,1:05:11.47,1:05:14.17,Default,,0,0,0,,但表中的元素还没有被求值 Dialogue: 0,1:05:14.24,1:05:15.63,Default,,0,0,0,,表达式没有被求值? Dialogue: 0,1:05:15.63,1:05:18.54,Default,,0,0,0,,但在每个阶段 你还是构造了一个表 Dialogue: 0,1:05:18.54,1:05:20.70,Default,,0,0,0,,教授:啊 我应该这样说 Dialogue: 0,1:05:20.70,1:05:22.27,Default,,0,0,0,,这个想法很好 Dialogue: 0,1:05:22.27,1:05:23.18,Default,,0,0,0,,但是 也不全对 Dialogue: 0,1:05:23.66,1:05:25.08,Default,,0,0,0,,因为实际发生的事情是这样的 Dialogue: 0,1:05:25.08,1:05:26.35,Default,,0,0,0,,我先把这个画成序对 Dialogue: 0,1:05:26.89,1:05:28.03,Default,,0,0,0,,假设我要构造一个特别大的流 Dialogue: 0,1:05:28.96,1:05:30.12,Default,,0,0,0,,比如枚举一段区间 Dialogue: 0,1:05:30.32,1:05:31.48,Default,,0,0,0,,从1到1,000,000,000 Dialogue: 0,1:05:32.74,1:05:35.74,Default,,0,0,0,,这实际上是一个序对 Dialogue: 0,1:05:39.34,1:05:43.36,Default,,0,0,0,,由1和一个PROMISE组成 Dialogue: 0,1:05:46.73,1:05:47.89,Default,,0,0,0,,就是这样 Dialogue: 0,1:05:47.89,1:05:48.76,Default,,0,0,0,,什么都没有构造 Dialogue: 0,1:05:51.60,1:05:53.29,Default,,0,0,0,,当我继续FORCE这个PROMISE Dialogue: 0,1:05:54.51,1:05:56.37,Default,,0,0,0,,再来看看 会发生什么 Dialogue: 0,1:05:56.37,1:05:59.66,Default,,0,0,0,,这个东西现在就成为了一个递归CONS Dialogue: 0,1:06:00.53,1:06:02.16,Default,,0,0,0,,所以这个PROMISE现在就变成了 Dialogue: 0,1:06:04.62,1:06:08.96,Default,,0,0,0,,一个2和做更多事情的PROMISE Dialogue: 0,1:06:11.35,1:06:12.73,Default,,0,0,0,,一直这样下去 Dialogue: 0,1:06:14.47,1:06:17.63,Default,,0,0,0,,直到你走完整个流才完整地构建了一个表 Dialogue: 0,1:06:18.20,1:06:19.58,Default,,0,0,0,,因为这个东西不是表 Dialogue: 0,1:06:20.03,1:06:21.48,Default,,0,0,0,,只是一个生成表的PROMISE Dialogue: 0,1:06:23.39,1:06:25.50,Default,,0,0,0,,技术上来说 PROMISE就是一个过程 Dialogue: 0,1:06:27.80,1:06:29.10,Default,,0,0,0,,因此并没有直接构造好一个表 Dialogue: 0,1:06:30.76,1:06:32.72,Default,,0,0,0,,我应该早点说的 Dialogue: 0,1:06:34.28,1:06:35.34,Default,,0,0,0,,好吧 就到这里 下课 Dialogue: 0,1:06:35.82,1:06:51.15,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:06:35.82,1:06:51.15,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec6a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: EN Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:09.67,0:00:13.34,EN,,0,0,0,,Stream Dialogue: 0,0:00:18.55,0:00:21.84,EN,,0,0,0,,PROFESSOR: Well, last time Gerry really let the cat out of the bag. Dialogue: 0,0:00:22.49,0:00:24.60,EN,,0,0,0,,He introduced the idea of assignment. Dialogue: 0,0:00:26.35,0:00:33.61,EN,,0,0,0,,Assignment and state. Dialogue: 0,0:00:37.48,0:00:40.03,EN,,0,0,0,,And as we started to see, the implications Dialogue: 0,0:00:40.72,0:00:43.16,EN,,0,0,0,,of introducing assignment and state into the language Dialogue: 0,0:00:43.16,0:00:44.41,EN,,0,0,0,,are absolutely frightening. Dialogue: 0,0:00:45.08,0:00:48.62,EN,,0,0,0,,First of all, the substitution model of evaluation breaks down. Dialogue: 0,0:00:49.13,0:00:52.48,EN,,0,0,0,,And we have to use this much more complicated environment model Dialogue: 0,0:00:52.48,0:00:54.27,EN,,0,0,0,,this very mechanistic thing with diagrams, Dialogue: 0,0:00:54.28,0:00:57.24,EN,,0,0,0,,even to say what statements in the programming language mean. Dialogue: 0,0:00:58.46,0:01:00.12,EN,,0,0,0,,And that's not a mere technical point. Dialogue: 0,0:01:00.26,0:01:03.28,EN,,0,0,0,,See, it's not that we had this particular substitution model and, Dialogue: 0,0:01:03.60,0:01:05.68,EN,,0,0,0,,well, it doesn't quite work, so we have to do something else. Dialogue: 0,0:01:05.71,0:01:09.79,EN,,0,0,0,,It's that nothing like the substitution model can work. Dialogue: 0,0:01:10.73,0:01:13.32,EN,,0,0,0,,Because suddenly, a variable Dialogue: 0,0:01:14.12,0:01:16.92,EN,,0,0,0,,is not just something that stands for a value. Dialogue: 0,0:01:17.95,0:01:21.76,EN,,0,0,0,,A variable now has to somehow specify a place Dialogue: 0,0:01:22.40,0:01:23.34,EN,,0,0,0,,that holds a value. Dialogue: 0,0:01:23.63,0:01:26.14,EN,,0,0,0,,And the value that's in that place can change. Dialogue: 0,0:01:30.28,0:01:34.09,EN,,0,0,0,,Or for instance, an expression like f of x Dialogue: 0,0:01:37.36,0:01:39.64,EN,,0,0,0,,might have a side effect in it. Dialogue: 0,0:01:40.41,0:01:42.60,EN,,0,0,0,,So if we say f of x and it has some value, Dialogue: 0,0:01:43.18,0:01:45.34,EN,,0,0,0,,and then later we say f of x again, Dialogue: 0,0:01:47.24,0:01:48.43,EN,,0,0,0,,we might get a different value Dialogue: 0,0:01:48.86,0:01:49.74,EN,,0,0,0,,depending on the order. Dialogue: 0,0:01:49.76,0:01:52.14,EN,,0,0,0,,So suddenly, we have to think not only about values Dialogue: 0,0:01:52.52,0:01:53.60,EN,,0,0,0,,but about time. Dialogue: 0,0:01:57.97,0:01:59.98,EN,,0,0,0,,And then things like pairs Dialogue: 0,0:02:00.65,0:02:02.52,EN,,0,0,0,,are no longer just their CARs and their CDRs. Dialogue: 0,0:02:02.52,0:02:05.61,EN,,0,0,0,,A pair now is not quite its CAR and its CDR. Dialogue: 0,0:02:05.80,0:02:07.05,EN,,0,0,0,,It's rather its identity. Dialogue: 0,0:02:08.44,0:02:11.65,EN,,0,0,0,,So a pair has identity. Dialogue: 0,0:02:11.65,0:02:12.59,EN,,0,0,0,,It's an object. Dialogue: 0,0:02:21.33,0:02:25.15,EN,,0,0,0,,And two pairs that have the same CAR and CDR Dialogue: 0,0:02:25.40,0:02:27.05,EN,,0,0,0,,well, might be the same or different, Dialogue: 0,0:02:27.87,0:02:30.51,EN,,0,0,0,,because suddenly we have to worry about sharing. Dialogue: 0,0:02:34.96,0:02:39.45,EN,,0,0,0,,So all of these things enter as soon as we introduce assignment. Dialogue: 0,0:02:40.48,0:02:43.98,EN,,0,0,0,,See, this is a really far cry from where we started with substitution. Dialogue: 0,0:02:45.04,0:02:48.91,EN,,0,0,0,,It's a technically harder way of looking at things Dialogue: 0,0:02:48.94,0:02:53.45,EN,,0,0,0,,because we have to think more mechanistically about our programming language. Dialogue: 0,0:02:53.47,0:02:55.34,EN,,0,0,0,,We can't just think about it as mathematics. Dialogue: 0,0:02:55.71,0:02:58.60,EN,,0,0,0,,It's philosophically harder, Dialogue: 0,0:02:59.15,0:03:00.65,EN,,0,0,0,,because suddenly there are all these funny issues Dialogue: 0,0:03:00.67,0:03:02.38,EN,,0,0,0,,what does it mean that something changes Dialogue: 0,0:03:02.38,0:03:03.77,EN,,0,0,0,,or that two things are the same. Dialogue: 0,0:03:03.84,0:03:06.83,EN,,0,0,0,,And also, it's programming harder, because Dialogue: 0,0:03:07.47,0:03:08.54,EN,,0,0,0,,as Gerry showed last time, Dialogue: 0,0:03:08.56,0:03:12.20,EN,,0,0,0,,there are all these bugs having to do with bad sequencing and aliasing Dialogue: 0,0:03:12.22,0:03:16.19,EN,,0,0,0,,that just don't exist in a language where we don't worry about objects. Dialogue: 0,0:03:18.21,0:03:21.20,EN,,0,0,0,,Well, how'd we get into this mess? Dialogue: 0,0:03:24.01,0:03:27.20,EN,,0,0,0,,Remember what we did, the reason we got into this is Dialogue: 0,0:03:27.40,0:03:31.47,EN,,0,0,0,,because we were looking to build modular systems. Dialogue: 0,0:03:35.15,0:03:37.69,EN,,0,0,0,,We wanted to build systems that Dialogue: 0,0:03:38.09,0:03:41.04,EN,,0,0,0,,that fall apart into chunks that seem natural. Dialogue: 0,0:03:42.76,0:03:43.82,EN,,0,0,0,,So for instance, Dialogue: 0,0:03:44.06,0:03:46.11,EN,,0,0,0,,we want to take a random number generator Dialogue: 0,0:03:46.22,0:03:49.40,EN,,0,0,0,,and package up the state of that random number generator inside of it Dialogue: 0,0:03:50.25,0:03:53.71,EN,,0,0,0,,so that we can separate the idea of picking random numbers Dialogue: 0,0:03:54.65,0:03:57.79,EN,,0,0,0,,from the general Monte Carlo strategy of estimating something Dialogue: 0,0:03:58.65,0:04:01.52,EN,,0,0,0,,and separate that from the particular way that you Dialogue: 0,0:04:01.90,0:04:05.74,EN,,0,0,0,,work with random numbers in that formula developed by Cesaro for pi. Dialogue: 0,0:04:06.80,0:04:07.92,EN,,0,0,0,,And similarly, Dialogue: 0,0:04:09.61,0:04:11.74,EN,,0,0,0,,when we go off and construct some models of things, Dialogue: 0,0:04:12.35,0:04:16.01,EN,,0,0,0,,Ah, if we go off and model a system that we see in the real world, Dialogue: 0,0:04:17.31,0:04:19.42,EN,,0,0,0,,we'd like our program to break into natural pieces, Dialogue: 0,0:04:19.44,0:04:20.52,EN,,0,0,0,,pieces that mirror Dialogue: 0,0:04:21.05,0:04:23.16,EN,,0,0,0,,the parts of the system that we see in the real world. Dialogue: 0,0:04:24.90,0:04:27.56,EN,,0,0,0,,So for example, if we look at a digital circuit, Dialogue: 0,0:04:28.36,0:04:29.18,EN,,0,0,0,,we say, gee, Dialogue: 0,0:04:30.44,0:04:31.44,EN,,0,0,0,,there's a circuit Dialogue: 0,0:04:32.08,0:04:35.16,EN,,0,0,0,,and it has a piece and it has another piece. Dialogue: 0,0:04:40.10,0:04:43.58,EN,,0,0,0,,And these different pieces sort of have identity. Dialogue: 0,0:04:43.58,0:04:44.59,EN,,0,0,0,,They have state. Dialogue: 0,0:04:45.55,0:04:47.13,EN,,0,0,0,,And the state sits on these wires. Dialogue: 0,0:04:48.58,0:04:50.22,EN,,0,0,0,,And we think of this piece as an object Dialogue: 0,0:04:50.49,0:04:51.93,EN,,0,0,0,,that's different from that as an object. Dialogue: 0,0:04:52.54,0:04:53.85,EN,,0,0,0,,And when we watch the system change, Dialogue: 0,0:04:53.87,0:04:55.40,EN,,0,0,0,,we think about a signal coming in here Dialogue: 0,0:04:55.63,0:04:58.41,EN,,0,0,0,,changing a state that might be here and going here Dialogue: 0,0:04:58.67,0:05:00.75,EN,,0,0,0,,and interacting with a state that might be stored there, Dialogue: 0,0:05:01.24,0:05:02.17,EN,,0,0,0,,and so on and so on. Dialogue: 0,0:05:06.86,0:05:11.24,EN,,0,0,0,,So what we'd like is we'd like to build in the computer Dialogue: 0,0:05:12.76,0:05:14.36,EN,,0,0,0,,systems that fall into pieces Dialogue: 0,0:05:14.68,0:05:17.87,EN,,0,0,0,,that fall into pieces that mirror our view of reality, Dialogue: 0,0:05:17.88,0:05:19.87,EN,,0,0,0,,of the way that the actual systems we're modeling Dialogue: 0,0:05:19.88,0:05:20.91,EN,,0,0,0,,seem to fall into pieces. Dialogue: 0,0:05:23.20,0:05:23.48,EN,,0,0,0,,Well, Dialogue: 0,0:05:25.74,0:05:28.99,EN,,0,0,0,,maybe the reason that building systems like this Dialogue: 0,0:05:28.99,0:05:31.50,EN,,0,0,0,,seems to introduce such technical complications Dialogue: 0,0:05:31.52,0:05:32.75,EN,,0,0,0,,has nothing to do with computers. Dialogue: 0,0:05:33.61,0:05:35.60,EN,,0,0,0,,See, maybe the real reason Dialogue: 0,0:05:36.70,0:05:38.65,EN,,0,0,0,,that we pay such a price to write programs Dialogue: 0,0:05:38.67,0:05:40.94,EN,,0,0,0,,that mirror our view of reality Dialogue: 0,0:05:41.52,0:05:43.13,EN,,0,0,0,,is that we have the wrong view of reality. Dialogue: 0,0:05:44.55,0:05:46.75,EN,,0,0,0,,See, maybe time is just an illusion, Dialogue: 0,0:05:47.26,0:05:48.60,EN,,0,0,0,,and nothing ever changes. Dialogue: 0,0:05:50.15,0:05:51.71,EN,,0,0,0,,See, for example, if I take this chalk, Dialogue: 0,0:05:52.44,0:05:53.77,EN,,0,0,0,,and we say, gee, this is an object Dialogue: 0,0:05:54.01,0:05:54.99,EN,,0,0,0,,and it has a state. Dialogue: 0,0:05:55.82,0:05:59.29,EN,,0,0,0,,At each moment it has a position and a velocity. Dialogue: 0,0:05:59.71,0:06:01.48,EN,,0,0,0,,And if we do something, that state can change. Dialogue: 0,0:06:04.34,0:06:07.37,EN,,0,0,0,,But if you studied any relativity, for instance, Dialogue: 0,0:06:07.74,0:06:09.71,EN,,0,0,0,,you know that you don't think of the path of that chalk Dialogue: 0,0:06:09.72,0:06:11.34,EN,,0,0,0,,as something that goes on instant by instant. Dialogue: 0,0:06:11.34,0:06:14.38,EN,,0,0,0,,It's more insightful to think of that whole chalk's existence Dialogue: 0,0:06:14.41,0:06:15.64,EN,,0,0,0,,as a path in space-time. Dialogue: 0,0:06:16.02,0:06:17.37,EN,,0,0,0,,that's all splayed out. Dialogue: 0,0:06:17.87,0:06:19.84,EN,,0,0,0,,There aren't individual positions and velocities. Dialogue: 0,0:06:19.84,0:06:23.80,EN,,0,0,0,,There's just its unchanging existence in space-time. Dialogue: 0,0:06:24.64,0:06:26.51,EN,,0,0,0,,Similarly, if we look at this electrical system, Dialogue: 0,0:06:27.69,0:06:30.43,EN,,0,0,0,,if we imagine this electrical system is implementing Dialogue: 0,0:06:30.59,0:06:33.96,EN,,0,0,0,,sort of signal processing system, Dialogue: 0,0:06:34.36,0:06:36.68,EN,,0,0,0,,the signal processing engineer who put that thing together Dialogue: 0,0:06:36.75,0:06:38.60,EN,,0,0,0,,doesn't think of it as, well, Dialogue: 0,0:06:38.96,0:06:41.40,EN,,0,0,0,,at each instance there's a voltage coming in. Dialogue: 0,0:06:41.49,0:06:43.16,EN,,0,0,0,,And that translates into something. Dialogue: 0,0:06:43.34,0:06:45.52,EN,,0,0,0,,And that affects the state over here, Dialogue: 0,0:06:45.53,0:06:46.81,EN,,0,0,0,,which changes the state over here. Dialogue: 0,0:06:46.81,0:06:50.11,EN,,0,0,0,,Nobody putting together a signal processing system thinks about it like that. Dialogue: 0,0:06:50.42,0:06:51.84,EN,,0,0,0,,Instead, you say there's this signal Dialogue: 0,0:06:54.04,0:06:58.06,EN,,0,0,0,,that's splayed out over time. Dialogue: 0,0:06:58.06,0:06:59.48,EN,,0,0,0,,And if this is acting as a filter, Dialogue: 0,0:07:00.20,0:07:04.04,EN,,0,0,0,,this whole thing transforms this whole thing Dialogue: 0,0:07:04.28,0:07:07.04,EN,,0,0,0,,for some sort of other output. Dialogue: 0,0:07:09.57,0:07:11.28,EN,,0,0,0,,You don't think of it as what's happening Dialogue: 0,0:07:11.28,0:07:13.29,EN,,0,0,0,,instant by instant as the state of these things. Dialogue: 0,0:07:14.16,0:07:17.32,EN,,0,0,0,,And somehow you think of this box as a whole thing, Dialogue: 0,0:07:17.32,0:07:20.16,EN,,0,0,0,,not as little pieces sending messages of state Dialogue: 0,0:07:20.40,0:07:21.96,EN,,0,0,0,,to each other at particular instants. Dialogue: 0,0:07:28.25,0:07:29.36,EN,,0,0,0,,Well, today we're going to look at Dialogue: 0,0:07:29.39,0:07:31.13,EN,,0,0,0,,another way to decompose systems Dialogue: 0,0:07:31.36,0:07:35.45,EN,,0,0,0,,that's more like the signal processing engineer's view of the world Dialogue: 0,0:07:35.69,0:07:38.96,EN,,0,0,0,,than it is like thinking about objects that communicate sending messages. Dialogue: 0,0:07:41.13,0:07:43.74,EN,,0,0,0,,That's called stream processing. Dialogue: 0,0:07:54.57,0:07:58.96,EN,,0,0,0,,And we're going to start by showing Dialogue: 0,0:08:00.59,0:08:04.16,EN,,0,0,0,,by showing how we can make our programs more uniform Dialogue: 0,0:08:05.15,0:08:06.54,EN,,0,0,0,,and see a lot more commonality Dialogue: 0,0:08:06.65,0:08:09.88,EN,,0,0,0,,if we throw out of these programs Dialogue: 0,0:08:10.81,0:08:12.30,EN,,0,0,0,,what you might say is a Dialogue: 0,0:08:12.35,0:08:15.12,EN,,0,0,0,,inordinate concern with worrying about time. Dialogue: 0,0:08:16.89,0:08:20.22,EN,,0,0,0,,Let me start by comparing two procedures. Dialogue: 0,0:08:23.55,0:08:25.69,EN,,0,0,0,,The first one does this. Dialogue: 0,0:08:25.69,0:08:27.77,EN,,0,0,0,,We imagine that there's a tree. Dialogue: 0,0:08:30.40,0:08:32.14,EN,,0,0,0,,Say there's a tree of integers. Dialogue: 0,0:08:33.28,0:08:34.42,EN,,0,0,0,,It's a binary tree. Dialogue: 0,0:08:36.12,0:08:36.97,EN,,0,0,0,,Say 1. Dialogue: 0,0:08:39.10,0:08:40.23,EN,,0,0,0,,So it looks like this. Dialogue: 0,0:08:40.23,0:08:42.92,EN,,0,0,0,,And there's integers in each of the nodes. Dialogue: 0,0:08:45.18,0:08:47.80,EN,,0,0,0,,And what we would like to compute is Dialogue: 0,0:08:48.67,0:08:51.56,EN,,0,0,0,,for each odd number sitting here, Dialogue: 0,0:08:52.30,0:08:55.10,EN,,0,0,0,,we'd like to find the square and then sum up all those squares. Dialogue: 0,0:08:57.05,0:08:59.48,EN,,0,0,0,,Well, that should be a familiar kind of thing. Dialogue: 0,0:08:59.48,0:09:01.95,EN,,0,0,0,,There's a recursive strategy for doing it. Dialogue: 0,0:09:02.93,0:09:04.35,EN,,0,0,0,,We look at each leaf, and either Dialogue: 0,0:09:04.56,0:09:06.68,EN,,0,0,0,,it's going to contribute the square of the number if it's odd Dialogue: 0,0:09:06.70,0:09:07.77,EN,,0,0,0,,or 0 if it's even. Dialogue: 0,0:09:08.68,0:09:12.11,EN,,0,0,0,,And then recursively, we can say at each tree Dialogue: 0,0:09:12.65,0:09:13.84,EN,,0,0,0,,the sum of all of them is Dialogue: 0,0:09:13.92,0:09:15.93,EN,,0,0,0,,the sum coming from the right branch and the left branch, Dialogue: 0,0:09:16.25,0:09:17.64,EN,,0,0,0,,and recursively down through the nodes. Dialogue: 0,0:09:17.64,0:09:18.70,EN,,0,0,0,,And that's a familiar way of Dialogue: 0,0:09:19.26,0:09:20.36,EN,,0,0,0,,thinking about programming. Dialogue: 0,0:09:20.36,0:09:22.59,EN,,0,0,0,,Let's actually look at that on the slide. Dialogue: 0,0:09:23.82,0:09:26.75,EN,,0,0,0,,We say to sum the odd squares in a tree, Dialogue: 0,0:09:27.37,0:09:29.36,EN,,0,0,0,,there's a test. Either it's a leaf node, Dialogue: 0,0:09:29.82,0:09:31.95,EN,,0,0,0,,and we're going to check to see if it's an integer, Dialogue: 0,0:09:32.88,0:09:36.38,EN,,0,0,0,,and then either it's odd, in which we take the square, or else it's 0. Dialogue: 0,0:09:37.16,0:09:38.99,EN,,0,0,0,,And then the sum of the whole thing Dialogue: 0,0:09:39.21,0:09:42.12,EN,,0,0,0,,is the sum coming from the left branch and the right branch. Dialogue: 0,0:09:46.34,0:09:50.56,EN,,0,0,0,,OK, well, let me contrast that with a second problem. Dialogue: 0,0:09:51.56,0:09:53.68,EN,,0,0,0,,Suppose I give you an integer n, Dialogue: 0,0:09:54.73,0:09:57.88,EN,,0,0,0,,and then some function to compute of the first of each integer Dialogue: 0,0:09:57.93,0:09:58.83,EN,,0,0,0,,1 through n. Dialogue: 0,0:09:59.10,0:10:01.08,EN,,0,0,0,,And then I want to collect together in a list Dialogue: 0,0:10:01.28,0:10:04.65,EN,,0,0,0,,all those function values that satisfy some property. Dialogue: 0,0:10:05.60,0:10:06.88,EN,,0,0,0,,That's a general kind of thing. Dialogue: 0,0:10:06.88,0:10:07.98,EN,,0,0,0,,Let's say to be specific, Dialogue: 0,0:10:08.62,0:10:10.48,EN,,0,0,0,,let's imagine that for each integer, k, Dialogue: 0,0:10:10.65,0:10:12.51,EN,,0,0,0,,we're going to compute the k Fibonacci number. Dialogue: 0,0:10:14.21,0:10:16.27,EN,,0,0,0,,And then we'll see which of those are odd Dialogue: 0,0:10:16.83,0:10:18.40,EN,,0,0,0,,and assemble those into a list. Dialogue: 0,0:10:19.05,0:10:20.71,EN,,0,0,0,,So here's a procedure that does that. Dialogue: 0,0:10:23.73,0:10:26.24,EN,,0,0,0,,Find the odd Fibonacci numbers among the first n. Dialogue: 0,0:10:26.24,0:10:28.91,EN,,0,0,0,,And here is a standard loop the way we've been writing it. Dialogue: 0,0:10:28.91,0:10:29.82,EN,,0,0,0,,This is a recursion. Dialogue: 0,0:10:30.80,0:10:31.79,EN,,0,0,0,,It's a loop on k, Dialogue: 0,0:10:32.03,0:10:34.35,EN,,0,0,0,,and says if k is bigger than n, it's the empty list. Dialogue: 0,0:10:35.13,0:10:37.36,EN,,0,0,0,,Otherwise we compute the k-th Fibonacci number, Dialogue: 0,0:10:37.44,0:10:38.06,EN,,0,0,0,,call that f. Dialogue: 0,0:10:40.37,0:10:42.84,EN,,0,0,0,,If it's odd, we CONS it on Dialogue: 0,0:10:43.76,0:10:46.01,EN,,0,0,0,,to the list starting with the next one. Dialogue: 0,0:10:47.69,0:10:50.12,EN,,0,0,0,,And otherwise, we just take the next one. Dialogue: 0,0:10:50.73,0:10:53.00,EN,,0,0,0,,And this is the standard way we've been writing iterative loops. Dialogue: 0,0:10:53.00,0:10:55.56,EN,,0,0,0,,And we start off calling that loop with 1. Dialogue: 0,0:10:57.58,0:11:00.06,EN,,0,0,0,,OK, so there are two procedures. Dialogue: 0,0:11:01.60,0:11:02.90,EN,,0,0,0,,Those procedures look very different. Dialogue: 0,0:11:02.90,0:11:04.20,EN,,0,0,0,,They have very different structures. Dialogue: 0,0:11:04.25,0:11:06.89,EN,,0,0,0,,Yet from a certain point of view, Dialogue: 0,0:11:06.92,0:11:09.61,EN,,0,0,0,,those procedures are really doing very much the same thing. Dialogue: 0,0:11:11.33,0:11:14.67,EN,,0,0,0,,So if I was talking like a signal processing engineer, Dialogue: 0,0:11:14.70,0:11:16.81,EN,,0,0,0,,what I might say Dialogue: 0,0:11:18.24,0:11:26.76,EN,,0,0,0,,the first procedure enumerates the leaves of a tree. Dialogue: 0,0:11:31.16,0:11:34.56,EN,,0,0,0,,And then we can think of a signal coming out of that, which is all the leaves. Dialogue: 0,0:11:35.33,0:11:43.39,EN,,0,0,0,,We'll filter them to see which ones are odd, Dialogue: 0,0:11:43.58,0:11:44.94,EN,,0,0,0,,put them through some kind of filter. Dialogue: 0,0:11:45.19,0:11:47.79,EN,,0,0,0,,We'll then put them through a kind of transducer. Dialogue: 0,0:11:49.20,0:11:51.69,EN,,0,0,0,,And for each one of those things, we'll take the square. Dialogue: 0,0:11:54.44,0:11:57.44,EN,,0,0,0,,And then we'll accumulate all of those. Dialogue: 0,0:11:58.29,0:12:00.04,EN,,0,0,0,,We'll accumulate them by sticking them together Dialogue: 0,0:12:00.35,0:12:03.37,EN,,0,0,0,,with addition starting from 0. Dialogue: 0,0:12:07.14,0:12:08.21,EN,,0,0,0,,That's the first program. Dialogue: 0,0:12:08.21,0:12:09.18,EN,,0,0,0,,The second program, Dialogue: 0,0:12:09.24,0:12:11.21,EN,,0,0,0,,I can describe in a very, very similar way. Dialogue: 0,0:12:11.78,0:12:13.42,EN,,0,0,0,,I'll say, we'll enumerate Dialogue: 0,0:12:15.80,0:12:19.10,EN,,0,0,0,,the numbers on this interval, for the interval 1 through n. Dialogue: 0,0:12:22.50,0:12:24.40,EN,,0,0,0,,We'll, for each one, Dialogue: 0,0:12:25.45,0:12:26.92,EN,,0,0,0,,compute the Fibonacci number, Dialogue: 0,0:12:27.79,0:12:29.27,EN,,0,0,0,,put them through a transducer. Dialogue: 0,0:12:29.27,0:12:30.78,EN,,0,0,0,,We'll then take the result of that, Dialogue: 0,0:12:31.31,0:12:34.20,EN,,0,0,0,,and we'll filter it for oddness. Dialogue: 0,0:12:36.27,0:12:39.24,EN,,0,0,0,,And then we'll take those and put them into an accumulator. Dialogue: 0,0:12:39.35,0:12:40.56,EN,,0,0,0,,This time we'll build up a list, Dialogue: 0,0:12:40.78,0:12:42.17,EN,,0,0,0,,so we'll accumulate with CONS Dialogue: 0,0:12:42.59,0:12:43.77,EN,,0,0,0,,starting from the empty list. Dialogue: 0,0:12:47.11,0:12:49.80,EN,,0,0,0,,So this way of looking at the program Dialogue: 0,0:12:49.85,0:12:51.84,EN,,0,0,0,,makes the two seem very, very similar. Dialogue: 0,0:12:51.90,0:12:52.84,EN,,0,0,0,,The problem is Dialogue: 0,0:12:53.20,0:12:56.49,EN,,0,0,0,,that that commonality is completely obscured Dialogue: 0,0:12:56.64,0:12:58.05,EN,,0,0,0,,when we look at the procedures we wrote. Dialogue: 0,0:12:58.05,0:13:01.44,EN,,0,0,0,,Let's go back and look at some odd squares again, Dialogue: 0,0:13:02.22,0:13:04.64,EN,,0,0,0,,and say things like, where's the enumerator? Dialogue: 0,0:13:06.35,0:13:08.14,EN,,0,0,0,,Where's the enumerator in this program? Dialogue: 0,0:13:08.14,0:13:10.52,EN,,0,0,0,,Well, it's not in one place. Dialogue: 0,0:13:11.02,0:13:15.47,EN,,0,0,0,,It's a little bit in this leaf-node test, Dialogue: 0,0:13:16.43,0:13:17.16,EN,,0,0,0,,which is going to stop. Dialogue: 0,0:13:17.16,0:13:20.06,EN,,0,0,0,,It's a little bit in the recursive structure of the thing itself. Dialogue: 0,0:13:23.15,0:13:24.12,EN,,0,0,0,,Where's the accumulator? Dialogue: 0,0:13:24.12,0:13:25.68,EN,,0,0,0,,The accumulator isn't in one place either. Dialogue: 0,0:13:25.68,0:13:30.73,EN,,0,0,0,,It's partly in this 0 and partly in this plus. Dialogue: 0,0:13:32.00,0:13:34.51,EN,,0,0,0,,Right? It's not there as a thing that we can look at. Dialogue: 0,0:13:34.51,0:13:39.05,EN,,0,0,0,,Similarly, if we look at odd Fibs, Dialogue: 0,0:13:39.05,0:13:42.80,EN,,0,0,0,,that's also, in some sense, an enumerator and an accumulator, Dialogue: 0,0:13:42.80,0:13:44.01,EN,,0,0,0,,but it looks very different. Dialogue: 0,0:13:44.62,0:13:50.09,EN,,0,0,0,,Because partly, the enumerator is here in this greater than sign in the test. Dialogue: 0,0:13:50.38,0:13:52.84,EN,,0,0,0,,And partly it's in this whole recursive structure in the loop, Dialogue: 0,0:13:53.18,0:13:54.24,EN,,0,0,0,,and the way that we call it. Dialogue: 0,0:13:55.68,0:13:56.32,EN,,0,0,0,,And then similarly, Dialogue: 0,0:13:56.52,0:13:58.76,EN,,0,0,0,,that's also mixed up in there with the accumulator, Dialogue: 0,0:13:58.91,0:14:00.12,EN,,0,0,0,,which is partly over there Dialogue: 0,0:14:00.41,0:14:01.40,EN,,0,0,0,,and partly over there. Dialogue: 0,0:14:03.60,0:14:06.08,EN,,0,0,0,,So these very, very natural pieces, Dialogue: 0,0:14:08.73,0:14:12.65,EN,,0,0,0,,these very natural boxes here don't appear in our programs. Dialogue: 0,0:14:13.26,0:14:14.36,EN,,0,0,0,,Because they're kind of mixed up. Dialogue: 0,0:14:14.36,0:14:16.29,EN,,0,0,0,,The programs don't chop things up in the right way. Dialogue: 0,0:14:19.45,0:14:22.17,EN,,0,0,0,,Going back to this fundamental principle of computer science Dialogue: 0,0:14:22.19,0:14:23.63,EN,,0,0,0,,that in order to control something, Dialogue: 0,0:14:23.63,0:14:24.96,EN,,0,0,0,,you need the name of it, Dialogue: 0,0:14:25.80,0:14:28.44,EN,,0,0,0,,we don't really have control over thinking about things this way Dialogue: 0,0:14:28.67,0:14:31.06,EN,,0,0,0,,because we don't have our hands in them explicitly. Dialogue: 0,0:14:31.06,0:14:33.80,EN,,0,0,0,,We don't have a good language for talking about them. Dialogue: 0,0:14:35.42,0:14:38.86,EN,,0,0,0,,Well, let's invent an appropriate language Dialogue: 0,0:14:42.52,0:14:44.04,EN,,0,0,0,,in which we can build these pieces. Dialogue: 0,0:14:44.78,0:14:47.21,EN,,0,0,0,,The key to the language is these guys, Dialogue: 0,0:14:47.21,0:14:49.71,EN,,0,0,0,,is what is these things I called signals? Dialogue: 0,0:14:50.48,0:14:53.32,EN,,0,0,0,,What are these things that are flying on the arrows between the boxes? Dialogue: 0,0:14:56.88,0:14:57.71,EN,,0,0,0,,Well, those things Dialogue: 0,0:14:59.85,0:15:03.52,EN,,0,0,0,,are going to be data structures called streams. Dialogue: 0,0:15:03.79,0:15:05.87,EN,,0,0,0,,That's going to be the key to inventing this language. Dialogue: 0,0:15:07.98,0:15:08.51,EN,,0,0,0,,What's a stream? Dialogue: 0,0:15:08.52,0:15:11.50,EN,,0,0,0,,Well, a stream is, like anything else, a data abstraction. Dialogue: 0,0:15:12.22,0:15:15.82,EN,,0,0,0,,So I should tell you what its selectors and constructors are. Dialogue: 0,0:15:16.87,0:15:19.48,EN,,0,0,0,,For a stream, we're going to have one constructor Dialogue: 0,0:15:19.98,0:15:21.43,EN,,0,0,0,,that's called CONS-stream. Dialogue: 0,0:15:25.69,0:15:28.11,EN,,0,0,0,,CONS-stream is going to put two things together Dialogue: 0,0:15:28.59,0:15:30.22,EN,,0,0,0,,to form a thing called a stream. Dialogue: 0,0:15:32.04,0:15:33.85,EN,,0,0,0,,And then to extract things from the stream, Dialogue: 0,0:15:33.98,0:15:36.11,EN,,0,0,0,,we're going to have a selector called the head of the stream. Dialogue: 0,0:15:38.01,0:15:38.86,EN,,0,0,0,,So if I have a stream, Dialogue: 0,0:15:39.00,0:15:40.41,EN,,0,0,0,,I can take its head Dialogue: 0,0:15:41.13,0:15:42.38,EN,,0,0,0,,or I can take its tail. Dialogue: 0,0:15:44.72,0:15:47.42,EN,,0,0,0,,And remember, I have to tell you George's contract Dialogue: 0,0:15:48.24,0:15:52.70,EN,,0,0,0,,to tell you what the axioms are that relate these. Dialogue: 0,0:15:53.44,0:16:00.17,EN,,0,0,0,,And it's going to be for any x and y, Dialogue: 0,0:16:03.40,0:16:05.44,EN,,0,0,0,,if I form the CONS-stream and take the head, Dialogue: 0,0:16:05.69,0:16:11.96,EN,,0,0,0,,the head of CONS-stream of x and y Dialogue: 0,0:16:13.29,0:16:14.52,EN,,0,0,0,,is going to be x Dialogue: 0,0:16:16.14,0:16:27.45,EN,,0,0,0,,and the tail of CONS-stream of x and y is going to be y. Dialogue: 0,0:16:28.44,0:16:34.75,EN,,0,0,0,,So those are the constructor, two selectors for streams, and an axiom. Dialogue: 0,0:16:34.75,0:16:35.85,EN,,0,0,0,,There's something fishy here. Dialogue: 0,0:16:36.98,0:16:39.00,EN,,0,0,0,,So you might notice that these are exactly Dialogue: 0,0:16:40.19,0:16:42.08,EN,,0,0,0,,the axioms for CONS, CAR, and CDR. Dialogue: 0,0:16:43.63,0:16:46.56,EN,,0,0,0,,So if I said instead of writing CONS-stream I wrote CONS Dialogue: 0,0:16:47.10,0:16:49.80,EN,,0,0,0,,and I said head was the CAR and tail was the CDR, Dialogue: 0,0:16:50.76,0:16:52.81,EN,,0,0,0,,those are exactly the axioms for pairs. Dialogue: 0,0:16:52.81,0:16:54.32,EN,,0,0,0,,And in fact, there's another thing here. Dialogue: 0,0:16:55.13,0:16:56.80,EN,,0,0,0,,We're going to have a thing called the-empty-stream Dialogue: 0,0:17:02.80,0:17:04.04,EN,,0,0,0,,which is like the-empty-list. Dialogue: 0,0:17:08.31,0:17:10.03,EN,,0,0,0,,So why am I introducing this terminology? Dialogue: 0,0:17:10.03,0:17:12.12,EN,,0,0,0,,Why don't I just keep talking about pairs and lists? Dialogue: 0,0:17:12.78,0:17:13.79,EN,,0,0,0,,Well, we'll see. Dialogue: 0,0:17:15.51,0:17:18.24,EN,,0,0,0,,For now, if you like, why don't you just pretend Dialogue: 0,0:17:18.30,0:17:21.56,EN,,0,0,0,,that streams really are just a terminology for lists. Dialogue: 0,0:17:21.56,0:17:22.99,EN,,0,0,0,,And we'll see in a little while why Dialogue: 0,0:17:23.61,0:17:26.09,EN,,0,0,0,,why we want to keep this extra abstraction layer Dialogue: 0,0:17:26.83,0:17:28.15,EN,,0,0,0,,and not just call them lists. Dialogue: 0,0:17:32.30,0:17:33.72,EN,,0,0,0,,OK, now that we have streams, Dialogue: 0,0:17:33.74,0:17:35.85,EN,,0,0,0,,we can start constructing the pieces of the language Dialogue: 0,0:17:37.04,0:17:38.17,EN,,0,0,0,,to operate on streams. Dialogue: 0,0:17:38.75,0:17:42.12,EN,,0,0,0,,And there are a whole bunch of very useful things that we could start making. Dialogue: 0,0:17:42.12,0:17:42.81,EN,,0,0,0,,For instance, Dialogue: 0,0:17:44.89,0:17:49.79,EN,,0,0,0,,we'll make our map box to take a stream, s, Dialogue: 0,0:17:54.80,0:17:56.62,EN,,0,0,0,,and a procedure, Dialogue: 0,0:17:57.80,0:17:59.21,EN,,0,0,0,,and to generate a new stream Dialogue: 0,0:18:00.14,0:18:02.28,EN,,0,0,0,,which has as its elements Dialogue: 0,0:18:02.28,0:18:04.88,EN,,0,0,0,,the procedure applied to all the successive elements of s. Dialogue: 0,0:18:05.87,0:18:07.40,EN,,0,0,0,,In fact, we've seen this before. Dialogue: 0,0:18:07.40,0:18:10.24,EN,,0,0,0,,This is the procedure map that we did with lists. Dialogue: 0,0:18:10.95,0:18:12.60,EN,,0,0,0,,And you see it's exactly map, Dialogue: 0,0:18:12.60,0:18:14.65,EN,,0,0,0,,except we're testing for empty-stream. Dialogue: 0,0:18:14.65,0:18:15.56,EN,,0,0,0,,Oh, I forgot to mention that. Dialogue: 0,0:18:15.56,0:18:17.15,EN,,0,0,0,,Empty-stream is like the null test. Dialogue: 0,0:18:18.03,0:18:20.48,EN,,0,0,0,,So if it's empty, we generate the empty stream. Dialogue: 0,0:18:20.51,0:18:22.28,EN,,0,0,0,,Otherwise, we form a new stream Dialogue: 0,0:18:23.52,0:18:27.18,EN,,0,0,0,,whose first element is the procedure applied to the head of the stream, Dialogue: 0,0:18:28.51,0:18:29.32,EN,,0,0,0,,and whose rest Dialogue: 0,0:18:29.60,0:18:32.43,EN,,0,0,0,,is gotten by mapping along with the procedure down the tail of the stream. Dialogue: 0,0:18:33.14,0:18:35.90,EN,,0,0,0,,So that looks exactly like the map procedure we looked at before. Dialogue: 0,0:18:37.03,0:18:38.20,EN,,0,0,0,,Here's another useful thing. Dialogue: 0,0:18:38.35,0:18:40.46,EN,,0,0,0,,Filter, this is our filter box. Dialogue: 0,0:18:40.46,0:18:43.89,EN,,0,0,0,,We're going to have a predicate and a stream. Dialogue: 0,0:18:43.89,0:18:45.08,EN,,0,0,0,,We're going to make a new stream Dialogue: 0,0:18:45.80,0:18:48.17,EN,,0,0,0,,consists of all the elements of the original one that satisfy the predicate. Dialogue: 0,0:18:48.33,0:18:49.48,EN,,0,0,0,,that satisfy the predicate. Dialogue: 0,0:18:50.38,0:18:51.31,EN,,0,0,0,,That's case analysis. Dialogue: 0,0:18:51.32,0:18:52.73,EN,,0,0,0,,When there's nothing in the stream, Dialogue: 0,0:18:53.04,0:18:54.22,EN,,0,0,0,,we return the empty stream. Dialogue: 0,0:18:56.28,0:18:59.18,EN,,0,0,0,,We test the predicate on the head of the stream. Dialogue: 0,0:19:00.06,0:19:01.04,EN,,0,0,0,,And if it's true, Dialogue: 0,0:19:01.53,0:19:02.83,EN,,0,0,0,,we add the head of the stream onto the result Dialogue: 0,0:19:03.02,0:19:06.22,EN,,0,0,0,,the result of filtering the tail of the stream. Dialogue: 0,0:19:08.22,0:19:10.04,EN,,0,0,0,,And otherwise, if that predicate was false, Dialogue: 0,0:19:10.49,0:19:11.98,EN,,0,0,0,,we just filter the tail of the stream. Dialogue: 0,0:19:13.50,0:19:14.46,EN,,0,0,0,,Right, so there's filter. Dialogue: 0,0:19:16.59,0:19:18.56,EN,,0,0,0,,Let me run through a couple more rather quickly. Dialogue: 0,0:19:18.56,0:19:20.70,EN,,0,0,0,,They're all in the book and you can look at them. Dialogue: 0,0:19:20.88,0:19:21.80,EN,,0,0,0,,Let me just flash through. Dialogue: 0,0:19:22.11,0:19:22.94,EN,,0,0,0,,Here's accumulate. Dialogue: 0,0:19:23.26,0:19:26.92,EN,,0,0,0,,Accumulate takes a way of combining things Dialogue: 0,0:19:27.36,0:19:29.05,EN,,0,0,0,,an initial value in a stream Dialogue: 0,0:19:29.96,0:19:31.13,EN,,0,0,0,,and sticks them all together. Dialogue: 0,0:19:31.56,0:19:33.69,EN,,0,0,0,,If the stream's empty, it's just the initial value. Dialogue: 0,0:19:33.97,0:19:36.20,EN,,0,0,0,,Otherwise, we combine the head of the stream Dialogue: 0,0:19:36.32,0:19:37.82,EN,,0,0,0,,with the result of accumulating Dialogue: 0,0:19:38.01,0:19:40.24,EN,,0,0,0,,the tail of the stream starting from the initial value. Dialogue: 0,0:19:40.90,0:19:42.83,EN,,0,0,0,,So that's what I'd use to add up everything in the stream. Dialogue: 0,0:19:42.83,0:19:43.98,EN,,0,0,0,,I'd accumulate with plus. Dialogue: 0,0:19:45.83,0:19:47.56,EN,,0,0,0,,How would I enumerate the leaves of a tree? Dialogue: 0,0:19:48.06,0:19:52.89,EN,,0,0,0,,Well, if the tree is just a leaf itself, Dialogue: 0,0:19:53.79,0:19:55.90,EN,,0,0,0,,I make something which only has that node in it. Dialogue: 0,0:19:56.64,0:19:59.32,EN,,0,0,0,,Otherwise, I append together the stuff of enumerating Dialogue: 0,0:19:59.61,0:20:02.35,EN,,0,0,0,,the left branch and the right branch. Dialogue: 0,0:20:04.34,0:20:08.32,EN,,0,0,0,,And then append here is like the ordinary append on lists. Dialogue: 0,0:20:13.19,0:20:13.85,EN,,0,0,0,,You can look at that. Dialogue: 0,0:20:13.85,0:20:17.53,EN,,0,0,0,,That's analogous to the ordinary procedure for appending two lists. Dialogue: 0,0:20:18.91,0:20:20.60,EN,,0,0,0,,Ah... How would I enumerate an interval? Dialogue: 0,0:20:21.96,0:20:23.77,EN,,0,0,0,,This will take two integers, low and high, Dialogue: 0,0:20:23.88,0:20:27.00,EN,,0,0,0,,and generate a stream of the integers going from low to high. Dialogue: 0,0:20:28.32,0:20:29.88,EN,,0,0,0,,And we can make a whole bunch of pieces. Dialogue: 0,0:20:31.89,0:20:34.48,EN,,0,0,0,,So that's a little language of talking about streams. Dialogue: 0,0:20:34.49,0:20:35.32,EN,,0,0,0,,Once we have streams, Dialogue: 0,0:20:35.32,0:20:37.67,EN,,0,0,0,,we can build things for manipulating them. Dialogue: 0,0:20:37.67,0:20:39.04,EN,,0,0,0,,Again, we're making a language. Dialogue: 0,0:20:40.20,0:20:42.22,EN,,0,0,0,,And now we can start expressing things in this language. Dialogue: 0,0:20:43.06,0:20:47.31,EN,,0,0,0,,Here's our original procedure for summing the odd squares in a tree. Dialogue: 0,0:20:47.31,0:20:52.62,EN,,0,0,0,,And you'll notice it looks exactly now like the block diagram, Dialogue: 0,0:20:52.64,0:20:54.59,EN,,0,0,0,,like the signal processing block diagram. Dialogue: 0,0:20:54.59,0:20:57.53,EN,,0,0,0,,So to sum the odd squares in a tree, Dialogue: 0,0:20:58.06,0:21:00.80,EN,,0,0,0,,we enumerate the leaves of the tree. Dialogue: 0,0:21:01.32,0:21:03.72,EN,,0,0,0,,We filter that for oddness. Dialogue: 0,0:21:04.83,0:21:06.54,EN,,0,0,0,,We map that for squareness. Dialogue: 0,0:21:09.32,0:21:13.34,EN,,0,0,0,,And we accumulate the result of that using addition, starting from 0. Dialogue: 0,0:21:14.76,0:21:17.20,EN,,0,0,0,,So we can see the pieces that we wanted. Dialogue: 0,0:21:17.29,0:21:19.36,EN,,0,0,0,,Similarly, the Fibonacci one, Dialogue: 0,0:21:20.04,0:21:21.88,EN,,0,0,0,,how do we get the odd Fibs? Dialogue: 0,0:21:22.05,0:21:24.57,EN,,0,0,0,,Well, we enumerate the interval from 1 to n, Dialogue: 0,0:21:26.32,0:21:28.64,EN,,0,0,0,,we map along that, Dialogue: 0,0:21:28.99,0:21:30.70,EN,,0,0,0,,computing the Fibonacci of each one. Dialogue: 0,0:21:30.92,0:21:33.79,EN,,0,0,0,,We filter the result of those for oddness. Dialogue: 0,0:21:34.81,0:21:36.64,EN,,0,0,0,,And we accumulate all of that stuff Dialogue: 0,0:21:36.88,0:21:39.12,EN,,0,0,0,,using CONS starting from the empty-list. Dialogue: 0,0:21:43.65,0:21:47.53,EN,,0,0,0,,OK, what's the advantage of this? Dialogue: 0,0:21:47.68,0:21:48.59,EN,,0,0,0,,Well, for one thing, Dialogue: 0,0:21:48.68,0:21:51.15,EN,,0,0,0,,we now have pieces that we can start mixing and matching. Dialogue: 0,0:21:51.88,0:21:52.64,EN,,0,0,0,,So for instance, Dialogue: 0,0:21:52.91,0:21:55.08,EN,,0,0,0,,if I wanted to change this, if I wanted to ah... Dialogue: 0,0:21:58.19,0:22:00.32,EN,,0,0,0,,compute the squares of the integers and then filter them, Dialogue: 0,0:22:00.33,0:22:01.34,EN,,0,0,0,,all I need to do Dialogue: 0,0:22:01.90,0:22:03.64,EN,,0,0,0,,is pick up a standard piece like this Dialogue: 0,0:22:03.68,0:22:05.40,EN,,0,0,0,,it's a map square and put it in. Dialogue: 0,0:22:06.57,0:22:07.60,EN,,0,0,0,,Or if we wanted to do Dialogue: 0,0:22:07.69,0:22:11.45,EN,,0,0,0,,this whole Fibonacci computation on the leaves of a tree Dialogue: 0,0:22:11.58,0:22:12.36,EN,,0,0,0,,rather than a sequence, Dialogue: 0,0:22:12.38,0:22:13.24,EN,,0,0,0,,all I need to do Dialogue: 0,0:22:13.40,0:22:15.93,EN,,0,0,0,,is replace this enumerator with that one. Dialogue: 0,0:22:18.03,0:22:19.82,EN,,0,0,0,,See, the advantage of this stream processing Dialogue: 0,0:22:20.24,0:22:21.53,EN,,0,0,0,,is that we're establishing-- Dialogue: 0,0:22:22.36,0:22:24.96,EN,,0,0,0,,this is one of the big themes of the course-- Dialogue: 0,0:22:25.29,0:22:27.48,EN,,0,0,0,,we're establishing conventional interfaces Dialogue: 0,0:22:32.89,0:22:37.15,EN,,0,0,0,,conventional interfaces that allow us to glue things together. Dialogue: 0,0:22:38.30,0:22:39.55,EN,,0,0,0,,Things like map and filter Dialogue: 0,0:22:39.79,0:22:41.64,EN,,0,0,0,,are a standard set of components Dialogue: 0,0:22:41.68,0:22:44.76,EN,,0,0,0,,that we can start using for pasting together programs in all sorts of ways. Dialogue: 0,0:22:45.75,0:22:48.81,EN,,0,0,0,,It allows us to see the commonality of programs. Dialogue: 0,0:22:49.95,0:22:50.92,EN,,0,0,0,,I just ought to mention, Dialogue: 0,0:22:51.08,0:22:53.07,EN,,0,0,0,,I've only showed you two procedures. Dialogue: 0,0:22:53.86,0:22:55.16,EN,,0,0,0,,But let me emphasize Dialogue: 0,0:22:55.20,0:22:57.77,EN,,0,0,0,,that this way of putting things together Dialogue: 0,0:22:57.80,0:23:01.00,EN,,0,0,0,,with maps, filters, and accumulators is very, very general. Dialogue: 0,0:23:01.41,0:23:07.28,EN,,0,0,0,,It's the generate and test paradigm for programs. Dialogue: 0,0:23:07.77,0:23:09.10,EN,,0,0,0,,And as an example of that, Dialogue: 0,0:23:09.39,0:23:12.94,EN,,0,0,0,,Richard Waters, who was at MIT when he was a graduate student, Dialogue: 0,0:23:12.96,0:23:15.26,EN,,0,0,0,,as part of his thesis research went and analyzed Dialogue: 0,0:23:15.80,0:23:19.21,EN,,0,0,0,,a large chunk of the IBM scientific subroutine library, Dialogue: 0,0:23:19.82,0:23:23.31,EN,,0,0,0,,and discovered that about 60% of the programs in it Dialogue: 0,0:23:24.06,0:23:28.25,EN,,0,0,0,,could be expressed exactly in terms using no more than what we've put here-- Dialogue: 0,0:23:28.86,0:23:30.17,EN,,0,0,0,,map, filter, and accumulate. Dialogue: 0,0:23:30.57,0:23:31.50,EN,,0,0,0,,All right, let's take a break. Dialogue: 0,0:23:36.59,0:23:37.12,EN,,0,0,0,,Questions? Dialogue: 0,0:23:41.18,0:23:42.89,EN,,0,0,0,,AUDIENCE: It seems like the essence of this whole thing Dialogue: 0,0:23:42.89,0:23:45.96,EN,,0,0,0,,is just that you have a very uniform, simple data structure Dialogue: 0,0:23:46.25,0:23:47.66,EN,,0,0,0,,to work with, the stream. Dialogue: 0,0:23:48.38,0:23:48.92,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:23:48.92,0:23:50.38,EN,,0,0,0,,The essence is that you, again, Dialogue: 0,0:23:50.40,0:23:53.07,EN,,0,0,0,,it's this sense of conventional interfaces. Dialogue: 0,0:23:53.71,0:23:55.61,EN,,0,0,0,,So you can start putting a lot of things together. Dialogue: 0,0:23:56.01,0:23:58.78,EN,,0,0,0,,And the stream is as you say, Dialogue: 0,0:23:58.78,0:24:00.89,EN,,0,0,0,,the uniform data structure that supports that. Dialogue: 0,0:24:00.89,0:24:02.84,EN,,0,0,0,,This is very much like APL, by the way. Dialogue: 0,0:24:03.60,0:24:05.21,EN,,0,0,0,,APL is very much the same idea, Dialogue: 0,0:24:05.21,0:24:06.96,EN,,0,0,0,,except in APL, instead of this stream, Dialogue: 0,0:24:07.13,0:24:08.44,EN,,0,0,0,,you have arrays and vectors. Dialogue: 0,0:24:09.56,0:24:14.48,EN,,0,0,0,,And a lot of the power of APL is exactly the same reason of the power of this. Dialogue: 0,0:24:19.91,0:24:20.91,EN,,0,0,0,,OK, thank you. Dialogue: 0,0:24:20.91,0:24:21.66,EN,,0,0,0,,Let's take a break. Dialogue: 0,0:24:21.66,0:24:30.35,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:24:57.47,0:24:57.61,EN,,0,0,0,,All right. Dialogue: 0,0:24:57.61,0:24:58.59,EN,,0,0,0,,We've been looking at Dialogue: 0,0:25:00.54,0:25:03.20,EN,,0,0,0,,at ways of organizing computations using streams. Dialogue: 0,0:25:03.85,0:25:05.47,EN,,0,0,0,,But what I want to do now is just show you two Dialogue: 0,0:25:05.93,0:25:09.12,EN,,0,0,0,,somewhat more complicated examples of that. Dialogue: 0,0:25:10.84,0:25:14.12,EN,,0,0,0,,Let's start by thinking about the following Dialogue: 0,0:25:14.20,0:25:16.81,EN,,0,0,0,,kind of utility procedure that will come in useful. Dialogue: 0,0:25:16.81,0:25:18.09,EN,,0,0,0,,Suppose I've got a stream. Dialogue: 0,0:25:19.96,0:25:23.15,EN,,0,0,0,,And the elements of this stream are themselves streams. Dialogue: 0,0:25:23.98,0:25:26.53,EN,,0,0,0,,So the first thing might be 1, 2, 3. Dialogue: 0,0:25:32.72,0:25:33.88,EN,,0,0,0,,So I've got a stream. Dialogue: 0,0:25:33.88,0:25:40.10,EN,,0,0,0,,And each element of the stream is itself a stream. Dialogue: 0,0:25:40.97,0:25:43.42,EN,,0,0,0,,And what I'd like to do is build a stream Dialogue: 0,0:25:43.64,0:25:46.75,EN,,0,0,0,,that sort of collects together all of the elements, Dialogue: 0,0:25:46.76,0:25:49.24,EN,,0,0,0,,pulls all of the elements out of these sub-streams Dialogue: 0,0:25:50.11,0:25:51.82,EN,,0,0,0,,and strings them all together in one thing. Dialogue: 0,0:25:52.27,0:25:55.61,EN,,0,0,0,,So just to show you the use of this language, how easy it is, Dialogue: 0,0:25:56.11,0:25:57.10,EN,,0,0,0,,call that flatten. Dialogue: 0,0:25:57.95,0:26:10.64,EN,,0,0,0,,And I can define to flatten this stream of streams. Dialogue: 0,0:26:12.89,0:26:13.80,EN,,0,0,0,,Well, what is that? Dialogue: 0,0:26:13.96,0:26:16.24,EN,,0,0,0,,That's just an accumulation. Dialogue: 0,0:26:16.32,0:26:25.05,EN,,0,0,0,,I want to accumulate using append, Dialogue: 0,0:26:25.07,0:26:26.45,EN,,0,0,0,,by successively appending. Dialogue: 0,0:26:26.73,0:26:29.29,EN,,0,0,0,,So I accumulate using append streams, Dialogue: 0,0:26:35.90,0:26:48.20,EN,,0,0,0,,starting with the-empty-stream down that stream of streams. Dialogue: 0,0:26:54.84,0:26:55.84,EN,,0,0,0,,OK, so there's an example of Dialogue: 0,0:26:56.92,0:26:59.23,EN,,0,0,0,,how you can start using these higher order things Dialogue: 0,0:26:59.60,0:27:00.83,EN,,0,0,0,,to do some interesting operations. Dialogue: 0,0:27:00.83,0:27:05.10,EN,,0,0,0,,In fact, there's another useful thing that I want to do. Dialogue: 0,0:27:05.10,0:27:07.05,EN,,0,0,0,,I want to define a procedure called flat-map, Dialogue: 0,0:27:17.18,0:27:20.59,EN,,0,0,0,,flat map of some function and a stream. Dialogue: 0,0:27:21.84,0:27:25.72,EN,,0,0,0,,And what this is going to do is s will be a stream of elements. Dialogue: 0,0:27:25.72,0:27:27.69,EN,,0,0,0,,f is going to be a function Dialogue: 0,0:27:27.72,0:27:30.62,EN,,0,0,0,,for each element in the stream produces another stream. Dialogue: 0,0:27:31.95,0:27:34.52,EN,,0,0,0,,And what I want to do is take all of the elements and all of those streams Dialogue: 0,0:27:35.00,0:27:36.00,EN,,0,0,0,,and combine them together. Dialogue: 0,0:27:36.00,0:27:49.13,EN,,0,0,0,,So that's just going to be the flatten of map f down s. Dialogue: 0,0:27:51.20,0:27:53.04,EN,,0,0,0,,Each time I apply f to an element of s, Dialogue: 0,0:27:53.05,0:27:53.85,EN,,0,0,0,,I get a stream. Dialogue: 0,0:27:54.29,0:27:55.24,EN,,0,0,0,,If I map it all the way down, Dialogue: 0,0:27:55.24,0:27:56.27,EN,,0,0,0,,I get a stream of streams, Dialogue: 0,0:27:56.46,0:27:57.42,EN,,0,0,0,,and I'll flatten that. Dialogue: 0,0:27:58.67,0:28:02.64,EN,,0,0,0,,Well, I want to use that to show you a Dialogue: 0,0:28:03.87,0:28:05.84,EN,,0,0,0,,a new way to do a familiar kind of problem. Dialogue: 0,0:28:06.51,0:28:12.27,EN,,0,0,0,,The problem's going to be like a lot of problems you've seen, Dialogue: 0,0:28:12.28,0:28:13.96,EN,,0,0,0,,although maybe not this particular one. Dialogue: 0,0:28:14.19,0:28:15.49,EN,,0,0,0,,I'm going to give you an integer, n. Dialogue: 0,0:28:18.68,0:28:19.93,EN,,0,0,0,,And the problem is going to be Dialogue: 0,0:28:21.20,0:28:31.53,EN,,0,0,0,,find all pairs and integers i and j, Dialogue: 0,0:28:32.30,0:28:39.96,EN,,0,0,0,,between 0 and i, with j less than i, up to n, Dialogue: 0,0:28:42.33,0:28:52.03,EN,,0,0,0,,such that i plus j is prime. Dialogue: 0,0:28:55.74,0:28:57.92,EN,,0,0,0,,So for example, if n equals 6, Dialogue: 0,0:28:59.74,0:29:00.78,EN,,0,0,0,,let's make a little table here, Dialogue: 0,0:29:01.55,0:29:06.67,EN,,0,0,0,,i and j and i plus j. Dialogue: 0,0:29:09.70,0:29:14.91,EN,,0,0,0,,So for, say, i equals 2 and j equals 1, I'd get 3. Dialogue: 0,0:29:15.52,0:29:20.38,EN,,0,0,0,,And for i equals 3, I could have j equals 2, and that would be 5. Dialogue: 0,0:29:21.21,0:29:26.51,EN,,0,0,0,,And 4 and 1 would be 5 and so on, Dialogue: 0,0:29:26.92,0:29:28.11,EN,,0,0,0,,up until i goes to 6. Dialogue: 0,0:29:28.40,0:29:32.54,EN,,0,0,0,,And what I'd like to return is to produce a stream Dialogue: 0,0:29:33.20,0:29:37.04,EN,,0,0,0,,all the triples like this, let's say i, j, and i plus j. Dialogue: 0,0:29:37.66,0:29:39.55,EN,,0,0,0,,So for each n, I want to generate this stream. Dialogue: 0,0:29:40.97,0:29:43.68,EN,,0,0,0,,OK, well, that's easy. Dialogue: 0,0:29:43.68,0:29:44.35,EN,,0,0,0,,Let's build it up. Dialogue: 0,0:29:47.23,0:29:48.22,EN,,0,0,0,,We start like this. Dialogue: 0,0:29:50.15,0:29:54.25,EN,,0,0,0,,We're going to say for each i, for each i Dialogue: 0,0:29:55.24,0:29:56.44,EN,,0,0,0,,we're going to generate a stream. Dialogue: 0,0:29:57.00,0:29:58.59,EN,,0,0,0,,For each i in the interval 1 through n, Dialogue: 0,0:29:58.59,0:29:59.76,EN,,0,0,0,,we're going to generate a stream. Dialogue: 0,0:30:00.66,0:30:01.80,EN,,0,0,0,,What's that stream going to be? Dialogue: 0,0:30:02.23,0:30:04.04,EN,,0,0,0,,We're going to start by generating all the pairs. Dialogue: 0,0:30:04.18,0:30:07.55,EN,,0,0,0,,So for each i, we're going to generate, Dialogue: 0,0:30:08.43,0:30:14.52,EN,,0,0,0,,for each j in the interval 1 to i minus 1, Dialogue: 0,0:30:16.91,0:30:17.98,EN,,0,0,0,,we'll generate the pair, Dialogue: 0,0:30:18.35,0:30:20.71,EN,,0,0,0,,or the list with two elements i and j. Dialogue: 0,0:30:23.78,0:30:27.10,EN,,0,0,0,,So we map along the interval, Dialogue: 0,0:30:28.60,0:30:29.74,EN,,0,0,0,,generating the pairs. Dialogue: 0,0:30:31.07,0:30:33.17,EN,,0,0,0,,And for each i, that generates a stream of pairs. Dialogue: 0,0:30:33.40,0:30:34.49,EN,,0,0,0,,And we flatmap it. Dialogue: 0,0:30:34.59,0:30:36.20,EN,,0,0,0,,Now we have all the pairs i and j, Dialogue: 0,0:30:36.81,0:30:38.08,EN,,0,0,0,,such that i is less than j. Dialogue: 0,0:30:38.73,0:30:39.85,EN,,0,0,0,,So that builds that. Dialogue: 0,0:30:39.85,0:30:40.76,EN,,0,0,0,,Now we're got to test them. Dialogue: 0,0:30:42.99,0:30:45.84,EN,,0,0,0,,Well, we take that thing we just built, the flatmap, Dialogue: 0,0:30:46.94,0:30:51.37,EN,,0,0,0,,and we filter it to see whether the i-- see, we had an i and a j. Dialogue: 0,0:30:51.66,0:30:54.17,EN,,0,0,0,,i was the first thing in the list, Dialogue: 0,0:30:54.30,0:30:55.60,EN,,0,0,0,,j was the second thing in the list. Dialogue: 0,0:30:57.21,0:31:00.01,EN,,0,0,0,,So we have a predicate which says in that list of two elements Dialogue: 0,0:31:00.22,0:31:02.00,EN,,0,0,0,,is the sum of the CAR and the CDR prime. Dialogue: 0,0:31:02.07,0:31:05.52,EN,,0,0,0,,And we filter that collection of pairs we just built. Dialogue: 0,0:31:06.54,0:31:07.85,EN,,0,0,0,,So those are the pairs we want. Dialogue: 0,0:31:09.42,0:31:10.24,EN,,0,0,0,,Now we go ahead Dialogue: 0,0:31:10.88,0:31:13.10,EN,,0,0,0,,Now we go ahead and we take the result of that filter Dialogue: 0,0:31:13.26,0:31:19.05,EN,,0,0,0,,we map along it, generating the list i and j and i plus j. Dialogue: 0,0:31:19.61,0:31:21.39,EN,,0,0,0,,And that's our procedure prime-sum-pairs. Dialogue: 0,0:31:22.57,0:31:24.76,EN,,0,0,0,,Ok, and then just to flash it up, here's the whole procedure. Dialogue: 0,0:31:28.08,0:31:30.97,EN,,0,0,0,,A map, a filter, a flatmap. Dialogue: 0,0:31:34.85,0:31:35.66,EN,,0,0,0,,There's the whole thing, Dialogue: 0,0:31:35.66,0:31:37.12,EN,,0,0,0,,even though this isn't particularly readable. Dialogue: 0,0:31:37.42,0:31:38.94,EN,,0,0,0,,It's just expanding that flatmap. Dialogue: 0,0:31:39.84,0:31:40.88,EN,,0,0,0,,So there's an example Dialogue: 0,0:31:43.28,0:31:45.00,EN,,0,0,0,,which illustrates the general point Dialogue: 0,0:31:45.12,0:31:46.30,EN,,0,0,0,,that nested loops Dialogue: 0,0:31:47.66,0:31:50.09,EN,,0,0,0,,in this procedure start looking like compositions of Dialogue: 0,0:31:50.11,0:31:52.81,EN,,0,0,0,,flatmaps of flatmaps of flatmaps of maps and things. Dialogue: 0,0:31:54.27,0:31:57.61,EN,,0,0,0,,So not only can we enumerate individual things, Dialogue: 0,0:31:57.61,0:31:58.81,EN,,0,0,0,,but by using flatmaps, Dialogue: 0,0:31:59.12,0:32:02.24,EN,,0,0,0,,we can do what would correspond to nested loops in most other languages. Dialogue: 0,0:32:03.23,0:32:03.76,EN,,0,0,0,,Of course, Dialogue: 0,0:32:04.91,0:32:08.03,EN,,0,0,0,,it's pretty awful to keep writing these flatmaps of flatmaps of flatmaps. Dialogue: 0,0:32:08.41,0:32:13.00,EN,,0,0,0,,Prime-sum-pairs you saw looked fairly complicated, Dialogue: 0,0:32:13.56,0:32:15.28,EN,,0,0,0,,even though the individual pieces were easy. Dialogue: 0,0:32:15.48,0:32:17.13,EN,,0,0,0,,So what you can do, if you like, Dialogue: 0,0:32:17.15,0:32:20.12,EN,,0,0,0,,is introduced some syntactic sugar that's called collect. Dialogue: 0,0:32:21.04,0:32:22.68,EN,,0,0,0,,And collect is just an abbreviation Dialogue: 0,0:32:22.91,0:32:26.16,EN,,0,0,0,,for that nest of flatmaps and filters arranged in that particular way. Dialogue: 0,0:32:26.16,0:32:28.60,EN,,0,0,0,,Here's prime-sum-pairs again, written using collect. Dialogue: 0,0:32:29.45,0:32:36.27,EN,,0,0,0,,It says to find all those pairs, I'm going to collect together a result, Dialogue: 0,0:32:36.52,0:32:39.20,EN,,0,0,0,,which is the list i, j, and i plus j, Dialogue: 0,0:32:40.84,0:32:45.39,EN,,0,0,0,,that's going to be generated as i runs through the interval from 1 to n Dialogue: 0,0:32:47.44,0:32:52.32,EN,,0,0,0,,and as j runs through the interval from 1 to i minus 1 Dialogue: 0,0:32:54.16,0:32:56.54,EN,,0,0,0,,such that i plus j is prime. Dialogue: 0,0:32:58.04,0:33:00.32,EN,,0,0,0,,So I'm not going to say what collect does in general. Dialogue: 0,0:33:00.69,0:33:02.75,EN,,0,0,0,,You can look at that by looking at it in the book. Dialogue: 0,0:33:03.42,0:33:05.45,EN,,0,0,0,,But pretty much, you can see that the pieces of this Dialogue: 0,0:33:05.84,0:33:08.60,EN,,0,0,0,,are the pieces of that original procedure I wrote. Dialogue: 0,0:33:08.82,0:33:11.40,EN,,0,0,0,,And this collect is just some syntactic sugar Dialogue: 0,0:33:11.44,0:33:14.80,EN,,0,0,0,,for automatically generating that nest of flatmaps and flatmaps. Dialogue: 0,0:33:16.31,0:33:20.33,EN,,0,0,0,,OK, well, let me do one more example Dialogue: 0,0:33:20.67,0:33:22.00,EN,,0,0,0,,that shows you the same kind of thing. Dialogue: 0,0:33:22.12,0:33:23.53,EN,,0,0,0,,Here's a very famous problem Dialogue: 0,0:33:24.70,0:33:28.75,EN,,0,0,0,,that's used to illustrate a lot of so-called backtracking computer algorithms Dialogue: 0,0:33:28.76,0:33:30.20,EN,,0,0,0,,This is the eight queens problem. Dialogue: 0,0:33:30.20,0:33:31.08,EN,,0,0,0,,This is a chess board. Dialogue: 0,0:33:32.37,0:33:33.64,EN,,0,0,0,,And the eight queens problem says, Dialogue: 0,0:33:33.64,0:33:35.85,EN,,0,0,0,,find a way to put down eight queens on a chess board Dialogue: 0,0:33:36.44,0:33:38.00,EN,,0,0,0,,so that no two are attacking each other. Dialogue: 0,0:33:38.00,0:33:40.60,EN,,0,0,0,,And here's a particular solution to the eight queens problem. Dialogue: 0,0:33:41.21,0:33:43.68,EN,,0,0,0,,So I have to make sure to put down queens Dialogue: 0,0:33:43.71,0:33:46.80,EN,,0,0,0,,no two are in the same row or the same column Dialogue: 0,0:33:47.72,0:33:49.47,EN,,0,0,0,,or sit along the same diagonal. Dialogue: 0,0:33:51.41,0:33:56.40,EN,,0,0,0,,Now, there's sort of a standard way of doing that. Dialogue: 0,0:33:59.74,0:34:01.48,EN,,0,0,0,,Well, first we need to do is Dialogue: 0,0:34:02.54,0:34:04.62,EN,,0,0,0,,below the surface, at George's level. Dialogue: 0,0:34:04.94,0:34:08.09,EN,,0,0,0,,We have to find some way to represent a board, and represent positions. Dialogue: 0,0:34:08.09,0:34:09.52,EN,,0,0,0,,And we'll not worry about that. Dialogue: 0,0:34:09.80,0:34:12.78,EN,,0,0,0,,But let's assume that there's a predicate called safe. Dialogue: 0,0:34:16.14,0:34:17.55,EN,,0,0,0,,And what safe is going to do Dialogue: 0,0:34:17.96,0:34:20.84,EN,,0,0,0,,is going to say given that I have a bunch of queens down on the chess board, Dialogue: 0,0:34:21.36,0:34:24.54,EN,,0,0,0,,is it OK to put a queen in this particular spot? Dialogue: 0,0:34:25.40,0:34:31.26,EN,,0,0,0,,So safe is going to take a row and a column. Dialogue: 0,0:34:32.76,0:34:35.47,EN,,0,0,0,,That's going to be a place where I'm going to try and put down the next queen, Dialogue: 0,0:34:36.06,0:34:42.76,EN,,0,0,0,,and the rest of positions. Dialogue: 0,0:34:45.58,0:34:46.75,EN,,0,0,0,,And what safe will say Dialogue: 0,0:34:46.86,0:34:51.68,EN,,0,0,0,,is given that I already have queens down in these positions, Dialogue: 0,0:34:53.02,0:34:54.76,EN,,0,0,0,,is it safe to put another queen down Dialogue: 0,0:34:55.10,0:34:57.20,EN,,0,0,0,,in that row and that column? Dialogue: 0,0:34:58.30,0:34:59.36,EN,,0,0,0,,And let's not worry about that. Dialogue: 0,0:34:59.36,0:35:01.38,EN,,0,0,0,,That's George's problem. and it's not hard to write. Dialogue: 0,0:35:01.38,0:35:06.27,EN,,0,0,0,,You just have to check whether this thing contains any things Dialogue: 0,0:35:06.30,0:35:08.52,EN,,0,0,0,,on that row or that column or in that diagonal. Dialogue: 0,0:35:10.53,0:35:13.12,EN,,0,0,0,,Now, how would you organize the program given that? Dialogue: 0,0:35:13.84,0:35:17.21,EN,,0,0,0,,And there's sort of a traditional way to organize it Dialogue: 0,0:35:17.93,0:35:18.97,EN,,0,0,0,,called backtracking. Dialogue: 0,0:35:20.52,0:35:23.21,EN,,0,0,0,,And it says, well, let's start off Dialogue: 0,0:35:25.13,0:35:28.88,EN,,0,0,0,,let's think about all the ways of putting the first queen down Dialogue: 0,0:35:30.04,0:35:31.34,EN,,0,0,0,,in the first column. Dialogue: 0,0:35:31.45,0:35:32.24,EN,,0,0,0,,There are eight ways. Dialogue: 0,0:35:32.58,0:35:35.00,EN,,0,0,0,,Well, let's say try the first column. Dialogue: 0,0:35:35.88,0:35:37.30,EN,,0,0,0,,Try column 1, row 1. Dialogue: 0,0:35:37.30,0:35:38.70,EN,,0,0,0,,These branches are going to represent Dialogue: 0,0:35:40.17,0:35:41.88,EN,,0,0,0,,the possibilities at each level. Dialogue: 0,0:35:43.36,0:35:45.53,EN,,0,0,0,,So I'll try and put a queen down in the first column. Dialogue: 0,0:35:46.14,0:35:47.74,EN,,0,0,0,,And now given that it's in the first column, Dialogue: 0,0:35:47.77,0:35:49.98,EN,,0,0,0,,I'll try and put the next queen down in the first column. Dialogue: 0,0:35:50.60,0:35:52.17,EN,,0,0,0,,That's no good, they're both... Dialogue: 0,0:35:53.31,0:35:54.60,EN,,0,0,0,,I'll try and put the first queen, Dialogue: 0,0:35:54.86,0:35:56.80,EN,,0,0,0,,the one in the first column, down in the first row. Dialogue: 0,0:35:56.92,0:35:57.47,EN,,0,0,0,,I'm sorry. Dialogue: 0,0:35:59.05,0:36:01.39,EN,,0,0,0,,And then given that, we'll put the next queen down in the first row. Dialogue: 0,0:36:01.39,0:36:02.09,EN,,0,0,0,,And that's no good. Dialogue: 0,0:36:02.09,0:36:03.18,EN,,0,0,0,,So I'll back up to here. Dialogue: 0,0:36:04.20,0:36:04.72,EN,,0,0,0,,And I'll say, Dialogue: 0,0:36:04.83,0:36:06.86,EN,,0,0,0,,oh, can I put the first queen down in the second row? Dialogue: 0,0:36:07.32,0:36:08.38,EN,,0,0,0,,Well, that's no good. Dialogue: 0,0:36:08.55,0:36:09.76,EN,,0,0,0,,Oh, can I put it down in the third row? Dialogue: 0,0:36:09.76,0:36:10.52,EN,,0,0,0,,Well, that's good. Dialogue: 0,0:36:12.79,0:36:15.13,EN,,0,0,0,,Well, now can I put the next queen down in the first column? Dialogue: 0,0:36:15.38,0:36:17.82,EN,,0,0,0,,Well, I can't visualize this chess board anymore, Dialogue: 0,0:36:17.82,0:36:18.86,EN,,0,0,0,,but I think that's right. Dialogue: 0,0:36:19.19,0:36:20.45,EN,,0,0,0,,And I try the next one. Dialogue: 0,0:36:20.45,0:36:24.17,EN,,0,0,0,,And at each place, I go as far down this tree as I can. Dialogue: 0,0:36:24.54,0:36:25.64,EN,,0,0,0,,And I back up. Dialogue: 0,0:36:25.64,0:36:28.97,EN,,0,0,0,,If I get down to here and find no possibilities below there, Dialogue: 0,0:36:29.00,0:36:30.12,EN,,0,0,0,,I back all the way up to here, Dialogue: 0,0:36:30.28,0:36:32.44,EN,,0,0,0,,and now start again generating this sub-tree. Dialogue: 0,0:36:33.26,0:36:34.32,EN,,0,0,0,,And I sort of walk around. Dialogue: 0,0:36:35.05,0:36:37.26,EN,,0,0,0,,And finally, if I ever manage to get all the way down, Dialogue: 0,0:36:37.72,0:36:38.59,EN,,0,0,0,,I've found a solution. Dialogue: 0,0:36:39.82,0:36:41.98,EN,,0,0,0,,So that's a typical sort of Dialogue: 0,0:36:43.12,0:36:45.93,EN,,0,0,0,,paradigm that's used a lot in AI programming. Dialogue: 0,0:36:45.93,0:36:47.30,EN,,0,0,0,,It's called backtracking search. Dialogue: 0,0:36:57.47,0:37:03.04,EN,,0,0,0,,And it's really unnecessary. Dialogue: 0,0:37:03.86,0:37:06.55,EN,,0,0,0,,You saw me get confused when I was visualizing this thing. Dialogue: 0,0:37:06.81,0:37:08.25,EN,,0,0,0,,And you sort of see the complication. Dialogue: 0,0:37:08.55,0:37:10.76,EN,,0,0,0,,This is a complicated thing to say. Dialogue: 0,0:37:10.76,0:37:11.82,EN,,0,0,0,,Why is it complicated? Dialogue: 0,0:37:12.39,0:37:13.29,EN,,0,0,0,,Its because somehow Dialogue: 0,0:37:13.53,0:37:17.39,EN,,0,0,0,,this program is too inordinately concerned with time. Dialogue: 0,0:37:18.58,0:37:20.43,EN,,0,0,0,,It's too much-- I try this one, and I try this one, Dialogue: 0,0:37:20.49,0:37:22.38,EN,,0,0,0,,and I go back to the last possibility. Dialogue: 0,0:37:22.89,0:37:24.34,EN,,0,0,0,,And that's a complicated thing. Dialogue: 0,0:37:24.34,0:37:26.36,EN,,0,0,0,,If I stop worrying about time so much, Dialogue: 0,0:37:28.04,0:37:29.76,EN,,0,0,0,,then there's a much simpler way to describe this. Dialogue: 0,0:37:31.20,0:37:32.36,EN,,0,0,0,,It says, let's imagine Dialogue: 0,0:37:33.31,0:37:36.57,EN,,0,0,0,,that I have in my hands Dialogue: 0,0:37:38.32,0:37:42.16,EN,,0,0,0,,the tree down to k minus 1 levels. Dialogue: 0,0:37:43.40,0:37:46.32,EN,,0,0,0,,See, suppose I had in my hands all possible ways Dialogue: 0,0:37:48.09,0:37:52.19,EN,,0,0,0,,to solve... to put down queens in the first k columns. Dialogue: 0,0:37:53.56,0:37:54.61,EN,,0,0,0,,Suppose I just had that. Dialogue: 0,0:37:54.61,0:37:55.79,EN,,0,0,0,,Let's not worry about how we get it. Dialogue: 0,0:37:57.07,0:37:59.20,EN,,0,0,0,,Well, then, how do I extend that? Dialogue: 0,0:37:59.20,0:38:02.16,EN,,0,0,0,,How do I find all possible ways to put down queens in the next column? Dialogue: 0,0:38:02.48,0:38:03.13,EN,,0,0,0,,It's really easy. Dialogue: 0,0:38:03.62,0:38:06.41,EN,,0,0,0,,For each of these positions I have, Dialogue: 0,0:38:07.82,0:38:13.96,EN,,0,0,0,,I enjoin, I think about putting down a queen in each row Dialogue: 0,0:38:15.08,0:38:16.16,EN,,0,0,0,,to make the next thing. Dialogue: 0,0:38:16.16,0:38:17.29,EN,,0,0,0,,And then for each one I put down, Dialogue: 0,0:38:17.44,0:38:19.71,EN,,0,0,0,,I filter those by the ones that are safe. Dialogue: 0,0:38:21.80,0:38:22.99,EN,,0,0,0,,So instead of thinking about Dialogue: 0,0:38:22.99,0:38:24.67,EN,,0,0,0,,this tree as generated step by step, Dialogue: 0,0:38:24.94,0:38:26.86,EN,,0,0,0,,I say, suppose I had it all there. Dialogue: 0,0:38:29.68,0:38:32.41,EN,,0,0,0,,And to extend it from level k minus 1 to level k, Dialogue: 0,0:38:32.64,0:38:36.24,EN,,0,0,0,,I just need to extend each thing in all possible ways Dialogue: 0,0:38:36.48,0:38:37.80,EN,,0,0,0,,and only keep the ones that are safe. Dialogue: 0,0:38:37.80,0:38:39.23,EN,,0,0,0,,And that will give me the tree to level k. Dialogue: 0,0:38:39.30,0:38:40.67,EN,,0,0,0,,And that's a recursive strategy Dialogue: 0,0:38:40.89,0:38:42.17,EN,,0,0,0,,for solving the eight queens problem. Dialogue: 0,0:38:44.53,0:38:45.34,EN,,0,0,0,,All right, well, let's look at it. Dialogue: 0,0:38:50.33,0:38:52.68,EN,,0,0,0,,To solve the eight queens problem Dialogue: 0,0:38:53.00,0:38:55.53,EN,,0,0,0,,on a board of some specified size, Dialogue: 0,0:38:58.92,0:39:01.03,EN,,0,0,0,,we write a sub-procedure called fill-columns. Dialogue: 0,0:39:01.13,0:39:04.86,EN,,0,0,0,,Fill-columns is going to put down queens up through column k. Dialogue: 0,0:39:06.35,0:39:07.70,EN,,0,0,0,,And here's the pattern of the recursion. Dialogue: 0,0:39:07.70,0:39:10.92,EN,,0,0,0,,I'm going to call fill-columns with the size eventually. Dialogue: 0,0:39:12.99,0:39:15.28,EN,,0,0,0,,So fill-columns says how to put down queens safely Dialogue: 0,0:39:15.29,0:39:17.16,EN,,0,0,0,,safely in the first k columns of this chess board Dialogue: 0,0:39:17.20,0:39:19.58,EN,,0,0,0,,with a size number of rows in it. Dialogue: 0,0:39:20.36,0:39:21.64,EN,,0,0,0,,If k is equal to 0, Dialogue: 0,0:39:22.27,0:39:23.60,EN,,0,0,0,,well, then I don't have to put anything down. Dialogue: 0,0:39:23.94,0:39:25.93,EN,,0,0,0,,So my solution is just an empty chess board. Dialogue: 0,0:39:26.71,0:39:28.07,EN,,0,0,0,,Otherwise, I'm going to do some stuff. Dialogue: 0,0:39:28.35,0:39:29.44,EN,,0,0,0,,And I'm going to use collect. Dialogue: 0,0:39:30.81,0:39:31.77,EN,,0,0,0,,And here's the collect. Dialogue: 0,0:39:34.33,0:39:41.91,EN,,0,0,0,,I find all ways to put down queens in the first k minus 1 columns. Dialogue: 0,0:39:42.19,0:39:43.32,EN,,0,0,0,,And this was just what I set for. Dialogue: 0,0:39:43.32,0:39:46.36,EN,,0,0,0,,Imagine I have this tree down to k minus 1 levels. Dialogue: 0,0:39:48.88,0:39:52.11,EN,,0,0,0,,And then I find all ways of trying a row, Dialogue: 0,0:39:52.52,0:39:54.13,EN,,0,0,0,,that's just each of the possible rows. Dialogue: 0,0:39:54.13,0:39:55.04,EN,,0,0,0,,They're size rows, Dialogue: 0,0:39:55.31,0:39:56.49,EN,,0,0,0,,so that's enumerate interval. Dialogue: 0,0:39:58.04,0:39:59.79,EN,,0,0,0,,And now what I do is I collect together Dialogue: 0,0:40:03.15,0:40:05.82,EN,,0,0,0,,the new row I'm going to try and column k Dialogue: 0,0:40:07.95,0:40:08.95,EN,,0,0,0,,with the rest of the queens. Dialogue: 0,0:40:08.95,0:40:10.09,EN,,0,0,0,,I adjoin a position. Dialogue: 0,0:40:10.20,0:40:11.29,EN,,0,0,0,,This is George's problem. Dialogue: 0,0:40:11.29,0:40:12.75,EN,,0,0,0,,An adjoined position is like safe. Dialogue: 0,0:40:13.64,0:40:15.28,EN,,0,0,0,,It's a thing that takes a row Dialogue: 0,0:40:15.50,0:40:17.04,EN,,0,0,0,,and a column and the rest of the positions Dialogue: 0,0:40:17.07,0:40:19.02,EN,,0,0,0,,and makes a new position collection. Dialogue: 0,0:40:19.66,0:40:25.77,EN,,0,0,0,,So I adjoin a position of a new row and a new column Dialogue: 0,0:40:26.06,0:40:27.68,EN,,0,0,0,,to the rest of the queens, Dialogue: 0,0:40:28.57,0:40:29.76,EN,,0,0,0,,where the rest of the queens Dialogue: 0,0:40:29.92,0:40:31.45,EN,,0,0,0,,runs through all possible ways Dialogue: 0,0:40:31.87,0:40:34.16,EN,,0,0,0,,of solving the problem in k minus 1 columns. Dialogue: 0,0:40:34.62,0:40:37.04,EN,,0,0,0,,And the new row runs through all possible rows Dialogue: 0,0:40:37.85,0:40:40.76,EN,,0,0,0,,such that it was safe to put one there. Dialogue: 0,0:40:43.24,0:40:44.70,EN,,0,0,0,,And that's the whole program. Dialogue: 0,0:40:46.33,0:40:47.31,EN,,0,0,0,,There's the whole procedure. Dialogue: 0,0:40:49.84,0:40:52.43,EN,,0,0,0,,Not only that, that doesn't just solve the eight queens problem, Dialogue: 0,0:40:53.42,0:40:56.68,EN,,0,0,0,,Right? It gives you all solutions to the eight queens problem. Dialogue: 0,0:40:56.68,0:40:58.48,EN,,0,0,0,,When you're done, you have a stream. Dialogue: 0,0:40:58.48,0:41:01.90,EN,,0,0,0,,And the elements of that stream are all possible ways of solving that problem. Dialogue: 0,0:41:05.31,0:41:06.26,EN,,0,0,0,,Why is that simpler? Dialogue: 0,0:41:06.26,0:41:08.54,EN,,0,0,0,,Well, we threw away the whole idea that Dialogue: 0,0:41:08.88,0:41:11.52,EN,,0,0,0,,is some process that happens in time with state. Dialogue: 0,0:41:12.72,0:41:14.42,EN,,0,0,0,,And we just said it's a whole collection of stuff. Dialogue: 0,0:41:14.94,0:41:16.00,EN,,0,0,0,,And that's why it's simpler. Dialogue: 0,0:41:18.00,0:41:20.11,EN,,0,0,0,,Right? We've changed our view. Dialogue: 0,0:41:20.11,0:41:22.59,EN,,0,0,0,,Remember, that's where we started today. Dialogue: 0,0:41:22.82,0:41:26.23,EN,,0,0,0,,We've changed our view of what it is we're trying to model. Dialogue: 0,0:41:26.23,0:41:29.20,EN,,0,0,0,,we stop modeling things that evolve in time Dialogue: 0,0:41:29.37,0:41:31.31,EN,,0,0,0,,have steps and have state. Dialogue: 0,0:41:31.75,0:41:33.79,EN,,0,0,0,,And instead, we're trying to model this global thing Dialogue: 0,0:41:33.80,0:41:35.93,EN,,0,0,0,,like the whole flight of the chalk, Dialogue: 0,0:41:36.28,0:41:38.88,EN,,0,0,0,,rather than its state at each instant. Dialogue: 0,0:41:40.75,0:41:41.44,EN,,0,0,0,,Any questions? Dialogue: 0,0:41:44.08,0:41:46.20,EN,,0,0,0,,AUDIENCE: It looks to me like backtracking would be Dialogue: 0,0:41:46.22,0:41:48.96,EN,,0,0,0,,searching for the first solution it can find, Dialogue: 0,0:41:49.31,0:41:51.48,EN,,0,0,0,,whereas this recursive search Dialogue: 0,0:41:51.48,0:41:53.26,EN,,0,0,0,,would be looking for all solutions. Dialogue: 0,0:41:53.32,0:41:53.60,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:41:54.03,0:41:55.26,EN,,0,0,0,,AUDIENCE: And it seems that Dialogue: 0,0:41:55.26,0:41:57.92,EN,,0,0,0,,if you have a large enough area to search, Dialogue: 0,0:41:57.92,0:42:00.92,EN,,0,0,0,,that the second is going to become impossible. Dialogue: 0,0:42:01.36,0:42:05.93,EN,,0,0,0,,PROFESSOR: OK, the answer to that question Dialogue: 0,0:42:07.13,0:42:08.44,EN,,0,0,0,,is the whole rest of this lecture. Dialogue: 0,0:42:08.57,0:42:10.54,EN,,0,0,0,,It's exactly the right question. Dialogue: 0,0:42:13.87,0:42:15.74,EN,,0,0,0,,And without trying to anticipate the lecture too much, Dialogue: 0,0:42:15.96,0:42:19.23,EN,,0,0,0,,you should start being suspicious at this point, Dialogue: 0,0:42:19.84,0:42:21.84,EN,,0,0,0,,and exactly those kinds of suspicions. Isn't it? Dialogue: 0,0:42:22.22,0:42:24.51,EN,,0,0,0,,It's wonderful, but isn't it so terribly inefficient? Dialogue: 0,0:42:24.83,0:42:26.03,EN,,0,0,0,,That's where we're going. Dialogue: 0,0:42:28.10,0:42:30.02,EN,,0,0,0,,So I won't answer now, but I'll answer later. Dialogue: 0,0:42:33.35,0:42:34.60,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:42:34.60,0:42:44.51,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:43:29.65,0:43:33.76,EN,,0,0,0,,Well, by now you should be starting to get suspicious. Dialogue: 0,0:43:35.60,0:43:39.26,EN,,0,0,0,,See, I've showed your this simple, elegant Dialogue: 0,0:43:40.51,0:43:42.28,EN,,0,0,0,,of putting programs together, Dialogue: 0,0:43:42.86,0:43:46.91,EN,,0,0,0,,very unlike these other traditional programs Dialogue: 0,0:43:46.92,0:43:48.19,EN,,0,0,0,,that sum the odd squares Dialogue: 0,0:43:48.72,0:43:51.32,EN,,0,0,0,,or compute the odd Fibonacci numbers. Dialogue: 0,0:43:53.74,0:43:55.48,EN,,0,0,0,,Very unlike these programs that mix up Dialogue: 0,0:43:55.85,0:43:58.84,EN,,0,0,0,,the enumerator and the filter and the accumulator. Dialogue: 0,0:44:00.44,0:44:01.82,EN,,0,0,0,,And by mixing it up, Dialogue: 0,0:44:02.20,0:44:04.59,EN,,0,0,0,,we don't have all of these wonderful Dialogue: 0,0:44:04.62,0:44:07.34,EN,,0,0,0,,conceptual advantages of these streams pieces, Dialogue: 0,0:44:07.82,0:44:09.53,EN,,0,0,0,,these wonderful mix and match components Dialogue: 0,0:44:09.55,0:44:11.77,EN,,0,0,0,,for putting together lots and lots of programs. Dialogue: 0,0:44:13.80,0:44:14.25,EN,,0,0,0,,On the other hand, Dialogue: 0,0:44:14.28,0:44:16.88,EN,,0,0,0,,most of the programs you've seen look like these ugly ones. Dialogue: 0,0:44:18.34,0:44:18.94,EN,,0,0,0,,Why's that? Dialogue: 0,0:44:19.20,0:44:20.59,EN,,0,0,0,,Can it possibly be Dialogue: 0,0:44:21.16,0:44:24.30,EN,,0,0,0,,that computer scientists are so obtuse Dialogue: 0,0:44:25.42,0:44:26.44,EN,,0,0,0,,that they don't notice Dialogue: 0,0:44:27.07,0:44:28.75,EN,,0,0,0,,that if you'd merely did this thing, Dialogue: 0,0:44:29.63,0:44:31.93,EN,,0,0,0,,then you can get this great programming elegance? Dialogue: 0,0:44:33.62,0:44:34.78,EN,,0,0,0,,There's got to be a catch. Dialogue: 0,0:44:36.76,0:44:39.05,EN,,0,0,0,,And it's actually pretty easy to see what the catch is. Dialogue: 0,0:44:39.51,0:44:41.74,EN,,0,0,0,,Let's think about the following problem. Dialogue: 0,0:44:42.03,0:44:45.47,EN,,0,0,0,,Suppose I tell you to find the second prime Dialogue: 0,0:44:46.16,0:44:48.16,EN,,0,0,0,,between 10,000 and 1 million, Dialogue: 0,0:44:49.12,0:44:50.56,EN,,0,0,0,,or if your computer's larger, Dialogue: 0,0:44:50.59,0:44:53.05,EN,,0,0,0,,say between 10,000 and 100 billion, or something. Dialogue: 0,0:44:54.32,0:44:55.45,EN,,0,0,0,,And you say, oh, that's easy. Dialogue: 0,0:44:55.47,0:44:56.65,EN,,0,0,0,,I can do that with a stream. Dialogue: 0,0:44:57.08,0:44:59.87,EN,,0,0,0,,All I do is I enumerate Dialogue: 0,0:45:00.57,0:45:02.89,EN,,0,0,0,,the interval from 10,000 to 1 million. Dialogue: 0,0:45:04.16,0:45:06.51,EN,,0,0,0,,So I get all those integers from 10,000 to 1 million. Dialogue: 0,0:45:06.80,0:45:08.64,EN,,0,0,0,,I filter them for prime-ness, Dialogue: 0,0:45:09.39,0:45:11.10,EN,,0,0,0,,so test all of them and see if they're prime. Dialogue: 0,0:45:11.76,0:45:12.83,EN,,0,0,0,,And I take the second element. Dialogue: 0,0:45:12.84,0:45:14.04,EN,,0,0,0,,Right? That's the head of the tail. Dialogue: 0,0:45:15.79,0:45:17.38,EN,,0,0,0,,OK? Well, that's clearly pretty ridiculous. Dialogue: 0,0:45:21.66,0:45:23.20,EN,,0,0,0,,We'd not even have room in the machine Dialogue: 0,0:45:23.58,0:45:25.24,EN,,0,0,0,,Right? To store the integers in the first place, Dialogue: 0,0:45:25.28,0:45:26.35,EN,,0,0,0,,much less to test them. Dialogue: 0,0:45:27.04,0:45:28.64,EN,,0,0,0,,And then I only want the second one. Dialogue: 0,0:45:29.81,0:45:34.94,EN,,0,0,0,,See, the power of this traditional programming style Dialogue: 0,0:45:36.43,0:45:37.68,EN,,0,0,0,,is exactly its weakness, Dialogue: 0,0:45:37.96,0:45:38.94,EN,,0,0,0,,that we're mixing up Dialogue: 0,0:45:39.61,0:45:43.50,EN,,0,0,0,,the enumerating and the testing and the accumulating. Dialogue: 0,0:45:44.88,0:45:46.46,EN,,0,0,0,,Right? We sort of don't do it all. Dialogue: 0,0:45:46.67,0:45:49.18,EN,,0,0,0,,So by the actual... so the very thing Dialogue: 0,0:45:49.45,0:45:51.74,EN,,0,0,0,,makes it conceptually ugly Dialogue: 0,0:45:52.20,0:45:53.80,EN,,0,0,0,,is the very thing that makes it efficient. Dialogue: 0,0:45:54.91,0:45:55.84,EN,,0,0,0,,Right? It's this mixing up. Dialogue: 0,0:45:57.80,0:45:59.34,EN,,0,0,0,,So it seems that all I've done this morning so far Dialogue: 0,0:45:59.34,0:46:00.42,EN,,0,0,0,,is just confuse you. Dialogue: 0,0:46:00.42,0:46:03.10,EN,,0,0,0,,I showed you this wonderful way that programming might work, Dialogue: 0,0:46:03.10,0:46:03.96,EN,,0,0,0,,except that it doesn't. Dialogue: 0,0:46:05.84,0:46:08.32,EN,,0,0,0,,Well, here's where the wonderful thing happens. Dialogue: 0,0:46:09.04,0:46:10.57,EN,,0,0,0,,It turns out in this game Dialogue: 0,0:46:11.21,0:46:13.84,EN,,0,0,0,,that we really can have our cake and eat it too. Dialogue: 0,0:46:14.87,0:46:16.11,EN,,0,0,0,,And what I mean by that Dialogue: 0,0:46:18.09,0:46:21.15,EN,,0,0,0,,is that we really can write stream programs Dialogue: 0,0:46:21.16,0:46:22.48,EN,,0,0,0,,exactly like the ones I wrote Dialogue: 0,0:46:23.55,0:46:27.74,EN,,0,0,0,,and arrange things so that when the machine actually runs, Dialogue: 0,0:46:28.33,0:46:31.52,EN,,0,0,0,,it's as efficient as running this traditional programming style Dialogue: 0,0:46:31.71,0:46:34.28,EN,,0,0,0,,that mixes up the generation and the test. Dialogue: 0,0:46:36.16,0:46:38.80,EN,,0,0,0,,Well, that sounds pretty magic. Dialogue: 0,0:46:40.77,0:46:41.82,EN,,0,0,0,,The key to this Dialogue: 0,0:46:42.00,0:46:43.69,EN,,0,0,0,,is that streams are not lists. Dialogue: 0,0:46:48.09,0:46:49.79,EN,,0,0,0,,We'll see this carefully in a second, but for now, Dialogue: 0,0:46:49.80,0:46:51.77,EN,,0,0,0,,let's take a look at that slide again. Dialogue: 0,0:46:52.24,0:46:53.80,EN,,0,0,0,,The image you should have here Dialogue: 0,0:46:53.84,0:46:55.58,EN,,0,0,0,,of this signal processing system Dialogue: 0,0:46:57.26,0:46:58.72,EN,,0,0,0,,is that what's going to happen Dialogue: 0,0:46:59.13,0:47:00.92,EN,,0,0,0,,is there's sort of this box Dialogue: 0,0:47:01.18,0:47:03.58,EN,,0,0,0,,that has the integers sitting in it. Dialogue: 0,0:47:05.36,0:47:06.40,EN,,0,0,0,,And there's this filter Dialogue: 0,0:47:07.45,0:47:09.37,EN,,0,0,0,,that's connected to it and it's tugging on them. Dialogue: 0,0:47:10.94,0:47:13.15,EN,,0,0,0,,And then there's someone who's tugging on this stuff Dialogue: 0,0:47:13.31,0:47:14.91,EN,,0,0,0,,saying what comes out of the filter. Dialogue: 0,0:47:16.79,0:47:18.70,EN,,0,0,0,,And the image you should have is that Dialogue: 0,0:47:18.99,0:47:20.72,EN,,0,0,0,,someone says, well, what's the first prime, Dialogue: 0,0:47:22.67,0:47:24.14,EN,,0,0,0,,and tugs on this filter. Dialogue: 0,0:47:24.59,0:47:26.12,EN,,0,0,0,,And the filter tugs on the integers. Dialogue: 0,0:47:28.02,0:47:29.15,EN,,0,0,0,,And you look only at that much, Dialogue: 0,0:47:29.16,0:47:30.93,EN,,0,0,0,,and then say, oh, I really wanted the second one. Dialogue: 0,0:47:30.93,0:47:31.95,EN,,0,0,0,,What's the second prime? Dialogue: 0,0:47:33.71,0:47:35.37,EN,,0,0,0,,And that no other computation Dialogue: 0,0:47:35.37,0:47:36.64,EN,,0,0,0,,no computation gets done Dialogue: 0,0:47:36.64,0:47:38.32,EN,,0,0,0,,except when you tug on these things. Dialogue: 0,0:47:40.50,0:47:41.41,EN,,0,0,0,,Let me try that again. Dialogue: 0,0:47:41.41,0:47:43.88,EN,,0,0,0,,This is a little device. Dialogue: 0,0:47:43.90,0:47:44.97,EN,,0,0,0,,This is a little stream machine Dialogue: 0,0:47:45.50,0:47:46.83,EN,,0,0,0,,invented by Eric Grimson Dialogue: 0,0:47:47.60,0:47:49.24,EN,,0,0,0,,who's been teaching this course at MIT. Dialogue: 0,0:47:49.83,0:47:52.51,EN,,0,0,0,,And the image is ... here's a stream of stuff, Dialogue: 0,0:47:52.54,0:47:53.82,EN,,0,0,0,,like a whole bunch of the integers. Dialogue: 0,0:47:54.78,0:47:56.33,EN,,0,0,0,,And here's some processing elements. Dialogue: 0,0:47:58.70,0:48:02.60,EN,,0,0,0,,And if, say, it's filter of filter of map, or something. Dialogue: 0,0:48:03.98,0:48:09.18,EN,,0,0,0,,And if I really tried to implement that with streams as lists, Dialogue: 0,0:48:09.24,0:48:11.26,EN,,0,0,0,,what I'd say is, well, I've got this list of things, Dialogue: 0,0:48:11.47,0:48:12.67,EN,,0,0,0,,and now I do the first filter. Dialogue: 0,0:48:12.67,0:48:14.07,EN,,0,0,0,,So I sort of do all this processing. Dialogue: 0,0:48:14.88,0:48:15.77,EN,,0,0,0,,And I take this Dialogue: 0,0:48:16.32,0:48:19.21,EN,,0,0,0,,and I process and I process and I process and I process. Dialogue: 0,0:48:19.61,0:48:21.05,EN,,0,0,0,,And now I'm got this new stream. Dialogue: 0,0:48:21.63,0:48:24.07,EN,,0,0,0,,Right? Now I take that result in my hand someplace. Dialogue: 0,0:48:24.07,0:48:25.26,EN,,0,0,0,,And I put that through the second one. Dialogue: 0,0:48:25.56,0:48:26.94,EN,,0,0,0,,And I process the whole thing. Dialogue: 0,0:48:28.27,0:48:29.51,EN,,0,0,0,,And there's this new stream. Dialogue: 0,0:48:32.13,0:48:33.36,EN,,0,0,0,,And then I take the result Dialogue: 0,0:48:34.28,0:48:36.36,EN,,0,0,0,,and I put it all the way through this one the same way. Dialogue: 0,0:48:36.36,0:48:40.99,EN,,0,0,0,,That's what would happen to these stream programs Dialogue: 0,0:48:41.69,0:48:42.97,EN,,0,0,0,,if streams were just lists. Dialogue: 0,0:48:43.86,0:48:45.64,EN,,0,0,0,,But in fact, streams aren't lists, they're streams. Dialogue: 0,0:48:45.82,0:48:48.11,EN,,0,0,0,,And the image you should have is something a little bit more like this. Dialogue: 0,0:48:50.23,0:48:52.52,EN,,0,0,0,,I've got these gadgets connected up Dialogue: 0,0:48:55.26,0:48:56.76,EN,,0,0,0,,by this data that's flowing out of them. Dialogue: 0,0:49:00.33,0:49:02.30,EN,,0,0,0,,And here's my original source of the streams. Dialogue: 0,0:49:02.32,0:49:02.92,EN,,0,0,0,,It might be Dialogue: 0,0:49:04.19,0:49:05.72,EN,,0,0,0,,starting to generate the integers. Dialogue: 0,0:49:05.98,0:49:07.39,EN,,0,0,0,,And now, what happens if I want a result? Dialogue: 0,0:49:07.58,0:49:08.91,EN,,0,0,0,,I tug on the end here. Dialogue: 0,0:49:10.20,0:49:11.07,EN,,0,0,0,,And this element says, Dialogue: 0,0:49:11.08,0:49:12.20,EN,,0,0,0,,gee, I need some more data. Dialogue: 0,0:49:13.09,0:49:15.52,EN,,0,0,0,,So it's sort of, this one comes here and tugs on that one. Dialogue: 0,0:49:15.83,0:49:17.39,EN,,0,0,0,,And it says, gee, I need some more data. Dialogue: 0,0:49:17.89,0:49:19.56,EN,,0,0,0,,And this one tugs on this thing, Dialogue: 0,0:49:19.56,0:49:20.28,EN,,0,0,0,,which might be a filter, Dialogue: 0,0:49:20.28,0:49:21.40,EN,,0,0,0,,and says, gee, I need some more data. Dialogue: 0,0:49:21.64,0:49:23.15,EN,,0,0,0,,And only as much of this Dialogue: 0,0:49:23.53,0:49:25.56,EN,,0,0,0,,thing at the end here gets generated as I tugged. Dialogue: 0,0:49:25.78,0:49:28.30,EN,,0,0,0,,And only as much of this stuff goes through the processing units Dialogue: 0,0:49:28.56,0:49:29.98,EN,,0,0,0,,as I'm pulling on the end I need. Dialogue: 0,0:49:30.76,0:49:32.09,EN,,0,0,0,,That's the image you should have Dialogue: 0,0:49:32.80,0:49:34.38,EN,,0,0,0,,of the difference between implementing Dialogue: 0,0:49:34.56,0:49:35.92,EN,,0,0,0,,what we're actually going to do Dialogue: 0,0:49:36.16,0:49:37.50,EN,,0,0,0,,and if streams were lists. Dialogue: 0,0:49:40.78,0:49:42.14,EN,,0,0,0,,Well, how do we make this thing? Dialogue: 0,0:49:42.35,0:49:43.32,EN,,0,0,0,,I hope you have the image. Dialogue: 0,0:49:43.40,0:49:44.52,EN,,0,0,0,,The trick is how to make it. Dialogue: 0,0:49:47.93,0:49:50.32,EN,,0,0,0,,We want to arrange for a stream Dialogue: 0,0:49:50.41,0:49:51.58,EN,,0,0,0,,to be a data structure Dialogue: 0,0:49:52.00,0:49:54.22,EN,,0,0,0,,that sorts of computes itself incrementally, Dialogue: 0,0:49:54.22,0:49:56.22,EN,,0,0,0,,sort of on-demand data structure. Dialogue: 0,0:49:58.96,0:50:00.51,EN,,0,0,0,,Right? And the basic idea Dialogue: 0,0:50:00.97,0:50:02.70,EN,,0,0,0,,is again, one of the very basic ideas Dialogue: 0,0:50:02.72,0:50:04.12,EN,,0,0,0,,that we're seeing throughout the whole course. Dialogue: 0,0:50:04.49,0:50:05.00,EN,,0,0,0,,And that is Dialogue: 0,0:50:05.52,0:50:06.97,EN,,0,0,0,,that there's not a firm distinction Dialogue: 0,0:50:06.99,0:50:08.44,EN,,0,0,0,,between programs and data. Dialogue: 0,0:50:09.24,0:50:10.54,EN,,0,0,0,,So what a stream is going to be Dialogue: 0,0:50:10.59,0:50:13.40,EN,,0,0,0,,is simultaneously this data structure that you think of, Dialogue: 0,0:50:13.45,0:50:15.92,EN,,0,0,0,,like the stream of the leaves of this tree. Dialogue: 0,0:50:16.86,0:50:17.85,EN,,0,0,0,,But at the same time, Dialogue: 0,0:50:17.85,0:50:19.32,EN,,0,0,0,,it's going to be a very clever procedure Dialogue: 0,0:50:20.24,0:50:22.22,EN,,0,0,0,,that has the method of computing in it. Dialogue: 0,0:50:23.74,0:50:25.93,EN,,0,0,0,,Well, let me try this. Dialogue: 0,0:50:25.93,0:50:26.62,EN,,0,0,0,,It's going to turn out Dialogue: 0,0:50:26.80,0:50:28.33,EN,,0,0,0,,that we don't need any more mechanism. Dialogue: 0,0:50:28.46,0:50:29.87,EN,,0,0,0,,We already have everything we need Dialogue: 0,0:50:30.14,0:50:30.99,EN,,0,0,0,,simply from the fact Dialogue: 0,0:50:31.02,0:50:33.93,EN,,0,0,0,,that we know how to handle procedures as first-class objects. Dialogue: 0,0:50:35.46,0:50:36.88,EN,,0,0,0,,Well, let's go back to the key. Dialogue: 0,0:50:36.88,0:50:39.03,EN,,0,0,0,,The key is, remember, we had these operations. Dialogue: 0,0:50:39.03,0:50:47.52,EN,,0,0,0,,CONS-stream and head and tail. Dialogue: 0,0:50:48.08,0:50:49.36,EN,,0,0,0,,When I started, I said Dialogue: 0,0:50:49.92,0:50:51.36,EN,,0,0,0,,you can think about this as CONS Dialogue: 0,0:50:51.40,0:50:52.62,EN,,0,0,0,,and think about this as CAR Dialogue: 0,0:50:52.62,0:50:53.52,EN,,0,0,0,,and think about that as CDR Dialogue: 0,0:50:53.55,0:50:54.16,EN,,0,0,0,,but it's not. Dialogue: 0,0:50:55.08,0:50:56.32,EN,,0,0,0,,Now, let's look at what they really are. Dialogue: 0,0:50:57.71,0:51:05.84,EN,,0,0,0,,Well, CONS-stream of x and y Dialogue: 0,0:51:07.48,0:51:17.79,EN,,0,0,0,,is going to be an abbreviation for the following thing. Dialogue: 0,0:51:19.54,0:51:28.32,EN,,0,0,0,,CONS form a pair, ordinary CONS, of x to a thing called delay of y. Dialogue: 0,0:51:31.68,0:51:33.53,EN,,0,0,0,,And before I explain that, let me go and write the rest. Dialogue: 0,0:51:34.52,0:51:35.53,EN,,0,0,0,,The head of a stream Dialogue: 0,0:51:38.09,0:51:39.79,EN,,0,0,0,,is going to be just the CAR. Dialogue: 0,0:51:42.38,0:51:44.25,EN,,0,0,0,,And the tail of a stream Dialogue: 0,0:51:46.68,0:51:54.60,EN,,0,0,0,,is going to be a thing called force the CDR of the stream. Dialogue: 0,0:51:56.12,0:51:57.04,EN,,0,0,0,,Now let me explain this. Dialogue: 0,0:51:58.06,0:51:59.88,EN,,0,0,0,,Delay is going to be a special magic thing. Dialogue: 0,0:52:01.42,0:52:02.33,EN,,0,0,0,,What delay does Dialogue: 0,0:52:03.85,0:52:05.31,EN,,0,0,0,,is take an expression Dialogue: 0,0:52:05.50,0:52:06.86,EN,,0,0,0,,and produce a promise Dialogue: 0,0:52:07.12,0:52:09.15,EN,,0,0,0,,to compute that expression when you ask for it. Dialogue: 0,0:52:10.60,0:52:11.98,EN,,0,0,0,,It doesn't do any computation here. Dialogue: 0,0:52:11.98,0:52:14.32,EN,,0,0,0,,Just sort of... It just gives you a rain check. Dialogue: 0,0:52:14.82,0:52:16.20,EN,,0,0,0,,It produces a promise. Dialogue: 0,0:52:17.11,0:52:18.20,EN,,0,0,0,,And CONS-stream says Dialogue: 0,0:52:18.81,0:52:21.96,EN,,0,0,0,,I'm going to put together in a pair x Dialogue: 0,0:52:23.31,0:52:25.36,EN,,0,0,0,,and a promise to compute y. Dialogue: 0,0:52:28.23,0:52:28.99,EN,,0,0,0,,Now, if I want the head, Dialogue: 0,0:52:28.99,0:52:30.75,EN,,0,0,0,,that's just the CAR that I put in the pair. Dialogue: 0,0:52:31.84,0:52:33.71,EN,,0,0,0,,And the key is that the tail is going to be-- Dialogue: 0,0:52:34.62,0:52:36.65,EN,,0,0,0,,force calls in that promise. Dialogue: 0,0:52:38.22,0:52:39.88,EN,,0,0,0,,Force -- Tail says, well, Dialogue: 0,0:52:40.03,0:52:41.02,EN,,0,0,0,,well, take that promise Dialogue: 0,0:52:41.85,0:52:44.52,EN,,0,0,0,,and now call in that promise. Dialogue: 0,0:52:44.56,0:52:46.03,EN,,0,0,0,,And then we compute that thing. Dialogue: 0,0:52:47.69,0:52:48.72,EN,,0,0,0,,That's how this is going to work. Dialogue: 0,0:52:48.74,0:52:51.55,EN,,0,0,0,,That's what CONS-stream, head, and tail really are. Dialogue: 0,0:52:54.60,0:52:55.57,EN,,0,0,0,,Now, let's see how this works. Dialogue: 0,0:52:55.57,0:52:57.50,EN,,0,0,0,,And we'll go through this fairly carefully. Let's -- Dialogue: 0,0:52:58.76,0:53:00.62,EN,,0,0,0,,We're going to see how this Dialogue: 0,0:53:01.32,0:53:03.66,EN,,0,0,0,,example of computing the second prime Dialogue: 0,0:53:05.50,0:53:07.16,EN,,0,0,0,,right? between 10,000 and a million. Dialogue: 0,0:53:08.65,0:53:12.03,EN,,0,0,0,,OK, so we start off and we have this expression. Dialogue: 0,0:53:15.36,0:53:16.62,EN,,0,0,0,,Right? The second prime-- Dialogue: 0,0:53:16.64,0:53:21.90,EN,,0,0,0,,the head of the tail of the result of filtering for primality Dialogue: 0,0:53:22.83,0:53:25.31,EN,,0,0,0,,the integers between 10,000 and 1 million. Dialogue: 0,0:53:26.71,0:53:27.61,EN,,0,0,0,,Now, what is that? Dialogue: 0,0:53:28.40,0:53:29.20,EN,,0,0,0,,What that is, Dialogue: 0,0:53:31.63,0:53:34.17,EN,,0,0,0,,that interval between 10,000 and 1 million, Dialogue: 0,0:53:35.72,0:53:37.32,EN,,0,0,0,,well, if you trace through enumerate interval, Dialogue: 0,0:53:37.34,0:53:38.78,EN,,0,0,0,,there builds a CONS-stream. Dialogue: 0,0:53:39.92,0:53:41.39,EN,,0,0,0,,And the CONS-stream is Dialogue: 0,0:53:41.96,0:53:43.61,EN,,0,0,0,,the CONS of 10,000 Dialogue: 0,0:53:44.51,0:53:48.92,EN,,0,0,0,,to a promise to compute the integers between 10,001 and 1 million. Dialogue: 0,0:53:54.00,0:53:55.75,EN,,0,0,0,,Okay? So that's what this expression is. Dialogue: 0,0:53:55.75,0:53:57.32,EN,,0,0,0,,Here I'm using the substitution model. Dialogue: 0,0:53:57.64,0:53:59.32,EN,,0,0,0,,And we can use the substitution model Dialogue: 0,0:53:59.34,0:54:01.01,EN,,0,0,0,,because we don't have side effects and state. Dialogue: 0,0:54:03.56,0:54:06.38,EN,,0,0,0,,Okay? So I have CONS of 10,000 Dialogue: 0,0:54:06.41,0:54:08.27,EN,,0,0,0,,to a promise to compute the rest of the integers. Dialogue: 0,0:54:08.32,0:54:10.49,EN,,0,0,0,,So only one integer, so far, got enumerated. Dialogue: 0,0:54:14.38,0:54:16.96,EN,,0,0,0,,Well, I'm going to filter that thing for primality. Dialogue: 0,0:54:19.44,0:54:21.90,EN,,0,0,0,,Again, you go back and look at the filter code. Dialogue: 0,0:54:22.36,0:54:24.46,EN,,0,0,0,,What the filter will first do is test the head. Dialogue: 0,0:54:25.46,0:54:28.25,EN,,0,0,0,,So in this case, the filter will test 10,000 Dialogue: 0,0:54:30.30,0:54:32.97,EN,,0,0,0,,oh, 10,000's not prime. Dialogue: 0,0:54:33.50,0:54:35.85,EN,,0,0,0,,Therefore, what I have to do recursively Dialogue: 0,0:54:36.25,0:54:37.39,EN,,0,0,0,,is filter the tail. Dialogue: 0,0:54:39.22,0:54:40.14,EN,,0,0,0,,And what's the tail of it, Dialogue: 0,0:54:40.16,0:54:43.76,EN,,0,0,0,,well, that's the tail of this pair with a promise in it. Dialogue: 0,0:54:46.34,0:54:48.06,EN,,0,0,0,,Tail now comes in and says, Dialogue: 0,0:54:48.28,0:54:49.50,EN,,0,0,0,,well, I'm going to force that. Dialogue: 0,0:54:49.68,0:54:50.94,EN,,0,0,0,,I'm going to force that promise, Dialogue: 0,0:54:52.30,0:54:54.36,EN,,0,0,0,,which means now I'm going to compute Dialogue: 0,0:54:55.58,0:54:57.96,EN,,0,0,0,,the integers between 10,001 and 1 million. Dialogue: 0,0:55:00.80,0:55:02.97,EN,,0,0,0,,OK? So this filter now is looking at that. Dialogue: 0,0:55:07.81,0:55:08.92,EN,,0,0,0,,That enumerate itself, Dialogue: 0,0:55:08.94,0:55:11.23,EN,,0,0,0,,now we're back in the original enumerate situation. Dialogue: 0,0:55:11.96,0:55:13.00,EN,,0,0,0,,The enumerate is Dialogue: 0,0:55:14.12,0:55:16.44,EN,,0,0,0,,CONS of the first thing, 10,001, Dialogue: 0,0:55:16.60,0:55:18.20,EN,,0,0,0,,onto a promise to compute the rest. Dialogue: 0,0:55:19.74,0:55:22.75,EN,,0,0,0,,So now the primality filter is going to go look at 10,001. Dialogue: 0,0:55:23.23,0:55:25.12,EN,,0,0,0,,It's going to decide if it likes that or not. Dialogue: 0,0:55:25.12,0:55:27.08,EN,,0,0,0,,It turns out 10,001 isn't prime. Dialogue: 0,0:55:27.55,0:55:29.61,EN,,0,0,0,,So it'll force it again and again and again. Dialogue: 0,0:55:32.92,0:55:35.80,EN,,0,0,0,,And finally, I think the first prime it hits is 10,009. Dialogue: 0,0:55:37.10,0:55:38.33,EN,,0,0,0,,And at that point, it'll stop. Dialogue: 0,0:55:40.84,0:55:41.93,EN,,0,0,0,,And that will be the first prime, Dialogue: 0,0:55:41.96,0:55:43.48,EN,,0,0,0,,and then eventually, it'll need the second prime. Dialogue: 0,0:55:45.24,0:55:46.84,EN,,0,0,0,,So at that point, it will go again. Dialogue: 0,0:55:47.03,0:55:48.25,EN,,0,0,0,,So you see what happens is that Dialogue: 0,0:55:48.52,0:55:50.49,EN,,0,0,0,,no more gets generated Dialogue: 0,0:55:51.85,0:55:52.91,EN,,0,0,0,,than you actually need. Dialogue: 0,0:55:56.48,0:55:59.92,EN,,0,0,0,,That enumerator is not going to generate any more integers Dialogue: 0,0:56:00.12,0:56:01.45,EN,,0,0,0,,than the filter asks it for Dialogue: 0,0:56:01.47,0:56:03.45,EN,,0,0,0,,as it's pulling in things to check for primality. Dialogue: 0,0:56:04.70,0:56:06.51,EN,,0,0,0,,And the filter is not going to generate Dialogue: 0,0:56:06.54,0:56:08.04,EN,,0,0,0,,any more stuff than you ask it for, Dialogue: 0,0:56:08.06,0:56:09.10,EN,,0,0,0,,which is the head of the tail. Dialogue: 0,0:56:11.61,0:56:13.26,EN,,0,0,0,,You see, what's happened is Dialogue: 0,0:56:14.70,0:56:18.24,EN,,0,0,0,,we've put that mixing of generation and test Dialogue: 0,0:56:18.67,0:56:20.65,EN,,0,0,0,,into what actually happens in the computer, Dialogue: 0,0:56:21.52,0:56:22.67,EN,,0,0,0,,even though Dialogue: 0,0:56:23.18,0:56:25.63,EN,,0,0,0,,that's not apparently what's happening from looking at our programs. Dialogue: 0,0:56:28.12,0:56:29.40,EN,,0,0,0,,OK, well, that seemed easy. Dialogue: 0,0:56:30.23,0:56:32.67,EN,,0,0,0,,All of this mechanism got put into this magic delay. Dialogue: 0,0:56:33.68,0:56:35.66,EN,,0,0,0,,So you're saying, gee, that must be where the magic is. Dialogue: 0,0:56:36.90,0:56:38.57,EN,,0,0,0,,But see there's no magic there either. Dialogue: 0,0:56:39.07,0:56:39.98,EN,,0,0,0,,You know what delay is. Dialogue: 0,0:56:40.61,0:56:45.07,EN,,0,0,0,,Delay on some expression Dialogue: 0,0:56:48.25,0:56:50.04,EN,,0,0,0,,is just an abbreviation for-- Dialogue: 0,0:56:53.36,0:56:55.63,EN,,0,0,0,,well, what's a promise to compute an expression? Dialogue: 0,0:56:56.49,0:57:01.12,EN,,0,0,0,,Lambda of nil, procedure of no arguments, which is that expression. Dialogue: 0,0:57:02.83,0:57:03.84,EN,,0,0,0,,Right? That's what a procedure is. Dialogue: 0,0:57:03.98,0:57:05.53,EN,,0,0,0,,It says I'm going to compute an expression. Dialogue: 0,0:57:06.05,0:57:06.73,EN,,0,0,0,,What's force? Dialogue: 0,0:57:07.34,0:57:10.80,EN,,0,0,0,,Right, how do I take up a promise? Dialogue: 0,0:57:10.80,0:57:14.11,EN,,0,0,0,,Well, force of some procedure, a promise, Dialogue: 0,0:57:14.78,0:57:15.40,EN,,0,0,0,,is just run it. Dialogue: 0,0:57:19.23,0:57:19.56,EN,,0,0,0,,Done. Dialogue: 0,0:57:20.24,0:57:21.37,EN,,0,0,0,,So there's no magic there at all. Dialogue: 0,0:57:23.52,0:57:24.24,EN,,0,0,0,,Well, what have we done? Dialogue: 0,0:57:26.44,0:57:27.50,EN,,0,0,0,,We said the old style, Dialogue: 0,0:57:28.14,0:57:30.81,EN,,0,0,0,,traditional style of programming is more efficient. Dialogue: 0,0:57:30.96,0:57:33.92,EN,,0,0,0,,And the stream thing is more perspicacious. Dialogue: 0,0:57:35.50,0:57:38.72,EN,,0,0,0,,And we managed to make the stream procedures Dialogue: 0,0:57:38.81,0:57:43.23,EN,,0,0,0,,run like the other procedures by using delay. Dialogue: 0,0:57:43.35,0:57:46.43,EN,,0,0,0,,And the thing that delay did for us was to de-couple Dialogue: 0,0:57:46.68,0:57:50.40,EN,,0,0,0,,the apparent order of events in our programs Dialogue: 0,0:57:51.21,0:57:53.84,EN,,0,0,0,,from the actual order of events that happened in the machine. Dialogue: 0,0:57:54.44,0:57:55.93,EN,,0,0,0,,That's really what delay is doing. Dialogue: 0,0:57:57.15,0:57:58.29,EN,,0,0,0,,That's exactly the whole point. Dialogue: 0,0:57:58.29,0:58:01.92,EN,,0,0,0,,We've given up, right, we've given up the idea Dialogue: 0,0:58:02.30,0:58:04.17,EN,,0,0,0,,that our procedures, as they run, Dialogue: 0,0:58:04.67,0:58:05.95,EN,,0,0,0,,or as we look at them, Dialogue: 0,0:58:06.33,0:58:08.25,EN,,0,0,0,,mirror some clear notion of time. Dialogue: 0,0:58:09.45,0:58:10.57,EN,,0,0,0,,And by giving that up, Dialogue: 0,0:58:11.21,0:58:13.32,EN,,0,0,0,,we give delay the freedom to arrange the order Dialogue: 0,0:58:13.34,0:58:15.20,EN,,0,0,0,,of events in the computation the way it likes. Dialogue: 0,0:58:16.69,0:58:17.61,EN,,0,0,0,,That's the whole idea. Dialogue: 0,0:58:17.61,0:58:19.45,EN,,0,0,0,,We de-couple the apparent order Dialogue: 0,0:58:19.95,0:58:21.13,EN,,0,0,0,,of events in our programs Dialogue: 0,0:58:21.16,0:58:22.89,EN,,0,0,0,,from the actual order of events in the computer. Dialogue: 0,0:58:24.09,0:58:25.77,EN,,0,0,0,,OK, well there's one more detail. Dialogue: 0,0:58:25.77,0:58:27.21,EN,,0,0,0,,It's just a technical detail, Dialogue: 0,0:58:27.21,0:58:28.43,EN,,0,0,0,,but it's actually an important one. Dialogue: 0,0:58:29.73,0:58:32.01,EN,,0,0,0,,As you run through these recursive programs unwinding, Dialogue: 0,0:58:32.16,0:58:33.58,EN,,0,0,0,,you'll see a lot of things that look like Dialogue: 0,0:58:33.64,0:58:37.87,EN,,0,0,0,,tail of the tail of the tail. Dialogue: 0,0:58:39.20,0:58:41.02,EN,,0,0,0,,Right. That's the kind of thing that would happen Dialogue: 0,0:58:41.02,0:58:42.88,EN,,0,0,0,,as I go CONSing down a stream all the way. Dialogue: 0,0:58:43.86,0:58:46.09,EN,,0,0,0,,And if each time I'm doing that, Dialogue: 0,0:58:46.14,0:58:47.58,EN,,0,0,0,,each time to compute a tail, Dialogue: 0,0:58:48.22,0:58:50.88,EN,,0,0,0,,I evaluate a procedure Dialogue: 0,0:58:51.07,0:58:53.07,EN,,0,0,0,,which then has to go re-compute its tail, Dialogue: 0,0:58:53.10,0:58:55.40,EN,,0,0,0,,and re-compute its tail and recompute its tail each time, Dialogue: 0,0:58:55.50,0:58:56.88,EN,,0,0,0,,you can see that's very inefficient Dialogue: 0,0:58:57.77,0:59:00.56,EN,,0,0,0,,compared to just having a list where the elements are all there, Dialogue: 0,0:59:01.16,0:59:04.00,EN,,0,0,0,,and I don't have to re-compute each tail every time I get the next tail. Dialogue: 0,0:59:05.29,0:59:08.28,EN,,0,0,0,,So there's one little hack Dialogue: 0,0:59:09.66,0:59:13.13,EN,,0,0,0,,to slightly change the abbreviation, change what delay is Dialogue: 0,0:59:14.96,0:59:18.20,EN,,0,0,0,,and make it a thing which is-- I'll write it this way. Dialogue: 0,0:59:19.68,0:59:22.04,EN,,0,0,0,,Delay -- The actual implementation, Dialogue: 0,0:59:24.52,0:59:27.93,EN,,0,0,0,,delay is an abbreviation for this thing, Dialogue: 0,0:59:28.11,0:59:30.86,EN,,0,0,0,,memo-proc of a procedure. Dialogue: 0,0:59:31.00,0:59:34.06,EN,,0,0,0,,Memo-proc is a special thing that transforms a procedure. Dialogue: 0,0:59:35.15,0:59:37.80,EN,,0,0,0,,What it does is it takes a procedure of no arguments Dialogue: 0,0:59:39.02,0:59:41.05,EN,,0,0,0,,and it transforms it into a procedure Dialogue: 0,0:59:41.36,0:59:43.55,EN,,0,0,0,,that'll only have to do its computation once. Dialogue: 0,0:59:45.10,0:59:47.45,EN,,0,0,0,,And what I mean by that is, you give it a procedure. Dialogue: 0,0:59:48.70,0:59:50.86,EN,,0,0,0,,The result of memo-proc will be a new procedure, Dialogue: 0,0:59:51.39,0:59:53.00,EN,,0,0,0,,which the first time you call it, Dialogue: 0,0:59:53.71,0:59:55.07,EN,,0,0,0,,will run the original procedure, Dialogue: 0,0:59:55.31,0:59:56.91,EN,,0,0,0,,remember what result it got, Dialogue: 0,0:59:58.56,1:00:00.68,EN,,0,0,0,,and then from ever on after, when you call it, Dialogue: 0,1:00:00.68,1:00:02.17,EN,,0,0,0,,it just won't have to do the computation. Dialogue: 0,1:00:02.19,1:00:04.43,EN,,0,0,0,,It will have cached that result someplace. Dialogue: 0,1:00:05.20,1:00:06.92,EN,,0,0,0,,And here's an implementation of memo-proc. Dialogue: 0,1:00:11.21,1:00:12.71,EN,,0,0,0,,Once you have the idea, it's easy to implement. Dialogue: 0,1:00:12.71,1:00:16.76,EN,,0,0,0,,Memo-proc is this little thing that has two little flags in there. Dialogue: 0,1:00:17.39,1:00:19.20,EN,,0,0,0,,It says, have I already been run? Dialogue: 0,1:00:20.32,1:00:22.48,EN,,0,0,0,,And initially it says, no, I haven't already been run. Dialogue: 0,1:00:23.62,1:00:27.04,EN,,0,0,0,,And what was the result I got the last time I was run? Dialogue: 0,1:00:29.07,1:00:31.07,EN,,0,0,0,,So memo-proc takes a procedure called proc, Dialogue: 0,1:00:31.56,1:00:34.01,EN,,0,0,0,,and it returns a new procedure of no arguments. Dialogue: 0,1:00:34.36,1:00:36.38,EN,,0,0,0,,Proc is supposed to be a procedure of no arguments. Dialogue: 0,1:00:38.61,1:00:41.37,EN,,0,0,0,,And it says, oh, if I'm not already run, Dialogue: 0,1:00:42.59,1:00:44.06,EN,,0,0,0,,then I'm going to do a sequence of things. Dialogue: 0,1:00:44.43,1:00:46.56,EN,,0,0,0,,I'm going to compute proc, Dialogue: 0,1:00:47.50,1:00:48.45,EN,,0,0,0,,I'm going to save that. Dialogue: 0,1:00:48.45,1:00:50.48,EN,,0,0,0,,I'm going to stash that in the variable result. Dialogue: 0,1:00:51.14,1:00:53.90,EN,,0,0,0,,I'm going to make a note to myself that I've already been run, Dialogue: 0,1:00:54.28,1:00:55.47,EN,,0,0,0,,and then I'll return the result. Dialogue: 0,1:00:56.61,1:00:59.01,EN,,0,0,0,,So that's if you compute it if it's not already run. Dialogue: 0,1:00:59.01,1:01:01.88,EN,,0,0,0,,If you call it and it's already been run, it just returns the result. Dialogue: 0,1:01:03.42,1:01:07.12,EN,,0,0,0,,So that's a little clever hack called memoization. Dialogue: 0,1:01:08.40,1:01:09.13,EN,,0,0,0,,And in this case, Dialogue: 0,1:01:10.35,1:01:14.14,EN,,0,0,0,,it short circuits having to re-compute the tail of the tail of the tail of the tail of the tail. Dialogue: 0,1:01:15.27,1:01:17.81,EN,,0,0,0,,So there isn't even that kind of inefficiency. Dialogue: 0,1:01:17.81,1:01:18.72,EN,,0,0,0,,And in fact, the streams Dialogue: 0,1:01:19.20,1:01:22.75,EN,,0,0,0,,will run with pretty much the same efficiency as the other programs precisely. Dialogue: 0,1:01:24.01,1:01:26.20,EN,,0,0,0,,And remember, again, the whole idea of this Dialogue: 0,1:01:27.48,1:01:28.60,EN,,0,0,0,,is that we've used Dialogue: 0,1:01:29.26,1:01:32.40,EN,,0,0,0,,the fact that there's no really good dividing line Dialogue: 0,1:01:32.41,1:01:33.61,EN,,0,0,0,,between procedures and data. Dialogue: 0,1:01:33.61,1:01:35.61,EN,,0,0,0,,We've written data structures that, in fact, Dialogue: 0,1:01:36.00,1:01:37.31,EN,,0,0,0,,are sort of like procedures. Dialogue: 0,1:01:38.76,1:01:40.73,EN,,0,0,0,,And what that's allowed us to do Dialogue: 0,1:01:41.58,1:01:46.54,EN,,0,0,0,,is take an example of a common control structure, Dialogue: 0,1:01:46.68,1:01:48.91,EN,,0,0,0,,in this place iteration. Dialogue: 0,1:01:49.62,1:01:51.05,EN,,0,0,0,,And we've built a data structure Dialogue: 0,1:01:51.32,1:01:52.84,EN,,0,0,0,,which, since itself is a procedure, Dialogue: 0,1:01:52.86,1:01:55.12,EN,,0,0,0,,kind of has this iteration control structure in it. Dialogue: 0,1:01:55.79,1:01:57.13,EN,,0,0,0,,And that's really what streams are. Dialogue: 0,1:01:58.91,1:01:59.76,EN,,0,0,0,,OK, questions? Dialogue: 0,1:02:03.95,1:02:05.84,EN,,0,0,0,,AUDIENCE: Your description of tail-tail-tail, Dialogue: 0,1:02:05.85,1:02:07.16,EN,,0,0,0,,if I understand it correctly, Dialogue: 0,1:02:07.28,1:02:10.76,EN,,0,0,0,,force is actually execution of a procedure, Dialogue: 0,1:02:10.78,1:02:12.83,EN,,0,0,0,,if it's done without this memo-proc thing. Dialogue: 0,1:02:12.89,1:02:13.15,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,1:02:13.44,1:02:16.38,EN,,0,0,0,,AUDIENCE: And you implied that memo-proc gets around that problem. Dialogue: 0,1:02:16.38,1:02:18.73,EN,,0,0,0,,Doesn't it only get around it if Dialogue: 0,1:02:19.34,1:02:22.19,EN,,0,0,0,,tail-tail-tail is always executing exactly the same-- Dialogue: 0,1:02:22.41,1:02:23.91,EN,,0,0,0,,PROFESSOR: Oh, that's-- sure. Dialogue: 0,1:02:23.91,1:02:25.84,EN,,0,0,0,,AUDIENCE: I guess I missed that point. Dialogue: 0,1:02:26.05,1:02:27.21,EN,,0,0,0,,PROFESSOR: Oh, sure. I mean the point is-- yeah. Dialogue: 0,1:02:31.12,1:02:33.64,EN,,0,0,0,,Yeah, I mean I have to do a computation to get the answer. Dialogue: 0,1:02:34.09,1:02:36.76,EN,,0,0,0,,But the point is, once I've found the tail of the stream, Dialogue: 0,1:02:37.58,1:02:38.70,EN,,0,0,0,,to get the tail of the tail, Dialogue: 0,1:02:38.70,1:02:40.51,EN,,0,0,0,,I shouldn't have had to re-compute the first tail. Dialogue: 0,1:02:42.98,1:02:44.32,EN,,0,0,0,,See, and if I didn't use memo-proc, Dialogue: 0,1:02:44.35,1:02:46.09,EN,,0,0,0,,that re-computation would have been done. Dialogue: 0,1:02:46.46,1:02:47.13,EN,,0,0,0,,AUDIENCE: I understand now. Dialogue: 0,1:02:50.83,1:02:52.56,EN,,0,0,0,,AUDIENCE: In one of your examples, you mentioned that Dialogue: 0,1:02:52.60,1:02:54.22,EN,,0,0,0,,we were able to use the substitution model Dialogue: 0,1:02:54.22,1:02:56.11,EN,,0,0,0,,because there are no side effects. Dialogue: 0,1:02:56.83,1:03:00.73,EN,,0,0,0,,What if we had a signal processing unit-- Dialogue: 0,1:03:00.78,1:03:02.03,EN,,0,0,0,,if we had a side effect, Dialogue: 0,1:03:02.04,1:03:03.04,EN,,0,0,0,,if we had a state? Dialogue: 0,1:03:03.62,1:03:06.84,EN,,0,0,0,,Could we still practically build the stream model? Dialogue: 0,1:03:08.46,1:03:10.59,EN,,0,0,0,,PROFESSOR: Hum... Maybe, That's a hard question. Dialogue: 0,1:03:11.20,1:03:13.42,EN,,0,0,0,,I'm going to talk a little bit later about the places where Dialogue: 0,1:03:14.36,1:03:18.24,EN,,0,0,0,,where substitution and side effects don't really mix very well. Dialogue: 0,1:03:18.96,1:03:20.48,EN,,0,0,0,,But in general, I think the answer is Dialogue: 0,1:03:20.49,1:03:21.63,EN,,0,0,0,,unless you're very careful, Dialogue: 0,1:03:21.90,1:03:24.46,EN,,0,0,0,,any amount of side effect is going to mess up everything. Dialogue: 0,1:03:35.04,1:03:38.25,EN,,0,0,0,,AUDIENCE: Sorry, I didn't quite understand the memo-proc operation. Uh... Dialogue: 0,1:03:39.68,1:03:41.12,EN,,0,0,0,,When do you execute the lambda? Dialogue: 0,1:03:41.99,1:03:43.21,EN,,0,0,0,,In other words, Dialogue: 0,1:03:43.68,1:03:45.15,EN,,0,0,0,,when memo-proc is executed, Dialogue: 0,1:03:45.18,1:03:47.71,EN,,0,0,0,,just this lambda expression is being generated. Dialogue: 0,1:03:48.01,1:03:49.68,EN,,0,0,0,,But it's not clear to me when it's executed. Dialogue: 0,1:03:50.39,1:03:51.12,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,1:03:51.35,1:03:52.68,EN,,0,0,0,,What memo-proc does-- remember, Dialogue: 0,1:03:53.07,1:03:55.85,EN,,0,0,0,,the thing that's going into memo-proc, the thing proc, Dialogue: 0,1:03:56.38,1:03:57.93,EN,,0,0,0,,is a procedure of no arguments. Dialogue: 0,1:03:57.93,1:03:59.05,EN,,0,0,0,,And someday, you're going to call it. Dialogue: 0,1:04:00.39,1:04:02.75,EN,,0,0,0,,Memo-proc translates that procedure Dialogue: 0,1:04:02.75,1:04:04.56,EN,,0,0,0,,into another procedure of no arguments, Dialogue: 0,1:04:04.59,1:04:05.80,EN,,0,0,0,,which someday you're going to call. Dialogue: 0,1:04:06.62,1:04:07.42,EN,,0,0,0,,That's that lambda. Dialogue: 0,1:04:09.89,1:04:14.08,EN,,0,0,0,,So here, where I initially built as my Dialogue: 0,1:04:15.85,1:04:17.92,EN,,0,0,0,,I built as my tail of the stream, Dialogue: 0,1:04:18.30,1:04:20.48,EN,,0,0,0,,say, this procedure of no arguments, Dialogue: 0,1:04:20.51,1:04:21.61,EN,,0,0,0,,which someday I'll call. Dialogue: 0,1:04:24.10,1:04:28.01,EN,,0,0,0,,Instead, I'm going to have the tail of the stream be memo-proc of it, Dialogue: 0,1:04:28.12,1:04:29.24,EN,,0,0,0,,which someday I'll call. Dialogue: 0,1:04:30.65,1:04:31.90,EN,,0,0,0,,So that lambda of nil, Dialogue: 0,1:04:32.03,1:04:36.06,EN,,0,0,0,,that gets called when you call the memo-proc, Dialogue: 0,1:04:38.97,1:04:40.96,EN,,0,0,0,,when you call the result of that memo-proc, Dialogue: 0,1:04:40.97,1:04:42.28,EN,,0,0,0,,which would be ordinarily Dialogue: 0,1:04:42.36,1:04:45.76,EN,,0,0,0,,when you would have called the original thing that you set it. Dialogue: 0,1:04:47.64,1:04:48.86,EN,,0,0,0,,AUDIENCE: OK, my ask is Dialogue: 0,1:04:48.86,1:04:50.86,EN,,0,0,0,,I had a feeling that when you call memo-proc, Dialogue: 0,1:04:50.86,1:04:52.30,EN,,0,0,0,,you just return this lambda. Dialogue: 0,1:04:52.61,1:04:53.07,EN,,0,0,0,,PROFESSOR: That's right. Dialogue: 0,1:04:53.77,1:04:58.10,EN,,0,0,0,,When you call memo-proc, you return the lambda. Dialogue: 0,1:04:58.10,1:04:59.84,EN,,0,0,0,,You never evaluate the expression at all, Dialogue: 0,1:04:59.87,1:05:02.27,EN,,0,0,0,,until the first time that you would have evaluated it. Dialogue: 0,1:05:07.76,1:05:09.10,EN,,0,0,0,,AUDIENCE: Do I understand it right Dialogue: 0,1:05:09.18,1:05:11.40,EN,,0,0,0,,you actually have to build the list up, Dialogue: 0,1:05:11.47,1:05:14.17,EN,,0,0,0,,but the elements of the list don't get evaluated? Dialogue: 0,1:05:14.24,1:05:15.63,EN,,0,0,0,,The expressions don't get evaluated? Dialogue: 0,1:05:15.63,1:05:18.54,EN,,0,0,0,,But at each stage, you actually are building a list. Dialogue: 0,1:05:18.54,1:05:20.70,EN,,0,0,0,,PROFESSOR: That's-- I really should have said this. Dialogue: 0,1:05:20.70,1:05:22.27,EN,,0,0,0,,That's a really good point. Dialogue: 0,1:05:22.27,1:05:23.18,EN,,0,0,0,,No, it's not quite right. Dialogue: 0,1:05:23.66,1:05:25.08,EN,,0,0,0,,See, cause what happens is this. Dialogue: 0,1:05:25.08,1:05:26.35,EN,,0,0,0,,Let me draw this as pairs. Dialogue: 0,1:05:26.89,1:05:28.03,EN,,0,0,0,,Suppose I'm going to make a big stream, Dialogue: 0,1:05:28.96,1:05:30.12,EN,,0,0,0,,like enumerate interval, Dialogue: 0,1:05:30.32,1:05:31.48,EN,,0,0,0,,1 through 1 billion. Dialogue: 0,1:05:32.74,1:05:35.74,EN,,0,0,0,,What that is, is a pair Dialogue: 0,1:05:39.34,1:05:43.36,EN,,0,0,0,,a 1 and a promise. Dialogue: 0,1:05:46.73,1:05:47.89,EN,,0,0,0,,That's exactly what it is. Dialogue: 0,1:05:47.89,1:05:48.76,EN,,0,0,0,,Nothing got built up. Dialogue: 0,1:05:51.60,1:05:53.29,EN,,0,0,0,,When I go and force this, Dialogue: 0,1:05:54.51,1:05:56.37,EN,,0,0,0,,and see, what happens? Dialogue: 0,1:05:56.37,1:05:59.66,EN,,0,0,0,,Well, this thing is now also recursively a CONS. Dialogue: 0,1:06:00.53,1:06:02.16,EN,,0,0,0,,So that this promise now is Dialogue: 0,1:06:04.62,1:06:08.96,EN,,0,0,0,,the next thing, which is a 2 and a promise to do more. Dialogue: 0,1:06:11.35,1:06:12.73,EN,,0,0,0,,And so on and so on and so on. Dialogue: 0,1:06:14.47,1:06:17.63,EN,,0,0,0,,So nothing gets built up until you walk down the stream. Dialogue: 0,1:06:18.20,1:06:19.58,EN,,0,0,0,,Because what's sitting here is not the list, Dialogue: 0,1:06:20.03,1:06:21.48,EN,,0,0,0,,but a promise to generate the list. Dialogue: 0,1:06:23.39,1:06:25.50,EN,,0,0,0,,And by promise, technically I mean procedure. Dialogue: 0,1:06:27.80,1:06:29.10,EN,,0,0,0,,So it doesn't get built up. Dialogue: 0,1:06:30.76,1:06:32.72,EN,,0,0,0,,Yeah, I should have said that before that. Dialogue: 0,1:06:34.28,1:06:35.34,EN,,0,0,0,,OK. That you. Let's take a break. Dialogue: 0,1:06:35.82,1:06:51.15,Declare,,0,0,0,,{\fad(500,500)}http://ocw.mit.edu Dialogue: 0,1:06:35.82,1:06:51.15,Declare,,0,0,0,,{\an2\fad(500,500)}https://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec6b.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Video Position: 629 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:20.97,0:00:24.08,EN,,0,0,0,,PROFESSOR: OK, well, we've been looking at streams, Dialogue: 0,0:00:24.08,0:00:27.82,EN,,0,0,0,,this signal processing way of putting systems together. Dialogue: 0,0:00:28.87,0:00:31.42,EN,,0,0,0,,And remember, the key idea is that Dialogue: 0,0:00:31.90,0:00:32.96,EN,,0,0,0,,we decouple Dialogue: 0,0:00:34.20,0:00:37.31,EN,,0,0,0,,the apparent order of events in our programs Dialogue: 0,0:00:37.58,0:00:40.17,EN,,0,0,0,,from the actual order of events in the computer. Dialogue: 0,0:00:41.07,0:00:42.28,EN,,0,0,0,,And that means that we can start Dialogue: 0,0:00:42.57,0:00:44.14,EN,,0,0,0,,dealing with very long streams Dialogue: 0,0:00:44.89,0:00:47.39,EN,,0,0,0,,and only having to generate the elements on demand. Dialogue: 0,0:00:47.53,0:00:49.39,EN,,0,0,0,,That sort of on-demand computation Dialogue: 0,0:00:49.52,0:00:51.40,EN,,0,0,0,,is built into the stream's data structure. Dialogue: 0,0:00:54.11,0:00:55.64,EN,,0,0,0,,So if we have a very long stream, Dialogue: 0,0:00:55.66,0:00:57.08,EN,,0,0,0,,we only compute what we need. Dialogue: 0,0:00:58.04,0:01:00.75,EN,,0,0,0,,The things only get computed when we actually ask for them. Dialogue: 0,0:01:00.75,0:01:01.74,EN,,0,0,0,,Well, what are examples? Dialogue: 0,0:01:02.11,0:01:03.60,EN,,0,0,0,,Are they actually asking for them? Dialogue: 0,0:01:05.02,0:01:06.01,EN,,0,0,0,,For instance, we might Dialogue: 0,0:01:09.21,0:01:11.37,EN,,0,0,0,,might ask for the n-th element of a stream. Dialogue: 0,0:01:15.36,0:01:18.92,EN,,0,0,0,,Here's a procedure that computes the n-th element of a stream. Dialogue: 0,0:01:20.09,0:01:21.23,EN,,0,0,0,,An integer n, Dialogue: 0,0:01:21.24,0:01:22.84,EN,,0,0,0,,the n-th element of some stream s, Dialogue: 0,0:01:23.40,0:01:25.42,EN,,0,0,0,,and we just recursively walk down the stream. Dialogue: 0,0:01:25.57,0:01:27.39,EN,,0,0,0,,And if n is 0, we compute the head. Dialogue: 0,0:01:27.96,0:01:30.99,EN,,0,0,0,,Otherwise, it's the n-th the minus 1 element Dialogue: 0,0:01:31.74,0:01:32.80,EN,,0,0,0,,of the stream. Dialogue: 0,0:01:34.31,0:01:36.43,EN,,0,0,0,,Those two are just like for Lisp, but the difference Dialogue: 0,0:01:36.62,0:01:38.76,EN,,0,0,0,,is those elements aren't going to get computed Dialogue: 0,0:01:38.86,0:01:40.99,EN,,0,0,0,,until we walk down, taking successive n-ths. Dialogue: 0,0:01:41.52,0:01:44.78,EN,,0,0,0,,So that's one way that the stream elements might get forced. Dialogue: 0,0:01:45.77,0:01:46.64,EN,,0,0,0,,And another way, Dialogue: 0,0:01:47.18,0:01:48.92,EN,,0,0,0,,here's a little procedure that prints a stream. Dialogue: 0,0:01:49.30,0:01:50.38,EN,,0,0,0,,We say print a stream, Dialogue: 0,0:01:51.90,0:01:53.28,EN,,0,0,0,,so to print a stream s. Dialogue: 0,0:01:54.15,0:01:55.12,EN,,0,0,0,,Well, what do we do? We'll Dialogue: 0,0:01:55.74,0:01:56.86,EN,,0,0,0,,We print the head of the stream, Dialogue: 0,0:01:57.74,0:01:59.32,EN,,0,0,0,,and that will cause the head to be computed. Dialogue: 0,0:01:59.72,0:02:02.84,EN,,0,0,0,,And then we recursively print stream the tail of the stream. Dialogue: 0,0:02:04.99,0:02:06.03,EN,,0,0,0,,And if we're already done, Dialogue: 0,0:02:06.04,0:02:08.57,EN,,0,0,0,,maybe we have to return something about the message done. Dialogue: 0,0:02:09.66,0:02:11.39,EN,,0,0,0,,OK, and then so if you make a stream, Dialogue: 0,0:02:11.64,0:02:13.64,EN,,0,0,0,,you could say here's the stream, this very long stream. Dialogue: 0,0:02:14.31,0:02:16.33,EN,,0,0,0,,And then you say print the stream, Dialogue: 0,0:02:16.41,0:02:19.77,EN,,0,0,0,,and the elements of the stream will get computed successively Dialogue: 0,0:02:19.87,0:02:21.12,EN,,0,0,0,,as that print calls them. Dialogue: 0,0:02:21.32,0:02:22.81,EN,,0,0,0,,They won't get all computed initially. Dialogue: 0,0:02:24.30,0:02:25.66,EN,,0,0,0,,So in this way, we can Dialogue: 0,0:02:27.50,0:02:29.61,EN,,0,0,0,,So in this way, we can deal with some very long streams. Dialogue: 0,0:02:30.19,0:02:31.92,EN,,0,0,0,,Well, how long can a stream be? Dialogue: 0,0:02:33.74,0:02:35.12,EN,,0,0,0,,Well, it can be infinitely long. Dialogue: 0,0:02:35.90,0:02:38.04,EN,,0,0,0,,Let's look at an example here on the computer. Dialogue: 0,0:02:38.92,0:02:41.96,EN,,0,0,0,,I could walk up to this computer, and I could say-- Dialogue: 0,0:02:43.48,0:02:53.31,EN,,0,0,0,,how about we'll define the stream of integers starting with some number N, Dialogue: 0,0:02:54.24,0:02:57.13,EN,,0,0,0,,the stream of positive integers starting with some number n. Dialogue: 0,0:03:00.36,0:03:19.16,EN,,0,0,0,,And that's cons-stream of n onto the integers from one more. Dialogue: 0,0:03:24.41,0:03:25.61,EN,,0,0,0,,So there are the integers. Dialogue: 0,0:03:28.99,0:03:31.50,EN,,0,0,0,,Then I could say let's get all the integers. Dialogue: 0,0:03:34.57,0:03:44.33,EN,,0,0,0,,define the stream of integers to be the integers starting with 1. Dialogue: 0,0:03:48.84,0:03:50.94,EN,,0,0,0,,And now if I say something like Dialogue: 0,0:03:54.41,0:03:55.80,EN,,0,0,0,,what's the what's the 20th integer. Dialogue: 0,0:04:03.42,0:04:05.53,EN,,0,0,0,,So it's 21 because we start counting at 0. Dialogue: 0,0:04:06.84,0:04:08.88,EN,,0,0,0,,Or I can do more complicated things. Dialogue: 0,0:04:09.45,0:04:10.84,EN,,0,0,0,,Let me to define a little predicate here. Dialogue: 0,0:04:11.77,0:04:18.51,EN,,0,0,0,,How about define no-seven. Dialogue: 0,0:04:19.58,0:04:20.75,EN,,0,0,0,,It's going to test an integer, Dialogue: 0,0:04:21.79,0:04:23.16,EN,,0,0,0,,and it's going to say it's not. Dialogue: 0,0:04:28.82,0:04:33.96,EN,,0,0,0,,I take the remainder of x by 7, Dialogue: 0,0:04:36.62,0:04:38.35,EN,,0,0,0,,I don't get 0. Dialogue: 0,0:04:43.80,0:04:49.77,EN,,0,0,0,,And then I could say define the integers with no sevens Dialogue: 0,0:04:50.22,0:04:59.12,EN,,0,0,0,,take all the integers and filter them to have no sevens. Dialogue: 0,0:05:11.57,0:05:13.34,EN,,0,0,0,,So now I've got the stream of all the integers Dialogue: 0,0:05:13.63,0:05:15.05,EN,,0,0,0,,that are not divisible by seven. Dialogue: 0,0:05:16.49,0:05:23.44,EN,,0,0,0,,So if I say what's the 100th integer Dialogue: 0,0:05:24.70,0:05:26.48,EN,,0,0,0,,and the list not divisible by seven, Dialogue: 0,0:05:26.86,0:05:28.11,EN,,0,0,0,,I get 117. Dialogue: 0,0:05:28.32,0:05:30.67,EN,,0,0,0,,Or if I'd like to say well, I could say ah. Dialogue: 0,0:05:32.30,0:05:34.38,EN,,0,0,0,,well, gee, what are all of them? Dialogue: 0,0:05:35.27,0:05:40.35,EN,,0,0,0,,So I could say print stream all these integers with no seven, Dialogue: 0,0:05:40.83,0:05:41.79,EN,,0,0,0,,it goes off printing. Dialogue: 0,0:05:45.10,0:05:47.07,EN,,0,0,0,,You may have to wait a very long time to see them all. Dialogue: 0,0:05:52.67,0:05:53.84,EN,,0,0,0,,Well, you can start asking, gee, Dialogue: 0,0:05:54.81,0:05:57.00,EN,,0,0,0,,you know, is it really true that this data structure Dialogue: 0,0:05:58.28,0:06:00.65,EN,,0,0,0,,with the integers is really all the integers? Dialogue: 0,0:06:01.10,0:06:04.05,EN,,0,0,0,,And let me draw a picture of that program I just wrote. Dialogue: 0,0:06:04.96,0:06:10.57,EN,,0,0,0,,Here's the, right, here's the definition of the integers again that I just typed in, Dialogue: 0,0:06:12.33,0:06:15.98,EN,,0,0,0,,Right it's a cons of the first integer under the integer starting with the rest. Dialogue: 0,0:06:17.61,0:06:19.77,EN,,0,0,0,,Now, we can make a picture of that and see what it looks like. Dialogue: 0,0:06:22.72,0:06:24.32,EN,,0,0,0,,Conceptually, what I have is a box Dialogue: 0,0:06:25.53,0:06:27.18,EN,,0,0,0,,that's the integer starting with n. Dialogue: 0,0:06:27.42,0:06:29.08,EN,,0,0,0,,It takes in some number n, Dialogue: 0,0:06:31.42,0:06:32.97,EN,,0,0,0,,and it's going to return a stream of-- Dialogue: 0,0:06:35.02,0:06:37.36,EN,,0,0,0,,this infinite stream of all integers starting with n. Dialogue: 0,0:06:38.08,0:06:38.73,EN,,0,0,0,,And what do I do? Dialogue: 0,0:06:38.75,0:06:42.38,EN,,0,0,0,,Well, this is an integers-from box. Dialogue: 0,0:06:45.07,0:06:45.80,EN,,0,0,0,,What's it got in it? Dialogue: 0,0:06:45.80,0:06:48.60,EN,,0,0,0,,Well, it takes in this n, Dialogue: 0,0:06:52.27,0:06:53.92,EN,,0,0,0,,and it increments it. Dialogue: 0,0:06:57.95,0:07:03.15,EN,,0,0,0,,And then it puts the result into recursively another integer's from box. Dialogue: 0,0:07:06.87,0:07:09.60,EN,,0,0,0,,It takes the result of that and the original n Dialogue: 0,0:07:10.24,0:07:12.78,EN,,0,0,0,,and puts those together with a cons Dialogue: 0,0:07:13.39,0:07:14.36,EN,,0,0,0,,and forms a stream. Dialogue: 0,0:07:14.57,0:07:17.26,EN,,0,0,0,,So that's a picture of that program I wrote. And this is a ... Dialogue: 0,0:07:18.52,0:07:20.32,EN,,0,0,0,,Let's see. These kind of diagrams we first saw Dialogue: 0,0:07:20.78,0:07:21.74,EN,,0,0,0,,drawn by Peter Henderson, Dialogue: 0,0:07:21.76,0:07:23.32,EN,,0,0,0,,the same guy who did the Escher language. Dialogue: 0,0:07:23.32,0:07:24.75,EN,,0,0,0,,We call them Henderson diagrams. Dialogue: 0,0:07:25.37,0:07:27.90,EN,,0,0,0,,And the convention here is that you put these things together. Dialogue: 0,0:07:28.53,0:07:32.51,EN,,0,0,0,,And the solid lines are things coming out are streams, Dialogue: 0,0:07:33.02,0:07:36.20,EN,,0,0,0,,and dotted lines are initial values going in. Dialogue: 0,0:07:37.27,0:07:39.02,EN,,0,0,0,,So this one has the shape of-- Dialogue: 0,0:07:39.40,0:07:41.60,EN,,0,0,0,,it takes in some integer, some initial value, Dialogue: 0,0:07:41.80,0:07:42.91,EN,,0,0,0,,and outputs a stream. Dialogue: 0,0:07:46.35,0:07:48.22,EN,,0,0,0,,Again, you can ask. You know it's really Dialogue: 0,0:07:48.38,0:07:50.88,EN,,0,0,0,,Is that data structure integers really all the integers? Dialogue: 0,0:07:52.09,0:07:54.91,EN,,0,0,0,,Alright? Or is it is something that's cleverly arranged Dialogue: 0,0:07:54.94,0:07:56.43,EN,,0,0,0,,so that whenever you look for an integer Dialogue: 0,0:07:56.44,0:07:57.24,EN,,0,0,0,,you find it there? Dialogue: 0,0:07:57.95,0:07:59.74,EN,,0,0,0,,That's sort of a philosophical question, right? Dialogue: 0,0:07:59.78,0:08:01.69,EN,,0,0,0,,If something is there Dialogue: 0,0:08:02.14,0:08:03.96,EN,,0,0,0,,whenever you look, is it really there or not? Dialogue: 0,0:08:04.45,0:08:07.34,EN,,0,0,0,,It's sort of the same sense in which Dialogue: 0,0:08:07.36,0:08:09.42,EN,,0,0,0,,the money in your savings account is in the bank. Dialogue: 0,0:08:12.38,0:08:12.64,EN,,0,0,0,,Well Dialogue: 0,0:08:16.35,0:08:17.48,EN,,0,0,0,,let me do another example. Dialogue: 0,0:08:18.68,0:08:20.70,EN,,0,0,0,,Umm, Gee, we started the course Dialogue: 0,0:08:20.72,0:08:22.72,EN,,0,0,0,,with an algorithm from Alexandria, Dialogue: 0,0:08:23.29,0:08:25.80,EN,,0,0,0,,which was Heron of Alexandria's algorithm Dialogue: 0,0:08:25.82,0:08:26.94,EN,,0,0,0,,for computing the square root. Dialogue: 0,0:08:28.47,0:08:32.03,EN,,0,0,0,,Let's take a look at another Alexandrian algorithm. Dialogue: 0,0:08:32.03,0:08:35.08,EN,,0,0,0,,This one is Eratosthenes method for Dialogue: 0,0:08:36.19,0:08:38.44,EN,,0,0,0,,for computing all of the primes. Dialogue: 0,0:08:41.16,0:08:42.83,EN,,0,0,0,,It is called the Sieve of Eratosthenes. Dialogue: 0,0:08:42.83,0:08:49.72,EN,,0,0,0,,And what you do is you start out, Dialogue: 0,0:08:50.99,0:08:52.28,EN,,0,0,0,,and you list all the integers, Dialogue: 0,0:08:52.60,0:08:53.53,EN,,0,0,0,,say, starting with 2. Dialogue: 0,0:08:53.88,0:08:55.04,EN,,0,0,0,,And then you take the first integer, and you say, Dialogue: 0,0:08:55.08,0:08:56.67,EN,,0,0,0,,and you say, oh, that's prime. Dialogue: 0,0:08:57.31,0:08:58.35,EN,,0,0,0,,And then you go look at the rest, Dialogue: 0,0:08:58.68,0:09:00.88,EN,,0,0,0,,and you cross out all the things divisible by 2. Dialogue: 0,0:09:01.52,0:09:04.73,EN,,0,0,0,,So I cross out this and this and this. Dialogue: 0,0:09:05.25,0:09:06.35,EN,,0,0,0,,This takes a long time Dialogue: 0,0:09:06.36,0:09:08.91,EN,,0,0,0,,because I have to do it for all of the integers. Dialogue: 0,0:09:11.16,0:09:15.39,EN,,0,0,0,,So I go through the entire list of integers, Dialogue: 0,0:09:18.27,0:09:20.94,EN,,0,0,0,,crossing the ones divisible by 2. Dialogue: 0,0:09:22.11,0:09:24.38,EN,,0,0,0,,And now when I finish with all of the integers, Dialogue: 0,0:09:24.78,0:09:26.72,EN,,0,0,0,,I go back and look and say what am I left with? Dialogue: 0,0:09:27.04,0:09:28.80,EN,,0,0,0,,Well, the first thing that starts there is 3. Dialogue: 0,0:09:29.33,0:09:30.33,EN,,0,0,0,,So 3 is a prime. Dialogue: 0,0:09:30.77,0:09:33.05,EN,,0,0,0,,And now I go back through what I'm left with, Dialogue: 0,0:09:33.36,0:09:35.07,EN,,0,0,0,,and I cross out all the things divisible by 3. Dialogue: 0,0:09:35.08,0:09:43.80,EN,,0,0,0,,So let's see, 9 and 15 and 21 and 27 and 33 and so on. Dialogue: 0,0:09:44.33,0:09:45.12,EN,,0,0,0,,I won't finish. Dialogue: 0,0:09:45.35,0:09:46.52,EN,,0,0,0,,Then I see what I'm left with. Dialogue: 0,0:09:47.25,0:09:49.84,EN,,0,0,0,,And the next one I have is 5. Dialogue: 0,0:09:50.49,0:09:52.04,EN,,0,0,0,,Now I can through the rest, Dialogue: 0,0:09:52.43,0:09:54.51,EN,,0,0,0,,and I find the first one that's divisible by 5. Dialogue: 0,0:09:54.54,0:09:57.61,EN,,0,0,0,,I cross out from the remainder all the ones that are divisible by 5. Dialogue: 0,0:09:58.35,0:09:59.24,EN,,0,0,0,,And I did that, Dialogue: 0,0:09:59.82,0:10:01.89,EN,,0,0,0,,and then I go through and find 7. Dialogue: 0,0:10:01.89,0:10:02.72,EN,,0,0,0,,Go through all the rest, Dialogue: 0,0:10:02.76,0:10:03.95,EN,,0,0,0,,cross out things divisible 7, Dialogue: 0,0:10:03.98,0:10:05.47,EN,,0,0,0,,and I keep doing that forever. Dialogue: 0,0:10:06.81,0:10:07.40,EN,,0,0,0,,And when I'm done, Dialogue: 0,0:10:07.40,0:10:09.10,EN,,0,0,0,,what I'm left with is a list of all the primes. Dialogue: 0,0:10:09.90,0:10:13.31,EN,,0,0,0,,So that's the Sieve of Eratosthenes. Dialogue: 0,0:10:15.43,0:10:17.69,EN,,0,0,0,,Let's look at it as a computer program. Dialogue: 0,0:10:17.93,0:10:19.85,EN,,0,0,0,,It's a procedure called sieve. Dialogue: 0,0:10:27.91,0:10:29.40,EN,,0,0,0,,Now, I just write what I did. Dialogue: 0,0:10:30.33,0:10:34.48,EN,,0,0,0,,I'll say to sieve some stream s. Dialogue: 0,0:10:38.77,0:10:39.93,EN,,0,0,0,,I'm going to build a stream Dialogue: 0,0:10:40.27,0:10:41.84,EN,,0,0,0,,whose first element is the head of this. Dialogue: 0,0:10:41.87,0:10:44.43,EN,,0,0,0,,Remember, I always found the first thing I was left with, Dialogue: 0,0:10:44.91,0:10:48.75,EN,,0,0,0,,and the rest of it is the result of taking the tail of S, Dialogue: 0,0:10:51.08,0:10:53.72,EN,,0,0,0,,filtering it to throw away all the things Dialogue: 0,0:10:53.74,0:10:55.32,EN,,0,0,0,,that are divisible by the head of S, Dialogue: 0,0:10:56.41,0:10:57.56,EN,,0,0,0,,and now sieving the result. Dialogue: 0,0:10:59.02,0:11:00.09,EN,,0,0,0,,That's just what I did. Dialogue: 0,0:11:01.98,0:11:04.68,EN,,0,0,0,,And now to get the infinite stream of times, Dialogue: 0,0:11:05.02,0:11:06.90,EN,,0,0,0,,we just sieve all the integers starting from 2. Dialogue: 0,0:11:14.92,0:11:15.56,EN,,0,0,0,,Let's try that. Dialogue: 0,0:11:16.30,0:11:18.30,EN,,0,0,0,,We can actually do it. Dialogue: 0,0:11:19.76,0:11:22.12,EN,,0,0,0,,I typed in the definition of sieve before, I hope, Dialogue: 0,0:11:22.86,0:11:24.06,EN,,0,0,0,,so I can say something like Dialogue: 0,0:11:24.92,0:11:33.45,EN,,0,0,0,,define the primes to be Dialogue: 0,0:11:34.64,0:11:41.45,EN,,0,0,0,,the result of sieving the integers starting with 2. Dialogue: 0,0:11:46.76,0:11:48.10,EN,,0,0,0,,So now I've got this list of primes. Dialogue: 0,0:11:48.10,0:11:50.99,EN,,0,0,0,,That's all of the primes, right? Dialogue: 0,0:11:50.99,0:11:53.52,EN,,0,0,0,,So, if for example, what's the 20th prime in that list? Dialogue: 0,0:12:00.73,0:12:01.68,EN,,0,0,0,,73. Dialogue: 0,0:12:02.54,0:12:03.34,EN,,0,0,0,,See, and that little pause, Dialogue: 0,0:12:03.36,0:12:04.92,EN,,0,0,0,,it was only at the point Dialogue: 0,0:12:04.94,0:12:06.43,EN,,0,0,0,,when I started asking for the 20th prime Dialogue: 0,0:12:06.46,0:12:07.68,EN,,0,0,0,,is that it started computing. Dialogue: 0,0:12:10.37,0:12:11.29,EN,,0,0,0,,Or I can say here Dialogue: 0,0:12:13.80,0:12:14.88,EN,,0,0,0,,Or I can say here let's look at all of the primes. Dialogue: 0,0:12:22.64,0:12:24.40,EN,,0,0,0,,And there it goes computing all of the primes. Dialogue: 0,0:12:25.35,0:12:26.28,EN,,0,0,0,,Of course, it will take a while Dialogue: 0,0:12:26.28,0:12:27.61,EN,,0,0,0,,again if I want to look at all of them, Dialogue: 0,0:12:27.79,0:12:28.57,EN,,0,0,0,,so let's stop it. Dialogue: 0,0:12:32.03,0:12:33.13,EN,,0,0,0,,Let me draw you a picture of that. Dialogue: 0,0:12:33.13,0:12:34.17,EN,,0,0,0,,Well, I've got a picture of that. Dialogue: 0,0:12:34.89,0:12:36.19,EN,,0,0,0,,What's that program really look like? Dialogue: 0,0:12:37.90,0:12:39.77,EN,,0,0,0,,Again, some practice with these diagrams, Dialogue: 0,0:12:39.82,0:12:40.54,EN,,0,0,0,,I have a sieve box. Dialogue: 0,0:12:42.61,0:12:43.56,EN,,0,0,0,,How does sieve work? Dialogue: 0,0:12:43.56,0:12:44.81,EN,,0,0,0,,It takes in a stream. Dialogue: 0,0:12:48.85,0:12:50.59,EN,,0,0,0,,It splits off the head from the tail. Dialogue: 0,0:12:50.87,0:12:53.26,EN,,0,0,0,,And the first thing that's going to come out of the sieve Dialogue: 0,0:12:53.48,0:12:54.97,EN,,0,0,0,,is the head of the original stream. Dialogue: 0,0:12:58.20,0:13:00.92,EN,,0,0,0,,Then it also takes the head and uses that. Dialogue: 0,0:13:02.55,0:13:05.10,EN,,0,0,0,,It takes the stream. It filters the tail Dialogue: 0,0:13:05.55,0:13:08.33,EN,,0,0,0,,It filters the tail and uses the head to filter for nondivisibility. Dialogue: 0,0:13:09.53,0:13:11.18,EN,,0,0,0,,It takes the result of nondivisibility Dialogue: 0,0:13:11.24,0:13:13.12,EN,,0,0,0,,and puts it through another sieve box Dialogue: 0,0:13:13.90,0:13:15.13,EN,,0,0,0,,and puts the result together. Dialogue: 0,0:13:15.13,0:13:16.89,EN,,0,0,0,,So you can think of this sieve a filter, Dialogue: 0,0:13:17.20,0:13:19.23,EN,,0,0,0,,but notice that it's an infinitely recursive filter. Dialogue: 0,0:13:19.65,0:13:20.88,EN,,0,0,0,,Because inside the sieve box Dialogue: 0,0:13:21.52,0:13:22.60,EN,,0,0,0,,is another sieve box, Dialogue: 0,0:13:23.37,0:13:25.85,EN,,0,0,0,,and inside that is another sieve box and another sieve box. Dialogue: 0,0:13:27.13,0:13:28.96,EN,,0,0,0,,So you see we start getting some very powerful things. Dialogue: 0,0:13:28.96,0:13:32.84,EN,,0,0,0,,We're starting to mix this signal processing view of the world Dialogue: 0,0:13:33.90,0:13:36.41,EN,,0,0,0,,with things like recursion that come from computation. Dialogue: 0,0:13:37.42,0:13:39.82,EN,,0,0,0,,And there are all sorts of interesting things you can do that are like this. Dialogue: 0,0:13:40.97,0:13:42.09,EN,,0,0,0,,All right, any questions? Dialogue: 0,0:13:48.19,0:13:49.16,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:14:28.65,0:14:30.36,EN,,0,0,0,,Well, we've been looking at a couple Dialogue: 0,0:14:30.36,0:14:32.09,EN,,0,0,0,,of examples of stream programming. Dialogue: 0,0:14:34.79,0:14:39.21,EN,,0,0,0,,All the stream procedures that we've looked at so far Dialogue: 0,0:14:39.72,0:14:41.32,EN,,0,0,0,,have the same kind of character. Dialogue: 0,0:14:41.49,0:14:43.63,EN,,0,0,0,,We've been writing these recursive procedures Dialogue: 0,0:14:44.16,0:14:46.49,EN,,0,0,0,,that kind of generate these stream elements one at a time Dialogue: 0,0:14:46.51,0:14:48.72,EN,,0,0,0,,and put them together in cons-streams. Dialogue: 0,0:14:49.15,0:14:50.86,EN,,0,0,0,,So we've been thinking a lot about generators. Dialogue: 0,0:14:50.92,0:14:53.63,EN,,0,0,0,,There's another way to think about stream processing, Dialogue: 0,0:14:53.79,0:14:56.96,EN,,0,0,0,,and that's to focus not on programs that sort of Dialogue: 0,0:14:57.36,0:14:59.93,EN,,0,0,0,,process these elements as you walk down the stream, Dialogue: 0,0:15:00.25,0:15:05.68,EN,,0,0,0,,but on things that kind of process the streams all at once. Dialogue: 0,0:15:07.18,0:15:09.16,EN,,0,0,0,,To show you what I mean, let me start by defining Dialogue: 0,0:15:09.23,0:15:11.50,EN,,0,0,0,,two procedures that will come in handy. Dialogue: 0,0:15:12.41,0:15:13.60,EN,,0,0,0,,The first one's called add streams. Dialogue: 0,0:15:15.36,0:15:18.25,EN,,0,0,0,,Add streams takes two streams: Dialogue: 0,0:15:18.81,0:15:20.88,EN,,0,0,0,,s1 and s2. Dialogue: 0,0:15:22.30,0:15:24.67,EN,,0,0,0,,And it's going to produce a stream Dialogue: 0,0:15:24.99,0:15:28.17,EN,,0,0,0,,whose elements are the are the corresponding sums Dialogue: 0,0:15:30.22,0:15:31.88,EN,,0,0,0,,We just sort of add them element-wise. Dialogue: 0,0:15:32.97,0:15:33.95,EN,,0,0,0,,If either stream is empty, Dialogue: 0,0:15:33.96,0:15:35.39,EN,,0,0,0,,we just return the other one. Dialogue: 0,0:15:36.81,0:15:38.96,EN,,0,0,0,,Otherwise, we're going to make a new stream Dialogue: 0,0:15:39.90,0:15:42.96,EN,,0,0,0,,whose head is the sum of the two heads Dialogue: 0,0:15:44.00,0:15:44.88,EN,,0,0,0,,whose tail Dialogue: 0,0:15:46.00,0:15:48.62,EN,,0,0,0,,is the result of recursively adding the tails. Dialogue: 0,0:15:50.09,0:15:52.73,EN,,0,0,0,,So that will produce the element-wise sum of two streams. Dialogue: 0,0:15:53.15,0:15:57.04,EN,,0,0,0,,And then another useful thing to have around is scale stream. Dialogue: 0,0:15:57.50,0:16:01.66,EN,,0,0,0,,Scale stream takes some constant number in a stream s Dialogue: 0,0:16:04.11,0:16:06.62,EN,,0,0,0,,and is going to produce the stream Dialogue: 0,0:16:07.18,0:16:09.50,EN,,0,0,0,,of elements of s multiplied by this constant. Dialogue: 0,0:16:09.71,0:16:11.21,EN,,0,0,0,,And that's easy, that's just a map Dialogue: 0,0:16:12.20,0:16:16.22,EN,,0,0,0,,of the function of an element that multiplies it by the constant, Dialogue: 0,0:16:16.35,0:16:17.80,EN,,0,0,0,,and we map that down the stream. Dialogue: 0,0:16:20.06,0:16:21.47,EN,,0,0,0,,So given those two, Dialogue: 0,0:16:22.64,0:16:24.36,EN,,0,0,0,,let me show you what I mean by programs that Dialogue: 0,0:16:24.70,0:16:27.00,EN,,0,0,0,,that operate on streams all at once. Dialogue: 0,0:16:28.12,0:16:28.73,EN,,0,0,0,,Let's look at this. Dialogue: 0,0:16:30.20,0:16:30.92,EN,,0,0,0,,Suppose I write this. Dialogue: 0,0:16:31.68,0:16:52.35,EN,,0,0,0,,I say define-- I'll call it ones-- to be cons-stream of 1 onto ones. Dialogue: 0,0:16:54.86,0:16:55.52,EN,,0,0,0,,What's that? Dialogue: 0,0:16:56.95,0:16:58.94,EN,,0,0,0,,That's going to be an infinite stream of ones Dialogue: 0,0:16:59.96,0:17:01.44,EN,,0,0,0,,because the first thing is 1. Dialogue: 0,0:17:03.33,0:17:05.15,EN,,0,0,0,,And the tail of it is a thing Dialogue: 0,0:17:05.55,0:17:06.83,EN,,0,0,0,,whose first thing is 1 Dialogue: 0,0:17:07.63,0:17:09.02,EN,,0,0,0,,whose tail is a thing Dialogue: 0,0:17:09.12,0:17:10.24,EN,,0,0,0,,whose first thing is 1 Dialogue: 0,0:17:10.52,0:17:11.78,EN,,0,0,0,,and so on and so on. Dialogue: 0,0:17:11.78,0:17:13.32,EN,,0,0,0,,So that's an infinite stream of ones. Dialogue: 0,0:17:15.13,0:17:15.93,EN,,0,0,0,,And now using that, Dialogue: 0,0:17:16.12,0:17:18.03,EN,,0,0,0,,let me give you another definition of the integers. Dialogue: 0,0:17:19.47,0:17:27.36,EN,,0,0,0,,We can define the integers to be-- Dialogue: 0,0:17:28.24,0:17:30.76,EN,,0,0,0,,well, the first integer we'll take to be 1, Dialogue: 0,0:17:32.75,0:17:38.57,EN,,0,0,0,,his cons-stream of 1 onto the element-wise sum Dialogue: 0,0:17:40.22,0:17:48.27,EN,,0,0,0,,onto add streams of the integers to ones. Dialogue: 0,0:17:55.10,0:17:56.35,EN,,0,0,0,,The integers are a thing Dialogue: 0,0:17:57.24,0:17:59.98,EN,,0,0,0,,whose first element is 1, Dialogue: 0,0:18:00.88,0:18:02.32,EN,,0,0,0,,and the rest of them you get Dialogue: 0,0:18:03.12,0:18:06.14,EN,,0,0,0,,by taking those integers and incrementing each one by one. Dialogue: 0,0:18:06.64,0:18:08.19,EN,,0,0,0,,So the second element of the integers Dialogue: 0,0:18:08.51,0:18:11.96,EN,,0,0,0,,is the first element of the integers incremented by one. Dialogue: 0,0:18:13.92,0:18:15.18,EN,,0,0,0,,And the rest of that is the next one, Dialogue: 0,0:18:15.20,0:18:16.48,EN,,0,0,0,,and the third element of that Dialogue: 0,0:18:16.62,0:18:20.41,EN,,0,0,0,,is the same as the first element of the tail of the integers Dialogue: 0,0:18:20.84,0:18:21.96,EN,,0,0,0,,incremented by one, Dialogue: 0,0:18:22.51,0:18:23.76,EN,,0,0,0,,which is the same as the Dialogue: 0,0:18:25.08,0:18:28.65,EN,,0,0,0,,first element of the original integers incremented by one Dialogue: 0,0:18:28.86,0:18:31.25,EN,,0,0,0,,and incremented by one again and so on. Dialogue: 0,0:18:35.24,0:18:36.31,EN,,0,0,0,,That looks pretty suspicious. Dialogue: 0,0:18:36.31,0:18:37.47,EN,,0,0,0,,See, notice that it works Dialogue: 0,0:18:38.12,0:18:38.99,EN,,0,0,0,,because of delay. Dialogue: 0,0:18:40.15,0:18:43.32,EN,,0,0,0,,See, this looks like-- let's take a look at ones. Dialogue: 0,0:18:43.87,0:18:45.92,EN,,0,0,0,,This looks like it couldn't even be processed Dialogue: 0,0:18:46.25,0:18:47.63,EN,,0,0,0,,because it's suddenly saying Dialogue: 0,0:18:47.79,0:18:48.96,EN,,0,0,0,,in order to know what ones is, Dialogue: 0,0:18:49.00,0:18:50.91,EN,,0,0,0,,I say it's cons-stream of something onto ones. Dialogue: 0,0:18:51.13,0:18:52.08,EN,,0,0,0,,The reason that works Dialogue: 0,0:18:52.09,0:18:54.04,EN,,0,0,0,,because of that very sneaky hidden delay in there. Dialogue: 0,0:18:55.25,0:18:56.56,EN,,0,0,0,,Because what this really is, Dialogue: 0,0:18:57.79,0:18:59.69,EN,,0,0,0,,remember, cons-stream is just an abbreviation. Dialogue: 0,0:19:00.29,0:19:01.15,EN,,0,0,0,,This really is Dialogue: 0,0:19:01.85,0:19:08.99,EN,,0,0,0,,cons of 1 onto delay of ones. Dialogue: 0,0:19:12.14,0:19:13.21,EN,,0,0,0,,So how does that work? Dialogue: 0,0:19:15.50,0:19:16.88,EN,,0,0,0,,You say I'm going to define ones. Dialogue: 0,0:19:18.02,0:19:20.24,EN,,0,0,0,,First I see what ones is supposed to be defined as. Dialogue: 0,0:19:20.70,0:19:23.40,EN,,0,0,0,,Well, ones is supposed to be defined as Dialogue: 0,0:19:24.89,0:19:28.11,EN,,0,0,0,,a cons whose first part is 1 Dialogue: 0,0:19:28.32,0:19:29.45,EN,,0,0,0,,and the second part is, Dialogue: 0,0:19:29.45,0:19:30.73,EN,,0,0,0,,well, it's a promise to compute something Dialogue: 0,0:19:30.75,0:19:31.69,EN,,0,0,0,,that I don't worry about yet. Dialogue: 0,0:19:32.71,0:19:34.25,EN,,0,0,0,,So it doesn't bother me that at the point Dialogue: 0,0:19:34.28,0:19:36.30,EN,,0,0,0,,I do this definition, ones isn't defined. Dialogue: 0,0:19:37.27,0:19:39.45,EN,,0,0,0,,Having run the definition, now ones is defined. Dialogue: 0,0:19:40.67,0:19:42.83,EN,,0,0,0,,So that when I go and look at the tail of it, it's defined. Dialogue: 0,0:19:44.92,0:19:46.06,EN,,0,0,0,,It's very sneaky. Dialogue: 0,0:19:46.59,0:19:47.90,EN,,0,0,0,,And an integer is the same way. Dialogue: 0,0:19:48.47,0:19:50.46,EN,,0,0,0,,I can refer to integers here because Dialogue: 0,0:19:51.13,0:19:53.21,EN,,0,0,0,,hidden way down-- because of this cons-stream. Dialogue: 0,0:19:53.85,0:19:55.24,EN,,0,0,0,,It's the cons-stream of 1 Dialogue: 0,0:19:55.37,0:19:57.05,EN,,0,0,0,,onto something that I don't worry that yet. Dialogue: 0,0:19:57.05,0:19:59.60,EN,,0,0,0,,So I don't look at it, and I don't notice that integers isn't defined Dialogue: 0,0:20:00.22,0:20:01.90,EN,,0,0,0,,at the point where I try and run the definition. Dialogue: 0,0:20:06.32,0:20:08.27,EN,,0,0,0,,OK, let me draw a picture of that integers thing Dialogue: 0,0:20:08.44,0:20:11.50,EN,,0,0,0,,because it still maybe seems a little bit shaky. Dialogue: 0,0:20:12.43,0:20:14.72,EN,,0,0,0,,What do I do? Uh... Dialogue: 0,0:20:15.02,0:20:16.30,EN,,0,0,0,,I've got the stream of ones, Dialogue: 0,0:20:20.51,0:20:21.88,EN,,0,0,0,,and that sort of comes in Dialogue: 0,0:20:23.26,0:20:24.92,EN,,0,0,0,,comes in and goes into an adder Dialogue: 0,0:20:24.96,0:20:26.59,EN,,0,0,0,,that's going to be this add streams thing. Dialogue: 0,0:20:29.31,0:20:35.87,EN,,0,0,0,,And that goes in-- that's going to put out the integers. Dialogue: 0,0:20:40.76,0:20:42.70,EN,,0,0,0,,And the other thing that goes into the adder here Dialogue: 0,0:20:44.94,0:20:46.97,EN,,0,0,0,,is the integer, so there's a little feedback loop. Dialogue: 0,0:20:48.06,0:20:49.42,EN,,0,0,0,,And all I need to start it off Dialogue: 0,0:20:50.09,0:20:52.88,EN,,0,0,0,,is someplace I've got a stick that initial 1. Dialogue: 0,0:20:57.10,0:20:58.64,EN,,0,0,0,,In a real signal processing thing, Dialogue: 0,0:20:58.72,0:21:02.48,EN,,0,0,0,,this might be a delay element with that was initialized to 1. Dialogue: 0,0:21:02.91,0:21:05.90,EN,,0,0,0,,But there's a picture of that ones program. Dialogue: 0,0:21:07.86,0:21:09.63,EN,,0,0,0,,And in fact, that looks a lot like-- Dialogue: 0,0:21:09.80,0:21:13.77,EN,,0,0,0,,if you've seen real signal block diagram things, Dialogue: 0,0:21:13.77,0:21:16.30,EN,,0,0,0,,that looks a lot like accumulators, Dialogue: 0,0:21:16.35,0:21:17.48,EN,,0,0,0,,finite state accumulators. Dialogue: 0,0:21:17.98,0:21:20.06,EN,,0,0,0,,And in fact, we can modify this a little bit Dialogue: 0,0:21:21.18,0:21:23.96,EN,,0,0,0,,to change this into something that integrates a stream Dialogue: 0,0:21:25.37,0:21:26.97,EN,,0,0,0,,or a finite state accumulator, Dialogue: 0,0:21:27.00,0:21:28.04,EN,,0,0,0,,however you like to think about it. Dialogue: 0,0:21:28.44,0:21:30.86,EN,,0,0,0,,So instead of the ones coming in and getting out the integers, Dialogue: 0,0:21:31.68,0:21:32.38,EN,,0,0,0,,what we'll do is Dialogue: 0,0:21:32.91,0:21:34.83,EN,,0,0,0,,say there's a stream s coming in, Dialogue: 0,0:21:35.76,0:21:40.56,EN,,0,0,0,,and we're going to get out the integral of this. Dialogue: 0,0:21:42.60,0:21:44.09,EN,,0,0,0,,successive values of that, Dialogue: 0,0:21:44.44,0:21:45.63,EN,,0,0,0,,and it looks almost the same. Dialogue: 0,0:21:45.66,0:21:46.84,EN,,0,0,0,,The only thing we're going to do is Dialogue: 0,0:21:47.02,0:21:48.08,EN,,0,0,0,,when s comes in here, Dialogue: 0,0:21:49.21,0:21:50.64,EN,,0,0,0,,before we just add it in Dialogue: 0,0:21:50.91,0:21:54.26,EN,,0,0,0,,we're going to multiply it by some number dt. Dialogue: 0,0:21:57.68,0:22:00.00,EN,,0,0,0,,And now what we have here, this is exactly the same thing. Dialogue: 0,0:22:00.00,0:22:00.91,EN,,0,0,0,,We have a box, Dialogue: 0,0:22:03.36,0:22:04.56,EN,,0,0,0,,which is an integrator. Dialogue: 0,0:22:09.79,0:22:11.26,EN,,0,0,0,,And it takes in a stream s, Dialogue: 0,0:22:11.90,0:22:14.51,EN,,0,0,0,,and instead of 1 here, Dialogue: 0,0:22:14.94,0:22:18.35,EN,,0,0,0,,we can put the additional value for the integral. Dialogue: 0,0:22:19.98,0:22:21.60,EN,,0,0,0,,And that one looks very much like a Dialogue: 0,0:22:22.35,0:22:24.86,EN,,0,0,0,,a signal processing block diagram program. Dialogue: 0,0:22:25.27,0:22:28.11,EN,,0,0,0,,In fact, here's the procedure that looks exactly like that. Dialogue: 0,0:22:31.49,0:22:33.61,EN,,0,0,0,,Find the integral of a stream. Dialogue: 0,0:22:34.01,0:22:35.48,EN,,0,0,0,,So an integral's going to take a stream Dialogue: 0,0:22:35.68,0:22:36.86,EN,,0,0,0,,Sand produce a new stream, Dialogue: 0,0:22:37.53,0:22:40.67,EN,,0,0,0,,and it takes in an initial value and some time constant. Dialogue: 0,0:22:42.23,0:22:42.97,EN,,0,0,0,,And what do we do? Dialogue: 0,0:22:43.04,0:22:45.05,EN,,0,0,0,,Well, we internally define this thing int, Dialogue: 0,0:22:45.20,0:22:46.32,EN,,0,0,0,,and we make this internal name Dialogue: 0,0:22:46.33,0:22:48.86,EN,,0,0,0,,so we can feed it back, loop it around itself. Dialogue: 0,0:22:49.40,0:22:50.80,EN,,0,0,0,,And int is defined to be Dialogue: 0,0:22:51.10,0:22:53.32,EN,,0,0,0,,something that starts out at the initial value, Dialogue: 0,0:22:54.97,0:23:00.14,EN,,0,0,0,,and the rest of it is gotten by adding together. Dialogue: 0,0:23:01.28,0:23:03.61,EN,,0,0,0,,We take our input stream, scale it by dt, Dialogue: 0,0:23:03.87,0:23:04.92,EN,,0,0,0,,and add that to int. Dialogue: 0,0:23:06.88,0:23:09.66,EN,,0,0,0,,And now we'll return from all that the value of integral is this thing int. Dialogue: 0,0:23:10.69,0:23:12.94,EN,,0,0,0,,And we use this internal definition syntax so we could Dialogue: 0,0:23:13.34,0:23:15.66,EN,,0,0,0,,write a little internal definition that refers to itself. Dialogue: 0,0:23:21.88,0:23:23.71,EN,,0,0,0,,Well, there are all sorts of things we can do. Dialogue: 0,0:23:23.71,0:23:24.51,EN,,0,0,0,,Let's try this one. Dialogue: 0,0:23:25.63,0:23:26.89,EN,,0,0,0,,how about the Fibonacci numbers. Dialogue: 0,0:23:26.89,0:23:32.62,EN,,0,0,0,,You can say define fibs. Dialogue: 0,0:23:36.35,0:23:37.63,EN,,0,0,0,,Well, what are the Fibonacci numbers? Dialogue: 0,0:23:37.98,0:23:46.54,EN,,0,0,0,,They're something that starts out with 0, Dialogue: 0,0:23:48.65,0:23:50.09,EN,,0,0,0,,and the next one is 1. Dialogue: 0,0:23:56.26,0:23:59.16,EN,,0,0,0,,And the rest of the Fibonacci numbers are gotten by Dialogue: 0,0:23:59.87,0:24:11.00,EN,,0,0,0,,adding the Fibonacci numbers to their own tail. Dialogue: 0,0:24:17.57,0:24:19.28,EN,,0,0,0,,There's a definition of the Fibonacci numbers. Dialogue: 0,0:24:20.58,0:24:21.43,EN,,0,0,0,,How does that work? Dialogue: 0,0:24:21.43,0:24:24.19,EN,,0,0,0,,Well, we start off, Dialogue: 0,0:24:24.20,0:24:26.49,EN,,0,0,0,,and someone says compute for us the Fibonacci numbers, Dialogue: 0,0:24:29.64,0:24:31.92,EN,,0,0,0,,and we're going to tell you it starts out with 0 and 1. Dialogue: 0,0:24:35.79,0:24:38.22,EN,,0,0,0,,And everything after the 0 and 1 Dialogue: 0,0:24:39.18,0:24:40.86,EN,,0,0,0,,is gotten by summing two streams. Dialogue: 0,0:24:41.12,0:24:42.59,EN,,0,0,0,,One is the fibs themselves, Dialogue: 0,0:24:44.06,0:24:45.69,EN,,0,0,0,,and the other one is the tail of the fibs. Dialogue: 0,0:24:49.12,0:24:51.16,EN,,0,0,0,,So if I know that these start out with 0 and 1, Dialogue: 0,0:24:51.79,0:24:55.42,EN,,0,0,0,,I know that the fibs now start out with 0 and 1, Dialogue: 0,0:24:55.74,0:24:57.40,EN,,0,0,0,,and the tail of the fibs start out with 1. Dialogue: 0,0:24:58.36,0:24:59.45,EN,,0,0,0,,So as soon as I know that, Dialogue: 0,0:24:59.66,0:25:02.11,EN,,0,0,0,,I know that the next one here is 0 plus 1 is 1, Dialogue: 0,0:25:02.96,0:25:04.60,EN,,0,0,0,,and that tells me that the next one here is 1 Dialogue: 0,0:25:04.62,0:25:05.72,EN,,0,0,0,,and the next one here is 1. Dialogue: 0,0:25:06.30,0:25:07.28,EN,,0,0,0,,And as soon as I know that, Dialogue: 0,0:25:07.29,0:25:08.76,EN,,0,0,0,,I know that the next one is 2. Dialogue: 0,0:25:09.39,0:25:11.70,EN,,0,0,0,,So the next one here is 2 and the next one here is 2. Dialogue: 0,0:25:11.70,0:25:12.56,EN,,0,0,0,,And this is 3. Dialogue: 0,0:25:14.72,0:25:15.79,EN,,0,0,0,,This one goes to 3, Dialogue: 0,0:25:16.19,0:25:17.13,EN,,0,0,0,,and this is 5. Dialogue: 0,0:25:18.67,0:25:19.96,EN,,0,0,0,,So it's a perfectly sensible definition. Dialogue: 0,0:25:21.50,0:25:22.78,EN,,0,0,0,,It's a one-line definition. Dialogue: 0,0:25:22.83,0:25:25.00,EN,,0,0,0,,And again, I could walk over to the computer Dialogue: 0,0:25:25.00,0:25:26.62,EN,,0,0,0,,and type that in, exactly that, Dialogue: 0,0:25:27.04,0:25:28.94,EN,,0,0,0,,and then say print stream the Fibonacci numbers, Dialogue: 0,0:25:28.94,0:25:30.15,EN,,0,0,0,,and they all come flying out. Dialogue: 0,0:25:32.79,0:25:35.20,EN,,0,0,0,,See, this is a lot like learning about recursion again. Dialogue: 0,0:25:36.81,0:25:39.79,EN,,0,0,0,,Instead of thinking that recursive procedures, Dialogue: 0,0:25:40.99,0:25:43.50,EN,,0,0,0,,we have recursively defined data objects. Dialogue: 0,0:25:45.16,0:25:46.92,EN,,0,0,0,,But that shouldn't surprise you at all, Dialogue: 0,0:25:47.12,0:25:49.50,EN,,0,0,0,,because by now, you should be coming to really believe Dialogue: 0,0:25:49.52,0:25:53.05,EN,,0,0,0,,that there's no difference really between procedures and data. Dialogue: 0,0:25:53.09,0:25:53.92,EN,,0,0,0,,In fact, in some sense, Dialogue: 0,0:25:53.93,0:25:56.41,EN,,0,0,0,,the underlying streams are procedures sitting there, Dialogue: 0,0:25:56.43,0:25:57.79,EN,,0,0,0,,although we don't think of them that way. Dialogue: 0,0:25:58.21,0:26:00.38,EN,,0,0,0,,So the fact that we have recursive procedures, Dialogue: 0,0:26:00.70,0:26:03.63,EN,,0,0,0,,well, then it should be natural that we have recursive data, too. Dialogue: 0,0:26:07.72,0:26:09.69,EN,,0,0,0,,OK, well, this is all pretty neat. Dialogue: 0,0:26:09.72,0:26:13.92,EN,,0,0,0,,Unfortunately, there are problems that streams aren't going to solve. Dialogue: 0,0:26:14.99,0:26:16.48,EN,,0,0,0,,Let me show you one of them. Dialogue: 0,0:26:17.58,0:26:20.35,EN,,0,0,0,,See, in the same way, let's imagine that we're Dialogue: 0,0:26:20.76,0:26:23.61,EN,,0,0,0,,building an analog computer to solve some differential equation Dialogue: 0,0:26:25.20,0:26:34.30,EN,,0,0,0,,like, say, we want to solve the equation y prime dy dt is y squared, Dialogue: 0,0:26:34.76,0:26:36.16,EN,,0,0,0,,and I'm going to give you some initial value. Dialogue: 0,0:26:36.39,0:26:38.03,EN,,0,0,0,,I'll tell you y of 0 equals 1. Dialogue: 0,0:26:41.48,0:26:44.06,EN,,0,0,0,,Let's say dt is equal to something. Dialogue: 0,0:26:46.77,0:26:47.53,EN,,0,0,0,,Now, in the old days, Dialogue: 0,0:26:48.00,0:26:50.65,EN,,0,0,0,,people built analog computers to solve these kinds of things. Dialogue: 0,0:26:51.36,0:26:53.02,EN,,0,0,0,,And the way you do that is really simple. Dialogue: 0,0:26:53.02,0:26:54.41,EN,,0,0,0,,You get yourself an integrator, Dialogue: 0,0:27:00.04,0:27:01.69,EN,,0,0,0,,like that one, an integrator box. Dialogue: 0,0:27:03.05,0:27:06.48,EN,,0,0,0,,And we put in the initial value y of 0 is 1. Dialogue: 0,0:27:08.53,0:27:10.92,EN,,0,0,0,,And now if we feed something in and get something out, Dialogue: 0,0:27:10.96,0:27:13.16,EN,,0,0,0,,we'll say, gee, what we're getting out is the answer. Dialogue: 0,0:27:14.25,0:27:16.96,EN,,0,0,0,,And what we're going to feed in is the derivative, Dialogue: 0,0:27:17.52,0:27:20.52,EN,,0,0,0,,and the derivative is supposed to be the square of the answer. Dialogue: 0,0:27:21.49,0:27:27.07,EN,,0,0,0,,So if we take these values and map using square, Dialogue: 0,0:27:30.73,0:27:32.09,EN,,0,0,0,,and if I feed this around, Dialogue: 0,0:27:36.28,0:27:38.48,EN,,0,0,0,,that's how I build a block diagram Dialogue: 0,0:27:38.57,0:27:41.08,EN,,0,0,0,,for an analog computer that solves this differential equation. Dialogue: 0,0:27:42.91,0:27:44.80,EN,,0,0,0,,Now, what we'd like to do is write a stream Dialogue: 0,0:27:44.80,0:27:46.78,EN,,0,0,0,,program that looks exactly like that. Dialogue: 0,0:27:47.23,0:27:48.72,EN,,0,0,0,,And what do I mean exactly like that? Dialogue: 0,0:27:49.39,0:27:58.30,EN,,0,0,0,,Well, I'd say define y to be the integral Dialogue: 0,0:28:04.28,0:28:11.68,EN,,0,0,0,,of dy starting at 1 with 0.001 as a time step. Dialogue: 0,0:28:13.79,0:28:15.45,EN,,0,0,0,,And I'd like to say that says this. Dialogue: 0,0:28:16.80,0:28:20.85,EN,,0,0,0,,And then I'd like to say, well, dy is gotten by mapping the square along y. Dialogue: 0,0:28:20.85,0:28:32.81,EN,,0,0,0,,So define dy to be map square along y. Dialogue: 0,0:28:33.51,0:28:36.80,EN,,0,0,0,,So there's a stream description of this analog computer, Dialogue: 0,0:28:38.62,0:28:40.32,EN,,0,0,0,,and unfortunately, it doesn't work. Dialogue: 0,0:28:41.41,0:28:42.67,EN,,0,0,0,,And you can see why it doesn't work Dialogue: 0,0:28:42.97,0:28:44.99,EN,,0,0,0,,because when I come in and say define y Dialogue: 0,0:28:46.43,0:28:47.85,EN,,0,0,0,,to be the integral of dy Dialogue: 0,0:28:49.04,0:28:50.65,EN,,0,0,0,,it says, oh, the integral of what-- huh? Dialogue: 0,0:28:51.19,0:28:52.12,EN,,0,0,0,,Oh, that's undefined. Dialogue: 0,0:28:53.71,0:28:57.63,EN,,0,0,0,,So I can't write this definition before I've written this one. Dialogue: 0,0:28:58.77,0:29:00.51,EN,,0,0,0,,On the other hand, if I try and write this one first, Dialogue: 0,0:29:00.51,0:29:03.02,EN,,0,0,0,,it says, oh, I define y to be the map of square along what? Dialogue: 0,0:29:03.58,0:29:04.64,EN,,0,0,0,,Oh, that's not defined yet. Dialogue: 0,0:29:05.77,0:29:08.17,EN,,0,0,0,,So I can't write this one first, and I can't write that one first. Dialogue: 0,0:29:09.08,0:29:11.58,EN,,0,0,0,,So I can't quite play this game. Dialogue: 0,0:29:17.56,0:29:18.51,EN,,0,0,0,,Well, is there a way out? Dialogue: 0,0:29:20.60,0:29:21.84,EN,,0,0,0,,See, we can do that with ones. Dialogue: 0,0:29:22.20,0:29:25.82,EN,,0,0,0,,See, over here, we did this thing ones, Dialogue: 0,0:29:27.24,0:29:29.90,EN,,0,0,0,,and we were able to define ones in terms of ones because Dialogue: 0,0:29:30.40,0:29:32.03,EN,,0,0,0,,of this delay that was built inside Dialogue: 0,0:29:32.43,0:29:34.12,EN,,0,0,0,,because cons-stream had a delay. Dialogue: 0,0:29:34.77,0:29:35.79,EN,,0,0,0,,Now, why's it sensible? Dialogue: 0,0:29:35.92,0:29:38.51,EN,,0,0,0,,Why's it sensible for cons-stream to be built with this delay? Dialogue: 0,0:29:40.73,0:29:43.13,EN,,0,0,0,,The reason is that cons-stream can do a useful thing Dialogue: 0,0:29:43.48,0:29:44.88,EN,,0,0,0,,without looking at its tail. Dialogue: 0,0:29:45.95,0:29:46.84,EN,,0,0,0,,See, if I say Dialogue: 0,0:29:47.48,0:29:49.64,EN,,0,0,0,,this is cons-stream of 1 onto something Dialogue: 0,0:29:49.92,0:29:51.69,EN,,0,0,0,,without knowing anything about something, Dialogue: 0,0:29:52.16,0:29:54.03,EN,,0,0,0,,I know that the stream starts off with 1. Dialogue: 0,0:29:54.87,0:29:57.29,EN,,0,0,0,,That's why it was sensible to build something like cons-stream. Dialogue: 0,0:29:59.96,0:30:01.24,EN,,0,0,0,,So we put a delay in there, Dialogue: 0,0:30:01.42,0:30:04.65,EN,,0,0,0,,and that allows us to have this sort of self-referential definition. Dialogue: 0,0:30:06.32,0:30:07.95,EN,,0,0,0,,Well, integral is a little bit the same way. Dialogue: 0,0:30:08.19,0:30:12.52,EN,,0,0,0,,See, notice for an integral, I can-- Dialogue: 0,0:30:14.60,0:30:16.08,EN,,0,0,0,,let's go back and look at integral for a second. Dialogue: 0,0:30:17.58,0:30:18.56,EN,,0,0,0,,See, notice integral, Dialogue: 0,0:30:21.39,0:30:25.00,EN,,0,0,0,,it makes sense to say what's the first thing in the integral Dialogue: 0,0:30:26.04,0:30:27.87,EN,,0,0,0,,without knowing the stream that you're integrating. Dialogue: 0,0:30:28.97,0:30:30.17,EN,,0,0,0,,Because the first thing in the integral Dialogue: 0,0:30:30.20,0:30:32.16,EN,,0,0,0,,is always going to be the initial value that you're handed. Dialogue: 0,0:30:33.14,0:30:36.11,EN,,0,0,0,,So integral could be a procedure like cons-stream. Dialogue: 0,0:30:37.09,0:30:37.98,EN,,0,0,0,,You could define it, Dialogue: 0,0:30:38.25,0:30:40.88,EN,,0,0,0,,and then even before it knows what it's supposed to be integrating, Dialogue: 0,0:30:42.84,0:30:45.18,EN,,0,0,0,,it knows enough to say what its initial value is. Dialogue: 0,0:30:46.71,0:30:48.17,EN,,0,0,0,,So we can make a smarter integral, Dialogue: 0,0:30:48.41,0:30:50.68,EN,,0,0,0,,which is aha, you're going to give me a stream to integrate Dialogue: 0,0:30:50.83,0:30:51.92,EN,,0,0,0,,and an initial value, Dialogue: 0,0:30:52.11,0:30:54.99,EN,,0,0,0,,but I really don't have to look at that stream that I'm supposed to integrate Dialogue: 0,0:30:55.21,0:30:56.97,EN,,0,0,0,,until you ask me to work down the stream. Dialogue: 0,0:30:58.43,0:31:00.51,EN,,0,0,0,,In other words, integral can be like cons-stream, Dialogue: 0,0:31:00.57,0:31:03.74,EN,,0,0,0,,and you can expect that there's going to be a delay around its integrand. Dialogue: 0,0:31:03.76,0:31:04.86,EN,,0,0,0,,And we can write that. Dialogue: 0,0:31:05.61,0:31:07.02,EN,,0,0,0,,Here's a procedure that does that. Dialogue: 0,0:31:07.65,0:31:08.75,EN,,0,0,0,,Another version of integral, Dialogue: 0,0:31:08.89,0:31:10.54,EN,,0,0,0,,and this is almost like the previous one, Dialogue: 0,0:31:11.10,0:31:13.34,EN,,0,0,0,,except the stream it's going to get in Dialogue: 0,0:31:13.77,0:31:15.69,EN,,0,0,0,,is going to expect to be a delayed object. Dialogue: 0,0:31:17.11,0:31:18.43,EN,,0,0,0,,And how does this integral work? Dialogue: 0,0:31:18.85,0:31:21.79,EN,,0,0,0,,Well, the little thing it's going to define inside of itself Dialogue: 0,0:31:22.14,0:31:24.19,EN,,0,0,0,,says on the cons-stream, Dialogue: 0,0:31:24.73,0:31:26.44,EN,,0,0,0,,the initial value is the initial value, Dialogue: 0,0:31:27.16,0:31:29.68,EN,,0,0,0,,but only inside of that cons-stream, Dialogue: 0,0:31:29.74,0:31:32.30,EN,,0,0,0,,and remember, there's going to be a hidden delay inside here. Dialogue: 0,0:31:34.95,0:31:39.07,EN,,0,0,0,,Only inside of that cons-stream will I start looking at Dialogue: 0,0:31:39.82,0:31:42.11,EN,,0,0,0,,what the actual delayed object is. Dialogue: 0,0:31:43.18,0:31:45.79,EN,,0,0,0,,So my answer is the first thing's the initial value. Dialogue: 0,0:31:45.97,0:31:47.90,EN,,0,0,0,,If anybody now asks me for my tail, Dialogue: 0,0:31:48.40,0:31:49.42,EN,,0,0,0,,at that point, Dialogue: 0,0:31:50.00,0:31:51.72,EN,,0,0,0,,I'm going to force that delayed object-- Dialogue: 0,0:31:52.62,0:31:53.60,EN,,0,0,0,,and I'll call that s-- Dialogue: 0,0:31:54.44,0:31:55.60,EN,,0,0,0,,and I do the add streams. Dialogue: 0,0:31:56.36,0:31:59.26,EN,,0,0,0,,So this is an integral which is sort of like cons-stream. Dialogue: 0,0:31:59.26,0:32:02.59,EN,,0,0,0,,It's not going to actually try and see what you handed it Dialogue: 0,0:32:03.88,0:32:07.13,EN,,0,0,0,,as the thing to integrate until you look past the first element. Dialogue: 0,0:32:10.12,0:32:11.02,EN,,0,0,0,,And if we do that Dialogue: 0,0:32:11.52,0:32:12.83,EN,,0,0,0,,and we can make this work, Dialogue: 0,0:32:13.36,0:32:15.20,EN,,0,0,0,,all we have to do here is Dialogue: 0,0:32:16.00,0:32:25.31,EN,,0,0,0,,define y to the integral of delay of y, of delay of dy. Dialogue: 0,0:32:27.09,0:32:28.22,EN,,0,0,0,,So y is going to be Dialogue: 0,0:32:28.40,0:32:34.36,EN,,0,0,0,,the integral of delay of dy starting at 1, Dialogue: 0,0:32:34.38,0:32:35.13,EN,,0,0,0,,and now this will work. Dialogue: 0,0:32:35.28,0:32:37.44,EN,,0,0,0,,Because I type in the definition of y, Dialogue: 0,0:32:38.00,0:32:39.68,EN,,0,0,0,,and that says, oh, I'm supposed to use the integral of Dialogue: 0,0:32:40.20,0:32:42.68,EN,,0,0,0,,something I don't care about right now because it's a delay. Dialogue: 0,0:32:44.60,0:32:46.32,EN,,0,0,0,,And these things, now you define dy. Dialogue: 0,0:32:46.32,0:32:47.37,EN,,0,0,0,,Now, y is defined. Dialogue: 0,0:32:47.55,0:32:48.89,EN,,0,0,0,,So when I define dy, Dialogue: 0,0:32:49.13,0:32:50.67,EN,,0,0,0,,it can see that definition for y. Dialogue: 0,0:32:51.70,0:32:52.84,EN,,0,0,0,,Everything is now started up. Dialogue: 0,0:32:52.84,0:32:54.33,EN,,0,0,0,,Both streams have their first element. Dialogue: 0,0:32:54.92,0:32:56.25,EN,,0,0,0,,And then when I start mapping down, Dialogue: 0,0:32:56.27,0:32:57.31,EN,,0,0,0,,looking at successive elements, Dialogue: 0,0:32:57.37,0:32:58.88,EN,,0,0,0,,both y and dy are defined. Dialogue: 0,0:33:00.59,0:33:04.24,EN,,0,0,0,,So there's a little game you can play that goes a little bit beyond Dialogue: 0,0:33:04.67,0:33:07.13,EN,,0,0,0,,just using the delay that's hidden inside streams. Dialogue: 0,0:33:08.36,0:33:08.97,EN,,0,0,0,,Questions? Dialogue: 0,0:33:13.52,0:33:14.27,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:34:07.30,0:34:10.04,EN,,0,0,0,,Well, just before the break, um.. Dialogue: 0,0:34:10.89,0:34:11.80,EN,,0,0,0,,I'm not sure if you noticed it, Dialogue: 0,0:34:11.82,0:34:13.55,EN,,0,0,0,,but something nasty started to happen. Dialogue: 0,0:34:14.83,0:34:18.40,EN,,0,0,0,,We've been going along with the streams Dialogue: 0,0:34:19.16,0:34:22.68,EN,,0,0,0,,and divorcing time in the programs from time in the computers, Dialogue: 0,0:34:22.86,0:34:26.28,EN,,0,0,0,,and all that divorcing got hidden inside the streams. Dialogue: 0,0:34:27.28,0:34:29.50,EN,,0,0,0,,And then at the very end, we saw that sometimes Dialogue: 0,0:34:29.71,0:34:32.19,EN,,0,0,0,,in order to really take advantage of this method, Dialogue: 0,0:34:32.22,0:34:34.38,EN,,0,0,0,,you have to pull out other delays. Dialogue: 0,0:34:34.38,0:34:35.85,EN,,0,0,0,,You have to write some explicit delays Dialogue: 0,0:34:36.09,0:34:37.95,EN,,0,0,0,,that are not hidden inside that cons-stream. Dialogue: 0,0:34:39.03,0:34:41.88,EN,,0,0,0,,And I did a very simple example with differential equations, Dialogue: 0,0:34:42.35,0:34:44.08,EN,,0,0,0,,but if you have some very complicated system Dialogue: 0,0:34:44.12,0:34:45.40,EN,,0,0,0,,with all kinds of self-loops, Dialogue: 0,0:34:45.95,0:34:47.84,EN,,0,0,0,,it becomes very, very difficult to Dialogue: 0,0:34:47.90,0:34:49.31,EN,,0,0,0,,see where you need those delays. Dialogue: 0,0:34:49.92,0:34:51.18,EN,,0,0,0,,And if you leave them out by mistake, Dialogue: 0,0:34:51.45,0:34:54.36,EN,,0,0,0,,it becomes very, very difficult to see why the thing maybe isn't working. Dialogue: 0,0:34:55.55,0:34:57.15,EN,,0,0,0,,So that's kind of mess, Dialogue: 0,0:34:57.79,0:35:01.71,EN,,0,0,0,,that by getting this power and allowing us to use delay, Dialogue: 0,0:35:02.08,0:35:04.70,EN,,0,0,0,,we end up with some very complicated programming sometimes, Dialogue: 0,0:35:04.72,0:35:06.80,EN,,0,0,0,,because it can't all be hidden inside the streams. Dialogue: 0,0:35:08.51,0:35:09.79,EN,,0,0,0,,Well, is there a way out of that? Dialogue: 0,0:35:11.13,0:35:12.67,EN,,0,0,0,,Yeah, there is a way out of that. Dialogue: 0,0:35:13.48,0:35:16.08,EN,,0,0,0,,We could change the language so that Dialogue: 0,0:35:16.14,0:35:18.19,EN,,0,0,0,,all procedures acted like cons-stream, Dialogue: 0,0:35:19.10,0:35:21.48,EN,,0,0,0,,so that every procedure automatically Dialogue: 0,0:35:22.32,0:35:25.45,EN,,0,0,0,,has an implicit delay around its arguments. Dialogue: 0,0:35:25.45,0:35:26.43,EN,,0,0,0,,And what would that mean? Dialogue: 0,0:35:27.52,0:35:29.53,EN,,0,0,0,,That would mean when you call a procedure, Dialogue: 0,0:35:30.16,0:35:31.88,EN,,0,0,0,,the arguments wouldn't get evaluated. Dialogue: 0,0:35:32.21,0:35:34.70,EN,,0,0,0,,Instead, they'd only be evaluated when you need them, Dialogue: 0,0:35:34.89,0:35:36.72,EN,,0,0,0,,so they might be passed off to some other procedure, Dialogue: 0,0:35:36.76,0:35:38.12,EN,,0,0,0,,which wouldn't evaluate them either. Dialogue: 0,0:35:39.26,0:35:41.90,EN,,0,0,0,,So all these procedures would be passing promises around. Dialogue: 0,0:35:42.15,0:35:44.46,EN,,0,0,0,,And then finally maybe when you finally got down Dialogue: 0,0:35:44.65,0:35:47.34,EN,,0,0,0,,to having to look at the value of something Dialogue: 0,0:35:47.36,0:35:48.99,EN,,0,0,0,,that was handed to a primitive operator Dialogue: 0,0:35:49.37,0:35:51.48,EN,,0,0,0,,which you actually start calling in all those promises. Dialogue: 0,0:35:52.38,0:35:53.16,EN,,0,0,0,,If we did that, Dialogue: 0,0:35:53.36,0:35:55.37,EN,,0,0,0,,since everything would have a uniform delay, Dialogue: 0,0:35:57.16,0:35:59.00,EN,,0,0,0,,then you wouldn't have to write any explicit delays, Dialogue: 0,0:35:59.04,0:36:01.55,EN,,0,0,0,,because it would be automatically built into the way the language works. Dialogue: 0,0:36:03.24,0:36:04.38,EN,,0,0,0,,Or another way to say that, Dialogue: 0,0:36:05.10,0:36:08.14,EN,,0,0,0,,technically what I'm describing is what's called Dialogue: 0,0:36:09.02,0:36:10.76,EN,,0,0,0,,if we did that, our language would be Dialogue: 0,0:36:12.19,0:36:16.57,EN,,0,0,0,,so-called normal-order evaluation language Dialogue: 0,0:36:20.20,0:36:23.47,EN,,0,0,0,,versus what we've actually been working with, Dialogue: 0,0:36:23.87,0:36:33.79,EN,,0,0,0,,which is called applicative order-- versus applicative-order evaluation. Dialogue: 0,0:36:34.56,0:36:36.83,EN,,0,0,0,,And remember the substitution model for applicative order. Dialogue: 0,0:36:36.83,0:36:40.49,EN,,0,0,0,,It says when you go and evaluate a combination, Dialogue: 0,0:36:40.51,0:36:42.11,EN,,0,0,0,,you find the values of all the pieces. Dialogue: 0,0:36:43.59,0:36:45.40,EN,,0,0,0,,You evaluate the arguments and then you Dialogue: 0,0:36:45.72,0:36:47.42,EN,,0,0,0,,substitute them in the body of the procedure. Dialogue: 0,0:36:47.60,0:36:49.55,EN,,0,0,0,,Normal order says no, don't do that. Dialogue: 0,0:36:49.89,0:36:51.90,EN,,0,0,0,,What you do is effectively Dialogue: 0,0:36:52.76,0:36:54.41,EN,,0,0,0,,substitute in the body of the procedure, Dialogue: 0,0:36:54.44,0:36:56.19,EN,,0,0,0,,but instead of evaluating the arguments, Dialogue: 0,0:36:56.54,0:36:58.08,EN,,0,0,0,,you just put a promise to compute them there. Dialogue: 0,0:36:58.81,0:36:59.90,EN,,0,0,0,,Or another way to say that Dialogue: 0,0:36:59.92,0:37:02.09,EN,,0,0,0,,you take the expressions for the arguments, if you like, Dialogue: 0,0:37:02.28,0:37:04.84,EN,,0,0,0,,and substitute them in the body of the procedure and go on, Dialogue: 0,0:37:05.16,0:37:06.88,EN,,0,0,0,,and never really simplify anything Dialogue: 0,0:37:07.16,0:37:08.76,EN,,0,0,0,,until you get down to a primitive operator. Dialogue: 0,0:37:09.47,0:37:10.99,EN,,0,0,0,,So that would be a normal-order language. Dialogue: 0,0:37:12.17,0:37:13.12,EN,,0,0,0,,Well, why don't we do that? Dialogue: 0,0:37:13.82,0:37:14.60,EN,,0,0,0,,Because if we did, Dialogue: 0,0:37:15.00,0:37:17.34,EN,,0,0,0,,we'd get all the advantages of delayed evaluation Dialogue: 0,0:37:17.90,0:37:18.80,EN,,0,0,0,,with none of the mess. Dialogue: 0,0:37:18.94,0:37:20.19,EN,,0,0,0,,In fact, if we did that Dialogue: 0,0:37:20.43,0:37:22.67,EN,,0,0,0,,and cons was just a delayed procedure, Dialogue: 0,0:37:22.68,0:37:24.57,EN,,0,0,0,,that would make cons the same as cons-stream. Dialogue: 0,0:37:24.71,0:37:25.82,EN,,0,0,0,,We wouldn't need streams at all Dialogue: 0,0:37:26.36,0:37:28.54,EN,,0,0,0,,because lists would automatically be streams. Dialogue: 0,0:37:29.55,0:37:30.70,EN,,0,0,0,,That's how lists would behave, Dialogue: 0,0:37:30.75,0:37:32.35,EN,,0,0,0,,all data structures would behave that way. Dialogue: 0,0:37:32.35,0:37:33.64,EN,,0,0,0,,Everything would behave that way. Dialogue: 0,0:37:35.07,0:37:37.63,EN,,0,0,0,,Right, You'd never really do any computation Dialogue: 0,0:37:37.66,0:37:39.42,EN,,0,0,0,,until you actually needed the answer. Dialogue: 0,0:37:40.80,0:37:43.58,EN,,0,0,0,,You wouldn't have to worry about all these explicit annoying delays. Dialogue: 0,0:37:44.79,0:37:46.16,EN,,0,0,0,,Well, why don't we do that? Dialogue: 0,0:37:47.16,0:37:48.81,EN,,0,0,0,,First of all, I should say people do do that. Dialogue: 0,0:37:49.23,0:37:51.85,EN,,0,0,0,,There's some very beautiful languages. Dialogue: 0,0:37:51.85,0:37:55.21,EN,,0,0,0,,One of the very nicest is a language called Miranda, Dialogue: 0,0:37:55.77,0:37:56.76,EN,,0,0,0,,which is, um.. Dialogue: 0,0:37:57.44,0:37:59.80,EN,,0,0,0,,developed by David Turner at the University of Kent. Dialogue: 0,0:38:00.71,0:38:01.93,EN,,0,0,0,,And that's how this language works. Dialogue: 0,0:38:01.93,0:38:03.34,EN,,0,0,0,,It's a normal-order language Dialogue: 0,0:38:04.27,0:38:05.55,EN,,0,0,0,,and its data structures, Dialogue: 0,0:38:06.16,0:38:08.41,EN,,0,0,0,,which look like lists, are actually streams. Dialogue: 0,0:38:08.96,0:38:10.91,EN,,0,0,0,,And you write ordinary procedures in Miranda, Dialogue: 0,0:38:11.28,0:38:13.28,EN,,0,0,0,,and they do these prime things and eight queens things, Dialogue: 0,0:38:13.32,0:38:14.97,EN,,0,0,0,,just without anything special. Dialogue: 0,0:38:14.97,0:38:16.35,EN,,0,0,0,,It's all built in there. Dialogue: 0,0:38:17.93,0:38:18.91,EN,,0,0,0,,But there's a price. Dialogue: 0,0:38:21.19,0:38:22.36,EN,,0,0,0,,Remember how we got here. Dialogue: 0,0:38:23.17,0:38:27.48,EN,,0,0,0,,We're decoupling time in the programs from time in the machines. Dialogue: 0,0:38:27.96,0:38:28.88,EN,,0,0,0,,And if we put delay, Dialogue: 0,0:38:29.04,0:38:30.33,EN,,0,0,0,,that sort of decouples it everywhere, Dialogue: 0,0:38:30.40,0:38:31.42,EN,,0,0,0,,not just in streams. Dialogue: 0,0:38:32.19,0:38:33.14,EN,,0,0,0,,Remember what we're trying to do. Dialogue: 0,0:38:33.14,0:38:38.11,EN,,0,0,0,,We're trying to think about programming as a way to specify processes. Dialogue: 0,0:38:39.30,0:38:40.62,EN,,0,0,0,,And if we give up too much time, Dialogue: 0,0:38:40.65,0:38:42.41,EN,,0,0,0,,our language becomes more elegant, Dialogue: 0,0:38:43.74,0:38:45.87,EN,,0,0,0,,but it becomes a little bit less expressive. Dialogue: 0,0:38:47.03,0:38:49.84,EN,,0,0,0,,There are certain distinctions that we can't draw. Dialogue: 0,0:38:51.48,0:38:53.15,EN,,0,0,0,,One of them, for instance, is iteration. Dialogue: 0,0:38:53.98,0:38:56.44,EN,,0,0,0,,Remember this old procedure, Dialogue: 0,0:38:56.96,0:38:58.28,EN,,0,0,0,,iterative factorial, Dialogue: 0,0:38:58.44,0:39:00.48,EN,,0,0,0,,that we looked at quite a long time ago. Dialogue: 0,0:39:01.23,0:39:02.97,EN,,0,0,0,,Iterative factorial had a thing, Dialogue: 0,0:39:03.04,0:39:04.91,EN,,0,0,0,,and it said there was an internal procedure, Dialogue: 0,0:39:05.18,0:39:07.50,EN,,0,0,0,,and there was a state which was a product and a counter, Dialogue: 0,0:39:08.70,0:39:10.96,EN,,0,0,0,,and we iterate that going around the loop. Dialogue: 0,0:39:12.12,0:39:13.68,EN,,0,0,0,,And we said that was an iterative procedure Dialogue: 0,0:39:13.71,0:39:14.83,EN,,0,0,0,,because it didn't build up state. Dialogue: 0,0:39:15.73,0:39:17.45,EN,,0,0,0,,And the reason it didn't build up state is Dialogue: 0,0:39:17.47,0:39:20.25,EN,,0,0,0,,because this iter that's called Dialogue: 0,0:39:20.30,0:39:22.86,EN,,0,0,0,,is just passing these things around to itself. Dialogue: 0,0:39:23.90,0:39:25.39,EN,,0,0,0,,Or in the substitution model that, Dialogue: 0,0:39:25.55,0:39:27.79,EN,,0,0,0,,you could see in the substitution model that Jerry did, Dialogue: 0,0:39:28.72,0:39:30.01,EN,,0,0,0,,that in an iterative procedure, Dialogue: 0,0:39:30.03,0:39:31.44,EN,,0,0,0,,that state doesn't have to grow. Dialogue: 0,0:39:31.82,0:39:34.22,EN,,0,0,0,,And in fact, we said it doesn't, so this is an iteration. Dialogue: 0,0:39:34.99,0:39:37.47,EN,,0,0,0,,But now think about this exact same text Dialogue: 0,0:39:37.47,0:39:39.10,EN,,0,0,0,,if we had a normal-order language. Dialogue: 0,0:39:41.15,0:39:42.17,EN,,0,0,0,,What would happen is Dialogue: 0,0:39:42.88,0:39:44.96,EN,,0,0,0,,this would no longer be an iterative procedure Dialogue: 0,0:39:45.65,0:39:48.67,EN,,0,0,0,,And if you really think about the details of the substitution model, Dialogue: 0,0:39:48.67,0:39:49.90,EN,,0,0,0,,which I'm not going to do here, Dialogue: 0,0:39:51.20,0:39:52.35,EN,,0,0,0,,this expression would grow. Dialogue: 0,0:39:52.36,0:39:53.18,EN,,0,0,0,,Why would it grow? Dialogue: 0,0:39:53.28,0:39:55.20,EN,,0,0,0,,It's because when iter calls itself, Dialogue: 0,0:39:55.85,0:39:57.31,EN,,0,0,0,,it calls itself with this product. Dialogue: 0,0:39:58.08,0:39:59.36,EN,,0,0,0,,If it's a normal-order language, Dialogue: 0,0:39:59.39,0:40:01.16,EN,,0,0,0,,that multiplication is not going to get done. Dialogue: 0,0:40:02.51,0:40:03.82,EN,,0,0,0,,That's going to say I'm to call myself Dialogue: 0,0:40:03.93,0:40:05.68,EN,,0,0,0,,with a promise to compute this product. Dialogue: 0,0:40:06.67,0:40:08.03,EN,,0,0,0,,And now iter goes around again. Dialogue: 0,0:40:09.76,0:40:11.55,EN,,0,0,0,,And I'm going to call myself Dialogue: 0,0:40:11.84,0:40:14.04,EN,,0,0,0,,with a promise to compute this product Dialogue: 0,0:40:14.04,0:40:17.82,EN,,0,0,0,,where now one of the one factors is a promise. Dialogue: 0,0:40:18.40,0:40:19.43,EN,,0,0,0,,And I call myself again. Dialogue: 0,0:40:19.43,0:40:21.13,EN,,0,0,0,,And if you write out the substitution model Dialogue: 0,0:40:21.98,0:40:23.60,EN,,0,0,0,,for that iterative process, Dialogue: 0,0:40:23.77,0:40:26.83,EN,,0,0,0,,you'll see exactly the same growth in state, Dialogue: 0,0:40:27.16,0:40:28.96,EN,,0,0,0,,all those promises that are getting remembered Dialogue: 0,0:40:28.97,0:40:30.76,EN,,0,0,0,,that have to get called in at the very end. Dialogue: 0,0:40:31.79,0:40:35.02,EN,,0,0,0,,So one of the disadvantages Dialogue: 0,0:40:35.05,0:40:36.86,EN,,0,0,0,,is that you can't really express iteration. Dialogue: 0,0:40:36.98,0:40:39.60,EN,,0,0,0,,Maybe that's a little theoretical reason why not, Dialogue: 0,0:40:39.61,0:40:43.90,EN,,0,0,0,,but in fact, people who are trying to write real operating systems Dialogue: 0,0:40:44.27,0:40:47.56,EN,,0,0,0,,in these languages are running into exactly these types of problems. Dialogue: 0,0:40:48.20,0:40:50.75,EN,,0,0,0,,Like it's perfectly possible to Dialogue: 0,0:40:51.64,0:40:54.38,EN,,0,0,0,,implement a text editor in languages like these. Dialogue: 0,0:40:54.61,0:40:56.08,EN,,0,0,0,,But after you work a while, Dialogue: 0,0:40:56.72,0:40:59.39,EN,,0,0,0,,you suddenly have 3 megabytes of stuff, Dialogue: 0,0:40:59.44,0:41:02.04,EN,,0,0,0,,which is-- I guess they call them Dialogue: 0,0:41:02.16,0:41:05.60,EN,,0,0,0,,the dragging tail problem who are looking at these, Dialogue: 0,0:41:05.82,0:41:08.20,EN,,0,0,0,,of stuff of promises that sort of haven't been called in Dialogue: 0,0:41:08.24,0:41:10.46,EN,,0,0,0,,because you couldn't quite express an iteration. Dialogue: 0,0:41:10.72,0:41:14.81,EN,,0,0,0,,And one of the research questions in these kinds of languages Dialogue: 0,0:41:14.83,0:41:17.48,EN,,0,0,0,,are figuring out the right compiler technology Dialogue: 0,0:41:17.82,0:41:19.85,EN,,0,0,0,,to get rid of the so-called dragging tails. Dialogue: 0,0:41:20.17,0:41:21.61,EN,,0,0,0,,It's not simple. Dialogue: 0,0:41:23.94,0:41:27.31,EN,,0,0,0,,But there's another kind of more striking issue Dialogue: 0,0:41:27.96,0:41:31.04,EN,,0,0,0,,about why you just don't go ahead and make your language normal order. Dialogue: 0,0:41:32.51,0:41:33.29,EN,,0,0,0,,And the reason is Dialogue: 0,0:41:35.05,0:41:38.09,EN,,0,0,0,,that normal-order evaluation and side effects Dialogue: 0,0:41:38.89,0:41:40.19,EN,,0,0,0,,just don't mix. Dialogue: 0,0:41:42.00,0:41:43.96,EN,,0,0,0,,They just don't go together very well. Dialogue: 0,0:41:45.44,0:41:46.65,EN,,0,0,0,,Somehow, you can't- Dialogue: 0,0:41:48.28,0:41:50.80,EN,,0,0,0,,it's sort of you can't simultaneously Dialogue: 0,0:41:51.00,0:41:54.33,EN,,0,0,0,,go around trying to model objects with local state and change Dialogue: 0,0:41:55.72,0:41:56.96,EN,,0,0,0,,at the same time Dialogue: 0,0:41:57.18,0:41:59.55,EN,,0,0,0,,do these normal-order tricks of de-coupling time. Dialogue: 0,0:42:00.40,0:42:03.55,EN,,0,0,0,,Let me just show you a really simple example, very, very simple. Dialogue: 0,0:42:03.79,0:42:05.50,EN,,0,0,0,,Suppose we had a normal-order language. Dialogue: 0,0:42:07.52,0:42:09.55,EN,,0,0,0,,And I'm going to start out in this language. Dialogue: 0,0:42:09.55,0:42:10.52,EN,,0,0,0,,This is now normal order. Dialogue: 0,0:42:10.52,0:42:12.22,EN,,0,0,0,,I'm going to define x to be 0. Dialogue: 0,0:42:13.57,0:42:15.56,EN,,0,0,0,,It's just some variable I'll initialize. Dialogue: 0,0:42:15.75,0:42:17.69,EN,,0,0,0,,And now I'm going to define this little funny function, Dialogue: 0,0:42:18.57,0:42:20.44,EN,,0,0,0,,which is an identity function. Dialogue: 0,0:42:22.64,0:42:23.90,EN,,0,0,0,,And what it does, Dialogue: 0,0:42:24.11,0:42:26.60,EN,,0,0,0,,it keeps track of the last time you called it using x. Dialogue: 0,0:42:31.40,0:42:34.16,EN,,0,0,0,,Right? So the identity of n just returns n, Dialogue: 0,0:42:34.17,0:42:35.39,EN,,0,0,0,,but it sets x to be n. Dialogue: 0,0:42:36.76,0:42:38.54,EN,,0,0,0,,And now I'll define a little increment function, Dialogue: 0,0:42:39.55,0:42:42.30,EN,,0,0,0,,which is a very little, simple scenario. Dialogue: 0,0:42:42.58,0:42:45.34,EN,,0,0,0,,Now, imagine I'm interacting with this in the normal-order language, Dialogue: 0,0:42:46.27,0:42:47.23,EN,,0,0,0,,and I type the following. Dialogue: 0,0:42:47.23,0:42:52.83,EN,,0,0,0,,I say define y to be increment the identity function of 3, Dialogue: 0,0:42:52.83,0:42:53.96,EN,,0,0,0,,so y is going to be 4. Dialogue: 0,0:42:57.41,0:42:58.35,EN,,0,0,0,,Now, I say what's x? Dialogue: 0,0:42:59.52,0:43:02.16,EN,,0,0,0,,Well, x should have been the value that was remembered last Dialogue: 0,0:43:02.64,0:43:04.01,EN,,0,0,0,,when I called the identity function. Dialogue: 0,0:43:04.71,0:43:06.73,EN,,0,0,0,,So you'd expect to say, well, x is 3 at this point, Dialogue: 0,0:43:06.91,0:43:07.52,EN,,0,0,0,,but it's not. Dialogue: 0,0:43:08.53,0:43:11.15,EN,,0,0,0,,Because when I defined here, y here, Dialogue: 0,0:43:11.79,0:43:13.45,EN,,0,0,0,,what I really defined y to be Dialogue: 0,0:43:13.47,0:43:15.71,EN,,0,0,0,,increment of a promise to do this thing. Dialogue: 0,0:43:17.00,0:43:18.17,EN,,0,0,0,,So I didn't look at y, Dialogue: 0,0:43:18.36,0:43:20.25,EN,,0,0,0,,so that identity function didn't get run. Dialogue: 0,0:43:21.56,0:43:23.20,EN,,0,0,0,,So if I type in this definition Dialogue: 0,0:43:23.31,0:43:24.80,EN,,0,0,0,,and look at x, I'm going to get 0. Dialogue: 0,0:43:28.36,0:43:31.20,EN,,0,0,0,,Now, if I go look at y and say what's y, Dialogue: 0,0:43:31.52,0:43:32.43,EN,,0,0,0,,say y is 4, Dialogue: 0,0:43:32.67,0:43:35.16,EN,,0,0,0,,looking at y, that very active looking at y Dialogue: 0,0:43:35.29,0:43:37.42,EN,,0,0,0,,caused the identity function to be run. Dialogue: 0,0:43:38.72,0:43:40.48,EN,,0,0,0,,And now x will get remembered as 3. Dialogue: 0,0:43:40.74,0:43:41.87,EN,,0,0,0,,So here x will be 0. Dialogue: 0,0:43:41.93,0:43:42.96,EN,,0,0,0,,Here, x will be 3. Dialogue: 0,0:43:43.28,0:43:46.16,EN,,0,0,0,,That's a tiny, little, simple scenario, Dialogue: 0,0:43:46.30,0:43:49.28,EN,,0,0,0,,but you can see what kind of a mess that's going to make Dialogue: 0,0:43:50.36,0:43:53.34,EN,,0,0,0,,for debugging interactive programs Dialogue: 0,0:43:54.12,0:43:55.88,EN,,0,0,0,,when you have normal-order evaluation. Dialogue: 0,0:43:57.10,0:43:58.12,EN,,0,0,0,,It's very confusing. Dialogue: 0,0:43:59.69,0:44:02.04,EN,,0,0,0,,But it's very confusing for a very deep reason, Dialogue: 0,0:44:02.80,0:44:06.41,EN,,0,0,0,,which is that the whole idea of putting in delays Dialogue: 0,0:44:06.92,0:44:08.43,EN,,0,0,0,,is that you throw away time. Dialogue: 0,0:44:09.78,0:44:11.75,EN,,0,0,0,,That's why we can have these infinite processes. Dialogue: 0,0:44:11.75,0:44:12.97,EN,,0,0,0,,Since we've thrown away time, Dialogue: 0,0:44:12.99,0:44:14.27,EN,,0,0,0,,we don't have to wait for them to run, Dialogue: 0,0:44:17.55,0:44:20.44,EN,,0,0,0,,Right? We decouple the order of events in the computer Dialogue: 0,0:44:20.83,0:44:22.11,EN,,0,0,0,,from what we write in our programs. Dialogue: 0,0:44:22.35,0:44:25.28,EN,,0,0,0,,But when we talk about state and set and change, Dialogue: 0,0:44:25.48,0:44:27.42,EN,,0,0,0,,that's exactly what we do want control of. Dialogue: 0,0:44:28.76,0:44:33.82,EN,,0,0,0,,So it's almost as if there's this fundamental contradiction in what you want. Dialogue: 0,0:44:34.57,0:44:39.12,EN,,0,0,0,,And that brings us back to these sort of philosophical mutterings Dialogue: 0,0:44:39.13,0:44:40.75,EN,,0,0,0,,what is it that you're trying to model Dialogue: 0,0:44:40.78,0:44:41.77,EN,,0,0,0,,and how do you look at the world. Dialogue: 0,0:44:42.41,0:44:44.30,EN,,0,0,0,,Or sometimes this is called the Dialogue: 0,0:44:44.76,0:44:46.60,EN,,0,0,0,,the debate over functional programming. Dialogue: 0,0:44:54.19,0:44:56.60,EN,,0,0,0,,A so-called purely functional language Dialogue: 0,0:44:57.07,0:44:59.20,EN,,0,0,0,,is one that just doesn't have any side effects. Dialogue: 0,0:45:00.44,0:45:01.63,EN,,0,0,0,,Since you have no side effects, Dialogue: 0,0:45:01.64,0:45:03.02,EN,,0,0,0,,there's no assignment operator, Dialogue: 0,0:45:03.34,0:45:05.72,EN,,0,0,0,,so there are no terrible consequences of it. Dialogue: 0,0:45:06.36,0:45:07.93,EN,,0,0,0,,You can use a substitution-like thing. Dialogue: 0,0:45:07.93,0:45:10.48,EN,,0,0,0,,Programs really are like mathematics and not like Dialogue: 0,0:45:10.76,0:45:13.82,EN,,0,0,0,,not like models in the real world, not like objects in the real world. Dialogue: 0,0:45:15.05,0:45:17.17,EN,,0,0,0,,There are a lot of wonderful things about functional languages. Dialogue: 0,0:45:17.17,0:45:19.63,EN,,0,0,0,,Since there's no time, you never have any synchronization problems. Dialogue: 0,0:45:20.64,0:45:23.72,EN,,0,0,0,,And if you want to put something into a parallel algorithm, Dialogue: 0,0:45:24.72,0:45:28.20,EN,,0,0,0,,you can run the pieces of that parallel processing any way you want. Dialogue: 0,0:45:29.40,0:45:31.44,EN,,0,0,0,,There's just never any synchronization to worry that, Dialogue: 0,0:45:31.50,0:45:33.34,EN,,0,0,0,,and it's a very congenial environment for doing this. Dialogue: 0,0:45:33.64,0:45:35.71,EN,,0,0,0,,The price is you give up assignment. Dialogue: 0,0:45:39.10,0:45:41.32,EN,,0,0,0,,So an advocate of a functional language would say, Dialogue: 0,0:45:41.34,0:45:43.04,EN,,0,0,0,,gee, that's just a tiny price to pay. Dialogue: 0,0:45:44.52,0:45:46.51,EN,,0,0,0,,You probably shouldn't use assignment most of the time anyway. Dialogue: 0,0:45:46.88,0:45:48.27,EN,,0,0,0,,And if you just give up assignment, Dialogue: 0,0:45:48.43,0:45:51.40,EN,,0,0,0,,you can be in this much, much nicer world Dialogue: 0,0:45:51.96,0:45:53.24,EN,,0,0,0,,than this place with objects. Dialogue: 0,0:45:54.19,0:45:56.30,EN,,0,0,0,,Well, what's the rejoinder to that? Dialogue: 0,0:45:56.30,0:45:58.59,EN,,0,0,0,,Remember how we got into this mess. Dialogue: 0,0:46:00.06,0:46:03.79,EN,,0,0,0,,We started trying to model things that had local state. Dialogue: 0,0:46:04.44,0:46:06.49,EN,,0,0,0,,So remember Gerry's random number generator. Dialogue: 0,0:46:07.16,0:46:08.67,EN,,0,0,0,,There was this random number generator Dialogue: 0,0:46:09.28,0:46:10.62,EN,,0,0,0,,that had some little state in it Dialogue: 0,0:46:10.83,0:46:12.08,EN,,0,0,0,,to compute the next random number Dialogue: 0,0:46:12.12,0:46:14.08,EN,,0,0,0,,and the next random number and the next random number. Dialogue: 0,0:46:14.28,0:46:16.14,EN,,0,0,0,,And we wanted to hide that state away from the Dialogue: 0,0:46:16.43,0:46:18.96,EN,,0,0,0,,the Cesaro compute pi process, Dialogue: 0,0:46:19.84,0:46:20.92,EN,,0,0,0,,and that's why we needed set! Dialogue: 0,0:46:20.97,0:46:22.91,EN,,0,0,0,,We wanted to package that stated modularly. Dialogue: 0,0:46:24.07,0:46:26.36,EN,,0,0,0,,Well, a functional programming person would say, Dialogue: 0,0:46:26.38,0:46:27.56,EN,,0,0,0,,well, you're just all wet. Dialogue: 0,0:46:27.56,0:46:29.84,EN,,0,0,0,,I mean, you can write a perfectly good modular program. Dialogue: 0,0:46:29.84,0:46:32.46,EN,,0,0,0,,It's just you're thinking about modularity wrong. Dialogue: 0,0:46:33.08,0:46:35.02,EN,,0,0,0,,You're hung up in this next random number Dialogue: 0,0:46:35.07,0:46:36.88,EN,,0,0,0,,and the next random number and the next random number. Dialogue: 0,0:46:36.88,0:46:39.42,EN,,0,0,0,,Why don't you just say let's write a program. Dialogue: 0,0:46:40.09,0:46:41.29,EN,,0,0,0,,Let's write an enumerator Dialogue: 0,0:46:41.95,0:46:44.48,EN,,0,0,0,,which just generates an infinite stream of random numbers. Dialogue: 0,0:46:49.01,0:46:50.91,EN,,0,0,0,,We can sort of have that stream all at once, Dialogue: 0,0:46:52.64,0:46:54.54,EN,,0,0,0,,and that's going to be our source of random numbers. Dialogue: 0,0:46:54.54,0:46:55.24,EN,,0,0,0,,And then if you like, Dialogue: 0,0:46:55.53,0:46:57.47,EN,,0,0,0,,you can put that through some sort of processor, Dialogue: 0,0:46:57.77,0:47:01.16,EN,,0,0,0,,which is-- I don't know-- a Cesaro test, Dialogue: 0,0:47:04.94,0:47:06.22,EN,,0,0,0,,and that can do what it wants. Dialogue: 0,0:47:06.88,0:47:08.56,EN,,0,0,0,,And what would come out of there Dialogue: 0,0:47:08.72,0:47:27.45,EN,,0,0,0,,would be a stream of successive approximations to pi. Dialogue: 0,0:47:28.14,0:47:30.65,EN,,0,0,0,,So as we looked further down this stream, Dialogue: 0,0:47:30.76,0:47:32.38,EN,,0,0,0,,we'd tug on this Cesaro thing, Dialogue: 0,0:47:33.12,0:47:35.36,EN,,0,0,0,,and it would pull out more and more random numbers. Dialogue: 0,0:47:35.54,0:47:37.21,EN,,0,0,0,,And the further and further we look down the stream, Dialogue: 0,0:47:37.23,0:47:38.96,EN,,0,0,0,,the better an approximation we'd get to pi. Dialogue: 0,0:47:39.72,0:47:41.66,EN,,0,0,0,,And it would do exactly the same as the other computation, Dialogue: 0,0:47:41.66,0:47:43.79,EN,,0,0,0,,except we're thinking about the modularity different. Dialogue: 0,0:47:43.89,0:47:45.55,EN,,0,0,0,,We're saying imagine we had all that Dialogue: 0,0:47:45.56,0:47:47.47,EN,,0,0,0,,infinite streams of random numbers all at once. Dialogue: 0,0:47:49.28,0:47:52.24,EN,,0,0,0,,You can see the details of this procedure in the book. Dialogue: 0,0:47:53.61,0:47:57.85,EN,,0,0,0,,But similarly, there are other things that we tend to get locked into Dialogue: 0,0:47:58.27,0:48:01.20,EN,,0,0,0,,on this one and that one and the next one and the next one, Dialogue: 0,0:48:01.37,0:48:02.81,EN,,0,0,0,,which don't have to be that way. Dialogue: 0,0:48:03.28,0:48:06.54,EN,,0,0,0,,Like you might think about like a banking system, Dialogue: 0,0:48:07.68,0:48:08.90,EN,,0,0,0,,which is a very simple idea. Dialogue: 0,0:48:08.90,0:48:12.21,EN,,0,0,0,,Imagine we have a program that sort of represents a bank account. Dialogue: 0,0:48:18.81,0:48:20.84,EN,,0,0,0,,The bank account might have in it-- Dialogue: 0,0:48:22.78,0:48:26.22,EN,,0,0,0,,if we looked at this in a sort of message-passing view of the world, Dialogue: 0,0:48:26.44,0:48:28.12,EN,,0,0,0,,we'd say a bank account is an object Dialogue: 0,0:48:28.59,0:48:31.51,EN,,0,0,0,,that has some local state in there, which is the balance, say. Dialogue: 0,0:48:34.11,0:48:36.00,EN,,0,0,0,,And a user using this system comes Dialogue: 0,0:48:36.44,0:48:38.14,EN,,0,0,0,,and sends a transaction request. Dialogue: 0,0:48:39.31,0:48:41.05,EN,,0,0,0,,So the user sends a transaction request, Dialogue: 0,0:48:41.07,0:48:42.20,EN,,0,0,0,,like deposit some money, Dialogue: 0,0:48:42.28,0:48:43.53,EN,,0,0,0,,and the bank account maybe-- Dialogue: 0,0:48:43.92,0:48:46.78,EN,,0,0,0,,let's say the bank account always responds with what the current balance is. Dialogue: 0,0:48:48.22,0:48:50.04,EN,,0,0,0,,The user says let's deposits some money, Dialogue: 0,0:48:50.06,0:48:53.21,EN,,0,0,0,,and the bank account sends back a message which is the balance. Dialogue: 0,0:48:54.35,0:48:57.42,EN,,0,0,0,,And the user says deposit some more, Dialogue: 0,0:48:57.45,0:48:58.81,EN,,0,0,0,,and the bank account sends back a message. Dialogue: 0,0:48:59.15,0:49:00.75,EN,,0,0,0,,And just like the random number generating Dialogue: 0,0:49:00.78,0:49:02.12,EN,,0,0,0,,you'd say, gee, we would like to use set. Dialogue: 0,0:49:03.20,0:49:06.88,EN,,0,0,0,,We'd like to have balance be a piece of local state inside this bank account Dialogue: 0,0:49:06.88,0:49:08.40,EN,,0,0,0,,because we want to separate the state of the user Dialogue: 0,0:49:08.41,0:49:09.57,EN,,0,0,0,,from the state of the bank account. Dialogue: 0,0:49:13.28,0:49:16.42,EN,,0,0,0,,Well, that's the message-processing view. Dialogue: 0,0:49:16.42,0:49:18.20,EN,,0,0,0,,There's a stream view with that thing, Dialogue: 0,0:49:19.48,0:49:22.19,EN,,0,0,0,,which does the same thing without any set or side effects. Dialogue: 0,0:49:22.74,0:49:26.73,EN,,0,0,0,,And the idea is again Dialogue: 0,0:49:27.37,0:49:30.25,EN,,0,0,0,,we don't think about anything having local state. Dialogue: 0,0:49:31.18,0:49:33.08,EN,,0,0,0,,We think about the bank account as something Dialogue: 0,0:49:33.40,0:49:37.71,EN,,0,0,0,,that's going to process a stream of transaction requests. Dialogue: 0,0:49:38.64,0:49:40.16,EN,,0,0,0,,So think about this bank account not Dialogue: 0,0:49:40.22,0:49:42.00,EN,,0,0,0,,as something that goes message by message, Dialogue: 0,0:49:42.44,0:49:45.85,EN,,0,0,0,,but something that takes in a stream of transaction requests Dialogue: 0,0:49:45.87,0:49:48.49,EN,,0,0,0,,like maybe successive deposit announced. Dialogue: 0,0:49:49.49,0:49:54.94,EN,,0,0,0,,1, 2, 2, 4, those might be successive amounts to deposit. Dialogue: 0,0:49:55.94,0:50:02.44,EN,,0,0,0,,And then coming out of it is the successive balances 1, 3, 5, 9. Dialogue: 0,0:50:03.77,0:50:06.14,EN,,0,0,0,,So we think of the bank account not as something that has state, Dialogue: 0,0:50:06.40,0:50:07.26,EN,,0,0,0,,but something that acts Dialogue: 0,0:50:08.92,0:50:10.82,EN,,0,0,0,,sort of on the infinite stream of requests. Dialogue: 0,0:50:10.82,0:50:12.30,EN,,0,0,0,,But remember, we've thrown away time. Dialogue: 0,0:50:12.37,0:50:14.27,EN,,0,0,0,,So what we can do is if the user's here, Dialogue: 0,0:50:16.12,0:50:19.13,EN,,0,0,0,,we can have this infinite stream of requests Dialogue: 0,0:50:19.18,0:50:22.54,EN,,0,0,0,,being generated one at a time coming from the user Dialogue: 0,0:50:24.06,0:50:26.57,EN,,0,0,0,,and this transaction stream Dialogue: 0,0:50:26.57,0:50:28.80,EN,,0,0,0,,coming back on a printer being printed one at a time. Dialogue: 0,0:50:30.01,0:50:31.37,EN,,0,0,0,,And if we drew a little line here, Dialogue: 0,0:50:32.56,0:50:33.08,EN,,0,0,0,,right there to the user, Dialogue: 0,0:50:33.28,0:50:34.91,EN,,0,0,0,,the user couldn't tell that this system doesn't have state. Dialogue: 0,0:50:36.19,0:50:37.71,EN,,0,0,0,,that this system doesn't have state. Dialogue: 0,0:50:39.56,0:50:41.13,EN,,0,0,0,,It looks just like the other one, Dialogue: 0,0:50:41.29,0:50:42.46,EN,,0,0,0,,but there's no state in there. Dialogue: 0,0:50:42.84,0:50:45.87,EN,,0,0,0,,And by the way, Dialogue: 0,0:50:46.72,0:50:49.47,EN,,0,0,0,,just to show you, here's an actual implementation Dialogue: 0,0:50:50.52,0:50:52.30,EN,,0,0,0,,of this-- we'll call it make deposit account Dialogue: 0,0:50:52.32,0:50:53.32,EN,,0,0,0,,because you can only deposit. Dialogue: 0,0:50:54.17,0:50:55.77,EN,,0,0,0,,It takes an initial balance Dialogue: 0,0:50:56.09,0:50:58.09,EN,,0,0,0,,and then a stream of deposits you might make. Dialogue: 0,0:51:00.02,0:51:00.82,EN,,0,0,0,,And what is it? Dialogue: 0,0:51:00.82,0:51:02.54,EN,,0,0,0,,Well, it's just cons-stream of the balance Dialogue: 0,0:51:03.23,0:51:05.31,EN,,0,0,0,,onto make a new account stream Dialogue: 0,0:51:06.24,0:51:07.32,EN,,0,0,0,,whose initial balance Dialogue: 0,0:51:07.48,0:51:10.27,EN,,0,0,0,,is the old balance plus the first thing in the deposit stream Dialogue: 0,0:51:10.86,0:51:13.40,EN,,0,0,0,,whose rest, right and, Dialogue: 0,0:51:13.76,0:51:17.37,EN,,0,0,0,,make deposit account works on the rest of which is the tail of the deposit stream. Dialogue: 0,0:51:18.30,0:51:23.84,EN,,0,0,0,,So there's sort of a very typical message-passing, Dialogue: 0,0:51:23.95,0:51:27.55,EN,,0,0,0,,message-passing, object-oriented thing that's done without side effects at all. Dialogue: 0,0:51:29.05,0:51:30.76,EN,,0,0,0,,There are very many things you can do this way. Dialogue: 0,0:51:32.25,0:51:35.23,EN,,0,0,0,,Well, can you do everything without assignment? Dialogue: 0,0:51:36.40,0:51:39.00,EN,,0,0,0,,Can everybody go over to purely functional languages? Dialogue: 0,0:51:40.05,0:51:42.04,EN,,0,0,0,,Well, we don't know, Dialogue: 0,0:51:42.27,0:51:43.44,EN,,0,0,0,,but there seem to be places Dialogue: 0,0:51:43.92,0:51:46.03,EN,,0,0,0,,where purely functional programming breaks down. Dialogue: 0,0:51:48.10,0:51:50.27,EN,,0,0,0,,Where it starts hurting is when you have things like this, Dialogue: 0,0:51:50.43,0:51:52.32,EN,,0,0,0,,but you also mix it up with Dialogue: 0,0:51:52.60,0:51:54.27,EN,,0,0,0,,the other things that we had to worry that, Dialogue: 0,0:51:54.30,0:51:55.64,EN,,0,0,0,,which are objects and sharing Dialogue: 0,0:51:55.90,0:51:58.52,EN,,0,0,0,,and two independent agents being the same. Dialogue: 0,0:51:58.85,0:51:59.93,EN,,0,0,0,,So under a typical one, Dialogue: 0,0:51:59.96,0:52:01.63,EN,,0,0,0,,suppose you want to extend this bank account. Dialogue: 0,0:52:03.24,0:52:04.27,EN,,0,0,0,,So here's a bank account. Dialogue: 0,0:52:12.22,0:52:14.75,EN,,0,0,0,,Bank accounts take in a stream of transaction requests Dialogue: 0,0:52:15.20,0:52:18.44,EN,,0,0,0,,and put out streams of, say, balances or responses to that. Dialogue: 0,0:52:18.78,0:52:20.16,EN,,0,0,0,,But suppose you want to model the fact Dialogue: 0,0:52:20.17,0:52:24.36,EN,,0,0,0,,that this is a joint bank account between two independent people. Dialogue: 0,0:52:25.68,0:52:28.65,EN,,0,0,0,,Right? I don't know. So suppose there are two people, Dialogue: 0,0:52:28.97,0:52:30.96,EN,,0,0,0,,say, Bill and Dave, Dialogue: 0,0:52:31.77,0:52:33.14,EN,,0,0,0,,who have a joint bank account. Dialogue: 0,0:52:35.96,0:52:36.85,EN,,0,0,0,,How would you model this? Dialogue: 0,0:52:36.88,0:52:39.80,EN,,0,0,0,,Well, you might, Bill puts out a stream of transaction requests, Dialogue: 0,0:52:40.24,0:52:42.25,EN,,0,0,0,,and Dave puts out a stream of transaction requests, Dialogue: 0,0:52:42.25,0:52:45.16,EN,,0,0,0,,and somehow, they have to merge into this bank account. Dialogue: 0,0:52:45.88,0:52:47.85,EN,,0,0,0,,So what you might do is write a little stream Dialogue: 0,0:52:47.90,0:52:50.65,EN,,0,0,0,,processing thing called merge, Dialogue: 0,0:52:57.23,0:52:59.13,EN,,0,0,0,,which sort of takes these, merges them together, Dialogue: 0,0:52:59.34,0:53:01.19,EN,,0,0,0,,produces a single stream for the bank account. Dialogue: 0,0:53:01.19,0:53:02.99,EN,,0,0,0,,Now they're both talking to the same bank account. Dialogue: 0,0:53:03.61,0:53:05.48,EN,,0,0,0,,That's all great, but how do you write merge? Dialogue: 0,0:53:05.93,0:53:08.24,EN,,0,0,0,,What, What's this procedure merge? Dialogue: 0,0:53:09.73,0:53:11.42,EN,,0,0,0,,You want to do something that's reasonable. Dialogue: 0,0:53:12.38,0:53:13.80,EN,,0,0,0,,Your first guess might be to say, Dialogue: 0,0:53:13.80,0:53:16.68,EN,,0,0,0,,well, we'll take alternate requests from Bill and Dave. Dialogue: 0,0:53:18.19,0:53:20.97,EN,,0,0,0,,But what happens if But what happens if suddenly in the middle thing Dialogue: 0,0:53:21.18,0:53:23.08,EN,,0,0,0,,Dave goes away on vacation for two years? Dialogue: 0,0:53:24.15,0:53:25.40,EN,,0,0,0,,Then Bill's sort of stuck. Dialogue: 0,0:53:27.69,0:53:29.75,EN,,0,0,0,,So what you want to do is-- well, it's hard to describe. Dialogue: 0,0:53:29.75,0:53:33.64,EN,,0,0,0,,What you want to do is what people call fair merge. Dialogue: 0,0:53:38.41,0:53:40.17,EN,,0,0,0,,The idea of fair merge is Dialogue: 0,0:53:40.73,0:53:42.46,EN,,0,0,0,,is it sort of should do them alternately, Dialogue: 0,0:53:42.49,0:53:43.92,EN,,0,0,0,,but if there's nothing waiting here, Dialogue: 0,0:53:43.96,0:53:44.91,EN,,0,0,0,,it should take one twice. Dialogue: 0,0:53:46.01,0:53:48.45,EN,,0,0,0,,Notice I can't even say that without talking about time. Dialogue: 0,0:53:51.30,0:53:56.41,EN,,0,0,0,,So one of the other active researcher areas in functional languages Dialogue: 0,0:53:56.43,0:53:59.48,EN,,0,0,0,,is inventing little things like fair merge Dialogue: 0,0:54:00.35,0:54:01.31,EN,,0,0,0,,maybe some others, Dialogue: 0,0:54:01.56,0:54:06.25,EN,,0,0,0,,which will take the places where I used to need side effects and objects Dialogue: 0,0:54:06.80,0:54:10.52,EN,,0,0,0,,and sort of hide them away in some very well-defined modules of the system Dialogue: 0,0:54:10.86,0:54:13.50,EN,,0,0,0,,so that all the problems of assignment Dialogue: 0,0:54:13.52,0:54:15.34,EN,,0,0,0,,don't sort of leak out all over the system but Dialogue: 0,0:54:15.40,0:54:17.88,EN,,0,0,0,,are captured in some fairly well-understood things. Dialogue: 0,0:54:20.78,0:54:22.70,EN,,0,0,0,,More generally, I think what you're seeing Dialogue: 0,0:54:23.12,0:54:24.06,EN,,0,0,0,,is that we're running across Dialogue: 0,0:54:24.08,0:54:26.67,EN,,0,0,0,,what I think is a very basic problem in computer science, Dialogue: 0,0:54:26.97,0:54:27.82,EN,,0,0,0,,which is how to Dialogue: 0,0:54:28.24,0:54:32.03,EN,,0,0,0,,how to define languages that somehow can talk about delayed evaluation Dialogue: 0,0:54:34.14,0:54:35.08,EN,,0,0,0,,But also Dialogue: 0,0:54:35.87,0:54:38.25,EN,,0,0,0,,be able to reflect this view that there are objects in the world. Dialogue: 0,0:54:38.36,0:54:40.36,EN,,0,0,0,,How do we somehow get both? Dialogue: 0,0:54:41.23,0:54:43.04,EN,,0,0,0,,And I think that's a very hard problem. Dialogue: 0,0:54:43.04,0:54:45.52,EN,,0,0,0,,And it may be that it's a very hard problem Dialogue: 0,0:54:45.85,0:54:48.17,EN,,0,0,0,,that has almost nothing to do with computer science, Dialogue: 0,0:54:48.59,0:54:50.24,EN,,0,0,0,,that it really is a problem having to do with Dialogue: 0,0:54:50.27,0:54:52.73,EN,,0,0,0,,two very incompatible ways of looking at the world. Dialogue: 0,0:54:54.14,0:54:54.72,EN,,0,0,0,,OK, questions? Dialogue: 0,0:55:17.55,0:55:19.20,EN,,0,0,0,,AUDIENCE: You mentioned earlier that Dialogue: 0,0:55:20.11,0:55:21.32,EN,,0,0,0,,once you introduce assignment, Dialogue: 0,0:55:21.32,0:55:25.89,EN,,0,0,0,,the general rule for using the substitution model is you can't. Dialogue: 0,0:55:25.89,0:55:27.57,EN,,0,0,0,,Unless you're very careful, you can't. Dialogue: 0,0:55:27.57,0:55:27.96,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:55:28.26,0:55:33.28,EN,,0,0,0,,AUDIENCE: Is there a set of techniques or a set of guidelines Dialogue: 0,0:55:33.42,0:55:35.92,EN,,0,0,0,,for localizing the effects of assignment Dialogue: 0,0:55:36.52,0:55:40.30,EN,,0,0,0,,so that the very careful becomes defined? Dialogue: 0,0:55:40.30,0:55:42.60,EN,,0,0,0,,PROFESSOR: I don't know. Um... Dialogue: 0,0:55:42.89,0:55:43.58,EN,,0,0,0,,Let me think. Dialogue: 0,0:55:45.43,0:55:48.94,EN,,0,0,0,,Well, certainly, there was an assignment inside memo proc, Dialogue: 0,0:55:50.12,0:55:51.48,EN,,0,0,0,,but that was sort of hidden away. Dialogue: 0,0:55:51.48,0:55:53.00,EN,,0,0,0,,It ended up not making any difference. Dialogue: 0,0:55:53.48,0:55:56.44,EN,,0,0,0,,Part of the reason for that is once this thing triggered Dialogue: 0,0:55:57.15,0:55:58.83,EN,,0,0,0,,that it had run and gotten an answer, Dialogue: 0,0:55:58.83,0:56:00.06,EN,,0,0,0,,that answer will never change. Dialogue: 0,0:56:00.60,0:56:02.33,EN,,0,0,0,,So that was sort of a one-time assignment. Dialogue: 0,0:56:02.35,0:56:03.85,EN,,0,0,0,,So one very general thing you can do Dialogue: 0,0:56:04.30,0:56:06.35,EN,,0,0,0,,is if you only do what's called a one-time assignment Dialogue: 0,0:56:08.04,0:56:09.24,EN,,0,0,0,,and never change anything, Dialogue: 0,0:56:09.63,0:56:10.54,EN,,0,0,0,,then you can do better. Dialogue: 0,0:56:11.25,0:56:14.12,EN,,0,0,0,,One of the problems in this merge thing, people have-- Dialogue: 0,0:56:14.67,0:56:18.32,EN,,0,0,0,,people have-- let me see if this is right. Dialogue: 0,0:56:18.49,0:56:21.55,EN,,0,0,0,,I think it's true that with fair merge, Dialogue: 0,0:56:22.25,0:56:26.09,EN,,0,0,0,,with just fair merge, you can begin effectively simulating Dialogue: 0,0:56:27.02,0:56:28.89,EN,,0,0,0,,assignment in the rest of the language. Dialogue: 0,0:56:30.82,0:56:33.29,EN,,0,0,0,,It seems like anything you do to go outside-- Dialogue: 0,0:56:33.50,0:56:35.50,EN,,0,0,0,,I'm not quite sure that's true for fair merge, Dialogue: 0,0:56:35.53,0:56:39.31,EN,,0,0,0,,but it's true of a little bit more general things that people have been doing. Dialogue: 0,0:56:39.52,0:56:41.34,EN,,0,0,0,,So it might be that any little bit you put in, Dialogue: 0,0:56:41.61,0:56:44.14,EN,,0,0,0,,suddenly if they allow you to build arbitrary stuff, Dialogue: 0,0:56:44.16,0:56:46.51,EN,,0,0,0,,it's almost as bad as having assignment altogether. Dialogue: 0,0:56:47.97,0:56:50.67,EN,,0,0,0,,But that's an area that people are thinking about now. Dialogue: 0,0:56:51.59,0:56:54.30,EN,,0,0,0,,AUDIENCE: I guess I don't see the problem here with merge Dialogue: 0,0:56:54.83,0:56:59.20,EN,,0,0,0,,if, you know the sense, I call Bill, if Bill is a procedure, Dialogue: 0,0:56:59.21,0:57:02.41,EN,,0,0,0,,then Bill is going to increment the bank account Dialogue: 0,0:57:02.44,0:57:04.73,EN,,0,0,0,,or build the list that 's going to put in the next element. Dialogue: 0,0:57:04.73,0:57:06.84,EN,,0,0,0,,If I call Dave twice in a row, that will do that. Dialogue: 0,0:57:07.17,0:57:09.35,EN,,0,0,0,,I'm not sure where fair merge has to be involved. Dialogue: 0,0:57:09.35,0:57:11.20,EN,,0,0,0,,PROFESSOR: The problem is imagine these really as people. Dialogue: 0,0:57:11.20,0:57:14.20,EN,,0,0,0,,See, here I have the user who's interacting with this bank account. Dialogue: 0,0:57:14.85,0:57:17.07,EN,,0,0,0,,Put in a request, get an answer. Put in a request, get an answer. Dialogue: 0,0:57:17.20,0:57:17.56,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,0:57:18.20,0:57:20.62,EN,,0,0,0,,PROFESSOR: But if the only way I can process request Dialogue: 0,0:57:20.65,0:57:22.25,EN,,0,0,0,,is to alternate them from two people-- Dialogue: 0,0:57:22.91,0:57:24.22,EN,,0,0,0,,AUDIENCE: Well, why would you alternate them? Dialogue: 0,0:57:24.22,0:57:25.23,EN,,0,0,0,,PROFESSOR: Why don't I? Dialogue: 0,0:57:25.45,0:57:25.80,EN,,0,0,0,,AUDIENCE: Yes. Why do you? Dialogue: 0,0:57:26.60,0:57:27.72,EN,,0,0,0,,PROFESSOR: Think of them as real people, right? Dialogue: 0,0:57:27.76,0:57:28.97,EN,,0,0,0,,This guy might go away for a year. Dialogue: 0,0:57:29.28,0:57:31.74,EN,,0,0,0,,And you're sitting here at the bank account window, Dialogue: 0,0:57:32.43,0:57:33.72,EN,,0,0,0,,and you can't put in two requests Dialogue: 0,0:57:33.74,0:57:34.94,EN,,0,0,0,,because it's waiting for this guy. Dialogue: 0,0:57:35.48,0:57:37.07,EN,,0,0,0,,AUDIENCE: Why does it have to be waiting for one? Dialogue: 0,0:57:37.38,0:57:39.11,EN,,0,0,0,,PROFESSOR: Because it's trying to compute a function. Dialogue: 0,0:57:39.11,0:57:40.92,EN,,0,0,0,,I have to define a function. Dialogue: 0,0:57:41.72,0:57:42.60,EN,,0,0,0,,Another way to say that Dialogue: 0,0:57:42.84,0:57:44.99,EN,,0,0,0,,is the answer to what comes out of this merge box Dialogue: 0,0:57:46.24,0:57:49.48,EN,,0,0,0,,is not a function of what goes in. Dialogue: 0,0:57:51.69,0:57:53.49,EN,,0,0,0,,Because, see, what would the function be? Dialogue: 0,0:57:53.49,0:57:58.86,EN,,0,0,0,,Suppose he puts in 1, 1, 1, 1, Dialogue: 0,0:57:59.82,0:58:02.78,EN,,0,0,0,,and he puts in 2, 2, 2, 2. Dialogue: 0,0:58:03.47,0:58:04.80,EN,,0,0,0,,What's the answer supposed to be? Dialogue: 0,0:58:05.58,0:58:08.74,EN,,0,0,0,,It's not good enough to say it's 1, 2, 1, 2, 1, 2. Dialogue: 0,0:58:08.74,0:58:09.39,EN,,0,0,0,,AUDIENCE: I understand. Dialogue: 0,0:58:09.39,0:58:11.56,EN,,0,0,0,,But when Bill puts in 1, 1 goes in. Dialogue: 0,0:58:11.56,0:58:13.95,EN,,0,0,0,,When Dave puts in 2, twice 2 goes in twice. Dialogue: 0,0:58:13.95,0:58:14.73,EN,,0,0,0,,AUDIENCE: When Bill puts in-- Dialogue: 0,0:58:14.76,0:58:15.08,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:58:15.13,0:58:18.43,EN,,0,0,0,,AUDIENCE: Why can't it be hooked to the time of the input-- Dialogue: 0,0:58:18.59,0:58:20.06,EN,,0,0,0,,the actual procedural-- Dialogue: 0,0:58:20.12,0:58:21.84,EN,,0,0,0,,PROFESSOR: Because I don't have time. Dialogue: 0,0:58:23.98,0:58:26.90,EN,,0,0,0,,See, all I can say is I'm going to define a function. Dialogue: 0,0:58:26.90,0:58:28.15,EN,,0,0,0,,I don't have time. Dialogue: 0,0:58:32.00,0:58:34.19,EN,,0,0,0,,There's no concept if it's going to alternate, Dialogue: 0,0:58:34.19,0:58:36.54,EN,,0,0,0,,except if nobody's there, it's going to wait a while for him. Dialogue: 0,0:58:38.42,0:58:41.36,EN,,0,0,0,,It's just going to say I have the stream of requests, Dialogue: 0,0:58:41.74,0:58:43.34,EN,,0,0,0,,the timeless infinite streams Dialogue: 0,0:58:43.36,0:58:45.29,EN,,0,0,0,,of all the requests that Dave would have made, right? Dialogue: 0,0:58:47.55,0:58:50.41,EN,,0,0,0,,And the timeless infinite stream of all the requests Bill would have made, Dialogue: 0,0:58:50.54,0:58:51.69,EN,,0,0,0,,and I want to operate on them. Dialogue: 0,0:58:51.69,0:58:53.51,EN,,0,0,0,,See, that's how this bank account is working. Dialogue: 0,0:58:56.71,0:58:57.58,EN,,0,0,0,,And the problem is Dialogue: 0,0:58:57.61,0:59:00.75,EN,,0,0,0,,that these poor people who are sitting at the bank account windows Dialogue: 0,0:59:00.76,0:59:03.82,EN,,0,0,0,,have the misfortune to exist in time. Dialogue: 0,0:59:05.29,0:59:07.13,EN,,0,0,0,,They don't see their infinite stream Dialogue: 0,0:59:07.69,0:59:09.53,EN,,0,0,0,,of all the requests they would have ever made. Dialogue: 0,0:59:10.07,0:59:11.55,EN,,0,0,0,,They're waiting now, and they want an answer. Dialogue: 0,0:59:14.48,0:59:15.76,EN,,0,0,0,,So if you're sitting there-- Dialogue: 0,0:59:16.24,0:59:20.86,EN,,0,0,0,,if this is the screen operation on some time-sharing system Dialogue: 0,0:59:21.52,0:59:22.60,EN,,0,0,0,,and it's working functionally, Dialogue: 0,0:59:22.64,0:59:24.59,EN,,0,0,0,,you want an answer then when you talk the character. Dialogue: 0,0:59:25.29,0:59:27.42,EN,,0,0,0,,You don't want it to have to wait for everybody in the whole system Dialogue: 0,0:59:27.45,0:59:29.92,EN,,0,0,0,,to have typed one character before it can get around to service you. Dialogue: 0,0:59:30.91,0:59:31.92,EN,,0,0,0,,So that's the problem. Dialogue: 0,0:59:34.00,0:59:36.38,EN,,0,0,0,,I mean, the fact that people live in time, apparently. Dialogue: 0,0:59:37.21,0:59:38.62,EN,,0,0,0,,If they didn't, it wouldn't be a problem. Dialogue: 0,0:59:49.10,0:59:51.02,EN,,0,0,0,,AUDIENCE: I'm afraid I miss the point of Dialogue: 0,0:59:51.08,0:59:54.24,EN,,0,0,0,,having no time in this banking transaction. Dialogue: 0,0:59:54.74,0:59:56.65,EN,,0,0,0,,Isn't time very important? Dialogue: 0,0:59:56.88,0:59:59.05,EN,,0,0,0,,For instance, the sequence of events. Dialogue: 0,0:59:59.95,1:00:05.02,EN,,0,0,0,,As if, If Dave take out $100, and then Dialogue: 0,1:00:06.30,1:00:08.40,EN,,0,0,0,,then the timing sequence should be important. Dialogue: 0,1:00:08.40,1:00:10.86,EN,,0,0,0,,How do you treat transactions as streams? Dialogue: 0,1:00:11.26,1:00:14.26,EN,,0,0,0,,PROFESSOR: Well, that's the thing I'm saying. Dialogue: 0,1:00:14.26,1:00:15.61,EN,,0,0,0,,This is an example where you can't. Dialogue: 0,1:00:17.51,1:00:18.12,EN,,0,0,0,,You can't. Dialogue: 0,1:00:18.16,1:00:20.08,EN,,0,0,0,,What goes, The point is what comes out of here Dialogue: 0,1:00:20.24,1:00:21.88,EN,,0,0,0,,is simply not a function of the stream going in here Dialogue: 0,1:00:21.92,1:00:23.60,EN,,0,0,0,,going in here and the stream going in here. Dialogue: 0,1:00:24.17,1:00:25.98,EN,,0,0,0,,It's a function of the stream going in here Dialogue: 0,1:00:26.19,1:00:27.26,EN,,0,0,0,,and the stream going in here Dialogue: 0,1:00:27.36,1:00:29.07,EN,,0,0,0,,and some kind of information about time, Dialogue: 0,1:00:29.37,1:00:32.36,EN,,0,0,0,,which is precisely what a normal-order language won't let you say. Dialogue: 0,1:00:34.81,1:00:37.95,EN,,0,0,0,,AUDIENCE: In order to brings this back into a more functional perspective, Dialogue: 0,1:00:38.54,1:00:42.04,EN,,0,0,0,,could we just explicitly time stamp all the inputs from Bill and Dave Dialogue: 0,1:00:42.54,1:00:46.40,EN,,0,0,0,,and define fair merge to just be the sort on those time stamps? Dialogue: 0,1:00:48.41,1:00:49.55,EN,,0,0,0,,PROFESSOR: Yeah, you can do that. Dialogue: 0,1:00:49.55,1:00:50.60,EN,,0,0,0,,You can do that sort of thing. Dialogue: 0,1:00:50.60,1:00:52.56,EN,,0,0,0,,Another thing you could say is imagine Dialogue: 0,1:00:52.76,1:00:54.44,EN,,0,0,0,,that really what this function is, Dialogue: 0,1:00:54.78,1:00:56.88,EN,,0,0,0,,is that it does a read every microsecond, Dialogue: 0,1:00:58.86,1:00:59.93,EN,,0,0,0,,and then if there's none there, Dialogue: 0,1:00:59.93,1:01:00.97,EN,,0,0,0,,that's considered an empty one. Dialogue: 0,1:01:00.97,1:01:03.39,EN,,0,0,0,,That's about equivalent to what you said. Dialogue: 0,1:01:03.61,1:01:06.08,EN,,0,0,0,,And yes, you can do that, but that's a glitch. Dialogue: 0,1:01:07.11,1:01:10.14,EN,,0,0,0,,So it's not quite only implementation we're worried about. Dialogue: 0,1:01:10.76,1:01:12.73,EN,,0,0,0,,We're worried about expressive power in the language, Dialogue: 0,1:01:12.75,1:01:14.67,EN,,0,0,0,,and what we're running across is a real mismatch Dialogue: 0,1:01:14.99,1:01:17.44,EN,,0,0,0,,between what we can say easily and what we'd like to say. Dialogue: 0,1:01:19.88,1:01:22.01,EN,,0,0,0,,AUDIENCE: It sounds like where we're getting hung up with that Dialogue: 0,1:01:22.06,1:01:26.09,EN,,0,0,0,,one input from both Bill and Dave at the same time. Dialogue: 0,1:01:26.12,1:01:28.43,EN,,0,0,0,,PROFESSOR: It's not quite one, but it's anything you define. Dialogue: 0,1:01:28.53,1:01:30.57,EN,,0,0,0,,So you can say Dave can go twice as often, Dialogue: 0,1:01:30.72,1:01:32.32,EN,,0,0,0,,but if anything you predefine, Dialogue: 0,1:01:32.68,1:01:33.87,EN,,0,0,0,,it's not the right thing. Dialogue: 0,1:01:36.11,1:01:40.70,EN,,0,0,0,,You can't decide at some particular function of their input requests. Dialogue: 0,1:01:41.93,1:01:43.37,EN,,0,0,0,,Worse yet, I mean, worse yet, Dialogue: 0,1:01:44.12,1:01:45.72,EN,,0,0,0,,there are things that even merge can't do. Dialogue: 0,1:01:47.29,1:01:49.69,EN,,0,0,0,,One thing you might want to do that's even more general is suddenly Dialogue: 0,1:01:50.24,1:01:52.47,EN,,0,0,0,,you add somebody else to this bank account system. Dialogue: 0,1:01:52.47,1:01:54.51,EN,,0,0,0,,You go and you add John to this bank account system. Dialogue: 0,1:01:56.03,1:01:58.89,EN,,0,0,0,,And now there's yet another stream that's going to come into the picture Dialogue: 0,1:01:58.91,1:02:00.70,EN,,0,0,0,,at some time which we haven't prespecified. Dialogue: 0,1:02:02.04,1:02:04.00,EN,,0,0,0,,So that's something even fair merge can't do, Dialogue: 0,1:02:04.00,1:02:08.25,EN,,0,0,0,,and they're things called-- I forget-- manager or something. Dialogue: 0,1:02:08.86,1:02:11.79,EN,,0,0,0,,That's a generalization of fair merge to allow that. Dialogue: 0,1:02:11.79,1:02:13.98,EN,,0,0,0,,There's a whole sort of research discipline saying Dialogue: 0,1:02:14.00,1:02:16.30,EN,,0,0,0,,how far can you push this functional perspective Dialogue: 0,1:02:16.59,1:02:18.72,EN,,0,0,0,,by adding more and more mechanism? Dialogue: 0,1:02:19.58,1:02:21.79,EN,,0,0,0,,And how far does that go before the whole thing breaks down Dialogue: 0,1:02:21.82,1:02:23.40,EN,,0,0,0,,and you might as well been using set anyway. Dialogue: 0,1:02:25.98,1:02:28.00,EN,,0,0,0,,AUDIENCE: But not automatic deposit. Dialogue: 0,1:02:39.32,1:02:40.49,EN,,0,0,0,,PROFESSOR: OK, thank you. Dialogue: 0,0:00:00.03,0:00:03.10,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:04.09,0:00:12.08,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:04.09,0:00:12.08,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N张大伟\N(DreamAndDead) Dialogue: 0,0:00:04.09,0:00:12.08,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.09,0:00:12.08,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:04.09,0:00:12.08,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:12.54,0:00:17.00,Declare,,0,0,0,,{\an2\fad(500,500)}流 II Dialogue: 0,0:00:20.97,0:00:24.08,Default,,0,0,0,,教授:上节课 我们介绍了流 Dialogue: 0,0:00:24.08,0:00:27.82,Default,,0,0,0,,按照信号处理的方式来组织系统 Dialogue: 0,0:00:28.87,0:00:31.42,Default,,0,0,0,,要记住的是 关键点在于 Dialogue: 0,0:00:31.90,0:00:32.96,Default,,0,0,0,,我们分离开 Dialogue: 0,0:00:34.20,0:00:37.31,Default,,0,0,0,,程序中 事件表面上的顺序 Dialogue: 0,0:00:37.58,0:00:40.17,Default,,0,0,0,,与机器中的实际计算顺序 Dialogue: 0,0:00:41.07,0:00:42.28,Default,,0,0,0,,那就意味着 我们可以 Dialogue: 0,0:00:42.57,0:00:44.14,Default,,0,0,0,,着手处理非常长的流 Dialogue: 0,0:00:44.89,0:00:47.39,Default,,0,0,0,,并且只有在需要的时候才生成其中的元素 Dialogue: 0,0:00:47.53,0:00:49.39,Default,,0,0,0,,这种按需计算的方式 Dialogue: 0,0:00:49.52,0:00:51.40,Default,,0,0,0,,是内建在流的数据结构中的 Dialogue: 0,0:00:54.11,0:00:55.64,Default,,0,0,0,,即使这个流非常之长 Dialogue: 0,0:00:55.66,0:00:57.08,Default,,0,0,0,,我们只计算所需要的 Dialogue: 0,0:00:58.04,0:01:00.75,Default,,0,0,0,,只有当我们要求的时候 新的数据才会生成 Dialogue: 0,0:01:00.75,0:01:01.74,Default,,0,0,0,,要举个什么样的例子呢? Dialogue: 0,0:01:02.11,0:01:03.60,Default,,0,0,0,,这个“按需”是什么个情况呢? Dialogue: 0,0:01:05.02,0:01:06.01,Default,,0,0,0,,举个例子 Dialogue: 0,0:01:09.21,0:01:11.37,Default,,0,0,0,,我们可能会想要一个流中的第N个元素 Dialogue: 0,0:01:15.36,0:01:18.92,Default,,0,0,0,,这个过程可以用于计算流的第N个元素 Dialogue: 0,0:01:20.09,0:01:21.23,Default,,0,0,0,,一个参数为索引N Dialogue: 0,0:01:21.24,0:01:22.84,Default,,0,0,0,,另一个参数是流S Dialogue: 0,0:01:23.40,0:01:25.42,Default,,0,0,0,,递归遍历这个流即可求解 Dialogue: 0,0:01:25.57,0:01:27.39,Default,,0,0,0,,如果N为0 我们就计算头部分 Dialogue: 0,0:01:27.96,0:01:30.99,Default,,0,0,0,,否则 就在流的尾部分 Dialogue: 0,0:01:31.74,0:01:32.80,Default,,0,0,0,,查找第N-1个元素 Dialogue: 0,0:01:34.31,0:01:36.43,Default,,0,0,0,,看起来是Lisp中很普通的编程方式 但是不同的是 Dialogue: 0,0:01:36.62,0:01:38.76,Default,,0,0,0,,直到我们不断遍历 取得相继的N个元素 Dialogue: 0,0:01:38.86,0:01:40.99,Default,,0,0,0,,这些元素才被计算出来 Dialogue: 0,0:01:41.52,0:01:44.78,Default,,0,0,0,,这是这些流元素可能被FORCE的一种方式 Dialogue: 0,0:01:45.77,0:01:46.64,Default,,0,0,0,,另外一种方式则是 Dialogue: 0,0:01:47.18,0:01:48.92,Default,,0,0,0,,这里有个简单的过程 用来打印一个流 Dialogue: 0,0:01:49.30,0:01:50.38,Default,,0,0,0,,它的定义是 Dialogue: 0,0:01:51.90,0:01:53.28,Default,,0,0,0,,过程PRINT-STREAM的定义是 Dialogue: 0,0:01:54.15,0:01:55.12,Default,,0,0,0,,我们要怎么做呢? Dialogue: 0,0:01:55.74,0:01:56.86,Default,,0,0,0,,先打印流的头部分 Dialogue: 0,0:01:57.74,0:01:59.32,Default,,0,0,0,,流的头部分在这时就被计算出来 Dialogue: 0,0:01:59.72,0:02:02.84,Default,,0,0,0,,然后我们再递归地打印流的尾部分 Dialogue: 0,0:02:04.99,0:02:06.03,Default,,0,0,0,,完成以后 Dialogue: 0,0:02:06.04,0:02:08.57,Default,,0,0,0,,就返回一个的表示完成的消息 “DONE” Dialogue: 0,0:02:09.66,0:02:11.39,Default,,0,0,0,,如果你构造了一个流 Dialogue: 0,0:02:11.64,0:02:13.64,Default,,0,0,0,,这个流非常的长 Dialogue: 0,0:02:14.31,0:02:16.33,Default,,0,0,0,,当你调用这个过程 Dialogue: 0,0:02:16.41,0:02:19.77,Default,,0,0,0,,流中的元素会随着PRINT-STREAM的调用 Dialogue: 0,0:02:19.87,0:02:21.12,Default,,0,0,0,,而被依次计算出来 Dialogue: 0,0:02:21.32,0:02:22.81,Default,,0,0,0,,不会在一开始就全部计算出来 Dialogue: 0,0:02:24.30,0:02:25.66,Default,,0,0,0,,正因为如此 我们能够 Dialogue: 0,0:02:27.50,0:02:29.61,Default,,0,0,0,,我们能够处理非常长的流 Dialogue: 0,0:02:30.19,0:02:31.92,Default,,0,0,0,,多长呢? Dialogue: 0,0:02:33.74,0:02:35.12,Default,,0,0,0,,可以是无限长 Dialogue: 0,0:02:35.90,0:02:38.04,Default,,0,0,0,,我们在计算机上实践一下 Dialogue: 0,0:02:38.92,0:02:41.96,Default,,0,0,0,,我可以在计算机前输入 Dialogue: 0,0:02:43.48,0:02:53.31,Default,,0,0,0,,我先定义一个函数 (INTEGERS-FROM N) Dialogue: 0,0:02:54.24,0:02:57.13,Default,,0,0,0,,用于生成一个从N开始的正整数流 Dialogue: 0,0:03:00.36,0:03:19.16,Default,,0,0,0,,也就是 (CONS-STREAM N (INTEGERS-FROM (+ N 1)))) Dialogue: 0,0:03:24.41,0:03:25.61,Default,,0,0,0,,这样就我们要的全部整数 Dialogue: 0,0:03:28.99,0:03:31.50,Default,,0,0,0,,现在我来尝试得到所有的整数 Dialogue: 0,0:03:34.57,0:03:44.33,Default,,0,0,0,,(DEFINE INTEGERS (INTEGERS-FROM 1)) Dialogue: 0,0:03:48.84,0:03:50.94,Default,,0,0,0,,如果现在我执行 (NTH-STREAM 20 INTEGERS) Dialogue: 0,0:03:54.41,0:03:55.80,Default,,0,0,0,,来查看第20个元素 Dialogue: 0,0:04:03.42,0:04:05.53,Default,,0,0,0,,得到21 因为索引是从0开始的 Dialogue: 0,0:04:06.84,0:04:08.88,Default,,0,0,0,,或者我们来点更复杂的 Dialogue: 0,0:04:09.45,0:04:10.84,Default,,0,0,0,,我再来定义一个谓词 Dialogue: 0,0:04:11.77,0:04:18.51,Default,,0,0,0,,谓词NO-SEVEN用来检测是否为7的倍数 Dialogue: 0,0:04:19.58,0:04:20.75,Default,,0,0,0,,它的判定方法是这样的: Dialogue: 0,0:04:21.79,0:04:23.16,Default,,0,0,0,,如果整数X不是7的倍数 Dialogue: 0,0:04:28.82,0:04:33.96,Default,,0,0,0,,我取X除7的余数 Dialogue: 0,0:04:36.62,0:04:38.35,Default,,0,0,0,,余数不应该为0 Dialogue: 0,0:04:43.80,0:04:49.77,Default,,0,0,0,,这时用NO-SEVEN这个谓词 Dialogue: 0,0:04:50.22,0:04:59.12,Default,,0,0,0,,过滤全部的整数 Dialogue: 0,0:05:11.57,0:05:13.34,Default,,0,0,0,,这样我就得到了所有的 Dialogue: 0,0:05:13.63,0:05:15.05,Default,,0,0,0,,不是7的倍数的整数构成的流 Dialogue: 0,0:05:16.49,0:05:23.44,Default,,0,0,0,,如果我问 这些不是7的倍数的整数中 Dialogue: 0,0:05:24.70,0:05:26.48,Default,,0,0,0,,的第100个数是多少? Dialogue: 0,0:05:26.86,0:05:28.11,Default,,0,0,0,,结果是117 Dialogue: 0,0:05:28.32,0:05:30.67,Default,,0,0,0,,或者我也可以问 Dialogue: 0,0:05:32.30,0:05:34.38,Default,,0,0,0,,这个流的所有元素都是些什么? Dialogue: 0,0:05:35.27,0:05:40.35,Default,,0,0,0,,我可以用(PRINT-STREAM NS)来尝试打印这个流 Dialogue: 0,0:05:40.83,0:05:41.79,Default,,0,0,0,,它就会输出个不停 Dialogue: 0,0:05:45.10,0:05:47.07,Default,,0,0,0,,你可能需要等上很久才能得到全部结果 Dialogue: 0,0:05:52.67,0:05:53.84,Default,,0,0,0,,你可能会问了 Dialogue: 0,0:05:54.81,0:05:57.00,Default,,0,0,0,,这个数据结构 Dialogue: 0,0:05:58.28,0:06:00.65,Default,,0,0,0,,真的全部是由整数构成的吗? Dialogue: 0,0:06:01.10,0:06:04.05,Default,,0,0,0,,现在我画一个图来演示下刚写的那个程序 Dialogue: 0,0:06:04.96,0:06:10.57,Default,,0,0,0,,这是我刚才键入的整数定义 Dialogue: 0,0:06:12.33,0:06:15.98,Default,,0,0,0,,它是一个由第一个整数和由下一个整数生成的流 所构成的序对 Dialogue: 0,0:06:17.61,0:06:19.77,Default,,0,0,0,,现在我们画个图来看看它到底是什么样 Dialogue: 0,0:06:22.72,0:06:24.32,Default,,0,0,0,,从概念上来说 这应该是一个盒子 Dialogue: 0,0:06:25.53,0:06:27.18,Default,,0,0,0,,这个盒子是(INTEGER-FROM N) Dialogue: 0,0:06:27.42,0:06:29.08,Default,,0,0,0,,它接受一个参数N Dialogue: 0,0:06:31.42,0:06:32.97,Default,,0,0,0,,然后返回一个流 Dialogue: 0,0:06:35.02,0:06:37.36,Default,,0,0,0,,这个无穷流表示从N开始的所有整数 Dialogue: 0,0:06:38.08,0:06:38.73,Default,,0,0,0,,我要做什么呢? Dialogue: 0,0:06:38.75,0:06:42.38,Default,,0,0,0,,呃 这个是INT-FROM盒子 Dialogue: 0,0:06:45.07,0:06:45.80,Default,,0,0,0,,里面是什么样子呢? Dialogue: 0,0:06:45.80,0:06:48.60,Default,,0,0,0,,取得参数N之后 Dialogue: 0,0:06:52.27,0:06:53.92,Default,,0,0,0,,将其 +1 Dialogue: 0,0:06:57.95,0:07:03.15,Default,,0,0,0,,然后把结果递归地传递给另一个INT-FROM盒子 Dialogue: 0,0:07:06.87,0:07:09.60,Default,,0,0,0,,把这个盒子的结果和最初的N Dialogue: 0,0:07:10.24,0:07:12.78,Default,,0,0,0,,用CONS组合起来 Dialogue: 0,0:07:13.39,0:07:14.36,Default,,0,0,0,,就形成了一个流 Dialogue: 0,0:07:14.57,0:07:17.26,Default,,0,0,0,,我刚才写的那个过程 画出来就是这样子 Dialogue: 0,0:07:18.52,0:07:20.32,Default,,0,0,0,,我们看到的这类图像 Dialogue: 0,0:07:20.78,0:07:21.74,Default,,0,0,0,,首先是由Peter Henderson提出的 Dialogue: 0,0:07:21.76,0:07:23.32,Default,,0,0,0,,也就是前面课程中绘图语言的发明者 Dialogue: 0,0:07:23.32,0:07:24.75,Default,,0,0,0,,我们把这种图叫做Henderson图 Dialogue: 0,0:07:25.37,0:07:27.90,Default,,0,0,0,,画这种图需要遵守一定的约定 Dialogue: 0,0:07:28.53,0:07:32.51,Default,,0,0,0,,这些实线代表输出的流 Dialogue: 0,0:07:33.02,0:07:36.20,Default,,0,0,0,,这些虚线则是初始的输入值 Dialogue: 0,0:07:37.27,0:07:39.02,Default,,0,0,0,,而这个图描述的形状是—— Dialogue: 0,0:07:39.40,0:07:41.60,Default,,0,0,0,,它会取一个整数作为初始值 Dialogue: 0,0:07:41.80,0:07:42.91,Default,,0,0,0,,然后输出一个流 Dialogue: 0,0:07:46.35,0:07:48.22,Default,,0,0,0,,现在 你可能又要问了 Dialogue: 0,0:07:48.38,0:07:50.88,Default,,0,0,0,,那个INTEGERS的数据结构真的全部都是整数吗? Dialogue: 0,0:07:52.09,0:07:54.91,Default,,0,0,0,,或者它只是经过了精心组织 Dialogue: 0,0:07:54.94,0:07:56.43,Default,,0,0,0,,以至于总可以在其中找到 Dialogue: 0,0:07:56.44,0:07:57.24,Default,,0,0,0,,我们需要的那个整数? Dialogue: 0,0:07:57.95,0:07:59.74,Default,,0,0,0,,这有点像个哲学问题 不是么? Dialogue: 0,0:07:59.78,0:08:01.69,Default,,0,0,0,,如果有一个东西 Dialogue: 0,0:08:02.14,0:08:03.96,Default,,0,0,0,,你不去观测它 能否知道它“存在”呢? Dialogue: 0,0:08:04.45,0:08:07.34,Default,,0,0,0,,这就有点像 Dialogue: 0,0:08:07.36,0:08:09.42,Default,,0,0,0,,你在银行中的存款那样 Dialogue: 0,0:08:12.38,0:08:12.64,Default,,0,0,0,,好吧 Dialogue: 0,0:08:16.35,0:08:17.48,Default,,0,0,0,,我们再来看一个例子 Dialogue: 0,0:08:18.68,0:08:20.70,Default,,0,0,0,,这门课的第一节课 Dialogue: 0,0:08:20.72,0:08:22.72,Default,,0,0,0,,我们就讲了一个来自于亚历山大的算法 Dialogue: 0,0:08:23.29,0:08:25.80,Default,,0,0,0,,来自亚历山大的Heron提出的 Dialogue: 0,0:08:25.82,0:08:26.94,Default,,0,0,0,,一个用于计算平方根的算法 Dialogue: 0,0:08:28.47,0:08:32.03,Default,,0,0,0,,现在再来看一个 同样来自于亚力山大的算法 Dialogue: 0,0:08:32.03,0:08:35.08,Default,,0,0,0,,这个被称为Eratosthenes算法的方法 Dialogue: 0,0:08:36.19,0:08:38.44,Default,,0,0,0,,用于计算所有的质数 Dialogue: 0,0:08:41.16,0:08:42.83,Default,,0,0,0,,它被称为Eratosthenes筛法 Dialogue: 0,0:08:42.83,0:08:49.72,Default,,0,0,0,,它是这样的 一开始 Dialogue: 0,0:08:50.99,0:08:52.28,Default,,0,0,0,,先列举所有的整数 Dialogue: 0,0:08:52.60,0:08:53.53,Default,,0,0,0,,从2开始 Dialogue: 0,0:08:53.88,0:08:55.04,Default,,0,0,0,,然后取第一个整数 Dialogue: 0,0:08:55.08,0:08:56.67,Default,,0,0,0,,然后你发现 哦 2是一个质数 Dialogue: 0,0:08:57.31,0:08:58.35,Default,,0,0,0,,然后你考察剩余的整数 Dialogue: 0,0:08:58.68,0:09:00.88,Default,,0,0,0,,划掉其中可以被2整除的数 Dialogue: 0,0:09:01.52,0:09:04.73,Default,,0,0,0,,我把这个划掉 还有这个 这个 Dialogue: 0,0:09:05.25,0:09:06.35,Default,,0,0,0,,有点费时 Dialogue: 0,0:09:06.36,0:09:08.91,Default,,0,0,0,,我要对所有的整数进行这样的操作 Dialogue: 0,0:09:11.16,0:09:15.39,Default,,0,0,0,,我遍历整个整数表 Dialogue: 0,0:09:18.27,0:09:20.94,Default,,0,0,0,,划掉所有被2整除的数 Dialogue: 0,0:09:22.11,0:09:24.38,Default,,0,0,0,,所有的整数都操作完后 Dialogue: 0,0:09:24.78,0:09:26.72,Default,,0,0,0,,回过头再来看还剩些什么 Dialogue: 0,0:09:27.04,0:09:28.80,Default,,0,0,0,,好的 下一个数就是3了 Dialogue: 0,0:09:29.33,0:09:30.33,Default,,0,0,0,,3也是一个质数 Dialogue: 0,0:09:30.77,0:09:33.05,Default,,0,0,0,,现在 我会继续在剩下的数中 Dialogue: 0,0:09:33.36,0:09:35.07,Default,,0,0,0,,划掉所有被3整除的数 Dialogue: 0,0:09:35.08,0:09:43.80,Default,,0,0,0,,划掉 9、15、21、27、33 等等 Dialogue: 0,0:09:44.33,0:09:45.12,Default,,0,0,0,,我就不往下划了 Dialogue: 0,0:09:45.35,0:09:46.52,Default,,0,0,0,,然后看看我们还剩下什么 Dialogue: 0,0:09:47.25,0:09:49.84,Default,,0,0,0,,而下一个就是5了 Dialogue: 0,0:09:50.49,0:09:52.04,Default,,0,0,0,,我又遍历剩下的数 Dialogue: 0,0:09:52.43,0:09:54.51,Default,,0,0,0,,找到第一个能被5整除的数 Dialogue: 0,0:09:54.54,0:09:57.61,Default,,0,0,0,,把剩下的能被5整除的数都划掉 Dialogue: 0,0:09:58.35,0:09:59.24,Default,,0,0,0,,做完这个之后 Dialogue: 0,0:09:59.82,0:10:01.89,Default,,0,0,0,,下一个数就是7 Dialogue: 0,0:10:01.89,0:10:02.72,Default,,0,0,0,,再遍历剩下的数 Dialogue: 0,0:10:02.76,0:10:03.95,Default,,0,0,0,,划掉所有被7整除的数 Dialogue: 0,0:10:03.98,0:10:05.47,Default,,0,0,0,,然后一直这样下去 Dialogue: 0,0:10:06.81,0:10:07.40,Default,,0,0,0,,全部结束的时候 Dialogue: 0,0:10:07.40,0:10:09.10,Default,,0,0,0,,我也就得到了所有的质数 Dialogue: 0,0:10:09.90,0:10:13.31,Default,,0,0,0,,这就是Eratosthenes筛法 Dialogue: 0,0:10:15.43,0:10:17.69,Default,,0,0,0,,我们来看下实际代码 Dialogue: 0,0:10:17.93,0:10:19.85,Default,,0,0,0,,这个过程命名为SIEVE Dialogue: 0,0:10:27.91,0:10:29.40,Default,,0,0,0,,这是对应的代码 Dialogue: 0,0:10:30.33,0:10:34.48,Default,,0,0,0,,SIEVE过程 以一个流S为参数 Dialogue: 0,0:10:38.77,0:10:39.93,Default,,0,0,0,,返回一个新的流 Dialogue: 0,0:10:40.27,0:10:41.84,Default,,0,0,0,,新的流的头部分 就是流S的头部分 Dialogue: 0,0:10:41.87,0:10:44.43,Default,,0,0,0,,回忆一下 我总是取剩下的数中的第一个 Dialogue: 0,0:10:44.91,0:10:48.75,Default,,0,0,0,,而尾部分则是把流S的尾部分 Dialogue: 0,0:10:51.08,0:10:53.72,Default,,0,0,0,,过滤掉所有 Dialogue: 0,0:10:53.74,0:10:55.32,Default,,0,0,0,,能被S头部分整除的数 Dialogue: 0,0:10:56.41,0:10:57.56,Default,,0,0,0,,然后再对结果筛选 Dialogue: 0,0:10:59.02,0:11:00.09,Default,,0,0,0,,这个代码就是这样 Dialogue: 0,0:11:01.98,0:11:04.68,Default,,0,0,0,,现在 为了得到由质数构成的无穷流 Dialogue: 0,0:11:05.02,0:11:06.90,Default,,0,0,0,,我们对从2开始的整数流进行SIEVE Dialogue: 0,0:11:14.92,0:11:15.56,Default,,0,0,0,,我们来实践一下 Dialogue: 0,0:11:16.30,0:11:18.30,Default,,0,0,0,,实际上 我们可以在计算机中运行 Dialogue: 0,0:11:19.76,0:11:22.12,Default,,0,0,0,,我希望我已经预先输入过SIEVE的定义了 Dialogue: 0,0:11:22.86,0:11:24.06,Default,,0,0,0,,所以我可以定义 Dialogue: 0,0:11:24.92,0:11:33.45,Default,,0,0,0,,我可以把PRIMES定义为 Dialogue: 0,0:11:34.64,0:11:41.45,Default,,0,0,0,,(SIEVE (INTEGERS-FROM 2)) Dialogue: 0,0:11:46.76,0:11:48.10,Default,,0,0,0,,现在我就得到了质数构成的表 Dialogue: 0,0:11:48.10,0:11:50.99,Default,,0,0,0,,这样就得到了所有的质数 对吧? Dialogue: 0,0:11:50.99,0:11:53.52,Default,,0,0,0,,比如我可以问 第20个质数是什么? Dialogue: 0,0:12:00.73,0:12:01.68,Default,,0,0,0,,结果是73 Dialogue: 0,0:12:02.54,0:12:03.34,Default,,0,0,0,,那个短促的停顿 Dialogue: 0,0:12:03.36,0:12:04.92,Default,,0,0,0,,这是因为 Dialogue: 0,0:12:04.94,0:12:06.43,Default,,0,0,0,,在我询问第20个元素时 Dialogue: 0,0:12:06.46,0:12:07.68,Default,,0,0,0,,它才进行实际的计算 Dialogue: 0,0:12:10.37,0:12:11.29,Default,,0,0,0,,在这里 我也可以要求 Dialogue: 0,0:12:13.80,0:12:14.88,Default,,0,0,0,,打印所有的质数 Dialogue: 0,0:12:22.64,0:12:24.40,Default,,0,0,0,,解释器就开始计算并打印所有的质数 Dialogue: 0,0:12:25.35,0:12:26.28,Default,,0,0,0,,得花上好一会儿 Dialogue: 0,0:12:26.28,0:12:27.61,Default,,0,0,0,,才能打赢完整 Dialogue: 0,0:12:27.79,0:12:28.57,Default,,0,0,0,,所以先把它停掉 Dialogue: 0,0:12:32.03,0:12:33.13,Default,,0,0,0,,让我来画图演示一下 Dialogue: 0,0:12:33.13,0:12:34.17,Default,,0,0,0,,我已经画好了 Dialogue: 0,0:12:34.89,0:12:36.19,Default,,0,0,0,,这个过程的图形应该是什么样子呢? Dialogue: 0,0:12:37.90,0:12:39.77,Default,,0,0,0,,用这类图形的约定来说 Dialogue: 0,0:12:39.82,0:12:40.54,Default,,0,0,0,,我有一个叫SIEVE的盒子 Dialogue: 0,0:12:42.61,0:12:43.56,Default,,0,0,0,,它是如何运作的呢? Dialogue: 0,0:12:43.56,0:12:44.81,Default,,0,0,0,,它以一个流作为输入 Dialogue: 0,0:12:48.85,0:12:50.59,Default,,0,0,0,,分离流的头、尾部分 Dialogue: 0,0:12:50.87,0:12:53.26,Default,,0,0,0,,从SIEVE盒子出来的第一个东西 Dialogue: 0,0:12:53.48,0:12:54.97,Default,,0,0,0,,就是原来流的头部分 Dialogue: 0,0:12:58.20,0:13:00.92,Default,,0,0,0,,头部分同样也用于这个盒子 Dialogue: 0,0:13:02.55,0:13:05.10,Default,,0,0,0,,这个盒子会过滤流的尾部分 Dialogue: 0,0:13:05.55,0:13:08.33,Default,,0,0,0,,过滤的依据是 能否被头部分整除 Dialogue: 0,0:13:09.53,0:13:11.18,Default,,0,0,0,,过滤得到的不可整除的那些数 Dialogue: 0,0:13:11.24,0:13:13.12,Default,,0,0,0,,再放入另一个SIEVE盒子 Dialogue: 0,0:13:13.90,0:13:15.13,Default,,0,0,0,,然后把它们组合输出 Dialogue: 0,0:13:15.13,0:13:16.89,Default,,0,0,0,,你可以把SIEVE想象为一个过滤器 Dialogue: 0,0:13:17.20,0:13:19.23,Default,,0,0,0,,只不过它是一个无穷递归的过滤器 Dialogue: 0,0:13:19.65,0:13:20.88,Default,,0,0,0,,这是因为在SIEVE盒子中 Dialogue: 0,0:13:21.52,0:13:22.60,Default,,0,0,0,,还有另外一个SIEVE盒子 Dialogue: 0,0:13:23.37,0:13:25.85,Default,,0,0,0,,内部的盒子里面还有另外一个SIEVE盒子 Dialogue: 0,0:13:27.13,0:13:28.96,Default,,0,0,0,,我们现在逐渐有了非常厉害的能力 Dialogue: 0,0:13:28.96,0:13:32.84,Default,,0,0,0,,我们开始把 信号处理的方法 Dialogue: 0,0:13:33.90,0:13:36.41,Default,,0,0,0,,和计算中的递归结合在一起 来建模世界 Dialogue: 0,0:13:37.42,0:13:39.82,Default,,0,0,0,,还有很多像是这样的事 Dialogue: 0,0:13:40.97,0:13:42.09,Default,,0,0,0,,好的 有什么问题吗? Dialogue: 0,0:13:48.19,0:13:49.16,Default,,0,0,0,,好吧 那我们休息一下 Dialogue: 0,0:13:49.64,0:14:04.12,Default,,0,0,0,,[音乐] Dialogue: 0,0:14:04.46,0:14:08.12,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:14:12.08,0:14:16.38,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:14:16.44,0:14:20.22,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:14:20.35,0:14:25.05,Declare,,0,0,0,,{\an2\fad(500,500)}流 II Dialogue: 0,0:14:28.65,0:14:30.36,Default,,0,0,0,,我们已经看了 Dialogue: 0,0:14:30.36,0:14:32.09,Default,,0,0,0,,好几个流式程序设计的例子 Dialogue: 0,0:14:34.79,0:14:39.21,Default,,0,0,0,,我们目前接触到的流过程 Dialogue: 0,0:14:39.72,0:14:41.32,Default,,0,0,0,,都有一个共同的特征 Dialogue: 0,0:14:41.49,0:14:43.63,Default,,0,0,0,,这些过程总是递归地 Dialogue: 0,0:14:44.16,0:14:46.49,Default,,0,0,0,,一次生成一个元素 Dialogue: 0,0:14:46.51,0:14:48.72,Default,,0,0,0,,再用CONS-STREAM连接起来 Dialogue: 0,0:14:49.15,0:14:50.86,Default,,0,0,0,,因此 我们一直把它当作是生成器 Dialogue: 0,0:14:50.92,0:14:53.63,Default,,0,0,0,,还有一种思考流式程序设计的方式 Dialogue: 0,0:14:53.79,0:14:56.96,Default,,0,0,0,,我们不认为程序是 Dialogue: 0,0:14:57.36,0:14:59.93,Default,,0,0,0,,沿着流逐一处理元素 Dialogue: 0,0:15:00.25,0:15:05.68,Default,,0,0,0,,而是一下子处理了整个流 Dialogue: 0,0:15:07.18,0:15:09.16,Default,,0,0,0,,我先来定义两个非常有用的过程 Dialogue: 0,0:15:09.23,0:15:11.50,Default,,0,0,0,,来帮助我说明 Dialogue: 0,0:15:12.41,0:15:13.60,Default,,0,0,0,,第一个过程是ADD-STREAMS Dialogue: 0,0:15:15.36,0:15:18.25,Default,,0,0,0,,它接受两个流作为参数 Dialogue: 0,0:15:18.81,0:15:20.88,Default,,0,0,0,,S1和S2 Dialogue: 0,0:15:22.30,0:15:24.67,Default,,0,0,0,,它生成一个新的流 Dialogue: 0,0:15:24.99,0:15:28.17,Default,,0,0,0,,其元素是两个流相应位置元素的和 Dialogue: 0,0:15:30.22,0:15:31.88,Default,,0,0,0,,相当于是“按元素”的加 Dialogue: 0,0:15:32.97,0:15:33.95,Default,,0,0,0,,如果其中一个流是空的 Dialogue: 0,0:15:33.96,0:15:35.39,Default,,0,0,0,,我们就返回另一个 Dialogue: 0,0:15:36.81,0:15:38.96,Default,,0,0,0,,否则 我们就构建一个新的流 Dialogue: 0,0:15:39.90,0:15:42.96,Default,,0,0,0,,新流的头部分是两个流头部分之和 Dialogue: 0,0:15:44.00,0:15:44.88,Default,,0,0,0,,而新流的尾部分 Dialogue: 0,0:15:46.00,0:15:48.62,Default,,0,0,0,,则是递归地加和尾部分 Dialogue: 0,0:15:50.09,0:15:52.73,Default,,0,0,0,,这就会产生“按元素”地加的效果 Dialogue: 0,0:15:53.15,0:15:57.04,Default,,0,0,0,,另一个过程是SCALE-STREAM Dialogue: 0,0:15:57.50,0:16:01.66,Default,,0,0,0,,SCALE-STREAM有两个参数 常数C和流S Dialogue: 0,0:16:04.11,0:16:06.62,Default,,0,0,0,,结果生成的流 Dialogue: 0,0:16:07.18,0:16:09.50,Default,,0,0,0,,就是将流S的所有元素乘上了C Dialogue: 0,0:16:09.71,0:16:11.21,Default,,0,0,0,,这很简单 就是一个MAP Dialogue: 0,0:16:12.20,0:16:16.22,Default,,0,0,0,,用到的函数是 X*C Dialogue: 0,0:16:16.35,0:16:17.80,Default,,0,0,0,,把这个函数MAP于整个流 Dialogue: 0,0:16:20.06,0:16:21.47,Default,,0,0,0,,有了这两个过程 Dialogue: 0,0:16:22.64,0:16:24.36,Default,,0,0,0,,我来给你们解释 什么叫做 Dialogue: 0,0:16:24.70,0:16:27.00,Default,,0,0,0,,“一下子处理整个流” Dialogue: 0,0:16:28.12,0:16:28.73,Default,,0,0,0,,我们来看这个 Dialogue: 0,0:16:30.20,0:16:30.92,Default,,0,0,0,,假设这样 Dialogue: 0,0:16:31.68,0:16:52.35,Default,,0,0,0,,(DEFINE ONES (CONS-STREAM 1 ONES)) Dialogue: 0,0:16:54.86,0:16:55.52,Default,,0,0,0,,这是什么? Dialogue: 0,0:16:56.95,0:16:58.94,Default,,0,0,0,,这是一个表示无穷个1的流 Dialogue: 0,0:16:59.96,0:17:01.44,Default,,0,0,0,,因为第一个元素是1 Dialogue: 0,0:17:03.33,0:17:05.15,Default,,0,0,0,,尾部分则是这样的 Dialogue: 0,0:17:05.55,0:17:06.83,Default,,0,0,0,,它的头部分是1 Dialogue: 0,0:17:07.63,0:17:09.02,Default,,0,0,0,,它的尾部分 Dialogue: 0,0:17:09.12,0:17:10.24,Default,,0,0,0,,的头部分又为1 Dialogue: 0,0:17:10.52,0:17:11.78,Default,,0,0,0,,以此类推 Dialogue: 0,0:17:11.78,0:17:13.32,Default,,0,0,0,,这就是无穷个1的流 Dialogue: 0,0:17:15.13,0:17:15.93,Default,,0,0,0,,现在根据ONES Dialogue: 0,0:17:16.12,0:17:18.03,Default,,0,0,0,,我再给出另一种定义整数的方式 Dialogue: 0,0:17:19.47,0:17:27.36,Default,,0,0,0,,(DEFINE INTEGERS Dialogue: 0,0:17:28.24,0:17:30.76,Default,,0,0,0,,当然 第一个数是1 Dialogue: 0,0:17:32.75,0:17:38.57,Default,,0,0,0,,(CONS-STREAM 1 (ADD-STREAM Dialogue: 0,0:17:40.22,0:17:48.27,Default,,0,0,0,,INTEGERS ONES))) Dialogue: 0,0:17:55.10,0:17:56.35,Default,,0,0,0,,整数流是这样的: Dialogue: 0,0:17:57.24,0:17:59.98,Default,,0,0,0,,它的第一个元素是1 Dialogue: 0,0:18:00.88,0:18:02.32,Default,,0,0,0,,而其余部分则是 Dialogue: 0,0:18:03.12,0:18:06.14,Default,,0,0,0,,依次把每个整数加1 Dialogue: 0,0:18:06.64,0:18:08.19,Default,,0,0,0,,因此 整数流的第二个元素则是 Dialogue: 0,0:18:08.51,0:18:11.96,Default,,0,0,0,,整数流的第一个元素加1 Dialogue: 0,0:18:13.92,0:18:15.18,Default,,0,0,0,,下一个数又要加1 Dialogue: 0,0:18:15.20,0:18:16.48,Default,,0,0,0,,第三个元素则是 Dialogue: 0,0:18:16.62,0:18:20.41,Default,,0,0,0,,INTEGER流尾部分的第一个元素 Dialogue: 0,0:18:20.84,0:18:21.96,Default,,0,0,0,,加1 Dialogue: 0,0:18:22.51,0:18:23.76,Default,,0,0,0,,这也就相当于 Dialogue: 0,0:18:25.08,0:18:28.65,Default,,0,0,0,,最初整数流的第一个元素加1 Dialogue: 0,0:18:28.86,0:18:31.25,Default,,0,0,0,,然后再加1 以此类推 Dialogue: 0,0:18:35.24,0:18:36.31,Default,,0,0,0,,这看起来有点匪夷所思 Dialogue: 0,0:18:36.31,0:18:37.47,Default,,0,0,0,,这样的过程可以正常运行 Dialogue: 0,0:18:38.12,0:18:38.99,Default,,0,0,0,,关键在于延时求值 Dialogue: 0,0:18:40.15,0:18:43.32,Default,,0,0,0,,我们来看这个ONES Dialogue: 0,0:18:43.87,0:18:45.92,Default,,0,0,0,,这看起来根本不可能 Dialogue: 0,0:18:46.25,0:18:47.63,Default,,0,0,0,,因为它突然说 Dialogue: 0,0:18:47.79,0:18:48.96,Default,,0,0,0,,在定义ONES的时候 Dialogue: 0,0:18:49.00,0:18:50.91,Default,,0,0,0,,发现它依赖于它本身 Dialogue: 0,0:18:51.13,0:18:52.08,Default,,0,0,0,,它之所以可以运行是因为 Dialogue: 0,0:18:52.09,0:18:54.04,Default,,0,0,0,,这里暗中隐藏着延时求值 Dialogue: 0,0:18:55.25,0:18:56.56,Default,,0,0,0,,这个代码实际上是 Dialogue: 0,0:18:57.79,0:18:59.69,Default,,0,0,0,,回忆下 CONS-STREAM是只是一个缩写 Dialogue: 0,0:19:00.29,0:19:01.15,Default,,0,0,0,,实际上则是 Dialogue: 0,0:19:01.85,0:19:08.99,Default,,0,0,0,,(CONS 1 (DELAY ONES)) Dialogue: 0,0:19:12.14,0:19:13.21,Default,,0,0,0,,它又是怎么运作的呢? Dialogue: 0,0:19:15.50,0:19:16.88,Default,,0,0,0,,你想要定义ONES Dialogue: 0,0:19:18.02,0:19:20.24,Default,,0,0,0,,我来看看ONES要被定义成什么样 Dialogue: 0,0:19:20.70,0:19:23.40,Default,,0,0,0,,ONES被定义为一个序对 Dialogue: 0,0:19:24.89,0:19:28.11,Default,,0,0,0,,其CAR部分为1 Dialogue: 0,0:19:28.32,0:19:29.45,Default,,0,0,0,,而CDR部分则是 Dialogue: 0,0:19:29.45,0:19:30.73,Default,,0,0,0,,是一个计算某物的PROMISE Dialogue: 0,0:19:30.75,0:19:31.69,Default,,0,0,0,,我现在还不用关心 Dialogue: 0,0:19:32.71,0:19:34.25,Default,,0,0,0,,所以虽然这时ONES还没有定义 Dialogue: 0,0:19:34.28,0:19:36.30,Default,,0,0,0,,但对我并不造成什么影响 Dialogue: 0,0:19:37.27,0:19:39.45,Default,,0,0,0,,一旦运行了整个定义 ONES就被定义了 Dialogue: 0,0:19:40.67,0:19:42.83,Default,,0,0,0,,所以 访问它尾部的时候 它就有定义了 Dialogue: 0,0:19:44.92,0:19:46.06,Default,,0,0,0,,这一点非常隐讳 Dialogue: 0,0:19:46.59,0:19:47.90,Default,,0,0,0,,整数流的定义也是如此 Dialogue: 0,0:19:48.47,0:19:50.46,Default,,0,0,0,,我可以在这里引用INTEGERS是因为 Dialogue: 0,0:19:51.13,0:19:53.21,Default,,0,0,0,,是因为这个CONS-STREAM的缘故 Dialogue: 0,0:19:53.85,0:19:55.24,Default,,0,0,0,,用CONS-STREAM把1 Dialogue: 0,0:19:55.37,0:19:57.05,Default,,0,0,0,,和一个不立即需要的东西组合起来 Dialogue: 0,0:19:57.05,0:19:59.60,Default,,0,0,0,,所以我在运行INTEGERS的定义的时候 Dialogue: 0,0:20:00.22,0:20:01.90,Default,,0,0,0,,并不会发现INTEGER没有定义过 Dialogue: 0,0:20:06.32,0:20:08.27,Default,,0,0,0,,听上去非常玄乎 Dialogue: 0,0:20:08.44,0:20:11.50,Default,,0,0,0,,让我用图像来演示一下INTEGERS的原理 Dialogue: 0,0:20:12.43,0:20:14.72,Default,,0,0,0,,怎么画呢? Dialogue: 0,0:20:15.02,0:20:16.30,Default,,0,0,0,,首先是ONES这个流 Dialogue: 0,0:20:20.51,0:20:21.88,Default,,0,0,0,,它作为参数输入 Dialogue: 0,0:20:23.26,0:20:24.92,Default,,0,0,0,,进入一个加法器 Dialogue: 0,0:20:24.96,0:20:26.59,Default,,0,0,0,,进行流的加法运算 Dialogue: 0,0:20:29.31,0:20:35.87,Default,,0,0,0,,输出则是整数流INTEGERS Dialogue: 0,0:20:40.76,0:20:42.70,Default,,0,0,0,,这里 这个整数流又重新进入加法器 Dialogue: 0,0:20:44.94,0:20:46.97,Default,,0,0,0,,形成了一个小型的反馈回路 Dialogue: 0,0:20:48.06,0:20:49.42,Default,,0,0,0,,我需要在某处接入最初的ONES Dialogue: 0,0:20:50.09,0:20:52.88,Default,,0,0,0,,才能让它生效 Dialogue: 0,0:20:57.10,0:20:58.64,Default,,0,0,0,,在真实的信号处理中 Dialogue: 0,0:20:58.72,0:21:02.48,Default,,0,0,0,,这里是一个被初始化为1的延时元件 Dialogue: 0,0:21:02.91,0:21:05.90,Default,,0,0,0,,这就是ONES程序的图示 Dialogue: 0,0:21:07.86,0:21:09.63,Default,,0,0,0,,事实上 这个非常像 Dialogue: 0,0:21:09.80,0:21:13.77,Default,,0,0,0,,如果你见过真正的信号方块图的话 Dialogue: 0,0:21:13.77,0:21:16.30,Default,,0,0,0,,这个图形非常像累加器 Dialogue: 0,0:21:16.35,0:21:17.48,Default,,0,0,0,,有穷状态累加器 Dialogue: 0,0:21:17.98,0:21:20.06,Default,,0,0,0,,事实上 我们可以稍加修改 Dialogue: 0,0:21:21.18,0:21:23.96,Default,,0,0,0,,就可以让它对一个流做积分 Dialogue: 0,0:21:25.37,0:21:26.97,Default,,0,0,0,,或者说是有穷状态累加器 Dialogue: 0,0:21:27.00,0:21:28.04,Default,,0,0,0,,你怎么认为都可以 Dialogue: 0,0:21:28.44,0:21:30.86,Default,,0,0,0,,现在 不再是输入ONES 输出INTEGERS Dialogue: 0,0:21:31.68,0:21:32.38,Default,,0,0,0,,我们要做的是 Dialogue: 0,0:21:32.91,0:21:34.83,Default,,0,0,0,,这里有一个流S为输入 Dialogue: 0,0:21:35.76,0:21:40.56,Default,,0,0,0,,我们要计算这个流的积分 Dialogue: 0,0:21:42.60,0:21:44.09,Default,,0,0,0,,也就是累加这个流的值 Dialogue: 0,0:21:44.44,0:21:45.63,Default,,0,0,0,,这看起来几乎就是一样的 Dialogue: 0,0:21:45.66,0:21:46.84,Default,,0,0,0,,我们要做的就是 Dialogue: 0,0:21:47.02,0:21:48.08,Default,,0,0,0,,当S从这里输入时 Dialogue: 0,0:21:49.21,0:21:50.64,Default,,0,0,0,,在把它求和之前 Dialogue: 0,0:21:50.91,0:21:54.26,Default,,0,0,0,,先将其乘以dt Dialogue: 0,0:21:57.68,0:22:00.00,Default,,0,0,0,,剩下的就不用改了 Dialogue: 0,0:22:00.00,0:22:00.91,Default,,0,0,0,,我们就得到了一个盒子 Dialogue: 0,0:22:03.36,0:22:04.56,Default,,0,0,0,,一个积分器 Dialogue: 0,0:22:09.79,0:22:11.26,Default,,0,0,0,,对一个流S进行积分 Dialogue: 0,0:22:11.90,0:22:14.51,Default,,0,0,0,,把这里的1替换为 Dialogue: 0,0:22:14.94,0:22:18.35,Default,,0,0,0,,该积分的初始值 Dialogue: 0,0:22:19.98,0:22:21.60,Default,,0,0,0,,这个看起来就非常像 Dialogue: 0,0:22:22.35,0:22:24.86,Default,,0,0,0,,信号处理中的方框图了 Dialogue: 0,0:22:25.27,0:22:28.11,Default,,0,0,0,,事实上 这个图示对应的是这样一个过程 Dialogue: 0,0:22:31.49,0:22:33.61,Default,,0,0,0,,对一个流进行积分 Dialogue: 0,0:22:34.01,0:22:35.48,Default,,0,0,0,,INTEGRAL函数接收一个流 Dialogue: 0,0:22:35.68,0:22:36.86,Default,,0,0,0,,返回一个新的流 Dialogue: 0,0:22:37.53,0:22:40.67,Default,,0,0,0,,它还接收一个初始值和某个时间常量 Dialogue: 0,0:22:42.23,0:22:42.97,Default,,0,0,0,,然后呢? Dialogue: 0,0:22:43.04,0:22:45.05,Default,,0,0,0,,首先在内部定义一个流INT Dialogue: 0,0:22:45.20,0:22:46.32,Default,,0,0,0,,之所以要给它一个内部名字 Dialogue: 0,0:22:46.33,0:22:48.86,Default,,0,0,0,,原因在于可以使它反馈 以形成循环 Dialogue: 0,0:22:49.40,0:22:50.80,Default,,0,0,0,,INT的定义是 Dialogue: 0,0:22:51.10,0:22:53.32,Default,,0,0,0,,一个以INITIA-VALUE开始的流 Dialogue: 0,0:22:54.97,0:23:00.14,Default,,0,0,0,,而其余的元素则是把它们加起来 Dialogue: 0,0:23:01.28,0:23:03.61,Default,,0,0,0,,我们把输入流乘以dt Dialogue: 0,0:23:03.87,0:23:04.92,Default,,0,0,0,,然后和INT相加 Dialogue: 0,0:23:06.88,0:23:09.66,Default,,0,0,0,,整个INTEGRAL函数的结果就是这个INT Dialogue: 0,0:23:10.69,0:23:12.94,Default,,0,0,0,,我们使用这种内部定义的语法 Dialogue: 0,0:23:13.34,0:23:15.66,Default,,0,0,0,,是为了可以在内部引用它自己 Dialogue: 0,0:23:21.88,0:23:23.71,Default,,0,0,0,,我们还可以做更多的事情 Dialogue: 0,0:23:23.71,0:23:24.51,Default,,0,0,0,,来看这个 Dialogue: 0,0:23:25.63,0:23:26.89,Default,,0,0,0,,斐波那契数 Dialogue: 0,0:23:26.89,0:23:32.62,Default,,0,0,0,,(DEFINE FIBS Dialogue: 0,0:23:36.35,0:23:37.63,Default,,0,0,0,,斐波那契数是什么呢? Dialogue: 0,0:23:37.98,0:23:46.54,Default,,0,0,0,,它从0开始 Dialogue: 0,0:23:48.65,0:23:50.09,Default,,0,0,0,,下一个是1 Dialogue: 0,0:23:56.26,0:23:59.16,Default,,0,0,0,,的其余的斐波那契数是通过 Dialogue: 0,0:23:59.87,0:24:11.00,Default,,0,0,0,,把它们的尾部分求和而得来 Dialogue: 0,0:24:17.57,0:24:19.28,Default,,0,0,0,,这样来定义斐波那契数 Dialogue: 0,0:24:20.58,0:24:21.43,Default,,0,0,0,,这是如何运作的呢? Dialogue: 0,0:24:21.43,0:24:24.19,Default,,0,0,0,,我们来试试 Dialogue: 0,0:24:24.20,0:24:26.49,Default,,0,0,0,,假如开始计算斐波那契数 Dialogue: 0,0:24:29.64,0:24:31.92,Default,,0,0,0,,首先告诉你 它以0和1开始 Dialogue: 0,0:24:35.79,0:24:38.22,Default,,0,0,0,,而0和1之后的数则是 Dialogue: 0,0:24:39.18,0:24:40.86,Default,,0,0,0,,通过加和两个流而得 Dialogue: 0,0:24:41.12,0:24:42.59,Default,,0,0,0,,一个流是FIBS本身 Dialogue: 0,0:24:44.06,0:24:45.69,Default,,0,0,0,,另一个是FIBS的尾部分 Dialogue: 0,0:24:49.12,0:24:51.16,Default,,0,0,0,,如果我知道这是以0和1起始的 Dialogue: 0,0:24:51.79,0:24:55.42,Default,,0,0,0,,我就能知道 FIBS是以0和1起始的 Dialogue: 0,0:24:55.74,0:24:57.40,Default,,0,0,0,,那么 FIBS的尾部分则应该以1开始 Dialogue: 0,0:24:58.36,0:24:59.45,Default,,0,0,0,,一旦我知道了这点 Dialogue: 0,0:24:59.66,0:25:02.11,Default,,0,0,0,,我就知道 FIBS的下一个数就是0+1=1 Dialogue: 0,0:25:02.96,0:25:04.60,Default,,0,0,0,,它也同样告诉我这里是1 Dialogue: 0,0:25:04.62,0:25:05.72,Default,,0,0,0,,这里也是1 Dialogue: 0,0:25:06.30,0:25:07.28,Default,,0,0,0,,知道了这些之后 Dialogue: 0,0:25:07.29,0:25:08.76,Default,,0,0,0,,我就知道下一个是2 Dialogue: 0,0:25:09.39,0:25:11.70,Default,,0,0,0,,这里是2 这里也是2 Dialogue: 0,0:25:11.70,0:25:12.56,Default,,0,0,0,,下一个是3 Dialogue: 0,0:25:14.72,0:25:15.79,Default,,0,0,0,,这里是3 Dialogue: 0,0:25:16.19,0:25:17.13,Default,,0,0,0,,这里是5 Dialogue: 0,0:25:18.67,0:25:19.96,Default,,0,0,0,,这个定义完全说得通 Dialogue: 0,0:25:21.50,0:25:22.78,Default,,0,0,0,,这个定义只有一行 Dialogue: 0,0:25:22.83,0:25:25.00,Default,,0,0,0,,当然 我也可以在计算机中 Dialogue: 0,0:25:25.00,0:25:26.62,Default,,0,0,0,,原原本本地键入计算机中 Dialogue: 0,0:25:27.04,0:25:28.94,Default,,0,0,0,,然后要求输出斐波那契数 Dialogue: 0,0:25:28.94,0:25:30.15,Default,,0,0,0,,然后它就会不断输出 Dialogue: 0,0:25:32.79,0:25:35.20,Default,,0,0,0,,这又像是在学习递归 Dialogue: 0,0:25:36.81,0:25:39.79,Default,,0,0,0,,过程可以被递归定义 Dialogue: 0,0:25:40.99,0:25:43.50,Default,,0,0,0,,我们也可以递归地定义数据对象 Dialogue: 0,0:25:45.16,0:25:46.92,Default,,0,0,0,,但你们一点儿不应该感到吃惊 Dialogue: 0,0:25:47.12,0:25:49.50,Default,,0,0,0,,因为现在 你们应该真正相信 Dialogue: 0,0:25:49.52,0:25:53.05,Default,,0,0,0,,过程与数据之间没有区别 Dialogue: 0,0:25:53.09,0:25:53.92,Default,,0,0,0,,事实上 就某种意义上来说 Dialogue: 0,0:25:53.93,0:25:56.41,Default,,0,0,0,,流也是由过程来实现的 Dialogue: 0,0:25:56.43,0:25:57.79,Default,,0,0,0,,只不过我们不把它看做过程而已 Dialogue: 0,0:25:58.21,0:26:00.38,Default,,0,0,0,,因此既然我们有递归过程 Dialogue: 0,0:26:00.70,0:26:03.63,Default,,0,0,0,,那么 有递归数据也就不足为奇了 Dialogue: 0,0:26:07.72,0:26:09.69,Default,,0,0,0,,虽然流非常简洁 Dialogue: 0,0:26:09.72,0:26:13.92,Default,,0,0,0,,但不幸的是 有些问题流无法解决 Dialogue: 0,0:26:14.99,0:26:16.48,Default,,0,0,0,,我来举个例子 Dialogue: 0,0:26:17.58,0:26:20.35,Default,,0,0,0,,同样地 我们来想象一下 Dialogue: 0,0:26:20.76,0:26:23.61,Default,,0,0,0,,我们正在构建求解微分方程的模拟计算机 Dialogue: 0,0:26:25.20,0:26:34.30,Default,,0,0,0,,比如求解方程 y' = y^2 Dialogue: 0,0:26:34.76,0:26:36.16,Default,,0,0,0,,我会给你一个初值 Dialogue: 0,0:26:36.39,0:26:38.03,Default,,0,0,0,,y(0) = 1 Dialogue: 0,0:26:41.48,0:26:44.06,Default,,0,0,0,,dt = .0001 Dialogue: 0,0:26:46.77,0:26:47.53,Default,,0,0,0,,很久之前 Dialogue: 0,0:26:48.00,0:26:50.65,Default,,0,0,0,,就有人构建模拟计算机 来解决这类问题 Dialogue: 0,0:26:51.36,0:26:53.02,Default,,0,0,0,,原理非常简单 Dialogue: 0,0:26:53.02,0:26:54.41,Default,,0,0,0,,你首先需要一个积分器 Dialogue: 0,0:27:00.04,0:27:01.69,Default,,0,0,0,,比如这个INT盒子 Dialogue: 0,0:27:03.05,0:27:06.48,Default,,0,0,0,,我们设定初始值 y(0) = 1 Dialogue: 0,0:27:08.53,0:27:10.92,Default,,0,0,0,,现在如果我们送入一个输入 就会得到输出 Dialogue: 0,0:27:10.96,0:27:13.16,Default,,0,0,0,,输出的结果就是y Dialogue: 0,0:27:14.25,0:27:16.96,Default,,0,0,0,,输入的是y的导数 Dialogue: 0,0:27:17.52,0:27:20.52,Default,,0,0,0,,在这里 导数 y' = y^2 Dialogue: 0,0:27:21.49,0:27:27.07,Default,,0,0,0,,如果我们用MAP把SQUARE映射在这些值上 Dialogue: 0,0:27:30.73,0:27:32.09,Default,,0,0,0,,然后把这个引过来 Dialogue: 0,0:27:36.28,0:27:38.48,Default,,0,0,0,,这个方块图 Dialogue: 0,0:27:38.57,0:27:41.08,Default,,0,0,0,,就是用于求解这个微分方程的模拟计算机 Dialogue: 0,0:27:42.91,0:27:44.80,Default,,0,0,0,,现在我们用代码 Dialogue: 0,0:27:44.80,0:27:46.78,Default,,0,0,0,,来表示下这个过程 Dialogue: 0,0:27:47.23,0:27:48.72,Default,,0,0,0,,这个图究竟表示的是什么呢? Dialogue: 0,0:27:49.39,0:27:58.30,Default,,0,0,0,,(DEFINE Y Dialogue: 0,0:28:04.28,0:28:11.68,Default,,0,0,0,,(INTEGRAL DY 1 .001)) Dialogue: 0,0:28:13.79,0:28:15.45,Default,,0,0,0,,接下来 Dialogue: 0,0:28:16.80,0:28:20.85,Default,,0,0,0,,通过MAP SQUARE 来表示dy Dialogue: 0,0:28:20.85,0:28:32.81,Default,,0,0,0,,(DEFINE DY (MAP SQUARE Y)) Dialogue: 0,0:28:33.51,0:28:36.80,Default,,0,0,0,,这就是这个模拟计算机的流式描述 Dialogue: 0,0:28:38.62,0:28:40.32,Default,,0,0,0,,不幸的是 它并不起效 Dialogue: 0,0:28:41.41,0:28:42.67,Default,,0,0,0,,你也可以发现这是为什么 Dialogue: 0,0:28:42.97,0:28:44.99,Default,,0,0,0,,因为我把Y定义为 Dialogue: 0,0:28:46.43,0:28:47.85,Default,,0,0,0,,DY 的积分 Dialogue: 0,0:28:49.04,0:28:50.65,Default,,0,0,0,,它会问 对什么的积分? Dialogue: 0,0:28:51.19,0:28:52.12,Default,,0,0,0,,没定义啊 Dialogue: 0,0:28:53.71,0:28:57.63,Default,,0,0,0,,所以这个定义必须写在这个定义的后面 Dialogue: 0,0:28:58.77,0:29:00.51,Default,,0,0,0,,另一方面 如果先定义了dy Dialogue: 0,0:29:00.51,0:29:03.02,Default,,0,0,0,,定义为 (MAP SQUARE 某个东西) Dialogue: 0,0:29:03.58,0:29:04.64,Default,,0,0,0,,这个也还没有定义 Dialogue: 0,0:29:05.77,0:29:08.17,Default,,0,0,0,,我既不能先写这个 又不能先写那个 Dialogue: 0,0:29:09.08,0:29:11.58,Default,,0,0,0,,这个游戏就没法玩了 Dialogue: 0,0:29:17.56,0:29:18.51,Default,,0,0,0,,怎样来解决呢? Dialogue: 0,0:29:20.60,0:29:21.84,Default,,0,0,0,,我们可以用ONES来解决 Dialogue: 0,0:29:22.20,0:29:25.82,Default,,0,0,0,,所以 我们在这里定义的ONES Dialogue: 0,0:29:27.24,0:29:29.90,Default,,0,0,0,,我们之所以可以使用ONES来定义ONES Dialogue: 0,0:29:30.40,0:29:32.03,Default,,0,0,0,,这是因为其中的延时求值 Dialogue: 0,0:29:32.43,0:29:34.12,Default,,0,0,0,,CONS-STREAM是延时求值的 Dialogue: 0,0:29:34.77,0:29:35.79,Default,,0,0,0,,那么 这又为什么说得通呢? Dialogue: 0,0:29:35.92,0:29:38.51,Default,,0,0,0,,为什么CONS-STREAM是延时求值的是合理的呢? Dialogue: 0,0:29:40.73,0:29:43.13,Default,,0,0,0,,原因在于 CONS-STREAM不需要其尾部分 Dialogue: 0,0:29:43.48,0:29:44.88,Default,,0,0,0,,就可以完成有意义的事 Dialogue: 0,0:29:45.95,0:29:46.84,Default,,0,0,0,,比如我说 Dialogue: 0,0:29:47.48,0:29:49.64,Default,,0,0,0,,这个是1和某个东西组成的流 Dialogue: 0,0:29:49.92,0:29:51.69,Default,,0,0,0,,虽然我对它一无所知 Dialogue: 0,0:29:52.16,0:29:54.03,Default,,0,0,0,,但我却知道整个流是以1开始的 Dialogue: 0,0:29:54.87,0:29:57.29,Default,,0,0,0,,所以用CONS-STREAM来构造是有意义的 Dialogue: 0,0:29:59.96,0:30:01.24,Default,,0,0,0,,我们在这里放了一个DELAY Dialogue: 0,0:30:01.42,0:30:04.65,Default,,0,0,0,,这就使得我们能够进行某种自引用的定义 Dialogue: 0,0:30:06.32,0:30:07.95,Default,,0,0,0,,INTEGRAL也可以用这种方式来解决 Dialogue: 0,0:30:08.19,0:30:12.52,Default,,0,0,0,,注意 对于INTEGRAL来说 我可以 Dialogue: 0,0:30:14.60,0:30:16.08,Default,,0,0,0,,让我们回过头来再看看INTEGRAL的定义 Dialogue: 0,0:30:17.58,0:30:18.56,Default,,0,0,0,,求积分的时候 Dialogue: 0,0:30:21.39,0:30:25.00,Default,,0,0,0,,知道INTEGRAL的第一个元素是合理的 Dialogue: 0,0:30:26.04,0:30:27.87,Default,,0,0,0,,尽管还不知道整个流是什么样的 Dialogue: 0,0:30:28.97,0:30:30.17,Default,,0,0,0,,这是因为INTEGRAL中第一个元素 Dialogue: 0,0:30:30.20,0:30:32.16,Default,,0,0,0,,总会是你传递过来的INITIAL-VALUE Dialogue: 0,0:30:33.14,0:30:36.11,Default,,0,0,0,,所以INTEGRAL可以用CONS-STREAM来实现 Dialogue: 0,0:30:37.09,0:30:37.98,Default,,0,0,0,,我们可以定义它 Dialogue: 0,0:30:38.25,0:30:40.88,Default,,0,0,0,,甚至不用知道要积分的流是什么 Dialogue: 0,0:30:42.84,0:30:45.18,Default,,0,0,0,,只需要知道初始值是什么就行了 Dialogue: 0,0:30:46.71,0:30:48.17,Default,,0,0,0,,INTEGRAL还可以修改得更为智能 Dialogue: 0,0:30:48.41,0:30:50.68,Default,,0,0,0,,我们给它一个待积分的流 Dialogue: 0,0:30:50.83,0:30:51.92,Default,,0,0,0,,以及一个初值 Dialogue: 0,0:30:52.11,0:30:54.99,Default,,0,0,0,,直到你要求沿着这个流求解积分时 Dialogue: 0,0:30:55.21,0:30:56.97,Default,,0,0,0,,我才关心这个流是什么 Dialogue: 0,0:30:58.43,0:31:00.51,Default,,0,0,0,,换句话说INTEGRAL可以像CONS-STREAM一样 Dialogue: 0,0:31:00.57,0:31:03.74,Default,,0,0,0,,你可以认为INTEGRAL被放在DELAY之中 Dialogue: 0,0:31:03.76,0:31:04.86,Default,,0,0,0,,我们这样修改 Dialogue: 0,0:31:05.61,0:31:07.02,Default,,0,0,0,,这个过程是像这样的 Dialogue: 0,0:31:07.65,0:31:08.75,Default,,0,0,0,,这是另一个版本的INTEGRAL Dialogue: 0,0:31:08.89,0:31:10.54,Default,,0,0,0,,这个跟之前的版本非常相似 Dialogue: 0,0:31:11.10,0:31:13.34,Default,,0,0,0,,只不过作为参数的流 Dialogue: 0,0:31:13.77,0:31:15.69,Default,,0,0,0,,必须要是一个延时对象 Dialogue: 0,0:31:17.11,0:31:18.43,Default,,0,0,0,,这个INTEGRAL又是如何运作的呢? Dialogue: 0,0:31:18.85,0:31:21.79,Default,,0,0,0,,我们在内部定义的INT则是 Dialogue: 0,0:31:22.14,0:31:24.19,Default,,0,0,0,,用CONS-STREAM构造一个流 Dialogue: 0,0:31:24.73,0:31:26.44,Default,,0,0,0,,初值还是INITIAL-VALUE Dialogue: 0,0:31:27.16,0:31:29.68,Default,,0,0,0,,但是在CONS-STREAM中 Dialogue: 0,0:31:29.74,0:31:32.30,Default,,0,0,0,,要注意 这里面有个隐藏的DELAY Dialogue: 0,0:31:34.95,0:31:39.07,Default,,0,0,0,,只有在这个CONS-STREAM的内部 Dialogue: 0,0:31:39.82,0:31:42.11,Default,,0,0,0,,我才会查看延时对象的实际内容 Dialogue: 0,0:31:43.18,0:31:45.79,Default,,0,0,0,,所以 答案的第一个元素将会是初值 Dialogue: 0,0:31:45.97,0:31:47.90,Default,,0,0,0,,如果有人想访问我的尾部分 Dialogue: 0,0:31:48.40,0:31:49.42,Default,,0,0,0,,此时 Dialogue: 0,0:31:50.00,0:31:51.72,Default,,0,0,0,,我会FORCE该延迟对象 Dialogue: 0,0:31:52.62,0:31:53.60,Default,,0,0,0,,把结果记作S Dialogue: 0,0:31:54.44,0:31:55.60,Default,,0,0,0,,然后再进行ADD-STREAMS Dialogue: 0,0:31:56.36,0:31:59.26,Default,,0,0,0,,这个INTEGRAL就有点像CONS-STREAM Dialogue: 0,0:31:59.26,0:32:02.59,Default,,0,0,0,,直到你确实需要知道第一个元素的时候 Dialogue: 0,0:32:03.88,0:32:07.13,Default,,0,0,0,,它才会去查看DELAYED-S是什么 Dialogue: 0,0:32:10.12,0:32:11.02,Default,,0,0,0,,如果这样的话 Dialogue: 0,0:32:11.52,0:32:12.83,Default,,0,0,0,,也就能求解 y' = y^2 了 Dialogue: 0,0:32:13.36,0:32:15.20,Default,,0,0,0,,这里我们只需要 Dialogue: 0,0:32:16.00,0:32:25.31,Default,,0,0,0,,把Y定义为对延时对象DY的积分 Dialogue: 0,0:32:27.09,0:32:28.22,Default,,0,0,0,,所以Y的定义就变成了 Dialogue: 0,0:32:28.40,0:32:34.36,Default,,0,0,0,,(INTEGRAL (DELAY DY) 1 .001) Dialogue: 0,0:32:34.38,0:32:35.13,Default,,0,0,0,,这样一来就可以了 Dialogue: 0,0:32:35.28,0:32:37.44,Default,,0,0,0,,因为我输入Y的定义 Dialogue: 0,0:32:38.00,0:32:39.68,Default,,0,0,0,,它是某个东西的积分 Dialogue: 0,0:32:40.20,0:32:42.68,Default,,0,0,0,,但这是个延迟对象 我现在还不用关心 Dialogue: 0,0:32:44.60,0:32:46.32,Default,,0,0,0,,这之后 再定义DY Dialogue: 0,0:32:46.32,0:32:47.37,Default,,0,0,0,,现在Y就有定义了 Dialogue: 0,0:32:47.55,0:32:48.89,Default,,0,0,0,,所以我在定义DY时 Dialogue: 0,0:32:49.13,0:32:50.67,Default,,0,0,0,,它可以知道Y的定义 Dialogue: 0,0:32:51.70,0:32:52.84,Default,,0,0,0,,一切都正常了 Dialogue: 0,0:32:52.84,0:32:54.33,Default,,0,0,0,,两个流都有第一个元素 Dialogue: 0,0:32:54.92,0:32:56.25,Default,,0,0,0,,当我不断取得下一个元素 Dialogue: 0,0:32:56.27,0:32:57.31,Default,,0,0,0,,沿着流做MAP运算时 Dialogue: 0,0:32:57.37,0:32:58.88,Default,,0,0,0,,Y和DY都被定义过了 Dialogue: 0,0:33:00.59,0:33:04.24,Default,,0,0,0,,所以为了继续这个游戏 我们不能仅仅 Dialogue: 0,0:33:04.67,0:33:07.13,Default,,0,0,0,,只使用隐藏在流中的DELAY Dialogue: 0,0:33:08.36,0:33:08.97,Default,,0,0,0,,有问题么? Dialogue: 0,0:33:13.52,0:33:14.27,Default,,0,0,0,,休息一下吧 Dialogue: 0,0:33:14.72,0:33:26.86,Default,,0,0,0,,[音乐] Dialogue: 0,0:33:27.37,0:33:30.94,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:33:52.16,0:33:55.26,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:33:55.42,0:33:59.26,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:34:00.38,0:34:03.93,Declare,,0,0,0,,{\an2\fad(500,500)}流 II Dialogue: 0,0:34:07.30,0:34:10.04,Default,,0,0,0,,上节课的最后 Dialogue: 0,0:34:10.89,0:34:11.80,Default,,0,0,0,,不知道你们注意到没有 Dialogue: 0,0:34:11.82,0:34:13.55,Default,,0,0,0,,事情正变得糟糕起来 Dialogue: 0,0:34:14.83,0:34:18.40,Default,,0,0,0,,我们讲了很多关于 流 Dialogue: 0,0:34:19.16,0:34:22.68,Default,,0,0,0,,以及分离程序中的时间和计算机中的时间 Dialogue: 0,0:34:22.86,0:34:26.28,Default,,0,0,0,,这些分离都被隐藏在流中了 Dialogue: 0,0:34:27.28,0:34:29.50,Default,,0,0,0,,上节课快结束时我们发现 Dialogue: 0,0:34:29.71,0:34:32.19,Default,,0,0,0,,为了真正发挥这种方法的优势 Dialogue: 0,0:34:32.22,0:34:34.38,Default,,0,0,0,,我们需要另外的DELAY Dialogue: 0,0:34:34.38,0:34:35.85,Default,,0,0,0,,不只需要隐藏在CONS-STREAM中的DELAY Dialogue: 0,0:34:36.09,0:34:37.95,Default,,0,0,0,,还需要显式地使用DELAY Dialogue: 0,0:34:39.03,0:34:41.88,Default,,0,0,0,,我只是用微分方程举了一个很简单的例子 Dialogue: 0,0:34:42.35,0:34:44.08,Default,,0,0,0,,但是如果你有一个非常复杂的系统 Dialogue: 0,0:34:44.12,0:34:45.40,Default,,0,0,0,,里面充斥着各种各样的自循环 Dialogue: 0,0:34:45.95,0:34:47.84,Default,,0,0,0,,那就很难再发现 Dialogue: 0,0:34:47.90,0:34:49.31,Default,,0,0,0,,在什么地方需要额外的DELAY了 Dialogue: 0,0:34:49.92,0:34:51.18,Default,,0,0,0,,假如你一不小心漏了一个 Dialogue: 0,0:34:51.45,0:34:54.36,Default,,0,0,0,,就很难发现程序为什么不起效 Dialogue: 0,0:34:55.55,0:34:57.15,Default,,0,0,0,,这是一种混乱 Dialogue: 0,0:34:57.79,0:35:01.71,Default,,0,0,0,,让我们能够使用DELAY Dialogue: 0,0:35:02.08,0:35:04.70,Default,,0,0,0,,有时却会让程序设计变得非常复杂 Dialogue: 0,0:35:04.72,0:35:06.80,Default,,0,0,0,,因为它们不能完全隐藏在流中 Dialogue: 0,0:35:08.51,0:35:09.79,Default,,0,0,0,,那么 有没有什么解决方案呢? Dialogue: 0,0:35:11.13,0:35:12.67,Default,,0,0,0,,所幸的是 有 Dialogue: 0,0:35:13.48,0:35:16.08,Default,,0,0,0,,我们可以修改整个语言 Dialogue: 0,0:35:16.14,0:35:18.19,Default,,0,0,0,,使得所有的过程都表现得像CONS-STREAM一样 Dialogue: 0,0:35:19.10,0:35:21.48,Default,,0,0,0,,这样所有的过程都会 Dialogue: 0,0:35:22.32,0:35:25.45,Default,,0,0,0,,自动、隐式地为它的参数加上DELAY Dialogue: 0,0:35:25.45,0:35:26.43,Default,,0,0,0,,这是什么意思呢? Dialogue: 0,0:35:27.52,0:35:29.53,Default,,0,0,0,,就是说 当你调用一个过程时 Dialogue: 0,0:35:30.16,0:35:31.88,Default,,0,0,0,,参数并不会立即求值 Dialogue: 0,0:35:32.21,0:35:34.70,Default,,0,0,0,,只有在需要被求值的时候 它们才会被求值 Dialogue: 0,0:35:34.89,0:35:36.72,Default,,0,0,0,,它们也可能被传递给其它的过程 Dialogue: 0,0:35:36.76,0:35:38.12,Default,,0,0,0,,而这个过程也不会求值这些参数 Dialogue: 0,0:35:39.26,0:35:41.90,Default,,0,0,0,,因此这些过程间传递的是PROMISE Dialogue: 0,0:35:42.15,0:35:44.46,Default,,0,0,0,,直到最后 Dialogue: 0,0:35:44.65,0:35:47.34,Default,,0,0,0,,你需要查看某个值的时候 Dialogue: 0,0:35:47.36,0:35:48.99,Default,,0,0,0,,可能是因为一个基本运算所需要 Dialogue: 0,0:35:49.37,0:35:51.48,Default,,0,0,0,,这是你才实际求值这些PROMISE Dialogue: 0,0:35:52.38,0:35:53.16,Default,,0,0,0,,像这样修改语言之后 Dialogue: 0,0:35:53.36,0:35:55.37,Default,,0,0,0,,由于所有的东西都是统一被延时的 Dialogue: 0,0:35:57.16,0:35:59.00,Default,,0,0,0,,就不需要任何显式的DELAY了 Dialogue: 0,0:35:59.04,0:36:01.55,Default,,0,0,0,,因为它自动地内建在语言之中了 Dialogue: 0,0:36:03.24,0:36:04.38,Default,,0,0,0,,换句话来说 Dialogue: 0,0:36:05.10,0:36:08.14,Default,,0,0,0,,从技术上来说 我所描述的 Dialogue: 0,0:36:09.02,0:36:10.76,Default,,0,0,0,,如果修改后的语言被称作 Dialogue: 0,0:36:12.19,0:36:16.57,Default,,0,0,0,,所谓的“正则序求值”语言 Dialogue: 0,0:36:20.20,0:36:23.47,Default,,0,0,0,,这个跟我们一直使用的语言不同 Dialogue: 0,0:36:23.87,0:36:33.79,Default,,0,0,0,,我们所用的是“应用序求值”语言 Dialogue: 0,0:36:34.56,0:36:36.83,Default,,0,0,0,,还记得应用序求值的代换模型吧 Dialogue: 0,0:36:36.83,0:36:40.49,Default,,0,0,0,,当你求值一个组合式的时候 Dialogue: 0,0:36:40.51,0:36:42.11,Default,,0,0,0,,你需要先计算出每一个元素的值 Dialogue: 0,0:36:43.59,0:36:45.40,Default,,0,0,0,,先求值所有的参数 Dialogue: 0,0:36:45.72,0:36:47.42,Default,,0,0,0,,再把它们代换入过程的体 Dialogue: 0,0:36:47.60,0:36:49.55,Default,,0,0,0,,正则序则不是这样 Dialogue: 0,0:36:49.89,0:36:51.90,Default,,0,0,0,,你所做的则是 Dialogue: 0,0:36:52.76,0:36:54.41,Default,,0,0,0,,直接将参数代换入过程的体 Dialogue: 0,0:36:54.44,0:36:56.19,Default,,0,0,0,,而不先对参数求值 Dialogue: 0,0:36:56.54,0:36:58.08,Default,,0,0,0,,只是代换入了一个计算参数的PROMISE Dialogue: 0,0:36:58.81,0:36:59.90,Default,,0,0,0,,换句话说就是 Dialogue: 0,0:36:59.92,0:37:02.09,Default,,0,0,0,,把作为参数的整个表达式 Dialogue: 0,0:37:02.28,0:37:04.84,Default,,0,0,0,,直接代入过程的体进行代换 Dialogue: 0,0:37:05.16,0:37:06.88,Default,,0,0,0,,在此之间从不进行任何化简 Dialogue: 0,0:37:07.16,0:37:08.76,Default,,0,0,0,,直到遇到一个基本运算符 Dialogue: 0,0:37:09.47,0:37:10.99,Default,,0,0,0,,这就是所谓的正则序求值语言 Dialogue: 0,0:37:12.17,0:37:13.12,Default,,0,0,0,,我们为什么不这样做呢? Dialogue: 0,0:37:13.82,0:37:14.60,Default,,0,0,0,,这样做了之后 Dialogue: 0,0:37:15.00,0:37:17.34,Default,,0,0,0,,我们就获得了延时求值的所有优点 Dialogue: 0,0:37:17.90,0:37:18.80,Default,,0,0,0,,而不会一片混乱 Dialogue: 0,0:37:18.94,0:37:20.19,Default,,0,0,0,,事实上 如果我们这样做了之后 Dialogue: 0,0:37:20.43,0:37:22.67,Default,,0,0,0,,CONS也会是延时求值的 Dialogue: 0,0:37:22.68,0:37:24.57,Default,,0,0,0,,就和CONS-STREAM一样 Dialogue: 0,0:37:24.71,0:37:25.82,Default,,0,0,0,,我们就不再需要流了 Dialogue: 0,0:37:26.36,0:37:28.54,Default,,0,0,0,,因为表自动成为了流 Dialogue: 0,0:37:29.55,0:37:30.70,Default,,0,0,0,,表和流有一样的行为 Dialogue: 0,0:37:30.75,0:37:32.35,Default,,0,0,0,,所有的数据结构也会像那样 Dialogue: 0,0:37:32.35,0:37:33.64,Default,,0,0,0,,所有的都是 Dialogue: 0,0:37:35.07,0:37:37.63,Default,,0,0,0,,直到需要答案的时候 Dialogue: 0,0:37:37.66,0:37:39.42,Default,,0,0,0,,才会去实际的求值 Dialogue: 0,0:37:40.80,0:37:43.58,Default,,0,0,0,,不必再担心 什么时候需要显式地标注DELAY Dialogue: 0,0:37:44.79,0:37:46.16,Default,,0,0,0,,为什么不这样做呢? Dialogue: 0,0:37:47.16,0:37:48.81,Default,,0,0,0,,首先 已经有人这样做过了 Dialogue: 0,0:37:49.23,0:37:51.85,Default,,0,0,0,,有一些十分优雅的语言 Dialogue: 0,0:37:51.85,0:37:55.21,Default,,0,0,0,,其中最为人称道的是一门名为 Miranda 的语言 Dialogue: 0,0:37:55.77,0:37:56.76,Default,,0,0,0,,它是由 Dialogue: 0,0:37:57.44,0:37:59.80,Default,,0,0,0,,肯特大学的 David Turner 开发的 Dialogue: 0,0:38:00.71,0:38:01.93,Default,,0,0,0,,它就是用这样的原理实现的 Dialogue: 0,0:38:01.93,0:38:03.34,Default,,0,0,0,,Miranda是正则序求值语言 Dialogue: 0,0:38:04.27,0:38:05.55,Default,,0,0,0,,它的数据结构 Dialogue: 0,0:38:06.16,0:38:08.41,Default,,0,0,0,,看起来像表 实际上确实流 Dialogue: 0,0:38:08.96,0:38:10.91,Default,,0,0,0,,你不需要任何特殊的功能 Dialogue: 0,0:38:11.28,0:38:13.28,Default,,0,0,0,,就可以在Miranda中编写普通的过程 Dialogue: 0,0:38:13.32,0:38:14.97,Default,,0,0,0,,来解决质数、八皇后这样的问题 Dialogue: 0,0:38:14.97,0:38:16.35,Default,,0,0,0,,这些都是语言的内建功能 Dialogue: 0,0:38:17.93,0:38:18.91,Default,,0,0,0,,但这样做也要付出代价 Dialogue: 0,0:38:21.19,0:38:22.36,Default,,0,0,0,,还记得我们为什么引入流了吗? Dialogue: 0,0:38:23.17,0:38:27.48,Default,,0,0,0,,我们分离了程序的时间和它实际执行的时间 Dialogue: 0,0:38:27.96,0:38:28.88,Default,,0,0,0,,如果我们引入了DELAY Dialogue: 0,0:38:29.04,0:38:30.33,Default,,0,0,0,,这样就在所有的地方完成了解耦 Dialogue: 0,0:38:30.40,0:38:31.42,Default,,0,0,0,,而不单单是在流中 Dialogue: 0,0:38:32.19,0:38:33.14,Default,,0,0,0,,我们的初衷是什么? Dialogue: 0,0:38:33.14,0:38:38.11,Default,,0,0,0,,我们把程序设计看做是指定计算过程 Dialogue: 0,0:38:39.30,0:38:40.62,Default,,0,0,0,,如果我们放弃了对时间的控制 Dialogue: 0,0:38:40.65,0:38:42.41,Default,,0,0,0,,尽管语言变得优雅起来 Dialogue: 0,0:38:43.74,0:38:45.87,Default,,0,0,0,,但是它的表达力却有所下降 Dialogue: 0,0:38:47.03,0:38:49.84,Default,,0,0,0,,这里面还有一些我们无法消除的区别 Dialogue: 0,0:38:51.48,0:38:53.15,Default,,0,0,0,,其中之一就是迭代 Dialogue: 0,0:38:53.98,0:38:56.44,Default,,0,0,0,,还记得这个程序吗? Dialogue: 0,0:38:56.96,0:38:58.28,Default,,0,0,0,,迭代式的阶乘 Dialogue: 0,0:38:58.44,0:39:00.48,Default,,0,0,0,,这是我们很早之前就研究过的 Dialogue: 0,0:39:01.23,0:39:02.97,Default,,0,0,0,,过程FACT-ITER Dialogue: 0,0:39:03.04,0:39:04.91,Default,,0,0,0,,有一个内部过程ITER Dialogue: 0,0:39:05.18,0:39:07.50,Default,,0,0,0,,它含有两个状态PRODUCT和COUNTER Dialogue: 0,0:39:08.70,0:39:10.96,Default,,0,0,0,,它们随着循环不断迭代 Dialogue: 0,0:39:12.12,0:39:13.68,Default,,0,0,0,,之所以说这个过程是迭代的 Dialogue: 0,0:39:13.71,0:39:14.83,Default,,0,0,0,,是因为它没有创建新状态 Dialogue: 0,0:39:15.73,0:39:17.45,Default,,0,0,0,,之所以没有创建新状态 Dialogue: 0,0:39:17.47,0:39:20.25,Default,,0,0,0,,是因为在调用ITER时 Dialogue: 0,0:39:20.30,0:39:22.86,Default,,0,0,0,,作为参数传递给它自己的始终是这些东西 Dialogue: 0,0:39:23.90,0:39:25.39,Default,,0,0,0,,在代换模型中 Dialogue: 0,0:39:25.55,0:39:27.79,Default,,0,0,0,,Gerald教授给你们讲解过 Dialogue: 0,0:39:28.72,0:39:30.01,Default,,0,0,0,,在迭代过程中 Dialogue: 0,0:39:30.03,0:39:31.44,Default,,0,0,0,,状态并不需要增长 Dialogue: 0,0:39:31.82,0:39:34.22,Default,,0,0,0,,因此这是一个迭代过程 Dialogue: 0,0:39:34.99,0:39:37.47,Default,,0,0,0,,但是如果用正则序语言 Dialogue: 0,0:39:37.47,0:39:39.10,Default,,0,0,0,,来运行这段程序 Dialogue: 0,0:39:41.15,0:39:42.17,Default,,0,0,0,,这就会导致 Dialogue: 0,0:39:42.88,0:39:44.96,Default,,0,0,0,,这个过程不再是迭代式了 Dialogue: 0,0:39:45.65,0:39:48.67,Default,,0,0,0,,如果你仔细地思考代换模型 Dialogue: 0,0:39:48.67,0:39:49.90,Default,,0,0,0,,在这里我就不细说了 Dialogue: 0,0:39:51.20,0:39:52.35,Default,,0,0,0,,这个表达式会不断增长 Dialogue: 0,0:39:52.36,0:39:53.18,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:39:53.28,0:39:55.20,Default,,0,0,0,,因为当ITER调用自己时 Dialogue: 0,0:39:55.85,0:39:57.31,Default,,0,0,0,,参数是这个乘法表达式 Dialogue: 0,0:39:58.08,0:39:59.36,Default,,0,0,0,,而在正则序语言中 Dialogue: 0,0:39:59.39,0:40:01.16,Default,,0,0,0,,这个乘法并不会在这里求值 Dialogue: 0,0:40:02.51,0:40:03.82,Default,,0,0,0,,传递给自己并代换的 Dialogue: 0,0:40:03.93,0:40:05.68,Default,,0,0,0,,只是这个乘法计算的PROMISE Dialogue: 0,0:40:06.67,0:40:08.03,Default,,0,0,0,,然后继续代换下去 Dialogue: 0,0:40:09.76,0:40:11.55,Default,,0,0,0,,我调用自己 Dialogue: 0,0:40:11.84,0:40:14.04,Default,,0,0,0,,用的是计算这个乘法的PROMISE Dialogue: 0,0:40:14.04,0:40:17.82,Default,,0,0,0,,但其中的一个因数也是个PROMISE Dialogue: 0,0:40:18.40,0:40:19.43,Default,,0,0,0,,然后我又自调用 Dialogue: 0,0:40:19.43,0:40:21.13,Default,,0,0,0,,如果你用代换模型 Dialogue: 0,0:40:21.98,0:40:23.60,Default,,0,0,0,,来推演这个迭代步骤 Dialogue: 0,0:40:23.77,0:40:26.83,Default,,0,0,0,,你会发现同样的状态增长 Dialogue: 0,0:40:27.16,0:40:28.96,Default,,0,0,0,,所有的PROMISE都需要被记住 Dialogue: 0,0:40:28.97,0:40:30.76,Default,,0,0,0,,以便在最后被调用 Dialogue: 0,0:40:31.79,0:40:35.02,Default,,0,0,0,,所以 正则序的缺点之一 Dialogue: 0,0:40:35.05,0:40:36.86,Default,,0,0,0,,就是无法有效地表达迭代 Dialogue: 0,0:40:36.98,0:40:39.60,Default,,0,0,0,,也许这个理由有点偏理论 Dialogue: 0,0:40:39.61,0:40:43.90,Default,,0,0,0,,但事实上 那些使用这类语言来编写 Dialogue: 0,0:40:44.27,0:40:47.56,Default,,0,0,0,,实际操作系统的人 也都遇到了这类问题 Dialogue: 0,0:40:48.20,0:40:50.75,Default,,0,0,0,,当然 完全可以 Dialogue: 0,0:40:51.64,0:40:54.38,Default,,0,0,0,,用这类语言实现一个文本编辑器 Dialogue: 0,0:40:54.61,0:40:56.08,Default,,0,0,0,,但是你才用了一会儿 Dialogue: 0,0:40:56.72,0:40:59.39,Default,,0,0,0,,就发现已经占用了3MB空间 Dialogue: 0,0:40:59.44,0:41:02.04,Default,,0,0,0,,我想 那些遇到这类问题的人 Dialogue: 0,0:41:02.16,0:41:05.60,Default,,0,0,0,,把它叫做 “拖尾问题” Dialogue: 0,0:41:05.82,0:41:08.20,Default,,0,0,0,,由于不能有效地表达迭代计算 Dialogue: 0,0:41:08.24,0:41:10.46,Default,,0,0,0,,导致堆积了一堆没有被调用的PROMISE Dialogue: 0,0:41:10.72,0:41:14.81,Default,,0,0,0,,针对这类语言的一个研究方向就是 Dialogue: 0,0:41:14.83,0:41:17.48,Default,,0,0,0,,找出一种有效的编译器技术 Dialogue: 0,0:41:17.82,0:41:19.85,Default,,0,0,0,,来避免这种所谓的“拖尾问题” Dialogue: 0,0:41:20.17,0:41:21.61,Default,,0,0,0,,这并不简单 Dialogue: 0,0:41:23.94,0:41:27.31,Default,,0,0,0,,但是 还有一个很突出的问题 Dialogue: 0,0:41:27.96,0:41:31.04,Default,,0,0,0,,使你的语言不能变成正则序 Dialogue: 0,0:41:32.51,0:41:33.29,Default,,0,0,0,,问题就在于 Dialogue: 0,0:41:35.05,0:41:38.09,Default,,0,0,0,,正则序和副作用 Dialogue: 0,0:41:38.89,0:41:40.19,Default,,0,0,0,,是不相容的 Dialogue: 0,0:41:42.00,0:41:43.96,Default,,0,0,0,,它们不能很好地相互配合 Dialogue: 0,0:41:45.44,0:41:46.65,Default,,0,0,0,,这是因为 你不能 Dialogue: 0,0:41:48.28,0:41:50.80,Default,,0,0,0,,你不能一边 Dialogue: 0,0:41:51.00,0:41:54.33,Default,,0,0,0,,建模具有局部状态的对象 Dialogue: 0,0:41:55.72,0:41:56.96,Default,,0,0,0,,同时又 Dialogue: 0,0:41:57.18,0:41:59.55,Default,,0,0,0,,使用正则序的技巧来解耦时间 Dialogue: 0,0:42:00.40,0:42:03.55,Default,,0,0,0,,我来举一个非常简单的例子 Dialogue: 0,0:42:03.79,0:42:05.50,Default,,0,0,0,,假设语言是正则序求值 Dialogue: 0,0:42:07.52,0:42:09.55,Default,,0,0,0,,例子是这样的 Dialogue: 0,0:42:09.55,0:42:10.52,Default,,0,0,0,,注意现在是正则序求值 Dialogue: 0,0:42:10.52,0:42:12.22,Default,,0,0,0,,(DEFINE X 0) Dialogue: 0,0:42:13.57,0:42:15.56,Default,,0,0,0,,这只是变量的初始化 Dialogue: 0,0:42:15.75,0:42:17.69,Default,,0,0,0,,现在我要定义一个有趣的函数 Dialogue: 0,0:42:18.57,0:42:20.44,Default,,0,0,0,,它就是恒等函数ID Dialogue: 0,0:42:22.64,0:42:23.90,Default,,0,0,0,,它所做的就是 Dialogue: 0,0:42:24.11,0:42:26.60,Default,,0,0,0,,用X来记录上一次调用它时N的值 Dialogue: 0,0:42:31.40,0:42:34.16,Default,,0,0,0,,因此(ID N)就返回N Dialogue: 0,0:42:34.17,0:42:35.39,Default,,0,0,0,,但还要把X赋值为N Dialogue: 0,0:42:36.76,0:42:38.54,Default,,0,0,0,,最后再定义一个过程INC Dialogue: 0,0:42:39.55,0:42:42.30,Default,,0,0,0,,也非常简单 Dialogue: 0,0:42:42.58,0:42:45.34,Default,,0,0,0,,假设在正则序求值的语言里 Dialogue: 0,0:42:46.27,0:42:47.23,Default,,0,0,0,,求值下面的表达式 Dialogue: 0,0:42:47.23,0:42:52.83,Default,,0,0,0,,我输入 (DEFINE Y (INC (ID 3))) Dialogue: 0,0:42:52.83,0:42:53.96,Default,,0,0,0,,因此Y的值应该是4 Dialogue: 0,0:42:57.41,0:42:58.35,Default,,0,0,0,,X应该是多少呢? Dialogue: 0,0:42:59.52,0:43:02.16,Default,,0,0,0,,X应该是最后一次被记住的值 Dialogue: 0,0:43:02.64,0:43:04.01,Default,,0,0,0,,也就是我调用函数ID的时候 Dialogue: 0,0:43:04.71,0:43:06.73,Default,,0,0,0,,你可能会想 这里X应该是3 Dialogue: 0,0:43:06.91,0:43:07.52,Default,,0,0,0,,但是并不是这样 Dialogue: 0,0:43:08.53,0:43:11.15,Default,,0,0,0,,这是因为当我在这里定义Y的时候 Dialogue: 0,0:43:11.79,0:43:13.45,Default,,0,0,0,,Y的真正定义却是 Dialogue: 0,0:43:13.47,0:43:15.71,Default,,0,0,0,,一个调用函数ID的PROMISE的增量 Dialogue: 0,0:43:17.00,0:43:18.17,Default,,0,0,0,,因为我没有访问Y Dialogue: 0,0:43:18.36,0:43:20.25,Default,,0,0,0,,所以ID没有运行 Dialogue: 0,0:43:21.56,0:43:23.20,Default,,0,0,0,,我输入这个定义之后 Dialogue: 0,0:43:23.31,0:43:24.80,Default,,0,0,0,,然后查询X得到的结果是0 Dialogue: 0,0:43:28.36,0:43:31.20,Default,,0,0,0,,现在 我输入Y查询它的值 Dialogue: 0,0:43:31.52,0:43:32.43,Default,,0,0,0,,就会得到结果4 Dialogue: 0,0:43:32.67,0:43:35.16,Default,,0,0,0,,对Y的主动查询 Dialogue: 0,0:43:35.29,0:43:37.42,Default,,0,0,0,,会导致ID运行 Dialogue: 0,0:43:38.72,0:43:40.48,Default,,0,0,0,,现在X=3就被记住 Dialogue: 0,0:43:40.74,0:43:41.87,Default,,0,0,0,,所以上面这里的X就应该是0 Dialogue: 0,0:43:41.93,0:43:42.96,Default,,0,0,0,,下面这里是3 Dialogue: 0,0:43:43.28,0:43:46.16,Default,,0,0,0,,这是一个非常简单的场景 Dialogue: 0,0:43:46.30,0:43:49.28,Default,,0,0,0,,但你会发现 调试正则序语言 Dialogue: 0,0:43:50.36,0:43:53.34,Default,,0,0,0,,的交互式程序 Dialogue: 0,0:43:54.12,0:43:55.88,Default,,0,0,0,,会变得相当混乱 Dialogue: 0,0:43:57.10,0:43:58.12,Default,,0,0,0,,很令人迷惑 Dialogue: 0,0:43:59.69,0:44:02.04,Default,,0,0,0,,导致这样的深层次的原因 Dialogue: 0,0:44:02.80,0:44:06.41,Default,,0,0,0,,也就是引入DELAY的根本理念 Dialogue: 0,0:44:06.92,0:44:08.43,Default,,0,0,0,,是因为我们抛弃了时间的概念 Dialogue: 0,0:44:09.78,0:44:11.75,Default,,0,0,0,,也因为如此我们可以处理一些无穷的情况 Dialogue: 0,0:44:11.75,0:44:12.97,Default,,0,0,0,,我们抛弃了时间 Dialogue: 0,0:44:12.99,0:44:14.27,Default,,0,0,0,,就没有必要等它们运行 Dialogue: 0,0:44:17.55,0:44:20.44,Default,,0,0,0,,我们把计算机中事件发生的顺序 Dialogue: 0,0:44:20.83,0:44:22.11,Default,,0,0,0,,与程序中的顺序 分离开来 Dialogue: 0,0:44:22.35,0:44:25.28,Default,,0,0,0,,但是当我们谈及状态、赋值和改变的时候 Dialogue: 0,0:44:25.48,0:44:27.42,Default,,0,0,0,,这些又都是我们想要控制的 Dialogue: 0,0:44:28.76,0:44:33.82,Default,,0,0,0,,我们的目的有着根本性的矛盾 Dialogue: 0,0:44:34.57,0:44:39.12,Default,,0,0,0,,这又让我们进入了一个哲学问题 Dialogue: 0,0:44:39.13,0:44:40.75,Default,,0,0,0,,用什么样的模型 Dialogue: 0,0:44:40.78,0:44:41.77,Default,,0,0,0,,和从什么角度来看这个世界 Dialogue: 0,0:44:42.41,0:44:44.30,Default,,0,0,0,,有时这也被称为 Dialogue: 0,0:44:44.76,0:44:46.60,Default,,0,0,0,,“函数式程序设计的争论” Dialogue: 0,0:44:54.19,0:44:56.60,Default,,0,0,0,,所谓的“纯函数式语言” Dialogue: 0,0:44:57.07,0:44:59.20,Default,,0,0,0,,是完全没有副作用的 Dialogue: 0,0:45:00.44,0:45:01.63,Default,,0,0,0,,不需要副作用 Dialogue: 0,0:45:01.64,0:45:03.02,Default,,0,0,0,,也就不需要赋值运算符 Dialogue: 0,0:45:03.34,0:45:05.72,Default,,0,0,0,,也就没有什么糟糕的后果 Dialogue: 0,0:45:06.36,0:45:07.93,Default,,0,0,0,,可以使用类似代换模型 Dialogue: 0,0:45:07.93,0:45:10.48,Default,,0,0,0,,程序更像是数学 Dialogue: 0,0:45:10.76,0:45:13.82,Default,,0,0,0,,而不像现实世界中的模型和对象 Dialogue: 0,0:45:15.05,0:45:17.17,Default,,0,0,0,,函数式语言有很多了不起的特性 Dialogue: 0,0:45:17.17,0:45:19.63,Default,,0,0,0,,没有时间的概念 所以完全不用担心同步的问题 Dialogue: 0,0:45:20.64,0:45:23.72,Default,,0,0,0,,如果你想在并行算法中应用一些东西 Dialogue: 0,0:45:24.72,0:45:28.20,Default,,0,0,0,,你可以在这些并行过程中随心所欲地使用 Dialogue: 0,0:45:29.40,0:45:31.44,Default,,0,0,0,,从来不担心同步问题 Dialogue: 0,0:45:31.50,0:45:33.34,Default,,0,0,0,,在这种环境下这样做是非常方便的 Dialogue: 0,0:45:33.64,0:45:35.71,Default,,0,0,0,,代价则是 放弃了赋值 Dialogue: 0,0:45:39.10,0:45:41.32,Default,,0,0,0,,函数式语言的支持者会认为 Dialogue: 0,0:45:41.34,0:45:43.04,Default,,0,0,0,,这点代价算不了什么 Dialogue: 0,0:45:44.52,0:45:46.51,Default,,0,0,0,,在大部分情况下 你都不应该使用赋值 Dialogue: 0,0:45:46.88,0:45:48.27,Default,,0,0,0,,如果用你放弃了赋值 Dialogue: 0,0:45:48.43,0:45:51.40,Default,,0,0,0,,你可以得到一个比对象世界 Dialogue: 0,0:45:51.96,0:45:53.24,Default,,0,0,0,,好得多的世界 Dialogue: 0,0:45:54.19,0:45:56.30,Default,,0,0,0,,怎么来反驳这个观点呢? Dialogue: 0,0:45:56.30,0:45:58.59,Default,,0,0,0,,想想 我们如何走到这一步的 Dialogue: 0,0:46:00.06,0:46:03.79,Default,,0,0,0,,我们尝试建模具有局部状态的对象 Dialogue: 0,0:46:04.44,0:46:06.49,Default,,0,0,0,,想一想Gerald教授给你们讲的随机数生成器 Dialogue: 0,0:46:07.16,0:46:08.67,Default,,0,0,0,,这里有一个随机数生成器 Dialogue: 0,0:46:09.28,0:46:10.62,Default,,0,0,0,,它内部有一些状态 Dialogue: 0,0:46:10.83,0:46:12.08,Default,,0,0,0,,用来计算下一个随机数 Dialogue: 0,0:46:12.12,0:46:14.08,Default,,0,0,0,,下下一个 以及再下一个 Dialogue: 0,0:46:14.28,0:46:16.14,Default,,0,0,0,,我们想要把这些状态跟 Dialogue: 0,0:46:16.43,0:46:18.96,Default,,0,0,0,,计算π的Cesaro算法分离开来 Dialogue: 0,0:46:19.84,0:46:20.92,Default,,0,0,0,,这就是我们为什么需要赋值 Dialogue: 0,0:46:20.97,0:46:22.91,Default,,0,0,0,,我们想要把状态封装在模块中 Dialogue: 0,0:46:24.07,0:46:26.36,Default,,0,0,0,,函数式语言程序员可能会说 Dialogue: 0,0:46:26.38,0:46:27.56,Default,,0,0,0,,“你搞错了” Dialogue: 0,0:46:27.56,0:46:29.84,Default,,0,0,0,,“我的意思是 你能写出另一种更具模块化的程序” Dialogue: 0,0:46:29.84,0:46:32.46,Default,,0,0,0,,“你对模块化的认识并不正确” Dialogue: 0,0:46:33.08,0:46:35.02,Default,,0,0,0,,你太执着于 “生成一个随机数 Dialogue: 0,0:46:35.07,0:46:36.88,Default,,0,0,0,,再生成一个 再生成一个” 这种范式了 Dialogue: 0,0:46:36.88,0:46:39.42,Default,,0,0,0,,为什么不写一个这样的程序 Dialogue: 0,0:46:40.09,0:46:41.29,Default,,0,0,0,,构造一个枚举器 Dialogue: 0,0:46:41.95,0:46:44.48,Default,,0,0,0,,它会生成一个随机数的无穷流 Dialogue: 0,0:46:49.01,0:46:50.91,Default,,0,0,0,,我们可以立即生成这个流 Dialogue: 0,0:46:52.64,0:46:54.54,Default,,0,0,0,,这样就可以用作随机数的源泉 Dialogue: 0,0:46:54.54,0:46:55.24,Default,,0,0,0,,如果有需要的话 Dialogue: 0,0:46:55.53,0:46:57.47,Default,,0,0,0,,你可以把它跟某个处理过程相连 Dialogue: 0,0:46:57.77,0:47:01.16,Default,,0,0,0,,比如说Cesaro测试 Dialogue: 0,0:47:04.94,0:47:06.22,Default,,0,0,0,,然后这个处理过程进行自己的计算 Dialogue: 0,0:47:06.88,0:47:08.56,Default,,0,0,0,,从这里出来的则是 Dialogue: 0,0:47:08.72,0:47:27.45,Default,,0,0,0,,其中是一串的对π的估计值组成的流 Dialogue: 0,0:47:28.14,0:47:30.65,Default,,0,0,0,,随着我们深入访问这个流 Dialogue: 0,0:47:30.76,0:47:32.38,Default,,0,0,0,,相当于去拽这个Cesaro盒子 Dialogue: 0,0:47:33.12,0:47:35.36,Default,,0,0,0,,它就会拉取出许多随机数 Dialogue: 0,0:47:35.54,0:47:37.21,Default,,0,0,0,,随着我们对流的深入访问 Dialogue: 0,0:47:37.23,0:47:38.96,Default,,0,0,0,,得到的对π的估计值就越准 Dialogue: 0,0:47:39.72,0:47:41.66,Default,,0,0,0,,具体的计算过程还是一样的 Dialogue: 0,0:47:41.66,0:47:43.79,Default,,0,0,0,,只不过使用了另一种模块化的方式 Dialogue: 0,0:47:43.89,0:47:45.55,Default,,0,0,0,,我们可以想象成一下子 Dialogue: 0,0:47:45.56,0:47:47.47,Default,,0,0,0,,就有了这所有的随机数 Dialogue: 0,0:47:49.28,0:47:52.24,Default,,0,0,0,,这个过程的细节在书上有 Dialogue: 0,0:47:53.61,0:47:57.85,Default,,0,0,0,,我们同样也陷于另外一些类似的事情中 Dialogue: 0,0:47:58.27,0:48:01.20,Default,,0,0,0,,这种关于 这个、下一个以及再下一个的范式 Dialogue: 0,0:48:01.37,0:48:02.81,Default,,0,0,0,,完全可以不这么来做 Dialogue: 0,0:48:03.28,0:48:06.54,Default,,0,0,0,,我们来思考一下银行系统 Dialogue: 0,0:48:07.68,0:48:08.90,Default,,0,0,0,,有个非常简单的场景 Dialogue: 0,0:48:08.90,0:48:12.21,Default,,0,0,0,,我们假设这个程序代表了银行帐户 Dialogue: 0,0:48:18.81,0:48:20.84,Default,,0,0,0,,银行账户中可能有 Dialogue: 0,0:48:22.78,0:48:26.22,Default,,0,0,0,,如果我们以消息传递的角度来看 Dialogue: 0,0:48:26.44,0:48:28.12,Default,,0,0,0,,我们认为银行账户是一个对象 Dialogue: 0,0:48:28.59,0:48:31.51,Default,,0,0,0,,内部保存着标识余额的局部状态BALANCE Dialogue: 0,0:48:34.11,0:48:36.00,Default,,0,0,0,,如果一个用户使用这个系统 Dialogue: 0,0:48:36.44,0:48:38.14,Default,,0,0,0,,发出交易请求 Dialogue: 0,0:48:39.31,0:48:41.05,Default,,0,0,0,,用户发出的交易请求可能是 Dialogue: 0,0:48:41.07,0:48:42.20,Default,,0,0,0,,存一些钱 Dialogue: 0,0:48:42.28,0:48:43.53,Default,,0,0,0,,银行账户就会 Dialogue: 0,0:48:43.92,0:48:46.78,Default,,0,0,0,,我们假设银行账户总是以当前余额作为回应 Dialogue: 0,0:48:48.22,0:48:50.04,Default,,0,0,0,,用户存了一些钱 Dialogue: 0,0:48:50.06,0:48:53.21,Default,,0,0,0,,银行账户就会返回一个消息指明当前余额 Dialogue: 0,0:48:54.35,0:48:57.42,Default,,0,0,0,,用户再存一些钱 Dialogue: 0,0:48:57.45,0:48:58.81,Default,,0,0,0,,银行就再返回消息 Dialogue: 0,0:48:59.15,0:49:00.75,Default,,0,0,0,,就像生成随机数一样 Dialogue: 0,0:49:00.78,0:49:02.12,Default,,0,0,0,,我们想使用赋值来实现 Dialogue: 0,0:49:03.20,0:49:06.88,Default,,0,0,0,,帐户的内部保存了局部状态BALANCE Dialogue: 0,0:49:06.88,0:49:08.40,Default,,0,0,0,,因为我们想要把用户状态 Dialogue: 0,0:49:08.41,0:49:09.57,Default,,0,0,0,,和银行账户的状态分离开来 Dialogue: 0,0:49:13.28,0:49:16.42,Default,,0,0,0,,这是从消息传递的角度来看 Dialogue: 0,0:49:16.42,0:49:18.20,Default,,0,0,0,,如果从流的角度来看 Dialogue: 0,0:49:19.48,0:49:22.19,Default,,0,0,0,,不需要赋值或副作用就可以达到同样的效果 Dialogue: 0,0:49:22.74,0:49:26.73,Default,,0,0,0,,再次强调 想法是这样的 Dialogue: 0,0:49:27.37,0:49:30.25,Default,,0,0,0,,我们认为它们都没有局部状态 Dialogue: 0,0:49:31.18,0:49:33.08,Default,,0,0,0,,我们把银行账户看作是 Dialogue: 0,0:49:33.40,0:49:37.71,Default,,0,0,0,,能够处理一系列交易请求的东西 Dialogue: 0,0:49:38.64,0:49:40.16,Default,,0,0,0,,不把银行账户看做 Dialogue: 0,0:49:40.22,0:49:42.00,Default,,0,0,0,,逐个消息地处理 Dialogue: 0,0:49:42.44,0:49:45.85,Default,,0,0,0,,而是处理某种交易请求流的东西 Dialogue: 0,0:49:45.87,0:49:48.49,Default,,0,0,0,,这个请求流可能是一些列的存款声明 Dialogue: 0,0:49:49.49,0:49:54.94,Default,,0,0,0,,比如 1 2 2 4 这样的连续存钱请求 Dialogue: 0,0:49:55.94,0:50:02.44,Default,,0,0,0,,从帐户出来的流应该是 1 3 5 9 Dialogue: 0,0:50:03.77,0:50:06.14,Default,,0,0,0,,我们不把银行账户看做某种具有状态的东西 Dialogue: 0,0:50:06.40,0:50:07.26,Default,,0,0,0,,而是某种能够处理 Dialogue: 0,0:50:08.92,0:50:10.82,Default,,0,0,0,,有关请求的无穷流的东西 Dialogue: 0,0:50:10.82,0:50:12.30,Default,,0,0,0,,但要注意 我们抛弃了时间 Dialogue: 0,0:50:12.37,0:50:14.27,Default,,0,0,0,,如果这里有一个用户 Dialogue: 0,0:50:16.12,0:50:19.13,Default,,0,0,0,,这个无穷请求流的元素 Dialogue: 0,0:50:19.18,0:50:22.54,Default,,0,0,0,,我们可以一次生成一个 Dialogue: 0,0:50:24.06,0:50:26.57,Default,,0,0,0,,而这个交易流 Dialogue: 0,0:50:26.57,0:50:28.80,Default,,0,0,0,,则会逐个打印在屏幕上 Dialogue: 0,0:50:30.01,0:50:31.37,Default,,0,0,0,,如果在这里画一条线 Dialogue: 0,0:50:32.56,0:50:33.08,Default,,0,0,0,,就在这里 Dialogue: 0,0:50:33.28,0:50:34.91,Default,,0,0,0,,对用户来说 他根本无法分辨 Dialogue: 0,0:50:36.19,0:50:37.71,Default,,0,0,0,,这个系统是否有内部状态 Dialogue: 0,0:50:39.56,0:50:41.13,Default,,0,0,0,,这个跟消息传递那种是一样的 Dialogue: 0,0:50:41.29,0:50:42.46,Default,,0,0,0,,只不过这个没有状态 Dialogue: 0,0:50:42.84,0:50:45.87,Default,,0,0,0,,哦 顺便提一下 Dialogue: 0,0:50:46.72,0:50:49.47,Default,,0,0,0,,这是具体的代码实现 Dialogue: 0,0:50:50.52,0:50:52.30,Default,,0,0,0,,我们把它叫做MAKE-DEPOSIT-ACCOUNT Dialogue: 0,0:50:52.32,0:50:53.32,Default,,0,0,0,,因为它只能够存钱 Dialogue: 0,0:50:54.17,0:50:55.77,Default,,0,0,0,,这个过程接受一个初始余额 Dialogue: 0,0:50:56.09,0:50:58.09,Default,,0,0,0,,以及一个可能发起的存款流 Dialogue: 0,0:51:00.02,0:51:00.82,Default,,0,0,0,,具体怎么做呢? Dialogue: 0,0:51:00.82,0:51:02.54,Default,,0,0,0,,它只是用CONS-STREAM把余额BALANCE Dialogue: 0,0:51:03.23,0:51:05.31,Default,,0,0,0,,和一个新的存款账户流组合在一起 Dialogue: 0,0:51:06.24,0:51:07.32,Default,,0,0,0,,新存款流的初始余额 Dialogue: 0,0:51:07.48,0:51:10.27,Default,,0,0,0,,就是之前BALANCE的值加上存款流的第一个元素 Dialogue: 0,0:51:10.86,0:51:13.40,Default,,0,0,0,,而其余部分则是 Dialogue: 0,0:51:13.76,0:51:17.37,Default,,0,0,0,,存款流的尾部分 Dialogue: 0,0:51:18.30,0:51:23.84,Default,,0,0,0,,因此这种非常典型的消息传递式、面向对象的问题 Dialogue: 0,0:51:23.95,0:51:27.55,Default,,0,0,0,,完全可以不用副作用来解决 Dialogue: 0,0:51:29.05,0:51:30.76,Default,,0,0,0,,很多地方都可以这样做 Dialogue: 0,0:51:32.25,0:51:35.23,Default,,0,0,0,,那么 我们可以完全不用赋值么? Dialogue: 0,0:51:36.40,0:51:39.00,Default,,0,0,0,,可以只用纯函数式语言吗? Dialogue: 0,0:51:40.05,0:51:42.04,Default,,0,0,0,,这个问题谁也说不清 Dialogue: 0,0:51:42.27,0:51:43.44,Default,,0,0,0,,好像有些地方 Dialogue: 0,0:51:43.92,0:51:46.03,Default,,0,0,0,,纯函数式语言无法派上用场 Dialogue: 0,0:51:48.10,0:51:50.27,Default,,0,0,0,,当遇到像这样的系统时 问题就变得棘手起来 Dialogue: 0,0:51:50.43,0:51:52.32,Default,,0,0,0,,特别是当你 Dialogue: 0,0:51:52.60,0:51:54.27,Default,,0,0,0,,还需要考虑其它因素的时候 Dialogue: 0,0:51:54.30,0:51:55.64,Default,,0,0,0,,有关对象和共享 Dialogue: 0,0:51:55.90,0:51:58.52,Default,,0,0,0,,以及两个独立的主体共享同一个东西 Dialogue: 0,0:51:58.85,0:51:59.93,Default,,0,0,0,,举一个典型的例子 Dialogue: 0,0:51:59.96,0:52:01.63,Default,,0,0,0,,假如你来扩展这个帐户 Dialogue: 0,0:52:03.24,0:52:04.27,Default,,0,0,0,,这是一个帐户 Dialogue: 0,0:52:12.22,0:52:14.75,Default,,0,0,0,,帐户接受一个交易请求流 Dialogue: 0,0:52:15.20,0:52:18.44,Default,,0,0,0,,输出的流则是关于余额的回复 Dialogue: 0,0:52:18.78,0:52:20.16,Default,,0,0,0,,假设你所建模的是联合账户 Dialogue: 0,0:52:20.17,0:52:24.36,Default,,0,0,0,,而由两个独立用户共享 Dialogue: 0,0:52:25.68,0:52:28.65,Default,,0,0,0,,我们假设 假设有两个人 Dialogue: 0,0:52:28.97,0:52:30.96,Default,,0,0,0,,比如说Bill和Dave Dialogue: 0,0:52:31.77,0:52:33.14,Default,,0,0,0,,他们俩共享一个帐户 Dialogue: 0,0:52:35.96,0:52:36.85,Default,,0,0,0,,怎么来建模呢? Dialogue: 0,0:52:36.88,0:52:39.80,Default,,0,0,0,,你或许会让Bill输出一个交易请求流 Dialogue: 0,0:52:40.24,0:52:42.25,Default,,0,0,0,,Dave也产生一个这样的流 Dialogue: 0,0:52:42.25,0:52:45.16,Default,,0,0,0,,这两个流需要以某种方式合并到银行账户中 Dialogue: 0,0:52:45.88,0:52:47.85,Default,,0,0,0,,因此你需要编写一个MERGE过程 Dialogue: 0,0:52:47.90,0:52:50.65,Default,,0,0,0,,来处理这些流 Dialogue: 0,0:52:57.23,0:52:59.13,Default,,0,0,0,,它把这些流合并在一起 Dialogue: 0,0:52:59.34,0:53:01.19,Default,,0,0,0,,形成单个流 送入银行账户 Dialogue: 0,0:53:01.19,0:53:02.99,Default,,0,0,0,,现在他们就共享一个帐户了 Dialogue: 0,0:53:03.61,0:53:05.48,Default,,0,0,0,,看起来不错 问题是怎么来实现MERGE Dialogue: 0,0:53:05.93,0:53:08.24,Default,,0,0,0,,MERGE怎么来合并? Dialogue: 0,0:53:09.73,0:53:11.42,Default,,0,0,0,,需要合理的合并依据 Dialogue: 0,0:53:12.38,0:53:13.80,Default,,0,0,0,,你可能首先会想 Dialogue: 0,0:53:13.80,0:53:16.68,Default,,0,0,0,,我们从Bill和Dave中选一个请求来处理 Dialogue: 0,0:53:18.19,0:53:20.97,Default,,0,0,0,,但是如果在这中途 Dialogue: 0,0:53:21.18,0:53:23.08,Default,,0,0,0,,Dave突然外出度假两年 会怎么样? Dialogue: 0,0:53:24.15,0:53:25.40,Default,,0,0,0,,Bill的交易就完全被阻塞了 Dialogue: 0,0:53:27.69,0:53:29.75,Default,,0,0,0,,你想要的是 Dialogue: 0,0:53:29.75,0:53:33.64,Default,,0,0,0,,是一种公平的合并 Dialogue: 0,0:53:38.41,0:53:40.17,Default,,0,0,0,,这个所谓公平的合并 Dialogue: 0,0:53:40.73,0:53:42.46,Default,,0,0,0,,应该是交替地一次处理一个 Dialogue: 0,0:53:42.49,0:53:43.92,Default,,0,0,0,,但是如果一个人没有了交易 Dialogue: 0,0:53:43.96,0:53:44.91,Default,,0,0,0,,应该继续去处理另一个人的交易 Dialogue: 0,0:53:46.01,0:53:48.45,Default,,0,0,0,,但是没有时间 我就不能这样做 Dialogue: 0,0:53:51.30,0:53:56.41,Default,,0,0,0,,函数式语言的另一个活跃研究领域就是 Dialogue: 0,0:53:56.43,0:53:59.48,Default,,0,0,0,,发明类似于“公平合并”的算法 Dialogue: 0,0:54:00.35,0:54:01.31,Default,,0,0,0,,又或者是其它的东西 Dialogue: 0,0:54:01.56,0:54:06.25,Default,,0,0,0,,用于取代原来需要副作用和对象的地方 Dialogue: 0,0:54:06.80,0:54:10.52,Default,,0,0,0,,用一种良好定义的模块化系统来隐藏它们 Dialogue: 0,0:54:10.86,0:54:13.50,Default,,0,0,0,,这样 系统中就不会到处产生 Dialogue: 0,0:54:13.52,0:54:15.34,Default,,0,0,0,,赋值所带来的问题 Dialogue: 0,0:54:15.40,0:54:17.88,Default,,0,0,0,,因为它可以被理解透彻的概念所描述 Dialogue: 0,0:54:20.78,0:54:22.70,Default,,0,0,0,,推而广之 我想你们也发现了 Dialogue: 0,0:54:23.12,0:54:24.06,Default,,0,0,0,,我们正面对 我所认为的 Dialogue: 0,0:54:24.08,0:54:26.67,Default,,0,0,0,,计算机科学中最基本的问题 Dialogue: 0,0:54:26.97,0:54:27.82,Default,,0,0,0,,也就是 Dialogue: 0,0:54:28.24,0:54:32.03,Default,,0,0,0,,我们如何定义一门支持延迟求值的语言 Dialogue: 0,0:54:34.14,0:54:35.08,Default,,0,0,0,,但同时又能够 Dialogue: 0,0:54:35.87,0:54:38.25,Default,,0,0,0,,又能够把事物看做对象来操作 Dialogue: 0,0:54:38.36,0:54:40.36,Default,,0,0,0,,怎么样才能两者兼有之? Dialogue: 0,0:54:41.23,0:54:43.04,Default,,0,0,0,,我认为这个问题很困难 Dialogue: 0,0:54:43.04,0:54:45.52,Default,,0,0,0,,但是这个很困难的问题 Dialogue: 0,0:54:45.85,0:54:48.17,Default,,0,0,0,,却和计算机科学的关系不大 Dialogue: 0,0:54:48.59,0:54:50.24,Default,,0,0,0,,它真正涉及的是 Dialogue: 0,0:54:50.27,0:54:52.73,Default,,0,0,0,,两种不相容的看待世界的方式 Dialogue: 0,0:54:54.14,0:54:54.72,Default,,0,0,0,,有问题吗? Dialogue: 0,0:55:17.55,0:55:19.20,Default,,0,0,0,,学生:你之前提到过 Dialogue: 0,0:55:20.11,0:55:21.32,Default,,0,0,0,,一旦引入了赋值 Dialogue: 0,0:55:21.32,0:55:25.89,Default,,0,0,0,,就不能使用代换模型了 Dialogue: 0,0:55:25.89,0:55:27.57,Default,,0,0,0,,除非你非常小心 Dialogue: 0,0:55:27.57,0:55:27.96,Default,,0,0,0,,教授:对的 Dialogue: 0,0:55:28.26,0:55:33.28,Default,,0,0,0,,学生:有什么技术或者指导方针 Dialogue: 0,0:55:33.42,0:55:35.92,Default,,0,0,0,,来确定赋值的影响 Dialogue: 0,0:55:36.52,0:55:40.30,Default,,0,0,0,,以便说清楚这个“很小心”是怎么回事吗? Dialogue: 0,0:55:40.30,0:55:42.60,Default,,0,0,0,,教授:我不知道 Dialogue: 0,0:55:42.89,0:55:43.58,Default,,0,0,0,,我想想 Dialogue: 0,0:55:45.43,0:55:48.94,Default,,0,0,0,,当然 实现MEM-PROC也使用了赋值 Dialogue: 0,0:55:50.12,0:55:51.48,Default,,0,0,0,,但是它被隐藏了起来 Dialogue: 0,0:55:51.48,0:55:53.00,Default,,0,0,0,,因为它没有对结果造成影响 Dialogue: 0,0:55:53.48,0:55:56.44,Default,,0,0,0,,部分原因之一在于 一旦触发这个过程 Dialogue: 0,0:55:57.15,0:55:58.83,Default,,0,0,0,,它被求值并得到结果 Dialogue: 0,0:55:58.83,0:56:00.06,Default,,0,0,0,,这个结果不会再变化 Dialogue: 0,0:56:00.60,0:56:02.33,Default,,0,0,0,,有点像单次赋值 Dialogue: 0,0:56:02.35,0:56:03.85,Default,,0,0,0,,一个一般性原则就是 Dialogue: 0,0:56:04.30,0:56:06.35,Default,,0,0,0,,如果你只用这种单次赋值 Dialogue: 0,0:56:08.04,0:56:09.24,Default,,0,0,0,,并且它不再改变 Dialogue: 0,0:56:09.63,0:56:10.54,Default,,0,0,0,,我想应该不会有太大问题 Dialogue: 0,0:56:11.25,0:56:14.12,Default,,0,0,0,,还有一个问题在于MERGE -- Dialogue: 0,0:56:14.67,0:56:18.32,Default,,0,0,0,,让我想想对不对 Dialogue: 0,0:56:18.49,0:56:21.55,Default,,0,0,0,,我认为有了公平合并这一技术 Dialogue: 0,0:56:22.25,0:56:26.09,Default,,0,0,0,,你可以在语言的其它地方 Dialogue: 0,0:56:27.02,0:56:28.89,Default,,0,0,0,,有效地模拟赋值 Dialogue: 0,0:56:30.82,0:56:33.29,Default,,0,0,0,,这就像为了解决问题你会引入一些东西 Dialogue: 0,0:56:33.50,0:56:35.50,Default,,0,0,0,,我不清楚对公平合并来说是否成立 Dialogue: 0,0:56:35.53,0:56:39.31,Default,,0,0,0,,但是对人们正在尝试的一些一般性事情是成立的 Dialogue: 0,0:56:39.52,0:56:41.34,Default,,0,0,0,,所以 这可能是你引入的这一点点东西 Dialogue: 0,0:56:41.61,0:56:44.14,Default,,0,0,0,,突然间 使你能构建任何东西 Dialogue: 0,0:56:44.16,0:56:46.51,Default,,0,0,0,,这就几乎跟有了赋值一样糟糕了 Dialogue: 0,0:56:47.97,0:56:50.67,Default,,0,0,0,,这也是人们在研究的一个领域 Dialogue: 0,0:56:51.59,0:56:54.30,Default,,0,0,0,,学生:我还没有太明白MERGE的问题 Dialogue: 0,0:56:54.83,0:56:59.20,Default,,0,0,0,,如果我调用Bill它是个过程 Dialogue: 0,0:56:59.21,0:57:02.41,Default,,0,0,0,,那么Bill就会增加银行账户 Dialogue: 0,0:57:02.44,0:57:04.73,Default,,0,0,0,,或者创建一个表 用于放置下一个存款 Dialogue: 0,0:57:04.73,0:57:06.84,Default,,0,0,0,,如果我连续调用Dave两次 他肯定也会那样 Dialogue: 0,0:57:07.17,0:57:09.35,Default,,0,0,0,,我并不清楚为什么需要公平合并 Dialogue: 0,0:57:09.35,0:57:11.20,Default,,0,0,0,,教授:关键在于你得把这些当作真人一样 Dialogue: 0,0:57:11.20,0:57:14.20,Default,,0,0,0,,这里有一个用户在操作帐户 Dialogue: 0,0:57:14.85,0:57:17.07,Default,,0,0,0,,请求一次 得到结果 Dialogue: 0,0:57:17.20,0:57:17.56,Default,,0,0,0,,学生:对 Dialogue: 0,0:57:18.20,0:57:20.62,Default,,0,0,0,,教授:如果我只能通过从两个流中选择一个 Dialogue: 0,0:57:20.65,0:57:22.25,Default,,0,0,0,,来处理请求的话 Dialogue: 0,0:57:22.91,0:57:24.22,Default,,0,0,0,,学生:为什么要二选一呢? Dialogue: 0,0:57:24.22,0:57:25.23,Default,,0,0,0,,教授:为什么不呢? Dialogue: 0,0:57:25.45,0:57:25.80,Default,,0,0,0,,学生:对啊 为什么要这样呢? Dialogue: 0,0:57:26.60,0:57:27.72,Default,,0,0,0,,教授:假设这些是现实中的人 对吗? Dialogue: 0,0:57:27.76,0:57:28.97,Default,,0,0,0,,这个人外出一年 Dialogue: 0,0:57:29.28,0:57:31.74,Default,,0,0,0,,你只能在银行账户窗口旁边等待 Dialogue: 0,0:57:32.43,0:57:33.72,Default,,0,0,0,,就是不能处理两个请求 Dialogue: 0,0:57:33.74,0:57:34.94,Default,,0,0,0,,因为你还得等这个人 Dialogue: 0,0:57:35.48,0:57:37.07,Default,,0,0,0,,学生:为什么非得等他呢? Dialogue: 0,0:57:37.38,0:57:39.11,Default,,0,0,0,,教授:因为这里是在计算一个函数 Dialogue: 0,0:57:39.11,0:57:40.92,Default,,0,0,0,,我必须定义一个函数 Dialogue: 0,0:57:41.72,0:57:42.60,Default,,0,0,0,,换种方式来说 Dialogue: 0,0:57:42.84,0:57:44.99,Default,,0,0,0,,这个MERGE盒子的输出 Dialogue: 0,0:57:46.24,0:57:49.48,Default,,0,0,0,,并不是输入的函数 Dialogue: 0,0:57:51.69,0:57:53.49,Default,,0,0,0,,明白了吗?再来看看这个MERGE是怎么运行的 Dialogue: 0,0:57:53.49,0:57:58.86,Default,,0,0,0,,假设Bill输入 1 1 1 1 Dialogue: 0,0:57:59.82,0:58:02.78,Default,,0,0,0,,Dave输入2 2 2 2 Dialogue: 0,0:58:03.47,0:58:04.80,Default,,0,0,0,,MERGE应该输出什么呢? Dialogue: 0,0:58:05.58,0:58:08.74,Default,,0,0,0,,这里并不一定是 1 2 1 2 1 2 Dialogue: 0,0:58:08.74,0:58:09.39,Default,,0,0,0,,学生:我明白了 Dialogue: 0,0:58:09.39,0:58:11.56,Default,,0,0,0,,当Bill输入1 1也就进去了 Dialogue: 0,0:58:11.56,0:58:13.95,Default,,0,0,0,,Dave再输入两个2 MERGE就输出两个2 Dialogue: 0,0:58:13.95,0:58:14.73,Default,,0,0,0,,学生:当Bill输入 Dialogue: 0,0:58:14.76,0:58:15.08,Default,,0,0,0,,教授:对的 Dialogue: 0,0:58:15.13,0:58:18.43,Default,,0,0,0,,学生:为什么不能在输入的数据上 Dialogue: 0,0:58:18.59,0:58:20.06,Default,,0,0,0,,加上时间信息呢? Dialogue: 0,0:58:20.12,0:58:21.84,Default,,0,0,0,,教授:因为这里没有时间这个概念 Dialogue: 0,0:58:23.98,0:58:26.90,Default,,0,0,0,,我只是定义一个函数 Dialogue: 0,0:58:26.90,0:58:28.15,Default,,0,0,0,,没有时间概念 Dialogue: 0,0:58:32.00,0:58:34.19,Default,,0,0,0,,如果是二选一的话 Dialogue: 0,0:58:34.19,0:58:36.54,Default,,0,0,0,,如果选中的流没有人 就得等待它 Dialogue: 0,0:58:38.42,0:58:41.36,Default,,0,0,0,,它只会说 我有一个请求流 Dialogue: 0,0:58:41.74,0:58:43.34,Default,,0,0,0,,这是是Dave生成的 Dialogue: 0,0:58:43.36,0:58:45.29,Default,,0,0,0,,没有时刻的、无穷长度的请求流 Dialogue: 0,0:58:47.55,0:58:50.41,Default,,0,0,0,,Bill可能生成 没有时刻的无穷请求流 Dialogue: 0,0:58:50.54,0:58:51.69,Default,,0,0,0,,我想对这些东西做运算 Dialogue: 0,0:58:51.69,0:58:53.51,Default,,0,0,0,,这就是银行帐户的工作原理 Dialogue: 0,0:58:56.71,0:58:57.58,Default,,0,0,0,,问题是 Dialogue: 0,0:58:57.61,0:59:00.75,Default,,0,0,0,,这些坐在银行窗口前的倒霉蛋们 Dialogue: 0,0:59:00.76,0:59:03.82,Default,,0,0,0,,来得并不是时候 Dialogue: 0,0:59:05.29,0:59:07.13,Default,,0,0,0,,它们才看不到这个无穷流 Dialogue: 0,0:59:07.69,0:59:09.53,Default,,0,0,0,,什么时候其中会有请求 Dialogue: 0,0:59:10.07,0:59:11.55,Default,,0,0,0,,他们只是等着 等待帐户的响应 Dialogue: 0,0:59:14.48,0:59:15.76,Default,,0,0,0,,假设你坐在屏幕前 Dialogue: 0,0:59:16.24,0:59:20.86,Default,,0,0,0,,操作着一台分时系统的计算机 Dialogue: 0,0:59:21.52,0:59:22.60,Default,,0,0,0,,而且它还是函数式的 Dialogue: 0,0:59:22.64,0:59:24.59,Default,,0,0,0,,输入指令后你就希望看到结果 Dialogue: 0,0:59:25.29,0:59:27.42,Default,,0,0,0,,但是你并不想主机在处理完所有其它人的命令 Dialogue: 0,0:59:27.45,0:59:29.92,Default,,0,0,0,,之后再来处理你的命令 Dialogue: 0,0:59:30.91,0:59:31.92,Default,,0,0,0,,这就是问题所在 Dialogue: 0,0:59:34.00,0:59:36.38,Default,,0,0,0,,我的意思就是 用户的世界当然是存在时间概念的 Dialogue: 0,0:59:37.21,0:59:38.62,Default,,0,0,0,,如果没有 这就不构成问题 Dialogue: 0,0:59:49.10,0:59:51.02,Default,,0,0,0,,学生:我想我还是不太理解 Dialogue: 0,0:59:51.08,0:59:54.24,Default,,0,0,0,,银行交易中为什么没有时间概念这一要点 Dialogue: 0,0:59:54.74,0:59:56.65,Default,,0,0,0,,难道时间不是非常重要吗? Dialogue: 0,0:59:56.88,0:59:59.05,Default,,0,0,0,,举例说 有一系列事件 Dialogue: 0,0:59:59.95,1:00:05.02,Default,,0,0,0,,比如Dave取款$100 Dialogue: 0,1:00:06.30,1:00:08.40,Default,,0,0,0,,这些顺序应该很重要才对 Dialogue: 0,1:00:08.40,1:00:10.86,Default,,0,0,0,,你怎么能把它们看作是流呢? Dialogue: 0,1:00:11.26,1:00:14.26,Default,,0,0,0,,教授:这就是我一直在强调的 Dialogue: 0,1:00:14.26,1:00:15.61,Default,,0,0,0,,在这个例子中确实做不到那一点 Dialogue: 0,1:00:17.51,1:00:18.12,Default,,0,0,0,,做不到 Dialogue: 0,1:00:18.16,1:00:20.08,Default,,0,0,0,,关键在于 这里的输出 Dialogue: 0,1:00:20.24,1:00:21.88,Default,,0,0,0,,并不是这两个输入流 Dialogue: 0,1:00:21.92,1:00:23.60,Default,,0,0,0,,的函数 Dialogue: 0,1:00:24.17,1:00:25.98,Default,,0,0,0,,这个函数跟这个输入流有关 Dialogue: 0,1:00:26.19,1:00:27.26,Default,,0,0,0,,还跟这个输入流有关 Dialogue: 0,1:00:27.36,1:00:29.07,Default,,0,0,0,,还包括某种有关时间的信息 Dialogue: 0,1:00:29.37,1:00:32.36,Default,,0,0,0,,这也正是正则序语言不想让你知道的 Dialogue: 0,1:00:34.81,1:00:37.95,Default,,0,0,0,,学生:为了让这个系统更加函数式 Dialogue: 0,1:00:38.54,1:00:42.04,Default,,0,0,0,,我们能不能把Bill和Dave的交易请求附上时间戳 Dialogue: 0,1:00:42.54,1:00:46.40,Default,,0,0,0,,而使用时间戳作为公平合并的依据? Dialogue: 0,1:00:48.41,1:00:49.55,Default,,0,0,0,,教授:当然 当然可以 Dialogue: 0,1:00:49.55,1:00:50.60,Default,,0,0,0,,你可以那样做 Dialogue: 0,1:00:50.60,1:00:52.56,Default,,0,0,0,,或者 我们可以这样来想象 Dialogue: 0,1:00:52.76,1:00:54.44,Default,,0,0,0,,我们把这个函数看作是 Dialogue: 0,1:00:54.78,1:00:56.88,Default,,0,0,0,,MERGE每毫秒读一次输入 Dialogue: 0,1:00:58.86,1:00:59.93,Default,,0,0,0,,如果没有读到东西 Dialogue: 0,1:00:59.93,1:01:00.97,Default,,0,0,0,,就认为没有请求 Dialogue: 0,1:01:00.97,1:01:03.39,Default,,0,0,0,,这和你刚刚说的那种方式是等价的 Dialogue: 0,1:01:03.61,1:01:06.08,Default,,0,0,0,,当然可以这样做 但有点旁门左道 Dialogue: 0,1:01:07.11,1:01:10.14,Default,,0,0,0,,我们不只是关心函数的具体实现 Dialogue: 0,1:01:10.76,1:01:12.73,Default,,0,0,0,,我们关心的是语言的表达力 Dialogue: 0,1:01:12.75,1:01:14.67,Default,,0,0,0,,我们遇到的困难是 Dialogue: 0,1:01:14.99,1:01:17.44,Default,,0,0,0,,我们不能很容易地表达我们想要表达的东西 Dialogue: 0,1:01:19.88,1:01:22.01,Default,,0,0,0,,学生:听起来好像如果两个人同时发出请求 Dialogue: 0,1:01:22.06,1:01:26.09,Default,,0,0,0,,这个方法就会出问题 Dialogue: 0,1:01:26.12,1:01:28.43,Default,,0,0,0,,教授:并不只是这个 只要是你定义的都可能出问题 Dialogue: 0,1:01:28.53,1:01:30.57,Default,,0,0,0,,你当然可以说Dave经常发起两个请求 Dialogue: 0,1:01:30.72,1:01:32.32,Default,,0,0,0,,但是你如果预先定义了什么 Dialogue: 0,1:01:32.68,1:01:33.87,Default,,0,0,0,,这样做也不正确 Dialogue: 0,1:01:36.11,1:01:40.70,Default,,0,0,0,,你不能确定某些特定函数的输入请求 Dialogue: 0,1:01:41.93,1:01:43.37,Default,,0,0,0,,但是还有更坏的情况 Dialogue: 0,1:01:44.12,1:01:45.72,Default,,0,0,0,,有一些情况甚至MERGE也处理不了 Dialogue: 0,1:01:47.29,1:01:49.69,Default,,0,0,0,,比如突然有一天你想要 Dialogue: 0,1:01:50.24,1:01:52.47,Default,,0,0,0,,把另一个人关联在这个银行帐户上 Dialogue: 0,1:01:52.47,1:01:54.51,Default,,0,0,0,,假如这个人是John Dialogue: 0,1:01:56.03,1:01:58.89,Default,,0,0,0,,现在图上就要多一个流 Dialogue: 0,1:01:58.91,1:02:00.70,Default,,0,0,0,,在一个我们未曾指定的时候 Dialogue: 0,1:02:02.04,1:02:04.00,Default,,0,0,0,,这种情况甚至公平合并也无法给出合理的合并 Dialogue: 0,1:02:04.00,1:02:08.25,Default,,0,0,0,,还需要有MANAGER一类的东西 Dialogue: 0,1:02:08.86,1:02:11.79,Default,,0,0,0,,需要一种更一般性的公平合并来解决 Dialogue: 0,1:02:11.79,1:02:13.98,Default,,0,0,0,,有很多研究都在讨论 Dialogue: 0,1:02:14.00,1:02:16.30,Default,,0,0,0,,通过不断引入新机制 Dialogue: 0,1:02:16.59,1:02:18.72,Default,,0,0,0,,函数式思维能应用到哪种程度? Dialogue: 0,1:02:19.58,1:02:21.79,Default,,0,0,0,,在我们不得不使用赋值之前 Dialogue: 0,1:02:21.82,1:02:23.40,Default,,0,0,0,,函数式程序设计能干成什么样? Dialogue: 0,1:02:25.98,1:02:28.00,Default,,0,0,0,,学生:看来自动存款就不行 Dialogue: 0,1:02:39.32,1:02:40.49,Default,,0,0,0,,教授:好的 下课 Dialogue: 0,1:02:41.32,1:03:00.08,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:02:41.32,1:03:00.08,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec6b.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.03,0:00:03.10,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:04.09,0:00:12.08,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:04.09,0:00:12.08,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N张大伟\N(DreamAndDead) Dialogue: 0,0:00:04.09,0:00:12.08,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:04.09,0:00:12.08,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:04.09,0:00:12.08,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:12.54,0:00:17.00,Declare,,0,0,0,,{\an2\fad(500,500)}流 II Dialogue: 0,0:00:20.97,0:00:24.08,Default,,0,0,0,,教授:上节课 我们介绍了流 Dialogue: 0,0:00:24.08,0:00:27.82,Default,,0,0,0,,按照信号处理的方式来组织系统 Dialogue: 0,0:00:28.87,0:00:31.42,Default,,0,0,0,,要记住的是 关键点在于 Dialogue: 0,0:00:31.90,0:00:32.96,Default,,0,0,0,,我们分离开 Dialogue: 0,0:00:34.20,0:00:37.31,Default,,0,0,0,,程序中 事件表面上的顺序 Dialogue: 0,0:00:37.58,0:00:40.17,Default,,0,0,0,,与机器中的实际计算顺序 Dialogue: 0,0:00:41.07,0:00:42.28,Default,,0,0,0,,那就意味着 我们可以 Dialogue: 0,0:00:42.57,0:00:44.14,Default,,0,0,0,,着手处理非常长的流 Dialogue: 0,0:00:44.89,0:00:47.39,Default,,0,0,0,,并且只有在需要的时候才生成其中的元素 Dialogue: 0,0:00:47.53,0:00:49.39,Default,,0,0,0,,这种按需计算的方式 Dialogue: 0,0:00:49.52,0:00:51.40,Default,,0,0,0,,是内建在流的数据结构中的 Dialogue: 0,0:00:54.11,0:00:55.64,Default,,0,0,0,,即使这个流非常之长 Dialogue: 0,0:00:55.66,0:00:57.08,Default,,0,0,0,,我们只计算所需要的 Dialogue: 0,0:00:58.04,0:01:00.75,Default,,0,0,0,,只有当我们要求的时候 新的数据才会生成 Dialogue: 0,0:01:00.75,0:01:01.74,Default,,0,0,0,,要举个什么样的例子呢? Dialogue: 0,0:01:02.11,0:01:03.60,Default,,0,0,0,,这个“按需”是什么个情况呢? Dialogue: 0,0:01:05.02,0:01:06.01,Default,,0,0,0,,举个例子 Dialogue: 0,0:01:09.21,0:01:11.37,Default,,0,0,0,,我们可能会想要一个流中的第N个元素 Dialogue: 0,0:01:15.36,0:01:18.92,Default,,0,0,0,,这个过程可以用于计算流的第N个元素 Dialogue: 0,0:01:20.09,0:01:21.23,Default,,0,0,0,,一个参数为索引N Dialogue: 0,0:01:21.24,0:01:22.84,Default,,0,0,0,,另一个参数是流S Dialogue: 0,0:01:23.40,0:01:25.42,Default,,0,0,0,,递归遍历这个流即可求解 Dialogue: 0,0:01:25.57,0:01:27.39,Default,,0,0,0,,如果N为0 我们就计算头部分 Dialogue: 0,0:01:27.96,0:01:30.99,Default,,0,0,0,,否则 就在流的尾部分 Dialogue: 0,0:01:31.74,0:01:32.80,Default,,0,0,0,,查找第N-1个元素 Dialogue: 0,0:01:34.31,0:01:36.43,Default,,0,0,0,,看起来是Lisp中很普通的编程方式 但是不同的是 Dialogue: 0,0:01:36.62,0:01:38.76,Default,,0,0,0,,直到我们不断遍历 取得相继的N个元素 Dialogue: 0,0:01:38.86,0:01:40.99,Default,,0,0,0,,这些元素才被计算出来 Dialogue: 0,0:01:41.52,0:01:44.78,Default,,0,0,0,,这是这些流元素可能被FORCE的一种方式 Dialogue: 0,0:01:45.77,0:01:46.64,Default,,0,0,0,,另外一种方式则是 Dialogue: 0,0:01:47.18,0:01:48.92,Default,,0,0,0,,这里有个简单的过程 用来打印一个流 Dialogue: 0,0:01:49.30,0:01:50.38,Default,,0,0,0,,它的定义是 Dialogue: 0,0:01:51.90,0:01:53.28,Default,,0,0,0,,过程PRINT-STREAM的定义是 Dialogue: 0,0:01:54.15,0:01:55.12,Default,,0,0,0,,我们要怎么做呢? Dialogue: 0,0:01:55.74,0:01:56.86,Default,,0,0,0,,先打印流的头部分 Dialogue: 0,0:01:57.74,0:01:59.32,Default,,0,0,0,,流的头部分在这时就被计算出来 Dialogue: 0,0:01:59.72,0:02:02.84,Default,,0,0,0,,然后我们再递归地打印流的尾部分 Dialogue: 0,0:02:04.99,0:02:06.03,Default,,0,0,0,,完成以后 Dialogue: 0,0:02:06.04,0:02:08.57,Default,,0,0,0,,就返回一个的表示完成的消息 “DONE” Dialogue: 0,0:02:09.66,0:02:11.39,Default,,0,0,0,,如果你构造了一个流 Dialogue: 0,0:02:11.64,0:02:13.64,Default,,0,0,0,,这个流非常的长 Dialogue: 0,0:02:14.31,0:02:16.33,Default,,0,0,0,,当你调用这个过程 Dialogue: 0,0:02:16.41,0:02:19.77,Default,,0,0,0,,流中的元素会随着PRINT-STREAM的调用 Dialogue: 0,0:02:19.87,0:02:21.12,Default,,0,0,0,,而被依次计算出来 Dialogue: 0,0:02:21.32,0:02:22.81,Default,,0,0,0,,不会在一开始就全部计算出来 Dialogue: 0,0:02:24.30,0:02:25.66,Default,,0,0,0,,正因为如此 我们能够 Dialogue: 0,0:02:27.50,0:02:29.61,Default,,0,0,0,,我们能够处理非常长的流 Dialogue: 0,0:02:30.19,0:02:31.92,Default,,0,0,0,,多长呢? Dialogue: 0,0:02:33.74,0:02:35.12,Default,,0,0,0,,可以是无限长 Dialogue: 0,0:02:35.90,0:02:38.04,Default,,0,0,0,,我们在计算机上实践一下 Dialogue: 0,0:02:38.92,0:02:41.96,Default,,0,0,0,,我可以在计算机前输入 Dialogue: 0,0:02:43.48,0:02:53.31,Default,,0,0,0,,我先定义一个函数 (INTEGERS-FROM N) Dialogue: 0,0:02:54.24,0:02:57.13,Default,,0,0,0,,用于生成一个从N开始的正整数流 Dialogue: 0,0:03:00.36,0:03:19.16,Default,,0,0,0,,也就是 (CONS-STREAM N (INTEGERS-FROM (+ N 1)))) Dialogue: 0,0:03:24.41,0:03:25.61,Default,,0,0,0,,这样就我们要的全部整数 Dialogue: 0,0:03:28.99,0:03:31.50,Default,,0,0,0,,现在我来尝试得到所有的整数 Dialogue: 0,0:03:34.57,0:03:44.33,Default,,0,0,0,,(DEFINE INTEGERS (INTEGERS-FROM 1)) Dialogue: 0,0:03:48.84,0:03:50.94,Default,,0,0,0,,如果现在我执行 (NTH-STREAM 20 INTEGERS) Dialogue: 0,0:03:54.41,0:03:55.80,Default,,0,0,0,,来查看第20个元素 Dialogue: 0,0:04:03.42,0:04:05.53,Default,,0,0,0,,得到21 因为索引是从0开始的 Dialogue: 0,0:04:06.84,0:04:08.88,Default,,0,0,0,,或者我们来点更复杂的 Dialogue: 0,0:04:09.45,0:04:10.84,Default,,0,0,0,,我再来定义一个谓词 Dialogue: 0,0:04:11.77,0:04:18.51,Default,,0,0,0,,谓词NO-SEVEN用来检测是否为7的倍数 Dialogue: 0,0:04:19.58,0:04:20.75,Default,,0,0,0,,它的判定方法是这样的: Dialogue: 0,0:04:21.79,0:04:23.16,Default,,0,0,0,,如果整数X不是7的倍数 Dialogue: 0,0:04:28.82,0:04:33.96,Default,,0,0,0,,我取X除7的余数 Dialogue: 0,0:04:36.62,0:04:38.35,Default,,0,0,0,,余数不应该为0 Dialogue: 0,0:04:43.80,0:04:49.77,Default,,0,0,0,,这时用NO-SEVEN这个谓词 Dialogue: 0,0:04:50.22,0:04:59.12,Default,,0,0,0,,过滤全部的整数 Dialogue: 0,0:05:11.57,0:05:13.34,Default,,0,0,0,,这样我就得到了所有的 Dialogue: 0,0:05:13.63,0:05:15.05,Default,,0,0,0,,不是7的倍数的整数构成的流 Dialogue: 0,0:05:16.49,0:05:23.44,Default,,0,0,0,,如果我问 这些不是7的倍数的整数中 Dialogue: 0,0:05:24.70,0:05:26.48,Default,,0,0,0,,的第100个数是多少? Dialogue: 0,0:05:26.86,0:05:28.11,Default,,0,0,0,,结果是117 Dialogue: 0,0:05:28.32,0:05:30.67,Default,,0,0,0,,或者我也可以问 Dialogue: 0,0:05:32.30,0:05:34.38,Default,,0,0,0,,这个流的所有元素都是些什么? Dialogue: 0,0:05:35.27,0:05:40.35,Default,,0,0,0,,我可以用(PRINT-STREAM NS)来尝试打印这个流 Dialogue: 0,0:05:40.83,0:05:41.79,Default,,0,0,0,,它就会输出个不停 Dialogue: 0,0:05:45.10,0:05:47.07,Default,,0,0,0,,你可能需要等上很久才能得到全部结果 Dialogue: 0,0:05:52.67,0:05:53.84,Default,,0,0,0,,你可能会问了 Dialogue: 0,0:05:54.81,0:05:57.00,Default,,0,0,0,,这个数据结构 Dialogue: 0,0:05:58.28,0:06:00.65,Default,,0,0,0,,真的全部是由整数构成的吗? Dialogue: 0,0:06:01.10,0:06:04.05,Default,,0,0,0,,现在我画一个图来演示下刚写的那个程序 Dialogue: 0,0:06:04.96,0:06:10.57,Default,,0,0,0,,这是我刚才键入的整数定义 Dialogue: 0,0:06:12.33,0:06:15.98,Default,,0,0,0,,它是一个由第一个整数和由下一个整数生成的流 所构成的序对 Dialogue: 0,0:06:17.61,0:06:19.77,Default,,0,0,0,,现在我们画个图来看看它到底是什么样 Dialogue: 0,0:06:22.72,0:06:24.32,Default,,0,0,0,,从概念上来说 这应该是一个盒子 Dialogue: 0,0:06:25.53,0:06:27.18,Default,,0,0,0,,这个盒子是(INTEGER-FROM N) Dialogue: 0,0:06:27.42,0:06:29.08,Default,,0,0,0,,它接受一个参数N Dialogue: 0,0:06:31.42,0:06:32.97,Default,,0,0,0,,然后返回一个流 Dialogue: 0,0:06:35.02,0:06:37.36,Default,,0,0,0,,这个无穷流表示从N开始的所有整数 Dialogue: 0,0:06:38.08,0:06:38.73,Default,,0,0,0,,我要做什么呢? Dialogue: 0,0:06:38.75,0:06:42.38,Default,,0,0,0,,呃 这个是INT-FROM盒子 Dialogue: 0,0:06:45.07,0:06:45.80,Default,,0,0,0,,里面是什么样子呢? Dialogue: 0,0:06:45.80,0:06:48.60,Default,,0,0,0,,取得参数N之后 Dialogue: 0,0:06:52.27,0:06:53.92,Default,,0,0,0,,将其 +1 Dialogue: 0,0:06:57.95,0:07:03.15,Default,,0,0,0,,然后把结果递归地传递给另一个INT-FROM盒子 Dialogue: 0,0:07:06.87,0:07:09.60,Default,,0,0,0,,把这个盒子的结果和最初的N Dialogue: 0,0:07:10.24,0:07:12.78,Default,,0,0,0,,用CONS组合起来 Dialogue: 0,0:07:13.39,0:07:14.36,Default,,0,0,0,,就形成了一个流 Dialogue: 0,0:07:14.57,0:07:17.26,Default,,0,0,0,,我刚才写的那个过程 画出来就是这样子 Dialogue: 0,0:07:18.52,0:07:20.32,Default,,0,0,0,,我们看到的这类图像 Dialogue: 0,0:07:20.78,0:07:21.74,Default,,0,0,0,,首先是由Peter Henderson提出的 Dialogue: 0,0:07:21.76,0:07:23.32,Default,,0,0,0,,也就是前面课程中绘图语言的发明者 Dialogue: 0,0:07:23.32,0:07:24.75,Default,,0,0,0,,我们把这种图叫做Henderson图 Dialogue: 0,0:07:25.37,0:07:27.90,Default,,0,0,0,,画这种图需要遵守一定的约定 Dialogue: 0,0:07:28.53,0:07:32.51,Default,,0,0,0,,这些实线代表输出的流 Dialogue: 0,0:07:33.02,0:07:36.20,Default,,0,0,0,,这些虚线则是初始的输入值 Dialogue: 0,0:07:37.27,0:07:39.02,Default,,0,0,0,,而这个图描述的形状是—— Dialogue: 0,0:07:39.40,0:07:41.60,Default,,0,0,0,,它会取一个整数作为初始值 Dialogue: 0,0:07:41.80,0:07:42.91,Default,,0,0,0,,然后输出一个流 Dialogue: 0,0:07:46.35,0:07:48.22,Default,,0,0,0,,现在 你可能又要问了 Dialogue: 0,0:07:48.38,0:07:50.88,Default,,0,0,0,,那个INTEGERS的数据结构真的全部都是整数吗? Dialogue: 0,0:07:52.09,0:07:54.91,Default,,0,0,0,,或者它只是经过了精心组织 Dialogue: 0,0:07:54.94,0:07:56.43,Default,,0,0,0,,以至于总可以在其中找到 Dialogue: 0,0:07:56.44,0:07:57.24,Default,,0,0,0,,我们需要的那个整数? Dialogue: 0,0:07:57.95,0:07:59.74,Default,,0,0,0,,这有点像个哲学问题 不是么? Dialogue: 0,0:07:59.78,0:08:01.69,Default,,0,0,0,,如果有一个东西 Dialogue: 0,0:08:02.14,0:08:03.96,Default,,0,0,0,,你不去观测它 能否知道它“存在”呢? Dialogue: 0,0:08:04.45,0:08:07.34,Default,,0,0,0,,这就有点像 Dialogue: 0,0:08:07.36,0:08:09.42,Default,,0,0,0,,你在银行中的存款那样 Dialogue: 0,0:08:12.38,0:08:12.64,Default,,0,0,0,,好吧 Dialogue: 0,0:08:16.35,0:08:17.48,Default,,0,0,0,,我们再来看一个例子 Dialogue: 0,0:08:18.68,0:08:20.70,Default,,0,0,0,,这门课的第一节课 Dialogue: 0,0:08:20.72,0:08:22.72,Default,,0,0,0,,我们就讲了一个来自于亚历山大的算法 Dialogue: 0,0:08:23.29,0:08:25.80,Default,,0,0,0,,来自亚历山大的Heron提出的 Dialogue: 0,0:08:25.82,0:08:26.94,Default,,0,0,0,,一个用于计算平方根的算法 Dialogue: 0,0:08:28.47,0:08:32.03,Default,,0,0,0,,现在再来看一个 同样来自于亚力山大的算法 Dialogue: 0,0:08:32.03,0:08:35.08,Default,,0,0,0,,这个被称为Eratosthenes算法的方法 Dialogue: 0,0:08:36.19,0:08:38.44,Default,,0,0,0,,用于计算所有的质数 Dialogue: 0,0:08:41.16,0:08:42.83,Default,,0,0,0,,它被称为Eratosthenes筛法 Dialogue: 0,0:08:42.83,0:08:49.72,Default,,0,0,0,,它是这样的 一开始 Dialogue: 0,0:08:50.99,0:08:52.28,Default,,0,0,0,,先列举所有的整数 Dialogue: 0,0:08:52.60,0:08:53.53,Default,,0,0,0,,从2开始 Dialogue: 0,0:08:53.88,0:08:55.04,Default,,0,0,0,,然后取第一个整数 Dialogue: 0,0:08:55.08,0:08:56.67,Default,,0,0,0,,然后你发现 哦 2是一个质数 Dialogue: 0,0:08:57.31,0:08:58.35,Default,,0,0,0,,然后你考察剩余的整数 Dialogue: 0,0:08:58.68,0:09:00.88,Default,,0,0,0,,划掉其中可以被2整除的数 Dialogue: 0,0:09:01.52,0:09:04.73,Default,,0,0,0,,我把这个划掉 还有这个 这个 Dialogue: 0,0:09:05.25,0:09:06.35,Default,,0,0,0,,有点费时 Dialogue: 0,0:09:06.36,0:09:08.91,Default,,0,0,0,,我要对所有的整数进行这样的操作 Dialogue: 0,0:09:11.16,0:09:15.39,Default,,0,0,0,,我遍历整个整数表 Dialogue: 0,0:09:18.27,0:09:20.94,Default,,0,0,0,,划掉所有被2整除的数 Dialogue: 0,0:09:22.11,0:09:24.38,Default,,0,0,0,,所有的整数都操作完后 Dialogue: 0,0:09:24.78,0:09:26.72,Default,,0,0,0,,回过头再来看还剩些什么 Dialogue: 0,0:09:27.04,0:09:28.80,Default,,0,0,0,,好的 下一个数就是3了 Dialogue: 0,0:09:29.33,0:09:30.33,Default,,0,0,0,,3也是一个质数 Dialogue: 0,0:09:30.77,0:09:33.05,Default,,0,0,0,,现在 我会继续在剩下的数中 Dialogue: 0,0:09:33.36,0:09:35.07,Default,,0,0,0,,划掉所有被3整除的数 Dialogue: 0,0:09:35.08,0:09:43.80,Default,,0,0,0,,划掉 9、15、21、27、33 等等 Dialogue: 0,0:09:44.33,0:09:45.12,Default,,0,0,0,,我就不往下划了 Dialogue: 0,0:09:45.35,0:09:46.52,Default,,0,0,0,,然后看看我们还剩下什么 Dialogue: 0,0:09:47.25,0:09:49.84,Default,,0,0,0,,而下一个就是5了 Dialogue: 0,0:09:50.49,0:09:52.04,Default,,0,0,0,,我又遍历剩下的数 Dialogue: 0,0:09:52.43,0:09:54.51,Default,,0,0,0,,找到第一个能被5整除的数 Dialogue: 0,0:09:54.54,0:09:57.61,Default,,0,0,0,,把剩下的能被5整除的数都划掉 Dialogue: 0,0:09:58.35,0:09:59.24,Default,,0,0,0,,做完这个之后 Dialogue: 0,0:09:59.82,0:10:01.89,Default,,0,0,0,,下一个数就是7 Dialogue: 0,0:10:01.89,0:10:02.72,Default,,0,0,0,,再遍历剩下的数 Dialogue: 0,0:10:02.76,0:10:03.95,Default,,0,0,0,,划掉所有被7整除的数 Dialogue: 0,0:10:03.98,0:10:05.47,Default,,0,0,0,,然后一直这样下去 Dialogue: 0,0:10:06.81,0:10:07.40,Default,,0,0,0,,全部结束的时候 Dialogue: 0,0:10:07.40,0:10:09.10,Default,,0,0,0,,我也就得到了所有的质数 Dialogue: 0,0:10:09.90,0:10:13.31,Default,,0,0,0,,这就是Eratosthenes筛法 Dialogue: 0,0:10:15.43,0:10:17.69,Default,,0,0,0,,我们来看下实际代码 Dialogue: 0,0:10:17.93,0:10:19.85,Default,,0,0,0,,这个过程命名为SIEVE Dialogue: 0,0:10:27.91,0:10:29.40,Default,,0,0,0,,这是对应的代码 Dialogue: 0,0:10:30.33,0:10:34.48,Default,,0,0,0,,SIEVE过程 以一个流S为参数 Dialogue: 0,0:10:38.77,0:10:39.93,Default,,0,0,0,,返回一个新的流 Dialogue: 0,0:10:40.27,0:10:41.84,Default,,0,0,0,,新的流的头部分 就是流S的头部分 Dialogue: 0,0:10:41.87,0:10:44.43,Default,,0,0,0,,回忆一下 我总是取剩下的数中的第一个 Dialogue: 0,0:10:44.91,0:10:48.75,Default,,0,0,0,,而尾部分则是把流S的尾部分 Dialogue: 0,0:10:51.08,0:10:53.72,Default,,0,0,0,,过滤掉所有 Dialogue: 0,0:10:53.74,0:10:55.32,Default,,0,0,0,,能被S头部分整除的数 Dialogue: 0,0:10:56.41,0:10:57.56,Default,,0,0,0,,然后再对结果筛选 Dialogue: 0,0:10:59.02,0:11:00.09,Default,,0,0,0,,这个代码就是这样 Dialogue: 0,0:11:01.98,0:11:04.68,Default,,0,0,0,,现在 为了得到由质数构成的无穷流 Dialogue: 0,0:11:05.02,0:11:06.90,Default,,0,0,0,,我们对从2开始的整数流进行SIEVE Dialogue: 0,0:11:14.92,0:11:15.56,Default,,0,0,0,,我们来实践一下 Dialogue: 0,0:11:16.30,0:11:18.30,Default,,0,0,0,,实际上 我们可以在计算机中运行 Dialogue: 0,0:11:19.76,0:11:22.12,Default,,0,0,0,,我希望我已经预先输入过SIEVE的定义了 Dialogue: 0,0:11:22.86,0:11:24.06,Default,,0,0,0,,所以我可以定义 Dialogue: 0,0:11:24.92,0:11:33.45,Default,,0,0,0,,我可以把PRIMES定义为 Dialogue: 0,0:11:34.64,0:11:41.45,Default,,0,0,0,,(SIEVE (INTEGERS-FROM 2)) Dialogue: 0,0:11:46.76,0:11:48.10,Default,,0,0,0,,现在我就得到了质数构成的表 Dialogue: 0,0:11:48.10,0:11:50.99,Default,,0,0,0,,这样就得到了所有的质数 对吧? Dialogue: 0,0:11:50.99,0:11:53.52,Default,,0,0,0,,比如我可以问 第20个质数是什么? Dialogue: 0,0:12:00.73,0:12:01.68,Default,,0,0,0,,结果是73 Dialogue: 0,0:12:02.54,0:12:03.34,Default,,0,0,0,,那个短促的停顿 Dialogue: 0,0:12:03.36,0:12:04.92,Default,,0,0,0,,这是因为 Dialogue: 0,0:12:04.94,0:12:06.43,Default,,0,0,0,,在我询问第20个元素时 Dialogue: 0,0:12:06.46,0:12:07.68,Default,,0,0,0,,它才进行实际的计算 Dialogue: 0,0:12:10.37,0:12:11.29,Default,,0,0,0,,在这里 我也可以要求 Dialogue: 0,0:12:13.80,0:12:14.88,Default,,0,0,0,,打印所有的质数 Dialogue: 0,0:12:22.64,0:12:24.40,Default,,0,0,0,,解释器就开始计算并打印所有的质数 Dialogue: 0,0:12:25.35,0:12:26.28,Default,,0,0,0,,得花上好一会儿 Dialogue: 0,0:12:26.28,0:12:27.61,Default,,0,0,0,,才能打赢完整 Dialogue: 0,0:12:27.79,0:12:28.57,Default,,0,0,0,,所以先把它停掉 Dialogue: 0,0:12:32.03,0:12:33.13,Default,,0,0,0,,让我来画图演示一下 Dialogue: 0,0:12:33.13,0:12:34.17,Default,,0,0,0,,我已经画好了 Dialogue: 0,0:12:34.89,0:12:36.19,Default,,0,0,0,,这个过程的图形应该是什么样子呢? Dialogue: 0,0:12:37.90,0:12:39.77,Default,,0,0,0,,用这类图形的约定来说 Dialogue: 0,0:12:39.82,0:12:40.54,Default,,0,0,0,,我有一个叫SIEVE的盒子 Dialogue: 0,0:12:42.61,0:12:43.56,Default,,0,0,0,,它是如何运作的呢? Dialogue: 0,0:12:43.56,0:12:44.81,Default,,0,0,0,,它以一个流作为输入 Dialogue: 0,0:12:48.85,0:12:50.59,Default,,0,0,0,,分离流的头、尾部分 Dialogue: 0,0:12:50.87,0:12:53.26,Default,,0,0,0,,从SIEVE盒子出来的第一个东西 Dialogue: 0,0:12:53.48,0:12:54.97,Default,,0,0,0,,就是原来流的头部分 Dialogue: 0,0:12:58.20,0:13:00.92,Default,,0,0,0,,头部分同样也用于这个盒子 Dialogue: 0,0:13:02.55,0:13:05.10,Default,,0,0,0,,这个盒子会过滤流的尾部分 Dialogue: 0,0:13:05.55,0:13:08.33,Default,,0,0,0,,过滤的依据是 能否被头部分整除 Dialogue: 0,0:13:09.53,0:13:11.18,Default,,0,0,0,,过滤得到的不可整除的那些数 Dialogue: 0,0:13:11.24,0:13:13.12,Default,,0,0,0,,再放入另一个SIEVE盒子 Dialogue: 0,0:13:13.90,0:13:15.13,Default,,0,0,0,,然后把它们组合输出 Dialogue: 0,0:13:15.13,0:13:16.89,Default,,0,0,0,,你可以把SIEVE想象为一个过滤器 Dialogue: 0,0:13:17.20,0:13:19.23,Default,,0,0,0,,只不过它是一个无穷递归的过滤器 Dialogue: 0,0:13:19.65,0:13:20.88,Default,,0,0,0,,这是因为在SIEVE盒子中 Dialogue: 0,0:13:21.52,0:13:22.60,Default,,0,0,0,,还有另外一个SIEVE盒子 Dialogue: 0,0:13:23.37,0:13:25.85,Default,,0,0,0,,内部的盒子里面还有另外一个SIEVE盒子 Dialogue: 0,0:13:27.13,0:13:28.96,Default,,0,0,0,,我们现在逐渐有了非常厉害的能力 Dialogue: 0,0:13:28.96,0:13:32.84,Default,,0,0,0,,我们开始把 信号处理的方法 Dialogue: 0,0:13:33.90,0:13:36.41,Default,,0,0,0,,和计算中的递归结合在一起 来建模世界 Dialogue: 0,0:13:37.42,0:13:39.82,Default,,0,0,0,,还有很多像是这样的事 Dialogue: 0,0:13:40.97,0:13:42.09,Default,,0,0,0,,好的 有什么问题吗? Dialogue: 0,0:13:48.19,0:13:49.16,Default,,0,0,0,,好吧 那我们休息一下 Dialogue: 0,0:13:49.64,0:14:04.12,Default,,0,0,0,,[音乐] Dialogue: 0,0:14:04.46,0:14:08.12,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:14:12.08,0:14:16.38,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:14:16.44,0:14:20.22,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:14:20.35,0:14:25.05,Declare,,0,0,0,,{\an2\fad(500,500)}流 II Dialogue: 0,0:14:28.65,0:14:30.36,Default,,0,0,0,,我们已经看了 Dialogue: 0,0:14:30.36,0:14:32.09,Default,,0,0,0,,好几个流式程序设计的例子 Dialogue: 0,0:14:34.79,0:14:39.21,Default,,0,0,0,,我们目前接触到的流过程 Dialogue: 0,0:14:39.72,0:14:41.32,Default,,0,0,0,,都有一个共同的特征 Dialogue: 0,0:14:41.49,0:14:43.63,Default,,0,0,0,,这些过程总是递归地 Dialogue: 0,0:14:44.16,0:14:46.49,Default,,0,0,0,,一次生成一个元素 Dialogue: 0,0:14:46.51,0:14:48.72,Default,,0,0,0,,再用CONS-STREAM连接起来 Dialogue: 0,0:14:49.15,0:14:50.86,Default,,0,0,0,,因此 我们一直把它当作是生成器 Dialogue: 0,0:14:50.92,0:14:53.63,Default,,0,0,0,,还有一种思考流式程序设计的方式 Dialogue: 0,0:14:53.79,0:14:56.96,Default,,0,0,0,,我们不认为程序是 Dialogue: 0,0:14:57.36,0:14:59.93,Default,,0,0,0,,沿着流逐一处理元素 Dialogue: 0,0:15:00.25,0:15:05.68,Default,,0,0,0,,而是一下子处理了整个流 Dialogue: 0,0:15:07.18,0:15:09.16,Default,,0,0,0,,我先来定义两个非常有用的过程 Dialogue: 0,0:15:09.23,0:15:11.50,Default,,0,0,0,,来帮助我说明 Dialogue: 0,0:15:12.41,0:15:13.60,Default,,0,0,0,,第一个过程是ADD-STREAMS Dialogue: 0,0:15:15.36,0:15:18.25,Default,,0,0,0,,它接受两个流作为参数 Dialogue: 0,0:15:18.81,0:15:20.88,Default,,0,0,0,,S1和S2 Dialogue: 0,0:15:22.30,0:15:24.67,Default,,0,0,0,,它生成一个新的流 Dialogue: 0,0:15:24.99,0:15:28.17,Default,,0,0,0,,其元素是两个流相应位置元素的和 Dialogue: 0,0:15:30.22,0:15:31.88,Default,,0,0,0,,相当于是“按元素”的加 Dialogue: 0,0:15:32.97,0:15:33.95,Default,,0,0,0,,如果其中一个流是空的 Dialogue: 0,0:15:33.96,0:15:35.39,Default,,0,0,0,,我们就返回另一个 Dialogue: 0,0:15:36.81,0:15:38.96,Default,,0,0,0,,否则 我们就构建一个新的流 Dialogue: 0,0:15:39.90,0:15:42.96,Default,,0,0,0,,新流的头部分是两个流头部分之和 Dialogue: 0,0:15:44.00,0:15:44.88,Default,,0,0,0,,而新流的尾部分 Dialogue: 0,0:15:46.00,0:15:48.62,Default,,0,0,0,,则是递归地加和尾部分 Dialogue: 0,0:15:50.09,0:15:52.73,Default,,0,0,0,,这就会产生“按元素”地加的效果 Dialogue: 0,0:15:53.15,0:15:57.04,Default,,0,0,0,,另一个过程是SCALE-STREAM Dialogue: 0,0:15:57.50,0:16:01.66,Default,,0,0,0,,SCALE-STREAM有两个参数 常数C和流S Dialogue: 0,0:16:04.11,0:16:06.62,Default,,0,0,0,,结果生成的流 Dialogue: 0,0:16:07.18,0:16:09.50,Default,,0,0,0,,就是将流S的所有元素乘上了C Dialogue: 0,0:16:09.71,0:16:11.21,Default,,0,0,0,,这很简单 就是一个MAP Dialogue: 0,0:16:12.20,0:16:16.22,Default,,0,0,0,,用到的函数是 X*C Dialogue: 0,0:16:16.35,0:16:17.80,Default,,0,0,0,,把这个函数MAP于整个流 Dialogue: 0,0:16:20.06,0:16:21.47,Default,,0,0,0,,有了这两个过程 Dialogue: 0,0:16:22.64,0:16:24.36,Default,,0,0,0,,我来给你们解释 什么叫做 Dialogue: 0,0:16:24.70,0:16:27.00,Default,,0,0,0,,“一下子处理整个流” Dialogue: 0,0:16:28.12,0:16:28.73,Default,,0,0,0,,我们来看这个 Dialogue: 0,0:16:30.20,0:16:30.92,Default,,0,0,0,,假设这样 Dialogue: 0,0:16:31.68,0:16:52.35,Default,,0,0,0,,(DEFINE ONES (CONS-STREAM 1 ONES)) Dialogue: 0,0:16:54.86,0:16:55.52,Default,,0,0,0,,这是什么? Dialogue: 0,0:16:56.95,0:16:58.94,Default,,0,0,0,,这是一个表示无穷个1的流 Dialogue: 0,0:16:59.96,0:17:01.44,Default,,0,0,0,,因为第一个元素是1 Dialogue: 0,0:17:03.33,0:17:05.15,Default,,0,0,0,,尾部分则是这样的 Dialogue: 0,0:17:05.55,0:17:06.83,Default,,0,0,0,,它的头部分是1 Dialogue: 0,0:17:07.63,0:17:09.02,Default,,0,0,0,,它的尾部分 Dialogue: 0,0:17:09.12,0:17:10.24,Default,,0,0,0,,的头部分又为1 Dialogue: 0,0:17:10.52,0:17:11.78,Default,,0,0,0,,以此类推 Dialogue: 0,0:17:11.78,0:17:13.32,Default,,0,0,0,,这就是无穷个1的流 Dialogue: 0,0:17:15.13,0:17:15.93,Default,,0,0,0,,现在根据ONES Dialogue: 0,0:17:16.12,0:17:18.03,Default,,0,0,0,,我再给出另一种定义整数的方式 Dialogue: 0,0:17:19.47,0:17:27.36,Default,,0,0,0,,(DEFINE INTEGERS Dialogue: 0,0:17:28.24,0:17:30.76,Default,,0,0,0,,当然 第一个数是1 Dialogue: 0,0:17:32.75,0:17:38.57,Default,,0,0,0,,(CONS-STREAM 1 (ADD-STREAM Dialogue: 0,0:17:40.22,0:17:48.27,Default,,0,0,0,,INTEGERS ONES))) Dialogue: 0,0:17:55.10,0:17:56.35,Default,,0,0,0,,整数流是这样的: Dialogue: 0,0:17:57.24,0:17:59.98,Default,,0,0,0,,它的第一个元素是1 Dialogue: 0,0:18:00.88,0:18:02.32,Default,,0,0,0,,而其余部分则是 Dialogue: 0,0:18:03.12,0:18:06.14,Default,,0,0,0,,依次把每个整数加1 Dialogue: 0,0:18:06.64,0:18:08.19,Default,,0,0,0,,因此 整数流的第二个元素则是 Dialogue: 0,0:18:08.51,0:18:11.96,Default,,0,0,0,,整数流的第一个元素加1 Dialogue: 0,0:18:13.92,0:18:15.18,Default,,0,0,0,,下一个数又要加1 Dialogue: 0,0:18:15.20,0:18:16.48,Default,,0,0,0,,第三个元素则是 Dialogue: 0,0:18:16.62,0:18:20.41,Default,,0,0,0,,INTEGER流尾部分的第一个元素 Dialogue: 0,0:18:20.84,0:18:21.96,Default,,0,0,0,,加1 Dialogue: 0,0:18:22.51,0:18:23.76,Default,,0,0,0,,这也就相当于 Dialogue: 0,0:18:25.08,0:18:28.65,Default,,0,0,0,,最初整数流的第一个元素加1 Dialogue: 0,0:18:28.86,0:18:31.25,Default,,0,0,0,,然后再加1 以此类推 Dialogue: 0,0:18:35.24,0:18:36.31,Default,,0,0,0,,这看起来有点匪夷所思 Dialogue: 0,0:18:36.31,0:18:37.47,Default,,0,0,0,,这样的过程可以正常运行 Dialogue: 0,0:18:38.12,0:18:38.99,Default,,0,0,0,,关键在于延时求值 Dialogue: 0,0:18:40.15,0:18:43.32,Default,,0,0,0,,我们来看这个ONES Dialogue: 0,0:18:43.87,0:18:45.92,Default,,0,0,0,,这看起来根本不可能 Dialogue: 0,0:18:46.25,0:18:47.63,Default,,0,0,0,,因为它突然说 Dialogue: 0,0:18:47.79,0:18:48.96,Default,,0,0,0,,在定义ONES的时候 Dialogue: 0,0:18:49.00,0:18:50.91,Default,,0,0,0,,发现它依赖于它本身 Dialogue: 0,0:18:51.13,0:18:52.08,Default,,0,0,0,,它之所以可以运行是因为 Dialogue: 0,0:18:52.09,0:18:54.04,Default,,0,0,0,,这里暗中隐藏着延时求值 Dialogue: 0,0:18:55.25,0:18:56.56,Default,,0,0,0,,这个代码实际上是 Dialogue: 0,0:18:57.79,0:18:59.69,Default,,0,0,0,,回忆下 CONS-STREAM是只是一个缩写 Dialogue: 0,0:19:00.29,0:19:01.15,Default,,0,0,0,,实际上则是 Dialogue: 0,0:19:01.85,0:19:08.99,Default,,0,0,0,,(CONS 1 (DELAY ONES)) Dialogue: 0,0:19:12.14,0:19:13.21,Default,,0,0,0,,它又是怎么运作的呢? Dialogue: 0,0:19:15.50,0:19:16.88,Default,,0,0,0,,你想要定义ONES Dialogue: 0,0:19:18.02,0:19:20.24,Default,,0,0,0,,我来看看ONES要被定义成什么样 Dialogue: 0,0:19:20.70,0:19:23.40,Default,,0,0,0,,ONES被定义为一个序对 Dialogue: 0,0:19:24.89,0:19:28.11,Default,,0,0,0,,其CAR部分为1 Dialogue: 0,0:19:28.32,0:19:29.45,Default,,0,0,0,,而CDR部分则是 Dialogue: 0,0:19:29.45,0:19:30.73,Default,,0,0,0,,是一个计算某物的PROMISE Dialogue: 0,0:19:30.75,0:19:31.69,Default,,0,0,0,,我现在还不用关心 Dialogue: 0,0:19:32.71,0:19:34.25,Default,,0,0,0,,所以虽然这时ONES还没有定义 Dialogue: 0,0:19:34.28,0:19:36.30,Default,,0,0,0,,但对我并不造成什么影响 Dialogue: 0,0:19:37.27,0:19:39.45,Default,,0,0,0,,一旦运行了整个定义 ONES就被定义了 Dialogue: 0,0:19:40.67,0:19:42.83,Default,,0,0,0,,所以 访问它尾部的时候 它就有定义了 Dialogue: 0,0:19:44.92,0:19:46.06,Default,,0,0,0,,这一点非常隐讳 Dialogue: 0,0:19:46.59,0:19:47.90,Default,,0,0,0,,整数流的定义也是如此 Dialogue: 0,0:19:48.47,0:19:50.46,Default,,0,0,0,,我可以在这里引用INTEGERS是因为 Dialogue: 0,0:19:51.13,0:19:53.21,Default,,0,0,0,,是因为这个CONS-STREAM的缘故 Dialogue: 0,0:19:53.85,0:19:55.24,Default,,0,0,0,,用CONS-STREAM把1 Dialogue: 0,0:19:55.37,0:19:57.05,Default,,0,0,0,,和一个不立即需要的东西组合起来 Dialogue: 0,0:19:57.05,0:19:59.60,Default,,0,0,0,,所以我在运行INTEGERS的定义的时候 Dialogue: 0,0:20:00.22,0:20:01.90,Default,,0,0,0,,并不会发现INTEGER没有定义过 Dialogue: 0,0:20:06.32,0:20:08.27,Default,,0,0,0,,听上去非常玄乎 Dialogue: 0,0:20:08.44,0:20:11.50,Default,,0,0,0,,让我用图像来演示一下INTEGERS的原理 Dialogue: 0,0:20:12.43,0:20:14.72,Default,,0,0,0,,怎么画呢? Dialogue: 0,0:20:15.02,0:20:16.30,Default,,0,0,0,,首先是ONES这个流 Dialogue: 0,0:20:20.51,0:20:21.88,Default,,0,0,0,,它作为参数输入 Dialogue: 0,0:20:23.26,0:20:24.92,Default,,0,0,0,,进入一个加法器 Dialogue: 0,0:20:24.96,0:20:26.59,Default,,0,0,0,,进行流的加法运算 Dialogue: 0,0:20:29.31,0:20:35.87,Default,,0,0,0,,输出则是整数流INTEGERS Dialogue: 0,0:20:40.76,0:20:42.70,Default,,0,0,0,,这里 这个整数流又重新进入加法器 Dialogue: 0,0:20:44.94,0:20:46.97,Default,,0,0,0,,形成了一个小型的反馈回路 Dialogue: 0,0:20:48.06,0:20:49.42,Default,,0,0,0,,我需要在某处接入最初的ONES Dialogue: 0,0:20:50.09,0:20:52.88,Default,,0,0,0,,才能让它生效 Dialogue: 0,0:20:57.10,0:20:58.64,Default,,0,0,0,,在真实的信号处理中 Dialogue: 0,0:20:58.72,0:21:02.48,Default,,0,0,0,,这里是一个被初始化为1的延时元件 Dialogue: 0,0:21:02.91,0:21:05.90,Default,,0,0,0,,这就是ONES程序的图示 Dialogue: 0,0:21:07.86,0:21:09.63,Default,,0,0,0,,事实上 这个非常像 Dialogue: 0,0:21:09.80,0:21:13.77,Default,,0,0,0,,如果你见过真正的信号方块图的话 Dialogue: 0,0:21:13.77,0:21:16.30,Default,,0,0,0,,这个图形非常像累加器 Dialogue: 0,0:21:16.35,0:21:17.48,Default,,0,0,0,,有穷状态累加器 Dialogue: 0,0:21:17.98,0:21:20.06,Default,,0,0,0,,事实上 我们可以稍加修改 Dialogue: 0,0:21:21.18,0:21:23.96,Default,,0,0,0,,就可以让它对一个流做积分 Dialogue: 0,0:21:25.37,0:21:26.97,Default,,0,0,0,,或者说是有穷状态累加器 Dialogue: 0,0:21:27.00,0:21:28.04,Default,,0,0,0,,你怎么认为都可以 Dialogue: 0,0:21:28.44,0:21:30.86,Default,,0,0,0,,现在 不再是输入ONES 输出INTEGERS Dialogue: 0,0:21:31.68,0:21:32.38,Default,,0,0,0,,我们要做的是 Dialogue: 0,0:21:32.91,0:21:34.83,Default,,0,0,0,,这里有一个流S为输入 Dialogue: 0,0:21:35.76,0:21:40.56,Default,,0,0,0,,我们要计算这个流的积分 Dialogue: 0,0:21:42.60,0:21:44.09,Default,,0,0,0,,也就是累加这个流的值 Dialogue: 0,0:21:44.44,0:21:45.63,Default,,0,0,0,,这看起来几乎就是一样的 Dialogue: 0,0:21:45.66,0:21:46.84,Default,,0,0,0,,我们要做的就是 Dialogue: 0,0:21:47.02,0:21:48.08,Default,,0,0,0,,当S从这里输入时 Dialogue: 0,0:21:49.21,0:21:50.64,Default,,0,0,0,,在把它求和之前 Dialogue: 0,0:21:50.91,0:21:54.26,Default,,0,0,0,,先将其乘以dt Dialogue: 0,0:21:57.68,0:22:00.00,Default,,0,0,0,,剩下的就不用改了 Dialogue: 0,0:22:00.00,0:22:00.91,Default,,0,0,0,,我们就得到了一个盒子 Dialogue: 0,0:22:03.36,0:22:04.56,Default,,0,0,0,,一个积分器 Dialogue: 0,0:22:09.79,0:22:11.26,Default,,0,0,0,,对一个流S进行积分 Dialogue: 0,0:22:11.90,0:22:14.51,Default,,0,0,0,,把这里的1替换为 Dialogue: 0,0:22:14.94,0:22:18.35,Default,,0,0,0,,该积分的初始值 Dialogue: 0,0:22:19.98,0:22:21.60,Default,,0,0,0,,这个看起来就非常像 Dialogue: 0,0:22:22.35,0:22:24.86,Default,,0,0,0,,信号处理中的方框图了 Dialogue: 0,0:22:25.27,0:22:28.11,Default,,0,0,0,,事实上 这个图示对应的是这样一个过程 Dialogue: 0,0:22:31.49,0:22:33.61,Default,,0,0,0,,对一个流进行积分 Dialogue: 0,0:22:34.01,0:22:35.48,Default,,0,0,0,,INTEGRAL函数接收一个流 Dialogue: 0,0:22:35.68,0:22:36.86,Default,,0,0,0,,返回一个新的流 Dialogue: 0,0:22:37.53,0:22:40.67,Default,,0,0,0,,它还接收一个初始值和某个时间常量 Dialogue: 0,0:22:42.23,0:22:42.97,Default,,0,0,0,,然后呢? Dialogue: 0,0:22:43.04,0:22:45.05,Default,,0,0,0,,首先在内部定义一个流INT Dialogue: 0,0:22:45.20,0:22:46.32,Default,,0,0,0,,之所以要给它一个内部名字 Dialogue: 0,0:22:46.33,0:22:48.86,Default,,0,0,0,,原因在于可以使它反馈 以形成循环 Dialogue: 0,0:22:49.40,0:22:50.80,Default,,0,0,0,,INT的定义是 Dialogue: 0,0:22:51.10,0:22:53.32,Default,,0,0,0,,一个以INITIA-VALUE开始的流 Dialogue: 0,0:22:54.97,0:23:00.14,Default,,0,0,0,,而其余的元素则是把它们加起来 Dialogue: 0,0:23:01.28,0:23:03.61,Default,,0,0,0,,我们把输入流乘以dt Dialogue: 0,0:23:03.87,0:23:04.92,Default,,0,0,0,,然后和INT相加 Dialogue: 0,0:23:06.88,0:23:09.66,Default,,0,0,0,,整个INTEGRAL函数的结果就是这个INT Dialogue: 0,0:23:10.69,0:23:12.94,Default,,0,0,0,,我们使用这种内部定义的语法 Dialogue: 0,0:23:13.34,0:23:15.66,Default,,0,0,0,,是为了可以在内部引用它自己 Dialogue: 0,0:23:21.88,0:23:23.71,Default,,0,0,0,,我们还可以做更多的事情 Dialogue: 0,0:23:23.71,0:23:24.51,Default,,0,0,0,,来看这个 Dialogue: 0,0:23:25.63,0:23:26.89,Default,,0,0,0,,斐波那契数 Dialogue: 0,0:23:26.89,0:23:32.62,Default,,0,0,0,,(DEFINE FIBS Dialogue: 0,0:23:36.35,0:23:37.63,Default,,0,0,0,,斐波那契数是什么呢? Dialogue: 0,0:23:37.98,0:23:46.54,Default,,0,0,0,,它从0开始 Dialogue: 0,0:23:48.65,0:23:50.09,Default,,0,0,0,,下一个是1 Dialogue: 0,0:23:56.26,0:23:59.16,Default,,0,0,0,,的其余的斐波那契数是通过 Dialogue: 0,0:23:59.87,0:24:11.00,Default,,0,0,0,,把它们的尾部分求和而得来 Dialogue: 0,0:24:17.57,0:24:19.28,Default,,0,0,0,,这样来定义斐波那契数 Dialogue: 0,0:24:20.58,0:24:21.43,Default,,0,0,0,,这是如何运作的呢? Dialogue: 0,0:24:21.43,0:24:24.19,Default,,0,0,0,,我们来试试 Dialogue: 0,0:24:24.20,0:24:26.49,Default,,0,0,0,,假如开始计算斐波那契数 Dialogue: 0,0:24:29.64,0:24:31.92,Default,,0,0,0,,首先告诉你 它以0和1开始 Dialogue: 0,0:24:35.79,0:24:38.22,Default,,0,0,0,,而0和1之后的数则是 Dialogue: 0,0:24:39.18,0:24:40.86,Default,,0,0,0,,通过加和两个流而得 Dialogue: 0,0:24:41.12,0:24:42.59,Default,,0,0,0,,一个流是FIBS本身 Dialogue: 0,0:24:44.06,0:24:45.69,Default,,0,0,0,,另一个是FIBS的尾部分 Dialogue: 0,0:24:49.12,0:24:51.16,Default,,0,0,0,,如果我知道这是以0和1起始的 Dialogue: 0,0:24:51.79,0:24:55.42,Default,,0,0,0,,我就能知道 FIBS是以0和1起始的 Dialogue: 0,0:24:55.74,0:24:57.40,Default,,0,0,0,,那么 FIBS的尾部分则应该以1开始 Dialogue: 0,0:24:58.36,0:24:59.45,Default,,0,0,0,,一旦我知道了这点 Dialogue: 0,0:24:59.66,0:25:02.11,Default,,0,0,0,,我就知道 FIBS的下一个数就是0+1=1 Dialogue: 0,0:25:02.96,0:25:04.60,Default,,0,0,0,,它也同样告诉我这里是1 Dialogue: 0,0:25:04.62,0:25:05.72,Default,,0,0,0,,这里也是1 Dialogue: 0,0:25:06.30,0:25:07.28,Default,,0,0,0,,知道了这些之后 Dialogue: 0,0:25:07.29,0:25:08.76,Default,,0,0,0,,我就知道下一个是2 Dialogue: 0,0:25:09.39,0:25:11.70,Default,,0,0,0,,这里是2 这里也是2 Dialogue: 0,0:25:11.70,0:25:12.56,Default,,0,0,0,,下一个是3 Dialogue: 0,0:25:14.72,0:25:15.79,Default,,0,0,0,,这里是3 Dialogue: 0,0:25:16.19,0:25:17.13,Default,,0,0,0,,这里是5 Dialogue: 0,0:25:18.67,0:25:19.96,Default,,0,0,0,,这个定义完全说得通 Dialogue: 0,0:25:21.50,0:25:22.78,Default,,0,0,0,,这个定义只有一行 Dialogue: 0,0:25:22.83,0:25:25.00,Default,,0,0,0,,当然 我也可以在计算机中 Dialogue: 0,0:25:25.00,0:25:26.62,Default,,0,0,0,,原原本本地键入计算机中 Dialogue: 0,0:25:27.04,0:25:28.94,Default,,0,0,0,,然后要求输出斐波那契数 Dialogue: 0,0:25:28.94,0:25:30.15,Default,,0,0,0,,然后它就会不断输出 Dialogue: 0,0:25:32.79,0:25:35.20,Default,,0,0,0,,这又像是在学习递归 Dialogue: 0,0:25:36.81,0:25:39.79,Default,,0,0,0,,过程可以被递归定义 Dialogue: 0,0:25:40.99,0:25:43.50,Default,,0,0,0,,我们也可以递归地定义数据对象 Dialogue: 0,0:25:45.16,0:25:46.92,Default,,0,0,0,,但你们一点儿不应该感到吃惊 Dialogue: 0,0:25:47.12,0:25:49.50,Default,,0,0,0,,因为现在 你们应该真正相信 Dialogue: 0,0:25:49.52,0:25:53.05,Default,,0,0,0,,过程与数据之间没有区别 Dialogue: 0,0:25:53.09,0:25:53.92,Default,,0,0,0,,事实上 就某种意义上来说 Dialogue: 0,0:25:53.93,0:25:56.41,Default,,0,0,0,,流也是由过程来实现的 Dialogue: 0,0:25:56.43,0:25:57.79,Default,,0,0,0,,只不过我们不把它看做过程而已 Dialogue: 0,0:25:58.21,0:26:00.38,Default,,0,0,0,,因此既然我们有递归过程 Dialogue: 0,0:26:00.70,0:26:03.63,Default,,0,0,0,,那么 有递归数据也就不足为奇了 Dialogue: 0,0:26:07.72,0:26:09.69,Default,,0,0,0,,虽然流非常简洁 Dialogue: 0,0:26:09.72,0:26:13.92,Default,,0,0,0,,但不幸的是 有些问题流无法解决 Dialogue: 0,0:26:14.99,0:26:16.48,Default,,0,0,0,,我来举个例子 Dialogue: 0,0:26:17.58,0:26:20.35,Default,,0,0,0,,同样地 我们来想象一下 Dialogue: 0,0:26:20.76,0:26:23.61,Default,,0,0,0,,我们正在构建求解微分方程的模拟计算机 Dialogue: 0,0:26:25.20,0:26:34.30,Default,,0,0,0,,比如求解方程 y' = y^2 Dialogue: 0,0:26:34.76,0:26:36.16,Default,,0,0,0,,我会给你一个初值 Dialogue: 0,0:26:36.39,0:26:38.03,Default,,0,0,0,,y(0) = 1 Dialogue: 0,0:26:41.48,0:26:44.06,Default,,0,0,0,,dt = .0001 Dialogue: 0,0:26:46.77,0:26:47.53,Default,,0,0,0,,很久之前 Dialogue: 0,0:26:48.00,0:26:50.65,Default,,0,0,0,,就有人构建模拟计算机 来解决这类问题 Dialogue: 0,0:26:51.36,0:26:53.02,Default,,0,0,0,,原理非常简单 Dialogue: 0,0:26:53.02,0:26:54.41,Default,,0,0,0,,你首先需要一个积分器 Dialogue: 0,0:27:00.04,0:27:01.69,Default,,0,0,0,,比如这个INT盒子 Dialogue: 0,0:27:03.05,0:27:06.48,Default,,0,0,0,,我们设定初始值 y(0) = 1 Dialogue: 0,0:27:08.53,0:27:10.92,Default,,0,0,0,,现在如果我们送入一个输入 就会得到输出 Dialogue: 0,0:27:10.96,0:27:13.16,Default,,0,0,0,,输出的结果就是y Dialogue: 0,0:27:14.25,0:27:16.96,Default,,0,0,0,,输入的是y的导数 Dialogue: 0,0:27:17.52,0:27:20.52,Default,,0,0,0,,在这里 导数 y' = y^2 Dialogue: 0,0:27:21.49,0:27:27.07,Default,,0,0,0,,如果我们用MAP把SQUARE映射在这些值上 Dialogue: 0,0:27:30.73,0:27:32.09,Default,,0,0,0,,然后把这个引过来 Dialogue: 0,0:27:36.28,0:27:38.48,Default,,0,0,0,,这个方块图 Dialogue: 0,0:27:38.57,0:27:41.08,Default,,0,0,0,,就是用于求解这个微分方程的模拟计算机 Dialogue: 0,0:27:42.91,0:27:44.80,Default,,0,0,0,,现在我们用代码 Dialogue: 0,0:27:44.80,0:27:46.78,Default,,0,0,0,,来表示下这个过程 Dialogue: 0,0:27:47.23,0:27:48.72,Default,,0,0,0,,这个图究竟表示的是什么呢? Dialogue: 0,0:27:49.39,0:27:58.30,Default,,0,0,0,,(DEFINE Y Dialogue: 0,0:28:04.28,0:28:11.68,Default,,0,0,0,,(INTEGRAL DY 1 .001)) Dialogue: 0,0:28:13.79,0:28:15.45,Default,,0,0,0,,接下来 Dialogue: 0,0:28:16.80,0:28:20.85,Default,,0,0,0,,通过MAP SQUARE 来表示dy Dialogue: 0,0:28:20.85,0:28:32.81,Default,,0,0,0,,(DEFINE DY (MAP SQUARE Y)) Dialogue: 0,0:28:33.51,0:28:36.80,Default,,0,0,0,,这就是这个模拟计算机的流式描述 Dialogue: 0,0:28:38.62,0:28:40.32,Default,,0,0,0,,不幸的是 它并不起效 Dialogue: 0,0:28:41.41,0:28:42.67,Default,,0,0,0,,你也可以发现这是为什么 Dialogue: 0,0:28:42.97,0:28:44.99,Default,,0,0,0,,因为我把Y定义为 Dialogue: 0,0:28:46.43,0:28:47.85,Default,,0,0,0,,DY 的积分 Dialogue: 0,0:28:49.04,0:28:50.65,Default,,0,0,0,,它会问 对什么的积分? Dialogue: 0,0:28:51.19,0:28:52.12,Default,,0,0,0,,没定义啊 Dialogue: 0,0:28:53.71,0:28:57.63,Default,,0,0,0,,所以这个定义必须写在这个定义的后面 Dialogue: 0,0:28:58.77,0:29:00.51,Default,,0,0,0,,另一方面 如果先定义了dy Dialogue: 0,0:29:00.51,0:29:03.02,Default,,0,0,0,,定义为 (MAP SQUARE 某个东西) Dialogue: 0,0:29:03.58,0:29:04.64,Default,,0,0,0,,这个也还没有定义 Dialogue: 0,0:29:05.77,0:29:08.17,Default,,0,0,0,,我既不能先写这个 又不能先写那个 Dialogue: 0,0:29:09.08,0:29:11.58,Default,,0,0,0,,这个游戏就没法玩了 Dialogue: 0,0:29:17.56,0:29:18.51,Default,,0,0,0,,怎样来解决呢? Dialogue: 0,0:29:20.60,0:29:21.84,Default,,0,0,0,,我们可以用ONES来解决 Dialogue: 0,0:29:22.20,0:29:25.82,Default,,0,0,0,,所以 我们在这里定义的ONES Dialogue: 0,0:29:27.24,0:29:29.90,Default,,0,0,0,,我们之所以可以使用ONES来定义ONES Dialogue: 0,0:29:30.40,0:29:32.03,Default,,0,0,0,,这是因为其中的延时求值 Dialogue: 0,0:29:32.43,0:29:34.12,Default,,0,0,0,,CONS-STREAM是延时求值的 Dialogue: 0,0:29:34.77,0:29:35.79,Default,,0,0,0,,那么 这又为什么说得通呢? Dialogue: 0,0:29:35.92,0:29:38.51,Default,,0,0,0,,为什么CONS-STREAM是延时求值的是合理的呢? Dialogue: 0,0:29:40.73,0:29:43.13,Default,,0,0,0,,原因在于 CONS-STREAM不需要其尾部分 Dialogue: 0,0:29:43.48,0:29:44.88,Default,,0,0,0,,就可以完成有意义的事 Dialogue: 0,0:29:45.95,0:29:46.84,Default,,0,0,0,,比如我说 Dialogue: 0,0:29:47.48,0:29:49.64,Default,,0,0,0,,这个是1和某个东西组成的流 Dialogue: 0,0:29:49.92,0:29:51.69,Default,,0,0,0,,虽然我对它一无所知 Dialogue: 0,0:29:52.16,0:29:54.03,Default,,0,0,0,,但我却知道整个流是以1开始的 Dialogue: 0,0:29:54.87,0:29:57.29,Default,,0,0,0,,所以用CONS-STREAM来构造是有意义的 Dialogue: 0,0:29:59.96,0:30:01.24,Default,,0,0,0,,我们在这里放了一个DELAY Dialogue: 0,0:30:01.42,0:30:04.65,Default,,0,0,0,,这就使得我们能够进行某种自引用的定义 Dialogue: 0,0:30:06.32,0:30:07.95,Default,,0,0,0,,INTEGRAL也可以用这种方式来解决 Dialogue: 0,0:30:08.19,0:30:12.52,Default,,0,0,0,,注意 对于INTEGRAL来说 我可以 Dialogue: 0,0:30:14.60,0:30:16.08,Default,,0,0,0,,让我们回过头来再看看INTEGRAL的定义 Dialogue: 0,0:30:17.58,0:30:18.56,Default,,0,0,0,,求积分的时候 Dialogue: 0,0:30:21.39,0:30:25.00,Default,,0,0,0,,知道INTEGRAL的第一个元素是合理的 Dialogue: 0,0:30:26.04,0:30:27.87,Default,,0,0,0,,尽管还不知道整个流是什么样的 Dialogue: 0,0:30:28.97,0:30:30.17,Default,,0,0,0,,这是因为INTEGRAL中第一个元素 Dialogue: 0,0:30:30.20,0:30:32.16,Default,,0,0,0,,总会是你传递过来的INITIAL-VALUE Dialogue: 0,0:30:33.14,0:30:36.11,Default,,0,0,0,,所以INTEGRAL可以用CONS-STREAM来实现 Dialogue: 0,0:30:37.09,0:30:37.98,Default,,0,0,0,,我们可以定义它 Dialogue: 0,0:30:38.25,0:30:40.88,Default,,0,0,0,,甚至不用知道要积分的流是什么 Dialogue: 0,0:30:42.84,0:30:45.18,Default,,0,0,0,,只需要知道初始值是什么就行了 Dialogue: 0,0:30:46.71,0:30:48.17,Default,,0,0,0,,INTEGRAL还可以修改得更为智能 Dialogue: 0,0:30:48.41,0:30:50.68,Default,,0,0,0,,我们给它一个待积分的流 Dialogue: 0,0:30:50.83,0:30:51.92,Default,,0,0,0,,以及一个初值 Dialogue: 0,0:30:52.11,0:30:54.99,Default,,0,0,0,,直到你要求沿着这个流求解积分时 Dialogue: 0,0:30:55.21,0:30:56.97,Default,,0,0,0,,我才关心这个流是什么 Dialogue: 0,0:30:58.43,0:31:00.51,Default,,0,0,0,,换句话说INTEGRAL可以像CONS-STREAM一样 Dialogue: 0,0:31:00.57,0:31:03.74,Default,,0,0,0,,你可以认为INTEGRAL被放在DELAY之中 Dialogue: 0,0:31:03.76,0:31:04.86,Default,,0,0,0,,我们这样修改 Dialogue: 0,0:31:05.61,0:31:07.02,Default,,0,0,0,,这个过程是像这样的 Dialogue: 0,0:31:07.65,0:31:08.75,Default,,0,0,0,,这是另一个版本的INTEGRAL Dialogue: 0,0:31:08.89,0:31:10.54,Default,,0,0,0,,这个跟之前的版本非常相似 Dialogue: 0,0:31:11.10,0:31:13.34,Default,,0,0,0,,只不过作为参数的流 Dialogue: 0,0:31:13.77,0:31:15.69,Default,,0,0,0,,必须要是一个延时对象 Dialogue: 0,0:31:17.11,0:31:18.43,Default,,0,0,0,,这个INTEGRAL又是如何运作的呢? Dialogue: 0,0:31:18.85,0:31:21.79,Default,,0,0,0,,我们在内部定义的INT则是 Dialogue: 0,0:31:22.14,0:31:24.19,Default,,0,0,0,,用CONS-STREAM构造一个流 Dialogue: 0,0:31:24.73,0:31:26.44,Default,,0,0,0,,初值还是INITIAL-VALUE Dialogue: 0,0:31:27.16,0:31:29.68,Default,,0,0,0,,但是在CONS-STREAM中 Dialogue: 0,0:31:29.74,0:31:32.30,Default,,0,0,0,,要注意 这里面有个隐藏的DELAY Dialogue: 0,0:31:34.95,0:31:39.07,Default,,0,0,0,,只有在这个CONS-STREAM的内部 Dialogue: 0,0:31:39.82,0:31:42.11,Default,,0,0,0,,我才会查看延时对象的实际内容 Dialogue: 0,0:31:43.18,0:31:45.79,Default,,0,0,0,,所以 答案的第一个元素将会是初值 Dialogue: 0,0:31:45.97,0:31:47.90,Default,,0,0,0,,如果有人想访问我的尾部分 Dialogue: 0,0:31:48.40,0:31:49.42,Default,,0,0,0,,此时 Dialogue: 0,0:31:50.00,0:31:51.72,Default,,0,0,0,,我会FORCE该延迟对象 Dialogue: 0,0:31:52.62,0:31:53.60,Default,,0,0,0,,把结果记作S Dialogue: 0,0:31:54.44,0:31:55.60,Default,,0,0,0,,然后再进行ADD-STREAMS Dialogue: 0,0:31:56.36,0:31:59.26,Default,,0,0,0,,这个INTEGRAL就有点像CONS-STREAM Dialogue: 0,0:31:59.26,0:32:02.59,Default,,0,0,0,,直到你确实需要知道第一个元素的时候 Dialogue: 0,0:32:03.88,0:32:07.13,Default,,0,0,0,,它才会去查看DELAYED-S是什么 Dialogue: 0,0:32:10.12,0:32:11.02,Default,,0,0,0,,如果这样的话 Dialogue: 0,0:32:11.52,0:32:12.83,Default,,0,0,0,,也就能求解 y' = y^2 了 Dialogue: 0,0:32:13.36,0:32:15.20,Default,,0,0,0,,这里我们只需要 Dialogue: 0,0:32:16.00,0:32:25.31,Default,,0,0,0,,把Y定义为对延时对象DY的积分 Dialogue: 0,0:32:27.09,0:32:28.22,Default,,0,0,0,,所以Y的定义就变成了 Dialogue: 0,0:32:28.40,0:32:34.36,Default,,0,0,0,,(INTEGRAL (DELAY DY) 1 .001) Dialogue: 0,0:32:34.38,0:32:35.13,Default,,0,0,0,,这样一来就可以了 Dialogue: 0,0:32:35.28,0:32:37.44,Default,,0,0,0,,因为我输入Y的定义 Dialogue: 0,0:32:38.00,0:32:39.68,Default,,0,0,0,,它是某个东西的积分 Dialogue: 0,0:32:40.20,0:32:42.68,Default,,0,0,0,,但这是个延迟对象 我现在还不用关心 Dialogue: 0,0:32:44.60,0:32:46.32,Default,,0,0,0,,这之后 再定义DY Dialogue: 0,0:32:46.32,0:32:47.37,Default,,0,0,0,,现在Y就有定义了 Dialogue: 0,0:32:47.55,0:32:48.89,Default,,0,0,0,,所以我在定义DY时 Dialogue: 0,0:32:49.13,0:32:50.67,Default,,0,0,0,,它可以知道Y的定义 Dialogue: 0,0:32:51.70,0:32:52.84,Default,,0,0,0,,一切都正常了 Dialogue: 0,0:32:52.84,0:32:54.33,Default,,0,0,0,,两个流都有第一个元素 Dialogue: 0,0:32:54.92,0:32:56.25,Default,,0,0,0,,当我不断取得下一个元素 Dialogue: 0,0:32:56.27,0:32:57.31,Default,,0,0,0,,沿着流做MAP运算时 Dialogue: 0,0:32:57.37,0:32:58.88,Default,,0,0,0,,Y和DY都被定义过了 Dialogue: 0,0:33:00.59,0:33:04.24,Default,,0,0,0,,所以为了继续这个游戏 我们不能仅仅 Dialogue: 0,0:33:04.67,0:33:07.13,Default,,0,0,0,,只使用隐藏在流中的DELAY Dialogue: 0,0:33:08.36,0:33:08.97,Default,,0,0,0,,有问题么? Dialogue: 0,0:33:13.52,0:33:14.27,Default,,0,0,0,,休息一下吧 Dialogue: 0,0:33:14.72,0:33:26.86,Default,,0,0,0,,[音乐] Dialogue: 0,0:33:27.37,0:33:30.94,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:33:52.16,0:33:55.26,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:33:55.42,0:33:59.26,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:34:00.38,0:34:03.93,Declare,,0,0,0,,{\an2\fad(500,500)}流 II Dialogue: 0,0:34:07.30,0:34:10.04,Default,,0,0,0,,上节课的最后 Dialogue: 0,0:34:10.89,0:34:11.80,Default,,0,0,0,,不知道你们注意到没有 Dialogue: 0,0:34:11.82,0:34:13.55,Default,,0,0,0,,事情正变得糟糕起来 Dialogue: 0,0:34:14.83,0:34:18.40,Default,,0,0,0,,我们讲了很多关于 流 Dialogue: 0,0:34:19.16,0:34:22.68,Default,,0,0,0,,以及分离程序中的时间和计算机中的时间 Dialogue: 0,0:34:22.86,0:34:26.28,Default,,0,0,0,,这些分离都被隐藏在流中了 Dialogue: 0,0:34:27.28,0:34:29.50,Default,,0,0,0,,上节课快结束时我们发现 Dialogue: 0,0:34:29.71,0:34:32.19,Default,,0,0,0,,为了真正发挥这种方法的优势 Dialogue: 0,0:34:32.22,0:34:34.38,Default,,0,0,0,,我们需要另外的DELAY Dialogue: 0,0:34:34.38,0:34:35.85,Default,,0,0,0,,不只需要隐藏在CONS-STREAM中的DELAY Dialogue: 0,0:34:36.09,0:34:37.95,Default,,0,0,0,,还需要显式地使用DELAY Dialogue: 0,0:34:39.03,0:34:41.88,Default,,0,0,0,,我只是用微分方程举了一个很简单的例子 Dialogue: 0,0:34:42.35,0:34:44.08,Default,,0,0,0,,但是如果你有一个非常复杂的系统 Dialogue: 0,0:34:44.12,0:34:45.40,Default,,0,0,0,,里面充斥着各种各样的自循环 Dialogue: 0,0:34:45.95,0:34:47.84,Default,,0,0,0,,那就很难再发现 Dialogue: 0,0:34:47.90,0:34:49.31,Default,,0,0,0,,在什么地方需要额外的DELAY了 Dialogue: 0,0:34:49.92,0:34:51.18,Default,,0,0,0,,假如你一不小心漏了一个 Dialogue: 0,0:34:51.45,0:34:54.36,Default,,0,0,0,,就很难发现程序为什么不起效 Dialogue: 0,0:34:55.55,0:34:57.15,Default,,0,0,0,,这是一种混乱 Dialogue: 0,0:34:57.79,0:35:01.71,Default,,0,0,0,,让我们能够使用DELAY Dialogue: 0,0:35:02.08,0:35:04.70,Default,,0,0,0,,有时却会让程序设计变得非常复杂 Dialogue: 0,0:35:04.72,0:35:06.80,Default,,0,0,0,,因为它们不能完全隐藏在流中 Dialogue: 0,0:35:08.51,0:35:09.79,Default,,0,0,0,,那么 有没有什么解决方案呢? Dialogue: 0,0:35:11.13,0:35:12.67,Default,,0,0,0,,所幸的是 有 Dialogue: 0,0:35:13.48,0:35:16.08,Default,,0,0,0,,我们可以修改整个语言 Dialogue: 0,0:35:16.14,0:35:18.19,Default,,0,0,0,,使得所有的过程都表现得像CONS-STREAM一样 Dialogue: 0,0:35:19.10,0:35:21.48,Default,,0,0,0,,这样所有的过程都会 Dialogue: 0,0:35:22.32,0:35:25.45,Default,,0,0,0,,自动、隐式地为它的参数加上DELAY Dialogue: 0,0:35:25.45,0:35:26.43,Default,,0,0,0,,这是什么意思呢? Dialogue: 0,0:35:27.52,0:35:29.53,Default,,0,0,0,,就是说 当你调用一个过程时 Dialogue: 0,0:35:30.16,0:35:31.88,Default,,0,0,0,,参数并不会立即求值 Dialogue: 0,0:35:32.21,0:35:34.70,Default,,0,0,0,,只有在需要被求值的时候 它们才会被求值 Dialogue: 0,0:35:34.89,0:35:36.72,Default,,0,0,0,,它们也可能被传递给其它的过程 Dialogue: 0,0:35:36.76,0:35:38.12,Default,,0,0,0,,而这个过程也不会求值这些参数 Dialogue: 0,0:35:39.26,0:35:41.90,Default,,0,0,0,,因此这些过程间传递的是PROMISE Dialogue: 0,0:35:42.15,0:35:44.46,Default,,0,0,0,,直到最后 Dialogue: 0,0:35:44.65,0:35:47.34,Default,,0,0,0,,你需要查看某个值的时候 Dialogue: 0,0:35:47.36,0:35:48.99,Default,,0,0,0,,可能是因为一个基本运算所需要 Dialogue: 0,0:35:49.37,0:35:51.48,Default,,0,0,0,,这是你才实际求值这些PROMISE Dialogue: 0,0:35:52.38,0:35:53.16,Default,,0,0,0,,像这样修改语言之后 Dialogue: 0,0:35:53.36,0:35:55.37,Default,,0,0,0,,由于所有的东西都是统一被延时的 Dialogue: 0,0:35:57.16,0:35:59.00,Default,,0,0,0,,就不需要任何显式的DELAY了 Dialogue: 0,0:35:59.04,0:36:01.55,Default,,0,0,0,,因为它自动地内建在语言之中了 Dialogue: 0,0:36:03.24,0:36:04.38,Default,,0,0,0,,换句话来说 Dialogue: 0,0:36:05.10,0:36:08.14,Default,,0,0,0,,从技术上来说 我所描述的 Dialogue: 0,0:36:09.02,0:36:10.76,Default,,0,0,0,,如果修改后的语言被称作 Dialogue: 0,0:36:12.19,0:36:16.57,Default,,0,0,0,,所谓的“正则序求值”语言 Dialogue: 0,0:36:20.20,0:36:23.47,Default,,0,0,0,,这个跟我们一直使用的语言不同 Dialogue: 0,0:36:23.87,0:36:33.79,Default,,0,0,0,,我们所用的是“应用序求值”语言 Dialogue: 0,0:36:34.56,0:36:36.83,Default,,0,0,0,,还记得应用序求值的代换模型吧 Dialogue: 0,0:36:36.83,0:36:40.49,Default,,0,0,0,,当你求值一个组合式的时候 Dialogue: 0,0:36:40.51,0:36:42.11,Default,,0,0,0,,你需要先计算出每一个元素的值 Dialogue: 0,0:36:43.59,0:36:45.40,Default,,0,0,0,,先求值所有的参数 Dialogue: 0,0:36:45.72,0:36:47.42,Default,,0,0,0,,再把它们代换入过程的体 Dialogue: 0,0:36:47.60,0:36:49.55,Default,,0,0,0,,正则序则不是这样 Dialogue: 0,0:36:49.89,0:36:51.90,Default,,0,0,0,,你所做的则是 Dialogue: 0,0:36:52.76,0:36:54.41,Default,,0,0,0,,直接将参数代换入过程的体 Dialogue: 0,0:36:54.44,0:36:56.19,Default,,0,0,0,,而不先对参数求值 Dialogue: 0,0:36:56.54,0:36:58.08,Default,,0,0,0,,只是代换入了一个计算参数的PROMISE Dialogue: 0,0:36:58.81,0:36:59.90,Default,,0,0,0,,换句话说就是 Dialogue: 0,0:36:59.92,0:37:02.09,Default,,0,0,0,,把作为参数的整个表达式 Dialogue: 0,0:37:02.28,0:37:04.84,Default,,0,0,0,,直接代入过程的体进行代换 Dialogue: 0,0:37:05.16,0:37:06.88,Default,,0,0,0,,在此之间从不进行任何化简 Dialogue: 0,0:37:07.16,0:37:08.76,Default,,0,0,0,,直到遇到一个基本运算符 Dialogue: 0,0:37:09.47,0:37:10.99,Default,,0,0,0,,这就是所谓的正则序求值语言 Dialogue: 0,0:37:12.17,0:37:13.12,Default,,0,0,0,,我们为什么不这样做呢? Dialogue: 0,0:37:13.82,0:37:14.60,Default,,0,0,0,,这样做了之后 Dialogue: 0,0:37:15.00,0:37:17.34,Default,,0,0,0,,我们就获得了延时求值的所有优点 Dialogue: 0,0:37:17.90,0:37:18.80,Default,,0,0,0,,而不会一片混乱 Dialogue: 0,0:37:18.94,0:37:20.19,Default,,0,0,0,,事实上 如果我们这样做了之后 Dialogue: 0,0:37:20.43,0:37:22.67,Default,,0,0,0,,CONS也会是延时求值的 Dialogue: 0,0:37:22.68,0:37:24.57,Default,,0,0,0,,就和CONS-STREAM一样 Dialogue: 0,0:37:24.71,0:37:25.82,Default,,0,0,0,,我们就不再需要流了 Dialogue: 0,0:37:26.36,0:37:28.54,Default,,0,0,0,,因为表自动成为了流 Dialogue: 0,0:37:29.55,0:37:30.70,Default,,0,0,0,,表和流有一样的行为 Dialogue: 0,0:37:30.75,0:37:32.35,Default,,0,0,0,,所有的数据结构也会像那样 Dialogue: 0,0:37:32.35,0:37:33.64,Default,,0,0,0,,所有的都是 Dialogue: 0,0:37:35.07,0:37:37.63,Default,,0,0,0,,直到需要答案的时候 Dialogue: 0,0:37:37.66,0:37:39.42,Default,,0,0,0,,才会去实际的求值 Dialogue: 0,0:37:40.80,0:37:43.58,Default,,0,0,0,,不必再担心 什么时候需要显式地标注DELAY Dialogue: 0,0:37:44.79,0:37:46.16,Default,,0,0,0,,为什么不这样做呢? Dialogue: 0,0:37:47.16,0:37:48.81,Default,,0,0,0,,首先 已经有人这样做过了 Dialogue: 0,0:37:49.23,0:37:51.85,Default,,0,0,0,,有一些十分优雅的语言 Dialogue: 0,0:37:51.85,0:37:55.21,Default,,0,0,0,,其中最为人称道的是一门名为 Miranda 的语言 Dialogue: 0,0:37:55.77,0:37:56.76,Default,,0,0,0,,它是由 Dialogue: 0,0:37:57.44,0:37:59.80,Default,,0,0,0,,肯特大学的 David Turner 开发的 Dialogue: 0,0:38:00.71,0:38:01.93,Default,,0,0,0,,它就是用这样的原理实现的 Dialogue: 0,0:38:01.93,0:38:03.34,Default,,0,0,0,,Miranda是正则序求值语言 Dialogue: 0,0:38:04.27,0:38:05.55,Default,,0,0,0,,它的数据结构 Dialogue: 0,0:38:06.16,0:38:08.41,Default,,0,0,0,,看起来像表 实际上确实流 Dialogue: 0,0:38:08.96,0:38:10.91,Default,,0,0,0,,你不需要任何特殊的功能 Dialogue: 0,0:38:11.28,0:38:13.28,Default,,0,0,0,,就可以在Miranda中编写普通的过程 Dialogue: 0,0:38:13.32,0:38:14.97,Default,,0,0,0,,来解决质数、八皇后这样的问题 Dialogue: 0,0:38:14.97,0:38:16.35,Default,,0,0,0,,这些都是语言的内建功能 Dialogue: 0,0:38:17.93,0:38:18.91,Default,,0,0,0,,但这样做也要付出代价 Dialogue: 0,0:38:21.19,0:38:22.36,Default,,0,0,0,,还记得我们为什么引入流了吗? Dialogue: 0,0:38:23.17,0:38:27.48,Default,,0,0,0,,我们分离了程序的时间和它实际执行的时间 Dialogue: 0,0:38:27.96,0:38:28.88,Default,,0,0,0,,如果我们引入了DELAY Dialogue: 0,0:38:29.04,0:38:30.33,Default,,0,0,0,,这样就在所有的地方完成了解耦 Dialogue: 0,0:38:30.40,0:38:31.42,Default,,0,0,0,,而不单单是在流中 Dialogue: 0,0:38:32.19,0:38:33.14,Default,,0,0,0,,我们的初衷是什么? Dialogue: 0,0:38:33.14,0:38:38.11,Default,,0,0,0,,我们把程序设计看做是指定计算过程 Dialogue: 0,0:38:39.30,0:38:40.62,Default,,0,0,0,,如果我们放弃了对时间的控制 Dialogue: 0,0:38:40.65,0:38:42.41,Default,,0,0,0,,尽管语言变得优雅起来 Dialogue: 0,0:38:43.74,0:38:45.87,Default,,0,0,0,,但是它的表达力却有所下降 Dialogue: 0,0:38:47.03,0:38:49.84,Default,,0,0,0,,这里面还有一些我们无法消除的区别 Dialogue: 0,0:38:51.48,0:38:53.15,Default,,0,0,0,,其中之一就是迭代 Dialogue: 0,0:38:53.98,0:38:56.44,Default,,0,0,0,,还记得这个程序吗? Dialogue: 0,0:38:56.96,0:38:58.28,Default,,0,0,0,,迭代式的阶乘 Dialogue: 0,0:38:58.44,0:39:00.48,Default,,0,0,0,,这是我们很早之前就研究过的 Dialogue: 0,0:39:01.23,0:39:02.97,Default,,0,0,0,,过程FACT-ITER Dialogue: 0,0:39:03.04,0:39:04.91,Default,,0,0,0,,有一个内部过程ITER Dialogue: 0,0:39:05.18,0:39:07.50,Default,,0,0,0,,它含有两个状态PRODUCT和COUNTER Dialogue: 0,0:39:08.70,0:39:10.96,Default,,0,0,0,,它们随着循环不断迭代 Dialogue: 0,0:39:12.12,0:39:13.68,Default,,0,0,0,,之所以说这个过程是迭代的 Dialogue: 0,0:39:13.71,0:39:14.83,Default,,0,0,0,,是因为它没有创建新状态 Dialogue: 0,0:39:15.73,0:39:17.45,Default,,0,0,0,,之所以没有创建新状态 Dialogue: 0,0:39:17.47,0:39:20.25,Default,,0,0,0,,是因为在调用ITER时 Dialogue: 0,0:39:20.30,0:39:22.86,Default,,0,0,0,,作为参数传递给它自己的始终是这些东西 Dialogue: 0,0:39:23.90,0:39:25.39,Default,,0,0,0,,在代换模型中 Dialogue: 0,0:39:25.55,0:39:27.79,Default,,0,0,0,,Gerald教授给你们讲解过 Dialogue: 0,0:39:28.72,0:39:30.01,Default,,0,0,0,,在迭代过程中 Dialogue: 0,0:39:30.03,0:39:31.44,Default,,0,0,0,,状态并不需要增长 Dialogue: 0,0:39:31.82,0:39:34.22,Default,,0,0,0,,因此这是一个迭代过程 Dialogue: 0,0:39:34.99,0:39:37.47,Default,,0,0,0,,但是如果用正则序语言 Dialogue: 0,0:39:37.47,0:39:39.10,Default,,0,0,0,,来运行这段程序 Dialogue: 0,0:39:41.15,0:39:42.17,Default,,0,0,0,,这就会导致 Dialogue: 0,0:39:42.88,0:39:44.96,Default,,0,0,0,,这个过程不再是迭代式了 Dialogue: 0,0:39:45.65,0:39:48.67,Default,,0,0,0,,如果你仔细地思考代换模型 Dialogue: 0,0:39:48.67,0:39:49.90,Default,,0,0,0,,在这里我就不细说了 Dialogue: 0,0:39:51.20,0:39:52.35,Default,,0,0,0,,这个表达式会不断增长 Dialogue: 0,0:39:52.36,0:39:53.18,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:39:53.28,0:39:55.20,Default,,0,0,0,,因为当ITER调用自己时 Dialogue: 0,0:39:55.85,0:39:57.31,Default,,0,0,0,,参数是这个乘法表达式 Dialogue: 0,0:39:58.08,0:39:59.36,Default,,0,0,0,,而在正则序语言中 Dialogue: 0,0:39:59.39,0:40:01.16,Default,,0,0,0,,这个乘法并不会在这里求值 Dialogue: 0,0:40:02.51,0:40:03.82,Default,,0,0,0,,传递给自己并代换的 Dialogue: 0,0:40:03.93,0:40:05.68,Default,,0,0,0,,只是这个乘法计算的PROMISE Dialogue: 0,0:40:06.67,0:40:08.03,Default,,0,0,0,,然后继续代换下去 Dialogue: 0,0:40:09.76,0:40:11.55,Default,,0,0,0,,我调用自己 Dialogue: 0,0:40:11.84,0:40:14.04,Default,,0,0,0,,用的是计算这个乘法的PROMISE Dialogue: 0,0:40:14.04,0:40:17.82,Default,,0,0,0,,但其中的一个因数也是个PROMISE Dialogue: 0,0:40:18.40,0:40:19.43,Default,,0,0,0,,然后我又自调用 Dialogue: 0,0:40:19.43,0:40:21.13,Default,,0,0,0,,如果你用代换模型 Dialogue: 0,0:40:21.98,0:40:23.60,Default,,0,0,0,,来推演这个迭代步骤 Dialogue: 0,0:40:23.77,0:40:26.83,Default,,0,0,0,,你会发现同样的状态增长 Dialogue: 0,0:40:27.16,0:40:28.96,Default,,0,0,0,,所有的PROMISE都需要被记住 Dialogue: 0,0:40:28.97,0:40:30.76,Default,,0,0,0,,以便在最后被调用 Dialogue: 0,0:40:31.79,0:40:35.02,Default,,0,0,0,,所以 正则序的缺点之一 Dialogue: 0,0:40:35.05,0:40:36.86,Default,,0,0,0,,就是无法有效地表达迭代 Dialogue: 0,0:40:36.98,0:40:39.60,Default,,0,0,0,,也许这个理由有点偏理论 Dialogue: 0,0:40:39.61,0:40:43.90,Default,,0,0,0,,但事实上 那些使用这类语言来编写 Dialogue: 0,0:40:44.27,0:40:47.56,Default,,0,0,0,,实际操作系统的人 也都遇到了这类问题 Dialogue: 0,0:40:48.20,0:40:50.75,Default,,0,0,0,,当然 完全可以 Dialogue: 0,0:40:51.64,0:40:54.38,Default,,0,0,0,,用这类语言实现一个文本编辑器 Dialogue: 0,0:40:54.61,0:40:56.08,Default,,0,0,0,,但是你才用了一会儿 Dialogue: 0,0:40:56.72,0:40:59.39,Default,,0,0,0,,就发现已经占用了3MB空间 Dialogue: 0,0:40:59.44,0:41:02.04,Default,,0,0,0,,我想 那些遇到这类问题的人 Dialogue: 0,0:41:02.16,0:41:05.60,Default,,0,0,0,,把它叫做 “拖尾问题” Dialogue: 0,0:41:05.82,0:41:08.20,Default,,0,0,0,,由于不能有效地表达迭代计算 Dialogue: 0,0:41:08.24,0:41:10.46,Default,,0,0,0,,导致堆积了一堆没有被调用的PROMISE Dialogue: 0,0:41:10.72,0:41:14.81,Default,,0,0,0,,针对这类语言的一个研究方向就是 Dialogue: 0,0:41:14.83,0:41:17.48,Default,,0,0,0,,找出一种有效的编译器技术 Dialogue: 0,0:41:17.82,0:41:19.85,Default,,0,0,0,,来避免这种所谓的“拖尾问题” Dialogue: 0,0:41:20.17,0:41:21.61,Default,,0,0,0,,这并不简单 Dialogue: 0,0:41:23.94,0:41:27.31,Default,,0,0,0,,但是 还有一个很突出的问题 Dialogue: 0,0:41:27.96,0:41:31.04,Default,,0,0,0,,使你的语言不能变成正则序 Dialogue: 0,0:41:32.51,0:41:33.29,Default,,0,0,0,,问题就在于 Dialogue: 0,0:41:35.05,0:41:38.09,Default,,0,0,0,,正则序和副作用 Dialogue: 0,0:41:38.89,0:41:40.19,Default,,0,0,0,,是不相容的 Dialogue: 0,0:41:42.00,0:41:43.96,Default,,0,0,0,,它们不能很好地相互配合 Dialogue: 0,0:41:45.44,0:41:46.65,Default,,0,0,0,,这是因为 你不能 Dialogue: 0,0:41:48.28,0:41:50.80,Default,,0,0,0,,你不能一边 Dialogue: 0,0:41:51.00,0:41:54.33,Default,,0,0,0,,建模具有局部状态的对象 Dialogue: 0,0:41:55.72,0:41:56.96,Default,,0,0,0,,同时又 Dialogue: 0,0:41:57.18,0:41:59.55,Default,,0,0,0,,使用正则序的技巧来解耦时间 Dialogue: 0,0:42:00.40,0:42:03.55,Default,,0,0,0,,我来举一个非常简单的例子 Dialogue: 0,0:42:03.79,0:42:05.50,Default,,0,0,0,,假设语言是正则序求值 Dialogue: 0,0:42:07.52,0:42:09.55,Default,,0,0,0,,例子是这样的 Dialogue: 0,0:42:09.55,0:42:10.52,Default,,0,0,0,,注意现在是正则序求值 Dialogue: 0,0:42:10.52,0:42:12.22,Default,,0,0,0,,(DEFINE X 0) Dialogue: 0,0:42:13.57,0:42:15.56,Default,,0,0,0,,这只是变量的初始化 Dialogue: 0,0:42:15.75,0:42:17.69,Default,,0,0,0,,现在我要定义一个有趣的函数 Dialogue: 0,0:42:18.57,0:42:20.44,Default,,0,0,0,,它就是恒等函数ID Dialogue: 0,0:42:22.64,0:42:23.90,Default,,0,0,0,,它所做的就是 Dialogue: 0,0:42:24.11,0:42:26.60,Default,,0,0,0,,用X来记录上一次调用它时N的值 Dialogue: 0,0:42:31.40,0:42:34.16,Default,,0,0,0,,因此(ID N)就返回N Dialogue: 0,0:42:34.17,0:42:35.39,Default,,0,0,0,,但还要把X赋值为N Dialogue: 0,0:42:36.76,0:42:38.54,Default,,0,0,0,,最后再定义一个过程INC Dialogue: 0,0:42:39.55,0:42:42.30,Default,,0,0,0,,也非常简单 Dialogue: 0,0:42:42.58,0:42:45.34,Default,,0,0,0,,假设在正则序求值的语言里 Dialogue: 0,0:42:46.27,0:42:47.23,Default,,0,0,0,,求值下面的表达式 Dialogue: 0,0:42:47.23,0:42:52.83,Default,,0,0,0,,我输入 (DEFINE Y (INC (ID 3))) Dialogue: 0,0:42:52.83,0:42:53.96,Default,,0,0,0,,因此Y的值应该是4 Dialogue: 0,0:42:57.41,0:42:58.35,Default,,0,0,0,,X应该是多少呢? Dialogue: 0,0:42:59.52,0:43:02.16,Default,,0,0,0,,X应该是最后一次被记住的值 Dialogue: 0,0:43:02.64,0:43:04.01,Default,,0,0,0,,也就是我调用函数ID的时候 Dialogue: 0,0:43:04.71,0:43:06.73,Default,,0,0,0,,你可能会想 这里X应该是3 Dialogue: 0,0:43:06.91,0:43:07.52,Default,,0,0,0,,但是并不是这样 Dialogue: 0,0:43:08.53,0:43:11.15,Default,,0,0,0,,这是因为当我在这里定义Y的时候 Dialogue: 0,0:43:11.79,0:43:13.45,Default,,0,0,0,,Y的真正定义却是 Dialogue: 0,0:43:13.47,0:43:15.71,Default,,0,0,0,,一个调用函数ID的PROMISE的增量 Dialogue: 0,0:43:17.00,0:43:18.17,Default,,0,0,0,,因为我没有访问Y Dialogue: 0,0:43:18.36,0:43:20.25,Default,,0,0,0,,所以ID没有运行 Dialogue: 0,0:43:21.56,0:43:23.20,Default,,0,0,0,,我输入这个定义之后 Dialogue: 0,0:43:23.31,0:43:24.80,Default,,0,0,0,,然后查询X得到的结果是0 Dialogue: 0,0:43:28.36,0:43:31.20,Default,,0,0,0,,现在 我输入Y查询它的值 Dialogue: 0,0:43:31.52,0:43:32.43,Default,,0,0,0,,就会得到结果4 Dialogue: 0,0:43:32.67,0:43:35.16,Default,,0,0,0,,对Y的主动查询 Dialogue: 0,0:43:35.29,0:43:37.42,Default,,0,0,0,,会导致ID运行 Dialogue: 0,0:43:38.72,0:43:40.48,Default,,0,0,0,,现在X=3就被记住 Dialogue: 0,0:43:40.74,0:43:41.87,Default,,0,0,0,,所以上面这里的X就应该是0 Dialogue: 0,0:43:41.93,0:43:42.96,Default,,0,0,0,,下面这里是3 Dialogue: 0,0:43:43.28,0:43:46.16,Default,,0,0,0,,这是一个非常简单的场景 Dialogue: 0,0:43:46.30,0:43:49.28,Default,,0,0,0,,但你会发现 调试正则序语言 Dialogue: 0,0:43:50.36,0:43:53.34,Default,,0,0,0,,的交互式程序 Dialogue: 0,0:43:54.12,0:43:55.88,Default,,0,0,0,,会变得相当混乱 Dialogue: 0,0:43:57.10,0:43:58.12,Default,,0,0,0,,很令人迷惑 Dialogue: 0,0:43:59.69,0:44:02.04,Default,,0,0,0,,导致这样的深层次的原因 Dialogue: 0,0:44:02.80,0:44:06.41,Default,,0,0,0,,也就是引入DELAY的根本理念 Dialogue: 0,0:44:06.92,0:44:08.43,Default,,0,0,0,,是因为我们抛弃了时间的概念 Dialogue: 0,0:44:09.78,0:44:11.75,Default,,0,0,0,,也因为如此我们可以处理一些无穷的情况 Dialogue: 0,0:44:11.75,0:44:12.97,Default,,0,0,0,,我们抛弃了时间 Dialogue: 0,0:44:12.99,0:44:14.27,Default,,0,0,0,,就没有必要等它们运行 Dialogue: 0,0:44:17.55,0:44:20.44,Default,,0,0,0,,我们把计算机中事件发生的顺序 Dialogue: 0,0:44:20.83,0:44:22.11,Default,,0,0,0,,与程序中的顺序 分离开来 Dialogue: 0,0:44:22.35,0:44:25.28,Default,,0,0,0,,但是当我们谈及状态、赋值和改变的时候 Dialogue: 0,0:44:25.48,0:44:27.42,Default,,0,0,0,,这些又都是我们想要控制的 Dialogue: 0,0:44:28.76,0:44:33.82,Default,,0,0,0,,我们的目的有着根本性的矛盾 Dialogue: 0,0:44:34.57,0:44:39.12,Default,,0,0,0,,这又让我们进入了一个哲学问题 Dialogue: 0,0:44:39.13,0:44:40.75,Default,,0,0,0,,用什么样的模型 Dialogue: 0,0:44:40.78,0:44:41.77,Default,,0,0,0,,和从什么角度来看这个世界 Dialogue: 0,0:44:42.41,0:44:44.30,Default,,0,0,0,,有时这也被称为 Dialogue: 0,0:44:44.76,0:44:46.60,Default,,0,0,0,,“函数式程序设计的争论” Dialogue: 0,0:44:54.19,0:44:56.60,Default,,0,0,0,,所谓的“纯函数式语言” Dialogue: 0,0:44:57.07,0:44:59.20,Default,,0,0,0,,是完全没有副作用的 Dialogue: 0,0:45:00.44,0:45:01.63,Default,,0,0,0,,不需要副作用 Dialogue: 0,0:45:01.64,0:45:03.02,Default,,0,0,0,,也就不需要赋值运算符 Dialogue: 0,0:45:03.34,0:45:05.72,Default,,0,0,0,,也就没有什么糟糕的后果 Dialogue: 0,0:45:06.36,0:45:07.93,Default,,0,0,0,,可以使用类似代换模型 Dialogue: 0,0:45:07.93,0:45:10.48,Default,,0,0,0,,程序更像是数学 Dialogue: 0,0:45:10.76,0:45:13.82,Default,,0,0,0,,而不像现实世界中的模型和对象 Dialogue: 0,0:45:15.05,0:45:17.17,Default,,0,0,0,,函数式语言有很多了不起的特性 Dialogue: 0,0:45:17.17,0:45:19.63,Default,,0,0,0,,没有时间的概念 所以完全不用担心同步的问题 Dialogue: 0,0:45:20.64,0:45:23.72,Default,,0,0,0,,如果你想在并行算法中应用一些东西 Dialogue: 0,0:45:24.72,0:45:28.20,Default,,0,0,0,,你可以在这些并行过程中随心所欲地使用 Dialogue: 0,0:45:29.40,0:45:31.44,Default,,0,0,0,,从来不担心同步问题 Dialogue: 0,0:45:31.50,0:45:33.34,Default,,0,0,0,,在这种环境下这样做是非常方便的 Dialogue: 0,0:45:33.64,0:45:35.71,Default,,0,0,0,,代价则是 放弃了赋值 Dialogue: 0,0:45:39.10,0:45:41.32,Default,,0,0,0,,函数式语言的支持者会认为 Dialogue: 0,0:45:41.34,0:45:43.04,Default,,0,0,0,,这点代价算不了什么 Dialogue: 0,0:45:44.52,0:45:46.51,Default,,0,0,0,,在大部分情况下 你都不应该使用赋值 Dialogue: 0,0:45:46.88,0:45:48.27,Default,,0,0,0,,如果用你放弃了赋值 Dialogue: 0,0:45:48.43,0:45:51.40,Default,,0,0,0,,你可以得到一个比对象世界 Dialogue: 0,0:45:51.96,0:45:53.24,Default,,0,0,0,,好得多的世界 Dialogue: 0,0:45:54.19,0:45:56.30,Default,,0,0,0,,怎么来反驳这个观点呢? Dialogue: 0,0:45:56.30,0:45:58.59,Default,,0,0,0,,想想 我们如何走到这一步的 Dialogue: 0,0:46:00.06,0:46:03.79,Default,,0,0,0,,我们尝试建模具有局部状态的对象 Dialogue: 0,0:46:04.44,0:46:06.49,Default,,0,0,0,,想一想Gerald教授给你们讲的随机数生成器 Dialogue: 0,0:46:07.16,0:46:08.67,Default,,0,0,0,,这里有一个随机数生成器 Dialogue: 0,0:46:09.28,0:46:10.62,Default,,0,0,0,,它内部有一些状态 Dialogue: 0,0:46:10.83,0:46:12.08,Default,,0,0,0,,用来计算下一个随机数 Dialogue: 0,0:46:12.12,0:46:14.08,Default,,0,0,0,,下下一个 以及再下一个 Dialogue: 0,0:46:14.28,0:46:16.14,Default,,0,0,0,,我们想要把这些状态跟 Dialogue: 0,0:46:16.43,0:46:18.96,Default,,0,0,0,,计算π的Cesaro算法分离开来 Dialogue: 0,0:46:19.84,0:46:20.92,Default,,0,0,0,,这就是我们为什么需要赋值 Dialogue: 0,0:46:20.97,0:46:22.91,Default,,0,0,0,,我们想要把状态封装在模块中 Dialogue: 0,0:46:24.07,0:46:26.36,Default,,0,0,0,,函数式语言程序员可能会说 Dialogue: 0,0:46:26.38,0:46:27.56,Default,,0,0,0,,“你搞错了” Dialogue: 0,0:46:27.56,0:46:29.84,Default,,0,0,0,,“我的意思是 你能写出另一种更具模块化的程序” Dialogue: 0,0:46:29.84,0:46:32.46,Default,,0,0,0,,“你对模块化的认识并不正确” Dialogue: 0,0:46:33.08,0:46:35.02,Default,,0,0,0,,你太执着于 “生成一个随机数 Dialogue: 0,0:46:35.07,0:46:36.88,Default,,0,0,0,,再生成一个 再生成一个” 这种范式了 Dialogue: 0,0:46:36.88,0:46:39.42,Default,,0,0,0,,为什么不写一个这样的程序 Dialogue: 0,0:46:40.09,0:46:41.29,Default,,0,0,0,,构造一个枚举器 Dialogue: 0,0:46:41.95,0:46:44.48,Default,,0,0,0,,它会生成一个随机数的无穷流 Dialogue: 0,0:46:49.01,0:46:50.91,Default,,0,0,0,,我们可以立即生成这个流 Dialogue: 0,0:46:52.64,0:46:54.54,Default,,0,0,0,,这样就可以用作随机数的源泉 Dialogue: 0,0:46:54.54,0:46:55.24,Default,,0,0,0,,如果有需要的话 Dialogue: 0,0:46:55.53,0:46:57.47,Default,,0,0,0,,你可以把它跟某个处理过程相连 Dialogue: 0,0:46:57.77,0:47:01.16,Default,,0,0,0,,比如说Cesaro测试 Dialogue: 0,0:47:04.94,0:47:06.22,Default,,0,0,0,,然后这个处理过程进行自己的计算 Dialogue: 0,0:47:06.88,0:47:08.56,Default,,0,0,0,,从这里出来的则是 Dialogue: 0,0:47:08.72,0:47:27.45,Default,,0,0,0,,其中是一串的对π的估计值组成的流 Dialogue: 0,0:47:28.14,0:47:30.65,Default,,0,0,0,,随着我们深入访问这个流 Dialogue: 0,0:47:30.76,0:47:32.38,Default,,0,0,0,,相当于去拽这个Cesaro盒子 Dialogue: 0,0:47:33.12,0:47:35.36,Default,,0,0,0,,它就会拉取出许多随机数 Dialogue: 0,0:47:35.54,0:47:37.21,Default,,0,0,0,,随着我们对流的深入访问 Dialogue: 0,0:47:37.23,0:47:38.96,Default,,0,0,0,,得到的对π的估计值就越准 Dialogue: 0,0:47:39.72,0:47:41.66,Default,,0,0,0,,具体的计算过程还是一样的 Dialogue: 0,0:47:41.66,0:47:43.79,Default,,0,0,0,,只不过使用了另一种模块化的方式 Dialogue: 0,0:47:43.89,0:47:45.55,Default,,0,0,0,,我们可以想象成一下子 Dialogue: 0,0:47:45.56,0:47:47.47,Default,,0,0,0,,就有了这所有的随机数 Dialogue: 0,0:47:49.28,0:47:52.24,Default,,0,0,0,,这个过程的细节在书上有 Dialogue: 0,0:47:53.61,0:47:57.85,Default,,0,0,0,,我们同样也陷于另外一些类似的事情中 Dialogue: 0,0:47:58.27,0:48:01.20,Default,,0,0,0,,这种关于 这个、下一个以及再下一个的范式 Dialogue: 0,0:48:01.37,0:48:02.81,Default,,0,0,0,,完全可以不这么来做 Dialogue: 0,0:48:03.28,0:48:06.54,Default,,0,0,0,,我们来思考一下银行系统 Dialogue: 0,0:48:07.68,0:48:08.90,Default,,0,0,0,,有个非常简单的场景 Dialogue: 0,0:48:08.90,0:48:12.21,Default,,0,0,0,,我们假设这个程序代表了银行帐户 Dialogue: 0,0:48:18.81,0:48:20.84,Default,,0,0,0,,银行账户中可能有 Dialogue: 0,0:48:22.78,0:48:26.22,Default,,0,0,0,,如果我们以消息传递的角度来看 Dialogue: 0,0:48:26.44,0:48:28.12,Default,,0,0,0,,我们认为银行账户是一个对象 Dialogue: 0,0:48:28.59,0:48:31.51,Default,,0,0,0,,内部保存着标识余额的局部状态BALANCE Dialogue: 0,0:48:34.11,0:48:36.00,Default,,0,0,0,,如果一个用户使用这个系统 Dialogue: 0,0:48:36.44,0:48:38.14,Default,,0,0,0,,发出交易请求 Dialogue: 0,0:48:39.31,0:48:41.05,Default,,0,0,0,,用户发出的交易请求可能是 Dialogue: 0,0:48:41.07,0:48:42.20,Default,,0,0,0,,存一些钱 Dialogue: 0,0:48:42.28,0:48:43.53,Default,,0,0,0,,银行账户就会 Dialogue: 0,0:48:43.92,0:48:46.78,Default,,0,0,0,,我们假设银行账户总是以当前余额作为回应 Dialogue: 0,0:48:48.22,0:48:50.04,Default,,0,0,0,,用户存了一些钱 Dialogue: 0,0:48:50.06,0:48:53.21,Default,,0,0,0,,银行账户就会返回一个消息指明当前余额 Dialogue: 0,0:48:54.35,0:48:57.42,Default,,0,0,0,,用户再存一些钱 Dialogue: 0,0:48:57.45,0:48:58.81,Default,,0,0,0,,银行就再返回消息 Dialogue: 0,0:48:59.15,0:49:00.75,Default,,0,0,0,,就像生成随机数一样 Dialogue: 0,0:49:00.78,0:49:02.12,Default,,0,0,0,,我们想使用赋值来实现 Dialogue: 0,0:49:03.20,0:49:06.88,Default,,0,0,0,,帐户的内部保存了局部状态BALANCE Dialogue: 0,0:49:06.88,0:49:08.40,Default,,0,0,0,,因为我们想要把用户状态 Dialogue: 0,0:49:08.41,0:49:09.57,Default,,0,0,0,,和银行账户的状态分离开来 Dialogue: 0,0:49:13.28,0:49:16.42,Default,,0,0,0,,这是从消息传递的角度来看 Dialogue: 0,0:49:16.42,0:49:18.20,Default,,0,0,0,,如果从流的角度来看 Dialogue: 0,0:49:19.48,0:49:22.19,Default,,0,0,0,,不需要赋值或副作用就可以达到同样的效果 Dialogue: 0,0:49:22.74,0:49:26.73,Default,,0,0,0,,再次强调 想法是这样的 Dialogue: 0,0:49:27.37,0:49:30.25,Default,,0,0,0,,我们认为它们都没有局部状态 Dialogue: 0,0:49:31.18,0:49:33.08,Default,,0,0,0,,我们把银行账户看作是 Dialogue: 0,0:49:33.40,0:49:37.71,Default,,0,0,0,,能够处理一系列交易请求的东西 Dialogue: 0,0:49:38.64,0:49:40.16,Default,,0,0,0,,不把银行账户看做 Dialogue: 0,0:49:40.22,0:49:42.00,Default,,0,0,0,,逐个消息地处理 Dialogue: 0,0:49:42.44,0:49:45.85,Default,,0,0,0,,而是处理某种交易请求流的东西 Dialogue: 0,0:49:45.87,0:49:48.49,Default,,0,0,0,,这个请求流可能是一些列的存款声明 Dialogue: 0,0:49:49.49,0:49:54.94,Default,,0,0,0,,比如 1 2 2 4 这样的连续存钱请求 Dialogue: 0,0:49:55.94,0:50:02.44,Default,,0,0,0,,从帐户出来的流应该是 1 3 5 9 Dialogue: 0,0:50:03.77,0:50:06.14,Default,,0,0,0,,我们不把银行账户看做某种具有状态的东西 Dialogue: 0,0:50:06.40,0:50:07.26,Default,,0,0,0,,而是某种能够处理 Dialogue: 0,0:50:08.92,0:50:10.82,Default,,0,0,0,,有关请求的无穷流的东西 Dialogue: 0,0:50:10.82,0:50:12.30,Default,,0,0,0,,但要注意 我们抛弃了时间 Dialogue: 0,0:50:12.37,0:50:14.27,Default,,0,0,0,,如果这里有一个用户 Dialogue: 0,0:50:16.12,0:50:19.13,Default,,0,0,0,,这个无穷请求流的元素 Dialogue: 0,0:50:19.18,0:50:22.54,Default,,0,0,0,,我们可以一次生成一个 Dialogue: 0,0:50:24.06,0:50:26.57,Default,,0,0,0,,而这个交易流 Dialogue: 0,0:50:26.57,0:50:28.80,Default,,0,0,0,,则会逐个打印在屏幕上 Dialogue: 0,0:50:30.01,0:50:31.37,Default,,0,0,0,,如果在这里画一条线 Dialogue: 0,0:50:32.56,0:50:33.08,Default,,0,0,0,,就在这里 Dialogue: 0,0:50:33.28,0:50:34.91,Default,,0,0,0,,对用户来说 他根本无法分辨 Dialogue: 0,0:50:36.19,0:50:37.71,Default,,0,0,0,,这个系统是否有内部状态 Dialogue: 0,0:50:39.56,0:50:41.13,Default,,0,0,0,,这个跟消息传递那种是一样的 Dialogue: 0,0:50:41.29,0:50:42.46,Default,,0,0,0,,只不过这个没有状态 Dialogue: 0,0:50:42.84,0:50:45.87,Default,,0,0,0,,哦 顺便提一下 Dialogue: 0,0:50:46.72,0:50:49.47,Default,,0,0,0,,这是具体的代码实现 Dialogue: 0,0:50:50.52,0:50:52.30,Default,,0,0,0,,我们把它叫做MAKE-DEPOSIT-ACCOUNT Dialogue: 0,0:50:52.32,0:50:53.32,Default,,0,0,0,,因为它只能够存钱 Dialogue: 0,0:50:54.17,0:50:55.77,Default,,0,0,0,,这个过程接受一个初始余额 Dialogue: 0,0:50:56.09,0:50:58.09,Default,,0,0,0,,以及一个可能发起的存款流 Dialogue: 0,0:51:00.02,0:51:00.82,Default,,0,0,0,,具体怎么做呢? Dialogue: 0,0:51:00.82,0:51:02.54,Default,,0,0,0,,它只是用CONS-STREAM把余额BALANCE Dialogue: 0,0:51:03.23,0:51:05.31,Default,,0,0,0,,和一个新的存款账户流组合在一起 Dialogue: 0,0:51:06.24,0:51:07.32,Default,,0,0,0,,新存款流的初始余额 Dialogue: 0,0:51:07.48,0:51:10.27,Default,,0,0,0,,就是之前BALANCE的值加上存款流的第一个元素 Dialogue: 0,0:51:10.86,0:51:13.40,Default,,0,0,0,,而其余部分则是 Dialogue: 0,0:51:13.76,0:51:17.37,Default,,0,0,0,,存款流的尾部分 Dialogue: 0,0:51:18.30,0:51:23.84,Default,,0,0,0,,因此这种非常典型的消息传递式、面向对象的问题 Dialogue: 0,0:51:23.95,0:51:27.55,Default,,0,0,0,,完全可以不用副作用来解决 Dialogue: 0,0:51:29.05,0:51:30.76,Default,,0,0,0,,很多地方都可以这样做 Dialogue: 0,0:51:32.25,0:51:35.23,Default,,0,0,0,,那么 我们可以完全不用赋值么? Dialogue: 0,0:51:36.40,0:51:39.00,Default,,0,0,0,,可以只用纯函数式语言吗? Dialogue: 0,0:51:40.05,0:51:42.04,Default,,0,0,0,,这个问题谁也说不清 Dialogue: 0,0:51:42.27,0:51:43.44,Default,,0,0,0,,好像有些地方 Dialogue: 0,0:51:43.92,0:51:46.03,Default,,0,0,0,,纯函数式语言无法派上用场 Dialogue: 0,0:51:48.10,0:51:50.27,Default,,0,0,0,,当遇到像这样的系统时 问题就变得棘手起来 Dialogue: 0,0:51:50.43,0:51:52.32,Default,,0,0,0,,特别是当你 Dialogue: 0,0:51:52.60,0:51:54.27,Default,,0,0,0,,还需要考虑其它因素的时候 Dialogue: 0,0:51:54.30,0:51:55.64,Default,,0,0,0,,有关对象和共享 Dialogue: 0,0:51:55.90,0:51:58.52,Default,,0,0,0,,以及两个独立的主体共享同一个东西 Dialogue: 0,0:51:58.85,0:51:59.93,Default,,0,0,0,,举一个典型的例子 Dialogue: 0,0:51:59.96,0:52:01.63,Default,,0,0,0,,假如你来扩展这个帐户 Dialogue: 0,0:52:03.24,0:52:04.27,Default,,0,0,0,,这是一个帐户 Dialogue: 0,0:52:12.22,0:52:14.75,Default,,0,0,0,,帐户接受一个交易请求流 Dialogue: 0,0:52:15.20,0:52:18.44,Default,,0,0,0,,输出的流则是关于余额的回复 Dialogue: 0,0:52:18.78,0:52:20.16,Default,,0,0,0,,假设你所建模的是联合账户 Dialogue: 0,0:52:20.17,0:52:24.36,Default,,0,0,0,,而由两个独立用户共享 Dialogue: 0,0:52:25.68,0:52:28.65,Default,,0,0,0,,我们假设 假设有两个人 Dialogue: 0,0:52:28.97,0:52:30.96,Default,,0,0,0,,比如说Bill和Dave Dialogue: 0,0:52:31.77,0:52:33.14,Default,,0,0,0,,他们俩共享一个帐户 Dialogue: 0,0:52:35.96,0:52:36.85,Default,,0,0,0,,怎么来建模呢? Dialogue: 0,0:52:36.88,0:52:39.80,Default,,0,0,0,,你或许会让Bill输出一个交易请求流 Dialogue: 0,0:52:40.24,0:52:42.25,Default,,0,0,0,,Dave也产生一个这样的流 Dialogue: 0,0:52:42.25,0:52:45.16,Default,,0,0,0,,这两个流需要以某种方式合并到银行账户中 Dialogue: 0,0:52:45.88,0:52:47.85,Default,,0,0,0,,因此你需要编写一个MERGE过程 Dialogue: 0,0:52:47.90,0:52:50.65,Default,,0,0,0,,来处理这些流 Dialogue: 0,0:52:57.23,0:52:59.13,Default,,0,0,0,,它把这些流合并在一起 Dialogue: 0,0:52:59.34,0:53:01.19,Default,,0,0,0,,形成单个流 送入银行账户 Dialogue: 0,0:53:01.19,0:53:02.99,Default,,0,0,0,,现在他们就共享一个帐户了 Dialogue: 0,0:53:03.61,0:53:05.48,Default,,0,0,0,,看起来不错 问题是怎么来实现MERGE Dialogue: 0,0:53:05.93,0:53:08.24,Default,,0,0,0,,MERGE怎么来合并? Dialogue: 0,0:53:09.73,0:53:11.42,Default,,0,0,0,,需要合理的合并依据 Dialogue: 0,0:53:12.38,0:53:13.80,Default,,0,0,0,,你可能首先会想 Dialogue: 0,0:53:13.80,0:53:16.68,Default,,0,0,0,,我们从Bill和Dave中选一个请求来处理 Dialogue: 0,0:53:18.19,0:53:20.97,Default,,0,0,0,,但是如果在这中途 Dialogue: 0,0:53:21.18,0:53:23.08,Default,,0,0,0,,Dave突然外出度假两年 会怎么样? Dialogue: 0,0:53:24.15,0:53:25.40,Default,,0,0,0,,Bill的交易就完全被阻塞了 Dialogue: 0,0:53:27.69,0:53:29.75,Default,,0,0,0,,你想要的是 Dialogue: 0,0:53:29.75,0:53:33.64,Default,,0,0,0,,是一种公平的合并 Dialogue: 0,0:53:38.41,0:53:40.17,Default,,0,0,0,,这个所谓公平的合并 Dialogue: 0,0:53:40.73,0:53:42.46,Default,,0,0,0,,应该是交替地一次处理一个 Dialogue: 0,0:53:42.49,0:53:43.92,Default,,0,0,0,,但是如果一个人没有了交易 Dialogue: 0,0:53:43.96,0:53:44.91,Default,,0,0,0,,应该继续去处理另一个人的交易 Dialogue: 0,0:53:46.01,0:53:48.45,Default,,0,0,0,,但是没有时间 我就不能这样做 Dialogue: 0,0:53:51.30,0:53:56.41,Default,,0,0,0,,函数式语言的另一个活跃研究领域就是 Dialogue: 0,0:53:56.43,0:53:59.48,Default,,0,0,0,,发明类似于“公平合并”的算法 Dialogue: 0,0:54:00.35,0:54:01.31,Default,,0,0,0,,又或者是其它的东西 Dialogue: 0,0:54:01.56,0:54:06.25,Default,,0,0,0,,用于取代原来需要副作用和对象的地方 Dialogue: 0,0:54:06.80,0:54:10.52,Default,,0,0,0,,用一种良好定义的模块化系统来隐藏它们 Dialogue: 0,0:54:10.86,0:54:13.50,Default,,0,0,0,,这样 系统中就不会到处产生 Dialogue: 0,0:54:13.52,0:54:15.34,Default,,0,0,0,,赋值所带来的问题 Dialogue: 0,0:54:15.40,0:54:17.88,Default,,0,0,0,,因为它可以被理解透彻的概念所描述 Dialogue: 0,0:54:20.78,0:54:22.70,Default,,0,0,0,,推而广之 我想你们也发现了 Dialogue: 0,0:54:23.12,0:54:24.06,Default,,0,0,0,,我们正面对 我所认为的 Dialogue: 0,0:54:24.08,0:54:26.67,Default,,0,0,0,,计算机科学中最基本的问题 Dialogue: 0,0:54:26.97,0:54:27.82,Default,,0,0,0,,也就是 Dialogue: 0,0:54:28.24,0:54:32.03,Default,,0,0,0,,我们如何定义一门支持延迟求值的语言 Dialogue: 0,0:54:34.14,0:54:35.08,Default,,0,0,0,,但同时又能够 Dialogue: 0,0:54:35.87,0:54:38.25,Default,,0,0,0,,又能够把事物看做对象来操作 Dialogue: 0,0:54:38.36,0:54:40.36,Default,,0,0,0,,怎么样才能两者兼有之? Dialogue: 0,0:54:41.23,0:54:43.04,Default,,0,0,0,,我认为这个问题很困难 Dialogue: 0,0:54:43.04,0:54:45.52,Default,,0,0,0,,但是这个很困难的问题 Dialogue: 0,0:54:45.85,0:54:48.17,Default,,0,0,0,,却和计算机科学的关系不大 Dialogue: 0,0:54:48.59,0:54:50.24,Default,,0,0,0,,它真正涉及的是 Dialogue: 0,0:54:50.27,0:54:52.73,Default,,0,0,0,,两种不相容的看待世界的方式 Dialogue: 0,0:54:54.14,0:54:54.72,Default,,0,0,0,,有问题吗? Dialogue: 0,0:55:17.55,0:55:19.20,Default,,0,0,0,,学生:你之前提到过 Dialogue: 0,0:55:20.11,0:55:21.32,Default,,0,0,0,,一旦引入了赋值 Dialogue: 0,0:55:21.32,0:55:25.89,Default,,0,0,0,,就不能使用代换模型了 Dialogue: 0,0:55:25.89,0:55:27.57,Default,,0,0,0,,除非你非常小心 Dialogue: 0,0:55:27.57,0:55:27.96,Default,,0,0,0,,教授:对的 Dialogue: 0,0:55:28.26,0:55:33.28,Default,,0,0,0,,学生:有什么技术或者指导方针 Dialogue: 0,0:55:33.42,0:55:35.92,Default,,0,0,0,,来确定赋值的影响 Dialogue: 0,0:55:36.52,0:55:40.30,Default,,0,0,0,,以便说清楚这个“很小心”是怎么回事吗? Dialogue: 0,0:55:40.30,0:55:42.60,Default,,0,0,0,,教授:我不知道 Dialogue: 0,0:55:42.89,0:55:43.58,Default,,0,0,0,,我想想 Dialogue: 0,0:55:45.43,0:55:48.94,Default,,0,0,0,,当然 实现MEM-PROC也使用了赋值 Dialogue: 0,0:55:50.12,0:55:51.48,Default,,0,0,0,,但是它被隐藏了起来 Dialogue: 0,0:55:51.48,0:55:53.00,Default,,0,0,0,,因为它没有对结果造成影响 Dialogue: 0,0:55:53.48,0:55:56.44,Default,,0,0,0,,部分原因之一在于 一旦触发这个过程 Dialogue: 0,0:55:57.15,0:55:58.83,Default,,0,0,0,,它被求值并得到结果 Dialogue: 0,0:55:58.83,0:56:00.06,Default,,0,0,0,,这个结果不会再变化 Dialogue: 0,0:56:00.60,0:56:02.33,Default,,0,0,0,,有点像单次赋值 Dialogue: 0,0:56:02.35,0:56:03.85,Default,,0,0,0,,一个一般性原则就是 Dialogue: 0,0:56:04.30,0:56:06.35,Default,,0,0,0,,如果你只用这种单次赋值 Dialogue: 0,0:56:08.04,0:56:09.24,Default,,0,0,0,,并且它不再改变 Dialogue: 0,0:56:09.63,0:56:10.54,Default,,0,0,0,,我想应该不会有太大问题 Dialogue: 0,0:56:11.25,0:56:14.12,Default,,0,0,0,,还有一个问题在于MERGE -- Dialogue: 0,0:56:14.67,0:56:18.32,Default,,0,0,0,,让我想想对不对 Dialogue: 0,0:56:18.49,0:56:21.55,Default,,0,0,0,,我认为有了公平合并这一技术 Dialogue: 0,0:56:22.25,0:56:26.09,Default,,0,0,0,,你可以在语言的其它地方 Dialogue: 0,0:56:27.02,0:56:28.89,Default,,0,0,0,,有效地模拟赋值 Dialogue: 0,0:56:30.82,0:56:33.29,Default,,0,0,0,,这就像为了解决问题你会引入一些东西 Dialogue: 0,0:56:33.50,0:56:35.50,Default,,0,0,0,,我不清楚对公平合并来说是否成立 Dialogue: 0,0:56:35.53,0:56:39.31,Default,,0,0,0,,但是对人们正在尝试的一些一般性事情是成立的 Dialogue: 0,0:56:39.52,0:56:41.34,Default,,0,0,0,,所以 这可能是你引入的这一点点东西 Dialogue: 0,0:56:41.61,0:56:44.14,Default,,0,0,0,,突然间 使你能构建任何东西 Dialogue: 0,0:56:44.16,0:56:46.51,Default,,0,0,0,,这就几乎跟有了赋值一样糟糕了 Dialogue: 0,0:56:47.97,0:56:50.67,Default,,0,0,0,,这也是人们在研究的一个领域 Dialogue: 0,0:56:51.59,0:56:54.30,Default,,0,0,0,,学生:我还没有太明白MERGE的问题 Dialogue: 0,0:56:54.83,0:56:59.20,Default,,0,0,0,,如果我调用Bill它是个过程 Dialogue: 0,0:56:59.21,0:57:02.41,Default,,0,0,0,,那么Bill就会增加银行账户 Dialogue: 0,0:57:02.44,0:57:04.73,Default,,0,0,0,,或者创建一个表 用于放置下一个存款 Dialogue: 0,0:57:04.73,0:57:06.84,Default,,0,0,0,,如果我连续调用Dave两次 他肯定也会那样 Dialogue: 0,0:57:07.17,0:57:09.35,Default,,0,0,0,,我并不清楚为什么需要公平合并 Dialogue: 0,0:57:09.35,0:57:11.20,Default,,0,0,0,,教授:关键在于你得把这些当作真人一样 Dialogue: 0,0:57:11.20,0:57:14.20,Default,,0,0,0,,这里有一个用户在操作帐户 Dialogue: 0,0:57:14.85,0:57:17.07,Default,,0,0,0,,请求一次 得到结果 Dialogue: 0,0:57:17.20,0:57:17.56,Default,,0,0,0,,学生:对 Dialogue: 0,0:57:18.20,0:57:20.62,Default,,0,0,0,,教授:如果我只能通过从两个流中选择一个 Dialogue: 0,0:57:20.65,0:57:22.25,Default,,0,0,0,,来处理请求的话 Dialogue: 0,0:57:22.91,0:57:24.22,Default,,0,0,0,,学生:为什么要二选一呢? Dialogue: 0,0:57:24.22,0:57:25.23,Default,,0,0,0,,教授:为什么不呢? Dialogue: 0,0:57:25.45,0:57:25.80,Default,,0,0,0,,学生:对啊 为什么要这样呢? Dialogue: 0,0:57:26.60,0:57:27.72,Default,,0,0,0,,教授:假设这些是现实中的人 对吗? Dialogue: 0,0:57:27.76,0:57:28.97,Default,,0,0,0,,这个人外出一年 Dialogue: 0,0:57:29.28,0:57:31.74,Default,,0,0,0,,你只能在银行账户窗口旁边等待 Dialogue: 0,0:57:32.43,0:57:33.72,Default,,0,0,0,,就是不能处理两个请求 Dialogue: 0,0:57:33.74,0:57:34.94,Default,,0,0,0,,因为你还得等这个人 Dialogue: 0,0:57:35.48,0:57:37.07,Default,,0,0,0,,学生:为什么非得等他呢? Dialogue: 0,0:57:37.38,0:57:39.11,Default,,0,0,0,,教授:因为这里是在计算一个函数 Dialogue: 0,0:57:39.11,0:57:40.92,Default,,0,0,0,,我必须定义一个函数 Dialogue: 0,0:57:41.72,0:57:42.60,Default,,0,0,0,,换种方式来说 Dialogue: 0,0:57:42.84,0:57:44.99,Default,,0,0,0,,这个MERGE盒子的输出 Dialogue: 0,0:57:46.24,0:57:49.48,Default,,0,0,0,,并不是输入的函数 Dialogue: 0,0:57:51.69,0:57:53.49,Default,,0,0,0,,明白了吗?再来看看这个MERGE是怎么运行的 Dialogue: 0,0:57:53.49,0:57:58.86,Default,,0,0,0,,假设Bill输入 1 1 1 1 Dialogue: 0,0:57:59.82,0:58:02.78,Default,,0,0,0,,Dave输入2 2 2 2 Dialogue: 0,0:58:03.47,0:58:04.80,Default,,0,0,0,,MERGE应该输出什么呢? Dialogue: 0,0:58:05.58,0:58:08.74,Default,,0,0,0,,这里并不一定是 1 2 1 2 1 2 Dialogue: 0,0:58:08.74,0:58:09.39,Default,,0,0,0,,学生:我明白了 Dialogue: 0,0:58:09.39,0:58:11.56,Default,,0,0,0,,当Bill输入1 1也就进去了 Dialogue: 0,0:58:11.56,0:58:13.95,Default,,0,0,0,,Dave再输入两个2 MERGE就输出两个2 Dialogue: 0,0:58:13.95,0:58:14.73,Default,,0,0,0,,学生:当Bill输入 Dialogue: 0,0:58:14.76,0:58:15.08,Default,,0,0,0,,教授:对的 Dialogue: 0,0:58:15.13,0:58:18.43,Default,,0,0,0,,学生:为什么不能在输入的数据上 Dialogue: 0,0:58:18.59,0:58:20.06,Default,,0,0,0,,加上时间信息呢? Dialogue: 0,0:58:20.12,0:58:21.84,Default,,0,0,0,,教授:因为这里没有时间这个概念 Dialogue: 0,0:58:23.98,0:58:26.90,Default,,0,0,0,,我只是定义一个函数 Dialogue: 0,0:58:26.90,0:58:28.15,Default,,0,0,0,,没有时间概念 Dialogue: 0,0:58:32.00,0:58:34.19,Default,,0,0,0,,如果是二选一的话 Dialogue: 0,0:58:34.19,0:58:36.54,Default,,0,0,0,,如果选中的流没有人 就得等待它 Dialogue: 0,0:58:38.42,0:58:41.36,Default,,0,0,0,,它只会说 我有一个请求流 Dialogue: 0,0:58:41.74,0:58:43.34,Default,,0,0,0,,这是是Dave生成的 Dialogue: 0,0:58:43.36,0:58:45.29,Default,,0,0,0,,没有时刻的、无穷长度的请求流 Dialogue: 0,0:58:47.55,0:58:50.41,Default,,0,0,0,,Bill可能生成 没有时刻的无穷请求流 Dialogue: 0,0:58:50.54,0:58:51.69,Default,,0,0,0,,我想对这些东西做运算 Dialogue: 0,0:58:51.69,0:58:53.51,Default,,0,0,0,,这就是银行帐户的工作原理 Dialogue: 0,0:58:56.71,0:58:57.58,Default,,0,0,0,,问题是 Dialogue: 0,0:58:57.61,0:59:00.75,Default,,0,0,0,,这些坐在银行窗口前的倒霉蛋们 Dialogue: 0,0:59:00.76,0:59:03.82,Default,,0,0,0,,来得并不是时候 Dialogue: 0,0:59:05.29,0:59:07.13,Default,,0,0,0,,它们才看不到这个无穷流 Dialogue: 0,0:59:07.69,0:59:09.53,Default,,0,0,0,,什么时候其中会有请求 Dialogue: 0,0:59:10.07,0:59:11.55,Default,,0,0,0,,他们只是等着 等待帐户的响应 Dialogue: 0,0:59:14.48,0:59:15.76,Default,,0,0,0,,假设你坐在屏幕前 Dialogue: 0,0:59:16.24,0:59:20.86,Default,,0,0,0,,操作着一台分时系统的计算机 Dialogue: 0,0:59:21.52,0:59:22.60,Default,,0,0,0,,而且它还是函数式的 Dialogue: 0,0:59:22.64,0:59:24.59,Default,,0,0,0,,输入指令后你就希望看到结果 Dialogue: 0,0:59:25.29,0:59:27.42,Default,,0,0,0,,但是你并不想主机在处理完所有其它人的命令 Dialogue: 0,0:59:27.45,0:59:29.92,Default,,0,0,0,,之后再来处理你的命令 Dialogue: 0,0:59:30.91,0:59:31.92,Default,,0,0,0,,这就是问题所在 Dialogue: 0,0:59:34.00,0:59:36.38,Default,,0,0,0,,我的意思就是 用户的世界当然是存在时间概念的 Dialogue: 0,0:59:37.21,0:59:38.62,Default,,0,0,0,,如果没有 这就不构成问题 Dialogue: 0,0:59:49.10,0:59:51.02,Default,,0,0,0,,学生:我想我还是不太理解 Dialogue: 0,0:59:51.08,0:59:54.24,Default,,0,0,0,,银行交易中为什么没有时间概念这一要点 Dialogue: 0,0:59:54.74,0:59:56.65,Default,,0,0,0,,难道时间不是非常重要吗? Dialogue: 0,0:59:56.88,0:59:59.05,Default,,0,0,0,,举例说 有一系列事件 Dialogue: 0,0:59:59.95,1:00:05.02,Default,,0,0,0,,比如Dave取款$100 Dialogue: 0,1:00:06.30,1:00:08.40,Default,,0,0,0,,这些顺序应该很重要才对 Dialogue: 0,1:00:08.40,1:00:10.86,Default,,0,0,0,,你怎么能把它们看作是流呢? Dialogue: 0,1:00:11.26,1:00:14.26,Default,,0,0,0,,教授:这就是我一直在强调的 Dialogue: 0,1:00:14.26,1:00:15.61,Default,,0,0,0,,在这个例子中确实做不到那一点 Dialogue: 0,1:00:17.51,1:00:18.12,Default,,0,0,0,,做不到 Dialogue: 0,1:00:18.16,1:00:20.08,Default,,0,0,0,,关键在于 这里的输出 Dialogue: 0,1:00:20.24,1:00:21.88,Default,,0,0,0,,并不是这两个输入流 Dialogue: 0,1:00:21.92,1:00:23.60,Default,,0,0,0,,的函数 Dialogue: 0,1:00:24.17,1:00:25.98,Default,,0,0,0,,这个函数跟这个输入流有关 Dialogue: 0,1:00:26.19,1:00:27.26,Default,,0,0,0,,还跟这个输入流有关 Dialogue: 0,1:00:27.36,1:00:29.07,Default,,0,0,0,,还包括某种有关时间的信息 Dialogue: 0,1:00:29.37,1:00:32.36,Default,,0,0,0,,这也正是正则序语言不想让你知道的 Dialogue: 0,1:00:34.81,1:00:37.95,Default,,0,0,0,,学生:为了让这个系统更加函数式 Dialogue: 0,1:00:38.54,1:00:42.04,Default,,0,0,0,,我们能不能把Bill和Dave的交易请求附上时间戳 Dialogue: 0,1:00:42.54,1:00:46.40,Default,,0,0,0,,而使用时间戳作为公平合并的依据? Dialogue: 0,1:00:48.41,1:00:49.55,Default,,0,0,0,,教授:当然 当然可以 Dialogue: 0,1:00:49.55,1:00:50.60,Default,,0,0,0,,你可以那样做 Dialogue: 0,1:00:50.60,1:00:52.56,Default,,0,0,0,,或者 我们可以这样来想象 Dialogue: 0,1:00:52.76,1:00:54.44,Default,,0,0,0,,我们把这个函数看作是 Dialogue: 0,1:00:54.78,1:00:56.88,Default,,0,0,0,,MERGE每毫秒读一次输入 Dialogue: 0,1:00:58.86,1:00:59.93,Default,,0,0,0,,如果没有读到东西 Dialogue: 0,1:00:59.93,1:01:00.97,Default,,0,0,0,,就认为没有请求 Dialogue: 0,1:01:00.97,1:01:03.39,Default,,0,0,0,,这和你刚刚说的那种方式是等价的 Dialogue: 0,1:01:03.61,1:01:06.08,Default,,0,0,0,,当然可以这样做 但有点旁门左道 Dialogue: 0,1:01:07.11,1:01:10.14,Default,,0,0,0,,我们不只是关心函数的具体实现 Dialogue: 0,1:01:10.76,1:01:12.73,Default,,0,0,0,,我们关心的是语言的表达力 Dialogue: 0,1:01:12.75,1:01:14.67,Default,,0,0,0,,我们遇到的困难是 Dialogue: 0,1:01:14.99,1:01:17.44,Default,,0,0,0,,我们不能很容易地表达我们想要表达的东西 Dialogue: 0,1:01:19.88,1:01:22.01,Default,,0,0,0,,学生:听起来好像如果两个人同时发出请求 Dialogue: 0,1:01:22.06,1:01:26.09,Default,,0,0,0,,这个方法就会出问题 Dialogue: 0,1:01:26.12,1:01:28.43,Default,,0,0,0,,教授:并不只是这个 只要是你定义的都可能出问题 Dialogue: 0,1:01:28.53,1:01:30.57,Default,,0,0,0,,你当然可以说Dave经常发起两个请求 Dialogue: 0,1:01:30.72,1:01:32.32,Default,,0,0,0,,但是你如果预先定义了什么 Dialogue: 0,1:01:32.68,1:01:33.87,Default,,0,0,0,,这样做也不正确 Dialogue: 0,1:01:36.11,1:01:40.70,Default,,0,0,0,,你不能确定某些特定函数的输入请求 Dialogue: 0,1:01:41.93,1:01:43.37,Default,,0,0,0,,但是还有更坏的情况 Dialogue: 0,1:01:44.12,1:01:45.72,Default,,0,0,0,,有一些情况甚至MERGE也处理不了 Dialogue: 0,1:01:47.29,1:01:49.69,Default,,0,0,0,,比如突然有一天你想要 Dialogue: 0,1:01:50.24,1:01:52.47,Default,,0,0,0,,把另一个人关联在这个银行帐户上 Dialogue: 0,1:01:52.47,1:01:54.51,Default,,0,0,0,,假如这个人是John Dialogue: 0,1:01:56.03,1:01:58.89,Default,,0,0,0,,现在图上就要多一个流 Dialogue: 0,1:01:58.91,1:02:00.70,Default,,0,0,0,,在一个我们未曾指定的时候 Dialogue: 0,1:02:02.04,1:02:04.00,Default,,0,0,0,,这种情况甚至公平合并也无法给出合理的合并 Dialogue: 0,1:02:04.00,1:02:08.25,Default,,0,0,0,,还需要有MANAGER一类的东西 Dialogue: 0,1:02:08.86,1:02:11.79,Default,,0,0,0,,需要一种更一般性的公平合并来解决 Dialogue: 0,1:02:11.79,1:02:13.98,Default,,0,0,0,,有很多研究都在讨论 Dialogue: 0,1:02:14.00,1:02:16.30,Default,,0,0,0,,通过不断引入新机制 Dialogue: 0,1:02:16.59,1:02:18.72,Default,,0,0,0,,函数式思维能应用到哪种程度? Dialogue: 0,1:02:19.58,1:02:21.79,Default,,0,0,0,,在我们不得不使用赋值之前 Dialogue: 0,1:02:21.82,1:02:23.40,Default,,0,0,0,,函数式程序设计能干成什么样? Dialogue: 0,1:02:25.98,1:02:28.00,Default,,0,0,0,,学生:看来自动存款就不行 Dialogue: 0,1:02:39.32,1:02:40.49,Default,,0,0,0,,教授:好的 下课 Dialogue: 0,1:02:41.32,1:03:00.08,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:02:41.32,1:03:00.08,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec6b.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Video Position: 629 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:20.97,0:00:24.08,EN,,0,0,0,,PROFESSOR: OK, well, we've been looking at streams, Dialogue: 0,0:00:24.08,0:00:27.82,EN,,0,0,0,,this signal processing way of putting systems together. Dialogue: 0,0:00:28.87,0:00:31.42,EN,,0,0,0,,And remember, the key idea is that Dialogue: 0,0:00:31.90,0:00:32.96,EN,,0,0,0,,we decouple Dialogue: 0,0:00:34.20,0:00:37.31,EN,,0,0,0,,the apparent order of events in our programs Dialogue: 0,0:00:37.58,0:00:40.17,EN,,0,0,0,,from the actual order of events in the computer. Dialogue: 0,0:00:41.07,0:00:42.28,EN,,0,0,0,,And that means that we can start Dialogue: 0,0:00:42.57,0:00:44.14,EN,,0,0,0,,dealing with very long streams Dialogue: 0,0:00:44.89,0:00:47.39,EN,,0,0,0,,and only having to generate the elements on demand. Dialogue: 0,0:00:47.53,0:00:49.39,EN,,0,0,0,,That sort of on-demand computation Dialogue: 0,0:00:49.52,0:00:51.40,EN,,0,0,0,,is built into the stream's data structure. Dialogue: 0,0:00:54.11,0:00:55.64,EN,,0,0,0,,So if we have a very long stream, Dialogue: 0,0:00:55.66,0:00:57.08,EN,,0,0,0,,we only compute what we need. Dialogue: 0,0:00:58.04,0:01:00.75,EN,,0,0,0,,The things only get computed when we actually ask for them. Dialogue: 0,0:01:00.75,0:01:01.74,EN,,0,0,0,,Well, what are examples? Dialogue: 0,0:01:02.11,0:01:03.60,EN,,0,0,0,,Are they actually asking for them? Dialogue: 0,0:01:05.02,0:01:06.01,EN,,0,0,0,,For instance, we might Dialogue: 0,0:01:09.21,0:01:11.37,EN,,0,0,0,,might ask for the n-th element of a stream. Dialogue: 0,0:01:15.36,0:01:18.92,EN,,0,0,0,,Here's a procedure that computes the n-th element of a stream. Dialogue: 0,0:01:20.09,0:01:21.23,EN,,0,0,0,,An integer n, Dialogue: 0,0:01:21.24,0:01:22.84,EN,,0,0,0,,the n-th element of some stream s, Dialogue: 0,0:01:23.40,0:01:25.42,EN,,0,0,0,,and we just recursively walk down the stream. Dialogue: 0,0:01:25.57,0:01:27.39,EN,,0,0,0,,And if n is 0, we compute the head. Dialogue: 0,0:01:27.96,0:01:30.99,EN,,0,0,0,,Otherwise, it's the n-th the minus 1 element Dialogue: 0,0:01:31.74,0:01:32.80,EN,,0,0,0,,of the stream. Dialogue: 0,0:01:34.31,0:01:36.43,EN,,0,0,0,,Those two are just like for Lisp, but the difference Dialogue: 0,0:01:36.62,0:01:38.76,EN,,0,0,0,,is those elements aren't going to get computed Dialogue: 0,0:01:38.86,0:01:40.99,EN,,0,0,0,,until we walk down, taking successive n-ths. Dialogue: 0,0:01:41.52,0:01:44.78,EN,,0,0,0,,So that's one way that the stream elements might get forced. Dialogue: 0,0:01:45.77,0:01:46.64,EN,,0,0,0,,And another way, Dialogue: 0,0:01:47.18,0:01:48.92,EN,,0,0,0,,here's a little procedure that prints a stream. Dialogue: 0,0:01:49.30,0:01:50.38,EN,,0,0,0,,We say print a stream, Dialogue: 0,0:01:51.90,0:01:53.28,EN,,0,0,0,,so to print a stream s. Dialogue: 0,0:01:54.15,0:01:55.12,EN,,0,0,0,,Well, what do we do? We'll Dialogue: 0,0:01:55.74,0:01:56.86,EN,,0,0,0,,We print the head of the stream, Dialogue: 0,0:01:57.74,0:01:59.32,EN,,0,0,0,,and that will cause the head to be computed. Dialogue: 0,0:01:59.72,0:02:02.84,EN,,0,0,0,,And then we recursively print stream the tail of the stream. Dialogue: 0,0:02:04.99,0:02:06.03,EN,,0,0,0,,And if we're already done, Dialogue: 0,0:02:06.04,0:02:08.57,EN,,0,0,0,,maybe we have to return something about the message done. Dialogue: 0,0:02:09.66,0:02:11.39,EN,,0,0,0,,OK, and then so if you make a stream, Dialogue: 0,0:02:11.64,0:02:13.64,EN,,0,0,0,,you could say here's the stream, this very long stream. Dialogue: 0,0:02:14.31,0:02:16.33,EN,,0,0,0,,And then you say print the stream, Dialogue: 0,0:02:16.41,0:02:19.77,EN,,0,0,0,,and the elements of the stream will get computed successively Dialogue: 0,0:02:19.87,0:02:21.12,EN,,0,0,0,,as that print calls them. Dialogue: 0,0:02:21.32,0:02:22.81,EN,,0,0,0,,They won't get all computed initially. Dialogue: 0,0:02:24.30,0:02:25.66,EN,,0,0,0,,So in this way, we can Dialogue: 0,0:02:27.50,0:02:29.61,EN,,0,0,0,,So in this way, we can deal with some very long streams. Dialogue: 0,0:02:30.19,0:02:31.92,EN,,0,0,0,,Well, how long can a stream be? Dialogue: 0,0:02:33.74,0:02:35.12,EN,,0,0,0,,Well, it can be infinitely long. Dialogue: 0,0:02:35.90,0:02:38.04,EN,,0,0,0,,Let's look at an example here on the computer. Dialogue: 0,0:02:38.92,0:02:41.96,EN,,0,0,0,,I could walk up to this computer, and I could say-- Dialogue: 0,0:02:43.48,0:02:53.31,EN,,0,0,0,,how about we'll define the stream of integers starting with some number N, Dialogue: 0,0:02:54.24,0:02:57.13,EN,,0,0,0,,the stream of positive integers starting with some number n. Dialogue: 0,0:03:00.36,0:03:19.16,EN,,0,0,0,,And that's cons-stream of n onto the integers from one more. Dialogue: 0,0:03:24.41,0:03:25.61,EN,,0,0,0,,So there are the integers. Dialogue: 0,0:03:28.99,0:03:31.50,EN,,0,0,0,,Then I could say let's get all the integers. Dialogue: 0,0:03:34.57,0:03:44.33,EN,,0,0,0,,define the stream of integers to be the integers starting with 1. Dialogue: 0,0:03:48.84,0:03:50.94,EN,,0,0,0,,And now if I say something like Dialogue: 0,0:03:54.41,0:03:55.80,EN,,0,0,0,,what's the what's the 20th integer. Dialogue: 0,0:04:03.42,0:04:05.53,EN,,0,0,0,,So it's 21 because we start counting at 0. Dialogue: 0,0:04:06.84,0:04:08.88,EN,,0,0,0,,Or I can do more complicated things. Dialogue: 0,0:04:09.45,0:04:10.84,EN,,0,0,0,,Let me to define a little predicate here. Dialogue: 0,0:04:11.77,0:04:18.51,EN,,0,0,0,,How about define no-seven. Dialogue: 0,0:04:19.58,0:04:20.75,EN,,0,0,0,,It's going to test an integer, Dialogue: 0,0:04:21.79,0:04:23.16,EN,,0,0,0,,and it's going to say it's not. Dialogue: 0,0:04:28.82,0:04:33.96,EN,,0,0,0,,I take the remainder of x by 7, Dialogue: 0,0:04:36.62,0:04:38.35,EN,,0,0,0,,I don't get 0. Dialogue: 0,0:04:43.80,0:04:49.77,EN,,0,0,0,,And then I could say define the integers with no sevens Dialogue: 0,0:04:50.22,0:04:59.12,EN,,0,0,0,,take all the integers and filter them to have no sevens. Dialogue: 0,0:05:11.57,0:05:13.34,EN,,0,0,0,,So now I've got the stream of all the integers Dialogue: 0,0:05:13.63,0:05:15.05,EN,,0,0,0,,that are not divisible by seven. Dialogue: 0,0:05:16.49,0:05:23.44,EN,,0,0,0,,So if I say what's the 100th integer Dialogue: 0,0:05:24.70,0:05:26.48,EN,,0,0,0,,and the list not divisible by seven, Dialogue: 0,0:05:26.86,0:05:28.11,EN,,0,0,0,,I get 117. Dialogue: 0,0:05:28.32,0:05:30.67,EN,,0,0,0,,Or if I'd like to say well, I could say ah. Dialogue: 0,0:05:32.30,0:05:34.38,EN,,0,0,0,,well, gee, what are all of them? Dialogue: 0,0:05:35.27,0:05:40.35,EN,,0,0,0,,So I could say print stream all these integers with no seven, Dialogue: 0,0:05:40.83,0:05:41.79,EN,,0,0,0,,it goes off printing. Dialogue: 0,0:05:45.10,0:05:47.07,EN,,0,0,0,,You may have to wait a very long time to see them all. Dialogue: 0,0:05:52.67,0:05:53.84,EN,,0,0,0,,Well, you can start asking, gee, Dialogue: 0,0:05:54.81,0:05:57.00,EN,,0,0,0,,you know, is it really true that this data structure Dialogue: 0,0:05:58.28,0:06:00.65,EN,,0,0,0,,with the integers is really all the integers? Dialogue: 0,0:06:01.10,0:06:04.05,EN,,0,0,0,,And let me draw a picture of that program I just wrote. Dialogue: 0,0:06:04.96,0:06:10.57,EN,,0,0,0,,Here's the, right, here's the definition of the integers again that I just typed in, Dialogue: 0,0:06:12.33,0:06:15.98,EN,,0,0,0,,Right it's a cons of the first integer under the integer starting with the rest. Dialogue: 0,0:06:17.61,0:06:19.77,EN,,0,0,0,,Now, we can make a picture of that and see what it looks like. Dialogue: 0,0:06:22.72,0:06:24.32,EN,,0,0,0,,Conceptually, what I have is a box Dialogue: 0,0:06:25.53,0:06:27.18,EN,,0,0,0,,that's the integer starting with n. Dialogue: 0,0:06:27.42,0:06:29.08,EN,,0,0,0,,It takes in some number n, Dialogue: 0,0:06:31.42,0:06:32.97,EN,,0,0,0,,and it's going to return a stream of-- Dialogue: 0,0:06:35.02,0:06:37.36,EN,,0,0,0,,this infinite stream of all integers starting with n. Dialogue: 0,0:06:38.08,0:06:38.73,EN,,0,0,0,,And what do I do? Dialogue: 0,0:06:38.75,0:06:42.38,EN,,0,0,0,,Well, this is an integers-from box. Dialogue: 0,0:06:45.07,0:06:45.80,EN,,0,0,0,,What's it got in it? Dialogue: 0,0:06:45.80,0:06:48.60,EN,,0,0,0,,Well, it takes in this n, Dialogue: 0,0:06:52.27,0:06:53.92,EN,,0,0,0,,and it increments it. Dialogue: 0,0:06:57.95,0:07:03.15,EN,,0,0,0,,And then it puts the result into recursively another integer's from box. Dialogue: 0,0:07:06.87,0:07:09.60,EN,,0,0,0,,It takes the result of that and the original n Dialogue: 0,0:07:10.24,0:07:12.78,EN,,0,0,0,,and puts those together with a cons Dialogue: 0,0:07:13.39,0:07:14.36,EN,,0,0,0,,and forms a stream. Dialogue: 0,0:07:14.57,0:07:17.26,EN,,0,0,0,,So that's a picture of that program I wrote. And this is a ... Dialogue: 0,0:07:18.52,0:07:20.32,EN,,0,0,0,,Let's see. These kind of diagrams we first saw Dialogue: 0,0:07:20.78,0:07:21.74,EN,,0,0,0,,drawn by Peter Henderson, Dialogue: 0,0:07:21.76,0:07:23.32,EN,,0,0,0,,the same guy who did the Escher language. Dialogue: 0,0:07:23.32,0:07:24.75,EN,,0,0,0,,We call them Henderson diagrams. Dialogue: 0,0:07:25.37,0:07:27.90,EN,,0,0,0,,And the convention here is that you put these things together. Dialogue: 0,0:07:28.53,0:07:32.51,EN,,0,0,0,,And the solid lines are things coming out are streams, Dialogue: 0,0:07:33.02,0:07:36.20,EN,,0,0,0,,and dotted lines are initial values going in. Dialogue: 0,0:07:37.27,0:07:39.02,EN,,0,0,0,,So this one has the shape of-- Dialogue: 0,0:07:39.40,0:07:41.60,EN,,0,0,0,,it takes in some integer, some initial value, Dialogue: 0,0:07:41.80,0:07:42.91,EN,,0,0,0,,and outputs a stream. Dialogue: 0,0:07:46.35,0:07:48.22,EN,,0,0,0,,Again, you can ask. You know it's really Dialogue: 0,0:07:48.38,0:07:50.88,EN,,0,0,0,,Is that data structure integers really all the integers? Dialogue: 0,0:07:52.09,0:07:54.91,EN,,0,0,0,,Alright? Or is it is something that's cleverly arranged Dialogue: 0,0:07:54.94,0:07:56.43,EN,,0,0,0,,so that whenever you look for an integer Dialogue: 0,0:07:56.44,0:07:57.24,EN,,0,0,0,,you find it there? Dialogue: 0,0:07:57.95,0:07:59.74,EN,,0,0,0,,That's sort of a philosophical question, right? Dialogue: 0,0:07:59.78,0:08:01.69,EN,,0,0,0,,If something is there Dialogue: 0,0:08:02.14,0:08:03.96,EN,,0,0,0,,whenever you look, is it really there or not? Dialogue: 0,0:08:04.45,0:08:07.34,EN,,0,0,0,,It's sort of the same sense in which Dialogue: 0,0:08:07.36,0:08:09.42,EN,,0,0,0,,the money in your savings account is in the bank. Dialogue: 0,0:08:12.38,0:08:12.64,EN,,0,0,0,,Well Dialogue: 0,0:08:16.35,0:08:17.48,EN,,0,0,0,,let me do another example. Dialogue: 0,0:08:18.68,0:08:20.70,EN,,0,0,0,,Umm, Gee, we started the course Dialogue: 0,0:08:20.72,0:08:22.72,EN,,0,0,0,,with an algorithm from Alexandria, Dialogue: 0,0:08:23.29,0:08:25.80,EN,,0,0,0,,which was Heron of Alexandria's algorithm Dialogue: 0,0:08:25.82,0:08:26.94,EN,,0,0,0,,for computing the square root. Dialogue: 0,0:08:28.47,0:08:32.03,EN,,0,0,0,,Let's take a look at another Alexandrian algorithm. Dialogue: 0,0:08:32.03,0:08:35.08,EN,,0,0,0,,This one is Eratosthenes method for Dialogue: 0,0:08:36.19,0:08:38.44,EN,,0,0,0,,for computing all of the primes. Dialogue: 0,0:08:41.16,0:08:42.83,EN,,0,0,0,,It is called the Sieve of Eratosthenes. Dialogue: 0,0:08:42.83,0:08:49.72,EN,,0,0,0,,And what you do is you start out, Dialogue: 0,0:08:50.99,0:08:52.28,EN,,0,0,0,,and you list all the integers, Dialogue: 0,0:08:52.60,0:08:53.53,EN,,0,0,0,,say, starting with 2. Dialogue: 0,0:08:53.88,0:08:55.04,EN,,0,0,0,,And then you take the first integer, and you say, Dialogue: 0,0:08:55.08,0:08:56.67,EN,,0,0,0,,and you say, oh, that's prime. Dialogue: 0,0:08:57.31,0:08:58.35,EN,,0,0,0,,And then you go look at the rest, Dialogue: 0,0:08:58.68,0:09:00.88,EN,,0,0,0,,and you cross out all the things divisible by 2. Dialogue: 0,0:09:01.52,0:09:04.73,EN,,0,0,0,,So I cross out this and this and this. Dialogue: 0,0:09:05.25,0:09:06.35,EN,,0,0,0,,This takes a long time Dialogue: 0,0:09:06.36,0:09:08.91,EN,,0,0,0,,because I have to do it for all of the integers. Dialogue: 0,0:09:11.16,0:09:15.39,EN,,0,0,0,,So I go through the entire list of integers, Dialogue: 0,0:09:18.27,0:09:20.94,EN,,0,0,0,,crossing the ones divisible by 2. Dialogue: 0,0:09:22.11,0:09:24.38,EN,,0,0,0,,And now when I finish with all of the integers, Dialogue: 0,0:09:24.78,0:09:26.72,EN,,0,0,0,,I go back and look and say what am I left with? Dialogue: 0,0:09:27.04,0:09:28.80,EN,,0,0,0,,Well, the first thing that starts there is 3. Dialogue: 0,0:09:29.33,0:09:30.33,EN,,0,0,0,,So 3 is a prime. Dialogue: 0,0:09:30.77,0:09:33.05,EN,,0,0,0,,And now I go back through what I'm left with, Dialogue: 0,0:09:33.36,0:09:35.07,EN,,0,0,0,,and I cross out all the things divisible by 3. Dialogue: 0,0:09:35.08,0:09:43.80,EN,,0,0,0,,So let's see, 9 and 15 and 21 and 27 and 33 and so on. Dialogue: 0,0:09:44.33,0:09:45.12,EN,,0,0,0,,I won't finish. Dialogue: 0,0:09:45.35,0:09:46.52,EN,,0,0,0,,Then I see what I'm left with. Dialogue: 0,0:09:47.25,0:09:49.84,EN,,0,0,0,,And the next one I have is 5. Dialogue: 0,0:09:50.49,0:09:52.04,EN,,0,0,0,,Now I can through the rest, Dialogue: 0,0:09:52.43,0:09:54.51,EN,,0,0,0,,and I find the first one that's divisible by 5. Dialogue: 0,0:09:54.54,0:09:57.61,EN,,0,0,0,,I cross out from the remainder all the ones that are divisible by 5. Dialogue: 0,0:09:58.35,0:09:59.24,EN,,0,0,0,,And I did that, Dialogue: 0,0:09:59.82,0:10:01.89,EN,,0,0,0,,and then I go through and find 7. Dialogue: 0,0:10:01.89,0:10:02.72,EN,,0,0,0,,Go through all the rest, Dialogue: 0,0:10:02.76,0:10:03.95,EN,,0,0,0,,cross out things divisible 7, Dialogue: 0,0:10:03.98,0:10:05.47,EN,,0,0,0,,and I keep doing that forever. Dialogue: 0,0:10:06.81,0:10:07.40,EN,,0,0,0,,And when I'm done, Dialogue: 0,0:10:07.40,0:10:09.10,EN,,0,0,0,,what I'm left with is a list of all the primes. Dialogue: 0,0:10:09.90,0:10:13.31,EN,,0,0,0,,So that's the Sieve of Eratosthenes. Dialogue: 0,0:10:15.43,0:10:17.69,EN,,0,0,0,,Let's look at it as a computer program. Dialogue: 0,0:10:17.93,0:10:19.85,EN,,0,0,0,,It's a procedure called sieve. Dialogue: 0,0:10:27.91,0:10:29.40,EN,,0,0,0,,Now, I just write what I did. Dialogue: 0,0:10:30.33,0:10:34.48,EN,,0,0,0,,I'll say to sieve some stream s. Dialogue: 0,0:10:38.77,0:10:39.93,EN,,0,0,0,,I'm going to build a stream Dialogue: 0,0:10:40.27,0:10:41.84,EN,,0,0,0,,whose first element is the head of this. Dialogue: 0,0:10:41.87,0:10:44.43,EN,,0,0,0,,Remember, I always found the first thing I was left with, Dialogue: 0,0:10:44.91,0:10:48.75,EN,,0,0,0,,and the rest of it is the result of taking the tail of S, Dialogue: 0,0:10:51.08,0:10:53.72,EN,,0,0,0,,filtering it to throw away all the things Dialogue: 0,0:10:53.74,0:10:55.32,EN,,0,0,0,,that are divisible by the head of S, Dialogue: 0,0:10:56.41,0:10:57.56,EN,,0,0,0,,and now sieving the result. Dialogue: 0,0:10:59.02,0:11:00.09,EN,,0,0,0,,That's just what I did. Dialogue: 0,0:11:01.98,0:11:04.68,EN,,0,0,0,,And now to get the infinite stream of times, Dialogue: 0,0:11:05.02,0:11:06.90,EN,,0,0,0,,we just sieve all the integers starting from 2. Dialogue: 0,0:11:14.92,0:11:15.56,EN,,0,0,0,,Let's try that. Dialogue: 0,0:11:16.30,0:11:18.30,EN,,0,0,0,,We can actually do it. Dialogue: 0,0:11:19.76,0:11:22.12,EN,,0,0,0,,I typed in the definition of sieve before, I hope, Dialogue: 0,0:11:22.86,0:11:24.06,EN,,0,0,0,,so I can say something like Dialogue: 0,0:11:24.92,0:11:33.45,EN,,0,0,0,,define the primes to be Dialogue: 0,0:11:34.64,0:11:41.45,EN,,0,0,0,,the result of sieving the integers starting with 2. Dialogue: 0,0:11:46.76,0:11:48.10,EN,,0,0,0,,So now I've got this list of primes. Dialogue: 0,0:11:48.10,0:11:50.99,EN,,0,0,0,,That's all of the primes, right? Dialogue: 0,0:11:50.99,0:11:53.52,EN,,0,0,0,,So, if for example, what's the 20th prime in that list? Dialogue: 0,0:12:00.73,0:12:01.68,EN,,0,0,0,,73. Dialogue: 0,0:12:02.54,0:12:03.34,EN,,0,0,0,,See, and that little pause, Dialogue: 0,0:12:03.36,0:12:04.92,EN,,0,0,0,,it was only at the point Dialogue: 0,0:12:04.94,0:12:06.43,EN,,0,0,0,,when I started asking for the 20th prime Dialogue: 0,0:12:06.46,0:12:07.68,EN,,0,0,0,,is that it started computing. Dialogue: 0,0:12:10.37,0:12:11.29,EN,,0,0,0,,Or I can say here Dialogue: 0,0:12:13.80,0:12:14.88,EN,,0,0,0,,Or I can say here let's look at all of the primes. Dialogue: 0,0:12:22.64,0:12:24.40,EN,,0,0,0,,And there it goes computing all of the primes. Dialogue: 0,0:12:25.35,0:12:26.28,EN,,0,0,0,,Of course, it will take a while Dialogue: 0,0:12:26.28,0:12:27.61,EN,,0,0,0,,again if I want to look at all of them, Dialogue: 0,0:12:27.79,0:12:28.57,EN,,0,0,0,,so let's stop it. Dialogue: 0,0:12:32.03,0:12:33.13,EN,,0,0,0,,Let me draw you a picture of that. Dialogue: 0,0:12:33.13,0:12:34.17,EN,,0,0,0,,Well, I've got a picture of that. Dialogue: 0,0:12:34.89,0:12:36.19,EN,,0,0,0,,What's that program really look like? Dialogue: 0,0:12:37.90,0:12:39.77,EN,,0,0,0,,Again, some practice with these diagrams, Dialogue: 0,0:12:39.82,0:12:40.54,EN,,0,0,0,,I have a sieve box. Dialogue: 0,0:12:42.61,0:12:43.56,EN,,0,0,0,,How does sieve work? Dialogue: 0,0:12:43.56,0:12:44.81,EN,,0,0,0,,It takes in a stream. Dialogue: 0,0:12:48.85,0:12:50.59,EN,,0,0,0,,It splits off the head from the tail. Dialogue: 0,0:12:50.87,0:12:53.26,EN,,0,0,0,,And the first thing that's going to come out of the sieve Dialogue: 0,0:12:53.48,0:12:54.97,EN,,0,0,0,,is the head of the original stream. Dialogue: 0,0:12:58.20,0:13:00.92,EN,,0,0,0,,Then it also takes the head and uses that. Dialogue: 0,0:13:02.55,0:13:05.10,EN,,0,0,0,,It takes the stream. It filters the tail Dialogue: 0,0:13:05.55,0:13:08.33,EN,,0,0,0,,It filters the tail and uses the head to filter for nondivisibility. Dialogue: 0,0:13:09.53,0:13:11.18,EN,,0,0,0,,It takes the result of nondivisibility Dialogue: 0,0:13:11.24,0:13:13.12,EN,,0,0,0,,and puts it through another sieve box Dialogue: 0,0:13:13.90,0:13:15.13,EN,,0,0,0,,and puts the result together. Dialogue: 0,0:13:15.13,0:13:16.89,EN,,0,0,0,,So you can think of this sieve a filter, Dialogue: 0,0:13:17.20,0:13:19.23,EN,,0,0,0,,but notice that it's an infinitely recursive filter. Dialogue: 0,0:13:19.65,0:13:20.88,EN,,0,0,0,,Because inside the sieve box Dialogue: 0,0:13:21.52,0:13:22.60,EN,,0,0,0,,is another sieve box, Dialogue: 0,0:13:23.37,0:13:25.85,EN,,0,0,0,,and inside that is another sieve box and another sieve box. Dialogue: 0,0:13:27.13,0:13:28.96,EN,,0,0,0,,So you see we start getting some very powerful things. Dialogue: 0,0:13:28.96,0:13:32.84,EN,,0,0,0,,We're starting to mix this signal processing view of the world Dialogue: 0,0:13:33.90,0:13:36.41,EN,,0,0,0,,with things like recursion that come from computation. Dialogue: 0,0:13:37.42,0:13:39.82,EN,,0,0,0,,And there are all sorts of interesting things you can do that are like this. Dialogue: 0,0:13:40.97,0:13:42.09,EN,,0,0,0,,All right, any questions? Dialogue: 0,0:13:48.19,0:13:49.16,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:14:28.65,0:14:30.36,EN,,0,0,0,,Well, we've been looking at a couple Dialogue: 0,0:14:30.36,0:14:32.09,EN,,0,0,0,,of examples of stream programming. Dialogue: 0,0:14:34.79,0:14:39.21,EN,,0,0,0,,All the stream procedures that we've looked at so far Dialogue: 0,0:14:39.72,0:14:41.32,EN,,0,0,0,,have the same kind of character. Dialogue: 0,0:14:41.49,0:14:43.63,EN,,0,0,0,,We've been writing these recursive procedures Dialogue: 0,0:14:44.16,0:14:46.49,EN,,0,0,0,,that kind of generate these stream elements one at a time Dialogue: 0,0:14:46.51,0:14:48.72,EN,,0,0,0,,and put them together in cons-streams. Dialogue: 0,0:14:49.15,0:14:50.86,EN,,0,0,0,,So we've been thinking a lot about generators. Dialogue: 0,0:14:50.92,0:14:53.63,EN,,0,0,0,,There's another way to think about stream processing, Dialogue: 0,0:14:53.79,0:14:56.96,EN,,0,0,0,,and that's to focus not on programs that sort of Dialogue: 0,0:14:57.36,0:14:59.93,EN,,0,0,0,,process these elements as you walk down the stream, Dialogue: 0,0:15:00.25,0:15:05.68,EN,,0,0,0,,but on things that kind of process the streams all at once. Dialogue: 0,0:15:07.18,0:15:09.16,EN,,0,0,0,,To show you what I mean, let me start by defining Dialogue: 0,0:15:09.23,0:15:11.50,EN,,0,0,0,,two procedures that will come in handy. Dialogue: 0,0:15:12.41,0:15:13.60,EN,,0,0,0,,The first one's called add streams. Dialogue: 0,0:15:15.36,0:15:18.25,EN,,0,0,0,,Add streams takes two streams: Dialogue: 0,0:15:18.81,0:15:20.88,EN,,0,0,0,,s1 and s2. Dialogue: 0,0:15:22.30,0:15:24.67,EN,,0,0,0,,And it's going to produce a stream Dialogue: 0,0:15:24.99,0:15:28.17,EN,,0,0,0,,whose elements are the are the corresponding sums Dialogue: 0,0:15:30.22,0:15:31.88,EN,,0,0,0,,We just sort of add them element-wise. Dialogue: 0,0:15:32.97,0:15:33.95,EN,,0,0,0,,If either stream is empty, Dialogue: 0,0:15:33.96,0:15:35.39,EN,,0,0,0,,we just return the other one. Dialogue: 0,0:15:36.81,0:15:38.96,EN,,0,0,0,,Otherwise, we're going to make a new stream Dialogue: 0,0:15:39.90,0:15:42.96,EN,,0,0,0,,whose head is the sum of the two heads Dialogue: 0,0:15:44.00,0:15:44.88,EN,,0,0,0,,whose tail Dialogue: 0,0:15:46.00,0:15:48.62,EN,,0,0,0,,is the result of recursively adding the tails. Dialogue: 0,0:15:50.09,0:15:52.73,EN,,0,0,0,,So that will produce the element-wise sum of two streams. Dialogue: 0,0:15:53.15,0:15:57.04,EN,,0,0,0,,And then another useful thing to have around is scale stream. Dialogue: 0,0:15:57.50,0:16:01.66,EN,,0,0,0,,Scale stream takes some constant number in a stream s Dialogue: 0,0:16:04.11,0:16:06.62,EN,,0,0,0,,and is going to produce the stream Dialogue: 0,0:16:07.18,0:16:09.50,EN,,0,0,0,,of elements of s multiplied by this constant. Dialogue: 0,0:16:09.71,0:16:11.21,EN,,0,0,0,,And that's easy, that's just a map Dialogue: 0,0:16:12.20,0:16:16.22,EN,,0,0,0,,of the function of an element that multiplies it by the constant, Dialogue: 0,0:16:16.35,0:16:17.80,EN,,0,0,0,,and we map that down the stream. Dialogue: 0,0:16:20.06,0:16:21.47,EN,,0,0,0,,So given those two, Dialogue: 0,0:16:22.64,0:16:24.36,EN,,0,0,0,,let me show you what I mean by programs that Dialogue: 0,0:16:24.70,0:16:27.00,EN,,0,0,0,,that operate on streams all at once. Dialogue: 0,0:16:28.12,0:16:28.73,EN,,0,0,0,,Let's look at this. Dialogue: 0,0:16:30.20,0:16:30.92,EN,,0,0,0,,Suppose I write this. Dialogue: 0,0:16:31.68,0:16:52.35,EN,,0,0,0,,I say define-- I'll call it ones-- to be cons-stream of 1 onto ones. Dialogue: 0,0:16:54.86,0:16:55.52,EN,,0,0,0,,What's that? Dialogue: 0,0:16:56.95,0:16:58.94,EN,,0,0,0,,That's going to be an infinite stream of ones Dialogue: 0,0:16:59.96,0:17:01.44,EN,,0,0,0,,because the first thing is 1. Dialogue: 0,0:17:03.33,0:17:05.15,EN,,0,0,0,,And the tail of it is a thing Dialogue: 0,0:17:05.55,0:17:06.83,EN,,0,0,0,,whose first thing is 1 Dialogue: 0,0:17:07.63,0:17:09.02,EN,,0,0,0,,whose tail is a thing Dialogue: 0,0:17:09.12,0:17:10.24,EN,,0,0,0,,whose first thing is 1 Dialogue: 0,0:17:10.52,0:17:11.78,EN,,0,0,0,,and so on and so on. Dialogue: 0,0:17:11.78,0:17:13.32,EN,,0,0,0,,So that's an infinite stream of ones. Dialogue: 0,0:17:15.13,0:17:15.93,EN,,0,0,0,,And now using that, Dialogue: 0,0:17:16.12,0:17:18.03,EN,,0,0,0,,let me give you another definition of the integers. Dialogue: 0,0:17:19.47,0:17:27.36,EN,,0,0,0,,We can define the integers to be-- Dialogue: 0,0:17:28.24,0:17:30.76,EN,,0,0,0,,well, the first integer we'll take to be 1, Dialogue: 0,0:17:32.75,0:17:38.57,EN,,0,0,0,,his cons-stream of 1 onto the element-wise sum Dialogue: 0,0:17:40.22,0:17:48.27,EN,,0,0,0,,onto add streams of the integers to ones. Dialogue: 0,0:17:55.10,0:17:56.35,EN,,0,0,0,,The integers are a thing Dialogue: 0,0:17:57.24,0:17:59.98,EN,,0,0,0,,whose first element is 1, Dialogue: 0,0:18:00.88,0:18:02.32,EN,,0,0,0,,and the rest of them you get Dialogue: 0,0:18:03.12,0:18:06.14,EN,,0,0,0,,by taking those integers and incrementing each one by one. Dialogue: 0,0:18:06.64,0:18:08.19,EN,,0,0,0,,So the second element of the integers Dialogue: 0,0:18:08.51,0:18:11.96,EN,,0,0,0,,is the first element of the integers incremented by one. Dialogue: 0,0:18:13.92,0:18:15.18,EN,,0,0,0,,And the rest of that is the next one, Dialogue: 0,0:18:15.20,0:18:16.48,EN,,0,0,0,,and the third element of that Dialogue: 0,0:18:16.62,0:18:20.41,EN,,0,0,0,,is the same as the first element of the tail of the integers Dialogue: 0,0:18:20.84,0:18:21.96,EN,,0,0,0,,incremented by one, Dialogue: 0,0:18:22.51,0:18:23.76,EN,,0,0,0,,which is the same as the Dialogue: 0,0:18:25.08,0:18:28.65,EN,,0,0,0,,first element of the original integers incremented by one Dialogue: 0,0:18:28.86,0:18:31.25,EN,,0,0,0,,and incremented by one again and so on. Dialogue: 0,0:18:35.24,0:18:36.31,EN,,0,0,0,,That looks pretty suspicious. Dialogue: 0,0:18:36.31,0:18:37.47,EN,,0,0,0,,See, notice that it works Dialogue: 0,0:18:38.12,0:18:38.99,EN,,0,0,0,,because of delay. Dialogue: 0,0:18:40.15,0:18:43.32,EN,,0,0,0,,See, this looks like-- let's take a look at ones. Dialogue: 0,0:18:43.87,0:18:45.92,EN,,0,0,0,,This looks like it couldn't even be processed Dialogue: 0,0:18:46.25,0:18:47.63,EN,,0,0,0,,because it's suddenly saying Dialogue: 0,0:18:47.79,0:18:48.96,EN,,0,0,0,,in order to know what ones is, Dialogue: 0,0:18:49.00,0:18:50.91,EN,,0,0,0,,I say it's cons-stream of something onto ones. Dialogue: 0,0:18:51.13,0:18:52.08,EN,,0,0,0,,The reason that works Dialogue: 0,0:18:52.09,0:18:54.04,EN,,0,0,0,,because of that very sneaky hidden delay in there. Dialogue: 0,0:18:55.25,0:18:56.56,EN,,0,0,0,,Because what this really is, Dialogue: 0,0:18:57.79,0:18:59.69,EN,,0,0,0,,remember, cons-stream is just an abbreviation. Dialogue: 0,0:19:00.29,0:19:01.15,EN,,0,0,0,,This really is Dialogue: 0,0:19:01.85,0:19:08.99,EN,,0,0,0,,cons of 1 onto delay of ones. Dialogue: 0,0:19:12.14,0:19:13.21,EN,,0,0,0,,So how does that work? Dialogue: 0,0:19:15.50,0:19:16.88,EN,,0,0,0,,You say I'm going to define ones. Dialogue: 0,0:19:18.02,0:19:20.24,EN,,0,0,0,,First I see what ones is supposed to be defined as. Dialogue: 0,0:19:20.70,0:19:23.40,EN,,0,0,0,,Well, ones is supposed to be defined as Dialogue: 0,0:19:24.89,0:19:28.11,EN,,0,0,0,,a cons whose first part is 1 Dialogue: 0,0:19:28.32,0:19:29.45,EN,,0,0,0,,and the second part is, Dialogue: 0,0:19:29.45,0:19:30.73,EN,,0,0,0,,well, it's a promise to compute something Dialogue: 0,0:19:30.75,0:19:31.69,EN,,0,0,0,,that I don't worry about yet. Dialogue: 0,0:19:32.71,0:19:34.25,EN,,0,0,0,,So it doesn't bother me that at the point Dialogue: 0,0:19:34.28,0:19:36.30,EN,,0,0,0,,I do this definition, ones isn't defined. Dialogue: 0,0:19:37.27,0:19:39.45,EN,,0,0,0,,Having run the definition, now ones is defined. Dialogue: 0,0:19:40.67,0:19:42.83,EN,,0,0,0,,So that when I go and look at the tail of it, it's defined. Dialogue: 0,0:19:44.92,0:19:46.06,EN,,0,0,0,,It's very sneaky. Dialogue: 0,0:19:46.59,0:19:47.90,EN,,0,0,0,,And an integer is the same way. Dialogue: 0,0:19:48.47,0:19:50.46,EN,,0,0,0,,I can refer to integers here because Dialogue: 0,0:19:51.13,0:19:53.21,EN,,0,0,0,,hidden way down-- because of this cons-stream. Dialogue: 0,0:19:53.85,0:19:55.24,EN,,0,0,0,,It's the cons-stream of 1 Dialogue: 0,0:19:55.37,0:19:57.05,EN,,0,0,0,,onto something that I don't worry that yet. Dialogue: 0,0:19:57.05,0:19:59.60,EN,,0,0,0,,So I don't look at it, and I don't notice that integers isn't defined Dialogue: 0,0:20:00.22,0:20:01.90,EN,,0,0,0,,at the point where I try and run the definition. Dialogue: 0,0:20:06.32,0:20:08.27,EN,,0,0,0,,OK, let me draw a picture of that integers thing Dialogue: 0,0:20:08.44,0:20:11.50,EN,,0,0,0,,because it still maybe seems a little bit shaky. Dialogue: 0,0:20:12.43,0:20:14.72,EN,,0,0,0,,What do I do? Uh... Dialogue: 0,0:20:15.02,0:20:16.30,EN,,0,0,0,,I've got the stream of ones, Dialogue: 0,0:20:20.51,0:20:21.88,EN,,0,0,0,,and that sort of comes in Dialogue: 0,0:20:23.26,0:20:24.92,EN,,0,0,0,,comes in and goes into an adder Dialogue: 0,0:20:24.96,0:20:26.59,EN,,0,0,0,,that's going to be this add streams thing. Dialogue: 0,0:20:29.31,0:20:35.87,EN,,0,0,0,,And that goes in-- that's going to put out the integers. Dialogue: 0,0:20:40.76,0:20:42.70,EN,,0,0,0,,And the other thing that goes into the adder here Dialogue: 0,0:20:44.94,0:20:46.97,EN,,0,0,0,,is the integer, so there's a little feedback loop. Dialogue: 0,0:20:48.06,0:20:49.42,EN,,0,0,0,,And all I need to start it off Dialogue: 0,0:20:50.09,0:20:52.88,EN,,0,0,0,,is someplace I've got a stick that initial 1. Dialogue: 0,0:20:57.10,0:20:58.64,EN,,0,0,0,,In a real signal processing thing, Dialogue: 0,0:20:58.72,0:21:02.48,EN,,0,0,0,,this might be a delay element with that was initialized to 1. Dialogue: 0,0:21:02.91,0:21:05.90,EN,,0,0,0,,But there's a picture of that ones program. Dialogue: 0,0:21:07.86,0:21:09.63,EN,,0,0,0,,And in fact, that looks a lot like-- Dialogue: 0,0:21:09.80,0:21:13.77,EN,,0,0,0,,if you've seen real signal block diagram things, Dialogue: 0,0:21:13.77,0:21:16.30,EN,,0,0,0,,that looks a lot like accumulators, Dialogue: 0,0:21:16.35,0:21:17.48,EN,,0,0,0,,finite state accumulators. Dialogue: 0,0:21:17.98,0:21:20.06,EN,,0,0,0,,And in fact, we can modify this a little bit Dialogue: 0,0:21:21.18,0:21:23.96,EN,,0,0,0,,to change this into something that integrates a stream Dialogue: 0,0:21:25.37,0:21:26.97,EN,,0,0,0,,or a finite state accumulator, Dialogue: 0,0:21:27.00,0:21:28.04,EN,,0,0,0,,however you like to think about it. Dialogue: 0,0:21:28.44,0:21:30.86,EN,,0,0,0,,So instead of the ones coming in and getting out the integers, Dialogue: 0,0:21:31.68,0:21:32.38,EN,,0,0,0,,what we'll do is Dialogue: 0,0:21:32.91,0:21:34.83,EN,,0,0,0,,say there's a stream s coming in, Dialogue: 0,0:21:35.76,0:21:40.56,EN,,0,0,0,,and we're going to get out the integral of this. Dialogue: 0,0:21:42.60,0:21:44.09,EN,,0,0,0,,successive values of that, Dialogue: 0,0:21:44.44,0:21:45.63,EN,,0,0,0,,and it looks almost the same. Dialogue: 0,0:21:45.66,0:21:46.84,EN,,0,0,0,,The only thing we're going to do is Dialogue: 0,0:21:47.02,0:21:48.08,EN,,0,0,0,,when s comes in here, Dialogue: 0,0:21:49.21,0:21:50.64,EN,,0,0,0,,before we just add it in Dialogue: 0,0:21:50.91,0:21:54.26,EN,,0,0,0,,we're going to multiply it by some number dt. Dialogue: 0,0:21:57.68,0:22:00.00,EN,,0,0,0,,And now what we have here, this is exactly the same thing. Dialogue: 0,0:22:00.00,0:22:00.91,EN,,0,0,0,,We have a box, Dialogue: 0,0:22:03.36,0:22:04.56,EN,,0,0,0,,which is an integrator. Dialogue: 0,0:22:09.79,0:22:11.26,EN,,0,0,0,,And it takes in a stream s, Dialogue: 0,0:22:11.90,0:22:14.51,EN,,0,0,0,,and instead of 1 here, Dialogue: 0,0:22:14.94,0:22:18.35,EN,,0,0,0,,we can put the additional value for the integral. Dialogue: 0,0:22:19.98,0:22:21.60,EN,,0,0,0,,And that one looks very much like a Dialogue: 0,0:22:22.35,0:22:24.86,EN,,0,0,0,,a signal processing block diagram program. Dialogue: 0,0:22:25.27,0:22:28.11,EN,,0,0,0,,In fact, here's the procedure that looks exactly like that. Dialogue: 0,0:22:31.49,0:22:33.61,EN,,0,0,0,,Find the integral of a stream. Dialogue: 0,0:22:34.01,0:22:35.48,EN,,0,0,0,,So an integral's going to take a stream Dialogue: 0,0:22:35.68,0:22:36.86,EN,,0,0,0,,Sand produce a new stream, Dialogue: 0,0:22:37.53,0:22:40.67,EN,,0,0,0,,and it takes in an initial value and some time constant. Dialogue: 0,0:22:42.23,0:22:42.97,EN,,0,0,0,,And what do we do? Dialogue: 0,0:22:43.04,0:22:45.05,EN,,0,0,0,,Well, we internally define this thing int, Dialogue: 0,0:22:45.20,0:22:46.32,EN,,0,0,0,,and we make this internal name Dialogue: 0,0:22:46.33,0:22:48.86,EN,,0,0,0,,so we can feed it back, loop it around itself. Dialogue: 0,0:22:49.40,0:22:50.80,EN,,0,0,0,,And int is defined to be Dialogue: 0,0:22:51.10,0:22:53.32,EN,,0,0,0,,something that starts out at the initial value, Dialogue: 0,0:22:54.97,0:23:00.14,EN,,0,0,0,,and the rest of it is gotten by adding together. Dialogue: 0,0:23:01.28,0:23:03.61,EN,,0,0,0,,We take our input stream, scale it by dt, Dialogue: 0,0:23:03.87,0:23:04.92,EN,,0,0,0,,and add that to int. Dialogue: 0,0:23:06.88,0:23:09.66,EN,,0,0,0,,And now we'll return from all that the value of integral is this thing int. Dialogue: 0,0:23:10.69,0:23:12.94,EN,,0,0,0,,And we use this internal definition syntax so we could Dialogue: 0,0:23:13.34,0:23:15.66,EN,,0,0,0,,write a little internal definition that refers to itself. Dialogue: 0,0:23:21.88,0:23:23.71,EN,,0,0,0,,Well, there are all sorts of things we can do. Dialogue: 0,0:23:23.71,0:23:24.51,EN,,0,0,0,,Let's try this one. Dialogue: 0,0:23:25.63,0:23:26.89,EN,,0,0,0,,how about the Fibonacci numbers. Dialogue: 0,0:23:26.89,0:23:32.62,EN,,0,0,0,,You can say define fibs. Dialogue: 0,0:23:36.35,0:23:37.63,EN,,0,0,0,,Well, what are the Fibonacci numbers? Dialogue: 0,0:23:37.98,0:23:46.54,EN,,0,0,0,,They're something that starts out with 0, Dialogue: 0,0:23:48.65,0:23:50.09,EN,,0,0,0,,and the next one is 1. Dialogue: 0,0:23:56.26,0:23:59.16,EN,,0,0,0,,And the rest of the Fibonacci numbers are gotten by Dialogue: 0,0:23:59.87,0:24:11.00,EN,,0,0,0,,adding the Fibonacci numbers to their own tail. Dialogue: 0,0:24:17.57,0:24:19.28,EN,,0,0,0,,There's a definition of the Fibonacci numbers. Dialogue: 0,0:24:20.58,0:24:21.43,EN,,0,0,0,,How does that work? Dialogue: 0,0:24:21.43,0:24:24.19,EN,,0,0,0,,Well, we start off, Dialogue: 0,0:24:24.20,0:24:26.49,EN,,0,0,0,,and someone says compute for us the Fibonacci numbers, Dialogue: 0,0:24:29.64,0:24:31.92,EN,,0,0,0,,and we're going to tell you it starts out with 0 and 1. Dialogue: 0,0:24:35.79,0:24:38.22,EN,,0,0,0,,And everything after the 0 and 1 Dialogue: 0,0:24:39.18,0:24:40.86,EN,,0,0,0,,is gotten by summing two streams. Dialogue: 0,0:24:41.12,0:24:42.59,EN,,0,0,0,,One is the fibs themselves, Dialogue: 0,0:24:44.06,0:24:45.69,EN,,0,0,0,,and the other one is the tail of the fibs. Dialogue: 0,0:24:49.12,0:24:51.16,EN,,0,0,0,,So if I know that these start out with 0 and 1, Dialogue: 0,0:24:51.79,0:24:55.42,EN,,0,0,0,,I know that the fibs now start out with 0 and 1, Dialogue: 0,0:24:55.74,0:24:57.40,EN,,0,0,0,,and the tail of the fibs start out with 1. Dialogue: 0,0:24:58.36,0:24:59.45,EN,,0,0,0,,So as soon as I know that, Dialogue: 0,0:24:59.66,0:25:02.11,EN,,0,0,0,,I know that the next one here is 0 plus 1 is 1, Dialogue: 0,0:25:02.96,0:25:04.60,EN,,0,0,0,,and that tells me that the next one here is 1 Dialogue: 0,0:25:04.62,0:25:05.72,EN,,0,0,0,,and the next one here is 1. Dialogue: 0,0:25:06.30,0:25:07.28,EN,,0,0,0,,And as soon as I know that, Dialogue: 0,0:25:07.29,0:25:08.76,EN,,0,0,0,,I know that the next one is 2. Dialogue: 0,0:25:09.39,0:25:11.70,EN,,0,0,0,,So the next one here is 2 and the next one here is 2. Dialogue: 0,0:25:11.70,0:25:12.56,EN,,0,0,0,,And this is 3. Dialogue: 0,0:25:14.72,0:25:15.79,EN,,0,0,0,,This one goes to 3, Dialogue: 0,0:25:16.19,0:25:17.13,EN,,0,0,0,,and this is 5. Dialogue: 0,0:25:18.67,0:25:19.96,EN,,0,0,0,,So it's a perfectly sensible definition. Dialogue: 0,0:25:21.50,0:25:22.78,EN,,0,0,0,,It's a one-line definition. Dialogue: 0,0:25:22.83,0:25:25.00,EN,,0,0,0,,And again, I could walk over to the computer Dialogue: 0,0:25:25.00,0:25:26.62,EN,,0,0,0,,and type that in, exactly that, Dialogue: 0,0:25:27.04,0:25:28.94,EN,,0,0,0,,and then say print stream the Fibonacci numbers, Dialogue: 0,0:25:28.94,0:25:30.15,EN,,0,0,0,,and they all come flying out. Dialogue: 0,0:25:32.79,0:25:35.20,EN,,0,0,0,,See, this is a lot like learning about recursion again. Dialogue: 0,0:25:36.81,0:25:39.79,EN,,0,0,0,,Instead of thinking that recursive procedures, Dialogue: 0,0:25:40.99,0:25:43.50,EN,,0,0,0,,we have recursively defined data objects. Dialogue: 0,0:25:45.16,0:25:46.92,EN,,0,0,0,,But that shouldn't surprise you at all, Dialogue: 0,0:25:47.12,0:25:49.50,EN,,0,0,0,,because by now, you should be coming to really believe Dialogue: 0,0:25:49.52,0:25:53.05,EN,,0,0,0,,that there's no difference really between procedures and data. Dialogue: 0,0:25:53.09,0:25:53.92,EN,,0,0,0,,In fact, in some sense, Dialogue: 0,0:25:53.93,0:25:56.41,EN,,0,0,0,,the underlying streams are procedures sitting there, Dialogue: 0,0:25:56.43,0:25:57.79,EN,,0,0,0,,although we don't think of them that way. Dialogue: 0,0:25:58.21,0:26:00.38,EN,,0,0,0,,So the fact that we have recursive procedures, Dialogue: 0,0:26:00.70,0:26:03.63,EN,,0,0,0,,well, then it should be natural that we have recursive data, too. Dialogue: 0,0:26:07.72,0:26:09.69,EN,,0,0,0,,OK, well, this is all pretty neat. Dialogue: 0,0:26:09.72,0:26:13.92,EN,,0,0,0,,Unfortunately, there are problems that streams aren't going to solve. Dialogue: 0,0:26:14.99,0:26:16.48,EN,,0,0,0,,Let me show you one of them. Dialogue: 0,0:26:17.58,0:26:20.35,EN,,0,0,0,,See, in the same way, let's imagine that we're Dialogue: 0,0:26:20.76,0:26:23.61,EN,,0,0,0,,building an analog computer to solve some differential equation Dialogue: 0,0:26:25.20,0:26:34.30,EN,,0,0,0,,like, say, we want to solve the equation y prime dy dt is y squared, Dialogue: 0,0:26:34.76,0:26:36.16,EN,,0,0,0,,and I'm going to give you some initial value. Dialogue: 0,0:26:36.39,0:26:38.03,EN,,0,0,0,,I'll tell you y of 0 equals 1. Dialogue: 0,0:26:41.48,0:26:44.06,EN,,0,0,0,,Let's say dt is equal to something. Dialogue: 0,0:26:46.77,0:26:47.53,EN,,0,0,0,,Now, in the old days, Dialogue: 0,0:26:48.00,0:26:50.65,EN,,0,0,0,,people built analog computers to solve these kinds of things. Dialogue: 0,0:26:51.36,0:26:53.02,EN,,0,0,0,,And the way you do that is really simple. Dialogue: 0,0:26:53.02,0:26:54.41,EN,,0,0,0,,You get yourself an integrator, Dialogue: 0,0:27:00.04,0:27:01.69,EN,,0,0,0,,like that one, an integrator box. Dialogue: 0,0:27:03.05,0:27:06.48,EN,,0,0,0,,And we put in the initial value y of 0 is 1. Dialogue: 0,0:27:08.53,0:27:10.92,EN,,0,0,0,,And now if we feed something in and get something out, Dialogue: 0,0:27:10.96,0:27:13.16,EN,,0,0,0,,we'll say, gee, what we're getting out is the answer. Dialogue: 0,0:27:14.25,0:27:16.96,EN,,0,0,0,,And what we're going to feed in is the derivative, Dialogue: 0,0:27:17.52,0:27:20.52,EN,,0,0,0,,and the derivative is supposed to be the square of the answer. Dialogue: 0,0:27:21.49,0:27:27.07,EN,,0,0,0,,So if we take these values and map using square, Dialogue: 0,0:27:30.73,0:27:32.09,EN,,0,0,0,,and if I feed this around, Dialogue: 0,0:27:36.28,0:27:38.48,EN,,0,0,0,,that's how I build a block diagram Dialogue: 0,0:27:38.57,0:27:41.08,EN,,0,0,0,,for an analog computer that solves this differential equation. Dialogue: 0,0:27:42.91,0:27:44.80,EN,,0,0,0,,Now, what we'd like to do is write a stream Dialogue: 0,0:27:44.80,0:27:46.78,EN,,0,0,0,,program that looks exactly like that. Dialogue: 0,0:27:47.23,0:27:48.72,EN,,0,0,0,,And what do I mean exactly like that? Dialogue: 0,0:27:49.39,0:27:58.30,EN,,0,0,0,,Well, I'd say define y to be the integral Dialogue: 0,0:28:04.28,0:28:11.68,EN,,0,0,0,,of dy starting at 1 with 0.001 as a time step. Dialogue: 0,0:28:13.79,0:28:15.45,EN,,0,0,0,,And I'd like to say that says this. Dialogue: 0,0:28:16.80,0:28:20.85,EN,,0,0,0,,And then I'd like to say, well, dy is gotten by mapping the square along y. Dialogue: 0,0:28:20.85,0:28:32.81,EN,,0,0,0,,So define dy to be map square along y. Dialogue: 0,0:28:33.51,0:28:36.80,EN,,0,0,0,,So there's a stream description of this analog computer, Dialogue: 0,0:28:38.62,0:28:40.32,EN,,0,0,0,,and unfortunately, it doesn't work. Dialogue: 0,0:28:41.41,0:28:42.67,EN,,0,0,0,,And you can see why it doesn't work Dialogue: 0,0:28:42.97,0:28:44.99,EN,,0,0,0,,because when I come in and say define y Dialogue: 0,0:28:46.43,0:28:47.85,EN,,0,0,0,,to be the integral of dy Dialogue: 0,0:28:49.04,0:28:50.65,EN,,0,0,0,,it says, oh, the integral of what-- huh? Dialogue: 0,0:28:51.19,0:28:52.12,EN,,0,0,0,,Oh, that's undefined. Dialogue: 0,0:28:53.71,0:28:57.63,EN,,0,0,0,,So I can't write this definition before I've written this one. Dialogue: 0,0:28:58.77,0:29:00.51,EN,,0,0,0,,On the other hand, if I try and write this one first, Dialogue: 0,0:29:00.51,0:29:03.02,EN,,0,0,0,,it says, oh, I define y to be the map of square along what? Dialogue: 0,0:29:03.58,0:29:04.64,EN,,0,0,0,,Oh, that's not defined yet. Dialogue: 0,0:29:05.77,0:29:08.17,EN,,0,0,0,,So I can't write this one first, and I can't write that one first. Dialogue: 0,0:29:09.08,0:29:11.58,EN,,0,0,0,,So I can't quite play this game. Dialogue: 0,0:29:17.56,0:29:18.51,EN,,0,0,0,,Well, is there a way out? Dialogue: 0,0:29:20.60,0:29:21.84,EN,,0,0,0,,See, we can do that with ones. Dialogue: 0,0:29:22.20,0:29:25.82,EN,,0,0,0,,See, over here, we did this thing ones, Dialogue: 0,0:29:27.24,0:29:29.90,EN,,0,0,0,,and we were able to define ones in terms of ones because Dialogue: 0,0:29:30.40,0:29:32.03,EN,,0,0,0,,of this delay that was built inside Dialogue: 0,0:29:32.43,0:29:34.12,EN,,0,0,0,,because cons-stream had a delay. Dialogue: 0,0:29:34.77,0:29:35.79,EN,,0,0,0,,Now, why's it sensible? Dialogue: 0,0:29:35.92,0:29:38.51,EN,,0,0,0,,Why's it sensible for cons-stream to be built with this delay? Dialogue: 0,0:29:40.73,0:29:43.13,EN,,0,0,0,,The reason is that cons-stream can do a useful thing Dialogue: 0,0:29:43.48,0:29:44.88,EN,,0,0,0,,without looking at its tail. Dialogue: 0,0:29:45.95,0:29:46.84,EN,,0,0,0,,See, if I say Dialogue: 0,0:29:47.48,0:29:49.64,EN,,0,0,0,,this is cons-stream of 1 onto something Dialogue: 0,0:29:49.92,0:29:51.69,EN,,0,0,0,,without knowing anything about something, Dialogue: 0,0:29:52.16,0:29:54.03,EN,,0,0,0,,I know that the stream starts off with 1. Dialogue: 0,0:29:54.87,0:29:57.29,EN,,0,0,0,,That's why it was sensible to build something like cons-stream. Dialogue: 0,0:29:59.96,0:30:01.24,EN,,0,0,0,,So we put a delay in there, Dialogue: 0,0:30:01.42,0:30:04.65,EN,,0,0,0,,and that allows us to have this sort of self-referential definition. Dialogue: 0,0:30:06.32,0:30:07.95,EN,,0,0,0,,Well, integral is a little bit the same way. Dialogue: 0,0:30:08.19,0:30:12.52,EN,,0,0,0,,See, notice for an integral, I can-- Dialogue: 0,0:30:14.60,0:30:16.08,EN,,0,0,0,,let's go back and look at integral for a second. Dialogue: 0,0:30:17.58,0:30:18.56,EN,,0,0,0,,See, notice integral, Dialogue: 0,0:30:21.39,0:30:25.00,EN,,0,0,0,,it makes sense to say what's the first thing in the integral Dialogue: 0,0:30:26.04,0:30:27.87,EN,,0,0,0,,without knowing the stream that you're integrating. Dialogue: 0,0:30:28.97,0:30:30.17,EN,,0,0,0,,Because the first thing in the integral Dialogue: 0,0:30:30.20,0:30:32.16,EN,,0,0,0,,is always going to be the initial value that you're handed. Dialogue: 0,0:30:33.14,0:30:36.11,EN,,0,0,0,,So integral could be a procedure like cons-stream. Dialogue: 0,0:30:37.09,0:30:37.98,EN,,0,0,0,,You could define it, Dialogue: 0,0:30:38.25,0:30:40.88,EN,,0,0,0,,and then even before it knows what it's supposed to be integrating, Dialogue: 0,0:30:42.84,0:30:45.18,EN,,0,0,0,,it knows enough to say what its initial value is. Dialogue: 0,0:30:46.71,0:30:48.17,EN,,0,0,0,,So we can make a smarter integral, Dialogue: 0,0:30:48.41,0:30:50.68,EN,,0,0,0,,which is aha, you're going to give me a stream to integrate Dialogue: 0,0:30:50.83,0:30:51.92,EN,,0,0,0,,and an initial value, Dialogue: 0,0:30:52.11,0:30:54.99,EN,,0,0,0,,but I really don't have to look at that stream that I'm supposed to integrate Dialogue: 0,0:30:55.21,0:30:56.97,EN,,0,0,0,,until you ask me to work down the stream. Dialogue: 0,0:30:58.43,0:31:00.51,EN,,0,0,0,,In other words, integral can be like cons-stream, Dialogue: 0,0:31:00.57,0:31:03.74,EN,,0,0,0,,and you can expect that there's going to be a delay around its integrand. Dialogue: 0,0:31:03.76,0:31:04.86,EN,,0,0,0,,And we can write that. Dialogue: 0,0:31:05.61,0:31:07.02,EN,,0,0,0,,Here's a procedure that does that. Dialogue: 0,0:31:07.65,0:31:08.75,EN,,0,0,0,,Another version of integral, Dialogue: 0,0:31:08.89,0:31:10.54,EN,,0,0,0,,and this is almost like the previous one, Dialogue: 0,0:31:11.10,0:31:13.34,EN,,0,0,0,,except the stream it's going to get in Dialogue: 0,0:31:13.77,0:31:15.69,EN,,0,0,0,,is going to expect to be a delayed object. Dialogue: 0,0:31:17.11,0:31:18.43,EN,,0,0,0,,And how does this integral work? Dialogue: 0,0:31:18.85,0:31:21.79,EN,,0,0,0,,Well, the little thing it's going to define inside of itself Dialogue: 0,0:31:22.14,0:31:24.19,EN,,0,0,0,,says on the cons-stream, Dialogue: 0,0:31:24.73,0:31:26.44,EN,,0,0,0,,the initial value is the initial value, Dialogue: 0,0:31:27.16,0:31:29.68,EN,,0,0,0,,but only inside of that cons-stream, Dialogue: 0,0:31:29.74,0:31:32.30,EN,,0,0,0,,and remember, there's going to be a hidden delay inside here. Dialogue: 0,0:31:34.95,0:31:39.07,EN,,0,0,0,,Only inside of that cons-stream will I start looking at Dialogue: 0,0:31:39.82,0:31:42.11,EN,,0,0,0,,what the actual delayed object is. Dialogue: 0,0:31:43.18,0:31:45.79,EN,,0,0,0,,So my answer is the first thing's the initial value. Dialogue: 0,0:31:45.97,0:31:47.90,EN,,0,0,0,,If anybody now asks me for my tail, Dialogue: 0,0:31:48.40,0:31:49.42,EN,,0,0,0,,at that point, Dialogue: 0,0:31:50.00,0:31:51.72,EN,,0,0,0,,I'm going to force that delayed object-- Dialogue: 0,0:31:52.62,0:31:53.60,EN,,0,0,0,,and I'll call that s-- Dialogue: 0,0:31:54.44,0:31:55.60,EN,,0,0,0,,and I do the add streams. Dialogue: 0,0:31:56.36,0:31:59.26,EN,,0,0,0,,So this is an integral which is sort of like cons-stream. Dialogue: 0,0:31:59.26,0:32:02.59,EN,,0,0,0,,It's not going to actually try and see what you handed it Dialogue: 0,0:32:03.88,0:32:07.13,EN,,0,0,0,,as the thing to integrate until you look past the first element. Dialogue: 0,0:32:10.12,0:32:11.02,EN,,0,0,0,,And if we do that Dialogue: 0,0:32:11.52,0:32:12.83,EN,,0,0,0,,and we can make this work, Dialogue: 0,0:32:13.36,0:32:15.20,EN,,0,0,0,,all we have to do here is Dialogue: 0,0:32:16.00,0:32:25.31,EN,,0,0,0,,define y to the integral of delay of y, of delay of dy. Dialogue: 0,0:32:27.09,0:32:28.22,EN,,0,0,0,,So y is going to be Dialogue: 0,0:32:28.40,0:32:34.36,EN,,0,0,0,,the integral of delay of dy starting at 1, Dialogue: 0,0:32:34.38,0:32:35.13,EN,,0,0,0,,and now this will work. Dialogue: 0,0:32:35.28,0:32:37.44,EN,,0,0,0,,Because I type in the definition of y, Dialogue: 0,0:32:38.00,0:32:39.68,EN,,0,0,0,,and that says, oh, I'm supposed to use the integral of Dialogue: 0,0:32:40.20,0:32:42.68,EN,,0,0,0,,something I don't care about right now because it's a delay. Dialogue: 0,0:32:44.60,0:32:46.32,EN,,0,0,0,,And these things, now you define dy. Dialogue: 0,0:32:46.32,0:32:47.37,EN,,0,0,0,,Now, y is defined. Dialogue: 0,0:32:47.55,0:32:48.89,EN,,0,0,0,,So when I define dy, Dialogue: 0,0:32:49.13,0:32:50.67,EN,,0,0,0,,it can see that definition for y. Dialogue: 0,0:32:51.70,0:32:52.84,EN,,0,0,0,,Everything is now started up. Dialogue: 0,0:32:52.84,0:32:54.33,EN,,0,0,0,,Both streams have their first element. Dialogue: 0,0:32:54.92,0:32:56.25,EN,,0,0,0,,And then when I start mapping down, Dialogue: 0,0:32:56.27,0:32:57.31,EN,,0,0,0,,looking at successive elements, Dialogue: 0,0:32:57.37,0:32:58.88,EN,,0,0,0,,both y and dy are defined. Dialogue: 0,0:33:00.59,0:33:04.24,EN,,0,0,0,,So there's a little game you can play that goes a little bit beyond Dialogue: 0,0:33:04.67,0:33:07.13,EN,,0,0,0,,just using the delay that's hidden inside streams. Dialogue: 0,0:33:08.36,0:33:08.97,EN,,0,0,0,,Questions? Dialogue: 0,0:33:13.52,0:33:14.27,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:34:07.30,0:34:10.04,EN,,0,0,0,,Well, just before the break, um.. Dialogue: 0,0:34:10.89,0:34:11.80,EN,,0,0,0,,I'm not sure if you noticed it, Dialogue: 0,0:34:11.82,0:34:13.55,EN,,0,0,0,,but something nasty started to happen. Dialogue: 0,0:34:14.83,0:34:18.40,EN,,0,0,0,,We've been going along with the streams Dialogue: 0,0:34:19.16,0:34:22.68,EN,,0,0,0,,and divorcing time in the programs from time in the computers, Dialogue: 0,0:34:22.86,0:34:26.28,EN,,0,0,0,,and all that divorcing got hidden inside the streams. Dialogue: 0,0:34:27.28,0:34:29.50,EN,,0,0,0,,And then at the very end, we saw that sometimes Dialogue: 0,0:34:29.71,0:34:32.19,EN,,0,0,0,,in order to really take advantage of this method, Dialogue: 0,0:34:32.22,0:34:34.38,EN,,0,0,0,,you have to pull out other delays. Dialogue: 0,0:34:34.38,0:34:35.85,EN,,0,0,0,,You have to write some explicit delays Dialogue: 0,0:34:36.09,0:34:37.95,EN,,0,0,0,,that are not hidden inside that cons-stream. Dialogue: 0,0:34:39.03,0:34:41.88,EN,,0,0,0,,And I did a very simple example with differential equations, Dialogue: 0,0:34:42.35,0:34:44.08,EN,,0,0,0,,but if you have some very complicated system Dialogue: 0,0:34:44.12,0:34:45.40,EN,,0,0,0,,with all kinds of self-loops, Dialogue: 0,0:34:45.95,0:34:47.84,EN,,0,0,0,,it becomes very, very difficult to Dialogue: 0,0:34:47.90,0:34:49.31,EN,,0,0,0,,see where you need those delays. Dialogue: 0,0:34:49.92,0:34:51.18,EN,,0,0,0,,And if you leave them out by mistake, Dialogue: 0,0:34:51.45,0:34:54.36,EN,,0,0,0,,it becomes very, very difficult to see why the thing maybe isn't working. Dialogue: 0,0:34:55.55,0:34:57.15,EN,,0,0,0,,So that's kind of mess, Dialogue: 0,0:34:57.79,0:35:01.71,EN,,0,0,0,,that by getting this power and allowing us to use delay, Dialogue: 0,0:35:02.08,0:35:04.70,EN,,0,0,0,,we end up with some very complicated programming sometimes, Dialogue: 0,0:35:04.72,0:35:06.80,EN,,0,0,0,,because it can't all be hidden inside the streams. Dialogue: 0,0:35:08.51,0:35:09.79,EN,,0,0,0,,Well, is there a way out of that? Dialogue: 0,0:35:11.13,0:35:12.67,EN,,0,0,0,,Yeah, there is a way out of that. Dialogue: 0,0:35:13.48,0:35:16.08,EN,,0,0,0,,We could change the language so that Dialogue: 0,0:35:16.14,0:35:18.19,EN,,0,0,0,,all procedures acted like cons-stream, Dialogue: 0,0:35:19.10,0:35:21.48,EN,,0,0,0,,so that every procedure automatically Dialogue: 0,0:35:22.32,0:35:25.45,EN,,0,0,0,,has an implicit delay around its arguments. Dialogue: 0,0:35:25.45,0:35:26.43,EN,,0,0,0,,And what would that mean? Dialogue: 0,0:35:27.52,0:35:29.53,EN,,0,0,0,,That would mean when you call a procedure, Dialogue: 0,0:35:30.16,0:35:31.88,EN,,0,0,0,,the arguments wouldn't get evaluated. Dialogue: 0,0:35:32.21,0:35:34.70,EN,,0,0,0,,Instead, they'd only be evaluated when you need them, Dialogue: 0,0:35:34.89,0:35:36.72,EN,,0,0,0,,so they might be passed off to some other procedure, Dialogue: 0,0:35:36.76,0:35:38.12,EN,,0,0,0,,which wouldn't evaluate them either. Dialogue: 0,0:35:39.26,0:35:41.90,EN,,0,0,0,,So all these procedures would be passing promises around. Dialogue: 0,0:35:42.15,0:35:44.46,EN,,0,0,0,,And then finally maybe when you finally got down Dialogue: 0,0:35:44.65,0:35:47.34,EN,,0,0,0,,to having to look at the value of something Dialogue: 0,0:35:47.36,0:35:48.99,EN,,0,0,0,,that was handed to a primitive operator Dialogue: 0,0:35:49.37,0:35:51.48,EN,,0,0,0,,which you actually start calling in all those promises. Dialogue: 0,0:35:52.38,0:35:53.16,EN,,0,0,0,,If we did that, Dialogue: 0,0:35:53.36,0:35:55.37,EN,,0,0,0,,since everything would have a uniform delay, Dialogue: 0,0:35:57.16,0:35:59.00,EN,,0,0,0,,then you wouldn't have to write any explicit delays, Dialogue: 0,0:35:59.04,0:36:01.55,EN,,0,0,0,,because it would be automatically built into the way the language works. Dialogue: 0,0:36:03.24,0:36:04.38,EN,,0,0,0,,Or another way to say that, Dialogue: 0,0:36:05.10,0:36:08.14,EN,,0,0,0,,technically what I'm describing is what's called Dialogue: 0,0:36:09.02,0:36:10.76,EN,,0,0,0,,if we did that, our language would be Dialogue: 0,0:36:12.19,0:36:16.57,EN,,0,0,0,,so-called normal-order evaluation language Dialogue: 0,0:36:20.20,0:36:23.47,EN,,0,0,0,,versus what we've actually been working with, Dialogue: 0,0:36:23.87,0:36:33.79,EN,,0,0,0,,which is called applicative order-- versus applicative-order evaluation. Dialogue: 0,0:36:34.56,0:36:36.83,EN,,0,0,0,,And remember the substitution model for applicative order. Dialogue: 0,0:36:36.83,0:36:40.49,EN,,0,0,0,,It says when you go and evaluate a combination, Dialogue: 0,0:36:40.51,0:36:42.11,EN,,0,0,0,,you find the values of all the pieces. Dialogue: 0,0:36:43.59,0:36:45.40,EN,,0,0,0,,You evaluate the arguments and then you Dialogue: 0,0:36:45.72,0:36:47.42,EN,,0,0,0,,substitute them in the body of the procedure. Dialogue: 0,0:36:47.60,0:36:49.55,EN,,0,0,0,,Normal order says no, don't do that. Dialogue: 0,0:36:49.89,0:36:51.90,EN,,0,0,0,,What you do is effectively Dialogue: 0,0:36:52.76,0:36:54.41,EN,,0,0,0,,substitute in the body of the procedure, Dialogue: 0,0:36:54.44,0:36:56.19,EN,,0,0,0,,but instead of evaluating the arguments, Dialogue: 0,0:36:56.54,0:36:58.08,EN,,0,0,0,,you just put a promise to compute them there. Dialogue: 0,0:36:58.81,0:36:59.90,EN,,0,0,0,,Or another way to say that Dialogue: 0,0:36:59.92,0:37:02.09,EN,,0,0,0,,you take the expressions for the arguments, if you like, Dialogue: 0,0:37:02.28,0:37:04.84,EN,,0,0,0,,and substitute them in the body of the procedure and go on, Dialogue: 0,0:37:05.16,0:37:06.88,EN,,0,0,0,,and never really simplify anything Dialogue: 0,0:37:07.16,0:37:08.76,EN,,0,0,0,,until you get down to a primitive operator. Dialogue: 0,0:37:09.47,0:37:10.99,EN,,0,0,0,,So that would be a normal-order language. Dialogue: 0,0:37:12.17,0:37:13.12,EN,,0,0,0,,Well, why don't we do that? Dialogue: 0,0:37:13.82,0:37:14.60,EN,,0,0,0,,Because if we did, Dialogue: 0,0:37:15.00,0:37:17.34,EN,,0,0,0,,we'd get all the advantages of delayed evaluation Dialogue: 0,0:37:17.90,0:37:18.80,EN,,0,0,0,,with none of the mess. Dialogue: 0,0:37:18.94,0:37:20.19,EN,,0,0,0,,In fact, if we did that Dialogue: 0,0:37:20.43,0:37:22.67,EN,,0,0,0,,and cons was just a delayed procedure, Dialogue: 0,0:37:22.68,0:37:24.57,EN,,0,0,0,,that would make cons the same as cons-stream. Dialogue: 0,0:37:24.71,0:37:25.82,EN,,0,0,0,,We wouldn't need streams at all Dialogue: 0,0:37:26.36,0:37:28.54,EN,,0,0,0,,because lists would automatically be streams. Dialogue: 0,0:37:29.55,0:37:30.70,EN,,0,0,0,,That's how lists would behave, Dialogue: 0,0:37:30.75,0:37:32.35,EN,,0,0,0,,all data structures would behave that way. Dialogue: 0,0:37:32.35,0:37:33.64,EN,,0,0,0,,Everything would behave that way. Dialogue: 0,0:37:35.07,0:37:37.63,EN,,0,0,0,,Right, You'd never really do any computation Dialogue: 0,0:37:37.66,0:37:39.42,EN,,0,0,0,,until you actually needed the answer. Dialogue: 0,0:37:40.80,0:37:43.58,EN,,0,0,0,,You wouldn't have to worry about all these explicit annoying delays. Dialogue: 0,0:37:44.79,0:37:46.16,EN,,0,0,0,,Well, why don't we do that? Dialogue: 0,0:37:47.16,0:37:48.81,EN,,0,0,0,,First of all, I should say people do do that. Dialogue: 0,0:37:49.23,0:37:51.85,EN,,0,0,0,,There's some very beautiful languages. Dialogue: 0,0:37:51.85,0:37:55.21,EN,,0,0,0,,One of the very nicest is a language called Miranda, Dialogue: 0,0:37:55.77,0:37:56.76,EN,,0,0,0,,which is, um.. Dialogue: 0,0:37:57.44,0:37:59.80,EN,,0,0,0,,developed by David Turner at the University of Kent. Dialogue: 0,0:38:00.71,0:38:01.93,EN,,0,0,0,,And that's how this language works. Dialogue: 0,0:38:01.93,0:38:03.34,EN,,0,0,0,,It's a normal-order language Dialogue: 0,0:38:04.27,0:38:05.55,EN,,0,0,0,,and its data structures, Dialogue: 0,0:38:06.16,0:38:08.41,EN,,0,0,0,,which look like lists, are actually streams. Dialogue: 0,0:38:08.96,0:38:10.91,EN,,0,0,0,,And you write ordinary procedures in Miranda, Dialogue: 0,0:38:11.28,0:38:13.28,EN,,0,0,0,,and they do these prime things and eight queens things, Dialogue: 0,0:38:13.32,0:38:14.97,EN,,0,0,0,,just without anything special. Dialogue: 0,0:38:14.97,0:38:16.35,EN,,0,0,0,,It's all built in there. Dialogue: 0,0:38:17.93,0:38:18.91,EN,,0,0,0,,But there's a price. Dialogue: 0,0:38:21.19,0:38:22.36,EN,,0,0,0,,Remember how we got here. Dialogue: 0,0:38:23.17,0:38:27.48,EN,,0,0,0,,We're decoupling time in the programs from time in the machines. Dialogue: 0,0:38:27.96,0:38:28.88,EN,,0,0,0,,And if we put delay, Dialogue: 0,0:38:29.04,0:38:30.33,EN,,0,0,0,,that sort of decouples it everywhere, Dialogue: 0,0:38:30.40,0:38:31.42,EN,,0,0,0,,not just in streams. Dialogue: 0,0:38:32.19,0:38:33.14,EN,,0,0,0,,Remember what we're trying to do. Dialogue: 0,0:38:33.14,0:38:38.11,EN,,0,0,0,,We're trying to think about programming as a way to specify processes. Dialogue: 0,0:38:39.30,0:38:40.62,EN,,0,0,0,,And if we give up too much time, Dialogue: 0,0:38:40.65,0:38:42.41,EN,,0,0,0,,our language becomes more elegant, Dialogue: 0,0:38:43.74,0:38:45.87,EN,,0,0,0,,but it becomes a little bit less expressive. Dialogue: 0,0:38:47.03,0:38:49.84,EN,,0,0,0,,There are certain distinctions that we can't draw. Dialogue: 0,0:38:51.48,0:38:53.15,EN,,0,0,0,,One of them, for instance, is iteration. Dialogue: 0,0:38:53.98,0:38:56.44,EN,,0,0,0,,Remember this old procedure, Dialogue: 0,0:38:56.96,0:38:58.28,EN,,0,0,0,,iterative factorial, Dialogue: 0,0:38:58.44,0:39:00.48,EN,,0,0,0,,that we looked at quite a long time ago. Dialogue: 0,0:39:01.23,0:39:02.97,EN,,0,0,0,,Iterative factorial had a thing, Dialogue: 0,0:39:03.04,0:39:04.91,EN,,0,0,0,,and it said there was an internal procedure, Dialogue: 0,0:39:05.18,0:39:07.50,EN,,0,0,0,,and there was a state which was a product and a counter, Dialogue: 0,0:39:08.70,0:39:10.96,EN,,0,0,0,,and we iterate that going around the loop. Dialogue: 0,0:39:12.12,0:39:13.68,EN,,0,0,0,,And we said that was an iterative procedure Dialogue: 0,0:39:13.71,0:39:14.83,EN,,0,0,0,,because it didn't build up state. Dialogue: 0,0:39:15.73,0:39:17.45,EN,,0,0,0,,And the reason it didn't build up state is Dialogue: 0,0:39:17.47,0:39:20.25,EN,,0,0,0,,because this iter that's called Dialogue: 0,0:39:20.30,0:39:22.86,EN,,0,0,0,,is just passing these things around to itself. Dialogue: 0,0:39:23.90,0:39:25.39,EN,,0,0,0,,Or in the substitution model that, Dialogue: 0,0:39:25.55,0:39:27.79,EN,,0,0,0,,you could see in the substitution model that Jerry did, Dialogue: 0,0:39:28.72,0:39:30.01,EN,,0,0,0,,that in an iterative procedure, Dialogue: 0,0:39:30.03,0:39:31.44,EN,,0,0,0,,that state doesn't have to grow. Dialogue: 0,0:39:31.82,0:39:34.22,EN,,0,0,0,,And in fact, we said it doesn't, so this is an iteration. Dialogue: 0,0:39:34.99,0:39:37.47,EN,,0,0,0,,But now think about this exact same text Dialogue: 0,0:39:37.47,0:39:39.10,EN,,0,0,0,,if we had a normal-order language. Dialogue: 0,0:39:41.15,0:39:42.17,EN,,0,0,0,,What would happen is Dialogue: 0,0:39:42.88,0:39:44.96,EN,,0,0,0,,this would no longer be an iterative procedure Dialogue: 0,0:39:45.65,0:39:48.67,EN,,0,0,0,,And if you really think about the details of the substitution model, Dialogue: 0,0:39:48.67,0:39:49.90,EN,,0,0,0,,which I'm not going to do here, Dialogue: 0,0:39:51.20,0:39:52.35,EN,,0,0,0,,this expression would grow. Dialogue: 0,0:39:52.36,0:39:53.18,EN,,0,0,0,,Why would it grow? Dialogue: 0,0:39:53.28,0:39:55.20,EN,,0,0,0,,It's because when iter calls itself, Dialogue: 0,0:39:55.85,0:39:57.31,EN,,0,0,0,,it calls itself with this product. Dialogue: 0,0:39:58.08,0:39:59.36,EN,,0,0,0,,If it's a normal-order language, Dialogue: 0,0:39:59.39,0:40:01.16,EN,,0,0,0,,that multiplication is not going to get done. Dialogue: 0,0:40:02.51,0:40:03.82,EN,,0,0,0,,That's going to say I'm to call myself Dialogue: 0,0:40:03.93,0:40:05.68,EN,,0,0,0,,with a promise to compute this product. Dialogue: 0,0:40:06.67,0:40:08.03,EN,,0,0,0,,And now iter goes around again. Dialogue: 0,0:40:09.76,0:40:11.55,EN,,0,0,0,,And I'm going to call myself Dialogue: 0,0:40:11.84,0:40:14.04,EN,,0,0,0,,with a promise to compute this product Dialogue: 0,0:40:14.04,0:40:17.82,EN,,0,0,0,,where now one of the one factors is a promise. Dialogue: 0,0:40:18.40,0:40:19.43,EN,,0,0,0,,And I call myself again. Dialogue: 0,0:40:19.43,0:40:21.13,EN,,0,0,0,,And if you write out the substitution model Dialogue: 0,0:40:21.98,0:40:23.60,EN,,0,0,0,,for that iterative process, Dialogue: 0,0:40:23.77,0:40:26.83,EN,,0,0,0,,you'll see exactly the same growth in state, Dialogue: 0,0:40:27.16,0:40:28.96,EN,,0,0,0,,all those promises that are getting remembered Dialogue: 0,0:40:28.97,0:40:30.76,EN,,0,0,0,,that have to get called in at the very end. Dialogue: 0,0:40:31.79,0:40:35.02,EN,,0,0,0,,So one of the disadvantages Dialogue: 0,0:40:35.05,0:40:36.86,EN,,0,0,0,,is that you can't really express iteration. Dialogue: 0,0:40:36.98,0:40:39.60,EN,,0,0,0,,Maybe that's a little theoretical reason why not, Dialogue: 0,0:40:39.61,0:40:43.90,EN,,0,0,0,,but in fact, people who are trying to write real operating systems Dialogue: 0,0:40:44.27,0:40:47.56,EN,,0,0,0,,in these languages are running into exactly these types of problems. Dialogue: 0,0:40:48.20,0:40:50.75,EN,,0,0,0,,Like it's perfectly possible to Dialogue: 0,0:40:51.64,0:40:54.38,EN,,0,0,0,,implement a text editor in languages like these. Dialogue: 0,0:40:54.61,0:40:56.08,EN,,0,0,0,,But after you work a while, Dialogue: 0,0:40:56.72,0:40:59.39,EN,,0,0,0,,you suddenly have 3 megabytes of stuff, Dialogue: 0,0:40:59.44,0:41:02.04,EN,,0,0,0,,which is-- I guess they call them Dialogue: 0,0:41:02.16,0:41:05.60,EN,,0,0,0,,the dragging tail problem who are looking at these, Dialogue: 0,0:41:05.82,0:41:08.20,EN,,0,0,0,,of stuff of promises that sort of haven't been called in Dialogue: 0,0:41:08.24,0:41:10.46,EN,,0,0,0,,because you couldn't quite express an iteration. Dialogue: 0,0:41:10.72,0:41:14.81,EN,,0,0,0,,And one of the research questions in these kinds of languages Dialogue: 0,0:41:14.83,0:41:17.48,EN,,0,0,0,,are figuring out the right compiler technology Dialogue: 0,0:41:17.82,0:41:19.85,EN,,0,0,0,,to get rid of the so-called dragging tails. Dialogue: 0,0:41:20.17,0:41:21.61,EN,,0,0,0,,It's not simple. Dialogue: 0,0:41:23.94,0:41:27.31,EN,,0,0,0,,But there's another kind of more striking issue Dialogue: 0,0:41:27.96,0:41:31.04,EN,,0,0,0,,about why you just don't go ahead and make your language normal order. Dialogue: 0,0:41:32.51,0:41:33.29,EN,,0,0,0,,And the reason is Dialogue: 0,0:41:35.05,0:41:38.09,EN,,0,0,0,,that normal-order evaluation and side effects Dialogue: 0,0:41:38.89,0:41:40.19,EN,,0,0,0,,just don't mix. Dialogue: 0,0:41:42.00,0:41:43.96,EN,,0,0,0,,They just don't go together very well. Dialogue: 0,0:41:45.44,0:41:46.65,EN,,0,0,0,,Somehow, you can't- Dialogue: 0,0:41:48.28,0:41:50.80,EN,,0,0,0,,it's sort of you can't simultaneously Dialogue: 0,0:41:51.00,0:41:54.33,EN,,0,0,0,,go around trying to model objects with local state and change Dialogue: 0,0:41:55.72,0:41:56.96,EN,,0,0,0,,at the same time Dialogue: 0,0:41:57.18,0:41:59.55,EN,,0,0,0,,do these normal-order tricks of de-coupling time. Dialogue: 0,0:42:00.40,0:42:03.55,EN,,0,0,0,,Let me just show you a really simple example, very, very simple. Dialogue: 0,0:42:03.79,0:42:05.50,EN,,0,0,0,,Suppose we had a normal-order language. Dialogue: 0,0:42:07.52,0:42:09.55,EN,,0,0,0,,And I'm going to start out in this language. Dialogue: 0,0:42:09.55,0:42:10.52,EN,,0,0,0,,This is now normal order. Dialogue: 0,0:42:10.52,0:42:12.22,EN,,0,0,0,,I'm going to define x to be 0. Dialogue: 0,0:42:13.57,0:42:15.56,EN,,0,0,0,,It's just some variable I'll initialize. Dialogue: 0,0:42:15.75,0:42:17.69,EN,,0,0,0,,And now I'm going to define this little funny function, Dialogue: 0,0:42:18.57,0:42:20.44,EN,,0,0,0,,which is an identity function. Dialogue: 0,0:42:22.64,0:42:23.90,EN,,0,0,0,,And what it does, Dialogue: 0,0:42:24.11,0:42:26.60,EN,,0,0,0,,it keeps track of the last time you called it using x. Dialogue: 0,0:42:31.40,0:42:34.16,EN,,0,0,0,,Right? So the identity of n just returns n, Dialogue: 0,0:42:34.17,0:42:35.39,EN,,0,0,0,,but it sets x to be n. Dialogue: 0,0:42:36.76,0:42:38.54,EN,,0,0,0,,And now I'll define a little increment function, Dialogue: 0,0:42:39.55,0:42:42.30,EN,,0,0,0,,which is a very little, simple scenario. Dialogue: 0,0:42:42.58,0:42:45.34,EN,,0,0,0,,Now, imagine I'm interacting with this in the normal-order language, Dialogue: 0,0:42:46.27,0:42:47.23,EN,,0,0,0,,and I type the following. Dialogue: 0,0:42:47.23,0:42:52.83,EN,,0,0,0,,I say define y to be increment the identity function of 3, Dialogue: 0,0:42:52.83,0:42:53.96,EN,,0,0,0,,so y is going to be 4. Dialogue: 0,0:42:57.41,0:42:58.35,EN,,0,0,0,,Now, I say what's x? Dialogue: 0,0:42:59.52,0:43:02.16,EN,,0,0,0,,Well, x should have been the value that was remembered last Dialogue: 0,0:43:02.64,0:43:04.01,EN,,0,0,0,,when I called the identity function. Dialogue: 0,0:43:04.71,0:43:06.73,EN,,0,0,0,,So you'd expect to say, well, x is 3 at this point, Dialogue: 0,0:43:06.91,0:43:07.52,EN,,0,0,0,,but it's not. Dialogue: 0,0:43:08.53,0:43:11.15,EN,,0,0,0,,Because when I defined here, y here, Dialogue: 0,0:43:11.79,0:43:13.45,EN,,0,0,0,,what I really defined y to be Dialogue: 0,0:43:13.47,0:43:15.71,EN,,0,0,0,,increment of a promise to do this thing. Dialogue: 0,0:43:17.00,0:43:18.17,EN,,0,0,0,,So I didn't look at y, Dialogue: 0,0:43:18.36,0:43:20.25,EN,,0,0,0,,so that identity function didn't get run. Dialogue: 0,0:43:21.56,0:43:23.20,EN,,0,0,0,,So if I type in this definition Dialogue: 0,0:43:23.31,0:43:24.80,EN,,0,0,0,,and look at x, I'm going to get 0. Dialogue: 0,0:43:28.36,0:43:31.20,EN,,0,0,0,,Now, if I go look at y and say what's y, Dialogue: 0,0:43:31.52,0:43:32.43,EN,,0,0,0,,say y is 4, Dialogue: 0,0:43:32.67,0:43:35.16,EN,,0,0,0,,looking at y, that very active looking at y Dialogue: 0,0:43:35.29,0:43:37.42,EN,,0,0,0,,caused the identity function to be run. Dialogue: 0,0:43:38.72,0:43:40.48,EN,,0,0,0,,And now x will get remembered as 3. Dialogue: 0,0:43:40.74,0:43:41.87,EN,,0,0,0,,So here x will be 0. Dialogue: 0,0:43:41.93,0:43:42.96,EN,,0,0,0,,Here, x will be 3. Dialogue: 0,0:43:43.28,0:43:46.16,EN,,0,0,0,,That's a tiny, little, simple scenario, Dialogue: 0,0:43:46.30,0:43:49.28,EN,,0,0,0,,but you can see what kind of a mess that's going to make Dialogue: 0,0:43:50.36,0:43:53.34,EN,,0,0,0,,for debugging interactive programs Dialogue: 0,0:43:54.12,0:43:55.88,EN,,0,0,0,,when you have normal-order evaluation. Dialogue: 0,0:43:57.10,0:43:58.12,EN,,0,0,0,,It's very confusing. Dialogue: 0,0:43:59.69,0:44:02.04,EN,,0,0,0,,But it's very confusing for a very deep reason, Dialogue: 0,0:44:02.80,0:44:06.41,EN,,0,0,0,,which is that the whole idea of putting in delays Dialogue: 0,0:44:06.92,0:44:08.43,EN,,0,0,0,,is that you throw away time. Dialogue: 0,0:44:09.78,0:44:11.75,EN,,0,0,0,,That's why we can have these infinite processes. Dialogue: 0,0:44:11.75,0:44:12.97,EN,,0,0,0,,Since we've thrown away time, Dialogue: 0,0:44:12.99,0:44:14.27,EN,,0,0,0,,we don't have to wait for them to run, Dialogue: 0,0:44:17.55,0:44:20.44,EN,,0,0,0,,Right? We decouple the order of events in the computer Dialogue: 0,0:44:20.83,0:44:22.11,EN,,0,0,0,,from what we write in our programs. Dialogue: 0,0:44:22.35,0:44:25.28,EN,,0,0,0,,But when we talk about state and set and change, Dialogue: 0,0:44:25.48,0:44:27.42,EN,,0,0,0,,that's exactly what we do want control of. Dialogue: 0,0:44:28.76,0:44:33.82,EN,,0,0,0,,So it's almost as if there's this fundamental contradiction in what you want. Dialogue: 0,0:44:34.57,0:44:39.12,EN,,0,0,0,,And that brings us back to these sort of philosophical mutterings Dialogue: 0,0:44:39.13,0:44:40.75,EN,,0,0,0,,what is it that you're trying to model Dialogue: 0,0:44:40.78,0:44:41.77,EN,,0,0,0,,and how do you look at the world. Dialogue: 0,0:44:42.41,0:44:44.30,EN,,0,0,0,,Or sometimes this is called the Dialogue: 0,0:44:44.76,0:44:46.60,EN,,0,0,0,,the debate over functional programming. Dialogue: 0,0:44:54.19,0:44:56.60,EN,,0,0,0,,A so-called purely functional language Dialogue: 0,0:44:57.07,0:44:59.20,EN,,0,0,0,,is one that just doesn't have any side effects. Dialogue: 0,0:45:00.44,0:45:01.63,EN,,0,0,0,,Since you have no side effects, Dialogue: 0,0:45:01.64,0:45:03.02,EN,,0,0,0,,there's no assignment operator, Dialogue: 0,0:45:03.34,0:45:05.72,EN,,0,0,0,,so there are no terrible consequences of it. Dialogue: 0,0:45:06.36,0:45:07.93,EN,,0,0,0,,You can use a substitution-like thing. Dialogue: 0,0:45:07.93,0:45:10.48,EN,,0,0,0,,Programs really are like mathematics and not like Dialogue: 0,0:45:10.76,0:45:13.82,EN,,0,0,0,,not like models in the real world, not like objects in the real world. Dialogue: 0,0:45:15.05,0:45:17.17,EN,,0,0,0,,There are a lot of wonderful things about functional languages. Dialogue: 0,0:45:17.17,0:45:19.63,EN,,0,0,0,,Since there's no time, you never have any synchronization problems. Dialogue: 0,0:45:20.64,0:45:23.72,EN,,0,0,0,,And if you want to put something into a parallel algorithm, Dialogue: 0,0:45:24.72,0:45:28.20,EN,,0,0,0,,you can run the pieces of that parallel processing any way you want. Dialogue: 0,0:45:29.40,0:45:31.44,EN,,0,0,0,,There's just never any synchronization to worry that, Dialogue: 0,0:45:31.50,0:45:33.34,EN,,0,0,0,,and it's a very congenial environment for doing this. Dialogue: 0,0:45:33.64,0:45:35.71,EN,,0,0,0,,The price is you give up assignment. Dialogue: 0,0:45:39.10,0:45:41.32,EN,,0,0,0,,So an advocate of a functional language would say, Dialogue: 0,0:45:41.34,0:45:43.04,EN,,0,0,0,,gee, that's just a tiny price to pay. Dialogue: 0,0:45:44.52,0:45:46.51,EN,,0,0,0,,You probably shouldn't use assignment most of the time anyway. Dialogue: 0,0:45:46.88,0:45:48.27,EN,,0,0,0,,And if you just give up assignment, Dialogue: 0,0:45:48.43,0:45:51.40,EN,,0,0,0,,you can be in this much, much nicer world Dialogue: 0,0:45:51.96,0:45:53.24,EN,,0,0,0,,than this place with objects. Dialogue: 0,0:45:54.19,0:45:56.30,EN,,0,0,0,,Well, what's the rejoinder to that? Dialogue: 0,0:45:56.30,0:45:58.59,EN,,0,0,0,,Remember how we got into this mess. Dialogue: 0,0:46:00.06,0:46:03.79,EN,,0,0,0,,We started trying to model things that had local state. Dialogue: 0,0:46:04.44,0:46:06.49,EN,,0,0,0,,So remember Gerry's random number generator. Dialogue: 0,0:46:07.16,0:46:08.67,EN,,0,0,0,,There was this random number generator Dialogue: 0,0:46:09.28,0:46:10.62,EN,,0,0,0,,that had some little state in it Dialogue: 0,0:46:10.83,0:46:12.08,EN,,0,0,0,,to compute the next random number Dialogue: 0,0:46:12.12,0:46:14.08,EN,,0,0,0,,and the next random number and the next random number. Dialogue: 0,0:46:14.28,0:46:16.14,EN,,0,0,0,,And we wanted to hide that state away from the Dialogue: 0,0:46:16.43,0:46:18.96,EN,,0,0,0,,the Cesaro compute pi process, Dialogue: 0,0:46:19.84,0:46:20.92,EN,,0,0,0,,and that's why we needed set! Dialogue: 0,0:46:20.97,0:46:22.91,EN,,0,0,0,,We wanted to package that stated modularly. Dialogue: 0,0:46:24.07,0:46:26.36,EN,,0,0,0,,Well, a functional programming person would say, Dialogue: 0,0:46:26.38,0:46:27.56,EN,,0,0,0,,well, you're just all wet. Dialogue: 0,0:46:27.56,0:46:29.84,EN,,0,0,0,,I mean, you can write a perfectly good modular program. Dialogue: 0,0:46:29.84,0:46:32.46,EN,,0,0,0,,It's just you're thinking about modularity wrong. Dialogue: 0,0:46:33.08,0:46:35.02,EN,,0,0,0,,You're hung up in this next random number Dialogue: 0,0:46:35.07,0:46:36.88,EN,,0,0,0,,and the next random number and the next random number. Dialogue: 0,0:46:36.88,0:46:39.42,EN,,0,0,0,,Why don't you just say let's write a program. Dialogue: 0,0:46:40.09,0:46:41.29,EN,,0,0,0,,Let's write an enumerator Dialogue: 0,0:46:41.95,0:46:44.48,EN,,0,0,0,,which just generates an infinite stream of random numbers. Dialogue: 0,0:46:49.01,0:46:50.91,EN,,0,0,0,,We can sort of have that stream all at once, Dialogue: 0,0:46:52.64,0:46:54.54,EN,,0,0,0,,and that's going to be our source of random numbers. Dialogue: 0,0:46:54.54,0:46:55.24,EN,,0,0,0,,And then if you like, Dialogue: 0,0:46:55.53,0:46:57.47,EN,,0,0,0,,you can put that through some sort of processor, Dialogue: 0,0:46:57.77,0:47:01.16,EN,,0,0,0,,which is-- I don't know-- a Cesaro test, Dialogue: 0,0:47:04.94,0:47:06.22,EN,,0,0,0,,and that can do what it wants. Dialogue: 0,0:47:06.88,0:47:08.56,EN,,0,0,0,,And what would come out of there Dialogue: 0,0:47:08.72,0:47:27.45,EN,,0,0,0,,would be a stream of successive approximations to pi. Dialogue: 0,0:47:28.14,0:47:30.65,EN,,0,0,0,,So as we looked further down this stream, Dialogue: 0,0:47:30.76,0:47:32.38,EN,,0,0,0,,we'd tug on this Cesaro thing, Dialogue: 0,0:47:33.12,0:47:35.36,EN,,0,0,0,,and it would pull out more and more random numbers. Dialogue: 0,0:47:35.54,0:47:37.21,EN,,0,0,0,,And the further and further we look down the stream, Dialogue: 0,0:47:37.23,0:47:38.96,EN,,0,0,0,,the better an approximation we'd get to pi. Dialogue: 0,0:47:39.72,0:47:41.66,EN,,0,0,0,,And it would do exactly the same as the other computation, Dialogue: 0,0:47:41.66,0:47:43.79,EN,,0,0,0,,except we're thinking about the modularity different. Dialogue: 0,0:47:43.89,0:47:45.55,EN,,0,0,0,,We're saying imagine we had all that Dialogue: 0,0:47:45.56,0:47:47.47,EN,,0,0,0,,infinite streams of random numbers all at once. Dialogue: 0,0:47:49.28,0:47:52.24,EN,,0,0,0,,You can see the details of this procedure in the book. Dialogue: 0,0:47:53.61,0:47:57.85,EN,,0,0,0,,But similarly, there are other things that we tend to get locked into Dialogue: 0,0:47:58.27,0:48:01.20,EN,,0,0,0,,on this one and that one and the next one and the next one, Dialogue: 0,0:48:01.37,0:48:02.81,EN,,0,0,0,,which don't have to be that way. Dialogue: 0,0:48:03.28,0:48:06.54,EN,,0,0,0,,Like you might think about like a banking system, Dialogue: 0,0:48:07.68,0:48:08.90,EN,,0,0,0,,which is a very simple idea. Dialogue: 0,0:48:08.90,0:48:12.21,EN,,0,0,0,,Imagine we have a program that sort of represents a bank account. Dialogue: 0,0:48:18.81,0:48:20.84,EN,,0,0,0,,The bank account might have in it-- Dialogue: 0,0:48:22.78,0:48:26.22,EN,,0,0,0,,if we looked at this in a sort of message-passing view of the world, Dialogue: 0,0:48:26.44,0:48:28.12,EN,,0,0,0,,we'd say a bank account is an object Dialogue: 0,0:48:28.59,0:48:31.51,EN,,0,0,0,,that has some local state in there, which is the balance, say. Dialogue: 0,0:48:34.11,0:48:36.00,EN,,0,0,0,,And a user using this system comes Dialogue: 0,0:48:36.44,0:48:38.14,EN,,0,0,0,,and sends a transaction request. Dialogue: 0,0:48:39.31,0:48:41.05,EN,,0,0,0,,So the user sends a transaction request, Dialogue: 0,0:48:41.07,0:48:42.20,EN,,0,0,0,,like deposit some money, Dialogue: 0,0:48:42.28,0:48:43.53,EN,,0,0,0,,and the bank account maybe-- Dialogue: 0,0:48:43.92,0:48:46.78,EN,,0,0,0,,let's say the bank account always responds with what the current balance is. Dialogue: 0,0:48:48.22,0:48:50.04,EN,,0,0,0,,The user says let's deposits some money, Dialogue: 0,0:48:50.06,0:48:53.21,EN,,0,0,0,,and the bank account sends back a message which is the balance. Dialogue: 0,0:48:54.35,0:48:57.42,EN,,0,0,0,,And the user says deposit some more, Dialogue: 0,0:48:57.45,0:48:58.81,EN,,0,0,0,,and the bank account sends back a message. Dialogue: 0,0:48:59.15,0:49:00.75,EN,,0,0,0,,And just like the random number generating Dialogue: 0,0:49:00.78,0:49:02.12,EN,,0,0,0,,you'd say, gee, we would like to use set. Dialogue: 0,0:49:03.20,0:49:06.88,EN,,0,0,0,,We'd like to have balance be a piece of local state inside this bank account Dialogue: 0,0:49:06.88,0:49:08.40,EN,,0,0,0,,because we want to separate the state of the user Dialogue: 0,0:49:08.41,0:49:09.57,EN,,0,0,0,,from the state of the bank account. Dialogue: 0,0:49:13.28,0:49:16.42,EN,,0,0,0,,Well, that's the message-processing view. Dialogue: 0,0:49:16.42,0:49:18.20,EN,,0,0,0,,There's a stream view with that thing, Dialogue: 0,0:49:19.48,0:49:22.19,EN,,0,0,0,,which does the same thing without any set or side effects. Dialogue: 0,0:49:22.74,0:49:26.73,EN,,0,0,0,,And the idea is again Dialogue: 0,0:49:27.37,0:49:30.25,EN,,0,0,0,,we don't think about anything having local state. Dialogue: 0,0:49:31.18,0:49:33.08,EN,,0,0,0,,We think about the bank account as something Dialogue: 0,0:49:33.40,0:49:37.71,EN,,0,0,0,,that's going to process a stream of transaction requests. Dialogue: 0,0:49:38.64,0:49:40.16,EN,,0,0,0,,So think about this bank account not Dialogue: 0,0:49:40.22,0:49:42.00,EN,,0,0,0,,as something that goes message by message, Dialogue: 0,0:49:42.44,0:49:45.85,EN,,0,0,0,,but something that takes in a stream of transaction requests Dialogue: 0,0:49:45.87,0:49:48.49,EN,,0,0,0,,like maybe successive deposit announced. Dialogue: 0,0:49:49.49,0:49:54.94,EN,,0,0,0,,1, 2, 2, 4, those might be successive amounts to deposit. Dialogue: 0,0:49:55.94,0:50:02.44,EN,,0,0,0,,And then coming out of it is the successive balances 1, 3, 5, 9. Dialogue: 0,0:50:03.77,0:50:06.14,EN,,0,0,0,,So we think of the bank account not as something that has state, Dialogue: 0,0:50:06.40,0:50:07.26,EN,,0,0,0,,but something that acts Dialogue: 0,0:50:08.92,0:50:10.82,EN,,0,0,0,,sort of on the infinite stream of requests. Dialogue: 0,0:50:10.82,0:50:12.30,EN,,0,0,0,,But remember, we've thrown away time. Dialogue: 0,0:50:12.37,0:50:14.27,EN,,0,0,0,,So what we can do is if the user's here, Dialogue: 0,0:50:16.12,0:50:19.13,EN,,0,0,0,,we can have this infinite stream of requests Dialogue: 0,0:50:19.18,0:50:22.54,EN,,0,0,0,,being generated one at a time coming from the user Dialogue: 0,0:50:24.06,0:50:26.57,EN,,0,0,0,,and this transaction stream Dialogue: 0,0:50:26.57,0:50:28.80,EN,,0,0,0,,coming back on a printer being printed one at a time. Dialogue: 0,0:50:30.01,0:50:31.37,EN,,0,0,0,,And if we drew a little line here, Dialogue: 0,0:50:32.56,0:50:33.08,EN,,0,0,0,,right there to the user, Dialogue: 0,0:50:33.28,0:50:34.91,EN,,0,0,0,,the user couldn't tell that this system doesn't have state. Dialogue: 0,0:50:36.19,0:50:37.71,EN,,0,0,0,,that this system doesn't have state. Dialogue: 0,0:50:39.56,0:50:41.13,EN,,0,0,0,,It looks just like the other one, Dialogue: 0,0:50:41.29,0:50:42.46,EN,,0,0,0,,but there's no state in there. Dialogue: 0,0:50:42.84,0:50:45.87,EN,,0,0,0,,And by the way, Dialogue: 0,0:50:46.72,0:50:49.47,EN,,0,0,0,,just to show you, here's an actual implementation Dialogue: 0,0:50:50.52,0:50:52.30,EN,,0,0,0,,of this-- we'll call it make deposit account Dialogue: 0,0:50:52.32,0:50:53.32,EN,,0,0,0,,because you can only deposit. Dialogue: 0,0:50:54.17,0:50:55.77,EN,,0,0,0,,It takes an initial balance Dialogue: 0,0:50:56.09,0:50:58.09,EN,,0,0,0,,and then a stream of deposits you might make. Dialogue: 0,0:51:00.02,0:51:00.82,EN,,0,0,0,,And what is it? Dialogue: 0,0:51:00.82,0:51:02.54,EN,,0,0,0,,Well, it's just cons-stream of the balance Dialogue: 0,0:51:03.23,0:51:05.31,EN,,0,0,0,,onto make a new account stream Dialogue: 0,0:51:06.24,0:51:07.32,EN,,0,0,0,,whose initial balance Dialogue: 0,0:51:07.48,0:51:10.27,EN,,0,0,0,,is the old balance plus the first thing in the deposit stream Dialogue: 0,0:51:10.86,0:51:13.40,EN,,0,0,0,,whose rest, right and, Dialogue: 0,0:51:13.76,0:51:17.37,EN,,0,0,0,,make deposit account works on the rest of which is the tail of the deposit stream. Dialogue: 0,0:51:18.30,0:51:23.84,EN,,0,0,0,,So there's sort of a very typical message-passing, Dialogue: 0,0:51:23.95,0:51:27.55,EN,,0,0,0,,message-passing, object-oriented thing that's done without side effects at all. Dialogue: 0,0:51:29.05,0:51:30.76,EN,,0,0,0,,There are very many things you can do this way. Dialogue: 0,0:51:32.25,0:51:35.23,EN,,0,0,0,,Well, can you do everything without assignment? Dialogue: 0,0:51:36.40,0:51:39.00,EN,,0,0,0,,Can everybody go over to purely functional languages? Dialogue: 0,0:51:40.05,0:51:42.04,EN,,0,0,0,,Well, we don't know, Dialogue: 0,0:51:42.27,0:51:43.44,EN,,0,0,0,,but there seem to be places Dialogue: 0,0:51:43.92,0:51:46.03,EN,,0,0,0,,where purely functional programming breaks down. Dialogue: 0,0:51:48.10,0:51:50.27,EN,,0,0,0,,Where it starts hurting is when you have things like this, Dialogue: 0,0:51:50.43,0:51:52.32,EN,,0,0,0,,but you also mix it up with Dialogue: 0,0:51:52.60,0:51:54.27,EN,,0,0,0,,the other things that we had to worry that, Dialogue: 0,0:51:54.30,0:51:55.64,EN,,0,0,0,,which are objects and sharing Dialogue: 0,0:51:55.90,0:51:58.52,EN,,0,0,0,,and two independent agents being the same. Dialogue: 0,0:51:58.85,0:51:59.93,EN,,0,0,0,,So under a typical one, Dialogue: 0,0:51:59.96,0:52:01.63,EN,,0,0,0,,suppose you want to extend this bank account. Dialogue: 0,0:52:03.24,0:52:04.27,EN,,0,0,0,,So here's a bank account. Dialogue: 0,0:52:12.22,0:52:14.75,EN,,0,0,0,,Bank accounts take in a stream of transaction requests Dialogue: 0,0:52:15.20,0:52:18.44,EN,,0,0,0,,and put out streams of, say, balances or responses to that. Dialogue: 0,0:52:18.78,0:52:20.16,EN,,0,0,0,,But suppose you want to model the fact Dialogue: 0,0:52:20.17,0:52:24.36,EN,,0,0,0,,that this is a joint bank account between two independent people. Dialogue: 0,0:52:25.68,0:52:28.65,EN,,0,0,0,,Right? I don't know. So suppose there are two people, Dialogue: 0,0:52:28.97,0:52:30.96,EN,,0,0,0,,say, Bill and Dave, Dialogue: 0,0:52:31.77,0:52:33.14,EN,,0,0,0,,who have a joint bank account. Dialogue: 0,0:52:35.96,0:52:36.85,EN,,0,0,0,,How would you model this? Dialogue: 0,0:52:36.88,0:52:39.80,EN,,0,0,0,,Well, you might, Bill puts out a stream of transaction requests, Dialogue: 0,0:52:40.24,0:52:42.25,EN,,0,0,0,,and Dave puts out a stream of transaction requests, Dialogue: 0,0:52:42.25,0:52:45.16,EN,,0,0,0,,and somehow, they have to merge into this bank account. Dialogue: 0,0:52:45.88,0:52:47.85,EN,,0,0,0,,So what you might do is write a little stream Dialogue: 0,0:52:47.90,0:52:50.65,EN,,0,0,0,,processing thing called merge, Dialogue: 0,0:52:57.23,0:52:59.13,EN,,0,0,0,,which sort of takes these, merges them together, Dialogue: 0,0:52:59.34,0:53:01.19,EN,,0,0,0,,produces a single stream for the bank account. Dialogue: 0,0:53:01.19,0:53:02.99,EN,,0,0,0,,Now they're both talking to the same bank account. Dialogue: 0,0:53:03.61,0:53:05.48,EN,,0,0,0,,That's all great, but how do you write merge? Dialogue: 0,0:53:05.93,0:53:08.24,EN,,0,0,0,,What, What's this procedure merge? Dialogue: 0,0:53:09.73,0:53:11.42,EN,,0,0,0,,You want to do something that's reasonable. Dialogue: 0,0:53:12.38,0:53:13.80,EN,,0,0,0,,Your first guess might be to say, Dialogue: 0,0:53:13.80,0:53:16.68,EN,,0,0,0,,well, we'll take alternate requests from Bill and Dave. Dialogue: 0,0:53:18.19,0:53:20.97,EN,,0,0,0,,But what happens if But what happens if suddenly in the middle thing Dialogue: 0,0:53:21.18,0:53:23.08,EN,,0,0,0,,Dave goes away on vacation for two years? Dialogue: 0,0:53:24.15,0:53:25.40,EN,,0,0,0,,Then Bill's sort of stuck. Dialogue: 0,0:53:27.69,0:53:29.75,EN,,0,0,0,,So what you want to do is-- well, it's hard to describe. Dialogue: 0,0:53:29.75,0:53:33.64,EN,,0,0,0,,What you want to do is what people call fair merge. Dialogue: 0,0:53:38.41,0:53:40.17,EN,,0,0,0,,The idea of fair merge is Dialogue: 0,0:53:40.73,0:53:42.46,EN,,0,0,0,,is it sort of should do them alternately, Dialogue: 0,0:53:42.49,0:53:43.92,EN,,0,0,0,,but if there's nothing waiting here, Dialogue: 0,0:53:43.96,0:53:44.91,EN,,0,0,0,,it should take one twice. Dialogue: 0,0:53:46.01,0:53:48.45,EN,,0,0,0,,Notice I can't even say that without talking about time. Dialogue: 0,0:53:51.30,0:53:56.41,EN,,0,0,0,,So one of the other active researcher areas in functional languages Dialogue: 0,0:53:56.43,0:53:59.48,EN,,0,0,0,,is inventing little things like fair merge Dialogue: 0,0:54:00.35,0:54:01.31,EN,,0,0,0,,maybe some others, Dialogue: 0,0:54:01.56,0:54:06.25,EN,,0,0,0,,which will take the places where I used to need side effects and objects Dialogue: 0,0:54:06.80,0:54:10.52,EN,,0,0,0,,and sort of hide them away in some very well-defined modules of the system Dialogue: 0,0:54:10.86,0:54:13.50,EN,,0,0,0,,so that all the problems of assignment Dialogue: 0,0:54:13.52,0:54:15.34,EN,,0,0,0,,don't sort of leak out all over the system but Dialogue: 0,0:54:15.40,0:54:17.88,EN,,0,0,0,,are captured in some fairly well-understood things. Dialogue: 0,0:54:20.78,0:54:22.70,EN,,0,0,0,,More generally, I think what you're seeing Dialogue: 0,0:54:23.12,0:54:24.06,EN,,0,0,0,,is that we're running across Dialogue: 0,0:54:24.08,0:54:26.67,EN,,0,0,0,,what I think is a very basic problem in computer science, Dialogue: 0,0:54:26.97,0:54:27.82,EN,,0,0,0,,which is how to Dialogue: 0,0:54:28.24,0:54:32.03,EN,,0,0,0,,how to define languages that somehow can talk about delayed evaluation Dialogue: 0,0:54:34.14,0:54:35.08,EN,,0,0,0,,But also Dialogue: 0,0:54:35.87,0:54:38.25,EN,,0,0,0,,be able to reflect this view that there are objects in the world. Dialogue: 0,0:54:38.36,0:54:40.36,EN,,0,0,0,,How do we somehow get both? Dialogue: 0,0:54:41.23,0:54:43.04,EN,,0,0,0,,And I think that's a very hard problem. Dialogue: 0,0:54:43.04,0:54:45.52,EN,,0,0,0,,And it may be that it's a very hard problem Dialogue: 0,0:54:45.85,0:54:48.17,EN,,0,0,0,,that has almost nothing to do with computer science, Dialogue: 0,0:54:48.59,0:54:50.24,EN,,0,0,0,,that it really is a problem having to do with Dialogue: 0,0:54:50.27,0:54:52.73,EN,,0,0,0,,two very incompatible ways of looking at the world. Dialogue: 0,0:54:54.14,0:54:54.72,EN,,0,0,0,,OK, questions? Dialogue: 0,0:55:17.55,0:55:19.20,EN,,0,0,0,,AUDIENCE: You mentioned earlier that Dialogue: 0,0:55:20.11,0:55:21.32,EN,,0,0,0,,once you introduce assignment, Dialogue: 0,0:55:21.32,0:55:25.89,EN,,0,0,0,,the general rule for using the substitution model is you can't. Dialogue: 0,0:55:25.89,0:55:27.57,EN,,0,0,0,,Unless you're very careful, you can't. Dialogue: 0,0:55:27.57,0:55:27.96,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:55:28.26,0:55:33.28,EN,,0,0,0,,AUDIENCE: Is there a set of techniques or a set of guidelines Dialogue: 0,0:55:33.42,0:55:35.92,EN,,0,0,0,,for localizing the effects of assignment Dialogue: 0,0:55:36.52,0:55:40.30,EN,,0,0,0,,so that the very careful becomes defined? Dialogue: 0,0:55:40.30,0:55:42.60,EN,,0,0,0,,PROFESSOR: I don't know. Um... Dialogue: 0,0:55:42.89,0:55:43.58,EN,,0,0,0,,Let me think. Dialogue: 0,0:55:45.43,0:55:48.94,EN,,0,0,0,,Well, certainly, there was an assignment inside memo proc, Dialogue: 0,0:55:50.12,0:55:51.48,EN,,0,0,0,,but that was sort of hidden away. Dialogue: 0,0:55:51.48,0:55:53.00,EN,,0,0,0,,It ended up not making any difference. Dialogue: 0,0:55:53.48,0:55:56.44,EN,,0,0,0,,Part of the reason for that is once this thing triggered Dialogue: 0,0:55:57.15,0:55:58.83,EN,,0,0,0,,that it had run and gotten an answer, Dialogue: 0,0:55:58.83,0:56:00.06,EN,,0,0,0,,that answer will never change. Dialogue: 0,0:56:00.60,0:56:02.33,EN,,0,0,0,,So that was sort of a one-time assignment. Dialogue: 0,0:56:02.35,0:56:03.85,EN,,0,0,0,,So one very general thing you can do Dialogue: 0,0:56:04.30,0:56:06.35,EN,,0,0,0,,is if you only do what's called a one-time assignment Dialogue: 0,0:56:08.04,0:56:09.24,EN,,0,0,0,,and never change anything, Dialogue: 0,0:56:09.63,0:56:10.54,EN,,0,0,0,,then you can do better. Dialogue: 0,0:56:11.25,0:56:14.12,EN,,0,0,0,,One of the problems in this merge thing, people have-- Dialogue: 0,0:56:14.67,0:56:18.32,EN,,0,0,0,,people have-- let me see if this is right. Dialogue: 0,0:56:18.49,0:56:21.55,EN,,0,0,0,,I think it's true that with fair merge, Dialogue: 0,0:56:22.25,0:56:26.09,EN,,0,0,0,,with just fair merge, you can begin effectively simulating Dialogue: 0,0:56:27.02,0:56:28.89,EN,,0,0,0,,assignment in the rest of the language. Dialogue: 0,0:56:30.82,0:56:33.29,EN,,0,0,0,,It seems like anything you do to go outside-- Dialogue: 0,0:56:33.50,0:56:35.50,EN,,0,0,0,,I'm not quite sure that's true for fair merge, Dialogue: 0,0:56:35.53,0:56:39.31,EN,,0,0,0,,but it's true of a little bit more general things that people have been doing. Dialogue: 0,0:56:39.52,0:56:41.34,EN,,0,0,0,,So it might be that any little bit you put in, Dialogue: 0,0:56:41.61,0:56:44.14,EN,,0,0,0,,suddenly if they allow you to build arbitrary stuff, Dialogue: 0,0:56:44.16,0:56:46.51,EN,,0,0,0,,it's almost as bad as having assignment altogether. Dialogue: 0,0:56:47.97,0:56:50.67,EN,,0,0,0,,But that's an area that people are thinking about now. Dialogue: 0,0:56:51.59,0:56:54.30,EN,,0,0,0,,AUDIENCE: I guess I don't see the problem here with merge Dialogue: 0,0:56:54.83,0:56:59.20,EN,,0,0,0,,if, you know the sense, I call Bill, if Bill is a procedure, Dialogue: 0,0:56:59.21,0:57:02.41,EN,,0,0,0,,then Bill is going to increment the bank account Dialogue: 0,0:57:02.44,0:57:04.73,EN,,0,0,0,,or build the list that 's going to put in the next element. Dialogue: 0,0:57:04.73,0:57:06.84,EN,,0,0,0,,If I call Dave twice in a row, that will do that. Dialogue: 0,0:57:07.17,0:57:09.35,EN,,0,0,0,,I'm not sure where fair merge has to be involved. Dialogue: 0,0:57:09.35,0:57:11.20,EN,,0,0,0,,PROFESSOR: The problem is imagine these really as people. Dialogue: 0,0:57:11.20,0:57:14.20,EN,,0,0,0,,See, here I have the user who's interacting with this bank account. Dialogue: 0,0:57:14.85,0:57:17.07,EN,,0,0,0,,Put in a request, get an answer. Put in a request, get an answer. Dialogue: 0,0:57:17.20,0:57:17.56,EN,,0,0,0,,AUDIENCE: Right. Dialogue: 0,0:57:18.20,0:57:20.62,EN,,0,0,0,,PROFESSOR: But if the only way I can process request Dialogue: 0,0:57:20.65,0:57:22.25,EN,,0,0,0,,is to alternate them from two people-- Dialogue: 0,0:57:22.91,0:57:24.22,EN,,0,0,0,,AUDIENCE: Well, why would you alternate them? Dialogue: 0,0:57:24.22,0:57:25.23,EN,,0,0,0,,PROFESSOR: Why don't I? Dialogue: 0,0:57:25.45,0:57:25.80,EN,,0,0,0,,AUDIENCE: Yes. Why do you? Dialogue: 0,0:57:26.60,0:57:27.72,EN,,0,0,0,,PROFESSOR: Think of them as real people, right? Dialogue: 0,0:57:27.76,0:57:28.97,EN,,0,0,0,,This guy might go away for a year. Dialogue: 0,0:57:29.28,0:57:31.74,EN,,0,0,0,,And you're sitting here at the bank account window, Dialogue: 0,0:57:32.43,0:57:33.72,EN,,0,0,0,,and you can't put in two requests Dialogue: 0,0:57:33.74,0:57:34.94,EN,,0,0,0,,because it's waiting for this guy. Dialogue: 0,0:57:35.48,0:57:37.07,EN,,0,0,0,,AUDIENCE: Why does it have to be waiting for one? Dialogue: 0,0:57:37.38,0:57:39.11,EN,,0,0,0,,PROFESSOR: Because it's trying to compute a function. Dialogue: 0,0:57:39.11,0:57:40.92,EN,,0,0,0,,I have to define a function. Dialogue: 0,0:57:41.72,0:57:42.60,EN,,0,0,0,,Another way to say that Dialogue: 0,0:57:42.84,0:57:44.99,EN,,0,0,0,,is the answer to what comes out of this merge box Dialogue: 0,0:57:46.24,0:57:49.48,EN,,0,0,0,,is not a function of what goes in. Dialogue: 0,0:57:51.69,0:57:53.49,EN,,0,0,0,,Because, see, what would the function be? Dialogue: 0,0:57:53.49,0:57:58.86,EN,,0,0,0,,Suppose he puts in 1, 1, 1, 1, Dialogue: 0,0:57:59.82,0:58:02.78,EN,,0,0,0,,and he puts in 2, 2, 2, 2. Dialogue: 0,0:58:03.47,0:58:04.80,EN,,0,0,0,,What's the answer supposed to be? Dialogue: 0,0:58:05.58,0:58:08.74,EN,,0,0,0,,It's not good enough to say it's 1, 2, 1, 2, 1, 2. Dialogue: 0,0:58:08.74,0:58:09.39,EN,,0,0,0,,AUDIENCE: I understand. Dialogue: 0,0:58:09.39,0:58:11.56,EN,,0,0,0,,But when Bill puts in 1, 1 goes in. Dialogue: 0,0:58:11.56,0:58:13.95,EN,,0,0,0,,When Dave puts in 2, twice 2 goes in twice. Dialogue: 0,0:58:13.95,0:58:14.73,EN,,0,0,0,,AUDIENCE: When Bill puts in-- Dialogue: 0,0:58:14.76,0:58:15.08,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:58:15.13,0:58:18.43,EN,,0,0,0,,AUDIENCE: Why can't it be hooked to the time of the input-- Dialogue: 0,0:58:18.59,0:58:20.06,EN,,0,0,0,,the actual procedural-- Dialogue: 0,0:58:20.12,0:58:21.84,EN,,0,0,0,,PROFESSOR: Because I don't have time. Dialogue: 0,0:58:23.98,0:58:26.90,EN,,0,0,0,,See, all I can say is I'm going to define a function. Dialogue: 0,0:58:26.90,0:58:28.15,EN,,0,0,0,,I don't have time. Dialogue: 0,0:58:32.00,0:58:34.19,EN,,0,0,0,,There's no concept if it's going to alternate, Dialogue: 0,0:58:34.19,0:58:36.54,EN,,0,0,0,,except if nobody's there, it's going to wait a while for him. Dialogue: 0,0:58:38.42,0:58:41.36,EN,,0,0,0,,It's just going to say I have the stream of requests, Dialogue: 0,0:58:41.74,0:58:43.34,EN,,0,0,0,,the timeless infinite streams Dialogue: 0,0:58:43.36,0:58:45.29,EN,,0,0,0,,of all the requests that Dave would have made, right? Dialogue: 0,0:58:47.55,0:58:50.41,EN,,0,0,0,,And the timeless infinite stream of all the requests Bill would have made, Dialogue: 0,0:58:50.54,0:58:51.69,EN,,0,0,0,,and I want to operate on them. Dialogue: 0,0:58:51.69,0:58:53.51,EN,,0,0,0,,See, that's how this bank account is working. Dialogue: 0,0:58:56.71,0:58:57.58,EN,,0,0,0,,And the problem is Dialogue: 0,0:58:57.61,0:59:00.75,EN,,0,0,0,,that these poor people who are sitting at the bank account windows Dialogue: 0,0:59:00.76,0:59:03.82,EN,,0,0,0,,have the misfortune to exist in time. Dialogue: 0,0:59:05.29,0:59:07.13,EN,,0,0,0,,They don't see their infinite stream Dialogue: 0,0:59:07.69,0:59:09.53,EN,,0,0,0,,of all the requests they would have ever made. Dialogue: 0,0:59:10.07,0:59:11.55,EN,,0,0,0,,They're waiting now, and they want an answer. Dialogue: 0,0:59:14.48,0:59:15.76,EN,,0,0,0,,So if you're sitting there-- Dialogue: 0,0:59:16.24,0:59:20.86,EN,,0,0,0,,if this is the screen operation on some time-sharing system Dialogue: 0,0:59:21.52,0:59:22.60,EN,,0,0,0,,and it's working functionally, Dialogue: 0,0:59:22.64,0:59:24.59,EN,,0,0,0,,you want an answer then when you talk the character. Dialogue: 0,0:59:25.29,0:59:27.42,EN,,0,0,0,,You don't want it to have to wait for everybody in the whole system Dialogue: 0,0:59:27.45,0:59:29.92,EN,,0,0,0,,to have typed one character before it can get around to service you. Dialogue: 0,0:59:30.91,0:59:31.92,EN,,0,0,0,,So that's the problem. Dialogue: 0,0:59:34.00,0:59:36.38,EN,,0,0,0,,I mean, the fact that people live in time, apparently. Dialogue: 0,0:59:37.21,0:59:38.62,EN,,0,0,0,,If they didn't, it wouldn't be a problem. Dialogue: 0,0:59:49.10,0:59:51.02,EN,,0,0,0,,AUDIENCE: I'm afraid I miss the point of Dialogue: 0,0:59:51.08,0:59:54.24,EN,,0,0,0,,having no time in this banking transaction. Dialogue: 0,0:59:54.74,0:59:56.65,EN,,0,0,0,,Isn't time very important? Dialogue: 0,0:59:56.88,0:59:59.05,EN,,0,0,0,,For instance, the sequence of events. Dialogue: 0,0:59:59.95,1:00:05.02,EN,,0,0,0,,As if, If Dave take out $100, and then Dialogue: 0,1:00:06.30,1:00:08.40,EN,,0,0,0,,then the timing sequence should be important. Dialogue: 0,1:00:08.40,1:00:10.86,EN,,0,0,0,,How do you treat transactions as streams? Dialogue: 0,1:00:11.26,1:00:14.26,EN,,0,0,0,,PROFESSOR: Well, that's the thing I'm saying. Dialogue: 0,1:00:14.26,1:00:15.61,EN,,0,0,0,,This is an example where you can't. Dialogue: 0,1:00:17.51,1:00:18.12,EN,,0,0,0,,You can't. Dialogue: 0,1:00:18.16,1:00:20.08,EN,,0,0,0,,What goes, The point is what comes out of here Dialogue: 0,1:00:20.24,1:00:21.88,EN,,0,0,0,,is simply not a function of the stream going in here Dialogue: 0,1:00:21.92,1:00:23.60,EN,,0,0,0,,going in here and the stream going in here. Dialogue: 0,1:00:24.17,1:00:25.98,EN,,0,0,0,,It's a function of the stream going in here Dialogue: 0,1:00:26.19,1:00:27.26,EN,,0,0,0,,and the stream going in here Dialogue: 0,1:00:27.36,1:00:29.07,EN,,0,0,0,,and some kind of information about time, Dialogue: 0,1:00:29.37,1:00:32.36,EN,,0,0,0,,which is precisely what a normal-order language won't let you say. Dialogue: 0,1:00:34.81,1:00:37.95,EN,,0,0,0,,AUDIENCE: In order to brings this back into a more functional perspective, Dialogue: 0,1:00:38.54,1:00:42.04,EN,,0,0,0,,could we just explicitly time stamp all the inputs from Bill and Dave Dialogue: 0,1:00:42.54,1:00:46.40,EN,,0,0,0,,and define fair merge to just be the sort on those time stamps? Dialogue: 0,1:00:48.41,1:00:49.55,EN,,0,0,0,,PROFESSOR: Yeah, you can do that. Dialogue: 0,1:00:49.55,1:00:50.60,EN,,0,0,0,,You can do that sort of thing. Dialogue: 0,1:00:50.60,1:00:52.56,EN,,0,0,0,,Another thing you could say is imagine Dialogue: 0,1:00:52.76,1:00:54.44,EN,,0,0,0,,that really what this function is, Dialogue: 0,1:00:54.78,1:00:56.88,EN,,0,0,0,,is that it does a read every microsecond, Dialogue: 0,1:00:58.86,1:00:59.93,EN,,0,0,0,,and then if there's none there, Dialogue: 0,1:00:59.93,1:01:00.97,EN,,0,0,0,,that's considered an empty one. Dialogue: 0,1:01:00.97,1:01:03.39,EN,,0,0,0,,That's about equivalent to what you said. Dialogue: 0,1:01:03.61,1:01:06.08,EN,,0,0,0,,And yes, you can do that, but that's a glitch. Dialogue: 0,1:01:07.11,1:01:10.14,EN,,0,0,0,,So it's not quite only implementation we're worried about. Dialogue: 0,1:01:10.76,1:01:12.73,EN,,0,0,0,,We're worried about expressive power in the language, Dialogue: 0,1:01:12.75,1:01:14.67,EN,,0,0,0,,and what we're running across is a real mismatch Dialogue: 0,1:01:14.99,1:01:17.44,EN,,0,0,0,,between what we can say easily and what we'd like to say. Dialogue: 0,1:01:19.88,1:01:22.01,EN,,0,0,0,,AUDIENCE: It sounds like where we're getting hung up with that Dialogue: 0,1:01:22.06,1:01:26.09,EN,,0,0,0,,one input from both Bill and Dave at the same time. Dialogue: 0,1:01:26.12,1:01:28.43,EN,,0,0,0,,PROFESSOR: It's not quite one, but it's anything you define. Dialogue: 0,1:01:28.53,1:01:30.57,EN,,0,0,0,,So you can say Dave can go twice as often, Dialogue: 0,1:01:30.72,1:01:32.32,EN,,0,0,0,,but if anything you predefine, Dialogue: 0,1:01:32.68,1:01:33.87,EN,,0,0,0,,it's not the right thing. Dialogue: 0,1:01:36.11,1:01:40.70,EN,,0,0,0,,You can't decide at some particular function of their input requests. Dialogue: 0,1:01:41.93,1:01:43.37,EN,,0,0,0,,Worse yet, I mean, worse yet, Dialogue: 0,1:01:44.12,1:01:45.72,EN,,0,0,0,,there are things that even merge can't do. Dialogue: 0,1:01:47.29,1:01:49.69,EN,,0,0,0,,One thing you might want to do that's even more general is suddenly Dialogue: 0,1:01:50.24,1:01:52.47,EN,,0,0,0,,you add somebody else to this bank account system. Dialogue: 0,1:01:52.47,1:01:54.51,EN,,0,0,0,,You go and you add John to this bank account system. Dialogue: 0,1:01:56.03,1:01:58.89,EN,,0,0,0,,And now there's yet another stream that's going to come into the picture Dialogue: 0,1:01:58.91,1:02:00.70,EN,,0,0,0,,at some time which we haven't prespecified. Dialogue: 0,1:02:02.04,1:02:04.00,EN,,0,0,0,,So that's something even fair merge can't do, Dialogue: 0,1:02:04.00,1:02:08.25,EN,,0,0,0,,and they're things called-- I forget-- manager or something. Dialogue: 0,1:02:08.86,1:02:11.79,EN,,0,0,0,,That's a generalization of fair merge to allow that. Dialogue: 0,1:02:11.79,1:02:13.98,EN,,0,0,0,,There's a whole sort of research discipline saying Dialogue: 0,1:02:14.00,1:02:16.30,EN,,0,0,0,,how far can you push this functional perspective Dialogue: 0,1:02:16.59,1:02:18.72,EN,,0,0,0,,by adding more and more mechanism? Dialogue: 0,1:02:19.58,1:02:21.79,EN,,0,0,0,,And how far does that go before the whole thing breaks down Dialogue: 0,1:02:21.82,1:02:23.40,EN,,0,0,0,,and you might as well been using set anyway. Dialogue: 0,1:02:25.98,1:02:28.00,EN,,0,0,0,,AUDIENCE: But not automatic deposit. Dialogue: 0,1:02:39.32,1:02:40.49,EN,,0,0,0,,PROFESSOR: OK, thank you. ================================================ FILE: Ass/lec7a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 601 Active Line: 612 Video Position: 62464 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:15.79,0:00:17.32,EN,,0,0,0,,PROFESSOR: Well today we're going to learn about something Dialogue: 0,0:00:17.52,0:00:18.41,EN,,0,0,0,,quite amazing. Dialogue: 0,0:00:19.20,0:00:21.88,EN,,0,0,0,,We're going to understand what we mean by a program Dialogue: 0,0:00:22.59,0:00:25.21,EN,,0,0,0,,a little bit more profoundly than we have up till now. Dialogue: 0,0:00:26.80,0:00:29.12,EN,,0,0,0,,Up till now, we've been thinking Dialogue: 0,0:00:29.26,0:00:32.09,EN,,0,0,0,,programs as describing machines. Dialogue: 0,0:00:32.72,0:00:37.21,EN,,0,0,0,,So for example, looking at this still store Dialogue: 0,0:00:37.93,0:00:41.77,EN,,0,0,0,,we see here is a program for factorial. Dialogue: 0,0:00:42.80,0:00:47.31,EN,,0,0,0,,And what it is, is a character string description, if you will, Dialogue: 0,0:00:47.66,0:00:51.98,EN,,0,0,0,,of the wiring diagram of a potentially infinite machine. Dialogue: 0,0:00:52.49,0:00:54.80,EN,,0,0,0,,And we can look at that a little bit and just see the idea. Dialogue: 0,0:00:55.13,0:00:58.20,EN,,0,0,0,,That this is a sort of compact notation which says, Dialogue: 0,0:00:58.54,0:01:00.17,EN,,0,0,0,,if n is 0, the result is one. Dialogue: 0,0:01:00.17,0:01:02.00,EN,,0,0,0,,Well here comes n coming into this machine, Dialogue: 0,0:01:02.33,0:01:03.52,EN,,0,0,0,,and if it's 0, Dialogue: 0,0:01:03.74,0:01:05.20,EN,,0,0,0,,then I control this switch Dialogue: 0,0:01:05.47,0:01:08.20,EN,,0,0,0,,in such a way that the switch allows the output to be one. Dialogue: 0,0:01:09.34,0:01:10.08,EN,,0,0,0,,Otherwise, Dialogue: 0,0:01:10.38,0:01:12.83,EN,,0,0,0,,it's n times factorial of n minus one. Dialogue: 0,0:01:12.97,0:01:15.13,EN,,0,0,0,,Well, I'm computing factorial of n minus one Dialogue: 0,0:01:15.29,0:01:16.68,EN,,0,0,0,,and multiplying that by n, Dialogue: 0,0:01:16.84,0:01:18.91,EN,,0,0,0,,in the case that it's not 0, Dialogue: 0,0:01:18.91,0:01:20.60,EN,,0,0,0,,this switch makes the output come from there. Dialogue: 0,0:01:21.90,0:01:22.32,EN,,0,0,0,,Of course, Dialogue: 0,0:01:22.36,0:01:25.13,EN,,0,0,0,,this is a machine with a potentially infinite number of parts, Dialogue: 0,0:01:25.48,0:01:28.12,EN,,0,0,0,,because factorial occurs within factorial, Dialogue: 0,0:01:28.43,0:01:30.17,EN,,0,0,0,,so we don't know how deep it has to be. Dialogue: 0,0:01:31.07,0:01:33.55,EN,,0,0,0,,But that's basically what our notation Dialogue: 0,0:01:34.22,0:01:37.69,EN,,0,0,0,,for programs really means to us at this point. Dialogue: 0,0:01:38.31,0:01:40.59,EN,,0,0,0,,It's a character string description, if you will, Dialogue: 0,0:01:41.28,0:01:44.16,EN,,0,0,0,,of a wiring diagram that could also be drawn some other way. Dialogue: 0,0:01:44.90,0:01:46.60,EN,,0,0,0,,And, in fact, many people have proposed to me, Dialogue: 0,0:01:46.84,0:01:49.04,EN,,0,0,0,,programming languages look graphical like this. Dialogue: 0,0:01:49.49,0:01:51.80,EN,,0,0,0,,I'm not sure I believe there are many advantages. Dialogue: 0,0:01:52.00,0:01:53.79,EN,,0,0,0,,The major disadvantage, of course, Dialogue: 0,0:01:53.80,0:01:55.63,EN,,0,0,0,,is that it takes up more space on a page, Dialogue: 0,0:01:55.96,0:01:59.95,EN,,0,0,0,,and, therefore, it's harder to pack into a listing or to edit very well. Dialogue: 0,0:02:01.34,0:02:02.16,EN,,0,0,0,,But in any case, Dialogue: 0,0:02:03.58,0:02:05.15,EN,,0,0,0,,there's something very remarkable Dialogue: 0,0:02:05.18,0:02:07.05,EN,,0,0,0,,that can happen in the computation world Dialogue: 0,0:02:07.64,0:02:10.64,EN,,0,0,0,,which is that you can have something called a universal machine. Dialogue: 0,0:02:10.73,0:02:15.24,EN,,0,0,0,,If we look at the second slide, Dialogue: 0,0:02:16.04,0:02:17.18,EN,,0,0,0,,what we see is Dialogue: 0,0:02:18.14,0:02:19.88,EN,,0,0,0,,a special machine called eval. Dialogue: 0,0:02:21.26,0:02:22.86,EN,,0,0,0,,There is a machine called eval, Dialogue: 0,0:02:22.88,0:02:24.24,EN,,0,0,0,,and I'm going to show it to you today. Dialogue: 0,0:02:25.82,0:02:26.67,EN,,0,0,0,,It's very simple. Dialogue: 0,0:02:27.78,0:02:30.80,EN,,0,0,0,,What is remarkable is that it will fit on the blackboard. Dialogue: 0,0:02:33.35,0:02:35.79,EN,,0,0,0,,However, eval is a machine Dialogue: 0,0:02:36.00,0:02:39.84,EN,,0,0,0,,which takes as input a description of another machine. Dialogue: 0,0:02:40.45,0:02:42.12,EN,,0,0,0,,It could take the wiring diagram Dialogue: 0,0:02:42.40,0:02:45.58,EN,,0,0,0,,of a factorial machine as input. Dialogue: 0,0:02:46.49,0:02:47.66,EN,,0,0,0,,Having done so, Dialogue: 0,0:02:48.49,0:02:52.57,EN,,0,0,0,,it becomes a simulator for the factorial machine Dialogue: 0,0:02:53.13,0:02:53.79,EN,,0,0,0,,such that, Dialogue: 0,0:02:54.16,0:02:56.36,EN,,0,0,0,,if you put a six in, out comes a 720. Dialogue: 0,0:02:58.91,0:03:01.68,EN,,0,0,0,,That's a very remarkable sort of machine. Dialogue: 0,0:03:02.13,0:03:03.58,EN,,0,0,0,,And the most amazing part of it Dialogue: 0,0:03:03.77,0:03:05.13,EN,,0,0,0,,it is that it fits on a blackboard. Dialogue: 0,0:03:05.59,0:03:06.65,EN,,0,0,0,,By contrast, Dialogue: 0,0:03:07.32,0:03:10.44,EN,,0,0,0,,one could imagine in the analog electronics world Dialogue: 0,0:03:11.55,0:03:12.86,EN,,0,0,0,,a very different machine. Dialogue: 0,0:03:14.57,0:03:16.33,EN,,0,0,0,,a machine where, a machine Dialogue: 0,0:03:16.52,0:03:18.81,EN,,0,0,0,,which also was, in some sense, universal, Dialogue: 0,0:03:19.26,0:03:23.12,EN,,0,0,0,,where you gave a circuit diagram as one of the inputs, Dialogue: 0,0:03:23.82,0:03:25.74,EN,,0,0,0,,for example, of this little low-pass filter, Dialogue: 0,0:03:26.01,0:03:27.48,EN,,0,0,0,,one-pole low-pass filter. Dialogue: 0,0:03:28.05,0:03:29.53,EN,,0,0,0,,And you can imagine that Dialogue: 0,0:03:29.71,0:03:33.15,EN,,0,0,0,,you could, for example, scan this out-- the scan lines Dialogue: 0,0:03:34.43,0:03:37.13,EN,,0,0,0,,Right? are the signal that's describing Dialogue: 0,0:03:37.39,0:03:40.40,EN,,0,0,0,,what this machine is to simulate-- Dialogue: 0,0:03:40.78,0:03:43.39,EN,,0,0,0,,then the analog of eval which is made out of electrical circuits, Dialogue: 0,0:03:43.68,0:03:45.15,EN,,0,0,0,,which configure itself into a filter Dialogue: 0,0:03:45.18,0:03:48.04,EN,,0,0,0,,has the frequency response specified by the circuit diagram. Dialogue: 0,0:03:49.89,0:03:51.48,EN,,0,0,0,,That's a very hard machine to make, Dialogue: 0,0:03:51.61,0:03:54.06,EN,,0,0,0,,and, surely, there's no chance that I could put it on a blackboard. Dialogue: 0,0:03:55.67,0:03:57.58,EN,,0,0,0,,So we're going to see an amazing thing today. Dialogue: 0,0:03:58.43,0:04:00.81,EN,,0,0,0,,We're going to see, on the blackboard, Dialogue: 0,0:04:01.16,0:04:02.49,EN,,0,0,0,,the universal machine. Dialogue: 0,0:04:02.79,0:04:04.41,EN,,0,0,0,,And we'll see that among other things, Dialogue: 0,0:04:04.52,0:04:05.80,EN,,0,0,0,,it's extremely simple. Dialogue: 0,0:04:06.78,0:04:08.75,EN,,0,0,0,,Now, we're getting very close Dialogue: 0,0:04:09.08,0:04:10.97,EN,,0,0,0,,the real spirit in the computer at this point. Dialogue: 0,0:04:11.28,0:04:14.62,EN,,0,0,0,,So I have to show a certain amount of reverence and respect, Dialogue: 0,0:04:15.18,0:04:17.32,EN,,0,0,0,,so I'm going to wear a suit jacket for the only time Dialogue: 0,0:04:17.52,0:04:19.29,EN,,0,0,0,,that you'll ever see me wear a suit jacket here. Dialogue: 0,0:04:20.47,0:04:22.73,EN,,0,0,0,,And I think I'm also going to Dialogue: 0,0:04:23.55,0:04:26.70,EN,,0,0,0,,put on an appropriate hat for the occasion. Dialogue: 0,0:04:28.78,0:04:31.44,EN,,0,0,0,,Now, this is a lecturer which I have to warn you-- Dialogue: 0,0:04:34.14,0:04:36.91,EN,,0,0,0,,let's see, normally, people under 40 Dialogue: 0,0:04:37.16,0:04:38.49,EN,,0,0,0,,and who don't have several children Dialogue: 0,0:04:38.67,0:04:40.49,EN,,0,0,0,,are advised to be careful. Dialogue: 0,0:04:40.49,0:04:41.96,EN,,0,0,0,,If they're really worried, they should leave. Dialogue: 0,0:04:43.34,0:04:45.56,EN,,0,0,0,,Because there's a certain amount of Dialogue: 0,0:04:45.72,0:04:47.13,EN,,0,0,0,,mysticism that will appear here Dialogue: 0,0:04:47.74,0:04:51.05,EN,,0,0,0,,which may be disturbing and cause trouble in your minds. Dialogue: 0,0:04:51.82,0:04:54.28,EN,,0,0,0,,Well in any case, let's see, Dialogue: 0,0:04:55.71,0:05:01.10,EN,,0,0,0,,I wish to write for you the evaluator for Lisp. Dialogue: 0,0:05:02.51,0:05:04.28,EN,,0,0,0,,Now the evaluator isn't very complicated. Dialogue: 0,0:05:05.02,0:05:07.63,EN,,0,0,0,,It's very much like all the programs we've seen already. Dialogue: 0,0:05:08.24,0:05:09.48,EN,,0,0,0,,That's the amazing part of it. Dialogue: 0,0:05:10.86,0:05:13.10,EN,,0,0,0,,It's going to be-- and I'm going to write it right here-- Dialogue: 0,0:05:15.28,0:05:16.62,EN,,0,0,0,,it's a program called eval. Dialogue: 0,0:05:22.90,0:05:26.24,EN,,0,0,0,,And it's a procedure of two arguments Dialogue: 0,0:05:26.28,0:05:29.44,EN,,0,0,0,,expression and an environment. Dialogue: 0,0:05:31.86,0:05:33.79,EN,,0,0,0,,And like every interesting procedure, Dialogue: 0,0:05:34.01,0:05:35.13,EN,,0,0,0,,it's a case analysis. Dialogue: 0,0:05:40.46,0:05:41.87,EN,,0,0,0,,But before I start on this, Dialogue: 0,0:05:42.52,0:05:43.90,EN,,0,0,0,,I want to tell you some things. Dialogue: 0,0:05:44.44,0:05:46.06,EN,,0,0,0,,The program we're going to write on the blackboard Dialogue: 0,0:05:46.56,0:05:50.24,EN,,0,0,0,,is ugly, dirty, disgusting, Dialogue: 0,0:05:50.94,0:05:53.16,EN,,0,0,0,,not the way I would write this is a professional. Dialogue: 0,0:05:54.32,0:05:56.57,EN,,0,0,0,,It is written with concrete syntax, Dialogue: 0,0:05:57.24,0:05:58.83,EN,,0,0,0,,meaning you've got really to use lots of CARs and CDRs Dialogue: 0,0:05:58.84,0:06:00.62,EN,,0,0,0,,which is exactly what I told you not to do. Dialogue: 0,0:06:02.94,0:06:05.61,EN,,0,0,0,,That's on purpose in this case, Dialogue: 0,0:06:06.11,0:06:09.02,EN,,0,0,0,,because I want it to be small, compact, Dialogue: 0,0:06:09.34,0:06:10.40,EN,,0,0,0,,fit on the blackboard Dialogue: 0,0:06:10.43,0:06:11.85,EN,,0,0,0,,so you can get the whole thing. Dialogue: 0,0:06:12.42,0:06:14.80,EN,,0,0,0,,So I don't want to use long names like I normally use. Dialogue: 0,0:06:15.60,0:06:17.29,EN,,0,0,0,,I want to use CAR-CDR because it's short. Dialogue: 0,0:06:18.06,0:06:20.78,EN,,0,0,0,,Okay, I wanna, it's a whole, that's a trade-off. Dialogue: 0,0:06:20.89,0:06:22.81,EN,,0,0,0,,I don't want you writing programs like this. Dialogue: 0,0:06:23.57,0:06:25.08,EN,,0,0,0,,This is purely for an effect. Dialogue: 0,0:06:25.85,0:06:27.61,EN,,0,0,0,,Now, you're going to have to work a little harder to read it, Dialogue: 0,0:06:27.77,0:06:30.19,EN,,0,0,0,,but I'm going to try to make it clear as I'm writing it. Dialogue: 0,0:06:31.27,0:06:34.40,EN,,0,0,0,,I'm also-- this is a pretty much complete interpreter, Dialogue: 0,0:06:34.51,0:06:36.24,EN,,0,0,0,,but there's going to be room for putting in more things-- Dialogue: 0,0:06:36.25,0:06:38.60,EN,,0,0,0,,I'm going to leave out definition and assignment, Dialogue: 0,0:06:39.10,0:06:42.41,EN,,0,0,0,,just because they are not essential, Dialogue: 0,0:06:42.88,0:06:46.46,EN,,0,0,0,,and a, for a mathematical reason I'll show you later Dialogue: 0,0:06:46.92,0:06:49.96,EN,,0,0,0,,and also they take up more space. Dialogue: 0,0:06:51.88,0:06:53.64,EN,,0,0,0,,But, in any case, what do we have to do? Dialogue: 0,0:06:53.95,0:06:55.66,EN,,0,0,0,,We have to do a dispatch Dialogue: 0,0:06:56.09,0:06:57.90,EN,,0,0,0,,which breaks the types of expressions up Dialogue: 0,0:06:58.28,0:07:00.38,EN,,0,0,0,,into particular classes. Dialogue: 0,0:07:01.72,0:07:03.26,EN,,0,0,0,,Okay? So that's what we're going to have here. Dialogue: 0,0:07:03.82,0:07:05.15,EN,,0,0,0,,Well, what expressions are there? Dialogue: 0,0:07:05.15,0:07:06.36,EN,,0,0,0,,Let's look at the kinds of expressions. Dialogue: 0,0:07:06.81,0:07:09.60,EN,,0,0,0,,We can have things like the numeral three. Dialogue: 0,0:07:10.42,0:07:11.58,EN,,0,0,0,,What do I want that to do? Dialogue: 0,0:07:12.72,0:07:14.75,EN,,0,0,0,,I can make choices, but I think right now, Dialogue: 0,0:07:15.05,0:07:16.20,EN,,0,0,0,,I want it to be a three. Dialogue: 0,0:07:17.05,0:07:17.88,EN,,0,0,0,,That's what I want. Dialogue: 0,0:07:18.72,0:07:19.69,EN,,0,0,0,,So that's easy enough. Dialogue: 0,0:07:20.03,0:07:22.91,EN,,0,0,0,,That means I want, if the thing is a number, Dialogue: 0,0:07:27.29,0:07:31.68,EN,,0,0,0,,that I want the expression itself as the answer. Dialogue: 0,0:07:35.42,0:07:36.76,EN,,0,0,0,,Now the next possibility Dialogue: 0,0:07:36.89,0:07:38.86,EN,,0,0,0,,is things that we represent as symbols. Dialogue: 0,0:07:39.39,0:07:46.75,EN,,0,0,0,,Examples of symbols are things like x, n, eval, number, x. Dialogue: 0,0:07:48.01,0:07:49.18,EN,,0,0,0,,What do I mean them to be? Dialogue: 0,0:07:50.16,0:07:51.63,EN,,0,0,0,,Those are things that stand for other things. Dialogue: 0,0:07:51.63,0:07:53.23,EN,,0,0,0,,Those are the variables of our language. Dialogue: 0,0:07:54.77,0:07:56.88,EN,,0,0,0,,And so I want to be able to say, for example, Dialogue: 0,0:07:57.05,0:08:01.04,EN,,0,0,0,,that x, for example, transforms to it's value which might be three. Dialogue: 0,0:08:02.64,0:08:05.76,EN,,0,0,0,,Or I might ask something like car. Dialogue: 0,0:08:07.76,0:08:09.40,EN,,0,0,0,,I want to have as its value-- Dialogue: 0,0:08:09.63,0:08:11.34,EN,,0,0,0,,be something like some procedure, Dialogue: 0,0:08:16.51,0:08:18.43,EN,,0,0,0,,which I don't know what is inside there, Dialogue: 0,0:08:18.64,0:08:21.15,EN,,0,0,0,,perhaps a machine language code or something like that. Dialogue: 0,0:08:22.84,0:08:24.27,EN,,0,0,0,,Ok? So, well, that's easy enough. Dialogue: 0,0:08:24.43,0:08:26.89,EN,,0,0,0,,I'm going to push that off on someone else. Dialogue: 0,0:08:27.80,0:08:28.89,EN,,0,0,0,,If something is a symbol, Dialogue: 0,0:08:30.80,0:08:32.48,EN,,0,0,0,,if the expression is a symbol, Dialogue: 0,0:08:33.42,0:08:34.88,EN,,0,0,0,,then I want the answer to be the result, Dialogue: 0,0:08:34.91,0:08:40.24,EN,,0,0,0,,looking up the expression in the environment. Dialogue: 0,0:08:46.48,0:08:48.99,EN,,0,0,0,,Now the environment is a dictionary Dialogue: 0,0:08:49.96,0:08:54.06,EN,,0,0,0,,which maps the symbol names to their values. Dialogue: 0,0:08:54.28,0:08:55.16,EN,,0,0,0,,And that's all it is. Dialogue: 0,0:08:56.28,0:08:57.20,EN,,0,0,0,,How it's done? Dialogue: 0,0:08:57.53,0:08:58.52,EN,,0,0,0,,Well, we'll see that later. Dialogue: 0,0:08:59.68,0:09:00.57,EN,,0,0,0,,It's very easy. Dialogue: 0,0:09:01.67,0:09:04.28,EN,,0,0,0,,It's easy to make data structures that are tables of various sorts. Dialogue: 0,0:09:04.84,0:09:05.74,EN,,0,0,0,,But it's only a table, Dialogue: 0,0:09:05.77,0:09:07.56,EN,,0,0,0,,and this is the access routine for some table. Dialogue: 0,0:09:09.55,0:09:10.81,EN,,0,0,0,,Ok? Well, the next thing, Dialogue: 0,0:09:11.31,0:09:12.56,EN,,0,0,0,,another kind of expression-- Dialogue: 0,0:09:12.67,0:09:15.56,EN,,0,0,0,,you have things that are described constants that are not numbers, Dialogue: 0,0:09:16.06,0:09:17.43,EN,,0,0,0,,like 'foo. Dialogue: 0,0:09:20.17,0:09:21.29,EN,,0,0,0,,Well, for my convenience, Dialogue: 0,0:09:21.31,0:09:23.36,EN,,0,0,0,,I want to syntactically transform that Dialogue: 0,0:09:24.73,0:09:26.80,EN,,0,0,0,,into a list structure which is, Dialogue: 0,0:09:26.84,0:09:31.52,EN,,0,0,0,,which is, quote foo. Dialogue: 0,0:09:33.72,0:09:37.18,EN,,0,0,0,,Or it's -- A quoted object, whatever it is, Dialogue: 0,0:09:38.35,0:09:40.83,EN,,0,0,0,,is going to be actually an abbreviation, Dialogue: 0,0:09:41.04,0:09:42.59,EN,,0,0,0,,which is not part of the evaluator Dialogue: 0,0:09:43.21,0:09:44.46,EN,,0,0,0,,but happens somewhere else, Dialogue: 0,0:09:44.75,0:09:47.79,EN,,0,0,0,,an abbreviation for an expression that looks like this. Dialogue: 0,0:09:48.78,0:09:50.48,EN,,0,0,0,,This way, I can test for Dialogue: 0,0:09:50.57,0:09:53.12,EN,,0,0,0,,the type of the expression as being a quotation Dialogue: 0,0:09:53.31,0:09:55.95,EN,,0,0,0,,by examining the car of the expression. Dialogue: 0,0:09:58.46,0:10:01.08,EN,,0,0,0,,So I'm not going to worry about that in the evaluator. Dialogue: 0,0:10:01.65,0:10:02.68,EN,,0,0,0,,It's happening somewhere earlier Dialogue: 0,0:10:02.70,0:10:03.96,EN,,0,0,0,,in the reader or something. Dialogue: 0,0:10:05.54,0:10:15.04,EN,,0,0,0,,If the expression of the expression is quote, Dialogue: 0,0:10:18.27,0:10:19.10,EN,,0,0,0,,then what I want, Dialogue: 0,0:10:19.63,0:10:25.13,EN,,0,0,0,,I want quote foo to itself evaluate to foo. Dialogue: 0,0:10:25.14,0:10:25.95,EN,,0,0,0,,It's a constant. Dialogue: 0,0:10:27.53,0:10:28.92,EN,,0,0,0,,This is just a way of saying Dialogue: 0,0:10:29.08,0:10:30.73,EN,,0,0,0,,that this evaluates to itself. Dialogue: 0,0:10:31.79,0:10:33.66,EN,,0,0,0,,Ok? So thats the. What is that? Dialogue: 0,0:10:33.66,0:10:36.36,EN,,0,0,0,,That's the first of the second of the list. Dialogue: 0,0:10:36.59,0:10:37.58,EN,,0,0,0,,That's the second of the list. Dialogue: 0,0:10:38.49,0:10:40.32,EN,,0,0,0,,The second element of the list is it's CADR. Dialogue: 0,0:10:41.28,0:10:42.38,EN,,0,0,0,,So I'm just going to write here, CADR. Dialogue: 0,0:10:51.08,0:10:52.35,EN,,0,0,0,,OK? What else do we have here? Dialogue: 0,0:10:52.51,0:10:53.80,EN,,0,0,0,,We have lambda expressions, Dialogue: 0,0:10:55.00,0:11:03.29,EN,,0,0,0,,for example, lambda of x plus x y. Dialogue: 0,0:11:04.16,0:11:06.33,EN,,0,0,0,,Well, I going have to have some representation for the procedure Dialogue: 0,0:11:06.33,0:11:07.85,EN,,0,0,0,,which is the value of an expression, Dialogue: 0,0:11:08.11,0:11:09.08,EN,,0,0,0,,of a lambda expression. Dialogue: 0,0:11:09.60,0:11:12.62,EN,,0,0,0,,The procedure here is not the expression lambda x. Dialogue: 0,0:11:13.13,0:11:15.56,EN,,0,0,0,,That's the description of it, the textual description. Dialogue: 0,0:11:16.41,0:11:18.33,EN,,0,0,0,,However, what what I going to expect to see here Dialogue: 0,0:11:18.56,0:11:21.20,EN,,0,0,0,,is something which contains an environment as one of its parts Dialogue: 0,0:11:23.23,0:11:25.36,EN,,0,0,0,,if I'm implementing a lexical language. Dialogue: 0,0:11:25.84,0:11:29.07,EN,,0,0,0,,And so what I'd like to see Dialogue: 0,0:11:29.20,0:11:30.67,EN,,0,0,0,,is some type flags. Dialogue: 0,0:11:30.70,0:11:33.90,EN,,0,0,0,,I'm going to have to be able to distinguish procedures later, Dialogue: 0,0:11:34.30,0:11:36.59,EN,,0,0,0,,procedures which were produced by lambdas, Dialogue: 0,0:11:36.81,0:11:38.03,EN,,0,0,0,,from ones that may be primitive. Dialogue: 0,0:11:39.06,0:11:41.96,EN,,0,0,0,,And so I'm going to have some flag, Dialogue: 0,0:11:41.98,0:11:43.56,EN,,0,0,0,,which I'll just arbitrarily call closure, Dialogue: 0,0:11:43.56,0:11:45.10,EN,,0,0,0,,just for historical reasons. Dialogue: 0,0:11:47.68,0:11:49.60,EN,,0,0,0,,Now, to say what parts of this are important. Dialogue: 0,0:11:49.92,0:11:51.12,EN,,0,0,0,,I'm going to need to know Dialogue: 0,0:11:51.24,0:11:52.92,EN,,0,0,0,,the bound variable list and the body. Dialogue: 0,0:11:54.22,0:11:55.40,EN,,0,0,0,,Well, that's the CDR of this, Dialogue: 0,0:11:56.09,0:12:01.85,EN,,0,0,0,,so it's going to be x and plus x y and some environment. Dialogue: 0,0:12:03.04,0:12:03.87,EN,,0,0,0,,and some environment. Dialogue: 0,0:12:08.17,0:12:12.20,EN,,0,0,0,,Now this is not something that users should ever see, Dialogue: 0,0:12:13.53,0:12:16.19,EN,,0,0,0,,this is purely a representation, internally, Dialogue: 0,0:12:16.76,0:12:18.30,EN,,0,0,0,,for a procedure object. Dialogue: 0,0:12:18.52,0:12:20.52,EN,,0,0,0,,It contains a bound variable list, Dialogue: 0,0:12:20.70,0:12:22.62,EN,,0,0,0,,a body, and an environment, Dialogue: 0,0:12:23.53,0:12:25.80,EN,,0,0,0,,and some type tag saying, I am a procedure. Dialogue: 0,0:12:26.34,0:12:27.37,EN,,0,0,0,,I'm going to make one now. Dialogue: 0,0:12:28.08,0:12:38.72,EN,,0,0,0,,So if the CAR of the expression is quote lambda, Dialogue: 0,0:12:43.47,0:12:44.81,EN,,0,0,0,,then what I'm going to put here Dialogue: 0,0:12:45.64,0:12:51.84,EN,,0,0,0,,is-- I'm going to make a list of closure, Dialogue: 0,0:12:55.15,0:13:00.73,EN,,0,0,0,,the CDR of the procedure description Dialogue: 0,0:13:01.56,0:13:02.97,EN,,0,0,0,,was everything except the lambda, Dialogue: 0,0:13:07.74,0:13:08.86,EN,,0,0,0,,and the current environment. Dialogue: 0,0:13:10.25,0:13:15.32,EN,,0,0,0,,This implements the rule for environments in the environment model. Dialogue: 0,0:13:15.45,0:13:18.52,EN,,0,0,0,,It has to do with construction of procedures from lambda expressions. Dialogue: 0,0:13:19.40,0:13:20.97,EN,,0,0,0,,The environment that was around Dialogue: 0,0:13:21.48,0:13:24.32,EN,,0,0,0,,at the time the evaluator encountered the lambda expression Dialogue: 0,0:13:25.04,0:13:28.46,EN,,0,0,0,,is the environment where the lambda expression gets Dialogue: 0,0:13:28.68,0:13:31.77,EN,,0,0,0,,where the procedure resulting interprets it's free variables. Dialogue: 0,0:13:34.72,0:13:35.82,EN,,0,0,0,,So that's part of that. Dialogue: 0,0:13:35.92,0:13:37.55,EN,,0,0,0,,And so we have to capture that environment Dialogue: 0,0:13:37.56,0:13:38.86,EN,,0,0,0,,as part of the procedure object. Dialogue: 0,0:13:39.21,0:13:40.62,EN,,0,0,0,,And we'll see how that gets used later. Dialogue: 0,0:13:42.03,0:13:43.77,EN,,0,0,0,,There are also conditional expressions Dialogue: 0,0:13:44.59,0:13:52.81,EN,,0,0,0,,of things like COND of say, p one, e one, p two, e two. Dialogue: 0,0:13:54.40,0:13:56.09,EN,,0,0,0,,Where this is a predicate, Dialogue: 0,0:13:56.35,0:13:58.43,EN,,0,0,0,,a predicate is a thing that is either true or false, Dialogue: 0,0:13:58.99,0:14:01.76,EN,,0,0,0,,and the expression to be evaluated if the predicate is true. Dialogue: 0,0:14:03.44,0:14:06.08,EN,,0,0,0,,A set of clauses, if you will, that's the name for such a thing. Dialogue: 0,0:14:06.79,0:14:09.36,EN,,0,0,0,,So I'm going put that somewhere else. Dialogue: 0,0:14:09.36,0:14:11.56,EN,,0,0,0,,We're going to worry about that in another piece of code. Dialogue: 0,0:14:12.42,0:14:21.28,EN,,0,0,0,,So EQ-- if the CAR of the expression is COND, Dialogue: 0,0:14:24.00,0:14:26.84,EN,,0,0,0,,then I'm going to do nothing more than evaluate the COND, Dialogue: 0,0:14:30.20,0:14:31.42,EN,,0,0,0,,the CDR of the expression. Dialogue: 0,0:14:34.40,0:14:38.49,EN,,0,0,0,,That's all the clauses in the environment that I'm given. Dialogue: 0,0:14:41.43,0:14:42.60,EN,,0,0,0,,Well, there's one more case, Dialogue: 0,0:14:44.09,0:14:48.22,EN,,0,0,0,,arbitrary thing like the sum of x and three, Dialogue: 0,0:14:50.62,0:14:53.95,EN,,0,0,0,,where this is an operator applied to operands, Dialogue: 0,0:14:55.13,0:14:56.59,EN,,0,0,0,,and there's nothing special about it. Dialogue: 0,0:14:56.59,0:14:59.63,EN,,0,0,0,,It's not one of the special cases, the special forms. Dialogue: 0,0:14:59.85,0:15:01.42,EN,,0,0,0,,These are the special forms. Dialogue: 0,0:15:09.65,0:15:12.12,EN,,0,0,0,,And if I were writing here a professional program, again, Dialogue: 0,0:15:12.36,0:15:14.17,EN,,0,0,0,,I would somehow make this data directed. Dialogue: 0,0:15:14.48,0:15:16.52,EN,,0,0,0,,So there wouldn't be a sequence of conditionals here, Dialogue: 0,0:15:16.65,0:15:18.20,EN,,0,0,0,,there'd be a dispatch on some bits Dialogue: 0,0:15:19.42,0:15:22.25,EN,,0,0,0,,if I were trying to do this in a more professional way. Dialogue: 0,0:15:22.36,0:15:24.14,EN,,0,0,0,,So that, in fact, I can add to the thing Dialogue: 0,0:15:24.68,0:15:26.38,EN,,0,0,0,,without changing my program much. Dialogue: 0,0:15:26.71,0:15:28.46,EN,,0,0,0,,So, for example, they would run fast, Dialogue: 0,0:15:29.04,0:15:30.43,EN,,0,0,0,,but I'm not worried about that. Dialogue: 0,0:15:31.28,0:15:33.98,EN,,0,0,0,,Here we're trying to look at this in its entirety. Dialogue: 0,0:15:35.07,0:15:35.80,EN,,0,0,0,,So it's else. Dialogue: 0,0:15:37.69,0:15:38.56,EN,,0,0,0,,Well, what do we do? Dialogue: 0,0:15:38.56,0:15:41.23,EN,,0,0,0,,In this case, I have to somehow do an addition. Dialogue: 0,0:15:44.35,0:15:46.16,EN,,0,0,0,,Well, I could find out what the plus is. Dialogue: 0,0:15:46.84,0:15:49.29,EN,,0,0,0,,I have to find out what the x and the three are. Dialogue: 0,0:15:50.55,0:15:53.96,EN,,0,0,0,,And then I have to apply the result of finding what the plus is Dialogue: 0,0:15:54.43,0:15:57.00,EN,,0,0,0,,to the result of finding out what the x and the three are. Dialogue: 0,0:15:58.11,0:15:59.39,EN,,0,0,0,,We'll have a name for that. Dialogue: 0,0:15:59.87,0:16:09.55,EN,,0,0,0,,So I'm going to apply the result of evaluating the CAR Dialogue: 0,0:16:11.20,0:16:12.14,EN,,0,0,0,,of the expression-- Dialogue: 0,0:16:13.21,0:16:15.50,EN,,0,0,0,,the car of the expression is the operator-- Dialogue: 0,0:16:17.20,0:16:18.51,EN,,0,0,0,,in the environment given. Dialogue: 0,0:16:20.51,0:16:22.89,EN,,0,0,0,,So evaluating the operator gets me the procedure. Dialogue: 0,0:16:24.05,0:16:26.78,EN,,0,0,0,,Now I have to evaluate all the operands to get the arguments. Dialogue: 0,0:16:27.29,0:16:28.22,EN,,0,0,0,,I'll call that EVLIST, Dialogue: 0,0:16:31.26,0:16:35.53,EN,,0,0,0,,the CDR of the operands, of the expression, Dialogue: 0,0:16:36.76,0:16:39.00,EN,,0,0,0,,with respect to the environment. Dialogue: 0,0:16:41.94,0:16:43.13,EN,,0,0,0,,EVLIST will come up later-- Dialogue: 0,0:16:43.26,0:16:48.07,EN,,0,0,0,,EVLIST, apply, COND pair, COND, lambda, define. Dialogue: 0,0:16:50.90,0:16:52.33,EN,,0,0,0,,So that what you are seeing here Dialogue: 0,0:16:52.67,0:16:56.11,EN,,0,0,0,,is pretty much all there is in the evaluator itself. Dialogue: 0,0:16:56.49,0:17:01.00,EN,,0,0,0,,It's the case dispatch on the type of the expression Dialogue: 0,0:17:01.24,0:17:02.11,EN,,0,0,0,,with the default Dialogue: 0,0:17:04.99,0:17:07.95,EN,,0,0,0,,being a general application or a combination. Dialogue: 0,0:17:17.52,0:17:19.52,EN,,0,0,0,,Now there is lots of things we haven't defined yet. Dialogue: 0,0:17:20.08,0:17:21.60,EN,,0,0,0,,Let's just look at them and see what they are. Dialogue: 0,0:17:21.78,0:17:24.12,EN,,0,0,0,,We're going to have to do this later, evcond. Dialogue: 0,0:17:25.48,0:17:26.67,EN,,0,0,0,,We have to write apply. Dialogue: 0,0:17:27.57,0:17:28.62,EN,,0,0,0,,We're going to have to write EVLIST. Dialogue: 0,0:17:28.94,0:17:30.20,EN,,0,0,0,,We're going to write LOOKUP. Dialogue: 0,0:17:31.79,0:17:33.43,EN,,0,0,0,,I think that's everything, isn't there? Dialogue: 0,0:17:33.43,0:17:35.16,EN,,0,0,0,,Everything else is something which is simple, Dialogue: 0,0:17:35.16,0:17:37.18,EN,,0,0,0,,or primitive, or something like that. Dialogue: 0,0:17:38.57,0:17:39.48,EN,,0,0,0,,And, of course, Dialogue: 0,0:17:39.69,0:17:42.06,EN,,0,0,0,,we could many more special forms here, Dialogue: 0,0:17:42.25,0:17:44.45,EN,,0,0,0,,but that would be a bad idea in general in a language. Dialogue: 0,0:17:44.45,0:17:45.92,EN,,0,0,0,,You make a language very complicated Dialogue: 0,0:17:46.00,0:17:47.48,EN,,0,0,0,,by putting a lot of things in there. Dialogue: 0,0:17:47.69,0:17:50.35,EN,,0,0,0,,The number of reserve words that should exist in a language Dialogue: 0,0:17:50.76,0:17:53.61,EN,,0,0,0,,should be no more than a person could remember on his fingers and toes. Dialogue: 0,0:17:54.16,0:17:55.53,EN,,0,0,0,,And I get very upset with languages Dialogue: 0,0:17:55.56,0:17:58.20,EN,,0,0,0,,which have hundreds of reserve words. Dialogue: 0,0:17:59.41,0:18:00.71,EN,,0,0,0,,But that's where the reserve words go. Dialogue: 0,0:18:03.15,0:18:06.54,EN,,0,0,0,,Okay. Well, now let's get to the next part of this, Dialogue: 0,0:18:06.56,0:18:07.69,EN,,0,0,0,,the kernel, apply. Dialogue: 0,0:18:09.64,0:18:10.75,EN,,0,0,0,,What else is this doing? Dialogue: 0,0:18:11.59,0:18:17.53,EN,,0,0,0,,Well, apply's job is to take a procedure and apply it to its arguments Dialogue: 0,0:18:17.66,0:18:20.68,EN,,0,0,0,,after both have been evaluated to come up with a procedure and the arguments Dialogue: 0,0:18:20.91,0:18:23.85,EN,,0,0,0,,rather the operator symbols and the operand symbols, Dialogue: 0,0:18:24.09,0:18:26.96,EN,,0,0,0,,whatever they are-- symbolic expressions. Dialogue: 0,0:18:33.27,0:18:35.08,EN,,0,0,0,,So we will define apply Dialogue: 0,0:18:38.35,0:18:40.65,EN,,0,0,0,,to be a procedure of two arguments, Dialogue: 0,0:18:40.75,0:18:43.44,EN,,0,0,0,,a procedure and arguments. Dialogue: 0,0:18:47.24,0:18:48.12,EN,,0,0,0,,And what does it do? Dialogue: 0,0:18:48.14,0:18:49.55,EN,,0,0,0,,It does nothing very complicated. Dialogue: 0,0:18:49.93,0:18:50.78,EN,,0,0,0,,It's got two cases. Dialogue: 0,0:18:53.58,0:18:55.16,EN,,0,0,0,,Either the procedure is primitive-- Dialogue: 0,0:19:03.42,0:19:06.41,EN,,0,0,0,,And I don't know exactly how that is done. Dialogue: 0,0:19:06.86,0:19:10.24,EN,,0,0,0,,It's possible there's some type information Dialogue: 0,0:19:10.38,0:19:12.41,EN,,0,0,0,,just like we made closure for, here, Dialogue: 0,0:19:12.68,0:19:15.05,EN,,0,0,0,,being the description of the type of a compound thing-- Dialogue: 0,0:19:16.33,0:19:17.79,EN,,0,0,0,,OK? probably so. Dialogue: 0,0:19:18.55,0:19:20.20,EN,,0,0,0,,But it is not essential how that works, Dialogue: 0,0:19:20.68,0:19:22.01,EN,,0,0,0,,in fact, it turns out, Dialogue: 0,0:19:22.19,0:19:23.85,EN,,0,0,0,,as you probably know or have deduced, Dialogue: 0,0:19:23.87,0:19:25.47,EN,,0,0,0,,that you don't need any primitives anyway. Dialogue: 0,0:19:27.35,0:19:29.28,EN,,0,0,0,,You can compute anything because without Dialogue: 0,0:19:30.46,0:19:33.19,EN,,0,0,0,,because some of the lambda that I've been playing with. Dialogue: 0,0:19:33.61,0:19:34.76,EN,,0,0,0,,But it's nice to have them. Dialogue: 0,0:19:34.81,0:19:36.27,EN,,0,0,0,,So here we're going to do some magic Dialogue: 0,0:19:36.30,0:19:37.47,EN,,0,0,0,,which I'm not going to explain. Dialogue: 0,0:19:38.06,0:19:41.44,EN,,0,0,0,,Go to machine language, apply primop. Dialogue: 0,0:19:42.91,0:19:43.80,EN,,0,0,0,,Here's how it adds. Dialogue: 0,0:19:44.78,0:19:46.10,EN,,0,0,0,,Execute an add instruction. Dialogue: 0,0:19:50.62,0:19:52.11,EN,,0,0,0,,However, the interesting part of a language Dialogue: 0,0:19:52.14,0:19:54.27,EN,,0,0,0,,is the glue by which the primitives are glued together. Dialogue: 0,0:19:54.91,0:19:55.90,EN,,0,0,0,,So let's look at that. Dialogue: 0,0:19:56.91,0:19:58.38,EN,,0,0,0,,Well, the other possibility Dialogue: 0,0:19:58.75,0:20:04.12,EN,,0,0,0,,this is a compound made up by executing a lambda expression, Dialogue: 0,0:20:04.97,0:20:07.05,EN,,0,0,0,,this is a compound procedure. Dialogue: 0,0:20:07.62,0:20:09.36,EN,,0,0,0,,Well, we'll check its type. Dialogue: 0,0:20:10.11,0:20:17.07,EN,,0,0,0,,If it is closure, Dialogue: 0,0:20:20.51,0:20:24.09,EN,,0,0,0,,if it's one of those, then I have to do an eval of the body. Dialogue: 0,0:20:24.19,0:20:27.39,EN,,0,0,0,,The way I do this, the way I deal with this at all Dialogue: 0,0:20:28.08,0:20:31.69,EN,,0,0,0,,is the way I evaluate the application of a procedure to its arguments, Dialogue: 0,0:20:31.72,0:20:33.71,EN,,0,0,0,,is by evaluating the body of the procedure Dialogue: 0,0:20:34.19,0:20:37.80,EN,,0,0,0,,in the environment resulting from extending the environment of the procedure Dialogue: 0,0:20:37.92,0:20:40.48,EN,,0,0,0,,with the bindings of the formal parameters Dialogue: 0,0:20:41.02,0:20:43.68,EN,,0,0,0,,of the procedure to the arguments that were passed to it. Dialogue: 0,0:20:46.70,0:20:47.87,EN,,0,0,0,,That was a long sentence. Dialogue: 0,0:20:51.13,0:20:52.16,EN,,0,0,0,,Well that's easy enough. Dialogue: 0,0:20:52.82,0:20:54.48,EN,,0,0,0,,Now here's going to be a lot of CAR-CDRing. Dialogue: 0,0:20:56.46,0:20:58.11,EN,,0,0,0,,I have to get the body of the procedure. Dialogue: 0,0:20:59.40,0:21:02.30,EN,,0,0,0,,Where's the body of the procedure in here? Dialogue: 0,0:21:02.96,0:21:04.08,EN,,0,0,0,,Well here's the CAR, Dialogue: 0,0:21:04.49,0:21:06.13,EN,,0,0,0,,here's the CDR is the whole rest of this. Dialogue: 0,0:21:06.13,0:21:06.96,EN,,0,0,0,,So here's the CADR. Dialogue: 0,0:21:07.40,0:21:09.45,EN,,0,0,0,,And so I see, what I have here is the body Dialogue: 0,0:21:09.45,0:21:13.04,EN,,0,0,0,,is the second element of the second element of the procedure. Dialogue: 0,0:21:13.20,0:21:15.15,EN,,0,0,0,,So it's the CADR of the CADR or the CADADR. Dialogue: 0,0:21:19.17,0:21:27.68,EN,,0,0,0,,It's the C-A-D-A-D-R, CADADR of the procedure. Dialogue: 0,0:21:30.26,0:21:31.56,EN,,0,0,0,,To evaluate the body Dialogue: 0,0:21:31.98,0:21:36.48,EN,,0,0,0,,in the result of binding that's making up more environment, Dialogue: 0,0:21:38.09,0:21:42.06,EN,,0,0,0,,well I need the formal parameters of the of the procedure, Dialogue: 0,0:21:42.06,0:21:42.72,EN,,0,0,0,,what is that? Dialogue: 0,0:21:43.50,0:21:45.13,EN,,0,0,0,,That's the CAR of the CADR. Dialogue: 0,0:21:46.52,0:21:48.78,EN,,0,0,0,,OK? It's horrible isn't it? Dialogue: 0,0:21:52.65,0:21:53.63,EN,,0,0,0,,--of the procedure. Dialogue: 0,0:21:55.44,0:22:00.86,EN,,0,0,0,,Bind that to the arguments that were passed in the environment, Dialogue: 0,0:22:00.89,0:22:04.14,EN,,0,0,0,,which is passed also as part of the procedure. Dialogue: 0,0:22:04.54,0:22:07.90,EN,,0,0,0,,Well, that's the CAR of the CDR of the CDR of this, Dialogue: 0,0:22:09.79,0:22:16.62,EN,,0,0,0,,CADDR, of the procedure. Dialogue: 0,0:22:20.29,0:22:24.96,EN,,0,0,0,,Bind, eval, pair, COND, lamda, define-- Dialogue: 0,0:22:26.14,0:22:29.68,EN,,0,0,0,,Now, of course, if I were being really a neat character, Dialogue: 0,0:22:29.87,0:22:31.34,EN,,0,0,0,,and I was being very careful, Dialogue: 0,0:22:32.24,0:22:34.12,EN,,0,0,0,,I would actually put an extra case here Dialogue: 0,0:22:34.38,0:22:35.98,EN,,0,0,0,,for checking for certain errors like, Dialogue: 0,0:22:36.17,0:22:38.41,EN,,0,0,0,,did you try to apply one to an argument? Dialogue: 0,0:22:39.00,0:22:41.69,EN,,0,0,0,,You get a undefined procedure type. Dialogue: 0,0:22:42.57,0:22:44.09,EN,,0,0,0,,So I may as well do that anyway. Dialogue: 0,0:22:45.80,0:22:55.96,EN,,0,0,0,,--else, some sort of error, like that. Dialogue: 0,0:22:57.61,0:23:01.61,EN,,0,0,0,,Now, of course, again, in some sort of more real system, Dialogue: 0,0:23:02.56,0:23:04.22,EN,,0,0,0,,written for professional reasons, Dialogue: 0,0:23:05.32,0:23:08.00,EN,,0,0,0,,this would be written with a case analysis Dialogue: 0,0:23:08.36,0:23:09.90,EN,,0,0,0,,done by some sort of dispatch. Dialogue: 0,0:23:10.75,0:23:12.68,EN,,0,0,0,,Over here, I would probably have other cases Dialogue: 0,0:23:12.70,0:23:14.14,EN,,0,0,0,,like, is this compiled code? Dialogue: 0,0:23:16.22,0:23:16.84,EN,,0,0,0,,It's very important. Dialogue: 0,0:23:16.88,0:23:18.35,EN,,0,0,0,,I might have distinguished the kind of code Dialogue: 0,0:23:18.38,0:23:22.33,EN,,0,0,0,,that's produced by a directly evaluating a lambda in interpretation Dialogue: 0,0:23:22.94,0:23:25.87,EN,,0,0,0,,from code that was produced by somebody's compiler or something like that. Dialogue: 0,0:23:26.11,0:23:27.23,EN,,0,0,0,,And we'll talk about that later. Dialogue: 0,0:23:27.23,0:23:29.61,EN,,0,0,0,,Or is this a piece Fortran program I have to go off and execute. Dialogue: 0,0:23:30.51,0:23:32.51,EN,,0,0,0,,It's a perfectly possible thing, at this point, to do that. Dialogue: 0,0:23:32.92,0:23:36.41,EN,,0,0,0,,In fact, in this concrete syntax evaluator I'm writing here, Dialogue: 0,0:23:37.45,0:23:40.86,EN,,0,0,0,,there's an assumption built in that this is Lisp, Dialogue: 0,0:23:42.30,0:23:43.82,EN,,0,0,0,,because I'm using CARs and CDRs. Dialogue: 0,0:23:43.84,0:23:45.10,EN,,0,0,0,,CAR means the operator, Dialogue: 0,0:23:45.28,0:23:46.64,EN,,0,0,0,,and CDR means the operand. Dialogue: 0,0:23:46.75,0:23:49.96,EN,,0,0,0,,In the text, there is an abstract syntax evaluator Dialogue: 0,0:23:50.35,0:23:53.15,EN,,0,0,0,,which these could be-- these are given abstract names Dialogue: 0,0:23:53.16,0:23:54.09,EN,,0,0,0,,like operator, and operand, Dialogue: 0,0:23:54.14,0:23:55.82,EN,,0,0,0,,and all these other things are like that. Dialogue: 0,0:23:56.16,0:23:56.86,EN,,0,0,0,,And, in that case, Dialogue: 0,0:23:57.02,0:24:00.91,EN,,0,0,0,,you could reprogram it to be ALGOL with no problem. Dialogue: 0,0:24:03.36,0:24:06.40,EN,,0,0,0,,Well, here we have added another couple of things Dialogue: 0,0:24:07.20,0:24:08.43,EN,,0,0,0,,that we haven't defined. Dialogue: 0,0:24:10.81,0:24:12.57,EN,,0,0,0,,I don't think I'll worry about these at all, Dialogue: 0,0:24:13.39,0:24:15.05,EN,,0,0,0,,however, this one will be interesting later. Dialogue: 0,0:24:17.18,0:24:19.76,EN,,0,0,0,,Let's just proceed through this and get it done. Dialogue: 0,0:24:20.55,0:24:22.65,EN,,0,0,0,,There's only two more blackboards so it can't be very long. Dialogue: 0,0:24:27.40,0:24:29.08,EN,,0,0,0,,It's carefully tailored to exactly fit. Dialogue: 0,0:24:30.07,0:24:30.98,EN,,0,0,0,,Well, what do we have left? Dialogue: 0,0:24:30.98,0:24:33.20,EN,,0,0,0,,We have to define EVLIST, which is over here. Dialogue: 0,0:24:33.73,0:24:35.07,EN,,0,0,0,,And EVLIST is nothing more Dialogue: 0,0:24:35.26,0:24:43.08,EN,,0,0,0,,than a map down a bunch of operands producing arguments. Dialogue: 0,0:24:44.30,0:24:45.40,EN,,0,0,0,,But I'm going to write it out. Dialogue: 0,0:24:45.82,0:24:48.30,EN,,0,0,0,,And one of the reasons I'm going to write this out is for a mystical reason, Dialogue: 0,0:24:49.88,0:24:52.04,EN,,0,0,0,,which is I want to make this evaluator so simple Dialogue: 0,0:24:52.06,0:24:53.56,EN,,0,0,0,,that it can understand itself. Dialogue: 0,0:24:56.45,0:24:58.09,EN,,0,0,0,,I'm going to really worry about that a little bit. Dialogue: 0,0:25:00.23,0:25:01.74,EN,,0,0,0,,So let's write it out completely. Dialogue: 0,0:25:02.85,0:25:04.24,EN,,0,0,0,,See, I don't want to worry about Dialogue: 0,0:25:04.27,0:25:06.08,EN,,0,0,0,,whether or not the thing can pass functional arguments. Dialogue: 0,0:25:06.27,0:25:08.06,EN,,0,0,0,,The value evaluator is not going to use them. Dialogue: 0,0:25:08.98,0:25:10.78,EN,,0,0,0,,The evaluator is not going to produce functional values. Dialogue: 0,0:25:10.88,0:25:12.67,EN,,0,0,0,,So even if there were a different, alternative language Dialogue: 0,0:25:12.80,0:25:13.96,EN,,0,0,0,,that were very close to this, Dialogue: 0,0:25:15.16,0:25:17.79,EN,,0,0,0,,this evaluates a complex language like Scheme Dialogue: 0,0:25:17.80,0:25:23.12,EN,,0,0,0,,which does allow procedural arguments, procedural values, and procedural data. Dialogue: 0,0:25:24.07,0:25:25.95,EN,,0,0,0,,But even if I were evaluating ALGOL, Dialogue: 0,0:25:27.34,0:25:28.96,EN,,0,0,0,,which doesn't allow procedural values, Dialogue: 0,0:25:29.47,0:25:30.59,EN,,0,0,0,,I could use this evaluator. Dialogue: 0,0:25:31.58,0:25:33.92,EN,,0,0,0,,And this evaluator is not making any assumptions about that. Dialogue: 0,0:25:34.27,0:25:36.03,EN,,0,0,0,,And, in fact, if this evaluator were to be restricted Dialogue: 0,0:25:36.27,0:25:37.50,EN,,0,0,0,,to not being able to that, it wouldn't matter Dialogue: 0,0:25:37.52,0:25:40.03,EN,,0,0,0,,because it doesn't use any of those clever things. Dialogue: 0,0:25:40.64,0:25:42.41,EN,,0,0,0,,So that's why I'm arranging this to be super simple. Dialogue: 0,0:25:44.07,0:25:46.46,EN,,0,0,0,,This is sort of the kernel of all possible language evaluators. Dialogue: 0,0:25:47.81,0:25:48.48,EN,,0,0,0,,How about that? Dialogue: 0,0:25:49.42,0:25:53.56,EN,,0,0,0,,Evlist-- well, what is it? Dialogue: 0,0:25:53.82,0:25:57.04,EN,,0,0,0,,It's the procedure of two arguments, l and an environment, Dialogue: 0,0:25:58.09,0:25:59.08,EN,,0,0,0,,where l is a list Dialogue: 0,0:25:59.58,0:26:08.27,EN,,0,0,0,,such that if the list of arguments is the empty list, Dialogue: 0,0:26:10.19,0:26:12.68,EN,,0,0,0,,then the result is the empty list. Dialogue: 0,0:26:14.03,0:26:19.23,EN,,0,0,0,,Otherwise, I want to cons up Dialogue: 0,0:26:20.75,0:26:26.67,EN,,0,0,0,,result of evaluating the CAR of the Dialogue: 0,0:26:28.16,0:26:32.51,EN,,0,0,0,,the CAR of the list of operands in the environment. Dialogue: 0,0:26:33.34,0:26:35.71,EN,,0,0,0,,So I want the first operand evaluated, Dialogue: 0,0:26:35.98,0:26:38.40,EN,,0,0,0,,and I'm going to make a list of the results Dialogue: 0,0:26:38.97,0:26:40.76,EN,,0,0,0,,by CONSing that onto the result Dialogue: 0,0:26:41.08,0:26:45.42,EN,,0,0,0,,of this EVLISTing as a CDR recursion, Dialogue: 0,0:26:46.22,0:26:50.13,EN,,0,0,0,,the CDR of the list relative to the same environment. Dialogue: 0,0:26:53.08,0:26:58.24,EN,,0,0,0,,Evlist, cons, else, COND, lambda, define-- Dialogue: 0,0:26:59.66,0:27:01.84,EN,,0,0,0,,OK? And I have one more Dialogue: 0,0:27:01.84,0:27:03.36,EN,,0,0,0,,that I want to put on the blackboard. Dialogue: 0,0:27:03.62,0:27:05.21,EN,,0,0,0,,It's the essence of this whole thing. Dialogue: 0,0:27:05.64,0:27:08.13,EN,,0,0,0,,And there's some sort of next layer down. Dialogue: 0,0:27:14.54,0:27:15.44,EN,,0,0,0,,Conditionals-- Dialogue: 0,0:27:15.69,0:27:16.99,EN,,0,0,0,,conditionals are the only thing left Dialogue: 0,0:27:17.02,0:27:18.17,EN,,0,0,0,,that are sort of substantial. Dialogue: 0,0:27:18.88,0:27:20.75,EN,,0,0,0,,Then below that, we have to worry about Dialogue: 0,0:27:21.07,0:27:22.94,EN,,0,0,0,,things like lookup and bind, Dialogue: 0,0:27:23.56,0:27:25.36,EN,,0,0,0,,and we'll look at that in a second. Dialogue: 0,0:27:25.53,0:27:27.93,EN,,0,0,0,,But of the substantial stuff at this level of detail, Dialogue: 0,0:27:28.65,0:27:30.62,EN,,0,0,0,,next important thing is how you deal with conditionals. Dialogue: 0,0:27:31.60,0:27:33.33,EN,,0,0,0,,Well, how do we have a conditional thing? Dialogue: 0,0:27:36.97,0:27:38.56,EN,,0,0,0,,It's a procedure Dialogue: 0,0:27:39.48,0:27:45.00,EN,,0,0,0,,of clauses and an environment. Dialogue: 0,0:27:47.71,0:27:48.51,EN,,0,0,0,,And what does it do? Dialogue: 0,0:27:49.82,0:27:55.47,EN,,0,0,0,,It says, if I've no more clauses, Dialogue: 0,0:28:02.60,0:28:03.96,EN,,0,0,0,,well, I have to give this a value. Dialogue: 0,0:28:04.70,0:28:05.87,EN,,0,0,0,,It could be that it was an error. Dialogue: 0,0:28:06.54,0:28:08.59,EN,,0,0,0,,Supposing it run off the end of a conditional, Dialogue: 0,0:28:09.15,0:28:10.06,EN,,0,0,0,,it's pretty arbitrary. Dialogue: 0,0:28:10.06,0:28:12.88,EN,,0,0,0,,It's up to me as programmer to choose what I want to happen. Dialogue: 0,0:28:13.65,0:28:15.45,EN,,0,0,0,,It's convenient for me, right now, to write down Dialogue: 0,0:28:15.63,0:28:17.53,EN,,0,0,0,,this has a value which is the empty list, Dialogue: 0,0:28:18.14,0:28:18.83,EN,,0,0,0,,doesn't matter. Dialogue: 0,0:28:20.10,0:28:20.88,EN,,0,0,0,,For error checking, Dialogue: 0,0:28:20.89,0:28:22.76,EN,,0,0,0,,some people might prefer something else. Dialogue: 0,0:28:23.11,0:28:24.81,EN,,0,0,0,,But the interesting things are the following ones. Dialogue: 0,0:28:25.39,0:28:27.24,EN,,0,0,0,,If I've got an else clause-- Dialogue: 0,0:28:31.00,0:28:32.73,EN,,0,0,0,,You see, if I have a list of clauses, Dialogue: 0,0:28:33.21,0:28:34.41,EN,,0,0,0,,then each clause is a list. Dialogue: 0,0:28:35.44,0:28:40.52,EN,,0,0,0,,And so the predicate part is the CAAR of the clauses. Dialogue: 0,0:28:43.56,0:28:45.02,EN,,0,0,0,,It's the CAR, Dialogue: 0,0:28:45.04,0:28:49.00,EN,,0,0,0,,which is the first part of the first clause in the list of clauses. Dialogue: 0,0:28:51.09,0:28:51.84,EN,,0,0,0,,If it's an else, Dialogue: 0,0:28:54.32,0:28:56.51,EN,,0,0,0,,then it means I want my result of the conditional Dialogue: 0,0:28:56.64,0:28:59.15,EN,,0,0,0,,to be the result of evaluating the matching expression. Dialogue: 0,0:29:00.12,0:29:04.32,EN,,0,0,0,,So I eval the CADAR. Dialogue: 0,0:29:07.00,0:29:09.56,EN,,0,0,0,,So this is the first clause, Dialogue: 0,0:29:10.12,0:29:11.63,EN,,0,0,0,,the second element of it, CADAR-- Dialogue: 0,0:29:12.81,0:29:17.08,EN,,0,0,0,,CADR of a CAR-- of the clauses, Dialogue: 0,0:29:21.23,0:29:22.57,EN,,0,0,0,,with respect to the environment. Dialogue: 0,0:29:26.62,0:29:28.60,EN,,0,0,0,,Now the next possibility is more interesting. Dialogue: 0,0:29:29.63,0:29:30.44,EN,,0,0,0,,If it's false, Dialogue: 0,0:29:33.05,0:29:35.10,EN,,0,0,0,,if the first predicate in the predicate list Dialogue: 0,0:29:35.74,0:29:37.68,EN,,0,0,0,,is not an else, and it's not false, Dialogue: 0,0:29:38.32,0:29:39.50,EN,,0,0,0,,if it's not the word else, Dialogue: 0,0:29:40.16,0:29:42.00,EN,,0,0,0,,and if it's not a false thing-- Dialogue: 0,0:29:42.03,0:29:43.66,EN,,0,0,0,,Let's write down what it is if it's a false thing. Dialogue: 0,0:29:44.36,0:29:50.08,EN,,0,0,0,,If the result of evaluating the first clause -- first predicate, Dialogue: 0,0:29:52.33,0:29:56.76,EN,,0,0,0,,the clauses-- respect the environment, Dialogue: 0,0:29:58.19,0:30:01.00,EN,,0,0,0,,if that evaluation yields false, Dialogue: 0,0:30:01.69,0:30:03.82,EN,,0,0,0,,then it means, I want to look at the next clause. Dialogue: 0,0:30:04.36,0:30:05.74,EN,,0,0,0,,So I want to discard the first one. Dialogue: 0,0:30:06.25,0:30:08.33,EN,,0,0,0,,So we just go around loop, evcond, Dialogue: 0,0:30:09.95,0:30:16.49,EN,,0,0,0,,the CDR of the clauses relative to that environment. Dialogue: 0,0:30:19.95,0:30:25.15,EN,,0,0,0,,And otherwise, I had a true clause, Dialogue: 0,0:30:26.84,0:30:28.96,EN,,0,0,0,,what I want is to evaluate Dialogue: 0,0:30:31.85,0:30:41.45,EN,,0,0,0,,the CADAR of the clauses relative to that environment. Dialogue: 0,0:30:48.20,0:30:49.61,EN,,0,0,0,,Boy, it's almost done. Dialogue: 0,0:30:51.21,0:30:52.80,EN,,0,0,0,,It's quite close to done. Dialogue: 0,0:30:53.73,0:30:55.87,EN,,0,0,0,,I think we're going to finish this part off. Dialogue: 0,0:30:56.21,0:30:58.57,EN,,0,0,0,,So just buzzing through this evaluator, Dialogue: 0,0:30:58.81,0:31:00.70,EN,,0,0,0,,but so far you're seeing almost everything. Dialogue: 0,0:31:01.08,0:31:04.04,EN,,0,0,0,,Let's look at the next transparency here. Dialogue: 0,0:31:06.32,0:31:10.43,EN,,0,0,0,,And see IS, Here is bind. Dialogue: 0,0:31:11.98,0:31:14.54,EN,,0,0,0,,Bind is for making more table. Dialogue: 0,0:31:15.46,0:31:18.67,EN,,0,0,0,,And what we are going to do here is make a-- Dialogue: 0,0:31:19.24,0:31:22.80,EN,,0,0,0,,we're going to make a new frame for an environment structure. Dialogue: 0,0:31:22.80,0:31:25.42,EN,,0,0,0,,The environment structure is going to be represented Dialogue: 0,0:31:25.93,0:31:27.20,EN,,0,0,0,,as a list of frames. Dialogue: 0,0:31:28.08,0:31:30.19,EN,,0,0,0,,So given an existing environment structure, Dialogue: 0,0:31:30.32,0:31:32.11,EN,,0,0,0,,I'm going to make a new environment structure Dialogue: 0,0:31:32.25,0:31:33.82,EN,,0,0,0,,by consing a new frame Dialogue: 0,0:31:33.93,0:31:35.69,EN,,0,0,0,,onto the existing environment structure, Dialogue: 0,0:31:36.62,0:31:40.36,EN,,0,0,0,,where the new frame consists of the result of pairing up the variables, Dialogue: 0,0:31:41.05,0:31:43.79,EN,,0,0,0,,which are the bound variables of the procedure I'm applying, Dialogue: 0,0:31:44.12,0:31:48.25,EN,,0,0,0,,to the values which are the arguments that were passed that procedure. Dialogue: 0,0:31:49.69,0:31:50.65,EN,,0,0,0,,This is just making a list, Dialogue: 0,0:31:51.64,0:31:54.06,EN,,0,0,0,,adding a new element to our list of frames, Dialogue: 0,0:31:54.30,0:31:55.60,EN,,0,0,0,,which is an environment structure, Dialogue: 0,0:31:55.74,0:31:56.89,EN,,0,0,0,,to make a new environment. Dialogue: 0,0:31:58.65,0:32:00.65,EN,,0,0,0,,Where pair-up is very simple. Dialogue: 0,0:32:01.54,0:32:02.84,EN,,0,0,0,,Pair-up is nothing more Dialogue: 0,0:32:03.13,0:32:05.56,EN,,0,0,0,,than if I have a list of variables and a list of values, Dialogue: 0,0:32:05.93,0:32:08.62,EN,,0,0,0,,well, if I run out of variables and if I run out of values, Dialogue: 0,0:32:08.62,0:32:09.58,EN,,0,0,0,,everything's OK. Dialogue: 0,0:32:09.72,0:32:11.48,EN,,0,0,0,,Otherwise, I've given too many arguments. Dialogue: 0,0:32:12.51,0:32:15.98,EN,,0,0,0,,If I've not run out of variables, but I've run out of values, Dialogue: 0,0:32:16.06,0:32:17.37,EN,,0,0,0,,that I have too few arguments. Dialogue: 0,0:32:18.51,0:32:19.63,EN,,0,0,0,,And in the general case, Dialogue: 0,0:32:19.63,0:32:21.48,EN,,0,0,0,,where I don't have any errors, and I'm not done, Dialogue: 0,0:32:22.06,0:32:25.61,EN,,0,0,0,,OK? Then I really am just adding a new pair Dialogue: 0,0:32:25.76,0:32:30.17,EN,,0,0,0,,of the first variable with the first argument, Dialogue: 0,0:32:30.94,0:32:32.12,EN,,0,0,0,,the first value, Dialogue: 0,0:32:32.76,0:32:36.40,EN,,0,0,0,,onto a list resulting from pairing-up Dialogue: 0,0:32:37.12,0:32:40.64,EN,,0,0,0,,the rest of the variables with the rest of the values. Dialogue: 0,0:32:42.95,0:32:44.78,EN,,0,0,0,,Lookup is of course equally simple. Dialogue: 0,0:32:46.28,0:32:49.63,EN,,0,0,0,,If I have to look up a symbol in an environment, Dialogue: 0,0:32:49.93,0:32:51.39,EN,,0,0,0,,well, if the environment is empty, Dialogue: 0,0:32:51.56,0:32:53.00,EN,,0,0,0,,then I've got an unbound variable. Dialogue: 0,0:32:54.65,0:32:55.47,EN,,0,0,0,,Otherwise, Dialogue: 0,0:32:56.86,0:33:00.36,EN,,0,0,0,,what I'm going to do is use a special pair list lookup procedure, Dialogue: 0,0:33:00.38,0:33:01.87,EN,,0,0,0,,which we'll have very shortly, Dialogue: 0,0:33:02.24,0:33:05.44,EN,,0,0,0,,of the symbol in the first frame of the environment. Dialogue: 0,0:33:05.93,0:33:07.21,EN,,0,0,0,,Since I know the environment is not empty, Dialogue: 0,0:33:07.23,0:33:08.40,EN,,0,0,0,,it must have a first frame. Dialogue: 0,0:33:09.20,0:33:11.14,EN,,0,0,0,,So I lookup the symbol in the first frame. Dialogue: 0,0:33:11.56,0:33:13.58,EN,,0,0,0,,That becomes the value cell here. Dialogue: 0,0:33:14.38,0:33:17.61,EN,,0,0,0,,OK? And then, if the value cell is empty, Dialogue: 0,0:33:18.44,0:33:20.57,EN,,0,0,0,,if there is no such value cell, Dialogue: 0,0:33:20.70,0:33:22.84,EN,,0,0,0,,then I have to continue and look at the rest of the frames. Dialogue: 0,0:33:23.72,0:33:25.04,EN,,0,0,0,,It means there was nothing found there. Dialogue: 0,0:33:25.99,0:33:28.89,EN,,0,0,0,,So that's a property of ASSQ is it returns emptiness Dialogue: 0,0:33:29.52,0:33:30.80,EN,,0,0,0,,if it doesn't find something. Dialogue: 0,0:33:32.32,0:33:33.85,EN,,0,0,0,,but if it did find something, Dialogue: 0,0:33:33.85,0:33:36.06,EN,,0,0,0,,then I'm going to use the CDR of the value cell here, Dialogue: 0,0:33:36.46,0:33:40.25,EN,,0,0,0,,which is the thing that was the pair consisting of the variable and the value. Dialogue: 0,0:33:41.05,0:33:43.93,EN,,0,0,0,,So the CDR of it is the value part. OK? Dialogue: 0,0:33:45.00,0:33:47.82,EN,,0,0,0,,Finally, ASSQ is something you've probably seen already. Dialogue: 0,0:33:47.97,0:33:50.83,EN,,0,0,0,,ASSQ takes a symbol and a list of pairs, Dialogue: 0,0:33:51.42,0:33:53.40,EN,,0,0,0,,and if the list is empty, it's empty. Dialogue: 0,0:33:53.52,0:33:56.30,EN,,0,0,0,,If the symbol is the first thing in the list-- Dialogue: 0,0:33:58.06,0:33:58.91,EN,,0,0,0,,That's an error. Dialogue: 0,0:33:59.82,0:34:02.17,EN,,0,0,0,,That should be CAAR, C-A-A-R. Dialogue: 0,0:34:03.16,0:34:04.16,EN,,0,0,0,,Everybody note that. Dialogue: 0,0:34:07.63,0:34:09.37,EN,,0,0,0,,Right there, OK? Dialogue: 0,0:34:13.42,0:34:14.41,EN,,0,0,0,,And in any case, Dialogue: 0,0:34:14.56,0:34:16.81,EN,,0,0,0,,f the symbol is the CAAR of the A list, Dialogue: 0,0:34:17.16,0:34:20.97,EN,,0,0,0,,then I want the first, the first pair, in the alist. Dialogue: 0,0:34:22.08,0:34:25.50,EN,,0,0,0,,So, in other words, if this is the key matching the right entry, Dialogue: 0,0:34:26.24,0:34:26.97,EN,,0,0,0,,otherwise, Dialogue: 0,0:34:27.08,0:34:28.94,EN,,0,0,0,,I want to look up that symbol in the rest. Dialogue: 0,0:34:30.08,0:34:33.31,EN,,0,0,0,,Sorry for producing a bug, bugs appear. Dialogue: 0,0:34:35.19,0:34:36.28,EN,,0,0,0,,Well, in any case, Dialogue: 0,0:34:37.05,0:34:39.48,EN,,0,0,0,,you're pretty much seeing the whole thing now. Dialogue: 0,0:34:41.88,0:34:43.29,EN,,0,0,0,,It's a very beautiful thing, Dialogue: 0,0:34:44.19,0:34:46.00,EN,,0,0,0,,even though it's written in an ugly style, Dialogue: 0,0:34:46.76,0:34:48.30,EN,,0,0,0,,being the kernel of every language. Dialogue: 0,0:34:49.60,0:34:51.37,EN,,0,0,0,,I suggest that we just-- let's look at it for a while. Dialogue: 0,0:35:00.32,0:35:47.02,EN,,0,0,0,,[ALSO SPRACH ZARATHUSTRA] Dialogue: 0,0:35:49.75,0:35:50.91,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:36:01.18,0:36:03.29,EN,,0,0,0,,Alright, I suppose it's time to take a small break then. Dialogue: 0,0:36:04.04,0:36:10.73,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:36:56.78,0:36:58.99,EN,,0,0,0,,OK, now we're just going to do a little bit of practice Dialogue: 0,0:36:59.29,0:37:02.67,EN,,0,0,0,,understanding what it is we've just shown you. OK? Dialogue: 0,0:37:03.47,0:37:05.48,EN,,0,0,0,,What we're going to do is go through, in detail, Dialogue: 0,0:37:05.50,0:37:10.36,EN,,0,0,0,,an evaluation by informally substituting through the interpreter. Dialogue: 0,0:37:11.50,0:37:14.94,EN,,0,0,0,,And since we have no assignments or definitions in this interpreter, Dialogue: 0,0:37:15.20,0:37:17.34,EN,,0,0,0,,we have no possible side effects, Dialogue: 0,0:37:17.98,0:37:22.03,EN,,0,0,0,,and so the we can do substitution with impunity Dialogue: 0,0:37:22.52,0:37:24.59,EN,,0,0,0,,and not worry about results. Dialogue: 0,0:37:25.33,0:37:27.80,EN,,0,0,0,,So the particular problem I'd like to look at Dialogue: 0,0:37:28.06,0:37:29.63,EN,,0,0,0,,is it an interesting one. Dialogue: 0,0:37:30.69,0:37:34.09,EN,,0,0,0,,It's the evaluation of Dialogue: 0,0:37:34.91,0:37:48.08,EN,,0,0,0,,quote, open, open, open, lambda of x, lambda of y plus x y, Dialogue: 0,0:37:50.30,0:37:52.62,EN,,0,0,0,,lambda, lambda, Dialogue: 0,0:37:53.04,0:37:56.12,EN,,0,0,0,,applied to three, applied to four, Dialogue: 0,0:37:56.94,0:37:59.58,EN,,0,0,0,,in some global environment which I'll call e0. Dialogue: 0,0:38:04.93,0:38:05.96,EN,,0,0,0,,So what we have here Dialogue: 0,0:38:06.36,0:38:08.04,EN,,0,0,0,,is a procedure of one argument x, Dialogue: 0,0:38:08.09,0:38:11.05,EN,,0,0,0,,which produces as its value a procedure of one argument y, Dialogue: 0,0:38:11.07,0:38:12.12,EN,,0,0,0,,which adds x to y. Dialogue: 0,0:38:14.30,0:38:17.96,EN,,0,0,0,,We are applying the procedure of one argument x to three. Dialogue: 0,0:38:17.96,0:38:19.39,EN,,0,0,0,,So x should become three. Dialogue: 0,0:38:21.40,0:38:23.98,EN,,0,0,0,,And the result of that should be procedure of one argument y, Dialogue: 0,0:38:24.33,0:38:25.82,EN,,0,0,0,,which will then apply to 4. Dialogue: 0,0:38:28.91,0:38:30.32,EN,,0,0,0,,And there is a very simple case, Dialogue: 0,0:38:31.04,0:38:32.73,EN,,0,0,0,,they will then add those results. Dialogue: 0,0:38:34.79,0:38:35.82,EN,,0,0,0,,And now in order to do that, Dialogue: 0,0:38:35.84,0:38:37.76,EN,,0,0,0,,I want to make a very simple environment model. Dialogue: 0,0:38:37.90,0:38:40.48,EN,,0,0,0,,And at this point, you should already have in your mind Dialogue: 0,0:38:40.99,0:38:42.59,EN,,0,0,0,,the environments that this produces. Dialogue: 0,0:38:44.46,0:38:46.62,EN,,0,0,0,,But we're going to start out with a global environment, Dialogue: 0,0:38:48.59,0:38:50.06,EN,,0,0,0,,which I'll call e0, Dialogue: 0,0:38:54.60,0:38:55.47,EN,,0,0,0,,which is that. Dialogue: 0,0:38:56.74,0:39:02.46,EN,,0,0,0,,And it's going to have in it things, definitions for plus, and times, Dialogue: 0,0:39:06.30,0:39:10.36,EN,,0,0,0,,and-- using Greek letters, isn't that interesting, for the objects-- Dialogue: 0,0:39:11.21,0:39:27.93,EN,,0,0,0,,and minus, and quotient, and CAR, and CDR, and CONS, and EQ, Dialogue: 0,0:39:28.59,0:39:31.05,EN,,0,0,0,,and everything else you might imagine in a global environment. Dialogue: 0,0:39:31.27,0:39:33.82,EN,,0,0,0,,It's got something there for each of those things, Dialogue: 0,0:39:34.62,0:39:36.09,EN,,0,0,0,,something the machine is born with, Dialogue: 0,0:39:37.10,0:39:38.09,EN,,0,0,0,,that's e0. Dialogue: 0,0:39:39.22,0:39:41.84,EN,,0,0,0,,Now what does it mean to do this evaluation? Dialogue: 0,0:39:42.94,0:39:45.18,EN,,0,0,0,,Well, we go through the set of special forms. Dialogue: 0,0:39:45.69,0:39:47.05,EN,,0,0,0,,First of all, this is not a number. Dialogue: 0,0:39:48.67,0:39:50.38,EN,,0,0,0,,This is not a symbol. Dialogue: 0,0:39:53.13,0:39:55.60,EN,,0,0,0,,Gee, it's not a quoted expression. Dialogue: 0,0:39:56.60,0:39:58.38,EN,,0,0,0,,This is a quoted expression, Dialogue: 0,0:39:59.47,0:40:00.80,EN,,0,0,0,,but that's not what I mentioned. Dialogue: 0,0:40:00.83,0:40:01.36,EN,,0,0,0,,The question is, Dialogue: 0,0:40:01.39,0:40:04.96,EN,,0,0,0,,whether or not the thing which is quoted is quoted expression? Dialogue: 0,0:40:05.89,0:40:07.96,EN,,0,0,0,,I'm evaluating an expression. Dialogue: 0,0:40:07.96,0:40:09.98,EN,,0,0,0,,This just says it's this particular expression. Dialogue: 0,0:40:11.41,0:40:12.66,EN,,0,0,0,,This is not a quoted expression. Dialogue: 0,0:40:13.71,0:40:17.21,EN,,0,0,0,,OK? It's not a thing that begins with lambda. Dialogue: 0,0:40:19.12,0:40:20.67,EN,,0,0,0,,It's not a thing that begins with COND. Dialogue: 0,0:40:22.03,0:40:25.95,EN,,0,0,0,,Therefore, it's an application of its of an operated operands. Dialogue: 0,0:40:26.31,0:40:27.12,EN,,0,0,0,,It's a combination. Dialogue: 0,0:40:28.57,0:40:30.70,EN,,0,0,0,,The combination thus has Dialogue: 0,0:40:30.89,0:40:34.00,EN,,0,0,0,,this as the operator Dialogue: 0,0:40:34.64,0:40:36.08,EN,,0,0,0,,and this is the operands. Dialogue: 0,0:40:40.13,0:40:42.41,EN,,0,0,0,,Well, that means that what I'm going to do is Dialogue: 0,0:40:42.57,0:40:47.90,EN,,0,0,0,,transform this into apply of eval, Dialogue: 0,0:40:50.12,0:40:57.61,EN,,0,0,0,,of quote, open, open lambda of x, lambda of y-- Dialogue: 0,0:40:57.88,0:40:59.12,EN,,0,0,0,,I'm evaluating the operator-- Dialogue: 0,0:40:59.95,0:41:04.19,EN,,0,0,0,,plus x y, in the environment, Dialogue: 0,0:41:07.26,0:41:08.64,EN,,0,0,0,,also e0, Dialogue: 0,0:41:12.78,0:41:15.20,EN,,0,0,0,,with the operands that I'm going to apply this to, Dialogue: 0,0:41:15.26,0:41:17.28,EN,,0,0,0,,the arguments being the result of EVLIST, Dialogue: 0,0:41:21.21,0:41:24.49,EN,,0,0,0,,the list containing four, fin e0. Dialogue: 0,0:41:29.01,0:41:31.26,EN,,0,0,0,,I'm using this funny notation here for e0 Dialogue: 0,0:41:32.32,0:41:34.83,EN,,0,0,0,,because this should be that environment. Dialogue: 0,0:41:35.45,0:41:37.77,EN,,0,0,0,,I haven't a name for it, Dialogue: 0,0:41:37.80,0:41:39.15,EN,,0,0,0,,because I have no environment to name it in. Dialogue: 0,0:41:41.96,0:41:44.09,EN,,0,0,0,,So this is just a representation Dialogue: 0,0:41:44.17,0:41:46.17,EN,,0,0,0,,what would be a quoted expression, if you will. Dialogue: 0,0:41:47.73,0:41:51.16,EN,,0,0,0,,The data structure, which is the environment, goes there. Dialogue: 0,0:41:53.04,0:41:55.04,EN,,0,0,0,,Well, that's what we're seeing here. Dialogue: 0,0:41:55.85,0:41:56.67,EN,,0,0,0,,Well in order to do this, Dialogue: 0,0:41:56.68,0:41:58.04,EN,,0,0,0,,I have to do this, and I have to do that. Dialogue: 0,0:41:59.61,0:42:00.49,EN,,0,0,0,,Well this one's easy, Dialogue: 0,0:42:00.57,0:42:03.18,EN,,0,0,0,,so why don't we do that one first. OK? Dialogue: 0,0:42:03.77,0:42:07.44,EN,,0,0,0,,This turns into apply of eval-- Dialogue: 0,0:42:07.45,0:42:08.83,EN,,0,0,0,,just copying something now. Dialogue: 0,0:42:09.42,0:42:11.00,EN,,0,0,0,,Most of the substitution rule is copying. Dialogue: 0,0:42:18.53,0:42:21.24,EN,,0,0,0,,So I'm going to not say the words when I copy, Dialogue: 0,0:42:21.71,0:42:23.87,EN,,0,0,0,,because it's faster. Dialogue: 0,0:42:26.41,0:42:28.64,EN,,0,0,0,,And then the EVLIST is going to turn into a Dialogue: 0,0:42:28.65,0:42:36.72,EN,,0,0,0,,cons, of eval, of four, in e0-- Dialogue: 0,0:42:38.78,0:42:40.17,EN,,0,0,0,,because it was not an empty list-- Dialogue: 0,0:42:41.44,0:42:49.39,EN,,0,0,0,,onto the result of EVLISTing, on the empty list, in e0. Dialogue: 0,0:42:52.58,0:42:54.20,EN,,0,0,0,,And I'm going to start leaving out steps soon, Dialogue: 0,0:42:54.24,0:42:55.36,EN,,0,0,0,,because it's going to get boring. Dialogue: 0,0:42:59.87,0:43:05.42,EN,,0,0,0,,But this is basically the same thing as apply, of eval-- Dialogue: 0,0:43:07.50,0:43:08.54,EN,,0,0,0,,I'm going to keep doing this-- Dialogue: 0,0:43:10.68,0:43:20.24,EN,,0,0,0,,the lambda of x, the lambda of y, plus xy, 3, close, e0. Dialogue: 0,0:43:20.24,0:43:21.20,EN,,0,0,0,,I'm a pretty good machine. Dialogue: 0,0:43:24.24,0:43:26.24,EN,,0,0,0,,Well, eval of four, Dialogue: 0,0:43:26.56,0:43:28.44,EN,,0,0,0,,that's meets the question, is it a number. Dialogue: 0,0:43:29.00,0:43:33.90,EN,,0,0,0,,So that's cons, right, cons of 4. Dialogue: 0,0:43:34.03,0:43:37.47,EN,,0,0,0,,And EVLIST of the empty list is the empty list, Dialogue: 0,0:43:38.33,0:43:39.24,EN,,0,0,0,,so that's this. Dialogue: 0,0:43:42.62,0:43:45.08,EN,,0,0,0,,OK. And that's very simple to understand, Dialogue: 0,0:43:45.10,0:43:47.44,EN,,0,0,0,,because that means the list containing four itself. Dialogue: 0,0:43:48.71,0:43:53.84,EN,,0,0,0,,So this is nothing more than apply of eval, Dialogue: 0,0:43:55.28,0:44:02.51,EN,,0,0,0,,quote, open, open, lambda of x, lambda of y, plus x y, Dialogue: 0,0:44:03.40,0:44:07.48,EN,,0,0,0,,three applied to, e0, applied to the list four-- Dialogue: 0,0:44:08.68,0:44:12.60,EN,,0,0,0,,applied to the list four-- bang Dialogue: 0,0:44:13.94,0:44:15.05,EN,,0,0,0,,So that's that step. Dialogue: 0,0:44:17.00,0:44:19.96,EN,,0,0,0,,Now let's look at the next, more interesting thing. Dialogue: 0,0:44:20.36,0:44:21.72,EN,,0,0,0,,What do I do to evaluate that? Dialogue: 0,0:44:23.07,0:44:24.44,EN,,0,0,0,,Evaluating this means Dialogue: 0,0:44:25.20,0:44:28.65,EN,,0,0,0,,means I have to evaluate-- Well, it's not. Dialogue: 0,0:44:29.46,0:44:31.04,EN,,0,0,0,,It's nothing but an application. Dialogue: 0,0:44:31.68,0:44:33.10,EN,,0,0,0,,It's not one of the special things. Dialogue: 0,0:44:33.57,0:44:36.51,EN,,0,0,0,,If the application of this operator, Dialogue: 0,0:44:36.51,0:44:37.37,EN,,0,0,0,,which we see here-- Dialogue: 0,0:44:37.66,0:44:38.94,EN,,0,0,0,,here's the operator-- Dialogue: 0,0:44:40.19,0:44:41.77,EN,,0,0,0,,applied to this operands, Dialogue: 0,0:44:44.54,0:44:45.74,EN,,0,0,0,,that combination. Dialogue: 0,0:44:46.72,0:44:48.25,EN,,0,0,0,,But we know how to do that, Dialogue: 0,0:44:48.84,0:44:52.37,EN,,0,0,0,,because that's the last case of the conditional. Dialogue: 0,0:44:52.37,0:44:55.52,EN,,0,0,0,,So substituting in for this evaluation, Dialogue: 0,0:44:55.71,0:44:57.47,EN,,0,0,0,,it's apply of eval of the operator Dialogue: 0,0:44:57.50,0:44:59.00,EN,,0,0,0,,in the EVLIST of the operands. Dialogue: 0,0:45:01.16,0:45:08.20,EN,,0,0,0,,Well, it's apply, of apply, of eval, Dialogue: 0,0:45:10.57,0:45:21.07,EN,,0,0,0,,of quote, open, lambda of x, lambda of y, plus x y, Dialogue: 0,0:45:21.80,0:45:23.45,EN,,0,0,0,,lambda, lambda, Dialogue: 0,0:45:23.74,0:45:25.42,EN,,0,0,0,,in environment e0. Dialogue: 0,0:45:30.52,0:45:32.67,EN,,0,0,0,,I'm going to short circuit the evaluation of the operands, Dialogue: 0,0:45:32.68,0:45:34.14,EN,,0,0,0,,because they're the same as they were before. Dialogue: 0,0:45:35.23,0:45:36.48,EN,,0,0,0,,I got a list containing three, Dialogue: 0,0:45:36.51,0:45:39.16,EN,,0,0,0,,apply that, and apply that to four. Dialogue: 0,0:45:42.44,0:45:43.56,EN,,0,0,0,,Well let's see. Dialogue: 0,0:45:44.41,0:45:46.38,EN,,0,0,0,,Eval of a lambda expression Dialogue: 0,0:45:48.01,0:45:49.45,EN,,0,0,0,,produces a procedure object. Dialogue: 0,0:45:52.03,0:45:57.88,EN,,0,0,0,,So this is apply, of apply, Dialogue: 0,0:46:00.30,0:46:02.27,EN,,0,0,0,,of the procedure object closure, Dialogue: 0,0:46:04.52,0:46:08.68,EN,,0,0,0,,which contains the body of the procedure, x, Dialogue: 0,0:46:08.94,0:46:11.92,EN,,0,0,0,,which is lambda, which binds x [UNINTELLIGIBLE] Dialogue: 0,0:46:12.13,0:46:15.40,EN,,0,0,0,,the internals of the body, Dialogue: 0,0:46:15.80,0:46:18.17,EN,,0,0,0,,it returns the procedure of one argument y, Dialogue: 0,0:46:18.56,0:46:20.63,EN,,0,0,0,,which adds x to y. Dialogue: 0,0:46:23.21,0:46:25.50,EN,,0,0,0,,Environment e0 is now captured in it, Dialogue: 0,0:46:27.24,0:46:29.63,EN,,0,0,0,,because this was evaluated with respect to e0. Dialogue: 0,0:46:30.11,0:46:32.43,EN,,0,0,0,,e0 is part now of the closure object. Dialogue: 0,0:46:33.04,0:46:38.19,EN,,0,0,0,,Apply that to open, three, close, apply, Dialogue: 0,0:46:38.81,0:46:41.30,EN,,0,0,0,,to open, 4, close, apply. Dialogue: 0,0:46:47.39,0:46:49.29,EN,,0,0,0,,So going from this step to this step Dialogue: 0,0:46:49.31,0:46:50.89,EN,,0,0,0,,meant that I made up a procedure object Dialogue: 0,0:46:50.91,0:46:52.03,EN,,0,0,0,,which captured in it Dialogue: 0,0:46:53.88,0:46:55.98,EN,,0,0,0,,e0 as part of the procedure object. Dialogue: 0,0:46:57.15,0:46:58.51,EN,,0,0,0,,Now, we're going to pass those to apply. Dialogue: 0,0:46:58.52,0:46:59.71,EN,,0,0,0,,We have to apply this procedure Dialogue: 0,0:47:00.48,0:47:01.58,EN,,0,0,0,,to that set of arguments. Dialogue: 0,0:47:02.71,0:47:06.51,EN,,0,0,0,,Well, but that procedure is not primitive. Dialogue: 0,0:47:07.38,0:47:09.88,EN,,0,0,0,,It's, in fact, a thing which has got the tag closure, Dialogue: 0,0:47:10.24,0:47:12.09,EN,,0,0,0,,and, therefore, what we have to do is do a bind. Dialogue: 0,0:47:13.71,0:47:14.72,EN,,0,0,0,,We have to bind. Dialogue: 0,0:47:15.83,0:47:19.40,EN,,0,0,0,,A new environment is made at this point, Dialogue: 0,0:47:20.44,0:47:22.80,EN,,0,0,0,,which has as its parent environment Dialogue: 0,0:47:22.94,0:47:27.56,EN,,0,0,0,,the one over here, e0, that environment. Dialogue: 0,0:47:30.32,0:47:31.57,EN,,0,0,0,,And we'll call this one, e1. Dialogue: 0,0:47:34.62,0:47:35.74,EN,,0,0,0,,Now what's bound in there? Dialogue: 0,0:47:36.04,0:47:37.48,EN,,0,0,0,,x is bound to three. Dialogue: 0,0:47:38.62,0:47:40.44,EN,,0,0,0,,So I have x equal three. Dialogue: 0,0:47:41.48,0:47:42.33,EN,,0,0,0,,That's what's in there. Dialogue: 0,0:47:44.94,0:47:46.24,EN,,0,0,0,,And we'll call that e1. Dialogue: 0,0:47:46.24,0:47:48.44,EN,,0,0,0,,So what this transforms into Dialogue: 0,0:47:49.13,0:47:50.72,EN,,0,0,0,,is an eval of the body Dialogue: 0,0:47:51.72,0:47:53.07,EN,,0,0,0,,of this, which is this, Dialogue: 0,0:47:54.40,0:47:55.72,EN,,0,0,0,,the body of that procedure, Dialogue: 0,0:47:56.44,0:47:58.52,EN,,0,0,0,,in the environment that you just saw. Dialogue: 0,0:48:00.29,0:48:05.05,EN,,0,0,0,,So that's an apply, of eval, Dialogue: 0,0:48:06.92,0:48:16.43,EN,,0,0,0,,quote, open, lambda of y, plus x y-- the body-- in e1. Dialogue: 0,0:48:20.49,0:48:22.48,EN,,0,0,0,,And apply the result of that to four, Dialogue: 0,0:48:23.68,0:48:26.73,EN,,0,0,0,,open, close, 4-- list of arguments. Dialogue: 0,0:48:28.43,0:48:29.87,EN,,0,0,0,,Well, that's sensible enough Dialogue: 0,0:48:30.08,0:48:32.27,EN,,0,0,0,,because evaluating a lambda, I know what to do. Dialogue: 0,0:48:33.11,0:48:34.17,EN,,0,0,0,,That means I apply, Dialogue: 0,0:48:37.16,0:48:38.92,EN,,0,0,0,,the procedure which is closure, Dialogue: 0,0:48:43.74,0:48:46.84,EN,,0,0,0,,binds one argument y, adds x to y, Dialogue: 0,0:48:49.28,0:48:52.15,EN,,0,0,0,,with e1 captured in it. Dialogue: 0,0:48:55.79,0:48:57.42,EN,,0,0,0,,And you should really see this. Right? Dialogue: 0,0:48:57.80,0:49:00.14,EN,,0,0,0,,I somehow manufactured a closure. Dialogue: 0,0:49:00.14,0:49:01.16,EN,,0,0,0,,I should've put this here. Dialogue: 0,0:49:01.79,0:49:03.04,EN,,0,0,0,,There was one over here too. Dialogue: 0,0:49:05.90,0:49:07.47,EN,,0,0,0,,OK? Well, there's one here now. Dialogue: 0,0:49:08.08,0:49:09.80,EN,,0,0,0,,I've captured e1, Dialogue: 0,0:49:10.41,0:49:14.25,EN,,0,0,0,,and this is the procedure of one argument y, Dialogue: 0,0:49:15.45,0:49:16.70,EN,,0,0,0,,whatever this is. Dialogue: 0,0:49:18.09,0:49:20.72,EN,,0,0,0,,That's what that is there, that closure. Dialogue: 0,0:49:22.57,0:49:26.46,EN,,0,0,0,,OK? I'm going to apply that to four. Dialogue: 0,0:49:30.28,0:49:31.77,EN,,0,0,0,,OK. Well, that's easy enough. Dialogue: 0,0:49:36.83,0:49:38.73,EN,,0,0,0,,That means I have to make a new environment Dialogue: 0,0:49:38.86,0:49:40.52,EN,,0,0,0,,by copying this pointer, Dialogue: 0,0:49:41.56,0:49:43.21,EN,,0,0,0,,which was the pointer of the procedure, Dialogue: 0,0:49:44.94,0:49:48.96,EN,,0,0,0,,which binds y equal 4 with that environment. Dialogue: 0,0:49:49.82,0:49:52.22,EN,,0,0,0,,And here's my new environment, which I'll call e2. Dialogue: 0,0:49:56.03,0:49:58.12,EN,,0,0,0,,And, of course, this application then Dialogue: 0,0:49:58.22,0:50:00.33,EN,,0,0,0,,is evaluate the body in e2. Dialogue: 0,0:50:01.58,0:50:07.87,EN,,0,0,0,,So this is eval, the body, Dialogue: 0,0:50:07.90,0:50:11.85,EN,,0,0,0,,which is plus x y, in the environment e2. Dialogue: 0,0:50:13.71,0:50:14.94,EN,,0,0,0,,But this is an application, Dialogue: 0,0:50:15.48,0:50:23.88,EN,,0,0,0,,so this is the apply, of eval, plus in e2, Dialogue: 0,0:50:26.33,0:50:37.34,EN,,0,0,0,,an EVLIST, quote, open, x y, in e2. Dialogue: 0,0:50:44.88,0:50:45.59,EN,,0,0,0,,Well, but let's see. Dialogue: 0,0:50:45.59,0:50:51.71,EN,,0,0,0,,That is apply, the object Dialogue: 0,0:50:52.08,0:50:53.87,EN,,0,0,0,,which is a result of that and plus. Dialogue: 0,0:50:54.19,0:50:55.66,EN,,0,0,0,,So here we are in e2, Dialogue: 0,0:50:55.69,0:50:57.72,EN,,0,0,0,,plus is not here, it's not here, Dialogue: 0,0:50:57.74,0:51:01.05,EN,,0,0,0,,yes, but's here as some primitive operator. Dialogue: 0,0:51:01.78,0:51:04.74,EN,,0,0,0,,So it's the primitive operator for addition. Dialogue: 0,0:51:07.47,0:51:14.12,EN,,0,0,0,,Apply that to the result of evaluating x and y in e2. Dialogue: 0,0:51:14.37,0:51:17.00,EN,,0,0,0,,But we can see that x is three and y is four. Dialogue: 0,0:51:18.11,0:51:23.31,EN,,0,0,0,,So that's a three and four, here. Dialogue: 0,0:51:24.16,0:51:26.28,EN,,0,0,0,,And that magically produces for me a seven. Dialogue: 0,0:51:30.52,0:51:32.44,EN,,0,0,0,,I wanted to go through this so you would see, Dialogue: 0,0:51:32.70,0:51:34.73,EN,,0,0,0,,essentially, one important ingredient, Dialogue: 0,0:51:35.76,0:51:37.29,EN,,0,0,0,,which is what's being passed around, Dialogue: 0,0:51:37.31,0:51:39.56,EN,,0,0,0,,and who owns what, and what his job is. Dialogue: 0,0:51:40.47,0:51:41.61,EN,,0,0,0,,So what do we have here? Dialogue: 0,0:51:41.70,0:51:42.62,EN,,0,0,0,,We have eval, Dialogue: 0,0:51:44.80,0:51:45.64,EN,,0,0,0,,We have eval, and we have apply, Dialogue: 0,0:51:45.66,0:51:46.62,EN,,0,0,0,,the two main players. Dialogue: 0,0:51:49.37,0:51:51.56,EN,,0,0,0,,And there is a big loop the goes around like this. Dialogue: 0,0:51:52.32,0:52:04.57,EN,,0,0,0,,Which is eval produces a procedure and arguments for apply. Dialogue: 0,0:52:06.27,0:52:08.57,EN,,0,0,0,,Now some things eval could do by itself. Dialogue: 0,0:52:09.50,0:52:10.86,EN,,0,0,0,,Those are little self things here. Dialogue: 0,0:52:10.86,0:52:11.74,EN,,0,0,0,,They're not interesting. Dialogue: 0,0:52:12.70,0:52:15.60,EN,,0,0,0,,Also eval evaluates all of the arguments, one after another. Dialogue: 0,0:52:16.24,0:52:17.28,EN,,0,0,0,,That's not very interesting. Dialogue: 0,0:52:17.65,0:52:20.09,EN,,0,0,0,,Apply can apply some procedures like plus, Dialogue: 0,0:52:21.02,0:52:22.04,EN,,0,0,0,,not very interesting. Dialogue: 0,0:52:22.30,0:52:24.64,EN,,0,0,0,,However, if apply can't apply a procedure like plus, Dialogue: 0,0:52:25.31,0:52:33.31,EN,,0,0,0,,it produces an expression and environment for eval. Dialogue: 0,0:52:35.47,0:52:37.61,EN,,0,0,0,,The procedural arguments wrap up Dialogue: 0,0:52:38.24,0:52:40.60,EN,,0,0,0,,essentially the state of a computation Dialogue: 0,0:52:41.66,0:52:43.42,EN,,0,0,0,,and, certainly, the expression of environment. Dialogue: 0,0:52:43.74,0:52:45.31,EN,,0,0,0,,And so what we're actually going to do next Dialogue: 0,0:52:45.32,0:52:46.46,EN,,0,0,0,,is not the complete state, Dialogue: 0,0:52:46.48,0:52:48.82,EN,,0,0,0,,because it doesn't say who wants the answers. Dialogue: 0,0:52:51.28,0:52:52.20,EN,,0,0,0,,But what we're going to do-- Dialogue: 0,0:52:52.24,0:52:54.80,EN,,0,0,0,,it's always got something like an expression of environment Dialogue: 0,0:52:54.99,0:52:56.14,EN,,0,0,0,,or procedure and arguments Dialogue: 0,0:52:56.28,0:52:58.08,EN,,0,0,0,,as the main loop that we're going around. Dialogue: 0,0:52:58.97,0:53:01.80,EN,,0,0,0,,There are minor little sub loops like eval through EVLIST, Dialogue: 0,0:53:04.49,0:53:06.76,EN,,0,0,0,,or eval through evcond, Dialogue: 0,0:53:09.10,0:53:11.96,EN,,0,0,0,,or apply through a primitive apply. Dialogue: 0,0:53:16.14,0:53:17.64,EN,,0,0,0,,But they're not the essential things. Dialogue: 0,0:53:18.86,0:53:20.28,EN,,0,0,0,,So that's what I wanted you to see. Dialogue: 0,0:53:21.86,0:53:22.88,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:53:25.93,0:53:27.37,EN,,0,0,0,,Yes. David Dialogue: 0,0:53:27.74,0:53:33.31,EN,,0,0,0,,AUDIENCE: I'm trying to understand how x got down to three Dialogue: 0,0:53:34.01,0:53:36.30,EN,,0,0,0,,instead of four. Dialogue: 0,0:53:37.07,0:53:38.52,EN,,0,0,0,,At the early part of the-- Dialogue: 0,0:53:38.56,0:53:40.54,EN,,0,0,0,,PROFESSOR: Here. Dialogue: 0,0:53:41.31,0:53:43.31,EN,,0,0,0,,You want to know how x got down to three? Dialogue: 0,0:53:43.52,0:53:47.42,EN,,0,0,0,,AUDIENCE: Because x is the outer procedure, Dialogue: 0,0:53:48.46,0:53:50.99,EN,,0,0,0,,and x and y are the inner procedure. Dialogue: 0,0:53:51.26,0:53:51.88,EN,,0,0,0,,PROFESSOR: Fine. Dialogue: 0,0:53:52.84,0:53:54.62,EN,,0,0,0,,Well, I was very careful and mechanical. Dialogue: 0,0:53:55.02,0:53:56.92,EN,,0,0,0,,First of all, I should write those procedures Dialogue: 0,0:53:56.94,0:53:58.41,EN,,0,0,0,,again for you, pretty printed. Dialogue: 0,0:54:00.61,0:54:01.47,EN,,0,0,0,,First order of business, Dialogue: 0,0:54:01.48,0:54:02.99,EN,,0,0,0,,because you're probably not reading them well. Dialogue: 0,0:54:03.83,0:54:04.70,EN,,0,0,0,,So I have here Dialogue: 0,0:54:05.15,0:54:09.60,EN,,0,0,0,,that procedure of-- was it x over there-- Dialogue: 0,0:54:11.21,0:54:14.99,EN,,0,0,0,,which is -- value of that procedure of y Dialogue: 0,0:54:15.72,0:54:18.44,EN,,0,0,0,,which adds x to y, Dialogue: 0,0:54:19.82,0:54:21.10,EN,,0,0,0,,lambda, lambda, Dialogue: 0,0:54:21.40,0:54:22.89,EN,,0,0,0,,applied that to three, Dialogue: 0,0:54:24.08,0:54:26.12,EN,,0,0,0,,takes the result of that, and applied that to four. Dialogue: 0,0:54:26.14,0:54:28.81,EN,,0,0,0,,Is that not what I wrote? OK? Dialogue: 0,0:54:28.81,0:54:32.33,EN,,0,0,0,,Now, you should immediately see that Dialogue: 0,0:54:33.77,0:54:34.94,EN,,0,0,0,,here is an application-- Dialogue: 0,0:54:35.16,0:54:36.46,EN,,0,0,0,,let me get a white piece of chalk-- Dialogue: 0,0:54:37.32,0:54:41.12,EN,,0,0,0,,here is an application, a combination. Dialogue: 0,0:54:43.44,0:54:46.40,EN,,0,0,0,,OK? That combination has this as the operator Dialogue: 0,0:54:48.14,0:54:49.55,EN,,0,0,0,,and this as the operand. Dialogue: 0,0:54:51.04,0:54:53.05,EN,,0,0,0,,The three is going in for the x here. Dialogue: 0,0:54:54.90,0:54:56.36,EN,,0,0,0,,The result of this Dialogue: 0,0:54:56.56,0:54:58.46,EN,,0,0,0,,is a procedure of one argument y, Dialogue: 0,0:54:58.73,0:54:59.79,EN,,0,0,0,,which gets applied to four. Dialogue: 0,0:55:00.88,0:55:01.58,EN,,0,0,0,,OK? Dialogue: 0,0:55:02.20,0:55:04.08,EN,,0,0,0,,So you just weren't reading the expression right. Dialogue: 0,0:55:04.40,0:55:07.85,EN,,0,0,0,,The way you see that over here. OK. Dialogue: 0,0:55:09.42,0:55:12.96,EN,,0,0,0,,is that here I have the actual procedure object, x. Dialogue: 0,0:55:13.34,0:55:15.31,EN,,0,0,0,,It's getting applied to three, Dialogue: 0,0:55:15.95,0:55:17.07,EN,,0,0,0,,the list containing three. Dialogue: 0,0:55:18.98,0:55:21.34,EN,,0,0,0,,What I'm left over with is something which gets applied to four. Dialogue: 0,0:55:24.08,0:55:25.20,EN,,0,0,0,,Are there any other questions? Dialogue: 0,0:55:28.35,0:55:30.38,EN,,0,0,0,,Time for our next small break then. Dialogue: 0,0:55:30.83,0:55:31.37,EN,,0,0,0,,Thank you. Dialogue: 0,0:55:33.73,0:55:41.40,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:56:08.41,0:56:11.29,EN,,0,0,0,,PROFESSOR: Let's see, at this point, Dialogue: 0,0:56:13.32,0:56:14.59,EN,,0,0,0,,you should be getting the feeling, Dialogue: 0,0:56:14.75,0:56:17.96,EN,,0,0,0,,what's this nonsense this Sussman character is feeding me? Dialogue: 0,0:56:20.74,0:56:23.92,EN,,0,0,0,,There's an awful lot of strange nonsense here. Dialogue: 0,0:56:24.80,0:56:27.40,EN,,0,0,0,,After all, he purported to explain to me Lisp, Dialogue: 0,0:56:28.01,0:56:29.90,EN,,0,0,0,,and he wrote me a Lisp program on the blackboard. Dialogue: 0,0:56:31.23,0:56:33.53,EN,,0,0,0,,The Lisp program was intended to be interpreted for Lisp, Dialogue: 0,0:56:33.85,0:56:35.02,EN,,0,0,0,,but you need a Lisp interpreter Dialogue: 0,0:56:35.04,0:56:36.30,EN,,0,0,0,,in order to understand that program. Dialogue: 0,0:56:38.37,0:56:40.19,EN,,0,0,0,,How could that program have told me anything Dialogue: 0,0:56:40.22,0:56:43.20,EN,,0,0,0,,there is to be known about Lisp? Dialogue: 0,0:56:44.15,0:56:46.22,EN,,0,0,0,,How is that not completely vacuous? Dialogue: 0,0:56:48.49,0:56:50.25,EN,,0,0,0,,It's a very strange thing. Dialogue: 0,0:56:50.99,0:56:52.43,EN,,0,0,0,,Does it tell me anything at all? Dialogue: 0,0:56:56.07,0:56:57.20,EN,,0,0,0,,Well, you see, the whole thing Dialogue: 0,0:56:57.32,0:56:59.79,EN,,0,0,0,,is sort of like these Escher's hands Dialogue: 0,0:57:00.46,0:57:03.55,EN,,0,0,0,,that we see on this slide. Dialogue: 0,0:57:06.18,0:57:07.72,EN,,0,0,0,,Yes, eval and apply Dialogue: 0,0:57:07.76,0:57:10.16,EN,,0,0,0,,each sort of draw each other Dialogue: 0,0:57:11.50,0:57:14.16,EN,,0,0,0,,and construct the real thing, Dialogue: 0,0:57:14.86,0:57:16.30,EN,,0,0,0,,which can sit out and draw itself. Dialogue: 0,0:57:17.11,0:57:18.46,EN,,0,0,0,,Escher was a very brilliant man, Dialogue: 0,0:57:18.68,0:57:20.41,EN,,0,0,0,,he just didn't know the names of these spirits. Dialogue: 0,0:57:23.91,0:57:25.00,EN,,0,0,0,,Well, I'm going to do now, Dialogue: 0,0:57:26.09,0:57:28.00,EN,,0,0,0,,is I'm going to try to convince you Dialogue: 0,0:57:28.16,0:57:29.87,EN,,0,0,0,,that both this mean something, Dialogue: 0,0:57:30.16,0:57:31.98,EN,,0,0,0,,and, as a aside, Dialogue: 0,0:57:32.99,0:57:34.72,EN,,0,0,0,,I'm going to show you why you don't need definitions. Dialogue: 0,0:57:36.09,0:57:37.71,EN,,0,0,0,,Just turns out that sort of falls out, Dialogue: 0,0:57:38.09,0:57:41.12,EN,,0,0,0,,why definitions are not essential in a mathematical sense Dialogue: 0,0:57:42.51,0:57:44.89,EN,,0,0,0,,for doing all the things we need to do for computing. Dialogue: 0,0:57:49.10,0:57:50.03,EN,,0,0,0,,Well, let's see here. Dialogue: 0,0:57:50.69,0:57:53.31,EN,,0,0,0,,Consider the following small program, Dialogue: 0,0:57:53.74,0:57:54.64,EN,,0,0,0,,what does it mean? Dialogue: 0,0:57:54.87,0:57:57.64,EN,,0,0,0,,This is a program for computing exponentials. Dialogue: 0,0:58:07.27,0:58:13.23,EN,,0,0,0,,The exponential of x to the nth power is if-- Dialogue: 0,0:58:16.83,0:58:18.12,EN,,0,0,0,,n is zero, Dialogue: 0,0:58:19.20,0:58:20.76,EN,,0,0,0,,then the result is one. Dialogue: 0,0:58:22.07,0:58:22.81,EN,,0,0,0,,Otherwise, Dialogue: 0,0:58:25.56,0:58:28.48,EN,,0,0,0,,I want the product of x Dialogue: 0,0:58:28.75,0:58:33.93,EN,,0,0,0,,and the result of exponentiating x to the n minus one power. Dialogue: 0,0:58:43.69,0:58:44.56,EN,,0,0,0,,I think I got it right. Dialogue: 0,0:58:46.63,0:58:48.72,EN,,0,0,0,,Now this is a recursive definition. Dialogue: 0,0:58:49.47,0:58:52.17,EN,,0,0,0,,It's a definition of the exponentiation Dialogue: 0,0:58:52.46,0:58:54.78,EN,,0,0,0,,procedure in terms of itself. Dialogue: 0,0:58:56.41,0:58:58.32,EN,,0,0,0,,And, as it has been mentioned before, Dialogue: 0,0:58:59.28,0:59:01.68,EN,,0,0,0,,your high school geometry teacher Dialogue: 0,0:59:01.84,0:59:04.04,EN,,0,0,0,,probably gave you a hard time about things like that. Dialogue: 0,0:59:05.65,0:59:06.73,EN,,0,0,0,,Was that justified? Dialogue: 0,0:59:07.91,0:59:10.84,EN,,0,0,0,,Why does this self referential definition Dialogue: 0,0:59:10.96,0:59:12.04,EN,,0,0,0,,make any sense? Dialogue: 0,0:59:13.43,0:59:15.10,EN,,0,0,0,,Well, first of all, I'm going to convince you that Dialogue: 0,0:59:15.13,0:59:17.60,EN,,0,0,0,,your high school geometry teacher was not telling you nonsense. Dialogue: 0,0:59:20.37,0:59:23.42,EN,,0,0,0,,Consider the following set of definitions here. Dialogue: 0,0:59:24.27,0:59:27.42,EN,,0,0,0,,x plus y equals three, Dialogue: 0,0:59:28.24,0:59:32.24,EN,,0,0,0,,and x minus y equal one. Dialogue: 0,0:59:33.07,0:59:35.56,EN,,0,0,0,,Well, gee, this tells you x in terms of y, Dialogue: 0,0:59:35.58,0:59:37.84,EN,,0,0,0,,and this one tells you y in terms of x, presumably. Dialogue: 0,0:59:40.15,0:59:42.95,EN,,0,0,0,,And yet this happens to have a unique solution in x and y. Dialogue: 0,0:59:55.91,0:59:58.11,EN,,0,0,0,,However, I could also write Dialogue: 0,0:59:59.87,1:00:04.25,EN,,0,0,0,,two x plus two y is six. Dialogue: 0,1:00:06.83,1:00:09.87,EN,,0,0,0,,These two equations have an infinite number solutions. Dialogue: 0,1:00:15.73,1:00:17.42,EN,,0,0,0,,And I could write you, for example, Dialogue: 0,1:00:18.89,1:00:21.53,EN,,0,0,0,,x minus y equal 2, Dialogue: 0,1:00:22.14,1:00:24.41,EN,,0,0,0,,and these two equations have no solutions. Dialogue: 0,1:00:29.82,1:00:33.04,EN,,0,0,0,,Well, I have here three sets of simultaneous linear equations, Dialogue: 0,1:00:35.45,1:00:39.51,EN,,0,0,0,,this set, this set, and this set. Dialogue: 0,1:00:39.88,1:00:41.79,EN,,0,0,0,,But they have different numbers of solutions. Dialogue: 0,1:00:42.90,1:00:45.76,EN,,0,0,0,,The number of solutions is not in the form of the equations. Dialogue: 0,1:00:46.33,1:00:48.20,EN,,0,0,0,,They all three sets have the same form. Dialogue: 0,1:00:48.54,1:00:50.41,EN,,0,0,0,,The number of solutions is in the content. Dialogue: 0,1:00:53.00,1:00:55.15,EN,,0,0,0,,I can't tell by looking at the form of a definition Dialogue: 0,1:00:55.16,1:00:56.24,EN,,0,0,0,,whether it makes sense, Dialogue: 0,1:00:56.86,1:00:58.60,EN,,0,0,0,,only by its detailed content. Dialogue: 0,1:00:59.66,1:01:00.88,EN,,0,0,0,,What are the coefficients, Dialogue: 0,1:01:01.34,1:01:03.39,EN,,0,0,0,,for example, in the case of linear equations? Dialogue: 0,1:01:05.10,1:01:06.72,EN,,0,0,0,,So I shouldn't expect to be able to tell Dialogue: 0,1:01:06.99,1:01:08.33,EN,,0,0,0,,looking at something like this, Dialogue: 0,1:01:08.59,1:01:09.95,EN,,0,0,0,,from some simple things like, Dialogue: 0,1:01:10.08,1:01:14.49,EN,,0,0,0,,oh yes, EXPT is the solution of this recursion equation. Dialogue: 0,1:01:16.03,1:01:18.41,EN,,0,0,0,,Expt is the procedure Dialogue: 0,1:01:18.91,1:01:21.10,EN,,0,0,0,,which if substituted in here, Dialogue: 0,1:01:22.04,1:01:24.06,EN,,0,0,0,,gives me expt back. Dialogue: 0,1:01:25.32,1:01:25.68,EN,,0,0,0,,OK? Dialogue: 0,1:01:26.04,1:01:29.24,EN,,0,0,0,,I can't tell, looking at this form, Dialogue: 0,1:01:29.80,1:01:32.60,EN,,0,0,0,,whether or not there's a single, unique solution for EXPT, Dialogue: 0,1:01:33.23,1:01:35.31,EN,,0,0,0,,an infinite number of solutions, or no solutions. Dialogue: 0,1:01:37.20,1:01:38.62,EN,,0,0,0,,It's got to be how it counts Dialogue: 0,1:01:38.64,1:01:40.14,EN,,0,0,0,,and things like that, the details. Dialogue: 0,1:01:40.60,1:01:42.75,EN,,0,0,0,,And it's harder in programming than linear algebra. Dialogue: 0,1:01:43.28,1:01:45.21,EN,,0,0,0,,There aren't too many theorems about it in programming. Dialogue: 0,1:01:48.45,1:01:51.21,EN,,0,0,0,,Well, I want to rewrite these equations a little bit, Dialogue: 0,1:01:51.93,1:01:53.77,EN,,0,0,0,,these over here. Dialogue: 0,1:01:53.97,1:01:56.62,EN,,0,0,0,,Because what we're investigating is equations like this. Dialogue: 0,1:01:57.00,1:01:58.38,EN,,0,0,0,,But I want to play a little with equations Dialogue: 0,1:01:58.40,1:01:59.53,EN,,0,0,0,,like this that we understand, Dialogue: 0,1:02:00.70,1:02:02.91,EN,,0,0,0,,just so we get some insight into this kind of question. Dialogue: 0,1:02:04.72,1:02:06.43,EN,,0,0,0,,We could rewrite our equations here, Dialogue: 0,1:02:06.75,1:02:08.67,EN,,0,0,0,,say these two, the ones that are interesting, Dialogue: 0,1:02:09.77,1:02:14.86,EN,,0,0,0,,as x equals three minus y, Dialogue: 0,1:02:15.88,1:02:19.68,EN,,0,0,0,,and y equals x minus one. Dialogue: 0,1:02:22.01,1:02:24.05,EN,,0,0,0,,What do we call this transformation? Dialogue: 0,1:02:24.05,1:02:26.52,EN,,0,0,0,,This is a linear transformation, t. Dialogue: 0,1:02:29.43,1:02:32.25,EN,,0,0,0,,Then what we're getting here is an equation Dialogue: 0,1:02:32.97,1:02:37.37,EN,,0,0,0,,x y equals t of x y. Dialogue: 0,1:02:42.99,1:02:43.98,EN,,0,0,0,,What am I looking for? Dialogue: 0,1:02:44.56,1:02:46.01,EN,,0,0,0,,I'm looking for a fixed point of t. Dialogue: 0,1:02:46.97,1:02:59.42,EN,,0,0,0,,The solution is a fixed point of t. Dialogue: 0,1:03:01.91,1:03:05.53,EN,,0,0,0,,So the methods we should have for looking for solutions to equations, Dialogue: 0,1:03:05.90,1:03:07.48,EN,,0,0,0,,if I can do it by fixed points, Dialogue: 0,1:03:08.65,1:03:09.87,EN,,0,0,0,,might be applicable. Dialogue: 0,1:03:10.88,1:03:12.36,EN,,0,0,0,,If I have a means of finding a solution Dialogue: 0,1:03:12.38,1:03:14.32,EN,,0,0,0,,to an equations by fixed points-- Dialogue: 0,1:03:15.52,1:03:18.19,EN,,0,0,0,,just, might not work-- Dialogue: 0,1:03:18.57,1:03:19.80,EN,,0,0,0,,but it might be applicable Dialogue: 0,1:03:20.09,1:03:22.27,EN,,0,0,0,,to investigating solutions of equations like this. Dialogue: 0,1:03:27.24,1:03:29.48,EN,,0,0,0,,But what I want you to feel is that this is an equation. Dialogue: 0,1:03:30.26,1:03:31.21,EN,,0,0,0,,It's an expression Dialogue: 0,1:03:31.36,1:03:33.58,EN,,0,0,0,,with several instances of various names Dialogue: 0,1:03:34.70,1:03:37.66,EN,,0,0,0,,which puts a constraint on the name, Dialogue: 0,1:03:38.43,1:03:40.52,EN,,0,0,0,,saying what that name could have as its value, Dialogue: 0,1:03:41.48,1:03:45.01,EN,,0,0,0,,rather than some sort of mechanical process of substitution right now. Dialogue: 0,1:03:47.74,1:03:49.77,EN,,0,0,0,,This is an equation which I'm going to try to solve. Dialogue: 0,1:03:51.22,1:03:52.43,EN,,0,0,0,,Well, let's play around and solve it. Dialogue: 0,1:03:53.96,1:03:55.66,EN,,0,0,0,,First of all, I want to write down Dialogue: 0,1:03:56.64,1:03:59.00,EN,,0,0,0,,the function which corresponds to t. Dialogue: 0,1:04:00.32,1:04:03.00,EN,,0,0,0,,First I want to write down the function which corresponds to t Dialogue: 0,1:04:04.49,1:04:06.96,EN,,0,0,0,,whose fixed point is the answer to this question. Dialogue: 0,1:04:10.76,1:04:11.28,EN,,0,0,0,,OK? Dialogue: 0,1:04:12.25,1:04:14.30,EN,,0,0,0,,Well, let's consider the following procedure f. Dialogue: 0,1:04:16.87,1:04:18.30,EN,,0,0,0,,I claim it computes that function. Dialogue: 0,1:04:19.34,1:04:22.91,EN,,0,0,0,,f is that procedure of one argument g, Dialogue: 0,1:04:25.23,1:04:25.93,EN,,0,0,0,,which is Dialogue: 0,1:04:26.40,1:04:32.00,EN,,0,0,0,,that procedure of two arguments x and n. Dialogue: 0,1:04:33.43,1:04:34.73,EN,,0,0,0,,Which have the property that Dialogue: 0,1:04:36.72,1:04:40.43,EN,,0,0,0,,if n is zero, Dialogue: 0,1:04:41.72,1:04:43.20,EN,,0,0,0,,then the result is one, Dialogue: 0,1:04:45.34,1:04:46.17,EN,,0,0,0,,otherwise, Dialogue: 0,1:04:49.90,1:05:01.40,EN,,0,0,0,,the result is the product of x and g, applied to x, and minus n1. Dialogue: 0,1:05:03.37,1:05:07.80,EN,,0,0,0,,g, times, else, COND, lambda, lambda-- Dialogue: 0,1:05:08.94,1:05:09.40,EN,,0,0,0,,OK? Dialogue: 0,1:05:12.30,1:05:14.62,EN,,0,0,0,,Here f is a procedure, Dialogue: 0,1:05:15.05,1:05:17.79,EN,,0,0,0,,which if I had a solution to that equation, Dialogue: 0,1:05:19.04,1:05:22.04,EN,,0,0,0,,if I had a good exponentiation procedure, Dialogue: 0,1:05:23.42,1:05:26.32,EN,,0,0,0,,and I applied f to that procedure, Dialogue: 0,1:05:27.60,1:05:31.24,EN,,0,0,0,,then the result would be a good exponentiation procedure. Dialogue: 0,1:05:37.46,1:05:38.57,EN,,0,0,0,,Because, what does it do? Dialogue: 0,1:05:39.42,1:05:40.88,EN,,0,0,0,,Well, all it is Dialogue: 0,1:05:42.36,1:05:44.64,EN,,0,0,0,,is exposing g were a good exponentiation procedure, Dialogue: 0,1:05:45.63,1:05:47.58,EN,,0,0,0,,well then this would produce, as its value, Dialogue: 0,1:05:47.84,1:05:49.68,EN,,0,0,0,,a procedure to arguments x and n, Dialogue: 0,1:05:50.49,1:05:51.52,EN,,0,0,0,,such that if n were 0, Dialogue: 0,1:05:51.55,1:05:52.41,EN,,0,0,0,,the result would be one, Dialogue: 0,1:05:52.44,1:05:54.16,EN,,0,0,0,,which is certainly true of exponentiation. Dialogue: 0,1:05:54.64,1:05:57.05,EN,,0,0,0,,Otherwise, it will be the result of multiplying x Dialogue: 0,1:05:57.26,1:05:59.26,EN,,0,0,0,,by the exponentiation procedure given to me Dialogue: 0,1:06:00.17,1:06:02.44,EN,,0,0,0,,with x and n minus one as arguments. Dialogue: 0,1:06:03.47,1:06:04.78,EN,,0,0,0,,So if this computed the correct Dialogue: 0,1:06:04.81,1:06:06.30,EN,,0,0,0,,exponentiation for n minus one, Dialogue: 0,1:06:07.87,1:06:11.28,EN,,0,0,0,,then this would be the correct exponentiation for exponent n, Dialogue: 0,1:06:12.17,1:06:14.41,EN,,0,0,0,,so this would have been the right exponentiation procedure. Dialogue: 0,1:06:17.50,1:06:19.82,EN,,0,0,0,,So what I really want to say here is Dialogue: 0,1:06:21.02,1:06:32.44,EN,,0,0,0,,E-X-P-T is a fixed point of f. Dialogue: 0,1:06:36.99,1:06:38.35,EN,,0,0,0,,Now our problem is Dialogue: 0,1:06:38.35,1:06:39.68,EN,,0,0,0,,there might be more than one fixed point. Dialogue: 0,1:06:40.06,1:06:42.19,EN,,0,0,0,,There might be no fixed points. Dialogue: 0,1:06:43.27,1:06:44.81,EN,,0,0,0,,I have to go hunting for the fixed points. Dialogue: 0,1:06:48.22,1:06:49.37,EN,,0,0,0,,Got to solve this equation. Dialogue: 0,1:06:52.16,1:06:54.28,EN,,0,0,0,,Well there are various ways to hunt for fixed points. Dialogue: 0,1:06:55.58,1:06:57.08,EN,,0,0,0,,Of course, the one we played with Dialogue: 0,1:06:57.24,1:07:01.16,EN,,0,0,0,,at the beginning of this term worked for cosine. Dialogue: 0,1:07:02.73,1:07:07.69,EN,,0,0,0,,Going to. Go into radians mode on your calculator Dialogue: 0,1:07:07.85,1:07:10.51,EN,,0,0,0,,and push cosine, and just keep doing it, Dialogue: 0,1:07:11.84,1:07:15.45,EN,,0,0,0,,and you get to some number which is about 0.73 or 0.74. Dialogue: 0,1:07:16.09,1:07:17.18,EN,,0,0,0,,I can't remember which. Dialogue: 0,1:07:20.57,1:07:22.64,EN,,0,0,0,,By iterating a procedure, which has Dialogue: 0,1:07:22.81,1:07:24.40,EN,,0,0,0,,By iterating a function, Dialogue: 0,1:07:25.60,1:07:27.16,EN,,0,0,0,,whose fixed point I'm searching for, Dialogue: 0,1:07:27.50,1:07:31.13,EN,,0,0,0,,it is sometimes the case that that function will converge Dialogue: 0,1:07:31.87,1:07:33.08,EN,,0,0,0,,in producing the fixed point. Dialogue: 0,1:07:33.77,1:07:35.44,EN,,0,0,0,,I think we luck out in this case, Dialogue: 0,1:07:36.44,1:07:37.21,EN,,0,0,0,,so let's look for it. Dialogue: 0,1:07:39.91,1:07:46.28,EN,,0,0,0,,Let's look at this overhead, this slide. Dialogue: 0,1:07:48.03,1:07:51.71,EN,,0,0,0,,Consider the following sequence of procedures. Dialogue: 0,1:07:56.40,1:07:57.79,EN,,0,0,0,,e0 over here Dialogue: 0,1:07:59.24,1:08:01.63,EN,,0,0,0,,the procedure which does nothing at all. Dialogue: 0,1:08:02.89,1:08:05.10,EN,,0,0,0,,It's the procedure which produces an error Dialogue: 0,1:08:05.10,1:08:06.24,EN,,0,0,0,,for any arguments you give it. Dialogue: 0,1:08:07.78,1:08:09.03,EN,,0,0,0,,It's basically useless. Dialogue: 0,1:08:14.48,1:08:20.08,EN,,0,0,0,,Well, however, I can make an approximation. Dialogue: 0,1:08:20.08,1:08:23.93,EN,,0,0,0,,Let's consider it the worst possible approximation to exponentiation, Dialogue: 0,1:08:24.73,1:08:25.53,EN,,0,0,0,,because it does nothing. Dialogue: 0,1:08:26.99,1:08:29.68,EN,,0,0,0,,Well, supposing I substituted e0 Dialogue: 0,1:08:30.35,1:08:33.26,EN,,0,0,0,,for g by calling f, Dialogue: 0,1:08:33.79,1:08:36.30,EN,,0,0,0,,as you see over here on e0. Dialogue: 0,1:08:37.38,1:08:39.77,EN,,0,0,0,,So you see over here, have e0 there. Dialogue: 0,1:08:40.84,1:08:42.35,EN,,0,0,0,,Then gee, what's e1? Dialogue: 0,1:08:43.63,1:08:46.03,EN,,0,0,0,,e1 is a procedure which exponentiate things Dialogue: 0,1:08:46.67,1:08:48.78,EN,,0,0,0,,to the 0th power, with no trouble. Dialogue: 0,1:08:49.60,1:08:50.75,EN,,0,0,0,,It gets the right answer, Dialogue: 0,1:08:51.05,1:08:52.35,EN,,0,0,0,,anything to the zero is one, Dialogue: 0,1:08:52.68,1:08:54.25,EN,,0,0,0,,and it makes an error on anything else. Dialogue: 0,1:08:57.39,1:09:01.56,EN,,0,0,0,,Well, now what if I take e1 Dialogue: 0,1:09:02.30,1:09:07.40,EN,,0,0,0,,and substituted it for g by calling f on e1? Dialogue: 0,1:09:09.58,1:09:11.18,EN,,0,0,0,,Oh gosh, Dialogue: 0,1:09:12.01,1:09:15.02,EN,,0,0,0,,I have here a procedure of two arguments. Dialogue: 0,1:09:15.67,1:09:16.84,EN,,0,0,0,,Now remember e1 Dialogue: 0,1:09:16.96,1:09:19.66,EN,,0,0,0,,was appropriate for taking exponentiations of 0, Dialogue: 0,1:09:21.47,1:09:23.37,EN,,0,0,0,,for raising to the 0 exponent. Dialogue: 0,1:09:24.20,1:09:25.00,EN,,0,0,0,,So here, Dialogue: 0,1:09:25.52,1:09:27.28,EN,,0,0,0,,if is n is 0, the result is one, Dialogue: 0,1:09:27.29,1:09:28.67,EN,,0,0,0,,so this guy is good for that too. Dialogue: 0,1:09:29.52,1:09:32.01,EN,,0,0,0,,However, I can use something for raising to the 0th power Dialogue: 0,1:09:32.51,1:09:35.26,EN,,0,0,0,,to multiply it by x to raise something to the first power. Dialogue: 0,1:09:35.97,1:09:39.67,EN,,0,0,0,,So e2 is good for both power 0 and 1. Dialogue: 0,1:09:41.60,1:09:41.92,EN,,0,0,0,,OK? Dialogue: 0,1:09:43.71,1:09:46.67,EN,,0,0,0,,And e3 is constructed from e2 in the same way. Dialogue: 0,1:09:47.89,1:09:50.24,EN,,0,0,0,,And e3, of course, by the same argument Dialogue: 0,1:09:50.32,1:09:53.37,EN,,0,0,0,,is good for powers 0, one, and two. Dialogue: 0,1:09:55.12,1:09:55.40,EN,,0,0,0,,OK? Dialogue: 0,1:09:56.09,1:09:59.08,EN,,0,0,0,,And so I will assert for you, without proof, Dialogue: 0,1:09:59.66,1:10:01.72,EN,,0,0,0,,because the proof is horribly difficult. Dialogue: 0,1:10:02.52,1:10:03.60,EN,,0,0,0,,And that's the sort of thing that Dialogue: 0,1:10:03.63,1:10:06.36,EN,,0,0,0,,people called denotational semanticists do. Dialogue: 0,1:10:06.59,1:10:07.64,EN,,0,0,0,,I suppose it was invented Dialogue: 0,1:10:07.87,1:10:10.59,EN,,0,0,0,,This great idea was invented by Scott and Strachey. Dialogue: 0,1:10:11.64,1:10:16.32,EN,,0,0,0,,Ah, sort of. They're very famous mathematician types Dialogue: 0,1:10:16.86,1:10:21.21,EN,,0,0,0,,who invented the interpretation for these programs that we have Dialogue: 0,1:10:22.36,1:10:24.00,EN,,0,0,0,,that I'm talking to you about right now. Dialogue: 0,1:10:24.24,1:10:26.17,EN,,0,0,0,,And they proved, by topology Dialogue: 0,1:10:27.04,1:10:29.32,EN,,0,0,0,,that there is such a fixed point Dialogue: 0,1:10:29.82,1:10:31.26,EN,,0,0,0,,in the cases that we want. Dialogue: 0,1:10:32.22,1:10:33.24,EN,,0,0,0,,But the assertion is Dialogue: 0,1:10:33.40,1:10:44.24,EN,,0,0,0,,E-X-P-T is limit as n goes to infinity of em. Dialogue: 0,1:10:45.52,1:10:47.90,EN,,0,0,0,,and And that we've constructed this by the following way. Dialogue: 0,1:10:50.52,1:10:55.66,EN,,0,0,0,,--is Well, it's f of, f of, f of, f of, f of-- Dialogue: 0,1:10:57.61,1:11:00.19,EN,,0,0,0,,f applied to anything at all. Dialogue: 0,1:11:01.12,1:11:02.46,EN,,0,0,0,,It didn't matter what that was, Dialogue: 0,1:11:03.18,1:11:05.00,EN,,0,0,0,,because, in fact, this always produces an error. Dialogue: 0,1:11:07.45,1:11:08.41,EN,,0,0,0,,Applied to this-- Dialogue: 0,1:11:12.89,1:11:14.48,EN,,0,0,0,,That's by infinite nesting of f's. Dialogue: 0,1:11:16.38,1:11:17.71,EN,,0,0,0,,So now my problem Dialogue: 0,1:11:18.22,1:11:19.76,EN,,0,0,0,,is to make some infinite things. Dialogue: 0,1:11:22.59,1:11:24.08,EN,,0,0,0,,We need some infinite things. Dialogue: 0,1:11:24.92,1:11:26.25,EN,,0,0,0,,How am I going to nest up an f Dialogue: 0,1:11:26.56,1:11:27.80,EN,,0,0,0,,an infinite number of times? Dialogue: 0,1:11:28.98,1:11:30.12,EN,,0,0,0,,I'd better construct this. Dialogue: 0,1:11:32.38,1:11:32.93,EN,,0,0,0,,Well, I don't know. Dialogue: 0,1:11:32.93,1:11:34.32,EN,,0,0,0,,How would I make an infinite loop at all? Dialogue: 0,1:11:34.81,1:11:36.32,EN,,0,0,0,,Let's take a very simple infinite loop, Dialogue: 0,1:11:36.57,1:11:38.34,EN,,0,0,0,,the simplest infinite loop imaginable. Dialogue: 0,1:11:43.55,1:11:47.55,EN,,0,0,0,,If I were to take that procedure of one argument x Dialogue: 0,1:11:48.00,1:11:49.79,EN,,0,0,0,,which applies x to x Dialogue: 0,1:11:53.55,1:11:53.92,EN,,0,0,0,,OK? Dialogue: 0,1:11:55.05,1:11:58.41,EN,,0,0,0,,and apply that to the procedure of one argument x Dialogue: 0,1:11:59.36,1:12:01.05,EN,,0,0,0,,which applies x to x, Dialogue: 0,1:12:04.83,1:12:06.00,EN,,0,0,0,,then this is an infinite loop. Dialogue: 0,1:12:07.21,1:12:09.31,EN,,0,0,0,,The reason why this is an infinite loop is as follows. Dialogue: 0,1:12:09.98,1:12:11.31,EN,,0,0,0,,The way I understand this Dialogue: 0,1:12:11.52,1:12:13.69,EN,,0,0,0,,is I substitute the argument Dialogue: 0,1:12:14.22,1:12:16.59,EN,,0,0,0,,for the formal parameter in the body. Dialogue: 0,1:12:18.85,1:12:21.60,EN,,0,0,0,,But if I do that, I take for each of these x's, Dialogue: 0,1:12:22.40,1:12:23.76,EN,,0,0,0,,I substitute one of these, Dialogue: 0,1:12:24.36,1:12:26.96,EN,,0,0,0,,making a copy of the original expression I just started with, Dialogue: 0,1:12:28.35,1:12:29.37,EN,,0,0,0,,the simplest infinite loop. Dialogue: 0,1:12:35.44,1:12:39.29,EN,,0,0,0,,Now I want to tell you about a particular operator Dialogue: 0,1:12:40.38,1:12:43.09,EN,,0,0,0,,which is constructed by a perturbation from this infinite loop. Dialogue: 0,1:12:46.96,1:12:47.92,EN,,0,0,0,,I'll call it y. Dialogue: 0,1:12:50.89,1:12:55.82,EN,,0,0,0,,OK y -- This is called Curry's Paradoxical Combinator of y Dialogue: 0,1:12:56.62,1:12:58.99,EN,,0,0,0,,after a fellow by the name of Curry, Dialogue: 0,1:12:59.34,1:13:01.85,EN,,0,0,0,,who was a logician of the 1930s also. Dialogue: 0,1:13:04.48,1:13:06.88,EN,,0,0,0,,And if I have a procedure of one argument f, Dialogue: 0,1:13:08.17,1:13:09.33,EN,,0,0,0,,what's it going to have in it? Dialogue: 0,1:13:09.33,1:13:11.20,EN,,0,0,0,,It's going to have a kind of infinite loop in it, Dialogue: 0,1:13:11.98,1:13:15.47,EN,,0,0,0,,which is that procedure of one argument x Dialogue: 0,1:13:15.95,1:13:18.80,EN,,0,0,0,,which applies f to x of x, Dialogue: 0,1:13:21.63,1:13:24.75,EN,,0,0,0,,applied to that procedure of one argument x, Dialogue: 0,1:13:25.10,1:13:27.34,EN,,0,0,0,,which applies f to f of x. Dialogue: 0,1:13:32.30,1:13:33.13,EN,,0,0,0,,Now what's this do? Dialogue: 0,1:13:34.80,1:13:36.06,EN,,0,0,0,,Suppose we apply y to F. Dialogue: 0,1:13:41.31,1:13:42.57,EN,,0,0,0,,OK? Well, that's easy enough. Dialogue: 0,1:13:43.15,1:13:44.62,EN,,0,0,0,,That's this capital F over here. Dialogue: 0,1:13:46.91,1:13:48.16,EN,,0,0,0,,Well, the easiest thing to say there Dialogue: 0,1:13:48.30,1:13:49.92,EN,,0,0,0,,is, I substitute F for here. Dialogue: 0,1:13:55.32,1:13:57.07,EN,,0,0,0,,So that's going to give me, basically-- Dialogue: 0,1:13:58.75,1:14:00.84,EN,,0,0,0,,because then I'm going to substitute this Dialogue: 0,1:14:01.45,1:14:02.80,EN,,0,0,0,,for x in here. Dialogue: 0,1:14:04.17,1:14:05.23,EN,,0,0,0,,That F of Dialogue: 0,1:14:08.97,1:14:10.09,EN,,0,0,0,,Let me actually do it in steps, Dialogue: 0,1:14:10.22,1:14:11.45,EN,,0,0,0,,so you can see it completely. Dialogue: 0,1:14:11.92,1:14:14.27,EN,,0,0,0,,I'm going to be very careful. OK? Dialogue: 0,1:14:15.02,1:14:18.25,EN,,0,0,0,,This is open, open, lambda of x , Dialogue: 0,1:14:19.08,1:14:22.11,EN,,0,0,0,,capital F, x, x, Dialogue: 0,1:14:26.88,1:14:35.55,EN,,0,0,0,,applied to itself, F of x of x. Dialogue: 0,1:14:37.91,1:14:39.66,EN,,0,0,0,,Substituting this for this in here, Dialogue: 0,1:14:40.06,1:14:40.91,EN,,0,0,0,,this is Dialogue: 0,1:14:43.13,1:14:48.35,EN,,0,0,0,,F applied to-- what is it-- substituting this in here Dialogue: 0,1:14:48.65,1:14:54.81,EN,,0,0,0,,open, open, lambda of x, F, of x and x, Dialogue: 0,1:14:57.07,1:14:58.17,EN,,0,0,0,,applied to Dialogue: 0,1:14:59.18,1:15:06.48,EN,,0,0,0,,lambda of x, F of x of x, F, Dialogue: 0,1:15:06.99,1:15:10.44,EN,,0,0,0,,lambda, pair, F. Dialogue: 0,1:15:11.51,1:15:12.40,EN,,0,0,0,,Oh, but what is this? Dialogue: 0,1:15:13.42,1:15:16.35,EN,,0,0,0,,This thing over here that I just computed, Dialogue: 0,1:15:17.13,1:15:18.56,EN,,0,0,0,,is this thing over here. Dialogue: 0,1:15:20.19,1:15:21.84,EN,,0,0,0,,But I just wrapped another F around it. Dialogue: 0,1:15:23.37,1:15:24.67,EN,,0,0,0,,So by applying y to F, Dialogue: 0,1:15:24.68,1:15:26.22,EN,,0,0,0,,I make an infinite series of F's. Dialogue: 0,1:15:27.85,1:15:29.45,EN,,0,0,0,,If I just let this run forever, Dialogue: 0,1:15:29.69,1:15:31.77,EN,,0,0,0,,I'll just keep making more and more F's outside. Dialogue: 0,1:15:33.17,1:15:34.80,EN,,0,0,0,,I ran an infinite loop which is useless, Dialogue: 0,1:15:35.20,1:15:37.02,EN,,0,0,0,,but it doesn't matter that the inside is useless. Dialogue: 0,1:15:39.85,1:15:47.85,EN,,0,0,0,,OK? So y of F is F applied to y of F. Dialogue: 0,1:15:50.33,1:15:52.14,EN,,0,0,0,,So y is a magical thing Dialogue: 0,1:15:53.85,1:15:56.25,EN,,0,0,0,,which, when applied to some function, Dialogue: 0,1:15:57.37,1:16:00.38,EN,,0,0,0,,produces the object which is the fixed point of that function, Dialogue: 0,1:16:01.69,1:16:04.25,EN,,0,0,0,,if it exists, and if this all works. Dialogue: 0,1:16:07.91,1:16:10.08,EN,,0,0,0,,Because, indeed, if I take y of F Dialogue: 0,1:16:10.12,1:16:11.12,EN,,0,0,0,,I get y of F out. Dialogue: 0,1:16:16.24,1:16:18.86,EN,,0,0,0,,Now I want you to think this in terms of Dialogue: 0,1:16:19.85,1:16:22.38,EN,,0,0,0,,the eval-apply interpreter for a bit. Dialogue: 0,1:16:23.86,1:16:26.27,EN,,0,0,0,,I wrote down a whole bunch of recursion equations out there. Dialogue: 0,1:16:28.54,1:16:30.22,EN,,0,0,0,,They're simultaneous in the same way Dialogue: 0,1:16:30.22,1:16:31.23,EN,,0,0,0,,these are simultaneous equations. Dialogue: 0,1:16:31.47,1:16:33.31,EN,,0,0,0,,Exponentiation was not a simultaneous equation. Dialogue: 0,1:16:33.31,1:16:35.79,EN,,0,0,0,,It was only one variable I was looking for a meaning for. Dialogue: 0,1:16:38.15,1:16:40.76,EN,,0,0,0,,But what Lisp is is the fixed point of the process Dialogue: 0,1:16:40.81,1:16:42.57,EN,,0,0,0,,that's which says, if I knew what Lisp was Dialogue: 0,1:16:42.59,1:16:46.51,EN,,0,0,0,,and substituted it in for eval, and apply, and so on, Dialogue: 0,1:16:46.59,1:16:49.79,EN,,0,0,0,,on the right hand sides of all those recursion equations, Dialogue: 0,1:16:50.94,1:16:53.96,EN,,0,0,0,,then if it was a real good Lisp, is a real one, Dialogue: 0,1:16:54.36,1:16:56.30,EN,,0,0,0,,then the left hand side would also be Lisp. Dialogue: 0,1:16:58.22,1:16:59.82,EN,,0,0,0,,So I made sense of that definition. Dialogue: 0,1:17:02.42,1:17:05.41,EN,,0,0,0,,Now whether or not there's an answer isn't so obvious. Dialogue: 0,1:17:05.69,1:17:06.75,EN,,0,0,0,,I can't attack that. Dialogue: 0,1:17:07.74,1:17:09.21,EN,,0,0,0,,Now these arguments that I'm giving you now Dialogue: 0,1:17:09.26,1:17:10.27,EN,,0,0,0,,are quite dangerous. Dialogue: 0,1:17:10.66,1:17:11.64,EN,,0,0,0,,Let's look over here. Dialogue: 0,1:17:13.05,1:17:14.61,EN,,0,0,0,,On the. These are limit arguments. Dialogue: 0,1:17:14.61,1:17:15.39,EN,,0,0,0,,We're talking about limits, Dialogue: 0,1:17:15.45,1:17:17.68,EN,,0,0,0,,and it's really calculus, or topology, Dialogue: 0,1:17:17.87,1:17:20.03,EN,,0,0,0,,or something like that, a kind of analysis. Dialogue: 0,1:17:20.76,1:17:23.38,EN,,0,0,0,,OK?Now here's an argument that you all believe. Dialogue: 0,1:17:23.38,1:17:25.29,EN,,0,0,0,,And I want to make sure you realize Dialogue: 0,1:17:25.42,1:17:27.66,EN,,0,0,0,,that I could be bullshitting you. Dialogue: 0,1:17:28.86,1:17:30.48,EN,,0,0,0,,Alright? What is this? Dialogue: 0,1:17:34.25,1:17:39.52,EN,,0,0,0,,u is the sum of 1/2, 1/4, and 1/8, and so on, Dialogue: 0,1:17:39.74,1:17:41.32,EN,,0,0,0,,the sum of a geometric series. Dialogue: 0,1:17:42.82,1:17:44.68,EN,,0,0,0,,And, of course, I could play a game here. Dialogue: 0,1:17:44.82,1:17:47.57,EN,,0,0,0,,u minus one is 1/2, plus 1/4, plus 1/8, and so on. Dialogue: 0,1:17:51.90,1:17:54.46,EN,,0,0,0,,But now if I multiple. What I could do here-- Dialogue: 0,1:17:56.09,1:17:57.93,EN,,0,0,0,,Ooops. There is a parentheses error here. Dialogue: 0,1:17:58.92,1:18:01.45,EN,,0,0,0,,But I can put here two times u minus one Dialogue: 0,1:18:01.74,1:18:03.99,EN,,0,0,0,,is one plus 1/2, plus 1/4, plus 1/8. Dialogue: 0,1:18:07.57,1:18:08.54,EN,,0,0,0,,Can I fix that? Dialogue: 0,1:18:14.01,1:18:16.43,EN,,0,0,0,,Yes, well. Dialogue: 0,1:18:18.19,1:18:18.65,EN,,0,0,0,,OK? Dialogue: 0,1:18:19.52,1:18:20.64,EN,,0,0,0,,But that gives me back Dialogue: 0,1:18:23.53,1:18:26.64,EN,,0,0,0,,two times u minus one is u, Dialogue: 0,1:18:27.80,1:18:29.58,EN,,0,0,0,,therefore, we conclude that u is two. Dialogue: 0,1:18:30.30,1:18:31.37,EN,,0,0,0,,And this actually is true. Dialogue: 0,1:18:31.96,1:18:33.32,EN,,0,0,0,,There's no problem like that. Dialogue: 0,1:18:34.04,1:18:37.55,EN,,0,0,0,,But supposing I did something different. Dialogue: 0,1:18:38.54,1:18:39.48,EN,,0,0,0,,Supposing I start up with something Dialogue: 0,1:18:39.50,1:18:41.20,EN,,0,0,0,,which manifestly has no sum. Dialogue: 0,1:18:41.56,1:18:46.99,EN,,0,0,0,,v is one, plus two, plus four, plus 8, plus dot, dot, dot. OK? Dialogue: 0,1:18:47.39,1:18:51.39,EN,,0,0,0,,Well, v minus one is surely two, plus four, plus eight, plus dot, dot, dot. Right? Dialogue: 0,1:18:52.27,1:18:56.03,EN,,0,0,0,,v minus one over two, gee, that looks like v again. Dialogue: 0,1:18:57.41,1:19:00.54,EN,,0,0,0,,From that I should be able to conclude that-- Dialogue: 0,1:19:01.37,1:19:02.91,EN,,0,0,0,,that's also wrong, apparently. Dialogue: 0,1:19:03.07,1:19:04.51,EN,,0,0,0,,v equals minus one. Dialogue: 0,1:19:12.45,1:19:13.82,EN,,0,0,0,,That should be a minus one. Dialogue: 0,1:19:15.28,1:19:16.91,EN,,0,0,0,,And that's certainly a false conclusion. Dialogue: 0,1:19:22.00,1:19:23.47,EN,,0,0,0,,So when you play with limits, Dialogue: 0,1:19:24.22,1:19:27.85,EN,,0,0,0,,arguments that may work in one case Dialogue: 0,1:19:29.42,1:19:30.75,EN,,0,0,0,,they may not work in some other case. Dialogue: 0,1:19:30.75,1:19:31.69,EN,,0,0,0,,You have to be very careful. Dialogue: 0,1:19:32.24,1:19:33.87,EN,,0,0,0,,The arguments have to be well-formed. Dialogue: 0,1:19:36.14,1:19:39.23,EN,,0,0,0,,And I don't know, in general, Dialogue: 0,1:19:39.85,1:19:41.93,EN,,0,0,0,,what the story is about arguments like this. Dialogue: 0,1:19:43.27,1:19:45.24,EN,,0,0,0,,We can read a pile of topology and find out. Dialogue: 0,1:19:46.27,1:19:48.64,EN,,0,0,0,,But, surely, at least you understand now, Dialogue: 0,1:19:49.10,1:19:51.13,EN,,0,0,0,,why it might be some meaning Dialogue: 0,1:19:51.15,1:19:52.76,EN,,0,0,0,,to the things we've been writing on the blackboard. Dialogue: 0,1:19:53.66,1:19:55.61,EN,,0,0,0,,And you understand what that might mean. Dialogue: 0,1:19:56.48,1:19:58.35,EN,,0,0,0,,So, I suppose, it's almost about time Dialogue: 0,1:19:59.07,1:20:03.84,EN,,0,0,0,,for you to merit being made a member Dialogue: 0,1:20:04.28,1:20:05.55,EN,,0,0,0,,of the grand recursive order Dialogue: 0,1:20:05.56,1:20:07.04,EN,,0,0,0,,of lambda calculus hackers. Dialogue: 0,1:20:08.84,1:20:10.17,EN,,0,0,0,,I would. This is the badge. Dialogue: 0,1:20:10.82,1:20:12.54,EN,,0,0,0,,Because you now understand, for example, Dialogue: 0,1:20:13.40,1:20:15.20,EN,,0,0,0,,what it says at the very top, Dialogue: 0,1:20:16.89,1:20:18.41,EN,,0,0,0,,y F equals F y F. Dialogue: 0,1:20:21.04,1:20:21.66,EN,,0,0,0,,Thank you. Dialogue: 0,1:20:21.85,1:20:22.75,EN,,0,0,0,,Are there any questions? Dialogue: 0,1:20:24.71,1:20:25.15,EN,,0,0,0,,Yes, Lev. Dialogue: 0,1:20:25.37,1:20:27.39,EN,,0,0,0,,AUDIENCE: With this, it seems that Dialogue: 0,1:20:27.40,1:20:30.22,EN,,0,0,0,,there's no need to define, as you imply, Dialogue: 0,1:20:30.24,1:20:32.70,EN,,0,0,0,,to just remember a value, to apply it later. Dialogue: 0,1:20:32.99,1:20:33.32,EN,,0,0,0,,PROFESSOR: Yeah. Dialogue: 0,1:20:33.50,1:20:36.44,EN,,0,0,0,,AUDIENCE: Defines were kind of a side-effect it seemed in the language. Dialogue: 0,1:20:36.49,1:20:38.52,EN,,0,0,0,,[INTERPOSING] are order dependent. Dialogue: 0,1:20:39.30,1:20:42.06,EN,,0,0,0,,Does this eliminate the side-effect from the. Dialogue: 0,1:20:42.28,1:20:44.68,EN,,0,0,0,,PROFESSOR: Well. The answer is, Dialogue: 0,1:20:44.88,1:20:46.44,EN,,0,0,0,,this is not the way these things were implemented. Dialogue: 0,1:20:47.52,1:20:47.93,EN,,0,0,0,,OK? Dialogue: 0,1:20:48.92,1:20:53.15,EN,,0,0,0,,Define, indeed is implemented as an operation Dialogue: 0,1:20:53.18,1:20:55.53,EN,,0,0,0,,that actually modifies an environment structure, Dialogue: 0,1:20:57.95,1:21:02.33,EN,,0,0,0,,changes the frame that the define is executed in. Dialogue: 0,1:21:03.69,1:21:06.51,EN,,0,0,0,,And there are many reasons for that, Dialogue: 0,1:21:07.39,1:21:08.64,EN,,0,0,0,,but a lot of this has to do with Dialogue: 0,1:21:08.67,1:21:10.09,EN,,0,0,0,,making an interactive system. Dialogue: 0,1:21:11.34,1:21:14.12,EN,,0,0,0,,What this is saying is that if you've made a system, Dialogue: 0,1:21:14.35,1:21:15.20,EN,,0,0,0,,and you know Dialogue: 0,1:21:15.42,1:21:16.60,EN,,0,0,0,,and you know you're not going to do any debugging Dialogue: 0,1:21:16.60,1:21:17.55,EN,,0,0,0,,or anything like that, Dialogue: 0,1:21:17.84,1:21:20.72,EN,,0,0,0,,and you know everything there is all at once, Dialogue: 0,1:21:20.75,1:21:21.24,EN,,0,0,0,,and you want to say, Dialogue: 0,1:21:21.26,1:21:23.12,EN,,0,0,0,,what is the meaning of a final set of equations? Dialogue: 0,1:21:24.09,1:21:25.26,EN,,0,0,0,,This gives you a meaning for it. Dialogue: 0,1:21:25.79,1:21:27.45,EN,,0,0,0,,But in order to make an interactive system, Dialogue: 0,1:21:27.45,1:21:28.75,EN,,0,0,0,,where you can change the meaning of one Dialogue: 0,1:21:28.76,1:21:31.68,EN,,0,0,0,,without changing everything else, incrementally, Dialogue: 0,1:21:32.33,1:21:35.04,EN,,0,0,0,,you can't do that by implementing it this way. Dialogue: 0,1:21:40.99,1:21:41.24,EN,,0,0,0,,Yes. Dialogue: 0,1:21:42.30,1:21:44.25,EN,,0,0,0,,AUDIENCE: Another question on your danger slide. Dialogue: 0,1:21:44.65,1:21:47.13,EN,,0,0,0,,It seemed that the two examples that you gave Dialogue: 0,1:21:47.16,1:21:49.07,EN,,0,0,0,,had to do with convergence and non-convergence? Dialogue: 0,1:21:49.18,1:21:49.56,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,1:21:50.30,1:21:52.62,EN,,0,0,0,,AUDIENCE: And that may or may not have something to do with Dialogue: 0,1:21:52.76,1:21:54.68,EN,,0,0,0,,with function theory in a way which Dialogue: 0,1:21:54.72,1:21:56.60,EN,,0,0,0,,would lead you to think of it in terms of linear systems, Dialogue: 0,1:21:57.74,1:21:59.00,EN,,0,0,0,,or non-linear systems. Dialogue: 0,1:21:59.34,1:22:01.76,EN,,0,0,0,,How does this convergence relate to being able to Dialogue: 0,1:22:02.35,1:22:05.53,EN,,0,0,0,,see a priori what properties of that might be violated? Dialogue: 0,1:22:05.79,1:22:06.57,EN,,0,0,0,,PROFESSOR: I don't know. Dialogue: 0,1:22:07.68,1:22:10.09,EN,,0,0,0,,The answer is, I don't know under what circumstances. Dialogue: 0,1:22:10.61,1:22:12.04,EN,,0,0,0,,I don't know how to translate that Dialogue: 0,1:22:12.52,1:22:14.73,EN,,0,0,0,,into less than an hour of talk more. Dialogue: 0,1:22:16.91,1:22:18.48,EN,,0,0,0,,What are the conditions under which, Dialogue: 0,1:22:18.86,1:22:20.76,EN,,0,0,0,,for which we know that these things converge? Dialogue: 0,1:22:22.86,1:22:23.31,EN,,0,0,0,,And indeed, Dialogue: 0,1:22:23.32,1:22:26.35,EN,,0,0,0,,all that was telling you that arguments that are based on convergence Dialogue: 0,1:22:28.24,1:22:29.47,EN,,0,0,0,,are flaky Dialogue: 0,1:22:29.66,1:22:31.58,EN,,0,0,0,,if you don't know the convergence beforehand. Dialogue: 0,1:22:32.81,1:22:34.20,EN,,0,0,0,,You can make wrong arguments. Dialogue: 0,1:22:34.44,1:22:37.31,EN,,0,0,0,,You can make deductions, as if you know the answer, Dialogue: 0,1:22:37.39,1:22:39.93,EN,,0,0,0,,and not be stopped somewhere by some obvious contradiction. Dialogue: 0,1:22:40.97,1:22:42.28,EN,,0,0,0,,AUDIENCE: So can we say then that Dialogue: 0,1:22:42.33,1:22:44.88,EN,,0,0,0,,if F is a convergent mathematical expression, Dialogue: 0,1:22:45.00,1:22:47.36,EN,,0,0,0,,then the recursion property can be-- Dialogue: 0,1:22:47.58,1:22:51.29,EN,,0,0,0,,PROFESSOR: Well, I think there's a technical kind of F, Dialogue: 0,1:22:52.12,1:22:54.22,EN,,0,0,0,,OK? There is a technical description Dialogue: 0,1:22:54.24,1:22:55.90,EN,,0,0,0,,of those F's that have the property Dialogue: 0,1:22:55.98,1:23:01.31,EN,,0,0,0,,that when you iteratively apply them like this, Dialogue: 0,1:23:01.52,1:23:02.25,EN,,0,0,0,,you converge. Dialogue: 0,1:23:03.02,1:23:06.51,EN,,0,0,0,,Things that are monotonic, and continuous, Dialogue: 0,1:23:07.32,1:23:07.95,EN,,0,0,0,,OK? Dialogue: 0,1:23:08.38,1:23:09.37,EN,,0,0,0,,and I forgot what else. Dialogue: 0,1:23:09.37,1:23:11.13,EN,,0,0,0,,There is a whole bunch of little conditions like that Dialogue: 0,1:23:11.68,1:23:12.99,EN,,0,0,0,,which have this property. Dialogue: 0,1:23:13.43,1:23:16.00,EN,,0,0,0,,Now the real problem is deducing from looking at the F, Dialogue: 0,1:23:16.92,1:23:17.88,EN,,0,0,0,,its definition here, Dialogue: 0,1:23:18.17,1:23:19.66,EN,,0,0,0,,whether not it has those properties, Dialogue: 0,1:23:20.27,1:23:21.32,EN,,0,0,0,,and that's very hard. Dialogue: 0,1:23:22.01,1:23:24.00,EN,,0,0,0,,The properties are easy. You can write them down. Dialogue: 0,1:23:24.58,1:23:26.32,EN,,0,0,0,,You can look in a book by Joe Stoy. Dialogue: 0,1:23:26.67,1:23:29.58,EN,,0,0,0,,It's a great book-- Stoy. Dialogue: 0,1:23:32.22,1:23:34.06,EN,,0,0,0,,It's called, The Scott-Strachey Dialogue: 0,1:23:34.49,1:23:38.46,EN,,0,0,0,,The Scott-Strachey Method of Denotational Semantics, Dialogue: 0,1:23:39.55,1:23:40.76,EN,,0,0,0,,and it's by Joe Stoy, Dialogue: 0,1:23:40.80,1:23:41.76,EN,,0,0,0,,MIT Press. Dialogue: 0,1:23:48.06,1:23:49.88,EN,,0,0,0,,And he works out all this in great detail, Dialogue: 0,1:23:50.20,1:23:51.37,EN,,0,0,0,,enough to horrify you. Dialogue: 0,1:23:55.05,1:23:56.19,EN,,0,0,0,,But it really is readable. Dialogue: 0,1:24:09.15,1:24:10.08,EN,,0,0,0,,OK, well, thank you. Dialogue: 0,1:24:11.49,1:24:12.99,EN,,0,0,0,,Time for the bigger break, I suppose. Dialogue: 0,0:00:00.03,0:00:01.28,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:01.39,0:00:08.09,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:01.39,0:00:08.09,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N张大伟 Dialogue: 0,0:00:01.39,0:00:08.09,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:01.39,0:00:08.09,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:01.39,0:00:08.09,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:08.94,0:00:12.59,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 I Dialogue: 0,0:00:15.79,0:00:17.32,Default,,0,0,0,,教授:今天我们将学习一些 Dialogue: 0,0:00:17.52,0:00:18.41,Default,,0,0,0,,非同一般的东西 Dialogue: 0,0:00:19.20,0:00:21.88,Default,,0,0,0,,我们将对计算机程序 Dialogue: 0,0:00:22.59,0:00:25.21,Default,,0,0,0,,有更深层次的理解 Dialogue: 0,0:00:26.80,0:00:29.12,Default,,0,0,0,,目前为止 我们一直把程序看作 Dialogue: 0,0:00:29.26,0:00:32.09,Default,,0,0,0,,对机器的描述 Dialogue: 0,0:00:32.72,0:00:37.21,Default,,0,0,0,,举个例子 在这个幻灯片上 Dialogue: 0,0:00:37.93,0:00:41.77,Default,,0,0,0,,我们可以看到一个计算阶乘的程序 Dialogue: 0,0:00:42.80,0:00:47.31,Default,,0,0,0,,当然 你可以认为这些字符串描述了 Dialogue: 0,0:00:47.66,0:00:51.98,Default,,0,0,0,,这个线路图所表示的无穷机器 Dialogue: 0,0:00:52.49,0:00:54.80,Default,,0,0,0,,我们可以稍稍地看下 它描述的是什么 Dialogue: 0,0:00:55.13,0:00:58.20,Default,,0,0,0,,这种紧凑的记法 描述的是: Dialogue: 0,0:00:58.54,0:01:00.17,Default,,0,0,0,,如果N是0 结果就是1 Dialogue: 0,0:01:00.17,0:01:02.00,Default,,0,0,0,,N是从这里进入机器的 Dialogue: 0,0:01:02.33,0:01:03.52,Default,,0,0,0,,如果它是0的话 Dialogue: 0,0:01:03.74,0:01:05.20,Default,,0,0,0,,那么我就控制这个开关 Dialogue: 0,0:01:05.47,0:01:08.20,Default,,0,0,0,,把它掰到输出为1的那一端 Dialogue: 0,0:01:09.34,0:01:10.08,Default,,0,0,0,,否则的话 Dialogue: 0,0:01:10.38,0:01:12.83,Default,,0,0,0,,就是(* N (FACT (- N 1))) Dialogue: 0,0:01:12.97,0:01:15.13,Default,,0,0,0,,我先计算(FACT (- N 1)) Dialogue: 0,0:01:15.29,0:01:16.68,Default,,0,0,0,,再把结果乘以N Dialogue: 0,0:01:16.84,0:01:18.91,Default,,0,0,0,,这样如果N不为0的话 Dialogue: 0,0:01:18.91,0:01:20.60,Default,,0,0,0,,这个开关就会输出这里的结果 Dialogue: 0,0:01:21.90,0:01:22.32,Default,,0,0,0,,当然了 Dialogue: 0,0:01:22.36,0:01:25.13,Default,,0,0,0,,这个机器可能有无穷多个部件 Dialogue: 0,0:01:25.48,0:01:28.12,Default,,0,0,0,,因为FACT内部又调用了FACT Dialogue: 0,0:01:28.43,0:01:30.17,Default,,0,0,0,,因此我们不知道调用栈有多深 Dialogue: 0,0:01:31.07,0:01:33.55,Default,,0,0,0,,但到目前为止 Dialogue: 0,0:01:34.22,0:01:37.69,Default,,0,0,0,,代码对我们来说就是这样的东西了 Dialogue: 0,0:01:38.31,0:01:40.59,Default,,0,0,0,,你可以认为代码是用字符串来描述 Dialogue: 0,0:01:41.28,0:01:44.16,Default,,0,0,0,,某种用其它方式描画的线路图 Dialogue: 0,0:01:44.90,0:01:46.60,Default,,0,0,0,,事实上 很多人都向我提议 Dialogue: 0,0:01:46.84,0:01:49.04,Default,,0,0,0,,说程序设计语言应该像这个一样 是图像化的 Dialogue: 0,0:01:49.49,0:01:51.80,Default,,0,0,0,,不过我不认为用图形表示会有很多优势 Dialogue: 0,0:01:52.00,0:01:53.79,Default,,0,0,0,,当然 最主要的劣势就是 Dialogue: 0,0:01:53.80,0:01:55.63,Default,,0,0,0,,它需要占用很大的平面空间 Dialogue: 0,0:01:55.96,0:01:59.95,Default,,0,0,0,,所以展示和修改起来就非常麻烦 Dialogue: 0,0:02:01.34,0:02:02.16,Default,,0,0,0,,但是不管怎样 Dialogue: 0,0:02:03.58,0:02:05.15,Default,,0,0,0,,在计算的世界中 Dialogue: 0,0:02:05.18,0:02:07.05,Default,,0,0,0,,还有一个非常重要的东西 Dialogue: 0,0:02:07.64,0:02:10.64,Default,,0,0,0,,也就是所谓的“通用机器” Dialogue: 0,0:02:10.73,0:02:15.24,Default,,0,0,0,,我们再来看第二张幻灯片 Dialogue: 0,0:02:16.04,0:02:17.18,Default,,0,0,0,,我们看到的就是 Dialogue: 0,0:02:18.14,0:02:19.88,Default,,0,0,0,,名为EVAL的特殊机器 Dialogue: 0,0:02:21.26,0:02:22.86,Default,,0,0,0,,这个叫做EVAL的机器 Dialogue: 0,0:02:22.88,0:02:24.24,Default,,0,0,0,,也就是我今天要讲解的 Dialogue: 0,0:02:25.82,0:02:26.67,Default,,0,0,0,,它非常简单 Dialogue: 0,0:02:27.78,0:02:30.80,Default,,0,0,0,,最了不起的是 它简单得可以写在黑板上 Dialogue: 0,0:02:33.35,0:02:35.79,Default,,0,0,0,,然而 EVAL这个机器 Dialogue: 0,0:02:36.00,0:02:39.84,Default,,0,0,0,,是以其它机器的描述作为输入的 Dialogue: 0,0:02:40.45,0:02:42.12,Default,,0,0,0,,它可以接收一个 Dialogue: 0,0:02:42.40,0:02:45.58,Default,,0,0,0,,阶乘机器的线路图作为输入 Dialogue: 0,0:02:46.49,0:02:47.66,Default,,0,0,0,,这样一来 Dialogue: 0,0:02:48.49,0:02:52.57,Default,,0,0,0,,它就可以模拟那台阶乘机器 Dialogue: 0,0:02:53.13,0:02:53.79,Default,,0,0,0,,这样的话 Dialogue: 0,0:02:54.16,0:02:56.36,Default,,0,0,0,,如果输入6 就会得到720 Dialogue: 0,0:02:58.91,0:03:01.68,Default,,0,0,0,,这是一个非常了不起的机器 Dialogue: 0,0:03:02.13,0:03:03.58,Default,,0,0,0,,而最让人惊奇的是 Dialogue: 0,0:03:03.77,0:03:05.13,Default,,0,0,0,,它竟然可以写在一个黑板内 Dialogue: 0,0:03:05.59,0:03:06.65,Default,,0,0,0,,与之相反的是 Dialogue: 0,0:03:07.32,0:03:10.44,Default,,0,0,0,,我们可以想象一下模拟电子世界中的 Dialogue: 0,0:03:11.55,0:03:12.86,Default,,0,0,0,,一台非常不同的机器 Dialogue: 0,0:03:14.57,0:03:16.33,Default,,0,0,0,,这台机器呢 Dialogue: 0,0:03:16.52,0:03:18.81,Default,,0,0,0,,某种意义上 同样也是“通用机器” Dialogue: 0,0:03:19.26,0:03:23.12,Default,,0,0,0,,只要你输入一个电路图 Dialogue: 0,0:03:23.82,0:03:25.74,Default,,0,0,0,,比如这个小型的低通滤波器 Dialogue: 0,0:03:26.01,0:03:27.48,Default,,0,0,0,,单极低通滤波器之类的 Dialogue: 0,0:03:28.05,0:03:29.53,Default,,0,0,0,,你可以想像 Dialogue: 0,0:03:29.71,0:03:33.15,Default,,0,0,0,,如果我们扫描这个元件得到扫描线 Dialogue: 0,0:03:34.43,0:03:37.13,Default,,0,0,0,,得到的信号描述的就是 Dialogue: 0,0:03:37.39,0:03:40.40,Default,,0,0,0,,这个机器所模拟的 Dialogue: 0,0:03:40.78,0:03:43.39,Default,,0,0,0,,这个模拟机器EVAL是由电路构成 Dialogue: 0,0:03:43.68,0:03:45.15,Default,,0,0,0,,它可以把自己配置成一个滤波器 Dialogue: 0,0:03:45.18,0:03:48.04,Default,,0,0,0,,响应由电路图指定的频率 Dialogue: 0,0:03:49.89,0:03:51.48,Default,,0,0,0,,这种机器很难制造出来 Dialogue: 0,0:03:51.61,0:03:54.06,Default,,0,0,0,,当然 更不可能用一个黑板就把它说清楚 Dialogue: 0,0:03:55.67,0:03:57.58,Default,,0,0,0,,所以今天我们将学习一些神奇的东西 Dialogue: 0,0:03:58.43,0:04:00.81,Default,,0,0,0,,我们将在黑板上见证 Dialogue: 0,0:04:01.16,0:04:02.49,Default,,0,0,0,,通用机器 Dialogue: 0,0:04:02.79,0:04:04.41,Default,,0,0,0,,跟其它程序比起来 Dialogue: 0,0:04:04.52,0:04:05.80,Default,,0,0,0,,它真是非常简单 Dialogue: 0,0:04:06.78,0:04:08.75,Default,,0,0,0,,现在 我们已经非常接近 Dialogue: 0,0:04:09.08,0:04:10.97,Default,,0,0,0,,计算机中真正的精灵了 Dialogue: 0,0:04:11.28,0:04:14.62,Default,,0,0,0,,所以为了保持足够的尊重 Dialogue: 0,0:04:15.18,0:04:17.32,Default,,0,0,0,,我特地穿上外套 Dialogue: 0,0:04:17.52,0:04:19.29,Default,,0,0,0,,你们应该从没见我穿过 Dialogue: 0,0:04:20.47,0:04:22.73,Default,,0,0,0,,在这个盛重的场合 Dialogue: 0,0:04:23.55,0:04:26.70,Default,,0,0,0,,我还得戴上一顶合适的帽子 Dialogue: 0,0:04:28.78,0:04:31.44,Default,,0,0,0,,开讲前再给大家提个醒 Dialogue: 0,0:04:34.14,0:04:36.91,Default,,0,0,0,,那些40岁以下 Dialogue: 0,0:04:37.16,0:04:38.49,Default,,0,0,0,,以及没有孩子的人 Dialogue: 0,0:04:38.67,0:04:40.49,Default,,0,0,0,,你们可要小心了 Dialogue: 0,0:04:40.49,0:04:41.96,Default,,0,0,0,,如果真的受不了 可以选择离开 Dialogue: 0,0:04:43.34,0:04:45.56,Default,,0,0,0,,因为一会儿要发生一些 Dialogue: 0,0:04:45.72,0:04:47.13,Default,,0,0,0,,非常神秘的事情 Dialogue: 0,0:04:47.74,0:04:51.05,Default,,0,0,0,,可能使你的大脑异常混乱 Dialogue: 0,0:04:51.82,0:04:54.28,Default,,0,0,0,,好了 无论如何 Dialogue: 0,0:04:55.71,0:05:01.10,Default,,0,0,0,,我要带着你们写一个Lisp求值器 Dialogue: 0,0:05:02.51,0:05:04.28,Default,,0,0,0,,求值器并不复杂 Dialogue: 0,0:05:05.02,0:05:07.63,Default,,0,0,0,,很像我们以前见到过的程序 Dialogue: 0,0:05:08.24,0:05:09.48,Default,,0,0,0,,这也是它令人吃惊的地方 Dialogue: 0,0:05:10.86,0:05:13.10,Default,,0,0,0,,现在我开始写这个程序 Dialogue: 0,0:05:15.28,0:05:16.62,Default,,0,0,0,,我把这个程序叫做EVAL Dialogue: 0,0:05:22.90,0:05:26.24,Default,,0,0,0,,这个过程接收两个参数 Dialogue: 0,0:05:26.28,0:05:29.44,Default,,0,0,0,,表达式EXP和环境ENV Dialogue: 0,0:05:31.86,0:05:33.79,Default,,0,0,0,,跟所有实用过程一样 Dialogue: 0,0:05:34.01,0:05:35.13,Default,,0,0,0,,它是个“按情况分析”语句 Dialogue: 0,0:05:40.46,0:05:41.87,Default,,0,0,0,,但是在我开始之前 Dialogue: 0,0:05:42.52,0:05:43.90,Default,,0,0,0,,我还想你们注意一下 Dialogue: 0,0:05:44.44,0:05:46.06,Default,,0,0,0,,我将要在黑板上写的程序 Dialogue: 0,0:05:46.56,0:05:50.24,Default,,0,0,0,,非常丑陋、混乱、令人作呕 Dialogue: 0,0:05:50.94,0:05:53.16,Default,,0,0,0,,并不是一种专业的写法 Dialogue: 0,0:05:54.32,0:05:56.57,Default,,0,0,0,,它是用具体语法写就的 Dialogue: 0,0:05:57.24,0:05:58.83,Default,,0,0,0,,也就是说用了很多CAR、CDR Dialogue: 0,0:05:58.84,0:06:00.62,Default,,0,0,0,,我之前告诉过你们这样写并不好 Dialogue: 0,0:06:02.94,0:06:05.61,Default,,0,0,0,,在这里是故意这样来写的 Dialogue: 0,0:06:06.11,0:06:09.02,Default,,0,0,0,,因为我想让它尽量精简 Dialogue: 0,0:06:09.34,0:06:10.40,Default,,0,0,0,,能塞在黑板内 Dialogue: 0,0:06:10.43,0:06:11.85,Default,,0,0,0,,你们就可以看到整个代码 Dialogue: 0,0:06:12.42,0:06:14.80,Default,,0,0,0,,我就不像平时那样实用长变量名了 Dialogue: 0,0:06:15.60,0:06:17.29,Default,,0,0,0,,就用CAR、CDR 因为它们短小 Dialogue: 0,0:06:18.06,0:06:20.78,Default,,0,0,0,,这算是一种取舍 Dialogue: 0,0:06:20.89,0:06:22.81,Default,,0,0,0,,我不希望你们这样来写程序 Dialogue: 0,0:06:23.57,0:06:25.08,Default,,0,0,0,,这里单纯地想达到一种简洁的效果 Dialogue: 0,0:06:25.85,0:06:27.61,Default,,0,0,0,,因此你们读起来可能有些费力 Dialogue: 0,0:06:27.77,0:06:30.19,Default,,0,0,0,,我尽量写得清楚一些 Dialogue: 0,0:06:31.27,0:06:34.40,Default,,0,0,0,,这个解释器已经比较完整了 Dialogue: 0,0:06:34.51,0:06:36.24,Default,,0,0,0,,但是还是缺少一些功能 Dialogue: 0,0:06:36.25,0:06:38.60,Default,,0,0,0,,我就不写定义和赋值的部分了 Dialogue: 0,0:06:39.10,0:06:42.41,Default,,0,0,0,,因为它们都不是最本质的 Dialogue: 0,0:06:42.88,0:06:46.46,Default,,0,0,0,,稍后我就会解释 这是数学上的原因 Dialogue: 0,0:06:46.92,0:06:49.96,Default,,0,0,0,,当然啦 黑板也没有那么大 Dialogue: 0,0:06:51.88,0:06:53.64,Default,,0,0,0,,但是 我们怎么做呢? Dialogue: 0,0:06:53.95,0:06:55.66,Default,,0,0,0,,我们需要一个分派 Dialogue: 0,0:06:56.09,0:06:57.90,Default,,0,0,0,,它根据表达式的类型 Dialogue: 0,0:06:58.28,0:07:00.38,Default,,0,0,0,,把它们划分为几类 Dialogue: 0,0:07:01.72,0:07:03.26,Default,,0,0,0,,这就是现在要做的 Dialogue: 0,0:07:03.82,0:07:05.15,Default,,0,0,0,,我们都有哪些表达式? Dialogue: 0,0:07:05.15,0:07:06.36,Default,,0,0,0,,我们先来看几种表达式 Dialogue: 0,0:07:06.81,0:07:09.60,Default,,0,0,0,,比如说 数字“3”就是一个表达式 Dialogue: 0,0:07:10.42,0:07:11.58,Default,,0,0,0,,我想让它代表什么呢? Dialogue: 0,0:07:12.72,0:07:14.75,Default,,0,0,0,,我有很多选择 但是就现在而言 Dialogue: 0,0:07:15.05,0:07:16.20,Default,,0,0,0,,我就想让它表示数字3 Dialogue: 0,0:07:17.05,0:07:17.88,Default,,0,0,0,,这就是我要的 Dialogue: 0,0:07:18.72,0:07:19.69,Default,,0,0,0,,这个足够简单 Dialogue: 0,0:07:20.03,0:07:22.91,Default,,0,0,0,,那就意味着 如果表达式是数字 Dialogue: 0,0:07:27.29,0:07:31.68,Default,,0,0,0,,表达式本身就应该是求值结果 Dialogue: 0,0:07:35.42,0:07:36.76,Default,,0,0,0,,另外一种情况是 Dialogue: 0,0:07:36.89,0:07:38.86,Default,,0,0,0,,表达式还可能是符号 Dialogue: 0,0:07:39.39,0:07:46.75,Default,,0,0,0,,比如EXP、ENV、EVAL、NUMBER、X之类 Dialogue: 0,0:07:48.01,0:07:49.18,Default,,0,0,0,,它们意味着什么? Dialogue: 0,0:07:50.16,0:07:51.63,Default,,0,0,0,,它们是一类代表其它事物的事物 Dialogue: 0,0:07:51.63,0:07:53.23,Default,,0,0,0,,也就是我们语言中所谓的变量 Dialogue: 0,0:07:54.77,0:07:56.88,Default,,0,0,0,,因此我想要能够 比如说 Dialogue: 0,0:07:57.05,0:08:01.04,Default,,0,0,0,,对X求值 可能会得到3 Dialogue: 0,0:08:02.64,0:08:05.76,Default,,0,0,0,,又可能是CAR Dialogue: 0,0:08:07.76,0:08:09.40,Default,,0,0,0,,我希望它的值是 Dialogue: 0,0:08:09.63,0:08:11.34,Default,,0,0,0,,某种类似于过程的东西 Dialogue: 0,0:08:16.51,0:08:18.43,Default,,0,0,0,,我不需要知道它内部是什么 Dialogue: 0,0:08:18.64,0:08:21.15,Default,,0,0,0,,可能是一些机器码 或者类似的东西 Dialogue: 0,0:08:22.84,0:08:24.27,Default,,0,0,0,,到这是还是相对简单的 Dialogue: 0,0:08:24.43,0:08:26.89,Default,,0,0,0,,我想把这部分交给其他人来写 Dialogue: 0,0:08:27.80,0:08:28.89,Default,,0,0,0,,如果我们有一个符号 Dialogue: 0,0:08:30.80,0:08:32.48,Default,,0,0,0,,假如表达式是符号 Dialogue: 0,0:08:33.42,0:08:34.88,Default,,0,0,0,,那么我求值它的结果就应该是 Dialogue: 0,0:08:34.91,0:08:40.24,Default,,0,0,0,,在环境ENV中查找该表达式的值 Dialogue: 0,0:08:46.48,0:08:48.99,Default,,0,0,0,,环境是一个字典 Dialogue: 0,0:08:49.96,0:08:54.06,Default,,0,0,0,,它把符号映射成一个值 Dialogue: 0,0:08:54.28,0:08:55.16,Default,,0,0,0,,就这么简单 Dialogue: 0,0:08:56.28,0:08:57.20,Default,,0,0,0,,怎么完成的呢? Dialogue: 0,0:08:57.53,0:08:58.52,Default,,0,0,0,,稍后我们再谈这个 Dialogue: 0,0:08:59.68,0:09:00.57,Default,,0,0,0,,其实并不难 Dialogue: 0,0:09:01.67,0:09:04.28,Default,,0,0,0,,编写类似于表的数据结构非常容易 Dialogue: 0,0:09:04.84,0:09:05.74,Default,,0,0,0,,但它只是一个表 Dialogue: 0,0:09:05.77,0:09:07.56,Default,,0,0,0,,而这是存取某个表的过程 Dialogue: 0,0:09:09.55,0:09:10.81,Default,,0,0,0,,好的 接下来 Dialogue: 0,0:09:11.31,0:09:12.56,Default,,0,0,0,,另一类表达式 Dialogue: 0,0:09:12.67,0:09:15.56,Default,,0,0,0,,表达式可能是一些不是数字的常量 Dialogue: 0,0:09:16.06,0:09:17.43,Default,,0,0,0,,比如 'FOO Dialogue: 0,0:09:20.17,0:09:21.29,Default,,0,0,0,,为了方便起见 Dialogue: 0,0:09:21.31,0:09:23.36,Default,,0,0,0,,我想在语法上 Dialogue: 0,0:09:24.73,0:09:26.80,Default,,0,0,0,,把它转换成表结构 Dialogue: 0,0:09:26.84,0:09:31.52,Default,,0,0,0,,比如说是(QUOTE FOO) Dialogue: 0,0:09:33.72,0:09:37.18,Default,,0,0,0,,一个被引用起来的对象 无论它是什么 Dialogue: 0,0:09:38.35,0:09:40.83,Default,,0,0,0,,都实际上是一个缩写 Dialogue: 0,0:09:41.04,0:09:42.59,Default,,0,0,0,,这一部分并不由求值器负责 Dialogue: 0,0:09:43.21,0:09:44.46,Default,,0,0,0,,这是在其它地方完成的 Dialogue: 0,0:09:44.75,0:09:47.79,Default,,0,0,0,,左边的符号就是右边表达式的缩略形式 Dialogue: 0,0:09:48.78,0:09:50.48,Default,,0,0,0,,这样 我就可以 Dialogue: 0,0:09:50.57,0:09:53.12,Default,,0,0,0,,依据表达式的CAR部分 Dialogue: 0,0:09:53.31,0:09:55.95,Default,,0,0,0,,来判断它的类型了 Dialogue: 0,0:09:58.46,0:10:01.08,Default,,0,0,0,,因此这一部分也不会出现在求值器中 Dialogue: 0,0:10:01.65,0:10:02.68,Default,,0,0,0,,这在更早时候 Dialogue: 0,0:10:02.70,0:10:03.96,Default,,0,0,0,,比如源代码读取阶段完成 Dialogue: 0,0:10:05.54,0:10:15.04,Default,,0,0,0,,如果是引用表达式 Dialogue: 0,0:10:18.27,0:10:19.10,Default,,0,0,0,,那么求值的结果就是 Dialogue: 0,0:10:19.63,0:10:25.13,Default,,0,0,0,,我想让(QUOTE FOO)求值为自身FOO Dialogue: 0,0:10:25.14,0:10:25.95,Default,,0,0,0,,一个常量 Dialogue: 0,0:10:27.53,0:10:28.92,Default,,0,0,0,,这条代码是说 Dialogue: 0,0:10:29.08,0:10:30.73,Default,,0,0,0,,这类表达式求值为它自己 Dialogue: 0,0:10:31.79,0:10:33.66,Default,,0,0,0,,怎么才能把它取出来呢? Dialogue: 0,0:10:33.66,0:10:36.36,Default,,0,0,0,,这是列表第二个元素的第一个部分 Dialogue: 0,0:10:36.59,0:10:37.58,Default,,0,0,0,,也就是表的第二个元素 Dialogue: 0,0:10:38.49,0:10:40.32,Default,,0,0,0,,也就是CADR Dialogue: 0,0:10:41.28,0:10:42.38,Default,,0,0,0,,所以这里我就写CADR Dialogue: 0,0:10:51.08,0:10:52.35,Default,,0,0,0,,表达式还可能是什么类型呢? Dialogue: 0,0:10:52.51,0:10:53.80,Default,,0,0,0,,还有LAMBDA表达式 Dialogue: 0,0:10:55.00,0:11:03.29,Default,,0,0,0,,比如 (LAMBDA (X) (+ X Y)) Dialogue: 0,0:11:04.16,0:11:06.33,Default,,0,0,0,,我还得找到某种表示方法 Dialogue: 0,0:11:06.33,0:11:07.85,Default,,0,0,0,,LAMBDA表达式求值的结果 Dialogue: 0,0:11:08.11,0:11:09.08,Default,,0,0,0,,也就是如何表示过程 Dialogue: 0,0:11:09.60,0:11:12.62,Default,,0,0,0,,过程并不就是表达式(LAMBDA (x)) Dialogue: 0,0:11:13.13,0:11:15.56,Default,,0,0,0,,表达式只是过程的代码描述 Dialogue: 0,0:11:16.41,0:11:18.33,Default,,0,0,0,,如果在词法作用域的语言中实现过程 Dialogue: 0,0:11:18.56,0:11:21.20,Default,,0,0,0,,那么我希望在表示过程的时候 Dialogue: 0,0:11:23.23,0:11:25.36,Default,,0,0,0,,能够把当前的求值环境包括进来 Dialogue: 0,0:11:25.84,0:11:29.07,Default,,0,0,0,,所以这里我还需要 Dialogue: 0,0:11:29.20,0:11:30.67,Default,,0,0,0,,一些类型标志 Dialogue: 0,0:11:30.70,0:11:33.90,Default,,0,0,0,,这样后面我就可以用它们来区分过程 Dialogue: 0,0:11:34.30,0:11:36.59,Default,,0,0,0,,看哪些是由LAMBDA表达式生成的 Dialogue: 0,0:11:36.81,0:11:38.03,Default,,0,0,0,,哪些是基本过程 Dialogue: 0,0:11:39.06,0:11:41.96,Default,,0,0,0,,所以这里是个类型标志 Dialogue: 0,0:11:41.98,0:11:43.56,Default,,0,0,0,,出于历史原因 Dialogue: 0,0:11:43.56,0:11:45.10,Default,,0,0,0,,我用CLOSURE作为类型标志 Dialogue: 0,0:11:47.68,0:11:49.60,Default,,0,0,0,,现在来看看 哪部分比较重要 Dialogue: 0,0:11:49.92,0:11:51.12,Default,,0,0,0,,我需要知道 Dialogue: 0,0:11:51.24,0:11:52.92,Default,,0,0,0,,绑定变量表和过程的体 Dialogue: 0,0:11:54.22,0:11:55.40,Default,,0,0,0,,这是它的CDR部分 Dialogue: 0,0:11:56.09,0:12:01.85,Default,,0,0,0,,这里就是((X) (+ X Y)) Dialogue: 0,0:12:03.04,0:12:03.87,Default,,0,0,0,,以及某个环境 Dialogue: 0,0:12:08.17,0:12:12.20,Default,,0,0,0,,用户不应该看到这个东西 Dialogue: 0,0:12:13.53,0:12:16.19,Default,,0,0,0,,这只是过程对象的 Dialogue: 0,0:12:16.76,0:12:18.30,Default,,0,0,0,,一种内部表示 Dialogue: 0,0:12:18.52,0:12:20.52,Default,,0,0,0,,它包括绑定变量表 Dialogue: 0,0:12:20.70,0:12:22.62,Default,,0,0,0,,过程的体和某个环境 Dialogue: 0,0:12:23.53,0:12:25.80,Default,,0,0,0,,以及一个类型标签 表示这是一个过程 Dialogue: 0,0:12:26.34,0:12:27.37,Default,,0,0,0,,接下来写代码 Dialogue: 0,0:12:28.08,0:12:38.72,Default,,0,0,0,,如果表达式的CAR部分是'LAMBDA Dialogue: 0,0:12:43.47,0:12:44.81,Default,,0,0,0,,这里 我就要 Dialogue: 0,0:12:45.64,0:12:51.84,Default,,0,0,0,,创建一个表 表头是'CLOSURE Dialogue: 0,0:12:55.15,0:13:00.73,Default,,0,0,0,,接着是 过程代码的CDR部分 Dialogue: 0,0:13:01.56,0:13:02.97,Default,,0,0,0,,也就是除开LAMBDA的其它部分 Dialogue: 0,0:13:07.74,0:13:08.86,Default,,0,0,0,,以及当前的环境 Dialogue: 0,0:13:10.25,0:13:15.32,Default,,0,0,0,,这样就实现了环境模型中的那些规则 Dialogue: 0,0:13:15.45,0:13:18.52,Default,,0,0,0,,这是从LAMBDA表达式中构建过程所必须遵守的 Dialogue: 0,0:13:19.40,0:13:20.97,Default,,0,0,0,,那个求值器在遇到 Dialogue: 0,0:13:21.48,0:13:24.32,Default,,0,0,0,,LAMBDA表达式时的环境 Dialogue: 0,0:13:25.04,0:13:28.46,Default,,0,0,0,,在过程运行的时候 Dialogue: 0,0:13:28.68,0:13:31.77,Default,,0,0,0,,会去这个环境中查找自由变量的值 Dialogue: 0,0:13:34.72,0:13:35.82,Default,,0,0,0,,所以需要把它囊括进来 Dialogue: 0,0:13:35.92,0:13:37.55,Default,,0,0,0,,因此我们必须把求值时的环境 Dialogue: 0,0:13:37.56,0:13:38.86,Default,,0,0,0,,作为过程对象的一部分 Dialogue: 0,0:13:39.21,0:13:40.62,Default,,0,0,0,,之后再来看它的作用 Dialogue: 0,0:13:42.03,0:13:43.77,Default,,0,0,0,,我们也有COND表达式 Dialogue: 0,0:13:44.59,0:13:52.81,Default,,0,0,0,,像是(COND (P1 E1) (P2 E2) ...)这样的 Dialogue: 0,0:13:54.40,0:13:56.09,Default,,0,0,0,,P1是谓词 Dialogue: 0,0:13:56.35,0:13:58.43,Default,,0,0,0,,谓词总是返回TRUE或者FALSE Dialogue: 0,0:13:58.99,0:14:01.76,Default,,0,0,0,,如果谓词P1为真时 表达式E1才被求值 Dialogue: 0,0:14:03.44,0:14:06.08,Default,,0,0,0,,当然 你也可以列这么一组子句 Dialogue: 0,0:14:06.79,0:14:09.36,Default,,0,0,0,,我会把它封装在另一个过程中 Dialogue: 0,0:14:09.36,0:14:11.56,Default,,0,0,0,,我们稍后在那个过程中进行处理 Dialogue: 0,0:14:12.42,0:14:21.28,Default,,0,0,0,,如果表达式的CAR部分是'COND的话 Dialogue: 0,0:14:24.00,0:14:26.84,Default,,0,0,0,,那么我就用EVCOND来求值这个表达式 Dialogue: 0,0:14:30.20,0:14:31.42,Default,,0,0,0,,求值表达式的CDR部分 Dialogue: 0,0:14:34.40,0:14:38.49,Default,,0,0,0,,记得带上环境 Dialogue: 0,0:14:41.43,0:14:42.60,Default,,0,0,0,,好的 还有一种情况 Dialogue: 0,0:14:44.09,0:14:48.22,Default,,0,0,0,,任意的像(+ X 3)这样的表达式 Dialogue: 0,0:14:50.62,0:14:53.95,Default,,0,0,0,,这是把运算符应用在运算对象上 Dialogue: 0,0:14:55.13,0:14:56.59,Default,,0,0,0,,这并没有什么特殊的 Dialogue: 0,0:14:56.59,0:14:59.63,Default,,0,0,0,,就是说 它不属于这里的特殊形式 Dialogue: 0,0:14:59.85,0:15:01.42,Default,,0,0,0,,上面写的这些都是特殊形式 Dialogue: 0,0:15:09.65,0:15:12.12,Default,,0,0,0,,再说明一下 如果我要把这个程序写得专业一点 Dialogue: 0,0:15:12.36,0:15:14.17,Default,,0,0,0,,我会把它设计成数据导向的 Dialogue: 0,0:15:14.48,0:15:16.52,Default,,0,0,0,,那样的话 这里就不会是一系列的条件判断 Dialogue: 0,0:15:16.65,0:15:18.20,Default,,0,0,0,,而是根据一些比特位来做分派 Dialogue: 0,0:15:19.42,0:15:22.25,Default,,0,0,0,,这样来设计会更加专业一些 Dialogue: 0,0:15:22.36,0:15:24.14,Default,,0,0,0,,并且 我不用大量修改程序 Dialogue: 0,0:15:24.68,0:15:26.38,Default,,0,0,0,,就可以添加规则 Dialogue: 0,0:15:26.71,0:15:28.46,Default,,0,0,0,,这样来做可能运行得更快 Dialogue: 0,0:15:29.04,0:15:30.43,Default,,0,0,0,,但这里我并不打算这么做 Dialogue: 0,0:15:31.28,0:15:33.98,Default,,0,0,0,,现在的目的是把握EVAL过程的整体 Dialogue: 0,0:15:35.07,0:15:35.80,Default,,0,0,0,,那么 最后一种情况 Dialogue: 0,0:15:37.69,0:15:38.56,Default,,0,0,0,,要怎么做呢? Dialogue: 0,0:15:38.56,0:15:41.23,Default,,0,0,0,,在这种情况下 我需要进行加法运算 Dialogue: 0,0:15:44.35,0:15:46.16,Default,,0,0,0,,那么我就得搞清楚 '+到底是什么 Dialogue: 0,0:15:46.84,0:15:49.29,Default,,0,0,0,,我还得知道X和3又代表什么 Dialogue: 0,0:15:50.55,0:15:53.96,Default,,0,0,0,,然后再把'+的所代表的东西 Dialogue: 0,0:15:54.43,0:15:57.00,Default,,0,0,0,,应用于'X与3所代表的东西上 Dialogue: 0,0:15:58.11,0:15:59.39,Default,,0,0,0,,具体来写一下 Dialogue: 0,0:15:59.87,0:16:09.55,Default,,0,0,0,,我要把表达式CAR部分的求值结果 Dialogue: 0,0:16:11.20,0:16:12.14,Default,,0,0,0,,应用在 Dialogue: 0,0:16:13.21,0:16:15.50,Default,,0,0,0,,表达式的CAR部分就是运算符 Dialogue: 0,0:16:17.20,0:16:18.51,Default,,0,0,0,,要在给定的环境中进行 Dialogue: 0,0:16:20.51,0:16:22.89,Default,,0,0,0,,对运算符求值会得到一个过程 Dialogue: 0,0:16:24.05,0:16:26.78,Default,,0,0,0,,现在 我要求值所有运算对象来取得参数 Dialogue: 0,0:16:27.29,0:16:28.22,Default,,0,0,0,,我将调用EVLIST Dialogue: 0,0:16:31.26,0:16:35.53,Default,,0,0,0,,来求值表达式的CDR部分 也就是运算对象 Dialogue: 0,0:16:36.76,0:16:39.00,Default,,0,0,0,,当然是在相应的环境中 Dialogue: 0,0:16:41.94,0:16:43.13,Default,,0,0,0,,我们待会儿再定义EVLIST Dialogue: 0,0:16:43.26,0:16:48.07,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:16:50.90,0:16:52.33,Default,,0,0,0,,你现在看到的 Dialogue: 0,0:16:52.67,0:16:56.11,Default,,0,0,0,,基本上就是一个完整的求值器 Dialogue: 0,0:16:56.49,0:17:01.00,Default,,0,0,0,,它根据表达式的类型分情况处理 Dialogue: 0,0:17:01.24,0:17:02.11,Default,,0,0,0,,默认的情况是 Dialogue: 0,0:17:04.99,0:17:07.95,Default,,0,0,0,,表达式应用或者说是组合式 Dialogue: 0,0:17:17.52,0:17:19.52,Default,,0,0,0,,不过还有好些过程 我们没有定义 Dialogue: 0,0:17:20.08,0:17:21.60,Default,,0,0,0,,接下来就看这些未定义的部分 Dialogue: 0,0:17:21.78,0:17:24.12,Default,,0,0,0,,我们还要定义EVCOND Dialogue: 0,0:17:25.48,0:17:26.67,Default,,0,0,0,,我得定义APPLY Dialogue: 0,0:17:27.57,0:17:28.62,Default,,0,0,0,,还有EVLIST Dialogue: 0,0:17:28.94,0:17:30.20,Default,,0,0,0,,以及LOOKUP Dialogue: 0,0:17:31.79,0:17:33.43,Default,,0,0,0,,我看看 没别的了吧? Dialogue: 0,0:17:33.43,0:17:35.16,Default,,0,0,0,,剩下的东西都很简单 Dialogue: 0,0:17:35.16,0:17:37.18,Default,,0,0,0,,比如基本元素之类的东西 Dialogue: 0,0:17:38.57,0:17:39.48,Default,,0,0,0,,当然 Dialogue: 0,0:17:39.69,0:17:42.06,Default,,0,0,0,,在这里 可以扩充很多特殊形式 Dialogue: 0,0:17:42.25,0:17:44.45,Default,,0,0,0,,但如果在通用语言中这么做就很糟糕 Dialogue: 0,0:17:44.45,0:17:45.92,Default,,0,0,0,,在这里添加大量的东西 Dialogue: 0,0:17:46.00,0:17:47.48,Default,,0,0,0,,会让语言变得复杂 Dialogue: 0,0:17:47.69,0:17:50.35,Default,,0,0,0,,语言中的保留字 Dialogue: 0,0:17:50.76,0:17:53.61,Default,,0,0,0,,不该比你能用几个手指、脚指记住的数目多 Dialogue: 0,0:17:54.16,0:17:55.53,Default,,0,0,0,,有些语言的保留字有成百上千个 Dialogue: 0,0:17:55.56,0:17:58.20,Default,,0,0,0,,我都不知道该说什么了 Dialogue: 0,0:17:59.41,0:18:00.71,Default,,0,0,0,,保留字就是在这里定义的 Dialogue: 0,0:18:03.15,0:18:06.54,Default,,0,0,0,,好 接下来 我们来看下一个部分 Dialogue: 0,0:18:06.56,0:18:07.69,Default,,0,0,0,,求值器的核心 APPLY Dialogue: 0,0:18:09.64,0:18:10.75,Default,,0,0,0,,它还做些什么呢? Dialogue: 0,0:18:11.59,0:18:17.53,Default,,0,0,0,,APPLY把还是符号状态的求值运算符和运算对象 Dialogue: 0,0:18:17.66,0:18:20.68,Default,,0,0,0,,求值为相应的过程以及参数值 Dialogue: 0,0:18:20.91,0:18:23.85,Default,,0,0,0,,然后把得到的过程应用在参数上 Dialogue: 0,0:18:24.09,0:18:26.96,Default,,0,0,0,,无论它们是什么符号表达式 Dialogue: 0,0:18:33.27,0:18:35.08,Default,,0,0,0,,我们把APPLY定义为 Dialogue: 0,0:18:38.35,0:18:40.65,Default,,0,0,0,,接收两个参数的过程 Dialogue: 0,0:18:40.75,0:18:43.44,Default,,0,0,0,,一个过程和对应的参数 Dialogue: 0,0:18:47.24,0:18:48.12,Default,,0,0,0,,它要怎么做呢? Dialogue: 0,0:18:48.14,0:18:49.55,Default,,0,0,0,,其实并不复杂 Dialogue: 0,0:18:49.93,0:18:50.78,Default,,0,0,0,,分两种情况就够了 Dialogue: 0,0:18:53.58,0:18:55.16,Default,,0,0,0,,如果这个过程是基本过程-- Dialogue: 0,0:19:03.42,0:19:06.41,Default,,0,0,0,,我不知道这个谓词具体是如何判断的 Dialogue: 0,0:19:06.86,0:19:10.24,Default,,0,0,0,,可能这里面有某种类型信息 Dialogue: 0,0:19:10.38,0:19:12.41,Default,,0,0,0,,就像我们在这里用'CLOSURE Dialogue: 0,0:19:12.68,0:19:15.05,Default,,0,0,0,,来描述一些复合对象一样 Dialogue: 0,0:19:16.33,0:19:17.79,Default,,0,0,0,,我想可能是这样 Dialogue: 0,0:19:18.55,0:19:20.20,Default,,0,0,0,,但是具体怎么判断并不重要 Dialogue: 0,0:19:20.68,0:19:22.01,Default,,0,0,0,,事实上 Dialogue: 0,0:19:22.19,0:19:23.85,Default,,0,0,0,,你可能已经知道或者推断过 Dialogue: 0,0:19:23.87,0:19:25.47,Default,,0,0,0,,我们并不需要任何基本过程 Dialogue: 0,0:19:27.35,0:19:29.28,Default,,0,0,0,,就算没有它们 照样可以进行计算 Dialogue: 0,0:19:30.46,0:19:33.19,Default,,0,0,0,,因为我们可以用一直在用的LAMBDA Dialogue: 0,0:19:33.61,0:19:34.76,Default,,0,0,0,,但是有它们总归方便点儿 Dialogue: 0,0:19:34.81,0:19:36.27,Default,,0,0,0,,我在这儿略施魔法 Dialogue: 0,0:19:36.30,0:19:37.47,Default,,0,0,0,,但不会去解释 Dialogue: 0,0:19:38.06,0:19:41.44,Default,,0,0,0,,转到机器语言 执行APPLY-PRIMOP Dialogue: 0,0:19:42.91,0:19:43.80,Default,,0,0,0,,加法是在这里运算的 Dialogue: 0,0:19:44.78,0:19:46.10,Default,,0,0,0,,执行加法指令 Dialogue: 0,0:19:50.62,0:19:52.11,Default,,0,0,0,,然而一门语言有趣的部分 Dialogue: 0,0:19:52.14,0:19:54.27,Default,,0,0,0,,在于组合基本元素的粘合剂 Dialogue: 0,0:19:54.91,0:19:55.90,Default,,0,0,0,,我们接着往下看 Dialogue: 0,0:19:56.91,0:19:58.38,Default,,0,0,0,,另一种可能就是 Dialogue: 0,0:19:58.75,0:20:04.12,Default,,0,0,0,,这个复合对象是求值LAMBDA表达式得到的 Dialogue: 0,0:20:04.97,0:20:07.05,Default,,0,0,0,,这是个复合过程 Dialogue: 0,0:20:07.62,0:20:09.36,Default,,0,0,0,,检测它的类型标志 Dialogue: 0,0:20:10.11,0:20:17.07,Default,,0,0,0,,如果是'CLOSURE Dialogue: 0,0:20:20.51,0:20:24.09,Default,,0,0,0,,如果是的话 我就得求值这个过程的体 Dialogue: 0,0:20:24.19,0:20:27.39,Default,,0,0,0,,过程的体的求值方式则是 Dialogue: 0,0:20:28.08,0:20:31.69,Default,,0,0,0,,我求值过程的应用是通过 Dialogue: 0,0:20:31.72,0:20:33.71,Default,,0,0,0,,先扩充程序的求值环境 Dialogue: 0,0:20:34.19,0:20:37.80,Default,,0,0,0,,在这个环境中 把过程的形式参数 Dialogue: 0,0:20:37.92,0:20:40.48,Default,,0,0,0,,跟传递过来的实际参数绑定在一起 Dialogue: 0,0:20:41.02,0:20:43.68,Default,,0,0,0,,在这个环境中求值过程的体 Dialogue: 0,0:20:46.70,0:20:47.87,Default,,0,0,0,,这句话很长 Dialogue: 0,0:20:51.13,0:20:52.16,Default,,0,0,0,,但其实简单 Dialogue: 0,0:20:52.82,0:20:54.48,Default,,0,0,0,,一会儿可能会出现许多CAR CDR... Dialogue: 0,0:20:56.46,0:20:58.11,Default,,0,0,0,,现在我先要得到过程体 Dialogue: 0,0:20:59.40,0:21:02.30,Default,,0,0,0,,如何取出过程体呢? Dialogue: 0,0:21:02.96,0:21:04.08,Default,,0,0,0,,这里是CAR部分 Dialogue: 0,0:21:04.49,0:21:06.13,Default,,0,0,0,,这一块是剩下部分的CDR部分 Dialogue: 0,0:21:06.13,0:21:06.96,Default,,0,0,0,,因此这就是CADR Dialogue: 0,0:21:07.40,0:21:09.45,Default,,0,0,0,,所以这里我得到的过程体 Dialogue: 0,0:21:09.45,0:21:13.04,Default,,0,0,0,,是过程对象第二个元素的第二个元素 Dialogue: 0,0:21:13.20,0:21:15.15,Default,,0,0,0,,因此CADR的CADR 也就是CADADR Dialogue: 0,0:21:19.17,0:21:27.68,Default,,0,0,0,,这里取过程对象的CADADR部分 Dialogue: 0,0:21:30.26,0:21:31.56,Default,,0,0,0,,为了求值过程体 Dialogue: 0,0:21:31.98,0:21:36.48,Default,,0,0,0,,要在参数绑定后的新环境之中进行 Dialogue: 0,0:21:38.09,0:21:42.06,Default,,0,0,0,,我还得获取过程的形式参数 Dialogue: 0,0:21:42.06,0:21:42.72,Default,,0,0,0,,要怎么取呢? Dialogue: 0,0:21:43.50,0:21:45.13,Default,,0,0,0,,就是CADR部分的CAR部分 Dialogue: 0,0:21:46.52,0:21:48.78,Default,,0,0,0,,这很糟糕不是吗? Dialogue: 0,0:21:52.65,0:21:53.63,Default,,0,0,0,,过程的CADR部分 Dialogue: 0,0:21:55.44,0:22:00.86,Default,,0,0,0,,在随着过程一起传递过来的环境中 Dialogue: 0,0:22:00.89,0:22:04.14,Default,,0,0,0,,把形参和由环境传递过来的实参绑定起来 Dialogue: 0,0:22:04.54,0:22:07.90,Default,,0,0,0,,也就是CDR的CDR的CAR Dialogue: 0,0:22:09.79,0:22:16.62,Default,,0,0,0,,也就是过程的CADDR部分 Dialogue: 0,0:22:20.29,0:22:24.96,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:22:26.14,0:22:29.68,Default,,0,0,0,,当然 如果我非常追求整洁 Dialogue: 0,0:22:29.87,0:22:31.34,Default,,0,0,0,,并且又非常谨慎 Dialogue: 0,0:22:32.24,0:22:34.12,Default,,0,0,0,,我会在后面多加一个情况 Dialogue: 0,0:22:34.38,0:22:35.98,Default,,0,0,0,,来判断是否出错 Dialogue: 0,0:22:36.17,0:22:38.41,Default,,0,0,0,,比如应用在参数上的是一个过程吗? Dialogue: 0,0:22:39.00,0:22:41.69,Default,,0,0,0,,如果不是 这里就是未定义的过程类型 Dialogue: 0,0:22:42.57,0:22:44.09,Default,,0,0,0,,我在这里也会这么做 Dialogue: 0,0:22:45.80,0:22:55.96,Default,,0,0,0,,像这样 在ELSE子句中返回错误 Dialogue: 0,0:22:57.61,0:23:01.61,Default,,0,0,0,,当然 在现实中的一些系统中 Dialogue: 0,0:23:02.56,0:23:04.22,Default,,0,0,0,,出于专业设计的考虑 Dialogue: 0,0:23:05.32,0:23:08.00,Default,,0,0,0,,这里可能会根据某种分派 Dialogue: 0,0:23:08.36,0:23:09.90,Default,,0,0,0,,来进行“分情况处理” Dialogue: 0,0:23:10.75,0:23:12.68,Default,,0,0,0,,回到这里 我可能还会添加新的条件来检查 Dialogue: 0,0:23:12.70,0:23:14.14,Default,,0,0,0,,比如 这是编译过的代码吗? Dialogue: 0,0:23:16.22,0:23:16.84,Default,,0,0,0,,这很重要 Dialogue: 0,0:23:16.88,0:23:18.35,Default,,0,0,0,,这样的话我就可以区分 Dialogue: 0,0:23:18.38,0:23:22.33,Default,,0,0,0,,过程是直接由解释LAMBDA表达式而来 Dialogue: 0,0:23:22.94,0:23:25.87,Default,,0,0,0,,还是从另外的编译器中得到的 等等 Dialogue: 0,0:23:26.11,0:23:27.23,Default,,0,0,0,,之后再讨论这个话题 Dialogue: 0,0:23:27.23,0:23:29.61,Default,,0,0,0,,又或许是 我必须要执行的一段Frotran代码 Dialogue: 0,0:23:30.51,0:23:32.51,Default,,0,0,0,,这完全是可能的 Dialogue: 0,0:23:32.92,0:23:36.41,Default,,0,0,0,,实际上 我用具体语法写的这个求值器 Dialogue: 0,0:23:37.45,0:23:40.86,Default,,0,0,0,,假定了它是用Lisp来编写的 Dialogue: 0,0:23:42.30,0:23:43.82,Default,,0,0,0,,这是因为我用了CAR和CDR Dialogue: 0,0:23:43.84,0:23:45.10,Default,,0,0,0,,用CAR来取运算符 Dialogue: 0,0:23:45.28,0:23:46.64,Default,,0,0,0,,用CDR来取运算对象 Dialogue: 0,0:23:46.75,0:23:49.96,Default,,0,0,0,,教科书上给出了一个用抽象语法编写的求值器 Dialogue: 0,0:23:50.35,0:23:53.15,Default,,0,0,0,,它使用的都是抽象的名字 Dialogue: 0,0:23:53.16,0:23:54.09,Default,,0,0,0,,比如OPERATOR、OPERAND Dialogue: 0,0:23:54.14,0:23:55.82,Default,,0,0,0,,以及类似的名字 Dialogue: 0,0:23:56.16,0:23:56.86,Default,,0,0,0,,那样的话 Dialogue: 0,0:23:57.02,0:24:00.91,Default,,0,0,0,,你可以毫无问题地用ALGOL来重新实现 Dialogue: 0,0:24:03.36,0:24:06.40,Default,,0,0,0,,写完APPLY之后 Dialogue: 0,0:24:07.20,0:24:08.43,Default,,0,0,0,,又有一些东西没有定义 Dialogue: 0,0:24:10.81,0:24:12.57,Default,,0,0,0,,我先不操心这两个 Dialogue: 0,0:24:13.39,0:24:15.05,Default,,0,0,0,,我们稍后讨论这个很重要的BIND Dialogue: 0,0:24:17.18,0:24:19.76,Default,,0,0,0,,现在我们来快速过一遍 结束这一部分 Dialogue: 0,0:24:20.55,0:24:22.65,Default,,0,0,0,,只剩下两块黑板了 不能够写太长 Dialogue: 0,0:24:27.40,0:24:29.08,Default,,0,0,0,,我还得悉心裁剪才能刚好写下 Dialogue: 0,0:24:30.07,0:24:30.98,Default,,0,0,0,,嗯 还剩下点什么? Dialogue: 0,0:24:30.98,0:24:33.20,Default,,0,0,0,,我们得定义这里的EVLIST Dialogue: 0,0:24:33.73,0:24:35.07,Default,,0,0,0,,EVLIST只不过是 Dialogue: 0,0:24:35.26,0:24:43.08,Default,,0,0,0,,在运算对象上映射某个函数得到参数 Dialogue: 0,0:24:44.30,0:24:45.40,Default,,0,0,0,,但是我还是要写出来看看 Dialogue: 0,0:24:45.82,0:24:48.30,Default,,0,0,0,,我把它写出来的原因有点神秘 Dialogue: 0,0:24:49.88,0:24:52.04,Default,,0,0,0,,我想让这个求值器简单得 Dialogue: 0,0:24:52.06,0:24:53.56,Default,,0,0,0,,可以求值自身 Dialogue: 0,0:24:56.45,0:24:58.09,Default,,0,0,0,,我真的很在意这一点 Dialogue: 0,0:25:00.23,0:25:01.74,Default,,0,0,0,,现在我就把它完全写在这里 Dialogue: 0,0:25:02.85,0:25:04.24,Default,,0,0,0,,我并不关心 Dialogue: 0,0:25:04.27,0:25:06.08,Default,,0,0,0,,它能否把过程作为参数传递 Dialogue: 0,0:25:06.27,0:25:08.06,Default,,0,0,0,,求值器并不会用到这些参数 Dialogue: 0,0:25:08.98,0:25:10.78,Default,,0,0,0,,求值器也不会生成一个是过程的值 Dialogue: 0,0:25:10.88,0:25:12.67,Default,,0,0,0,,因此 如果另外有个不同的语言 Dialogue: 0,0:25:12.80,0:25:13.96,Default,,0,0,0,,跟这个又非常相似 Dialogue: 0,0:25:15.16,0:25:17.79,Default,,0,0,0,,这个求值器能够求值像Scheme这样的复杂语言 Dialogue: 0,0:25:17.80,0:25:23.12,Default,,0,0,0,,Scheme是能够把过程当做参数传递的 Dialogue: 0,0:25:24.07,0:25:25.95,Default,,0,0,0,,但当我在求值ALGOL时 Dialogue: 0,0:25:27.34,0:25:28.96,Default,,0,0,0,,尽管ALGOL并不支持过程值 Dialogue: 0,0:25:29.47,0:25:30.59,Default,,0,0,0,,这个求值器也能正常工作 Dialogue: 0,0:25:31.58,0:25:33.92,Default,,0,0,0,,因为这个解释器 并没有对这个做过什么假定 Dialogue: 0,0:25:34.27,0:25:36.03,Default,,0,0,0,,实际上 就算这个求值器 Dialogue: 0,0:25:36.27,0:25:37.50,Default,,0,0,0,,被限制不允许那么做 也没有什么关系 Dialogue: 0,0:25:37.52,0:25:40.03,Default,,0,0,0,,因为它没有使用那些高级功能 Dialogue: 0,0:25:40.64,0:25:42.41,Default,,0,0,0,,这就是我为什么要把它设计得非常简单 Dialogue: 0,0:25:44.07,0:25:46.46,Default,,0,0,0,,这几乎是所有可能的语言求值器的核心 Dialogue: 0,0:25:47.81,0:25:48.48,Default,,0,0,0,,回到这个定义上来 Dialogue: 0,0:25:49.42,0:25:53.56,Default,,0,0,0,,EVLIST -- 它是什么呢? Dialogue: 0,0:25:53.82,0:25:57.04,Default,,0,0,0,,这个过程接收两个参数 L和ENV Dialogue: 0,0:25:58.09,0:25:59.08,Default,,0,0,0,,其中L是个表 Dialogue: 0,0:25:59.58,0:26:08.27,Default,,0,0,0,,这样的话 如果参数表是空表 Dialogue: 0,0:26:10.19,0:26:12.68,Default,,0,0,0,,那么结果就是空表 Dialogue: 0,0:26:14.03,0:26:19.23,Default,,0,0,0,,否则的话 我就要组合 Dialogue: 0,0:26:20.75,0:26:26.67,Default,,0,0,0,,在ENV中求值运算对象表的CAR部分 Dialogue: 0,0:26:28.16,0:26:32.51,Default,,0,0,0,,在ENV中求值运算对象CAR部分的结果 Dialogue: 0,0:26:33.34,0:26:35.71,Default,,0,0,0,,我想先求值第一个运算对象 Dialogue: 0,0:26:35.98,0:26:38.40,Default,,0,0,0,,返回的结果将是一个新表 Dialogue: 0,0:26:38.97,0:26:40.76,Default,,0,0,0,,是通过把这个和 Dialogue: 0,0:26:41.08,0:26:45.42,Default,,0,0,0,,用CDR递归EVLIST的结果组合得到的 Dialogue: 0,0:26:46.22,0:26:50.13,Default,,0,0,0,,在同样的ENV下 L的CDR部分 Dialogue: 0,0:26:53.08,0:26:58.24,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:26:59.66,0:27:01.84,Default,,0,0,0,,还有一个过程 Dialogue: 0,0:27:01.84,0:27:03.36,Default,,0,0,0,,我也想写在这里 Dialogue: 0,0:27:03.62,0:27:05.21,Default,,0,0,0,,它是这整个的关键 Dialogue: 0,0:27:05.64,0:27:08.13,Default,,0,0,0,,还要深入一个层次 Dialogue: 0,0:27:14.54,0:27:15.44,Default,,0,0,0,,也就是COND语句 Dialogue: 0,0:27:15.69,0:27:16.99,Default,,0,0,0,,在剩下的东西中 Dialogue: 0,0:27:17.02,0:27:18.17,Default,,0,0,0,,EVCOND是唯一的重要过程 Dialogue: 0,0:27:18.88,0:27:20.75,Default,,0,0,0,,解决完这个后 Dialogue: 0,0:27:21.07,0:27:22.94,Default,,0,0,0,,我们再讨论LOOKUP和BIND Dialogue: 0,0:27:23.56,0:27:25.36,Default,,0,0,0,,稍后再来讨论 Dialogue: 0,0:27:25.53,0:27:27.93,Default,,0,0,0,,在这个层次上 这是非常重要的 Dialogue: 0,0:27:28.65,0:27:30.62,Default,,0,0,0,,下一个重要的事就是如何处理COND语句 Dialogue: 0,0:27:31.60,0:27:33.33,Default,,0,0,0,,那么 我们怎么来处理呢? Dialogue: 0,0:27:36.97,0:27:38.56,Default,,0,0,0,,它是一个过程 Dialogue: 0,0:27:39.48,0:27:45.00,Default,,0,0,0,,参数是一组子句CLAUSES和环境ENV Dialogue: 0,0:27:47.71,0:27:48.51,Default,,0,0,0,,它做些什么呢? Dialogue: 0,0:27:49.82,0:27:55.47,Default,,0,0,0,,如果子句为空 Dialogue: 0,0:28:02.60,0:28:03.96,Default,,0,0,0,,我得有一个返回值 Dialogue: 0,0:28:04.70,0:28:05.87,Default,,0,0,0,,可能是一个错误 Dialogue: 0,0:28:06.54,0:28:08.59,Default,,0,0,0,,如果遍历完了所有条件 都没有符合的 Dialogue: 0,0:28:09.15,0:28:10.06,Default,,0,0,0,,那么它可能有任意的行为 Dialogue: 0,0:28:10.06,0:28:12.88,Default,,0,0,0,,这完全取决于程序员要怎么处理 Dialogue: 0,0:28:13.65,0:28:15.45,Default,,0,0,0,,现在对我来说最方便的是 Dialogue: 0,0:28:15.63,0:28:17.53,Default,,0,0,0,,让它返回一个空表 Dialogue: 0,0:28:18.14,0:28:18.83,Default,,0,0,0,,这无所谓 Dialogue: 0,0:28:20.10,0:28:20.88,Default,,0,0,0,,为了检查出错误 Dialogue: 0,0:28:20.89,0:28:22.76,Default,,0,0,0,,有些人喜欢在这里写点别的 Dialogue: 0,0:28:23.11,0:28:24.81,Default,,0,0,0,,下面的更有意思 Dialogue: 0,0:28:25.39,0:28:27.24,Default,,0,0,0,,如果我遇到了ELSE子句 Dialogue: 0,0:28:31.00,0:28:32.73,Default,,0,0,0,,请看 我们有一个由子句组成的表 Dialogue: 0,0:28:33.21,0:28:34.41,Default,,0,0,0,,其中每个子句也是一个表 Dialogue: 0,0:28:35.44,0:28:40.52,Default,,0,0,0,,因此谓词就应该是CLAUSES的CAAR部分 Dialogue: 0,0:28:43.56,0:28:45.02,Default,,0,0,0,,它是 Dialogue: 0,0:28:45.04,0:28:49.00,Default,,0,0,0,,CLAUSES表中第一个元素的CAR部分 Dialogue: 0,0:28:51.09,0:28:51.84,Default,,0,0,0,,如果它是'ELSE的话 Dialogue: 0,0:28:54.32,0:28:56.51,Default,,0,0,0,,就意味着整个COND表达式的结果 Dialogue: 0,0:28:56.64,0:28:59.15,Default,,0,0,0,,就是求值匹配表达式的结果 Dialogue: 0,0:29:00.12,0:29:04.32,Default,,0,0,0,,所以我求值CADAR部分 Dialogue: 0,0:29:07.00,0:29:09.56,Default,,0,0,0,,这是第一个子句的 Dialogue: 0,0:29:10.12,0:29:11.63,Default,,0,0,0,,第二个元素 也就是CADAR Dialogue: 0,0:29:12.81,0:29:17.08,Default,,0,0,0,,也就是CLAUSES的CAR部分的CADR部分 Dialogue: 0,0:29:21.23,0:29:22.57,Default,,0,0,0,,求值的环境是ENV Dialogue: 0,0:29:26.62,0:29:28.60,Default,,0,0,0,,下一种可能性更有意思 Dialogue: 0,0:29:29.63,0:29:30.44,Default,,0,0,0,,如果它返回FALSE的话 Dialogue: 0,0:29:33.05,0:29:35.10,Default,,0,0,0,,如果谓词表中的第一个谓词 Dialogue: 0,0:29:35.74,0:29:37.68,Default,,0,0,0,,既不是ELSE子句 又不为FALSE Dialogue: 0,0:29:38.32,0:29:39.50,Default,,0,0,0,,也就是它不是保留字ELSE Dialogue: 0,0:29:40.16,0:29:42.00,Default,,0,0,0,,并且也不是一个值为FALSE的东西 Dialogue: 0,0:29:42.03,0:29:43.66,Default,,0,0,0,,如果为FALSE又要怎么处理呢? Dialogue: 0,0:29:44.36,0:29:50.08,Default,,0,0,0,,如果在相应的环境中 Dialogue: 0,0:29:52.33,0:29:56.76,Default,,0,0,0,,求值子句中第一个谓词的结果 Dialogue: 0,0:29:58.19,0:30:01.00,Default,,0,0,0,,如果求值的结果是FALSE的话 Dialogue: 0,0:30:01.69,0:30:03.82,Default,,0,0,0,,这就意味着 还得接着判断后面的子句 Dialogue: 0,0:30:04.36,0:30:05.74,Default,,0,0,0,,第一个就扔掉不管了 Dialogue: 0,0:30:06.25,0:30:08.33,Default,,0,0,0,,所以就进入下一个EVCOND循环 Dialogue: 0,0:30:09.95,0:30:16.49,Default,,0,0,0,,在对应的环境中继续判断子句的CDR部分 Dialogue: 0,0:30:19.95,0:30:25.15,Default,,0,0,0,,又或者 我遇到了求值为TRUE的子句 Dialogue: 0,0:30:26.84,0:30:28.96,Default,,0,0,0,,这样的话 我想在对应的环境中 Dialogue: 0,0:30:31.85,0:30:41.45,Default,,0,0,0,,求值CLAUSES的CADAR部分 Dialogue: 0,0:30:48.20,0:30:49.61,Default,,0,0,0,,快了 快完成了 Dialogue: 0,0:30:51.21,0:30:52.80,Default,,0,0,0,,基本上完整了 Dialogue: 0,0:30:53.73,0:30:55.87,Default,,0,0,0,,把这一部分结束 Dialogue: 0,0:30:56.21,0:30:58.57,Default,,0,0,0,,再回顾一下这个求值器 Dialogue: 0,0:30:58.81,0:31:00.70,Default,,0,0,0,,它基本上就是这样了 Dialogue: 0,0:31:01.08,0:31:04.04,Default,,0,0,0,,接着来看一张幻灯片 Dialogue: 0,0:31:06.32,0:31:10.43,Default,,0,0,0,,这是BIND的定义 Dialogue: 0,0:31:11.98,0:31:14.54,Default,,0,0,0,,BIND用于在环境中添加新的绑定 Dialogue: 0,0:31:15.46,0:31:18.67,Default,,0,0,0,,我们要在这里 Dialogue: 0,0:31:19.24,0:31:22.80,Default,,0,0,0,,为环境结构创建一个新框架 Dialogue: 0,0:31:22.80,0:31:25.42,Default,,0,0,0,,环境结构是通过由框架组成的表 Dialogue: 0,0:31:25.93,0:31:27.20,Default,,0,0,0,,来表示的 Dialogue: 0,0:31:28.08,0:31:30.19,Default,,0,0,0,,给定一个已有的环境 Dialogue: 0,0:31:30.32,0:31:32.11,Default,,0,0,0,,我可以通过把一个新建的框架 Dialogue: 0,0:31:32.25,0:31:33.82,Default,,0,0,0,,CONS在已有的环境上 Dialogue: 0,0:31:33.93,0:31:35.69,Default,,0,0,0,,来获得新的环境 Dialogue: 0,0:31:36.62,0:31:40.36,Default,,0,0,0,,正在应用的过程中 那些被绑定变量 Dialogue: 0,0:31:41.05,0:31:43.79,Default,,0,0,0,,与传递给过程的参数值结合在一起 Dialogue: 0,0:31:44.12,0:31:48.25,Default,,0,0,0,,组成了我们所创建的新框架 Dialogue: 0,0:31:49.69,0:31:50.65,Default,,0,0,0,,BIND其实就是创建表 Dialogue: 0,0:31:51.64,0:31:54.06,Default,,0,0,0,,环境就是一组由框架组成的表 Dialogue: 0,0:31:54.30,0:31:55.60,Default,,0,0,0,,把新的元素加入其中 Dialogue: 0,0:31:55.74,0:31:56.89,Default,,0,0,0,,也就形成了新的环境 Dialogue: 0,0:31:58.65,0:32:00.65,Default,,0,0,0,,而PAIR-UP的定义非常简单 Dialogue: 0,0:32:01.54,0:32:02.84,Default,,0,0,0,,PAIR-UP只不过是 Dialogue: 0,0:32:03.13,0:32:05.56,Default,,0,0,0,,如果我们有一个变量表和一个值表 Dialogue: 0,0:32:05.93,0:32:08.62,Default,,0,0,0,,那么 如果它俩的元素个数又相同 Dialogue: 0,0:32:08.62,0:32:09.58,Default,,0,0,0,,就可以让它们一一对应 Dialogue: 0,0:32:09.72,0:32:11.48,Default,,0,0,0,,否则的话 就是参数传递多了 Dialogue: 0,0:32:12.51,0:32:15.98,Default,,0,0,0,,如果值的个数比变量的个数多 Dialogue: 0,0:32:16.06,0:32:17.37,Default,,0,0,0,,那就说明参数传递少了 Dialogue: 0,0:32:18.51,0:32:19.63,Default,,0,0,0,,通常的情况是 Dialogue: 0,0:32:19.63,0:32:21.48,Default,,0,0,0,,如果没有出错 又没有完成的话 Dialogue: 0,0:32:22.06,0:32:25.61,Default,,0,0,0,,我就添加一个由第一个变量 Dialogue: 0,0:32:25.76,0:32:30.17,Default,,0,0,0,,和第一个参数组成的新序对 Dialogue: 0,0:32:30.94,0:32:32.12,Default,,0,0,0,,这是第一个值 Dialogue: 0,0:32:32.76,0:32:36.40,Default,,0,0,0,,把它们CONS在 Dialogue: 0,0:32:37.12,0:32:40.64,Default,,0,0,0,,剩余变量和值组成的表上 Dialogue: 0,0:32:42.95,0:32:44.78,Default,,0,0,0,,LOOKUP也同样简单 Dialogue: 0,0:32:46.28,0:32:49.63,Default,,0,0,0,,加入我要在环境中查找一个符号 Dialogue: 0,0:32:49.93,0:32:51.39,Default,,0,0,0,,那么 如果是空环境 Dialogue: 0,0:32:51.56,0:32:53.00,Default,,0,0,0,,那么就说明 该变量尚未绑定 Dialogue: 0,0:32:54.65,0:32:55.47,Default,,0,0,0,,否则 Dialogue: 0,0:32:56.86,0:33:00.36,Default,,0,0,0,,我就要使用一个特殊的关联表查找过程 Dialogue: 0,0:33:00.38,0:33:01.87,Default,,0,0,0,,我们不久就会看到它的定义 Dialogue: 0,0:33:02.24,0:33:05.44,Default,,0,0,0,,用它在环境的第一个框架中查找该符号 Dialogue: 0,0:33:05.93,0:33:07.21,Default,,0,0,0,,由于我知道这个环境不是空的 Dialogue: 0,0:33:07.23,0:33:08.40,Default,,0,0,0,,因此 它至少有一个框架 Dialogue: 0,0:33:09.20,0:33:11.14,Default,,0,0,0,,所以 我就在它第一个框架中查找 Dialogue: 0,0:33:11.56,0:33:13.58,Default,,0,0,0,,找到的序对会传递给这里的VCELL Dialogue: 0,0:33:14.38,0:33:17.61,Default,,0,0,0,,如果VCELL为空 Dialogue: 0,0:33:18.44,0:33:20.57,Default,,0,0,0,,那就说明当前框架中没有这个符号 Dialogue: 0,0:33:20.70,0:33:22.84,Default,,0,0,0,,我就需要在环境中剩下的框架中查找 Dialogue: 0,0:33:23.72,0:33:25.04,Default,,0,0,0,,VCELL为空 意味着当前框架没有相应的符号 Dialogue: 0,0:33:25.99,0:33:28.89,Default,,0,0,0,,如果没有找到 Dialogue: 0,0:33:29.52,0:33:30.80,Default,,0,0,0,,ASSQ就会返回空表 Dialogue: 0,0:33:32.32,0:33:33.85,Default,,0,0,0,,如果找到了 Dialogue: 0,0:33:33.85,0:33:36.06,Default,,0,0,0,,那么我就使用VCELL的CDR部分 Dialogue: 0,0:33:36.46,0:33:40.25,Default,,0,0,0,,因为VCELL是变量和值组成的序对 Dialogue: 0,0:33:41.05,0:33:43.93,Default,,0,0,0,,因此可以用CDR取得对应的值 Dialogue: 0,0:33:45.00,0:33:47.82,Default,,0,0,0,,ASSQ这个过程你们之前见过 Dialogue: 0,0:33:47.97,0:33:50.83,Default,,0,0,0,,ASSQ的参数是一个符号和一个由序对组成的表 Dialogue: 0,0:33:51.42,0:33:53.40,Default,,0,0,0,,如果表为空 它就返回空表 Dialogue: 0,0:33:53.52,0:33:56.30,Default,,0,0,0,,如果这个符号是ALIST的第一个元素 Dialogue: 0,0:33:58.06,0:33:58.91,Default,,0,0,0,,这里写错了 Dialogue: 0,0:33:59.82,0:34:02.17,Default,,0,0,0,,应该是CAAR Dialogue: 0,0:34:03.16,0:34:04.16,Default,,0,0,0,,大家注意一下 Dialogue: 0,0:34:07.63,0:34:09.37,Default,,0,0,0,,就是这里 看到了吗? Dialogue: 0,0:34:13.42,0:34:14.41,Default,,0,0,0,,总之 Dialogue: 0,0:34:14.56,0:34:16.81,Default,,0,0,0,,如果符号等于表的CAAR Dialogue: 0,0:34:17.16,0:34:20.97,Default,,0,0,0,,那么我就返回ALIST中第一个序对 Dialogue: 0,0:34:22.08,0:34:25.50,Default,,0,0,0,,换句话说 这个键匹配了正确的条目 Dialogue: 0,0:34:26.24,0:34:26.97,Default,,0,0,0,,否则的话 Dialogue: 0,0:34:27.08,0:34:28.94,Default,,0,0,0,,我就需要在剩下的表中继续查找 Dialogue: 0,0:34:30.08,0:34:33.31,Default,,0,0,0,,这里有个笔误 很抱歉 Dialogue: 0,0:34:35.19,0:34:36.28,Default,,0,0,0,,好了 不管如何 Dialogue: 0,0:34:37.05,0:34:39.48,Default,,0,0,0,,你们基本上已经看到了全貌 Dialogue: 0,0:34:41.88,0:34:43.29,Default,,0,0,0,,虽然我们的代码风格非常丑陋 Dialogue: 0,0:34:44.19,0:34:46.00,Default,,0,0,0,,但是作为所有语言的核心 Dialogue: 0,0:34:46.76,0:34:48.30,Default,,0,0,0,,它却是非常美妙 Dialogue: 0,0:34:49.60,0:34:51.37,Default,,0,0,0,,我提议 让我们再欣赏一会儿 Dialogue: 0,0:35:00.32,0:35:47.02,Default,,0,0,0,,[音乐] Dialogue: 0,0:35:49.75,0:35:50.91,Default,,0,0,0,,大家有什么问题吗? Dialogue: 0,0:36:01.18,0:36:03.29,Default,,0,0,0,,没有的话就休息一会儿吧 Dialogue: 0,0:36:04.04,0:36:10.73,Default,,0,0,0,,[音乐] Dialogue: 0,0:36:13.88,0:36:17.64,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:36:40.80,0:36:43.93,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:36:43.95,0:36:47.98,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:36:48.06,0:36:51.93,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 I Dialogue: 0,0:36:56.78,0:36:58.99,Default,,0,0,0,,现在 我们将用一个实例 Dialogue: 0,0:36:59.29,0:37:02.67,Default,,0,0,0,,来理解一下求值器的运作过程 Dialogue: 0,0:37:03.47,0:37:05.48,Default,,0,0,0,,我们通过手工进行代换 Dialogue: 0,0:37:05.50,0:37:10.36,Default,,0,0,0,,来深入解释器的详细工作原理 Dialogue: 0,0:37:11.50,0:37:14.94,Default,,0,0,0,,由于我们的求值器不支持赋值和定义 Dialogue: 0,0:37:15.20,0:37:17.34,Default,,0,0,0,,我们也就不用担心副作用 Dialogue: 0,0:37:17.98,0:37:22.03,Default,,0,0,0,,因此我们可以放心大胆地进行代换 Dialogue: 0,0:37:22.52,0:37:24.59,Default,,0,0,0,,不用担心任何副作用 Dialogue: 0,0:37:25.33,0:37:27.80,Default,,0,0,0,,我们将要尝试去手工代换 Dialogue: 0,0:37:28.06,0:37:29.63,Default,,0,0,0,,这个复杂的表达式 Dialogue: 0,0:37:30.69,0:37:34.09,Default,,0,0,0,,(EVAL Dialogue: 0,0:37:34.91,0:37:48.08,Default,,0,0,0,,'(((LAMBDA (X) (LAMBDA (Y) (+ X Y))) Dialogue: 0,0:37:50.30,0:37:52.62,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:37:53.04,0:37:56.12,Default,,0,0,0,,要把它应用在3和4上 Dialogue: 0,0:37:56.94,0:37:59.58,Default,,0,0,0,,求值过程是发生在全局环境E0中的 Dialogue: 0,0:38:04.93,0:38:05.96,Default,,0,0,0,,这里的这个表达式 Dialogue: 0,0:38:06.36,0:38:08.04,Default,,0,0,0,,是个参数为X的一元过程 Dialogue: 0,0:38:08.09,0:38:11.05,Default,,0,0,0,,返回一个参数为Y的一元过程 Dialogue: 0,0:38:11.07,0:38:12.12,Default,,0,0,0,,后者计算X+Y Dialogue: 0,0:38:14.30,0:38:17.96,Default,,0,0,0,,外层的这个过程应用于数字3 Dialogue: 0,0:38:17.96,0:38:19.39,Default,,0,0,0,,所以X应该是3 Dialogue: 0,0:38:21.40,0:38:23.98,Default,,0,0,0,,返回的结果是一个参数为Y的一元过程 Dialogue: 0,0:38:24.33,0:38:25.82,Default,,0,0,0,,该过程将应用于数字4 Dialogue: 0,0:38:28.91,0:38:30.32,Default,,0,0,0,,然后要做的也很简单 Dialogue: 0,0:38:31.04,0:38:32.73,Default,,0,0,0,,计算X+Y即可 Dialogue: 0,0:38:34.79,0:38:35.82,Default,,0,0,0,,具体做之前 Dialogue: 0,0:38:35.84,0:38:37.76,Default,,0,0,0,,先来构造一个非常简单的环境模型 Dialogue: 0,0:38:37.90,0:38:40.48,Default,,0,0,0,,到了现在 我相信你们已经想到 Dialogue: 0,0:38:40.99,0:38:42.59,Default,,0,0,0,,这个过程产生的环境了 Dialogue: 0,0:38:44.46,0:38:46.62,Default,,0,0,0,,我们从全局环境开始 Dialogue: 0,0:38:48.59,0:38:50.06,Default,,0,0,0,,我们把它记作E0 Dialogue: 0,0:38:54.60,0:38:55.47,Default,,0,0,0,,就像这样 Dialogue: 0,0:38:56.74,0:39:02.46,Default,,0,0,0,,里面应该有过程+、*的定义 Dialogue: 0,0:39:06.30,0:39:10.36,Default,,0,0,0,,这里 我们用希腊字母来表示过程对象 这样有趣点 Dialogue: 0,0:39:11.21,0:39:27.93,Default,,0,0,0,,-、/、CAR、CDR、CONS以及EQ? Dialogue: 0,0:39:28.59,0:39:31.05,Default,,0,0,0,,其它需要的基本过程都在全局环境中 Dialogue: 0,0:39:31.27,0:39:33.82,Default,,0,0,0,,每个符号都对应着一个过程对象 Dialogue: 0,0:39:34.62,0:39:36.09,Default,,0,0,0,,这些都是解释器自带的 Dialogue: 0,0:39:37.10,0:39:38.09,Default,,0,0,0,,这就是E0 Dialogue: 0,0:39:39.22,0:39:41.84,Default,,0,0,0,,现在 这个求值要怎样进行呢? Dialogue: 0,0:39:42.94,0:39:45.18,Default,,0,0,0,,我们来看看这些特殊形式 Dialogue: 0,0:39:45.69,0:39:47.05,Default,,0,0,0,,首先 这不是数字 Dialogue: 0,0:39:48.67,0:39:50.38,Default,,0,0,0,,也不是符号 Dialogue: 0,0:39:53.13,0:39:55.60,Default,,0,0,0,,这不是一个引用表达式 Dialogue: 0,0:39:56.60,0:39:58.38,Default,,0,0,0,,虽然外层是一个引用表达式 Dialogue: 0,0:39:59.47,0:40:00.80,Default,,0,0,0,,但并不是我想要去求值的那个 Dialogue: 0,0:40:00.83,0:40:01.36,Default,,0,0,0,,我想问的是 Dialogue: 0,0:40:01.39,0:40:04.96,Default,,0,0,0,,被引用的这个表达式 是否也是个引用表达式? Dialogue: 0,0:40:05.89,0:40:07.96,Default,,0,0,0,,我是在求值一个表达式 Dialogue: 0,0:40:07.96,0:40:09.98,Default,,0,0,0,,这个引号是为了引用这个特定表达式 Dialogue: 0,0:40:11.41,0:40:12.66,Default,,0,0,0,,而被引用的并非引用表达式 Dialogue: 0,0:40:13.71,0:40:17.21,Default,,0,0,0,,当然 它也不是以LAMBDA开头 Dialogue: 0,0:40:19.12,0:40:20.67,Default,,0,0,0,,也不以COND开头 Dialogue: 0,0:40:22.03,0:40:25.95,Default,,0,0,0,,因此它是过程的应用 Dialogue: 0,0:40:26.31,0:40:27.12,Default,,0,0,0,,这是一个组合式 Dialogue: 0,0:40:28.57,0:40:30.70,Default,,0,0,0,,既然它是组合式 Dialogue: 0,0:40:30.89,0:40:34.00,Default,,0,0,0,,这就是它的运算符 Dialogue: 0,0:40:34.64,0:40:36.08,Default,,0,0,0,,而这是它的运算对象 Dialogue: 0,0:40:40.13,0:40:42.41,Default,,0,0,0,,这就意味着 我要 Dialogue: 0,0:40:42.57,0:40:47.90,Default,,0,0,0,,把它转换成 Dialogue: 0,0:40:50.12,0:40:57.61,Default,,0,0,0,,(APPLY (EVAL '((LAMBDA (X) (LAMBDA (y) Dialogue: 0,0:40:57.88,0:40:59.12,Default,,0,0,0,,也就是在E0环境中 Dialogue: 0,0:40:59.95,0:41:04.19,Default,,0,0,0,,求值(+ X Y) Dialogue: 0,0:41:07.26,0:41:08.64,Default,,0,0,0,,不要漏了 Dialogue: 0,0:41:12.78,0:41:15.20,Default,,0,0,0,,要应用到的运算对象则是 Dialogue: 0,0:41:15.26,0:41:17.28,Default,,0,0,0,,用EVLIST求值参数的结果 Dialogue: 0,0:41:21.21,0:41:24.49,Default,,0,0,0,,也就是'(4) Dialogue: 0,0:41:29.01,0:41:31.26,Default,,0,0,0,,我用这个特殊的记号来表示 Dialogue: 0,0:41:32.32,0:41:34.83,Default,,0,0,0,,这是为了指代那个环境 Dialogue: 0,0:41:35.45,0:41:37.77,Default,,0,0,0,,我无法为它命名 Dialogue: 0,0:41:37.80,0:41:39.15,Default,,0,0,0,,因为我没有环境来存放的名字 Dialogue: 0,0:41:41.96,0:41:44.09,Default,,0,0,0,,你当然可以把看作是 Dialogue: 0,0:41:44.17,0:41:46.17,Default,,0,0,0,,某种引用表达式 Dialogue: 0,0:41:47.73,0:41:51.16,Default,,0,0,0,,在那里 它表示环境这种数据结构 Dialogue: 0,0:41:53.04,0:41:55.04,Default,,0,0,0,,好的 这是变换后的结果 Dialogue: 0,0:41:55.85,0:41:56.67,Default,,0,0,0,,为了执行这个表达式 Dialogue: 0,0:41:56.68,0:41:58.04,Default,,0,0,0,,我还得求值这两个表达式 Dialogue: 0,0:41:59.61,0:42:00.49,Default,,0,0,0,,EVLIST简单点 Dialogue: 0,0:42:00.57,0:42:03.18,Default,,0,0,0,,我们先计算这个吧 Dialogue: 0,0:42:03.77,0:42:07.44,Default,,0,0,0,,这就被归约为 Dialogue: 0,0:42:07.45,0:42:08.83,Default,,0,0,0,,上面的某些部分直接抄过来就好 Dialogue: 0,0:42:09.42,0:42:11.00,Default,,0,0,0,,代换的过程中少不了照抄 Dialogue: 0,0:42:18.53,0:42:21.24,Default,,0,0,0,,抄写的时候我就不多加解释了 Dialogue: 0,0:42:21.71,0:42:23.87,Default,,0,0,0,,这样能快一点儿 Dialogue: 0,0:42:26.41,0:42:28.64,Default,,0,0,0,,EVLIST的部分就代换成为 Dialogue: 0,0:42:28.65,0:42:36.72,Default,,0,0,0,,(CONS (EVAL '4 ) Dialogue: 0,0:42:38.78,0:42:40.17,Default,,0,0,0,,因为它不是空表 Dialogue: 0,0:42:41.44,0:42:49.39,Default,,0,0,0,,(EVLIST '() )) Dialogue: 0,0:42:52.58,0:42:54.20,Default,,0,0,0,,我要省略一些步骤了 Dialogue: 0,0:42:54.24,0:42:55.36,Default,,0,0,0,,因为太详细就有些无聊了 Dialogue: 0,0:42:59.87,0:43:05.42,Default,,0,0,0,,下一步跟上面基本上一样 Dialogue: 0,0:43:07.50,0:43:08.54,Default,,0,0,0,,继续照抄 Dialogue: 0,0:43:10.68,0:43:20.24,Default,,0,0,0,,(((LAMBDA (X) (LAMBDA (Y) (+ X Y)) 3) 4) ) Dialogue: 0,0:43:20.24,0:43:21.20,Default,,0,0,0,,看来我还宝刀未老嘛 Dialogue: 0,0:43:24.24,0:43:26.24,Default,,0,0,0,,下面对4求值 Dialogue: 0,0:43:26.56,0:43:28.44,Default,,0,0,0,,4是一个数字 Dialogue: 0,0:43:29.00,0:43:33.90,Default,,0,0,0,,结果就应该是(CONS 4 Dialogue: 0,0:43:34.03,0:43:37.47,Default,,0,0,0,,EVLIST对空表求值 结果也是空表 Dialogue: 0,0:43:38.33,0:43:39.24,Default,,0,0,0,,也就是这个 Dialogue: 0,0:43:42.62,0:43:45.08,Default,,0,0,0,,这个非常容易理解 Dialogue: 0,0:43:45.10,0:43:47.44,Default,,0,0,0,,就是一个只含有4的表 Dialogue: 0,0:43:48.71,0:43:53.84,Default,,0,0,0,,继续代换为 (APPLY (EVAL Dialogue: 0,0:43:55.28,0:44:02.51,Default,,0,0,0,,'((LAMBDA (X) (LAMBDA (Y) (+ X Y)) Dialogue: 0,0:44:03.40,0:44:07.48,Default,,0,0,0,,3) 4) ) Dialogue: 0,0:44:08.68,0:44:12.60,Default,,0,0,0,,应用在'(4)上 这样就完成了 Dialogue: 0,0:44:13.94,0:44:15.05,Default,,0,0,0,,这是这一步的结果 Dialogue: 0,0:44:17.00,0:44:19.96,Default,,0,0,0,,现在让我们进行下一步 更有意思的一步 Dialogue: 0,0:44:20.36,0:44:21.72,Default,,0,0,0,,这行代码要如何求值? Dialogue: 0,0:44:23.07,0:44:24.44,Default,,0,0,0,,为了求值这一部分 Dialogue: 0,0:44:25.20,0:44:28.65,Default,,0,0,0,,我得先求值-- 首先 它不是-- Dialogue: 0,0:44:29.46,0:44:31.04,Default,,0,0,0,,这是一个应用 Dialogue: 0,0:44:31.68,0:44:33.10,Default,,0,0,0,,它并不是特殊形式 Dialogue: 0,0:44:33.57,0:44:36.51,Default,,0,0,0,,如果应用中的运算符 Dialogue: 0,0:44:36.51,0:44:37.37,Default,,0,0,0,,就是这里 Dialogue: 0,0:44:37.66,0:44:38.94,Default,,0,0,0,,这就是运算符 Dialogue: 0,0:44:40.19,0:44:41.77,Default,,0,0,0,,应用在这个运算对象上 Dialogue: 0,0:44:44.54,0:44:45.74,Default,,0,0,0,,形成了一个组合式 Dialogue: 0,0:44:46.72,0:44:48.25,Default,,0,0,0,,现在我们要如何来求值呢? Dialogue: 0,0:44:48.84,0:44:52.37,Default,,0,0,0,,它是COND语句中的最后一种情况 Dialogue: 0,0:44:52.37,0:44:55.52,Default,,0,0,0,,在这步求值中 进行的代换是 Dialogue: 0,0:44:55.71,0:44:57.47,Default,,0,0,0,,把运算符的求值结果 Dialogue: 0,0:44:57.50,0:44:59.00,Default,,0,0,0,,应用在EVLIST的运算对象上 Dialogue: 0,0:45:01.16,0:45:08.20,Default,,0,0,0,,这也就是 (APPLY (APPLY (EVAL Dialogue: 0,0:45:10.57,0:45:21.07,Default,,0,0,0,,'(LAMBDA (X) (LAMBDA (Y) (+ X Y))) Dialogue: 0,0:45:21.80,0:45:23.45,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:45:23.74,0:45:25.42,Default,,0,0,0,,) Dialogue: 0,0:45:30.52,0:45:32.67,Default,,0,0,0,,我就直接给出运算对象的求值结果了 Dialogue: 0,0:45:32.68,0:45:34.14,Default,,0,0,0,,具体过程跟之前是一样的 Dialogue: 0,0:45:35.23,0:45:36.48,Default,,0,0,0,,我有一个表'(3) Dialogue: 0,0:45:36.51,0:45:39.16,Default,,0,0,0,,把它应用于'(4) Dialogue: 0,0:45:42.44,0:45:43.56,Default,,0,0,0,,我们接着看 Dialogue: 0,0:45:44.41,0:45:46.38,Default,,0,0,0,,对一个LAMBDA表达式求值 Dialogue: 0,0:45:48.01,0:45:49.45,Default,,0,0,0,,会产生一个过程对象 Dialogue: 0,0:45:52.03,0:45:57.88,Default,,0,0,0,,继续变换就是 (APPLY (APPLY Dialogue: 0,0:46:00.30,0:46:02.27,Default,,0,0,0,,然后是一个过程对象 '(CLOSURE Dialogue: 0,0:46:04.52,0:46:08.68,Default,,0,0,0,,它里面包含了过程的体 Dialogue: 0,0:46:08.94,0:46:11.92,Default,,0,0,0,,它绑定了变量X Dialogue: 0,0:46:12.13,0:46:15.40,Default,,0,0,0,,然后是函数体内部 Dialogue: 0,0:46:15.80,0:46:18.17,Default,,0,0,0,,它返回一个参数为Y的单参过程 Dialogue: 0,0:46:18.56,0:46:20.63,Default,,0,0,0,,这个过程计算X+Y Dialogue: 0,0:46:23.21,0:46:25.50,Default,,0,0,0,,这个过程对象捕获了环境 Dialogue: 0,0:46:27.24,0:46:29.63,Default,,0,0,0,,因为这些求值都是在中发生的 Dialogue: 0,0:46:30.11,0:46:32.43,Default,,0,0,0,,现在 也是CLOSURE对象的一部分 Dialogue: 0,0:46:33.04,0:46:38.19,Default,,0,0,0,,先应用于'(3) Dialogue: 0,0:46:38.81,0:46:41.30,Default,,0,0,0,,再应用于'(4) Dialogue: 0,0:46:47.39,0:46:49.29,Default,,0,0,0,,在这步到这步的过程中 Dialogue: 0,0:46:49.31,0:46:50.89,Default,,0,0,0,,我构建了一个过程对象 Dialogue: 0,0:46:50.91,0:46:52.03,Default,,0,0,0,,它捕获了 Dialogue: 0,0:46:53.88,0:46:55.98,Default,,0,0,0,,并将其作为本身的一部分 Dialogue: 0,0:46:57.15,0:46:58.51,Default,,0,0,0,,现在 要把它们传递给APPLY了 Dialogue: 0,0:46:58.52,0:46:59.71,Default,,0,0,0,,我们得把这个过程 Dialogue: 0,0:47:00.48,0:47:01.58,Default,,0,0,0,,应用在对应的参数上 Dialogue: 0,0:47:02.71,0:47:06.51,Default,,0,0,0,,这里的过程并不是基本过程 Dialogue: 0,0:47:07.38,0:47:09.88,Default,,0,0,0,,它有一个类型标志'CLOSURE Dialogue: 0,0:47:10.24,0:47:12.09,Default,,0,0,0,,因此还需要进行参数绑定 Dialogue: 0,0:47:13.71,0:47:14.72,Default,,0,0,0,,必须要绑定 Dialogue: 0,0:47:15.83,0:47:19.40,Default,,0,0,0,,在这里构造的新环境 Dialogue: 0,0:47:20.44,0:47:22.80,Default,,0,0,0,,它有一个父环境 Dialogue: 0,0:47:22.94,0:47:27.56,Default,,0,0,0,,父环境是这里的 Dialogue: 0,0:47:30.32,0:47:31.57,Default,,0,0,0,,我们把新环境记作 Dialogue: 0,0:47:34.62,0:47:35.74,Default,,0,0,0,,这里要绑定些什么呢? Dialogue: 0,0:47:36.04,0:47:37.48,Default,,0,0,0,,变量X绑定为值3 Dialogue: 0,0:47:38.62,0:47:40.44,Default,,0,0,0,,这里写X=3 Dialogue: 0,0:47:41.48,0:47:42.33,Default,,0,0,0,,就是这些 Dialogue: 0,0:47:44.94,0:47:46.24,Default,,0,0,0,,新环境记作E1 Dialogue: 0,0:47:46.24,0:47:48.44,Default,,0,0,0,,而这个表达式会变换为 Dialogue: 0,0:47:49.13,0:47:50.72,Default,,0,0,0,,对一个过程体的求值 Dialogue: 0,0:47:51.72,0:47:53.07,Default,,0,0,0,,就是这个 在这里 Dialogue: 0,0:47:54.40,0:47:55.72,Default,,0,0,0,,这个过程的体 Dialogue: 0,0:47:56.44,0:47:58.52,Default,,0,0,0,,在刚才创建的中进行求值 Dialogue: 0,0:48:00.29,0:48:05.05,Default,,0,0,0,,也就是 (APPLY (EVAL Dialogue: 0,0:48:06.92,0:48:16.43,Default,,0,0,0,,'(LAMBDA (Y) (+ X Y)) ) Dialogue: 0,0:48:20.49,0:48:22.48,Default,,0,0,0,,把求值的结果应用于4 Dialogue: 0,0:48:23.68,0:48:26.73,Default,,0,0,0,,也就是'(4) Dialogue: 0,0:48:28.43,0:48:29.87,Default,,0,0,0,,到了这里就很清晰了 Dialogue: 0,0:48:30.08,0:48:32.27,Default,,0,0,0,,我知道该如何求值LAMBDA表达式 Dialogue: 0,0:48:33.11,0:48:34.17,Default,,0,0,0,,也就是(APPLY Dialogue: 0,0:48:37.16,0:48:38.92,Default,,0,0,0,,一个过程对象'(CLOSURE Dialogue: 0,0:48:43.74,0:48:46.84,Default,,0,0,0,,它绑定参数Y 计算X+Y Dialogue: 0,0:48:49.28,0:48:52.15,Default,,0,0,0,,并且捕获了环境 Dialogue: 0,0:48:55.79,0:48:57.42,Default,,0,0,0,,你应该已经见过了 对吧? Dialogue: 0,0:48:57.80,0:49:00.14,Default,,0,0,0,,我构造了一个CLOSURE对象 Dialogue: 0,0:49:00.14,0:49:01.16,Default,,0,0,0,,放在这里 Dialogue: 0,0:49:01.79,0:49:03.04,Default,,0,0,0,,之前的那个也是 Dialogue: 0,0:49:05.90,0:49:07.47,Default,,0,0,0,,这是现在的这个 Dialogue: 0,0:49:08.08,0:49:09.80,Default,,0,0,0,,它捕获了环境 Dialogue: 0,0:49:10.41,0:49:14.25,Default,,0,0,0,,而这个是参数为Y的一元过程 Dialogue: 0,0:49:15.45,0:49:16.70,Default,,0,0,0,,先不管它具体是什么 Dialogue: 0,0:49:18.09,0:49:20.72,Default,,0,0,0,,我们只知道它是一个CLOSURE Dialogue: 0,0:49:22.57,0:49:26.46,Default,,0,0,0,,将这个过程应用于'(4) Dialogue: 0,0:49:30.28,0:49:31.77,Default,,0,0,0,,很简单 Dialogue: 0,0:49:36.83,0:49:38.73,Default,,0,0,0,,我需要通过复制一个指针 Dialogue: 0,0:49:38.86,0:49:40.52,Default,,0,0,0,,就是这个过程的指针 Dialogue: 0,0:49:41.56,0:49:43.21,Default,,0,0,0,,来构造一个新环境 Dialogue: 0,0:49:44.94,0:49:48.96,Default,,0,0,0,,同时还得把参数Y跟值4绑定 Dialogue: 0,0:49:49.82,0:49:52.22,Default,,0,0,0,,我把这个新环境 记作 Dialogue: 0,0:49:56.03,0:49:58.12,Default,,0,0,0,,当然 这里的这个应用 Dialogue: 0,0:49:58.22,0:50:00.33,Default,,0,0,0,,其过程体的求值 是在中进行的 Dialogue: 0,0:50:01.58,0:50:07.87,Default,,0,0,0,,所以这就变成了对过程体的求值 Dialogue: 0,0:50:07.90,0:50:11.85,Default,,0,0,0,,也就是 (EVAL '(+ X Y) ) Dialogue: 0,0:50:13.71,0:50:14.94,Default,,0,0,0,,但由于这是一个应用 Dialogue: 0,0:50:15.48,0:50:23.88,Default,,0,0,0,,所以又代换为 (APPLY (EVAL '+ ) Dialogue: 0,0:50:26.33,0:50:37.34,Default,,0,0,0,,(EVLIST '(X Y) )) Dialogue: 0,0:50:44.88,0:50:45.59,Default,,0,0,0,,我们来看 Dialogue: 0,0:50:45.59,0:50:51.71,Default,,0,0,0,,下一步代换为 (APPLY Dialogue: 0,0:50:52.08,0:50:53.87,Default,,0,0,0,,求值‘+得到的结果 Dialogue: 0,0:50:54.19,0:50:55.66,Default,,0,0,0,,所以我们从开始找 Dialogue: 0,0:50:55.69,0:50:57.72,Default,,0,0,0,,'+既不在 也不在 Dialogue: 0,0:50:57.74,0:51:01.05,Default,,0,0,0,,‘+是中的基本运算符 Dialogue: 0,0:51:01.78,0:51:04.74,Default,,0,0,0,,这个基本运算符是用于加法的 Dialogue: 0,0:51:07.47,0:51:14.12,Default,,0,0,0,,把它应用于 在中求值X和Y的结果 Dialogue: 0,0:51:14.37,0:51:17.00,Default,,0,0,0,,我们知道X是3 Y是4 Dialogue: 0,0:51:18.11,0:51:23.31,Default,,0,0,0,,所以这里是'(3 4) Dialogue: 0,0:51:24.16,0:51:26.28,Default,,0,0,0,,然后就神奇地得到结果7 Dialogue: 0,0:51:30.52,0:51:32.44,Default,,0,0,0,,我再来整理一下这个过程 这样你们 Dialogue: 0,0:51:32.70,0:51:34.73,Default,,0,0,0,,就能了解这其中的重要本质 Dialogue: 0,0:51:35.76,0:51:37.29,Default,,0,0,0,,这个过程中传递了些什么? Dialogue: 0,0:51:37.31,0:51:39.56,Default,,0,0,0,,每个模块持有什么 又负责什么? Dialogue: 0,0:51:40.47,0:51:41.61,Default,,0,0,0,,有哪些模块呢? Dialogue: 0,0:51:41.70,0:51:42.62,Default,,0,0,0,,一个是EVAL Dialogue: 0,0:51:44.80,0:51:45.64,Default,,0,0,0,,还有个APPLY Dialogue: 0,0:51:45.66,0:51:46.62,Default,,0,0,0,,两个主要角色 Dialogue: 0,0:51:49.37,0:51:51.56,Default,,0,0,0,,它们之间有个像这样的大循环 Dialogue: 0,0:51:52.32,0:52:04.57,Default,,0,0,0,,其中 EVAL为APPLY生成过程和参数 Dialogue: 0,0:52:06.27,0:52:08.57,Default,,0,0,0,,也有些事情 EVAL也可以自己做 Dialogue: 0,0:52:09.50,0:52:10.86,Default,,0,0,0,,都是一些细小的事情 Dialogue: 0,0:52:10.86,0:52:11.74,Default,,0,0,0,,并不十分有趣 Dialogue: 0,0:52:12.70,0:52:15.60,Default,,0,0,0,,同时 EVAL也逐个求值所有的参数 Dialogue: 0,0:52:16.24,0:52:17.28,Default,,0,0,0,,也没什么意思 Dialogue: 0,0:52:17.65,0:52:20.09,Default,,0,0,0,,APPLY可以应用像+这类的过程 Dialogue: 0,0:52:21.02,0:52:22.04,Default,,0,0,0,,这很普通 Dialogue: 0,0:52:22.30,0:52:24.64,Default,,0,0,0,,然而 如果APPLY不能应用像+这样的过程 Dialogue: 0,0:52:25.31,0:52:33.31,Default,,0,0,0,,它就为EVAL生成一个表达式及相应的环境 Dialogue: 0,0:52:35.47,0:52:37.61,Default,,0,0,0,,过程的参数封装了 Dialogue: 0,0:52:38.24,0:52:40.60,Default,,0,0,0,,计算所必需的状态 Dialogue: 0,0:52:41.66,0:52:43.42,Default,,0,0,0,,以及相应的环境 Dialogue: 0,0:52:43.74,0:52:45.31,Default,,0,0,0,,但我们接下来要做的 Dialogue: 0,0:52:45.32,0:52:46.46,Default,,0,0,0,,并不是完整的状态 Dialogue: 0,0:52:46.48,0:52:48.82,Default,,0,0,0,,因为它没有说明谁需要返回的结果 Dialogue: 0,0:52:51.28,0:52:52.20,Default,,0,0,0,,我们要做的就是 Dialogue: 0,0:52:52.24,0:52:54.80,Default,,0,0,0,,总是把某个表达式以及相应的环境 Dialogue: 0,0:52:54.99,0:52:56.14,Default,,0,0,0,,或者过程对象以及其参数 Dialogue: 0,0:52:56.28,0:52:58.08,Default,,0,0,0,,在这个循环之间不断传递 Dialogue: 0,0:52:58.97,0:53:01.80,Default,,0,0,0,,这里还有一些小型的子循环 比如EVLIST Dialogue: 0,0:53:04.49,0:53:06.76,Default,,0,0,0,,又或者是EVAL中的EVCOND循环 Dialogue: 0,0:53:09.10,0:53:11.96,Default,,0,0,0,,甚至于APPLY调用PRIMITIVE-APPLY Dialogue: 0,0:53:16.14,0:53:17.64,Default,,0,0,0,,但是它们并不是最主要的 Dialogue: 0,0:53:18.86,0:53:20.28,Default,,0,0,0,,这整个就是我想让你们看到的 Dialogue: 0,0:53:21.86,0:53:22.88,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:53:25.93,0:53:27.37,Default,,0,0,0,,David 请说 Dialogue: 0,0:53:27.74,0:53:33.31,Default,,0,0,0,,学生:我不明白为什么X是3 Dialogue: 0,0:53:34.01,0:53:36.30,Default,,0,0,0,,而不是4 Dialogue: 0,0:53:37.07,0:53:38.52,Default,,0,0,0,,在那个部分 Dialogue: 0,0:53:38.56,0:53:40.54,Default,,0,0,0,,教授:是在这里 Dialogue: 0,0:53:41.31,0:53:43.31,Default,,0,0,0,,你想知道X是如何跟3绑定的 Dialogue: 0,0:53:43.52,0:53:47.42,Default,,0,0,0,,学生:因为X是外层过程的参数 Dialogue: 0,0:53:48.46,0:53:50.99,Default,,0,0,0,,而内层过程中既有X又有Y Dialogue: 0,0:53:51.26,0:53:51.88,Default,,0,0,0,,教授:明白了 Dialogue: 0,0:53:52.84,0:53:54.62,Default,,0,0,0,,代换的过程中 我已经非常小心了 Dialogue: 0,0:53:55.02,0:53:56.92,Default,,0,0,0,,或许首先 我应该把这些过程 Dialogue: 0,0:53:56.94,0:53:58.41,Default,,0,0,0,,重新编排得更易读一点 Dialogue: 0,0:54:00.61,0:54:01.47,Default,,0,0,0,,你之所以有所疑惑 Dialogue: 0,0:54:01.48,0:54:02.99,Default,,0,0,0,,或许是因为你把程序看岔了 Dialogue: 0,0:54:03.83,0:54:04.70,Default,,0,0,0,,所以这里应该是 Dialogue: 0,0:54:05.15,0:54:09.60,Default,,0,0,0,,一个以X为参数的过程 Dialogue: 0,0:54:11.21,0:54:14.99,Default,,0,0,0,,它返回一个以Y为参数的过程 Dialogue: 0,0:54:15.72,0:54:18.44,Default,,0,0,0,,后者计算X+Y Dialogue: 0,0:54:19.82,0:54:21.10,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:54:21.40,0:54:22.89,Default,,0,0,0,,外面的过程应用到3上 Dialogue: 0,0:54:24.08,0:54:26.12,Default,,0,0,0,,把得到的结果应用到4上 Dialogue: 0,0:54:26.14,0:54:28.81,Default,,0,0,0,,这个和之前那个是一样的 对吧? Dialogue: 0,0:54:28.81,0:54:32.33,Default,,0,0,0,,现在 你可以立马发现 Dialogue: 0,0:54:33.77,0:54:34.94,Default,,0,0,0,,这里是一个应用 Dialogue: 0,0:54:35.16,0:54:36.46,Default,,0,0,0,,我先换根白粉笔 Dialogue: 0,0:54:37.32,0:54:41.12,Default,,0,0,0,,这一部分是应用 是一个组合式 Dialogue: 0,0:54:43.44,0:54:46.40,Default,,0,0,0,,这部分是组合式的运算符 Dialogue: 0,0:54:48.14,0:54:49.55,Default,,0,0,0,,而这是运算对象 Dialogue: 0,0:54:51.04,0:54:53.05,Default,,0,0,0,,这个3会跟这里的X绑定 Dialogue: 0,0:54:54.90,0:54:56.36,Default,,0,0,0,,而这个组合式的结果 Dialogue: 0,0:54:56.56,0:54:58.46,Default,,0,0,0,,是一个参数为Y的一元过程 Dialogue: 0,0:54:58.73,0:54:59.79,Default,,0,0,0,,它将应用于4 Dialogue: 0,0:55:00.88,0:55:01.58,Default,,0,0,0,,明白了吧? Dialogue: 0,0:55:02.20,0:55:04.08,Default,,0,0,0,,所以你可能只是看岔了 Dialogue: 0,0:55:04.40,0:55:07.85,Default,,0,0,0,,而你们在这里看到的 Dialogue: 0,0:55:09.42,0:55:12.96,Default,,0,0,0,,是一个实际的过程对象 它有一个参数X Dialogue: 0,0:55:13.34,0:55:15.31,Default,,0,0,0,,这个CLOSURE将应用于3 Dialogue: 0,0:55:15.95,0:55:17.07,Default,,0,0,0,,也就是'(3) Dialogue: 0,0:55:18.98,0:55:21.34,Default,,0,0,0,,得到的结果再应用于'(4) Dialogue: 0,0:55:24.08,0:55:25.20,Default,,0,0,0,,还有疑问吗? Dialogue: 0,0:55:28.35,0:55:30.38,Default,,0,0,0,,那就休息一下吧 Dialogue: 0,0:55:30.83,0:55:31.37,Default,,0,0,0,,谢谢大家 Dialogue: 0,0:55:33.73,0:55:41.40,Default,,0,0,0,,[音乐] Dialogue: 0,0:55:42.12,0:55:47.44,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:55:50.70,0:55:54.08,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:55:54.12,0:55:59.16,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:55:59.23,0:56:03.95,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 I Dialogue: 0,0:56:08.41,0:56:11.29,Default,,0,0,0,,教授:课上到这里 Dialogue: 0,0:56:13.32,0:56:14.59,Default,,0,0,0,,你们可能开始觉得 Dialogue: 0,0:56:14.75,0:56:17.96,Default,,0,0,0,,Sussman教授又在胡说八道些什么 Dialogue: 0,0:56:20.74,0:56:23.92,Default,,0,0,0,,他讲的东西奇怪、愚蠢又毫无意义 Dialogue: 0,0:56:24.80,0:56:27.40,Default,,0,0,0,,他还宣称要给我们解释Lisp Dialogue: 0,0:56:28.01,0:56:29.90,Default,,0,0,0,,然后在黑板上给我们写了一个Lisp程序 Dialogue: 0,0:56:31.23,0:56:33.53,Default,,0,0,0,,他还说:“这个Lisp程序就是Lisp解释器” Dialogue: 0,0:56:33.85,0:56:35.02,Default,,0,0,0,,但是为了运行这个Lisp程序 Dialogue: 0,0:56:35.04,0:56:36.30,Default,,0,0,0,,你还先得有一个Lisp解释器啊 Dialogue: 0,0:56:38.37,0:56:40.19,Default,,0,0,0,,那个程序怎么能告诉我 Dialogue: 0,0:56:40.22,0:56:43.20,Default,,0,0,0,,有关于Lisp的知识呢? Dialogue: 0,0:56:44.15,0:56:46.22,Default,,0,0,0,,它为什么又不是空中楼阁呢? Dialogue: 0,0:56:48.49,0:56:50.25,Default,,0,0,0,,这件事非常奇怪 Dialogue: 0,0:56:50.99,0:56:52.43,Default,,0,0,0,,它究竟告诉了我什么? Dialogue: 0,0:56:56.07,0:56:57.20,Default,,0,0,0,,我们发现 其实这整件事 Dialogue: 0,0:56:57.32,0:56:59.79,Default,,0,0,0,,非常像我们在这张幻灯片上看到的 Dialogue: 0,0:57:00.46,0:57:03.55,Default,,0,0,0,,Escher所画的手 Dialogue: 0,0:57:06.18,0:57:07.72,Default,,0,0,0,,是的 EVAL和APPLY Dialogue: 0,0:57:07.76,0:57:10.16,Default,,0,0,0,,彼此画出彼此 Dialogue: 0,0:57:11.50,0:57:14.16,Default,,0,0,0,,并且构造出了真实的东西 Dialogue: 0,0:57:14.86,0:57:16.30,Default,,0,0,0,,它完全是自己画出了自己 Dialogue: 0,0:57:17.11,0:57:18.46,Default,,0,0,0,,Escher真是绝顶聪明 Dialogue: 0,0:57:18.68,0:57:20.41,Default,,0,0,0,,他只不过叫不出这些精灵的名字 Dialogue: 0,0:57:23.91,0:57:25.00,Default,,0,0,0,,我现在要做的就是 Dialogue: 0,0:57:26.09,0:57:28.00,Default,,0,0,0,,使你们相信 Dialogue: 0,0:57:28.16,0:57:29.87,Default,,0,0,0,,这一切都是有意义的 Dialogue: 0,0:57:30.16,0:57:31.98,Default,,0,0,0,,并且 Dialogue: 0,0:57:32.99,0:57:34.72,Default,,0,0,0,,我将要解释为什么我们不需要DEFINE Dialogue: 0,0:57:36.09,0:57:37.71,Default,,0,0,0,,事实证明 我们并不需要DEFINE Dialogue: 0,0:57:38.09,0:57:41.12,Default,,0,0,0,,为了进行数学意义上的计算 Dialogue: 0,0:57:42.51,0:57:44.89,Default,,0,0,0,,DEFINE并不是必需的 Dialogue: 0,0:57:49.10,0:57:50.03,Default,,0,0,0,,我们来看一下 Dialogue: 0,0:57:50.69,0:57:53.31,Default,,0,0,0,,考虑下面的一小段程序 Dialogue: 0,0:57:53.74,0:57:54.64,Default,,0,0,0,,它有什么作用? Dialogue: 0,0:57:54.87,0:57:57.64,Default,,0,0,0,,这是一个计算指数的程序 Dialogue: 0,0:58:07.27,0:58:13.23,Default,,0,0,0,,EXPT计算X的N次方 Dialogue: 0,0:58:16.83,0:58:18.12,Default,,0,0,0,,如果N为0 Dialogue: 0,0:58:19.20,0:58:20.76,Default,,0,0,0,,那么结果就是1 Dialogue: 0,0:58:22.07,0:58:22.81,Default,,0,0,0,,否则 Dialogue: 0,0:58:25.56,0:58:28.48,Default,,0,0,0,,结果就是X乘以 Dialogue: 0,0:58:28.75,0:58:33.93,Default,,0,0,0,,(EXPT X (- N 1)))) Dialogue: 0,0:58:43.69,0:58:44.56,Default,,0,0,0,,应该没错 Dialogue: 0,0:58:46.63,0:58:48.72,Default,,0,0,0,,一个递归定义 Dialogue: 0,0:58:49.47,0:58:52.17,Default,,0,0,0,,用EXPT自身 Dialogue: 0,0:58:52.46,0:58:54.78,Default,,0,0,0,,来定义EXPT过程自己 Dialogue: 0,0:58:56.41,0:58:58.32,Default,,0,0,0,,就像我之前说的那样 Dialogue: 0,0:58:59.28,0:59:01.68,Default,,0,0,0,,你们高中数学老师在教这些东西的时候 Dialogue: 0,0:59:01.84,0:59:04.04,Default,,0,0,0,,你们一定学得很痛苦 Dialogue: 0,0:59:05.65,0:59:06.73,Default,,0,0,0,,这样定义合理吗? Dialogue: 0,0:59:07.91,0:59:10.84,Default,,0,0,0,,为什么这种自引用的定义 Dialogue: 0,0:59:10.96,0:59:12.04,Default,,0,0,0,,能够说得通呢? Dialogue: 0,0:59:13.43,0:59:15.10,Default,,0,0,0,,首先我要说的是 Dialogue: 0,0:59:15.13,0:59:17.60,Default,,0,0,0,,你们高中数学老师并非在胡说八道 Dialogue: 0,0:59:20.37,0:59:23.42,Default,,0,0,0,,考虑下面的几组定义 Dialogue: 0,0:59:24.27,0:59:27.42,Default,,0,0,0,,X+Y=3 Dialogue: 0,0:59:28.24,0:59:32.24,Default,,0,0,0,,X-Y=1 Dialogue: 0,0:59:33.07,0:59:35.56,Default,,0,0,0,,这个方程用Y来告诉你X Dialogue: 0,0:59:35.58,0:59:37.84,Default,,0,0,0,,而这个方程或许是用X来告诉你Y Dialogue: 0,0:59:40.15,0:59:42.95,Default,,0,0,0,,碰巧这组方程有唯一的解 Dialogue: 0,0:59:55.91,0:59:58.11,Default,,0,0,0,,然而 我也可能有这样的方程 Dialogue: 0,0:59:59.87,1:00:04.25,Default,,0,0,0,,2X+2Y=6 Dialogue: 0,1:00:06.83,1:00:09.87,Default,,0,0,0,,这两个方程有无穷多个解 Dialogue: 0,1:00:15.73,1:00:17.42,Default,,0,0,0,,我还可以有像这样的方程 Dialogue: 0,1:00:18.89,1:00:21.53,Default,,0,0,0,,X-Y=2 Dialogue: 0,1:00:22.14,1:00:24.41,Default,,0,0,0,,而下面的这两个方程没有解 Dialogue: 0,1:00:29.82,1:00:33.04,Default,,0,0,0,,这里 我有三组线性方程组 Dialogue: 0,1:00:35.45,1:00:39.51,Default,,0,0,0,,分别是这组、这组和这组 Dialogue: 0,1:00:39.88,1:00:41.79,Default,,0,0,0,,它们的解的数目完全不同 Dialogue: 0,1:00:42.90,1:00:45.76,Default,,0,0,0,,解的数目并不取决于方程的形式 Dialogue: 0,1:00:46.33,1:00:48.20,Default,,0,0,0,,三组方程都有一样的形式 Dialogue: 0,1:00:48.54,1:00:50.41,Default,,0,0,0,,解的数目取决于方程的内容 Dialogue: 0,1:00:53.00,1:00:55.15,Default,,0,0,0,,我不能通过观察方程的形式 Dialogue: 0,1:00:55.16,1:00:56.24,Default,,0,0,0,,来判断解的数目 Dialogue: 0,1:00:56.86,1:00:58.60,Default,,0,0,0,,必须要看它的内容 Dialogue: 0,1:00:59.66,1:01:00.88,Default,,0,0,0,,比如 对于线性方程组 Dialogue: 0,1:01:01.34,1:01:03.39,Default,,0,0,0,,它的系数都是什么? Dialogue: 0,1:01:05.10,1:01:06.72,Default,,0,0,0,,我不能够通过观察 Dialogue: 0,1:01:06.99,1:01:08.33,Default,,0,0,0,,像这样的简单情况 Dialogue: 0,1:01:08.59,1:01:09.95,Default,,0,0,0,,来判定 Dialogue: 0,1:01:10.08,1:01:14.49,Default,,0,0,0,,EXPT就是这个递归方程的解 Dialogue: 0,1:01:16.03,1:01:18.41,Default,,0,0,0,,我不能说 EXPT就是那个过程 Dialogue: 0,1:01:18.91,1:01:21.10,Default,,0,0,0,,如果我们把它代换入其中 Dialogue: 0,1:01:22.04,1:01:24.06,Default,,0,0,0,,它就能给我们返回EXPT Dialogue: 0,1:01:25.32,1:01:25.68,Default,,0,0,0,,能跟上吗? Dialogue: 0,1:01:26.04,1:01:29.24,Default,,0,0,0,,通过观察这个形式 我也无法判别 Dialogue: 0,1:01:29.80,1:01:32.60,Default,,0,0,0,,EXPT是否有唯一解 Dialogue: 0,1:01:33.23,1:01:35.31,Default,,0,0,0,,有无穷个解 还是根本没有解 Dialogue: 0,1:01:37.20,1:01:38.62,Default,,0,0,0,,我们要了解它是如何计数的 Dialogue: 0,1:01:38.64,1:01:40.14,Default,,0,0,0,,或者是一些类似的计算细节 Dialogue: 0,1:01:40.60,1:01:42.75,Default,,0,0,0,,这可比在线性代数难多了 Dialogue: 0,1:01:43.28,1:01:45.21,Default,,0,0,0,,程序设计中可用的定理并不多 Dialogue: 0,1:01:48.45,1:01:51.21,Default,,0,0,0,,我想把这些方程稍稍重写一下 Dialogue: 0,1:01:51.93,1:01:53.77,Default,,0,0,0,,就是这里的方程 Dialogue: 0,1:01:53.97,1:01:56.62,Default,,0,0,0,,因为我们要研究的是这种形式的方程 Dialogue: 0,1:01:57.00,1:01:58.38,Default,,0,0,0,,但是我想用我们比较了解的方程 Dialogue: 0,1:01:58.40,1:01:59.53,Default,,0,0,0,,来做演示 Dialogue: 0,1:02:00.70,1:02:02.91,Default,,0,0,0,,以便于对于这类问题有深入的洞见 Dialogue: 0,1:02:04.72,1:02:06.43,Default,,0,0,0,,我们可以把这里的方程 改写为 Dialogue: 0,1:02:06.75,1:02:08.67,Default,,0,0,0,,这样的一种有趣形式 Dialogue: 0,1:02:09.77,1:02:14.86,Default,,0,0,0,,X=3-Y Dialogue: 0,1:02:15.88,1:02:19.68,Default,,0,0,0,,Y=X-1 Dialogue: 0,1:02:22.01,1:02:24.05,Default,,0,0,0,,我们把这种变换叫什么来着? Dialogue: 0,1:02:24.05,1:02:26.52,Default,,0,0,0,,这是一个线性变换 记为T Dialogue: 0,1:02:29.43,1:02:32.25,Default,,0,0,0,,我们这里就得到了一个方程 Dialogue: 0,1:02:32.97,1:02:37.37,Default,,0,0,0,, = T Dialogue: 0,1:02:42.99,1:02:43.98,Default,,0,0,0,,我要去找什么呢? Dialogue: 0,1:02:44.56,1:02:46.01,Default,,0,0,0,,我在找T的不动点 Dialogue: 0,1:02:46.97,1:02:59.42,Default,,0,0,0,,T的不动点就是方程的解 Dialogue: 0,1:03:01.91,1:03:05.53,Default,,0,0,0,,所以 如果我们能通过找不动点 Dialogue: 0,1:03:05.90,1:03:07.48,Default,,0,0,0,,来求解方程 Dialogue: 0,1:03:08.65,1:03:09.87,Default,,0,0,0,,这看来是可行的 Dialogue: 0,1:03:10.88,1:03:12.36,Default,,0,0,0,,如果我可以用不动点 Dialogue: 0,1:03:12.38,1:03:14.32,Default,,0,0,0,,来求解方程 Dialogue: 0,1:03:15.52,1:03:18.19,Default,,0,0,0,,当然 也许它不可行 Dialogue: 0,1:03:18.57,1:03:19.80,Default,,0,0,0,,不过也可以借鉴来 Dialogue: 0,1:03:20.09,1:03:22.27,Default,,0,0,0,,研究如何求解这类方程 Dialogue: 0,1:03:27.24,1:03:29.48,Default,,0,0,0,,重要的是 我想让你们把它看成一个方程 Dialogue: 0,1:03:30.26,1:03:31.21,Default,,0,0,0,,它是一个表达式 Dialogue: 0,1:03:31.36,1:03:33.58,Default,,0,0,0,,其中有不同的变量 Dialogue: 0,1:03:34.70,1:03:37.66,Default,,0,0,0,,只不过这些名字还得满足一定的约束 Dialogue: 0,1:03:38.43,1:03:40.52,Default,,0,0,0,,这些名字限定了对应变量的取值 Dialogue: 0,1:03:41.48,1:03:45.01,Default,,0,0,0,,我们不能够随意、机械地代换 Dialogue: 0,1:03:47.74,1:03:49.77,Default,,0,0,0,,这就是我尝试求解的方程 Dialogue: 0,1:03:51.22,1:03:52.43,Default,,0,0,0,,我们来试试看 Dialogue: 0,1:03:53.96,1:03:55.66,Default,,0,0,0,,首先我需要写下 Dialogue: 0,1:03:56.64,1:03:59.00,Default,,0,0,0,,跟T相对应的函数 Dialogue: 0,1:04:00.32,1:04:03.00,Default,,0,0,0,,我写下的这个T对应的函数 Dialogue: 0,1:04:04.49,1:04:06.96,Default,,0,0,0,,它的不动点就是这个方程的解 Dialogue: 0,1:04:10.76,1:04:11.28,Default,,0,0,0,,能明白吗? Dialogue: 0,1:04:12.25,1:04:14.30,Default,,0,0,0,,让我们来看下面这个过程F Dialogue: 0,1:04:16.87,1:04:18.30,Default,,0,0,0,,我说 F计算的是这样一个函数 Dialogue: 0,1:04:19.34,1:04:22.91,Default,,0,0,0,,F本身是一个参数为G的一元过程 Dialogue: 0,1:04:25.23,1:04:25.93,Default,,0,0,0,,它返回 Dialogue: 0,1:04:26.40,1:04:32.00,Default,,0,0,0,,一个参数为X和N的过程 Dialogue: 0,1:04:33.43,1:04:34.73,Default,,0,0,0,,这个过程的定义是: Dialogue: 0,1:04:36.72,1:04:40.43,Default,,0,0,0,,如果N为0 Dialogue: 0,1:04:41.72,1:04:43.20,Default,,0,0,0,,那么结果就是1 Dialogue: 0,1:04:45.34,1:04:46.17,Default,,0,0,0,,否则的话 Dialogue: 0,1:04:49.90,1:05:01.40,Default,,0,0,0,,结果就是(* X (G X (- N 1))) Dialogue: 0,1:05:03.37,1:05:07.80,Default,,0,0,0,,(闭合括号中) Dialogue: 0,1:05:08.94,1:05:09.40,Default,,0,0,0,,没问题吧 Dialogue: 0,1:05:12.30,1:05:14.62,Default,,0,0,0,,这里 F是一个过程 Dialogue: 0,1:05:15.05,1:05:17.79,Default,,0,0,0,,如果我能解出这个方程 Dialogue: 0,1:05:19.04,1:05:22.04,Default,,0,0,0,,如果我找到了一个良好的指数过程 Dialogue: 0,1:05:23.42,1:05:26.32,Default,,0,0,0,,我把这个F应用到那个过程上 Dialogue: 0,1:05:27.60,1:05:31.24,Default,,0,0,0,,那么返回的应该也是一个良好的指数过程 Dialogue: 0,1:05:37.46,1:05:38.57,Default,,0,0,0,,这是为什么呢? Dialogue: 0,1:05:39.42,1:05:40.88,Default,,0,0,0,,这是因为 Dialogue: 0,1:05:42.36,1:05:44.64,Default,,0,0,0,,F假设G是一个良好的指数过程 Dialogue: 0,1:05:45.63,1:05:47.58,Default,,0,0,0,,那么这里就会返回 Dialogue: 0,1:05:47.84,1:05:49.68,Default,,0,0,0,,一个参数为X和N的过程 Dialogue: 0,1:05:50.49,1:05:51.52,Default,,0,0,0,,其中如果N=0 Dialogue: 0,1:05:51.55,1:05:52.41,Default,,0,0,0,,结果就是1 Dialogue: 0,1:05:52.44,1:05:54.16,Default,,0,0,0,,这是非常符合定义的 Dialogue: 0,1:05:54.64,1:05:57.05,Default,,0,0,0,,否则 就返回X乘以 Dialogue: 0,1:05:57.26,1:05:59.26,Default,,0,0,0,,用给定的指数过程G Dialogue: 0,1:06:00.17,1:06:02.44,Default,,0,0,0,,计算(G X (- N 1)) Dialogue: 0,1:06:03.47,1:06:04.78,Default,,0,0,0,,因此如果G能够 Dialogue: 0,1:06:04.81,1:06:06.30,Default,,0,0,0,,正确计算X^(N-1) Dialogue: 0,1:06:07.87,1:06:11.28,Default,,0,0,0,,那么这个表达式就能正确计算X^N Dialogue: 0,1:06:12.17,1:06:14.41,Default,,0,0,0,,所以整个就会是一个正确的求指数过程 Dialogue: 0,1:06:17.50,1:06:19.82,Default,,0,0,0,,因此 我在这里真正想指出的是 Dialogue: 0,1:06:21.02,1:06:32.44,Default,,0,0,0,,过程EXPT是函数F的不动点 Dialogue: 0,1:06:36.99,1:06:38.35,Default,,0,0,0,,现在我们的问题在于 Dialogue: 0,1:06:38.35,1:06:39.68,Default,,0,0,0,,不动点可能不止一个 Dialogue: 0,1:06:40.06,1:06:42.19,Default,,0,0,0,,也可能没有不动点 Dialogue: 0,1:06:43.27,1:06:44.81,Default,,0,0,0,,所以我们必须求出不动点 Dialogue: 0,1:06:48.22,1:06:49.37,Default,,0,0,0,,需要来解这个方程 Dialogue: 0,1:06:52.16,1:06:54.28,Default,,0,0,0,,求不动点的方法有很多种 Dialogue: 0,1:06:55.58,1:06:57.08,Default,,0,0,0,,本门课程的第一节课 Dialogue: 0,1:06:57.24,1:07:01.16,Default,,0,0,0,,我们就用余弦函数做了演示 Dialogue: 0,1:07:02.73,1:07:07.69,Default,,0,0,0,,先把你的计算器调成弧度制 Dialogue: 0,1:07:07.85,1:07:10.51,Default,,0,0,0,,然后一直按COS键 Dialogue: 0,1:07:11.84,1:07:15.45,Default,,0,0,0,,最后数字会稳定在0.73、0.74左右 Dialogue: 0,1:07:16.09,1:07:17.18,Default,,0,0,0,,我记不清是哪个了 Dialogue: 0,1:07:20.57,1:07:22.64,Default,,0,0,0,,通过迭代一个过程 Dialogue: 0,1:07:22.81,1:07:24.40,Default,,0,0,0,,我们不断迭代 Dialogue: 0,1:07:25.60,1:07:27.16,Default,,0,0,0,,想要寻找不动点的函数 Dialogue: 0,1:07:27.50,1:07:31.13,Default,,0,0,0,,有时候 它就会收敛在一个点上 Dialogue: 0,1:07:31.87,1:07:33.08,Default,,0,0,0,,这就是不动点 Dialogue: 0,1:07:33.77,1:07:35.44,Default,,0,0,0,,碰碰运气 Dialogue: 0,1:07:36.44,1:07:37.21,Default,,0,0,0,,来试试这种方法 Dialogue: 0,1:07:39.91,1:07:46.28,Default,,0,0,0,,来看这张幻灯片 Dialogue: 0,1:07:48.03,1:07:51.71,Default,,0,0,0,,考虑这么一连串的过程 Dialogue: 0,1:07:56.40,1:07:57.79,Default,,0,0,0,,这里的E0 Dialogue: 0,1:07:59.24,1:08:01.63,Default,,0,0,0,,这个E0过程什么也不做 Dialogue: 0,1:08:02.89,1:08:05.10,Default,,0,0,0,,无论你给它传递什么参数 Dialogue: 0,1:08:05.10,1:08:06.24,Default,,0,0,0,,它都会产生ERROR Dialogue: 0,1:08:07.78,1:08:09.03,Default,,0,0,0,,基本上没什么用 Dialogue: 0,1:08:14.48,1:08:20.08,Default,,0,0,0,,然而 我可以做近似 Dialogue: 0,1:08:20.08,1:08:23.93,Default,,0,0,0,,让我们考虑下 指数过程的最差近似 Dialogue: 0,1:08:24.73,1:08:25.53,Default,,0,0,0,,因为它什么也做不了 Dialogue: 0,1:08:26.99,1:08:29.68,Default,,0,0,0,,假设我调用F Dialogue: 0,1:08:30.35,1:08:33.26,Default,,0,0,0,,用E0去代换G Dialogue: 0,1:08:33.79,1:08:36.30,Default,,0,0,0,,这里 G就被代换为了E0 Dialogue: 0,1:08:37.38,1:08:39.77,Default,,0,0,0,,所以在这里就是E0 Dialogue: 0,1:08:40.84,1:08:42.35,Default,,0,0,0,,那么E1又成了什么呢? Dialogue: 0,1:08:43.63,1:08:46.03,Default,,0,0,0,,如果用E1来计算X^0 Dialogue: 0,1:08:46.67,1:08:48.78,Default,,0,0,0,,没什么问题 Dialogue: 0,1:08:49.60,1:08:50.75,Default,,0,0,0,,它返回的结果是正确的 Dialogue: 0,1:08:51.05,1:08:52.35,Default,,0,0,0,,任何数的0次幂都是1 Dialogue: 0,1:08:52.68,1:08:54.25,Default,,0,0,0,,然而计算其它次幂就会出错 Dialogue: 0,1:08:57.39,1:09:01.56,Default,,0,0,0,,现在如果我用E1来调用F Dialogue: 0,1:09:02.30,1:09:07.40,Default,,0,0,0,,把G代换为E1 会发生什么? Dialogue: 0,1:09:09.58,1:09:11.18,Default,,0,0,0,,这样的话 Dialogue: 0,1:09:12.01,1:09:15.02,Default,,0,0,0,,我就会得到这个二元过程 Dialogue: 0,1:09:15.67,1:09:16.84,Default,,0,0,0,,想一想 E1这个过程 Dialogue: 0,1:09:16.96,1:09:19.66,Default,,0,0,0,,只能正确计算X^0 Dialogue: 0,1:09:21.47,1:09:23.37,Default,,0,0,0,,它只能计算0次幂 Dialogue: 0,1:09:24.20,1:09:25.00,Default,,0,0,0,,所以这里 Dialogue: 0,1:09:25.52,1:09:27.28,Default,,0,0,0,,如果N为0 结果就是1 Dialogue: 0,1:09:27.29,1:09:28.67,Default,,0,0,0,,E2的这部分也正确 Dialogue: 0,1:09:29.52,1:09:32.01,Default,,0,0,0,,然而 我可以通过把0次幂乘以X Dialogue: 0,1:09:32.51,1:09:35.26,Default,,0,0,0,,来计算1次幂 Dialogue: 0,1:09:35.97,1:09:39.67,Default,,0,0,0,,所以E2可以正确计算0次幂和1次幂 Dialogue: 0,1:09:41.60,1:09:41.92,Default,,0,0,0,,对吧? Dialogue: 0,1:09:43.71,1:09:46.67,Default,,0,0,0,,E3的构造过程和E2是类似的 Dialogue: 0,1:09:47.89,1:09:50.24,Default,,0,0,0,,当然 E3具有同样的参数 Dialogue: 0,1:09:50.32,1:09:53.37,Default,,0,0,0,,能够正确计算0、1、2次幂 Dialogue: 0,1:09:55.12,1:09:55.40,Default,,0,0,0,,对吧? Dialogue: 0,1:09:56.09,1:09:59.08,Default,,0,0,0,,因此我就不加证明地告诉你结论 Dialogue: 0,1:09:59.66,1:10:01.72,Default,,0,0,0,,因为这个证明过程太难了 Dialogue: 0,1:10:02.52,1:10:03.60,Default,,0,0,0,,这种事情 Dialogue: 0,1:10:03.63,1:10:06.36,Default,,0,0,0,,是由人们所谓“指称语义学家”完成的 Dialogue: 0,1:10:06.59,1:10:07.64,Default,,0,0,0,,这个伟大的想法 Dialogue: 0,1:10:07.87,1:10:10.59,Default,,0,0,0,,应该是由Scott和Strachey提出的 Dialogue: 0,1:10:11.64,1:10:16.32,Default,,0,0,0,,他们是非常著名的数学家 Dialogue: 0,1:10:16.86,1:10:21.21,Default,,0,0,0,,他们发明了这些程序的解释方式 Dialogue: 0,1:10:22.36,1:10:24.00,Default,,0,0,0,,就是我刚才讲的那些 Dialogue: 0,1:10:24.24,1:10:26.17,Default,,0,0,0,,他们通过拓扑学的方法证明了 Dialogue: 0,1:10:27.04,1:10:29.32,Default,,0,0,0,,在我们刚才那种情况下 Dialogue: 0,1:10:29.82,1:10:31.26,Default,,0,0,0,,不动点是存在的 Dialogue: 0,1:10:32.22,1:10:33.24,Default,,0,0,0,,这个结论就是: Dialogue: 0,1:10:33.40,1:10:44.24,Default,,0,0,0,,当N趋近于无穷时 EXPT是E(N)的极限 Dialogue: 0,1:10:45.52,1:10:47.90,Default,,0,0,0,,我们是通过下面这种方式来构造这个极限的 Dialogue: 0,1:10:50.52,1:10:55.66,Default,,0,0,0,,EXPT=(F (F (F (F .... Dialogue: 0,1:10:57.61,1:11:00.19,Default,,0,0,0,,(F 丄) Dialogue: 0,1:11:01.12,1:11:02.46,Default,,0,0,0,,它是什么都无所谓 Dialogue: 0,1:11:03.18,1:11:05.00,Default,,0,0,0,,因为它总会生成一个错误 Dialogue: 0,1:11:07.45,1:11:08.41,Default,,0,0,0,,(闭合括号中) Dialogue: 0,1:11:12.89,1:11:14.48,Default,,0,0,0,,这是F无穷嵌套调用 Dialogue: 0,1:11:16.38,1:11:17.71,Default,,0,0,0,,现在我们的问题 Dialogue: 0,1:11:18.22,1:11:19.76,Default,,0,0,0,,又变成了如何构造出无穷调用 Dialogue: 0,1:11:22.59,1:11:24.08,Default,,0,0,0,,我们需要它们 Dialogue: 0,1:11:24.92,1:11:26.25,Default,,0,0,0,,我怎样才能把F Dialogue: 0,1:11:26.56,1:11:27.80,Default,,0,0,0,,嵌套无穷层呢? Dialogue: 0,1:11:28.98,1:11:30.12,Default,,0,0,0,,我得把它构造出来 Dialogue: 0,1:11:32.38,1:11:32.93,Default,,0,0,0,,好吧 我不知道 Dialogue: 0,1:11:32.93,1:11:34.32,Default,,0,0,0,,到底怎么样构建一个无穷循环呢? Dialogue: 0,1:11:34.81,1:11:36.32,Default,,0,0,0,,我们先来看个非常简单的无穷循环 Dialogue: 0,1:11:36.57,1:11:38.34,Default,,0,0,0,,能想到的最简单的无穷循环 Dialogue: 0,1:11:43.55,1:11:47.55,Default,,0,0,0,,把这样一个参数为X的函数过程 Dialogue: 0,1:11:48.00,1:11:49.79,Default,,0,0,0,,过程体是(X X) Dialogue: 0,1:11:53.55,1:11:53.92,Default,,0,0,0,,看到了吧? Dialogue: 0,1:11:55.05,1:11:58.41,Default,,0,0,0,,应用在一个参数为X过程上 Dialogue: 0,1:11:59.36,1:12:01.05,Default,,0,0,0,,后者的过程体也是(X X) Dialogue: 0,1:12:04.83,1:12:06.00,Default,,0,0,0,,这就形成了一个无穷循环 Dialogue: 0,1:12:07.21,1:12:09.31,Default,,0,0,0,,这个循环之所以是无穷的 Dialogue: 0,1:12:09.98,1:12:11.31,Default,,0,0,0,,是因为 Dialogue: 0,1:12:11.52,1:12:13.69,Default,,0,0,0,,我用实际参数代换掉 Dialogue: 0,1:12:14.22,1:12:16.59,Default,,0,0,0,,过程体的形式参数 Dialogue: 0,1:12:18.85,1:12:21.60,Default,,0,0,0,,这样做了以后 这里的每个X Dialogue: 0,1:12:22.40,1:12:23.76,Default,,0,0,0,,都被代换为了这个 Dialogue: 0,1:12:24.36,1:12:26.96,Default,,0,0,0,,相当于把最初的表达式又复制了一遍 Dialogue: 0,1:12:28.35,1:12:29.37,Default,,0,0,0,,这就是最简单的无穷循环 Dialogue: 0,1:12:35.44,1:12:39.29,Default,,0,0,0,,现在 我要介绍一个特殊的运算符 Dialogue: 0,1:12:40.38,1:12:43.09,Default,,0,0,0,,它是通过对这个无穷循环稍作修改而来 Dialogue: 0,1:12:46.96,1:12:47.92,Default,,0,0,0,,我把它记作“Y” Dialogue: 0,1:12:50.89,1:12:55.82,Default,,0,0,0,,它的全称是:Curry的矛盾Y组合子 Dialogue: 0,1:12:56.62,1:12:58.99,Default,,0,0,0,,这是用二十世纪三十年代的逻辑学家 Dialogue: 0,1:12:59.34,1:13:01.85,Default,,0,0,0,,Curry的名字来命名的 Dialogue: 0,1:13:04.48,1:13:06.88,Default,,0,0,0,,Y组合子是一个参数为f的过程 Dialogue: 0,1:13:08.17,1:13:09.33,Default,,0,0,0,,它的过程体是什么呢? Dialogue: 0,1:13:09.33,1:13:11.20,Default,,0,0,0,,它的内部是某种无穷循环 Dialogue: 0,1:13:11.98,1:13:15.47,Default,,0,0,0,,是一个参数为x的过程 Dialogue: 0,1:13:15.95,1:13:18.80,Default,,0,0,0,,它调用(f (x x)) Dialogue: 0,1:13:21.63,1:13:24.75,Default,,0,0,0,,这个过程应用在一个参数为X的过程上 Dialogue: 0,1:13:25.10,1:13:27.34,Default,,0,0,0,,后者调用(f (x x)) Dialogue: 0,1:13:32.30,1:13:33.13,Default,,0,0,0,,这个是怎么运作的? Dialogue: 0,1:13:34.80,1:13:36.06,Default,,0,0,0,,假设执行(Y F) Dialogue: 0,1:13:41.31,1:13:42.57,Default,,0,0,0,,这非常简单 Dialogue: 0,1:13:43.15,1:13:44.62,Default,,0,0,0,,这里大写的F跟那边的是同一个 Dialogue: 0,1:13:46.91,1:13:48.16,Default,,0,0,0,,在这里 很简单 Dialogue: 0,1:13:48.30,1:13:49.92,Default,,0,0,0,,我把F代换到这里来 Dialogue: 0,1:13:55.32,1:13:57.07,Default,,0,0,0,,基本上 我就会得到 Dialogue: 0,1:13:58.75,1:14:00.84,Default,,0,0,0,,因为我待会儿要用这个表达式 Dialogue: 0,1:14:01.45,1:14:02.80,Default,,0,0,0,,代换这里的x Dialogue: 0,1:14:04.17,1:14:05.23,Default,,0,0,0,,这里就是(F Dialogue: 0,1:14:08.97,1:14:10.09,Default,,0,0,0,,我还是把这步写出来吧 Dialogue: 0,1:14:10.22,1:14:11.45,Default,,0,0,0,,这样你们就能看得更全面 Dialogue: 0,1:14:11.92,1:14:14.27,Default,,0,0,0,,我会非常小心 好吗? Dialogue: 0,1:14:15.02,1:14:18.25,Default,,0,0,0,,这里是 ((LAMBDA (x) Dialogue: 0,1:14:19.08,1:14:22.11,Default,,0,0,0,,(F (x x)) Dialogue: 0,1:14:26.88,1:14:35.55,Default,,0,0,0,,把它应用到自身 (LAMBDA (x) (F (x x))) Dialogue: 0,1:14:37.91,1:14:39.66,Default,,0,0,0,,把这个表达式代换进去 Dialogue: 0,1:14:40.06,1:14:40.91,Default,,0,0,0,,就得到 Dialogue: 0,1:14:43.13,1:14:48.35,Default,,0,0,0,,把这个代进去 得到什么呢? Dialogue: 0,1:14:48.65,1:14:54.81,Default,,0,0,0,,(F (LAMBDA (x) (F (x x))) Dialogue: 0,1:14:57.07,1:14:58.17,Default,,0,0,0,,应用到 Dialogue: 0,1:14:59.18,1:15:06.48,Default,,0,0,0,,(LAMBDA (x) (F (x x)))) Dialogue: 0,1:15:06.99,1:15:10.44,Default,,0,0,0,,(闭合括号中) Dialogue: 0,1:15:11.51,1:15:12.40,Default,,0,0,0,,哇 这又是什么? Dialogue: 0,1:15:13.42,1:15:16.35,Default,,0,0,0,,我刚才计算的这一部分 Dialogue: 0,1:15:17.13,1:15:18.56,Default,,0,0,0,,就是这里的这部分 Dialogue: 0,1:15:20.19,1:15:21.84,Default,,0,0,0,,只不过它被包在另一个F里面 Dialogue: 0,1:15:23.37,1:15:24.67,Default,,0,0,0,,因此 通过把Y应用在F上 Dialogue: 0,1:15:24.68,1:15:26.22,Default,,0,0,0,,我构造出了F的无穷嵌套 Dialogue: 0,1:15:27.85,1:15:29.45,Default,,0,0,0,,我如果让它一直这样进行下去 Dialogue: 0,1:15:29.69,1:15:31.77,Default,,0,0,0,,我在外层就会得到越来越多的F Dialogue: 0,1:15:33.17,1:15:34.80,Default,,0,0,0,,我运行一个无用的循环 Dialogue: 0,1:15:35.20,1:15:37.02,Default,,0,0,0,,但内部是无用的并不重要 Dialogue: 0,1:15:39.85,1:15:47.85,Default,,0,0,0,,因此 我们有 (Y F)=(F (Y F)) Dialogue: 0,1:15:50.33,1:15:52.14,Default,,0,0,0,,Y组合子十分神奇 Dialogue: 0,1:15:53.85,1:15:56.25,Default,,0,0,0,,如果把它应用于某个函数 Dialogue: 0,1:15:57.37,1:16:00.38,Default,,0,0,0,,它就会返回这个函数的不动点 Dialogue: 0,1:16:01.69,1:16:04.25,Default,,0,0,0,,当然是在不动点存在的前提下 Dialogue: 0,1:16:07.91,1:16:10.08,Default,,0,0,0,,这是因为 如果我把(Y F)带入F Dialogue: 0,1:16:10.12,1:16:11.12,Default,,0,0,0,,结果还是(Y F) Dialogue: 0,1:16:16.24,1:16:18.86,Default,,0,0,0,,现在我想让你们在 Dialogue: 0,1:16:19.85,1:16:22.38,Default,,0,0,0,,EVAL-APPLY解释器方面思考一下 Dialogue: 0,1:16:23.86,1:16:26.27,Default,,0,0,0,,我在这里写了一大堆递归方程组 Dialogue: 0,1:16:28.54,1:16:30.22,Default,,0,0,0,,那些联立方程组像 Dialogue: 0,1:16:30.22,1:16:31.23,Default,,0,0,0,,这些方程一样联立起来 Dialogue: 0,1:16:31.47,1:16:33.31,Default,,0,0,0,,但EXPT不是联立方程 Dialogue: 0,1:16:33.31,1:16:35.79,Default,,0,0,0,,只是一个需要我赋义的变量 Dialogue: 0,1:16:38.15,1:16:40.76,Default,,0,0,0,,而Lisp则是某个过程的不动点 Dialogue: 0,1:16:40.81,1:16:42.57,Default,,0,0,0,,对这个过程来说 如果我知道Lisp的定义 Dialogue: 0,1:16:42.59,1:16:46.51,Default,,0,0,0,,然后在递归方程等号的右边 Dialogue: 0,1:16:46.59,1:16:49.79,Default,,0,0,0,,用它来代换EVAL、APPLY等变量 Dialogue: 0,1:16:50.94,1:16:53.96,Default,,0,0,0,,如果它是一个良好定义的Lisp的话 Dialogue: 0,1:16:54.36,1:16:56.30,Default,,0,0,0,,那么递归方程等号左边 也是一个良好定义的Lisp Dialogue: 0,1:16:58.22,1:16:59.82,Default,,0,0,0,,这样 那个定义就讲得通了 Dialogue: 0,1:17:02.42,1:17:05.41,Default,,0,0,0,,不过是否有解却不太明显 Dialogue: 0,1:17:05.69,1:17:06.75,Default,,0,0,0,,我也说不清 Dialogue: 0,1:17:07.74,1:17:09.21,Default,,0,0,0,,现在我要介绍的论证 Dialogue: 0,1:17:09.26,1:17:10.27,Default,,0,0,0,,相当危险 Dialogue: 0,1:17:10.66,1:17:11.64,Default,,0,0,0,,具体看这里 Dialogue: 0,1:17:13.05,1:17:14.61,Default,,0,0,0,,这些是关于极限的论证 Dialogue: 0,1:17:14.61,1:17:15.39,Default,,0,0,0,,我们要讨论的极限 Dialogue: 0,1:17:15.45,1:17:17.68,Default,,0,0,0,,是微积分或者拓扑学的概念 Dialogue: 0,1:17:17.87,1:17:20.03,Default,,0,0,0,,或者说是类似的 数学分析中的概念 Dialogue: 0,1:17:20.76,1:17:23.38,Default,,0,0,0,,这个论证是你们都承认的 Dialogue: 0,1:17:23.38,1:17:25.29,Default,,0,0,0,,我想让你们意识到 Dialogue: 0,1:17:25.42,1:17:27.66,Default,,0,0,0,,我可以把你们耍得团团转 Dialogue: 0,1:17:28.86,1:17:30.48,Default,,0,0,0,,准备好了吗? 这是什么? Dialogue: 0,1:17:34.25,1:17:39.52,Default,,0,0,0,,u = 1 + 1/2 + 1/4 + ....... Dialogue: 0,1:17:39.74,1:17:41.32,Default,,0,0,0,,这是几何级数求和 Dialogue: 0,1:17:42.82,1:17:44.68,Default,,0,0,0,,当然 我也可以耍点小把戏 Dialogue: 0,1:17:44.82,1:17:47.57,Default,,0,0,0,,u - 1 = 1/2 + 1/4 + 1/8 ...... Dialogue: 0,1:17:51.90,1:17:54.46,Default,,0,0,0,,这里我可以 Dialogue: 0,1:17:56.09,1:17:57.93,Default,,0,0,0,,糟糕了 这里漏掉了括号 Dialogue: 0,1:17:58.92,1:18:01.45,Default,,0,0,0,,这里应该是 Dialogue: 0,1:18:01.74,1:18:03.99,Default,,0,0,0,,2(u - 1) = 1 + 1/2 + 1/4 + 1/8 ........ Dialogue: 0,1:18:07.57,1:18:08.54,Default,,0,0,0,,这里能修改一下吗? Dialogue: 0,1:18:14.01,1:18:16.43,Default,,0,0,0,,哦 可以 Dialogue: 0,1:18:18.19,1:18:18.65,Default,,0,0,0,,看到了吗? Dialogue: 0,1:18:19.52,1:18:20.64,Default,,0,0,0,,这样 我就得到 Dialogue: 0,1:18:23.53,1:18:26.64,Default,,0,0,0,,2(u - 1) = u Dialogue: 0,1:18:27.80,1:18:29.58,Default,,0,0,0,,因此我们推断出 u=2 Dialogue: 0,1:18:30.30,1:18:31.37,Default,,0,0,0,,这是正确的 Dialogue: 0,1:18:31.96,1:18:33.32,Default,,0,0,0,,这个推理过程没有问题 Dialogue: 0,1:18:34.04,1:18:37.55,Default,,0,0,0,,但如果我要是做点别的什么呢? Dialogue: 0,1:18:38.54,1:18:39.48,Default,,0,0,0,,假设我要求和的式子 Dialogue: 0,1:18:39.50,1:18:41.20,Default,,0,0,0,,明显没有和 Dialogue: 0,1:18:41.56,1:18:46.99,Default,,0,0,0,,v = 1 + 2 + 4 + ........ Dialogue: 0,1:18:47.39,1:18:51.39,Default,,0,0,0,,v - 1 = 2 + 4 + 8 + ...... Dialogue: 0,1:18:52.27,1:18:56.03,Default,,0,0,0,,(v - 1)/2 = v Dialogue: 0,1:18:57.41,1:19:00.54,Default,,0,0,0,,这里我就可以推断出 Dialogue: 0,1:19:01.37,1:19:02.91,Default,,0,0,0,,显然这里又写错了 Dialogue: 0,1:19:03.07,1:19:04.51,Default,,0,0,0,,应该是 v = -1 Dialogue: 0,1:19:12.45,1:19:13.82,Default,,0,0,0,,这里应该是-1 Dialogue: 0,1:19:15.28,1:19:16.91,Default,,0,0,0,,这个结论明显是错误的 Dialogue: 0,1:19:22.00,1:19:23.47,Default,,0,0,0,,当你处理极限的时候 Dialogue: 0,1:19:24.22,1:19:27.85,Default,,0,0,0,,在某种方式下可行的论证 Dialogue: 0,1:19:29.42,1:19:30.75,Default,,0,0,0,,在其它情况下可能又不行了 Dialogue: 0,1:19:30.75,1:19:31.69,Default,,0,0,0,,要多加注意 Dialogue: 0,1:19:32.24,1:19:33.87,Default,,0,0,0,,参数必须具有良好的形式 Dialogue: 0,1:19:36.14,1:19:39.23,Default,,0,0,0,,但我不清楚 通常来说 Dialogue: 0,1:19:39.85,1:19:41.93,Default,,0,0,0,,像这样的论证有什么样的要求 Dialogue: 0,1:19:43.27,1:19:45.24,Default,,0,0,0,,我们要研习一大堆拓扑学文献来寻找答案 Dialogue: 0,1:19:46.27,1:19:48.64,Default,,0,0,0,,但是至少你们现在理解了 Dialogue: 0,1:19:49.10,1:19:51.13,Default,,0,0,0,,为什么我们在黑板上写的这些东西 Dialogue: 0,1:19:51.15,1:19:52.76,Default,,0,0,0,,是有一定语义的 Dialogue: 0,1:19:53.66,1:19:55.61,Default,,0,0,0,,你们也理解了它的语义 Dialogue: 0,1:19:56.48,1:19:58.35,Default,,0,0,0,,我想现在是时候 Dialogue: 0,1:19:59.07,1:20:03.84,Default,,0,0,0,,祝贺你们成为 Dialogue: 0,1:20:04.28,1:20:05.55,Default,,0,0,0,,神圣的递归秩序中的 Dialogue: 0,1:20:05.56,1:20:07.04,Default,,0,0,0,,一名LAMBDA演算黑客了 Dialogue: 0,1:20:08.84,1:20:10.17,Default,,0,0,0,,这是我们的徽章 Dialogue: 0,1:20:10.82,1:20:12.54,Default,,0,0,0,,因为你已经理解了 Dialogue: 0,1:20:13.40,1:20:15.20,Default,,0,0,0,,它上面的那句话 Dialogue: 0,1:20:16.89,1:20:18.41,Default,,0,0,0,,(Y F) = (F (Y F)) Dialogue: 0,1:20:21.04,1:20:21.66,Default,,0,0,0,,这节课讲完了 Dialogue: 0,1:20:21.85,1:20:22.75,Default,,0,0,0,,有什么问题吗? Dialogue: 0,1:20:24.71,1:20:25.15,Default,,0,0,0,,Lev 请说 Dialogue: 0,1:20:25.37,1:20:27.39,Default,,0,0,0,,学生:目前的状况来看 Dialogue: 0,1:20:27.40,1:20:30.22,Default,,0,0,0,,正如你指出的那样 我们不再需要DEFINE Dialogue: 0,1:20:30.24,1:20:32.70,Default,,0,0,0,,不需要先存储一个值 以后再用 Dialogue: 0,1:20:32.99,1:20:33.32,Default,,0,0,0,,教授:对 Dialogue: 0,1:20:33.50,1:20:36.44,Default,,0,0,0,,学生:DEFINE在语言中好像有一些副作用 Dialogue: 0,1:20:36.49,1:20:38.52,Default,,0,0,0,,(听不清)并且依赖于时序 Dialogue: 0,1:20:39.30,1:20:42.06,Default,,0,0,0,,不用DEFINE 是否消除了副作用? Dialogue: 0,1:20:42.28,1:20:44.68,Default,,0,0,0,,教授: 实际上 Dialogue: 0,1:20:44.88,1:20:46.44,Default,,0,0,0,,解释器并不是像这样实现的 Dialogue: 0,1:20:47.52,1:20:47.93,Default,,0,0,0,,明白了吧? Dialogue: 0,1:20:48.92,1:20:53.15,Default,,0,0,0,,在实际的实现中 DEFINE这个运算 Dialogue: 0,1:20:53.18,1:20:55.53,Default,,0,0,0,,确实修改了环境 Dialogue: 0,1:20:57.95,1:21:02.33,Default,,0,0,0,,改变了执行DEFINE的那个框架 Dialogue: 0,1:21:03.69,1:21:06.51,Default,,0,0,0,,这样做是有很多原因的 Dialogue: 0,1:21:07.39,1:21:08.64,Default,,0,0,0,,其中之一就是 Dialogue: 0,1:21:08.67,1:21:10.09,Default,,0,0,0,,方便交互式系统 Dialogue: 0,1:21:11.34,1:21:14.12,Default,,0,0,0,,就是说 如果你构造了一个系统 Dialogue: 0,1:21:14.35,1:21:15.20,Default,,0,0,0,,而且你知道 Dialogue: 0,1:21:15.42,1:21:16.60,Default,,0,0,0,,你不打算进行调试 Dialogue: 0,1:21:16.60,1:21:17.55,Default,,0,0,0,,或之类的事儿 Dialogue: 0,1:21:17.84,1:21:20.72,Default,,0,0,0,,你想立马知道所有的东西 Dialogue: 0,1:21:20.75,1:21:21.24,Default,,0,0,0,,你想知道的是 Dialogue: 0,1:21:21.26,1:21:23.12,Default,,0,0,0,,方程组的最终解是什么? Dialogue: 0,1:21:24.09,1:21:25.26,Default,,0,0,0,,然后系统返回你相应的值 Dialogue: 0,1:21:25.79,1:21:27.45,Default,,0,0,0,,但如果想要让系统变成交互式的 Dialogue: 0,1:21:27.45,1:21:28.75,Default,,0,0,0,,这样你可以在不影响其它部分的情况下 Dialogue: 0,1:21:28.76,1:21:31.68,Default,,0,0,0,,增量式地修改某一部分 Dialogue: 0,1:21:32.33,1:21:35.04,Default,,0,0,0,,没有DEFINE的话 就不能这么做了 Dialogue: 0,1:21:40.99,1:21:41.24,Default,,0,0,0,,你说 Dialogue: 0,1:21:42.30,1:21:44.25,Default,,0,0,0,,学生:就是那张“危险”的幻灯片 Dialogue: 0,1:21:44.65,1:21:47.13,Default,,0,0,0,,好像你举的两个例子 Dialogue: 0,1:21:47.16,1:21:49.07,Default,,0,0,0,,与其收敛与否有关系? Dialogue: 0,1:21:49.18,1:21:49.56,Default,,0,0,0,,教授:是的 Dialogue: 0,1:21:50.30,1:21:52.62,Default,,0,0,0,,学生:函数理论中是否有 Dialogue: 0,1:21:52.76,1:21:54.68,Default,,0,0,0,,像线性系统 Dialogue: 0,1:21:54.72,1:21:56.60,Default,,0,0,0,,或者非线性系统中的 Dialogue: 0,1:21:57.74,1:21:59.00,Default,,0,0,0,,那种思考方式 Dialogue: 0,1:21:59.34,1:22:01.76,Default,,0,0,0,,函数的收敛性能否先验地知道 Dialogue: 0,1:22:02.35,1:22:05.53,Default,,0,0,0,,哪些属性可能被违反? Dialogue: 0,1:22:05.79,1:22:06.57,Default,,0,0,0,,教授:我不知道 Dialogue: 0,1:22:07.68,1:22:10.09,Default,,0,0,0,,我也不知道它需要什么条件 Dialogue: 0,1:22:10.61,1:22:12.04,Default,,0,0,0,,我不知道怎么在一节课内 Dialogue: 0,1:22:12.52,1:22:14.73,Default,,0,0,0,,就给你们讲清楚 Dialogue: 0,1:22:16.91,1:22:18.48,Default,,0,0,0,,有什么条件来判别它们 Dialogue: 0,1:22:18.86,1:22:20.76,Default,,0,0,0,,是否收敛? Dialogue: 0,1:22:22.86,1:22:23.31,Default,,0,0,0,,确实 Dialogue: 0,1:22:23.32,1:22:26.35,Default,,0,0,0,,这些都是为了告诉你 基于收敛的论证 Dialogue: 0,1:22:28.24,1:22:29.47,Default,,0,0,0,,都不可靠 Dialogue: 0,1:22:29.66,1:22:31.58,Default,,0,0,0,,如果你事先不知道收敛性的话 Dialogue: 0,1:22:32.81,1:22:34.20,Default,,0,0,0,,你可能做出错误的论证 Dialogue: 0,1:22:34.44,1:22:37.31,Default,,0,0,0,,你可以先假设知道了答案 然后进行演绎 Dialogue: 0,1:22:37.39,1:22:39.93,Default,,0,0,0,,看它会不会产生什么明显的矛盾 Dialogue: 0,1:22:40.97,1:22:42.28,Default,,0,0,0,,学生:我们是否可以说 Dialogue: 0,1:22:42.33,1:22:44.88,Default,,0,0,0,,如果数学表达式F收敛 Dialogue: 0,1:22:45.00,1:22:47.36,Default,,0,0,0,,那么它的递归性质就-- Dialogue: 0,1:22:47.58,1:22:51.29,Default,,0,0,0,,教授:我认为 在技术上有一类F Dialogue: 0,1:22:52.12,1:22:54.22,Default,,0,0,0,,通过一些技术准则 Dialogue: 0,1:22:54.24,1:22:55.90,Default,,0,0,0,,我们可以找到这样的F Dialogue: 0,1:22:55.98,1:23:01.31,Default,,0,0,0,,当你像这样迭代地应用它们时 Dialogue: 0,1:23:01.52,1:23:02.25,Default,,0,0,0,,它一定会收敛 Dialogue: 0,1:23:03.02,1:23:06.51,Default,,0,0,0,,这类准则包括:单调、连续 Dialogue: 0,1:23:07.32,1:23:07.95,Default,,0,0,0,,我想想 Dialogue: 0,1:23:08.38,1:23:09.37,Default,,0,0,0,,我把其它的准则忘了 Dialogue: 0,1:23:09.37,1:23:11.13,Default,,0,0,0,,还有一些列像这样的 Dialogue: 0,1:23:11.68,1:23:12.99,Default,,0,0,0,,判别准则 Dialogue: 0,1:23:13.43,1:23:16.00,Default,,0,0,0,,现在的难点是 给定F然后进行推理 Dialogue: 0,1:23:16.92,1:23:17.88,Default,,0,0,0,,这是F的定义 Dialogue: 0,1:23:18.17,1:23:19.66,Default,,0,0,0,,它满足这些准则吗? Dialogue: 0,1:23:20.27,1:23:21.32,Default,,0,0,0,,这很难判断 Dialogue: 0,1:23:22.01,1:23:24.00,Default,,0,0,0,,那些准则都很简单得可以写下来 Dialogue: 0,1:23:24.58,1:23:26.32,Default,,0,0,0,,你可以看Joe Stoy写的一本书 Dialogue: 0,1:23:26.67,1:23:29.58,Default,,0,0,0,,那本书非常不错 Dialogue: 0,1:23:32.22,1:23:34.06,Default,,0,0,0,,叫做The Scott-Strachey Dialogue: 0,1:23:34.49,1:23:38.46,Default,,0,0,0,,《指称语义:基于Scott-Strachey方法》 Dialogue: 0,1:23:39.55,1:23:40.76,Default,,0,0,0,,作者是Joe Stoy Dialogue: 0,1:23:40.80,1:23:41.76,Default,,0,0,0,,由MIT出版社出版 Dialogue: 0,1:23:48.06,1:23:49.88,Default,,0,0,0,,他把这一方面讲得非常详细 Dialogue: 0,1:23:50.20,1:23:51.37,Default,,0,0,0,,绝对会让你吓一大跳 Dialogue: 0,1:23:55.05,1:23:56.19,Default,,0,0,0,,但是这本书仍然值得一读 Dialogue: 0,1:24:09.15,1:24:10.08,Default,,0,0,0,,好吧 谢谢大家 Dialogue: 0,1:24:11.49,1:24:12.99,Default,,0,0,0,,这节课到此为止 Dialogue: 0,1:24:14.17,1:24:34.60,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:24:14.17,1:24:34.49,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec7a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 621 Active Line: 629 Video Position: 66176 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.03,0:00:01.28,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:01.39,0:00:08.09,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:01.39,0:00:08.09,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N张大伟 Dialogue: 0,0:00:01.39,0:00:08.09,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:01.39,0:00:08.09,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:01.39,0:00:08.09,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:08.94,0:00:12.59,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 I Dialogue: 0,0:00:15.79,0:00:17.32,Default,,0,0,0,,教授:今天我们将学习一些 Dialogue: 0,0:00:17.52,0:00:18.41,Default,,0,0,0,,非同一般的东西 Dialogue: 0,0:00:19.20,0:00:21.88,Default,,0,0,0,,我们将对计算机程序 Dialogue: 0,0:00:22.59,0:00:25.21,Default,,0,0,0,,有更深层次的理解 Dialogue: 0,0:00:26.80,0:00:29.12,Default,,0,0,0,,目前为止 我们一直把程序看作 Dialogue: 0,0:00:29.26,0:00:32.09,Default,,0,0,0,,对机器的描述 Dialogue: 0,0:00:32.72,0:00:37.21,Default,,0,0,0,,举个例子 在这个幻灯片上 Dialogue: 0,0:00:37.93,0:00:41.77,Default,,0,0,0,,我们可以看到一个计算阶乘的程序 Dialogue: 0,0:00:42.80,0:00:47.31,Default,,0,0,0,,当然 你可以认为这些字符串描述了 Dialogue: 0,0:00:47.66,0:00:51.98,Default,,0,0,0,,这个线路图所表示的无穷机器 Dialogue: 0,0:00:52.49,0:00:54.80,Default,,0,0,0,,我们可以稍稍地看下 它描述的是什么 Dialogue: 0,0:00:55.13,0:00:58.20,Default,,0,0,0,,这种紧凑的记法 描述的是: Dialogue: 0,0:00:58.54,0:01:00.17,Default,,0,0,0,,如果N是0 结果就是1 Dialogue: 0,0:01:00.17,0:01:02.00,Default,,0,0,0,,N是从这里进入机器的 Dialogue: 0,0:01:02.33,0:01:03.52,Default,,0,0,0,,如果它是0的话 Dialogue: 0,0:01:03.74,0:01:05.20,Default,,0,0,0,,那么我就控制这个开关 Dialogue: 0,0:01:05.47,0:01:08.20,Default,,0,0,0,,把它掰到输出为1的那一端 Dialogue: 0,0:01:09.34,0:01:10.08,Default,,0,0,0,,否则的话 Dialogue: 0,0:01:10.38,0:01:12.83,Default,,0,0,0,,就是(* N (FACT (- N 1))) Dialogue: 0,0:01:12.97,0:01:15.13,Default,,0,0,0,,我先计算(FACT (- N 1)) Dialogue: 0,0:01:15.29,0:01:16.68,Default,,0,0,0,,再把结果乘以N Dialogue: 0,0:01:16.84,0:01:18.91,Default,,0,0,0,,这样如果N不为0的话 Dialogue: 0,0:01:18.91,0:01:20.60,Default,,0,0,0,,这个开关就会输出这里的结果 Dialogue: 0,0:01:21.90,0:01:22.32,Default,,0,0,0,,当然了 Dialogue: 0,0:01:22.36,0:01:25.13,Default,,0,0,0,,这个机器可能有无穷多个部件 Dialogue: 0,0:01:25.48,0:01:28.12,Default,,0,0,0,,因为FACT内部又调用了FACT Dialogue: 0,0:01:28.43,0:01:30.17,Default,,0,0,0,,因此我们不知道调用栈有多深 Dialogue: 0,0:01:31.07,0:01:33.55,Default,,0,0,0,,但到目前为止 Dialogue: 0,0:01:34.22,0:01:37.69,Default,,0,0,0,,代码对我们来说就是这样的东西了 Dialogue: 0,0:01:38.31,0:01:40.59,Default,,0,0,0,,你可以认为代码是用字符串来描述 Dialogue: 0,0:01:41.28,0:01:44.16,Default,,0,0,0,,某种用其它方式描画的线路图 Dialogue: 0,0:01:44.90,0:01:46.60,Default,,0,0,0,,事实上 很多人都向我提议 Dialogue: 0,0:01:46.84,0:01:49.04,Default,,0,0,0,,说程序设计语言应该像这个一样 是图像化的 Dialogue: 0,0:01:49.49,0:01:51.80,Default,,0,0,0,,不过我不认为用图形表示会有很多优势 Dialogue: 0,0:01:52.00,0:01:53.79,Default,,0,0,0,,当然 最主要的劣势就是 Dialogue: 0,0:01:53.80,0:01:55.63,Default,,0,0,0,,它需要占用很大的平面空间 Dialogue: 0,0:01:55.96,0:01:59.95,Default,,0,0,0,,所以展示和修改起来就非常麻烦 Dialogue: 0,0:02:01.34,0:02:02.16,Default,,0,0,0,,但是不管怎样 Dialogue: 0,0:02:03.58,0:02:05.15,Default,,0,0,0,,在计算的世界中 Dialogue: 0,0:02:05.18,0:02:07.05,Default,,0,0,0,,还有一个非常重要的东西 Dialogue: 0,0:02:07.64,0:02:10.64,Default,,0,0,0,,也就是所谓的“通用机器” Dialogue: 0,0:02:10.73,0:02:15.24,Default,,0,0,0,,我们再来看第二张幻灯片 Dialogue: 0,0:02:16.04,0:02:17.18,Default,,0,0,0,,我们看到的就是 Dialogue: 0,0:02:18.14,0:02:19.88,Default,,0,0,0,,名为EVAL的特殊机器 Dialogue: 0,0:02:21.26,0:02:22.86,Default,,0,0,0,,这个叫做EVAL的机器 Dialogue: 0,0:02:22.88,0:02:24.24,Default,,0,0,0,,也就是我今天要讲解的 Dialogue: 0,0:02:25.82,0:02:26.67,Default,,0,0,0,,它非常简单 Dialogue: 0,0:02:27.78,0:02:30.80,Default,,0,0,0,,最了不起的是 它简单得可以写在黑板上 Dialogue: 0,0:02:33.35,0:02:35.79,Default,,0,0,0,,然而 EVAL这个机器 Dialogue: 0,0:02:36.00,0:02:39.84,Default,,0,0,0,,是以其它机器的描述作为输入的 Dialogue: 0,0:02:40.45,0:02:42.12,Default,,0,0,0,,它可以接收一个 Dialogue: 0,0:02:42.40,0:02:45.58,Default,,0,0,0,,阶乘机器的线路图作为输入 Dialogue: 0,0:02:46.49,0:02:47.66,Default,,0,0,0,,这样一来 Dialogue: 0,0:02:48.49,0:02:52.57,Default,,0,0,0,,它就可以模拟那台阶乘机器 Dialogue: 0,0:02:53.13,0:02:53.79,Default,,0,0,0,,这样的话 Dialogue: 0,0:02:54.16,0:02:56.36,Default,,0,0,0,,如果输入6 就会得到720 Dialogue: 0,0:02:58.91,0:03:01.68,Default,,0,0,0,,这是一个非常了不起的机器 Dialogue: 0,0:03:02.13,0:03:03.58,Default,,0,0,0,,而最让人惊奇的是 Dialogue: 0,0:03:03.77,0:03:05.13,Default,,0,0,0,,它竟然可以写在一个黑板内 Dialogue: 0,0:03:05.59,0:03:06.65,Default,,0,0,0,,与之相反的是 Dialogue: 0,0:03:07.32,0:03:10.44,Default,,0,0,0,,我们可以想象一下模拟电子世界中的 Dialogue: 0,0:03:11.55,0:03:12.86,Default,,0,0,0,,一台非常不同的机器 Dialogue: 0,0:03:14.57,0:03:16.33,Default,,0,0,0,,这台机器呢 Dialogue: 0,0:03:16.52,0:03:18.81,Default,,0,0,0,,某种意义上 同样也是“通用机器” Dialogue: 0,0:03:19.26,0:03:23.12,Default,,0,0,0,,只要你输入一个电路图 Dialogue: 0,0:03:23.82,0:03:25.74,Default,,0,0,0,,比如这个小型的低通滤波器 Dialogue: 0,0:03:26.01,0:03:27.48,Default,,0,0,0,,单极低通滤波器之类的 Dialogue: 0,0:03:28.05,0:03:29.53,Default,,0,0,0,,你可以想像 Dialogue: 0,0:03:29.71,0:03:33.15,Default,,0,0,0,,如果我们扫描这个元件得到扫描线 Dialogue: 0,0:03:34.43,0:03:37.13,Default,,0,0,0,,得到的信号描述的就是 Dialogue: 0,0:03:37.39,0:03:40.40,Default,,0,0,0,,这个机器所模拟的 Dialogue: 0,0:03:40.78,0:03:43.39,Default,,0,0,0,,这个模拟机器EVAL是由电路构成 Dialogue: 0,0:03:43.68,0:03:45.15,Default,,0,0,0,,它可以把自己配置成一个滤波器 Dialogue: 0,0:03:45.18,0:03:48.04,Default,,0,0,0,,响应由电路图指定的频率 Dialogue: 0,0:03:49.89,0:03:51.48,Default,,0,0,0,,这种机器很难制造出来 Dialogue: 0,0:03:51.61,0:03:54.06,Default,,0,0,0,,当然 更不可能用一个黑板就把它说清楚 Dialogue: 0,0:03:55.67,0:03:57.58,Default,,0,0,0,,所以今天我们将学习一些神奇的东西 Dialogue: 0,0:03:58.43,0:04:00.81,Default,,0,0,0,,我们将在黑板上见证 Dialogue: 0,0:04:01.16,0:04:02.49,Default,,0,0,0,,通用机器 Dialogue: 0,0:04:02.79,0:04:04.41,Default,,0,0,0,,跟其它程序比起来 Dialogue: 0,0:04:04.52,0:04:05.80,Default,,0,0,0,,它真是非常简单 Dialogue: 0,0:04:06.78,0:04:08.75,Default,,0,0,0,,现在 我们已经非常接近 Dialogue: 0,0:04:09.08,0:04:10.97,Default,,0,0,0,,计算机中真正的精灵了 Dialogue: 0,0:04:11.28,0:04:14.62,Default,,0,0,0,,所以为了保持足够的尊重 Dialogue: 0,0:04:15.18,0:04:17.32,Default,,0,0,0,,我特地穿上外套 Dialogue: 0,0:04:17.52,0:04:19.29,Default,,0,0,0,,你们应该从没见我穿过 Dialogue: 0,0:04:20.47,0:04:22.73,Default,,0,0,0,,在这个盛重的场合 Dialogue: 0,0:04:23.55,0:04:26.70,Default,,0,0,0,,我还得戴上一顶合适的帽子 Dialogue: 0,0:04:28.78,0:04:31.44,Default,,0,0,0,,开讲前再给大家提个醒 Dialogue: 0,0:04:34.14,0:04:36.91,Default,,0,0,0,,那些40岁以下 Dialogue: 0,0:04:37.16,0:04:38.49,Default,,0,0,0,,以及没有孩子的人 Dialogue: 0,0:04:38.67,0:04:40.49,Default,,0,0,0,,你们可要小心了 Dialogue: 0,0:04:40.49,0:04:41.96,Default,,0,0,0,,如果真的受不了 可以选择离开 Dialogue: 0,0:04:43.34,0:04:45.56,Default,,0,0,0,,因为一会儿要发生一些 Dialogue: 0,0:04:45.72,0:04:47.13,Default,,0,0,0,,非常神秘的事情 Dialogue: 0,0:04:47.74,0:04:51.05,Default,,0,0,0,,可能使你的大脑异常混乱 Dialogue: 0,0:04:51.82,0:04:54.28,Default,,0,0,0,,好了 无论如何 Dialogue: 0,0:04:55.71,0:05:01.10,Default,,0,0,0,,我要带着你们写一个Lisp求值器 Dialogue: 0,0:05:02.51,0:05:04.28,Default,,0,0,0,,求值器并不复杂 Dialogue: 0,0:05:05.02,0:05:07.63,Default,,0,0,0,,很像我们以前见到过的程序 Dialogue: 0,0:05:08.24,0:05:09.48,Default,,0,0,0,,这也是它令人吃惊的地方 Dialogue: 0,0:05:10.86,0:05:13.10,Default,,0,0,0,,现在我开始写这个程序 Dialogue: 0,0:05:15.28,0:05:16.62,Default,,0,0,0,,我把这个程序叫做EVAL Dialogue: 0,0:05:22.90,0:05:26.24,Default,,0,0,0,,这个过程接收两个参数 Dialogue: 0,0:05:26.28,0:05:29.44,Default,,0,0,0,,表达式EXP和环境ENV Dialogue: 0,0:05:31.86,0:05:33.79,Default,,0,0,0,,跟所有实用过程一样 Dialogue: 0,0:05:34.01,0:05:35.13,Default,,0,0,0,,它是个“按情况分析”语句 Dialogue: 0,0:05:40.46,0:05:41.87,Default,,0,0,0,,但是在我开始之前 Dialogue: 0,0:05:42.52,0:05:43.90,Default,,0,0,0,,我还想你们注意一下 Dialogue: 0,0:05:44.44,0:05:46.06,Default,,0,0,0,,我将要在黑板上写的程序 Dialogue: 0,0:05:46.56,0:05:50.24,Default,,0,0,0,,非常丑陋、混乱、令人作呕 Dialogue: 0,0:05:50.94,0:05:53.16,Default,,0,0,0,,并不是一种专业的写法 Dialogue: 0,0:05:54.32,0:05:56.57,Default,,0,0,0,,它是用具体语法写就的 Dialogue: 0,0:05:57.24,0:05:58.83,Default,,0,0,0,,也就是说用了很多CAR、CDR Dialogue: 0,0:05:58.84,0:06:00.62,Default,,0,0,0,,我之前告诉过你们这样写并不好 Dialogue: 0,0:06:02.94,0:06:05.61,Default,,0,0,0,,在这里是故意这样来写的 Dialogue: 0,0:06:06.11,0:06:09.02,Default,,0,0,0,,因为我想让它尽量精简 Dialogue: 0,0:06:09.34,0:06:10.40,Default,,0,0,0,,能塞在黑板内 Dialogue: 0,0:06:10.43,0:06:11.85,Default,,0,0,0,,你们就可以看到整个代码 Dialogue: 0,0:06:12.42,0:06:14.80,Default,,0,0,0,,我就不像平时那样实用长变量名了 Dialogue: 0,0:06:15.60,0:06:17.29,Default,,0,0,0,,就用CAR、CDR 因为它们短小 Dialogue: 0,0:06:18.06,0:06:20.78,Default,,0,0,0,,这算是一种取舍 Dialogue: 0,0:06:20.89,0:06:22.81,Default,,0,0,0,,我不希望你们这样来写程序 Dialogue: 0,0:06:23.57,0:06:25.08,Default,,0,0,0,,这里单纯地想达到一种简洁的效果 Dialogue: 0,0:06:25.85,0:06:27.61,Default,,0,0,0,,因此你们读起来可能有些费力 Dialogue: 0,0:06:27.77,0:06:30.19,Default,,0,0,0,,我尽量写得清楚一些 Dialogue: 0,0:06:31.27,0:06:34.40,Default,,0,0,0,,这个解释器已经比较完整了 Dialogue: 0,0:06:34.51,0:06:36.24,Default,,0,0,0,,但是还是缺少一些功能 Dialogue: 0,0:06:36.25,0:06:38.60,Default,,0,0,0,,我就不写定义和赋值的部分了 Dialogue: 0,0:06:39.10,0:06:42.41,Default,,0,0,0,,因为它们都不是最本质的 Dialogue: 0,0:06:42.88,0:06:46.46,Default,,0,0,0,,稍后我就会解释 这是数学上的原因 Dialogue: 0,0:06:46.92,0:06:49.96,Default,,0,0,0,,当然啦 黑板也没有那么大 Dialogue: 0,0:06:51.88,0:06:53.64,Default,,0,0,0,,但是 我们怎么做呢? Dialogue: 0,0:06:53.95,0:06:55.66,Default,,0,0,0,,我们需要一个分派 Dialogue: 0,0:06:56.09,0:06:57.90,Default,,0,0,0,,它根据表达式的类型 Dialogue: 0,0:06:58.28,0:07:00.38,Default,,0,0,0,,把它们划分为几类 Dialogue: 0,0:07:01.72,0:07:03.26,Default,,0,0,0,,这就是现在要做的 Dialogue: 0,0:07:03.82,0:07:05.15,Default,,0,0,0,,我们都有哪些表达式? Dialogue: 0,0:07:05.15,0:07:06.36,Default,,0,0,0,,我们先来看几种表达式 Dialogue: 0,0:07:06.81,0:07:09.60,Default,,0,0,0,,比如说 数字“3”就是一个表达式 Dialogue: 0,0:07:10.42,0:07:11.58,Default,,0,0,0,,我想让它代表什么呢? Dialogue: 0,0:07:12.72,0:07:14.75,Default,,0,0,0,,我有很多选择 但是就现在而言 Dialogue: 0,0:07:15.05,0:07:16.20,Default,,0,0,0,,我就想让它表示数字3 Dialogue: 0,0:07:17.05,0:07:17.88,Default,,0,0,0,,这就是我要的 Dialogue: 0,0:07:18.72,0:07:19.69,Default,,0,0,0,,这个足够简单 Dialogue: 0,0:07:20.03,0:07:22.91,Default,,0,0,0,,那就意味着 如果表达式是数字 Dialogue: 0,0:07:27.29,0:07:31.68,Default,,0,0,0,,表达式本身就应该是求值结果 Dialogue: 0,0:07:35.42,0:07:36.76,Default,,0,0,0,,另外一种情况是 Dialogue: 0,0:07:36.89,0:07:38.86,Default,,0,0,0,,表达式还可能是符号 Dialogue: 0,0:07:39.39,0:07:46.75,Default,,0,0,0,,比如EXP、ENV、EVAL、NUMBER、X之类 Dialogue: 0,0:07:48.01,0:07:49.18,Default,,0,0,0,,它们意味着什么? Dialogue: 0,0:07:50.16,0:07:51.63,Default,,0,0,0,,它们是一类代表其它事物的事物 Dialogue: 0,0:07:51.63,0:07:53.23,Default,,0,0,0,,也就是我们语言中所谓的变量 Dialogue: 0,0:07:54.77,0:07:56.88,Default,,0,0,0,,因此我想要能够 比如说 Dialogue: 0,0:07:57.05,0:08:01.04,Default,,0,0,0,,对X求值 可能会得到3 Dialogue: 0,0:08:02.64,0:08:05.76,Default,,0,0,0,,又可能是CAR Dialogue: 0,0:08:07.76,0:08:09.40,Default,,0,0,0,,我希望它的值是 Dialogue: 0,0:08:09.63,0:08:11.34,Default,,0,0,0,,某种类似于过程的东西 Dialogue: 0,0:08:16.51,0:08:18.43,Default,,0,0,0,,我不需要知道它内部是什么 Dialogue: 0,0:08:18.64,0:08:21.15,Default,,0,0,0,,可能是一些机器码 或者类似的东西 Dialogue: 0,0:08:22.84,0:08:24.27,Default,,0,0,0,,到这是还是相对简单的 Dialogue: 0,0:08:24.43,0:08:26.89,Default,,0,0,0,,我想把这部分交给其他人来写 Dialogue: 0,0:08:27.80,0:08:28.89,Default,,0,0,0,,如果我们有一个符号 Dialogue: 0,0:08:30.80,0:08:32.48,Default,,0,0,0,,假如表达式是符号 Dialogue: 0,0:08:33.42,0:08:34.88,Default,,0,0,0,,那么我求值它的结果就应该是 Dialogue: 0,0:08:34.91,0:08:40.24,Default,,0,0,0,,在环境ENV中查找该表达式的值 Dialogue: 0,0:08:46.48,0:08:48.99,Default,,0,0,0,,环境是一个字典 Dialogue: 0,0:08:49.96,0:08:54.06,Default,,0,0,0,,它把符号映射成一个值 Dialogue: 0,0:08:54.28,0:08:55.16,Default,,0,0,0,,就这么简单 Dialogue: 0,0:08:56.28,0:08:57.20,Default,,0,0,0,,怎么完成的呢? Dialogue: 0,0:08:57.53,0:08:58.52,Default,,0,0,0,,稍后我们再谈这个 Dialogue: 0,0:08:59.68,0:09:00.57,Default,,0,0,0,,其实并不难 Dialogue: 0,0:09:01.67,0:09:04.28,Default,,0,0,0,,编写类似于表的数据结构非常容易 Dialogue: 0,0:09:04.84,0:09:05.74,Default,,0,0,0,,但它只是一个表 Dialogue: 0,0:09:05.77,0:09:07.56,Default,,0,0,0,,而这是存取某个表的过程 Dialogue: 0,0:09:09.55,0:09:10.81,Default,,0,0,0,,好的 接下来 Dialogue: 0,0:09:11.31,0:09:12.56,Default,,0,0,0,,另一类表达式 Dialogue: 0,0:09:12.67,0:09:15.56,Default,,0,0,0,,表达式可能是一些不是数字的常量 Dialogue: 0,0:09:16.06,0:09:17.43,Default,,0,0,0,,比如 'FOO Dialogue: 0,0:09:20.17,0:09:21.29,Default,,0,0,0,,为了方便起见 Dialogue: 0,0:09:21.31,0:09:23.36,Default,,0,0,0,,我想在语法上 Dialogue: 0,0:09:24.73,0:09:26.80,Default,,0,0,0,,把它转换成表结构 Dialogue: 0,0:09:26.84,0:09:31.52,Default,,0,0,0,,比如说是(QUOTE FOO) Dialogue: 0,0:09:33.72,0:09:37.18,Default,,0,0,0,,一个被引用起来的对象 无论它是什么 Dialogue: 0,0:09:38.35,0:09:40.83,Default,,0,0,0,,都实际上是一个缩写 Dialogue: 0,0:09:41.04,0:09:42.59,Default,,0,0,0,,这一部分并不由求值器负责 Dialogue: 0,0:09:43.21,0:09:44.46,Default,,0,0,0,,这是在其它地方完成的 Dialogue: 0,0:09:44.75,0:09:47.79,Default,,0,0,0,,左边的符号就是右边表达式的缩略形式 Dialogue: 0,0:09:48.78,0:09:50.48,Default,,0,0,0,,这样 我就可以 Dialogue: 0,0:09:50.57,0:09:53.12,Default,,0,0,0,,依据表达式的CAR部分 Dialogue: 0,0:09:53.31,0:09:55.95,Default,,0,0,0,,来判断它的类型了 Dialogue: 0,0:09:58.46,0:10:01.08,Default,,0,0,0,,因此这一部分也不会出现在求值器中 Dialogue: 0,0:10:01.65,0:10:02.68,Default,,0,0,0,,这在更早时候 Dialogue: 0,0:10:02.70,0:10:03.96,Default,,0,0,0,,比如源代码读取阶段完成 Dialogue: 0,0:10:05.54,0:10:15.04,Default,,0,0,0,,如果是引用表达式 Dialogue: 0,0:10:18.27,0:10:19.10,Default,,0,0,0,,那么求值的结果就是 Dialogue: 0,0:10:19.63,0:10:25.13,Default,,0,0,0,,我想让(QUOTE FOO)求值为自身FOO Dialogue: 0,0:10:25.14,0:10:25.95,Default,,0,0,0,,一个常量 Dialogue: 0,0:10:27.53,0:10:28.92,Default,,0,0,0,,这条代码是说 Dialogue: 0,0:10:29.08,0:10:30.73,Default,,0,0,0,,这类表达式求值为它自己 Dialogue: 0,0:10:31.79,0:10:33.66,Default,,0,0,0,,怎么才能把它取出来呢? Dialogue: 0,0:10:33.66,0:10:36.36,Default,,0,0,0,,这是列表第二个元素的第一个部分 Dialogue: 0,0:10:36.59,0:10:37.58,Default,,0,0,0,,也就是表的第二个元素 Dialogue: 0,0:10:38.49,0:10:40.32,Default,,0,0,0,,也就是CADR Dialogue: 0,0:10:41.28,0:10:42.38,Default,,0,0,0,,所以这里我就写CADR Dialogue: 0,0:10:51.08,0:10:52.35,Default,,0,0,0,,表达式还可能是什么类型呢? Dialogue: 0,0:10:52.51,0:10:53.80,Default,,0,0,0,,还有LAMBDA表达式 Dialogue: 0,0:10:55.00,0:11:03.29,Default,,0,0,0,,比如 (LAMBDA (X) (+ X Y)) Dialogue: 0,0:11:04.16,0:11:06.33,Default,,0,0,0,,我还得找到某种表示方法 Dialogue: 0,0:11:06.33,0:11:07.85,Default,,0,0,0,,LAMBDA表达式求值的结果 Dialogue: 0,0:11:08.11,0:11:09.08,Default,,0,0,0,,也就是如何表示过程 Dialogue: 0,0:11:09.60,0:11:12.62,Default,,0,0,0,,过程并不就是表达式(LAMBDA (x)) Dialogue: 0,0:11:13.13,0:11:15.56,Default,,0,0,0,,表达式只是过程的代码描述 Dialogue: 0,0:11:16.41,0:11:18.33,Default,,0,0,0,,如果在词法作用域的语言中实现过程 Dialogue: 0,0:11:18.56,0:11:21.20,Default,,0,0,0,,那么我希望在表示过程的时候 Dialogue: 0,0:11:23.23,0:11:25.36,Default,,0,0,0,,能够把当前的求值环境包括进来 Dialogue: 0,0:11:25.84,0:11:29.07,Default,,0,0,0,,所以这里我还需要 Dialogue: 0,0:11:29.20,0:11:30.67,Default,,0,0,0,,一些类型标志 Dialogue: 0,0:11:30.70,0:11:33.90,Default,,0,0,0,,这样后面我就可以用它们来区分过程 Dialogue: 0,0:11:34.30,0:11:36.59,Default,,0,0,0,,看哪些是由LAMBDA表达式生成的 Dialogue: 0,0:11:36.81,0:11:38.03,Default,,0,0,0,,哪些是基本过程 Dialogue: 0,0:11:39.06,0:11:41.96,Default,,0,0,0,,所以这里是个类型标志 Dialogue: 0,0:11:41.98,0:11:43.56,Default,,0,0,0,,出于历史原因 Dialogue: 0,0:11:43.56,0:11:45.10,Default,,0,0,0,,我用CLOSURE作为类型标志 Dialogue: 0,0:11:47.68,0:11:49.60,Default,,0,0,0,,现在来看看 哪部分比较重要 Dialogue: 0,0:11:49.92,0:11:51.12,Default,,0,0,0,,我需要知道 Dialogue: 0,0:11:51.24,0:11:52.92,Default,,0,0,0,,绑定变量表和过程的体 Dialogue: 0,0:11:54.22,0:11:55.40,Default,,0,0,0,,这是它的CDR部分 Dialogue: 0,0:11:56.09,0:12:01.85,Default,,0,0,0,,这里就是((X) (+ X Y)) Dialogue: 0,0:12:03.04,0:12:03.87,Default,,0,0,0,,以及某个环境 Dialogue: 0,0:12:08.17,0:12:12.20,Default,,0,0,0,,用户不应该看到这个东西 Dialogue: 0,0:12:13.53,0:12:16.19,Default,,0,0,0,,这只是过程对象的 Dialogue: 0,0:12:16.76,0:12:18.30,Default,,0,0,0,,一种内部表示 Dialogue: 0,0:12:18.52,0:12:20.52,Default,,0,0,0,,它包括绑定变量表 Dialogue: 0,0:12:20.70,0:12:22.62,Default,,0,0,0,,过程的体和某个环境 Dialogue: 0,0:12:23.53,0:12:25.80,Default,,0,0,0,,以及一个类型标签 表示这是一个过程 Dialogue: 0,0:12:26.34,0:12:27.37,Default,,0,0,0,,接下来写代码 Dialogue: 0,0:12:28.08,0:12:38.72,Default,,0,0,0,,如果表达式的CAR部分是'LAMBDA Dialogue: 0,0:12:43.47,0:12:44.81,Default,,0,0,0,,这里 我就要 Dialogue: 0,0:12:45.64,0:12:51.84,Default,,0,0,0,,创建一个表 表头是'CLOSURE Dialogue: 0,0:12:55.15,0:13:00.73,Default,,0,0,0,,接着是 过程代码的CDR部分 Dialogue: 0,0:13:01.56,0:13:02.97,Default,,0,0,0,,也就是除开LAMBDA的其它部分 Dialogue: 0,0:13:07.74,0:13:08.86,Default,,0,0,0,,以及当前的环境 Dialogue: 0,0:13:10.25,0:13:15.32,Default,,0,0,0,,这样就实现了环境模型中的那些规则 Dialogue: 0,0:13:15.45,0:13:18.52,Default,,0,0,0,,这是从LAMBDA表达式中构建过程所必须遵守的 Dialogue: 0,0:13:19.40,0:13:20.97,Default,,0,0,0,,那个求值器在遇到 Dialogue: 0,0:13:21.48,0:13:24.32,Default,,0,0,0,,LAMBDA表达式时的环境 Dialogue: 0,0:13:25.04,0:13:28.46,Default,,0,0,0,,在过程运行的时候 Dialogue: 0,0:13:28.68,0:13:31.77,Default,,0,0,0,,会去这个环境中查找自由变量的值 Dialogue: 0,0:13:34.72,0:13:35.82,Default,,0,0,0,,所以需要把它囊括进来 Dialogue: 0,0:13:35.92,0:13:37.55,Default,,0,0,0,,因此我们必须把求值时的环境 Dialogue: 0,0:13:37.56,0:13:38.86,Default,,0,0,0,,作为过程对象的一部分 Dialogue: 0,0:13:39.21,0:13:40.62,Default,,0,0,0,,之后再来看它的作用 Dialogue: 0,0:13:42.03,0:13:43.77,Default,,0,0,0,,我们也有COND表达式 Dialogue: 0,0:13:44.59,0:13:52.81,Default,,0,0,0,,像是(COND (P1 E1) (P2 E2) ...)这样的 Dialogue: 0,0:13:54.40,0:13:56.09,Default,,0,0,0,,P1是谓词 Dialogue: 0,0:13:56.35,0:13:58.43,Default,,0,0,0,,谓词总是返回TRUE或者FALSE Dialogue: 0,0:13:58.99,0:14:01.76,Default,,0,0,0,,如果谓词P1为真时 表达式E1才被求值 Dialogue: 0,0:14:03.44,0:14:06.08,Default,,0,0,0,,当然 你也可以列这么一组子句 Dialogue: 0,0:14:06.79,0:14:09.36,Default,,0,0,0,,我会把它封装在另一个过程中 Dialogue: 0,0:14:09.36,0:14:11.56,Default,,0,0,0,,我们稍后在那个过程中进行处理 Dialogue: 0,0:14:12.42,0:14:21.28,Default,,0,0,0,,如果表达式的CAR部分是'COND的话 Dialogue: 0,0:14:24.00,0:14:26.84,Default,,0,0,0,,那么我就用EVCOND来求值这个表达式 Dialogue: 0,0:14:30.20,0:14:31.42,Default,,0,0,0,,求值表达式的CDR部分 Dialogue: 0,0:14:34.40,0:14:38.49,Default,,0,0,0,,记得带上环境 Dialogue: 0,0:14:41.43,0:14:42.60,Default,,0,0,0,,好的 还有一种情况 Dialogue: 0,0:14:44.09,0:14:48.22,Default,,0,0,0,,任意的像(+ X 3)这样的表达式 Dialogue: 0,0:14:50.62,0:14:53.95,Default,,0,0,0,,这是把运算符应用在运算对象上 Dialogue: 0,0:14:55.13,0:14:56.59,Default,,0,0,0,,这并没有什么特殊的 Dialogue: 0,0:14:56.59,0:14:59.63,Default,,0,0,0,,就是说 它不属于这里的特殊形式 Dialogue: 0,0:14:59.85,0:15:01.42,Default,,0,0,0,,上面写的这些都是特殊形式 Dialogue: 0,0:15:09.65,0:15:12.12,Default,,0,0,0,,再说明一下 如果我要把这个程序写得专业一点 Dialogue: 0,0:15:12.36,0:15:14.17,Default,,0,0,0,,我会把它设计成数据导向的 Dialogue: 0,0:15:14.48,0:15:16.52,Default,,0,0,0,,那样的话 这里就不会是一系列的条件判断 Dialogue: 0,0:15:16.65,0:15:18.20,Default,,0,0,0,,而是根据一些比特位来做分派 Dialogue: 0,0:15:19.42,0:15:22.25,Default,,0,0,0,,这样来设计会更加专业一些 Dialogue: 0,0:15:22.36,0:15:24.14,Default,,0,0,0,,并且 我不用大量修改程序 Dialogue: 0,0:15:24.68,0:15:26.38,Default,,0,0,0,,就可以添加规则 Dialogue: 0,0:15:26.71,0:15:28.46,Default,,0,0,0,,这样来做可能运行得更快 Dialogue: 0,0:15:29.04,0:15:30.43,Default,,0,0,0,,但这里我并不打算这么做 Dialogue: 0,0:15:31.28,0:15:33.98,Default,,0,0,0,,现在的目的是把握EVAL过程的整体 Dialogue: 0,0:15:35.07,0:15:35.80,Default,,0,0,0,,那么 最后一种情况 Dialogue: 0,0:15:37.69,0:15:38.56,Default,,0,0,0,,要怎么做呢? Dialogue: 0,0:15:38.56,0:15:41.23,Default,,0,0,0,,在这种情况下 我需要进行加法运算 Dialogue: 0,0:15:44.35,0:15:46.16,Default,,0,0,0,,那么我就得搞清楚 '+到底是什么 Dialogue: 0,0:15:46.84,0:15:49.29,Default,,0,0,0,,我还得知道X和3又代表什么 Dialogue: 0,0:15:50.55,0:15:53.96,Default,,0,0,0,,然后再把'+的所代表的东西 Dialogue: 0,0:15:54.43,0:15:57.00,Default,,0,0,0,,应用于'X与3所代表的东西上 Dialogue: 0,0:15:58.11,0:15:59.39,Default,,0,0,0,,具体来写一下 Dialogue: 0,0:15:59.87,0:16:09.55,Default,,0,0,0,,我要把表达式CAR部分的求值结果 Dialogue: 0,0:16:11.20,0:16:12.14,Default,,0,0,0,,应用在 Dialogue: 0,0:16:13.21,0:16:15.50,Default,,0,0,0,,表达式的CAR部分就是运算符 Dialogue: 0,0:16:17.20,0:16:18.51,Default,,0,0,0,,要在给定的环境中进行 Dialogue: 0,0:16:20.51,0:16:22.89,Default,,0,0,0,,对运算符求值会得到一个过程 Dialogue: 0,0:16:24.05,0:16:26.78,Default,,0,0,0,,现在 我要求值所有运算对象来取得参数 Dialogue: 0,0:16:27.29,0:16:28.22,Default,,0,0,0,,我将调用EVLIST Dialogue: 0,0:16:31.26,0:16:35.53,Default,,0,0,0,,来求值表达式的CDR部分 也就是运算对象 Dialogue: 0,0:16:36.76,0:16:39.00,Default,,0,0,0,,当然是在相应的环境中 Dialogue: 0,0:16:41.94,0:16:43.13,Default,,0,0,0,,我们待会儿再定义EVLIST Dialogue: 0,0:16:43.26,0:16:48.07,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:16:50.90,0:16:52.33,Default,,0,0,0,,你现在看到的 Dialogue: 0,0:16:52.67,0:16:56.11,Default,,0,0,0,,基本上就是一个完整的求值器 Dialogue: 0,0:16:56.49,0:17:01.00,Default,,0,0,0,,它根据表达式的类型分情况处理 Dialogue: 0,0:17:01.24,0:17:02.11,Default,,0,0,0,,默认的情况是 Dialogue: 0,0:17:04.99,0:17:07.95,Default,,0,0,0,,表达式应用或者说是组合式 Dialogue: 0,0:17:17.52,0:17:19.52,Default,,0,0,0,,不过还有好些过程 我们没有定义 Dialogue: 0,0:17:20.08,0:17:21.60,Default,,0,0,0,,接下来就看这些未定义的部分 Dialogue: 0,0:17:21.78,0:17:24.12,Default,,0,0,0,,我们还要定义EVCOND Dialogue: 0,0:17:25.48,0:17:26.67,Default,,0,0,0,,我得定义APPLY Dialogue: 0,0:17:27.57,0:17:28.62,Default,,0,0,0,,还有EVLIST Dialogue: 0,0:17:28.94,0:17:30.20,Default,,0,0,0,,以及LOOKUP Dialogue: 0,0:17:31.79,0:17:33.43,Default,,0,0,0,,我看看 没别的了吧? Dialogue: 0,0:17:33.43,0:17:35.16,Default,,0,0,0,,剩下的东西都很简单 Dialogue: 0,0:17:35.16,0:17:37.18,Default,,0,0,0,,比如基本元素之类的东西 Dialogue: 0,0:17:38.57,0:17:39.48,Default,,0,0,0,,当然 Dialogue: 0,0:17:39.69,0:17:42.06,Default,,0,0,0,,在这里 可以扩充很多特殊形式 Dialogue: 0,0:17:42.25,0:17:44.45,Default,,0,0,0,,但如果在通用语言中这么做就很糟糕 Dialogue: 0,0:17:44.45,0:17:45.92,Default,,0,0,0,,在这里添加大量的东西 Dialogue: 0,0:17:46.00,0:17:47.48,Default,,0,0,0,,会让语言变得复杂 Dialogue: 0,0:17:47.69,0:17:50.35,Default,,0,0,0,,语言中的保留字 Dialogue: 0,0:17:50.76,0:17:53.61,Default,,0,0,0,,不该比你能用几个手指、脚指记住的数目多 Dialogue: 0,0:17:54.16,0:17:55.53,Default,,0,0,0,,有些语言的保留字有成百上千个 Dialogue: 0,0:17:55.56,0:17:58.20,Default,,0,0,0,,我都不知道该说什么了 Dialogue: 0,0:17:59.41,0:18:00.71,Default,,0,0,0,,保留字就是在这里定义的 Dialogue: 0,0:18:03.15,0:18:06.54,Default,,0,0,0,,好 接下来 我们来看下一个部分 Dialogue: 0,0:18:06.56,0:18:07.69,Default,,0,0,0,,求值器的核心 APPLY Dialogue: 0,0:18:09.64,0:18:10.75,Default,,0,0,0,,它还做些什么呢? Dialogue: 0,0:18:11.59,0:18:17.53,Default,,0,0,0,,APPLY把还是符号状态的求值运算符和运算对象 Dialogue: 0,0:18:17.66,0:18:20.68,Default,,0,0,0,,求值为相应的过程以及参数值 Dialogue: 0,0:18:20.91,0:18:23.85,Default,,0,0,0,,然后把得到的过程应用在参数上 Dialogue: 0,0:18:24.09,0:18:26.96,Default,,0,0,0,,无论它们是什么符号表达式 Dialogue: 0,0:18:33.27,0:18:35.08,Default,,0,0,0,,我们把APPLY定义为 Dialogue: 0,0:18:38.35,0:18:40.65,Default,,0,0,0,,接收两个参数的过程 Dialogue: 0,0:18:40.75,0:18:43.44,Default,,0,0,0,,一个过程和对应的参数 Dialogue: 0,0:18:47.24,0:18:48.12,Default,,0,0,0,,它要怎么做呢? Dialogue: 0,0:18:48.14,0:18:49.55,Default,,0,0,0,,其实并不复杂 Dialogue: 0,0:18:49.93,0:18:50.78,Default,,0,0,0,,分两种情况就够了 Dialogue: 0,0:18:53.58,0:18:55.16,Default,,0,0,0,,如果这个过程是基本过程-- Dialogue: 0,0:19:03.42,0:19:06.41,Default,,0,0,0,,我不知道这个谓词具体是如何判断的 Dialogue: 0,0:19:06.86,0:19:10.24,Default,,0,0,0,,可能这里面有某种类型信息 Dialogue: 0,0:19:10.38,0:19:12.41,Default,,0,0,0,,就像我们在这里用'CLOSURE Dialogue: 0,0:19:12.68,0:19:15.05,Default,,0,0,0,,来描述一些复合对象一样 Dialogue: 0,0:19:16.33,0:19:17.79,Default,,0,0,0,,我想可能是这样 Dialogue: 0,0:19:18.55,0:19:20.20,Default,,0,0,0,,但是具体怎么判断并不重要 Dialogue: 0,0:19:20.68,0:19:22.01,Default,,0,0,0,,事实上 Dialogue: 0,0:19:22.19,0:19:23.85,Default,,0,0,0,,你可能已经知道或者推断过 Dialogue: 0,0:19:23.87,0:19:25.47,Default,,0,0,0,,我们并不需要任何基本过程 Dialogue: 0,0:19:27.35,0:19:29.28,Default,,0,0,0,,就算没有它们 照样可以进行计算 Dialogue: 0,0:19:30.46,0:19:33.19,Default,,0,0,0,,因为我们可以用一直在用的LAMBDA Dialogue: 0,0:19:33.61,0:19:34.76,Default,,0,0,0,,但是有它们总归方便点儿 Dialogue: 0,0:19:34.81,0:19:36.27,Default,,0,0,0,,我在这儿略施魔法 Dialogue: 0,0:19:36.30,0:19:37.47,Default,,0,0,0,,但不会去解释 Dialogue: 0,0:19:38.06,0:19:41.44,Default,,0,0,0,,转到机器语言 执行APPLY-PRIMOP Dialogue: 0,0:19:42.91,0:19:43.80,Default,,0,0,0,,加法是在这里运算的 Dialogue: 0,0:19:44.78,0:19:46.10,Default,,0,0,0,,执行加法指令 Dialogue: 0,0:19:50.62,0:19:52.11,Default,,0,0,0,,然而一门语言有趣的部分 Dialogue: 0,0:19:52.14,0:19:54.27,Default,,0,0,0,,在于组合基本元素的粘合剂 Dialogue: 0,0:19:54.91,0:19:55.90,Default,,0,0,0,,我们接着往下看 Dialogue: 0,0:19:56.91,0:19:58.38,Default,,0,0,0,,另一种可能就是 Dialogue: 0,0:19:58.75,0:20:04.12,Default,,0,0,0,,这个复合对象是求值LAMBDA表达式得到的 Dialogue: 0,0:20:04.97,0:20:07.05,Default,,0,0,0,,这是个复合过程 Dialogue: 0,0:20:07.62,0:20:09.36,Default,,0,0,0,,检测它的类型标志 Dialogue: 0,0:20:10.11,0:20:17.07,Default,,0,0,0,,如果是'CLOSURE Dialogue: 0,0:20:20.51,0:20:24.09,Default,,0,0,0,,如果是的话 我就得求值这个过程的体 Dialogue: 0,0:20:24.19,0:20:27.39,Default,,0,0,0,,过程的体的求值方式则是 Dialogue: 0,0:20:28.08,0:20:31.69,Default,,0,0,0,,我求值过程的应用是通过 Dialogue: 0,0:20:31.72,0:20:33.71,Default,,0,0,0,,先扩充程序的求值环境 Dialogue: 0,0:20:34.19,0:20:37.80,Default,,0,0,0,,在这个环境中 把过程的形式参数 Dialogue: 0,0:20:37.92,0:20:40.48,Default,,0,0,0,,跟传递过来的实际参数绑定在一起 Dialogue: 0,0:20:41.02,0:20:43.68,Default,,0,0,0,,在这个环境中求值过程的体 Dialogue: 0,0:20:46.70,0:20:47.87,Default,,0,0,0,,这句话很长 Dialogue: 0,0:20:51.13,0:20:52.16,Default,,0,0,0,,但其实简单 Dialogue: 0,0:20:52.82,0:20:54.48,Default,,0,0,0,,一会儿可能会出现许多CAR CDR... Dialogue: 0,0:20:56.46,0:20:58.11,Default,,0,0,0,,现在我先要得到过程体 Dialogue: 0,0:20:59.40,0:21:02.30,Default,,0,0,0,,如何取出过程体呢? Dialogue: 0,0:21:02.96,0:21:04.08,Default,,0,0,0,,这里是CAR部分 Dialogue: 0,0:21:04.49,0:21:06.13,Default,,0,0,0,,这一块是剩下部分的CDR部分 Dialogue: 0,0:21:06.13,0:21:06.96,Default,,0,0,0,,因此这就是CADR Dialogue: 0,0:21:07.40,0:21:09.45,Default,,0,0,0,,所以这里我得到的过程体 Dialogue: 0,0:21:09.45,0:21:13.04,Default,,0,0,0,,是过程对象第二个元素的第二个元素 Dialogue: 0,0:21:13.20,0:21:15.15,Default,,0,0,0,,因此CADR的CADR 也就是CADADR Dialogue: 0,0:21:19.17,0:21:27.68,Default,,0,0,0,,这里取过程对象的CADADR部分 Dialogue: 0,0:21:30.26,0:21:31.56,Default,,0,0,0,,为了求值过程体 Dialogue: 0,0:21:31.98,0:21:36.48,Default,,0,0,0,,要在参数绑定后的新环境之中进行 Dialogue: 0,0:21:38.09,0:21:42.06,Default,,0,0,0,,我还得获取过程的形式参数 Dialogue: 0,0:21:42.06,0:21:42.72,Default,,0,0,0,,要怎么取呢? Dialogue: 0,0:21:43.50,0:21:45.13,Default,,0,0,0,,就是CADR部分的CAR部分 Dialogue: 0,0:21:46.52,0:21:48.78,Default,,0,0,0,,这很糟糕不是吗? Dialogue: 0,0:21:52.65,0:21:53.63,Default,,0,0,0,,过程的CADR部分 Dialogue: 0,0:21:55.44,0:22:00.86,Default,,0,0,0,,在随着过程一起传递过来的环境中 Dialogue: 0,0:22:00.89,0:22:04.14,Default,,0,0,0,,把形参和由环境传递过来的实参绑定起来 Dialogue: 0,0:22:04.54,0:22:07.90,Default,,0,0,0,,也就是CDR的CDR的CAR Dialogue: 0,0:22:09.79,0:22:16.62,Default,,0,0,0,,也就是过程的CADDR部分 Dialogue: 0,0:22:20.29,0:22:24.96,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:22:26.14,0:22:29.68,Default,,0,0,0,,当然 如果我非常追求整洁 Dialogue: 0,0:22:29.87,0:22:31.34,Default,,0,0,0,,并且又非常谨慎 Dialogue: 0,0:22:32.24,0:22:34.12,Default,,0,0,0,,我会在后面多加一个情况 Dialogue: 0,0:22:34.38,0:22:35.98,Default,,0,0,0,,来判断是否出错 Dialogue: 0,0:22:36.17,0:22:38.41,Default,,0,0,0,,比如应用在参数上的是一个过程吗? Dialogue: 0,0:22:39.00,0:22:41.69,Default,,0,0,0,,如果不是 这里就是未定义的过程类型 Dialogue: 0,0:22:42.57,0:22:44.09,Default,,0,0,0,,我在这里也会这么做 Dialogue: 0,0:22:45.80,0:22:55.96,Default,,0,0,0,,像这样 在ELSE子句中返回错误 Dialogue: 0,0:22:57.61,0:23:01.61,Default,,0,0,0,,当然 在现实中的一些系统中 Dialogue: 0,0:23:02.56,0:23:04.22,Default,,0,0,0,,出于专业设计的考虑 Dialogue: 0,0:23:05.32,0:23:08.00,Default,,0,0,0,,这里可能会根据某种分派 Dialogue: 0,0:23:08.36,0:23:09.90,Default,,0,0,0,,来进行“分情况处理” Dialogue: 0,0:23:10.75,0:23:12.68,Default,,0,0,0,,回到这里 我可能还会添加新的条件来检查 Dialogue: 0,0:23:12.70,0:23:14.14,Default,,0,0,0,,比如 这是编译过的代码吗? Dialogue: 0,0:23:16.22,0:23:16.84,Default,,0,0,0,,这很重要 Dialogue: 0,0:23:16.88,0:23:18.35,Default,,0,0,0,,这样的话我就可以区分 Dialogue: 0,0:23:18.38,0:23:22.33,Default,,0,0,0,,过程是直接由解释LAMBDA表达式而来 Dialogue: 0,0:23:22.94,0:23:25.87,Default,,0,0,0,,还是从另外的编译器中得到的 等等 Dialogue: 0,0:23:26.11,0:23:27.23,Default,,0,0,0,,之后再讨论这个话题 Dialogue: 0,0:23:27.23,0:23:29.61,Default,,0,0,0,,又或许是 我必须要执行的一段Frotran代码 Dialogue: 0,0:23:30.51,0:23:32.51,Default,,0,0,0,,这完全是可能的 Dialogue: 0,0:23:32.92,0:23:36.41,Default,,0,0,0,,实际上 我用具体语法写的这个求值器 Dialogue: 0,0:23:37.45,0:23:40.86,Default,,0,0,0,,假定了它是用Lisp来编写的 Dialogue: 0,0:23:42.30,0:23:43.82,Default,,0,0,0,,这是因为我用了CAR和CDR Dialogue: 0,0:23:43.84,0:23:45.10,Default,,0,0,0,,用CAR来取运算符 Dialogue: 0,0:23:45.28,0:23:46.64,Default,,0,0,0,,用CDR来取运算对象 Dialogue: 0,0:23:46.75,0:23:49.96,Default,,0,0,0,,教科书上给出了一个用抽象语法编写的求值器 Dialogue: 0,0:23:50.35,0:23:53.15,Default,,0,0,0,,它使用的都是抽象的名字 Dialogue: 0,0:23:53.16,0:23:54.09,Default,,0,0,0,,比如OPERATOR、OPERAND Dialogue: 0,0:23:54.14,0:23:55.82,Default,,0,0,0,,以及类似的名字 Dialogue: 0,0:23:56.16,0:23:56.86,Default,,0,0,0,,那样的话 Dialogue: 0,0:23:57.02,0:24:00.91,Default,,0,0,0,,你可以毫无问题地用ALGOL来重新实现 Dialogue: 0,0:24:03.36,0:24:06.40,Default,,0,0,0,,写完APPLY之后 Dialogue: 0,0:24:07.20,0:24:08.43,Default,,0,0,0,,又有一些东西没有定义 Dialogue: 0,0:24:10.81,0:24:12.57,Default,,0,0,0,,我先不操心这两个 Dialogue: 0,0:24:13.39,0:24:15.05,Default,,0,0,0,,我们稍后讨论这个很重要的BIND Dialogue: 0,0:24:17.18,0:24:19.76,Default,,0,0,0,,现在我们来快速过一遍 结束这一部分 Dialogue: 0,0:24:20.55,0:24:22.65,Default,,0,0,0,,只剩下两块黑板了 不能够写太长 Dialogue: 0,0:24:27.40,0:24:29.08,Default,,0,0,0,,我还得悉心裁剪才能刚好写下 Dialogue: 0,0:24:30.07,0:24:30.98,Default,,0,0,0,,嗯 还剩下点什么? Dialogue: 0,0:24:30.98,0:24:33.20,Default,,0,0,0,,我们得定义这里的EVLIST Dialogue: 0,0:24:33.73,0:24:35.07,Default,,0,0,0,,EVLIST只不过是 Dialogue: 0,0:24:35.26,0:24:43.08,Default,,0,0,0,,在运算对象上映射某个函数得到参数 Dialogue: 0,0:24:44.30,0:24:45.40,Default,,0,0,0,,但是我还是要写出来看看 Dialogue: 0,0:24:45.82,0:24:48.30,Default,,0,0,0,,我把它写出来的原因有点神秘 Dialogue: 0,0:24:49.88,0:24:52.04,Default,,0,0,0,,我想让这个求值器简单得 Dialogue: 0,0:24:52.06,0:24:53.56,Default,,0,0,0,,可以求值自身 Dialogue: 0,0:24:56.45,0:24:58.09,Default,,0,0,0,,我真的很在意这一点 Dialogue: 0,0:25:00.23,0:25:01.74,Default,,0,0,0,,现在我就把它完全写在这里 Dialogue: 0,0:25:02.85,0:25:04.24,Default,,0,0,0,,我并不关心 Dialogue: 0,0:25:04.27,0:25:06.08,Default,,0,0,0,,它能否把过程作为参数传递 Dialogue: 0,0:25:06.27,0:25:08.06,Default,,0,0,0,,求值器并不会用到这些参数 Dialogue: 0,0:25:08.98,0:25:10.78,Default,,0,0,0,,求值器也不会生成一个是过程的值 Dialogue: 0,0:25:10.88,0:25:12.67,Default,,0,0,0,,因此 如果另外有个不同的语言 Dialogue: 0,0:25:12.80,0:25:13.96,Default,,0,0,0,,跟这个又非常相似 Dialogue: 0,0:25:15.16,0:25:17.79,Default,,0,0,0,,这个求值器能够求值像Scheme这样的复杂语言 Dialogue: 0,0:25:17.80,0:25:23.12,Default,,0,0,0,,Scheme是能够把过程当做参数传递的 Dialogue: 0,0:25:24.07,0:25:25.95,Default,,0,0,0,,但当我在求值ALGOL时 Dialogue: 0,0:25:27.34,0:25:28.96,Default,,0,0,0,,尽管ALGOL并不支持过程值 Dialogue: 0,0:25:29.47,0:25:30.59,Default,,0,0,0,,这个求值器也能正常工作 Dialogue: 0,0:25:31.58,0:25:33.92,Default,,0,0,0,,因为这个解释器 并没有对这个做过什么假定 Dialogue: 0,0:25:34.27,0:25:36.03,Default,,0,0,0,,实际上 就算这个求值器 Dialogue: 0,0:25:36.27,0:25:37.50,Default,,0,0,0,,被限制不允许那么做 也没有什么关系 Dialogue: 0,0:25:37.52,0:25:40.03,Default,,0,0,0,,因为它没有使用那些高级功能 Dialogue: 0,0:25:40.64,0:25:42.41,Default,,0,0,0,,这就是我为什么要把它设计得非常简单 Dialogue: 0,0:25:44.07,0:25:46.46,Default,,0,0,0,,这几乎是所有可能的语言求值器的核心 Dialogue: 0,0:25:47.81,0:25:48.48,Default,,0,0,0,,回到这个定义上来 Dialogue: 0,0:25:49.42,0:25:53.56,Default,,0,0,0,,EVLIST -- 它是什么呢? Dialogue: 0,0:25:53.82,0:25:57.04,Default,,0,0,0,,这个过程接收两个参数 L和ENV Dialogue: 0,0:25:58.09,0:25:59.08,Default,,0,0,0,,其中L是个表 Dialogue: 0,0:25:59.58,0:26:08.27,Default,,0,0,0,,这样的话 如果参数表是空表 Dialogue: 0,0:26:10.19,0:26:12.68,Default,,0,0,0,,那么结果就是空表 Dialogue: 0,0:26:14.03,0:26:19.23,Default,,0,0,0,,否则的话 我就要组合 Dialogue: 0,0:26:20.75,0:26:26.67,Default,,0,0,0,,在ENV中求值运算对象表的CAR部分 Dialogue: 0,0:26:28.16,0:26:32.51,Default,,0,0,0,,在ENV中求值运算对象CAR部分的结果 Dialogue: 0,0:26:33.34,0:26:35.71,Default,,0,0,0,,我想先求值第一个运算对象 Dialogue: 0,0:26:35.98,0:26:38.40,Default,,0,0,0,,返回的结果将是一个新表 Dialogue: 0,0:26:38.97,0:26:40.76,Default,,0,0,0,,是通过把这个和 Dialogue: 0,0:26:41.08,0:26:45.42,Default,,0,0,0,,用CDR递归EVLIST的结果组合得到的 Dialogue: 0,0:26:46.22,0:26:50.13,Default,,0,0,0,,在同样的ENV下 L的CDR部分 Dialogue: 0,0:26:53.08,0:26:58.24,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:26:59.66,0:27:01.84,Default,,0,0,0,,还有一个过程 Dialogue: 0,0:27:01.84,0:27:03.36,Default,,0,0,0,,我也想写在这里 Dialogue: 0,0:27:03.62,0:27:05.21,Default,,0,0,0,,它是这整个的关键 Dialogue: 0,0:27:05.64,0:27:08.13,Default,,0,0,0,,还要深入一个层次 Dialogue: 0,0:27:14.54,0:27:15.44,Default,,0,0,0,,也就是COND语句 Dialogue: 0,0:27:15.69,0:27:16.99,Default,,0,0,0,,在剩下的东西中 Dialogue: 0,0:27:17.02,0:27:18.17,Default,,0,0,0,,EVCOND是唯一的重要过程 Dialogue: 0,0:27:18.88,0:27:20.75,Default,,0,0,0,,解决完这个后 Dialogue: 0,0:27:21.07,0:27:22.94,Default,,0,0,0,,我们再讨论LOOKUP和BIND Dialogue: 0,0:27:23.56,0:27:25.36,Default,,0,0,0,,稍后再来讨论 Dialogue: 0,0:27:25.53,0:27:27.93,Default,,0,0,0,,在这个层次上 这是非常重要的 Dialogue: 0,0:27:28.65,0:27:30.62,Default,,0,0,0,,下一个重要的事就是如何处理COND语句 Dialogue: 0,0:27:31.60,0:27:33.33,Default,,0,0,0,,那么 我们怎么来处理呢? Dialogue: 0,0:27:36.97,0:27:38.56,Default,,0,0,0,,它是一个过程 Dialogue: 0,0:27:39.48,0:27:45.00,Default,,0,0,0,,参数是一组子句CLAUSES和环境ENV Dialogue: 0,0:27:47.71,0:27:48.51,Default,,0,0,0,,它做些什么呢? Dialogue: 0,0:27:49.82,0:27:55.47,Default,,0,0,0,,如果子句为空 Dialogue: 0,0:28:02.60,0:28:03.96,Default,,0,0,0,,我得有一个返回值 Dialogue: 0,0:28:04.70,0:28:05.87,Default,,0,0,0,,可能是一个错误 Dialogue: 0,0:28:06.54,0:28:08.59,Default,,0,0,0,,如果遍历完了所有条件 都没有符合的 Dialogue: 0,0:28:09.15,0:28:10.06,Default,,0,0,0,,那么它可能有任意的行为 Dialogue: 0,0:28:10.06,0:28:12.88,Default,,0,0,0,,这完全取决于程序员要怎么处理 Dialogue: 0,0:28:13.65,0:28:15.45,Default,,0,0,0,,现在对我来说最方便的是 Dialogue: 0,0:28:15.63,0:28:17.53,Default,,0,0,0,,让它返回一个空表 Dialogue: 0,0:28:18.14,0:28:18.83,Default,,0,0,0,,这无所谓 Dialogue: 0,0:28:20.10,0:28:20.88,Default,,0,0,0,,为了检查出错误 Dialogue: 0,0:28:20.89,0:28:22.76,Default,,0,0,0,,有些人喜欢在这里写点别的 Dialogue: 0,0:28:23.11,0:28:24.81,Default,,0,0,0,,下面的更有意思 Dialogue: 0,0:28:25.39,0:28:27.24,Default,,0,0,0,,如果我遇到了ELSE子句 Dialogue: 0,0:28:31.00,0:28:32.73,Default,,0,0,0,,请看 我们有一个由子句组成的表 Dialogue: 0,0:28:33.21,0:28:34.41,Default,,0,0,0,,其中每个子句也是一个表 Dialogue: 0,0:28:35.44,0:28:40.52,Default,,0,0,0,,因此谓词就应该是CLAUSES的CAAR部分 Dialogue: 0,0:28:43.56,0:28:45.02,Default,,0,0,0,,它是 Dialogue: 0,0:28:45.04,0:28:49.00,Default,,0,0,0,,CLAUSES表中第一个元素的CAR部分 Dialogue: 0,0:28:51.09,0:28:51.84,Default,,0,0,0,,如果它是'ELSE的话 Dialogue: 0,0:28:54.32,0:28:56.51,Default,,0,0,0,,就意味着整个COND表达式的结果 Dialogue: 0,0:28:56.64,0:28:59.15,Default,,0,0,0,,就是求值匹配表达式的结果 Dialogue: 0,0:29:00.12,0:29:04.32,Default,,0,0,0,,所以我求值CADAR部分 Dialogue: 0,0:29:07.00,0:29:09.56,Default,,0,0,0,,这是第一个子句的 Dialogue: 0,0:29:10.12,0:29:11.63,Default,,0,0,0,,第二个元素 也就是CADAR Dialogue: 0,0:29:12.81,0:29:17.08,Default,,0,0,0,,也就是CLAUSES的CAR部分的CADR部分 Dialogue: 0,0:29:21.23,0:29:22.57,Default,,0,0,0,,求值的环境是ENV Dialogue: 0,0:29:26.62,0:29:28.60,Default,,0,0,0,,下一种可能性更有意思 Dialogue: 0,0:29:29.63,0:29:30.44,Default,,0,0,0,,如果它返回FALSE的话 Dialogue: 0,0:29:33.05,0:29:35.10,Default,,0,0,0,,如果谓词表中的第一个谓词 Dialogue: 0,0:29:35.74,0:29:37.68,Default,,0,0,0,,既不是ELSE子句 又不为FALSE Dialogue: 0,0:29:38.32,0:29:39.50,Default,,0,0,0,,也就是它不是保留字ELSE Dialogue: 0,0:29:40.16,0:29:42.00,Default,,0,0,0,,并且也不是一个值为FALSE的东西 Dialogue: 0,0:29:42.03,0:29:43.66,Default,,0,0,0,,如果为FALSE又要怎么处理呢? Dialogue: 0,0:29:44.36,0:29:50.08,Default,,0,0,0,,如果在相应的环境中 Dialogue: 0,0:29:52.33,0:29:56.76,Default,,0,0,0,,求值子句中第一个谓词的结果 Dialogue: 0,0:29:58.19,0:30:01.00,Default,,0,0,0,,如果求值的结果是FALSE的话 Dialogue: 0,0:30:01.69,0:30:03.82,Default,,0,0,0,,这就意味着 还得接着判断后面的子句 Dialogue: 0,0:30:04.36,0:30:05.74,Default,,0,0,0,,第一个就扔掉不管了 Dialogue: 0,0:30:06.25,0:30:08.33,Default,,0,0,0,,所以就进入下一个EVCOND循环 Dialogue: 0,0:30:09.95,0:30:16.49,Default,,0,0,0,,在对应的环境中继续判断子句的CDR部分 Dialogue: 0,0:30:19.95,0:30:25.15,Default,,0,0,0,,又或者 我遇到了求值为TRUE的子句 Dialogue: 0,0:30:26.84,0:30:28.96,Default,,0,0,0,,这样的话 我想在对应的环境中 Dialogue: 0,0:30:31.85,0:30:41.45,Default,,0,0,0,,求值CLAUSES的CADAR部分 Dialogue: 0,0:30:48.20,0:30:49.61,Default,,0,0,0,,快了 快完成了 Dialogue: 0,0:30:51.21,0:30:52.80,Default,,0,0,0,,基本上完整了 Dialogue: 0,0:30:53.73,0:30:55.87,Default,,0,0,0,,把这一部分结束 Dialogue: 0,0:30:56.21,0:30:58.57,Default,,0,0,0,,再回顾一下这个求值器 Dialogue: 0,0:30:58.81,0:31:00.70,Default,,0,0,0,,它基本上就是这样了 Dialogue: 0,0:31:01.08,0:31:04.04,Default,,0,0,0,,接着来看一张幻灯片 Dialogue: 0,0:31:06.32,0:31:10.43,Default,,0,0,0,,这是BIND的定义 Dialogue: 0,0:31:11.98,0:31:14.54,Default,,0,0,0,,BIND用于在环境中添加新的绑定 Dialogue: 0,0:31:15.46,0:31:18.67,Default,,0,0,0,,我们要在这里 Dialogue: 0,0:31:19.24,0:31:22.80,Default,,0,0,0,,为环境结构创建一个新框架 Dialogue: 0,0:31:22.80,0:31:25.42,Default,,0,0,0,,环境结构是通过由框架组成的表 Dialogue: 0,0:31:25.93,0:31:27.20,Default,,0,0,0,,来表示的 Dialogue: 0,0:31:28.08,0:31:30.19,Default,,0,0,0,,给定一个已有的环境 Dialogue: 0,0:31:30.32,0:31:32.11,Default,,0,0,0,,我可以通过把一个新建的框架 Dialogue: 0,0:31:32.25,0:31:33.82,Default,,0,0,0,,CONS在已有的环境上 Dialogue: 0,0:31:33.93,0:31:35.69,Default,,0,0,0,,来获得新的环境 Dialogue: 0,0:31:36.62,0:31:40.36,Default,,0,0,0,,正在应用的过程中 那些被绑定变量 Dialogue: 0,0:31:41.05,0:31:43.79,Default,,0,0,0,,与传递给过程的参数值结合在一起 Dialogue: 0,0:31:44.12,0:31:48.25,Default,,0,0,0,,组成了我们所创建的新框架 Dialogue: 0,0:31:49.69,0:31:50.65,Default,,0,0,0,,BIND其实就是创建表 Dialogue: 0,0:31:51.64,0:31:54.06,Default,,0,0,0,,环境就是一组由框架组成的表 Dialogue: 0,0:31:54.30,0:31:55.60,Default,,0,0,0,,把新的元素加入其中 Dialogue: 0,0:31:55.74,0:31:56.89,Default,,0,0,0,,也就形成了新的环境 Dialogue: 0,0:31:58.65,0:32:00.65,Default,,0,0,0,,而PAIR-UP的定义非常简单 Dialogue: 0,0:32:01.54,0:32:02.84,Default,,0,0,0,,PAIR-UP只不过是 Dialogue: 0,0:32:03.13,0:32:05.56,Default,,0,0,0,,如果我们有一个变量表和一个值表 Dialogue: 0,0:32:05.93,0:32:08.62,Default,,0,0,0,,那么 如果它俩的元素个数又相同 Dialogue: 0,0:32:08.62,0:32:09.58,Default,,0,0,0,,就可以让它们一一对应 Dialogue: 0,0:32:09.72,0:32:11.48,Default,,0,0,0,,否则的话 就是参数传递多了 Dialogue: 0,0:32:12.51,0:32:15.98,Default,,0,0,0,,如果值的个数比变量的个数多 Dialogue: 0,0:32:16.06,0:32:17.37,Default,,0,0,0,,那就说明参数传递少了 Dialogue: 0,0:32:18.51,0:32:19.63,Default,,0,0,0,,通常的情况是 Dialogue: 0,0:32:19.63,0:32:21.48,Default,,0,0,0,,如果没有出错 又没有完成的话 Dialogue: 0,0:32:22.06,0:32:25.61,Default,,0,0,0,,我就添加一个由第一个变量 Dialogue: 0,0:32:25.76,0:32:30.17,Default,,0,0,0,,和第一个参数组成的新序对 Dialogue: 0,0:32:30.94,0:32:32.12,Default,,0,0,0,,这是第一个值 Dialogue: 0,0:32:32.76,0:32:36.40,Default,,0,0,0,,把它们CONS在 Dialogue: 0,0:32:37.12,0:32:40.64,Default,,0,0,0,,剩余变量和值组成的表上 Dialogue: 0,0:32:42.95,0:32:44.78,Default,,0,0,0,,LOOKUP也同样简单 Dialogue: 0,0:32:46.28,0:32:49.63,Default,,0,0,0,,加入我要在环境中查找一个符号 Dialogue: 0,0:32:49.93,0:32:51.39,Default,,0,0,0,,那么 如果是空环境 Dialogue: 0,0:32:51.56,0:32:53.00,Default,,0,0,0,,那么就说明 该变量尚未绑定 Dialogue: 0,0:32:54.65,0:32:55.47,Default,,0,0,0,,否则 Dialogue: 0,0:32:56.86,0:33:00.36,Default,,0,0,0,,我就要使用一个特殊的关联表查找过程 Dialogue: 0,0:33:00.38,0:33:01.87,Default,,0,0,0,,我们不久就会看到它的定义 Dialogue: 0,0:33:02.24,0:33:05.44,Default,,0,0,0,,用它在环境的第一个框架中查找该符号 Dialogue: 0,0:33:05.93,0:33:07.21,Default,,0,0,0,,由于我知道这个环境不是空的 Dialogue: 0,0:33:07.23,0:33:08.40,Default,,0,0,0,,因此 它至少有一个框架 Dialogue: 0,0:33:09.20,0:33:11.14,Default,,0,0,0,,所以 我就在它第一个框架中查找 Dialogue: 0,0:33:11.56,0:33:13.58,Default,,0,0,0,,找到的序对会传递给这里的VCELL Dialogue: 0,0:33:14.38,0:33:17.61,Default,,0,0,0,,如果VCELL为空 Dialogue: 0,0:33:18.44,0:33:20.57,Default,,0,0,0,,那就说明当前框架中没有这个符号 Dialogue: 0,0:33:20.70,0:33:22.84,Default,,0,0,0,,我就需要在环境中剩下的框架中查找 Dialogue: 0,0:33:23.72,0:33:25.04,Default,,0,0,0,,VCELL为空 意味着当前框架没有相应的符号 Dialogue: 0,0:33:25.99,0:33:28.89,Default,,0,0,0,,如果没有找到 Dialogue: 0,0:33:29.52,0:33:30.80,Default,,0,0,0,,ASSQ就会返回空表 Dialogue: 0,0:33:32.32,0:33:33.85,Default,,0,0,0,,如果找到了 Dialogue: 0,0:33:33.85,0:33:36.06,Default,,0,0,0,,那么我就使用VCELL的CDR部分 Dialogue: 0,0:33:36.46,0:33:40.25,Default,,0,0,0,,因为VCELL是变量和值组成的序对 Dialogue: 0,0:33:41.05,0:33:43.93,Default,,0,0,0,,因此可以用CDR取得对应的值 Dialogue: 0,0:33:45.00,0:33:47.82,Default,,0,0,0,,ASSQ这个过程你们之前见过 Dialogue: 0,0:33:47.97,0:33:50.83,Default,,0,0,0,,ASSQ的参数是一个符号和一个由序对组成的表 Dialogue: 0,0:33:51.42,0:33:53.40,Default,,0,0,0,,如果表为空 它就返回空表 Dialogue: 0,0:33:53.52,0:33:56.30,Default,,0,0,0,,如果这个符号是ALIST的第一个元素 Dialogue: 0,0:33:58.06,0:33:58.91,Default,,0,0,0,,这里写错了 Dialogue: 0,0:33:59.82,0:34:02.17,Default,,0,0,0,,应该是CAAR Dialogue: 0,0:34:03.16,0:34:04.16,Default,,0,0,0,,大家注意一下 Dialogue: 0,0:34:07.63,0:34:09.37,Default,,0,0,0,,就是这里 看到了吗? Dialogue: 0,0:34:13.42,0:34:14.41,Default,,0,0,0,,总之 Dialogue: 0,0:34:14.56,0:34:16.81,Default,,0,0,0,,如果符号等于表的CAAR Dialogue: 0,0:34:17.16,0:34:20.97,Default,,0,0,0,,那么我就返回ALIST中第一个序对 Dialogue: 0,0:34:22.08,0:34:25.50,Default,,0,0,0,,换句话说 这个键匹配了正确的条目 Dialogue: 0,0:34:26.24,0:34:26.97,Default,,0,0,0,,否则的话 Dialogue: 0,0:34:27.08,0:34:28.94,Default,,0,0,0,,我就需要在剩下的表中继续查找 Dialogue: 0,0:34:30.08,0:34:33.31,Default,,0,0,0,,这里有个笔误 很抱歉 Dialogue: 0,0:34:35.19,0:34:36.28,Default,,0,0,0,,好了 不管如何 Dialogue: 0,0:34:37.05,0:34:39.48,Default,,0,0,0,,你们基本上已经看到了全貌 Dialogue: 0,0:34:41.88,0:34:43.29,Default,,0,0,0,,虽然我们的代码风格非常丑陋 Dialogue: 0,0:34:44.19,0:34:46.00,Default,,0,0,0,,但是作为所有语言的核心 Dialogue: 0,0:34:46.76,0:34:48.30,Default,,0,0,0,,它却是非常美妙 Dialogue: 0,0:34:49.60,0:34:51.37,Default,,0,0,0,,我提议 让我们再欣赏一会儿 Dialogue: 0,0:35:00.32,0:35:47.02,Default,,0,0,0,,[音乐] Dialogue: 0,0:35:49.75,0:35:50.91,Default,,0,0,0,,大家有什么问题吗? Dialogue: 0,0:36:01.18,0:36:03.29,Default,,0,0,0,,没有的话就休息一会儿吧 Dialogue: 0,0:36:04.04,0:36:10.73,Default,,0,0,0,,[音乐] Dialogue: 0,0:36:13.88,0:36:17.64,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:36:40.80,0:36:43.93,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:36:43.95,0:36:47.98,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:36:48.06,0:36:51.93,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 I Dialogue: 0,0:36:56.78,0:36:58.99,Default,,0,0,0,,现在 我们将用一个实例 Dialogue: 0,0:36:59.29,0:37:02.67,Default,,0,0,0,,来理解一下求值器的运作过程 Dialogue: 0,0:37:03.47,0:37:05.48,Default,,0,0,0,,我们通过手工进行代换 Dialogue: 0,0:37:05.50,0:37:10.36,Default,,0,0,0,,来深入解释器的详细工作原理 Dialogue: 0,0:37:11.50,0:37:14.94,Default,,0,0,0,,由于我们的求值器不支持赋值和定义 Dialogue: 0,0:37:15.20,0:37:17.34,Default,,0,0,0,,我们也就不用担心副作用 Dialogue: 0,0:37:17.98,0:37:22.03,Default,,0,0,0,,因此我们可以放心大胆地进行代换 Dialogue: 0,0:37:22.52,0:37:24.59,Default,,0,0,0,,不用担心任何副作用 Dialogue: 0,0:37:25.33,0:37:27.80,Default,,0,0,0,,我们将要尝试去手工代换 Dialogue: 0,0:37:28.06,0:37:29.63,Default,,0,0,0,,这个复杂的表达式 Dialogue: 0,0:37:30.69,0:37:34.09,Default,,0,0,0,,(EVAL Dialogue: 0,0:37:34.91,0:37:48.08,Default,,0,0,0,,'(((LAMBDA (X) (LAMBDA (Y) (+ X Y))) Dialogue: 0,0:37:50.30,0:37:52.62,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:37:53.04,0:37:56.12,Default,,0,0,0,,要把它应用在3和4上 Dialogue: 0,0:37:56.94,0:37:59.58,Default,,0,0,0,,求值过程是发生在全局环境E0中的 Dialogue: 0,0:38:04.93,0:38:05.96,Default,,0,0,0,,这里的这个表达式 Dialogue: 0,0:38:06.36,0:38:08.04,Default,,0,0,0,,是个参数为X的一元过程 Dialogue: 0,0:38:08.09,0:38:11.05,Default,,0,0,0,,返回一个参数为Y的一元过程 Dialogue: 0,0:38:11.07,0:38:12.12,Default,,0,0,0,,后者计算X+Y Dialogue: 0,0:38:14.30,0:38:17.96,Default,,0,0,0,,外层的这个过程应用于数字3 Dialogue: 0,0:38:17.96,0:38:19.39,Default,,0,0,0,,所以X应该是3 Dialogue: 0,0:38:21.40,0:38:23.98,Default,,0,0,0,,返回的结果是一个参数为Y的一元过程 Dialogue: 0,0:38:24.33,0:38:25.82,Default,,0,0,0,,该过程将应用于数字4 Dialogue: 0,0:38:28.91,0:38:30.32,Default,,0,0,0,,然后要做的也很简单 Dialogue: 0,0:38:31.04,0:38:32.73,Default,,0,0,0,,计算X+Y即可 Dialogue: 0,0:38:34.79,0:38:35.82,Default,,0,0,0,,具体做之前 Dialogue: 0,0:38:35.84,0:38:37.76,Default,,0,0,0,,先来构造一个非常简单的环境模型 Dialogue: 0,0:38:37.90,0:38:40.48,Default,,0,0,0,,到了现在 我相信你们已经想到 Dialogue: 0,0:38:40.99,0:38:42.59,Default,,0,0,0,,这个过程产生的环境了 Dialogue: 0,0:38:44.46,0:38:46.62,Default,,0,0,0,,我们从全局环境开始 Dialogue: 0,0:38:48.59,0:38:50.06,Default,,0,0,0,,我们把它记作E0 Dialogue: 0,0:38:54.60,0:38:55.47,Default,,0,0,0,,就像这样 Dialogue: 0,0:38:56.74,0:39:02.46,Default,,0,0,0,,里面应该有过程+、*的定义 Dialogue: 0,0:39:06.30,0:39:10.36,Default,,0,0,0,,这里 我们用希腊字母来表示过程对象 这样有趣点 Dialogue: 0,0:39:11.21,0:39:27.93,Default,,0,0,0,,-、/、CAR、CDR、CONS以及EQ? Dialogue: 0,0:39:28.59,0:39:31.05,Default,,0,0,0,,其它需要的基本过程都在全局环境中 Dialogue: 0,0:39:31.27,0:39:33.82,Default,,0,0,0,,每个符号都对应着一个过程对象 Dialogue: 0,0:39:34.62,0:39:36.09,Default,,0,0,0,,这些都是解释器自带的 Dialogue: 0,0:39:37.10,0:39:38.09,Default,,0,0,0,,这就是E0 Dialogue: 0,0:39:39.22,0:39:41.84,Default,,0,0,0,,现在 这个求值要怎样进行呢? Dialogue: 0,0:39:42.94,0:39:45.18,Default,,0,0,0,,我们来看看这些特殊形式 Dialogue: 0,0:39:45.69,0:39:47.05,Default,,0,0,0,,首先 这不是数字 Dialogue: 0,0:39:48.67,0:39:50.38,Default,,0,0,0,,也不是符号 Dialogue: 0,0:39:53.13,0:39:55.60,Default,,0,0,0,,这不是一个引用表达式 Dialogue: 0,0:39:56.60,0:39:58.38,Default,,0,0,0,,虽然外层是一个引用表达式 Dialogue: 0,0:39:59.47,0:40:00.80,Default,,0,0,0,,但并不是我想要去求值的那个 Dialogue: 0,0:40:00.83,0:40:01.36,Default,,0,0,0,,我想问的是 Dialogue: 0,0:40:01.39,0:40:04.96,Default,,0,0,0,,被引用的这个表达式 是否也是个引用表达式? Dialogue: 0,0:40:05.89,0:40:07.96,Default,,0,0,0,,我是在求值一个表达式 Dialogue: 0,0:40:07.96,0:40:09.98,Default,,0,0,0,,这个引号是为了引用这个特定表达式 Dialogue: 0,0:40:11.41,0:40:12.66,Default,,0,0,0,,而被引用的并非引用表达式 Dialogue: 0,0:40:13.71,0:40:17.21,Default,,0,0,0,,当然 它也不是以LAMBDA开头 Dialogue: 0,0:40:19.12,0:40:20.67,Default,,0,0,0,,也不以COND开头 Dialogue: 0,0:40:22.03,0:40:25.95,Default,,0,0,0,,因此它是过程的应用 Dialogue: 0,0:40:26.31,0:40:27.12,Default,,0,0,0,,这是一个组合式 Dialogue: 0,0:40:28.57,0:40:30.70,Default,,0,0,0,,既然它是组合式 Dialogue: 0,0:40:30.89,0:40:34.00,Default,,0,0,0,,这就是它的运算符 Dialogue: 0,0:40:34.64,0:40:36.08,Default,,0,0,0,,而这是它的运算对象 Dialogue: 0,0:40:40.13,0:40:42.41,Default,,0,0,0,,这就意味着 我要 Dialogue: 0,0:40:42.57,0:40:47.90,Default,,0,0,0,,把它转换成 Dialogue: 0,0:40:50.12,0:40:57.61,Default,,0,0,0,,(APPLY (EVAL '((LAMBDA (X) (LAMBDA (y) Dialogue: 0,0:40:57.88,0:40:59.12,Default,,0,0,0,,也就是在E0环境中 Dialogue: 0,0:40:59.95,0:41:04.19,Default,,0,0,0,,求值(+ X Y) Dialogue: 0,0:41:07.26,0:41:08.64,Default,,0,0,0,,不要漏了 Dialogue: 0,0:41:12.78,0:41:15.20,Default,,0,0,0,,要应用到的运算对象则是 Dialogue: 0,0:41:15.26,0:41:17.28,Default,,0,0,0,,用EVLIST求值参数的结果 Dialogue: 0,0:41:21.21,0:41:24.49,Default,,0,0,0,,也就是'(4) Dialogue: 0,0:41:29.01,0:41:31.26,Default,,0,0,0,,我用这个特殊的记号来表示 Dialogue: 0,0:41:32.32,0:41:34.83,Default,,0,0,0,,这是为了指代那个环境 Dialogue: 0,0:41:35.45,0:41:37.77,Default,,0,0,0,,我无法为它命名 Dialogue: 0,0:41:37.80,0:41:39.15,Default,,0,0,0,,因为我没有环境来存放的名字 Dialogue: 0,0:41:41.96,0:41:44.09,Default,,0,0,0,,你当然可以把看作是 Dialogue: 0,0:41:44.17,0:41:46.17,Default,,0,0,0,,某种引用表达式 Dialogue: 0,0:41:47.73,0:41:51.16,Default,,0,0,0,,在那里 它表示环境这种数据结构 Dialogue: 0,0:41:53.04,0:41:55.04,Default,,0,0,0,,好的 这是变换后的结果 Dialogue: 0,0:41:55.85,0:41:56.67,Default,,0,0,0,,为了执行这个表达式 Dialogue: 0,0:41:56.68,0:41:58.04,Default,,0,0,0,,我还得求值这两个表达式 Dialogue: 0,0:41:59.61,0:42:00.49,Default,,0,0,0,,EVLIST简单点 Dialogue: 0,0:42:00.57,0:42:03.18,Default,,0,0,0,,我们先计算这个吧 Dialogue: 0,0:42:03.77,0:42:07.44,Default,,0,0,0,,这就被归约为 Dialogue: 0,0:42:07.45,0:42:08.83,Default,,0,0,0,,上面的某些部分直接抄过来就好 Dialogue: 0,0:42:09.42,0:42:11.00,Default,,0,0,0,,代换的过程中少不了照抄 Dialogue: 0,0:42:18.53,0:42:21.24,Default,,0,0,0,,抄写的时候我就不多加解释了 Dialogue: 0,0:42:21.71,0:42:23.87,Default,,0,0,0,,这样能快一点儿 Dialogue: 0,0:42:26.41,0:42:28.64,Default,,0,0,0,,EVLIST的部分就代换成为 Dialogue: 0,0:42:28.65,0:42:36.72,Default,,0,0,0,,(CONS (EVAL '4 ) Dialogue: 0,0:42:38.78,0:42:40.17,Default,,0,0,0,,因为它不是空表 Dialogue: 0,0:42:41.44,0:42:49.39,Default,,0,0,0,,(EVLIST '() )) Dialogue: 0,0:42:52.58,0:42:54.20,Default,,0,0,0,,我要省略一些步骤了 Dialogue: 0,0:42:54.24,0:42:55.36,Default,,0,0,0,,因为太详细就有些无聊了 Dialogue: 0,0:42:59.87,0:43:05.42,Default,,0,0,0,,下一步跟上面基本上一样 Dialogue: 0,0:43:07.50,0:43:08.54,Default,,0,0,0,,继续照抄 Dialogue: 0,0:43:10.68,0:43:20.24,Default,,0,0,0,,(((LAMBDA (X) (LAMBDA (Y) (+ X Y)) 3) 4) ) Dialogue: 0,0:43:20.24,0:43:21.20,Default,,0,0,0,,看来我还宝刀未老嘛 Dialogue: 0,0:43:24.24,0:43:26.24,Default,,0,0,0,,下面对4求值 Dialogue: 0,0:43:26.56,0:43:28.44,Default,,0,0,0,,4是一个数字 Dialogue: 0,0:43:29.00,0:43:33.90,Default,,0,0,0,,结果就应该是(CONS 4 Dialogue: 0,0:43:34.03,0:43:37.47,Default,,0,0,0,,EVLIST对空表求值 结果也是空表 Dialogue: 0,0:43:38.33,0:43:39.24,Default,,0,0,0,,也就是这个 Dialogue: 0,0:43:42.62,0:43:45.08,Default,,0,0,0,,这个非常容易理解 Dialogue: 0,0:43:45.10,0:43:47.44,Default,,0,0,0,,就是一个只含有4的表 Dialogue: 0,0:43:48.71,0:43:53.84,Default,,0,0,0,,继续代换为 (APPLY (EVAL Dialogue: 0,0:43:55.28,0:44:02.51,Default,,0,0,0,,'((LAMBDA (X) (LAMBDA (Y) (+ X Y)) Dialogue: 0,0:44:03.40,0:44:07.48,Default,,0,0,0,,3) 4) ) Dialogue: 0,0:44:08.68,0:44:12.60,Default,,0,0,0,,应用在'(4)上 这样就完成了 Dialogue: 0,0:44:13.94,0:44:15.05,Default,,0,0,0,,这是这一步的结果 Dialogue: 0,0:44:17.00,0:44:19.96,Default,,0,0,0,,现在让我们进行下一步 更有意思的一步 Dialogue: 0,0:44:20.36,0:44:21.72,Default,,0,0,0,,这行代码要如何求值? Dialogue: 0,0:44:23.07,0:44:24.44,Default,,0,0,0,,为了求值这一部分 Dialogue: 0,0:44:25.20,0:44:28.65,Default,,0,0,0,,我得先求值-- 首先 它不是-- Dialogue: 0,0:44:29.46,0:44:31.04,Default,,0,0,0,,这是一个应用 Dialogue: 0,0:44:31.68,0:44:33.10,Default,,0,0,0,,它并不是特殊形式 Dialogue: 0,0:44:33.57,0:44:36.51,Default,,0,0,0,,如果应用中的运算符 Dialogue: 0,0:44:36.51,0:44:37.37,Default,,0,0,0,,就是这里 Dialogue: 0,0:44:37.66,0:44:38.94,Default,,0,0,0,,这就是运算符 Dialogue: 0,0:44:40.19,0:44:41.77,Default,,0,0,0,,应用在这个运算对象上 Dialogue: 0,0:44:44.54,0:44:45.74,Default,,0,0,0,,形成了一个组合式 Dialogue: 0,0:44:46.72,0:44:48.25,Default,,0,0,0,,现在我们要如何来求值呢? Dialogue: 0,0:44:48.84,0:44:52.37,Default,,0,0,0,,它是COND语句中的最后一种情况 Dialogue: 0,0:44:52.37,0:44:55.52,Default,,0,0,0,,在这步求值中 进行的代换是 Dialogue: 0,0:44:55.71,0:44:57.47,Default,,0,0,0,,把运算符的求值结果 Dialogue: 0,0:44:57.50,0:44:59.00,Default,,0,0,0,,应用在EVLIST的运算对象上 Dialogue: 0,0:45:01.16,0:45:08.20,Default,,0,0,0,,这也就是 (APPLY (APPLY (EVAL Dialogue: 0,0:45:10.57,0:45:21.07,Default,,0,0,0,,'(LAMBDA (X) (LAMBDA (Y) (+ X Y))) Dialogue: 0,0:45:21.80,0:45:23.45,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:45:23.74,0:45:25.42,Default,,0,0,0,,) Dialogue: 0,0:45:30.52,0:45:32.67,Default,,0,0,0,,我就直接给出运算对象的求值结果了 Dialogue: 0,0:45:32.68,0:45:34.14,Default,,0,0,0,,具体过程跟之前是一样的 Dialogue: 0,0:45:35.23,0:45:36.48,Default,,0,0,0,,我有一个表'(3) Dialogue: 0,0:45:36.51,0:45:39.16,Default,,0,0,0,,把它应用于'(4) Dialogue: 0,0:45:42.44,0:45:43.56,Default,,0,0,0,,我们接着看 Dialogue: 0,0:45:44.41,0:45:46.38,Default,,0,0,0,,对一个LAMBDA表达式求值 Dialogue: 0,0:45:48.01,0:45:49.45,Default,,0,0,0,,会产生一个过程对象 Dialogue: 0,0:45:52.03,0:45:57.88,Default,,0,0,0,,继续变换就是 (APPLY (APPLY Dialogue: 0,0:46:00.30,0:46:02.27,Default,,0,0,0,,然后是一个过程对象 '(CLOSURE Dialogue: 0,0:46:04.52,0:46:08.68,Default,,0,0,0,,它里面包含了过程的体 Dialogue: 0,0:46:08.94,0:46:11.92,Default,,0,0,0,,它绑定了变量X Dialogue: 0,0:46:12.13,0:46:15.40,Default,,0,0,0,,然后是函数体内部 Dialogue: 0,0:46:15.80,0:46:18.17,Default,,0,0,0,,它返回一个参数为Y的单参过程 Dialogue: 0,0:46:18.56,0:46:20.63,Default,,0,0,0,,这个过程计算X+Y Dialogue: 0,0:46:23.21,0:46:25.50,Default,,0,0,0,,这个过程对象捕获了环境 Dialogue: 0,0:46:27.24,0:46:29.63,Default,,0,0,0,,因为这些求值都是在中发生的 Dialogue: 0,0:46:30.11,0:46:32.43,Default,,0,0,0,,现在 也是CLOSURE对象的一部分 Dialogue: 0,0:46:33.04,0:46:38.19,Default,,0,0,0,,先应用于'(3) Dialogue: 0,0:46:38.81,0:46:41.30,Default,,0,0,0,,再应用于'(4) Dialogue: 0,0:46:47.39,0:46:49.29,Default,,0,0,0,,在这步到这步的过程中 Dialogue: 0,0:46:49.31,0:46:50.89,Default,,0,0,0,,我构建了一个过程对象 Dialogue: 0,0:46:50.91,0:46:52.03,Default,,0,0,0,,它捕获了 Dialogue: 0,0:46:53.88,0:46:55.98,Default,,0,0,0,,并将其作为本身的一部分 Dialogue: 0,0:46:57.15,0:46:58.51,Default,,0,0,0,,现在 要把它们传递给APPLY了 Dialogue: 0,0:46:58.52,0:46:59.71,Default,,0,0,0,,我们得把这个过程 Dialogue: 0,0:47:00.48,0:47:01.58,Default,,0,0,0,,应用在对应的参数上 Dialogue: 0,0:47:02.71,0:47:06.51,Default,,0,0,0,,这里的过程并不是基本过程 Dialogue: 0,0:47:07.38,0:47:09.88,Default,,0,0,0,,它有一个类型标志'CLOSURE Dialogue: 0,0:47:10.24,0:47:12.09,Default,,0,0,0,,因此还需要进行参数绑定 Dialogue: 0,0:47:13.71,0:47:14.72,Default,,0,0,0,,必须要绑定 Dialogue: 0,0:47:15.83,0:47:19.40,Default,,0,0,0,,在这里构造的新环境 Dialogue: 0,0:47:20.44,0:47:22.80,Default,,0,0,0,,它有一个父环境 Dialogue: 0,0:47:22.94,0:47:27.56,Default,,0,0,0,,父环境是这里的 Dialogue: 0,0:47:30.32,0:47:31.57,Default,,0,0,0,,我们把新环境记作 Dialogue: 0,0:47:34.62,0:47:35.74,Default,,0,0,0,,这里要绑定些什么呢? Dialogue: 0,0:47:36.04,0:47:37.48,Default,,0,0,0,,变量X绑定为值3 Dialogue: 0,0:47:38.62,0:47:40.44,Default,,0,0,0,,这里写X=3 Dialogue: 0,0:47:41.48,0:47:42.33,Default,,0,0,0,,就是这些 Dialogue: 0,0:47:44.94,0:47:46.24,Default,,0,0,0,,新环境记作E1 Dialogue: 0,0:47:46.24,0:47:48.44,Default,,0,0,0,,而这个表达式会变换为 Dialogue: 0,0:47:49.13,0:47:50.72,Default,,0,0,0,,对一个过程体的求值 Dialogue: 0,0:47:51.72,0:47:53.07,Default,,0,0,0,,就是这个 在这里 Dialogue: 0,0:47:54.40,0:47:55.72,Default,,0,0,0,,这个过程的体 Dialogue: 0,0:47:56.44,0:47:58.52,Default,,0,0,0,,在刚才创建的中进行求值 Dialogue: 0,0:48:00.29,0:48:05.05,Default,,0,0,0,,也就是 (APPLY (EVAL Dialogue: 0,0:48:06.92,0:48:16.43,Default,,0,0,0,,'(LAMBDA (Y) (+ X Y)) ) Dialogue: 0,0:48:20.49,0:48:22.48,Default,,0,0,0,,把求值的结果应用于4 Dialogue: 0,0:48:23.68,0:48:26.73,Default,,0,0,0,,也就是'(4) Dialogue: 0,0:48:28.43,0:48:29.87,Default,,0,0,0,,到了这里就很清晰了 Dialogue: 0,0:48:30.08,0:48:32.27,Default,,0,0,0,,我知道该如何求值LAMBDA表达式 Dialogue: 0,0:48:33.11,0:48:34.17,Default,,0,0,0,,也就是(APPLY Dialogue: 0,0:48:37.16,0:48:38.92,Default,,0,0,0,,一个过程对象'(CLOSURE Dialogue: 0,0:48:43.74,0:48:46.84,Default,,0,0,0,,它绑定参数Y 计算X+Y Dialogue: 0,0:48:49.28,0:48:52.15,Default,,0,0,0,,并且捕获了环境 Dialogue: 0,0:48:55.79,0:48:57.42,Default,,0,0,0,,你应该已经见过了 对吧? Dialogue: 0,0:48:57.80,0:49:00.14,Default,,0,0,0,,我构造了一个CLOSURE对象 Dialogue: 0,0:49:00.14,0:49:01.16,Default,,0,0,0,,放在这里 Dialogue: 0,0:49:01.79,0:49:03.04,Default,,0,0,0,,之前的那个也是 Dialogue: 0,0:49:05.90,0:49:07.47,Default,,0,0,0,,这是现在的这个 Dialogue: 0,0:49:08.08,0:49:09.80,Default,,0,0,0,,它捕获了环境 Dialogue: 0,0:49:10.41,0:49:14.25,Default,,0,0,0,,而这个是参数为Y的一元过程 Dialogue: 0,0:49:15.45,0:49:16.70,Default,,0,0,0,,先不管它具体是什么 Dialogue: 0,0:49:18.09,0:49:20.72,Default,,0,0,0,,我们只知道它是一个CLOSURE Dialogue: 0,0:49:22.57,0:49:26.46,Default,,0,0,0,,将这个过程应用于'(4) Dialogue: 0,0:49:30.28,0:49:31.77,Default,,0,0,0,,很简单 Dialogue: 0,0:49:36.83,0:49:38.73,Default,,0,0,0,,我需要通过复制一个指针 Dialogue: 0,0:49:38.86,0:49:40.52,Default,,0,0,0,,就是这个过程的指针 Dialogue: 0,0:49:41.56,0:49:43.21,Default,,0,0,0,,来构造一个新环境 Dialogue: 0,0:49:44.94,0:49:48.96,Default,,0,0,0,,同时还得把参数Y跟值4绑定 Dialogue: 0,0:49:49.82,0:49:52.22,Default,,0,0,0,,我把这个新环境 记作 Dialogue: 0,0:49:56.03,0:49:58.12,Default,,0,0,0,,当然 这里的这个应用 Dialogue: 0,0:49:58.22,0:50:00.33,Default,,0,0,0,,其过程体的求值 是在中进行的 Dialogue: 0,0:50:01.58,0:50:07.87,Default,,0,0,0,,所以这就变成了对过程体的求值 Dialogue: 0,0:50:07.90,0:50:11.85,Default,,0,0,0,,也就是 (EVAL '(+ X Y) ) Dialogue: 0,0:50:13.71,0:50:14.94,Default,,0,0,0,,但由于这是一个应用 Dialogue: 0,0:50:15.48,0:50:23.88,Default,,0,0,0,,所以又代换为 (APPLY (EVAL '+ ) Dialogue: 0,0:50:26.33,0:50:37.34,Default,,0,0,0,,(EVLIST '(X Y) )) Dialogue: 0,0:50:44.88,0:50:45.59,Default,,0,0,0,,我们来看 Dialogue: 0,0:50:45.59,0:50:51.71,Default,,0,0,0,,下一步代换为 (APPLY Dialogue: 0,0:50:52.08,0:50:53.87,Default,,0,0,0,,求值‘+得到的结果 Dialogue: 0,0:50:54.19,0:50:55.66,Default,,0,0,0,,所以我们从开始找 Dialogue: 0,0:50:55.69,0:50:57.72,Default,,0,0,0,,'+既不在 也不在 Dialogue: 0,0:50:57.74,0:51:01.05,Default,,0,0,0,,‘+是中的基本运算符 Dialogue: 0,0:51:01.78,0:51:04.74,Default,,0,0,0,,这个基本运算符是用于加法的 Dialogue: 0,0:51:07.47,0:51:14.12,Default,,0,0,0,,把它应用于 在中求值X和Y的结果 Dialogue: 0,0:51:14.37,0:51:17.00,Default,,0,0,0,,我们知道X是3 Y是4 Dialogue: 0,0:51:18.11,0:51:23.31,Default,,0,0,0,,所以这里是'(3 4) Dialogue: 0,0:51:24.16,0:51:26.28,Default,,0,0,0,,然后就神奇地得到结果7 Dialogue: 0,0:51:30.52,0:51:32.44,Default,,0,0,0,,我再来整理一下这个过程 这样你们 Dialogue: 0,0:51:32.70,0:51:34.73,Default,,0,0,0,,就能了解这其中的重要本质 Dialogue: 0,0:51:35.76,0:51:37.29,Default,,0,0,0,,这个过程中传递了些什么? Dialogue: 0,0:51:37.31,0:51:39.56,Default,,0,0,0,,每个模块持有什么 又负责什么? Dialogue: 0,0:51:40.47,0:51:41.61,Default,,0,0,0,,有哪些模块呢? Dialogue: 0,0:51:41.70,0:51:42.62,Default,,0,0,0,,一个是EVAL Dialogue: 0,0:51:44.80,0:51:45.64,Default,,0,0,0,,还有个APPLY Dialogue: 0,0:51:45.66,0:51:46.62,Default,,0,0,0,,两个主要角色 Dialogue: 0,0:51:49.37,0:51:51.56,Default,,0,0,0,,它们之间有个像这样的大循环 Dialogue: 0,0:51:52.32,0:52:04.57,Default,,0,0,0,,其中 EVAL为APPLY生成过程和参数 Dialogue: 0,0:52:06.27,0:52:08.57,Default,,0,0,0,,也有些事情 EVAL也可以自己做 Dialogue: 0,0:52:09.50,0:52:10.86,Default,,0,0,0,,都是一些细小的事情 Dialogue: 0,0:52:10.86,0:52:11.74,Default,,0,0,0,,并不十分有趣 Dialogue: 0,0:52:12.70,0:52:15.60,Default,,0,0,0,,同时 EVAL也逐个求值所有的参数 Dialogue: 0,0:52:16.24,0:52:17.28,Default,,0,0,0,,也没什么意思 Dialogue: 0,0:52:17.65,0:52:20.09,Default,,0,0,0,,APPLY可以应用像+这类的过程 Dialogue: 0,0:52:21.02,0:52:22.04,Default,,0,0,0,,这很普通 Dialogue: 0,0:52:22.30,0:52:24.64,Default,,0,0,0,,然而 如果APPLY不能应用像+这样的过程 Dialogue: 0,0:52:25.31,0:52:33.31,Default,,0,0,0,,它就为EVAL生成一个表达式及相应的环境 Dialogue: 0,0:52:35.47,0:52:37.61,Default,,0,0,0,,过程的参数封装了 Dialogue: 0,0:52:38.24,0:52:40.60,Default,,0,0,0,,计算所必需的状态 Dialogue: 0,0:52:41.66,0:52:43.42,Default,,0,0,0,,以及相应的环境 Dialogue: 0,0:52:43.74,0:52:45.31,Default,,0,0,0,,但我们接下来要做的 Dialogue: 0,0:52:45.32,0:52:46.46,Default,,0,0,0,,并不是完整的状态 Dialogue: 0,0:52:46.48,0:52:48.82,Default,,0,0,0,,因为它没有说明谁需要返回的结果 Dialogue: 0,0:52:51.28,0:52:52.20,Default,,0,0,0,,我们要做的就是 Dialogue: 0,0:52:52.24,0:52:54.80,Default,,0,0,0,,总是把某个表达式以及相应的环境 Dialogue: 0,0:52:54.99,0:52:56.14,Default,,0,0,0,,或者过程对象以及其参数 Dialogue: 0,0:52:56.28,0:52:58.08,Default,,0,0,0,,在这个循环之间不断传递 Dialogue: 0,0:52:58.97,0:53:01.80,Default,,0,0,0,,这里还有一些小型的子循环 比如EVLIST Dialogue: 0,0:53:04.49,0:53:06.76,Default,,0,0,0,,又或者是EVAL中的EVCOND循环 Dialogue: 0,0:53:09.10,0:53:11.96,Default,,0,0,0,,甚至于APPLY调用PRIMITIVE-APPLY Dialogue: 0,0:53:16.14,0:53:17.64,Default,,0,0,0,,但是它们并不是最主要的 Dialogue: 0,0:53:18.86,0:53:20.28,Default,,0,0,0,,这整个就是我想让你们看到的 Dialogue: 0,0:53:21.86,0:53:22.88,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:53:25.93,0:53:27.37,Default,,0,0,0,,David 请说 Dialogue: 0,0:53:27.74,0:53:33.31,Default,,0,0,0,,学生:我不明白为什么X是3 Dialogue: 0,0:53:34.01,0:53:36.30,Default,,0,0,0,,而不是4 Dialogue: 0,0:53:37.07,0:53:38.52,Default,,0,0,0,,在那个部分 Dialogue: 0,0:53:38.56,0:53:40.54,Default,,0,0,0,,教授:是在这里 Dialogue: 0,0:53:41.31,0:53:43.31,Default,,0,0,0,,你想知道X是如何跟3绑定的 Dialogue: 0,0:53:43.52,0:53:47.42,Default,,0,0,0,,学生:因为X是外层过程的参数 Dialogue: 0,0:53:48.46,0:53:50.99,Default,,0,0,0,,而内层过程中既有X又有Y Dialogue: 0,0:53:51.26,0:53:51.88,Default,,0,0,0,,教授:明白了 Dialogue: 0,0:53:52.84,0:53:54.62,Default,,0,0,0,,代换的过程中 我已经非常小心了 Dialogue: 0,0:53:55.02,0:53:56.92,Default,,0,0,0,,或许首先 我应该把这些过程 Dialogue: 0,0:53:56.94,0:53:58.41,Default,,0,0,0,,重新编排得更易读一点 Dialogue: 0,0:54:00.61,0:54:01.47,Default,,0,0,0,,你之所以有所疑惑 Dialogue: 0,0:54:01.48,0:54:02.99,Default,,0,0,0,,或许是因为你把程序看岔了 Dialogue: 0,0:54:03.83,0:54:04.70,Default,,0,0,0,,所以这里应该是 Dialogue: 0,0:54:05.15,0:54:09.60,Default,,0,0,0,,一个以X为参数的过程 Dialogue: 0,0:54:11.21,0:54:14.99,Default,,0,0,0,,它返回一个以Y为参数的过程 Dialogue: 0,0:54:15.72,0:54:18.44,Default,,0,0,0,,后者计算X+Y Dialogue: 0,0:54:19.82,0:54:21.10,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:54:21.40,0:54:22.89,Default,,0,0,0,,外面的过程应用到3上 Dialogue: 0,0:54:24.08,0:54:26.12,Default,,0,0,0,,把得到的结果应用到4上 Dialogue: 0,0:54:26.14,0:54:28.81,Default,,0,0,0,,这个和之前那个是一样的 对吧? Dialogue: 0,0:54:28.81,0:54:32.33,Default,,0,0,0,,现在 你可以立马发现 Dialogue: 0,0:54:33.77,0:54:34.94,Default,,0,0,0,,这里是一个应用 Dialogue: 0,0:54:35.16,0:54:36.46,Default,,0,0,0,,我先换根白粉笔 Dialogue: 0,0:54:37.32,0:54:41.12,Default,,0,0,0,,这一部分是应用 是一个组合式 Dialogue: 0,0:54:43.44,0:54:46.40,Default,,0,0,0,,这部分是组合式的运算符 Dialogue: 0,0:54:48.14,0:54:49.55,Default,,0,0,0,,而这是运算对象 Dialogue: 0,0:54:51.04,0:54:53.05,Default,,0,0,0,,这个3会跟这里的X绑定 Dialogue: 0,0:54:54.90,0:54:56.36,Default,,0,0,0,,而这个组合式的结果 Dialogue: 0,0:54:56.56,0:54:58.46,Default,,0,0,0,,是一个参数为Y的一元过程 Dialogue: 0,0:54:58.73,0:54:59.79,Default,,0,0,0,,它将应用于4 Dialogue: 0,0:55:00.88,0:55:01.58,Default,,0,0,0,,明白了吧? Dialogue: 0,0:55:02.20,0:55:04.08,Default,,0,0,0,,所以你可能只是看岔了 Dialogue: 0,0:55:04.40,0:55:07.85,Default,,0,0,0,,而你们在这里看到的 Dialogue: 0,0:55:09.42,0:55:12.96,Default,,0,0,0,,是一个实际的过程对象 它有一个参数X Dialogue: 0,0:55:13.34,0:55:15.31,Default,,0,0,0,,这个CLOSURE将应用于3 Dialogue: 0,0:55:15.95,0:55:17.07,Default,,0,0,0,,也就是'(3) Dialogue: 0,0:55:18.98,0:55:21.34,Default,,0,0,0,,得到的结果再应用于'(4) Dialogue: 0,0:55:24.08,0:55:25.20,Default,,0,0,0,,还有疑问吗? Dialogue: 0,0:55:28.35,0:55:30.38,Default,,0,0,0,,那就休息一下吧 Dialogue: 0,0:55:30.83,0:55:31.37,Default,,0,0,0,,谢谢大家 Dialogue: 0,0:55:33.73,0:55:41.40,Default,,0,0,0,,[音乐] Dialogue: 0,0:55:42.12,0:55:47.44,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:55:50.70,0:55:54.08,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:55:54.12,0:55:59.16,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:55:59.23,0:56:03.95,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 I Dialogue: 0,0:56:08.41,0:56:11.29,Default,,0,0,0,,教授:课上到这里 Dialogue: 0,0:56:13.32,0:56:14.59,Default,,0,0,0,,你们可能开始觉得 Dialogue: 0,0:56:14.75,0:56:17.96,Default,,0,0,0,,Sussman教授又在胡说八道些什么 Dialogue: 0,0:56:20.74,0:56:23.92,Default,,0,0,0,,他讲的东西奇怪、愚蠢又毫无意义 Dialogue: 0,0:56:24.80,0:56:27.40,Default,,0,0,0,,他还宣称要给我们解释Lisp Dialogue: 0,0:56:28.01,0:56:29.90,Default,,0,0,0,,然后在黑板上给我们写了一个Lisp程序 Dialogue: 0,0:56:31.23,0:56:33.53,Default,,0,0,0,,他还说:“这个Lisp程序就是Lisp解释器” Dialogue: 0,0:56:33.85,0:56:35.02,Default,,0,0,0,,但是为了运行这个Lisp程序 Dialogue: 0,0:56:35.04,0:56:36.30,Default,,0,0,0,,你还先得有一个Lisp解释器啊 Dialogue: 0,0:56:38.37,0:56:40.19,Default,,0,0,0,,那个程序怎么能告诉我 Dialogue: 0,0:56:40.22,0:56:43.20,Default,,0,0,0,,有关于Lisp的知识呢? Dialogue: 0,0:56:44.15,0:56:46.22,Default,,0,0,0,,它为什么又不是空中楼阁呢? Dialogue: 0,0:56:48.49,0:56:50.25,Default,,0,0,0,,这件事非常奇怪 Dialogue: 0,0:56:50.99,0:56:52.43,Default,,0,0,0,,它究竟告诉了我什么? Dialogue: 0,0:56:56.07,0:56:57.20,Default,,0,0,0,,我们发现 其实这整件事 Dialogue: 0,0:56:57.32,0:56:59.79,Default,,0,0,0,,非常像我们在这张幻灯片上看到的 Dialogue: 0,0:57:00.46,0:57:03.55,Default,,0,0,0,,Escher所画的手 Dialogue: 0,0:57:06.18,0:57:07.72,Default,,0,0,0,,是的 EVAL和APPLY Dialogue: 0,0:57:07.76,0:57:10.16,Default,,0,0,0,,彼此画出彼此 Dialogue: 0,0:57:11.50,0:57:14.16,Default,,0,0,0,,并且构造出了真实的东西 Dialogue: 0,0:57:14.86,0:57:16.30,Default,,0,0,0,,它完全是自己画出了自己 Dialogue: 0,0:57:17.11,0:57:18.46,Default,,0,0,0,,Escher真是绝顶聪明 Dialogue: 0,0:57:18.68,0:57:20.41,Default,,0,0,0,,他只不过叫不出这些精灵的名字 Dialogue: 0,0:57:23.91,0:57:25.00,Default,,0,0,0,,我现在要做的就是 Dialogue: 0,0:57:26.09,0:57:28.00,Default,,0,0,0,,使你们相信 Dialogue: 0,0:57:28.16,0:57:29.87,Default,,0,0,0,,这一切都是有意义的 Dialogue: 0,0:57:30.16,0:57:31.98,Default,,0,0,0,,并且 Dialogue: 0,0:57:32.99,0:57:34.72,Default,,0,0,0,,我将要解释为什么我们不需要DEFINE Dialogue: 0,0:57:36.09,0:57:37.71,Default,,0,0,0,,事实证明 我们并不需要DEFINE Dialogue: 0,0:57:38.09,0:57:41.12,Default,,0,0,0,,为了进行数学意义上的计算 Dialogue: 0,0:57:42.51,0:57:44.89,Default,,0,0,0,,DEFINE并不是必需的 Dialogue: 0,0:57:49.10,0:57:50.03,Default,,0,0,0,,我们来看一下 Dialogue: 0,0:57:50.69,0:57:53.31,Default,,0,0,0,,考虑下面的一小段程序 Dialogue: 0,0:57:53.74,0:57:54.64,Default,,0,0,0,,它有什么作用? Dialogue: 0,0:57:54.87,0:57:57.64,Default,,0,0,0,,这是一个计算指数的程序 Dialogue: 0,0:58:07.27,0:58:13.23,Default,,0,0,0,,EXPT计算X的N次方 Dialogue: 0,0:58:16.83,0:58:18.12,Default,,0,0,0,,如果N为0 Dialogue: 0,0:58:19.20,0:58:20.76,Default,,0,0,0,,那么结果就是1 Dialogue: 0,0:58:22.07,0:58:22.81,Default,,0,0,0,,否则 Dialogue: 0,0:58:25.56,0:58:28.48,Default,,0,0,0,,结果就是X乘以 Dialogue: 0,0:58:28.75,0:58:33.93,Default,,0,0,0,,(EXPT X (- N 1)))) Dialogue: 0,0:58:43.69,0:58:44.56,Default,,0,0,0,,应该没错 Dialogue: 0,0:58:46.63,0:58:48.72,Default,,0,0,0,,一个递归定义 Dialogue: 0,0:58:49.47,0:58:52.17,Default,,0,0,0,,用EXPT自身 Dialogue: 0,0:58:52.46,0:58:54.78,Default,,0,0,0,,来定义EXPT过程自己 Dialogue: 0,0:58:56.41,0:58:58.32,Default,,0,0,0,,就像我之前说的那样 Dialogue: 0,0:58:59.28,0:59:01.68,Default,,0,0,0,,你们高中数学老师在教这些东西的时候 Dialogue: 0,0:59:01.84,0:59:04.04,Default,,0,0,0,,你们一定学得很痛苦 Dialogue: 0,0:59:05.65,0:59:06.73,Default,,0,0,0,,这样定义合理吗? Dialogue: 0,0:59:07.91,0:59:10.84,Default,,0,0,0,,为什么这种自引用的定义 Dialogue: 0,0:59:10.96,0:59:12.04,Default,,0,0,0,,能够说得通呢? Dialogue: 0,0:59:13.43,0:59:15.10,Default,,0,0,0,,首先我要说的是 Dialogue: 0,0:59:15.13,0:59:17.60,Default,,0,0,0,,你们高中数学老师并非在胡说八道 Dialogue: 0,0:59:20.37,0:59:23.42,Default,,0,0,0,,考虑下面的几组定义 Dialogue: 0,0:59:24.27,0:59:27.42,Default,,0,0,0,,X+Y=3 Dialogue: 0,0:59:28.24,0:59:32.24,Default,,0,0,0,,X-Y=1 Dialogue: 0,0:59:33.07,0:59:35.56,Default,,0,0,0,,这个方程用Y来告诉你X Dialogue: 0,0:59:35.58,0:59:37.84,Default,,0,0,0,,而这个方程或许是用X来告诉你Y Dialogue: 0,0:59:40.15,0:59:42.95,Default,,0,0,0,,碰巧这组方程有唯一的解 Dialogue: 0,0:59:55.91,0:59:58.11,Default,,0,0,0,,然而 我也可能有这样的方程 Dialogue: 0,0:59:59.87,1:00:04.25,Default,,0,0,0,,2X+2Y=6 Dialogue: 0,1:00:06.83,1:00:09.87,Default,,0,0,0,,这两个方程有无穷多个解 Dialogue: 0,1:00:15.73,1:00:17.42,Default,,0,0,0,,我还可以有像这样的方程 Dialogue: 0,1:00:18.89,1:00:21.53,Default,,0,0,0,,X-Y=2 Dialogue: 0,1:00:22.14,1:00:24.41,Default,,0,0,0,,而下面的这两个方程没有解 Dialogue: 0,1:00:29.82,1:00:33.04,Default,,0,0,0,,这里 我有三组线性方程组 Dialogue: 0,1:00:35.45,1:00:39.51,Default,,0,0,0,,分别是这组、这组和这组 Dialogue: 0,1:00:39.88,1:00:41.79,Default,,0,0,0,,它们的解的数目完全不同 Dialogue: 0,1:00:42.90,1:00:45.76,Default,,0,0,0,,解的数目并不取决于方程的形式 Dialogue: 0,1:00:46.33,1:00:48.20,Default,,0,0,0,,三组方程都有一样的形式 Dialogue: 0,1:00:48.54,1:00:50.41,Default,,0,0,0,,解的数目取决于方程的内容 Dialogue: 0,1:00:53.00,1:00:55.15,Default,,0,0,0,,我不能通过观察方程的形式 Dialogue: 0,1:00:55.16,1:00:56.24,Default,,0,0,0,,来判断解的数目 Dialogue: 0,1:00:56.86,1:00:58.60,Default,,0,0,0,,必须要看它的内容 Dialogue: 0,1:00:59.66,1:01:00.88,Default,,0,0,0,,比如 对于线性方程组 Dialogue: 0,1:01:01.34,1:01:03.39,Default,,0,0,0,,它的系数都是什么? Dialogue: 0,1:01:05.10,1:01:06.72,Default,,0,0,0,,我不能够通过观察 Dialogue: 0,1:01:06.99,1:01:08.33,Default,,0,0,0,,像这样的简单情况 Dialogue: 0,1:01:08.59,1:01:09.95,Default,,0,0,0,,来判定 Dialogue: 0,1:01:10.08,1:01:14.49,Default,,0,0,0,,EXPT就是这个递归方程的解 Dialogue: 0,1:01:16.03,1:01:18.41,Default,,0,0,0,,我不能说 EXPT就是那个过程 Dialogue: 0,1:01:18.91,1:01:21.10,Default,,0,0,0,,如果我们把它代换入其中 Dialogue: 0,1:01:22.04,1:01:24.06,Default,,0,0,0,,它就能给我们返回EXPT Dialogue: 0,1:01:25.32,1:01:25.68,Default,,0,0,0,,能跟上吗? Dialogue: 0,1:01:26.04,1:01:29.24,Default,,0,0,0,,通过观察这个形式 我也无法判别 Dialogue: 0,1:01:29.80,1:01:32.60,Default,,0,0,0,,EXPT是否有唯一解 Dialogue: 0,1:01:33.23,1:01:35.31,Default,,0,0,0,,有无穷个解 还是根本没有解 Dialogue: 0,1:01:37.20,1:01:38.62,Default,,0,0,0,,我们要了解它是如何计数的 Dialogue: 0,1:01:38.64,1:01:40.14,Default,,0,0,0,,或者是一些类似的计算细节 Dialogue: 0,1:01:40.60,1:01:42.75,Default,,0,0,0,,这可比在线性代数难多了 Dialogue: 0,1:01:43.28,1:01:45.21,Default,,0,0,0,,程序设计中可用的定理并不多 Dialogue: 0,1:01:48.45,1:01:51.21,Default,,0,0,0,,我想把这些方程稍稍重写一下 Dialogue: 0,1:01:51.93,1:01:53.77,Default,,0,0,0,,就是这里的方程 Dialogue: 0,1:01:53.97,1:01:56.62,Default,,0,0,0,,因为我们要研究的是这种形式的方程 Dialogue: 0,1:01:57.00,1:01:58.38,Default,,0,0,0,,但是我想用我们比较了解的方程 Dialogue: 0,1:01:58.40,1:01:59.53,Default,,0,0,0,,来做演示 Dialogue: 0,1:02:00.70,1:02:02.91,Default,,0,0,0,,以便于对于这类问题有深入的洞见 Dialogue: 0,1:02:04.72,1:02:06.43,Default,,0,0,0,,我们可以把这里的方程 改写为 Dialogue: 0,1:02:06.75,1:02:08.67,Default,,0,0,0,,这样的一种有趣形式 Dialogue: 0,1:02:09.77,1:02:14.86,Default,,0,0,0,,X=3-Y Dialogue: 0,1:02:15.88,1:02:19.68,Default,,0,0,0,,Y=X-1 Dialogue: 0,1:02:22.01,1:02:24.05,Default,,0,0,0,,我们把这种变换叫什么来着? Dialogue: 0,1:02:24.05,1:02:26.52,Default,,0,0,0,,这是一个线性变换 记为T Dialogue: 0,1:02:29.43,1:02:32.25,Default,,0,0,0,,我们这里就得到了一个方程 Dialogue: 0,1:02:32.97,1:02:37.37,Default,,0,0,0,, = T Dialogue: 0,1:02:42.99,1:02:43.98,Default,,0,0,0,,我要去找什么呢? Dialogue: 0,1:02:44.56,1:02:46.01,Default,,0,0,0,,我在找T的不动点 Dialogue: 0,1:02:46.97,1:02:59.42,Default,,0,0,0,,T的不动点就是方程的解 Dialogue: 0,1:03:01.91,1:03:05.53,Default,,0,0,0,,所以 如果我们能通过找不动点 Dialogue: 0,1:03:05.90,1:03:07.48,Default,,0,0,0,,来求解方程 Dialogue: 0,1:03:08.65,1:03:09.87,Default,,0,0,0,,这看来是可行的 Dialogue: 0,1:03:10.88,1:03:12.36,Default,,0,0,0,,如果我可以用不动点 Dialogue: 0,1:03:12.38,1:03:14.32,Default,,0,0,0,,来求解方程 Dialogue: 0,1:03:15.52,1:03:18.19,Default,,0,0,0,,当然 也许它不可行 Dialogue: 0,1:03:18.57,1:03:19.80,Default,,0,0,0,,不过也可以借鉴来 Dialogue: 0,1:03:20.09,1:03:22.27,Default,,0,0,0,,研究如何求解这类方程 Dialogue: 0,1:03:27.24,1:03:29.48,Default,,0,0,0,,重要的是 我想让你们把它看成一个方程 Dialogue: 0,1:03:30.26,1:03:31.21,Default,,0,0,0,,它是一个表达式 Dialogue: 0,1:03:31.36,1:03:33.58,Default,,0,0,0,,其中有不同的变量 Dialogue: 0,1:03:34.70,1:03:37.66,Default,,0,0,0,,只不过这些名字还得满足一定的约束 Dialogue: 0,1:03:38.43,1:03:40.52,Default,,0,0,0,,这些名字限定了对应变量的取值 Dialogue: 0,1:03:41.48,1:03:45.01,Default,,0,0,0,,我们不能够随意、机械地代换 Dialogue: 0,1:03:47.74,1:03:49.77,Default,,0,0,0,,这就是我尝试求解的方程 Dialogue: 0,1:03:51.22,1:03:52.43,Default,,0,0,0,,我们来试试看 Dialogue: 0,1:03:53.96,1:03:55.66,Default,,0,0,0,,首先我需要写下 Dialogue: 0,1:03:56.64,1:03:59.00,Default,,0,0,0,,跟T相对应的函数 Dialogue: 0,1:04:00.32,1:04:03.00,Default,,0,0,0,,我写下的这个T对应的函数 Dialogue: 0,1:04:04.49,1:04:06.96,Default,,0,0,0,,它的不动点就是这个方程的解 Dialogue: 0,1:04:10.76,1:04:11.28,Default,,0,0,0,,能明白吗? Dialogue: 0,1:04:12.25,1:04:14.30,Default,,0,0,0,,让我们来看下面这个过程F Dialogue: 0,1:04:16.87,1:04:18.30,Default,,0,0,0,,我说 F计算的是这样一个函数 Dialogue: 0,1:04:19.34,1:04:22.91,Default,,0,0,0,,F本身是一个参数为G的一元过程 Dialogue: 0,1:04:25.23,1:04:25.93,Default,,0,0,0,,它返回 Dialogue: 0,1:04:26.40,1:04:32.00,Default,,0,0,0,,一个参数为X和N的过程 Dialogue: 0,1:04:33.43,1:04:34.73,Default,,0,0,0,,这个过程的定义是: Dialogue: 0,1:04:36.72,1:04:40.43,Default,,0,0,0,,如果N为0 Dialogue: 0,1:04:41.72,1:04:43.20,Default,,0,0,0,,那么结果就是1 Dialogue: 0,1:04:45.34,1:04:46.17,Default,,0,0,0,,否则的话 Dialogue: 0,1:04:49.90,1:05:01.40,Default,,0,0,0,,结果就是(* X (G X (- N 1))) Dialogue: 0,1:05:03.37,1:05:07.80,Default,,0,0,0,,(闭合括号中) Dialogue: 0,1:05:08.94,1:05:09.40,Default,,0,0,0,,没问题吧 Dialogue: 0,1:05:12.30,1:05:14.62,Default,,0,0,0,,这里 F是一个过程 Dialogue: 0,1:05:15.05,1:05:17.79,Default,,0,0,0,,如果我能解出这个方程 Dialogue: 0,1:05:19.04,1:05:22.04,Default,,0,0,0,,如果我找到了一个良好的指数过程 Dialogue: 0,1:05:23.42,1:05:26.32,Default,,0,0,0,,我把这个F应用到那个过程上 Dialogue: 0,1:05:27.60,1:05:31.24,Default,,0,0,0,,那么返回的应该也是一个良好的指数过程 Dialogue: 0,1:05:37.46,1:05:38.57,Default,,0,0,0,,这是为什么呢? Dialogue: 0,1:05:39.42,1:05:40.88,Default,,0,0,0,,这是因为 Dialogue: 0,1:05:42.36,1:05:44.64,Default,,0,0,0,,F假设G是一个良好的指数过程 Dialogue: 0,1:05:45.63,1:05:47.58,Default,,0,0,0,,那么这里就会返回 Dialogue: 0,1:05:47.84,1:05:49.68,Default,,0,0,0,,一个参数为X和N的过程 Dialogue: 0,1:05:50.49,1:05:51.52,Default,,0,0,0,,其中如果N=0 Dialogue: 0,1:05:51.55,1:05:52.41,Default,,0,0,0,,结果就是1 Dialogue: 0,1:05:52.44,1:05:54.16,Default,,0,0,0,,这是非常符合定义的 Dialogue: 0,1:05:54.64,1:05:57.05,Default,,0,0,0,,否则 就返回X乘以 Dialogue: 0,1:05:57.26,1:05:59.26,Default,,0,0,0,,用给定的指数过程G Dialogue: 0,1:06:00.17,1:06:02.44,Default,,0,0,0,,计算(G X (- N 1)) Dialogue: 0,1:06:03.47,1:06:04.78,Default,,0,0,0,,因此如果G能够 Dialogue: 0,1:06:04.81,1:06:06.30,Default,,0,0,0,,正确计算X^(N-1) Dialogue: 0,1:06:07.87,1:06:11.28,Default,,0,0,0,,那么这个表达式就能正确计算X^N Dialogue: 0,1:06:12.17,1:06:14.41,Default,,0,0,0,,所以整个就会是一个正确的求指数过程 Dialogue: 0,1:06:17.50,1:06:19.82,Default,,0,0,0,,因此 我在这里真正想指出的是 Dialogue: 0,1:06:21.02,1:06:32.44,Default,,0,0,0,,过程EXPT是函数F的不动点 Dialogue: 0,1:06:36.99,1:06:38.35,Default,,0,0,0,,现在我们的问题在于 Dialogue: 0,1:06:38.35,1:06:39.68,Default,,0,0,0,,不动点可能不止一个 Dialogue: 0,1:06:40.06,1:06:42.19,Default,,0,0,0,,也可能没有不动点 Dialogue: 0,1:06:43.27,1:06:44.81,Default,,0,0,0,,所以我们必须求出不动点 Dialogue: 0,1:06:48.22,1:06:49.37,Default,,0,0,0,,需要来解这个方程 Dialogue: 0,1:06:52.16,1:06:54.28,Default,,0,0,0,,求不动点的方法有很多种 Dialogue: 0,1:06:55.58,1:06:57.08,Default,,0,0,0,,本门课程的第一节课 Dialogue: 0,1:06:57.24,1:07:01.16,Default,,0,0,0,,我们就用余弦函数做了演示 Dialogue: 0,1:07:02.73,1:07:07.69,Default,,0,0,0,,先把你的计算器调成弧度制 Dialogue: 0,1:07:07.85,1:07:10.51,Default,,0,0,0,,然后一直按COS键 Dialogue: 0,1:07:11.84,1:07:15.45,Default,,0,0,0,,最后数字会稳定在0.73、0.74左右 Dialogue: 0,1:07:16.09,1:07:17.18,Default,,0,0,0,,我记不清是哪个了 Dialogue: 0,1:07:20.57,1:07:22.64,Default,,0,0,0,,通过迭代一个过程 Dialogue: 0,1:07:22.81,1:07:24.40,Default,,0,0,0,,我们不断迭代 Dialogue: 0,1:07:25.60,1:07:27.16,Default,,0,0,0,,想要寻找不动点的函数 Dialogue: 0,1:07:27.50,1:07:31.13,Default,,0,0,0,,有时候 它就会收敛在一个点上 Dialogue: 0,1:07:31.87,1:07:33.08,Default,,0,0,0,,这就是不动点 Dialogue: 0,1:07:33.77,1:07:35.44,Default,,0,0,0,,碰碰运气 Dialogue: 0,1:07:36.44,1:07:37.21,Default,,0,0,0,,来试试这种方法 Dialogue: 0,1:07:39.91,1:07:46.28,Default,,0,0,0,,来看这张幻灯片 Dialogue: 0,1:07:48.03,1:07:51.71,Default,,0,0,0,,考虑这么一连串的过程 Dialogue: 0,1:07:56.40,1:07:57.79,Default,,0,0,0,,这里的E0 Dialogue: 0,1:07:59.24,1:08:01.63,Default,,0,0,0,,这个E0过程什么也不做 Dialogue: 0,1:08:02.89,1:08:05.10,Default,,0,0,0,,无论你给它传递什么参数 Dialogue: 0,1:08:05.10,1:08:06.24,Default,,0,0,0,,它都会产生ERROR Dialogue: 0,1:08:07.78,1:08:09.03,Default,,0,0,0,,基本上没什么用 Dialogue: 0,1:08:14.48,1:08:20.08,Default,,0,0,0,,然而 我可以做近似 Dialogue: 0,1:08:20.08,1:08:23.93,Default,,0,0,0,,让我们考虑下 指数过程的最差近似 Dialogue: 0,1:08:24.73,1:08:25.53,Default,,0,0,0,,因为它什么也做不了 Dialogue: 0,1:08:26.99,1:08:29.68,Default,,0,0,0,,假设我调用F Dialogue: 0,1:08:30.35,1:08:33.26,Default,,0,0,0,,用E0去代换G Dialogue: 0,1:08:33.79,1:08:36.30,Default,,0,0,0,,这里 G就被代换为了E0 Dialogue: 0,1:08:37.38,1:08:39.77,Default,,0,0,0,,所以在这里就是E0 Dialogue: 0,1:08:40.84,1:08:42.35,Default,,0,0,0,,那么E1又成了什么呢? Dialogue: 0,1:08:43.63,1:08:46.03,Default,,0,0,0,,如果用E1来计算X^0 Dialogue: 0,1:08:46.67,1:08:48.78,Default,,0,0,0,,没什么问题 Dialogue: 0,1:08:49.60,1:08:50.75,Default,,0,0,0,,它返回的结果是正确的 Dialogue: 0,1:08:51.05,1:08:52.35,Default,,0,0,0,,任何数的0次幂都是1 Dialogue: 0,1:08:52.68,1:08:54.25,Default,,0,0,0,,然而计算其它次幂就会出错 Dialogue: 0,1:08:57.39,1:09:01.56,Default,,0,0,0,,现在如果我用E1来调用F Dialogue: 0,1:09:02.30,1:09:07.40,Default,,0,0,0,,把G代换为E1 会发生什么? Dialogue: 0,1:09:09.58,1:09:11.18,Default,,0,0,0,,这样的话 Dialogue: 0,1:09:12.01,1:09:15.02,Default,,0,0,0,,我就会得到这个二元过程 Dialogue: 0,1:09:15.67,1:09:16.84,Default,,0,0,0,,想一想 E1这个过程 Dialogue: 0,1:09:16.96,1:09:19.66,Default,,0,0,0,,只能正确计算X^0 Dialogue: 0,1:09:21.47,1:09:23.37,Default,,0,0,0,,它只能计算0次幂 Dialogue: 0,1:09:24.20,1:09:25.00,Default,,0,0,0,,所以这里 Dialogue: 0,1:09:25.52,1:09:27.28,Default,,0,0,0,,如果N为0 结果就是1 Dialogue: 0,1:09:27.29,1:09:28.67,Default,,0,0,0,,E2的这部分也正确 Dialogue: 0,1:09:29.52,1:09:32.01,Default,,0,0,0,,然而 我可以通过把0次幂乘以X Dialogue: 0,1:09:32.51,1:09:35.26,Default,,0,0,0,,来计算1次幂 Dialogue: 0,1:09:35.97,1:09:39.67,Default,,0,0,0,,所以E2可以正确计算0次幂和1次幂 Dialogue: 0,1:09:41.60,1:09:41.92,Default,,0,0,0,,对吧? Dialogue: 0,1:09:43.71,1:09:46.67,Default,,0,0,0,,E3的构造过程和E2是类似的 Dialogue: 0,1:09:47.89,1:09:50.24,Default,,0,0,0,,当然 E3具有同样的参数 Dialogue: 0,1:09:50.32,1:09:53.37,Default,,0,0,0,,能够正确计算0、1、2次幂 Dialogue: 0,1:09:55.12,1:09:55.40,Default,,0,0,0,,对吧? Dialogue: 0,1:09:56.09,1:09:59.08,Default,,0,0,0,,因此我就不加证明地告诉你结论 Dialogue: 0,1:09:59.66,1:10:01.72,Default,,0,0,0,,因为这个证明过程太难了 Dialogue: 0,1:10:02.52,1:10:03.60,Default,,0,0,0,,这种事情 Dialogue: 0,1:10:03.63,1:10:06.36,Default,,0,0,0,,是由人们所谓“指称语义学家”完成的 Dialogue: 0,1:10:06.59,1:10:07.64,Default,,0,0,0,,这个伟大的想法 Dialogue: 0,1:10:07.87,1:10:10.59,Default,,0,0,0,,应该是由Scott和Strachey提出的 Dialogue: 0,1:10:11.64,1:10:16.32,Default,,0,0,0,,他们是非常著名的数学家 Dialogue: 0,1:10:16.86,1:10:21.21,Default,,0,0,0,,他们发明了这些程序的解释方式 Dialogue: 0,1:10:22.36,1:10:24.00,Default,,0,0,0,,就是我刚才讲的那些 Dialogue: 0,1:10:24.24,1:10:26.17,Default,,0,0,0,,他们通过拓扑学的方法证明了 Dialogue: 0,1:10:27.04,1:10:29.32,Default,,0,0,0,,在我们刚才那种情况下 Dialogue: 0,1:10:29.82,1:10:31.26,Default,,0,0,0,,不动点是存在的 Dialogue: 0,1:10:32.22,1:10:33.24,Default,,0,0,0,,这个结论就是: Dialogue: 0,1:10:33.40,1:10:44.24,Default,,0,0,0,,当N趋近于无穷时 EXPT是E(N)的极限 Dialogue: 0,1:10:45.52,1:10:47.90,Default,,0,0,0,,我们是通过下面这种方式来构造这个极限的 Dialogue: 0,1:10:50.52,1:10:55.66,Default,,0,0,0,,EXPT=(F (F (F (F .... Dialogue: 0,1:10:57.61,1:11:00.19,Default,,0,0,0,,(F 丄) Dialogue: 0,1:11:01.12,1:11:02.46,Default,,0,0,0,,它是什么都无所谓 Dialogue: 0,1:11:03.18,1:11:05.00,Default,,0,0,0,,因为它总会生成一个错误 Dialogue: 0,1:11:07.45,1:11:08.41,Default,,0,0,0,,(闭合括号中) Dialogue: 0,1:11:12.89,1:11:14.48,Default,,0,0,0,,这是F无穷嵌套调用 Dialogue: 0,1:11:16.38,1:11:17.71,Default,,0,0,0,,现在我们的问题 Dialogue: 0,1:11:18.22,1:11:19.76,Default,,0,0,0,,又变成了如何构造出无穷调用 Dialogue: 0,1:11:22.59,1:11:24.08,Default,,0,0,0,,我们需要它们 Dialogue: 0,1:11:24.92,1:11:26.25,Default,,0,0,0,,我怎样才能把F Dialogue: 0,1:11:26.56,1:11:27.80,Default,,0,0,0,,嵌套无穷层呢? Dialogue: 0,1:11:28.98,1:11:30.12,Default,,0,0,0,,我得把它构造出来 Dialogue: 0,1:11:32.38,1:11:32.93,Default,,0,0,0,,好吧 我不知道 Dialogue: 0,1:11:32.93,1:11:34.32,Default,,0,0,0,,到底怎么样构建一个无穷循环呢? Dialogue: 0,1:11:34.81,1:11:36.32,Default,,0,0,0,,我们先来看个非常简单的无穷循环 Dialogue: 0,1:11:36.57,1:11:38.34,Default,,0,0,0,,能想到的最简单的无穷循环 Dialogue: 0,1:11:43.55,1:11:47.55,Default,,0,0,0,,把这样一个参数为X的函数过程 Dialogue: 0,1:11:48.00,1:11:49.79,Default,,0,0,0,,过程体是(X X) Dialogue: 0,1:11:53.55,1:11:53.92,Default,,0,0,0,,看到了吧? Dialogue: 0,1:11:55.05,1:11:58.41,Default,,0,0,0,,应用在一个参数为X过程上 Dialogue: 0,1:11:59.36,1:12:01.05,Default,,0,0,0,,后者的过程体也是(X X) Dialogue: 0,1:12:04.83,1:12:06.00,Default,,0,0,0,,这就形成了一个无穷循环 Dialogue: 0,1:12:07.21,1:12:09.31,Default,,0,0,0,,这个循环之所以是无穷的 Dialogue: 0,1:12:09.98,1:12:11.31,Default,,0,0,0,,是因为 Dialogue: 0,1:12:11.52,1:12:13.69,Default,,0,0,0,,我用实际参数代换掉 Dialogue: 0,1:12:14.22,1:12:16.59,Default,,0,0,0,,过程体的形式参数 Dialogue: 0,1:12:18.85,1:12:21.60,Default,,0,0,0,,这样做了以后 这里的每个X Dialogue: 0,1:12:22.40,1:12:23.76,Default,,0,0,0,,都被代换为了这个 Dialogue: 0,1:12:24.36,1:12:26.96,Default,,0,0,0,,相当于把最初的表达式又复制了一遍 Dialogue: 0,1:12:28.35,1:12:29.37,Default,,0,0,0,,这就是最简单的无穷循环 Dialogue: 0,1:12:35.44,1:12:39.29,Default,,0,0,0,,现在 我要介绍一个特殊的运算符 Dialogue: 0,1:12:40.38,1:12:43.09,Default,,0,0,0,,它是通过对这个无穷循环稍作修改而来 Dialogue: 0,1:12:46.96,1:12:47.92,Default,,0,0,0,,我把它记作“Y” Dialogue: 0,1:12:50.89,1:12:55.82,Default,,0,0,0,,它的全称是:Curry的矛盾Y组合子 Dialogue: 0,1:12:56.62,1:12:58.99,Default,,0,0,0,,这是用二十世纪三十年代的逻辑学家 Dialogue: 0,1:12:59.34,1:13:01.85,Default,,0,0,0,,Curry的名字来命名的 Dialogue: 0,1:13:04.48,1:13:06.88,Default,,0,0,0,,Y组合子是一个参数为f的过程 Dialogue: 0,1:13:08.17,1:13:09.33,Default,,0,0,0,,它的过程体是什么呢? Dialogue: 0,1:13:09.33,1:13:11.20,Default,,0,0,0,,它的内部是某种无穷循环 Dialogue: 0,1:13:11.98,1:13:15.47,Default,,0,0,0,,是一个参数为x的过程 Dialogue: 0,1:13:15.95,1:13:18.80,Default,,0,0,0,,它调用(f (x x)) Dialogue: 0,1:13:21.63,1:13:24.75,Default,,0,0,0,,这个过程应用在一个参数为X的过程上 Dialogue: 0,1:13:25.10,1:13:27.34,Default,,0,0,0,,后者调用(f (x x)) Dialogue: 0,1:13:32.30,1:13:33.13,Default,,0,0,0,,这个是怎么运作的? Dialogue: 0,1:13:34.80,1:13:36.06,Default,,0,0,0,,假设执行(Y F) Dialogue: 0,1:13:41.31,1:13:42.57,Default,,0,0,0,,这非常简单 Dialogue: 0,1:13:43.15,1:13:44.62,Default,,0,0,0,,这里大写的F跟那边的是同一个 Dialogue: 0,1:13:46.91,1:13:48.16,Default,,0,0,0,,在这里 很简单 Dialogue: 0,1:13:48.30,1:13:49.92,Default,,0,0,0,,我把F代换到这里来 Dialogue: 0,1:13:55.32,1:13:57.07,Default,,0,0,0,,基本上 我就会得到 Dialogue: 0,1:13:58.75,1:14:00.84,Default,,0,0,0,,因为我待会儿要用这个表达式 Dialogue: 0,1:14:01.45,1:14:02.80,Default,,0,0,0,,代换这里的x Dialogue: 0,1:14:04.17,1:14:05.23,Default,,0,0,0,,这里就是(F Dialogue: 0,1:14:08.97,1:14:10.09,Default,,0,0,0,,我还是把这步写出来吧 Dialogue: 0,1:14:10.22,1:14:11.45,Default,,0,0,0,,这样你们就能看得更全面 Dialogue: 0,1:14:11.92,1:14:14.27,Default,,0,0,0,,我会非常小心 好吗? Dialogue: 0,1:14:15.02,1:14:18.25,Default,,0,0,0,,这里是 ((LAMBDA (x) Dialogue: 0,1:14:19.08,1:14:22.11,Default,,0,0,0,,(F (x x)) Dialogue: 0,1:14:26.88,1:14:35.55,Default,,0,0,0,,把它应用到自身 (LAMBDA (x) (F (x x))) Dialogue: 0,1:14:37.91,1:14:39.66,Default,,0,0,0,,把这个表达式代换进去 Dialogue: 0,1:14:40.06,1:14:40.91,Default,,0,0,0,,就得到 Dialogue: 0,1:14:43.13,1:14:48.35,Default,,0,0,0,,把这个代进去 得到什么呢? Dialogue: 0,1:14:48.65,1:14:54.81,Default,,0,0,0,,(F (LAMBDA (x) (F (x x))) Dialogue: 0,1:14:57.07,1:14:58.17,Default,,0,0,0,,应用到 Dialogue: 0,1:14:59.18,1:15:06.48,Default,,0,0,0,,(LAMBDA (x) (F (x x)))) Dialogue: 0,1:15:06.99,1:15:10.44,Default,,0,0,0,,(闭合括号中) Dialogue: 0,1:15:11.51,1:15:12.40,Default,,0,0,0,,哇 这又是什么? Dialogue: 0,1:15:13.42,1:15:16.35,Default,,0,0,0,,我刚才计算的这一部分 Dialogue: 0,1:15:17.13,1:15:18.56,Default,,0,0,0,,就是这里的这部分 Dialogue: 0,1:15:20.19,1:15:21.84,Default,,0,0,0,,只不过它被包在另一个F里面 Dialogue: 0,1:15:23.37,1:15:24.67,Default,,0,0,0,,因此 通过把Y应用在F上 Dialogue: 0,1:15:24.68,1:15:26.22,Default,,0,0,0,,我构造出了F的无穷嵌套 Dialogue: 0,1:15:27.85,1:15:29.45,Default,,0,0,0,,我如果让它一直这样进行下去 Dialogue: 0,1:15:29.69,1:15:31.77,Default,,0,0,0,,我在外层就会得到越来越多的F Dialogue: 0,1:15:33.17,1:15:34.80,Default,,0,0,0,,我运行一个无用的循环 Dialogue: 0,1:15:35.20,1:15:37.02,Default,,0,0,0,,但内部是无用的并不重要 Dialogue: 0,1:15:39.85,1:15:47.85,Default,,0,0,0,,因此 我们有 (Y F)=(F (Y F)) Dialogue: 0,1:15:50.33,1:15:52.14,Default,,0,0,0,,Y组合子十分神奇 Dialogue: 0,1:15:53.85,1:15:56.25,Default,,0,0,0,,如果把它应用于某个函数 Dialogue: 0,1:15:57.37,1:16:00.38,Default,,0,0,0,,它就会返回这个函数的不动点 Dialogue: 0,1:16:01.69,1:16:04.25,Default,,0,0,0,,当然是在不动点存在的前提下 Dialogue: 0,1:16:07.91,1:16:10.08,Default,,0,0,0,,这是因为 如果我把(Y F)带入F Dialogue: 0,1:16:10.12,1:16:11.12,Default,,0,0,0,,结果还是(Y F) Dialogue: 0,1:16:16.24,1:16:18.86,Default,,0,0,0,,现在我想让你们在 Dialogue: 0,1:16:19.85,1:16:22.38,Default,,0,0,0,,EVAL-APPLY解释器方面思考一下 Dialogue: 0,1:16:23.86,1:16:26.27,Default,,0,0,0,,我在这里写了一大堆递归方程组 Dialogue: 0,1:16:28.54,1:16:30.22,Default,,0,0,0,,那些联立方程组像 Dialogue: 0,1:16:30.22,1:16:31.23,Default,,0,0,0,,这些方程一样联立起来 Dialogue: 0,1:16:31.47,1:16:33.31,Default,,0,0,0,,但EXPT不是联立方程 Dialogue: 0,1:16:33.31,1:16:35.79,Default,,0,0,0,,只是一个需要我赋义的变量 Dialogue: 0,1:16:38.15,1:16:40.76,Default,,0,0,0,,而Lisp则是某个过程的不动点 Dialogue: 0,1:16:40.81,1:16:42.57,Default,,0,0,0,,对这个过程来说 如果我知道Lisp的定义 Dialogue: 0,1:16:42.59,1:16:46.51,Default,,0,0,0,,然后在递归方程等号的右边 Dialogue: 0,1:16:46.59,1:16:49.79,Default,,0,0,0,,用它来代换EVAL、APPLY等变量 Dialogue: 0,1:16:50.94,1:16:53.96,Default,,0,0,0,,如果它是一个良好定义的Lisp的话 Dialogue: 0,1:16:54.36,1:16:56.30,Default,,0,0,0,,那么递归方程等号左边 也是一个良好定义的Lisp Dialogue: 0,1:16:58.22,1:16:59.82,Default,,0,0,0,,这样 那个定义就讲得通了 Dialogue: 0,1:17:02.42,1:17:05.41,Default,,0,0,0,,不过是否有解却不太明显 Dialogue: 0,1:17:05.69,1:17:06.75,Default,,0,0,0,,我也说不清 Dialogue: 0,1:17:07.74,1:17:09.21,Default,,0,0,0,,现在我要介绍的论证 Dialogue: 0,1:17:09.26,1:17:10.27,Default,,0,0,0,,相当危险 Dialogue: 0,1:17:10.66,1:17:11.64,Default,,0,0,0,,具体看这里 Dialogue: 0,1:17:13.05,1:17:14.61,Default,,0,0,0,,这些是关于极限的论证 Dialogue: 0,1:17:14.61,1:17:15.39,Default,,0,0,0,,我们要讨论的极限 Dialogue: 0,1:17:15.45,1:17:17.68,Default,,0,0,0,,是微积分或者拓扑学的概念 Dialogue: 0,1:17:17.87,1:17:20.03,Default,,0,0,0,,或者说是类似的 数学分析中的概念 Dialogue: 0,1:17:20.76,1:17:23.38,Default,,0,0,0,,这个论证是你们都承认的 Dialogue: 0,1:17:23.38,1:17:25.29,Default,,0,0,0,,我想让你们意识到 Dialogue: 0,1:17:25.42,1:17:27.66,Default,,0,0,0,,我可以把你们耍得团团转 Dialogue: 0,1:17:28.86,1:17:30.48,Default,,0,0,0,,准备好了吗? 这是什么? Dialogue: 0,1:17:34.25,1:17:39.52,Default,,0,0,0,,u = 1 + 1/2 + 1/4 + ....... Dialogue: 0,1:17:39.74,1:17:41.32,Default,,0,0,0,,这是几何级数求和 Dialogue: 0,1:17:42.82,1:17:44.68,Default,,0,0,0,,当然 我也可以耍点小把戏 Dialogue: 0,1:17:44.82,1:17:47.57,Default,,0,0,0,,u - 1 = 1/2 + 1/4 + 1/8 ...... Dialogue: 0,1:17:51.90,1:17:54.46,Default,,0,0,0,,这里我可以 Dialogue: 0,1:17:56.09,1:17:57.93,Default,,0,0,0,,糟糕了 这里漏掉了括号 Dialogue: 0,1:17:58.92,1:18:01.45,Default,,0,0,0,,这里应该是 Dialogue: 0,1:18:01.74,1:18:03.99,Default,,0,0,0,,2(u - 1) = 1 + 1/2 + 1/4 + 1/8 ........ Dialogue: 0,1:18:07.57,1:18:08.54,Default,,0,0,0,,这里能修改一下吗? Dialogue: 0,1:18:14.01,1:18:16.43,Default,,0,0,0,,哦 可以 Dialogue: 0,1:18:18.19,1:18:18.65,Default,,0,0,0,,看到了吗? Dialogue: 0,1:18:19.52,1:18:20.64,Default,,0,0,0,,这样 我就得到 Dialogue: 0,1:18:23.53,1:18:26.64,Default,,0,0,0,,2(u - 1) = u Dialogue: 0,1:18:27.80,1:18:29.58,Default,,0,0,0,,因此我们推断出 u=2 Dialogue: 0,1:18:30.30,1:18:31.37,Default,,0,0,0,,这是正确的 Dialogue: 0,1:18:31.96,1:18:33.32,Default,,0,0,0,,这个推理过程没有问题 Dialogue: 0,1:18:34.04,1:18:37.55,Default,,0,0,0,,但如果我要是做点别的什么呢? Dialogue: 0,1:18:38.54,1:18:39.48,Default,,0,0,0,,假设我要求和的式子 Dialogue: 0,1:18:39.50,1:18:41.20,Default,,0,0,0,,明显没有和 Dialogue: 0,1:18:41.56,1:18:46.99,Default,,0,0,0,,v = 1 + 2 + 4 + ........ Dialogue: 0,1:18:47.39,1:18:51.39,Default,,0,0,0,,v - 1 = 2 + 4 + 8 + ...... Dialogue: 0,1:18:52.27,1:18:56.03,Default,,0,0,0,,(v - 1)/2 = v Dialogue: 0,1:18:57.41,1:19:00.54,Default,,0,0,0,,这里我就可以推断出 Dialogue: 0,1:19:01.37,1:19:02.91,Default,,0,0,0,,显然这里又写错了 Dialogue: 0,1:19:03.07,1:19:04.51,Default,,0,0,0,,应该是 v = -1 Dialogue: 0,1:19:12.45,1:19:13.82,Default,,0,0,0,,这里应该是-1 Dialogue: 0,1:19:15.28,1:19:16.91,Default,,0,0,0,,这个结论明显是错误的 Dialogue: 0,1:19:22.00,1:19:23.47,Default,,0,0,0,,当你处理极限的时候 Dialogue: 0,1:19:24.22,1:19:27.85,Default,,0,0,0,,在某种方式下可行的论证 Dialogue: 0,1:19:29.42,1:19:30.75,Default,,0,0,0,,在其它情况下可能又不行了 Dialogue: 0,1:19:30.75,1:19:31.69,Default,,0,0,0,,要多加注意 Dialogue: 0,1:19:32.24,1:19:33.87,Default,,0,0,0,,参数必须具有良好的形式 Dialogue: 0,1:19:36.14,1:19:39.23,Default,,0,0,0,,但我不清楚 通常来说 Dialogue: 0,1:19:39.85,1:19:41.93,Default,,0,0,0,,像这样的论证有什么样的要求 Dialogue: 0,1:19:43.27,1:19:45.24,Default,,0,0,0,,我们要研习一大堆拓扑学文献来寻找答案 Dialogue: 0,1:19:46.27,1:19:48.64,Default,,0,0,0,,但是至少你们现在理解了 Dialogue: 0,1:19:49.10,1:19:51.13,Default,,0,0,0,,为什么我们在黑板上写的这些东西 Dialogue: 0,1:19:51.15,1:19:52.76,Default,,0,0,0,,是有一定语义的 Dialogue: 0,1:19:53.66,1:19:55.61,Default,,0,0,0,,你们也理解了它的语义 Dialogue: 0,1:19:56.48,1:19:58.35,Default,,0,0,0,,我想现在是时候 Dialogue: 0,1:19:59.07,1:20:03.84,Default,,0,0,0,,祝贺你们成为 Dialogue: 0,1:20:04.28,1:20:05.55,Default,,0,0,0,,神圣的递归秩序中的 Dialogue: 0,1:20:05.56,1:20:07.04,Default,,0,0,0,,一名LAMBDA演算黑客了 Dialogue: 0,1:20:08.84,1:20:10.17,Default,,0,0,0,,这是我们的徽章 Dialogue: 0,1:20:10.82,1:20:12.54,Default,,0,0,0,,因为你已经理解了 Dialogue: 0,1:20:13.40,1:20:15.20,Default,,0,0,0,,它上面的那句话 Dialogue: 0,1:20:16.89,1:20:18.41,Default,,0,0,0,,(Y F) = (F (Y F)) Dialogue: 0,1:20:21.04,1:20:21.66,Default,,0,0,0,,这节课讲完了 Dialogue: 0,1:20:21.85,1:20:22.75,Default,,0,0,0,,有什么问题吗? Dialogue: 0,1:20:24.71,1:20:25.15,Default,,0,0,0,,Lev 请说 Dialogue: 0,1:20:25.37,1:20:27.39,Default,,0,0,0,,学生:目前的状况来看 Dialogue: 0,1:20:27.40,1:20:30.22,Default,,0,0,0,,正如你指出的那样 我们不再需要DEFINE Dialogue: 0,1:20:30.24,1:20:32.70,Default,,0,0,0,,不需要先存储一个值 以后再用 Dialogue: 0,1:20:32.99,1:20:33.32,Default,,0,0,0,,教授:对 Dialogue: 0,1:20:33.50,1:20:36.44,Default,,0,0,0,,学生:DEFINE在语言中好像有一些副作用 Dialogue: 0,1:20:36.49,1:20:38.52,Default,,0,0,0,,(听不清)并且依赖于时序 Dialogue: 0,1:20:39.30,1:20:42.06,Default,,0,0,0,,不用DEFINE 是否消除了副作用? Dialogue: 0,1:20:42.28,1:20:44.68,Default,,0,0,0,,教授: 实际上 Dialogue: 0,1:20:44.88,1:20:46.44,Default,,0,0,0,,解释器并不是像这样实现的 Dialogue: 0,1:20:47.52,1:20:47.93,Default,,0,0,0,,明白了吧? Dialogue: 0,1:20:48.92,1:20:53.15,Default,,0,0,0,,在实际的实现中 DEFINE这个运算 Dialogue: 0,1:20:53.18,1:20:55.53,Default,,0,0,0,,确实修改了环境 Dialogue: 0,1:20:57.95,1:21:02.33,Default,,0,0,0,,改变了执行DEFINE的那个框架 Dialogue: 0,1:21:03.69,1:21:06.51,Default,,0,0,0,,这样做是有很多原因的 Dialogue: 0,1:21:07.39,1:21:08.64,Default,,0,0,0,,其中之一就是 Dialogue: 0,1:21:08.67,1:21:10.09,Default,,0,0,0,,方便交互式系统 Dialogue: 0,1:21:11.34,1:21:14.12,Default,,0,0,0,,就是说 如果你构造了一个系统 Dialogue: 0,1:21:14.35,1:21:15.20,Default,,0,0,0,,而且你知道 Dialogue: 0,1:21:15.42,1:21:16.60,Default,,0,0,0,,你不打算进行调试 Dialogue: 0,1:21:16.60,1:21:17.55,Default,,0,0,0,,或之类的事儿 Dialogue: 0,1:21:17.84,1:21:20.72,Default,,0,0,0,,你想立马知道所有的东西 Dialogue: 0,1:21:20.75,1:21:21.24,Default,,0,0,0,,你想知道的是 Dialogue: 0,1:21:21.26,1:21:23.12,Default,,0,0,0,,方程组的最终解是什么? Dialogue: 0,1:21:24.09,1:21:25.26,Default,,0,0,0,,然后系统返回你相应的值 Dialogue: 0,1:21:25.79,1:21:27.45,Default,,0,0,0,,但如果想要让系统变成交互式的 Dialogue: 0,1:21:27.45,1:21:28.75,Default,,0,0,0,,这样你可以在不影响其它部分的情况下 Dialogue: 0,1:21:28.76,1:21:31.68,Default,,0,0,0,,增量式地修改某一部分 Dialogue: 0,1:21:32.33,1:21:35.04,Default,,0,0,0,,没有DEFINE的话 就不能这么做了 Dialogue: 0,1:21:40.99,1:21:41.24,Default,,0,0,0,,你说 Dialogue: 0,1:21:42.30,1:21:44.25,Default,,0,0,0,,学生:就是那张“危险”的幻灯片 Dialogue: 0,1:21:44.65,1:21:47.13,Default,,0,0,0,,好像你举的两个例子 Dialogue: 0,1:21:47.16,1:21:49.07,Default,,0,0,0,,与其收敛与否有关系? Dialogue: 0,1:21:49.18,1:21:49.56,Default,,0,0,0,,教授:是的 Dialogue: 0,1:21:50.30,1:21:52.62,Default,,0,0,0,,学生:函数理论中是否有 Dialogue: 0,1:21:52.76,1:21:54.68,Default,,0,0,0,,像线性系统 Dialogue: 0,1:21:54.72,1:21:56.60,Default,,0,0,0,,或者非线性系统中的 Dialogue: 0,1:21:57.74,1:21:59.00,Default,,0,0,0,,那种思考方式 Dialogue: 0,1:21:59.34,1:22:01.76,Default,,0,0,0,,函数的收敛性能否先验地知道 Dialogue: 0,1:22:02.35,1:22:05.53,Default,,0,0,0,,哪些属性可能被违反? Dialogue: 0,1:22:05.79,1:22:06.57,Default,,0,0,0,,教授:我不知道 Dialogue: 0,1:22:07.68,1:22:10.09,Default,,0,0,0,,我也不知道它需要什么条件 Dialogue: 0,1:22:10.61,1:22:12.04,Default,,0,0,0,,我不知道怎么在一节课内 Dialogue: 0,1:22:12.52,1:22:14.73,Default,,0,0,0,,就给你们讲清楚 Dialogue: 0,1:22:16.91,1:22:18.48,Default,,0,0,0,,有什么条件来判别它们 Dialogue: 0,1:22:18.86,1:22:20.76,Default,,0,0,0,,是否收敛? Dialogue: 0,1:22:22.86,1:22:23.31,Default,,0,0,0,,确实 Dialogue: 0,1:22:23.32,1:22:26.35,Default,,0,0,0,,这些都是为了告诉你 基于收敛的论证 Dialogue: 0,1:22:28.24,1:22:29.47,Default,,0,0,0,,都不可靠 Dialogue: 0,1:22:29.66,1:22:31.58,Default,,0,0,0,,如果你事先不知道收敛性的话 Dialogue: 0,1:22:32.81,1:22:34.20,Default,,0,0,0,,你可能做出错误的论证 Dialogue: 0,1:22:34.44,1:22:37.31,Default,,0,0,0,,你可以先假设知道了答案 然后进行演绎 Dialogue: 0,1:22:37.39,1:22:39.93,Default,,0,0,0,,看它会不会产生什么明显的矛盾 Dialogue: 0,1:22:40.97,1:22:42.28,Default,,0,0,0,,学生:我们是否可以说 Dialogue: 0,1:22:42.33,1:22:44.88,Default,,0,0,0,,如果数学表达式F收敛 Dialogue: 0,1:22:45.00,1:22:47.36,Default,,0,0,0,,那么它的递归性质就-- Dialogue: 0,1:22:47.58,1:22:51.29,Default,,0,0,0,,教授:我认为 在技术上有一类F Dialogue: 0,1:22:52.12,1:22:54.22,Default,,0,0,0,,通过一些技术准则 Dialogue: 0,1:22:54.24,1:22:55.90,Default,,0,0,0,,我们可以找到这样的F Dialogue: 0,1:22:55.98,1:23:01.31,Default,,0,0,0,,当你像这样迭代地应用它们时 Dialogue: 0,1:23:01.52,1:23:02.25,Default,,0,0,0,,它一定会收敛 Dialogue: 0,1:23:03.02,1:23:06.51,Default,,0,0,0,,这类准则包括:单调、连续 Dialogue: 0,1:23:07.32,1:23:07.95,Default,,0,0,0,,我想想 Dialogue: 0,1:23:08.38,1:23:09.37,Default,,0,0,0,,我把其它的准则忘了 Dialogue: 0,1:23:09.37,1:23:11.13,Default,,0,0,0,,还有一些列像这样的 Dialogue: 0,1:23:11.68,1:23:12.99,Default,,0,0,0,,判别准则 Dialogue: 0,1:23:13.43,1:23:16.00,Default,,0,0,0,,现在的难点是 给定F然后进行推理 Dialogue: 0,1:23:16.92,1:23:17.88,Default,,0,0,0,,这是F的定义 Dialogue: 0,1:23:18.17,1:23:19.66,Default,,0,0,0,,它满足这些准则吗? Dialogue: 0,1:23:20.27,1:23:21.32,Default,,0,0,0,,这很难判断 Dialogue: 0,1:23:22.01,1:23:24.00,Default,,0,0,0,,那些准则都很简单得可以写下来 Dialogue: 0,1:23:24.58,1:23:26.32,Default,,0,0,0,,你可以看Joe Stoy写的一本书 Dialogue: 0,1:23:26.67,1:23:29.58,Default,,0,0,0,,那本书非常不错 Dialogue: 0,1:23:32.22,1:23:34.06,Default,,0,0,0,,叫做The Scott-Strachey Dialogue: 0,1:23:34.49,1:23:38.46,Default,,0,0,0,,《指称语义:基于Scott-Strachey方法》 Dialogue: 0,1:23:39.55,1:23:40.76,Default,,0,0,0,,作者是Joe Stoy Dialogue: 0,1:23:40.80,1:23:41.76,Default,,0,0,0,,由MIT出版社出版 Dialogue: 0,1:23:48.06,1:23:49.88,Default,,0,0,0,,他把这一方面讲得非常详细 Dialogue: 0,1:23:50.20,1:23:51.37,Default,,0,0,0,,绝对会让你吓一大跳 Dialogue: 0,1:23:55.05,1:23:56.19,Default,,0,0,0,,但是这本书仍然值得一读 Dialogue: 0,1:24:09.15,1:24:10.08,Default,,0,0,0,,好吧 谢谢大家 Dialogue: 0,1:24:11.49,1:24:12.99,Default,,0,0,0,,这节课到此为止 Dialogue: 0,1:24:14.17,1:24:34.60,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:24:14.17,1:24:34.49,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec7a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Video Position: 343 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:11.42,0:00:13.24,EN,,0,0,0,,Metacircular Evaluator - I Dialogue: 0,0:00:15.79,0:00:17.32,EN,,0,0,0,,PROFESSOR: Well today we're going to learn about something Dialogue: 0,0:00:17.52,0:00:18.41,EN,,0,0,0,,quite amazing. Dialogue: 0,0:00:19.20,0:00:21.88,EN,,0,0,0,,We're going to understand what we mean by a program Dialogue: 0,0:00:22.59,0:00:25.21,EN,,0,0,0,,a little bit more profoundly than we have up till now. Dialogue: 0,0:00:26.80,0:00:29.12,EN,,0,0,0,,Up till now, we've been thinking Dialogue: 0,0:00:29.26,0:00:32.09,EN,,0,0,0,,programs as describing machines. Dialogue: 0,0:00:32.72,0:00:37.21,EN,,0,0,0,,So for example, looking at this still store Dialogue: 0,0:00:37.93,0:00:41.77,EN,,0,0,0,,we see here is a program for factorial. Dialogue: 0,0:00:42.80,0:00:47.31,EN,,0,0,0,,And what it is, is a character string description, if you will, Dialogue: 0,0:00:47.66,0:00:51.98,EN,,0,0,0,,of the wiring diagram of a potentially infinite machine. Dialogue: 0,0:00:52.49,0:00:54.80,EN,,0,0,0,,And we can look at that a little bit and just see the idea. Dialogue: 0,0:00:55.13,0:00:58.20,EN,,0,0,0,,That this is a sort of compact notation which says, Dialogue: 0,0:00:58.54,0:01:00.17,EN,,0,0,0,,if n is 0, the result is one. Dialogue: 0,0:01:00.17,0:01:02.00,EN,,0,0,0,,Well here comes n coming into this machine, Dialogue: 0,0:01:02.33,0:01:03.52,EN,,0,0,0,,and if it's 0, Dialogue: 0,0:01:03.74,0:01:05.20,EN,,0,0,0,,then I control this switch Dialogue: 0,0:01:05.47,0:01:08.20,EN,,0,0,0,,in such a way that the switch allows the output to be one. Dialogue: 0,0:01:09.34,0:01:10.08,EN,,0,0,0,,Otherwise, Dialogue: 0,0:01:10.38,0:01:12.83,EN,,0,0,0,,it's n times factorial of n minus one. Dialogue: 0,0:01:12.97,0:01:15.13,EN,,0,0,0,,Well, I'm computing factorial of n minus one Dialogue: 0,0:01:15.29,0:01:16.68,EN,,0,0,0,,and multiplying that by n, Dialogue: 0,0:01:16.84,0:01:18.91,EN,,0,0,0,,in the case that it's not 0, Dialogue: 0,0:01:18.91,0:01:20.60,EN,,0,0,0,,this switch makes the output come from there. Dialogue: 0,0:01:21.90,0:01:22.32,EN,,0,0,0,,Of course, Dialogue: 0,0:01:22.36,0:01:25.13,EN,,0,0,0,,this is a machine with a potentially infinite number of parts, Dialogue: 0,0:01:25.48,0:01:28.12,EN,,0,0,0,,because factorial occurs within factorial, Dialogue: 0,0:01:28.43,0:01:30.17,EN,,0,0,0,,so we don't know how deep it has to be. Dialogue: 0,0:01:31.07,0:01:33.55,EN,,0,0,0,,But that's basically what our notation Dialogue: 0,0:01:34.22,0:01:37.69,EN,,0,0,0,,for programs really means to us at this point. Dialogue: 0,0:01:38.31,0:01:40.59,EN,,0,0,0,,It's a character string description, if you will, Dialogue: 0,0:01:41.28,0:01:44.16,EN,,0,0,0,,of a wiring diagram that could also be drawn some other way. Dialogue: 0,0:01:44.90,0:01:46.60,EN,,0,0,0,,And, in fact, many people have proposed to me, Dialogue: 0,0:01:46.84,0:01:49.04,EN,,0,0,0,,programming languages look graphical like this. Dialogue: 0,0:01:49.49,0:01:51.80,EN,,0,0,0,,I'm not sure I believe there are many advantages. Dialogue: 0,0:01:52.00,0:01:53.79,EN,,0,0,0,,The major disadvantage, of course, Dialogue: 0,0:01:53.80,0:01:55.63,EN,,0,0,0,,is that it takes up more space on a page, Dialogue: 0,0:01:55.96,0:01:59.95,EN,,0,0,0,,and, therefore, it's harder to pack into a listing or to edit very well. Dialogue: 0,0:02:01.34,0:02:02.16,EN,,0,0,0,,But in any case, Dialogue: 0,0:02:03.58,0:02:05.15,EN,,0,0,0,,there's something very remarkable Dialogue: 0,0:02:05.18,0:02:07.05,EN,,0,0,0,,that can happen in the computation world Dialogue: 0,0:02:07.64,0:02:10.64,EN,,0,0,0,,which is that you can have something called a universal machine. Dialogue: 0,0:02:10.73,0:02:15.24,EN,,0,0,0,,If we look at the second slide, Dialogue: 0,0:02:16.04,0:02:17.18,EN,,0,0,0,,what we see is Dialogue: 0,0:02:18.14,0:02:19.88,EN,,0,0,0,,a special machine called eval. Dialogue: 0,0:02:21.26,0:02:22.86,EN,,0,0,0,,There is a machine called eval, Dialogue: 0,0:02:22.88,0:02:24.24,EN,,0,0,0,,and I'm going to show it to you today. Dialogue: 0,0:02:25.82,0:02:26.67,EN,,0,0,0,,It's very simple. Dialogue: 0,0:02:27.78,0:02:30.80,EN,,0,0,0,,What is remarkable is that it will fit on the blackboard. Dialogue: 0,0:02:33.35,0:02:35.79,EN,,0,0,0,,However, eval is a machine Dialogue: 0,0:02:36.00,0:02:39.84,EN,,0,0,0,,which takes as input a description of another machine. Dialogue: 0,0:02:40.45,0:02:42.12,EN,,0,0,0,,It could take the wiring diagram Dialogue: 0,0:02:42.40,0:02:45.58,EN,,0,0,0,,of a factorial machine as input. Dialogue: 0,0:02:46.49,0:02:47.66,EN,,0,0,0,,Having done so, Dialogue: 0,0:02:48.49,0:02:52.57,EN,,0,0,0,,it becomes a simulator for the factorial machine Dialogue: 0,0:02:53.13,0:02:53.79,EN,,0,0,0,,such that, Dialogue: 0,0:02:54.16,0:02:56.36,EN,,0,0,0,,if you put a six in, out comes a 720. Dialogue: 0,0:02:58.91,0:03:01.68,EN,,0,0,0,,That's a very remarkable sort of machine. Dialogue: 0,0:03:02.13,0:03:03.58,EN,,0,0,0,,And the most amazing part of it Dialogue: 0,0:03:03.77,0:03:05.13,EN,,0,0,0,,it is that it fits on a blackboard. Dialogue: 0,0:03:05.59,0:03:06.65,EN,,0,0,0,,By contrast, Dialogue: 0,0:03:07.32,0:03:10.44,EN,,0,0,0,,one could imagine in the analog electronics world Dialogue: 0,0:03:11.55,0:03:12.86,EN,,0,0,0,,a very different machine. Dialogue: 0,0:03:14.57,0:03:16.33,EN,,0,0,0,,a machine where, a machine Dialogue: 0,0:03:16.52,0:03:18.81,EN,,0,0,0,,which also was, in some sense, universal, Dialogue: 0,0:03:19.26,0:03:23.12,EN,,0,0,0,,where you gave a circuit diagram as one of the inputs, Dialogue: 0,0:03:23.82,0:03:25.74,EN,,0,0,0,,for example, of this little low-pass filter, Dialogue: 0,0:03:26.01,0:03:27.48,EN,,0,0,0,,one-pole low-pass filter. Dialogue: 0,0:03:28.05,0:03:29.53,EN,,0,0,0,,And you can imagine that Dialogue: 0,0:03:29.71,0:03:33.15,EN,,0,0,0,,you could, for example, scan this out-- the scan lines Dialogue: 0,0:03:34.43,0:03:37.13,EN,,0,0,0,,Right? are the signal that's describing Dialogue: 0,0:03:37.39,0:03:40.40,EN,,0,0,0,,what this machine is to simulate-- Dialogue: 0,0:03:40.78,0:03:43.39,EN,,0,0,0,,then the analog of eval which is made out of electrical circuits, Dialogue: 0,0:03:43.68,0:03:45.15,EN,,0,0,0,,which configure itself into a filter Dialogue: 0,0:03:45.18,0:03:48.04,EN,,0,0,0,,has the frequency response specified by the circuit diagram. Dialogue: 0,0:03:49.89,0:03:51.48,EN,,0,0,0,,That's a very hard machine to make, Dialogue: 0,0:03:51.61,0:03:54.06,EN,,0,0,0,,and, surely, there's no chance that I could put it on a blackboard. Dialogue: 0,0:03:55.67,0:03:57.58,EN,,0,0,0,,So we're going to see an amazing thing today. Dialogue: 0,0:03:58.43,0:04:00.81,EN,,0,0,0,,We're going to see, on the blackboard, Dialogue: 0,0:04:01.16,0:04:02.49,EN,,0,0,0,,the universal machine. Dialogue: 0,0:04:02.79,0:04:04.41,EN,,0,0,0,,And we'll see that among other things, Dialogue: 0,0:04:04.52,0:04:05.80,EN,,0,0,0,,it's extremely simple. Dialogue: 0,0:04:06.78,0:04:08.75,EN,,0,0,0,,Now, we're getting very close Dialogue: 0,0:04:09.08,0:04:10.97,EN,,0,0,0,,the real spirit in the computer at this point. Dialogue: 0,0:04:11.28,0:04:14.62,EN,,0,0,0,,So I have to show a certain amount of reverence and respect, Dialogue: 0,0:04:15.18,0:04:17.32,EN,,0,0,0,,so I'm going to wear a suit jacket for the only time Dialogue: 0,0:04:17.52,0:04:19.29,EN,,0,0,0,,that you'll ever see me wear a suit jacket here. Dialogue: 0,0:04:20.47,0:04:22.73,EN,,0,0,0,,And I think I'm also going to Dialogue: 0,0:04:23.55,0:04:26.70,EN,,0,0,0,,put on an appropriate hat for the occasion. Dialogue: 0,0:04:28.78,0:04:31.44,EN,,0,0,0,,Now, this is a lecturer which I have to warn you-- Dialogue: 0,0:04:34.14,0:04:36.91,EN,,0,0,0,,let's see, normally, people under 40 Dialogue: 0,0:04:37.16,0:04:38.49,EN,,0,0,0,,and who don't have several children Dialogue: 0,0:04:38.67,0:04:40.49,EN,,0,0,0,,are advised to be careful. Dialogue: 0,0:04:40.49,0:04:41.96,EN,,0,0,0,,If they're really worried, they should leave. Dialogue: 0,0:04:43.34,0:04:45.56,EN,,0,0,0,,Because there's a certain amount of Dialogue: 0,0:04:45.72,0:04:47.13,EN,,0,0,0,,mysticism that will appear here Dialogue: 0,0:04:47.74,0:04:51.05,EN,,0,0,0,,which may be disturbing and cause trouble in your minds. Dialogue: 0,0:04:51.82,0:04:54.28,EN,,0,0,0,,Well in any case, let's see, Dialogue: 0,0:04:55.71,0:05:01.10,EN,,0,0,0,,I wish to write for you the evaluator for Lisp. Dialogue: 0,0:05:02.51,0:05:04.28,EN,,0,0,0,,Now the evaluator isn't very complicated. Dialogue: 0,0:05:05.02,0:05:07.63,EN,,0,0,0,,It's very much like all the programs we've seen already. Dialogue: 0,0:05:08.24,0:05:09.48,EN,,0,0,0,,That's the amazing part of it. Dialogue: 0,0:05:10.86,0:05:13.10,EN,,0,0,0,,It's going to be-- and I'm going to write it right here-- Dialogue: 0,0:05:15.28,0:05:16.62,EN,,0,0,0,,it's a program called eval. Dialogue: 0,0:05:22.90,0:05:26.24,EN,,0,0,0,,And it's a procedure of two arguments Dialogue: 0,0:05:26.28,0:05:29.44,EN,,0,0,0,,expression and an environment. Dialogue: 0,0:05:31.86,0:05:33.79,EN,,0,0,0,,And like every interesting procedure, Dialogue: 0,0:05:34.01,0:05:35.13,EN,,0,0,0,,it's a case analysis. Dialogue: 0,0:05:40.46,0:05:41.87,EN,,0,0,0,,But before I start on this, Dialogue: 0,0:05:42.52,0:05:43.90,EN,,0,0,0,,I want to tell you some things. Dialogue: 0,0:05:44.44,0:05:46.06,EN,,0,0,0,,The program we're going to write on the blackboard Dialogue: 0,0:05:46.56,0:05:50.24,EN,,0,0,0,,is ugly, dirty, disgusting, Dialogue: 0,0:05:50.94,0:05:53.16,EN,,0,0,0,,not the way I would write this is a professional. Dialogue: 0,0:05:54.32,0:05:56.57,EN,,0,0,0,,It is written with concrete syntax, Dialogue: 0,0:05:57.24,0:05:58.83,EN,,0,0,0,,meaning you've got really to use lots of CARs and CDRs Dialogue: 0,0:05:58.84,0:06:00.62,EN,,0,0,0,,which is exactly what I told you not to do. Dialogue: 0,0:06:02.94,0:06:05.61,EN,,0,0,0,,That's on purpose in this case, Dialogue: 0,0:06:06.11,0:06:09.02,EN,,0,0,0,,because I want it to be small, compact, Dialogue: 0,0:06:09.34,0:06:10.40,EN,,0,0,0,,fit on the blackboard Dialogue: 0,0:06:10.43,0:06:11.85,EN,,0,0,0,,so you can get the whole thing. Dialogue: 0,0:06:12.42,0:06:14.80,EN,,0,0,0,,So I don't want to use long names like I normally use. Dialogue: 0,0:06:15.60,0:06:17.29,EN,,0,0,0,,I want to use CAR-CDR because it's short. Dialogue: 0,0:06:18.06,0:06:20.78,EN,,0,0,0,,Okay, I wanna, it's a whole, that's a trade-off. Dialogue: 0,0:06:20.89,0:06:22.81,EN,,0,0,0,,I don't want you writing programs like this. Dialogue: 0,0:06:23.57,0:06:25.08,EN,,0,0,0,,This is purely for an effect. Dialogue: 0,0:06:25.85,0:06:27.61,EN,,0,0,0,,Now, you're going to have to work a little harder to read it, Dialogue: 0,0:06:27.77,0:06:30.19,EN,,0,0,0,,but I'm going to try to make it clear as I'm writing it. Dialogue: 0,0:06:31.27,0:06:34.40,EN,,0,0,0,,I'm also-- this is a pretty much complete interpreter, Dialogue: 0,0:06:34.51,0:06:36.24,EN,,0,0,0,,but there's going to be room for putting in more things-- Dialogue: 0,0:06:36.25,0:06:38.60,EN,,0,0,0,,I'm going to leave out definition and assignment, Dialogue: 0,0:06:39.10,0:06:42.41,EN,,0,0,0,,just because they are not essential, Dialogue: 0,0:06:42.88,0:06:46.46,EN,,0,0,0,,and a, for a mathematical reason I'll show you later Dialogue: 0,0:06:46.92,0:06:49.96,EN,,0,0,0,,and also they take up more space. Dialogue: 0,0:06:51.88,0:06:53.64,EN,,0,0,0,,But, in any case, what do we have to do? Dialogue: 0,0:06:53.95,0:06:55.66,EN,,0,0,0,,We have to do a dispatch Dialogue: 0,0:06:56.09,0:06:57.90,EN,,0,0,0,,which breaks the types of expressions up Dialogue: 0,0:06:58.28,0:07:00.38,EN,,0,0,0,,into particular classes. Dialogue: 0,0:07:01.72,0:07:03.26,EN,,0,0,0,,Okay? So that's what we're going to have here. Dialogue: 0,0:07:03.82,0:07:05.15,EN,,0,0,0,,Well, what expressions are there? Dialogue: 0,0:07:05.15,0:07:06.36,EN,,0,0,0,,Let's look at the kinds of expressions. Dialogue: 0,0:07:06.81,0:07:09.60,EN,,0,0,0,,We can have things like the numeral three. Dialogue: 0,0:07:10.42,0:07:11.58,EN,,0,0,0,,What do I want that to do? Dialogue: 0,0:07:12.72,0:07:14.75,EN,,0,0,0,,I can make choices, but I think right now, Dialogue: 0,0:07:15.05,0:07:16.20,EN,,0,0,0,,I want it to be a three. Dialogue: 0,0:07:17.05,0:07:17.88,EN,,0,0,0,,That's what I want. Dialogue: 0,0:07:18.72,0:07:19.69,EN,,0,0,0,,So that's easy enough. Dialogue: 0,0:07:20.03,0:07:22.91,EN,,0,0,0,,That means I want, if the thing is a number, Dialogue: 0,0:07:27.29,0:07:31.68,EN,,0,0,0,,that I want the expression itself as the answer. Dialogue: 0,0:07:35.42,0:07:36.76,EN,,0,0,0,,Now the next possibility Dialogue: 0,0:07:36.89,0:07:38.86,EN,,0,0,0,,is things that we represent as symbols. Dialogue: 0,0:07:39.39,0:07:46.75,EN,,0,0,0,,Examples of symbols are things like x, n, eval, number, x. Dialogue: 0,0:07:48.01,0:07:49.18,EN,,0,0,0,,What do I mean them to be? Dialogue: 0,0:07:50.16,0:07:51.63,EN,,0,0,0,,Those are things that stand for other things. Dialogue: 0,0:07:51.63,0:07:53.23,EN,,0,0,0,,Those are the variables of our language. Dialogue: 0,0:07:54.77,0:07:56.88,EN,,0,0,0,,And so I want to be able to say, for example, Dialogue: 0,0:07:57.05,0:08:01.04,EN,,0,0,0,,that x, for example, transforms to it's value which might be three. Dialogue: 0,0:08:02.64,0:08:05.76,EN,,0,0,0,,Or I might ask something like car. Dialogue: 0,0:08:07.76,0:08:09.40,EN,,0,0,0,,I want to have as its value-- Dialogue: 0,0:08:09.63,0:08:11.34,EN,,0,0,0,,be something like some procedure, Dialogue: 0,0:08:16.51,0:08:18.43,EN,,0,0,0,,which I don't know what is inside there, Dialogue: 0,0:08:18.64,0:08:21.15,EN,,0,0,0,,perhaps a machine language code or something like that. Dialogue: 0,0:08:22.84,0:08:24.27,EN,,0,0,0,,Ok? So, well, that's easy enough. Dialogue: 0,0:08:24.43,0:08:26.89,EN,,0,0,0,,I'm going to push that off on someone else. Dialogue: 0,0:08:27.80,0:08:28.89,EN,,0,0,0,,If something is a symbol, Dialogue: 0,0:08:30.80,0:08:32.48,EN,,0,0,0,,if the expression is a symbol, Dialogue: 0,0:08:33.42,0:08:34.88,EN,,0,0,0,,then I want the answer to be the result, Dialogue: 0,0:08:34.91,0:08:40.24,EN,,0,0,0,,looking up the expression in the environment. Dialogue: 0,0:08:46.48,0:08:48.99,EN,,0,0,0,,Now the environment is a dictionary Dialogue: 0,0:08:49.96,0:08:54.06,EN,,0,0,0,,which maps the symbol names to their values. Dialogue: 0,0:08:54.28,0:08:55.16,EN,,0,0,0,,And that's all it is. Dialogue: 0,0:08:56.28,0:08:57.20,EN,,0,0,0,,How it's done? Dialogue: 0,0:08:57.53,0:08:58.52,EN,,0,0,0,,Well, we'll see that later. Dialogue: 0,0:08:59.68,0:09:00.57,EN,,0,0,0,,It's very easy. Dialogue: 0,0:09:01.67,0:09:04.28,EN,,0,0,0,,It's easy to make data structures that are tables of various sorts. Dialogue: 0,0:09:04.84,0:09:05.74,EN,,0,0,0,,But it's only a table, Dialogue: 0,0:09:05.77,0:09:07.56,EN,,0,0,0,,and this is the access routine for some table. Dialogue: 0,0:09:09.55,0:09:10.81,EN,,0,0,0,,Ok? Well, the next thing, Dialogue: 0,0:09:11.31,0:09:12.56,EN,,0,0,0,,another kind of expression-- Dialogue: 0,0:09:12.67,0:09:15.56,EN,,0,0,0,,you have things that are described constants that are not numbers, Dialogue: 0,0:09:16.06,0:09:17.43,EN,,0,0,0,,like 'foo. Dialogue: 0,0:09:20.17,0:09:21.29,EN,,0,0,0,,Well, for my convenience, Dialogue: 0,0:09:21.31,0:09:23.36,EN,,0,0,0,,I want to syntactically transform that Dialogue: 0,0:09:24.73,0:09:26.80,EN,,0,0,0,,into a list structure which is, Dialogue: 0,0:09:26.84,0:09:31.52,EN,,0,0,0,,which is, quote foo. Dialogue: 0,0:09:33.72,0:09:37.18,EN,,0,0,0,,Or it's -- A quoted object, whatever it is, Dialogue: 0,0:09:38.35,0:09:40.83,EN,,0,0,0,,is going to be actually an abbreviation, Dialogue: 0,0:09:41.04,0:09:42.59,EN,,0,0,0,,which is not part of the evaluator Dialogue: 0,0:09:43.21,0:09:44.46,EN,,0,0,0,,but happens somewhere else, Dialogue: 0,0:09:44.75,0:09:47.79,EN,,0,0,0,,an abbreviation for an expression that looks like this. Dialogue: 0,0:09:48.78,0:09:50.48,EN,,0,0,0,,This way, I can test for Dialogue: 0,0:09:50.57,0:09:53.12,EN,,0,0,0,,the type of the expression as being a quotation Dialogue: 0,0:09:53.31,0:09:55.95,EN,,0,0,0,,by examining the car of the expression. Dialogue: 0,0:09:58.46,0:10:01.08,EN,,0,0,0,,So I'm not going to worry about that in the evaluator. Dialogue: 0,0:10:01.65,0:10:02.68,EN,,0,0,0,,It's happening somewhere earlier Dialogue: 0,0:10:02.70,0:10:03.96,EN,,0,0,0,,in the reader or something. Dialogue: 0,0:10:05.54,0:10:15.04,EN,,0,0,0,,If the expression of the expression is quote, Dialogue: 0,0:10:18.27,0:10:19.10,EN,,0,0,0,,then what I want, Dialogue: 0,0:10:19.63,0:10:25.13,EN,,0,0,0,,I want quote foo to itself evaluate to foo. Dialogue: 0,0:10:25.14,0:10:25.95,EN,,0,0,0,,It's a constant. Dialogue: 0,0:10:27.53,0:10:28.92,EN,,0,0,0,,This is just a way of saying Dialogue: 0,0:10:29.08,0:10:30.73,EN,,0,0,0,,that this evaluates to itself. Dialogue: 0,0:10:31.79,0:10:33.66,EN,,0,0,0,,Ok? So thats the. What is that? Dialogue: 0,0:10:33.66,0:10:36.36,EN,,0,0,0,,That's the first of the second of the list. Dialogue: 0,0:10:36.59,0:10:37.58,EN,,0,0,0,,That's the second of the list. Dialogue: 0,0:10:38.49,0:10:40.32,EN,,0,0,0,,The second element of the list is it's CADR. Dialogue: 0,0:10:41.28,0:10:42.38,EN,,0,0,0,,So I'm just going to write here, CADR. Dialogue: 0,0:10:51.08,0:10:52.35,EN,,0,0,0,,OK? What else do we have here? Dialogue: 0,0:10:52.51,0:10:53.80,EN,,0,0,0,,We have lambda expressions, Dialogue: 0,0:10:55.00,0:11:03.29,EN,,0,0,0,,for example, lambda of x plus x y. Dialogue: 0,0:11:04.16,0:11:06.33,EN,,0,0,0,,Well, I going have to have some representation for the procedure Dialogue: 0,0:11:06.33,0:11:07.85,EN,,0,0,0,,which is the value of an expression, Dialogue: 0,0:11:08.11,0:11:09.08,EN,,0,0,0,,of a lambda expression. Dialogue: 0,0:11:09.60,0:11:12.62,EN,,0,0,0,,The procedure here is not the expression lambda x. Dialogue: 0,0:11:13.13,0:11:15.56,EN,,0,0,0,,That's the description of it, the textual description. Dialogue: 0,0:11:16.41,0:11:18.33,EN,,0,0,0,,However, what what I going to expect to see here Dialogue: 0,0:11:18.56,0:11:21.20,EN,,0,0,0,,is something which contains an environment as one of its parts Dialogue: 0,0:11:23.23,0:11:25.36,EN,,0,0,0,,if I'm implementing a lexical language. Dialogue: 0,0:11:25.84,0:11:29.07,EN,,0,0,0,,And so what I'd like to see Dialogue: 0,0:11:29.20,0:11:30.67,EN,,0,0,0,,is some type flags. Dialogue: 0,0:11:30.70,0:11:33.90,EN,,0,0,0,,I'm going to have to be able to distinguish procedures later, Dialogue: 0,0:11:34.30,0:11:36.59,EN,,0,0,0,,procedures which were produced by lambdas, Dialogue: 0,0:11:36.81,0:11:38.03,EN,,0,0,0,,from ones that may be primitive. Dialogue: 0,0:11:39.06,0:11:41.96,EN,,0,0,0,,And so I'm going to have some flag, Dialogue: 0,0:11:41.98,0:11:43.56,EN,,0,0,0,,which I'll just arbitrarily call closure, Dialogue: 0,0:11:43.56,0:11:45.10,EN,,0,0,0,,just for historical reasons. Dialogue: 0,0:11:47.68,0:11:49.60,EN,,0,0,0,,Now, to say what parts of this are important. Dialogue: 0,0:11:49.92,0:11:51.12,EN,,0,0,0,,I'm going to need to know Dialogue: 0,0:11:51.24,0:11:52.92,EN,,0,0,0,,the bound variable list and the body. Dialogue: 0,0:11:54.22,0:11:55.40,EN,,0,0,0,,Well, that's the CDR of this, Dialogue: 0,0:11:56.09,0:12:01.85,EN,,0,0,0,,so it's going to be x and plus x y and some environment. Dialogue: 0,0:12:03.04,0:12:03.87,EN,,0,0,0,,and some environment. Dialogue: 0,0:12:08.17,0:12:12.20,EN,,0,0,0,,Now this is not something that users should ever see, Dialogue: 0,0:12:13.53,0:12:16.19,EN,,0,0,0,,this is purely a representation, internally, Dialogue: 0,0:12:16.76,0:12:18.30,EN,,0,0,0,,for a procedure object. Dialogue: 0,0:12:18.52,0:12:20.52,EN,,0,0,0,,It contains a bound variable list, Dialogue: 0,0:12:20.70,0:12:22.62,EN,,0,0,0,,a body, and an environment, Dialogue: 0,0:12:23.53,0:12:25.80,EN,,0,0,0,,and some type tag saying, I am a procedure. Dialogue: 0,0:12:26.34,0:12:27.37,EN,,0,0,0,,I'm going to make one now. Dialogue: 0,0:12:28.08,0:12:38.72,EN,,0,0,0,,So if the CAR of the expression is quote lambda, Dialogue: 0,0:12:43.47,0:12:44.81,EN,,0,0,0,,then what I'm going to put here Dialogue: 0,0:12:45.64,0:12:51.84,EN,,0,0,0,,is-- I'm going to make a list of closure, Dialogue: 0,0:12:55.15,0:13:00.73,EN,,0,0,0,,the CDR of the procedure description Dialogue: 0,0:13:01.56,0:13:02.97,EN,,0,0,0,,was everything except the lambda, Dialogue: 0,0:13:07.74,0:13:08.86,EN,,0,0,0,,and the current environment. Dialogue: 0,0:13:10.25,0:13:15.32,EN,,0,0,0,,This implements the rule for environments in the environment model. Dialogue: 0,0:13:15.45,0:13:18.52,EN,,0,0,0,,It has to do with construction of procedures from lambda expressions. Dialogue: 0,0:13:19.40,0:13:20.97,EN,,0,0,0,,The environment that was around Dialogue: 0,0:13:21.48,0:13:24.32,EN,,0,0,0,,at the time the evaluator encountered the lambda expression Dialogue: 0,0:13:25.04,0:13:28.46,EN,,0,0,0,,is the environment where the lambda expression gets Dialogue: 0,0:13:28.68,0:13:31.77,EN,,0,0,0,,where the procedure resulting interprets it's free variables. Dialogue: 0,0:13:34.72,0:13:35.82,EN,,0,0,0,,So that's part of that. Dialogue: 0,0:13:35.92,0:13:37.55,EN,,0,0,0,,And so we have to capture that environment Dialogue: 0,0:13:37.56,0:13:38.86,EN,,0,0,0,,as part of the procedure object. Dialogue: 0,0:13:39.21,0:13:40.62,EN,,0,0,0,,And we'll see how that gets used later. Dialogue: 0,0:13:42.03,0:13:43.77,EN,,0,0,0,,There are also conditional expressions Dialogue: 0,0:13:44.59,0:13:52.81,EN,,0,0,0,,of things like COND of say, p one, e one, p two, e two. Dialogue: 0,0:13:54.40,0:13:56.09,EN,,0,0,0,,Where this is a predicate, Dialogue: 0,0:13:56.35,0:13:58.43,EN,,0,0,0,,a predicate is a thing that is either true or false, Dialogue: 0,0:13:58.99,0:14:01.76,EN,,0,0,0,,and the expression to be evaluated if the predicate is true. Dialogue: 0,0:14:03.44,0:14:06.08,EN,,0,0,0,,A set of clauses, if you will, that's the name for such a thing. Dialogue: 0,0:14:06.79,0:14:09.36,EN,,0,0,0,,So I'm going put that somewhere else. Dialogue: 0,0:14:09.36,0:14:11.56,EN,,0,0,0,,We're going to worry about that in another piece of code. Dialogue: 0,0:14:12.42,0:14:21.28,EN,,0,0,0,,So EQ-- if the CAR of the expression is COND, Dialogue: 0,0:14:24.00,0:14:26.84,EN,,0,0,0,,then I'm going to do nothing more than evaluate the COND, Dialogue: 0,0:14:30.20,0:14:31.42,EN,,0,0,0,,the CDR of the expression. Dialogue: 0,0:14:34.40,0:14:38.49,EN,,0,0,0,,That's all the clauses in the environment that I'm given. Dialogue: 0,0:14:41.43,0:14:42.60,EN,,0,0,0,,Well, there's one more case, Dialogue: 0,0:14:44.09,0:14:48.22,EN,,0,0,0,,arbitrary thing like the sum of x and three, Dialogue: 0,0:14:50.62,0:14:53.95,EN,,0,0,0,,where this is an operator applied to operands, Dialogue: 0,0:14:55.13,0:14:56.59,EN,,0,0,0,,and there's nothing special about it. Dialogue: 0,0:14:56.59,0:14:59.63,EN,,0,0,0,,It's not one of the special cases, the special forms. Dialogue: 0,0:14:59.85,0:15:01.42,EN,,0,0,0,,These are the special forms. Dialogue: 0,0:15:09.65,0:15:12.12,EN,,0,0,0,,And if I were writing here a professional program, again, Dialogue: 0,0:15:12.36,0:15:14.17,EN,,0,0,0,,I would somehow make this data directed. Dialogue: 0,0:15:14.48,0:15:16.52,EN,,0,0,0,,So there wouldn't be a sequence of conditionals here, Dialogue: 0,0:15:16.65,0:15:18.20,EN,,0,0,0,,there'd be a dispatch on some bits Dialogue: 0,0:15:19.42,0:15:22.25,EN,,0,0,0,,if I were trying to do this in a more professional way. Dialogue: 0,0:15:22.36,0:15:24.14,EN,,0,0,0,,So that, in fact, I can add to the thing Dialogue: 0,0:15:24.68,0:15:26.38,EN,,0,0,0,,without changing my program much. Dialogue: 0,0:15:26.71,0:15:28.46,EN,,0,0,0,,So, for example, they would run fast, Dialogue: 0,0:15:29.04,0:15:30.43,EN,,0,0,0,,but I'm not worried about that. Dialogue: 0,0:15:31.28,0:15:33.98,EN,,0,0,0,,Here we're trying to look at this in its entirety. Dialogue: 0,0:15:35.07,0:15:35.80,EN,,0,0,0,,So it's else. Dialogue: 0,0:15:37.69,0:15:38.56,EN,,0,0,0,,Well, what do we do? Dialogue: 0,0:15:38.56,0:15:41.23,EN,,0,0,0,,In this case, I have to somehow do an addition. Dialogue: 0,0:15:44.35,0:15:46.16,EN,,0,0,0,,Well, I could find out what the plus is. Dialogue: 0,0:15:46.84,0:15:49.29,EN,,0,0,0,,I have to find out what the x and the three are. Dialogue: 0,0:15:50.55,0:15:53.96,EN,,0,0,0,,And then I have to apply the result of finding what the plus is Dialogue: 0,0:15:54.43,0:15:57.00,EN,,0,0,0,,to the result of finding out what the x and the three are. Dialogue: 0,0:15:58.11,0:15:59.39,EN,,0,0,0,,We'll have a name for that. Dialogue: 0,0:15:59.87,0:16:09.55,EN,,0,0,0,,So I'm going to apply the result of evaluating the CAR Dialogue: 0,0:16:11.20,0:16:12.14,EN,,0,0,0,,of the expression-- Dialogue: 0,0:16:13.21,0:16:15.50,EN,,0,0,0,,the car of the expression is the operator-- Dialogue: 0,0:16:17.20,0:16:18.51,EN,,0,0,0,,in the environment given. Dialogue: 0,0:16:20.51,0:16:22.89,EN,,0,0,0,,So evaluating the operator gets me the procedure. Dialogue: 0,0:16:24.05,0:16:26.78,EN,,0,0,0,,Now I have to evaluate all the operands to get the arguments. Dialogue: 0,0:16:27.29,0:16:28.22,EN,,0,0,0,,I'll call that EVLIST, Dialogue: 0,0:16:31.26,0:16:35.53,EN,,0,0,0,,the CDR of the operands, of the expression, Dialogue: 0,0:16:36.76,0:16:39.00,EN,,0,0,0,,with respect to the environment. Dialogue: 0,0:16:41.94,0:16:43.13,EN,,0,0,0,,EVLIST will come up later-- Dialogue: 0,0:16:43.26,0:16:48.07,EN,,0,0,0,,EVLIST, apply, COND pair, COND, lambda, define. Dialogue: 0,0:16:50.90,0:16:52.33,EN,,0,0,0,,So that what you are seeing here Dialogue: 0,0:16:52.67,0:16:56.11,EN,,0,0,0,,is pretty much all there is in the evaluator itself. Dialogue: 0,0:16:56.49,0:17:01.00,EN,,0,0,0,,It's the case dispatch on the type of the expression Dialogue: 0,0:17:01.24,0:17:02.11,EN,,0,0,0,,with the default Dialogue: 0,0:17:04.99,0:17:07.95,EN,,0,0,0,,being a general application or a combination. Dialogue: 0,0:17:17.52,0:17:19.52,EN,,0,0,0,,Now there is lots of things we haven't defined yet. Dialogue: 0,0:17:20.08,0:17:21.60,EN,,0,0,0,,Let's just look at them and see what they are. Dialogue: 0,0:17:21.78,0:17:24.12,EN,,0,0,0,,We're going to have to do this later, evcond. Dialogue: 0,0:17:25.48,0:17:26.67,EN,,0,0,0,,We have to write apply. Dialogue: 0,0:17:27.57,0:17:28.62,EN,,0,0,0,,We're going to have to write EVLIST. Dialogue: 0,0:17:28.94,0:17:30.20,EN,,0,0,0,,We're going to write LOOKUP. Dialogue: 0,0:17:31.79,0:17:33.43,EN,,0,0,0,,I think that's everything, isn't there? Dialogue: 0,0:17:33.43,0:17:35.16,EN,,0,0,0,,Everything else is something which is simple, Dialogue: 0,0:17:35.16,0:17:37.18,EN,,0,0,0,,or primitive, or something like that. Dialogue: 0,0:17:38.57,0:17:39.48,EN,,0,0,0,,And, of course, Dialogue: 0,0:17:39.69,0:17:42.06,EN,,0,0,0,,we could many more special forms here, Dialogue: 0,0:17:42.25,0:17:44.45,EN,,0,0,0,,but that would be a bad idea in general in a language. Dialogue: 0,0:17:44.45,0:17:45.92,EN,,0,0,0,,You make a language very complicated Dialogue: 0,0:17:46.00,0:17:47.48,EN,,0,0,0,,by putting a lot of things in there. Dialogue: 0,0:17:47.69,0:17:50.35,EN,,0,0,0,,The number of reserve words that should exist in a language Dialogue: 0,0:17:50.76,0:17:53.61,EN,,0,0,0,,should be no more than a person could remember on his fingers and toes. Dialogue: 0,0:17:54.16,0:17:55.53,EN,,0,0,0,,And I get very upset with languages Dialogue: 0,0:17:55.56,0:17:58.20,EN,,0,0,0,,which have hundreds of reserve words. Dialogue: 0,0:17:59.41,0:18:00.71,EN,,0,0,0,,But that's where the reserve words go. Dialogue: 0,0:18:03.15,0:18:06.54,EN,,0,0,0,,Okay. Well, now let's get to the next part of this, Dialogue: 0,0:18:06.56,0:18:07.69,EN,,0,0,0,,the kernel, apply. Dialogue: 0,0:18:09.64,0:18:10.75,EN,,0,0,0,,What else is this doing? Dialogue: 0,0:18:11.59,0:18:17.53,EN,,0,0,0,,Well, apply's job is to take a procedure and apply it to its arguments Dialogue: 0,0:18:17.66,0:18:20.68,EN,,0,0,0,,after both have been evaluated to come up with a procedure and the arguments Dialogue: 0,0:18:20.91,0:18:23.85,EN,,0,0,0,,rather the operator symbols and the operand symbols, Dialogue: 0,0:18:24.09,0:18:26.96,EN,,0,0,0,,whatever they are-- symbolic expressions. Dialogue: 0,0:18:33.27,0:18:35.08,EN,,0,0,0,,So we will define apply Dialogue: 0,0:18:38.35,0:18:40.65,EN,,0,0,0,,to be a procedure of two arguments, Dialogue: 0,0:18:40.75,0:18:43.44,EN,,0,0,0,,a procedure and arguments. Dialogue: 0,0:18:47.24,0:18:48.12,EN,,0,0,0,,And what does it do? Dialogue: 0,0:18:48.14,0:18:49.55,EN,,0,0,0,,It does nothing very complicated. Dialogue: 0,0:18:49.93,0:18:50.78,EN,,0,0,0,,It's got two cases. Dialogue: 0,0:18:53.58,0:18:55.16,EN,,0,0,0,,Either the procedure is primitive-- Dialogue: 0,0:19:03.42,0:19:06.41,EN,,0,0,0,,And I don't know exactly how that is done. Dialogue: 0,0:19:06.86,0:19:10.24,EN,,0,0,0,,It's possible there's some type information Dialogue: 0,0:19:10.38,0:19:12.41,EN,,0,0,0,,just like we made closure for, here, Dialogue: 0,0:19:12.68,0:19:15.05,EN,,0,0,0,,being the description of the type of a compound thing-- Dialogue: 0,0:19:16.33,0:19:17.79,EN,,0,0,0,,OK? probably so. Dialogue: 0,0:19:18.55,0:19:20.20,EN,,0,0,0,,But it is not essential how that works, Dialogue: 0,0:19:20.68,0:19:22.01,EN,,0,0,0,,in fact, it turns out, Dialogue: 0,0:19:22.19,0:19:23.85,EN,,0,0,0,,as you probably know or have deduced, Dialogue: 0,0:19:23.87,0:19:25.47,EN,,0,0,0,,that you don't need any primitives anyway. Dialogue: 0,0:19:27.35,0:19:29.28,EN,,0,0,0,,You can compute anything because without Dialogue: 0,0:19:30.46,0:19:33.19,EN,,0,0,0,,because some of the lambda that I've been playing with. Dialogue: 0,0:19:33.61,0:19:34.76,EN,,0,0,0,,But it's nice to have them. Dialogue: 0,0:19:34.81,0:19:36.27,EN,,0,0,0,,So here we're going to do some magic Dialogue: 0,0:19:36.30,0:19:37.47,EN,,0,0,0,,which I'm not going to explain. Dialogue: 0,0:19:38.06,0:19:41.44,EN,,0,0,0,,Go to machine language, apply primop. Dialogue: 0,0:19:42.91,0:19:43.80,EN,,0,0,0,,Here's how it adds. Dialogue: 0,0:19:44.78,0:19:46.10,EN,,0,0,0,,Execute an add instruction. Dialogue: 0,0:19:50.62,0:19:52.11,EN,,0,0,0,,However, the interesting part of a language Dialogue: 0,0:19:52.14,0:19:54.27,EN,,0,0,0,,is the glue by which the primitives are glued together. Dialogue: 0,0:19:54.91,0:19:55.90,EN,,0,0,0,,So let's look at that. Dialogue: 0,0:19:56.91,0:19:58.38,EN,,0,0,0,,Well, the other possibility Dialogue: 0,0:19:58.75,0:20:04.12,EN,,0,0,0,,this is a compound made up by executing a lambda expression, Dialogue: 0,0:20:04.97,0:20:07.05,EN,,0,0,0,,this is a compound procedure. Dialogue: 0,0:20:07.62,0:20:09.36,EN,,0,0,0,,Well, we'll check its type. Dialogue: 0,0:20:10.11,0:20:17.07,EN,,0,0,0,,If it is closure, Dialogue: 0,0:20:20.51,0:20:24.09,EN,,0,0,0,,if it's one of those, then I have to do an eval of the body. Dialogue: 0,0:20:24.19,0:20:27.39,EN,,0,0,0,,The way I do this, the way I deal with this at all Dialogue: 0,0:20:28.08,0:20:31.69,EN,,0,0,0,,is the way I evaluate the application of a procedure to its arguments, Dialogue: 0,0:20:31.72,0:20:33.71,EN,,0,0,0,,is by evaluating the body of the procedure Dialogue: 0,0:20:34.19,0:20:37.80,EN,,0,0,0,,in the environment resulting from extending the environment of the procedure Dialogue: 0,0:20:37.92,0:20:40.48,EN,,0,0,0,,with the bindings of the formal parameters Dialogue: 0,0:20:41.02,0:20:43.68,EN,,0,0,0,,of the procedure to the arguments that were passed to it. Dialogue: 0,0:20:46.70,0:20:47.87,EN,,0,0,0,,That was a long sentence. Dialogue: 0,0:20:51.13,0:20:52.16,EN,,0,0,0,,Well that's easy enough. Dialogue: 0,0:20:52.82,0:20:54.48,EN,,0,0,0,,Now here's going to be a lot of CAR-CDRing. Dialogue: 0,0:20:56.46,0:20:58.11,EN,,0,0,0,,I have to get the body of the procedure. Dialogue: 0,0:20:59.40,0:21:02.30,EN,,0,0,0,,Where's the body of the procedure in here? Dialogue: 0,0:21:02.96,0:21:04.08,EN,,0,0,0,,Well here's the CAR, Dialogue: 0,0:21:04.49,0:21:06.13,EN,,0,0,0,,here's the CDR is the whole rest of this. Dialogue: 0,0:21:06.13,0:21:06.96,EN,,0,0,0,,So here's the CADR. Dialogue: 0,0:21:07.40,0:21:09.45,EN,,0,0,0,,And so I see, what I have here is the body Dialogue: 0,0:21:09.45,0:21:13.04,EN,,0,0,0,,is the second element of the second element of the procedure. Dialogue: 0,0:21:13.20,0:21:15.15,EN,,0,0,0,,So it's the CADR of the CADR or the CADADR. Dialogue: 0,0:21:19.17,0:21:27.68,EN,,0,0,0,,It's the C-A-D-A-D-R, CADADR of the procedure. Dialogue: 0,0:21:30.26,0:21:31.56,EN,,0,0,0,,To evaluate the body Dialogue: 0,0:21:31.98,0:21:36.48,EN,,0,0,0,,in the result of binding that's making up more environment, Dialogue: 0,0:21:38.09,0:21:42.06,EN,,0,0,0,,well I need the formal parameters of the of the procedure, Dialogue: 0,0:21:42.06,0:21:42.72,EN,,0,0,0,,what is that? Dialogue: 0,0:21:43.50,0:21:45.13,EN,,0,0,0,,That's the CAR of the CADR. Dialogue: 0,0:21:46.52,0:21:48.78,EN,,0,0,0,,OK? It's horrible isn't it? Dialogue: 0,0:21:52.65,0:21:53.63,EN,,0,0,0,,--of the procedure. Dialogue: 0,0:21:55.44,0:22:00.86,EN,,0,0,0,,Bind that to the arguments that were passed in the environment, Dialogue: 0,0:22:00.89,0:22:04.14,EN,,0,0,0,,which is passed also as part of the procedure. Dialogue: 0,0:22:04.54,0:22:07.90,EN,,0,0,0,,Well, that's the CAR of the CDR of the CDR of this, Dialogue: 0,0:22:09.79,0:22:16.62,EN,,0,0,0,,CADDR, of the procedure. Dialogue: 0,0:22:20.29,0:22:24.96,EN,,0,0,0,,Bind, eval, pair, COND, lamda, define-- Dialogue: 0,0:22:26.14,0:22:29.68,EN,,0,0,0,,Now, of course, if I were being really a neat character, Dialogue: 0,0:22:29.87,0:22:31.34,EN,,0,0,0,,and I was being very careful, Dialogue: 0,0:22:32.24,0:22:34.12,EN,,0,0,0,,I would actually put an extra case here Dialogue: 0,0:22:34.38,0:22:35.98,EN,,0,0,0,,for checking for certain errors like, Dialogue: 0,0:22:36.17,0:22:38.41,EN,,0,0,0,,did you try to apply one to an argument? Dialogue: 0,0:22:39.00,0:22:41.69,EN,,0,0,0,,You get a undefined procedure type. Dialogue: 0,0:22:42.57,0:22:44.09,EN,,0,0,0,,So I may as well do that anyway. Dialogue: 0,0:22:45.80,0:22:55.96,EN,,0,0,0,,--else, some sort of error, like that. Dialogue: 0,0:22:57.61,0:23:01.61,EN,,0,0,0,,Now, of course, again, in some sort of more real system, Dialogue: 0,0:23:02.56,0:23:04.22,EN,,0,0,0,,written for professional reasons, Dialogue: 0,0:23:05.32,0:23:08.00,EN,,0,0,0,,this would be written with a case analysis Dialogue: 0,0:23:08.36,0:23:09.90,EN,,0,0,0,,done by some sort of dispatch. Dialogue: 0,0:23:10.75,0:23:12.68,EN,,0,0,0,,Over here, I would probably have other cases Dialogue: 0,0:23:12.70,0:23:14.14,EN,,0,0,0,,like, is this compiled code? Dialogue: 0,0:23:16.22,0:23:16.84,EN,,0,0,0,,It's very important. Dialogue: 0,0:23:16.88,0:23:18.35,EN,,0,0,0,,I might have distinguished the kind of code Dialogue: 0,0:23:18.38,0:23:22.33,EN,,0,0,0,,that's produced by a directly evaluating a lambda in interpretation Dialogue: 0,0:23:22.94,0:23:25.87,EN,,0,0,0,,from code that was produced by somebody's compiler or something like that. Dialogue: 0,0:23:26.11,0:23:27.23,EN,,0,0,0,,And we'll talk about that later. Dialogue: 0,0:23:27.23,0:23:29.61,EN,,0,0,0,,Or is this a piece Fortran program I have to go off and execute. Dialogue: 0,0:23:30.51,0:23:32.51,EN,,0,0,0,,It's a perfectly possible thing, at this point, to do that. Dialogue: 0,0:23:32.92,0:23:36.41,EN,,0,0,0,,In fact, in this concrete syntax evaluator I'm writing here, Dialogue: 0,0:23:37.45,0:23:40.86,EN,,0,0,0,,there's an assumption built in that this is Lisp, Dialogue: 0,0:23:42.30,0:23:43.82,EN,,0,0,0,,because I'm using CARs and CDRs. Dialogue: 0,0:23:43.84,0:23:45.10,EN,,0,0,0,,CAR means the operator, Dialogue: 0,0:23:45.28,0:23:46.64,EN,,0,0,0,,and CDR means the operand. Dialogue: 0,0:23:46.75,0:23:49.96,EN,,0,0,0,,In the text, there is an abstract syntax evaluator Dialogue: 0,0:23:50.35,0:23:53.15,EN,,0,0,0,,which these could be-- these are given abstract names Dialogue: 0,0:23:53.16,0:23:54.09,EN,,0,0,0,,like operator, and operand, Dialogue: 0,0:23:54.14,0:23:55.82,EN,,0,0,0,,and all these other things are like that. Dialogue: 0,0:23:56.16,0:23:56.86,EN,,0,0,0,,And, in that case, Dialogue: 0,0:23:57.02,0:24:00.91,EN,,0,0,0,,you could reprogram it to be ALGOL with no problem. Dialogue: 0,0:24:03.36,0:24:06.40,EN,,0,0,0,,Well, here we have added another couple of things Dialogue: 0,0:24:07.20,0:24:08.43,EN,,0,0,0,,that we haven't defined. Dialogue: 0,0:24:10.81,0:24:12.57,EN,,0,0,0,,I don't think I'll worry about these at all, Dialogue: 0,0:24:13.39,0:24:15.05,EN,,0,0,0,,however, this one will be interesting later. Dialogue: 0,0:24:17.18,0:24:19.76,EN,,0,0,0,,Let's just proceed through this and get it done. Dialogue: 0,0:24:20.55,0:24:22.65,EN,,0,0,0,,There's only two more blackboards so it can't be very long. Dialogue: 0,0:24:27.40,0:24:29.08,EN,,0,0,0,,It's carefully tailored to exactly fit. Dialogue: 0,0:24:30.07,0:24:30.98,EN,,0,0,0,,Well, what do we have left? Dialogue: 0,0:24:30.98,0:24:33.20,EN,,0,0,0,,We have to define EVLIST, which is over here. Dialogue: 0,0:24:33.73,0:24:35.07,EN,,0,0,0,,And EVLIST is nothing more Dialogue: 0,0:24:35.26,0:24:43.08,EN,,0,0,0,,than a map down a bunch of operands producing arguments. Dialogue: 0,0:24:44.30,0:24:45.40,EN,,0,0,0,,But I'm going to write it out. Dialogue: 0,0:24:45.82,0:24:48.30,EN,,0,0,0,,And one of the reasons I'm going to write this out is for a mystical reason, Dialogue: 0,0:24:49.88,0:24:52.04,EN,,0,0,0,,which is I want to make this evaluator so simple Dialogue: 0,0:24:52.06,0:24:53.56,EN,,0,0,0,,that it can understand itself. Dialogue: 0,0:24:56.45,0:24:58.09,EN,,0,0,0,,I'm going to really worry about that a little bit. Dialogue: 0,0:25:00.23,0:25:01.74,EN,,0,0,0,,So let's write it out completely. Dialogue: 0,0:25:02.85,0:25:04.24,EN,,0,0,0,,See, I don't want to worry about Dialogue: 0,0:25:04.27,0:25:06.08,EN,,0,0,0,,whether or not the thing can pass functional arguments. Dialogue: 0,0:25:06.27,0:25:08.06,EN,,0,0,0,,The value evaluator is not going to use them. Dialogue: 0,0:25:08.98,0:25:10.78,EN,,0,0,0,,The evaluator is not going to produce functional values. Dialogue: 0,0:25:10.88,0:25:12.67,EN,,0,0,0,,So even if there were a different, alternative language Dialogue: 0,0:25:12.80,0:25:13.96,EN,,0,0,0,,that were very close to this, Dialogue: 0,0:25:15.16,0:25:17.79,EN,,0,0,0,,this evaluates a complex language like Scheme Dialogue: 0,0:25:17.80,0:25:23.12,EN,,0,0,0,,which does allow procedural arguments, procedural values, and procedural data. Dialogue: 0,0:25:24.07,0:25:25.95,EN,,0,0,0,,But even if I were evaluating ALGOL, Dialogue: 0,0:25:27.34,0:25:28.96,EN,,0,0,0,,which doesn't allow procedural values, Dialogue: 0,0:25:29.47,0:25:30.59,EN,,0,0,0,,I could use this evaluator. Dialogue: 0,0:25:31.58,0:25:33.92,EN,,0,0,0,,And this evaluator is not making any assumptions about that. Dialogue: 0,0:25:34.27,0:25:36.03,EN,,0,0,0,,And, in fact, if this evaluator were to be restricted Dialogue: 0,0:25:36.27,0:25:37.50,EN,,0,0,0,,to not being able to that, it wouldn't matter Dialogue: 0,0:25:37.52,0:25:40.03,EN,,0,0,0,,because it doesn't use any of those clever things. Dialogue: 0,0:25:40.64,0:25:42.41,EN,,0,0,0,,So that's why I'm arranging this to be super simple. Dialogue: 0,0:25:44.07,0:25:46.46,EN,,0,0,0,,This is sort of the kernel of all possible language evaluators. Dialogue: 0,0:25:47.81,0:25:48.48,EN,,0,0,0,,How about that? Dialogue: 0,0:25:49.42,0:25:53.56,EN,,0,0,0,,Evlist-- well, what is it? Dialogue: 0,0:25:53.82,0:25:57.04,EN,,0,0,0,,It's the procedure of two arguments, l and an environment, Dialogue: 0,0:25:58.09,0:25:59.08,EN,,0,0,0,,where l is a list Dialogue: 0,0:25:59.58,0:26:08.27,EN,,0,0,0,,such that if the list of arguments is the empty list, Dialogue: 0,0:26:10.19,0:26:12.68,EN,,0,0,0,,then the result is the empty list. Dialogue: 0,0:26:14.03,0:26:19.23,EN,,0,0,0,,Otherwise, I want to cons up Dialogue: 0,0:26:20.75,0:26:26.67,EN,,0,0,0,,result of evaluating the CAR of the Dialogue: 0,0:26:28.16,0:26:32.51,EN,,0,0,0,,the CAR of the list of operands in the environment. Dialogue: 0,0:26:33.34,0:26:35.71,EN,,0,0,0,,So I want the first operand evaluated, Dialogue: 0,0:26:35.98,0:26:38.40,EN,,0,0,0,,and I'm going to make a list of the results Dialogue: 0,0:26:38.97,0:26:40.76,EN,,0,0,0,,by CONSing that onto the result Dialogue: 0,0:26:41.08,0:26:45.42,EN,,0,0,0,,of this EVLISTing as a CDR recursion, Dialogue: 0,0:26:46.22,0:26:50.13,EN,,0,0,0,,the CDR of the list relative to the same environment. Dialogue: 0,0:26:53.08,0:26:58.24,EN,,0,0,0,,Evlist, cons, else, COND, lambda, define-- Dialogue: 0,0:26:59.66,0:27:01.84,EN,,0,0,0,,OK? And I have one more Dialogue: 0,0:27:01.84,0:27:03.36,EN,,0,0,0,,that I want to put on the blackboard. Dialogue: 0,0:27:03.62,0:27:05.21,EN,,0,0,0,,It's the essence of this whole thing. Dialogue: 0,0:27:05.64,0:27:08.13,EN,,0,0,0,,And there's some sort of next layer down. Dialogue: 0,0:27:14.54,0:27:15.44,EN,,0,0,0,,Conditionals-- Dialogue: 0,0:27:15.69,0:27:16.99,EN,,0,0,0,,conditionals are the only thing left Dialogue: 0,0:27:17.02,0:27:18.17,EN,,0,0,0,,that are sort of substantial. Dialogue: 0,0:27:18.88,0:27:20.75,EN,,0,0,0,,Then below that, we have to worry about Dialogue: 0,0:27:21.07,0:27:22.94,EN,,0,0,0,,things like lookup and bind, Dialogue: 0,0:27:23.56,0:27:25.36,EN,,0,0,0,,and we'll look at that in a second. Dialogue: 0,0:27:25.53,0:27:27.93,EN,,0,0,0,,But of the substantial stuff at this level of detail, Dialogue: 0,0:27:28.65,0:27:30.62,EN,,0,0,0,,next important thing is how you deal with conditionals. Dialogue: 0,0:27:31.60,0:27:33.33,EN,,0,0,0,,Well, how do we have a conditional thing? Dialogue: 0,0:27:36.97,0:27:38.56,EN,,0,0,0,,It's a procedure Dialogue: 0,0:27:39.48,0:27:45.00,EN,,0,0,0,,of clauses and an environment. Dialogue: 0,0:27:47.71,0:27:48.51,EN,,0,0,0,,And what does it do? Dialogue: 0,0:27:49.82,0:27:55.47,EN,,0,0,0,,It says, if I've no more clauses, Dialogue: 0,0:28:02.60,0:28:03.96,EN,,0,0,0,,well, I have to give this a value. Dialogue: 0,0:28:04.70,0:28:05.87,EN,,0,0,0,,It could be that it was an error. Dialogue: 0,0:28:06.54,0:28:08.59,EN,,0,0,0,,Supposing it run off the end of a conditional, Dialogue: 0,0:28:09.15,0:28:10.06,EN,,0,0,0,,it's pretty arbitrary. Dialogue: 0,0:28:10.06,0:28:12.88,EN,,0,0,0,,It's up to me as programmer to choose what I want to happen. Dialogue: 0,0:28:13.65,0:28:15.45,EN,,0,0,0,,It's convenient for me, right now, to write down Dialogue: 0,0:28:15.63,0:28:17.53,EN,,0,0,0,,this has a value which is the empty list, Dialogue: 0,0:28:18.14,0:28:18.83,EN,,0,0,0,,doesn't matter. Dialogue: 0,0:28:20.10,0:28:20.88,EN,,0,0,0,,For error checking, Dialogue: 0,0:28:20.89,0:28:22.76,EN,,0,0,0,,some people might prefer something else. Dialogue: 0,0:28:23.11,0:28:24.81,EN,,0,0,0,,But the interesting things are the following ones. Dialogue: 0,0:28:25.39,0:28:27.24,EN,,0,0,0,,If I've got an else clause-- Dialogue: 0,0:28:31.00,0:28:32.73,EN,,0,0,0,,You see, if I have a list of clauses, Dialogue: 0,0:28:33.21,0:28:34.41,EN,,0,0,0,,then each clause is a list. Dialogue: 0,0:28:35.44,0:28:40.52,EN,,0,0,0,,And so the predicate part is the CAAR of the clauses. Dialogue: 0,0:28:43.56,0:28:45.02,EN,,0,0,0,,It's the CAR, Dialogue: 0,0:28:45.04,0:28:49.00,EN,,0,0,0,,which is the first part of the first clause in the list of clauses. Dialogue: 0,0:28:51.09,0:28:51.84,EN,,0,0,0,,If it's an else, Dialogue: 0,0:28:54.32,0:28:56.51,EN,,0,0,0,,then it means I want my result of the conditional Dialogue: 0,0:28:56.64,0:28:59.15,EN,,0,0,0,,to be the result of evaluating the matching expression. Dialogue: 0,0:29:00.12,0:29:04.32,EN,,0,0,0,,So I eval the CADAR. Dialogue: 0,0:29:07.00,0:29:09.56,EN,,0,0,0,,So this is the first clause, Dialogue: 0,0:29:10.12,0:29:11.63,EN,,0,0,0,,the second element of it, CADAR-- Dialogue: 0,0:29:12.81,0:29:17.08,EN,,0,0,0,,CADR of a CAR-- of the clauses, Dialogue: 0,0:29:21.23,0:29:22.57,EN,,0,0,0,,with respect to the environment. Dialogue: 0,0:29:26.62,0:29:28.60,EN,,0,0,0,,Now the next possibility is more interesting. Dialogue: 0,0:29:29.63,0:29:30.44,EN,,0,0,0,,If it's false, Dialogue: 0,0:29:33.05,0:29:35.10,EN,,0,0,0,,if the first predicate in the predicate list Dialogue: 0,0:29:35.74,0:29:37.68,EN,,0,0,0,,is not an else, and it's not false, Dialogue: 0,0:29:38.32,0:29:39.50,EN,,0,0,0,,if it's not the word else, Dialogue: 0,0:29:40.16,0:29:42.00,EN,,0,0,0,,and if it's not a false thing-- Dialogue: 0,0:29:42.03,0:29:43.66,EN,,0,0,0,,Let's write down what it is if it's a false thing. Dialogue: 0,0:29:44.36,0:29:50.08,EN,,0,0,0,,If the result of evaluating the first clause -- first predicate, Dialogue: 0,0:29:52.33,0:29:56.76,EN,,0,0,0,,the clauses-- respect the environment, Dialogue: 0,0:29:58.19,0:30:01.00,EN,,0,0,0,,if that evaluation yields false, Dialogue: 0,0:30:01.69,0:30:03.82,EN,,0,0,0,,then it means, I want to look at the next clause. Dialogue: 0,0:30:04.36,0:30:05.74,EN,,0,0,0,,So I want to discard the first one. Dialogue: 0,0:30:06.25,0:30:08.33,EN,,0,0,0,,So we just go around loop, evcond, Dialogue: 0,0:30:09.95,0:30:16.49,EN,,0,0,0,,the CDR of the clauses relative to that environment. Dialogue: 0,0:30:19.95,0:30:25.15,EN,,0,0,0,,And otherwise, I had a true clause, Dialogue: 0,0:30:26.84,0:30:28.96,EN,,0,0,0,,what I want is to evaluate Dialogue: 0,0:30:31.85,0:30:41.45,EN,,0,0,0,,the CADAR of the clauses relative to that environment. Dialogue: 0,0:30:48.20,0:30:49.61,EN,,0,0,0,,Boy, it's almost done. Dialogue: 0,0:30:51.21,0:30:52.80,EN,,0,0,0,,It's quite close to done. Dialogue: 0,0:30:53.73,0:30:55.87,EN,,0,0,0,,I think we're going to finish this part off. Dialogue: 0,0:30:56.21,0:30:58.57,EN,,0,0,0,,So just buzzing through this evaluator, Dialogue: 0,0:30:58.81,0:31:00.70,EN,,0,0,0,,but so far you're seeing almost everything. Dialogue: 0,0:31:01.08,0:31:04.04,EN,,0,0,0,,Let's look at the next transparency here. Dialogue: 0,0:31:06.32,0:31:10.43,EN,,0,0,0,,And see IS, Here is bind. Dialogue: 0,0:31:11.98,0:31:14.54,EN,,0,0,0,,Bind is for making more table. Dialogue: 0,0:31:15.46,0:31:18.67,EN,,0,0,0,,And what we are going to do here is make a-- Dialogue: 0,0:31:19.24,0:31:22.80,EN,,0,0,0,,we're going to make a new frame for an environment structure. Dialogue: 0,0:31:22.80,0:31:25.42,EN,,0,0,0,,The environment structure is going to be represented Dialogue: 0,0:31:25.93,0:31:27.20,EN,,0,0,0,,as a list of frames. Dialogue: 0,0:31:28.08,0:31:30.19,EN,,0,0,0,,So given an existing environment structure, Dialogue: 0,0:31:30.32,0:31:32.11,EN,,0,0,0,,I'm going to make a new environment structure Dialogue: 0,0:31:32.25,0:31:33.82,EN,,0,0,0,,by consing a new frame Dialogue: 0,0:31:33.93,0:31:35.69,EN,,0,0,0,,onto the existing environment structure, Dialogue: 0,0:31:36.62,0:31:40.36,EN,,0,0,0,,where the new frame consists of the result of pairing up the variables, Dialogue: 0,0:31:41.05,0:31:43.79,EN,,0,0,0,,which are the bound variables of the procedure I'm applying, Dialogue: 0,0:31:44.12,0:31:48.25,EN,,0,0,0,,to the values which are the arguments that were passed that procedure. Dialogue: 0,0:31:49.69,0:31:50.65,EN,,0,0,0,,This is just making a list, Dialogue: 0,0:31:51.64,0:31:54.06,EN,,0,0,0,,adding a new element to our list of frames, Dialogue: 0,0:31:54.30,0:31:55.60,EN,,0,0,0,,which is an environment structure, Dialogue: 0,0:31:55.74,0:31:56.89,EN,,0,0,0,,to make a new environment. Dialogue: 0,0:31:58.65,0:32:00.65,EN,,0,0,0,,Where pair-up is very simple. Dialogue: 0,0:32:01.54,0:32:02.84,EN,,0,0,0,,Pair-up is nothing more Dialogue: 0,0:32:03.13,0:32:05.56,EN,,0,0,0,,than if I have a list of variables and a list of values, Dialogue: 0,0:32:05.93,0:32:08.62,EN,,0,0,0,,well, if I run out of variables and if I run out of values, Dialogue: 0,0:32:08.62,0:32:09.58,EN,,0,0,0,,everything's OK. Dialogue: 0,0:32:09.72,0:32:11.48,EN,,0,0,0,,Otherwise, I've given too many arguments. Dialogue: 0,0:32:12.51,0:32:15.98,EN,,0,0,0,,If I've not run out of variables, but I've run out of values, Dialogue: 0,0:32:16.06,0:32:17.37,EN,,0,0,0,,that I have too few arguments. Dialogue: 0,0:32:18.51,0:32:19.63,EN,,0,0,0,,And in the general case, Dialogue: 0,0:32:19.63,0:32:21.48,EN,,0,0,0,,where I don't have any errors, and I'm not done, Dialogue: 0,0:32:22.06,0:32:25.61,EN,,0,0,0,,OK? Then I really am just adding a new pair Dialogue: 0,0:32:25.76,0:32:30.17,EN,,0,0,0,,of the first variable with the first argument, Dialogue: 0,0:32:30.94,0:32:32.12,EN,,0,0,0,,the first value, Dialogue: 0,0:32:32.76,0:32:36.40,EN,,0,0,0,,onto a list resulting from pairing-up Dialogue: 0,0:32:37.12,0:32:40.64,EN,,0,0,0,,the rest of the variables with the rest of the values. Dialogue: 0,0:32:42.95,0:32:44.78,EN,,0,0,0,,Lookup is of course equally simple. Dialogue: 0,0:32:46.28,0:32:49.63,EN,,0,0,0,,If I have to look up a symbol in an environment, Dialogue: 0,0:32:49.93,0:32:51.39,EN,,0,0,0,,well, if the environment is empty, Dialogue: 0,0:32:51.56,0:32:53.00,EN,,0,0,0,,then I've got an unbound variable. Dialogue: 0,0:32:54.65,0:32:55.47,EN,,0,0,0,,Otherwise, Dialogue: 0,0:32:56.86,0:33:00.36,EN,,0,0,0,,what I'm going to do is use a special pair list lookup procedure, Dialogue: 0,0:33:00.38,0:33:01.87,EN,,0,0,0,,which we'll have very shortly, Dialogue: 0,0:33:02.24,0:33:05.44,EN,,0,0,0,,of the symbol in the first frame of the environment. Dialogue: 0,0:33:05.93,0:33:07.21,EN,,0,0,0,,Since I know the environment is not empty, Dialogue: 0,0:33:07.23,0:33:08.40,EN,,0,0,0,,it must have a first frame. Dialogue: 0,0:33:09.20,0:33:11.14,EN,,0,0,0,,So I lookup the symbol in the first frame. Dialogue: 0,0:33:11.56,0:33:13.58,EN,,0,0,0,,That becomes the value cell here. Dialogue: 0,0:33:14.38,0:33:17.61,EN,,0,0,0,,OK? And then, if the value cell is empty, Dialogue: 0,0:33:18.44,0:33:20.57,EN,,0,0,0,,if there is no such value cell, Dialogue: 0,0:33:20.70,0:33:22.84,EN,,0,0,0,,then I have to continue and look at the rest of the frames. Dialogue: 0,0:33:23.72,0:33:25.04,EN,,0,0,0,,It means there was nothing found there. Dialogue: 0,0:33:25.99,0:33:28.89,EN,,0,0,0,,So that's a property of ASSQ is it returns emptiness Dialogue: 0,0:33:29.52,0:33:30.80,EN,,0,0,0,,if it doesn't find something. Dialogue: 0,0:33:32.32,0:33:33.85,EN,,0,0,0,,but if it did find something, Dialogue: 0,0:33:33.85,0:33:36.06,EN,,0,0,0,,then I'm going to use the CDR of the value cell here, Dialogue: 0,0:33:36.46,0:33:40.25,EN,,0,0,0,,which is the thing that was the pair consisting of the variable and the value. Dialogue: 0,0:33:41.05,0:33:43.93,EN,,0,0,0,,So the CDR of it is the value part. OK? Dialogue: 0,0:33:45.00,0:33:47.82,EN,,0,0,0,,Finally, ASSQ is something you've probably seen already. Dialogue: 0,0:33:47.97,0:33:50.83,EN,,0,0,0,,ASSQ takes a symbol and a list of pairs, Dialogue: 0,0:33:51.42,0:33:53.40,EN,,0,0,0,,and if the list is empty, it's empty. Dialogue: 0,0:33:53.52,0:33:56.30,EN,,0,0,0,,If the symbol is the first thing in the list-- Dialogue: 0,0:33:58.06,0:33:58.91,EN,,0,0,0,,That's an error. Dialogue: 0,0:33:59.82,0:34:02.17,EN,,0,0,0,,That should be CAAR, C-A-A-R. Dialogue: 0,0:34:03.16,0:34:04.16,EN,,0,0,0,,Everybody note that. Dialogue: 0,0:34:07.63,0:34:09.37,EN,,0,0,0,,Right there, OK? Dialogue: 0,0:34:13.42,0:34:14.41,EN,,0,0,0,,And in any case, Dialogue: 0,0:34:14.56,0:34:16.81,EN,,0,0,0,,f the symbol is the CAAR of the A list, Dialogue: 0,0:34:17.16,0:34:20.97,EN,,0,0,0,,then I want the first, the first pair, in the alist. Dialogue: 0,0:34:22.08,0:34:25.50,EN,,0,0,0,,So, in other words, if this is the key matching the right entry, Dialogue: 0,0:34:26.24,0:34:26.97,EN,,0,0,0,,otherwise, Dialogue: 0,0:34:27.08,0:34:28.94,EN,,0,0,0,,I want to look up that symbol in the rest. Dialogue: 0,0:34:30.08,0:34:33.31,EN,,0,0,0,,Sorry for producing a bug, bugs appear. Dialogue: 0,0:34:35.19,0:34:36.28,EN,,0,0,0,,Well, in any case, Dialogue: 0,0:34:37.05,0:34:39.48,EN,,0,0,0,,you're pretty much seeing the whole thing now. Dialogue: 0,0:34:41.88,0:34:43.29,EN,,0,0,0,,It's a very beautiful thing, Dialogue: 0,0:34:44.19,0:34:46.00,EN,,0,0,0,,even though it's written in an ugly style, Dialogue: 0,0:34:46.76,0:34:48.30,EN,,0,0,0,,being the kernel of every language. Dialogue: 0,0:34:49.60,0:34:51.37,EN,,0,0,0,,I suggest that we just-- let's look at it for a while. Dialogue: 0,0:35:00.32,0:35:47.02,EN,,0,0,0,,[ALSO SPRACH ZARATHUSTRA] Dialogue: 0,0:35:49.75,0:35:50.91,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:36:01.18,0:36:03.29,EN,,0,0,0,,Alright, I suppose it's time to take a small break then. Dialogue: 0,0:36:04.04,0:36:10.73,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:36:56.78,0:36:58.99,EN,,0,0,0,,OK, now we're just going to do a little bit of practice Dialogue: 0,0:36:59.29,0:37:02.67,EN,,0,0,0,,understanding what it is we've just shown you. OK? Dialogue: 0,0:37:03.47,0:37:05.48,EN,,0,0,0,,What we're going to do is go through, in detail, Dialogue: 0,0:37:05.50,0:37:10.36,EN,,0,0,0,,an evaluation by informally substituting through the interpreter. Dialogue: 0,0:37:11.50,0:37:14.94,EN,,0,0,0,,And since we have no assignments or definitions in this interpreter, Dialogue: 0,0:37:15.20,0:37:17.34,EN,,0,0,0,,we have no possible side effects, Dialogue: 0,0:37:17.98,0:37:22.03,EN,,0,0,0,,and so the we can do substitution with impunity Dialogue: 0,0:37:22.52,0:37:24.59,EN,,0,0,0,,and not worry about results. Dialogue: 0,0:37:25.33,0:37:27.80,EN,,0,0,0,,So the particular problem I'd like to look at Dialogue: 0,0:37:28.06,0:37:29.63,EN,,0,0,0,,is it an interesting one. Dialogue: 0,0:37:30.69,0:37:34.09,EN,,0,0,0,,It's the evaluation of Dialogue: 0,0:37:34.91,0:37:48.08,EN,,0,0,0,,quote, open, open, open, lambda of x, lambda of y plus x y, Dialogue: 0,0:37:50.30,0:37:52.62,EN,,0,0,0,,lambda, lambda, Dialogue: 0,0:37:53.04,0:37:56.12,EN,,0,0,0,,applied to three, applied to four, Dialogue: 0,0:37:56.94,0:37:59.58,EN,,0,0,0,,in some global environment which I'll call e0. Dialogue: 0,0:38:04.93,0:38:05.96,EN,,0,0,0,,So what we have here Dialogue: 0,0:38:06.36,0:38:08.04,EN,,0,0,0,,is a procedure of one argument x, Dialogue: 0,0:38:08.09,0:38:11.05,EN,,0,0,0,,which produces as its value a procedure of one argument y, Dialogue: 0,0:38:11.07,0:38:12.12,EN,,0,0,0,,which adds x to y. Dialogue: 0,0:38:14.30,0:38:17.96,EN,,0,0,0,,We are applying the procedure of one argument x to three. Dialogue: 0,0:38:17.96,0:38:19.39,EN,,0,0,0,,So x should become three. Dialogue: 0,0:38:21.40,0:38:23.98,EN,,0,0,0,,And the result of that should be procedure of one argument y, Dialogue: 0,0:38:24.33,0:38:25.82,EN,,0,0,0,,which will then apply to 4. Dialogue: 0,0:38:28.91,0:38:30.32,EN,,0,0,0,,And there is a very simple case, Dialogue: 0,0:38:31.04,0:38:32.73,EN,,0,0,0,,they will then add those results. Dialogue: 0,0:38:34.79,0:38:35.82,EN,,0,0,0,,And now in order to do that, Dialogue: 0,0:38:35.84,0:38:37.76,EN,,0,0,0,,I want to make a very simple environment model. Dialogue: 0,0:38:37.90,0:38:40.48,EN,,0,0,0,,And at this point, you should already have in your mind Dialogue: 0,0:38:40.99,0:38:42.59,EN,,0,0,0,,the environments that this produces. Dialogue: 0,0:38:44.46,0:38:46.62,EN,,0,0,0,,But we're going to start out with a global environment, Dialogue: 0,0:38:48.59,0:38:50.06,EN,,0,0,0,,which I'll call e0, Dialogue: 0,0:38:54.60,0:38:55.47,EN,,0,0,0,,which is that. Dialogue: 0,0:38:56.74,0:39:02.46,EN,,0,0,0,,And it's going to have in it things, definitions for plus, and times, Dialogue: 0,0:39:06.30,0:39:10.36,EN,,0,0,0,,and-- using Greek letters, isn't that interesting, for the objects-- Dialogue: 0,0:39:11.21,0:39:27.93,EN,,0,0,0,,and minus, and quotient, and CAR, and CDR, and CONS, and EQ, Dialogue: 0,0:39:28.59,0:39:31.05,EN,,0,0,0,,and everything else you might imagine in a global environment. Dialogue: 0,0:39:31.27,0:39:33.82,EN,,0,0,0,,It's got something there for each of those things, Dialogue: 0,0:39:34.62,0:39:36.09,EN,,0,0,0,,something the machine is born with, Dialogue: 0,0:39:37.10,0:39:38.09,EN,,0,0,0,,that's e0. Dialogue: 0,0:39:39.22,0:39:41.84,EN,,0,0,0,,Now what does it mean to do this evaluation? Dialogue: 0,0:39:42.94,0:39:45.18,EN,,0,0,0,,Well, we go through the set of special forms. Dialogue: 0,0:39:45.69,0:39:47.05,EN,,0,0,0,,First of all, this is not a number. Dialogue: 0,0:39:48.67,0:39:50.38,EN,,0,0,0,,This is not a symbol. Dialogue: 0,0:39:53.13,0:39:55.60,EN,,0,0,0,,Gee, it's not a quoted expression. Dialogue: 0,0:39:56.60,0:39:58.38,EN,,0,0,0,,This is a quoted expression, Dialogue: 0,0:39:59.47,0:40:00.80,EN,,0,0,0,,but that's not what I mentioned. Dialogue: 0,0:40:00.83,0:40:01.36,EN,,0,0,0,,The question is, Dialogue: 0,0:40:01.39,0:40:04.96,EN,,0,0,0,,whether or not the thing which is quoted is quoted expression? Dialogue: 0,0:40:05.89,0:40:07.96,EN,,0,0,0,,I'm evaluating an expression. Dialogue: 0,0:40:07.96,0:40:09.98,EN,,0,0,0,,This just says it's this particular expression. Dialogue: 0,0:40:11.41,0:40:12.66,EN,,0,0,0,,This is not a quoted expression. Dialogue: 0,0:40:13.71,0:40:17.21,EN,,0,0,0,,OK? It's not a thing that begins with lambda. Dialogue: 0,0:40:19.12,0:40:20.67,EN,,0,0,0,,It's not a thing that begins with COND. Dialogue: 0,0:40:22.03,0:40:25.95,EN,,0,0,0,,Therefore, it's an application of its of an operated operands. Dialogue: 0,0:40:26.31,0:40:27.12,EN,,0,0,0,,It's a combination. Dialogue: 0,0:40:28.57,0:40:30.70,EN,,0,0,0,,The combination thus has Dialogue: 0,0:40:30.89,0:40:34.00,EN,,0,0,0,,this as the operator Dialogue: 0,0:40:34.64,0:40:36.08,EN,,0,0,0,,and this is the operands. Dialogue: 0,0:40:40.13,0:40:42.41,EN,,0,0,0,,Well, that means that what I'm going to do is Dialogue: 0,0:40:42.57,0:40:47.90,EN,,0,0,0,,transform this into apply of eval, Dialogue: 0,0:40:50.12,0:40:57.61,EN,,0,0,0,,of quote, open, open lambda of x, lambda of y-- Dialogue: 0,0:40:57.88,0:40:59.12,EN,,0,0,0,,I'm evaluating the operator-- Dialogue: 0,0:40:59.95,0:41:04.19,EN,,0,0,0,,plus x y, in the environment, Dialogue: 0,0:41:07.26,0:41:08.64,EN,,0,0,0,,also e0, Dialogue: 0,0:41:12.78,0:41:15.20,EN,,0,0,0,,with the operands that I'm going to apply this to, Dialogue: 0,0:41:15.26,0:41:17.28,EN,,0,0,0,,the arguments being the result of EVLIST, Dialogue: 0,0:41:21.21,0:41:24.49,EN,,0,0,0,,the list containing four, fin e0. Dialogue: 0,0:41:29.01,0:41:31.26,EN,,0,0,0,,I'm using this funny notation here for e0 Dialogue: 0,0:41:32.32,0:41:34.83,EN,,0,0,0,,because this should be that environment. Dialogue: 0,0:41:35.45,0:41:37.77,EN,,0,0,0,,I haven't a name for it, Dialogue: 0,0:41:37.80,0:41:39.15,EN,,0,0,0,,because I have no environment to name it in. Dialogue: 0,0:41:41.96,0:41:44.09,EN,,0,0,0,,So this is just a representation Dialogue: 0,0:41:44.17,0:41:46.17,EN,,0,0,0,,what would be a quoted expression, if you will. Dialogue: 0,0:41:47.73,0:41:51.16,EN,,0,0,0,,The data structure, which is the environment, goes there. Dialogue: 0,0:41:53.04,0:41:55.04,EN,,0,0,0,,Well, that's what we're seeing here. Dialogue: 0,0:41:55.85,0:41:56.67,EN,,0,0,0,,Well in order to do this, Dialogue: 0,0:41:56.68,0:41:58.04,EN,,0,0,0,,I have to do this, and I have to do that. Dialogue: 0,0:41:59.61,0:42:00.49,EN,,0,0,0,,Well this one's easy, Dialogue: 0,0:42:00.57,0:42:03.18,EN,,0,0,0,,so why don't we do that one first. OK? Dialogue: 0,0:42:03.77,0:42:07.44,EN,,0,0,0,,This turns into apply of eval-- Dialogue: 0,0:42:07.45,0:42:08.83,EN,,0,0,0,,just copying something now. Dialogue: 0,0:42:09.42,0:42:11.00,EN,,0,0,0,,Most of the substitution rule is copying. Dialogue: 0,0:42:18.53,0:42:21.24,EN,,0,0,0,,So I'm going to not say the words when I copy, Dialogue: 0,0:42:21.71,0:42:23.87,EN,,0,0,0,,because it's faster. Dialogue: 0,0:42:26.41,0:42:28.64,EN,,0,0,0,,And then the EVLIST is going to turn into a Dialogue: 0,0:42:28.65,0:42:36.72,EN,,0,0,0,,cons, of eval, of four, in e0-- Dialogue: 0,0:42:38.78,0:42:40.17,EN,,0,0,0,,because it was not an empty list-- Dialogue: 0,0:42:41.44,0:42:49.39,EN,,0,0,0,,onto the result of EVLISTing, on the empty list, in e0. Dialogue: 0,0:42:52.58,0:42:54.20,EN,,0,0,0,,And I'm going to start leaving out steps soon, Dialogue: 0,0:42:54.24,0:42:55.36,EN,,0,0,0,,because it's going to get boring. Dialogue: 0,0:42:59.87,0:43:05.42,EN,,0,0,0,,But this is basically the same thing as apply, of eval-- Dialogue: 0,0:43:07.50,0:43:08.54,EN,,0,0,0,,I'm going to keep doing this-- Dialogue: 0,0:43:10.68,0:43:20.24,EN,,0,0,0,,the lambda of x, the lambda of y, plus xy, 3, close, e0. Dialogue: 0,0:43:20.24,0:43:21.20,EN,,0,0,0,,I'm a pretty good machine. Dialogue: 0,0:43:24.24,0:43:26.24,EN,,0,0,0,,Well, eval of four, Dialogue: 0,0:43:26.56,0:43:28.44,EN,,0,0,0,,that's meets the question, is it a number. Dialogue: 0,0:43:29.00,0:43:33.90,EN,,0,0,0,,So that's cons, right, cons of 4. Dialogue: 0,0:43:34.03,0:43:37.47,EN,,0,0,0,,And EVLIST of the empty list is the empty list, Dialogue: 0,0:43:38.33,0:43:39.24,EN,,0,0,0,,so that's this. Dialogue: 0,0:43:42.62,0:43:45.08,EN,,0,0,0,,OK. And that's very simple to understand, Dialogue: 0,0:43:45.10,0:43:47.44,EN,,0,0,0,,because that means the list containing four itself. Dialogue: 0,0:43:48.71,0:43:53.84,EN,,0,0,0,,So this is nothing more than apply of eval, Dialogue: 0,0:43:55.28,0:44:02.51,EN,,0,0,0,,quote, open, open, lambda of x, lambda of y, plus x y, Dialogue: 0,0:44:03.40,0:44:07.48,EN,,0,0,0,,three applied to, e0, applied to the list four-- Dialogue: 0,0:44:08.68,0:44:12.60,EN,,0,0,0,,applied to the list four-- bang Dialogue: 0,0:44:13.94,0:44:15.05,EN,,0,0,0,,So that's that step. Dialogue: 0,0:44:17.00,0:44:19.96,EN,,0,0,0,,Now let's look at the next, more interesting thing. Dialogue: 0,0:44:20.36,0:44:21.72,EN,,0,0,0,,What do I do to evaluate that? Dialogue: 0,0:44:23.07,0:44:24.44,EN,,0,0,0,,Evaluating this means Dialogue: 0,0:44:25.20,0:44:28.65,EN,,0,0,0,,means I have to evaluate-- Well, it's not. Dialogue: 0,0:44:29.46,0:44:31.04,EN,,0,0,0,,It's nothing but an application. Dialogue: 0,0:44:31.68,0:44:33.10,EN,,0,0,0,,It's not one of the special things. Dialogue: 0,0:44:33.57,0:44:36.51,EN,,0,0,0,,If the application of this operator, Dialogue: 0,0:44:36.51,0:44:37.37,EN,,0,0,0,,which we see here-- Dialogue: 0,0:44:37.66,0:44:38.94,EN,,0,0,0,,here's the operator-- Dialogue: 0,0:44:40.19,0:44:41.77,EN,,0,0,0,,applied to this operands, Dialogue: 0,0:44:44.54,0:44:45.74,EN,,0,0,0,,that combination. Dialogue: 0,0:44:46.72,0:44:48.25,EN,,0,0,0,,But we know how to do that, Dialogue: 0,0:44:48.84,0:44:52.37,EN,,0,0,0,,because that's the last case of the conditional. Dialogue: 0,0:44:52.37,0:44:55.52,EN,,0,0,0,,So substituting in for this evaluation, Dialogue: 0,0:44:55.71,0:44:57.47,EN,,0,0,0,,it's apply of eval of the operator Dialogue: 0,0:44:57.50,0:44:59.00,EN,,0,0,0,,in the EVLIST of the operands. Dialogue: 0,0:45:01.16,0:45:08.20,EN,,0,0,0,,Well, it's apply, of apply, of eval, Dialogue: 0,0:45:10.57,0:45:21.07,EN,,0,0,0,,of quote, open, lambda of x, lambda of y, plus x y, Dialogue: 0,0:45:21.80,0:45:23.45,EN,,0,0,0,,lambda, lambda, Dialogue: 0,0:45:23.74,0:45:25.42,EN,,0,0,0,,in environment e0. Dialogue: 0,0:45:30.52,0:45:32.67,EN,,0,0,0,,I'm going to short circuit the evaluation of the operands, Dialogue: 0,0:45:32.68,0:45:34.14,EN,,0,0,0,,because they're the same as they were before. Dialogue: 0,0:45:35.23,0:45:36.48,EN,,0,0,0,,I got a list containing three, Dialogue: 0,0:45:36.51,0:45:39.16,EN,,0,0,0,,apply that, and apply that to four. Dialogue: 0,0:45:42.44,0:45:43.56,EN,,0,0,0,,Well let's see. Dialogue: 0,0:45:44.41,0:45:46.38,EN,,0,0,0,,Eval of a lambda expression Dialogue: 0,0:45:48.01,0:45:49.45,EN,,0,0,0,,produces a procedure object. Dialogue: 0,0:45:52.03,0:45:57.88,EN,,0,0,0,,So this is apply, of apply, Dialogue: 0,0:46:00.30,0:46:02.27,EN,,0,0,0,,of the procedure object closure, Dialogue: 0,0:46:04.52,0:46:08.68,EN,,0,0,0,,which contains the body of the procedure, x, Dialogue: 0,0:46:08.94,0:46:11.92,EN,,0,0,0,,which is lambda, which binds x [UNINTELLIGIBLE] Dialogue: 0,0:46:12.13,0:46:15.40,EN,,0,0,0,,the internals of the body, Dialogue: 0,0:46:15.80,0:46:18.17,EN,,0,0,0,,it returns the procedure of one argument y, Dialogue: 0,0:46:18.56,0:46:20.63,EN,,0,0,0,,which adds x to y. Dialogue: 0,0:46:23.21,0:46:25.50,EN,,0,0,0,,Environment e0 is now captured in it, Dialogue: 0,0:46:27.24,0:46:29.63,EN,,0,0,0,,because this was evaluated with respect to e0. Dialogue: 0,0:46:30.11,0:46:32.43,EN,,0,0,0,,e0 is part now of the closure object. Dialogue: 0,0:46:33.04,0:46:38.19,EN,,0,0,0,,Apply that to open, three, close, apply, Dialogue: 0,0:46:38.81,0:46:41.30,EN,,0,0,0,,to open, 4, close, apply. Dialogue: 0,0:46:47.39,0:46:49.29,EN,,0,0,0,,So going from this step to this step Dialogue: 0,0:46:49.31,0:46:50.89,EN,,0,0,0,,meant that I made up a procedure object Dialogue: 0,0:46:50.91,0:46:52.03,EN,,0,0,0,,which captured in it Dialogue: 0,0:46:53.88,0:46:55.98,EN,,0,0,0,,e0 as part of the procedure object. Dialogue: 0,0:46:57.15,0:46:58.51,EN,,0,0,0,,Now, we're going to pass those to apply. Dialogue: 0,0:46:58.52,0:46:59.71,EN,,0,0,0,,We have to apply this procedure Dialogue: 0,0:47:00.48,0:47:01.58,EN,,0,0,0,,to that set of arguments. Dialogue: 0,0:47:02.71,0:47:06.51,EN,,0,0,0,,Well, but that procedure is not primitive. Dialogue: 0,0:47:07.38,0:47:09.88,EN,,0,0,0,,It's, in fact, a thing which has got the tag closure, Dialogue: 0,0:47:10.24,0:47:12.09,EN,,0,0,0,,and, therefore, what we have to do is do a bind. Dialogue: 0,0:47:13.71,0:47:14.72,EN,,0,0,0,,We have to bind. Dialogue: 0,0:47:15.83,0:47:19.40,EN,,0,0,0,,A new environment is made at this point, Dialogue: 0,0:47:20.44,0:47:22.80,EN,,0,0,0,,which has as its parent environment Dialogue: 0,0:47:22.94,0:47:27.56,EN,,0,0,0,,the one over here, e0, that environment. Dialogue: 0,0:47:30.32,0:47:31.57,EN,,0,0,0,,And we'll call this one, e1. Dialogue: 0,0:47:34.62,0:47:35.74,EN,,0,0,0,,Now what's bound in there? Dialogue: 0,0:47:36.04,0:47:37.48,EN,,0,0,0,,x is bound to three. Dialogue: 0,0:47:38.62,0:47:40.44,EN,,0,0,0,,So I have x equal three. Dialogue: 0,0:47:41.48,0:47:42.33,EN,,0,0,0,,That's what's in there. Dialogue: 0,0:47:44.94,0:47:46.24,EN,,0,0,0,,And we'll call that e1. Dialogue: 0,0:47:46.24,0:47:48.44,EN,,0,0,0,,So what this transforms into Dialogue: 0,0:47:49.13,0:47:50.72,EN,,0,0,0,,is an eval of the body Dialogue: 0,0:47:51.72,0:47:53.07,EN,,0,0,0,,of this, which is this, Dialogue: 0,0:47:54.40,0:47:55.72,EN,,0,0,0,,the body of that procedure, Dialogue: 0,0:47:56.44,0:47:58.52,EN,,0,0,0,,in the environment that you just saw. Dialogue: 0,0:48:00.29,0:48:05.05,EN,,0,0,0,,So that's an apply, of eval, Dialogue: 0,0:48:06.92,0:48:16.43,EN,,0,0,0,,quote, open, lambda of y, plus x y-- the body-- in e1. Dialogue: 0,0:48:20.49,0:48:22.48,EN,,0,0,0,,And apply the result of that to four, Dialogue: 0,0:48:23.68,0:48:26.73,EN,,0,0,0,,open, close, 4-- list of arguments. Dialogue: 0,0:48:28.43,0:48:29.87,EN,,0,0,0,,Well, that's sensible enough Dialogue: 0,0:48:30.08,0:48:32.27,EN,,0,0,0,,because evaluating a lambda, I know what to do. Dialogue: 0,0:48:33.11,0:48:34.17,EN,,0,0,0,,That means I apply, Dialogue: 0,0:48:37.16,0:48:38.92,EN,,0,0,0,,the procedure which is closure, Dialogue: 0,0:48:43.74,0:48:46.84,EN,,0,0,0,,binds one argument y, adds x to y, Dialogue: 0,0:48:49.28,0:48:52.15,EN,,0,0,0,,with e1 captured in it. Dialogue: 0,0:48:55.79,0:48:57.42,EN,,0,0,0,,And you should really see this. Right? Dialogue: 0,0:48:57.80,0:49:00.14,EN,,0,0,0,,I somehow manufactured a closure. Dialogue: 0,0:49:00.14,0:49:01.16,EN,,0,0,0,,I should've put this here. Dialogue: 0,0:49:01.79,0:49:03.04,EN,,0,0,0,,There was one over here too. Dialogue: 0,0:49:05.90,0:49:07.47,EN,,0,0,0,,OK? Well, there's one here now. Dialogue: 0,0:49:08.08,0:49:09.80,EN,,0,0,0,,I've captured e1, Dialogue: 0,0:49:10.41,0:49:14.25,EN,,0,0,0,,and this is the procedure of one argument y, Dialogue: 0,0:49:15.45,0:49:16.70,EN,,0,0,0,,whatever this is. Dialogue: 0,0:49:18.09,0:49:20.72,EN,,0,0,0,,That's what that is there, that closure. Dialogue: 0,0:49:22.57,0:49:26.46,EN,,0,0,0,,OK? I'm going to apply that to four. Dialogue: 0,0:49:30.28,0:49:31.77,EN,,0,0,0,,OK. Well, that's easy enough. Dialogue: 0,0:49:36.83,0:49:38.73,EN,,0,0,0,,That means I have to make a new environment Dialogue: 0,0:49:38.86,0:49:40.52,EN,,0,0,0,,by copying this pointer, Dialogue: 0,0:49:41.56,0:49:43.21,EN,,0,0,0,,which was the pointer of the procedure, Dialogue: 0,0:49:44.94,0:49:48.96,EN,,0,0,0,,which binds y equal 4 with that environment. Dialogue: 0,0:49:49.82,0:49:52.22,EN,,0,0,0,,And here's my new environment, which I'll call e2. Dialogue: 0,0:49:56.03,0:49:58.12,EN,,0,0,0,,And, of course, this application then Dialogue: 0,0:49:58.22,0:50:00.33,EN,,0,0,0,,is evaluate the body in e2. Dialogue: 0,0:50:01.58,0:50:07.87,EN,,0,0,0,,So this is eval, the body, Dialogue: 0,0:50:07.90,0:50:11.85,EN,,0,0,0,,which is plus x y, in the environment e2. Dialogue: 0,0:50:13.71,0:50:14.94,EN,,0,0,0,,But this is an application, Dialogue: 0,0:50:15.48,0:50:23.88,EN,,0,0,0,,so this is the apply, of eval, plus in e2, Dialogue: 0,0:50:26.33,0:50:37.34,EN,,0,0,0,,an EVLIST, quote, open, x y, in e2. Dialogue: 0,0:50:44.88,0:50:45.59,EN,,0,0,0,,Well, but let's see. Dialogue: 0,0:50:45.59,0:50:51.71,EN,,0,0,0,,That is apply, the object Dialogue: 0,0:50:52.08,0:50:53.87,EN,,0,0,0,,which is a result of that and plus. Dialogue: 0,0:50:54.19,0:50:55.66,EN,,0,0,0,,So here we are in e2, Dialogue: 0,0:50:55.69,0:50:57.72,EN,,0,0,0,,plus is not here, it's not here, Dialogue: 0,0:50:57.74,0:51:01.05,EN,,0,0,0,,yes, but's here as some primitive operator. Dialogue: 0,0:51:01.78,0:51:04.74,EN,,0,0,0,,So it's the primitive operator for addition. Dialogue: 0,0:51:07.47,0:51:14.12,EN,,0,0,0,,Apply that to the result of evaluating x and y in e2. Dialogue: 0,0:51:14.37,0:51:17.00,EN,,0,0,0,,But we can see that x is three and y is four. Dialogue: 0,0:51:18.11,0:51:23.31,EN,,0,0,0,,So that's a three and four, here. Dialogue: 0,0:51:24.16,0:51:26.28,EN,,0,0,0,,And that magically produces for me a seven. Dialogue: 0,0:51:30.52,0:51:32.44,EN,,0,0,0,,I wanted to go through this so you would see, Dialogue: 0,0:51:32.70,0:51:34.73,EN,,0,0,0,,essentially, one important ingredient, Dialogue: 0,0:51:35.76,0:51:37.29,EN,,0,0,0,,which is what's being passed around, Dialogue: 0,0:51:37.31,0:51:39.56,EN,,0,0,0,,and who owns what, and what his job is. Dialogue: 0,0:51:40.47,0:51:41.61,EN,,0,0,0,,So what do we have here? Dialogue: 0,0:51:41.70,0:51:42.62,EN,,0,0,0,,We have eval, Dialogue: 0,0:51:44.80,0:51:45.64,EN,,0,0,0,,We have eval, and we have apply, Dialogue: 0,0:51:45.66,0:51:46.62,EN,,0,0,0,,the two main players. Dialogue: 0,0:51:49.37,0:51:51.56,EN,,0,0,0,,And there is a big loop the goes around like this. Dialogue: 0,0:51:52.32,0:52:04.57,EN,,0,0,0,,Which is eval produces a procedure and arguments for apply. Dialogue: 0,0:52:06.27,0:52:08.57,EN,,0,0,0,,Now some things eval could do by itself. Dialogue: 0,0:52:09.50,0:52:10.86,EN,,0,0,0,,Those are little self things here. Dialogue: 0,0:52:10.86,0:52:11.74,EN,,0,0,0,,They're not interesting. Dialogue: 0,0:52:12.70,0:52:15.60,EN,,0,0,0,,Also eval evaluates all of the arguments, one after another. Dialogue: 0,0:52:16.24,0:52:17.28,EN,,0,0,0,,That's not very interesting. Dialogue: 0,0:52:17.65,0:52:20.09,EN,,0,0,0,,Apply can apply some procedures like plus, Dialogue: 0,0:52:21.02,0:52:22.04,EN,,0,0,0,,not very interesting. Dialogue: 0,0:52:22.30,0:52:24.64,EN,,0,0,0,,However, if apply can't apply a procedure like plus, Dialogue: 0,0:52:25.31,0:52:33.31,EN,,0,0,0,,it produces an expression and environment for eval. Dialogue: 0,0:52:35.47,0:52:37.61,EN,,0,0,0,,The procedural arguments wrap up Dialogue: 0,0:52:38.24,0:52:40.60,EN,,0,0,0,,essentially the state of a computation Dialogue: 0,0:52:41.66,0:52:43.42,EN,,0,0,0,,and, certainly, the expression of environment. Dialogue: 0,0:52:43.74,0:52:45.31,EN,,0,0,0,,And so what we're actually going to do next Dialogue: 0,0:52:45.32,0:52:46.46,EN,,0,0,0,,is not the complete state, Dialogue: 0,0:52:46.48,0:52:48.82,EN,,0,0,0,,because it doesn't say who wants the answers. Dialogue: 0,0:52:51.28,0:52:52.20,EN,,0,0,0,,But what we're going to do-- Dialogue: 0,0:52:52.24,0:52:54.80,EN,,0,0,0,,it's always got something like an expression of environment Dialogue: 0,0:52:54.99,0:52:56.14,EN,,0,0,0,,or procedure and arguments Dialogue: 0,0:52:56.28,0:52:58.08,EN,,0,0,0,,as the main loop that we're going around. Dialogue: 0,0:52:58.97,0:53:01.80,EN,,0,0,0,,There are minor little sub loops like eval through EVLIST, Dialogue: 0,0:53:04.49,0:53:06.76,EN,,0,0,0,,or eval through evcond, Dialogue: 0,0:53:09.10,0:53:11.96,EN,,0,0,0,,or apply through a primitive apply. Dialogue: 0,0:53:16.14,0:53:17.64,EN,,0,0,0,,But they're not the essential things. Dialogue: 0,0:53:18.86,0:53:20.28,EN,,0,0,0,,So that's what I wanted you to see. Dialogue: 0,0:53:21.86,0:53:22.88,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:53:25.93,0:53:27.37,EN,,0,0,0,,Yes. David Dialogue: 0,0:53:27.74,0:53:33.31,EN,,0,0,0,,AUDIENCE: I'm trying to understand how x got down to three Dialogue: 0,0:53:34.01,0:53:36.30,EN,,0,0,0,,instead of four. Dialogue: 0,0:53:37.07,0:53:38.52,EN,,0,0,0,,At the early part of the-- Dialogue: 0,0:53:38.56,0:53:40.54,EN,,0,0,0,,PROFESSOR: Here. Dialogue: 0,0:53:41.31,0:53:43.31,EN,,0,0,0,,You want to know how x got down to three? Dialogue: 0,0:53:43.52,0:53:47.42,EN,,0,0,0,,AUDIENCE: Because x is the outer procedure, Dialogue: 0,0:53:48.46,0:53:50.99,EN,,0,0,0,,and x and y are the inner procedure. Dialogue: 0,0:53:51.26,0:53:51.88,EN,,0,0,0,,PROFESSOR: Fine. Dialogue: 0,0:53:52.84,0:53:54.62,EN,,0,0,0,,Well, I was very careful and mechanical. Dialogue: 0,0:53:55.02,0:53:56.92,EN,,0,0,0,,First of all, I should write those procedures Dialogue: 0,0:53:56.94,0:53:58.41,EN,,0,0,0,,again for you, pretty printed. Dialogue: 0,0:54:00.61,0:54:01.47,EN,,0,0,0,,First order of business, Dialogue: 0,0:54:01.48,0:54:02.99,EN,,0,0,0,,because you're probably not reading them well. Dialogue: 0,0:54:03.83,0:54:04.70,EN,,0,0,0,,So I have here Dialogue: 0,0:54:05.15,0:54:09.60,EN,,0,0,0,,that procedure of-- was it x over there-- Dialogue: 0,0:54:11.21,0:54:14.99,EN,,0,0,0,,which is -- value of that procedure of y Dialogue: 0,0:54:15.72,0:54:18.44,EN,,0,0,0,,which adds x to y, Dialogue: 0,0:54:19.82,0:54:21.10,EN,,0,0,0,,lambda, lambda, Dialogue: 0,0:54:21.40,0:54:22.89,EN,,0,0,0,,applied that to three, Dialogue: 0,0:54:24.08,0:54:26.12,EN,,0,0,0,,takes the result of that, and applied that to four. Dialogue: 0,0:54:26.14,0:54:28.81,EN,,0,0,0,,Is that not what I wrote? OK? Dialogue: 0,0:54:28.81,0:54:32.33,EN,,0,0,0,,Now, you should immediately see that Dialogue: 0,0:54:33.77,0:54:34.94,EN,,0,0,0,,here is an application-- Dialogue: 0,0:54:35.16,0:54:36.46,EN,,0,0,0,,let me get a white piece of chalk-- Dialogue: 0,0:54:37.32,0:54:41.12,EN,,0,0,0,,here is an application, a combination. Dialogue: 0,0:54:43.44,0:54:46.40,EN,,0,0,0,,OK? That combination has this as the operator Dialogue: 0,0:54:48.14,0:54:49.55,EN,,0,0,0,,and this as the operand. Dialogue: 0,0:54:51.04,0:54:53.05,EN,,0,0,0,,The three is going in for the x here. Dialogue: 0,0:54:54.90,0:54:56.36,EN,,0,0,0,,The result of this Dialogue: 0,0:54:56.56,0:54:58.46,EN,,0,0,0,,is a procedure of one argument y, Dialogue: 0,0:54:58.73,0:54:59.79,EN,,0,0,0,,which gets applied to four. Dialogue: 0,0:55:00.88,0:55:01.58,EN,,0,0,0,,OK? Dialogue: 0,0:55:02.20,0:55:04.08,EN,,0,0,0,,So you just weren't reading the expression right. Dialogue: 0,0:55:04.40,0:55:07.85,EN,,0,0,0,,The way you see that over here. OK. Dialogue: 0,0:55:09.42,0:55:12.96,EN,,0,0,0,,is that here I have the actual procedure object, x. Dialogue: 0,0:55:13.34,0:55:15.31,EN,,0,0,0,,It's getting applied to three, Dialogue: 0,0:55:15.95,0:55:17.07,EN,,0,0,0,,the list containing three. Dialogue: 0,0:55:18.98,0:55:21.34,EN,,0,0,0,,What I'm left over with is something which gets applied to four. Dialogue: 0,0:55:24.08,0:55:25.20,EN,,0,0,0,,Are there any other questions? Dialogue: 0,0:55:28.35,0:55:30.38,EN,,0,0,0,,Time for our next small break then. Dialogue: 0,0:55:30.83,0:55:31.37,EN,,0,0,0,,Thank you. Dialogue: 0,0:55:33.73,0:55:41.40,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:56:08.41,0:56:11.29,EN,,0,0,0,,PROFESSOR: Let's see, at this point, Dialogue: 0,0:56:13.32,0:56:14.59,EN,,0,0,0,,you should be getting the feeling, Dialogue: 0,0:56:14.75,0:56:17.96,EN,,0,0,0,,what's this nonsense this Sussman character is feeding me? Dialogue: 0,0:56:20.74,0:56:23.92,EN,,0,0,0,,There's an awful lot of strange nonsense here. Dialogue: 0,0:56:24.80,0:56:27.40,EN,,0,0,0,,After all, he purported to explain to me Lisp, Dialogue: 0,0:56:28.01,0:56:29.90,EN,,0,0,0,,and he wrote me a Lisp program on the blackboard. Dialogue: 0,0:56:31.23,0:56:33.53,EN,,0,0,0,,The Lisp program was intended to be interpreted for Lisp, Dialogue: 0,0:56:33.85,0:56:35.02,EN,,0,0,0,,but you need a Lisp interpreter Dialogue: 0,0:56:35.04,0:56:36.30,EN,,0,0,0,,in order to understand that program. Dialogue: 0,0:56:38.37,0:56:40.19,EN,,0,0,0,,How could that program have told me anything Dialogue: 0,0:56:40.22,0:56:43.20,EN,,0,0,0,,there is to be known about Lisp? Dialogue: 0,0:56:44.15,0:56:46.22,EN,,0,0,0,,How is that not completely vacuous? Dialogue: 0,0:56:48.49,0:56:50.25,EN,,0,0,0,,It's a very strange thing. Dialogue: 0,0:56:50.99,0:56:52.43,EN,,0,0,0,,Does it tell me anything at all? Dialogue: 0,0:56:56.07,0:56:57.20,EN,,0,0,0,,Well, you see, the whole thing Dialogue: 0,0:56:57.32,0:56:59.79,EN,,0,0,0,,is sort of like these Escher's hands Dialogue: 0,0:57:00.46,0:57:03.55,EN,,0,0,0,,that we see on this slide. Dialogue: 0,0:57:06.18,0:57:07.72,EN,,0,0,0,,Yes, eval and apply Dialogue: 0,0:57:07.76,0:57:10.16,EN,,0,0,0,,each sort of draw each other Dialogue: 0,0:57:11.50,0:57:14.16,EN,,0,0,0,,and construct the real thing, Dialogue: 0,0:57:14.86,0:57:16.30,EN,,0,0,0,,which can sit out and draw itself. Dialogue: 0,0:57:17.11,0:57:18.46,EN,,0,0,0,,Escher was a very brilliant man, Dialogue: 0,0:57:18.68,0:57:20.41,EN,,0,0,0,,he just didn't know the names of these spirits. Dialogue: 0,0:57:23.91,0:57:25.00,EN,,0,0,0,,Well, I'm going to do now, Dialogue: 0,0:57:26.09,0:57:28.00,EN,,0,0,0,,is I'm going to try to convince you Dialogue: 0,0:57:28.16,0:57:29.87,EN,,0,0,0,,that both this mean something, Dialogue: 0,0:57:30.16,0:57:31.98,EN,,0,0,0,,and, as a aside, Dialogue: 0,0:57:32.99,0:57:34.72,EN,,0,0,0,,I'm going to show you why you don't need definitions. Dialogue: 0,0:57:36.09,0:57:37.71,EN,,0,0,0,,Just turns out that sort of falls out, Dialogue: 0,0:57:38.09,0:57:41.12,EN,,0,0,0,,why definitions are not essential in a mathematical sense Dialogue: 0,0:57:42.51,0:57:44.89,EN,,0,0,0,,for doing all the things we need to do for computing. Dialogue: 0,0:57:49.10,0:57:50.03,EN,,0,0,0,,Well, let's see here. Dialogue: 0,0:57:50.69,0:57:53.31,EN,,0,0,0,,Consider the following small program, Dialogue: 0,0:57:53.74,0:57:54.64,EN,,0,0,0,,what does it mean? Dialogue: 0,0:57:54.87,0:57:57.64,EN,,0,0,0,,This is a program for computing exponentials. Dialogue: 0,0:58:07.27,0:58:13.23,EN,,0,0,0,,The exponential of x to the nth power is if-- Dialogue: 0,0:58:16.83,0:58:18.12,EN,,0,0,0,,n is zero, Dialogue: 0,0:58:19.20,0:58:20.76,EN,,0,0,0,,then the result is one. Dialogue: 0,0:58:22.07,0:58:22.81,EN,,0,0,0,,Otherwise, Dialogue: 0,0:58:25.56,0:58:28.48,EN,,0,0,0,,I want the product of x Dialogue: 0,0:58:28.75,0:58:33.93,EN,,0,0,0,,and the result of exponentiating x to the n minus one power. Dialogue: 0,0:58:43.69,0:58:44.56,EN,,0,0,0,,I think I got it right. Dialogue: 0,0:58:46.63,0:58:48.72,EN,,0,0,0,,Now this is a recursive definition. Dialogue: 0,0:58:49.47,0:58:52.17,EN,,0,0,0,,It's a definition of the exponentiation Dialogue: 0,0:58:52.46,0:58:54.78,EN,,0,0,0,,procedure in terms of itself. Dialogue: 0,0:58:56.41,0:58:58.32,EN,,0,0,0,,And, as it has been mentioned before, Dialogue: 0,0:58:59.28,0:59:01.68,EN,,0,0,0,,your high school geometry teacher Dialogue: 0,0:59:01.84,0:59:04.04,EN,,0,0,0,,probably gave you a hard time about things like that. Dialogue: 0,0:59:05.65,0:59:06.73,EN,,0,0,0,,Was that justified? Dialogue: 0,0:59:07.91,0:59:10.84,EN,,0,0,0,,Why does this self referential definition Dialogue: 0,0:59:10.96,0:59:12.04,EN,,0,0,0,,make any sense? Dialogue: 0,0:59:13.43,0:59:15.10,EN,,0,0,0,,Well, first of all, I'm going to convince you that Dialogue: 0,0:59:15.13,0:59:17.60,EN,,0,0,0,,your high school geometry teacher was not telling you nonsense. Dialogue: 0,0:59:20.37,0:59:23.42,EN,,0,0,0,,Consider the following set of definitions here. Dialogue: 0,0:59:24.27,0:59:27.42,EN,,0,0,0,,x plus y equals three, Dialogue: 0,0:59:28.24,0:59:32.24,EN,,0,0,0,,and x minus y equal one. Dialogue: 0,0:59:33.07,0:59:35.56,EN,,0,0,0,,Well, gee, this tells you x in terms of y, Dialogue: 0,0:59:35.58,0:59:37.84,EN,,0,0,0,,and this one tells you y in terms of x, presumably. Dialogue: 0,0:59:40.15,0:59:42.95,EN,,0,0,0,,And yet this happens to have a unique solution in x and y. Dialogue: 0,0:59:55.91,0:59:58.11,EN,,0,0,0,,However, I could also write Dialogue: 0,0:59:59.87,1:00:04.25,EN,,0,0,0,,two x plus two y is six. Dialogue: 0,1:00:06.83,1:00:09.87,EN,,0,0,0,,These two equations have an infinite number solutions. Dialogue: 0,1:00:15.73,1:00:17.42,EN,,0,0,0,,And I could write you, for example, Dialogue: 0,1:00:18.89,1:00:21.53,EN,,0,0,0,,x minus y equal 2, Dialogue: 0,1:00:22.14,1:00:24.41,EN,,0,0,0,,and these two equations have no solutions. Dialogue: 0,1:00:29.82,1:00:33.04,EN,,0,0,0,,Well, I have here three sets of simultaneous linear equations, Dialogue: 0,1:00:35.45,1:00:39.51,EN,,0,0,0,,this set, this set, and this set. Dialogue: 0,1:00:39.88,1:00:41.79,EN,,0,0,0,,But they have different numbers of solutions. Dialogue: 0,1:00:42.90,1:00:45.76,EN,,0,0,0,,The number of solutions is not in the form of the equations. Dialogue: 0,1:00:46.33,1:00:48.20,EN,,0,0,0,,They all three sets have the same form. Dialogue: 0,1:00:48.54,1:00:50.41,EN,,0,0,0,,The number of solutions is in the content. Dialogue: 0,1:00:53.00,1:00:55.15,EN,,0,0,0,,I can't tell by looking at the form of a definition Dialogue: 0,1:00:55.16,1:00:56.24,EN,,0,0,0,,whether it makes sense, Dialogue: 0,1:00:56.86,1:00:58.60,EN,,0,0,0,,only by its detailed content. Dialogue: 0,1:00:59.66,1:01:00.88,EN,,0,0,0,,What are the coefficients, Dialogue: 0,1:01:01.34,1:01:03.39,EN,,0,0,0,,for example, in the case of linear equations? Dialogue: 0,1:01:05.10,1:01:06.72,EN,,0,0,0,,So I shouldn't expect to be able to tell Dialogue: 0,1:01:06.99,1:01:08.33,EN,,0,0,0,,looking at something like this, Dialogue: 0,1:01:08.59,1:01:09.95,EN,,0,0,0,,from some simple things like, Dialogue: 0,1:01:10.08,1:01:14.49,EN,,0,0,0,,oh yes, EXPT is the solution of this recursion equation. Dialogue: 0,1:01:16.03,1:01:18.41,EN,,0,0,0,,Expt is the procedure Dialogue: 0,1:01:18.91,1:01:21.10,EN,,0,0,0,,which if substituted in here, Dialogue: 0,1:01:22.04,1:01:24.06,EN,,0,0,0,,gives me expt back. Dialogue: 0,1:01:25.32,1:01:25.68,EN,,0,0,0,,OK? Dialogue: 0,1:01:26.04,1:01:29.24,EN,,0,0,0,,I can't tell, looking at this form, Dialogue: 0,1:01:29.80,1:01:32.60,EN,,0,0,0,,whether or not there's a single, unique solution for EXPT, Dialogue: 0,1:01:33.23,1:01:35.31,EN,,0,0,0,,an infinite number of solutions, or no solutions. Dialogue: 0,1:01:37.20,1:01:38.62,EN,,0,0,0,,It's got to be how it counts Dialogue: 0,1:01:38.64,1:01:40.14,EN,,0,0,0,,and things like that, the details. Dialogue: 0,1:01:40.60,1:01:42.75,EN,,0,0,0,,And it's harder in programming than linear algebra. Dialogue: 0,1:01:43.28,1:01:45.21,EN,,0,0,0,,There aren't too many theorems about it in programming. Dialogue: 0,1:01:48.45,1:01:51.21,EN,,0,0,0,,Well, I want to rewrite these equations a little bit, Dialogue: 0,1:01:51.93,1:01:53.77,EN,,0,0,0,,these over here. Dialogue: 0,1:01:53.97,1:01:56.62,EN,,0,0,0,,Because what we're investigating is equations like this. Dialogue: 0,1:01:57.00,1:01:58.38,EN,,0,0,0,,But I want to play a little with equations Dialogue: 0,1:01:58.40,1:01:59.53,EN,,0,0,0,,like this that we understand, Dialogue: 0,1:02:00.70,1:02:02.91,EN,,0,0,0,,just so we get some insight into this kind of question. Dialogue: 0,1:02:04.72,1:02:06.43,EN,,0,0,0,,We could rewrite our equations here, Dialogue: 0,1:02:06.75,1:02:08.67,EN,,0,0,0,,say these two, the ones that are interesting, Dialogue: 0,1:02:09.77,1:02:14.86,EN,,0,0,0,,as x equals three minus y, Dialogue: 0,1:02:15.88,1:02:19.68,EN,,0,0,0,,and y equals x minus one. Dialogue: 0,1:02:22.01,1:02:24.05,EN,,0,0,0,,What do we call this transformation? Dialogue: 0,1:02:24.05,1:02:26.52,EN,,0,0,0,,This is a linear transformation, t. Dialogue: 0,1:02:29.43,1:02:32.25,EN,,0,0,0,,Then what we're getting here is an equation Dialogue: 0,1:02:32.97,1:02:37.37,EN,,0,0,0,,x y equals t of x y. Dialogue: 0,1:02:42.99,1:02:43.98,EN,,0,0,0,,What am I looking for? Dialogue: 0,1:02:44.56,1:02:46.01,EN,,0,0,0,,I'm looking for a fixed point of t. Dialogue: 0,1:02:46.97,1:02:59.42,EN,,0,0,0,,The solution is a fixed point of t. Dialogue: 0,1:03:01.91,1:03:05.53,EN,,0,0,0,,So the methods we should have for looking for solutions to equations, Dialogue: 0,1:03:05.90,1:03:07.48,EN,,0,0,0,,if I can do it by fixed points, Dialogue: 0,1:03:08.65,1:03:09.87,EN,,0,0,0,,might be applicable. Dialogue: 0,1:03:10.88,1:03:12.36,EN,,0,0,0,,If I have a means of finding a solution Dialogue: 0,1:03:12.38,1:03:14.32,EN,,0,0,0,,to an equations by fixed points-- Dialogue: 0,1:03:15.52,1:03:18.19,EN,,0,0,0,,just, might not work-- Dialogue: 0,1:03:18.57,1:03:19.80,EN,,0,0,0,,but it might be applicable Dialogue: 0,1:03:20.09,1:03:22.27,EN,,0,0,0,,to investigating solutions of equations like this. Dialogue: 0,1:03:27.24,1:03:29.48,EN,,0,0,0,,But what I want you to feel is that this is an equation. Dialogue: 0,1:03:30.26,1:03:31.21,EN,,0,0,0,,It's an expression Dialogue: 0,1:03:31.36,1:03:33.58,EN,,0,0,0,,with several instances of various names Dialogue: 0,1:03:34.70,1:03:37.66,EN,,0,0,0,,which puts a constraint on the name, Dialogue: 0,1:03:38.43,1:03:40.52,EN,,0,0,0,,saying what that name could have as its value, Dialogue: 0,1:03:41.48,1:03:45.01,EN,,0,0,0,,rather than some sort of mechanical process of substitution right now. Dialogue: 0,1:03:47.74,1:03:49.77,EN,,0,0,0,,This is an equation which I'm going to try to solve. Dialogue: 0,1:03:51.22,1:03:52.43,EN,,0,0,0,,Well, let's play around and solve it. Dialogue: 0,1:03:53.96,1:03:55.66,EN,,0,0,0,,First of all, I want to write down Dialogue: 0,1:03:56.64,1:03:59.00,EN,,0,0,0,,the function which corresponds to t. Dialogue: 0,1:04:00.32,1:04:03.00,EN,,0,0,0,,First I want to write down the function which corresponds to t Dialogue: 0,1:04:04.49,1:04:06.96,EN,,0,0,0,,whose fixed point is the answer to this question. Dialogue: 0,1:04:10.76,1:04:11.28,EN,,0,0,0,,OK? Dialogue: 0,1:04:12.25,1:04:14.30,EN,,0,0,0,,Well, let's consider the following procedure f. Dialogue: 0,1:04:16.87,1:04:18.30,EN,,0,0,0,,I claim it computes that function. Dialogue: 0,1:04:19.34,1:04:22.91,EN,,0,0,0,,f is that procedure of one argument g, Dialogue: 0,1:04:25.23,1:04:25.93,EN,,0,0,0,,which is Dialogue: 0,1:04:26.40,1:04:32.00,EN,,0,0,0,,that procedure of two arguments x and n. Dialogue: 0,1:04:33.43,1:04:34.73,EN,,0,0,0,,Which have the property that Dialogue: 0,1:04:36.72,1:04:40.43,EN,,0,0,0,,if n is zero, Dialogue: 0,1:04:41.72,1:04:43.20,EN,,0,0,0,,then the result is one, Dialogue: 0,1:04:45.34,1:04:46.17,EN,,0,0,0,,otherwise, Dialogue: 0,1:04:49.90,1:05:01.40,EN,,0,0,0,,the result is the product of x and g, applied to x, and minus n1. Dialogue: 0,1:05:03.37,1:05:07.80,EN,,0,0,0,,g, times, else, COND, lambda, lambda-- Dialogue: 0,1:05:08.94,1:05:09.40,EN,,0,0,0,,OK? Dialogue: 0,1:05:12.30,1:05:14.62,EN,,0,0,0,,Here f is a procedure, Dialogue: 0,1:05:15.05,1:05:17.79,EN,,0,0,0,,which if I had a solution to that equation, Dialogue: 0,1:05:19.04,1:05:22.04,EN,,0,0,0,,if I had a good exponentiation procedure, Dialogue: 0,1:05:23.42,1:05:26.32,EN,,0,0,0,,and I applied f to that procedure, Dialogue: 0,1:05:27.60,1:05:31.24,EN,,0,0,0,,then the result would be a good exponentiation procedure. Dialogue: 0,1:05:37.46,1:05:38.57,EN,,0,0,0,,Because, what does it do? Dialogue: 0,1:05:39.42,1:05:40.88,EN,,0,0,0,,Well, all it is Dialogue: 0,1:05:42.36,1:05:44.64,EN,,0,0,0,,is exposing g were a good exponentiation procedure, Dialogue: 0,1:05:45.63,1:05:47.58,EN,,0,0,0,,well then this would produce, as its value, Dialogue: 0,1:05:47.84,1:05:49.68,EN,,0,0,0,,a procedure to arguments x and n, Dialogue: 0,1:05:50.49,1:05:51.52,EN,,0,0,0,,such that if n were 0, Dialogue: 0,1:05:51.55,1:05:52.41,EN,,0,0,0,,the result would be one, Dialogue: 0,1:05:52.44,1:05:54.16,EN,,0,0,0,,which is certainly true of exponentiation. Dialogue: 0,1:05:54.64,1:05:57.05,EN,,0,0,0,,Otherwise, it will be the result of multiplying x Dialogue: 0,1:05:57.26,1:05:59.26,EN,,0,0,0,,by the exponentiation procedure given to me Dialogue: 0,1:06:00.17,1:06:02.44,EN,,0,0,0,,with x and n minus one as arguments. Dialogue: 0,1:06:03.47,1:06:04.78,EN,,0,0,0,,So if this computed the correct Dialogue: 0,1:06:04.81,1:06:06.30,EN,,0,0,0,,exponentiation for n minus one, Dialogue: 0,1:06:07.87,1:06:11.28,EN,,0,0,0,,then this would be the correct exponentiation for exponent n, Dialogue: 0,1:06:12.17,1:06:14.41,EN,,0,0,0,,so this would have been the right exponentiation procedure. Dialogue: 0,1:06:17.50,1:06:19.82,EN,,0,0,0,,So what I really want to say here is Dialogue: 0,1:06:21.02,1:06:32.44,EN,,0,0,0,,E-X-P-T is a fixed point of f. Dialogue: 0,1:06:36.99,1:06:38.35,EN,,0,0,0,,Now our problem is Dialogue: 0,1:06:38.35,1:06:39.68,EN,,0,0,0,,there might be more than one fixed point. Dialogue: 0,1:06:40.06,1:06:42.19,EN,,0,0,0,,There might be no fixed points. Dialogue: 0,1:06:43.27,1:06:44.81,EN,,0,0,0,,I have to go hunting for the fixed points. Dialogue: 0,1:06:48.22,1:06:49.37,EN,,0,0,0,,Got to solve this equation. Dialogue: 0,1:06:52.16,1:06:54.28,EN,,0,0,0,,Well there are various ways to hunt for fixed points. Dialogue: 0,1:06:55.58,1:06:57.08,EN,,0,0,0,,Of course, the one we played with Dialogue: 0,1:06:57.24,1:07:01.16,EN,,0,0,0,,at the beginning of this term worked for cosine. Dialogue: 0,1:07:02.73,1:07:07.69,EN,,0,0,0,,Going to. Go into radians mode on your calculator Dialogue: 0,1:07:07.85,1:07:10.51,EN,,0,0,0,,and push cosine, and just keep doing it, Dialogue: 0,1:07:11.84,1:07:15.45,EN,,0,0,0,,and you get to some number which is about 0.73 or 0.74. Dialogue: 0,1:07:16.09,1:07:17.18,EN,,0,0,0,,I can't remember which. Dialogue: 0,1:07:20.57,1:07:22.64,EN,,0,0,0,,By iterating a procedure, which has Dialogue: 0,1:07:22.81,1:07:24.40,EN,,0,0,0,,By iterating a function, Dialogue: 0,1:07:25.60,1:07:27.16,EN,,0,0,0,,whose fixed point I'm searching for, Dialogue: 0,1:07:27.50,1:07:31.13,EN,,0,0,0,,it is sometimes the case that that function will converge Dialogue: 0,1:07:31.87,1:07:33.08,EN,,0,0,0,,in producing the fixed point. Dialogue: 0,1:07:33.77,1:07:35.44,EN,,0,0,0,,I think we luck out in this case, Dialogue: 0,1:07:36.44,1:07:37.21,EN,,0,0,0,,so let's look for it. Dialogue: 0,1:07:39.91,1:07:46.28,EN,,0,0,0,,Let's look at this overhead, this slide. Dialogue: 0,1:07:48.03,1:07:51.71,EN,,0,0,0,,Consider the following sequence of procedures. Dialogue: 0,1:07:56.40,1:07:57.79,EN,,0,0,0,,e0 over here Dialogue: 0,1:07:59.24,1:08:01.63,EN,,0,0,0,,the procedure which does nothing at all. Dialogue: 0,1:08:02.89,1:08:05.10,EN,,0,0,0,,It's the procedure which produces an error Dialogue: 0,1:08:05.10,1:08:06.24,EN,,0,0,0,,for any arguments you give it. Dialogue: 0,1:08:07.78,1:08:09.03,EN,,0,0,0,,It's basically useless. Dialogue: 0,1:08:14.48,1:08:20.08,EN,,0,0,0,,Well, however, I can make an approximation. Dialogue: 0,1:08:20.08,1:08:23.93,EN,,0,0,0,,Let's consider it the worst possible approximation to exponentiation, Dialogue: 0,1:08:24.73,1:08:25.53,EN,,0,0,0,,because it does nothing. Dialogue: 0,1:08:26.99,1:08:29.68,EN,,0,0,0,,Well, supposing I substituted e0 Dialogue: 0,1:08:30.35,1:08:33.26,EN,,0,0,0,,for g by calling f, Dialogue: 0,1:08:33.79,1:08:36.30,EN,,0,0,0,,as you see over here on e0. Dialogue: 0,1:08:37.38,1:08:39.77,EN,,0,0,0,,So you see over here, have e0 there. Dialogue: 0,1:08:40.84,1:08:42.35,EN,,0,0,0,,Then gee, what's e1? Dialogue: 0,1:08:43.63,1:08:46.03,EN,,0,0,0,,e1 is a procedure which exponentiate things Dialogue: 0,1:08:46.67,1:08:48.78,EN,,0,0,0,,to the 0th power, with no trouble. Dialogue: 0,1:08:49.60,1:08:50.75,EN,,0,0,0,,It gets the right answer, Dialogue: 0,1:08:51.05,1:08:52.35,EN,,0,0,0,,anything to the zero is one, Dialogue: 0,1:08:52.68,1:08:54.25,EN,,0,0,0,,and it makes an error on anything else. Dialogue: 0,1:08:57.39,1:09:01.56,EN,,0,0,0,,Well, now what if I take e1 Dialogue: 0,1:09:02.30,1:09:07.40,EN,,0,0,0,,and substituted it for g by calling f on e1? Dialogue: 0,1:09:09.58,1:09:11.18,EN,,0,0,0,,Oh gosh, Dialogue: 0,1:09:12.01,1:09:15.02,EN,,0,0,0,,I have here a procedure of two arguments. Dialogue: 0,1:09:15.67,1:09:16.84,EN,,0,0,0,,Now remember e1 Dialogue: 0,1:09:16.96,1:09:19.66,EN,,0,0,0,,was appropriate for taking exponentiations of 0, Dialogue: 0,1:09:21.47,1:09:23.37,EN,,0,0,0,,for raising to the 0 exponent. Dialogue: 0,1:09:24.20,1:09:25.00,EN,,0,0,0,,So here, Dialogue: 0,1:09:25.52,1:09:27.28,EN,,0,0,0,,if is n is 0, the result is one, Dialogue: 0,1:09:27.29,1:09:28.67,EN,,0,0,0,,so this guy is good for that too. Dialogue: 0,1:09:29.52,1:09:32.01,EN,,0,0,0,,However, I can use something for raising to the 0th power Dialogue: 0,1:09:32.51,1:09:35.26,EN,,0,0,0,,to multiply it by x to raise something to the first power. Dialogue: 0,1:09:35.97,1:09:39.67,EN,,0,0,0,,So e2 is good for both power 0 and 1. Dialogue: 0,1:09:41.60,1:09:41.92,EN,,0,0,0,,OK? Dialogue: 0,1:09:43.71,1:09:46.67,EN,,0,0,0,,And e3 is constructed from e2 in the same way. Dialogue: 0,1:09:47.89,1:09:50.24,EN,,0,0,0,,And e3, of course, by the same argument Dialogue: 0,1:09:50.32,1:09:53.37,EN,,0,0,0,,is good for powers 0, one, and two. Dialogue: 0,1:09:55.12,1:09:55.40,EN,,0,0,0,,OK? Dialogue: 0,1:09:56.09,1:09:59.08,EN,,0,0,0,,And so I will assert for you, without proof, Dialogue: 0,1:09:59.66,1:10:01.72,EN,,0,0,0,,because the proof is horribly difficult. Dialogue: 0,1:10:02.52,1:10:03.60,EN,,0,0,0,,And that's the sort of thing that Dialogue: 0,1:10:03.63,1:10:06.36,EN,,0,0,0,,people called denotational semanticists do. Dialogue: 0,1:10:06.59,1:10:07.64,EN,,0,0,0,,I suppose it was invented Dialogue: 0,1:10:07.87,1:10:10.59,EN,,0,0,0,,This great idea was invented by Scott and Strachey. Dialogue: 0,1:10:11.64,1:10:16.32,EN,,0,0,0,,Ah, sort of. They're very famous mathematician types Dialogue: 0,1:10:16.86,1:10:21.21,EN,,0,0,0,,who invented the interpretation for these programs that we have Dialogue: 0,1:10:22.36,1:10:24.00,EN,,0,0,0,,that I'm talking to you about right now. Dialogue: 0,1:10:24.24,1:10:26.17,EN,,0,0,0,,And they proved, by topology Dialogue: 0,1:10:27.04,1:10:29.32,EN,,0,0,0,,that there is such a fixed point Dialogue: 0,1:10:29.82,1:10:31.26,EN,,0,0,0,,in the cases that we want. Dialogue: 0,1:10:32.22,1:10:33.24,EN,,0,0,0,,But the assertion is Dialogue: 0,1:10:33.40,1:10:44.24,EN,,0,0,0,,E-X-P-T is limit as n goes to infinity of em. Dialogue: 0,1:10:45.52,1:10:47.90,EN,,0,0,0,,and And that we've constructed this by the following way. Dialogue: 0,1:10:50.52,1:10:55.66,EN,,0,0,0,,--is Well, it's f of, f of, f of, f of, f of-- Dialogue: 0,1:10:57.61,1:11:00.19,EN,,0,0,0,,f applied to anything at all. Dialogue: 0,1:11:01.12,1:11:02.46,EN,,0,0,0,,It didn't matter what that was, Dialogue: 0,1:11:03.18,1:11:05.00,EN,,0,0,0,,because, in fact, this always produces an error. Dialogue: 0,1:11:07.45,1:11:08.41,EN,,0,0,0,,Applied to this-- Dialogue: 0,1:11:12.89,1:11:14.48,EN,,0,0,0,,That's by infinite nesting of f's. Dialogue: 0,1:11:16.38,1:11:17.71,EN,,0,0,0,,So now my problem Dialogue: 0,1:11:18.22,1:11:19.76,EN,,0,0,0,,is to make some infinite things. Dialogue: 0,1:11:22.59,1:11:24.08,EN,,0,0,0,,We need some infinite things. Dialogue: 0,1:11:24.92,1:11:26.25,EN,,0,0,0,,How am I going to nest up an f Dialogue: 0,1:11:26.56,1:11:27.80,EN,,0,0,0,,an infinite number of times? Dialogue: 0,1:11:28.98,1:11:30.12,EN,,0,0,0,,I'd better construct this. Dialogue: 0,1:11:32.38,1:11:32.93,EN,,0,0,0,,Well, I don't know. Dialogue: 0,1:11:32.93,1:11:34.32,EN,,0,0,0,,How would I make an infinite loop at all? Dialogue: 0,1:11:34.81,1:11:36.32,EN,,0,0,0,,Let's take a very simple infinite loop, Dialogue: 0,1:11:36.57,1:11:38.34,EN,,0,0,0,,the simplest infinite loop imaginable. Dialogue: 0,1:11:43.55,1:11:47.55,EN,,0,0,0,,If I were to take that procedure of one argument x Dialogue: 0,1:11:48.00,1:11:49.79,EN,,0,0,0,,which applies x to x Dialogue: 0,1:11:53.55,1:11:53.92,EN,,0,0,0,,OK? Dialogue: 0,1:11:55.05,1:11:58.41,EN,,0,0,0,,and apply that to the procedure of one argument x Dialogue: 0,1:11:59.36,1:12:01.05,EN,,0,0,0,,which applies x to x, Dialogue: 0,1:12:04.83,1:12:06.00,EN,,0,0,0,,then this is an infinite loop. Dialogue: 0,1:12:07.21,1:12:09.31,EN,,0,0,0,,The reason why this is an infinite loop is as follows. Dialogue: 0,1:12:09.98,1:12:11.31,EN,,0,0,0,,The way I understand this Dialogue: 0,1:12:11.52,1:12:13.69,EN,,0,0,0,,is I substitute the argument Dialogue: 0,1:12:14.22,1:12:16.59,EN,,0,0,0,,for the formal parameter in the body. Dialogue: 0,1:12:18.85,1:12:21.60,EN,,0,0,0,,But if I do that, I take for each of these x's, Dialogue: 0,1:12:22.40,1:12:23.76,EN,,0,0,0,,I substitute one of these, Dialogue: 0,1:12:24.36,1:12:26.96,EN,,0,0,0,,making a copy of the original expression I just started with, Dialogue: 0,1:12:28.35,1:12:29.37,EN,,0,0,0,,the simplest infinite loop. Dialogue: 0,1:12:35.44,1:12:39.29,EN,,0,0,0,,Now I want to tell you about a particular operator Dialogue: 0,1:12:40.38,1:12:43.09,EN,,0,0,0,,which is constructed by a perturbation from this infinite loop. Dialogue: 0,1:12:46.96,1:12:47.92,EN,,0,0,0,,I'll call it y. Dialogue: 0,1:12:50.89,1:12:55.82,EN,,0,0,0,,OK y -- This is called Curry's Paradoxical Combinator of y Dialogue: 0,1:12:56.62,1:12:58.99,EN,,0,0,0,,after a fellow by the name of Curry, Dialogue: 0,1:12:59.34,1:13:01.85,EN,,0,0,0,,who was a logician of the 1930s also. Dialogue: 0,1:13:04.48,1:13:06.88,EN,,0,0,0,,And if I have a procedure of one argument f, Dialogue: 0,1:13:08.17,1:13:09.33,EN,,0,0,0,,what's it going to have in it? Dialogue: 0,1:13:09.33,1:13:11.20,EN,,0,0,0,,It's going to have a kind of infinite loop in it, Dialogue: 0,1:13:11.98,1:13:15.47,EN,,0,0,0,,which is that procedure of one argument x Dialogue: 0,1:13:15.95,1:13:18.80,EN,,0,0,0,,which applies f to x of x, Dialogue: 0,1:13:21.63,1:13:24.75,EN,,0,0,0,,applied to that procedure of one argument x, Dialogue: 0,1:13:25.10,1:13:27.34,EN,,0,0,0,,which applies f to f of x. Dialogue: 0,1:13:32.30,1:13:33.13,EN,,0,0,0,,Now what's this do? Dialogue: 0,1:13:34.80,1:13:36.06,EN,,0,0,0,,Suppose we apply y to F. Dialogue: 0,1:13:41.31,1:13:42.57,EN,,0,0,0,,OK? Well, that's easy enough. Dialogue: 0,1:13:43.15,1:13:44.62,EN,,0,0,0,,That's this capital F over here. Dialogue: 0,1:13:46.91,1:13:48.16,EN,,0,0,0,,Well, the easiest thing to say there Dialogue: 0,1:13:48.30,1:13:49.92,EN,,0,0,0,,is, I substitute F for here. Dialogue: 0,1:13:55.32,1:13:57.07,EN,,0,0,0,,So that's going to give me, basically-- Dialogue: 0,1:13:58.75,1:14:00.84,EN,,0,0,0,,because then I'm going to substitute this Dialogue: 0,1:14:01.45,1:14:02.80,EN,,0,0,0,,for x in here. Dialogue: 0,1:14:04.17,1:14:05.23,EN,,0,0,0,,That F of Dialogue: 0,1:14:08.97,1:14:10.09,EN,,0,0,0,,Let me actually do it in steps, Dialogue: 0,1:14:10.22,1:14:11.45,EN,,0,0,0,,so you can see it completely. Dialogue: 0,1:14:11.92,1:14:14.27,EN,,0,0,0,,I'm going to be very careful. OK? Dialogue: 0,1:14:15.02,1:14:18.25,EN,,0,0,0,,This is open, open, lambda of x , Dialogue: 0,1:14:19.08,1:14:22.11,EN,,0,0,0,,capital F, x, x, Dialogue: 0,1:14:26.88,1:14:35.55,EN,,0,0,0,,applied to itself, F of x of x. Dialogue: 0,1:14:37.91,1:14:39.66,EN,,0,0,0,,Substituting this for this in here, Dialogue: 0,1:14:40.06,1:14:40.91,EN,,0,0,0,,this is Dialogue: 0,1:14:43.13,1:14:48.35,EN,,0,0,0,,F applied to-- what is it-- substituting this in here Dialogue: 0,1:14:48.65,1:14:54.81,EN,,0,0,0,,open, open, lambda of x, F, of x and x, Dialogue: 0,1:14:57.07,1:14:58.17,EN,,0,0,0,,applied to Dialogue: 0,1:14:59.18,1:15:06.48,EN,,0,0,0,,lambda of x, F of x of x, F, Dialogue: 0,1:15:06.99,1:15:10.44,EN,,0,0,0,,lambda, pair, F. Dialogue: 0,1:15:11.51,1:15:12.40,EN,,0,0,0,,Oh, but what is this? Dialogue: 0,1:15:13.42,1:15:16.35,EN,,0,0,0,,This thing over here that I just computed, Dialogue: 0,1:15:17.13,1:15:18.56,EN,,0,0,0,,is this thing over here. Dialogue: 0,1:15:20.19,1:15:21.84,EN,,0,0,0,,But I just wrapped another F around it. Dialogue: 0,1:15:23.37,1:15:24.67,EN,,0,0,0,,So by applying y to F, Dialogue: 0,1:15:24.68,1:15:26.22,EN,,0,0,0,,I make an infinite series of F's. Dialogue: 0,1:15:27.85,1:15:29.45,EN,,0,0,0,,If I just let this run forever, Dialogue: 0,1:15:29.69,1:15:31.77,EN,,0,0,0,,I'll just keep making more and more F's outside. Dialogue: 0,1:15:33.17,1:15:34.80,EN,,0,0,0,,I ran an infinite loop which is useless, Dialogue: 0,1:15:35.20,1:15:37.02,EN,,0,0,0,,but it doesn't matter that the inside is useless. Dialogue: 0,1:15:39.85,1:15:47.85,EN,,0,0,0,,OK? So y of F is F applied to y of F. Dialogue: 0,1:15:50.33,1:15:52.14,EN,,0,0,0,,So y is a magical thing Dialogue: 0,1:15:53.85,1:15:56.25,EN,,0,0,0,,which, when applied to some function, Dialogue: 0,1:15:57.37,1:16:00.38,EN,,0,0,0,,produces the object which is the fixed point of that function, Dialogue: 0,1:16:01.69,1:16:04.25,EN,,0,0,0,,if it exists, and if this all works. Dialogue: 0,1:16:07.91,1:16:10.08,EN,,0,0,0,,Because, indeed, if I take y of F Dialogue: 0,1:16:10.12,1:16:11.12,EN,,0,0,0,,I get y of F out. Dialogue: 0,1:16:16.24,1:16:18.86,EN,,0,0,0,,Now I want you to think this in terms of Dialogue: 0,1:16:19.85,1:16:22.38,EN,,0,0,0,,the eval-apply interpreter for a bit. Dialogue: 0,1:16:23.86,1:16:26.27,EN,,0,0,0,,I wrote down a whole bunch of recursion equations out there. Dialogue: 0,1:16:28.54,1:16:30.22,EN,,0,0,0,,They're simultaneous in the same way Dialogue: 0,1:16:30.22,1:16:31.23,EN,,0,0,0,,these are simultaneous equations. Dialogue: 0,1:16:31.47,1:16:33.31,EN,,0,0,0,,Exponentiation was not a simultaneous equation. Dialogue: 0,1:16:33.31,1:16:35.79,EN,,0,0,0,,It was only one variable I was looking for a meaning for. Dialogue: 0,1:16:38.15,1:16:40.76,EN,,0,0,0,,But what Lisp is is the fixed point of the process Dialogue: 0,1:16:40.81,1:16:42.57,EN,,0,0,0,,that's which says, if I knew what Lisp was Dialogue: 0,1:16:42.59,1:16:46.51,EN,,0,0,0,,and substituted it in for eval, and apply, and so on, Dialogue: 0,1:16:46.59,1:16:49.79,EN,,0,0,0,,on the right hand sides of all those recursion equations, Dialogue: 0,1:16:50.94,1:16:53.96,EN,,0,0,0,,then if it was a real good Lisp, is a real one, Dialogue: 0,1:16:54.36,1:16:56.30,EN,,0,0,0,,then the left hand side would also be Lisp. Dialogue: 0,1:16:58.22,1:16:59.82,EN,,0,0,0,,So I made sense of that definition. Dialogue: 0,1:17:02.42,1:17:05.41,EN,,0,0,0,,Now whether or not there's an answer isn't so obvious. Dialogue: 0,1:17:05.69,1:17:06.75,EN,,0,0,0,,I can't attack that. Dialogue: 0,1:17:07.74,1:17:09.21,EN,,0,0,0,,Now these arguments that I'm giving you now Dialogue: 0,1:17:09.26,1:17:10.27,EN,,0,0,0,,are quite dangerous. Dialogue: 0,1:17:10.66,1:17:11.64,EN,,0,0,0,,Let's look over here. Dialogue: 0,1:17:13.05,1:17:14.61,EN,,0,0,0,,On the. These are limit arguments. Dialogue: 0,1:17:14.61,1:17:15.39,EN,,0,0,0,,We're talking about limits, Dialogue: 0,1:17:15.45,1:17:17.68,EN,,0,0,0,,and it's really calculus, or topology, Dialogue: 0,1:17:17.87,1:17:20.03,EN,,0,0,0,,or something like that, a kind of analysis. Dialogue: 0,1:17:20.76,1:17:23.38,EN,,0,0,0,,OK?Now here's an argument that you all believe. Dialogue: 0,1:17:23.38,1:17:25.29,EN,,0,0,0,,And I want to make sure you realize Dialogue: 0,1:17:25.42,1:17:27.66,EN,,0,0,0,,that I could be bullshitting you. Dialogue: 0,1:17:28.86,1:17:30.48,EN,,0,0,0,,Alright? What is this? Dialogue: 0,1:17:34.25,1:17:39.52,EN,,0,0,0,,u is the sum of 1/2, 1/4, and 1/8, and so on, Dialogue: 0,1:17:39.74,1:17:41.32,EN,,0,0,0,,the sum of a geometric series. Dialogue: 0,1:17:42.82,1:17:44.68,EN,,0,0,0,,And, of course, I could play a game here. Dialogue: 0,1:17:44.82,1:17:47.57,EN,,0,0,0,,u minus one is 1/2, plus 1/4, plus 1/8, and so on. Dialogue: 0,1:17:51.90,1:17:54.46,EN,,0,0,0,,But now if I multiple. What I could do here-- Dialogue: 0,1:17:56.09,1:17:57.93,EN,,0,0,0,,Ooops. There is a parentheses error here. Dialogue: 0,1:17:58.92,1:18:01.45,EN,,0,0,0,,But I can put here two times u minus one Dialogue: 0,1:18:01.74,1:18:03.99,EN,,0,0,0,,is one plus 1/2, plus 1/4, plus 1/8. Dialogue: 0,1:18:07.57,1:18:08.54,EN,,0,0,0,,Can I fix that? Dialogue: 0,1:18:14.01,1:18:16.43,EN,,0,0,0,,Yes, well. Dialogue: 0,1:18:18.19,1:18:18.65,EN,,0,0,0,,OK? Dialogue: 0,1:18:19.52,1:18:20.64,EN,,0,0,0,,But that gives me back Dialogue: 0,1:18:23.53,1:18:26.64,EN,,0,0,0,,two times u minus one is u, Dialogue: 0,1:18:27.80,1:18:29.58,EN,,0,0,0,,therefore, we conclude that u is two. Dialogue: 0,1:18:30.30,1:18:31.37,EN,,0,0,0,,And this actually is true. Dialogue: 0,1:18:31.96,1:18:33.32,EN,,0,0,0,,There's no problem like that. Dialogue: 0,1:18:34.04,1:18:37.55,EN,,0,0,0,,But supposing I did something different. Dialogue: 0,1:18:38.54,1:18:39.48,EN,,0,0,0,,Supposing I start up with something Dialogue: 0,1:18:39.50,1:18:41.20,EN,,0,0,0,,which manifestly has no sum. Dialogue: 0,1:18:41.56,1:18:46.99,EN,,0,0,0,,v is one, plus two, plus four, plus 8, plus dot, dot, dot. OK? Dialogue: 0,1:18:47.39,1:18:51.39,EN,,0,0,0,,Well, v minus one is surely two, plus four, plus eight, plus dot, dot, dot. Right? Dialogue: 0,1:18:52.27,1:18:56.03,EN,,0,0,0,,v minus one over two, gee, that looks like v again. Dialogue: 0,1:18:57.41,1:19:00.54,EN,,0,0,0,,From that I should be able to conclude that-- Dialogue: 0,1:19:01.37,1:19:02.91,EN,,0,0,0,,that's also wrong, apparently. Dialogue: 0,1:19:03.07,1:19:04.51,EN,,0,0,0,,v equals minus one. Dialogue: 0,1:19:12.45,1:19:13.82,EN,,0,0,0,,That should be a minus one. Dialogue: 0,1:19:15.28,1:19:16.91,EN,,0,0,0,,And that's certainly a false conclusion. Dialogue: 0,1:19:22.00,1:19:23.47,EN,,0,0,0,,So when you play with limits, Dialogue: 0,1:19:24.22,1:19:27.85,EN,,0,0,0,,arguments that may work in one case Dialogue: 0,1:19:29.42,1:19:30.75,EN,,0,0,0,,they may not work in some other case. Dialogue: 0,1:19:30.75,1:19:31.69,EN,,0,0,0,,You have to be very careful. Dialogue: 0,1:19:32.24,1:19:33.87,EN,,0,0,0,,The arguments have to be well-formed. Dialogue: 0,1:19:36.14,1:19:39.23,EN,,0,0,0,,And I don't know, in general, Dialogue: 0,1:19:39.85,1:19:41.93,EN,,0,0,0,,what the story is about arguments like this. Dialogue: 0,1:19:43.27,1:19:45.24,EN,,0,0,0,,We can read a pile of topology and find out. Dialogue: 0,1:19:46.27,1:19:48.64,EN,,0,0,0,,But, surely, at least you understand now, Dialogue: 0,1:19:49.10,1:19:51.13,EN,,0,0,0,,why it might be some meaning Dialogue: 0,1:19:51.15,1:19:52.76,EN,,0,0,0,,to the things we've been writing on the blackboard. Dialogue: 0,1:19:53.66,1:19:55.61,EN,,0,0,0,,And you understand what that might mean. Dialogue: 0,1:19:56.48,1:19:58.35,EN,,0,0,0,,So, I suppose, it's almost about time Dialogue: 0,1:19:59.07,1:20:03.84,EN,,0,0,0,,for you to merit being made a member Dialogue: 0,1:20:04.28,1:20:05.55,EN,,0,0,0,,of the grand recursive order Dialogue: 0,1:20:05.56,1:20:07.04,EN,,0,0,0,,of lambda calculus hackers. Dialogue: 0,1:20:08.84,1:20:10.17,EN,,0,0,0,,I would. This is the badge. Dialogue: 0,1:20:10.82,1:20:12.54,EN,,0,0,0,,Because you now understand, for example, Dialogue: 0,1:20:13.40,1:20:15.20,EN,,0,0,0,,what it says at the very top, Dialogue: 0,1:20:16.89,1:20:18.41,EN,,0,0,0,,y F equals F y F. Dialogue: 0,1:20:21.04,1:20:21.66,EN,,0,0,0,,Thank you. Dialogue: 0,1:20:21.85,1:20:22.75,EN,,0,0,0,,Are there any questions? Dialogue: 0,1:20:24.71,1:20:25.15,EN,,0,0,0,,Yes, Lev. Dialogue: 0,1:20:25.37,1:20:27.39,EN,,0,0,0,,AUDIENCE: With this, it seems that Dialogue: 0,1:20:27.40,1:20:30.22,EN,,0,0,0,,there's no need to define, as you imply, Dialogue: 0,1:20:30.24,1:20:32.70,EN,,0,0,0,,to just remember a value, to apply it later. Dialogue: 0,1:20:32.99,1:20:33.32,EN,,0,0,0,,PROFESSOR: Yeah. Dialogue: 0,1:20:33.50,1:20:36.44,EN,,0,0,0,,AUDIENCE: Defines were kind of a side-effect it seemed in the language. Dialogue: 0,1:20:36.49,1:20:38.52,EN,,0,0,0,,[INTERPOSING] are order dependent. Dialogue: 0,1:20:39.30,1:20:42.06,EN,,0,0,0,,Does this eliminate the side-effect from the. Dialogue: 0,1:20:42.28,1:20:44.68,EN,,0,0,0,,PROFESSOR: Well. The answer is, Dialogue: 0,1:20:44.88,1:20:46.44,EN,,0,0,0,,this is not the way these things were implemented. Dialogue: 0,1:20:47.52,1:20:47.93,EN,,0,0,0,,OK? Dialogue: 0,1:20:48.92,1:20:53.15,EN,,0,0,0,,Define, indeed is implemented as an operation Dialogue: 0,1:20:53.18,1:20:55.53,EN,,0,0,0,,that actually modifies an environment structure, Dialogue: 0,1:20:57.95,1:21:02.33,EN,,0,0,0,,changes the frame that the define is executed in. Dialogue: 0,1:21:03.69,1:21:06.51,EN,,0,0,0,,And there are many reasons for that, Dialogue: 0,1:21:07.39,1:21:08.64,EN,,0,0,0,,but a lot of this has to do with Dialogue: 0,1:21:08.67,1:21:10.09,EN,,0,0,0,,making an interactive system. Dialogue: 0,1:21:11.34,1:21:14.12,EN,,0,0,0,,What this is saying is that if you've made a system, Dialogue: 0,1:21:14.35,1:21:15.20,EN,,0,0,0,,and you know Dialogue: 0,1:21:15.42,1:21:16.60,EN,,0,0,0,,and you know you're not going to do any debugging Dialogue: 0,1:21:16.60,1:21:17.55,EN,,0,0,0,,or anything like that, Dialogue: 0,1:21:17.84,1:21:20.72,EN,,0,0,0,,and you know everything there is all at once, Dialogue: 0,1:21:20.75,1:21:21.24,EN,,0,0,0,,and you want to say, Dialogue: 0,1:21:21.26,1:21:23.12,EN,,0,0,0,,what is the meaning of a final set of equations? Dialogue: 0,1:21:24.09,1:21:25.26,EN,,0,0,0,,This gives you a meaning for it. Dialogue: 0,1:21:25.79,1:21:27.45,EN,,0,0,0,,But in order to make an interactive system, Dialogue: 0,1:21:27.45,1:21:28.75,EN,,0,0,0,,where you can change the meaning of one Dialogue: 0,1:21:28.76,1:21:31.68,EN,,0,0,0,,without changing everything else, incrementally, Dialogue: 0,1:21:32.33,1:21:35.04,EN,,0,0,0,,you can't do that by implementing it this way. Dialogue: 0,1:21:40.99,1:21:41.24,EN,,0,0,0,,Yes. Dialogue: 0,1:21:42.30,1:21:44.25,EN,,0,0,0,,AUDIENCE: Another question on your danger slide. Dialogue: 0,1:21:44.65,1:21:47.13,EN,,0,0,0,,It seemed that the two examples that you gave Dialogue: 0,1:21:47.16,1:21:49.07,EN,,0,0,0,,had to do with convergence and non-convergence? Dialogue: 0,1:21:49.18,1:21:49.56,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,1:21:50.30,1:21:52.62,EN,,0,0,0,,AUDIENCE: And that may or may not have something to do with Dialogue: 0,1:21:52.76,1:21:54.68,EN,,0,0,0,,with function theory in a way which Dialogue: 0,1:21:54.72,1:21:56.60,EN,,0,0,0,,would lead you to think of it in terms of linear systems, Dialogue: 0,1:21:57.74,1:21:59.00,EN,,0,0,0,,or non-linear systems. Dialogue: 0,1:21:59.34,1:22:01.76,EN,,0,0,0,,How does this convergence relate to being able to Dialogue: 0,1:22:02.35,1:22:05.53,EN,,0,0,0,,see a priori what properties of that might be violated? Dialogue: 0,1:22:05.79,1:22:06.57,EN,,0,0,0,,PROFESSOR: I don't know. Dialogue: 0,1:22:07.68,1:22:10.09,EN,,0,0,0,,The answer is, I don't know under what circumstances. Dialogue: 0,1:22:10.61,1:22:12.04,EN,,0,0,0,,I don't know how to translate that Dialogue: 0,1:22:12.52,1:22:14.73,EN,,0,0,0,,into less than an hour of talk more. Dialogue: 0,1:22:16.91,1:22:18.48,EN,,0,0,0,,What are the conditions under which, Dialogue: 0,1:22:18.86,1:22:20.76,EN,,0,0,0,,for which we know that these things converge? Dialogue: 0,1:22:22.86,1:22:23.31,EN,,0,0,0,,And indeed, Dialogue: 0,1:22:23.32,1:22:26.35,EN,,0,0,0,,all that was telling you that arguments that are based on convergence Dialogue: 0,1:22:28.24,1:22:29.47,EN,,0,0,0,,are flaky Dialogue: 0,1:22:29.66,1:22:31.58,EN,,0,0,0,,if you don't know the convergence beforehand. Dialogue: 0,1:22:32.81,1:22:34.20,EN,,0,0,0,,You can make wrong arguments. Dialogue: 0,1:22:34.44,1:22:37.31,EN,,0,0,0,,You can make deductions, as if you know the answer, Dialogue: 0,1:22:37.39,1:22:39.93,EN,,0,0,0,,and not be stopped somewhere by some obvious contradiction. Dialogue: 0,1:22:40.97,1:22:42.28,EN,,0,0,0,,AUDIENCE: So can we say then that Dialogue: 0,1:22:42.33,1:22:44.88,EN,,0,0,0,,if F is a convergent mathematical expression, Dialogue: 0,1:22:45.00,1:22:47.36,EN,,0,0,0,,then the recursion property can be-- Dialogue: 0,1:22:47.58,1:22:51.29,EN,,0,0,0,,PROFESSOR: Well, I think there's a technical kind of F, Dialogue: 0,1:22:52.12,1:22:54.22,EN,,0,0,0,,OK? There is a technical description Dialogue: 0,1:22:54.24,1:22:55.90,EN,,0,0,0,,of those F's that have the property Dialogue: 0,1:22:55.98,1:23:01.31,EN,,0,0,0,,that when you iteratively apply them like this, Dialogue: 0,1:23:01.52,1:23:02.25,EN,,0,0,0,,you converge. Dialogue: 0,1:23:03.02,1:23:06.51,EN,,0,0,0,,Things that are monotonic, and continuous, Dialogue: 0,1:23:07.32,1:23:07.95,EN,,0,0,0,,OK? Dialogue: 0,1:23:08.38,1:23:09.37,EN,,0,0,0,,and I forgot what else. Dialogue: 0,1:23:09.37,1:23:11.13,EN,,0,0,0,,There is a whole bunch of little conditions like that Dialogue: 0,1:23:11.68,1:23:12.99,EN,,0,0,0,,which have this property. Dialogue: 0,1:23:13.43,1:23:16.00,EN,,0,0,0,,Now the real problem is deducing from looking at the F, Dialogue: 0,1:23:16.92,1:23:17.88,EN,,0,0,0,,its definition here, Dialogue: 0,1:23:18.17,1:23:19.66,EN,,0,0,0,,whether not it has those properties, Dialogue: 0,1:23:20.27,1:23:21.32,EN,,0,0,0,,and that's very hard. Dialogue: 0,1:23:22.01,1:23:24.00,EN,,0,0,0,,The properties are easy. You can write them down. Dialogue: 0,1:23:24.58,1:23:26.32,EN,,0,0,0,,You can look in a book by Joe Stoy. Dialogue: 0,1:23:26.67,1:23:29.58,EN,,0,0,0,,It's a great book-- Stoy. Dialogue: 0,1:23:32.22,1:23:34.06,EN,,0,0,0,,It's called, The Scott-Strachey Dialogue: 0,1:23:34.49,1:23:38.46,EN,,0,0,0,,The Scott-Strachey Method of Denotational Semantics, Dialogue: 0,1:23:39.55,1:23:40.76,EN,,0,0,0,,and it's by Joe Stoy, Dialogue: 0,1:23:40.80,1:23:41.76,EN,,0,0,0,,MIT Press. Dialogue: 0,1:23:48.06,1:23:49.88,EN,,0,0,0,,And he works out all this in great detail, Dialogue: 0,1:23:50.20,1:23:51.37,EN,,0,0,0,,enough to horrify you. Dialogue: 0,1:23:55.05,1:23:56.19,EN,,0,0,0,,But it really is readable. Dialogue: 0,1:24:09.15,1:24:10.08,EN,,0,0,0,,OK, well, thank you. Dialogue: 0,1:24:11.49,1:24:12.99,EN,,0,0,0,,Time for the bigger break, I suppose. Dialogue: 0,1:24:14.17,1:24:20.92,EN,,0,0,0,,http://ocw.mit.edu Dialogue: 0,1:24:20.92,1:24:34.49,EN,,0,0,0,,https://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec7b.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 3 Video Position: 790 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:17.21,0:00:17.96,EN,,0,0,0,,PROFESSOR: Well, let's see. Dialogue: 0,0:00:19.52,0:00:21.29,EN,,0,0,0,,What we did so far was a lot of fun, Dialogue: 0,0:00:21.52,0:00:23.05,EN,,0,0,0,,was it useful for anything? Dialogue: 0,0:00:26.33,0:00:27.96,EN,,0,0,0,,I suppose the answer is going to be yes. Dialogue: 0,0:00:29.38,0:00:31.92,EN,,0,0,0,,If these metacircular interpreters Dialogue: 0,0:00:32.96,0:00:34.60,EN,,0,0,0,,are a valuable thing to play with. Dialogue: 0,0:00:34.62,0:00:36.17,EN,,0,0,0,,I spend, say Dialogue: 0,0:00:38.05,0:00:41.85,EN,,0,0,0,,there have been times I spend 50% of my time, over a year, Dialogue: 0,0:00:42.86,0:00:45.26,EN,,0,0,0,,trying various design alternatives Dialogue: 0,0:00:45.76,0:00:48.19,EN,,0,0,0,,by experimenting with them with metacircular interpreters-- Dialogue: 0,0:00:49.47,0:00:52.01,EN,,0,0,0,,metacircular interpreters like the sort you just saw. Dialogue: 0,0:00:52.57,0:00:54.11,EN,,0,0,0,,Metacircular is because Dialogue: 0,0:00:54.72,0:00:56.94,EN,,0,0,0,,they are defined in terms of themselves in such a way Dialogue: 0,0:00:56.97,0:00:59.71,EN,,0,0,0,,that the language they interpret contains itself. Dialogue: 0,0:01:01.27,0:01:03.87,EN,,0,0,0,,Such interpreters are a convenient medium Dialogue: 0,0:01:03.88,0:01:05.58,EN,,0,0,0,,for exploring language issues. Dialogue: 0,0:01:06.80,0:01:09.44,EN,,0,0,0,,If you want to try adding a new feature, Dialogue: 0,0:01:10.51,0:01:12.38,EN,,0,0,0,,it's sort of a snap, it's easy, Dialogue: 0,0:01:12.73,0:01:15.10,EN,,0,0,0,,you just do it and see what happens. Dialogue: 0,0:01:15.49,0:01:17.20,EN,,0,0,0,,You play with that language for a while you say, Dialogue: 0,0:01:17.24,0:01:18.24,EN,,0,0,0,,gee, I'm didn't like that, Dialogue: 0,0:01:18.52,0:01:19.47,EN,,0,0,0,,you throw it away. Dialogue: 0,0:01:20.96,0:01:23.55,EN,,0,0,0,,Or you might want to see what Dialogue: 0,0:01:23.64,0:01:27.37,EN,,0,0,0,,the difference is if you'd make a slight difference in the binding strategy, Dialogue: 0,0:01:28.81,0:01:31.90,EN,,0,0,0,,or some more complicated things that might occur. Dialogue: 0,0:01:33.72,0:01:35.48,EN,,0,0,0,,In fact, these metacircular interpreters Dialogue: 0,0:01:36.17,0:01:37.88,EN,,0,0,0,,are an excellent medium for people Dialogue: 0,0:01:38.20,0:01:42.56,EN,,0,0,0,,exchanging ideas about language design, Dialogue: 0,0:01:43.98,0:01:45.74,EN,,0,0,0,,because they're pretty easy to understand, Dialogue: 0,0:01:46.28,0:01:48.46,EN,,0,0,0,,and they're short, and compact, and simple. Dialogue: 0,0:01:49.32,0:01:50.80,EN,,0,0,0,,If I have some idea Dialogue: 0,0:01:51.53,0:01:53.77,EN,,0,0,0,,that I want somebody to criticize Dialogue: 0,0:01:54.25,0:01:58.32,EN,,0,0,0,,like say, Dan Friedman at Indiana, Dialogue: 0,0:01:59.05,0:02:02.00,EN,,0,0,0,,I'd write a little metacircular interpreter Dialogue: 0,0:02:02.56,0:02:03.79,EN,,0,0,0,,send him some network mail Dialogue: 0,0:02:04.65,0:02:05.45,EN,,0,0,0,,with this interpreter in it. Dialogue: 0,0:02:05.45,0:02:07.90,EN,,0,0,0,,He could whip it up on his machine and play with it Dialogue: 0,0:02:07.92,0:02:09.82,EN,,0,0,0,,and say, that's no good. Dialogue: 0,0:02:11.94,0:02:13.10,EN,,0,0,0,,And then send it back to me and say, Dialogue: 0,0:02:13.13,0:02:14.83,EN,,0,0,0,,well, why don't you try this one, it's a little better. Dialogue: 0,0:02:16.88,0:02:19.36,EN,,0,0,0,,So I want to show you some of that technology. Dialogue: 0,0:02:20.16,0:02:24.20,EN,,0,0,0,,See, because, really, it's the essential, simple technology Dialogue: 0,0:02:24.72,0:02:28.68,EN,,0,0,0,,for getting started in designing your own languages for particular purposes. Dialogue: 0,0:02:30.79,0:02:32.08,EN,,0,0,0,,Let's start by adding Dialogue: 0,0:02:32.51,0:02:34.21,EN,,0,0,0,,a very simple feature to a Lisp. Dialogue: 0,0:02:40.64,0:02:44.37,EN,,0,0,0,,Now, one thing I want to tell you about is features, before I start. Dialogue: 0,0:02:49.56,0:02:52.17,EN,,0,0,0,,There are many languages that have made a mess of themselves Dialogue: 0,0:02:53.05,0:02:54.91,EN,,0,0,0,,by adding huge numbers of features. Dialogue: 0,0:02:56.86,0:02:58.38,EN,,0,0,0,,Computer scientists have a joke Dialogue: 0,0:02:59.28,0:03:02.52,EN,,0,0,0,,about bugs that transform it to features all the time. Dialogue: 0,0:03:05.03,0:03:06.46,EN,,0,0,0,,But I like to think of it is that Dialogue: 0,0:03:08.91,0:03:11.44,EN,,0,0,0,,many systems suffer from what's called creeping featurism. Dialogue: 0,0:03:12.82,0:03:13.44,EN,,0,0,0,,Which is that Dialogue: 0,0:03:14.94,0:03:18.16,EN,,0,0,0,,George has a pet feature he'd like in the system, Dialogue: 0,0:03:18.72,0:03:19.36,EN,,0,0,0,,so he adds it. Dialogue: 0,0:03:20.17,0:03:22.14,EN,,0,0,0,,And then Harry says, go says Dialogue: 0,0:03:22.17,0:03:24.20,EN,,0,0,0,,gee, this system is no longer what exactly I like, Dialogue: 0,0:03:24.24,0:03:25.92,EN,,0,0,0,,so I'm going to add my favorite feature. Dialogue: 0,0:03:26.64,0:03:30.24,EN,,0,0,0,,And then Jim adds his favorite feature. Dialogue: 0,0:03:30.83,0:03:31.79,EN,,0,0,0,,And, after a while, Dialogue: 0,0:03:31.80,0:03:34.81,EN,,0,0,0,,the thing has a manual 500 pages long Dialogue: 0,0:03:35.15,0:03:36.51,EN,,0,0,0,,that no one can understand. Dialogue: 0,0:03:37.79,0:03:39.32,EN,,0,0,0,,And sometimes it's the same person Dialogue: 0,0:03:39.90,0:03:41.37,EN,,0,0,0,,who writes all of these features Dialogue: 0,0:03:41.39,0:03:43.23,EN,,0,0,0,,and produces this terribly complicated thing. Dialogue: 0,0:03:44.14,0:03:46.09,EN,,0,0,0,,In some cases, like editors, Dialogue: 0,0:03:47.37,0:03:49.12,EN,,0,0,0,,it's sort of reasonable to have lots of features, Dialogue: 0,0:03:50.92,0:03:52.65,EN,,0,0,0,,because there are a lot of things you want to be able to do Dialogue: 0,0:03:52.68,0:03:53.76,EN,,0,0,0,,and many of them arbitrary. Dialogue: 0,0:03:56.11,0:03:57.29,EN,,0,0,0,,But in computer languages, Dialogue: 0,0:03:57.85,0:03:58.91,EN,,0,0,0,,I think it's a disaster Dialogue: 0,0:04:00.01,0:04:01.29,EN,,0,0,0,,to have too much stuff in them. Dialogue: 0,0:04:04.03,0:04:08.00,EN,,0,0,0,,The other alternative you get into is something called feeping creaturism, Dialogue: 0,0:04:09.52,0:04:11.39,EN,,0,0,0,,which is where you have a box Dialogue: 0,0:04:11.80,0:04:15.29,EN,,0,0,0,,which has a display, a fancy display, and a mouse, Dialogue: 0,0:04:15.95,0:04:20.04,EN,,0,0,0,,and there is all sorts of complexity associated with all this fancy IO. Dialogue: 0,0:04:21.01,0:04:22.80,EN,,0,0,0,,And your computer language becomes Dialogue: 0,0:04:23.34,0:04:25.37,EN,,0,0,0,,a dismal, little, tiny thing that barely works Dialogue: 0,0:04:25.40,0:04:27.90,EN,,0,0,0,,because of all the swapping, and disk twitching, and so on, Dialogue: 0,0:04:28.09,0:04:29.36,EN,,0,0,0,,caused by your Window system. Dialogue: 0,0:04:30.08,0:04:31.82,EN,,0,0,0,,And every time you go near the computer, Dialogue: 0,0:04:31.93,0:04:33.45,EN,,0,0,0,,the mouse process wakes up and says, Dialogue: 0,0:04:33.85,0:04:35.95,EN,,0,0,0,,gee do you have something for me to do, Dialogue: 0,0:04:36.14,0:04:37.23,EN,,0,0,0,,and then it goes back to sleep. Dialogue: 0,0:04:37.44,0:04:39.44,EN,,0,0,0,,And if you accidentally push mouse with you elbow, Dialogue: 0,0:04:39.61,0:04:42.32,EN,,0,0,0,,a big puff of smoke comes out of your computer and things like that. Dialogue: 0,0:04:42.94,0:04:45.29,EN,,0,0,0,,So two ways to disastrously Dialogue: 0,0:04:45.55,0:04:47.21,EN,,0,0,0,,destroy a system by adding features. Dialogue: 0,0:04:47.50,0:04:49.73,EN,,0,0,0,,But try right now to add a little, simple feature. Dialogue: 0,0:04:52.60,0:04:53.77,EN,,0,0,0,,This actually is a good one, Dialogue: 0,0:04:53.85,0:04:56.17,EN,,0,0,0,,and in fact, real Lisps have it. Dialogue: 0,0:04:57.25,0:04:58.17,EN,,0,0,0,,As you've seen, Dialogue: 0,0:04:59.29,0:05:03.13,EN,,0,0,0,,there are procedures like plus and times Dialogue: 0,0:05:03.37,0:05:04.89,EN,,0,0,0,,that take any number of arguments. Dialogue: 0,0:05:05.43,0:05:06.44,EN,,0,0,0,,So we can write things Dialogue: 0,0:05:06.57,0:05:10.94,EN,,0,0,0,,like the sum of the product of a and x and x, Dialogue: 0,0:05:12.09,0:05:16.99,EN,,0,0,0,,and the product of b and x and c. Dialogue: 0,0:05:17.54,0:05:18.68,EN,,0,0,0,,As you can see here, Dialogue: 0,0:05:18.92,0:05:21.76,EN,,0,0,0,,addition takes three arguments or two arguments, Dialogue: 0,0:05:22.30,0:05:24.81,EN,,0,0,0,,multiplication takes two arguments or three arguments, Dialogue: 0,0:05:25.08,0:05:26.76,EN,,0,0,0,,taking numbers of arguments Dialogue: 0,0:05:26.78,0:05:28.49,EN,,0,0,0,,all of which are to be treated in the same way. Dialogue: 0,0:05:30.00,0:05:32.17,EN,,0,0,0,,This is a valuable thing, Dialogue: 0,0:05:32.28,0:05:34.01,EN,,0,0,0,,indefinite numbers of arguments. Dialogue: 0,0:05:34.96,0:05:38.41,EN,,0,0,0,,Yet the particular Lisp system that I show you Dialogue: 0,0:05:39.23,0:05:41.85,EN,,0,0,0,,is one where the numbers of arguments is fixed, Dialogue: 0,0:05:42.62,0:05:45.28,EN,,0,0,0,,because I had to match the arguments against the formal parameters Dialogue: 0,0:05:45.63,0:05:47.92,EN,,0,0,0,,in the binder, where there's a pairup. Dialogue: 0,0:05:50.81,0:05:53.80,EN,,0,0,0,,Well, I'd like to be able to define new procedures like this Dialogue: 0,0:05:54.89,0:05:57.32,EN,,0,0,0,,that can have any number of arguments. Dialogue: 0,0:05:58.75,0:06:00.40,EN,,0,0,0,,Well there's several parts to this problem. Dialogue: 0,0:06:01.34,0:06:04.81,EN,,0,0,0,,The first part is coming up with the syntactic specification, Dialogue: 0,0:06:05.72,0:06:11.21,EN,,0,0,0,,some way of notating the additional arguments, Dialogue: 0,0:06:12.17,0:06:13.63,EN,,0,0,0,,of which you don't know how many there are. Dialogue: 0,0:06:15.48,0:06:16.62,EN,,0,0,0,,And then there's the other thing, Dialogue: 0,0:06:17.10,0:06:18.70,EN,,0,0,0,,which is once we've notated it, Dialogue: 0,0:06:19.07,0:06:20.78,EN,,0,0,0,,how are we going to interpret that notation Dialogue: 0,0:06:21.74,0:06:23.10,EN,,0,0,0,,so as to do the right thing, Dialogue: 0,0:06:23.85,0:06:25.37,EN,,0,0,0,,whatever the right thing is? Dialogue: 0,0:06:26.98,0:06:28.80,EN,,0,0,0,,So let's consider an example of a sort of thing Dialogue: 0,0:06:28.84,0:06:30.27,EN,,0,0,0,,we might want to be able to do. Dialogue: 0,0:06:33.07,0:06:34.51,EN,,0,0,0,,So an example might be, Dialogue: 0,0:06:35.42,0:06:37.34,EN,,0,0,0,,that I might want to be able to define a procedure Dialogue: 0,0:06:37.95,0:06:41.36,EN,,0,0,0,,which is a procedure of one required argument x Dialogue: 0,0:06:42.20,0:06:45.26,EN,,0,0,0,,and a non-required -- bunch of arguments, Dialogue: 0,0:06:45.28,0:06:47.23,EN,,0,0,0,,I don't know how many there are, called y. Dialogue: 0,0:06:49.09,0:06:50.36,EN,,0,0,0,,So x is required, Dialogue: 0,0:06:55.88,0:06:57.44,EN,,0,0,0,,and there are many y's, Dialogue: 0,0:06:59.53,0:07:05.99,EN,,0,0,0,,many arguments-- y will be the list of them. Dialogue: 0,0:07:14.48,0:07:16.06,EN,,0,0,0,,Now, with such a thing, Dialogue: 0,0:07:16.09,0:07:17.68,EN,,0,0,0,,we might be able to say something like, Dialogue: 0,0:07:19.02,0:07:21.98,EN,,0,0,0,,map-- I'm going to do something to every one-- Dialogue: 0,0:07:22.52,0:07:25.76,EN,,0,0,0,,of that procedure of one argument u, Dialogue: 0,0:07:27.00,0:07:34.54,EN,,0,0,0,,which multiplies x by u, and we'll apply that to y. Dialogue: 0,0:07:36.89,0:07:38.04,EN,,0,0,0,,I've used a dot here Dialogue: 0,0:07:38.59,0:07:41.31,EN,,0,0,0,,to indicate that the thing after this Dialogue: 0,0:07:42.19,0:07:44.30,EN,,0,0,0,,is a list of all the rest of the arguments. Dialogue: 0,0:07:46.30,0:07:48.12,EN,,0,0,0,,I'm making a syntactic specification. Dialogue: 0,0:07:53.32,0:07:54.64,EN,,0,0,0,,Now, what this depends upon, Dialogue: 0,0:07:55.71,0:07:58.06,EN,,0,0,0,,the reason why this is sort of a reasonable thing to do, Dialogue: 0,0:07:59.77,0:08:01.96,EN,,0,0,0,,is because this happens to be a syntax Dialogue: 0,0:08:02.00,0:08:03.60,EN,,0,0,0,,that's used in the Lisp reader Dialogue: 0,0:08:04.41,0:08:07.15,EN,,0,0,0,,for representing conses. Dialogue: 0,0:08:08.94,0:08:11.08,EN,,0,0,0,,We've never introduced that before.You never see. Dialogue: 0,0:08:11.08,0:08:12.78,EN,,0,0,0,,You may have seen when playing with the system Dialogue: 0,0:08:13.04,0:08:14.62,EN,,0,0,0,,if you cons two things together, you get the Dialogue: 0,0:08:14.89,0:08:18.12,EN,,0,0,0,,first, space, dot, the second, space-- Dialogue: 0,0:08:19.79,0:08:22.83,EN,,0,0,0,,the first, space, dot, space, the second Dialogue: 0,0:08:23.08,0:08:24.64,EN,,0,0,0,,with parentheses around the whole thing. Dialogue: 0,0:08:26.98,0:08:28.16,EN,,0,0,0,,So that, for example, Dialogue: 0,0:08:28.97,0:08:35.04,EN,,0,0,0,,this x dot y corresponds to a pair, Dialogue: 0,0:08:36.33,0:08:39.29,EN,,0,0,0,,which has got an x in it and a y in it. Dialogue: 0,0:08:41.48,0:08:43.98,EN,,0,0,0,,The other notations that you've seen so far Dialogue: 0,0:08:44.94,0:08:46.67,EN,,0,0,0,,are things like, like Dialogue: 0,0:08:46.92,0:08:55.24,EN,,0,0,0,,a procedure of arguments x and y and z which do things Dialogue: 0,0:08:55.71,0:08:57.63,EN,,0,0,0,,and that looks like-- Dialogue: 0,0:09:02.00,0:09:03.61,EN,,0,0,0,,Just looking at the bound variable list, Dialogue: 0,0:09:04.22,0:09:05.29,EN,,0,0,0,,it looks like this, Dialogue: 0,0:09:09.93,0:09:17.32,EN,,0,0,0,,x, y, z, and the empty thing. Dialogue: 0,0:09:18.28,0:09:21.08,EN,,0,0,0,,If I have a list of arguments I wish to match this against, Dialogue: 0,0:09:22.60,0:09:25.60,EN,,0,0,0,,I have a list of arguments one, two, three, Dialogue: 0,0:09:25.87,0:09:27.26,EN,,0,0,0,,I want to match these against. Dialogue: 0,0:09:28.38,0:09:37.10,EN,,0,0,0,,OK? So I might have here a list of three things, Dialogue: 0,0:09:42.44,0:09:46.94,EN,,0,0,0,,one, two, three. Dialogue: 0,0:09:48.99,0:09:53.16,EN,,0,0,0,,And I want to match x, y, z against one, two, three. Dialogue: 0,0:09:54.22,0:09:56.28,EN,,0,0,0,,Well, it's clear that the one matches the x, Dialogue: 0,0:09:56.32,0:09:58.01,EN,,0,0,0,,because I can just sort of follow the structure, Dialogue: 0,0:09:58.86,0:10:01.56,EN,,0,0,0,,and the two matches the y, Dialogue: 0,0:10:02.46,0:10:04.04,EN,,0,0,0,,and the three matches the z. Dialogue: 0,0:10:05.48,0:10:09.53,EN,,0,0,0,,But now, supposing I were to compare this x dot y. Dialogue: 0,0:10:09.55,0:10:11.84,EN,,0,0,0,,this is x dot y-- Dialogue: 0,0:10:12.51,0:10:16.91,EN,,0,0,0,,supposing I compare that with a list of three arguments, one, two, three. Dialogue: 0,0:10:19.08,0:10:20.00,EN,,0,0,0,,Let's look at that again. Dialogue: 0,0:10:28.00,0:10:30.32,EN,,0,0,0,,One, two, three-- Dialogue: 0,0:10:30.86,0:10:32.88,EN,,0,0,0,,Well, I can walk along here Dialogue: 0,0:10:32.99,0:10:35.50,EN,,0,0,0,,and say, oh yes, x matches the one, Dialogue: 0,0:10:37.56,0:10:41.84,EN,,0,0,0,,Ah, the y matches the list, which is two and three. Dialogue: 0,0:10:43.74,0:10:46.22,EN,,0,0,0,,So the notation I'm choosing here Dialogue: 0,0:10:46.41,0:10:50.16,EN,,0,0,0,,is one that's very natural for Lisp system. Dialogue: 0,0:10:52.66,0:10:54.14,EN,,0,0,0,,But I'm going to choose this as a notation Dialogue: 0,0:10:54.17,0:10:55.80,EN,,0,0,0,,for representing a bunch of arguments. Dialogue: 0,0:10:58.29,0:11:00.09,EN,,0,0,0,,Now, there's an alternative possibility. Dialogue: 0,0:11:00.59,0:11:02.78,EN,,0,0,0,,If I don't want to take one special out, Dialogue: 0,0:11:03.00,0:11:05.00,EN,,0,0,0,,or two special ones out or something like that, Dialogue: 0,0:11:06.54,0:11:07.56,EN,,0,0,0,,if I don't want to do that, Dialogue: 0,0:11:08.78,0:11:10.44,EN,,0,0,0,,if I want to talk about Dialogue: 0,0:11:10.52,0:11:12.52,EN,,0,0,0,,just the list of all the arguments like in addition, Dialogue: 0,0:11:13.88,0:11:17.96,EN,,0,0,0,,well then the argument list I'm going to choose to be Dialogue: 0,0:11:18.20,0:11:23.45,EN,,0,0,0,,that procedure of all the arguments x, which does something with x Dialogue: 0,0:11:25.14,0:11:26.30,EN,,0,0,0,,And which, for example, Dialogue: 0,0:11:26.81,0:11:27.96,EN,,0,0,0,,if I take the procedure, Dialogue: 0,0:11:28.06,0:11:30.44,EN,,0,0,0,,which takes all the arguments x Dialogue: 0,0:11:31.12,0:11:32.70,EN,,0,0,0,,and returned the list of them, Dialogue: 0,0:11:34.81,0:11:38.67,EN,,0,0,0,,OK? That's list. That's the procedure list. Dialogue: 0,0:11:45.85,0:11:46.67,EN,,0,0,0,,How does this work? Dialogue: 0,0:11:46.84,0:11:50.06,EN,,0,0,0,,Well, indeed what I had as the bound variable list in this case, Dialogue: 0,0:11:50.60,0:11:51.45,EN,,0,0,0,,whatever it is, Dialogue: 0,0:11:51.61,0:11:53.68,EN,,0,0,0,,is being matched against a list of arguments. Dialogue: 0,0:11:55.14,0:11:57.14,EN,,0,0,0,,This symbol now is all of the arguments. Dialogue: 0,0:12:01.49,0:12:05.13,EN,,0,0,0,,And so this is the choice I'm making for a particular syntactic specification, Dialogue: 0,0:12:05.64,0:12:07.63,EN,,0,0,0,,for the description of procedures Dialogue: 0,0:12:08.04,0:12:10.56,EN,,0,0,0,,which take indefinite numbers of arguments. Dialogue: 0,0:12:13.45,0:12:14.60,EN,,0,0,0,,There are two cases of it, Dialogue: 0,0:12:15.40,0:12:16.35,EN,,0,0,0,,this one and this one. Dialogue: 0,0:12:17.44,0:12:18.36,EN,,0,0,0,,And none of this. Dialogue: 0,0:12:18.42,0:12:20.11,EN,,0,0,0,,When you make syntactic specifications, Dialogue: 0,0:12:20.44,0:12:22.54,EN,,0,0,0,,it's important that it's unambiguous, Dialogue: 0,0:12:23.56,0:12:27.36,EN,,0,0,0,,that neither of these can be confused with Dialogue: 0,0:12:27.66,0:12:31.20,EN,,0,0,0,,a representation we already have, this one. Dialogue: 0,0:12:33.61,0:12:35.82,EN,,0,0,0,,I can always tell whether I have Dialogue: 0,0:12:36.54,0:12:39.80,EN,,0,0,0,,a fixed number of explicitly named arguments Dialogue: 0,0:12:40.28,0:12:41.76,EN,,0,0,0,,made by these formal parameters, Dialogue: 0,0:12:42.64,0:12:43.13,EN,,0,0,0,,or Dialogue: 0,0:12:43.28,0:12:45.36,EN,,0,0,0,,a fixed number of named formal parameters Dialogue: 0,0:12:45.44,0:12:48.01,EN,,0,0,0,,followed by a thing which picks up all the rest of them, Dialogue: 0,0:12:49.42,0:12:53.52,EN,,0,0,0,,or a list of all the arguments Dialogue: 0,0:12:53.68,0:12:56.52,EN,,0,0,0,,which will be matched against this particular formal parameter called x, Dialogue: 0,0:12:56.99,0:12:58.84,EN,,0,0,0,,because these are syntactically distinguishable. Dialogue: 0,0:13:02.25,0:13:04.62,EN,,0,0,0,,Many languages make terrible errors in that form Dialogue: 0,0:13:05.04,0:13:08.03,EN,,0,0,0,,where whole segments of interpretation are cut off, Dialogue: 0,0:13:08.64,0:13:13.92,EN,,0,0,0,,because there are syntactic ambiguities in the language. Dialogue: 0,0:13:14.56,0:13:16.67,EN,,0,0,0,,They are the traditional problems with ALGOL like languages Dialogue: 0,0:13:16.67,0:13:23.47,EN,,0,0,0,,having to do with the nesting of ifs in the predicate part. Dialogue: 0,0:13:25.06,0:13:25.93,EN,,0,0,0,,In any case, Dialogue: 0,0:13:27.52,0:13:29.44,EN,,0,0,0,,now, so I've told you about the syntax, Dialogue: 0,0:13:30.27,0:13:34.83,EN,,0,0,0,,now, what are we going to do about the semantics of this? Dialogue: 0,0:13:35.25,0:13:36.11,EN,,0,0,0,,How do we interpret it? Dialogue: 0,0:13:36.59,0:13:37.96,EN,,0,0,0,,Well this is just super easy. Dialogue: 0,0:13:38.44,0:13:42.57,EN,,0,0,0,,I'm going to modify the metacircular interpreter to do it. Dialogue: 0,0:13:43.71,0:13:44.76,EN,,0,0,0,,And that's a one liner. Dialogue: 0,0:13:45.98,0:13:46.57,EN,,0,0,0,,There it is. Dialogue: 0,0:13:47.53,0:13:49.56,EN,,0,0,0,,I'm changing the way you pair things up. Dialogue: 0,0:13:50.81,0:13:54.19,EN,,0,0,0,,OK? Here we have procedure that pairs -- Dialogue: 0,0:13:56.76,0:14:02.03,EN,,0,0,0,,Here's the procedure that pairs the Dialogue: 0,0:14:04.81,0:14:09.56,EN,,0,0,0,,the variables, the formal parameters, with the arguments that were passed Dialogue: 0,0:14:12.16,0:14:16.68,EN,,0,0,0,,from the last description of the metacircular interpreter. Dialogue: 0,0:14:18.96,0:14:21.93,EN,,0,0,0,,And here's some things that are the same as they were before. Dialogue: 0,0:14:22.67,0:14:23.23,EN,,0,0,0,,In other words, Dialogue: 0,0:14:23.31,0:14:25.07,EN,,0,0,0,,if the list of variables is empty, Dialogue: 0,0:14:25.52,0:14:27.31,EN,,0,0,0,,then if the list of values is empty, Dialogue: 0,0:14:27.45,0:14:29.61,EN,,0,0,0,,then I have an empty list. Dialogue: 0,0:14:31.05,0:14:33.00,EN,,0,0,0,,Otherwise, I have too many arguments, Dialogue: 0,0:14:33.98,0:14:40.19,EN,,0,0,0,,If I have, that is if I have empty variables but not empty values. Dialogue: 0,0:14:41.58,0:14:44.00,EN,,0,0,0,,If I have empty values, Dialogue: 0,0:14:44.96,0:14:47.47,EN,,0,0,0,,OK? But the variables are not empty, Dialogue: 0,0:14:47.48,0:14:48.56,EN,,0,0,0,,that I have too few arguments. Dialogue: 0,0:14:48.94,0:14:51.31,EN,,0,0,0,,However if I have a variable -- the variables are a symbol-- Dialogue: 0,0:14:55.53,0:14:56.49,EN,,0,0,0,,interesting case-- Dialogue: 0,0:14:58.30,0:15:04.40,EN,,0,0,0,,then, what I should do is say, oh yes, this is the special case Dialogue: 0,0:15:04.59,0:15:06.51,EN,,0,0,0,,that I have a symbolic tail. Dialogue: 0,0:15:08.35,0:15:14.11,EN,,0,0,0,,OK. I have here a thing just like we looked over here. Dialogue: 0,0:15:14.90,0:15:17.87,EN,,0,0,0,,This is a tail which is a symbol, y. Dialogue: 0,0:15:18.63,0:15:19.39,EN,,0,0,0,,It's not a nil. Dialogue: 0,0:15:20.73,0:15:21.72,EN,,0,0,0,,It's not the empty list. Dialogue: 0,0:15:23.26,0:15:25.60,EN,,0,0,0,,Here's a symbolic tail that is just the very beginning of the tail. Dialogue: 0,0:15:25.98,0:15:26.81,EN,,0,0,0,,There is nothing else. Dialogue: 0,0:15:27.79,0:15:28.72,EN,,0,0,0,,In that case, Dialogue: 0,0:15:29.96,0:15:37.20,EN,,0,0,0,,I wish to match that variable with all the values Dialogue: 0,0:15:38.03,0:15:42.52,EN,,0,0,0,,and add that to the pairing that I'm making. Dialogue: 0,0:15:44.50,0:15:46.91,EN,,0,0,0,,Otherwise, I go through the normal arrangement Dialogue: 0,0:15:47.15,0:15:48.52,EN,,0,0,0,,of making up the whole pairing. Dialogue: 0,0:15:52.02,0:15:53.82,EN,,0,0,0,,I suppose that's very simple. Dialogue: 0,0:15:54.51,0:15:55.84,EN,,0,0,0,,And that's all there is to it. Dialogue: 0,0:15:57.08,0:15:58.33,EN,,0,0,0,,And now I'll answer some questions. Dialogue: 0,0:16:02.62,0:16:05.05,EN,,0,0,0,,The first one-- Are there any questions? Dialogue: 0,0:16:06.60,0:16:06.94,EN,,0,0,0,,Yes? Dialogue: 0,0:16:07.37,0:16:09.92,EN,,0,0,0,,AUDIENCE: Could you explain that third form? Dialogue: 0,0:16:09.98,0:16:12.12,EN,,0,0,0,,PROFESSOR: Third form. This one? OK. Dialogue: 0,0:16:12.59,0:16:14.27,EN,,0,0,0,,Well, maybe we should look at the thing Dialogue: 0,0:16:14.30,0:16:16.24,EN,,0,0,0,,as a piece of list structure. Dialogue: 0,0:16:18.57,0:16:22.73,EN,,0,0,0,,This is a procedure which contains a lambda. Dialogue: 0,0:16:25.85,0:16:29.61,EN,,0,0,0,,I'm just looking at the list structure which represents this. Dialogue: 0,0:16:31.26,0:16:32.44,EN,,0,0,0,,Here's x. Dialogue: 0,0:16:32.73,0:16:33.98,EN,,0,0,0,,These are our symbols. Dialogue: 0,0:16:37.41,0:16:39.58,EN,,0,0,0,,And then the body is nothing but x. Dialogue: 0,0:16:44.84,0:16:48.75,EN,,0,0,0,,If I were looking for the bound variable list part of this procedure, Dialogue: 0,0:16:50.09,0:16:51.58,EN,,0,0,0,,I would go looking at the CADR, Dialogue: 0,0:16:52.14,0:16:53.16,EN,,0,0,0,,and I'd find a symbol. Dialogue: 0,0:16:54.01,0:16:57.16,EN,,0,0,0,,So the, matcher, which is this pairup thing I just showed you, Dialogue: 0,0:16:58.24,0:17:00.44,EN,,0,0,0,,is going to be matching a symbolic object Dialogue: 0,0:17:01.56,0:17:04.40,EN,,0,0,0,,against a list of arguments that were passed. Dialogue: 0,0:17:05.76,0:17:09.55,EN,,0,0,0,,And it will bind that symbol to the list of arguments. Dialogue: 0,0:17:11.37,0:17:16.48,EN,,0,0,0,,The -- In this case, if I'm looking for it, Dialogue: 0,0:17:16.92,0:17:20.97,EN,,0,0,0,,the match will be against this in the bound variable list position. Dialogue: 0,0:17:24.14,0:17:26.14,EN,,0,0,0,,Now, if what this does is Dialogue: 0,0:17:26.17,0:17:29.13,EN,,0,0,0,,it gets a list of arguments and returns it, that's list Dialogue: 0,0:17:30.40,0:17:31.39,EN,,0,0,0,,That's the procedure is. Dialogue: 0,0:17:34.51,0:17:35.48,EN,,0,0,0,,Oh well, thank you. Dialogue: 0,0:17:36.14,0:17:37.28,EN,,0,0,0,,Let's take a break. Dialogue: 0,0:17:37.83,0:17:55.36,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:17:55.36,0:17:59.02,EN,,0,0,0,, Dialogue: 0,0:18:03.53,0:18:07.56,EN,,0,0,0,, Dialogue: 0,0:18:07.56,0:18:11.69,EN,,0,0,0,, Dialogue: 0,0:18:12.25,0:18:16.11,EN,,0,0,0,, Dialogue: 0,0:18:20.86,0:18:21.61,EN,,0,0,0,,PROFESSOR: Well let's see. Dialogue: 0,0:18:23.26,0:18:26.32,EN,,0,0,0,,Now, I'm going to tell you about a rather more substantial variation Dialogue: 0,0:18:27.45,0:18:31.04,EN,,0,0,0,,one that's a famous variation Dialogue: 0,0:18:31.60,0:18:36.80,EN,,0,0,0,,hat many early Lisps had. Dialogue: 0,0:18:38.25,0:18:40.06,EN,,0,0,0,,It's called dynamic binding of variables. Dialogue: 0,0:18:41.77,0:18:44.68,EN,,0,0,0,,And we'll investigate a little bit about that right now. Dialogue: 0,0:18:47.62,0:18:50.16,EN,,0,0,0,,I'm going to first introduce this by showing you the sort of thing Dialogue: 0,0:18:50.35,0:18:52.36,EN,,0,0,0,,that would make someone want this idea. Dialogue: 0,0:18:53.74,0:18:55.23,EN,,0,0,0,,I'm not going to tell what it is yet, Dialogue: 0,0:18:55.40,0:18:57.60,EN,,0,0,0,,I'm going to show you why you might want it. Dialogue: 0,0:18:58.64,0:18:59.93,EN,,0,0,0,,Suppose, for example, Dialogue: 0,0:19:00.75,0:19:02.59,EN,,0,0,0,,we looked at the sum procedure again Dialogue: 0,0:19:05.02,0:19:06.43,EN,,0,0,0,,for summing up a bunch of things. Dialogue: 0,0:19:08.14,0:19:09.47,EN,,0,0,0,,To be that procedure, Dialogue: 0,0:19:09.60,0:19:10.78,EN,,0,0,0,,of a term, Dialogue: 0,0:19:13.04,0:19:14.41,EN,,0,0,0,,lower bound, Dialogue: 0,0:19:15.24,0:19:17.04,EN,,0,0,0,,method of computing the next index, Dialogue: 0,0:19:17.24,0:19:18.56,EN,,0,0,0,,and upper bound, Dialogue: 0,0:19:19.36,0:19:20.16,EN,,0,0,0,,such that, Dialogue: 0,0:19:23.16,0:19:26.94,EN,,0,0,0,,if a is greater than b Dialogue: 0,0:19:27.15,0:19:28.64,EN,,0,0,0,,then the result is 0, Dialogue: 0,0:19:30.24,0:19:31.08,EN,,0,0,0,,otherwise, Dialogue: 0,0:19:33.68,0:19:39.82,EN,,0,0,0,,it's the sum, of the term, procedure, applied to a Dialogue: 0,0:19:40.60,0:19:44.24,EN,,0,0,0,,and the result of adding up, terms, Dialogue: 0,0:19:47.68,0:19:52.64,EN,,0,0,0,,with the next a being the a, Dialogue: 0,0:20:00.30,0:20:03.56,EN,,0,0,0,,the next procedure passed along, Dialogue: 0,0:20:06.40,0:20:08.25,EN,,0,0,0,,and the upper bound being passed along. Dialogue: 0,0:20:14.51,0:20:15.76,EN,,0,0,0,,Blink, blink, blink-- Dialogue: 0,0:20:17.82,0:20:21.45,EN,,0,0,0,,OK? Now, when I use this sum procedure, Dialogue: 0,0:20:21.96,0:20:24.35,EN,,0,0,0,,I can use it, for example, like this. Dialogue: 0,0:20:25.45,0:20:38.04,EN,,0,0,0,,We can define the sum of the powers to be, Dialogue: 0,0:20:38.08,0:20:40.33,EN,,0,0,0,,for example, sum of a bunch of powers x to the n, Dialogue: 0,0:20:41.10,0:20:45.93,EN,,0,0,0,,to be that procedure of a, b, and n-- Dialogue: 0,0:20:45.95,0:20:47.69,EN,,0,0,0,,lower bound, the upper bound, and n-- Dialogue: 0,0:20:48.06,0:20:53.34,EN,,0,0,0,,which is sum, of lambda of x, Dialogue: 0,0:20:53.60,0:20:59.31,EN,,0,0,0,,the procedure of one argument x, which exponentiates x to the n, Dialogue: 0,0:21:02.19,0:21:09.29,EN,,0,0,0,,with the a, the incrementer, and b, being passed along. Dialogue: 0,0:21:11.82,0:21:15.76,EN,,0,0,0,,So we're adding up x to n, given an x. Dialogue: 0,0:21:16.14,0:21:19.74,EN,,0,0,0,,x takes on values from a to b, incrementing by one. Dialogue: 0,0:21:22.94,0:21:24.38,EN,,0,0,0,,I can also write the-- Dialogue: 0,0:21:27.68,0:21:28.20,EN,,0,0,0,,That's right. Dialogue: 0,0:21:29.78,0:21:31.02,EN,,0,0,0,,Product, excuse me. Dialogue: 0,0:21:31.91,0:21:33.36,EN,,0,0,0,,The product of a bunch of powers. Dialogue: 0,0:21:38.08,0:21:39.12,EN,,0,0,0,,It's a strange name. Dialogue: 0,0:21:40.02,0:21:40.80,EN,,0,0,0,,I'm going to leave it there. Dialogue: 0,0:21:41.96,0:21:46.32,EN,,0,0,0,,Weird-- OK? I write up what I have. Dialogue: 0,0:21:49.34,0:21:50.19,EN,,0,0,0,,I'm sure that's right. Dialogue: 0,0:21:51.37,0:21:53.82,EN,,0,0,0,,And if I want the product of a bunch of powers-- Dialogue: 0,0:21:58.41,0:22:02.36,EN,,0,0,0,,That was 12 brain cells, that double-take. Dialogue: 0,0:22:03.00,0:22:06.81,EN,,0,0,0,,I can for example use the procedure which is like sum, Dialogue: 0,0:22:06.81,0:22:08.22,EN,,0,0,0,,which is for making products, Dialogue: 0,0:22:08.56,0:22:11.05,EN,,0,0,0,,but it's similar to that, that you've seen before. Dialogue: 0,0:22:11.45,0:22:16.38,EN,,0,0,0,,There's a procedure of three arguments again. Dialogue: 0,0:22:17.00,0:22:25.42,EN,,0,0,0,,Which is the product of terms that are constructed, or factors in this case, Dialogue: 0,0:22:25.66,0:22:31.60,EN,,0,0,0,,constructed from exponentiating x to the n, Dialogue: 0,0:22:34.43,0:22:37.85,EN,,0,0,0,,where I start with a, I increment, and I go to b. Dialogue: 0,0:22:41.53,0:22:41.88,EN,,0,0,0,,Now, Dialogue: 0,0:22:46.83,0:22:49.50,EN,,0,0,0,,there's some sort of thing here that should disturb you immediately. Dialogue: 0,0:22:50.75,0:22:52.01,EN,,0,0,0,,These look the same. Dialogue: 0,0:22:53.18,0:22:55.20,EN,,0,0,0,,Why am I writing this code so many times? Dialogue: 0,0:22:56.59,0:22:59.72,EN,,0,0,0,,Here I am, in the same boat I've been in before. Dialogue: 0,0:23:01.00,0:23:03.15,EN,,0,0,0,,Right? Wouldn't it be nice to make an abstraction here? Dialogue: 0,0:23:03.81,0:23:05.76,EN,,0,0,0,,What's an example of a good abstraction to make? Dialogue: 0,0:23:05.85,0:23:07.55,EN,,0,0,0,,Well, I see some codes that's identical. Dialogue: 0,0:23:08.47,0:23:09.32,EN,,0,0,0,,Here's one, Dialogue: 0,0:23:09.98,0:23:11.08,EN,,0,0,0,,and here's another. Dialogue: 0,0:23:14.45,0:23:16.22,EN,,0,0,0,,And so maybe I should be able to pull that out. Dialogue: 0,0:23:17.09,0:23:19.23,EN,,0,0,0,,I should be able to say, oh yes, Dialogue: 0,0:23:20.51,0:23:22.67,EN,,0,0,0,,the sum of the powers could be written in terms of Dialogue: 0,0:23:22.88,0:23:24.52,EN,,0,0,0,,something called the nth power procedure. Dialogue: 0,0:23:25.71,0:23:27.40,EN,,0,0,0,,Imagine somebody wanted to write Dialogue: 0,0:23:27.74,0:23:30.03,EN,,0,0,0,,a slightly different procedure that looks like this. Dialogue: 0,0:23:37.63,0:23:45.18,EN,,0,0,0,,The sum powers to be a procedure Dialogue: 0,0:23:46.44,0:23:48.46,EN,,0,0,0,,of a, b, and n, Dialogue: 0,0:23:48.75,0:23:52.27,EN,,0,0,0,,which the result of summing up the nth power. Dialogue: 0,0:23:53.88,0:23:55.42,EN,,0,0,0,,We're going to give a name to that idea, Dialogue: 0,0:23:58.35,0:24:02.27,EN,,0,0,0,,for starting at a, going by one, and ending at b. Dialogue: 0,0:24:05.74,0:24:06.91,EN,,0,0,0,,And similarly, Dialogue: 0,0:24:10.65,0:24:12.76,EN,,0,0,0,,I might want to write the product powers this way, Dialogue: 0,0:24:12.89,0:24:15.24,EN,,0,0,0,,abstracting out this idea. Dialogue: 0,0:24:16.27,0:24:17.37,EN,,0,0,0,,I might want this. Dialogue: 0,0:24:22.10,0:24:23.02,EN,,0,0,0,,Product powers, Dialogue: 0,0:24:29.48,0:24:34.94,EN,,0,0,0,,to be a procedure of a, b, and n, Dialogue: 0,0:24:35.31,0:24:42.33,EN,,0,0,0,,which is the product of the nth power operation Dialogue: 0,0:24:46.44,0:24:50.30,EN,,0,0,0,,on a with the incrementation and b being Dialogue: 0,0:24:53.50,0:24:57.56,EN,,0,0,0,,being my arguments for the analogous-thing product. Dialogue: 0,0:24:58.38,0:25:00.24,EN,,0,0,0,,And I'd like to be able to define, Dialogue: 0,0:25:02.04,0:25:03.88,EN,,0,0,0,,I'd like to be able to define nth power-- Dialogue: 0,0:25:04.89,0:25:05.93,EN,,0,0,0,,I'll put it over here. Dialogue: 0,0:25:12.22,0:25:12.99,EN,,0,0,0,,I'll put it at the top. Dialogue: 0,0:25:25.41,0:25:29.04,EN,,0,0,0,,--to be, in fact, my procedure of one argument x Dialogue: 0,0:25:29.60,0:25:34.56,EN,,0,0,0,,which is the result of exponentiating x to the n. Dialogue: 0,0:25:35.93,0:25:36.96,EN,,0,0,0,,But I have a problem. Dialogue: 0,0:25:38.64,0:25:39.93,EN,,0,0,0,,My environment model, Dialogue: 0,0:25:40.57,0:25:43.23,EN,,0,0,0,,that is my means of interpretation Dialogue: 0,0:25:44.00,0:25:45.95,EN,,0,0,0,,of interpretation for the language that we've defined so far, Dialogue: 0,0:25:46.27,0:25:48.81,EN,,0,0,0,,does not give me a meaning for this n. Dialogue: 0,0:25:52.76,0:25:59.26,EN,,0,0,0,,Because, as you know, the, as you know Dialogue: 0,0:26:00.76,0:26:04.25,EN,,0,0,0,,this n is free in this procedure. Dialogue: 0,0:26:06.41,0:26:07.98,EN,,0,0,0,,The environment model tells us Dialogue: 0,0:26:08.60,0:26:10.20,EN,,0,0,0,,that the meaning of a free variable Dialogue: 0,0:26:11.21,0:26:14.99,EN,,0,0,0,,is determined in the environment in which this procedure is defined. Dialogue: 0,0:26:16.64,0:26:17.47,EN,,0,0,0,,In a way I have written it, Dialogue: 0,0:26:17.48,0:26:19.84,EN,,0,0,0,,assuming these things are defined on the blackboard as is, Dialogue: 0,0:26:21.64,0:26:23.63,EN,,0,0,0,,this is defined in the global environment, Dialogue: 0,0:26:24.06,0:26:25.15,EN,,0,0,0,,where there is no n. Dialogue: 0,0:26:25.93,0:26:27.63,EN,,0,0,0,,Therefore, n is unbound variable. Dialogue: 0,0:26:28.72,0:26:31.66,EN,,0,0,0,,But it's perfectly clear, to most of us, Dialogue: 0,0:26:32.60,0:26:36.32,EN,,0,0,0,,that we would like it to be this n and this n. Dialogue: 0,0:26:38.99,0:26:42.67,EN,,0,0,0,,On the other hand, OK, it would be nice. Dialogue: 0,0:26:42.84,0:26:44.28,EN,,0,0,0,,Certainly we've got to be careful here Dialogue: 0,0:26:44.56,0:26:46.06,EN,,0,0,0,,of keeping this to be this, Dialogue: 0,0:26:48.96,0:26:52.83,EN,,0,0,0,,and this one over here, wherever it is to be this one. Dialogue: 0,0:26:57.39,0:26:59.74,EN,,0,0,0,,Well, the desire to make this work Dialogue: 0,0:27:00.67,0:27:02.72,EN,,0,0,0,,has led to a very famous bug. Dialogue: 0,0:27:04.65,0:27:06.04,EN,,0,0,0,,I'll tell you about the famous bug. Dialogue: 0,0:27:07.15,0:27:09.40,EN,,0,0,0,,Look at this slide. Dialogue: 0,0:27:10.66,0:27:12.70,EN,,0,0,0,,This is an idea called dynamic binding. Dialogue: 0,0:27:13.99,0:27:16.91,EN,,0,0,0,,Where, instead of the free variable being interpreted Dialogue: 0,0:27:17.76,0:27:21.23,EN,,0,0,0,,in the environment of definition of a procedure, Dialogue: 0,0:27:22.40,0:27:25.16,EN,,0,0,0,,the free variable is interpreted as having its value Dialogue: 0,0:27:25.44,0:27:29.31,EN,,0,0,0,,in the environment of the caller of the procedure. Dialogue: 0,0:27:31.85,0:27:34.84,EN,,0,0,0,,So what you have is a system Dialogue: 0,0:27:34.86,0:27:39.68,EN,,0,0,0,,where you search up the chain of callers of a particular procedure, Dialogue: 0,0:27:40.43,0:27:42.65,EN,,0,0,0,,and, of course, in this case, Dialogue: 0,0:27:42.84,0:27:44.30,EN,,0,0,0,,since nth power is called Dialogue: 0,0:27:44.33,0:27:45.98,EN,,0,0,0,,from inside product whatever it is-- Dialogue: 0,0:27:46.41,0:27:48.68,EN,,0,0,0,,I had to write our own sum which is the analogous procedure-- Dialogue: 0,0:27:50.51,0:27:54.92,EN,,0,0,0,,and product is presumably called from product powers, Dialogue: 0,0:27:55.13,0:27:56.14,EN,,0,0,0,,as you see over here, Dialogue: 0,0:27:56.83,0:27:59.37,EN,,0,0,0,,then since product powers bind with variable n , Dialogue: 0,0:28:00.09,0:28:04.09,EN,,0,0,0,,then nth powers n would be derived through that chain. Dialogue: 0,0:28:08.14,0:28:09.64,EN,,0,0,0,,Similarly, this n, Dialogue: 0,0:28:10.11,0:28:12.01,EN,,0,0,0,,the nth power in n in this case, Dialogue: 0,0:28:12.32,0:28:15.80,EN,,0,0,0,,would come through nth power here being called from inside sum. Dialogue: 0,0:28:15.80,0:28:18.27,EN,,0,0,0,,You can see it being called from inside sum here. Dialogue: 0,0:28:20.73,0:28:21.69,EN,,0,0,0,,It's called term here. Dialogue: 0,0:28:22.90,0:28:25.72,EN,,0,0,0,,But sum was called from inside of sum powers, Dialogue: 0,0:28:26.94,0:28:27.96,EN,,0,0,0,,which bound n. Dialogue: 0,0:28:28.93,0:28:30.65,EN,,0,0,0,,Therefore, there would be an n available Dialogue: 0,0:28:32.75,0:28:36.11,EN,,0,0,0,,that n to get it's value from. Dialogue: 0,0:28:37.95,0:28:39.24,EN,,0,0,0,,This is called dynamic -- Dialogue: 0,0:28:39.28,0:28:43.10,EN,,0,0,0,,What we have below this white line plus over here Dialogue: 0,0:28:43.31,0:28:46.04,EN,,0,0,0,,is what's called a dynamic binding view of the world. Dialogue: 0,0:28:46.59,0:28:49.00,EN,,0,0,0,,If that works, that's a dynamic binding view. Dialogue: 0,0:28:50.85,0:28:52.65,EN,,0,0,0,,Now, let's take a look, for example, Dialogue: 0,0:28:54.54,0:28:55.99,EN,,0,0,0,,at just what it takes to implement that. Dialogue: 0,0:28:55.99,0:28:56.96,EN,,0,0,0,,That's real easy. Dialogue: 0,0:28:57.48,0:28:59.34,EN,,0,0,0,,In fact, the very first Lisps Dialogue: 0,0:29:00.01,0:29:02.52,EN,,0,0,0,,had any form of interpretations of the free variables at all, Dialogue: 0,0:29:03.31,0:29:05.98,EN,,0,0,0,,had dynamic binding interpretations for the free variables. Dialogue: 0,0:29:06.40,0:29:10.14,EN,,0,0,0,,APL has dynamic binding interpretation for the free variables, Dialogue: 0,0:29:11.68,0:29:14.32,EN,,0,0,0,,not lexical or static binding. Dialogue: 0,0:29:15.22,0:29:17.00,EN,,0,0,0,,So, of course, the change is in eval. Dialogue: 0,0:29:19.31,0:29:20.59,EN,,0,0,0,,And it's really in two places. Dialogue: 0,0:29:22.78,0:29:25.61,EN,,0,0,0,,First of all, one thing we see, Dialogue: 0,0:29:26.52,0:29:28.49,EN,,0,0,0,,is that things become a little simpler. Dialogue: 0,0:29:29.39,0:29:33.63,EN,,0,0,0,,If I don't have to have the -- If I don't have to have the Dialogue: 0,0:29:33.64,0:29:36.20,EN,,0,0,0,,environment be the environment of definition for procedure, Dialogue: 0,0:29:36.44,0:29:38.04,EN,,0,0,0,,the procedure need not capture Dialogue: 0,0:29:38.43,0:29:40.17,EN,,0,0,0,,the environment at the time it's defined. Dialogue: 0,0:29:42.03,0:29:44.96,EN,,0,0,0,,And so if we look here at this slide, Dialogue: 0,0:29:45.84,0:29:50.08,EN,,0,0,0,,we see that the clause for a lambda expression, Dialogue: 0,0:29:50.73,0:29:52.43,EN,,0,0,0,,which is the way a procedure is defined, Dialogue: 0,0:29:53.92,0:29:56.73,EN,,0,0,0,,does not make up a thing which has a type closure Dialogue: 0,0:29:56.75,0:30:01.05,EN,,0,0,0,,and a attached environment structure. Dialogue: 0,0:30:01.29,0:30:02.54,EN,,0,0,0,,It's just the expression itself. Dialogue: 0,0:30:02.54,0:30:04.76,EN,,0,0,0,,And we'll decompose that some other way somewhere else. Dialogue: 0,0:30:06.44,0:30:09.40,EN,,0,0,0,,The other thing we see is the applicator Dialogue: 0,0:30:10.36,0:30:13.69,EN,,0,0,0,,applicator must be able to get the environment of the caller. Dialogue: 0,0:30:14.29,0:30:17.24,EN,,0,0,0,,The caller of a procedure is right here. Dialogue: 0,0:30:17.26,0:30:19.45,EN,,0,0,0,,If the procedure is a application-- Dialogue: 0,0:30:19.56,0:30:21.63,EN,,0,0,0,,If the expression we're evaluating is a combination, Dialogue: 0,0:30:21.79,0:30:23.71,EN,,0,0,0,,then we're going to call a combination Dialogue: 0,0:30:23.93,0:30:25.50,EN,,0,0,0,,then we're going to call a procedure Dialogue: 0,0:30:25.66,0:30:27.37,EN,,0,0,0,,which is the value of the operator. Dialogue: 0,0:30:29.84,0:30:31.44,EN,,0,0,0,,The environment of the caller Dialogue: 0,0:30:31.98,0:30:34.51,EN,,0,0,0,,is the environment we have right here, available now. Dialogue: 0,0:30:35.89,0:30:40.72,EN,,0,0,0,,So all I have to do is pass that environment to the applicator, to apply. Dialogue: 0,0:30:41.49,0:30:42.75,EN,,0,0,0,,And if we look at that here, Dialogue: 0,0:30:43.58,0:30:44.97,EN,,0,0,0,,the only change we have to make Dialogue: 0,0:30:45.71,0:30:48.41,EN,,0,0,0,,is that fellow takes that environment Dialogue: 0,0:30:48.78,0:30:55.68,EN,,0,0,0,,uses that environment for the purpose of extending that environment Dialogue: 0,0:30:56.67,0:30:59.02,EN,,0,0,0,,when abiding the formal parameters Dialogue: 0,0:30:59.02,0:31:01.37,EN,,0,0,0,,of the procedure to the arguments that were passed, Dialogue: 0,0:31:03.08,0:31:05.98,EN,,0,0,0,,not an environment that was captured in the procedure. Dialogue: 0,0:31:06.81,0:31:09.45,EN,,0,0,0,,The reason why the first Lisps were implemented this way, Dialogue: 0,0:31:09.66,0:31:11.96,EN,,0,0,0,,is the sort of the obvious, accidental implementation. Dialogue: 0,0:31:14.13,0:31:16.68,EN,,0,0,0,,And, of course, as usual, people got used to it and liked it. Dialogue: 0,0:31:17.25,0:31:18.27,EN,,0,0,0,,And there were some people said, Dialogue: 0,0:31:18.40,0:31:19.50,EN,,0,0,0,,this is the way to do it. Dialogue: 0,0:31:21.59,0:31:24.09,EN,,0,0,0,,Unfortunately that causes some serious problems. Dialogue: 0,0:31:25.40,0:31:27.24,EN,,0,0,0,,The most important, serious problem Dialogue: 0,0:31:27.53,0:31:29.84,EN,,0,0,0,,in using dynamic binding Dialogue: 0,0:31:31.00,0:31:33.56,EN,,0,0,0,,is there's a modularity crisis that's involved it. Dialogue: 0,0:31:35.46,0:31:37.66,EN,,0,0,0,,If two people are working together on some big system, Dialogue: 0,0:31:38.57,0:31:40.01,EN,,0,0,0,,then an important thing to one Dialogue: 0,0:31:40.35,0:31:42.19,EN,,0,0,0,,is that the names used by each one Dialogue: 0,0:31:42.99,0:31:44.58,EN,,0,0,0,,don't interfere with the names of the other. Dialogue: 0,0:31:47.93,0:31:50.78,EN,,0,0,0,,It's important that when I invent some segment of code Dialogue: 0,0:31:51.07,0:31:53.13,EN,,0,0,0,,that no one can make my code stop working Dialogue: 0,0:31:53.88,0:31:56.57,EN,,0,0,0,,by using my names that I use internal to my code, Dialogue: 0,0:31:56.75,0:31:57.71,EN,,0,0,0,,internal to his code. Dialogue: 0,0:31:59.85,0:32:00.46,EN,,0,0,0,,However, Dialogue: 0,0:32:01.04,0:32:05.18,EN,,0,0,0,,dynamic binding violates that particular modularity constraint in a clear way. Dialogue: 0,0:32:06.67,0:32:08.08,EN,,0,0,0,,Consider, for example, Dialogue: 0,0:32:09.18,0:32:10.35,EN,,0,0,0,,what happens over here. Dialogue: 0,0:32:12.54,0:32:13.79,EN,,0,0,0,,Suppose it was the case Dialogue: 0,0:32:15.47,0:32:19.81,EN,,0,0,0,,that I decided to change the word next. Dialogue: 0,0:32:19.81,0:32:24.41,EN,,0,0,0,,Supposing somebody is writing, somebody is writing sum, Dialogue: 0,0:32:25.10,0:32:26.68,EN,,0,0,0,,and somebody else is going to use sum. Dialogue: 0,0:32:28.97,0:32:30.32,EN,,0,0,0,,The writer of sum Dialogue: 0,0:32:30.49,0:32:32.30,EN,,0,0,0,,has a choice of what names he may use. Dialogue: 0,0:32:33.66,0:32:34.84,EN,,0,0,0,,Let's say, I'm that writer. Dialogue: 0,0:32:36.83,0:32:39.30,EN,,0,0,0,,Well, by gosh, just happens I didn't want to call this next. Dialogue: 0,0:32:39.30,0:32:40.09,EN,,0,0,0,,I called it n. Dialogue: 0,0:32:41.74,0:32:43.10,EN,,0,0,0,,So all places where you see next, Dialogue: 0,0:32:44.28,0:32:45.26,EN,,0,0,0,,I called it n. Dialogue: 0,0:32:48.14,0:32:48.48,EN,,0,0,0,,Whoops. Dialogue: 0,0:32:49.94,0:32:52.22,EN,,0,0,0,,I changed nothing about the specifications of this program, Dialogue: 0,0:32:53.32,0:32:54.86,EN,,0,0,0,,but this program stops working. Dialogue: 0,0:32:56.11,0:32:57.96,EN,,0,0,0,,Not only that, unfortunately, this one does too. Dialogue: 0,0:32:59.50,0:33:01.40,EN,,0,0,0,,Why do these programs stop working? Dialogue: 0,0:33:02.26,0:33:03.24,EN,,0,0,0,,Well, it's sort of clear. Dialogue: 0,0:33:04.48,0:33:09.29,EN,,0,0,0,,Instead of chasing out the value of the n Dialogue: 0,0:33:09.31,0:33:13.72,EN,,0,0,0,,that occurs in nth power over here or over here, Dialogue: 0,0:33:14.97,0:33:17.16,EN,,0,0,0,,through the environment of definition, Dialogue: 0,0:33:17.20,0:33:19.58,EN,,0,0,0,,where this one is always linked to this one, Dialogue: 0,0:33:19.87,0:33:21.48,EN,,0,0,0,,if it was through the environment of definition, Dialogue: 0,0:33:21.55,0:33:23.63,EN,,0,0,0,,because here is the definition. Dialogue: 0,0:33:24.37,0:33:26.25,EN,,0,0,0,,This lambda expression was executed Dialogue: 0,0:33:26.59,0:33:28.59,EN,,0,0,0,,in the environment where that n was defined. Dialogue: 0,0:33:30.70,0:33:31.84,EN,,0,0,0,,If instead of doing that, Dialogue: 0,0:33:32.01,0:33:33.68,EN,,0,0,0,,I have to chase through the call chain, Dialogue: 0,0:33:34.78,0:33:36.27,EN,,0,0,0,,then look what horrible thing happens. Dialogue: 0,0:33:37.32,0:33:41.18,EN,,0,0,0,,Well, this was called from inside sum as term, term a. Dialogue: 0,0:33:41.76,0:33:42.38,EN,,0,0,0,,term a. Dialogue: 0,0:33:44.78,0:33:46.19,EN,,0,0,0,,I'm looking for a value of n. Dialogue: 0,0:33:47.35,0:33:48.40,EN,,0,0,0,,Instead of getting this one, Dialogue: 0,0:33:48.84,0:33:49.76,EN,,0,0,0,,I get that one. Dialogue: 0,0:33:50.70,0:33:52.54,EN,,0,0,0,,So by changing the insides of this program, Dialogue: 0,0:33:52.86,0:33:54.09,EN,,0,0,0,,this program stops working. Dialogue: 0,0:33:56.77,0:34:00.08,EN,,0,0,0,,So I no longer have a quantifier, as I described before. Dialogue: 0,0:34:01.12,0:34:05.13,EN,,0,0,0,,Which is a symbol -- The lambda symbol is supposed to be a quantifier. Dialogue: 0,0:34:05.43,0:34:06.70,EN,,0,0,0,,A thing which has the property Dialogue: 0,0:34:06.89,0:34:11.42,EN,,0,0,0,,that the names that are bound by it are unimportant, Dialogue: 0,0:34:12.65,0:34:15.71,EN,,0,0,0,,that I can uniformly substitute any names for these Dialogue: 0,0:34:16.92,0:34:19.98,EN,,0,0,0,,throughout this thing, so long as they don't occur in here, the new names, Dialogue: 0,0:34:20.94,0:34:23.16,EN,,0,0,0,,and the meaning of this expression should remain unchanged. Dialogue: 0,0:34:24.04,0:34:25.50,EN,,0,0,0,,I've just changed the meaning of the expression Dialogue: 0,0:34:25.53,0:34:27.20,EN,,0,0,0,,by changing the one of the names. Dialogue: 0,0:34:28.69,0:34:30.89,EN,,0,0,0,,So lambda is no longer a well defined idea. Dialogue: 0,0:34:32.17,0:34:33.37,EN,,0,0,0,,It's a very serious problem. Dialogue: 0,0:34:34.55,0:34:35.55,EN,,0,0,0,,So for that reason, Dialogue: 0,0:34:36.64,0:34:42.51,EN,,0,0,0,,I and my buddies have given up this particular kind of abstraction, Dialogue: 0,0:34:43.13,0:34:44.36,EN,,0,0,0,,which I would like to have, Dialogue: 0,0:34:45.61,0:34:47.50,EN,,0,0,0,,in favor of a modularity principle. Dialogue: 0,0:34:48.09,0:34:50.20,EN,,0,0,0,,But this is the kind of experiment you can do Dialogue: 0,0:34:51.96,0:34:53.68,EN,,0,0,0,,if you want to play with these interpreters. Dialogue: 0,0:34:54.83,0:34:56.91,EN,,0,0,0,,You can try them out this way, that way, and the other way. Dialogue: 0,0:34:58.11,0:35:00.25,EN,,0,0,0,,You see what makes a nicer language. Dialogue: 0,0:35:02.68,0:35:04.49,EN,,0,0,0,,So that's a very important thing to be able to do. Dialogue: 0,0:35:04.99,0:35:06.68,EN,,0,0,0,,Now, I would like to give you a feeling Dialogue: 0,0:35:06.72,0:35:08.49,EN,,0,0,0,,for I think the right thing to do is here. Dialogue: 0,0:35:09.32,0:35:12.91,EN,,0,0,0,,How are you going to, how are you going to I get this kind of Dialogue: 0,0:35:13.04,0:35:15.34,EN,,0,0,0,,of power in a lexical system? Dialogue: 0,0:35:16.28,0:35:17.39,EN,,0,0,0,,And the answer is, of course, Dialogue: 0,0:35:17.55,0:35:20.03,EN,,0,0,0,,what I really want is a something that makes up for me Dialogue: 0,0:35:20.68,0:35:22.60,EN,,0,0,0,,an exponentiator for a particular n. Dialogue: 0,0:35:23.69,0:35:24.28,EN,,0,0,0,,Given an n, Dialogue: 0,0:35:24.32,0:35:25.66,EN,,0,0,0,,it will make me an exponentiator. Dialogue: 0,0:35:26.28,0:35:27.40,EN,,0,0,0,,Oh, but that's easy too. Dialogue: 0,0:35:28.17,0:35:30.57,EN,,0,0,0,,In other words, I can write my program this way. Dialogue: 0,0:35:35.84,0:35:37.84,EN,,0,0,0,,I'm going to define a thing called PGEN, Dialogue: 0,0:35:40.25,0:35:42.54,EN,,0,0,0,,which is a procedure of n Dialogue: 0,0:35:43.16,0:35:45.95,EN,,0,0,0,,which produces for me an exponentiator. Dialogue: 0,0:35:50.24,0:35:51.23,EN,,0,0,0,,--x to the n. Dialogue: 0,0:35:56.80,0:35:57.98,EN,,0,0,0,,Given that I have that, Dialogue: 0,0:35:58.59,0:36:00.88,EN,,0,0,0,,then I can capture the abstraction I wanted Dialogue: 0,0:36:01.42,0:36:03.93,EN,,0,0,0,,even better, because now it's encapsulated in a way Dialogue: 0,0:36:04.09,0:36:06.60,EN,,0,0,0,,where I can't be destroyed by a change of names. Dialogue: 0,0:36:07.89,0:36:12.35,EN,,0,0,0,,I can define some powers Dialogue: 0,0:36:17.28,0:36:20.70,EN,,0,0,0,,I can define some powers to be a procedure again of a, b, and n Dialogue: 0,0:36:21.61,0:36:26.83,EN,,0,0,0,,which is the sum of the term function Dialogue: 0,0:36:26.88,0:36:32.32,EN,,0,0,0,,generated by using this generator, PGEN, n, Dialogue: 0,0:36:34.40,0:36:38.01,EN,,0,0,0,,with a, incrementer, and b. Dialogue: 0,0:36:42.49,0:36:47.95,EN,,0,0,0,,And I can define the product of powers Dialogue: 0,0:36:54.11,0:36:58.84,EN,,0,0,0,,to be a procedure of a, b, and n Dialogue: 0,0:36:59.80,0:37:09.96,EN,,0,0,0,,which is the product PGEN, n, with a, increment, and b. Dialogue: 0,0:37:11.28,0:37:13.28,EN,,0,0,0,,Now, of course, this is a very simple example Dialogue: 0,0:37:13.60,0:37:16.35,EN,,0,0,0,,where this object that I'm trying to abstract over is small. Dialogue: 0,0:37:17.28,0:37:18.83,EN,,0,0,0,,But it could be a 100 lines of code. Dialogue: 0,0:37:20.10,0:37:23.67,EN,,0,0,0,,And so, the purpose of this is, of course, to make it simple. Dialogue: 0,0:37:23.67,0:37:24.57,EN,,0,0,0,,I'd give a name to it, Dialogue: 0,0:37:24.73,0:37:26.94,EN,,0,0,0,,it's just that here it's a parameterized name. Dialogue: 0,0:37:28.20,0:37:30.27,EN,,0,0,0,,It's a name that depends upon, explicitly, Dialogue: 0,0:37:30.49,0:37:33.63,EN,,0,0,0,,the lexically apparent value of n. Dialogue: 0,0:37:37.13,0:37:38.59,EN,,0,0,0,,So you can think of this as a long name. Dialogue: 0,0:37:40.21,0:37:41.58,EN,,0,0,0,,And here, I've solved my problem Dialogue: 0,0:37:41.76,0:37:45.82,EN,,0,0,0,,by naming my... by naming the term generation Dialogue: 0,0:37:46.12,0:37:49.22,EN,,0,0,0,,procedures within an n in them. Dialogue: 0,0:37:55.08,0:37:55.87,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:37:57.00,0:37:58.38,EN,,0,0,0,,Oh, yes, David. Dialogue: 0,0:37:58.57,0:38:02.27,EN,,0,0,0,,AUDIENCE: Is the only solution to um... Dialogue: 0,0:38:03.07,0:38:06.46,EN,,0,0,0,,the problem you raise to create another procedure? Dialogue: 0,0:38:06.47,0:38:08.92,EN,,0,0,0,,In other words, can this only work in languages that are Dialogue: 0,0:38:08.99,0:38:11.56,EN,,0,0,0,,capable of defining objects as procedures? Dialogue: 0,0:38:12.41,0:38:13.76,EN,,0,0,0,,PROFESSOR: Oh, I see. Dialogue: 0,0:38:15.90,0:38:19.74,EN,,0,0,0,,My solution to making this abstraction, Dialogue: 0,0:38:20.14,0:38:22.86,EN,,0,0,0,,when I didn't want include the procedure inside the body, Dialogue: 0,0:38:23.26,0:38:26.81,EN,,0,0,0,,depends upon my ability to return a procedure or export one. Dialogue: 0,0:38:27.04,0:38:27.24,EN,,0,0,0,,AUDIENCE: And that's right. Dialogue: 0,0:38:28.19,0:38:28.88,EN,,0,0,0,,PROFESSOR: And that's right. Dialogue: 0,0:38:29.53,0:38:31.52,EN,,0,0,0,,If I don't have that, Dialogue: 0,0:38:32.24,0:38:35.13,EN,,0,0,0,,then I just don't have this ability to make an abstraction in a way Dialogue: 0,0:38:35.53,0:38:41.77,EN,,0,0,0,,where I don't have possibilities of symbol conflicts that were unanticipated. Dialogue: 0,0:38:43.00,0:38:43.48,EN,,0,0,0,,That's right. Dialogue: 0,0:38:44.14,0:38:46.51,EN,,0,0,0,,So one of the, the essential -- I consider, I consider Dialogue: 0,0:38:46.54,0:38:48.91,EN,,0,0,0,,being able to return the procedural value and, therefore, Dialogue: 0,0:38:49.20,0:38:58.28,EN,,0,0,0,,and therefore, to sort of have first class procedures, in general, Dialogue: 0,0:38:59.13,0:39:02.46,EN,,0,0,0,,as being essential to doing very good modular programming. Dialogue: 0,0:39:03.70,0:39:06.43,EN,,0,0,0,,Now, indeed there are many other ways to skin this cat. Dialogue: 0,0:39:07.44,0:39:09.16,EN,,0,0,0,,What you can do is take for each of the Dialogue: 0,0:39:09.18,0:39:11.84,EN,,0,0,0,,for each of the bad things that you have to worry about, Dialogue: 0,0:39:12.27,0:39:15.20,EN,,0,0,0,,you can make a special feature that covers that thing. Dialogue: 0,0:39:15.84,0:39:17.12,EN,,0,0,0,,You can make a package system. Dialogue: 0,0:39:17.74,0:39:21.16,EN,,0,0,0,,You can make a module system as in Ada, et cetera. OK? Dialogue: 0,0:39:22.24,0:39:24.88,EN,,0,0,0,,And all of those work, or they cover little regions of it. Dialogue: 0,0:39:26.44,0:39:28.38,EN,,0,0,0,,The thing is that returning procedures as values Dialogue: 0,0:39:28.41,0:39:29.74,EN,,0,0,0,,cover all of those problems. Dialogue: 0,0:39:32.68,0:39:34.60,EN,,0,0,0,,And so it's the simplest mechanism Dialogue: 0,0:39:35.58,0:39:37.79,EN,,0,0,0,,that gives you the best modularity, Dialogue: 0,0:39:39.21,0:39:41.31,EN,,0,0,0,,gives you all of the known modularity mechanisms. Dialogue: 0,0:39:45.59,0:39:48.24,EN,,0,0,0,,Well, I suppose it's time for the next break, thank you. Dialogue: 0,0:39:48.24,0:40:01.08,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:40:01.28,0:40:04.75,EN,,0,0,0,, Dialogue: 0,0:40:25.69,0:40:29.42,EN,,0,0,0,, Dialogue: 0,0:40:30.01,0:40:33.28,EN,,0,0,0,, Dialogue: 0,0:40:34.17,0:40:37.61,EN,,0,0,0,, Dialogue: 0,0:40:42.32,0:40:44.28,EN,,0,0,0,,PROFESSOR: Well, yesterday when you learned about streams, Dialogue: 0,0:40:46.01,0:40:51.16,EN,,0,0,0,,Hal worried to you about the order of evaluation Dialogue: 0,0:40:51.95,0:40:53.87,EN,,0,0,0,,and delayed arguments to procedures. Dialogue: 0,0:40:55.61,0:40:58.30,EN,,0,0,0,,The way we played with streams yesterday, Dialogue: 0,0:41:00.25,0:41:04.22,EN,,0,0,0,,it was the responsibility of the caller and the callee Dialogue: 0,0:41:05.77,0:41:08.84,EN,,0,0,0,,both agree that an argument was delayed, Dialogue: 0,0:41:09.42,0:41:13.44,EN,,0,0,0,,and the callee must force the argument if it needs the answer. Dialogue: 0,0:41:15.13,0:41:17.87,EN,,0,0,0,,So there had to be a lot of hand shaking between Dialogue: 0,0:41:18.17,0:41:24.32,EN,,0,0,0,,the designer of a procedure and user of it over delayedness. Dialogue: 0,0:41:26.36,0:41:28.72,EN,,0,0,0,,That turns out, of course, to be a fairly bad thing, Dialogue: 0,0:41:29.48,0:41:30.96,EN,,0,0,0,,it works all right with streams. Dialogue: 0,0:41:31.74,0:41:32.86,EN,,0,0,0,,But as a general thing, Dialogue: 0,0:41:32.92,0:41:36.32,EN,,0,0,0,,what you want is an idea to have a locus, Dialogue: 0,0:41:36.46,0:41:38.49,EN,,0,0,0,,a decision, a design decision in general, Dialogue: 0,0:41:38.89,0:41:41.28,EN,,0,0,0,,to have a place where it's made, explicitly, Dialogue: 0,0:41:41.63,0:41:43.93,EN,,0,0,0,,and notated in a clear way. Dialogue: 0,0:41:45.88,0:41:49.28,EN,,0,0,0,,And so it's not a very good idea to have to have an agreement, Dialogue: 0,0:41:50.46,0:41:54.89,EN,,0,0,0,,between the person who writes a procedure and the person who calls it, Dialogue: 0,0:41:55.08,0:41:57.98,EN,,0,0,0,,about such details as, maybe, the arguments of evaluation, Dialogue: 0,0:41:58.43,0:41:59.50,EN,,0,0,0,,the order of evaluation. Dialogue: 0,0:41:59.50,0:42:00.75,EN,,0,0,0,,Although, that's not so bad. Dialogue: 0,0:42:01.02,0:42:03.95,EN,,0,0,0,,I mean, we have other such agreements like, the input's a number. Dialogue: 0,0:42:05.20,0:42:06.08,EN,,0,0,0,,But it would be nice if Dialogue: 0,0:42:06.35,0:42:09.20,EN,,0,0,0,,one of these guys could take responsibility, completely. Dialogue: 0,0:42:11.02,0:42:13.31,EN,,0,0,0,,Now this is not a new idea. Dialogue: 0,0:42:15.51,0:42:21.16,EN,,0,0,0,,ALGOL 60 had two different ways of calling a procedure. Dialogue: 0,0:42:22.02,0:42:24.28,EN,,0,0,0,,The arguments could be passed by name or by value. Dialogue: 0,0:42:25.59,0:42:27.48,EN,,0,0,0,,And what that meant was that Dialogue: 0,0:42:27.63,0:42:29.72,EN,,0,0,0,,a name argument was delayed. Dialogue: 0,0:42:31.11,0:42:32.84,EN,,0,0,0,,That when you passed an argument by name, Dialogue: 0,0:42:33.64,0:42:36.52,EN,,0,0,0,,that its value would only be obtained Dialogue: 0,0:42:36.96,0:42:39.55,EN,,0,0,0,,if you accessed that argument. Dialogue: 0,0:42:42.29,0:42:44.20,EN,,0,0,0,,So what I'd like to do now is show you, Dialogue: 0,0:42:44.43,0:42:46.96,EN,,0,0,0,,first of all, a little bit about, again, Dialogue: 0,0:42:46.99,0:42:48.65,EN,,0,0,0,,we're going to make a modification to a language. Dialogue: 0,0:42:50.32,0:42:51.79,EN,,0,0,0,,In this case, we're going to add a feature. Dialogue: 0,0:42:53.37,0:42:55.05,EN,,0,0,0,,We're going to add the feature of, Dialogue: 0,0:42:55.36,0:42:58.73,EN,,0,0,0,,by name parameters, if you will, or delayed parameters. Dialogue: 0,0:43:00.43,0:43:04.41,EN,,0,0,0,,Because, in fact, the default in our Lisp system Dialogue: 0,0:43:04.76,0:43:06.60,EN,,0,0,0,,is by the value of a pointer. Dialogue: 0,0:43:08.22,0:43:09.15,EN,,0,0,0,,A pointer is copied, Dialogue: 0,0:43:09.15,0:43:10.91,EN,,0,0,0,,but the data structure it points at is not. Dialogue: 0,0:43:13.41,0:43:14.84,EN,,0,0,0,,But I'd like to, in fact, show you Dialogue: 0,0:43:15.04,0:43:18.38,EN,,0,0,0,,is how you add name arguments as well. Dialogue: 0,0:43:19.99,0:43:22.12,EN,,0,0,0,,Now again, why would we need such a thing? Dialogue: 0,0:43:23.10,0:43:24.72,EN,,0,0,0,,Well supposing we wanted to invent Dialogue: 0,0:43:25.24,0:43:28.44,EN,,0,0,0,,certain kinds of what otherwise would be special forms, Dialogue: 0,0:43:28.73,0:43:29.72,EN,,0,0,0,,reserve words? Dialogue: 0,0:43:29.72,0:43:31.48,EN,,0,0,0,,But I'd rather not take up reserve words. Dialogue: 0,0:43:32.18,0:43:34.76,EN,,0,0,0,,I want procedures that can do things like if. Dialogue: 0,0:43:36.36,0:43:39.42,EN,,0,0,0,,If is special, or cond, or whatever it is. Dialogue: 0,0:43:39.42,0:43:40.43,EN,,0,0,0,,It's the same thing. Dialogue: 0,0:43:40.59,0:43:42.86,EN,,0,0,0,,It's special in that it determines whether or not Dialogue: 0,0:43:42.92,0:43:45.02,EN,,0,0,0,,to evaluate the consequent or the alternative Dialogue: 0,0:43:46.22,0:43:49.76,EN,,0,0,0,,based on the value of the predicate part of an expression. Dialogue: 0,0:43:50.84,0:43:53.12,EN,,0,0,0,,So taking the value of one thing Dialogue: 0,0:43:53.44,0:43:55.36,EN,,0,0,0,,determines whether or not to do something else. Dialogue: 0,0:43:57.27,0:43:58.88,EN,,0,0,0,,Whereas all the procedures like plus, Dialogue: 0,0:43:59.15,0:44:01.20,EN,,0,0,0,,evaluate... the ones that we can define right now, Dialogue: 0,0:44:01.42,0:44:06.56,EN,,0,0,0,,evaluate all of their arguments before application. Dialogue: 0,0:44:08.67,0:44:09.64,EN,,0,0,0,,So, for example, Dialogue: 0,0:44:10.46,0:44:12.41,EN,,0,0,0,,supposing I wish to be able to define something like Dialogue: 0,0:44:15.39,0:44:18.75,EN,,0,0,0,,the reverse of if in terms of if. Dialogue: 0,0:44:19.85,0:44:20.70,EN,,0,0,0,,Call it unless. Dialogue: 0,0:44:24.89,0:44:27.47,EN,,0,0,0,,We've a predicate, a consequent, and an alternative. Dialogue: 0,0:44:28.67,0:44:30.44,EN,,0,0,0,,Now what I would like to sort of be able to do is Dialogue: 0,0:44:30.46,0:44:32.08,EN,,0,0,0,,say-- oh, I'll do it in terms of cond. Dialogue: 0,0:44:32.64,0:44:36.72,EN,,0,0,0,,Cond, if not the predicate, Dialogue: 0,0:44:38.96,0:44:40.32,EN,,0,0,0,,then take the consequent, Dialogue: 0,0:44:41.58,0:44:45.63,EN,,0,0,0,,otherwise, take the alternative. Dialogue: 0,0:44:51.29,0:44:52.76,EN,,0,0,0,,Now, what I'd like this to mean, Dialogue: 0,0:44:53.32,0:44:55.40,EN,,0,0,0,,is supposing I do something like this. Dialogue: 0,0:44:56.92,0:45:04.12,EN,,0,0,0,,I'd like this unless say if equals one, 0, Dialogue: 0,0:45:05.08,0:45:06.64,EN,,0,0,0,,then the answer is two, Dialogue: 0,0:45:07.90,0:45:11.35,EN,,0,0,0,,otherwise, the quotient of one and 0. Dialogue: 0,0:45:15.92,0:45:18.91,EN,,0,0,0,,What I'd like that to mean is the result of substituting Dialogue: 0,0:45:20.00,0:45:23.26,EN,,0,0,0,,equal one, 0, and the quotient of one, 0 Dialogue: 0,0:45:23.66,0:45:24.76,EN,,0,0,0,,for p, c, and a. Dialogue: 0,0:45:25.58,0:45:27.58,EN,,0,0,0,,I'd like that to mean, and this is funny, Dialogue: 0,0:45:28.11,0:45:30.33,EN,,0,0,0,,I'd like it to transform into or mean Dialogue: 0,0:45:30.75,0:45:38.44,EN,,0,0,0,,cond not equal one, 0, Dialogue: 0,0:45:40.62,0:45:42.54,EN,,0,0,0,,then the result is two, Dialogue: 0,0:45:44.28,0:45:45.10,EN,,0,0,0,,otherwise Dialogue: 0,0:45:48.22,0:45:51.16,EN,,0,0,0,,I want it to be the quotient one and 0. Dialogue: 0,0:45:54.48,0:45:56.48,EN,,0,0,0,,Now, you know that if I were to type this into Lisp, Dialogue: 0,0:45:57.74,0:45:58.59,EN,,0,0,0,,I'd get a two. Dialogue: 0,0:45:59.97,0:46:01.32,EN,,0,0,0,,There's no problem with that. Dialogue: 0,0:46:02.91,0:46:04.64,EN,,0,0,0,,However, if I were to type this into Lisp, Dialogue: 0,0:46:05.28,0:46:07.79,EN,,0,0,0,,because all the arguments are evaluated before I start, Dialogue: 0,0:46:09.12,0:46:10.73,EN,,0,0,0,,then I'm going to get an error out of this. Dialogue: 0,0:46:13.38,0:46:15.61,EN,,0,0,0,,So that if the substitutions work at all, of course, Dialogue: 0,0:46:16.03,0:46:16.88,EN,,0,0,0,,I would get the right answer. Dialogue: 0,0:46:16.88,0:46:20.16,EN,,0,0,0,,But here's a case where the substitutions don't work. Dialogue: 0,0:46:22.17,0:46:23.86,EN,,0,0,0,,I don't get the wrong answer. Dialogue: 0,0:46:23.86,0:46:24.67,EN,,0,0,0,,I get no answer. Dialogue: 0,0:46:24.80,0:46:25.60,EN,,0,0,0,,I get an error. Dialogue: 0,0:46:28.42,0:46:31.21,EN,,0,0,0,,Now, however, I'd like to be able to make my definition Dialogue: 0,0:46:31.61,0:46:32.99,EN,,0,0,0,,so that this kind of thing works. Dialogue: 0,0:46:34.48,0:46:36.51,EN,,0,0,0,,What I want to do is say something special Dialogue: 0,0:46:36.70,0:46:38.76,EN,,0,0,0,,about c and a. Dialogue: 0,0:46:39.93,0:46:43.15,EN,,0,0,0,,I want them to be delayed automatically. Dialogue: 0,0:46:44.27,0:46:48.08,EN,,0,0,0,,I don't want them to be, I don't want them to be evaluated Dialogue: 0,0:46:48.52,0:46:49.74,EN,,0,0,0,,at the time I call. Dialogue: 0,0:46:51.52,0:46:52.72,EN,,0,0,0,,So I'm going to make a declaration, Dialogue: 0,0:46:52.75,0:46:55.32,EN,,0,0,0,,and then I'm going to see how to implement such a declaration. Dialogue: 0,0:46:55.60,0:46:57.63,EN,,0,0,0,,But again, I want you to say to yourself, Dialogue: 0,0:46:57.79,0:47:00.25,EN,,0,0,0,,oh, this is an interesting kluge he's adding in here. Dialogue: 0,0:47:00.76,0:47:02.16,EN,,0,0,0,,A kluge, you know. Dialogue: 0,0:47:02.25,0:47:04.72,EN,,0,0,0,,The piles of kluges make a big complicated mess. Dialogue: 0,0:47:05.75,0:47:09.79,EN,,0,0,0,,And is this going to foul up something else that might occur. Dialogue: 0,0:47:10.12,0:47:12.70,EN,,0,0,0,,First of all, is it syntactically unambiguous? Dialogue: 0,0:47:13.86,0:47:15.50,EN,,0,0,0,,Well, it will be syntactically unambiguous Dialogue: 0,0:47:15.71,0:47:16.91,EN,,0,0,0,,with what we've seen so far. Dialogue: 0,0:47:17.84,0:47:20.76,EN,,0,0,0,,But what I'm going to do may, in fact, cause trouble. Dialogue: 0,0:47:21.67,0:47:24.67,EN,,0,0,0,,It may be that the thing I had will conflict with Dialogue: 0,0:47:25.15,0:47:27.10,EN,,0,0,0,,type declarations I might want to add in the future Dialogue: 0,0:47:28.19,0:47:31.08,EN,,0,0,0,,for giving some system, some compiler or something, Dialogue: 0,0:47:31.21,0:47:33.66,EN,,0,0,0,,the ability to optimize given the types are known. Dialogue: 0,0:47:34.75,0:47:36.97,EN,,0,0,0,,Or it might conflict with other types of declarations Dialogue: 0,0:47:37.00,0:47:39.71,EN,,0,0,0,,that I might want to make about the formal parameters. Dialogue: 0,0:47:40.57,0:47:42.56,EN,,0,0,0,,So I'm not making a general mechanism here Dialogue: 0,0:47:43.77,0:47:45.24,EN,,0,0,0,,where I can add declarations. Dialogue: 0,0:47:45.28,0:47:46.54,EN,,0,0,0,,And I would like to be able to do that. Dialogue: 0,0:47:46.89,0:47:48.81,EN,,0,0,0,,But I don't want to talk about that right now. Dialogue: 0,0:47:51.01,0:47:53.88,EN,,0,0,0,,So here I'm going to do, I'm going to build a kluge. Dialogue: 0,0:47:57.56,0:48:08.38,EN,,0,0,0,,So we're going to define unless of a predicate-- Dialogue: 0,0:48:08.81,0:48:10.27,EN,,0,0,0,,and I'm going to call these by name-- Dialogue: 0,0:48:12.78,0:48:15.28,EN,,0,0,0,,the consequent, and name the alternative. Dialogue: 0,0:48:19.85,0:48:25.28,EN,,0,0,0,,Huh, huh-- I got caught in the corner. Dialogue: 0,0:48:31.76,0:48:35.61,EN,,0,0,0,,If not p then the result is c, Dialogue: 0,0:48:36.80,0:48:41.16,EN,,0,0,0,,else-- that's what I'd like. Dialogue: 0,0:48:44.67,0:48:46.88,EN,,0,0,0,,Where I can explicitly declare Dialogue: 0,0:48:47.55,0:48:51.65,EN,,0,0,0,,certain of the parameters to be delayed, to be computed later. Dialogue: 0,0:48:55.60,0:48:58.48,EN,,0,0,0,,Now, this is actually a very complicated modification to an interpreter Dialogue: 0,0:48:58.70,0:48:59.77,EN,,0,0,0,,rather than a simple one. Dialogue: 0,0:49:00.45,0:49:03.10,EN,,0,0,0,,The ones you saw before, dynamic binding Dialogue: 0,0:49:03.40,0:49:06.89,EN,,0,0,0,,or adding indefinite argument procedures, Dialogue: 0,0:49:07.50,0:49:08.52,EN,,0,0,0,,is relatively simple. Dialogue: 0,0:49:09.28,0:49:11.28,EN,,0,0,0,,But this one changes a basic strategy. Dialogue: 0,0:49:12.32,0:49:13.39,EN,,0,0,0,,The problem here Dialogue: 0,0:49:13.96,0:49:17.63,EN,,0,0,0,,is that our interpreter, as written Dialogue: 0,0:49:17.96,0:49:23.40,EN,,0,0,0,,evaluates a combination by evaluating the procedure, Dialogue: 0,0:49:24.24,0:49:25.92,EN,,0,0,0,,the operator producing the procedure, Dialogue: 0,0:49:26.20,0:49:30.35,EN,,0,0,0,,and evaluating the operands producing the arguments, Dialogue: 0,0:49:30.76,0:49:35.26,EN,,0,0,0,,and then doing apply of the procedure to the arguments. Dialogue: 0,0:49:36.38,0:49:37.07,EN,,0,0,0,,However, here, Dialogue: 0,0:49:37.36,0:49:41.48,EN,,0,0,0,,I don't want to evaluate the operands to produce the arguments Dialogue: 0,0:49:41.74,0:49:43.66,EN,,0,0,0,,until after I examined the procedure Dialogue: 0,0:49:44.62,0:49:46.86,EN,,0,0,0,,to see what the procedure's declarations look like. Dialogue: 0,0:49:49.59,0:49:50.59,EN,,0,0,0,,So let's look at that. Dialogue: 0,0:49:52.68,0:49:56.54,EN,,0,0,0,,Here we have a changed evaluator. Dialogue: 0,0:49:57.48,0:50:01.15,EN,,0,0,0,,I'm starting with the simple lexical evaluator, Dialogue: 0,0:50:01.72,0:50:02.65,EN,,0,0,0,,not dynamic Dialogue: 0,0:50:04.14,0:50:08.20,EN,,0,0,0,,but we're going to have to do something sort of similar in some ways. Dialogue: 0,0:50:09.75,0:50:11.45,EN,,0,0,0,,Because of the fact that, Dialogue: 0,0:50:11.90,0:50:13.34,EN,,0,0,0,,if I delay a procedure-- Dialogue: 0,0:50:13.66,0:50:15.15,EN,,0,0,0,,I'm sorry-- delay an argument to a procedure, Dialogue: 0,0:50:15.40,0:50:17.52,EN,,0,0,0,,I'm going to have to attach and environment to it. Dialogue: 0,0:50:19.36,0:50:21.55,EN,,0,0,0,,Remember how Hal implemented delay. Dialogue: 0,0:50:23.38,0:50:25.44,EN,,0,0,0,,Hal implemented delay as being Dialogue: 0,0:50:25.50,0:50:27.47,EN,,0,0,0,,a procedure of no arguments Dialogue: 0,0:50:28.56,0:50:30.52,EN,,0,0,0,,which does some expression. Dialogue: 0,0:50:31.18,0:50:36.94,EN,,0,0,0,,That's what delay of the expression is. --of that expression. Dialogue: 0,0:50:39.29,0:50:40.99,EN,,0,0,0,,This turned into something like this. Dialogue: 0,0:50:44.52,0:50:46.92,EN,,0,0,0,,Now, however, if I evaluate a lambda expression, Dialogue: 0,0:50:47.42,0:50:49.20,EN,,0,0,0,,I have to capture the environment. Dialogue: 0,0:50:51.41,0:50:53.45,EN,,0,0,0,,The reason why is because there are Dialogue: 0,0:50:54.60,0:50:56.32,EN,,0,0,0,,there are variables in there Dialogue: 0,0:50:57.02,0:51:00.83,EN,,0,0,0,,who's meaning I wish to derive from the context where this was written. Dialogue: 0,0:51:04.01,0:51:05.76,EN,,0,0,0,,So that's why a lambda does the job. Dialogue: 0,0:51:06.62,0:51:07.50,EN,,0,0,0,,It's the right thing. Dialogue: 0,0:51:08.07,0:51:15.12,EN,,0,0,0,,And such that the forcing of a delayed expression Dialogue: 0,0:51:16.52,0:51:20.08,EN,,0,0,0,,was same thing as calling that with no arguments. Dialogue: 0,0:51:21.09,0:51:22.28,EN,,0,0,0,,It's just the opposite of this. Dialogue: 0,0:51:24.10,0:51:26.94,EN,,0,0,0,,Producing an environment of the call Dialogue: 0,0:51:27.36,0:51:29.90,EN,,0,0,0,,which is, in fact, the environment where this was defined Dialogue: 0,0:51:30.81,0:51:32.36,EN,,0,0,0,,with an extra frame in it that's empty. Dialogue: 0,0:51:33.23,0:51:34.41,EN,,0,0,0,,I don't care about that. Dialogue: 0,0:51:36.24,0:51:39.40,EN,,0,0,0,,Well, if we go back to this slide, Dialogue: 0,0:51:40.99,0:51:43.72,EN,,0,0,0,,since it's the case, if we look at this for a second, Dialogue: 0,0:51:44.14,0:51:46.12,EN,,0,0,0,,everything is the same as it was before Dialogue: 0,0:51:46.35,0:51:50.65,EN,,0,0,0,,except the case of applications or combinations. Dialogue: 0,0:51:51.98,0:51:53.71,EN,,0,0,0,,And combinations are going to do two things. Dialogue: 0,0:51:54.68,0:51:57.79,EN,,0,0,0,,One, is I have to evaluate the procedure-- Dialogue: 0,0:51:57.92,0:51:59.88,EN,,0,0,0,,I have to get the procedure-- by evaluating the operator. Dialogue: 0,0:52:00.70,0:52:01.69,EN,,0,0,0,,That's what you see right here. Dialogue: 0,0:52:02.38,0:52:04.35,EN,,0,0,0,,I have to make sure that that's current, Dialogue: 0,0:52:04.46,0:52:05.76,EN,,0,0,0,,that is not a delayed object, Dialogue: 0,0:52:06.36,0:52:09.85,EN,,0,0,0,,and evaluate that to the point where became it's forced now. Dialogue: 0,0:52:10.73,0:52:12.08,EN,,0,0,0,,And then I have to somehow Dialogue: 0,0:52:12.24,0:52:17.32,EN,,0,0,0,,apply that to the, to the operands. Dialogue: 0,0:52:18.03,0:52:19.61,EN,,0,0,0,,But I have to keep the environment, Dialogue: 0,0:52:19.63,0:52:20.92,EN,,0,0,0,,pass that environmental along. Dialogue: 0,0:52:21.53,0:52:23.71,EN,,0,0,0,,So some of those operands I may have to delay. Dialogue: 0,0:52:23.71,0:52:27.53,EN,,0,0,0,,I may have to attach that environment to those operands. Dialogue: 0,0:52:29.66,0:52:31.52,EN,,0,0,0,,This is a rather complicated thing happening here. Dialogue: 0,0:52:32.99,0:52:34.24,EN,,0,0,0,,Looking at that in apply. Dialogue: 0,0:52:36.40,0:52:38.72,EN,,0,0,0,,Apply, well it has a primitive procedure Dialogue: 0,0:52:39.36,0:52:40.60,EN,,0,0,0,,thing just like before. Dialogue: 0,0:52:42.61,0:52:44.68,EN,,0,0,0,,But the compound one is a little more interesting. Dialogue: 0,0:52:47.25,0:52:49.52,EN,,0,0,0,,I have to evaluate the body, just as before, Dialogue: 0,0:52:50.48,0:52:51.98,EN,,0,0,0,,in an environment which is Dialogue: 0,0:52:52.28,0:52:54.97,EN,,0,0,0,,which is the result of binding some Dialogue: 0,0:52:55.61,0:53:00.29,EN,,0,0,0,,formal parameters to arguments in the environment. Dialogue: 0,0:53:00.29,0:53:01.07,EN,,0,0,0,,That's true. Dialogue: 0,0:53:01.53,0:53:03.82,EN,,0,0,0,,The environment is the one that comes from the procedure now. Dialogue: 0,0:53:03.82,0:53:06.65,EN,,0,0,0,,It's a lexical language, statically bound. Dialogue: 0,0:53:08.04,0:53:11.82,EN,,0,0,0,,However, one thing I have to do is strip off the declarations Dialogue: 0,0:53:11.84,0:53:12.84,EN,,0,0,0,,to get the names of the variables. Dialogue: 0,0:53:12.84,0:53:15.20,EN,,0,0,0,,That's what this guy does, vnames. Dialogue: 0,0:53:15.45,0:53:16.67,EN,,0,0,0,,And the other thing I have to do Dialogue: 0,0:53:16.97,0:53:18.86,EN,,0,0,0,,is process these declarations, Dialogue: 0,0:53:19.13,0:53:21.52,EN,,0,0,0,,deciding which of these operands-- Dialogue: 0,0:53:21.76,0:53:23.92,EN,,0,0,0,,that's the operands now, as opposed to the arguments-- Dialogue: 0,0:53:24.09,0:53:25.87,EN,,0,0,0,,which of these operands to evaluate, Dialogue: 0,0:53:26.62,0:53:30.20,EN,,0,0,0,,and which of them are to be Dialogue: 0,0:53:30.99,0:53:33.77,EN,,0,0,0,,encapsulated in delays of some sort. Dialogue: 0,0:53:37.28,0:53:40.08,EN,,0,0,0,,The other thing you see here is that we got a primitive, Dialogue: 0,0:53:40.60,0:53:42.38,EN,,0,0,0,,a primitive like plus, Dialogue: 0,0:53:42.68,0:53:45.58,EN,,0,0,0,,had better get at the real operands. Dialogue: 0,0:53:45.82,0:53:47.39,EN,,0,0,0,,So here is a place where we're going to have to force them. Dialogue: 0,0:53:47.92,0:53:50.38,EN,,0,0,0,,And we're going to look at what evlist is going to have to do a bunch of forces. Dialogue: 0,0:53:51.34,0:53:52.78,EN,,0,0,0,,So we have two different kinds of evlist now. Dialogue: 0,0:53:52.78,0:53:54.09,EN,,0,0,0,,We have evlist and gevlist. Dialogue: 0,0:53:54.52,0:53:57.16,EN,,0,0,0,,Gevlist is going to wrap delays around some things Dialogue: 0,0:53:57.18,0:53:59.74,EN,,0,0,0,,and force others, evaluate others. Dialogue: 0,0:53:59.87,0:54:05.85,EN,,0,0,0,,And this guy's going to do some forcing of things. Dialogue: 0,0:54:07.90,0:54:09.16,EN,,0,0,0,,Just looking at this a little bit, Dialogue: 0,0:54:09.69,0:54:11.98,EN,,0,0,0,,this is a game you must play for yourself, you know. Dialogue: 0,0:54:12.25,0:54:14.67,EN,,0,0,0,,It's not something that you're going to see all possible Dialogue: 0,0:54:14.72,0:54:18.20,EN,,0,0,0,,variations on an evaluator talking to me. Dialogue: 0,0:54:19.52,0:54:21.24,EN,,0,0,0,,What you have to do is do this for yourself. Dialogue: 0,0:54:21.37,0:54:23.84,EN,,0,0,0,,And after you feel this, you play this a bit, Dialogue: 0,0:54:24.22,0:54:27.02,EN,,0,0,0,,you get to see all the possible design decisions and what they might mean, Dialogue: 0,0:54:27.77,0:54:29.16,EN,,0,0,0,,and how they interact with each other. Dialogue: 0,0:54:29.93,0:54:32.38,EN,,0,0,0,,So what languages might have in them. Dialogue: 0,0:54:33.16,0:54:34.64,EN,,0,0,0,,And what are some of the consistent sets Dialogue: 0,0:54:34.94,0:54:36.32,EN,,0,0,0,,that make a legitimate language. Dialogue: 0,0:54:37.20,0:54:40.06,EN,,0,0,0,,Whereas what things are complicated kluges that are just piles of junk. Dialogue: 0,0:54:41.85,0:54:44.68,EN,,0,0,0,,So evlist of course, over here, just as I said, Dialogue: 0,0:54:44.81,0:54:46.03,EN,,0,0,0,,is a list of operands Dialogue: 0,0:54:46.70,0:54:50.28,EN,,0,0,0,,which are going to be undelayed after evaluation. Dialogue: 0,0:54:50.75,0:54:51.90,EN,,0,0,0,,So these are going to be forced, Dialogue: 0,0:54:53.28,0:54:54.44,EN,,0,0,0,,whatever that's going to mean. Dialogue: 0,0:54:56.05,0:54:58.51,EN,,0,0,0,,And gevlist, which is the next thing-- Dialogue: 0,0:55:01.26,0:55:01.85,EN,,0,0,0,,Thank you. Dialogue: 0,0:55:04.04,0:55:06.35,EN,,0,0,0,,What we see here, uh Dialogue: 0,0:55:07.80,0:55:09.61,EN,,0,0,0,,well there's a couple of possibilities. Dialogue: 0,0:55:09.81,0:55:11.52,EN,,0,0,0,,Either it's a normal, ordinary thing, Dialogue: 0,0:55:12.48,0:55:13.69,EN,,0,0,0,,a symbol sitting there Dialogue: 0,0:55:13.74,0:55:16.20,EN,,0,0,0,,like the predicate in the unless, Dialogue: 0,0:55:17.64,0:55:18.81,EN,,0,0,0,,and that's what we have here. Dialogue: 0,0:55:19.39,0:55:22.49,EN,,0,0,0,,In which case, this is intended to be evaluated in applicative order. Dialogue: 0,0:55:23.34,0:55:25.45,EN,,0,0,0,,And it's, essentially, just what we had before. Dialogue: 0,0:55:25.63,0:55:28.84,EN,,0,0,0,,It's mapping eval down the list. Dialogue: 0,0:55:29.95,0:55:32.14,EN,,0,0,0,,In other words, I evaluate the first expression Dialogue: 0,0:55:32.65,0:55:37.36,EN,,0,0,0,,and continue gevlisting the CDR of the expression in the environment. Dialogue: 0,0:55:37.93,0:55:43.20,EN,,0,0,0,,However, it's possible that this is a name parameter. Dialogue: 0,0:55:44.00,0:55:45.05,EN,,0,0,0,,If it's a name parameter, Dialogue: 0,0:55:45.20,0:55:46.59,EN,,0,0,0,,I want to put a delay in Dialogue: 0,0:55:47.00,0:55:50.97,EN,,0,0,0,,which combines that expression, which I'm calling by name, Dialogue: 0,0:55:52.14,0:55:57.74,EN,,0,0,0,,with the environment that's available at this time Dialogue: 0,0:55:59.05,0:56:00.59,EN,,0,0,0,,and passing that as the parameter. Dialogue: 0,0:56:02.79,0:56:05.04,EN,,0,0,0,,And this is part of the mapping process that you see here. Dialogue: 0,0:56:09.07,0:56:11.31,EN,,0,0,0,,The only other interesting place in this procedure Dialogue: 0,0:56:11.37,0:56:13.53,EN,,0,0,0,,in this interpreter is cond. Dialogue: 0,0:56:14.70,0:56:15.92,EN,,0,0,0,,People tend to write this thing, Dialogue: 0,0:56:15.93,0:56:17.24,EN,,0,0,0,,and then they leave this one out. Dialogue: 0,0:56:18.55,0:56:19.98,EN,,0,0,0,,There's a place where you have to force. Dialogue: 0,0:56:20.51,0:56:23.10,EN,,0,0,0,,Conditionals have to know Dialogue: 0,0:56:24.20,0:56:25.90,EN,,0,0,0,,whether or not the answer is true or false. Dialogue: 0,0:56:25.99,0:56:26.83,EN,,0,0,0,,It's like a primitive. Dialogue: 0,0:56:28.55,0:56:30.56,EN,,0,0,0,,When you do a conditional, you have to force. Dialogue: 0,0:56:31.72,0:56:33.95,EN,,0,0,0,,Now, I'm not going to look at any more of this in any detail. Dialogue: 0,0:56:34.62,0:56:36.28,EN,,0,0,0,,It isn't very exciting. Dialogue: 0,0:56:36.75,0:56:38.99,EN,,0,0,0,,And what's left is how you make delays. Dialogue: 0,0:56:38.99,0:56:40.91,EN,,0,0,0,,Well, delays are data structures Dialogue: 0,0:56:41.31,0:56:44.75,EN,,0,0,0,,which contain an expression, an environment, and a type on them. Dialogue: 0,0:56:44.84,0:56:46.36,EN,,0,0,0,,And it says they're a thunk. Dialogue: 0,0:56:46.96,0:56:48.46,EN,,0,0,0,,That comes from ALGOL language, Dialogue: 0,0:56:49.07,0:56:50.81,EN,,0,0,0,,and it's claimed to be the sound of Dialogue: 0,0:56:50.83,0:56:52.06,EN,,0,0,0,,of something being pushed on a stack. Dialogue: 0,0:56:52.97,0:56:53.41,EN,,0,0,0,,I don't know. Dialogue: 0,0:56:53.41,0:56:57.12,EN,,0,0,0,,I was not an ALGOLician, so or an ALGOLite or whatever, Dialogue: 0,0:56:57.60,0:56:58.38,EN,,0,0,0,,so I don't know. Dialogue: 0,0:56:58.74,0:56:59.64,EN,,0,0,0,,But that's what was claimed. Dialogue: 0,0:57:00.27,0:57:01.56,EN,,0,0,0,,And undelay is something Dialogue: 0,0:57:01.77,0:57:03.66,EN,,0,0,0,,which will recursively undelay thunks Dialogue: 0,0:57:03.69,0:57:06.00,EN,,0,0,0,,until the thunk becomes something which isn't a thunk. Dialogue: 0,0:57:07.72,0:57:10.94,EN,,0,0,0,,This is the way you implement a call by name like thing in ALGOL. Dialogue: 0,0:57:12.05,0:57:13.76,EN,,0,0,0,,And that's about all there is. Dialogue: 0,0:57:15.21,0:57:16.25,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:57:26.68,0:57:27.52,EN,,0,0,0,,AUDIENCE: Gerry? Dialogue: 0,0:57:28.09,0:57:28.80,EN,,0,0,0,,PROFESSOR: Yes, Vesko? Dialogue: 0,0:57:30.03,0:57:32.99,EN,,0,0,0,,AUDIENCE: I noticed you avoided calling by name Dialogue: 0,0:57:33.44,0:57:34.89,EN,,0,0,0,,in the primitive procedures, Dialogue: 0,0:57:36.41,0:57:38.38,EN,,0,0,0,,I was wondering what cause you have on that? Dialogue: 0,0:57:38.41,0:57:39.21,EN,,0,0,0,,You never need that? Dialogue: 0,0:57:40.07,0:57:41.61,EN,,0,0,0,,PROFESSOR: Vesko is asking Dialogue: 0,0:57:42.06,0:57:46.00,EN,,0,0,0,,if it's ever reasonable to call a primitive procedure by name? Dialogue: 0,0:57:47.14,0:57:48.70,EN,,0,0,0,,The answer is, yes. Dialogue: 0,0:57:49.27,0:57:52.32,EN,,0,0,0,,There's one particular case where it's reasonable, actually two. Dialogue: 0,0:57:55.53,0:57:58.27,EN,,0,0,0,,Construction of a data structure like cons Dialogue: 0,0:57:59.02,0:58:02.00,EN,,0,0,0,,where making an array if you have arrays with any number of elements. Dialogue: 0,0:58:03.26,0:58:07.44,EN,,0,0,0,,OK? It's unnecessary to evaluate those arguments. Dialogue: 0,0:58:07.44,0:58:08.83,EN,,0,0,0,,All you need is promises Dialogue: 0,0:58:09.10,0:58:10.81,EN,,0,0,0,,to evaluate those arguments if you look at them. Dialogue: 0,0:58:11.50,0:58:15.08,EN,,0,0,0,,If I cons together a, two things, Dialogue: 0,0:58:16.24,0:58:17.77,EN,,0,0,0,,then I could cons together the promises Dialogue: 0,0:58:17.80,0:58:19.93,EN,,0,0,0,,just as easily as I can cons together the things. Dialogue: 0,0:58:21.15,0:58:23.37,EN,,0,0,0,,And it's not even when I CAR CDR them Dialogue: 0,0:58:23.39,0:58:24.30,EN,,0,0,0,,that I have to look at them. Dialogue: 0,0:58:24.84,0:58:26.97,EN,,0,0,0,,That just gets out the promises and passes them to somebody. Dialogue: 0,0:58:28.26,0:58:30.51,EN,,0,0,0,,That's why the lambda calculus definition, the Dialogue: 0,0:58:30.57,0:58:34.03,EN,,0,0,0,,the Alonzo Church definition of CAR, CDR, and cons makes sense. Dialogue: 0,0:58:34.42,0:58:36.32,EN,,0,0,0,,It's because no work is done in CAR, CDR, and cons, Dialogue: 0,0:58:36.38,0:58:40.06,EN,,0,0,0,,it's just shuffling data, it's just routing, if you will. Dialogue: 0,0:58:40.99,0:58:42.20,EN,,0,0,0,,However, the things that do have Dialogue: 0,0:58:42.24,0:58:43.84,EN,,0,0,0,,to look at data are things like plus. Dialogue: 0,0:58:45.28,0:58:46.91,EN,,0,0,0,,Because they have a look at the bits Dialogue: 0,0:58:47.12,0:58:48.30,EN,,0,0,0,,that the numbers are made out of, Dialogue: 0,0:58:48.32,0:58:50.44,EN,,0,0,0,,unless they're lambda calculus numbers Dialogue: 0,0:58:50.44,0:58:51.88,EN,,0,0,0,,which are funny. OK? Dialogue: 0,0:58:52.43,0:58:53.58,EN,,0,0,0,,They have to look at the bits to Dialogue: 0,0:58:53.77,0:58:55.53,EN,,0,0,0,,be able to crunch them together to do the add. Dialogue: 0,0:58:59.21,0:58:59.92,EN,,0,0,0,,So, in fact, Dialogue: 0,0:59:00.19,0:59:02.78,EN,,0,0,0,,data constructors, data selectors, Dialogue: 0,0:59:03.24,0:59:05.50,EN,,0,0,0,,in fact, things that side-effect data objects Dialogue: 0,0:59:06.27,0:59:09.76,EN,,0,0,0,,don't need to do, don't need to do any forcing Dialogue: 0,0:59:11.34,0:59:13.39,EN,,0,0,0,,in the laziest possible interpreters. Dialogue: 0,0:59:16.46,0:59:16.99,EN,,0,0,0,,On the other hand Dialogue: 0,0:59:17.02,0:59:18.70,EN,,0,0,0,,predicates on data structures have to. Dialogue: 0,0:59:19.61,0:59:22.65,EN,,0,0,0,,If you want to say, is this a, is this a pair? Dialogue: 0,0:59:23.56,0:59:24.40,EN,,0,0,0,,Or is it a symbol? Dialogue: 0,0:59:24.64,0:59:26.57,EN,,0,0,0,,Well, you better find out. You got to look at it then. Dialogue: 0,0:59:30.30,0:59:31.18,EN,,0,0,0,,Any other questions? Dialogue: 0,0:59:40.05,0:59:41.61,EN,,0,0,0,,Oh, well, I suppose it's time for a break. Dialogue: 0,0:00:00.01,0:00:01.63,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:01.63,0:00:09.15,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N张大伟 Dialogue: 0,0:00:01.63,0:00:09.15,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:01.63,0:00:09.15,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:01.63,0:00:09.15,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:01.63,0:00:09.15,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:09.52,0:00:13.66,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 II Dialogue: 0,0:00:17.21,0:00:17.96,Default,,0,0,0,,教授:目前为止 Dialogue: 0,0:00:19.52,0:00:21.29,Default,,0,0,0,,我们学的东西都非常有趣 Dialogue: 0,0:00:21.52,0:00:23.05,Default,,0,0,0,,但它有什么实际的用途吗? Dialogue: 0,0:00:26.33,0:00:27.96,Default,,0,0,0,,我想答案是“是的” Dialogue: 0,0:00:29.38,0:00:31.92,Default,,0,0,0,,这些元循环解释器 Dialogue: 0,0:00:32.96,0:00:34.60,Default,,0,0,0,,非常值得琢磨 Dialogue: 0,0:00:34.62,0:00:36.17,Default,,0,0,0,,我花了大概 Dialogue: 0,0:00:38.05,0:00:41.85,Default,,0,0,0,,曾几何时 我花了半年的功夫 Dialogue: 0,0:00:42.86,0:00:45.26,Default,,0,0,0,,用上节课讲的那种 Dialogue: 0,0:00:45.76,0:00:48.19,Default,,0,0,0,,元循环解释器来试验 Dialogue: 0,0:00:49.47,0:00:52.01,Default,,0,0,0,,各种各样的设计变种 Dialogue: 0,0:00:52.57,0:00:54.11,Default,,0,0,0,,用元循环解释器是因为 Dialogue: 0,0:00:54.72,0:00:56.94,Default,,0,0,0,,它们通过自己定义自己 Dialogue: 0,0:00:56.97,0:00:59.71,Default,,0,0,0,,因此被解释的语言也包含了自己 Dialogue: 0,0:01:01.27,0:01:03.87,Default,,0,0,0,,这样的解释器是一种的媒介 Dialogue: 0,0:01:03.88,0:01:05.58,Default,,0,0,0,,方便我们探索语言问题 Dialogue: 0,0:01:06.80,0:01:09.44,Default,,0,0,0,,如果你想添加一个新的FEATURE Dialogue: 0,0:01:10.51,0:01:12.38,Default,,0,0,0,,这就是小菜一碟 Dialogue: 0,0:01:12.73,0:01:15.10,Default,,0,0,0,,你只需要稍作修改 然后观察结果 Dialogue: 0,0:01:15.49,0:01:17.20,Default,,0,0,0,,在尝试了一会儿新语言后 Dialogue: 0,0:01:17.24,0:01:18.24,Default,,0,0,0,,你可能觉得它不好 Dialogue: 0,0:01:18.52,0:01:19.47,Default,,0,0,0,,就把它扔到一边去了 Dialogue: 0,0:01:20.96,0:01:23.55,Default,,0,0,0,,或者你也想研究 Dialogue: 0,0:01:23.64,0:01:27.37,Default,,0,0,0,,不同绑定策略的差异 Dialogue: 0,0:01:28.81,0:01:31.90,Default,,0,0,0,,或者是一些更复杂的东西 Dialogue: 0,0:01:33.72,0:01:35.48,Default,,0,0,0,,事实上 这些元循环解释器 Dialogue: 0,0:01:36.17,0:01:37.88,Default,,0,0,0,,非常适合作为交换媒介 Dialogue: 0,0:01:38.20,0:01:42.56,Default,,0,0,0,,用于承载人们关于语言设计想法 Dialogue: 0,0:01:43.98,0:01:45.74,Default,,0,0,0,,因为它们易于理解 Dialogue: 0,0:01:46.28,0:01:48.46,Default,,0,0,0,,它们短小、紧凑而且简洁 Dialogue: 0,0:01:49.32,0:01:50.80,Default,,0,0,0,,如果我有一些点子 Dialogue: 0,0:01:51.53,0:01:53.77,Default,,0,0,0,,想让其它人评论一下 Dialogue: 0,0:01:54.25,0:01:58.32,Default,,0,0,0,,比如Indiana大学的Dan Friedman教授 Dialogue: 0,0:01:59.05,0:02:02.00,Default,,0,0,0,,我就编写一个小型元循环解释器 Dialogue: 0,0:02:02.56,0:02:03.79,Default,,0,0,0,,然后给他发一封电子邮件 Dialogue: 0,0:02:04.65,0:02:05.45,Default,,0,0,0,,并附上解释器 Dialogue: 0,0:02:05.45,0:02:07.90,Default,,0,0,0,,他就可以在计算机上安装并运行 Dialogue: 0,0:02:07.92,0:02:09.82,Default,,0,0,0,,可能他会觉得这个设计并不好 Dialogue: 0,0:02:11.94,0:02:13.10,Default,,0,0,0,,然后他会给我回一封邮件 Dialogue: 0,0:02:13.13,0:02:14.83,Default,,0,0,0,,“为什么不试试这个 这个更好一点” Dialogue: 0,0:02:16.88,0:02:19.36,Default,,0,0,0,,所以我将会讲一些这方面的技术 Dialogue: 0,0:02:20.16,0:02:24.20,Default,,0,0,0,,因为在设计你自己的特定用途语言时 Dialogue: 0,0:02:24.72,0:02:28.68,Default,,0,0,0,,这种简单的技术非常重要 Dialogue: 0,0:02:30.79,0:02:32.08,Default,,0,0,0,,我们试着先在Lisp中 Dialogue: 0,0:02:32.51,0:02:34.21,Default,,0,0,0,,添加一个非常简单的FEATURE Dialogue: 0,0:02:40.64,0:02:44.37,Default,,0,0,0,,在这之前 我先来谈谈FEATURE吧 Dialogue: 0,0:02:49.56,0:02:52.17,Default,,0,0,0,,很多语言添加了大量的FEATURE Dialogue: 0,0:02:53.05,0:02:54.91,Default,,0,0,0,,把它们本身搞得混乱不堪 Dialogue: 0,0:02:56.86,0:02:58.38,Default,,0,0,0,,计算机科学家有一个笑话 Dialogue: 0,0:02:59.28,0:03:02.52,Default,,0,0,0,,“这不是BUG 这是FEATURE” Dialogue: 0,0:03:05.03,0:03:06.46,Default,,0,0,0,,而我宁愿认为 Dialogue: 0,0:03:08.91,0:03:11.44,Default,,0,0,0,,很多系统都在遭受着“功能蔓延”的影响 Dialogue: 0,0:03:12.82,0:03:13.44,Default,,0,0,0,,比方说 Dialogue: 0,0:03:14.94,0:03:18.16,Default,,0,0,0,,George希望系统中有某个FEATURE Dialogue: 0,0:03:18.72,0:03:19.36,Default,,0,0,0,,他就加了进来 Dialogue: 0,0:03:20.17,0:03:22.14,Default,,0,0,0,,Harry也想着 Dialogue: 0,0:03:22.17,0:03:24.20,Default,,0,0,0,,这个系统现在也不是我喜欢的那个了 Dialogue: 0,0:03:24.24,0:03:25.92,Default,,0,0,0,,然后加入了自己最喜欢的FEATURE Dialogue: 0,0:03:26.64,0:03:30.24,Default,,0,0,0,,Jim也这样做 Dialogue: 0,0:03:30.83,0:03:31.79,Default,,0,0,0,,一段时间过后 Dialogue: 0,0:03:31.80,0:03:34.81,Default,,0,0,0,,操作手册就多达500页 Dialogue: 0,0:03:35.15,0:03:36.51,Default,,0,0,0,,以至于没人能看得懂 Dialogue: 0,0:03:37.79,0:03:39.32,Default,,0,0,0,,有时候也可能只是 Dialogue: 0,0:03:39.90,0:03:41.37,Default,,0,0,0,,同一个人在添加FEATURE Dialogue: 0,0:03:41.39,0:03:43.23,Default,,0,0,0,,也会导致同样糟糕的结果 Dialogue: 0,0:03:44.14,0:03:46.09,Default,,0,0,0,,很多情况下 比如编辑器 Dialogue: 0,0:03:47.37,0:03:49.12,Default,,0,0,0,,具有很多FEATURE就很合理 Dialogue: 0,0:03:50.92,0:03:52.65,Default,,0,0,0,,因为你想要能够完成 Dialogue: 0,0:03:52.68,0:03:53.76,Default,,0,0,0,,各种不同的事情 Dialogue: 0,0:03:56.11,0:03:57.29,Default,,0,0,0,,但对计算机语言来说 Dialogue: 0,0:03:57.85,0:03:58.91,Default,,0,0,0,,我认为太多的FEATURE Dialogue: 0,0:04:00.01,0:04:01.29,Default,,0,0,0,,是一个灾难 Dialogue: 0,0:04:04.03,0:04:08.00,Default,,0,0,0,,另外 系统也可能变成某种“尖叫的怪物” Dialogue: 0,0:04:09.52,0:04:11.39,Default,,0,0,0,,假设你有一个盒子 Dialogue: 0,0:04:11.80,0:04:15.29,Default,,0,0,0,,它有一个鼠标和花哨的显示器 Dialogue: 0,0:04:15.95,0:04:20.04,Default,,0,0,0,,这些花哨的IO带来了各种各样的复杂性 Dialogue: 0,0:04:21.01,0:04:22.80,Default,,0,0,0,,你的程序语言就变成了 Dialogue: 0,0:04:23.34,0:04:25.37,Default,,0,0,0,,阴暗无用的小玩意儿 Dialogue: 0,0:04:25.40,0:04:27.90,Default,,0,0,0,,这是由计算机上的视窗系统进行的 Dialogue: 0,0:04:28.09,0:04:29.36,Default,,0,0,0,,内存换页和磁盘抖动所导致的 Dialogue: 0,0:04:30.08,0:04:31.82,Default,,0,0,0,,每当你使用计算机的时候 Dialogue: 0,0:04:31.93,0:04:33.45,Default,,0,0,0,,鼠标处理进程就会唤醒 Dialogue: 0,0:04:33.85,0:04:35.95,Default,,0,0,0,,你有什么事情要我做的吗? Dialogue: 0,0:04:36.14,0:04:37.23,Default,,0,0,0,,然后又回去休眠 Dialogue: 0,0:04:37.44,0:04:39.44,Default,,0,0,0,,如果你的胳膊肘不小心碰到了鼠标 Dialogue: 0,0:04:39.61,0:04:42.32,Default,,0,0,0,,一大堆烟雾就会从你的电脑出来 类似于这样 Dialogue: 0,0:04:42.94,0:04:45.29,Default,,0,0,0,,这就是由于添加FEATURE Dialogue: 0,0:04:45.55,0:04:47.21,Default,,0,0,0,,导致系统不能用的两种典型情况 Dialogue: 0,0:04:47.50,0:04:49.73,Default,,0,0,0,,现在我们要添加的是 一个非常简单的FEATURE Dialogue: 0,0:04:52.60,0:04:53.77,Default,,0,0,0,,这个FEATURE非常好 Dialogue: 0,0:04:53.85,0:04:56.17,Default,,0,0,0,,事实上 Lisp中就有这个FEATURE Dialogue: 0,0:04:57.25,0:04:58.17,Default,,0,0,0,,我们都知道 Dialogue: 0,0:04:59.29,0:05:03.13,Default,,0,0,0,,像+、*这样的过程 Dialogue: 0,0:05:03.37,0:05:04.89,Default,,0,0,0,,可以接受不定数目的参数 Dialogue: 0,0:05:05.43,0:05:06.44,Default,,0,0,0,,因此我们就可以写 Dialogue: 0,0:05:06.57,0:05:10.94,Default,,0,0,0,,(+ (* A X X) Dialogue: 0,0:05:12.09,0:05:16.99,Default,,0,0,0,,(* B X) C) Dialogue: 0,0:05:17.54,0:05:18.68,Default,,0,0,0,,这里可以看到 Dialogue: 0,0:05:18.92,0:05:21.76,Default,,0,0,0,,+有两到三个参数 Dialogue: 0,0:05:22.30,0:05:24.81,Default,,0,0,0,,*也有两到三个参数 Dialogue: 0,0:05:25.08,0:05:26.76,Default,,0,0,0,,不管多少个参数 Dialogue: 0,0:05:26.78,0:05:28.49,Default,,0,0,0,,都应该用同样的方式对待 Dialogue: 0,0:05:30.00,0:05:32.17,Default,,0,0,0,,支持不定数目的参数 Dialogue: 0,0:05:32.28,0:05:34.01,Default,,0,0,0,,这一点非常有用 Dialogue: 0,0:05:34.96,0:05:38.41,Default,,0,0,0,,而我上节课所讲的Lisp求值器 Dialogue: 0,0:05:39.23,0:05:41.85,Default,,0,0,0,,只能处理固定数目的参数 Dialogue: 0,0:05:42.62,0:05:45.28,Default,,0,0,0,,因为我要用BIND过程中的PAIR-UP过程 Dialogue: 0,0:05:45.63,0:05:47.92,Default,,0,0,0,,让形式参数与实际参数一一对应 Dialogue: 0,0:05:50.81,0:05:53.80,Default,,0,0,0,,假如我想能够定义像这样的过程 Dialogue: 0,0:05:54.89,0:05:57.32,Default,,0,0,0,,它们可以接收任意个数的参数 Dialogue: 0,0:05:58.75,0:06:00.40,Default,,0,0,0,,这个问题有好几部分 Dialogue: 0,0:06:01.34,0:06:04.81,Default,,0,0,0,,首先是挑选合适的语法描述 Dialogue: 0,0:06:05.72,0:06:11.21,Default,,0,0,0,,我们需要能够标注额外的参数 Dialogue: 0,0:06:12.17,0:06:13.63,Default,,0,0,0,,标注那些不知道个数的参数 Dialogue: 0,0:06:15.48,0:06:16.62,Default,,0,0,0,,另外就是 Dialogue: 0,0:06:17.10,0:06:18.70,Default,,0,0,0,,一旦我们标注出来后 Dialogue: 0,0:06:19.07,0:06:20.78,Default,,0,0,0,,我们怎样解释这些个记号 Dialogue: 0,0:06:21.74,0:06:23.10,Default,,0,0,0,,才能得到 Dialogue: 0,0:06:23.85,0:06:25.37,Default,,0,0,0,,正确的结果呢? Dialogue: 0,0:06:26.98,0:06:28.80,Default,,0,0,0,,让我们来考虑一种 Dialogue: 0,0:06:28.84,0:06:30.27,Default,,0,0,0,,我们可能会遇到的情况 Dialogue: 0,0:06:33.07,0:06:34.51,Default,,0,0,0,,比如说 Dialogue: 0,0:06:35.42,0:06:37.34,Default,,0,0,0,,我想要定义这样的一个过程 Dialogue: 0,0:06:37.95,0:06:41.36,Default,,0,0,0,,它有一个必选参数X Dialogue: 0,0:06:42.20,0:06:45.26,Default,,0,0,0,,还有个可选参数 -- 或者说一堆参数 Dialogue: 0,0:06:45.28,0:06:47.23,Default,,0,0,0,,我不知道它们的数目 就记作Y吧 Dialogue: 0,0:06:49.09,0:06:50.36,Default,,0,0,0,,X是必选的 Dialogue: 0,0:06:55.88,0:06:57.44,Default,,0,0,0,,然而有很多参数Y Dialogue: 0,0:06:59.53,0:07:05.99,Default,,0,0,0,,这些参数形成的表 -- 我就记作Y Dialogue: 0,0:07:14.48,0:07:16.06,Default,,0,0,0,,写好了参数表 Dialogue: 0,0:07:16.09,0:07:17.68,Default,,0,0,0,,我现在要这样定义过程体 Dialogue: 0,0:07:19.02,0:07:21.98,Default,,0,0,0,,我要对每一个元素都做同样的处理 Dialogue: 0,0:07:22.52,0:07:25.76,Default,,0,0,0,,(MAP (LAMBDA (U) Dialogue: 0,0:07:27.00,0:07:34.54,Default,,0,0,0,,(* X U)) Y) Dialogue: 0,0:07:36.89,0:07:38.04,Default,,0,0,0,,这里 我用了一个“点号” Dialogue: 0,0:07:38.59,0:07:41.31,Default,,0,0,0,,来表明点号后面的东西 Dialogue: 0,0:07:42.19,0:07:44.30,Default,,0,0,0,,是剩下的所有参数构成的表 Dialogue: 0,0:07:46.30,0:07:48.12,Default,,0,0,0,,这就是一个语法规范 Dialogue: 0,0:07:53.32,0:07:54.64,Default,,0,0,0,,为什么这样来写呢? Dialogue: 0,0:07:55.71,0:07:58.06,Default,,0,0,0,,这种语法规范之所以合理 Dialogue: 0,0:07:59.77,0:08:01.96,Default,,0,0,0,,是因为Lisp的源码读取器 Dialogue: 0,0:08:02.00,0:08:03.60,Default,,0,0,0,,刚好使用这种语法 Dialogue: 0,0:08:04.41,0:08:07.15,Default,,0,0,0,,来表示序对 Dialogue: 0,0:08:08.94,0:08:11.08,Default,,0,0,0,,我们之前没有介绍过 Dialogue: 0,0:08:11.08,0:08:12.78,Default,,0,0,0,,你在自己尝试的时候可能遇到过 Dialogue: 0,0:08:13.04,0:08:14.62,Default,,0,0,0,,当你调用(CONS X Y)时 Dialogue: 0,0:08:14.89,0:08:18.12,Default,,0,0,0,,你会得到 X . Y Dialogue: 0,0:08:19.79,0:08:22.83,Default,,0,0,0,,准确来说是(X . Y) Dialogue: 0,0:08:23.08,0:08:24.64,Default,,0,0,0,,两边还有括号 Dialogue: 0,0:08:26.98,0:08:28.16,Default,,0,0,0,,举例来说吧 Dialogue: 0,0:08:28.97,0:08:35.04,Default,,0,0,0,,这里的(X . Y)对应着一个序对 Dialogue: 0,0:08:36.33,0:08:39.29,Default,,0,0,0,,X是CAR部分 Y是CDR部分 Dialogue: 0,0:08:41.48,0:08:43.98,Default,,0,0,0,,你们目前为止见过的其它记号 Dialogue: 0,0:08:44.94,0:08:46.67,Default,,0,0,0,,是像 Dialogue: 0,0:08:46.92,0:08:55.24,Default,,0,0,0,,(LAMBDA (X Y Z) ...)这样的 Dialogue: 0,0:08:55.71,0:08:57.63,Default,,0,0,0,,它们则是像这样的 Dialogue: 0,0:09:02.00,0:09:03.61,Default,,0,0,0,,就拿形式参数表来说 Dialogue: 0,0:09:04.22,0:09:05.29,Default,,0,0,0,,它实际上是这样 Dialogue: 0,0:09:09.93,0:09:17.32,Default,,0,0,0,,这里分别是 X、Y、Z和空表 Dialogue: 0,0:09:18.28,0:09:21.08,Default,,0,0,0,,如果我有一个想要与之匹配的参数表的话 Dialogue: 0,0:09:22.60,0:09:25.60,Default,,0,0,0,,假设实际参数表是'(1 2 3) Dialogue: 0,0:09:25.87,0:09:27.26,Default,,0,0,0,,我想把它们和形参相匹配 Dialogue: 0,0:09:28.38,0:09:37.10,Default,,0,0,0,,所以这里 可能有个三个元素的表 Dialogue: 0,0:09:42.44,0:09:46.94,Default,,0,0,0,,分别是1、2、3 Dialogue: 0,0:09:48.99,0:09:53.16,Default,,0,0,0,,用'(1 2 3)来匹配'(X Y Z) Dialogue: 0,0:09:54.22,0:09:56.28,Default,,0,0,0,,很显然1和X相匹配 Dialogue: 0,0:09:56.32,0:09:58.01,Default,,0,0,0,,因为我可以顺着这个结构来 Dialogue: 0,0:09:58.86,0:10:01.56,Default,,0,0,0,,2和Y相匹配 Dialogue: 0,0:10:02.46,0:10:04.04,Default,,0,0,0,,3和Z相匹配 Dialogue: 0,0:10:05.48,0:10:09.53,Default,,0,0,0,,假设我现在要把这个(X . Y) Dialogue: 0,0:10:09.55,0:10:11.84,Default,,0,0,0,,这个是(X . Y) Dialogue: 0,0:10:12.51,0:10:16.91,Default,,0,0,0,,如果我想把它跟'(1 2 3)相匹配的话 Dialogue: 0,0:10:19.08,0:10:20.00,Default,,0,0,0,,我们再来看 Dialogue: 0,0:10:28.00,0:10:30.32,Default,,0,0,0,,这里是1、2、3 Dialogue: 0,0:10:30.86,0:10:32.88,Default,,0,0,0,,我可以沿着这里遍历 Dialogue: 0,0:10:32.99,0:10:35.50,Default,,0,0,0,,会发现 1和X相匹配 Dialogue: 0,0:10:37.56,0:10:41.84,Default,,0,0,0,,而Y和表'(2 3)相匹配 Dialogue: 0,0:10:43.74,0:10:46.22,Default,,0,0,0,,所以这里选用的表示法 Dialogue: 0,0:10:46.41,0:10:50.16,Default,,0,0,0,,对于Lisp来说是非常自然的 Dialogue: 0,0:10:52.66,0:10:54.14,Default,,0,0,0,,所以我就选择用这个记号 Dialogue: 0,0:10:54.17,0:10:55.80,Default,,0,0,0,,来表示数目不定的参数 Dialogue: 0,0:10:58.29,0:11:00.09,Default,,0,0,0,,还有一种可能性 Dialogue: 0,0:11:00.59,0:11:02.78,Default,,0,0,0,,如果我不是特别想命名某个参数 Dialogue: 0,0:11:03.00,0:11:05.00,Default,,0,0,0,,或者是命名某两个参数之类的 Dialogue: 0,0:11:06.54,0:11:07.56,Default,,0,0,0,,如果我不想那样的话 Dialogue: 0,0:11:08.78,0:11:10.44,Default,,0,0,0,,如果我想像+那样 Dialogue: 0,0:11:10.52,0:11:12.52,Default,,0,0,0,,一下子引用所有的参数 Dialogue: 0,0:11:13.88,0:11:17.96,Default,,0,0,0,,那么我就应该把参数表写成 Dialogue: 0,0:11:18.20,0:11:23.45,Default,,0,0,0,,(LAMBDA X ...) Dialogue: 0,0:11:25.14,0:11:26.30,Default,,0,0,0,,举例来说 Dialogue: 0,0:11:26.81,0:11:27.96,Default,,0,0,0,,如果我定义一个过程 Dialogue: 0,0:11:28.06,0:11:30.44,Default,,0,0,0,,它把接收所有的参数 Dialogue: 0,0:11:31.12,0:11:32.70,Default,,0,0,0,,然后返回一个由它们组成的表X Dialogue: 0,0:11:34.81,0:11:38.67,Default,,0,0,0,,返回的结果就是过程的参数表 明白吗? Dialogue: 0,0:11:45.85,0:11:46.67,Default,,0,0,0,,这又是怎么回事呢? Dialogue: 0,0:11:46.84,0:11:50.06,Default,,0,0,0,,实际上 无论我们的参数表是何种形式 Dialogue: 0,0:11:50.60,0:11:51.45,Default,,0,0,0,,无论是何种形式 Dialogue: 0,0:11:51.61,0:11:53.68,Default,,0,0,0,,都要与实际参数表相匹配 Dialogue: 0,0:11:55.14,0:11:57.14,Default,,0,0,0,,现在 这个符号就是所有的实际参数了 Dialogue: 0,0:12:01.49,0:12:05.13,Default,,0,0,0,,所以 我选择使用这个特定的语法规范 Dialogue: 0,0:12:05.64,0:12:07.63,Default,,0,0,0,,来描述那些 Dialogue: 0,0:12:08.04,0:12:10.56,Default,,0,0,0,,接收不定数目参数的过程 Dialogue: 0,0:12:13.45,0:12:14.60,Default,,0,0,0,,一共有两种情况 Dialogue: 0,0:12:15.40,0:12:16.35,Default,,0,0,0,,上面这种和下面这种 Dialogue: 0,0:12:17.44,0:12:18.36,Default,,0,0,0,,这两种都 -- Dialogue: 0,0:12:18.42,0:12:20.11,Default,,0,0,0,,当你们在制定语法规范时 Dialogue: 0,0:12:20.44,0:12:22.54,Default,,0,0,0,,千万注意不要有歧义 Dialogue: 0,0:12:23.56,0:12:27.36,Default,,0,0,0,,就比如说这里的两种情况 Dialogue: 0,0:12:27.66,0:12:31.20,Default,,0,0,0,,就不要与这里我们已有的这种混淆了 Dialogue: 0,0:12:33.61,0:12:35.82,Default,,0,0,0,,我总是可以区分出 Dialogue: 0,0:12:36.54,0:12:39.80,Default,,0,0,0,,过程的形式参数 Dialogue: 0,0:12:40.28,0:12:41.76,Default,,0,0,0,,是数目固定的具名参数 Dialogue: 0,0:12:42.64,0:12:43.13,Default,,0,0,0,,还是 Dialogue: 0,0:12:43.28,0:12:45.36,Default,,0,0,0,,既有数目固定的具名参数 Dialogue: 0,0:12:45.44,0:12:48.01,Default,,0,0,0,,又跟着数目可变的参数 Dialogue: 0,0:12:49.42,0:12:53.52,Default,,0,0,0,,又或者是所有参数组成的表 Dialogue: 0,0:12:53.68,0:12:56.52,Default,,0,0,0,,这个表会和这里的形式参数X相匹配 Dialogue: 0,0:12:56.99,0:12:58.84,Default,,0,0,0,,我都是可以从语法上区分它们 Dialogue: 0,0:13:02.25,0:13:04.62,Default,,0,0,0,,由于语言中存在语法歧义 Dialogue: 0,0:13:05.04,0:13:08.03,Default,,0,0,0,,整个待解释的程序被错误地分段 Dialogue: 0,0:13:08.64,0:13:13.92,Default,,0,0,0,,从而导致了可怕的错误 Dialogue: 0,0:13:14.56,0:13:16.67,Default,,0,0,0,,类Algol语言中就有些传统问题 Dialogue: 0,0:13:16.67,0:13:23.47,Default,,0,0,0,,就跟谓词部分的嵌套IF语句有关 Dialogue: 0,0:13:25.06,0:13:25.93,Default,,0,0,0,,总之 Dialogue: 0,0:13:27.52,0:13:29.44,Default,,0,0,0,,我现在已经把语法告诉你们了 Dialogue: 0,0:13:30.27,0:13:34.83,Default,,0,0,0,,我们要怎么来处理它的语义呢? Dialogue: 0,0:13:35.25,0:13:36.11,Default,,0,0,0,,我们如何来解释它? Dialogue: 0,0:13:36.59,0:13:37.96,Default,,0,0,0,,其实很简单 Dialogue: 0,0:13:38.44,0:13:42.57,Default,,0,0,0,,我修改一下元循环解释器就行 Dialogue: 0,0:13:43.71,0:13:44.76,Default,,0,0,0,,只需修改一行 Dialogue: 0,0:13:45.98,0:13:46.57,Default,,0,0,0,,在这里 Dialogue: 0,0:13:47.53,0:13:49.56,Default,,0,0,0,,我修改一下PAIR-UP过程 Dialogue: 0,0:13:50.81,0:13:54.19,Default,,0,0,0,,这里的PAIR-UP过程把 Dialogue: 0,0:13:56.76,0:14:02.03,Default,,0,0,0,,这是从上节课的元循环求值器中 Dialogue: 0,0:14:04.81,0:14:09.56,Default,,0,0,0,,摘录过来的PAIR-UP过程 Dialogue: 0,0:14:12.16,0:14:16.68,Default,,0,0,0,,它把形式参数与传递过来的实际参数匹配起来 Dialogue: 0,0:14:18.96,0:14:21.93,Default,,0,0,0,,大部分地方都和以前一样 Dialogue: 0,0:14:22.67,0:14:23.23,Default,,0,0,0,,也就是说 Dialogue: 0,0:14:23.31,0:14:25.07,Default,,0,0,0,,如果变量表为空 Dialogue: 0,0:14:25.52,0:14:27.31,Default,,0,0,0,,并且值表也为空 Dialogue: 0,0:14:27.45,0:14:29.61,Default,,0,0,0,,就返回空表 Dialogue: 0,0:14:31.05,0:14:33.00,Default,,0,0,0,,否则就是参数过多 Dialogue: 0,0:14:33.98,0:14:40.19,Default,,0,0,0,,如果变量表为空 但值表非空 Dialogue: 0,0:14:41.58,0:14:44.00,Default,,0,0,0,,如果值表为空 Dialogue: 0,0:14:44.96,0:14:47.47,Default,,0,0,0,,但是变量表又非空 Dialogue: 0,0:14:47.48,0:14:48.56,Default,,0,0,0,,那就是实际参数少了 Dialogue: 0,0:14:48.94,0:14:51.31,Default,,0,0,0,,然而如果我有一个变量是符号的话 Dialogue: 0,0:14:55.53,0:14:56.49,Default,,0,0,0,,这就有意思了 Dialogue: 0,0:14:58.30,0:15:04.40,Default,,0,0,0,,那么 我就认为遇到了特殊情况 Dialogue: 0,0:15:04.59,0:15:06.51,Default,,0,0,0,,也就是尾部分为符号的情况 Dialogue: 0,0:15:08.35,0:15:14.11,Default,,0,0,0,,情况就像这里的一样 Dialogue: 0,0:15:14.90,0:15:17.87,Default,,0,0,0,,这个尾部分就是一个符号Y Dialogue: 0,0:15:18.63,0:15:19.39,Default,,0,0,0,,它不是NIL Dialogue: 0,0:15:20.73,0:15:21.72,Default,,0,0,0,,不是个空表 Dialogue: 0,0:15:23.26,0:15:25.60,Default,,0,0,0,,而这个一开始就是个符号 Dialogue: 0,0:15:25.98,0:15:26.81,Default,,0,0,0,,就没有别的东西了 Dialogue: 0,0:15:27.79,0:15:28.72,Default,,0,0,0,,这种情况下 Dialogue: 0,0:15:29.96,0:15:37.20,Default,,0,0,0,,我就用这个符号去匹配所有的值 Dialogue: 0,0:15:38.03,0:15:42.52,Default,,0,0,0,,并把它们添加到要返回的结果中 Dialogue: 0,0:15:44.50,0:15:46.91,Default,,0,0,0,,否则的话 我就像正常情况那样 Dialogue: 0,0:15:47.15,0:15:48.52,Default,,0,0,0,,来创建所有的配对 Dialogue: 0,0:15:52.02,0:15:53.82,Default,,0,0,0,,我认为这很容易理解 Dialogue: 0,0:15:54.51,0:15:55.84,Default,,0,0,0,,就是这些 Dialogue: 0,0:15:57.08,0:15:58.33,Default,,0,0,0,,现在 答疑时间 Dialogue: 0,0:16:02.62,0:16:05.05,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:16:06.60,0:16:06.94,Default,,0,0,0,,你说 Dialogue: 0,0:16:07.37,0:16:09.92,Default,,0,0,0,,学生:你能再解释一下第三种形式吗? Dialogue: 0,0:16:09.98,0:16:12.12,Default,,0,0,0,,教授:第三种?这个? Dialogue: 0,0:16:12.59,0:16:14.27,Default,,0,0,0,,或许你用表结构来思考 Dialogue: 0,0:16:14.30,0:16:16.24,Default,,0,0,0,,会更容易理解一些 Dialogue: 0,0:16:18.57,0:16:22.73,Default,,0,0,0,,这是一个过程 包含一个LAMBDA Dialogue: 0,0:16:25.85,0:16:29.61,Default,,0,0,0,,我画出来的这个表结构就代表上面的这个 Dialogue: 0,0:16:31.26,0:16:32.44,Default,,0,0,0,,这里是X Dialogue: 0,0:16:32.73,0:16:33.98,Default,,0,0,0,,这些是我们的符号 Dialogue: 0,0:16:37.41,0:16:39.58,Default,,0,0,0,,过程体就是X而已 Dialogue: 0,0:16:44.84,0:16:48.75,Default,,0,0,0,,如果我需要这个过程的形式参数表 Dialogue: 0,0:16:50.09,0:16:51.58,Default,,0,0,0,,我就取它的CADR部分 Dialogue: 0,0:16:52.14,0:16:53.16,Default,,0,0,0,,我会得到一个符号 Dialogue: 0,0:16:54.01,0:16:57.16,Default,,0,0,0,,所以我们的匹配器 -- 也就是我给你们展示的PAIR-UP过程 Dialogue: 0,0:16:58.24,0:17:00.44,Default,,0,0,0,,就会把这个符号对象 Dialogue: 0,0:17:01.56,0:17:04.40,Default,,0,0,0,,跟我们传递的实际参数表相匹配了 Dialogue: 0,0:17:05.76,0:17:09.55,Default,,0,0,0,,这个符号与实际参数表相绑定 Dialogue: 0,0:17:11.37,0:17:16.48,Default,,0,0,0,,而在这个例子中 如果我去取它的话 Dialogue: 0,0:17:16.92,0:17:20.97,Default,,0,0,0,,匹配器就会把它与变量表的这个部分相匹配 Dialogue: 0,0:17:24.14,0:17:26.14,Default,,0,0,0,,如果一个过程只是 Dialogue: 0,0:17:26.17,0:17:29.13,Default,,0,0,0,,直接返回得到的参数表的话 返回的就是一个表 Dialogue: 0,0:17:30.40,0:17:31.39,Default,,0,0,0,,这个过程就是这样的 Dialogue: 0,0:17:34.51,0:17:35.48,Default,,0,0,0,,好吧 谢谢大家 Dialogue: 0,0:17:36.14,0:17:37.28,Default,,0,0,0,,大家休息一下吧 Dialogue: 0,0:17:37.83,0:17:55.36,Default,,0,0,0,,[音乐] Dialogue: 0,0:17:55.36,0:17:59.02,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:18:03.53,0:18:07.56,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:18:07.56,0:18:11.69,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:18:12.25,0:18:16.11,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 II Dialogue: 0,0:18:20.86,0:18:21.61,Default,,0,0,0,,教授:我们接着来看 Dialogue: 0,0:18:23.26,0:18:26.32,Default,,0,0,0,,现在 我将介绍一种相当重要的变种 Dialogue: 0,0:18:27.45,0:18:31.04,Default,,0,0,0,,这种变体非常有名 Dialogue: 0,0:18:31.60,0:18:36.80,Default,,0,0,0,,早期的很多Lisp都支持它 Dialogue: 0,0:18:38.25,0:18:40.06,Default,,0,0,0,,它被称为变量的动态绑定 Dialogue: 0,0:18:41.77,0:18:44.68,Default,,0,0,0,,我们现在来研究一下它 Dialogue: 0,0:18:47.62,0:18:50.16,Default,,0,0,0,,我先来介绍一下是什么导致 Dialogue: 0,0:18:50.35,0:18:52.36,Default,,0,0,0,,人们产生这样的想法 Dialogue: 0,0:18:53.74,0:18:55.23,Default,,0,0,0,,然而我并不会直接点明原因 Dialogue: 0,0:18:55.40,0:18:57.60,Default,,0,0,0,,我来举一个例子 你们来感受一下 Dialogue: 0,0:18:58.64,0:18:59.93,Default,,0,0,0,,假设 Dialogue: 0,0:19:00.75,0:19:02.59,Default,,0,0,0,,我们再来考察一下 Dialogue: 0,0:19:05.02,0:19:06.43,Default,,0,0,0,,计算一系列数之和的SUM过程 Dialogue: 0,0:19:08.14,0:19:09.47,Default,,0,0,0,,它的参数为 Dialogue: 0,0:19:09.60,0:19:10.78,Default,,0,0,0,,计算当前项的TERM Dialogue: 0,0:19:13.04,0:19:14.41,Default,,0,0,0,,下界A Dialogue: 0,0:19:15.24,0:19:17.04,Default,,0,0,0,,计算下一项索引的NEXT Dialogue: 0,0:19:17.24,0:19:18.56,Default,,0,0,0,,上界B Dialogue: 0,0:19:19.36,0:19:20.16,Default,,0,0,0,,过程体是 Dialogue: 0,0:19:23.16,0:19:26.94,Default,,0,0,0,,如果A>B Dialogue: 0,0:19:27.15,0:19:28.64,Default,,0,0,0,,那么结果就是0 Dialogue: 0,0:19:30.24,0:19:31.08,Default,,0,0,0,,否则就是 Dialogue: 0,0:19:33.68,0:19:39.82,Default,,0,0,0,,(+ (TERM A) Dialogue: 0,0:19:40.60,0:19:44.24,Default,,0,0,0,,(SUM TERM Dialogue: 0,0:19:47.68,0:19:52.64,Default,,0,0,0,,(NEXT A) Dialogue: 0,0:20:00.30,0:20:03.56,Default,,0,0,0,,这个NEXT过程直接传递过去 Dialogue: 0,0:20:06.40,0:20:08.25,Default,,0,0,0,,上界B也直接传递过去 Dialogue: 0,0:20:14.51,0:20:15.76,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:20:17.82,0:20:21.45,Default,,0,0,0,,当我使用SUM过程的时候 Dialogue: 0,0:20:21.96,0:20:24.35,Default,,0,0,0,,我可以像这样来用 Dialogue: 0,0:20:25.45,0:20:38.04,Default,,0,0,0,,我们可以把SUM-POWERS过程定义为 Dialogue: 0,0:20:38.08,0:20:40.33,Default,,0,0,0,,这个函数是用来计算Σ(X^N)的 Dialogue: 0,0:20:41.10,0:20:45.93,Default,,0,0,0,,它的参数有A、B以及N Dialogue: 0,0:20:45.95,0:20:47.69,Default,,0,0,0,,分别指下界、上界以及指数 Dialogue: 0,0:20:48.06,0:20:53.34,Default,,0,0,0,,它的定义是(SUM (LAMBDA (X) Dialogue: 0,0:20:53.60,0:20:59.31,Default,,0,0,0,,这个参数为X的过程计算(EXPT X N) Dialogue: 0,0:21:02.19,0:21:09.29,Default,,0,0,0,,我们还要传递A、1+还有B Dialogue: 0,0:21:11.82,0:21:15.76,Default,,0,0,0,,因此 给定一系列X 我们计算Σ(X^N)的值 Dialogue: 0,0:21:16.14,0:21:19.74,Default,,0,0,0,,X从A到B取值 步长为1 Dialogue: 0,0:21:22.94,0:21:24.38,Default,,0,0,0,,我也可以定义-- Dialogue: 0,0:21:27.68,0:21:28.20,Default,,0,0,0,,好像这里有点问题 Dialogue: 0,0:21:29.78,0:21:31.02,Default,,0,0,0,,不好意思 Dialogue: 0,0:21:31.91,0:21:33.36,Default,,0,0,0,,这里应该是PRODUCT-POWERS Dialogue: 0,0:21:38.08,0:21:39.12,Default,,0,0,0,,名字有点奇怪 Dialogue: 0,0:21:40.02,0:21:40.80,Default,,0,0,0,,还是不改了 Dialogue: 0,0:21:41.96,0:21:46.32,Default,,0,0,0,,有点怪 就按原来的吧 Dialogue: 0,0:21:49.34,0:21:50.19,Default,,0,0,0,,这回应该对了 Dialogue: 0,0:21:51.37,0:21:53.82,Default,,0,0,0,,而PRODUCT-POWERS的定义则是 Dialogue: 0,0:21:58.41,0:22:02.36,Default,,0,0,0,,(意义不明) Dialogue: 0,0:22:03.00,0:22:06.81,Default,,0,0,0,,我可以用像SUM一样的过程 Dialogue: 0,0:22:06.81,0:22:08.22,Default,,0,0,0,,只不过是用来计算乘积的 Dialogue: 0,0:22:08.56,0:22:11.05,Default,,0,0,0,,但是很类似 就跟你们在那里见到的一样 Dialogue: 0,0:22:11.45,0:22:16.38,Default,,0,0,0,,它也是一个三参数的过程 Dialogue: 0,0:22:17.00,0:22:25.42,Default,,0,0,0,,求积的因数是通过构造而来 Dialogue: 0,0:22:25.66,0:22:31.60,Default,,0,0,0,,也就是(PRODUCT (LAMBDA (X) (EXPT X N)) Dialogue: 0,0:22:34.43,0:22:37.85,Default,,0,0,0,,下界是A 步长为1 上界为B Dialogue: 0,0:22:41.53,0:22:41.88,Default,,0,0,0,,现在 Dialogue: 0,0:22:46.83,0:22:49.50,Default,,0,0,0,,你可能马上就意识到一些问题 Dialogue: 0,0:22:50.75,0:22:52.01,Default,,0,0,0,,它们看起来几乎一样 Dialogue: 0,0:22:53.18,0:22:55.20,Default,,0,0,0,,为什么要重复写代码呢? Dialogue: 0,0:22:56.59,0:22:59.72,Default,,0,0,0,,现在就很像我们之前遇到的情况了 Dialogue: 0,0:23:01.00,0:23:03.15,Default,,0,0,0,,构建一个抽象不是更好吗? Dialogue: 0,0:23:03.81,0:23:05.76,Default,,0,0,0,,如何构建良好的抽象呢? Dialogue: 0,0:23:05.85,0:23:07.55,Default,,0,0,0,,我看到有一些完全相同的代码 Dialogue: 0,0:23:08.47,0:23:09.32,Default,,0,0,0,,这有一段 Dialogue: 0,0:23:09.98,0:23:11.08,Default,,0,0,0,,这是另一段 Dialogue: 0,0:23:14.45,0:23:16.22,Default,,0,0,0,,所以我应该把它们提取出来 Dialogue: 0,0:23:17.09,0:23:19.23,Default,,0,0,0,,我就会想 Dialogue: 0,0:23:20.51,0:23:22.67,Default,,0,0,0,,SUM-POWERS可以用 Dialogue: 0,0:23:22.88,0:23:24.52,Default,,0,0,0,,NTH-POWERS的过程来编写 Dialogue: 0,0:23:25.71,0:23:27.40,Default,,0,0,0,,假如有人想写一个 Dialogue: 0,0:23:27.74,0:23:30.03,Default,,0,0,0,,稍微不同的过程 就像这个一样 Dialogue: 0,0:23:37.63,0:23:45.18,Default,,0,0,0,,(DEFINE SUM-POWERS Dialogue: 0,0:23:46.44,0:23:48.46,Default,,0,0,0,,(LAMBDA (A B N) Dialogue: 0,0:23:48.75,0:23:52.27,Default,,0,0,0,,(SUM (NTH-POWER Dialogue: 0,0:23:53.88,0:23:55.42,Default,,0,0,0,,我们调用过程NTH-POWER Dialogue: 0,0:23:58.35,0:24:02.27,Default,,0,0,0,,下界为A 步长为1 上界为B Dialogue: 0,0:24:05.74,0:24:06.91,Default,,0,0,0,,类似地 Dialogue: 0,0:24:10.65,0:24:12.76,Default,,0,0,0,,我想用这种方式来重写PRODUCT-POWERS Dialogue: 0,0:24:12.89,0:24:15.24,Default,,0,0,0,,把求幂指数从这里抽象出来 Dialogue: 0,0:24:16.27,0:24:17.37,Default,,0,0,0,,可以这样写 Dialogue: 0,0:24:22.10,0:24:23.02,Default,,0,0,0,,(DEFINE PRODUCT-POWERS Dialogue: 0,0:24:29.48,0:24:34.94,Default,,0,0,0,,(LAMBDA (A B N) Dialogue: 0,0:24:35.31,0:24:42.33,Default,,0,0,0,,(PRODUCT NTH-POWERS Dialogue: 0,0:24:46.44,0:24:50.30,Default,,0,0,0,,A 1+ B))) Dialogue: 0,0:24:53.50,0:24:57.56,Default,,0,0,0,,把NTH-POWER的结果作为PRODUCT的参数 Dialogue: 0,0:24:58.38,0:25:00.24,Default,,0,0,0,,我们还需要定义 Dialogue: 0,0:25:02.04,0:25:03.88,Default,,0,0,0,,还需要定义过程NTH-POWERS Dialogue: 0,0:25:04.89,0:25:05.93,Default,,0,0,0,,我把它写在这边 Dialogue: 0,0:25:12.22,0:25:12.99,Default,,0,0,0,,写在上面 Dialogue: 0,0:25:25.41,0:25:29.04,Default,,0,0,0,,它是一个参数为X的过程 Dialogue: 0,0:25:29.60,0:25:34.56,Default,,0,0,0,,计算(EXPT X N) Dialogue: 0,0:25:35.93,0:25:36.96,Default,,0,0,0,,但是我遇到一个问题 Dialogue: 0,0:25:38.64,0:25:39.93,Default,,0,0,0,,我们使用的环境模型 Dialogue: 0,0:25:40.57,0:25:43.23,Default,,0,0,0,,我们用来解释 Dialogue: 0,0:25:44.00,0:25:45.95,Default,,0,0,0,,目前所定义的语言的这种手段 Dialogue: 0,0:25:46.27,0:25:48.81,Default,,0,0,0,,并没有给我说明这个N的值 Dialogue: 0,0:25:52.76,0:25:59.26,Default,,0,0,0,,因为 正如大家所知 Dialogue: 0,0:26:00.76,0:26:04.25,Default,,0,0,0,,在这个过程中 N是自由变量 Dialogue: 0,0:26:06.41,0:26:07.98,Default,,0,0,0,,环境模型告诉我们 Dialogue: 0,0:26:08.60,0:26:10.20,Default,,0,0,0,,自由变量的值 Dialogue: 0,0:26:11.21,0:26:14.99,Default,,0,0,0,,取决于过程被定义时所在的环境 Dialogue: 0,0:26:16.64,0:26:17.47,Default,,0,0,0,,在我编写它们的时候 Dialogue: 0,0:26:17.48,0:26:19.84,Default,,0,0,0,,就假设它们已经在黑板上被定义了 Dialogue: 0,0:26:21.64,0:26:23.63,Default,,0,0,0,,NTH-POWER是定义在全局环境下的 Dialogue: 0,0:26:24.06,0:26:25.15,Default,,0,0,0,,其中没有N的定义 Dialogue: 0,0:26:25.93,0:26:27.63,Default,,0,0,0,,因此 N是未绑定的变量 Dialogue: 0,0:26:28.72,0:26:31.66,Default,,0,0,0,,但对我们来说 Dialogue: 0,0:26:32.60,0:26:36.32,Default,,0,0,0,,我们明确希望它是这里和这里的N Dialogue: 0,0:26:38.99,0:26:42.67,Default,,0,0,0,,另外一方面 Dialogue: 0,0:26:42.84,0:26:44.28,Default,,0,0,0,,当然我们要十分小心地确保 Dialogue: 0,0:26:44.56,0:26:46.06,Default,,0,0,0,,这里的N是这里的N Dialogue: 0,0:26:48.96,0:26:52.83,Default,,0,0,0,,还有这里的这个 要跟这里的一致 Dialogue: 0,0:26:57.39,0:26:59.74,Default,,0,0,0,,这种想法造就了 Dialogue: 0,0:27:00.67,0:27:02.72,Default,,0,0,0,,一个非常著名的BUG Dialogue: 0,0:27:04.65,0:27:06.04,Default,,0,0,0,,我来细说下这个BUG Dialogue: 0,0:27:07.15,0:27:09.40,Default,,0,0,0,,请看这张幻灯片 Dialogue: 0,0:27:10.66,0:27:12.70,Default,,0,0,0,,这种想法被称作“动态绑定” Dialogue: 0,0:27:13.99,0:27:16.91,Default,,0,0,0,,在这种情况下 自由变量不再被 Dialogue: 0,0:27:17.76,0:27:21.23,Default,,0,0,0,,定义过程时的环境所解释 Dialogue: 0,0:27:22.40,0:27:25.16,Default,,0,0,0,,这种情况下 自由变量的值 Dialogue: 0,0:27:25.44,0:27:29.31,Default,,0,0,0,,就像是存储在过程调用者的环境中一样 Dialogue: 0,0:27:31.85,0:27:34.84,Default,,0,0,0,,所以在这个系统中 Dialogue: 0,0:27:34.86,0:27:39.68,Default,,0,0,0,,你需要不断地搜索调用过程的调用者的环境 Dialogue: 0,0:27:40.43,0:27:42.65,Default,,0,0,0,,当然 在本例中 Dialogue: 0,0:27:42.84,0:27:44.30,Default,,0,0,0,,无论NTH-POWER在何处定义 Dialogue: 0,0:27:44.33,0:27:45.98,Default,,0,0,0,,它都是在PRODUCT过程中被调用的 Dialogue: 0,0:27:46.41,0:27:48.68,Default,,0,0,0,,我就需要在SUM过程中再编写一个类似的过程 Dialogue: 0,0:27:50.51,0:27:54.92,Default,,0,0,0,,而PRODUCT又是被PRODUCT-POWERS所调用 Dialogue: 0,0:27:55.13,0:27:56.14,Default,,0,0,0,,就是你们在这里看到的 Dialogue: 0,0:27:56.83,0:27:59.37,Default,,0,0,0,,由于PRODUCT-POWERS过程绑定了变量N Dialogue: 0,0:28:00.09,0:28:04.09,Default,,0,0,0,,因此NTH-POWER中的N会从这个链中派生出来 Dialogue: 0,0:28:08.14,0:28:09.64,Default,,0,0,0,,相似地 这个N Dialogue: 0,0:28:10.11,0:28:12.01,Default,,0,0,0,,NTH-POWER中的N在这种情况下 Dialogue: 0,0:28:12.32,0:28:15.80,Default,,0,0,0,,可能是来自于这里SUM过程的调用 Dialogue: 0,0:28:15.80,0:28:18.27,Default,,0,0,0,,你们可以从这里看到 它在SUM内部被调用 Dialogue: 0,0:28:20.73,0:28:21.69,Default,,0,0,0,,对应这里的TERM Dialogue: 0,0:28:22.90,0:28:25.72,Default,,0,0,0,,而SUM是在SUM-POWERS的内部被调用 Dialogue: 0,0:28:26.94,0:28:27.96,Default,,0,0,0,,后者绑定了N Dialogue: 0,0:28:28.93,0:28:30.65,Default,,0,0,0,,因此这里就有一个N Dialogue: 0,0:28:32.75,0:28:36.11,Default,,0,0,0,,可供NTH-POWER中的N取值 Dialogue: 0,0:28:37.95,0:28:39.24,Default,,0,0,0,,这就是动态 -- Dialogue: 0,0:28:39.28,0:28:43.10,Default,,0,0,0,,这条白线以下的东西 再加上这部分 Dialogue: 0,0:28:43.31,0:28:46.04,Default,,0,0,0,,就是我们所谓的动态绑定 Dialogue: 0,0:28:46.59,0:28:49.00,Default,,0,0,0,,用动态绑定的角度来解释 就可以正常运行 Dialogue: 0,0:28:50.85,0:28:52.65,Default,,0,0,0,,现在 让我们来看一个例子 Dialogue: 0,0:28:54.54,0:28:55.99,Default,,0,0,0,,要怎么实现这个功能 Dialogue: 0,0:28:55.99,0:28:56.96,Default,,0,0,0,,非常简单 Dialogue: 0,0:28:57.48,0:28:59.34,Default,,0,0,0,,事实上 最早的Lisp实现 Dialogue: 0,0:29:00.01,0:29:02.52,Default,,0,0,0,,对自由变量有各种形式的解释 Dialogue: 0,0:29:03.31,0:29:05.98,Default,,0,0,0,,包括用动态绑定来解释自由变量 Dialogue: 0,0:29:06.40,0:29:10.14,Default,,0,0,0,,APL也是用动态绑定来解释自由变量的 Dialogue: 0,0:29:11.68,0:29:14.32,Default,,0,0,0,,而不是词法绑定 或者说静态绑定 Dialogue: 0,0:29:15.22,0:29:17.00,Default,,0,0,0,,当然 要从EVAL开始修改 Dialogue: 0,0:29:19.31,0:29:20.59,Default,,0,0,0,,只需修改两个地方就行 Dialogue: 0,0:29:22.78,0:29:25.61,Default,,0,0,0,,首先我们会发现 Dialogue: 0,0:29:26.52,0:29:28.49,Default,,0,0,0,,事情变得更简单了 Dialogue: 0,0:29:29.39,0:29:33.63,Default,,0,0,0,,如果我不需要 Dialogue: 0,0:29:33.64,0:29:36.20,Default,,0,0,0,,在定义过程的那个环境中求值 Dialogue: 0,0:29:36.44,0:29:38.04,Default,,0,0,0,,过程在定义的时候就无需 Dialogue: 0,0:29:38.43,0:29:40.17,Default,,0,0,0,,捕获当时的环境了 Dialogue: 0,0:29:42.03,0:29:44.96,Default,,0,0,0,,所以我们可以在幻灯片的这里看到 Dialogue: 0,0:29:45.84,0:29:50.08,Default,,0,0,0,,这条用于判断是否为LAMBDA表达式的子句 Dialogue: 0,0:29:50.73,0:29:52.43,Default,,0,0,0,,过程就是在这个时候创建的 Dialogue: 0,0:29:53.92,0:29:56.73,Default,,0,0,0,,就不会返回一个带有类型标签 Dialogue: 0,0:29:56.75,0:30:01.05,Default,,0,0,0,,和环境结构的过程对象了 Dialogue: 0,0:30:01.29,0:30:02.54,Default,,0,0,0,,就是EXP本身 Dialogue: 0,0:30:02.54,0:30:04.76,Default,,0,0,0,,而我们会在其它地方用某种方式来解耦 Dialogue: 0,0:30:06.44,0:30:09.40,Default,,0,0,0,,另外一处修改就是组合式的应用 Dialogue: 0,0:30:10.36,0:30:13.69,Default,,0,0,0,,应用的时候必须要取得调用者的环境 Dialogue: 0,0:30:14.29,0:30:17.24,Default,,0,0,0,,调用者的环境就在这里 Dialogue: 0,0:30:17.26,0:30:19.45,Default,,0,0,0,,如果表达式是一个过程应用-- Dialogue: 0,0:30:19.56,0:30:21.63,Default,,0,0,0,,如果我们求值的是一个组合式 Dialogue: 0,0:30:21.79,0:30:23.71,Default,,0,0,0,,我们就会调用一个组合式 Dialogue: 0,0:30:23.93,0:30:25.50,Default,,0,0,0,,调用一个过程 Dialogue: 0,0:30:25.66,0:30:27.37,Default,,0,0,0,,来取得运算符的值 Dialogue: 0,0:30:29.84,0:30:31.44,Default,,0,0,0,,调用者的环境 Dialogue: 0,0:30:31.98,0:30:34.51,Default,,0,0,0,,就是我们当前的环境 Dialogue: 0,0:30:35.89,0:30:40.72,Default,,0,0,0,,所以 我只需要要把这个环境传递给APPLY Dialogue: 0,0:30:41.49,0:30:42.75,Default,,0,0,0,,我们再来看看APPLY Dialogue: 0,0:30:43.58,0:30:44.97,Default,,0,0,0,,我们只需要 Dialogue: 0,0:30:45.71,0:30:48.41,Default,,0,0,0,,把参数列表加上一个环境ENV Dialogue: 0,0:30:48.78,0:30:55.68,Default,,0,0,0,,然后用这个环境来扩展环境 Dialogue: 0,0:30:56.67,0:30:59.02,Default,,0,0,0,,扩展把形式参数 Dialogue: 0,0:30:59.02,0:31:01.37,Default,,0,0,0,,和传递过来的实际参数绑定在一起的环境 Dialogue: 0,0:31:03.08,0:31:05.98,Default,,0,0,0,,而不再是之前由过程捕获的环境了 Dialogue: 0,0:31:06.81,0:31:09.45,Default,,0,0,0,,最早的Lisp偶然地采用了 Dialogue: 0,0:31:09.66,0:31:11.96,Default,,0,0,0,,这种最显然的方式实现 Dialogue: 0,0:31:14.13,0:31:16.68,Default,,0,0,0,,当然 像往常一样 人们习惯了并喜欢上了它 Dialogue: 0,0:31:17.25,0:31:18.27,Default,,0,0,0,,因此就有一些人说 Dialogue: 0,0:31:18.40,0:31:19.50,Default,,0,0,0,,“就应该这么来做” Dialogue: 0,0:31:21.59,0:31:24.09,Default,,0,0,0,,不幸的是 这导致一些严重的问题 Dialogue: 0,0:31:25.40,0:31:27.24,Default,,0,0,0,,最严重的一点是 Dialogue: 0,0:31:27.53,0:31:29.84,Default,,0,0,0,,采用动态绑定 Dialogue: 0,0:31:31.00,0:31:33.56,Default,,0,0,0,,破坏了模块性 Dialogue: 0,0:31:35.46,0:31:37.66,Default,,0,0,0,,如果有两个人在一个大型系统上协同工作 Dialogue: 0,0:31:38.57,0:31:40.01,Default,,0,0,0,,那么一个重要的原则就是 Dialogue: 0,0:31:40.35,0:31:42.19,Default,,0,0,0,,每个人所使用的名字 Dialogue: 0,0:31:42.99,0:31:44.58,Default,,0,0,0,,都不应该干扰到对方的名字 Dialogue: 0,0:31:47.93,0:31:50.78,Default,,0,0,0,,如果我写了一段代码 Dialogue: 0,0:31:51.07,0:31:53.13,Default,,0,0,0,,别人就不能通过在他代码内部 Dialogue: 0,0:31:53.88,0:31:56.57,Default,,0,0,0,,使用我代码中的名字来破坏我的代码 Dialogue: 0,0:31:56.75,0:31:57.71,Default,,0,0,0,,这一点很重要 Dialogue: 0,0:31:59.85,0:32:00.46,Default,,0,0,0,,然而 Dialogue: 0,0:32:01.04,0:32:05.18,Default,,0,0,0,,动态绑定明显地违背了这种特定的模块化约束 Dialogue: 0,0:32:06.67,0:32:08.08,Default,,0,0,0,,我们考虑一下 Dialogue: 0,0:32:09.18,0:32:10.35,Default,,0,0,0,,这段代码会有什么效果? Dialogue: 0,0:32:12.54,0:32:13.79,Default,,0,0,0,,假设我想要把 Dialogue: 0,0:32:15.47,0:32:19.81,Default,,0,0,0,,我想要把变量NEXT换个名字 Dialogue: 0,0:32:19.81,0:32:24.41,Default,,0,0,0,,假设某个人要编写SUM过程 Dialogue: 0,0:32:25.10,0:32:26.68,Default,,0,0,0,,而别人则会使用这个SUM过程 Dialogue: 0,0:32:28.97,0:32:30.32,Default,,0,0,0,,编写SUM的那个人 Dialogue: 0,0:32:30.49,0:32:32.30,Default,,0,0,0,,可以选择他想要使用的名字 Dialogue: 0,0:32:33.66,0:32:34.84,Default,,0,0,0,,假设我就是那个编写者 Dialogue: 0,0:32:36.83,0:32:39.30,Default,,0,0,0,,刚巧 这里我不想用NEXT来表示 Dialogue: 0,0:32:39.30,0:32:40.09,Default,,0,0,0,,而是用N来表示 Dialogue: 0,0:32:41.74,0:32:43.10,Default,,0,0,0,,所以我把所有出现NEXT的地方 Dialogue: 0,0:32:44.28,0:32:45.26,Default,,0,0,0,,都换成N Dialogue: 0,0:32:48.14,0:32:48.48,Default,,0,0,0,,哎呀 Dialogue: 0,0:32:49.94,0:32:52.22,Default,,0,0,0,,我没有改变这个程序的规范 Dialogue: 0,0:32:53.32,0:32:54.86,Default,,0,0,0,,但是整个程序就崩溃了 Dialogue: 0,0:32:56.11,0:32:57.96,Default,,0,0,0,,不仅如此 这边也出现了问题 Dialogue: 0,0:32:59.50,0:33:01.40,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:33:02.26,0:33:03.24,Default,,0,0,0,,答案非常明显 Dialogue: 0,0:33:04.48,0:33:09.29,Default,,0,0,0,,NTH-POWER中的变量N的值 Dialogue: 0,0:33:09.31,0:33:13.72,Default,,0,0,0,,也就是这个N和这个N Dialogue: 0,0:33:14.97,0:33:17.16,Default,,0,0,0,,根据环境模型的定义 Dialogue: 0,0:33:17.20,0:33:19.58,Default,,0,0,0,,这两个N总是相关的 Dialogue: 0,0:33:19.87,0:33:21.48,Default,,0,0,0,,如果是根据环境模型的定义的话 Dialogue: 0,0:33:21.55,0:33:23.63,Default,,0,0,0,,因为N在这里被绑定 Dialogue: 0,0:33:24.37,0:33:26.25,Default,,0,0,0,,这个LAMBDA表达式是在 Dialogue: 0,0:33:26.59,0:33:28.59,Default,,0,0,0,,N被绑定的环境中执行的 Dialogue: 0,0:33:30.70,0:33:31.84,Default,,0,0,0,,如果不用环境模型的话 Dialogue: 0,0:33:32.01,0:33:33.68,Default,,0,0,0,,我必须追踪过程的调用链 Dialogue: 0,0:33:34.78,0:33:36.27,Default,,0,0,0,,那么就会发生糟糕的事儿 Dialogue: 0,0:33:37.32,0:33:41.18,Default,,0,0,0,,在SUM内部 这个是作为TERM调用的 Dialogue: 0,0:33:41.76,0:33:42.38,Default,,0,0,0,,这里的(TERM A) Dialogue: 0,0:33:44.78,0:33:46.19,Default,,0,0,0,,这时再来查找N的值 Dialogue: 0,0:33:47.35,0:33:48.40,Default,,0,0,0,,我得到的不知这个值 Dialogue: 0,0:33:48.84,0:33:49.76,Default,,0,0,0,,而是这个值 Dialogue: 0,0:33:50.70,0:33:52.54,Default,,0,0,0,,因此 只是这个程序的内部做了修改 Dialogue: 0,0:33:52.86,0:33:54.09,Default,,0,0,0,,这个程序却崩溃了 Dialogue: 0,0:33:56.77,0:34:00.08,Default,,0,0,0,,LAMBDA就不再像我以前说得那样是个量词了 Dialogue: 0,0:34:01.12,0:34:05.13,Default,,0,0,0,,LAMBDA应该是一个量词 Dialogue: 0,0:34:05.43,0:34:06.70,Default,,0,0,0,,量词有一个性质 Dialogue: 0,0:34:06.89,0:34:11.42,Default,,0,0,0,,被它绑定的名字都不重要 Dialogue: 0,0:34:12.65,0:34:15.71,Default,,0,0,0,,只要我用不在过程体中的新名字 Dialogue: 0,0:34:16.92,0:34:19.98,Default,,0,0,0,,统一地在过程体中代换旧名字 Dialogue: 0,0:34:20.94,0:34:23.16,Default,,0,0,0,,就不会改变表达式的语义 Dialogue: 0,0:34:24.04,0:34:25.50,Default,,0,0,0,,而我刚才却通过修改一个名字 Dialogue: 0,0:34:25.53,0:34:27.20,Default,,0,0,0,,改变了表达式的语义 Dialogue: 0,0:34:28.69,0:34:30.89,Default,,0,0,0,,因此LAMBDA就不再是一个良好定义的量词了 Dialogue: 0,0:34:32.17,0:34:33.37,Default,,0,0,0,,这个问题非常严重 Dialogue: 0,0:34:34.55,0:34:35.55,Default,,0,0,0,,正是因为这个原因 Dialogue: 0,0:34:36.64,0:34:42.51,Default,,0,0,0,,我和同事放弃了这种抽象方法 Dialogue: 0,0:34:43.13,0:34:44.36,Default,,0,0,0,,相对的 我更喜欢 Dialogue: 0,0:34:45.61,0:34:47.50,Default,,0,0,0,,模块化原则 Dialogue: 0,0:34:48.09,0:34:50.20,Default,,0,0,0,,如果你愿意探索解释器 Dialogue: 0,0:34:51.96,0:34:53.68,Default,,0,0,0,,那就非常值得做这类实验 Dialogue: 0,0:34:54.83,0:34:56.91,Default,,0,0,0,,你可以尝试多种设计 Dialogue: 0,0:34:58.11,0:35:00.25,Default,,0,0,0,,探索更优雅的语言设计 Dialogue: 0,0:35:02.68,0:35:04.49,Default,,0,0,0,,这是元循环求值器非常重要的功能 Dialogue: 0,0:35:04.99,0:35:06.68,Default,,0,0,0,,现在 我也想讲一讲 Dialogue: 0,0:35:06.72,0:35:08.49,Default,,0,0,0,,这种情况下的正确做法 Dialogue: 0,0:35:09.32,0:35:12.91,Default,,0,0,0,,我又如何来获得这种 Dialogue: 0,0:35:13.04,0:35:15.34,Default,,0,0,0,,词法作用域的能力呢? Dialogue: 0,0:35:16.28,0:35:17.39,Default,,0,0,0,,当然 实际情况是 Dialogue: 0,0:35:17.55,0:35:20.03,Default,,0,0,0,,在这里我想要的是 Dialogue: 0,0:35:20.68,0:35:22.60,Default,,0,0,0,,针对特定N的求指数函数 Dialogue: 0,0:35:23.69,0:35:24.28,Default,,0,0,0,,给定一个N Dialogue: 0,0:35:24.32,0:35:25.66,Default,,0,0,0,,它会返回给我一个特定的求指数过程 Dialogue: 0,0:35:26.28,0:35:27.40,Default,,0,0,0,,这非常简单 Dialogue: 0,0:35:28.17,0:35:30.57,Default,,0,0,0,,换言之 我可以这样来写 Dialogue: 0,0:35:35.84,0:35:37.84,Default,,0,0,0,,我要定义一个过程PGEN Dialogue: 0,0:35:40.25,0:35:42.54,Default,,0,0,0,,它有一个参数N Dialogue: 0,0:35:43.16,0:35:45.95,Default,,0,0,0,,返回一个指数过程 Dialogue: 0,0:35:50.24,0:35:51.23,Default,,0,0,0,,计算X^N Dialogue: 0,0:35:56.80,0:35:57.98,Default,,0,0,0,,有了这个以后 Dialogue: 0,0:35:58.59,0:36:00.88,Default,,0,0,0,,我就可以进行想要的那种抽象 Dialogue: 0,0:36:01.42,0:36:03.93,Default,,0,0,0,,甚至于现在的封装方法还要更好一些 Dialogue: 0,0:36:04.09,0:36:06.60,Default,,0,0,0,,因为系统现在不会因改名而崩溃了 Dialogue: 0,0:36:07.89,0:36:12.35,Default,,0,0,0,,(DEFINE SUM-POWERS Dialogue: 0,0:36:17.28,0:36:20.70,Default,,0,0,0,,(LAMBDA (A B N) Dialogue: 0,0:36:21.61,0:36:26.83,Default,,0,0,0,,(SUM Dialogue: 0,0:36:26.88,0:36:32.32,Default,,0,0,0,,(PGEN N) Dialogue: 0,0:36:34.40,0:36:38.01,Default,,0,0,0,,A 1+ B))) Dialogue: 0,0:36:42.49,0:36:47.95,Default,,0,0,0,,(DEFINE PRODUCT-POWERS Dialogue: 0,0:36:54.11,0:36:58.84,Default,,0,0,0,,(LAMBDA (A B N) Dialogue: 0,0:36:59.80,0:37:09.96,Default,,0,0,0,,(PRODUCT (PGEN N) A 1+ B))) Dialogue: 0,0:37:11.28,0:37:13.28,Default,,0,0,0,,当然 这只是一个非常简单的例子 Dialogue: 0,0:37:13.60,0:37:16.35,Default,,0,0,0,,这里 我想要抽象的对象也十分简单 Dialogue: 0,0:37:17.28,0:37:18.83,Default,,0,0,0,,但它也有可能是长达100行的代码 Dialogue: 0,0:37:20.10,0:37:23.67,Default,,0,0,0,,我这么写是为了保持简单 Dialogue: 0,0:37:23.67,0:37:24.57,Default,,0,0,0,,我给它命了名 Dialogue: 0,0:37:24.73,0:37:26.94,Default,,0,0,0,,这里它只是一个参数化的名字 Dialogue: 0,0:37:28.20,0:37:30.27,Default,,0,0,0,,这个名字显式地依赖于 Dialogue: 0,0:37:30.49,0:37:33.63,Default,,0,0,0,,词法作用域下N的值 Dialogue: 0,0:37:37.13,0:37:38.59,Default,,0,0,0,,因此可以把它看做一个很长的名字 Dialogue: 0,0:37:40.21,0:37:41.58,Default,,0,0,0,,这里 我是通过 Dialogue: 0,0:37:41.76,0:37:45.82,Default,,0,0,0,,为计算TERM的过程命名 Dialogue: 0,0:37:46.12,0:37:49.22,Default,,0,0,0,,来解决问题的 Dialogue: 0,0:37:55.08,0:37:55.87,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:37:57.00,0:37:58.38,Default,,0,0,0,,David 你说 Dialogue: 0,0:37:58.57,0:38:02.27,Default,,0,0,0,,学生:刚才那个问题 Dialogue: 0,0:38:03.07,0:38:06.46,Default,,0,0,0,,只能通过新建一个过程来解决吗? Dialogue: 0,0:38:06.47,0:38:08.92,Default,,0,0,0,,换句话说 是不是必须要语言能够 Dialogue: 0,0:38:08.99,0:38:11.56,Default,,0,0,0,,把对象定义为过程? Dialogue: 0,0:38:12.41,0:38:13.76,Default,,0,0,0,,教授:我明白了 Dialogue: 0,0:38:15.90,0:38:19.74,Default,,0,0,0,,我构建抽象的这种方法 Dialogue: 0,0:38:20.14,0:38:22.86,Default,,0,0,0,,需要过程能够返回或者导出一个过程 Dialogue: 0,0:38:23.26,0:38:26.81,Default,,0,0,0,,以便我不想让过程体中包含特定过程 Dialogue: 0,0:38:27.04,0:38:27.24,Default,,0,0,0,,学生:没错 Dialogue: 0,0:38:28.19,0:38:28.88,Default,,0,0,0,,教授:是这样的 Dialogue: 0,0:38:29.53,0:38:31.52,Default,,0,0,0,,如果我不能这么做的话 Dialogue: 0,0:38:32.24,0:38:35.13,Default,,0,0,0,,那么我就无法去构造一个抽象 Dialogue: 0,0:38:35.53,0:38:41.77,Default,,0,0,0,,使得符号之间不会出现冲突 Dialogue: 0,0:38:43.00,0:38:43.48,Default,,0,0,0,,你说得对 Dialogue: 0,0:38:44.14,0:38:46.51,Default,,0,0,0,,我认为 Dialogue: 0,0:38:46.54,0:38:48.91,Default,,0,0,0,,能够把过程作为返回值 Dialogue: 0,0:38:49.20,0:38:58.28,Default,,0,0,0,,更一般地说是支持“第一级过程” Dialogue: 0,0:38:59.13,0:39:02.46,Default,,0,0,0,,是模块化程序程序设计所必须的 Dialogue: 0,0:39:03.70,0:39:06.43,Default,,0,0,0,,有很多种方式来解决这个问题 Dialogue: 0,0:39:07.44,0:39:09.16,Default,,0,0,0,,你可以的做的就是 Dialogue: 0,0:39:09.18,0:39:11.84,Default,,0,0,0,,针对你所需要关心的每一种糟糕情况 Dialogue: 0,0:39:12.27,0:39:15.20,Default,,0,0,0,,你可以添加一个特殊的FEATURE来解决它 Dialogue: 0,0:39:15.84,0:39:17.12,Default,,0,0,0,,你可以做一个包系统 Dialogue: 0,0:39:17.74,0:39:21.16,Default,,0,0,0,,或者像Ada中的模块系统 等等 Dialogue: 0,0:39:22.24,0:39:24.88,Default,,0,0,0,,这些都可以 可能区别只是解决的程度不一 Dialogue: 0,0:39:26.44,0:39:28.38,Default,,0,0,0,,而能够把过程作为返回值 Dialogue: 0,0:39:28.41,0:39:29.74,Default,,0,0,0,,可以解决这所有的问题 Dialogue: 0,0:39:32.68,0:39:34.60,Default,,0,0,0,,这种最简单的机制 Dialogue: 0,0:39:35.58,0:39:37.79,Default,,0,0,0,,却可以给予你最好的模块性 Dialogue: 0,0:39:39.21,0:39:41.31,Default,,0,0,0,,它赋予你所有已知的模块机制 Dialogue: 0,0:39:45.59,0:39:48.24,Default,,0,0,0,,好的 该休息一会儿了 谢谢大家 Dialogue: 0,0:39:48.24,0:40:01.08,Default,,0,0,0,,[音乐] Dialogue: 0,0:40:01.28,0:40:04.75,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:40:25.69,0:40:29.42,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:40:30.01,0:40:33.28,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:40:34.17,0:40:37.61,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 II Dialogue: 0,0:40:42.32,0:40:44.28,Default,,0,0,0,,教授:昨天你们学习流的时候 Dialogue: 0,0:40:46.01,0:40:51.16,Default,,0,0,0,,Hal教授告诉了你们求值顺序 Dialogue: 0,0:40:51.95,0:40:53.87,Default,,0,0,0,,以及过程的延迟求值 Dialogue: 0,0:40:55.61,0:40:58.30,Default,,0,0,0,,昨天在讲流的时候 我们说 Dialogue: 0,0:41:00.25,0:41:04.22,Default,,0,0,0,,调用者和被调者都应该认同 Dialogue: 0,0:41:05.77,0:41:08.84,Default,,0,0,0,,参数是被延迟了的 Dialogue: 0,0:41:09.42,0:41:13.44,Default,,0,0,0,,如果被调者需要结果 就需要对参数FORCE Dialogue: 0,0:41:15.13,0:41:17.87,Default,,0,0,0,,因此在过程的设计者和使用者之间 Dialogue: 0,0:41:18.17,0:41:24.32,Default,,0,0,0,,就有很多关于延时求值的握手 Dialogue: 0,0:41:26.36,0:41:28.72,Default,,0,0,0,,当然 这看起来相当糟糕 Dialogue: 0,0:41:29.48,0:41:30.96,Default,,0,0,0,,虽说对于流没什么不妥 Dialogue: 0,0:41:31.74,0:41:32.86,Default,,0,0,0,,但作为一般性的原则来说 Dialogue: 0,0:41:32.92,0:41:36.32,Default,,0,0,0,,我们希望能有个地方 Dialogue: 0,0:41:36.46,0:41:38.49,Default,,0,0,0,,能够把我们的设计考虑 Dialogue: 0,0:41:38.89,0:41:41.28,Default,,0,0,0,,显式地、清晰地 Dialogue: 0,0:41:41.63,0:41:43.93,Default,,0,0,0,,标注出来 Dialogue: 0,0:41:45.88,0:41:49.28,Default,,0,0,0,,因此就不必在过程编写者 Dialogue: 0,0:41:50.46,0:41:54.89,Default,,0,0,0,,和使用者之间达成共识 Dialogue: 0,0:41:55.08,0:41:57.98,Default,,0,0,0,,有关于参数求值 Dialogue: 0,0:41:58.43,0:41:59.50,Default,,0,0,0,,以及求值顺序等细节 Dialogue: 0,0:41:59.50,0:42:00.75,Default,,0,0,0,,虽然 这也不是太糟糕 Dialogue: 0,0:42:01.02,0:42:03.95,Default,,0,0,0,,我的意思是 可能还有像“输入是一个数字”这样的共识 Dialogue: 0,0:42:05.20,0:42:06.08,Default,,0,0,0,,但是 Dialogue: 0,0:42:06.35,0:42:09.20,Default,,0,0,0,,如果其中一个人可以全权负责 就再好不过了 Dialogue: 0,0:42:11.02,0:42:13.31,Default,,0,0,0,,这个想法已经不算新潮了 Dialogue: 0,0:42:15.51,0:42:21.16,Default,,0,0,0,,Algol60就支持两种不同的过程调用方法 Dialogue: 0,0:42:22.02,0:42:24.28,Default,,0,0,0,,参数可以按名或按值传递 Dialogue: 0,0:42:25.59,0:42:27.48,Default,,0,0,0,,按名传递就意味着 Dialogue: 0,0:42:27.63,0:42:29.72,Default,,0,0,0,,参数会延时求值 Dialogue: 0,0:42:31.11,0:42:32.84,Default,,0,0,0,,当你按名传递一个参数时 Dialogue: 0,0:42:33.64,0:42:36.52,Default,,0,0,0,,只有你去取它的值的时候 Dialogue: 0,0:42:36.96,0:42:39.55,Default,,0,0,0,,它的值才会被计算出来 Dialogue: 0,0:42:42.29,0:42:44.20,Default,,0,0,0,,所以 现在我就要 Dialogue: 0,0:42:44.43,0:42:46.96,Default,,0,0,0,,像之前那样 Dialogue: 0,0:42:46.99,0:42:48.65,Default,,0,0,0,,对语言做出一些小小的修改 Dialogue: 0,0:42:50.32,0:42:51.79,Default,,0,0,0,,这里 我们再添加一个新的FEATURE Dialogue: 0,0:42:53.37,0:42:55.05,Default,,0,0,0,,我们要添加的FEATURE是 Dialogue: 0,0:42:55.36,0:42:58.73,Default,,0,0,0,,“按名传递参数” 或者可以叫做“延迟求值参数” Dialogue: 0,0:43:00.43,0:43:04.41,Default,,0,0,0,,因为事实上 Lisp系统中默认 Dialogue: 0,0:43:04.76,0:43:06.60,Default,,0,0,0,,传递的是一个指针 Dialogue: 0,0:43:08.22,0:43:09.15,Default,,0,0,0,,指针被复制了一份 Dialogue: 0,0:43:09.15,0:43:10.91,Default,,0,0,0,,但所指的数据结构却没有被复制 Dialogue: 0,0:43:13.41,0:43:14.84,Default,,0,0,0,,现在我要告诉你们 Dialogue: 0,0:43:15.04,0:43:18.38,Default,,0,0,0,,如何来添加按名传递参数 Dialogue: 0,0:43:19.99,0:43:22.12,Default,,0,0,0,,为什么我们需要这样的FEATURE呢? Dialogue: 0,0:43:23.10,0:43:24.72,Default,,0,0,0,,假设我们想要开发 Dialogue: 0,0:43:25.24,0:43:28.44,Default,,0,0,0,,像是某种特殊形式的功能 Dialogue: 0,0:43:28.73,0:43:29.72,Default,,0,0,0,,类似于“保留字” Dialogue: 0,0:43:29.72,0:43:31.48,Default,,0,0,0,,但不是用保留字的方式来实现 Dialogue: 0,0:43:32.18,0:43:34.76,Default,,0,0,0,,我想用过程来实现类似IF的效果 Dialogue: 0,0:43:36.36,0:43:39.42,Default,,0,0,0,,无论是IF还是COND 都是特殊形式 Dialogue: 0,0:43:39.42,0:43:40.43,Default,,0,0,0,,它俩是一样的 Dialogue: 0,0:43:40.59,0:43:42.86,Default,,0,0,0,,这个特殊形式用于 Dialogue: 0,0:43:42.92,0:43:45.02,Default,,0,0,0,,根据谓词返回真假 Dialogue: 0,0:43:46.22,0:43:49.76,Default,,0,0,0,,决定求值真子句还是假子句 Dialogue: 0,0:43:50.84,0:43:53.12,Default,,0,0,0,,它们都是根据某个值 Dialogue: 0,0:43:53.44,0:43:55.36,Default,,0,0,0,,来决定是否去做另外的某件事 Dialogue: 0,0:43:57.27,0:43:58.88,Default,,0,0,0,,然而像+之类的过程 Dialogue: 0,0:43:59.15,0:44:01.20,Default,,0,0,0,,也就是那些我们现在可以定义的过程 Dialogue: 0,0:44:01.42,0:44:06.56,Default,,0,0,0,,是在应用前就求值所有的参数 Dialogue: 0,0:44:08.67,0:44:09.64,Default,,0,0,0,,因此 举例来说 Dialogue: 0,0:44:10.46,0:44:12.41,Default,,0,0,0,,假设我想定义一个过程 Dialogue: 0,0:44:15.39,0:44:18.75,Default,,0,0,0,,用IF来实现与IF相反的效果 Dialogue: 0,0:44:19.85,0:44:20.70,Default,,0,0,0,,我叫它UNLESS Dialogue: 0,0:44:24.89,0:44:27.47,Default,,0,0,0,,参数是 谓词P、真子句C和假子句A Dialogue: 0,0:44:28.67,0:44:30.44,Default,,0,0,0,,接下来 我想 Dialogue: 0,0:44:30.46,0:44:32.08,Default,,0,0,0,,用COND来实现 Dialogue: 0,0:44:32.64,0:44:36.72,Default,,0,0,0,,(COND ((NOT P) Dialogue: 0,0:44:38.96,0:44:40.32,Default,,0,0,0,,结果就是真子句C Dialogue: 0,0:44:41.58,0:44:45.63,Default,,0,0,0,,否则就是假子句A Dialogue: 0,0:44:51.29,0:44:52.76,Default,,0,0,0,,我定义这个过程是为了 Dialogue: 0,0:44:53.32,0:44:55.40,Default,,0,0,0,,请考虑下面这种情况 Dialogue: 0,0:44:56.92,0:45:04.12,Default,,0,0,0,,(UNLESS (= 1 0) Dialogue: 0,0:45:05.08,0:45:06.64,Default,,0,0,0,,那么结果就是2 Dialogue: 0,0:45:07.90,0:45:11.35,Default,,0,0,0,,否则 结果就是(/ 1 0) Dialogue: 0,0:45:15.92,0:45:18.91,Default,,0,0,0,,这段代码相当于进行这样的代换: Dialogue: 0,0:45:20.00,0:45:23.26,Default,,0,0,0,,用(= 1 0)、2和(/ 1 0) Dialogue: 0,0:45:23.66,0:45:24.76,Default,,0,0,0,,分别代换上面的P、C以及A Dialogue: 0,0:45:25.58,0:45:27.58,Default,,0,0,0,,这样很有趣 Dialogue: 0,0:45:28.11,0:45:30.33,Default,,0,0,0,,代换后就变成了 Dialogue: 0,0:45:30.75,0:45:38.44,Default,,0,0,0,,(COND ((NOT (= 1 0)) Dialogue: 0,0:45:40.62,0:45:42.54,Default,,0,0,0,,结果就是2 Dialogue: 0,0:45:44.28,0:45:45.10,Default,,0,0,0,,否则就是 Dialogue: 0,0:45:48.22,0:45:51.16,Default,,0,0,0,,(/ 1 0) Dialogue: 0,0:45:54.48,0:45:56.48,Default,,0,0,0,,你们也知道 如果向Lisp中输入这段代码 Dialogue: 0,0:45:57.74,0:45:58.59,Default,,0,0,0,,结果会是2 Dialogue: 0,0:45:59.97,0:46:01.32,Default,,0,0,0,,这没问题 Dialogue: 0,0:46:02.91,0:46:04.64,Default,,0,0,0,,但如果我输入的是这段代码 Dialogue: 0,0:46:05.28,0:46:07.79,Default,,0,0,0,,由于参数会在过程调用前求值 Dialogue: 0,0:46:09.12,0:46:10.73,Default,,0,0,0,,那么这段代码就会报错 Dialogue: 0,0:46:13.38,0:46:15.61,Default,,0,0,0,,当然 如果成功进行代换的话 Dialogue: 0,0:46:16.03,0:46:16.88,Default,,0,0,0,,我可以得到正确的结果 Dialogue: 0,0:46:16.88,0:46:20.16,Default,,0,0,0,,但是这里这种情况 代换并不能进行 Dialogue: 0,0:46:22.17,0:46:23.86,Default,,0,0,0,,我连错误的结果都无法得到 Dialogue: 0,0:46:23.86,0:46:24.67,Default,,0,0,0,,没有结果 Dialogue: 0,0:46:24.80,0:46:25.60,Default,,0,0,0,,只能得到错误 Dialogue: 0,0:46:28.42,0:46:31.21,Default,,0,0,0,,现在 我要想办法 Dialogue: 0,0:46:31.61,0:46:32.99,Default,,0,0,0,,使这样的定义可以成功运行 Dialogue: 0,0:46:34.48,0:46:36.51,Default,,0,0,0,,但我想标注出 Dialogue: 0,0:46:36.70,0:46:38.76,Default,,0,0,0,,C和A是特殊的东西 Dialogue: 0,0:46:39.93,0:46:43.15,Default,,0,0,0,,我想使它们自动地延时求值 Dialogue: 0,0:46:44.27,0:46:48.08,Default,,0,0,0,,我不想它们在我调用过程的时候 Dialogue: 0,0:46:48.52,0:46:49.74,Default,,0,0,0,,就被求值 Dialogue: 0,0:46:51.52,0:46:52.72,Default,,0,0,0,,所以我得先制定一种声明 Dialogue: 0,0:46:52.75,0:46:55.32,Default,,0,0,0,,然后再考虑如何实现此种声明 Dialogue: 0,0:46:55.60,0:46:57.63,Default,,0,0,0,,再次强调 希望你们能够提醒自己 Dialogue: 0,0:46:57.79,0:47:00.25,Default,,0,0,0,,我们这里添加的是临时组件 Dialogue: 0,0:47:00.76,0:47:02.16,Default,,0,0,0,,必须要知道 Dialogue: 0,0:47:02.25,0:47:04.72,Default,,0,0,0,,滥用临时组件会造成大混乱 Dialogue: 0,0:47:05.75,0:47:09.79,Default,,0,0,0,,还会破坏一些已有的东西 Dialogue: 0,0:47:10.12,0:47:12.70,Default,,0,0,0,,首先 它会造成语法歧义性么? Dialogue: 0,0:47:13.86,0:47:15.50,Default,,0,0,0,,就我们目前已有的语法来说 Dialogue: 0,0:47:15.71,0:47:16.91,Default,,0,0,0,,它不会造成什么歧义 Dialogue: 0,0:47:17.84,0:47:20.76,Default,,0,0,0,,但接下来要做的却可能招来麻烦 Dialogue: 0,0:47:21.67,0:47:24.67,Default,,0,0,0,,我要添加的东西可能会跟 Dialogue: 0,0:47:25.15,0:47:27.10,Default,,0,0,0,,我以后添加的类型声明冲突 Dialogue: 0,0:47:28.19,0:47:31.08,Default,,0,0,0,,类型系统通过提供已知的类型信息 Dialogue: 0,0:47:31.21,0:47:33.66,Default,,0,0,0,,使得语言系统或者编译器可以做出优化 Dialogue: 0,0:47:34.75,0:47:36.97,Default,,0,0,0,,当然也会与我想添加的形式参数的 Dialogue: 0,0:47:37.00,0:47:39.71,Default,,0,0,0,,其它类型的声明相冲突 Dialogue: 0,0:47:40.57,0:47:42.56,Default,,0,0,0,,所以这里我并不打算做一个一般性的机制 Dialogue: 0,0:47:43.77,0:47:45.24,Default,,0,0,0,,使得我可以添加声明 Dialogue: 0,0:47:45.28,0:47:46.54,Default,,0,0,0,,虽然我很想那么做 Dialogue: 0,0:47:46.89,0:47:48.81,Default,,0,0,0,,但现在并不打算这么做 Dialogue: 0,0:47:51.01,0:47:53.88,Default,,0,0,0,,接下来 我要添加某种临时的解决方法 Dialogue: 0,0:47:57.56,0:48:08.38,Default,,0,0,0,,(DEFINE (UNLESS P Dialogue: 0,0:48:08.81,0:48:10.27,Default,,0,0,0,,后面的参数都是按名调用 Dialogue: 0,0:48:12.78,0:48:15.28,Default,,0,0,0,,分别记作(NAME C)和(NAME A) Dialogue: 0,0:48:19.85,0:48:25.28,Default,,0,0,0,,哈 哈 卡在黑板边了 Dialogue: 0,0:48:31.76,0:48:35.61,Default,,0,0,0,,(COND ((NOT P) C) Dialogue: 0,0:48:36.80,0:48:41.16,Default,,0,0,0,,(ELSE A))) Dialogue: 0,0:48:44.67,0:48:46.88,Default,,0,0,0,,我可以显式地声明 Dialogue: 0,0:48:47.55,0:48:51.65,Default,,0,0,0,,哪些参数按名称传递或延时求值 Dialogue: 0,0:48:55.60,0:48:58.48,Default,,0,0,0,,对解释器的这个修改并不简单 Dialogue: 0,0:48:58.70,0:48:59.77,Default,,0,0,0,,反而相当复杂 Dialogue: 0,0:49:00.45,0:49:03.10,Default,,0,0,0,,我们之前介绍的动态绑定 Dialogue: 0,0:49:03.40,0:49:06.89,Default,,0,0,0,,或者让过程支持不定数目的参数 Dialogue: 0,0:49:07.50,0:49:08.52,Default,,0,0,0,,都相对简单 Dialogue: 0,0:49:09.28,0:49:11.28,Default,,0,0,0,,这次的修改涉及基本策略 Dialogue: 0,0:49:12.32,0:49:13.39,Default,,0,0,0,,这里的问题是 Dialogue: 0,0:49:13.96,0:49:17.63,Default,,0,0,0,,我们的解释器 就如代码所写的那样 Dialogue: 0,0:49:17.96,0:49:23.40,Default,,0,0,0,,在求值组合式时 Dialogue: 0,0:49:24.24,0:49:25.92,Default,,0,0,0,,先通过求值运算符取得过程 Dialogue: 0,0:49:26.20,0:49:30.35,Default,,0,0,0,,然后再求值运算对象得到参数 Dialogue: 0,0:49:30.76,0:49:35.26,Default,,0,0,0,,再把过程应用到参数上 Dialogue: 0,0:49:36.38,0:49:37.07,Default,,0,0,0,,然而这里 Dialogue: 0,0:49:37.36,0:49:41.48,Default,,0,0,0,,直到我检查了整个过程 Dialogue: 0,0:49:41.74,0:49:43.66,Default,,0,0,0,,确定了程序的声明 Dialogue: 0,0:49:44.62,0:49:46.86,Default,,0,0,0,,才会去求值程序的参数 Dialogue: 0,0:49:49.59,0:49:50.59,Default,,0,0,0,,我们来看这个 Dialogue: 0,0:49:52.68,0:49:56.54,Default,,0,0,0,,这是修改后的求值器 Dialogue: 0,0:49:57.48,0:50:01.15,Default,,0,0,0,,我是基于那个最简单的词法作用域求值器 Dialogue: 0,0:50:01.72,0:50:02.65,Default,,0,0,0,,不是动态绑定的那个 Dialogue: 0,0:50:04.14,0:50:08.20,Default,,0,0,0,,但是却要做一些类似于动态绑定的修改 Dialogue: 0,0:50:09.75,0:50:11.45,Default,,0,0,0,,这是因为 Dialogue: 0,0:50:11.90,0:50:13.34,Default,,0,0,0,,如果我延时一个过程 -- Dialogue: 0,0:50:13.66,0:50:15.15,Default,,0,0,0,,哦说错了 -- 延时一个过程的参数 Dialogue: 0,0:50:15.40,0:50:17.52,Default,,0,0,0,,就必须把当前的环境和参数关联在一起 Dialogue: 0,0:50:19.36,0:50:21.55,Default,,0,0,0,,还记得Hal教授如何实现DELAY的吧? Dialogue: 0,0:50:23.38,0:50:25.44,Default,,0,0,0,,Hal教授把DELAY实现为 Dialogue: 0,0:50:25.50,0:50:27.47,Default,,0,0,0,,一个无参过程 Dialogue: 0,0:50:28.56,0:50:30.52,Default,,0,0,0,,用来执行某些表达式 Dialogue: 0,0:50:31.18,0:50:36.94,Default,,0,0,0,,就是这样让表达式延迟求值的 Dialogue: 0,0:50:39.29,0:50:40.99,Default,,0,0,0,,(DELAY E)实际上是这个 Dialogue: 0,0:50:44.52,0:50:46.92,Default,,0,0,0,,然而 如果我求值这个LAMBDA表达式 Dialogue: 0,0:50:47.42,0:50:49.20,Default,,0,0,0,,我就必须得捕获当前环境 Dialogue: 0,0:50:51.41,0:50:53.45,Default,,0,0,0,,这是因为 Dialogue: 0,0:50:54.60,0:50:56.32,Default,,0,0,0,,我想让这其中的变量的值 Dialogue: 0,0:50:57.02,0:51:00.83,Default,,0,0,0,,取决于它们被定义时的上下文 Dialogue: 0,0:51:04.01,0:51:05.76,Default,,0,0,0,,这也就是为什么要用LAMBDA表达式 Dialogue: 0,0:51:06.62,0:51:07.50,Default,,0,0,0,,这才是正确的 Dialogue: 0,0:51:08.07,0:51:15.12,Default,,0,0,0,,(FORCE E)则相当于 Dialogue: 0,0:51:16.52,0:51:20.08,Default,,0,0,0,,无参地调用这个过程 Dialogue: 0,0:51:21.09,0:51:22.28,Default,,0,0,0,,恰恰和上面相对 Dialogue: 0,0:51:24.10,0:51:26.94,Default,,0,0,0,,这个调用产生的环境则是 Dialogue: 0,0:51:27.36,0:51:29.90,Default,,0,0,0,,定义这个过程时的环境 Dialogue: 0,0:51:30.81,0:51:32.36,Default,,0,0,0,,额外加上一个空框架 Dialogue: 0,0:51:33.23,0:51:34.41,Default,,0,0,0,,我并不在意它 Dialogue: 0,0:51:36.24,0:51:39.40,Default,,0,0,0,,我们再来看这张幻灯片 Dialogue: 0,0:51:40.99,0:51:43.72,Default,,0,0,0,,仔细观察一会儿 Dialogue: 0,0:51:44.14,0:51:46.12,Default,,0,0,0,,会发现大部分跟以前相同 Dialogue: 0,0:51:46.35,0:51:50.65,Default,,0,0,0,,只是对应用或组合式的处理不同 Dialogue: 0,0:51:51.98,0:51:53.71,Default,,0,0,0,,处理组合式分两步 Dialogue: 0,0:51:54.68,0:51:57.79,Default,,0,0,0,,首先要求值这个过程 Dialogue: 0,0:51:57.92,0:51:59.88,Default,,0,0,0,,我就必须通过求值运算符来得到对应过程 Dialogue: 0,0:52:00.70,0:52:01.69,Default,,0,0,0,,也就是这一部分 Dialogue: 0,0:52:02.38,0:52:04.35,Default,,0,0,0,,我得这个值是计算求出的现值 Dialogue: 0,0:52:04.46,0:52:05.76,Default,,0,0,0,,而不是一个延时对象 Dialogue: 0,0:52:06.36,0:52:09.85,Default,,0,0,0,,也就要求值它在被延时前的表达式 Dialogue: 0,0:52:10.73,0:52:12.08,Default,,0,0,0,,接下来我就要 Dialogue: 0,0:52:12.24,0:52:17.32,Default,,0,0,0,,把它应用于运算对象 Dialogue: 0,0:52:18.03,0:52:19.61,Default,,0,0,0,,但我仍然要保持这个环境 Dialogue: 0,0:52:19.63,0:52:20.92,Default,,0,0,0,,并将其传递过去 Dialogue: 0,0:52:21.53,0:52:23.71,Default,,0,0,0,,如果有一些运算对象是延时了的 Dialogue: 0,0:52:23.71,0:52:27.53,Default,,0,0,0,,我就需要为这些运算对象附上相应的环境 Dialogue: 0,0:52:29.66,0:52:31.52,Default,,0,0,0,,这里的处理相当复杂 Dialogue: 0,0:52:32.99,0:52:34.24,Default,,0,0,0,,来看看APPLY中对应的部分 Dialogue: 0,0:52:36.40,0:52:38.72,Default,,0,0,0,,APPLY这一部分处理基本过程 Dialogue: 0,0:52:39.36,0:52:40.60,Default,,0,0,0,,这和之前一样 Dialogue: 0,0:52:42.61,0:52:44.68,Default,,0,0,0,,但复合过程部分就比较有意思了 Dialogue: 0,0:52:47.25,0:52:49.52,Default,,0,0,0,,和之前一样 我需要求值过程体 Dialogue: 0,0:52:50.48,0:52:51.98,Default,,0,0,0,,基于的环境是 Dialogue: 0,0:52:52.28,0:52:54.97,Default,,0,0,0,,把形式参数和 Dialogue: 0,0:52:55.61,0:53:00.29,Default,,0,0,0,,实际参数绑定在一起的结果 Dialogue: 0,0:53:00.29,0:53:01.07,Default,,0,0,0,,是这样的 Dialogue: 0,0:53:01.53,0:53:03.82,Default,,0,0,0,,环境来自于过程对象 Dialogue: 0,0:53:03.82,0:53:06.65,Default,,0,0,0,,因为我们的语言是词法作用域、静态绑定的 Dialogue: 0,0:53:08.04,0:53:11.82,Default,,0,0,0,,然而 我还需要去掉NAME声明 Dialogue: 0,0:53:11.84,0:53:12.84,Default,,0,0,0,,获得变量的实际名字 Dialogue: 0,0:53:12.84,0:53:15.20,Default,,0,0,0,,这是由VNAMES过程完成的 Dialogue: 0,0:53:15.45,0:53:16.67,Default,,0,0,0,,然后要做的就是 Dialogue: 0,0:53:16.97,0:53:18.86,Default,,0,0,0,,处理这些声明 Dialogue: 0,0:53:19.13,0:53:21.52,Default,,0,0,0,,决定这些运算对象中 Dialogue: 0,0:53:21.76,0:53:23.92,Default,,0,0,0,,现在它们还是形式参数 而非实际参数 Dialogue: 0,0:53:24.09,0:53:25.87,Default,,0,0,0,,哪些运算对象需要立即求值 Dialogue: 0,0:53:26.62,0:53:30.20,Default,,0,0,0,,而哪些运算对象又要 Dialogue: 0,0:53:30.99,0:53:33.77,Default,,0,0,0,,用某种方式封装为延时对象 Dialogue: 0,0:53:37.28,0:53:40.08,Default,,0,0,0,,另外 在处理基本过程这里 Dialogue: 0,0:53:40.60,0:53:42.38,Default,,0,0,0,,当遇到像+这样的基本过程 Dialogue: 0,0:53:42.68,0:53:45.58,Default,,0,0,0,,它们的参数最好立即求值 Dialogue: 0,0:53:45.82,0:53:47.39,Default,,0,0,0,,也就我们需要是这里FORCE这些表达式 Dialogue: 0,0:53:47.92,0:53:50.38,Default,,0,0,0,,EVLIST中完成了很多FORCE操作 Dialogue: 0,0:53:51.34,0:53:52.78,Default,,0,0,0,,现在 我们有了两种不同的EVLIST Dialogue: 0,0:53:52.78,0:53:54.09,Default,,0,0,0,,EVLIST和GEVLIST Dialogue: 0,0:53:54.52,0:53:57.16,Default,,0,0,0,,GEVLIST封装延迟参数 Dialogue: 0,0:53:57.18,0:53:59.74,Default,,0,0,0,,而对另外的参数立即求值 Dialogue: 0,0:53:59.87,0:54:05.85,Default,,0,0,0,,而EVLIST则会FORCE所有的表达式 Dialogue: 0,0:54:07.90,0:54:09.16,Default,,0,0,0,,简单地看下EVLIST的代码 Dialogue: 0,0:54:09.69,0:54:11.98,Default,,0,0,0,,课后你们一定要亲自上手试试 Dialogue: 0,0:54:12.25,0:54:14.67,Default,,0,0,0,,光是听我在这里讲课 Dialogue: 0,0:54:14.72,0:54:18.20,Default,,0,0,0,,可不能够学到求值器的不同变种 Dialogue: 0,0:54:19.52,0:54:21.24,Default,,0,0,0,,你们需要上手亲自实践一下。 Dialogue: 0,0:54:21.37,0:54:23.84,Default,,0,0,0,,你试验过后 对它们有了感悟 Dialogue: 0,0:54:24.22,0:54:27.02,Default,,0,0,0,,你才能理解各种可能的设计决策 Dialogue: 0,0:54:27.77,0:54:29.16,Default,,0,0,0,,才能清楚它们如何相互关联 Dialogue: 0,0:54:29.93,0:54:32.38,Default,,0,0,0,,了解求值器描述的是何种语言 Dialogue: 0,0:54:33.16,0:54:34.64,Default,,0,0,0,,以及构建一门合理的语言 Dialogue: 0,0:54:34.94,0:54:36.32,Default,,0,0,0,,需要哪些一致性集合 Dialogue: 0,0:54:37.20,0:54:40.06,Default,,0,0,0,,哪些临时方案又是复杂而无用 Dialogue: 0,0:54:41.85,0:54:44.68,Default,,0,0,0,,就和我说得一样 这里的EVLIST Dialogue: 0,0:54:44.81,0:54:46.03,Default,,0,0,0,,参数之一为运算对象表 Dialogue: 0,0:54:46.70,0:54:50.28,Default,,0,0,0,,表中的元素会在求值之后被取消延时 Dialogue: 0,0:54:50.75,0:54:51.90,Default,,0,0,0,,它们都会被FORCE Dialogue: 0,0:54:53.28,0:54:54.44,Default,,0,0,0,,无论它们是否为延时对象 Dialogue: 0,0:54:56.05,0:54:58.51,Default,,0,0,0,,下一个 GEVLIST Dialogue: 0,0:55:01.26,0:55:01.85,Default,,0,0,0,,谢谢 Dialogue: 0,0:55:04.04,0:55:06.35,Default,,0,0,0,,我们在这里会发现 Dialogue: 0,0:55:07.80,0:55:09.61,Default,,0,0,0,,这里面有多种可能 Dialogue: 0,0:55:09.81,0:55:11.52,Default,,0,0,0,,要么是普通的情况 Dialogue: 0,0:55:12.48,0:55:13.69,Default,,0,0,0,,比如元素直接是一个符号 Dialogue: 0,0:55:13.74,0:55:16.20,Default,,0,0,0,,就像UNLESS中的参数P那样 Dialogue: 0,0:55:17.64,0:55:18.81,Default,,0,0,0,,对应这一部分代码 Dialogue: 0,0:55:19.39,0:55:22.49,Default,,0,0,0,,在这种情况下 我们就用应用序来求值 Dialogue: 0,0:55:23.34,0:55:25.45,Default,,0,0,0,,基本上就像以前一样 Dialogue: 0,0:55:25.63,0:55:28.84,Default,,0,0,0,,就是将EVAL映射在这个表上 Dialogue: 0,0:55:29.95,0:55:32.14,Default,,0,0,0,,换言之 就是先求值第一个表达式 Dialogue: 0,0:55:32.65,0:55:37.36,Default,,0,0,0,,然后在ENV中 求值(GEVLIST (CDR EXPRS)) Dialogue: 0,0:55:37.93,0:55:43.20,Default,,0,0,0,,然而 我们也可能遇到按名传递的参数 Dialogue: 0,0:55:44.00,0:55:45.05,Default,,0,0,0,,如果参数是按名传递 Dialogue: 0,0:55:45.20,0:55:46.59,Default,,0,0,0,,我就需要给它包裹上一个DELAY Dialogue: 0,0:55:47.00,0:55:50.97,Default,,0,0,0,,DELAY里面就是我想按名调用的表达式 Dialogue: 0,0:55:52.14,0:55:57.74,Default,,0,0,0,,还要附上定义过程时的环境 Dialogue: 0,0:55:59.05,0:56:00.59,Default,,0,0,0,,把它们作为实际参数 Dialogue: 0,0:56:02.79,0:56:05.04,Default,,0,0,0,,然后像这样继续递归处理 Dialogue: 0,0:56:09.07,0:56:11.31,Default,,0,0,0,,这个解释器中另外一个有意思的地方 Dialogue: 0,0:56:11.37,0:56:13.53,Default,,0,0,0,,就在于COND Dialogue: 0,0:56:14.70,0:56:15.92,Default,,0,0,0,,人们可能就这么来写 Dialogue: 0,0:56:15.93,0:56:17.24,Default,,0,0,0,,然后就不管了 Dialogue: 0,0:56:18.55,0:56:19.98,Default,,0,0,0,,你需要在一处FORCE Dialogue: 0,0:56:20.51,0:56:23.10,Default,,0,0,0,,COND表达式需要知道 Dialogue: 0,0:56:24.20,0:56:25.90,Default,,0,0,0,,谓词判定结果的真假 Dialogue: 0,0:56:25.99,0:56:26.83,Default,,0,0,0,,就像基本过程那样 Dialogue: 0,0:56:28.55,0:56:30.56,Default,,0,0,0,,求值COND语句时 需要FORCE Dialogue: 0,0:56:31.72,0:56:33.95,Default,,0,0,0,,剩下的细节就没什么特别的了 Dialogue: 0,0:56:34.62,0:56:36.28,Default,,0,0,0,,就先不深究了 Dialogue: 0,0:56:36.75,0:56:38.99,Default,,0,0,0,,剩下的就是如何实现MAKE-DELAY Dialogue: 0,0:56:38.99,0:56:40.91,Default,,0,0,0,,延时对象是一种数据结构 Dialogue: 0,0:56:41.31,0:56:44.75,Default,,0,0,0,,它包括:类型标识、表达式以及环境 Dialogue: 0,0:56:44.84,0:56:46.36,Default,,0,0,0,,它的类型标识是'THUNK Dialogue: 0,0:56:46.96,0:56:48.46,Default,,0,0,0,,这个术语来自于Algol语言 Dialogue: 0,0:56:49.07,0:56:50.81,Default,,0,0,0,,据说这是个拟声词 Dialogue: 0,0:56:50.83,0:56:52.06,Default,,0,0,0,,是把东西压栈的声音 Dialogue: 0,0:56:52.97,0:56:53.41,Default,,0,0,0,,我不太清楚 Dialogue: 0,0:56:53.41,0:56:57.12,Default,,0,0,0,,我既不是Algol学家 又不是Algol程序员 Dialogue: 0,0:56:57.60,0:56:58.38,Default,,0,0,0,,所以我不太清楚 Dialogue: 0,0:56:58.74,0:56:59.64,Default,,0,0,0,,但据说它是那样的 Dialogue: 0,0:57:00.27,0:57:01.56,Default,,0,0,0,,而UNDELAY的定义则是 Dialogue: 0,0:57:01.77,0:57:03.66,Default,,0,0,0,,递归地UNDELAY这些THUNK Dialogue: 0,0:57:03.69,0:57:06.00,Default,,0,0,0,,直到得到一个非THUNK对象 Dialogue: 0,0:57:07.72,0:57:10.94,Default,,0,0,0,,这就是如何实现Algol中的按名调用 Dialogue: 0,0:57:12.05,0:57:13.76,Default,,0,0,0,,差不多就是这样了 Dialogue: 0,0:57:15.21,0:57:16.25,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:57:26.68,0:57:27.52,Default,,0,0,0,,学生:Gerry? Dialogue: 0,0:57:28.09,0:57:28.80,Default,,0,0,0,,教授:你说 Vesko Dialogue: 0,0:57:30.03,0:57:32.99,Default,,0,0,0,,学生:我注意到 对于基本过程 Dialogue: 0,0:57:33.44,0:57:34.89,Default,,0,0,0,,你是避免按名调用的 Dialogue: 0,0:57:36.41,0:57:38.38,Default,,0,0,0,,我很想知道 你为什么要这样? Dialogue: 0,0:57:38.41,0:57:39.21,Default,,0,0,0,,需要这样吗? Dialogue: 0,0:57:40.07,0:57:41.61,Default,,0,0,0,,教授:Vesko想问的是 Dialogue: 0,0:57:42.06,0:57:46.00,Default,,0,0,0,,基本过程也按名调用是否合理? Dialogue: 0,0:57:47.14,0:57:48.70,Default,,0,0,0,,答案是:是的 Dialogue: 0,0:57:49.27,0:57:52.32,Default,,0,0,0,,有一种情况下是可以的 实际上是两种 Dialogue: 0,0:57:55.53,0:57:58.27,Default,,0,0,0,,比如用CONS来构造一个数据结构 Dialogue: 0,0:57:59.02,0:58:02.00,Default,,0,0,0,,构建一个元素个数不定的数组时 Dialogue: 0,0:58:03.26,0:58:07.44,Default,,0,0,0,,就没必要求值参数 Dialogue: 0,0:58:07.44,0:58:08.83,Default,,0,0,0,,你只需要创建一些PROMISE Dialogue: 0,0:58:09.10,0:58:10.81,Default,,0,0,0,,在确实需要时才来求值这些参数 Dialogue: 0,0:58:11.50,0:58:15.08,Default,,0,0,0,,如果我把两个对象CONS起来 Dialogue: 0,0:58:16.24,0:58:17.77,Default,,0,0,0,,那么我CONS这些PROMISE Dialogue: 0,0:58:17.80,0:58:19.93,Default,,0,0,0,,就和CONS这些对象一样容易 Dialogue: 0,0:58:21.15,0:58:23.37,Default,,0,0,0,,甚至在对它们进行CAR CDR的时候 Dialogue: 0,0:58:23.39,0:58:24.30,Default,,0,0,0,,也不用进行实际的计算 Dialogue: 0,0:58:24.84,0:58:26.97,Default,,0,0,0,,取出PROMISE 并直接传递给其它人 Dialogue: 0,0:58:28.26,0:58:30.51,Default,,0,0,0,,这也就是为什么Alonzo Church用LAMBDA演算 Dialogue: 0,0:58:30.57,0:58:34.03,Default,,0,0,0,,定义的CAR、CDR和CONS说得通的原因 Dialogue: 0,0:58:34.42,0:58:36.32,Default,,0,0,0,,这是因为CAR、CDR以及CONS并没有执行计算 Dialogue: 0,0:58:36.38,0:58:40.06,Default,,0,0,0,,你们可以认为它是在重组数据而已 Dialogue: 0,0:58:40.99,0:58:42.20,Default,,0,0,0,,然而像 + 这样的过程 Dialogue: 0,0:58:42.24,0:58:43.84,Default,,0,0,0,,必须要了解参数是什么 Dialogue: 0,0:58:45.28,0:58:46.91,Default,,0,0,0,,它们需要确认 Dialogue: 0,0:58:47.12,0:58:48.30,Default,,0,0,0,,构成这些数字的比特 Dialogue: 0,0:58:48.32,0:58:50.44,Default,,0,0,0,,除非它们处理的是LAMBDA演算中的数字 Dialogue: 0,0:58:50.44,0:58:51.88,Default,,0,0,0,,这就是另外一码事了 Dialogue: 0,0:58:52.43,0:58:53.58,Default,,0,0,0,,为了运算加法 Dialogue: 0,0:58:53.77,0:58:55.53,Default,,0,0,0,,它需要知道构成数字的比特 Dialogue: 0,0:58:59.21,0:58:59.92,Default,,0,0,0,,因此 实际上 Dialogue: 0,0:59:00.19,0:59:02.78,Default,,0,0,0,,数据的构造过程和选择过程 Dialogue: 0,0:59:03.24,0:59:05.50,Default,,0,0,0,,以及具有副作用的数据对象 Dialogue: 0,0:59:06.27,0:59:09.76,Default,,0,0,0,,在最极端的惰性解释器中 Dialogue: 0,0:59:11.34,0:59:13.39,Default,,0,0,0,,也不需要被FORCE Dialogue: 0,0:59:16.46,0:59:16.99,Default,,0,0,0,,另外一方面 Dialogue: 0,0:59:17.02,0:59:18.70,Default,,0,0,0,,针对数据结构的谓词需要被FORCE Dialogue: 0,0:59:19.61,0:59:22.65,Default,,0,0,0,,如果你想判断 这是一个序对吗? Dialogue: 0,0:59:23.56,0:59:24.40,Default,,0,0,0,,或者是一个符号? Dialogue: 0,0:59:24.64,0:59:26.57,Default,,0,0,0,,最好搞清楚是什么 Dialogue: 0,0:59:30.30,0:59:31.18,Default,,0,0,0,,还有问题吗? Dialogue: 0,0:59:40.05,0:59:41.61,Default,,0,0,0,,那好吧 下课 Dialogue: 0,0:59:42.10,1:00:04.56,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:59:42.10,1:00:04.56,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec7b.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 6 Video Position: 286 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.01,0:00:01.63,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:01.63,0:00:09.15,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N张大伟 Dialogue: 0,0:00:01.63,0:00:09.15,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:01.63,0:00:09.15,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:01.63,0:00:09.15,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:01.63,0:00:09.15,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:09.52,0:00:13.66,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 II Dialogue: 0,0:00:17.21,0:00:17.96,Default,,0,0,0,,教授:目前为止 Dialogue: 0,0:00:19.52,0:00:21.29,Default,,0,0,0,,我们学的东西都非常有趣 Dialogue: 0,0:00:21.52,0:00:23.05,Default,,0,0,0,,但它有什么实际的用途吗? Dialogue: 0,0:00:26.33,0:00:27.96,Default,,0,0,0,,我想答案是“是的” Dialogue: 0,0:00:29.38,0:00:31.92,Default,,0,0,0,,这些元循环解释器 Dialogue: 0,0:00:32.96,0:00:34.60,Default,,0,0,0,,非常值得琢磨 Dialogue: 0,0:00:34.62,0:00:36.17,Default,,0,0,0,,我花了大概 Dialogue: 0,0:00:38.05,0:00:41.85,Default,,0,0,0,,曾几何时 我花了半年的功夫 Dialogue: 0,0:00:42.86,0:00:45.26,Default,,0,0,0,,用上节课讲的那种 Dialogue: 0,0:00:45.76,0:00:48.19,Default,,0,0,0,,元循环解释器来试验 Dialogue: 0,0:00:49.47,0:00:52.01,Default,,0,0,0,,各种各样的设计变种 Dialogue: 0,0:00:52.57,0:00:54.11,Default,,0,0,0,,用元循环解释器是因为 Dialogue: 0,0:00:54.72,0:00:56.94,Default,,0,0,0,,它们通过自己定义自己 Dialogue: 0,0:00:56.97,0:00:59.71,Default,,0,0,0,,因此被解释的语言也包含了自己 Dialogue: 0,0:01:01.27,0:01:03.87,Default,,0,0,0,,这样的解释器是一种的媒介 Dialogue: 0,0:01:03.88,0:01:05.58,Default,,0,0,0,,方便我们探索语言问题 Dialogue: 0,0:01:06.80,0:01:09.44,Default,,0,0,0,,如果你想添加一个新的FEATURE Dialogue: 0,0:01:10.51,0:01:12.38,Default,,0,0,0,,这就是小菜一碟 Dialogue: 0,0:01:12.73,0:01:15.10,Default,,0,0,0,,你只需要稍作修改 然后观察结果 Dialogue: 0,0:01:15.49,0:01:17.20,Default,,0,0,0,,在尝试了一会儿新语言后 Dialogue: 0,0:01:17.24,0:01:18.24,Default,,0,0,0,,你可能觉得它不好 Dialogue: 0,0:01:18.52,0:01:19.47,Default,,0,0,0,,就把它扔到一边去了 Dialogue: 0,0:01:20.96,0:01:23.55,Default,,0,0,0,,或者你也想研究 Dialogue: 0,0:01:23.64,0:01:27.37,Default,,0,0,0,,不同绑定策略的差异 Dialogue: 0,0:01:28.81,0:01:31.90,Default,,0,0,0,,或者是一些更复杂的东西 Dialogue: 0,0:01:33.72,0:01:35.48,Default,,0,0,0,,事实上 这些元循环解释器 Dialogue: 0,0:01:36.17,0:01:37.88,Default,,0,0,0,,非常适合作为交换媒介 Dialogue: 0,0:01:38.20,0:01:42.56,Default,,0,0,0,,用于承载人们关于语言设计想法 Dialogue: 0,0:01:43.98,0:01:45.74,Default,,0,0,0,,因为它们易于理解 Dialogue: 0,0:01:46.28,0:01:48.46,Default,,0,0,0,,它们短小、紧凑而且简洁 Dialogue: 0,0:01:49.32,0:01:50.80,Default,,0,0,0,,如果我有一些点子 Dialogue: 0,0:01:51.53,0:01:53.77,Default,,0,0,0,,想让其它人评论一下 Dialogue: 0,0:01:54.25,0:01:58.32,Default,,0,0,0,,比如Indiana大学的Dan Friedman教授 Dialogue: 0,0:01:59.05,0:02:02.00,Default,,0,0,0,,我就编写一个小型元循环解释器 Dialogue: 0,0:02:02.56,0:02:03.79,Default,,0,0,0,,然后给他发一封电子邮件 Dialogue: 0,0:02:04.65,0:02:05.45,Default,,0,0,0,,并附上解释器 Dialogue: 0,0:02:05.45,0:02:07.90,Default,,0,0,0,,他就可以在计算机上安装并运行 Dialogue: 0,0:02:07.92,0:02:09.82,Default,,0,0,0,,可能他会觉得这个设计并不好 Dialogue: 0,0:02:11.94,0:02:13.10,Default,,0,0,0,,然后他会给我回一封邮件 Dialogue: 0,0:02:13.13,0:02:14.83,Default,,0,0,0,,“为什么不试试这个 这个更好一点” Dialogue: 0,0:02:16.88,0:02:19.36,Default,,0,0,0,,所以我将会讲一些这方面的技术 Dialogue: 0,0:02:20.16,0:02:24.20,Default,,0,0,0,,因为在设计你自己的特定用途语言时 Dialogue: 0,0:02:24.72,0:02:28.68,Default,,0,0,0,,这种简单的技术非常重要 Dialogue: 0,0:02:30.79,0:02:32.08,Default,,0,0,0,,我们试着先在Lisp中 Dialogue: 0,0:02:32.51,0:02:34.21,Default,,0,0,0,,添加一个非常简单的FEATURE Dialogue: 0,0:02:40.64,0:02:44.37,Default,,0,0,0,,在这之前 我先来谈谈FEATURE吧 Dialogue: 0,0:02:49.56,0:02:52.17,Default,,0,0,0,,很多语言添加了大量的FEATURE Dialogue: 0,0:02:53.05,0:02:54.91,Default,,0,0,0,,把它们本身搞得混乱不堪 Dialogue: 0,0:02:56.86,0:02:58.38,Default,,0,0,0,,计算机科学家有一个笑话 Dialogue: 0,0:02:59.28,0:03:02.52,Default,,0,0,0,,“这不是BUG 这是FEATURE” Dialogue: 0,0:03:05.03,0:03:06.46,Default,,0,0,0,,而我宁愿认为 Dialogue: 0,0:03:08.91,0:03:11.44,Default,,0,0,0,,很多系统都在遭受着“功能蔓延”的影响 Dialogue: 0,0:03:12.82,0:03:13.44,Default,,0,0,0,,比方说 Dialogue: 0,0:03:14.94,0:03:18.16,Default,,0,0,0,,George希望系统中有某个FEATURE Dialogue: 0,0:03:18.72,0:03:19.36,Default,,0,0,0,,他就加了进来 Dialogue: 0,0:03:20.17,0:03:22.14,Default,,0,0,0,,Harry也想着 Dialogue: 0,0:03:22.17,0:03:24.20,Default,,0,0,0,,这个系统现在也不是我喜欢的那个了 Dialogue: 0,0:03:24.24,0:03:25.92,Default,,0,0,0,,然后加入了自己最喜欢的FEATURE Dialogue: 0,0:03:26.64,0:03:30.24,Default,,0,0,0,,Jim也这样做 Dialogue: 0,0:03:30.83,0:03:31.79,Default,,0,0,0,,一段时间过后 Dialogue: 0,0:03:31.80,0:03:34.81,Default,,0,0,0,,操作手册就多达500页 Dialogue: 0,0:03:35.15,0:03:36.51,Default,,0,0,0,,以至于没人能看得懂 Dialogue: 0,0:03:37.79,0:03:39.32,Default,,0,0,0,,有时候也可能只是 Dialogue: 0,0:03:39.90,0:03:41.37,Default,,0,0,0,,同一个人在添加FEATURE Dialogue: 0,0:03:41.39,0:03:43.23,Default,,0,0,0,,也会导致同样糟糕的结果 Dialogue: 0,0:03:44.14,0:03:46.09,Default,,0,0,0,,很多情况下 比如编辑器 Dialogue: 0,0:03:47.37,0:03:49.12,Default,,0,0,0,,具有很多FEATURE就很合理 Dialogue: 0,0:03:50.92,0:03:52.65,Default,,0,0,0,,因为你想要能够完成 Dialogue: 0,0:03:52.68,0:03:53.76,Default,,0,0,0,,各种不同的事情 Dialogue: 0,0:03:56.11,0:03:57.29,Default,,0,0,0,,但对计算机语言来说 Dialogue: 0,0:03:57.85,0:03:58.91,Default,,0,0,0,,我认为太多的FEATURE Dialogue: 0,0:04:00.01,0:04:01.29,Default,,0,0,0,,是一个灾难 Dialogue: 0,0:04:04.03,0:04:08.00,Default,,0,0,0,,另外 系统也可能变成某种“尖叫的怪物” Dialogue: 0,0:04:09.52,0:04:11.39,Default,,0,0,0,,假设你有一个盒子 Dialogue: 0,0:04:11.80,0:04:15.29,Default,,0,0,0,,它有一个鼠标和花哨的显示器 Dialogue: 0,0:04:15.95,0:04:20.04,Default,,0,0,0,,这些花哨的IO带来了各种各样的复杂性 Dialogue: 0,0:04:21.01,0:04:22.80,Default,,0,0,0,,你的程序语言就变成了 Dialogue: 0,0:04:23.34,0:04:25.37,Default,,0,0,0,,阴暗无用的小玩意儿 Dialogue: 0,0:04:25.40,0:04:27.90,Default,,0,0,0,,这是由计算机上的视窗系统进行的 Dialogue: 0,0:04:28.09,0:04:29.36,Default,,0,0,0,,内存换页和磁盘抖动所导致的 Dialogue: 0,0:04:30.08,0:04:31.82,Default,,0,0,0,,每当你使用计算机的时候 Dialogue: 0,0:04:31.93,0:04:33.45,Default,,0,0,0,,鼠标处理进程就会唤醒 Dialogue: 0,0:04:33.85,0:04:35.95,Default,,0,0,0,,你有什么事情要我做的吗? Dialogue: 0,0:04:36.14,0:04:37.23,Default,,0,0,0,,然后又回去休眠 Dialogue: 0,0:04:37.44,0:04:39.44,Default,,0,0,0,,如果你的胳膊肘不小心碰到了鼠标 Dialogue: 0,0:04:39.61,0:04:42.32,Default,,0,0,0,,一大堆烟雾就会从你的电脑出来 类似于这样 Dialogue: 0,0:04:42.94,0:04:45.29,Default,,0,0,0,,这就是由于添加FEATURE Dialogue: 0,0:04:45.55,0:04:47.21,Default,,0,0,0,,导致系统不能用的两种典型情况 Dialogue: 0,0:04:47.50,0:04:49.73,Default,,0,0,0,,现在我们要添加的是 一个非常简单的FEATURE Dialogue: 0,0:04:52.60,0:04:53.77,Default,,0,0,0,,这个FEATURE非常好 Dialogue: 0,0:04:53.85,0:04:56.17,Default,,0,0,0,,事实上 Lisp中就有这个FEATURE Dialogue: 0,0:04:57.25,0:04:58.17,Default,,0,0,0,,我们都知道 Dialogue: 0,0:04:59.29,0:05:03.13,Default,,0,0,0,,像+、*这样的过程 Dialogue: 0,0:05:03.37,0:05:04.89,Default,,0,0,0,,可以接受不定数目的参数 Dialogue: 0,0:05:05.43,0:05:06.44,Default,,0,0,0,,因此我们就可以写 Dialogue: 0,0:05:06.57,0:05:10.94,Default,,0,0,0,,(+ (* A X X) Dialogue: 0,0:05:12.09,0:05:16.99,Default,,0,0,0,,(* B X) C) Dialogue: 0,0:05:17.54,0:05:18.68,Default,,0,0,0,,这里可以看到 Dialogue: 0,0:05:18.92,0:05:21.76,Default,,0,0,0,,+有两到三个参数 Dialogue: 0,0:05:22.30,0:05:24.81,Default,,0,0,0,,*也有两到三个参数 Dialogue: 0,0:05:25.08,0:05:26.76,Default,,0,0,0,,不管多少个参数 Dialogue: 0,0:05:26.78,0:05:28.49,Default,,0,0,0,,都应该用同样的方式对待 Dialogue: 0,0:05:30.00,0:05:32.17,Default,,0,0,0,,支持不定数目的参数 Dialogue: 0,0:05:32.28,0:05:34.01,Default,,0,0,0,,这一点非常有用 Dialogue: 0,0:05:34.96,0:05:38.41,Default,,0,0,0,,而我上节课所讲的Lisp求值器 Dialogue: 0,0:05:39.23,0:05:41.85,Default,,0,0,0,,只能处理固定数目的参数 Dialogue: 0,0:05:42.62,0:05:45.28,Default,,0,0,0,,因为我要用BIND过程中的PAIR-UP过程 Dialogue: 0,0:05:45.63,0:05:47.92,Default,,0,0,0,,让形式参数与实际参数一一对应 Dialogue: 0,0:05:50.81,0:05:53.80,Default,,0,0,0,,假如我想能够定义像这样的过程 Dialogue: 0,0:05:54.89,0:05:57.32,Default,,0,0,0,,它们可以接收任意个数的参数 Dialogue: 0,0:05:58.75,0:06:00.40,Default,,0,0,0,,这个问题有好几部分 Dialogue: 0,0:06:01.34,0:06:04.81,Default,,0,0,0,,首先是挑选合适的语法描述 Dialogue: 0,0:06:05.72,0:06:11.21,Default,,0,0,0,,我们需要能够标注额外的参数 Dialogue: 0,0:06:12.17,0:06:13.63,Default,,0,0,0,,标注那些不知道个数的参数 Dialogue: 0,0:06:15.48,0:06:16.62,Default,,0,0,0,,另外就是 Dialogue: 0,0:06:17.10,0:06:18.70,Default,,0,0,0,,一旦我们标注出来后 Dialogue: 0,0:06:19.07,0:06:20.78,Default,,0,0,0,,我们怎样解释这些个记号 Dialogue: 0,0:06:21.74,0:06:23.10,Default,,0,0,0,,才能得到 Dialogue: 0,0:06:23.85,0:06:25.37,Default,,0,0,0,,正确的结果呢? Dialogue: 0,0:06:26.98,0:06:28.80,Default,,0,0,0,,让我们来考虑一种 Dialogue: 0,0:06:28.84,0:06:30.27,Default,,0,0,0,,我们可能会遇到的情况 Dialogue: 0,0:06:33.07,0:06:34.51,Default,,0,0,0,,比如说 Dialogue: 0,0:06:35.42,0:06:37.34,Default,,0,0,0,,我想要定义这样的一个过程 Dialogue: 0,0:06:37.95,0:06:41.36,Default,,0,0,0,,它有一个必选参数X Dialogue: 0,0:06:42.20,0:06:45.26,Default,,0,0,0,,还有个可选参数 -- 或者说一堆参数 Dialogue: 0,0:06:45.28,0:06:47.23,Default,,0,0,0,,我不知道它们的数目 就记作Y吧 Dialogue: 0,0:06:49.09,0:06:50.36,Default,,0,0,0,,X是必选的 Dialogue: 0,0:06:55.88,0:06:57.44,Default,,0,0,0,,然而有很多参数Y Dialogue: 0,0:06:59.53,0:07:05.99,Default,,0,0,0,,这些参数形成的表 -- 我就记作Y Dialogue: 0,0:07:14.48,0:07:16.06,Default,,0,0,0,,写好了参数表 Dialogue: 0,0:07:16.09,0:07:17.68,Default,,0,0,0,,我现在要这样定义过程体 Dialogue: 0,0:07:19.02,0:07:21.98,Default,,0,0,0,,我要对每一个元素都做同样的处理 Dialogue: 0,0:07:22.52,0:07:25.76,Default,,0,0,0,,(MAP (LAMBDA (U) Dialogue: 0,0:07:27.00,0:07:34.54,Default,,0,0,0,,(* X U)) Y) Dialogue: 0,0:07:36.89,0:07:38.04,Default,,0,0,0,,这里 我用了一个“点号” Dialogue: 0,0:07:38.59,0:07:41.31,Default,,0,0,0,,来表明点号后面的东西 Dialogue: 0,0:07:42.19,0:07:44.30,Default,,0,0,0,,是剩下的所有参数构成的表 Dialogue: 0,0:07:46.30,0:07:48.12,Default,,0,0,0,,这就是一个语法规范 Dialogue: 0,0:07:53.32,0:07:54.64,Default,,0,0,0,,为什么这样来写呢? Dialogue: 0,0:07:55.71,0:07:58.06,Default,,0,0,0,,这种语法规范之所以合理 Dialogue: 0,0:07:59.77,0:08:01.96,Default,,0,0,0,,是因为Lisp的源码读取器 Dialogue: 0,0:08:02.00,0:08:03.60,Default,,0,0,0,,刚好使用这种语法 Dialogue: 0,0:08:04.41,0:08:07.15,Default,,0,0,0,,来表示序对 Dialogue: 0,0:08:08.94,0:08:11.08,Default,,0,0,0,,我们之前没有介绍过 Dialogue: 0,0:08:11.08,0:08:12.78,Default,,0,0,0,,你在自己尝试的时候可能遇到过 Dialogue: 0,0:08:13.04,0:08:14.62,Default,,0,0,0,,当你调用(CONS X Y)时 Dialogue: 0,0:08:14.89,0:08:18.12,Default,,0,0,0,,你会得到 X . Y Dialogue: 0,0:08:19.79,0:08:22.83,Default,,0,0,0,,准确来说是(X . Y) Dialogue: 0,0:08:23.08,0:08:24.64,Default,,0,0,0,,两边还有括号 Dialogue: 0,0:08:26.98,0:08:28.16,Default,,0,0,0,,举例来说吧 Dialogue: 0,0:08:28.97,0:08:35.04,Default,,0,0,0,,这里的(X . Y)对应着一个序对 Dialogue: 0,0:08:36.33,0:08:39.29,Default,,0,0,0,,X是CAR部分 Y是CDR部分 Dialogue: 0,0:08:41.48,0:08:43.98,Default,,0,0,0,,你们目前为止见过的其它记号 Dialogue: 0,0:08:44.94,0:08:46.67,Default,,0,0,0,,是像 Dialogue: 0,0:08:46.92,0:08:55.24,Default,,0,0,0,,(LAMBDA (X Y Z) ...)这样的 Dialogue: 0,0:08:55.71,0:08:57.63,Default,,0,0,0,,它们则是像这样的 Dialogue: 0,0:09:02.00,0:09:03.61,Default,,0,0,0,,就拿形式参数表来说 Dialogue: 0,0:09:04.22,0:09:05.29,Default,,0,0,0,,它实际上是这样 Dialogue: 0,0:09:09.93,0:09:17.32,Default,,0,0,0,,这里分别是 X、Y、Z和空表 Dialogue: 0,0:09:18.28,0:09:21.08,Default,,0,0,0,,如果我有一个想要与之匹配的参数表的话 Dialogue: 0,0:09:22.60,0:09:25.60,Default,,0,0,0,,假设实际参数表是'(1 2 3) Dialogue: 0,0:09:25.87,0:09:27.26,Default,,0,0,0,,我想把它们和形参相匹配 Dialogue: 0,0:09:28.38,0:09:37.10,Default,,0,0,0,,所以这里 可能有个三个元素的表 Dialogue: 0,0:09:42.44,0:09:46.94,Default,,0,0,0,,分别是1、2、3 Dialogue: 0,0:09:48.99,0:09:53.16,Default,,0,0,0,,用'(1 2 3)来匹配'(X Y Z) Dialogue: 0,0:09:54.22,0:09:56.28,Default,,0,0,0,,很显然1和X相匹配 Dialogue: 0,0:09:56.32,0:09:58.01,Default,,0,0,0,,因为我可以顺着这个结构来 Dialogue: 0,0:09:58.86,0:10:01.56,Default,,0,0,0,,2和Y相匹配 Dialogue: 0,0:10:02.46,0:10:04.04,Default,,0,0,0,,3和Z相匹配 Dialogue: 0,0:10:05.48,0:10:09.53,Default,,0,0,0,,假设我现在要把这个(X . Y) Dialogue: 0,0:10:09.55,0:10:11.84,Default,,0,0,0,,这个是(X . Y) Dialogue: 0,0:10:12.51,0:10:16.91,Default,,0,0,0,,如果我想把它跟'(1 2 3)相匹配的话 Dialogue: 0,0:10:19.08,0:10:20.00,Default,,0,0,0,,我们再来看 Dialogue: 0,0:10:28.00,0:10:30.32,Default,,0,0,0,,这里是1、2、3 Dialogue: 0,0:10:30.86,0:10:32.88,Default,,0,0,0,,我可以沿着这里遍历 Dialogue: 0,0:10:32.99,0:10:35.50,Default,,0,0,0,,会发现 1和X相匹配 Dialogue: 0,0:10:37.56,0:10:41.84,Default,,0,0,0,,而Y和表'(2 3)相匹配 Dialogue: 0,0:10:43.74,0:10:46.22,Default,,0,0,0,,所以这里选用的表示法 Dialogue: 0,0:10:46.41,0:10:50.16,Default,,0,0,0,,对于Lisp来说是非常自然的 Dialogue: 0,0:10:52.66,0:10:54.14,Default,,0,0,0,,所以我就选择用这个记号 Dialogue: 0,0:10:54.17,0:10:55.80,Default,,0,0,0,,来表示数目不定的参数 Dialogue: 0,0:10:58.29,0:11:00.09,Default,,0,0,0,,还有一种可能性 Dialogue: 0,0:11:00.59,0:11:02.78,Default,,0,0,0,,如果我不是特别想命名某个参数 Dialogue: 0,0:11:03.00,0:11:05.00,Default,,0,0,0,,或者是命名某两个参数之类的 Dialogue: 0,0:11:06.54,0:11:07.56,Default,,0,0,0,,如果我不想那样的话 Dialogue: 0,0:11:08.78,0:11:10.44,Default,,0,0,0,,如果我想像+那样 Dialogue: 0,0:11:10.52,0:11:12.52,Default,,0,0,0,,一下子引用所有的参数 Dialogue: 0,0:11:13.88,0:11:17.96,Default,,0,0,0,,那么我就应该把参数表写成 Dialogue: 0,0:11:18.20,0:11:23.45,Default,,0,0,0,,(LAMBDA X ...) Dialogue: 0,0:11:25.14,0:11:26.30,Default,,0,0,0,,举例来说 Dialogue: 0,0:11:26.81,0:11:27.96,Default,,0,0,0,,如果我定义一个过程 Dialogue: 0,0:11:28.06,0:11:30.44,Default,,0,0,0,,它把接收所有的参数 Dialogue: 0,0:11:31.12,0:11:32.70,Default,,0,0,0,,然后返回一个由它们组成的表X Dialogue: 0,0:11:34.81,0:11:38.67,Default,,0,0,0,,返回的结果就是过程的参数表 明白吗? Dialogue: 0,0:11:45.85,0:11:46.67,Default,,0,0,0,,这又是怎么回事呢? Dialogue: 0,0:11:46.84,0:11:50.06,Default,,0,0,0,,实际上 无论我们的参数表是何种形式 Dialogue: 0,0:11:50.60,0:11:51.45,Default,,0,0,0,,无论是何种形式 Dialogue: 0,0:11:51.61,0:11:53.68,Default,,0,0,0,,都要与实际参数表相匹配 Dialogue: 0,0:11:55.14,0:11:57.14,Default,,0,0,0,,现在 这个符号就是所有的实际参数了 Dialogue: 0,0:12:01.49,0:12:05.13,Default,,0,0,0,,所以 我选择使用这个特定的语法规范 Dialogue: 0,0:12:05.64,0:12:07.63,Default,,0,0,0,,来描述那些 Dialogue: 0,0:12:08.04,0:12:10.56,Default,,0,0,0,,接收不定数目参数的过程 Dialogue: 0,0:12:13.45,0:12:14.60,Default,,0,0,0,,一共有两种情况 Dialogue: 0,0:12:15.40,0:12:16.35,Default,,0,0,0,,上面这种和下面这种 Dialogue: 0,0:12:17.44,0:12:18.36,Default,,0,0,0,,这两种都 -- Dialogue: 0,0:12:18.42,0:12:20.11,Default,,0,0,0,,当你们在制定语法规范时 Dialogue: 0,0:12:20.44,0:12:22.54,Default,,0,0,0,,千万注意不要有歧义 Dialogue: 0,0:12:23.56,0:12:27.36,Default,,0,0,0,,就比如说这里的两种情况 Dialogue: 0,0:12:27.66,0:12:31.20,Default,,0,0,0,,就不要与这里我们已有的这种混淆了 Dialogue: 0,0:12:33.61,0:12:35.82,Default,,0,0,0,,我总是可以区分出 Dialogue: 0,0:12:36.54,0:12:39.80,Default,,0,0,0,,过程的形式参数 Dialogue: 0,0:12:40.28,0:12:41.76,Default,,0,0,0,,是数目固定的具名参数 Dialogue: 0,0:12:42.64,0:12:43.13,Default,,0,0,0,,还是 Dialogue: 0,0:12:43.28,0:12:45.36,Default,,0,0,0,,既有数目固定的具名参数 Dialogue: 0,0:12:45.44,0:12:48.01,Default,,0,0,0,,又跟着数目可变的参数 Dialogue: 0,0:12:49.42,0:12:53.52,Default,,0,0,0,,又或者是所有参数组成的表 Dialogue: 0,0:12:53.68,0:12:56.52,Default,,0,0,0,,这个表会和这里的形式参数X相匹配 Dialogue: 0,0:12:56.99,0:12:58.84,Default,,0,0,0,,我都是可以从语法上区分它们 Dialogue: 0,0:13:02.25,0:13:04.62,Default,,0,0,0,,由于语言中存在语法歧义 Dialogue: 0,0:13:05.04,0:13:08.03,Default,,0,0,0,,整个待解释的程序被错误地分段 Dialogue: 0,0:13:08.64,0:13:13.92,Default,,0,0,0,,从而导致了可怕的错误 Dialogue: 0,0:13:14.56,0:13:16.67,Default,,0,0,0,,类Algol语言中就有些传统问题 Dialogue: 0,0:13:16.67,0:13:23.47,Default,,0,0,0,,就跟谓词部分的嵌套IF语句有关 Dialogue: 0,0:13:25.06,0:13:25.93,Default,,0,0,0,,总之 Dialogue: 0,0:13:27.52,0:13:29.44,Default,,0,0,0,,我现在已经把语法告诉你们了 Dialogue: 0,0:13:30.27,0:13:34.83,Default,,0,0,0,,我们要怎么来处理它的语义呢? Dialogue: 0,0:13:35.25,0:13:36.11,Default,,0,0,0,,我们如何来解释它? Dialogue: 0,0:13:36.59,0:13:37.96,Default,,0,0,0,,其实很简单 Dialogue: 0,0:13:38.44,0:13:42.57,Default,,0,0,0,,我修改一下元循环解释器就行 Dialogue: 0,0:13:43.71,0:13:44.76,Default,,0,0,0,,只需修改一行 Dialogue: 0,0:13:45.98,0:13:46.57,Default,,0,0,0,,在这里 Dialogue: 0,0:13:47.53,0:13:49.56,Default,,0,0,0,,我修改一下PAIR-UP过程 Dialogue: 0,0:13:50.81,0:13:54.19,Default,,0,0,0,,这里的PAIR-UP过程把 Dialogue: 0,0:13:56.76,0:14:02.03,Default,,0,0,0,,这是从上节课的元循环求值器中 Dialogue: 0,0:14:04.81,0:14:09.56,Default,,0,0,0,,摘录过来的PAIR-UP过程 Dialogue: 0,0:14:12.16,0:14:16.68,Default,,0,0,0,,它把形式参数与传递过来的实际参数匹配起来 Dialogue: 0,0:14:18.96,0:14:21.93,Default,,0,0,0,,大部分地方都和以前一样 Dialogue: 0,0:14:22.67,0:14:23.23,Default,,0,0,0,,也就是说 Dialogue: 0,0:14:23.31,0:14:25.07,Default,,0,0,0,,如果变量表为空 Dialogue: 0,0:14:25.52,0:14:27.31,Default,,0,0,0,,并且值表也为空 Dialogue: 0,0:14:27.45,0:14:29.61,Default,,0,0,0,,就返回空表 Dialogue: 0,0:14:31.05,0:14:33.00,Default,,0,0,0,,否则就是参数过多 Dialogue: 0,0:14:33.98,0:14:40.19,Default,,0,0,0,,如果变量表为空 但值表非空 Dialogue: 0,0:14:41.58,0:14:44.00,Default,,0,0,0,,如果值表为空 Dialogue: 0,0:14:44.96,0:14:47.47,Default,,0,0,0,,但是变量表又非空 Dialogue: 0,0:14:47.48,0:14:48.56,Default,,0,0,0,,那就是实际参数少了 Dialogue: 0,0:14:48.94,0:14:51.31,Default,,0,0,0,,然而如果我有一个变量是符号的话 Dialogue: 0,0:14:55.53,0:14:56.49,Default,,0,0,0,,这就有意思了 Dialogue: 0,0:14:58.30,0:15:04.40,Default,,0,0,0,,那么 我就认为遇到了特殊情况 Dialogue: 0,0:15:04.59,0:15:06.51,Default,,0,0,0,,也就是尾部分为符号的情况 Dialogue: 0,0:15:08.35,0:15:14.11,Default,,0,0,0,,情况就像这里的一样 Dialogue: 0,0:15:14.90,0:15:17.87,Default,,0,0,0,,这个尾部分就是一个符号Y Dialogue: 0,0:15:18.63,0:15:19.39,Default,,0,0,0,,它不是NIL Dialogue: 0,0:15:20.73,0:15:21.72,Default,,0,0,0,,不是个空表 Dialogue: 0,0:15:23.26,0:15:25.60,Default,,0,0,0,,而这个一开始就是个符号 Dialogue: 0,0:15:25.98,0:15:26.81,Default,,0,0,0,,就没有别的东西了 Dialogue: 0,0:15:27.79,0:15:28.72,Default,,0,0,0,,这种情况下 Dialogue: 0,0:15:29.96,0:15:37.20,Default,,0,0,0,,我就用这个符号去匹配所有的值 Dialogue: 0,0:15:38.03,0:15:42.52,Default,,0,0,0,,并把它们添加到要返回的结果中 Dialogue: 0,0:15:44.50,0:15:46.91,Default,,0,0,0,,否则的话 我就像正常情况那样 Dialogue: 0,0:15:47.15,0:15:48.52,Default,,0,0,0,,来创建所有的配对 Dialogue: 0,0:15:52.02,0:15:53.82,Default,,0,0,0,,我认为这很容易理解 Dialogue: 0,0:15:54.51,0:15:55.84,Default,,0,0,0,,就是这些 Dialogue: 0,0:15:57.08,0:15:58.33,Default,,0,0,0,,现在 答疑时间 Dialogue: 0,0:16:02.62,0:16:05.05,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:16:06.60,0:16:06.94,Default,,0,0,0,,你说 Dialogue: 0,0:16:07.37,0:16:09.92,Default,,0,0,0,,学生:你能再解释一下第三种形式吗? Dialogue: 0,0:16:09.98,0:16:12.12,Default,,0,0,0,,教授:第三种?这个? Dialogue: 0,0:16:12.59,0:16:14.27,Default,,0,0,0,,或许你用表结构来思考 Dialogue: 0,0:16:14.30,0:16:16.24,Default,,0,0,0,,会更容易理解一些 Dialogue: 0,0:16:18.57,0:16:22.73,Default,,0,0,0,,这是一个过程 包含一个LAMBDA Dialogue: 0,0:16:25.85,0:16:29.61,Default,,0,0,0,,我画出来的这个表结构就代表上面的这个 Dialogue: 0,0:16:31.26,0:16:32.44,Default,,0,0,0,,这里是X Dialogue: 0,0:16:32.73,0:16:33.98,Default,,0,0,0,,这些是我们的符号 Dialogue: 0,0:16:37.41,0:16:39.58,Default,,0,0,0,,过程体就是X而已 Dialogue: 0,0:16:44.84,0:16:48.75,Default,,0,0,0,,如果我需要这个过程的形式参数表 Dialogue: 0,0:16:50.09,0:16:51.58,Default,,0,0,0,,我就取它的CADR部分 Dialogue: 0,0:16:52.14,0:16:53.16,Default,,0,0,0,,我会得到一个符号 Dialogue: 0,0:16:54.01,0:16:57.16,Default,,0,0,0,,所以我们的匹配器 -- 也就是我给你们展示的PAIR-UP过程 Dialogue: 0,0:16:58.24,0:17:00.44,Default,,0,0,0,,就会把这个符号对象 Dialogue: 0,0:17:01.56,0:17:04.40,Default,,0,0,0,,跟我们传递的实际参数表相匹配了 Dialogue: 0,0:17:05.76,0:17:09.55,Default,,0,0,0,,这个符号与实际参数表相绑定 Dialogue: 0,0:17:11.37,0:17:16.48,Default,,0,0,0,,而在这个例子中 如果我去取它的话 Dialogue: 0,0:17:16.92,0:17:20.97,Default,,0,0,0,,匹配器就会把它与变量表的这个部分相匹配 Dialogue: 0,0:17:24.14,0:17:26.14,Default,,0,0,0,,如果一个过程只是 Dialogue: 0,0:17:26.17,0:17:29.13,Default,,0,0,0,,直接返回得到的参数表的话 返回的就是一个表 Dialogue: 0,0:17:30.40,0:17:31.39,Default,,0,0,0,,这个过程就是这样的 Dialogue: 0,0:17:34.51,0:17:35.48,Default,,0,0,0,,好吧 谢谢大家 Dialogue: 0,0:17:36.14,0:17:37.28,Default,,0,0,0,,大家休息一下吧 Dialogue: 0,0:17:37.83,0:17:55.36,Default,,0,0,0,,[音乐] Dialogue: 0,0:17:55.36,0:17:59.02,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:18:03.53,0:18:07.56,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:18:07.56,0:18:11.69,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:18:12.25,0:18:16.11,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 II Dialogue: 0,0:18:20.86,0:18:21.61,Default,,0,0,0,,教授:我们接着来看 Dialogue: 0,0:18:23.26,0:18:26.32,Default,,0,0,0,,现在 我将介绍一种相当重要的变种 Dialogue: 0,0:18:27.45,0:18:31.04,Default,,0,0,0,,这种变体非常有名 Dialogue: 0,0:18:31.60,0:18:36.80,Default,,0,0,0,,早期的很多Lisp都支持它 Dialogue: 0,0:18:38.25,0:18:40.06,Default,,0,0,0,,它被称为变量的动态绑定 Dialogue: 0,0:18:41.77,0:18:44.68,Default,,0,0,0,,我们现在来研究一下它 Dialogue: 0,0:18:47.62,0:18:50.16,Default,,0,0,0,,我先来介绍一下是什么导致 Dialogue: 0,0:18:50.35,0:18:52.36,Default,,0,0,0,,人们产生这样的想法 Dialogue: 0,0:18:53.74,0:18:55.23,Default,,0,0,0,,然而我并不会直接点明原因 Dialogue: 0,0:18:55.40,0:18:57.60,Default,,0,0,0,,我来举一个例子 你们来感受一下 Dialogue: 0,0:18:58.64,0:18:59.93,Default,,0,0,0,,假设 Dialogue: 0,0:19:00.75,0:19:02.59,Default,,0,0,0,,我们再来考察一下 Dialogue: 0,0:19:05.02,0:19:06.43,Default,,0,0,0,,计算一系列数之和的SUM过程 Dialogue: 0,0:19:08.14,0:19:09.47,Default,,0,0,0,,它的参数为 Dialogue: 0,0:19:09.60,0:19:10.78,Default,,0,0,0,,计算当前项的TERM Dialogue: 0,0:19:13.04,0:19:14.41,Default,,0,0,0,,下界A Dialogue: 0,0:19:15.24,0:19:17.04,Default,,0,0,0,,计算下一项索引的NEXT Dialogue: 0,0:19:17.24,0:19:18.56,Default,,0,0,0,,上界B Dialogue: 0,0:19:19.36,0:19:20.16,Default,,0,0,0,,过程体是 Dialogue: 0,0:19:23.16,0:19:26.94,Default,,0,0,0,,如果A>B Dialogue: 0,0:19:27.15,0:19:28.64,Default,,0,0,0,,那么结果就是0 Dialogue: 0,0:19:30.24,0:19:31.08,Default,,0,0,0,,否则就是 Dialogue: 0,0:19:33.68,0:19:39.82,Default,,0,0,0,,(+ (TERM A) Dialogue: 0,0:19:40.60,0:19:44.24,Default,,0,0,0,,(SUM TERM Dialogue: 0,0:19:47.68,0:19:52.64,Default,,0,0,0,,(NEXT A) Dialogue: 0,0:20:00.30,0:20:03.56,Default,,0,0,0,,这个NEXT过程直接传递过去 Dialogue: 0,0:20:06.40,0:20:08.25,Default,,0,0,0,,上界B也直接传递过去 Dialogue: 0,0:20:14.51,0:20:15.76,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:20:17.82,0:20:21.45,Default,,0,0,0,,当我使用SUM过程的时候 Dialogue: 0,0:20:21.96,0:20:24.35,Default,,0,0,0,,我可以像这样来用 Dialogue: 0,0:20:25.45,0:20:38.04,Default,,0,0,0,,我们可以把SUM-POWERS过程定义为 Dialogue: 0,0:20:38.08,0:20:40.33,Default,,0,0,0,,这个函数是用来计算Σ(X^N)的 Dialogue: 0,0:20:41.10,0:20:45.93,Default,,0,0,0,,它的参数有A、B以及N Dialogue: 0,0:20:45.95,0:20:47.69,Default,,0,0,0,,分别指下界、上界以及指数 Dialogue: 0,0:20:48.06,0:20:53.34,Default,,0,0,0,,它的定义是(SUM (LAMBDA (X) Dialogue: 0,0:20:53.60,0:20:59.31,Default,,0,0,0,,这个参数为X的过程计算(EXPT X N) Dialogue: 0,0:21:02.19,0:21:09.29,Default,,0,0,0,,我们还要传递A、1+还有B Dialogue: 0,0:21:11.82,0:21:15.76,Default,,0,0,0,,因此 给定一系列X 我们计算Σ(X^N)的值 Dialogue: 0,0:21:16.14,0:21:19.74,Default,,0,0,0,,X从A到B取值 步长为1 Dialogue: 0,0:21:22.94,0:21:24.38,Default,,0,0,0,,我也可以定义-- Dialogue: 0,0:21:27.68,0:21:28.20,Default,,0,0,0,,好像这里有点问题 Dialogue: 0,0:21:29.78,0:21:31.02,Default,,0,0,0,,不好意思 Dialogue: 0,0:21:31.91,0:21:33.36,Default,,0,0,0,,这里应该是PRODUCT-POWERS Dialogue: 0,0:21:38.08,0:21:39.12,Default,,0,0,0,,名字有点奇怪 Dialogue: 0,0:21:40.02,0:21:40.80,Default,,0,0,0,,还是不改了 Dialogue: 0,0:21:41.96,0:21:46.32,Default,,0,0,0,,有点怪 就按原来的吧 Dialogue: 0,0:21:49.34,0:21:50.19,Default,,0,0,0,,这回应该对了 Dialogue: 0,0:21:51.37,0:21:53.82,Default,,0,0,0,,而PRODUCT-POWERS的定义则是 Dialogue: 0,0:21:58.41,0:22:02.36,Default,,0,0,0,,(意义不明) Dialogue: 0,0:22:03.00,0:22:06.81,Default,,0,0,0,,我可以用像SUM一样的过程 Dialogue: 0,0:22:06.81,0:22:08.22,Default,,0,0,0,,只不过是用来计算乘积的 Dialogue: 0,0:22:08.56,0:22:11.05,Default,,0,0,0,,但是很类似 就跟你们在那里见到的一样 Dialogue: 0,0:22:11.45,0:22:16.38,Default,,0,0,0,,它也是一个三参数的过程 Dialogue: 0,0:22:17.00,0:22:25.42,Default,,0,0,0,,求积的因数是通过构造而来 Dialogue: 0,0:22:25.66,0:22:31.60,Default,,0,0,0,,也就是(PRODUCT (LAMBDA (X) (EXPT X N)) Dialogue: 0,0:22:34.43,0:22:37.85,Default,,0,0,0,,下界是A 步长为1 上界为B Dialogue: 0,0:22:41.53,0:22:41.88,Default,,0,0,0,,现在 Dialogue: 0,0:22:46.83,0:22:49.50,Default,,0,0,0,,你可能马上就意识到一些问题 Dialogue: 0,0:22:50.75,0:22:52.01,Default,,0,0,0,,它们看起来几乎一样 Dialogue: 0,0:22:53.18,0:22:55.20,Default,,0,0,0,,为什么要重复写代码呢? Dialogue: 0,0:22:56.59,0:22:59.72,Default,,0,0,0,,现在就很像我们之前遇到的情况了 Dialogue: 0,0:23:01.00,0:23:03.15,Default,,0,0,0,,构建一个抽象不是更好吗? Dialogue: 0,0:23:03.81,0:23:05.76,Default,,0,0,0,,如何构建良好的抽象呢? Dialogue: 0,0:23:05.85,0:23:07.55,Default,,0,0,0,,我看到有一些完全相同的代码 Dialogue: 0,0:23:08.47,0:23:09.32,Default,,0,0,0,,这有一段 Dialogue: 0,0:23:09.98,0:23:11.08,Default,,0,0,0,,这是另一段 Dialogue: 0,0:23:14.45,0:23:16.22,Default,,0,0,0,,所以我应该把它们提取出来 Dialogue: 0,0:23:17.09,0:23:19.23,Default,,0,0,0,,我就会想 Dialogue: 0,0:23:20.51,0:23:22.67,Default,,0,0,0,,SUM-POWERS可以用 Dialogue: 0,0:23:22.88,0:23:24.52,Default,,0,0,0,,NTH-POWERS的过程来编写 Dialogue: 0,0:23:25.71,0:23:27.40,Default,,0,0,0,,假如有人想写一个 Dialogue: 0,0:23:27.74,0:23:30.03,Default,,0,0,0,,稍微不同的过程 就像这个一样 Dialogue: 0,0:23:37.63,0:23:45.18,Default,,0,0,0,,(DEFINE SUM-POWERS Dialogue: 0,0:23:46.44,0:23:48.46,Default,,0,0,0,,(LAMBDA (A B N) Dialogue: 0,0:23:48.75,0:23:52.27,Default,,0,0,0,,(SUM (NTH-POWER Dialogue: 0,0:23:53.88,0:23:55.42,Default,,0,0,0,,我们调用过程NTH-POWER Dialogue: 0,0:23:58.35,0:24:02.27,Default,,0,0,0,,下界为A 步长为1 上界为B Dialogue: 0,0:24:05.74,0:24:06.91,Default,,0,0,0,,类似地 Dialogue: 0,0:24:10.65,0:24:12.76,Default,,0,0,0,,我想用这种方式来重写PRODUCT-POWERS Dialogue: 0,0:24:12.89,0:24:15.24,Default,,0,0,0,,把求幂指数从这里抽象出来 Dialogue: 0,0:24:16.27,0:24:17.37,Default,,0,0,0,,可以这样写 Dialogue: 0,0:24:22.10,0:24:23.02,Default,,0,0,0,,(DEFINE PRODUCT-POWERS Dialogue: 0,0:24:29.48,0:24:34.94,Default,,0,0,0,,(LAMBDA (A B N) Dialogue: 0,0:24:35.31,0:24:42.33,Default,,0,0,0,,(PRODUCT NTH-POWERS Dialogue: 0,0:24:46.44,0:24:50.30,Default,,0,0,0,,A 1+ B))) Dialogue: 0,0:24:53.50,0:24:57.56,Default,,0,0,0,,把NTH-POWER的结果作为PRODUCT的参数 Dialogue: 0,0:24:58.38,0:25:00.24,Default,,0,0,0,,我们还需要定义 Dialogue: 0,0:25:02.04,0:25:03.88,Default,,0,0,0,,还需要定义过程NTH-POWERS Dialogue: 0,0:25:04.89,0:25:05.93,Default,,0,0,0,,我把它写在这边 Dialogue: 0,0:25:12.22,0:25:12.99,Default,,0,0,0,,写在上面 Dialogue: 0,0:25:25.41,0:25:29.04,Default,,0,0,0,,它是一个参数为X的过程 Dialogue: 0,0:25:29.60,0:25:34.56,Default,,0,0,0,,计算(EXPT X N) Dialogue: 0,0:25:35.93,0:25:36.96,Default,,0,0,0,,但是我遇到一个问题 Dialogue: 0,0:25:38.64,0:25:39.93,Default,,0,0,0,,我们使用的环境模型 Dialogue: 0,0:25:40.57,0:25:43.23,Default,,0,0,0,,我们用来解释 Dialogue: 0,0:25:44.00,0:25:45.95,Default,,0,0,0,,目前所定义的语言的这种手段 Dialogue: 0,0:25:46.27,0:25:48.81,Default,,0,0,0,,并没有给我说明这个N的值 Dialogue: 0,0:25:52.76,0:25:59.26,Default,,0,0,0,,因为 正如大家所知 Dialogue: 0,0:26:00.76,0:26:04.25,Default,,0,0,0,,在这个过程中 N是自由变量 Dialogue: 0,0:26:06.41,0:26:07.98,Default,,0,0,0,,环境模型告诉我们 Dialogue: 0,0:26:08.60,0:26:10.20,Default,,0,0,0,,自由变量的值 Dialogue: 0,0:26:11.21,0:26:14.99,Default,,0,0,0,,取决于过程被定义时所在的环境 Dialogue: 0,0:26:16.64,0:26:17.47,Default,,0,0,0,,在我编写它们的时候 Dialogue: 0,0:26:17.48,0:26:19.84,Default,,0,0,0,,就假设它们已经在黑板上被定义了 Dialogue: 0,0:26:21.64,0:26:23.63,Default,,0,0,0,,NTH-POWER是定义在全局环境下的 Dialogue: 0,0:26:24.06,0:26:25.15,Default,,0,0,0,,其中没有N的定义 Dialogue: 0,0:26:25.93,0:26:27.63,Default,,0,0,0,,因此 N是未绑定的变量 Dialogue: 0,0:26:28.72,0:26:31.66,Default,,0,0,0,,但对我们来说 Dialogue: 0,0:26:32.60,0:26:36.32,Default,,0,0,0,,我们明确希望它是这里和这里的N Dialogue: 0,0:26:38.99,0:26:42.67,Default,,0,0,0,,另外一方面 Dialogue: 0,0:26:42.84,0:26:44.28,Default,,0,0,0,,当然我们要十分小心地确保 Dialogue: 0,0:26:44.56,0:26:46.06,Default,,0,0,0,,这里的N是这里的N Dialogue: 0,0:26:48.96,0:26:52.83,Default,,0,0,0,,还有这里的这个 要跟这里的一致 Dialogue: 0,0:26:57.39,0:26:59.74,Default,,0,0,0,,这种想法造就了 Dialogue: 0,0:27:00.67,0:27:02.72,Default,,0,0,0,,一个非常著名的BUG Dialogue: 0,0:27:04.65,0:27:06.04,Default,,0,0,0,,我来细说下这个BUG Dialogue: 0,0:27:07.15,0:27:09.40,Default,,0,0,0,,请看这张幻灯片 Dialogue: 0,0:27:10.66,0:27:12.70,Default,,0,0,0,,这种想法被称作“动态绑定” Dialogue: 0,0:27:13.99,0:27:16.91,Default,,0,0,0,,在这种情况下 自由变量不再被 Dialogue: 0,0:27:17.76,0:27:21.23,Default,,0,0,0,,定义过程时的环境所解释 Dialogue: 0,0:27:22.40,0:27:25.16,Default,,0,0,0,,这种情况下 自由变量的值 Dialogue: 0,0:27:25.44,0:27:29.31,Default,,0,0,0,,就像是存储在过程调用者的环境中一样 Dialogue: 0,0:27:31.85,0:27:34.84,Default,,0,0,0,,所以在这个系统中 Dialogue: 0,0:27:34.86,0:27:39.68,Default,,0,0,0,,你需要不断地搜索调用过程的调用者的环境 Dialogue: 0,0:27:40.43,0:27:42.65,Default,,0,0,0,,当然 在本例中 Dialogue: 0,0:27:42.84,0:27:44.30,Default,,0,0,0,,无论NTH-POWER在何处定义 Dialogue: 0,0:27:44.33,0:27:45.98,Default,,0,0,0,,它都是在PRODUCT过程中被调用的 Dialogue: 0,0:27:46.41,0:27:48.68,Default,,0,0,0,,我就需要在SUM过程中再编写一个类似的过程 Dialogue: 0,0:27:50.51,0:27:54.92,Default,,0,0,0,,而PRODUCT又是被PRODUCT-POWERS所调用 Dialogue: 0,0:27:55.13,0:27:56.14,Default,,0,0,0,,就是你们在这里看到的 Dialogue: 0,0:27:56.83,0:27:59.37,Default,,0,0,0,,由于PRODUCT-POWERS过程绑定了变量N Dialogue: 0,0:28:00.09,0:28:04.09,Default,,0,0,0,,因此NTH-POWER中的N会从这个链中派生出来 Dialogue: 0,0:28:08.14,0:28:09.64,Default,,0,0,0,,相似地 这个N Dialogue: 0,0:28:10.11,0:28:12.01,Default,,0,0,0,,NTH-POWER中的N在这种情况下 Dialogue: 0,0:28:12.32,0:28:15.80,Default,,0,0,0,,可能是来自于这里SUM过程的调用 Dialogue: 0,0:28:15.80,0:28:18.27,Default,,0,0,0,,你们可以从这里看到 它在SUM内部被调用 Dialogue: 0,0:28:20.73,0:28:21.69,Default,,0,0,0,,对应这里的TERM Dialogue: 0,0:28:22.90,0:28:25.72,Default,,0,0,0,,而SUM是在SUM-POWERS的内部被调用 Dialogue: 0,0:28:26.94,0:28:27.96,Default,,0,0,0,,后者绑定了N Dialogue: 0,0:28:28.93,0:28:30.65,Default,,0,0,0,,因此这里就有一个N Dialogue: 0,0:28:32.75,0:28:36.11,Default,,0,0,0,,可供NTH-POWER中的N取值 Dialogue: 0,0:28:37.95,0:28:39.24,Default,,0,0,0,,这就是动态 -- Dialogue: 0,0:28:39.28,0:28:43.10,Default,,0,0,0,,这条白线以下的东西 再加上这部分 Dialogue: 0,0:28:43.31,0:28:46.04,Default,,0,0,0,,就是我们所谓的动态绑定 Dialogue: 0,0:28:46.59,0:28:49.00,Default,,0,0,0,,用动态绑定的角度来解释 就可以正常运行 Dialogue: 0,0:28:50.85,0:28:52.65,Default,,0,0,0,,现在 让我们来看一个例子 Dialogue: 0,0:28:54.54,0:28:55.99,Default,,0,0,0,,要怎么实现这个功能 Dialogue: 0,0:28:55.99,0:28:56.96,Default,,0,0,0,,非常简单 Dialogue: 0,0:28:57.48,0:28:59.34,Default,,0,0,0,,事实上 最早的Lisp实现 Dialogue: 0,0:29:00.01,0:29:02.52,Default,,0,0,0,,对自由变量有各种形式的解释 Dialogue: 0,0:29:03.31,0:29:05.98,Default,,0,0,0,,包括用动态绑定来解释自由变量 Dialogue: 0,0:29:06.40,0:29:10.14,Default,,0,0,0,,APL也是用动态绑定来解释自由变量的 Dialogue: 0,0:29:11.68,0:29:14.32,Default,,0,0,0,,而不是词法绑定 或者说静态绑定 Dialogue: 0,0:29:15.22,0:29:17.00,Default,,0,0,0,,当然 要从EVAL开始修改 Dialogue: 0,0:29:19.31,0:29:20.59,Default,,0,0,0,,只需修改两个地方就行 Dialogue: 0,0:29:22.78,0:29:25.61,Default,,0,0,0,,首先我们会发现 Dialogue: 0,0:29:26.52,0:29:28.49,Default,,0,0,0,,事情变得更简单了 Dialogue: 0,0:29:29.39,0:29:33.63,Default,,0,0,0,,如果我不需要 Dialogue: 0,0:29:33.64,0:29:36.20,Default,,0,0,0,,在定义过程的那个环境中求值 Dialogue: 0,0:29:36.44,0:29:38.04,Default,,0,0,0,,过程在定义的时候就无需 Dialogue: 0,0:29:38.43,0:29:40.17,Default,,0,0,0,,捕获当时的环境了 Dialogue: 0,0:29:42.03,0:29:44.96,Default,,0,0,0,,所以我们可以在幻灯片的这里看到 Dialogue: 0,0:29:45.84,0:29:50.08,Default,,0,0,0,,这条用于判断是否为LAMBDA表达式的子句 Dialogue: 0,0:29:50.73,0:29:52.43,Default,,0,0,0,,过程就是在这个时候创建的 Dialogue: 0,0:29:53.92,0:29:56.73,Default,,0,0,0,,就不会返回一个带有类型标签 Dialogue: 0,0:29:56.75,0:30:01.05,Default,,0,0,0,,和环境结构的过程对象了 Dialogue: 0,0:30:01.29,0:30:02.54,Default,,0,0,0,,就是EXP本身 Dialogue: 0,0:30:02.54,0:30:04.76,Default,,0,0,0,,而我们会在其它地方用某种方式来解耦 Dialogue: 0,0:30:06.44,0:30:09.40,Default,,0,0,0,,另外一处修改就是组合式的应用 Dialogue: 0,0:30:10.36,0:30:13.69,Default,,0,0,0,,应用的时候必须要取得调用者的环境 Dialogue: 0,0:30:14.29,0:30:17.24,Default,,0,0,0,,调用者的环境就在这里 Dialogue: 0,0:30:17.26,0:30:19.45,Default,,0,0,0,,如果表达式是一个过程应用-- Dialogue: 0,0:30:19.56,0:30:21.63,Default,,0,0,0,,如果我们求值的是一个组合式 Dialogue: 0,0:30:21.79,0:30:23.71,Default,,0,0,0,,我们就会调用一个组合式 Dialogue: 0,0:30:23.93,0:30:25.50,Default,,0,0,0,,调用一个过程 Dialogue: 0,0:30:25.66,0:30:27.37,Default,,0,0,0,,来取得运算符的值 Dialogue: 0,0:30:29.84,0:30:31.44,Default,,0,0,0,,调用者的环境 Dialogue: 0,0:30:31.98,0:30:34.51,Default,,0,0,0,,就是我们当前的环境 Dialogue: 0,0:30:35.89,0:30:40.72,Default,,0,0,0,,所以 我只需要要把这个环境传递给APPLY Dialogue: 0,0:30:41.49,0:30:42.75,Default,,0,0,0,,我们再来看看APPLY Dialogue: 0,0:30:43.58,0:30:44.97,Default,,0,0,0,,我们只需要 Dialogue: 0,0:30:45.71,0:30:48.41,Default,,0,0,0,,把参数列表加上一个环境ENV Dialogue: 0,0:30:48.78,0:30:55.68,Default,,0,0,0,,然后用这个环境来扩展环境 Dialogue: 0,0:30:56.67,0:30:59.02,Default,,0,0,0,,扩展把形式参数 Dialogue: 0,0:30:59.02,0:31:01.37,Default,,0,0,0,,和传递过来的实际参数绑定在一起的环境 Dialogue: 0,0:31:03.08,0:31:05.98,Default,,0,0,0,,而不再是之前由过程捕获的环境了 Dialogue: 0,0:31:06.81,0:31:09.45,Default,,0,0,0,,最早的Lisp偶然地采用了 Dialogue: 0,0:31:09.66,0:31:11.96,Default,,0,0,0,,这种最显然的方式实现 Dialogue: 0,0:31:14.13,0:31:16.68,Default,,0,0,0,,当然 像往常一样 人们习惯了并喜欢上了它 Dialogue: 0,0:31:17.25,0:31:18.27,Default,,0,0,0,,因此就有一些人说 Dialogue: 0,0:31:18.40,0:31:19.50,Default,,0,0,0,,“就应该这么来做” Dialogue: 0,0:31:21.59,0:31:24.09,Default,,0,0,0,,不幸的是 这导致一些严重的问题 Dialogue: 0,0:31:25.40,0:31:27.24,Default,,0,0,0,,最严重的一点是 Dialogue: 0,0:31:27.53,0:31:29.84,Default,,0,0,0,,采用动态绑定 Dialogue: 0,0:31:31.00,0:31:33.56,Default,,0,0,0,,破坏了模块性 Dialogue: 0,0:31:35.46,0:31:37.66,Default,,0,0,0,,如果有两个人在一个大型系统上协同工作 Dialogue: 0,0:31:38.57,0:31:40.01,Default,,0,0,0,,那么一个重要的原则就是 Dialogue: 0,0:31:40.35,0:31:42.19,Default,,0,0,0,,每个人所使用的名字 Dialogue: 0,0:31:42.99,0:31:44.58,Default,,0,0,0,,都不应该干扰到对方的名字 Dialogue: 0,0:31:47.93,0:31:50.78,Default,,0,0,0,,如果我写了一段代码 Dialogue: 0,0:31:51.07,0:31:53.13,Default,,0,0,0,,别人就不能通过在他代码内部 Dialogue: 0,0:31:53.88,0:31:56.57,Default,,0,0,0,,使用我代码中的名字来破坏我的代码 Dialogue: 0,0:31:56.75,0:31:57.71,Default,,0,0,0,,这一点很重要 Dialogue: 0,0:31:59.85,0:32:00.46,Default,,0,0,0,,然而 Dialogue: 0,0:32:01.04,0:32:05.18,Default,,0,0,0,,动态绑定明显地违背了这种特定的模块化约束 Dialogue: 0,0:32:06.67,0:32:08.08,Default,,0,0,0,,我们考虑一下 Dialogue: 0,0:32:09.18,0:32:10.35,Default,,0,0,0,,这段代码会有什么效果? Dialogue: 0,0:32:12.54,0:32:13.79,Default,,0,0,0,,假设我想要把 Dialogue: 0,0:32:15.47,0:32:19.81,Default,,0,0,0,,我想要把变量NEXT换个名字 Dialogue: 0,0:32:19.81,0:32:24.41,Default,,0,0,0,,假设某个人要编写SUM过程 Dialogue: 0,0:32:25.10,0:32:26.68,Default,,0,0,0,,而别人则会使用这个SUM过程 Dialogue: 0,0:32:28.97,0:32:30.32,Default,,0,0,0,,编写SUM的那个人 Dialogue: 0,0:32:30.49,0:32:32.30,Default,,0,0,0,,可以选择他想要使用的名字 Dialogue: 0,0:32:33.66,0:32:34.84,Default,,0,0,0,,假设我就是那个编写者 Dialogue: 0,0:32:36.83,0:32:39.30,Default,,0,0,0,,刚巧 这里我不想用NEXT来表示 Dialogue: 0,0:32:39.30,0:32:40.09,Default,,0,0,0,,而是用N来表示 Dialogue: 0,0:32:41.74,0:32:43.10,Default,,0,0,0,,所以我把所有出现NEXT的地方 Dialogue: 0,0:32:44.28,0:32:45.26,Default,,0,0,0,,都换成N Dialogue: 0,0:32:48.14,0:32:48.48,Default,,0,0,0,,哎呀 Dialogue: 0,0:32:49.94,0:32:52.22,Default,,0,0,0,,我没有改变这个程序的规范 Dialogue: 0,0:32:53.32,0:32:54.86,Default,,0,0,0,,但是整个程序就崩溃了 Dialogue: 0,0:32:56.11,0:32:57.96,Default,,0,0,0,,不仅如此 这边也出现了问题 Dialogue: 0,0:32:59.50,0:33:01.40,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:33:02.26,0:33:03.24,Default,,0,0,0,,答案非常明显 Dialogue: 0,0:33:04.48,0:33:09.29,Default,,0,0,0,,NTH-POWER中的变量N的值 Dialogue: 0,0:33:09.31,0:33:13.72,Default,,0,0,0,,也就是这个N和这个N Dialogue: 0,0:33:14.97,0:33:17.16,Default,,0,0,0,,根据环境模型的定义 Dialogue: 0,0:33:17.20,0:33:19.58,Default,,0,0,0,,这两个N总是相关的 Dialogue: 0,0:33:19.87,0:33:21.48,Default,,0,0,0,,如果是根据环境模型的定义的话 Dialogue: 0,0:33:21.55,0:33:23.63,Default,,0,0,0,,因为N在这里被绑定 Dialogue: 0,0:33:24.37,0:33:26.25,Default,,0,0,0,,这个LAMBDA表达式是在 Dialogue: 0,0:33:26.59,0:33:28.59,Default,,0,0,0,,N被绑定的环境中执行的 Dialogue: 0,0:33:30.70,0:33:31.84,Default,,0,0,0,,如果不用环境模型的话 Dialogue: 0,0:33:32.01,0:33:33.68,Default,,0,0,0,,我必须追踪过程的调用链 Dialogue: 0,0:33:34.78,0:33:36.27,Default,,0,0,0,,那么就会发生糟糕的事儿 Dialogue: 0,0:33:37.32,0:33:41.18,Default,,0,0,0,,在SUM内部 这个是作为TERM调用的 Dialogue: 0,0:33:41.76,0:33:42.38,Default,,0,0,0,,这里的(TERM A) Dialogue: 0,0:33:44.78,0:33:46.19,Default,,0,0,0,,这时再来查找N的值 Dialogue: 0,0:33:47.35,0:33:48.40,Default,,0,0,0,,我得到的不知这个值 Dialogue: 0,0:33:48.84,0:33:49.76,Default,,0,0,0,,而是这个值 Dialogue: 0,0:33:50.70,0:33:52.54,Default,,0,0,0,,因此 只是这个程序的内部做了修改 Dialogue: 0,0:33:52.86,0:33:54.09,Default,,0,0,0,,这个程序却崩溃了 Dialogue: 0,0:33:56.77,0:34:00.08,Default,,0,0,0,,LAMBDA就不再像我以前说得那样是个量词了 Dialogue: 0,0:34:01.12,0:34:05.13,Default,,0,0,0,,LAMBDA应该是一个量词 Dialogue: 0,0:34:05.43,0:34:06.70,Default,,0,0,0,,量词有一个性质 Dialogue: 0,0:34:06.89,0:34:11.42,Default,,0,0,0,,被它绑定的名字都不重要 Dialogue: 0,0:34:12.65,0:34:15.71,Default,,0,0,0,,只要我用不在过程体中的新名字 Dialogue: 0,0:34:16.92,0:34:19.98,Default,,0,0,0,,统一地在过程体中代换旧名字 Dialogue: 0,0:34:20.94,0:34:23.16,Default,,0,0,0,,就不会改变表达式的语义 Dialogue: 0,0:34:24.04,0:34:25.50,Default,,0,0,0,,而我刚才却通过修改一个名字 Dialogue: 0,0:34:25.53,0:34:27.20,Default,,0,0,0,,改变了表达式的语义 Dialogue: 0,0:34:28.69,0:34:30.89,Default,,0,0,0,,因此LAMBDA就不再是一个良好定义的量词了 Dialogue: 0,0:34:32.17,0:34:33.37,Default,,0,0,0,,这个问题非常严重 Dialogue: 0,0:34:34.55,0:34:35.55,Default,,0,0,0,,正是因为这个原因 Dialogue: 0,0:34:36.64,0:34:42.51,Default,,0,0,0,,我和同事放弃了这种抽象方法 Dialogue: 0,0:34:43.13,0:34:44.36,Default,,0,0,0,,相对的 我更喜欢 Dialogue: 0,0:34:45.61,0:34:47.50,Default,,0,0,0,,模块化原则 Dialogue: 0,0:34:48.09,0:34:50.20,Default,,0,0,0,,如果你愿意探索解释器 Dialogue: 0,0:34:51.96,0:34:53.68,Default,,0,0,0,,那就非常值得做这类实验 Dialogue: 0,0:34:54.83,0:34:56.91,Default,,0,0,0,,你可以尝试多种设计 Dialogue: 0,0:34:58.11,0:35:00.25,Default,,0,0,0,,探索更优雅的语言设计 Dialogue: 0,0:35:02.68,0:35:04.49,Default,,0,0,0,,这是元循环求值器非常重要的功能 Dialogue: 0,0:35:04.99,0:35:06.68,Default,,0,0,0,,现在 我也想讲一讲 Dialogue: 0,0:35:06.72,0:35:08.49,Default,,0,0,0,,这种情况下的正确做法 Dialogue: 0,0:35:09.32,0:35:12.91,Default,,0,0,0,,我又如何来获得这种 Dialogue: 0,0:35:13.04,0:35:15.34,Default,,0,0,0,,词法作用域的能力呢? Dialogue: 0,0:35:16.28,0:35:17.39,Default,,0,0,0,,当然 实际情况是 Dialogue: 0,0:35:17.55,0:35:20.03,Default,,0,0,0,,在这里我想要的是 Dialogue: 0,0:35:20.68,0:35:22.60,Default,,0,0,0,,针对特定N的求指数函数 Dialogue: 0,0:35:23.69,0:35:24.28,Default,,0,0,0,,给定一个N Dialogue: 0,0:35:24.32,0:35:25.66,Default,,0,0,0,,它会返回给我一个特定的求指数过程 Dialogue: 0,0:35:26.28,0:35:27.40,Default,,0,0,0,,这非常简单 Dialogue: 0,0:35:28.17,0:35:30.57,Default,,0,0,0,,换言之 我可以这样来写 Dialogue: 0,0:35:35.84,0:35:37.84,Default,,0,0,0,,我要定义一个过程PGEN Dialogue: 0,0:35:40.25,0:35:42.54,Default,,0,0,0,,它有一个参数N Dialogue: 0,0:35:43.16,0:35:45.95,Default,,0,0,0,,返回一个指数过程 Dialogue: 0,0:35:50.24,0:35:51.23,Default,,0,0,0,,计算X^N Dialogue: 0,0:35:56.80,0:35:57.98,Default,,0,0,0,,有了这个以后 Dialogue: 0,0:35:58.59,0:36:00.88,Default,,0,0,0,,我就可以进行想要的那种抽象 Dialogue: 0,0:36:01.42,0:36:03.93,Default,,0,0,0,,甚至于现在的封装方法还要更好一些 Dialogue: 0,0:36:04.09,0:36:06.60,Default,,0,0,0,,因为系统现在不会因改名而崩溃了 Dialogue: 0,0:36:07.89,0:36:12.35,Default,,0,0,0,,(DEFINE SUM-POWERS Dialogue: 0,0:36:17.28,0:36:20.70,Default,,0,0,0,,(LAMBDA (A B N) Dialogue: 0,0:36:21.61,0:36:26.83,Default,,0,0,0,,(SUM Dialogue: 0,0:36:26.88,0:36:32.32,Default,,0,0,0,,(PGEN N) Dialogue: 0,0:36:34.40,0:36:38.01,Default,,0,0,0,,A 1+ B))) Dialogue: 0,0:36:42.49,0:36:47.95,Default,,0,0,0,,(DEFINE PRODUCT-POWERS Dialogue: 0,0:36:54.11,0:36:58.84,Default,,0,0,0,,(LAMBDA (A B N) Dialogue: 0,0:36:59.80,0:37:09.96,Default,,0,0,0,,(PRODUCT (PGEN N) A 1+ B))) Dialogue: 0,0:37:11.28,0:37:13.28,Default,,0,0,0,,当然 这只是一个非常简单的例子 Dialogue: 0,0:37:13.60,0:37:16.35,Default,,0,0,0,,这里 我想要抽象的对象也十分简单 Dialogue: 0,0:37:17.28,0:37:18.83,Default,,0,0,0,,但它也有可能是长达100行的代码 Dialogue: 0,0:37:20.10,0:37:23.67,Default,,0,0,0,,我这么写是为了保持简单 Dialogue: 0,0:37:23.67,0:37:24.57,Default,,0,0,0,,我给它命了名 Dialogue: 0,0:37:24.73,0:37:26.94,Default,,0,0,0,,这里它只是一个参数化的名字 Dialogue: 0,0:37:28.20,0:37:30.27,Default,,0,0,0,,这个名字显式地依赖于 Dialogue: 0,0:37:30.49,0:37:33.63,Default,,0,0,0,,词法作用域下N的值 Dialogue: 0,0:37:37.13,0:37:38.59,Default,,0,0,0,,因此可以把它看做一个很长的名字 Dialogue: 0,0:37:40.21,0:37:41.58,Default,,0,0,0,,这里 我是通过 Dialogue: 0,0:37:41.76,0:37:45.82,Default,,0,0,0,,为计算TERM的过程命名 Dialogue: 0,0:37:46.12,0:37:49.22,Default,,0,0,0,,来解决问题的 Dialogue: 0,0:37:55.08,0:37:55.87,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:37:57.00,0:37:58.38,Default,,0,0,0,,David 你说 Dialogue: 0,0:37:58.57,0:38:02.27,Default,,0,0,0,,学生:刚才那个问题 Dialogue: 0,0:38:03.07,0:38:06.46,Default,,0,0,0,,只能通过新建一个过程来解决吗? Dialogue: 0,0:38:06.47,0:38:08.92,Default,,0,0,0,,换句话说 是不是必须要语言能够 Dialogue: 0,0:38:08.99,0:38:11.56,Default,,0,0,0,,把对象定义为过程? Dialogue: 0,0:38:12.41,0:38:13.76,Default,,0,0,0,,教授:我明白了 Dialogue: 0,0:38:15.90,0:38:19.74,Default,,0,0,0,,我构建抽象的这种方法 Dialogue: 0,0:38:20.14,0:38:22.86,Default,,0,0,0,,需要过程能够返回或者导出一个过程 Dialogue: 0,0:38:23.26,0:38:26.81,Default,,0,0,0,,以便我不想让过程体中包含特定过程 Dialogue: 0,0:38:27.04,0:38:27.24,Default,,0,0,0,,学生:没错 Dialogue: 0,0:38:28.19,0:38:28.88,Default,,0,0,0,,教授:是这样的 Dialogue: 0,0:38:29.53,0:38:31.52,Default,,0,0,0,,如果我不能这么做的话 Dialogue: 0,0:38:32.24,0:38:35.13,Default,,0,0,0,,那么我就无法去构造一个抽象 Dialogue: 0,0:38:35.53,0:38:41.77,Default,,0,0,0,,使得符号之间不会出现冲突 Dialogue: 0,0:38:43.00,0:38:43.48,Default,,0,0,0,,你说得对 Dialogue: 0,0:38:44.14,0:38:46.51,Default,,0,0,0,,我认为 Dialogue: 0,0:38:46.54,0:38:48.91,Default,,0,0,0,,能够把过程作为返回值 Dialogue: 0,0:38:49.20,0:38:58.28,Default,,0,0,0,,更一般地说是支持“第一级过程” Dialogue: 0,0:38:59.13,0:39:02.46,Default,,0,0,0,,是模块化程序程序设计所必须的 Dialogue: 0,0:39:03.70,0:39:06.43,Default,,0,0,0,,有很多种方式来解决这个问题 Dialogue: 0,0:39:07.44,0:39:09.16,Default,,0,0,0,,你可以的做的就是 Dialogue: 0,0:39:09.18,0:39:11.84,Default,,0,0,0,,针对你所需要关心的每一种糟糕情况 Dialogue: 0,0:39:12.27,0:39:15.20,Default,,0,0,0,,你可以添加一个特殊的FEATURE来解决它 Dialogue: 0,0:39:15.84,0:39:17.12,Default,,0,0,0,,你可以做一个包系统 Dialogue: 0,0:39:17.74,0:39:21.16,Default,,0,0,0,,或者像Ada中的模块系统 等等 Dialogue: 0,0:39:22.24,0:39:24.88,Default,,0,0,0,,这些都可以 可能区别只是解决的程度不一 Dialogue: 0,0:39:26.44,0:39:28.38,Default,,0,0,0,,而能够把过程作为返回值 Dialogue: 0,0:39:28.41,0:39:29.74,Default,,0,0,0,,可以解决这所有的问题 Dialogue: 0,0:39:32.68,0:39:34.60,Default,,0,0,0,,这种最简单的机制 Dialogue: 0,0:39:35.58,0:39:37.79,Default,,0,0,0,,却可以给予你最好的模块性 Dialogue: 0,0:39:39.21,0:39:41.31,Default,,0,0,0,,它赋予你所有已知的模块机制 Dialogue: 0,0:39:45.59,0:39:48.24,Default,,0,0,0,,好的 该休息一会儿了 谢谢大家 Dialogue: 0,0:39:48.24,0:40:01.08,Default,,0,0,0,,[音乐] Dialogue: 0,0:40:01.28,0:40:04.75,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:40:25.69,0:40:29.42,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:40:30.01,0:40:33.28,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:40:34.17,0:40:37.61,Declare,,0,0,0,,{\an2\fad(500,500)}元循环求值器 II Dialogue: 0,0:40:42.32,0:40:44.28,Default,,0,0,0,,教授:昨天你们学习流的时候 Dialogue: 0,0:40:46.01,0:40:51.16,Default,,0,0,0,,Hal教授告诉了你们求值顺序 Dialogue: 0,0:40:51.95,0:40:53.87,Default,,0,0,0,,以及过程的延迟求值 Dialogue: 0,0:40:55.61,0:40:58.30,Default,,0,0,0,,昨天在讲流的时候 我们说 Dialogue: 0,0:41:00.25,0:41:04.22,Default,,0,0,0,,调用者和被调者都应该认同 Dialogue: 0,0:41:05.77,0:41:08.84,Default,,0,0,0,,参数是被延迟了的 Dialogue: 0,0:41:09.42,0:41:13.44,Default,,0,0,0,,如果被调者需要结果 就需要对参数FORCE Dialogue: 0,0:41:15.13,0:41:17.87,Default,,0,0,0,,因此在过程的设计者和使用者之间 Dialogue: 0,0:41:18.17,0:41:24.32,Default,,0,0,0,,就有很多关于延时求值的握手 Dialogue: 0,0:41:26.36,0:41:28.72,Default,,0,0,0,,当然 这看起来相当糟糕 Dialogue: 0,0:41:29.48,0:41:30.96,Default,,0,0,0,,虽说对于流没什么不妥 Dialogue: 0,0:41:31.74,0:41:32.86,Default,,0,0,0,,但作为一般性的原则来说 Dialogue: 0,0:41:32.92,0:41:36.32,Default,,0,0,0,,我们希望能有个地方 Dialogue: 0,0:41:36.46,0:41:38.49,Default,,0,0,0,,能够把我们的设计考虑 Dialogue: 0,0:41:38.89,0:41:41.28,Default,,0,0,0,,显式地、清晰地 Dialogue: 0,0:41:41.63,0:41:43.93,Default,,0,0,0,,标注出来 Dialogue: 0,0:41:45.88,0:41:49.28,Default,,0,0,0,,因此就不必在过程编写者 Dialogue: 0,0:41:50.46,0:41:54.89,Default,,0,0,0,,和使用者之间达成共识 Dialogue: 0,0:41:55.08,0:41:57.98,Default,,0,0,0,,有关于参数求值 Dialogue: 0,0:41:58.43,0:41:59.50,Default,,0,0,0,,以及求值顺序等细节 Dialogue: 0,0:41:59.50,0:42:00.75,Default,,0,0,0,,虽然 这也不是太糟糕 Dialogue: 0,0:42:01.02,0:42:03.95,Default,,0,0,0,,我的意思是 可能还有像“输入是一个数字”这样的共识 Dialogue: 0,0:42:05.20,0:42:06.08,Default,,0,0,0,,但是 Dialogue: 0,0:42:06.35,0:42:09.20,Default,,0,0,0,,如果其中一个人可以全权负责 就再好不过了 Dialogue: 0,0:42:11.02,0:42:13.31,Default,,0,0,0,,这个想法已经不算新潮了 Dialogue: 0,0:42:15.51,0:42:21.16,Default,,0,0,0,,Algol60就支持两种不同的过程调用方法 Dialogue: 0,0:42:22.02,0:42:24.28,Default,,0,0,0,,参数可以按名或按值传递 Dialogue: 0,0:42:25.59,0:42:27.48,Default,,0,0,0,,按名传递就意味着 Dialogue: 0,0:42:27.63,0:42:29.72,Default,,0,0,0,,参数会延时求值 Dialogue: 0,0:42:31.11,0:42:32.84,Default,,0,0,0,,当你按名传递一个参数时 Dialogue: 0,0:42:33.64,0:42:36.52,Default,,0,0,0,,只有你去取它的值的时候 Dialogue: 0,0:42:36.96,0:42:39.55,Default,,0,0,0,,它的值才会被计算出来 Dialogue: 0,0:42:42.29,0:42:44.20,Default,,0,0,0,,所以 现在我就要 Dialogue: 0,0:42:44.43,0:42:46.96,Default,,0,0,0,,像之前那样 Dialogue: 0,0:42:46.99,0:42:48.65,Default,,0,0,0,,对语言做出一些小小的修改 Dialogue: 0,0:42:50.32,0:42:51.79,Default,,0,0,0,,这里 我们再添加一个新的FEATURE Dialogue: 0,0:42:53.37,0:42:55.05,Default,,0,0,0,,我们要添加的FEATURE是 Dialogue: 0,0:42:55.36,0:42:58.73,Default,,0,0,0,,“按名传递参数” 或者可以叫做“延迟求值参数” Dialogue: 0,0:43:00.43,0:43:04.41,Default,,0,0,0,,因为事实上 Lisp系统中默认 Dialogue: 0,0:43:04.76,0:43:06.60,Default,,0,0,0,,传递的是一个指针 Dialogue: 0,0:43:08.22,0:43:09.15,Default,,0,0,0,,指针被复制了一份 Dialogue: 0,0:43:09.15,0:43:10.91,Default,,0,0,0,,但所指的数据结构却没有被复制 Dialogue: 0,0:43:13.41,0:43:14.84,Default,,0,0,0,,现在我要告诉你们 Dialogue: 0,0:43:15.04,0:43:18.38,Default,,0,0,0,,如何来添加按名传递参数 Dialogue: 0,0:43:19.99,0:43:22.12,Default,,0,0,0,,为什么我们需要这样的FEATURE呢? Dialogue: 0,0:43:23.10,0:43:24.72,Default,,0,0,0,,假设我们想要开发 Dialogue: 0,0:43:25.24,0:43:28.44,Default,,0,0,0,,像是某种特殊形式的功能 Dialogue: 0,0:43:28.73,0:43:29.72,Default,,0,0,0,,类似于“保留字” Dialogue: 0,0:43:29.72,0:43:31.48,Default,,0,0,0,,但不是用保留字的方式来实现 Dialogue: 0,0:43:32.18,0:43:34.76,Default,,0,0,0,,我想用过程来实现类似IF的效果 Dialogue: 0,0:43:36.36,0:43:39.42,Default,,0,0,0,,无论是IF还是COND 都是特殊形式 Dialogue: 0,0:43:39.42,0:43:40.43,Default,,0,0,0,,它俩是一样的 Dialogue: 0,0:43:40.59,0:43:42.86,Default,,0,0,0,,这个特殊形式用于 Dialogue: 0,0:43:42.92,0:43:45.02,Default,,0,0,0,,根据谓词返回真假 Dialogue: 0,0:43:46.22,0:43:49.76,Default,,0,0,0,,决定求值真子句还是假子句 Dialogue: 0,0:43:50.84,0:43:53.12,Default,,0,0,0,,它们都是根据某个值 Dialogue: 0,0:43:53.44,0:43:55.36,Default,,0,0,0,,来决定是否去做另外的某件事 Dialogue: 0,0:43:57.27,0:43:58.88,Default,,0,0,0,,然而像+之类的过程 Dialogue: 0,0:43:59.15,0:44:01.20,Default,,0,0,0,,也就是那些我们现在可以定义的过程 Dialogue: 0,0:44:01.42,0:44:06.56,Default,,0,0,0,,是在应用前就求值所有的参数 Dialogue: 0,0:44:08.67,0:44:09.64,Default,,0,0,0,,因此 举例来说 Dialogue: 0,0:44:10.46,0:44:12.41,Default,,0,0,0,,假设我想定义一个过程 Dialogue: 0,0:44:15.39,0:44:18.75,Default,,0,0,0,,用IF来实现与IF相反的效果 Dialogue: 0,0:44:19.85,0:44:20.70,Default,,0,0,0,,我叫它UNLESS Dialogue: 0,0:44:24.89,0:44:27.47,Default,,0,0,0,,参数是 谓词P、真子句C和假子句A Dialogue: 0,0:44:28.67,0:44:30.44,Default,,0,0,0,,接下来 我想 Dialogue: 0,0:44:30.46,0:44:32.08,Default,,0,0,0,,用COND来实现 Dialogue: 0,0:44:32.64,0:44:36.72,Default,,0,0,0,,(COND ((NOT P) Dialogue: 0,0:44:38.96,0:44:40.32,Default,,0,0,0,,结果就是真子句C Dialogue: 0,0:44:41.58,0:44:45.63,Default,,0,0,0,,否则就是假子句A Dialogue: 0,0:44:51.29,0:44:52.76,Default,,0,0,0,,我定义这个过程是为了 Dialogue: 0,0:44:53.32,0:44:55.40,Default,,0,0,0,,请考虑下面这种情况 Dialogue: 0,0:44:56.92,0:45:04.12,Default,,0,0,0,,(UNLESS (= 1 0) Dialogue: 0,0:45:05.08,0:45:06.64,Default,,0,0,0,,那么结果就是2 Dialogue: 0,0:45:07.90,0:45:11.35,Default,,0,0,0,,否则 结果就是(/ 1 0) Dialogue: 0,0:45:15.92,0:45:18.91,Default,,0,0,0,,这段代码相当于进行这样的代换: Dialogue: 0,0:45:20.00,0:45:23.26,Default,,0,0,0,,用(= 1 0)、2和(/ 1 0) Dialogue: 0,0:45:23.66,0:45:24.76,Default,,0,0,0,,分别代换上面的P、C以及A Dialogue: 0,0:45:25.58,0:45:27.58,Default,,0,0,0,,这样很有趣 Dialogue: 0,0:45:28.11,0:45:30.33,Default,,0,0,0,,代换后就变成了 Dialogue: 0,0:45:30.75,0:45:38.44,Default,,0,0,0,,(COND ((NOT (= 1 0)) Dialogue: 0,0:45:40.62,0:45:42.54,Default,,0,0,0,,结果就是2 Dialogue: 0,0:45:44.28,0:45:45.10,Default,,0,0,0,,否则就是 Dialogue: 0,0:45:48.22,0:45:51.16,Default,,0,0,0,,(/ 1 0) Dialogue: 0,0:45:54.48,0:45:56.48,Default,,0,0,0,,你们也知道 如果向Lisp中输入这段代码 Dialogue: 0,0:45:57.74,0:45:58.59,Default,,0,0,0,,结果会是2 Dialogue: 0,0:45:59.97,0:46:01.32,Default,,0,0,0,,这没问题 Dialogue: 0,0:46:02.91,0:46:04.64,Default,,0,0,0,,但如果我输入的是这段代码 Dialogue: 0,0:46:05.28,0:46:07.79,Default,,0,0,0,,由于参数会在过程调用前求值 Dialogue: 0,0:46:09.12,0:46:10.73,Default,,0,0,0,,那么这段代码就会报错 Dialogue: 0,0:46:13.38,0:46:15.61,Default,,0,0,0,,当然 如果成功进行代换的话 Dialogue: 0,0:46:16.03,0:46:16.88,Default,,0,0,0,,我可以得到正确的结果 Dialogue: 0,0:46:16.88,0:46:20.16,Default,,0,0,0,,但是这里这种情况 代换并不能进行 Dialogue: 0,0:46:22.17,0:46:23.86,Default,,0,0,0,,我连错误的结果都无法得到 Dialogue: 0,0:46:23.86,0:46:24.67,Default,,0,0,0,,没有结果 Dialogue: 0,0:46:24.80,0:46:25.60,Default,,0,0,0,,只能得到错误 Dialogue: 0,0:46:28.42,0:46:31.21,Default,,0,0,0,,现在 我要想办法 Dialogue: 0,0:46:31.61,0:46:32.99,Default,,0,0,0,,使这样的定义可以成功运行 Dialogue: 0,0:46:34.48,0:46:36.51,Default,,0,0,0,,但我想标注出 Dialogue: 0,0:46:36.70,0:46:38.76,Default,,0,0,0,,C和A是特殊的东西 Dialogue: 0,0:46:39.93,0:46:43.15,Default,,0,0,0,,我想使它们自动地延时求值 Dialogue: 0,0:46:44.27,0:46:48.08,Default,,0,0,0,,我不想它们在我调用过程的时候 Dialogue: 0,0:46:48.52,0:46:49.74,Default,,0,0,0,,就被求值 Dialogue: 0,0:46:51.52,0:46:52.72,Default,,0,0,0,,所以我得先制定一种声明 Dialogue: 0,0:46:52.75,0:46:55.32,Default,,0,0,0,,然后再考虑如何实现此种声明 Dialogue: 0,0:46:55.60,0:46:57.63,Default,,0,0,0,,再次强调 希望你们能够提醒自己 Dialogue: 0,0:46:57.79,0:47:00.25,Default,,0,0,0,,我们这里添加的是临时组件 Dialogue: 0,0:47:00.76,0:47:02.16,Default,,0,0,0,,必须要知道 Dialogue: 0,0:47:02.25,0:47:04.72,Default,,0,0,0,,滥用临时组件会造成大混乱 Dialogue: 0,0:47:05.75,0:47:09.79,Default,,0,0,0,,还会破坏一些已有的东西 Dialogue: 0,0:47:10.12,0:47:12.70,Default,,0,0,0,,首先 它会造成语法歧义性么? Dialogue: 0,0:47:13.86,0:47:15.50,Default,,0,0,0,,就我们目前已有的语法来说 Dialogue: 0,0:47:15.71,0:47:16.91,Default,,0,0,0,,它不会造成什么歧义 Dialogue: 0,0:47:17.84,0:47:20.76,Default,,0,0,0,,但接下来要做的却可能招来麻烦 Dialogue: 0,0:47:21.67,0:47:24.67,Default,,0,0,0,,我要添加的东西可能会跟 Dialogue: 0,0:47:25.15,0:47:27.10,Default,,0,0,0,,我以后添加的类型声明冲突 Dialogue: 0,0:47:28.19,0:47:31.08,Default,,0,0,0,,类型系统通过提供已知的类型信息 Dialogue: 0,0:47:31.21,0:47:33.66,Default,,0,0,0,,使得语言系统或者编译器可以做出优化 Dialogue: 0,0:47:34.75,0:47:36.97,Default,,0,0,0,,当然也会与我想添加的形式参数的 Dialogue: 0,0:47:37.00,0:47:39.71,Default,,0,0,0,,其它类型的声明相冲突 Dialogue: 0,0:47:40.57,0:47:42.56,Default,,0,0,0,,所以这里我并不打算做一个一般性的机制 Dialogue: 0,0:47:43.77,0:47:45.24,Default,,0,0,0,,使得我可以添加声明 Dialogue: 0,0:47:45.28,0:47:46.54,Default,,0,0,0,,虽然我很想那么做 Dialogue: 0,0:47:46.89,0:47:48.81,Default,,0,0,0,,但现在并不打算这么做 Dialogue: 0,0:47:51.01,0:47:53.88,Default,,0,0,0,,接下来 我要添加某种临时的解决方法 Dialogue: 0,0:47:57.56,0:48:08.38,Default,,0,0,0,,(DEFINE (UNLESS P Dialogue: 0,0:48:08.81,0:48:10.27,Default,,0,0,0,,后面的参数都是按名调用 Dialogue: 0,0:48:12.78,0:48:15.28,Default,,0,0,0,,分别记作(NAME C)和(NAME A) Dialogue: 0,0:48:19.85,0:48:25.28,Default,,0,0,0,,哈 哈 卡在黑板边了 Dialogue: 0,0:48:31.76,0:48:35.61,Default,,0,0,0,,(COND ((NOT P) C) Dialogue: 0,0:48:36.80,0:48:41.16,Default,,0,0,0,,(ELSE A))) Dialogue: 0,0:48:44.67,0:48:46.88,Default,,0,0,0,,我可以显式地声明 Dialogue: 0,0:48:47.55,0:48:51.65,Default,,0,0,0,,哪些参数按名称传递或延时求值 Dialogue: 0,0:48:55.60,0:48:58.48,Default,,0,0,0,,对解释器的这个修改并不简单 Dialogue: 0,0:48:58.70,0:48:59.77,Default,,0,0,0,,反而相当复杂 Dialogue: 0,0:49:00.45,0:49:03.10,Default,,0,0,0,,我们之前介绍的动态绑定 Dialogue: 0,0:49:03.40,0:49:06.89,Default,,0,0,0,,或者让过程支持不定数目的参数 Dialogue: 0,0:49:07.50,0:49:08.52,Default,,0,0,0,,都相对简单 Dialogue: 0,0:49:09.28,0:49:11.28,Default,,0,0,0,,这次的修改涉及基本策略 Dialogue: 0,0:49:12.32,0:49:13.39,Default,,0,0,0,,这里的问题是 Dialogue: 0,0:49:13.96,0:49:17.63,Default,,0,0,0,,我们的解释器 就如代码所写的那样 Dialogue: 0,0:49:17.96,0:49:23.40,Default,,0,0,0,,在求值组合式时 Dialogue: 0,0:49:24.24,0:49:25.92,Default,,0,0,0,,先通过求值运算符取得过程 Dialogue: 0,0:49:26.20,0:49:30.35,Default,,0,0,0,,然后再求值运算对象得到参数 Dialogue: 0,0:49:30.76,0:49:35.26,Default,,0,0,0,,再把过程应用到参数上 Dialogue: 0,0:49:36.38,0:49:37.07,Default,,0,0,0,,然而这里 Dialogue: 0,0:49:37.36,0:49:41.48,Default,,0,0,0,,直到我检查了整个过程 Dialogue: 0,0:49:41.74,0:49:43.66,Default,,0,0,0,,确定了程序的声明 Dialogue: 0,0:49:44.62,0:49:46.86,Default,,0,0,0,,才会去求值程序的参数 Dialogue: 0,0:49:49.59,0:49:50.59,Default,,0,0,0,,我们来看这个 Dialogue: 0,0:49:52.68,0:49:56.54,Default,,0,0,0,,这是修改后的求值器 Dialogue: 0,0:49:57.48,0:50:01.15,Default,,0,0,0,,我是基于那个最简单的词法作用域求值器 Dialogue: 0,0:50:01.72,0:50:02.65,Default,,0,0,0,,不是动态绑定的那个 Dialogue: 0,0:50:04.14,0:50:08.20,Default,,0,0,0,,但是却要做一些类似于动态绑定的修改 Dialogue: 0,0:50:09.75,0:50:11.45,Default,,0,0,0,,这是因为 Dialogue: 0,0:50:11.90,0:50:13.34,Default,,0,0,0,,如果我延时一个过程 -- Dialogue: 0,0:50:13.66,0:50:15.15,Default,,0,0,0,,哦说错了 -- 延时一个过程的参数 Dialogue: 0,0:50:15.40,0:50:17.52,Default,,0,0,0,,就必须把当前的环境和参数关联在一起 Dialogue: 0,0:50:19.36,0:50:21.55,Default,,0,0,0,,还记得Hal教授如何实现DELAY的吧? Dialogue: 0,0:50:23.38,0:50:25.44,Default,,0,0,0,,Hal教授把DELAY实现为 Dialogue: 0,0:50:25.50,0:50:27.47,Default,,0,0,0,,一个无参过程 Dialogue: 0,0:50:28.56,0:50:30.52,Default,,0,0,0,,用来执行某些表达式 Dialogue: 0,0:50:31.18,0:50:36.94,Default,,0,0,0,,就是这样让表达式延迟求值的 Dialogue: 0,0:50:39.29,0:50:40.99,Default,,0,0,0,,(DELAY E)实际上是这个 Dialogue: 0,0:50:44.52,0:50:46.92,Default,,0,0,0,,然而 如果我求值这个LAMBDA表达式 Dialogue: 0,0:50:47.42,0:50:49.20,Default,,0,0,0,,我就必须得捕获当前环境 Dialogue: 0,0:50:51.41,0:50:53.45,Default,,0,0,0,,这是因为 Dialogue: 0,0:50:54.60,0:50:56.32,Default,,0,0,0,,我想让这其中的变量的值 Dialogue: 0,0:50:57.02,0:51:00.83,Default,,0,0,0,,取决于它们被定义时的上下文 Dialogue: 0,0:51:04.01,0:51:05.76,Default,,0,0,0,,这也就是为什么要用LAMBDA表达式 Dialogue: 0,0:51:06.62,0:51:07.50,Default,,0,0,0,,这才是正确的 Dialogue: 0,0:51:08.07,0:51:15.12,Default,,0,0,0,,(FORCE E)则相当于 Dialogue: 0,0:51:16.52,0:51:20.08,Default,,0,0,0,,无参地调用这个过程 Dialogue: 0,0:51:21.09,0:51:22.28,Default,,0,0,0,,恰恰和上面相对 Dialogue: 0,0:51:24.10,0:51:26.94,Default,,0,0,0,,这个调用产生的环境则是 Dialogue: 0,0:51:27.36,0:51:29.90,Default,,0,0,0,,定义这个过程时的环境 Dialogue: 0,0:51:30.81,0:51:32.36,Default,,0,0,0,,额外加上一个空框架 Dialogue: 0,0:51:33.23,0:51:34.41,Default,,0,0,0,,我并不在意它 Dialogue: 0,0:51:36.24,0:51:39.40,Default,,0,0,0,,我们再来看这张幻灯片 Dialogue: 0,0:51:40.99,0:51:43.72,Default,,0,0,0,,仔细观察一会儿 Dialogue: 0,0:51:44.14,0:51:46.12,Default,,0,0,0,,会发现大部分跟以前相同 Dialogue: 0,0:51:46.35,0:51:50.65,Default,,0,0,0,,只是对应用或组合式的处理不同 Dialogue: 0,0:51:51.98,0:51:53.71,Default,,0,0,0,,处理组合式分两步 Dialogue: 0,0:51:54.68,0:51:57.79,Default,,0,0,0,,首先要求值这个过程 Dialogue: 0,0:51:57.92,0:51:59.88,Default,,0,0,0,,我就必须通过求值运算符来得到对应过程 Dialogue: 0,0:52:00.70,0:52:01.69,Default,,0,0,0,,也就是这一部分 Dialogue: 0,0:52:02.38,0:52:04.35,Default,,0,0,0,,我得这个值是计算求出的现值 Dialogue: 0,0:52:04.46,0:52:05.76,Default,,0,0,0,,而不是一个延时对象 Dialogue: 0,0:52:06.36,0:52:09.85,Default,,0,0,0,,也就要求值它在被延时前的表达式 Dialogue: 0,0:52:10.73,0:52:12.08,Default,,0,0,0,,接下来我就要 Dialogue: 0,0:52:12.24,0:52:17.32,Default,,0,0,0,,把它应用于运算对象 Dialogue: 0,0:52:18.03,0:52:19.61,Default,,0,0,0,,但我仍然要保持这个环境 Dialogue: 0,0:52:19.63,0:52:20.92,Default,,0,0,0,,并将其传递过去 Dialogue: 0,0:52:21.53,0:52:23.71,Default,,0,0,0,,如果有一些运算对象是延时了的 Dialogue: 0,0:52:23.71,0:52:27.53,Default,,0,0,0,,我就需要为这些运算对象附上相应的环境 Dialogue: 0,0:52:29.66,0:52:31.52,Default,,0,0,0,,这里的处理相当复杂 Dialogue: 0,0:52:32.99,0:52:34.24,Default,,0,0,0,,来看看APPLY中对应的部分 Dialogue: 0,0:52:36.40,0:52:38.72,Default,,0,0,0,,APPLY这一部分处理基本过程 Dialogue: 0,0:52:39.36,0:52:40.60,Default,,0,0,0,,这和之前一样 Dialogue: 0,0:52:42.61,0:52:44.68,Default,,0,0,0,,但复合过程部分就比较有意思了 Dialogue: 0,0:52:47.25,0:52:49.52,Default,,0,0,0,,和之前一样 我需要求值过程体 Dialogue: 0,0:52:50.48,0:52:51.98,Default,,0,0,0,,基于的环境是 Dialogue: 0,0:52:52.28,0:52:54.97,Default,,0,0,0,,把形式参数和 Dialogue: 0,0:52:55.61,0:53:00.29,Default,,0,0,0,,实际参数绑定在一起的结果 Dialogue: 0,0:53:00.29,0:53:01.07,Default,,0,0,0,,是这样的 Dialogue: 0,0:53:01.53,0:53:03.82,Default,,0,0,0,,环境来自于过程对象 Dialogue: 0,0:53:03.82,0:53:06.65,Default,,0,0,0,,因为我们的语言是词法作用域、静态绑定的 Dialogue: 0,0:53:08.04,0:53:11.82,Default,,0,0,0,,然而 我还需要去掉NAME声明 Dialogue: 0,0:53:11.84,0:53:12.84,Default,,0,0,0,,获得变量的实际名字 Dialogue: 0,0:53:12.84,0:53:15.20,Default,,0,0,0,,这是由VNAMES过程完成的 Dialogue: 0,0:53:15.45,0:53:16.67,Default,,0,0,0,,然后要做的就是 Dialogue: 0,0:53:16.97,0:53:18.86,Default,,0,0,0,,处理这些声明 Dialogue: 0,0:53:19.13,0:53:21.52,Default,,0,0,0,,决定这些运算对象中 Dialogue: 0,0:53:21.76,0:53:23.92,Default,,0,0,0,,现在它们还是形式参数 而非实际参数 Dialogue: 0,0:53:24.09,0:53:25.87,Default,,0,0,0,,哪些运算对象需要立即求值 Dialogue: 0,0:53:26.62,0:53:30.20,Default,,0,0,0,,而哪些运算对象又要 Dialogue: 0,0:53:30.99,0:53:33.77,Default,,0,0,0,,用某种方式封装为延时对象 Dialogue: 0,0:53:37.28,0:53:40.08,Default,,0,0,0,,另外 在处理基本过程这里 Dialogue: 0,0:53:40.60,0:53:42.38,Default,,0,0,0,,当遇到像+这样的基本过程 Dialogue: 0,0:53:42.68,0:53:45.58,Default,,0,0,0,,它们的参数最好立即求值 Dialogue: 0,0:53:45.82,0:53:47.39,Default,,0,0,0,,也就我们需要是这里FORCE这些表达式 Dialogue: 0,0:53:47.92,0:53:50.38,Default,,0,0,0,,EVLIST中完成了很多FORCE操作 Dialogue: 0,0:53:51.34,0:53:52.78,Default,,0,0,0,,现在 我们有了两种不同的EVLIST Dialogue: 0,0:53:52.78,0:53:54.09,Default,,0,0,0,,EVLIST和GEVLIST Dialogue: 0,0:53:54.52,0:53:57.16,Default,,0,0,0,,GEVLIST封装延迟参数 Dialogue: 0,0:53:57.18,0:53:59.74,Default,,0,0,0,,而对另外的参数立即求值 Dialogue: 0,0:53:59.87,0:54:05.85,Default,,0,0,0,,而EVLIST则会FORCE所有的表达式 Dialogue: 0,0:54:07.90,0:54:09.16,Default,,0,0,0,,简单地看下EVLIST的代码 Dialogue: 0,0:54:09.69,0:54:11.98,Default,,0,0,0,,课后你们一定要亲自上手试试 Dialogue: 0,0:54:12.25,0:54:14.67,Default,,0,0,0,,光是听我在这里讲课 Dialogue: 0,0:54:14.72,0:54:18.20,Default,,0,0,0,,可不能够学到求值器的不同变种 Dialogue: 0,0:54:19.52,0:54:21.24,Default,,0,0,0,,你们需要上手亲自实践一下。 Dialogue: 0,0:54:21.37,0:54:23.84,Default,,0,0,0,,你试验过后 对它们有了感悟 Dialogue: 0,0:54:24.22,0:54:27.02,Default,,0,0,0,,你才能理解各种可能的设计决策 Dialogue: 0,0:54:27.77,0:54:29.16,Default,,0,0,0,,才能清楚它们如何相互关联 Dialogue: 0,0:54:29.93,0:54:32.38,Default,,0,0,0,,了解求值器描述的是何种语言 Dialogue: 0,0:54:33.16,0:54:34.64,Default,,0,0,0,,以及构建一门合理的语言 Dialogue: 0,0:54:34.94,0:54:36.32,Default,,0,0,0,,需要哪些一致性集合 Dialogue: 0,0:54:37.20,0:54:40.06,Default,,0,0,0,,哪些临时方案又是复杂而无用 Dialogue: 0,0:54:41.85,0:54:44.68,Default,,0,0,0,,就和我说得一样 这里的EVLIST Dialogue: 0,0:54:44.81,0:54:46.03,Default,,0,0,0,,参数之一为运算对象表 Dialogue: 0,0:54:46.70,0:54:50.28,Default,,0,0,0,,表中的元素会在求值之后被取消延时 Dialogue: 0,0:54:50.75,0:54:51.90,Default,,0,0,0,,它们都会被FORCE Dialogue: 0,0:54:53.28,0:54:54.44,Default,,0,0,0,,无论它们是否为延时对象 Dialogue: 0,0:54:56.05,0:54:58.51,Default,,0,0,0,,下一个 GEVLIST Dialogue: 0,0:55:01.26,0:55:01.85,Default,,0,0,0,,谢谢 Dialogue: 0,0:55:04.04,0:55:06.35,Default,,0,0,0,,我们在这里会发现 Dialogue: 0,0:55:07.80,0:55:09.61,Default,,0,0,0,,这里面有多种可能 Dialogue: 0,0:55:09.81,0:55:11.52,Default,,0,0,0,,要么是普通的情况 Dialogue: 0,0:55:12.48,0:55:13.69,Default,,0,0,0,,比如元素直接是一个符号 Dialogue: 0,0:55:13.74,0:55:16.20,Default,,0,0,0,,就像UNLESS中的参数P那样 Dialogue: 0,0:55:17.64,0:55:18.81,Default,,0,0,0,,对应这一部分代码 Dialogue: 0,0:55:19.39,0:55:22.49,Default,,0,0,0,,在这种情况下 我们就用应用序来求值 Dialogue: 0,0:55:23.34,0:55:25.45,Default,,0,0,0,,基本上就像以前一样 Dialogue: 0,0:55:25.63,0:55:28.84,Default,,0,0,0,,就是将EVAL映射在这个表上 Dialogue: 0,0:55:29.95,0:55:32.14,Default,,0,0,0,,换言之 就是先求值第一个表达式 Dialogue: 0,0:55:32.65,0:55:37.36,Default,,0,0,0,,然后在ENV中 求值(GEVLIST (CDR EXPRS)) Dialogue: 0,0:55:37.93,0:55:43.20,Default,,0,0,0,,然而 我们也可能遇到按名传递的参数 Dialogue: 0,0:55:44.00,0:55:45.05,Default,,0,0,0,,如果参数是按名传递 Dialogue: 0,0:55:45.20,0:55:46.59,Default,,0,0,0,,我就需要给它包裹上一个DELAY Dialogue: 0,0:55:47.00,0:55:50.97,Default,,0,0,0,,DELAY里面就是我想按名调用的表达式 Dialogue: 0,0:55:52.14,0:55:57.74,Default,,0,0,0,,还要附上定义过程时的环境 Dialogue: 0,0:55:59.05,0:56:00.59,Default,,0,0,0,,把它们作为实际参数 Dialogue: 0,0:56:02.79,0:56:05.04,Default,,0,0,0,,然后像这样继续递归处理 Dialogue: 0,0:56:09.07,0:56:11.31,Default,,0,0,0,,这个解释器中另外一个有意思的地方 Dialogue: 0,0:56:11.37,0:56:13.53,Default,,0,0,0,,就在于COND Dialogue: 0,0:56:14.70,0:56:15.92,Default,,0,0,0,,人们可能就这么来写 Dialogue: 0,0:56:15.93,0:56:17.24,Default,,0,0,0,,然后就不管了 Dialogue: 0,0:56:18.55,0:56:19.98,Default,,0,0,0,,你需要在一处FORCE Dialogue: 0,0:56:20.51,0:56:23.10,Default,,0,0,0,,COND表达式需要知道 Dialogue: 0,0:56:24.20,0:56:25.90,Default,,0,0,0,,谓词判定结果的真假 Dialogue: 0,0:56:25.99,0:56:26.83,Default,,0,0,0,,就像基本过程那样 Dialogue: 0,0:56:28.55,0:56:30.56,Default,,0,0,0,,求值COND语句时 需要FORCE Dialogue: 0,0:56:31.72,0:56:33.95,Default,,0,0,0,,剩下的细节就没什么特别的了 Dialogue: 0,0:56:34.62,0:56:36.28,Default,,0,0,0,,就先不深究了 Dialogue: 0,0:56:36.75,0:56:38.99,Default,,0,0,0,,剩下的就是如何实现MAKE-DELAY Dialogue: 0,0:56:38.99,0:56:40.91,Default,,0,0,0,,延时对象是一种数据结构 Dialogue: 0,0:56:41.31,0:56:44.75,Default,,0,0,0,,它包括:类型标识、表达式以及环境 Dialogue: 0,0:56:44.84,0:56:46.36,Default,,0,0,0,,它的类型标识是'THUNK Dialogue: 0,0:56:46.96,0:56:48.46,Default,,0,0,0,,这个术语来自于Algol语言 Dialogue: 0,0:56:49.07,0:56:50.81,Default,,0,0,0,,据说这是个拟声词 Dialogue: 0,0:56:50.83,0:56:52.06,Default,,0,0,0,,是把东西压栈的声音 Dialogue: 0,0:56:52.97,0:56:53.41,Default,,0,0,0,,我不太清楚 Dialogue: 0,0:56:53.41,0:56:57.12,Default,,0,0,0,,我既不是Algol学家 又不是Algol程序员 Dialogue: 0,0:56:57.60,0:56:58.38,Default,,0,0,0,,所以我不太清楚 Dialogue: 0,0:56:58.74,0:56:59.64,Default,,0,0,0,,但据说它是那样的 Dialogue: 0,0:57:00.27,0:57:01.56,Default,,0,0,0,,而UNDELAY的定义则是 Dialogue: 0,0:57:01.77,0:57:03.66,Default,,0,0,0,,递归地UNDELAY这些THUNK Dialogue: 0,0:57:03.69,0:57:06.00,Default,,0,0,0,,直到得到一个非THUNK对象 Dialogue: 0,0:57:07.72,0:57:10.94,Default,,0,0,0,,这就是如何实现Algol中的按名调用 Dialogue: 0,0:57:12.05,0:57:13.76,Default,,0,0,0,,差不多就是这样了 Dialogue: 0,0:57:15.21,0:57:16.25,Default,,0,0,0,,有什么问题吗? Dialogue: 0,0:57:26.68,0:57:27.52,Default,,0,0,0,,学生:Gerry? Dialogue: 0,0:57:28.09,0:57:28.80,Default,,0,0,0,,教授:你说 Vesko Dialogue: 0,0:57:30.03,0:57:32.99,Default,,0,0,0,,学生:我注意到 对于基本过程 Dialogue: 0,0:57:33.44,0:57:34.89,Default,,0,0,0,,你是避免按名调用的 Dialogue: 0,0:57:36.41,0:57:38.38,Default,,0,0,0,,我很想知道 你为什么要这样? Dialogue: 0,0:57:38.41,0:57:39.21,Default,,0,0,0,,需要这样吗? Dialogue: 0,0:57:40.07,0:57:41.61,Default,,0,0,0,,教授:Vesko想问的是 Dialogue: 0,0:57:42.06,0:57:46.00,Default,,0,0,0,,基本过程也按名调用是否合理? Dialogue: 0,0:57:47.14,0:57:48.70,Default,,0,0,0,,答案是:是的 Dialogue: 0,0:57:49.27,0:57:52.32,Default,,0,0,0,,有一种情况下是可以的 实际上是两种 Dialogue: 0,0:57:55.53,0:57:58.27,Default,,0,0,0,,比如用CONS来构造一个数据结构 Dialogue: 0,0:57:59.02,0:58:02.00,Default,,0,0,0,,构建一个元素个数不定的数组时 Dialogue: 0,0:58:03.26,0:58:07.44,Default,,0,0,0,,就没必要求值参数 Dialogue: 0,0:58:07.44,0:58:08.83,Default,,0,0,0,,你只需要创建一些PROMISE Dialogue: 0,0:58:09.10,0:58:10.81,Default,,0,0,0,,在确实需要时才来求值这些参数 Dialogue: 0,0:58:11.50,0:58:15.08,Default,,0,0,0,,如果我把两个对象CONS起来 Dialogue: 0,0:58:16.24,0:58:17.77,Default,,0,0,0,,那么我CONS这些PROMISE Dialogue: 0,0:58:17.80,0:58:19.93,Default,,0,0,0,,就和CONS这些对象一样容易 Dialogue: 0,0:58:21.15,0:58:23.37,Default,,0,0,0,,甚至在对它们进行CAR CDR的时候 Dialogue: 0,0:58:23.39,0:58:24.30,Default,,0,0,0,,也不用进行实际的计算 Dialogue: 0,0:58:24.84,0:58:26.97,Default,,0,0,0,,取出PROMISE 并直接传递给其它人 Dialogue: 0,0:58:28.26,0:58:30.51,Default,,0,0,0,,这也就是为什么Alonzo Church用LAMBDA演算 Dialogue: 0,0:58:30.57,0:58:34.03,Default,,0,0,0,,定义的CAR、CDR和CONS说得通的原因 Dialogue: 0,0:58:34.42,0:58:36.32,Default,,0,0,0,,这是因为CAR、CDR以及CONS并没有执行计算 Dialogue: 0,0:58:36.38,0:58:40.06,Default,,0,0,0,,你们可以认为它是在重组数据而已 Dialogue: 0,0:58:40.99,0:58:42.20,Default,,0,0,0,,然而像 + 这样的过程 Dialogue: 0,0:58:42.24,0:58:43.84,Default,,0,0,0,,必须要了解参数是什么 Dialogue: 0,0:58:45.28,0:58:46.91,Default,,0,0,0,,它们需要确认 Dialogue: 0,0:58:47.12,0:58:48.30,Default,,0,0,0,,构成这些数字的比特 Dialogue: 0,0:58:48.32,0:58:50.44,Default,,0,0,0,,除非它们处理的是LAMBDA演算中的数字 Dialogue: 0,0:58:50.44,0:58:51.88,Default,,0,0,0,,这就是另外一码事了 Dialogue: 0,0:58:52.43,0:58:53.58,Default,,0,0,0,,为了运算加法 Dialogue: 0,0:58:53.77,0:58:55.53,Default,,0,0,0,,它需要知道构成数字的比特 Dialogue: 0,0:58:59.21,0:58:59.92,Default,,0,0,0,,因此 实际上 Dialogue: 0,0:59:00.19,0:59:02.78,Default,,0,0,0,,数据的构造过程和选择过程 Dialogue: 0,0:59:03.24,0:59:05.50,Default,,0,0,0,,以及具有副作用的数据对象 Dialogue: 0,0:59:06.27,0:59:09.76,Default,,0,0,0,,在最极端的惰性解释器中 Dialogue: 0,0:59:11.34,0:59:13.39,Default,,0,0,0,,也不需要被FORCE Dialogue: 0,0:59:16.46,0:59:16.99,Default,,0,0,0,,另外一方面 Dialogue: 0,0:59:17.02,0:59:18.70,Default,,0,0,0,,针对数据结构的谓词需要被FORCE Dialogue: 0,0:59:19.61,0:59:22.65,Default,,0,0,0,,如果你想判断 这是一个序对吗? Dialogue: 0,0:59:23.56,0:59:24.40,Default,,0,0,0,,或者是一个符号? Dialogue: 0,0:59:24.64,0:59:26.57,Default,,0,0,0,,最好搞清楚是什么 Dialogue: 0,0:59:30.30,0:59:31.18,Default,,0,0,0,,还有问题吗? Dialogue: 0,0:59:40.05,0:59:41.61,Default,,0,0,0,,那好吧 下课 Dialogue: 0,0:59:42.10,1:00:04.56,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:59:42.10,1:00:04.56,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec7b.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 1 Video Position: 516 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:09.52,0:00:13.66,EN,,0,0,0,,Metacircular Evaluator II Dialogue: 0,0:00:17.21,0:00:17.96,EN,,0,0,0,,PROFESSOR: Well, let's see. Dialogue: 0,0:00:19.52,0:00:21.29,EN,,0,0,0,,What we did so far was a lot of fun, Dialogue: 0,0:00:21.52,0:00:23.05,EN,,0,0,0,,was it useful for anything? Dialogue: 0,0:00:26.33,0:00:27.96,EN,,0,0,0,,I suppose the answer is going to be yes. Dialogue: 0,0:00:29.38,0:00:31.92,EN,,0,0,0,,If these metacircular interpreters Dialogue: 0,0:00:32.96,0:00:34.60,EN,,0,0,0,,are a valuable thing to play with. Dialogue: 0,0:00:34.62,0:00:36.17,EN,,0,0,0,,I spend, say Dialogue: 0,0:00:38.05,0:00:41.85,EN,,0,0,0,,there have been times I spend 50% of my time, over a year, Dialogue: 0,0:00:42.86,0:00:45.26,EN,,0,0,0,,trying various design alternatives Dialogue: 0,0:00:45.76,0:00:48.19,EN,,0,0,0,,by experimenting with them with metacircular interpreters-- Dialogue: 0,0:00:49.47,0:00:52.01,EN,,0,0,0,,metacircular interpreters like the sort you just saw. Dialogue: 0,0:00:52.57,0:00:54.11,EN,,0,0,0,,Metacircular is because Dialogue: 0,0:00:54.72,0:00:56.94,EN,,0,0,0,,they are defined in terms of themselves in such a way Dialogue: 0,0:00:56.97,0:00:59.71,EN,,0,0,0,,that the language they interpret contains itself. Dialogue: 0,0:01:01.27,0:01:03.87,EN,,0,0,0,,Such interpreters are a convenient medium Dialogue: 0,0:01:03.88,0:01:05.58,EN,,0,0,0,,for exploring language issues. Dialogue: 0,0:01:06.80,0:01:09.44,EN,,0,0,0,,If you want to try adding a new feature, Dialogue: 0,0:01:10.51,0:01:12.38,EN,,0,0,0,,it's sort of a snap, it's easy, Dialogue: 0,0:01:12.73,0:01:15.10,EN,,0,0,0,,you just do it and see what happens. Dialogue: 0,0:01:15.49,0:01:17.20,EN,,0,0,0,,You play with that language for a while you say, Dialogue: 0,0:01:17.24,0:01:18.24,EN,,0,0,0,,gee, I'm didn't like that, Dialogue: 0,0:01:18.52,0:01:19.47,EN,,0,0,0,,you throw it away. Dialogue: 0,0:01:20.96,0:01:23.55,EN,,0,0,0,,Or you might want to see what Dialogue: 0,0:01:23.64,0:01:27.37,EN,,0,0,0,,the difference is if you'd make a slight difference in the binding strategy, Dialogue: 0,0:01:28.81,0:01:31.90,EN,,0,0,0,,or some more complicated things that might occur. Dialogue: 0,0:01:33.72,0:01:35.48,EN,,0,0,0,,In fact, these metacircular interpreters Dialogue: 0,0:01:36.17,0:01:37.88,EN,,0,0,0,,are an excellent medium for people Dialogue: 0,0:01:38.20,0:01:42.56,EN,,0,0,0,,exchanging ideas about language design, Dialogue: 0,0:01:43.98,0:01:45.74,EN,,0,0,0,,because they're pretty easy to understand, Dialogue: 0,0:01:46.28,0:01:48.46,EN,,0,0,0,,and they're short, and compact, and simple. Dialogue: 0,0:01:49.32,0:01:50.80,EN,,0,0,0,,If I have some idea Dialogue: 0,0:01:51.53,0:01:53.77,EN,,0,0,0,,that I want somebody to criticize Dialogue: 0,0:01:54.25,0:01:58.32,EN,,0,0,0,,like say, Dan Friedman at Indiana, Dialogue: 0,0:01:59.05,0:02:02.00,EN,,0,0,0,,I'd write a little metacircular interpreter Dialogue: 0,0:02:02.56,0:02:03.79,EN,,0,0,0,,send him some network mail Dialogue: 0,0:02:04.65,0:02:05.45,EN,,0,0,0,,with this interpreter in it. Dialogue: 0,0:02:05.45,0:02:07.90,EN,,0,0,0,,He could whip it up on his machine and play with it Dialogue: 0,0:02:07.92,0:02:09.82,EN,,0,0,0,,and say, that's no good. Dialogue: 0,0:02:11.94,0:02:13.10,EN,,0,0,0,,And then send it back to me and say, Dialogue: 0,0:02:13.13,0:02:14.83,EN,,0,0,0,,well, why don't you try this one, it's a little better. Dialogue: 0,0:02:16.88,0:02:19.36,EN,,0,0,0,,So I want to show you some of that technology. Dialogue: 0,0:02:20.16,0:02:24.20,EN,,0,0,0,,See, because, really, it's the essential, simple technology Dialogue: 0,0:02:24.72,0:02:28.68,EN,,0,0,0,,for getting started in designing your own languages for particular purposes. Dialogue: 0,0:02:30.79,0:02:32.08,EN,,0,0,0,,Let's start by adding Dialogue: 0,0:02:32.51,0:02:34.21,EN,,0,0,0,,a very simple feature to a Lisp. Dialogue: 0,0:02:40.64,0:02:44.37,EN,,0,0,0,,Now, one thing I want to tell you about is features, before I start. Dialogue: 0,0:02:49.56,0:02:52.17,EN,,0,0,0,,There are many languages that have made a mess of themselves Dialogue: 0,0:02:53.05,0:02:54.91,EN,,0,0,0,,by adding huge numbers of features. Dialogue: 0,0:02:56.86,0:02:58.38,EN,,0,0,0,,Computer scientists have a joke Dialogue: 0,0:02:59.28,0:03:02.52,EN,,0,0,0,,about bugs that transform it to features all the time. Dialogue: 0,0:03:05.03,0:03:06.46,EN,,0,0,0,,But I like to think of it is that Dialogue: 0,0:03:08.91,0:03:11.44,EN,,0,0,0,,many systems suffer from what's called creeping featurism. Dialogue: 0,0:03:12.82,0:03:13.44,EN,,0,0,0,,Which is that Dialogue: 0,0:03:14.94,0:03:18.16,EN,,0,0,0,,George has a pet feature he'd like in the system, Dialogue: 0,0:03:18.72,0:03:19.36,EN,,0,0,0,,so he adds it. Dialogue: 0,0:03:20.17,0:03:22.14,EN,,0,0,0,,And then Harry says, go says Dialogue: 0,0:03:22.17,0:03:24.20,EN,,0,0,0,,gee, this system is no longer what exactly I like, Dialogue: 0,0:03:24.24,0:03:25.92,EN,,0,0,0,,so I'm going to add my favorite feature. Dialogue: 0,0:03:26.64,0:03:30.24,EN,,0,0,0,,And then Jim adds his favorite feature. Dialogue: 0,0:03:30.83,0:03:31.79,EN,,0,0,0,,And, after a while, Dialogue: 0,0:03:31.80,0:03:34.81,EN,,0,0,0,,the thing has a manual 500 pages long Dialogue: 0,0:03:35.15,0:03:36.51,EN,,0,0,0,,that no one can understand. Dialogue: 0,0:03:37.79,0:03:39.32,EN,,0,0,0,,And sometimes it's the same person Dialogue: 0,0:03:39.90,0:03:41.37,EN,,0,0,0,,who writes all of these features Dialogue: 0,0:03:41.39,0:03:43.23,EN,,0,0,0,,and produces this terribly complicated thing. Dialogue: 0,0:03:44.14,0:03:46.09,EN,,0,0,0,,In some cases, like editors, Dialogue: 0,0:03:47.37,0:03:49.12,EN,,0,0,0,,it's sort of reasonable to have lots of features, Dialogue: 0,0:03:50.92,0:03:52.65,EN,,0,0,0,,because there are a lot of things you want to be able to do Dialogue: 0,0:03:52.68,0:03:53.76,EN,,0,0,0,,and many of them arbitrary. Dialogue: 0,0:03:56.11,0:03:57.29,EN,,0,0,0,,But in computer languages, Dialogue: 0,0:03:57.85,0:03:58.91,EN,,0,0,0,,I think it's a disaster Dialogue: 0,0:04:00.01,0:04:01.29,EN,,0,0,0,,to have too much stuff in them. Dialogue: 0,0:04:04.03,0:04:08.00,EN,,0,0,0,,The other alternative you get into is something called feeping creaturism, Dialogue: 0,0:04:09.52,0:04:11.39,EN,,0,0,0,,which is where you have a box Dialogue: 0,0:04:11.80,0:04:15.29,EN,,0,0,0,,which has a display, a fancy display, and a mouse, Dialogue: 0,0:04:15.95,0:04:20.04,EN,,0,0,0,,and there is all sorts of complexity associated with all this fancy IO. Dialogue: 0,0:04:21.01,0:04:22.80,EN,,0,0,0,,And your computer language becomes Dialogue: 0,0:04:23.34,0:04:25.37,EN,,0,0,0,,a dismal, little, tiny thing that barely works Dialogue: 0,0:04:25.40,0:04:27.90,EN,,0,0,0,,because of all the swapping, and disk twitching, and so on, Dialogue: 0,0:04:28.09,0:04:29.36,EN,,0,0,0,,caused by your Window system. Dialogue: 0,0:04:30.08,0:04:31.82,EN,,0,0,0,,And every time you go near the computer, Dialogue: 0,0:04:31.93,0:04:33.45,EN,,0,0,0,,the mouse process wakes up and says, Dialogue: 0,0:04:33.85,0:04:35.95,EN,,0,0,0,,gee do you have something for me to do, Dialogue: 0,0:04:36.14,0:04:37.23,EN,,0,0,0,,and then it goes back to sleep. Dialogue: 0,0:04:37.44,0:04:39.44,EN,,0,0,0,,And if you accidentally push mouse with you elbow, Dialogue: 0,0:04:39.61,0:04:42.32,EN,,0,0,0,,a big puff of smoke comes out of your computer and things like that. Dialogue: 0,0:04:42.94,0:04:45.29,EN,,0,0,0,,So two ways to disastrously Dialogue: 0,0:04:45.55,0:04:47.21,EN,,0,0,0,,destroy a system by adding features. Dialogue: 0,0:04:47.50,0:04:49.73,EN,,0,0,0,,But try right now to add a little, simple feature. Dialogue: 0,0:04:52.60,0:04:53.77,EN,,0,0,0,,This actually is a good one, Dialogue: 0,0:04:53.85,0:04:56.17,EN,,0,0,0,,and in fact, real Lisps have it. Dialogue: 0,0:04:57.25,0:04:58.17,EN,,0,0,0,,As you've seen, Dialogue: 0,0:04:59.29,0:05:03.13,EN,,0,0,0,,there are procedures like plus and times Dialogue: 0,0:05:03.37,0:05:04.89,EN,,0,0,0,,that take any number of arguments. Dialogue: 0,0:05:05.43,0:05:06.44,EN,,0,0,0,,So we can write things Dialogue: 0,0:05:06.57,0:05:10.94,EN,,0,0,0,,like the sum of the product of a and x and x, Dialogue: 0,0:05:12.09,0:05:16.99,EN,,0,0,0,,and the product of b and x and c. Dialogue: 0,0:05:17.54,0:05:18.68,EN,,0,0,0,,As you can see here, Dialogue: 0,0:05:18.92,0:05:21.76,EN,,0,0,0,,addition takes three arguments or two arguments, Dialogue: 0,0:05:22.30,0:05:24.81,EN,,0,0,0,,multiplication takes two arguments or three arguments, Dialogue: 0,0:05:25.08,0:05:26.76,EN,,0,0,0,,taking numbers of arguments Dialogue: 0,0:05:26.78,0:05:28.49,EN,,0,0,0,,all of which are to be treated in the same way. Dialogue: 0,0:05:30.00,0:05:32.17,EN,,0,0,0,,This is a valuable thing, Dialogue: 0,0:05:32.28,0:05:34.01,EN,,0,0,0,,indefinite numbers of arguments. Dialogue: 0,0:05:34.96,0:05:38.41,EN,,0,0,0,,Yet the particular Lisp system that I show you Dialogue: 0,0:05:39.23,0:05:41.85,EN,,0,0,0,,is one where the numbers of arguments is fixed, Dialogue: 0,0:05:42.62,0:05:45.28,EN,,0,0,0,,because I had to match the arguments against the formal parameters Dialogue: 0,0:05:45.63,0:05:47.92,EN,,0,0,0,,in the binder, where there's a pairup. Dialogue: 0,0:05:50.81,0:05:53.80,EN,,0,0,0,,Well, I'd like to be able to define new procedures like this Dialogue: 0,0:05:54.89,0:05:57.32,EN,,0,0,0,,that can have any number of arguments. Dialogue: 0,0:05:58.75,0:06:00.40,EN,,0,0,0,,Well there's several parts to this problem. Dialogue: 0,0:06:01.34,0:06:04.81,EN,,0,0,0,,The first part is coming up with the syntactic specification, Dialogue: 0,0:06:05.72,0:06:11.21,EN,,0,0,0,,some way of notating the additional arguments, Dialogue: 0,0:06:12.17,0:06:13.63,EN,,0,0,0,,of which you don't know how many there are. Dialogue: 0,0:06:15.48,0:06:16.62,EN,,0,0,0,,And then there's the other thing, Dialogue: 0,0:06:17.10,0:06:18.70,EN,,0,0,0,,which is once we've notated it, Dialogue: 0,0:06:19.07,0:06:20.78,EN,,0,0,0,,how are we going to interpret that notation Dialogue: 0,0:06:21.74,0:06:23.10,EN,,0,0,0,,so as to do the right thing, Dialogue: 0,0:06:23.85,0:06:25.37,EN,,0,0,0,,whatever the right thing is? Dialogue: 0,0:06:26.98,0:06:28.80,EN,,0,0,0,,So let's consider an example of a sort of thing Dialogue: 0,0:06:28.84,0:06:30.27,EN,,0,0,0,,we might want to be able to do. Dialogue: 0,0:06:33.07,0:06:34.51,EN,,0,0,0,,So an example might be, Dialogue: 0,0:06:35.42,0:06:37.34,EN,,0,0,0,,that I might want to be able to define a procedure Dialogue: 0,0:06:37.95,0:06:41.36,EN,,0,0,0,,which is a procedure of one required argument x Dialogue: 0,0:06:42.20,0:06:45.26,EN,,0,0,0,,and a non-required -- bunch of arguments, Dialogue: 0,0:06:45.28,0:06:47.23,EN,,0,0,0,,I don't know how many there are, called y. Dialogue: 0,0:06:49.09,0:06:50.36,EN,,0,0,0,,So x is required, Dialogue: 0,0:06:55.88,0:06:57.44,EN,,0,0,0,,and there are many y's, Dialogue: 0,0:06:59.53,0:07:05.99,EN,,0,0,0,,many arguments-- y will be the list of them. Dialogue: 0,0:07:14.48,0:07:16.06,EN,,0,0,0,,Now, with such a thing, Dialogue: 0,0:07:16.09,0:07:17.68,EN,,0,0,0,,we might be able to say something like, Dialogue: 0,0:07:19.02,0:07:21.98,EN,,0,0,0,,map-- I'm going to do something to every one-- Dialogue: 0,0:07:22.52,0:07:25.76,EN,,0,0,0,,of that procedure of one argument u, Dialogue: 0,0:07:27.00,0:07:34.54,EN,,0,0,0,,which multiplies x by u, and we'll apply that to y. Dialogue: 0,0:07:36.89,0:07:38.04,EN,,0,0,0,,I've used a dot here Dialogue: 0,0:07:38.59,0:07:41.31,EN,,0,0,0,,to indicate that the thing after this Dialogue: 0,0:07:42.19,0:07:44.30,EN,,0,0,0,,is a list of all the rest of the arguments. Dialogue: 0,0:07:46.30,0:07:48.12,EN,,0,0,0,,I'm making a syntactic specification. Dialogue: 0,0:07:53.32,0:07:54.64,EN,,0,0,0,,Now, what this depends upon, Dialogue: 0,0:07:55.71,0:07:58.06,EN,,0,0,0,,the reason why this is sort of a reasonable thing to do, Dialogue: 0,0:07:59.77,0:08:01.96,EN,,0,0,0,,is because this happens to be a syntax Dialogue: 0,0:08:02.00,0:08:03.60,EN,,0,0,0,,that's used in the Lisp reader Dialogue: 0,0:08:04.41,0:08:07.15,EN,,0,0,0,,for representing conses. Dialogue: 0,0:08:08.94,0:08:11.08,EN,,0,0,0,,We've never introduced that before.You never see. Dialogue: 0,0:08:11.08,0:08:12.78,EN,,0,0,0,,You may have seen when playing with the system Dialogue: 0,0:08:13.04,0:08:14.62,EN,,0,0,0,,if you cons two things together, you get the Dialogue: 0,0:08:14.89,0:08:18.12,EN,,0,0,0,,first, space, dot, the second, space-- Dialogue: 0,0:08:19.79,0:08:22.83,EN,,0,0,0,,the first, space, dot, space, the second Dialogue: 0,0:08:23.08,0:08:24.64,EN,,0,0,0,,with parentheses around the whole thing. Dialogue: 0,0:08:26.98,0:08:28.16,EN,,0,0,0,,So that, for example, Dialogue: 0,0:08:28.97,0:08:35.04,EN,,0,0,0,,this x dot y corresponds to a pair, Dialogue: 0,0:08:36.33,0:08:39.29,EN,,0,0,0,,which has got an x in it and a y in it. Dialogue: 0,0:08:41.48,0:08:43.98,EN,,0,0,0,,The other notations that you've seen so far Dialogue: 0,0:08:44.94,0:08:46.67,EN,,0,0,0,,are things like, like Dialogue: 0,0:08:46.92,0:08:55.24,EN,,0,0,0,,a procedure of arguments x and y and z which do things Dialogue: 0,0:08:55.71,0:08:57.63,EN,,0,0,0,,and that looks like-- Dialogue: 0,0:09:02.00,0:09:03.61,EN,,0,0,0,,Just looking at the bound variable list, Dialogue: 0,0:09:04.22,0:09:05.29,EN,,0,0,0,,it looks like this, Dialogue: 0,0:09:09.93,0:09:17.32,EN,,0,0,0,,x, y, z, and the empty thing. Dialogue: 0,0:09:18.28,0:09:21.08,EN,,0,0,0,,If I have a list of arguments I wish to match this against, Dialogue: 0,0:09:22.60,0:09:25.60,EN,,0,0,0,,I have a list of arguments one, two, three, Dialogue: 0,0:09:25.87,0:09:27.26,EN,,0,0,0,,I want to match these against. Dialogue: 0,0:09:28.38,0:09:37.10,EN,,0,0,0,,OK? So I might have here a list of three things, Dialogue: 0,0:09:42.44,0:09:46.94,EN,,0,0,0,,one, two, three. Dialogue: 0,0:09:48.99,0:09:53.16,EN,,0,0,0,,And I want to match x, y, z against one, two, three. Dialogue: 0,0:09:54.22,0:09:56.28,EN,,0,0,0,,Well, it's clear that the one matches the x, Dialogue: 0,0:09:56.32,0:09:58.01,EN,,0,0,0,,because I can just sort of follow the structure, Dialogue: 0,0:09:58.86,0:10:01.56,EN,,0,0,0,,and the two matches the y, Dialogue: 0,0:10:02.46,0:10:04.04,EN,,0,0,0,,and the three matches the z. Dialogue: 0,0:10:05.48,0:10:09.53,EN,,0,0,0,,But now, supposing I were to compare this x dot y. Dialogue: 0,0:10:09.55,0:10:11.84,EN,,0,0,0,,this is x dot y-- Dialogue: 0,0:10:12.51,0:10:16.91,EN,,0,0,0,,supposing I compare that with a list of three arguments, one, two, three. Dialogue: 0,0:10:19.08,0:10:20.00,EN,,0,0,0,,Let's look at that again. Dialogue: 0,0:10:28.00,0:10:30.32,EN,,0,0,0,,One, two, three-- Dialogue: 0,0:10:30.86,0:10:32.88,EN,,0,0,0,,Well, I can walk along here Dialogue: 0,0:10:32.99,0:10:35.50,EN,,0,0,0,,and say, oh yes, x matches the one, Dialogue: 0,0:10:37.56,0:10:41.84,EN,,0,0,0,,Ah, the y matches the list, which is two and three. Dialogue: 0,0:10:43.74,0:10:46.22,EN,,0,0,0,,So the notation I'm choosing here Dialogue: 0,0:10:46.41,0:10:50.16,EN,,0,0,0,,is one that's very natural for Lisp system. Dialogue: 0,0:10:52.66,0:10:54.14,EN,,0,0,0,,But I'm going to choose this as a notation Dialogue: 0,0:10:54.17,0:10:55.80,EN,,0,0,0,,for representing a bunch of arguments. Dialogue: 0,0:10:58.29,0:11:00.09,EN,,0,0,0,,Now, there's an alternative possibility. Dialogue: 0,0:11:00.59,0:11:02.78,EN,,0,0,0,,If I don't want to take one special out, Dialogue: 0,0:11:03.00,0:11:05.00,EN,,0,0,0,,or two special ones out or something like that, Dialogue: 0,0:11:06.54,0:11:07.56,EN,,0,0,0,,if I don't want to do that, Dialogue: 0,0:11:08.78,0:11:10.44,EN,,0,0,0,,if I want to talk about Dialogue: 0,0:11:10.52,0:11:12.52,EN,,0,0,0,,just the list of all the arguments like in addition, Dialogue: 0,0:11:13.88,0:11:17.96,EN,,0,0,0,,well then the argument list I'm going to choose to be Dialogue: 0,0:11:18.20,0:11:23.45,EN,,0,0,0,,that procedure of all the arguments x, which does something with x Dialogue: 0,0:11:25.14,0:11:26.30,EN,,0,0,0,,And which, for example, Dialogue: 0,0:11:26.81,0:11:27.96,EN,,0,0,0,,if I take the procedure, Dialogue: 0,0:11:28.06,0:11:30.44,EN,,0,0,0,,which takes all the arguments x Dialogue: 0,0:11:31.12,0:11:32.70,EN,,0,0,0,,and returned the list of them, Dialogue: 0,0:11:34.81,0:11:38.67,EN,,0,0,0,,OK? That's list. That's the procedure list. Dialogue: 0,0:11:45.85,0:11:46.67,EN,,0,0,0,,How does this work? Dialogue: 0,0:11:46.84,0:11:50.06,EN,,0,0,0,,Well, indeed what I had as the bound variable list in this case, Dialogue: 0,0:11:50.60,0:11:51.45,EN,,0,0,0,,whatever it is, Dialogue: 0,0:11:51.61,0:11:53.68,EN,,0,0,0,,is being matched against a list of arguments. Dialogue: 0,0:11:55.14,0:11:57.14,EN,,0,0,0,,This symbol now is all of the arguments. Dialogue: 0,0:12:01.49,0:12:05.13,EN,,0,0,0,,And so this is the choice I'm making for a particular syntactic specification, Dialogue: 0,0:12:05.64,0:12:07.63,EN,,0,0,0,,for the description of procedures Dialogue: 0,0:12:08.04,0:12:10.56,EN,,0,0,0,,which take indefinite numbers of arguments. Dialogue: 0,0:12:13.45,0:12:14.60,EN,,0,0,0,,There are two cases of it, Dialogue: 0,0:12:15.40,0:12:16.35,EN,,0,0,0,,this one and this one. Dialogue: 0,0:12:17.44,0:12:18.36,EN,,0,0,0,,And none of this. Dialogue: 0,0:12:18.42,0:12:20.11,EN,,0,0,0,,When you make syntactic specifications, Dialogue: 0,0:12:20.44,0:12:22.54,EN,,0,0,0,,it's important that it's unambiguous, Dialogue: 0,0:12:23.56,0:12:27.36,EN,,0,0,0,,that neither of these can be confused with Dialogue: 0,0:12:27.66,0:12:31.20,EN,,0,0,0,,a representation we already have, this one. Dialogue: 0,0:12:33.61,0:12:35.82,EN,,0,0,0,,I can always tell whether I have Dialogue: 0,0:12:36.54,0:12:39.80,EN,,0,0,0,,a fixed number of explicitly named arguments Dialogue: 0,0:12:40.28,0:12:41.76,EN,,0,0,0,,made by these formal parameters, Dialogue: 0,0:12:42.64,0:12:43.13,EN,,0,0,0,,or Dialogue: 0,0:12:43.28,0:12:45.36,EN,,0,0,0,,a fixed number of named formal parameters Dialogue: 0,0:12:45.44,0:12:48.01,EN,,0,0,0,,followed by a thing which picks up all the rest of them, Dialogue: 0,0:12:49.42,0:12:53.52,EN,,0,0,0,,or a list of all the arguments Dialogue: 0,0:12:53.68,0:12:56.52,EN,,0,0,0,,which will be matched against this particular formal parameter called x, Dialogue: 0,0:12:56.99,0:12:58.84,EN,,0,0,0,,because these are syntactically distinguishable. Dialogue: 0,0:13:02.25,0:13:04.62,EN,,0,0,0,,Many languages make terrible errors in that form Dialogue: 0,0:13:05.04,0:13:08.03,EN,,0,0,0,,where whole segments of interpretation are cut off, Dialogue: 0,0:13:08.64,0:13:13.92,EN,,0,0,0,,because there are syntactic ambiguities in the language. Dialogue: 0,0:13:14.56,0:13:16.67,EN,,0,0,0,,They are the traditional problems with ALGOL like languages Dialogue: 0,0:13:16.67,0:13:23.47,EN,,0,0,0,,having to do with the nesting of ifs in the predicate part. Dialogue: 0,0:13:25.06,0:13:25.93,EN,,0,0,0,,In any case, Dialogue: 0,0:13:27.52,0:13:29.44,EN,,0,0,0,,now, so I've told you about the syntax, Dialogue: 0,0:13:30.27,0:13:34.83,EN,,0,0,0,,now, what are we going to do about the semantics of this? Dialogue: 0,0:13:35.25,0:13:36.11,EN,,0,0,0,,How do we interpret it? Dialogue: 0,0:13:36.59,0:13:37.96,EN,,0,0,0,,Well this is just super easy. Dialogue: 0,0:13:38.44,0:13:42.57,EN,,0,0,0,,I'm going to modify the metacircular interpreter to do it. Dialogue: 0,0:13:43.71,0:13:44.76,EN,,0,0,0,,And that's a one liner. Dialogue: 0,0:13:45.98,0:13:46.57,EN,,0,0,0,,There it is. Dialogue: 0,0:13:47.53,0:13:49.56,EN,,0,0,0,,I'm changing the way you pair things up. Dialogue: 0,0:13:50.81,0:13:54.19,EN,,0,0,0,,OK? Here we have procedure that pairs -- Dialogue: 0,0:13:56.76,0:14:02.03,EN,,0,0,0,,Here's the procedure that pairs the Dialogue: 0,0:14:04.81,0:14:09.56,EN,,0,0,0,,the variables, the formal parameters, with the arguments that were passed Dialogue: 0,0:14:12.16,0:14:16.68,EN,,0,0,0,,from the last description of the metacircular interpreter. Dialogue: 0,0:14:18.96,0:14:21.93,EN,,0,0,0,,And here's some things that are the same as they were before. Dialogue: 0,0:14:22.67,0:14:23.23,EN,,0,0,0,,In other words, Dialogue: 0,0:14:23.31,0:14:25.07,EN,,0,0,0,,if the list of variables is empty, Dialogue: 0,0:14:25.52,0:14:27.31,EN,,0,0,0,,then if the list of values is empty, Dialogue: 0,0:14:27.45,0:14:29.61,EN,,0,0,0,,then I have an empty list. Dialogue: 0,0:14:31.05,0:14:33.00,EN,,0,0,0,,Otherwise, I have too many arguments, Dialogue: 0,0:14:33.98,0:14:40.19,EN,,0,0,0,,If I have, that is if I have empty variables but not empty values. Dialogue: 0,0:14:41.58,0:14:44.00,EN,,0,0,0,,If I have empty values, Dialogue: 0,0:14:44.96,0:14:47.47,EN,,0,0,0,,OK? But the variables are not empty, Dialogue: 0,0:14:47.48,0:14:48.56,EN,,0,0,0,,that I have too few arguments. Dialogue: 0,0:14:48.94,0:14:51.31,EN,,0,0,0,,However if I have a variable -- the variables are a symbol-- Dialogue: 0,0:14:55.53,0:14:56.49,EN,,0,0,0,,interesting case-- Dialogue: 0,0:14:58.30,0:15:04.40,EN,,0,0,0,,then, what I should do is say, oh yes, this is the special case Dialogue: 0,0:15:04.59,0:15:06.51,EN,,0,0,0,,that I have a symbolic tail. Dialogue: 0,0:15:08.35,0:15:14.11,EN,,0,0,0,,OK. I have here a thing just like we looked over here. Dialogue: 0,0:15:14.90,0:15:17.87,EN,,0,0,0,,This is a tail which is a symbol, y. Dialogue: 0,0:15:18.63,0:15:19.39,EN,,0,0,0,,It's not a nil. Dialogue: 0,0:15:20.73,0:15:21.72,EN,,0,0,0,,It's not the empty list. Dialogue: 0,0:15:23.26,0:15:25.60,EN,,0,0,0,,Here's a symbolic tail that is just the very beginning of the tail. Dialogue: 0,0:15:25.98,0:15:26.81,EN,,0,0,0,,There is nothing else. Dialogue: 0,0:15:27.79,0:15:28.72,EN,,0,0,0,,In that case, Dialogue: 0,0:15:29.96,0:15:37.20,EN,,0,0,0,,I wish to match that variable with all the values Dialogue: 0,0:15:38.03,0:15:42.52,EN,,0,0,0,,and add that to the pairing that I'm making. Dialogue: 0,0:15:44.50,0:15:46.91,EN,,0,0,0,,Otherwise, I go through the normal arrangement Dialogue: 0,0:15:47.15,0:15:48.52,EN,,0,0,0,,of making up the whole pairing. Dialogue: 0,0:15:52.02,0:15:53.82,EN,,0,0,0,,I suppose that's very simple. Dialogue: 0,0:15:54.51,0:15:55.84,EN,,0,0,0,,And that's all there is to it. Dialogue: 0,0:15:57.08,0:15:58.33,EN,,0,0,0,,And now I'll answer some questions. Dialogue: 0,0:16:02.62,0:16:05.05,EN,,0,0,0,,The first one-- Are there any questions? Dialogue: 0,0:16:06.60,0:16:06.94,EN,,0,0,0,,Yes? Dialogue: 0,0:16:07.37,0:16:09.92,EN,,0,0,0,,AUDIENCE: Could you explain that third form? Dialogue: 0,0:16:09.98,0:16:12.12,EN,,0,0,0,,PROFESSOR: Third form. This one? OK. Dialogue: 0,0:16:12.59,0:16:14.27,EN,,0,0,0,,Well, maybe we should look at the thing Dialogue: 0,0:16:14.30,0:16:16.24,EN,,0,0,0,,as a piece of list structure. Dialogue: 0,0:16:18.57,0:16:22.73,EN,,0,0,0,,This is a procedure which contains a lambda. Dialogue: 0,0:16:25.85,0:16:29.61,EN,,0,0,0,,I'm just looking at the list structure which represents this. Dialogue: 0,0:16:31.26,0:16:32.44,EN,,0,0,0,,Here's x. Dialogue: 0,0:16:32.73,0:16:33.98,EN,,0,0,0,,These are our symbols. Dialogue: 0,0:16:37.41,0:16:39.58,EN,,0,0,0,,And then the body is nothing but x. Dialogue: 0,0:16:44.84,0:16:48.75,EN,,0,0,0,,If I were looking for the bound variable list part of this procedure, Dialogue: 0,0:16:50.09,0:16:51.58,EN,,0,0,0,,I would go looking at the CADR, Dialogue: 0,0:16:52.14,0:16:53.16,EN,,0,0,0,,and I'd find a symbol. Dialogue: 0,0:16:54.01,0:16:57.16,EN,,0,0,0,,So the, matcher, which is this pairup thing I just showed you, Dialogue: 0,0:16:58.24,0:17:00.44,EN,,0,0,0,,is going to be matching a symbolic object Dialogue: 0,0:17:01.56,0:17:04.40,EN,,0,0,0,,against a list of arguments that were passed. Dialogue: 0,0:17:05.76,0:17:09.55,EN,,0,0,0,,And it will bind that symbol to the list of arguments. Dialogue: 0,0:17:11.37,0:17:16.48,EN,,0,0,0,,The -- In this case, if I'm looking for it, Dialogue: 0,0:17:16.92,0:17:20.97,EN,,0,0,0,,the match will be against this in the bound variable list position. Dialogue: 0,0:17:24.14,0:17:26.14,EN,,0,0,0,,Now, if what this does is Dialogue: 0,0:17:26.17,0:17:29.13,EN,,0,0,0,,it gets a list of arguments and returns it, that's list Dialogue: 0,0:17:30.40,0:17:31.39,EN,,0,0,0,,That's the procedure is. Dialogue: 0,0:17:34.51,0:17:35.48,EN,,0,0,0,,Oh well, thank you. Dialogue: 0,0:17:36.14,0:17:37.28,EN,,0,0,0,,Let's take a break. Dialogue: 0,0:17:37.83,0:17:55.36,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:17:55.36,0:17:59.02,EN,,0,0,0,, Dialogue: 0,0:18:03.53,0:18:07.56,EN,,0,0,0,, Dialogue: 0,0:18:07.56,0:18:11.69,EN,,0,0,0,, Dialogue: 0,0:18:12.25,0:18:16.11,EN,,0,0,0,, Dialogue: 0,0:18:20.86,0:18:21.61,EN,,0,0,0,,PROFESSOR: Well let's see. Dialogue: 0,0:18:23.26,0:18:26.32,EN,,0,0,0,,Now, I'm going to tell you about a rather more substantial variation Dialogue: 0,0:18:27.45,0:18:31.04,EN,,0,0,0,,one that's a famous variation Dialogue: 0,0:18:31.60,0:18:36.80,EN,,0,0,0,,hat many early Lisps had. Dialogue: 0,0:18:38.25,0:18:40.06,EN,,0,0,0,,It's called dynamic binding of variables. Dialogue: 0,0:18:41.77,0:18:44.68,EN,,0,0,0,,And we'll investigate a little bit about that right now. Dialogue: 0,0:18:47.62,0:18:50.16,EN,,0,0,0,,I'm going to first introduce this by showing you the sort of thing Dialogue: 0,0:18:50.35,0:18:52.36,EN,,0,0,0,,that would make someone want this idea. Dialogue: 0,0:18:53.74,0:18:55.23,EN,,0,0,0,,I'm not going to tell what it is yet, Dialogue: 0,0:18:55.40,0:18:57.60,EN,,0,0,0,,I'm going to show you why you might want it. Dialogue: 0,0:18:58.64,0:18:59.93,EN,,0,0,0,,Suppose, for example, Dialogue: 0,0:19:00.75,0:19:02.59,EN,,0,0,0,,we looked at the sum procedure again Dialogue: 0,0:19:05.02,0:19:06.43,EN,,0,0,0,,for summing up a bunch of things. Dialogue: 0,0:19:08.14,0:19:09.47,EN,,0,0,0,,To be that procedure, Dialogue: 0,0:19:09.60,0:19:10.78,EN,,0,0,0,,of a term, Dialogue: 0,0:19:13.04,0:19:14.41,EN,,0,0,0,,lower bound, Dialogue: 0,0:19:15.24,0:19:17.04,EN,,0,0,0,,method of computing the next index, Dialogue: 0,0:19:17.24,0:19:18.56,EN,,0,0,0,,and upper bound, Dialogue: 0,0:19:19.36,0:19:20.16,EN,,0,0,0,,such that, Dialogue: 0,0:19:23.16,0:19:26.94,EN,,0,0,0,,if a is greater than b Dialogue: 0,0:19:27.15,0:19:28.64,EN,,0,0,0,,then the result is 0, Dialogue: 0,0:19:30.24,0:19:31.08,EN,,0,0,0,,otherwise, Dialogue: 0,0:19:33.68,0:19:39.82,EN,,0,0,0,,it's the sum, of the term, procedure, applied to a Dialogue: 0,0:19:40.60,0:19:44.24,EN,,0,0,0,,and the result of adding up, terms, Dialogue: 0,0:19:47.68,0:19:52.64,EN,,0,0,0,,with the next a being the a, Dialogue: 0,0:20:00.30,0:20:03.56,EN,,0,0,0,,the next procedure passed along, Dialogue: 0,0:20:06.40,0:20:08.25,EN,,0,0,0,,and the upper bound being passed along. Dialogue: 0,0:20:14.51,0:20:15.76,EN,,0,0,0,,Blink, blink, blink-- Dialogue: 0,0:20:17.82,0:20:21.45,EN,,0,0,0,,OK? Now, when I use this sum procedure, Dialogue: 0,0:20:21.96,0:20:24.35,EN,,0,0,0,,I can use it, for example, like this. Dialogue: 0,0:20:25.45,0:20:38.04,EN,,0,0,0,,We can define the sum of the powers to be, Dialogue: 0,0:20:38.08,0:20:40.33,EN,,0,0,0,,for example, sum of a bunch of powers x to the n, Dialogue: 0,0:20:41.10,0:20:45.93,EN,,0,0,0,,to be that procedure of a, b, and n-- Dialogue: 0,0:20:45.95,0:20:47.69,EN,,0,0,0,,lower bound, the upper bound, and n-- Dialogue: 0,0:20:48.06,0:20:53.34,EN,,0,0,0,,which is sum, of lambda of x, Dialogue: 0,0:20:53.60,0:20:59.31,EN,,0,0,0,,the procedure of one argument x, which exponentiates x to the n, Dialogue: 0,0:21:02.19,0:21:09.29,EN,,0,0,0,,with the a, the incrementer, and b, being passed along. Dialogue: 0,0:21:11.82,0:21:15.76,EN,,0,0,0,,So we're adding up x to n, given an x. Dialogue: 0,0:21:16.14,0:21:19.74,EN,,0,0,0,,x takes on values from a to b, incrementing by one. Dialogue: 0,0:21:22.94,0:21:24.38,EN,,0,0,0,,I can also write the-- Dialogue: 0,0:21:27.68,0:21:28.20,EN,,0,0,0,,That's right. Dialogue: 0,0:21:29.78,0:21:31.02,EN,,0,0,0,,Product, excuse me. Dialogue: 0,0:21:31.91,0:21:33.36,EN,,0,0,0,,The product of a bunch of powers. Dialogue: 0,0:21:38.08,0:21:39.12,EN,,0,0,0,,It's a strange name. Dialogue: 0,0:21:40.02,0:21:40.80,EN,,0,0,0,,I'm going to leave it there. Dialogue: 0,0:21:41.96,0:21:46.32,EN,,0,0,0,,Weird-- OK? I write up what I have. Dialogue: 0,0:21:49.34,0:21:50.19,EN,,0,0,0,,I'm sure that's right. Dialogue: 0,0:21:51.37,0:21:53.82,EN,,0,0,0,,And if I want the product of a bunch of powers-- Dialogue: 0,0:21:58.41,0:22:02.36,EN,,0,0,0,,That was 12 brain cells, that double-take. Dialogue: 0,0:22:03.00,0:22:06.81,EN,,0,0,0,,I can for example use the procedure which is like sum, Dialogue: 0,0:22:06.81,0:22:08.22,EN,,0,0,0,,which is for making products, Dialogue: 0,0:22:08.56,0:22:11.05,EN,,0,0,0,,but it's similar to that, that you've seen before. Dialogue: 0,0:22:11.45,0:22:16.38,EN,,0,0,0,,There's a procedure of three arguments again. Dialogue: 0,0:22:17.00,0:22:25.42,EN,,0,0,0,,Which is the product of terms that are constructed, or factors in this case, Dialogue: 0,0:22:25.66,0:22:31.60,EN,,0,0,0,,constructed from exponentiating x to the n, Dialogue: 0,0:22:34.43,0:22:37.85,EN,,0,0,0,,where I start with a, I increment, and I go to b. Dialogue: 0,0:22:41.53,0:22:41.88,EN,,0,0,0,,Now, Dialogue: 0,0:22:46.83,0:22:49.50,EN,,0,0,0,,there's some sort of thing here that should disturb you immediately. Dialogue: 0,0:22:50.75,0:22:52.01,EN,,0,0,0,,These look the same. Dialogue: 0,0:22:53.18,0:22:55.20,EN,,0,0,0,,Why am I writing this code so many times? Dialogue: 0,0:22:56.59,0:22:59.72,EN,,0,0,0,,Here I am, in the same boat I've been in before. Dialogue: 0,0:23:01.00,0:23:03.15,EN,,0,0,0,,Right? Wouldn't it be nice to make an abstraction here? Dialogue: 0,0:23:03.81,0:23:05.76,EN,,0,0,0,,What's an example of a good abstraction to make? Dialogue: 0,0:23:05.85,0:23:07.55,EN,,0,0,0,,Well, I see some codes that's identical. Dialogue: 0,0:23:08.47,0:23:09.32,EN,,0,0,0,,Here's one, Dialogue: 0,0:23:09.98,0:23:11.08,EN,,0,0,0,,and here's another. Dialogue: 0,0:23:14.45,0:23:16.22,EN,,0,0,0,,And so maybe I should be able to pull that out. Dialogue: 0,0:23:17.09,0:23:19.23,EN,,0,0,0,,I should be able to say, oh yes, Dialogue: 0,0:23:20.51,0:23:22.67,EN,,0,0,0,,the sum of the powers could be written in terms of Dialogue: 0,0:23:22.88,0:23:24.52,EN,,0,0,0,,something called the nth power procedure. Dialogue: 0,0:23:25.71,0:23:27.40,EN,,0,0,0,,Imagine somebody wanted to write Dialogue: 0,0:23:27.74,0:23:30.03,EN,,0,0,0,,a slightly different procedure that looks like this. Dialogue: 0,0:23:37.63,0:23:45.18,EN,,0,0,0,,The sum powers to be a procedure Dialogue: 0,0:23:46.44,0:23:48.46,EN,,0,0,0,,of a, b, and n, Dialogue: 0,0:23:48.75,0:23:52.27,EN,,0,0,0,,which the result of summing up the nth power. Dialogue: 0,0:23:53.88,0:23:55.42,EN,,0,0,0,,We're going to give a name to that idea, Dialogue: 0,0:23:58.35,0:24:02.27,EN,,0,0,0,,for starting at a, going by one, and ending at b. Dialogue: 0,0:24:05.74,0:24:06.91,EN,,0,0,0,,And similarly, Dialogue: 0,0:24:10.65,0:24:12.76,EN,,0,0,0,,I might want to write the product powers this way, Dialogue: 0,0:24:12.89,0:24:15.24,EN,,0,0,0,,abstracting out this idea. Dialogue: 0,0:24:16.27,0:24:17.37,EN,,0,0,0,,I might want this. Dialogue: 0,0:24:22.10,0:24:23.02,EN,,0,0,0,,Product powers, Dialogue: 0,0:24:29.48,0:24:34.94,EN,,0,0,0,,to be a procedure of a, b, and n, Dialogue: 0,0:24:35.31,0:24:42.33,EN,,0,0,0,,which is the product of the nth power operation Dialogue: 0,0:24:46.44,0:24:50.30,EN,,0,0,0,,on a with the incrementation and b being Dialogue: 0,0:24:53.50,0:24:57.56,EN,,0,0,0,,being my arguments for the analogous-thing product. Dialogue: 0,0:24:58.38,0:25:00.24,EN,,0,0,0,,And I'd like to be able to define, Dialogue: 0,0:25:02.04,0:25:03.88,EN,,0,0,0,,I'd like to be able to define nth power-- Dialogue: 0,0:25:04.89,0:25:05.93,EN,,0,0,0,,I'll put it over here. Dialogue: 0,0:25:12.22,0:25:12.99,EN,,0,0,0,,I'll put it at the top. Dialogue: 0,0:25:25.41,0:25:29.04,EN,,0,0,0,,--to be, in fact, my procedure of one argument x Dialogue: 0,0:25:29.60,0:25:34.56,EN,,0,0,0,,which is the result of exponentiating x to the n. Dialogue: 0,0:25:35.93,0:25:36.96,EN,,0,0,0,,But I have a problem. Dialogue: 0,0:25:38.64,0:25:39.93,EN,,0,0,0,,My environment model, Dialogue: 0,0:25:40.57,0:25:43.23,EN,,0,0,0,,that is my means of interpretation Dialogue: 0,0:25:44.00,0:25:45.95,EN,,0,0,0,,of interpretation for the language that we've defined so far, Dialogue: 0,0:25:46.27,0:25:48.81,EN,,0,0,0,,does not give me a meaning for this n. Dialogue: 0,0:25:52.76,0:25:59.26,EN,,0,0,0,,Because, as you know, the, as you know Dialogue: 0,0:26:00.76,0:26:04.25,EN,,0,0,0,,this n is free in this procedure. Dialogue: 0,0:26:06.41,0:26:07.98,EN,,0,0,0,,The environment model tells us Dialogue: 0,0:26:08.60,0:26:10.20,EN,,0,0,0,,that the meaning of a free variable Dialogue: 0,0:26:11.21,0:26:14.99,EN,,0,0,0,,is determined in the environment in which this procedure is defined. Dialogue: 0,0:26:16.64,0:26:17.47,EN,,0,0,0,,In a way I have written it, Dialogue: 0,0:26:17.48,0:26:19.84,EN,,0,0,0,,assuming these things are defined on the blackboard as is, Dialogue: 0,0:26:21.64,0:26:23.63,EN,,0,0,0,,this is defined in the global environment, Dialogue: 0,0:26:24.06,0:26:25.15,EN,,0,0,0,,where there is no n. Dialogue: 0,0:26:25.93,0:26:27.63,EN,,0,0,0,,Therefore, n is unbound variable. Dialogue: 0,0:26:28.72,0:26:31.66,EN,,0,0,0,,But it's perfectly clear, to most of us, Dialogue: 0,0:26:32.60,0:26:36.32,EN,,0,0,0,,that we would like it to be this n and this n. Dialogue: 0,0:26:38.99,0:26:42.67,EN,,0,0,0,,On the other hand, OK, it would be nice. Dialogue: 0,0:26:42.84,0:26:44.28,EN,,0,0,0,,Certainly we've got to be careful here Dialogue: 0,0:26:44.56,0:26:46.06,EN,,0,0,0,,of keeping this to be this, Dialogue: 0,0:26:48.96,0:26:52.83,EN,,0,0,0,,and this one over here, wherever it is to be this one. Dialogue: 0,0:26:57.39,0:26:59.74,EN,,0,0,0,,Well, the desire to make this work Dialogue: 0,0:27:00.67,0:27:02.72,EN,,0,0,0,,has led to a very famous bug. Dialogue: 0,0:27:04.65,0:27:06.04,EN,,0,0,0,,I'll tell you about the famous bug. Dialogue: 0,0:27:07.15,0:27:09.40,EN,,0,0,0,,Look at this slide. Dialogue: 0,0:27:10.66,0:27:12.70,EN,,0,0,0,,This is an idea called dynamic binding. Dialogue: 0,0:27:13.99,0:27:16.91,EN,,0,0,0,,Where, instead of the free variable being interpreted Dialogue: 0,0:27:17.76,0:27:21.23,EN,,0,0,0,,in the environment of definition of a procedure, Dialogue: 0,0:27:22.40,0:27:25.16,EN,,0,0,0,,the free variable is interpreted as having its value Dialogue: 0,0:27:25.44,0:27:29.31,EN,,0,0,0,,in the environment of the caller of the procedure. Dialogue: 0,0:27:31.85,0:27:34.84,EN,,0,0,0,,So what you have is a system Dialogue: 0,0:27:34.86,0:27:39.68,EN,,0,0,0,,where you search up the chain of callers of a particular procedure, Dialogue: 0,0:27:40.43,0:27:42.65,EN,,0,0,0,,and, of course, in this case, Dialogue: 0,0:27:42.84,0:27:44.30,EN,,0,0,0,,since nth power is called Dialogue: 0,0:27:44.33,0:27:45.98,EN,,0,0,0,,from inside product whatever it is-- Dialogue: 0,0:27:46.41,0:27:48.68,EN,,0,0,0,,I had to write our own sum which is the analogous procedure-- Dialogue: 0,0:27:50.51,0:27:54.92,EN,,0,0,0,,and product is presumably called from product powers, Dialogue: 0,0:27:55.13,0:27:56.14,EN,,0,0,0,,as you see over here, Dialogue: 0,0:27:56.83,0:27:59.37,EN,,0,0,0,,then since product powers bind with variable n , Dialogue: 0,0:28:00.09,0:28:04.09,EN,,0,0,0,,then nth powers n would be derived through that chain. Dialogue: 0,0:28:08.14,0:28:09.64,EN,,0,0,0,,Similarly, this n, Dialogue: 0,0:28:10.11,0:28:12.01,EN,,0,0,0,,the nth power in n in this case, Dialogue: 0,0:28:12.32,0:28:15.80,EN,,0,0,0,,would come through nth power here being called from inside sum. Dialogue: 0,0:28:15.80,0:28:18.27,EN,,0,0,0,,You can see it being called from inside sum here. Dialogue: 0,0:28:20.73,0:28:21.69,EN,,0,0,0,,It's called term here. Dialogue: 0,0:28:22.90,0:28:25.72,EN,,0,0,0,,But sum was called from inside of sum powers, Dialogue: 0,0:28:26.94,0:28:27.96,EN,,0,0,0,,which bound n. Dialogue: 0,0:28:28.93,0:28:30.65,EN,,0,0,0,,Therefore, there would be an n available Dialogue: 0,0:28:32.75,0:28:36.11,EN,,0,0,0,,that n to get it's value from. Dialogue: 0,0:28:37.95,0:28:39.24,EN,,0,0,0,,This is called dynamic -- Dialogue: 0,0:28:39.28,0:28:43.10,EN,,0,0,0,,What we have below this white line plus over here Dialogue: 0,0:28:43.31,0:28:46.04,EN,,0,0,0,,is what's called a dynamic binding view of the world. Dialogue: 0,0:28:46.59,0:28:49.00,EN,,0,0,0,,If that works, that's a dynamic binding view. Dialogue: 0,0:28:50.85,0:28:52.65,EN,,0,0,0,,Now, let's take a look, for example, Dialogue: 0,0:28:54.54,0:28:55.99,EN,,0,0,0,,at just what it takes to implement that. Dialogue: 0,0:28:55.99,0:28:56.96,EN,,0,0,0,,That's real easy. Dialogue: 0,0:28:57.48,0:28:59.34,EN,,0,0,0,,In fact, the very first Lisps Dialogue: 0,0:29:00.01,0:29:02.52,EN,,0,0,0,,had any form of interpretations of the free variables at all, Dialogue: 0,0:29:03.31,0:29:05.98,EN,,0,0,0,,had dynamic binding interpretations for the free variables. Dialogue: 0,0:29:06.40,0:29:10.14,EN,,0,0,0,,APL has dynamic binding interpretation for the free variables, Dialogue: 0,0:29:11.68,0:29:14.32,EN,,0,0,0,,not lexical or static binding. Dialogue: 0,0:29:15.22,0:29:17.00,EN,,0,0,0,,So, of course, the change is in eval. Dialogue: 0,0:29:19.31,0:29:20.59,EN,,0,0,0,,And it's really in two places. Dialogue: 0,0:29:22.78,0:29:25.61,EN,,0,0,0,,First of all, one thing we see, Dialogue: 0,0:29:26.52,0:29:28.49,EN,,0,0,0,,is that things become a little simpler. Dialogue: 0,0:29:29.39,0:29:33.63,EN,,0,0,0,,If I don't have to have the -- If I don't have to have the Dialogue: 0,0:29:33.64,0:29:36.20,EN,,0,0,0,,environment be the environment of definition for procedure, Dialogue: 0,0:29:36.44,0:29:38.04,EN,,0,0,0,,the procedure need not capture Dialogue: 0,0:29:38.43,0:29:40.17,EN,,0,0,0,,the environment at the time it's defined. Dialogue: 0,0:29:42.03,0:29:44.96,EN,,0,0,0,,And so if we look here at this slide, Dialogue: 0,0:29:45.84,0:29:50.08,EN,,0,0,0,,we see that the clause for a lambda expression, Dialogue: 0,0:29:50.73,0:29:52.43,EN,,0,0,0,,which is the way a procedure is defined, Dialogue: 0,0:29:53.92,0:29:56.73,EN,,0,0,0,,does not make up a thing which has a type closure Dialogue: 0,0:29:56.75,0:30:01.05,EN,,0,0,0,,and a attached environment structure. Dialogue: 0,0:30:01.29,0:30:02.54,EN,,0,0,0,,It's just the expression itself. Dialogue: 0,0:30:02.54,0:30:04.76,EN,,0,0,0,,And we'll decompose that some other way somewhere else. Dialogue: 0,0:30:06.44,0:30:09.40,EN,,0,0,0,,The other thing we see is the applicator Dialogue: 0,0:30:10.36,0:30:13.69,EN,,0,0,0,,applicator must be able to get the environment of the caller. Dialogue: 0,0:30:14.29,0:30:17.24,EN,,0,0,0,,The caller of a procedure is right here. Dialogue: 0,0:30:17.26,0:30:19.45,EN,,0,0,0,,If the procedure is a application-- Dialogue: 0,0:30:19.56,0:30:21.63,EN,,0,0,0,,If the expression we're evaluating is a combination, Dialogue: 0,0:30:21.79,0:30:23.71,EN,,0,0,0,,then we're going to call a combination Dialogue: 0,0:30:23.93,0:30:25.50,EN,,0,0,0,,then we're going to call a procedure Dialogue: 0,0:30:25.66,0:30:27.37,EN,,0,0,0,,which is the value of the operator. Dialogue: 0,0:30:29.84,0:30:31.44,EN,,0,0,0,,The environment of the caller Dialogue: 0,0:30:31.98,0:30:34.51,EN,,0,0,0,,is the environment we have right here, available now. Dialogue: 0,0:30:35.89,0:30:40.72,EN,,0,0,0,,So all I have to do is pass that environment to the applicator, to apply. Dialogue: 0,0:30:41.49,0:30:42.75,EN,,0,0,0,,And if we look at that here, Dialogue: 0,0:30:43.58,0:30:44.97,EN,,0,0,0,,the only change we have to make Dialogue: 0,0:30:45.71,0:30:48.41,EN,,0,0,0,,is that fellow takes that environment Dialogue: 0,0:30:48.78,0:30:55.68,EN,,0,0,0,,uses that environment for the purpose of extending that environment Dialogue: 0,0:30:56.67,0:30:59.02,EN,,0,0,0,,when abiding the formal parameters Dialogue: 0,0:30:59.02,0:31:01.37,EN,,0,0,0,,of the procedure to the arguments that were passed, Dialogue: 0,0:31:03.08,0:31:05.98,EN,,0,0,0,,not an environment that was captured in the procedure. Dialogue: 0,0:31:06.81,0:31:09.45,EN,,0,0,0,,The reason why the first Lisps were implemented this way, Dialogue: 0,0:31:09.66,0:31:11.96,EN,,0,0,0,,is the sort of the obvious, accidental implementation. Dialogue: 0,0:31:14.13,0:31:16.68,EN,,0,0,0,,And, of course, as usual, people got used to it and liked it. Dialogue: 0,0:31:17.25,0:31:18.27,EN,,0,0,0,,And there were some people said, Dialogue: 0,0:31:18.40,0:31:19.50,EN,,0,0,0,,this is the way to do it. Dialogue: 0,0:31:21.59,0:31:24.09,EN,,0,0,0,,Unfortunately that causes some serious problems. Dialogue: 0,0:31:25.40,0:31:27.24,EN,,0,0,0,,The most important, serious problem Dialogue: 0,0:31:27.53,0:31:29.84,EN,,0,0,0,,in using dynamic binding Dialogue: 0,0:31:31.00,0:31:33.56,EN,,0,0,0,,is there's a modularity crisis that's involved it. Dialogue: 0,0:31:35.46,0:31:37.66,EN,,0,0,0,,If two people are working together on some big system, Dialogue: 0,0:31:38.57,0:31:40.01,EN,,0,0,0,,then an important thing to one Dialogue: 0,0:31:40.35,0:31:42.19,EN,,0,0,0,,is that the names used by each one Dialogue: 0,0:31:42.99,0:31:44.58,EN,,0,0,0,,don't interfere with the names of the other. Dialogue: 0,0:31:47.93,0:31:50.78,EN,,0,0,0,,It's important that when I invent some segment of code Dialogue: 0,0:31:51.07,0:31:53.13,EN,,0,0,0,,that no one can make my code stop working Dialogue: 0,0:31:53.88,0:31:56.57,EN,,0,0,0,,by using my names that I use internal to my code, Dialogue: 0,0:31:56.75,0:31:57.71,EN,,0,0,0,,internal to his code. Dialogue: 0,0:31:59.85,0:32:00.46,EN,,0,0,0,,However, Dialogue: 0,0:32:01.04,0:32:05.18,EN,,0,0,0,,dynamic binding violates that particular modularity constraint in a clear way. Dialogue: 0,0:32:06.67,0:32:08.08,EN,,0,0,0,,Consider, for example, Dialogue: 0,0:32:09.18,0:32:10.35,EN,,0,0,0,,what happens over here. Dialogue: 0,0:32:12.54,0:32:13.79,EN,,0,0,0,,Suppose it was the case Dialogue: 0,0:32:15.47,0:32:19.81,EN,,0,0,0,,that I decided to change the word next. Dialogue: 0,0:32:19.81,0:32:24.41,EN,,0,0,0,,Supposing somebody is writing, somebody is writing sum, Dialogue: 0,0:32:25.10,0:32:26.68,EN,,0,0,0,,and somebody else is going to use sum. Dialogue: 0,0:32:28.97,0:32:30.32,EN,,0,0,0,,The writer of sum Dialogue: 0,0:32:30.49,0:32:32.30,EN,,0,0,0,,has a choice of what names he may use. Dialogue: 0,0:32:33.66,0:32:34.84,EN,,0,0,0,,Let's say, I'm that writer. Dialogue: 0,0:32:36.83,0:32:39.30,EN,,0,0,0,,Well, by gosh, just happens I didn't want to call this next. Dialogue: 0,0:32:39.30,0:32:40.09,EN,,0,0,0,,I called it n. Dialogue: 0,0:32:41.74,0:32:43.10,EN,,0,0,0,,So all places where you see next, Dialogue: 0,0:32:44.28,0:32:45.26,EN,,0,0,0,,I called it n. Dialogue: 0,0:32:48.14,0:32:48.48,EN,,0,0,0,,Whoops. Dialogue: 0,0:32:49.94,0:32:52.22,EN,,0,0,0,,I changed nothing about the specifications of this program, Dialogue: 0,0:32:53.32,0:32:54.86,EN,,0,0,0,,but this program stops working. Dialogue: 0,0:32:56.11,0:32:57.96,EN,,0,0,0,,Not only that, unfortunately, this one does too. Dialogue: 0,0:32:59.50,0:33:01.40,EN,,0,0,0,,Why do these programs stop working? Dialogue: 0,0:33:02.26,0:33:03.24,EN,,0,0,0,,Well, it's sort of clear. Dialogue: 0,0:33:04.48,0:33:09.29,EN,,0,0,0,,Instead of chasing out the value of the n Dialogue: 0,0:33:09.31,0:33:13.72,EN,,0,0,0,,that occurs in nth power over here or over here, Dialogue: 0,0:33:14.97,0:33:17.16,EN,,0,0,0,,through the environment of definition, Dialogue: 0,0:33:17.20,0:33:19.58,EN,,0,0,0,,where this one is always linked to this one, Dialogue: 0,0:33:19.87,0:33:21.48,EN,,0,0,0,,if it was through the environment of definition, Dialogue: 0,0:33:21.55,0:33:23.63,EN,,0,0,0,,because here is the definition. Dialogue: 0,0:33:24.37,0:33:26.25,EN,,0,0,0,,This lambda expression was executed Dialogue: 0,0:33:26.59,0:33:28.59,EN,,0,0,0,,in the environment where that n was defined. Dialogue: 0,0:33:30.70,0:33:31.84,EN,,0,0,0,,If instead of doing that, Dialogue: 0,0:33:32.01,0:33:33.68,EN,,0,0,0,,I have to chase through the call chain, Dialogue: 0,0:33:34.78,0:33:36.27,EN,,0,0,0,,then look what horrible thing happens. Dialogue: 0,0:33:37.32,0:33:41.18,EN,,0,0,0,,Well, this was called from inside sum as term, term a. Dialogue: 0,0:33:41.76,0:33:42.38,EN,,0,0,0,,term a. Dialogue: 0,0:33:44.78,0:33:46.19,EN,,0,0,0,,I'm looking for a value of n. Dialogue: 0,0:33:47.35,0:33:48.40,EN,,0,0,0,,Instead of getting this one, Dialogue: 0,0:33:48.84,0:33:49.76,EN,,0,0,0,,I get that one. Dialogue: 0,0:33:50.70,0:33:52.54,EN,,0,0,0,,So by changing the insides of this program, Dialogue: 0,0:33:52.86,0:33:54.09,EN,,0,0,0,,this program stops working. Dialogue: 0,0:33:56.77,0:34:00.08,EN,,0,0,0,,So I no longer have a quantifier, as I described before. Dialogue: 0,0:34:01.12,0:34:05.13,EN,,0,0,0,,Which is a symbol -- The lambda symbol is supposed to be a quantifier. Dialogue: 0,0:34:05.43,0:34:06.70,EN,,0,0,0,,A thing which has the property Dialogue: 0,0:34:06.89,0:34:11.42,EN,,0,0,0,,that the names that are bound by it are unimportant, Dialogue: 0,0:34:12.65,0:34:15.71,EN,,0,0,0,,that I can uniformly substitute any names for these Dialogue: 0,0:34:16.92,0:34:19.98,EN,,0,0,0,,throughout this thing, so long as they don't occur in here, the new names, Dialogue: 0,0:34:20.94,0:34:23.16,EN,,0,0,0,,and the meaning of this expression should remain unchanged. Dialogue: 0,0:34:24.04,0:34:25.50,EN,,0,0,0,,I've just changed the meaning of the expression Dialogue: 0,0:34:25.53,0:34:27.20,EN,,0,0,0,,by changing the one of the names. Dialogue: 0,0:34:28.69,0:34:30.89,EN,,0,0,0,,So lambda is no longer a well defined idea. Dialogue: 0,0:34:32.17,0:34:33.37,EN,,0,0,0,,It's a very serious problem. Dialogue: 0,0:34:34.55,0:34:35.55,EN,,0,0,0,,So for that reason, Dialogue: 0,0:34:36.64,0:34:42.51,EN,,0,0,0,,I and my buddies have given up this particular kind of abstraction, Dialogue: 0,0:34:43.13,0:34:44.36,EN,,0,0,0,,which I would like to have, Dialogue: 0,0:34:45.61,0:34:47.50,EN,,0,0,0,,in favor of a modularity principle. Dialogue: 0,0:34:48.09,0:34:50.20,EN,,0,0,0,,But this is the kind of experiment you can do Dialogue: 0,0:34:51.96,0:34:53.68,EN,,0,0,0,,if you want to play with these interpreters. Dialogue: 0,0:34:54.83,0:34:56.91,EN,,0,0,0,,You can try them out this way, that way, and the other way. Dialogue: 0,0:34:58.11,0:35:00.25,EN,,0,0,0,,You see what makes a nicer language. Dialogue: 0,0:35:02.68,0:35:04.49,EN,,0,0,0,,So that's a very important thing to be able to do. Dialogue: 0,0:35:04.99,0:35:06.68,EN,,0,0,0,,Now, I would like to give you a feeling Dialogue: 0,0:35:06.72,0:35:08.49,EN,,0,0,0,,for I think the right thing to do is here. Dialogue: 0,0:35:09.32,0:35:12.91,EN,,0,0,0,,How are you going to, how are you going to I get this kind of Dialogue: 0,0:35:13.04,0:35:15.34,EN,,0,0,0,,of power in a lexical system? Dialogue: 0,0:35:16.28,0:35:17.39,EN,,0,0,0,,And the answer is, of course, Dialogue: 0,0:35:17.55,0:35:20.03,EN,,0,0,0,,what I really want is a something that makes up for me Dialogue: 0,0:35:20.68,0:35:22.60,EN,,0,0,0,,an exponentiator for a particular n. Dialogue: 0,0:35:23.69,0:35:24.28,EN,,0,0,0,,Given an n, Dialogue: 0,0:35:24.32,0:35:25.66,EN,,0,0,0,,it will make me an exponentiator. Dialogue: 0,0:35:26.28,0:35:27.40,EN,,0,0,0,,Oh, but that's easy too. Dialogue: 0,0:35:28.17,0:35:30.57,EN,,0,0,0,,In other words, I can write my program this way. Dialogue: 0,0:35:35.84,0:35:37.84,EN,,0,0,0,,I'm going to define a thing called PGEN, Dialogue: 0,0:35:40.25,0:35:42.54,EN,,0,0,0,,which is a procedure of n Dialogue: 0,0:35:43.16,0:35:45.95,EN,,0,0,0,,which produces for me an exponentiator. Dialogue: 0,0:35:50.24,0:35:51.23,EN,,0,0,0,,--x to the n. Dialogue: 0,0:35:56.80,0:35:57.98,EN,,0,0,0,,Given that I have that, Dialogue: 0,0:35:58.59,0:36:00.88,EN,,0,0,0,,then I can capture the abstraction I wanted Dialogue: 0,0:36:01.42,0:36:03.93,EN,,0,0,0,,even better, because now it's encapsulated in a way Dialogue: 0,0:36:04.09,0:36:06.60,EN,,0,0,0,,where I can't be destroyed by a change of names. Dialogue: 0,0:36:07.89,0:36:12.35,EN,,0,0,0,,I can define some powers Dialogue: 0,0:36:17.28,0:36:20.70,EN,,0,0,0,,I can define some powers to be a procedure again of a, b, and n Dialogue: 0,0:36:21.61,0:36:26.83,EN,,0,0,0,,which is the sum of the term function Dialogue: 0,0:36:26.88,0:36:32.32,EN,,0,0,0,,generated by using this generator, PGEN, n, Dialogue: 0,0:36:34.40,0:36:38.01,EN,,0,0,0,,with a, incrementer, and b. Dialogue: 0,0:36:42.49,0:36:47.95,EN,,0,0,0,,And I can define the product of powers Dialogue: 0,0:36:54.11,0:36:58.84,EN,,0,0,0,,to be a procedure of a, b, and n Dialogue: 0,0:36:59.80,0:37:09.96,EN,,0,0,0,,which is the product PGEN, n, with a, increment, and b. Dialogue: 0,0:37:11.28,0:37:13.28,EN,,0,0,0,,Now, of course, this is a very simple example Dialogue: 0,0:37:13.60,0:37:16.35,EN,,0,0,0,,where this object that I'm trying to abstract over is small. Dialogue: 0,0:37:17.28,0:37:18.83,EN,,0,0,0,,But it could be a 100 lines of code. Dialogue: 0,0:37:20.10,0:37:23.67,EN,,0,0,0,,And so, the purpose of this is, of course, to make it simple. Dialogue: 0,0:37:23.67,0:37:24.57,EN,,0,0,0,,I'd give a name to it, Dialogue: 0,0:37:24.73,0:37:26.94,EN,,0,0,0,,it's just that here it's a parameterized name. Dialogue: 0,0:37:28.20,0:37:30.27,EN,,0,0,0,,It's a name that depends upon, explicitly, Dialogue: 0,0:37:30.49,0:37:33.63,EN,,0,0,0,,the lexically apparent value of n. Dialogue: 0,0:37:37.13,0:37:38.59,EN,,0,0,0,,So you can think of this as a long name. Dialogue: 0,0:37:40.21,0:37:41.58,EN,,0,0,0,,And here, I've solved my problem Dialogue: 0,0:37:41.76,0:37:45.82,EN,,0,0,0,,by naming my... by naming the term generation Dialogue: 0,0:37:46.12,0:37:49.22,EN,,0,0,0,,procedures within an n in them. Dialogue: 0,0:37:55.08,0:37:55.87,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:37:57.00,0:37:58.38,EN,,0,0,0,,Oh, yes, David. Dialogue: 0,0:37:58.57,0:38:02.27,EN,,0,0,0,,AUDIENCE: Is the only solution to um... Dialogue: 0,0:38:03.07,0:38:06.46,EN,,0,0,0,,the problem you raise to create another procedure? Dialogue: 0,0:38:06.47,0:38:08.92,EN,,0,0,0,,In other words, can this only work in languages that are Dialogue: 0,0:38:08.99,0:38:11.56,EN,,0,0,0,,capable of defining objects as procedures? Dialogue: 0,0:38:12.41,0:38:13.76,EN,,0,0,0,,PROFESSOR: Oh, I see. Dialogue: 0,0:38:15.90,0:38:19.74,EN,,0,0,0,,My solution to making this abstraction, Dialogue: 0,0:38:20.14,0:38:22.86,EN,,0,0,0,,when I didn't want include the procedure inside the body, Dialogue: 0,0:38:23.26,0:38:26.81,EN,,0,0,0,,depends upon my ability to return a procedure or export one. Dialogue: 0,0:38:27.04,0:38:27.24,EN,,0,0,0,,AUDIENCE: And that's right. Dialogue: 0,0:38:28.19,0:38:28.88,EN,,0,0,0,,PROFESSOR: And that's right. Dialogue: 0,0:38:29.53,0:38:31.52,EN,,0,0,0,,If I don't have that, Dialogue: 0,0:38:32.24,0:38:35.13,EN,,0,0,0,,then I just don't have this ability to make an abstraction in a way Dialogue: 0,0:38:35.53,0:38:41.77,EN,,0,0,0,,where I don't have possibilities of symbol conflicts that were unanticipated. Dialogue: 0,0:38:43.00,0:38:43.48,EN,,0,0,0,,That's right. Dialogue: 0,0:38:44.14,0:38:46.51,EN,,0,0,0,,So one of the, the essential -- I consider, I consider Dialogue: 0,0:38:46.54,0:38:48.91,EN,,0,0,0,,being able to return the procedural value and, therefore, Dialogue: 0,0:38:49.20,0:38:58.28,EN,,0,0,0,,and therefore, to sort of have first class procedures, in general, Dialogue: 0,0:38:59.13,0:39:02.46,EN,,0,0,0,,as being essential to doing very good modular programming. Dialogue: 0,0:39:03.70,0:39:06.43,EN,,0,0,0,,Now, indeed there are many other ways to skin this cat. Dialogue: 0,0:39:07.44,0:39:09.16,EN,,0,0,0,,What you can do is take for each of the Dialogue: 0,0:39:09.18,0:39:11.84,EN,,0,0,0,,for each of the bad things that you have to worry about, Dialogue: 0,0:39:12.27,0:39:15.20,EN,,0,0,0,,you can make a special feature that covers that thing. Dialogue: 0,0:39:15.84,0:39:17.12,EN,,0,0,0,,You can make a package system. Dialogue: 0,0:39:17.74,0:39:21.16,EN,,0,0,0,,You can make a module system as in Ada, et cetera. OK? Dialogue: 0,0:39:22.24,0:39:24.88,EN,,0,0,0,,And all of those work, or they cover little regions of it. Dialogue: 0,0:39:26.44,0:39:28.38,EN,,0,0,0,,The thing is that returning procedures as values Dialogue: 0,0:39:28.41,0:39:29.74,EN,,0,0,0,,cover all of those problems. Dialogue: 0,0:39:32.68,0:39:34.60,EN,,0,0,0,,And so it's the simplest mechanism Dialogue: 0,0:39:35.58,0:39:37.79,EN,,0,0,0,,that gives you the best modularity, Dialogue: 0,0:39:39.21,0:39:41.31,EN,,0,0,0,,gives you all of the known modularity mechanisms. Dialogue: 0,0:39:45.59,0:39:48.24,EN,,0,0,0,,Well, I suppose it's time for the next break, thank you. Dialogue: 0,0:39:48.24,0:40:01.08,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:40:01.28,0:40:04.75,EN,,0,0,0,, Dialogue: 0,0:40:25.69,0:40:29.42,EN,,0,0,0,, Dialogue: 0,0:40:30.01,0:40:33.28,EN,,0,0,0,, Dialogue: 0,0:40:34.17,0:40:37.61,EN,,0,0,0,, Dialogue: 0,0:40:42.32,0:40:44.28,EN,,0,0,0,,PROFESSOR: Well, yesterday when you learned about streams, Dialogue: 0,0:40:46.01,0:40:51.16,EN,,0,0,0,,Hal worried to you about the order of evaluation Dialogue: 0,0:40:51.95,0:40:53.87,EN,,0,0,0,,and delayed arguments to procedures. Dialogue: 0,0:40:55.61,0:40:58.30,EN,,0,0,0,,The way we played with streams yesterday, Dialogue: 0,0:41:00.25,0:41:04.22,EN,,0,0,0,,it was the responsibility of the caller and the callee Dialogue: 0,0:41:05.77,0:41:08.84,EN,,0,0,0,,both agree that an argument was delayed, Dialogue: 0,0:41:09.42,0:41:13.44,EN,,0,0,0,,and the callee must force the argument if it needs the answer. Dialogue: 0,0:41:15.13,0:41:17.87,EN,,0,0,0,,So there had to be a lot of hand shaking between Dialogue: 0,0:41:18.17,0:41:24.32,EN,,0,0,0,,the designer of a procedure and user of it over delayedness. Dialogue: 0,0:41:26.36,0:41:28.72,EN,,0,0,0,,That turns out, of course, to be a fairly bad thing, Dialogue: 0,0:41:29.48,0:41:30.96,EN,,0,0,0,,it works all right with streams. Dialogue: 0,0:41:31.74,0:41:32.86,EN,,0,0,0,,But as a general thing, Dialogue: 0,0:41:32.92,0:41:36.32,EN,,0,0,0,,what you want is an idea to have a locus, Dialogue: 0,0:41:36.46,0:41:38.49,EN,,0,0,0,,a decision, a design decision in general, Dialogue: 0,0:41:38.89,0:41:41.28,EN,,0,0,0,,to have a place where it's made, explicitly, Dialogue: 0,0:41:41.63,0:41:43.93,EN,,0,0,0,,and notated in a clear way. Dialogue: 0,0:41:45.88,0:41:49.28,EN,,0,0,0,,And so it's not a very good idea to have to have an agreement, Dialogue: 0,0:41:50.46,0:41:54.89,EN,,0,0,0,,between the person who writes a procedure and the person who calls it, Dialogue: 0,0:41:55.08,0:41:57.98,EN,,0,0,0,,about such details as, maybe, the arguments of evaluation, Dialogue: 0,0:41:58.43,0:41:59.50,EN,,0,0,0,,the order of evaluation. Dialogue: 0,0:41:59.50,0:42:00.75,EN,,0,0,0,,Although, that's not so bad. Dialogue: 0,0:42:01.02,0:42:03.95,EN,,0,0,0,,I mean, we have other such agreements like, the input's a number. Dialogue: 0,0:42:05.20,0:42:06.08,EN,,0,0,0,,But it would be nice if Dialogue: 0,0:42:06.35,0:42:09.20,EN,,0,0,0,,one of these guys could take responsibility, completely. Dialogue: 0,0:42:11.02,0:42:13.31,EN,,0,0,0,,Now this is not a new idea. Dialogue: 0,0:42:15.51,0:42:21.16,EN,,0,0,0,,ALGOL 60 had two different ways of calling a procedure. Dialogue: 0,0:42:22.02,0:42:24.28,EN,,0,0,0,,The arguments could be passed by name or by value. Dialogue: 0,0:42:25.59,0:42:27.48,EN,,0,0,0,,And what that meant was that Dialogue: 0,0:42:27.63,0:42:29.72,EN,,0,0,0,,a name argument was delayed. Dialogue: 0,0:42:31.11,0:42:32.84,EN,,0,0,0,,That when you passed an argument by name, Dialogue: 0,0:42:33.64,0:42:36.52,EN,,0,0,0,,that its value would only be obtained Dialogue: 0,0:42:36.96,0:42:39.55,EN,,0,0,0,,if you accessed that argument. Dialogue: 0,0:42:42.29,0:42:44.20,EN,,0,0,0,,So what I'd like to do now is show you, Dialogue: 0,0:42:44.43,0:42:46.96,EN,,0,0,0,,first of all, a little bit about, again, Dialogue: 0,0:42:46.99,0:42:48.65,EN,,0,0,0,,we're going to make a modification to a language. Dialogue: 0,0:42:50.32,0:42:51.79,EN,,0,0,0,,In this case, we're going to add a feature. Dialogue: 0,0:42:53.37,0:42:55.05,EN,,0,0,0,,We're going to add the feature of, Dialogue: 0,0:42:55.36,0:42:58.73,EN,,0,0,0,,by name parameters, if you will, or delayed parameters. Dialogue: 0,0:43:00.43,0:43:04.41,EN,,0,0,0,,Because, in fact, the default in our Lisp system Dialogue: 0,0:43:04.76,0:43:06.60,EN,,0,0,0,,is by the value of a pointer. Dialogue: 0,0:43:08.22,0:43:09.15,EN,,0,0,0,,A pointer is copied, Dialogue: 0,0:43:09.15,0:43:10.91,EN,,0,0,0,,but the data structure it points at is not. Dialogue: 0,0:43:13.41,0:43:14.84,EN,,0,0,0,,But I'd like to, in fact, show you Dialogue: 0,0:43:15.04,0:43:18.38,EN,,0,0,0,,is how you add name arguments as well. Dialogue: 0,0:43:19.99,0:43:22.12,EN,,0,0,0,,Now again, why would we need such a thing? Dialogue: 0,0:43:23.10,0:43:24.72,EN,,0,0,0,,Well supposing we wanted to invent Dialogue: 0,0:43:25.24,0:43:28.44,EN,,0,0,0,,certain kinds of what otherwise would be special forms, Dialogue: 0,0:43:28.73,0:43:29.72,EN,,0,0,0,,reserve words? Dialogue: 0,0:43:29.72,0:43:31.48,EN,,0,0,0,,But I'd rather not take up reserve words. Dialogue: 0,0:43:32.18,0:43:34.76,EN,,0,0,0,,I want procedures that can do things like if. Dialogue: 0,0:43:36.36,0:43:39.42,EN,,0,0,0,,If is special, or cond, or whatever it is. Dialogue: 0,0:43:39.42,0:43:40.43,EN,,0,0,0,,It's the same thing. Dialogue: 0,0:43:40.59,0:43:42.86,EN,,0,0,0,,It's special in that it determines whether or not Dialogue: 0,0:43:42.92,0:43:45.02,EN,,0,0,0,,to evaluate the consequent or the alternative Dialogue: 0,0:43:46.22,0:43:49.76,EN,,0,0,0,,based on the value of the predicate part of an expression. Dialogue: 0,0:43:50.84,0:43:53.12,EN,,0,0,0,,So taking the value of one thing Dialogue: 0,0:43:53.44,0:43:55.36,EN,,0,0,0,,determines whether or not to do something else. Dialogue: 0,0:43:57.27,0:43:58.88,EN,,0,0,0,,Whereas all the procedures like plus, Dialogue: 0,0:43:59.15,0:44:01.20,EN,,0,0,0,,evaluate... the ones that we can define right now, Dialogue: 0,0:44:01.42,0:44:06.56,EN,,0,0,0,,evaluate all of their arguments before application. Dialogue: 0,0:44:08.67,0:44:09.64,EN,,0,0,0,,So, for example, Dialogue: 0,0:44:10.46,0:44:12.41,EN,,0,0,0,,supposing I wish to be able to define something like Dialogue: 0,0:44:15.39,0:44:18.75,EN,,0,0,0,,the reverse of if in terms of if. Dialogue: 0,0:44:19.85,0:44:20.70,EN,,0,0,0,,Call it unless. Dialogue: 0,0:44:24.89,0:44:27.47,EN,,0,0,0,,We've a predicate, a consequent, and an alternative. Dialogue: 0,0:44:28.67,0:44:30.44,EN,,0,0,0,,Now what I would like to sort of be able to do is Dialogue: 0,0:44:30.46,0:44:32.08,EN,,0,0,0,,say-- oh, I'll do it in terms of cond. Dialogue: 0,0:44:32.64,0:44:36.72,EN,,0,0,0,,Cond, if not the predicate, Dialogue: 0,0:44:38.96,0:44:40.32,EN,,0,0,0,,then take the consequent, Dialogue: 0,0:44:41.58,0:44:45.63,EN,,0,0,0,,otherwise, take the alternative. Dialogue: 0,0:44:51.29,0:44:52.76,EN,,0,0,0,,Now, what I'd like this to mean, Dialogue: 0,0:44:53.32,0:44:55.40,EN,,0,0,0,,is supposing I do something like this. Dialogue: 0,0:44:56.92,0:45:04.12,EN,,0,0,0,,I'd like this unless say if equals one, 0, Dialogue: 0,0:45:05.08,0:45:06.64,EN,,0,0,0,,then the answer is two, Dialogue: 0,0:45:07.90,0:45:11.35,EN,,0,0,0,,otherwise, the quotient of one and 0. Dialogue: 0,0:45:15.92,0:45:18.91,EN,,0,0,0,,What I'd like that to mean is the result of substituting Dialogue: 0,0:45:20.00,0:45:23.26,EN,,0,0,0,,equal one, 0, and the quotient of one, 0 Dialogue: 0,0:45:23.66,0:45:24.76,EN,,0,0,0,,for p, c, and a. Dialogue: 0,0:45:25.58,0:45:27.58,EN,,0,0,0,,I'd like that to mean, and this is funny, Dialogue: 0,0:45:28.11,0:45:30.33,EN,,0,0,0,,I'd like it to transform into or mean Dialogue: 0,0:45:30.75,0:45:38.44,EN,,0,0,0,,cond not equal one, 0, Dialogue: 0,0:45:40.62,0:45:42.54,EN,,0,0,0,,then the result is two, Dialogue: 0,0:45:44.28,0:45:45.10,EN,,0,0,0,,otherwise Dialogue: 0,0:45:48.22,0:45:51.16,EN,,0,0,0,,I want it to be the quotient one and 0. Dialogue: 0,0:45:54.48,0:45:56.48,EN,,0,0,0,,Now, you know that if I were to type this into Lisp, Dialogue: 0,0:45:57.74,0:45:58.59,EN,,0,0,0,,I'd get a two. Dialogue: 0,0:45:59.97,0:46:01.32,EN,,0,0,0,,There's no problem with that. Dialogue: 0,0:46:02.91,0:46:04.64,EN,,0,0,0,,However, if I were to type this into Lisp, Dialogue: 0,0:46:05.28,0:46:07.79,EN,,0,0,0,,because all the arguments are evaluated before I start, Dialogue: 0,0:46:09.12,0:46:10.73,EN,,0,0,0,,then I'm going to get an error out of this. Dialogue: 0,0:46:13.38,0:46:15.61,EN,,0,0,0,,So that if the substitutions work at all, of course, Dialogue: 0,0:46:16.03,0:46:16.88,EN,,0,0,0,,I would get the right answer. Dialogue: 0,0:46:16.88,0:46:20.16,EN,,0,0,0,,But here's a case where the substitutions don't work. Dialogue: 0,0:46:22.17,0:46:23.86,EN,,0,0,0,,I don't get the wrong answer. Dialogue: 0,0:46:23.86,0:46:24.67,EN,,0,0,0,,I get no answer. Dialogue: 0,0:46:24.80,0:46:25.60,EN,,0,0,0,,I get an error. Dialogue: 0,0:46:28.42,0:46:31.21,EN,,0,0,0,,Now, however, I'd like to be able to make my definition Dialogue: 0,0:46:31.61,0:46:32.99,EN,,0,0,0,,so that this kind of thing works. Dialogue: 0,0:46:34.48,0:46:36.51,EN,,0,0,0,,What I want to do is say something special Dialogue: 0,0:46:36.70,0:46:38.76,EN,,0,0,0,,about c and a. Dialogue: 0,0:46:39.93,0:46:43.15,EN,,0,0,0,,I want them to be delayed automatically. Dialogue: 0,0:46:44.27,0:46:48.08,EN,,0,0,0,,I don't want them to be, I don't want them to be evaluated Dialogue: 0,0:46:48.52,0:46:49.74,EN,,0,0,0,,at the time I call. Dialogue: 0,0:46:51.52,0:46:52.72,EN,,0,0,0,,So I'm going to make a declaration, Dialogue: 0,0:46:52.75,0:46:55.32,EN,,0,0,0,,and then I'm going to see how to implement such a declaration. Dialogue: 0,0:46:55.60,0:46:57.63,EN,,0,0,0,,But again, I want you to say to yourself, Dialogue: 0,0:46:57.79,0:47:00.25,EN,,0,0,0,,oh, this is an interesting kluge he's adding in here. Dialogue: 0,0:47:00.76,0:47:02.16,EN,,0,0,0,,A kluge, you know. Dialogue: 0,0:47:02.25,0:47:04.72,EN,,0,0,0,,The piles of kluges make a big complicated mess. Dialogue: 0,0:47:05.75,0:47:09.79,EN,,0,0,0,,And is this going to foul up something else that might occur. Dialogue: 0,0:47:10.12,0:47:12.70,EN,,0,0,0,,First of all, is it syntactically unambiguous? Dialogue: 0,0:47:13.86,0:47:15.50,EN,,0,0,0,,Well, it will be syntactically unambiguous Dialogue: 0,0:47:15.71,0:47:16.91,EN,,0,0,0,,with what we've seen so far. Dialogue: 0,0:47:17.84,0:47:20.76,EN,,0,0,0,,But what I'm going to do may, in fact, cause trouble. Dialogue: 0,0:47:21.67,0:47:24.67,EN,,0,0,0,,It may be that the thing I had will conflict with Dialogue: 0,0:47:25.15,0:47:27.10,EN,,0,0,0,,type declarations I might want to add in the future Dialogue: 0,0:47:28.19,0:47:31.08,EN,,0,0,0,,for giving some system, some compiler or something, Dialogue: 0,0:47:31.21,0:47:33.66,EN,,0,0,0,,the ability to optimize given the types are known. Dialogue: 0,0:47:34.75,0:47:36.97,EN,,0,0,0,,Or it might conflict with other types of declarations Dialogue: 0,0:47:37.00,0:47:39.71,EN,,0,0,0,,that I might want to make about the formal parameters. Dialogue: 0,0:47:40.57,0:47:42.56,EN,,0,0,0,,So I'm not making a general mechanism here Dialogue: 0,0:47:43.77,0:47:45.24,EN,,0,0,0,,where I can add declarations. Dialogue: 0,0:47:45.28,0:47:46.54,EN,,0,0,0,,And I would like to be able to do that. Dialogue: 0,0:47:46.89,0:47:48.81,EN,,0,0,0,,But I don't want to talk about that right now. Dialogue: 0,0:47:51.01,0:47:53.88,EN,,0,0,0,,So here I'm going to do, I'm going to build a kluge. Dialogue: 0,0:47:57.56,0:48:08.38,EN,,0,0,0,,So we're going to define unless of a predicate-- Dialogue: 0,0:48:08.81,0:48:10.27,EN,,0,0,0,,and I'm going to call these by name-- Dialogue: 0,0:48:12.78,0:48:15.28,EN,,0,0,0,,the consequent, and name the alternative. Dialogue: 0,0:48:19.85,0:48:25.28,EN,,0,0,0,,Huh, huh-- I got caught in the corner. Dialogue: 0,0:48:31.76,0:48:35.61,EN,,0,0,0,,If not p then the result is c, Dialogue: 0,0:48:36.80,0:48:41.16,EN,,0,0,0,,else-- that's what I'd like. Dialogue: 0,0:48:44.67,0:48:46.88,EN,,0,0,0,,Where I can explicitly declare Dialogue: 0,0:48:47.55,0:48:51.65,EN,,0,0,0,,certain of the parameters to be delayed, to be computed later. Dialogue: 0,0:48:55.60,0:48:58.48,EN,,0,0,0,,Now, this is actually a very complicated modification to an interpreter Dialogue: 0,0:48:58.70,0:48:59.77,EN,,0,0,0,,rather than a simple one. Dialogue: 0,0:49:00.45,0:49:03.10,EN,,0,0,0,,The ones you saw before, dynamic binding Dialogue: 0,0:49:03.40,0:49:06.89,EN,,0,0,0,,or adding indefinite argument procedures, Dialogue: 0,0:49:07.50,0:49:08.52,EN,,0,0,0,,is relatively simple. Dialogue: 0,0:49:09.28,0:49:11.28,EN,,0,0,0,,But this one changes a basic strategy. Dialogue: 0,0:49:12.32,0:49:13.39,EN,,0,0,0,,The problem here Dialogue: 0,0:49:13.96,0:49:17.63,EN,,0,0,0,,is that our interpreter, as written Dialogue: 0,0:49:17.96,0:49:23.40,EN,,0,0,0,,evaluates a combination by evaluating the procedure, Dialogue: 0,0:49:24.24,0:49:25.92,EN,,0,0,0,,the operator producing the procedure, Dialogue: 0,0:49:26.20,0:49:30.35,EN,,0,0,0,,and evaluating the operands producing the arguments, Dialogue: 0,0:49:30.76,0:49:35.26,EN,,0,0,0,,and then doing apply of the procedure to the arguments. Dialogue: 0,0:49:36.38,0:49:37.07,EN,,0,0,0,,However, here, Dialogue: 0,0:49:37.36,0:49:41.48,EN,,0,0,0,,I don't want to evaluate the operands to produce the arguments Dialogue: 0,0:49:41.74,0:49:43.66,EN,,0,0,0,,until after I examined the procedure Dialogue: 0,0:49:44.62,0:49:46.86,EN,,0,0,0,,to see what the procedure's declarations look like. Dialogue: 0,0:49:49.59,0:49:50.59,EN,,0,0,0,,So let's look at that. Dialogue: 0,0:49:52.68,0:49:56.54,EN,,0,0,0,,Here we have a changed evaluator. Dialogue: 0,0:49:57.48,0:50:01.15,EN,,0,0,0,,I'm starting with the simple lexical evaluator, Dialogue: 0,0:50:01.72,0:50:02.65,EN,,0,0,0,,not dynamic Dialogue: 0,0:50:04.14,0:50:08.20,EN,,0,0,0,,but we're going to have to do something sort of similar in some ways. Dialogue: 0,0:50:09.75,0:50:11.45,EN,,0,0,0,,Because of the fact that, Dialogue: 0,0:50:11.90,0:50:13.34,EN,,0,0,0,,if I delay a procedure-- Dialogue: 0,0:50:13.66,0:50:15.15,EN,,0,0,0,,I'm sorry-- delay an argument to a procedure, Dialogue: 0,0:50:15.40,0:50:17.52,EN,,0,0,0,,I'm going to have to attach and environment to it. Dialogue: 0,0:50:19.36,0:50:21.55,EN,,0,0,0,,Remember how Hal implemented delay. Dialogue: 0,0:50:23.38,0:50:25.44,EN,,0,0,0,,Hal implemented delay as being Dialogue: 0,0:50:25.50,0:50:27.47,EN,,0,0,0,,a procedure of no arguments Dialogue: 0,0:50:28.56,0:50:30.52,EN,,0,0,0,,which does some expression. Dialogue: 0,0:50:31.18,0:50:36.94,EN,,0,0,0,,That's what delay of the expression is. --of that expression. Dialogue: 0,0:50:39.29,0:50:40.99,EN,,0,0,0,,This turned into something like this. Dialogue: 0,0:50:44.52,0:50:46.92,EN,,0,0,0,,Now, however, if I evaluate a lambda expression, Dialogue: 0,0:50:47.42,0:50:49.20,EN,,0,0,0,,I have to capture the environment. Dialogue: 0,0:50:51.41,0:50:53.45,EN,,0,0,0,,The reason why is because there are Dialogue: 0,0:50:54.60,0:50:56.32,EN,,0,0,0,,there are variables in there Dialogue: 0,0:50:57.02,0:51:00.83,EN,,0,0,0,,who's meaning I wish to derive from the context where this was written. Dialogue: 0,0:51:04.01,0:51:05.76,EN,,0,0,0,,So that's why a lambda does the job. Dialogue: 0,0:51:06.62,0:51:07.50,EN,,0,0,0,,It's the right thing. Dialogue: 0,0:51:08.07,0:51:15.12,EN,,0,0,0,,And such that the forcing of a delayed expression Dialogue: 0,0:51:16.52,0:51:20.08,EN,,0,0,0,,was same thing as calling that with no arguments. Dialogue: 0,0:51:21.09,0:51:22.28,EN,,0,0,0,,It's just the opposite of this. Dialogue: 0,0:51:24.10,0:51:26.94,EN,,0,0,0,,Producing an environment of the call Dialogue: 0,0:51:27.36,0:51:29.90,EN,,0,0,0,,which is, in fact, the environment where this was defined Dialogue: 0,0:51:30.81,0:51:32.36,EN,,0,0,0,,with an extra frame in it that's empty. Dialogue: 0,0:51:33.23,0:51:34.41,EN,,0,0,0,,I don't care about that. Dialogue: 0,0:51:36.24,0:51:39.40,EN,,0,0,0,,Well, if we go back to this slide, Dialogue: 0,0:51:40.99,0:51:43.72,EN,,0,0,0,,since it's the case, if we look at this for a second, Dialogue: 0,0:51:44.14,0:51:46.12,EN,,0,0,0,,everything is the same as it was before Dialogue: 0,0:51:46.35,0:51:50.65,EN,,0,0,0,,except the case of applications or combinations. Dialogue: 0,0:51:51.98,0:51:53.71,EN,,0,0,0,,And combinations are going to do two things. Dialogue: 0,0:51:54.68,0:51:57.79,EN,,0,0,0,,One, is I have to evaluate the procedure-- Dialogue: 0,0:51:57.92,0:51:59.88,EN,,0,0,0,,I have to get the procedure-- by evaluating the operator. Dialogue: 0,0:52:00.70,0:52:01.69,EN,,0,0,0,,That's what you see right here. Dialogue: 0,0:52:02.38,0:52:04.35,EN,,0,0,0,,I have to make sure that that's current, Dialogue: 0,0:52:04.46,0:52:05.76,EN,,0,0,0,,that is not a delayed object, Dialogue: 0,0:52:06.36,0:52:09.85,EN,,0,0,0,,and evaluate that to the point where became it's forced now. Dialogue: 0,0:52:10.73,0:52:12.08,EN,,0,0,0,,And then I have to somehow Dialogue: 0,0:52:12.24,0:52:17.32,EN,,0,0,0,,apply that to the, to the operands. Dialogue: 0,0:52:18.03,0:52:19.61,EN,,0,0,0,,But I have to keep the environment, Dialogue: 0,0:52:19.63,0:52:20.92,EN,,0,0,0,,pass that environmental along. Dialogue: 0,0:52:21.53,0:52:23.71,EN,,0,0,0,,So some of those operands I may have to delay. Dialogue: 0,0:52:23.71,0:52:27.53,EN,,0,0,0,,I may have to attach that environment to those operands. Dialogue: 0,0:52:29.66,0:52:31.52,EN,,0,0,0,,This is a rather complicated thing happening here. Dialogue: 0,0:52:32.99,0:52:34.24,EN,,0,0,0,,Looking at that in apply. Dialogue: 0,0:52:36.40,0:52:38.72,EN,,0,0,0,,Apply, well it has a primitive procedure Dialogue: 0,0:52:39.36,0:52:40.60,EN,,0,0,0,,thing just like before. Dialogue: 0,0:52:42.61,0:52:44.68,EN,,0,0,0,,But the compound one is a little more interesting. Dialogue: 0,0:52:47.25,0:52:49.52,EN,,0,0,0,,I have to evaluate the body, just as before, Dialogue: 0,0:52:50.48,0:52:51.98,EN,,0,0,0,,in an environment which is Dialogue: 0,0:52:52.28,0:52:54.97,EN,,0,0,0,,which is the result of binding some Dialogue: 0,0:52:55.61,0:53:00.29,EN,,0,0,0,,formal parameters to arguments in the environment. Dialogue: 0,0:53:00.29,0:53:01.07,EN,,0,0,0,,That's true. Dialogue: 0,0:53:01.53,0:53:03.82,EN,,0,0,0,,The environment is the one that comes from the procedure now. Dialogue: 0,0:53:03.82,0:53:06.65,EN,,0,0,0,,It's a lexical language, statically bound. Dialogue: 0,0:53:08.04,0:53:11.82,EN,,0,0,0,,However, one thing I have to do is strip off the declarations Dialogue: 0,0:53:11.84,0:53:12.84,EN,,0,0,0,,to get the names of the variables. Dialogue: 0,0:53:12.84,0:53:15.20,EN,,0,0,0,,That's what this guy does, vnames. Dialogue: 0,0:53:15.45,0:53:16.67,EN,,0,0,0,,And the other thing I have to do Dialogue: 0,0:53:16.97,0:53:18.86,EN,,0,0,0,,is process these declarations, Dialogue: 0,0:53:19.13,0:53:21.52,EN,,0,0,0,,deciding which of these operands-- Dialogue: 0,0:53:21.76,0:53:23.92,EN,,0,0,0,,that's the operands now, as opposed to the arguments-- Dialogue: 0,0:53:24.09,0:53:25.87,EN,,0,0,0,,which of these operands to evaluate, Dialogue: 0,0:53:26.62,0:53:30.20,EN,,0,0,0,,and which of them are to be Dialogue: 0,0:53:30.99,0:53:33.77,EN,,0,0,0,,encapsulated in delays of some sort. Dialogue: 0,0:53:37.28,0:53:40.08,EN,,0,0,0,,The other thing you see here is that we got a primitive, Dialogue: 0,0:53:40.60,0:53:42.38,EN,,0,0,0,,a primitive like plus, Dialogue: 0,0:53:42.68,0:53:45.58,EN,,0,0,0,,had better get at the real operands. Dialogue: 0,0:53:45.82,0:53:47.39,EN,,0,0,0,,So here is a place where we're going to have to force them. Dialogue: 0,0:53:47.92,0:53:50.38,EN,,0,0,0,,And we're going to look at what evlist is going to have to do a bunch of forces. Dialogue: 0,0:53:51.34,0:53:52.78,EN,,0,0,0,,So we have two different kinds of evlist now. Dialogue: 0,0:53:52.78,0:53:54.09,EN,,0,0,0,,We have evlist and gevlist. Dialogue: 0,0:53:54.52,0:53:57.16,EN,,0,0,0,,Gevlist is going to wrap delays around some things Dialogue: 0,0:53:57.18,0:53:59.74,EN,,0,0,0,,and force others, evaluate others. Dialogue: 0,0:53:59.87,0:54:05.85,EN,,0,0,0,,And this guy's going to do some forcing of things. Dialogue: 0,0:54:07.90,0:54:09.16,EN,,0,0,0,,Just looking at this a little bit, Dialogue: 0,0:54:09.69,0:54:11.98,EN,,0,0,0,,this is a game you must play for yourself, you know. Dialogue: 0,0:54:12.25,0:54:14.67,EN,,0,0,0,,It's not something that you're going to see all possible Dialogue: 0,0:54:14.72,0:54:18.20,EN,,0,0,0,,variations on an evaluator talking to me. Dialogue: 0,0:54:19.52,0:54:21.24,EN,,0,0,0,,What you have to do is do this for yourself. Dialogue: 0,0:54:21.37,0:54:23.84,EN,,0,0,0,,And after you feel this, you play this a bit, Dialogue: 0,0:54:24.22,0:54:27.02,EN,,0,0,0,,you get to see all the possible design decisions and what they might mean, Dialogue: 0,0:54:27.77,0:54:29.16,EN,,0,0,0,,and how they interact with each other. Dialogue: 0,0:54:29.93,0:54:32.38,EN,,0,0,0,,So what languages might have in them. Dialogue: 0,0:54:33.16,0:54:34.64,EN,,0,0,0,,And what are some of the consistent sets Dialogue: 0,0:54:34.94,0:54:36.32,EN,,0,0,0,,that make a legitimate language. Dialogue: 0,0:54:37.20,0:54:40.06,EN,,0,0,0,,Whereas what things are complicated kluges that are just piles of junk. Dialogue: 0,0:54:41.85,0:54:44.68,EN,,0,0,0,,So evlist of course, over here, just as I said, Dialogue: 0,0:54:44.81,0:54:46.03,EN,,0,0,0,,is a list of operands Dialogue: 0,0:54:46.70,0:54:50.28,EN,,0,0,0,,which are going to be undelayed after evaluation. Dialogue: 0,0:54:50.75,0:54:51.90,EN,,0,0,0,,So these are going to be forced, Dialogue: 0,0:54:53.28,0:54:54.44,EN,,0,0,0,,whatever that's going to mean. Dialogue: 0,0:54:56.05,0:54:58.51,EN,,0,0,0,,And gevlist, which is the next thing-- Dialogue: 0,0:55:01.26,0:55:01.85,EN,,0,0,0,,Thank you. Dialogue: 0,0:55:04.04,0:55:06.35,EN,,0,0,0,,What we see here, uh Dialogue: 0,0:55:07.80,0:55:09.61,EN,,0,0,0,,well there's a couple of possibilities. Dialogue: 0,0:55:09.81,0:55:11.52,EN,,0,0,0,,Either it's a normal, ordinary thing, Dialogue: 0,0:55:12.48,0:55:13.69,EN,,0,0,0,,a symbol sitting there Dialogue: 0,0:55:13.74,0:55:16.20,EN,,0,0,0,,like the predicate in the unless, Dialogue: 0,0:55:17.64,0:55:18.81,EN,,0,0,0,,and that's what we have here. Dialogue: 0,0:55:19.39,0:55:22.49,EN,,0,0,0,,In which case, this is intended to be evaluated in applicative order. Dialogue: 0,0:55:23.34,0:55:25.45,EN,,0,0,0,,And it's, essentially, just what we had before. Dialogue: 0,0:55:25.63,0:55:28.84,EN,,0,0,0,,It's mapping eval down the list. Dialogue: 0,0:55:29.95,0:55:32.14,EN,,0,0,0,,In other words, I evaluate the first expression Dialogue: 0,0:55:32.65,0:55:37.36,EN,,0,0,0,,and continue gevlisting the CDR of the expression in the environment. Dialogue: 0,0:55:37.93,0:55:43.20,EN,,0,0,0,,However, it's possible that this is a name parameter. Dialogue: 0,0:55:44.00,0:55:45.05,EN,,0,0,0,,If it's a name parameter, Dialogue: 0,0:55:45.20,0:55:46.59,EN,,0,0,0,,I want to put a delay in Dialogue: 0,0:55:47.00,0:55:50.97,EN,,0,0,0,,which combines that expression, which I'm calling by name, Dialogue: 0,0:55:52.14,0:55:57.74,EN,,0,0,0,,with the environment that's available at this time Dialogue: 0,0:55:59.05,0:56:00.59,EN,,0,0,0,,and passing that as the parameter. Dialogue: 0,0:56:02.79,0:56:05.04,EN,,0,0,0,,And this is part of the mapping process that you see here. Dialogue: 0,0:56:09.07,0:56:11.31,EN,,0,0,0,,The only other interesting place in this procedure Dialogue: 0,0:56:11.37,0:56:13.53,EN,,0,0,0,,in this interpreter is cond. Dialogue: 0,0:56:14.70,0:56:15.92,EN,,0,0,0,,People tend to write this thing, Dialogue: 0,0:56:15.93,0:56:17.24,EN,,0,0,0,,and then they leave this one out. Dialogue: 0,0:56:18.55,0:56:19.98,EN,,0,0,0,,There's a place where you have to force. Dialogue: 0,0:56:20.51,0:56:23.10,EN,,0,0,0,,Conditionals have to know Dialogue: 0,0:56:24.20,0:56:25.90,EN,,0,0,0,,whether or not the answer is true or false. Dialogue: 0,0:56:25.99,0:56:26.83,EN,,0,0,0,,It's like a primitive. Dialogue: 0,0:56:28.55,0:56:30.56,EN,,0,0,0,,When you do a conditional, you have to force. Dialogue: 0,0:56:31.72,0:56:33.95,EN,,0,0,0,,Now, I'm not going to look at any more of this in any detail. Dialogue: 0,0:56:34.62,0:56:36.28,EN,,0,0,0,,It isn't very exciting. Dialogue: 0,0:56:36.75,0:56:38.99,EN,,0,0,0,,And what's left is how you make delays. Dialogue: 0,0:56:38.99,0:56:40.91,EN,,0,0,0,,Well, delays are data structures Dialogue: 0,0:56:41.31,0:56:44.75,EN,,0,0,0,,which contain an expression, an environment, and a type on them. Dialogue: 0,0:56:44.84,0:56:46.36,EN,,0,0,0,,And it says they're a thunk. Dialogue: 0,0:56:46.96,0:56:48.46,EN,,0,0,0,,That comes from ALGOL language, Dialogue: 0,0:56:49.07,0:56:50.81,EN,,0,0,0,,and it's claimed to be the sound of Dialogue: 0,0:56:50.83,0:56:52.06,EN,,0,0,0,,of something being pushed on a stack. Dialogue: 0,0:56:52.97,0:56:53.41,EN,,0,0,0,,I don't know. Dialogue: 0,0:56:53.41,0:56:57.12,EN,,0,0,0,,I was not an ALGOLician, so or an ALGOLite or whatever, Dialogue: 0,0:56:57.60,0:56:58.38,EN,,0,0,0,,so I don't know. Dialogue: 0,0:56:58.74,0:56:59.64,EN,,0,0,0,,But that's what was claimed. Dialogue: 0,0:57:00.27,0:57:01.56,EN,,0,0,0,,And undelay is something Dialogue: 0,0:57:01.77,0:57:03.66,EN,,0,0,0,,which will recursively undelay thunks Dialogue: 0,0:57:03.69,0:57:06.00,EN,,0,0,0,,until the thunk becomes something which isn't a thunk. Dialogue: 0,0:57:07.72,0:57:10.94,EN,,0,0,0,,This is the way you implement a call by name like thing in ALGOL. Dialogue: 0,0:57:12.05,0:57:13.76,EN,,0,0,0,,And that's about all there is. Dialogue: 0,0:57:15.21,0:57:16.25,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:57:26.68,0:57:27.52,EN,,0,0,0,,AUDIENCE: Gerry? Dialogue: 0,0:57:28.09,0:57:28.80,EN,,0,0,0,,PROFESSOR: Yes, Vesko? Dialogue: 0,0:57:30.03,0:57:32.99,EN,,0,0,0,,AUDIENCE: I noticed you avoided calling by name Dialogue: 0,0:57:33.44,0:57:34.89,EN,,0,0,0,,in the primitive procedures, Dialogue: 0,0:57:36.41,0:57:38.38,EN,,0,0,0,,I was wondering what cause you have on that? Dialogue: 0,0:57:38.41,0:57:39.21,EN,,0,0,0,,You never need that? Dialogue: 0,0:57:40.07,0:57:41.61,EN,,0,0,0,,PROFESSOR: Vesko is asking Dialogue: 0,0:57:42.06,0:57:46.00,EN,,0,0,0,,if it's ever reasonable to call a primitive procedure by name? Dialogue: 0,0:57:47.14,0:57:48.70,EN,,0,0,0,,The answer is, yes. Dialogue: 0,0:57:49.27,0:57:52.32,EN,,0,0,0,,There's one particular case where it's reasonable, actually two. Dialogue: 0,0:57:55.53,0:57:58.27,EN,,0,0,0,,Construction of a data structure like cons Dialogue: 0,0:57:59.02,0:58:02.00,EN,,0,0,0,,where making an array if you have arrays with any number of elements. Dialogue: 0,0:58:03.26,0:58:07.44,EN,,0,0,0,,OK? It's unnecessary to evaluate those arguments. Dialogue: 0,0:58:07.44,0:58:08.83,EN,,0,0,0,,All you need is promises Dialogue: 0,0:58:09.10,0:58:10.81,EN,,0,0,0,,to evaluate those arguments if you look at them. Dialogue: 0,0:58:11.50,0:58:15.08,EN,,0,0,0,,If I cons together a, two things, Dialogue: 0,0:58:16.24,0:58:17.77,EN,,0,0,0,,then I could cons together the promises Dialogue: 0,0:58:17.80,0:58:19.93,EN,,0,0,0,,just as easily as I can cons together the things. Dialogue: 0,0:58:21.15,0:58:23.37,EN,,0,0,0,,And it's not even when I CAR CDR them Dialogue: 0,0:58:23.39,0:58:24.30,EN,,0,0,0,,that I have to look at them. Dialogue: 0,0:58:24.84,0:58:26.97,EN,,0,0,0,,That just gets out the promises and passes them to somebody. Dialogue: 0,0:58:28.26,0:58:30.51,EN,,0,0,0,,That's why the lambda calculus definition, the Dialogue: 0,0:58:30.57,0:58:34.03,EN,,0,0,0,,the Alonzo Church definition of CAR, CDR, and cons makes sense. Dialogue: 0,0:58:34.42,0:58:36.32,EN,,0,0,0,,It's because no work is done in CAR, CDR, and cons, Dialogue: 0,0:58:36.38,0:58:40.06,EN,,0,0,0,,it's just shuffling data, it's just routing, if you will. Dialogue: 0,0:58:40.99,0:58:42.20,EN,,0,0,0,,However, the things that do have Dialogue: 0,0:58:42.24,0:58:43.84,EN,,0,0,0,,to look at data are things like plus. Dialogue: 0,0:58:45.28,0:58:46.91,EN,,0,0,0,,Because they have a look at the bits Dialogue: 0,0:58:47.12,0:58:48.30,EN,,0,0,0,,that the numbers are made out of, Dialogue: 0,0:58:48.32,0:58:50.44,EN,,0,0,0,,unless they're lambda calculus numbers Dialogue: 0,0:58:50.44,0:58:51.88,EN,,0,0,0,,which are funny. OK? Dialogue: 0,0:58:52.43,0:58:53.58,EN,,0,0,0,,They have to look at the bits to Dialogue: 0,0:58:53.77,0:58:55.53,EN,,0,0,0,,be able to crunch them together to do the add. Dialogue: 0,0:58:59.21,0:58:59.92,EN,,0,0,0,,So, in fact, Dialogue: 0,0:59:00.19,0:59:02.78,EN,,0,0,0,,data constructors, data selectors, Dialogue: 0,0:59:03.24,0:59:05.50,EN,,0,0,0,,in fact, things that side-effect data objects Dialogue: 0,0:59:06.27,0:59:09.76,EN,,0,0,0,,don't need to do, don't need to do any forcing Dialogue: 0,0:59:11.34,0:59:13.39,EN,,0,0,0,,in the laziest possible interpreters. Dialogue: 0,0:59:16.46,0:59:16.99,EN,,0,0,0,,On the other hand Dialogue: 0,0:59:17.02,0:59:18.70,EN,,0,0,0,,predicates on data structures have to. Dialogue: 0,0:59:19.61,0:59:22.65,EN,,0,0,0,,If you want to say, is this a, is this a pair? Dialogue: 0,0:59:23.56,0:59:24.40,EN,,0,0,0,,Or is it a symbol? Dialogue: 0,0:59:24.64,0:59:26.57,EN,,0,0,0,,Well, you better find out. You got to look at it then. Dialogue: 0,0:59:30.30,0:59:31.18,EN,,0,0,0,,Any other questions? Dialogue: 0,0:59:40.05,0:59:41.61,EN,,0,0,0,,Oh, well, I suppose it's time for a break. ================================================ FILE: Ass/lec8a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 3 Video Position: 790 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:18.27,0:00:19.68,EN,,0,0,0,,PROFESSOR: The last time we began having a look Dialogue: 0,0:00:19.72,0:00:21.26,EN,,0,0,0,,at how languages are constructed. Dialogue: 0,0:00:22.41,0:00:25.88,EN,,0,0,0,,Remember the main point that an evaluator for, LISP, say, Dialogue: 0,0:00:26.08,0:00:27.58,EN,,0,0,0,,has two main elements. Dialogue: 0,0:00:27.58,0:00:28.40,EN,,0,0,0,,There is EVAL, Dialogue: 0,0:00:31.04,0:00:37.42,EN,,0,0,0,,and EVAL's job is to take in an expression and an environment Dialogue: 0,0:00:38.91,0:00:44.44,EN,,0,0,0,,and turn that into a procedure and some arguments Dialogue: 0,0:00:45.42,0:00:47.05,EN,,0,0,0,,and pass that off to APPLY. Dialogue: 0,0:00:49.41,0:00:51.29,EN,,0,0,0,,And APPLY takes the procedure in the arguments, Dialogue: 0,0:00:51.69,0:00:55.12,EN,,0,0,0,,turns that back into, in a general case, another expression Dialogue: 0,0:00:55.39,0:00:57.71,EN,,0,0,0,,to be evaluated in another environment Dialogue: 0,0:00:57.74,0:01:00.00,EN,,0,0,0,,and passes that off to EVAL, which passes it to APPLY, Dialogue: 0,0:01:00.27,0:01:01.44,EN,,0,0,0,,and there's this whole big circle Dialogue: 0,0:01:01.47,0:01:02.94,EN,,0,0,0,,where things go around and around and around Dialogue: 0,0:01:03.02,0:01:06.56,EN,,0,0,0,,until you get either to some very primitive data or to a primitive procedure. Dialogue: 0,0:01:07.74,0:01:09.24,EN,,0,0,0,,See, what this cycle has to do with Dialogue: 0,0:01:09.44,0:01:12.57,EN,,0,0,0,,is unwinding the means of combination Dialogue: 0,0:01:12.59,0:01:14.36,EN,,0,0,0,,and the means of abstraction in the language. Dialogue: 0,0:01:15.02,0:01:17.72,EN,,0,0,0,,So for instance, you have a procedure in LISP-- Dialogue: 0,0:01:17.74,0:01:20.52,EN,,0,0,0,,a procedure is a general way of saying, Dialogue: 0,0:01:20.54,0:01:22.57,EN,,0,0,0,,I want to be able to evaluate this expression Dialogue: 0,0:01:22.67,0:01:24.41,EN,,0,0,0,,for any value of the arguments, Dialogue: 0,0:01:25.76,0:01:27.18,EN,,0,0,0,,and that's sort of what's going on here. Dialogue: 0,0:01:27.67,0:01:28.51,EN,,0,0,0,,That's what APPLY does. Dialogue: 0,0:01:28.51,0:01:30.68,EN,,0,0,0,,It says the general thing coming in with the arguments Dialogue: 0,0:01:30.72,0:01:32.70,EN,,0,0,0,,reduces to the expression that's the body, Dialogue: 0,0:01:33.05,0:01:34.72,EN,,0,0,0,,and then if that's a compound expression Dialogue: 0,0:01:34.83,0:01:36.46,EN,,0,0,0,,or another procedure application, Dialogue: 0,0:01:36.78,0:01:38.44,EN,,0,0,0,,the thing will go around and around the circle. Dialogue: 0,0:01:40.33,0:01:44.08,EN,,0,0,0,,Anyway, that's sort of the basic structure of gee, pretty much any interpreter. Dialogue: 0,0:01:45.20,0:01:46.25,EN,,0,0,0,,The other thing that you saw Dialogue: 0,0:01:46.28,0:01:47.66,EN,,0,0,0,,once you have the interpreter in your hands, Dialogue: 0,0:01:47.69,0:01:49.87,EN,,0,0,0,,you have all this power to start playing with the language. Dialogue: 0,0:01:49.87,0:01:51.52,EN,,0,0,0,,So you can make it dynamically scoped, Dialogue: 0,0:01:51.84,0:01:54.56,EN,,0,0,0,,or you can put in normal order evaluation, Dialogue: 0,0:01:54.59,0:01:56.48,EN,,0,0,0,,or you can add new forms to the language, Dialogue: 0,0:01:56.86,0:01:57.50,EN,,0,0,0,,whatever you like. Dialogue: 0,0:01:57.58,0:01:58.62,EN,,0,0,0,,Or more generally, Dialogue: 0,0:01:58.76,0:02:01.32,EN,,0,0,0,,there's this notion of metalinguistic abstraction, Dialogue: 0,0:02:02.64,0:02:06.01,EN,,0,0,0,,which says that part of your perspective Dialogue: 0,0:02:07.61,0:02:10.52,EN,,0,0,0,,as an engineer, as a software engineer, but as an engineer in general Dialogue: 0,0:02:11.39,0:02:13.88,EN,,0,0,0,,is that you can gain control of complexity Dialogue: 0,0:02:14.96,0:02:17.16,EN,,0,0,0,,by inventing new languages sometimes. Dialogue: 0,0:02:18.01,0:02:20.81,EN,,0,0,0,,See, one way to think about computer programming Dialogue: 0,0:02:21.55,0:02:26.27,EN,,0,0,0,,is that it only incidentally has to do with getting a computer to do something. Dialogue: 0,0:02:26.44,0:02:28.97,EN,,0,0,0,,Primarily what a computer program has to do with, Dialogue: 0,0:02:29.00,0:02:32.52,EN,,0,0,0,,it's a way of expressing ideas with communicating ideas. Dialogue: 0,0:02:33.16,0:02:34.04,EN,,0,0,0,,And sometimes Dialogue: 0,0:02:34.89,0:02:36.62,EN,,0,0,0,,when you want to communicate new kinds of ideas, Dialogue: 0,0:02:36.65,0:02:38.73,EN,,0,0,0,,you'd like to invent new modes of expressing that. Dialogue: 0,0:02:39.82,0:02:44.99,EN,,0,0,0,,Well, today we're going to apply this framework to build a new language. Dialogue: 0,0:02:45.73,0:02:48.00,EN,,0,0,0,,See, once we have the basic idea of the interpreter, Dialogue: 0,0:02:48.03,0:02:50.27,EN,,0,0,0,,you can pretty much go build any language that you like. Dialogue: 0,0:02:50.83,0:02:53.21,EN,,0,0,0,,So for example, we can go off and build Pascal. Dialogue: 0,0:02:54.37,0:02:55.15,EN,,0,0,0,,And... Dialogue: 0,0:02:56.17,0:02:58.19,EN,,0,0,0,,gee, we would worry about syntax and parsing Dialogue: 0,0:02:58.19,0:03:00.51,EN,,0,0,0,,and various kinds of compiler optimizations, Dialogue: 0,0:03:01.12,0:03:03.29,EN,,0,0,0,,and there are people who make honest livings doing that, Dialogue: 0,0:03:03.85,0:03:07.60,EN,,0,0,0,,but at the level of abstraction that we're talking, Dialogue: 0,0:03:08.04,0:03:10.99,EN,,0,0,0,,a Pascal interpreter would not look very different at all Dialogue: 0,0:03:12.03,0:03:13.76,EN,,0,0,0,,from what you saw Gerry do last time. Dialogue: 0,0:03:15.02,0:03:18.96,EN,,0,0,0,,Instead of that, we'll spend today building a really different language, Dialogue: 0,0:03:20.51,0:03:22.81,EN,,0,0,0,,a language that encourages you Dialogue: 0,0:03:23.05,0:03:26.04,EN,,0,0,0,,to think about programming not in terms of procedures, Dialogue: 0,0:03:26.24,0:03:27.64,EN,,0,0,0,,but in a really different way. Dialogue: 0,0:03:29.09,0:03:31.02,EN,,0,0,0,,And the lecture today is Dialogue: 0,0:03:31.74,0:03:34.64,EN,,0,0,0,,going to be at two levels simultaneously. Dialogue: 0,0:03:34.81,0:03:35.52,EN,,0,0,0,,On the one hand, Dialogue: 0,0:03:35.90,0:03:37.71,EN,,0,0,0,,I'm going to show you what this language looks like, Dialogue: 0,0:03:38.96,0:03:41.08,EN,,0,0,0,,and on the other hand, I'll show you how it's implemented. Dialogue: 0,0:03:41.32,0:03:42.96,EN,,0,0,0,,And we'll build an implementation in LISP Dialogue: 0,0:03:42.99,0:03:43.90,EN,,0,0,0,,and see how that works. Dialogue: 0,0:03:44.04,0:03:48.25,EN,,0,0,0,,And you should be drawing lessons on two levels. Dialogue: 0,0:03:48.68,0:03:53.00,EN,,0,0,0,,The first is to realize just how different a language can be. Dialogue: 0,0:03:53.79,0:03:58.14,EN,,0,0,0,,So if you think that the jump from Fortran to LISP is a big deal, Dialogue: 0,0:03:58.24,0:03:59.36,EN,,0,0,0,,you haven't seen anything yet. Dialogue: 0,0:04:01.56,0:04:03.68,EN,,0,0,0,,And secondly, Dialogue: 0,0:04:03.77,0:04:06.54,EN,,0,0,0,,you'll see that even with such a very different language, Dialogue: 0,0:04:07.36,0:04:09.52,EN,,0,0,0,,which will turn out to not have procedures at all Dialogue: 0,0:04:09.92,0:04:11.64,EN,,0,0,0,,and not talk about functions at all, Dialogue: 0,0:04:12.20,0:04:15.72,EN,,0,0,0,,there will still be this basic cycle of eval and apply Dialogue: 0,0:04:16.19,0:04:19.98,EN,,0,0,0,,that's unwinds the means of combination and the means an abstraction. Dialogue: 0,0:04:20.95,0:04:24.68,EN,,0,0,0,,And then thirdly, as kind of a minor but elegant technical point, Dialogue: 0,0:04:24.89,0:04:28.52,EN,,0,0,0,,you'll see a nice use of streams to avoid backtracking. Dialogue: 0,0:04:32.33,0:04:34.40,EN,,0,0,0,,OK, well, I said that this language is very different. Dialogue: 0,0:04:35.86,0:04:36.64,EN,,0,0,0,,To explain that, Dialogue: 0,0:04:37.05,0:04:42.81,EN,,0,0,0,,let's go back to the very first idea that we talked about in this course, Dialogue: 0,0:04:43.26,0:04:46.54,EN,,0,0,0,,and that was the idea of the distinction between Dialogue: 0,0:04:46.72,0:04:49.52,EN,,0,0,0,,the declarative knowledge of mathematics-- Dialogue: 0,0:04:50.19,0:04:54.14,EN,,0,0,0,,the definition of a square root as a mathematical truth-- Dialogue: 0,0:04:55.48,0:04:59.56,EN,,0,0,0,,and the idea that computer science talks about the how to knowledge-- Dialogue: 0,0:04:59.76,0:05:04.59,EN,,0,0,0,,contrast that definition of square root with a program to compute a square root. Dialogue: 0,0:05:05.97,0:05:07.07,EN,,0,0,0,,That's where we started off. Dialogue: 0,0:05:08.51,0:05:09.52,EN,,0,0,0,,Well, wouldn't it be great Dialogue: 0,0:05:09.88,0:05:12.16,EN,,0,0,0,,if you could somehow bridge this gap Dialogue: 0,0:05:12.81,0:05:16.43,EN,,0,0,0,,and make a programming language which sort of did things, Dialogue: 0,0:05:16.67,0:05:21.61,EN,,0,0,0,,but you talked about it in terms of truth, in declarative terms? Dialogue: 0,0:05:22.38,0:05:25.50,EN,,0,0,0,,So that would be a programming language in which you specify facts. Dialogue: 0,0:05:27.69,0:05:28.88,EN,,0,0,0,,You tell it what is. Dialogue: 0,0:05:28.88,0:05:29.96,EN,,0,0,0,,You say what is true. Dialogue: 0,0:05:30.95,0:05:33.07,EN,,0,0,0,,And then when you want an answer, Dialogue: 0,0:05:33.21,0:05:36.38,EN,,0,0,0,,somehow the language has built into it automatically Dialogue: 0,0:05:37.60,0:05:39.45,EN,,0,0,0,,general kinds of how to knowledge Dialogue: 0,0:05:39.47,0:05:40.64,EN,,0,0,0,,so it can just take your facts Dialogue: 0,0:05:40.89,0:05:42.83,EN,,0,0,0,,and it can evolve these methods on its own Dialogue: 0,0:05:43.31,0:05:46.12,EN,,0,0,0,,using the facts you gave it and maybe some general rules of logic. Dialogue: 0,0:05:49.33,0:05:50.54,EN,,0,0,0,,So for instance, Dialogue: 0,0:05:52.06,0:05:55.12,EN,,0,0,0,,I might go up to this program and start telling it some things. Dialogue: 0,0:05:56.00,0:06:07.08,EN,,0,0,0,,So I might tell it that the son of Adam is Abel. Dialogue: 0,0:06:08.92,0:06:16.51,EN,,0,0,0,,And I might tell it that the son of Adam is Cain. Dialogue: 0,0:06:17.66,0:06:25.08,EN,,0,0,0,,And I might tell it that the son of Cain is Enoch. Dialogue: 0,0:06:27.79,0:06:34.89,EN,,0,0,0,,And I might tell it that the son of Enoch is Irad, Dialogue: 0,0:06:37.02,0:06:40.72,EN,,0,0,0,,and all through the rest of our chapter whatever of Genesis, Dialogue: 0,0:06:41.15,0:06:43.18,EN,,0,0,0,,which ends up ending in Adah, by the way, Dialogue: 0,0:06:43.32,0:06:46.78,EN,,0,0,0,,and this shows the genealogy of Adah from Cain. Dialogue: 0,0:06:48.44,0:06:50.67,EN,,0,0,0,,Anyway, once you tell it these facts, Dialogue: 0,0:06:52.35,0:06:53.40,EN,,0,0,0,,you might ask it things. Dialogue: 0,0:06:53.51,0:06:55.05,EN,,0,0,0,,You might go up to your language and say, Dialogue: 0,0:06:56.06,0:06:59.29,EN,,0,0,0,,who's the son of Adam? Dialogue: 0,0:07:00.42,0:07:04.91,EN,,0,0,0,,And you can very easily imagine having a little general purpose search program Dialogue: 0,0:07:05.52,0:07:06.96,EN,,0,0,0,,which would be able to go through Dialogue: 0,0:07:07.00,0:07:09.26,EN,,0,0,0,,and in response to that say, oh yeah, there are two answers: Dialogue: 0,0:07:09.29,0:07:10.44,EN,,0,0,0,,the son of Adam is Abel Dialogue: 0,0:07:10.68,0:07:12.17,EN,,0,0,0,,and the son of Adam is Cain. Dialogue: 0,0:07:14.14,0:07:14.97,EN,,0,0,0,,Or you might say, Dialogue: 0,0:07:15.07,0:07:16.89,EN,,0,0,0,,based on the very same facts, Dialogue: 0,0:07:18.04,0:07:19.95,EN,,0,0,0,,who is Cain the son of? Dialogue: 0,0:07:21.95,0:07:27.02,EN,,0,0,0,,And then you can imagine generating another slightly different search program Dialogue: 0,0:07:27.92,0:07:29.21,EN,,0,0,0,,which would be able to go through Dialogue: 0,0:07:29.45,0:07:33.05,EN,,0,0,0,,and checked for who is Cain, and son of, Dialogue: 0,0:07:33.52,0:07:34.44,EN,,0,0,0,,and come up with Adam. Dialogue: 0,0:07:35.89,0:07:36.99,EN,,0,0,0,,Or you might say, Dialogue: 0,0:07:38.01,0:07:41.40,EN,,0,0,0,,what's the relationship between Cain and Enoch? Dialogue: 0,0:07:42.07,0:07:45.08,EN,,0,0,0,,And again, a minor variant on that search program. Dialogue: 0,0:07:46.34,0:07:48.16,EN,,0,0,0,,You could figure out that it said son of. Dialogue: 0,0:07:52.88,0:07:54.92,EN,,0,0,0,,But even here in this very simple example, Dialogue: 0,0:07:56.14,0:07:58.44,EN,,0,0,0,,what you see is that a single fact, Dialogue: 0,0:07:58.81,0:08:01.52,EN,,0,0,0,,see, a single fact like the son of Adam is Cain Dialogue: 0,0:08:02.84,0:08:05.52,EN,,0,0,0,,can be used to answer different kinds of questions. Dialogue: 0,0:08:06.52,0:08:08.12,EN,,0,0,0,,You can say, who's Cain the son of, Dialogue: 0,0:08:08.14,0:08:10.92,EN,,0,0,0,,or you can say who's the son of Adam, Dialogue: 0,0:08:10.94,0:08:12.86,EN,,0,0,0,,or you can say what's the relation between Adam and Cain? Dialogue: 0,0:08:12.88,0:08:14.48,EN,,0,0,0,,Those are different questions Dialogue: 0,0:08:15.53,0:08:18.54,EN,,0,0,0,,being run by different traditional procedures Dialogue: 0,0:08:18.68,0:08:20.72,EN,,0,0,0,,all based on the same fact. Dialogue: 0,0:08:22.75,0:08:25.92,EN,,0,0,0,,And that's going to be the essence of the power of this programming style, Dialogue: 0,0:08:26.91,0:08:29.50,EN,,0,0,0,,that one piece of declarative knowledge Dialogue: 0,0:08:30.04,0:08:34.01,EN,,0,0,0,,can be used as the basis for a lot of different kinds of how-to knowledge, Dialogue: 0,0:08:34.81,0:08:37.08,EN,,0,0,0,,as opposed to the kinds of procedures we're writing Dialogue: 0,0:08:37.15,0:08:39.55,EN,,0,0,0,,where you sort of tell it what input you're giving in Dialogue: 0,0:08:39.61,0:08:40.65,EN,,0,0,0,,and what answer you want. Dialogue: 0,0:08:41.49,0:08:44.70,EN,,0,0,0,,So for instance, our square root program can perfectly well answer the question, Dialogue: 0,0:08:44.76,0:08:47.16,EN,,0,0,0,,what's the square root of 144? Dialogue: 0,0:08:48.90,0:08:49.77,EN,,0,0,0,,But in principle, Dialogue: 0,0:08:49.82,0:08:52.83,EN,,0,0,0,,the mathematical definition of square root tells you other things. Dialogue: 0,0:08:52.84,0:08:56.43,EN,,0,0,0,,Like it could say, what is 17 the square root of? Dialogue: 0,0:08:57.59,0:08:59.71,EN,,0,0,0,,And that would be have to be answered by a different program. Dialogue: 0,0:09:01.92,0:09:03.50,EN,,0,0,0,,So the mathematical definition, Dialogue: 0,0:09:03.98,0:09:05.12,EN,,0,0,0,,or in general, the Dialogue: 0,0:09:05.53,0:09:10.30,EN,,0,0,0,,the facts that you give it are somehow unbiased as to what the question is. Dialogue: 0,0:09:10.90,0:09:12.81,EN,,0,0,0,,Whereas the programs we tend to write specifically Dialogue: 0,0:09:12.83,0:09:14.20,EN,,0,0,0,,because they are how-to knowledge Dialogue: 0,0:09:14.24,0:09:16.36,EN,,0,0,0,,tend to be looking for a specific answer. Dialogue: 0,0:09:17.56,0:09:20.12,EN,,0,0,0,,So that's going to be one characteristic of what we're talking about. Dialogue: 0,0:09:21.81,0:09:22.60,EN,,0,0,0,,We can go on. Dialogue: 0,0:09:23.48,0:09:27.52,EN,,0,0,0,,We can imagine that we've given our language some sort of facts. Dialogue: 0,0:09:27.71,0:09:29.61,EN,,0,0,0,,Now let's give it some rules of inference. Dialogue: 0,0:09:30.02,0:09:31.36,EN,,0,0,0,,We can say, for instance, Dialogue: 0,0:09:31.95,0:09:36.19,EN,,0,0,0,,if the-- make up some syntax here-- Dialogue: 0,0:09:36.44,0:09:41.53,EN,,0,0,0,,if the son of x is y-- Dialogue: 0,0:09:41.68,0:09:45.21,EN,,0,0,0,,I'll put question marks to indicate variables here-- Dialogue: 0,0:09:45.61,0:09:56.06,EN,,0,0,0,,if the son of x is y and the son of y is z, Dialogue: 0,0:09:58.96,0:10:08.46,EN,,0,0,0,,then the grandson of x is z. Dialogue: 0,0:10:09.32,0:10:13.40,EN,,0,0,0,,So I can imagine telling my machine that rule Dialogue: 0,0:10:15.00,0:10:17.28,EN,,0,0,0,,and then being able to say, for instance, Dialogue: 0,0:10:17.44,0:10:18.68,EN,,0,0,0,,who's the grandson of Adam? Dialogue: 0,0:10:20.61,0:10:23.64,EN,,0,0,0,,Or who is Irad the grandson of? Dialogue: 0,0:10:24.79,0:10:29.08,EN,,0,0,0,,Or deduce all grandson relationships you possibly can from this information. Dialogue: 0,0:10:31.13,0:10:35.60,EN,,0,0,0,,We can imagine somehow the language knowing how to do that automatically. Dialogue: 0,0:10:40.22,0:10:45.20,EN,,0,0,0,,Ok, Let me give you maybe a little bit more concrete example. Dialogue: 0,0:10:45.77,0:10:51.95,EN,,0,0,0,,Here's a procedure that merges two sorted lists. Dialogue: 0,0:10:53.92,0:11:00.27,EN,,0,0,0,,So x and y are two, say, lists of numbers, Dialogue: 0,0:11:00.30,0:11:04.20,EN,,0,0,0,,lists of distinct numbers, if you like, that are in increasing order. Dialogue: 0,0:11:04.76,0:11:07.53,EN,,0,0,0,,And what merge does is take two such lists Dialogue: 0,0:11:07.71,0:11:10.38,EN,,0,0,0,,and combine them into a list where everything's in increasing order, Dialogue: 0,0:11:11.21,0:11:15.00,EN,,0,0,0,,and this is a pretty easy programs Dialogue: 0,0:11:15.02,0:11:16.14,EN,,0,0,0,,that you ought to be able to write. Dialogue: 0,0:11:16.39,0:11:18.64,EN,,0,0,0,,It says, if x is empty, the answer is y. Dialogue: 0,0:11:18.86,0:11:20.46,EN,,0,0,0,,If y is empty, the answer is x. Dialogue: 0,0:11:21.18,0:11:22.99,EN,,0,0,0,,Otherwise, you compare the first two elements. Dialogue: 0,0:11:22.99,0:11:24.46,EN,,0,0,0,,So you pick out the first thing in x Dialogue: 0,0:11:24.84,0:11:26.01,EN,,0,0,0,,and the first thing in y, Dialogue: 0,0:11:26.81,0:11:31.68,EN,,0,0,0,,and then depending on which of those first elements is less, Dialogue: 0,0:11:32.83,0:11:36.60,EN,,0,0,0,,you stick the lower one on to the result a recursively merging, Dialogue: 0,0:11:37.87,0:11:39.92,EN,,0,0,0,,either chopping the first one off x Dialogue: 0,0:11:40.11,0:11:41.61,EN,,0,0,0,,or chopping the first one off y. Dialogue: 0,0:11:42.40,0:11:43.96,EN,,0,0,0,,That's a standard kind of program. Dialogue: 0,0:11:46.47,0:11:48.41,EN,,0,0,0,,Let's look at the logic. Dialogue: 0,0:11:48.62,0:11:49.79,EN,,0,0,0,,Let's forget about the program Dialogue: 0,0:11:50.28,0:11:52.76,EN,,0,0,0,,and look at the logic on which that procedure is based. Dialogue: 0,0:11:53.82,0:11:55.00,EN,,0,0,0,,See, there's some logic which says, Dialogue: 0,0:11:55.02,0:11:57.21,EN,,0,0,0,,gee, if the first one is less, Dialogue: 0,0:11:57.53,0:12:00.00,EN,,0,0,0,,then we get the answer by sticking something onto the Dialogue: 0,0:12:00.16,0:12:02.12,EN,,0,0,0,,the result of recursively merging the rest. Dialogue: 0,0:12:02.84,0:12:04.09,EN,,0,0,0,,So let's try and be explicit about Dialogue: 0,0:12:04.24,0:12:06.41,EN,,0,0,0,,what that logic is that's making the program work. Dialogue: 0,0:12:08.30,0:12:09.44,EN,,0,0,0,,So here's one piece. Dialogue: 0,0:12:10.13,0:12:11.53,EN,,0,0,0,,Here's the piece of the program which Dialogue: 0,0:12:12.64,0:12:15.26,EN,,0,0,0,,recursively chops down x Dialogue: 0,0:12:15.66,0:12:17.82,EN,,0,0,0,,if the first thing in x is smaller. Dialogue: 0,0:12:19.98,0:12:22.54,EN,,0,0,0,,And if you want to be very explicit about what the logic is there, Dialogue: 0,0:12:23.45,0:12:26.49,EN,,0,0,0,,what's really going on is a deduction, Dialogue: 0,0:12:26.72,0:12:32.38,EN,,0,0,0,,which says, if you know that some list, that we'll call cdr of x, and y Dialogue: 0,0:12:33.29,0:12:35.44,EN,,0,0,0,,merged to form z, Dialogue: 0,0:12:37.84,0:12:41.52,EN,,0,0,0,,And you know that a is less than the first thing in y. Dialogue: 0,0:12:43.60,0:12:48.52,EN,,0,0,0,,then you know that if you put a onto the cdr of x. Dialogue: 0,0:12:49.74,0:12:51.85,EN,,0,0,0,,and that result and y Dialogue: 0,0:12:52.60,0:12:54.99,EN,,0,0,0,,merge-to-form a onto z. Dialogue: 0,0:12:55.82,0:12:58.09,EN,,0,0,0,,And what that is, that's the underlying piece of logic-- Dialogue: 0,0:12:58.72,0:12:59.95,EN,,0,0,0,,I haven't written it as a program, Dialogue: 0,0:12:59.96,0:13:02.00,EN,,0,0,0,,I wrote it a sort of deduction Dialogue: 0,0:13:02.03,0:13:04.89,EN,,0,0,0,,that sits underneath this particular clause Dialogue: 0,0:13:05.21,0:13:07.26,EN,,0,0,0,,that says we can use the recursion there. Dialogue: 0,0:13:09.41,0:13:12.78,EN,,0,0,0,,And then similar, here's the other clause just to complete it. Dialogue: 0,0:13:14.00,0:13:15.87,EN,,0,0,0,,The other clause is based on this piece of logic, Dialogue: 0,0:13:15.92,0:13:18.35,EN,,0,0,0,,which is almost the same and I won't go through it, Dialogue: 0,0:13:19.00,0:13:20.35,EN,,0,0,0,,and then there's the end cases Dialogue: 0,0:13:20.41,0:13:22.01,EN,,0,0,0,,where we tested for null, Dialogue: 0,0:13:22.03,0:13:24.04,EN,,0,0,0,,and that's based on the idea that for any x, Dialogue: 0,0:13:24.51,0:13:27.20,EN,,0,0,0,,x and the empty list merge to form an x, Dialogue: 0,0:13:28.04,0:13:30.86,EN,,0,0,0,,or for any y, the empty list and y merge to form y. Dialogue: 0,0:13:33.36,0:13:38.12,EN,,0,0,0,,OK, so there's a piece of procedure Dialogue: 0,0:13:38.43,0:13:40.11,EN,,0,0,0,,and the logic on which it's based. Dialogue: 0,0:13:41.74,0:13:42.97,EN,,0,0,0,,And notice a big difference. Dialogue: 0,0:13:45.10,0:13:50.52,EN,,0,0,0,,The procedure looked like this: Dialogue: 0,0:13:50.65,0:13:52.28,EN,,0,0,0,,it said there was a box-- Dialogue: 0,0:13:52.86,0:13:55.39,EN,,0,0,0,,and all the things we've been doing have the characteristic Dialogue: 0,0:13:55.40,0:13:57.69,EN,,0,0,0,,we have boxes and things going in and things going out-- Dialogue: 0,0:13:58.08,0:13:59.61,EN,,0,0,0,,there was this box called merge, Dialogue: 0,0:14:01.29,0:14:03.85,EN,,0,0,0,,and in came an x and y, Dialogue: 0,0:14:04.44,0:14:05.37,EN,,0,0,0,,and out came an answer. Dialogue: 0,0:14:07.63,0:14:09.48,EN,,0,0,0,,That's the character of the procedure that we wrote. Dialogue: 0,0:14:13.02,0:14:14.66,EN,,0,0,0,,These rules don't look like that. Dialogue: 0,0:14:14.66,0:14:16.76,EN,,0,0,0,,These rules talk about a relation. Dialogue: 0,0:14:17.92,0:14:24.16,EN,,0,0,0,,There's some sort of relation that in those slides I called mrege-to-form. Dialogue: 0,0:14:25.37,0:14:28.76,EN,,0,0,0,,So I said x and y merge to form z, Dialogue: 0,0:14:29.00,0:14:32.33,EN,,0,0,0,,and somehow this is not -- this is a function. Dialogue: 0,0:14:32.61,0:14:32.85,EN,,0,0,0,,Right? Dialogue: 0,0:14:32.85,0:14:34.41,EN,,0,0,0,,The answer is a function of x and y, Dialogue: 0,0:14:34.59,0:14:38.19,EN,,0,0,0,,and here what I have is a relation between three things. Dialogue: 0,0:14:39.72,0:14:41.32,EN,,0,0,0,,And I'm not going to specify Dialogue: 0,0:14:42.09,0:14:43.77,EN,,0,0,0,,which is the input and which is the output. Dialogue: 0,0:14:44.20,0:14:47.40,EN,,0,0,0,,And the reason I want to say that is because in principle, Dialogue: 0,0:14:48.64,0:14:50.83,EN,,0,0,0,,we could use exactly those same logic rules Dialogue: 0,0:14:50.84,0:14:52.44,EN,,0,0,0,,answer a lot of different questions. Dialogue: 0,0:14:54.57,0:14:56.30,EN,,0,0,0,,So we can say, for instance-- giving Dialogue: 0,0:14:56.72,0:14:59.05,EN,,0,0,0,,imagine giving our machine those rules of logic. Dialogue: 0,0:14:59.05,0:15:01.20,EN,,0,0,0,,Not the program, the underlying rules of logic. Dialogue: 0,0:15:01.40,0:15:03.12,EN,,0,0,0,,Then it ought to be able to say-- Dialogue: 0,0:15:04.75,0:15:05.52,EN,,0,0,0,,we could ask it-- Dialogue: 0,0:15:06.73,0:15:19.18,EN,,0,0,0,,1, 3, 7 and 2, 4, 8 merge to form what? Dialogue: 0,0:15:20.91,0:15:23.42,EN,,0,0,0,,And that's a question it ought to be able to answer. Dialogue: 0,0:15:23.88,0:15:27.36,EN,,0,0,0,,That's exactly the same question that our Lisp procedure answered. Dialogue: 0,0:15:28.18,0:15:30.14,EN,,0,0,0,,But the exact same rules Dialogue: 0,0:15:30.89,0:15:34.80,EN,,0,0,0,,should also be able to answer a question like this: Dialogue: 0,0:15:36.19,0:15:43.24,EN,,0,0,0,,1, 3, 7 and what merged to form 1, 2, 3, 4, 7, 8? Dialogue: 0,0:15:45.56,0:15:47.80,EN,,0,0,0,,The same rules of logic can answer this, Dialogue: 0,0:15:47.84,0:15:49.90,EN,,0,0,0,,although the procedure we wrote can't answer that question. Dialogue: 0,0:15:50.80,0:15:52.33,EN,,0,0,0,,Or we might be able to say what Dialogue: 0,0:15:53.71,0:16:01.12,EN,,0,0,0,,what and what else merge to form-- Dialogue: 0,0:16:04.28,0:16:12.68,EN,,0,0,0,,what and what else merge to form 1, 2, 3, 4, 7, 8? Dialogue: 0,0:16:13.78,0:16:15.34,EN,,0,0,0,,And the thing should be able to go through, Dialogue: 0,0:16:15.84,0:16:17.31,EN,,0,0,0,,if it really can apply that logic, Dialogue: 0,0:16:17.79,0:16:22.54,EN,,0,0,0,,and deduce all, whatever is, 2 to the sixth answers to that question. Dialogue: 0,0:16:25.60,0:16:27.69,EN,,0,0,0,,Cause it could be 1 and the rester, or it could be 1, 2 and the rest. Dialogue: 0,0:16:27.69,0:16:28.75,EN,,0,0,0,,or it could be 1, 2 and the rester. Dialogue: 0,0:16:28.79,0:16:31.53,EN,,0,0,0,,Or it could be 1 and 3 and 7 and the rest. Dialogue: 0,0:16:32.01,0:16:33.26,EN,,0,0,0,,There's a whole bunch of answers. Dialogue: 0,0:16:33.41,0:16:37.76,EN,,0,0,0,,And in principle, the logic should be enough to deduce that. Dialogue: 0,0:16:38.55,0:16:42.03,EN,,0,0,0,,So there are going to be two big differences Dialogue: 0,0:16:44.04,0:16:46.00,EN,,0,0,0,,in the kind of program we're going to look at Dialogue: 0,0:16:46.54,0:16:48.19,EN,,0,0,0,,and not only Lisp, Dialogue: 0,0:16:48.20,0:16:50.56,EN,,0,0,0,,but essentially all the programming you've probably done so far Dialogue: 0,0:16:52.03,0:16:53.60,EN,,0,0,0,,in pretty much any language you can think of. Dialogue: 0,0:16:54.15,0:16:57.79,EN,,0,0,0,,The first is, we're not going to be computing functions. Dialogue: 0,0:17:00.62,0:17:02.01,EN,,0,0,0,,We're not going to be talking about Dialogue: 0,0:17:02.62,0:17:04.41,EN,,0,0,0,,about things that take input and output. Dialogue: 0,0:17:04.41,0:17:05.82,EN,,0,0,0,,We're going to be talking about relations. Dialogue: 0,0:17:06.89,0:17:10.00,EN,,0,0,0,,And that means in principle, these relations don't have directionality. Dialogue: 0,0:17:11.08,0:17:15.05,EN,,0,0,0,,So the knowledge that you specify to answer this question, Dialogue: 0,0:17:16.46,0:17:18.41,EN,,0,0,0,,should be same, that same knowledge Dialogue: 0,0:17:18.43,0:17:21.80,EN,,0,0,0,,also allow you to answer these other questions and conversely. Dialogue: 0,0:17:26.60,0:17:29.40,EN,,0,0,0,,And the second issue is that Dialogue: 0,0:17:29.61,0:17:31.23,EN,,0,0,0,,since we're talking about relations, Dialogue: 0,0:17:32.32,0:17:34.44,EN,,0,0,0,,these relations don't necessarily have one answer. Dialogue: 0,0:17:35.61,0:17:37.00,EN,,0,0,0,,So that third question down there Dialogue: 0,0:17:37.02,0:17:38.36,EN,,0,0,0,,doesn't have a particular answer, Dialogue: 0,0:17:38.40,0:17:39.58,EN,,0,0,0,,it has a whole bunch of answers. Dialogue: 0,0:17:42.27,0:17:44.64,EN,,0,0,0,,Well, that's where we're going. Dialogue: 0,0:17:44.64,0:17:45.90,EN,,0,0,0,,This style of programming, Dialogue: 0,0:17:46.72,0:17:49.21,EN,,0,0,0,,by the way, is called logic programming, Dialogue: 0,0:17:50.22,0:17:51.58,EN,,0,0,0,,for kind of obvious reasons. Dialogue: 0,0:17:56.16,0:18:00.38,EN,,0,0,0,,And people who do logic programming say that -- Dialogue: 0,0:18:00.40,0:18:03.15,EN,,0,0,0,,they have this little phrase-- Dialogue: 0,0:18:03.16,0:18:04.67,EN,,0,0,0,,they say the point of logic programming Dialogue: 0,0:18:04.76,0:18:09.00,EN,,0,0,0,,is that you use logic to express what is true, Dialogue: 0,0:18:10.09,0:18:13.88,EN,,0,0,0,,you use logic to check whether something is true, Dialogue: 0,0:18:14.67,0:18:17.24,EN,,0,0,0,,and you use logic to find out what is true. Dialogue: 0,0:18:19.20,0:18:22.09,EN,,0,0,0,,The best known logic programming language, Dialogue: 0,0:18:22.97,0:18:24.78,EN,,0,0,0,,as you probably know, is called Prolog. Dialogue: 0,0:18:25.78,0:18:28.88,EN,,0,0,0,,The language that we're going to implement this morning Dialogue: 0,0:18:29.82,0:18:32.32,EN,,0,0,0,,is something we call the query language, Dialogue: 0,0:18:32.48,0:18:34.41,EN,,0,0,0,,and it essentially has the essence of prolog. Dialogue: 0,0:18:35.32,0:18:36.73,EN,,0,0,0,,It can do about the same stuff, Dialogue: 0,0:18:37.29,0:18:38.73,EN,,0,0,0,,although it's a lot slower Dialogue: 0,0:18:38.73,0:18:40.01,EN,,0,0,0,,because we're going to implement it in LISP Dialogue: 0,0:18:41.90,0:18:44.36,EN,,0,0,0,,rather than building a particular compiler. Dialogue: 0,0:18:44.46,0:18:46.62,EN,,0,0,0,,We're going to interpret it on top of the LISP interpreter. Dialogue: 0,0:18:47.51,0:18:49.84,EN,,0,0,0,,But other than that, it can do about the same stuff as prolog. Dialogue: 0,0:18:49.88,0:18:52.78,EN,,0,0,0,,It has about the same power and about the same limitations. Dialogue: 0,0:18:55.08,0:18:56.17,EN,,0,0,0,,All right, let's break for question. Dialogue: 0,0:19:00.43,0:19:02.84,EN,,0,0,0,,AUDIENCE: Yes, could you please repeat what the three Dialogue: 0,0:19:03.48,0:19:06.09,EN,,0,0,0,,things you use logic programming to find? Dialogue: 0,0:19:06.72,0:19:09.84,EN,,0,0,0,,In other words, to find what is true, learn what is true-- what is the? Dialogue: 0,0:19:09.84,0:19:10.52,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:19:10.56,0:19:15.74,EN,,0,0,0,,Sort of a logic programmer's little catechism. Dialogue: 0,0:19:15.85,0:19:19.16,EN,,0,0,0,,You use logic to express what is true, Dialogue: 0,0:19:20.80,0:19:21.79,EN,,0,0,0,,like these rules. Dialogue: 0,0:19:22.61,0:19:25.56,EN,,0,0,0,,You use logic to check whether something is true, Dialogue: 0,0:19:25.60,0:19:27.76,EN,,0,0,0,,and that's the kind of question I didn't answer here. Dialogue: 0,0:19:28.55,0:19:29.29,EN,,0,0,0,,I might say-- Dialogue: 0,0:19:29.68,0:19:32.14,EN,,0,0,0,,another question I could put down here is to say, Dialogue: 0,0:19:33.26,0:19:36.56,EN,,0,0,0,,is it true that 1, 3, 7 and 2, 4, 8 Dialogue: 0,0:19:36.91,0:19:40.38,EN,,0,0,0,,merge to form 1, 2, 6, 10 Dialogue: 0,0:19:41.12,0:19:44.68,EN,,0,0,0,,And that same logic should be enough to say no. Dialogue: 0,0:19:45.69,0:19:47.93,EN,,0,0,0,,So I use logic to check what is true, Dialogue: 0,0:19:48.28,0:19:50.48,EN,,0,0,0,,and then you also use logic to find out what's true. Dialogue: 0,0:20:04.46,0:20:05.16,EN,,0,0,0,,Let's break. Dialogue: 0,0:20:06.13,0:20:17.02,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:21:03.24,0:21:04.97,EN,,0,0,0,,PROFESSOR: OK, let's go ahead and Dialogue: 0,0:21:05.84,0:21:08.44,EN,,0,0,0,,take a look at this query language and operation. Dialogue: 0,0:21:10.52,0:21:11.84,EN,,0,0,0,,The first thing you might notice, Dialogue: 0,0:21:12.24,0:21:14.14,EN,,0,0,0,,when I put up that little biblical database, Dialogue: 0,0:21:14.16,0:21:17.24,EN,,0,0,0,,is that it's nice to be able to ask this language questions Dialogue: 0,0:21:17.48,0:21:19.92,EN,,0,0,0,,in relation to some collection of facts. Dialogue: 0,0:21:21.33,0:21:25.15,EN,,0,0,0,,So let's start off and make a little collection of facts. Dialogue: 0,0:21:26.06,0:21:29.68,EN,,0,0,0,,This is a tiny fragment of personnel records Dialogue: 0,0:21:30.08,0:21:32.62,EN,,0,0,0,,for a Boston high tech company, Dialogue: 0,0:21:33.05,0:21:36.80,EN,,0,0,0,,and here's a piece of the personnel records of Ben Bitdiddle. Dialogue: 0,0:21:37.50,0:21:41.95,EN,,0,0,0,,And Ben Bitdiddle is the computer wizard in this company, Dialogue: 0,0:21:42.84,0:21:45.80,EN,,0,0,0,,he's the underpaid computer wizard in this company. Dialogue: 0,0:21:46.42,0:21:48.78,EN,,0,0,0,,His supervisor is all Oliver Warbucks, Dialogue: 0,0:21:49.28,0:21:50.70,EN,,0,0,0,,and here's his address. Dialogue: 0,0:21:52.15,0:21:56.54,EN,,0,0,0,,So the format is we're giving this information: job, salary, supervisor, address. Dialogue: 0,0:21:57.56,0:21:59.25,EN,,0,0,0,,And there are some other conventions. Dialogue: 0,0:21:59.25,0:22:02.22,EN,,0,0,0,,Computer here means that Ben works in the computer division, and Dialogue: 0,0:22:02.76,0:22:04.94,EN,,0,0,0,,his position in the computer division is wizard. Dialogue: 0,0:22:05.66,0:22:07.15,EN,,0,0,0,,Here's somebody else. Dialogue: 0,0:22:07.16,0:22:12.28,EN,,0,0,0,,Alyssa, Alyssa P. Hacker is a computer programmer, Dialogue: 0,0:22:13.36,0:22:14.60,EN,,0,0,0,,and she works for Ben, Dialogue: 0,0:22:15.21,0:22:16.54,EN,,0,0,0,,and she lives in Cambridge. Dialogue: 0,0:22:17.55,0:22:19.42,EN,,0,0,0,,And there's another programmer who works for Ben Dialogue: 0,0:22:20.03,0:22:21.44,EN,,0,0,0,,who's Lem E. Tweakit. Dialogue: 0,0:22:22.82,0:22:26.73,EN,,0,0,0,,And there's a programmer trainee, who is Louis Reasoner, Dialogue: 0,0:22:27.42,0:22:28.62,EN,,0,0,0,,and he works for Alyssa. Dialogue: 0,0:22:30.10,0:22:35.45,EN,,0,0,0,,And the big wheel of the company doesn't work for anybody. Dialogue: 0,0:22:36.81,0:22:38.11,EN,,0,0,0,,Right, That's Oliver Warbucks. Dialogue: 0,0:22:38.11,0:22:39.31,EN,,0,0,0,,Anyway, what we're going to do is Dialogue: 0,0:22:40.94,0:22:43.66,EN,,0,0,0,,is ask questions about that little world. Dialogue: 0,0:22:44.97,0:22:48.40,EN,,0,0,0,,And that'll be a sample world that we're going to do logic in. Dialogue: 0,0:22:51.42,0:22:54.96,EN,,0,0,0,,Let me just write up here, for probably the last time, Dialogue: 0,0:22:55.60,0:22:58.20,EN,,0,0,0,,what I said is the very most important thing you should get out of this course, Dialogue: 0,0:22:58.80,0:23:01.66,EN,,0,0,0,,and that is, when somebody tells you about a language, Dialogue: 0,0:23:02.25,0:23:04.43,EN,,0,0,0,,you say, fine-- what are the primitives, Dialogue: 0,0:23:06.12,0:23:07.79,EN,,0,0,0,,what are the means of combination, Dialogue: 0,0:23:14.70,0:23:16.40,EN,,0,0,0,,how do you put the primitives together, Dialogue: 0,0:23:16.67,0:23:19.37,EN,,0,0,0,,and then how do you abstract them, Dialogue: 0,0:23:19.96,0:23:21.93,EN,,0,0,0,,how do you abstract the compound pieces Dialogue: 0,0:23:24.68,0:23:27.58,EN,,0,0,0,,so you can use them as pieces to make something more complicated? Dialogue: 0,0:23:29.02,0:23:30.81,EN,,0,0,0,,And we've said this a whole bunch of times already, Dialogue: 0,0:23:31.16,0:23:32.48,EN,,0,0,0,,but it's worth saying again. Dialogue: 0,0:23:35.00,0:23:36.67,EN,,0,0,0,,OKay? Let's start. Dialogue: 0,0:23:36.67,0:23:37.34,EN,,0,0,0,,The primitives. Dialogue: 0,0:23:37.77,0:23:39.44,EN,,0,0,0,,Well, there's really only one primitive, Dialogue: 0,0:23:40.96,0:23:43.20,EN,,0,0,0,,and the primitive in this language is called a query. Dialogue: 0,0:23:44.14,0:23:45.74,EN,,0,0,0,,A primitive query. Dialogue: 0,0:23:46.81,0:23:48.25,EN,,0,0,0,,Let's look at some primitive queries. Dialogue: 0,0:23:51.82,0:23:53.02,EN,,0,0,0,,Alright. Job x. Dialogue: 0,0:23:53.10,0:23:54.81,EN,,0,0,0,,Who is a computer programmer? Dialogue: 0,0:23:55.55,0:23:59.88,EN,,0,0,0,,Or find every fact in the database Dialogue: 0,0:24:01.55,0:24:06.14,EN,,0,0,0,,that matches job of the x is computer programmer. Dialogue: 0,0:24:06.64,0:24:08.01,EN,,0,0,0,,And you see a little syntax here. Dialogue: 0,0:24:08.47,0:24:10.59,EN,,0,0,0,,Things without question marks are meant to be literal, Dialogue: 0,0:24:11.28,0:24:13.15,EN,,0,0,0,,question mark x means that's a variable, Dialogue: 0,0:24:13.31,0:24:15.56,EN,,0,0,0,,and this thing will match, for example, Dialogue: 0,0:24:16.03,0:24:19.00,EN,,0,0,0,,the fact that Alyssa P. Hacker is a computer programmer, Dialogue: 0,0:24:19.28,0:24:21.93,EN,,0,0,0,,or x is Alyssa P. Hacker. Dialogue: 0,0:24:26.82,0:24:29.98,EN,,0,0,0,,Or more generally, I could have something with two variables in it. Dialogue: 0,0:24:30.75,0:24:31.45,EN,,0,0,0,,I could say, Dialogue: 0,0:24:31.60,0:24:35.88,EN,,0,0,0,,the job of x is computer something, Dialogue: 0,0:24:39.34,0:24:41.39,EN,,0,0,0,,and that'll match computer wizard. Dialogue: 0,0:24:42.14,0:24:44.28,EN,,0,0,0,,So there's something here: type will match wizard, Dialogue: 0,0:24:44.92,0:24:46.46,EN,,0,0,0,,or type will match programmer, Dialogue: 0,0:24:47.48,0:24:50.37,EN,,0,0,0,,or x might match various certain things. Dialogue: 0,0:24:50.37,0:24:52.24,EN,,0,0,0,,So there are, in our little example, Dialogue: 0,0:24:52.25,0:24:55.15,EN,,0,0,0,,only three facts in that database that match that query. Dialogue: 0,0:24:59.12,0:25:02.08,EN,,0,0,0,,Let's see, just to show you some syntax, the same query, Dialogue: 0,0:25:05.29,0:25:08.09,EN,,0,0,0,,this query doesn't match the job of x, Dialogue: 0,0:25:09.85,0:25:11.79,EN,,0,0,0,,doesn't match Lewis Reasoner, Dialogue: 0,0:25:11.84,0:25:13.64,EN,,0,0,0,,the reason for that is when I write something here, Dialogue: 0,0:25:14.22,0:25:17.74,EN,,0,0,0,,what I mean is that this is going to be a list of two symbols, Dialogue: 0,0:25:19.96,0:25:21.96,EN,,0,0,0,,of which the first is the word computer, Dialogue: 0,0:25:22.32,0:25:23.80,EN,,0,0,0,,and the second can be anything. Dialogue: 0,0:25:25.08,0:25:27.32,EN,,0,0,0,,And Lewis's job description here has three symbols, Dialogue: 0,0:25:27.80,0:25:28.83,EN,,0,0,0,,so it doesn't match. Dialogue: 0,0:25:30.34,0:25:32.19,EN,,0,0,0,,And just to show you a little bit of syntax, Dialogue: 0,0:25:35.04,0:25:38.32,EN,,0,0,0,,the more general thing I might want to type is a thing with a dot here, Dialogue: 0,0:25:40.17,0:25:42.92,EN,,0,0,0,,and this is just standard list notation for saying, Dialogue: 0,0:25:43.04,0:25:43.82,EN,,0,0,0,,this is a list, Dialogue: 0,0:25:44.12,0:25:47.32,EN,,0,0,0,,of which the first element is the word computers, Dialogue: 0,0:25:47.58,0:25:50.22,EN,,0,0,0,,and THE REST, is something that I'll call type. Dialogue: 0,0:25:53.73,0:25:55.50,EN,,0,0,0,,So this one would match. Dialogue: 0,0:25:56.93,0:25:59.31,EN,,0,0,0,,Lewis's job is computer programmer trainee, Dialogue: 0,0:25:59.44,0:26:03.29,EN,,0,0,0,,and type here would be the cdr of this list. Dialogue: 0,0:26:03.32,0:26:05.64,EN,,0,0,0,,It would be the list programmer trainee. Dialogue: 0,0:26:06.96,0:26:10.46,EN,,0,0,0,,And that kind of dot processing is done automatically by the LISP reader. Dialogue: 0,0:26:15.90,0:26:17.76,EN,,0,0,0,,Well, let's actually try this. Dialogue: 0,0:26:17.76,0:26:20.51,EN,,0,0,0,,The idea is I'm going to type in queries in this language, Dialogue: 0,0:26:20.76,0:26:21.82,EN,,0,0,0,,and answers will come out. Dialogue: 0,0:26:22.54,0:26:24.48,EN,,0,0,0,,Let's look at this. Dialogue: 0,0:26:25.18,0:26:26.51,EN,,0,0,0,,I can go up and say, Dialogue: 0,0:26:27.34,0:26:28.88,EN,,0,0,0,,who works in the computer division? Dialogue: 0,0:26:30.00,0:26:38.22,EN,,0,0,0,,Job of x is computer dot y. Dialogue: 0,0:26:39.73,0:26:41.48,EN,,0,0,0,,Doesn't matter what I call the dummy variables. Dialogue: 0,0:26:42.76,0:26:44.14,EN,,0,0,0,,It says the answers to that, Dialogue: 0,0:26:44.41,0:26:45.68,EN,,0,0,0,,and it's found four answers. Dialogue: 0,0:26:48.65,0:26:50.09,EN,,0,0,0,,Or I can go off and say, Dialogue: 0,0:26:50.56,0:26:52.38,EN,,0,0,0,,tell me about everybody's supervisor. Dialogue: 0,0:26:52.81,0:26:54.88,EN,,0,0,0,,So I'll put in the query, the primitive query, Dialogue: 0,0:26:56.52,0:26:59.39,EN,,0,0,0,,the supervisor of x is y. Dialogue: 0,0:27:02.56,0:27:05.42,EN,,0,0,0,,There are all the supervisor relationships I know. Dialogue: 0,0:27:05.54,0:27:08.83,EN,,0,0,0,,Or I could go type in, who lives in Cambridge? Dialogue: 0,0:27:08.83,0:27:09.47,EN,,0,0,0,,So I can say, Dialogue: 0,0:27:10.24,0:27:20.92,EN,,0,0,0,,the address of x is Cambridge dot anything. Dialogue: 0,0:27:25.09,0:27:26.89,EN,,0,0,0,,And only one person lives in Cambridge. Dialogue: 0,0:27:30.82,0:27:32.17,EN,,0,0,0,,OK, so those are primitive queries. Dialogue: 0,0:27:32.17,0:27:34.96,EN,,0,0,0,,And you see what happens to basic interaction with the system Dialogue: 0,0:27:35.29,0:27:39.24,EN,,0,0,0,,is you type in a query, and it types out all possible answers. Dialogue: 0,0:27:39.62,0:27:40.65,EN,,0,0,0,,Or another way to say that: Dialogue: 0,0:27:40.67,0:27:44.16,EN,,0,0,0,,it finds out all the possible values of those variables Dialogue: 0,0:27:44.19,0:27:45.87,EN,,0,0,0,,x and y or t or whatever I've called them, Dialogue: 0,0:27:46.09,0:27:52.08,EN,,0,0,0,,and it types out all ways of taking that query and instantiating it-- Dialogue: 0,0:27:52.92,0:27:55.16,EN,,0,0,0,,remember that from the rule system lecture-- Dialogue: 0,0:27:55.16,0:27:58.83,EN,,0,0,0,,instantiates the query with all possible values for those variables Dialogue: 0,0:27:59.00,0:28:00.35,EN,,0,0,0,,and then types out all of them. Dialogue: 0,0:28:01.00,0:28:03.35,EN,,0,0,0,,And there are a lot of ways you can arrange a logic language. Dialogue: 0,0:28:03.35,0:28:06.01,EN,,0,0,0,,Prolog, for instance, does something slightly different. Dialogue: 0,0:28:06.01,0:28:07.44,EN,,0,0,0,,Rather than typing back your query, Dialogue: 0,0:28:07.76,0:28:10.78,EN,,0,0,0,,prolog would type out, x equals this and y equals that, Dialogue: 0,0:28:10.97,0:28:12.94,EN,,0,0,0,,or x equals this and y equals that. Dialogue: 0,0:28:13.66,0:28:15.48,EN,,0,0,0,,And that's a very surface level thing, Dialogue: 0,0:28:15.71,0:28:17.05,EN,,0,0,0,,you can decide what you like. Dialogue: 0,0:28:18.97,0:28:19.58,EN,,0,0,0,,OK. Dialogue: 0,0:28:21.00,0:28:22.68,EN,,0,0,0,,Alright. So the primitives in this language? Dialogue: 0,0:28:23.39,0:28:24.57,EN,,0,0,0,,Only one, right? Dialogue: 0,0:28:24.57,0:28:27.23,EN,,0,0,0,,Primitive query. Dialogue: 0,0:28:31.31,0:28:32.56,EN,,0,0,0,,Means of combination. Dialogue: 0,0:28:34.33,0:28:37.68,EN,,0,0,0,,Let's look at some compound queries in this language. Dialogue: 0,0:28:39.77,0:28:40.46,EN,,0,0,0,,Here's one. Dialogue: 0,0:28:41.79,0:28:42.51,EN,,0,0,0,,This one says, Dialogue: 0,0:28:45.05,0:28:48.22,EN,,0,0,0,,tell me all the people who work in the computer division. Dialogue: 0,0:28:49.81,0:28:52.00,EN,,0,0,0,,Tell me all the people who work in the computer division Dialogue: 0,0:28:52.54,0:28:53.96,EN,,0,0,0,,together with their supervisors. Dialogue: 0,0:28:56.80,0:28:58.83,EN,,0,0,0,,Where I write that is the query is and. Dialogue: 0,0:29:00.22,0:29:04.06,EN,,0,0,0,,And the job of the x is computer something or other. Dialogue: 0,0:29:04.92,0:29:06.83,EN,,0,0,0,,And job of x is computer dot y. Dialogue: 0,0:29:07.56,0:29:10.03,EN,,0,0,0,,And the supervisor of x is z. Dialogue: 0,0:29:11.44,0:29:14.16,EN,,0,0,0,,Tell me all the people in the computer division-- that's this-- Dialogue: 0,0:29:14.30,0:29:15.88,EN,,0,0,0,,together with their supervisors. Dialogue: 0,0:29:16.46,0:29:17.82,EN,,0,0,0,,And notice in this query Dialogue: 0,0:29:18.67,0:29:22.41,EN,,0,0,0,,I have three variables-- x, y, and z. Dialogue: 0,0:29:23.58,0:29:28.65,EN,,0,0,0,,And this x is supposed to be the same as that x. Dialogue: 0,0:29:29.45,0:29:31.16,EN,,0,0,0,,So x works in the computer division, Dialogue: 0,0:29:31.31,0:29:33.00,EN,,0,0,0,,and the supervisor of x is z. Dialogue: 0,0:29:34.81,0:29:35.80,EN,,0,0,0,,Let's try another one. Dialogue: 0,0:29:37.25,0:29:39.28,EN,,0,0,0,,So one means of combination is and. Dialogue: 0,0:29:41.44,0:29:43.96,EN,,0,0,0,,Who are all the people who make more than $30,000? Dialogue: 0,0:29:45.71,0:29:51.71,EN,,0,0,0,,And the salary of some person p is some amount a. Dialogue: 0,0:29:54.59,0:29:57.45,EN,,0,0,0,,And when I go and look at a, Dialogue: 0,0:29:57.48,0:30:00.12,EN,,0,0,0,,a is greater than $30,000. Dialogue: 0,0:30:00.60,0:30:03.23,EN,,0,0,0,,And LISP value here is a little piece of interface Dialogue: 0,0:30:04.30,0:30:10.04,EN,,0,0,0,,that interfaces the query language to the underlying LISP. Dialogue: 0,0:30:10.60,0:30:12.72,EN,,0,0,0,,And what the LISP value allows you to do Dialogue: 0,0:30:12.75,0:30:16.91,EN,,0,0,0,,call any LISP predicate inside a query. Dialogue: 0,0:30:17.18,0:30:20.11,EN,,0,0,0,,So here I'm using the LISP predicate greater than, so I say LISP value. Dialogue: 0,0:30:21.02,0:30:21.75,EN,,0,0,0,,This I say and. Dialogue: 0,0:30:21.75,0:30:24.48,EN,,0,0,0,,So all the people whose salary is greater than $30,000. Dialogue: 0,0:30:28.19,0:30:30.03,EN,,0,0,0,,Or here's a more complicated one. Dialogue: 0,0:30:31.27,0:30:35.02,EN,,0,0,0,,Tell me all the people who work in the computer division Dialogue: 0,0:30:36.25,0:30:39.36,EN,,0,0,0,,who do not have a supervisor who works in the computer division. Dialogue: 0,0:30:42.79,0:30:45.51,EN,,0,0,0,,and x works in the computer division. Dialogue: 0,0:30:45.51,0:30:47.32,EN,,0,0,0,,The job of x is computer dot y. Dialogue: 0,0:30:47.78,0:30:49.24,EN,,0,0,0,,And it's not the case Dialogue: 0,0:30:50.49,0:30:54.25,EN,,0,0,0,,that both x has a supervisor z Dialogue: 0,0:30:55.37,0:30:57.87,EN,,0,0,0,,and the job of z is computer something or other. Dialogue: 0,0:30:59.62,0:31:00.35,EN,,0,0,0,,All right, so again, Dialogue: 0,0:31:00.51,0:31:02.38,EN,,0,0,0,,this x has got to be that x, Dialogue: 0,0:31:03.20,0:31:05.76,EN,,0,0,0,,and this z is going to be that z. Dialogue: 0,0:31:09.39,0:31:11.38,EN,,0,0,0,,And then you see another means a combination, not. Dialogue: 0,0:31:17.71,0:31:18.67,EN,,0,0,0,,All right, well, let's look at that. Dialogue: 0,0:31:20.88,0:31:22.08,EN,,0,0,0,,It works the same way. Dialogue: 0,0:31:22.40,0:31:24.12,EN,,0,0,0,,I can go up to the machine and say Dialogue: 0,0:31:26.89,0:31:35.40,EN,,0,0,0,,and the job of the x is computer dot y. Dialogue: 0,0:31:38.84,0:31:45.95,EN,,0,0,0,,And the supervisor of x is z. Dialogue: 0,0:31:46.83,0:31:49.53,EN,,0,0,0,,And I typed that in like a query. Dialogue: 0,0:31:51.07,0:31:52.97,EN,,0,0,0,,And what it types back, Dialogue: 0,0:31:54.00,0:31:58.73,EN,,0,0,0,,what you see are the queries I typed in instantiated by all possible answers. Dialogue: 0,0:31:58.93,0:32:00.08,EN,,0,0,0,,And then you see there are a lot of answers. Dialogue: 0,0:32:01.69,0:32:02.14,EN,,0,0,0,,All right. Dialogue: 0,0:32:02.19,0:32:04.04,EN,,0,0,0,,So the means of combination in this language-- Dialogue: 0,0:32:05.21,0:32:06.60,EN,,0,0,0,,and this is why it's called a logic language-- Dialogue: 0,0:32:06.64,0:32:09.47,EN,,0,0,0,,are logical operations. Dialogue: 0,0:32:09.80,0:32:15.68,EN,,0,0,0,,Means of combinations are things like AND and NOT Dialogue: 0,0:32:15.96,0:32:17.92,EN,,0,0,0,,and there's one I didn't show you, which is OR. Dialogue: 0,0:32:18.49,0:32:20.36,EN,,0,0,0,,And then I showed you LISP value, Dialogue: 0,0:32:20.72,0:32:24.48,EN,,0,0,0,,which is a, not logic, of course, Dialogue: 0,0:32:24.51,0:32:26.89,EN,,0,0,0,,but is a little special hack to interface that to LISP Dialogue: 0,0:32:27.34,0:32:28.75,EN,,0,0,0,,so you can get more power. Dialogue: 0,0:32:29.25,0:32:30.67,EN,,0,0,0,,Those are the means of combination. Dialogue: 0,0:32:32.59,0:32:33.98,EN,,0,0,0,,OK, the means of abstraction. Dialogue: 0,0:32:34.16,0:32:35.21,EN,,0,0,0,,What we'd like to do-- Dialogue: 0,0:32:38.27,0:32:41.24,EN,,0,0,0,,let's go back for second and look at that last slide. Dialogue: 0,0:32:42.26,0:32:44.25,EN,,0,0,0,,We might like to take very complicated thing, Dialogue: 0,0:32:44.46,0:32:48.00,EN,,0,0,0,,the idea that someone works in a division Dialogue: 0,0:32:48.01,0:32:50.09,EN,,0,0,0,,but does not have a supervisor in the division. Dialogue: 0,0:32:52.40,0:32:55.10,EN,,0,0,0,,And as before, name that. Dialogue: 0,0:32:56.09,0:32:58.12,EN,,0,0,0,,Well, if someone works in a division Dialogue: 0,0:32:58.17,0:33:00.25,EN,,0,0,0,,and does not have a supervisor who works in that division, Dialogue: 0,0:33:00.48,0:33:01.93,EN,,0,0,0,,that means that person is a big shot. Dialogue: 0,0:33:02.75,0:33:05.13,EN,,0,0,0,,So let's make a rule that Dialogue: 0,0:33:06.43,0:33:09.16,EN,,0,0,0,,somebody x is a big shot in some department Dialogue: 0,0:33:10.91,0:33:14.68,EN,,0,0,0,,if x works in the department Dialogue: 0,0:33:16.04,0:33:20.08,EN,,0,0,0,,and it's not the case that x has a supervisor who works in the department. Dialogue: 0,0:33:21.51,0:33:22.94,EN,,0,0,0,,So this is our means of abstraction. Dialogue: 0,0:33:22.94,0:33:23.90,EN,,0,0,0,,This is a rule. Dialogue: 0,0:33:26.22,0:33:27.58,EN,,0,0,0,,And a rule has three parts. Dialogue: 0,0:33:31.00,0:33:32.48,EN,,0,0,0,,The thing that says it's a rule. Dialogue: 0,0:33:33.40,0:33:35.48,EN,,0,0,0,,And then there's the conclusion of the rule. Dialogue: 0,0:33:37.53,0:33:39.07,EN,,0,0,0,,And then there's the body of the rule. Dialogue: 0,0:33:40.00,0:33:41.88,EN,,0,0,0,,And you can read this as a piece of logic which says, Dialogue: 0,0:33:41.92,0:33:45.15,EN,,0,0,0,,if you know that the body of the rule is true, Dialogue: 0,0:33:46.40,0:33:48.72,EN,,0,0,0,,then you can conclude that the conclusion is true. Dialogue: 0,0:33:49.45,0:33:53.28,EN,,0,0,0,,Or in order to deduce that x is a big shot in some department, Dialogue: 0,0:33:53.79,0:33:55.71,EN,,0,0,0,,it's enough to verify that. Dialogue: 0,0:33:57.48,0:33:58.82,EN,,0,0,0,,So that's what rules look like. Dialogue: 0,0:34:03.28,0:34:06.16,EN,,0,0,0,,Let's go back and look at that merge example Dialogue: 0,0:34:06.73,0:34:07.92,EN,,0,0,0,,that I did before the break. Dialogue: 0,0:34:08.11,0:34:10.68,EN,,0,0,0,,Let's look at how that would look in terms of rules. Dialogue: 0,0:34:11.44,0:34:12.84,EN,,0,0,0,,I'm going to take the logic I put up Dialogue: 0,0:34:13.08,0:34:15.50,EN,,0,0,0,,and just change it into a bunch of rules in this format. Dialogue: 0,0:34:18.73,0:34:19.35,EN,,0,0,0,,We have a rule. Dialogue: 0,0:34:19.35,0:34:20.96,EN,,0,0,0,,Remember, there was this thing merge-to-form. Dialogue: 0,0:34:21.71,0:34:22.97,EN,,0,0,0,,There is a rule that says, Dialogue: 0,0:34:26.28,0:34:29.62,EN,,0,0,0,,the empty list and y merge to form y. Dialogue: 0,0:34:29.62,0:34:30.87,EN,,0,0,0,,This is the rule conclusion. Dialogue: 0,0:34:33.21,0:34:35.74,EN,,0,0,0,,And notice this particular rule has no body. Dialogue: 0,0:34:36.65,0:34:37.66,EN,,0,0,0,,And in this language, Dialogue: 0,0:34:38.11,0:34:40.86,EN,,0,0,0,,a rule with no body is something that is always true. Dialogue: 0,0:34:41.23,0:34:42.51,EN,,0,0,0,,You can always assume that's true. Dialogue: 0,0:34:45.19,0:34:46.49,EN,,0,0,0,,And there was another piece of logic Dialogue: 0,0:34:46.64,0:34:49.46,EN,,0,0,0,,that said anything in the empty list merged to form the anything. Dialogue: 0,0:34:49.46,0:34:50.12,EN,,0,0,0,,That's this. Dialogue: 0,0:34:50.90,0:34:53.55,EN,,0,0,0,,A rule y and the empty list merge to form y. Dialogue: 0,0:34:55.51,0:34:58.40,EN,,0,0,0,,Those corresponded to the two end cases in our merge procedure, Dialogue: 0,0:34:58.44,0:34:59.77,EN,,0,0,0,,but now we're talking about logic, Dialogue: 0,0:35:00.41,0:35:01.45,EN,,0,0,0,,not about procedures. Dialogue: 0,0:35:03.49,0:35:04.48,EN,,0,0,0,,Then we had another rule, Dialogue: 0,0:35:04.83,0:35:08.73,EN,,0,0,0,,which said if you know how shorter things merge, Dialogue: 0,0:35:08.91,0:35:09.83,EN,,0,0,0,,you can put them together. Dialogue: 0,0:35:09.83,0:35:14.16,EN,,0,0,0,,So this says, if you have a list x and y and z, Dialogue: 0,0:35:14.92,0:35:17.61,EN,,0,0,0,,and if you want to deduce that a dot x-- Dialogue: 0,0:35:17.63,0:35:19.08,EN,,0,0,0,,this means cons a onto x, Dialogue: 0,0:35:19.48,0:35:22.36,EN,,0,0,0,,or a list whose first thing is a and whose rest is x-- Dialogue: 0,0:35:23.16,0:35:27.40,EN,,0,0,0,,so if you want to deduce that a dot x and b dot y merge to form b dot z-- Dialogue: 0,0:35:30.36,0:35:33.90,EN,,0,0,0,,that would say you merge these two lists a x and b y Dialogue: 0,0:35:33.92,0:35:35.85,EN,,0,0,0,,and you're going to get something that starts with b-- Dialogue: 0,0:35:36.76,0:35:40.67,EN,,0,0,0,,you can deduce that if you know that it's the case Dialogue: 0,0:35:40.91,0:35:44.48,EN,,0,0,0,,both that a dot x and y merge to form z Dialogue: 0,0:35:45.18,0:35:47.24,EN,,0,0,0,,and a is larger than b. Dialogue: 0,0:35:48.69,0:35:50.59,EN,,0,0,0,,So when I merge them, b will come first in the list. Dialogue: 0,0:35:51.82,0:35:54.91,EN,,0,0,0,,That's a little translation of the logic rule Dialogue: 0,0:35:55.24,0:35:57.18,EN,,0,0,0,,that I wrote in pseudo-English before. Dialogue: 0,0:35:57.96,0:36:01.63,EN,,0,0,0,,And then just for completeness, here's the other case. Dialogue: 0,0:36:02.88,0:36:05.95,EN,,0,0,0,,a dot x and b dot y merge to form a dot z Dialogue: 0,0:36:06.08,0:36:09.16,EN,,0,0,0,,if x and b dot y merged to form z and b is larger than a. Dialogue: 0,0:36:09.47,0:36:11.00,EN,,0,0,0,,and b is larger than a. Dialogue: 0,0:36:12.19,0:36:15.98,EN,,0,0,0,,So that's a little program that I've typed in in this language, Dialogue: 0,0:36:16.01,0:36:17.07,EN,,0,0,0,,and now let's look at it run. Dialogue: 0,0:36:21.90,0:36:23.90,EN,,0,0,0,,So I typed in the merge rules before, Dialogue: 0,0:36:24.62,0:36:25.77,EN,,0,0,0,,and I could say, ahh Dialogue: 0,0:36:27.04,0:36:28.51,EN,,0,0,0,,I could use this like a procedure. Dialogue: 0,0:36:28.51,0:36:38.24,EN,,0,0,0,,I could say merge to form 1 and 3 and 2 and 7. Dialogue: 0,0:36:39.42,0:36:41.55,EN,,0,0,0,,So here I'm using it like the LISP procedure. Dialogue: 0,0:36:43.16,0:36:44.97,EN,,0,0,0,,Now it's going to think about that for a while Dialogue: 0,0:36:46.43,0:36:47.56,EN,,0,0,0,,and apply these rules. Dialogue: 0,0:36:50.78,0:36:51.92,EN,,0,0,0,,So it found an answer. Dialogue: 0,0:36:52.80,0:36:54.54,EN,,0,0,0,,Now it's going to see if there are any other answers Dialogue: 0,0:36:55.07,0:36:57.32,EN,,0,0,0,,it doesn't know a priori there's only one answer. Dialogue: 0,0:36:57.81,0:36:59.90,EN,,0,0,0,,So it's sitting here checking all possibilities, Dialogue: 0,0:37:00.41,0:37:02.54,EN,,0,0,0,,and it says, no more. Done. Dialogue: 0,0:37:03.16,0:37:05.07,EN,,0,0,0,,So there I've used those rules like a procedure. Dialogue: 0,0:37:05.21,0:37:09.05,EN,,0,0,0,,Or remember the whole point is that I can ask different kinds of questions. Dialogue: 0,0:37:10.22,0:37:11.07,EN,,0,0,0,,I could say Dialogue: 0,0:37:18.56,0:37:24.59,EN,,0,0,0,,merge to form, let's see, how about 2 and a. Dialogue: 0,0:37:24.59,0:37:27.90,EN,,0,0,0,,Some list of two elements which I know starts with 2, Dialogue: 0,0:37:29.37,0:37:31.26,EN,,0,0,0,,and the other thing I don't know, Dialogue: 0,0:37:33.05,0:37:35.04,EN,,0,0,0,,and x and some other list Dialogue: 0,0:37:36.48,0:37:39.51,EN,,0,0,0,,merge to form a 1, 2, 3 and 4. Dialogue: 0,0:37:42.76,0:37:44.11,EN,,0,0,0,,So now it's going to think about that. Dialogue: 0,0:37:44.59,0:37:49.40,EN,,0,0,0,,It's got to find-- so it found one possibility. Dialogue: 0,0:37:49.52,0:37:52.46,EN,,0,0,0,,It said a could be 3, and x could be the list 1, 4. Dialogue: 0,0:37:53.72,0:37:55.16,EN,,0,0,0,,And now, again, it's got to check Dialogue: 0,0:37:56.56,0:37:57.71,EN,,0,0,0,,because it doesn't a priori know Dialogue: 0,0:37:57.74,0:38:00.30,EN,,0,0,0,,that there aren't any other possibilities going on. Dialogue: 0,0:38:03.68,0:38:06.57,EN,,0,0,0,,Or like I said, Dialogue: 0,0:38:07.00,0:38:09.84,EN,,0,0,0,,I could say something like merge to form, Dialogue: 0,0:38:10.54,0:38:17.55,EN,,0,0,0,,like, what and what else merge to form 1, 2, 3, 4, 5? Dialogue: 0,0:38:23.68,0:38:25.53,EN,,0,0,0,,Now it's going to think about that. Dialogue: 0,0:38:28.49,0:38:30.31,EN,,0,0,0,,And there are a lot of answers that it might get. Dialogue: 0,0:38:35.18,0:38:38.57,EN,,0,0,0,,And what you see is here you're really paying the price of slowness. Dialogue: 0,0:38:42.21,0:38:43.88,EN,,0,0,0,,And kind of for three reasons. Dialogue: 0,0:38:43.88,0:38:46.22,EN,,0,0,0,,One is that this language is doubly interpreted. Dialogue: 0,0:38:47.63,0:38:49.72,EN,,0,0,0,,Whereas in a real implementation, Dialogue: 0,0:38:49.76,0:38:52.04,EN,,0,0,0,,you would go compile this down to primitive operations. Dialogue: 0,0:38:52.19,0:38:53.87,EN,,0,0,0,,The other reason is that Dialogue: 0,0:38:53.88,0:38:58.11,EN,,0,0,0,,this particular algorithm for merges is doubly recursive. Dialogue: 0,0:38:58.38,0:39:00.06,EN,,0,0,0,,So it's going to take a very long time. Dialogue: 0,0:39:01.02,0:39:04.33,EN,,0,0,0,,And eventually, this is going to go through Dialogue: 0,0:39:04.59,0:39:07.13,EN,,0,0,0,,and find-- find what? Dialogue: 0,0:39:07.13,0:39:08.73,EN,,0,0,0,,Two to the fifth possible answers. Dialogue: 0,0:39:12.14,0:39:14.96,EN,,0,0,0,,And you see they come out in some fairly arbitrary order, Dialogue: 0,0:39:15.00,0:39:18.14,EN,,0,0,0,,depending on which order it's going to be trying these rules. Dialogue: 0,0:39:20.16,0:39:22.11,EN,,0,0,0,,In fact, what we're going to do when they edit the videotape Dialogue: 0,0:39:22.40,0:39:23.48,EN,,0,0,0,,is speed all this up. Dialogue: 0,0:39:24.08,0:39:26.60,EN,,0,0,0,,Don't you like taking out these waits? Dialogue: 0,0:39:26.60,0:39:28.27,EN,,0,0,0,,And don't you wish you could do that in your demos? Dialogue: 0,0:39:29.48,0:39:34.24,EN,,0,0,0,,Anyway, it's still grinding there. Dialogue: 0,0:39:39.22,0:39:41.12,EN,,0,0,0,,Anyway, there are 32 possibilities-- Dialogue: 0,0:39:41.13,0:39:42.63,EN,,0,0,0,,we won't wait for it to print out all of them. Dialogue: 0,0:39:47.85,0:39:50.44,EN,,0,0,0,,OK, so the needs of abstraction in this language are rules. Dialogue: 0,0:39:53.53,0:39:58.01,EN,,0,0,0,,So we take some bunch of things that are put together with logic Dialogue: 0,0:39:59.12,0:40:00.08,EN,,0,0,0,,and we name them. Dialogue: 0,0:40:00.35,0:40:03.41,EN,,0,0,0,,And you can think of that as naming a particular pattern of logic. Dialogue: 0,0:40:03.41,0:40:04.54,EN,,0,0,0,,Or you can think of that as saying, Dialogue: 0,0:40:04.56,0:40:06.75,EN,,0,0,0,,if you want to deduce some conclusion, Dialogue: 0,0:40:07.90,0:40:09.52,EN,,0,0,0,,you can apply those rules of logic. Dialogue: 0,0:40:10.66,0:40:13.20,EN,,0,0,0,,And those are three elements of this language. Dialogue: 0,0:40:13.42,0:40:14.56,EN,,0,0,0,,Let's break now, Dialogue: 0,0:40:14.60,0:40:16.59,EN,,0,0,0,,and then we'll talk about how it's actually implemented. Dialogue: 0,0:40:23.61,0:40:28.84,EN,,0,0,0,,AUDIENCE: Does using LISP value primitive or whatever interfere with your means Dialogue: 0,0:40:29.15,0:40:30.64,EN,,0,0,0,,both directions on a query? Dialogue: 0,0:40:31.77,0:40:34.48,EN,,0,0,0,,PROFESSOR: OK, that's a-- the question is, Dialogue: 0,0:40:35.08,0:40:36.92,EN,,0,0,0,,does using LISP value interfere Dialogue: 0,0:40:37.53,0:40:40.09,EN,,0,0,0,,with the ability to go both directions on the query? Dialogue: 0,0:40:40.09,0:40:42.81,EN,,0,0,0,,We haven't really talked about the implementation yet, Dialogue: 0,0:40:43.68,0:40:45.52,EN,,0,0,0,,but the answer is, yes, it can. Dialogue: 0,0:40:46.89,0:40:50.20,EN,,0,0,0,,In general, as we'll see at the end-- Dialogue: 0,0:40:50.22,0:40:52.17,EN,,0,0,0,,although I really won't to go into details-- Dialogue: 0,0:40:53.21,0:40:59.36,EN,,0,0,0,,it's fairly complicated, especially when you use either not or LISP value-- Dialogue: 0,0:40:59.55,0:41:02.89,EN,,0,0,0,,or actually, if you use anything besides only and, Dialogue: 0,0:41:04.12,0:41:08.19,EN,,0,0,0,,it becomes very complicated to say when these things will work. Dialogue: 0,0:41:08.20,0:41:10.36,EN,,0,0,0,,They won't work quite in all situations. Dialogue: 0,0:41:10.36,0:41:13.39,EN,,0,0,0,,I'll talk about that at the end of the second half today. Dialogue: 0,0:41:14.30,0:41:15.84,EN,,0,0,0,,But the answer to your question is, yes, Dialogue: 0,0:41:16.19,0:41:19.21,EN,,0,0,0,,by dragging in a lot more power from LISP value, Dialogue: 0,0:41:19.40,0:41:23.77,EN,,0,0,0,,you lose some of the principal power of logic programming. Dialogue: 0,0:41:24.17,0:41:25.56,EN,,0,0,0,,That's a trade-off that you have to make. Dialogue: 0,0:41:28.48,0:41:29.39,EN,,0,0,0,,OK, let's take a break. Dialogue: 0,0:00:00.00,0:00:02.67,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:02.70,0:00:10.27,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:02.70,0:00:10.27,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.70,0:00:10.27,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.70,0:00:10.27,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.70,0:00:10.27,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:10.28,0:00:15.24,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 I Dialogue: 0,0:00:18.27,0:00:19.68,Default,,0,0,0,,教授:上节课中 我们学习了 Dialogue: 0,0:00:19.72,0:00:21.26,Default,,0,0,0,,如何构造语言 Dialogue: 0,0:00:22.41,0:00:25.88,Default,,0,0,0,,核心点就是 像Lisp这样的求值器 Dialogue: 0,0:00:26.08,0:00:27.58,Default,,0,0,0,,有两个主要部分 Dialogue: 0,0:00:27.58,0:00:28.40,Default,,0,0,0,,一个是EVAL Dialogue: 0,0:00:31.04,0:00:37.42,Default,,0,0,0,,EVAL接受一个表达式EXP和环境ENV Dialogue: 0,0:00:38.91,0:00:44.44,Default,,0,0,0,,然后返回一个过程和相关的实际参数 Dialogue: 0,0:00:45.42,0:00:47.05,Default,,0,0,0,,并把它们传递给APPLY Dialogue: 0,0:00:49.41,0:00:51.29,Default,,0,0,0,,APPLY接收这些过程和实际参数 Dialogue: 0,0:00:51.69,0:00:55.12,Default,,0,0,0,,通常来说 APPLY会返回另一个表达式 Dialogue: 0,0:00:55.39,0:00:57.71,Default,,0,0,0,,返回一个在其它环境中求值的表达式 Dialogue: 0,0:00:57.74,0:01:00.00,Default,,0,0,0,,表达式就像这样在EVAL-APPLY之间传递 Dialogue: 0,0:01:00.27,0:01:01.44,Default,,0,0,0,,这就是整个元循环 Dialogue: 0,0:01:01.47,0:01:02.94,Default,,0,0,0,,表达式在这里面循环往复 Dialogue: 0,0:01:03.02,0:01:06.56,Default,,0,0,0,,直到最后求值为基本数据或基本过程 Dialogue: 0,0:01:07.74,0:01:09.24,Default,,0,0,0,,这个循环要做的就是 Dialogue: 0,0:01:09.44,0:01:12.57,Default,,0,0,0,,把语言中的组合手段 Dialogue: 0,0:01:12.59,0:01:14.36,Default,,0,0,0,,和抽象手段展开 Dialogue: 0,0:01:15.02,0:01:17.72,Default,,0,0,0,,比如说在Lisp中 你有一个过程 Dialogue: 0,0:01:17.74,0:01:20.52,Default,,0,0,0,,定义过程是为了 Dialogue: 0,0:01:20.54,0:01:22.57,Default,,0,0,0,,让表达式的计算过程 Dialogue: 0,0:01:22.67,0:01:24.41,Default,,0,0,0,,适用于任意的参数 Dialogue: 0,0:01:25.76,0:01:27.18,Default,,0,0,0,,这就是这里面发生的事情 Dialogue: 0,0:01:27.67,0:01:28.51,Default,,0,0,0,,这就是APPLY做的事 Dialogue: 0,0:01:28.51,0:01:30.68,Default,,0,0,0,,当一个带参数的一般性表达式进入以后 Dialogue: 0,0:01:30.72,0:01:32.70,Default,,0,0,0,,它将其归约为过程体的表达式 Dialogue: 0,0:01:33.05,0:01:34.72,Default,,0,0,0,,如果归约得到的是复合表达式 Dialogue: 0,0:01:34.83,0:01:36.46,Default,,0,0,0,,或者是另外的过程应用 Dialogue: 0,0:01:36.78,0:01:38.44,Default,,0,0,0,,那么这个循环就会不断地进行 Dialogue: 0,0:01:40.33,0:01:44.08,Default,,0,0,0,,这基本上就是 -- 大部分解释器的基本结构了 Dialogue: 0,0:01:45.20,0:01:46.25,Default,,0,0,0,,另外一点就是 Dialogue: 0,0:01:46.28,0:01:47.66,Default,,0,0,0,,一旦你有了一个解释器 Dialogue: 0,0:01:47.69,0:01:49.87,Default,,0,0,0,,你就有了操作这门语言的所有能力 Dialogue: 0,0:01:49.87,0:01:51.52,Default,,0,0,0,,因此你可以让它成为动态作用域 Dialogue: 0,0:01:51.84,0:01:54.56,Default,,0,0,0,,你也可以引入正则序求值 Dialogue: 0,0:01:54.59,0:01:56.48,Default,,0,0,0,,你也可以为语言添加新的形式 Dialogue: 0,0:01:56.86,0:01:57.50,Default,,0,0,0,,想怎么样都行 Dialogue: 0,0:01:57.58,0:01:58.62,Default,,0,0,0,,或者更一般地说 Dialogue: 0,0:01:58.76,0:02:01.32,Default,,0,0,0,,这种元语言抽象的概念 Dialogue: 0,0:02:02.64,0:02:06.01,Default,,0,0,0,,它告诉我们 作为一名软件工程师 Dialogue: 0,0:02:07.61,0:02:10.52,Default,,0,0,0,,从广义的“工程师”的角度来看 Dialogue: 0,0:02:11.39,0:02:13.88,Default,,0,0,0,,有时你可以通过发明新的语言 Dialogue: 0,0:02:14.96,0:02:17.16,Default,,0,0,0,,来获得控制复杂度的能力 Dialogue: 0,0:02:18.01,0:02:20.81,Default,,0,0,0,,一种思考计算机程序设计的方法就是 Dialogue: 0,0:02:21.55,0:02:26.27,Default,,0,0,0,,它只是偶然地让计算机执行某事儿 Dialogue: 0,0:02:26.44,0:02:28.97,Default,,0,0,0,,计算机程序的主要工作却是 Dialogue: 0,0:02:29.00,0:02:32.52,Default,,0,0,0,,用来表达和交换想法 Dialogue: 0,0:02:33.16,0:02:34.04,Default,,0,0,0,,有时 Dialogue: 0,0:02:34.89,0:02:36.62,Default,,0,0,0,,当我们想要表达新的想法时 Dialogue: 0,0:02:36.65,0:02:38.73,Default,,0,0,0,,我们就想要发明新的模式来表达它们 Dialogue: 0,0:02:39.82,0:02:44.99,Default,,0,0,0,,那么 今天我们就将按照这个框架来创建新语言 Dialogue: 0,0:02:45.73,0:02:48.00,Default,,0,0,0,,一旦我们了解了解释器的基本结构 Dialogue: 0,0:02:48.03,0:02:50.27,Default,,0,0,0,,我们就可以按意愿来构造任意的语言 Dialogue: 0,0:02:50.83,0:02:53.21,Default,,0,0,0,,比如说 我们可以构造Pascal(的解释器) Dialogue: 0,0:02:54.37,0:02:55.15,Default,,0,0,0,,以及 Dialogue: 0,0:02:56.17,0:02:58.19,Default,,0,0,0,,我们需要操心语法的表示与解析 Dialogue: 0,0:02:58.19,0:03:00.51,Default,,0,0,0,,还有一大堆的编译器优化 Dialogue: 0,0:03:01.12,0:03:03.29,Default,,0,0,0,,还有一些人会这样做 Dialogue: 0,0:03:03.85,0:03:07.60,Default,,0,0,0,,但是就在我们所讨论的抽象层次来说 Dialogue: 0,0:03:08.04,0:03:10.99,Default,,0,0,0,,一个Pascal语言的解释器看起来 Dialogue: 0,0:03:12.03,0:03:13.76,Default,,0,0,0,,跟Gerry教授上节课所讲的大同小异 Dialogue: 0,0:03:15.02,0:03:18.96,Default,,0,0,0,,但是今天 我们要构建一门与众不同的语言 Dialogue: 0,0:03:20.51,0:03:22.81,Default,,0,0,0,,这门语言 Dialogue: 0,0:03:23.05,0:03:26.04,Default,,0,0,0,,不推荐你用过程式的思维来思考程序设计 Dialogue: 0,0:03:26.24,0:03:27.64,Default,,0,0,0,,而是用一种非常不同的方式 Dialogue: 0,0:03:29.09,0:03:31.02,Default,,0,0,0,,今天的课程呢 Dialogue: 0,0:03:31.74,0:03:34.64,Default,,0,0,0,,将会在两个层次中同时进行 Dialogue: 0,0:03:34.81,0:03:35.52,Default,,0,0,0,,一方面 Dialogue: 0,0:03:35.90,0:03:37.71,Default,,0,0,0,,我会向大家介绍这门语言是如何使用的 Dialogue: 0,0:03:38.96,0:03:41.08,Default,,0,0,0,,另一方面呢 我会带领大家实现这门语言 Dialogue: 0,0:03:41.32,0:03:42.96,Default,,0,0,0,,我们将会用Lisp来实现 Dialogue: 0,0:03:42.99,0:03:43.90,Default,,0,0,0,,并观察它的运行原理 Dialogue: 0,0:03:44.04,0:03:48.25,Default,,0,0,0,,你应该在两个层次上学到知识 Dialogue: 0,0:03:48.68,0:03:53.00,Default,,0,0,0,,首先要认识到 语言之间可以有多么地“不同” Dialogue: 0,0:03:53.79,0:03:58.14,Default,,0,0,0,,如果你认为Fortran和Lisp算是天差地别的话 Dialogue: 0,0:03:58.24,0:03:59.36,Default,,0,0,0,,那就小巫见大巫了 Dialogue: 0,0:04:01.56,0:04:03.68,Default,,0,0,0,,其次 Dialogue: 0,0:04:03.77,0:04:06.54,Default,,0,0,0,,甚至于在这门与众不同的语言中 Dialogue: 0,0:04:07.36,0:04:09.52,Default,,0,0,0,,这门既不讨论函数 Dialogue: 0,0:04:09.92,0:04:11.64,Default,,0,0,0,,也没有过程的语言中 Dialogue: 0,0:04:12.20,0:04:15.72,Default,,0,0,0,,其中也有基本的EVAL-APPLY循环 Dialogue: 0,0:04:16.19,0:04:19.98,Default,,0,0,0,,也就是对组合手段和抽象手段的展开 Dialogue: 0,0:04:20.95,0:04:24.68,Default,,0,0,0,,第三点 是一个不太重要但非常优雅的技术技巧 Dialogue: 0,0:04:24.89,0:04:28.52,Default,,0,0,0,,就是如何巧妙地使用流来避免回溯 Dialogue: 0,0:04:32.33,0:04:34.40,Default,,0,0,0,,好吧 我说过这门语言与众不同 Dialogue: 0,0:04:35.86,0:04:36.64,Default,,0,0,0,,为了解释这点 Dialogue: 0,0:04:37.05,0:04:42.81,Default,,0,0,0,,让我们回到这门课最初的理念上 Dialogue: 0,0:04:43.26,0:04:46.54,Default,,0,0,0,,就是要区别 Dialogue: 0,0:04:46.72,0:04:49.52,Default,,0,0,0,,数学中“陈述性”的知识 Dialogue: 0,0:04:50.19,0:04:54.14,Default,,0,0,0,,比如平方根的定义就是一条数学事实 Dialogue: 0,0:04:55.48,0:04:59.56,Default,,0,0,0,,而计算机科学讨论的是“如何做”的知识 Dialogue: 0,0:04:59.76,0:05:04.59,Default,,0,0,0,,“什么是平方根”和“如何计算平方根”是不同的 Dialogue: 0,0:05:05.97,0:05:07.07,Default,,0,0,0,,我们是从这里开始的 Dialogue: 0,0:05:08.51,0:05:09.52,Default,,0,0,0,,如果我们能够通过某种方式 Dialogue: 0,0:05:09.88,0:05:12.16,Default,,0,0,0,,弥合这种差距 岂不是更好么? Dialogue: 0,0:05:12.81,0:05:16.43,Default,,0,0,0,,我们创建一门这样的语言 Dialogue: 0,0:05:16.67,0:05:21.61,Default,,0,0,0,,以声明式的方式、用数学事实来完成计算 Dialogue: 0,0:05:22.38,0:05:25.50,Default,,0,0,0,,你用这种该语言来指定事实 Dialogue: 0,0:05:27.69,0:05:28.88,Default,,0,0,0,,你告诉它 Dialogue: 0,0:05:28.88,0:05:29.96,Default,,0,0,0,,什么是事实 Dialogue: 0,0:05:30.95,0:05:33.07,Default,,0,0,0,,而当你需要一个答案时 Dialogue: 0,0:05:33.21,0:05:36.38,Default,,0,0,0,,语言已经自动地内建了 Dialogue: 0,0:05:37.60,0:05:39.45,Default,,0,0,0,,有关于“如何做”的一般性知识 Dialogue: 0,0:05:39.47,0:05:40.64,Default,,0,0,0,,这样它就可以根据你给出的事实 Dialogue: 0,0:05:40.89,0:05:42.83,Default,,0,0,0,,自行地演进这些方法 Dialogue: 0,0:05:43.31,0:05:46.12,Default,,0,0,0,,通过你给定的事实和某种一般性的逻辑规则 Dialogue: 0,0:05:49.33,0:05:50.54,Default,,0,0,0,,就比如说 Dialogue: 0,0:05:52.06,0:05:55.12,Default,,0,0,0,,我会告诉程序下述事实 Dialogue: 0,0:05:56.00,0:06:07.08,Default,,0,0,0,,我告诉它 (SON-OF ADAM ABEL) Dialogue: 0,0:06:08.92,0:06:16.51,Default,,0,0,0,,同时告诉它 (SON-OF ADAM CAIN) Dialogue: 0,0:06:17.66,0:06:25.08,Default,,0,0,0,,以及 (SON-OF CAIN ENOCH) Dialogue: 0,0:06:27.79,0:06:34.89,Default,,0,0,0,,还有 (SON-OF ENOCH IRAD) Dialogue: 0,0:06:37.02,0:06:40.72,Default,,0,0,0,,以及《创世纪》章节中的其它人物 Dialogue: 0,0:06:41.15,0:06:43.18,Default,,0,0,0,,最后终止于ADAH Dialogue: 0,0:06:43.32,0:06:46.78,Default,,0,0,0,,这些是从ADAH到CAIN的家谱 Dialogue: 0,0:06:48.44,0:06:50.67,Default,,0,0,0,,总之 一旦你指明了这些事实 Dialogue: 0,0:06:52.35,0:06:53.40,Default,,0,0,0,,你就可以提出问题 Dialogue: 0,0:06:53.51,0:06:55.05,Default,,0,0,0,,你可以对语言系统发问 Dialogue: 0,0:06:56.06,0:06:59.29,Default,,0,0,0,,谁是ADAM的孩子? Dialogue: 0,0:07:00.42,0:07:04.91,Default,,0,0,0,,可以很容易地想到一个通用搜索程序 Dialogue: 0,0:07:05.52,0:07:06.96,Default,,0,0,0,,它会遍历所有的事实 Dialogue: 0,0:07:07.00,0:07:09.26,Default,,0,0,0,,然后回答:“哦 有两个答案” Dialogue: 0,0:07:09.29,0:07:10.44,Default,,0,0,0,,ABEL是ADAM的孩子 Dialogue: 0,0:07:10.68,0:07:12.17,Default,,0,0,0,,CAIN也是ADAM的孩子 Dialogue: 0,0:07:14.14,0:07:14.97,Default,,0,0,0,,你也可以这样问 Dialogue: 0,0:07:15.07,0:07:16.89,Default,,0,0,0,,基于同样的事实 Dialogue: 0,0:07:18.04,0:07:19.95,Default,,0,0,0,,CAIN是谁的孩子? Dialogue: 0,0:07:21.95,0:07:27.02,Default,,0,0,0,,你们就会想到生成另外一个略微不同的搜索程序 Dialogue: 0,0:07:27.92,0:07:29.21,Default,,0,0,0,,它也会遍历所有的事实 Dialogue: 0,0:07:29.45,0:07:33.05,Default,,0,0,0,,检查谁的孩子是CAIN Dialogue: 0,0:07:33.52,0:07:34.44,Default,,0,0,0,,发现结果是ADAM Dialogue: 0,0:07:35.89,0:07:36.99,Default,,0,0,0,,你也可以问 Dialogue: 0,0:07:38.01,0:07:41.40,Default,,0,0,0,,CAIN和ENOCH之间是什么关系? Dialogue: 0,0:07:42.07,0:07:45.08,Default,,0,0,0,,又会生成另一个略微不同的搜索程序 Dialogue: 0,0:07:46.34,0:07:48.16,Default,,0,0,0,,得到的结果是亲子关系(SON-OF) Dialogue: 0,0:07:52.88,0:07:54.92,Default,,0,0,0,,在这个非常简单的例子中 Dialogue: 0,0:07:56.14,0:07:58.44,Default,,0,0,0,,我们发现 即使是单条事实 Dialogue: 0,0:07:58.81,0:08:01.52,Default,,0,0,0,,比如说 (SON-OF ADAM CAIN) Dialogue: 0,0:08:02.84,0:08:05.52,Default,,0,0,0,,可以被用来回答不同种类的问题 Dialogue: 0,0:08:06.52,0:08:08.12,Default,,0,0,0,,你可以问CAIN是谁的孩子? Dialogue: 0,0:08:08.14,0:08:10.92,Default,,0,0,0,,你也可以问ADAM的孩子是谁? Dialogue: 0,0:08:10.94,0:08:12.86,Default,,0,0,0,,你也可以问ADAM和CAIN之间的关系是什么? Dialogue: 0,0:08:12.88,0:08:14.48,Default,,0,0,0,,这些由不同的传统程序 Dialogue: 0,0:08:15.53,0:08:18.54,Default,,0,0,0,,所解答的不同的问题 Dialogue: 0,0:08:18.68,0:08:20.72,Default,,0,0,0,,都基于同样的事实 Dialogue: 0,0:08:22.75,0:08:25.92,Default,,0,0,0,,这正是这种程序设计风格的威力所在 Dialogue: 0,0:08:26.91,0:08:29.50,Default,,0,0,0,,也就是一条陈述性知识 Dialogue: 0,0:08:30.04,0:08:34.01,Default,,0,0,0,,可以作为大量关于“如何做”的各种知识的基础 Dialogue: 0,0:08:34.81,0:08:37.08,Default,,0,0,0,,这跟我们正在编写的过程是不同的 Dialogue: 0,0:08:37.15,0:08:39.55,Default,,0,0,0,,我们编写的过程描述了输入 Dialogue: 0,0:08:39.61,0:08:40.65,Default,,0,0,0,,以及想要的输出 Dialogue: 0,0:08:41.49,0:08:44.70,Default,,0,0,0,,比如说 我们的平方根程序可以完美地回答 Dialogue: 0,0:08:44.76,0:08:47.16,Default,,0,0,0,,144的平方根是多少? Dialogue: 0,0:08:48.90,0:08:49.77,Default,,0,0,0,,但从原理上来说 Dialogue: 0,0:08:49.82,0:08:52.83,Default,,0,0,0,,平方根的数学定义告诉了你另外的东西 Dialogue: 0,0:08:52.84,0:08:56.43,Default,,0,0,0,,就比如说 17是谁的平方根 Dialogue: 0,0:08:57.59,0:08:59.71,Default,,0,0,0,,这就需要另外一个程序来解答 Dialogue: 0,0:09:01.92,0:09:03.50,Default,,0,0,0,,因此 数学定义 Dialogue: 0,0:09:03.98,0:09:05.12,Default,,0,0,0,,或者更一般地说 Dialogue: 0,0:09:05.53,0:09:10.30,Default,,0,0,0,,你给定的事实 对于问题是没有偏向性的 Dialogue: 0,0:09:10.90,0:09:12.81,Default,,0,0,0,,而我们倾向于编写专门的程序 Dialogue: 0,0:09:12.83,0:09:14.20,Default,,0,0,0,,因为它们是关于“如何做”的知识 Dialogue: 0,0:09:14.24,0:09:16.36,Default,,0,0,0,,倾向于寻找特定的答案 Dialogue: 0,0:09:17.56,0:09:20.12,Default,,0,0,0,,所以这是我们正在讨论的一个特点 Dialogue: 0,0:09:21.81,0:09:22.60,Default,,0,0,0,,然而我们可以更进一步 Dialogue: 0,0:09:23.48,0:09:27.52,Default,,0,0,0,,想象一下 我们可以向语言给定一些事实 Dialogue: 0,0:09:27.71,0:09:29.61,Default,,0,0,0,,现在 我们给它一些推理规则 Dialogue: 0,0:09:30.02,0:09:31.36,Default,,0,0,0,,比如说 Dialogue: 0,0:09:31.95,0:09:36.19,Default,,0,0,0,,这里 我们先用某种语法表示 Dialogue: 0,0:09:36.44,0:09:41.53,Default,,0,0,0,,如果(SON-OF ?X ?Y)成立 Dialogue: 0,0:09:41.68,0:09:45.21,Default,,0,0,0,,在这里 我用问号来标识变量 Dialogue: 0,0:09:45.61,0:09:56.06,Default,,0,0,0,,如果(SON-OF ?X ?Y)和(SON-OF ?Y ?Z)都成立 Dialogue: 0,0:09:58.96,0:10:08.46,Default,,0,0,0,,那么就有(GRANSON ?X ?Z) Dialogue: 0,0:10:09.32,0:10:13.40,Default,,0,0,0,,想象一下 如果把这条规则告诉机器 Dialogue: 0,0:10:15.00,0:10:17.28,Default,,0,0,0,,那么我们就可以这么来询问 Dialogue: 0,0:10:17.44,0:10:18.68,Default,,0,0,0,,谁是ADAM的孙子? Dialogue: 0,0:10:20.61,0:10:23.64,Default,,0,0,0,,或者说 IRAD是谁的孙子? Dialogue: 0,0:10:24.79,0:10:29.08,Default,,0,0,0,,或者从这些信息中尽可能地推断出所有的祖孙关系 Dialogue: 0,0:10:31.13,0:10:35.60,Default,,0,0,0,,我们可以想象 语言知道如何自动求解 Dialogue: 0,0:10:40.22,0:10:45.20,Default,,0,0,0,,好吧 我再举一个更具体一点的例子 Dialogue: 0,0:10:45.77,0:10:51.95,Default,,0,0,0,,这是个用来合并两个有序表的过程 Dialogue: 0,0:10:53.92,0:11:00.27,Default,,0,0,0,,X和Y是两个由数字构成的表 Dialogue: 0,0:11:00.30,0:11:04.20,Default,,0,0,0,,我们可以认为它们是严格升序的表 Dialogue: 0,0:11:04.76,0:11:07.53,Default,,0,0,0,,MERGE会把这两个表 Dialogue: 0,0:11:07.71,0:11:10.38,Default,,0,0,0,,合并成一个有序的表 Dialogue: 0,0:11:11.21,0:11:15.00,Default,,0,0,0,,这个程序非常简单 Dialogue: 0,0:11:15.02,0:11:16.14,Default,,0,0,0,,你们可以轻松地写出来 Dialogue: 0,0:11:16.39,0:11:18.64,Default,,0,0,0,,也就是 如果X为空 那么结果就是Y Dialogue: 0,0:11:18.86,0:11:20.46,Default,,0,0,0,,如果Y为空 那结果就是X Dialogue: 0,0:11:21.18,0:11:22.99,Default,,0,0,0,,否则的话 就要比较为首的两个元素 Dialogue: 0,0:11:22.99,0:11:24.46,Default,,0,0,0,,取出X中的第一个元素 Dialogue: 0,0:11:24.84,0:11:26.01,Default,,0,0,0,,以及Y中的第一个元素 Dialogue: 0,0:11:26.81,0:11:31.68,Default,,0,0,0,,把它们当中谁是最小的那一个 Dialogue: 0,0:11:32.83,0:11:36.60,Default,,0,0,0,,CONS在递归地调用MERGE的结果上 Dialogue: 0,0:11:37.87,0:11:39.92,Default,,0,0,0,,要么就是(MERGE (CDR X) Y) Dialogue: 0,0:11:40.11,0:11:41.61,Default,,0,0,0,,要么就是(MERGE X (CDR Y)) Dialogue: 0,0:11:42.40,0:11:43.96,Default,,0,0,0,,这是标准的程序 Dialogue: 0,0:11:46.47,0:11:48.41,Default,,0,0,0,,我们来考察下其中的逻辑 Dialogue: 0,0:11:48.62,0:11:49.79,Default,,0,0,0,,先不考虑程序 Dialogue: 0,0:11:50.28,0:11:52.76,Default,,0,0,0,,来看看这个过程所基于的逻辑 Dialogue: 0,0:11:53.82,0:11:55.00,Default,,0,0,0,,这其中的逻辑是 Dialogue: 0,0:11:55.02,0:11:57.21,Default,,0,0,0,,如果第一个元素较小 Dialogue: 0,0:11:57.53,0:12:00.00,Default,,0,0,0,,那么最后的结果就是把它 Dialogue: 0,0:12:00.16,0:12:02.12,Default,,0,0,0,,跟递归MERGE的结果CONS起来 Dialogue: 0,0:12:02.84,0:12:04.09,Default,,0,0,0,,让我们试着把 Dialogue: 0,0:12:04.24,0:12:06.41,Default,,0,0,0,,使这个程序运作的逻辑说清楚一点 Dialogue: 0,0:12:08.30,0:12:09.44,Default,,0,0,0,,这是一部分 Dialogue: 0,0:12:10.13,0:12:11.53,Default,,0,0,0,,这段程序 Dialogue: 0,0:12:12.64,0:12:15.26,Default,,0,0,0,,递归地剥离X Dialogue: 0,0:12:15.66,0:12:17.82,Default,,0,0,0,,如果X中的首元素较小的话 Dialogue: 0,0:12:19.98,0:12:22.54,Default,,0,0,0,,如果要显式地指出其中的逻辑的话 Dialogue: 0,0:12:23.45,0:12:26.49,Default,,0,0,0,,它其实就是演绎推理 Dialogue: 0,0:12:26.72,0:12:32.38,Default,,0,0,0,,其中 如果知道表CDR-X和表Y Dialogue: 0,0:12:33.29,0:12:35.44,Default,,0,0,0,,能够通过MERGE-TO-FORM形成Z Dialogue: 0,0:12:37.84,0:12:41.52,Default,,0,0,0,,并且还知道A比Y中的第一个元素小 Dialogue: 0,0:12:43.60,0:12:48.52,Default,,0,0,0,,那么你就知道 如果你把A和CDR-X给CONS起来 Dialogue: 0,0:12:49.74,0:12:51.85,Default,,0,0,0,,得到的结果和Y一起 Dialogue: 0,0:12:52.60,0:12:54.99,Default,,0,0,0,,可以通过MERGE-TO-FORM形成Z Dialogue: 0,0:12:55.82,0:12:58.09,Default,,0,0,0,,这就是它所基于的逻辑 Dialogue: 0,0:12:58.72,0:12:59.95,Default,,0,0,0,,我没有把它写成程序 Dialogue: 0,0:12:59.96,0:13:02.00,Default,,0,0,0,,我把它写成了某种演绎 Dialogue: 0,0:13:02.03,0:13:04.89,Default,,0,0,0,,正是属于这个特定子句的 Dialogue: 0,0:13:05.21,0:13:07.26,Default,,0,0,0,,它告诉我们可以在这里使用递归 Dialogue: 0,0:13:09.41,0:13:12.78,Default,,0,0,0,,同样地 这里还有些句子来补全其中的逻辑 Dialogue: 0,0:13:14.00,0:13:15.87,Default,,0,0,0,,其它的句子都是基于这些逻辑 Dialogue: 0,0:13:15.92,0:13:18.35,Default,,0,0,0,,由于它们大部分是相同的 我就不细讲了 Dialogue: 0,0:13:19.00,0:13:20.35,Default,,0,0,0,,然后就是终止条件 Dialogue: 0,0:13:20.41,0:13:22.01,Default,,0,0,0,,是用来检查NULL的 Dialogue: 0,0:13:22.03,0:13:24.04,Default,,0,0,0,,其基本想法是 对于任意的X Dialogue: 0,0:13:24.51,0:13:27.20,Default,,0,0,0,,X和空表可以通过MERGE-TO-FORM形成X Dialogue: 0,0:13:28.04,0:13:30.86,Default,,0,0,0,,而空表可以和任意的Y通过MERGE-TO-FORM形成Y Dialogue: 0,0:13:33.36,0:13:38.12,Default,,0,0,0,,这就是一段过程的代码 Dialogue: 0,0:13:38.43,0:13:40.11,Default,,0,0,0,,以及它所基于的逻辑 Dialogue: 0,0:13:41.74,0:13:42.97,Default,,0,0,0,,请注意其中的巨大差异 Dialogue: 0,0:13:45.10,0:13:50.52,Default,,0,0,0,,过程看起来是像这样的: Dialogue: 0,0:13:50.65,0:13:52.28,Default,,0,0,0,,首先这有一个盒子 Dialogue: 0,0:13:52.86,0:13:55.39,Default,,0,0,0,,我们到目前为止所做的事都有这样的特征 Dialogue: 0,0:13:55.40,0:13:57.69,Default,,0,0,0,,我们有一个盒子 有东西进去 也有东西出来 Dialogue: 0,0:13:58.08,0:13:59.61,Default,,0,0,0,,这儿有个MERGE盒子 Dialogue: 0,0:14:01.29,0:14:03.85,Default,,0,0,0,,输入是X和Y Dialogue: 0,0:14:04.44,0:14:05.37,Default,,0,0,0,,输出ANS Dialogue: 0,0:14:07.63,0:14:09.48,Default,,0,0,0,,这是我们所编写的程序的特征 Dialogue: 0,0:14:13.02,0:14:14.66,Default,,0,0,0,,但是规则并不像这样 Dialogue: 0,0:14:14.66,0:14:16.76,Default,,0,0,0,,规则讨论的是关系 Dialogue: 0,0:14:17.92,0:14:24.16,Default,,0,0,0,,也就是在幻灯片中我称作MERGE-TO-FORM的关系 Dialogue: 0,0:14:25.37,0:14:28.76,Default,,0,0,0,,每当我说X和Y通过MERGE-TO-FORM形成Z Dialogue: 0,0:14:29.00,0:14:32.33,Default,,0,0,0,,这个是一个函数 Dialogue: 0,0:14:32.61,0:14:32.85,Default,,0,0,0,,对吧? Dialogue: 0,0:14:32.85,0:14:34.41,Default,,0,0,0,,ANS是X和Y的函数 Dialogue: 0,0:14:34.59,0:14:38.19,Default,,0,0,0,,而我这里得到的是三个东西之间的关系 Dialogue: 0,0:14:39.72,0:14:41.32,Default,,0,0,0,,我不会指明 Dialogue: 0,0:14:42.09,0:14:43.77,Default,,0,0,0,,哪个是输入 哪个是输出 Dialogue: 0,0:14:44.20,0:14:47.40,Default,,0,0,0,,我之所以这么说 是因为原理上 Dialogue: 0,0:14:48.64,0:14:50.83,Default,,0,0,0,,我们可以用同样的逻辑规则 Dialogue: 0,0:14:50.84,0:14:52.44,Default,,0,0,0,,来回答相当多的问题 Dialogue: 0,0:14:54.57,0:14:56.30,Default,,0,0,0,,比如 我们可以问 Dialogue: 0,0:14:56.72,0:14:59.05,Default,,0,0,0,,想象一下 如果把这些逻辑规则输入机器 Dialogue: 0,0:14:59.05,0:15:01.20,Default,,0,0,0,,不是输入程序 而是其中依赖的逻辑 Dialogue: 0,0:15:01.40,0:15:03.12,Default,,0,0,0,,那么 它也就应该回答-- Dialogue: 0,0:15:04.75,0:15:05.52,Default,,0,0,0,,我们可以问它 Dialogue: 0,0:15:06.73,0:15:19.18,Default,,0,0,0,,(1 3 7)和(2 4 8)可以通过MERGE-TO-FORM形成什么? Dialogue: 0,0:15:20.91,0:15:23.42,Default,,0,0,0,,机器能够回答这样的问题 Dialogue: 0,0:15:23.88,0:15:27.36,Default,,0,0,0,,这同样也是我们的Lisp程序所回答的问题 Dialogue: 0,0:15:28.18,0:15:30.14,Default,,0,0,0,,但这同样的规则 Dialogue: 0,0:15:30.89,0:15:34.80,Default,,0,0,0,,也能够回答像这样的问题: Dialogue: 0,0:15:36.19,0:15:43.24,Default,,0,0,0,,(1 3 7)和什么能够通过MERGE-TO-FORM形成(1 2 3 4 7 8) Dialogue: 0,0:15:45.56,0:15:47.80,Default,,0,0,0,,同样的逻辑规则也能够回答这个 Dialogue: 0,0:15:47.84,0:15:49.90,Default,,0,0,0,,但我们编写的过程却无法回答这个问题 Dialogue: 0,0:15:50.80,0:15:52.33,Default,,0,0,0,,又或者 我们可以问 Dialogue: 0,0:15:53.71,0:16:01.12,Default,,0,0,0,,什么和什么能通过MERGE-TO-FORM Dialogue: 0,0:16:04.28,0:16:12.68,Default,,0,0,0,,哪两个东西可以通过MERGE-TO-FORM形成(1 2 3 4 7 8)? Dialogue: 0,0:16:13.78,0:16:15.34,Default,,0,0,0,,机器能够进行遍历 Dialogue: 0,0:16:15.84,0:16:17.31,Default,,0,0,0,,如果它能应用这些逻辑规则的话 Dialogue: 0,0:16:17.79,0:16:22.54,Default,,0,0,0,,就能够推断出这个问题所有的2^6种答案 Dialogue: 0,0:16:25.60,0:16:27.69,Default,,0,0,0,,因为可以分别是 (1)和其余的 Dialogue: 0,0:16:27.69,0:16:28.75,Default,,0,0,0,,也可以是 (1 2)和其余的 Dialogue: 0,0:16:28.79,0:16:31.53,Default,,0,0,0,,也可以是(1 3 7)和其余的 Dialogue: 0,0:16:32.01,0:16:33.26,Default,,0,0,0,,有一大堆的答案 Dialogue: 0,0:16:33.41,0:16:37.76,Default,,0,0,0,,但原理上来说 逻辑能推断出所有的答案 Dialogue: 0,0:16:38.55,0:16:42.03,Default,,0,0,0,,因此这里面就有两个巨大的不同 Dialogue: 0,0:16:44.04,0:16:46.00,Default,,0,0,0,,在我们所编写的程序中 Dialogue: 0,0:16:46.54,0:16:48.19,Default,,0,0,0,,不只是Lisp程序 Dialogue: 0,0:16:48.20,0:16:50.56,Default,,0,0,0,,基本上是你们目前编写过的所有程序 Dialogue: 0,0:16:52.03,0:16:53.60,Default,,0,0,0,,用你能叫出名字的程序语言所编写的程序 Dialogue: 0,0:16:54.15,0:16:57.79,Default,,0,0,0,,首先 我们并不准备计算一个函数 Dialogue: 0,0:17:00.62,0:17:02.01,Default,,0,0,0,,我们将要讨论的东西 Dialogue: 0,0:17:02.62,0:17:04.41,Default,,0,0,0,,并不具有输入和输出 Dialogue: 0,0:17:04.41,0:17:05.82,Default,,0,0,0,,我们讨论的是关系 Dialogue: 0,0:17:06.89,0:17:10.00,Default,,0,0,0,,也就是说 原理上 关系是没有方向性的 Dialogue: 0,0:17:11.08,0:17:15.05,Default,,0,0,0,,所以你指明用来回答这个问题的知识 Dialogue: 0,0:17:16.46,0:17:18.41,Default,,0,0,0,,也同样应该能够反过来 Dialogue: 0,0:17:18.43,0:17:21.80,Default,,0,0,0,,让你回答其它的这些问题 Dialogue: 0,0:17:26.60,0:17:29.40,Default,,0,0,0,,其次则是 Dialogue: 0,0:17:29.61,0:17:31.23,Default,,0,0,0,,因为我们讨论的是关系 Dialogue: 0,0:17:32.32,0:17:34.44,Default,,0,0,0,,关系的答案并不唯一 Dialogue: 0,0:17:35.61,0:17:37.00,Default,,0,0,0,,所以在第三个问题中 Dialogue: 0,0:17:37.02,0:17:38.36,Default,,0,0,0,,并没有特定的答案 Dialogue: 0,0:17:38.40,0:17:39.58,Default,,0,0,0,,它有很多的答案 Dialogue: 0,0:17:42.27,0:17:44.64,Default,,0,0,0,,这就是我们的目标 Dialogue: 0,0:17:44.64,0:17:45.90,Default,,0,0,0,,顺便说一下 Dialogue: 0,0:17:46.72,0:17:49.21,Default,,0,0,0,,这种程序设计风格被称作逻辑式程序设计 Dialogue: 0,0:17:50.22,0:17:51.58,Default,,0,0,0,,原因是显而易见的 Dialogue: 0,0:17:56.16,0:18:00.38,Default,,0,0,0,,用逻辑式进行程序设计的那群人之间 Dialogue: 0,0:18:00.40,0:18:03.15,Default,,0,0,0,,流传着几句箴言 Dialogue: 0,0:18:03.16,0:18:04.67,Default,,0,0,0,,他们把逻辑式程序设计的要点归纳为 Dialogue: 0,0:18:04.76,0:18:09.00,Default,,0,0,0,,用逻辑来表达 什么算是“真的” Dialogue: 0,0:18:10.09,0:18:13.88,Default,,0,0,0,,用逻辑来检测 是否是“真的” Dialogue: 0,0:18:14.67,0:18:17.24,Default,,0,0,0,,用逻辑来找出这些“真的” Dialogue: 0,0:18:19.20,0:18:22.09,Default,,0,0,0,,最为大家所熟知的逻辑式程序设计语言 Dialogue: 0,0:18:22.97,0:18:24.78,Default,,0,0,0,,你们可能也听过 -- 叫做Prolog Dialogue: 0,0:18:25.78,0:18:28.88,Default,,0,0,0,,今天早上我们将要实现的这门语言 Dialogue: 0,0:18:29.82,0:18:32.32,Default,,0,0,0,,是一种查询语言 Dialogue: 0,0:18:32.48,0:18:34.41,Default,,0,0,0,,它基本上就是Prolog的本质了 Dialogue: 0,0:18:35.32,0:18:36.73,Default,,0,0,0,,它可以完成相同的工作 Dialogue: 0,0:18:37.29,0:18:38.73,Default,,0,0,0,,虽然它比Prolog慢得多 Dialogue: 0,0:18:38.73,0:18:40.01,Default,,0,0,0,,这是因为我们是通过Lisp来解释的 Dialogue: 0,0:18:41.90,0:18:44.36,Default,,0,0,0,,而非构造一个专门的编译器 Dialogue: 0,0:18:44.46,0:18:46.62,Default,,0,0,0,,对它的解释 将运行在Lisp解释器之上 Dialogue: 0,0:18:47.51,0:18:49.84,Default,,0,0,0,,除此之外 它可以完成与Prolog相同的事儿 Dialogue: 0,0:18:49.88,0:18:52.78,Default,,0,0,0,,不但同样的能力 也有同样的局限 Dialogue: 0,0:18:55.08,0:18:56.17,Default,,0,0,0,,好吧 先解答一下疑惑 Dialogue: 0,0:19:00.43,0:19:02.84,Default,,0,0,0,,学生:您能再重复一下 Dialogue: 0,0:19:03.48,0:19:06.09,Default,,0,0,0,,用逻辑去寻找的三件事么? Dialogue: 0,0:19:06.72,0:19:09.84,Default,,0,0,0,,就是那些 找出什么为真 知道什么是真 等等 Dialogue: 0,0:19:09.84,0:19:10.52,Default,,0,0,0,,教授:好的 Dialogue: 0,0:19:10.56,0:19:15.74,Default,,0,0,0,,这算是程序员的某种“教义问答” Dialogue: 0,0:19:15.85,0:19:19.16,Default,,0,0,0,,我们用逻辑来表达怎么算是“真的” Dialogue: 0,0:19:20.80,0:19:21.79,Default,,0,0,0,,就像这些规则一样 Dialogue: 0,0:19:22.61,0:19:25.56,Default,,0,0,0,,我们用逻辑来检测某事是否是“真的” Dialogue: 0,0:19:25.60,0:19:27.76,Default,,0,0,0,,但在这里我没有回答这个问题 Dialogue: 0,0:19:28.55,0:19:29.29,Default,,0,0,0,,我可以问 Dialogue: 0,0:19:29.68,0:19:32.14,Default,,0,0,0,,在这里我可以这样来问 Dialogue: 0,0:19:33.26,0:19:36.56,Default,,0,0,0,,(1 3 7)和(2 4 8)是否能够 Dialogue: 0,0:19:36.91,0:19:40.38,Default,,0,0,0,,通过MERGE-TO-FORM形成(1 2 6 19) Dialogue: 0,0:19:41.12,0:19:44.68,Default,,0,0,0,,同样的逻辑规则会告诉我们不行 Dialogue: 0,0:19:45.69,0:19:47.93,Default,,0,0,0,,这里 我使用逻辑来检测是否为真 Dialogue: 0,0:19:48.28,0:19:50.48,Default,,0,0,0,,然后 我们也可以使用逻辑来找出为真的东西 Dialogue: 0,0:20:04.46,0:20:05.16,Default,,0,0,0,,休息一下吧 Dialogue: 0,0:20:06.13,0:20:17.02,Default,,0,0,0,,[音乐] Dialogue: 0,0:20:17.05,0:20:20.68,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:20:47.59,0:20:51.02,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:20:51.07,0:20:55.60,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:20:55.63,0:21:00.68,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 I Dialogue: 0,0:21:03.24,0:21:04.97,Default,,0,0,0,,教授:让我们继续来看一看 Dialogue: 0,0:21:05.84,0:21:08.44,Default,,0,0,0,,这个查询语言及其操作 Dialogue: 0,0:21:10.52,0:21:11.84,Default,,0,0,0,,首先需要注意到 Dialogue: 0,0:21:12.24,0:21:14.14,Default,,0,0,0,,当我建立好那个小型的圣经数据库后 Dialogue: 0,0:21:14.16,0:21:17.24,Default,,0,0,0,,我们就能够针对一系列的事实 Dialogue: 0,0:21:17.48,0:21:19.92,Default,,0,0,0,,以关系的方式来向这个语言提问 Dialogue: 0,0:21:21.33,0:21:25.15,Default,,0,0,0,,因此 我们先来陈述一些事实 Dialogue: 0,0:21:26.06,0:21:29.68,Default,,0,0,0,,这是波士顿一家高科技公司的 Dialogue: 0,0:21:30.08,0:21:32.62,Default,,0,0,0,,一小部分人事档案 Dialogue: 0,0:21:33.05,0:21:36.80,Default,,0,0,0,,这部分档案是Ben Bitdiddle的 Dialogue: 0,0:21:37.50,0:21:41.95,Default,,0,0,0,,Bitdiddle是这家公司的计算机向导 Dialogue: 0,0:21:42.84,0:21:45.80,Default,,0,0,0,,他是这家公司的低薪向导 Dialogue: 0,0:21:46.42,0:21:48.78,Default,,0,0,0,,他的上司是Oliver Warbucks Dialogue: 0,0:21:49.28,0:21:50.70,Default,,0,0,0,,这里是他的住址 Dialogue: 0,0:21:52.15,0:21:56.54,Default,,0,0,0,,我们按照这样的格式给出信息:职务、薪水、上司、住址 Dialogue: 0,0:21:57.56,0:21:59.25,Default,,0,0,0,,还有一些其它的约定 Dialogue: 0,0:21:59.25,0:22:02.22,Default,,0,0,0,,这里的COMPUTER表示BEN在计算机分部工作 Dialogue: 0,0:22:02.76,0:22:04.94,Default,,0,0,0,,而他在这个分部的工作是向导 Dialogue: 0,0:22:05.66,0:22:07.15,Default,,0,0,0,,这里是其他人的 Dialogue: 0,0:22:07.16,0:22:12.28,Default,,0,0,0,,Alyssa P.Hacker是一名计算机程序员 Dialogue: 0,0:22:13.36,0:22:14.60,Default,,0,0,0,,她的上司是Ben Dialogue: 0,0:22:15.21,0:22:16.54,Default,,0,0,0,,而她住在Cambridge Dialogue: 0,0:22:17.55,0:22:19.42,Default,,0,0,0,,Ben手下的另外一个程序员 Dialogue: 0,0:22:20.03,0:22:21.44,Default,,0,0,0,,叫做Lem E. Tweakit Dialogue: 0,0:22:22.82,0:22:26.73,Default,,0,0,0,,实习程序员 Louis Reasoner Dialogue: 0,0:22:27.42,0:22:28.62,Default,,0,0,0,,在Alyssa手下工作 Dialogue: 0,0:22:30.10,0:22:35.45,Default,,0,0,0,,公司里的“大老板”不为任何人工作 Dialogue: 0,0:22:36.81,0:22:38.11,Default,,0,0,0,,这就是Oliver Warbucks的档案了 Dialogue: 0,0:22:38.11,0:22:39.31,Default,,0,0,0,,我们将要做的就是 Dialogue: 0,0:22:40.94,0:22:43.66,Default,,0,0,0,,对这个小型的世界提问 Dialogue: 0,0:22:44.97,0:22:48.40,Default,,0,0,0,,这将是我们进行逻辑运算的样本世界 Dialogue: 0,0:22:51.42,0:22:54.96,Default,,0,0,0,,我再最后一次强调一下 Dialogue: 0,0:22:55.60,0:22:58.20,Default,,0,0,0,,你们应该从这门课中学到的最重要的知识 Dialogue: 0,0:22:58.80,0:23:01.66,Default,,0,0,0,,也就是 当别人向你介绍语言时 Dialogue: 0,0:23:02.25,0:23:04.43,Default,,0,0,0,,你要问:“它的基本元素是什么?” Dialogue: 0,0:23:06.12,0:23:07.79,Default,,0,0,0,,组合的手段有哪些? Dialogue: 0,0:23:14.70,0:23:16.40,Default,,0,0,0,,如何把基本元素组织在一起 Dialogue: 0,0:23:16.67,0:23:19.37,Default,,0,0,0,,然后把它们抽象出来? Dialogue: 0,0:23:19.96,0:23:21.93,Default,,0,0,0,,如何抽象这些复合元素 Dialogue: 0,0:23:24.68,0:23:27.58,Default,,0,0,0,,以便于你能够复用它们构造更复杂的东西? Dialogue: 0,0:23:29.02,0:23:30.81,Default,,0,0,0,,我已经强调过很多次了 Dialogue: 0,0:23:31.16,0:23:32.48,Default,,0,0,0,,但还是值得重申一遍 Dialogue: 0,0:23:35.00,0:23:36.67,Default,,0,0,0,,记住了么?我们开始了 Dialogue: 0,0:23:36.67,0:23:37.34,Default,,0,0,0,,首先是基本元素 Dialogue: 0,0:23:37.77,0:23:39.44,Default,,0,0,0,,这其中 只有唯一的基本元素 Dialogue: 0,0:23:40.96,0:23:43.20,Default,,0,0,0,,这门语言中的基本元素就是“查询” Dialogue: 0,0:23:44.14,0:23:45.74,Default,,0,0,0,,一条基本查询 Dialogue: 0,0:23:46.81,0:23:48.25,Default,,0,0,0,,我们先来看几条基本查询 Dialogue: 0,0:23:51.82,0:23:53.02,Default,,0,0,0,,首先 这条查询问的是 Dialogue: 0,0:23:53.10,0:23:54.81,Default,,0,0,0,,“谁是计算机程序员?” Dialogue: 0,0:23:55.55,0:23:59.88,Default,,0,0,0,,或者可以解释为:找出数据库中 Dialogue: 0,0:24:01.55,0:24:06.14,Default,,0,0,0,,所有JOB栏为COMPUTER PROGRAMMER的事实 Dialogue: 0,0:24:06.64,0:24:08.01,Default,,0,0,0,,这里有一些小语法 Dialogue: 0,0:24:08.47,0:24:10.59,Default,,0,0,0,,不带问号的都是字面量 Dialogue: 0,0:24:11.28,0:24:13.15,Default,,0,0,0,,?X表示X是变量 Dialogue: 0,0:24:13.31,0:24:15.56,Default,,0,0,0,,而这条查询会匹配 比如说 -- Dialogue: 0,0:24:16.03,0:24:19.00,Default,,0,0,0,,Alyssa P. Hacker 是程序员 Dialogue: 0,0:24:19.28,0:24:21.93,Default,,0,0,0,,其中X为Alyssa P. Hacker这条事实 Dialogue: 0,0:24:26.82,0:24:29.98,Default,,0,0,0,,或者更一般地 我可以在一条查询中引入两个变量 Dialogue: 0,0:24:30.75,0:24:31.45,Default,,0,0,0,,我可以问 Dialogue: 0,0:24:31.60,0:24:35.88,Default,,0,0,0,,?X的JOB必须是COMPUTER ?TYPE Dialogue: 0,0:24:39.34,0:24:41.39,Default,,0,0,0,,也就是会匹配COMPUTER WIZARD Dialogue: 0,0:24:42.14,0:24:44.28,Default,,0,0,0,,所以这里?TYPE可能会匹配WIZARD Dialogue: 0,0:24:44.92,0:24:46.46,Default,,0,0,0,,也可能会匹配PROGRAMMER Dialogue: 0,0:24:47.48,0:24:50.37,Default,,0,0,0,,而?X会匹配不同的东西 Dialogue: 0,0:24:50.37,0:24:52.24,Default,,0,0,0,,但在我们的这个小例子中 Dialogue: 0,0:24:52.25,0:24:55.15,Default,,0,0,0,,数据库中只有三条事实符合那条查询 Dialogue: 0,0:24:59.12,0:25:02.08,Default,,0,0,0,,把语法说得再清楚一点 同样的查询 Dialogue: 0,0:25:05.29,0:25:08.09,Default,,0,0,0,,同样的这条指定了?X的JOB的查询 Dialogue: 0,0:25:09.85,0:25:11.79,Default,,0,0,0,,并不能够与Lewis Reasoner匹配 Dialogue: 0,0:25:11.84,0:25:13.64,Default,,0,0,0,,这是因为我这里所写的 Dialogue: 0,0:25:14.22,0:25:17.74,Default,,0,0,0,,表示要匹配的是由两个符号构成的表 Dialogue: 0,0:25:19.96,0:25:21.96,Default,,0,0,0,,其中首元素必须为单词“COMPUTER” Dialogue: 0,0:25:22.32,0:25:23.80,Default,,0,0,0,,而第二个可以匹配任意的东西 Dialogue: 0,0:25:25.08,0:25:27.32,Default,,0,0,0,,而Lewis这里的工作描述有三个符号 Dialogue: 0,0:25:27.80,0:25:28.83,Default,,0,0,0,,因此不匹配 Dialogue: 0,0:25:30.34,0:25:32.19,Default,,0,0,0,,你们还需要知道的一种语法是 Dialogue: 0,0:25:35.04,0:25:38.32,Default,,0,0,0,,更具一般性的点记号 Dialogue: 0,0:25:40.17,0:25:42.92,Default,,0,0,0,,这个标准的表记号表示的是 Dialogue: 0,0:25:43.04,0:25:43.82,Default,,0,0,0,,首先这是一个表 Dialogue: 0,0:25:44.12,0:25:47.32,Default,,0,0,0,,它的首元素为单词“COMPUTER” Dialogue: 0,0:25:47.58,0:25:50.22,Default,,0,0,0,,而其余的部分 我们把它们称作?TYPE Dialogue: 0,0:25:53.73,0:25:55.50,Default,,0,0,0,,因此这条查询就会匹配上 Dialogue: 0,0:25:56.93,0:25:59.31,Default,,0,0,0,,Lewis的工作是COMPUTER PROGRAMMER TRAINEE Dialogue: 0,0:25:59.44,0:26:03.29,Default,,0,0,0,,而?TYPE的值将会是这个表的CDR部分 Dialogue: 0,0:26:03.32,0:26:05.64,Default,,0,0,0,,也就是表(PROGRAMMER TRAINEE) Dialogue: 0,0:26:06.96,0:26:10.46,Default,,0,0,0,,Lisp源码读取器会自动完成对点记号的处理 Dialogue: 0,0:26:15.90,0:26:17.76,Default,,0,0,0,,让我们来实际操作一下 Dialogue: 0,0:26:17.76,0:26:20.51,Default,,0,0,0,,我将向语言系统输入这些查询 Dialogue: 0,0:26:20.76,0:26:21.82,Default,,0,0,0,,然后得到结果 Dialogue: 0,0:26:22.54,0:26:24.48,Default,,0,0,0,,让我们在计算机中试试 Dialogue: 0,0:26:25.18,0:26:26.51,Default,,0,0,0,,我可以问 Dialogue: 0,0:26:27.34,0:26:28.88,Default,,0,0,0,,谁在计算机分部工作? Dialogue: 0,0:26:30.00,0:26:38.22,Default,,0,0,0,,(JOB ?X (COMPUTER . ?Y) Dialogue: 0,0:26:39.73,0:26:41.48,Default,,0,0,0,,哑变量的名字并不重要 Dialogue: 0,0:26:42.76,0:26:44.14,Default,,0,0,0,,查询的结果是 Dialogue: 0,0:26:44.41,0:26:45.68,Default,,0,0,0,,有四条记录 Dialogue: 0,0:26:48.65,0:26:50.09,Default,,0,0,0,,我也可以问 Dialogue: 0,0:26:50.56,0:26:52.38,Default,,0,0,0,,大家的上司都是谁? Dialogue: 0,0:26:52.81,0:26:54.88,Default,,0,0,0,,我输入一条基本查询 Dialogue: 0,0:26:56.52,0:26:59.39,Default,,0,0,0,,(SUPERVISOR ?X ?Y) Dialogue: 0,0:27:02.56,0:27:05.42,Default,,0,0,0,,这些都是我所知道的上下级关系 Dialogue: 0,0:27:05.54,0:27:08.83,Default,,0,0,0,,或者我也可以问:“谁住在Cambridge?” Dialogue: 0,0:27:08.83,0:27:09.47,Default,,0,0,0,,我就这么输入: Dialogue: 0,0:27:10.24,0:27:20.92,Default,,0,0,0,,(ADDRESS ?X (CAMBRIDGE . ?T)) Dialogue: 0,0:27:25.09,0:27:26.89,Default,,0,0,0,,只有一个人住在Cambridge Dialogue: 0,0:27:30.82,0:27:32.17,Default,,0,0,0,,这些就是基本查询 Dialogue: 0,0:27:32.17,0:27:34.96,Default,,0,0,0,,你们看到的这些 就是与系统的基础交互 Dialogue: 0,0:27:35.29,0:27:39.24,Default,,0,0,0,,你输入一条查询 他输出所有可能的查询 Dialogue: 0,0:27:39.62,0:27:40.65,Default,,0,0,0,,换句话说 也就是 Dialogue: 0,0:27:40.67,0:27:44.16,Default,,0,0,0,,它找出这些变量所有可能的值 Dialogue: 0,0:27:44.19,0:27:45.87,Default,,0,0,0,,不管它是叫X、Y还是T Dialogue: 0,0:27:46.09,0:27:52.08,Default,,0,0,0,,然后它输出的是用所有可行值实例化该条查询的结果 Dialogue: 0,0:27:52.92,0:27:55.16,Default,,0,0,0,,也就是规则系统那一课讲的“实例化” Dialogue: 0,0:27:55.16,0:27:58.83,Default,,0,0,0,,用变量所有可能的值来实例化查询 Dialogue: 0,0:27:59.00,0:28:00.35,Default,,0,0,0,,然后输出所有的结果 Dialogue: 0,0:28:01.00,0:28:03.35,Default,,0,0,0,,当然 还有不同的呈现结果的方式 Dialogue: 0,0:28:03.35,0:28:06.01,Default,,0,0,0,,比如说 Prolog就有些不一样 Dialogue: 0,0:28:06.01,0:28:07.44,Default,,0,0,0,,它并不向你返回查询 Dialogue: 0,0:28:07.76,0:28:10.78,Default,,0,0,0,,Prolog会输出X=这个 Y=那个 Dialogue: 0,0:28:10.97,0:28:12.94,Default,,0,0,0,,又或者X=这个 Y=那个 Dialogue: 0,0:28:13.66,0:28:15.48,Default,,0,0,0,,这是使用界面层次的差别 Dialogue: 0,0:28:15.71,0:28:17.05,Default,,0,0,0,,你可以根据你的喜好来决定 Dialogue: 0,0:28:18.97,0:28:19.58,Default,,0,0,0,,我们继续 Dialogue: 0,0:28:21.00,0:28:22.68,Default,,0,0,0,,也就是说 这个语言中的基本元素 Dialogue: 0,0:28:23.39,0:28:24.57,Default,,0,0,0,,只有一个 对吧? Dialogue: 0,0:28:24.57,0:28:27.23,Default,,0,0,0,,也就是基本查询 Dialogue: 0,0:28:31.31,0:28:32.56,Default,,0,0,0,,来看看组合的手段 Dialogue: 0,0:28:34.33,0:28:37.68,Default,,0,0,0,,我们来考察一下这个语言中的复合查询 Dialogue: 0,0:28:39.77,0:28:40.46,Default,,0,0,0,,比如这条 Dialogue: 0,0:28:41.79,0:28:42.51,Default,,0,0,0,,这条查询是说 Dialogue: 0,0:28:45.05,0:28:48.22,Default,,0,0,0,,列举出所有在计算机分部工作的人 Dialogue: 0,0:28:49.81,0:28:52.00,Default,,0,0,0,,在计算机分部工作的人 Dialogue: 0,0:28:52.54,0:28:53.96,Default,,0,0,0,,以及他们的上司 Dialogue: 0,0:28:56.80,0:28:58.83,Default,,0,0,0,,我使用AND来编写这条查询 Dialogue: 0,0:29:00.22,0:29:04.06,Default,,0,0,0,,(AND (JOB ?X (COMPUTER . ?Y)) Dialogue: 0,0:29:04.92,0:29:06.83,Default,,0,0,0,,(JOB ?X (COMPUTER . ?Y)) Dialogue: 0,0:29:07.56,0:29:10.03,Default,,0,0,0,,并且(SUPERVISOR ?X ?Z) Dialogue: 0,0:29:11.44,0:29:14.16,Default,,0,0,0,,找出所有在计算机分部工作的人 -- 对应这条 Dialogue: 0,0:29:14.30,0:29:15.88,Default,,0,0,0,,以及它们的上司 Dialogue: 0,0:29:16.46,0:29:17.82,Default,,0,0,0,,注意这条查询中 Dialogue: 0,0:29:18.67,0:29:22.41,Default,,0,0,0,,我引入了三个变量 ?X ?Y 以及 ?Z Dialogue: 0,0:29:23.58,0:29:28.65,Default,,0,0,0,,并且 这两个?X应该匹配同样的东西 Dialogue: 0,0:29:29.45,0:29:31.16,Default,,0,0,0,,?X被约束在了计算机分部中 Dialogue: 0,0:29:31.31,0:29:33.00,Default,,0,0,0,,并且?X的上司是?Z Dialogue: 0,0:29:34.81,0:29:35.80,Default,,0,0,0,,我们再来看一条 Dialogue: 0,0:29:37.25,0:29:39.28,Default,,0,0,0,,AND算是一种组合手段 Dialogue: 0,0:29:41.44,0:29:43.96,Default,,0,0,0,,哪些人的薪水超过$30,000? Dialogue: 0,0:29:45.71,0:29:51.71,Default,,0,0,0,,(AND (SALARY ?P ?A) Dialogue: 0,0:29:54.59,0:29:57.45,Default,,0,0,0,,而关于?A的要求则是 Dialogue: 0,0:29:57.48,0:30:00.12,Default,,0,0,0,,(LISP-VALUE > ?A 300000) Dialogue: 0,0:30:00.60,0:30:03.23,Default,,0,0,0,,这里的LISP-VALUE是一个接口 Dialogue: 0,0:30:04.30,0:30:10.04,Default,,0,0,0,,用来连接查询语言与其底层的Lisp Dialogue: 0,0:30:10.60,0:30:12.72,Default,,0,0,0,,LISP-VALUE让你能够在查询 Dialogue: 0,0:30:12.75,0:30:16.91,Default,,0,0,0,,中调用任意的Lisp谓词 Dialogue: 0,0:30:17.18,0:30:20.11,Default,,0,0,0,,因为我要用Lisp中的谓词> 所以我用LISP-VALUE Dialogue: 0,0:30:21.02,0:30:21.75,Default,,0,0,0,,所以这里我用了AND Dialogue: 0,0:30:21.75,0:30:24.48,Default,,0,0,0,,因此这样就查询出了薪水超过$30000的人 Dialogue: 0,0:30:28.19,0:30:30.03,Default,,0,0,0,,或者这条更复杂的查询 Dialogue: 0,0:30:31.27,0:30:35.02,Default,,0,0,0,,告诉我所有那些 在计算机分部中工作 Dialogue: 0,0:30:36.25,0:30:39.36,Default,,0,0,0,,但他的上司不在计算机分部工作的人 Dialogue: 0,0:30:42.79,0:30:45.51,Default,,0,0,0,,(AND (JOB ?X (COMPUTER . ?Y)) Dialogue: 0,0:30:45.51,0:30:47.32,Default,,0,0,0,,表示?X在计算机分部工作 Dialogue: 0,0:30:47.78,0:30:49.24,Default,,0,0,0,,但是呢 Dialogue: 0,0:30:50.49,0:30:54.25,Default,,0,0,0,,?X的上司?Z Dialogue: 0,0:30:55.37,0:30:57.87,Default,,0,0,0,,?Z的JOB不是形如(COMPUTER ...)一类的 Dialogue: 0,0:30:59.62,0:31:00.35,Default,,0,0,0,,同样的 Dialogue: 0,0:31:00.51,0:31:02.38,Default,,0,0,0,,这两个?X应该是一致的 Dialogue: 0,0:31:03.20,0:31:05.76,Default,,0,0,0,,而这两个?Z也应该是一致的 Dialogue: 0,0:31:09.39,0:31:11.38,Default,,0,0,0,,你又了解了另一种组合手段 -- NOT Dialogue: 0,0:31:17.71,0:31:18.67,Default,,0,0,0,,好了 再让我们来试试这些 Dialogue: 0,0:31:20.88,0:31:22.08,Default,,0,0,0,,它同样起效 Dialogue: 0,0:31:22.40,0:31:24.12,Default,,0,0,0,,我可以问计算机: Dialogue: 0,0:31:26.89,0:31:35.40,Default,,0,0,0,,(AND (JOB ?X (COMPUTER . ?Y))) Dialogue: 0,0:31:38.84,0:31:45.95,Default,,0,0,0,,另一个条件是(SUPERVISOR ?X ?Z) Dialogue: 0,0:31:46.83,0:31:49.53,Default,,0,0,0,,我把这条查询输入进去 Dialogue: 0,0:31:51.07,0:31:52.97,Default,,0,0,0,,计算机返回给我们的 Dialogue: 0,0:31:54.00,0:31:58.73,Default,,0,0,0,,计算机利用所有可能的答案把我的查询实例化了 Dialogue: 0,0:31:58.93,0:32:00.08,Default,,0,0,0,,你会发现有很多的答案 Dialogue: 0,0:32:01.69,0:32:02.14,Default,,0,0,0,,好 Dialogue: 0,0:32:02.19,0:32:04.04,Default,,0,0,0,,之所以把这门语言称作“逻辑语言” Dialogue: 0,0:32:05.21,0:32:06.60,Default,,0,0,0,,是因为这门语言中的组合手段 Dialogue: 0,0:32:06.64,0:32:09.47,Default,,0,0,0,,都是逻辑运算 Dialogue: 0,0:32:09.80,0:32:15.68,Default,,0,0,0,,组合的手段有AND和NOT Dialogue: 0,0:32:15.96,0:32:17.92,Default,,0,0,0,,以及我还没有告诉你的OR Dialogue: 0,0:32:18.49,0:32:20.36,Default,,0,0,0,,我还告诉过你LISP-VALUE Dialogue: 0,0:32:20.72,0:32:24.48,Default,,0,0,0,,当然 虽然它不是一个逻辑运算 Dialogue: 0,0:32:24.51,0:32:26.89,Default,,0,0,0,,但是这个特殊的小技巧把它跟Lisp连接在了一起 Dialogue: 0,0:32:27.34,0:32:28.75,Default,,0,0,0,,让你获得了更多的力量 Dialogue: 0,0:32:29.25,0:32:30.67,Default,,0,0,0,,这些就是组合手段 Dialogue: 0,0:32:32.59,0:32:33.98,Default,,0,0,0,,好 接着是抽象手段 Dialogue: 0,0:32:34.16,0:32:35.21,Default,,0,0,0,,我们想要的是 Dialogue: 0,0:32:38.27,0:32:41.24,Default,,0,0,0,,想让我们回过头来看上一张幻灯片 Dialogue: 0,0:32:42.26,0:32:44.25,Default,,0,0,0,,我们想要把一些非常复杂的东西 Dialogue: 0,0:32:44.46,0:32:48.00,Default,,0,0,0,,比如不与上司在同一部门工作 Dialogue: 0,0:32:48.01,0:32:50.09,Default,,0,0,0,,的人的这种概念 Dialogue: 0,0:32:52.40,0:32:55.10,Default,,0,0,0,,像以前一样 给它命名 Dialogue: 0,0:32:56.09,0:32:58.12,Default,,0,0,0,,如果在某个分部工作的人 Dialogue: 0,0:32:58.17,0:33:00.25,Default,,0,0,0,,他的上司却不在那个分部工作 Dialogue: 0,0:33:00.48,0:33:01.93,Default,,0,0,0,,这就意味着他是个“大腕” Dialogue: 0,0:33:02.75,0:33:05.13,Default,,0,0,0,,这样 我们就定义一条规则指明 Dialogue: 0,0:33:06.43,0:33:09.16,Default,,0,0,0,,如果?X是某个部门的BIGSHOT Dialogue: 0,0:33:10.91,0:33:14.68,Default,,0,0,0,,如果他在该部门工作 Dialogue: 0,0:33:16.04,0:33:20.08,Default,,0,0,0,,并且他的上司不在该部门工作 Dialogue: 0,0:33:21.51,0:33:22.94,Default,,0,0,0,,因此这就是我们的抽象手段 Dialogue: 0,0:33:22.94,0:33:23.90,Default,,0,0,0,,这是一条规则 Dialogue: 0,0:33:26.22,0:33:27.58,Default,,0,0,0,,规则由三部分构成 Dialogue: 0,0:33:31.00,0:33:32.48,Default,,0,0,0,,关键字RULE表明这是一条规则 Dialogue: 0,0:33:33.40,0:33:35.48,Default,,0,0,0,,接着是规则的结论 Dialogue: 0,0:33:37.53,0:33:39.07,Default,,0,0,0,,然后是规则的体 Dialogue: 0,0:33:40.00,0:33:41.88,Default,,0,0,0,,你可以把它解读为这样的一段逻辑: Dialogue: 0,0:33:41.92,0:33:45.15,Default,,0,0,0,,如果你知道规则的体为真 Dialogue: 0,0:33:46.40,0:33:48.72,Default,,0,0,0,,那么你就可以推导出结论为真 Dialogue: 0,0:33:49.45,0:33:53.28,Default,,0,0,0,,或者说为了推断出?X是某个部门的“大腕” Dialogue: 0,0:33:53.79,0:33:55.71,Default,,0,0,0,,这些条件足够验证了 Dialogue: 0,0:33:57.48,0:33:58.82,Default,,0,0,0,,这就是规则的形式 Dialogue: 0,0:34:03.28,0:34:06.16,Default,,0,0,0,,让我们回过头来看看 Dialogue: 0,0:34:06.73,0:34:07.92,Default,,0,0,0,,课间休息前我举的那个例子 Dialogue: 0,0:34:08.11,0:34:10.68,Default,,0,0,0,,我们来看看 如果用规则来描述会是什么样的 Dialogue: 0,0:34:11.44,0:34:12.84,Default,,0,0,0,,我会抽取出其中的逻辑 Dialogue: 0,0:34:13.08,0:34:15.50,Default,,0,0,0,,并将它们变为这种格式的规则 Dialogue: 0,0:34:18.73,0:34:19.35,Default,,0,0,0,,就有了下面的规则 Dialogue: 0,0:34:19.35,0:34:20.96,Default,,0,0,0,,这就是MERGE-TO-FORM的规则 Dialogue: 0,0:34:21.71,0:34:22.97,Default,,0,0,0,,这个规则是说 Dialogue: 0,0:34:26.28,0:34:29.62,Default,,0,0,0,,'()与?Y可以通过MERGE-TO-FORM形成?Y Dialogue: 0,0:34:29.62,0:34:30.87,Default,,0,0,0,,这是规则的结论 Dialogue: 0,0:34:33.21,0:34:35.74,Default,,0,0,0,,需要注意的是 这个特定的规则没有体 Dialogue: 0,0:34:36.65,0:34:37.66,Default,,0,0,0,,在这门语言中 Dialogue: 0,0:34:38.11,0:34:40.86,Default,,0,0,0,,没有体的规则总是真的 Dialogue: 0,0:34:41.23,0:34:42.51,Default,,0,0,0,,你总是可以假设它们为真 Dialogue: 0,0:34:45.19,0:34:46.49,Default,,0,0,0,,另一条规则说的是 Dialogue: 0,0:34:46.64,0:34:49.46,Default,,0,0,0,,任意对象与空表进行MERGE-TO-FORM 得到的任然是原物 Dialogue: 0,0:34:49.46,0:34:50.12,Default,,0,0,0,,就是这条 Dialogue: 0,0:34:50.90,0:34:53.55,Default,,0,0,0,,(MERGE-TO-FORM ?Y '() ?Y) Dialogue: 0,0:34:55.51,0:34:58.40,Default,,0,0,0,,它们对应了我们MERGE过程中的两个终止条件 Dialogue: 0,0:34:58.44,0:34:59.77,Default,,0,0,0,,但我们现在讨论的是逻辑 Dialogue: 0,0:35:00.41,0:35:01.45,Default,,0,0,0,,而非过程 Dialogue: 0,0:35:03.49,0:35:04.48,Default,,0,0,0,,我们还有另外一条规则 Dialogue: 0,0:35:04.83,0:35:08.73,Default,,0,0,0,,描述的是 如果你知道如何MERGE较短的表 Dialogue: 0,0:35:08.91,0:35:09.83,Default,,0,0,0,,那么你就可以把它们结合在一起 Dialogue: 0,0:35:09.83,0:35:14.16,Default,,0,0,0,,这条规则说:如果你有表?X、?Y以及?Z Dialogue: 0,0:35:14.92,0:35:17.61,Default,,0,0,0,,如果你想推断出(?A . ?X) Dialogue: 0,0:35:17.63,0:35:19.08,Default,,0,0,0,,这个记法表示(CONS ?A ?X) Dialogue: 0,0:35:19.48,0:35:22.36,Default,,0,0,0,,或者说首元素是'A、剩余元素是'X的表 Dialogue: 0,0:35:23.16,0:35:27.40,Default,,0,0,0,,由此 如果你想推断(MERGE-TO-FROM (?A . ?X) (?B . ?Y) (?B . ?Z)) Dialogue: 0,0:35:30.36,0:35:33.90,Default,,0,0,0,,毋宁说如果你想要把表(?A ?X)和表(?B ?Y)合并得到 Dialogue: 0,0:35:33.92,0:35:35.85,Default,,0,0,0,,一个以?B为首的表 Dialogue: 0,0:35:36.76,0:35:40.67,Default,,0,0,0,,你想要推断出这个结果 就要满足 Dialogue: 0,0:35:40.91,0:35:44.48,Default,,0,0,0,,不但(MERGE-TP-FORM (?A . ?X) ?Y ?Z) Dialogue: 0,0:35:45.18,0:35:47.24,Default,,0,0,0,,并且(LISP-VALUE > ?A ?B) Dialogue: 0,0:35:48.69,0:35:50.59,Default,,0,0,0,,因此当我在合并它们时 ?B会首先出现在表中 Dialogue: 0,0:35:51.82,0:35:54.91,Default,,0,0,0,,这就是简单的把我之前写的伪代码 Dialogue: 0,0:35:55.24,0:35:57.18,Default,,0,0,0,,翻译成逻辑的语言 Dialogue: 0,0:35:57.96,0:36:01.63,Default,,0,0,0,,为了翻译完整 这还里有种情况 Dialogue: 0,0:36:02.88,0:36:05.95,Default,,0,0,0,,(MERGE-TO-FORM (?A . ?X) (?B . ?Y) (?A . ?Z))成立 Dialogue: 0,0:36:06.08,0:36:09.16,Default,,0,0,0,,就需要(MERGE-TO-FORM ?X (?B . ?Y) ?Z) Dialogue: 0,0:36:09.47,0:36:11.00,Default,,0,0,0,,和(LISP-VALUE > ?B ?A)都成立 Dialogue: 0,0:36:12.19,0:36:15.98,Default,,0,0,0,,我已经把这个用逻辑语言编写的小程序输入计算机了 Dialogue: 0,0:36:16.01,0:36:17.07,Default,,0,0,0,,现在让我们来试着运行一下 Dialogue: 0,0:36:21.90,0:36:23.90,Default,,0,0,0,,由于我已经输入过MERGE-TO-FORM的规则了 Dialogue: 0,0:36:24.62,0:36:25.77,Default,,0,0,0,,我就可以 Dialogue: 0,0:36:27.04,0:36:28.51,Default,,0,0,0,,我可以像过程一样使用它 Dialogue: 0,0:36:28.51,0:36:38.24,Default,,0,0,0,,我可以问(MERGE-TO-FORM (1 3) (2 7) ?X) Dialogue: 0,0:36:39.42,0:36:41.55,Default,,0,0,0,,这里 我把它当作一个Lisp过程来使用 Dialogue: 0,0:36:43.16,0:36:44.97,Default,,0,0,0,,它先会思考一会儿 Dialogue: 0,0:36:46.43,0:36:47.56,Default,,0,0,0,,然后应用这些规则 Dialogue: 0,0:36:50.78,0:36:51.92,Default,,0,0,0,,它找到了一个答案 Dialogue: 0,0:36:52.80,0:36:54.54,Default,,0,0,0,,现在它还要继续寻找其它的答案 Dialogue: 0,0:36:55.07,0:36:57.32,Default,,0,0,0,,因为它事先不知道这里答案只有一个 Dialogue: 0,0:36:57.81,0:36:59.90,Default,,0,0,0,,因此它就在这里检查所有的可能性 Dialogue: 0,0:37:00.41,0:37:02.54,Default,,0,0,0,,确认没有后 输出'DONE' Dialogue: 0,0:37:03.16,0:37:05.07,Default,,0,0,0,,这里 我把它们当作过程来使用 Dialogue: 0,0:37:05.21,0:37:09.05,Default,,0,0,0,,不过要注意 我还可以问不同类型的问题 Dialogue: 0,0:37:10.22,0:37:11.07,Default,,0,0,0,,我可以问 Dialogue: 0,0:37:18.56,0:37:24.59,Default,,0,0,0,,(MERGE-TO-FORM (2 ?A) Dialogue: 0,0:37:24.59,0:37:27.90,Default,,0,0,0,,一个我已知是以2为首的二元表 Dialogue: 0,0:37:29.37,0:37:31.26,Default,,0,0,0,,而另外一个东西是未知的 Dialogue: 0,0:37:33.05,0:37:35.04,Default,,0,0,0,,用?X来表示这个未知的表 Dialogue: 0,0:37:36.48,0:37:39.51,Default,,0,0,0,,可以通过MERGE-TO-FORM形成(1 2 3 4) Dialogue: 0,0:37:42.76,0:37:44.11,Default,,0,0,0,,现在它将思考这个问题 Dialogue: 0,0:37:44.59,0:37:49.40,Default,,0,0,0,,它会找到 -- 它找到了一种可能 Dialogue: 0,0:37:49.52,0:37:52.46,Default,,0,0,0,,比如A=3 X=(1 4) Dialogue: 0,0:37:53.72,0:37:55.16,Default,,0,0,0,,现在 它又要继续检查 Dialogue: 0,0:37:56.56,0:37:57.71,Default,,0,0,0,,因为它事先并不知道 Dialogue: 0,0:37:57.74,0:38:00.30,Default,,0,0,0,,这里并没有其它的可能了 Dialogue: 0,0:38:03.68,0:38:06.57,Default,,0,0,0,,或者 就像我说过的 Dialogue: 0,0:38:07.00,0:38:09.84,Default,,0,0,0,,我可以问 Dialogue: 0,0:38:10.54,0:38:17.55,Default,,0,0,0,,能够通过MERGE-TO-FORM形成(1 2 3 4 5)的?X和?Y分别是什么? Dialogue: 0,0:38:23.68,0:38:25.53,Default,,0,0,0,,语言系统又要思考这个问题 Dialogue: 0,0:38:28.49,0:38:30.31,Default,,0,0,0,,它可能会得到很多答案 Dialogue: 0,0:38:35.18,0:38:38.57,Default,,0,0,0,,这里我们就体会到了缓慢的代价 Dialogue: 0,0:38:42.21,0:38:43.88,Default,,0,0,0,,大概是有三种原因造成这样 Dialogue: 0,0:38:43.88,0:38:46.22,Default,,0,0,0,,首先 这门语言经过了两次解释 Dialogue: 0,0:38:47.63,0:38:49.72,Default,,0,0,0,,然而在真正的实现中 Dialogue: 0,0:38:49.76,0:38:52.04,Default,,0,0,0,,你应该把这些编译成基本运算 Dialogue: 0,0:38:52.19,0:38:53.87,Default,,0,0,0,,其次就是 Dialogue: 0,0:38:53.88,0:38:58.11,Default,,0,0,0,,这个MERGE算法 是双重递归的 Dialogue: 0,0:38:58.38,0:39:00.06,Default,,0,0,0,,因此它需要花费很长的时间 Dialogue: 0,0:39:01.02,0:39:04.33,Default,,0,0,0,,最后呢 它又要遍历所有的情况 Dialogue: 0,0:39:04.59,0:39:07.13,Default,,0,0,0,,找出 -- 找出什么呢? Dialogue: 0,0:39:07.13,0:39:08.73,Default,,0,0,0,,所有的2^5种可行解 Dialogue: 0,0:39:12.14,0:39:14.96,Default,,0,0,0,,我们发现它们以某种相当随意的顺序输出 Dialogue: 0,0:39:15.00,0:39:18.14,Default,,0,0,0,,这取决于它们用什么样的顺序尝试这些规则 Dialogue: 0,0:39:20.16,0:39:22.11,Default,,0,0,0,,事实上 在后期制作本视频时 Dialogue: 0,0:39:22.40,0:39:23.48,Default,,0,0,0,,我们将加速这段 Dialogue: 0,0:39:24.08,0:39:26.60,Default,,0,0,0,,我们就不再这里浪费时间了 Dialogue: 0,0:39:26.60,0:39:28.27,Default,,0,0,0,,课后你们可以自行尝试 Dialogue: 0,0:39:29.48,0:39:34.24,Default,,0,0,0,,好吧 它还在运行 Dialogue: 0,0:39:39.22,0:39:41.12,Default,,0,0,0,,总之 一共有32种可能 Dialogue: 0,0:39:41.13,0:39:42.63,Default,,0,0,0,,我们就不等到输出所有的结果了 Dialogue: 0,0:39:47.85,0:39:50.44,Default,,0,0,0,,因此 这门语言中的抽象手段就是RULE Dialogue: 0,0:39:53.53,0:39:58.01,Default,,0,0,0,,我们用逻辑把事物组织在一起 Dialogue: 0,0:39:59.12,0:40:00.08,Default,,0,0,0,,并为它们命名 Dialogue: 0,0:40:00.35,0:40:03.41,Default,,0,0,0,,你们可以认为这是为一组特定的逻辑模式命名 Dialogue: 0,0:40:03.41,0:40:04.54,Default,,0,0,0,,你们可以把它想做 Dialogue: 0,0:40:04.56,0:40:06.75,Default,,0,0,0,,如果我们想要推断出某个结论 Dialogue: 0,0:40:07.90,0:40:09.52,Default,,0,0,0,,就可以应用这些逻辑规则 Dialogue: 0,0:40:10.66,0:40:13.20,Default,,0,0,0,,这些就是这门语言中的三种要素 Dialogue: 0,0:40:13.42,0:40:14.56,Default,,0,0,0,,我们先休息一会儿 Dialogue: 0,0:40:14.60,0:40:16.59,Default,,0,0,0,,然后再来讨论如何实际实现 Dialogue: 0,0:40:23.61,0:40:28.84,Default,,0,0,0,,学生:使用LISP-VALUE之类的基本过程会影响 Dialogue: 0,0:40:29.15,0:40:30.64,Default,,0,0,0,,查询的双向性吗? Dialogue: 0,0:40:31.77,0:40:34.48,Default,,0,0,0,,教授:这个问题 -- 你问的是 Dialogue: 0,0:40:35.08,0:40:36.92,Default,,0,0,0,,使用LISP-VALUE是否会影响 Dialogue: 0,0:40:37.53,0:40:40.09,Default,,0,0,0,,双向地推断一条查询 Dialogue: 0,0:40:40.09,0:40:42.81,Default,,0,0,0,,虽然我们还没有实际讨论具体实现 Dialogue: 0,0:40:43.68,0:40:45.52,Default,,0,0,0,,但是它们确实会造成影响 Dialogue: 0,0:40:46.89,0:40:50.20,Default,,0,0,0,,通常来说 我们最后将会发现 Dialogue: 0,0:40:50.22,0:40:52.17,Default,,0,0,0,,虽然我不会讲得太细 Dialogue: 0,0:40:53.21,0:40:59.36,Default,,0,0,0,,当你使用NOT和LISP-VALUE时 会变得相当复杂 Dialogue: 0,0:40:59.55,0:41:02.89,Default,,0,0,0,,或者实际上 只要你用了除AND以外的东西 Dialogue: 0,0:41:04.12,0:41:08.19,Default,,0,0,0,,很难再说清楚这些东西是否会起效了 Dialogue: 0,0:41:08.20,0:41:10.36,Default,,0,0,0,,它们并不是在任何情况下都有效 Dialogue: 0,0:41:10.36,0:41:13.39,Default,,0,0,0,,我会在下一堂课的最后讨论这个问题 Dialogue: 0,0:41:14.30,0:41:15.84,Default,,0,0,0,,但对于你的问题来说:答案是“会影响” Dialogue: 0,0:41:16.19,0:41:19.21,Default,,0,0,0,,用LISP-VALUE一方面从Lisp中获得了巨大威力 Dialogue: 0,0:41:19.40,0:41:23.77,Default,,0,0,0,,另一方面你失去了逻辑式程序设计的重要威力 Dialogue: 0,0:41:24.17,0:41:25.56,Default,,0,0,0,,这是你需要做出的取舍 Dialogue: 0,0:41:28.48,0:41:29.39,Default,,0,0,0,,好吧 先休息一会儿 Dialogue: 0,0:41:30.17,0:41:44.30,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:41:30.17,0:41:44.30,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec8a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:02.67,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP学习小组\N倾情制作 Dialogue: 0,0:00:02.70,0:00:10.27,title,,0,0,0,,{\fad(600,800)\pos(324,32)}计算机程序的构造和解释 Dialogue: 0,0:00:02.70,0:00:10.27,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.70,0:00:10.27,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.70,0:00:10.27,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.70,0:00:10.27,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:10.28,0:00:15.24,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 I Dialogue: 0,0:00:18.27,0:00:19.68,Default,,0,0,0,,教授:上节课中 我们学习了 Dialogue: 0,0:00:19.72,0:00:21.26,Default,,0,0,0,,如何构造语言 Dialogue: 0,0:00:22.41,0:00:25.88,Default,,0,0,0,,核心点就是 像Lisp这样的求值器 Dialogue: 0,0:00:26.08,0:00:27.58,Default,,0,0,0,,有两个主要部分 Dialogue: 0,0:00:27.58,0:00:28.40,Default,,0,0,0,,一个是EVAL Dialogue: 0,0:00:31.04,0:00:37.42,Default,,0,0,0,,EVAL接受一个表达式EXP和环境ENV Dialogue: 0,0:00:38.91,0:00:44.44,Default,,0,0,0,,然后返回一个过程和相关的实际参数 Dialogue: 0,0:00:45.42,0:00:47.05,Default,,0,0,0,,并把它们传递给APPLY Dialogue: 0,0:00:49.41,0:00:51.29,Default,,0,0,0,,APPLY接收这些过程和实际参数 Dialogue: 0,0:00:51.69,0:00:55.12,Default,,0,0,0,,通常来说 APPLY会返回另一个表达式 Dialogue: 0,0:00:55.39,0:00:57.71,Default,,0,0,0,,返回一个在其它环境中求值的表达式 Dialogue: 0,0:00:57.74,0:01:00.00,Default,,0,0,0,,表达式就像这样在EVAL-APPLY之间传递 Dialogue: 0,0:01:00.27,0:01:01.44,Default,,0,0,0,,这就是整个元循环 Dialogue: 0,0:01:01.47,0:01:02.94,Default,,0,0,0,,表达式在这里面循环往复 Dialogue: 0,0:01:03.02,0:01:06.56,Default,,0,0,0,,直到最后求值为基本数据或基本过程 Dialogue: 0,0:01:07.74,0:01:09.24,Default,,0,0,0,,这个循环要做的就是 Dialogue: 0,0:01:09.44,0:01:12.57,Default,,0,0,0,,把语言中的组合手段 Dialogue: 0,0:01:12.59,0:01:14.36,Default,,0,0,0,,和抽象手段展开 Dialogue: 0,0:01:15.02,0:01:17.72,Default,,0,0,0,,比如说在Lisp中 你有一个过程 Dialogue: 0,0:01:17.74,0:01:20.52,Default,,0,0,0,,定义过程是为了 Dialogue: 0,0:01:20.54,0:01:22.57,Default,,0,0,0,,让表达式的计算过程 Dialogue: 0,0:01:22.67,0:01:24.41,Default,,0,0,0,,适用于任意的参数 Dialogue: 0,0:01:25.76,0:01:27.18,Default,,0,0,0,,这就是这里面发生的事情 Dialogue: 0,0:01:27.67,0:01:28.51,Default,,0,0,0,,这就是APPLY做的事 Dialogue: 0,0:01:28.51,0:01:30.68,Default,,0,0,0,,当一个带参数的一般性表达式进入以后 Dialogue: 0,0:01:30.72,0:01:32.70,Default,,0,0,0,,它将其归约为过程体的表达式 Dialogue: 0,0:01:33.05,0:01:34.72,Default,,0,0,0,,如果归约得到的是复合表达式 Dialogue: 0,0:01:34.83,0:01:36.46,Default,,0,0,0,,或者是另外的过程应用 Dialogue: 0,0:01:36.78,0:01:38.44,Default,,0,0,0,,那么这个循环就会不断地进行 Dialogue: 0,0:01:40.33,0:01:44.08,Default,,0,0,0,,这基本上就是 -- 大部分解释器的基本结构了 Dialogue: 0,0:01:45.20,0:01:46.25,Default,,0,0,0,,另外一点就是 Dialogue: 0,0:01:46.28,0:01:47.66,Default,,0,0,0,,一旦你有了一个解释器 Dialogue: 0,0:01:47.69,0:01:49.87,Default,,0,0,0,,你就有了操作这门语言的所有能力 Dialogue: 0,0:01:49.87,0:01:51.52,Default,,0,0,0,,因此你可以让它成为动态作用域 Dialogue: 0,0:01:51.84,0:01:54.56,Default,,0,0,0,,你也可以引入正则序求值 Dialogue: 0,0:01:54.59,0:01:56.48,Default,,0,0,0,,你也可以为语言添加新的形式 Dialogue: 0,0:01:56.86,0:01:57.50,Default,,0,0,0,,想怎么样都行 Dialogue: 0,0:01:57.58,0:01:58.62,Default,,0,0,0,,或者更一般地说 Dialogue: 0,0:01:58.76,0:02:01.32,Default,,0,0,0,,这种元语言抽象的概念 Dialogue: 0,0:02:02.64,0:02:06.01,Default,,0,0,0,,它告诉我们 作为一名软件工程师 Dialogue: 0,0:02:07.61,0:02:10.52,Default,,0,0,0,,从广义的“工程师”的角度来看 Dialogue: 0,0:02:11.39,0:02:13.88,Default,,0,0,0,,有时你可以通过发明新的语言 Dialogue: 0,0:02:14.96,0:02:17.16,Default,,0,0,0,,来获得控制复杂度的能力 Dialogue: 0,0:02:18.01,0:02:20.81,Default,,0,0,0,,一种思考计算机程序设计的方法就是 Dialogue: 0,0:02:21.55,0:02:26.27,Default,,0,0,0,,它只是偶然地让计算机执行某事儿 Dialogue: 0,0:02:26.44,0:02:28.97,Default,,0,0,0,,计算机程序的主要工作却是 Dialogue: 0,0:02:29.00,0:02:32.52,Default,,0,0,0,,用来表达和交换想法 Dialogue: 0,0:02:33.16,0:02:34.04,Default,,0,0,0,,有时 Dialogue: 0,0:02:34.89,0:02:36.62,Default,,0,0,0,,当我们想要表达新的想法时 Dialogue: 0,0:02:36.65,0:02:38.73,Default,,0,0,0,,我们就想要发明新的模式来表达它们 Dialogue: 0,0:02:39.82,0:02:44.99,Default,,0,0,0,,那么 今天我们就将按照这个框架来创建新语言 Dialogue: 0,0:02:45.73,0:02:48.00,Default,,0,0,0,,一旦我们了解了解释器的基本结构 Dialogue: 0,0:02:48.03,0:02:50.27,Default,,0,0,0,,我们就可以按意愿来构造任意的语言 Dialogue: 0,0:02:50.83,0:02:53.21,Default,,0,0,0,,比如说 我们可以构造Pascal(的解释器) Dialogue: 0,0:02:54.37,0:02:55.15,Default,,0,0,0,,以及 Dialogue: 0,0:02:56.17,0:02:58.19,Default,,0,0,0,,我们需要操心语法的表示与解析 Dialogue: 0,0:02:58.19,0:03:00.51,Default,,0,0,0,,还有一大堆的编译器优化 Dialogue: 0,0:03:01.12,0:03:03.29,Default,,0,0,0,,还有一些人会这样做 Dialogue: 0,0:03:03.85,0:03:07.60,Default,,0,0,0,,但是就在我们所讨论的抽象层次来说 Dialogue: 0,0:03:08.04,0:03:10.99,Default,,0,0,0,,一个Pascal语言的解释器看起来 Dialogue: 0,0:03:12.03,0:03:13.76,Default,,0,0,0,,跟Gerry教授上节课所讲的大同小异 Dialogue: 0,0:03:15.02,0:03:18.96,Default,,0,0,0,,但是今天 我们要构建一门与众不同的语言 Dialogue: 0,0:03:20.51,0:03:22.81,Default,,0,0,0,,这门语言 Dialogue: 0,0:03:23.05,0:03:26.04,Default,,0,0,0,,不推荐你用过程式的思维来思考程序设计 Dialogue: 0,0:03:26.24,0:03:27.64,Default,,0,0,0,,而是用一种非常不同的方式 Dialogue: 0,0:03:29.09,0:03:31.02,Default,,0,0,0,,今天的课程呢 Dialogue: 0,0:03:31.74,0:03:34.64,Default,,0,0,0,,将会在两个层次中同时进行 Dialogue: 0,0:03:34.81,0:03:35.52,Default,,0,0,0,,一方面 Dialogue: 0,0:03:35.90,0:03:37.71,Default,,0,0,0,,我会向大家介绍这门语言是如何使用的 Dialogue: 0,0:03:38.96,0:03:41.08,Default,,0,0,0,,另一方面呢 我会带领大家实现这门语言 Dialogue: 0,0:03:41.32,0:03:42.96,Default,,0,0,0,,我们将会用Lisp来实现 Dialogue: 0,0:03:42.99,0:03:43.90,Default,,0,0,0,,并观察它的运行原理 Dialogue: 0,0:03:44.04,0:03:48.25,Default,,0,0,0,,你应该在两个层次上学到知识 Dialogue: 0,0:03:48.68,0:03:53.00,Default,,0,0,0,,首先要认识到 语言之间可以有多么地“不同” Dialogue: 0,0:03:53.79,0:03:58.14,Default,,0,0,0,,如果你认为Fortran和Lisp算是天差地别的话 Dialogue: 0,0:03:58.24,0:03:59.36,Default,,0,0,0,,那就小巫见大巫了 Dialogue: 0,0:04:01.56,0:04:03.68,Default,,0,0,0,,其次 Dialogue: 0,0:04:03.77,0:04:06.54,Default,,0,0,0,,甚至于在这门与众不同的语言中 Dialogue: 0,0:04:07.36,0:04:09.52,Default,,0,0,0,,这门既不讨论函数 Dialogue: 0,0:04:09.92,0:04:11.64,Default,,0,0,0,,也没有过程的语言中 Dialogue: 0,0:04:12.20,0:04:15.72,Default,,0,0,0,,其中也有基本的EVAL-APPLY循环 Dialogue: 0,0:04:16.19,0:04:19.98,Default,,0,0,0,,也就是对组合手段和抽象手段的展开 Dialogue: 0,0:04:20.95,0:04:24.68,Default,,0,0,0,,第三点 是一个不太重要但非常优雅的技术技巧 Dialogue: 0,0:04:24.89,0:04:28.52,Default,,0,0,0,,就是如何巧妙地使用流来避免回溯 Dialogue: 0,0:04:32.33,0:04:34.40,Default,,0,0,0,,好吧 我说过这门语言与众不同 Dialogue: 0,0:04:35.86,0:04:36.64,Default,,0,0,0,,为了解释这点 Dialogue: 0,0:04:37.05,0:04:42.81,Default,,0,0,0,,让我们回到这门课最初的理念上 Dialogue: 0,0:04:43.26,0:04:46.54,Default,,0,0,0,,就是要区别 Dialogue: 0,0:04:46.72,0:04:49.52,Default,,0,0,0,,数学中“陈述性”的知识 Dialogue: 0,0:04:50.19,0:04:54.14,Default,,0,0,0,,比如平方根的定义就是一条数学事实 Dialogue: 0,0:04:55.48,0:04:59.56,Default,,0,0,0,,而计算机科学讨论的是“如何做”的知识 Dialogue: 0,0:04:59.76,0:05:04.59,Default,,0,0,0,,“什么是平方根”和“如何计算平方根”是不同的 Dialogue: 0,0:05:05.97,0:05:07.07,Default,,0,0,0,,我们是从这里开始的 Dialogue: 0,0:05:08.51,0:05:09.52,Default,,0,0,0,,如果我们能够通过某种方式 Dialogue: 0,0:05:09.88,0:05:12.16,Default,,0,0,0,,弥合这种差距 岂不是更好么? Dialogue: 0,0:05:12.81,0:05:16.43,Default,,0,0,0,,我们创建一门这样的语言 Dialogue: 0,0:05:16.67,0:05:21.61,Default,,0,0,0,,以声明式的方式、用数学事实来完成计算 Dialogue: 0,0:05:22.38,0:05:25.50,Default,,0,0,0,,你用这种该语言来指定事实 Dialogue: 0,0:05:27.69,0:05:28.88,Default,,0,0,0,,你告诉它 Dialogue: 0,0:05:28.88,0:05:29.96,Default,,0,0,0,,什么是事实 Dialogue: 0,0:05:30.95,0:05:33.07,Default,,0,0,0,,而当你需要一个答案时 Dialogue: 0,0:05:33.21,0:05:36.38,Default,,0,0,0,,语言已经自动地内建了 Dialogue: 0,0:05:37.60,0:05:39.45,Default,,0,0,0,,有关于“如何做”的一般性知识 Dialogue: 0,0:05:39.47,0:05:40.64,Default,,0,0,0,,这样它就可以根据你给出的事实 Dialogue: 0,0:05:40.89,0:05:42.83,Default,,0,0,0,,自行地演进这些方法 Dialogue: 0,0:05:43.31,0:05:46.12,Default,,0,0,0,,通过你给定的事实和某种一般性的逻辑规则 Dialogue: 0,0:05:49.33,0:05:50.54,Default,,0,0,0,,就比如说 Dialogue: 0,0:05:52.06,0:05:55.12,Default,,0,0,0,,我会告诉程序下述事实 Dialogue: 0,0:05:56.00,0:06:07.08,Default,,0,0,0,,我告诉它 (SON-OF ADAM ABEL) Dialogue: 0,0:06:08.92,0:06:16.51,Default,,0,0,0,,同时告诉它 (SON-OF ADAM CAIN) Dialogue: 0,0:06:17.66,0:06:25.08,Default,,0,0,0,,以及 (SON-OF CAIN ENOCH) Dialogue: 0,0:06:27.79,0:06:34.89,Default,,0,0,0,,还有 (SON-OF ENOCH IRAD) Dialogue: 0,0:06:37.02,0:06:40.72,Default,,0,0,0,,以及《创世纪》章节中的其它人物 Dialogue: 0,0:06:41.15,0:06:43.18,Default,,0,0,0,,最后终止于ADAH Dialogue: 0,0:06:43.32,0:06:46.78,Default,,0,0,0,,这些是从ADAH到CAIN的家谱 Dialogue: 0,0:06:48.44,0:06:50.67,Default,,0,0,0,,总之 一旦你指明了这些事实 Dialogue: 0,0:06:52.35,0:06:53.40,Default,,0,0,0,,你就可以提出问题 Dialogue: 0,0:06:53.51,0:06:55.05,Default,,0,0,0,,你可以对语言系统发问 Dialogue: 0,0:06:56.06,0:06:59.29,Default,,0,0,0,,谁是ADAM的孩子? Dialogue: 0,0:07:00.42,0:07:04.91,Default,,0,0,0,,可以很容易地想到一个通用搜索程序 Dialogue: 0,0:07:05.52,0:07:06.96,Default,,0,0,0,,它会遍历所有的事实 Dialogue: 0,0:07:07.00,0:07:09.26,Default,,0,0,0,,然后回答:“哦 有两个答案” Dialogue: 0,0:07:09.29,0:07:10.44,Default,,0,0,0,,ABEL是ADAM的孩子 Dialogue: 0,0:07:10.68,0:07:12.17,Default,,0,0,0,,CAIN也是ADAM的孩子 Dialogue: 0,0:07:14.14,0:07:14.97,Default,,0,0,0,,你也可以这样问 Dialogue: 0,0:07:15.07,0:07:16.89,Default,,0,0,0,,基于同样的事实 Dialogue: 0,0:07:18.04,0:07:19.95,Default,,0,0,0,,CAIN是谁的孩子? Dialogue: 0,0:07:21.95,0:07:27.02,Default,,0,0,0,,你们就会想到生成另外一个略微不同的搜索程序 Dialogue: 0,0:07:27.92,0:07:29.21,Default,,0,0,0,,它也会遍历所有的事实 Dialogue: 0,0:07:29.45,0:07:33.05,Default,,0,0,0,,检查谁的孩子是CAIN Dialogue: 0,0:07:33.52,0:07:34.44,Default,,0,0,0,,发现结果是ADAM Dialogue: 0,0:07:35.89,0:07:36.99,Default,,0,0,0,,你也可以问 Dialogue: 0,0:07:38.01,0:07:41.40,Default,,0,0,0,,CAIN和ENOCH之间是什么关系? Dialogue: 0,0:07:42.07,0:07:45.08,Default,,0,0,0,,又会生成另一个略微不同的搜索程序 Dialogue: 0,0:07:46.34,0:07:48.16,Default,,0,0,0,,得到的结果是亲子关系(SON-OF) Dialogue: 0,0:07:52.88,0:07:54.92,Default,,0,0,0,,在这个非常简单的例子中 Dialogue: 0,0:07:56.14,0:07:58.44,Default,,0,0,0,,我们发现 即使是单条事实 Dialogue: 0,0:07:58.81,0:08:01.52,Default,,0,0,0,,比如说 (SON-OF ADAM CAIN) Dialogue: 0,0:08:02.84,0:08:05.52,Default,,0,0,0,,可以被用来回答不同种类的问题 Dialogue: 0,0:08:06.52,0:08:08.12,Default,,0,0,0,,你可以问CAIN是谁的孩子? Dialogue: 0,0:08:08.14,0:08:10.92,Default,,0,0,0,,你也可以问ADAM的孩子是谁? Dialogue: 0,0:08:10.94,0:08:12.86,Default,,0,0,0,,你也可以问ADAM和CAIN之间的关系是什么? Dialogue: 0,0:08:12.88,0:08:14.48,Default,,0,0,0,,这些由不同的传统程序 Dialogue: 0,0:08:15.53,0:08:18.54,Default,,0,0,0,,所解答的不同的问题 Dialogue: 0,0:08:18.68,0:08:20.72,Default,,0,0,0,,都基于同样的事实 Dialogue: 0,0:08:22.75,0:08:25.92,Default,,0,0,0,,这正是这种程序设计风格的威力所在 Dialogue: 0,0:08:26.91,0:08:29.50,Default,,0,0,0,,也就是一条陈述性知识 Dialogue: 0,0:08:30.04,0:08:34.01,Default,,0,0,0,,可以作为大量关于“如何做”的各种知识的基础 Dialogue: 0,0:08:34.81,0:08:37.08,Default,,0,0,0,,这跟我们正在编写的过程是不同的 Dialogue: 0,0:08:37.15,0:08:39.55,Default,,0,0,0,,我们编写的过程描述了输入 Dialogue: 0,0:08:39.61,0:08:40.65,Default,,0,0,0,,以及想要的输出 Dialogue: 0,0:08:41.49,0:08:44.70,Default,,0,0,0,,比如说 我们的平方根程序可以完美地回答 Dialogue: 0,0:08:44.76,0:08:47.16,Default,,0,0,0,,144的平方根是多少? Dialogue: 0,0:08:48.90,0:08:49.77,Default,,0,0,0,,但从原理上来说 Dialogue: 0,0:08:49.82,0:08:52.83,Default,,0,0,0,,平方根的数学定义告诉了你另外的东西 Dialogue: 0,0:08:52.84,0:08:56.43,Default,,0,0,0,,就比如说 17是谁的平方根 Dialogue: 0,0:08:57.59,0:08:59.71,Default,,0,0,0,,这就需要另外一个程序来解答 Dialogue: 0,0:09:01.92,0:09:03.50,Default,,0,0,0,,因此 数学定义 Dialogue: 0,0:09:03.98,0:09:05.12,Default,,0,0,0,,或者更一般地说 Dialogue: 0,0:09:05.53,0:09:10.30,Default,,0,0,0,,你给定的事实 对于问题是没有偏向性的 Dialogue: 0,0:09:10.90,0:09:12.81,Default,,0,0,0,,而我们倾向于编写专门的程序 Dialogue: 0,0:09:12.83,0:09:14.20,Default,,0,0,0,,因为它们是关于“如何做”的知识 Dialogue: 0,0:09:14.24,0:09:16.36,Default,,0,0,0,,倾向于寻找特定的答案 Dialogue: 0,0:09:17.56,0:09:20.12,Default,,0,0,0,,所以这是我们正在讨论的一个特点 Dialogue: 0,0:09:21.81,0:09:22.60,Default,,0,0,0,,然而我们可以更进一步 Dialogue: 0,0:09:23.48,0:09:27.52,Default,,0,0,0,,想象一下 我们可以向语言给定一些事实 Dialogue: 0,0:09:27.71,0:09:29.61,Default,,0,0,0,,现在 我们给它一些推理规则 Dialogue: 0,0:09:30.02,0:09:31.36,Default,,0,0,0,,比如说 Dialogue: 0,0:09:31.95,0:09:36.19,Default,,0,0,0,,这里 我们先用某种语法表示 Dialogue: 0,0:09:36.44,0:09:41.53,Default,,0,0,0,,如果(SON-OF ?X ?Y)成立 Dialogue: 0,0:09:41.68,0:09:45.21,Default,,0,0,0,,在这里 我用问号来标识变量 Dialogue: 0,0:09:45.61,0:09:56.06,Default,,0,0,0,,如果(SON-OF ?X ?Y)和(SON-OF ?Y ?Z)都成立 Dialogue: 0,0:09:58.96,0:10:08.46,Default,,0,0,0,,那么就有(GRANSON ?X ?Z) Dialogue: 0,0:10:09.32,0:10:13.40,Default,,0,0,0,,想象一下 如果把这条规则告诉机器 Dialogue: 0,0:10:15.00,0:10:17.28,Default,,0,0,0,,那么我们就可以这么来询问 Dialogue: 0,0:10:17.44,0:10:18.68,Default,,0,0,0,,谁是ADAM的孙子? Dialogue: 0,0:10:20.61,0:10:23.64,Default,,0,0,0,,或者说 IRAD是谁的孙子? Dialogue: 0,0:10:24.79,0:10:29.08,Default,,0,0,0,,或者从这些信息中尽可能地推断出所有的祖孙关系 Dialogue: 0,0:10:31.13,0:10:35.60,Default,,0,0,0,,我们可以想象 语言知道如何自动求解 Dialogue: 0,0:10:40.22,0:10:45.20,Default,,0,0,0,,好吧 我再举一个更具体一点的例子 Dialogue: 0,0:10:45.77,0:10:51.95,Default,,0,0,0,,这是个用来合并两个有序表的过程 Dialogue: 0,0:10:53.92,0:11:00.27,Default,,0,0,0,,X和Y是两个由数字构成的表 Dialogue: 0,0:11:00.30,0:11:04.20,Default,,0,0,0,,我们可以认为它们是严格升序的表 Dialogue: 0,0:11:04.76,0:11:07.53,Default,,0,0,0,,MERGE会把这两个表 Dialogue: 0,0:11:07.71,0:11:10.38,Default,,0,0,0,,合并成一个有序的表 Dialogue: 0,0:11:11.21,0:11:15.00,Default,,0,0,0,,这个程序非常简单 Dialogue: 0,0:11:15.02,0:11:16.14,Default,,0,0,0,,你们可以轻松地写出来 Dialogue: 0,0:11:16.39,0:11:18.64,Default,,0,0,0,,也就是 如果X为空 那么结果就是Y Dialogue: 0,0:11:18.86,0:11:20.46,Default,,0,0,0,,如果Y为空 那结果就是X Dialogue: 0,0:11:21.18,0:11:22.99,Default,,0,0,0,,否则的话 就要比较为首的两个元素 Dialogue: 0,0:11:22.99,0:11:24.46,Default,,0,0,0,,取出X中的第一个元素 Dialogue: 0,0:11:24.84,0:11:26.01,Default,,0,0,0,,以及Y中的第一个元素 Dialogue: 0,0:11:26.81,0:11:31.68,Default,,0,0,0,,把它们当中谁是最小的那一个 Dialogue: 0,0:11:32.83,0:11:36.60,Default,,0,0,0,,CONS在递归地调用MERGE的结果上 Dialogue: 0,0:11:37.87,0:11:39.92,Default,,0,0,0,,要么就是(MERGE (CDR X) Y) Dialogue: 0,0:11:40.11,0:11:41.61,Default,,0,0,0,,要么就是(MERGE X (CDR Y)) Dialogue: 0,0:11:42.40,0:11:43.96,Default,,0,0,0,,这是标准的程序 Dialogue: 0,0:11:46.47,0:11:48.41,Default,,0,0,0,,我们来考察下其中的逻辑 Dialogue: 0,0:11:48.62,0:11:49.79,Default,,0,0,0,,先不考虑程序 Dialogue: 0,0:11:50.28,0:11:52.76,Default,,0,0,0,,来看看这个过程所基于的逻辑 Dialogue: 0,0:11:53.82,0:11:55.00,Default,,0,0,0,,这其中的逻辑是 Dialogue: 0,0:11:55.02,0:11:57.21,Default,,0,0,0,,如果第一个元素较小 Dialogue: 0,0:11:57.53,0:12:00.00,Default,,0,0,0,,那么最后的结果就是把它 Dialogue: 0,0:12:00.16,0:12:02.12,Default,,0,0,0,,跟递归MERGE的结果CONS起来 Dialogue: 0,0:12:02.84,0:12:04.09,Default,,0,0,0,,让我们试着把 Dialogue: 0,0:12:04.24,0:12:06.41,Default,,0,0,0,,使这个程序运作的逻辑说清楚一点 Dialogue: 0,0:12:08.30,0:12:09.44,Default,,0,0,0,,这是一部分 Dialogue: 0,0:12:10.13,0:12:11.53,Default,,0,0,0,,这段程序 Dialogue: 0,0:12:12.64,0:12:15.26,Default,,0,0,0,,递归地剥离X Dialogue: 0,0:12:15.66,0:12:17.82,Default,,0,0,0,,如果X中的首元素较小的话 Dialogue: 0,0:12:19.98,0:12:22.54,Default,,0,0,0,,如果要显式地指出其中的逻辑的话 Dialogue: 0,0:12:23.45,0:12:26.49,Default,,0,0,0,,它其实就是演绎推理 Dialogue: 0,0:12:26.72,0:12:32.38,Default,,0,0,0,,其中 如果知道表CDR-X和表Y Dialogue: 0,0:12:33.29,0:12:35.44,Default,,0,0,0,,能够通过MERGE-TO-FORM形成Z Dialogue: 0,0:12:37.84,0:12:41.52,Default,,0,0,0,,并且还知道A比Y中的第一个元素小 Dialogue: 0,0:12:43.60,0:12:48.52,Default,,0,0,0,,那么你就知道 如果你把A和CDR-X给CONS起来 Dialogue: 0,0:12:49.74,0:12:51.85,Default,,0,0,0,,得到的结果和Y一起 Dialogue: 0,0:12:52.60,0:12:54.99,Default,,0,0,0,,可以通过MERGE-TO-FORM形成Z Dialogue: 0,0:12:55.82,0:12:58.09,Default,,0,0,0,,这就是它所基于的逻辑 Dialogue: 0,0:12:58.72,0:12:59.95,Default,,0,0,0,,我没有把它写成程序 Dialogue: 0,0:12:59.96,0:13:02.00,Default,,0,0,0,,我把它写成了某种演绎 Dialogue: 0,0:13:02.03,0:13:04.89,Default,,0,0,0,,正是属于这个特定子句的 Dialogue: 0,0:13:05.21,0:13:07.26,Default,,0,0,0,,它告诉我们可以在这里使用递归 Dialogue: 0,0:13:09.41,0:13:12.78,Default,,0,0,0,,同样地 这里还有些句子来补全其中的逻辑 Dialogue: 0,0:13:14.00,0:13:15.87,Default,,0,0,0,,其它的句子都是基于这些逻辑 Dialogue: 0,0:13:15.92,0:13:18.35,Default,,0,0,0,,由于它们大部分是相同的 我就不细讲了 Dialogue: 0,0:13:19.00,0:13:20.35,Default,,0,0,0,,然后就是终止条件 Dialogue: 0,0:13:20.41,0:13:22.01,Default,,0,0,0,,是用来检查NULL的 Dialogue: 0,0:13:22.03,0:13:24.04,Default,,0,0,0,,其基本想法是 对于任意的X Dialogue: 0,0:13:24.51,0:13:27.20,Default,,0,0,0,,X和空表可以通过MERGE-TO-FORM形成X Dialogue: 0,0:13:28.04,0:13:30.86,Default,,0,0,0,,而空表可以和任意的Y通过MERGE-TO-FORM形成Y Dialogue: 0,0:13:33.36,0:13:38.12,Default,,0,0,0,,这就是一段过程的代码 Dialogue: 0,0:13:38.43,0:13:40.11,Default,,0,0,0,,以及它所基于的逻辑 Dialogue: 0,0:13:41.74,0:13:42.97,Default,,0,0,0,,请注意其中的巨大差异 Dialogue: 0,0:13:45.10,0:13:50.52,Default,,0,0,0,,过程看起来是像这样的: Dialogue: 0,0:13:50.65,0:13:52.28,Default,,0,0,0,,首先这有一个盒子 Dialogue: 0,0:13:52.86,0:13:55.39,Default,,0,0,0,,我们到目前为止所做的事都有这样的特征 Dialogue: 0,0:13:55.40,0:13:57.69,Default,,0,0,0,,我们有一个盒子 有东西进去 也有东西出来 Dialogue: 0,0:13:58.08,0:13:59.61,Default,,0,0,0,,这儿有个MERGE盒子 Dialogue: 0,0:14:01.29,0:14:03.85,Default,,0,0,0,,输入是X和Y Dialogue: 0,0:14:04.44,0:14:05.37,Default,,0,0,0,,输出ANS Dialogue: 0,0:14:07.63,0:14:09.48,Default,,0,0,0,,这是我们所编写的程序的特征 Dialogue: 0,0:14:13.02,0:14:14.66,Default,,0,0,0,,但是规则并不像这样 Dialogue: 0,0:14:14.66,0:14:16.76,Default,,0,0,0,,规则讨论的是关系 Dialogue: 0,0:14:17.92,0:14:24.16,Default,,0,0,0,,也就是在幻灯片中我称作MERGE-TO-FORM的关系 Dialogue: 0,0:14:25.37,0:14:28.76,Default,,0,0,0,,每当我说X和Y通过MERGE-TO-FORM形成Z Dialogue: 0,0:14:29.00,0:14:32.33,Default,,0,0,0,,这个是一个函数 Dialogue: 0,0:14:32.61,0:14:32.85,Default,,0,0,0,,对吧? Dialogue: 0,0:14:32.85,0:14:34.41,Default,,0,0,0,,ANS是X和Y的函数 Dialogue: 0,0:14:34.59,0:14:38.19,Default,,0,0,0,,而我这里得到的是三个东西之间的关系 Dialogue: 0,0:14:39.72,0:14:41.32,Default,,0,0,0,,我不会指明 Dialogue: 0,0:14:42.09,0:14:43.77,Default,,0,0,0,,哪个是输入 哪个是输出 Dialogue: 0,0:14:44.20,0:14:47.40,Default,,0,0,0,,我之所以这么说 是因为原理上 Dialogue: 0,0:14:48.64,0:14:50.83,Default,,0,0,0,,我们可以用同样的逻辑规则 Dialogue: 0,0:14:50.84,0:14:52.44,Default,,0,0,0,,来回答相当多的问题 Dialogue: 0,0:14:54.57,0:14:56.30,Default,,0,0,0,,比如 我们可以问 Dialogue: 0,0:14:56.72,0:14:59.05,Default,,0,0,0,,想象一下 如果把这些逻辑规则输入机器 Dialogue: 0,0:14:59.05,0:15:01.20,Default,,0,0,0,,不是输入程序 而是其中依赖的逻辑 Dialogue: 0,0:15:01.40,0:15:03.12,Default,,0,0,0,,那么 它也就应该回答-- Dialogue: 0,0:15:04.75,0:15:05.52,Default,,0,0,0,,我们可以问它 Dialogue: 0,0:15:06.73,0:15:19.18,Default,,0,0,0,,(1 3 7)和(2 4 8)可以通过MERGE-TO-FORM形成什么? Dialogue: 0,0:15:20.91,0:15:23.42,Default,,0,0,0,,机器能够回答这样的问题 Dialogue: 0,0:15:23.88,0:15:27.36,Default,,0,0,0,,这同样也是我们的Lisp程序所回答的问题 Dialogue: 0,0:15:28.18,0:15:30.14,Default,,0,0,0,,但这同样的规则 Dialogue: 0,0:15:30.89,0:15:34.80,Default,,0,0,0,,也能够回答像这样的问题: Dialogue: 0,0:15:36.19,0:15:43.24,Default,,0,0,0,,(1 3 7)和什么能够通过MERGE-TO-FORM形成(1 2 3 4 7 8) Dialogue: 0,0:15:45.56,0:15:47.80,Default,,0,0,0,,同样的逻辑规则也能够回答这个 Dialogue: 0,0:15:47.84,0:15:49.90,Default,,0,0,0,,但我们编写的过程却无法回答这个问题 Dialogue: 0,0:15:50.80,0:15:52.33,Default,,0,0,0,,又或者 我们可以问 Dialogue: 0,0:15:53.71,0:16:01.12,Default,,0,0,0,,什么和什么能通过MERGE-TO-FORM Dialogue: 0,0:16:04.28,0:16:12.68,Default,,0,0,0,,哪两个东西可以通过MERGE-TO-FORM形成(1 2 3 4 7 8)? Dialogue: 0,0:16:13.78,0:16:15.34,Default,,0,0,0,,机器能够进行遍历 Dialogue: 0,0:16:15.84,0:16:17.31,Default,,0,0,0,,如果它能应用这些逻辑规则的话 Dialogue: 0,0:16:17.79,0:16:22.54,Default,,0,0,0,,就能够推断出这个问题所有的2^6种答案 Dialogue: 0,0:16:25.60,0:16:27.69,Default,,0,0,0,,因为可以分别是 (1)和其余的 Dialogue: 0,0:16:27.69,0:16:28.75,Default,,0,0,0,,也可以是 (1 2)和其余的 Dialogue: 0,0:16:28.79,0:16:31.53,Default,,0,0,0,,也可以是(1 3 7)和其余的 Dialogue: 0,0:16:32.01,0:16:33.26,Default,,0,0,0,,有一大堆的答案 Dialogue: 0,0:16:33.41,0:16:37.76,Default,,0,0,0,,但原理上来说 逻辑能推断出所有的答案 Dialogue: 0,0:16:38.55,0:16:42.03,Default,,0,0,0,,因此这里面就有两个巨大的不同 Dialogue: 0,0:16:44.04,0:16:46.00,Default,,0,0,0,,在我们所编写的程序中 Dialogue: 0,0:16:46.54,0:16:48.19,Default,,0,0,0,,不只是Lisp程序 Dialogue: 0,0:16:48.20,0:16:50.56,Default,,0,0,0,,基本上是你们目前编写过的所有程序 Dialogue: 0,0:16:52.03,0:16:53.60,Default,,0,0,0,,用你能叫出名字的程序语言所编写的程序 Dialogue: 0,0:16:54.15,0:16:57.79,Default,,0,0,0,,首先 我们并不准备计算一个函数 Dialogue: 0,0:17:00.62,0:17:02.01,Default,,0,0,0,,我们将要讨论的东西 Dialogue: 0,0:17:02.62,0:17:04.41,Default,,0,0,0,,并不具有输入和输出 Dialogue: 0,0:17:04.41,0:17:05.82,Default,,0,0,0,,我们讨论的是关系 Dialogue: 0,0:17:06.89,0:17:10.00,Default,,0,0,0,,也就是说 原理上 关系是没有方向性的 Dialogue: 0,0:17:11.08,0:17:15.05,Default,,0,0,0,,所以你指明用来回答这个问题的知识 Dialogue: 0,0:17:16.46,0:17:18.41,Default,,0,0,0,,也同样应该能够反过来 Dialogue: 0,0:17:18.43,0:17:21.80,Default,,0,0,0,,让你回答其它的这些问题 Dialogue: 0,0:17:26.60,0:17:29.40,Default,,0,0,0,,其次则是 Dialogue: 0,0:17:29.61,0:17:31.23,Default,,0,0,0,,因为我们讨论的是关系 Dialogue: 0,0:17:32.32,0:17:34.44,Default,,0,0,0,,关系的答案并不唯一 Dialogue: 0,0:17:35.61,0:17:37.00,Default,,0,0,0,,所以在第三个问题中 Dialogue: 0,0:17:37.02,0:17:38.36,Default,,0,0,0,,并没有特定的答案 Dialogue: 0,0:17:38.40,0:17:39.58,Default,,0,0,0,,它有很多的答案 Dialogue: 0,0:17:42.27,0:17:44.64,Default,,0,0,0,,这就是我们的目标 Dialogue: 0,0:17:44.64,0:17:45.90,Default,,0,0,0,,顺便说一下 Dialogue: 0,0:17:46.72,0:17:49.21,Default,,0,0,0,,这种程序设计风格被称作逻辑式程序设计 Dialogue: 0,0:17:50.22,0:17:51.58,Default,,0,0,0,,原因是显而易见的 Dialogue: 0,0:17:56.16,0:18:00.38,Default,,0,0,0,,用逻辑式进行程序设计的那群人之间 Dialogue: 0,0:18:00.40,0:18:03.15,Default,,0,0,0,,流传着几句箴言 Dialogue: 0,0:18:03.16,0:18:04.67,Default,,0,0,0,,他们把逻辑式程序设计的要点归纳为 Dialogue: 0,0:18:04.76,0:18:09.00,Default,,0,0,0,,用逻辑来表达 什么算是“真的” Dialogue: 0,0:18:10.09,0:18:13.88,Default,,0,0,0,,用逻辑来检测 是否是“真的” Dialogue: 0,0:18:14.67,0:18:17.24,Default,,0,0,0,,用逻辑来找出这些“真的” Dialogue: 0,0:18:19.20,0:18:22.09,Default,,0,0,0,,最为大家所熟知的逻辑式程序设计语言 Dialogue: 0,0:18:22.97,0:18:24.78,Default,,0,0,0,,你们可能也听过 -- 叫做Prolog Dialogue: 0,0:18:25.78,0:18:28.88,Default,,0,0,0,,今天早上我们将要实现的这门语言 Dialogue: 0,0:18:29.82,0:18:32.32,Default,,0,0,0,,是一种查询语言 Dialogue: 0,0:18:32.48,0:18:34.41,Default,,0,0,0,,它基本上就是Prolog的本质了 Dialogue: 0,0:18:35.32,0:18:36.73,Default,,0,0,0,,它可以完成相同的工作 Dialogue: 0,0:18:37.29,0:18:38.73,Default,,0,0,0,,虽然它比Prolog慢得多 Dialogue: 0,0:18:38.73,0:18:40.01,Default,,0,0,0,,这是因为我们是通过Lisp来解释的 Dialogue: 0,0:18:41.90,0:18:44.36,Default,,0,0,0,,而非构造一个专门的编译器 Dialogue: 0,0:18:44.46,0:18:46.62,Default,,0,0,0,,对它的解释 将运行在Lisp解释器之上 Dialogue: 0,0:18:47.51,0:18:49.84,Default,,0,0,0,,除此之外 它可以完成与Prolog相同的事儿 Dialogue: 0,0:18:49.88,0:18:52.78,Default,,0,0,0,,不但同样的能力 也有同样的局限 Dialogue: 0,0:18:55.08,0:18:56.17,Default,,0,0,0,,好吧 先解答一下疑惑 Dialogue: 0,0:19:00.43,0:19:02.84,Default,,0,0,0,,学生:您能再重复一下 Dialogue: 0,0:19:03.48,0:19:06.09,Default,,0,0,0,,用逻辑去寻找的三件事么? Dialogue: 0,0:19:06.72,0:19:09.84,Default,,0,0,0,,就是那些 找出什么为真 知道什么是真 等等 Dialogue: 0,0:19:09.84,0:19:10.52,Default,,0,0,0,,教授:好的 Dialogue: 0,0:19:10.56,0:19:15.74,Default,,0,0,0,,这算是程序员的某种“教义问答” Dialogue: 0,0:19:15.85,0:19:19.16,Default,,0,0,0,,我们用逻辑来表达怎么算是“真的” Dialogue: 0,0:19:20.80,0:19:21.79,Default,,0,0,0,,就像这些规则一样 Dialogue: 0,0:19:22.61,0:19:25.56,Default,,0,0,0,,我们用逻辑来检测某事是否是“真的” Dialogue: 0,0:19:25.60,0:19:27.76,Default,,0,0,0,,但在这里我没有回答这个问题 Dialogue: 0,0:19:28.55,0:19:29.29,Default,,0,0,0,,我可以问 Dialogue: 0,0:19:29.68,0:19:32.14,Default,,0,0,0,,在这里我可以这样来问 Dialogue: 0,0:19:33.26,0:19:36.56,Default,,0,0,0,,(1 3 7)和(2 4 8)是否能够 Dialogue: 0,0:19:36.91,0:19:40.38,Default,,0,0,0,,通过MERGE-TO-FORM形成(1 2 6 19) Dialogue: 0,0:19:41.12,0:19:44.68,Default,,0,0,0,,同样的逻辑规则会告诉我们不行 Dialogue: 0,0:19:45.69,0:19:47.93,Default,,0,0,0,,这里 我使用逻辑来检测是否为真 Dialogue: 0,0:19:48.28,0:19:50.48,Default,,0,0,0,,然后 我们也可以使用逻辑来找出为真的东西 Dialogue: 0,0:20:04.46,0:20:05.16,Default,,0,0,0,,休息一下吧 Dialogue: 0,0:20:06.13,0:20:17.02,Default,,0,0,0,,[音乐] Dialogue: 0,0:20:17.05,0:20:20.68,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:20:47.59,0:20:51.02,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:20:51.07,0:20:55.60,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:20:55.63,0:21:00.68,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 I Dialogue: 0,0:21:03.24,0:21:04.97,Default,,0,0,0,,教授:让我们继续来看一看 Dialogue: 0,0:21:05.84,0:21:08.44,Default,,0,0,0,,这个查询语言及其操作 Dialogue: 0,0:21:10.52,0:21:11.84,Default,,0,0,0,,首先需要注意到 Dialogue: 0,0:21:12.24,0:21:14.14,Default,,0,0,0,,当我建立好那个小型的圣经数据库后 Dialogue: 0,0:21:14.16,0:21:17.24,Default,,0,0,0,,我们就能够针对一系列的事实 Dialogue: 0,0:21:17.48,0:21:19.92,Default,,0,0,0,,以关系的方式来向这个语言提问 Dialogue: 0,0:21:21.33,0:21:25.15,Default,,0,0,0,,因此 我们先来陈述一些事实 Dialogue: 0,0:21:26.06,0:21:29.68,Default,,0,0,0,,这是波士顿一家高科技公司的 Dialogue: 0,0:21:30.08,0:21:32.62,Default,,0,0,0,,一小部分人事档案 Dialogue: 0,0:21:33.05,0:21:36.80,Default,,0,0,0,,这部分档案是Ben Bitdiddle的 Dialogue: 0,0:21:37.50,0:21:41.95,Default,,0,0,0,,Bitdiddle是这家公司的计算机向导 Dialogue: 0,0:21:42.84,0:21:45.80,Default,,0,0,0,,他是这家公司的低薪向导 Dialogue: 0,0:21:46.42,0:21:48.78,Default,,0,0,0,,他的上司是Oliver Warbucks Dialogue: 0,0:21:49.28,0:21:50.70,Default,,0,0,0,,这里是他的住址 Dialogue: 0,0:21:52.15,0:21:56.54,Default,,0,0,0,,我们按照这样的格式给出信息:职务、薪水、上司、住址 Dialogue: 0,0:21:57.56,0:21:59.25,Default,,0,0,0,,还有一些其它的约定 Dialogue: 0,0:21:59.25,0:22:02.22,Default,,0,0,0,,这里的COMPUTER表示BEN在计算机分部工作 Dialogue: 0,0:22:02.76,0:22:04.94,Default,,0,0,0,,而他在这个分部的工作是向导 Dialogue: 0,0:22:05.66,0:22:07.15,Default,,0,0,0,,这里是其他人的 Dialogue: 0,0:22:07.16,0:22:12.28,Default,,0,0,0,,Alyssa P.Hacker是一名计算机程序员 Dialogue: 0,0:22:13.36,0:22:14.60,Default,,0,0,0,,她的上司是Ben Dialogue: 0,0:22:15.21,0:22:16.54,Default,,0,0,0,,而她住在Cambridge Dialogue: 0,0:22:17.55,0:22:19.42,Default,,0,0,0,,Ben手下的另外一个程序员 Dialogue: 0,0:22:20.03,0:22:21.44,Default,,0,0,0,,叫做Lem E. Tweakit Dialogue: 0,0:22:22.82,0:22:26.73,Default,,0,0,0,,实习程序员 Louis Reasoner Dialogue: 0,0:22:27.42,0:22:28.62,Default,,0,0,0,,在Alyssa手下工作 Dialogue: 0,0:22:30.10,0:22:35.45,Default,,0,0,0,,公司里的“大老板”不为任何人工作 Dialogue: 0,0:22:36.81,0:22:38.11,Default,,0,0,0,,这就是Oliver Warbucks的档案了 Dialogue: 0,0:22:38.11,0:22:39.31,Default,,0,0,0,,我们将要做的就是 Dialogue: 0,0:22:40.94,0:22:43.66,Default,,0,0,0,,对这个小型的世界提问 Dialogue: 0,0:22:44.97,0:22:48.40,Default,,0,0,0,,这将是我们进行逻辑运算的样本世界 Dialogue: 0,0:22:51.42,0:22:54.96,Default,,0,0,0,,我再最后一次强调一下 Dialogue: 0,0:22:55.60,0:22:58.20,Default,,0,0,0,,你们应该从这门课中学到的最重要的知识 Dialogue: 0,0:22:58.80,0:23:01.66,Default,,0,0,0,,也就是 当别人向你介绍语言时 Dialogue: 0,0:23:02.25,0:23:04.43,Default,,0,0,0,,你要问:“它的基本元素是什么?” Dialogue: 0,0:23:06.12,0:23:07.79,Default,,0,0,0,,组合的手段有哪些? Dialogue: 0,0:23:14.70,0:23:16.40,Default,,0,0,0,,如何把基本元素组织在一起 Dialogue: 0,0:23:16.67,0:23:19.37,Default,,0,0,0,,然后把它们抽象出来? Dialogue: 0,0:23:19.96,0:23:21.93,Default,,0,0,0,,如何抽象这些复合元素 Dialogue: 0,0:23:24.68,0:23:27.58,Default,,0,0,0,,以便于你能够复用它们构造更复杂的东西? Dialogue: 0,0:23:29.02,0:23:30.81,Default,,0,0,0,,我已经强调过很多次了 Dialogue: 0,0:23:31.16,0:23:32.48,Default,,0,0,0,,但还是值得重申一遍 Dialogue: 0,0:23:35.00,0:23:36.67,Default,,0,0,0,,记住了么?我们开始了 Dialogue: 0,0:23:36.67,0:23:37.34,Default,,0,0,0,,首先是基本元素 Dialogue: 0,0:23:37.77,0:23:39.44,Default,,0,0,0,,这其中 只有唯一的基本元素 Dialogue: 0,0:23:40.96,0:23:43.20,Default,,0,0,0,,这门语言中的基本元素就是“查询” Dialogue: 0,0:23:44.14,0:23:45.74,Default,,0,0,0,,一条基本查询 Dialogue: 0,0:23:46.81,0:23:48.25,Default,,0,0,0,,我们先来看几条基本查询 Dialogue: 0,0:23:51.82,0:23:53.02,Default,,0,0,0,,首先 这条查询问的是 Dialogue: 0,0:23:53.10,0:23:54.81,Default,,0,0,0,,“谁是计算机程序员?” Dialogue: 0,0:23:55.55,0:23:59.88,Default,,0,0,0,,或者可以解释为:找出数据库中 Dialogue: 0,0:24:01.55,0:24:06.14,Default,,0,0,0,,所有JOB栏为COMPUTER PROGRAMMER的事实 Dialogue: 0,0:24:06.64,0:24:08.01,Default,,0,0,0,,这里有一些小语法 Dialogue: 0,0:24:08.47,0:24:10.59,Default,,0,0,0,,不带问号的都是字面量 Dialogue: 0,0:24:11.28,0:24:13.15,Default,,0,0,0,,?X表示X是变量 Dialogue: 0,0:24:13.31,0:24:15.56,Default,,0,0,0,,而这条查询会匹配 比如说 -- Dialogue: 0,0:24:16.03,0:24:19.00,Default,,0,0,0,,Alyssa P. Hacker 是程序员 Dialogue: 0,0:24:19.28,0:24:21.93,Default,,0,0,0,,其中X为Alyssa P. Hacker这条事实 Dialogue: 0,0:24:26.82,0:24:29.98,Default,,0,0,0,,或者更一般地 我可以在一条查询中引入两个变量 Dialogue: 0,0:24:30.75,0:24:31.45,Default,,0,0,0,,我可以问 Dialogue: 0,0:24:31.60,0:24:35.88,Default,,0,0,0,,?X的JOB必须是COMPUTER ?TYPE Dialogue: 0,0:24:39.34,0:24:41.39,Default,,0,0,0,,也就是会匹配COMPUTER WIZARD Dialogue: 0,0:24:42.14,0:24:44.28,Default,,0,0,0,,所以这里?TYPE可能会匹配WIZARD Dialogue: 0,0:24:44.92,0:24:46.46,Default,,0,0,0,,也可能会匹配PROGRAMMER Dialogue: 0,0:24:47.48,0:24:50.37,Default,,0,0,0,,而?X会匹配不同的东西 Dialogue: 0,0:24:50.37,0:24:52.24,Default,,0,0,0,,但在我们的这个小例子中 Dialogue: 0,0:24:52.25,0:24:55.15,Default,,0,0,0,,数据库中只有三条事实符合那条查询 Dialogue: 0,0:24:59.12,0:25:02.08,Default,,0,0,0,,把语法说得再清楚一点 同样的查询 Dialogue: 0,0:25:05.29,0:25:08.09,Default,,0,0,0,,同样的这条指定了?X的JOB的查询 Dialogue: 0,0:25:09.85,0:25:11.79,Default,,0,0,0,,并不能够与Lewis Reasoner匹配 Dialogue: 0,0:25:11.84,0:25:13.64,Default,,0,0,0,,这是因为我这里所写的 Dialogue: 0,0:25:14.22,0:25:17.74,Default,,0,0,0,,表示要匹配的是由两个符号构成的表 Dialogue: 0,0:25:19.96,0:25:21.96,Default,,0,0,0,,其中首元素必须为单词“COMPUTER” Dialogue: 0,0:25:22.32,0:25:23.80,Default,,0,0,0,,而第二个可以匹配任意的东西 Dialogue: 0,0:25:25.08,0:25:27.32,Default,,0,0,0,,而Lewis这里的工作描述有三个符号 Dialogue: 0,0:25:27.80,0:25:28.83,Default,,0,0,0,,因此不匹配 Dialogue: 0,0:25:30.34,0:25:32.19,Default,,0,0,0,,你们还需要知道的一种语法是 Dialogue: 0,0:25:35.04,0:25:38.32,Default,,0,0,0,,更具一般性的点记号 Dialogue: 0,0:25:40.17,0:25:42.92,Default,,0,0,0,,这个标准的表记号表示的是 Dialogue: 0,0:25:43.04,0:25:43.82,Default,,0,0,0,,首先这是一个表 Dialogue: 0,0:25:44.12,0:25:47.32,Default,,0,0,0,,它的首元素为单词“COMPUTER” Dialogue: 0,0:25:47.58,0:25:50.22,Default,,0,0,0,,而其余的部分 我们把它们称作?TYPE Dialogue: 0,0:25:53.73,0:25:55.50,Default,,0,0,0,,因此这条查询就会匹配上 Dialogue: 0,0:25:56.93,0:25:59.31,Default,,0,0,0,,Lewis的工作是COMPUTER PROGRAMMER TRAINEE Dialogue: 0,0:25:59.44,0:26:03.29,Default,,0,0,0,,而?TYPE的值将会是这个表的CDR部分 Dialogue: 0,0:26:03.32,0:26:05.64,Default,,0,0,0,,也就是表(PROGRAMMER TRAINEE) Dialogue: 0,0:26:06.96,0:26:10.46,Default,,0,0,0,,Lisp源码读取器会自动完成对点记号的处理 Dialogue: 0,0:26:15.90,0:26:17.76,Default,,0,0,0,,让我们来实际操作一下 Dialogue: 0,0:26:17.76,0:26:20.51,Default,,0,0,0,,我将向语言系统输入这些查询 Dialogue: 0,0:26:20.76,0:26:21.82,Default,,0,0,0,,然后得到结果 Dialogue: 0,0:26:22.54,0:26:24.48,Default,,0,0,0,,让我们在计算机中试试 Dialogue: 0,0:26:25.18,0:26:26.51,Default,,0,0,0,,我可以问 Dialogue: 0,0:26:27.34,0:26:28.88,Default,,0,0,0,,谁在计算机分部工作? Dialogue: 0,0:26:30.00,0:26:38.22,Default,,0,0,0,,(JOB ?X (COMPUTER . ?Y) Dialogue: 0,0:26:39.73,0:26:41.48,Default,,0,0,0,,哑变量的名字并不重要 Dialogue: 0,0:26:42.76,0:26:44.14,Default,,0,0,0,,查询的结果是 Dialogue: 0,0:26:44.41,0:26:45.68,Default,,0,0,0,,有四条记录 Dialogue: 0,0:26:48.65,0:26:50.09,Default,,0,0,0,,我也可以问 Dialogue: 0,0:26:50.56,0:26:52.38,Default,,0,0,0,,大家的上司都是谁? Dialogue: 0,0:26:52.81,0:26:54.88,Default,,0,0,0,,我输入一条基本查询 Dialogue: 0,0:26:56.52,0:26:59.39,Default,,0,0,0,,(SUPERVISOR ?X ?Y) Dialogue: 0,0:27:02.56,0:27:05.42,Default,,0,0,0,,这些都是我所知道的上下级关系 Dialogue: 0,0:27:05.54,0:27:08.83,Default,,0,0,0,,或者我也可以问:“谁住在Cambridge?” Dialogue: 0,0:27:08.83,0:27:09.47,Default,,0,0,0,,我就这么输入: Dialogue: 0,0:27:10.24,0:27:20.92,Default,,0,0,0,,(ADDRESS ?X (CAMBRIDGE . ?T)) Dialogue: 0,0:27:25.09,0:27:26.89,Default,,0,0,0,,只有一个人住在Cambridge Dialogue: 0,0:27:30.82,0:27:32.17,Default,,0,0,0,,这些就是基本查询 Dialogue: 0,0:27:32.17,0:27:34.96,Default,,0,0,0,,你们看到的这些 就是与系统的基础交互 Dialogue: 0,0:27:35.29,0:27:39.24,Default,,0,0,0,,你输入一条查询 他输出所有可能的查询 Dialogue: 0,0:27:39.62,0:27:40.65,Default,,0,0,0,,换句话说 也就是 Dialogue: 0,0:27:40.67,0:27:44.16,Default,,0,0,0,,它找出这些变量所有可能的值 Dialogue: 0,0:27:44.19,0:27:45.87,Default,,0,0,0,,不管它是叫X、Y还是T Dialogue: 0,0:27:46.09,0:27:52.08,Default,,0,0,0,,然后它输出的是用所有可行值实例化该条查询的结果 Dialogue: 0,0:27:52.92,0:27:55.16,Default,,0,0,0,,也就是规则系统那一课讲的“实例化” Dialogue: 0,0:27:55.16,0:27:58.83,Default,,0,0,0,,用变量所有可能的值来实例化查询 Dialogue: 0,0:27:59.00,0:28:00.35,Default,,0,0,0,,然后输出所有的结果 Dialogue: 0,0:28:01.00,0:28:03.35,Default,,0,0,0,,当然 还有不同的呈现结果的方式 Dialogue: 0,0:28:03.35,0:28:06.01,Default,,0,0,0,,比如说 Prolog就有些不一样 Dialogue: 0,0:28:06.01,0:28:07.44,Default,,0,0,0,,它并不向你返回查询 Dialogue: 0,0:28:07.76,0:28:10.78,Default,,0,0,0,,Prolog会输出X=这个 Y=那个 Dialogue: 0,0:28:10.97,0:28:12.94,Default,,0,0,0,,又或者X=这个 Y=那个 Dialogue: 0,0:28:13.66,0:28:15.48,Default,,0,0,0,,这是使用界面层次的差别 Dialogue: 0,0:28:15.71,0:28:17.05,Default,,0,0,0,,你可以根据你的喜好来决定 Dialogue: 0,0:28:18.97,0:28:19.58,Default,,0,0,0,,我们继续 Dialogue: 0,0:28:21.00,0:28:22.68,Default,,0,0,0,,也就是说 这个语言中的基本元素 Dialogue: 0,0:28:23.39,0:28:24.57,Default,,0,0,0,,只有一个 对吧? Dialogue: 0,0:28:24.57,0:28:27.23,Default,,0,0,0,,也就是基本查询 Dialogue: 0,0:28:31.31,0:28:32.56,Default,,0,0,0,,来看看组合的手段 Dialogue: 0,0:28:34.33,0:28:37.68,Default,,0,0,0,,我们来考察一下这个语言中的复合查询 Dialogue: 0,0:28:39.77,0:28:40.46,Default,,0,0,0,,比如这条 Dialogue: 0,0:28:41.79,0:28:42.51,Default,,0,0,0,,这条查询是说 Dialogue: 0,0:28:45.05,0:28:48.22,Default,,0,0,0,,列举出所有在计算机分部工作的人 Dialogue: 0,0:28:49.81,0:28:52.00,Default,,0,0,0,,在计算机分部工作的人 Dialogue: 0,0:28:52.54,0:28:53.96,Default,,0,0,0,,以及他们的上司 Dialogue: 0,0:28:56.80,0:28:58.83,Default,,0,0,0,,我使用AND来编写这条查询 Dialogue: 0,0:29:00.22,0:29:04.06,Default,,0,0,0,,(AND (JOB ?X (COMPUTER . ?Y)) Dialogue: 0,0:29:04.92,0:29:06.83,Default,,0,0,0,,(JOB ?X (COMPUTER . ?Y)) Dialogue: 0,0:29:07.56,0:29:10.03,Default,,0,0,0,,并且(SUPERVISOR ?X ?Z) Dialogue: 0,0:29:11.44,0:29:14.16,Default,,0,0,0,,找出所有在计算机分部工作的人 -- 对应这条 Dialogue: 0,0:29:14.30,0:29:15.88,Default,,0,0,0,,以及它们的上司 Dialogue: 0,0:29:16.46,0:29:17.82,Default,,0,0,0,,注意这条查询中 Dialogue: 0,0:29:18.67,0:29:22.41,Default,,0,0,0,,我引入了三个变量 ?X ?Y 以及 ?Z Dialogue: 0,0:29:23.58,0:29:28.65,Default,,0,0,0,,并且 这两个?X应该匹配同样的东西 Dialogue: 0,0:29:29.45,0:29:31.16,Default,,0,0,0,,?X被约束在了计算机分部中 Dialogue: 0,0:29:31.31,0:29:33.00,Default,,0,0,0,,并且?X的上司是?Z Dialogue: 0,0:29:34.81,0:29:35.80,Default,,0,0,0,,我们再来看一条 Dialogue: 0,0:29:37.25,0:29:39.28,Default,,0,0,0,,AND算是一种组合手段 Dialogue: 0,0:29:41.44,0:29:43.96,Default,,0,0,0,,哪些人的薪水超过$30,000? Dialogue: 0,0:29:45.71,0:29:51.71,Default,,0,0,0,,(AND (SALARY ?P ?A) Dialogue: 0,0:29:54.59,0:29:57.45,Default,,0,0,0,,而关于?A的要求则是 Dialogue: 0,0:29:57.48,0:30:00.12,Default,,0,0,0,,(LISP-VALUE > ?A 300000) Dialogue: 0,0:30:00.60,0:30:03.23,Default,,0,0,0,,这里的LISP-VALUE是一个接口 Dialogue: 0,0:30:04.30,0:30:10.04,Default,,0,0,0,,用来连接查询语言与其底层的Lisp Dialogue: 0,0:30:10.60,0:30:12.72,Default,,0,0,0,,LISP-VALUE让你能够在查询 Dialogue: 0,0:30:12.75,0:30:16.91,Default,,0,0,0,,中调用任意的Lisp谓词 Dialogue: 0,0:30:17.18,0:30:20.11,Default,,0,0,0,,因为我要用Lisp中的谓词> 所以我用LISP-VALUE Dialogue: 0,0:30:21.02,0:30:21.75,Default,,0,0,0,,所以这里我用了AND Dialogue: 0,0:30:21.75,0:30:24.48,Default,,0,0,0,,因此这样就查询出了薪水超过$30000的人 Dialogue: 0,0:30:28.19,0:30:30.03,Default,,0,0,0,,或者这条更复杂的查询 Dialogue: 0,0:30:31.27,0:30:35.02,Default,,0,0,0,,告诉我所有那些 在计算机分部中工作 Dialogue: 0,0:30:36.25,0:30:39.36,Default,,0,0,0,,但他的上司不在计算机分部工作的人 Dialogue: 0,0:30:42.79,0:30:45.51,Default,,0,0,0,,(AND (JOB ?X (COMPUTER . ?Y)) Dialogue: 0,0:30:45.51,0:30:47.32,Default,,0,0,0,,表示?X在计算机分部工作 Dialogue: 0,0:30:47.78,0:30:49.24,Default,,0,0,0,,但是呢 Dialogue: 0,0:30:50.49,0:30:54.25,Default,,0,0,0,,?X的上司?Z Dialogue: 0,0:30:55.37,0:30:57.87,Default,,0,0,0,,?Z的JOB不是形如(COMPUTER ...)一类的 Dialogue: 0,0:30:59.62,0:31:00.35,Default,,0,0,0,,同样的 Dialogue: 0,0:31:00.51,0:31:02.38,Default,,0,0,0,,这两个?X应该是一致的 Dialogue: 0,0:31:03.20,0:31:05.76,Default,,0,0,0,,而这两个?Z也应该是一致的 Dialogue: 0,0:31:09.39,0:31:11.38,Default,,0,0,0,,你又了解了另一种组合手段 -- NOT Dialogue: 0,0:31:17.71,0:31:18.67,Default,,0,0,0,,好了 再让我们来试试这些 Dialogue: 0,0:31:20.88,0:31:22.08,Default,,0,0,0,,它同样起效 Dialogue: 0,0:31:22.40,0:31:24.12,Default,,0,0,0,,我可以问计算机: Dialogue: 0,0:31:26.89,0:31:35.40,Default,,0,0,0,,(AND (JOB ?X (COMPUTER . ?Y))) Dialogue: 0,0:31:38.84,0:31:45.95,Default,,0,0,0,,另一个条件是(SUPERVISOR ?X ?Z) Dialogue: 0,0:31:46.83,0:31:49.53,Default,,0,0,0,,我把这条查询输入进去 Dialogue: 0,0:31:51.07,0:31:52.97,Default,,0,0,0,,计算机返回给我们的 Dialogue: 0,0:31:54.00,0:31:58.73,Default,,0,0,0,,计算机利用所有可能的答案把我的查询实例化了 Dialogue: 0,0:31:58.93,0:32:00.08,Default,,0,0,0,,你会发现有很多的答案 Dialogue: 0,0:32:01.69,0:32:02.14,Default,,0,0,0,,好 Dialogue: 0,0:32:02.19,0:32:04.04,Default,,0,0,0,,之所以把这门语言称作“逻辑语言” Dialogue: 0,0:32:05.21,0:32:06.60,Default,,0,0,0,,是因为这门语言中的组合手段 Dialogue: 0,0:32:06.64,0:32:09.47,Default,,0,0,0,,都是逻辑运算 Dialogue: 0,0:32:09.80,0:32:15.68,Default,,0,0,0,,组合的手段有AND和NOT Dialogue: 0,0:32:15.96,0:32:17.92,Default,,0,0,0,,以及我还没有告诉你的OR Dialogue: 0,0:32:18.49,0:32:20.36,Default,,0,0,0,,我还告诉过你LISP-VALUE Dialogue: 0,0:32:20.72,0:32:24.48,Default,,0,0,0,,当然 虽然它不是一个逻辑运算 Dialogue: 0,0:32:24.51,0:32:26.89,Default,,0,0,0,,但是这个特殊的小技巧把它跟Lisp连接在了一起 Dialogue: 0,0:32:27.34,0:32:28.75,Default,,0,0,0,,让你获得了更多的力量 Dialogue: 0,0:32:29.25,0:32:30.67,Default,,0,0,0,,这些就是组合手段 Dialogue: 0,0:32:32.59,0:32:33.98,Default,,0,0,0,,好 接着是抽象手段 Dialogue: 0,0:32:34.16,0:32:35.21,Default,,0,0,0,,我们想要的是 Dialogue: 0,0:32:38.27,0:32:41.24,Default,,0,0,0,,想让我们回过头来看上一张幻灯片 Dialogue: 0,0:32:42.26,0:32:44.25,Default,,0,0,0,,我们想要把一些非常复杂的东西 Dialogue: 0,0:32:44.46,0:32:48.00,Default,,0,0,0,,比如不与上司在同一部门工作 Dialogue: 0,0:32:48.01,0:32:50.09,Default,,0,0,0,,的人的这种概念 Dialogue: 0,0:32:52.40,0:32:55.10,Default,,0,0,0,,像以前一样 给它命名 Dialogue: 0,0:32:56.09,0:32:58.12,Default,,0,0,0,,如果在某个分部工作的人 Dialogue: 0,0:32:58.17,0:33:00.25,Default,,0,0,0,,他的上司却不在那个分部工作 Dialogue: 0,0:33:00.48,0:33:01.93,Default,,0,0,0,,这就意味着他是个“大腕” Dialogue: 0,0:33:02.75,0:33:05.13,Default,,0,0,0,,这样 我们就定义一条规则指明 Dialogue: 0,0:33:06.43,0:33:09.16,Default,,0,0,0,,如果?X是某个部门的BIGSHOT Dialogue: 0,0:33:10.91,0:33:14.68,Default,,0,0,0,,如果他在该部门工作 Dialogue: 0,0:33:16.04,0:33:20.08,Default,,0,0,0,,并且他的上司不在该部门工作 Dialogue: 0,0:33:21.51,0:33:22.94,Default,,0,0,0,,因此这就是我们的抽象手段 Dialogue: 0,0:33:22.94,0:33:23.90,Default,,0,0,0,,这是一条规则 Dialogue: 0,0:33:26.22,0:33:27.58,Default,,0,0,0,,规则由三部分构成 Dialogue: 0,0:33:31.00,0:33:32.48,Default,,0,0,0,,关键字RULE表明这是一条规则 Dialogue: 0,0:33:33.40,0:33:35.48,Default,,0,0,0,,接着是规则的结论 Dialogue: 0,0:33:37.53,0:33:39.07,Default,,0,0,0,,然后是规则的体 Dialogue: 0,0:33:40.00,0:33:41.88,Default,,0,0,0,,你可以把它解读为这样的一段逻辑: Dialogue: 0,0:33:41.92,0:33:45.15,Default,,0,0,0,,如果你知道规则的体为真 Dialogue: 0,0:33:46.40,0:33:48.72,Default,,0,0,0,,那么你就可以推导出结论为真 Dialogue: 0,0:33:49.45,0:33:53.28,Default,,0,0,0,,或者说为了推断出?X是某个部门的“大腕” Dialogue: 0,0:33:53.79,0:33:55.71,Default,,0,0,0,,这些条件足够验证了 Dialogue: 0,0:33:57.48,0:33:58.82,Default,,0,0,0,,这就是规则的形式 Dialogue: 0,0:34:03.28,0:34:06.16,Default,,0,0,0,,让我们回过头来看看 Dialogue: 0,0:34:06.73,0:34:07.92,Default,,0,0,0,,课间休息前我举的那个例子 Dialogue: 0,0:34:08.11,0:34:10.68,Default,,0,0,0,,我们来看看 如果用规则来描述会是什么样的 Dialogue: 0,0:34:11.44,0:34:12.84,Default,,0,0,0,,我会抽取出其中的逻辑 Dialogue: 0,0:34:13.08,0:34:15.50,Default,,0,0,0,,并将它们变为这种格式的规则 Dialogue: 0,0:34:18.73,0:34:19.35,Default,,0,0,0,,就有了下面的规则 Dialogue: 0,0:34:19.35,0:34:20.96,Default,,0,0,0,,这就是MERGE-TO-FORM的规则 Dialogue: 0,0:34:21.71,0:34:22.97,Default,,0,0,0,,这个规则是说 Dialogue: 0,0:34:26.28,0:34:29.62,Default,,0,0,0,,'()与?Y可以通过MERGE-TO-FORM形成?Y Dialogue: 0,0:34:29.62,0:34:30.87,Default,,0,0,0,,这是规则的结论 Dialogue: 0,0:34:33.21,0:34:35.74,Default,,0,0,0,,需要注意的是 这个特定的规则没有体 Dialogue: 0,0:34:36.65,0:34:37.66,Default,,0,0,0,,在这门语言中 Dialogue: 0,0:34:38.11,0:34:40.86,Default,,0,0,0,,没有体的规则总是真的 Dialogue: 0,0:34:41.23,0:34:42.51,Default,,0,0,0,,你总是可以假设它们为真 Dialogue: 0,0:34:45.19,0:34:46.49,Default,,0,0,0,,另一条规则说的是 Dialogue: 0,0:34:46.64,0:34:49.46,Default,,0,0,0,,任意对象与空表进行MERGE-TO-FORM 得到的任然是原物 Dialogue: 0,0:34:49.46,0:34:50.12,Default,,0,0,0,,就是这条 Dialogue: 0,0:34:50.90,0:34:53.55,Default,,0,0,0,,(MERGE-TO-FORM ?Y '() ?Y) Dialogue: 0,0:34:55.51,0:34:58.40,Default,,0,0,0,,它们对应了我们MERGE过程中的两个终止条件 Dialogue: 0,0:34:58.44,0:34:59.77,Default,,0,0,0,,但我们现在讨论的是逻辑 Dialogue: 0,0:35:00.41,0:35:01.45,Default,,0,0,0,,而非过程 Dialogue: 0,0:35:03.49,0:35:04.48,Default,,0,0,0,,我们还有另外一条规则 Dialogue: 0,0:35:04.83,0:35:08.73,Default,,0,0,0,,描述的是 如果你知道如何MERGE较短的表 Dialogue: 0,0:35:08.91,0:35:09.83,Default,,0,0,0,,那么你就可以把它们结合在一起 Dialogue: 0,0:35:09.83,0:35:14.16,Default,,0,0,0,,这条规则说:如果你有表?X、?Y以及?Z Dialogue: 0,0:35:14.92,0:35:17.61,Default,,0,0,0,,如果你想推断出(?A . ?X) Dialogue: 0,0:35:17.63,0:35:19.08,Default,,0,0,0,,这个记法表示(CONS ?A ?X) Dialogue: 0,0:35:19.48,0:35:22.36,Default,,0,0,0,,或者说首元素是'A、剩余元素是'X的表 Dialogue: 0,0:35:23.16,0:35:27.40,Default,,0,0,0,,由此 如果你想推断(MERGE-TO-FROM (?A . ?X) (?B . ?Y) (?B . ?Z)) Dialogue: 0,0:35:30.36,0:35:33.90,Default,,0,0,0,,毋宁说如果你想要把表(?A ?X)和表(?B ?Y)合并得到 Dialogue: 0,0:35:33.92,0:35:35.85,Default,,0,0,0,,一个以?B为首的表 Dialogue: 0,0:35:36.76,0:35:40.67,Default,,0,0,0,,你想要推断出这个结果 就要满足 Dialogue: 0,0:35:40.91,0:35:44.48,Default,,0,0,0,,不但(MERGE-TP-FORM (?A . ?X) ?Y ?Z) Dialogue: 0,0:35:45.18,0:35:47.24,Default,,0,0,0,,并且(LISP-VALUE > ?A ?B) Dialogue: 0,0:35:48.69,0:35:50.59,Default,,0,0,0,,因此当我在合并它们时 ?B会首先出现在表中 Dialogue: 0,0:35:51.82,0:35:54.91,Default,,0,0,0,,这就是简单的把我之前写的伪代码 Dialogue: 0,0:35:55.24,0:35:57.18,Default,,0,0,0,,翻译成逻辑的语言 Dialogue: 0,0:35:57.96,0:36:01.63,Default,,0,0,0,,为了翻译完整 这还里有种情况 Dialogue: 0,0:36:02.88,0:36:05.95,Default,,0,0,0,,(MERGE-TO-FORM (?A . ?X) (?B . ?Y) (?A . ?Z))成立 Dialogue: 0,0:36:06.08,0:36:09.16,Default,,0,0,0,,就需要(MERGE-TO-FORM ?X (?B . ?Y) ?Z) Dialogue: 0,0:36:09.47,0:36:11.00,Default,,0,0,0,,和(LISP-VALUE > ?B ?A)都成立 Dialogue: 0,0:36:12.19,0:36:15.98,Default,,0,0,0,,我已经把这个用逻辑语言编写的小程序输入计算机了 Dialogue: 0,0:36:16.01,0:36:17.07,Default,,0,0,0,,现在让我们来试着运行一下 Dialogue: 0,0:36:21.90,0:36:23.90,Default,,0,0,0,,由于我已经输入过MERGE-TO-FORM的规则了 Dialogue: 0,0:36:24.62,0:36:25.77,Default,,0,0,0,,我就可以 Dialogue: 0,0:36:27.04,0:36:28.51,Default,,0,0,0,,我可以像过程一样使用它 Dialogue: 0,0:36:28.51,0:36:38.24,Default,,0,0,0,,我可以问(MERGE-TO-FORM (1 3) (2 7) ?X) Dialogue: 0,0:36:39.42,0:36:41.55,Default,,0,0,0,,这里 我把它当作一个Lisp过程来使用 Dialogue: 0,0:36:43.16,0:36:44.97,Default,,0,0,0,,它先会思考一会儿 Dialogue: 0,0:36:46.43,0:36:47.56,Default,,0,0,0,,然后应用这些规则 Dialogue: 0,0:36:50.78,0:36:51.92,Default,,0,0,0,,它找到了一个答案 Dialogue: 0,0:36:52.80,0:36:54.54,Default,,0,0,0,,现在它还要继续寻找其它的答案 Dialogue: 0,0:36:55.07,0:36:57.32,Default,,0,0,0,,因为它事先不知道这里答案只有一个 Dialogue: 0,0:36:57.81,0:36:59.90,Default,,0,0,0,,因此它就在这里检查所有的可能性 Dialogue: 0,0:37:00.41,0:37:02.54,Default,,0,0,0,,确认没有后 输出'DONE' Dialogue: 0,0:37:03.16,0:37:05.07,Default,,0,0,0,,这里 我把它们当作过程来使用 Dialogue: 0,0:37:05.21,0:37:09.05,Default,,0,0,0,,不过要注意 我还可以问不同类型的问题 Dialogue: 0,0:37:10.22,0:37:11.07,Default,,0,0,0,,我可以问 Dialogue: 0,0:37:18.56,0:37:24.59,Default,,0,0,0,,(MERGE-TO-FORM (2 ?A) Dialogue: 0,0:37:24.59,0:37:27.90,Default,,0,0,0,,一个我已知是以2为首的二元表 Dialogue: 0,0:37:29.37,0:37:31.26,Default,,0,0,0,,而另外一个东西是未知的 Dialogue: 0,0:37:33.05,0:37:35.04,Default,,0,0,0,,用?X来表示这个未知的表 Dialogue: 0,0:37:36.48,0:37:39.51,Default,,0,0,0,,可以通过MERGE-TO-FORM形成(1 2 3 4) Dialogue: 0,0:37:42.76,0:37:44.11,Default,,0,0,0,,现在它将思考这个问题 Dialogue: 0,0:37:44.59,0:37:49.40,Default,,0,0,0,,它会找到 -- 它找到了一种可能 Dialogue: 0,0:37:49.52,0:37:52.46,Default,,0,0,0,,比如A=3 X=(1 4) Dialogue: 0,0:37:53.72,0:37:55.16,Default,,0,0,0,,现在 它又要继续检查 Dialogue: 0,0:37:56.56,0:37:57.71,Default,,0,0,0,,因为它事先并不知道 Dialogue: 0,0:37:57.74,0:38:00.30,Default,,0,0,0,,这里并没有其它的可能了 Dialogue: 0,0:38:03.68,0:38:06.57,Default,,0,0,0,,或者 就像我说过的 Dialogue: 0,0:38:07.00,0:38:09.84,Default,,0,0,0,,我可以问 Dialogue: 0,0:38:10.54,0:38:17.55,Default,,0,0,0,,能够通过MERGE-TO-FORM形成(1 2 3 4 5)的?X和?Y分别是什么? Dialogue: 0,0:38:23.68,0:38:25.53,Default,,0,0,0,,语言系统又要思考这个问题 Dialogue: 0,0:38:28.49,0:38:30.31,Default,,0,0,0,,它可能会得到很多答案 Dialogue: 0,0:38:35.18,0:38:38.57,Default,,0,0,0,,这里我们就体会到了缓慢的代价 Dialogue: 0,0:38:42.21,0:38:43.88,Default,,0,0,0,,大概是有三种原因造成这样 Dialogue: 0,0:38:43.88,0:38:46.22,Default,,0,0,0,,首先 这门语言经过了两次解释 Dialogue: 0,0:38:47.63,0:38:49.72,Default,,0,0,0,,然而在真正的实现中 Dialogue: 0,0:38:49.76,0:38:52.04,Default,,0,0,0,,你应该把这些编译成基本运算 Dialogue: 0,0:38:52.19,0:38:53.87,Default,,0,0,0,,其次就是 Dialogue: 0,0:38:53.88,0:38:58.11,Default,,0,0,0,,这个MERGE算法 是双重递归的 Dialogue: 0,0:38:58.38,0:39:00.06,Default,,0,0,0,,因此它需要花费很长的时间 Dialogue: 0,0:39:01.02,0:39:04.33,Default,,0,0,0,,最后呢 它又要遍历所有的情况 Dialogue: 0,0:39:04.59,0:39:07.13,Default,,0,0,0,,找出 -- 找出什么呢? Dialogue: 0,0:39:07.13,0:39:08.73,Default,,0,0,0,,所有的2^5种可行解 Dialogue: 0,0:39:12.14,0:39:14.96,Default,,0,0,0,,我们发现它们以某种相当随意的顺序输出 Dialogue: 0,0:39:15.00,0:39:18.14,Default,,0,0,0,,这取决于它们用什么样的顺序尝试这些规则 Dialogue: 0,0:39:20.16,0:39:22.11,Default,,0,0,0,,事实上 在后期制作本视频时 Dialogue: 0,0:39:22.40,0:39:23.48,Default,,0,0,0,,我们将加速这段 Dialogue: 0,0:39:24.08,0:39:26.60,Default,,0,0,0,,我们就不再这里浪费时间了 Dialogue: 0,0:39:26.60,0:39:28.27,Default,,0,0,0,,课后你们可以自行尝试 Dialogue: 0,0:39:29.48,0:39:34.24,Default,,0,0,0,,好吧 它还在运行 Dialogue: 0,0:39:39.22,0:39:41.12,Default,,0,0,0,,总之 一共有32种可能 Dialogue: 0,0:39:41.13,0:39:42.63,Default,,0,0,0,,我们就不等到输出所有的结果了 Dialogue: 0,0:39:47.85,0:39:50.44,Default,,0,0,0,,因此 这门语言中的抽象手段就是RULE Dialogue: 0,0:39:53.53,0:39:58.01,Default,,0,0,0,,我们用逻辑把事物组织在一起 Dialogue: 0,0:39:59.12,0:40:00.08,Default,,0,0,0,,并为它们命名 Dialogue: 0,0:40:00.35,0:40:03.41,Default,,0,0,0,,你们可以认为这是为一组特定的逻辑模式命名 Dialogue: 0,0:40:03.41,0:40:04.54,Default,,0,0,0,,你们可以把它想做 Dialogue: 0,0:40:04.56,0:40:06.75,Default,,0,0,0,,如果我们想要推断出某个结论 Dialogue: 0,0:40:07.90,0:40:09.52,Default,,0,0,0,,就可以应用这些逻辑规则 Dialogue: 0,0:40:10.66,0:40:13.20,Default,,0,0,0,,这些就是这门语言中的三种要素 Dialogue: 0,0:40:13.42,0:40:14.56,Default,,0,0,0,,我们先休息一会儿 Dialogue: 0,0:40:14.60,0:40:16.59,Default,,0,0,0,,然后再来讨论如何实际实现 Dialogue: 0,0:40:23.61,0:40:28.84,Default,,0,0,0,,学生:使用LISP-VALUE之类的基本过程会影响 Dialogue: 0,0:40:29.15,0:40:30.64,Default,,0,0,0,,查询的双向性吗? Dialogue: 0,0:40:31.77,0:40:34.48,Default,,0,0,0,,教授:这个问题 -- 你问的是 Dialogue: 0,0:40:35.08,0:40:36.92,Default,,0,0,0,,使用LISP-VALUE是否会影响 Dialogue: 0,0:40:37.53,0:40:40.09,Default,,0,0,0,,双向地推断一条查询 Dialogue: 0,0:40:40.09,0:40:42.81,Default,,0,0,0,,虽然我们还没有实际讨论具体实现 Dialogue: 0,0:40:43.68,0:40:45.52,Default,,0,0,0,,但是它们确实会造成影响 Dialogue: 0,0:40:46.89,0:40:50.20,Default,,0,0,0,,通常来说 我们最后将会发现 Dialogue: 0,0:40:50.22,0:40:52.17,Default,,0,0,0,,虽然我不会讲得太细 Dialogue: 0,0:40:53.21,0:40:59.36,Default,,0,0,0,,当你使用NOT和LISP-VALUE时 会变得相当复杂 Dialogue: 0,0:40:59.55,0:41:02.89,Default,,0,0,0,,或者实际上 只要你用了除AND以外的东西 Dialogue: 0,0:41:04.12,0:41:08.19,Default,,0,0,0,,很难再说清楚这些东西是否会起效了 Dialogue: 0,0:41:08.20,0:41:10.36,Default,,0,0,0,,它们并不是在任何情况下都有效 Dialogue: 0,0:41:10.36,0:41:13.39,Default,,0,0,0,,我会在下一堂课的最后讨论这个问题 Dialogue: 0,0:41:14.30,0:41:15.84,Default,,0,0,0,,但对于你的问题来说:答案是“会影响” Dialogue: 0,0:41:16.19,0:41:19.21,Default,,0,0,0,,用LISP-VALUE一方面从Lisp中获得了巨大威力 Dialogue: 0,0:41:19.40,0:41:23.77,Default,,0,0,0,,另一方面你失去了逻辑式程序设计的重要威力 Dialogue: 0,0:41:24.17,0:41:25.56,Default,,0,0,0,,这是你需要做出的取舍 Dialogue: 0,0:41:28.48,0:41:29.39,Default,,0,0,0,,好吧 先休息一会儿 Dialogue: 0,0:41:30.17,0:41:44.30,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,0:41:30.17,0:41:44.30,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec8a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: None [Aegisub Project Garbage] Scroll Position: 654 Active Line: 681 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:18.27,0:00:19.68,EN,,0,0,0,,PROFESSOR: The last time we began having a look Dialogue: 0,0:00:19.72,0:00:21.26,EN,,0,0,0,,at how languages are constructed. Dialogue: 0,0:00:22.41,0:00:25.88,EN,,0,0,0,,Remember the main point that an evaluator for, LISP, say, Dialogue: 0,0:00:26.08,0:00:27.58,EN,,0,0,0,,has two main elements. Dialogue: 0,0:00:27.58,0:00:28.40,EN,,0,0,0,,There is EVAL, Dialogue: 0,0:00:31.04,0:00:37.42,EN,,0,0,0,,and EVAL's job is to take in an expression and an environment Dialogue: 0,0:00:38.91,0:00:44.44,EN,,0,0,0,,and turn that into a procedure and some arguments Dialogue: 0,0:00:45.42,0:00:47.05,EN,,0,0,0,,and pass that off to APPLY. Dialogue: 0,0:00:49.41,0:00:51.29,EN,,0,0,0,,And APPLY takes the procedure in the arguments, Dialogue: 0,0:00:51.69,0:00:55.12,EN,,0,0,0,,turns that back into, in a general case, another expression Dialogue: 0,0:00:55.39,0:00:57.71,EN,,0,0,0,,to be evaluated in another environment Dialogue: 0,0:00:57.74,0:01:00.00,EN,,0,0,0,,and passes that off to EVAL, which passes it to APPLY, Dialogue: 0,0:01:00.27,0:01:01.44,EN,,0,0,0,,and there's this whole big circle Dialogue: 0,0:01:01.47,0:01:02.94,EN,,0,0,0,,where things go around and around and around Dialogue: 0,0:01:03.02,0:01:06.56,EN,,0,0,0,,until you get either to some very primitive data or to a primitive procedure. Dialogue: 0,0:01:07.74,0:01:09.24,EN,,0,0,0,,See, what this cycle has to do with Dialogue: 0,0:01:09.44,0:01:12.57,EN,,0,0,0,,is unwinding the means of combination Dialogue: 0,0:01:12.59,0:01:14.36,EN,,0,0,0,,and the means of abstraction in the language. Dialogue: 0,0:01:15.02,0:01:17.72,EN,,0,0,0,,So for instance, you have a procedure in LISP-- Dialogue: 0,0:01:17.74,0:01:20.52,EN,,0,0,0,,a procedure is a general way of saying, Dialogue: 0,0:01:20.54,0:01:22.57,EN,,0,0,0,,I want to be able to evaluate this expression Dialogue: 0,0:01:22.67,0:01:24.41,EN,,0,0,0,,for any value of the arguments, Dialogue: 0,0:01:25.76,0:01:27.18,EN,,0,0,0,,and that's sort of what's going on here. Dialogue: 0,0:01:27.67,0:01:28.51,EN,,0,0,0,,That's what APPLY does. Dialogue: 0,0:01:28.51,0:01:30.68,EN,,0,0,0,,It says the general thing coming in with the arguments Dialogue: 0,0:01:30.72,0:01:32.70,EN,,0,0,0,,reduces to the expression that's the body, Dialogue: 0,0:01:33.05,0:01:34.72,EN,,0,0,0,,and then if that's a compound expression Dialogue: 0,0:01:34.83,0:01:36.46,EN,,0,0,0,,or another procedure application, Dialogue: 0,0:01:36.78,0:01:38.44,EN,,0,0,0,,the thing will go around and around the circle. Dialogue: 0,0:01:40.33,0:01:44.08,EN,,0,0,0,,Anyway, that's sort of the basic structure of gee, pretty much any interpreter. Dialogue: 0,0:01:45.20,0:01:46.25,EN,,0,0,0,,The other thing that you saw Dialogue: 0,0:01:46.28,0:01:47.66,EN,,0,0,0,,once you have the interpreter in your hands, Dialogue: 0,0:01:47.69,0:01:49.87,EN,,0,0,0,,you have all this power to start playing with the language. Dialogue: 0,0:01:49.87,0:01:51.52,EN,,0,0,0,,So you can make it dynamically scoped, Dialogue: 0,0:01:51.84,0:01:54.56,EN,,0,0,0,,or you can put in normal order evaluation, Dialogue: 0,0:01:54.59,0:01:56.48,EN,,0,0,0,,or you can add new forms to the language, Dialogue: 0,0:01:56.86,0:01:57.50,EN,,0,0,0,,whatever you like. Dialogue: 0,0:01:57.58,0:01:58.62,EN,,0,0,0,,Or more generally, Dialogue: 0,0:01:58.76,0:02:01.32,EN,,0,0,0,,there's this notion of metalinguistic abstraction, Dialogue: 0,0:02:02.64,0:02:06.01,EN,,0,0,0,,which says that part of your perspective Dialogue: 0,0:02:07.61,0:02:10.52,EN,,0,0,0,,as an engineer, as a software engineer, but as an engineer in general Dialogue: 0,0:02:11.39,0:02:13.88,EN,,0,0,0,,is that you can gain control of complexity Dialogue: 0,0:02:14.96,0:02:17.16,EN,,0,0,0,,by inventing new languages sometimes. Dialogue: 0,0:02:18.01,0:02:20.81,EN,,0,0,0,,See, one way to think about computer programming Dialogue: 0,0:02:21.55,0:02:26.27,EN,,0,0,0,,is that it only incidentally has to do with getting a computer to do something. Dialogue: 0,0:02:26.44,0:02:28.97,EN,,0,0,0,,Primarily what a computer program has to do with, Dialogue: 0,0:02:29.00,0:02:32.52,EN,,0,0,0,,it's a way of expressing ideas with communicating ideas. Dialogue: 0,0:02:33.16,0:02:34.04,EN,,0,0,0,,And sometimes Dialogue: 0,0:02:34.89,0:02:36.62,EN,,0,0,0,,when you want to communicate new kinds of ideas, Dialogue: 0,0:02:36.65,0:02:38.73,EN,,0,0,0,,you'd like to invent new modes of expressing that. Dialogue: 0,0:02:39.82,0:02:44.99,EN,,0,0,0,,Well, today we're going to apply this framework to build a new language. Dialogue: 0,0:02:45.73,0:02:48.00,EN,,0,0,0,,See, once we have the basic idea of the interpreter, Dialogue: 0,0:02:48.03,0:02:50.27,EN,,0,0,0,,you can pretty much go build any language that you like. Dialogue: 0,0:02:50.83,0:02:53.21,EN,,0,0,0,,So for example, we can go off and build Pascal. Dialogue: 0,0:02:54.37,0:02:55.15,EN,,0,0,0,,And... Dialogue: 0,0:02:56.17,0:02:58.19,EN,,0,0,0,,gee, we would worry about syntax and parsing Dialogue: 0,0:02:58.19,0:03:00.51,EN,,0,0,0,,and various kinds of compiler optimizations, Dialogue: 0,0:03:01.12,0:03:03.29,EN,,0,0,0,,and there are people who make honest livings doing that, Dialogue: 0,0:03:03.85,0:03:07.60,EN,,0,0,0,,but at the level of abstraction that we're talking, Dialogue: 0,0:03:08.04,0:03:10.99,EN,,0,0,0,,a Pascal interpreter would not look very different at all Dialogue: 0,0:03:12.03,0:03:13.76,EN,,0,0,0,,from what you saw Gerry do last time. Dialogue: 0,0:03:15.02,0:03:18.96,EN,,0,0,0,,Instead of that, we'll spend today building a really different language, Dialogue: 0,0:03:20.51,0:03:22.81,EN,,0,0,0,,a language that encourages you Dialogue: 0,0:03:23.05,0:03:26.04,EN,,0,0,0,,to think about programming not in terms of procedures, Dialogue: 0,0:03:26.24,0:03:27.64,EN,,0,0,0,,but in a really different way. Dialogue: 0,0:03:29.09,0:03:31.02,EN,,0,0,0,,And the lecture today is Dialogue: 0,0:03:31.74,0:03:34.64,EN,,0,0,0,,going to be at two levels simultaneously. Dialogue: 0,0:03:34.81,0:03:35.52,EN,,0,0,0,,On the one hand, Dialogue: 0,0:03:35.90,0:03:37.71,EN,,0,0,0,,I'm going to show you what this language looks like, Dialogue: 0,0:03:38.96,0:03:41.08,EN,,0,0,0,,and on the other hand, I'll show you how it's implemented. Dialogue: 0,0:03:41.32,0:03:42.96,EN,,0,0,0,,And we'll build an implementation in LISP Dialogue: 0,0:03:42.99,0:03:43.90,EN,,0,0,0,,and see how that works. Dialogue: 0,0:03:44.04,0:03:48.25,EN,,0,0,0,,And you should be drawing lessons on two levels. Dialogue: 0,0:03:48.68,0:03:53.00,EN,,0,0,0,,The first is to realize just how different a language can be. Dialogue: 0,0:03:53.79,0:03:58.14,EN,,0,0,0,,So if you think that the jump from Fortran to LISP is a big deal, Dialogue: 0,0:03:58.24,0:03:59.36,EN,,0,0,0,,you haven't seen anything yet. Dialogue: 0,0:04:01.56,0:04:03.68,EN,,0,0,0,,And secondly, Dialogue: 0,0:04:03.77,0:04:06.54,EN,,0,0,0,,you'll see that even with such a very different language, Dialogue: 0,0:04:07.36,0:04:09.52,EN,,0,0,0,,which will turn out to not have procedures at all Dialogue: 0,0:04:09.92,0:04:11.64,EN,,0,0,0,,and not talk about functions at all, Dialogue: 0,0:04:12.20,0:04:15.72,EN,,0,0,0,,there will still be this basic cycle of eval and apply Dialogue: 0,0:04:16.19,0:04:19.98,EN,,0,0,0,,that's unwinds the means of combination and the means an abstraction. Dialogue: 0,0:04:20.95,0:04:24.68,EN,,0,0,0,,And then thirdly, as kind of a minor but elegant technical point, Dialogue: 0,0:04:24.89,0:04:28.52,EN,,0,0,0,,you'll see a nice use of streams to avoid backtracking. Dialogue: 0,0:04:32.33,0:04:34.40,EN,,0,0,0,,OK, well, I said that this language is very different. Dialogue: 0,0:04:35.86,0:04:36.64,EN,,0,0,0,,To explain that, Dialogue: 0,0:04:37.05,0:04:42.81,EN,,0,0,0,,let's go back to the very first idea that we talked about in this course, Dialogue: 0,0:04:43.26,0:04:46.54,EN,,0,0,0,,and that was the idea of the distinction between Dialogue: 0,0:04:46.72,0:04:49.52,EN,,0,0,0,,the declarative knowledge of mathematics-- Dialogue: 0,0:04:50.19,0:04:54.14,EN,,0,0,0,,the definition of a square root as a mathematical truth-- Dialogue: 0,0:04:55.48,0:04:59.56,EN,,0,0,0,,and the idea that computer science talks about the how to knowledge-- Dialogue: 0,0:04:59.76,0:05:04.59,EN,,0,0,0,,contrast that definition of square root with a program to compute a square root. Dialogue: 0,0:05:05.97,0:05:07.07,EN,,0,0,0,,That's where we started off. Dialogue: 0,0:05:08.51,0:05:09.52,EN,,0,0,0,,Well, wouldn't it be great Dialogue: 0,0:05:09.88,0:05:12.16,EN,,0,0,0,,if you could somehow bridge this gap Dialogue: 0,0:05:12.81,0:05:16.43,EN,,0,0,0,,and make a programming language which sort of did things, Dialogue: 0,0:05:16.67,0:05:21.61,EN,,0,0,0,,but you talked about it in terms of truth, in declarative terms? Dialogue: 0,0:05:22.38,0:05:25.50,EN,,0,0,0,,So that would be a programming language in which you specify facts. Dialogue: 0,0:05:27.69,0:05:28.88,EN,,0,0,0,,You tell it what is. Dialogue: 0,0:05:28.88,0:05:29.96,EN,,0,0,0,,You say what is true. Dialogue: 0,0:05:30.95,0:05:33.07,EN,,0,0,0,,And then when you want an answer, Dialogue: 0,0:05:33.21,0:05:36.38,EN,,0,0,0,,somehow the language has built into it automatically Dialogue: 0,0:05:37.60,0:05:39.45,EN,,0,0,0,,general kinds of how to knowledge Dialogue: 0,0:05:39.47,0:05:40.64,EN,,0,0,0,,so it can just take your facts Dialogue: 0,0:05:40.89,0:05:42.83,EN,,0,0,0,,and it can evolve these methods on its own Dialogue: 0,0:05:43.31,0:05:46.12,EN,,0,0,0,,using the facts you gave it and maybe some general rules of logic. Dialogue: 0,0:05:49.33,0:05:50.54,EN,,0,0,0,,So for instance, Dialogue: 0,0:05:52.06,0:05:55.12,EN,,0,0,0,,I might go up to this program and start telling it some things. Dialogue: 0,0:05:56.00,0:06:07.08,EN,,0,0,0,,So I might tell it that the son of Adam is Abel. Dialogue: 0,0:06:08.92,0:06:16.51,EN,,0,0,0,,And I might tell it that the son of Adam is Cain. Dialogue: 0,0:06:17.66,0:06:25.08,EN,,0,0,0,,And I might tell it that the son of Cain is Enoch. Dialogue: 0,0:06:27.79,0:06:34.89,EN,,0,0,0,,And I might tell it that the son of Enoch is Irad, Dialogue: 0,0:06:37.02,0:06:40.72,EN,,0,0,0,,and all through the rest of our chapter whatever of Genesis, Dialogue: 0,0:06:41.15,0:06:43.18,EN,,0,0,0,,which ends up ending in Adah, by the way, Dialogue: 0,0:06:43.32,0:06:46.78,EN,,0,0,0,,and this shows the genealogy of Adah from Cain. Dialogue: 0,0:06:48.44,0:06:50.67,EN,,0,0,0,,Anyway, once you tell it these facts, Dialogue: 0,0:06:52.35,0:06:53.40,EN,,0,0,0,,you might ask it things. Dialogue: 0,0:06:53.51,0:06:55.05,EN,,0,0,0,,You might go up to your language and say, Dialogue: 0,0:06:56.06,0:06:59.29,EN,,0,0,0,,who's the son of Adam? Dialogue: 0,0:07:00.42,0:07:04.91,EN,,0,0,0,,And you can very easily imagine having a little general purpose search program Dialogue: 0,0:07:05.52,0:07:06.96,EN,,0,0,0,,which would be able to go through Dialogue: 0,0:07:07.00,0:07:09.26,EN,,0,0,0,,and in response to that say, oh yeah, there are two answers: Dialogue: 0,0:07:09.29,0:07:10.44,EN,,0,0,0,,the son of Adam is Abel Dialogue: 0,0:07:10.68,0:07:12.17,EN,,0,0,0,,and the son of Adam is Cain. Dialogue: 0,0:07:14.14,0:07:14.97,EN,,0,0,0,,Or you might say, Dialogue: 0,0:07:15.07,0:07:16.89,EN,,0,0,0,,based on the very same facts, Dialogue: 0,0:07:18.04,0:07:19.95,EN,,0,0,0,,who is Cain the son of? Dialogue: 0,0:07:21.95,0:07:27.02,EN,,0,0,0,,And then you can imagine generating another slightly different search program Dialogue: 0,0:07:27.92,0:07:29.21,EN,,0,0,0,,which would be able to go through Dialogue: 0,0:07:29.45,0:07:33.05,EN,,0,0,0,,and checked for who is Cain, and son of, Dialogue: 0,0:07:33.52,0:07:34.44,EN,,0,0,0,,and come up with Adam. Dialogue: 0,0:07:35.89,0:07:36.99,EN,,0,0,0,,Or you might say, Dialogue: 0,0:07:38.01,0:07:41.40,EN,,0,0,0,,what's the relationship between Cain and Enoch? Dialogue: 0,0:07:42.07,0:07:45.08,EN,,0,0,0,,And again, a minor variant on that search program. Dialogue: 0,0:07:46.34,0:07:48.16,EN,,0,0,0,,You could figure out that it said son of. Dialogue: 0,0:07:52.88,0:07:54.92,EN,,0,0,0,,But even here in this very simple example, Dialogue: 0,0:07:56.14,0:07:58.44,EN,,0,0,0,,what you see is that a single fact, Dialogue: 0,0:07:58.81,0:08:01.52,EN,,0,0,0,,see, a single fact like the son of Adam is Cain Dialogue: 0,0:08:02.84,0:08:05.52,EN,,0,0,0,,can be used to answer different kinds of questions. Dialogue: 0,0:08:06.52,0:08:08.12,EN,,0,0,0,,You can say, who's Cain the son of, Dialogue: 0,0:08:08.14,0:08:10.92,EN,,0,0,0,,or you can say who's the son of Adam, Dialogue: 0,0:08:10.94,0:08:12.86,EN,,0,0,0,,or you can say what's the relation between Adam and Cain? Dialogue: 0,0:08:12.88,0:08:14.48,EN,,0,0,0,,Those are different questions Dialogue: 0,0:08:15.53,0:08:18.54,EN,,0,0,0,,being run by different traditional procedures Dialogue: 0,0:08:18.68,0:08:20.72,EN,,0,0,0,,all based on the same fact. Dialogue: 0,0:08:22.75,0:08:25.92,EN,,0,0,0,,And that's going to be the essence of the power of this programming style, Dialogue: 0,0:08:26.91,0:08:29.50,EN,,0,0,0,,that one piece of declarative knowledge Dialogue: 0,0:08:30.04,0:08:34.01,EN,,0,0,0,,can be used as the basis for a lot of different kinds of how-to knowledge, Dialogue: 0,0:08:34.81,0:08:37.08,EN,,0,0,0,,as opposed to the kinds of procedures we're writing Dialogue: 0,0:08:37.15,0:08:39.55,EN,,0,0,0,,where you sort of tell it what input you're giving in Dialogue: 0,0:08:39.61,0:08:40.65,EN,,0,0,0,,and what answer you want. Dialogue: 0,0:08:41.49,0:08:44.70,EN,,0,0,0,,So for instance, our square root program can perfectly well answer the question, Dialogue: 0,0:08:44.76,0:08:47.16,EN,,0,0,0,,what's the square root of 144? Dialogue: 0,0:08:48.90,0:08:49.77,EN,,0,0,0,,But in principle, Dialogue: 0,0:08:49.82,0:08:52.83,EN,,0,0,0,,the mathematical definition of square root tells you other things. Dialogue: 0,0:08:52.84,0:08:56.43,EN,,0,0,0,,Like it could say, what is 17 the square root of? Dialogue: 0,0:08:57.59,0:08:59.71,EN,,0,0,0,,And that would be have to be answered by a different program. Dialogue: 0,0:09:01.92,0:09:03.50,EN,,0,0,0,,So the mathematical definition, Dialogue: 0,0:09:03.98,0:09:05.12,EN,,0,0,0,,or in general, the Dialogue: 0,0:09:05.53,0:09:10.30,EN,,0,0,0,,the facts that you give it are somehow unbiased as to what the question is. Dialogue: 0,0:09:10.90,0:09:12.81,EN,,0,0,0,,Whereas the programs we tend to write specifically Dialogue: 0,0:09:12.83,0:09:14.20,EN,,0,0,0,,because they are how-to knowledge Dialogue: 0,0:09:14.24,0:09:16.36,EN,,0,0,0,,tend to be looking for a specific answer. Dialogue: 0,0:09:17.56,0:09:20.12,EN,,0,0,0,,So that's going to be one characteristic of what we're talking about. Dialogue: 0,0:09:21.81,0:09:22.60,EN,,0,0,0,,We can go on. Dialogue: 0,0:09:23.48,0:09:27.52,EN,,0,0,0,,We can imagine that we've given our language some sort of facts. Dialogue: 0,0:09:27.71,0:09:29.61,EN,,0,0,0,,Now let's give it some rules of inference. Dialogue: 0,0:09:30.02,0:09:31.36,EN,,0,0,0,,We can say, for instance, Dialogue: 0,0:09:31.95,0:09:36.19,EN,,0,0,0,,if the-- make up some syntax here-- Dialogue: 0,0:09:36.44,0:09:41.53,EN,,0,0,0,,if the son of x is y-- Dialogue: 0,0:09:41.68,0:09:45.21,EN,,0,0,0,,I'll put question marks to indicate variables here-- Dialogue: 0,0:09:45.61,0:09:56.06,EN,,0,0,0,,if the son of x is y and the son of y is z, Dialogue: 0,0:09:58.96,0:10:08.46,EN,,0,0,0,,then the grandson of x is z. Dialogue: 0,0:10:09.32,0:10:13.40,EN,,0,0,0,,So I can imagine telling my machine that rule Dialogue: 0,0:10:15.00,0:10:17.28,EN,,0,0,0,,and then being able to say, for instance, Dialogue: 0,0:10:17.44,0:10:18.68,EN,,0,0,0,,who's the grandson of Adam? Dialogue: 0,0:10:20.61,0:10:23.64,EN,,0,0,0,,Or who is Irad the grandson of? Dialogue: 0,0:10:24.79,0:10:29.08,EN,,0,0,0,,Or deduce all grandson relationships you possibly can from this information. Dialogue: 0,0:10:31.13,0:10:35.60,EN,,0,0,0,,We can imagine somehow the language knowing how to do that automatically. Dialogue: 0,0:10:40.22,0:10:45.20,EN,,0,0,0,,Ok, Let me give you maybe a little bit more concrete example. Dialogue: 0,0:10:45.77,0:10:51.95,EN,,0,0,0,,Here's a procedure that merges two sorted lists. Dialogue: 0,0:10:53.92,0:11:00.27,EN,,0,0,0,,So x and y are two, say, lists of numbers, Dialogue: 0,0:11:00.30,0:11:04.20,EN,,0,0,0,,lists of distinct numbers, if you like, that are in increasing order. Dialogue: 0,0:11:04.76,0:11:07.53,EN,,0,0,0,,And what merge does is take two such lists Dialogue: 0,0:11:07.71,0:11:10.38,EN,,0,0,0,,and combine them into a list where everything's in increasing order, Dialogue: 0,0:11:11.21,0:11:15.00,EN,,0,0,0,,and this is a pretty easy programs Dialogue: 0,0:11:15.02,0:11:16.14,EN,,0,0,0,,that you ought to be able to write. Dialogue: 0,0:11:16.39,0:11:18.64,EN,,0,0,0,,It says, if x is empty, the answer is y. Dialogue: 0,0:11:18.86,0:11:20.46,EN,,0,0,0,,If y is empty, the answer is x. Dialogue: 0,0:11:21.18,0:11:22.99,EN,,0,0,0,,Otherwise, you compare the first two elements. Dialogue: 0,0:11:22.99,0:11:24.46,EN,,0,0,0,,So you pick out the first thing in x Dialogue: 0,0:11:24.84,0:11:26.01,EN,,0,0,0,,and the first thing in y, Dialogue: 0,0:11:26.81,0:11:31.68,EN,,0,0,0,,and then depending on which of those first elements is less, Dialogue: 0,0:11:32.83,0:11:36.60,EN,,0,0,0,,you stick the lower one on to the result a recursively merging, Dialogue: 0,0:11:37.87,0:11:39.92,EN,,0,0,0,,either chopping the first one off x Dialogue: 0,0:11:40.11,0:11:41.61,EN,,0,0,0,,or chopping the first one off y. Dialogue: 0,0:11:42.40,0:11:43.96,EN,,0,0,0,,That's a standard kind of program. Dialogue: 0,0:11:46.47,0:11:48.41,EN,,0,0,0,,Let's look at the logic. Dialogue: 0,0:11:48.62,0:11:49.79,EN,,0,0,0,,Let's forget about the program Dialogue: 0,0:11:50.28,0:11:52.76,EN,,0,0,0,,and look at the logic on which that procedure is based. Dialogue: 0,0:11:53.82,0:11:55.00,EN,,0,0,0,,See, there's some logic which says, Dialogue: 0,0:11:55.02,0:11:57.21,EN,,0,0,0,,gee, if the first one is less, Dialogue: 0,0:11:57.53,0:12:00.00,EN,,0,0,0,,then we get the answer by sticking something onto the Dialogue: 0,0:12:00.16,0:12:02.12,EN,,0,0,0,,the result of recursively merging the rest. Dialogue: 0,0:12:02.84,0:12:04.09,EN,,0,0,0,,So let's try and be explicit about Dialogue: 0,0:12:04.24,0:12:06.41,EN,,0,0,0,,what that logic is that's making the program work. Dialogue: 0,0:12:08.30,0:12:09.44,EN,,0,0,0,,So here's one piece. Dialogue: 0,0:12:10.13,0:12:11.53,EN,,0,0,0,,Here's the piece of the program which Dialogue: 0,0:12:12.64,0:12:15.26,EN,,0,0,0,,recursively chops down x Dialogue: 0,0:12:15.66,0:12:17.82,EN,,0,0,0,,if the first thing in x is smaller. Dialogue: 0,0:12:19.98,0:12:22.54,EN,,0,0,0,,And if you want to be very explicit about what the logic is there, Dialogue: 0,0:12:23.45,0:12:26.49,EN,,0,0,0,,what's really going on is a deduction, Dialogue: 0,0:12:26.72,0:12:32.38,EN,,0,0,0,,which says, if you know that some list, that we'll call cdr of x, and y Dialogue: 0,0:12:33.29,0:12:35.44,EN,,0,0,0,,merged to form z, Dialogue: 0,0:12:37.84,0:12:41.52,EN,,0,0,0,,And you know that a is less than the first thing in y. Dialogue: 0,0:12:43.60,0:12:48.52,EN,,0,0,0,,then you know that if you put a onto the cdr of x. Dialogue: 0,0:12:49.74,0:12:51.85,EN,,0,0,0,,and that result and y Dialogue: 0,0:12:52.60,0:12:54.99,EN,,0,0,0,,merge-to-form a onto z. Dialogue: 0,0:12:55.82,0:12:58.09,EN,,0,0,0,,And what that is, that's the underlying piece of logic-- Dialogue: 0,0:12:58.72,0:12:59.95,EN,,0,0,0,,I haven't written it as a program, Dialogue: 0,0:12:59.96,0:13:02.00,EN,,0,0,0,,I wrote it a sort of deduction Dialogue: 0,0:13:02.03,0:13:04.89,EN,,0,0,0,,that sits underneath this particular clause Dialogue: 0,0:13:05.21,0:13:07.26,EN,,0,0,0,,that says we can use the recursion there. Dialogue: 0,0:13:09.41,0:13:12.78,EN,,0,0,0,,And then similar, here's the other clause just to complete it. Dialogue: 0,0:13:14.00,0:13:15.87,EN,,0,0,0,,The other clause is based on this piece of logic, Dialogue: 0,0:13:15.92,0:13:18.35,EN,,0,0,0,,which is almost the same and I won't go through it, Dialogue: 0,0:13:19.00,0:13:20.35,EN,,0,0,0,,and then there's the end cases Dialogue: 0,0:13:20.41,0:13:22.01,EN,,0,0,0,,where we tested for null, Dialogue: 0,0:13:22.03,0:13:24.04,EN,,0,0,0,,and that's based on the idea that for any x, Dialogue: 0,0:13:24.51,0:13:27.20,EN,,0,0,0,,x and the empty list merge to form an x, Dialogue: 0,0:13:28.04,0:13:30.86,EN,,0,0,0,,or for any y, the empty list and y merge to form y. Dialogue: 0,0:13:33.36,0:13:38.12,EN,,0,0,0,,OK, so there's a piece of procedure Dialogue: 0,0:13:38.43,0:13:40.11,EN,,0,0,0,,and the logic on which it's based. Dialogue: 0,0:13:41.74,0:13:42.97,EN,,0,0,0,,And notice a big difference. Dialogue: 0,0:13:45.10,0:13:50.52,EN,,0,0,0,,The procedure looked like this: Dialogue: 0,0:13:50.65,0:13:52.28,EN,,0,0,0,,it said there was a box-- Dialogue: 0,0:13:52.86,0:13:55.39,EN,,0,0,0,,and all the things we've been doing have the characteristic Dialogue: 0,0:13:55.40,0:13:57.69,EN,,0,0,0,,we have boxes and things going in and things going out-- Dialogue: 0,0:13:58.08,0:13:59.61,EN,,0,0,0,,there was this box called merge, Dialogue: 0,0:14:01.29,0:14:03.85,EN,,0,0,0,,and in came an x and y, Dialogue: 0,0:14:04.44,0:14:05.37,EN,,0,0,0,,and out came an answer. Dialogue: 0,0:14:07.63,0:14:09.48,EN,,0,0,0,,That's the character of the procedure that we wrote. Dialogue: 0,0:14:13.02,0:14:14.66,EN,,0,0,0,,These rules don't look like that. Dialogue: 0,0:14:14.66,0:14:16.76,EN,,0,0,0,,These rules talk about a relation. Dialogue: 0,0:14:17.92,0:14:24.16,EN,,0,0,0,,There's some sort of relation that in those slides I called mrege-to-form. Dialogue: 0,0:14:25.37,0:14:28.76,EN,,0,0,0,,So I said x and y merge to form z, Dialogue: 0,0:14:29.00,0:14:32.33,EN,,0,0,0,,and somehow this is not -- this is a function. Dialogue: 0,0:14:32.61,0:14:32.85,EN,,0,0,0,,Right? Dialogue: 0,0:14:32.85,0:14:34.41,EN,,0,0,0,,The answer is a function of x and y, Dialogue: 0,0:14:34.59,0:14:38.19,EN,,0,0,0,,and here what I have is a relation between three things. Dialogue: 0,0:14:39.72,0:14:41.32,EN,,0,0,0,,And I'm not going to specify Dialogue: 0,0:14:42.09,0:14:43.77,EN,,0,0,0,,which is the input and which is the output. Dialogue: 0,0:14:44.20,0:14:47.40,EN,,0,0,0,,And the reason I want to say that is because in principle, Dialogue: 0,0:14:48.64,0:14:50.83,EN,,0,0,0,,we could use exactly those same logic rules Dialogue: 0,0:14:50.84,0:14:52.44,EN,,0,0,0,,answer a lot of different questions. Dialogue: 0,0:14:54.57,0:14:56.30,EN,,0,0,0,,So we can say, for instance-- giving Dialogue: 0,0:14:56.72,0:14:59.05,EN,,0,0,0,,imagine giving our machine those rules of logic. Dialogue: 0,0:14:59.05,0:15:01.20,EN,,0,0,0,,Not the program, the underlying rules of logic. Dialogue: 0,0:15:01.40,0:15:03.12,EN,,0,0,0,,Then it ought to be able to say-- Dialogue: 0,0:15:04.75,0:15:05.52,EN,,0,0,0,,we could ask it-- Dialogue: 0,0:15:06.73,0:15:19.18,EN,,0,0,0,,1, 3, 7 and 2, 4, 8 merge to form what? Dialogue: 0,0:15:20.91,0:15:23.42,EN,,0,0,0,,And that's a question it ought to be able to answer. Dialogue: 0,0:15:23.88,0:15:27.36,EN,,0,0,0,,That's exactly the same question that our Lisp procedure answered. Dialogue: 0,0:15:28.18,0:15:30.14,EN,,0,0,0,,But the exact same rules Dialogue: 0,0:15:30.89,0:15:34.80,EN,,0,0,0,,should also be able to answer a question like this: Dialogue: 0,0:15:36.19,0:15:43.24,EN,,0,0,0,,1, 3, 7 and what merged to form 1, 2, 3, 4, 7, 8? Dialogue: 0,0:15:45.56,0:15:47.80,EN,,0,0,0,,The same rules of logic can answer this, Dialogue: 0,0:15:47.84,0:15:49.90,EN,,0,0,0,,although the procedure we wrote can't answer that question. Dialogue: 0,0:15:50.80,0:15:52.33,EN,,0,0,0,,Or we might be able to say what Dialogue: 0,0:15:53.71,0:16:01.12,EN,,0,0,0,,what and what else merge to form-- Dialogue: 0,0:16:04.28,0:16:12.68,EN,,0,0,0,,what and what else merge to form 1, 2, 3, 4, 7, 8? Dialogue: 0,0:16:13.78,0:16:15.34,EN,,0,0,0,,And the thing should be able to go through, Dialogue: 0,0:16:15.84,0:16:17.31,EN,,0,0,0,,if it really can apply that logic, Dialogue: 0,0:16:17.79,0:16:22.54,EN,,0,0,0,,and deduce all, whatever is, 2 to the sixth answers to that question. Dialogue: 0,0:16:25.60,0:16:27.69,EN,,0,0,0,,Cause it could be 1 and the rester, or it could be 1, 2 and the rest. Dialogue: 0,0:16:27.69,0:16:28.75,EN,,0,0,0,,or it could be 1, 2 and the rester. Dialogue: 0,0:16:28.79,0:16:31.53,EN,,0,0,0,,Or it could be 1 and 3 and 7 and the rest. Dialogue: 0,0:16:32.01,0:16:33.26,EN,,0,0,0,,There's a whole bunch of answers. Dialogue: 0,0:16:33.41,0:16:37.76,EN,,0,0,0,,And in principle, the logic should be enough to deduce that. Dialogue: 0,0:16:38.55,0:16:42.03,EN,,0,0,0,,So there are going to be two big differences Dialogue: 0,0:16:44.04,0:16:46.00,EN,,0,0,0,,in the kind of program we're going to look at Dialogue: 0,0:16:46.54,0:16:48.19,EN,,0,0,0,,and not only Lisp, Dialogue: 0,0:16:48.20,0:16:50.56,EN,,0,0,0,,but essentially all the programming you've probably done so far Dialogue: 0,0:16:52.03,0:16:53.60,EN,,0,0,0,,in pretty much any language you can think of. Dialogue: 0,0:16:54.15,0:16:57.79,EN,,0,0,0,,The first is, we're not going to be computing functions. Dialogue: 0,0:17:00.62,0:17:02.01,EN,,0,0,0,,We're not going to be talking about Dialogue: 0,0:17:02.62,0:17:04.41,EN,,0,0,0,,about things that take input and output. Dialogue: 0,0:17:04.41,0:17:05.82,EN,,0,0,0,,We're going to be talking about relations. Dialogue: 0,0:17:06.89,0:17:10.00,EN,,0,0,0,,And that means in principle, these relations don't have directionality. Dialogue: 0,0:17:11.08,0:17:15.05,EN,,0,0,0,,So the knowledge that you specify to answer this question, Dialogue: 0,0:17:16.46,0:17:18.41,EN,,0,0,0,,should be same, that same knowledge Dialogue: 0,0:17:18.43,0:17:21.80,EN,,0,0,0,,also allow you to answer these other questions and conversely. Dialogue: 0,0:17:26.60,0:17:29.40,EN,,0,0,0,,And the second issue is that Dialogue: 0,0:17:29.61,0:17:31.23,EN,,0,0,0,,since we're talking about relations, Dialogue: 0,0:17:32.32,0:17:34.44,EN,,0,0,0,,these relations don't necessarily have one answer. Dialogue: 0,0:17:35.61,0:17:37.00,EN,,0,0,0,,So that third question down there Dialogue: 0,0:17:37.02,0:17:38.36,EN,,0,0,0,,doesn't have a particular answer, Dialogue: 0,0:17:38.40,0:17:39.58,EN,,0,0,0,,it has a whole bunch of answers. Dialogue: 0,0:17:42.27,0:17:44.64,EN,,0,0,0,,Well, that's where we're going. Dialogue: 0,0:17:44.64,0:17:45.90,EN,,0,0,0,,This style of programming, Dialogue: 0,0:17:46.72,0:17:49.21,EN,,0,0,0,,by the way, is called logic programming, Dialogue: 0,0:17:50.22,0:17:51.58,EN,,0,0,0,,for kind of obvious reasons. Dialogue: 0,0:17:56.16,0:18:00.38,EN,,0,0,0,,And people who do logic programming say that -- Dialogue: 0,0:18:00.40,0:18:03.15,EN,,0,0,0,,they have this little phrase-- Dialogue: 0,0:18:03.16,0:18:04.67,EN,,0,0,0,,they say the point of logic programming Dialogue: 0,0:18:04.76,0:18:09.00,EN,,0,0,0,,is that you use logic to express what is true, Dialogue: 0,0:18:10.09,0:18:13.88,EN,,0,0,0,,you use logic to check whether something is true, Dialogue: 0,0:18:14.67,0:18:17.24,EN,,0,0,0,,and you use logic to find out what is true. Dialogue: 0,0:18:19.20,0:18:22.09,EN,,0,0,0,,The best known logic programming language, Dialogue: 0,0:18:22.97,0:18:24.78,EN,,0,0,0,,as you probably know, is called Prolog. Dialogue: 0,0:18:25.78,0:18:28.88,EN,,0,0,0,,The language that we're going to implement this morning Dialogue: 0,0:18:29.82,0:18:32.32,EN,,0,0,0,,is something we call the query language, Dialogue: 0,0:18:32.48,0:18:34.41,EN,,0,0,0,,and it essentially has the essence of prolog. Dialogue: 0,0:18:35.32,0:18:36.73,EN,,0,0,0,,It can do about the same stuff, Dialogue: 0,0:18:37.29,0:18:38.73,EN,,0,0,0,,although it's a lot slower Dialogue: 0,0:18:38.73,0:18:40.01,EN,,0,0,0,,because we're going to implement it in LISP Dialogue: 0,0:18:41.90,0:18:44.36,EN,,0,0,0,,rather than building a particular compiler. Dialogue: 0,0:18:44.46,0:18:46.62,EN,,0,0,0,,We're going to interpret it on top of the LISP interpreter. Dialogue: 0,0:18:47.51,0:18:49.84,EN,,0,0,0,,But other than that, it can do about the same stuff as prolog. Dialogue: 0,0:18:49.88,0:18:52.78,EN,,0,0,0,,It has about the same power and about the same limitations. Dialogue: 0,0:18:55.08,0:18:56.17,EN,,0,0,0,,All right, let's break for question. Dialogue: 0,0:19:00.43,0:19:02.84,EN,,0,0,0,,AUDIENCE: Yes, could you please repeat what the three Dialogue: 0,0:19:03.48,0:19:06.09,EN,,0,0,0,,things you use logic programming to find? Dialogue: 0,0:19:06.72,0:19:09.84,EN,,0,0,0,,In other words, to find what is true, learn what is true-- what is the? Dialogue: 0,0:19:09.84,0:19:10.52,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:19:10.56,0:19:15.74,EN,,0,0,0,,Sort of a logic programmer's little catechism. Dialogue: 0,0:19:15.85,0:19:19.16,EN,,0,0,0,,You use logic to express what is true, Dialogue: 0,0:19:20.80,0:19:21.79,EN,,0,0,0,,like these rules. Dialogue: 0,0:19:22.61,0:19:25.56,EN,,0,0,0,,You use logic to check whether something is true, Dialogue: 0,0:19:25.60,0:19:27.76,EN,,0,0,0,,and that's the kind of question I didn't answer here. Dialogue: 0,0:19:28.55,0:19:29.29,EN,,0,0,0,,I might say-- Dialogue: 0,0:19:29.68,0:19:32.14,EN,,0,0,0,,another question I could put down here is to say, Dialogue: 0,0:19:33.26,0:19:36.56,EN,,0,0,0,,is it true that 1, 3, 7 and 2, 4, 8 Dialogue: 0,0:19:36.91,0:19:40.38,EN,,0,0,0,,merge to form 1, 2, 6, 10 Dialogue: 0,0:19:41.12,0:19:44.68,EN,,0,0,0,,And that same logic should be enough to say no. Dialogue: 0,0:19:45.69,0:19:47.93,EN,,0,0,0,,So I use logic to check what is true, Dialogue: 0,0:19:48.28,0:19:50.48,EN,,0,0,0,,and then you also use logic to find out what's true. Dialogue: 0,0:20:04.46,0:20:05.16,EN,,0,0,0,,Let's break. Dialogue: 0,0:20:06.13,0:20:17.02,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:21:03.24,0:21:04.97,EN,,0,0,0,,PROFESSOR: OK, let's go ahead and Dialogue: 0,0:21:05.84,0:21:08.44,EN,,0,0,0,,take a look at this query language and operation. Dialogue: 0,0:21:10.52,0:21:11.84,EN,,0,0,0,,The first thing you might notice, Dialogue: 0,0:21:12.24,0:21:14.14,EN,,0,0,0,,when I put up that little biblical database, Dialogue: 0,0:21:14.16,0:21:17.24,EN,,0,0,0,,is that it's nice to be able to ask this language questions Dialogue: 0,0:21:17.48,0:21:19.92,EN,,0,0,0,,in relation to some collection of facts. Dialogue: 0,0:21:21.33,0:21:25.15,EN,,0,0,0,,So let's start off and make a little collection of facts. Dialogue: 0,0:21:26.06,0:21:29.68,EN,,0,0,0,,This is a tiny fragment of personnel records Dialogue: 0,0:21:30.08,0:21:32.62,EN,,0,0,0,,for a Boston high tech company, Dialogue: 0,0:21:33.05,0:21:36.80,EN,,0,0,0,,and here's a piece of the personnel records of Ben Bitdiddle. Dialogue: 0,0:21:37.50,0:21:41.95,EN,,0,0,0,,And Ben Bitdiddle is the computer wizard in this company, Dialogue: 0,0:21:42.84,0:21:45.80,EN,,0,0,0,,he's the underpaid computer wizard in this company. Dialogue: 0,0:21:46.42,0:21:48.78,EN,,0,0,0,,His supervisor is all Oliver Warbucks, Dialogue: 0,0:21:49.28,0:21:50.70,EN,,0,0,0,,and here's his address. Dialogue: 0,0:21:52.15,0:21:56.54,EN,,0,0,0,,So the format is we're giving this information: job, salary, supervisor, address. Dialogue: 0,0:21:57.56,0:21:59.25,EN,,0,0,0,,And there are some other conventions. Dialogue: 0,0:21:59.25,0:22:02.22,EN,,0,0,0,,Computer here means that Ben works in the computer division, and Dialogue: 0,0:22:02.76,0:22:04.94,EN,,0,0,0,,his position in the computer division is wizard. Dialogue: 0,0:22:05.66,0:22:07.15,EN,,0,0,0,,Here's somebody else. Dialogue: 0,0:22:07.16,0:22:12.28,EN,,0,0,0,,Alyssa, Alyssa P. Hacker is a computer programmer, Dialogue: 0,0:22:13.36,0:22:14.60,EN,,0,0,0,,and she works for Ben, Dialogue: 0,0:22:15.21,0:22:16.54,EN,,0,0,0,,and she lives in Cambridge. Dialogue: 0,0:22:17.55,0:22:19.42,EN,,0,0,0,,And there's another programmer who works for Ben Dialogue: 0,0:22:20.03,0:22:21.44,EN,,0,0,0,,who's Lem E. Tweakit. Dialogue: 0,0:22:22.82,0:22:26.73,EN,,0,0,0,,And there's a programmer trainee, who is Louis Reasoner, Dialogue: 0,0:22:27.42,0:22:28.62,EN,,0,0,0,,and he works for Alyssa. Dialogue: 0,0:22:30.10,0:22:35.45,EN,,0,0,0,,And the big wheel of the company doesn't work for anybody. Dialogue: 0,0:22:36.81,0:22:38.11,EN,,0,0,0,,Right, That's Oliver Warbucks. Dialogue: 0,0:22:38.11,0:22:39.31,EN,,0,0,0,,Anyway, what we're going to do is Dialogue: 0,0:22:40.94,0:22:43.66,EN,,0,0,0,,is ask questions about that little world. Dialogue: 0,0:22:44.97,0:22:48.40,EN,,0,0,0,,And that'll be a sample world that we're going to do logic in. Dialogue: 0,0:22:51.42,0:22:54.96,EN,,0,0,0,,Let me just write up here, for probably the last time, Dialogue: 0,0:22:55.60,0:22:58.20,EN,,0,0,0,,what I said is the very most important thing you should get out of this course, Dialogue: 0,0:22:58.80,0:23:01.66,EN,,0,0,0,,and that is, when somebody tells you about a language, Dialogue: 0,0:23:02.25,0:23:04.43,EN,,0,0,0,,you say, fine-- what are the primitives, Dialogue: 0,0:23:06.12,0:23:07.79,EN,,0,0,0,,what are the means of combination, Dialogue: 0,0:23:14.70,0:23:16.40,EN,,0,0,0,,how do you put the primitives together, Dialogue: 0,0:23:16.67,0:23:19.37,EN,,0,0,0,,and then how do you abstract them, Dialogue: 0,0:23:19.96,0:23:21.93,EN,,0,0,0,,how do you abstract the compound pieces Dialogue: 0,0:23:24.68,0:23:27.58,EN,,0,0,0,,so you can use them as pieces to make something more complicated? Dialogue: 0,0:23:29.02,0:23:30.81,EN,,0,0,0,,And we've said this a whole bunch of times already, Dialogue: 0,0:23:31.16,0:23:32.48,EN,,0,0,0,,but it's worth saying again. Dialogue: 0,0:23:35.00,0:23:36.67,EN,,0,0,0,,OKay? Let's start. Dialogue: 0,0:23:36.67,0:23:37.34,EN,,0,0,0,,The primitives. Dialogue: 0,0:23:37.77,0:23:39.44,EN,,0,0,0,,Well, there's really only one primitive, Dialogue: 0,0:23:40.96,0:23:43.20,EN,,0,0,0,,and the primitive in this language is called a query. Dialogue: 0,0:23:44.14,0:23:45.74,EN,,0,0,0,,A primitive query. Dialogue: 0,0:23:46.81,0:23:48.25,EN,,0,0,0,,Let's look at some primitive queries. Dialogue: 0,0:23:51.82,0:23:53.02,EN,,0,0,0,,Alright. Job x. Dialogue: 0,0:23:53.10,0:23:54.81,EN,,0,0,0,,Who is a computer programmer? Dialogue: 0,0:23:55.55,0:23:59.88,EN,,0,0,0,,Or find every fact in the database Dialogue: 0,0:24:01.55,0:24:06.14,EN,,0,0,0,,that matches job of the x is computer programmer. Dialogue: 0,0:24:06.64,0:24:08.01,EN,,0,0,0,,And you see a little syntax here. Dialogue: 0,0:24:08.47,0:24:10.59,EN,,0,0,0,,Things without question marks are meant to be literal, Dialogue: 0,0:24:11.28,0:24:13.15,EN,,0,0,0,,question mark x means that's a variable, Dialogue: 0,0:24:13.31,0:24:15.56,EN,,0,0,0,,and this thing will match, for example, Dialogue: 0,0:24:16.03,0:24:19.00,EN,,0,0,0,,the fact that Alyssa P. Hacker is a computer programmer, Dialogue: 0,0:24:19.28,0:24:21.93,EN,,0,0,0,,or x is Alyssa P. Hacker. Dialogue: 0,0:24:26.82,0:24:29.98,EN,,0,0,0,,Or more generally, I could have something with two variables in it. Dialogue: 0,0:24:30.75,0:24:31.45,EN,,0,0,0,,I could say, Dialogue: 0,0:24:31.60,0:24:35.88,EN,,0,0,0,,the job of x is computer something, Dialogue: 0,0:24:39.34,0:24:41.39,EN,,0,0,0,,and that'll match computer wizard. Dialogue: 0,0:24:42.14,0:24:44.28,EN,,0,0,0,,So there's something here: type will match wizard, Dialogue: 0,0:24:44.92,0:24:46.46,EN,,0,0,0,,or type will match programmer, Dialogue: 0,0:24:47.48,0:24:50.37,EN,,0,0,0,,or x might match various certain things. Dialogue: 0,0:24:50.37,0:24:52.24,EN,,0,0,0,,So there are, in our little example, Dialogue: 0,0:24:52.25,0:24:55.15,EN,,0,0,0,,only three facts in that database that match that query. Dialogue: 0,0:24:59.12,0:25:02.08,EN,,0,0,0,,Let's see, just to show you some syntax, the same query, Dialogue: 0,0:25:05.29,0:25:08.09,EN,,0,0,0,,this query doesn't match the job of x, Dialogue: 0,0:25:09.85,0:25:11.79,EN,,0,0,0,,doesn't match Lewis Reasoner, Dialogue: 0,0:25:11.84,0:25:13.64,EN,,0,0,0,,the reason for that is when I write something here, Dialogue: 0,0:25:14.22,0:25:17.74,EN,,0,0,0,,what I mean is that this is going to be a list of two symbols, Dialogue: 0,0:25:19.96,0:25:21.96,EN,,0,0,0,,of which the first is the word computer, Dialogue: 0,0:25:22.32,0:25:23.80,EN,,0,0,0,,and the second can be anything. Dialogue: 0,0:25:25.08,0:25:27.32,EN,,0,0,0,,And Lewis's job description here has three symbols, Dialogue: 0,0:25:27.80,0:25:28.83,EN,,0,0,0,,so it doesn't match. Dialogue: 0,0:25:30.34,0:25:32.19,EN,,0,0,0,,And just to show you a little bit of syntax, Dialogue: 0,0:25:35.04,0:25:38.32,EN,,0,0,0,,the more general thing I might want to type is a thing with a dot here, Dialogue: 0,0:25:40.17,0:25:42.92,EN,,0,0,0,,and this is just standard list notation for saying, Dialogue: 0,0:25:43.04,0:25:43.82,EN,,0,0,0,,this is a list, Dialogue: 0,0:25:44.12,0:25:47.32,EN,,0,0,0,,of which the first element is the word computers, Dialogue: 0,0:25:47.58,0:25:50.22,EN,,0,0,0,,and THE REST, is something that I'll call type. Dialogue: 0,0:25:53.73,0:25:55.50,EN,,0,0,0,,So this one would match. Dialogue: 0,0:25:56.93,0:25:59.31,EN,,0,0,0,,Lewis's job is computer programmer trainee, Dialogue: 0,0:25:59.44,0:26:03.29,EN,,0,0,0,,and type here would be the cdr of this list. Dialogue: 0,0:26:03.32,0:26:05.64,EN,,0,0,0,,It would be the list programmer trainee. Dialogue: 0,0:26:06.96,0:26:10.46,EN,,0,0,0,,And that kind of dot processing is done automatically by the LISP reader. Dialogue: 0,0:26:15.90,0:26:17.76,EN,,0,0,0,,Well, let's actually try this. Dialogue: 0,0:26:17.76,0:26:20.51,EN,,0,0,0,,The idea is I'm going to type in queries in this language, Dialogue: 0,0:26:20.76,0:26:21.82,EN,,0,0,0,,and answers will come out. Dialogue: 0,0:26:22.54,0:26:24.48,EN,,0,0,0,,Let's look at this. Dialogue: 0,0:26:25.18,0:26:26.51,EN,,0,0,0,,I can go up and say, Dialogue: 0,0:26:27.34,0:26:28.88,EN,,0,0,0,,who works in the computer division? Dialogue: 0,0:26:30.00,0:26:38.22,EN,,0,0,0,,Job of x is computer dot y. Dialogue: 0,0:26:39.73,0:26:41.48,EN,,0,0,0,,Doesn't matter what I call the dummy variables. Dialogue: 0,0:26:42.76,0:26:44.14,EN,,0,0,0,,It says the answers to that, Dialogue: 0,0:26:44.41,0:26:45.68,EN,,0,0,0,,and it's found four answers. Dialogue: 0,0:26:48.65,0:26:50.09,EN,,0,0,0,,Or I can go off and say, Dialogue: 0,0:26:50.56,0:26:52.38,EN,,0,0,0,,tell me about everybody's supervisor. Dialogue: 0,0:26:52.81,0:26:54.88,EN,,0,0,0,,So I'll put in the query, the primitive query, Dialogue: 0,0:26:56.52,0:26:59.39,EN,,0,0,0,,the supervisor of x is y. Dialogue: 0,0:27:02.56,0:27:05.42,EN,,0,0,0,,There are all the supervisor relationships I know. Dialogue: 0,0:27:05.54,0:27:08.83,EN,,0,0,0,,Or I could go type in, who lives in Cambridge? Dialogue: 0,0:27:08.83,0:27:09.47,EN,,0,0,0,,So I can say, Dialogue: 0,0:27:10.24,0:27:20.92,EN,,0,0,0,,the address of x is Cambridge dot anything. Dialogue: 0,0:27:25.09,0:27:26.89,EN,,0,0,0,,And only one person lives in Cambridge. Dialogue: 0,0:27:30.82,0:27:32.17,EN,,0,0,0,,OK, so those are primitive queries. Dialogue: 0,0:27:32.17,0:27:34.96,EN,,0,0,0,,And you see what happens to basic interaction with the system Dialogue: 0,0:27:35.29,0:27:39.24,EN,,0,0,0,,is you type in a query, and it types out all possible answers. Dialogue: 0,0:27:39.62,0:27:40.65,EN,,0,0,0,,Or another way to say that: Dialogue: 0,0:27:40.67,0:27:44.16,EN,,0,0,0,,it finds out all the possible values of those variables Dialogue: 0,0:27:44.19,0:27:45.87,EN,,0,0,0,,x and y or t or whatever I've called them, Dialogue: 0,0:27:46.09,0:27:52.08,EN,,0,0,0,,and it types out all ways of taking that query and instantiating it-- Dialogue: 0,0:27:52.92,0:27:55.16,EN,,0,0,0,,remember that from the rule system lecture-- Dialogue: 0,0:27:55.16,0:27:58.83,EN,,0,0,0,,instantiates the query with all possible values for those variables Dialogue: 0,0:27:59.00,0:28:00.35,EN,,0,0,0,,and then types out all of them. Dialogue: 0,0:28:01.00,0:28:03.35,EN,,0,0,0,,And there are a lot of ways you can arrange a logic language. Dialogue: 0,0:28:03.35,0:28:06.01,EN,,0,0,0,,Prolog, for instance, does something slightly different. Dialogue: 0,0:28:06.01,0:28:07.44,EN,,0,0,0,,Rather than typing back your query, Dialogue: 0,0:28:07.76,0:28:10.78,EN,,0,0,0,,prolog would type out, x equals this and y equals that, Dialogue: 0,0:28:10.97,0:28:12.94,EN,,0,0,0,,or x equals this and y equals that. Dialogue: 0,0:28:13.66,0:28:15.48,EN,,0,0,0,,And that's a very surface level thing, Dialogue: 0,0:28:15.71,0:28:17.05,EN,,0,0,0,,you can decide what you like. Dialogue: 0,0:28:18.97,0:28:19.58,EN,,0,0,0,,OK. Dialogue: 0,0:28:21.00,0:28:22.68,EN,,0,0,0,,Alright. So the primitives in this language? Dialogue: 0,0:28:23.39,0:28:24.57,EN,,0,0,0,,Only one, right? Dialogue: 0,0:28:24.57,0:28:27.23,EN,,0,0,0,,Primitive query. Dialogue: 0,0:28:31.31,0:28:32.56,EN,,0,0,0,,Means of combination. Dialogue: 0,0:28:34.33,0:28:37.68,EN,,0,0,0,,Let's look at some compound queries in this language. Dialogue: 0,0:28:39.77,0:28:40.46,EN,,0,0,0,,Here's one. Dialogue: 0,0:28:41.79,0:28:42.51,EN,,0,0,0,,This one says, Dialogue: 0,0:28:45.05,0:28:48.22,EN,,0,0,0,,tell me all the people who work in the computer division. Dialogue: 0,0:28:49.81,0:28:52.00,EN,,0,0,0,,Tell me all the people who work in the computer division Dialogue: 0,0:28:52.54,0:28:53.96,EN,,0,0,0,,together with their supervisors. Dialogue: 0,0:28:56.80,0:28:58.83,EN,,0,0,0,,Where I write that is the query is and. Dialogue: 0,0:29:00.22,0:29:04.06,EN,,0,0,0,,And the job of the x is computer something or other. Dialogue: 0,0:29:04.92,0:29:06.83,EN,,0,0,0,,And job of x is computer dot y. Dialogue: 0,0:29:07.56,0:29:10.03,EN,,0,0,0,,And the supervisor of x is z. Dialogue: 0,0:29:11.44,0:29:14.16,EN,,0,0,0,,Tell me all the people in the computer division-- that's this-- Dialogue: 0,0:29:14.30,0:29:15.88,EN,,0,0,0,,together with their supervisors. Dialogue: 0,0:29:16.46,0:29:17.82,EN,,0,0,0,,And notice in this query Dialogue: 0,0:29:18.67,0:29:22.41,EN,,0,0,0,,I have three variables-- x, y, and z. Dialogue: 0,0:29:23.58,0:29:28.65,EN,,0,0,0,,And this x is supposed to be the same as that x. Dialogue: 0,0:29:29.45,0:29:31.16,EN,,0,0,0,,So x works in the computer division, Dialogue: 0,0:29:31.31,0:29:33.00,EN,,0,0,0,,and the supervisor of x is z. Dialogue: 0,0:29:34.81,0:29:35.80,EN,,0,0,0,,Let's try another one. Dialogue: 0,0:29:37.25,0:29:39.28,EN,,0,0,0,,So one means of combination is and. Dialogue: 0,0:29:41.44,0:29:43.96,EN,,0,0,0,,Who are all the people who make more than $30,000? Dialogue: 0,0:29:45.71,0:29:51.71,EN,,0,0,0,,And the salary of some person p is some amount a. Dialogue: 0,0:29:54.59,0:29:57.45,EN,,0,0,0,,And when I go and look at a, Dialogue: 0,0:29:57.48,0:30:00.12,EN,,0,0,0,,a is greater than $30,000. Dialogue: 0,0:30:00.60,0:30:03.23,EN,,0,0,0,,And LISP value here is a little piece of interface Dialogue: 0,0:30:04.30,0:30:10.04,EN,,0,0,0,,that interfaces the query language to the underlying LISP. Dialogue: 0,0:30:10.60,0:30:12.72,EN,,0,0,0,,And what the LISP value allows you to do Dialogue: 0,0:30:12.75,0:30:16.91,EN,,0,0,0,,call any LISP predicate inside a query. Dialogue: 0,0:30:17.18,0:30:20.11,EN,,0,0,0,,So here I'm using the LISP predicate greater than, so I say LISP value. Dialogue: 0,0:30:21.02,0:30:21.75,EN,,0,0,0,,This I say and. Dialogue: 0,0:30:21.75,0:30:24.48,EN,,0,0,0,,So all the people whose salary is greater than $30,000. Dialogue: 0,0:30:28.19,0:30:30.03,EN,,0,0,0,,Or here's a more complicated one. Dialogue: 0,0:30:31.27,0:30:35.02,EN,,0,0,0,,Tell me all the people who work in the computer division Dialogue: 0,0:30:36.25,0:30:39.36,EN,,0,0,0,,who do not have a supervisor who works in the computer division. Dialogue: 0,0:30:42.79,0:30:45.51,EN,,0,0,0,,and x works in the computer division. Dialogue: 0,0:30:45.51,0:30:47.32,EN,,0,0,0,,The job of x is computer dot y. Dialogue: 0,0:30:47.78,0:30:49.24,EN,,0,0,0,,And it's not the case Dialogue: 0,0:30:50.49,0:30:54.25,EN,,0,0,0,,that both x has a supervisor z Dialogue: 0,0:30:55.37,0:30:57.87,EN,,0,0,0,,and the job of z is computer something or other. Dialogue: 0,0:30:59.62,0:31:00.35,EN,,0,0,0,,All right, so again, Dialogue: 0,0:31:00.51,0:31:02.38,EN,,0,0,0,,this x has got to be that x, Dialogue: 0,0:31:03.20,0:31:05.76,EN,,0,0,0,,and this z is going to be that z. Dialogue: 0,0:31:09.39,0:31:11.38,EN,,0,0,0,,And then you see another means a combination, not. Dialogue: 0,0:31:17.71,0:31:18.67,EN,,0,0,0,,All right, well, let's look at that. Dialogue: 0,0:31:20.88,0:31:22.08,EN,,0,0,0,,It works the same way. Dialogue: 0,0:31:22.40,0:31:24.12,EN,,0,0,0,,I can go up to the machine and say Dialogue: 0,0:31:26.89,0:31:35.40,EN,,0,0,0,,and the job of the x is computer dot y. Dialogue: 0,0:31:38.84,0:31:45.95,EN,,0,0,0,,And the supervisor of x is z. Dialogue: 0,0:31:46.83,0:31:49.53,EN,,0,0,0,,And I typed that in like a query. Dialogue: 0,0:31:51.07,0:31:52.97,EN,,0,0,0,,And what it types back, Dialogue: 0,0:31:54.00,0:31:58.73,EN,,0,0,0,,what you see are the queries I typed in instantiated by all possible answers. Dialogue: 0,0:31:58.93,0:32:00.08,EN,,0,0,0,,And then you see there are a lot of answers. Dialogue: 0,0:32:01.69,0:32:02.14,EN,,0,0,0,,All right. Dialogue: 0,0:32:02.19,0:32:04.04,EN,,0,0,0,,So the means of combination in this language-- Dialogue: 0,0:32:05.21,0:32:06.60,EN,,0,0,0,,and this is why it's called a logic language-- Dialogue: 0,0:32:06.64,0:32:09.47,EN,,0,0,0,,are logical operations. Dialogue: 0,0:32:09.80,0:32:15.68,EN,,0,0,0,,Means of combinations are things like AND and NOT Dialogue: 0,0:32:15.96,0:32:17.92,EN,,0,0,0,,and there's one I didn't show you, which is OR. Dialogue: 0,0:32:18.49,0:32:20.36,EN,,0,0,0,,And then I showed you LISP value, Dialogue: 0,0:32:20.72,0:32:24.48,EN,,0,0,0,,which is a, not logic, of course, Dialogue: 0,0:32:24.51,0:32:26.89,EN,,0,0,0,,but is a little special hack to interface that to LISP Dialogue: 0,0:32:27.34,0:32:28.75,EN,,0,0,0,,so you can get more power. Dialogue: 0,0:32:29.25,0:32:30.67,EN,,0,0,0,,Those are the means of combination. Dialogue: 0,0:32:32.59,0:32:33.98,EN,,0,0,0,,OK, the means of abstraction. Dialogue: 0,0:32:34.16,0:32:35.21,EN,,0,0,0,,What we'd like to do-- Dialogue: 0,0:32:38.27,0:32:41.24,EN,,0,0,0,,let's go back for second and look at that last slide. Dialogue: 0,0:32:42.26,0:32:44.25,EN,,0,0,0,,We might like to take very complicated thing, Dialogue: 0,0:32:44.46,0:32:48.00,EN,,0,0,0,,the idea that someone works in a division Dialogue: 0,0:32:48.01,0:32:50.09,EN,,0,0,0,,but does not have a supervisor in the division. Dialogue: 0,0:32:52.40,0:32:55.10,EN,,0,0,0,,And as before, name that. Dialogue: 0,0:32:56.09,0:32:58.12,EN,,0,0,0,,Well, if someone works in a division Dialogue: 0,0:32:58.17,0:33:00.25,EN,,0,0,0,,and does not have a supervisor who works in that division, Dialogue: 0,0:33:00.48,0:33:01.93,EN,,0,0,0,,that means that person is a big shot. Dialogue: 0,0:33:02.75,0:33:05.13,EN,,0,0,0,,So let's make a rule that Dialogue: 0,0:33:06.43,0:33:09.16,EN,,0,0,0,,somebody x is a big shot in some department Dialogue: 0,0:33:10.91,0:33:14.68,EN,,0,0,0,,if x works in the department Dialogue: 0,0:33:16.04,0:33:20.08,EN,,0,0,0,,and it's not the case that x has a supervisor who works in the department. Dialogue: 0,0:33:21.51,0:33:22.94,EN,,0,0,0,,So this is our means of abstraction. Dialogue: 0,0:33:22.94,0:33:23.90,EN,,0,0,0,,This is a rule. Dialogue: 0,0:33:26.22,0:33:27.58,EN,,0,0,0,,And a rule has three parts. Dialogue: 0,0:33:31.00,0:33:32.48,EN,,0,0,0,,The thing that says it's a rule. Dialogue: 0,0:33:33.40,0:33:35.48,EN,,0,0,0,,And then there's the conclusion of the rule. Dialogue: 0,0:33:37.53,0:33:39.07,EN,,0,0,0,,And then there's the body of the rule. Dialogue: 0,0:33:40.00,0:33:41.88,EN,,0,0,0,,And you can read this as a piece of logic which says, Dialogue: 0,0:33:41.92,0:33:45.15,EN,,0,0,0,,if you know that the body of the rule is true, Dialogue: 0,0:33:46.40,0:33:48.72,EN,,0,0,0,,then you can conclude that the conclusion is true. Dialogue: 0,0:33:49.45,0:33:53.28,EN,,0,0,0,,Or in order to deduce that x is a big shot in some department, Dialogue: 0,0:33:53.79,0:33:55.71,EN,,0,0,0,,it's enough to verify that. Dialogue: 0,0:33:57.48,0:33:58.82,EN,,0,0,0,,So that's what rules look like. Dialogue: 0,0:34:03.28,0:34:06.16,EN,,0,0,0,,Let's go back and look at that merge example Dialogue: 0,0:34:06.73,0:34:07.92,EN,,0,0,0,,that I did before the break. Dialogue: 0,0:34:08.11,0:34:10.68,EN,,0,0,0,,Let's look at how that would look in terms of rules. Dialogue: 0,0:34:11.44,0:34:12.84,EN,,0,0,0,,I'm going to take the logic I put up Dialogue: 0,0:34:13.08,0:34:15.50,EN,,0,0,0,,and just change it into a bunch of rules in this format. Dialogue: 0,0:34:18.73,0:34:19.35,EN,,0,0,0,,We have a rule. Dialogue: 0,0:34:19.35,0:34:20.96,EN,,0,0,0,,Remember, there was this thing merge-to-form. Dialogue: 0,0:34:21.71,0:34:22.97,EN,,0,0,0,,There is a rule that says, Dialogue: 0,0:34:26.28,0:34:29.62,EN,,0,0,0,,the empty list and y merge to form y. Dialogue: 0,0:34:29.62,0:34:30.87,EN,,0,0,0,,This is the rule conclusion. Dialogue: 0,0:34:33.21,0:34:35.74,EN,,0,0,0,,And notice this particular rule has no body. Dialogue: 0,0:34:36.65,0:34:37.66,EN,,0,0,0,,And in this language, Dialogue: 0,0:34:38.11,0:34:40.86,EN,,0,0,0,,a rule with no body is something that is always true. Dialogue: 0,0:34:41.23,0:34:42.51,EN,,0,0,0,,You can always assume that's true. Dialogue: 0,0:34:45.19,0:34:46.49,EN,,0,0,0,,And there was another piece of logic Dialogue: 0,0:34:46.64,0:34:49.46,EN,,0,0,0,,that said anything in the empty list merged to form the anything. Dialogue: 0,0:34:49.46,0:34:50.12,EN,,0,0,0,,That's this. Dialogue: 0,0:34:50.90,0:34:53.55,EN,,0,0,0,,A rule y and the empty list merge to form y. Dialogue: 0,0:34:55.51,0:34:58.40,EN,,0,0,0,,Those corresponded to the two end cases in our merge procedure, Dialogue: 0,0:34:58.44,0:34:59.77,EN,,0,0,0,,but now we're talking about logic, Dialogue: 0,0:35:00.41,0:35:01.45,EN,,0,0,0,,not about procedures. Dialogue: 0,0:35:03.49,0:35:04.48,EN,,0,0,0,,Then we had another rule, Dialogue: 0,0:35:04.83,0:35:08.73,EN,,0,0,0,,which said if you know how shorter things merge, Dialogue: 0,0:35:08.91,0:35:09.83,EN,,0,0,0,,you can put them together. Dialogue: 0,0:35:09.83,0:35:14.16,EN,,0,0,0,,So this says, if you have a list x and y and z, Dialogue: 0,0:35:14.92,0:35:17.61,EN,,0,0,0,,and if you want to deduce that a dot x-- Dialogue: 0,0:35:17.63,0:35:19.08,EN,,0,0,0,,this means cons a onto x, Dialogue: 0,0:35:19.48,0:35:22.36,EN,,0,0,0,,or a list whose first thing is a and whose rest is x-- Dialogue: 0,0:35:23.16,0:35:27.40,EN,,0,0,0,,so if you want to deduce that a dot x and b dot y merge to form b dot z-- Dialogue: 0,0:35:30.36,0:35:33.90,EN,,0,0,0,,that would say you merge these two lists a x and b y Dialogue: 0,0:35:33.92,0:35:35.85,EN,,0,0,0,,and you're going to get something that starts with b-- Dialogue: 0,0:35:36.76,0:35:40.67,EN,,0,0,0,,you can deduce that if you know that it's the case Dialogue: 0,0:35:40.91,0:35:44.48,EN,,0,0,0,,both that a dot x and y merge to form z Dialogue: 0,0:35:45.18,0:35:47.24,EN,,0,0,0,,and a is larger than b. Dialogue: 0,0:35:48.69,0:35:50.59,EN,,0,0,0,,So when I merge them, b will come first in the list. Dialogue: 0,0:35:51.82,0:35:54.91,EN,,0,0,0,,That's a little translation of the logic rule Dialogue: 0,0:35:55.24,0:35:57.18,EN,,0,0,0,,that I wrote in pseudo-English before. Dialogue: 0,0:35:57.96,0:36:01.63,EN,,0,0,0,,And then just for completeness, here's the other case. Dialogue: 0,0:36:02.88,0:36:05.95,EN,,0,0,0,,a dot x and b dot y merge to form a dot z Dialogue: 0,0:36:06.08,0:36:09.16,EN,,0,0,0,,if x and b dot y merged to form z and b is larger than a. Dialogue: 0,0:36:09.47,0:36:11.00,EN,,0,0,0,,and b is larger than a. Dialogue: 0,0:36:12.19,0:36:15.98,EN,,0,0,0,,So that's a little program that I've typed in in this language, Dialogue: 0,0:36:16.01,0:36:17.07,EN,,0,0,0,,and now let's look at it run. Dialogue: 0,0:36:21.90,0:36:23.90,EN,,0,0,0,,So I typed in the merge rules before, Dialogue: 0,0:36:24.62,0:36:25.77,EN,,0,0,0,,and I could say, ahh Dialogue: 0,0:36:27.04,0:36:28.51,EN,,0,0,0,,I could use this like a procedure. Dialogue: 0,0:36:28.51,0:36:38.24,EN,,0,0,0,,I could say merge to form 1 and 3 and 2 and 7. Dialogue: 0,0:36:39.42,0:36:41.55,EN,,0,0,0,,So here I'm using it like the LISP procedure. Dialogue: 0,0:36:43.16,0:36:44.97,EN,,0,0,0,,Now it's going to think about that for a while Dialogue: 0,0:36:46.43,0:36:47.56,EN,,0,0,0,,and apply these rules. Dialogue: 0,0:36:50.78,0:36:51.92,EN,,0,0,0,,So it found an answer. Dialogue: 0,0:36:52.80,0:36:54.54,EN,,0,0,0,,Now it's going to see if there are any other answers Dialogue: 0,0:36:55.07,0:36:57.32,EN,,0,0,0,,it doesn't know a priori there's only one answer. Dialogue: 0,0:36:57.81,0:36:59.90,EN,,0,0,0,,So it's sitting here checking all possibilities, Dialogue: 0,0:37:00.41,0:37:02.54,EN,,0,0,0,,and it says, no more. Done. Dialogue: 0,0:37:03.16,0:37:05.07,EN,,0,0,0,,So there I've used those rules like a procedure. Dialogue: 0,0:37:05.21,0:37:09.05,EN,,0,0,0,,Or remember the whole point is that I can ask different kinds of questions. Dialogue: 0,0:37:10.22,0:37:11.07,EN,,0,0,0,,I could say Dialogue: 0,0:37:18.56,0:37:24.59,EN,,0,0,0,,merge to form, let's see, how about 2 and a. Dialogue: 0,0:37:24.59,0:37:27.90,EN,,0,0,0,,Some list of two elements which I know starts with 2, Dialogue: 0,0:37:29.37,0:37:31.26,EN,,0,0,0,,and the other thing I don't know, Dialogue: 0,0:37:33.05,0:37:35.04,EN,,0,0,0,,and x and some other list Dialogue: 0,0:37:36.48,0:37:39.51,EN,,0,0,0,,merge to form a 1, 2, 3 and 4. Dialogue: 0,0:37:42.76,0:37:44.11,EN,,0,0,0,,So now it's going to think about that. Dialogue: 0,0:37:44.59,0:37:49.40,EN,,0,0,0,,It's got to find-- so it found one possibility. Dialogue: 0,0:37:49.52,0:37:52.46,EN,,0,0,0,,It said a could be 3, and x could be the list 1, 4. Dialogue: 0,0:37:53.72,0:37:55.16,EN,,0,0,0,,And now, again, it's got to check Dialogue: 0,0:37:56.56,0:37:57.71,EN,,0,0,0,,because it doesn't a priori know Dialogue: 0,0:37:57.74,0:38:00.30,EN,,0,0,0,,that there aren't any other possibilities going on. Dialogue: 0,0:38:03.68,0:38:06.57,EN,,0,0,0,,Or like I said, Dialogue: 0,0:38:07.00,0:38:09.84,EN,,0,0,0,,I could say something like merge to form, Dialogue: 0,0:38:10.54,0:38:17.55,EN,,0,0,0,,like, what and what else merge to form 1, 2, 3, 4, 5? Dialogue: 0,0:38:23.68,0:38:25.53,EN,,0,0,0,,Now it's going to think about that. Dialogue: 0,0:38:28.49,0:38:30.31,EN,,0,0,0,,And there are a lot of answers that it might get. Dialogue: 0,0:38:35.18,0:38:38.57,EN,,0,0,0,,And what you see is here you're really paying the price of slowness. Dialogue: 0,0:38:42.21,0:38:43.88,EN,,0,0,0,,And kind of for three reasons. Dialogue: 0,0:38:43.88,0:38:46.22,EN,,0,0,0,,One is that this language is doubly interpreted. Dialogue: 0,0:38:47.63,0:38:49.72,EN,,0,0,0,,Whereas in a real implementation, Dialogue: 0,0:38:49.76,0:38:52.04,EN,,0,0,0,,you would go compile this down to primitive operations. Dialogue: 0,0:38:52.19,0:38:53.87,EN,,0,0,0,,The other reason is that Dialogue: 0,0:38:53.88,0:38:58.11,EN,,0,0,0,,this particular algorithm for merges is doubly recursive. Dialogue: 0,0:38:58.38,0:39:00.06,EN,,0,0,0,,So it's going to take a very long time. Dialogue: 0,0:39:01.02,0:39:04.33,EN,,0,0,0,,And eventually, this is going to go through Dialogue: 0,0:39:04.59,0:39:07.13,EN,,0,0,0,,and find-- find what? Dialogue: 0,0:39:07.13,0:39:08.73,EN,,0,0,0,,Two to the fifth possible answers. Dialogue: 0,0:39:12.14,0:39:14.96,EN,,0,0,0,,And you see they come out in some fairly arbitrary order, Dialogue: 0,0:39:15.00,0:39:18.14,EN,,0,0,0,,depending on which order it's going to be trying these rules. Dialogue: 0,0:39:20.16,0:39:22.11,EN,,0,0,0,,In fact, what we're going to do when they edit the videotape Dialogue: 0,0:39:22.40,0:39:23.48,EN,,0,0,0,,is speed all this up. Dialogue: 0,0:39:24.08,0:39:26.60,EN,,0,0,0,,Don't you like taking out these waits? Dialogue: 0,0:39:26.60,0:39:28.27,EN,,0,0,0,,And don't you wish you could do that in your demos? Dialogue: 0,0:39:29.48,0:39:34.24,EN,,0,0,0,,Anyway, it's still grinding there. Dialogue: 0,0:39:39.22,0:39:41.12,EN,,0,0,0,,Anyway, there are 32 possibilities-- Dialogue: 0,0:39:41.13,0:39:42.63,EN,,0,0,0,,we won't wait for it to print out all of them. Dialogue: 0,0:39:47.85,0:39:50.44,EN,,0,0,0,,OK, so the needs of abstraction in this language are rules. Dialogue: 0,0:39:53.53,0:39:58.01,EN,,0,0,0,,So we take some bunch of things that are put together with logic Dialogue: 0,0:39:59.12,0:40:00.08,EN,,0,0,0,,and we name them. Dialogue: 0,0:40:00.35,0:40:03.41,EN,,0,0,0,,And you can think of that as naming a particular pattern of logic. Dialogue: 0,0:40:03.41,0:40:04.54,EN,,0,0,0,,Or you can think of that as saying, Dialogue: 0,0:40:04.56,0:40:06.75,EN,,0,0,0,,if you want to deduce some conclusion, Dialogue: 0,0:40:07.90,0:40:09.52,EN,,0,0,0,,you can apply those rules of logic. Dialogue: 0,0:40:10.66,0:40:13.20,EN,,0,0,0,,And those are three elements of this language. Dialogue: 0,0:40:13.42,0:40:14.56,EN,,0,0,0,,Let's break now, Dialogue: 0,0:40:14.60,0:40:16.59,EN,,0,0,0,,and then we'll talk about how it's actually implemented. Dialogue: 0,0:40:23.61,0:40:28.84,EN,,0,0,0,,AUDIENCE: Does using LISP value primitive or whatever interfere with your means Dialogue: 0,0:40:29.15,0:40:30.64,EN,,0,0,0,,both directions on a query? Dialogue: 0,0:40:31.77,0:40:34.48,EN,,0,0,0,,PROFESSOR: OK, that's a-- the question is, Dialogue: 0,0:40:35.08,0:40:36.92,EN,,0,0,0,,does using LISP value interfere Dialogue: 0,0:40:37.53,0:40:40.09,EN,,0,0,0,,with the ability to go both directions on the query? Dialogue: 0,0:40:40.09,0:40:42.81,EN,,0,0,0,,We haven't really talked about the implementation yet, Dialogue: 0,0:40:43.68,0:40:45.52,EN,,0,0,0,,but the answer is, yes, it can. Dialogue: 0,0:40:46.89,0:40:50.20,EN,,0,0,0,,In general, as we'll see at the end-- Dialogue: 0,0:40:50.22,0:40:52.17,EN,,0,0,0,,although I really won't to go into details-- Dialogue: 0,0:40:53.21,0:40:59.36,EN,,0,0,0,,it's fairly complicated, especially when you use either not or LISP value-- Dialogue: 0,0:40:59.55,0:41:02.89,EN,,0,0,0,,or actually, if you use anything besides only and, Dialogue: 0,0:41:04.12,0:41:08.19,EN,,0,0,0,,it becomes very complicated to say when these things will work. Dialogue: 0,0:41:08.20,0:41:10.36,EN,,0,0,0,,They won't work quite in all situations. Dialogue: 0,0:41:10.36,0:41:13.39,EN,,0,0,0,,I'll talk about that at the end of the second half today. Dialogue: 0,0:41:14.30,0:41:15.84,EN,,0,0,0,,But the answer to your question is, yes, Dialogue: 0,0:41:16.19,0:41:19.21,EN,,0,0,0,,by dragging in a lot more power from LISP value, Dialogue: 0,0:41:19.40,0:41:23.77,EN,,0,0,0,,you lose some of the principal power of logic programming. Dialogue: 0,0:41:24.17,0:41:25.56,EN,,0,0,0,,That's a trade-off that you have to make. Dialogue: 0,0:41:28.48,0:41:29.39,EN,,0,0,0,,OK, let's take a break. ================================================ FILE: Ass/lec8b.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:18.91,0:00:21.79,EN,,0,0,0,,PROFESSOR: All right, well, we've seen how the query language works. Dialogue: 0,0:00:22.64,0:00:25.07,EN,,0,0,0,,Now, let's talk about how it's implemented. Dialogue: 0,0:00:26.28,0:00:27.98,EN,,0,0,0,,You already pretty much can guess Dialogue: 0,0:00:28.59,0:00:29.47,EN,,0,0,0,,what's going on there. Dialogue: 0,0:00:29.47,0:00:31.64,EN,,0,0,0,,At the bottom of it, there's a pattern matcher. Dialogue: 0,0:00:32.81,0:00:34.25,EN,,0,0,0,,And we looked at a pattern matcher Dialogue: 0,0:00:34.67,0:00:36.94,EN,,0,0,0,,when we did the rule-based control language. Dialogue: 0,0:00:38.11,0:00:40.59,EN,,0,0,0,,Just to remind you, here are some sample patterns. Dialogue: 0,0:00:41.52,0:00:43.68,EN,,0,0,0,,This is a pattern that will match Dialogue: 0,0:00:43.80,0:00:44.92,EN,,0,0,0,,any list of three things Dialogue: 0,0:00:44.96,0:00:47.10,EN,,0,0,0,,which the first is a Dialogue: 0,0:00:47.16,0:00:48.33,EN,,0,0,0,,the second is c Dialogue: 0,0:00:48.48,0:00:50.19,EN,,0,0,0,,and the middle one can be anything. Dialogue: 0,0:00:50.65,0:00:52.27,EN,,0,0,0,,So in this little pattern-matching syntax, Dialogue: 0,0:00:52.30,0:00:54.05,EN,,0,0,0,,there's only one distinction you make. Dialogue: 0,0:00:54.05,0:00:57.20,EN,,0,0,0,,There's either literal things or variables, Dialogue: 0,0:00:57.23,0:00:58.86,EN,,0,0,0,,and variables begin with question mark. Dialogue: 0,0:01:01.37,0:01:03.64,EN,,0,0,0,,So this matches any list of three things Dialogue: 0,0:01:04.44,0:01:06.50,EN,,0,0,0,,of which the first is a and the second is c. Dialogue: 0,0:01:06.50,0:01:09.00,EN,,0,0,0,,This one matches any list of three things Dialogue: 0,0:01:10.43,0:01:12.53,EN,,0,0,0,,of which the first is the symbol job. Dialogue: 0,0:01:12.53,0:01:13.90,EN,,0,0,0,,The second can be anything. Dialogue: 0,0:01:14.21,0:01:15.90,EN,,0,0,0,,And the third is a list of two things Dialogue: 0,0:01:15.95,0:01:17.72,EN,,0,0,0,,of which the first is the symbol computer Dialogue: 0,0:01:17.88,0:01:19.42,EN,,0,0,0,,and the second can be anything. Dialogue: 0,0:01:20.48,0:01:25.55,EN,,0,0,0,,And this one, this next one matches any list of three things, Dialogue: 0,0:01:25.87,0:01:26.99,EN,,0,0,0,,and the only difference is, Dialogue: 0,0:01:28.40,0:01:31.32,EN,,0,0,0,,here, the third list, the first is the symbol computer, Dialogue: 0,0:01:31.76,0:01:33.29,EN,,0,0,0,,and then there's some rest of the list. Dialogue: 0,0:01:35.04,0:01:37.53,EN,,0,0,0,,So this means two elements and this means arbitrary number. Dialogue: 0,0:01:37.86,0:01:39.74,EN,,0,0,0,,And our language implementation isn't Dialogue: 0,0:01:39.85,0:01:42.06,EN,,0,0,0,,isn't even going to have to worry about implementing this dot Dialogue: 0,0:01:42.11,0:01:44.17,EN,,0,0,0,,because that's automatically done by Lisp's reader. Dialogue: 0,0:01:48.34,0:01:50.31,EN,,0,0,0,,Remember matchers also have some consistency in them. Dialogue: 0,0:01:50.31,0:01:52.32,EN,,0,0,0,,This match is a list of three things Dialogue: 0,0:01:52.59,0:01:53.98,EN,,0,0,0,,of which the first is a. Dialogue: 0,0:01:54.43,0:01:55.79,EN,,0,0,0,,And the second and third can be anything, Dialogue: 0,0:01:55.80,0:01:57.08,EN,,0,0,0,,but they have to be the same thing. Dialogue: 0,0:01:57.94,0:01:58.84,EN,,0,0,0,,They're both called x. Dialogue: 0,0:01:59.60,0:02:01.55,EN,,0,0,0,,And this matches a list of four things Dialogue: 0,0:02:01.96,0:02:03.26,EN,,0,0,0,,of which the first is the fourth Dialogue: 0,0:02:03.66,0:02:05.15,EN,,0,0,0,,and the second is the same as the third. Dialogue: 0,0:02:05.59,0:02:08.60,EN,,0,0,0,,And this last one matches any list that begins with a. Dialogue: 0,0:02:09.68,0:02:11.05,EN,,0,0,0,,The first thing is a, Dialogue: 0,0:02:11.23,0:02:12.56,EN,,0,0,0,,and the rest can be anything. Dialogue: 0,0:02:14.04,0:02:16.60,EN,,0,0,0,,So that's just a review of pattern matcher syntax Dialogue: 0,0:02:16.62,0:02:17.87,EN,,0,0,0,,that you've already seen. Dialogue: 0,0:02:18.78,0:02:19.64,EN,,0,0,0,,And remember, Dialogue: 0,0:02:19.79,0:02:22.28,EN,,0,0,0,,that's implemented by some procedure called match. Dialogue: 0,0:02:24.87,0:02:36.06,EN,,0,0,0,,And match takes a pattern and some data and a dictionary. Dialogue: 0,0:02:43.20,0:02:47.12,EN,,0,0,0,,And match asks the question Dialogue: 0,0:02:47.79,0:02:52.64,EN,,0,0,0,,is there any way to match this pattern against this data object Dialogue: 0,0:02:53.55,0:02:56.73,EN,,0,0,0,,subject to the bindings that are already in this dictionary? Dialogue: 0,0:02:58.16,0:02:59.21,EN,,0,0,0,,So, for instance, Dialogue: 0,0:02:59.56,0:03:06.43,EN,,0,0,0,,if we're going to match the pattern x, y, y, x Dialogue: 0,0:03:07.71,0:03:13.84,EN,,0,0,0,,against the data a, b, b, a Dialogue: 0,0:03:15.12,0:03:20.52,EN,,0,0,0,,subject to a dictionary, that says x equals a. Dialogue: 0,0:03:22.01,0:03:25.23,EN,,0,0,0,,Then the matcher would say, yes, that's consistent. Dialogue: 0,0:03:25.26,0:03:27.16,EN,,0,0,0,,These match, and it's consistent Dialogue: 0,0:03:27.80,0:03:30.20,EN,,0,0,0,,with what's in the dictionary to say that x equals a. Dialogue: 0,0:03:30.32,0:03:31.60,EN,,0,0,0,,And the result of the match Dialogue: 0,0:03:32.25,0:03:34.30,EN,,0,0,0,,is the extended dictionary Dialogue: 0,0:03:34.46,0:03:37.60,EN,,0,0,0,,that says x equals a and y equals b. Dialogue: 0,0:03:39.49,0:03:42.24,EN,,0,0,0,,So a matcher takes in pattern data dictionary, Dialogue: 0,0:03:42.38,0:03:44.54,EN,,0,0,0,,puts out an extended dictionary if it matches, Dialogue: 0,0:03:44.97,0:03:46.84,EN,,0,0,0,,or if it doesn't match, says that it fails. Dialogue: 0,0:03:46.84,0:03:47.71,EN,,0,0,0,,So, for example, Dialogue: 0,0:03:47.88,0:03:50.38,EN,,0,0,0,,if I use the same pattern here, Dialogue: 0,0:03:50.97,0:03:55.12,EN,,0,0,0,,if I say this x, y, y, x Dialogue: 0,0:03:55.66,0:03:58.49,EN,,0,0,0,,match a, b, b, a Dialogue: 0,0:03:59.47,0:04:02.84,EN,,0,0,0,,with the dictionary y equals a, Dialogue: 0,0:04:05.15,0:04:06.81,EN,,0,0,0,,then the matcher would put out fail. Dialogue: 0,0:04:12.52,0:04:14.65,EN,,0,0,0,,Well, you've already seen the code for a pattern matcher Dialogue: 0,0:04:15.00,0:04:16.17,EN,,0,0,0,,so I'm not going to go over it, Dialogue: 0,0:04:16.64,0:04:19.77,EN,,0,0,0,,but it's the same thing we've been doing before. Dialogue: 0,0:04:21.19,0:04:23.22,EN,,0,0,0,,You saw that in the system on rule-based control. Dialogue: 0,0:04:23.22,0:04:24.56,EN,,0,0,0,,It's essentially the same matcher. Dialogue: 0,0:04:24.95,0:04:27.66,EN,,0,0,0,,In fact, I think the syntax is a little bit simpler Dialogue: 0,0:04:28.16,0:04:29.31,EN,,0,0,0,,because we're not worrying about Dialogue: 0,0:04:29.40,0:04:31.40,EN,,0,0,0,,arbitrary constants and expressions and things. Dialogue: 0,0:04:31.40,0:04:32.88,EN,,0,0,0,,There's just variables and constants. Dialogue: 0,0:04:35.79,0:04:37.32,EN,,0,0,0,,OK, well, given that, Dialogue: 0,0:04:38.46,0:04:39.61,EN,,0,0,0,,what's a primitive query? Dialogue: 0,0:04:42.97,0:04:45.34,EN,,0,0,0,,Primitive query is going to be a rather complicated thing. Dialogue: 0,0:04:46.67,0:05:03.58,EN,,0,0,0,,It's going to be-- let's think about the query job of x is d dot y. Dialogue: 0,0:05:07.04,0:05:08.73,EN,,0,0,0,,That's a query we might type in. Dialogue: 0,0:05:09.40,0:05:11.39,EN,,0,0,0,,That's going to be implemented in the system. Dialogue: 0,0:05:14.14,0:05:15.66,EN,,0,0,0,,We'll think of it as this little box. Dialogue: 0,0:05:15.70,0:05:16.80,EN,,0,0,0,,Here's the primitive query. Dialogue: 0,0:05:18.88,0:05:20.30,EN,,0,0,0,,What this little box is going to do Dialogue: 0,0:05:22.24,0:05:27.28,EN,,0,0,0,,is take in two streams and put out a stream. Dialogue: 0,0:05:31.96,0:05:33.20,EN,,0,0,0,,and put out a stream. Dialogue: 0,0:05:34.03,0:05:36.19,EN,,0,0,0,,So the shape of a primitive query Dialogue: 0,0:05:36.51,0:05:38.46,EN,,0,0,0,,is that it's a thing where two streams come in Dialogue: 0,0:05:38.67,0:05:39.96,EN,,0,0,0,,and one stream goes out. Dialogue: 0,0:05:41.12,0:05:46.20,EN,,0,0,0,,What these streams are going to be is down here is the database. Dialogue: 0,0:05:51.95,0:05:53.93,EN,,0,0,0,,So we imagine all the things in the database Dialogue: 0,0:05:55.93,0:05:57.20,EN,,0,0,0,,sort of sitting there in a stream Dialogue: 0,0:05:57.31,0:05:58.40,EN,,0,0,0,,and this thing sucks on them. Dialogue: 0,0:06:00.36,0:06:02.43,EN,,0,0,0,,So what are some things that might be in the database? Dialogue: 0,0:06:08.43,0:06:20.32,EN,,0,0,0,,Oh, job of Alyssa is something Dialogue: 0,0:06:21.96,0:06:23.71,EN,,0,0,0,,and some other job is something. Dialogue: 0,0:06:25.77,0:06:30.41,EN,,0,0,0,,So imagine all of the facts in the database sitting there in the stream. Dialogue: 0,0:06:32.04,0:06:33.10,EN,,0,0,0,,That's what comes in here. Dialogue: 0,0:06:33.36,0:06:34.52,EN,,0,0,0,,What comes in here Dialogue: 0,0:06:34.89,0:06:36.52,EN,,0,0,0,,is a stream of dictionaries. Dialogue: 0,0:06:38.51,0:06:41.40,EN,,0,0,0,,So one particular dictionary might say Dialogue: 0,0:06:46.70,0:06:49.31,EN,,0,0,0,,might say y equals programmer. Dialogue: 0,0:06:55.47,0:06:56.64,EN,,0,0,0,,Now, what the query does Dialogue: 0,0:06:57.07,0:06:59.80,EN,,0,0,0,,when it gets in a dictionary from this stream, Dialogue: 0,0:07:02.01,0:07:06.67,EN,,0,0,0,,it finds all possible ways of matching the query Dialogue: 0,0:07:07.45,0:07:10.24,EN,,0,0,0,,against whatever is coming in from the database. Dialogue: 0,0:07:11.39,0:07:12.89,EN,,0,0,0,,It looks at the query as a pattern, Dialogue: 0,0:07:13.15,0:07:16.72,EN,,0,0,0,,matches it against any fact from the database Dialogue: 0,0:07:16.96,0:07:21.98,EN,,0,0,0,,or all possible ways of finding and matching the database Dialogue: 0,0:07:22.94,0:07:25.68,EN,,0,0,0,,with respect to this dictionary that's coming in. Dialogue: 0,0:07:27.55,0:07:29.69,EN,,0,0,0,,So for each fact in the database, Dialogue: 0,0:07:29.72,0:07:34.35,EN,,0,0,0,,it calls the matcher using the pattern, fact, and dictionary. Dialogue: 0,0:07:35.11,0:07:37.68,EN,,0,0,0,,And every time it gets a good match, Dialogue: 0,0:07:38.19,0:07:39.93,EN,,0,0,0,,it puts out the extended dictionary. Dialogue: 0,0:07:40.67,0:07:42.32,EN,,0,0,0,,So, for example, if this one comes in Dialogue: 0,0:07:43.00,0:07:44.09,EN,,0,0,0,,and it finds a match, Dialogue: 0,0:07:44.51,0:07:45.87,EN,,0,0,0,,out will come a dictionary Dialogue: 0,0:07:46.81,0:07:49.79,EN,,0,0,0,,that in this case will have y equals programmer Dialogue: 0,0:07:51.52,0:07:52.97,EN,,0,0,0,,nd x equals something. Dialogue: 0,0:07:56.54,0:07:58.75,EN,,0,0,0,,y is programmer, x is something, Dialogue: 0,0:07:58.96,0:08:00.54,EN,,0,0,0,,and d is whatever it found. Dialogue: 0,0:08:01.72,0:08:02.27,EN,,0,0,0,,And that's all. Dialogue: 0,0:08:03.52,0:08:07.82,EN,,0,0,0,,And, of course, it's going to try this for every fact in the dictionary. Dialogue: 0,0:08:07.98,0:08:09.25,EN,,0,0,0,,So it might find lots of them. Dialogue: 0,0:08:09.56,0:08:10.59,EN,,0,0,0,,It might find another one Dialogue: 0,0:08:11.28,0:08:17.12,EN,,0,0,0,,that says y equals programmer and x equals, and d equals. Dialogue: 0,0:08:19.18,0:08:21.55,EN,,0,0,0,,So thats, So for one frame coming in, Dialogue: 0,0:08:21.76,0:08:23.69,EN,,0,0,0,,it might put out-- for one dictionary coming in, Dialogue: 0,0:08:23.72,0:08:25.24,EN,,0,0,0,,it might put out a lot of dictionaries, Dialogue: 0,0:08:26.54,0:08:28.67,EN,,0,0,0,,or it might put out none. Dialogue: 0,0:08:30.47,0:08:38.48,EN,,0,0,0,,It might have something that wouldn't match like x equals FOO. Dialogue: 0,0:08:39.02,0:08:40.89,EN,,0,0,0,,This one might not match anything Dialogue: 0,0:08:41.52,0:08:45.12,EN,,0,0,0,,in which case nothing will go into this stream corresponding to this frame. Dialogue: 0,0:08:47.51,0:08:51.28,EN,,0,0,0,,Or what you might do is put in an empty frame, Dialogue: 0,0:08:52.91,0:08:56.24,EN,,0,0,0,,and an empty frame says try matching all ways-- Dialogue: 0,0:08:59.87,0:09:02.33,EN,,0,0,0,,find all possible ways of matching the query Dialogue: 0,0:09:02.57,0:09:06.14,EN,,0,0,0,,against something in the database subject to no previous restrictions. Dialogue: 0,0:09:07.57,0:09:09.16,EN,,0,0,0,,And if you think about what that means, that's just Dialogue: 0,0:09:10.32,0:09:13.87,EN,,0,0,0,,the computation that's done when you type in a query right off. Dialogue: 0,0:09:14.20,0:09:15.56,EN,,0,0,0,,It tries to find all matches. Dialogue: 0,0:09:16.65,0:09:18.83,EN,,0,0,0,,So a primitive query sets up this mechanism. Dialogue: 0,0:09:19.37,0:09:20.57,EN,,0,0,0,,And what the language does, Dialogue: 0,0:09:22.75,0:09:24.67,EN,,0,0,0,,when you type in the query at the top level, Dialogue: 0,0:09:24.84,0:09:26.14,EN,,0,0,0,,it takes this mechanism, Dialogue: 0,0:09:26.16,0:09:28.35,EN,,0,0,0,,feeds in one single empty dictionary, Dialogue: 0,0:09:30.86,0:09:32.56,EN,,0,0,0,,and then for each thing that comes out Dialogue: 0,0:09:33.08,0:09:35.88,EN,,0,0,0,,takes the original query Dialogue: 0,0:09:36.56,0:09:40.44,EN,,0,0,0,,and instantiates the result with all the different dictionaries, Dialogue: 0,0:09:40.81,0:09:44.36,EN,,0,0,0,,producing a new stream of instantiated patterns here. Dialogue: 0,0:09:44.99,0:09:46.51,EN,,0,0,0,,And that's what gets printed on the terminal. Dialogue: 0,0:09:48.17,0:09:51.24,EN,,0,0,0,,That's the basic mechanism going on there. Dialogue: 0,0:09:53.51,0:09:55.48,EN,,0,0,0,,Well, why is that so complicated? Dialogue: 0,0:09:57.71,0:10:01.00,EN,,0,0,0,,You probably can think of a lot simpler ways to arrange this match for Dialogue: 0,0:10:01.37,0:10:04.25,EN,,0,0,0,,a primitive query rather than having all of these streams floating around. Dialogue: 0,0:10:05.18,0:10:06.09,EN,,0,0,0,,And the answer is-- Dialogue: 0,0:10:07.15,0:10:08.51,EN,,0,0,0,,you probably guess already. Dialogue: 0,0:10:10.86,0:10:14.09,EN,,0,0,0,,The answer is this thing extends elegantly Dialogue: 0,0:10:14.56,0:10:16.76,EN,,0,0,0,,to implement the means of combination. Dialogue: 0,0:10:17.79,0:10:18.80,EN,,0,0,0,,So, for instance, Dialogue: 0,0:10:20.65,0:10:22.47,EN,,0,0,0,,suppose I don't only want to do this. Dialogue: 0,0:10:22.47,0:10:26.96,EN,,0,0,0,,I don't want to say who to be everybody's job description. Dialogue: 0,0:10:27.23,0:10:28.35,EN,,0,0,0,,Suppose I want to say Dialogue: 0,0:10:29.47,0:10:35.92,EN,,0,0,0,,to say AND the job of x is d dot y Dialogue: 0,0:10:36.80,0:10:47.04,EN,,0,0,0,,and the supervisor of x is z. Dialogue: 0,0:10:48.80,0:10:50.67,EN,,0,0,0,,Now, supervisor of x is z Dialogue: 0,0:10:51.39,0:10:52.96,EN,,0,0,0,,is going to be another primitive query Dialogue: 0,0:10:53.71,0:10:58.43,EN,,0,0,0,,that has the same shape to take in a stream of data objects, Dialogue: 0,0:10:59.18,0:11:01.64,EN,,0,0,0,,a stream of initial dictionaries, Dialogue: 0,0:11:01.68,0:11:05.52,EN,,0,0,0,,which are the restrictions to try and use when you match, Dialogue: 0,0:11:05.53,0:11:07.44,EN,,0,0,0,,and it's going to put out a stream of dictionaries. Dialogue: 0,0:11:08.70,0:11:10.80,EN,,0,0,0,,So that's what this primitive query looks like. Dialogue: 0,0:11:11.50,0:11:12.91,EN,,0,0,0,,And how do I implement the AND? Dialogue: 0,0:11:12.91,0:11:13.45,EN,,0,0,0,,Well, it's simple. Dialogue: 0,0:11:13.45,0:11:14.44,EN,,0,0,0,,I just hook them together. Dialogue: 0,0:11:14.88,0:11:16.28,EN,,0,0,0,,I take the output of this one, Dialogue: 0,0:11:16.96,0:11:18.81,EN,,0,0,0,,and I put that to the input of that one. Dialogue: 0,0:11:19.83,0:11:21.84,EN,,0,0,0,,And I take the dictionary here and I fan it out. Dialogue: 0,0:11:26.57,0:11:27.96,EN,,0,0,0,,And then you see how that's going to work, Dialogue: 0,0:11:29.05,0:11:32.44,EN,,0,0,0,,because what's going to happen is a frame will now come in here, Dialogue: 0,0:11:32.51,0:11:36.84,EN,,0,0,0,,which has a binding for x, y, and d. Dialogue: 0,0:11:37.92,0:11:39.28,EN,,0,0,0,,And then when this one gets it, it'll say, Dialogue: 0,0:11:39.29,0:11:41.60,EN,,0,0,0,,oh, gee, subject to these restrictions, Dialogue: 0,0:11:42.17,0:11:49.24,EN,,0,0,0,,which now already have values in the dictionary for y and x and d, Dialogue: 0,0:11:51.80,0:11:53.08,EN,,0,0,0,,it looks in the database and says, Dialogue: 0,0:11:53.12,0:11:54.92,EN,,0,0,0,,gee, can I find any supervisor facts? Dialogue: 0,0:11:56.04,0:11:58.51,EN,,0,0,0,,And if it finds any, out will come dictionaries Dialogue: 0,0:11:59.58,0:12:09.34,EN,,0,0,0,,which have bindings for y and x and d and z now. Dialogue: 0,0:12:12.07,0:12:14.09,EN,,0,0,0,,And then notice that the match--- Dialogue: 0,0:12:14.19,0:12:17.24,EN,,0,0,0,,because the frames coming in here have these restrictions, Dialogue: 0,0:12:17.61,0:12:20.28,EN,,0,0,0,,that's the thing that assures when you do the AND, Dialogue: 0,0:12:20.49,0:12:24.62,EN,,0,0,0,,this x will mean the same thing as that x. Dialogue: 0,0:12:26.47,0:12:28.96,EN,,0,0,0,,Because by the time something comes floating in here, Dialogue: 0,0:12:29.96,0:12:32.65,EN,,0,0,0,,x has a value that you have to match against consistently. Dialogue: 0,0:12:34.46,0:12:36.17,EN,,0,0,0,,And then you remember from the code from the matcher, Dialogue: 0,0:12:36.19,0:12:38.17,EN,,0,0,0,,there was something in the way the matcher did dictionaries Dialogue: 0,0:12:38.20,0:12:39.82,EN,,0,0,0,,that arrange consistent matches. Dialogue: 0,0:12:40.92,0:12:41.77,EN,,0,0,0,,So there's AND. Dialogue: 0,0:12:44.08,0:12:46.94,EN,,0,0,0,,The important point to notice is the general shape. Dialogue: 0,0:12:48.49,0:12:51.55,EN,,0,0,0,,Look at what happened: the AND of two queries, say, P and Q. Dialogue: 0,0:12:52.88,0:12:55.61,EN,,0,0,0,,Here's P and Q. Dialogue: 0,0:12:57.29,0:12:58.60,EN,,0,0,0,,The AND of two queries, Dialogue: 0,0:13:00.27,0:13:01.19,EN,,0,0,0,,well, it looks like this. Dialogue: 0,0:13:01.19,0:13:04.44,EN,,0,0,0,,Each query takes in a stream from the database, Dialogue: 0,0:13:04.54,0:13:05.71,EN,,0,0,0,,a stream of inputs, Dialogue: 0,0:13:06.33,0:13:08.17,EN,,0,0,0,,and puts out a stream of outputs. Dialogue: 0,0:13:10.23,0:13:11.72,EN,,0,0,0,,And the important point to notice Dialogue: 0,0:13:12.20,0:13:15.02,EN,,0,0,0,,is that if I draw a box around this thing Dialogue: 0,0:13:19.26,0:13:23.64,EN,,0,0,0,,and say this is AND of P and Q, Dialogue: 0,0:13:25.66,0:13:30.38,EN,,0,0,0,,then that box has exactly the same overall shape. Dialogue: 0,0:13:32.04,0:13:34.20,EN,,0,0,0,,It's something that takes in a stream from the database. Dialogue: 0,0:13:34.20,0:13:35.74,EN,,0,0,0,,Here it's going to get fanned out inside, Dialogue: 0,0:13:36.60,0:13:37.93,EN,,0,0,0,,but from the outside you don't see that. Dialogue: 0,0:13:38.16,0:13:40.64,EN,,0,0,0,,It takes an input stream and puts out an output stream. Dialogue: 0,0:13:42.06,0:13:43.16,EN,,0,0,0,,So this is AND. Dialogue: 0,0:13:43.57,0:13:45.72,EN,,0,0,0,,And then similarly, OR would look like this. Dialogue: 0,0:13:46.02,0:13:49.58,EN,,0,0,0,,OR would-- although I didn't show you examples of OR. Dialogue: 0,0:13:49.84,0:13:54.70,EN,,0,0,0,,OR would say can I find all ways of matching P or Q. Dialogue: 0,0:13:55.80,0:13:58.07,EN,,0,0,0,,So I have P and Q. Each will have their shape. Dialogue: 0,0:14:04.46,0:14:06.68,EN,,0,0,0,,And the way OR is implemented is Dialogue: 0,0:14:08.54,0:14:10.91,EN,,0,0,0,,I'll take my database stream. Dialogue: 0,0:14:12.50,0:14:13.49,EN,,0,0,0,,I'll fan it out. Dialogue: 0,0:14:13.49,0:14:16.04,EN,,0,0,0,,I'll put one into P and one into Q. Dialogue: 0,0:14:17.44,0:14:21.98,EN,,0,0,0,,I'll take my initial query stream coming in and fan it out. Dialogue: 0,0:14:26.75,0:14:29.16,EN,,0,0,0,,So I'll look at all the answers I might get from P Dialogue: 0,0:14:29.29,0:14:31.08,EN,,0,0,0,,and all the answers I might get from Q, Dialogue: 0,0:14:31.61,0:14:34.56,EN,,0,0,0,,and I'll put them through some sort of thing that appends them Dialogue: 0,0:14:34.62,0:14:37.48,EN,,0,0,0,,or merges the result into one stream, Dialogue: 0,0:14:39.64,0:14:40.88,EN,,0,0,0,,and that's what will come out. Dialogue: 0,0:14:41.08,0:14:48.24,EN,,0,0,0,,And this whole thing from the outside is OR. Dialogue: 0,0:14:52.35,0:14:54.89,EN,,0,0,0,,And again, you see it has the same overall shape Dialogue: 0,0:14:55.07,0:14:56.54,EN,,0,0,0,,And again, you see it has the same overall shape Dialogue: 0,0:15:01.00,0:15:01.61,EN,,0,0,0,,What's NOT? Dialogue: 0,0:15:02.02,0:15:03.45,EN,,0,0,0,,NOT works kind of the same way. Dialogue: 0,0:15:04.31,0:15:05.95,EN,,0,0,0,,If I have some query P, Dialogue: 0,0:15:06.86,0:15:13.50,EN,,0,0,0,,If I have P, I take the primitive query for P. Dialogue: 0,0:15:14.69,0:15:16.32,EN,,0,0,0,,Here, I'm going to implement NOT P. Dialogue: 0,0:15:18.68,0:15:20.54,EN,,0,0,0,,And NOT's just going to act as a filter. Dialogue: 0,0:15:20.72,0:15:21.95,EN,,0,0,0,,I'll take in the database Dialogue: 0,0:15:23.84,0:15:28.28,EN,,0,0,0,,and my original stream of dictionaries coming in, Dialogue: 0,0:15:28.78,0:15:31.53,EN,,0,0,0,,and what NOT P will do is Dialogue: 0,0:15:31.88,0:15:37.40,EN,,0,0,0,,it will filter these guys. Dialogue: 0,0:15:39.02,0:15:40.09,EN,,0,0,0,,And the way it will filter it, Dialogue: 0,0:15:40.19,0:15:42.70,EN,,0,0,0,,it will say when I get in a dictionary here, Dialogue: 0,0:15:43.42,0:15:44.65,EN,,0,0,0,,I'll find all the matches, Dialogue: 0,0:15:44.83,0:15:46.48,EN,,0,0,0,,and if I find any, I'll throw it away. Dialogue: 0,0:15:47.46,0:15:49.93,EN,,0,0,0,,And if I don't find any matches to something coming in here, Dialogue: 0,0:15:50.12,0:15:51.37,EN,,0,0,0,,I'll just pass that through, Dialogue: 0,0:15:52.40,0:15:53.55,EN,,0,0,0,,so NOT is a pure filter. Dialogue: 0,0:15:55.34,0:15:59.98,EN,,0,0,0,,So AND is-- think of these sort of electoral resistors or something. Dialogue: 0,0:15:59.98,0:16:01.85,EN,,0,0,0,,AND is series combination Dialogue: 0,0:16:02.49,0:16:04.14,EN,,0,0,0,,and OR is parallel combination. Dialogue: 0,0:16:04.96,0:16:07.46,EN,,0,0,0,,And then NOT is not going to extend any dictionaries at all. Dialogue: 0,0:16:07.46,0:16:08.40,EN,,0,0,0,,It's just going to filter it. Dialogue: 0,0:16:08.75,0:16:11.79,EN,,0,0,0,,It's going to throw away the ones for which it finds a way to match. Dialogue: 0,0:16:12.64,0:16:14.19,EN,,0,0,0,,And lisp-value is sort of the same way. Dialogue: 0,0:16:14.84,0:16:16.60,EN,,0,0,0,,The filter's a little more complicated. Dialogue: 0,0:16:16.60,0:16:17.37,EN,,0,0,0,,It applies to predicate. Dialogue: 0,0:16:19.93,0:16:21.64,EN,,0,0,0,,The major point to notice here, Dialogue: 0,0:16:21.92,0:16:23.55,EN,,0,0,0,,and it's a major point we've looked at before, Dialogue: 0,0:16:23.64,0:16:25.29,EN,,0,0,0,,is this idea of closure. Dialogue: 0,0:16:28.22,0:16:31.80,EN,,0,0,0,,The things that we build as a means of combination Dialogue: 0,0:16:31.95,0:16:34.51,EN,,0,0,0,,have the same overall structure Dialogue: 0,0:16:35.69,0:16:37.58,EN,,0,0,0,,as the primitive things that we're combining. Dialogue: 0,0:16:39.75,0:16:41.68,EN,,0,0,0,,So the AND of two things Dialogue: 0,0:16:41.71,0:16:43.72,EN,,0,0,0,,looked at from the outside has the same shape. Dialogue: 0,0:16:44.63,0:16:46.14,EN,,0,0,0,,And what that means is that Dialogue: 0,0:16:46.94,0:16:50.28,EN,,0,0,0,,this box here could be an AND or an OR or a NOT or something Dialogue: 0,0:16:50.30,0:16:54.22,EN,,0,0,0,,because it has the same shape to interface to the larger things. Dialogue: 0,0:16:54.95,0:16:56.68,EN,,0,0,0,,It's the same thing that allowed us to get Dialogue: 0,0:16:56.92,0:16:58.96,EN,,0,0,0,,complexity in the Escher picture language Dialogue: 0,0:16:59.55,0:17:01.31,EN,,0,0,0,,or allows you to immediately build up these Dialogue: 0,0:17:01.34,0:17:03.26,EN,,0,0,0,,complicated structures just out of pairs. Dialogue: 0,0:17:03.93,0:17:04.78,EN,,0,0,0,,It's closure. Dialogue: 0,0:17:06.28,0:17:08.06,EN,,0,0,0,,And that's the thing that Dialogue: 0,0:17:09.64,0:17:11.72,EN,,0,0,0,,allowed me to do what by now you took for granted Dialogue: 0,0:17:11.76,0:17:14.91,EN,,0,0,0,,I said, gee, there's a query which is AND of job and salary, Dialogue: 0,0:17:14.91,0:17:18.80,EN,,0,0,0,,and I said, oh, there's another one, which is AND of job, a NOT of something. Dialogue: 0,0:17:19.26,0:17:20.92,EN,,0,0,0,,The fact that I can do that is Dialogue: 0,0:17:20.94,0:17:22.91,EN,,0,0,0,,a direct consequence of this closure principle. Dialogue: 0,0:17:25.18,0:17:27.08,EN,,0,0,0,,OK, let's break and then we'll go on. Dialogue: 0,0:17:29.32,0:17:30.89,EN,,0,0,0,,AUDIENCE: Where does the dictionary come from? Dialogue: 0,0:17:30.99,0:17:36.03,EN,,0,0,0,,PROFESSOR: The dictionary comes initially from what you type in. Dialogue: 0,0:17:36.09,0:17:37.32,EN,,0,0,0,,So when you start this up, Dialogue: 0,0:17:39.16,0:17:41.09,EN,,0,0,0,,the first thing it does is set up this whole structure. Dialogue: 0,0:17:41.09,0:17:42.64,EN,,0,0,0,,It puts in one empty dictionary. Dialogue: 0,0:17:45.00,0:17:47.24,EN,,0,0,0,,And if all you have is one primitive query, Dialogue: 0,0:17:48.24,0:17:51.10,EN,,0,0,0,,then what will come out is a bunch of dictionaries with things filled in. Dialogue: 0,0:17:52.31,0:17:54.33,EN,,0,0,0,,The general situation that I have here Dialogue: 0,0:17:54.51,0:17:59.71,EN,,0,0,0,,is when this is in the middle of some nest of combined things. Dialogue: 0,0:18:01.55,0:18:02.30,EN,,0,0,0,,So by the time. Dialogue: 0,0:18:02.38,0:18:03.79,EN,,0,0,0,,Let's look at the picture over here. Dialogue: 0,0:18:04.38,0:18:06.73,EN,,0,0,0,,This supervisor query gets in some dictionary. Dialogue: 0,0:18:06.73,0:18:08.03,EN,,0,0,0,,Where did this one come from? Dialogue: 0,0:18:08.73,0:18:11.15,EN,,0,0,0,,This dictionary came from the fact that Dialogue: 0,0:18:12.84,0:18:14.89,EN,,0,0,0,,I'm looking at the output of this primitive query. Dialogue: 0,0:18:16.26,0:18:17.88,EN,,0,0,0,,So maybe to be very specific, Dialogue: 0,0:18:18.35,0:18:21.72,EN,,0,0,0,,if I literally typed in just this query at the top level, Dialogue: 0,0:18:22.27,0:18:22.92,EN,,0,0,0,,this AND, Dialogue: 0,0:18:23.07,0:18:25.28,EN,,0,0,0,,what would actually happen is it would build this structure Dialogue: 0,0:18:25.50,0:18:30.24,EN,,0,0,0,,and start up this whole thing with one empty dictionary. Dialogue: 0,0:18:31.77,0:18:34.33,EN,,0,0,0,,And now this one would process, and a whole bunch of dictionaries Dialogue: 0,0:18:34.36,0:18:37.36,EN,,0,0,0,,would come out with x, y's and d's in them. Dialogue: 0,0:18:38.64,0:18:39.58,EN,,0,0,0,,Run it through this one. Dialogue: 0,0:18:40.19,0:18:42.16,EN,,0,0,0,,So now that's the input to this one. Dialogue: 0,0:18:42.16,0:18:43.72,EN,,0,0,0,,This one would now put out some other stuff. Dialogue: 0,0:18:45.04,0:18:48.22,EN,,0,0,0,,And if this itself were buried in some larger thing, Dialogue: 0,0:18:49.31,0:18:51.00,EN,,0,0,0,,like an OR of something, Dialogue: 0,0:18:53.42,0:18:55.71,EN,,0,0,0,,then that would go feed into the next one. Dialogue: 0,0:18:58.56,0:19:01.28,EN,,0,0,0,,So you initially get only one empty dictionary when you start it, Dialogue: 0,0:19:01.68,0:19:04.08,EN,,0,0,0,,but as you're in the middle of processing these compounds things, Dialogue: 0,0:19:04.11,0:19:06.65,EN,,0,0,0,,that's where these cascades of dictionaries start getting generated. Dialogue: 0,0:19:07.66,0:19:12.28,EN,,0,0,0,,AUDIENCE: Dictionaries only come about as a result of using the queries? Dialogue: 0,0:19:15.12,0:19:17.69,EN,,0,0,0,,Or do they stays, do they become-- Dialogue: 0,0:19:18.84,0:19:22.81,EN,,0,0,0,,do they stay someplace in space like the database does? Dialogue: 0,0:19:23.68,0:19:24.98,EN,,0,0,0,,Are these temporary items? Dialogue: 0,0:19:24.98,0:19:27.18,EN,,0,0,0,,PROFESSOR: They're created temporarily in the matcher. Dialogue: 0,0:19:28.03,0:19:29.88,EN,,0,0,0,,Really, they're someplace in storage. Dialogue: 0,0:19:29.88,0:19:33.02,EN,,0,0,0,,Initially, someone creates a thing called the empty dictionary Dialogue: 0,0:19:34.22,0:19:36.80,EN,,0,0,0,,that gets initially fed to this match procedure, Dialogue: 0,0:19:36.81,0:19:39.05,EN,,0,0,0,,and then the match procedure builds some dictionaries, Dialogue: 0,0:19:39.07,0:19:40.27,EN,,0,0,0,,and they get passed on and on. Dialogue: 0,0:19:40.76,0:19:42.48,EN,,0,0,0,,AUDIENCE: OK, so they'll go way after the match? Dialogue: 0,0:19:43.64,0:19:46.25,EN,,0,0,0,,PROFESSOR: They'll go away when no one needs them again, yeah. Dialogue: 0,0:19:51.90,0:19:53.60,EN,,0,0,0,,AUDIENCE: It appears that the AND performs Dialogue: 0,0:19:53.63,0:19:55.37,EN,,0,0,0,,some redundant searches of the database. Dialogue: 0,0:19:55.96,0:19:57.48,EN,,0,0,0,,If the first clause matched, Dialogue: 0,0:19:57.50,0:19:59.90,EN,,0,0,0,,let's say, the third element and not on the first two elements, Dialogue: 0,0:20:00.25,0:20:03.64,EN,,0,0,0,,the second clause is going to look at those first two elements again, Dialogue: 0,0:20:04.32,0:20:06.59,EN,,0,0,0,,discarding them because they don't match. Dialogue: 0,0:20:06.64,0:20:08.72,EN,,0,0,0,,The match is already in the dictionary. Dialogue: 0,0:20:10.00,0:20:12.56,EN,,0,0,0,,Would it makes sense to carry the data element Dialogue: 0,0:20:12.57,0:20:14.43,EN,,0,0,0,,from the database along with the dictionary? Dialogue: 0,0:20:15.69,0:20:17.60,EN,,0,0,0,,PROFESSOR: Yeah, there're... Well, in general, Dialogue: 0,0:20:17.63,0:20:19.48,EN,,0,0,0,,there are other ways to arrange this search, Dialogue: 0,0:20:20.12,0:20:21.74,EN,,0,0,0,,and there's some analysis that you can do. Dialogue: 0,0:20:21.74,0:20:23.16,EN,,0,0,0,,I think there's a problem in the book, Dialogue: 0,0:20:23.87,0:20:26.65,EN,,0,0,0,,which talks about a different way that you can cascade AND Dialogue: 0,0:20:27.00,0:20:29.20,EN,,0,0,0,,to eliminate various kinds of redundancies. Dialogue: 0,0:20:29.85,0:20:30.72,EN,,0,0,0,,This one is meant to be-- Dialogue: 0,0:20:31.32,0:20:34.54,EN,,0,0,0,,was mainly meant to be very simple so you can see how they fit together. Dialogue: 0,0:20:34.70,0:20:35.38,EN,,0,0,0,,But you're quite right. Dialogue: 0,0:20:35.38,0:20:37.32,EN,,0,0,0,,There are redundancies here that you can get rid of. Dialogue: 0,0:20:38.37,0:20:40.80,EN,,0,0,0,,That's another reason why this language is somewhat slow. Dialogue: 0,0:20:41.19,0:20:42.70,EN,,0,0,0,,There are a lot smarter things you can do. Dialogue: 0,0:20:42.93,0:20:46.22,EN,,0,0,0,,We're just trying to show you a very simple, in principle, implementation. Dialogue: 0,0:20:51.22,0:20:53.23,EN,,0,0,0,,AUDIENCE: Did you model this language on Prolog, Dialogue: 0,0:20:53.24,0:20:55.13,EN,,0,0,0,,or did it just come out looking like Prolog? Dialogue: 0,0:21:04.96,0:21:07.08,EN,,0,0,0,,PROFESSOR: Well, Gerry insulted a whole bunch of people yesterday, Dialogue: 0,0:21:07.24,0:21:09.92,EN,,0,0,0,,so I might as well say that the MIT attitude towards Prolog is Dialogue: 0,0:21:10.19,0:21:12.60,EN,,0,0,0,,is something that people did in about 1971 Dialogue: 0,0:21:12.64,0:21:15.60,EN,,0,0,0,,and decided that it wasn't really the right thing and stopped. Dialogue: 0,0:21:16.12,0:21:22.80,EN,,0,0,0,,So we modeled this on the sort of natural way that this thing was done Dialogue: 0,0:21:22.84,0:21:24.73,EN,,0,0,0,,in about 1971, Dialogue: 0,0:21:25.13,0:21:27.24,EN,,0,0,0,,except at that point, we didn't do it with streams. Dialogue: 0,0:21:28.27,0:21:33.04,EN,,0,0,0,,And then we... After we were using it for about six months, Dialogue: 0,0:21:33.08,0:21:34.91,EN,,0,0,0,,we discovered that it had all these problems, Dialogue: 0,0:21:34.94,0:21:36.30,EN,,0,0,0,,some of which I'll talk about later. Dialogue: 0,0:21:37.33,0:21:38.19,EN,,0,0,0,,And we said, Dialogue: 0,0:21:38.44,0:21:39.92,EN,,0,0,0,,gee, Prolog must have fixed those, Dialogue: 0,0:21:39.93,0:21:41.21,EN,,0,0,0,,and then we found out that it didn't. Dialogue: 0,0:21:41.25,0:21:43.02,EN,,0,0,0,,So this does about the same thing as Prolog. Dialogue: 0,0:21:43.60,0:21:44.95,EN,,0,0,0,,AUDIENCE: Does Prolog use streams? Dialogue: 0,0:21:44.95,0:21:46.20,EN,,0,0,0,,PROFESSOR: No. Prolog -- Dialogue: 0,0:21:46.78,0:21:51.04,EN,,0,0,0,,In how it behaves, it behaves a lot like Prolog. Dialogue: 0,0:21:51.04,0:21:52.96,EN,,0,0,0,,Prolog uses a backtracking strategy. Dialogue: 0,0:21:53.80,0:21:55.71,EN,,0,0,0,,But the other thing that's really good about Prolog Dialogue: 0,0:21:55.72,0:21:57.98,EN,,0,0,0,,that makes it a usable thing Dialogue: 0,0:21:58.28,0:22:01.50,EN,,0,0,0,,is that there's a really very, very Dialogue: 0,0:22:01.68,0:22:04.09,EN,,0,0,0,,there's a really very, very well-engineered compiler technology Dialogue: 0,0:22:04.11,0:22:05.32,EN,,0,0,0,,that makes it run fast. Dialogue: 0,0:22:06.65,0:22:10.81,EN,,0,0,0,,So although you saw the merge spitting out these answers very, very slowly, Dialogue: 0,0:22:11.66,0:22:13.61,EN,,0,0,0,,a real Prolog will run very, very fast. Dialogue: 0,0:22:14.70,0:22:16.48,EN,,0,0,0,,Because even though it's sort of doing this, Dialogue: 0,0:22:16.67,0:22:20.81,EN,,0,0,0,,the real work that went into Prolog is a very, very excellent compiler effort. Dialogue: 0,0:22:24.30,0:22:25.21,EN,,0,0,0,,Let's take a break. Dialogue: 0,0:22:25.42,0:22:36.17,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:23:16.65,0:23:18.83,EN,,0,0,0,,We've looked at the primitive queries Dialogue: 0,0:23:19.21,0:23:23.52,EN,,0,0,0,,and the ways that streams are used to implement the means of combination: Dialogue: 0,0:23:23.79,0:23:25.72,EN,,0,0,0,,AND and OR and NOT. Dialogue: 0,0:23:26.95,0:23:28.43,EN,,0,0,0,,Now, let go on to the means of abstraction. Dialogue: 0,0:23:29.58,0:23:32.80,EN,,0,0,0,,Remember, the means of abstraction in this language are rules. Dialogue: 0,0:23:35.15,0:23:37.79,EN,,0,0,0,,So z is a boss in division d Dialogue: 0,0:23:39.18,0:23:43.77,EN,,0,0,0,,if there's some x who has a job in division d Dialogue: 0,0:23:45.68,0:23:47.47,EN,,0,0,0,,and z is the supervisor of x. Dialogue: 0,0:23:48.90,0:23:50.60,EN,,0,0,0,,That's what it means for someone to be a boss. Dialogue: 0,0:23:52.26,0:23:53.15,EN,,0,0,0,,So, and in effect, Dialogue: 0,0:23:53.34,0:23:55.61,EN,,0,0,0,,if you think about what we're doing with relation to this, Dialogue: 0,0:23:56.80,0:23:57.90,EN,,0,0,0,,there's the query we wrote-- Dialogue: 0,0:23:57.93,0:24:01.90,EN,,0,0,0,,the job of x is in d and the supervisor of x is z-- Dialogue: 0,0:24:02.19,0:24:04.28,EN,,0,0,0,,what we in effect want to do is take this whole mess Dialogue: 0,0:24:05.07,0:24:06.57,EN,,0,0,0,,and draw a box around it Dialogue: 0,0:24:19.08,0:24:24.54,EN,,0,0,0,,and say this whole thing inside the box Dialogue: 0,0:24:25.15,0:24:32.48,EN,,0,0,0,,is boss of z in division d. Dialogue: 0,0:24:33.90,0:24:35.25,EN,,0,0,0,,That's in effect what we want to do. Dialogue: 0,0:24:38.72,0:24:39.72,EN,,0,0,0,,So, for instance, Dialogue: 0,0:24:43.18,0:24:44.08,EN,,0,0,0,,if we've done that, Dialogue: 0,0:24:45.00,0:24:47.84,EN,,0,0,0,,and we want to check whether or not it's true Dialogue: 0,0:24:47.95,0:24:50.51,EN,,0,0,0,,that Ben Bitdiddle is a boss in the computer division, Dialogue: 0,0:24:51.10,0:25:02.86,EN,,0,0,0,,so if I want to say boss of Ben Bitdiddle in the computer division, Dialogue: 0,0:25:04.78,0:25:07.08,EN,,0,0,0,,imagine typing that in as query to the system, Dialogue: 0,0:25:07.12,0:25:09.16,EN,,0,0,0,,in effect what we want to do Dialogue: 0,0:25:10.67,0:25:12.92,EN,,0,0,0,,is set up a dictionary here, Dialogue: 0,0:25:15.82,0:25:23.63,EN,,0,0,0,,which has z to Ben Bitdiddle Dialogue: 0,0:25:28.88,0:25:33.31,EN,,0,0,0,,and d to computer. Dialogue: 0,0:25:37.08,0:25:38.62,EN,,0,0,0,,Where did that dictionary come from? Dialogue: 0,0:25:38.68,0:25:40.71,EN,,0,0,0,,Let's look at the slide for one second. Dialogue: 0,0:25:40.71,0:25:43.71,EN,,0,0,0,,That dictionary came from matching the query Dialogue: 0,0:25:44.30,0:25:46.33,EN,,0,0,0,,that said boss of Ben Bitdiddle and computer Dialogue: 0,0:25:46.51,0:25:49.63,EN,,0,0,0,,onto the conclusion of the rule: boss of z and d. Dialogue: 0,0:25:51.65,0:25:54.11,EN,,0,0,0,,So we match the query to the conclusion of the rule. Dialogue: 0,0:25:54.19,0:25:55.53,EN,,0,0,0,,That gives us a dictionary, Dialogue: 0,0:25:58.99,0:26:02.54,EN,,0,0,0,,and that's the thing that we would now like to put into this whole big thing Dialogue: 0,0:26:02.92,0:26:05.56,EN,,0,0,0,,and process and see if anything comes out the other side. Dialogue: 0,0:26:06.67,0:26:09.88,EN,,0,0,0,,If anything comes out, it'll be true. Dialogue: 0,0:26:11.33,0:26:12.37,EN,,0,0,0,,That's the basic idea. Dialogue: 0,0:26:12.37,0:26:13.24,EN,,0,0,0,,So in general, Dialogue: 0,0:26:14.03,0:26:15.40,EN,,0,0,0,,the way we implement a rule Dialogue: 0,0:26:15.85,0:26:18.89,EN,,0,0,0,,is we match the conclusion of the rule Dialogue: 0,0:26:20.86,0:26:22.96,EN,,0,0,0,,against something we might want to check it's true. Dialogue: 0,0:26:23.58,0:26:25.12,EN,,0,0,0,,That match gives us a dictionary, Dialogue: 0,0:26:25.29,0:26:28.22,EN,,0,0,0,,and with respect to that dictionary, Dialogue: 0,0:26:30.35,0:26:34.51,EN,,0,0,0,,we process the body of the rule. Dialogue: 0,0:26:36.33,0:26:37.68,EN,,0,0,0,,Well, that's really all there is, Dialogue: 0,0:26:38.64,0:26:41.44,EN,,0,0,0,,except for two technical points. Dialogue: 0,0:26:43.04,0:26:44.32,EN,,0,0,0,,The first technical point is that Dialogue: 0,0:26:45.74,0:26:47.26,EN,,0,0,0,,I might have said something else. Dialogue: 0,0:26:47.51,0:26:48.41,EN,,0,0,0,,I might have said Dialogue: 0,0:26:50.54,0:26:52.36,EN,,0,0,0,,who's the boss in the computer division? Dialogue: 0,0:26:52.54,0:26:56.32,EN,,0,0,0,,So I might say boss of who in computer division. Dialogue: 0,0:27:00.78,0:27:01.63,EN,,0,0,0,,And if I did that, Dialogue: 0,0:27:02.57,0:27:04.62,EN,,0,0,0,,what I would really like to do in effect is not Dialogue: 0,0:27:05.04,0:27:06.49,EN,,0,0,0,,is start up this dictionary Dialogue: 0,0:27:08.35,0:27:09.88,EN,,0,0,0,,with a match that sort of says, Dialogue: 0,0:27:09.93,0:27:11.20,EN,,0,0,0,,well, d is computer Dialogue: 0,0:27:14.35,0:27:18.48,EN,,0,0,0,,and z is whatever who is. Dialogue: 0,0:27:21.70,0:27:23.22,EN,,0,0,0,,And our matcher won't quite do that. Dialogue: 0,0:27:23.22,0:27:27.00,EN,,0,0,0,,That's not quite matching a pattern against data. Dialogue: 0,0:27:28.58,0:27:29.72,EN,,0,0,0,,It's matching two patterns Dialogue: 0,0:27:29.74,0:27:31.58,EN,,0,0,0,,sort of saying are they consistent or not Dialogue: 0,0:27:31.90,0:27:33.48,EN,,0,0,0,,or what ways make them consistent. Dialogue: 0,0:27:33.48,0:27:36.43,EN,,0,0,0,,In other words, what we need is not quite a pattern matcher, Dialogue: 0,0:27:36.96,0:27:38.91,EN,,0,0,0,,but something a little bit more general Dialogue: 0,0:27:39.13,0:27:40.11,EN,,0,0,0,,called a unifier. Dialogue: 0,0:27:44.42,0:27:48.06,EN,,0,0,0,,And a unifier is a slight generalization of a pattern matcher. Dialogue: 0,0:27:49.53,0:27:52.17,EN,,0,0,0,,What a unifier does is take two patterns Dialogue: 0,0:27:53.23,0:27:57.53,EN,,0,0,0,,and say what's the most general thing you can substitute Dialogue: 0,0:27:58.20,0:28:00.01,EN,,0,0,0,,for the variables in those two patterns Dialogue: 0,0:28:02.68,0:28:05.08,EN,,0,0,0,,to make them satisfy the pattern simultaneously? Dialogue: 0,0:28:05.68,0:28:06.60,EN,,0,0,0,,Let me give you an example. Dialogue: 0,0:28:08.86,0:28:14.49,EN,,0,0,0,,If I have the pattern two-element list, which is x and x, Dialogue: 0,0:28:15.76,0:28:17.15,EN,,0,0,0,,so this is I have a two-element list Dialogue: 0,0:28:17.32,0:28:18.64,EN,,0,0,0,,where both elements are the same Dialogue: 0,0:28:18.67,0:28:20.04,EN,,0,0,0,,and otherwise I don't care what they are, Dialogue: 0,0:28:20.40,0:28:22.83,EN,,0,0,0,,and I unify that against the pattern Dialogue: 0,0:28:22.92,0:28:24.62,EN,,0,0,0,,that says there's a two-element list, Dialogue: 0,0:28:24.65,0:28:27.61,EN,,0,0,0,,and the first one is a and something and c Dialogue: 0,0:28:28.00,0:28:30.14,EN,,0,0,0,,and the second one is a and b and z, Dialogue: 0,0:28:33.07,0:28:34.88,EN,,0,0,0,,then what the unifier should tell me is, Dialogue: 0,0:28:34.89,0:28:36.17,EN,,0,0,0,,oh yeah, in that dictionary, Dialogue: 0,0:28:36.35,0:28:37.96,EN,,0,0,0,,x has to be a, b, c, Dialogue: 0,0:28:39.34,0:28:41.92,EN,,0,0,0,,and y has to be d and z has to be c. Dialogue: 0,0:28:43.44,0:28:46.28,EN,,0,0,0,,Those are the restrictions I'd have to put on the values of x, y, and z Dialogue: 0,0:28:46.33,0:28:47.58,EN,,0,0,0,,to make these two unify, Dialogue: 0,0:28:48.12,0:28:50.84,EN,,0,0,0,,or in other words, to make this match x Dialogue: 0,0:28:51.15,0:28:53.37,EN,,0,0,0,,and make this match x. Dialogue: 0,0:28:55.28,0:28:57.76,EN,,0,0,0,,The unifier should be able to deduce that. Dialogue: 0,0:28:58.54,0:29:01.08,EN,,0,0,0,,But the unifier may-- there are more complicated things. Dialogue: 0,0:29:01.08,0:29:03.07,EN,,0,0,0,,I might have said something a little bit more complicated. Dialogue: 0,0:29:03.48,0:29:05.74,EN,,0,0,0,,I might have said there's a list with two elements, Dialogue: 0,0:29:07.00,0:29:08.28,EN,,0,0,0,,and they're both the same, Dialogue: 0,0:29:08.86,0:29:11.15,EN,,0,0,0,,and they should unify against something of this form. Dialogue: 0,0:29:12.65,0:29:15.36,EN,,0,0,0,,And the unifier should be able to deduce from that. Dialogue: 0,0:29:16.89,0:29:19.57,EN,,0,0,0,,Like that y would have to be b. y would have to be b. Dialogue: 0,0:29:19.57,0:29:22.12,EN,,0,0,0,,Because these two are the same, Dialogue: 0,0:29:22.22,0:29:23.52,EN,,0,0,0,,so y's got to be b. Dialogue: 0,0:29:24.34,0:29:27.53,EN,,0,0,0,,And v here would have to be a. Dialogue: 0,0:29:28.94,0:29:30.99,EN,,0,0,0,,And z and w can be anything, Dialogue: 0,0:29:31.00,0:29:32.43,EN,,0,0,0,,but they have to be the same thing. Dialogue: 0,0:29:35.71,0:29:41.76,EN,,0,0,0,,And x would have to be b, followed by a, followed by whatever w Dialogue: 0,0:29:42.83,0:29:44.68,EN,,0,0,0,,or whatever z is, which is the same. Dialogue: 0,0:29:44.70,0:29:49.42,EN,,0,0,0,,So you see, the unifier somehow has to deduce things to unify these patterns. Dialogue: 0,0:29:50.88,0:29:53.52,EN,,0,0,0,,So you might think there's some kind of magic deduction going on, Dialogue: 0,0:29:54.27,0:29:55.23,EN,,0,0,0,,but there's not. Dialogue: 0,0:29:55.85,0:29:59.88,EN,,0,0,0,,A unifier is basically a very simple modification of a pattern matcher. Dialogue: 0,0:30:00.15,0:30:01.85,EN,,0,0,0,,And if you look in the book, you'll see something like Dialogue: 0,0:30:02.25,0:30:06.16,EN,,0,0,0,,like three or four lines of code added to the pattern matcher you just saw Dialogue: 0,0:30:06.49,0:30:08.17,EN,,0,0,0,,to handle the symmetric case. Dialogue: 0,0:30:08.28,0:30:10.81,EN,,0,0,0,,Remember, the pattern matcher has a place where it says Dialogue: 0,0:30:11.66,0:30:14.28,EN,,0,0,0,,is this variable matching a constant. Dialogue: 0,0:30:14.98,0:30:16.42,EN,,0,0,0,,And if so, it checks in the dictionary. Dialogue: 0,0:30:16.42,0:30:18.25,EN,,0,0,0,,There's only one other clause in the unifier, Dialogue: 0,0:30:18.49,0:30:20.75,EN,,0,0,0,,which says is this variable matching a variable, Dialogue: 0,0:30:22.00,0:30:23.42,EN,,0,0,0,,in which case you go look in the dictionary Dialogue: 0,0:30:23.45,0:30:25.68,EN,,0,0,0,,and see if that's consistent with what's in the dictionary. Dialogue: 0,0:30:27.03,0:30:31.13,EN,,0,0,0,,So all the, quote, deduction that's in this language, Dialogue: 0,0:30:31.28,0:30:34.59,EN,,0,0,0,,if you sort of look at it, sort of sits in the rule applications, Dialogue: 0,0:30:34.99,0:30:37.88,EN,,0,0,0,,which, if you look at that, sits in the unifier, Dialogue: 0,0:30:38.36,0:30:40.32,EN,,0,0,0,,which, if you look at that under a microscope, Dialogue: 0,0:30:40.56,0:30:43.96,EN,,0,0,0,,sits essentially in the pattern matcher. Dialogue: 0,0:30:44.94,0:30:47.07,EN,,0,0,0,,There's no magic at all going on in there. Dialogue: 0,0:30:47.41,0:30:50.25,EN,,0,0,0,,And the, quote, deduction that you see Dialogue: 0,0:30:50.94,0:30:52.89,EN,,0,0,0,,is just the fact that there's this recursion, Dialogue: 0,0:30:52.92,0:30:55.69,EN,,0,0,0,,which is unwinding the matches bit by bit. Dialogue: 0,0:30:56.03,0:30:58.03,EN,,0,0,0,,So it looks like this thing is being very clever, Dialogue: 0,0:30:58.44,0:31:00.36,EN,,0,0,0,,but in fact, it's not being very clever at all. Dialogue: 0,0:31:02.14,0:31:04.41,EN,,0,0,0,,There are cases where a unifier might have to be clever. Dialogue: 0,0:31:04.88,0:31:05.87,EN,,0,0,0,,Let me show you one more. Dialogue: 0,0:31:11.07,0:31:13.36,EN,,0,0,0,,Suppose I want to unify a list of two elements, Dialogue: 0,0:31:13.48,0:31:14.81,EN,,0,0,0,,x and x, Dialogue: 0,0:31:17.24,0:31:22.14,EN,,0,0,0,,with a thing that says it's y followed by a dot y. Dialogue: 0,0:31:24.37,0:31:26.12,EN,,0,0,0,,Now, if you think of what that would have to mean, Dialogue: 0,0:31:26.86,0:31:29.71,EN,,0,0,0,,it would have to mean that x had better be the same as y, Dialogue: 0,0:31:30.92,0:31:31.66,EN,,0,0,0,,but also Dialogue: 0,0:31:31.82,0:31:36.16,EN,,0,0,0,,x had better be the same as a list whose first element is a and whose rest is y. Dialogue: 0,0:31:37.33,0:31:39.45,EN,,0,0,0,,And if you think about what that would have to mean, Dialogue: 0,0:31:42.27,0:31:44.71,EN,,0,0,0,,it would have to mean that y is the infinite list of a's. Dialogue: 0,0:31:47.50,0:31:48.35,EN,,0,0,0,,In some sense, Dialogue: 0,0:31:49.21,0:31:52.40,EN,,0,0,0,,in order to do that unification, Dialogue: 0,0:31:52.60,0:31:54.84,EN,,0,0,0,,I have to solve the fixed-point equation Dialogue: 0,0:31:55.05,0:32:01.84,EN,,0,0,0,,cons of a to y is equal to y. Dialogue: 0,0:32:04.57,0:32:06.96,EN,,0,0,0,,And in general, I wrote a very simple one. Dialogue: 0,0:32:07.29,0:32:08.67,EN,,0,0,0,,Really doing unification Dialogue: 0,0:32:08.97,0:32:11.98,EN,,0,0,0,,might have to solve an arbitrary fixed-point equation: Dialogue: 0,0:32:12.01,0:32:13.42,EN,,0,0,0,,f of y equals y. Dialogue: 0,0:32:15.53,0:32:17.08,EN,,0,0,0,,And basically, you can't do that Dialogue: 0,0:32:17.10,0:32:19.47,EN,,0,0,0,,and make the thing finite all the time. Dialogue: 0,0:32:20.57,0:32:23.60,EN,,0,0,0,,So how does the logic language handle that? Dialogue: 0,0:32:24.89,0:32:26.48,EN,,0,0,0,,The answer is it doesn't. Dialogue: 0,0:32:27.16,0:32:28.04,EN,,0,0,0,,It just punts. Dialogue: 0,0:32:28.73,0:32:31.07,EN,,0,0,0,,And there's a little check in the unifier, Dialogue: 0,0:32:31.31,0:32:33.82,EN,,0,0,0,,which says, oh, is this one of the hard cases Dialogue: 0,0:32:34.44,0:32:38.00,EN,,0,0,0,,which when I go to match things would involve solving a fixed-point equation? Dialogue: 0,0:32:38.65,0:32:40.81,EN,,0,0,0,,And in this case, I will throw up my hands. Dialogue: 0,0:32:42.84,0:32:44.65,EN,,0,0,0,,And if that check were not in there, Dialogue: 0,0:32:45.00,0:32:45.88,EN,,0,0,0,,what would happen? Dialogue: 0,0:32:47.99,0:32:49.10,EN,,0,0,0,,In most cases is Dialogue: 0,0:32:49.13,0:32:51.31,EN,,0,0,0,,that the unifier would just go into an infinite loop. Dialogue: 0,0:32:53.74,0:32:56.54,EN,,0,0,0,,And other logic programming languages work like that. Dialogue: 0,0:32:56.80,0:32:58.14,EN,,0,0,0,,So there's really no magic. Dialogue: 0,0:32:58.22,0:32:59.93,EN,,0,0,0,,The easy case is done in a matcher. Dialogue: 0,0:33:00.10,0:33:01.58,EN,,0,0,0,,The hard case is not done at all. Dialogue: 0,0:33:02.96,0:33:05.47,EN,,0,0,0,,And that's about the state of this technology. Dialogue: 0,0:33:11.88,0:33:14.24,EN,,0,0,0,,OK, Let me just say again formally Dialogue: 0,0:33:14.27,0:33:16.38,EN,,0,0,0,,how rules work now that I talked about unifiers. Dialogue: 0,0:33:17.39,0:33:18.75,EN,,0,0,0,,So the official definition Dialogue: 0,0:33:19.20,0:33:20.96,EN,,0,0,0,,is that to apply a rule, Dialogue: 0,0:33:24.17,0:33:27.13,EN,,0,0,0,,we-- well, let's start using some words we've used before. Dialogue: 0,0:33:28.27,0:33:32.01,EN,,0,0,0,,Let's talk about sticking dictionaries into Dialogue: 0,0:33:32.88,0:33:34.78,EN,,0,0,0,,these big boxes of query things Dialogue: 0,0:33:34.81,0:33:38.54,EN,,0,0,0,,as evaluating these large queries Dialogue: 0,0:33:39.95,0:33:43.85,EN,,0,0,0,,relative to an environment or a frame. Dialogue: 0,0:33:43.85,0:33:45.04,EN,,0,0,0,,So when you think of that dictionary, Dialogue: 0,0:33:45.07,0:33:46.28,EN,,0,0,0,,what's the dictionary after all? Dialogue: 0,0:33:46.72,0:33:48.18,EN,,0,0,0,,It's a bunch of meanings for symbols. Dialogue: 0,0:33:48.18,0:33:50.22,EN,,0,0,0,,That's what we've been calling frames or environments. Dialogue: 0,0:33:51.80,0:33:55.97,EN,,0,0,0,,What does it mean to do some processing relevant to an environment? Dialogue: 0,0:33:55.97,0:33:57.42,EN,,0,0,0,,That's what we've been calling evaluation. Dialogue: 0,0:33:58.33,0:34:01.56,EN,,0,0,0,,So we can say the way that you apply a rule Dialogue: 0,0:34:01.92,0:34:06.16,EN,,0,0,0,,is to evaluate the rule body relative to an environment Dialogue: 0,0:34:06.67,0:34:11.58,EN,,0,0,0,,that's formed by unifying the rule conclusion with the given query. Dialogue: 0,0:34:13.23,0:34:14.51,EN,,0,0,0,,And the thing I want you to notice Dialogue: 0,0:34:14.80,0:34:17.08,EN,,0,0,0,,is the complete formal similarity Dialogue: 0,0:34:18.16,0:34:21.50,EN,,0,0,0,,to the net of circular evaluator or the substitution model. Dialogue: 0,0:34:21.63,0:34:22.73,EN,,0,0,0,,To apply a procedure, Dialogue: 0,0:34:22.86,0:34:28.36,EN,,0,0,0,,we evaluate the procedure body relative to an environment Dialogue: 0,0:34:28.54,0:34:33.13,EN,,0,0,0,,that's formed by blinding the procedure parameters to the arguments. Dialogue: 0,0:34:34.56,0:34:36.41,EN,,0,0,0,,There's a complete formal similarity there Dialogue: 0,0:34:36.44,0:34:40.41,EN,,0,0,0,,between the rules, rule application, and procedure application Dialogue: 0,0:34:40.57,0:34:42.30,EN,,0,0,0,,even though these things are very, very different. Dialogue: 0,0:34:43.65,0:34:45.61,EN,,0,0,0,,And again, you have the EVAL APPLY loop. Dialogue: 0,0:34:47.29,0:34:49.52,EN,,0,0,0,,EVAL and APPLY. Dialogue: 0,0:34:53.39,0:34:57.39,EN,,0,0,0,,So in general, I might be processing some combined expression Dialogue: 0,0:34:57.42,0:34:59.13,EN,,0,0,0,,that will turn into a rule application, Dialogue: 0,0:35:00.70,0:35:03.28,EN,,0,0,0,,which will generate some dictionaries or frames or environments-- Dialogue: 0,0:35:03.31,0:35:04.72,EN,,0,0,0,,whatever you want to call them-- from match, Dialogue: 0,0:35:05.02,0:35:08.43,EN,,0,0,0,,which will then be the input to some big compound thing like this. Dialogue: 0,0:35:08.66,0:35:11.77,EN,,0,0,0,,This has pieces of it and may have other rule applications. Dialogue: 0,0:35:13.58,0:35:15.68,EN,,0,0,0,,And you have essentially the same cycle Dialogue: 0,0:35:15.72,0:35:18.68,EN,,0,0,0,,even though there's nothing here at all that looks like procedures. Dialogue: 0,0:35:19.68,0:35:21.87,EN,,0,0,0,,It really has to do with the fact you've built a language Dialogue: 0,0:35:22.08,0:35:25.49,EN,,0,0,0,,whose means of combination and abstraction unwind in certain ways. Dialogue: 0,0:35:28.77,0:35:29.52,EN,,0,0,0,,And then in general, Dialogue: 0,0:35:29.77,0:35:31.39,EN,,0,0,0,,what happens at the very top level, Dialogue: 0,0:35:33.79,0:35:35.96,EN,,0,0,0,,you might have rules in your database also, Dialogue: 0,0:35:36.65,0:35:38.70,EN,,0,0,0,,so things in this database might be rules. Dialogue: 0,0:35:40.46,0:35:42.06,EN,,0,0,0,,There are ways to check that things are true. Dialogue: 0,0:35:42.92,0:35:44.89,EN,,0,0,0,,So it might come in here and have to do a rule check. Dialogue: 0,0:35:46.75,0:35:48.16,EN,,0,0,0,,And then there's some control structure Dialogue: 0,0:35:48.19,0:35:50.48,EN,,0,0,0,,which says, well, you look at some rules, and you look at some data elements, Dialogue: 0,0:35:50.51,0:35:51.80,EN,,0,0,0,,and you look at some rules and data elements, Dialogue: 0,0:35:51.84,0:35:53.12,EN,,0,0,0,,and these fan out and out and out. Dialogue: 0,0:35:53.35,0:35:55.48,EN,,0,0,0,,So it becomes essentially impossible Dialogue: 0,0:35:55.68,0:35:57.69,EN,,0,0,0,,to say what order it's looking at these things in, Dialogue: 0,0:35:58.20,0:36:00.27,EN,,0,0,0,,whether it's breadth first or depth first or anything. Dialogue: 0,0:36:00.28,0:36:01.64,EN,,0,0,0,,And it's even more impossible Dialogue: 0,0:36:01.66,0:36:05.58,EN,,0,0,0,,because the actual order is somehow buried in the delays of the streams. Dialogue: 0,0:36:07.69,0:36:11.16,EN,,0,0,0,,So what's very hard to tell from this is the order in which it's scanned. Dialogue: 0,0:36:11.27,0:36:12.16,EN,,0,0,0,,But what's true is, Dialogue: 0,0:36:12.19,0:36:13.64,EN,,0,0,0,,because you're looking at the stream view, Dialogue: 0,0:36:13.90,0:36:15.82,EN,,0,0,0,,is that all of them eventually get looked at. Dialogue: 0,0:36:24.98,0:36:28.15,EN,,0,0,0,,Let me just mention one tiny technical problem. Dialogue: 0,0:36:30.88,0:36:33.55,EN,,0,0,0,,Um Suppose I tried over here. Dialogue: 0,0:36:37.53,0:36:41.00,EN,,0,0,0,,Suppose I tried saying boss of y is computer, Dialogue: 0,0:36:44.22,0:36:45.78,EN,,0,0,0,,then a funny thing would happen. Dialogue: 0,0:36:45.78,0:36:50.25,EN,,0,0,0,,As I stuck a dictionary with y in here, Dialogue: 0,0:36:52.73,0:36:57.37,EN,,0,0,0,,I might get-- this y is not the same as that y, Dialogue: 0,0:36:57.42,0:37:00.62,EN,,0,0,0,,which was the other piece of somebody's job description. Dialogue: 0,0:37:01.58,0:37:03.80,EN,,0,0,0,,So if I really only did literally what I said, Dialogue: 0,0:37:04.22,0:37:06.44,EN,,0,0,0,,we'd get some variable conflict problems. Dialogue: 0,0:37:09.28,0:37:10.48,EN,,0,0,0,,So I lied to you a little bit. Dialogue: 0,0:37:10.93,0:37:13.84,EN,,0,0,0,,Notice that problem is exactly a problem we've run into before. Dialogue: 0,0:37:14.27,0:37:15.56,EN,,0,0,0,,It is precisely Dialogue: 0,0:37:15.96,0:37:18.36,EN,,0,0,0,,the need for local variables in a language. Dialogue: 0,0:37:19.24,0:37:21.74,EN,,0,0,0,,When I square, when I have the sum of squares, Dialogue: 0,0:37:21.79,0:37:23.39,EN,,0,0,0,,that x had better not be that x. Dialogue: 0,0:37:24.96,0:37:26.32,EN,,0,0,0,,That's exactly the same as Dialogue: 0,0:37:27.39,0:37:29.77,EN,,0,0,0,,as this y had better not be that y. Dialogue: 0,0:37:31.80,0:37:32.75,EN,,0,0,0,,And we know how to solve that. Dialogue: 0,0:37:32.78,0:37:34.49,EN,,0,0,0,,We built -- That was this whole environment model, Dialogue: 0,0:37:34.51,0:37:37.04,EN,,0,0,0,,and we built chains of frames and all sorts of things like that. Dialogue: 0,0:37:37.71,0:37:39.10,EN,,0,0,0,,There's a much more brutal way to solve it. Dialogue: 0,0:37:39.10,0:37:41.73,EN,,0,0,0,,In the query language, we didn't even do that. Dialogue: 0,0:37:41.73,0:37:43.18,EN,,0,0,0,,We did something completely brutal. Dialogue: 0,0:37:43.54,0:37:45.93,EN,,0,0,0,,We said every time you apply a rule, Dialogue: 0,0:37:47.26,0:37:49.63,EN,,0,0,0,,rename consistently all the variables in the rule Dialogue: 0,0:37:49.77,0:37:53.50,EN,,0,0,0,,to some new unique names that won't conflict with anything. Dialogue: 0,0:37:54.04,0:37:57.10,EN,,0,0,0,,If you looked at the -- That's conceptually simpler, Dialogue: 0,0:37:57.12,0:37:59.24,EN,,0,0,0,,but really brutal and not particularly efficient. Dialogue: 0,0:37:59.97,0:38:01.15,EN,,0,0,0,,But notice, Dialogue: 0,0:38:01.39,0:38:04.68,EN,,0,0,0,,we could have gotten rid of all of our environment structures Dialogue: 0,0:38:05.50,0:38:08.72,EN,,0,0,0,,if we defined for procedures in Lisp the same thing. Dialogue: 0,0:38:08.75,0:38:11.56,EN,,0,0,0,,If every time we applied a procedure and did the substitution model Dialogue: 0,0:38:11.87,0:38:13.90,EN,,0,0,0,,we renamed all the variables in the procedure, Dialogue: 0,0:38:14.19,0:38:16.28,EN,,0,0,0,,then we never would have had to worry about local variables Dialogue: 0,0:38:16.33,0:38:17.39,EN,,0,0,0,,because they would never arise. Dialogue: 0,0:38:19.04,0:38:20.41,EN,,0,0,0,,OK, well, that would be inefficient, Dialogue: 0,0:38:20.91,0:38:23.04,EN,,0,0,0,,and it's inefficient here in the query language, too, Dialogue: 0,0:38:23.29,0:38:24.59,EN,,0,0,0,,but we did it to keep it simple. Dialogue: 0,0:38:25.61,0:38:26.67,EN,,0,0,0,,Let's break for questions. Dialogue: 0,0:38:30.88,0:38:33.39,EN,,0,0,0,,AUDIENCE: When you started this section, Dialogue: 0,0:38:33.40,0:38:39.60,EN,,0,0,0,,you emphasized how powerful our APPLY EVAL model was Dialogue: 0,0:38:39.63,0:38:41.17,EN,,0,0,0,,that we could use it for any language. Dialogue: 0,0:38:41.17,0:38:43.39,EN,,0,0,0,,And then you say we're going to have this language which is so different. Dialogue: 0,0:38:43.95,0:38:45.13,EN,,0,0,0,,It turns out that this language, Dialogue: 0,0:38:45.58,0:38:47.88,EN,,0,0,0,,as you just pointed out, is very much the same. Dialogue: 0,0:38:47.88,0:38:49.85,EN,,0,0,0,,I'm wondering if you're arguing that all languages end up Dialogue: 0,0:38:50.48,0:38:54.57,EN,,0,0,0,,coming down to this you can apply a rule or apply a procedure Dialogue: 0,0:38:55.12,0:38:55.98,EN,,0,0,0,,or some kind of apply? Dialogue: 0,0:38:57.07,0:38:58.88,EN,,0,0,0,,PROFESSOR: I would say that pretty much any language Dialogue: 0,0:38:58.92,0:39:00.30,EN,,0,0,0,,where you really are building up Dialogue: 0,0:39:00.92,0:39:04.40,EN,,0,0,0,,these means of combination and giving them simpler names Dialogue: 0,0:39:04.70,0:39:06.86,EN,,0,0,0,,and you're saying anything of the sort, like Dialogue: 0,0:39:07.79,0:39:09.90,EN,,0,0,0,,here's a general kind of expression, Dialogue: 0,0:39:09.98,0:39:11.40,EN,,0,0,0,,like how to square something, Dialogue: 0,0:39:12.03,0:39:14.20,EN,,0,0,0,,almost anything that you would call a procedure. Dialogue: 0,0:39:14.88,0:39:15.88,EN,,0,0,0,,If that's got to have parts, Dialogue: 0,0:39:15.90,0:39:17.24,EN,,0,0,0,,you have to unwind those parts. Dialogue: 0,0:39:18.02,0:39:20.19,EN,,0,0,0,,You have to have some kind of organization which says Dialogue: 0,0:39:20.57,0:39:24.03,EN,,0,0,0,,when I look at the abstract variables or tags Dialogue: 0,0:39:24.06,0:39:27.10,EN,,0,0,0,,or whatever you want to call them that might stand for particular things, Dialogue: 0,0:39:28.33,0:39:29.34,EN,,0,0,0,,you have to keep track of that, Dialogue: 0,0:39:29.39,0:39:30.91,EN,,0,0,0,,and that's going to be something like an environment. Dialogue: 0,0:39:31.72,0:39:32.54,EN,,0,0,0,,And then if you say Dialogue: 0,0:39:32.70,0:39:35.26,EN,,0,0,0,,this part can have parts which I have to unwind, Dialogue: 0,0:39:35.80,0:39:37.44,EN,,0,0,0,,you've got to have something like this cycle. Dialogue: 0,0:39:39.97,0:39:43.20,EN,,0,0,0,,And lots and lots of languages have that character Dialogue: 0,0:39:43.36,0:39:45.40,EN,,0,0,0,,as long ... when they sort of get put together in this way. Dialogue: 0,0:39:45.59,0:39:47.20,EN,,0,0,0,,This language again really is different Dialogue: 0,0:39:47.21,0:39:49.50,EN,,0,0,0,,because there's nothing like procedures on the outside. Dialogue: 0,0:39:50.69,0:39:52.68,EN,,0,0,0,,When you go below the surface and you see the implementation, Dialogue: 0,0:39:52.70,0:39:54.24,EN,,0,0,0,,of course, it starts looking the same. Dialogue: 0,0:39:54.87,0:39:56.95,EN,,0,0,0,,But from the outside, it's a very different world view. Dialogue: 0,0:39:56.95,0:39:58.54,EN,,0,0,0,,You're not computing functions of inputs. Dialogue: 0,0:40:03.97,0:40:05.71,EN,,0,0,0,,AUDIENCE: You mentioned earlier that Dialogue: 0,0:40:06.60,0:40:09.55,EN,,0,0,0,,when you build all of these rules in pattern matcher Dialogue: 0,0:40:10.01,0:40:11.42,EN,,0,0,0,,and with the delayed action of streams, Dialogue: 0,0:40:11.45,0:40:12.72,EN,,0,0,0,,you really have no way to know Dialogue: 0,0:40:13.37,0:40:15.36,EN,,0,0,0,,in what order things are evaluated. Dialogue: 0,0:40:15.58,0:40:15.94,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:40:15.94,0:40:18.28,EN,,0,0,0,,AUDIENCE: And that would indicate then that Dialogue: 0,0:40:18.94,0:40:22.28,EN,,0,0,0,,you should only express declarative knowledge that's true for all-time, Dialogue: 0,0:40:22.30,0:40:23.79,EN,,0,0,0,,no-time sequence built into it. Dialogue: 0,0:40:23.95,0:40:25.47,EN,,0,0,0,,Otherwise, these things get all-- Dialogue: 0,0:40:27.39,0:40:28.76,EN,,0,0,0,,PROFESSOR: Yes. Yes. Dialogue: 0,0:40:28.82,0:40:29.48,EN,,0,0,0,,The question is Dialogue: 0,0:40:30.06,0:40:32.60,EN,,0,0,0,,this really is set up for doing declarative knowledge, Dialogue: 0,0:40:33.26,0:40:34.81,EN,,0,0,0,,and as I presented it-- no Dialogue: 0,0:40:35.71,0:40:39.56,EN,,0,0,0,,and I'll show you some of the ugly warts under this after the break. Dialogue: 0,0:40:40.83,0:40:42.60,EN,,0,0,0,,As I presented it, it's just doing logic. Dialogue: 0,0:40:43.07,0:40:44.52,EN,,0,0,0,,And in principle, if it were logic, Dialogue: 0,0:40:44.54,0:40:46.81,EN,,0,0,0,,it wouldn't matter what order it's getting done. Dialogue: 0,0:40:48.84,0:40:51.55,EN,,0,0,0,,And it's quite true Dialogue: 0,0:40:51.60,0:40:53.61,EN,,0,0,0,,when you start doing things where you have side effects Dialogue: 0,0:40:53.68,0:40:55.20,EN,,0,0,0,,like adding things to the database Dialogue: 0,0:40:55.23,0:40:58.16,EN,,0,0,0,,and taking things out, and we'll see some others, Dialogue: 0,0:40:58.75,0:41:00.83,EN,,0,0,0,,you loose that kind of control. Dialogue: 0,0:41:01.29,0:41:02.94,EN,,0,0,0,,So, for example, contrasting with Prolog. Dialogue: 0,0:41:02.94,0:41:05.15,EN,,0,0,0,,Say Prolog has various features Dialogue: 0,0:41:05.16,0:41:07.79,EN,,0,0,0,,where you really exploit the order of evaluation. Dialogue: 0,0:41:09.64,0:41:11.77,EN,,0,0,0,,And people write Prolog programs that way. Dialogue: 0,0:41:11.77,0:41:14.04,EN,,0,0,0,,That turns out to be very complicated in Prolog, Dialogue: 0,0:41:14.32,0:41:17.55,EN,,0,0,0,,although if you're an expert Prolog programmer, you can do it. Dialogue: 0,0:41:18.59,0:41:20.21,EN,,0,0,0,,However, here I don't think you can do it at all. Dialogue: 0,0:41:20.21,0:41:21.24,EN,,0,0,0,,It's very complicated Dialogue: 0,0:41:21.72,0:41:23.64,EN,,0,0,0,,because you really are giving up control over Dialogue: 0,0:41:23.77,0:41:25.72,EN,,0,0,0,,any prearranged order of trying things. Dialogue: 0,0:41:27.15,0:41:30.16,EN,,0,0,0,,AUDIENCE: Now, that would indicate then that you have a functional mapping. Dialogue: 0,0:41:30.67,0:41:32.51,EN,,0,0,0,,And when you started out this lecture, Dialogue: 0,0:41:32.99,0:41:34.08,EN,,0,0,0,,you said that Dialogue: 0,0:41:34.67,0:41:36.70,EN,,0,0,0,,we express the declarative knowledge which is a relation, Dialogue: 0,0:41:37.15,0:41:38.81,EN,,0,0,0,,and we don't talk about the inputs and the outputs. Dialogue: 0,0:41:41.21,0:41:43.37,EN,,0,0,0,,PROFESSOR: Well, there's a pun on functional, right? Dialogue: 0,0:41:43.37,0:41:45.79,EN,,0,0,0,,There's functional in the sense of no side effects Dialogue: 0,0:41:46.20,0:41:48.16,EN,,0,0,0,,and not depending on what order is going on. Dialogue: 0,0:41:48.70,0:41:51.04,EN,,0,0,0,,And then there's functional in the sense of mathematical function, Dialogue: 0,0:41:51.07,0:41:52.22,EN,,0,0,0,,which means input and output. Dialogue: 0,0:41:52.59,0:41:54.36,EN,,0,0,0,,And it's just that pun that you're making, I think. Dialogue: 0,0:41:56.51,0:41:58.51,EN,,0,0,0,,AUDIENCE: I'm a little unclear on what you're doing with Dialogue: 0,0:41:58.81,0:42:00.70,EN,,0,0,0,,two statements, the two boss statements. Dialogue: 0,0:42:01.27,0:42:05.74,EN,,0,0,0,,Is the first one building up the database Dialogue: 0,0:42:05.76,0:42:08.08,EN,,0,0,0,,and the second one a query or-- Dialogue: 0,0:42:09.07,0:42:10.12,EN,,0,0,0,,PROFESSOR: OK, I'm sorry. Dialogue: 0,0:42:12.44,0:42:15.16,EN,,0,0,0,,What I meant here, if I type something like this in as a query-- Dialogue: 0,0:42:16.12,0:42:18.44,EN,,0,0,0,,I should have given an example way at the very beginning. Dialogue: 0,0:42:19.47,0:42:23.52,EN,,0,0,0,,If I type in job, Ben Bitdiddle, computer wizard, Dialogue: 0,0:42:25.04,0:42:27.77,EN,,0,0,0,,what the processing will do is if it finds a match, Dialogue: 0,0:42:28.30,0:42:30.28,EN,,0,0,0,,it'll find a match to that exact thing, Dialogue: 0,0:42:30.86,0:42:33.28,EN,,0,0,0,,and it'll type out a job, Ben Bitdiddle, computer wizard. Dialogue: 0,0:42:34.22,0:42:35.60,EN,,0,0,0,,If it doesn't find a match, Dialogue: 0,0:42:35.69,0:42:36.75,EN,,0,0,0,,it won't find anything. Dialogue: 0,0:42:37.40,0:42:39.55,EN,,0,0,0,,So what I should have said is the way Dialogue: 0,0:42:39.56,0:42:42.27,EN,,0,0,0,,you use the query language to check whether something is true, Dialogue: 0,0:42:43.40,0:42:45.77,EN,,0,0,0,,that's one of the things you want to do in logic programming, Dialogue: 0,0:42:46.41,0:42:49.34,EN,,0,0,0,,is you type in your query and either that comes out or it doesn't. Dialogue: 0,0:42:50.68,0:42:52.38,EN,,0,0,0,,So what I was trying to illustrate here, Dialogue: 0,0:42:52.41,0:42:54.80,EN,,0,0,0,,I wanted to start with a very simple example Dialogue: 0,0:42:54.83,0:42:56.62,EN,,0,0,0,,before talking about unifiers. Dialogue: 0,0:42:57.48,0:42:58.11,EN,,0,0,0,,So what I should have said, Dialogue: 0,0:42:58.14,0:43:00.96,EN,,0,0,0,,if I just wanted to check whether this is true, Dialogue: 0,0:43:01.18,0:43:03.28,EN,,0,0,0,,I could type that in and see if anything came out Dialogue: 0,0:43:05.16,0:43:06.27,EN,,0,0,0,,AUDIENCE: And then the second one-- Dialogue: 0,0:43:06.28,0:43:07.84,EN,,0,0,0,,PROFESSOR: The second one would be a real query. Dialogue: 0,0:43:07.88,0:43:09.12,EN,,0,0,0,,AUDIENCE: A real query, yeah. Dialogue: 0,0:43:10.77,0:43:13.10,EN,,0,0,0,,PROFESSOR: What would come out, see, it would go in here say with WHO, Dialogue: 0,0:43:13.90,0:43:15.74,EN,,0,0,0,,and in would go frame that says z Dialogue: 0,0:43:16.62,0:43:18.81,EN,,0,0,0,,z is bound to who and d is bound to computer. Dialogue: 0,0:43:19.56,0:43:20.49,EN,,0,0,0,,And this will pass through, Dialogue: 0,0:43:20.51,0:43:21.95,EN,,0,0,0,,and then by the time it got out of here, Dialogue: 0,0:43:22.01,0:43:23.25,EN,,0,0,0,,who would pick up a binding. Dialogue: 0,0:43:26.95,0:43:28.76,EN,,0,0,0,,AUDIENCE: On the unifying thing there, Dialogue: 0,0:43:29.18,0:43:35.96,EN,,0,0,0,,I still am not sure what happens with who and z. Dialogue: 0,0:43:36.46,0:43:39.58,EN,,0,0,0,,OK being unifying-- the rule here says-- Dialogue: 0,0:43:42.03,0:43:46.22,EN,,0,0,0,,OK, so you say that you can't make question mark equal to question mark who. Dialogue: 0,0:43:46.26,0:43:48.08,EN,,0,0,0,,PROFESSOR: Right. That's what the matcher can't do. Dialogue: 0,0:43:48.36,0:43:50.83,EN,,0,0,0,,But unifier, what this will mean to a unifier Dialogue: 0,0:43:51.92,0:43:54.01,EN,,0,0,0,,is that there's an environment with three variables. Dialogue: 0,0:43:56.69,0:43:57.90,EN,,0,0,0,,d here is computer. Dialogue: 0,0:43:58.52,0:44:00.19,EN,,0,0,0,,z is whatever who is. Dialogue: 0,0:44:01.83,0:44:05.26,EN,,0,0,0,,So if later on in the matcher routine Dialogue: 0,0:44:07.20,0:44:10.38,EN,,0,0,0,,it said, for example, who has to be 3, Dialogue: 0,0:44:12.06,0:44:13.66,EN,,0,0,0,,then when I looked up in the dictionary, Dialogue: 0,0:44:14.00,0:44:16.40,EN,,0,0,0,,it will say, oh, z is 3 because it's the same as who. Dialogue: 0,0:44:18.36,0:44:20.44,EN,,0,0,0,,And that's in some sense the only thing you need to do Dialogue: 0,0:44:20.46,0:44:21.98,EN,,0,0,0,,to extend the unifier to a matcher. Dialogue: 0,0:44:22.48,0:44:24.80,EN,,0,0,0,,AUDIENCE: OK, because it looked like when you were telling how to unify, Dialogue: 0,0:44:24.83,0:44:26.96,EN,,0,0,0,,it looked like you would put the things together in such a way Dialogue: 0,0:44:26.99,0:44:29.23,EN,,0,0,0,,that you'd actually solve and have a value for both of them. Dialogue: 0,0:44:29.77,0:44:31.24,EN,,0,0,0,,And what it looks like now Dialogue: 0,0:44:31.28,0:44:32.83,EN,,0,0,0,,is that you're actually pass a dictionary Dialogue: 0,0:44:32.88,0:44:34.86,EN,,0,0,0,,with two variables and the variables are linked. Dialogue: 0,0:44:34.88,0:44:37.23,EN,,0,0,0,,PROFESSOR: Right. It only looks like you're solving for both of them Dialogue: 0,0:44:37.52,0:44:39.74,EN,,0,0,0,,because you're sort of looking at the whole solution at once. Dialogue: 0,0:44:40.54,0:44:42.81,EN,,0,0,0,,If you sort of watch the thing getting built up recursively, Dialogue: 0,0:44:42.81,0:44:43.74,EN,,0,0,0,,it's merely this. Dialogue: 0,0:44:44.98,0:44:48.40,EN,,0,0,0,,AUDIENCE: OK, so you do pass off that dictionary with two variables? Dialogue: 0,0:44:48.40,0:44:49.11,EN,,0,0,0,,PROFESSOR: That's right. Dialogue: 0,0:44:49.11,0:44:49.68,EN,,0,0,0,,AUDIENCE: And link? Dialogue: 0,0:44:50.38,0:44:52.91,EN,,0,0,0,,PROFESSOR: Right. It just looks like an ordinary dictionary. Dialogue: 0,0:44:54.35,0:44:56.06,EN,,0,0,0,,AUDIENCE: When you're talking about the unifier, Dialogue: 0,0:44:56.09,0:45:00.19,EN,,0,0,0,,is it that there are some cases or some points Dialogue: 0,0:45:00.75,0:45:03.98,EN,,0,0,0,,that you are not able to unify them? Dialogue: 0,0:45:04.03,0:45:04.30,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:45:04.97,0:45:08.46,EN,,0,0,0,,AUDIENCE: Can you just by building the rules or Dialogue: 0,0:45:09.16,0:45:15.93,EN,,0,0,0,,writing the forms know in advance if you are going to be able to solve Dialogue: 0,0:45:16.48,0:45:18.54,EN,,0,0,0,,to get the unification or not? Dialogue: 0,0:45:18.76,0:45:22.94,EN,,0,0,0,,Can you add some properties either to the rules itself Dialogue: 0,0:45:23.18,0:45:25.45,EN,,0,0,0,,or to the form that you're writing Dialogue: 0,0:45:25.82,0:45:29.04,EN,,0,0,0,,so that you avoid the problem of not finding unification? Dialogue: 0,0:45:29.18,0:45:31.15,EN,,0,0,0,,Well I mean, you can agree, Dialogue: 0,0:45:31.47,0:45:35.26,EN,,0,0,0,,I think, to write in a fairly restricted way where you won't run into it. Dialogue: 0,0:45:35.60,0:45:36.67,EN,,0,0,0,,See, because what you're getting-- Dialogue: 0,0:45:36.88,0:45:39.12,EN,,0,0,0,,see, the place where you get into problems is when you-- Dialogue: 0,0:45:39.68,0:45:44.25,EN,,0,0,0,,well, again, you're trying to match things like that Dialogue: 0,0:45:44.59,0:45:47.20,EN,,0,0,0,,against things where these have structure, Dialogue: 0,0:45:47.55,0:45:55.30,EN,,0,0,0,,where a, y, b, y something. Dialogue: 0,0:45:58.98,0:46:01.48,EN,,0,0,0,,So this is the kind of place where you're going to get into trouble. Dialogue: 0,0:46:03.07,0:46:05.80,EN,,0,0,0,,AUDIENCE: So you can do that syntactically? Dialogue: 0,0:46:06.14,0:46:08.76,EN,,0,0,0,,PROFESSOR: So you can kind of watch your rules Dialogue: 0,0:46:08.76,0:46:10.49,EN,,0,0,0,,in the kinds of things that your writing. Dialogue: 0,0:46:11.90,0:46:14.08,EN,,0,0,0,,AUDIENCE: So that's the problem that the builder Dialogue: 0,0:46:14.11,0:46:16.27,EN,,0,0,0,,of the database has to be concerned? Dialogue: 0,0:46:16.57,0:46:17.80,EN,,0,0,0,,PROFESSOR: That's a problem. Dialogue: 0,0:46:19.93,0:46:22.01,EN,,0,0,0,,It's a problem either-- not quite the builder of the database, Dialogue: 0,0:46:22.04,0:46:23.61,EN,,0,0,0,,the person who is expressing the rules, Dialogue: 0,0:46:24.01,0:46:25.31,EN,,0,0,0,,or the builder of the database. Dialogue: 0,0:46:25.80,0:46:29.79,EN,,0,0,0,,What the unifier actually does is you can check at the next level down Dialogue: 0,0:46:29.92,0:46:31.87,EN,,0,0,0,,when you actually get to the unifier Dialogue: 0,0:46:32.41,0:46:34.76,EN,,0,0,0,,and you'll see in the code where it looks up in the dictionary. Dialogue: 0,0:46:34.94,0:46:36.83,EN,,0,0,0,,If it sort of says what does y have to be? Dialogue: 0,0:46:37.26,0:46:41.42,EN,,0,0,0,,Oh, does y have to be something that contains a y as its expression? Dialogue: 0,0:46:41.96,0:46:43.26,EN,,0,0,0,,At that point, the unifier and say, Dialogue: 0,0:46:43.28,0:46:46.24,EN,,0,0,0,,oh my God, I'm trying to solve a fixed-point equation. Dialogue: 0,0:46:46.24,0:46:46.99,EN,,0,0,0,,I'll give it up here. Dialogue: 0,0:46:48.59,0:46:51.91,EN,,0,0,0,,AUDIENCE: You make the distinction between the rules in the database. Dialogue: 0,0:46:51.91,0:46:56.48,EN,,0,0,0,,Are the rules added to the database? Dialogue: 0,0:46:56.95,0:46:57.36,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,0:46:57.87,0:46:58.87,EN,,0,0,0,,Yes, I should have said that. Dialogue: 0,0:46:58.87,0:47:00.33,EN,,0,0,0,,One way to think about rules Dialogue: 0,0:47:00.60,0:47:02.65,EN,,0,0,0,,is that they're just other things in the database. Dialogue: 0,0:47:03.71,0:47:06.81,EN,,0,0,0,,So if you want to check the things that have to be checked in the database, Dialogue: 0,0:47:06.83,0:47:09.44,EN,,0,0,0,,they're kind of virtual facts that are in the database. Dialogue: 0,0:47:09.44,0:47:12.32,EN,,0,0,0,,AUDIENCE: But in that explanation, you made the differentiation Dialogue: 0,0:47:12.43,0:47:17.26,EN,,0,0,0,,between database and the rules itself. Dialogue: 0,0:47:18.23,0:47:19.90,EN,,0,0,0,,PROFESSOR: Yeah, I probably should not have done that. Dialogue: 0,0:47:20.49,0:47:23.31,EN,,0,0,0,,The only reason to do that is in terms of the implementation. Dialogue: 0,0:47:23.54,0:47:24.67,EN,,0,0,0,,When you look at the implementation, Dialogue: 0,0:47:24.68,0:47:27.50,EN,,0,0,0,,there's a part which says check either primitive Dialogue: 0,0:47:27.55,0:47:29.85,EN,,0,0,0,,assertions in the database or check rules. Dialogue: 0,0:47:30.47,0:47:32.72,EN,,0,0,0,,And then the real reason, the real reason why Dialogue: 0,0:47:32.78,0:47:34.56,EN,,0,0,0,,you can't tell what order things are going to come out in Dialogue: 0,0:47:34.96,0:47:40.46,EN,,0,0,0,,is that the rules database and the data database Dialogue: 0,0:47:40.48,0:47:43.68,EN,,0,0,0,,sort of get merged in a kind of delayed evaluation way. Dialogue: 0,0:47:44.60,0:47:46.80,EN,,0,0,0,,And so that's what makes the order very complicated. Dialogue: 0,0:47:55.44,0:47:56.09,EN,,0,0,0,,OK, let's break. Dialogue: 0,0:47:56.30,0:48:09.90,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:48:33.16,0:48:35.37,EN,,0,0,0,,We've just seen how the logic language works Dialogue: 0,0:48:35.39,0:48:36.41,EN,,0,0,0,,and how rules work. Dialogue: 0,0:48:37.23,0:48:39.37,EN,,0,0,0,,Now, let's turn to a more profound question. Dialogue: 0,0:48:40.12,0:48:41.28,EN,,0,0,0,,What do these things mean? Dialogue: 0,0:48:43.18,0:48:46.86,EN,,0,0,0,,That brings us to the subtlest, most devious part Dialogue: 0,0:48:46.99,0:48:48.67,EN,,0,0,0,,of this whole query language business, Dialogue: 0,0:48:49.21,0:48:53.07,EN,,0,0,0,,and that is that it's not quite what it seems to be. Dialogue: 0,0:48:53.57,0:48:56.22,EN,,0,0,0,,AND and OR and NOT Dialogue: 0,0:48:57.02,0:48:58.88,EN,,0,0,0,,and the logical implication of rules Dialogue: 0,0:48:59.69,0:49:06.64,EN,,0,0,0,,are not really the AND and OR and NOT and logical implication of logic. Dialogue: 0,0:49:07.69,0:49:09.71,EN,,0,0,0,,Let me give you an example of that. Dialogue: 0,0:49:09.91,0:49:12.22,EN,,0,0,0,,Certainly, if we have two things in logic, Dialogue: 0,0:49:12.40,0:49:19.44,EN,,0,0,0,,it ought to be the case that AND of P and Q Dialogue: 0,0:49:20.00,0:49:22.59,EN,,0,0,0,,is the same as AND of Q and P Dialogue: 0,0:49:23.10,0:49:24.51,EN,,0,0,0,,and that OR of P and Q Dialogue: 0,0:49:24.78,0:49:26.51,EN,,0,0,0,,is the same as OR of Q and P. Dialogue: 0,0:49:28.67,0:49:30.09,EN,,0,0,0,,But let's look here. Dialogue: 0,0:49:30.10,0:49:32.01,EN,,0,0,0,,Here's an example. Dialogue: 0,0:49:32.18,0:49:36.16,EN,,0,0,0,,Let's talk about somebody outranking somebody else Dialogue: 0,0:49:36.28,0:49:40.14,EN,,0,0,0,,in this our little database organization. Dialogue: 0,0:49:40.14,0:49:42.89,EN,,0,0,0,,We'll say s is outranked by b Dialogue: 0,0:49:44.64,0:49:48.62,EN,,0,0,0,,if or if either the supervisor of s is b Dialogue: 0,0:49:49.63,0:49:51.07,EN,,0,0,0,,or there's some middle manager here, Dialogue: 0,0:49:51.10,0:49:55.82,EN,,0,0,0,,that supervisor of s is m, and m is outranked by b. Dialogue: 0,0:49:59.64,0:50:02.31,EN,,0,0,0,,So there's one way to define rule outranked by. Dialogue: 0,0:50:02.31,0:50:04.16,EN,,0,0,0,,Or we can write exactly the same thing, Dialogue: 0,0:50:05.08,0:50:06.91,EN,,0,0,0,,except at the bottom here, Dialogue: 0,0:50:07.21,0:50:09.88,EN,,0,0,0,,we reversed the order of these two clauses. Dialogue: 0,0:50:11.63,0:50:12.99,EN,,0,0,0,,And certainly if this were logic, Dialogue: 0,0:50:13.00,0:50:14.88,EN,,0,0,0,,those ought to mean the same thing. Dialogue: 0,0:50:16.69,0:50:17.31,EN,,0,0,0,,However, Dialogue: 0,0:50:17.71,0:50:19.61,EN,,0,0,0,,in our particular implementation, Dialogue: 0,0:50:19.64,0:50:22.88,EN,,0,0,0,,if you say something like who's outranked by Ben Bitdiddle, Dialogue: 0,0:50:23.48,0:50:25.36,EN,,0,0,0,,what you'll find is that this rule Dialogue: 0,0:50:26.76,0:50:28.72,EN,,0,0,0,,will work perfectly well and generate answers, Dialogue: 0,0:50:30.04,0:50:31.98,EN,,0,0,0,,whereas this rule will go into an infinite loop. Dialogue: 0,0:50:34.11,0:50:36.27,EN,,0,0,0,,And the reason for that is that Dialogue: 0,0:50:36.33,0:50:40.33,EN,,0,0,0,,this will come in and say, oh, who's outranked by Ben Bitdiddle? Dialogue: 0,0:50:41.92,0:50:43.53,EN,,0,0,0,,Find an s, find an s Dialogue: 0,0:50:43.88,0:50:46.22,EN,,0,0,0,,which is outranked by b, where b is Ben Bitdiddle, Dialogue: 0,0:50:47.50,0:50:49.63,EN,,0,0,0,,which is going to happen in it a subproblem. Dialogue: 0,0:50:50.33,0:50:51.98,EN,,0,0,0,,Oh gee, find an m Dialogue: 0,0:50:52.24,0:50:54.57,EN,,0,0,0,,such as m is outranked by Ben Bitdiddle Dialogue: 0,0:50:55.61,0:50:57.36,EN,,0,0,0,,with no restrictions on m. Dialogue: 0,0:50:58.56,0:51:00.40,EN,,0,0,0,,So this will say in order to solve this problem, Dialogue: 0,0:51:01.42,0:51:03.29,EN,,0,0,0,,I solve exactly the same problem. Dialogue: 0,0:51:04.57,0:51:07.23,EN,,0,0,0,,And then after I've solved that, I'll check for a supervisory relationship. Dialogue: 0,0:51:08.00,0:51:09.16,EN,,0,0,0,,Whereas this one won't get into that, Dialogue: 0,0:51:09.18,0:51:12.35,EN,,0,0,0,,because before it tries to find this outranked by, Dialogue: 0,0:51:12.94,0:51:15.26,EN,,0,0,0,,it'll already have had a restriction on m here. Dialogue: 0,0:51:18.38,0:51:20.94,EN,,0,0,0,,So these two things which ought to mean the same, Dialogue: 0,0:51:20.99,0:51:22.67,EN,,0,0,0,,in fact, one goes into an infinite loop. Dialogue: 0,0:51:22.86,0:51:25.04,EN,,0,0,0,,One goes, one does not. Dialogue: 0,0:51:26.72,0:51:29.77,EN,,0,0,0,,That's a very extreme case Dialogue: 0,0:51:29.79,0:51:32.65,EN,,0,0,0,,of a general thing that you'll find in logic programming that Dialogue: 0,0:51:34.28,0:51:38.70,EN,,0,0,0,,if you start changing the order of the things in the ANDs or ORs, Dialogue: 0,0:51:39.34,0:51:41.58,EN,,0,0,0,,you'll find tremendous differences in efficiency. Dialogue: 0,0:51:42.24,0:51:43.21,EN,,0,0,0,,And we just saw Dialogue: 0,0:51:43.55,0:51:46.54,EN,,0,0,0,,an infinitely big difference in efficiency and an infinite loop. Dialogue: 0,0:51:49.19,0:51:51.74,EN,,0,0,0,,And there are similar things having to do order Dialogue: 0,0:51:52.00,0:51:53.31,EN,,0,0,0,,in which you enter rules. Dialogue: 0,0:51:54.07,0:51:56.48,EN,,0,0,0,,The order in which it happens to look at rules in the database Dialogue: 0,0:51:56.70,0:51:59.95,EN,,0,0,0,,may vastly change the efficiency with which it gets out answers or, Dialogue: 0,0:52:00.46,0:52:02.60,EN,,0,0,0,,in fact, send it into an infinite loop for some orderings. Dialogue: 0,0:52:03.84,0:52:07.29,EN,,0,0,0,,And this whole thing has to do Dialogue: 0,0:52:07.63,0:52:10.04,EN,,0,0,0,,the fact that you're checking these rules in some order. Dialogue: 0,0:52:10.95,0:52:14.41,EN,,0,0,0,,And some rules may lead to really long paths of implication. Dialogue: 0,0:52:14.44,0:52:16.06,EN,,0,0,0,,Others might, others might not. Dialogue: 0,0:52:16.44,0:52:17.68,EN,,0,0,0,,And you don't know a priori Dialogue: 0,0:52:17.72,0:52:19.16,EN,,0,0,0,,which ones are good and which ones are bad. Dialogue: 0,0:52:19.30,0:52:21.48,EN,,0,0,0,,And there's a whole bunch of research having to do with that, Dialogue: 0,0:52:22.16,0:52:23.76,EN,,0,0,0,,mostly having to do with thinking about Dialogue: 0,0:52:23.95,0:52:26.97,EN,,0,0,0,,making parallel implementations of logic programming languages. Dialogue: 0,0:52:27.32,0:52:29.90,EN,,0,0,0,,And in some sense, what you'd like to do is check all rules in parallel Dialogue: 0,0:52:30.36,0:52:32.80,EN,,0,0,0,,and whichever ones get answers, you bubble them up. And Dialogue: 0,0:52:33.04,0:52:34.99,EN,,0,0,0,,if some go down infinite deductive chain, Dialogue: 0,0:52:35.02,0:52:38.25,EN,,0,0,0,,well, you just-- you know, memory is cheap and processors are cheap, Dialogue: 0,0:52:38.28,0:52:40.49,EN,,0,0,0,,you just let them buzz for as for as long as you want. Dialogue: 0,0:52:43.47,0:52:44.83,EN,,0,0,0,,There's a deeper problem, though, Dialogue: 0,0:52:45.18,0:52:50.49,EN,,0,0,0,,in comparing this logic language to real logic. Dialogue: 0,0:52:50.68,0:52:52.52,EN,,0,0,0,,The example I just showed you, it Dialogue: 0,0:52:52.97,0:52:54.80,EN,,0,0,0,,went into an infinite loop maybe, Dialogue: 0,0:52:55.37,0:52:56.99,EN,,0,0,0,,but at least it didn't give the wrong answer. Dialogue: 0,0:52:58.37,0:53:03.64,EN,,0,0,0,,There's an actual deeper problem when we start comparing, Dialogue: 0,0:53:03.68,0:53:05.24,EN,,0,0,0,,you know, seriously comparing Dialogue: 0,0:53:05.71,0:53:08.46,EN,,0,0,0,,this logic language with real classical logic. Dialogue: 0,0:53:09.49,0:53:12.43,EN,,0,0,0,,So let's sort of review real classical logic. Dialogue: 0,0:53:13.71,0:53:21.04,EN,,0,0,0,,All humans are mortal. Dialogue: 0,0:53:22.35,0:53:23.45,EN,,0,0,0,,That's pretty classical logic. Dialogue: 0,0:53:24.39,0:53:28.67,EN,,0,0,0,,Then maybe we'll continue in the very best classical tradition. Dialogue: 0,0:53:29.24,0:53:32.46,EN,,0,0,0,,We'll say all-- let's make it really classical. Dialogue: 0,0:53:32.67,0:53:37.16,EN,,0,0,0,,All Greeks are human, Dialogue: 0,0:53:40.49,0:53:46.06,EN,,0,0,0,,which has the syllogism that Socrates is a Greek. Dialogue: 0,0:53:48.17,0:53:49.21,EN,,0,0,0,,And then what do you write here? Dialogue: 0,0:53:49.21,0:53:51.89,EN,,0,0,0,,I think three dots, classical logic. Dialogue: 0,0:53:51.89,0:53:54.33,EN,,0,0,0,,Therefore, then the syllogism, Dialogue: 0,0:53:54.64,0:53:59.55,EN,,0,0,0,,Socrates is mortal. Dialogue: 0,0:54:01.36,0:54:04.91,EN,,0,0,0,,So there's some real honest classical logic. Dialogue: 0,0:54:05.88,0:54:11.05,EN,,0,0,0,,Let's compare that with our classical logic database. Dialogue: 0,0:54:12.40,0:54:14.46,EN,,0,0,0,,So here's a classical logic database. Dialogue: 0,0:54:16.27,0:54:17.48,EN,,0,0,0,,Socrates is a Greek. Dialogue: 0,0:54:18.03,0:54:18.84,EN,,0,0,0,,Plato is a Greek. Dialogue: 0,0:54:19.60,0:54:20.40,EN,,0,0,0,,Zeus is a Greek, Dialogue: 0,0:54:20.84,0:54:21.98,EN,,0,0,0,,and Zeus is a god. Dialogue: 0,0:54:24.12,0:54:29.96,EN,,0,0,0,,And all humans are mortal. Dialogue: 0,0:54:30.54,0:54:32.12,EN,,0,0,0,,To show that something is mortal, Dialogue: 0,0:54:32.16,0:54:33.60,EN,,0,0,0,,it's enough to show that it's human. Dialogue: 0,0:54:34.65,0:54:35.90,EN,,0,0,0,,All humans are fallible. Dialogue: 0,0:54:38.90,0:54:40.98,EN,,0,0,0,,And all Greeks are humans is not quite right. Dialogue: 0,0:54:40.98,0:54:44.41,EN,,0,0,0,,This says that all Greeks who are not gods are human. Dialogue: 0,0:54:45.71,0:54:47.04,EN,,0,0,0,,So to show something's human, Dialogue: 0,0:54:47.07,0:54:48.89,EN,,0,0,0,,it's enough to show it's a Greek and not a god. Dialogue: 0,0:54:49.32,0:54:52.88,EN,,0,0,0,,And the address of any Greek god is Mount Olympus. Dialogue: 0,0:54:54.32,0:54:57.16,EN,,0,0,0,,So there's a little classical logic database. Dialogue: 0,0:54:57.39,0:54:59.32,EN,,0,0,0,,And indeed, that would work fairly well. Dialogue: 0,0:54:59.49,0:55:02.09,EN,,0,0,0,,If we type that in and say Dialogue: 0,0:55:03.47,0:55:06.57,EN,,0,0,0,,is Socrates mortal or Socrates fallible or mortal? Dialogue: 0,0:55:06.91,0:55:07.69,EN,,0,0,0,,It'll say yes. Dialogue: 0,0:55:07.77,0:55:09.71,EN,,0,0,0,,Is Plato mortal and fallible. Dialogue: 0,0:55:09.71,0:55:10.24,EN,,0,0,0,,It'll say yes. Dialogue: 0,0:55:10.68,0:55:12.21,EN,,0,0,0,,If we say is Zeus mortal? Dialogue: 0,0:55:12.21,0:55:13.23,EN,,0,0,0,,It won't find anything. Dialogue: 0,0:55:14.90,0:55:15.96,EN,,0,0,0,,And it'll work perfectly well. Dialogue: 0,0:55:16.54,0:55:20.12,EN,,0,0,0,,However, suppose we want to extend this. Dialogue: 0,0:55:20.12,0:55:23.05,EN,,0,0,0,,Let's define what it means for someone to be a perfect being. Dialogue: 0,0:55:23.82,0:55:27.21,EN,,0,0,0,,Let's say rule: a perfect being. Dialogue: 0,0:55:34.05,0:55:35.48,EN,,0,0,0,,And I think this is right. Dialogue: 0,0:55:35.48,0:55:38.14,EN,,0,0,0,,If you're up on your medieval scholastic philosophy, Dialogue: 0,0:55:38.44,0:55:40.17,EN,,0,0,0,,I believe that perfect beings are ones Dialogue: 0,0:55:40.68,0:55:42.65,EN,,0,0,0,,who were neither mortal nor fallible. Dialogue: 0,0:55:44.10,0:55:56.84,EN,,0,0,0,,AND NOT mortal x, NOT fallible x. Dialogue: 0,0:55:59.30,0:56:00.89,EN,,0,0,0,,So we'll define this system Dialogue: 0,0:56:02.67,0:56:04.36,EN,,0,0,0,,to teach it what a perfect being is. Dialogue: 0,0:56:05.79,0:56:07.69,EN,,0,0,0,,And now what we're going to do is Dialogue: 0,0:56:08.06,0:56:10.17,EN,,0,0,0,,ask for the address of all the perfect beings. Dialogue: 0,0:56:11.48,0:56:22.30,EN,,0,0,0,,AND the address of x is y and x is perfect. Dialogue: 0,0:56:23.48,0:56:24.97,EN,,0,0,0,,And so what we're generating here is Dialogue: 0,0:56:24.99,0:56:27.80,EN,,0,0,0,,the world's most exclusive mailing list. Dialogue: 0,0:56:30.16,0:56:32.20,EN,,0,0,0,,For the address of all the perfect beings, Dialogue: 0,0:56:32.24,0:56:33.47,EN,,0,0,0,,we might have typed this in. Dialogue: 0,0:56:33.83,0:56:35.44,EN,,0,0,0,,Or we might type in this. Dialogue: 0,0:56:36.24,0:56:50.57,EN,,0,0,0,,We'll say AND perfect of x and the address of x is y. Dialogue: 0,0:56:52.06,0:56:54.96,EN,,0,0,0,,Well, suppose we type all that in and we try this query. Dialogue: 0,0:56:55.19,0:56:56.76,EN,,0,0,0,,This query is going to give us an answer. Dialogue: 0,0:56:57.65,0:57:00.00,EN,,0,0,0,,This query will say, yeah, Mount Olympus. Dialogue: 0,0:57:04.23,0:57:06.57,EN,,0,0,0,,This query, in fact, is going to give us nothing. Dialogue: 0,0:57:06.74,0:57:09.58,EN,,0,0,0,,It will say no addresses of perfect beings. Dialogue: 0,0:57:11.64,0:57:12.51,EN,,0,0,0,,Now, why is that? Dialogue: 0,0:57:12.51,0:57:13.44,EN,,0,0,0,,Why is there a difference? Dialogue: 0,0:57:14.23,0:57:15.69,EN,,0,0,0,,This is not an infinite loop question. Dialogue: 0,0:57:15.69,0:57:17.08,EN,,0,0,0,,This is a different answer question. Dialogue: 0,0:57:19.48,0:57:20.09,EN,,0,0,0,,The reason is Dialogue: 0,0:57:20.38,0:57:22.32,EN,,0,0,0,,that if you remember the implementation of NOT, Dialogue: 0,0:57:23.50,0:57:24.84,EN,,0,0,0,,NOT acted as a filter. Dialogue: 0,0:57:25.88,0:57:29.00,EN,,0,0,0,,NOT said I'm going to take some possible dictionaries, Dialogue: 0,0:57:29.05,0:57:31.56,EN,,0,0,0,,some possible frames, some possible answers, Dialogue: 0,0:57:31.79,0:57:33.16,EN,,0,0,0,,and filter out the ones Dialogue: 0,0:57:33.29,0:57:34.94,EN,,0,0,0,,that happened to satisfy some condition, Dialogue: 0,0:57:34.97,0:57:36.11,EN,,0,0,0,,and that's how I implement NOT. Dialogue: 0,0:57:36.92,0:57:38.43,EN,,0,0,0,,If you think about what's going on here, Dialogue: 0,0:57:40.11,0:57:42.65,EN,,0,0,0,,I'll build this query box where the address piece Dialogue: 0,0:57:43.32,0:57:47.39,EN,,0,0,0,,the output of an address piece gets fed into a perfect piece. Dialogue: 0,0:57:50.29,0:57:51.00,EN,,0,0,0,,What will happen is Dialogue: 0,0:57:51.32,0:57:53.26,EN,,0,0,0,,the address piece will set up some things of Dialogue: 0,0:57:53.32,0:57:54.83,EN,,0,0,0,,everyone whose address I know. Dialogue: 0,0:57:55.29,0:57:57.64,EN,,0,0,0,,Those will get filtered by the NOTs inside perfect here. Dialogue: 0,0:57:59.88,0:58:04.19,EN,,0,0,0,,So it will throw out the ones which happened to be either mortal or fallible. Dialogue: 0,0:58:04.91,0:58:06.38,EN,,0,0,0,,In the other order what happens Dialogue: 0,0:58:06.73,0:58:09.12,EN,,0,0,0,,is I set this up, started up with an empty frame. Dialogue: 0,0:58:09.52,0:58:12.35,EN,,0,0,0,,The perfect in here doesn't find anything for the NOTs to filter, Dialogue: 0,0:58:12.38,0:58:13.98,EN,,0,0,0,,so nothing comes out here at all. Dialogue: 0,0:58:18.83,0:58:21.50,EN,,0,0,0,,And there's sort of nothing there that gets fed into the address thing. Dialogue: 0,0:58:21.94,0:58:23.15,EN,,0,0,0,,So here, I don't get an answer. Dialogue: 0,0:58:23.93,0:58:27.04,EN,,0,0,0,,And again, the reason for that is NOT isn't generating anything. Dialogue: 0,0:58:27.44,0:58:28.80,EN,,0,0,0,,NOT's only throwing out things. Dialogue: 0,0:58:29.08,0:58:30.51,EN,,0,0,0,,And if I never started up with anything, Dialogue: 0,0:58:30.52,0:58:31.74,EN,,0,0,0,,there's nothing for it to throw out. Dialogue: 0,0:58:32.02,0:58:33.77,EN,,0,0,0,,So out of this thing, I get the wrong answer. Dialogue: 0,0:58:37.20,0:58:37.97,EN,,0,0,0,,How can you fix that? Dialogue: 0,0:58:37.97,0:58:39.07,EN,,0,0,0,,Well, there are ways to fix that. Dialogue: 0,0:58:39.36,0:58:40.91,EN,,0,0,0,,So you might say, well, that's sort of stupid. Dialogue: 0,0:58:41.41,0:58:44.90,EN,,0,0,0,,Why are you just doing all your NOT stuff at the beginning? Dialogue: 0,0:58:44.96,0:58:47.48,EN,,0,0,0,,The right way to implement NOT is to realize Dialogue: 0,0:58:47.84,0:58:50.08,EN,,0,0,0,,that when you have conditions like NOT, Dialogue: 0,0:58:50.33,0:58:52.09,EN,,0,0,0,,you should generate all your answers first, Dialogue: 0,0:58:52.80,0:58:54.97,EN,,0,0,0,,and then with each of these dictionaries pass along Dialogue: 0,0:58:55.52,0:58:57.85,EN,,0,0,0,,Gee, at the very end I'll do filtering. Dialogue: 0,0:58:58.56,0:59:02.01,EN,,0,0,0,,And there are implementations of logic languages that work like that Dialogue: 0,0:59:02.41,0:59:04.05,EN,,0,0,0,,that solve this particular problem. Dialogue: 0,0:59:06.80,0:59:08.97,EN,,0,0,0,,However, there's a more profound problem, Dialogue: 0,0:59:09.60,0:59:11.53,EN,,0,0,0,,which is which one of these is the right answer? Dialogue: 0,0:59:12.53,0:59:14.24,EN,,0,0,0,,Is it Mount Olympus or is it nothing? Dialogue: 0,0:59:15.37,0:59:18.73,EN,,0,0,0,,So you might say it's Mount Olympus, Dialogue: 0,0:59:18.76,0:59:20.73,EN,,0,0,0,,because after all, Zeus is in that database, Dialogue: 0,0:59:22.52,0:59:25.10,EN,,0,0,0,,and Zeus was neither mortal nor fallible. Dialogue: 0,0:59:29.55,0:59:32.44,EN,,0,0,0,,So you might say Zeus wants to satisfy Dialogue: 0,0:59:34.30,0:59:44.03,EN,,0,0,0,,NOT mortal Zeus or NOT fallible Zeus. Dialogue: 0,0:59:44.12,0:59:45.85,EN,,0,0,0,,But let's actually look at that database. Dialogue: 0,0:59:47.92,0:59:48.46,EN,,0,0,0,,Let's look at it. Dialogue: 0,0:59:49.36,0:59:53.24,EN,,0,0,0,,There's no way-- how does it know that Zeus is not fallible? Dialogue: 0,0:59:54.81,0:59:56.11,EN,,0,0,0,,There's nothing in there about that. Dialogue: 0,0:59:57.93,0:59:59.66,EN,,0,0,0,,What's in there is that humans are fallible. Dialogue: 0,1:00:02.16,1:00:04.12,EN,,0,0,0,,How does it know that Zeus is not mortal? Dialogue: 0,1:00:04.48,1:00:05.93,EN,,0,0,0,,There's nothing in there about that. Dialogue: 0,1:00:07.98,1:00:11.00,EN,,0,0,0,,It just said I don't have any rule, which-- Dialogue: 0,1:00:11.68,1:00:14.06,EN,,0,0,0,,see the only way I can deduce something's mortal is if it's human Dialogue: 0,1:00:14.08,1:00:15.68,EN,,0,0,0,,and that's all it really knows about mortal. Dialogue: 0,1:00:16.69,1:00:19.85,EN,,0,0,0,,And in fact, if you remember your classical mythology, Dialogue: 0,1:00:19.87,1:00:23.48,EN,,0,0,0,,you know that the Greek gods were not mortal but fallible. Dialogue: 0,1:00:25.05,1:00:28.65,EN,,0,0,0,,So the answer is not in the rules there. Dialogue: 0,1:00:30.85,1:00:32.10,EN,,0,0,0,,See, why does it deduce that? Dialogue: 0,1:00:34.49,1:00:38.32,EN,,0,0,0,,See, Socrates would certainly not have made this error of logic. Dialogue: 0,1:00:40.08,1:00:42.67,EN,,0,0,0,,What NOT means in this language is not NOT. Dialogue: 0,1:00:43.37,1:00:44.32,EN,,0,0,0,,It's not the NOT of logic. Dialogue: 0,1:00:44.93,1:00:46.40,EN,,0,0,0,,What NOT needs in this language is Dialogue: 0,1:00:47.16,1:00:49.96,EN,,0,0,0,,not deducible from things in the database Dialogue: 0,1:00:50.75,1:00:53.34,EN,,0,0,0,,as opposed to not true. Dialogue: 0,1:00:55.02,1:00:56.30,EN,,0,0,0,,That's a very big difference. Dialogue: 0,1:00:57.30,1:00:58.64,EN,,0,0,0,,Subtle, but big. Dialogue: 0,1:00:59.25,1:01:00.27,EN,,0,0,0,,So, in fact, Dialogue: 0,1:01:00.76,1:01:03.92,EN,,0,0,0,,this is perfectly happy to say not anything that it doesn't know about. Dialogue: 0,1:01:04.68,1:01:06.14,EN,,0,0,0,,So if you ask it is it not true Dialogue: 0,1:01:06.16,1:01:07.83,EN,,0,0,0,,that Zeus likes chocolate ice cream? Dialogue: 0,1:01:07.85,1:01:09.12,EN,,0,0,0,,It will say sure, it's not true. Dialogue: 0,1:01:10.64,1:01:12.51,EN,,0,0,0,,Or anything else or anything it doesn't know about. Dialogue: 0,1:01:12.59,1:01:17.34,EN,,0,0,0,,NOT means not deducible from the things you've told me. Dialogue: 0,1:01:18.28,1:01:22.44,EN,,0,0,0,,In a world where you're identifying not deducible Dialogue: 0,1:01:22.65,1:01:24.00,EN,,0,0,0,,with, in fact, not true, Dialogue: 0,1:01:24.41,1:01:26.30,EN,,0,0,0,,this is called the closed world assumption. Dialogue: 0,1:01:37.37,1:01:38.17,EN,,0,0,0,,closed world assumption. Dialogue: 0,1:01:38.20,1:01:42.38,EN,,0,0,0,,Anything that I cannot deduce from what I know Dialogue: 0,1:01:43.50,1:01:44.36,EN,,0,0,0,,is not true, Dialogue: 0,1:01:46.24,1:01:48.01,EN,,0,0,0,,Right? If I don't know anything about x, Dialogue: 0,1:01:48.22,1:01:49.21,EN,,0,0,0,,the x isn't true. Dialogue: 0,1:01:49.29,1:01:50.33,EN,,0,0,0,,That's very dangerous. Dialogue: 0,1:01:51.29,1:01:52.44,EN,,0,0,0,,From a logical point of view, Dialogue: 0,1:01:52.46,1:01:53.76,EN,,0,0,0,,first of all, it doesn't really makes sense. Dialogue: 0,1:01:54.48,1:01:56.33,EN,,0,0,0,,Because if I don't know anything about x, Dialogue: 0,1:01:58.38,1:01:59.69,EN,,0,0,0,,I'm willing to say not x. Dialogue: 0,1:02:00.24,1:02:03.32,EN,,0,0,0,,But am I willing to say not not x? Dialogue: 0,1:02:03.85,1:02:05.66,EN,,0,0,0,,Well, sure, I don't know anything about that either maybe. Dialogue: 0,1:02:06.47,1:02:08.65,EN,,0,0,0,,So not not x is not necessarily the same as x Dialogue: 0,1:02:09.24,1:02:10.94,EN,,0,0,0,,and so on and so on and so on, so Dialogue: 0,1:02:11.71,1:02:13.93,EN,,0,0,0,,there's some sort of funny bias in there. Dialogue: 0,1:02:15.97,1:02:17.29,EN,,0,0,0,,So that's sort of funny. Dialogue: 0,1:02:17.29,1:02:18.09,EN,,0,0,0,,The second thing, Dialogue: 0,1:02:20.14,1:02:24.12,EN,,0,0,0,,if you start building up real reasoning programs based on this, Dialogue: 0,1:02:24.70,1:02:26.11,EN,,0,0,0,,think how dangerous that is. Dialogue: 0,1:02:27.07,1:02:32.00,EN,,0,0,0,,You're saying I know I'm in a position Dialogue: 0,1:02:32.22,1:02:36.22,EN,,0,0,0,,to deduce everything true that's relevant to this problem. Dialogue: 0,1:02:37.44,1:02:40.78,EN,,0,0,0,,I'm reasoning, and built into my reasoning mechanism Dialogue: 0,1:02:41.23,1:02:44.20,EN,,0,0,0,,is the assumption that anything that I don't know Dialogue: 0,1:02:44.24,1:02:46.27,EN,,0,0,0,,can't possibly be relevant to this problem. Dialogue: 0,1:02:48.44,1:02:53.04,EN,,0,0,0,,Right? There are a lot of big organizations that work like that, right? Dialogue: 0,1:02:53.16,1:02:56.83,EN,,0,0,0,,Most corporate marketing divisions work like that. Dialogue: 0,1:02:56.83,1:02:59.12,EN,,0,0,0,,You know the consequences to that. Dialogue: 0,1:03:00.33,1:03:03.45,EN,,0,0,0,,So it's very dangerous to start really Dialogue: 0,1:03:03.84,1:03:06.25,EN,,0,0,0,,typing in these big logical implication systems Dialogue: 0,1:03:07.05,1:03:09.00,EN,,0,0,0,,and going on what they say, Dialogue: 0,1:03:09.02,1:03:11.28,EN,,0,0,0,,because they have this really limiting assumption built in. Dialogue: 0,1:03:12.60,1:03:14.36,EN,,0,0,0,,So you have to be very, very careful about that. Dialogue: 0,1:03:15.29,1:03:16.28,EN,,0,0,0,,And that's a deep problem. Dialogue: 0,1:03:16.56,1:03:17.82,EN,,0,0,0,,That's not a problem about Dialogue: 0,1:03:18.22,1:03:20.14,EN,,0,0,0,,we can make a little bit cleverer implementation Dialogue: 0,1:03:20.16,1:03:21.85,EN,,0,0,0,,and do the filters and organize the Dialogue: 0,1:03:22.16,1:03:23.84,EN,,0,0,0,,the infinite loops to make them go away. Dialogue: 0,1:03:23.84,1:03:25.08,EN,,0,0,0,,It's a different kind of problem. Dialogue: 0,1:03:25.92,1:03:26.89,EN,,0,0,0,,It's a different semantics. Dialogue: 0,1:03:27.06,1:03:30.51,EN,,0,0,0,,So I think to wrap this up, it's fair to say Dialogue: 0,1:03:31.34,1:03:34.43,EN,,0,0,0,,that logic programming I think is a terrifically exciting idea, Dialogue: 0,1:03:34.60,1:03:37.00,EN,,0,0,0,,the idea that you can bridge this Dialogue: 0,1:03:37.04,1:03:38.78,EN,,0,0,0,,gap from the imperative to the declarative, Dialogue: 0,1:03:39.90,1:03:42.94,EN,,0,0,0,,that you can start talking about relations Dialogue: 0,1:03:43.58,1:03:45.08,EN,,0,0,0,,and really get tremendous power Dialogue: 0,1:03:46.09,1:03:49.48,EN,,0,0,0,,by going above the abstraction of what's my input and what's my output. Dialogue: 0,1:03:50.56,1:03:51.53,EN,,0,0,0,,And linked to logic, Dialogue: 0,1:03:52.46,1:03:56.46,EN,,0,0,0,,the problem is it's a goal that I think has yet to be realized. Dialogue: 0,1:03:58.03,1:04:01.80,EN,,0,0,0,,And probably one of the very most interesting Dialogue: 0,1:04:02.27,1:04:04.41,EN,,0,0,0,,research questions going on now in languages Dialogue: 0,1:04:04.67,1:04:08.28,EN,,0,0,0,,is how do you somehow make a real logic language? Dialogue: 0,1:04:09.46,1:04:11.05,EN,,0,0,0,,And secondly, how do you bridge the gap Dialogue: 0,1:04:11.31,1:04:13.15,EN,,0,0,0,,this world of logic and relations Dialogue: 0,1:04:13.52,1:04:16.43,EN,,0,0,0,,to the worlds of more traditional languages Dialogue: 0,1:04:16.46,1:04:17.98,EN,,0,0,0,,and somehow combine the power of both. Dialogue: 0,1:04:18.88,1:04:19.68,EN,,0,0,0,,OK, let's break. Dialogue: 0,1:04:23.29,1:04:25.29,EN,,0,0,0,,AUDIENCE: Couldn't you solve that last problem Dialogue: 0,1:04:25.29,1:04:27.74,EN,,0,0,0,,by having the extra rules that imply it? Dialogue: 0,1:04:27.96,1:04:29.85,EN,,0,0,0,,The problem here is you have the definition of something, Dialogue: 0,1:04:29.88,1:04:31.82,EN,,0,0,0,,but you don't have the definition of its opposite. Dialogue: 0,1:04:32.08,1:04:33.92,EN,,0,0,0,,If you include in the database something that says Dialogue: 0,1:04:34.14,1:04:36.89,EN,,0,0,0,,uh... something implies mortal x, Dialogue: 0,1:04:36.99,1:04:38.70,EN,,0,0,0,,something else implies not mortal x, Dialogue: 0,1:04:38.75,1:04:40.37,EN,,0,0,0,,haven't you basically solved the problem? Dialogue: 0,1:04:43.37,1:04:44.14,EN,,0,0,0,,PROFESSOR: But the issue is Dialogue: 0,1:04:44.75,1:04:46.38,EN,,0,0,0,,do you put a finite number of those in? Dialogue: 0,1:04:48.65,1:04:53.13,EN,,0,0,0,,AUDIENCE: If things are specified always in pairs-- Dialogue: 0,1:04:53.61,1:04:57.07,EN,,0,0,0,,PROFESSOR: But the question is then what do you do about deduction? Dialogue: 0,1:05:00.20,1:05:02.11,EN,,0,0,0,,See, you can't specify NOTs. Dialogue: 0,1:05:03.40,1:05:04.76,EN,,0,0,0,,But the problem is, in a big system, Dialogue: 0,1:05:04.78,1:05:07.96,EN,,0,0,0,,it turns out that might not be a finite number of things. Dialogue: 0,1:05:12.82,1:05:15.29,EN,,0,0,0,,There are also sort of two issues. Dialogue: 0,1:05:15.29,1:05:16.56,EN,,0,0,0,,Partly it might not be finite. Dialogue: 0,1:05:16.69,1:05:19.39,EN,,0,0,0,,Partly it might be that's not what you want. Dialogue: 0,1:05:21.51,1:05:24.52,EN,,0,0,0,,So a good example would be suppose I want to do connectivity. Dialogue: 0,1:05:25.12,1:05:26.54,EN,,0,0,0,,I want a reason about connectivity. Dialogue: 0,1:05:28.05,1:05:30.38,EN,,0,0,0,,And I'm going to tell you there's four things: Dialogue: 0,1:05:30.40,1:05:33.74,EN,,0,0,0,,a and b and c and d. Dialogue: 0,1:05:35.48,1:05:38.19,EN,,0,0,0,,And I'll tell you a is connected to b Dialogue: 0,1:05:38.64,1:05:41.42,EN,,0,0,0,,and c's connected to d. Dialogue: 0,1:05:43.20,1:05:44.80,EN,,0,0,0,,And now I'll tell you is a connected to d? Dialogue: 0,1:05:45.05,1:05:46.03,EN,,0,0,0,,That's the question. Dialogue: 0,1:05:46.78,1:05:48.52,EN,,0,0,0,,There's an example where I would like Dialogue: 0,1:05:48.70,1:05:50.35,EN,,0,0,0,,something like the closed world assumption. Dialogue: 0,1:05:54.43,1:05:55.66,EN,,0,0,0,,That's a tiny toy, Dialogue: 0,1:05:56.24,1:05:58.30,EN,,0,0,0,,but a lot of times, I want to be able to say something like Dialogue: 0,1:05:58.48,1:06:01.34,EN,,0,0,0,,anything that I haven't told you, assume is not true. Dialogue: 0,1:06:04.26,1:06:06.27,EN,,0,0,0,,So it's not as simple as you only want to put in Dialogue: 0,1:06:06.27,1:06:08.09,EN,,0,0,0,,explicit NOTs all over the place. Dialogue: 0,1:06:09.47,1:06:12.70,EN,,0,0,0,,It's that sometimes it really isn't clear what you even want. Dialogue: 0,1:06:14.15,1:06:17.92,EN,,0,0,0,,That having to specify both everything and not everything is too precise, Dialogue: 0,1:06:17.93,1:06:20.00,EN,,0,0,0,,and then you get down into problems there. Dialogue: 0,1:06:20.96,1:06:22.68,EN,,0,0,0,,But there are a lot of approaches that Dialogue: 0,1:06:23.32,1:06:25.93,EN,,0,0,0,,you know, that explicitly put in NOTs and reason based on that. Dialogue: 0,1:06:26.51,1:06:27.66,EN,,0,0,0,,So it's a very good idea. Dialogue: 0,1:06:28.07,1:06:31.45,EN,,0,0,0,,It's just that then it starts becoming a little cumbersome Dialogue: 0,1:06:31.48,1:06:33.49,EN,,0,0,0,,in the very large problems you'd like to use. Dialogue: 0,1:06:43.46,1:06:45.96,EN,,0,0,0,,AUDIENCE: I'm not sure how directly related to the argument this is, Dialogue: 0,1:06:46.00,1:06:47.98,EN,,0,0,0,,but one of your points was that Dialogue: 0,1:06:48.49,1:06:50.16,EN,,0,0,0,,one of the dangers of the closed world rule is Dialogue: 0,1:06:50.19,1:06:52.06,EN,,0,0,0,,you never really know all the things that are there. Dialogue: 0,1:06:53.44,1:06:55.32,EN,,0,0,0,,You never really know all the parts to it. Dialogue: 0,1:06:55.87,1:06:58.16,EN,,0,0,0,,Isn't that a major problem with any programming? Dialogue: 0,1:06:58.16,1:06:59.64,EN,,0,0,0,,I always write programs where I Dialogue: 0,1:06:59.90,1:07:01.56,EN,,0,0,0,,I assume that I've got all the cases, Dialogue: 0,1:07:01.58,1:07:03.40,EN,,0,0,0,,and so I check for them all or whatever, and i Dialogue: 0,1:07:04.06,1:07:04.99,EN,,0,0,0,,and somewhere down the road, I Dialogue: 0,1:07:05.02,1:07:06.52,EN,,0,0,0,,I find out that I didn't check for one of them. Dialogue: 0,1:07:07.39,1:07:08.54,EN,,0,0,0,,PROFESSOR: Well, sure, it's true. Dialogue: 0,1:07:08.54,1:07:09.76,EN,,0,0,0,,But the problem here is Dialogue: 0,1:07:11.96,1:07:15.47,EN,,0,0,0,,it's that assumption which is the thing that you're making Dialogue: 0,1:07:15.48,1:07:17.34,EN,,0,0,0,,if you believe you're identifying this with logic. Dialogue: 0,1:07:19.60,1:07:20.51,EN,,0,0,0,,So you're quite right. Dialogue: 0,1:07:20.51,1:07:22.22,EN,,0,0,0,,It's a situation you're never in. Dialogue: 0,1:07:22.22,1:07:24.14,EN,,0,0,0,,The problem is if you're starting to believe that Dialogue: 0,1:07:24.17,1:07:25.44,EN,,0,0,0,,what this is doing is logic Dialogue: 0,1:07:26.17,1:07:27.32,EN,,0,0,0,,and you look at the rules you write down Dialogue: 0,1:07:27.34,1:07:28.89,EN,,0,0,0,,and say what can I deduce from them, Dialogue: 0,1:07:29.53,1:07:32.80,EN,,0,0,0,,you have to be very careful to remember that NOT means something else. Dialogue: 0,1:07:33.47,1:07:35.21,EN,,0,0,0,,And it means something else based on an assumption Dialogue: 0,1:07:35.24,1:07:36.70,EN,,0,0,0,,which is probably not true. Dialogue: 0,1:07:39.03,1:07:40.19,EN,,0,0,0,,AUDIENCE: Do I understand you correctly that Dialogue: 0,1:07:40.25,1:07:41.84,EN,,0,0,0,,you cannot fix this problem Dialogue: 0,1:07:42.25,1:07:46.08,EN,,0,0,0,,without killing off all possibilities of inference through altering NOT? Dialogue: 0,1:07:46.54,1:07:49.80,EN,,0,0,0,,PROFESSOR: No, that's not quite right. Dialogue: 0,1:07:52.96,1:07:55.08,EN,,0,0,0,,There are ways to do logic with real NOTs. Dialogue: 0,1:07:56.34,1:07:58.03,EN,,0,0,0,,There are actually ways to do that. Dialogue: 0,1:07:58.54,1:08:00.84,EN,,0,0,0,,But they're very inefficient as far as anybody knows. Dialogue: 0,1:08:01.61,1:08:02.56,EN,,0,0,0,,And they're much more-- Dialogue: 0,1:08:04.09,1:08:06.89,EN,,0,0,0,,they don't-- the, quote, inference in here Dialogue: 0,1:08:07.39,1:08:08.83,EN,,0,0,0,,is built into this unifier Dialogue: 0,1:08:08.91,1:08:11.29,EN,,0,0,0,,and this pattern matching unification algorithm. Dialogue: 0,1:08:11.98,1:08:16.19,EN,,0,0,0,,There are ways to automate real logical reasoning. Dialogue: 0,1:08:16.59,1:08:18.19,EN,,0,0,0,,But it's not based on that, Dialogue: 0,1:08:18.51,1:08:20.73,EN,,0,0,0,,and logic programming languages don't tend to do that Dialogue: 0,1:08:20.75,1:08:23.85,EN,,0,0,0,,because it's very inefficient as far as anybody knows. Dialogue: 0,1:08:29.39,1:08:30.03,EN,,0,0,0,,All right, thank you. Dialogue: 0,0:00:00.00,0:00:02.14,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP 学习小组\N倾情制作 Dialogue: 0,0:00:02.40,0:00:09.84,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:02.40,0:00:09.84,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.40,0:00:09.84,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.40,0:00:09.84,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.40,0:00:09.84,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:09.90,0:00:16.04,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 II Dialogue: 0,0:00:18.91,0:00:21.79,Default,,0,0,0,,我们已经了解了查询语言的使用方式 Dialogue: 0,0:00:22.64,0:00:25.07,Default,,0,0,0,,现在该来讨论如何实现了 Dialogue: 0,0:00:26.28,0:00:27.98,Default,,0,0,0,,你们也应该能够猜到 Dialogue: 0,0:00:28.59,0:00:29.47,Default,,0,0,0,,它其中的原理了 Dialogue: 0,0:00:29.47,0:00:31.64,Default,,0,0,0,,它的最底层是一个模式匹配器 Dialogue: 0,0:00:32.81,0:00:34.25,Default,,0,0,0,,我们在《基于规则的控制语言》一课中 Dialogue: 0,0:00:34.67,0:00:36.94,Default,,0,0,0,,已经介绍过模式匹配器了 Dialogue: 0,0:00:38.11,0:00:40.59,Default,,0,0,0,,我举个例子来让你们温习一下 Dialogue: 0,0:00:41.52,0:00:43.68,Default,,0,0,0,,这个模式会匹配 Dialogue: 0,0:00:43.80,0:00:44.92,Default,,0,0,0,,一个含有三个元素的表 Dialogue: 0,0:00:44.96,0:00:47.10,Default,,0,0,0,,其中 首元素为A Dialogue: 0,0:00:47.16,0:00:48.33,Default,,0,0,0,,其次是C Dialogue: 0,0:00:48.48,0:00:50.19,Default,,0,0,0,,而中间可以为任意元素 Dialogue: 0,0:00:50.65,0:00:52.27,Default,,0,0,0,,所以在这个小型的模式匹配语言中 Dialogue: 0,0:00:52.30,0:00:54.05,Default,,0,0,0,,你只能区分一种类型 Dialogue: 0,0:00:54.05,0:00:57.20,Default,,0,0,0,,也就是区分字面量或者变量 Dialogue: 0,0:00:57.23,0:00:58.86,Default,,0,0,0,,以问号开头的就是变量 Dialogue: 0,0:01:01.37,0:01:03.64,Default,,0,0,0,,因此这个模式会匹配任意的三元表 Dialogue: 0,0:01:04.44,0:01:06.50,Default,,0,0,0,,只要它的首元素为A 而第三个元素为C Dialogue: 0,0:01:06.50,0:01:09.00,Default,,0,0,0,,而这个模式匹配的三元表 Dialogue: 0,0:01:10.43,0:01:12.53,Default,,0,0,0,,它的首元素必须是符号'JOB Dialogue: 0,0:01:12.53,0:01:13.90,Default,,0,0,0,,第二个元素为任意值 Dialogue: 0,0:01:14.21,0:01:15.90,Default,,0,0,0,,第三个元素必须是一个二元表 Dialogue: 0,0:01:15.95,0:01:17.72,Default,,0,0,0,,二元表的首元素为符号'COMPUTER Dialogue: 0,0:01:17.88,0:01:19.42,Default,,0,0,0,,第二个元素可以为任意值 Dialogue: 0,0:01:20.48,0:01:25.55,Default,,0,0,0,,而下一条模式所匹配的三元表 Dialogue: 0,0:01:25.87,0:01:26.99,Default,,0,0,0,,区别就在于 Dialogue: 0,0:01:28.40,0:01:31.32,Default,,0,0,0,,在于第三个元素的首元素必须为符号'COMPUTER Dialogue: 0,0:01:31.76,0:01:33.29,Default,,0,0,0,,表剩余部分可以是任意值 Dialogue: 0,0:01:35.04,0:01:37.53,Default,,0,0,0,,也就是说 上面是二元表 而下面没有限定数目 Dialogue: 0,0:01:37.86,0:01:39.74,Default,,0,0,0,,然而我们的语言实现 Dialogue: 0,0:01:39.85,0:01:42.06,Default,,0,0,0,,根本不用操心如何去实现这个点号 Dialogue: 0,0:01:42.11,0:01:44.17,Default,,0,0,0,,因为这个由Lisp读取器自动地完成 Dialogue: 0,0:01:48.34,0:01:50.31,Default,,0,0,0,,要注意 匹配器还要保持一致性 Dialogue: 0,0:01:50.31,0:01:52.32,Default,,0,0,0,,这个模式匹配一个三元表 Dialogue: 0,0:01:52.59,0:01:53.98,Default,,0,0,0,,表的首元素是A Dialogue: 0,0:01:54.43,0:01:55.79,Default,,0,0,0,,而第二个元素和第三个元素可以是任意值 Dialogue: 0,0:01:55.80,0:01:57.08,Default,,0,0,0,,但它们必须是相同的 Dialogue: 0,0:01:57.94,0:01:58.84,Default,,0,0,0,,它们都是?X Dialogue: 0,0:01:59.60,0:02:01.55,Default,,0,0,0,,而这个模式匹配一个四元表 Dialogue: 0,0:02:01.96,0:02:03.26,Default,,0,0,0,,其中第一个元素与第四个元素相同 Dialogue: 0,0:02:03.66,0:02:05.15,Default,,0,0,0,,而第二个元素与第三个元素相同 Dialogue: 0,0:02:05.59,0:02:08.60,Default,,0,0,0,,最后一个模式匹配以A开头的任意表 Dialogue: 0,0:02:09.68,0:02:11.05,Default,,0,0,0,,以A开头 Dialogue: 0,0:02:11.23,0:02:12.56,Default,,0,0,0,,余下的可以是任意值 Dialogue: 0,0:02:14.04,0:02:16.60,Default,,0,0,0,,这是对我们已经学习过的模式匹配语言 Dialogue: 0,0:02:16.62,0:02:17.87,Default,,0,0,0,,的一个回顾 Dialogue: 0,0:02:18.78,0:02:19.64,Default,,0,0,0,,还记得吗 Dialogue: 0,0:02:19.79,0:02:22.28,Default,,0,0,0,,这是由一个叫做MATCH的过程实现的 Dialogue: 0,0:02:24.87,0:02:36.06,Default,,0,0,0,,MATCH有三个参数:PAT、DATA以及DICTIONARY Dialogue: 0,0:02:43.20,0:02:47.12,Default,,0,0,0,,MATCH考虑的是 Dialogue: 0,0:02:47.79,0:02:52.64,Default,,0,0,0,,利用给定DICTIONAY中的绑定 Dialogue: 0,0:02:53.55,0:02:56.73,Default,,0,0,0,,能够找到一种方法把模式与数据对象匹配起来吗? Dialogue: 0,0:02:58.16,0:02:59.21,Default,,0,0,0,,比如说 Dialogue: 0,0:02:59.56,0:03:06.43,Default,,0,0,0,,如果我们想要把模式(?X ?Y ?Y ?X) Dialogue: 0,0:03:07.71,0:03:13.84,Default,,0,0,0,,与数据对象(A B B A)相匹配 Dialogue: 0,0:03:15.12,0:03:20.52,Default,,0,0,0,,又给定了一个字典 X=A Dialogue: 0,0:03:22.01,0:03:25.23,Default,,0,0,0,,MATCH就会说:“它们是一致的” Dialogue: 0,0:03:25.26,0:03:27.16,Default,,0,0,0,,再给定的字典说 X=A 的情况下 Dialogue: 0,0:03:27.80,0:03:30.20,Default,,0,0,0,,模式与数据相匹配 Dialogue: 0,0:03:30.32,0:03:31.60,Default,,0,0,0,,而匹配的结果则是 Dialogue: 0,0:03:32.25,0:03:34.30,Default,,0,0,0,,一个扩展了的词典 Dialogue: 0,0:03:34.46,0:03:37.60,Default,,0,0,0,,其中包含 X=A Y=B Dialogue: 0,0:03:39.49,0:03:42.24,Default,,0,0,0,,MATCH接收模式、数据以及字典 Dialogue: 0,0:03:42.38,0:03:44.54,Default,,0,0,0,,如果成功匹配就输出一个扩展后的词典 Dialogue: 0,0:03:44.97,0:03:46.84,Default,,0,0,0,,否则就报错 Dialogue: 0,0:03:46.84,0:03:47.71,Default,,0,0,0,,因此 比如说 Dialogue: 0,0:03:47.88,0:03:50.38,Default,,0,0,0,,如果我在这里使用同样的模式 Dialogue: 0,0:03:50.97,0:03:55.12,Default,,0,0,0,,如果我用模式(?X ?Y ?Y ?X) Dialogue: 0,0:03:55.66,0:03:58.49,Default,,0,0,0,,去匹配(A B B A) Dialogue: 0,0:03:59.47,0:04:02.84,Default,,0,0,0,,并给定词典 Y=A Dialogue: 0,0:04:05.15,0:04:06.81,Default,,0,0,0,,那么MATCH就会输出FAIL Dialogue: 0,0:04:12.52,0:04:14.65,Default,,0,0,0,,你们已经见过模式匹配器的代码了 Dialogue: 0,0:04:15.00,0:04:16.17,Default,,0,0,0,,我就不会再去细讲 Dialogue: 0,0:04:16.64,0:04:19.77,Default,,0,0,0,,这跟我们以前做的类似 Dialogue: 0,0:04:21.19,0:04:23.22,Default,,0,0,0,,我们在《基于规则的系统》中已经见过了 Dialogue: 0,0:04:23.22,0:04:24.56,Default,,0,0,0,,基本上是同样的匹配器 Dialogue: 0,0:04:24.95,0:04:27.66,Default,,0,0,0,,实际上 我认为这里的语法还更简单一点 Dialogue: 0,0:04:28.16,0:04:29.31,Default,,0,0,0,,因为我们不用去关心 Dialogue: 0,0:04:29.40,0:04:31.40,Default,,0,0,0,,任意变量、任意表达式之类的东西 Dialogue: 0,0:04:31.40,0:04:32.88,Default,,0,0,0,,这里面只区分变量和常量 Dialogue: 0,0:04:35.79,0:04:37.32,Default,,0,0,0,,那么 有了模式匹配器以后 Dialogue: 0,0:04:38.46,0:04:39.61,Default,,0,0,0,,基本查询又是怎么样的呢? Dialogue: 0,0:04:42.97,0:04:45.34,Default,,0,0,0,,基本查询将会是一个相当复杂的东西 Dialogue: 0,0:04:46.67,0:05:03.58,Default,,0,0,0,,就拿查询(JOB ?X (?D . ?Y))来说 Dialogue: 0,0:05:07.04,0:05:08.73,Default,,0,0,0,,我们可能会输入这样的查询 Dialogue: 0,0:05:09.40,0:05:11.39,Default,,0,0,0,,这又将如何在系统内实现呢? Dialogue: 0,0:05:14.14,0:05:15.66,Default,,0,0,0,,我们可以把它想做这个小盒子 Dialogue: 0,0:05:15.70,0:05:16.80,Default,,0,0,0,,这是一条基本查询 Dialogue: 0,0:05:18.88,0:05:20.30,Default,,0,0,0,,这个小盒子将会 Dialogue: 0,0:05:22.24,0:05:27.28,Default,,0,0,0,,以两条流作为输入 Dialogue: 0,0:05:31.96,0:05:33.20,Default,,0,0,0,,并输出一条流 Dialogue: 0,0:05:34.03,0:05:36.19,Default,,0,0,0,,因此一条基本查询的形状 Dialogue: 0,0:05:36.51,0:05:38.46,Default,,0,0,0,,就将是有两条输入流 Dialogue: 0,0:05:38.67,0:05:39.96,Default,,0,0,0,,和一条输出流 Dialogue: 0,0:05:41.12,0:05:46.20,Default,,0,0,0,,而这些流 来自于这里的数据库 Dialogue: 0,0:05:51.95,0:05:53.93,Default,,0,0,0,,因此我们把数据库中的所有数据 Dialogue: 0,0:05:55.93,0:05:57.20,Default,,0,0,0,,想象成一条流 Dialogue: 0,0:05:57.31,0:05:58.40,Default,,0,0,0,,而这个盒子不断地吸取 Dialogue: 0,0:06:00.36,0:06:02.43,Default,,0,0,0,,那么 数据库中有什么呢? Dialogue: 0,0:06:08.43,0:06:20.32,Default,,0,0,0,,首先是(JOB (ALYSSA ...)) Dialogue: 0,0:06:21.96,0:06:23.71,Default,,0,0,0,,以及还有其它的JOB数据 Dialogue: 0,0:06:25.77,0:06:30.41,Default,,0,0,0,,想象一下 数据库中的所有事实都在这条流中 Dialogue: 0,0:06:32.04,0:06:33.10,Default,,0,0,0,,都到了这里 Dialogue: 0,0:06:33.36,0:06:34.52,Default,,0,0,0,,而这条流送来的 Dialogue: 0,0:06:34.89,0:06:36.52,Default,,0,0,0,,是一些字典 Dialogue: 0,0:06:38.51,0:06:41.40,Default,,0,0,0,,其中一个就可能是 Dialogue: 0,0:06:46.70,0:06:49.31,Default,,0,0,0,,Y=PROG Dialogue: 0,0:06:55.47,0:06:56.64,Default,,0,0,0,,现在 查询工作就是要 Dialogue: 0,0:06:57.07,0:06:59.80,Default,,0,0,0,,当它从这条流中取得一个字典后 Dialogue: 0,0:07:02.01,0:07:06.67,Default,,0,0,0,,它会搜寻数据库中的东西 Dialogue: 0,0:07:07.45,0:07:10.24,Default,,0,0,0,,来尽可能产生所有匹配结果 Dialogue: 0,0:07:11.39,0:07:12.89,Default,,0,0,0,,它把查询视作一种模式 Dialogue: 0,0:07:13.15,0:07:16.72,Default,,0,0,0,,并将它们与数据库中的事实匹配起来 Dialogue: 0,0:07:16.96,0:07:21.98,Default,,0,0,0,,结合着相应的字典中的数据 Dialogue: 0,0:07:22.94,0:07:25.68,Default,,0,0,0,,找到数据库中所有匹配的结果 Dialogue: 0,0:07:27.55,0:07:29.69,Default,,0,0,0,,所以针对数据库中的每条事实 Dialogue: 0,0:07:29.72,0:07:34.35,Default,,0,0,0,,它都会调用(MATCH PAT FACT DICTIONAY)来检查 Dialogue: 0,0:07:35.11,0:07:37.68,Default,,0,0,0,,如果成功匹配 Dialogue: 0,0:07:38.19,0:07:39.93,Default,,0,0,0,,它就输出一个扩展了的字典 Dialogue: 0,0:07:40.67,0:07:42.32,Default,,0,0,0,,比如说 这里进来了一本字典 Dialogue: 0,0:07:43.00,0:07:44.09,Default,,0,0,0,,并且成功匹配 Dialogue: 0,0:07:44.51,0:07:45.87,Default,,0,0,0,,那么就会输出一本字典 Dialogue: 0,0:07:46.81,0:07:49.79,Default,,0,0,0,,本例中就是Y=PROG Dialogue: 0,0:07:51.52,0:07:52.97,Default,,0,0,0,,X=... Dialogue: 0,0:07:56.54,0:07:58.75,Default,,0,0,0,,Y=PROG X=... Dialogue: 0,0:07:58.96,0:08:00.54,Default,,0,0,0,,D又是一个新的项 Dialogue: 0,0:08:01.72,0:08:02.27,Default,,0,0,0,,像这样扩展 Dialogue: 0,0:08:03.52,0:08:07.82,Default,,0,0,0,,当然 它会针对数据库中的所有事实做同样的尝试 Dialogue: 0,0:08:07.98,0:08:09.25,Default,,0,0,0,,所以就可能有很多的结果 Dialogue: 0,0:08:09.56,0:08:10.59,Default,,0,0,0,,可能会产生另一本字典 Dialogue: 0,0:08:11.28,0:08:17.12,Default,,0,0,0,,其中 Y=PROG X=... D=... Dialogue: 0,0:08:19.18,0:08:21.55,Default,,0,0,0,,因此 对于每个输入的框架 Dialogue: 0,0:08:21.76,0:08:23.69,Default,,0,0,0,,对于每输入一本字典 Dialogue: 0,0:08:23.72,0:08:25.24,Default,,0,0,0,,它可能输出很多本字典 Dialogue: 0,0:08:26.54,0:08:28.67,Default,,0,0,0,,或者什么也不输出 Dialogue: 0,0:08:30.47,0:08:38.48,Default,,0,0,0,,可能会有一些不匹配的情况 比如X=FOO Dialogue: 0,0:08:39.02,0:08:40.89,Default,,0,0,0,,这个条目不会匹配任何东西 Dialogue: 0,0:08:41.52,0:08:45.12,Default,,0,0,0,,就这个框架来说 不会向输出流中输出东西 Dialogue: 0,0:08:47.51,0:08:51.28,Default,,0,0,0,,或者你也可以输入一个空框架 Dialogue: 0,0:08:52.91,0:08:56.24,Default,,0,0,0,,空框架是用来 Dialogue: 0,0:08:59.87,0:09:02.33,Default,,0,0,0,,在没有任何约束的情况下 Dialogue: 0,0:09:02.57,0:09:06.14,Default,,0,0,0,,匹配数据库中所有可能的结果 Dialogue: 0,0:09:07.57,0:09:09.16,Default,,0,0,0,,这仅仅代表着 Dialogue: 0,0:09:10.32,0:09:13.87,Default,,0,0,0,,处理你输入的查询 最初所进行的计算 Dialogue: 0,0:09:14.20,0:09:15.56,Default,,0,0,0,,它试图找出所有的匹配 Dialogue: 0,0:09:16.65,0:09:18.83,Default,,0,0,0,,基本查询建立了这种机制 Dialogue: 0,0:09:19.37,0:09:20.57,Default,,0,0,0,,而语言要做的是 Dialogue: 0,0:09:22.75,0:09:24.67,Default,,0,0,0,,当你在顶层输入这条查询时 Dialogue: 0,0:09:24.84,0:09:26.14,Default,,0,0,0,,它基于这种机制 Dialogue: 0,0:09:26.16,0:09:28.35,Default,,0,0,0,,它会输入一本空的字典 Dialogue: 0,0:09:30.86,0:09:32.56,Default,,0,0,0,,而对于输出的每个东西 Dialogue: 0,0:09:33.08,0:09:35.88,Default,,0,0,0,,然后把最初的查询 Dialogue: 0,0:09:36.56,0:09:40.44,Default,,0,0,0,,用不同的字典来实例化 Dialogue: 0,0:09:40.81,0:09:44.36,Default,,0,0,0,,于是实例化后的模式就形成了一条新的流 Dialogue: 0,0:09:44.99,0:09:46.51,Default,,0,0,0,,这就是在终端上打印出来的内容 Dialogue: 0,0:09:48.17,0:09:51.24,Default,,0,0,0,,这也就是其中的基本原理 Dialogue: 0,0:09:53.51,0:09:55.48,Default,,0,0,0,,那么 这又为什么复杂呢? Dialogue: 0,0:09:57.71,0:10:01.00,Default,,0,0,0,,除了使用这种基于流的方法 Dialogue: 0,0:10:01.37,0:10:04.25,Default,,0,0,0,,你们可以想出很多更简单的方法来组织基本查询 Dialogue: 0,0:10:05.18,0:10:06.09,Default,,0,0,0,,而答案就在于 Dialogue: 0,0:10:07.15,0:10:08.51,Default,,0,0,0,,你们可能已经在想了 Dialogue: 0,0:10:10.86,0:10:14.09,Default,,0,0,0,,答案就是 这种方法能够优雅地 Dialogue: 0,0:10:14.56,0:10:16.76,Default,,0,0,0,,实现组合手段 Dialogue: 0,0:10:17.79,0:10:18.80,Default,,0,0,0,,比如说 Dialogue: 0,0:10:20.65,0:10:22.47,Default,,0,0,0,,假设我还想实现其它的效果 Dialogue: 0,0:10:22.47,0:10:26.96,Default,,0,0,0,,我不只是想查询所有人的工作信息 Dialogue: 0,0:10:27.23,0:10:28.35,Default,,0,0,0,,假设我还想查询 Dialogue: 0,0:10:29.47,0:10:35.92,Default,,0,0,0,,(AND (JOB ?X (?D . ?Y)) Dialogue: 0,0:10:36.80,0:10:47.04,Default,,0,0,0,,(SUPERVIOSR ?X ?Z)) Dialogue: 0,0:10:48.80,0:10:50.67,Default,,0,0,0,,(SUPERVISOR ?X ?Z)这条查询 Dialogue: 0,0:10:51.39,0:10:52.96,Default,,0,0,0,,是另外的一条基本查询 Dialogue: 0,0:10:53.71,0:10:58.43,Default,,0,0,0,,它也有类似的形状——接收一条数据对象流 Dialogue: 0,0:10:59.18,0:11:01.64,Default,,0,0,0,,一条初始字典流 Dialogue: 0,0:11:01.68,0:11:05.52,Default,,0,0,0,,字典是你在进行匹配时 需要遵循的约束 Dialogue: 0,0:11:05.53,0:11:07.44,Default,,0,0,0,,然后它会输出一条字典流 Dialogue: 0,0:11:08.70,0:11:10.80,Default,,0,0,0,,这就是这条基本查询的形状 Dialogue: 0,0:11:11.50,0:11:12.91,Default,,0,0,0,,我又该如何实现AND呢? Dialogue: 0,0:11:12.91,0:11:13.45,Default,,0,0,0,,其实很简单 Dialogue: 0,0:11:13.45,0:11:14.44,Default,,0,0,0,,把它们连接起来就好了 Dialogue: 0,0:11:14.88,0:11:16.28,Default,,0,0,0,,我把这条查询的输出 Dialogue: 0,0:11:16.96,0:11:18.81,Default,,0,0,0,,连接在这条查询的输入上 Dialogue: 0,0:11:19.83,0:11:21.84,Default,,0,0,0,,然后把这里的字典扇出开来 Dialogue: 0,0:11:26.57,0:11:27.96,Default,,0,0,0,,你们就能发现它是如何工作的了 Dialogue: 0,0:11:29.05,0:11:32.44,Default,,0,0,0,,这里会输出一个框架 Dialogue: 0,0:11:32.51,0:11:36.84,Default,,0,0,0,,其中有X、Y和D的绑定 Dialogue: 0,0:11:37.92,0:11:39.28,Default,,0,0,0,,当后面的查询接收到结果后 Dialogue: 0,0:11:39.29,0:11:41.60,Default,,0,0,0,,当它了解了这些约束后 Dialogue: 0,0:11:42.17,0:11:49.24,Default,,0,0,0,,字典中的是Y、X和D的值 Dialogue: 0,0:11:51.80,0:11:53.08,Default,,0,0,0,,它会搜寻数据库 Dialogue: 0,0:11:53.12,0:11:54.92,Default,,0,0,0,,试图找到有关SUPERVISOR关系的事实 Dialogue: 0,0:11:56.04,0:11:58.51,Default,,0,0,0,,如果找到了的话 它就会输出一些词典 Dialogue: 0,0:11:59.58,0:12:09.34,Default,,0,0,0,,其中有Y、X、D以及Z的绑定 Dialogue: 0,0:12:12.07,0:12:14.09,Default,,0,0,0,,不过要注意 Dialogue: 0,0:12:14.19,0:12:17.24,Default,,0,0,0,,因为这里输入的框架建立了约束 Dialogue: 0,0:12:17.61,0:12:20.28,Default,,0,0,0,,它保证了当你执行AND运算时 Dialogue: 0,0:12:20.49,0:12:24.62,Default,,0,0,0,,这两个X是相同的 Dialogue: 0,0:12:26.47,0:12:28.96,Default,,0,0,0,,这是因为通过这条流输出时 Dialogue: 0,0:12:29.96,0:12:32.65,Default,,0,0,0,,X已经有值了 你要确保匹配的一致性 Dialogue: 0,0:12:34.46,0:12:36.17,Default,,0,0,0,,然后我们想起在MATCH的代码中 Dialogue: 0,0:12:36.19,0:12:38.17,Default,,0,0,0,,有一种操作字典的特殊组织方法 Dialogue: 0,0:12:38.20,0:12:39.82,Default,,0,0,0,,确保了匹配的一致性 Dialogue: 0,0:12:40.92,0:12:41.77,Default,,0,0,0,,这就是AND的实现 Dialogue: 0,0:12:44.08,0:12:46.94,Default,,0,0,0,,关键是要注意它的一般性形状 Dialogue: 0,0:12:48.49,0:12:51.55,Default,,0,0,0,,我们来看看(AND P Q) Dialogue: 0,0:12:52.88,0:12:55.61,Default,,0,0,0,,这里是P和Q Dialogue: 0,0:12:57.29,0:12:58.60,Default,,0,0,0,,两条查询的AND Dialogue: 0,0:13:00.27,0:13:01.19,Default,,0,0,0,,看起来像是这样 Dialogue: 0,0:13:01.19,0:13:04.44,Default,,0,0,0,,每一条查询都通过一条流连接数据库 Dialogue: 0,0:13:04.54,0:13:05.71,Default,,0,0,0,,一条输入流 Dialogue: 0,0:13:06.33,0:13:08.17,Default,,0,0,0,,并输出一条输出流 Dialogue: 0,0:13:10.23,0:13:11.72,Default,,0,0,0,,关键是要注意 Dialogue: 0,0:13:12.20,0:13:15.02,Default,,0,0,0,,如果我在它们周围画一个盒子 Dialogue: 0,0:13:19.26,0:13:23.64,Default,,0,0,0,,这就是(AND P Q) Dialogue: 0,0:13:25.66,0:13:30.38,Default,,0,0,0,,那么这个盒子也有同样的形状 Dialogue: 0,0:13:32.04,0:13:34.20,Default,,0,0,0,,它也有一条连接数据库的流 Dialogue: 0,0:13:34.20,0:13:35.74,Default,,0,0,0,,但是在内部会扇出开来 Dialogue: 0,0:13:36.60,0:13:37.93,Default,,0,0,0,,但是在外部你看不到 Dialogue: 0,0:13:38.16,0:13:40.64,Default,,0,0,0,,它接收一个流 并输出一个流 Dialogue: 0,0:13:42.06,0:13:43.16,Default,,0,0,0,,这就是AND Dialogue: 0,0:13:43.57,0:13:45.72,Default,,0,0,0,,类似地 OR可能看起像这样 Dialogue: 0,0:13:46.02,0:13:49.58,Default,,0,0,0,,虽然我没给你们演示过OR的用法 Dialogue: 0,0:13:49.84,0:13:54.70,Default,,0,0,0,,OR会尝试找出P或Q所有匹配的事实 Dialogue: 0,0:13:55.80,0:13:58.07,Default,,0,0,0,,P、Q两条查询都有各自的形状 Dialogue: 0,0:14:04.46,0:14:06.68,Default,,0,0,0,,OR的实现则是 Dialogue: 0,0:14:08.54,0:14:10.91,Default,,0,0,0,,我把来自于数据库的流 Dialogue: 0,0:14:12.50,0:14:13.49,Default,,0,0,0,,扇出开来 Dialogue: 0,0:14:13.49,0:14:16.04,Default,,0,0,0,,把它们分别送给P和Q Dialogue: 0,0:14:17.44,0:14:21.98,Default,,0,0,0,,我把最初的查询流也给扇出开来 Dialogue: 0,0:14:26.75,0:14:29.16,Default,,0,0,0,,这样我不但能够得到P的所有结果 Dialogue: 0,0:14:29.29,0:14:31.08,Default,,0,0,0,,也能得到Q的所有结果 Dialogue: 0,0:14:31.61,0:14:34.56,Default,,0,0,0,,把这些输出送入某种“附加器”中 Dialogue: 0,0:14:34.62,0:14:37.48,Default,,0,0,0,,或者把它们“合并”到一条流中 Dialogue: 0,0:14:39.64,0:14:40.88,Default,,0,0,0,,然后得到输出 Dialogue: 0,0:14:41.08,0:14:48.24,Default,,0,0,0,,而从外部来看 这整个东西就是OR Dialogue: 0,0:14:52.35,0:14:54.89,Default,,0,0,0,,同样的 当你们从外部观察它时 Dialogue: 0,0:14:55.07,0:14:56.54,Default,,0,0,0,,你会发现它具有相同的形状 Dialogue: 0,0:15:01.00,0:15:01.61,Default,,0,0,0,,NOT又如何实现呢? Dialogue: 0,0:15:02.02,0:15:03.45,Default,,0,0,0,,NOT的原理有些类似 Dialogue: 0,0:15:04.31,0:15:05.95,Default,,0,0,0,,如果我有一条查询P Dialogue: 0,0:15:06.86,0:15:13.50,Default,,0,0,0,,这是一条基本查询P Dialogue: 0,0:15:14.69,0:15:16.32,Default,,0,0,0,,现在我要实现(NOT P) Dialogue: 0,0:15:18.68,0:15:20.54,Default,,0,0,0,,NOT的作用像是一个过滤器 Dialogue: 0,0:15:20.72,0:15:21.95,Default,,0,0,0,,这里连接数据库 Dialogue: 0,0:15:23.84,0:15:28.28,Default,,0,0,0,,这里是输入的字典流 Dialogue: 0,0:15:28.78,0:15:31.53,Default,,0,0,0,,(NOT P)要做的就是 Dialogue: 0,0:15:31.88,0:15:37.40,Default,,0,0,0,,对这些东西做过滤 Dialogue: 0,0:15:39.02,0:15:40.09,Default,,0,0,0,,过滤的方法则是 Dialogue: 0,0:15:40.19,0:15:42.70,Default,,0,0,0,,如果我在这里获得了一本字典 Dialogue: 0,0:15:43.42,0:15:44.65,Default,,0,0,0,,那么我就去找所有的匹配 Dialogue: 0,0:15:44.83,0:15:46.48,Default,,0,0,0,,然后丢弃找到的结果 Dialogue: 0,0:15:47.46,0:15:49.93,Default,,0,0,0,,如果我没有在这里找到匹配 Dialogue: 0,0:15:50.12,0:15:51.37,Default,,0,0,0,,我就把它传递过去 Dialogue: 0,0:15:52.40,0:15:53.55,Default,,0,0,0,,NOT就是一个纯粹的过滤器 Dialogue: 0,0:15:55.34,0:15:59.98,Default,,0,0,0,,因此AND就类似于一个电阻 Dialogue: 0,0:15:59.98,0:16:01.85,Default,,0,0,0,,AND是串行的组合 Dialogue: 0,0:16:02.49,0:16:04.14,Default,,0,0,0,,OR是并行组合 Dialogue: 0,0:16:04.96,0:16:07.46,Default,,0,0,0,,然而NOT并不会对字典做任何扩展 Dialogue: 0,0:16:07.46,0:16:08.40,Default,,0,0,0,,它只会做过滤 Dialogue: 0,0:16:08.75,0:16:11.79,Default,,0,0,0,,它会丢弃那些能够匹配的结果 Dialogue: 0,0:16:12.64,0:16:14.19,Default,,0,0,0,,LISP-VALUE的原理类似 Dialogue: 0,0:16:14.84,0:16:16.60,Default,,0,0,0,,它的过滤器会复杂点 Dialogue: 0,0:16:16.60,0:16:17.37,Default,,0,0,0,,因为要应用到谓词上 Dialogue: 0,0:16:19.93,0:16:21.64,Default,,0,0,0,,这里需要注意的关键点是 Dialogue: 0,0:16:21.92,0:16:23.55,Default,,0,0,0,,我们之前也强调过了 Dialogue: 0,0:16:23.64,0:16:25.29,Default,,0,0,0,,就是关于“闭包性质”的思想 Dialogue: 0,0:16:28.22,0:16:31.80,Default,,0,0,0,,我们通过组合手段构建的东西 Dialogue: 0,0:16:31.95,0:16:34.51,Default,,0,0,0,,跟所使用的基本物件 Dialogue: 0,0:16:35.69,0:16:37.58,Default,,0,0,0,,有同样的结构 Dialogue: 0,0:16:39.75,0:16:41.68,Default,,0,0,0,,所以从外面看 Dialogue: 0,0:16:41.71,0:16:43.72,Default,,0,0,0,,查询的AND与基本查询结构相同 Dialogue: 0,0:16:44.63,0:16:46.14,Default,,0,0,0,,这就意味着 Dialogue: 0,0:16:46.94,0:16:50.28,Default,,0,0,0,,这里的盒子可以是AND、OR、NOT或者其它的 Dialogue: 0,0:16:50.30,0:16:54.22,Default,,0,0,0,,因为它具有相同的形状来连接更大的东西 Dialogue: 0,0:16:54.95,0:16:56.68,Default,,0,0,0,,这种思想能够让我们获得 Dialogue: 0,0:16:56.92,0:16:58.96,Default,,0,0,0,,Escher绘图语言中的那种复杂度 Dialogue: 0,0:16:59.55,0:17:01.31,Default,,0,0,0,,让你能够仅仅使用序对 Dialogue: 0,0:17:01.34,0:17:03.26,Default,,0,0,0,,构建出这些复杂结构 Dialogue: 0,0:17:03.93,0:17:04.78,Default,,0,0,0,,这就是“闭包性质” Dialogue: 0,0:17:06.28,0:17:08.06,Default,,0,0,0,,这种性质 Dialogue: 0,0:17:09.64,0:17:11.72,Default,,0,0,0,,能够让我完成你们现在觉得理所当然的事儿 Dialogue: 0,0:17:11.76,0:17:14.91,Default,,0,0,0,,比如我可以查询(AND JOB SALARY) Dialogue: 0,0:17:14.91,0:17:18.80,Default,,0,0,0,,当然我也可以查询(AND JOB (NOT ...))等等 Dialogue: 0,0:17:19.26,0:17:20.92,Default,,0,0,0,,这种便利是由 Dialogue: 0,0:17:20.94,0:17:22.91,Default,,0,0,0,,这种“闭包原则”直接带给我们的 Dialogue: 0,0:17:25.18,0:17:27.08,Default,,0,0,0,,好吧 提问时间 Dialogue: 0,0:17:29.32,0:17:30.89,Default,,0,0,0,,学生:字典是从哪里来的? Dialogue: 0,0:17:30.99,0:17:36.03,Default,,0,0,0,,教授:字典最初来自于你的输入 Dialogue: 0,0:17:36.09,0:17:37.32,Default,,0,0,0,,因此当你最初进行查询时 Dialogue: 0,0:17:39.16,0:17:41.09,Default,,0,0,0,,它首先会建立起这整个结构 Dialogue: 0,0:17:41.09,0:17:42.64,Default,,0,0,0,,它先输入一个空字典 Dialogue: 0,0:17:45.00,0:17:47.24,Default,,0,0,0,,如果你只有一条基本查询的话 Dialogue: 0,0:17:48.24,0:17:51.10,Default,,0,0,0,,那么它就会输出一系列具有内容的字典 Dialogue: 0,0:17:52.31,0:17:54.33,Default,,0,0,0,,这里演示的一般性情况是 Dialogue: 0,0:17:54.51,0:17:59.71,Default,,0,0,0,,某个嵌套组合查询的中间过程 Dialogue: 0,0:18:01.55,0:18:02.30,Default,,0,0,0,,所以在那时 Dialogue: 0,0:18:02.38,0:18:03.79,Default,,0,0,0,,让我们来看看这里 Dialogue: 0,0:18:04.38,0:18:06.73,Default,,0,0,0,,这条SUPERVISOR查询得到了某本字典 Dialogue: 0,0:18:06.73,0:18:08.03,Default,,0,0,0,,这本字典来自于哪里呢? Dialogue: 0,0:18:08.73,0:18:11.15,Default,,0,0,0,,它来自于 Dialogue: 0,0:18:12.84,0:18:14.89,Default,,0,0,0,,这条基本查询的输出 Dialogue: 0,0:18:16.26,0:18:17.88,Default,,0,0,0,,说得更具体一点 Dialogue: 0,0:18:18.35,0:18:21.72,Default,,0,0,0,,如果我最初在顶层只输入了这条查询 Dialogue: 0,0:18:22.27,0:18:22.92,Default,,0,0,0,,这整条AND查询 Dialogue: 0,0:18:23.07,0:18:25.28,Default,,0,0,0,,它实际上会构建这种结构 Dialogue: 0,0:18:25.50,0:18:30.24,Default,,0,0,0,,并使用一本空字典来启动整个过程 Dialogue: 0,0:18:31.77,0:18:34.33,Default,,0,0,0,,处理过程开始后 会产生一系列的字典 Dialogue: 0,0:18:34.36,0:18:37.36,Default,,0,0,0,,其中就有X、Y以及D Dialogue: 0,0:18:38.64,0:18:39.58,Default,,0,0,0,,向这边传递 Dialogue: 0,0:18:40.19,0:18:42.16,Default,,0,0,0,,这就是这条查询的输入 Dialogue: 0,0:18:42.16,0:18:43.72,Default,,0,0,0,,这条查询也会生成其它的东西 Dialogue: 0,0:18:45.04,0:18:48.22,Default,,0,0,0,,如果这整个查询是构建在一个更大的查询中的话 Dialogue: 0,0:18:49.31,0:18:51.00,Default,,0,0,0,,比如说一条OR查询 Dialogue: 0,0:18:53.42,0:18:55.71,Default,,0,0,0,,那么它将输出到下一个查询中 Dialogue: 0,0:18:58.56,0:19:01.28,Default,,0,0,0,,因此最初开始处理时 只有一本空字典 Dialogue: 0,0:19:01.68,0:19:04.08,Default,,0,0,0,,但是在处理这些复合查询的过程中 Dialogue: 0,0:19:04.11,0:19:06.65,Default,,0,0,0,,会生成各种不同的字典 Dialogue: 0,0:19:07.66,0:19:12.28,Default,,0,0,0,,学生:字典都是查询的结果吗? Dialogue: 0,0:19:15.12,0:19:17.69,Default,,0,0,0,,它们会变成 Dialogue: 0,0:19:18.84,0:19:22.81,Default,,0,0,0,,它们存储在数据库中吗? Dialogue: 0,0:19:23.68,0:19:24.98,Default,,0,0,0,,它们是临时数据吗? Dialogue: 0,0:19:24.98,0:19:27.18,Default,,0,0,0,,教授:它们是在MATCH过程中临时创建的 Dialogue: 0,0:19:28.03,0:19:29.88,Default,,0,0,0,,但它们实际存放在内存中 Dialogue: 0,0:19:29.88,0:19:33.02,Default,,0,0,0,,最初 某人创建了一本THE-EMPTY-DICT字典 Dialogue: 0,0:19:34.22,0:19:36.80,Default,,0,0,0,,送入这个匹配过程 Dialogue: 0,0:19:36.81,0:19:39.05,Default,,0,0,0,,MATCH过程据此构建新字典 Dialogue: 0,0:19:39.07,0:19:40.27,Default,,0,0,0,,并把它们传递下去 Dialogue: 0,0:19:40.76,0:19:42.48,Default,,0,0,0,,学生:因此匹配完成后它们就被丢弃了? Dialogue: 0,0:19:43.64,0:19:46.25,Default,,0,0,0,,教授:实际上 当没人需要它们后(就被废料回收了) Dialogue: 0,0:19:51.90,0:19:53.60,Default,,0,0,0,,学生:似乎AND查询对数据库 Dialogue: 0,0:19:53.63,0:19:55.37,Default,,0,0,0,,进行了一些冗余操作 Dialogue: 0,0:19:55.96,0:19:57.48,Default,,0,0,0,,如果第一条子句扫描过了 Dialogue: 0,0:19:57.50,0:19:59.90,Default,,0,0,0,,比如说前两个元素没有匹配 而第三个元素匹配了 Dialogue: 0,0:20:00.25,0:20:03.64,Default,,0,0,0,,然而第二条子句又会检查这两个元素 Dialogue: 0,0:20:04.32,0:20:06.59,Default,,0,0,0,,然后又一次丢弃这些不匹配的元素 Dialogue: 0,0:20:06.64,0:20:08.72,Default,,0,0,0,,而字典中已经有匹配的项了 Dialogue: 0,0:20:10.00,0:20:12.56,Default,,0,0,0,,如果我们把数据库中的数据 Dialogue: 0,0:20:12.57,0:20:14.43,Default,,0,0,0,,跟字典同时传递 这样可行么? Dialogue: 0,0:20:15.69,0:20:17.60,Default,,0,0,0,,教授:实际上 通常来说 Dialogue: 0,0:20:17.63,0:20:19.48,Default,,0,0,0,,我们能够以其它方式来安排这些搜索 Dialogue: 0,0:20:20.12,0:20:21.74,Default,,0,0,0,,你也可以做一些分析 Dialogue: 0,0:20:21.74,0:20:23.16,Default,,0,0,0,,我记得书里面就有这样的习题 Dialogue: 0,0:20:23.87,0:20:26.65,Default,,0,0,0,,是考察通过安排AND子句的顺序 Dialogue: 0,0:20:27.00,0:20:29.20,Default,,0,0,0,,来消除不同类型的冗余 Dialogue: 0,0:20:29.85,0:20:30.72,Default,,0,0,0,,而这里只是为了 Dialogue: 0,0:20:31.32,0:20:34.54,Default,,0,0,0,,用非常简单的情况来向你们展示它们是如何配合的 Dialogue: 0,0:20:34.70,0:20:35.38,Default,,0,0,0,,但是你说得非常对 Dialogue: 0,0:20:35.38,0:20:37.32,Default,,0,0,0,,这些冗余是可以避免的 Dialogue: 0,0:20:38.37,0:20:40.80,Default,,0,0,0,,这也是这门语言缓慢的原因之一 Dialogue: 0,0:20:41.19,0:20:42.70,Default,,0,0,0,,你们可以让它变得更聪明 Dialogue: 0,0:20:42.93,0:20:46.22,Default,,0,0,0,,我只是为了向你们演示非常简单的、原理性的实现 Dialogue: 0,0:20:51.22,0:20:53.23,Default,,0,0,0,,学生:您是根据Prolog来建模这门语言的 Dialogue: 0,0:20:53.24,0:20:55.13,Default,,0,0,0,,还是说它只是偶然地像Prolog? Dialogue: 0,0:21:04.96,0:21:07.08,Default,,0,0,0,,教授:Gerry教授昨天羞辱了一大堆人 Dialogue: 0,0:21:07.24,0:21:09.92,Default,,0,0,0,,我想说真实的情况是 Dialogue: 0,0:21:10.19,0:21:12.60,Default,,0,0,0,,MIT的研究人员在1971年做了类似的事 Dialogue: 0,0:21:12.64,0:21:15.60,Default,,0,0,0,,但是发现这个方向并不正确 并停止了研究 Dialogue: 0,0:21:16.12,0:21:22.80,Default,,0,0,0,,因此我们是根据查询处理的基本原理建模的 Dialogue: 0,0:21:22.84,0:21:24.73,Default,,0,0,0,,大概在1971年左右 Dialogue: 0,0:21:25.13,0:21:27.24,Default,,0,0,0,,只是说 那时候我们还没有用流来实现 Dialogue: 0,0:21:28.27,0:21:33.04,Default,,0,0,0,,然后我们 -- 但我们使用了它差不多六个月后 Dialogue: 0,0:21:33.08,0:21:34.91,Default,,0,0,0,,发现它存在各种各样的问题 Dialogue: 0,0:21:34.94,0:21:36.30,Default,,0,0,0,,稍后我会解释 Dialogue: 0,0:21:37.33,0:21:38.19,Default,,0,0,0,,然后我们就想 Dialogue: 0,0:21:38.44,0:21:39.92,Default,,0,0,0,,Prolog一定解决了这些问题 Dialogue: 0,0:21:39.93,0:21:41.21,Default,,0,0,0,,但却发现它并没有 Dialogue: 0,0:21:41.25,0:21:43.02,Default,,0,0,0,,从这种意义上来说 它确实跟Prolog一样 Dialogue: 0,0:21:43.60,0:21:44.95,Default,,0,0,0,,学生:Prolog基于流么? Dialogue: 0,0:21:44.95,0:21:46.20,Default,,0,0,0,,教授:不 Prolog基于的是 Dialogue: 0,0:21:46.78,0:21:51.04,Default,,0,0,0,,就行为上来说 我们的语言很像Prolog Dialogue: 0,0:21:51.04,0:21:52.96,Default,,0,0,0,,Prolog使用回溯策略 Dialogue: 0,0:21:53.80,0:21:55.71,Default,,0,0,0,,但是Prolog有一个优点非常好 Dialogue: 0,0:21:55.72,0:21:57.98,Default,,0,0,0,,也使得它变得实用 Dialogue: 0,0:21:58.28,0:22:01.50,Default,,0,0,0,,你知道吗 Dialogue: 0,0:22:01.68,0:22:04.09,Default,,0,0,0,,它们精心设计了Prolog的编译器 Dialogue: 0,0:22:04.11,0:22:05.32,Default,,0,0,0,,使得它能够高速运行 Dialogue: 0,0:22:06.65,0:22:10.81,Default,,0,0,0,,因此 虽然我们这门语言非常缓慢地输出答案 Dialogue: 0,0:22:11.66,0:22:13.61,Default,,0,0,0,,真正的Prolog程序却运行得非常快 Dialogue: 0,0:22:14.70,0:22:16.48,Default,,0,0,0,,这是因为 尽管搜索过程十分低效 Dialogue: 0,0:22:16.67,0:22:20.81,Default,,0,0,0,,Prolog卓越的编译器也会高效地完成工作 Dialogue: 0,0:22:24.30,0:22:25.21,Default,,0,0,0,,休息一下吧 Dialogue: 0,0:22:25.42,0:22:36.17,Default,,0,0,0,,[音乐] Dialogue: 0,0:22:36.35,0:22:39.87,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:23:01.48,0:23:05.12,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:23:05.18,0:23:09.05,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:23:09.12,0:23:13.66,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 II Dialogue: 0,0:23:16.65,0:23:18.83,Default,,0,0,0,,我们已经考察过了基本查询 Dialogue: 0,0:23:19.21,0:23:23.52,Default,,0,0,0,,以及如何使用流来实现组合手段 Dialogue: 0,0:23:23.79,0:23:25.72,Default,,0,0,0,,AND、OR以及NOT Dialogue: 0,0:23:26.95,0:23:28.43,Default,,0,0,0,,现在 该讨论抽象手段了 Dialogue: 0,0:23:29.58,0:23:32.80,Default,,0,0,0,,回想一下 我们这门语言的抽象手段是RULE Dialogue: 0,0:23:35.15,0:23:37.79,Default,,0,0,0,,(BOSS ?Z ?D)描述的是 Dialogue: 0,0:23:39.18,0:23:43.77,Default,,0,0,0,,如果某人在D部门工作 Dialogue: 0,0:23:45.68,0:23:47.47,Default,,0,0,0,,并且Z是X的上司 Dialogue: 0,0:23:48.90,0:23:50.60,Default,,0,0,0,,这就是所谓的“BOSS” Dialogue: 0,0:23:52.26,0:23:53.15,Default,,0,0,0,,并且 实际上 Dialogue: 0,0:23:53.34,0:23:55.61,Default,,0,0,0,,如果我们考察一下编写的规则与这边的关系 Dialogue: 0,0:23:56.80,0:23:57.90,Default,,0,0,0,,这是我们编写的查询 Dialogue: 0,0:23:57.93,0:24:01.90,Default,,0,0,0,,这个是(JOB ?X ?D) 而这个是(SUPERVISOR ?X ?Z) Dialogue: 0,0:24:02.19,0:24:04.28,Default,,0,0,0,,我们实际想要把这一大堆东西 Dialogue: 0,0:24:05.07,0:24:06.57,Default,,0,0,0,,用一个盒子封装起来 Dialogue: 0,0:24:19.08,0:24:24.54,Default,,0,0,0,,然后把这个盒子里的所有东西 Dialogue: 0,0:24:25.15,0:24:32.48,Default,,0,0,0,,认为是(BOSS ?Z ?D) Dialogue: 0,0:24:33.90,0:24:35.25,Default,,0,0,0,,这是我们想要达到的效果 Dialogue: 0,0:24:38.72,0:24:39.72,Default,,0,0,0,,因此 比如说 Dialogue: 0,0:24:43.18,0:24:44.08,Default,,0,0,0,,我们这样做了过后 Dialogue: 0,0:24:45.00,0:24:47.84,Default,,0,0,0,,我们想要检查 Dialogue: 0,0:24:47.95,0:24:50.51,Default,,0,0,0,,Ben Bitdiddle是否为计算机分部的BOSS Dialogue: 0,0:24:51.10,0:25:02.86,Default,,0,0,0,,如果我想查询 (BOSS (BITDIDDLE BEN) COMPUTER) Dialogue: 0,0:25:04.78,0:25:07.08,Default,,0,0,0,,想象一下把这条查询输入系统 Dialogue: 0,0:25:07.12,0:25:09.16,Default,,0,0,0,,实际上发生的是 Dialogue: 0,0:25:10.67,0:25:12.92,Default,,0,0,0,,在这里先构建一本字典 Dialogue: 0,0:25:15.82,0:25:23.63,Default,,0,0,0,,其中 ?Z=BITDIDDLE Dialogue: 0,0:25:28.88,0:25:33.31,Default,,0,0,0,,?D=COMPUTER Dialogue: 0,0:25:37.08,0:25:38.62,Default,,0,0,0,,这个字典又是来自于哪里呢? Dialogue: 0,0:25:38.68,0:25:40.71,Default,,0,0,0,,我们来看下幻灯片 Dialogue: 0,0:25:40.71,0:25:43.71,Default,,0,0,0,,这本字典是通过把 Dialogue: 0,0:25:44.30,0:25:46.33,Default,,0,0,0,,查询(BOSS (BITDIDDLE BEN) COMPUTER) Dialogue: 0,0:25:46.51,0:25:49.63,Default,,0,0,0,,与规则的结论(BOSS ?Z ?D)相匹配得到 Dialogue: 0,0:25:51.65,0:25:54.11,Default,,0,0,0,,所以我们把规则的结论和查询匹配了起来 Dialogue: 0,0:25:54.19,0:25:55.53,Default,,0,0,0,,这样我们就获得了一本字典 Dialogue: 0,0:25:58.99,0:26:02.54,Default,,0,0,0,,现在我们就要把这本字典输入到这整个结构中 Dialogue: 0,0:26:02.92,0:26:05.56,Default,,0,0,0,,进行处理 并观察是否有输出 Dialogue: 0,0:26:06.67,0:26:09.88,Default,,0,0,0,,如果输出了结果 那么查询就为真 Dialogue: 0,0:26:11.33,0:26:12.37,Default,,0,0,0,,这是基本的思想 Dialogue: 0,0:26:12.37,0:26:13.24,Default,,0,0,0,,因此 通常来说 Dialogue: 0,0:26:14.03,0:26:15.40,Default,,0,0,0,,我们实现规则的方法就是 Dialogue: 0,0:26:15.85,0:26:18.89,Default,,0,0,0,,用规则的结论去匹配 Dialogue: 0,0:26:20.86,0:26:22.96,Default,,0,0,0,,假设为真的查询 Dialogue: 0,0:26:23.58,0:26:25.12,Default,,0,0,0,,这个过程会产生一本字典 Dialogue: 0,0:26:25.29,0:26:28.22,Default,,0,0,0,,在有了相关字典后 Dialogue: 0,0:26:30.35,0:26:34.51,Default,,0,0,0,,我们来处理规则的体 Dialogue: 0,0:26:36.33,0:26:37.68,Default,,0,0,0,,基本上就是这样了 Dialogue: 0,0:26:38.64,0:26:41.44,Default,,0,0,0,,但还有两个技术点 Dialogue: 0,0:26:43.04,0:26:44.32,Default,,0,0,0,,首先就是 Dialogue: 0,0:26:45.74,0:26:47.26,Default,,0,0,0,,我也可能有其它的问法 Dialogue: 0,0:26:47.51,0:26:48.41,Default,,0,0,0,,比如说 Dialogue: 0,0:26:50.54,0:26:52.36,Default,,0,0,0,,查询计算机分部的BOSS Dialogue: 0,0:26:52.54,0:26:56.32,Default,,0,0,0,,就可以查询 (BOSS ?WHO COMPUTER) Dialogue: 0,0:27:00.78,0:27:01.63,Default,,0,0,0,,这样做了以后 Dialogue: 0,0:27:02.57,0:27:04.62,Default,,0,0,0,,我真正想要做的 Dialogue: 0,0:27:05.04,0:27:06.49,Default,,0,0,0,,就是先建立一本字典 Dialogue: 0,0:27:08.35,0:27:09.88,Default,,0,0,0,,其中有一些约束 Dialogue: 0,0:27:09.93,0:27:11.20,Default,,0,0,0,,比如 ?D=COMPUTER Dialogue: 0,0:27:14.35,0:27:18.48,Default,,0,0,0,,而?Z等同于?WHO Dialogue: 0,0:27:21.70,0:27:23.22,Default,,0,0,0,,我们的匹配器不会那么做 Dialogue: 0,0:27:23.22,0:27:27.00,Default,,0,0,0,,这不是模式和数据的匹配方式 Dialogue: 0,0:27:28.58,0:27:29.72,Default,,0,0,0,,这是在匹配两个模式 Dialogue: 0,0:27:29.74,0:27:31.58,Default,,0,0,0,,并判断它们是否一致 Dialogue: 0,0:27:31.90,0:27:33.48,Default,,0,0,0,,又是什么使它们不一致 Dialogue: 0,0:27:33.48,0:27:36.43,Default,,0,0,0,,换句话说 我们需要的不是一个模式匹配器 Dialogue: 0,0:27:36.96,0:27:38.91,Default,,0,0,0,,而是一种更一般性的东西 Dialogue: 0,0:27:39.13,0:27:40.11,Default,,0,0,0,,就是“合一”算法 Dialogue: 0,0:27:44.42,0:27:48.06,Default,,0,0,0,,“合一”是更为一般化的模式匹配算法 Dialogue: 0,0:27:49.53,0:27:52.17,Default,,0,0,0,,合一算法接收两条模式 Dialogue: 0,0:27:53.23,0:27:57.53,Default,,0,0,0,,它考虑的是:可以找到哪些一般性的元素 Dialogue: 0,0:27:58.20,0:28:00.01,Default,,0,0,0,,用来代换模式中的变量 Dialogue: 0,0:28:02.68,0:28:05.08,Default,,0,0,0,,使得它俩能够同时满足 Dialogue: 0,0:28:05.68,0:28:06.60,Default,,0,0,0,,让我来举个例子 Dialogue: 0,0:28:08.86,0:28:14.49,Default,,0,0,0,,我有一个含有两个元素的模式:(?X ?X) Dialogue: 0,0:28:15.76,0:28:17.15,Default,,0,0,0,,它描述的是一个二元表 Dialogue: 0,0:28:17.32,0:28:18.64,Default,,0,0,0,,不管元素具体是什么 Dialogue: 0,0:28:18.67,0:28:20.04,Default,,0,0,0,,但两个元素是相同的 Dialogue: 0,0:28:20.40,0:28:22.83,Default,,0,0,0,,我把它与另一个模式进行“合一” Dialogue: 0,0:28:22.92,0:28:24.62,Default,,0,0,0,,后者描述的是一个二元表 Dialogue: 0,0:28:24.65,0:28:27.61,Default,,0,0,0,,首元素一张由A、?Y、C构成的表 Dialogue: 0,0:28:28.00,0:28:30.14,Default,,0,0,0,,而第二个元素是由A、B、?Z构成的表 Dialogue: 0,0:28:33.07,0:28:34.88,Default,,0,0,0,,那么 合一算法能够告诉我 Dialogue: 0,0:28:34.89,0:28:36.17,Default,,0,0,0,,在生成的字典中 Dialogue: 0,0:28:36.35,0:28:37.96,Default,,0,0,0,,?X必须是(A B C) Dialogue: 0,0:28:39.34,0:28:41.92,Default,,0,0,0,,?Y必须为B ?Z必须为C Dialogue: 0,0:28:43.44,0:28:46.28,Default,,0,0,0,,这些是我必须对X、Y以及Z施加的约束 Dialogue: 0,0:28:46.33,0:28:47.58,Default,,0,0,0,,以便让两个模式合一 Dialogue: 0,0:28:48.12,0:28:50.84,Default,,0,0,0,,或者换句话来说 让它匹配这个?X Dialogue: 0,0:28:51.15,0:28:53.37,Default,,0,0,0,,让它匹配这个?X Dialogue: 0,0:28:55.28,0:28:57.76,Default,,0,0,0,,合一算法需要能够推断出这些 Dialogue: 0,0:28:58.54,0:29:01.08,Default,,0,0,0,,但是合一算法也会遇到复杂的情况 Dialogue: 0,0:29:01.08,0:29:03.07,Default,,0,0,0,,我可能会询问一些复杂的查询 Dialogue: 0,0:29:03.48,0:29:05.74,Default,,0,0,0,,比如这是一个二元表 Dialogue: 0,0:29:07.00,0:29:08.28,Default,,0,0,0,,其中的元素都是相同的 Dialogue: 0,0:29:08.86,0:29:11.15,Default,,0,0,0,,它要与这个模式进行合一 Dialogue: 0,0:29:12.65,0:29:15.36,Default,,0,0,0,,合一算法也要能够从中推断出 Dialogue: 0,0:29:16.89,0:29:19.57,Default,,0,0,0,,?Y必须为B Dialogue: 0,0:29:19.57,0:29:22.12,Default,,0,0,0,,因为这两个是一样的 Dialogue: 0,0:29:22.22,0:29:23.52,Default,,0,0,0,,因此?Y就是B Dialogue: 0,0:29:24.34,0:29:27.53,Default,,0,0,0,,这里 ?V应该为A Dialogue: 0,0:29:28.94,0:29:30.99,Default,,0,0,0,,只要?Z和?W取值相同 Dialogue: 0,0:29:31.00,0:29:32.43,Default,,0,0,0,,它们就可以是任意值 Dialogue: 0,0:29:35.71,0:29:41.76,Default,,0,0,0,,?X就应该是(B A ?W) 其中?W为任意值 Dialogue: 0,0:29:42.83,0:29:44.68,Default,,0,0,0,,或者是?Z -- 因为?Z和?W是一致的 Dialogue: 0,0:29:44.70,0:29:49.42,Default,,0,0,0,,发现了么 合一算法需要从这些模式中推断出信息 Dialogue: 0,0:29:50.88,0:29:53.52,Default,,0,0,0,,所以你们可能认为 这其中有某种魔法般的推理 Dialogue: 0,0:29:54.27,0:29:55.23,Default,,0,0,0,,但其实并不是 Dialogue: 0,0:29:55.85,0:29:59.88,Default,,0,0,0,,合一算法基本上只是对模式匹配的小小修改 Dialogue: 0,0:30:00.15,0:30:01.85,Default,,0,0,0,,如果你们翻阅教材 就会发现 Dialogue: 0,0:30:02.25,0:30:06.16,Default,,0,0,0,,在模式匹配算法中加入了三到四行代码 Dialogue: 0,0:30:06.49,0:30:08.17,Default,,0,0,0,,来处理对称的情况 Dialogue: 0,0:30:08.28,0:30:10.81,Default,,0,0,0,,还记得吗 模式匹配中有一处代码判断 Dialogue: 0,0:30:11.66,0:30:14.28,Default,,0,0,0,,这个变量匹配一个常量吗? Dialogue: 0,0:30:14.98,0:30:16.42,Default,,0,0,0,,如果是的话 就在字典中进行检查 Dialogue: 0,0:30:16.42,0:30:18.25,Default,,0,0,0,,在合一算法中只有另一条子句 Dialogue: 0,0:30:18.49,0:30:20.75,Default,,0,0,0,,它判断两个变量是否相匹配 Dialogue: 0,0:30:22.00,0:30:23.42,Default,,0,0,0,,这种情况下你去查询字典 Dialogue: 0,0:30:23.45,0:30:25.68,Default,,0,0,0,,看它们在字典的约束下是否一致 Dialogue: 0,0:30:27.03,0:30:31.13,Default,,0,0,0,,因此 这门语言中的所有“推断” Dialogue: 0,0:30:31.28,0:30:34.59,Default,,0,0,0,,你会发现它蕴含在规则应用中 Dialogue: 0,0:30:34.99,0:30:37.88,Default,,0,0,0,,更进一步地考察 你会发现在合一算法中 Dialogue: 0,0:30:38.36,0:30:40.32,Default,,0,0,0,,如果更进一步地用“显微镜”观察 Dialogue: 0,0:30:40.56,0:30:43.96,Default,,0,0,0,,基本上就在模式匹配算法中 Dialogue: 0,0:30:44.94,0:30:47.07,Default,,0,0,0,,这其中并没有什么魔法 Dialogue: 0,0:30:47.41,0:30:50.25,Default,,0,0,0,,而你们所见到的“推断” Dialogue: 0,0:30:50.94,0:30:52.89,Default,,0,0,0,,只是因为其中的递归 Dialogue: 0,0:30:52.92,0:30:55.69,Default,,0,0,0,,它一点一点地回绕MATCH过程 Dialogue: 0,0:30:56.03,0:30:58.03,Default,,0,0,0,,它让这个过程看起来很聪明 Dialogue: 0,0:30:58.44,0:31:00.36,Default,,0,0,0,,但它实际上并不是那么聪明 Dialogue: 0,0:31:02.14,0:31:04.41,Default,,0,0,0,,当然 合一算法需要聪明地识别出一些情况 Dialogue: 0,0:31:04.88,0:31:05.87,Default,,0,0,0,,我来举个例子吧 Dialogue: 0,0:31:11.07,0:31:13.36,Default,,0,0,0,,假设我想要用一个二元表进行合一 Dialogue: 0,0:31:13.48,0:31:14.81,Default,,0,0,0,,(?X ?X) Dialogue: 0,0:31:17.24,0:31:22.14,Default,,0,0,0,,另一个模式则是 (?Y (a . ?Y)) Dialogue: 0,0:31:24.37,0:31:26.12,Default,,0,0,0,,现在 如果你想一想它所表达的意思 Dialogue: 0,0:31:26.86,0:31:29.71,Default,,0,0,0,,它表示了?X应该跟?Y一致 Dialogue: 0,0:31:30.92,0:31:31.66,Default,,0,0,0,,同时呢 Dialogue: 0,0:31:31.82,0:31:36.16,Default,,0,0,0,,?X又应该跟(A . ?Y)相同 Dialogue: 0,0:31:37.33,0:31:39.45,Default,,0,0,0,,如果你仔细思考它成立的条件 Dialogue: 0,0:31:42.27,0:31:44.71,Default,,0,0,0,,你会发现 ?Y必须是一个由A构成的无穷表 Dialogue: 0,0:31:47.50,0:31:48.35,Default,,0,0,0,,从某种角度来说 Dialogue: 0,0:31:49.21,0:31:52.40,Default,,0,0,0,,为了完成这样的合一 Dialogue: 0,0:31:52.60,0:31:54.84,Default,,0,0,0,,我需要求解一个不动点方程 Dialogue: 0,0:31:55.05,0:32:01.84,Default,,0,0,0,,(CONS 'A Y)=Y Dialogue: 0,0:32:04.57,0:32:06.96,Default,,0,0,0,,通常来说 --- 我这个例子很简单 Dialogue: 0,0:32:07.29,0:32:08.67,Default,,0,0,0,,但实际进行合一时 Dialogue: 0,0:32:08.97,0:32:11.98,Default,,0,0,0,,我们可能要求解一个任意的不动点方程 Dialogue: 0,0:32:12.01,0:32:13.42,Default,,0,0,0,,(F Y)=Y Dialogue: 0,0:32:15.53,0:32:17.08,Default,,0,0,0,,你基本上不能保证 Dialogue: 0,0:32:17.10,0:32:19.47,Default,,0,0,0,,在有穷时间内找到解 Dialogue: 0,0:32:20.57,0:32:23.60,Default,,0,0,0,,我们的逻辑语言又该如何处理这类情况呢? Dialogue: 0,0:32:24.89,0:32:26.48,Default,,0,0,0,,答案就是:“不处理” Dialogue: 0,0:32:27.16,0:32:28.04,Default,,0,0,0,,它会撒手不干 Dialogue: 0,0:32:28.73,0:32:31.07,Default,,0,0,0,,合一算法中有一处小检查 Dialogue: 0,0:32:31.31,0:32:33.82,Default,,0,0,0,,用来判断是否为困难的情况 Dialogue: 0,0:32:34.44,0:32:38.00,Default,,0,0,0,,也就是 匹配这些东西需要求解不动点方程 Dialogue: 0,0:32:38.65,0:32:40.81,Default,,0,0,0,,遇到这类情况 我就撒手不干 Dialogue: 0,0:32:42.84,0:32:44.65,Default,,0,0,0,,如果不进行这样的检查 Dialogue: 0,0:32:45.00,0:32:45.88,Default,,0,0,0,,会发生什么情况? Dialogue: 0,0:32:47.99,0:32:49.10,Default,,0,0,0,,大多数情况就是 Dialogue: 0,0:32:49.13,0:32:51.31,Default,,0,0,0,,合一算法会陷入无穷循环 Dialogue: 0,0:32:53.74,0:32:56.54,Default,,0,0,0,,其它的逻辑语言有类似的工作原理 Dialogue: 0,0:32:56.80,0:32:58.14,Default,,0,0,0,,因此这其中没有什么魔法 Dialogue: 0,0:32:58.22,0:32:59.93,Default,,0,0,0,,简单的情况由匹配器完成 Dialogue: 0,0:33:00.10,0:33:01.58,Default,,0,0,0,,困难的情况根本不去处理 Dialogue: 0,0:33:02.96,0:33:05.47,Default,,0,0,0,,这就是这种技术的现状 Dialogue: 0,0:33:11.88,0:33:14.24,Default,,0,0,0,,现在 我来形式化地描述一下 Dialogue: 0,0:33:14.27,0:33:16.38,Default,,0,0,0,,规则系统的运行原理 -- 也就是合一算法 Dialogue: 0,0:33:17.39,0:33:18.75,Default,,0,0,0,,因此 正式的定义就是 Dialogue: 0,0:33:19.20,0:33:20.96,Default,,0,0,0,,应用一条规则 Dialogue: 0,0:33:24.17,0:33:27.13,Default,,0,0,0,,我们需要使用一些之前的术语 Dialogue: 0,0:33:28.27,0:33:32.01,Default,,0,0,0,,我们把向查询的盒子中 Dialogue: 0,0:33:32.88,0:33:34.78,Default,,0,0,0,,塞入字典称作是 Dialogue: 0,0:33:34.81,0:33:38.54,Default,,0,0,0,,相对一个环境或者框架 Dialogue: 0,0:33:39.95,0:33:43.85,Default,,0,0,0,,对这些大型查询求值 Dialogue: 0,0:33:43.85,0:33:45.04,Default,,0,0,0,,因此 当我们谈及“字典”的时候 Dialogue: 0,0:33:45.07,0:33:46.28,Default,,0,0,0,,“字典”究竟是什么? Dialogue: 0,0:33:46.72,0:33:48.18,Default,,0,0,0,,它是符号的一系列语义 Dialogue: 0,0:33:48.18,0:33:50.22,Default,,0,0,0,,我们把它叫做“框架”或者“环境” Dialogue: 0,0:33:51.80,0:33:55.97,Default,,0,0,0,,根据环境进行操作 又是什么? Dialogue: 0,0:33:55.97,0:33:57.42,Default,,0,0,0,,我们把这个叫做“求值” Dialogue: 0,0:33:58.33,0:34:01.56,Default,,0,0,0,,因此我们就说 应用一条规则的方法是 Dialogue: 0,0:34:01.92,0:34:06.16,Default,,0,0,0,,先通过将给定的查询与规则的结论合一 得到环境 Dialogue: 0,0:34:06.67,0:34:11.58,Default,,0,0,0,,再在该环境中求值相应规则的体 Dialogue: 0,0:34:13.23,0:34:14.51,Default,,0,0,0,,我想要让你们注意的是 Dialogue: 0,0:34:14.80,0:34:17.08,Default,,0,0,0,,这非常像是 Dialogue: 0,0:34:18.16,0:34:21.50,Default,,0,0,0,,元循环求值器以及代换模型 Dialogue: 0,0:34:21.63,0:34:22.73,Default,,0,0,0,,规则的应用就是 Dialogue: 0,0:34:22.86,0:34:28.36,Default,,0,0,0,,在一个环境中求值规则的体 Dialogue: 0,0:34:28.54,0:34:33.13,Default,,0,0,0,,环境是通过将实际参数与形式参数绑定起来得到的 Dialogue: 0,0:34:34.56,0:34:36.41,Default,,0,0,0,,规则、规则的应用、过程的应用 Dialogue: 0,0:34:36.44,0:34:40.41,Default,,0,0,0,,它们在形式上完全相似 Dialogue: 0,0:34:40.57,0:34:42.30,Default,,0,0,0,,尽管它们又非常不同 Dialogue: 0,0:34:43.65,0:34:45.61,Default,,0,0,0,,再一次地出现了EVAL-APPLY循环 Dialogue: 0,0:34:47.29,0:34:49.52,Default,,0,0,0,,EVAL-APPLY Dialogue: 0,0:34:53.39,0:34:57.39,Default,,0,0,0,,因此通常来说 我们可能会处理一些复合表达式 Dialogue: 0,0:34:57.42,0:34:59.13,Default,,0,0,0,,它们会变成规则的应用 Dialogue: 0,0:35:00.70,0:35:03.28,Default,,0,0,0,,进一步又会产生字典、框架或者环境 Dialogue: 0,0:35:03.31,0:35:04.72,Default,,0,0,0,,不管你要怎么叫它 Dialogue: 0,0:35:05.02,0:35:08.43,Default,,0,0,0,,它们随后又会作为某个大的复合对象的输入 Dialogue: 0,0:35:08.66,0:35:11.77,Default,,0,0,0,,这有它的一部分 并可能有其它规则的应用 Dialogue: 0,0:35:13.58,0:35:15.68,Default,,0,0,0,,这基本上就是相同的循环 Dialogue: 0,0:35:15.72,0:35:18.68,Default,,0,0,0,,尽管这里没有什么东西看起来像过程 Dialogue: 0,0:35:19.68,0:35:21.87,Default,,0,0,0,,这是因为我们创建的语言 Dialogue: 0,0:35:22.08,0:35:25.49,Default,,0,0,0,,它们的组合手段和抽象手段以某种方式展开 Dialogue: 0,0:35:28.77,0:35:29.52,Default,,0,0,0,,通常来说 Dialogue: 0,0:35:29.77,0:35:31.39,Default,,0,0,0,,最顶层所发生的是 Dialogue: 0,0:35:33.79,0:35:35.96,Default,,0,0,0,,数据库中也有一些规则 Dialogue: 0,0:35:36.65,0:35:38.70,Default,,0,0,0,,数据库中的数据也可能是规则 Dialogue: 0,0:35:40.46,0:35:42.06,Default,,0,0,0,,它们用来检查对象是否为真 Dialogue: 0,0:35:42.92,0:35:44.89,Default,,0,0,0,,所以这里可能会有规则检查 Dialogue: 0,0:35:46.75,0:35:48.16,Default,,0,0,0,,然后就会有一些控制结构 Dialogue: 0,0:35:48.19,0:35:50.48,Default,,0,0,0,,用来判断你访问的是规则 Dialogue: 0,0:35:50.51,0:35:51.80,Default,,0,0,0,,还是数据元素 Dialogue: 0,0:35:51.84,0:35:53.12,Default,,0,0,0,,然后不断地把它们扇出来开 Dialogue: 0,0:35:53.35,0:35:55.48,Default,,0,0,0,,所以基本上不可能说清楚 Dialogue: 0,0:35:55.68,0:35:57.69,Default,,0,0,0,,是用什么样的顺序来查询这些东西的 Dialogue: 0,0:35:58.20,0:36:00.27,Default,,0,0,0,,是广度优先还是深度优先 Dialogue: 0,0:36:00.28,0:36:01.64,Default,,0,0,0,,另外一个原因是 Dialogue: 0,0:36:01.66,0:36:05.58,Default,,0,0,0,,我们通过惰性流隐藏了实际执行顺序 Dialogue: 0,0:36:07.69,0:36:11.16,Default,,0,0,0,,因此很难说清楚它的扫描顺序 Dialogue: 0,0:36:11.27,0:36:12.16,Default,,0,0,0,,但真实的是 Dialogue: 0,0:36:12.19,0:36:13.64,Default,,0,0,0,,由于你是在流视图观察它的 Dialogue: 0,0:36:13.90,0:36:15.82,Default,,0,0,0,,而它们最终都要被扫描到 Dialogue: 0,0:36:24.98,0:36:28.15,Default,,0,0,0,,这里还有一个小小的技术问题 Dialogue: 0,0:36:30.88,0:36:33.55,Default,,0,0,0,,假设我在这里输入 Dialogue: 0,0:36:37.53,0:36:41.00,Default,,0,0,0,,假设我输入(BOSS ?Y COMPUTER) Dialogue: 0,0:36:44.22,0:36:45.78,Default,,0,0,0,,然后就会发生一件有意思的事儿 Dialogue: 0,0:36:45.78,0:36:50.25,Default,,0,0,0,,这里的字典就有一项?Y Dialogue: 0,0:36:52.73,0:36:57.37,Default,,0,0,0,,而这两个?Y是不相同的 Dialogue: 0,0:36:57.42,0:37:00.62,Default,,0,0,0,,后者是其它人的工作描述 Dialogue: 0,0:37:01.58,0:37:03.80,Default,,0,0,0,,因此 按照输入“照本宣科”地执行的话 Dialogue: 0,0:37:04.22,0:37:06.44,Default,,0,0,0,,我们就会遇到变量冲突的问题 Dialogue: 0,0:37:09.28,0:37:10.48,Default,,0,0,0,,所以我骗了你们一下 Dialogue: 0,0:37:10.93,0:37:13.84,Default,,0,0,0,,注意 我们之前也遇到过同样的问题 Dialogue: 0,0:37:14.27,0:37:15.56,Default,,0,0,0,,具体来说就是 Dialogue: 0,0:37:15.96,0:37:18.36,Default,,0,0,0,,一门语言需要局部变量 Dialogue: 0,0:37:19.24,0:37:21.74,Default,,0,0,0,,当我计算SQUARE和SUM-SQUARES的时候 Dialogue: 0,0:37:21.79,0:37:23.39,Default,,0,0,0,,这两个X应该是不同的 Dialogue: 0,0:37:24.96,0:37:26.32,Default,,0,0,0,,同样的道理 Dialogue: 0,0:37:27.39,0:37:29.77,Default,,0,0,0,,这两个?Y应该也不相同 Dialogue: 0,0:37:31.80,0:37:32.75,Default,,0,0,0,,我们知道该如何解决 Dialogue: 0,0:37:32.78,0:37:34.49,Default,,0,0,0,,就是引入环境模型 Dialogue: 0,0:37:34.51,0:37:37.04,Default,,0,0,0,,我们构建类似于“框架链”一类的东西 Dialogue: 0,0:37:37.71,0:37:39.10,Default,,0,0,0,,还有更加“粗暴”的解决方法 Dialogue: 0,0:37:39.10,0:37:41.73,Default,,0,0,0,,在查询语言中 我们根本不这么做 Dialogue: 0,0:37:41.73,0:37:43.18,Default,,0,0,0,,我们的解决方法非常粗暴 Dialogue: 0,0:37:43.54,0:37:45.93,Default,,0,0,0,,我们规定 每次你在应用一条规则的时候 Dialogue: 0,0:37:47.26,0:37:49.63,Default,,0,0,0,,用一个不会引起冲突的唯一名字 Dialogue: 0,0:37:49.77,0:37:53.50,Default,,0,0,0,,统一地为规则中的所有变量更名 Dialogue: 0,0:37:54.04,0:37:57.10,Default,,0,0,0,,这个从概念上来说更简单 Dialogue: 0,0:37:57.12,0:37:59.24,Default,,0,0,0,,但既粗暴 又不是很有效 Dialogue: 0,0:37:59.97,0:38:01.15,Default,,0,0,0,,但是请注意 Dialogue: 0,0:38:01.39,0:38:04.68,Default,,0,0,0,,如果我们对Lisp中定义的过程也这么处理 Dialogue: 0,0:38:05.50,0:38:08.72,Default,,0,0,0,,那么就不需要环境模型了 Dialogue: 0,0:38:08.75,0:38:11.56,Default,,0,0,0,,如果我们每次在应用一个过程的时候 Dialogue: 0,0:38:11.87,0:38:13.90,Default,,0,0,0,,我们为过程中的所有变量更名 Dialogue: 0,0:38:14.19,0:38:16.28,Default,,0,0,0,,那么我们就不需要担心局部变量了 Dialogue: 0,0:38:16.33,0:38:17.39,Default,,0,0,0,,因为它们不会出现 Dialogue: 0,0:38:19.04,0:38:20.41,Default,,0,0,0,,但这种做法比较低效 Dialogue: 0,0:38:20.91,0:38:23.04,Default,,0,0,0,,在我们的查询语言中同样也比较低效 Dialogue: 0,0:38:23.29,0:38:24.59,Default,,0,0,0,,但我们还是这样做了 并让它保持简单 Dialogue: 0,0:38:25.61,0:38:26.67,Default,,0,0,0,,有问题吗? Dialogue: 0,0:38:30.88,0:38:33.39,Default,,0,0,0,,学生:您这一小节开始的时候 Dialogue: 0,0:38:33.40,0:38:39.60,Default,,0,0,0,,就强调APPLY-EVAL模型是多么的强大 Dialogue: 0,0:38:39.63,0:38:41.17,Default,,0,0,0,,以至于任何语言都适用 Dialogue: 0,0:38:41.17,0:38:43.39,Default,,0,0,0,,但你又说这门语言将会非常不同 Dialogue: 0,0:38:43.95,0:38:45.13,Default,,0,0,0,,但最后却发现这门语言 Dialogue: 0,0:38:45.58,0:38:47.88,Default,,0,0,0,,就像你指出的那样--也是同样的 Dialogue: 0,0:38:47.88,0:38:49.85,Default,,0,0,0,,我在想 您是否是在论证 Dialogue: 0,0:38:50.48,0:38:54.57,Default,,0,0,0,,所有的语言都可以转化成 规则或过程的应用 Dialogue: 0,0:38:55.12,0:38:55.98,Default,,0,0,0,,或者类似的 Dialogue: 0,0:38:57.07,0:38:58.88,Default,,0,0,0,,教授:可以说 几乎所有语言 Dialogue: 0,0:38:58.92,0:39:00.30,Default,,0,0,0,,我们通过组合手段构建对象 Dialogue: 0,0:39:00.92,0:39:04.40,Default,,0,0,0,,用简单的名字给它们命名 Dialogue: 0,0:39:04.70,0:39:06.86,Default,,0,0,0,,你可以把任何类似的 比如 Dialogue: 0,0:39:07.79,0:39:09.90,Default,,0,0,0,,有一种一般性的表达式 Dialogue: 0,0:39:09.98,0:39:11.40,Default,,0,0,0,,比如说如何计算某数的平方 Dialogue: 0,0:39:12.03,0:39:14.20,Default,,0,0,0,,几乎所有的东西都可以称为“过程” Dialogue: 0,0:39:14.88,0:39:15.88,Default,,0,0,0,,如果语言中有这么一部分的话 Dialogue: 0,0:39:15.90,0:39:17.24,Default,,0,0,0,,那么你就需要能够展开它们 Dialogue: 0,0:39:18.02,0:39:20.19,Default,,0,0,0,,你需要有某种组织 使得 Dialogue: 0,0:39:20.57,0:39:24.03,Default,,0,0,0,,当你查看这些抽象变量 或者说标签的时候 Dialogue: 0,0:39:24.06,0:39:27.10,Default,,0,0,0,,它们可能代表着某些特定的东西 Dialogue: 0,0:39:28.33,0:39:29.34,Default,,0,0,0,,你必须一直跟踪它们 Dialogue: 0,0:39:29.39,0:39:30.91,Default,,0,0,0,,这就会形成类似于环境的结构 Dialogue: 0,0:39:31.72,0:39:32.54,Default,,0,0,0,,让后当你要 Dialogue: 0,0:39:32.70,0:39:35.26,Default,,0,0,0,,展开复合对象其中的一个部分的时候 Dialogue: 0,0:39:35.80,0:39:37.44,Default,,0,0,0,,你就需要EVAL-APPLY循环了 Dialogue: 0,0:39:39.97,0:39:43.20,Default,,0,0,0,,有很多很多的语言有这样的特点 Dialogue: 0,0:39:43.36,0:39:45.40,Default,,0,0,0,,它们也是按这种方式组织的 Dialogue: 0,0:39:45.59,0:39:47.20,Default,,0,0,0,,而这门语言特殊之处在于 Dialogue: 0,0:39:47.21,0:39:49.50,Default,,0,0,0,,从外界看 并没有“过程” Dialogue: 0,0:39:50.69,0:39:52.68,Default,,0,0,0,,而当你剖开表层 深入到实现中去 Dialogue: 0,0:39:52.70,0:39:54.24,Default,,0,0,0,,当然 你会发现本质是一样的 Dialogue: 0,0:39:54.87,0:39:56.95,Default,,0,0,0,,但是从外界来看 这是一种非常不同的世界观 Dialogue: 0,0:39:56.95,0:39:58.54,Default,,0,0,0,,你没有计算输入的函数 Dialogue: 0,0:40:03.97,0:40:05.71,Default,,0,0,0,,学生:您之前提到过 Dialogue: 0,0:40:06.60,0:40:09.55,Default,,0,0,0,,当用模式匹配来实现这些规则时 Dialogue: 0,0:40:10.01,0:40:11.42,Default,,0,0,0,,由于使用了流实现延迟求值 Dialogue: 0,0:40:11.45,0:40:12.72,Default,,0,0,0,,所以没有办法知道 Dialogue: 0,0:40:13.37,0:40:15.36,Default,,0,0,0,,对象的求值顺序 Dialogue: 0,0:40:15.58,0:40:15.94,Default,,0,0,0,,教授:是这样的 Dialogue: 0,0:40:15.94,0:40:18.28,Default,,0,0,0,,学生:但这就表明 Dialogue: 0,0:40:18.94,0:40:22.28,Default,,0,0,0,,我们只能表达总是为真的陈述性知识 Dialogue: 0,0:40:22.30,0:40:23.79,Default,,0,0,0,,语言并不支持时间序列 Dialogue: 0,0:40:23.95,0:40:25.47,Default,,0,0,0,,否则的话 后果就会-- Dialogue: 0,0:40:27.39,0:40:28.76,Default,,0,0,0,,教授:是的 非常正确 Dialogue: 0,0:40:28.82,0:40:29.48,Default,,0,0,0,,问题在于 Dialogue: 0,0:40:30.06,0:40:32.60,Default,,0,0,0,,这个本来就是用来处理陈述性知识的 Dialogue: 0,0:40:33.26,0:40:34.81,Default,,0,0,0,,而就我目前所演示的来说 不支持 Dialogue: 0,0:40:35.71,0:40:39.56,Default,,0,0,0,,休息之后我会向你们揭露这其中的丑陋之处 Dialogue: 0,0:40:40.83,0:40:42.60,Default,,0,0,0,,就如我目前所展示的 它只是进行逻辑运算 Dialogue: 0,0:40:43.07,0:40:44.52,Default,,0,0,0,,原理上来说 如果我们做的是逻辑运算 Dialogue: 0,0:40:44.54,0:40:46.81,Default,,0,0,0,,用什么顺序完成并不会造成影响 Dialogue: 0,0:40:48.84,0:40:51.55,Default,,0,0,0,,但是呢 Dialogue: 0,0:40:51.60,0:40:53.61,Default,,0,0,0,,当你在进行一些具有副作用的操作的时候 Dialogue: 0,0:40:53.68,0:40:55.20,Default,,0,0,0,,比如向数据库中添加项 Dialogue: 0,0:40:55.23,0:40:58.16,Default,,0,0,0,,从中取出项 等等操作 Dialogue: 0,0:40:58.75,0:41:00.83,Default,,0,0,0,,你就丧失了这类控制 Dialogue: 0,0:41:01.29,0:41:02.94,Default,,0,0,0,,因此 这就与Prolog完全不同 Dialogue: 0,0:41:02.94,0:41:05.15,Default,,0,0,0,,Prolog有各种功能 Dialogue: 0,0:41:05.16,0:41:07.79,Default,,0,0,0,,能够让你利用求值的顺序 Dialogue: 0,0:41:09.64,0:41:11.77,Default,,0,0,0,,人们也这么来写Prolog Dialogue: 0,0:41:11.77,0:41:14.04,Default,,0,0,0,,结果发现这样变得非常困难 Dialogue: 0,0:41:14.32,0:41:17.55,Default,,0,0,0,,但如果你是Prolog程序专家 你就可以这么做 Dialogue: 0,0:41:18.59,0:41:20.21,Default,,0,0,0,,但是我认为你们现在并不可以 Dialogue: 0,0:41:20.21,0:41:21.24,Default,,0,0,0,,它相当复杂 Dialogue: 0,0:41:21.72,0:41:23.64,Default,,0,0,0,,因为你们放弃了对事先安排的 Dialogue: 0,0:41:23.77,0:41:25.72,Default,,0,0,0,,求值顺序的控制权 Dialogue: 0,0:41:27.15,0:41:30.16,Default,,0,0,0,,学生:这就表明 当你有一个函数式映射时 Dialogue: 0,0:41:30.67,0:41:32.51,Default,,0,0,0,,而你最初在讲这门课的时候 Dialogue: 0,0:41:32.99,0:41:34.08,Default,,0,0,0,,你说过 Dialogue: 0,0:41:34.67,0:41:36.70,Default,,0,0,0,,我们在表述作为关系的陈述性知识 Dialogue: 0,0:41:37.15,0:41:38.81,Default,,0,0,0,,因为我们讨论的不是输入和输出 Dialogue: 0,0:41:41.21,0:41:43.37,Default,,0,0,0,,教授:这是关于“函数式”的双关语 Dialogue: 0,0:41:43.37,0:41:45.79,Default,,0,0,0,,一种是没有副作用 Dialogue: 0,0:41:46.20,0:41:48.16,Default,,0,0,0,,因此并不依赖于求值的顺序 Dialogue: 0,0:41:48.70,0:41:51.04,Default,,0,0,0,,还有就是数学意义上的“函数” Dialogue: 0,0:41:51.07,0:41:52.22,Default,,0,0,0,,有关于输入和输出 Dialogue: 0,0:41:52.59,0:41:54.36,Default,,0,0,0,,我想这就是你想表达的双关 Dialogue: 0,0:41:56.51,0:41:58.51,Default,,0,0,0,,学生:我对其中两条语句不太明白 Dialogue: 0,0:41:58.81,0:42:00.70,Default,,0,0,0,,也就是那两条有关BOSS的语句 Dialogue: 0,0:42:01.27,0:42:05.74,Default,,0,0,0,,是不是 第一条查询构建了一个数据库 Dialogue: 0,0:42:05.76,0:42:08.08,Default,,0,0,0,,然后第二条查询-- Dialogue: 0,0:42:09.07,0:42:10.12,Default,,0,0,0,,教授:抱歉 Dialogue: 0,0:42:12.44,0:42:15.16,Default,,0,0,0,,这里的意思是 如果我输入这样的查询 Dialogue: 0,0:42:16.12,0:42:18.44,Default,,0,0,0,,我应该最初就给你们举这个例子 Dialogue: 0,0:42:19.47,0:42:23.52,Default,,0,0,0,,如果我输入(JOB (BITDIDDLE BEN) (COMPUTER WIZARD)) Dialogue: 0,0:42:25.04,0:42:27.77,Default,,0,0,0,,系统会找到一处事实 Dialogue: 0,0:42:28.30,0:42:30.28,Default,,0,0,0,,来完全匹配这条查询 Dialogue: 0,0:42:30.86,0:42:33.28,Default,,0,0,0,,然后输出(JOB (BITDIDDLE BEN) (COMPUTER WIZARD)) Dialogue: 0,0:42:34.22,0:42:35.60,Default,,0,0,0,,如果没找到这样的匹配 Dialogue: 0,0:42:35.69,0:42:36.75,Default,,0,0,0,,它就什么也不输出 Dialogue: 0,0:42:37.40,0:42:39.55,Default,,0,0,0,,我应该这么来表述 Dialogue: 0,0:42:39.56,0:42:42.27,Default,,0,0,0,,这门语言是用来查询某个表述是否为真 Dialogue: 0,0:42:43.40,0:42:45.77,Default,,0,0,0,,这是逻辑式编程的目的之一 Dialogue: 0,0:42:46.41,0:42:49.34,Default,,0,0,0,,输入一条查询 要么得到结果 要么没有 Dialogue: 0,0:42:50.68,0:42:52.38,Default,,0,0,0,,因此 我这里想要演示的是 Dialogue: 0,0:42:52.41,0:42:54.80,Default,,0,0,0,,我想要在介绍合一算法前 Dialogue: 0,0:42:54.83,0:42:56.62,Default,,0,0,0,,举一个简单的例子 Dialogue: 0,0:42:57.48,0:42:58.11,Default,,0,0,0,,所以 我应该说 Dialogue: 0,0:42:58.14,0:43:00.96,Default,,0,0,0,,如果我想要检查 这个是否为真 Dialogue: 0,0:43:01.18,0:43:03.28,Default,,0,0,0,,我就可以将它输入 并看有没有任何输出 Dialogue: 0,0:43:05.16,0:43:06.27,Default,,0,0,0,,学生:然后第二条查询 Dialogue: 0,0:43:06.28,0:43:07.84,Default,,0,0,0,,教授:第二条就是真正意义上的“查询” Dialogue: 0,0:43:07.88,0:43:09.12,Default,,0,0,0,,学生:好的 真正的查询 Dialogue: 0,0:43:10.77,0:43:13.10,Default,,0,0,0,,教授:在这里它就会输出与?WHO相关的信息 Dialogue: 0,0:43:13.90,0:43:15.74,Default,,0,0,0,,就会有一个框架 存储着 Dialogue: 0,0:43:16.62,0:43:18.81,Default,,0,0,0,,?Z=?WHO ?D=COMPUTER Dialogue: 0,0:43:19.56,0:43:20.49,Default,,0,0,0,,这个会传递下去 Dialogue: 0,0:43:20.51,0:43:21.95,Default,,0,0,0,,传递到这里的时候 Dialogue: 0,0:43:22.01,0:43:23.25,Default,,0,0,0,,?WHO就会被绑定起来 Dialogue: 0,0:43:26.95,0:43:28.76,Default,,0,0,0,,学生:在合一那里 Dialogue: 0,0:43:29.18,0:43:35.96,Default,,0,0,0,,我还是不太清楚?WHO和?Z之间发生了什么 Dialogue: 0,0:43:36.46,0:43:39.58,Default,,0,0,0,,要进行合一的话 这里的规则说 Dialogue: 0,0:43:42.03,0:43:46.22,Default,,0,0,0,,你说过 两个模式变量之间不能互相绑定 Dialogue: 0,0:43:46.26,0:43:48.08,Default,,0,0,0,,教授:模式匹配器确实不能这样 Dialogue: 0,0:43:48.36,0:43:50.83,Default,,0,0,0,,但对合一算法来说 Dialogue: 0,0:43:51.92,0:43:54.01,Default,,0,0,0,,就是一个有存储三个变量的环境 Dialogue: 0,0:43:56.69,0:43:57.90,Default,,0,0,0,,其中?D=COMPUTER Dialogue: 0,0:43:58.52,0:44:00.19,Default,,0,0,0,,?Z=?WHO Dialogue: 0,0:44:01.83,0:44:05.26,Default,,0,0,0,,所以在稍后的匹配过程中 Dialogue: 0,0:44:07.20,0:44:10.38,Default,,0,0,0,,如果?WHO=3 Dialogue: 0,0:44:12.06,0:44:13.66,Default,,0,0,0,,那么当我再查找字典的时候 Dialogue: 0,0:44:14.00,0:44:16.40,Default,,0,0,0,,它会告诉我 因为?Z=?WHO 所以?Z=3 Dialogue: 0,0:44:18.36,0:44:20.44,Default,,0,0,0,,从某种意义上来说 你就只需要修改这一点 Dialogue: 0,0:44:20.46,0:44:21.98,Default,,0,0,0,,就可以把合一算法变成模式匹配器 Dialogue: 0,0:44:22.48,0:44:24.80,Default,,0,0,0,,学生:但是看起来你好像告诉了它 如何进行合一 Dialogue: 0,0:44:24.83,0:44:26.96,Default,,0,0,0,,就像你已经解好了方程 准备好了值 Dialogue: 0,0:44:26.99,0:44:29.23,Default,,0,0,0,,并把它们安排成这样 Dialogue: 0,0:44:29.77,0:44:31.24,Default,,0,0,0,,现在看起来就像是 Dialogue: 0,0:44:31.28,0:44:32.83,Default,,0,0,0,,你传递了一本字典 Dialogue: 0,0:44:32.88,0:44:34.86,Default,,0,0,0,,其中的两个变量是关联起来的 Dialogue: 0,0:44:34.88,0:44:37.23,Default,,0,0,0,,教授:实际上 我们在同时求解它们 Dialogue: 0,0:44:37.52,0:44:39.74,Default,,0,0,0,,这是因为我们想要一下得到整个答案 Dialogue: 0,0:44:40.54,0:44:42.81,Default,,0,0,0,,如果你观察它们是如何被递归地构建的 Dialogue: 0,0:44:42.81,0:44:43.74,Default,,0,0,0,,基本上就是这样了 Dialogue: 0,0:44:44.98,0:44:48.40,Default,,0,0,0,,学生:也就是确实要传递含有两个变量的字典? Dialogue: 0,0:44:48.40,0:44:49.11,Default,,0,0,0,,教授:是的 Dialogue: 0,0:44:49.11,0:44:49.68,Default,,0,0,0,,学生:然后把它们关联起来? Dialogue: 0,0:44:50.38,0:44:52.91,Default,,0,0,0,,教授:就像通常的字典那样 Dialogue: 0,0:44:54.35,0:44:56.06,Default,,0,0,0,,学生:你在讨论合一算法的时候 Dialogue: 0,0:44:56.09,0:45:00.19,Default,,0,0,0,,你说过在某些情况下 Dialogue: 0,0:45:00.75,0:45:03.98,Default,,0,0,0,,合一不能够完成 Dialogue: 0,0:45:04.03,0:45:04.30,Default,,0,0,0,,教授:是的 Dialogue: 0,0:45:04.97,0:45:08.46,Default,,0,0,0,,学生:那么 是否可以通过编写规则 Dialogue: 0,0:45:09.16,0:45:15.93,Default,,0,0,0,,或者 写入那些事先知道可解的形式 Dialogue: 0,0:45:16.48,0:45:18.54,Default,,0,0,0,,来使得合一算法能够完成 Dialogue: 0,0:45:18.76,0:45:22.94,Default,,0,0,0,,是否可以在规则中添加一些属性 Dialogue: 0,0:45:23.18,0:45:25.45,Default,,0,0,0,,或者向输入的形式中添加属性 Dialogue: 0,0:45:25.82,0:45:29.04,Default,,0,0,0,,来避免无法进行合一的窘境 Dialogue: 0,0:45:29.18,0:45:31.15,Default,,0,0,0,,PROFESSOR: 我想 你也同意 Dialogue: 0,0:45:31.47,0:45:35.26,Default,,0,0,0,,用非常受限的方式来编写查询 Dialogue: 0,0:45:35.60,0:45:36.67,Default,,0,0,0,,看 你遇到的是 Dialogue: 0,0:45:36.88,0:45:39.12,Default,,0,0,0,,仔细看 你遇到问题是在 Dialogue: 0,0:45:39.68,0:45:44.25,Default,,0,0,0,,用像这样的东西去匹配 Dialogue: 0,0:45:44.59,0:45:47.20,Default,,0,0,0,,具有这样结构的模式时 Dialogue: 0,0:45:47.55,0:45:55.30,Default,,0,0,0,,比如((A ?Y B) ?Y) Dialogue: 0,0:45:58.98,0:46:01.48,Default,,0,0,0,,这是你可能遇到问题的一个地方 Dialogue: 0,0:46:03.07,0:46:05.80,Default,,0,0,0,,学生:所以你可以在语法层次上处理它么? Dialogue: 0,0:46:06.14,0:46:08.76,Default,,0,0,0,,教授:你可以在写查询时 Dialogue: 0,0:46:08.76,0:46:10.49,Default,,0,0,0,,注意你的规则 Dialogue: 0,0:46:11.90,0:46:14.08,Default,,0,0,0,,学生:这个问题应该由 Dialogue: 0,0:46:14.11,0:46:16.27,Default,,0,0,0,,数据库的构建者考虑么? Dialogue: 0,0:46:16.57,0:46:17.80,Default,,0,0,0,,教授:这个问题 Dialogue: 0,0:46:19.93,0:46:22.01,Default,,0,0,0,,不完全是数据库的构建者 Dialogue: 0,0:46:22.04,0:46:23.61,Default,,0,0,0,,或者是表述规则的人 Dialogue: 0,0:46:24.01,0:46:25.31,Default,,0,0,0,,所需要考虑的 Dialogue: 0,0:46:25.80,0:46:29.79,Default,,0,0,0,,当你们仔细审查合一算法的代码时 Dialogue: 0,0:46:29.92,0:46:31.87,Default,,0,0,0,,你们会发现 Dialogue: 0,0:46:32.41,0:46:34.76,Default,,0,0,0,,它实际上在查询一个字典 Dialogue: 0,0:46:34.94,0:46:36.83,Default,,0,0,0,,它会问 ?Y的取值应该是什么? Dialogue: 0,0:46:37.26,0:46:41.42,Default,,0,0,0,,?Y应该是一个含有自包含的表达式么? Dialogue: 0,0:46:41.96,0:46:43.26,Default,,0,0,0,,这时候 合一算法就会说 Dialogue: 0,0:46:43.28,0:46:46.24,Default,,0,0,0,,哦 我正在求解一个不动点方程 Dialogue: 0,0:46:46.24,0:46:46.99,Default,,0,0,0,,我还是放弃吧 Dialogue: 0,0:46:48.59,0:46:51.91,Default,,0,0,0,,学生:你区分过数据库中的规则 Dialogue: 0,0:46:51.91,0:46:56.48,Default,,0,0,0,,这些规则是加入数据库的么? Dialogue: 0,0:46:56.95,0:46:57.36,Default,,0,0,0,,教授:是的 Dialogue: 0,0:46:57.87,0:46:58.87,Default,,0,0,0,,我应该这么来说 Dialogue: 0,0:46:58.87,0:47:00.33,Default,,0,0,0,,你们可以把规则看作 Dialogue: 0,0:47:00.60,0:47:02.65,Default,,0,0,0,,数据库中的其它东西 Dialogue: 0,0:47:03.71,0:47:06.81,Default,,0,0,0,,如果你想要检查数据库中需要检查的东西 Dialogue: 0,0:47:06.83,0:47:09.44,Default,,0,0,0,,它们就是存在于数据库中的虚拟事实 Dialogue: 0,0:47:09.44,0:47:12.32,Default,,0,0,0,,学生:但是在这个解释中 Dialogue: 0,0:47:12.43,0:47:17.26,Default,,0,0,0,,你就已经区分了数据库和规则本身 Dialogue: 0,0:47:18.23,0:47:19.90,Default,,0,0,0,,教授:是的 我应该不这么来说 Dialogue: 0,0:47:20.49,0:47:23.31,Default,,0,0,0,,这样做的唯一理由就是实现 Dialogue: 0,0:47:23.54,0:47:24.67,Default,,0,0,0,,当你们查看具体实现时 Dialogue: 0,0:47:24.68,0:47:27.50,Default,,0,0,0,,会发现其中有部分用来检查数据库中的 Dialogue: 0,0:47:27.55,0:47:29.85,Default,,0,0,0,,基本断言或者规则 Dialogue: 0,0:47:30.47,0:47:32.72,Default,,0,0,0,,这其中的真正原因就是 Dialogue: 0,0:47:32.78,0:47:34.56,Default,,0,0,0,,你不知道查询结果是以什么顺序输出的 Dialogue: 0,0:47:34.96,0:47:40.46,Default,,0,0,0,,而规则数据库和数据数据库 Dialogue: 0,0:47:40.48,0:47:43.68,Default,,0,0,0,,是通过某种延迟求值的方式合并的 Dialogue: 0,0:47:44.60,0:47:46.80,Default,,0,0,0,,这就使得顺序变得非常复杂 Dialogue: 0,0:47:55.44,0:47:56.09,Default,,0,0,0,,那好 我们休息一下 Dialogue: 0,0:47:56.30,0:48:09.90,Default,,0,0,0,,[音乐] Dialogue: 0,0:48:10.04,0:48:14.41,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:48:18.68,0:48:22.09,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:48:22.09,0:48:25.96,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:48:26.00,0:48:29.87,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 II Dialogue: 0,0:48:33.16,0:48:35.37,Default,,0,0,0,,我们已经学习了逻辑式语言与 Dialogue: 0,0:48:35.39,0:48:36.41,Default,,0,0,0,,规则系统的运行原理 Dialogue: 0,0:48:37.23,0:48:39.37,Default,,0,0,0,,现在 让我们来探讨一个更加深刻的问题 Dialogue: 0,0:48:40.12,0:48:41.28,Default,,0,0,0,,来看下它们意味着什么 Dialogue: 0,0:48:43.18,0:48:46.86,Default,,0,0,0,,这把我们带入到整个查询语言中 Dialogue: 0,0:48:46.99,0:48:48.67,Default,,0,0,0,,最微妙的部分 Dialogue: 0,0:48:49.21,0:48:53.07,Default,,0,0,0,,也就是它看起来与想象中不同的地方 Dialogue: 0,0:48:53.57,0:48:56.22,Default,,0,0,0,,AND、OR以及NOT Dialogue: 0,0:48:57.02,0:48:58.88,Default,,0,0,0,,以及规则的逻辑蕴含 Dialogue: 0,0:48:59.69,0:49:06.64,Default,,0,0,0,,并不是逻辑学中的与、或、非以及蕴含 Dialogue: 0,0:49:07.69,0:49:09.71,Default,,0,0,0,,让我来举一个实例 Dialogue: 0,0:49:09.91,0:49:12.22,Default,,0,0,0,,当然 如果我们有两个逻辑命题 Dialogue: 0,0:49:12.40,0:49:19.44,Default,,0,0,0,,那么(AND P Q)就应该 Dialogue: 0,0:49:20.00,0:49:22.59,Default,,0,0,0,,等同于(AND Q P) Dialogue: 0,0:49:23.10,0:49:24.51,Default,,0,0,0,,而(OR P Q)就应该 Dialogue: 0,0:49:24.78,0:49:26.51,Default,,0,0,0,,等同于(OR Q P) Dialogue: 0,0:49:28.67,0:49:30.09,Default,,0,0,0,,但我们来看看这里 Dialogue: 0,0:49:30.10,0:49:32.01,Default,,0,0,0,,这里是一个例子 Dialogue: 0,0:49:32.18,0:49:36.16,Default,,0,0,0,,来看看 在我们的数据库中 Dialogue: 0,0:49:36.28,0:49:40.14,Default,,0,0,0,,如何表示某人的级别高于他人 Dialogue: 0,0:49:40.14,0:49:42.89,Default,,0,0,0,,我们定义(OUTRANKED-BY ?S ?B)为 Dialogue: 0,0:49:44.64,0:49:48.62,Default,,0,0,0,,或者S是B的上司 Dialogue: 0,0:49:49.63,0:49:51.07,Default,,0,0,0,,或者这其中有某个中间经理M Dialogue: 0,0:49:51.10,0:49:55.82,Default,,0,0,0,,其中S是M的上司 M的级别又比B高 Dialogue: 0,0:49:59.64,0:50:02.31,Default,,0,0,0,,这是定义OUTRANKED-BY的一种方式 Dialogue: 0,0:50:02.31,0:50:04.16,Default,,0,0,0,,或者我们可以原封不动地写过来 Dialogue: 0,0:50:05.08,0:50:06.91,Default,,0,0,0,,除了在最底部的这里 Dialogue: 0,0:50:07.21,0:50:09.88,Default,,0,0,0,,我们颠倒一下这两个子句的顺序 Dialogue: 0,0:50:11.63,0:50:12.99,Default,,0,0,0,,当然 如果它们都是逻辑表达式的话 Dialogue: 0,0:50:13.00,0:50:14.88,Default,,0,0,0,,它们应该表示的是相同的东西 Dialogue: 0,0:50:16.69,0:50:17.31,Default,,0,0,0,,然而 Dialogue: 0,0:50:17.71,0:50:19.61,Default,,0,0,0,,在我们这个特定的实现中 Dialogue: 0,0:50:19.64,0:50:22.88,Default,,0,0,0,,如果你查询(OUTRANDKED-BY ?WHO (BITDIIDLE BEN)) Dialogue: 0,0:50:23.48,0:50:25.36,Default,,0,0,0,,你会发现 这条规则 Dialogue: 0,0:50:26.76,0:50:28.72,Default,,0,0,0,,会完美地生成答案 Dialogue: 0,0:50:30.04,0:50:31.98,Default,,0,0,0,,然而 这条规则会陷入无穷循环 Dialogue: 0,0:50:34.11,0:50:36.27,Default,,0,0,0,,其中的原因就是 Dialogue: 0,0:50:36.33,0:50:40.33,Default,,0,0,0,,这条规则会问谁比BEN BITDIDDLE级别高? Dialogue: 0,0:50:41.92,0:50:43.53,Default,,0,0,0,,它试图寻找一个S Dialogue: 0,0:50:43.88,0:50:46.22,Default,,0,0,0,,使得S比B的级别更高 其中B是BEN BITDIDDLE Dialogue: 0,0:50:47.50,0:50:49.63,Default,,0,0,0,,这会在一个子问题中重复出现 Dialogue: 0,0:50:50.33,0:50:51.98,Default,,0,0,0,,找到一个M Dialogue: 0,0:50:52.24,0:50:54.57,Default,,0,0,0,,使得M的级别高于BEN BITDIDDLE Dialogue: 0,0:50:55.61,0:50:57.36,Default,,0,0,0,,而对M没有限制 Dialogue: 0,0:50:58.56,0:51:00.40,Default,,0,0,0,,这就相当于为了解决这个问题 Dialogue: 0,0:51:01.42,0:51:03.29,Default,,0,0,0,,我就还需要求解同样的问题 Dialogue: 0,0:51:04.57,0:51:07.23,Default,,0,0,0,,在把它解出来后 我才检查SUPERVISOR关系 Dialogue: 0,0:51:08.00,0:51:09.16,Default,,0,0,0,,然而这条规则没有这样的问题 Dialogue: 0,0:51:09.18,0:51:12.35,Default,,0,0,0,,因为在它尝试找出这条OUTRANKED-BY规则之前 Dialogue: 0,0:51:12.94,0:51:15.26,Default,,0,0,0,,在这里已经对M施加过约束了 Dialogue: 0,0:51:18.38,0:51:20.94,Default,,0,0,0,,随意 这两条规则理论上是相同的 Dialogue: 0,0:51:20.99,0:51:22.67,Default,,0,0,0,,但实际上 其中一条会陷入无穷循环 Dialogue: 0,0:51:22.86,0:51:25.04,Default,,0,0,0,,而另一条不会 Dialogue: 0,0:51:26.72,0:51:29.77,Default,,0,0,0,,通过这个非常极端的例子 Dialogue: 0,0:51:29.79,0:51:32.65,Default,,0,0,0,,你会发现在逻辑式程序设计中 Dialogue: 0,0:51:34.28,0:51:38.70,Default,,0,0,0,,如果你改变了AND或OR所连接子句的顺序 Dialogue: 0,0:51:39.34,0:51:41.58,Default,,0,0,0,,你会发现效率上的巨大差异 Dialogue: 0,0:51:42.24,0:51:43.21,Default,,0,0,0,,我们刚刚就看到了 Dialogue: 0,0:51:43.55,0:51:46.54,Default,,0,0,0,,在无穷循环方面的巨大差异 Dialogue: 0,0:51:49.19,0:51:51.74,Default,,0,0,0,,同样的 这也跟输入规则 Dialogue: 0,0:51:52.00,0:51:53.31,Default,,0,0,0,,的顺序有关 Dialogue: 0,0:51:54.07,0:51:56.48,Default,,0,0,0,,向数据库查询规则的顺序 Dialogue: 0,0:51:56.70,0:51:59.95,Default,,0,0,0,,会极大程度上影响效率:比如得到答案 Dialogue: 0,0:52:00.46,0:52:02.60,Default,,0,0,0,,或者在某些顺序下陷入无穷循环 Dialogue: 0,0:52:03.84,0:52:07.29,Default,,0,0,0,,这些都跟 Dialogue: 0,0:52:07.63,0:52:10.04,Default,,0,0,0,,你检查这些规则的顺序有关 Dialogue: 0,0:52:10.95,0:52:14.41,Default,,0,0,0,,有些规则的蕴含路径会相当的长 Dialogue: 0,0:52:14.44,0:52:16.06,Default,,0,0,0,,而另外一些不会 Dialogue: 0,0:52:16.44,0:52:17.68,Default,,0,0,0,,但你事先并不知道 Dialogue: 0,0:52:17.72,0:52:19.16,Default,,0,0,0,,哪一个长 哪一个短 Dialogue: 0,0:52:19.30,0:52:21.48,Default,,0,0,0,,有很多研究都与此有关 Dialogue: 0,0:52:22.16,0:52:23.76,Default,,0,0,0,,其中大多数都是想通过 Dialogue: 0,0:52:23.95,0:52:26.97,Default,,0,0,0,,用并行的方法来实现逻辑式程序设计语言 Dialogue: 0,0:52:27.32,0:52:29.90,Default,,0,0,0,,某种意义上来说 就是并行地检查所有规则 Dialogue: 0,0:52:30.36,0:52:32.80,Default,,0,0,0,,一旦有一条搜索得到答案 就返回结果 Dialogue: 0,0:52:33.04,0:52:34.99,Default,,0,0,0,,如果某条路径陷入了无穷的推导 Dialogue: 0,0:52:35.02,0:52:38.25,Default,,0,0,0,,那么 你只需知道 内存和处理器都非常廉价 Dialogue: 0,0:52:38.28,0:52:40.49,Default,,0,0,0,,让它们根据你的需要一直搜寻就好了 Dialogue: 0,0:52:43.47,0:52:44.83,Default,,0,0,0,,尽管如此 与真正的逻辑相比 Dialogue: 0,0:52:45.18,0:52:50.49,Default,,0,0,0,,这门逻辑式语言还有一个更深刻的问题 Dialogue: 0,0:52:50.68,0:52:52.52,Default,,0,0,0,,我给你们演示的例子 Dialogue: 0,0:52:52.97,0:52:54.80,Default,,0,0,0,,只是会陷入无穷循环 Dialogue: 0,0:52:55.37,0:52:56.99,Default,,0,0,0,,但至少不会给你错误的答案 Dialogue: 0,0:52:58.37,0:53:03.64,Default,,0,0,0,,当我们开始严肃地把这门逻辑式语言 Dialogue: 0,0:53:03.68,0:53:05.24,Default,,0,0,0,,与真正的经典逻辑作比较时 Dialogue: 0,0:53:05.71,0:53:08.46,Default,,0,0,0,,就会发现其中最深层次的问题 Dialogue: 0,0:53:09.49,0:53:12.43,Default,,0,0,0,,让我们来看看真正的经典逻辑 Dialogue: 0,0:53:13.71,0:53:21.04,Default,,0,0,0,,所有的人类都是凡人 Dialogue: 0,0:53:22.35,0:53:23.45,Default,,0,0,0,,相当经典的逻辑命题 Dialogue: 0,0:53:24.39,0:53:28.67,Default,,0,0,0,,然后我们就依照最经典的传统 Dialogue: 0,0:53:29.24,0:53:32.46,Default,,0,0,0,,我们按照最传统的方式来做 Dialogue: 0,0:53:32.67,0:53:37.16,Default,,0,0,0,,所有的希腊人都是人类 Dialogue: 0,0:53:40.49,0:53:46.06,Default,,0,0,0,,苏格拉底是希腊人 Dialogue: 0,0:53:48.17,0:53:49.21,Default,,0,0,0,,然后我们又该写什么呢? Dialogue: 0,0:53:49.21,0:53:51.89,Default,,0,0,0,,经典逻辑中有一个三点符号 Dialogue: 0,0:53:51.89,0:53:54.33,Default,,0,0,0,,因此 我们得到了一个三段论 Dialogue: 0,0:53:54.64,0:53:59.55,Default,,0,0,0,,苏格拉底是凡人 Dialogue: 0,0:54:01.36,0:54:04.91,Default,,0,0,0,,这些都是真正的经典逻辑 Dialogue: 0,0:54:05.88,0:54:11.05,Default,,0,0,0,,把它跟我们经典逻辑数据库比较一下 Dialogue: 0,0:54:12.40,0:54:14.46,Default,,0,0,0,,这是一个经典逻辑数据库 Dialogue: 0,0:54:16.27,0:54:17.48,Default,,0,0,0,,(GREEK SOCRATES) Dialogue: 0,0:54:18.03,0:54:18.84,Default,,0,0,0,,(GREEK PLATO) Dialogue: 0,0:54:19.60,0:54:20.40,Default,,0,0,0,,(GREEK ZEUS) Dialogue: 0,0:54:20.84,0:54:21.98,Default,,0,0,0,,(GOD ZEUS) Dialogue: 0,0:54:24.12,0:54:29.96,Default,,0,0,0,,所有的人类都是凡人 Dialogue: 0,0:54:30.54,0:54:32.12,Default,,0,0,0,,为了证明某人是平凡的 Dialogue: 0,0:54:32.16,0:54:33.60,Default,,0,0,0,,只需要证明他是人类 Dialogue: 0,0:54:34.65,0:54:35.90,Default,,0,0,0,,所有的人类都是不可靠的 Dialogue: 0,0:54:38.90,0:54:40.98,Default,,0,0,0,,并且说所有的希腊人都是人类 并不正确 Dialogue: 0,0:54:40.98,0:54:44.41,Default,,0,0,0,,这条规则说 所有不是神的希腊人都是人类 Dialogue: 0,0:54:45.71,0:54:47.04,Default,,0,0,0,,因此为了证明某人是人类 Dialogue: 0,0:54:47.07,0:54:48.89,Default,,0,0,0,,只需要说明他是一个希腊人 并且不是神 Dialogue: 0,0:54:49.32,0:54:52.88,Default,,0,0,0,,任何一个希腊神的住址是奥林匹斯山 Dialogue: 0,0:54:54.32,0:54:57.16,Default,,0,0,0,,这就是一个小型经典逻辑数据库 Dialogue: 0,0:54:57.39,0:54:59.32,Default,,0,0,0,,确实 它运行得相当好 Dialogue: 0,0:54:59.49,0:55:02.09,Default,,0,0,0,,如果我们向其询问 Dialogue: 0,0:55:03.47,0:55:06.57,Default,,0,0,0,,苏格拉底是凡人么 不可靠么? Dialogue: 0,0:55:06.91,0:55:07.69,Default,,0,0,0,,它会输出:是 Dialogue: 0,0:55:07.77,0:55:09.71,Default,,0,0,0,,柏拉图是凡人并且不可靠么? Dialogue: 0,0:55:09.71,0:55:10.24,Default,,0,0,0,,它会回答:是 Dialogue: 0,0:55:10.68,0:55:12.21,Default,,0,0,0,,如果我们问宙斯是凡人么 Dialogue: 0,0:55:12.21,0:55:13.23,Default,,0,0,0,,它什么都不会找到 Dialogue: 0,0:55:14.90,0:55:15.96,Default,,0,0,0,,运行得非常完美 Dialogue: 0,0:55:16.54,0:55:20.12,Default,,0,0,0,,然而 如果我们想要把它扩展一下 Dialogue: 0,0:55:20.12,0:55:23.05,Default,,0,0,0,,让我们来定义一下什么是“完美生命体” Dialogue: 0,0:55:23.82,0:55:27.21,Default,,0,0,0,,我们把规则PERFECT定义为 Dialogue: 0,0:55:34.05,0:55:35.48,Default,,0,0,0,,我想这样来定义是正确的 Dialogue: 0,0:55:35.48,0:55:38.14,Default,,0,0,0,,如果你熟悉中世纪经院哲学 Dialogue: 0,0:55:38.44,0:55:40.17,Default,,0,0,0,,我想所谓“完美生命体”一定 Dialogue: 0,0:55:40.68,0:55:42.65,Default,,0,0,0,,既不是凡人 又不会不可靠 Dialogue: 0,0:55:44.10,0:55:56.84,Default,,0,0,0,,(AND (NOT (MORTAL ?X)) (NOT (FALLIBLE ?X))) Dialogue: 0,0:55:59.30,0:56:00.89,Default,,0,0,0,,这样 我们就定义了一个规则 Dialogue: 0,0:56:02.67,0:56:04.36,Default,,0,0,0,,来告诉系统 什么是“完美生命体” Dialogue: 0,0:56:05.79,0:56:07.69,Default,,0,0,0,,现在 我们就要 Dialogue: 0,0:56:08.06,0:56:10.17,Default,,0,0,0,,询问所有“完美生命体”的地址 Dialogue: 0,0:56:11.48,0:56:22.30,Default,,0,0,0,,(AND (ADDRESS ?X ?Y) (PERFECT ?X)) Dialogue: 0,0:56:23.48,0:56:24.97,Default,,0,0,0,,在这里 我们生成了 Dialogue: 0,0:56:24.99,0:56:27.80,Default,,0,0,0,,世界上最独有的邮件列表 Dialogue: 0,0:56:30.16,0:56:32.20,Default,,0,0,0,,为了查询所有完美生命体的地址 Dialogue: 0,0:56:32.24,0:56:33.47,Default,,0,0,0,,我们会输入像这样的查询 Dialogue: 0,0:56:33.83,0:56:35.44,Default,,0,0,0,,或者像这样输入 Dialogue: 0,0:56:36.24,0:56:50.57,Default,,0,0,0,,(AND (PERFECT ?X) (ADDRESS ?X ?Y)) Dialogue: 0,0:56:52.06,0:56:54.96,Default,,0,0,0,,假设我们把它输入进去 并尝试查询 Dialogue: 0,0:56:55.19,0:56:56.76,Default,,0,0,0,,这条查询会给我们答案 Dialogue: 0,0:56:57.65,0:57:00.00,Default,,0,0,0,,这条查询会输出:奥林匹斯山 Dialogue: 0,0:57:04.23,0:57:06.57,Default,,0,0,0,,而这条查询 什么也不会输出 Dialogue: 0,0:57:06.74,0:57:09.58,Default,,0,0,0,,它找不到完美生命体的地址 Dialogue: 0,0:57:11.64,0:57:12.51,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:57:12.51,0:57:13.44,Default,,0,0,0,,这又为什么不同? Dialogue: 0,0:57:14.23,0:57:15.69,Default,,0,0,0,,这个问题跟无穷循环没什么关系 Dialogue: 0,0:57:15.69,0:57:17.08,Default,,0,0,0,,这个的问题是答案不相同 Dialogue: 0,0:57:19.48,0:57:20.09,Default,,0,0,0,,原因就是 Dialogue: 0,0:57:20.38,0:57:22.32,Default,,0,0,0,,如果你们还记得NOT的实现的话 Dialogue: 0,0:57:23.50,0:57:24.84,Default,,0,0,0,,NOT是作为一个过滤器 Dialogue: 0,0:57:25.88,0:57:29.00,Default,,0,0,0,,NOT会接收一本字典 Dialogue: 0,0:57:29.05,0:57:31.56,Default,,0,0,0,,里面有可行解构成的框架 Dialogue: 0,0:57:31.79,0:57:33.16,Default,,0,0,0,,然后过滤出那些 Dialogue: 0,0:57:33.29,0:57:34.94,Default,,0,0,0,,满足某个条件的解 Dialogue: 0,0:57:34.97,0:57:36.11,Default,,0,0,0,,这就是我如何实现NOT的 Dialogue: 0,0:57:36.92,0:57:38.43,Default,,0,0,0,,如果你们仔细想想其中的原理 Dialogue: 0,0:57:40.11,0:57:42.65,Default,,0,0,0,,我创建了一个查询盒子 Dialogue: 0,0:57:43.32,0:57:47.39,Default,,0,0,0,,ADDRESS盒子的输出作为了PERFECT的输入 Dialogue: 0,0:57:50.29,0:57:51.00,Default,,0,0,0,,这就使得 Dialogue: 0,0:57:51.32,0:57:53.26,Default,,0,0,0,,ADDRESS盒子会创建出 Dialogue: 0,0:57:53.32,0:57:54.83,Default,,0,0,0,,我知道地址的人 Dialogue: 0,0:57:55.29,0:57:57.64,Default,,0,0,0,,这些都会被PERFECT中的NOT给过滤掉 Dialogue: 0,0:57:59.88,0:58:04.19,Default,,0,0,0,,所以它会丢弃掉那些满足平凡的或者不可靠的数据 Dialogue: 0,0:58:04.91,0:58:06.38,Default,,0,0,0,,而对于另外一种顺序来说 Dialogue: 0,0:58:06.73,0:58:09.12,Default,,0,0,0,,我以一个空框架开始的 Dialogue: 0,0:58:09.52,0:58:12.35,Default,,0,0,0,,但是这里PERFECT没有可以给NOT过滤的东西 Dialogue: 0,0:58:12.38,0:58:13.98,Default,,0,0,0,,所以这里不会有什么输出 Dialogue: 0,0:58:18.83,0:58:21.50,Default,,0,0,0,,这也就导致没有东西输入到ADDRESS中 Dialogue: 0,0:58:21.94,0:58:23.15,Default,,0,0,0,,因此 我得不到答案 Dialogue: 0,0:58:23.93,0:58:27.04,Default,,0,0,0,,在强调一下 这是因为NOT不会生成任何东西 Dialogue: 0,0:58:27.44,0:58:28.80,Default,,0,0,0,,NOT只会丢弃数据 Dialogue: 0,0:58:29.08,0:58:30.51,Default,,0,0,0,,如果我不向NOT传递东西的话 Dialogue: 0,0:58:30.52,0:58:31.74,Default,,0,0,0,,它也就不会输出 Dialogue: 0,0:58:32.02,0:58:33.77,Default,,0,0,0,,这样我就得到了错误的答案 Dialogue: 0,0:58:37.20,0:58:37.97,Default,,0,0,0,,我们又该如何修复它呢? Dialogue: 0,0:58:37.97,0:58:39.07,Default,,0,0,0,,当然 有很多办法 Dialogue: 0,0:58:39.36,0:58:40.91,Default,,0,0,0,,你可能认为 现在这样有点愚蠢 Dialogue: 0,0:58:41.41,0:58:44.90,Default,,0,0,0,,为什么要一开始就执行NOT呢? Dialogue: 0,0:58:44.96,0:58:47.48,Default,,0,0,0,,想要正确地实现NOT Dialogue: 0,0:58:47.84,0:58:50.08,Default,,0,0,0,,就是要认识到当你遇到NOT时 Dialogue: 0,0:58:50.33,0:58:52.09,Default,,0,0,0,,你应该首先生成好答案 Dialogue: 0,0:58:52.80,0:58:54.97,Default,,0,0,0,,然后通过字典把它们传递过来 Dialogue: 0,0:58:55.52,0:58:57.85,Default,,0,0,0,,然后再最后再做过滤 Dialogue: 0,0:58:58.56,0:59:02.01,Default,,0,0,0,,有些按照这种方式实现的逻辑式语言 Dialogue: 0,0:59:02.41,0:59:04.05,Default,,0,0,0,,能够解决这个问题 Dialogue: 0,0:59:06.80,0:59:08.97,Default,,0,0,0,,然而 还有一个更深刻的问题 Dialogue: 0,0:59:09.60,0:59:11.53,Default,,0,0,0,,也就是 哪个才是正确答案呢? Dialogue: 0,0:59:12.53,0:59:14.24,Default,,0,0,0,,是奥林匹斯山 还是没有呢? Dialogue: 0,0:59:15.37,0:59:18.73,Default,,0,0,0,,你可能会认为是奥林匹斯山 Dialogue: 0,0:59:18.76,0:59:20.73,Default,,0,0,0,,毕竟 宙斯在数据库中 Dialogue: 0,0:59:22.52,0:59:25.10,Default,,0,0,0,,宙斯不是平凡的 也不是不可靠的 Dialogue: 0,0:59:29.55,0:59:32.44,Default,,0,0,0,,因此你可能会认为宙斯满足 Dialogue: 0,0:59:34.30,0:59:44.03,Default,,0,0,0,,(NOT (MORTAL ZEUS))或者(NOT (FALLIBLE ZEUS)) Dialogue: 0,0:59:44.12,0:59:45.85,Default,,0,0,0,,但我们实际来看一看数据库 Dialogue: 0,0:59:47.92,0:59:48.46,Default,,0,0,0,,来看一下 Dialogue: 0,0:59:49.36,0:59:53.24,Default,,0,0,0,,它要如何知道宙斯不是不可靠的? Dialogue: 0,0:59:54.81,0:59:56.11,Default,,0,0,0,,这里面没有关于它的知识 Dialogue: 0,0:59:57.93,0:59:59.66,Default,,0,0,0,,里面只能得到人类是不可靠的 Dialogue: 0,1:00:02.16,1:00:04.12,Default,,0,0,0,,它又如何知道宙斯不是不可靠的呢? Dialogue: 0,1:00:04.48,1:00:05.93,Default,,0,0,0,,这其中没有相关的规则 Dialogue: 0,1:00:07.98,1:00:11.00,Default,,0,0,0,,它只是说 我没有这样的规则 Dialogue: 0,1:00:11.68,1:00:14.06,Default,,0,0,0,,我只能通过某人是人类来推断出他是平凡的 Dialogue: 0,1:00:14.08,1:00:15.68,Default,,0,0,0,,这也是它所知道关于“平凡”的所有东西 Dialogue: 0,1:00:16.69,1:00:19.85,Default,,0,0,0,,然而 如果你还记得古典神话的话 Dialogue: 0,1:00:19.87,1:00:23.48,Default,,0,0,0,,你就知道 古希腊众神是不平凡的 但都不可靠 Dialogue: 0,1:00:25.05,1:00:28.65,Default,,0,0,0,,所以 不能通过这些规则得到答案 Dialogue: 0,1:00:30.85,1:00:32.10,Default,,0,0,0,,但它又为什么推导出这些呢? Dialogue: 0,1:00:34.49,1:00:38.32,Default,,0,0,0,,显然 苏格拉底不会犯这类逻辑错误 Dialogue: 0,1:00:40.08,1:00:42.67,Default,,0,0,0,,在这门语言中 NOT并不是NOT Dialogue: 0,1:00:43.37,1:00:44.32,Default,,0,0,0,,不是逻辑非运算 Dialogue: 0,1:00:44.93,1:00:46.40,Default,,0,0,0,,这门语言中 NOT表示的是 Dialogue: 0,1:00:47.16,1:00:49.96,Default,,0,0,0,,不可以从数据库中推断出结果 Dialogue: 0,1:00:50.75,1:00:53.34,Default,,0,0,0,,而不是“非真” Dialogue: 0,1:00:55.02,1:00:56.30,Default,,0,0,0,,完全是天壤之别 Dialogue: 0,1:00:57.30,1:00:58.64,Default,,0,0,0,,很细微 但也很巨大 Dialogue: 0,1:00:59.25,1:01:00.27,Default,,0,0,0,,因此 实际上 Dialogue: 0,1:01:00.76,1:01:03.92,Default,,0,0,0,,如果什么都不知道 最好就说NOT Dialogue: 0,1:01:04.68,1:01:06.14,Default,,0,0,0,,如果你问它 Dialogue: 0,1:01:06.16,1:01:07.83,Default,,0,0,0,,宙斯是否喜欢巧克力冰激凌 Dialogue: 0,1:01:07.85,1:01:09.12,Default,,0,0,0,,它会说 这个查询当然非真 Dialogue: 0,1:01:10.64,1:01:12.51,Default,,0,0,0,,这些事情它都不知道 Dialogue: 0,1:01:12.59,1:01:17.34,Default,,0,0,0,,NOT表示:不能从你告知它的事实中推断出来 Dialogue: 0,1:01:18.28,1:01:22.44,Default,,0,0,0,,换句话说 你要把“无法推断出” Dialogue: 0,1:01:22.65,1:01:24.00,Default,,0,0,0,,与“命题非真”区别开来 Dialogue: 0,1:01:24.41,1:01:26.30,Default,,0,0,0,,这被称作是“封闭世界假说” Dialogue: 0,1:01:37.37,1:01:38.17,Default,,0,0,0,,封闭世界假说 Dialogue: 0,1:01:38.20,1:01:42.38,Default,,0,0,0,,只要结论不能通过我所知道的知识推断出来 Dialogue: 0,1:01:43.50,1:01:44.36,Default,,0,0,0,,那么就不是真的 Dialogue: 0,1:01:46.24,1:01:48.01,Default,,0,0,0,,对吧 如果我对X一无所知 Dialogue: 0,1:01:48.22,1:01:49.21,Default,,0,0,0,,那么X就非真 Dialogue: 0,1:01:49.29,1:01:50.33,Default,,0,0,0,,这相当危险 Dialogue: 0,1:01:51.29,1:01:52.44,Default,,0,0,0,,首先 从逻辑学的角度来说 Dialogue: 0,1:01:52.46,1:01:53.76,Default,,0,0,0,,它一点也说不通 Dialogue: 0,1:01:54.48,1:01:56.33,Default,,0,0,0,,因为如果我对X一无所知的话 Dialogue: 0,1:01:58.38,1:01:59.69,Default,,0,0,0,,就说X非真 Dialogue: 0,1:02:00.24,1:02:03.32,Default,,0,0,0,,但为什么不说“X非真”非真 Dialogue: 0,1:02:03.85,1:02:05.66,Default,,0,0,0,,当然 我也许对后面那个命题也一无所知 Dialogue: 0,1:02:06.47,1:02:08.65,Default,,0,0,0,,因此(NOT (NOT X))就没有必要与X一致 Dialogue: 0,1:02:09.24,1:02:10.94,Default,,0,0,0,,等等等等 Dialogue: 0,1:02:11.71,1:02:13.93,Default,,0,0,0,,因此 这里面一定有某种“偏见” Dialogue: 0,1:02:15.97,1:02:17.29,Default,,0,0,0,,这相当有趣 Dialogue: 0,1:02:17.29,1:02:18.09,Default,,0,0,0,,第二点就是 Dialogue: 0,1:02:20.14,1:02:24.12,Default,,0,0,0,,如果你基于此 构建一个真正的推理程序 Dialogue: 0,1:02:24.70,1:02:26.11,Default,,0,0,0,,想一想是多么地危险 Dialogue: 0,1:02:27.07,1:02:32.00,Default,,0,0,0,,你说我知道我可以推断出 Dialogue: 0,1:02:32.22,1:02:36.22,Default,,0,0,0,,与这个问题有关的所有事情 Dialogue: 0,1:02:37.44,1:02:40.78,Default,,0,0,0,,因为在我推理机制的内部 Dialogue: 0,1:02:41.23,1:02:44.20,Default,,0,0,0,,会认为所有与问题有关的知识 Dialogue: 0,1:02:44.24,1:02:46.27,Default,,0,0,0,,我都已经知道了 Dialogue: 0,1:02:48.44,1:02:53.04,Default,,0,0,0,,有相当多的大型组织都像这样运作 对吧? Dialogue: 0,1:02:53.16,1:02:56.83,Default,,0,0,0,,大多数公司的市场部门都是这样工作的。 Dialogue: 0,1:02:56.83,1:02:59.12,Default,,0,0,0,,你们也知道这样做的后果 Dialogue: 0,1:03:00.33,1:03:03.45,Default,,0,0,0,,因此 向这个大型逻辑推理系统 Dialogue: 0,1:03:03.84,1:03:06.25,Default,,0,0,0,,输入各种查询 根据输出继续工作 Dialogue: 0,1:03:07.05,1:03:09.00,Default,,0,0,0,,的做法相当危险 Dialogue: 0,1:03:09.02,1:03:11.28,Default,,0,0,0,,因为它们内建的假说非常地有限 Dialogue: 0,1:03:12.60,1:03:14.36,Default,,0,0,0,,因此你对此需要非常非常地小心 Dialogue: 0,1:03:15.29,1:03:16.28,Default,,0,0,0,,就是这么一个深层次问题 Dialogue: 0,1:03:16.56,1:03:17.82,Default,,0,0,0,,这个问题并不是 Dialogue: 0,1:03:18.22,1:03:20.14,Default,,0,0,0,,通过构建更加聪明的实现 Dialogue: 0,1:03:20.16,1:03:21.85,Default,,0,0,0,,或者通过组织无穷循环 Dialogue: 0,1:03:22.16,1:03:23.84,Default,,0,0,0,,以及过滤器就可以消除的 Dialogue: 0,1:03:23.84,1:03:25.08,Default,,0,0,0,,这是完全不同的一类问题 Dialogue: 0,1:03:25.92,1:03:26.89,Default,,0,0,0,,完全不同的语义 Dialogue: 0,1:03:27.06,1:03:30.51,Default,,0,0,0,,我想该总结一下了 平心而论 Dialogue: 0,1:03:31.34,1:03:34.43,Default,,0,0,0,,逻辑式程序设计是一个振奋人心的想法 Dialogue: 0,1:03:34.60,1:03:37.00,Default,,0,0,0,,这个想法使你能够弥合 Dialogue: 0,1:03:37.04,1:03:38.78,Default,,0,0,0,,命令式与声明式语言的鸿沟 Dialogue: 0,1:03:39.90,1:03:42.94,Default,,0,0,0,,使得你可以谈论关系 Dialogue: 0,1:03:43.58,1:03:45.08,Default,,0,0,0,,从而获得惊人的力量 Dialogue: 0,1:03:46.09,1:03:49.48,Default,,0,0,0,,让你超越输入和输出的抽象 Dialogue: 0,1:03:50.56,1:03:51.53,Default,,0,0,0,,而关于逻辑 Dialogue: 0,1:03:52.46,1:03:56.46,Default,,0,0,0,,我认为这个问题还尚未解决 Dialogue: 0,1:03:58.03,1:04:01.80,Default,,0,0,0,,也许现在语言中最令人感兴趣的 Dialogue: 0,1:04:02.27,1:04:04.41,Default,,0,0,0,,研究问题之一就是 Dialogue: 0,1:04:04.67,1:04:08.28,Default,,0,0,0,,你该如何创建一门真正的逻辑语言? Dialogue: 0,1:04:09.46,1:04:11.05,Default,,0,0,0,,其次 你如何从 Dialogue: 0,1:04:11.31,1:04:13.15,Default,,0,0,0,,这个逻辑和关系的世界 Dialogue: 0,1:04:13.52,1:04:16.43,Default,,0,0,0,,到更传统语言的世界之间 Dialogue: 0,1:04:16.46,1:04:17.98,Default,,0,0,0,,架起桥梁并结合两者的力量 Dialogue: 0,1:04:18.88,1:04:19.68,Default,,0,0,0,,有什么问题吗? Dialogue: 0,1:04:23.29,1:04:25.29,Default,,0,0,0,,学生:你能够通过添加额外的规则 Dialogue: 0,1:04:25.29,1:04:27.74,Default,,0,0,0,,来解决最后一个问题么? Dialogue: 0,1:04:27.96,1:04:29.85,Default,,0,0,0,,这里的困境是:你有某物的定义 Dialogue: 0,1:04:29.88,1:04:31.82,Default,,0,0,0,,但没有它对立面的定义 Dialogue: 0,1:04:32.08,1:04:33.92,Default,,0,0,0,,如果你在数据库中有 Dialogue: 0,1:04:34.14,1:04:36.89,Default,,0,0,0,,某些规则推导出(MORTAL X) Dialogue: 0,1:04:36.99,1:04:38.70,Default,,0,0,0,,另外一些规则推导出(NOT (MORTAL X)) Dialogue: 0,1:04:38.75,1:04:40.37,Default,,0,0,0,,这不就基本上解决这个问题么? Dialogue: 0,1:04:43.37,1:04:44.14,Default,,0,0,0,,教授:但问题就是 Dialogue: 0,1:04:44.75,1:04:46.38,Default,,0,0,0,,添加的这些规则是有穷个么? Dialogue: 0,1:04:48.65,1:04:53.13,Default,,0,0,0,,学生:如果你同时定义正、反两面 -- Dialogue: 0,1:04:53.61,1:04:57.07,Default,,0,0,0,,教授:但问题就是 你该如何去做推断? Dialogue: 0,1:05:00.20,1:05:02.11,Default,,0,0,0,,要知道 你不能直接定义命题的非 Dialogue: 0,1:05:03.40,1:05:04.76,Default,,0,0,0,,而问题就在于 在大型系统中 Dialogue: 0,1:05:04.78,1:05:07.96,Default,,0,0,0,,可能含有无穷个数的东西 Dialogue: 0,1:05:12.82,1:05:15.29,Default,,0,0,0,,这其中有两个问题 Dialogue: 0,1:05:15.29,1:05:16.56,Default,,0,0,0,,其一是可能有无穷项 Dialogue: 0,1:05:16.69,1:05:19.39,Default,,0,0,0,,另外是因为可能不向你想的那样 Dialogue: 0,1:05:21.51,1:05:24.52,Default,,0,0,0,,一个极好的例子 就是连通性 Dialogue: 0,1:05:25.12,1:05:26.54,Default,,0,0,0,,我想对连通性做推理 Dialogue: 0,1:05:28.05,1:05:30.38,Default,,0,0,0,,我会告诉你这有四个对象 Dialogue: 0,1:05:30.40,1:05:33.74,Default,,0,0,0,,A、B、C和D Dialogue: 0,1:05:35.48,1:05:38.19,Default,,0,0,0,,我会告诉你A和B相连 Dialogue: 0,1:05:38.64,1:05:41.42,Default,,0,0,0,,C和D相连 Dialogue: 0,1:05:43.20,1:05:44.80,Default,,0,0,0,,然后我再告诉你A和D相连 Dialogue: 0,1:05:45.05,1:05:46.03,Default,,0,0,0,,就是这种情况 Dialogue: 0,1:05:46.78,1:05:48.52,Default,,0,0,0,,在这个例子中 Dialogue: 0,1:05:48.70,1:05:50.35,Default,,0,0,0,,我就希望有“封闭世界假说”这样的东西 Dialogue: 0,1:05:54.43,1:05:55.66,Default,,0,0,0,,这是个小玩具 Dialogue: 0,1:05:56.24,1:05:58.30,Default,,0,0,0,,但是很多时候 我都想说 Dialogue: 0,1:05:58.48,1:06:01.34,Default,,0,0,0,,我没告诉你的事 都假设非真 Dialogue: 0,1:06:04.26,1:06:06.27,Default,,0,0,0,,所以这并不是你显式地 Dialogue: 0,1:06:06.27,1:06:08.09,Default,,0,0,0,,为所有命题定义否命题就可以解决的 Dialogue: 0,1:06:09.47,1:06:12.70,Default,,0,0,0,,而是有些时候 你不清楚自己真正想要什么 Dialogue: 0,1:06:14.15,1:06:17.92,Default,,0,0,0,,同时定义原命题与否命题又太过于精细 Dialogue: 0,1:06:17.93,1:06:20.00,Default,,0,0,0,,这会使你陷入困境 Dialogue: 0,1:06:20.96,1:06:22.68,Default,,0,0,0,,但还是有很多方法 Dialogue: 0,1:06:23.32,1:06:25.93,Default,,0,0,0,,显式地定义否命题 并基于此进行推理 Dialogue: 0,1:06:26.51,1:06:27.66,Default,,0,0,0,,这个想法非常好 Dialogue: 0,1:06:28.07,1:06:31.45,Default,,0,0,0,,只是在一些复杂的大型问题中 Dialogue: 0,1:06:31.48,1:06:33.49,Default,,0,0,0,,这么做就变得有些笨重了 Dialogue: 0,1:06:43.46,1:06:45.96,Default,,0,0,0,,学生:有个论点 我不知道它和本节课的直接关系 Dialogue: 0,1:06:46.00,1:06:47.98,Default,,0,0,0,,但你想要表达的是 Dialogue: 0,1:06:48.49,1:06:50.16,Default,,0,0,0,,封闭世界假说的危害之一就是 Dialogue: 0,1:06:50.19,1:06:52.06,Default,,0,0,0,,你永远不会真正了解那里的所有事物 Dialogue: 0,1:06:53.44,1:06:55.32,Default,,0,0,0,,你永远不会知道它们的每个部分 Dialogue: 0,1:06:55.87,1:06:58.16,Default,,0,0,0,,这难道不是任何一门程序设计语言的主要问题吗? Dialogue: 0,1:06:58.16,1:06:59.64,Default,,0,0,0,,写程序时 我总是 Dialogue: 0,1:06:59.90,1:07:01.56,Default,,0,0,0,,假设我考虑了所有的情况 Dialogue: 0,1:07:01.58,1:07:03.40,Default,,0,0,0,,然后我检查了每一种情况 Dialogue: 0,1:07:04.06,1:07:04.99,Default,,0,0,0,,然而在某处 Dialogue: 0,1:07:05.02,1:07:06.52,Default,,0,0,0,,我发现了我遗漏了其中的一个 Dialogue: 0,1:07:07.39,1:07:08.54,Default,,0,0,0,,教授:你说得很对 Dialogue: 0,1:07:08.54,1:07:09.76,Default,,0,0,0,,但这里的问题在于 Dialogue: 0,1:07:11.96,1:07:15.47,Default,,0,0,0,,对于你所做的事情 Dialogue: 0,1:07:15.48,1:07:17.34,Default,,0,0,0,,你是否认为它是逻辑问题 Dialogue: 0,1:07:19.60,1:07:20.51,Default,,0,0,0,,你说得非常正确 Dialogue: 0,1:07:20.51,1:07:22.22,Default,,0,0,0,,这是你永远不会遇到的情况 Dialogue: 0,1:07:22.22,1:07:24.14,Default,,0,0,0,,问题在于 如果你认为 Dialogue: 0,1:07:24.17,1:07:25.44,Default,,0,0,0,,你在进行逻辑式程序设计 Dialogue: 0,1:07:26.17,1:07:27.32,Default,,0,0,0,,然后审视你所编写的规则 Dialogue: 0,1:07:27.34,1:07:28.89,Default,,0,0,0,,并思考能从中推断出什么 Dialogue: 0,1:07:29.53,1:07:32.80,Default,,0,0,0,,你就需要清醒地认识到NOT具有另外的意义 Dialogue: 0,1:07:33.47,1:07:35.21,Default,,0,0,0,,它的意义基于某种假设 Dialogue: 0,1:07:35.24,1:07:36.70,Default,,0,0,0,,并且可能并不正确 Dialogue: 0,1:07:39.03,1:07:40.19,Default,,0,0,0,,学生:我不知道这样理解是否正确 Dialogue: 0,1:07:40.25,1:07:41.84,Default,,0,0,0,,也就是我们无法通过改变NOT Dialogue: 0,1:07:42.25,1:07:46.08,Default,,0,0,0,,来消灭推断的所有可能性 从而解决这个问题? Dialogue: 0,1:07:46.54,1:07:49.80,Default,,0,0,0,,教授:不 并不是这样 Dialogue: 0,1:07:52.96,1:07:55.08,Default,,0,0,0,,有很多种方法可以实现真正的逻辑非 Dialogue: 0,1:07:56.34,1:07:58.03,Default,,0,0,0,,实际上有很多种方法 Dialogue: 0,1:07:58.54,1:08:00.84,Default,,0,0,0,,但目前没有一个广为人知的高效算法 Dialogue: 0,1:08:01.61,1:08:02.56,Default,,0,0,0,,而且他们还-- Dialogue: 0,1:08:04.09,1:08:06.89,Default,,0,0,0,,这里所谓的“推论” Dialogue: 0,1:08:07.39,1:08:08.83,Default,,0,0,0,,是建立在这个合一算法 Dialogue: 0,1:08:08.91,1:08:11.29,Default,,0,0,0,,以及模式匹配算法之中的 Dialogue: 0,1:08:11.98,1:08:16.19,Default,,0,0,0,,有多种方法可以实现真正的逻辑推理 Dialogue: 0,1:08:16.59,1:08:18.19,Default,,0,0,0,,但它们并不基于此 Dialogue: 0,1:08:18.51,1:08:20.73,Default,,0,0,0,,而逻辑式程序设计语言也不倾向于这么做 Dialogue: 0,1:08:20.75,1:08:23.85,Default,,0,0,0,,因为大家都知道 那样做非常低效 Dialogue: 0,1:08:29.39,1:08:30.03,Default,,0,0,0,,好吧 下课 Dialogue: 0,1:08:30.03,1:08:42.68,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:08:30.03,1:08:42.68,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec8b.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Audio File: ../../../../Movies/lec8b_480_muxed.mp4 Video File: ../../../../Movies/lec8b_480_muxed.mp4 Video AR Mode: 4 Video AR Value: 1.333333 Video Zoom Percent: 2.000000 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.00,0:00:02.14,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP 学习小组\N倾情制作 Dialogue: 0,0:00:02.40,0:00:09.84,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:02.40,0:00:09.84,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.40,0:00:09.84,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.40,0:00:09.84,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.40,0:00:09.84,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:09.90,0:00:16.04,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 II Dialogue: 0,0:00:18.91,0:00:21.79,Default,,0,0,0,,我们已经了解了查询语言的使用方式 Dialogue: 0,0:00:22.64,0:00:25.07,Default,,0,0,0,,现在该来讨论如何实现了 Dialogue: 0,0:00:26.28,0:00:27.98,Default,,0,0,0,,你们也应该能够猜到 Dialogue: 0,0:00:28.59,0:00:29.47,Default,,0,0,0,,它其中的原理了 Dialogue: 0,0:00:29.47,0:00:31.64,Default,,0,0,0,,它的最底层是一个模式匹配器 Dialogue: 0,0:00:32.81,0:00:34.25,Default,,0,0,0,,我们在《基于规则的控制语言》一课中 Dialogue: 0,0:00:34.67,0:00:36.94,Default,,0,0,0,,已经介绍过模式匹配器了 Dialogue: 0,0:00:38.11,0:00:40.59,Default,,0,0,0,,我举个例子来让你们温习一下 Dialogue: 0,0:00:41.52,0:00:43.68,Default,,0,0,0,,这个模式会匹配 Dialogue: 0,0:00:43.80,0:00:44.92,Default,,0,0,0,,一个含有三个元素的表 Dialogue: 0,0:00:44.96,0:00:47.10,Default,,0,0,0,,其中 首元素为A Dialogue: 0,0:00:47.16,0:00:48.33,Default,,0,0,0,,其次是C Dialogue: 0,0:00:48.48,0:00:50.19,Default,,0,0,0,,而中间可以为任意元素 Dialogue: 0,0:00:50.65,0:00:52.27,Default,,0,0,0,,所以在这个小型的模式匹配语言中 Dialogue: 0,0:00:52.30,0:00:54.05,Default,,0,0,0,,你只能区分一种类型 Dialogue: 0,0:00:54.05,0:00:57.20,Default,,0,0,0,,也就是区分字面量或者变量 Dialogue: 0,0:00:57.23,0:00:58.86,Default,,0,0,0,,以问号开头的就是变量 Dialogue: 0,0:01:01.37,0:01:03.64,Default,,0,0,0,,因此这个模式会匹配任意的三元表 Dialogue: 0,0:01:04.44,0:01:06.50,Default,,0,0,0,,只要它的首元素为A 而第三个元素为C Dialogue: 0,0:01:06.50,0:01:09.00,Default,,0,0,0,,而这个模式匹配的三元表 Dialogue: 0,0:01:10.43,0:01:12.53,Default,,0,0,0,,它的首元素必须是符号'JOB Dialogue: 0,0:01:12.53,0:01:13.90,Default,,0,0,0,,第二个元素为任意值 Dialogue: 0,0:01:14.21,0:01:15.90,Default,,0,0,0,,第三个元素必须是一个二元表 Dialogue: 0,0:01:15.95,0:01:17.72,Default,,0,0,0,,二元表的首元素为符号'COMPUTER Dialogue: 0,0:01:17.88,0:01:19.42,Default,,0,0,0,,第二个元素可以为任意值 Dialogue: 0,0:01:20.48,0:01:25.55,Default,,0,0,0,,而下一条模式所匹配的三元表 Dialogue: 0,0:01:25.87,0:01:26.99,Default,,0,0,0,,区别就在于 Dialogue: 0,0:01:28.40,0:01:31.32,Default,,0,0,0,,在于第三个元素的首元素必须为符号'COMPUTER Dialogue: 0,0:01:31.76,0:01:33.29,Default,,0,0,0,,表剩余部分可以是任意值 Dialogue: 0,0:01:35.04,0:01:37.53,Default,,0,0,0,,也就是说 上面是二元表 而下面没有限定数目 Dialogue: 0,0:01:37.86,0:01:39.74,Default,,0,0,0,,然而我们的语言实现 Dialogue: 0,0:01:39.85,0:01:42.06,Default,,0,0,0,,根本不用操心如何去实现这个点号 Dialogue: 0,0:01:42.11,0:01:44.17,Default,,0,0,0,,因为这个由Lisp读取器自动地完成 Dialogue: 0,0:01:48.34,0:01:50.31,Default,,0,0,0,,要注意 匹配器还要保持一致性 Dialogue: 0,0:01:50.31,0:01:52.32,Default,,0,0,0,,这个模式匹配一个三元表 Dialogue: 0,0:01:52.59,0:01:53.98,Default,,0,0,0,,表的首元素是A Dialogue: 0,0:01:54.43,0:01:55.79,Default,,0,0,0,,而第二个元素和第三个元素可以是任意值 Dialogue: 0,0:01:55.80,0:01:57.08,Default,,0,0,0,,但它们必须是相同的 Dialogue: 0,0:01:57.94,0:01:58.84,Default,,0,0,0,,它们都是?X Dialogue: 0,0:01:59.60,0:02:01.55,Default,,0,0,0,,而这个模式匹配一个四元表 Dialogue: 0,0:02:01.96,0:02:03.26,Default,,0,0,0,,其中第一个元素与第四个元素相同 Dialogue: 0,0:02:03.66,0:02:05.15,Default,,0,0,0,,而第二个元素与第三个元素相同 Dialogue: 0,0:02:05.59,0:02:08.60,Default,,0,0,0,,最后一个模式匹配以A开头的任意表 Dialogue: 0,0:02:09.68,0:02:11.05,Default,,0,0,0,,以A开头 Dialogue: 0,0:02:11.23,0:02:12.56,Default,,0,0,0,,余下的可以是任意值 Dialogue: 0,0:02:14.04,0:02:16.60,Default,,0,0,0,,这是对我们已经学习过的模式匹配语言 Dialogue: 0,0:02:16.62,0:02:17.87,Default,,0,0,0,,的一个回顾 Dialogue: 0,0:02:18.78,0:02:19.64,Default,,0,0,0,,还记得吗 Dialogue: 0,0:02:19.79,0:02:22.28,Default,,0,0,0,,这是由一个叫做MATCH的过程实现的 Dialogue: 0,0:02:24.87,0:02:36.06,Default,,0,0,0,,MATCH有三个参数:PAT、DATA以及DICTIONARY Dialogue: 0,0:02:43.20,0:02:47.12,Default,,0,0,0,,MATCH考虑的是 Dialogue: 0,0:02:47.79,0:02:52.64,Default,,0,0,0,,利用给定DICTIONAY中的绑定 Dialogue: 0,0:02:53.55,0:02:56.73,Default,,0,0,0,,能够找到一种方法把模式与数据对象匹配起来吗? Dialogue: 0,0:02:58.16,0:02:59.21,Default,,0,0,0,,比如说 Dialogue: 0,0:02:59.56,0:03:06.43,Default,,0,0,0,,如果我们想要把模式(?X ?Y ?Y ?X) Dialogue: 0,0:03:07.71,0:03:13.84,Default,,0,0,0,,与数据对象(A B B A)相匹配 Dialogue: 0,0:03:15.12,0:03:20.52,Default,,0,0,0,,又给定了一个字典 X=A Dialogue: 0,0:03:22.01,0:03:25.23,Default,,0,0,0,,MATCH就会说:“它们是一致的” Dialogue: 0,0:03:25.26,0:03:27.16,Default,,0,0,0,,再给定的字典说 X=A 的情况下 Dialogue: 0,0:03:27.80,0:03:30.20,Default,,0,0,0,,模式与数据相匹配 Dialogue: 0,0:03:30.32,0:03:31.60,Default,,0,0,0,,而匹配的结果则是 Dialogue: 0,0:03:32.25,0:03:34.30,Default,,0,0,0,,一个扩展了的词典 Dialogue: 0,0:03:34.46,0:03:37.60,Default,,0,0,0,,其中包含 X=A Y=B Dialogue: 0,0:03:39.49,0:03:42.24,Default,,0,0,0,,MATCH接收模式、数据以及字典 Dialogue: 0,0:03:42.38,0:03:44.54,Default,,0,0,0,,如果成功匹配就输出一个扩展后的词典 Dialogue: 0,0:03:44.97,0:03:46.84,Default,,0,0,0,,否则就报错 Dialogue: 0,0:03:46.84,0:03:47.71,Default,,0,0,0,,因此 比如说 Dialogue: 0,0:03:47.88,0:03:50.38,Default,,0,0,0,,如果我在这里使用同样的模式 Dialogue: 0,0:03:50.97,0:03:55.12,Default,,0,0,0,,如果我用模式(?X ?Y ?Y ?X) Dialogue: 0,0:03:55.66,0:03:58.49,Default,,0,0,0,,去匹配(A B B A) Dialogue: 0,0:03:59.47,0:04:02.84,Default,,0,0,0,,并给定词典 Y=A Dialogue: 0,0:04:05.15,0:04:06.81,Default,,0,0,0,,那么MATCH就会输出FAIL Dialogue: 0,0:04:12.52,0:04:14.65,Default,,0,0,0,,你们已经见过模式匹配器的代码了 Dialogue: 0,0:04:15.00,0:04:16.17,Default,,0,0,0,,我就不会再去细讲 Dialogue: 0,0:04:16.64,0:04:19.77,Default,,0,0,0,,这跟我们以前做的类似 Dialogue: 0,0:04:21.19,0:04:23.22,Default,,0,0,0,,我们在《基于规则的系统》中已经见过了 Dialogue: 0,0:04:23.22,0:04:24.56,Default,,0,0,0,,基本上是同样的匹配器 Dialogue: 0,0:04:24.95,0:04:27.66,Default,,0,0,0,,实际上 我认为这里的语法还更简单一点 Dialogue: 0,0:04:28.16,0:04:29.31,Default,,0,0,0,,因为我们不用去关心 Dialogue: 0,0:04:29.40,0:04:31.40,Default,,0,0,0,,任意变量、任意表达式之类的东西 Dialogue: 0,0:04:31.40,0:04:32.88,Default,,0,0,0,,这里面只区分变量和常量 Dialogue: 0,0:04:35.79,0:04:37.32,Default,,0,0,0,,那么 有了模式匹配器以后 Dialogue: 0,0:04:38.46,0:04:39.61,Default,,0,0,0,,基本查询又是怎么样的呢? Dialogue: 0,0:04:42.97,0:04:45.34,Default,,0,0,0,,基本查询将会是一个相当复杂的东西 Dialogue: 0,0:04:46.67,0:05:03.58,Default,,0,0,0,,就拿查询(JOB ?X (?D . ?Y))来说 Dialogue: 0,0:05:07.04,0:05:08.73,Default,,0,0,0,,我们可能会输入这样的查询 Dialogue: 0,0:05:09.40,0:05:11.39,Default,,0,0,0,,这又将如何在系统内实现呢? Dialogue: 0,0:05:14.14,0:05:15.66,Default,,0,0,0,,我们可以把它想做这个小盒子 Dialogue: 0,0:05:15.70,0:05:16.80,Default,,0,0,0,,这是一条基本查询 Dialogue: 0,0:05:18.88,0:05:20.30,Default,,0,0,0,,这个小盒子将会 Dialogue: 0,0:05:22.24,0:05:27.28,Default,,0,0,0,,以两条流作为输入 Dialogue: 0,0:05:31.96,0:05:33.20,Default,,0,0,0,,并输出一条流 Dialogue: 0,0:05:34.03,0:05:36.19,Default,,0,0,0,,因此一条基本查询的形状 Dialogue: 0,0:05:36.51,0:05:38.46,Default,,0,0,0,,就将是有两条输入流 Dialogue: 0,0:05:38.67,0:05:39.96,Default,,0,0,0,,和一条输出流 Dialogue: 0,0:05:41.12,0:05:46.20,Default,,0,0,0,,而这些流 来自于这里的数据库 Dialogue: 0,0:05:51.95,0:05:53.93,Default,,0,0,0,,因此我们把数据库中的所有数据 Dialogue: 0,0:05:55.93,0:05:57.20,Default,,0,0,0,,想象成一条流 Dialogue: 0,0:05:57.31,0:05:58.40,Default,,0,0,0,,而这个盒子不断地吸取 Dialogue: 0,0:06:00.36,0:06:02.43,Default,,0,0,0,,那么 数据库中有什么呢? Dialogue: 0,0:06:08.43,0:06:20.32,Default,,0,0,0,,首先是(JOB (ALYSSA ...)) Dialogue: 0,0:06:21.96,0:06:23.71,Default,,0,0,0,,以及还有其它的JOB数据 Dialogue: 0,0:06:25.77,0:06:30.41,Default,,0,0,0,,想象一下 数据库中的所有事实都在这条流中 Dialogue: 0,0:06:32.04,0:06:33.10,Default,,0,0,0,,都到了这里 Dialogue: 0,0:06:33.36,0:06:34.52,Default,,0,0,0,,而这条流送来的 Dialogue: 0,0:06:34.89,0:06:36.52,Default,,0,0,0,,是一些字典 Dialogue: 0,0:06:38.51,0:06:41.40,Default,,0,0,0,,其中一个就可能是 Dialogue: 0,0:06:46.70,0:06:49.31,Default,,0,0,0,,Y=PROG Dialogue: 0,0:06:55.47,0:06:56.64,Default,,0,0,0,,现在 查询工作就是要 Dialogue: 0,0:06:57.07,0:06:59.80,Default,,0,0,0,,当它从这条流中取得一个字典后 Dialogue: 0,0:07:02.01,0:07:06.67,Default,,0,0,0,,它会搜寻数据库中的东西 Dialogue: 0,0:07:07.45,0:07:10.24,Default,,0,0,0,,来尽可能产生所有匹配结果 Dialogue: 0,0:07:11.39,0:07:12.89,Default,,0,0,0,,它把查询视作一种模式 Dialogue: 0,0:07:13.15,0:07:16.72,Default,,0,0,0,,并将它们与数据库中的事实匹配起来 Dialogue: 0,0:07:16.96,0:07:21.98,Default,,0,0,0,,结合着相应的字典中的数据 Dialogue: 0,0:07:22.94,0:07:25.68,Default,,0,0,0,,找到数据库中所有匹配的结果 Dialogue: 0,0:07:27.55,0:07:29.69,Default,,0,0,0,,所以针对数据库中的每条事实 Dialogue: 0,0:07:29.72,0:07:34.35,Default,,0,0,0,,它都会调用(MATCH PAT FACT DICTIONAY)来检查 Dialogue: 0,0:07:35.11,0:07:37.68,Default,,0,0,0,,如果成功匹配 Dialogue: 0,0:07:38.19,0:07:39.93,Default,,0,0,0,,它就输出一个扩展了的字典 Dialogue: 0,0:07:40.67,0:07:42.32,Default,,0,0,0,,比如说 这里进来了一本字典 Dialogue: 0,0:07:43.00,0:07:44.09,Default,,0,0,0,,并且成功匹配 Dialogue: 0,0:07:44.51,0:07:45.87,Default,,0,0,0,,那么就会输出一本字典 Dialogue: 0,0:07:46.81,0:07:49.79,Default,,0,0,0,,本例中就是Y=PROG Dialogue: 0,0:07:51.52,0:07:52.97,Default,,0,0,0,,X=... Dialogue: 0,0:07:56.54,0:07:58.75,Default,,0,0,0,,Y=PROG X=... Dialogue: 0,0:07:58.96,0:08:00.54,Default,,0,0,0,,D又是一个新的项 Dialogue: 0,0:08:01.72,0:08:02.27,Default,,0,0,0,,像这样扩展 Dialogue: 0,0:08:03.52,0:08:07.82,Default,,0,0,0,,当然 它会针对数据库中的所有事实做同样的尝试 Dialogue: 0,0:08:07.98,0:08:09.25,Default,,0,0,0,,所以就可能有很多的结果 Dialogue: 0,0:08:09.56,0:08:10.59,Default,,0,0,0,,可能会产生另一本字典 Dialogue: 0,0:08:11.28,0:08:17.12,Default,,0,0,0,,其中 Y=PROG X=... D=... Dialogue: 0,0:08:19.18,0:08:21.55,Default,,0,0,0,,因此 对于每个输入的框架 Dialogue: 0,0:08:21.76,0:08:23.69,Default,,0,0,0,,对于每输入一本字典 Dialogue: 0,0:08:23.72,0:08:25.24,Default,,0,0,0,,它可能输出很多本字典 Dialogue: 0,0:08:26.54,0:08:28.67,Default,,0,0,0,,或者什么也不输出 Dialogue: 0,0:08:30.47,0:08:38.48,Default,,0,0,0,,可能会有一些不匹配的情况 比如X=FOO Dialogue: 0,0:08:39.02,0:08:40.89,Default,,0,0,0,,这个条目不会匹配任何东西 Dialogue: 0,0:08:41.52,0:08:45.12,Default,,0,0,0,,就这个框架来说 不会向输出流中输出东西 Dialogue: 0,0:08:47.51,0:08:51.28,Default,,0,0,0,,或者你也可以输入一个空框架 Dialogue: 0,0:08:52.91,0:08:56.24,Default,,0,0,0,,空框架是用来 Dialogue: 0,0:08:59.87,0:09:02.33,Default,,0,0,0,,在没有任何约束的情况下 Dialogue: 0,0:09:02.57,0:09:06.14,Default,,0,0,0,,匹配数据库中所有可能的结果 Dialogue: 0,0:09:07.57,0:09:09.16,Default,,0,0,0,,这仅仅代表着 Dialogue: 0,0:09:10.32,0:09:13.87,Default,,0,0,0,,处理你输入的查询 最初所进行的计算 Dialogue: 0,0:09:14.20,0:09:15.56,Default,,0,0,0,,它试图找出所有的匹配 Dialogue: 0,0:09:16.65,0:09:18.83,Default,,0,0,0,,基本查询建立了这种机制 Dialogue: 0,0:09:19.37,0:09:20.57,Default,,0,0,0,,而语言要做的是 Dialogue: 0,0:09:22.75,0:09:24.67,Default,,0,0,0,,当你在顶层输入这条查询时 Dialogue: 0,0:09:24.84,0:09:26.14,Default,,0,0,0,,它基于这种机制 Dialogue: 0,0:09:26.16,0:09:28.35,Default,,0,0,0,,它会输入一本空的字典 Dialogue: 0,0:09:30.86,0:09:32.56,Default,,0,0,0,,而对于输出的每个东西 Dialogue: 0,0:09:33.08,0:09:35.88,Default,,0,0,0,,然后把最初的查询 Dialogue: 0,0:09:36.56,0:09:40.44,Default,,0,0,0,,用不同的字典来实例化 Dialogue: 0,0:09:40.81,0:09:44.36,Default,,0,0,0,,于是实例化后的模式就形成了一条新的流 Dialogue: 0,0:09:44.99,0:09:46.51,Default,,0,0,0,,这就是在终端上打印出来的内容 Dialogue: 0,0:09:48.17,0:09:51.24,Default,,0,0,0,,这也就是其中的基本原理 Dialogue: 0,0:09:53.51,0:09:55.48,Default,,0,0,0,,那么 这又为什么复杂呢? Dialogue: 0,0:09:57.71,0:10:01.00,Default,,0,0,0,,除了使用这种基于流的方法 Dialogue: 0,0:10:01.37,0:10:04.25,Default,,0,0,0,,你们可以想出很多更简单的方法来组织基本查询 Dialogue: 0,0:10:05.18,0:10:06.09,Default,,0,0,0,,而答案就在于 Dialogue: 0,0:10:07.15,0:10:08.51,Default,,0,0,0,,你们可能已经在想了 Dialogue: 0,0:10:10.86,0:10:14.09,Default,,0,0,0,,答案就是 这种方法能够优雅地 Dialogue: 0,0:10:14.56,0:10:16.76,Default,,0,0,0,,实现组合手段 Dialogue: 0,0:10:17.79,0:10:18.80,Default,,0,0,0,,比如说 Dialogue: 0,0:10:20.65,0:10:22.47,Default,,0,0,0,,假设我还想实现其它的效果 Dialogue: 0,0:10:22.47,0:10:26.96,Default,,0,0,0,,我不只是想查询所有人的工作信息 Dialogue: 0,0:10:27.23,0:10:28.35,Default,,0,0,0,,假设我还想查询 Dialogue: 0,0:10:29.47,0:10:35.92,Default,,0,0,0,,(AND (JOB ?X (?D . ?Y)) Dialogue: 0,0:10:36.80,0:10:47.04,Default,,0,0,0,,(SUPERVIOSR ?X ?Z)) Dialogue: 0,0:10:48.80,0:10:50.67,Default,,0,0,0,,(SUPERVISOR ?X ?Z)这条查询 Dialogue: 0,0:10:51.39,0:10:52.96,Default,,0,0,0,,是另外的一条基本查询 Dialogue: 0,0:10:53.71,0:10:58.43,Default,,0,0,0,,它也有类似的形状——接收一条数据对象流 Dialogue: 0,0:10:59.18,0:11:01.64,Default,,0,0,0,,一条初始字典流 Dialogue: 0,0:11:01.68,0:11:05.52,Default,,0,0,0,,字典是你在进行匹配时 需要遵循的约束 Dialogue: 0,0:11:05.53,0:11:07.44,Default,,0,0,0,,然后它会输出一条字典流 Dialogue: 0,0:11:08.70,0:11:10.80,Default,,0,0,0,,这就是这条基本查询的形状 Dialogue: 0,0:11:11.50,0:11:12.91,Default,,0,0,0,,我又该如何实现AND呢? Dialogue: 0,0:11:12.91,0:11:13.45,Default,,0,0,0,,其实很简单 Dialogue: 0,0:11:13.45,0:11:14.44,Default,,0,0,0,,把它们连接起来就好了 Dialogue: 0,0:11:14.88,0:11:16.28,Default,,0,0,0,,我把这条查询的输出 Dialogue: 0,0:11:16.96,0:11:18.81,Default,,0,0,0,,连接在这条查询的输入上 Dialogue: 0,0:11:19.83,0:11:21.84,Default,,0,0,0,,然后把这里的字典扇出开来 Dialogue: 0,0:11:26.57,0:11:27.96,Default,,0,0,0,,你们就能发现它是如何工作的了 Dialogue: 0,0:11:29.05,0:11:32.44,Default,,0,0,0,,这里会输出一个框架 Dialogue: 0,0:11:32.51,0:11:36.84,Default,,0,0,0,,其中有X、Y和D的绑定 Dialogue: 0,0:11:37.92,0:11:39.28,Default,,0,0,0,,当后面的查询接收到结果后 Dialogue: 0,0:11:39.29,0:11:41.60,Default,,0,0,0,,当它了解了这些约束后 Dialogue: 0,0:11:42.17,0:11:49.24,Default,,0,0,0,,字典中的是Y、X和D的值 Dialogue: 0,0:11:51.80,0:11:53.08,Default,,0,0,0,,它会搜寻数据库 Dialogue: 0,0:11:53.12,0:11:54.92,Default,,0,0,0,,试图找到有关SUPERVISOR关系的事实 Dialogue: 0,0:11:56.04,0:11:58.51,Default,,0,0,0,,如果找到了的话 它就会输出一些词典 Dialogue: 0,0:11:59.58,0:12:09.34,Default,,0,0,0,,其中有Y、X、D以及Z的绑定 Dialogue: 0,0:12:12.07,0:12:14.09,Default,,0,0,0,,不过要注意 Dialogue: 0,0:12:14.19,0:12:17.24,Default,,0,0,0,,因为这里输入的框架建立了约束 Dialogue: 0,0:12:17.61,0:12:20.28,Default,,0,0,0,,它保证了当你执行AND运算时 Dialogue: 0,0:12:20.49,0:12:24.62,Default,,0,0,0,,这两个X是相同的 Dialogue: 0,0:12:26.47,0:12:28.96,Default,,0,0,0,,这是因为通过这条流输出时 Dialogue: 0,0:12:29.96,0:12:32.65,Default,,0,0,0,,X已经有值了 你要确保匹配的一致性 Dialogue: 0,0:12:34.46,0:12:36.17,Default,,0,0,0,,然后我们想起在MATCH的代码中 Dialogue: 0,0:12:36.19,0:12:38.17,Default,,0,0,0,,有一种操作字典的特殊组织方法 Dialogue: 0,0:12:38.20,0:12:39.82,Default,,0,0,0,,确保了匹配的一致性 Dialogue: 0,0:12:40.92,0:12:41.77,Default,,0,0,0,,这就是AND的实现 Dialogue: 0,0:12:44.08,0:12:46.94,Default,,0,0,0,,关键是要注意它的一般性形状 Dialogue: 0,0:12:48.49,0:12:51.55,Default,,0,0,0,,我们来看看(AND P Q) Dialogue: 0,0:12:52.88,0:12:55.61,Default,,0,0,0,,这里是P和Q Dialogue: 0,0:12:57.29,0:12:58.60,Default,,0,0,0,,两条查询的AND Dialogue: 0,0:13:00.27,0:13:01.19,Default,,0,0,0,,看起来像是这样 Dialogue: 0,0:13:01.19,0:13:04.44,Default,,0,0,0,,每一条查询都通过一条流连接数据库 Dialogue: 0,0:13:04.54,0:13:05.71,Default,,0,0,0,,一条输入流 Dialogue: 0,0:13:06.33,0:13:08.17,Default,,0,0,0,,并输出一条输出流 Dialogue: 0,0:13:10.23,0:13:11.72,Default,,0,0,0,,关键是要注意 Dialogue: 0,0:13:12.20,0:13:15.02,Default,,0,0,0,,如果我在它们周围画一个盒子 Dialogue: 0,0:13:19.26,0:13:23.64,Default,,0,0,0,,这就是(AND P Q) Dialogue: 0,0:13:25.66,0:13:30.38,Default,,0,0,0,,那么这个盒子也有同样的形状 Dialogue: 0,0:13:32.04,0:13:34.20,Default,,0,0,0,,它也有一条连接数据库的流 Dialogue: 0,0:13:34.20,0:13:35.74,Default,,0,0,0,,但是在内部会扇出开来 Dialogue: 0,0:13:36.60,0:13:37.93,Default,,0,0,0,,但是在外部你看不到 Dialogue: 0,0:13:38.16,0:13:40.64,Default,,0,0,0,,它接收一个流 并输出一个流 Dialogue: 0,0:13:42.06,0:13:43.16,Default,,0,0,0,,这就是AND Dialogue: 0,0:13:43.57,0:13:45.72,Default,,0,0,0,,类似地 OR可能看起像这样 Dialogue: 0,0:13:46.02,0:13:49.58,Default,,0,0,0,,虽然我没给你们演示过OR的用法 Dialogue: 0,0:13:49.84,0:13:54.70,Default,,0,0,0,,OR会尝试找出P或Q所有匹配的事实 Dialogue: 0,0:13:55.80,0:13:58.07,Default,,0,0,0,,P、Q两条查询都有各自的形状 Dialogue: 0,0:14:04.46,0:14:06.68,Default,,0,0,0,,OR的实现则是 Dialogue: 0,0:14:08.54,0:14:10.91,Default,,0,0,0,,我把来自于数据库的流 Dialogue: 0,0:14:12.50,0:14:13.49,Default,,0,0,0,,扇出开来 Dialogue: 0,0:14:13.49,0:14:16.04,Default,,0,0,0,,把它们分别送给P和Q Dialogue: 0,0:14:17.44,0:14:21.98,Default,,0,0,0,,我把最初的查询流也给扇出开来 Dialogue: 0,0:14:26.75,0:14:29.16,Default,,0,0,0,,这样我不但能够得到P的所有结果 Dialogue: 0,0:14:29.29,0:14:31.08,Default,,0,0,0,,也能得到Q的所有结果 Dialogue: 0,0:14:31.61,0:14:34.56,Default,,0,0,0,,把这些输出送入某种“附加器”中 Dialogue: 0,0:14:34.62,0:14:37.48,Default,,0,0,0,,或者把它们“合并”到一条流中 Dialogue: 0,0:14:39.64,0:14:40.88,Default,,0,0,0,,然后得到输出 Dialogue: 0,0:14:41.08,0:14:48.24,Default,,0,0,0,,而从外部来看 这整个东西就是OR Dialogue: 0,0:14:52.35,0:14:54.89,Default,,0,0,0,,同样的 当你们从外部观察它时 Dialogue: 0,0:14:55.07,0:14:56.54,Default,,0,0,0,,你会发现它具有相同的形状 Dialogue: 0,0:15:01.00,0:15:01.61,Default,,0,0,0,,NOT又如何实现呢? Dialogue: 0,0:15:02.02,0:15:03.45,Default,,0,0,0,,NOT的原理有些类似 Dialogue: 0,0:15:04.31,0:15:05.95,Default,,0,0,0,,如果我有一条查询P Dialogue: 0,0:15:06.86,0:15:13.50,Default,,0,0,0,,这是一条基本查询P Dialogue: 0,0:15:14.69,0:15:16.32,Default,,0,0,0,,现在我要实现(NOT P) Dialogue: 0,0:15:18.68,0:15:20.54,Default,,0,0,0,,NOT的作用像是一个过滤器 Dialogue: 0,0:15:20.72,0:15:21.95,Default,,0,0,0,,这里连接数据库 Dialogue: 0,0:15:23.84,0:15:28.28,Default,,0,0,0,,这里是输入的字典流 Dialogue: 0,0:15:28.78,0:15:31.53,Default,,0,0,0,,(NOT P)要做的就是 Dialogue: 0,0:15:31.88,0:15:37.40,Default,,0,0,0,,对这些东西做过滤 Dialogue: 0,0:15:39.02,0:15:40.09,Default,,0,0,0,,过滤的方法则是 Dialogue: 0,0:15:40.19,0:15:42.70,Default,,0,0,0,,如果我在这里获得了一本字典 Dialogue: 0,0:15:43.42,0:15:44.65,Default,,0,0,0,,那么我就去找所有的匹配 Dialogue: 0,0:15:44.83,0:15:46.48,Default,,0,0,0,,然后丢弃找到的结果 Dialogue: 0,0:15:47.46,0:15:49.93,Default,,0,0,0,,如果我没有在这里找到匹配 Dialogue: 0,0:15:50.12,0:15:51.37,Default,,0,0,0,,我就把它传递过去 Dialogue: 0,0:15:52.40,0:15:53.55,Default,,0,0,0,,NOT就是一个纯粹的过滤器 Dialogue: 0,0:15:55.34,0:15:59.98,Default,,0,0,0,,因此AND就类似于一个电阻 Dialogue: 0,0:15:59.98,0:16:01.85,Default,,0,0,0,,AND是串行的组合 Dialogue: 0,0:16:02.49,0:16:04.14,Default,,0,0,0,,OR是并行组合 Dialogue: 0,0:16:04.96,0:16:07.46,Default,,0,0,0,,然而NOT并不会对字典做任何扩展 Dialogue: 0,0:16:07.46,0:16:08.40,Default,,0,0,0,,它只会做过滤 Dialogue: 0,0:16:08.75,0:16:11.79,Default,,0,0,0,,它会丢弃那些能够匹配的结果 Dialogue: 0,0:16:12.64,0:16:14.19,Default,,0,0,0,,LISP-VALUE的原理类似 Dialogue: 0,0:16:14.84,0:16:16.60,Default,,0,0,0,,它的过滤器会复杂点 Dialogue: 0,0:16:16.60,0:16:17.37,Default,,0,0,0,,因为要应用到谓词上 Dialogue: 0,0:16:19.93,0:16:21.64,Default,,0,0,0,,这里需要注意的关键点是 Dialogue: 0,0:16:21.92,0:16:23.55,Default,,0,0,0,,我们之前也强调过了 Dialogue: 0,0:16:23.64,0:16:25.29,Default,,0,0,0,,就是关于“闭包性质”的思想 Dialogue: 0,0:16:28.22,0:16:31.80,Default,,0,0,0,,我们通过组合手段构建的东西 Dialogue: 0,0:16:31.95,0:16:34.51,Default,,0,0,0,,跟所使用的基本物件 Dialogue: 0,0:16:35.69,0:16:37.58,Default,,0,0,0,,有同样的结构 Dialogue: 0,0:16:39.75,0:16:41.68,Default,,0,0,0,,所以从外面看 Dialogue: 0,0:16:41.71,0:16:43.72,Default,,0,0,0,,查询的AND与基本查询结构相同 Dialogue: 0,0:16:44.63,0:16:46.14,Default,,0,0,0,,这就意味着 Dialogue: 0,0:16:46.94,0:16:50.28,Default,,0,0,0,,这里的盒子可以是AND、OR、NOT或者其它的 Dialogue: 0,0:16:50.30,0:16:54.22,Default,,0,0,0,,因为它具有相同的形状来连接更大的东西 Dialogue: 0,0:16:54.95,0:16:56.68,Default,,0,0,0,,这种思想能够让我们获得 Dialogue: 0,0:16:56.92,0:16:58.96,Default,,0,0,0,,Escher绘图语言中的那种复杂度 Dialogue: 0,0:16:59.55,0:17:01.31,Default,,0,0,0,,让你能够仅仅使用序对 Dialogue: 0,0:17:01.34,0:17:03.26,Default,,0,0,0,,构建出这些复杂结构 Dialogue: 0,0:17:03.93,0:17:04.78,Default,,0,0,0,,这就是“闭包性质” Dialogue: 0,0:17:06.28,0:17:08.06,Default,,0,0,0,,这种性质 Dialogue: 0,0:17:09.64,0:17:11.72,Default,,0,0,0,,能够让我完成你们现在觉得理所当然的事儿 Dialogue: 0,0:17:11.76,0:17:14.91,Default,,0,0,0,,比如我可以查询(AND JOB SALARY) Dialogue: 0,0:17:14.91,0:17:18.80,Default,,0,0,0,,当然我也可以查询(AND JOB (NOT ...))等等 Dialogue: 0,0:17:19.26,0:17:20.92,Default,,0,0,0,,这种便利是由 Dialogue: 0,0:17:20.94,0:17:22.91,Default,,0,0,0,,这种“闭包原则”直接带给我们的 Dialogue: 0,0:17:25.18,0:17:27.08,Default,,0,0,0,,好吧 提问时间 Dialogue: 0,0:17:29.32,0:17:30.89,Default,,0,0,0,,学生:字典是从哪里来的? Dialogue: 0,0:17:30.99,0:17:36.03,Default,,0,0,0,,教授:字典最初来自于你的输入 Dialogue: 0,0:17:36.09,0:17:37.32,Default,,0,0,0,,因此当你最初进行查询时 Dialogue: 0,0:17:39.16,0:17:41.09,Default,,0,0,0,,它首先会建立起这整个结构 Dialogue: 0,0:17:41.09,0:17:42.64,Default,,0,0,0,,它先输入一个空字典 Dialogue: 0,0:17:45.00,0:17:47.24,Default,,0,0,0,,如果你只有一条基本查询的话 Dialogue: 0,0:17:48.24,0:17:51.10,Default,,0,0,0,,那么它就会输出一系列具有内容的字典 Dialogue: 0,0:17:52.31,0:17:54.33,Default,,0,0,0,,这里演示的一般性情况是 Dialogue: 0,0:17:54.51,0:17:59.71,Default,,0,0,0,,某个嵌套组合查询的中间过程 Dialogue: 0,0:18:01.55,0:18:02.30,Default,,0,0,0,,所以在那时 Dialogue: 0,0:18:02.38,0:18:03.79,Default,,0,0,0,,让我们来看看这里 Dialogue: 0,0:18:04.38,0:18:06.73,Default,,0,0,0,,这条SUPERVISOR查询得到了某本字典 Dialogue: 0,0:18:06.73,0:18:08.03,Default,,0,0,0,,这本字典来自于哪里呢? Dialogue: 0,0:18:08.73,0:18:11.15,Default,,0,0,0,,它来自于 Dialogue: 0,0:18:12.84,0:18:14.89,Default,,0,0,0,,这条基本查询的输出 Dialogue: 0,0:18:16.26,0:18:17.88,Default,,0,0,0,,说得更具体一点 Dialogue: 0,0:18:18.35,0:18:21.72,Default,,0,0,0,,如果我最初在顶层只输入了这条查询 Dialogue: 0,0:18:22.27,0:18:22.92,Default,,0,0,0,,这整条AND查询 Dialogue: 0,0:18:23.07,0:18:25.28,Default,,0,0,0,,它实际上会构建这种结构 Dialogue: 0,0:18:25.50,0:18:30.24,Default,,0,0,0,,并使用一本空字典来启动整个过程 Dialogue: 0,0:18:31.77,0:18:34.33,Default,,0,0,0,,处理过程开始后 会产生一系列的字典 Dialogue: 0,0:18:34.36,0:18:37.36,Default,,0,0,0,,其中就有X、Y以及D Dialogue: 0,0:18:38.64,0:18:39.58,Default,,0,0,0,,向这边传递 Dialogue: 0,0:18:40.19,0:18:42.16,Default,,0,0,0,,这就是这条查询的输入 Dialogue: 0,0:18:42.16,0:18:43.72,Default,,0,0,0,,这条查询也会生成其它的东西 Dialogue: 0,0:18:45.04,0:18:48.22,Default,,0,0,0,,如果这整个查询是构建在一个更大的查询中的话 Dialogue: 0,0:18:49.31,0:18:51.00,Default,,0,0,0,,比如说一条OR查询 Dialogue: 0,0:18:53.42,0:18:55.71,Default,,0,0,0,,那么它将输出到下一个查询中 Dialogue: 0,0:18:58.56,0:19:01.28,Default,,0,0,0,,因此最初开始处理时 只有一本空字典 Dialogue: 0,0:19:01.68,0:19:04.08,Default,,0,0,0,,但是在处理这些复合查询的过程中 Dialogue: 0,0:19:04.11,0:19:06.65,Default,,0,0,0,,会生成各种不同的字典 Dialogue: 0,0:19:07.66,0:19:12.28,Default,,0,0,0,,学生:字典都是查询的结果吗? Dialogue: 0,0:19:15.12,0:19:17.69,Default,,0,0,0,,它们会变成 Dialogue: 0,0:19:18.84,0:19:22.81,Default,,0,0,0,,它们存储在数据库中吗? Dialogue: 0,0:19:23.68,0:19:24.98,Default,,0,0,0,,它们是临时数据吗? Dialogue: 0,0:19:24.98,0:19:27.18,Default,,0,0,0,,教授:它们是在MATCH过程中临时创建的 Dialogue: 0,0:19:28.03,0:19:29.88,Default,,0,0,0,,但它们实际存放在内存中 Dialogue: 0,0:19:29.88,0:19:33.02,Default,,0,0,0,,最初 某人创建了一本THE-EMPTY-DICT字典 Dialogue: 0,0:19:34.22,0:19:36.80,Default,,0,0,0,,送入这个匹配过程 Dialogue: 0,0:19:36.81,0:19:39.05,Default,,0,0,0,,MATCH过程据此构建新字典 Dialogue: 0,0:19:39.07,0:19:40.27,Default,,0,0,0,,并把它们传递下去 Dialogue: 0,0:19:40.76,0:19:42.48,Default,,0,0,0,,学生:因此匹配完成后它们就被丢弃了? Dialogue: 0,0:19:43.64,0:19:46.25,Default,,0,0,0,,教授:实际上 当没人需要它们后(就被废料回收了) Dialogue: 0,0:19:51.90,0:19:53.60,Default,,0,0,0,,学生:似乎AND查询对数据库 Dialogue: 0,0:19:53.63,0:19:55.37,Default,,0,0,0,,进行了一些冗余操作 Dialogue: 0,0:19:55.96,0:19:57.48,Default,,0,0,0,,如果第一条子句扫描过了 Dialogue: 0,0:19:57.50,0:19:59.90,Default,,0,0,0,,比如说前两个元素没有匹配 而第三个元素匹配了 Dialogue: 0,0:20:00.25,0:20:03.64,Default,,0,0,0,,然而第二条子句又会检查这两个元素 Dialogue: 0,0:20:04.32,0:20:06.59,Default,,0,0,0,,然后又一次丢弃这些不匹配的元素 Dialogue: 0,0:20:06.64,0:20:08.72,Default,,0,0,0,,而字典中已经有匹配的项了 Dialogue: 0,0:20:10.00,0:20:12.56,Default,,0,0,0,,如果我们把数据库中的数据 Dialogue: 0,0:20:12.57,0:20:14.43,Default,,0,0,0,,跟字典同时传递 这样可行么? Dialogue: 0,0:20:15.69,0:20:17.60,Default,,0,0,0,,教授:实际上 通常来说 Dialogue: 0,0:20:17.63,0:20:19.48,Default,,0,0,0,,我们能够以其它方式来安排这些搜索 Dialogue: 0,0:20:20.12,0:20:21.74,Default,,0,0,0,,你也可以做一些分析 Dialogue: 0,0:20:21.74,0:20:23.16,Default,,0,0,0,,我记得书里面就有这样的习题 Dialogue: 0,0:20:23.87,0:20:26.65,Default,,0,0,0,,是考察通过安排AND子句的顺序 Dialogue: 0,0:20:27.00,0:20:29.20,Default,,0,0,0,,来消除不同类型的冗余 Dialogue: 0,0:20:29.85,0:20:30.72,Default,,0,0,0,,而这里只是为了 Dialogue: 0,0:20:31.32,0:20:34.54,Default,,0,0,0,,用非常简单的情况来向你们展示它们是如何配合的 Dialogue: 0,0:20:34.70,0:20:35.38,Default,,0,0,0,,但是你说得非常对 Dialogue: 0,0:20:35.38,0:20:37.32,Default,,0,0,0,,这些冗余是可以避免的 Dialogue: 0,0:20:38.37,0:20:40.80,Default,,0,0,0,,这也是这门语言缓慢的原因之一 Dialogue: 0,0:20:41.19,0:20:42.70,Default,,0,0,0,,你们可以让它变得更聪明 Dialogue: 0,0:20:42.93,0:20:46.22,Default,,0,0,0,,我只是为了向你们演示非常简单的、原理性的实现 Dialogue: 0,0:20:51.22,0:20:53.23,Default,,0,0,0,,学生:您是根据Prolog来建模这门语言的 Dialogue: 0,0:20:53.24,0:20:55.13,Default,,0,0,0,,还是说它只是偶然地像Prolog? Dialogue: 0,0:21:04.96,0:21:07.08,Default,,0,0,0,,教授:Gerry教授昨天羞辱了一大堆人 Dialogue: 0,0:21:07.24,0:21:09.92,Default,,0,0,0,,我想说真实的情况是 Dialogue: 0,0:21:10.19,0:21:12.60,Default,,0,0,0,,MIT的研究人员在1971年做了类似的事 Dialogue: 0,0:21:12.64,0:21:15.60,Default,,0,0,0,,但是发现这个方向并不正确 并停止了研究 Dialogue: 0,0:21:16.12,0:21:22.80,Default,,0,0,0,,因此我们是根据查询处理的基本原理建模的 Dialogue: 0,0:21:22.84,0:21:24.73,Default,,0,0,0,,大概在1971年左右 Dialogue: 0,0:21:25.13,0:21:27.24,Default,,0,0,0,,只是说 那时候我们还没有用流来实现 Dialogue: 0,0:21:28.27,0:21:33.04,Default,,0,0,0,,然后我们 -- 但我们使用了它差不多六个月后 Dialogue: 0,0:21:33.08,0:21:34.91,Default,,0,0,0,,发现它存在各种各样的问题 Dialogue: 0,0:21:34.94,0:21:36.30,Default,,0,0,0,,稍后我会解释 Dialogue: 0,0:21:37.33,0:21:38.19,Default,,0,0,0,,然后我们就想 Dialogue: 0,0:21:38.44,0:21:39.92,Default,,0,0,0,,Prolog一定解决了这些问题 Dialogue: 0,0:21:39.93,0:21:41.21,Default,,0,0,0,,但却发现它并没有 Dialogue: 0,0:21:41.25,0:21:43.02,Default,,0,0,0,,从这种意义上来说 它确实跟Prolog一样 Dialogue: 0,0:21:43.60,0:21:44.95,Default,,0,0,0,,学生:Prolog基于流么? Dialogue: 0,0:21:44.95,0:21:46.20,Default,,0,0,0,,教授:不 Prolog基于的是 Dialogue: 0,0:21:46.78,0:21:51.04,Default,,0,0,0,,就行为上来说 我们的语言很像Prolog Dialogue: 0,0:21:51.04,0:21:52.96,Default,,0,0,0,,Prolog使用回溯策略 Dialogue: 0,0:21:53.80,0:21:55.71,Default,,0,0,0,,但是Prolog有一个优点非常好 Dialogue: 0,0:21:55.72,0:21:57.98,Default,,0,0,0,,也使得它变得实用 Dialogue: 0,0:21:58.28,0:22:01.50,Default,,0,0,0,,你知道吗 Dialogue: 0,0:22:01.68,0:22:04.09,Default,,0,0,0,,它们精心设计了Prolog的编译器 Dialogue: 0,0:22:04.11,0:22:05.32,Default,,0,0,0,,使得它能够高速运行 Dialogue: 0,0:22:06.65,0:22:10.81,Default,,0,0,0,,因此 虽然我们这门语言非常缓慢地输出答案 Dialogue: 0,0:22:11.66,0:22:13.61,Default,,0,0,0,,真正的Prolog程序却运行得非常快 Dialogue: 0,0:22:14.70,0:22:16.48,Default,,0,0,0,,这是因为 尽管搜索过程十分低效 Dialogue: 0,0:22:16.67,0:22:20.81,Default,,0,0,0,,Prolog卓越的编译器也会高效地完成工作 Dialogue: 0,0:22:24.30,0:22:25.21,Default,,0,0,0,,休息一下吧 Dialogue: 0,0:22:25.42,0:22:36.17,Default,,0,0,0,,[音乐] Dialogue: 0,0:22:36.35,0:22:39.87,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:23:01.48,0:23:05.12,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:23:05.18,0:23:09.05,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:23:09.12,0:23:13.66,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 II Dialogue: 0,0:23:16.65,0:23:18.83,Default,,0,0,0,,我们已经考察过了基本查询 Dialogue: 0,0:23:19.21,0:23:23.52,Default,,0,0,0,,以及如何使用流来实现组合手段 Dialogue: 0,0:23:23.79,0:23:25.72,Default,,0,0,0,,AND、OR以及NOT Dialogue: 0,0:23:26.95,0:23:28.43,Default,,0,0,0,,现在 该讨论抽象手段了 Dialogue: 0,0:23:29.58,0:23:32.80,Default,,0,0,0,,回想一下 我们这门语言的抽象手段是RULE Dialogue: 0,0:23:35.15,0:23:37.79,Default,,0,0,0,,(BOSS ?Z ?D)描述的是 Dialogue: 0,0:23:39.18,0:23:43.77,Default,,0,0,0,,如果某人在D部门工作 Dialogue: 0,0:23:45.68,0:23:47.47,Default,,0,0,0,,并且Z是X的上司 Dialogue: 0,0:23:48.90,0:23:50.60,Default,,0,0,0,,这就是所谓的“BOSS” Dialogue: 0,0:23:52.26,0:23:53.15,Default,,0,0,0,,并且 实际上 Dialogue: 0,0:23:53.34,0:23:55.61,Default,,0,0,0,,如果我们考察一下编写的规则与这边的关系 Dialogue: 0,0:23:56.80,0:23:57.90,Default,,0,0,0,,这是我们编写的查询 Dialogue: 0,0:23:57.93,0:24:01.90,Default,,0,0,0,,这个是(JOB ?X ?D) 而这个是(SUPERVISOR ?X ?Z) Dialogue: 0,0:24:02.19,0:24:04.28,Default,,0,0,0,,我们实际想要把这一大堆东西 Dialogue: 0,0:24:05.07,0:24:06.57,Default,,0,0,0,,用一个盒子封装起来 Dialogue: 0,0:24:19.08,0:24:24.54,Default,,0,0,0,,然后把这个盒子里的所有东西 Dialogue: 0,0:24:25.15,0:24:32.48,Default,,0,0,0,,认为是(BOSS ?Z ?D) Dialogue: 0,0:24:33.90,0:24:35.25,Default,,0,0,0,,这是我们想要达到的效果 Dialogue: 0,0:24:38.72,0:24:39.72,Default,,0,0,0,,因此 比如说 Dialogue: 0,0:24:43.18,0:24:44.08,Default,,0,0,0,,我们这样做了过后 Dialogue: 0,0:24:45.00,0:24:47.84,Default,,0,0,0,,我们想要检查 Dialogue: 0,0:24:47.95,0:24:50.51,Default,,0,0,0,,Ben Bitdiddle是否为计算机分部的BOSS Dialogue: 0,0:24:51.10,0:25:02.86,Default,,0,0,0,,如果我想查询 (BOSS (BITDIDDLE BEN) COMPUTER) Dialogue: 0,0:25:04.78,0:25:07.08,Default,,0,0,0,,想象一下把这条查询输入系统 Dialogue: 0,0:25:07.12,0:25:09.16,Default,,0,0,0,,实际上发生的是 Dialogue: 0,0:25:10.67,0:25:12.92,Default,,0,0,0,,在这里先构建一本字典 Dialogue: 0,0:25:15.82,0:25:23.63,Default,,0,0,0,,其中 ?Z=BITDIDDLE Dialogue: 0,0:25:28.88,0:25:33.31,Default,,0,0,0,,?D=COMPUTER Dialogue: 0,0:25:37.08,0:25:38.62,Default,,0,0,0,,这个字典又是来自于哪里呢? Dialogue: 0,0:25:38.68,0:25:40.71,Default,,0,0,0,,我们来看下幻灯片 Dialogue: 0,0:25:40.71,0:25:43.71,Default,,0,0,0,,这本字典是通过把 Dialogue: 0,0:25:44.30,0:25:46.33,Default,,0,0,0,,查询(BOSS (BITDIDDLE BEN) COMPUTER) Dialogue: 0,0:25:46.51,0:25:49.63,Default,,0,0,0,,与规则的结论(BOSS ?Z ?D)相匹配得到 Dialogue: 0,0:25:51.65,0:25:54.11,Default,,0,0,0,,所以我们把规则的结论和查询匹配了起来 Dialogue: 0,0:25:54.19,0:25:55.53,Default,,0,0,0,,这样我们就获得了一本字典 Dialogue: 0,0:25:58.99,0:26:02.54,Default,,0,0,0,,现在我们就要把这本字典输入到这整个结构中 Dialogue: 0,0:26:02.92,0:26:05.56,Default,,0,0,0,,进行处理 并观察是否有输出 Dialogue: 0,0:26:06.67,0:26:09.88,Default,,0,0,0,,如果输出了结果 那么查询就为真 Dialogue: 0,0:26:11.33,0:26:12.37,Default,,0,0,0,,这是基本的思想 Dialogue: 0,0:26:12.37,0:26:13.24,Default,,0,0,0,,因此 通常来说 Dialogue: 0,0:26:14.03,0:26:15.40,Default,,0,0,0,,我们实现规则的方法就是 Dialogue: 0,0:26:15.85,0:26:18.89,Default,,0,0,0,,用规则的结论去匹配 Dialogue: 0,0:26:20.86,0:26:22.96,Default,,0,0,0,,假设为真的查询 Dialogue: 0,0:26:23.58,0:26:25.12,Default,,0,0,0,,这个过程会产生一本字典 Dialogue: 0,0:26:25.29,0:26:28.22,Default,,0,0,0,,在有了相关字典后 Dialogue: 0,0:26:30.35,0:26:34.51,Default,,0,0,0,,我们来处理规则的体 Dialogue: 0,0:26:36.33,0:26:37.68,Default,,0,0,0,,基本上就是这样了 Dialogue: 0,0:26:38.64,0:26:41.44,Default,,0,0,0,,但还有两个技术点 Dialogue: 0,0:26:43.04,0:26:44.32,Default,,0,0,0,,首先就是 Dialogue: 0,0:26:45.74,0:26:47.26,Default,,0,0,0,,我也可能有其它的问法 Dialogue: 0,0:26:47.51,0:26:48.41,Default,,0,0,0,,比如说 Dialogue: 0,0:26:50.54,0:26:52.36,Default,,0,0,0,,查询计算机分部的BOSS Dialogue: 0,0:26:52.54,0:26:56.32,Default,,0,0,0,,就可以查询 (BOSS ?WHO COMPUTER) Dialogue: 0,0:27:00.78,0:27:01.63,Default,,0,0,0,,这样做了以后 Dialogue: 0,0:27:02.57,0:27:04.62,Default,,0,0,0,,我真正想要做的 Dialogue: 0,0:27:05.04,0:27:06.49,Default,,0,0,0,,就是先建立一本字典 Dialogue: 0,0:27:08.35,0:27:09.88,Default,,0,0,0,,其中有一些约束 Dialogue: 0,0:27:09.93,0:27:11.20,Default,,0,0,0,,比如 ?D=COMPUTER Dialogue: 0,0:27:14.35,0:27:18.48,Default,,0,0,0,,而?Z等同于?WHO Dialogue: 0,0:27:21.70,0:27:23.22,Default,,0,0,0,,我们的匹配器不会那么做 Dialogue: 0,0:27:23.22,0:27:27.00,Default,,0,0,0,,这不是模式和数据的匹配方式 Dialogue: 0,0:27:28.58,0:27:29.72,Default,,0,0,0,,这是在匹配两个模式 Dialogue: 0,0:27:29.74,0:27:31.58,Default,,0,0,0,,并判断它们是否一致 Dialogue: 0,0:27:31.90,0:27:33.48,Default,,0,0,0,,又是什么使它们不一致 Dialogue: 0,0:27:33.48,0:27:36.43,Default,,0,0,0,,换句话说 我们需要的不是一个模式匹配器 Dialogue: 0,0:27:36.96,0:27:38.91,Default,,0,0,0,,而是一种更一般性的东西 Dialogue: 0,0:27:39.13,0:27:40.11,Default,,0,0,0,,就是“合一”算法 Dialogue: 0,0:27:44.42,0:27:48.06,Default,,0,0,0,,“合一”是更为一般化的模式匹配算法 Dialogue: 0,0:27:49.53,0:27:52.17,Default,,0,0,0,,合一算法接收两条模式 Dialogue: 0,0:27:53.23,0:27:57.53,Default,,0,0,0,,它考虑的是:可以找到哪些一般性的元素 Dialogue: 0,0:27:58.20,0:28:00.01,Default,,0,0,0,,用来代换模式中的变量 Dialogue: 0,0:28:02.68,0:28:05.08,Default,,0,0,0,,使得它俩能够同时满足 Dialogue: 0,0:28:05.68,0:28:06.60,Default,,0,0,0,,让我来举个例子 Dialogue: 0,0:28:08.86,0:28:14.49,Default,,0,0,0,,我有一个含有两个元素的模式:(?X ?X) Dialogue: 0,0:28:15.76,0:28:17.15,Default,,0,0,0,,它描述的是一个二元表 Dialogue: 0,0:28:17.32,0:28:18.64,Default,,0,0,0,,不管元素具体是什么 Dialogue: 0,0:28:18.67,0:28:20.04,Default,,0,0,0,,但两个元素是相同的 Dialogue: 0,0:28:20.40,0:28:22.83,Default,,0,0,0,,我把它与另一个模式进行“合一” Dialogue: 0,0:28:22.92,0:28:24.62,Default,,0,0,0,,后者描述的是一个二元表 Dialogue: 0,0:28:24.65,0:28:27.61,Default,,0,0,0,,首元素一张由A、?Y、C构成的表 Dialogue: 0,0:28:28.00,0:28:30.14,Default,,0,0,0,,而第二个元素是由A、B、?Z构成的表 Dialogue: 0,0:28:33.07,0:28:34.88,Default,,0,0,0,,那么 合一算法能够告诉我 Dialogue: 0,0:28:34.89,0:28:36.17,Default,,0,0,0,,在生成的字典中 Dialogue: 0,0:28:36.35,0:28:37.96,Default,,0,0,0,,?X必须是(A B C) Dialogue: 0,0:28:39.34,0:28:41.92,Default,,0,0,0,,?Y必须为B ?Z必须为C Dialogue: 0,0:28:43.44,0:28:46.28,Default,,0,0,0,,这些是我必须对X、Y以及Z施加的约束 Dialogue: 0,0:28:46.33,0:28:47.58,Default,,0,0,0,,以便让两个模式合一 Dialogue: 0,0:28:48.12,0:28:50.84,Default,,0,0,0,,或者换句话来说 让它匹配这个?X Dialogue: 0,0:28:51.15,0:28:53.37,Default,,0,0,0,,让它匹配这个?X Dialogue: 0,0:28:55.28,0:28:57.76,Default,,0,0,0,,合一算法需要能够推断出这些 Dialogue: 0,0:28:58.54,0:29:01.08,Default,,0,0,0,,但是合一算法也会遇到复杂的情况 Dialogue: 0,0:29:01.08,0:29:03.07,Default,,0,0,0,,我可能会询问一些复杂的查询 Dialogue: 0,0:29:03.48,0:29:05.74,Default,,0,0,0,,比如这是一个二元表 Dialogue: 0,0:29:07.00,0:29:08.28,Default,,0,0,0,,其中的元素都是相同的 Dialogue: 0,0:29:08.86,0:29:11.15,Default,,0,0,0,,它要与这个模式进行合一 Dialogue: 0,0:29:12.65,0:29:15.36,Default,,0,0,0,,合一算法也要能够从中推断出 Dialogue: 0,0:29:16.89,0:29:19.57,Default,,0,0,0,,?Y必须为B Dialogue: 0,0:29:19.57,0:29:22.12,Default,,0,0,0,,因为这两个是一样的 Dialogue: 0,0:29:22.22,0:29:23.52,Default,,0,0,0,,因此?Y就是B Dialogue: 0,0:29:24.34,0:29:27.53,Default,,0,0,0,,这里 ?V应该为A Dialogue: 0,0:29:28.94,0:29:30.99,Default,,0,0,0,,只要?Z和?W取值相同 Dialogue: 0,0:29:31.00,0:29:32.43,Default,,0,0,0,,它们就可以是任意值 Dialogue: 0,0:29:35.71,0:29:41.76,Default,,0,0,0,,?X就应该是(B A ?W) 其中?W为任意值 Dialogue: 0,0:29:42.83,0:29:44.68,Default,,0,0,0,,或者是?Z -- 因为?Z和?W是一致的 Dialogue: 0,0:29:44.70,0:29:49.42,Default,,0,0,0,,发现了么 合一算法需要从这些模式中推断出信息 Dialogue: 0,0:29:50.88,0:29:53.52,Default,,0,0,0,,所以你们可能认为 这其中有某种魔法般的推理 Dialogue: 0,0:29:54.27,0:29:55.23,Default,,0,0,0,,但其实并不是 Dialogue: 0,0:29:55.85,0:29:59.88,Default,,0,0,0,,合一算法基本上只是对模式匹配的小小修改 Dialogue: 0,0:30:00.15,0:30:01.85,Default,,0,0,0,,如果你们翻阅教材 就会发现 Dialogue: 0,0:30:02.25,0:30:06.16,Default,,0,0,0,,在模式匹配算法中加入了三到四行代码 Dialogue: 0,0:30:06.49,0:30:08.17,Default,,0,0,0,,来处理对称的情况 Dialogue: 0,0:30:08.28,0:30:10.81,Default,,0,0,0,,还记得吗 模式匹配中有一处代码判断 Dialogue: 0,0:30:11.66,0:30:14.28,Default,,0,0,0,,这个变量匹配一个常量吗? Dialogue: 0,0:30:14.98,0:30:16.42,Default,,0,0,0,,如果是的话 就在字典中进行检查 Dialogue: 0,0:30:16.42,0:30:18.25,Default,,0,0,0,,在合一算法中只有另一条子句 Dialogue: 0,0:30:18.49,0:30:20.75,Default,,0,0,0,,它判断两个变量是否相匹配 Dialogue: 0,0:30:22.00,0:30:23.42,Default,,0,0,0,,这种情况下你去查询字典 Dialogue: 0,0:30:23.45,0:30:25.68,Default,,0,0,0,,看它们在字典的约束下是否一致 Dialogue: 0,0:30:27.03,0:30:31.13,Default,,0,0,0,,因此 这门语言中的所有“推断” Dialogue: 0,0:30:31.28,0:30:34.59,Default,,0,0,0,,你会发现它蕴含在规则应用中 Dialogue: 0,0:30:34.99,0:30:37.88,Default,,0,0,0,,更进一步地考察 你会发现在合一算法中 Dialogue: 0,0:30:38.36,0:30:40.32,Default,,0,0,0,,如果更进一步地用“显微镜”观察 Dialogue: 0,0:30:40.56,0:30:43.96,Default,,0,0,0,,基本上就在模式匹配算法中 Dialogue: 0,0:30:44.94,0:30:47.07,Default,,0,0,0,,这其中并没有什么魔法 Dialogue: 0,0:30:47.41,0:30:50.25,Default,,0,0,0,,而你们所见到的“推断” Dialogue: 0,0:30:50.94,0:30:52.89,Default,,0,0,0,,只是因为其中的递归 Dialogue: 0,0:30:52.92,0:30:55.69,Default,,0,0,0,,它一点一点地回绕MATCH过程 Dialogue: 0,0:30:56.03,0:30:58.03,Default,,0,0,0,,它让这个过程看起来很聪明 Dialogue: 0,0:30:58.44,0:31:00.36,Default,,0,0,0,,但它实际上并不是那么聪明 Dialogue: 0,0:31:02.14,0:31:04.41,Default,,0,0,0,,当然 合一算法需要聪明地识别出一些情况 Dialogue: 0,0:31:04.88,0:31:05.87,Default,,0,0,0,,我来举个例子吧 Dialogue: 0,0:31:11.07,0:31:13.36,Default,,0,0,0,,假设我想要用一个二元表进行合一 Dialogue: 0,0:31:13.48,0:31:14.81,Default,,0,0,0,,(?X ?X) Dialogue: 0,0:31:17.24,0:31:22.14,Default,,0,0,0,,另一个模式则是 (?Y (a . ?Y)) Dialogue: 0,0:31:24.37,0:31:26.12,Default,,0,0,0,,现在 如果你想一想它所表达的意思 Dialogue: 0,0:31:26.86,0:31:29.71,Default,,0,0,0,,它表示了?X应该跟?Y一致 Dialogue: 0,0:31:30.92,0:31:31.66,Default,,0,0,0,,同时呢 Dialogue: 0,0:31:31.82,0:31:36.16,Default,,0,0,0,,?X又应该跟(A . ?Y)相同 Dialogue: 0,0:31:37.33,0:31:39.45,Default,,0,0,0,,如果你仔细思考它成立的条件 Dialogue: 0,0:31:42.27,0:31:44.71,Default,,0,0,0,,你会发现 ?Y必须是一个由A构成的无穷表 Dialogue: 0,0:31:47.50,0:31:48.35,Default,,0,0,0,,从某种角度来说 Dialogue: 0,0:31:49.21,0:31:52.40,Default,,0,0,0,,为了完成这样的合一 Dialogue: 0,0:31:52.60,0:31:54.84,Default,,0,0,0,,我需要求解一个不动点方程 Dialogue: 0,0:31:55.05,0:32:01.84,Default,,0,0,0,,(CONS 'A Y)=Y Dialogue: 0,0:32:04.57,0:32:06.96,Default,,0,0,0,,通常来说 --- 我这个例子很简单 Dialogue: 0,0:32:07.29,0:32:08.67,Default,,0,0,0,,但实际进行合一时 Dialogue: 0,0:32:08.97,0:32:11.98,Default,,0,0,0,,我们可能要求解一个任意的不动点方程 Dialogue: 0,0:32:12.01,0:32:13.42,Default,,0,0,0,,(F Y)=Y Dialogue: 0,0:32:15.53,0:32:17.08,Default,,0,0,0,,你基本上不能保证 Dialogue: 0,0:32:17.10,0:32:19.47,Default,,0,0,0,,在有穷时间内找到解 Dialogue: 0,0:32:20.57,0:32:23.60,Default,,0,0,0,,我们的逻辑语言又该如何处理这类情况呢? Dialogue: 0,0:32:24.89,0:32:26.48,Default,,0,0,0,,答案就是:“不处理” Dialogue: 0,0:32:27.16,0:32:28.04,Default,,0,0,0,,它会撒手不干 Dialogue: 0,0:32:28.73,0:32:31.07,Default,,0,0,0,,合一算法中有一处小检查 Dialogue: 0,0:32:31.31,0:32:33.82,Default,,0,0,0,,用来判断是否为困难的情况 Dialogue: 0,0:32:34.44,0:32:38.00,Default,,0,0,0,,也就是 匹配这些东西需要求解不动点方程 Dialogue: 0,0:32:38.65,0:32:40.81,Default,,0,0,0,,遇到这类情况 我就撒手不干 Dialogue: 0,0:32:42.84,0:32:44.65,Default,,0,0,0,,如果不进行这样的检查 Dialogue: 0,0:32:45.00,0:32:45.88,Default,,0,0,0,,会发生什么情况? Dialogue: 0,0:32:47.99,0:32:49.10,Default,,0,0,0,,大多数情况就是 Dialogue: 0,0:32:49.13,0:32:51.31,Default,,0,0,0,,合一算法会陷入无穷循环 Dialogue: 0,0:32:53.74,0:32:56.54,Default,,0,0,0,,其它的逻辑语言有类似的工作原理 Dialogue: 0,0:32:56.80,0:32:58.14,Default,,0,0,0,,因此这其中没有什么魔法 Dialogue: 0,0:32:58.22,0:32:59.93,Default,,0,0,0,,简单的情况由匹配器完成 Dialogue: 0,0:33:00.10,0:33:01.58,Default,,0,0,0,,困难的情况根本不去处理 Dialogue: 0,0:33:02.96,0:33:05.47,Default,,0,0,0,,这就是这种技术的现状 Dialogue: 0,0:33:11.88,0:33:14.24,Default,,0,0,0,,现在 我来形式化地描述一下 Dialogue: 0,0:33:14.27,0:33:16.38,Default,,0,0,0,,规则系统的运行原理 -- 也就是合一算法 Dialogue: 0,0:33:17.39,0:33:18.75,Default,,0,0,0,,因此 正式的定义就是 Dialogue: 0,0:33:19.20,0:33:20.96,Default,,0,0,0,,应用一条规则 Dialogue: 0,0:33:24.17,0:33:27.13,Default,,0,0,0,,我们需要使用一些之前的术语 Dialogue: 0,0:33:28.27,0:33:32.01,Default,,0,0,0,,我们把向查询的盒子中 Dialogue: 0,0:33:32.88,0:33:34.78,Default,,0,0,0,,塞入字典称作是 Dialogue: 0,0:33:34.81,0:33:38.54,Default,,0,0,0,,相对一个环境或者框架 Dialogue: 0,0:33:39.95,0:33:43.85,Default,,0,0,0,,对这些大型查询求值 Dialogue: 0,0:33:43.85,0:33:45.04,Default,,0,0,0,,因此 当我们谈及“字典”的时候 Dialogue: 0,0:33:45.07,0:33:46.28,Default,,0,0,0,,“字典”究竟是什么? Dialogue: 0,0:33:46.72,0:33:48.18,Default,,0,0,0,,它是符号的一系列语义 Dialogue: 0,0:33:48.18,0:33:50.22,Default,,0,0,0,,我们把它叫做“框架”或者“环境” Dialogue: 0,0:33:51.80,0:33:55.97,Default,,0,0,0,,根据环境进行操作 又是什么? Dialogue: 0,0:33:55.97,0:33:57.42,Default,,0,0,0,,我们把这个叫做“求值” Dialogue: 0,0:33:58.33,0:34:01.56,Default,,0,0,0,,因此我们就说 应用一条规则的方法是 Dialogue: 0,0:34:01.92,0:34:06.16,Default,,0,0,0,,先通过将给定的查询与规则的结论合一 得到环境 Dialogue: 0,0:34:06.67,0:34:11.58,Default,,0,0,0,,再在该环境中求值相应规则的体 Dialogue: 0,0:34:13.23,0:34:14.51,Default,,0,0,0,,我想要让你们注意的是 Dialogue: 0,0:34:14.80,0:34:17.08,Default,,0,0,0,,这非常像是 Dialogue: 0,0:34:18.16,0:34:21.50,Default,,0,0,0,,元循环求值器以及代换模型 Dialogue: 0,0:34:21.63,0:34:22.73,Default,,0,0,0,,规则的应用就是 Dialogue: 0,0:34:22.86,0:34:28.36,Default,,0,0,0,,在一个环境中求值规则的体 Dialogue: 0,0:34:28.54,0:34:33.13,Default,,0,0,0,,环境是通过将实际参数与形式参数绑定起来得到的 Dialogue: 0,0:34:34.56,0:34:36.41,Default,,0,0,0,,规则、规则的应用、过程的应用 Dialogue: 0,0:34:36.44,0:34:40.41,Default,,0,0,0,,它们在形式上完全相似 Dialogue: 0,0:34:40.57,0:34:42.30,Default,,0,0,0,,尽管它们又非常不同 Dialogue: 0,0:34:43.65,0:34:45.61,Default,,0,0,0,,再一次地出现了EVAL-APPLY循环 Dialogue: 0,0:34:47.29,0:34:49.52,Default,,0,0,0,,EVAL-APPLY Dialogue: 0,0:34:53.39,0:34:57.39,Default,,0,0,0,,因此通常来说 我们可能会处理一些复合表达式 Dialogue: 0,0:34:57.42,0:34:59.13,Default,,0,0,0,,它们会变成规则的应用 Dialogue: 0,0:35:00.70,0:35:03.28,Default,,0,0,0,,进一步又会产生字典、框架或者环境 Dialogue: 0,0:35:03.31,0:35:04.72,Default,,0,0,0,,不管你要怎么叫它 Dialogue: 0,0:35:05.02,0:35:08.43,Default,,0,0,0,,它们随后又会作为某个大的复合对象的输入 Dialogue: 0,0:35:08.66,0:35:11.77,Default,,0,0,0,,这有它的一部分 并可能有其它规则的应用 Dialogue: 0,0:35:13.58,0:35:15.68,Default,,0,0,0,,这基本上就是相同的循环 Dialogue: 0,0:35:15.72,0:35:18.68,Default,,0,0,0,,尽管这里没有什么东西看起来像过程 Dialogue: 0,0:35:19.68,0:35:21.87,Default,,0,0,0,,这是因为我们创建的语言 Dialogue: 0,0:35:22.08,0:35:25.49,Default,,0,0,0,,它们的组合手段和抽象手段以某种方式展开 Dialogue: 0,0:35:28.77,0:35:29.52,Default,,0,0,0,,通常来说 Dialogue: 0,0:35:29.77,0:35:31.39,Default,,0,0,0,,最顶层所发生的是 Dialogue: 0,0:35:33.79,0:35:35.96,Default,,0,0,0,,数据库中也有一些规则 Dialogue: 0,0:35:36.65,0:35:38.70,Default,,0,0,0,,数据库中的数据也可能是规则 Dialogue: 0,0:35:40.46,0:35:42.06,Default,,0,0,0,,它们用来检查对象是否为真 Dialogue: 0,0:35:42.92,0:35:44.89,Default,,0,0,0,,所以这里可能会有规则检查 Dialogue: 0,0:35:46.75,0:35:48.16,Default,,0,0,0,,然后就会有一些控制结构 Dialogue: 0,0:35:48.19,0:35:50.48,Default,,0,0,0,,用来判断你访问的是规则 Dialogue: 0,0:35:50.51,0:35:51.80,Default,,0,0,0,,还是数据元素 Dialogue: 0,0:35:51.84,0:35:53.12,Default,,0,0,0,,然后不断地把它们扇出来开 Dialogue: 0,0:35:53.35,0:35:55.48,Default,,0,0,0,,所以基本上不可能说清楚 Dialogue: 0,0:35:55.68,0:35:57.69,Default,,0,0,0,,是用什么样的顺序来查询这些东西的 Dialogue: 0,0:35:58.20,0:36:00.27,Default,,0,0,0,,是广度优先还是深度优先 Dialogue: 0,0:36:00.28,0:36:01.64,Default,,0,0,0,,另外一个原因是 Dialogue: 0,0:36:01.66,0:36:05.58,Default,,0,0,0,,我们通过惰性流隐藏了实际执行顺序 Dialogue: 0,0:36:07.69,0:36:11.16,Default,,0,0,0,,因此很难说清楚它的扫描顺序 Dialogue: 0,0:36:11.27,0:36:12.16,Default,,0,0,0,,但真实的是 Dialogue: 0,0:36:12.19,0:36:13.64,Default,,0,0,0,,由于你是在流视图观察它的 Dialogue: 0,0:36:13.90,0:36:15.82,Default,,0,0,0,,而它们最终都要被扫描到 Dialogue: 0,0:36:24.98,0:36:28.15,Default,,0,0,0,,这里还有一个小小的技术问题 Dialogue: 0,0:36:30.88,0:36:33.55,Default,,0,0,0,,假设我在这里输入 Dialogue: 0,0:36:37.53,0:36:41.00,Default,,0,0,0,,假设我输入(BOSS ?Y COMPUTER) Dialogue: 0,0:36:44.22,0:36:45.78,Default,,0,0,0,,然后就会发生一件有意思的事儿 Dialogue: 0,0:36:45.78,0:36:50.25,Default,,0,0,0,,这里的字典就有一项?Y Dialogue: 0,0:36:52.73,0:36:57.37,Default,,0,0,0,,而这两个?Y是不相同的 Dialogue: 0,0:36:57.42,0:37:00.62,Default,,0,0,0,,后者是其它人的工作描述 Dialogue: 0,0:37:01.58,0:37:03.80,Default,,0,0,0,,因此 按照输入“照本宣科”地执行的话 Dialogue: 0,0:37:04.22,0:37:06.44,Default,,0,0,0,,我们就会遇到变量冲突的问题 Dialogue: 0,0:37:09.28,0:37:10.48,Default,,0,0,0,,所以我骗了你们一下 Dialogue: 0,0:37:10.93,0:37:13.84,Default,,0,0,0,,注意 我们之前也遇到过同样的问题 Dialogue: 0,0:37:14.27,0:37:15.56,Default,,0,0,0,,具体来说就是 Dialogue: 0,0:37:15.96,0:37:18.36,Default,,0,0,0,,一门语言需要局部变量 Dialogue: 0,0:37:19.24,0:37:21.74,Default,,0,0,0,,当我计算SQUARE和SUM-SQUARES的时候 Dialogue: 0,0:37:21.79,0:37:23.39,Default,,0,0,0,,这两个X应该是不同的 Dialogue: 0,0:37:24.96,0:37:26.32,Default,,0,0,0,,同样的道理 Dialogue: 0,0:37:27.39,0:37:29.77,Default,,0,0,0,,这两个?Y应该也不相同 Dialogue: 0,0:37:31.80,0:37:32.75,Default,,0,0,0,,我们知道该如何解决 Dialogue: 0,0:37:32.78,0:37:34.49,Default,,0,0,0,,就是引入环境模型 Dialogue: 0,0:37:34.51,0:37:37.04,Default,,0,0,0,,我们构建类似于“框架链”一类的东西 Dialogue: 0,0:37:37.71,0:37:39.10,Default,,0,0,0,,还有更加“粗暴”的解决方法 Dialogue: 0,0:37:39.10,0:37:41.73,Default,,0,0,0,,在查询语言中 我们根本不这么做 Dialogue: 0,0:37:41.73,0:37:43.18,Default,,0,0,0,,我们的解决方法非常粗暴 Dialogue: 0,0:37:43.54,0:37:45.93,Default,,0,0,0,,我们规定 每次你在应用一条规则的时候 Dialogue: 0,0:37:47.26,0:37:49.63,Default,,0,0,0,,用一个不会引起冲突的唯一名字 Dialogue: 0,0:37:49.77,0:37:53.50,Default,,0,0,0,,统一地为规则中的所有变量更名 Dialogue: 0,0:37:54.04,0:37:57.10,Default,,0,0,0,,这个从概念上来说更简单 Dialogue: 0,0:37:57.12,0:37:59.24,Default,,0,0,0,,但既粗暴 又不是很有效 Dialogue: 0,0:37:59.97,0:38:01.15,Default,,0,0,0,,但是请注意 Dialogue: 0,0:38:01.39,0:38:04.68,Default,,0,0,0,,如果我们对Lisp中定义的过程也这么处理 Dialogue: 0,0:38:05.50,0:38:08.72,Default,,0,0,0,,那么就不需要环境模型了 Dialogue: 0,0:38:08.75,0:38:11.56,Default,,0,0,0,,如果我们每次在应用一个过程的时候 Dialogue: 0,0:38:11.87,0:38:13.90,Default,,0,0,0,,我们为过程中的所有变量更名 Dialogue: 0,0:38:14.19,0:38:16.28,Default,,0,0,0,,那么我们就不需要担心局部变量了 Dialogue: 0,0:38:16.33,0:38:17.39,Default,,0,0,0,,因为它们不会出现 Dialogue: 0,0:38:19.04,0:38:20.41,Default,,0,0,0,,但这种做法比较低效 Dialogue: 0,0:38:20.91,0:38:23.04,Default,,0,0,0,,在我们的查询语言中同样也比较低效 Dialogue: 0,0:38:23.29,0:38:24.59,Default,,0,0,0,,但我们还是这样做了 并让它保持简单 Dialogue: 0,0:38:25.61,0:38:26.67,Default,,0,0,0,,有问题吗? Dialogue: 0,0:38:30.88,0:38:33.39,Default,,0,0,0,,学生:您这一小节开始的时候 Dialogue: 0,0:38:33.40,0:38:39.60,Default,,0,0,0,,就强调APPLY-EVAL模型是多么的强大 Dialogue: 0,0:38:39.63,0:38:41.17,Default,,0,0,0,,以至于任何语言都适用 Dialogue: 0,0:38:41.17,0:38:43.39,Default,,0,0,0,,但你又说这门语言将会非常不同 Dialogue: 0,0:38:43.95,0:38:45.13,Default,,0,0,0,,但最后却发现这门语言 Dialogue: 0,0:38:45.58,0:38:47.88,Default,,0,0,0,,就像你指出的那样--也是同样的 Dialogue: 0,0:38:47.88,0:38:49.85,Default,,0,0,0,,我在想 您是否是在论证 Dialogue: 0,0:38:50.48,0:38:54.57,Default,,0,0,0,,所有的语言都可以转化成 规则或过程的应用 Dialogue: 0,0:38:55.12,0:38:55.98,Default,,0,0,0,,或者类似的 Dialogue: 0,0:38:57.07,0:38:58.88,Default,,0,0,0,,教授:可以说 几乎所有语言 Dialogue: 0,0:38:58.92,0:39:00.30,Default,,0,0,0,,我们通过组合手段构建对象 Dialogue: 0,0:39:00.92,0:39:04.40,Default,,0,0,0,,用简单的名字给它们命名 Dialogue: 0,0:39:04.70,0:39:06.86,Default,,0,0,0,,你可以把任何类似的 比如 Dialogue: 0,0:39:07.79,0:39:09.90,Default,,0,0,0,,有一种一般性的表达式 Dialogue: 0,0:39:09.98,0:39:11.40,Default,,0,0,0,,比如说如何计算某数的平方 Dialogue: 0,0:39:12.03,0:39:14.20,Default,,0,0,0,,几乎所有的东西都可以称为“过程” Dialogue: 0,0:39:14.88,0:39:15.88,Default,,0,0,0,,如果语言中有这么一部分的话 Dialogue: 0,0:39:15.90,0:39:17.24,Default,,0,0,0,,那么你就需要能够展开它们 Dialogue: 0,0:39:18.02,0:39:20.19,Default,,0,0,0,,你需要有某种组织 使得 Dialogue: 0,0:39:20.57,0:39:24.03,Default,,0,0,0,,当你查看这些抽象变量 或者说标签的时候 Dialogue: 0,0:39:24.06,0:39:27.10,Default,,0,0,0,,它们可能代表着某些特定的东西 Dialogue: 0,0:39:28.33,0:39:29.34,Default,,0,0,0,,你必须一直跟踪它们 Dialogue: 0,0:39:29.39,0:39:30.91,Default,,0,0,0,,这就会形成类似于环境的结构 Dialogue: 0,0:39:31.72,0:39:32.54,Default,,0,0,0,,让后当你要 Dialogue: 0,0:39:32.70,0:39:35.26,Default,,0,0,0,,展开复合对象其中的一个部分的时候 Dialogue: 0,0:39:35.80,0:39:37.44,Default,,0,0,0,,你就需要EVAL-APPLY循环了 Dialogue: 0,0:39:39.97,0:39:43.20,Default,,0,0,0,,有很多很多的语言有这样的特点 Dialogue: 0,0:39:43.36,0:39:45.40,Default,,0,0,0,,它们也是按这种方式组织的 Dialogue: 0,0:39:45.59,0:39:47.20,Default,,0,0,0,,而这门语言特殊之处在于 Dialogue: 0,0:39:47.21,0:39:49.50,Default,,0,0,0,,从外界看 并没有“过程” Dialogue: 0,0:39:50.69,0:39:52.68,Default,,0,0,0,,而当你剖开表层 深入到实现中去 Dialogue: 0,0:39:52.70,0:39:54.24,Default,,0,0,0,,当然 你会发现本质是一样的 Dialogue: 0,0:39:54.87,0:39:56.95,Default,,0,0,0,,但是从外界来看 这是一种非常不同的世界观 Dialogue: 0,0:39:56.95,0:39:58.54,Default,,0,0,0,,你没有计算输入的函数 Dialogue: 0,0:40:03.97,0:40:05.71,Default,,0,0,0,,学生:您之前提到过 Dialogue: 0,0:40:06.60,0:40:09.55,Default,,0,0,0,,当用模式匹配来实现这些规则时 Dialogue: 0,0:40:10.01,0:40:11.42,Default,,0,0,0,,由于使用了流实现延迟求值 Dialogue: 0,0:40:11.45,0:40:12.72,Default,,0,0,0,,所以没有办法知道 Dialogue: 0,0:40:13.37,0:40:15.36,Default,,0,0,0,,对象的求值顺序 Dialogue: 0,0:40:15.58,0:40:15.94,Default,,0,0,0,,教授:是这样的 Dialogue: 0,0:40:15.94,0:40:18.28,Default,,0,0,0,,学生:但这就表明 Dialogue: 0,0:40:18.94,0:40:22.28,Default,,0,0,0,,我们只能表达总是为真的陈述性知识 Dialogue: 0,0:40:22.30,0:40:23.79,Default,,0,0,0,,语言并不支持时间序列 Dialogue: 0,0:40:23.95,0:40:25.47,Default,,0,0,0,,否则的话 后果就会-- Dialogue: 0,0:40:27.39,0:40:28.76,Default,,0,0,0,,教授:是的 非常正确 Dialogue: 0,0:40:28.82,0:40:29.48,Default,,0,0,0,,问题在于 Dialogue: 0,0:40:30.06,0:40:32.60,Default,,0,0,0,,这个本来就是用来处理陈述性知识的 Dialogue: 0,0:40:33.26,0:40:34.81,Default,,0,0,0,,而就我目前所演示的来说 不支持 Dialogue: 0,0:40:35.71,0:40:39.56,Default,,0,0,0,,休息之后我会向你们揭露这其中的丑陋之处 Dialogue: 0,0:40:40.83,0:40:42.60,Default,,0,0,0,,就如我目前所展示的 它只是进行逻辑运算 Dialogue: 0,0:40:43.07,0:40:44.52,Default,,0,0,0,,原理上来说 如果我们做的是逻辑运算 Dialogue: 0,0:40:44.54,0:40:46.81,Default,,0,0,0,,用什么顺序完成并不会造成影响 Dialogue: 0,0:40:48.84,0:40:51.55,Default,,0,0,0,,但是呢 Dialogue: 0,0:40:51.60,0:40:53.61,Default,,0,0,0,,当你在进行一些具有副作用的操作的时候 Dialogue: 0,0:40:53.68,0:40:55.20,Default,,0,0,0,,比如向数据库中添加项 Dialogue: 0,0:40:55.23,0:40:58.16,Default,,0,0,0,,从中取出项 等等操作 Dialogue: 0,0:40:58.75,0:41:00.83,Default,,0,0,0,,你就丧失了这类控制 Dialogue: 0,0:41:01.29,0:41:02.94,Default,,0,0,0,,因此 这就与Prolog完全不同 Dialogue: 0,0:41:02.94,0:41:05.15,Default,,0,0,0,,Prolog有各种功能 Dialogue: 0,0:41:05.16,0:41:07.79,Default,,0,0,0,,能够让你利用求值的顺序 Dialogue: 0,0:41:09.64,0:41:11.77,Default,,0,0,0,,人们也这么来写Prolog Dialogue: 0,0:41:11.77,0:41:14.04,Default,,0,0,0,,结果发现这样变得非常困难 Dialogue: 0,0:41:14.32,0:41:17.55,Default,,0,0,0,,但如果你是Prolog程序专家 你就可以这么做 Dialogue: 0,0:41:18.59,0:41:20.21,Default,,0,0,0,,但是我认为你们现在并不可以 Dialogue: 0,0:41:20.21,0:41:21.24,Default,,0,0,0,,它相当复杂 Dialogue: 0,0:41:21.72,0:41:23.64,Default,,0,0,0,,因为你们放弃了对事先安排的 Dialogue: 0,0:41:23.77,0:41:25.72,Default,,0,0,0,,求值顺序的控制权 Dialogue: 0,0:41:27.15,0:41:30.16,Default,,0,0,0,,学生:这就表明 当你有一个函数式映射时 Dialogue: 0,0:41:30.67,0:41:32.51,Default,,0,0,0,,而你最初在讲这门课的时候 Dialogue: 0,0:41:32.99,0:41:34.08,Default,,0,0,0,,你说过 Dialogue: 0,0:41:34.67,0:41:36.70,Default,,0,0,0,,我们在表述作为关系的陈述性知识 Dialogue: 0,0:41:37.15,0:41:38.81,Default,,0,0,0,,因为我们讨论的不是输入和输出 Dialogue: 0,0:41:41.21,0:41:43.37,Default,,0,0,0,,教授:这是关于“函数式”的双关语 Dialogue: 0,0:41:43.37,0:41:45.79,Default,,0,0,0,,一种是没有副作用 Dialogue: 0,0:41:46.20,0:41:48.16,Default,,0,0,0,,因此并不依赖于求值的顺序 Dialogue: 0,0:41:48.70,0:41:51.04,Default,,0,0,0,,还有就是数学意义上的“函数” Dialogue: 0,0:41:51.07,0:41:52.22,Default,,0,0,0,,有关于输入和输出 Dialogue: 0,0:41:52.59,0:41:54.36,Default,,0,0,0,,我想这就是你想表达的双关 Dialogue: 0,0:41:56.51,0:41:58.51,Default,,0,0,0,,学生:我对其中两条语句不太明白 Dialogue: 0,0:41:58.81,0:42:00.70,Default,,0,0,0,,也就是那两条有关BOSS的语句 Dialogue: 0,0:42:01.27,0:42:05.74,Default,,0,0,0,,是不是 第一条查询构建了一个数据库 Dialogue: 0,0:42:05.76,0:42:08.08,Default,,0,0,0,,然后第二条查询-- Dialogue: 0,0:42:09.07,0:42:10.12,Default,,0,0,0,,教授:抱歉 Dialogue: 0,0:42:12.44,0:42:15.16,Default,,0,0,0,,这里的意思是 如果我输入这样的查询 Dialogue: 0,0:42:16.12,0:42:18.44,Default,,0,0,0,,我应该最初就给你们举这个例子 Dialogue: 0,0:42:19.47,0:42:23.52,Default,,0,0,0,,如果我输入(JOB (BITDIDDLE BEN) (COMPUTER WIZARD)) Dialogue: 0,0:42:25.04,0:42:27.77,Default,,0,0,0,,系统会找到一处事实 Dialogue: 0,0:42:28.30,0:42:30.28,Default,,0,0,0,,来完全匹配这条查询 Dialogue: 0,0:42:30.86,0:42:33.28,Default,,0,0,0,,然后输出(JOB (BITDIDDLE BEN) (COMPUTER WIZARD)) Dialogue: 0,0:42:34.22,0:42:35.60,Default,,0,0,0,,如果没找到这样的匹配 Dialogue: 0,0:42:35.69,0:42:36.75,Default,,0,0,0,,它就什么也不输出 Dialogue: 0,0:42:37.40,0:42:39.55,Default,,0,0,0,,我应该这么来表述 Dialogue: 0,0:42:39.56,0:42:42.27,Default,,0,0,0,,这门语言是用来查询某个表述是否为真 Dialogue: 0,0:42:43.40,0:42:45.77,Default,,0,0,0,,这是逻辑式编程的目的之一 Dialogue: 0,0:42:46.41,0:42:49.34,Default,,0,0,0,,输入一条查询 要么得到结果 要么没有 Dialogue: 0,0:42:50.68,0:42:52.38,Default,,0,0,0,,因此 我这里想要演示的是 Dialogue: 0,0:42:52.41,0:42:54.80,Default,,0,0,0,,我想要在介绍合一算法前 Dialogue: 0,0:42:54.83,0:42:56.62,Default,,0,0,0,,举一个简单的例子 Dialogue: 0,0:42:57.48,0:42:58.11,Default,,0,0,0,,所以 我应该说 Dialogue: 0,0:42:58.14,0:43:00.96,Default,,0,0,0,,如果我想要检查 这个是否为真 Dialogue: 0,0:43:01.18,0:43:03.28,Default,,0,0,0,,我就可以将它输入 并看有没有任何输出 Dialogue: 0,0:43:05.16,0:43:06.27,Default,,0,0,0,,学生:然后第二条查询 Dialogue: 0,0:43:06.28,0:43:07.84,Default,,0,0,0,,教授:第二条就是真正意义上的“查询” Dialogue: 0,0:43:07.88,0:43:09.12,Default,,0,0,0,,学生:好的 真正的查询 Dialogue: 0,0:43:10.77,0:43:13.10,Default,,0,0,0,,教授:在这里它就会输出与?WHO相关的信息 Dialogue: 0,0:43:13.90,0:43:15.74,Default,,0,0,0,,就会有一个框架 存储着 Dialogue: 0,0:43:16.62,0:43:18.81,Default,,0,0,0,,?Z=?WHO ?D=COMPUTER Dialogue: 0,0:43:19.56,0:43:20.49,Default,,0,0,0,,这个会传递下去 Dialogue: 0,0:43:20.51,0:43:21.95,Default,,0,0,0,,传递到这里的时候 Dialogue: 0,0:43:22.01,0:43:23.25,Default,,0,0,0,,?WHO就会被绑定起来 Dialogue: 0,0:43:26.95,0:43:28.76,Default,,0,0,0,,学生:在合一那里 Dialogue: 0,0:43:29.18,0:43:35.96,Default,,0,0,0,,我还是不太清楚?WHO和?Z之间发生了什么 Dialogue: 0,0:43:36.46,0:43:39.58,Default,,0,0,0,,要进行合一的话 这里的规则说 Dialogue: 0,0:43:42.03,0:43:46.22,Default,,0,0,0,,你说过 两个模式变量之间不能互相绑定 Dialogue: 0,0:43:46.26,0:43:48.08,Default,,0,0,0,,教授:模式匹配器确实不能这样 Dialogue: 0,0:43:48.36,0:43:50.83,Default,,0,0,0,,但对合一算法来说 Dialogue: 0,0:43:51.92,0:43:54.01,Default,,0,0,0,,就是一个有存储三个变量的环境 Dialogue: 0,0:43:56.69,0:43:57.90,Default,,0,0,0,,其中?D=COMPUTER Dialogue: 0,0:43:58.52,0:44:00.19,Default,,0,0,0,,?Z=?WHO Dialogue: 0,0:44:01.83,0:44:05.26,Default,,0,0,0,,所以在稍后的匹配过程中 Dialogue: 0,0:44:07.20,0:44:10.38,Default,,0,0,0,,如果?WHO=3 Dialogue: 0,0:44:12.06,0:44:13.66,Default,,0,0,0,,那么当我再查找字典的时候 Dialogue: 0,0:44:14.00,0:44:16.40,Default,,0,0,0,,它会告诉我 因为?Z=?WHO 所以?Z=3 Dialogue: 0,0:44:18.36,0:44:20.44,Default,,0,0,0,,从某种意义上来说 你就只需要修改这一点 Dialogue: 0,0:44:20.46,0:44:21.98,Default,,0,0,0,,就可以把合一算法变成模式匹配器 Dialogue: 0,0:44:22.48,0:44:24.80,Default,,0,0,0,,学生:但是看起来你好像告诉了它 如何进行合一 Dialogue: 0,0:44:24.83,0:44:26.96,Default,,0,0,0,,就像你已经解好了方程 准备好了值 Dialogue: 0,0:44:26.99,0:44:29.23,Default,,0,0,0,,并把它们安排成这样 Dialogue: 0,0:44:29.77,0:44:31.24,Default,,0,0,0,,现在看起来就像是 Dialogue: 0,0:44:31.28,0:44:32.83,Default,,0,0,0,,你传递了一本字典 Dialogue: 0,0:44:32.88,0:44:34.86,Default,,0,0,0,,其中的两个变量是关联起来的 Dialogue: 0,0:44:34.88,0:44:37.23,Default,,0,0,0,,教授:实际上 我们在同时求解它们 Dialogue: 0,0:44:37.52,0:44:39.74,Default,,0,0,0,,这是因为我们想要一下得到整个答案 Dialogue: 0,0:44:40.54,0:44:42.81,Default,,0,0,0,,如果你观察它们是如何被递归地构建的 Dialogue: 0,0:44:42.81,0:44:43.74,Default,,0,0,0,,基本上就是这样了 Dialogue: 0,0:44:44.98,0:44:48.40,Default,,0,0,0,,学生:也就是确实要传递含有两个变量的字典? Dialogue: 0,0:44:48.40,0:44:49.11,Default,,0,0,0,,教授:是的 Dialogue: 0,0:44:49.11,0:44:49.68,Default,,0,0,0,,学生:然后把它们关联起来? Dialogue: 0,0:44:50.38,0:44:52.91,Default,,0,0,0,,教授:就像通常的字典那样 Dialogue: 0,0:44:54.35,0:44:56.06,Default,,0,0,0,,学生:你在讨论合一算法的时候 Dialogue: 0,0:44:56.09,0:45:00.19,Default,,0,0,0,,你说过在某些情况下 Dialogue: 0,0:45:00.75,0:45:03.98,Default,,0,0,0,,合一不能够完成 Dialogue: 0,0:45:04.03,0:45:04.30,Default,,0,0,0,,教授:是的 Dialogue: 0,0:45:04.97,0:45:08.46,Default,,0,0,0,,学生:那么 是否可以通过编写规则 Dialogue: 0,0:45:09.16,0:45:15.93,Default,,0,0,0,,或者 写入那些事先知道可解的形式 Dialogue: 0,0:45:16.48,0:45:18.54,Default,,0,0,0,,来使得合一算法能够完成 Dialogue: 0,0:45:18.76,0:45:22.94,Default,,0,0,0,,是否可以在规则中添加一些属性 Dialogue: 0,0:45:23.18,0:45:25.45,Default,,0,0,0,,或者向输入的形式中添加属性 Dialogue: 0,0:45:25.82,0:45:29.04,Default,,0,0,0,,来避免无法进行合一的窘境 Dialogue: 0,0:45:29.18,0:45:31.15,Default,,0,0,0,,PROFESSOR: 我想 你也同意 Dialogue: 0,0:45:31.47,0:45:35.26,Default,,0,0,0,,用非常受限的方式来编写查询 Dialogue: 0,0:45:35.60,0:45:36.67,Default,,0,0,0,,看 你遇到的是 Dialogue: 0,0:45:36.88,0:45:39.12,Default,,0,0,0,,仔细看 你遇到问题是在 Dialogue: 0,0:45:39.68,0:45:44.25,Default,,0,0,0,,用像这样的东西去匹配 Dialogue: 0,0:45:44.59,0:45:47.20,Default,,0,0,0,,具有这样结构的模式时 Dialogue: 0,0:45:47.55,0:45:55.30,Default,,0,0,0,,比如((A ?Y B) ?Y) Dialogue: 0,0:45:58.98,0:46:01.48,Default,,0,0,0,,这是你可能遇到问题的一个地方 Dialogue: 0,0:46:03.07,0:46:05.80,Default,,0,0,0,,学生:所以你可以在语法层次上处理它么? Dialogue: 0,0:46:06.14,0:46:08.76,Default,,0,0,0,,教授:你可以在写查询时 Dialogue: 0,0:46:08.76,0:46:10.49,Default,,0,0,0,,注意你的规则 Dialogue: 0,0:46:11.90,0:46:14.08,Default,,0,0,0,,学生:这个问题应该由 Dialogue: 0,0:46:14.11,0:46:16.27,Default,,0,0,0,,数据库的构建者考虑么? Dialogue: 0,0:46:16.57,0:46:17.80,Default,,0,0,0,,教授:这个问题 Dialogue: 0,0:46:19.93,0:46:22.01,Default,,0,0,0,,不完全是数据库的构建者 Dialogue: 0,0:46:22.04,0:46:23.61,Default,,0,0,0,,或者是表述规则的人 Dialogue: 0,0:46:24.01,0:46:25.31,Default,,0,0,0,,所需要考虑的 Dialogue: 0,0:46:25.80,0:46:29.79,Default,,0,0,0,,当你们仔细审查合一算法的代码时 Dialogue: 0,0:46:29.92,0:46:31.87,Default,,0,0,0,,你们会发现 Dialogue: 0,0:46:32.41,0:46:34.76,Default,,0,0,0,,它实际上在查询一个字典 Dialogue: 0,0:46:34.94,0:46:36.83,Default,,0,0,0,,它会问 ?Y的取值应该是什么? Dialogue: 0,0:46:37.26,0:46:41.42,Default,,0,0,0,,?Y应该是一个含有自包含的表达式么? Dialogue: 0,0:46:41.96,0:46:43.26,Default,,0,0,0,,这时候 合一算法就会说 Dialogue: 0,0:46:43.28,0:46:46.24,Default,,0,0,0,,哦 我正在求解一个不动点方程 Dialogue: 0,0:46:46.24,0:46:46.99,Default,,0,0,0,,我还是放弃吧 Dialogue: 0,0:46:48.59,0:46:51.91,Default,,0,0,0,,学生:你区分过数据库中的规则 Dialogue: 0,0:46:51.91,0:46:56.48,Default,,0,0,0,,这些规则是加入数据库的么? Dialogue: 0,0:46:56.95,0:46:57.36,Default,,0,0,0,,教授:是的 Dialogue: 0,0:46:57.87,0:46:58.87,Default,,0,0,0,,我应该这么来说 Dialogue: 0,0:46:58.87,0:47:00.33,Default,,0,0,0,,你们可以把规则看作 Dialogue: 0,0:47:00.60,0:47:02.65,Default,,0,0,0,,数据库中的其它东西 Dialogue: 0,0:47:03.71,0:47:06.81,Default,,0,0,0,,如果你想要检查数据库中需要检查的东西 Dialogue: 0,0:47:06.83,0:47:09.44,Default,,0,0,0,,它们就是存在于数据库中的虚拟事实 Dialogue: 0,0:47:09.44,0:47:12.32,Default,,0,0,0,,学生:但是在这个解释中 Dialogue: 0,0:47:12.43,0:47:17.26,Default,,0,0,0,,你就已经区分了数据库和规则本身 Dialogue: 0,0:47:18.23,0:47:19.90,Default,,0,0,0,,教授:是的 我应该不这么来说 Dialogue: 0,0:47:20.49,0:47:23.31,Default,,0,0,0,,这样做的唯一理由就是实现 Dialogue: 0,0:47:23.54,0:47:24.67,Default,,0,0,0,,当你们查看具体实现时 Dialogue: 0,0:47:24.68,0:47:27.50,Default,,0,0,0,,会发现其中有部分用来检查数据库中的 Dialogue: 0,0:47:27.55,0:47:29.85,Default,,0,0,0,,基本断言或者规则 Dialogue: 0,0:47:30.47,0:47:32.72,Default,,0,0,0,,这其中的真正原因就是 Dialogue: 0,0:47:32.78,0:47:34.56,Default,,0,0,0,,你不知道查询结果是以什么顺序输出的 Dialogue: 0,0:47:34.96,0:47:40.46,Default,,0,0,0,,而规则数据库和数据数据库 Dialogue: 0,0:47:40.48,0:47:43.68,Default,,0,0,0,,是通过某种延迟求值的方式合并的 Dialogue: 0,0:47:44.60,0:47:46.80,Default,,0,0,0,,这就使得顺序变得非常复杂 Dialogue: 0,0:47:55.44,0:47:56.09,Default,,0,0,0,,那好 我们休息一下 Dialogue: 0,0:47:56.30,0:48:09.90,Default,,0,0,0,,[音乐] Dialogue: 0,0:48:10.04,0:48:14.41,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:48:18.68,0:48:22.09,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:48:22.09,0:48:25.96,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:48:26.00,0:48:29.87,Declare,,0,0,0,,{\an2\fad(500,500)}逻辑式程序设计 II Dialogue: 0,0:48:33.16,0:48:35.37,Default,,0,0,0,,我们已经学习了逻辑式语言与 Dialogue: 0,0:48:35.39,0:48:36.41,Default,,0,0,0,,规则系统的运行原理 Dialogue: 0,0:48:37.23,0:48:39.37,Default,,0,0,0,,现在 让我们来探讨一个更加深刻的问题 Dialogue: 0,0:48:40.12,0:48:41.28,Default,,0,0,0,,来看下它们意味着什么 Dialogue: 0,0:48:43.18,0:48:46.86,Default,,0,0,0,,这把我们带入到整个查询语言中 Dialogue: 0,0:48:46.99,0:48:48.67,Default,,0,0,0,,最微妙的部分 Dialogue: 0,0:48:49.21,0:48:53.07,Default,,0,0,0,,也就是它看起来与想象中不同的地方 Dialogue: 0,0:48:53.57,0:48:56.22,Default,,0,0,0,,AND、OR以及NOT Dialogue: 0,0:48:57.02,0:48:58.88,Default,,0,0,0,,以及规则的逻辑蕴含 Dialogue: 0,0:48:59.69,0:49:06.64,Default,,0,0,0,,并不是逻辑学中的与、或、非以及蕴含 Dialogue: 0,0:49:07.69,0:49:09.71,Default,,0,0,0,,让我来举一个实例 Dialogue: 0,0:49:09.91,0:49:12.22,Default,,0,0,0,,当然 如果我们有两个逻辑命题 Dialogue: 0,0:49:12.40,0:49:19.44,Default,,0,0,0,,那么(AND P Q)就应该 Dialogue: 0,0:49:20.00,0:49:22.59,Default,,0,0,0,,等同于(AND Q P) Dialogue: 0,0:49:23.10,0:49:24.51,Default,,0,0,0,,而(OR P Q)就应该 Dialogue: 0,0:49:24.78,0:49:26.51,Default,,0,0,0,,等同于(OR Q P) Dialogue: 0,0:49:28.67,0:49:30.09,Default,,0,0,0,,但我们来看看这里 Dialogue: 0,0:49:30.10,0:49:32.01,Default,,0,0,0,,这里是一个例子 Dialogue: 0,0:49:32.18,0:49:36.16,Default,,0,0,0,,来看看 在我们的数据库中 Dialogue: 0,0:49:36.28,0:49:40.14,Default,,0,0,0,,如何表示某人的级别高于他人 Dialogue: 0,0:49:40.14,0:49:42.89,Default,,0,0,0,,我们定义(OUTRANKED-BY ?S ?B)为 Dialogue: 0,0:49:44.64,0:49:48.62,Default,,0,0,0,,或者S是B的上司 Dialogue: 0,0:49:49.63,0:49:51.07,Default,,0,0,0,,或者这其中有某个中间经理M Dialogue: 0,0:49:51.10,0:49:55.82,Default,,0,0,0,,其中S是M的上司 M的级别又比B高 Dialogue: 0,0:49:59.64,0:50:02.31,Default,,0,0,0,,这是定义OUTRANKED-BY的一种方式 Dialogue: 0,0:50:02.31,0:50:04.16,Default,,0,0,0,,或者我们可以原封不动地写过来 Dialogue: 0,0:50:05.08,0:50:06.91,Default,,0,0,0,,除了在最底部的这里 Dialogue: 0,0:50:07.21,0:50:09.88,Default,,0,0,0,,我们颠倒一下这两个子句的顺序 Dialogue: 0,0:50:11.63,0:50:12.99,Default,,0,0,0,,当然 如果它们都是逻辑表达式的话 Dialogue: 0,0:50:13.00,0:50:14.88,Default,,0,0,0,,它们应该表示的是相同的东西 Dialogue: 0,0:50:16.69,0:50:17.31,Default,,0,0,0,,然而 Dialogue: 0,0:50:17.71,0:50:19.61,Default,,0,0,0,,在我们这个特定的实现中 Dialogue: 0,0:50:19.64,0:50:22.88,Default,,0,0,0,,如果你查询(OUTRANDKED-BY ?WHO (BITDIIDLE BEN)) Dialogue: 0,0:50:23.48,0:50:25.36,Default,,0,0,0,,你会发现 这条规则 Dialogue: 0,0:50:26.76,0:50:28.72,Default,,0,0,0,,会完美地生成答案 Dialogue: 0,0:50:30.04,0:50:31.98,Default,,0,0,0,,然而 这条规则会陷入无穷循环 Dialogue: 0,0:50:34.11,0:50:36.27,Default,,0,0,0,,其中的原因就是 Dialogue: 0,0:50:36.33,0:50:40.33,Default,,0,0,0,,这条规则会问谁比BEN BITDIDDLE级别高? Dialogue: 0,0:50:41.92,0:50:43.53,Default,,0,0,0,,它试图寻找一个S Dialogue: 0,0:50:43.88,0:50:46.22,Default,,0,0,0,,使得S比B的级别更高 其中B是BEN BITDIDDLE Dialogue: 0,0:50:47.50,0:50:49.63,Default,,0,0,0,,这会在一个子问题中重复出现 Dialogue: 0,0:50:50.33,0:50:51.98,Default,,0,0,0,,找到一个M Dialogue: 0,0:50:52.24,0:50:54.57,Default,,0,0,0,,使得M的级别高于BEN BITDIDDLE Dialogue: 0,0:50:55.61,0:50:57.36,Default,,0,0,0,,而对M没有限制 Dialogue: 0,0:50:58.56,0:51:00.40,Default,,0,0,0,,这就相当于为了解决这个问题 Dialogue: 0,0:51:01.42,0:51:03.29,Default,,0,0,0,,我就还需要求解同样的问题 Dialogue: 0,0:51:04.57,0:51:07.23,Default,,0,0,0,,在把它解出来后 我才检查SUPERVISOR关系 Dialogue: 0,0:51:08.00,0:51:09.16,Default,,0,0,0,,然而这条规则没有这样的问题 Dialogue: 0,0:51:09.18,0:51:12.35,Default,,0,0,0,,因为在它尝试找出这条OUTRANKED-BY规则之前 Dialogue: 0,0:51:12.94,0:51:15.26,Default,,0,0,0,,在这里已经对M施加过约束了 Dialogue: 0,0:51:18.38,0:51:20.94,Default,,0,0,0,,随意 这两条规则理论上是相同的 Dialogue: 0,0:51:20.99,0:51:22.67,Default,,0,0,0,,但实际上 其中一条会陷入无穷循环 Dialogue: 0,0:51:22.86,0:51:25.04,Default,,0,0,0,,而另一条不会 Dialogue: 0,0:51:26.72,0:51:29.77,Default,,0,0,0,,通过这个非常极端的例子 Dialogue: 0,0:51:29.79,0:51:32.65,Default,,0,0,0,,你会发现在逻辑式程序设计中 Dialogue: 0,0:51:34.28,0:51:38.70,Default,,0,0,0,,如果你改变了AND或OR所连接子句的顺序 Dialogue: 0,0:51:39.34,0:51:41.58,Default,,0,0,0,,你会发现效率上的巨大差异 Dialogue: 0,0:51:42.24,0:51:43.21,Default,,0,0,0,,我们刚刚就看到了 Dialogue: 0,0:51:43.55,0:51:46.54,Default,,0,0,0,,在无穷循环方面的巨大差异 Dialogue: 0,0:51:49.19,0:51:51.74,Default,,0,0,0,,同样的 这也跟输入规则 Dialogue: 0,0:51:52.00,0:51:53.31,Default,,0,0,0,,的顺序有关 Dialogue: 0,0:51:54.07,0:51:56.48,Default,,0,0,0,,向数据库查询规则的顺序 Dialogue: 0,0:51:56.70,0:51:59.95,Default,,0,0,0,,会极大程度上影响效率:比如得到答案 Dialogue: 0,0:52:00.46,0:52:02.60,Default,,0,0,0,,或者在某些顺序下陷入无穷循环 Dialogue: 0,0:52:03.84,0:52:07.29,Default,,0,0,0,,这些都跟 Dialogue: 0,0:52:07.63,0:52:10.04,Default,,0,0,0,,你检查这些规则的顺序有关 Dialogue: 0,0:52:10.95,0:52:14.41,Default,,0,0,0,,有些规则的蕴含路径会相当的长 Dialogue: 0,0:52:14.44,0:52:16.06,Default,,0,0,0,,而另外一些不会 Dialogue: 0,0:52:16.44,0:52:17.68,Default,,0,0,0,,但你事先并不知道 Dialogue: 0,0:52:17.72,0:52:19.16,Default,,0,0,0,,哪一个长 哪一个短 Dialogue: 0,0:52:19.30,0:52:21.48,Default,,0,0,0,,有很多研究都与此有关 Dialogue: 0,0:52:22.16,0:52:23.76,Default,,0,0,0,,其中大多数都是想通过 Dialogue: 0,0:52:23.95,0:52:26.97,Default,,0,0,0,,用并行的方法来实现逻辑式程序设计语言 Dialogue: 0,0:52:27.32,0:52:29.90,Default,,0,0,0,,某种意义上来说 就是并行地检查所有规则 Dialogue: 0,0:52:30.36,0:52:32.80,Default,,0,0,0,,一旦有一条搜索得到答案 就返回结果 Dialogue: 0,0:52:33.04,0:52:34.99,Default,,0,0,0,,如果某条路径陷入了无穷的推导 Dialogue: 0,0:52:35.02,0:52:38.25,Default,,0,0,0,,那么 你只需知道 内存和处理器都非常廉价 Dialogue: 0,0:52:38.28,0:52:40.49,Default,,0,0,0,,让它们根据你的需要一直搜寻就好了 Dialogue: 0,0:52:43.47,0:52:44.83,Default,,0,0,0,,尽管如此 与真正的逻辑相比 Dialogue: 0,0:52:45.18,0:52:50.49,Default,,0,0,0,,这门逻辑式语言还有一个更深刻的问题 Dialogue: 0,0:52:50.68,0:52:52.52,Default,,0,0,0,,我给你们演示的例子 Dialogue: 0,0:52:52.97,0:52:54.80,Default,,0,0,0,,只是会陷入无穷循环 Dialogue: 0,0:52:55.37,0:52:56.99,Default,,0,0,0,,但至少不会给你错误的答案 Dialogue: 0,0:52:58.37,0:53:03.64,Default,,0,0,0,,当我们开始严肃地把这门逻辑式语言 Dialogue: 0,0:53:03.68,0:53:05.24,Default,,0,0,0,,与真正的经典逻辑作比较时 Dialogue: 0,0:53:05.71,0:53:08.46,Default,,0,0,0,,就会发现其中最深层次的问题 Dialogue: 0,0:53:09.49,0:53:12.43,Default,,0,0,0,,让我们来看看真正的经典逻辑 Dialogue: 0,0:53:13.71,0:53:21.04,Default,,0,0,0,,所有的人类都是凡人 Dialogue: 0,0:53:22.35,0:53:23.45,Default,,0,0,0,,相当经典的逻辑命题 Dialogue: 0,0:53:24.39,0:53:28.67,Default,,0,0,0,,然后我们就依照最经典的传统 Dialogue: 0,0:53:29.24,0:53:32.46,Default,,0,0,0,,我们按照最传统的方式来做 Dialogue: 0,0:53:32.67,0:53:37.16,Default,,0,0,0,,所有的希腊人都是人类 Dialogue: 0,0:53:40.49,0:53:46.06,Default,,0,0,0,,苏格拉底是希腊人 Dialogue: 0,0:53:48.17,0:53:49.21,Default,,0,0,0,,然后我们又该写什么呢? Dialogue: 0,0:53:49.21,0:53:51.89,Default,,0,0,0,,经典逻辑中有一个三点符号 Dialogue: 0,0:53:51.89,0:53:54.33,Default,,0,0,0,,因此 我们得到了一个三段论 Dialogue: 0,0:53:54.64,0:53:59.55,Default,,0,0,0,,苏格拉底是凡人 Dialogue: 0,0:54:01.36,0:54:04.91,Default,,0,0,0,,这些都是真正的经典逻辑 Dialogue: 0,0:54:05.88,0:54:11.05,Default,,0,0,0,,把它跟我们经典逻辑数据库比较一下 Dialogue: 0,0:54:12.40,0:54:14.46,Default,,0,0,0,,这是一个经典逻辑数据库 Dialogue: 0,0:54:16.27,0:54:17.48,Default,,0,0,0,,(GREEK SOCRATES) Dialogue: 0,0:54:18.03,0:54:18.84,Default,,0,0,0,,(GREEK PLATO) Dialogue: 0,0:54:19.60,0:54:20.40,Default,,0,0,0,,(GREEK ZEUS) Dialogue: 0,0:54:20.84,0:54:21.98,Default,,0,0,0,,(GOD ZEUS) Dialogue: 0,0:54:24.12,0:54:29.96,Default,,0,0,0,,所有的人类都是凡人 Dialogue: 0,0:54:30.54,0:54:32.12,Default,,0,0,0,,为了证明某人是平凡的 Dialogue: 0,0:54:32.16,0:54:33.60,Default,,0,0,0,,只需要证明他是人类 Dialogue: 0,0:54:34.65,0:54:35.90,Default,,0,0,0,,所有的人类都是不可靠的 Dialogue: 0,0:54:38.90,0:54:40.98,Default,,0,0,0,,并且说所有的希腊人都是人类 并不正确 Dialogue: 0,0:54:40.98,0:54:44.41,Default,,0,0,0,,这条规则说 所有不是神的希腊人都是人类 Dialogue: 0,0:54:45.71,0:54:47.04,Default,,0,0,0,,因此为了证明某人是人类 Dialogue: 0,0:54:47.07,0:54:48.89,Default,,0,0,0,,只需要说明他是一个希腊人 并且不是神 Dialogue: 0,0:54:49.32,0:54:52.88,Default,,0,0,0,,任何一个希腊神的住址是奥林匹斯山 Dialogue: 0,0:54:54.32,0:54:57.16,Default,,0,0,0,,这就是一个小型经典逻辑数据库 Dialogue: 0,0:54:57.39,0:54:59.32,Default,,0,0,0,,确实 它运行得相当好 Dialogue: 0,0:54:59.49,0:55:02.09,Default,,0,0,0,,如果我们向其询问 Dialogue: 0,0:55:03.47,0:55:06.57,Default,,0,0,0,,苏格拉底是凡人么 不可靠么? Dialogue: 0,0:55:06.91,0:55:07.69,Default,,0,0,0,,它会输出:是 Dialogue: 0,0:55:07.77,0:55:09.71,Default,,0,0,0,,柏拉图是凡人并且不可靠么? Dialogue: 0,0:55:09.71,0:55:10.24,Default,,0,0,0,,它会回答:是 Dialogue: 0,0:55:10.68,0:55:12.21,Default,,0,0,0,,如果我们问宙斯是凡人么 Dialogue: 0,0:55:12.21,0:55:13.23,Default,,0,0,0,,它什么都不会找到 Dialogue: 0,0:55:14.90,0:55:15.96,Default,,0,0,0,,运行得非常完美 Dialogue: 0,0:55:16.54,0:55:20.12,Default,,0,0,0,,然而 如果我们想要把它扩展一下 Dialogue: 0,0:55:20.12,0:55:23.05,Default,,0,0,0,,让我们来定义一下什么是“完美生命体” Dialogue: 0,0:55:23.82,0:55:27.21,Default,,0,0,0,,我们把规则PERFECT定义为 Dialogue: 0,0:55:34.05,0:55:35.48,Default,,0,0,0,,我想这样来定义是正确的 Dialogue: 0,0:55:35.48,0:55:38.14,Default,,0,0,0,,如果你熟悉中世纪经院哲学 Dialogue: 0,0:55:38.44,0:55:40.17,Default,,0,0,0,,我想所谓“完美生命体”一定 Dialogue: 0,0:55:40.68,0:55:42.65,Default,,0,0,0,,既不是凡人 又不会不可靠 Dialogue: 0,0:55:44.10,0:55:56.84,Default,,0,0,0,,(AND (NOT (MORTAL ?X)) (NOT (FALLIBLE ?X))) Dialogue: 0,0:55:59.30,0:56:00.89,Default,,0,0,0,,这样 我们就定义了一个规则 Dialogue: 0,0:56:02.67,0:56:04.36,Default,,0,0,0,,来告诉系统 什么是“完美生命体” Dialogue: 0,0:56:05.79,0:56:07.69,Default,,0,0,0,,现在 我们就要 Dialogue: 0,0:56:08.06,0:56:10.17,Default,,0,0,0,,询问所有“完美生命体”的地址 Dialogue: 0,0:56:11.48,0:56:22.30,Default,,0,0,0,,(AND (ADDRESS ?X ?Y) (PERFECT ?X)) Dialogue: 0,0:56:23.48,0:56:24.97,Default,,0,0,0,,在这里 我们生成了 Dialogue: 0,0:56:24.99,0:56:27.80,Default,,0,0,0,,世界上最独有的邮件列表 Dialogue: 0,0:56:30.16,0:56:32.20,Default,,0,0,0,,为了查询所有完美生命体的地址 Dialogue: 0,0:56:32.24,0:56:33.47,Default,,0,0,0,,我们会输入像这样的查询 Dialogue: 0,0:56:33.83,0:56:35.44,Default,,0,0,0,,或者像这样输入 Dialogue: 0,0:56:36.24,0:56:50.57,Default,,0,0,0,,(AND (PERFECT ?X) (ADDRESS ?X ?Y)) Dialogue: 0,0:56:52.06,0:56:54.96,Default,,0,0,0,,假设我们把它输入进去 并尝试查询 Dialogue: 0,0:56:55.19,0:56:56.76,Default,,0,0,0,,这条查询会给我们答案 Dialogue: 0,0:56:57.65,0:57:00.00,Default,,0,0,0,,这条查询会输出:奥林匹斯山 Dialogue: 0,0:57:04.23,0:57:06.57,Default,,0,0,0,,而这条查询 什么也不会输出 Dialogue: 0,0:57:06.74,0:57:09.58,Default,,0,0,0,,它找不到完美生命体的地址 Dialogue: 0,0:57:11.64,0:57:12.51,Default,,0,0,0,,为什么会这样? Dialogue: 0,0:57:12.51,0:57:13.44,Default,,0,0,0,,这又为什么不同? Dialogue: 0,0:57:14.23,0:57:15.69,Default,,0,0,0,,这个问题跟无穷循环没什么关系 Dialogue: 0,0:57:15.69,0:57:17.08,Default,,0,0,0,,这个的问题是答案不相同 Dialogue: 0,0:57:19.48,0:57:20.09,Default,,0,0,0,,原因就是 Dialogue: 0,0:57:20.38,0:57:22.32,Default,,0,0,0,,如果你们还记得NOT的实现的话 Dialogue: 0,0:57:23.50,0:57:24.84,Default,,0,0,0,,NOT是作为一个过滤器 Dialogue: 0,0:57:25.88,0:57:29.00,Default,,0,0,0,,NOT会接收一本字典 Dialogue: 0,0:57:29.05,0:57:31.56,Default,,0,0,0,,里面有可行解构成的框架 Dialogue: 0,0:57:31.79,0:57:33.16,Default,,0,0,0,,然后过滤出那些 Dialogue: 0,0:57:33.29,0:57:34.94,Default,,0,0,0,,满足某个条件的解 Dialogue: 0,0:57:34.97,0:57:36.11,Default,,0,0,0,,这就是我如何实现NOT的 Dialogue: 0,0:57:36.92,0:57:38.43,Default,,0,0,0,,如果你们仔细想想其中的原理 Dialogue: 0,0:57:40.11,0:57:42.65,Default,,0,0,0,,我创建了一个查询盒子 Dialogue: 0,0:57:43.32,0:57:47.39,Default,,0,0,0,,ADDRESS盒子的输出作为了PERFECT的输入 Dialogue: 0,0:57:50.29,0:57:51.00,Default,,0,0,0,,这就使得 Dialogue: 0,0:57:51.32,0:57:53.26,Default,,0,0,0,,ADDRESS盒子会创建出 Dialogue: 0,0:57:53.32,0:57:54.83,Default,,0,0,0,,我知道地址的人 Dialogue: 0,0:57:55.29,0:57:57.64,Default,,0,0,0,,这些都会被PERFECT中的NOT给过滤掉 Dialogue: 0,0:57:59.88,0:58:04.19,Default,,0,0,0,,所以它会丢弃掉那些满足平凡的或者不可靠的数据 Dialogue: 0,0:58:04.91,0:58:06.38,Default,,0,0,0,,而对于另外一种顺序来说 Dialogue: 0,0:58:06.73,0:58:09.12,Default,,0,0,0,,我以一个空框架开始的 Dialogue: 0,0:58:09.52,0:58:12.35,Default,,0,0,0,,但是这里PERFECT没有可以给NOT过滤的东西 Dialogue: 0,0:58:12.38,0:58:13.98,Default,,0,0,0,,所以这里不会有什么输出 Dialogue: 0,0:58:18.83,0:58:21.50,Default,,0,0,0,,这也就导致没有东西输入到ADDRESS中 Dialogue: 0,0:58:21.94,0:58:23.15,Default,,0,0,0,,因此 我得不到答案 Dialogue: 0,0:58:23.93,0:58:27.04,Default,,0,0,0,,在强调一下 这是因为NOT不会生成任何东西 Dialogue: 0,0:58:27.44,0:58:28.80,Default,,0,0,0,,NOT只会丢弃数据 Dialogue: 0,0:58:29.08,0:58:30.51,Default,,0,0,0,,如果我不向NOT传递东西的话 Dialogue: 0,0:58:30.52,0:58:31.74,Default,,0,0,0,,它也就不会输出 Dialogue: 0,0:58:32.02,0:58:33.77,Default,,0,0,0,,这样我就得到了错误的答案 Dialogue: 0,0:58:37.20,0:58:37.97,Default,,0,0,0,,我们又该如何修复它呢? Dialogue: 0,0:58:37.97,0:58:39.07,Default,,0,0,0,,当然 有很多办法 Dialogue: 0,0:58:39.36,0:58:40.91,Default,,0,0,0,,你可能认为 现在这样有点愚蠢 Dialogue: 0,0:58:41.41,0:58:44.90,Default,,0,0,0,,为什么要一开始就执行NOT呢? Dialogue: 0,0:58:44.96,0:58:47.48,Default,,0,0,0,,想要正确地实现NOT Dialogue: 0,0:58:47.84,0:58:50.08,Default,,0,0,0,,就是要认识到当你遇到NOT时 Dialogue: 0,0:58:50.33,0:58:52.09,Default,,0,0,0,,你应该首先生成好答案 Dialogue: 0,0:58:52.80,0:58:54.97,Default,,0,0,0,,然后通过字典把它们传递过来 Dialogue: 0,0:58:55.52,0:58:57.85,Default,,0,0,0,,然后再最后再做过滤 Dialogue: 0,0:58:58.56,0:59:02.01,Default,,0,0,0,,有些按照这种方式实现的逻辑式语言 Dialogue: 0,0:59:02.41,0:59:04.05,Default,,0,0,0,,能够解决这个问题 Dialogue: 0,0:59:06.80,0:59:08.97,Default,,0,0,0,,然而 还有一个更深刻的问题 Dialogue: 0,0:59:09.60,0:59:11.53,Default,,0,0,0,,也就是 哪个才是正确答案呢? Dialogue: 0,0:59:12.53,0:59:14.24,Default,,0,0,0,,是奥林匹斯山 还是没有呢? Dialogue: 0,0:59:15.37,0:59:18.73,Default,,0,0,0,,你可能会认为是奥林匹斯山 Dialogue: 0,0:59:18.76,0:59:20.73,Default,,0,0,0,,毕竟 宙斯在数据库中 Dialogue: 0,0:59:22.52,0:59:25.10,Default,,0,0,0,,宙斯不是平凡的 也不是不可靠的 Dialogue: 0,0:59:29.55,0:59:32.44,Default,,0,0,0,,因此你可能会认为宙斯满足 Dialogue: 0,0:59:34.30,0:59:44.03,Default,,0,0,0,,(NOT (MORTAL ZEUS))或者(NOT (FALLIBLE ZEUS)) Dialogue: 0,0:59:44.12,0:59:45.85,Default,,0,0,0,,但我们实际来看一看数据库 Dialogue: 0,0:59:47.92,0:59:48.46,Default,,0,0,0,,来看一下 Dialogue: 0,0:59:49.36,0:59:53.24,Default,,0,0,0,,它要如何知道宙斯不是不可靠的? Dialogue: 0,0:59:54.81,0:59:56.11,Default,,0,0,0,,这里面没有关于它的知识 Dialogue: 0,0:59:57.93,0:59:59.66,Default,,0,0,0,,里面只能得到人类是不可靠的 Dialogue: 0,1:00:02.16,1:00:04.12,Default,,0,0,0,,它又如何知道宙斯不是不可靠的呢? Dialogue: 0,1:00:04.48,1:00:05.93,Default,,0,0,0,,这其中没有相关的规则 Dialogue: 0,1:00:07.98,1:00:11.00,Default,,0,0,0,,它只是说 我没有这样的规则 Dialogue: 0,1:00:11.68,1:00:14.06,Default,,0,0,0,,我只能通过某人是人类来推断出他是平凡的 Dialogue: 0,1:00:14.08,1:00:15.68,Default,,0,0,0,,这也是它所知道关于“平凡”的所有东西 Dialogue: 0,1:00:16.69,1:00:19.85,Default,,0,0,0,,然而 如果你还记得古典神话的话 Dialogue: 0,1:00:19.87,1:00:23.48,Default,,0,0,0,,你就知道 古希腊众神是不平凡的 但都不可靠 Dialogue: 0,1:00:25.05,1:00:28.65,Default,,0,0,0,,所以 不能通过这些规则得到答案 Dialogue: 0,1:00:30.85,1:00:32.10,Default,,0,0,0,,但它又为什么推导出这些呢? Dialogue: 0,1:00:34.49,1:00:38.32,Default,,0,0,0,,显然 苏格拉底不会犯这类逻辑错误 Dialogue: 0,1:00:40.08,1:00:42.67,Default,,0,0,0,,在这门语言中 NOT并不是NOT Dialogue: 0,1:00:43.37,1:00:44.32,Default,,0,0,0,,不是逻辑非运算 Dialogue: 0,1:00:44.93,1:00:46.40,Default,,0,0,0,,这门语言中 NOT表示的是 Dialogue: 0,1:00:47.16,1:00:49.96,Default,,0,0,0,,不可以从数据库中推断出结果 Dialogue: 0,1:00:50.75,1:00:53.34,Default,,0,0,0,,而不是“非真” Dialogue: 0,1:00:55.02,1:00:56.30,Default,,0,0,0,,完全是天壤之别 Dialogue: 0,1:00:57.30,1:00:58.64,Default,,0,0,0,,很细微 但也很巨大 Dialogue: 0,1:00:59.25,1:01:00.27,Default,,0,0,0,,因此 实际上 Dialogue: 0,1:01:00.76,1:01:03.92,Default,,0,0,0,,如果什么都不知道 最好就说NOT Dialogue: 0,1:01:04.68,1:01:06.14,Default,,0,0,0,,如果你问它 Dialogue: 0,1:01:06.16,1:01:07.83,Default,,0,0,0,,宙斯是否喜欢巧克力冰激凌 Dialogue: 0,1:01:07.85,1:01:09.12,Default,,0,0,0,,它会说 这个查询当然非真 Dialogue: 0,1:01:10.64,1:01:12.51,Default,,0,0,0,,这些事情它都不知道 Dialogue: 0,1:01:12.59,1:01:17.34,Default,,0,0,0,,NOT表示:不能从你告知它的事实中推断出来 Dialogue: 0,1:01:18.28,1:01:22.44,Default,,0,0,0,,换句话说 你要把“无法推断出” Dialogue: 0,1:01:22.65,1:01:24.00,Default,,0,0,0,,与“命题非真”区别开来 Dialogue: 0,1:01:24.41,1:01:26.30,Default,,0,0,0,,这被称作是“封闭世界假说” Dialogue: 0,1:01:37.37,1:01:38.17,Default,,0,0,0,,封闭世界假说 Dialogue: 0,1:01:38.20,1:01:42.38,Default,,0,0,0,,只要结论不能通过我所知道的知识推断出来 Dialogue: 0,1:01:43.50,1:01:44.36,Default,,0,0,0,,那么就不是真的 Dialogue: 0,1:01:46.24,1:01:48.01,Default,,0,0,0,,对吧 如果我对X一无所知 Dialogue: 0,1:01:48.22,1:01:49.21,Default,,0,0,0,,那么X就非真 Dialogue: 0,1:01:49.29,1:01:50.33,Default,,0,0,0,,这相当危险 Dialogue: 0,1:01:51.29,1:01:52.44,Default,,0,0,0,,首先 从逻辑学的角度来说 Dialogue: 0,1:01:52.46,1:01:53.76,Default,,0,0,0,,它一点也说不通 Dialogue: 0,1:01:54.48,1:01:56.33,Default,,0,0,0,,因为如果我对X一无所知的话 Dialogue: 0,1:01:58.38,1:01:59.69,Default,,0,0,0,,就说X非真 Dialogue: 0,1:02:00.24,1:02:03.32,Default,,0,0,0,,但为什么不说“X非真”非真 Dialogue: 0,1:02:03.85,1:02:05.66,Default,,0,0,0,,当然 我也许对后面那个命题也一无所知 Dialogue: 0,1:02:06.47,1:02:08.65,Default,,0,0,0,,因此(NOT (NOT X))就没有必要与X一致 Dialogue: 0,1:02:09.24,1:02:10.94,Default,,0,0,0,,等等等等 Dialogue: 0,1:02:11.71,1:02:13.93,Default,,0,0,0,,因此 这里面一定有某种“偏见” Dialogue: 0,1:02:15.97,1:02:17.29,Default,,0,0,0,,这相当有趣 Dialogue: 0,1:02:17.29,1:02:18.09,Default,,0,0,0,,第二点就是 Dialogue: 0,1:02:20.14,1:02:24.12,Default,,0,0,0,,如果你基于此 构建一个真正的推理程序 Dialogue: 0,1:02:24.70,1:02:26.11,Default,,0,0,0,,想一想是多么地危险 Dialogue: 0,1:02:27.07,1:02:32.00,Default,,0,0,0,,你说我知道我可以推断出 Dialogue: 0,1:02:32.22,1:02:36.22,Default,,0,0,0,,与这个问题有关的所有事情 Dialogue: 0,1:02:37.44,1:02:40.78,Default,,0,0,0,,因为在我推理机制的内部 Dialogue: 0,1:02:41.23,1:02:44.20,Default,,0,0,0,,会认为所有与问题有关的知识 Dialogue: 0,1:02:44.24,1:02:46.27,Default,,0,0,0,,我都已经知道了 Dialogue: 0,1:02:48.44,1:02:53.04,Default,,0,0,0,,有相当多的大型组织都像这样运作 对吧? Dialogue: 0,1:02:53.16,1:02:56.83,Default,,0,0,0,,大多数公司的市场部门都是这样工作的。 Dialogue: 0,1:02:56.83,1:02:59.12,Default,,0,0,0,,你们也知道这样做的后果 Dialogue: 0,1:03:00.33,1:03:03.45,Default,,0,0,0,,因此 向这个大型逻辑推理系统 Dialogue: 0,1:03:03.84,1:03:06.25,Default,,0,0,0,,输入各种查询 根据输出继续工作 Dialogue: 0,1:03:07.05,1:03:09.00,Default,,0,0,0,,的做法相当危险 Dialogue: 0,1:03:09.02,1:03:11.28,Default,,0,0,0,,因为它们内建的假说非常地有限 Dialogue: 0,1:03:12.60,1:03:14.36,Default,,0,0,0,,因此你对此需要非常非常地小心 Dialogue: 0,1:03:15.29,1:03:16.28,Default,,0,0,0,,就是这么一个深层次问题 Dialogue: 0,1:03:16.56,1:03:17.82,Default,,0,0,0,,这个问题并不是 Dialogue: 0,1:03:18.22,1:03:20.14,Default,,0,0,0,,通过构建更加聪明的实现 Dialogue: 0,1:03:20.16,1:03:21.85,Default,,0,0,0,,或者通过组织无穷循环 Dialogue: 0,1:03:22.16,1:03:23.84,Default,,0,0,0,,以及过滤器就可以消除的 Dialogue: 0,1:03:23.84,1:03:25.08,Default,,0,0,0,,这是完全不同的一类问题 Dialogue: 0,1:03:25.92,1:03:26.89,Default,,0,0,0,,完全不同的语义 Dialogue: 0,1:03:27.06,1:03:30.51,Default,,0,0,0,,我想该总结一下了 平心而论 Dialogue: 0,1:03:31.34,1:03:34.43,Default,,0,0,0,,逻辑式程序设计是一个振奋人心的想法 Dialogue: 0,1:03:34.60,1:03:37.00,Default,,0,0,0,,这个想法使你能够弥合 Dialogue: 0,1:03:37.04,1:03:38.78,Default,,0,0,0,,命令式与声明式语言的鸿沟 Dialogue: 0,1:03:39.90,1:03:42.94,Default,,0,0,0,,使得你可以谈论关系 Dialogue: 0,1:03:43.58,1:03:45.08,Default,,0,0,0,,从而获得惊人的力量 Dialogue: 0,1:03:46.09,1:03:49.48,Default,,0,0,0,,让你超越输入和输出的抽象 Dialogue: 0,1:03:50.56,1:03:51.53,Default,,0,0,0,,而关于逻辑 Dialogue: 0,1:03:52.46,1:03:56.46,Default,,0,0,0,,我认为这个问题还尚未解决 Dialogue: 0,1:03:58.03,1:04:01.80,Default,,0,0,0,,也许现在语言中最令人感兴趣的 Dialogue: 0,1:04:02.27,1:04:04.41,Default,,0,0,0,,研究问题之一就是 Dialogue: 0,1:04:04.67,1:04:08.28,Default,,0,0,0,,你该如何创建一门真正的逻辑语言? Dialogue: 0,1:04:09.46,1:04:11.05,Default,,0,0,0,,其次 你如何从 Dialogue: 0,1:04:11.31,1:04:13.15,Default,,0,0,0,,这个逻辑和关系的世界 Dialogue: 0,1:04:13.52,1:04:16.43,Default,,0,0,0,,到更传统语言的世界之间 Dialogue: 0,1:04:16.46,1:04:17.98,Default,,0,0,0,,架起桥梁并结合两者的力量 Dialogue: 0,1:04:18.88,1:04:19.68,Default,,0,0,0,,有什么问题吗? Dialogue: 0,1:04:23.29,1:04:25.29,Default,,0,0,0,,学生:你能够通过添加额外的规则 Dialogue: 0,1:04:25.29,1:04:27.74,Default,,0,0,0,,来解决最后一个问题么? Dialogue: 0,1:04:27.96,1:04:29.85,Default,,0,0,0,,这里的困境是:你有某物的定义 Dialogue: 0,1:04:29.88,1:04:31.82,Default,,0,0,0,,但没有它对立面的定义 Dialogue: 0,1:04:32.08,1:04:33.92,Default,,0,0,0,,如果你在数据库中有 Dialogue: 0,1:04:34.14,1:04:36.89,Default,,0,0,0,,某些规则推导出(MORTAL X) Dialogue: 0,1:04:36.99,1:04:38.70,Default,,0,0,0,,另外一些规则推导出(NOT (MORTAL X)) Dialogue: 0,1:04:38.75,1:04:40.37,Default,,0,0,0,,这不就基本上解决这个问题么? Dialogue: 0,1:04:43.37,1:04:44.14,Default,,0,0,0,,教授:但问题就是 Dialogue: 0,1:04:44.75,1:04:46.38,Default,,0,0,0,,添加的这些规则是有穷个么? Dialogue: 0,1:04:48.65,1:04:53.13,Default,,0,0,0,,学生:如果你同时定义正、反两面 -- Dialogue: 0,1:04:53.61,1:04:57.07,Default,,0,0,0,,教授:但问题就是 你该如何去做推断? Dialogue: 0,1:05:00.20,1:05:02.11,Default,,0,0,0,,要知道 你不能直接定义命题的非 Dialogue: 0,1:05:03.40,1:05:04.76,Default,,0,0,0,,而问题就在于 在大型系统中 Dialogue: 0,1:05:04.78,1:05:07.96,Default,,0,0,0,,可能含有无穷个数的东西 Dialogue: 0,1:05:12.82,1:05:15.29,Default,,0,0,0,,这其中有两个问题 Dialogue: 0,1:05:15.29,1:05:16.56,Default,,0,0,0,,其一是可能有无穷项 Dialogue: 0,1:05:16.69,1:05:19.39,Default,,0,0,0,,另外是因为可能不向你想的那样 Dialogue: 0,1:05:21.51,1:05:24.52,Default,,0,0,0,,一个极好的例子 就是连通性 Dialogue: 0,1:05:25.12,1:05:26.54,Default,,0,0,0,,我想对连通性做推理 Dialogue: 0,1:05:28.05,1:05:30.38,Default,,0,0,0,,我会告诉你这有四个对象 Dialogue: 0,1:05:30.40,1:05:33.74,Default,,0,0,0,,A、B、C和D Dialogue: 0,1:05:35.48,1:05:38.19,Default,,0,0,0,,我会告诉你A和B相连 Dialogue: 0,1:05:38.64,1:05:41.42,Default,,0,0,0,,C和D相连 Dialogue: 0,1:05:43.20,1:05:44.80,Default,,0,0,0,,然后我再告诉你A和D相连 Dialogue: 0,1:05:45.05,1:05:46.03,Default,,0,0,0,,就是这种情况 Dialogue: 0,1:05:46.78,1:05:48.52,Default,,0,0,0,,在这个例子中 Dialogue: 0,1:05:48.70,1:05:50.35,Default,,0,0,0,,我就希望有“封闭世界假说”这样的东西 Dialogue: 0,1:05:54.43,1:05:55.66,Default,,0,0,0,,这是个小玩具 Dialogue: 0,1:05:56.24,1:05:58.30,Default,,0,0,0,,但是很多时候 我都想说 Dialogue: 0,1:05:58.48,1:06:01.34,Default,,0,0,0,,我没告诉你的事 都假设非真 Dialogue: 0,1:06:04.26,1:06:06.27,Default,,0,0,0,,所以这并不是你显式地 Dialogue: 0,1:06:06.27,1:06:08.09,Default,,0,0,0,,为所有命题定义否命题就可以解决的 Dialogue: 0,1:06:09.47,1:06:12.70,Default,,0,0,0,,而是有些时候 你不清楚自己真正想要什么 Dialogue: 0,1:06:14.15,1:06:17.92,Default,,0,0,0,,同时定义原命题与否命题又太过于精细 Dialogue: 0,1:06:17.93,1:06:20.00,Default,,0,0,0,,这会使你陷入困境 Dialogue: 0,1:06:20.96,1:06:22.68,Default,,0,0,0,,但还是有很多方法 Dialogue: 0,1:06:23.32,1:06:25.93,Default,,0,0,0,,显式地定义否命题 并基于此进行推理 Dialogue: 0,1:06:26.51,1:06:27.66,Default,,0,0,0,,这个想法非常好 Dialogue: 0,1:06:28.07,1:06:31.45,Default,,0,0,0,,只是在一些复杂的大型问题中 Dialogue: 0,1:06:31.48,1:06:33.49,Default,,0,0,0,,这么做就变得有些笨重了 Dialogue: 0,1:06:43.46,1:06:45.96,Default,,0,0,0,,学生:有个论点 我不知道它和本节课的直接关系 Dialogue: 0,1:06:46.00,1:06:47.98,Default,,0,0,0,,但你想要表达的是 Dialogue: 0,1:06:48.49,1:06:50.16,Default,,0,0,0,,封闭世界假说的危害之一就是 Dialogue: 0,1:06:50.19,1:06:52.06,Default,,0,0,0,,你永远不会真正了解那里的所有事物 Dialogue: 0,1:06:53.44,1:06:55.32,Default,,0,0,0,,你永远不会知道它们的每个部分 Dialogue: 0,1:06:55.87,1:06:58.16,Default,,0,0,0,,这难道不是任何一门程序设计语言的主要问题吗? Dialogue: 0,1:06:58.16,1:06:59.64,Default,,0,0,0,,写程序时 我总是 Dialogue: 0,1:06:59.90,1:07:01.56,Default,,0,0,0,,假设我考虑了所有的情况 Dialogue: 0,1:07:01.58,1:07:03.40,Default,,0,0,0,,然后我检查了每一种情况 Dialogue: 0,1:07:04.06,1:07:04.99,Default,,0,0,0,,然而在某处 Dialogue: 0,1:07:05.02,1:07:06.52,Default,,0,0,0,,我发现了我遗漏了其中的一个 Dialogue: 0,1:07:07.39,1:07:08.54,Default,,0,0,0,,教授:你说得很对 Dialogue: 0,1:07:08.54,1:07:09.76,Default,,0,0,0,,但这里的问题在于 Dialogue: 0,1:07:11.96,1:07:15.47,Default,,0,0,0,,对于你所做的事情 Dialogue: 0,1:07:15.48,1:07:17.34,Default,,0,0,0,,你是否认为它是逻辑问题 Dialogue: 0,1:07:19.60,1:07:20.51,Default,,0,0,0,,你说得非常正确 Dialogue: 0,1:07:20.51,1:07:22.22,Default,,0,0,0,,这是你永远不会遇到的情况 Dialogue: 0,1:07:22.22,1:07:24.14,Default,,0,0,0,,问题在于 如果你认为 Dialogue: 0,1:07:24.17,1:07:25.44,Default,,0,0,0,,你在进行逻辑式程序设计 Dialogue: 0,1:07:26.17,1:07:27.32,Default,,0,0,0,,然后审视你所编写的规则 Dialogue: 0,1:07:27.34,1:07:28.89,Default,,0,0,0,,并思考能从中推断出什么 Dialogue: 0,1:07:29.53,1:07:32.80,Default,,0,0,0,,你就需要清醒地认识到NOT具有另外的意义 Dialogue: 0,1:07:33.47,1:07:35.21,Default,,0,0,0,,它的意义基于某种假设 Dialogue: 0,1:07:35.24,1:07:36.70,Default,,0,0,0,,并且可能并不正确 Dialogue: 0,1:07:39.03,1:07:40.19,Default,,0,0,0,,学生:我不知道这样理解是否正确 Dialogue: 0,1:07:40.25,1:07:41.84,Default,,0,0,0,,也就是我们无法通过改变NOT Dialogue: 0,1:07:42.25,1:07:46.08,Default,,0,0,0,,来消灭推断的所有可能性 从而解决这个问题? Dialogue: 0,1:07:46.54,1:07:49.80,Default,,0,0,0,,教授:不 并不是这样 Dialogue: 0,1:07:52.96,1:07:55.08,Default,,0,0,0,,有很多种方法可以实现真正的逻辑非 Dialogue: 0,1:07:56.34,1:07:58.03,Default,,0,0,0,,实际上有很多种方法 Dialogue: 0,1:07:58.54,1:08:00.84,Default,,0,0,0,,但目前没有一个广为人知的高效算法 Dialogue: 0,1:08:01.61,1:08:02.56,Default,,0,0,0,,而且他们还-- Dialogue: 0,1:08:04.09,1:08:06.89,Default,,0,0,0,,这里所谓的“推论” Dialogue: 0,1:08:07.39,1:08:08.83,Default,,0,0,0,,是建立在这个合一算法 Dialogue: 0,1:08:08.91,1:08:11.29,Default,,0,0,0,,以及模式匹配算法之中的 Dialogue: 0,1:08:11.98,1:08:16.19,Default,,0,0,0,,有多种方法可以实现真正的逻辑推理 Dialogue: 0,1:08:16.59,1:08:18.19,Default,,0,0,0,,但它们并不基于此 Dialogue: 0,1:08:18.51,1:08:20.73,Default,,0,0,0,,而逻辑式程序设计语言也不倾向于这么做 Dialogue: 0,1:08:20.75,1:08:23.85,Default,,0,0,0,,因为大家都知道 那样做非常低效 Dialogue: 0,1:08:29.39,1:08:30.03,Default,,0,0,0,,好吧 下课 Dialogue: 0,1:08:30.03,1:08:42.68,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:08:30.03,1:08:42.68,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec8b.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Active Line: 5 Video Position: 984 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:18.91,0:00:21.79,EN,,0,0,0,,PROFESSOR: All right, well, we've seen how the query language works. Dialogue: 0,0:00:22.64,0:00:25.07,EN,,0,0,0,,Now, let's talk about how it's implemented. Dialogue: 0,0:00:26.28,0:00:27.98,EN,,0,0,0,,You already pretty much can guess Dialogue: 0,0:00:28.59,0:00:29.47,EN,,0,0,0,,what's going on there. Dialogue: 0,0:00:29.47,0:00:31.64,EN,,0,0,0,,At the bottom of it, there's a pattern matcher. Dialogue: 0,0:00:32.81,0:00:34.25,EN,,0,0,0,,And we looked at a pattern matcher Dialogue: 0,0:00:34.67,0:00:36.94,EN,,0,0,0,,when we did the rule-based control language. Dialogue: 0,0:00:38.11,0:00:40.59,EN,,0,0,0,,Just to remind you, here are some sample patterns. Dialogue: 0,0:00:41.52,0:00:43.68,EN,,0,0,0,,This is a pattern that will match Dialogue: 0,0:00:43.80,0:00:44.92,EN,,0,0,0,,any list of three things Dialogue: 0,0:00:44.96,0:00:47.10,EN,,0,0,0,,which the first is a Dialogue: 0,0:00:47.16,0:00:48.33,EN,,0,0,0,,the second is c Dialogue: 0,0:00:48.48,0:00:50.19,EN,,0,0,0,,and the middle one can be anything. Dialogue: 0,0:00:50.65,0:00:52.27,EN,,0,0,0,,So in this little pattern-matching syntax, Dialogue: 0,0:00:52.30,0:00:54.05,EN,,0,0,0,,there's only one distinction you make. Dialogue: 0,0:00:54.05,0:00:57.20,EN,,0,0,0,,There's either literal things or variables, Dialogue: 0,0:00:57.23,0:00:58.86,EN,,0,0,0,,and variables begin with question mark. Dialogue: 0,0:01:01.37,0:01:03.64,EN,,0,0,0,,So this matches any list of three things Dialogue: 0,0:01:04.44,0:01:06.50,EN,,0,0,0,,of which the first is a and the second is c. Dialogue: 0,0:01:06.50,0:01:09.00,EN,,0,0,0,,This one matches any list of three things Dialogue: 0,0:01:10.43,0:01:12.53,EN,,0,0,0,,of which the first is the symbol job. Dialogue: 0,0:01:12.53,0:01:13.90,EN,,0,0,0,,The second can be anything. Dialogue: 0,0:01:14.21,0:01:15.90,EN,,0,0,0,,And the third is a list of two things Dialogue: 0,0:01:15.95,0:01:17.72,EN,,0,0,0,,of which the first is the symbol computer Dialogue: 0,0:01:17.88,0:01:19.42,EN,,0,0,0,,and the second can be anything. Dialogue: 0,0:01:20.48,0:01:25.55,EN,,0,0,0,,And this one, this next one matches any list of three things, Dialogue: 0,0:01:25.87,0:01:26.99,EN,,0,0,0,,and the only difference is, Dialogue: 0,0:01:28.40,0:01:31.32,EN,,0,0,0,,here, the third list, the first is the symbol computer, Dialogue: 0,0:01:31.76,0:01:33.29,EN,,0,0,0,,and then there's some rest of the list. Dialogue: 0,0:01:35.04,0:01:37.53,EN,,0,0,0,,So this means two elements and this means arbitrary number. Dialogue: 0,0:01:37.86,0:01:39.74,EN,,0,0,0,,And our language implementation isn't Dialogue: 0,0:01:39.85,0:01:42.06,EN,,0,0,0,,isn't even going to have to worry about implementing this dot Dialogue: 0,0:01:42.11,0:01:44.17,EN,,0,0,0,,because that's automatically done by Lisp's reader. Dialogue: 0,0:01:48.34,0:01:50.31,EN,,0,0,0,,Remember matchers also have some consistency in them. Dialogue: 0,0:01:50.31,0:01:52.32,EN,,0,0,0,,This match is a list of three things Dialogue: 0,0:01:52.59,0:01:53.98,EN,,0,0,0,,of which the first is a. Dialogue: 0,0:01:54.43,0:01:55.79,EN,,0,0,0,,And the second and third can be anything, Dialogue: 0,0:01:55.80,0:01:57.08,EN,,0,0,0,,but they have to be the same thing. Dialogue: 0,0:01:57.94,0:01:58.84,EN,,0,0,0,,They're both called x. Dialogue: 0,0:01:59.60,0:02:01.55,EN,,0,0,0,,And this matches a list of four things Dialogue: 0,0:02:01.96,0:02:03.26,EN,,0,0,0,,of which the first is the fourth Dialogue: 0,0:02:03.66,0:02:05.15,EN,,0,0,0,,and the second is the same as the third. Dialogue: 0,0:02:05.59,0:02:08.60,EN,,0,0,0,,And this last one matches any list that begins with a. Dialogue: 0,0:02:09.68,0:02:11.05,EN,,0,0,0,,The first thing is a, Dialogue: 0,0:02:11.23,0:02:12.56,EN,,0,0,0,,and the rest can be anything. Dialogue: 0,0:02:14.04,0:02:16.60,EN,,0,0,0,,So that's just a review of pattern matcher syntax Dialogue: 0,0:02:16.62,0:02:17.87,EN,,0,0,0,,that you've already seen. Dialogue: 0,0:02:18.78,0:02:19.64,EN,,0,0,0,,And remember, Dialogue: 0,0:02:19.79,0:02:22.28,EN,,0,0,0,,that's implemented by some procedure called match. Dialogue: 0,0:02:24.87,0:02:36.06,EN,,0,0,0,,And match takes a pattern and some data and a dictionary. Dialogue: 0,0:02:43.20,0:02:47.12,EN,,0,0,0,,And match asks the question Dialogue: 0,0:02:47.79,0:02:52.64,EN,,0,0,0,,is there any way to match this pattern against this data object Dialogue: 0,0:02:53.55,0:02:56.73,EN,,0,0,0,,subject to the bindings that are already in this dictionary? Dialogue: 0,0:02:58.16,0:02:59.21,EN,,0,0,0,,So, for instance, Dialogue: 0,0:02:59.56,0:03:06.43,EN,,0,0,0,,if we're going to match the pattern x, y, y, x Dialogue: 0,0:03:07.71,0:03:13.84,EN,,0,0,0,,against the data a, b, b, a Dialogue: 0,0:03:15.12,0:03:20.52,EN,,0,0,0,,subject to a dictionary, that says x equals a. Dialogue: 0,0:03:22.01,0:03:25.23,EN,,0,0,0,,Then the matcher would say, yes, that's consistent. Dialogue: 0,0:03:25.26,0:03:27.16,EN,,0,0,0,,These match, and it's consistent Dialogue: 0,0:03:27.80,0:03:30.20,EN,,0,0,0,,with what's in the dictionary to say that x equals a. Dialogue: 0,0:03:30.32,0:03:31.60,EN,,0,0,0,,And the result of the match Dialogue: 0,0:03:32.25,0:03:34.30,EN,,0,0,0,,is the extended dictionary Dialogue: 0,0:03:34.46,0:03:37.60,EN,,0,0,0,,that says x equals a and y equals b. Dialogue: 0,0:03:39.49,0:03:42.24,EN,,0,0,0,,So a matcher takes in pattern data dictionary, Dialogue: 0,0:03:42.38,0:03:44.54,EN,,0,0,0,,puts out an extended dictionary if it matches, Dialogue: 0,0:03:44.97,0:03:46.84,EN,,0,0,0,,or if it doesn't match, says that it fails. Dialogue: 0,0:03:46.84,0:03:47.71,EN,,0,0,0,,So, for example, Dialogue: 0,0:03:47.88,0:03:50.38,EN,,0,0,0,,if I use the same pattern here, Dialogue: 0,0:03:50.97,0:03:55.12,EN,,0,0,0,,if I say this x, y, y, x Dialogue: 0,0:03:55.66,0:03:58.49,EN,,0,0,0,,match a, b, b, a Dialogue: 0,0:03:59.47,0:04:02.84,EN,,0,0,0,,with the dictionary y equals a, Dialogue: 0,0:04:05.15,0:04:06.81,EN,,0,0,0,,then the matcher would put out fail. Dialogue: 0,0:04:12.52,0:04:14.65,EN,,0,0,0,,Well, you've already seen the code for a pattern matcher Dialogue: 0,0:04:15.00,0:04:16.17,EN,,0,0,0,,so I'm not going to go over it, Dialogue: 0,0:04:16.64,0:04:19.77,EN,,0,0,0,,but it's the same thing we've been doing before. Dialogue: 0,0:04:21.19,0:04:23.22,EN,,0,0,0,,You saw that in the system on rule-based control. Dialogue: 0,0:04:23.22,0:04:24.56,EN,,0,0,0,,It's essentially the same matcher. Dialogue: 0,0:04:24.95,0:04:27.66,EN,,0,0,0,,In fact, I think the syntax is a little bit simpler Dialogue: 0,0:04:28.16,0:04:29.31,EN,,0,0,0,,because we're not worrying about Dialogue: 0,0:04:29.40,0:04:31.40,EN,,0,0,0,,arbitrary constants and expressions and things. Dialogue: 0,0:04:31.40,0:04:32.88,EN,,0,0,0,,There's just variables and constants. Dialogue: 0,0:04:35.79,0:04:37.32,EN,,0,0,0,,OK, well, given that, Dialogue: 0,0:04:38.46,0:04:39.61,EN,,0,0,0,,what's a primitive query? Dialogue: 0,0:04:42.97,0:04:45.34,EN,,0,0,0,,Primitive query is going to be a rather complicated thing. Dialogue: 0,0:04:46.67,0:05:03.58,EN,,0,0,0,,It's going to be-- let's think about the query job of x is d dot y. Dialogue: 0,0:05:07.04,0:05:08.73,EN,,0,0,0,,That's a query we might type in. Dialogue: 0,0:05:09.40,0:05:11.39,EN,,0,0,0,,That's going to be implemented in the system. Dialogue: 0,0:05:14.14,0:05:15.66,EN,,0,0,0,,We'll think of it as this little box. Dialogue: 0,0:05:15.70,0:05:16.80,EN,,0,0,0,,Here's the primitive query. Dialogue: 0,0:05:18.88,0:05:20.30,EN,,0,0,0,,What this little box is going to do Dialogue: 0,0:05:22.24,0:05:27.28,EN,,0,0,0,,is take in two streams and put out a stream. Dialogue: 0,0:05:31.96,0:05:33.20,EN,,0,0,0,,and put out a stream. Dialogue: 0,0:05:34.03,0:05:36.19,EN,,0,0,0,,So the shape of a primitive query Dialogue: 0,0:05:36.51,0:05:38.46,EN,,0,0,0,,is that it's a thing where two streams come in Dialogue: 0,0:05:38.67,0:05:39.96,EN,,0,0,0,,and one stream goes out. Dialogue: 0,0:05:41.12,0:05:46.20,EN,,0,0,0,,What these streams are going to be is down here is the database. Dialogue: 0,0:05:51.95,0:05:53.93,EN,,0,0,0,,So we imagine all the things in the database Dialogue: 0,0:05:55.93,0:05:57.20,EN,,0,0,0,,sort of sitting there in a stream Dialogue: 0,0:05:57.31,0:05:58.40,EN,,0,0,0,,and this thing sucks on them. Dialogue: 0,0:06:00.36,0:06:02.43,EN,,0,0,0,,So what are some things that might be in the database? Dialogue: 0,0:06:08.43,0:06:20.32,EN,,0,0,0,,Oh, job of Alyssa is something Dialogue: 0,0:06:21.96,0:06:23.71,EN,,0,0,0,,and some other job is something. Dialogue: 0,0:06:25.77,0:06:30.41,EN,,0,0,0,,So imagine all of the facts in the database sitting there in the stream. Dialogue: 0,0:06:32.04,0:06:33.10,EN,,0,0,0,,That's what comes in here. Dialogue: 0,0:06:33.36,0:06:34.52,EN,,0,0,0,,What comes in here Dialogue: 0,0:06:34.89,0:06:36.52,EN,,0,0,0,,is a stream of dictionaries. Dialogue: 0,0:06:38.51,0:06:41.40,EN,,0,0,0,,So one particular dictionary might say Dialogue: 0,0:06:46.70,0:06:49.31,EN,,0,0,0,,might say y equals programmer. Dialogue: 0,0:06:55.47,0:06:56.64,EN,,0,0,0,,Now, what the query does Dialogue: 0,0:06:57.07,0:06:59.80,EN,,0,0,0,,when it gets in a dictionary from this stream, Dialogue: 0,0:07:02.01,0:07:06.67,EN,,0,0,0,,it finds all possible ways of matching the query Dialogue: 0,0:07:07.45,0:07:10.24,EN,,0,0,0,,against whatever is coming in from the database. Dialogue: 0,0:07:11.39,0:07:12.89,EN,,0,0,0,,It looks at the query as a pattern, Dialogue: 0,0:07:13.15,0:07:16.72,EN,,0,0,0,,matches it against any fact from the database Dialogue: 0,0:07:16.96,0:07:21.98,EN,,0,0,0,,or all possible ways of finding and matching the database Dialogue: 0,0:07:22.94,0:07:25.68,EN,,0,0,0,,with respect to this dictionary that's coming in. Dialogue: 0,0:07:27.55,0:07:29.69,EN,,0,0,0,,So for each fact in the database, Dialogue: 0,0:07:29.72,0:07:34.35,EN,,0,0,0,,it calls the matcher using the pattern, fact, and dictionary. Dialogue: 0,0:07:35.11,0:07:37.68,EN,,0,0,0,,And every time it gets a good match, Dialogue: 0,0:07:38.19,0:07:39.93,EN,,0,0,0,,it puts out the extended dictionary. Dialogue: 0,0:07:40.67,0:07:42.32,EN,,0,0,0,,So, for example, if this one comes in Dialogue: 0,0:07:43.00,0:07:44.09,EN,,0,0,0,,and it finds a match, Dialogue: 0,0:07:44.51,0:07:45.87,EN,,0,0,0,,out will come a dictionary Dialogue: 0,0:07:46.81,0:07:49.79,EN,,0,0,0,,that in this case will have y equals programmer Dialogue: 0,0:07:51.52,0:07:52.97,EN,,0,0,0,,nd x equals something. Dialogue: 0,0:07:56.54,0:07:58.75,EN,,0,0,0,,y is programmer, x is something, Dialogue: 0,0:07:58.96,0:08:00.54,EN,,0,0,0,,and d is whatever it found. Dialogue: 0,0:08:01.72,0:08:02.27,EN,,0,0,0,,And that's all. Dialogue: 0,0:08:03.52,0:08:07.82,EN,,0,0,0,,And, of course, it's going to try this for every fact in the dictionary. Dialogue: 0,0:08:07.98,0:08:09.25,EN,,0,0,0,,So it might find lots of them. Dialogue: 0,0:08:09.56,0:08:10.59,EN,,0,0,0,,It might find another one Dialogue: 0,0:08:11.28,0:08:17.12,EN,,0,0,0,,that says y equals programmer and x equals, and d equals. Dialogue: 0,0:08:19.18,0:08:21.55,EN,,0,0,0,,So thats, So for one frame coming in, Dialogue: 0,0:08:21.76,0:08:23.69,EN,,0,0,0,,it might put out-- for one dictionary coming in, Dialogue: 0,0:08:23.72,0:08:25.24,EN,,0,0,0,,it might put out a lot of dictionaries, Dialogue: 0,0:08:26.54,0:08:28.67,EN,,0,0,0,,or it might put out none. Dialogue: 0,0:08:30.47,0:08:38.48,EN,,0,0,0,,It might have something that wouldn't match like x equals FOO. Dialogue: 0,0:08:39.02,0:08:40.89,EN,,0,0,0,,This one might not match anything Dialogue: 0,0:08:41.52,0:08:45.12,EN,,0,0,0,,in which case nothing will go into this stream corresponding to this frame. Dialogue: 0,0:08:47.51,0:08:51.28,EN,,0,0,0,,Or what you might do is put in an empty frame, Dialogue: 0,0:08:52.91,0:08:56.24,EN,,0,0,0,,and an empty frame says try matching all ways-- Dialogue: 0,0:08:59.87,0:09:02.33,EN,,0,0,0,,find all possible ways of matching the query Dialogue: 0,0:09:02.57,0:09:06.14,EN,,0,0,0,,against something in the database subject to no previous restrictions. Dialogue: 0,0:09:07.57,0:09:09.16,EN,,0,0,0,,And if you think about what that means, that's just Dialogue: 0,0:09:10.32,0:09:13.87,EN,,0,0,0,,the computation that's done when you type in a query right off. Dialogue: 0,0:09:14.20,0:09:15.56,EN,,0,0,0,,It tries to find all matches. Dialogue: 0,0:09:16.65,0:09:18.83,EN,,0,0,0,,So a primitive query sets up this mechanism. Dialogue: 0,0:09:19.37,0:09:20.57,EN,,0,0,0,,And what the language does, Dialogue: 0,0:09:22.75,0:09:24.67,EN,,0,0,0,,when you type in the query at the top level, Dialogue: 0,0:09:24.84,0:09:26.14,EN,,0,0,0,,it takes this mechanism, Dialogue: 0,0:09:26.16,0:09:28.35,EN,,0,0,0,,feeds in one single empty dictionary, Dialogue: 0,0:09:30.86,0:09:32.56,EN,,0,0,0,,and then for each thing that comes out Dialogue: 0,0:09:33.08,0:09:35.88,EN,,0,0,0,,takes the original query Dialogue: 0,0:09:36.56,0:09:40.44,EN,,0,0,0,,and instantiates the result with all the different dictionaries, Dialogue: 0,0:09:40.81,0:09:44.36,EN,,0,0,0,,producing a new stream of instantiated patterns here. Dialogue: 0,0:09:44.99,0:09:46.51,EN,,0,0,0,,And that's what gets printed on the terminal. Dialogue: 0,0:09:48.17,0:09:51.24,EN,,0,0,0,,That's the basic mechanism going on there. Dialogue: 0,0:09:53.51,0:09:55.48,EN,,0,0,0,,Well, why is that so complicated? Dialogue: 0,0:09:57.71,0:10:01.00,EN,,0,0,0,,You probably can think of a lot simpler ways to arrange this match for Dialogue: 0,0:10:01.37,0:10:04.25,EN,,0,0,0,,a primitive query rather than having all of these streams floating around. Dialogue: 0,0:10:05.18,0:10:06.09,EN,,0,0,0,,And the answer is-- Dialogue: 0,0:10:07.15,0:10:08.51,EN,,0,0,0,,you probably guess already. Dialogue: 0,0:10:10.86,0:10:14.09,EN,,0,0,0,,The answer is this thing extends elegantly Dialogue: 0,0:10:14.56,0:10:16.76,EN,,0,0,0,,to implement the means of combination. Dialogue: 0,0:10:17.79,0:10:18.80,EN,,0,0,0,,So, for instance, Dialogue: 0,0:10:20.65,0:10:22.47,EN,,0,0,0,,suppose I don't only want to do this. Dialogue: 0,0:10:22.47,0:10:26.96,EN,,0,0,0,,I don't want to say who to be everybody's job description. Dialogue: 0,0:10:27.23,0:10:28.35,EN,,0,0,0,,Suppose I want to say Dialogue: 0,0:10:29.47,0:10:35.92,EN,,0,0,0,,to say AND the job of x is d dot y Dialogue: 0,0:10:36.80,0:10:47.04,EN,,0,0,0,,and the supervisor of x is z. Dialogue: 0,0:10:48.80,0:10:50.67,EN,,0,0,0,,Now, supervisor of x is z Dialogue: 0,0:10:51.39,0:10:52.96,EN,,0,0,0,,is going to be another primitive query Dialogue: 0,0:10:53.71,0:10:58.43,EN,,0,0,0,,that has the same shape to take in a stream of data objects, Dialogue: 0,0:10:59.18,0:11:01.64,EN,,0,0,0,,a stream of initial dictionaries, Dialogue: 0,0:11:01.68,0:11:05.52,EN,,0,0,0,,which are the restrictions to try and use when you match, Dialogue: 0,0:11:05.53,0:11:07.44,EN,,0,0,0,,and it's going to put out a stream of dictionaries. Dialogue: 0,0:11:08.70,0:11:10.80,EN,,0,0,0,,So that's what this primitive query looks like. Dialogue: 0,0:11:11.50,0:11:12.91,EN,,0,0,0,,And how do I implement the AND? Dialogue: 0,0:11:12.91,0:11:13.45,EN,,0,0,0,,Well, it's simple. Dialogue: 0,0:11:13.45,0:11:14.44,EN,,0,0,0,,I just hook them together. Dialogue: 0,0:11:14.88,0:11:16.28,EN,,0,0,0,,I take the output of this one, Dialogue: 0,0:11:16.96,0:11:18.81,EN,,0,0,0,,and I put that to the input of that one. Dialogue: 0,0:11:19.83,0:11:21.84,EN,,0,0,0,,And I take the dictionary here and I fan it out. Dialogue: 0,0:11:26.57,0:11:27.96,EN,,0,0,0,,And then you see how that's going to work, Dialogue: 0,0:11:29.05,0:11:32.44,EN,,0,0,0,,because what's going to happen is a frame will now come in here, Dialogue: 0,0:11:32.51,0:11:36.84,EN,,0,0,0,,which has a binding for x, y, and d. Dialogue: 0,0:11:37.92,0:11:39.28,EN,,0,0,0,,And then when this one gets it, it'll say, Dialogue: 0,0:11:39.29,0:11:41.60,EN,,0,0,0,,oh, gee, subject to these restrictions, Dialogue: 0,0:11:42.17,0:11:49.24,EN,,0,0,0,,which now already have values in the dictionary for y and x and d, Dialogue: 0,0:11:51.80,0:11:53.08,EN,,0,0,0,,it looks in the database and says, Dialogue: 0,0:11:53.12,0:11:54.92,EN,,0,0,0,,gee, can I find any supervisor facts? Dialogue: 0,0:11:56.04,0:11:58.51,EN,,0,0,0,,And if it finds any, out will come dictionaries Dialogue: 0,0:11:59.58,0:12:09.34,EN,,0,0,0,,which have bindings for y and x and d and z now. Dialogue: 0,0:12:12.07,0:12:14.09,EN,,0,0,0,,And then notice that the match--- Dialogue: 0,0:12:14.19,0:12:17.24,EN,,0,0,0,,because the frames coming in here have these restrictions, Dialogue: 0,0:12:17.61,0:12:20.28,EN,,0,0,0,,that's the thing that assures when you do the AND, Dialogue: 0,0:12:20.49,0:12:24.62,EN,,0,0,0,,this x will mean the same thing as that x. Dialogue: 0,0:12:26.47,0:12:28.96,EN,,0,0,0,,Because by the time something comes floating in here, Dialogue: 0,0:12:29.96,0:12:32.65,EN,,0,0,0,,x has a value that you have to match against consistently. Dialogue: 0,0:12:34.46,0:12:36.17,EN,,0,0,0,,And then you remember from the code from the matcher, Dialogue: 0,0:12:36.19,0:12:38.17,EN,,0,0,0,,there was something in the way the matcher did dictionaries Dialogue: 0,0:12:38.20,0:12:39.82,EN,,0,0,0,,that arrange consistent matches. Dialogue: 0,0:12:40.92,0:12:41.77,EN,,0,0,0,,So there's AND. Dialogue: 0,0:12:44.08,0:12:46.94,EN,,0,0,0,,The important point to notice is the general shape. Dialogue: 0,0:12:48.49,0:12:51.55,EN,,0,0,0,,Look at what happened: the AND of two queries, say, P and Q. Dialogue: 0,0:12:52.88,0:12:55.61,EN,,0,0,0,,Here's P and Q. Dialogue: 0,0:12:57.29,0:12:58.60,EN,,0,0,0,,The AND of two queries, Dialogue: 0,0:13:00.27,0:13:01.19,EN,,0,0,0,,well, it looks like this. Dialogue: 0,0:13:01.19,0:13:04.44,EN,,0,0,0,,Each query takes in a stream from the database, Dialogue: 0,0:13:04.54,0:13:05.71,EN,,0,0,0,,a stream of inputs, Dialogue: 0,0:13:06.33,0:13:08.17,EN,,0,0,0,,and puts out a stream of outputs. Dialogue: 0,0:13:10.23,0:13:11.72,EN,,0,0,0,,And the important point to notice Dialogue: 0,0:13:12.20,0:13:15.02,EN,,0,0,0,,is that if I draw a box around this thing Dialogue: 0,0:13:19.26,0:13:23.64,EN,,0,0,0,,and say this is AND of P and Q, Dialogue: 0,0:13:25.66,0:13:30.38,EN,,0,0,0,,then that box has exactly the same overall shape. Dialogue: 0,0:13:32.04,0:13:34.20,EN,,0,0,0,,It's something that takes in a stream from the database. Dialogue: 0,0:13:34.20,0:13:35.74,EN,,0,0,0,,Here it's going to get fanned out inside, Dialogue: 0,0:13:36.60,0:13:37.93,EN,,0,0,0,,but from the outside you don't see that. Dialogue: 0,0:13:38.16,0:13:40.64,EN,,0,0,0,,It takes an input stream and puts out an output stream. Dialogue: 0,0:13:42.06,0:13:43.16,EN,,0,0,0,,So this is AND. Dialogue: 0,0:13:43.57,0:13:45.72,EN,,0,0,0,,And then similarly, OR would look like this. Dialogue: 0,0:13:46.02,0:13:49.58,EN,,0,0,0,,OR would-- although I didn't show you examples of OR. Dialogue: 0,0:13:49.84,0:13:54.70,EN,,0,0,0,,OR would say can I find all ways of matching P or Q. Dialogue: 0,0:13:55.80,0:13:58.07,EN,,0,0,0,,So I have P and Q. Each will have their shape. Dialogue: 0,0:14:04.46,0:14:06.68,EN,,0,0,0,,And the way OR is implemented is Dialogue: 0,0:14:08.54,0:14:10.91,EN,,0,0,0,,I'll take my database stream. Dialogue: 0,0:14:12.50,0:14:13.49,EN,,0,0,0,,I'll fan it out. Dialogue: 0,0:14:13.49,0:14:16.04,EN,,0,0,0,,I'll put one into P and one into Q. Dialogue: 0,0:14:17.44,0:14:21.98,EN,,0,0,0,,I'll take my initial query stream coming in and fan it out. Dialogue: 0,0:14:26.75,0:14:29.16,EN,,0,0,0,,So I'll look at all the answers I might get from P Dialogue: 0,0:14:29.29,0:14:31.08,EN,,0,0,0,,and all the answers I might get from Q, Dialogue: 0,0:14:31.61,0:14:34.56,EN,,0,0,0,,and I'll put them through some sort of thing that appends them Dialogue: 0,0:14:34.62,0:14:37.48,EN,,0,0,0,,or merges the result into one stream, Dialogue: 0,0:14:39.64,0:14:40.88,EN,,0,0,0,,and that's what will come out. Dialogue: 0,0:14:41.08,0:14:48.24,EN,,0,0,0,,And this whole thing from the outside is OR. Dialogue: 0,0:14:52.35,0:14:54.89,EN,,0,0,0,,And again, you see it has the same overall shape Dialogue: 0,0:14:55.07,0:14:56.54,EN,,0,0,0,,And again, you see it has the same overall shape Dialogue: 0,0:15:01.00,0:15:01.61,EN,,0,0,0,,What's NOT? Dialogue: 0,0:15:02.02,0:15:03.45,EN,,0,0,0,,NOT works kind of the same way. Dialogue: 0,0:15:04.31,0:15:05.95,EN,,0,0,0,,If I have some query P, Dialogue: 0,0:15:06.86,0:15:13.50,EN,,0,0,0,,If I have P, I take the primitive query for P. Dialogue: 0,0:15:14.69,0:15:16.32,EN,,0,0,0,,Here, I'm going to implement NOT P. Dialogue: 0,0:15:18.68,0:15:20.54,EN,,0,0,0,,And NOT's just going to act as a filter. Dialogue: 0,0:15:20.72,0:15:21.95,EN,,0,0,0,,I'll take in the database Dialogue: 0,0:15:23.84,0:15:28.28,EN,,0,0,0,,and my original stream of dictionaries coming in, Dialogue: 0,0:15:28.78,0:15:31.53,EN,,0,0,0,,and what NOT P will do is Dialogue: 0,0:15:31.88,0:15:37.40,EN,,0,0,0,,it will filter these guys. Dialogue: 0,0:15:39.02,0:15:40.09,EN,,0,0,0,,And the way it will filter it, Dialogue: 0,0:15:40.19,0:15:42.70,EN,,0,0,0,,it will say when I get in a dictionary here, Dialogue: 0,0:15:43.42,0:15:44.65,EN,,0,0,0,,I'll find all the matches, Dialogue: 0,0:15:44.83,0:15:46.48,EN,,0,0,0,,and if I find any, I'll throw it away. Dialogue: 0,0:15:47.46,0:15:49.93,EN,,0,0,0,,And if I don't find any matches to something coming in here, Dialogue: 0,0:15:50.12,0:15:51.37,EN,,0,0,0,,I'll just pass that through, Dialogue: 0,0:15:52.40,0:15:53.55,EN,,0,0,0,,so NOT is a pure filter. Dialogue: 0,0:15:55.34,0:15:59.98,EN,,0,0,0,,So AND is-- think of these sort of electoral resistors or something. Dialogue: 0,0:15:59.98,0:16:01.85,EN,,0,0,0,,AND is series combination Dialogue: 0,0:16:02.49,0:16:04.14,EN,,0,0,0,,and OR is parallel combination. Dialogue: 0,0:16:04.96,0:16:07.46,EN,,0,0,0,,And then NOT is not going to extend any dictionaries at all. Dialogue: 0,0:16:07.46,0:16:08.40,EN,,0,0,0,,It's just going to filter it. Dialogue: 0,0:16:08.75,0:16:11.79,EN,,0,0,0,,It's going to throw away the ones for which it finds a way to match. Dialogue: 0,0:16:12.64,0:16:14.19,EN,,0,0,0,,And lisp-value is sort of the same way. Dialogue: 0,0:16:14.84,0:16:16.60,EN,,0,0,0,,The filter's a little more complicated. Dialogue: 0,0:16:16.60,0:16:17.37,EN,,0,0,0,,It applies to predicate. Dialogue: 0,0:16:19.93,0:16:21.64,EN,,0,0,0,,The major point to notice here, Dialogue: 0,0:16:21.92,0:16:23.55,EN,,0,0,0,,and it's a major point we've looked at before, Dialogue: 0,0:16:23.64,0:16:25.29,EN,,0,0,0,,is this idea of closure. Dialogue: 0,0:16:28.22,0:16:31.80,EN,,0,0,0,,The things that we build as a means of combination Dialogue: 0,0:16:31.95,0:16:34.51,EN,,0,0,0,,have the same overall structure Dialogue: 0,0:16:35.69,0:16:37.58,EN,,0,0,0,,as the primitive things that we're combining. Dialogue: 0,0:16:39.75,0:16:41.68,EN,,0,0,0,,So the AND of two things Dialogue: 0,0:16:41.71,0:16:43.72,EN,,0,0,0,,looked at from the outside has the same shape. Dialogue: 0,0:16:44.63,0:16:46.14,EN,,0,0,0,,And what that means is that Dialogue: 0,0:16:46.94,0:16:50.28,EN,,0,0,0,,this box here could be an AND or an OR or a NOT or something Dialogue: 0,0:16:50.30,0:16:54.22,EN,,0,0,0,,because it has the same shape to interface to the larger things. Dialogue: 0,0:16:54.95,0:16:56.68,EN,,0,0,0,,It's the same thing that allowed us to get Dialogue: 0,0:16:56.92,0:16:58.96,EN,,0,0,0,,complexity in the Escher picture language Dialogue: 0,0:16:59.55,0:17:01.31,EN,,0,0,0,,or allows you to immediately build up these Dialogue: 0,0:17:01.34,0:17:03.26,EN,,0,0,0,,complicated structures just out of pairs. Dialogue: 0,0:17:03.93,0:17:04.78,EN,,0,0,0,,It's closure. Dialogue: 0,0:17:06.28,0:17:08.06,EN,,0,0,0,,And that's the thing that Dialogue: 0,0:17:09.64,0:17:11.72,EN,,0,0,0,,allowed me to do what by now you took for granted Dialogue: 0,0:17:11.76,0:17:14.91,EN,,0,0,0,,I said, gee, there's a query which is AND of job and salary, Dialogue: 0,0:17:14.91,0:17:18.80,EN,,0,0,0,,and I said, oh, there's another one, which is AND of job, a NOT of something. Dialogue: 0,0:17:19.26,0:17:20.92,EN,,0,0,0,,The fact that I can do that is Dialogue: 0,0:17:20.94,0:17:22.91,EN,,0,0,0,,a direct consequence of this closure principle. Dialogue: 0,0:17:25.18,0:17:27.08,EN,,0,0,0,,OK, let's break and then we'll go on. Dialogue: 0,0:17:29.32,0:17:30.89,EN,,0,0,0,,AUDIENCE: Where does the dictionary come from? Dialogue: 0,0:17:30.99,0:17:36.03,EN,,0,0,0,,PROFESSOR: The dictionary comes initially from what you type in. Dialogue: 0,0:17:36.09,0:17:37.32,EN,,0,0,0,,So when you start this up, Dialogue: 0,0:17:39.16,0:17:41.09,EN,,0,0,0,,the first thing it does is set up this whole structure. Dialogue: 0,0:17:41.09,0:17:42.64,EN,,0,0,0,,It puts in one empty dictionary. Dialogue: 0,0:17:45.00,0:17:47.24,EN,,0,0,0,,And if all you have is one primitive query, Dialogue: 0,0:17:48.24,0:17:51.10,EN,,0,0,0,,then what will come out is a bunch of dictionaries with things filled in. Dialogue: 0,0:17:52.31,0:17:54.33,EN,,0,0,0,,The general situation that I have here Dialogue: 0,0:17:54.51,0:17:59.71,EN,,0,0,0,,is when this is in the middle of some nest of combined things. Dialogue: 0,0:18:01.55,0:18:02.30,EN,,0,0,0,,So by the time. Dialogue: 0,0:18:02.38,0:18:03.79,EN,,0,0,0,,Let's look at the picture over here. Dialogue: 0,0:18:04.38,0:18:06.73,EN,,0,0,0,,This supervisor query gets in some dictionary. Dialogue: 0,0:18:06.73,0:18:08.03,EN,,0,0,0,,Where did this one come from? Dialogue: 0,0:18:08.73,0:18:11.15,EN,,0,0,0,,This dictionary came from the fact that Dialogue: 0,0:18:12.84,0:18:14.89,EN,,0,0,0,,I'm looking at the output of this primitive query. Dialogue: 0,0:18:16.26,0:18:17.88,EN,,0,0,0,,So maybe to be very specific, Dialogue: 0,0:18:18.35,0:18:21.72,EN,,0,0,0,,if I literally typed in just this query at the top level, Dialogue: 0,0:18:22.27,0:18:22.92,EN,,0,0,0,,this AND, Dialogue: 0,0:18:23.07,0:18:25.28,EN,,0,0,0,,what would actually happen is it would build this structure Dialogue: 0,0:18:25.50,0:18:30.24,EN,,0,0,0,,and start up this whole thing with one empty dictionary. Dialogue: 0,0:18:31.77,0:18:34.33,EN,,0,0,0,,And now this one would process, and a whole bunch of dictionaries Dialogue: 0,0:18:34.36,0:18:37.36,EN,,0,0,0,,would come out with x, y's and d's in them. Dialogue: 0,0:18:38.64,0:18:39.58,EN,,0,0,0,,Run it through this one. Dialogue: 0,0:18:40.19,0:18:42.16,EN,,0,0,0,,So now that's the input to this one. Dialogue: 0,0:18:42.16,0:18:43.72,EN,,0,0,0,,This one would now put out some other stuff. Dialogue: 0,0:18:45.04,0:18:48.22,EN,,0,0,0,,And if this itself were buried in some larger thing, Dialogue: 0,0:18:49.31,0:18:51.00,EN,,0,0,0,,like an OR of something, Dialogue: 0,0:18:53.42,0:18:55.71,EN,,0,0,0,,then that would go feed into the next one. Dialogue: 0,0:18:58.56,0:19:01.28,EN,,0,0,0,,So you initially get only one empty dictionary when you start it, Dialogue: 0,0:19:01.68,0:19:04.08,EN,,0,0,0,,but as you're in the middle of processing these compounds things, Dialogue: 0,0:19:04.11,0:19:06.65,EN,,0,0,0,,that's where these cascades of dictionaries start getting generated. Dialogue: 0,0:19:07.66,0:19:12.28,EN,,0,0,0,,AUDIENCE: Dictionaries only come about as a result of using the queries? Dialogue: 0,0:19:15.12,0:19:17.69,EN,,0,0,0,,Or do they stays, do they become-- Dialogue: 0,0:19:18.84,0:19:22.81,EN,,0,0,0,,do they stay someplace in space like the database does? Dialogue: 0,0:19:23.68,0:19:24.98,EN,,0,0,0,,Are these temporary items? Dialogue: 0,0:19:24.98,0:19:27.18,EN,,0,0,0,,PROFESSOR: They're created temporarily in the matcher. Dialogue: 0,0:19:28.03,0:19:29.88,EN,,0,0,0,,Really, they're someplace in storage. Dialogue: 0,0:19:29.88,0:19:33.02,EN,,0,0,0,,Initially, someone creates a thing called the empty dictionary Dialogue: 0,0:19:34.22,0:19:36.80,EN,,0,0,0,,that gets initially fed to this match procedure, Dialogue: 0,0:19:36.81,0:19:39.05,EN,,0,0,0,,and then the match procedure builds some dictionaries, Dialogue: 0,0:19:39.07,0:19:40.27,EN,,0,0,0,,and they get passed on and on. Dialogue: 0,0:19:40.76,0:19:42.48,EN,,0,0,0,,AUDIENCE: OK, so they'll go way after the match? Dialogue: 0,0:19:43.64,0:19:46.25,EN,,0,0,0,,PROFESSOR: They'll go away when no one needs them again, yeah. Dialogue: 0,0:19:51.90,0:19:53.60,EN,,0,0,0,,AUDIENCE: It appears that the AND performs Dialogue: 0,0:19:53.63,0:19:55.37,EN,,0,0,0,,some redundant searches of the database. Dialogue: 0,0:19:55.96,0:19:57.48,EN,,0,0,0,,If the first clause matched, Dialogue: 0,0:19:57.50,0:19:59.90,EN,,0,0,0,,let's say, the third element and not on the first two elements, Dialogue: 0,0:20:00.25,0:20:03.64,EN,,0,0,0,,the second clause is going to look at those first two elements again, Dialogue: 0,0:20:04.32,0:20:06.59,EN,,0,0,0,,discarding them because they don't match. Dialogue: 0,0:20:06.64,0:20:08.72,EN,,0,0,0,,The match is already in the dictionary. Dialogue: 0,0:20:10.00,0:20:12.56,EN,,0,0,0,,Would it makes sense to carry the data element Dialogue: 0,0:20:12.57,0:20:14.43,EN,,0,0,0,,from the database along with the dictionary? Dialogue: 0,0:20:15.69,0:20:17.60,EN,,0,0,0,,PROFESSOR: Yeah, there're... Well, in general, Dialogue: 0,0:20:17.63,0:20:19.48,EN,,0,0,0,,there are other ways to arrange this search, Dialogue: 0,0:20:20.12,0:20:21.74,EN,,0,0,0,,and there's some analysis that you can do. Dialogue: 0,0:20:21.74,0:20:23.16,EN,,0,0,0,,I think there's a problem in the book, Dialogue: 0,0:20:23.87,0:20:26.65,EN,,0,0,0,,which talks about a different way that you can cascade AND Dialogue: 0,0:20:27.00,0:20:29.20,EN,,0,0,0,,to eliminate various kinds of redundancies. Dialogue: 0,0:20:29.85,0:20:30.72,EN,,0,0,0,,This one is meant to be-- Dialogue: 0,0:20:31.32,0:20:34.54,EN,,0,0,0,,was mainly meant to be very simple so you can see how they fit together. Dialogue: 0,0:20:34.70,0:20:35.38,EN,,0,0,0,,But you're quite right. Dialogue: 0,0:20:35.38,0:20:37.32,EN,,0,0,0,,There are redundancies here that you can get rid of. Dialogue: 0,0:20:38.37,0:20:40.80,EN,,0,0,0,,That's another reason why this language is somewhat slow. Dialogue: 0,0:20:41.19,0:20:42.70,EN,,0,0,0,,There are a lot smarter things you can do. Dialogue: 0,0:20:42.93,0:20:46.22,EN,,0,0,0,,We're just trying to show you a very simple, in principle, implementation. Dialogue: 0,0:20:51.22,0:20:53.23,EN,,0,0,0,,AUDIENCE: Did you model this language on Prolog, Dialogue: 0,0:20:53.24,0:20:55.13,EN,,0,0,0,,or did it just come out looking like Prolog? Dialogue: 0,0:21:04.96,0:21:07.08,EN,,0,0,0,,PROFESSOR: Well, Gerry insulted a whole bunch of people yesterday, Dialogue: 0,0:21:07.24,0:21:09.92,EN,,0,0,0,,so I might as well say that the MIT attitude towards Prolog is Dialogue: 0,0:21:10.19,0:21:12.60,EN,,0,0,0,,is something that people did in about 1971 Dialogue: 0,0:21:12.64,0:21:15.60,EN,,0,0,0,,and decided that it wasn't really the right thing and stopped. Dialogue: 0,0:21:16.12,0:21:22.80,EN,,0,0,0,,So we modeled this on the sort of natural way that this thing was done Dialogue: 0,0:21:22.84,0:21:24.73,EN,,0,0,0,,in about 1971, Dialogue: 0,0:21:25.13,0:21:27.24,EN,,0,0,0,,except at that point, we didn't do it with streams. Dialogue: 0,0:21:28.27,0:21:33.04,EN,,0,0,0,,And then we... After we were using it for about six months, Dialogue: 0,0:21:33.08,0:21:34.91,EN,,0,0,0,,we discovered that it had all these problems, Dialogue: 0,0:21:34.94,0:21:36.30,EN,,0,0,0,,some of which I'll talk about later. Dialogue: 0,0:21:37.33,0:21:38.19,EN,,0,0,0,,And we said, Dialogue: 0,0:21:38.44,0:21:39.92,EN,,0,0,0,,gee, Prolog must have fixed those, Dialogue: 0,0:21:39.93,0:21:41.21,EN,,0,0,0,,and then we found out that it didn't. Dialogue: 0,0:21:41.25,0:21:43.02,EN,,0,0,0,,So this does about the same thing as Prolog. Dialogue: 0,0:21:43.60,0:21:44.95,EN,,0,0,0,,AUDIENCE: Does Prolog use streams? Dialogue: 0,0:21:44.95,0:21:46.20,EN,,0,0,0,,PROFESSOR: No. Prolog -- Dialogue: 0,0:21:46.78,0:21:51.04,EN,,0,0,0,,In how it behaves, it behaves a lot like Prolog. Dialogue: 0,0:21:51.04,0:21:52.96,EN,,0,0,0,,Prolog uses a backtracking strategy. Dialogue: 0,0:21:53.80,0:21:55.71,EN,,0,0,0,,But the other thing that's really good about Prolog Dialogue: 0,0:21:55.72,0:21:57.98,EN,,0,0,0,,that makes it a usable thing Dialogue: 0,0:21:58.28,0:22:01.50,EN,,0,0,0,,is that there's a really very, very Dialogue: 0,0:22:01.68,0:22:04.09,EN,,0,0,0,,there's a really very, very well-engineered compiler technology Dialogue: 0,0:22:04.11,0:22:05.32,EN,,0,0,0,,that makes it run fast. Dialogue: 0,0:22:06.65,0:22:10.81,EN,,0,0,0,,So although you saw the merge spitting out these answers very, very slowly, Dialogue: 0,0:22:11.66,0:22:13.61,EN,,0,0,0,,a real Prolog will run very, very fast. Dialogue: 0,0:22:14.70,0:22:16.48,EN,,0,0,0,,Because even though it's sort of doing this, Dialogue: 0,0:22:16.67,0:22:20.81,EN,,0,0,0,,the real work that went into Prolog is a very, very excellent compiler effort. Dialogue: 0,0:22:24.30,0:22:25.21,EN,,0,0,0,,Let's take a break. Dialogue: 0,0:22:25.42,0:22:36.17,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:23:16.65,0:23:18.83,EN,,0,0,0,,We've looked at the primitive queries Dialogue: 0,0:23:19.21,0:23:23.52,EN,,0,0,0,,and the ways that streams are used to implement the means of combination: Dialogue: 0,0:23:23.79,0:23:25.72,EN,,0,0,0,,AND and OR and NOT. Dialogue: 0,0:23:26.95,0:23:28.43,EN,,0,0,0,,Now, let go on to the means of abstraction. Dialogue: 0,0:23:29.58,0:23:32.80,EN,,0,0,0,,Remember, the means of abstraction in this language are rules. Dialogue: 0,0:23:35.15,0:23:37.79,EN,,0,0,0,,So z is a boss in division d Dialogue: 0,0:23:39.18,0:23:43.77,EN,,0,0,0,,if there's some x who has a job in division d Dialogue: 0,0:23:45.68,0:23:47.47,EN,,0,0,0,,and z is the supervisor of x. Dialogue: 0,0:23:48.90,0:23:50.60,EN,,0,0,0,,That's what it means for someone to be a boss. Dialogue: 0,0:23:52.26,0:23:53.15,EN,,0,0,0,,So, and in effect, Dialogue: 0,0:23:53.34,0:23:55.61,EN,,0,0,0,,if you think about what we're doing with relation to this, Dialogue: 0,0:23:56.80,0:23:57.90,EN,,0,0,0,,there's the query we wrote-- Dialogue: 0,0:23:57.93,0:24:01.90,EN,,0,0,0,,the job of x is in d and the supervisor of x is z-- Dialogue: 0,0:24:02.19,0:24:04.28,EN,,0,0,0,,what we in effect want to do is take this whole mess Dialogue: 0,0:24:05.07,0:24:06.57,EN,,0,0,0,,and draw a box around it Dialogue: 0,0:24:19.08,0:24:24.54,EN,,0,0,0,,and say this whole thing inside the box Dialogue: 0,0:24:25.15,0:24:32.48,EN,,0,0,0,,is boss of z in division d. Dialogue: 0,0:24:33.90,0:24:35.25,EN,,0,0,0,,That's in effect what we want to do. Dialogue: 0,0:24:38.72,0:24:39.72,EN,,0,0,0,,So, for instance, Dialogue: 0,0:24:43.18,0:24:44.08,EN,,0,0,0,,if we've done that, Dialogue: 0,0:24:45.00,0:24:47.84,EN,,0,0,0,,and we want to check whether or not it's true Dialogue: 0,0:24:47.95,0:24:50.51,EN,,0,0,0,,that Ben Bitdiddle is a boss in the computer division, Dialogue: 0,0:24:51.10,0:25:02.86,EN,,0,0,0,,so if I want to say boss of Ben Bitdiddle in the computer division, Dialogue: 0,0:25:04.78,0:25:07.08,EN,,0,0,0,,imagine typing that in as query to the system, Dialogue: 0,0:25:07.12,0:25:09.16,EN,,0,0,0,,in effect what we want to do Dialogue: 0,0:25:10.67,0:25:12.92,EN,,0,0,0,,is set up a dictionary here, Dialogue: 0,0:25:15.82,0:25:23.63,EN,,0,0,0,,which has z to Ben Bitdiddle Dialogue: 0,0:25:28.88,0:25:33.31,EN,,0,0,0,,and d to computer. Dialogue: 0,0:25:37.08,0:25:38.62,EN,,0,0,0,,Where did that dictionary come from? Dialogue: 0,0:25:38.68,0:25:40.71,EN,,0,0,0,,Let's look at the slide for one second. Dialogue: 0,0:25:40.71,0:25:43.71,EN,,0,0,0,,That dictionary came from matching the query Dialogue: 0,0:25:44.30,0:25:46.33,EN,,0,0,0,,that said boss of Ben Bitdiddle and computer Dialogue: 0,0:25:46.51,0:25:49.63,EN,,0,0,0,,onto the conclusion of the rule: boss of z and d. Dialogue: 0,0:25:51.65,0:25:54.11,EN,,0,0,0,,So we match the query to the conclusion of the rule. Dialogue: 0,0:25:54.19,0:25:55.53,EN,,0,0,0,,That gives us a dictionary, Dialogue: 0,0:25:58.99,0:26:02.54,EN,,0,0,0,,and that's the thing that we would now like to put into this whole big thing Dialogue: 0,0:26:02.92,0:26:05.56,EN,,0,0,0,,and process and see if anything comes out the other side. Dialogue: 0,0:26:06.67,0:26:09.88,EN,,0,0,0,,If anything comes out, it'll be true. Dialogue: 0,0:26:11.33,0:26:12.37,EN,,0,0,0,,That's the basic idea. Dialogue: 0,0:26:12.37,0:26:13.24,EN,,0,0,0,,So in general, Dialogue: 0,0:26:14.03,0:26:15.40,EN,,0,0,0,,the way we implement a rule Dialogue: 0,0:26:15.85,0:26:18.89,EN,,0,0,0,,is we match the conclusion of the rule Dialogue: 0,0:26:20.86,0:26:22.96,EN,,0,0,0,,against something we might want to check it's true. Dialogue: 0,0:26:23.58,0:26:25.12,EN,,0,0,0,,That match gives us a dictionary, Dialogue: 0,0:26:25.29,0:26:28.22,EN,,0,0,0,,and with respect to that dictionary, Dialogue: 0,0:26:30.35,0:26:34.51,EN,,0,0,0,,we process the body of the rule. Dialogue: 0,0:26:36.33,0:26:37.68,EN,,0,0,0,,Well, that's really all there is, Dialogue: 0,0:26:38.64,0:26:41.44,EN,,0,0,0,,except for two technical points. Dialogue: 0,0:26:43.04,0:26:44.32,EN,,0,0,0,,The first technical point is that Dialogue: 0,0:26:45.74,0:26:47.26,EN,,0,0,0,,I might have said something else. Dialogue: 0,0:26:47.51,0:26:48.41,EN,,0,0,0,,I might have said Dialogue: 0,0:26:50.54,0:26:52.36,EN,,0,0,0,,who's the boss in the computer division? Dialogue: 0,0:26:52.54,0:26:56.32,EN,,0,0,0,,So I might say boss of who in computer division. Dialogue: 0,0:27:00.78,0:27:01.63,EN,,0,0,0,,And if I did that, Dialogue: 0,0:27:02.57,0:27:04.62,EN,,0,0,0,,what I would really like to do in effect is not Dialogue: 0,0:27:05.04,0:27:06.49,EN,,0,0,0,,is start up this dictionary Dialogue: 0,0:27:08.35,0:27:09.88,EN,,0,0,0,,with a match that sort of says, Dialogue: 0,0:27:09.93,0:27:11.20,EN,,0,0,0,,well, d is computer Dialogue: 0,0:27:14.35,0:27:18.48,EN,,0,0,0,,and z is whatever who is. Dialogue: 0,0:27:21.70,0:27:23.22,EN,,0,0,0,,And our matcher won't quite do that. Dialogue: 0,0:27:23.22,0:27:27.00,EN,,0,0,0,,That's not quite matching a pattern against data. Dialogue: 0,0:27:28.58,0:27:29.72,EN,,0,0,0,,It's matching two patterns Dialogue: 0,0:27:29.74,0:27:31.58,EN,,0,0,0,,sort of saying are they consistent or not Dialogue: 0,0:27:31.90,0:27:33.48,EN,,0,0,0,,or what ways make them consistent. Dialogue: 0,0:27:33.48,0:27:36.43,EN,,0,0,0,,In other words, what we need is not quite a pattern matcher, Dialogue: 0,0:27:36.96,0:27:38.91,EN,,0,0,0,,but something a little bit more general Dialogue: 0,0:27:39.13,0:27:40.11,EN,,0,0,0,,called a unifier. Dialogue: 0,0:27:44.42,0:27:48.06,EN,,0,0,0,,And a unifier is a slight generalization of a pattern matcher. Dialogue: 0,0:27:49.53,0:27:52.17,EN,,0,0,0,,What a unifier does is take two patterns Dialogue: 0,0:27:53.23,0:27:57.53,EN,,0,0,0,,and say what's the most general thing you can substitute Dialogue: 0,0:27:58.20,0:28:00.01,EN,,0,0,0,,for the variables in those two patterns Dialogue: 0,0:28:02.68,0:28:05.08,EN,,0,0,0,,to make them satisfy the pattern simultaneously? Dialogue: 0,0:28:05.68,0:28:06.60,EN,,0,0,0,,Let me give you an example. Dialogue: 0,0:28:08.86,0:28:14.49,EN,,0,0,0,,If I have the pattern two-element list, which is x and x, Dialogue: 0,0:28:15.76,0:28:17.15,EN,,0,0,0,,so this is I have a two-element list Dialogue: 0,0:28:17.32,0:28:18.64,EN,,0,0,0,,where both elements are the same Dialogue: 0,0:28:18.67,0:28:20.04,EN,,0,0,0,,and otherwise I don't care what they are, Dialogue: 0,0:28:20.40,0:28:22.83,EN,,0,0,0,,and I unify that against the pattern Dialogue: 0,0:28:22.92,0:28:24.62,EN,,0,0,0,,that says there's a two-element list, Dialogue: 0,0:28:24.65,0:28:27.61,EN,,0,0,0,,and the first one is a and something and c Dialogue: 0,0:28:28.00,0:28:30.14,EN,,0,0,0,,and the second one is a and b and z, Dialogue: 0,0:28:33.07,0:28:34.88,EN,,0,0,0,,then what the unifier should tell me is, Dialogue: 0,0:28:34.89,0:28:36.17,EN,,0,0,0,,oh yeah, in that dictionary, Dialogue: 0,0:28:36.35,0:28:37.96,EN,,0,0,0,,x has to be a, b, c, Dialogue: 0,0:28:39.34,0:28:41.92,EN,,0,0,0,,and y has to be d and z has to be c. Dialogue: 0,0:28:43.44,0:28:46.28,EN,,0,0,0,,Those are the restrictions I'd have to put on the values of x, y, and z Dialogue: 0,0:28:46.33,0:28:47.58,EN,,0,0,0,,to make these two unify, Dialogue: 0,0:28:48.12,0:28:50.84,EN,,0,0,0,,or in other words, to make this match x Dialogue: 0,0:28:51.15,0:28:53.37,EN,,0,0,0,,and make this match x. Dialogue: 0,0:28:55.28,0:28:57.76,EN,,0,0,0,,The unifier should be able to deduce that. Dialogue: 0,0:28:58.54,0:29:01.08,EN,,0,0,0,,But the unifier may-- there are more complicated things. Dialogue: 0,0:29:01.08,0:29:03.07,EN,,0,0,0,,I might have said something a little bit more complicated. Dialogue: 0,0:29:03.48,0:29:05.74,EN,,0,0,0,,I might have said there's a list with two elements, Dialogue: 0,0:29:07.00,0:29:08.28,EN,,0,0,0,,and they're both the same, Dialogue: 0,0:29:08.86,0:29:11.15,EN,,0,0,0,,and they should unify against something of this form. Dialogue: 0,0:29:12.65,0:29:15.36,EN,,0,0,0,,And the unifier should be able to deduce from that. Dialogue: 0,0:29:16.89,0:29:19.57,EN,,0,0,0,,Like that y would have to be b. y would have to be b. Dialogue: 0,0:29:19.57,0:29:22.12,EN,,0,0,0,,Because these two are the same, Dialogue: 0,0:29:22.22,0:29:23.52,EN,,0,0,0,,so y's got to be b. Dialogue: 0,0:29:24.34,0:29:27.53,EN,,0,0,0,,And v here would have to be a. Dialogue: 0,0:29:28.94,0:29:30.99,EN,,0,0,0,,And z and w can be anything, Dialogue: 0,0:29:31.00,0:29:32.43,EN,,0,0,0,,but they have to be the same thing. Dialogue: 0,0:29:35.71,0:29:41.76,EN,,0,0,0,,And x would have to be b, followed by a, followed by whatever w Dialogue: 0,0:29:42.83,0:29:44.68,EN,,0,0,0,,or whatever z is, which is the same. Dialogue: 0,0:29:44.70,0:29:49.42,EN,,0,0,0,,So you see, the unifier somehow has to deduce things to unify these patterns. Dialogue: 0,0:29:50.88,0:29:53.52,EN,,0,0,0,,So you might think there's some kind of magic deduction going on, Dialogue: 0,0:29:54.27,0:29:55.23,EN,,0,0,0,,but there's not. Dialogue: 0,0:29:55.85,0:29:59.88,EN,,0,0,0,,A unifier is basically a very simple modification of a pattern matcher. Dialogue: 0,0:30:00.15,0:30:01.85,EN,,0,0,0,,And if you look in the book, you'll see something like Dialogue: 0,0:30:02.25,0:30:06.16,EN,,0,0,0,,like three or four lines of code added to the pattern matcher you just saw Dialogue: 0,0:30:06.49,0:30:08.17,EN,,0,0,0,,to handle the symmetric case. Dialogue: 0,0:30:08.28,0:30:10.81,EN,,0,0,0,,Remember, the pattern matcher has a place where it says Dialogue: 0,0:30:11.66,0:30:14.28,EN,,0,0,0,,is this variable matching a constant. Dialogue: 0,0:30:14.98,0:30:16.42,EN,,0,0,0,,And if so, it checks in the dictionary. Dialogue: 0,0:30:16.42,0:30:18.25,EN,,0,0,0,,There's only one other clause in the unifier, Dialogue: 0,0:30:18.49,0:30:20.75,EN,,0,0,0,,which says is this variable matching a variable, Dialogue: 0,0:30:22.00,0:30:23.42,EN,,0,0,0,,in which case you go look in the dictionary Dialogue: 0,0:30:23.45,0:30:25.68,EN,,0,0,0,,and see if that's consistent with what's in the dictionary. Dialogue: 0,0:30:27.03,0:30:31.13,EN,,0,0,0,,So all the, quote, deduction that's in this language, Dialogue: 0,0:30:31.28,0:30:34.59,EN,,0,0,0,,if you sort of look at it, sort of sits in the rule applications, Dialogue: 0,0:30:34.99,0:30:37.88,EN,,0,0,0,,which, if you look at that, sits in the unifier, Dialogue: 0,0:30:38.36,0:30:40.32,EN,,0,0,0,,which, if you look at that under a microscope, Dialogue: 0,0:30:40.56,0:30:43.96,EN,,0,0,0,,sits essentially in the pattern matcher. Dialogue: 0,0:30:44.94,0:30:47.07,EN,,0,0,0,,There's no magic at all going on in there. Dialogue: 0,0:30:47.41,0:30:50.25,EN,,0,0,0,,And the, quote, deduction that you see Dialogue: 0,0:30:50.94,0:30:52.89,EN,,0,0,0,,is just the fact that there's this recursion, Dialogue: 0,0:30:52.92,0:30:55.69,EN,,0,0,0,,which is unwinding the matches bit by bit. Dialogue: 0,0:30:56.03,0:30:58.03,EN,,0,0,0,,So it looks like this thing is being very clever, Dialogue: 0,0:30:58.44,0:31:00.36,EN,,0,0,0,,but in fact, it's not being very clever at all. Dialogue: 0,0:31:02.14,0:31:04.41,EN,,0,0,0,,There are cases where a unifier might have to be clever. Dialogue: 0,0:31:04.88,0:31:05.87,EN,,0,0,0,,Let me show you one more. Dialogue: 0,0:31:11.07,0:31:13.36,EN,,0,0,0,,Suppose I want to unify a list of two elements, Dialogue: 0,0:31:13.48,0:31:14.81,EN,,0,0,0,,x and x, Dialogue: 0,0:31:17.24,0:31:22.14,EN,,0,0,0,,with a thing that says it's y followed by a dot y. Dialogue: 0,0:31:24.37,0:31:26.12,EN,,0,0,0,,Now, if you think of what that would have to mean, Dialogue: 0,0:31:26.86,0:31:29.71,EN,,0,0,0,,it would have to mean that x had better be the same as y, Dialogue: 0,0:31:30.92,0:31:31.66,EN,,0,0,0,,but also Dialogue: 0,0:31:31.82,0:31:36.16,EN,,0,0,0,,x had better be the same as a list whose first element is a and whose rest is y. Dialogue: 0,0:31:37.33,0:31:39.45,EN,,0,0,0,,And if you think about what that would have to mean, Dialogue: 0,0:31:42.27,0:31:44.71,EN,,0,0,0,,it would have to mean that y is the infinite list of a's. Dialogue: 0,0:31:47.50,0:31:48.35,EN,,0,0,0,,In some sense, Dialogue: 0,0:31:49.21,0:31:52.40,EN,,0,0,0,,in order to do that unification, Dialogue: 0,0:31:52.60,0:31:54.84,EN,,0,0,0,,I have to solve the fixed-point equation Dialogue: 0,0:31:55.05,0:32:01.84,EN,,0,0,0,,cons of a to y is equal to y. Dialogue: 0,0:32:04.57,0:32:06.96,EN,,0,0,0,,And in general, I wrote a very simple one. Dialogue: 0,0:32:07.29,0:32:08.67,EN,,0,0,0,,Really doing unification Dialogue: 0,0:32:08.97,0:32:11.98,EN,,0,0,0,,might have to solve an arbitrary fixed-point equation: Dialogue: 0,0:32:12.01,0:32:13.42,EN,,0,0,0,,f of y equals y. Dialogue: 0,0:32:15.53,0:32:17.08,EN,,0,0,0,,And basically, you can't do that Dialogue: 0,0:32:17.10,0:32:19.47,EN,,0,0,0,,and make the thing finite all the time. Dialogue: 0,0:32:20.57,0:32:23.60,EN,,0,0,0,,So how does the logic language handle that? Dialogue: 0,0:32:24.89,0:32:26.48,EN,,0,0,0,,The answer is it doesn't. Dialogue: 0,0:32:27.16,0:32:28.04,EN,,0,0,0,,It just punts. Dialogue: 0,0:32:28.73,0:32:31.07,EN,,0,0,0,,And there's a little check in the unifier, Dialogue: 0,0:32:31.31,0:32:33.82,EN,,0,0,0,,which says, oh, is this one of the hard cases Dialogue: 0,0:32:34.44,0:32:38.00,EN,,0,0,0,,which when I go to match things would involve solving a fixed-point equation? Dialogue: 0,0:32:38.65,0:32:40.81,EN,,0,0,0,,And in this case, I will throw up my hands. Dialogue: 0,0:32:42.84,0:32:44.65,EN,,0,0,0,,And if that check were not in there, Dialogue: 0,0:32:45.00,0:32:45.88,EN,,0,0,0,,what would happen? Dialogue: 0,0:32:47.99,0:32:49.10,EN,,0,0,0,,In most cases is Dialogue: 0,0:32:49.13,0:32:51.31,EN,,0,0,0,,that the unifier would just go into an infinite loop. Dialogue: 0,0:32:53.74,0:32:56.54,EN,,0,0,0,,And other logic programming languages work like that. Dialogue: 0,0:32:56.80,0:32:58.14,EN,,0,0,0,,So there's really no magic. Dialogue: 0,0:32:58.22,0:32:59.93,EN,,0,0,0,,The easy case is done in a matcher. Dialogue: 0,0:33:00.10,0:33:01.58,EN,,0,0,0,,The hard case is not done at all. Dialogue: 0,0:33:02.96,0:33:05.47,EN,,0,0,0,,And that's about the state of this technology. Dialogue: 0,0:33:11.88,0:33:14.24,EN,,0,0,0,,OK, Let me just say again formally Dialogue: 0,0:33:14.27,0:33:16.38,EN,,0,0,0,,how rules work now that I talked about unifiers. Dialogue: 0,0:33:17.39,0:33:18.75,EN,,0,0,0,,So the official definition Dialogue: 0,0:33:19.20,0:33:20.96,EN,,0,0,0,,is that to apply a rule, Dialogue: 0,0:33:24.17,0:33:27.13,EN,,0,0,0,,we-- well, let's start using some words we've used before. Dialogue: 0,0:33:28.27,0:33:32.01,EN,,0,0,0,,Let's talk about sticking dictionaries into Dialogue: 0,0:33:32.88,0:33:34.78,EN,,0,0,0,,these big boxes of query things Dialogue: 0,0:33:34.81,0:33:38.54,EN,,0,0,0,,as evaluating these large queries Dialogue: 0,0:33:39.95,0:33:43.85,EN,,0,0,0,,relative to an environment or a frame. Dialogue: 0,0:33:43.85,0:33:45.04,EN,,0,0,0,,So when you think of that dictionary, Dialogue: 0,0:33:45.07,0:33:46.28,EN,,0,0,0,,what's the dictionary after all? Dialogue: 0,0:33:46.72,0:33:48.18,EN,,0,0,0,,It's a bunch of meanings for symbols. Dialogue: 0,0:33:48.18,0:33:50.22,EN,,0,0,0,,That's what we've been calling frames or environments. Dialogue: 0,0:33:51.80,0:33:55.97,EN,,0,0,0,,What does it mean to do some processing relevant to an environment? Dialogue: 0,0:33:55.97,0:33:57.42,EN,,0,0,0,,That's what we've been calling evaluation. Dialogue: 0,0:33:58.33,0:34:01.56,EN,,0,0,0,,So we can say the way that you apply a rule Dialogue: 0,0:34:01.92,0:34:06.16,EN,,0,0,0,,is to evaluate the rule body relative to an environment Dialogue: 0,0:34:06.67,0:34:11.58,EN,,0,0,0,,that's formed by unifying the rule conclusion with the given query. Dialogue: 0,0:34:13.23,0:34:14.51,EN,,0,0,0,,And the thing I want you to notice Dialogue: 0,0:34:14.80,0:34:17.08,EN,,0,0,0,,is the complete formal similarity Dialogue: 0,0:34:18.16,0:34:21.50,EN,,0,0,0,,to the net of circular evaluator or the substitution model. Dialogue: 0,0:34:21.63,0:34:22.73,EN,,0,0,0,,To apply a procedure, Dialogue: 0,0:34:22.86,0:34:28.36,EN,,0,0,0,,we evaluate the procedure body relative to an environment Dialogue: 0,0:34:28.54,0:34:33.13,EN,,0,0,0,,that's formed by blinding the procedure parameters to the arguments. Dialogue: 0,0:34:34.56,0:34:36.41,EN,,0,0,0,,There's a complete formal similarity there Dialogue: 0,0:34:36.44,0:34:40.41,EN,,0,0,0,,between the rules, rule application, and procedure application Dialogue: 0,0:34:40.57,0:34:42.30,EN,,0,0,0,,even though these things are very, very different. Dialogue: 0,0:34:43.65,0:34:45.61,EN,,0,0,0,,And again, you have the EVAL APPLY loop. Dialogue: 0,0:34:47.29,0:34:49.52,EN,,0,0,0,,EVAL and APPLY. Dialogue: 0,0:34:53.39,0:34:57.39,EN,,0,0,0,,So in general, I might be processing some combined expression Dialogue: 0,0:34:57.42,0:34:59.13,EN,,0,0,0,,that will turn into a rule application, Dialogue: 0,0:35:00.70,0:35:03.28,EN,,0,0,0,,which will generate some dictionaries or frames or environments-- Dialogue: 0,0:35:03.31,0:35:04.72,EN,,0,0,0,,whatever you want to call them-- from match, Dialogue: 0,0:35:05.02,0:35:08.43,EN,,0,0,0,,which will then be the input to some big compound thing like this. Dialogue: 0,0:35:08.66,0:35:11.77,EN,,0,0,0,,This has pieces of it and may have other rule applications. Dialogue: 0,0:35:13.58,0:35:15.68,EN,,0,0,0,,And you have essentially the same cycle Dialogue: 0,0:35:15.72,0:35:18.68,EN,,0,0,0,,even though there's nothing here at all that looks like procedures. Dialogue: 0,0:35:19.68,0:35:21.87,EN,,0,0,0,,It really has to do with the fact you've built a language Dialogue: 0,0:35:22.08,0:35:25.49,EN,,0,0,0,,whose means of combination and abstraction unwind in certain ways. Dialogue: 0,0:35:28.77,0:35:29.52,EN,,0,0,0,,And then in general, Dialogue: 0,0:35:29.77,0:35:31.39,EN,,0,0,0,,what happens at the very top level, Dialogue: 0,0:35:33.79,0:35:35.96,EN,,0,0,0,,you might have rules in your database also, Dialogue: 0,0:35:36.65,0:35:38.70,EN,,0,0,0,,so things in this database might be rules. Dialogue: 0,0:35:40.46,0:35:42.06,EN,,0,0,0,,There are ways to check that things are true. Dialogue: 0,0:35:42.92,0:35:44.89,EN,,0,0,0,,So it might come in here and have to do a rule check. Dialogue: 0,0:35:46.75,0:35:48.16,EN,,0,0,0,,And then there's some control structure Dialogue: 0,0:35:48.19,0:35:50.48,EN,,0,0,0,,which says, well, you look at some rules, and you look at some data elements, Dialogue: 0,0:35:50.51,0:35:51.80,EN,,0,0,0,,and you look at some rules and data elements, Dialogue: 0,0:35:51.84,0:35:53.12,EN,,0,0,0,,and these fan out and out and out. Dialogue: 0,0:35:53.35,0:35:55.48,EN,,0,0,0,,So it becomes essentially impossible Dialogue: 0,0:35:55.68,0:35:57.69,EN,,0,0,0,,to say what order it's looking at these things in, Dialogue: 0,0:35:58.20,0:36:00.27,EN,,0,0,0,,whether it's breadth first or depth first or anything. Dialogue: 0,0:36:00.28,0:36:01.64,EN,,0,0,0,,And it's even more impossible Dialogue: 0,0:36:01.66,0:36:05.58,EN,,0,0,0,,because the actual order is somehow buried in the delays of the streams. Dialogue: 0,0:36:07.69,0:36:11.16,EN,,0,0,0,,So what's very hard to tell from this is the order in which it's scanned. Dialogue: 0,0:36:11.27,0:36:12.16,EN,,0,0,0,,But what's true is, Dialogue: 0,0:36:12.19,0:36:13.64,EN,,0,0,0,,because you're looking at the stream view, Dialogue: 0,0:36:13.90,0:36:15.82,EN,,0,0,0,,is that all of them eventually get looked at. Dialogue: 0,0:36:24.98,0:36:28.15,EN,,0,0,0,,Let me just mention one tiny technical problem. Dialogue: 0,0:36:30.88,0:36:33.55,EN,,0,0,0,,Um Suppose I tried over here. Dialogue: 0,0:36:37.53,0:36:41.00,EN,,0,0,0,,Suppose I tried saying boss of y is computer, Dialogue: 0,0:36:44.22,0:36:45.78,EN,,0,0,0,,then a funny thing would happen. Dialogue: 0,0:36:45.78,0:36:50.25,EN,,0,0,0,,As I stuck a dictionary with y in here, Dialogue: 0,0:36:52.73,0:36:57.37,EN,,0,0,0,,I might get-- this y is not the same as that y, Dialogue: 0,0:36:57.42,0:37:00.62,EN,,0,0,0,,which was the other piece of somebody's job description. Dialogue: 0,0:37:01.58,0:37:03.80,EN,,0,0,0,,So if I really only did literally what I said, Dialogue: 0,0:37:04.22,0:37:06.44,EN,,0,0,0,,we'd get some variable conflict problems. Dialogue: 0,0:37:09.28,0:37:10.48,EN,,0,0,0,,So I lied to you a little bit. Dialogue: 0,0:37:10.93,0:37:13.84,EN,,0,0,0,,Notice that problem is exactly a problem we've run into before. Dialogue: 0,0:37:14.27,0:37:15.56,EN,,0,0,0,,It is precisely Dialogue: 0,0:37:15.96,0:37:18.36,EN,,0,0,0,,the need for local variables in a language. Dialogue: 0,0:37:19.24,0:37:21.74,EN,,0,0,0,,When I square, when I have the sum of squares, Dialogue: 0,0:37:21.79,0:37:23.39,EN,,0,0,0,,that x had better not be that x. Dialogue: 0,0:37:24.96,0:37:26.32,EN,,0,0,0,,That's exactly the same as Dialogue: 0,0:37:27.39,0:37:29.77,EN,,0,0,0,,as this y had better not be that y. Dialogue: 0,0:37:31.80,0:37:32.75,EN,,0,0,0,,And we know how to solve that. Dialogue: 0,0:37:32.78,0:37:34.49,EN,,0,0,0,,We built -- That was this whole environment model, Dialogue: 0,0:37:34.51,0:37:37.04,EN,,0,0,0,,and we built chains of frames and all sorts of things like that. Dialogue: 0,0:37:37.71,0:37:39.10,EN,,0,0,0,,There's a much more brutal way to solve it. Dialogue: 0,0:37:39.10,0:37:41.73,EN,,0,0,0,,In the query language, we didn't even do that. Dialogue: 0,0:37:41.73,0:37:43.18,EN,,0,0,0,,We did something completely brutal. Dialogue: 0,0:37:43.54,0:37:45.93,EN,,0,0,0,,We said every time you apply a rule, Dialogue: 0,0:37:47.26,0:37:49.63,EN,,0,0,0,,rename consistently all the variables in the rule Dialogue: 0,0:37:49.77,0:37:53.50,EN,,0,0,0,,to some new unique names that won't conflict with anything. Dialogue: 0,0:37:54.04,0:37:57.10,EN,,0,0,0,,If you looked at the -- That's conceptually simpler, Dialogue: 0,0:37:57.12,0:37:59.24,EN,,0,0,0,,but really brutal and not particularly efficient. Dialogue: 0,0:37:59.97,0:38:01.15,EN,,0,0,0,,But notice, Dialogue: 0,0:38:01.39,0:38:04.68,EN,,0,0,0,,we could have gotten rid of all of our environment structures Dialogue: 0,0:38:05.50,0:38:08.72,EN,,0,0,0,,if we defined for procedures in Lisp the same thing. Dialogue: 0,0:38:08.75,0:38:11.56,EN,,0,0,0,,If every time we applied a procedure and did the substitution model Dialogue: 0,0:38:11.87,0:38:13.90,EN,,0,0,0,,we renamed all the variables in the procedure, Dialogue: 0,0:38:14.19,0:38:16.28,EN,,0,0,0,,then we never would have had to worry about local variables Dialogue: 0,0:38:16.33,0:38:17.39,EN,,0,0,0,,because they would never arise. Dialogue: 0,0:38:19.04,0:38:20.41,EN,,0,0,0,,OK, well, that would be inefficient, Dialogue: 0,0:38:20.91,0:38:23.04,EN,,0,0,0,,and it's inefficient here in the query language, too, Dialogue: 0,0:38:23.29,0:38:24.59,EN,,0,0,0,,but we did it to keep it simple. Dialogue: 0,0:38:25.61,0:38:26.67,EN,,0,0,0,,Let's break for questions. Dialogue: 0,0:38:30.88,0:38:33.39,EN,,0,0,0,,AUDIENCE: When you started this section, Dialogue: 0,0:38:33.40,0:38:39.60,EN,,0,0,0,,you emphasized how powerful our APPLY EVAL model was Dialogue: 0,0:38:39.63,0:38:41.17,EN,,0,0,0,,that we could use it for any language. Dialogue: 0,0:38:41.17,0:38:43.39,EN,,0,0,0,,And then you say we're going to have this language which is so different. Dialogue: 0,0:38:43.95,0:38:45.13,EN,,0,0,0,,It turns out that this language, Dialogue: 0,0:38:45.58,0:38:47.88,EN,,0,0,0,,as you just pointed out, is very much the same. Dialogue: 0,0:38:47.88,0:38:49.85,EN,,0,0,0,,I'm wondering if you're arguing that all languages end up Dialogue: 0,0:38:50.48,0:38:54.57,EN,,0,0,0,,coming down to this you can apply a rule or apply a procedure Dialogue: 0,0:38:55.12,0:38:55.98,EN,,0,0,0,,or some kind of apply? Dialogue: 0,0:38:57.07,0:38:58.88,EN,,0,0,0,,PROFESSOR: I would say that pretty much any language Dialogue: 0,0:38:58.92,0:39:00.30,EN,,0,0,0,,where you really are building up Dialogue: 0,0:39:00.92,0:39:04.40,EN,,0,0,0,,these means of combination and giving them simpler names Dialogue: 0,0:39:04.70,0:39:06.86,EN,,0,0,0,,and you're saying anything of the sort, like Dialogue: 0,0:39:07.79,0:39:09.90,EN,,0,0,0,,here's a general kind of expression, Dialogue: 0,0:39:09.98,0:39:11.40,EN,,0,0,0,,like how to square something, Dialogue: 0,0:39:12.03,0:39:14.20,EN,,0,0,0,,almost anything that you would call a procedure. Dialogue: 0,0:39:14.88,0:39:15.88,EN,,0,0,0,,If that's got to have parts, Dialogue: 0,0:39:15.90,0:39:17.24,EN,,0,0,0,,you have to unwind those parts. Dialogue: 0,0:39:18.02,0:39:20.19,EN,,0,0,0,,You have to have some kind of organization which says Dialogue: 0,0:39:20.57,0:39:24.03,EN,,0,0,0,,when I look at the abstract variables or tags Dialogue: 0,0:39:24.06,0:39:27.10,EN,,0,0,0,,or whatever you want to call them that might stand for particular things, Dialogue: 0,0:39:28.33,0:39:29.34,EN,,0,0,0,,you have to keep track of that, Dialogue: 0,0:39:29.39,0:39:30.91,EN,,0,0,0,,and that's going to be something like an environment. Dialogue: 0,0:39:31.72,0:39:32.54,EN,,0,0,0,,And then if you say Dialogue: 0,0:39:32.70,0:39:35.26,EN,,0,0,0,,this part can have parts which I have to unwind, Dialogue: 0,0:39:35.80,0:39:37.44,EN,,0,0,0,,you've got to have something like this cycle. Dialogue: 0,0:39:39.97,0:39:43.20,EN,,0,0,0,,And lots and lots of languages have that character Dialogue: 0,0:39:43.36,0:39:45.40,EN,,0,0,0,,as long ... when they sort of get put together in this way. Dialogue: 0,0:39:45.59,0:39:47.20,EN,,0,0,0,,This language again really is different Dialogue: 0,0:39:47.21,0:39:49.50,EN,,0,0,0,,because there's nothing like procedures on the outside. Dialogue: 0,0:39:50.69,0:39:52.68,EN,,0,0,0,,When you go below the surface and you see the implementation, Dialogue: 0,0:39:52.70,0:39:54.24,EN,,0,0,0,,of course, it starts looking the same. Dialogue: 0,0:39:54.87,0:39:56.95,EN,,0,0,0,,But from the outside, it's a very different world view. Dialogue: 0,0:39:56.95,0:39:58.54,EN,,0,0,0,,You're not computing functions of inputs. Dialogue: 0,0:40:03.97,0:40:05.71,EN,,0,0,0,,AUDIENCE: You mentioned earlier that Dialogue: 0,0:40:06.60,0:40:09.55,EN,,0,0,0,,when you build all of these rules in pattern matcher Dialogue: 0,0:40:10.01,0:40:11.42,EN,,0,0,0,,and with the delayed action of streams, Dialogue: 0,0:40:11.45,0:40:12.72,EN,,0,0,0,,you really have no way to know Dialogue: 0,0:40:13.37,0:40:15.36,EN,,0,0,0,,in what order things are evaluated. Dialogue: 0,0:40:15.58,0:40:15.94,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:40:15.94,0:40:18.28,EN,,0,0,0,,AUDIENCE: And that would indicate then that Dialogue: 0,0:40:18.94,0:40:22.28,EN,,0,0,0,,you should only express declarative knowledge that's true for all-time, Dialogue: 0,0:40:22.30,0:40:23.79,EN,,0,0,0,,no-time sequence built into it. Dialogue: 0,0:40:23.95,0:40:25.47,EN,,0,0,0,,Otherwise, these things get all-- Dialogue: 0,0:40:27.39,0:40:28.76,EN,,0,0,0,,PROFESSOR: Yes. Yes. Dialogue: 0,0:40:28.82,0:40:29.48,EN,,0,0,0,,The question is Dialogue: 0,0:40:30.06,0:40:32.60,EN,,0,0,0,,this really is set up for doing declarative knowledge, Dialogue: 0,0:40:33.26,0:40:34.81,EN,,0,0,0,,and as I presented it-- no Dialogue: 0,0:40:35.71,0:40:39.56,EN,,0,0,0,,and I'll show you some of the ugly warts under this after the break. Dialogue: 0,0:40:40.83,0:40:42.60,EN,,0,0,0,,As I presented it, it's just doing logic. Dialogue: 0,0:40:43.07,0:40:44.52,EN,,0,0,0,,And in principle, if it were logic, Dialogue: 0,0:40:44.54,0:40:46.81,EN,,0,0,0,,it wouldn't matter what order it's getting done. Dialogue: 0,0:40:48.84,0:40:51.55,EN,,0,0,0,,And it's quite true Dialogue: 0,0:40:51.60,0:40:53.61,EN,,0,0,0,,when you start doing things where you have side effects Dialogue: 0,0:40:53.68,0:40:55.20,EN,,0,0,0,,like adding things to the database Dialogue: 0,0:40:55.23,0:40:58.16,EN,,0,0,0,,and taking things out, and we'll see some others, Dialogue: 0,0:40:58.75,0:41:00.83,EN,,0,0,0,,you loose that kind of control. Dialogue: 0,0:41:01.29,0:41:02.94,EN,,0,0,0,,So, for example, contrasting with Prolog. Dialogue: 0,0:41:02.94,0:41:05.15,EN,,0,0,0,,Say Prolog has various features Dialogue: 0,0:41:05.16,0:41:07.79,EN,,0,0,0,,where you really exploit the order of evaluation. Dialogue: 0,0:41:09.64,0:41:11.77,EN,,0,0,0,,And people write Prolog programs that way. Dialogue: 0,0:41:11.77,0:41:14.04,EN,,0,0,0,,That turns out to be very complicated in Prolog, Dialogue: 0,0:41:14.32,0:41:17.55,EN,,0,0,0,,although if you're an expert Prolog programmer, you can do it. Dialogue: 0,0:41:18.59,0:41:20.21,EN,,0,0,0,,However, here I don't think you can do it at all. Dialogue: 0,0:41:20.21,0:41:21.24,EN,,0,0,0,,It's very complicated Dialogue: 0,0:41:21.72,0:41:23.64,EN,,0,0,0,,because you really are giving up control over Dialogue: 0,0:41:23.77,0:41:25.72,EN,,0,0,0,,any prearranged order of trying things. Dialogue: 0,0:41:27.15,0:41:30.16,EN,,0,0,0,,AUDIENCE: Now, that would indicate then that you have a functional mapping. Dialogue: 0,0:41:30.67,0:41:32.51,EN,,0,0,0,,And when you started out this lecture, Dialogue: 0,0:41:32.99,0:41:34.08,EN,,0,0,0,,you said that Dialogue: 0,0:41:34.67,0:41:36.70,EN,,0,0,0,,we express the declarative knowledge which is a relation, Dialogue: 0,0:41:37.15,0:41:38.81,EN,,0,0,0,,and we don't talk about the inputs and the outputs. Dialogue: 0,0:41:41.21,0:41:43.37,EN,,0,0,0,,PROFESSOR: Well, there's a pun on functional, right? Dialogue: 0,0:41:43.37,0:41:45.79,EN,,0,0,0,,There's functional in the sense of no side effects Dialogue: 0,0:41:46.20,0:41:48.16,EN,,0,0,0,,and not depending on what order is going on. Dialogue: 0,0:41:48.70,0:41:51.04,EN,,0,0,0,,And then there's functional in the sense of mathematical function, Dialogue: 0,0:41:51.07,0:41:52.22,EN,,0,0,0,,which means input and output. Dialogue: 0,0:41:52.59,0:41:54.36,EN,,0,0,0,,And it's just that pun that you're making, I think. Dialogue: 0,0:41:56.51,0:41:58.51,EN,,0,0,0,,AUDIENCE: I'm a little unclear on what you're doing with Dialogue: 0,0:41:58.81,0:42:00.70,EN,,0,0,0,,two statements, the two boss statements. Dialogue: 0,0:42:01.27,0:42:05.74,EN,,0,0,0,,Is the first one building up the database Dialogue: 0,0:42:05.76,0:42:08.08,EN,,0,0,0,,and the second one a query or-- Dialogue: 0,0:42:09.07,0:42:10.12,EN,,0,0,0,,PROFESSOR: OK, I'm sorry. Dialogue: 0,0:42:12.44,0:42:15.16,EN,,0,0,0,,What I meant here, if I type something like this in as a query-- Dialogue: 0,0:42:16.12,0:42:18.44,EN,,0,0,0,,I should have given an example way at the very beginning. Dialogue: 0,0:42:19.47,0:42:23.52,EN,,0,0,0,,If I type in job, Ben Bitdiddle, computer wizard, Dialogue: 0,0:42:25.04,0:42:27.77,EN,,0,0,0,,what the processing will do is if it finds a match, Dialogue: 0,0:42:28.30,0:42:30.28,EN,,0,0,0,,it'll find a match to that exact thing, Dialogue: 0,0:42:30.86,0:42:33.28,EN,,0,0,0,,and it'll type out a job, Ben Bitdiddle, computer wizard. Dialogue: 0,0:42:34.22,0:42:35.60,EN,,0,0,0,,If it doesn't find a match, Dialogue: 0,0:42:35.69,0:42:36.75,EN,,0,0,0,,it won't find anything. Dialogue: 0,0:42:37.40,0:42:39.55,EN,,0,0,0,,So what I should have said is the way Dialogue: 0,0:42:39.56,0:42:42.27,EN,,0,0,0,,you use the query language to check whether something is true, Dialogue: 0,0:42:43.40,0:42:45.77,EN,,0,0,0,,that's one of the things you want to do in logic programming, Dialogue: 0,0:42:46.41,0:42:49.34,EN,,0,0,0,,is you type in your query and either that comes out or it doesn't. Dialogue: 0,0:42:50.68,0:42:52.38,EN,,0,0,0,,So what I was trying to illustrate here, Dialogue: 0,0:42:52.41,0:42:54.80,EN,,0,0,0,,I wanted to start with a very simple example Dialogue: 0,0:42:54.83,0:42:56.62,EN,,0,0,0,,before talking about unifiers. Dialogue: 0,0:42:57.48,0:42:58.11,EN,,0,0,0,,So what I should have said, Dialogue: 0,0:42:58.14,0:43:00.96,EN,,0,0,0,,if I just wanted to check whether this is true, Dialogue: 0,0:43:01.18,0:43:03.28,EN,,0,0,0,,I could type that in and see if anything came out Dialogue: 0,0:43:05.16,0:43:06.27,EN,,0,0,0,,AUDIENCE: And then the second one-- Dialogue: 0,0:43:06.28,0:43:07.84,EN,,0,0,0,,PROFESSOR: The second one would be a real query. Dialogue: 0,0:43:07.88,0:43:09.12,EN,,0,0,0,,AUDIENCE: A real query, yeah. Dialogue: 0,0:43:10.77,0:43:13.10,EN,,0,0,0,,PROFESSOR: What would come out, see, it would go in here say with WHO, Dialogue: 0,0:43:13.90,0:43:15.74,EN,,0,0,0,,and in would go frame that says z Dialogue: 0,0:43:16.62,0:43:18.81,EN,,0,0,0,,z is bound to who and d is bound to computer. Dialogue: 0,0:43:19.56,0:43:20.49,EN,,0,0,0,,And this will pass through, Dialogue: 0,0:43:20.51,0:43:21.95,EN,,0,0,0,,and then by the time it got out of here, Dialogue: 0,0:43:22.01,0:43:23.25,EN,,0,0,0,,who would pick up a binding. Dialogue: 0,0:43:26.95,0:43:28.76,EN,,0,0,0,,AUDIENCE: On the unifying thing there, Dialogue: 0,0:43:29.18,0:43:35.96,EN,,0,0,0,,I still am not sure what happens with who and z. Dialogue: 0,0:43:36.46,0:43:39.58,EN,,0,0,0,,OK being unifying-- the rule here says-- Dialogue: 0,0:43:42.03,0:43:46.22,EN,,0,0,0,,OK, so you say that you can't make question mark equal to question mark who. Dialogue: 0,0:43:46.26,0:43:48.08,EN,,0,0,0,,PROFESSOR: Right. That's what the matcher can't do. Dialogue: 0,0:43:48.36,0:43:50.83,EN,,0,0,0,,But unifier, what this will mean to a unifier Dialogue: 0,0:43:51.92,0:43:54.01,EN,,0,0,0,,is that there's an environment with three variables. Dialogue: 0,0:43:56.69,0:43:57.90,EN,,0,0,0,,d here is computer. Dialogue: 0,0:43:58.52,0:44:00.19,EN,,0,0,0,,z is whatever who is. Dialogue: 0,0:44:01.83,0:44:05.26,EN,,0,0,0,,So if later on in the matcher routine Dialogue: 0,0:44:07.20,0:44:10.38,EN,,0,0,0,,it said, for example, who has to be 3, Dialogue: 0,0:44:12.06,0:44:13.66,EN,,0,0,0,,then when I looked up in the dictionary, Dialogue: 0,0:44:14.00,0:44:16.40,EN,,0,0,0,,it will say, oh, z is 3 because it's the same as who. Dialogue: 0,0:44:18.36,0:44:20.44,EN,,0,0,0,,And that's in some sense the only thing you need to do Dialogue: 0,0:44:20.46,0:44:21.98,EN,,0,0,0,,to extend the unifier to a matcher. Dialogue: 0,0:44:22.48,0:44:24.80,EN,,0,0,0,,AUDIENCE: OK, because it looked like when you were telling how to unify, Dialogue: 0,0:44:24.83,0:44:26.96,EN,,0,0,0,,it looked like you would put the things together in such a way Dialogue: 0,0:44:26.99,0:44:29.23,EN,,0,0,0,,that you'd actually solve and have a value for both of them. Dialogue: 0,0:44:29.77,0:44:31.24,EN,,0,0,0,,And what it looks like now Dialogue: 0,0:44:31.28,0:44:32.83,EN,,0,0,0,,is that you're actually pass a dictionary Dialogue: 0,0:44:32.88,0:44:34.86,EN,,0,0,0,,with two variables and the variables are linked. Dialogue: 0,0:44:34.88,0:44:37.23,EN,,0,0,0,,PROFESSOR: Right. It only looks like you're solving for both of them Dialogue: 0,0:44:37.52,0:44:39.74,EN,,0,0,0,,because you're sort of looking at the whole solution at once. Dialogue: 0,0:44:40.54,0:44:42.81,EN,,0,0,0,,If you sort of watch the thing getting built up recursively, Dialogue: 0,0:44:42.81,0:44:43.74,EN,,0,0,0,,it's merely this. Dialogue: 0,0:44:44.98,0:44:48.40,EN,,0,0,0,,AUDIENCE: OK, so you do pass off that dictionary with two variables? Dialogue: 0,0:44:48.40,0:44:49.11,EN,,0,0,0,,PROFESSOR: That's right. Dialogue: 0,0:44:49.11,0:44:49.68,EN,,0,0,0,,AUDIENCE: And link? Dialogue: 0,0:44:50.38,0:44:52.91,EN,,0,0,0,,PROFESSOR: Right. It just looks like an ordinary dictionary. Dialogue: 0,0:44:54.35,0:44:56.06,EN,,0,0,0,,AUDIENCE: When you're talking about the unifier, Dialogue: 0,0:44:56.09,0:45:00.19,EN,,0,0,0,,is it that there are some cases or some points Dialogue: 0,0:45:00.75,0:45:03.98,EN,,0,0,0,,that you are not able to unify them? Dialogue: 0,0:45:04.03,0:45:04.30,EN,,0,0,0,,PROFESSOR: Right. Dialogue: 0,0:45:04.97,0:45:08.46,EN,,0,0,0,,AUDIENCE: Can you just by building the rules or Dialogue: 0,0:45:09.16,0:45:15.93,EN,,0,0,0,,writing the forms know in advance if you are going to be able to solve Dialogue: 0,0:45:16.48,0:45:18.54,EN,,0,0,0,,to get the unification or not? Dialogue: 0,0:45:18.76,0:45:22.94,EN,,0,0,0,,Can you add some properties either to the rules itself Dialogue: 0,0:45:23.18,0:45:25.45,EN,,0,0,0,,or to the form that you're writing Dialogue: 0,0:45:25.82,0:45:29.04,EN,,0,0,0,,so that you avoid the problem of not finding unification? Dialogue: 0,0:45:29.18,0:45:31.15,EN,,0,0,0,,Well I mean, you can agree, Dialogue: 0,0:45:31.47,0:45:35.26,EN,,0,0,0,,I think, to write in a fairly restricted way where you won't run into it. Dialogue: 0,0:45:35.60,0:45:36.67,EN,,0,0,0,,See, because what you're getting-- Dialogue: 0,0:45:36.88,0:45:39.12,EN,,0,0,0,,see, the place where you get into problems is when you-- Dialogue: 0,0:45:39.68,0:45:44.25,EN,,0,0,0,,well, again, you're trying to match things like that Dialogue: 0,0:45:44.59,0:45:47.20,EN,,0,0,0,,against things where these have structure, Dialogue: 0,0:45:47.55,0:45:55.30,EN,,0,0,0,,where a, y, b, y something. Dialogue: 0,0:45:58.98,0:46:01.48,EN,,0,0,0,,So this is the kind of place where you're going to get into trouble. Dialogue: 0,0:46:03.07,0:46:05.80,EN,,0,0,0,,AUDIENCE: So you can do that syntactically? Dialogue: 0,0:46:06.14,0:46:08.76,EN,,0,0,0,,PROFESSOR: So you can kind of watch your rules Dialogue: 0,0:46:08.76,0:46:10.49,EN,,0,0,0,,in the kinds of things that your writing. Dialogue: 0,0:46:11.90,0:46:14.08,EN,,0,0,0,,AUDIENCE: So that's the problem that the builder Dialogue: 0,0:46:14.11,0:46:16.27,EN,,0,0,0,,of the database has to be concerned? Dialogue: 0,0:46:16.57,0:46:17.80,EN,,0,0,0,,PROFESSOR: That's a problem. Dialogue: 0,0:46:19.93,0:46:22.01,EN,,0,0,0,,It's a problem either-- not quite the builder of the database, Dialogue: 0,0:46:22.04,0:46:23.61,EN,,0,0,0,,the person who is expressing the rules, Dialogue: 0,0:46:24.01,0:46:25.31,EN,,0,0,0,,or the builder of the database. Dialogue: 0,0:46:25.80,0:46:29.79,EN,,0,0,0,,What the unifier actually does is you can check at the next level down Dialogue: 0,0:46:29.92,0:46:31.87,EN,,0,0,0,,when you actually get to the unifier Dialogue: 0,0:46:32.41,0:46:34.76,EN,,0,0,0,,and you'll see in the code where it looks up in the dictionary. Dialogue: 0,0:46:34.94,0:46:36.83,EN,,0,0,0,,If it sort of says what does y have to be? Dialogue: 0,0:46:37.26,0:46:41.42,EN,,0,0,0,,Oh, does y have to be something that contains a y as its expression? Dialogue: 0,0:46:41.96,0:46:43.26,EN,,0,0,0,,At that point, the unifier and say, Dialogue: 0,0:46:43.28,0:46:46.24,EN,,0,0,0,,oh my God, I'm trying to solve a fixed-point equation. Dialogue: 0,0:46:46.24,0:46:46.99,EN,,0,0,0,,I'll give it up here. Dialogue: 0,0:46:48.59,0:46:51.91,EN,,0,0,0,,AUDIENCE: You make the distinction between the rules in the database. Dialogue: 0,0:46:51.91,0:46:56.48,EN,,0,0,0,,Are the rules added to the database? Dialogue: 0,0:46:56.95,0:46:57.36,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,0:46:57.87,0:46:58.87,EN,,0,0,0,,Yes, I should have said that. Dialogue: 0,0:46:58.87,0:47:00.33,EN,,0,0,0,,One way to think about rules Dialogue: 0,0:47:00.60,0:47:02.65,EN,,0,0,0,,is that they're just other things in the database. Dialogue: 0,0:47:03.71,0:47:06.81,EN,,0,0,0,,So if you want to check the things that have to be checked in the database, Dialogue: 0,0:47:06.83,0:47:09.44,EN,,0,0,0,,they're kind of virtual facts that are in the database. Dialogue: 0,0:47:09.44,0:47:12.32,EN,,0,0,0,,AUDIENCE: But in that explanation, you made the differentiation Dialogue: 0,0:47:12.43,0:47:17.26,EN,,0,0,0,,between database and the rules itself. Dialogue: 0,0:47:18.23,0:47:19.90,EN,,0,0,0,,PROFESSOR: Yeah, I probably should not have done that. Dialogue: 0,0:47:20.49,0:47:23.31,EN,,0,0,0,,The only reason to do that is in terms of the implementation. Dialogue: 0,0:47:23.54,0:47:24.67,EN,,0,0,0,,When you look at the implementation, Dialogue: 0,0:47:24.68,0:47:27.50,EN,,0,0,0,,there's a part which says check either primitive Dialogue: 0,0:47:27.55,0:47:29.85,EN,,0,0,0,,assertions in the database or check rules. Dialogue: 0,0:47:30.47,0:47:32.72,EN,,0,0,0,,And then the real reason, the real reason why Dialogue: 0,0:47:32.78,0:47:34.56,EN,,0,0,0,,you can't tell what order things are going to come out in Dialogue: 0,0:47:34.96,0:47:40.46,EN,,0,0,0,,is that the rules database and the data database Dialogue: 0,0:47:40.48,0:47:43.68,EN,,0,0,0,,sort of get merged in a kind of delayed evaluation way. Dialogue: 0,0:47:44.60,0:47:46.80,EN,,0,0,0,,And so that's what makes the order very complicated. Dialogue: 0,0:47:55.44,0:47:56.09,EN,,0,0,0,,OK, let's break. Dialogue: 0,0:47:56.30,0:48:09.90,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:48:10.04,0:48:14.41,EN,,0,0,0,, Dialogue: 0,0:48:18.68,0:48:22.09,EN,,0,0,0,, Dialogue: 0,0:48:22.09,0:48:25.96,EN,,0,0,0,, Dialogue: 0,0:48:26.00,0:48:29.87,EN,,0,0,0,, Dialogue: 0,0:48:33.16,0:48:35.37,EN,,0,0,0,,We've just seen how the logic language works Dialogue: 0,0:48:35.39,0:48:36.41,EN,,0,0,0,,and how rules work. Dialogue: 0,0:48:37.23,0:48:39.37,EN,,0,0,0,,Now, let's turn to a more profound question. Dialogue: 0,0:48:40.12,0:48:41.28,EN,,0,0,0,,What do these things mean? Dialogue: 0,0:48:43.18,0:48:46.86,EN,,0,0,0,,That brings us to the subtlest, most devious part Dialogue: 0,0:48:46.99,0:48:48.67,EN,,0,0,0,,of this whole query language business, Dialogue: 0,0:48:49.21,0:48:53.07,EN,,0,0,0,,and that is that it's not quite what it seems to be. Dialogue: 0,0:48:53.57,0:48:56.22,EN,,0,0,0,,AND and OR and NOT Dialogue: 0,0:48:57.02,0:48:58.88,EN,,0,0,0,,and the logical implication of rules Dialogue: 0,0:48:59.69,0:49:06.64,EN,,0,0,0,,are not really the AND and OR and NOT and logical implication of logic. Dialogue: 0,0:49:07.69,0:49:09.71,EN,,0,0,0,,Let me give you an example of that. Dialogue: 0,0:49:09.91,0:49:12.22,EN,,0,0,0,,Certainly, if we have two things in logic, Dialogue: 0,0:49:12.40,0:49:19.44,EN,,0,0,0,,it ought to be the case that AND of P and Q Dialogue: 0,0:49:20.00,0:49:22.59,EN,,0,0,0,,is the same as AND of Q and P Dialogue: 0,0:49:23.10,0:49:24.51,EN,,0,0,0,,and that OR of P and Q Dialogue: 0,0:49:24.78,0:49:26.51,EN,,0,0,0,,is the same as OR of Q and P. Dialogue: 0,0:49:28.67,0:49:30.09,EN,,0,0,0,,But let's look here. Dialogue: 0,0:49:30.10,0:49:32.01,EN,,0,0,0,,Here's an example. Dialogue: 0,0:49:32.18,0:49:36.16,EN,,0,0,0,,Let's talk about somebody outranking somebody else Dialogue: 0,0:49:36.28,0:49:40.14,EN,,0,0,0,,in this our little database organization. Dialogue: 0,0:49:40.14,0:49:42.89,EN,,0,0,0,,We'll say s is outranked by b Dialogue: 0,0:49:44.64,0:49:48.62,EN,,0,0,0,,if or if either the supervisor of s is b Dialogue: 0,0:49:49.63,0:49:51.07,EN,,0,0,0,,or there's some middle manager here, Dialogue: 0,0:49:51.10,0:49:55.82,EN,,0,0,0,,that supervisor of s is m, and m is outranked by b. Dialogue: 0,0:49:59.64,0:50:02.31,EN,,0,0,0,,So there's one way to define rule outranked by. Dialogue: 0,0:50:02.31,0:50:04.16,EN,,0,0,0,,Or we can write exactly the same thing, Dialogue: 0,0:50:05.08,0:50:06.91,EN,,0,0,0,,except at the bottom here, Dialogue: 0,0:50:07.21,0:50:09.88,EN,,0,0,0,,we reversed the order of these two clauses. Dialogue: 0,0:50:11.63,0:50:12.99,EN,,0,0,0,,And certainly if this were logic, Dialogue: 0,0:50:13.00,0:50:14.88,EN,,0,0,0,,those ought to mean the same thing. Dialogue: 0,0:50:16.69,0:50:17.31,EN,,0,0,0,,However, Dialogue: 0,0:50:17.71,0:50:19.61,EN,,0,0,0,,in our particular implementation, Dialogue: 0,0:50:19.64,0:50:22.88,EN,,0,0,0,,if you say something like who's outranked by Ben Bitdiddle, Dialogue: 0,0:50:23.48,0:50:25.36,EN,,0,0,0,,what you'll find is that this rule Dialogue: 0,0:50:26.76,0:50:28.72,EN,,0,0,0,,will work perfectly well and generate answers, Dialogue: 0,0:50:30.04,0:50:31.98,EN,,0,0,0,,whereas this rule will go into an infinite loop. Dialogue: 0,0:50:34.11,0:50:36.27,EN,,0,0,0,,And the reason for that is that Dialogue: 0,0:50:36.33,0:50:40.33,EN,,0,0,0,,this will come in and say, oh, who's outranked by Ben Bitdiddle? Dialogue: 0,0:50:41.92,0:50:43.53,EN,,0,0,0,,Find an s, find an s Dialogue: 0,0:50:43.88,0:50:46.22,EN,,0,0,0,,which is outranked by b, where b is Ben Bitdiddle, Dialogue: 0,0:50:47.50,0:50:49.63,EN,,0,0,0,,which is going to happen in it a subproblem. Dialogue: 0,0:50:50.33,0:50:51.98,EN,,0,0,0,,Oh gee, find an m Dialogue: 0,0:50:52.24,0:50:54.57,EN,,0,0,0,,such as m is outranked by Ben Bitdiddle Dialogue: 0,0:50:55.61,0:50:57.36,EN,,0,0,0,,with no restrictions on m. Dialogue: 0,0:50:58.56,0:51:00.40,EN,,0,0,0,,So this will say in order to solve this problem, Dialogue: 0,0:51:01.42,0:51:03.29,EN,,0,0,0,,I solve exactly the same problem. Dialogue: 0,0:51:04.57,0:51:07.23,EN,,0,0,0,,And then after I've solved that, I'll check for a supervisory relationship. Dialogue: 0,0:51:08.00,0:51:09.16,EN,,0,0,0,,Whereas this one won't get into that, Dialogue: 0,0:51:09.18,0:51:12.35,EN,,0,0,0,,because before it tries to find this outranked by, Dialogue: 0,0:51:12.94,0:51:15.26,EN,,0,0,0,,it'll already have had a restriction on m here. Dialogue: 0,0:51:18.38,0:51:20.94,EN,,0,0,0,,So these two things which ought to mean the same, Dialogue: 0,0:51:20.99,0:51:22.67,EN,,0,0,0,,in fact, one goes into an infinite loop. Dialogue: 0,0:51:22.86,0:51:25.04,EN,,0,0,0,,One goes, one does not. Dialogue: 0,0:51:26.72,0:51:29.77,EN,,0,0,0,,That's a very extreme case Dialogue: 0,0:51:29.79,0:51:32.65,EN,,0,0,0,,of a general thing that you'll find in logic programming that Dialogue: 0,0:51:34.28,0:51:38.70,EN,,0,0,0,,if you start changing the order of the things in the ANDs or ORs, Dialogue: 0,0:51:39.34,0:51:41.58,EN,,0,0,0,,you'll find tremendous differences in efficiency. Dialogue: 0,0:51:42.24,0:51:43.21,EN,,0,0,0,,And we just saw Dialogue: 0,0:51:43.55,0:51:46.54,EN,,0,0,0,,an infinitely big difference in efficiency and an infinite loop. Dialogue: 0,0:51:49.19,0:51:51.74,EN,,0,0,0,,And there are similar things having to do order Dialogue: 0,0:51:52.00,0:51:53.31,EN,,0,0,0,,in which you enter rules. Dialogue: 0,0:51:54.07,0:51:56.48,EN,,0,0,0,,The order in which it happens to look at rules in the database Dialogue: 0,0:51:56.70,0:51:59.95,EN,,0,0,0,,may vastly change the efficiency with which it gets out answers or, Dialogue: 0,0:52:00.46,0:52:02.60,EN,,0,0,0,,in fact, send it into an infinite loop for some orderings. Dialogue: 0,0:52:03.84,0:52:07.29,EN,,0,0,0,,And this whole thing has to do Dialogue: 0,0:52:07.63,0:52:10.04,EN,,0,0,0,,the fact that you're checking these rules in some order. Dialogue: 0,0:52:10.95,0:52:14.41,EN,,0,0,0,,And some rules may lead to really long paths of implication. Dialogue: 0,0:52:14.44,0:52:16.06,EN,,0,0,0,,Others might, others might not. Dialogue: 0,0:52:16.44,0:52:17.68,EN,,0,0,0,,And you don't know a priori Dialogue: 0,0:52:17.72,0:52:19.16,EN,,0,0,0,,which ones are good and which ones are bad. Dialogue: 0,0:52:19.30,0:52:21.48,EN,,0,0,0,,And there's a whole bunch of research having to do with that, Dialogue: 0,0:52:22.16,0:52:23.76,EN,,0,0,0,,mostly having to do with thinking about Dialogue: 0,0:52:23.95,0:52:26.97,EN,,0,0,0,,making parallel implementations of logic programming languages. Dialogue: 0,0:52:27.32,0:52:29.90,EN,,0,0,0,,And in some sense, what you'd like to do is check all rules in parallel Dialogue: 0,0:52:30.36,0:52:32.80,EN,,0,0,0,,and whichever ones get answers, you bubble them up. And Dialogue: 0,0:52:33.04,0:52:34.99,EN,,0,0,0,,if some go down infinite deductive chain, Dialogue: 0,0:52:35.02,0:52:38.25,EN,,0,0,0,,well, you just-- you know, memory is cheap and processors are cheap, Dialogue: 0,0:52:38.28,0:52:40.49,EN,,0,0,0,,you just let them buzz for as for as long as you want. Dialogue: 0,0:52:43.47,0:52:44.83,EN,,0,0,0,,There's a deeper problem, though, Dialogue: 0,0:52:45.18,0:52:50.49,EN,,0,0,0,,in comparing this logic language to real logic. Dialogue: 0,0:52:50.68,0:52:52.52,EN,,0,0,0,,The example I just showed you, it Dialogue: 0,0:52:52.97,0:52:54.80,EN,,0,0,0,,went into an infinite loop maybe, Dialogue: 0,0:52:55.37,0:52:56.99,EN,,0,0,0,,but at least it didn't give the wrong answer. Dialogue: 0,0:52:58.37,0:53:03.64,EN,,0,0,0,,There's an actual deeper problem when we start comparing, Dialogue: 0,0:53:03.68,0:53:05.24,EN,,0,0,0,,you know, seriously comparing Dialogue: 0,0:53:05.71,0:53:08.46,EN,,0,0,0,,this logic language with real classical logic. Dialogue: 0,0:53:09.49,0:53:12.43,EN,,0,0,0,,So let's sort of review real classical logic. Dialogue: 0,0:53:13.71,0:53:21.04,EN,,0,0,0,,All humans are mortal. Dialogue: 0,0:53:22.35,0:53:23.45,EN,,0,0,0,,That's pretty classical logic. Dialogue: 0,0:53:24.39,0:53:28.67,EN,,0,0,0,,Then maybe we'll continue in the very best classical tradition. Dialogue: 0,0:53:29.24,0:53:32.46,EN,,0,0,0,,We'll say all-- let's make it really classical. Dialogue: 0,0:53:32.67,0:53:37.16,EN,,0,0,0,,All Greeks are human, Dialogue: 0,0:53:40.49,0:53:46.06,EN,,0,0,0,,which has the syllogism that Socrates is a Greek. Dialogue: 0,0:53:48.17,0:53:49.21,EN,,0,0,0,,And then what do you write here? Dialogue: 0,0:53:49.21,0:53:51.89,EN,,0,0,0,,I think three dots, classical logic. Dialogue: 0,0:53:51.89,0:53:54.33,EN,,0,0,0,,Therefore, then the syllogism, Dialogue: 0,0:53:54.64,0:53:59.55,EN,,0,0,0,,Socrates is mortal. Dialogue: 0,0:54:01.36,0:54:04.91,EN,,0,0,0,,So there's some real honest classical logic. Dialogue: 0,0:54:05.88,0:54:11.05,EN,,0,0,0,,Let's compare that with our classical logic database. Dialogue: 0,0:54:12.40,0:54:14.46,EN,,0,0,0,,So here's a classical logic database. Dialogue: 0,0:54:16.27,0:54:17.48,EN,,0,0,0,,Socrates is a Greek. Dialogue: 0,0:54:18.03,0:54:18.84,EN,,0,0,0,,Plato is a Greek. Dialogue: 0,0:54:19.60,0:54:20.40,EN,,0,0,0,,Zeus is a Greek, Dialogue: 0,0:54:20.84,0:54:21.98,EN,,0,0,0,,and Zeus is a god. Dialogue: 0,0:54:24.12,0:54:29.96,EN,,0,0,0,,And all humans are mortal. Dialogue: 0,0:54:30.54,0:54:32.12,EN,,0,0,0,,To show that something is mortal, Dialogue: 0,0:54:32.16,0:54:33.60,EN,,0,0,0,,it's enough to show that it's human. Dialogue: 0,0:54:34.65,0:54:35.90,EN,,0,0,0,,All humans are fallible. Dialogue: 0,0:54:38.90,0:54:40.98,EN,,0,0,0,,And all Greeks are humans is not quite right. Dialogue: 0,0:54:40.98,0:54:44.41,EN,,0,0,0,,This says that all Greeks who are not gods are human. Dialogue: 0,0:54:45.71,0:54:47.04,EN,,0,0,0,,So to show something's human, Dialogue: 0,0:54:47.07,0:54:48.89,EN,,0,0,0,,it's enough to show it's a Greek and not a god. Dialogue: 0,0:54:49.32,0:54:52.88,EN,,0,0,0,,And the address of any Greek god is Mount Olympus. Dialogue: 0,0:54:54.32,0:54:57.16,EN,,0,0,0,,So there's a little classical logic database. Dialogue: 0,0:54:57.39,0:54:59.32,EN,,0,0,0,,And indeed, that would work fairly well. Dialogue: 0,0:54:59.49,0:55:02.09,EN,,0,0,0,,If we type that in and say Dialogue: 0,0:55:03.47,0:55:06.57,EN,,0,0,0,,is Socrates mortal or Socrates fallible or mortal? Dialogue: 0,0:55:06.91,0:55:07.69,EN,,0,0,0,,It'll say yes. Dialogue: 0,0:55:07.77,0:55:09.71,EN,,0,0,0,,Is Plato mortal and fallible. Dialogue: 0,0:55:09.71,0:55:10.24,EN,,0,0,0,,It'll say yes. Dialogue: 0,0:55:10.68,0:55:12.21,EN,,0,0,0,,If we say is Zeus mortal? Dialogue: 0,0:55:12.21,0:55:13.23,EN,,0,0,0,,It won't find anything. Dialogue: 0,0:55:14.90,0:55:15.96,EN,,0,0,0,,And it'll work perfectly well. Dialogue: 0,0:55:16.54,0:55:20.12,EN,,0,0,0,,However, suppose we want to extend this. Dialogue: 0,0:55:20.12,0:55:23.05,EN,,0,0,0,,Let's define what it means for someone to be a perfect being. Dialogue: 0,0:55:23.82,0:55:27.21,EN,,0,0,0,,Let's say rule: a perfect being. Dialogue: 0,0:55:34.05,0:55:35.48,EN,,0,0,0,,And I think this is right. Dialogue: 0,0:55:35.48,0:55:38.14,EN,,0,0,0,,If you're up on your medieval scholastic philosophy, Dialogue: 0,0:55:38.44,0:55:40.17,EN,,0,0,0,,I believe that perfect beings are ones Dialogue: 0,0:55:40.68,0:55:42.65,EN,,0,0,0,,who were neither mortal nor fallible. Dialogue: 0,0:55:44.10,0:55:56.84,EN,,0,0,0,,AND NOT mortal x, NOT fallible x. Dialogue: 0,0:55:59.30,0:56:00.89,EN,,0,0,0,,So we'll define this system Dialogue: 0,0:56:02.67,0:56:04.36,EN,,0,0,0,,to teach it what a perfect being is. Dialogue: 0,0:56:05.79,0:56:07.69,EN,,0,0,0,,And now what we're going to do is Dialogue: 0,0:56:08.06,0:56:10.17,EN,,0,0,0,,ask for the address of all the perfect beings. Dialogue: 0,0:56:11.48,0:56:22.30,EN,,0,0,0,,AND the address of x is y and x is perfect. Dialogue: 0,0:56:23.48,0:56:24.97,EN,,0,0,0,,And so what we're generating here is Dialogue: 0,0:56:24.99,0:56:27.80,EN,,0,0,0,,the world's most exclusive mailing list. Dialogue: 0,0:56:30.16,0:56:32.20,EN,,0,0,0,,For the address of all the perfect beings, Dialogue: 0,0:56:32.24,0:56:33.47,EN,,0,0,0,,we might have typed this in. Dialogue: 0,0:56:33.83,0:56:35.44,EN,,0,0,0,,Or we might type in this. Dialogue: 0,0:56:36.24,0:56:50.57,EN,,0,0,0,,We'll say AND perfect of x and the address of x is y. Dialogue: 0,0:56:52.06,0:56:54.96,EN,,0,0,0,,Well, suppose we type all that in and we try this query. Dialogue: 0,0:56:55.19,0:56:56.76,EN,,0,0,0,,This query is going to give us an answer. Dialogue: 0,0:56:57.65,0:57:00.00,EN,,0,0,0,,This query will say, yeah, Mount Olympus. Dialogue: 0,0:57:04.23,0:57:06.57,EN,,0,0,0,,This query, in fact, is going to give us nothing. Dialogue: 0,0:57:06.74,0:57:09.58,EN,,0,0,0,,It will say no addresses of perfect beings. Dialogue: 0,0:57:11.64,0:57:12.51,EN,,0,0,0,,Now, why is that? Dialogue: 0,0:57:12.51,0:57:13.44,EN,,0,0,0,,Why is there a difference? Dialogue: 0,0:57:14.23,0:57:15.69,EN,,0,0,0,,This is not an infinite loop question. Dialogue: 0,0:57:15.69,0:57:17.08,EN,,0,0,0,,This is a different answer question. Dialogue: 0,0:57:19.48,0:57:20.09,EN,,0,0,0,,The reason is Dialogue: 0,0:57:20.38,0:57:22.32,EN,,0,0,0,,that if you remember the implementation of NOT, Dialogue: 0,0:57:23.50,0:57:24.84,EN,,0,0,0,,NOT acted as a filter. Dialogue: 0,0:57:25.88,0:57:29.00,EN,,0,0,0,,NOT said I'm going to take some possible dictionaries, Dialogue: 0,0:57:29.05,0:57:31.56,EN,,0,0,0,,some possible frames, some possible answers, Dialogue: 0,0:57:31.79,0:57:33.16,EN,,0,0,0,,and filter out the ones Dialogue: 0,0:57:33.29,0:57:34.94,EN,,0,0,0,,that happened to satisfy some condition, Dialogue: 0,0:57:34.97,0:57:36.11,EN,,0,0,0,,and that's how I implement NOT. Dialogue: 0,0:57:36.92,0:57:38.43,EN,,0,0,0,,If you think about what's going on here, Dialogue: 0,0:57:40.11,0:57:42.65,EN,,0,0,0,,I'll build this query box where the address piece Dialogue: 0,0:57:43.32,0:57:47.39,EN,,0,0,0,,the output of an address piece gets fed into a perfect piece. Dialogue: 0,0:57:50.29,0:57:51.00,EN,,0,0,0,,What will happen is Dialogue: 0,0:57:51.32,0:57:53.26,EN,,0,0,0,,the address piece will set up some things of Dialogue: 0,0:57:53.32,0:57:54.83,EN,,0,0,0,,everyone whose address I know. Dialogue: 0,0:57:55.29,0:57:57.64,EN,,0,0,0,,Those will get filtered by the NOTs inside perfect here. Dialogue: 0,0:57:59.88,0:58:04.19,EN,,0,0,0,,So it will throw out the ones which happened to be either mortal or fallible. Dialogue: 0,0:58:04.91,0:58:06.38,EN,,0,0,0,,In the other order what happens Dialogue: 0,0:58:06.73,0:58:09.12,EN,,0,0,0,,is I set this up, started up with an empty frame. Dialogue: 0,0:58:09.52,0:58:12.35,EN,,0,0,0,,The perfect in here doesn't find anything for the NOTs to filter, Dialogue: 0,0:58:12.38,0:58:13.98,EN,,0,0,0,,so nothing comes out here at all. Dialogue: 0,0:58:18.83,0:58:21.50,EN,,0,0,0,,And there's sort of nothing there that gets fed into the address thing. Dialogue: 0,0:58:21.94,0:58:23.15,EN,,0,0,0,,So here, I don't get an answer. Dialogue: 0,0:58:23.93,0:58:27.04,EN,,0,0,0,,And again, the reason for that is NOT isn't generating anything. Dialogue: 0,0:58:27.44,0:58:28.80,EN,,0,0,0,,NOT's only throwing out things. Dialogue: 0,0:58:29.08,0:58:30.51,EN,,0,0,0,,And if I never started up with anything, Dialogue: 0,0:58:30.52,0:58:31.74,EN,,0,0,0,,there's nothing for it to throw out. Dialogue: 0,0:58:32.02,0:58:33.77,EN,,0,0,0,,So out of this thing, I get the wrong answer. Dialogue: 0,0:58:37.20,0:58:37.97,EN,,0,0,0,,How can you fix that? Dialogue: 0,0:58:37.97,0:58:39.07,EN,,0,0,0,,Well, there are ways to fix that. Dialogue: 0,0:58:39.36,0:58:40.91,EN,,0,0,0,,So you might say, well, that's sort of stupid. Dialogue: 0,0:58:41.41,0:58:44.90,EN,,0,0,0,,Why are you just doing all your NOT stuff at the beginning? Dialogue: 0,0:58:44.96,0:58:47.48,EN,,0,0,0,,The right way to implement NOT is to realize Dialogue: 0,0:58:47.84,0:58:50.08,EN,,0,0,0,,that when you have conditions like NOT, Dialogue: 0,0:58:50.33,0:58:52.09,EN,,0,0,0,,you should generate all your answers first, Dialogue: 0,0:58:52.80,0:58:54.97,EN,,0,0,0,,and then with each of these dictionaries pass along Dialogue: 0,0:58:55.52,0:58:57.85,EN,,0,0,0,,Gee, at the very end I'll do filtering. Dialogue: 0,0:58:58.56,0:59:02.01,EN,,0,0,0,,And there are implementations of logic languages that work like that Dialogue: 0,0:59:02.41,0:59:04.05,EN,,0,0,0,,that solve this particular problem. Dialogue: 0,0:59:06.80,0:59:08.97,EN,,0,0,0,,However, there's a more profound problem, Dialogue: 0,0:59:09.60,0:59:11.53,EN,,0,0,0,,which is which one of these is the right answer? Dialogue: 0,0:59:12.53,0:59:14.24,EN,,0,0,0,,Is it Mount Olympus or is it nothing? Dialogue: 0,0:59:15.37,0:59:18.73,EN,,0,0,0,,So you might say it's Mount Olympus, Dialogue: 0,0:59:18.76,0:59:20.73,EN,,0,0,0,,because after all, Zeus is in that database, Dialogue: 0,0:59:22.52,0:59:25.10,EN,,0,0,0,,and Zeus was neither mortal nor fallible. Dialogue: 0,0:59:29.55,0:59:32.44,EN,,0,0,0,,So you might say Zeus wants to satisfy Dialogue: 0,0:59:34.30,0:59:44.03,EN,,0,0,0,,NOT mortal Zeus or NOT fallible Zeus. Dialogue: 0,0:59:44.12,0:59:45.85,EN,,0,0,0,,But let's actually look at that database. Dialogue: 0,0:59:47.92,0:59:48.46,EN,,0,0,0,,Let's look at it. Dialogue: 0,0:59:49.36,0:59:53.24,EN,,0,0,0,,There's no way-- how does it know that Zeus is not fallible? Dialogue: 0,0:59:54.81,0:59:56.11,EN,,0,0,0,,There's nothing in there about that. Dialogue: 0,0:59:57.93,0:59:59.66,EN,,0,0,0,,What's in there is that humans are fallible. Dialogue: 0,1:00:02.16,1:00:04.12,EN,,0,0,0,,How does it know that Zeus is not mortal? Dialogue: 0,1:00:04.48,1:00:05.93,EN,,0,0,0,,There's nothing in there about that. Dialogue: 0,1:00:07.98,1:00:11.00,EN,,0,0,0,,It just said I don't have any rule, which-- Dialogue: 0,1:00:11.68,1:00:14.06,EN,,0,0,0,,see the only way I can deduce something's mortal is if it's human Dialogue: 0,1:00:14.08,1:00:15.68,EN,,0,0,0,,and that's all it really knows about mortal. Dialogue: 0,1:00:16.69,1:00:19.85,EN,,0,0,0,,And in fact, if you remember your classical mythology, Dialogue: 0,1:00:19.87,1:00:23.48,EN,,0,0,0,,you know that the Greek gods were not mortal but fallible. Dialogue: 0,1:00:25.05,1:00:28.65,EN,,0,0,0,,So the answer is not in the rules there. Dialogue: 0,1:00:30.85,1:00:32.10,EN,,0,0,0,,See, why does it deduce that? Dialogue: 0,1:00:34.49,1:00:38.32,EN,,0,0,0,,See, Socrates would certainly not have made this error of logic. Dialogue: 0,1:00:40.08,1:00:42.67,EN,,0,0,0,,What NOT means in this language is not NOT. Dialogue: 0,1:00:43.37,1:00:44.32,EN,,0,0,0,,It's not the NOT of logic. Dialogue: 0,1:00:44.93,1:00:46.40,EN,,0,0,0,,What NOT needs in this language is Dialogue: 0,1:00:47.16,1:00:49.96,EN,,0,0,0,,not deducible from things in the database Dialogue: 0,1:00:50.75,1:00:53.34,EN,,0,0,0,,as opposed to not true. Dialogue: 0,1:00:55.02,1:00:56.30,EN,,0,0,0,,That's a very big difference. Dialogue: 0,1:00:57.30,1:00:58.64,EN,,0,0,0,,Subtle, but big. Dialogue: 0,1:00:59.25,1:01:00.27,EN,,0,0,0,,So, in fact, Dialogue: 0,1:01:00.76,1:01:03.92,EN,,0,0,0,,this is perfectly happy to say not anything that it doesn't know about. Dialogue: 0,1:01:04.68,1:01:06.14,EN,,0,0,0,,So if you ask it is it not true Dialogue: 0,1:01:06.16,1:01:07.83,EN,,0,0,0,,that Zeus likes chocolate ice cream? Dialogue: 0,1:01:07.85,1:01:09.12,EN,,0,0,0,,It will say sure, it's not true. Dialogue: 0,1:01:10.64,1:01:12.51,EN,,0,0,0,,Or anything else or anything it doesn't know about. Dialogue: 0,1:01:12.59,1:01:17.34,EN,,0,0,0,,NOT means not deducible from the things you've told me. Dialogue: 0,1:01:18.28,1:01:22.44,EN,,0,0,0,,In a world where you're identifying not deducible Dialogue: 0,1:01:22.65,1:01:24.00,EN,,0,0,0,,with, in fact, not true, Dialogue: 0,1:01:24.41,1:01:26.30,EN,,0,0,0,,this is called the closed world assumption. Dialogue: 0,1:01:37.37,1:01:38.17,EN,,0,0,0,,closed world assumption. Dialogue: 0,1:01:38.20,1:01:42.38,EN,,0,0,0,,Anything that I cannot deduce from what I know Dialogue: 0,1:01:43.50,1:01:44.36,EN,,0,0,0,,is not true, Dialogue: 0,1:01:46.24,1:01:48.01,EN,,0,0,0,,Right? If I don't know anything about x, Dialogue: 0,1:01:48.22,1:01:49.21,EN,,0,0,0,,the x isn't true. Dialogue: 0,1:01:49.29,1:01:50.33,EN,,0,0,0,,That's very dangerous. Dialogue: 0,1:01:51.29,1:01:52.44,EN,,0,0,0,,From a logical point of view, Dialogue: 0,1:01:52.46,1:01:53.76,EN,,0,0,0,,first of all, it doesn't really makes sense. Dialogue: 0,1:01:54.48,1:01:56.33,EN,,0,0,0,,Because if I don't know anything about x, Dialogue: 0,1:01:58.38,1:01:59.69,EN,,0,0,0,,I'm willing to say not x. Dialogue: 0,1:02:00.24,1:02:03.32,EN,,0,0,0,,But am I willing to say not not x? Dialogue: 0,1:02:03.85,1:02:05.66,EN,,0,0,0,,Well, sure, I don't know anything about that either maybe. Dialogue: 0,1:02:06.47,1:02:08.65,EN,,0,0,0,,So not not x is not necessarily the same as x Dialogue: 0,1:02:09.24,1:02:10.94,EN,,0,0,0,,and so on and so on and so on, so Dialogue: 0,1:02:11.71,1:02:13.93,EN,,0,0,0,,there's some sort of funny bias in there. Dialogue: 0,1:02:15.97,1:02:17.29,EN,,0,0,0,,So that's sort of funny. Dialogue: 0,1:02:17.29,1:02:18.09,EN,,0,0,0,,The second thing, Dialogue: 0,1:02:20.14,1:02:24.12,EN,,0,0,0,,if you start building up real reasoning programs based on this, Dialogue: 0,1:02:24.70,1:02:26.11,EN,,0,0,0,,think how dangerous that is. Dialogue: 0,1:02:27.07,1:02:32.00,EN,,0,0,0,,You're saying I know I'm in a position Dialogue: 0,1:02:32.22,1:02:36.22,EN,,0,0,0,,to deduce everything true that's relevant to this problem. Dialogue: 0,1:02:37.44,1:02:40.78,EN,,0,0,0,,I'm reasoning, and built into my reasoning mechanism Dialogue: 0,1:02:41.23,1:02:44.20,EN,,0,0,0,,is the assumption that anything that I don't know Dialogue: 0,1:02:44.24,1:02:46.27,EN,,0,0,0,,can't possibly be relevant to this problem. Dialogue: 0,1:02:48.44,1:02:53.04,EN,,0,0,0,,Right? There are a lot of big organizations that work like that, right? Dialogue: 0,1:02:53.16,1:02:56.83,EN,,0,0,0,,Most corporate marketing divisions work like that. Dialogue: 0,1:02:56.83,1:02:59.12,EN,,0,0,0,,You know the consequences to that. Dialogue: 0,1:03:00.33,1:03:03.45,EN,,0,0,0,,So it's very dangerous to start really Dialogue: 0,1:03:03.84,1:03:06.25,EN,,0,0,0,,typing in these big logical implication systems Dialogue: 0,1:03:07.05,1:03:09.00,EN,,0,0,0,,and going on what they say, Dialogue: 0,1:03:09.02,1:03:11.28,EN,,0,0,0,,because they have this really limiting assumption built in. Dialogue: 0,1:03:12.60,1:03:14.36,EN,,0,0,0,,So you have to be very, very careful about that. Dialogue: 0,1:03:15.29,1:03:16.28,EN,,0,0,0,,And that's a deep problem. Dialogue: 0,1:03:16.56,1:03:17.82,EN,,0,0,0,,That's not a problem about Dialogue: 0,1:03:18.22,1:03:20.14,EN,,0,0,0,,we can make a little bit cleverer implementation Dialogue: 0,1:03:20.16,1:03:21.85,EN,,0,0,0,,and do the filters and organize the Dialogue: 0,1:03:22.16,1:03:23.84,EN,,0,0,0,,the infinite loops to make them go away. Dialogue: 0,1:03:23.84,1:03:25.08,EN,,0,0,0,,It's a different kind of problem. Dialogue: 0,1:03:25.92,1:03:26.89,EN,,0,0,0,,It's a different semantics. Dialogue: 0,1:03:27.06,1:03:30.51,EN,,0,0,0,,So I think to wrap this up, it's fair to say Dialogue: 0,1:03:31.34,1:03:34.43,EN,,0,0,0,,that logic programming I think is a terrifically exciting idea, Dialogue: 0,1:03:34.60,1:03:37.00,EN,,0,0,0,,the idea that you can bridge this Dialogue: 0,1:03:37.04,1:03:38.78,EN,,0,0,0,,gap from the imperative to the declarative, Dialogue: 0,1:03:39.90,1:03:42.94,EN,,0,0,0,,that you can start talking about relations Dialogue: 0,1:03:43.58,1:03:45.08,EN,,0,0,0,,and really get tremendous power Dialogue: 0,1:03:46.09,1:03:49.48,EN,,0,0,0,,by going above the abstraction of what's my input and what's my output. Dialogue: 0,1:03:50.56,1:03:51.53,EN,,0,0,0,,And linked to logic, Dialogue: 0,1:03:52.46,1:03:56.46,EN,,0,0,0,,the problem is it's a goal that I think has yet to be realized. Dialogue: 0,1:03:58.03,1:04:01.80,EN,,0,0,0,,And probably one of the very most interesting Dialogue: 0,1:04:02.27,1:04:04.41,EN,,0,0,0,,research questions going on now in languages Dialogue: 0,1:04:04.67,1:04:08.28,EN,,0,0,0,,is how do you somehow make a real logic language? Dialogue: 0,1:04:09.46,1:04:11.05,EN,,0,0,0,,And secondly, how do you bridge the gap Dialogue: 0,1:04:11.31,1:04:13.15,EN,,0,0,0,,this world of logic and relations Dialogue: 0,1:04:13.52,1:04:16.43,EN,,0,0,0,,to the worlds of more traditional languages Dialogue: 0,1:04:16.46,1:04:17.98,EN,,0,0,0,,and somehow combine the power of both. Dialogue: 0,1:04:18.88,1:04:19.68,EN,,0,0,0,,OK, let's break. Dialogue: 0,1:04:23.29,1:04:25.29,EN,,0,0,0,,AUDIENCE: Couldn't you solve that last problem Dialogue: 0,1:04:25.29,1:04:27.74,EN,,0,0,0,,by having the extra rules that imply it? Dialogue: 0,1:04:27.96,1:04:29.85,EN,,0,0,0,,The problem here is you have the definition of something, Dialogue: 0,1:04:29.88,1:04:31.82,EN,,0,0,0,,but you don't have the definition of its opposite. Dialogue: 0,1:04:32.08,1:04:33.92,EN,,0,0,0,,If you include in the database something that says Dialogue: 0,1:04:34.14,1:04:36.89,EN,,0,0,0,,uh... something implies mortal x, Dialogue: 0,1:04:36.99,1:04:38.70,EN,,0,0,0,,something else implies not mortal x, Dialogue: 0,1:04:38.75,1:04:40.37,EN,,0,0,0,,haven't you basically solved the problem? Dialogue: 0,1:04:43.37,1:04:44.14,EN,,0,0,0,,PROFESSOR: But the issue is Dialogue: 0,1:04:44.75,1:04:46.38,EN,,0,0,0,,do you put a finite number of those in? Dialogue: 0,1:04:48.65,1:04:53.13,EN,,0,0,0,,AUDIENCE: If things are specified always in pairs-- Dialogue: 0,1:04:53.61,1:04:57.07,EN,,0,0,0,,PROFESSOR: But the question is then what do you do about deduction? Dialogue: 0,1:05:00.20,1:05:02.11,EN,,0,0,0,,See, you can't specify NOTs. Dialogue: 0,1:05:03.40,1:05:04.76,EN,,0,0,0,,But the problem is, in a big system, Dialogue: 0,1:05:04.78,1:05:07.96,EN,,0,0,0,,it turns out that might not be a finite number of things. Dialogue: 0,1:05:12.82,1:05:15.29,EN,,0,0,0,,There are also sort of two issues. Dialogue: 0,1:05:15.29,1:05:16.56,EN,,0,0,0,,Partly it might not be finite. Dialogue: 0,1:05:16.69,1:05:19.39,EN,,0,0,0,,Partly it might be that's not what you want. Dialogue: 0,1:05:21.51,1:05:24.52,EN,,0,0,0,,So a good example would be suppose I want to do connectivity. Dialogue: 0,1:05:25.12,1:05:26.54,EN,,0,0,0,,I want a reason about connectivity. Dialogue: 0,1:05:28.05,1:05:30.38,EN,,0,0,0,,And I'm going to tell you there's four things: Dialogue: 0,1:05:30.40,1:05:33.74,EN,,0,0,0,,a and b and c and d. Dialogue: 0,1:05:35.48,1:05:38.19,EN,,0,0,0,,And I'll tell you a is connected to b Dialogue: 0,1:05:38.64,1:05:41.42,EN,,0,0,0,,and c's connected to d. Dialogue: 0,1:05:43.20,1:05:44.80,EN,,0,0,0,,And now I'll tell you is a connected to d? Dialogue: 0,1:05:45.05,1:05:46.03,EN,,0,0,0,,That's the question. Dialogue: 0,1:05:46.78,1:05:48.52,EN,,0,0,0,,There's an example where I would like Dialogue: 0,1:05:48.70,1:05:50.35,EN,,0,0,0,,something like the closed world assumption. Dialogue: 0,1:05:54.43,1:05:55.66,EN,,0,0,0,,That's a tiny toy, Dialogue: 0,1:05:56.24,1:05:58.30,EN,,0,0,0,,but a lot of times, I want to be able to say something like Dialogue: 0,1:05:58.48,1:06:01.34,EN,,0,0,0,,anything that I haven't told you, assume is not true. Dialogue: 0,1:06:04.26,1:06:06.27,EN,,0,0,0,,So it's not as simple as you only want to put in Dialogue: 0,1:06:06.27,1:06:08.09,EN,,0,0,0,,explicit NOTs all over the place. Dialogue: 0,1:06:09.47,1:06:12.70,EN,,0,0,0,,It's that sometimes it really isn't clear what you even want. Dialogue: 0,1:06:14.15,1:06:17.92,EN,,0,0,0,,That having to specify both everything and not everything is too precise, Dialogue: 0,1:06:17.93,1:06:20.00,EN,,0,0,0,,and then you get down into problems there. Dialogue: 0,1:06:20.96,1:06:22.68,EN,,0,0,0,,But there are a lot of approaches that Dialogue: 0,1:06:23.32,1:06:25.93,EN,,0,0,0,,you know, that explicitly put in NOTs and reason based on that. Dialogue: 0,1:06:26.51,1:06:27.66,EN,,0,0,0,,So it's a very good idea. Dialogue: 0,1:06:28.07,1:06:31.45,EN,,0,0,0,,It's just that then it starts becoming a little cumbersome Dialogue: 0,1:06:31.48,1:06:33.49,EN,,0,0,0,,in the very large problems you'd like to use. Dialogue: 0,1:06:43.46,1:06:45.96,EN,,0,0,0,,AUDIENCE: I'm not sure how directly related to the argument this is, Dialogue: 0,1:06:46.00,1:06:47.98,EN,,0,0,0,,but one of your points was that Dialogue: 0,1:06:48.49,1:06:50.16,EN,,0,0,0,,one of the dangers of the closed world rule is Dialogue: 0,1:06:50.19,1:06:52.06,EN,,0,0,0,,you never really know all the things that are there. Dialogue: 0,1:06:53.44,1:06:55.32,EN,,0,0,0,,You never really know all the parts to it. Dialogue: 0,1:06:55.87,1:06:58.16,EN,,0,0,0,,Isn't that a major problem with any programming? Dialogue: 0,1:06:58.16,1:06:59.64,EN,,0,0,0,,I always write programs where I Dialogue: 0,1:06:59.90,1:07:01.56,EN,,0,0,0,,I assume that I've got all the cases, Dialogue: 0,1:07:01.58,1:07:03.40,EN,,0,0,0,,and so I check for them all or whatever, and i Dialogue: 0,1:07:04.06,1:07:04.99,EN,,0,0,0,,and somewhere down the road, I Dialogue: 0,1:07:05.02,1:07:06.52,EN,,0,0,0,,I find out that I didn't check for one of them. Dialogue: 0,1:07:07.39,1:07:08.54,EN,,0,0,0,,PROFESSOR: Well, sure, it's true. Dialogue: 0,1:07:08.54,1:07:09.76,EN,,0,0,0,,But the problem here is Dialogue: 0,1:07:11.96,1:07:15.47,EN,,0,0,0,,it's that assumption which is the thing that you're making Dialogue: 0,1:07:15.48,1:07:17.34,EN,,0,0,0,,if you believe you're identifying this with logic. Dialogue: 0,1:07:19.60,1:07:20.51,EN,,0,0,0,,So you're quite right. Dialogue: 0,1:07:20.51,1:07:22.22,EN,,0,0,0,,It's a situation you're never in. Dialogue: 0,1:07:22.22,1:07:24.14,EN,,0,0,0,,The problem is if you're starting to believe that Dialogue: 0,1:07:24.17,1:07:25.44,EN,,0,0,0,,what this is doing is logic Dialogue: 0,1:07:26.17,1:07:27.32,EN,,0,0,0,,and you look at the rules you write down Dialogue: 0,1:07:27.34,1:07:28.89,EN,,0,0,0,,and say what can I deduce from them, Dialogue: 0,1:07:29.53,1:07:32.80,EN,,0,0,0,,you have to be very careful to remember that NOT means something else. Dialogue: 0,1:07:33.47,1:07:35.21,EN,,0,0,0,,And it means something else based on an assumption Dialogue: 0,1:07:35.24,1:07:36.70,EN,,0,0,0,,which is probably not true. Dialogue: 0,1:07:39.03,1:07:40.19,EN,,0,0,0,,AUDIENCE: Do I understand you correctly that Dialogue: 0,1:07:40.25,1:07:41.84,EN,,0,0,0,,you cannot fix this problem Dialogue: 0,1:07:42.25,1:07:46.08,EN,,0,0,0,,without killing off all possibilities of inference through altering NOT? Dialogue: 0,1:07:46.54,1:07:49.80,EN,,0,0,0,,PROFESSOR: No, that's not quite right. Dialogue: 0,1:07:52.96,1:07:55.08,EN,,0,0,0,,There are ways to do logic with real NOTs. Dialogue: 0,1:07:56.34,1:07:58.03,EN,,0,0,0,,There are actually ways to do that. Dialogue: 0,1:07:58.54,1:08:00.84,EN,,0,0,0,,But they're very inefficient as far as anybody knows. Dialogue: 0,1:08:01.61,1:08:02.56,EN,,0,0,0,,And they're much more-- Dialogue: 0,1:08:04.09,1:08:06.89,EN,,0,0,0,,they don't-- the, quote, inference in here Dialogue: 0,1:08:07.39,1:08:08.83,EN,,0,0,0,,is built into this unifier Dialogue: 0,1:08:08.91,1:08:11.29,EN,,0,0,0,,and this pattern matching unification algorithm. Dialogue: 0,1:08:11.98,1:08:16.19,EN,,0,0,0,,There are ways to automate real logical reasoning. Dialogue: 0,1:08:16.59,1:08:18.19,EN,,0,0,0,,But it's not based on that, Dialogue: 0,1:08:18.51,1:08:20.73,EN,,0,0,0,,and logic programming languages don't tend to do that Dialogue: 0,1:08:20.75,1:08:23.85,EN,,0,0,0,,because it's very inefficient as far as anybody knows. Dialogue: 0,1:08:29.39,1:08:30.03,EN,,0,0,0,,All right, thank you. ================================================ FILE: Ass/lec9a.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 2346 Active Line: 2352 Video Position: 109459 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:12.03,0:00:14.03,EN,,0,0,0,,Register Machines Dialogue: 0,0:00:17.26,0:00:19.07,EN,,0,0,0,,PROFESSOR: Well, up 'til now, I suppose, Dialogue: 0,0:00:19.32,0:00:23.93,EN,,0,0,0,,we've been learning about a lot of techniques for Dialogue: 0,0:00:24.09,0:00:28.83,EN,,0,0,0,,organizing big programs, symbolic manipulation a bit, Dialogue: 0,0:00:30.84,0:00:35.60,EN,,0,0,0,,some of the technology that you use for establishing languages, Dialogue: 0,0:00:35.63,0:00:36.78,EN,,0,0,0,,one in terms of another, Dialogue: 0,0:00:37.10,0:00:39.92,EN,,0,0,0,,which is used for organizing very large programs. Dialogue: 0,0:00:39.96,0:00:42.30,EN,,0,0,0,,In fact, the nicest programs I know Dialogue: 0,0:00:42.44,0:00:44.43,EN,,0,0,0,,look more like a pile of languages Dialogue: 0,0:00:44.91,0:00:47.96,EN,,0,0,0,,than like a decomposition of a problem into parts. Dialogue: 0,0:00:49.90,0:00:51.45,EN,,0,0,0,,Well, I suppose at this point, Dialogue: 0,0:00:52.08,0:00:53.58,EN,,0,0,0,,there are still, however, a few mysteries Dialogue: 0,0:00:53.61,0:00:55.32,EN,,0,0,0,,about how this sort of stuff works. Dialogue: 0,0:00:56.26,0:00:59.68,EN,,0,0,0,,And so what we'd like to do now is Dialogue: 0,0:01:00.03,0:01:02.60,EN,,0,0,0,,diverge from the plan of Dialogue: 0,0:01:02.96,0:01:05.42,EN,,0,0,0,,telling you how to organize big programs, Dialogue: 0,0:01:05.45,0:01:08.19,EN,,0,0,0,,and rather tell you something about the mechanisms Dialogue: 0,0:01:08.52,0:01:11.71,EN,,0,0,0,,by which these things can be made to work. Dialogue: 0,0:01:12.19,0:01:14.83,EN,,0,0,0,,The main reason for this is Dialogue: 0,0:01:15.80,0:01:17.87,EN,,0,0,0,,demystification, if you will, Dialogue: 0,0:01:18.65,0:01:20.54,EN,,0,0,0,,that we have a lot of mysteries left, Dialogue: 0,0:01:21.08,0:01:25.48,EN,,0,0,0,,like exactly how it is the case that a program is controlled, Dialogue: 0,0:01:26.08,0:01:30.38,EN,,0,0,0,,how a computer knows what the next thing to do is, Dialogue: 0,0:01:30.52,0:01:31.74,EN,,0,0,0,,or something like that. Dialogue: 0,0:01:32.43,0:01:35.56,EN,,0,0,0,,And what I'd like to do now is make that clear to you Dialogue: 0,0:01:35.85,0:01:39.10,EN,,0,0,0,,that even if you've never played with a physical computer before, Dialogue: 0,0:01:39.56,0:01:43.50,EN,,0,0,0,,the mechanism is really very simple, Dialogue: 0,0:01:44.33,0:01:46.35,EN,,0,0,0,,and that you can understand it completely with no trouble. Dialogue: 0,0:01:47.65,0:01:51.24,EN,,0,0,0,,So I'd like to start by imagining that we-- Dialogue: 0,0:01:51.32,0:01:52.91,EN,,0,0,0,,well, the way we're going to do this, by the way, Dialogue: 0,0:01:52.96,0:01:55.80,EN,,0,0,0,,is we're going to take some very simple Lisp programs, Dialogue: 0,0:01:56.54,0:01:58.12,EN,,0,0,0,,very simple Lisp programs, Dialogue: 0,0:01:59.04,0:02:00.62,EN,,0,0,0,,and transform them into hardware. Dialogue: 0,0:02:02.16,0:02:04.16,EN,,0,0,0,,I'm not going to worry about some intermediate step Dialogue: 0,0:02:04.70,0:02:07.45,EN,,0,0,0,,of going through some existing computer machine language Dialogue: 0,0:02:07.47,0:02:09.05,EN,,0,0,0,,and then showing you how that computer works, Dialogue: 0,0:02:09.82,0:02:12.00,EN,,0,0,0,,because that's not as illuminating. Dialogue: 0,0:02:12.75,0:02:14.17,EN,,0,0,0,,So what I'm really going to show you Dialogue: 0,0:02:14.51,0:02:17.48,EN,,0,0,0,,is how a piece of machinery can be built Dialogue: 0,0:02:18.03,0:02:22.04,EN,,0,0,0,,to do a job that you have written down as a program. Dialogue: 0,0:02:22.04,0:02:24.03,EN,,0,0,0,,That program is, in fact, a description of a machine. Dialogue: 0,0:02:25.76,0:02:27.69,EN,,0,0,0,,We're going to start with a very simple program, Dialogue: 0,0:02:28.09,0:02:30.81,EN,,0,0,0,,proceed to show you some simple mechanisms, Dialogue: 0,0:02:31.39,0:02:33.68,EN,,0,0,0,,proceed to a few more complicated programs, Dialogue: 0,0:02:34.30,0:02:37.42,EN,,0,0,0,,and then later show you a not very complicated program, Dialogue: 0,0:02:37.44,0:02:41.23,EN,,0,0,0,,how the evaluator transforms into a piece of hardware. Dialogue: 0,0:02:41.23,0:02:42.06,EN,,0,0,0,,And of course at that point, Dialogue: 0,0:02:42.08,0:02:44.08,EN,,0,0,0,,you have made the universal transition Dialogue: 0,0:02:44.22,0:02:46.88,EN,,0,0,0,,and can execute any program imaginable Dialogue: 0,0:02:47.16,0:02:48.80,EN,,0,0,0,,with a piece of well-defined hardware. Dialogue: 0,0:02:51.72,0:02:52.91,EN,,0,0,0,,Well, let's start up now, Dialogue: 0,0:02:53.05,0:02:55.31,EN,,0,0,0,,give you a real concrete feeling for this sort of thing. Dialogue: 0,0:02:55.44,0:02:57.66,EN,,0,0,0,,Let's start with a very simple program. Dialogue: 0,0:02:59.60,0:03:00.85,EN,,0,0,0,,Here's Euclid's algorithm. Dialogue: 0,0:03:03.88,0:03:07.00,EN,,0,0,0,,It's actually a little bit more modern than Euclid's algorithm. Dialogue: 0,0:03:07.02,0:03:10.09,EN,,0,0,0,,Euclid's algorithm for computing the greatest common divisor of two numbers Dialogue: 0,0:03:10.41,0:03:13.60,EN,,0,0,0,,was invented 350 BC, I think. Dialogue: 0,0:03:14.30,0:03:15.69,EN,,0,0,0,,It's the oldest known algorithm. Dialogue: 0,0:03:19.32,0:03:23.34,EN,,0,0,0,,But here we're going to talk about GCD of A and B, Dialogue: 0,0:03:23.36,0:03:25.61,EN,,0,0,0,,the Greatest Common Divisor or two numbers, A and B. Dialogue: 0,0:03:26.20,0:03:28.91,EN,,0,0,0,,And the algorithm is extremely simple. Dialogue: 0,0:03:29.50,0:03:31.08,EN,,0,0,0,,If B is 0, Dialogue: 0,0:03:34.16,0:03:36.83,EN,,0,0,0,,then the result is going to be A. Dialogue: 0,0:03:37.52,0:03:43.61,EN,,0,0,0,,Otherwise, the result is the GCD of B Dialogue: 0,0:03:44.49,0:03:53.39,EN,,0,0,0,,and the remainder when A is divided by B. Dialogue: 0,0:03:58.53,0:04:01.90,EN,,0,0,0,,So this we have here is a very simple iterative process. Dialogue: 0,0:04:02.03,0:04:04.08,EN,,0,0,0,,This a simple recursive procedure, Dialogue: 0,0:04:04.38,0:04:07.53,EN,,0,0,0,,recursively defined procedure, recursive definition, Dialogue: 0,0:04:07.71,0:04:09.26,EN,,0,0,0,,which yields an iterative process. Dialogue: 0,0:04:09.95,0:04:12.46,EN,,0,0,0,,And the way it works is that every step, Dialogue: 0,0:04:12.80,0:04:15.10,EN,,0,0,0,,it determines whether B was zero. Dialogue: 0,0:04:16.24,0:04:18.80,EN,,0,0,0,,And if B is 0, we got the answer in A. Dialogue: 0,0:04:19.63,0:04:22.46,EN,,0,0,0,,Otherwise, we make another step Dialogue: 0,0:04:22.49,0:04:23.87,EN,,0,0,0,,where A is the old B, Dialogue: 0,0:04:23.88,0:04:27.04,EN,,0,0,0,,and B is the remainder of the old A divided by the old B. Dialogue: 0,0:04:28.76,0:04:29.55,EN,,0,0,0,,Very simple. Dialogue: 0,0:04:31.11,0:04:32.72,EN,,0,0,0,,Now this, I've already told you Dialogue: 0,0:04:32.99,0:04:34.86,EN,,0,0,0,,some of the mechanism by just saying it that way. Dialogue: 0,0:04:34.86,0:04:35.90,EN,,0,0,0,,I said it in time. Dialogue: 0,0:04:36.36,0:04:37.72,EN,,0,0,0,,I said there are certain steps, Dialogue: 0,0:04:38.14,0:04:39.32,EN,,0,0,0,,and that, in fact, Dialogue: 0,0:04:39.52,0:04:40.86,EN,,0,0,0,,one of the things you can see here Dialogue: 0,0:04:41.18,0:04:43.69,EN,,0,0,0,,is that one of the reasons why this is iterative Dialogue: 0,0:04:43.95,0:04:47.68,EN,,0,0,0,,is nothing is needed of the last step to get the answer. Dialogue: 0,0:04:49.44,0:04:55.29,EN,,0,0,0,,All of the information that's needed to run this algorithm is in A and B. Dialogue: 0,0:04:55.74,0:04:57.80,EN,,0,0,0,,It has two well-defined state variables. Dialogue: 0,0:05:00.47,0:05:02.33,EN,,0,0,0,,So I'm going to define a machine for you Dialogue: 0,0:05:03.98,0:05:05.55,EN,,0,0,0,,can compute you GCDs. Dialogue: 0,0:05:06.56,0:05:07.12,EN,,0,0,0,,Now let's see. Dialogue: 0,0:05:07.12,0:05:11.28,EN,,0,0,0,,Every computer that's ever been made that's a single-process computer, Dialogue: 0,0:05:11.80,0:05:14.08,EN,,0,0,0,,as opposed to a multiprocessor of some sort, Dialogue: 0,0:05:15.04,0:05:16.59,EN,,0,0,0,,is made according to the same plan. Dialogue: 0,0:05:17.84,0:05:19.53,EN,,0,0,0,,The plan is the computer has two parts, Dialogue: 0,0:05:20.57,0:05:22.35,EN,,0,0,0,,a part called the datapaths, Dialogue: 0,0:05:23.10,0:05:24.36,EN,,0,0,0,,and a part called the controller. Dialogue: 0,0:05:25.91,0:05:29.28,EN,,0,0,0,,The datapaths correspond to a calculator that you might have. Dialogue: 0,0:05:29.71,0:05:31.87,EN,,0,0,0,,It contains certain registers that remember things, Dialogue: 0,0:05:31.90,0:05:33.13,EN,,0,0,0,,and you've all used calculators. Dialogue: 0,0:05:33.56,0:05:35.34,EN,,0,0,0,,It has some buttons on it and some lights. Dialogue: 0,0:05:37.03,0:05:38.49,EN,,0,0,0,,And so by pushing the various buttons, Dialogue: 0,0:05:38.52,0:05:41.34,EN,,0,0,0,,you can cause operations to happen inside there among the registers, Dialogue: 0,0:05:41.87,0:05:43.48,EN,,0,0,0,,and some of the results to be displayed. Dialogue: 0,0:05:45.16,0:05:46.25,EN,,0,0,0,,That's completely mechanical. Dialogue: 0,0:05:46.25,0:05:49.55,EN,,0,0,0,,You could imagine that box has no intelligence in it. Dialogue: 0,0:05:50.90,0:05:53.28,EN,,0,0,0,,Now it might be very impressive that it can produce the sine of a number, Dialogue: 0,0:05:53.53,0:05:58.97,EN,,0,0,0,,but that at least is apparently possibly mechanical. Dialogue: 0,0:05:58.97,0:06:01.71,EN,,0,0,0,,At least, I could open that up in the same way I'm about to open GCD. Dialogue: 0,0:06:02.69,0:06:04.36,EN,,0,0,0,,So this may have a whole computer inside of it, Dialogue: 0,0:06:04.68,0:06:05.69,EN,,0,0,0,,but that's not interesting. Dialogue: 0,0:06:05.94,0:06:07.10,EN,,0,0,0,,Addition is certainly simple. Dialogue: 0,0:06:08.20,0:06:09.84,EN,,0,0,0,,That can be done without any further mechanism. Dialogue: 0,0:06:10.89,0:06:15.64,EN,,0,0,0,,Now also, if we were to look at the other half, the controller, Dialogue: 0,0:06:15.93,0:06:17.39,EN,,0,0,0,,that's a part that's dumb, too. Dialogue: 0,0:06:18.19,0:06:19.16,EN,,0,0,0,,It pushes the buttons. Dialogue: 0,0:06:20.35,0:06:21.52,EN,,0,0,0,,It pushes them according to the sequence, Dialogue: 0,0:06:21.55,0:06:22.84,EN,,0,0,0,,which is written down on a piece of paper, Dialogue: 0,0:06:24.27,0:06:25.64,EN,,0,0,0,,and observes the lights. Dialogue: 0,0:06:26.29,0:06:29.44,EN,,0,0,0,,And every so often, it comes to a place in a sequence that says, Dialogue: 0,0:06:29.47,0:06:32.37,EN,,0,0,0,,if light A is on, do this sequence. Dialogue: 0,0:06:32.37,0:06:33.85,EN,,0,0,0,,Otherwise, do that sequence. Dialogue: 0,0:06:34.62,0:06:37.45,EN,,0,0,0,,And thereby, there's no complexity there either. Dialogue: 0,0:06:38.35,0:06:39.32,EN,,0,0,0,,Well, let's just draw that Dialogue: 0,0:06:39.34,0:06:40.57,EN,,0,0,0,,and see what we feel about that. Dialogue: 0,0:06:42.51,0:06:44.84,EN,,0,0,0,,So for computing GCDs, Dialogue: 0,0:06:45.88,0:06:49.52,EN,,0,0,0,,what I want you to think about is that there are these registers. Dialogue: 0,0:06:50.56,0:06:53.02,EN,,0,0,0,,A register is a place where I store a number, in this case. Dialogue: 0,0:06:53.52,0:06:54.65,EN,,0,0,0,,And this one's called a. Dialogue: 0,0:06:56.81,0:06:58.70,EN,,0,0,0,,And then there's another one for storing b. Dialogue: 0,0:07:03.17,0:07:05.45,EN,,0,0,0,,Now we have to see what things we can do with these registers, Dialogue: 0,0:07:05.98,0:07:08.73,EN,,0,0,0,,and they're not entirely obvious what you can do with them. Dialogue: 0,0:07:09.84,0:07:11.72,EN,,0,0,0,,Well, we have to see what things we need to do with them. Dialogue: 0,0:07:11.82,0:07:13.87,EN,,0,0,0,,We're looking at the problem we're trying to solve. Dialogue: 0,0:07:14.03,0:07:16.09,EN,,0,0,0,,One of the important things for designing a computer, Dialogue: 0,0:07:17.10,0:07:19.58,EN,,0,0,0,,which I think most designers don't do, Dialogue: 0,0:07:20.20,0:07:21.88,EN,,0,0,0,,is you stay the problem you want to solve Dialogue: 0,0:07:22.62,0:07:25.18,EN,,0,0,0,,and then use what you learn from studying the problem you want to solve Dialogue: 0,0:07:25.44,0:07:27.28,EN,,0,0,0,,to put in the mechanisms needed to solve it Dialogue: 0,0:07:27.53,0:07:28.70,EN,,0,0,0,,in the computer you're building, Dialogue: 0,0:07:28.81,0:07:30.08,EN,,0,0,0,,no more no less. Dialogue: 0,0:07:32.14,0:07:33.96,EN,,0,0,0,,Now it may be that the problem you're trying to solve Dialogue: 0,0:07:34.24,0:07:35.40,EN,,0,0,0,,is everybody's problem, Dialogue: 0,0:07:36.06,0:07:37.58,EN,,0,0,0,,in which case you have to build in a universal Dialogue: 0,0:07:37.60,0:07:39.29,EN,,0,0,0,,interpreter of some language. Dialogue: 0,0:07:40.19,0:07:42.32,EN,,0,0,0,,But you shouldn't put any more in than required Dialogue: 0,0:07:42.35,0:07:44.25,EN,,0,0,0,,to build the universal interpreter of some language. Dialogue: 0,0:07:44.44,0:07:45.85,EN,,0,0,0,,We'll worry about that in a second. Dialogue: 0,0:07:47.23,0:07:49.93,EN,,0,0,0,,OK, going back to here, let's see. Dialogue: 0,0:07:49.93,0:07:51.24,EN,,0,0,0,,What do we have to be able to do? Dialogue: 0,0:07:51.79,0:07:54.14,EN,,0,0,0,,Well, somehow, we have to be able to get B into A. Dialogue: 0,0:07:56.08,0:07:59.60,EN,,0,0,0,,We have to be able to get the old value of B into the value of A. Dialogue: 0,0:08:00.38,0:08:03.32,EN,,0,0,0,,So we have to have some path by which stuff can flow Dialogue: 0,0:08:03.34,0:08:04.76,EN,,0,0,0,,whatever this information is, Dialogue: 0,0:08:05.37,0:08:06.57,EN,,0,0,0,,OK? from b to a. Dialogue: 0,0:08:07.39,0:08:09.26,EN,,0,0,0,,I'm going to draw that with by an arrow Dialogue: 0,0:08:09.52,0:08:12.62,EN,,0,0,0,,saying that it is possible to move the contents of b into a, Dialogue: 0,0:08:12.96,0:08:14.57,EN,,0,0,0,,replacing the value of a. Dialogue: 0,0:08:15.12,0:08:16.73,EN,,0,0,0,,And there's a little button here which you push Dialogue: 0,0:08:17.48,0:08:18.56,EN,,0,0,0,,which allows that to happen. Dialogue: 0,0:08:19.71,0:08:20.78,EN,,0,0,0,,That's what the little x is here. Dialogue: 0,0:08:23.07,0:08:23.93,EN,,0,0,0,,Now it's also the case Dialogue: 0,0:08:23.95,0:08:26.28,EN,,0,0,0,,that I have to be able to compute the remainder of a and b. Dialogue: 0,0:08:27.00,0:08:28.49,EN,,0,0,0,,Now that may be a complicated mess. Dialogue: 0,0:08:28.86,0:08:30.86,EN,,0,0,0,,On the other hand, I'm going to make it a small box. Dialogue: 0,0:08:31.96,0:08:33.92,EN,,0,0,0,,If we have to, we may open up that box Dialogue: 0,0:08:34.12,0:08:35.63,EN,,0,0,0,,and look inside and see what it is. Dialogue: 0,0:08:37.77,0:08:39.16,EN,,0,0,0,,So here, I'm going to have a little box, Dialogue: 0,0:08:39.20,0:08:40.38,EN,,0,0,0,,which I'm going to draw this way, Dialogue: 0,0:08:43.16,0:08:44.38,EN,,0,0,0,,which we'll call the remainder. Dialogue: 0,0:08:46.44,0:08:48.60,EN,,0,0,0,,And it's going to take in a. Dialogue: 0,0:08:50.91,0:08:52.16,EN,,0,0,0,,That's going to take in b. Dialogue: 0,0:08:54.37,0:08:56.51,EN,,0,0,0,,And it's going to put out something, Dialogue: 0,0:08:58.89,0:09:00.46,EN,,0,0,0,,the remainder of a divided by b. Dialogue: 0,0:09:02.29,0:09:03.61,EN,,0,0,0,,Another thing we have to see here is Dialogue: 0,0:09:03.64,0:09:06.06,EN,,0,0,0,,that we have to be able to test whether b is equal to 0. Dialogue: 0,0:09:08.00,0:09:09.66,EN,,0,0,0,,Well, that means somebody's got to be looking at-- Dialogue: 0,0:09:10.00,0:09:12.30,EN,,0,0,0,,a thing that's looking at the value of b. Dialogue: 0,0:09:13.39,0:09:14.40,EN,,0,0,0,,I have a light bulb here Dialogue: 0,0:09:15.85,0:09:17.39,EN,,0,0,0,,which lights up if b equals 0. Dialogue: 0,0:09:21.11,0:09:22.01,EN,,0,0,0,,That's its job. Dialogue: 0,0:09:24.03,0:09:26.78,EN,,0,0,0,,And finally, I suppose, because of the fact Dialogue: 0,0:09:26.96,0:09:30.43,EN,,0,0,0,,that we want the new value of a to be the old value of b, Dialogue: 0,0:09:30.46,0:09:34.41,EN,,0,0,0,,and simultaneously the new value of b to be something I've done with a, Dialogue: 0,0:09:35.28,0:09:37.60,EN,,0,0,0,,and if I plan to make my machine Dialogue: 0,0:09:37.80,0:09:39.74,EN,,0,0,0,,such that everything happens one at a time, Dialogue: 0,0:09:40.20,0:09:41.40,EN,,0,0,0,,one motion at a time, Dialogue: 0,0:09:41.61,0:09:43.42,EN,,0,0,0,,and I can't put two numbers in a register, Dialogue: 0,0:09:44.03,0:09:46.30,EN,,0,0,0,,then I have to have another place to put one while I'm interchanging. Dialogue: 0,0:09:49.29,0:09:49.60,EN,,0,0,0,,OK? Dialogue: 0,0:09:50.00,0:09:51.85,EN,,0,0,0,,I can't interchange the two things in my hands, Dialogue: 0,0:09:52.11,0:09:53.72,EN,,0,0,0,,unless I either put two in one hand Dialogue: 0,0:09:53.72,0:09:55.13,EN,,0,0,0,,and then pull it back the other way, Dialogue: 0,0:09:55.50,0:09:56.91,EN,,0,0,0,,or unless I put one down, Dialogue: 0,0:09:57.02,0:09:58.68,EN,,0,0,0,,pick it up, and put the other one, like that Dialogue: 0,0:09:59.64,0:10:00.94,EN,,0,0,0,,unless I'm a juggler, Dialogue: 0,0:10:01.66,0:10:03.50,EN,,0,0,0,,which I'm not, as you can see, Dialogue: 0,0:10:04.65,0:10:07.36,EN,,0,0,0,,in which case I have a possibility of timing errors. Dialogue: 0,0:10:08.85,0:10:11.04,EN,,0,0,0,,In fact, much of the type of computer design Dialogue: 0,0:10:11.07,0:10:12.68,EN,,0,0,0,,people do involves timing errors, Dialogue: 0,0:10:13.12,0:10:15.00,EN,,0,0,0,,of some potential timing errors, Dialogue: 0,0:10:15.24,0:10:16.43,EN,,0,0,0,,which I don't much like. Dialogue: 0,0:10:17.34,0:10:18.64,EN,,0,0,0,,But. So for that reason, Dialogue: 0,0:10:18.68,0:10:21.21,EN,,0,0,0,,I have to have a place to put the third thing down Dialogue: 0,0:10:22.06,0:10:23.29,EN,,0,0,0,,the second one of them down. Dialogue: 0,0:10:23.41,0:10:24.72,EN,,0,0,0,,So I have a place called t, Dialogue: 0,0:10:24.75,0:10:26.84,EN,,0,0,0,,which is a register just for temporary, t, Dialogue: 0,0:10:28.59,0:10:29.63,EN,,0,0,0,,with a button on it. Dialogue: 0,0:10:30.47,0:10:31.88,EN,,0,0,0,,And then I'll take the result of that, Dialogue: 0,0:10:31.90,0:10:34.14,EN,,0,0,0,,since I have to take that and put into b, over here, Dialogue: 0,0:10:34.68,0:10:36.73,EN,,0,0,0,,we'll take the result of that and go like this, Dialogue: 0,0:10:38.41,0:10:39.30,EN,,0,0,0,,and a button here. Dialogue: 0,0:10:42.43,0:10:45.84,EN,,0,0,0,,So that's the datapaths of a GCD machine. Dialogue: 0,0:10:47.60,0:10:48.57,EN,,0,0,0,,Now what's the controller? Dialogue: 0,0:10:49.74,0:10:51.28,EN,,0,0,0,,Controller's a very simple thing, too. Dialogue: 0,0:10:52.28,0:10:53.26,EN,,0,0,0,,The machine has a state. Dialogue: 0,0:10:54.38,0:10:57.72,EN,,0,0,0,,The way I like to visualize that is that I've got a maze. Dialogue: 0,0:10:59.01,0:11:03.20,EN,,0,0,0,,And the maze has a bunch of places connected by directed arrows. Dialogue: 0,0:11:04.43,0:11:05.60,EN,,0,0,0,,And what I have is a marble, Dialogue: 0,0:11:06.46,0:11:09.07,EN,,0,0,0,,which represents the state of the controller. Dialogue: 0,0:11:10.74,0:11:12.27,EN,,0,0,0,,The marble rolls around in the maze. Dialogue: 0,0:11:13.74,0:11:17.15,EN,,0,0,0,,Of course, this analogy breaks down for energy reasons. Dialogue: 0,0:11:17.15,0:11:19.08,EN,,0,0,0,,I sometimes have to pump the marble up to the top, Dialogue: 0,0:11:19.12,0:11:21.85,EN,,0,0,0,,because it's going to otherwise be a perpetual motion machine. Dialogue: 0,0:11:22.00,0:11:23.32,EN,,0,0,0,,But not worrying about that, Dialogue: 0,0:11:23.90,0:11:25.90,EN,,0,0,0,,this is not a physical analogy. Dialogue: 0,0:11:26.08,0:11:27.42,EN,,0,0,0,,This marble rolls around. Dialogue: 0,0:11:27.68,0:11:29.56,EN,,0,0,0,,And every time it rolls around certain bumpers, Dialogue: 0,0:11:29.68,0:11:30.97,EN,,0,0,0,,like in a pinball machine, Dialogue: 0,0:11:31.26,0:11:32.60,EN,,0,0,0,,it pushes one of these buttons. Dialogue: 0,0:11:34.83,0:11:37.50,EN,,0,0,0,,And every so often, it comes to a place, which is a division, Dialogue: 0,0:11:38.62,0:11:39.68,EN,,0,0,0,,where it has to make a choice. Dialogue: 0,0:11:40.25,0:11:42.36,EN,,0,0,0,,And there's a flap, which is controlled by this. Dialogue: 0,0:11:46.00,0:11:48.82,EN,,0,0,0,,So that's a really mechanical way of thinking about it. Dialogue: 0,0:11:48.82,0:11:51.05,EN,,0,0,0,,Of course, controllers not these days, are not built that way Dialogue: 0,0:11:51.08,0:11:51.84,EN,,0,0,0,,in real computers. Dialogue: 0,0:11:51.84,0:11:56.01,EN,,0,0,0,,They're built with a little bit of ROM and a state register. Dialogue: 0,0:11:56.61,0:11:58.73,EN,,0,0,0,,But there was a time, like the DEC PDP-6, Dialogue: 0,0:11:59.29,0:12:01.02,EN,,0,0,0,,where that's how you built the controller of a machine. Dialogue: 0,0:12:01.80,0:12:03.61,EN,,0,0,0,,There was a bit that ran around the delay line, Dialogue: 0,0:12:05.69,0:12:08.14,EN,,0,0,0,,and it triggered things as it went by. Dialogue: 0,0:12:08.58,0:12:10.70,EN,,0,0,0,,And it would come back to the beginning and get fed round again. Dialogue: 0,0:12:11.99,0:12:13.72,EN,,0,0,0,,And of course, there were all sorts of great bugs you could have Dialogue: 0,0:12:13.74,0:12:17.67,EN,,0,0,0,,like two bits going around, two marbles. Dialogue: 0,0:12:17.67,0:12:19.26,EN,,0,0,0,,And then the machine has lost its marbles. Dialogue: 0,0:12:19.45,0:12:20.20,EN,,0,0,0,,That happens, too. Dialogue: 0,0:12:20.98,0:12:21.58,EN,,0,0,0,,Oh, well. Dialogue: 0,0:12:22.27,0:12:24.22,EN,,0,0,0,,So anyway, for this machine, Dialogue: 0,0:12:24.27,0:12:25.48,EN,,0,0,0,,what I have to do is the following. Dialogue: 0,0:12:25.80,0:12:27.74,EN,,0,0,0,,I'm going to start my maze here. Dialogue: 0,0:12:30.52,0:12:32.73,EN,,0,0,0,,And the first thing I've got to do, Dialogue: 0,0:12:33.76,0:12:36.75,EN,,0,0,0,,is in a notation which many of you are familiar with, Dialogue: 0,0:12:37.07,0:12:39.85,EN,,0,0,0,,is b equal to zero, a test. Dialogue: 0,0:12:41.50,0:12:43.79,EN,,0,0,0,,And there's a possibility, either yes, Dialogue: 0,0:12:43.93,0:12:45.58,EN,,0,0,0,,in which case I'm done. Dialogue: 0,0:12:49.79,0:12:51.26,EN,,0,0,0,,Otherwise, if no, Dialogue: 0,0:12:52.70,0:12:54.32,EN,,0,0,0,,then I'm going have to roll over some bumpers. Dialogue: 0,0:12:55.00,0:12:56.46,EN,,0,0,0,,I'm going to do it in the following order. Dialogue: 0,0:12:57.42,0:13:03.40,EN,,0,0,0,,I want to, I want to do this interchange game. Dialogue: 0,0:13:04.05,0:13:05.80,EN,,0,0,0,,Now first, since I need both a and b, Dialogue: 0,0:13:06.32,0:13:08.57,EN,,0,0,0,,but then the first-- and this is not necessary-- Dialogue: 0,0:13:08.65,0:13:09.72,EN,,0,0,0,,I want to collect this. Dialogue: 0,0:13:11.07,0:13:12.62,EN,,0,0,0,,This is the thing that's going to go into b. Dialogue: 0,0:13:13.24,0:13:14.03,EN,,0,0,0,,So I'm going to say, Dialogue: 0,0:13:14.28,0:13:16.27,EN,,0,0,0,,take this, which depends upon both a and b, Dialogue: 0,0:13:16.36,0:13:18.67,EN,,0,0,0,,and put the remainder into here. Dialogue: 0,0:13:19.15,0:13:20.33,EN,,0,0,0,,So I'm going to push this button first. Dialogue: 0,0:13:21.53,0:13:24.43,EN,,0,0,0,,Then, I'm going to transfer b to a, Dialogue: 0,0:13:24.44,0:13:25.60,EN,,0,0,0,,push that button, Dialogue: 0,0:13:25.82,0:13:27.63,EN,,0,0,0,,and then I transfer the temporary into b, Dialogue: 0,0:13:28.76,0:13:29.42,EN,,0,0,0,,push that button. Dialogue: 0,0:13:32.03,0:13:34.97,EN,,0,0,0,,So a very sequential machine, Dialogue: 0,0:13:35.39,0:13:36.52,EN,,0,0,0,,it's very inefficient. Dialogue: 0,0:13:37.75,0:13:39.05,EN,,0,0,0,,But that's fine right now. Dialogue: 0,0:13:39.81,0:13:40.97,EN,,0,0,0,,We're going to name the buttons, Dialogue: 0,0:13:41.47,0:13:42.72,EN,,0,0,0,,t gets remainder. Dialogue: 0,0:13:46.75,0:13:48.73,EN,,0,0,0,,a gets b. Dialogue: 0,0:13:50.03,0:13:54.81,EN,,0,0,0,,And b gets t. Dialogue: 0,0:13:55.47,0:13:57.63,EN,,0,0,0,,And then I'm going to go around here Dialogue: 0,0:13:58.78,0:13:59.88,EN,,0,0,0,,and it's to go back to start. Dialogue: 0,0:14:01.62,0:14:03.87,EN,,0,0,0,,And if you look, what are we seeing here? Dialogue: 0,0:14:03.87,0:14:04.91,EN,,0,0,0,,We're seeing the various-- Dialogue: 0,0:14:05.05,0:14:07.16,EN,,0,0,0,,what I really have is some sort of mechanical connection, Dialogue: 0,0:14:07.42,0:14:13.63,EN,,0,0,0,,where t gets r controls this thing. Dialogue: 0,0:14:16.83,0:14:21.48,EN,,0,0,0,,And I have here that a gets b controls this fellow over here, Dialogue: 0,0:14:26.96,0:14:28.12,EN,,0,0,0,,and this fellow over here. Dialogue: 0,0:14:28.12,0:14:31.08,EN,,0,0,0,,Boy, that's absolutely pessimal, Dialogue: 0,0:14:31.48,0:14:32.48,EN,,0,0,0,,the inverse of optimal. Dialogue: 0,0:14:32.63,0:14:34.59,EN,,0,0,0,,Every line heads across every other line the way I drew it. Dialogue: 0,0:14:38.54,0:14:41.15,EN,,0,0,0,,I suppose this goes here, b gets t. Dialogue: 0,0:14:45.69,0:14:47.95,EN,,0,0,0,,Now I'd like to run this machine. Dialogue: 0,0:14:48.04,0:14:49.34,EN,,0,0,0,,But before I run the machine, Dialogue: 0,0:14:49.37,0:14:51.40,EN,,0,0,0,,I want to write down a description of this controller, Dialogue: 0,0:14:51.63,0:14:52.81,EN,,0,0,0,,just so you can see that these things, Dialogue: 0,0:14:52.84,0:14:55.63,EN,,0,0,0,,of course, as usual, can be written down in some nice language, Dialogue: 0,0:14:56.08,0:14:58.08,EN,,0,0,0,,so that we don't have to always draw these diagrams. Dialogue: 0,0:14:58.36,0:15:00.68,EN,,0,0,0,,One of the problems with diagrams is that they take up a lot of space. Dialogue: 0,0:15:00.89,0:15:01.98,EN,,0,0,0,,And for a machine this small, Dialogue: 0,0:15:02.00,0:15:03.05,EN,,0,0,0,,it takes two blackboards. Dialogue: 0,0:15:03.22,0:15:05.24,EN,,0,0,0,,For a machine that's the evaluator machine, Dialogue: 0,0:15:05.40,0:15:07.10,EN,,0,0,0,,I have trouble putting it into this room, Dialogue: 0,0:15:07.95,0:15:09.16,EN,,0,0,0,,even though it isn't very big. Dialogue: 0,0:15:09.90,0:15:11.28,EN,,0,0,0,,So I'm going to make a little language for this Dialogue: 0,0:15:11.29,0:15:12.51,EN,,0,0,0,,that's just a description of that, Dialogue: 0,0:15:13.10,0:15:23.29,EN,,0,0,0,,saying define a machine we'll call GCD. Dialogue: 0,0:15:24.42,0:15:25.66,EN,,0,0,0,,Of course, once we have something like this, Dialogue: 0,0:15:25.68,0:15:26.83,EN,,0,0,0,,we have a simulator for it. Dialogue: 0,0:15:27.22,0:15:29.42,EN,,0,0,0,,And the reason why we want to build a language in this form, Dialogue: 0,0:15:29.56,0:15:32.94,EN,,0,0,0,,is because all of a sudden we can manipulate these expressions that I'm writing down. Dialogue: 0,0:15:33.21,0:15:34.91,EN,,0,0,0,,And then of course I can write things I can Dialogue: 0,0:15:35.29,0:15:38.16,EN,,0,0,0,,algebraically manipulate these things, simulate them Dialogue: 0,0:15:38.20,0:15:39.96,EN,,0,0,0,,all that sort of things that I might want to do, Dialogue: 0,0:15:40.12,0:15:42.59,EN,,0,0,0,,perhaps transform them as a layout, who knows. Dialogue: 0,0:15:43.63,0:15:48.38,EN,,0,0,0,,Once I have a nice representation of registers, Dialogue: 0,0:15:48.51,0:15:49.61,EN,,0,0,0,,it has certain registers, Dialogue: 0,0:15:53.00,0:15:55.64,EN,,0,0,0,,which we can call A, B, and T. Dialogue: 0,0:15:56.75,0:15:57.80,EN,,0,0,0,,And there's a controller. Dialogue: 0,0:16:02.19,0:16:04.46,EN,,0,0,0,,Actually, a better language, which would be more explicit, Dialogue: 0,0:16:04.49,0:16:06.97,EN,,0,0,0,,would be one which named every button Dialogue: 0,0:16:08.14,0:16:10.17,EN,,0,0,0,,also and said what it did. Dialogue: 0,0:16:10.42,0:16:11.37,EN,,0,0,0,,Like, this button Dialogue: 0,0:16:11.55,0:16:14.19,EN,,0,0,0,,causes the contents of T to go to the contents of B. Dialogue: 0,0:16:15.10,0:16:16.09,EN,,0,0,0,,Well I don't want to do that, Dialogue: 0,0:16:16.11,0:16:17.95,EN,,0,0,0,,because it's actually harder to read to do that, Dialogue: 0,0:16:18.20,0:16:19.34,EN,,0,0,0,,and it takes up more space. Dialogue: 0,0:16:19.51,0:16:22.36,EN,,0,0,0,,So I'm going to have that in the instructions written in the controller. Dialogue: 0,0:16:23.29,0:16:25.24,EN,,0,0,0,,It's going to be implicit what the operations are. Dialogue: 0,0:16:26.32,0:16:28.57,EN,,0,0,0,,They can be deduced by reading these Dialogue: 0,0:16:29.16,0:16:31.39,EN,,0,0,0,,and collecting together all the different things that can be done. Dialogue: 0,0:16:31.69,0:16:33.50,EN,,0,0,0,,We look and see, see... Dialogue: 0,0:16:33.50,0:16:34.70,EN,,0,0,0,,Well, let's just look at what these things are. Dialogue: 0,0:16:35.71,0:16:37.29,EN,,0,0,0,,There's a little loop that we go around Dialogue: 0,0:16:38.24,0:16:40.20,EN,,0,0,0,,which says branch, Dialogue: 0,0:16:42.64,0:16:46.46,EN,,0,0,0,,this is the representation of the little flap Dialogue: 0,0:16:46.89,0:16:48.49,EN,,0,0,0,,that decides which way you go here, Dialogue: 0,0:16:49.10,0:16:58.00,EN,,0,0,0,,if 0, OK, fetch of B, the contents of B, Dialogue: 0,0:16:58.65,0:17:00.06,EN,,0,0,0,,and if the contents of B is 0, Dialogue: 0,0:17:00.32,0:17:01.72,EN,,0,0,0,,then go to a place called done. Dialogue: 0,0:17:03.64,0:17:05.29,EN,,0,0,0,,Now, one thing you're seeing here, Dialogue: 0,0:17:05.29,0:17:07.40,EN,,0,0,0,,this looks very much like a traditional computer language. Dialogue: 0,0:17:08.17,0:17:09.55,EN,,0,0,0,,And what you're seeing here Dialogue: 0,0:17:10.03,0:17:12.00,EN,,0,0,0,,is things like labels Dialogue: 0,0:17:12.99,0:17:16.86,EN,,0,0,0,,that represent places in a sequence written down as a sequence. Dialogue: 0,0:17:17.60,0:17:18.94,EN,,0,0,0,,The reason why they're needed Dialogue: 0,0:17:19.48,0:17:21.15,EN,,0,0,0,,is because over here, Dialogue: 0,0:17:21.45,0:17:22.81,EN,,0,0,0,,I've written something with loops. Dialogue: 0,0:17:23.32,0:17:26.11,EN,,0,0,0,,But if I'm writing English text, or something like that, Dialogue: 0,0:17:26.44,0:17:28.09,EN,,0,0,0,,it's hard to refer to a place. Dialogue: 0,0:17:28.58,0:17:29.53,EN,,0,0,0,,I don't have arrows. Dialogue: 0,0:17:30.80,0:17:33.02,EN,,0,0,0,,Arrows are represented by giving names Dialogue: 0,0:17:33.05,0:17:34.44,EN,,0,0,0,,to the places where the arrows terminate, Dialogue: 0,0:17:34.57,0:17:36.28,EN,,0,0,0,,and then referring to them by those names. Dialogue: 0,0:17:37.40,0:17:38.59,EN,,0,0,0,,Now this is just an encoding. Dialogue: 0,0:17:39.86,0:17:41.88,EN,,0,0,0,,There's nothing magical about things like that. Dialogue: 0,0:17:43.15,0:17:44.96,EN,,0,0,0,,Next thing we're going to do is we're going to say, Dialogue: 0,0:17:45.02,0:17:46.84,EN,,0,0,0,,how do we do T gets R? Dialogue: 0,0:17:47.45,0:17:49.76,EN,,0,0,0,,Oh, that's easy enough, assign. Dialogue: 0,0:17:52.19,0:17:55.55,EN,,0,0,0,,We assign to T the remainder. Dialogue: 0,0:17:56.32,0:17:59.24,EN,,0,0,0,,Assign is the name of the button. Dialogue: 0,0:18:01.47,0:18:02.64,EN,,0,0,0,,That's the button-pusher. Dialogue: 0,0:18:03.14,0:18:04.97,EN,,0,0,0,,Assign to T the remainder, Dialogue: 0,0:18:04.99,0:18:06.76,EN,,0,0,0,,and here's the representation of the operation, Dialogue: 0,0:18:11.74,0:18:17.53,EN,,0,0,0,,when we divide the fetch of A by the fetch of B. Dialogue: 0,0:18:23.85,0:18:30.99,EN,,0,0,0,,And we're also going to assign to A the fetch of B, Dialogue: 0,0:18:34.99,0:18:47.88,EN,,0,0,0,,assign to B the result of getting the contents of T. Dialogue: 0,0:18:49.61,0:18:51.85,EN,,0,0,0,,And now I have to refer to the beginning here. Dialogue: 0,0:18:53.18,0:18:55.92,EN,,0,0,0,,I see, why don't I call that loop like I have here? Dialogue: 0,0:19:04.09,0:19:07.04,EN,,0,0,0,,OK? So that's that reference to that arrow. Dialogue: 0,0:19:07.61,0:19:08.95,EN,,0,0,0,,And when we're done, we're done. Dialogue: 0,0:19:09.02,0:19:13.07,EN,,0,0,0,,We go to here, which is the end of the thing. Dialogue: 0,0:19:15.26,0:19:17.04,EN,,0,0,0,,So here's just a written representation Dialogue: 0,0:19:17.69,0:19:20.86,EN,,0,0,0,,of this fragment of machinery that we've drawn here. Dialogue: 0,0:19:21.66,0:19:24.84,EN,,0,0,0,,Now the next thing I'd like to do is run this. Dialogue: 0,0:19:25.49,0:19:26.65,EN,,0,0,0,,I want us to feel it running. Dialogue: 0,0:19:27.62,0:19:29.80,EN,,0,0,0,,Never done this before, you got to do it once. Dialogue: 0,0:19:31.01,0:19:32.62,EN,,0,0,0,,So let's take a particular problem. Dialogue: 0,0:19:33.10,0:19:34.70,EN,,0,0,0,,Suppose we want to compute the GCD Dialogue: 0,0:19:35.04,0:19:40.68,EN,,0,0,0,,of a equals 30 and b equals 42. Dialogue: 0,0:19:42.21,0:19:44.92,EN,,0,0,0,,I have no idea what that is right now. Dialogue: 0,0:19:45.86,0:19:47.60,EN,,0,0,0,,But a 30 and b is 42. Dialogue: 0,0:19:50.96,0:19:52.09,EN,,0,0,0,,So that's how I start this thing up. Dialogue: 0,0:19:52.60,0:19:53.90,EN,,0,0,0,,Well, what's the first thing I do? Dialogue: 0,0:19:54.24,0:19:56.86,EN,,0,0,0,,I say is B equal to 0, no. Dialogue: 0,0:19:57.59,0:20:02.11,EN,,0,0,0,,Then assign to T the remainder of the fetch of A and the fetch of B. Dialogue: 0,0:20:02.80,0:20:07.60,EN,,0,0,0,,Well the remainder of 30 when divided by 42 is itself 30. Dialogue: 0,0:20:11.13,0:20:12.03,EN,,0,0,0,,Push that button. Dialogue: 0,0:20:12.92,0:20:15.10,EN,,0,0,0,,Now the marble has rolled to here. Dialogue: 0,0:20:17.10,0:20:18.06,EN,,0,0,0,,A gets B. Dialogue: 0,0:20:19.02,0:20:20.76,EN,,0,0,0,,That pushes this button. Dialogue: 0,0:20:21.22,0:20:22.54,EN,,0,0,0,,So 42 moves into here. Dialogue: 0,0:20:26.59,0:20:27.60,EN,,0,0,0,,B gets T. Dialogue: 0,0:20:28.36,0:20:29.34,EN,,0,0,0,,Push that button. Dialogue: 0,0:20:29.87,0:20:30.96,EN,,0,0,0,,The 30 goes here. Dialogue: 0,0:20:32.57,0:20:33.69,EN,,0,0,0,,Let met just interchange them. Dialogue: 0,0:20:34.66,0:20:38.27,EN,,0,0,0,,Now let's see, go back to the beginning. Dialogue: 0,0:20:38.64,0:20:39.72,EN,,0,0,0,,B 0, no. Dialogue: 0,0:20:40.19,0:20:41.50,EN,,0,0,0,,T gets the remainder. Dialogue: 0,0:20:43.23,0:20:46.30,EN,,0,0,0,,I suppose the remainder when dividing 42 by 30 is 12. Dialogue: 0,0:20:47.24,0:20:48.30,EN,,0,0,0,,I push that one. Dialogue: 0,0:20:48.53,0:20:51.40,EN,,0,0,0,,Next thing I do is allow the 30 to go to here, Dialogue: 0,0:20:53.90,0:20:55.95,EN,,0,0,0,,push this one, allow the 12 to go to here. Dialogue: 0,0:20:58.41,0:21:00.38,EN,,0,0,0,,OK? Go around this thing. Dialogue: 0,0:21:00.38,0:21:01.31,EN,,0,0,0,,Is that done? Dialogue: 0,0:21:01.53,0:21:02.12,EN,,0,0,0,,No. Dialogue: 0,0:21:02.36,0:21:08.22,EN,,0,0,0,,How about-- so now I have to find out the remainder of 30 divided by 12. Dialogue: 0,0:21:08.85,0:21:10.67,EN,,0,0,0,,And I believe that's 6. Dialogue: 0,0:21:12.42,0:21:15.13,EN,,0,0,0,,So 6 goes here on this button push. Dialogue: 0,0:21:16.20,0:21:18.25,EN,,0,0,0,,Then the next thing I push is this one, Dialogue: 0,0:21:18.30,0:21:19.61,EN,,0,0,0,,which the 12 goes into here. Dialogue: 0,0:21:23.73,0:21:25.09,EN,,0,0,0,,Then I push this button. Dialogue: 0,0:21:25.09,0:21:26.00,EN,,0,0,0,,The 6 gets into here. Dialogue: 0,0:21:29.85,0:21:31.68,EN,,0,0,0,,Is 6 equal to 0? Dialogue: 0,0:21:31.88,0:21:32.49,EN,,0,0,0,,No. Dialogue: 0,0:21:33.42,0:21:33.98,EN,,0,0,0,,OK. Dialogue: 0,0:21:34.38,0:21:36.80,EN,,0,0,0,,So then at that point, Dialogue: 0,0:21:36.89,0:21:38.12,EN,,0,0,0,,the next thing to do is divide it. Dialogue: 0,0:21:38.14,0:21:39.80,EN,,0,0,0,,Ooh, this has got a remainder of 0. Dialogue: 0,0:21:40.66,0:21:41.74,EN,,0,0,0,,Looks like we're almost done. Dialogue: 0,0:21:42.36,0:21:44.36,EN,,0,0,0,,Move the 6 over here next. Dialogue: 0,0:21:47.00,0:21:48.27,EN,,0,0,0,,0 over here. Dialogue: 0,0:21:49.09,0:21:50.20,EN,,0,0,0,,Is the answer 0? Dialogue: 0,0:21:50.20,0:21:50.73,EN,,0,0,0,,Yes. Dialogue: 0,0:21:51.34,0:21:53.36,EN,,0,0,0,,B is 0, therefore the answer is in A. Dialogue: 0,0:21:54.28,0:21:55.76,EN,,0,0,0,,The answer is 6. Dialogue: 0,0:21:56.61,0:21:57.61,EN,,0,0,0,,And indeed that's right, Dialogue: 0,0:21:57.63,0:21:59.47,EN,,0,0,0,,because if we look at the original problem, Dialogue: 0,0:22:00.08,0:22:06.64,EN,,0,0,0,,what we have is 30 is 2 times 3 times 5, Dialogue: 0,0:22:07.00,0:22:11.12,EN,,0,0,0,,and 42 is 2 times 3 times 7. Dialogue: 0,0:22:11.67,0:22:14.11,EN,,0,0,0,,So the greatest common divisor is 2 times 3, Dialogue: 0,0:22:14.20,0:22:15.08,EN,,0,0,0,,which is 6. Dialogue: 0,0:22:18.38,0:22:20.56,EN,,0,0,0,,Now normally, we write one other little line here, Dialogue: 0,0:22:20.59,0:22:22.52,EN,,0,0,0,,just to make it a little bit clearer, Dialogue: 0,0:22:22.89,0:22:27.71,EN,,0,0,0,,which is that we leave in a connection saying Dialogue: 0,0:22:27.85,0:22:31.01,EN,,0,0,0,,that this light is the guy that that flap looks at. Dialogue: 0,0:22:34.00,0:22:37.32,EN,,0,0,0,,Of course, any real machine has a lot more Dialogue: 0,0:22:37.85,0:22:40.00,EN,,0,0,0,,complicated things in it than what I've just shown you. Dialogue: 0,0:22:41.35,0:22:47.16,EN,,0,0,0,,Let's look for a second at the first still store. Dialogue: 0,0:22:47.98,0:22:48.81,EN,,0,0,0,,Wow. Dialogue: 0,0:22:50.19,0:22:52.43,EN,,0,0,0,,Well you see, for example, one thing we might want to do Dialogue: 0,0:22:52.65,0:22:55.85,EN,,0,0,0,,is worry about the operations that are of IO form. Dialogue: 0,0:22:56.84,0:23:01.42,EN,,0,0,0,,And we may have to collect something from the outside. Dialogue: 0,0:23:01.98,0:23:03.93,EN,,0,0,0,,So a state machine that we might have, Dialogue: 0,0:23:04.30,0:23:07.02,EN,,0,0,0,,the controller may have to, Dialogue: 0,0:23:07.26,0:23:10.56,EN,,0,0,0,,may have to, for example, get a value from something Dialogue: 0,0:23:10.78,0:23:12.41,EN,,0,0,0,,and put register a to load it up. Dialogue: 0,0:23:13.49,0:23:15.92,EN,,0,0,0,,I have to master load up register b with another value. Dialogue: 0,0:23:17.07,0:23:18.60,EN,,0,0,0,,And then later, when I'm done, Dialogue: 0,0:23:18.99,0:23:20.52,EN,,0,0,0,,I might want to print the answer out. Dialogue: 0,0:23:21.20,0:23:25.23,EN,,0,0,0,,And of course, that might be either simple or complicated. Dialogue: 0,0:23:26.09,0:23:28.03,EN,,0,0,0,,I'm writing, assuming print is very simple, Dialogue: 0,0:23:28.09,0:23:29.29,EN,,0,0,0,,and read is very simple. Dialogue: 0,0:23:29.88,0:23:31.08,EN,,0,0,0,,But in fact, in the real world, Dialogue: 0,0:23:31.12,0:23:32.89,EN,,0,0,0,,those are very complicated operations, Dialogue: 0,0:23:33.08,0:23:35.52,EN,,0,0,0,,fairly, usually much, much larger and more complicated Dialogue: 0,0:23:35.55,0:23:38.33,EN,,0,0,0,,than the thing you're doing as your problem you're trying to solve. Dialogue: 0,0:23:41.67,0:23:43.90,EN,,0,0,0,,On the other hand, I can remember a time when, Dialogue: 0,0:23:44.89,0:23:48.78,EN,,0,0,0,,I remember using IBM 7090 computer of sorts, Dialogue: 0,0:23:49.05,0:23:53.04,EN,,0,0,0,,where things like read and write of a single object, Dialogue: 0,0:23:53.08,0:23:54.62,EN,,0,0,0,,a single number, a number, Dialogue: 0,0:23:55.84,0:23:58.54,EN,,0,0,0,,is a primitive operation of the IO controller. Dialogue: 0,0:23:59.63,0:24:02.04,EN,,0,0,0,,OK? And so we have that kind of thing in there. Dialogue: 0,0:24:02.33,0:24:04.67,EN,,0,0,0,,And in such a machine, Dialogue: 0,0:24:05.44,0:24:06.89,EN,,0,0,0,,well, what are we really doing? Dialogue: 0,0:24:07.12,0:24:11.60,EN,,0,0,0,,We're just saying that there's a source over here called "read" Dialogue: 0,0:24:12.20,0:24:14.46,EN,,0,0,0,,which is an operation which always has a value. Dialogue: 0,0:24:14.66,0:24:17.13,EN,,0,0,0,,We have to think about this as always having a value Dialogue: 0,0:24:17.21,0:24:19.84,EN,,0,0,0,,which can be gated into either register a or b. Dialogue: 0,0:24:21.66,0:24:23.23,EN,,0,0,0,,And print is some sort of thing Dialogue: 0,0:24:23.37,0:24:25.02,EN,,0,0,0,,which when you gate it appropriately, Dialogue: 0,0:24:25.24,0:24:26.43,EN,,0,0,0,,when you push the button on it, Dialogue: 0,0:24:26.65,0:24:29.61,EN,,0,0,0,,will cause a print of the value that's currently in register a. Dialogue: 0,0:24:31.66,0:24:32.73,EN,,0,0,0,,Nothing very exciting. Dialogue: 0,0:24:33.32,0:24:35.20,EN,,0,0,0,,So that's one sort of thing you might want to have. Dialogue: 0,0:24:35.88,0:24:38.32,EN,,0,0,0,,But these are also other things that are a little bit worrisome. Dialogue: 0,0:24:38.32,0:24:40.67,EN,,0,0,0,,Like I've used here some complicated mechanisms. Dialogue: 0,0:24:41.05,0:24:42.48,EN,,0,0,0,,What you see here is remainder. Dialogue: 0,0:24:43.85,0:24:44.44,EN,,0,0,0,,What is that? Dialogue: 0,0:24:44.69,0:24:46.41,EN,,0,0,0,,That may not be so obvious how to compute. Dialogue: 0,0:24:46.92,0:24:48.92,EN,,0,0,0,,It may be something which when you open it up, Dialogue: 0,0:24:49.48,0:24:50.62,EN,,0,0,0,,you get a whole machine. Dialogue: 0,0:24:51.84,0:24:53.66,EN,,0,0,0,,OK? In fact, that's true. Dialogue: 0,0:24:54.54,0:24:59.15,EN,,0,0,0,,For example, if I write down the program for remainder, Dialogue: 0,0:24:59.44,0:25:02.44,EN,,0,0,0,,the simplest program for it is by repeated subtraction. Dialogue: 0,0:25:04.78,0:25:05.95,EN,,0,0,0,,Because of course, division can be done Dialogue: 0,0:25:05.96,0:25:08.99,EN,,0,0,0,,by repeated subtraction of numbers, of integers. Dialogue: 0,0:25:09.80,0:25:23.58,EN,,0,0,0,,So the remainder of N divided by D Dialogue: 0,0:25:24.99,0:25:31.44,EN,,0,0,0,,is nothing more than if N is less than D, Dialogue: 0,0:25:32.24,0:25:33.66,EN,,0,0,0,,then the result is N. Dialogue: 0,0:25:34.30,0:25:35.90,EN,,0,0,0,,Otherwise, it's the remainder Dialogue: 0,0:25:41.15,0:25:47.60,EN,,0,0,0,,when we subtract D from N with respect to D, Dialogue: 0,0:25:48.27,0:25:49.32,EN,,0,0,0,,when divided by D. Dialogue: 0,0:25:51.28,0:25:55.05,EN,,0,0,0,,Gee, this looks just like the GCD program. Dialogue: 0,0:25:56.89,0:25:59.48,EN,,0,0,0,,Of course, it's not a very nice way to do remainders. Dialogue: 0,0:25:59.75,0:26:00.91,EN,,0,0,0,,You'd really want to use something like Dialogue: 0,0:26:00.92,0:26:05.42,EN,,0,0,0,,binary notation and shift and things like that in a practical computer. Dialogue: 0,0:26:05.55,0:26:06.97,EN,,0,0,0,,But the point of that is Dialogue: 0,0:26:07.13,0:26:08.48,EN,,0,0,0,,that if I open this thing up, Dialogue: 0,0:26:08.92,0:26:10.64,EN,,0,0,0,,I might find inside of it a computer. Dialogue: 0,0:26:11.88,0:26:12.99,EN,,0,0,0,,Oh, we know how to do that. Dialogue: 0,0:26:13.51,0:26:14.33,EN,,0,0,0,,We just made one. Dialogue: 0,0:26:15.64,0:26:17.10,EN,,0,0,0,,And it could be another thing just like this. Dialogue: 0,0:26:17.40,0:26:18.06,EN,,0,0,0,,On the other hand, Dialogue: 0,0:26:18.08,0:26:20.00,EN,,0,0,0,,we might want to make a more efficient Dialogue: 0,0:26:20.01,0:26:21.68,EN,,0,0,0,,or better-structured machine, Dialogue: 0,0:26:21.85,0:26:23.96,EN,,0,0,0,,or maybe make use of some of the registers more than once, Dialogue: 0,0:26:24.00,0:26:27.05,EN,,0,0,0,,or some horrible mess like that that hardware designers like to do, Dialogue: 0,0:26:27.31,0:26:28.60,EN,,0,0,0,,and for very good reasons. Dialogue: 0,0:26:29.25,0:26:31.56,EN,,0,0,0,,So for example, here's a machine that you see, Dialogue: 0,0:26:32.52,0:26:34.91,EN,,0,0,0,,which you're not supposed to be able to read. Dialogue: 0,0:26:35.05,0:26:37.52,EN,,0,0,0,,It's a little bit complicated. OK? Dialogue: 0,0:26:37.52,0:26:39.87,EN,,0,0,0,,But what it is is the integration of Dialogue: 0,0:26:40.09,0:26:43.82,EN,,0,0,0,,remainder into the GCD machine. Dialogue: 0,0:26:44.46,0:26:46.02,EN,,0,0,0,,And it takes, in fact, no more registers. Dialogue: 0,0:26:46.02,0:26:48.62,EN,,0,0,0,,There are three registers in the datapaths. OK? Dialogue: 0,0:26:49.05,0:26:50.64,EN,,0,0,0,,But now there's a subtractor. Dialogue: 0,0:26:51.55,0:26:52.99,EN,,0,0,0,,There are two things that are tested. Dialogue: 0,0:26:53.02,0:26:55.07,EN,,0,0,0,,Is b equal to 0, Dialogue: 0,0:26:55.23,0:26:56.56,EN,,0,0,0,,or is t less than b? Dialogue: 0,0:26:57.25,0:26:59.45,EN,,0,0,0,,And then the controller, which you see over here, Dialogue: 0,0:27:00.22,0:27:01.76,EN,,0,0,0,,is not much more complicated. Dialogue: 0,0:27:01.85,0:27:03.87,EN,,0,0,0,,But it has two loops in it, Dialogue: 0,0:27:04.52,0:27:08.33,EN,,0,0,0,,one of which is the main one for doing the GCD, Dialogue: 0,0:27:08.40,0:27:10.14,EN,,0,0,0,,and one of which is the subtraction loop Dialogue: 0,0:27:10.43,0:27:12.80,EN,,0,0,0,,for doing the remainder sub-operation. Dialogue: 0,0:27:14.03,0:27:15.80,EN,,0,0,0,,And there are ways, of course, of, Dialogue: 0,0:27:15.96,0:27:18.68,EN,,0,0,0,,if you think about it, taking the remainder program. Dialogue: 0,0:27:19.92,0:27:21.71,EN,,0,0,0,,If I take remainder, as you see over there Dialogue: 0,0:27:21.72,0:27:22.83,EN,,0,0,0,,as a lambda expression, Dialogue: 0,0:27:23.56,0:27:27.02,EN,,0,0,0,,substitute it in for remainder over here in the GCD program, Dialogue: 0,0:27:28.20,0:27:30.12,EN,,0,0,0,,OK, then do some simplification Dialogue: 0,0:27:30.32,0:27:33.66,EN,,0,0,0,,by substituting a and b for remainder in there, Dialogue: 0,0:27:34.46,0:27:35.95,EN,,0,0,0,,then I can unwind this loop. Dialogue: 0,0:27:36.63,0:27:39.42,EN,,0,0,0,,And I can get this piece of machinery Dialogue: 0,0:27:40.73,0:27:42.94,EN,,0,0,0,,by basically, a little bit of simplification Dialogue: 0,0:27:43.36,0:27:45.21,EN,,0,0,0,,algebraic simplification on the lambda expressions. Dialogue: 0,0:27:48.55,0:27:51.20,EN,,0,0,0,,So I suppose you've seen your first very simple machines now. Dialogue: 0,0:27:51.95,0:27:53.28,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:28:02.70,0:28:03.10,EN,,0,0,0,,Good. Dialogue: 0,0:28:05.36,0:28:06.54,EN,,0,0,0,,This looks easy, doesn't it? Dialogue: 0,0:28:10.14,0:28:11.32,EN,,0,0,0,,Thank you. I suppose, take a break. Dialogue: 0,0:28:12.54,0:28:24.94,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:28:47.93,0:28:48.70,EN,,0,0,0,,PROFESSOR: Well, let's see. Dialogue: 0,0:28:49.37,0:28:52.46,EN,,0,0,0,,Now you know how to make an iterative procedure, Dialogue: 0,0:28:52.54,0:28:54.54,EN,,0,0,0,,or a procedure that yields an iterative process, Dialogue: 0,0:28:55.18,0:28:56.52,EN,,0,0,0,,turn into a machine. Dialogue: 0,0:28:57.77,0:29:00.04,EN,,0,0,0,,I suppose the next thing we want to do is worry about things Dialogue: 0,0:29:00.54,0:29:02.30,EN,,0,0,0,,that reveal recursive processes. Dialogue: 0,0:29:02.81,0:29:05.05,EN,,0,0,0,,So let's play with a simple factorial procedure. Dialogue: 0,0:29:11.20,0:29:16.94,EN,,0,0,0,,We define factorial of N to be Dialogue: 0,0:29:19.63,0:29:24.25,EN,,0,0,0,,if n is 1, the result is 1, Dialogue: 0,0:29:24.62,0:29:27.69,EN,,0,0,0,,using 1 right now to decrease the amount of work I have to do to simulate it, Dialogue: 0,0:29:28.12,0:29:33.94,EN,,0,0,0,,else it's times N factorial N minus 1. Dialogue: 0,0:29:42.52,0:29:46.04,EN,,0,0,0,,And what's different with this program, as you know, Dialogue: 0,0:29:46.65,0:29:50.36,EN,,0,0,0,,is that after I've computed factorial of N minus 1 here, Dialogue: 0,0:29:50.67,0:29:52.26,EN,,0,0,0,,I have to do something to the result. Dialogue: 0,0:29:52.26,0:29:53.68,EN,,0,0,0,,I have to multiply it by N. Dialogue: 0,0:29:56.00,0:30:00.67,EN,,0,0,0,,So the only way I can visualize what this machine is doing, Dialogue: 0,0:30:01.08,0:30:02.01,EN,,0,0,0,,because of the fact-- Dialogue: 0,0:30:02.35,0:30:03.18,EN,,0,0,0,,think of it this way, Dialogue: 0,0:30:03.36,0:30:04.94,EN,,0,0,0,,that I have a machine out here Dialogue: 0,0:30:05.08,0:30:08.11,EN,,0,0,0,,which somehow needs a factorial machine in order to compute its answer. Dialogue: 0,0:30:09.32,0:30:11.16,EN,,0,0,0,,But this machine, the outer machine, Dialogue: 0,0:30:11.20,0:30:13.02,EN,,0,0,0,,has to exist before and after Dialogue: 0,0:30:13.92,0:30:15.72,EN,,0,0,0,,the factorial machine, which is inside. Dialogue: 0,0:30:16.80,0:30:17.90,EN,,0,0,0,,Whereas in the iterative case, Dialogue: 0,0:30:18.75,0:30:20.52,EN,,0,0,0,,the outer machine doesn't need to exist Dialogue: 0,0:30:20.91,0:30:24.01,EN,,0,0,0,,after the inner machine is running, Dialogue: 0,0:30:24.83,0:30:26.16,EN,,0,0,0,,because you never need to go back Dialogue: 0,0:30:26.19,0:30:27.53,EN,,0,0,0,,to the outer machine to do anything. Dialogue: 0,0:30:28.64,0:30:30.06,EN,,0,0,0,,So here we have a problem Dialogue: 0,0:30:30.27,0:30:30.97,EN,,0,0,0,,where we have a machine Dialogue: 0,0:30:31.00,0:30:32.73,EN,,0,0,0,,which has the same machine inside of it, Dialogue: 0,0:30:33.87,0:30:35.52,EN,,0,0,0,,an infinitely large machine. Dialogue: 0,0:30:40.39,0:30:43.12,EN,,0,0,0,,And it's got other things inside of it, like a multiplier, Dialogue: 0,0:30:44.76,0:30:46.03,EN,,0,0,0,,which takes some inputs, Dialogue: 0,0:30:46.27,0:30:47.77,EN,,0,0,0,,and there's a minus 1 box, Dialogue: 0,0:30:48.12,0:30:49.31,EN,,0,0,0,,and things like that. Dialogue: 0,0:30:50.69,0:30:53.72,EN,,0,0,0,,You know, You can imagine that's what it looks like. Dialogue: 0,0:30:54.37,0:30:56.76,EN,,0,0,0,,But the important thing is that here I have Dialogue: 0,0:30:57.02,0:30:58.70,EN,,0,0,0,,something that happens before and after, Dialogue: 0,0:30:58.78,0:31:01.60,EN,,0,0,0,,in the outer machine, the execution of the inner machine. Dialogue: 0,0:31:02.54,0:31:04.08,EN,,0,0,0,,So this machine has to have a life. Dialogue: 0,0:31:05.47,0:31:11.44,EN,,0,0,0,,It has to exist on both times sides of this machine. Dialogue: 0,0:31:13.49,0:31:15.80,EN,,0,0,0,,So somehow, I have to have a place to store Dialogue: 0,0:31:16.19,0:31:18.19,EN,,0,0,0,,the things that this thing needs to run. Dialogue: 0,0:31:20.03,0:31:22.09,EN,,0,0,0,,Infinite objects don't exist in the real world. Dialogue: 0,0:31:24.14,0:31:25.58,EN,,0,0,0,,What we have to do is arrange an illusion Dialogue: 0,0:31:26.12,0:31:27.48,EN,,0,0,0,,that we have an infinite object, Dialogue: 0,0:31:27.98,0:31:29.77,EN,,0,0,0,,we have an infinite amount of hardware somewhere. Dialogue: 0,0:31:31.83,0:31:35.34,EN,,0,0,0,,Now of course, illusion's all that really matters. Dialogue: 0,0:31:36.28,0:31:37.37,EN,,0,0,0,,If we can arrange Dialogue: 0,0:31:38.00,0:31:39.84,EN,,0,0,0,,that every time you look at some infinite object, Dialogue: 0,0:31:39.88,0:31:42.96,EN,,0,0,0,,the part of it that you look at is there, Dialogue: 0,0:31:44.49,0:31:46.04,EN,,0,0,0,,then it's as infinite as you need it to be. Dialogue: 0,0:31:47.39,0:31:49.44,EN,,0,0,0,,And of course, one of the things we might want to do, Dialogue: 0,0:31:49.82,0:31:52.49,EN,,0,0,0,,just look at this thing over here, Dialogue: 0,0:31:53.00,0:31:54.97,EN,,0,0,0,,is the organization that we've had so far Dialogue: 0,0:31:56.04,0:31:57.64,EN,,0,0,0,,organization that we've had so far Dialogue: 0,0:31:57.92,0:32:01.37,EN,,0,0,0,,involves having a part of the machine, Dialogue: 0,0:32:01.40,0:32:02.33,EN,,0,0,0,,which is the controller, Dialogue: 0,0:32:03.18,0:32:04.46,EN,,0,0,0,,which sits right over here, Dialogue: 0,0:32:04.78,0:32:07.61,EN,,0,0,0,,which is perfectly finite and very simple. Dialogue: 0,0:32:09.17,0:32:10.44,EN,,0,0,0,,We have some datapaths, Dialogue: 0,0:32:10.46,0:32:12.75,EN,,0,0,0,,which consist of registers and operators. Dialogue: 0,0:32:13.08,0:32:15.20,EN,,0,0,0,,And what I propose to do here is decompose Dialogue: 0,0:32:15.48,0:32:16.96,EN,,0,0,0,,the machine into two parts, Dialogue: 0,0:32:17.36,0:32:19.79,EN,,0,0,0,,such that there is a part which is fundamentally finite, Dialogue: 0,0:32:20.78,0:32:23.53,EN,,0,0,0,,and some part where a certain amount of infinite stuff can be kept. Dialogue: 0,0:32:24.23,0:32:25.90,EN,,0,0,0,,On the other hand this is very simple Dialogue: 0,0:32:26.41,0:32:28.72,EN,,0,0,0,,and really isn't infinite, but it's just very large. Dialogue: 0,0:32:29.43,0:32:30.40,EN,,0,0,0,,But it's so simple Dialogue: 0,0:32:30.52,0:32:32.92,EN,,0,0,0,,that it could be cheaply reproduced in such large amounts, Dialogue: 0,0:32:34.09,0:32:34.92,EN,,0,0,0,,we call it memory, Dialogue: 0,0:32:35.95,0:32:39.07,EN,,0,0,0,,OK? that we can make a structure called a stack out of it Dialogue: 0,0:32:39.40,0:32:41.23,EN,,0,0,0,,which will allow us to, in fact, Dialogue: 0,0:32:41.45,0:32:43.63,EN,,0,0,0,,simulate the existence of an infinite machine Dialogue: 0,0:32:43.64,0:32:46.96,EN,,0,0,0,,which is made out of a recursive nest of many machines. Dialogue: 0,0:32:48.34,0:32:50.43,EN,,0,0,0,,And the way it's going to work is that Dialogue: 0,0:32:50.56,0:32:52.97,EN,,0,0,0,,we're going to store in this place called the stack Dialogue: 0,0:32:54.30,0:32:57.58,EN,,0,0,0,,the information required after the inner machine runs Dialogue: 0,0:32:59.18,0:33:01.07,EN,,0,0,0,,to resume the operation of the outer machine. Dialogue: 0,0:33:03.84,0:33:05.48,EN,,0,0,0,,So it will remember Dialogue: 0,0:33:05.63,0:33:07.95,EN,,0,0,0,,the important things about the life of the outer machine Dialogue: 0,0:33:08.04,0:33:10.30,EN,,0,0,0,,that will be needed for this computation. Dialogue: 0,0:33:11.39,0:33:12.48,EN,,0,0,0,,Since, of course, Dialogue: 0,0:33:12.75,0:33:16.33,EN,,0,0,0,,these machines are nested in a recursive manner, Dialogue: 0,0:33:18.33,0:33:23.39,EN,,0,0,0,,then in fact the stack will only be accessed in a manner Dialogue: 0,0:33:23.45,0:33:26.44,EN,,0,0,0,,which is the last thing that goes in is the first thing that comes out. Dialogue: 0,0:33:29.33,0:33:30.64,EN,,0,0,0,,So we'll only need to access Dialogue: 0,0:33:30.80,0:33:32.52,EN,,0,0,0,,some little part of this stack memory. Dialogue: 0,0:33:34.93,0:33:35.92,EN,,0,0,0,,OK, well, let's do it. Dialogue: 0,0:33:36.81,0:33:38.41,EN,,0,0,0,,I'm going to build you a datapath now, Dialogue: 0,0:33:38.44,0:33:39.68,EN,,0,0,0,,and I'm going to write the controller. Dialogue: 0,0:33:40.37,0:33:42.86,EN,,0,0,0,,And then we're going to execute this to see how you do it. Dialogue: 0,0:33:43.51,0:33:46.88,EN,,0,0,0,,So the factorial machine isn't so bad. Dialogue: 0,0:33:47.90,0:33:50.16,EN,,0,0,0,,It's going to have a register called the value, Dialogue: 0,0:33:52.22,0:33:53.88,EN,,0,0,0,,where the answer is going to be stored, Dialogue: 0,0:33:54.89,0:33:56.67,EN,,0,0,0,,and a registered called N, Dialogue: 0,0:33:59.85,0:34:04.16,EN,,0,0,0,,which is where the number I'm taking factorial will be stored, factorial of. Dialogue: 0,0:34:04.51,0:34:06.57,EN,,0,0,0,,And it will be necessary in some instances Dialogue: 0,0:34:07.48,0:34:10.52,EN,,0,0,0,,to connect VAL to N. Dialogue: 0,0:34:11.74,0:34:15.63,EN,,0,0,0,,In fact, one nice case of this is if I just said over here, Dialogue: 0,0:34:16.38,0:34:19.53,EN,,0,0,0,,N, because that would be right for N equal 1N. Dialogue: 0,0:34:20.09,0:34:23.26,EN,,0,0,0,,And I could just move the answer over there if that's important. Dialogue: 0,0:34:23.90,0:34:25.55,EN,,0,0,0,,I'm not worried about that right now. Dialogue: 0,0:34:26.98,0:34:28.60,EN,,0,0,0,,And there are things I have to be able to do. Dialogue: 0,0:34:29.06,0:34:31.02,EN,,0,0,0,,Like I have to be able to, as we see here, Dialogue: 0,0:34:31.21,0:34:34.67,EN,,0,0,0,,multiply N by something in VAL, Dialogue: 0,0:34:34.91,0:34:37.45,EN,,0,0,0,,because VAL is the result of computing factorial. Dialogue: 0,0:34:38.68,0:34:40.44,EN,,0,0,0,,And I have to put the result back into VAL. Dialogue: 0,0:34:41.48,0:34:42.65,EN,,0,0,0,,So here we can see Dialogue: 0,0:34:42.83,0:34:46.43,EN,,0,0,0,,that the result of computing a factorial Dialogue: 0,0:34:46.57,0:34:49.20,EN,,0,0,0,,is N times the result of computing a factorial. Dialogue: 0,0:34:50.69,0:34:53.77,EN,,0,0,0,,VAL will be the representation of the answer of the inner factorial. Dialogue: 0,0:34:55.19,0:35:00.25,EN,,0,0,0,,And so I'm going to have to have a multiplier here, Dialogue: 0,0:35:02.36,0:35:07.18,EN,,0,0,0,,which is going to sample the value of N and the value of VAL Dialogue: 0,0:35:08.64,0:35:15.60,EN,,0,0,0,,OK? and put the result back into VAL like that. Dialogue: 0,0:35:17.17,0:35:19.39,EN,,0,0,0,,I'm also going to have to be able to see if N is 1. Dialogue: 0,0:35:21.32,0:35:22.38,EN,,0,0,0,,So I need a light bulb. Dialogue: 0,0:35:28.20,0:35:30.40,EN,,0,0,0,,And I suppose the other thing I'm going to need to have Dialogue: 0,0:35:31.02,0:35:32.84,EN,,0,0,0,,is a way of decrementing N. Dialogue: 0,0:35:34.84,0:35:36.09,EN,,0,0,0,,So I'm going to have a decrementer, Dialogue: 0,0:35:38.19,0:35:41.39,EN,,0,0,0,,which takes N and is going to put back the result into N. Dialogue: 0,0:35:46.62,0:35:48.40,EN,,0,0,0,,That's pretty much what I need in my machine. Dialogue: 0,0:35:49.55,0:35:51.64,EN,,0,0,0,,Now, there's a little bit else I need. Dialogue: 0,0:35:52.30,0:35:53.58,EN,,0,0,0,,It's a little bit more complicated, Dialogue: 0,0:35:55.16,0:35:56.88,EN,,0,0,0,,because I'm also going to need a way to store, Dialogue: 0,0:35:57.16,0:35:59.69,EN,,0,0,0,,to save away, the things that are going to be needed Dialogue: 0,0:36:01.02,0:36:03.07,EN,,0,0,0,,for resuming the computation of a factorial Dialogue: 0,0:36:03.10,0:36:04.89,EN,,0,0,0,,after I've done a sub-factorial. Dialogue: 0,0:36:06.25,0:36:06.86,EN,,0,0,0,,What's that? Dialogue: 0,0:36:07.23,0:36:08.73,EN,,0,0,0,,One thing I need is N. Dialogue: 0,0:36:09.85,0:36:12.04,EN,,0,0,0,,So I'm going to build here a thing called a stack. Dialogue: 0,0:36:14.70,0:36:15.77,EN,,0,0,0,,The stack is Dialogue: 0,0:36:17.98,0:36:24.97,EN,,0,0,0,,a bunch of stuff that I'm going to write in sequentially. Dialogue: 0,0:36:27.15,0:36:28.59,EN,,0,0,0,,I don't know how long it is. Dialogue: 0,0:36:29.15,0:36:31.48,EN,,0,0,0,,The longer it is, the better my illusion of infinity. Dialogue: 0,0:36:33.23,0:36:35.56,EN,,0,0,0,,And I'm going to have to have a way of getting stuff Dialogue: 0,0:36:35.60,0:36:37.02,EN,,0,0,0,,out of N and into the stack Dialogue: 0,0:36:38.12,0:36:39.08,EN,,0,0,0,,and vice versa. Dialogue: 0,0:36:39.93,0:36:41.74,EN,,0,0,0,,So I'm going to need a connection like this, Dialogue: 0,0:36:44.41,0:36:45.48,EN,,0,0,0,,which is two-way, Dialogue: 0,0:36:50.44,0:36:52.22,EN,,0,0,0,,whereby I can save the value of N Dialogue: 0,0:36:52.24,0:36:55.50,EN,,0,0,0,,and then restore it some other time through that connection. Dialogue: 0,0:36:56.04,0:36:56.84,EN,,0,0,0,,This is the stack. Dialogue: 0,0:36:58.10,0:37:01.71,EN,,0,0,0,,I also need a way of remembering Dialogue: 0,0:37:01.84,0:37:07.72,EN,,0,0,0,,where I was in the computation of factorial in the outer program. Dialogue: 0,0:37:08.53,0:37:10.06,EN,,0,0,0,,Now in the case of this machine, Dialogue: 0,0:37:10.76,0:37:13.34,EN,,0,0,0,,it isn't very much a problem. Dialogue: 0,0:37:14.17,0:37:16.24,EN,,0,0,0,,Factorial always returns, Dialogue: 0,0:37:16.86,0:37:19.07,EN,,0,0,0,,has to go back to the place where we multiply by N, Dialogue: 0,0:37:19.34,0:37:20.72,EN,,0,0,0,,except for the last time, Dialogue: 0,0:37:21.15,0:37:23.02,EN,,0,0,0,,when it has to return to whatever needs the factorial Dialogue: 0,0:37:23.04,0:37:24.04,EN,,0,0,0,,or go to done or stop. Dialogue: 0,0:37:25.66,0:37:26.67,EN,,0,0,0,,However, in general, Dialogue: 0,0:37:27.16,0:37:28.73,EN,,0,0,0,,I'm going to have to remember where I have been, Dialogue: 0,0:37:29.13,0:37:31.24,EN,,0,0,0,,because I might have computed factorial from somewhere else. Dialogue: 0,0:37:32.08,0:37:34.89,EN,,0,0,0,,I have to go back to that place and continue there. Dialogue: 0,0:37:36.07,0:37:38.00,EN,,0,0,0,,So I'm going to have to have some way of taking the place Dialogue: 0,0:37:38.01,0:37:40.86,EN,,0,0,0,,where the marble is in the finite state controller, Dialogue: 0,0:37:41.32,0:37:42.64,EN,,0,0,0,,the state of the controller, Dialogue: 0,0:37:44.22,0:37:46.35,EN,,0,0,0,,and storing that in the stack as well. Dialogue: 0,0:37:47.40,0:37:49.10,EN,,0,0,0,,And I'm going to have to have ways of restoring that Dialogue: 0,0:37:49.45,0:37:51.12,EN,,0,0,0,,back to the state of the-- the marble. Dialogue: 0,0:37:52.14,0:37:54.28,EN,,0,0,0,,So I have to have something that moves the marble to the right place. Dialogue: 0,0:37:54.70,0:37:56.52,EN,,0,0,0,,Well, we're going to have a place which is the marble now. Dialogue: 0,0:37:57.87,0:37:59.34,EN,,0,0,0,,And it's called the continue register, Dialogue: 0,0:38:03.61,0:38:04.52,EN,,0,0,0,,called continue, Dialogue: 0,0:38:09.16,0:38:10.68,EN,,0,0,0,,which is the place to put the marble Dialogue: 0,0:38:11.00,0:38:13.05,EN,,0,0,0,,next time I go to continue. Dialogue: 0,0:38:14.91,0:38:15.92,EN,,0,0,0,,That's what that's for. Dialogue: 0,0:38:16.14,0:38:18.48,EN,,0,0,0,,And so there's got to be some path from that into the controller. Dialogue: 0,0:38:22.91,0:38:27.12,EN,,0,0,0,,I also have to have some way of saving that on the stack. Dialogue: 0,0:38:29.45,0:38:33.10,EN,,0,0,0,,And I have to have some way of setting that up to have various constants, Dialogue: 0,0:38:34.01,0:38:35.69,EN,,0,0,0,,a certain fixed number of constants. Dialogue: 0,0:38:36.86,0:38:38.20,EN,,0,0,0,,And that's very easy to arrange. Dialogue: 0,0:38:38.84,0:38:40.14,EN,,0,0,0,,So let's have some constants here. Dialogue: 0,0:38:40.18,0:38:41.50,EN,,0,0,0,,We'll call this one after-fact. Dialogue: 0,0:38:47.32,0:38:48.75,EN,,0,0,0,,And that's a constant Dialogue: 0,0:38:48.84,0:38:51.50,EN,,0,0,0,,which will get into the continue register, Dialogue: 0,0:38:52.59,0:38:54.43,EN,,0,0,0,,and also another one called fact-done. Dialogue: 0,0:39:05.21,0:39:07.82,EN,,0,0,0,,So this is the machine I want to build. Dialogue: 0,0:39:08.13,0:39:09.48,EN,,0,0,0,,That's its datapaths, at least. Dialogue: 0,0:39:09.92,0:39:11.69,EN,,0,0,0,,And it mixes a little with the controller here, Dialogue: 0,0:39:11.85,0:39:14.59,EN,,0,0,0,,because of the fact that I have to remember where I was Dialogue: 0,0:39:14.70,0:39:16.35,EN,,0,0,0,,and restore myself to that place. Dialogue: 0,0:39:17.30,0:39:19.93,EN,,0,0,0,,But let's write the program now which represents the controller. Dialogue: 0,0:39:20.39,0:39:23.47,EN,,0,0,0,,I'm not going to write the define machine thing and the register list, Dialogue: 0,0:39:23.48,0:39:24.89,EN,,0,0,0,,because that's not very interesting. Dialogue: 0,0:39:25.13,0:39:27.79,EN,,0,0,0,,I'm just going to write down the sequence of instructions Dialogue: 0,0:39:27.82,0:39:29.02,EN,,0,0,0,,that constitute the controller. Dialogue: 0,0:39:31.48,0:39:41.85,EN,,0,0,0,,So we have assign, to set up, continue to done. Dialogue: 0,0:39:45.15,0:39:45.82,EN,,0,0,0,,We have a loop Dialogue: 0,0:39:47.34,0:39:56.08,EN,,0,0,0,,which says branch if equal 1 fetch N, Dialogue: 0,0:40:00.94,0:40:04.11,EN,,0,0,0,,if N is 1, then go to the base step of the induction, Dialogue: 0,0:40:06.06,0:40:07.20,EN,,0,0,0,,the simple case. Dialogue: 0,0:40:08.05,0:40:08.76,EN,,0,0,0,,Otherwise, Dialogue: 0,0:40:08.88,0:40:10.84,EN,,0,0,0,,I have to remember the things that are necessary Dialogue: 0,0:40:10.88,0:40:13.84,EN,,0,0,0,,to perform a sub-factorial. Dialogue: 0,0:40:14.67,0:40:16.75,EN,,0,0,0,,I'm going to go over here, and I have to perform a sub-factorial. Dialogue: 0,0:40:17.57,0:40:19.29,EN,,0,0,0,,So I have to remember what's needed to do that Dialogue: 0,0:40:19.71,0:40:22.52,EN,,0,0,0,,remember what's needed after I will be done with that. Dialogue: 0,0:40:24.00,0:40:25.51,EN,,0,0,0,,See, I'm about to do something terrible. Dialogue: 0,0:40:25.72,0:40:27.39,EN,,0,0,0,,I'm about to change the value of N. Dialogue: 0,0:40:28.57,0:40:30.40,EN,,0,0,0,,But this guy has to know the old value of N. Dialogue: 0,0:40:32.14,0:40:33.64,EN,,0,0,0,,But in order to make the sub-factorial work, Dialogue: 0,0:40:33.66,0:40:34.92,EN,,0,0,0,,I have to change the value of N. Dialogue: 0,0:40:35.60,0:40:37.10,EN,,0,0,0,,So I have to remember the old value. Dialogue: 0,0:40:38.00,0:40:39.60,EN,,0,0,0,,And I also have to remember where I've been. Dialogue: 0,0:40:40.85,0:40:42.32,EN,,0,0,0,,So I save up continue. Dialogue: 0,0:40:47.70,0:40:51.29,EN,,0,0,0,,And this is an instruction that says, put something in the stack. Dialogue: 0,0:40:53.12,0:40:55.53,EN,,0,0,0,,Save the contents of the continuation register, Dialogue: 0,0:40:56.51,0:40:58.00,EN,,0,0,0,,which in this case is done, Dialogue: 0,0:40:58.88,0:41:00.25,EN,,0,0,0,,because later I'm going to change that, too, Dialogue: 0,0:41:00.27,0:41:02.78,EN,,0,0,0,,because I need to go back to after-fact, as well. Dialogue: 0,0:41:03.55,0:41:04.19,EN,,0,0,0,,We'll see that. Dialogue: 0,0:41:05.04,0:41:09.71,EN,,0,0,0,,We save N, because I'm going to need that for later. Dialogue: 0,0:41:10.38,0:41:20.54,EN,,0,0,0,,Assign to N the decrement of fetch N. Dialogue: 0,0:41:23.26,0:41:28.97,EN,,0,0,0,,Assign continue, Dialogue: 0,0:41:32.12,0:41:33.42,EN,,0,0,0,,we're going to look at this now, Dialogue: 0,0:41:34.06,0:41:35.61,EN,,0,0,0,,to after, we'll call it. Dialogue: 0,0:41:37.69,0:41:38.70,EN,,0,0,0,,That's a good name for this, Dialogue: 0,0:41:38.73,0:41:40.65,EN,,0,0,0,,a little bit easier and shorter, and fits in here. Dialogue: 0,0:41:53.36,0:41:54.64,EN,,0,0,0,,Now look what I'm doing here. Dialogue: 0,0:41:55.33,0:41:57.02,EN,,0,0,0,,I'm saying, if the answer is 1, Dialogue: 0,0:41:58.72,0:41:59.66,EN,,0,0,0,,OK, I'm done. Dialogue: 0,0:42:00.46,0:42:01.66,EN,,0,0,0,,I'm going to have to just get the answer. Dialogue: 0,0:42:02.15,0:42:04.88,EN,,0,0,0,,Otherwise, I'm going to save the continuation, save N, Dialogue: 0,0:42:05.77,0:42:07.32,EN,,0,0,0,,make N one less than N, Dialogue: 0,0:42:07.60,0:42:09.63,EN,,0,0,0,,remember I'm going to come back to someplace else, Dialogue: 0,0:42:09.64,0:42:11.48,EN,,0,0,0,,and go back and start doing another factorial. Dialogue: 0,0:42:13.50,0:42:15.74,EN,,0,0,0,,OK? However, I've got a different machine in me now. Dialogue: 0,0:42:16.05,0:42:18.38,EN,,0,0,0,,N is 1, and continue is something else. Dialogue: 0,0:42:22.11,0:42:23.21,EN,,0,0,0,,N is N minus 1. Dialogue: 0,0:42:23.77,0:42:25.28,EN,,0,0,0,,Now after I'm done with that, Dialogue: 0,0:42:26.94,0:42:27.76,EN,,0,0,0,,I can go there. Dialogue: 0,0:42:28.66,0:42:30.46,EN,,0,0,0,,I will restore the old value of N, Dialogue: 0,0:42:32.68,0:42:36.56,EN,,0,0,0,,which is the opposite of this save over here. Dialogue: 0,0:42:38.36,0:42:39.88,EN,,0,0,0,,I will restore the continuation. Dialogue: 0,0:42:49.66,0:42:52.57,EN,,0,0,0,,I will then go to here. Dialogue: 0,0:42:54.32,0:43:00.86,EN,,0,0,0,,I will assign to the VAL register Dialogue: 0,0:43:01.16,0:43:08.13,EN,,0,0,0,,the product of N and fetch VAL. Dialogue: 0,0:43:13.44,0:43:18.30,EN,,0,0,0,,VAL fetch product assign. Dialogue: 0,0:43:19.79,0:43:21.44,EN,,0,0,0,,And then I will be done. Dialogue: 0,0:43:21.44,0:43:25.68,EN,,0,0,0,,I will have my answer to the sub-factorial in VAL. Dialogue: 0,0:43:26.57,0:43:27.37,EN,,0,0,0,,At that point, Dialogue: 0,0:43:27.66,0:43:28.75,EN,,0,0,0,,I'm going to return Dialogue: 0,0:43:29.28,0:43:31.61,EN,,0,0,0,,by going to the place where the continuation is pointing. Dialogue: 0,0:43:33.64,0:43:35.77,EN,,0,0,0,,That says, go to fetch continue. Dialogue: 0,0:43:45.87,0:43:47.40,EN,,0,0,0,,And then I have finally a base step, Dialogue: 0,0:43:49.31,0:43:50.51,EN,,0,0,0,,which is the immediate answer. Dialogue: 0,0:43:50.68,0:43:56.88,EN,,0,0,0,,Assign to VAL fetch N, Dialogue: 0,0:44:01.36,0:44:02.75,EN,,0,0,0,,and go to fetch continue. Dialogue: 0,0:44:12.67,0:44:13.55,EN,,0,0,0,,And then I'm done. Dialogue: 0,0:44:18.64,0:44:21.21,EN,,0,0,0,,Now let's see how this executes on a very simple case, Dialogue: 0,0:44:22.51,0:44:23.53,EN,,0,0,0,,because then we'll see Dialogue: 0,0:44:23.66,0:44:26.52,EN,,0,0,0,,the use of this stack to do the job we need. Dialogue: 0,0:44:26.89,0:44:28.22,EN,,0,0,0,,This is statically what it's doing, Dialogue: 0,0:44:28.22,0:44:29.80,EN,,0,0,0,,but we have look dynamically at this. Dialogue: 0,0:44:31.34,0:44:32.09,EN,,0,0,0,,So let's see. Dialogue: 0,0:44:32.30,0:44:34.56,EN,,0,0,0,,First thing we do is continue gets done. Dialogue: 0,0:44:36.73,0:44:38.09,EN,,0,0,0,,The way that happened is I pushed this. Dialogue: 0,0:44:38.30,0:44:39.60,EN,,0,0,0,,Let's call that done the way I have it. Dialogue: 0,0:44:46.22,0:44:47.03,EN,,0,0,0,,I push that button. Dialogue: 0,0:44:47.03,0:44:48.11,EN,,0,0,0,,Done goes into there. Dialogue: 0,0:44:48.95,0:44:53.71,EN,,0,0,0,,Now I also have to set this thing up to have an initial value. Dialogue: 0,0:44:53.85,0:44:58.08,EN,,0,0,0,,Let's consider a factorial of three, Dialogue: 0,0:44:58.38,0:44:59.24,EN,,0,0,0,,a simple case. Dialogue: 0,0:45:00.54,0:45:04.04,EN,,0,0,0,,And we're going to start out with our stack growing over here. Dialogue: 0,0:45:05.90,0:45:07.76,EN,,0,0,0,,Stacks have their own little internal state Dialogue: 0,0:45:07.79,0:45:09.05,EN,,0,0,0,,saying where they are, Dialogue: 0,0:45:09.80,0:45:11.64,EN,,0,0,0,,where the next place I'm going to write is. Dialogue: 0,0:45:12.77,0:45:14.59,EN,,0,0,0,,So now we say, is N 1? Dialogue: 0,0:45:14.76,0:45:15.71,EN,,0,0,0,,The answer is no. Dialogue: 0,0:45:16.11,0:45:18.56,EN,,0,0,0,,So now I'm going to save continue, bang. Dialogue: 0,0:45:19.15,0:45:20.65,EN,,0,0,0,,Now that done goes in here. Dialogue: 0,0:45:22.08,0:45:23.55,EN,,0,0,0,,And this moves to here, Dialogue: 0,0:45:24.88,0:45:26.14,EN,,0,0,0,,the next place I'm going to write. Dialogue: 0,0:45:26.66,0:45:28.78,EN,,0,0,0,,Save N 3. Dialogue: 0,0:45:29.95,0:45:30.32,EN,,0,0,0,,OK? Dialogue: 0,0:45:30.67,0:45:33.61,EN,,0,0,0,,Assign to N the decrement of N. Dialogue: 0,0:45:33.96,0:45:35.37,EN,,0,0,0,,That means I've pushed this button. Dialogue: 0,0:45:35.94,0:45:37.32,EN,,0,0,0,,This becomes 2. Dialogue: 0,0:45:38.73,0:45:42.28,EN,,0,0,0,,OK? Assign to continue aft. Dialogue: 0,0:45:42.58,0:45:43.61,EN,,0,0,0,,So I've pushed that button. Dialogue: 0,0:45:43.61,0:45:44.54,EN,,0,0,0,,Aft goes in here. Dialogue: 0,0:45:49.14,0:45:53.93,EN,,0,0,0,,OK, now go to loop, bang, so up to here. Dialogue: 0,0:45:54.83,0:45:57.08,EN,,0,0,0,,Is N 1? No Dialogue: 0,0:45:57.78,0:45:59.23,EN,,0,0,0,,So I have to save continue. Dialogue: 0,0:45:59.49,0:46:00.27,EN,,0,0,0,,What's continue? Dialogue: 0,0:46:00.60,0:46:01.53,EN,,0,0,0,,Continue is aft. Dialogue: 0,0:46:01.53,0:46:02.32,EN,,0,0,0,,Push this button. Dialogue: 0,0:46:02.78,0:46:03.95,EN,,0,0,0,,So this moves to here. Dialogue: 0,0:46:08.49,0:46:09.74,EN,,0,0,0,,I have to save N. Dialogue: 0,0:46:10.51,0:46:12.12,EN,,0,0,0,,N is over here. I got to 2. Dialogue: 0,0:46:12.28,0:46:13.37,EN,,0,0,0,,Push that button. Dialogue: 0,0:46:13.85,0:46:15.24,EN,,0,0,0,,So a 2 gets written there. Dialogue: 0,0:46:16.05,0:46:17.64,EN,,0,0,0,,And then this thing moves down here. Dialogue: 0,0:46:20.06,0:46:22.60,EN,,0,0,0,,OK, save N. Assign N to the decrement of N. Dialogue: 0,0:46:24.60,0:46:25.46,EN,,0,0,0,,This becomes a 1. Dialogue: 0,0:46:29.24,0:46:30.54,EN,,0,0,0,,Assign continue to aft. Dialogue: 0,0:46:31.37,0:46:34.48,EN,,0,0,0,,A-F-T gets written there again. Dialogue: 0,0:46:34.96,0:46:35.64,EN,,0,0,0,,Go to loop. Dialogue: 0,0:46:36.52,0:46:37.74,EN,,0,0,0,,Is N equal to 1? Dialogue: 0,0:46:37.93,0:46:39.52,EN,,0,0,0,,Oh, yes, the answer is 1. Dialogue: 0,0:46:41.04,0:46:43.26,EN,,0,0,0,,OK, go to base step. Dialogue: 0,0:46:44.16,0:46:45.77,EN,,0,0,0,,Assign to VAL fetch of N. Dialogue: 0,0:46:46.56,0:46:50.72,EN,,0,0,0,,Bang, 1 gets put in there. OK? Dialogue: 0,0:46:51.10,0:46:52.20,EN,,0,0,0,,Go to fetch continue. Dialogue: 0,0:46:52.20,0:46:53.53,EN,,0,0,0,,So we look in continue. Dialogue: 0,0:46:53.68,0:46:56.06,EN,,0,0,0,,Basically, I'm pushing a button over here that goes to the controller. Dialogue: 0,0:46:56.67,0:46:58.28,EN,,0,0,0,,The continue becomes aft, Dialogue: 0,0:46:58.32,0:47:00.25,EN,,0,0,0,,and all of a sudden, the program's running here. Dialogue: 0,0:47:02.64,0:47:05.63,EN,,0,0,0,,I now have to restore the outer version of factorial. Dialogue: 0,0:47:06.65,0:47:07.55,EN,,0,0,0,,So we go here. Dialogue: 0,0:47:07.55,0:47:09.48,EN,,0,0,0,,We say, restore N. Dialogue: 0,0:47:10.32,0:47:13.04,EN,,0,0,0,,So restore N means take the contents that's here. Dialogue: 0,0:47:13.94,0:47:18.17,EN,,0,0,0,,Push this button, and it goes into here, 2, Dialogue: 0,0:47:18.56,0:47:20.04,EN,,0,0,0,,and the pointer moves up. Dialogue: 0,0:47:21.98,0:47:24.49,EN,,0,0,0,,Restore continue, pretty easy. Dialogue: 0,0:47:24.81,0:47:26.49,EN,,0,0,0,,Go push this button. Dialogue: 0,0:47:27.02,0:47:28.92,EN,,0,0,0,,And then aft gets written in here again. Dialogue: 0,0:47:31.28,0:47:32.64,EN,,0,0,0,,That means this thing moves up. Dialogue: 0,0:47:32.64,0:47:35.19,EN,,0,0,0,,I've gotten rid of something else on my stack. Dialogue: 0,0:47:42.24,0:47:43.47,EN,,0,0,0,,Right, then I go to here, Dialogue: 0,0:47:43.87,0:47:47.15,EN,,0,0,0,,which says, assign to VAL the product of N and VAL. Dialogue: 0,0:47:47.85,0:47:50.57,EN,,0,0,0,,So I push this button over here, bang. Dialogue: 0,0:47:50.97,0:47:52.91,EN,,0,0,0,,2 times 1 gives me a 2, Dialogue: 0,0:47:54.01,0:47:54.75,EN,,0,0,0,,get written there. Dialogue: 0,0:47:55.76,0:47:57.20,EN,,0,0,0,,OK? Go to fetch continue. Dialogue: 0,0:47:57.54,0:47:59.85,EN,,0,0,0,,Continue is aft. I go to aft. Dialogue: 0,0:48:01.15,0:48:03.88,EN,,0,0,0,,OK? Aft says restore N. Dialogue: 0,0:48:04.36,0:48:05.72,EN,,0,0,0,,Do your restore N, Dialogue: 0,0:48:05.87,0:48:08.44,EN,,0,0,0,,means I take the value over here, which is 3, Dialogue: 0,0:48:09.24,0:48:10.33,EN,,0,0,0,,push this up to here, Dialogue: 0,0:48:10.60,0:48:15.50,EN,,0,0,0,,and move it into here, N. Dialogue: 0,0:48:16.25,0:48:17.34,EN,,0,0,0,,Now it's pushing that button. Dialogue: 0,0:48:18.01,0:48:19.90,EN,,0,0,0,,The next thing I do is restore continue. Dialogue: 0,0:48:20.20,0:48:22.20,EN,,0,0,0,,Continue is now going to become done. Dialogue: 0,0:48:22.83,0:48:26.78,EN,,0,0,0,,So this moves up here when I push this button. Dialogue: 0,0:48:27.13,0:48:29.72,EN,,0,0,0,,Done may or may be there anymore, Dialogue: 0,0:48:29.72,0:48:31.55,EN,,0,0,0,,I'm not interested, but it certainly is here. Dialogue: 0,0:48:35.80,0:48:38.12,EN,,0,0,0,,Next thing I do is assign to VAL Dialogue: 0,0:48:38.43,0:48:40.76,EN,,0,0,0,,the product of the fetch of N and the fetch of VAL. Dialogue: 0,0:48:41.44,0:48:44.30,EN,,0,0,0,,That's pushing this button over here, bang. Dialogue: 0,0:48:44.30,0:48:45.77,EN,,0,0,0,,2 times 3 is 6. Dialogue: 0,0:48:46.52,0:48:47.87,EN,,0,0,0,,So I get a 6 over here. Dialogue: 0,0:48:50.97,0:48:53.40,EN,,0,0,0,,OK? And go to fetch continue, Dialogue: 0,0:48:53.48,0:48:54.83,EN,,0,0,0,,whoops, I go to done, and I'm done. Dialogue: 0,0:48:55.02,0:48:56.09,EN,,0,0,0,,And my answer is 6, Dialogue: 0,0:48:56.60,0:48:57.82,EN,,0,0,0,,as you can see in the VAL register. Dialogue: 0,0:48:58.95,0:48:59.82,EN,,0,0,0,,And in fact, Dialogue: 0,0:49:00.91,0:49:03.34,EN,,0,0,0,,the stack is in the state it originally was in. Dialogue: 0,0:49:08.20,0:49:10.70,EN,,0,0,0,,Now there's a bit of discipline in using these things like stacks Dialogue: 0,0:49:11.20,0:49:12.27,EN,,0,0,0,,that we have to be careful of. Dialogue: 0,0:49:13.62,0:49:15.52,EN,,0,0,0,,And we'll see that in the next segment. Dialogue: 0,0:49:16.26,0:49:18.46,EN,,0,0,0,,But first I want to ask if there are any questions for this. Dialogue: 0,0:49:28.56,0:49:29.64,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:49:30.17,0:49:30.63,EN,,0,0,0,,Yes, Ron. Dialogue: 0,0:49:30.63,0:49:33.37,EN,,0,0,0,,AUDIENCE: What happens when you roll off the end of the stack with-- Dialogue: 0,0:49:33.39,0:49:34.62,EN,,0,0,0,,PROFESSOR: What do you mean, roll off of? Dialogue: 0,0:49:35.03,0:49:37.50,EN,,0,0,0,,AUDIENCE: Well, the largest number-- a larger starting point of N Dialogue: 0,0:49:37.52,0:49:38.72,EN,,0,0,0,,requires more memory, correct? Dialogue: 0,0:49:38.86,0:49:39.44,EN,,0,0,0,,PROFESSOR: Oh, yes. Dialogue: 0,0:49:39.44,0:49:41.12,EN,,0,0,0,,Well, I need to have a long enough stack. Dialogue: 0,0:49:41.53,0:49:43.20,EN,,0,0,0,,You say, what if I violate my illusion? Dialogue: 0,0:49:43.84,0:49:44.12,EN,,0,0,0,,AUDIENCE: Yes. Dialogue: 0,0:49:44.55,0:49:46.73,EN,,0,0,0,,PROFESSOR: Well, then the magic doesn't work. OK? Dialogue: 0,0:49:47.96,0:49:51.00,EN,,0,0,0,,The truth of the matter is that every machine is finite. Dialogue: 0,0:49:51.64,0:49:53.72,EN,,0,0,0,,And for a procedure like this, Dialogue: 0,0:49:54.17,0:49:58.86,EN,,0,0,0,,there's a limit to the number of sub-factorials I could have. Dialogue: 0,0:49:59.95,0:50:02.48,EN,,0,0,0,,Remember when we were doing the y-operator a while ago, Dialogue: 0,0:50:02.80,0:50:06.22,EN,,0,0,0,,we pointed out that there was a sequence of exponentiation procedures, Dialogue: 0,0:50:06.25,0:50:08.09,EN,,0,0,0,,each of which was a little better than the previous one. Dialogue: 0,0:50:08.72,0:50:11.60,EN,,0,0,0,,Well, we're now seeing how we implement that mathematical idea. Dialogue: 0,0:50:13.09,0:50:14.19,EN,,0,0,0,,The limiting process Dialogue: 0,0:50:14.35,0:50:16.33,EN,,0,0,0,,is only so good as as far as you take the limit. Dialogue: 0,0:50:17.99,0:50:19.42,EN,,0,0,0,,If you think about it, what am I using here? Dialogue: 0,0:50:19.42,0:50:22.65,EN,,0,0,0,,I'm using about two chunks, pieces of memory Dialogue: 0,0:50:23.04,0:50:27.07,EN,,0,0,0,,for iteration for every recursion of this process. Dialogue: 0,0:50:29.10,0:50:31.71,EN,,0,0,0,,If we try to compute factorial of 10,000, Dialogue: 0,0:50:31.72,0:50:32.81,EN,,0,0,0,,that's not a lot of memory. Dialogue: 0,0:50:33.18,0:50:34.68,EN,,0,0,0,,On the other hand, it's an awful big number. Dialogue: 0,0:50:35.95,0:50:38.41,EN,,0,0,0,,So the question is, is that a valuable thing in this case. Dialogue: 0,0:50:39.18,0:50:42.19,EN,,0,0,0,,But it really turns out not to be a terrible limit, Dialogue: 0,0:50:42.22,0:50:43.53,EN,,0,0,0,,because memory is el cheapo, Dialogue: 0,0:50:44.16,0:50:45.34,EN,,0,0,0,,and people are pretty expensive. Dialogue: 0,0:50:48.13,0:50:50.22,EN,,0,0,0,,OK, thank you, let's take a break. Dialogue: 0,0:50:50.78,0:51:07.60,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:51:56.11,0:51:57.04,EN,,0,0,0,,PROFESSOR: Well, let's see. Dialogue: 0,0:51:58.70,0:52:03.37,EN,,0,0,0,,What I've shown you now is how to do a simple iterative process Dialogue: 0,0:52:03.69,0:52:05.31,EN,,0,0,0,,and a simple recursive process. Dialogue: 0,0:52:05.64,0:52:08.68,EN,,0,0,0,,I just want to summarize the design of simple machines Dialogue: 0,0:52:09.63,0:52:11.12,EN,,0,0,0,,for specific applications Dialogue: 0,0:52:11.21,0:52:13.58,EN,,0,0,0,,by showing you a little bit more complicated design, Dialogue: 0,0:52:13.96,0:52:17.13,EN,,0,0,0,,that of a thing that does doubly recursive Fibonacci, Dialogue: 0,0:52:17.23,0:52:19.88,EN,,0,0,0,,because it will indicate to us, and we'll understand, Dialogue: 0,0:52:20.04,0:52:22.68,EN,,0,0,0,,a bit about the conventions required Dialogue: 0,0:52:22.76,0:52:25.04,EN,,0,0,0,,for making stacks operate correctly. Dialogue: 0,0:52:26.40,0:52:27.11,EN,,0,0,0,,So let's see. Dialogue: 0,0:52:27.11,0:52:28.27,EN,,0,0,0,,I'm just going to write down, first of all, Dialogue: 0,0:52:28.30,0:52:29.71,EN,,0,0,0,,the program I'm going to translate. Dialogue: 0,0:52:34.15,0:52:36.52,EN,,0,0,0,,I need a Fibonacci procedure, Dialogue: 0,0:52:39.23,0:52:41.58,EN,,0,0,0,,it's very simple, which says, if Dialogue: 0,0:52:44.60,0:52:48.56,EN,,0,0,0,,N is less than 2, the result is N, Dialogue: 0,0:52:49.26,0:52:55.34,EN,,0,0,0,,otherwise it's the sum of Fib of N minus 1 Dialogue: 0,0:52:58.44,0:52:59.85,EN,,0,0,0,,and Fib of N minus 2. Dialogue: 0,0:53:07.05,0:53:09.29,EN,,0,0,0,,That's the plan I have here. Dialogue: 0,0:53:09.29,0:53:12.56,EN,,0,0,0,,And we're just going to write down the controller for such a machine. Dialogue: 0,0:53:13.07,0:53:15.53,EN,,0,0,0,,We're going to assume that there are registers, N, Dialogue: 0,0:53:15.56,0:53:19.15,EN,,0,0,0,,which holds the number we're taking Fibonacci of, Dialogue: 0,0:53:19.82,0:53:21.80,EN,,0,0,0,,VAL, which is where the answer is going to get put, Dialogue: 0,0:53:22.17,0:53:24.97,EN,,0,0,0,,and continue, which is the thing that's linked to the controller, Dialogue: 0,0:53:26.11,0:53:26.81,EN,,0,0,0,,like before. Dialogue: 0,0:53:26.96,0:53:29.21,EN,,0,0,0,,But I'm not going to draw another physical datapath, Dialogue: 0,0:53:31.53,0:53:34.00,EN,,0,0,0,,because it's pretty much the same as the last one you've seen. Dialogue: 0,0:53:34.36,0:53:37.84,EN,,0,0,0,,And of course, one of the most amazing things about computation Dialogue: 0,0:53:38.75,0:53:39.88,EN,,0,0,0,,is that after a while, Dialogue: 0,0:53:40.08,0:53:41.93,EN,,0,0,0,,you build up a little more features and a few more features, Dialogue: 0,0:53:41.95,0:53:43.32,EN,,0,0,0,,and all of the sudden, you've got everything you need. Dialogue: 0,0:53:44.75,0:53:47.60,EN,,0,0,0,,So it's remarkable that it just gets there so fast. Dialogue: 0,0:53:48.17,0:53:50.84,EN,,0,0,0,,I don't need much more to make a universal computer. Dialogue: 0,0:53:51.81,0:53:54.68,EN,,0,0,0,,But in any case, let's look at the controller for the Fibonacci thing. Dialogue: 0,0:53:55.06,0:53:57.07,EN,,0,0,0,,First thing I want to do is Dialogue: 0,0:53:57.32,0:54:02.52,EN,,0,0,0,,start the thing up by assign to continue Dialogue: 0,0:54:07.13,0:54:10.28,EN,,0,0,0,,a place called done, called Fib-done here. Dialogue: 0,0:54:14.14,0:54:15.53,EN,,0,0,0,,So that means that somewhere over here, Dialogue: 0,0:54:15.55,0:54:18.48,EN,,0,0,0,,I'm going to have a label, Fib-done, Dialogue: 0,0:54:19.71,0:54:21.10,EN,,0,0,0,,which is the place where I go Dialogue: 0,0:54:21.23,0:54:22.44,EN,,0,0,0,,when I want the machine to stop. Dialogue: 0,0:54:24.00,0:54:24.86,EN,,0,0,0,,That's what that is. Dialogue: 0,0:54:25.92,0:54:26.89,EN,,0,0,0,,And I'm going to make up a loop. Dialogue: 0,0:54:31.11,0:54:34.25,EN,,0,0,0,,It's a place I'm going to go to in order to start up computing a Fib. Dialogue: 0,0:54:35.47,0:54:36.86,EN,,0,0,0,,Whatever is in N at this point, Dialogue: 0,0:54:37.39,0:54:38.99,EN,,0,0,0,,Fibonacci will be computed of, Dialogue: 0,0:54:39.13,0:54:42.01,EN,,0,0,0,,and we will return to the place specified by continue. Dialogue: 0,0:54:44.80,0:54:48.40,EN,,0,0,0,,So what you're going to see here at this place, Dialogue: 0,0:54:48.44,0:54:50.48,EN,,0,0,0,,what I want here is the contract Dialogue: 0,0:54:50.97,0:54:54.25,EN,,0,0,0,,that says, I'm going to write this with a comment syntax, Dialogue: 0,0:54:54.57,0:55:00.99,EN,,0,0,0,,the contract is N contains arg, the argument. Dialogue: 0,0:55:02.10,0:55:09.82,EN,,0,0,0,,Continue is the recipient. Dialogue: 0,0:55:13.36,0:55:14.29,EN,,0,0,0,,And that's where it is. Dialogue: 0,0:55:15.71,0:55:18.96,EN,,0,0,0,,At this point, if I ever go to this place, Dialogue: 0,0:55:19.24,0:55:21.04,EN,,0,0,0,,I'm expecting this to be true, Dialogue: 0,0:55:21.52,0:55:23.32,EN,,0,0,0,,the argument for computing the Fibonacci. Dialogue: 0,0:55:24.82,0:55:26.83,EN,,0,0,0,,Now the next thing I want to do is to branch. Dialogue: 0,0:55:30.22,0:55:32.22,EN,,0,0,0,,And if N is less than 2-- Dialogue: 0,0:55:35.07,0:55:37.44,EN,,0,0,0,,by the way, I'm using what looks like Lisp syntax. Dialogue: 0,0:55:38.73,0:55:39.63,EN,,0,0,0,,This is not Lisp. Dialogue: 0,0:55:41.31,0:55:42.38,EN,,0,0,0,,This does not run. Dialogue: 0,0:55:42.75,0:55:45.47,EN,,0,0,0,,What I'm writing here does not run as a simple Lisp program. Dialogue: 0,0:55:46.12,0:55:49.31,EN,,0,0,0,,This is a representation of another language. Dialogue: 0,0:55:49.71,0:55:52.25,EN,,0,0,0,,The reason I'm using the syntax of parentheses and so on Dialogue: 0,0:55:52.40,0:55:54.70,EN,,0,0,0,,is because I tend to use a Lisp system Dialogue: 0,0:55:55.32,0:55:57.34,EN,,0,0,0,,to write an interpreter for this Dialogue: 0,0:55:57.82,0:55:59.18,EN,,0,0,0,,which allows me to simulate Dialogue: 0,0:55:59.29,0:56:00.91,EN,,0,0,0,,the machine I'm trying to build. Dialogue: 0,0:56:03.38,0:56:06.24,EN,,0,0,0,,I don't want to confuse this to think that this is Lisp code. Dialogue: 0,0:56:06.94,0:56:08.60,EN,,0,0,0,,It's just I'm using a lot of the pieces of Lisp. Dialogue: 0,0:56:09.51,0:56:10.84,EN,,0,0,0,,I'm embedding a language in Lisp, Dialogue: 0,0:56:11.02,0:56:12.44,EN,,0,0,0,,using Lisp as pieces Dialogue: 0,0:56:12.72,0:56:15.12,EN,,0,0,0,,to make my process of making my simulator easy. Dialogue: 0,0:56:16.62,0:56:18.56,EN,,0,0,0,,So I'm inheriting from Lisp all of its properties. Dialogue: 0,0:56:19.10,0:56:21.53,EN,,0,0,0,,Fetch of N 2, Dialogue: 0,0:56:21.77,0:56:23.72,EN,,0,0,0,,I want to go to a place called immediate answer. Dialogue: 0,0:56:26.20,0:56:27.29,EN,,0,0,0,,It's the base step. Dialogue: 0,0:56:33.15,0:56:34.35,EN,,0,0,0,,Now, that's somewhere over here, Dialogue: 0,0:56:35.92,0:56:36.89,EN,,0,0,0,,just above done. Dialogue: 0,0:56:37.75,0:56:38.64,EN,,0,0,0,,And we'll see it later. Dialogue: 0,0:56:39.42,0:56:40.70,EN,,0,0,0,,Now, in the general case, Dialogue: 0,0:56:40.72,0:56:42.44,EN,,0,0,0,,which is the part I'm going to write down now, Dialogue: 0,0:56:43.13,0:56:44.19,EN,,0,0,0,,let's just do it. Dialogue: 0,0:56:44.91,0:56:48.20,EN,,0,0,0,,Well, first of all, I'm going to have to call Fibonacci twice. Dialogue: 0,0:56:49.42,0:56:52.54,EN,,0,0,0,,In each case-- well, in one case at least, Dialogue: 0,0:56:52.78,0:56:53.95,EN,,0,0,0,,I'm going to have to know what to do Dialogue: 0,0:56:53.96,0:56:55.36,EN,,0,0,0,,to come back and do the next one. Dialogue: 0,0:56:56.31,0:56:58.36,EN,,0,0,0,,I have to remember, Dialogue: 0,0:56:59.20,0:57:01.23,EN,,0,0,0,,have I done the first Fib, Dialogue: 0,0:57:01.26,0:57:02.54,EN,,0,0,0,,or have I done the second one? Dialogue: 0,0:57:04.50,0:57:07.04,EN,,0,0,0,,Do I have to come back to the place where I do the second Fib, Dialogue: 0,0:57:07.07,0:57:09.08,EN,,0,0,0,,or do I have to come back to the place where I do the add? Dialogue: 0,0:57:10.12,0:57:12.11,EN,,0,0,0,,In both cases I going to need, I don't Dialogue: 0,0:57:12.14,0:57:14.46,EN,,0,0,0,,In the first case, over the first Fibonacci, Dialogue: 0,0:57:14.51,0:57:16.98,EN,,0,0,0,,I'm going to need the value of N for computing for the second one. Dialogue: 0,0:57:19.84,0:57:21.58,EN,,0,0,0,,So I have to store some of these things up. Dialogue: 0,0:57:23.36,0:57:24.89,EN,,0,0,0,,So first I'm going to save continue. Dialogue: 0,0:57:26.19,0:57:27.32,EN,,0,0,0,,That's who needs the answer. Dialogue: 0,0:57:31.32,0:57:32.46,EN,,0,0,0,,And the reason I'm doing that Dialogue: 0,0:57:32.48,0:57:34.20,EN,,0,0,0,,is because I'm about to assign continue Dialogue: 0,0:57:40.11,0:57:44.32,EN,,0,0,0,,to the place which is the place I want to go to after. Dialogue: 0,0:57:46.83,0:57:50.27,EN,,0,0,0,,Let's call it Fib-N-minus-1, Dialogue: 0,0:57:51.04,0:57:53.76,EN,,0,0,0,,big long name, classic Lisp name. Dialogue: 0,0:57:57.36,0:58:00.22,EN,,0,0,0,,Because I'm going to compute the first Fib of N minus 1, Dialogue: 0,0:58:00.84,0:58:01.72,EN,,0,0,0,,and then after that, Dialogue: 0,0:58:01.72,0:58:03.29,EN,,0,0,0,,I want to come back and do something else. Dialogue: 0,0:58:03.96,0:58:06.52,EN,,0,0,0,,That's the place I want to go to after I've done Dialogue: 0,0:58:07.55,0:58:09.48,EN,,0,0,0,,the first Fibonacci calculation. Dialogue: 0,0:58:11.52,0:58:13.13,EN,,0,0,0,,And I want to do a save of N, Dialogue: 0,0:58:14.41,0:58:17.26,EN,,0,0,0,,because I'm going to need it later, after that. Dialogue: 0,0:58:19.13,0:58:20.54,EN,,0,0,0,,Now I'm going to, at this point, Dialogue: 0,0:58:20.67,0:58:22.84,EN,,0,0,0,,get ready to do the Fibonacci of N minus 1. Dialogue: 0,0:58:23.02,0:58:33.95,EN,,0,0,0,,So assign to N the difference of the fetch of N and 1. Dialogue: 0,0:58:38.11,0:58:40.27,EN,,0,0,0,,Now I'm ready to go back to doing the Fib loop. Dialogue: 0,0:58:47.18,0:58:49.87,EN,,0,0,0,,Do I have... Have I satisfied my contract? Dialogue: 0,0:58:50.40,0:58:51.50,EN,,0,0,0,,And the answer is yes. Dialogue: 0,0:58:51.77,0:58:55.12,EN,,0,0,0,,N contains N minus 1, which is what I need. Dialogue: 0,0:58:56.43,0:59:00.09,EN,,0,0,0,,OK? Continue contains a place I want to go to when I'm done Dialogue: 0,0:59:01.28,0:59:03.07,EN,,0,0,0,,with calculating FIB N minus 1. Dialogue: 0,0:59:04.10,0:59:05.44,EN,,0,0,0,,So I've satisfied the contract. Dialogue: 0,0:59:05.44,0:59:09.02,EN,,0,0,0,,And therefore, I can write down here a tag, after, a label, Dialogue: 0,0:59:11.47,0:59:17.56,EN,,0,0,0,,after-Fib-N-minus-1. Dialogue: 0,0:59:20.49,0:59:21.63,EN,,0,0,0,,Now what am I going to do here? Dialogue: 0,0:59:22.69,0:59:23.61,EN,,0,0,0,,Here's a place Dialogue: 0,0:59:23.95,0:59:26.75,EN,,0,0,0,,where I now have to get ready to do Fib of N minus 2. Dialogue: 0,0:59:29.27,0:59:30.72,EN,,0,0,0,,But in order to do a Fib of N minus 2, Dialogue: 0,0:59:30.75,0:59:31.63,EN,,0,0,0,,look, I don't know. Dialogue: 0,0:59:31.78,0:59:33.40,EN,,0,0,0,,I've clobbered my N over here. Dialogue: 0,0:59:33.81,0:59:35.47,EN,,0,0,0,,And presumably my N is counted down Dialogue: 0,0:59:37.85,0:59:38.80,EN,,0,0,0,,all the way to 1 or 0 or something at this point. Dialogue: 0,0:59:39.78,0:59:42.51,EN,,0,0,0,,So I don't know what the value of N in the N register is. Dialogue: 0,0:59:43.03,0:59:44.75,EN,,0,0,0,,I want the value of N that was on the stack Dialogue: 0,0:59:44.80,0:59:46.00,EN,,0,0,0,,that I saved over here Dialogue: 0,0:59:46.17,0:59:47.88,EN,,0,0,0,,so that could restore it over here. Dialogue: 0,0:59:49.52,0:59:51.02,EN,,0,0,0,,I saved up the value of N, Dialogue: 0,0:59:51.15,0:59:54.49,EN,,0,0,0,,which is this value of N at this point, Dialogue: 0,0:59:54.89,0:59:57.37,EN,,0,0,0,,so that I could restore it after computing Fib of N minus 1, Dialogue: 0,0:59:57.53,0:59:59.36,EN,,0,0,0,,so that I could count that down to N minus 2 Dialogue: 0,0:59:59.39,1:00:00.86,EN,,0,0,0,,and then compute Fib of N minus 2. Dialogue: 0,1:00:01.81,1:00:02.75,EN,,0,0,0,,So let's restore that. Dialogue: 0,1:00:08.83,1:00:09.77,EN,,0,0,0,,Restore of N. Dialogue: 0,1:00:11.13,1:00:15.98,EN,,0,0,0,,Now I'm about to do something which is superstitious, Dialogue: 0,1:00:16.00,1:00:17.40,EN,,0,0,0,,and we will remove it shortly. Dialogue: 0,1:00:18.52,1:00:20.48,EN,,0,0,0,,I am about to finish the sequence Dialogue: 0,1:00:20.59,1:00:23.44,EN,,0,0,0,,of doing the subroutine call, if you will. Dialogue: 0,1:00:24.80,1:00:25.95,EN,,0,0,0,,I'm going to say, well, Dialogue: 0,1:00:26.06,1:00:27.90,EN,,0,0,0,,I also saved up the continuation, Dialogue: 0,1:00:28.48,1:00:30.43,EN,,0,0,0,,since I'm going to restore it now. Dialogue: 0,1:00:31.60,1:00:32.60,EN,,0,0,0,,But actually, I don't have to, Dialogue: 0,1:00:32.64,1:00:33.55,EN,,0,0,0,,because I'm not going to need it. Dialogue: 0,1:00:34.61,1:00:35.72,EN,,0,0,0,,We'll fix that in a second. Dialogue: 0,1:00:36.26,1:00:37.95,EN,,0,0,0,,So we'll do a restore of continue, Dialogue: 0,1:00:46.04,1:00:48.02,EN,,0,0,0,,which is what I would in general need to do. Dialogue: 0,1:00:48.02,1:00:49.23,EN,,0,0,0,,And we're just going to see whats called Dialogue: 0,1:00:49.31,1:00:52.14,EN,,0,0,0,,what you would call in the compiler world a peephole optimization, Dialogue: 0,1:00:52.27,1:00:53.72,EN,,0,0,0,,which says, whoops, you didn't have to do that. Dialogue: 0,1:00:55.42,1:00:57.10,EN,,0,0,0,,OK, so the next thing I see here Dialogue: 0,1:00:58.46,1:01:02.28,EN,,0,0,0,,is that I have to get ready now to do Fibonacci of N minus 2. Dialogue: 0,1:01:02.77,1:01:04.49,EN,,0,0,0,,But I don't have to save N anymore. Dialogue: 0,1:01:05.05,1:01:06.72,EN,,0,0,0,,The reason why I don't have to save N anymore Dialogue: 0,1:01:06.80,1:01:09.34,EN,,0,0,0,,is because I don't need N after I've done Fib of N minus 2, Dialogue: 0,1:01:09.36,1:01:10.72,EN,,0,0,0,,because the next thing I do is add. Dialogue: 0,1:01:13.54,1:01:15.85,EN,,0,0,0,,So I'm just going to set up my N that way. Dialogue: 0,1:01:16.60,1:01:28.99,EN,,0,0,0,,Assign N minus difference of fetch N and 2. Dialogue: 0,1:01:31.85,1:01:34.01,EN,,0,0,0,,Now I have to finish the setup Dialogue: 0,1:01:34.27,1:01:36.73,EN,,0,0,0,,for calling Fibonacci of N minus 2. Dialogue: 0,1:01:36.95,1:01:38.33,EN,,0,0,0,,Well, I have to save up continue Dialogue: 0,1:01:44.22,1:01:49.02,EN,,0,0,0,,and assign continue, continue, Dialogue: 0,1:01:52.30,1:01:59.95,EN,,0,0,0,,to the place which is after Fib N 2, Dialogue: 0,1:02:02.57,1:02:04.03,EN,,0,0,0,,that place over here somewhere. Dialogue: 0,1:02:05.32,1:02:07.23,EN,,0,0,0,,However, I've got to be very careful. Dialogue: 0,1:02:08.65,1:02:11.42,EN,,0,0,0,,The old value, the value of Fib of N minus 1, Dialogue: 0,1:02:12.06,1:02:13.12,EN,,0,0,0,,I'm going to need later. Dialogue: 0,1:02:15.30,1:02:17.37,EN,,0,0,0,,The value of Fibonacci of N minus 1, Dialogue: 0,1:02:17.61,1:02:18.48,EN,,0,0,0,,I'm going to need. Dialogue: 0,1:02:18.78,1:02:19.80,EN,,0,0,0,,And I can't clobber it, Dialogue: 0,1:02:21.07,1:02:23.60,EN,,0,0,0,,because I'm going to have to add it to the value of Fib of N minus 2. Dialogue: 0,1:02:24.15,1:02:25.88,EN,,0,0,0,,That's in the value register, so I'm going to save it. Dialogue: 0,1:02:27.79,1:02:32.60,EN,,0,0,0,,So I have to save this right now, save up VAL. Dialogue: 0,1:02:33.78,1:02:35.44,EN,,0,0,0,,And now I can go off to my subroutine, Dialogue: 0,1:02:36.67,1:02:39.54,EN,,0,0,0,,go to Fib loop. Dialogue: 0,1:02:44.22,1:02:46.57,EN,,0,0,0,,Now before I go any further Dialogue: 0,1:02:46.80,1:02:49.36,EN,,0,0,0,,and finish this program, Dialogue: 0,1:02:49.39,1:02:51.05,EN,,0,0,0,,I just want to look at this segment so far Dialogue: 0,1:02:51.23,1:02:56.00,EN,,0,0,0,,and see, oh yes, there's a sequence of instructions here, if you will Dialogue: 0,1:02:57.84,1:02:59.08,EN,,0,0,0,,that I can do something about. Dialogue: 0,1:03:01.58,1:03:03.20,EN,,0,0,0,,Here I have a restore of continue, Dialogue: 0,1:03:04.25,1:03:05.48,EN,,0,0,0,,a save of continue, Dialogue: 0,1:03:06.01,1:03:07.40,EN,,0,0,0,,and then an assign of continue, Dialogue: 0,1:03:08.70,1:03:10.64,EN,,0,0,0,,with no other references to continue in between. Dialogue: 0,1:03:13.84,1:03:15.48,EN,,0,0,0,,The restore followed by the save Dialogue: 0,1:03:15.50,1:03:16.67,EN,,0,0,0,,leaves the stack unchanged. Dialogue: 0,1:03:19.09,1:03:21.72,EN,,0,0,0,,The only difference is that I set the continue register to a value, Dialogue: 0,1:03:21.96,1:03:23.28,EN,,0,0,0,,which is the value that was on the stack. Dialogue: 0,1:03:24.33,1:03:25.79,EN,,0,0,0,,Since I now clobber that value, Dialogue: 0,1:03:26.44,1:03:27.93,EN,,0,0,0,,as in it was never referenced, Dialogue: 0,1:03:28.59,1:03:30.09,EN,,0,0,0,,these instructions are unnecessary. Dialogue: 0,1:03:31.76,1:03:35.39,EN,,0,0,0,,So we will remove these. Dialogue: 0,1:03:38.88,1:03:40.78,EN,,0,0,0,,But I couldn't have seen that unless I had written them down. Dialogue: 0,1:03:43.78,1:03:44.72,EN,,0,0,0,,Was that really true? Dialogue: 0,1:03:45.77,1:03:46.60,EN,,0,0,0,,Well, I don't know. Dialogue: 0,1:03:48.61,1:03:52.91,EN,,0,0,0,,OK, so we've now gone off to compute Fibonacci of N minus 2. Dialogue: 0,1:03:53.66,1:03:54.59,EN,,0,0,0,,So after that, Dialogue: 0,1:04:02.96,1:04:03.85,EN,,0,0,0,,what are we going to do? Dialogue: 0,1:04:05.07,1:04:06.76,EN,,0,0,0,,Well, I suppose the first thing we have to do-- Dialogue: 0,1:04:06.99,1:04:07.88,EN,,0,0,0,,we've got two things. Dialogue: 0,1:04:07.96,1:04:10.49,EN,,0,0,0,,We've got a thing in the value register which is now valuable. Dialogue: 0,1:04:10.92,1:04:11.98,EN,,0,0,0,,We also have a thing on the stack Dialogue: 0,1:04:12.04,1:04:13.63,EN,,0,0,0,,can be restored into the value register. Dialogue: 0,1:04:14.81,1:04:16.57,EN,,0,0,0,,And what I have to be careful with now Dialogue: 0,1:04:16.88,1:04:18.99,EN,,0,0,0,,is I want to shuffle this right so I can do the multiply. Dialogue: 0,1:04:19.47,1:04:21.24,EN,,0,0,0,,Now there are various conventions I might use, Dialogue: 0,1:04:21.47,1:04:23.52,EN,,0,0,0,,but I'm going to be very picky and say, Dialogue: 0,1:04:23.55,1:04:25.88,EN,,0,0,0,,I'm only going to restore into a register I've saved from. Dialogue: 0,1:04:26.74,1:04:28.28,EN,,0,0,0,,If that's the case, I have to do a shuffle here. Dialogue: 0,1:04:29.24,1:04:31.84,EN,,0,0,0,,It's the same problem with how many hands I have. Dialogue: 0,1:04:32.68,1:04:37.13,EN,,0,0,0,,So I'm going to assign to N, Dialogue: 0,1:04:37.16,1:04:39.37,EN,,0,0,0,,because I'm not going to need N anymore, N is useless, Dialogue: 0,1:04:39.92,1:04:41.21,EN,,0,0,0,,the current value of VAL, Dialogue: 0,1:04:45.21,1:04:47.34,EN,,0,0,0,,which was the value of Fib of N minus 2. Dialogue: 0,1:04:52.95,1:04:56.35,EN,,0,0,0,,And I'm going to restore the value register now. Dialogue: 0,1:05:01.85,1:05:03.92,EN,,0,0,0,,This restore matches this save. Dialogue: 0,1:05:05.58,1:05:08.83,EN,,0,0,0,,And if you're very careful and examine very carefully what goes on, Dialogue: 0,1:05:09.21,1:05:11.96,EN,,0,0,0,,OK? restores and saves are always matched. Dialogue: 0,1:05:13.84,1:05:15.15,EN,,0,0,0,,Now there's an outstanding save, Dialogue: 0,1:05:15.18,1:05:16.38,EN,,0,0,0,,of course, that we have to get rid of soon. Dialogue: 0,1:05:19.00,1:05:20.59,EN,,0,0,0,,And so I restored the value register. Dialogue: 0,1:05:20.94,1:05:22.57,EN,,0,0,0,,Now I restore the continue one, Dialogue: 0,1:05:31.15,1:05:32.40,EN,,0,0,0,,which matches this one, Dialogue: 0,1:05:34.80,1:05:37.85,EN,,0,0,0,,dot, dot, dot, dot, dot, dot, dot, down to here, Dialogue: 0,1:05:40.59,1:05:42.46,EN,,0,0,0,,Now restoring that continuation. Dialogue: 0,1:05:42.86,1:05:45.71,EN,,0,0,0,,That continuation is a continuation of Fib of N, Dialogue: 0,1:05:46.46,1:05:47.84,EN,,0,0,0,,which is the problem I was trying to solve, Dialogue: 0,1:05:47.85,1:05:49.32,EN,,0,0,0,,a major problem I'm trying to solve. Dialogue: 0,1:05:49.98,1:05:52.35,EN,,0,0,0,,So that's the guy I have to go back to who wants Fib of N. Dialogue: 0,1:05:52.54,1:05:54.03,EN,,0,0,0,,I saved them all the way up here Dialogue: 0,1:05:54.16,1:05:56.60,EN,,0,0,0,,when I realized N was not less than 2. Dialogue: 0,1:05:57.36,1:05:59.07,EN,,0,0,0,,And so I had to do a complicated operation. Dialogue: 0,1:06:00.84,1:06:02.57,EN,,0,0,0,,Now I've got everything I need to do it. Dialogue: 0,1:06:03.24,1:06:04.36,EN,,0,0,0,,So I'm going to restore that, Dialogue: 0,1:06:05.42,1:06:21.08,EN,,0,0,0,,assign to VAL the sum of fetch VAL and fetch of N Dialogue: 0,1:06:27.44,1:06:28.60,EN,,0,0,0,,and go to continue. Dialogue: 0,1:06:38.26,1:06:44.78,EN,,0,0,0,,So now I've returned from computing Fibonacci of N, Dialogue: 0,1:06:45.39,1:06:46.57,EN,,0,0,0,,the general case. Dialogue: 0,1:06:47.11,1:06:50.60,EN,,0,0,0,,Now what's left is we have to fix up a few details, Dialogue: 0,1:06:50.99,1:06:55.53,EN,,0,0,0,,like there's the base case of this induction, immediate answer, Dialogue: 0,1:07:02.54,1:07:06.59,EN,,0,0,0,,as, which is nothing more than Dialogue: 0,1:07:06.60,1:07:11.85,EN,,0,0,0,,assign to VAL fetch of N, Dialogue: 0,1:07:13.64,1:07:15.47,EN,,0,0,0,,because N was less than 2, Dialogue: 0,1:07:15.50,1:07:16.89,EN,,0,0,0,,and therefore, the answer is N Dialogue: 0,1:07:16.99,1:07:18.19,EN,,0,0,0,,in our original program, Dialogue: 0,1:07:19.23,1:07:26.48,EN,,0,0,0,,and return continue-- Dialogue: 0,1:07:31.24,1:07:36.13,EN,,0,0,0,,bobble, bobble almost-- and finally Fib done. Dialogue: 0,1:07:43.46,1:07:45.64,EN,,0,0,0,,So that's a fairly complicated program. Dialogue: 0,1:07:45.64,1:07:47.34,EN,,0,0,0,,And the reason I wanted you see to that Dialogue: 0,1:07:47.50,1:07:49.21,EN,,0,0,0,,is because I want you to see the particular Dialogue: 0,1:07:49.45,1:07:52.67,EN,,0,0,0,,flavors of stack discipline that I was obeying. Dialogue: 0,1:07:53.32,1:07:55.21,EN,,0,0,0,,It was first of all, I don't want to save anything Dialogue: 0,1:07:56.92,1:07:58.12,EN,,0,0,0,,that I'm not going to need later. Dialogue: 0,1:08:00.57,1:08:01.85,EN,,0,0,0,,I was being very careful. Dialogue: 0,1:08:01.85,1:08:02.91,EN,,0,0,0,,And it's very important. Dialogue: 0,1:08:03.94,1:08:06.52,EN,,0,0,0,,And there are all sorts of other disciplines people make Dialogue: 0,1:08:07.37,1:08:09.61,EN,,0,0,0,,with frames and things like that of some sort, Dialogue: 0,1:08:10.19,1:08:11.39,EN,,0,0,0,,where you save all sorts of junk Dialogue: 0,1:08:11.40,1:08:12.64,EN,,0,0,0,,you're not going to need later and restore it Dialogue: 0,1:08:12.67,1:08:15.26,EN,,0,0,0,,because, in some sense, it's easier to do that. Dialogue: 0,1:08:15.83,1:08:17.40,EN,,0,0,0,,That's going to lead to various disasters, Dialogue: 0,1:08:18.59,1:08:20.25,EN,,0,0,0,,which we'll see a little later. Dialogue: 0,1:08:21.44,1:08:24.24,EN,,0,0,0,,It's crucial to save exactly what you're going to need later. Dialogue: 0,1:08:26.89,1:08:28.01,EN,,0,0,0,,It's an important idea. Dialogue: 0,1:08:29.87,1:08:33.36,EN,,0,0,0,,And the responsibility of that is whoever saves something Dialogue: 0,1:08:33.76,1:08:35.32,EN,,0,0,0,,is the guy who restores it, because he needs it. Dialogue: 0,1:08:36.93,1:08:38.54,EN,,0,0,0,,And in such discipline, Dialogue: 0,1:08:38.86,1:08:40.76,EN,,0,0,0,,you can see what things are unnecessary, Dialogue: 0,1:08:43.45,1:08:44.73,EN,,0,0,0,,operations that are unimportant. Dialogue: 0,1:08:47.15,1:08:50.40,EN,,0,0,0,,Now, one other thing I want to tell you about is very simple Dialogue: 0,1:08:51.66,1:08:54.67,EN,,0,0,0,,is that, of course, the picture you see is not the whole picture. Dialogue: 0,1:08:55.35,1:08:56.68,EN,,0,0,0,,Supposing I had systems Dialogue: 0,1:08:56.80,1:09:01.52,EN,,0,0,0,,had things like other operations, CAR, CDR, CONS, Dialogue: 0,1:09:03.53,1:09:05.60,EN,,0,0,0,,building a vector Dialogue: 0,1:09:05.88,1:09:07.32,EN,,0,0,0,,and referencing the nth element of it, Dialogue: 0,1:09:08.30,1:09:09.21,EN,,0,0,0,,or things like that. Dialogue: 0,1:09:10.40,1:09:13.60,EN,,0,0,0,,Well, at this level of detail, whatever it is, Dialogue: 0,1:09:13.87,1:09:17.85,EN,,0,0,0,,we can conceptualize those as primitive operations in the datapath. Dialogue: 0,1:09:18.75,1:09:21.95,EN,,0,0,0,,In other words, we could say that some machine that, for example, has Dialogue: 0,1:09:22.32,1:09:24.11,EN,,0,0,0,,has the append machine, Dialogue: 0,1:09:24.20,1:09:26.46,EN,,0,0,0,,which has to do cons of the CAR of x Dialogue: 0,1:09:26.64,1:09:29.80,EN,,0,0,0,,with the append of the CDR of x and y, Dialogue: 0,1:09:29.88,1:09:33.18,EN,,0,0,0,,well, gee, that's exactly the same as the factorial structure. Dialogue: 0,1:09:33.63,1:09:35.29,EN,,0,0,0,,Well, it's got about the same structure. Dialogue: 0,1:09:36.54,1:09:37.27,EN,,0,0,0,,And what do we have? Dialogue: 0,1:09:37.27,1:09:39.39,EN,,0,0,0,,We have some sort of things in it Dialogue: 0,1:09:39.76,1:09:42.48,EN,,0,0,0,,which may be registers, x and y, Dialogue: 0,1:09:42.51,1:09:45.12,EN,,0,0,0,,and then x has to somehow move to y sometimes, Dialogue: 0,1:09:45.28,1:09:46.75,EN,,0,0,0,,x has to get the value of y. Dialogue: 0,1:09:46.93,1:09:50.11,EN,,0,0,0,,And then we may have to be able to do something which is a cons. Dialogue: 0,1:09:51.70,1:09:57.74,EN,,0,0,0,,I don't remember if I need to like this is in this system, Dialogue: 0,1:09:57.76,1:10:01.10,EN,,0,0,0,,but cons is sort of like subtract or add or something. Dialogue: 0,1:10:01.42,1:10:02.70,EN,,0,0,0,,It combines two things, Dialogue: 0,1:10:02.73,1:10:04.27,EN,,0,0,0,,producing a thing which is the cons, Dialogue: 0,1:10:04.51,1:10:06.49,EN,,0,0,0,,which we may then think goes into there. Dialogue: 0,1:10:07.60,1:10:09.72,EN,,0,0,0,,And then maybe a thing called the CAR, Dialogue: 0,1:10:12.88,1:10:16.22,EN,,0,0,0,,which will produce-- I can get the CAR or something. Dialogue: 0,1:10:16.92,1:10:19.55,EN,,0,0,0,,And maybe I can get the CDR of something, and so on. Dialogue: 0,1:10:20.15,1:10:22.30,EN,,0,0,0,,But we shouldn't be too afraid of saying things this way, Dialogue: 0,1:10:22.92,1:10:24.24,EN,,0,0,0,,because the worst that could happen Dialogue: 0,1:10:24.94,1:10:26.41,EN,,0,0,0,,is if we open up cons, Dialogue: 0,1:10:27.31,1:10:29.82,EN,,0,0,0,,what we're going to find is some machine. Dialogue: 0,1:10:31.88,1:10:34.44,EN,,0,0,0,,And cons may in fact overlap with CAR and CDR, and it always does, Dialogue: 0,1:10:35.50,1:10:38.12,EN,,0,0,0,,in the same way that plus and minus overlap, Dialogue: 0,1:10:38.57,1:10:39.85,EN,,0,0,0,,and really the same business. Dialogue: 0,1:10:41.21,1:10:42.60,EN,,0,0,0,,CONS, CAR, and CDR are going to overlap, Dialogue: 0,1:10:42.62,1:10:44.52,EN,,0,0,0,,and we're going to find a little controller, Dialogue: 0,1:10:45.50,1:10:46.54,EN,,0,0,0,,a little datapath, Dialogue: 0,1:10:48.03,1:10:49.64,EN,,0,0,0,,which may have some registers in it, Dialogue: 0,1:10:50.00,1:10:52.86,EN,,0,0,0,,some stuff like that. Dialogue: 0,1:10:53.30,1:10:54.41,EN,,0,0,0,,And maybe inside it, Dialogue: 0,1:10:54.43,1:10:56.16,EN,,0,0,0,,there may also be an infinite part, Dialogue: 0,1:10:56.46,1:10:58.70,EN,,0,0,0,,a part that's semi-infinite or something, Dialogue: 0,1:10:58.81,1:11:00.65,EN,,0,0,0,,which is a lot of very uniform stuff, Dialogue: 0,1:11:00.96,1:11:02.03,EN,,0,0,0,,which we'll call memory. Dialogue: 0,1:11:06.57,1:11:08.83,EN,,0,0,0,,And I wouldn't be so horrified if that were the way it works. Dialogue: 0,1:11:09.33,1:11:11.07,EN,,0,0,0,,In fact, it does, and we'll talk about that later. Dialogue: 0,1:11:13.32,1:11:14.57,EN,,0,0,0,,So are there any questions? Dialogue: 0,1:11:24.34,1:11:25.80,EN,,0,0,0,,Gee, what an unquestioning audience. Dialogue: 0,1:11:28.67,1:11:30.33,EN,,0,0,0,,Suppose I tell you a horrible pile of lies. Dialogue: 0,1:11:39.69,1:11:40.38,EN,,0,0,0,,OK. Dialogue: 0,1:11:41.99,1:11:42.52,EN,,0,0,0,,Well, thank you. Dialogue: 0,1:11:42.52,1:11:43.28,EN,,0,0,0,,Let's take our break. Dialogue: 0,0:00:00.03,0:00:02.04,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP 学习小组\N倾情制作 Dialogue: 0,0:00:02.04,0:00:09.09,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:02.04,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.04,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.04,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.04,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:09.21,0:00:13.12,Declare,,0,0,0,,{\an2\fad(500,500)}寄存机器 Dialogue: 0,0:00:17.26,0:00:19.07,Default,,0,0,0,,教授:我认为 到目前为止 Dialogue: 0,0:00:19.32,0:00:23.93,Default,,0,0,0,,我们已经学习了很多关于 Dialogue: 0,0:00:24.09,0:00:28.83,Default,,0,0,0,,组织程序以及操纵符号的技术 Dialogue: 0,0:00:30.84,0:00:35.60,Default,,0,0,0,,以及用来构建语言的技术 Dialogue: 0,0:00:35.63,0:00:36.78,Default,,0,0,0,,用一门语言去创建另一门语言 Dialogue: 0,0:00:37.10,0:00:39.92,Default,,0,0,0,,这在组织大型程序时非常有用 Dialogue: 0,0:00:39.96,0:00:42.30,Default,,0,0,0,,实际上 我所知的最好的程序 Dialogue: 0,0:00:42.44,0:00:44.43,Default,,0,0,0,,看起来更像是一堆语言 Dialogue: 0,0:00:44.91,0:00:47.96,Default,,0,0,0,,而不是将问题分解成若干部分 Dialogue: 0,0:00:49.90,0:00:51.45,Default,,0,0,0,,我想 此时此刻 Dialogue: 0,0:00:52.08,0:00:53.58,Default,,0,0,0,,关于这类东西的工作方式 Dialogue: 0,0:00:53.61,0:00:55.32,Default,,0,0,0,,仍然存在一些谜团 Dialogue: 0,0:00:56.26,0:00:59.68,Default,,0,0,0,,因此 我现在需要 Dialogue: 0,0:01:00.03,0:01:02.60,Default,,0,0,0,,偏离原先的计划 Dialogue: 0,0:01:02.96,0:01:05.42,Default,,0,0,0,,不再继续讲解如何组织大型程序 Dialogue: 0,0:01:05.45,0:01:08.19,Default,,0,0,0,,而是告诉你一些关于 Dialogue: 0,0:01:08.52,0:01:11.71,Default,,0,0,0,,使这些事情可以起作用的机制 Dialogue: 0,0:01:12.19,0:01:14.83,Default,,0,0,0,,这样做的主要是为了 Dialogue: 0,0:01:15.80,0:01:17.87,Default,,0,0,0,,揭秘 Dialogue: 0,0:01:18.65,0:01:20.54,Default,,0,0,0,,剩下的很多谜团 Dialogue: 0,0:01:21.08,0:01:25.48,Default,,0,0,0,,比如说 如何控制程序的运行 Dialogue: 0,0:01:26.08,0:01:30.38,Default,,0,0,0,,计算机如何知晓下一步的动作 Dialogue: 0,0:01:30.52,0:01:31.74,Default,,0,0,0,,等等等等 Dialogue: 0,0:01:32.43,0:01:35.56,Default,,0,0,0,,我现在就要让你们清楚地知道 Dialogue: 0,0:01:35.85,0:01:39.10,Default,,0,0,0,,就算你之前没有使用过计算机 Dialogue: 0,0:01:39.56,0:01:43.50,Default,,0,0,0,,但这种机制非常简单 Dialogue: 0,0:01:44.33,0:01:46.35,Default,,0,0,0,,你可以毫无问题地理解它 Dialogue: 0,0:01:47.65,0:01:51.24,Default,,0,0,0,,好吧 我们先来想象一个 -- Dialogue: 0,0:01:51.32,0:01:52.91,Default,,0,0,0,,先说明一下 我们采用的方法是 Dialogue: 0,0:01:52.96,0:01:55.80,Default,,0,0,0,,把一些非常简单的Lisp程序 Dialogue: 0,0:01:56.54,0:01:58.12,Default,,0,0,0,,真的非常简单 Dialogue: 0,0:01:59.04,0:02:00.62,Default,,0,0,0,,把它们转换成硬件 Dialogue: 0,0:02:02.16,0:02:04.16,Default,,0,0,0,,我不会考虑一些中间步骤 Dialogue: 0,0:02:04.70,0:02:07.45,Default,,0,0,0,,比如转换成某种现有的机器语言 Dialogue: 0,0:02:07.47,0:02:09.05,Default,,0,0,0,,然后来解释计算机是如何工作的 Dialogue: 0,0:02:09.82,0:02:12.00,Default,,0,0,0,,因为那不太明显 Dialogue: 0,0:02:12.75,0:02:14.17,Default,,0,0,0,,所以我真正要向你展示的是 Dialogue: 0,0:02:14.51,0:02:17.48,Default,,0,0,0,,如何构建一台机器来完成 Dialogue: 0,0:02:18.03,0:02:22.04,Default,,0,0,0,,一项由你写的程序所描述的工作 Dialogue: 0,0:02:22.04,0:02:24.03,Default,,0,0,0,,而程序呢 实际上就是一个机器的描述 Dialogue: 0,0:02:25.76,0:02:27.69,Default,,0,0,0,,我们从一个非常简单的程序开始 Dialogue: 0,0:02:28.09,0:02:30.81,Default,,0,0,0,,然后演示一些简单的机制 Dialogue: 0,0:02:31.39,0:02:33.68,Default,,0,0,0,,进而用更复杂的程序 Dialogue: 0,0:02:34.30,0:02:37.42,Default,,0,0,0,,然后又演示一个不那么复杂的程序 Dialogue: 0,0:02:37.44,0:02:41.23,Default,,0,0,0,,来演示求值器是如何变成硬件的 Dialogue: 0,0:02:41.23,0:02:42.06,Default,,0,0,0,,当然 到那个时候 Dialogue: 0,0:02:42.08,0:02:44.08,Default,,0,0,0,,你就有了通用的转换算法 Dialogue: 0,0:02:44.22,0:02:46.88,Default,,0,0,0,,并且可以用一个定义明确的硬件 Dialogue: 0,0:02:47.16,0:02:48.80,Default,,0,0,0,,来执行任何可以想象的程序 Dialogue: 0,0:02:51.72,0:02:52.91,Default,,0,0,0,,那么 现在让我们开始 Dialogue: 0,0:02:53.05,0:02:55.31,Default,,0,0,0,,给你们关于这些东西的具体感觉 Dialogue: 0,0:02:55.44,0:02:57.66,Default,,0,0,0,,我们先从一个非常简单的程序开始 Dialogue: 0,0:02:59.60,0:03:00.85,Default,,0,0,0,,这是欧几里得算法 Dialogue: 0,0:03:03.88,0:03:07.00,Default,,0,0,0,,它实际上比欧几里德算法更现代一些 Dialogue: 0,0:03:07.02,0:03:10.09,Default,,0,0,0,,我想 用来计算两数最大公约数的欧几里得算法 Dialogue: 0,0:03:10.41,0:03:13.60,Default,,0,0,0,,是在公元前350年发明的 Dialogue: 0,0:03:14.30,0:03:15.69,Default,,0,0,0,,它是已知最古老的算法 Dialogue: 0,0:03:19.32,0:03:23.34,Default,,0,0,0,,我们先定义(GCD A B) Dialogue: 0,0:03:23.36,0:03:25.61,Default,,0,0,0,,也就是用来计算A、B两数的最大公约数 Dialogue: 0,0:03:26.20,0:03:28.91,Default,,0,0,0,,这个算法相当简单 Dialogue: 0,0:03:29.50,0:03:31.08,Default,,0,0,0,,如果B等于0 Dialogue: 0,0:03:34.16,0:03:36.83,Default,,0,0,0,,那么结果就是A Dialogue: 0,0:03:37.52,0:03:43.61,Default,,0,0,0,,否则结果就是 (GCD B Dialogue: 0,0:03:44.49,0:03:53.39,Default,,0,0,0,,(REMAINDER A B)) Dialogue: 0,0:03:58.53,0:04:01.90,Default,,0,0,0,,这里 我们定义了一个简单的迭代过程 Dialogue: 0,0:04:02.03,0:04:04.08,Default,,0,0,0,,这是一个简单的递归过程 Dialogue: 0,0:04:04.38,0:04:07.53,Default,,0,0,0,,也可以说这个过程是递归地定义的 Dialogue: 0,0:04:07.71,0:04:09.26,Default,,0,0,0,,但它产生的计算过程是迭代的 Dialogue: 0,0:04:09.95,0:04:12.46,Default,,0,0,0,,它的原理是 在每一步 Dialogue: 0,0:04:12.80,0:04:15.10,Default,,0,0,0,,判断B是否为0 Dialogue: 0,0:04:16.24,0:04:18.80,Default,,0,0,0,,如果B为0 那么A的值就是我们的答案 Dialogue: 0,0:04:19.63,0:04:22.46,Default,,0,0,0,,否则就进入下一个步骤 Dialogue: 0,0:04:22.49,0:04:23.87,Default,,0,0,0,,其中A就变成旧的B Dialogue: 0,0:04:23.88,0:04:27.04,Default,,0,0,0,,而B的值 是A旧值除B旧值的余数 Dialogue: 0,0:04:28.76,0:04:29.55,Default,,0,0,0,,非常简单 Dialogue: 0,0:04:31.11,0:04:32.72,Default,,0,0,0,,现在 我已经通过这种方式 Dialogue: 0,0:04:32.99,0:04:34.86,Default,,0,0,0,,告诉了你一些机制 Dialogue: 0,0:04:34.86,0:04:35.90,Default,,0,0,0,,我是按时序告诉你们的 Dialogue: 0,0:04:36.36,0:04:37.72,Default,,0,0,0,,我说 其中有特定的步骤 Dialogue: 0,0:04:38.14,0:04:39.32,Default,,0,0,0,,并且实际上 Dialogue: 0,0:04:39.52,0:04:40.86,Default,,0,0,0,,你可以在这里知道 Dialogue: 0,0:04:41.18,0:04:43.69,Default,,0,0,0,,为什么这个过程是迭代的 Dialogue: 0,0:04:43.95,0:04:47.68,Default,,0,0,0,,是因为最后一步无需额外信息来得到答案 Dialogue: 0,0:04:49.44,0:04:55.29,Default,,0,0,0,,所有运行此算法所需的信息都在A和B中 Dialogue: 0,0:04:55.74,0:04:57.80,Default,,0,0,0,,它有两个定义明确的状态变量 Dialogue: 0,0:05:00.47,0:05:02.33,Default,,0,0,0,,现在 我就要给你们定义一台机器 Dialogue: 0,0:05:03.98,0:05:05.55,Default,,0,0,0,,用来计算GCD Dialogue: 0,0:05:06.56,0:05:07.12,Default,,0,0,0,,我们来看看 Dialogue: 0,0:05:07.12,0:05:11.28,Default,,0,0,0,,每台制造的计算机都是单进程计算机 Dialogue: 0,0:05:11.80,0:05:14.08,Default,,0,0,0,,而不是某种多处理器 Dialogue: 0,0:05:15.04,0:05:16.59,Default,,0,0,0,,都是按照相同的方案制定的 Dialogue: 0,0:05:17.84,0:05:19.53,Default,,0,0,0,,这种方案就是:计算机由两部分组成 Dialogue: 0,0:05:20.57,0:05:22.35,Default,,0,0,0,,一部分叫数据通路 Dialogue: 0,0:05:23.10,0:05:24.36,Default,,0,0,0,,而另一部分叫控制器 Dialogue: 0,0:05:25.91,0:05:29.28,Default,,0,0,0,,数据通路相当于你可能有的计算器 Dialogue: 0,0:05:29.71,0:05:31.87,Default,,0,0,0,,它有一些寄存器 能够存储数据 Dialogue: 0,0:05:31.90,0:05:33.13,Default,,0,0,0,,你们都用过计算器 Dialogue: 0,0:05:33.56,0:05:35.34,Default,,0,0,0,,它上面有一些按钮和指示灯 Dialogue: 0,0:05:37.03,0:05:38.49,Default,,0,0,0,,通过按下不同的按钮 Dialogue: 0,0:05:38.52,0:05:41.34,Default,,0,0,0,,你可以使操作在寄存器内发生 Dialogue: 0,0:05:41.87,0:05:43.48,Default,,0,0,0,,并显示计算结果 Dialogue: 0,0:05:45.16,0:05:46.25,Default,,0,0,0,,它是完全机械式的 Dialogue: 0,0:05:46.25,0:05:49.55,Default,,0,0,0,,你可以认为那个盒子没有任何智能 Dialogue: 0,0:05:50.90,0:05:53.28,Default,,0,0,0,,它能计算一个数的正弦也许令人吃惊 Dialogue: 0,0:05:53.53,0:05:58.97,Default,,0,0,0,,但它显然是机械式的 Dialogue: 0,0:05:58.97,0:06:01.71,Default,,0,0,0,,至少 我可以像打开GCD机器一样打开它 Dialogue: 0,0:06:02.69,0:06:04.36,Default,,0,0,0,,也就是说 它其中可能有一整台计算机 Dialogue: 0,0:06:04.68,0:06:05.69,Default,,0,0,0,,但这并不有趣 Dialogue: 0,0:06:05.94,0:06:07.10,Default,,0,0,0,,加法相当简单 Dialogue: 0,0:06:08.20,0:06:09.84,Default,,0,0,0,,不借助额外机制就可以完成 Dialogue: 0,0:06:10.89,0:06:15.64,Default,,0,0,0,,现在 如果我们来看另外的一部分:控制器 Dialogue: 0,0:06:15.93,0:06:17.39,Default,,0,0,0,,这一部分也非常简单 Dialogue: 0,0:06:18.19,0:06:19.16,Default,,0,0,0,,它负责按下按钮 Dialogue: 0,0:06:20.35,0:06:21.52,Default,,0,0,0,,它根据指令序列来按按钮 Dialogue: 0,0:06:21.55,0:06:22.84,Default,,0,0,0,,指令是写在纸上的 Dialogue: 0,0:06:24.27,0:06:25.64,Default,,0,0,0,,控制器还会观察指示灯 Dialogue: 0,0:06:26.29,0:06:29.44,Default,,0,0,0,,而且每隔一段 它就会来到指令序列中的一处 Dialogue: 0,0:06:29.47,0:06:32.37,Default,,0,0,0,,如果指示灯A亮 则执行某段指令 Dialogue: 0,0:06:32.37,0:06:33.85,Default,,0,0,0,,否则执行另外的指令 Dialogue: 0,0:06:34.62,0:06:37.45,Default,,0,0,0,,因此 这其中也没有什么复杂的 Dialogue: 0,0:06:38.35,0:06:39.32,Default,,0,0,0,,那么 让我们来画一下 Dialogue: 0,0:06:39.34,0:06:40.57,Default,,0,0,0,,然后来感受一下它 Dialogue: 0,0:06:42.51,0:06:44.84,Default,,0,0,0,,为了计算GCD Dialogue: 0,0:06:45.88,0:06:49.52,Default,,0,0,0,,你们要知道:这其中有一些寄存器 Dialogue: 0,0:06:50.56,0:06:53.02,Default,,0,0,0,,这里 寄存器就是一个存储数值的地方 Dialogue: 0,0:06:53.52,0:06:54.65,Default,,0,0,0,,这个寄存器存储的是A Dialogue: 0,0:06:56.81,0:06:58.70,Default,,0,0,0,,而另外的这个存储的是B Dialogue: 0,0:07:03.17,0:07:05.45,Default,,0,0,0,,现在我们来看看 有了这些寄存器后能做什么 Dialogue: 0,0:07:05.98,0:07:08.73,Default,,0,0,0,,至于你能利用它做什么 并不是很明显 Dialogue: 0,0:07:09.84,0:07:11.72,Default,,0,0,0,,那么 我们必须看看需要用它们做什么 Dialogue: 0,0:07:11.82,0:07:13.87,Default,,0,0,0,,我们来看看尝试求解的问题 Dialogue: 0,0:07:14.03,0:07:16.09,Default,,0,0,0,,计算机设计的一个要点就是 Dialogue: 0,0:07:17.10,0:07:19.58,Default,,0,0,0,,我想大多数设计师都不会照做 Dialogue: 0,0:07:20.20,0:07:21.88,Default,,0,0,0,,也就是专注于待解的问题 Dialogue: 0,0:07:22.62,0:07:25.18,Default,,0,0,0,,然后使用你研究问题所学到的东西 Dialogue: 0,0:07:25.44,0:07:27.28,Default,,0,0,0,,把那些求解问题所需要的机制 Dialogue: 0,0:07:27.53,0:07:28.70,Default,,0,0,0,,融入正在构建的计算机中 Dialogue: 0,0:07:28.81,0:07:30.08,Default,,0,0,0,,不多也不少 Dialogue: 0,0:07:32.14,0:07:33.96,Default,,0,0,0,,现在 可能你所要解决的问题 Dialogue: 0,0:07:34.24,0:07:35.40,Default,,0,0,0,,是大家共有的问题 Dialogue: 0,0:07:36.06,0:07:37.58,Default,,0,0,0,,这种情况下你需要构建 Dialogue: 0,0:07:37.60,0:07:39.29,Default,,0,0,0,,某种语言的通用解释器 Dialogue: 0,0:07:40.19,0:07:42.32,Default,,0,0,0,,但是你添加的机制不能比 Dialogue: 0,0:07:42.35,0:07:44.25,Default,,0,0,0,,想构建的语言解释器的需求多 Dialogue: 0,0:07:44.44,0:07:45.85,Default,,0,0,0,,这一点 我们稍后来讨论 Dialogue: 0,0:07:47.23,0:07:49.93,Default,,0,0,0,,好了 让我们回到这里 Dialogue: 0,0:07:49.93,0:07:51.24,Default,,0,0,0,,我们必须能够做什么? Dialogue: 0,0:07:51.79,0:07:54.14,Default,,0,0,0,,首先 我们能把B的值赋给A Dialogue: 0,0:07:56.08,0:07:59.60,Default,,0,0,0,,我们要能够把B的旧值赋给A Dialogue: 0,0:08:00.38,0:08:03.32,Default,,0,0,0,,因此 我们需要某种能够让数据流通的“路径” Dialogue: 0,0:08:03.34,0:08:04.76,Default,,0,0,0,,而不管数据具体是什么 Dialogue: 0,0:08:05.37,0:08:06.57,Default,,0,0,0,,从B到A的通路 Dialogue: 0,0:08:07.39,0:08:09.26,Default,,0,0,0,,我箭头来指示 Dialogue: 0,0:08:09.52,0:08:12.62,Default,,0,0,0,,我们能够把B的值赋给A Dialogue: 0,0:08:12.96,0:08:14.57,Default,,0,0,0,,从而替换A的旧值 Dialogue: 0,0:08:15.12,0:08:16.73,Default,,0,0,0,,当你按下这里的按钮后 Dialogue: 0,0:08:17.48,0:08:18.56,Default,,0,0,0,,就能够实现这个效果 Dialogue: 0,0:08:19.71,0:08:20.78,Default,,0,0,0,,这个按钮就在这里 Dialogue: 0,0:08:23.07,0:08:23.93,Default,,0,0,0,,同样的 Dialogue: 0,0:08:23.95,0:08:26.28,Default,,0,0,0,,我还需要能够计算A除B的余数 Dialogue: 0,0:08:27.00,0:08:28.49,Default,,0,0,0,,这可能混乱而又复杂 Dialogue: 0,0:08:28.86,0:08:30.86,Default,,0,0,0,,但另一方面 我会把它放到一个小盒子中 Dialogue: 0,0:08:31.96,0:08:33.92,Default,,0,0,0,,如果有必要的话 我们可以打开那个盒子 Dialogue: 0,0:08:34.12,0:08:35.63,Default,,0,0,0,,看看其中有些什么 Dialogue: 0,0:08:37.77,0:08:39.16,Default,,0,0,0,,这就是那个小盒子 Dialogue: 0,0:08:39.20,0:08:40.38,Default,,0,0,0,,我这么来画它 Dialogue: 0,0:08:43.16,0:08:44.38,Default,,0,0,0,,我把它叫做REM Dialogue: 0,0:08:46.44,0:08:48.60,Default,,0,0,0,,它接受A Dialogue: 0,0:08:50.91,0:08:52.16,Default,,0,0,0,,同时也要接受B Dialogue: 0,0:08:54.37,0:08:56.51,Default,,0,0,0,,它有一个输出 Dialogue: 0,0:08:58.89,0:09:00.46,Default,,0,0,0,,也就是A除以B的余数 Dialogue: 0,0:09:02.29,0:09:03.61,Default,,0,0,0,,在这里 我们同样需要能够 Dialogue: 0,0:09:03.64,0:09:06.06,Default,,0,0,0,,判断B是否等于0 Dialogue: 0,0:09:08.00,0:09:09.66,Default,,0,0,0,,也就是说 总得有个东西 Dialogue: 0,0:09:10.00,0:09:12.30,Default,,0,0,0,,去查询B的值 Dialogue: 0,0:09:13.39,0:09:14.40,Default,,0,0,0,,这是一个指示灯 Dialogue: 0,0:09:15.85,0:09:17.39,Default,,0,0,0,,当B等于0时 它就会点亮 Dialogue: 0,0:09:21.11,0:09:22.01,Default,,0,0,0,,它就是干这个的 Dialogue: 0,0:09:24.03,0:09:26.78,Default,,0,0,0,,最后 因为我们希望 Dialogue: 0,0:09:26.96,0:09:30.43,Default,,0,0,0,,A的新值是B的旧值 Dialogue: 0,0:09:30.46,0:09:34.41,Default,,0,0,0,,同时B的新值是有关于A的 Dialogue: 0,0:09:35.28,0:09:37.60,Default,,0,0,0,,如果我打算让机器 Dialogue: 0,0:09:37.80,0:09:39.74,Default,,0,0,0,,一次只发生一件事 Dialogue: 0,0:09:40.20,0:09:41.40,Default,,0,0,0,,一次执行一个动作 Dialogue: 0,0:09:41.61,0:09:43.42,Default,,0,0,0,,并且我不能在一个寄存器中放两个数字 Dialogue: 0,0:09:44.03,0:09:46.30,Default,,0,0,0,,那么进行互换时 必须有另外的地方放置一个数字 Dialogue: 0,0:09:49.29,0:09:49.60,Default,,0,0,0,,对吧? Dialogue: 0,0:09:50.00,0:09:51.85,Default,,0,0,0,,我不能同时交换两手的东西 Dialogue: 0,0:09:52.11,0:09:53.72,Default,,0,0,0,,除非我一手拿两个 Dialogue: 0,0:09:53.72,0:09:55.13,Default,,0,0,0,,然后从中取另外一个 Dialogue: 0,0:09:55.50,0:09:56.91,Default,,0,0,0,,或者我先放下一个 Dialogue: 0,0:09:57.02,0:09:58.68,Default,,0,0,0,,取得另一个后再像这样捡起来 Dialogue: 0,0:09:59.64,0:10:00.94,Default,,0,0,0,,除非我是耍杂技的 Dialogue: 0,0:10:01.66,0:10:03.50,Default,,0,0,0,,当然正如大家所见 我并不是 Dialogue: 0,0:10:04.65,0:10:07.36,Default,,0,0,0,,这种情况下 我就会遇到时序错误 Dialogue: 0,0:10:08.85,0:10:11.04,Default,,0,0,0,,事实上 人们所做的许多类型的计算机设计 Dialogue: 0,0:10:11.07,0:10:12.68,Default,,0,0,0,,都遇到了时序错误 Dialogue: 0,0:10:13.12,0:10:15.00,Default,,0,0,0,,或者潜在的时序错误 Dialogue: 0,0:10:15.24,0:10:16.43,Default,,0,0,0,,我不太喜欢这种错误 Dialogue: 0,0:10:17.34,0:10:18.64,Default,,0,0,0,,因此 出于这个原因 Dialogue: 0,0:10:18.68,0:10:21.21,Default,,0,0,0,,我需要有一个地方来放置 Dialogue: 0,0:10:22.06,0:10:23.29,Default,,0,0,0,,其中的一个元素 Dialogue: 0,0:10:23.41,0:10:24.72,Default,,0,0,0,,因此 这里有一个寄存器 Dialogue: 0,0:10:24.75,0:10:26.84,Default,,0,0,0,,用来存放临时值T Dialogue: 0,0:10:28.59,0:10:29.63,Default,,0,0,0,,上面有一个按钮 Dialogue: 0,0:10:30.47,0:10:31.88,Default,,0,0,0,,我会使用它的结果 Dialogue: 0,0:10:31.90,0:10:34.14,Default,,0,0,0,,因为我需要把这个结果送入B Dialogue: 0,0:10:34.68,0:10:36.73,Default,,0,0,0,,我们会把结果像这样给送过来 Dialogue: 0,0:10:38.41,0:10:39.30,Default,,0,0,0,,这里同样有一个按钮 Dialogue: 0,0:10:42.43,0:10:45.84,Default,,0,0,0,,这就是GCD机器的数据通路 Dialogue: 0,0:10:47.60,0:10:48.57,Default,,0,0,0,,那么 控制器又是怎样的呢? Dialogue: 0,0:10:49.74,0:10:51.28,Default,,0,0,0,,控制器同样很简单 Dialogue: 0,0:10:52.28,0:10:53.26,Default,,0,0,0,,机器具有状态 Dialogue: 0,0:10:54.38,0:10:57.72,Default,,0,0,0,,我喜欢形象地把它们比作迷宫 Dialogue: 0,0:10:59.01,0:11:03.20,Default,,0,0,0,,这个迷宫的各处是通过直接的箭头连接的 Dialogue: 0,0:11:04.43,0:11:05.60,Default,,0,0,0,,而我有一颗弹珠 Dialogue: 0,0:11:06.46,0:11:09.07,Default,,0,0,0,,它代表了控制器的状态 Dialogue: 0,0:11:10.74,0:11:12.27,Default,,0,0,0,,弹珠在迷宫中四处滚动 Dialogue: 0,0:11:13.74,0:11:17.15,Default,,0,0,0,,当然 这种类比因能量的原因而不成立 Dialogue: 0,0:11:17.15,0:11:19.08,Default,,0,0,0,,有时我不得不将弹珠泵到顶部 Dialogue: 0,0:11:19.12,0:11:21.85,Default,,0,0,0,,不然它就会成为一台永动机 Dialogue: 0,0:11:22.00,0:11:23.32,Default,,0,0,0,,但不用担心那么多 Dialogue: 0,0:11:23.90,0:11:25.90,Default,,0,0,0,,这并不是一个物理比喻 Dialogue: 0,0:11:26.08,0:11:27.42,Default,,0,0,0,,弹珠到处滚动 Dialogue: 0,0:11:27.68,0:11:29.56,Default,,0,0,0,,就像弹球机一样 Dialogue: 0,0:11:29.68,0:11:30.97,Default,,0,0,0,,每次当它滚动到一些缓冲器时 Dialogue: 0,0:11:31.26,0:11:32.60,Default,,0,0,0,,它就会按下这些按钮 Dialogue: 0,0:11:34.83,0:11:37.50,Default,,0,0,0,,它也会经常来到一个分支区域 Dialogue: 0,0:11:38.62,0:11:39.68,Default,,0,0,0,,它要在这里做选择 Dialogue: 0,0:11:40.25,0:11:42.36,Default,,0,0,0,,然后有一个由这个组件控制的挡板 Dialogue: 0,0:11:46.00,0:11:48.82,Default,,0,0,0,,所以这是一个非常机械化的思考方式 Dialogue: 0,0:11:48.82,0:11:51.05,Default,,0,0,0,,当然 真实计算机中的控制器 Dialogue: 0,0:11:51.08,0:11:51.84,Default,,0,0,0,,并不是这样的 Dialogue: 0,0:11:51.84,0:11:56.01,Default,,0,0,0,,而是由一些ROM和状态寄存器构成 Dialogue: 0,0:11:56.61,0:11:58.73,Default,,0,0,0,,但曾几何时 像DEC、PDP-6这些个机器 Dialogue: 0,0:11:59.29,0:12:01.02,Default,,0,0,0,,它们的控制器就是我们说的那样 Dialogue: 0,0:12:01.80,0:12:03.61,Default,,0,0,0,,延迟线上有一些比特信息 Dialogue: 0,0:12:05.69,0:12:08.14,Default,,0,0,0,,它随着时间的推移而触发事件 Dialogue: 0,0:12:08.58,0:12:10.70,Default,,0,0,0,,然后回到开始并再次轮回 Dialogue: 0,0:12:11.99,0:12:13.72,Default,,0,0,0,,当然 还有各种各样的错误 Dialogue: 0,0:12:13.74,0:12:17.67,Default,,0,0,0,,比如两个比特的信息 -- 对应两个弹珠 Dialogue: 0,0:12:17.67,0:12:19.26,Default,,0,0,0,,机器也会丢失弹珠 Dialogue: 0,0:12:19.45,0:12:20.20,Default,,0,0,0,,这也会发生 Dialogue: 0,0:12:20.98,0:12:21.58,Default,,0,0,0,,好吧 Dialogue: 0,0:12:22.27,0:12:24.22,Default,,0,0,0,,无论如何 对于这台机器 Dialogue: 0,0:12:24.27,0:12:25.48,Default,,0,0,0,,我想要这么来做 Dialogue: 0,0:12:25.80,0:12:27.74,Default,,0,0,0,,迷宫从这里开始 Dialogue: 0,0:12:30.52,0:12:32.73,Default,,0,0,0,,我首先要做的是 Dialogue: 0,0:12:33.76,0:12:36.75,Default,,0,0,0,,用一个你们非常熟悉的流程图记号 Dialogue: 0,0:12:37.07,0:12:39.85,Default,,0,0,0,,这是一个判断:B是否为0 Dialogue: 0,0:12:41.50,0:12:43.79,Default,,0,0,0,,如果判断为是的话 Dialogue: 0,0:12:43.93,0:12:45.58,Default,,0,0,0,,那我就做完了 Dialogue: 0,0:12:49.79,0:12:51.26,Default,,0,0,0,,否则的话 Dialogue: 0,0:12:52.70,0:12:54.32,Default,,0,0,0,,我就不得不滚动一些缓冲器 Dialogue: 0,0:12:55.00,0:12:56.46,Default,,0,0,0,,按照下列顺序执行 Dialogue: 0,0:12:57.42,0:13:03.40,Default,,0,0,0,,我想向这样来做一个互换游戏 Dialogue: 0,0:13:04.05,0:13:05.80,Default,,0,0,0,,首先 因为我需要A和B Dialogue: 0,0:13:06.32,0:13:08.57,Default,,0,0,0,,但首先 -- 虽然并不是必要的 Dialogue: 0,0:13:08.65,0:13:09.72,Default,,0,0,0,,我需要先把它们收集起来 Dialogue: 0,0:13:11.07,0:13:12.62,Default,,0,0,0,,这里的值要送入到B中 Dialogue: 0,0:13:13.24,0:13:14.03,Default,,0,0,0,,因此 我会说 Dialogue: 0,0:13:14.28,0:13:16.27,Default,,0,0,0,,用A和B的值来计算这个 Dialogue: 0,0:13:16.36,0:13:18.67,Default,,0,0,0,,并把算得的余数放到这里 Dialogue: 0,0:13:19.15,0:13:20.33,Default,,0,0,0,,因此 我首先要按下这个按钮 Dialogue: 0,0:13:21.53,0:13:24.43,Default,,0,0,0,,然后我要把B的值送入A Dialogue: 0,0:13:24.44,0:13:25.60,Default,,0,0,0,,通过按这个钮来实现 Dialogue: 0,0:13:25.82,0:13:27.63,Default,,0,0,0,,然后我再把临时值送入B Dialogue: 0,0:13:28.76,0:13:29.42,Default,,0,0,0,,通过这个按钮实现 Dialogue: 0,0:13:32.03,0:13:34.97,Default,,0,0,0,,这是一个相当时序化的机器 Dialogue: 0,0:13:35.39,0:13:36.52,Default,,0,0,0,,它非常的低效 Dialogue: 0,0:13:37.75,0:13:39.05,Default,,0,0,0,,但目前来说还好 Dialogue: 0,0:13:39.81,0:13:40.97,Default,,0,0,0,,我们来为按钮命名 Dialogue: 0,0:13:41.47,0:13:42.72,Default,,0,0,0,,T←R Dialogue: 0,0:13:46.75,0:13:48.73,Default,,0,0,0,,A←B Dialogue: 0,0:13:50.03,0:13:54.81,Default,,0,0,0,,B←T Dialogue: 0,0:13:55.47,0:13:57.63,Default,,0,0,0,,然后我要来到这里 Dialogue: 0,0:13:58.78,0:13:59.88,Default,,0,0,0,,也就是回到开始的地方 Dialogue: 0,0:14:01.62,0:14:03.87,Default,,0,0,0,,在这里 我们看到了什么? Dialogue: 0,0:14:03.87,0:14:04.91,Default,,0,0,0,,我们看到各种各样的 -- Dialogue: 0,0:14:05.05,0:14:07.16,Default,,0,0,0,,我们真正拥有的是某种机械连接 Dialogue: 0,0:14:07.42,0:14:13.63,Default,,0,0,0,,其中T←R控制了这个东西 Dialogue: 0,0:14:16.83,0:14:21.48,Default,,0,0,0,,A←B控制了这个东西 Dialogue: 0,0:14:26.96,0:14:28.12,Default,,0,0,0,,而这里的这个东西 Dialogue: 0,0:14:28.12,0:14:31.08,Default,,0,0,0,,同学们 这简直太恶劣了 Dialogue: 0,0:14:31.48,0:14:32.48,Default,,0,0,0,,一点也没有优化 Dialogue: 0,0:14:32.63,0:14:34.59,Default,,0,0,0,,我画的所有线条都相互交叉 Dialogue: 0,0:14:38.54,0:14:41.15,Default,,0,0,0,,我想B←T控制的是这个 Dialogue: 0,0:14:45.69,0:14:47.95,Default,,0,0,0,,现在 我就要运行这台机器了 Dialogue: 0,0:14:48.04,0:14:49.34,Default,,0,0,0,,但是在我运行它之前 Dialogue: 0,0:14:49.37,0:14:51.40,Default,,0,0,0,,我想写下它的控制器的描述 Dialogue: 0,0:14:51.63,0:14:52.81,Default,,0,0,0,,以便使你们相信 Dialogue: 0,0:14:52.84,0:14:55.63,Default,,0,0,0,,这些东西可以组织成某种良好的语言 Dialogue: 0,0:14:56.08,0:14:58.08,Default,,0,0,0,,这样我们就不必总是像这样画图 Dialogue: 0,0:14:58.36,0:15:00.68,Default,,0,0,0,,图示的缺陷之一 就是占用了太多空间 Dialogue: 0,0:15:00.89,0:15:01.98,Default,,0,0,0,,对于这样的一个小型机器来说 Dialogue: 0,0:15:02.00,0:15:03.05,Default,,0,0,0,,它占用了两块黑板 Dialogue: 0,0:15:03.22,0:15:05.24,Default,,0,0,0,,而一台求值器机器 Dialogue: 0,0:15:05.40,0:15:07.10,Default,,0,0,0,,我就很难将它画在这间屋子里了 Dialogue: 0,0:15:07.95,0:15:09.16,Default,,0,0,0,,尽管它还不是非常大 Dialogue: 0,0:15:09.90,0:15:11.28,Default,,0,0,0,,因此我要为它构造一门小型语言 Dialogue: 0,0:15:11.29,0:15:12.51,Default,,0,0,0,,用来描述这个机器 Dialogue: 0,0:15:13.10,0:15:23.29,Default,,0,0,0,,(DEFIME-MACHINE GCD Dialogue: 0,0:15:24.42,0:15:25.66,Default,,0,0,0,,当然 一旦我们有了像这样的描述 Dialogue: 0,0:15:25.68,0:15:26.83,Default,,0,0,0,,我们就能够模拟该机器 Dialogue: 0,0:15:27.22,0:15:29.42,Default,,0,0,0,,我之所以想构建这种形式的语言 Dialogue: 0,0:15:29.56,0:15:32.94,Default,,0,0,0,,是因为我们能够立即操纵这些表达式 Dialogue: 0,0:15:33.21,0:15:34.91,Default,,0,0,0,,因此 我也就能够 Dialogue: 0,0:15:35.29,0:15:38.16,Default,,0,0,0,,代数地操作 或者模拟这些东西 Dialogue: 0,0:15:38.20,0:15:39.96,Default,,0,0,0,,以及各种各样我想进行的操作 Dialogue: 0,0:15:40.12,0:15:42.59,Default,,0,0,0,,或者还可以把它们转换成布局图 谁知道呢? Dialogue: 0,0:15:43.63,0:15:48.38,Default,,0,0,0,,一旦我有了寄存器的良好表示 Dialogue: 0,0:15:48.51,0:15:49.61,Default,,0,0,0,,它有一些寄存器 Dialogue: 0,0:15:53.00,0:15:55.64,Default,,0,0,0,,记作(REGISTERS A B T) Dialogue: 0,0:15:56.75,0:15:57.80,Default,,0,0,0,,它还有控制器 Dialogue: 0,0:16:02.19,0:16:04.46,Default,,0,0,0,,实际上 更好的做法是让它更显式一些 Dialogue: 0,0:16:04.49,0:16:06.97,Default,,0,0,0,,也就是说 为每一个按钮命名 Dialogue: 0,0:16:08.14,0:16:10.17,Default,,0,0,0,,并指明它们的操作 Dialogue: 0,0:16:10.42,0:16:11.37,Default,,0,0,0,,比如说这个按钮 Dialogue: 0,0:16:11.55,0:16:14.19,Default,,0,0,0,,会让T的值送入到B中 Dialogue: 0,0:16:15.10,0:16:16.09,Default,,0,0,0,,但我却不想这么做 Dialogue: 0,0:16:16.11,0:16:17.95,Default,,0,0,0,,因为这样会让代码难以阅读 Dialogue: 0,0:16:18.20,0:16:19.34,Default,,0,0,0,,也会占用更多空间 Dialogue: 0,0:16:19.51,0:16:22.36,Default,,0,0,0,,所以我会把相关的指令写在控制器中 Dialogue: 0,0:16:23.29,0:16:25.24,Default,,0,0,0,,这样就隐式地指明了具体的操作 Dialogue: 0,0:16:26.32,0:16:28.57,Default,,0,0,0,,可以通过阅读代码推断出来 Dialogue: 0,0:16:29.16,0:16:31.39,Default,,0,0,0,,并收集所有可以完成的不同事情 Dialogue: 0,0:16:31.69,0:16:33.50,Default,,0,0,0,,我们来看一看 Dialogue: 0,0:16:33.50,0:16:34.70,Default,,0,0,0,,我们来看下这些东西是什么吧 Dialogue: 0,0:16:35.71,0:16:37.29,Default,,0,0,0,,首先是一个循环 Dialogue: 0,0:16:38.24,0:16:40.20,Default,,0,0,0,,先是一条分支指令 Dialogue: 0,0:16:42.64,0:16:46.46,Default,,0,0,0,,这个就对应了机器中的小挡板 Dialogue: 0,0:16:46.89,0:16:48.49,Default,,0,0,0,,它决定了你在此处的走向 Dialogue: 0,0:16:49.10,0:16:58.00,Default,,0,0,0,,判断 -- 取B的值 并判断是否为0 Dialogue: 0,0:16:58.65,0:17:00.06,Default,,0,0,0,,如果B的值是0 Dialogue: 0,0:17:00.32,0:17:01.72,Default,,0,0,0,,那么就跳转到一个叫DONE的地方 Dialogue: 0,0:17:03.64,0:17:05.29,Default,,0,0,0,,现在 你们在这里看到的是 Dialogue: 0,0:17:05.29,0:17:07.40,Default,,0,0,0,,这个看起来非常像传统计算机语言 Dialogue: 0,0:17:08.17,0:17:09.55,Default,,0,0,0,,但你们所见的是 Dialogue: 0,0:17:10.03,0:17:12.00,Default,,0,0,0,,一些个标签 Dialogue: 0,0:17:12.99,0:17:16.86,Default,,0,0,0,,它们代表着存放了一系列指令的地方 Dialogue: 0,0:17:17.60,0:17:18.94,Default,,0,0,0,,之所以需要它们 Dialogue: 0,0:17:19.48,0:17:21.15,Default,,0,0,0,,是因为在这里 Dialogue: 0,0:17:21.45,0:17:22.81,Default,,0,0,0,,我表达了“循环”的概念 Dialogue: 0,0:17:23.32,0:17:26.11,Default,,0,0,0,,但是如果我是在写英文之类的文本 Dialogue: 0,0:17:26.44,0:17:28.09,Default,,0,0,0,,就很难去引用一个位置 Dialogue: 0,0:17:28.58,0:17:29.53,Default,,0,0,0,,我没有箭头 Dialogue: 0,0:17:30.80,0:17:33.02,Default,,0,0,0,,箭头是通过 Dialogue: 0,0:17:33.05,0:17:34.44,Default,,0,0,0,,给箭头所指的地方命名来表示的 Dialogue: 0,0:17:34.57,0:17:36.28,Default,,0,0,0,,并通过名字来引用 Dialogue: 0,0:17:37.40,0:17:38.59,Default,,0,0,0,,这只是一种编码 Dialogue: 0,0:17:39.86,0:17:41.88,Default,,0,0,0,,而不是某种魔法 Dialogue: 0,0:17:43.15,0:17:44.96,Default,,0,0,0,,接下来我们要做的是 Dialogue: 0,0:17:45.02,0:17:46.84,Default,,0,0,0,,我们如何来实现T←R Dialogue: 0,0:17:47.45,0:17:49.76,Default,,0,0,0,,非常简单 用ASSIGN Dialogue: 0,0:17:52.19,0:17:55.55,Default,,0,0,0,,我们把余数赋值给T Dialogue: 0,0:17:56.32,0:17:59.24,Default,,0,0,0,,ASSIGN就是按钮的名字 Dialogue: 0,0:18:01.47,0:18:02.64,Default,,0,0,0,,就是按按钮的家伙 Dialogue: 0,0:18:03.14,0:18:04.97,Default,,0,0,0,,把余数赋给T Dialogue: 0,0:18:04.99,0:18:06.76,Default,,0,0,0,,这个操作是这样表示的 Dialogue: 0,0:18:11.74,0:18:17.53,Default,,0,0,0,,取A、B的值 相除得到余数 Dialogue: 0,0:18:23.85,0:18:30.99,Default,,0,0,0,,同时 我们也要取B的值 赋给A Dialogue: 0,0:18:34.99,0:18:47.88,Default,,0,0,0,,再取T的值赋给B Dialogue: 0,0:18:49.61,0:18:51.85,Default,,0,0,0,,现在 我需要引用这个开头 Dialogue: 0,0:18:53.18,0:18:55.92,Default,,0,0,0,,呃 我为什么不把这里叫做LOOP呢? Dialogue: 0,0:19:04.09,0:19:07.04,Default,,0,0,0,,这就是如何引用这个箭头 Dialogue: 0,0:19:07.61,0:19:08.95,Default,,0,0,0,,当执行到DONE时 就完成了所有操作 Dialogue: 0,0:19:09.02,0:19:13.07,Default,,0,0,0,,我们来到了这里 所有指令的结尾 Dialogue: 0,0:19:15.26,0:19:17.04,Default,,0,0,0,,这段文字化描述的就是 Dialogue: 0,0:19:17.69,0:19:20.86,Default,,0,0,0,,我们在这里画的一小部分机器 Dialogue: 0,0:19:21.66,0:19:24.84,Default,,0,0,0,,下面 我就要运行它 Dialogue: 0,0:19:25.49,0:19:26.65,Default,,0,0,0,,我想让你们感受一下它的运行 Dialogue: 0,0:19:27.62,0:19:29.80,Default,,0,0,0,,从来没有做过这个 你必须做一次 Dialogue: 0,0:19:31.01,0:19:32.62,Default,,0,0,0,,让我们以一个具体的问题来演示 Dialogue: 0,0:19:33.10,0:19:34.70,Default,,0,0,0,,假设我们想要计算 Dialogue: 0,0:19:35.04,0:19:40.68,Default,,0,0,0,,30和42的最大公约数 Dialogue: 0,0:19:42.21,0:19:44.92,Default,,0,0,0,,我现在不知道结果是多少 Dialogue: 0,0:19:45.86,0:19:47.60,Default,,0,0,0,,但我知道A=30而B=42 Dialogue: 0,0:19:50.96,0:19:52.09,Default,,0,0,0,,我就这么着开始 Dialogue: 0,0:19:52.60,0:19:53.90,Default,,0,0,0,,那么 我首先要做些什么呢? Dialogue: 0,0:19:54.24,0:19:56.86,Default,,0,0,0,,我先判断B是否为0:否 Dialogue: 0,0:19:57.59,0:20:02.11,Default,,0,0,0,,然后计算A除B的余数 并赋给T Dialogue: 0,0:20:02.80,0:20:07.60,Default,,0,0,0,,当然 30除以42的余数就是30自己 Dialogue: 0,0:20:11.13,0:20:12.03,Default,,0,0,0,,按下那个按钮 Dialogue: 0,0:20:12.92,0:20:15.10,Default,,0,0,0,,现在弹珠就滚动到了这里 Dialogue: 0,0:20:17.10,0:20:18.06,Default,,0,0,0,,A←B Dialogue: 0,0:20:19.02,0:20:20.76,Default,,0,0,0,,又按下了这个按钮 Dialogue: 0,0:20:21.22,0:20:22.54,Default,,0,0,0,,因此42来到了这里 Dialogue: 0,0:20:26.59,0:20:27.60,Default,,0,0,0,,B←T Dialogue: 0,0:20:28.36,0:20:29.34,Default,,0,0,0,,按下了这个按钮 Dialogue: 0,0:20:29.87,0:20:30.96,Default,,0,0,0,,30来到了这里 Dialogue: 0,0:20:32.57,0:20:33.69,Default,,0,0,0,,这样我就交换了它们 Dialogue: 0,0:20:34.66,0:20:38.27,Default,,0,0,0,,我们再来看看 回到开始 Dialogue: 0,0:20:38.64,0:20:39.72,Default,,0,0,0,,B为0么?不 Dialogue: 0,0:20:40.19,0:20:41.50,Default,,0,0,0,,将余数赋给T Dialogue: 0,0:20:43.23,0:20:46.30,Default,,0,0,0,,我想 42除以30的余数是12 Dialogue: 0,0:20:47.24,0:20:48.30,Default,,0,0,0,,按下这个钮 Dialogue: 0,0:20:48.53,0:20:51.40,Default,,0,0,0,,下面 我想让30来到这里 Dialogue: 0,0:20:53.90,0:20:55.95,Default,,0,0,0,,按下这个钮 让12来到这里 Dialogue: 0,0:20:58.41,0:21:00.38,Default,,0,0,0,,然后继续 Dialogue: 0,0:21:00.38,0:21:01.31,Default,,0,0,0,,程序执行完了么? Dialogue: 0,0:21:01.53,0:21:02.12,Default,,0,0,0,,并没有 Dialogue: 0,0:21:02.36,0:21:08.22,Default,,0,0,0,,现在 我需要求解30除以12的余数 Dialogue: 0,0:21:08.85,0:21:10.67,Default,,0,0,0,,我想答案是6 Dialogue: 0,0:21:12.42,0:21:15.13,Default,,0,0,0,,按下这个钮 6就到了这里 Dialogue: 0,0:21:16.20,0:21:18.25,Default,,0,0,0,,然后我又按下这个钮 Dialogue: 0,0:21:18.30,0:21:19.61,Default,,0,0,0,,这就让12来到了这里 Dialogue: 0,0:21:23.73,0:21:25.09,Default,,0,0,0,,然后我又按下这个按钮 Dialogue: 0,0:21:25.09,0:21:26.00,Default,,0,0,0,,6就来到了这里 Dialogue: 0,0:21:29.85,0:21:31.68,Default,,0,0,0,,6等于0么? Dialogue: 0,0:21:31.88,0:21:32.49,Default,,0,0,0,,不等于 Dialogue: 0,0:21:33.42,0:21:33.98,Default,,0,0,0,,好的 Dialogue: 0,0:21:34.38,0:21:36.80,Default,,0,0,0,,因此这时 Dialogue: 0,0:21:36.89,0:21:38.12,Default,,0,0,0,,接下来又要计算余数 Dialogue: 0,0:21:38.14,0:21:39.80,Default,,0,0,0,,哦 这个的余数是0 Dialogue: 0,0:21:40.66,0:21:41.74,Default,,0,0,0,,看起来我们就快完成了 Dialogue: 0,0:21:42.36,0:21:44.36,Default,,0,0,0,,将6从这里挪到这里 Dialogue: 0,0:21:47.00,0:21:48.27,Default,,0,0,0,,0移动到这里 Dialogue: 0,0:21:49.09,0:21:50.20,Default,,0,0,0,,0等于0么? Dialogue: 0,0:21:50.20,0:21:50.73,Default,,0,0,0,,是的 Dialogue: 0,0:21:51.34,0:21:53.36,Default,,0,0,0,,B的值等于0 因此答案就是A的值 Dialogue: 0,0:21:54.28,0:21:55.76,Default,,0,0,0,,因此答案就是6 Dialogue: 0,0:21:56.61,0:21:57.61,Default,,0,0,0,,这确实是正确的答案 Dialogue: 0,0:21:57.63,0:21:59.47,Default,,0,0,0,,因为如果我们回过头审视最初的问题 Dialogue: 0,0:22:00.08,0:22:06.64,Default,,0,0,0,,我们知道30=2×3×5 Dialogue: 0,0:22:07.00,0:22:11.12,Default,,0,0,0,,42=2×3×7 Dialogue: 0,0:22:11.67,0:22:14.11,Default,,0,0,0,,因此最大公约数就是2×3 Dialogue: 0,0:22:14.20,0:22:15.08,Default,,0,0,0,,也就是6 Dialogue: 0,0:22:18.38,0:22:20.56,Default,,0,0,0,,我们通常在这里画另外一条线 Dialogue: 0,0:22:20.59,0:22:22.52,Default,,0,0,0,,为了使它更清晰一点 Dialogue: 0,0:22:22.89,0:22:27.71,Default,,0,0,0,,在这两者之间建立了联系 Dialogue: 0,0:22:27.85,0:22:31.01,Default,,0,0,0,,小挡板需要根据这个指示灯来工作 Dialogue: 0,0:22:34.00,0:22:37.32,Default,,0,0,0,,当然 跟我给你们展示的东西相比 Dialogue: 0,0:22:37.85,0:22:40.00,Default,,0,0,0,,真实计算机的组件更加复杂 Dialogue: 0,0:22:41.35,0:22:47.16,Default,,0,0,0,,让我们来看看第一张幻灯片 Dialogue: 0,0:22:47.98,0:22:48.81,Default,,0,0,0,,哇 Dialogue: 0,0:22:50.19,0:22:52.43,Default,,0,0,0,,我们看到 我们想要做的就是 Dialogue: 0,0:22:52.65,0:22:55.85,Default,,0,0,0,,IO形式的操作 Dialogue: 0,0:22:56.84,0:23:01.42,Default,,0,0,0,,我们需要从外部搜集一些东西 Dialogue: 0,0:23:01.98,0:23:03.93,Default,,0,0,0,,因此 对我们的状态机器来说 Dialogue: 0,0:23:04.30,0:23:07.02,Default,,0,0,0,,它们的控制器 Dialogue: 0,0:23:07.26,0:23:10.56,Default,,0,0,0,,可能会从某处取得某值 Dialogue: 0,0:23:10.78,0:23:12.41,Default,,0,0,0,,将它们放入寄存器并从中读取 Dialogue: 0,0:23:13.49,0:23:15.92,Default,,0,0,0,,我还可以把另外的值加载到寄存器B中 Dialogue: 0,0:23:17.07,0:23:18.60,Default,,0,0,0,,稍后 当执行完毕后 Dialogue: 0,0:23:18.99,0:23:20.52,Default,,0,0,0,,我想要输出结果 Dialogue: 0,0:23:21.20,0:23:25.23,Default,,0,0,0,,当然 答案或简单或复杂 Dialogue: 0,0:23:26.09,0:23:28.03,Default,,0,0,0,,我写代码的时候 总假设PRINT很简单 Dialogue: 0,0:23:28.09,0:23:29.29,Default,,0,0,0,,READ也很简单 Dialogue: 0,0:23:29.88,0:23:31.08,Default,,0,0,0,,但实际上 在真实世界中 Dialogue: 0,0:23:31.12,0:23:32.89,Default,,0,0,0,,这些都是非常复杂的操作 Dialogue: 0,0:23:33.08,0:23:35.52,Default,,0,0,0,,跟你尝试求解的问题相比 Dialogue: 0,0:23:35.55,0:23:38.33,Default,,0,0,0,,它们通常更加庞大而复杂 Dialogue: 0,0:23:41.67,0:23:43.90,Default,,0,0,0,,另一方面 我犹记得 Dialogue: 0,0:23:44.89,0:23:48.78,Default,,0,0,0,,使用IBM 7090一类的计算机的时候 Dialogue: 0,0:23:49.05,0:23:53.04,Default,,0,0,0,,它的READ和WRITE只能操作单个对象 Dialogue: 0,0:23:53.08,0:23:54.62,Default,,0,0,0,,也就是一个数字 Dialogue: 0,0:23:55.84,0:23:58.54,Default,,0,0,0,,这就是一个基本的IO操作 Dialogue: 0,0:23:59.63,0:24:02.04,Default,,0,0,0,,我们这里有同样的操作 Dialogue: 0,0:24:02.33,0:24:04.67,Default,,0,0,0,,在这样的一台机器中 Dialogue: 0,0:24:05.44,0:24:06.89,Default,,0,0,0,,我们实际上在做什么? Dialogue: 0,0:24:07.12,0:24:11.60,Default,,0,0,0,,我们看到 这个叫做“READ”的组件是数据源头 Dialogue: 0,0:24:12.20,0:24:14.46,Default,,0,0,0,,这个操作总是返回一个值 Dialogue: 0,0:24:14.66,0:24:17.13,Default,,0,0,0,,我们可以把它看做 总是返回一个值 Dialogue: 0,0:24:17.21,0:24:19.84,Default,,0,0,0,,它可以赋给寄存器A或B Dialogue: 0,0:24:21.66,0:24:23.23,Default,,0,0,0,,而PRINT这个过程呢 Dialogue: 0,0:24:23.37,0:24:25.02,Default,,0,0,0,,当你正确连接它的时候 Dialogue: 0,0:24:25.24,0:24:26.43,Default,,0,0,0,,当你按下上面的按钮 Dialogue: 0,0:24:26.65,0:24:29.61,Default,,0,0,0,,就会打印出当前寄存器A中的值 Dialogue: 0,0:24:31.66,0:24:32.73,Default,,0,0,0,,这非常普通 Dialogue: 0,0:24:33.32,0:24:35.20,Default,,0,0,0,,这是我们想要的一种功能 Dialogue: 0,0:24:35.88,0:24:38.32,Default,,0,0,0,,但这里还有些其它事情需要我们担忧 Dialogue: 0,0:24:38.32,0:24:40.67,Default,,0,0,0,,比如说 这里我使用了一些复杂的机制 Dialogue: 0,0:24:41.05,0:24:42.48,Default,,0,0,0,,我们这里有REMAINDER组件 Dialogue: 0,0:24:43.85,0:24:44.44,Default,,0,0,0,,这是个什么东西呢? Dialogue: 0,0:24:44.69,0:24:46.41,Default,,0,0,0,,求取余数的计算过程并不是那么“显然” Dialogue: 0,0:24:46.92,0:24:48.92,Default,,0,0,0,,如果我们把这个组件给拆开 Dialogue: 0,0:24:49.48,0:24:50.62,Default,,0,0,0,,就会得到一整台机器 Dialogue: 0,0:24:51.84,0:24:53.66,Default,,0,0,0,,事实就是这样的 Dialogue: 0,0:24:54.54,0:24:59.15,Default,,0,0,0,,举例来说 如果要编程实现REMAINDER Dialogue: 0,0:24:59.44,0:25:02.44,Default,,0,0,0,,最简单的算法就是 不断地做减法 Dialogue: 0,0:25:04.78,0:25:05.95,Default,,0,0,0,,这是因为 除法可以通过 Dialogue: 0,0:25:05.96,0:25:08.99,Default,,0,0,0,,对整数不断做减法来实现 Dialogue: 0,0:25:09.80,0:25:23.58,Default,,0,0,0,,N除以D的余数不外乎就是 Dialogue: 0,0:25:24.99,0:25:31.44,Default,,0,0,0,,如果N小于D的话 Dialogue: 0,0:25:32.24,0:25:33.66,Default,,0,0,0,,答案就是N Dialogue: 0,0:25:34.30,0:25:35.90,Default,,0,0,0,,否则的话就是 Dialogue: 0,0:25:41.15,0:25:47.60,Default,,0,0,0,,N先减去D Dialogue: 0,0:25:48.27,0:25:49.32,Default,,0,0,0,,再除以D的余数 Dialogue: 0,0:25:51.28,0:25:55.05,Default,,0,0,0,,天啊 这个看起来就像是GCD程序 Dialogue: 0,0:25:56.89,0:25:59.48,Default,,0,0,0,,当然 这个不是求余数的最优算法 Dialogue: 0,0:25:59.75,0:26:00.91,Default,,0,0,0,,在实际中 你应该使用那些 Dialogue: 0,0:26:00.92,0:26:05.42,Default,,0,0,0,,二进制运算、移位运算等操作 Dialogue: 0,0:26:05.55,0:26:06.97,Default,,0,0,0,,但关键点就是 Dialogue: 0,0:26:07.13,0:26:08.48,Default,,0,0,0,,如果我把这些组件打开 Dialogue: 0,0:26:08.92,0:26:10.64,Default,,0,0,0,,我可能会发现其中有一台计算机 Dialogue: 0,0:26:11.88,0:26:12.99,Default,,0,0,0,,现在我们就知道它的原理了 Dialogue: 0,0:26:13.51,0:26:14.33,Default,,0,0,0,,因为我们就造过一台 Dialogue: 0,0:26:15.64,0:26:17.10,Default,,0,0,0,,这些个机器都大同小异 Dialogue: 0,0:26:17.40,0:26:18.06,Default,,0,0,0,,另外一方面 Dialogue: 0,0:26:18.08,0:26:20.00,Default,,0,0,0,,我们可能想要构建一台更高效 Dialogue: 0,0:26:20.01,0:26:21.68,Default,,0,0,0,,组织更精良的机器 Dialogue: 0,0:26:21.85,0:26:23.96,Default,,0,0,0,,比如说 多次利用其中的寄存器 Dialogue: 0,0:26:24.00,0:26:27.05,Default,,0,0,0,,或者是硬件设计者能想到的其它可怕混乱 Dialogue: 0,0:26:27.31,0:26:28.60,Default,,0,0,0,,等等原因 Dialogue: 0,0:26:29.25,0:26:31.56,Default,,0,0,0,,比如说 你们所见的这台机器 Dialogue: 0,0:26:32.52,0:26:34.91,Default,,0,0,0,,不是让你们去细读它的结构的 Dialogue: 0,0:26:35.05,0:26:37.52,Default,,0,0,0,,它有些复杂 对吧? Dialogue: 0,0:26:37.52,0:26:39.87,Default,,0,0,0,,但它实际上是 Dialogue: 0,0:26:40.09,0:26:43.82,Default,,0,0,0,,整合了REMAINDER的GCD机器 Dialogue: 0,0:26:44.46,0:26:46.02,Default,,0,0,0,,并且实际上 它没有多余的寄存器 Dialogue: 0,0:26:46.02,0:26:48.62,Default,,0,0,0,,数据通路上有三个寄存器 Dialogue: 0,0:26:49.05,0:26:50.64,Default,,0,0,0,,但现在 这里有个减法器 Dialogue: 0,0:26:51.55,0:26:52.99,Default,,0,0,0,,又有两个东西被测试 Dialogue: 0,0:26:53.02,0:26:55.07,Default,,0,0,0,,B等于0么? Dialogue: 0,0:26:55.23,0:26:56.56,Default,,0,0,0,,T小于B么? Dialogue: 0,0:26:57.25,0:26:59.45,Default,,0,0,0,,而至于这一块的控制器 Dialogue: 0,0:27:00.22,0:27:01.76,Default,,0,0,0,,并不会更加复杂 Dialogue: 0,0:27:01.85,0:27:03.87,Default,,0,0,0,,它有两个循环 Dialogue: 0,0:27:04.52,0:27:08.33,Default,,0,0,0,,最主要的循环是计算GCD的 Dialogue: 0,0:27:08.40,0:27:10.14,Default,,0,0,0,,而另一条是减法循环 Dialogue: 0,0:27:10.43,0:27:12.80,Default,,0,0,0,,是用来计算余数的子操作 Dialogue: 0,0:27:14.03,0:27:15.80,Default,,0,0,0,,当然 还有一种思考方式 Dialogue: 0,0:27:15.96,0:27:18.68,Default,,0,0,0,,就是把求余数程序 Dialogue: 0,0:27:19.92,0:27:21.71,Default,,0,0,0,,如果我把那边的REMAINDER机器 Dialogue: 0,0:27:21.72,0:27:22.83,Default,,0,0,0,,当作LAMBDA表达式 Dialogue: 0,0:27:23.56,0:27:27.02,Default,,0,0,0,,代换到GCD程序的REMAINDER中 Dialogue: 0,0:27:28.20,0:27:30.12,Default,,0,0,0,,然后再做一些化简 Dialogue: 0,0:27:30.32,0:27:33.66,Default,,0,0,0,,代换其中的A和B Dialogue: 0,0:27:34.46,0:27:35.95,Default,,0,0,0,,那么 我就可以展开这个循环 Dialogue: 0,0:27:36.63,0:27:39.42,Default,,0,0,0,,那么我就可以通过 Dialogue: 0,0:27:40.73,0:27:42.94,Default,,0,0,0,,LAMBDA表达式的基本代数化简 Dialogue: 0,0:27:43.36,0:27:45.21,Default,,0,0,0,,来得到这台机器 Dialogue: 0,0:27:48.55,0:27:51.20,Default,,0,0,0,,我想 你们已经见识了一个非常简单的机器了 Dialogue: 0,0:27:51.95,0:27:53.28,Default,,0,0,0,,有什么疑问么? Dialogue: 0,0:28:02.70,0:28:03.10,Default,,0,0,0,,很好 Dialogue: 0,0:28:05.36,0:28:06.54,Default,,0,0,0,,看起来很容易 难道不是吗? Dialogue: 0,0:28:10.14,0:28:11.32,Default,,0,0,0,,好吧 休息一下 谢谢大家 Dialogue: 0,0:28:12.54,0:28:24.94,Default,,0,0,0,,[音乐] Dialogue: 0,0:28:25.13,0:28:28.08,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:28:31.37,0:28:34.70,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:28:34.76,0:28:38.00,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:28:38.00,0:28:43.29,Declare,,0,0,0,,{\an2\fad(500,500)}寄存机器 Dialogue: 0,0:28:47.93,0:28:48.70,Default,,0,0,0,,教授:好吧 Dialogue: 0,0:28:49.37,0:28:52.46,Default,,0,0,0,,现在 你们已经知道如何去把迭代过程 Dialogue: 0,0:28:52.54,0:28:54.54,Default,,0,0,0,,或者是产生迭代计算的过程 Dialogue: 0,0:28:55.18,0:28:56.52,Default,,0,0,0,,变成一台机器 Dialogue: 0,0:28:57.77,0:29:00.04,Default,,0,0,0,,我想 接下来我们就应该考虑 Dialogue: 0,0:29:00.54,0:29:02.30,Default,,0,0,0,,如何来处理递归过程了 Dialogue: 0,0:29:02.81,0:29:05.05,Default,,0,0,0,,我们先从一个简单的阶乘过程开始 Dialogue: 0,0:29:11.20,0:29:16.94,Default,,0,0,0,,(DEFINE (FACT N) Dialogue: 0,0:29:19.63,0:29:24.25,Default,,0,0,0,,如果N=1 那么结果就是1 Dialogue: 0,0:29:24.62,0:29:27.69,Default,,0,0,0,,为了减少模拟它的工作量 我就使用1 Dialogue: 0,0:29:28.12,0:29:33.94,Default,,0,0,0,,否则结果就是(* N (FACT (- N 1))) Dialogue: 0,0:29:42.52,0:29:46.04,Default,,0,0,0,,正如你们所知 这个程序的不同之处在于 Dialogue: 0,0:29:46.65,0:29:50.36,Default,,0,0,0,,这里 我在计算(FACT (- N 1))之后 Dialogue: 0,0:29:50.67,0:29:52.26,Default,,0,0,0,,我要对结果做一些运算 Dialogue: 0,0:29:52.26,0:29:53.68,Default,,0,0,0,,我要将它与N相乘 Dialogue: 0,0:29:56.00,0:30:00.67,Default,,0,0,0,,将这台机器可视化的唯一途径就是 Dialogue: 0,0:30:01.08,0:30:02.01,Default,,0,0,0,,首先 由于-- Dialogue: 0,0:30:02.35,0:30:03.18,Default,,0,0,0,,请你们这么来想 Dialogue: 0,0:30:03.36,0:30:04.94,Default,,0,0,0,,这里 我有一台机器 Dialogue: 0,0:30:05.08,0:30:08.11,Default,,0,0,0,,而这台机器又需要某个阶乘机器来计算结果 Dialogue: 0,0:30:09.32,0:30:11.16,Default,,0,0,0,,但外面的这台机器 Dialogue: 0,0:30:11.20,0:30:13.02,Default,,0,0,0,,又需要在调用内部阶乘机器 Dialogue: 0,0:30:13.92,0:30:15.72,Default,,0,0,0,,的前后都要存在 Dialogue: 0,0:30:16.80,0:30:17.90,Default,,0,0,0,,然而在迭代情况中 Dialogue: 0,0:30:18.75,0:30:20.52,Default,,0,0,0,,外面的机器不需要 Dialogue: 0,0:30:20.91,0:30:24.01,Default,,0,0,0,,在内部机器运行后保持存在 Dialogue: 0,0:30:24.83,0:30:26.16,Default,,0,0,0,,这是因为你不需要回到 Dialogue: 0,0:30:26.19,0:30:27.53,Default,,0,0,0,,外部机器来进行其它操作 Dialogue: 0,0:30:28.64,0:30:30.06,Default,,0,0,0,,因此 我们这里的问题是 Dialogue: 0,0:30:30.27,0:30:30.97,Default,,0,0,0,,我们的机器内部 Dialogue: 0,0:30:31.00,0:30:32.73,Default,,0,0,0,,有一个同样的机器 Dialogue: 0,0:30:33.87,0:30:35.52,Default,,0,0,0,,一台无穷大的机器 Dialogue: 0,0:30:40.39,0:30:43.12,Default,,0,0,0,,这里面也有其它的东西 比如乘法器 Dialogue: 0,0:30:44.76,0:30:46.03,Default,,0,0,0,,它接收输入 Dialogue: 0,0:30:46.27,0:30:47.77,Default,,0,0,0,,这是-1操作 Dialogue: 0,0:30:48.12,0:30:49.31,Default,,0,0,0,,等等 Dialogue: 0,0:30:50.69,0:30:53.72,Default,,0,0,0,,你们可以想象 -- 它就是这个样子的 Dialogue: 0,0:30:54.37,0:30:56.76,Default,,0,0,0,,但重要之处就在于 Dialogue: 0,0:30:57.02,0:30:58.70,Default,,0,0,0,,内部机器执行之前与执行之后 Dialogue: 0,0:30:58.78,0:31:01.60,Default,,0,0,0,,外部机器中都进行了一些运算 Dialogue: 0,0:31:02.54,0:31:04.08,Default,,0,0,0,,因此这台机器必须有“生命” Dialogue: 0,0:31:05.47,0:31:11.44,Default,,0,0,0,,外部机器需要在内部机器的两个时间点保持存在 Dialogue: 0,0:31:13.49,0:31:15.80,Default,,0,0,0,,因此 我就需要有一个地方来保存 Dialogue: 0,0:31:16.19,0:31:18.19,Default,,0,0,0,,维持外部机器运转的数据 Dialogue: 0,0:31:20.03,0:31:22.09,Default,,0,0,0,,现实世界中不存在无穷的对象 Dialogue: 0,0:31:24.14,0:31:25.58,Default,,0,0,0,,我们要做的就是营造一种假象 Dialogue: 0,0:31:26.12,0:31:27.48,Default,,0,0,0,,一种无穷对象的假象 Dialogue: 0,0:31:27.98,0:31:29.77,Default,,0,0,0,,我们在某处有无穷的硬件资源 Dialogue: 0,0:31:31.83,0:31:35.34,Default,,0,0,0,,现在 这个假象非常重要 Dialogue: 0,0:31:36.28,0:31:37.37,Default,,0,0,0,,如果我们能保证 Dialogue: 0,0:31:38.00,0:31:39.84,Default,,0,0,0,,每次当你查看某个无穷对象时 Dialogue: 0,0:31:39.88,0:31:42.96,Default,,0,0,0,,你所要观察的那部分存在 Dialogue: 0,0:31:44.49,0:31:46.04,Default,,0,0,0,,那么就不需要实际上的“无穷” Dialogue: 0,0:31:47.39,0:31:49.44,Default,,0,0,0,,当然 这里面我们想做的就是 Dialogue: 0,0:31:49.82,0:31:52.49,Default,,0,0,0,,来看下这里的东西 Dialogue: 0,0:31:53.00,0:31:54.97,Default,,0,0,0,,这是我们目前为止的结构 Dialogue: 0,0:31:56.04,0:31:57.64,Default,,0,0,0,,这些结构呢 Dialogue: 0,0:31:57.92,0:32:01.37,Default,,0,0,0,,是机器的几大部分 Dialogue: 0,0:32:01.40,0:32:02.33,Default,,0,0,0,,比如控制器 Dialogue: 0,0:32:03.18,0:32:04.46,Default,,0,0,0,,它在这里 Dialogue: 0,0:32:04.78,0:32:07.61,Default,,0,0,0,,它相当简单 并且是有穷的 Dialogue: 0,0:32:09.17,0:32:10.44,Default,,0,0,0,,我们还有数据通路 Dialogue: 0,0:32:10.46,0:32:12.75,Default,,0,0,0,,它由寄存器和运算器组成 Dialogue: 0,0:32:13.08,0:32:15.20,Default,,0,0,0,,现在我提议 Dialogue: 0,0:32:15.48,0:32:16.96,Default,,0,0,0,,把机器分成两部分 Dialogue: 0,0:32:17.36,0:32:19.79,Default,,0,0,0,,这样 其中一部分全部是有穷的 Dialogue: 0,0:32:20.78,0:32:23.53,Default,,0,0,0,,而另一部分 可以保存无穷数据中的一部分 Dialogue: 0,0:32:24.23,0:32:25.90,Default,,0,0,0,,换句话说 这部分也非常简单 Dialogue: 0,0:32:26.41,0:32:28.72,Default,,0,0,0,,但并非无穷 只是非常大而已 Dialogue: 0,0:32:29.43,0:32:30.40,Default,,0,0,0,,但它非常简单 Dialogue: 0,0:32:30.52,0:32:32.92,Default,,0,0,0,,以至于能够廉价地大量生产 Dialogue: 0,0:32:34.09,0:32:34.92,Default,,0,0,0,,它就是内存 Dialogue: 0,0:32:35.95,0:32:39.07,Default,,0,0,0,,我们可以利用它来构造栈结构 Dialogue: 0,0:32:39.40,0:32:41.23,Default,,0,0,0,,事实上 这就使得我们 Dialogue: 0,0:32:41.45,0:32:43.63,Default,,0,0,0,,能够模拟无穷机器的存在 Dialogue: 0,0:32:43.64,0:32:46.96,Default,,0,0,0,,也就是那些递归嵌套的机器 Dialogue: 0,0:32:48.34,0:32:50.43,Default,,0,0,0,,而它的原理则是 Dialogue: 0,0:32:50.56,0:32:52.97,Default,,0,0,0,,我们要在栈上存放必要的信息 Dialogue: 0,0:32:54.30,0:32:57.58,Default,,0,0,0,,用于内部机器执行完毕后 Dialogue: 0,0:32:59.18,0:33:01.07,Default,,0,0,0,,继续外部机器的操作 Dialogue: 0,0:33:03.84,0:33:05.48,Default,,0,0,0,,因此它会记住 Dialogue: 0,0:33:05.63,0:33:07.95,Default,,0,0,0,,关于外部机器生命期的重要数据 Dialogue: 0,0:33:08.04,0:33:10.30,Default,,0,0,0,,这些是进行计算所必需的 Dialogue: 0,0:33:11.39,0:33:12.48,Default,,0,0,0,,当然 Dialogue: 0,0:33:12.75,0:33:16.33,Default,,0,0,0,,由于这些机器是通过递归的方式嵌套的 Dialogue: 0,0:33:18.33,0:33:23.39,Default,,0,0,0,,因此 栈的存取方式也会是 Dialogue: 0,0:33:23.45,0:33:26.44,Default,,0,0,0,,也会是后进先出的 Dialogue: 0,0:33:29.33,0:33:30.64,Default,,0,0,0,,因此我们只需要存取 Dialogue: 0,0:33:30.80,0:33:32.52,Default,,0,0,0,,这个栈内存的一小部分 Dialogue: 0,0:33:34.93,0:33:35.92,Default,,0,0,0,,好吧 让我们来试一试 Dialogue: 0,0:33:36.81,0:33:38.41,Default,,0,0,0,,我已经给你们画好了数据通路 Dialogue: 0,0:33:38.44,0:33:39.68,Default,,0,0,0,,现在该布置控制器了 Dialogue: 0,0:33:40.37,0:33:42.86,Default,,0,0,0,,然后我们来运行一下 观察实际工作原理 Dialogue: 0,0:33:43.51,0:33:46.88,Default,,0,0,0,,还好阶乘机器不是特别的复杂 Dialogue: 0,0:33:47.90,0:33:50.16,Default,,0,0,0,,它有一个VAL寄存器 Dialogue: 0,0:33:52.22,0:33:53.88,Default,,0,0,0,,这是用来存储答案的 Dialogue: 0,0:33:54.89,0:33:56.67,Default,,0,0,0,,还有一个寄存器N Dialogue: 0,0:33:59.85,0:34:04.16,Default,,0,0,0,,它里面存储的是要计算阶乘的数 Dialogue: 0,0:34:04.51,0:34:06.57,Default,,0,0,0,,为了满足某些情况 Dialogue: 0,0:34:07.48,0:34:10.52,Default,,0,0,0,,我们要连接VAL和N Dialogue: 0,0:34:11.74,0:34:15.63,Default,,0,0,0,,事实上 如果我在这里返回N Dialogue: 0,0:34:16.38,0:34:19.53,Default,,0,0,0,,也是正确的 因为这时N就等于1 Dialogue: 0,0:34:20.09,0:34:23.26,Default,,0,0,0,,这样的话 我就可以把结果移动过去 Dialogue: 0,0:34:23.90,0:34:25.55,Default,,0,0,0,,但我现在不考虑这个问题 Dialogue: 0,0:34:26.98,0:34:28.60,Default,,0,0,0,,我还需要做一些事情 Dialogue: 0,0:34:29.06,0:34:31.02,Default,,0,0,0,,就像我们在这里看到的 我们还需要 Dialogue: 0,0:34:31.21,0:34:34.67,Default,,0,0,0,,用VAL的值乘以N Dialogue: 0,0:34:34.91,0:34:37.45,Default,,0,0,0,,因为VAL是计算阶乘的结果 Dialogue: 0,0:34:38.68,0:34:40.44,Default,,0,0,0,,我需要把算得的结果送回VAL Dialogue: 0,0:34:41.48,0:34:42.65,Default,,0,0,0,,所以这里我们看到 Dialogue: 0,0:34:42.83,0:34:46.43,Default,,0,0,0,,N的阶乘就是 Dialogue: 0,0:34:46.57,0:34:49.20,Default,,0,0,0,,N乘以某个阶乘 Dialogue: 0,0:34:50.69,0:34:53.77,Default,,0,0,0,,而VAL就代表了内部阶乘的结果 Dialogue: 0,0:34:55.19,0:35:00.25,Default,,0,0,0,,因此 在这里我需要有一个乘法器 Dialogue: 0,0:35:02.36,0:35:07.18,Default,,0,0,0,,它的参数有:N以及VAL Dialogue: 0,0:35:08.64,0:35:15.60,Default,,0,0,0,,并且 像这样把计算结果送回VAL Dialogue: 0,0:35:17.17,0:35:19.39,Default,,0,0,0,,我也需要知道N是否为1 Dialogue: 0,0:35:21.32,0:35:22.38,Default,,0,0,0,,因此我需要一个指示灯 Dialogue: 0,0:35:28.20,0:35:30.40,Default,,0,0,0,,另外 我想我还需要 Dialogue: 0,0:35:31.02,0:35:32.84,Default,,0,0,0,,一个组件来减小N Dialogue: 0,0:35:34.84,0:35:36.09,Default,,0,0,0,,所以这里有一个递减器 Dialogue: 0,0:35:38.19,0:35:41.39,Default,,0,0,0,,它接收参数N 将结果送回N Dialogue: 0,0:35:46.62,0:35:48.40,Default,,0,0,0,,这基本上就是我的机器所需要的东西了 Dialogue: 0,0:35:49.55,0:35:51.64,Default,,0,0,0,,然而 我还需要一些个东西 Dialogue: 0,0:35:52.30,0:35:53.58,Default,,0,0,0,,一个稍微复杂一点的东西 Dialogue: 0,0:35:55.16,0:35:56.88,Default,,0,0,0,,因为我需要有一种方式能够存储 Dialogue: 0,0:35:57.16,0:35:59.69,Default,,0,0,0,,必要的一些信息 Dialogue: 0,0:36:01.02,0:36:03.07,Default,,0,0,0,,以便计算完子阶乘后 Dialogue: 0,0:36:03.10,0:36:04.89,Default,,0,0,0,,恢复原始阶乘的计算 Dialogue: 0,0:36:06.25,0:36:06.86,Default,,0,0,0,,需要哪些信息呢? Dialogue: 0,0:36:07.23,0:36:08.73,Default,,0,0,0,,首先就是N Dialogue: 0,0:36:09.85,0:36:12.04,Default,,0,0,0,,因此 我要在这里构造一个栈 Dialogue: 0,0:36:14.70,0:36:15.77,Default,,0,0,0,,所谓的栈就是 Dialogue: 0,0:36:17.98,0:36:24.97,Default,,0,0,0,,一大堆连续的空间 Dialogue: 0,0:36:27.15,0:36:28.59,Default,,0,0,0,,我不知道它到底有多深 Dialogue: 0,0:36:29.15,0:36:31.48,Default,,0,0,0,,栈越深 无穷的假象营造得就越好 Dialogue: 0,0:36:33.23,0:36:35.56,Default,,0,0,0,,我还需要有一种方法 能够把 Dialogue: 0,0:36:35.60,0:36:37.02,Default,,0,0,0,,N中的值放入栈中 Dialogue: 0,0:36:38.12,0:36:39.08,Default,,0,0,0,,反过来也是 Dialogue: 0,0:36:39.93,0:36:41.74,Default,,0,0,0,,因此我需要一条像这样的连接 Dialogue: 0,0:36:44.41,0:36:45.48,Default,,0,0,0,,它是双向的 Dialogue: 0,0:36:50.44,0:36:52.22,Default,,0,0,0,,通过它 我就可以在某个时间 Dialogue: 0,0:36:52.24,0:36:55.50,Default,,0,0,0,,把N的值存储起来 Dialogue: 0,0:36:56.04,0:36:56.84,Default,,0,0,0,,这就是栈 Dialogue: 0,0:36:58.10,0:37:01.71,Default,,0,0,0,,我还需要一种方法来记住 Dialogue: 0,0:37:01.84,0:37:07.72,Default,,0,0,0,,我现在计算到外部程序的哪个地方了 Dialogue: 0,0:37:08.53,0:37:10.06,Default,,0,0,0,,现在 对于这台机器来说 Dialogue: 0,0:37:10.76,0:37:13.34,Default,,0,0,0,,这并不是什么问题 Dialogue: 0,0:37:14.17,0:37:16.24,Default,,0,0,0,,FACT总是返回在 Dialogue: 0,0:37:16.86,0:37:19.07,Default,,0,0,0,,一个跟N相乘的地方 Dialogue: 0,0:37:19.34,0:37:20.72,Default,,0,0,0,,除了最后的一次 Dialogue: 0,0:37:21.15,0:37:23.02,Default,,0,0,0,,它返回到需要FACT最终答案的地方 Dialogue: 0,0:37:23.04,0:37:24.04,Default,,0,0,0,,或者是'DONE、'STOP之类的 Dialogue: 0,0:37:25.66,0:37:26.67,Default,,0,0,0,,然而 通常来说 Dialogue: 0,0:37:27.16,0:37:28.73,Default,,0,0,0,,我需要记住我去过哪些地方 Dialogue: 0,0:37:29.13,0:37:31.24,Default,,0,0,0,,因为 我可能从其它地方调用FACT Dialogue: 0,0:37:32.08,0:37:34.89,Default,,0,0,0,,我需要返回到那个地方 并从那里继续 Dialogue: 0,0:37:36.07,0:37:38.00,Default,,0,0,0,,因此 我需要有一种方法能够 Dialogue: 0,0:37:38.01,0:37:40.86,Default,,0,0,0,,记住有穷状态控制器中弹珠的位置 Dialogue: 0,0:37:41.32,0:37:42.64,Default,,0,0,0,,也就是控制器的状态 Dialogue: 0,0:37:44.22,0:37:46.35,Default,,0,0,0,,并将它存储在栈中 Dialogue: 0,0:37:47.40,0:37:49.10,Default,,0,0,0,,我也需要有一种方法 Dialogue: 0,0:37:49.45,0:37:51.12,Default,,0,0,0,,能够恢复弹珠的状态 Dialogue: 0,0:37:52.14,0:37:54.28,Default,,0,0,0,,因此 我需要有一种将弹珠归位的能力 Dialogue: 0,0:37:54.70,0:37:56.52,Default,,0,0,0,,现在 我们有一个地方用于存储弹珠 Dialogue: 0,0:37:57.87,0:37:59.34,Default,,0,0,0,,它被称作“继续”寄存器 Dialogue: 0,0:38:03.61,0:38:04.52,Default,,0,0,0,,记作CONTINUE Dialogue: 0,0:38:09.16,0:38:10.68,Default,,0,0,0,,下一次调用(GOTO CONTINUE)时 Dialogue: 0,0:38:11.00,0:38:13.05,Default,,0,0,0,,弹珠就会去向这个地方 Dialogue: 0,0:38:14.91,0:38:15.92,Default,,0,0,0,,它就是用来干这个的 Dialogue: 0,0:38:16.14,0:38:18.48,Default,,0,0,0,,因此 它和控制器之间应该有一条通路 Dialogue: 0,0:38:22.91,0:38:27.12,Default,,0,0,0,,我也能够将它存储在栈上 Dialogue: 0,0:38:29.45,0:38:33.10,Default,,0,0,0,,我也能够把它设置成各种常量 Dialogue: 0,0:38:34.01,0:38:35.69,Default,,0,0,0,,某一些常量 Dialogue: 0,0:38:36.86,0:38:38.20,Default,,0,0,0,,这非常容易实现 Dialogue: 0,0:38:38.84,0:38:40.14,Default,,0,0,0,,我们现在这里设一些常量 Dialogue: 0,0:38:40.18,0:38:41.50,Default,,0,0,0,,我们把这个记作AFTER-FACT Dialogue: 0,0:38:47.32,0:38:48.75,Default,,0,0,0,,这个常量 Dialogue: 0,0:38:48.84,0:38:51.50,Default,,0,0,0,,会送入CONTINUE寄存器 Dialogue: 0,0:38:52.59,0:38:54.43,Default,,0,0,0,,另外一个寄存器是FACT-DONE Dialogue: 0,0:39:05.21,0:39:07.82,Default,,0,0,0,,这就是我想要构建的机器 Dialogue: 0,0:39:08.13,0:39:09.48,Default,,0,0,0,,至少是数据通路部分 Dialogue: 0,0:39:09.92,0:39:11.69,Default,,0,0,0,,这里还混合了一些控制器 Dialogue: 0,0:39:11.85,0:39:14.59,Default,,0,0,0,,这是因为我需要记住我当前的位置 Dialogue: 0,0:39:14.70,0:39:16.35,Default,,0,0,0,,并将我恢复到该位置 Dialogue: 0,0:39:17.30,0:39:19.93,Default,,0,0,0,,现在 让我们来编写控制器对应的程序 Dialogue: 0,0:39:20.39,0:39:23.47,Default,,0,0,0,,我就把DEFINE-MACHINE和寄存器列表给省略了 Dialogue: 0,0:39:23.48,0:39:24.89,Default,,0,0,0,,因为它们无关紧要 Dialogue: 0,0:39:25.13,0:39:27.79,Default,,0,0,0,,我就直接写那些跟控制器有关的 Dialogue: 0,0:39:27.82,0:39:29.02,Default,,0,0,0,,指令序列 Dialogue: 0,0:39:31.48,0:39:41.85,Default,,0,0,0,,首先是(ASSIGN CONTINUE DONE) Dialogue: 0,0:39:45.15,0:39:45.82,Default,,0,0,0,,然后是一个循环 Dialogue: 0,0:39:47.34,0:39:56.08,Default,,0,0,0,,先判断 如果1=N 那么就跳转 Dialogue: 0,0:40:00.94,0:40:04.11,Default,,0,0,0,,那么就进入归纳的基本步骤 Dialogue: 0,0:40:06.06,0:40:07.20,Default,,0,0,0,,也就是最简单的情况 Dialogue: 0,0:40:08.05,0:40:08.76,Default,,0,0,0,,否则的话 Dialogue: 0,0:40:08.88,0:40:10.84,Default,,0,0,0,,我就要记住那些 Dialogue: 0,0:40:10.88,0:40:13.84,Default,,0,0,0,,计算子阶乘所必须的信息 Dialogue: 0,0:40:14.67,0:40:16.75,Default,,0,0,0,,我需要来带这里 以便计算子阶乘 Dialogue: 0,0:40:17.57,0:40:19.29,Default,,0,0,0,,所以我需要记住 完成它需要些什么 Dialogue: 0,0:40:19.71,0:40:22.52,Default,,0,0,0,,需要记住我计算完之后需要哪些东西 Dialogue: 0,0:40:24.00,0:40:25.51,Default,,0,0,0,,看到了吗 我要做些糟糕的事儿 Dialogue: 0,0:40:25.72,0:40:27.39,Default,,0,0,0,,我要去修改N的值 Dialogue: 0,0:40:28.57,0:40:30.40,Default,,0,0,0,,但是它又需要记住N的旧值 Dialogue: 0,0:40:32.14,0:40:33.64,Default,,0,0,0,,但是为了计算子阶乘 Dialogue: 0,0:40:33.66,0:40:34.92,Default,,0,0,0,,我又需要修改N的值 Dialogue: 0,0:40:35.60,0:40:37.10,Default,,0,0,0,,因此 我就得记住N的旧值 Dialogue: 0,0:40:38.00,0:40:39.60,Default,,0,0,0,,我也需要记住我的位置 Dialogue: 0,0:40:40.85,0:40:42.32,Default,,0,0,0,,因此 我保存CONTINUE的值 Dialogue: 0,0:40:47.70,0:40:51.29,Default,,0,0,0,,这条指令 就是用来将数据入栈的 Dialogue: 0,0:40:53.12,0:40:55.53,Default,,0,0,0,,将CONTINUE寄存器的值保存起来 Dialogue: 0,0:40:56.51,0:40:58.00,Default,,0,0,0,,在本例中也就是DONE Dialogue: 0,0:40:58.88,0:41:00.25,Default,,0,0,0,,因为稍后我也会修改它 Dialogue: 0,0:41:00.27,0:41:02.78,Default,,0,0,0,,因为我也需要回到AFTER-FACT Dialogue: 0,0:41:03.55,0:41:04.19,Default,,0,0,0,,我们来看看 Dialogue: 0,0:41:05.04,0:41:09.71,Default,,0,0,0,,我们需要存储N 因为稍后会用到 Dialogue: 0,0:41:10.38,0:41:20.54,Default,,0,0,0,,(ASSIGN N (-1+ (FETCH N))) Dialogue: 0,0:41:23.26,0:41:28.97,Default,,0,0,0,,(ASSIGN CONTINUE ... Dialogue: 0,0:41:32.12,0:41:33.42,Default,,0,0,0,,我看一下 -- Dialogue: 0,0:41:34.06,0:41:35.61,Default,,0,0,0,,AFT) Dialogue: 0,0:41:37.69,0:41:38.70,Default,,0,0,0,,这个名字很好 Dialogue: 0,0:41:38.73,0:41:40.65,Default,,0,0,0,,因为它短小精炼 很适合用在这里 Dialogue: 0,0:41:53.36,0:41:54.64,Default,,0,0,0,,现在 来看看我怎么做 Dialogue: 0,0:41:55.33,0:41:57.02,Default,,0,0,0,,我说 如果ANSWER是1的话 Dialogue: 0,0:41:58.72,0:41:59.66,Default,,0,0,0,,那程序就结束了 Dialogue: 0,0:42:00.46,0:42:01.66,Default,,0,0,0,,我只需要取得这个答案 Dialogue: 0,0:42:02.15,0:42:04.88,Default,,0,0,0,,否则我就要保存当前的继续以及N的值 Dialogue: 0,0:42:05.77,0:42:07.32,Default,,0,0,0,,然后让N减1 Dialogue: 0,0:42:07.60,0:42:09.63,Default,,0,0,0,,注意 我先要跳转到某处 Dialogue: 0,0:42:09.64,0:42:11.48,Default,,0,0,0,,然后来到这里 计算另外的阶乘 Dialogue: 0,0:42:13.50,0:42:15.74,Default,,0,0,0,,然而 这之中又有了另外的机器 Dialogue: 0,0:42:16.05,0:42:18.38,Default,,0,0,0,,其中N=1 CONTINUE是其它值 Dialogue: 0,0:42:22.11,0:42:23.21,Default,,0,0,0,,N=N-1 Dialogue: 0,0:42:23.77,0:42:25.28,Default,,0,0,0,,再我完成这个之后 Dialogue: 0,0:42:26.94,0:42:27.76,Default,,0,0,0,,我会来到这里 Dialogue: 0,0:42:28.66,0:42:30.46,Default,,0,0,0,,我会恢复N的旧值 Dialogue: 0,0:42:32.68,0:42:36.56,Default,,0,0,0,,也就是这里SAVE的逆运算 Dialogue: 0,0:42:38.36,0:42:39.88,Default,,0,0,0,,然后恢复CONTINUE Dialogue: 0,0:42:49.66,0:42:52.57,Default,,0,0,0,,然后我又会来到这里 Dialogue: 0,0:42:54.32,0:43:00.86,Default,,0,0,0,,(ASSIGN VAL Dialogue: 0,0:43:01.16,0:43:08.13,Default,,0,0,0,,(* (FETCH N) (FETCH VAL))) Dialogue: 0,0:43:13.44,0:43:18.30,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:43:19.79,0:43:21.44,Default,,0,0,0,,这样操作就完成了 Dialogue: 0,0:43:21.44,0:43:25.68,Default,,0,0,0,,子阶乘的结果就存储在了VAL中 Dialogue: 0,0:43:26.57,0:43:27.37,Default,,0,0,0,,这个时候 Dialogue: 0,0:43:27.66,0:43:28.75,Default,,0,0,0,,我就要返回到 Dialogue: 0,0:43:29.28,0:43:31.61,Default,,0,0,0,,CONTINUE所指向的地方 Dialogue: 0,0:43:33.64,0:43:35.77,Default,,0,0,0,,也就是(GOTO (FETCH CONTINUE)) Dialogue: 0,0:43:45.87,0:43:47.40,Default,,0,0,0,,最后就是基本情况的那步 Dialogue: 0,0:43:49.31,0:43:50.51,Default,,0,0,0,,也就是一个立即值 Dialogue: 0,0:43:50.68,0:43:56.88,Default,,0,0,0,,(ASSIGN VAL (FETCH N)) Dialogue: 0,0:44:01.36,0:44:02.75,Default,,0,0,0,,(GOTO (FETCH CONTINUE)) Dialogue: 0,0:44:12.67,0:44:13.55,Default,,0,0,0,,这样我就完成了 Dialogue: 0,0:44:18.64,0:44:21.21,Default,,0,0,0,,现在 我们用一个非常简单的例子来运行一下 Dialogue: 0,0:44:22.51,0:44:23.53,Default,,0,0,0,,因为这样我们就将看到 Dialogue: 0,0:44:23.66,0:44:26.52,Default,,0,0,0,,栈是如何帮助我们完成计算的 Dialogue: 0,0:44:26.89,0:44:28.22,Default,,0,0,0,,这是计算的静态描述 Dialogue: 0,0:44:28.22,0:44:29.80,Default,,0,0,0,,我们需要动态地观察它 Dialogue: 0,0:44:31.34,0:44:32.09,Default,,0,0,0,,因此 让我们来看看 Dialogue: 0,0:44:32.30,0:44:34.56,Default,,0,0,0,,首先我们要把CONTINUE设置为DONE Dialogue: 0,0:44:36.73,0:44:38.09,Default,,0,0,0,,这是我通过按下这个钮来实现的 Dialogue: 0,0:44:38.30,0:44:39.60,Default,,0,0,0,,我们还是把它记作DONE吧 Dialogue: 0,0:44:46.22,0:44:47.03,Default,,0,0,0,,我按下这个按钮 Dialogue: 0,0:44:47.03,0:44:48.11,Default,,0,0,0,,DONE就进到了这里 Dialogue: 0,0:44:48.95,0:44:53.71,Default,,0,0,0,,现在 我还要为这些东西设置初始值 Dialogue: 0,0:44:53.85,0:44:58.08,Default,,0,0,0,,让我们考虑3的阶乘 Dialogue: 0,0:44:58.38,0:44:59.24,Default,,0,0,0,,这个例子非常简单 Dialogue: 0,0:45:00.54,0:45:04.04,Default,,0,0,0,,我们的栈从这里开始增长 Dialogue: 0,0:45:05.90,0:45:07.76,Default,,0,0,0,,栈有它们自己的内部状态 Dialogue: 0,0:45:07.79,0:45:09.05,Default,,0,0,0,,用来标识栈顶位置 Dialogue: 0,0:45:09.80,0:45:11.64,Default,,0,0,0,,也就是下一个可写位置 Dialogue: 0,0:45:12.77,0:45:14.59,Default,,0,0,0,,现在我们问 N=1么? Dialogue: 0,0:45:14.76,0:45:15.71,Default,,0,0,0,,当然不等于 Dialogue: 0,0:45:16.11,0:45:18.56,Default,,0,0,0,,因此现在我要保存CONTINUE Dialogue: 0,0:45:19.15,0:45:20.65,Default,,0,0,0,,现在 DONE就来到了这里 Dialogue: 0,0:45:22.08,0:45:23.55,Default,,0,0,0,,然后 这个指针移动到了这里 Dialogue: 0,0:45:24.88,0:45:26.14,Default,,0,0,0,,下次我要把数据写到这里 Dialogue: 0,0:45:26.66,0:45:28.78,Default,,0,0,0,,保存N的值--也就是3 Dialogue: 0,0:45:29.95,0:45:30.32,Default,,0,0,0,,对吧? Dialogue: 0,0:45:30.67,0:45:33.61,Default,,0,0,0,,N←N-1 Dialogue: 0,0:45:33.96,0:45:35.37,Default,,0,0,0,,也就是说 我得按下这个钮 Dialogue: 0,0:45:35.94,0:45:37.32,Default,,0,0,0,,这就变成了2 Dialogue: 0,0:45:38.73,0:45:42.28,Default,,0,0,0,,COUNTINUE←AFT Dialogue: 0,0:45:42.58,0:45:43.61,Default,,0,0,0,,因此我要按下这个钮 Dialogue: 0,0:45:43.61,0:45:44.54,Default,,0,0,0,,AFT就进入了这里 Dialogue: 0,0:45:49.14,0:45:53.93,Default,,0,0,0,,然后 跳转到LOOP 我们就来到了这里 Dialogue: 0,0:45:54.83,0:45:57.08,Default,,0,0,0,,N=1么?当然不 Dialogue: 0,0:45:57.78,0:45:59.23,Default,,0,0,0,,因此我又要保存CONTINUE Dialogue: 0,0:45:59.49,0:46:00.27,Default,,0,0,0,,CONTINUE的值是什么呢? Dialogue: 0,0:46:00.60,0:46:01.53,Default,,0,0,0,,目前是AFT Dialogue: 0,0:46:01.53,0:46:02.32,Default,,0,0,0,,按下这个按钮 Dialogue: 0,0:46:02.78,0:46:03.95,Default,,0,0,0,,这个指针移动到了这里 Dialogue: 0,0:46:08.49,0:46:09.74,Default,,0,0,0,,我还要保存N Dialogue: 0,0:46:10.51,0:46:12.12,Default,,0,0,0,,N在那里 它的值是2 Dialogue: 0,0:46:12.28,0:46:13.37,Default,,0,0,0,,按下这个按钮 Dialogue: 0,0:46:13.85,0:46:15.24,Default,,0,0,0,,2就进入了这里 Dialogue: 0,0:46:16.05,0:46:17.64,Default,,0,0,0,,然后这个指针移动到了这里 Dialogue: 0,0:46:20.06,0:46:22.60,Default,,0,0,0,,保存N之后 又赋N←N-1 Dialogue: 0,0:46:24.60,0:46:25.46,Default,,0,0,0,,它就变成了1 Dialogue: 0,0:46:29.24,0:46:30.54,Default,,0,0,0,,CONTINUE←AFT Dialogue: 0,0:46:31.37,0:46:34.48,Default,,0,0,0,,AFT又进入了这里 Dialogue: 0,0:46:34.96,0:46:35.64,Default,,0,0,0,,然后又跳转到LOOP Dialogue: 0,0:46:36.52,0:46:37.74,Default,,0,0,0,,N等于1么? Dialogue: 0,0:46:37.93,0:46:39.52,Default,,0,0,0,,是的 那么答案就是1 Dialogue: 0,0:46:41.04,0:46:43.26,Default,,0,0,0,,跳转到BASE那一步 Dialogue: 0,0:46:44.16,0:46:45.77,Default,,0,0,0,,(ASSIGN VAL (FETCH N)) Dialogue: 0,0:46:46.56,0:46:50.72,Default,,0,0,0,,按下这个 1就进入到了这里 Dialogue: 0,0:46:51.10,0:46:52.20,Default,,0,0,0,,(GOTO (FETCH CONTINUE)) Dialogue: 0,0:46:52.20,0:46:53.53,Default,,0,0,0,,来看下CONTINUE寄存器 Dialogue: 0,0:46:53.68,0:46:56.06,Default,,0,0,0,,基本上来说 我按下这里的按钮 进入到控制器 Dialogue: 0,0:46:56.67,0:46:58.28,Default,,0,0,0,,CONTINUE寄存器就变成了AFT Dialogue: 0,0:46:58.32,0:47:00.25,Default,,0,0,0,,这样一下子 程序就运行到了这里 Dialogue: 0,0:47:02.64,0:47:05.63,Default,,0,0,0,,现在 我就需要恢复外部的阶乘了 Dialogue: 0,0:47:06.65,0:47:07.55,Default,,0,0,0,,因此我们来到这里 Dialogue: 0,0:47:07.55,0:47:09.48,Default,,0,0,0,,我们先要恢复N Dialogue: 0,0:47:10.32,0:47:13.04,Default,,0,0,0,,这就意味着 我们要使用这里的内容 Dialogue: 0,0:47:13.94,0:47:18.17,Default,,0,0,0,,按下这个按钮 2就会来到这里 Dialogue: 0,0:47:18.56,0:47:20.04,Default,,0,0,0,,然后指针会向上移动 Dialogue: 0,0:47:21.98,0:47:24.49,Default,,0,0,0,,恢复CONTINUE寄存器也非常简单 Dialogue: 0,0:47:24.81,0:47:26.49,Default,,0,0,0,,来按下这个按钮 Dialogue: 0,0:47:27.02,0:47:28.92,Default,,0,0,0,,然后 AFT又一次进入到这里 Dialogue: 0,0:47:31.28,0:47:32.64,Default,,0,0,0,,同时 这个指针也要上移 Dialogue: 0,0:47:32.64,0:47:35.19,Default,,0,0,0,,这样就避开了栈上的其它东西 Dialogue: 0,0:47:42.24,0:47:43.47,Default,,0,0,0,,然后我来到这里 Dialogue: 0,0:47:43.87,0:47:47.15,Default,,0,0,0,,也就是(ASSIGN VAL (* N VAL)) Dialogue: 0,0:47:47.85,0:47:50.57,Default,,0,0,0,,然后我按下这个按钮 Dialogue: 0,0:47:50.97,0:47:52.91,Default,,0,0,0,,2乘以1等于2 Dialogue: 0,0:47:54.01,0:47:54.75,Default,,0,0,0,,我写到这里 Dialogue: 0,0:47:55.76,0:47:57.20,Default,,0,0,0,,然后是(GOTO (FETCH CONTINUE)) Dialogue: 0,0:47:57.54,0:47:59.85,Default,,0,0,0,,CONTINUE现在是AFT 我跳转到AFT Dialogue: 0,0:48:01.15,0:48:03.88,Default,,0,0,0,,AFT首先要恢复N Dialogue: 0,0:48:04.36,0:48:05.72,Default,,0,0,0,,恢复N指的是 Dialogue: 0,0:48:05.87,0:48:08.44,Default,,0,0,0,,我把这里的值 也就是3 Dialogue: 0,0:48:09.24,0:48:10.33,Default,,0,0,0,,按下这里的按钮 Dialogue: 0,0:48:10.60,0:48:15.50,Default,,0,0,0,,然后把它放到这里 N Dialogue: 0,0:48:16.25,0:48:17.34,Default,,0,0,0,,然后 我们按下这个钮 Dialogue: 0,0:48:18.01,0:48:19.90,Default,,0,0,0,,接下来我就要恢复CONTINUE Dialogue: 0,0:48:20.20,0:48:22.20,Default,,0,0,0,,CONTINUE寄存器现在成为了DONE Dialogue: 0,0:48:22.83,0:48:26.78,Default,,0,0,0,,当我按下这个钮后 指针就移动到了这里 Dialogue: 0,0:48:27.13,0:48:29.72,Default,,0,0,0,,DONE可能从此之后不在这里了 Dialogue: 0,0:48:29.72,0:48:31.55,Default,,0,0,0,,对此我并不感兴趣 但它现在一定在这里 Dialogue: 0,0:48:35.80,0:48:38.12,Default,,0,0,0,,下一步 我将要把VAL赋值为 Dialogue: 0,0:48:38.43,0:48:40.76,Default,,0,0,0,,N乘以VAL的值 Dialogue: 0,0:48:41.44,0:48:44.30,Default,,0,0,0,,按下这里的按钮就可以实现 Dialogue: 0,0:48:44.30,0:48:45.77,Default,,0,0,0,,2乘以3等于6 Dialogue: 0,0:48:46.52,0:48:47.87,Default,,0,0,0,,所以这里我就得到了6 Dialogue: 0,0:48:50.97,0:48:53.40,Default,,0,0,0,,下一步是(GOTO (FETCH CONTINUE)) Dialogue: 0,0:48:53.48,0:48:54.83,Default,,0,0,0,,哦 跳转到DONE 这样我就完成了 Dialogue: 0,0:48:55.02,0:48:56.09,Default,,0,0,0,,最后的答案是6 Dialogue: 0,0:48:56.60,0:48:57.82,Default,,0,0,0,,你们可以在VAL寄存器中看到 Dialogue: 0,0:48:58.95,0:48:59.82,Default,,0,0,0,,事实上 Dialogue: 0,0:49:00.91,0:49:03.34,Default,,0,0,0,,栈又回到了它初始的状态 Dialogue: 0,0:49:08.20,0:49:10.70,Default,,0,0,0,,在使用像栈这样的东西中 有一些原则 Dialogue: 0,0:49:11.20,0:49:12.27,Default,,0,0,0,,我们需要注意 Dialogue: 0,0:49:13.62,0:49:15.52,Default,,0,0,0,,我们会在下一小节中介绍 Dialogue: 0,0:49:16.26,0:49:18.46,Default,,0,0,0,,但首先 对于这一小节所讲的内容 Dialogue: 0,0:49:28.56,0:49:29.64,Default,,0,0,0,,有什么问题么? Dialogue: 0,0:49:30.17,0:49:30.63,Default,,0,0,0,,Ron 请讲 Dialogue: 0,0:49:30.63,0:49:33.37,Default,,0,0,0,,学生:当你越过了栈的顶端会怎样-- Dialogue: 0,0:49:33.39,0:49:34.62,Default,,0,0,0,,教授:你所谓的“越过”是指什么? Dialogue: 0,0:49:35.03,0:49:37.50,Default,,0,0,0,,学生:如果我们的N是一个很大的数 Dialogue: 0,0:49:37.52,0:49:38.72,Default,,0,0,0,,就需要更多的内存 对吧? Dialogue: 0,0:49:38.86,0:49:39.44,Default,,0,0,0,,教授:是的 Dialogue: 0,0:49:39.44,0:49:41.12,Default,,0,0,0,,这样 我就需要一个足够大的栈 Dialogue: 0,0:49:41.53,0:49:43.20,Default,,0,0,0,,你想问 如果破坏了无穷存储的假象会发生什么? Dialogue: 0,0:49:43.84,0:49:44.12,Default,,0,0,0,,学生:是的 Dialogue: 0,0:49:44.55,0:49:46.73,Default,,0,0,0,,教授:那么 这些魔法就不再起效了 Dialogue: 0,0:49:47.96,0:49:51.00,Default,,0,0,0,,真相就是 任何机器都是有穷的 Dialogue: 0,0:49:51.64,0:49:53.72,Default,,0,0,0,,而对于像这样的过程 Dialogue: 0,0:49:54.17,0:49:58.86,Default,,0,0,0,,我只能进行有限数量的子阶乘计算 Dialogue: 0,0:49:59.95,0:50:02.48,Default,,0,0,0,,想一想 我们之前讲解的Y组合子 Dialogue: 0,0:50:02.80,0:50:06.22,Default,,0,0,0,,我们指出 存在一系列的指数过程 Dialogue: 0,0:50:06.25,0:50:08.09,Default,,0,0,0,,其中每一个都要比前一个更精准 Dialogue: 0,0:50:08.72,0:50:11.60,Default,,0,0,0,,现在 我们看到了如何实现这个数学理念 Dialogue: 0,0:50:13.09,0:50:14.19,Default,,0,0,0,,这个取极限的过程 Dialogue: 0,0:50:14.35,0:50:16.33,Default,,0,0,0,,只有当你取到极限时才足够精准 Dialogue: 0,0:50:17.99,0:50:19.42,Default,,0,0,0,,如果你仔细想想 我这里用了什么 Dialogue: 0,0:50:19.42,0:50:22.65,Default,,0,0,0,,对于这个过程的每一次递归 Dialogue: 0,0:50:23.04,0:50:27.07,Default,,0,0,0,,我用了大概两块内存 Dialogue: 0,0:50:29.10,0:50:31.71,Default,,0,0,0,,如果我们尝试计算10000的阶乘 Dialogue: 0,0:50:31.72,0:50:32.81,Default,,0,0,0,,这并不会花掉很多内存 Dialogue: 0,0:50:33.18,0:50:34.68,Default,,0,0,0,,虽然这是一个很大的数 Dialogue: 0,0:50:35.95,0:50:38.41,Default,,0,0,0,,因此 实际的问题就是值不值得 Dialogue: 0,0:50:39.18,0:50:42.19,Default,,0,0,0,,但这并不是这种实现的局限 Dialogue: 0,0:50:42.22,0:50:43.53,Default,,0,0,0,,因为内存非常低廉 Dialogue: 0,0:50:44.16,0:50:45.34,Default,,0,0,0,,但人力资源却相当昂贵 Dialogue: 0,0:50:48.13,0:50:50.22,Default,,0,0,0,,好吧 我们先休息一下 谢谢大家 Dialogue: 0,0:50:50.78,0:51:07.60,Default,,0,0,0,,[音乐] Dialogue: 0,0:51:07.60,0:51:12.19,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:51:39.93,0:51:43.69,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:51:43.71,0:51:47.93,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:51:47.93,0:51:53.08,Declare,,0,0,0,,{\an2\fad(500,500)}寄存机器 Dialogue: 0,0:51:56.11,0:51:57.04,Default,,0,0,0,,教授:我们讲解了 Dialogue: 0,0:51:58.70,0:52:03.37,Default,,0,0,0,,如果进行简单的迭代计算 Dialogue: 0,0:52:03.69,0:52:05.31,Default,,0,0,0,,以及简单的递归计算 Dialogue: 0,0:52:05.64,0:52:08.68,Default,,0,0,0,,我只想通过向你们展示一些针对特定应用的 Dialogue: 0,0:52:09.63,0:52:11.12,Default,,0,0,0,,更加复杂的设计 Dialogue: 0,0:52:11.21,0:52:13.58,Default,,0,0,0,,来总结简单机器的设计 Dialogue: 0,0:52:13.96,0:52:17.13,Default,,0,0,0,,也就是同时递归地调用两个斐波那契函数 Dialogue: 0,0:52:17.23,0:52:19.88,Default,,0,0,0,,因为它会向我们表明 并且我们会理解 Dialogue: 0,0:52:20.04,0:52:22.68,Default,,0,0,0,,一些关于栈正常工作 Dialogue: 0,0:52:22.76,0:52:25.04,Default,,0,0,0,,所需要遵守的约定 Dialogue: 0,0:52:26.40,0:52:27.11,Default,,0,0,0,,现在 让我们来看看 Dialogue: 0,0:52:27.11,0:52:28.27,Default,,0,0,0,,先让我在黑板上写下 Dialogue: 0,0:52:28.30,0:52:29.71,Default,,0,0,0,,将要翻译的程序 Dialogue: 0,0:52:34.15,0:52:36.52,Default,,0,0,0,,这是一个斐波那契过程 Dialogue: 0,0:52:39.23,0:52:41.58,Default,,0,0,0,,它非常的简单 Dialogue: 0,0:52:44.60,0:52:48.56,Default,,0,0,0,,如果N小于2 那么结果就是N Dialogue: 0,0:52:49.26,0:52:55.34,Default,,0,0,0,,否则就是(FIB (- N 1))加上 Dialogue: 0,0:52:58.44,0:52:59.85,Default,,0,0,0,,(FIB (- N 2)) Dialogue: 0,0:53:07.05,0:53:09.29,Default,,0,0,0,,这就是我的计划 Dialogue: 0,0:53:09.29,0:53:12.56,Default,,0,0,0,,现在 我们要来写下这台机器的控制器 Dialogue: 0,0:53:13.07,0:53:15.53,Default,,0,0,0,,首先 我们假设有一个寄存器N Dialogue: 0,0:53:15.56,0:53:19.15,Default,,0,0,0,,里面存放的是斐波那契函数的自变量 Dialogue: 0,0:53:19.82,0:53:21.80,Default,,0,0,0,,而计算结果会存放在VAL寄存器中 Dialogue: 0,0:53:22.17,0:53:24.97,Default,,0,0,0,,CONTINUE寄存器会和控制器相连 Dialogue: 0,0:53:26.11,0:53:26.81,Default,,0,0,0,,就跟之前一样 Dialogue: 0,0:53:26.96,0:53:29.21,Default,,0,0,0,,但我不会再去画数据通路了 Dialogue: 0,0:53:31.53,0:53:34.00,Default,,0,0,0,,因为它和之前的那个差不多 Dialogue: 0,0:53:34.36,0:53:37.84,Default,,0,0,0,,当然 关于计算的最神奇的事情之一 Dialogue: 0,0:53:38.75,0:53:39.88,Default,,0,0,0,,就是一段时间后 Dialogue: 0,0:53:40.08,0:53:41.93,Default,,0,0,0,,你构建了一个又一个的小功能 Dialogue: 0,0:53:41.95,0:53:43.32,Default,,0,0,0,,你就一下子拥有了需要的一切 Dialogue: 0,0:53:44.75,0:53:47.60,Default,,0,0,0,,这种效率是非常了不起的 Dialogue: 0,0:53:48.17,0:53:50.84,Default,,0,0,0,,构造制作一台通用计算机不需要太多的东西 Dialogue: 0,0:53:51.81,0:53:54.68,Default,,0,0,0,,总之 我们来看看斐波那契机器的控制器 Dialogue: 0,0:53:55.06,0:53:57.07,Default,,0,0,0,,我首先要做的是 Dialogue: 0,0:53:57.32,0:54:02.52,Default,,0,0,0,,通过为CONTINUE寄存器赋值 Dialogue: 0,0:54:07.13,0:54:10.28,Default,,0,0,0,,赋FIB-DONE来启动计算 Dialogue: 0,0:54:14.14,0:54:15.53,Default,,0,0,0,,这就意味着在这里 Dialogue: 0,0:54:15.55,0:54:18.48,Default,,0,0,0,,我需要有一个标签 FIB-DONE Dialogue: 0,0:54:19.71,0:54:21.10,Default,,0,0,0,,当我来到这个地方后 Dialogue: 0,0:54:21.23,0:54:22.44,Default,,0,0,0,,机器就停止了 Dialogue: 0,0:54:24.00,0:54:24.86,Default,,0,0,0,,这就是这个标签的作用 Dialogue: 0,0:54:25.92,0:54:26.89,Default,,0,0,0,,然后我要创建一个循环 Dialogue: 0,0:54:31.11,0:54:34.25,Default,,0,0,0,,我要来到这里来启动FIB的计算 Dialogue: 0,0:54:35.47,0:54:36.86,Default,,0,0,0,,无论这时 N等于多少 Dialogue: 0,0:54:37.39,0:54:38.99,Default,,0,0,0,,斐波那契函数都会被计算 Dialogue: 0,0:54:39.13,0:54:42.01,Default,,0,0,0,,然后会返回到由CONTINUE寄存器指向的地方 Dialogue: 0,0:54:44.80,0:54:48.40,Default,,0,0,0,,因此你们将在这里看到 Dialogue: 0,0:54:48.44,0:54:50.48,Default,,0,0,0,,我想要在做一个约定 Dialogue: 0,0:54:50.97,0:54:54.25,Default,,0,0,0,,我用注释的形式来说明这个约定 Dialogue: 0,0:54:54.57,0:55:00.99,Default,,0,0,0,,也就是N中存储的是参数 Dialogue: 0,0:55:02.10,0:55:09.82,Default,,0,0,0,,而CONTINUE存储的是接收者 Dialogue: 0,0:55:13.36,0:55:14.29,Default,,0,0,0,,这个约定就是这样的 Dialogue: 0,0:55:15.71,0:55:18.96,Default,,0,0,0,,因此每当我来到这里 Dialogue: 0,0:55:19.24,0:55:21.04,Default,,0,0,0,,我希望这个约定是成立的 Dialogue: 0,0:55:21.52,0:55:23.32,Default,,0,0,0,,这些计算斐波那契函数所需要的参数 Dialogue: 0,0:55:24.82,0:55:26.83,Default,,0,0,0,,接下来我想做的是分支 Dialogue: 0,0:55:30.22,0:55:32.22,Default,,0,0,0,,如果N小于2 Dialogue: 0,0:55:35.07,0:55:37.44,Default,,0,0,0,,随便说一下 我使用的语法看起来像Lisp Dialogue: 0,0:55:38.73,0:55:39.63,Default,,0,0,0,,但它并不是Lisp Dialogue: 0,0:55:41.31,0:55:42.38,Default,,0,0,0,,它们运行不起来 Dialogue: 0,0:55:42.75,0:55:45.47,Default,,0,0,0,,我在这里写的并不是一个简单的Lisp程序 Dialogue: 0,0:55:46.12,0:55:49.31,Default,,0,0,0,,这是另一门语言的表示形式 Dialogue: 0,0:55:49.71,0:55:52.25,Default,,0,0,0,,我之所以使用这种满是括号的语法 Dialogue: 0,0:55:52.40,0:55:54.70,Default,,0,0,0,,是因为我刚好使用Lisp系统 Dialogue: 0,0:55:55.32,0:55:57.34,Default,,0,0,0,,来为这门语言编写解释器 Dialogue: 0,0:55:57.82,0:55:59.18,Default,,0,0,0,,这就使得我们能够模拟 Dialogue: 0,0:55:59.29,0:56:00.91,Default,,0,0,0,,我想要构建的机器 Dialogue: 0,0:56:03.38,0:56:06.24,Default,,0,0,0,,我不想让你们感到困惑 认为这是Lisp代码 Dialogue: 0,0:56:06.94,0:56:08.60,Default,,0,0,0,,只是我用了很多Lisp组件 Dialogue: 0,0:56:09.51,0:56:10.84,Default,,0,0,0,,我在Lisp中嵌入了一门语言 Dialogue: 0,0:56:11.02,0:56:12.44,Default,,0,0,0,,把Lisp当作组件 Dialogue: 0,0:56:12.72,0:56:15.12,Default,,0,0,0,,这样就能让我的模拟工作变得简单 Dialogue: 0,0:56:16.62,0:56:18.56,Default,,0,0,0,,我从Lisp中继承了这些属性 Dialogue: 0,0:56:19.10,0:56:21.53,Default,,0,0,0,,(FETCH N) 2) Dialogue: 0,0:56:21.77,0:56:23.72,Default,,0,0,0,,成立的话 我想要跳转到IMMEDIATE-ANSWER这个地方 Dialogue: 0,0:56:26.20,0:56:27.29,Default,,0,0,0,,这是基本步骤 Dialogue: 0,0:56:33.15,0:56:34.35,Default,,0,0,0,,它对应在这里 Dialogue: 0,0:56:35.92,0:56:36.89,Default,,0,0,0,,也就是在FIB-DONE的上方 Dialogue: 0,0:56:37.75,0:56:38.64,Default,,0,0,0,,我们稍后就会看到 Dialogue: 0,0:56:39.42,0:56:40.70,Default,,0,0,0,,现在 对于一般情况来说 Dialogue: 0,0:56:40.72,0:56:42.44,Default,,0,0,0,,也就是我现在要写的 Dialogue: 0,0:56:43.13,0:56:44.19,Default,,0,0,0,,是这样的 Dialogue: 0,0:56:44.91,0:56:48.20,Default,,0,0,0,,首先呢 我需要调用斐波那契函数两次 Dialogue: 0,0:56:49.42,0:56:52.54,Default,,0,0,0,,在每一次中 -- 至少在其中一次 Dialogue: 0,0:56:52.78,0:56:53.95,Default,,0,0,0,,我得需要知道该怎么做 Dialogue: 0,0:56:53.96,0:56:55.36,Default,,0,0,0,,才能回过头来进行另外一个计算 Dialogue: 0,0:56:56.31,0:56:58.36,Default,,0,0,0,,我需要记住 Dialogue: 0,0:56:59.20,0:57:01.23,Default,,0,0,0,,我计算完第一个FIB了么? Dialogue: 0,0:57:01.26,0:57:02.54,Default,,0,0,0,,或者第二个也计算完了? Dialogue: 0,0:57:04.50,0:57:07.04,Default,,0,0,0,,我是该返回到计算第二个FIB的地方 Dialogue: 0,0:57:07.07,0:57:09.08,Default,,0,0,0,,还是回到执行ADD的地方 Dialogue: 0,0:57:10.12,0:57:12.11,Default,,0,0,0,,无论哪种情况 我都需要-- Dialogue: 0,0:57:12.14,0:57:14.46,Default,,0,0,0,,在第一个计算第一个FIB时 Dialogue: 0,0:57:14.51,0:57:16.98,Default,,0,0,0,,我需要保存N的值 来计算第二个FIB Dialogue: 0,0:57:19.84,0:57:21.58,Default,,0,0,0,,因此我要把这些东西保存起来 Dialogue: 0,0:57:23.36,0:57:24.89,Default,,0,0,0,,首先要保存CONTINUE Dialogue: 0,0:57:26.19,0:57:27.32,Default,,0,0,0,,也就是答案的接收者 Dialogue: 0,0:57:31.32,0:57:32.46,Default,,0,0,0,,我之所以要这么做 Dialogue: 0,0:57:32.48,0:57:34.20,Default,,0,0,0,,是因为我现在要把CONTINUE赋值为 Dialogue: 0,0:57:40.11,0:57:44.32,Default,,0,0,0,,我待会儿想要返回的地方 Dialogue: 0,0:57:46.83,0:57:50.27,Default,,0,0,0,,我们把它叫做AFTER-FIB-N-1 Dialogue: 0,0:57:51.04,0:57:53.76,Default,,0,0,0,,这个长名字 非常具有Lisp的命名特点 Dialogue: 0,0:57:57.36,0:58:00.22,Default,,0,0,0,,这是因为我先要计算第一个(FIB (- N 1)) Dialogue: 0,0:58:00.84,0:58:01.72,Default,,0,0,0,,计算完成之后 Dialogue: 0,0:58:01.72,0:58:03.29,Default,,0,0,0,,我想要回过头来做些其它事 Dialogue: 0,0:58:03.96,0:58:06.52,Default,,0,0,0,,而AFTER-FIB-N-1这个地方 Dialogue: 0,0:58:07.55,0:58:09.48,Default,,0,0,0,,就是我计算完第一个FIB后应该返回的地方 Dialogue: 0,0:58:11.52,0:58:13.13,Default,,0,0,0,,接下来我要保存N Dialogue: 0,0:58:14.41,0:58:17.26,Default,,0,0,0,,因为我稍后需要用到它 Dialogue: 0,0:58:19.13,0:58:20.54,Default,,0,0,0,,在这里 我就已经 Dialogue: 0,0:58:20.67,0:58:22.84,Default,,0,0,0,,准备好计算(FIB (- N 1))了 Dialogue: 0,0:58:23.02,0:58:33.95,Default,,0,0,0,,(ASSIGN N (- (FETCH N) 1)) Dialogue: 0,0:58:38.11,0:58:40.27,Default,,0,0,0,,现在 该跳转到FIB-LOOP了 Dialogue: 0,0:58:47.18,0:58:49.87,Default,,0,0,0,,我满足我立下的约定么? Dialogue: 0,0:58:50.40,0:58:51.50,Default,,0,0,0,,答案是是的 Dialogue: 0,0:58:51.77,0:58:55.12,Default,,0,0,0,,N现在存储的是N-1 这是我需要的 Dialogue: 0,0:58:56.43,0:59:00.09,Default,,0,0,0,,而CONTINUE包含的是计算完成后 返回的目的地 Dialogue: 0,0:59:01.28,0:59:03.07,Default,,0,0,0,,也就是计算(FIB (- N 1))完成之后 Dialogue: 0,0:59:04.10,0:59:05.44,Default,,0,0,0,,因此我满足了这些约定 Dialogue: 0,0:59:05.44,0:59:09.02,Default,,0,0,0,,因此 我就可以在这里写下一个标签 Dialogue: 0,0:59:11.47,0:59:17.56,Default,,0,0,0,,AFTER-FIB-N-1 Dialogue: 0,0:59:20.49,0:59:21.63,Default,,0,0,0,,在这里 我又该做些什么呢? Dialogue: 0,0:59:22.69,0:59:23.61,Default,,0,0,0,,在这里 Dialogue: 0,0:59:23.95,0:59:26.75,Default,,0,0,0,,我已经准备好去计算(FIB (- N 2))了 Dialogue: 0,0:59:29.27,0:59:30.72,Default,,0,0,0,,但是为了计算(FIB (- N 2)) Dialogue: 0,0:59:30.75,0:59:31.63,Default,,0,0,0,,首先 我不知道 Dialogue: 0,0:59:31.78,0:59:33.40,Default,,0,0,0,,这里 我已经改变了N Dialogue: 0,0:59:33.81,0:59:35.47,Default,,0,0,0,,或者在这个时候 我的N总是不断地 Dialogue: 0,0:59:37.85,0:59:38.80,Default,,0,0,0,,向1或者0递减 Dialogue: 0,0:59:39.78,0:59:42.51,Default,,0,0,0,,所以我不知道N寄存器中存储的到底是什么 Dialogue: 0,0:59:43.03,0:59:44.75,Default,,0,0,0,,我想要保存在栈中的N的值 Dialogue: 0,0:59:44.80,0:59:46.00,Default,,0,0,0,,也就是我在这里保存的值 Dialogue: 0,0:59:46.17,0:59:47.88,Default,,0,0,0,,这样我就可以在这里恢复它 Dialogue: 0,0:59:49.52,0:59:51.02,Default,,0,0,0,,我在这里存储的N Dialogue: 0,0:59:51.15,0:59:54.49,Default,,0,0,0,,是这个时间点N的值 Dialogue: 0,0:59:54.89,0:59:57.37,Default,,0,0,0,,因此计算完(FIB (- N 1))之后我可以恢复它 Dialogue: 0,0:59:57.53,0:59:59.36,Default,,0,0,0,,这样的话 我就可以计算(- N 2) Dialogue: 0,0:59:59.39,1:00:00.86,Default,,0,0,0,,然后就可以计算(FIB (- N 2))的值 Dialogue: 0,1:00:01.81,1:00:02.75,Default,,0,0,0,,现在让我们来恢复它 Dialogue: 0,1:00:08.83,1:00:09.77,Default,,0,0,0,,(RESTORE N) Dialogue: 0,1:00:11.13,1:00:15.98,Default,,0,0,0,,现在我要做一件很教条的事 Dialogue: 0,1:00:16.00,1:00:17.40,Default,,0,0,0,,我们会尽快将其删除 Dialogue: 0,1:00:18.52,1:00:20.48,Default,,0,0,0,,如果你们愿意的话 Dialogue: 0,1:00:20.59,1:00:23.44,Default,,0,0,0,,我将要结束子过程调用 Dialogue: 0,1:00:24.80,1:00:25.95,Default,,0,0,0,,接下来我会说 Dialogue: 0,1:00:26.06,1:00:27.90,Default,,0,0,0,,因为我保存了CONTINUE Dialogue: 0,1:00:28.48,1:00:30.43,Default,,0,0,0,,现在就要去恢复它 Dialogue: 0,1:00:31.60,1:00:32.60,Default,,0,0,0,,但实际上 我并不需要这么做 Dialogue: 0,1:00:32.64,1:00:33.55,Default,,0,0,0,,因为我并不需要用到它 Dialogue: 0,1:00:34.61,1:00:35.72,Default,,0,0,0,,我们稍后会修正它 Dialogue: 0,1:00:36.26,1:00:37.95,Default,,0,0,0,,现在我们来恢复CONTINUE Dialogue: 0,1:00:46.04,1:00:48.02,Default,,0,0,0,,通常来说 我都会这么做 Dialogue: 0,1:00:48.02,1:00:49.23,Default,,0,0,0,,我们将要看到 Dialogue: 0,1:00:49.31,1:00:52.14,Default,,0,0,0,,编译器领域中的“窥孔优化” Dialogue: 0,1:00:52.27,1:00:53.72,Default,,0,0,0,,来帮我们消除这个不必要的步骤 Dialogue: 0,1:00:55.42,1:00:57.10,Default,,0,0,0,,因此 我即将要做的就是 Dialogue: 0,1:00:58.46,1:01:02.28,Default,,0,0,0,,准备好计算(FIB (- N 2)) Dialogue: 0,1:01:02.77,1:01:04.49,Default,,0,0,0,,但是我不再需要保存N了 Dialogue: 0,1:01:05.05,1:01:06.72,Default,,0,0,0,,原因就是 Dialogue: 0,1:01:06.80,1:01:09.34,Default,,0,0,0,,计算完(FIB (- N 2))之后 我就不需要N了 Dialogue: 0,1:01:09.36,1:01:10.72,Default,,0,0,0,,因为 我接下来要做的就是ADD Dialogue: 0,1:01:13.54,1:01:15.85,Default,,0,0,0,,因此 我会这么来设置N Dialogue: 0,1:01:16.60,1:01:28.99,Default,,0,0,0,,(ASSIGN N (- (FETCH N) 2)) Dialogue: 0,1:01:31.85,1:01:34.01,Default,,0,0,0,,现在我需要结束 Dialogue: 0,1:01:34.27,1:01:36.73,Default,,0,0,0,,调用(FIB (- N 2))的设置过程了 Dialogue: 0,1:01:36.95,1:01:38.33,Default,,0,0,0,,我需要保存CONTINUE Dialogue: 0,1:01:44.22,1:01:49.02,Default,,0,0,0,,然后把CONTINUE赋值为 Dialogue: 0,1:01:52.30,1:01:59.95,Default,,0,0,0,,AFTER-FIB-N-2 Dialogue: 0,1:02:02.57,1:02:04.03,Default,,0,0,0,,对应了那边代码的某处 Dialogue: 0,1:02:05.32,1:02:07.23,Default,,0,0,0,,然而 我需要非常小心 Dialogue: 0,1:02:08.65,1:02:11.42,Default,,0,0,0,,而(FIB (- N 1))的值 Dialogue: 0,1:02:12.06,1:02:13.12,Default,,0,0,0,,我稍后会用到 Dialogue: 0,1:02:15.30,1:02:17.37,Default,,0,0,0,,(FIB (- N 1))的值 Dialogue: 0,1:02:17.61,1:02:18.48,Default,,0,0,0,,我需要它的值 Dialogue: 0,1:02:18.78,1:02:19.80,Default,,0,0,0,,我不能去改变它 Dialogue: 0,1:02:21.07,1:02:23.60,Default,,0,0,0,,因为我需要用它来加上(FIB (- N 2)) Dialogue: 0,1:02:24.15,1:02:25.88,Default,,0,0,0,,它是存放在寄存器中的 因此我需要保存它 Dialogue: 0,1:02:27.79,1:02:32.60,Default,,0,0,0,,所以现在我要用(SAVE VAL)来保存它 Dialogue: 0,1:02:33.78,1:02:35.44,Default,,0,0,0,,现在我就可以调用子过程了 Dialogue: 0,1:02:36.67,1:02:39.54,Default,,0,0,0,,(GOTO FIB-LOOP) Dialogue: 0,1:02:44.22,1:02:46.57,Default,,0,0,0,,现在 在进行更进一步计算之前 Dialogue: 0,1:02:46.80,1:02:49.36,Default,,0,0,0,,在结束这个程序之前 Dialogue: 0,1:02:49.39,1:02:51.05,Default,,0,0,0,,我想审视一下目前的代码片段 Dialogue: 0,1:02:51.23,1:02:56.00,Default,,0,0,0,,这里有一系列的指令 Dialogue: 0,1:02:57.84,1:02:59.08,Default,,0,0,0,,我可以对它们进行某些操作 Dialogue: 0,1:03:01.58,1:03:03.20,Default,,0,0,0,,这里 我有一个操作用来恢复CONTINUE Dialogue: 0,1:03:04.25,1:03:05.48,Default,,0,0,0,,一个操作用来保存CONTINUE Dialogue: 0,1:03:06.01,1:03:07.40,Default,,0,0,0,,然后给CONTINUE赋值 Dialogue: 0,1:03:08.70,1:03:10.64,Default,,0,0,0,,但这之中没有CONTINUE的其它引用 Dialogue: 0,1:03:13.84,1:03:15.48,Default,,0,0,0,,恢复之后又保存 Dialogue: 0,1:03:15.50,1:03:16.67,Default,,0,0,0,,使得栈没有被修改 Dialogue: 0,1:03:19.09,1:03:21.72,Default,,0,0,0,,唯一的区别就是 我给CONTINUE寄存器赋了值 Dialogue: 0,1:03:21.96,1:03:23.28,Default,,0,0,0,,一个存放在栈上的值 Dialogue: 0,1:03:24.33,1:03:25.79,Default,,0,0,0,,由于我现在改变了这个值 Dialogue: 0,1:03:26.44,1:03:27.93,Default,,0,0,0,,但这之间并没有引用这个值 Dialogue: 0,1:03:28.59,1:03:30.09,Default,,0,0,0,,这些指令就是不必要的 Dialogue: 0,1:03:31.76,1:03:35.39,Default,,0,0,0,,因此我们会移除它们 Dialogue: 0,1:03:38.88,1:03:40.78,Default,,0,0,0,,但我只有先把它们写出来 才会发现这个情况 Dialogue: 0,1:03:43.78,1:03:44.72,Default,,0,0,0,,真是这样吗? Dialogue: 0,1:03:45.77,1:03:46.60,Default,,0,0,0,,我并不知道 Dialogue: 0,1:03:48.61,1:03:52.91,Default,,0,0,0,,现在 我们要开始计算(FIB (- N 2))了 Dialogue: 0,1:03:53.66,1:03:54.59,Default,,0,0,0,,计算完毕后 Dialogue: 0,1:04:02.96,1:04:03.85,Default,,0,0,0,,我们又要做什么呢? Dialogue: 0,1:04:05.07,1:04:06.76,Default,,0,0,0,,我想 我们首先要做的就是 Dialogue: 0,1:04:06.99,1:04:07.88,Default,,0,0,0,,我们有两件事要做 Dialogue: 0,1:04:07.96,1:04:10.49,Default,,0,0,0,,目前VAL寄存器中的值 是有意义的 Dialogue: 0,1:04:10.92,1:04:11.98,Default,,0,0,0,,然而 栈上也有一个数据 Dialogue: 0,1:04:12.04,1:04:13.63,Default,,0,0,0,,需要恢复到VAL寄存器中 Dialogue: 0,1:04:14.81,1:04:16.57,Default,,0,0,0,,现在我需要非常小心的是 Dialogue: 0,1:04:16.88,1:04:18.99,Default,,0,0,0,,正确地给它们排序 以便计算乘法 Dialogue: 0,1:04:19.47,1:04:21.24,Default,,0,0,0,,现在 我可能会使用不同的约定 Dialogue: 0,1:04:21.47,1:04:23.52,Default,,0,0,0,,但我现在会采用非常挑剔的一种 Dialogue: 0,1:04:23.55,1:04:25.88,Default,,0,0,0,,栈上数据来自于哪个寄存器 就恢复到那个寄存器中 Dialogue: 0,1:04:26.74,1:04:28.28,Default,,0,0,0,,如果是这样的话 在这里我就要进行洗牌 Dialogue: 0,1:04:29.24,1:04:31.84,Default,,0,0,0,,这跟我有多少只手是同样的问题 Dialogue: 0,1:04:32.68,1:04:37.13,Default,,0,0,0,,现在我要给N赋值 Dialogue: 0,1:04:37.16,1:04:39.37,Default,,0,0,0,,因为我现在不再需要N了 N是无用的 Dialogue: 0,1:04:39.92,1:04:41.21,Default,,0,0,0,,获取当前VAL寄存器的值 Dialogue: 0,1:04:45.21,1:04:47.34,Default,,0,0,0,,也就是(FIB (- N 2))的值 Dialogue: 0,1:04:52.95,1:04:56.35,Default,,0,0,0,,现在 我就要恢复VAL寄存器了 Dialogue: 0,1:05:01.85,1:05:03.92,Default,,0,0,0,,这个RESTORE匹配这里的SAVE Dialogue: 0,1:05:05.58,1:05:08.83,Default,,0,0,0,,如果你非常仔细地研究发生了什么 Dialogue: 0,1:05:09.21,1:05:11.96,Default,,0,0,0,,会发现 RESTORE和SAVE总是成对的 Dialogue: 0,1:05:13.84,1:05:15.15,Default,,0,0,0,,现在 这里有个额外的SAVE Dialogue: 0,1:05:15.18,1:05:16.38,Default,,0,0,0,,当然 我们很快就会消灭它 Dialogue: 0,1:05:19.00,1:05:20.59,Default,,0,0,0,,恢复完VAL寄存器后 Dialogue: 0,1:05:20.94,1:05:22.57,Default,,0,0,0,,我就要恢复CONTINUE寄存器了 Dialogue: 0,1:05:31.15,1:05:32.40,Default,,0,0,0,,它匹配了这个 Dialogue: 0,1:05:34.80,1:05:37.85,Default,,0,0,0,,从这里到这里 Dialogue: 0,1:05:40.59,1:05:42.46,Default,,0,0,0,,这样就恢复了继续 Dialogue: 0,1:05:42.86,1:05:45.71,Default,,0,0,0,,这个表达式继续是由(FIB N)产生的 Dialogue: 0,1:05:46.46,1:05:47.84,Default,,0,0,0,,也就是我正尝试求解的 Dialogue: 0,1:05:47.85,1:05:49.32,Default,,0,0,0,,最主要的问题 Dialogue: 0,1:05:49.98,1:05:52.35,Default,,0,0,0,,我需要把(FIB N)的答案返回给这个继续 Dialogue: 0,1:05:52.54,1:05:54.03,Default,,0,0,0,,在我意识到N并不小于2之前 Dialogue: 0,1:05:54.16,1:05:56.60,Default,,0,0,0,,我一直保存着它们 Dialogue: 0,1:05:57.36,1:05:59.07,Default,,0,0,0,,因此 我需要进行一个复杂的运算 Dialogue: 0,1:06:00.84,1:06:02.57,Default,,0,0,0,,现在万事俱备 Dialogue: 0,1:06:03.24,1:06:04.36,Default,,0,0,0,,因此我要恢复它们 Dialogue: 0,1:06:05.42,1:06:21.08,Default,,0,0,0,,(ASSIGN VAL (+ (FETCH VAL) (FETCH N))) Dialogue: 0,1:06:27.44,1:06:28.60,Default,,0,0,0,,然后跳转到CONTINUE Dialogue: 0,1:06:38.26,1:06:44.78,Default,,0,0,0,,然后我就从(FIB N)中返回了出来 Dialogue: 0,1:06:45.39,1:06:46.57,Default,,0,0,0,,也就是FIB的一般情况 Dialogue: 0,1:06:47.11,1:06:50.60,Default,,0,0,0,,现在还有一些细节 需要我们填充 Dialogue: 0,1:06:50.99,1:06:55.53,Default,,0,0,0,,比如归纳的基本情况:可以立即得到答案 Dialogue: 0,1:07:02.54,1:07:06.59,Default,,0,0,0,,这不过就是 Dialogue: 0,1:07:06.60,1:07:11.85,Default,,0,0,0,,(ASSIGN VAL (FETCH N) Dialogue: 0,1:07:13.64,1:07:15.47,Default,,0,0,0,,因为N小于2 Dialogue: 0,1:07:15.50,1:07:16.89,Default,,0,0,0,,因此答案就是N Dialogue: 0,1:07:16.99,1:07:18.19,Default,,0,0,0,,跟源程序是一致的 Dialogue: 0,1:07:19.23,1:07:26.48,Default,,0,0,0,,(GOTO (FETCH CONTINUE)) Dialogue: 0,1:07:31.24,1:07:36.13,Default,,0,0,0,,最后就结束了 Dialogue: 0,1:07:43.46,1:07:45.64,Default,,0,0,0,,这是个相当复杂的程序 Dialogue: 0,1:07:45.64,1:07:47.34,Default,,0,0,0,,我之所以给你们演示这个程序 Dialogue: 0,1:07:47.50,1:07:49.21,Default,,0,0,0,,是因为我想让你们见识 Dialogue: 0,1:07:49.45,1:07:52.67,Default,,0,0,0,,我所遵守的栈使用准则 Dialogue: 0,1:07:53.32,1:07:55.21,Default,,0,0,0,,第一点就是 我不想保存那些 Dialogue: 0,1:07:56.92,1:07:58.12,Default,,0,0,0,,稍后不需要的值 Dialogue: 0,1:08:00.57,1:08:01.85,Default,,0,0,0,,我非常地小心 Dialogue: 0,1:08:01.85,1:08:02.91,Default,,0,0,0,,这非常重要 Dialogue: 0,1:08:03.94,1:08:06.52,Default,,0,0,0,,当然 人们还制定了其它的准则 Dialogue: 0,1:08:07.37,1:08:09.61,Default,,0,0,0,,来操作栈帧之类的东西 Dialogue: 0,1:08:10.19,1:08:11.39,Default,,0,0,0,,这些准则中 那些不再需要的东西 Dialogue: 0,1:08:11.40,1:08:12.64,Default,,0,0,0,,也需要保存并恢复 Dialogue: 0,1:08:12.67,1:08:15.26,Default,,0,0,0,,因为从某种意义上来说 这样做更容易些 Dialogue: 0,1:08:15.83,1:08:17.40,Default,,0,0,0,,但这会带来各种灾难 Dialogue: 0,1:08:18.59,1:08:20.25,Default,,0,0,0,,我们稍后就会见识一些 Dialogue: 0,1:08:21.44,1:08:24.24,Default,,0,0,0,,只保存那些你稍后需要的值 这很关键 Dialogue: 0,1:08:26.89,1:08:28.01,Default,,0,0,0,,这是非常重要的理念 Dialogue: 0,1:08:29.87,1:08:33.36,Default,,0,0,0,,无论谁保存了一个值 都应该由他来恢复 Dialogue: 0,1:08:33.76,1:08:35.32,Default,,0,0,0,,因为他需要这个值 Dialogue: 0,1:08:36.93,1:08:38.54,Default,,0,0,0,,在这样的准则中 Dialogue: 0,1:08:38.86,1:08:40.76,Default,,0,0,0,,你可以发现哪些数据是不必要的 Dialogue: 0,1:08:43.45,1:08:44.73,Default,,0,0,0,,哪些操作又是不重要的 Dialogue: 0,1:08:47.15,1:08:50.40,Default,,0,0,0,,我还想告诉你们 Dialogue: 0,1:08:51.66,1:08:54.67,Default,,0,0,0,,当然 你们看到的并不是全部的图景 Dialogue: 0,1:08:55.35,1:08:56.68,Default,,0,0,0,,假设我的系统中 Dialogue: 0,1:08:56.80,1:09:01.52,Default,,0,0,0,,具有像CAR、CDR、CONS这样的运算 Dialogue: 0,1:09:03.53,1:09:05.60,Default,,0,0,0,,或者创建一个向量 Dialogue: 0,1:09:05.88,1:09:07.32,Default,,0,0,0,,并引用它的第N个元素 Dialogue: 0,1:09:08.30,1:09:09.21,Default,,0,0,0,,等等运算 Dialogue: 0,1:09:10.40,1:09:13.60,Default,,0,0,0,,然而 就在这个层次的细节来说 Dialogue: 0,1:09:13.87,1:09:17.85,Default,,0,0,0,,我们可以在数据通路中把它们视为基本运算 Dialogue: 0,1:09:18.75,1:09:21.95,Default,,0,0,0,,换句话说 我们可以认为 有一台机器 Dialogue: 0,1:09:22.32,1:09:24.11,Default,,0,0,0,,包含了APPEND机器 Dialogue: 0,1:09:24.20,1:09:26.46,Default,,0,0,0,,它通过(CONS (CAR X) Dialogue: 0,1:09:26.64,1:09:29.80,Default,,0,0,0,,(APPEND (CDR X) Y)来实现 Dialogue: 0,1:09:29.88,1:09:33.18,Default,,0,0,0,,哦 天啊 这就跟阶乘机器有相同的结构 Dialogue: 0,1:09:33.63,1:09:35.29,Default,,0,0,0,,当然 它有相同的结构 Dialogue: 0,1:09:36.54,1:09:37.27,Default,,0,0,0,,我们有什么呢? Dialogue: 0,1:09:37.27,1:09:39.39,Default,,0,0,0,,我们有某种东西 其中有 Dialogue: 0,1:09:39.76,1:09:42.48,Default,,0,0,0,,诸如X、Y之类的寄存器 Dialogue: 0,1:09:42.51,1:09:45.12,Default,,0,0,0,,有时X会移动到Y中 Dialogue: 0,1:09:45.28,1:09:46.75,Default,,0,0,0,,或者X会取得Y的值 Dialogue: 0,1:09:46.93,1:09:50.11,Default,,0,0,0,,我们或许要需要能够进行CONS运算 Dialogue: 0,1:09:51.70,1:09:57.74,Default,,0,0,0,,我记不清这个系统中是否需要这样的东西 Dialogue: 0,1:09:57.76,1:10:01.10,Default,,0,0,0,,但CONS有点类似于减法器或加法器之类的东西 Dialogue: 0,1:10:01.42,1:10:02.70,Default,,0,0,0,,它把两个东西结合起来 Dialogue: 0,1:10:02.73,1:10:04.27,Default,,0,0,0,,然后产生一个序对 Dialogue: 0,1:10:04.51,1:10:06.49,Default,,0,0,0,,然后会把输出结果送入到这里 Dialogue: 0,1:10:07.60,1:10:09.72,Default,,0,0,0,,可能还有一个叫做CAR的组件 Dialogue: 0,1:10:12.88,1:10:16.22,Default,,0,0,0,,它的结果是 -- 某个东西的CAR部分 Dialogue: 0,1:10:16.92,1:10:19.55,Default,,0,0,0,,我还可以取得某物的CDR部分 等等 Dialogue: 0,1:10:20.15,1:10:22.30,Default,,0,0,0,,但我们不应该害怕这么说 Dialogue: 0,1:10:22.92,1:10:24.24,Default,,0,0,0,,因为最坏的情况不过 Dialogue: 0,1:10:24.94,1:10:26.41,Default,,0,0,0,,当我们打开CONS后 Dialogue: 0,1:10:27.31,1:10:29.82,Default,,0,0,0,,会发现其中存在某台机器 Dialogue: 0,1:10:31.88,1:10:34.44,Default,,0,0,0,,CONS可能会与CAR和CDR有所重叠 Dialogue: 0,1:10:35.50,1:10:38.12,Default,,0,0,0,,就像加法和减法有所重叠一样 Dialogue: 0,1:10:38.57,1:10:39.85,Default,,0,0,0,,它们本质上都是一样的 Dialogue: 0,1:10:41.21,1:10:42.60,Default,,0,0,0,,CONS、CAR和CDR将会有所重叠 Dialogue: 0,1:10:42.62,1:10:44.52,Default,,0,0,0,,我们会发现其中有小型控制器 Dialogue: 0,1:10:45.50,1:10:46.54,Default,,0,0,0,,小型的数据通路 Dialogue: 0,1:10:48.03,1:10:49.64,Default,,0,0,0,,其中还有一些寄存器 Dialogue: 0,1:10:50.00,1:10:52.86,Default,,0,0,0,,一些其它的像这样的东西 Dialogue: 0,1:10:53.30,1:10:54.41,Default,,0,0,0,,并且 也许在这之中 Dialogue: 0,1:10:54.43,1:10:56.16,Default,,0,0,0,,可能也有无穷的部分 Dialogue: 0,1:10:56.46,1:10:58.70,Default,,0,0,0,,又或者是半无穷的 之类的 Dialogue: 0,1:10:58.81,1:11:00.65,Default,,0,0,0,,这些都是统一的东西 Dialogue: 0,1:11:00.96,1:11:02.03,Default,,0,0,0,,也就是我们所谓的“内存” Dialogue: 0,1:11:06.57,1:11:08.83,Default,,0,0,0,,有限的内存也能无穷地存储 对此我一点也不吃惊 Dialogue: 0,1:11:09.33,1:11:11.07,Default,,0,0,0,,实际上它就是这样的 我们之后就会了解 Dialogue: 0,1:11:13.32,1:11:14.57,Default,,0,0,0,,那么 有什么疑问么? Dialogue: 0,1:11:24.34,1:11:25.80,Default,,0,0,0,,天啊!你们都一言不发 Dialogue: 0,1:11:28.67,1:11:30.33,Default,,0,0,0,,假设我说得都是谎言吧! Dialogue: 0,1:11:39.69,1:11:40.38,Default,,0,0,0,,好吧 Dialogue: 0,1:11:41.99,1:11:42.52,Default,,0,0,0,,谢谢大家 Dialogue: 0,1:11:42.52,1:11:43.28,Default,,0,0,0,,我们下课吧! Dialogue: 0,1:11:44.23,1:11:55.15,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:11:44.23,1:11:55.15,Default,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec9a.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 1258 Active Line: 1269 Video Position: 128947 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.03,0:00:02.04,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP 学习小组\N倾情制作 Dialogue: 0,0:00:02.04,0:00:09.09,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:02.04,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.04,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:02.04,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:02.04,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:09.21,0:00:13.12,Declare,,0,0,0,,{\an2\fad(500,500)}寄存机器 Dialogue: 0,0:00:17.26,0:00:19.07,Default,,0,0,0,,教授:我认为 到目前为止 Dialogue: 0,0:00:19.32,0:00:23.93,Default,,0,0,0,,我们已经学习了很多关于 Dialogue: 0,0:00:24.09,0:00:28.83,Default,,0,0,0,,组织程序以及操纵符号的技术 Dialogue: 0,0:00:30.84,0:00:35.60,Default,,0,0,0,,以及用来构建语言的技术 Dialogue: 0,0:00:35.63,0:00:36.78,Default,,0,0,0,,用一门语言去创建另一门语言 Dialogue: 0,0:00:37.10,0:00:39.92,Default,,0,0,0,,这在组织大型程序时非常有用 Dialogue: 0,0:00:39.96,0:00:42.30,Default,,0,0,0,,实际上 我所知的最好的程序 Dialogue: 0,0:00:42.44,0:00:44.43,Default,,0,0,0,,看起来更像是一堆语言 Dialogue: 0,0:00:44.91,0:00:47.96,Default,,0,0,0,,而不是将问题分解成若干部分 Dialogue: 0,0:00:49.90,0:00:51.45,Default,,0,0,0,,我想 此时此刻 Dialogue: 0,0:00:52.08,0:00:53.58,Default,,0,0,0,,关于这类东西的工作方式 Dialogue: 0,0:00:53.61,0:00:55.32,Default,,0,0,0,,仍然存在一些谜团 Dialogue: 0,0:00:56.26,0:00:59.68,Default,,0,0,0,,因此 我现在需要 Dialogue: 0,0:01:00.03,0:01:02.60,Default,,0,0,0,,偏离原先的计划 Dialogue: 0,0:01:02.96,0:01:05.42,Default,,0,0,0,,不再继续讲解如何组织大型程序 Dialogue: 0,0:01:05.45,0:01:08.19,Default,,0,0,0,,而是告诉你一些关于 Dialogue: 0,0:01:08.52,0:01:11.71,Default,,0,0,0,,使这些事情可以起作用的机制 Dialogue: 0,0:01:12.19,0:01:14.83,Default,,0,0,0,,这样做的主要是为了 Dialogue: 0,0:01:15.80,0:01:17.87,Default,,0,0,0,,揭秘 Dialogue: 0,0:01:18.65,0:01:20.54,Default,,0,0,0,,剩下的很多谜团 Dialogue: 0,0:01:21.08,0:01:25.48,Default,,0,0,0,,比如说 如何控制程序的运行 Dialogue: 0,0:01:26.08,0:01:30.38,Default,,0,0,0,,计算机如何知晓下一步的动作 Dialogue: 0,0:01:30.52,0:01:31.74,Default,,0,0,0,,等等等等 Dialogue: 0,0:01:32.43,0:01:35.56,Default,,0,0,0,,我现在就要让你们清楚地知道 Dialogue: 0,0:01:35.85,0:01:39.10,Default,,0,0,0,,就算你之前没有使用过计算机 Dialogue: 0,0:01:39.56,0:01:43.50,Default,,0,0,0,,但这种机制非常简单 Dialogue: 0,0:01:44.33,0:01:46.35,Default,,0,0,0,,你可以毫无问题地理解它 Dialogue: 0,0:01:47.65,0:01:51.24,Default,,0,0,0,,好吧 我们先来想象一个 -- Dialogue: 0,0:01:51.32,0:01:52.91,Default,,0,0,0,,先说明一下 我们采用的方法是 Dialogue: 0,0:01:52.96,0:01:55.80,Default,,0,0,0,,把一些非常简单的Lisp程序 Dialogue: 0,0:01:56.54,0:01:58.12,Default,,0,0,0,,真的非常简单 Dialogue: 0,0:01:59.04,0:02:00.62,Default,,0,0,0,,把它们转换成硬件 Dialogue: 0,0:02:02.16,0:02:04.16,Default,,0,0,0,,我不会考虑一些中间步骤 Dialogue: 0,0:02:04.70,0:02:07.45,Default,,0,0,0,,比如转换成某种现有的机器语言 Dialogue: 0,0:02:07.47,0:02:09.05,Default,,0,0,0,,然后来解释计算机是如何工作的 Dialogue: 0,0:02:09.82,0:02:12.00,Default,,0,0,0,,因为那不太明显 Dialogue: 0,0:02:12.75,0:02:14.17,Default,,0,0,0,,所以我真正要向你展示的是 Dialogue: 0,0:02:14.51,0:02:17.48,Default,,0,0,0,,如何构建一台机器来完成 Dialogue: 0,0:02:18.03,0:02:22.04,Default,,0,0,0,,一项由你写的程序所描述的工作 Dialogue: 0,0:02:22.04,0:02:24.03,Default,,0,0,0,,而程序呢 实际上就是一个机器的描述 Dialogue: 0,0:02:25.76,0:02:27.69,Default,,0,0,0,,我们从一个非常简单的程序开始 Dialogue: 0,0:02:28.09,0:02:30.81,Default,,0,0,0,,然后演示一些简单的机制 Dialogue: 0,0:02:31.39,0:02:33.68,Default,,0,0,0,,进而用更复杂的程序 Dialogue: 0,0:02:34.30,0:02:37.42,Default,,0,0,0,,然后又演示一个不那么复杂的程序 Dialogue: 0,0:02:37.44,0:02:41.23,Default,,0,0,0,,来演示求值器是如何变成硬件的 Dialogue: 0,0:02:41.23,0:02:42.06,Default,,0,0,0,,当然 到那个时候 Dialogue: 0,0:02:42.08,0:02:44.08,Default,,0,0,0,,你就有了通用的转换算法 Dialogue: 0,0:02:44.22,0:02:46.88,Default,,0,0,0,,并且可以用一个定义明确的硬件 Dialogue: 0,0:02:47.16,0:02:48.80,Default,,0,0,0,,来执行任何可以想象的程序 Dialogue: 0,0:02:51.72,0:02:52.91,Default,,0,0,0,,那么 现在让我们开始 Dialogue: 0,0:02:53.05,0:02:55.31,Default,,0,0,0,,给你们关于这些东西的具体感觉 Dialogue: 0,0:02:55.44,0:02:57.66,Default,,0,0,0,,我们先从一个非常简单的程序开始 Dialogue: 0,0:02:59.60,0:03:00.85,Default,,0,0,0,,这是欧几里得算法 Dialogue: 0,0:03:03.88,0:03:07.00,Default,,0,0,0,,它实际上比欧几里德算法更现代一些 Dialogue: 0,0:03:07.02,0:03:10.09,Default,,0,0,0,,我想 用来计算两数最大公约数的欧几里得算法 Dialogue: 0,0:03:10.41,0:03:13.60,Default,,0,0,0,,是在公元前350年发明的 Dialogue: 0,0:03:14.30,0:03:15.69,Default,,0,0,0,,它是已知最古老的算法 Dialogue: 0,0:03:19.32,0:03:23.34,Default,,0,0,0,,我们先定义(GCD A B) Dialogue: 0,0:03:23.36,0:03:25.61,Default,,0,0,0,,也就是用来计算A、B两数的最大公约数 Dialogue: 0,0:03:26.20,0:03:28.91,Default,,0,0,0,,这个算法相当简单 Dialogue: 0,0:03:29.50,0:03:31.08,Default,,0,0,0,,如果B等于0 Dialogue: 0,0:03:34.16,0:03:36.83,Default,,0,0,0,,那么结果就是A Dialogue: 0,0:03:37.52,0:03:43.61,Default,,0,0,0,,否则结果就是 (GCD B Dialogue: 0,0:03:44.49,0:03:53.39,Default,,0,0,0,,(REMAINDER A B)) Dialogue: 0,0:03:58.53,0:04:01.90,Default,,0,0,0,,这里 我们定义了一个简单的迭代过程 Dialogue: 0,0:04:02.03,0:04:04.08,Default,,0,0,0,,这是一个简单的递归过程 Dialogue: 0,0:04:04.38,0:04:07.53,Default,,0,0,0,,也可以说这个过程是递归地定义的 Dialogue: 0,0:04:07.71,0:04:09.26,Default,,0,0,0,,但它产生的计算过程是迭代的 Dialogue: 0,0:04:09.95,0:04:12.46,Default,,0,0,0,,它的原理是 在每一步 Dialogue: 0,0:04:12.80,0:04:15.10,Default,,0,0,0,,判断B是否为0 Dialogue: 0,0:04:16.24,0:04:18.80,Default,,0,0,0,,如果B为0 那么A的值就是我们的答案 Dialogue: 0,0:04:19.63,0:04:22.46,Default,,0,0,0,,否则就进入下一个步骤 Dialogue: 0,0:04:22.49,0:04:23.87,Default,,0,0,0,,其中A就变成旧的B Dialogue: 0,0:04:23.88,0:04:27.04,Default,,0,0,0,,而B的值 是A旧值除B旧值的余数 Dialogue: 0,0:04:28.76,0:04:29.55,Default,,0,0,0,,非常简单 Dialogue: 0,0:04:31.11,0:04:32.72,Default,,0,0,0,,现在 我已经通过这种方式 Dialogue: 0,0:04:32.99,0:04:34.86,Default,,0,0,0,,告诉了你一些机制 Dialogue: 0,0:04:34.86,0:04:35.90,Default,,0,0,0,,我是按时序告诉你们的 Dialogue: 0,0:04:36.36,0:04:37.72,Default,,0,0,0,,我说 其中有特定的步骤 Dialogue: 0,0:04:38.14,0:04:39.32,Default,,0,0,0,,并且实际上 Dialogue: 0,0:04:39.52,0:04:40.86,Default,,0,0,0,,你可以在这里知道 Dialogue: 0,0:04:41.18,0:04:43.69,Default,,0,0,0,,为什么这个过程是迭代的 Dialogue: 0,0:04:43.95,0:04:47.68,Default,,0,0,0,,是因为最后一步无需额外信息来得到答案 Dialogue: 0,0:04:49.44,0:04:55.29,Default,,0,0,0,,所有运行此算法所需的信息都在A和B中 Dialogue: 0,0:04:55.74,0:04:57.80,Default,,0,0,0,,它有两个定义明确的状态变量 Dialogue: 0,0:05:00.47,0:05:02.33,Default,,0,0,0,,现在 我就要给你们定义一台机器 Dialogue: 0,0:05:03.98,0:05:05.55,Default,,0,0,0,,用来计算GCD Dialogue: 0,0:05:06.56,0:05:07.12,Default,,0,0,0,,我们来看看 Dialogue: 0,0:05:07.12,0:05:11.28,Default,,0,0,0,,每台制造的计算机都是单进程计算机 Dialogue: 0,0:05:11.80,0:05:14.08,Default,,0,0,0,,而不是某种多处理器 Dialogue: 0,0:05:15.04,0:05:16.59,Default,,0,0,0,,都是按照相同的方案制定的 Dialogue: 0,0:05:17.84,0:05:19.53,Default,,0,0,0,,这种方案就是:计算机由两部分组成 Dialogue: 0,0:05:20.57,0:05:22.35,Default,,0,0,0,,一部分叫数据通路 Dialogue: 0,0:05:23.10,0:05:24.36,Default,,0,0,0,,而另一部分叫控制器 Dialogue: 0,0:05:25.91,0:05:29.28,Default,,0,0,0,,数据通路相当于你可能有的计算器 Dialogue: 0,0:05:29.71,0:05:31.87,Default,,0,0,0,,它有一些寄存器 能够存储数据 Dialogue: 0,0:05:31.90,0:05:33.13,Default,,0,0,0,,你们都用过计算器 Dialogue: 0,0:05:33.56,0:05:35.34,Default,,0,0,0,,它上面有一些按钮和指示灯 Dialogue: 0,0:05:37.03,0:05:38.49,Default,,0,0,0,,通过按下不同的按钮 Dialogue: 0,0:05:38.52,0:05:41.34,Default,,0,0,0,,你可以使操作在寄存器内发生 Dialogue: 0,0:05:41.87,0:05:43.48,Default,,0,0,0,,并显示计算结果 Dialogue: 0,0:05:45.16,0:05:46.25,Default,,0,0,0,,它是完全机械式的 Dialogue: 0,0:05:46.25,0:05:49.55,Default,,0,0,0,,你可以认为那个盒子没有任何智能 Dialogue: 0,0:05:50.90,0:05:53.28,Default,,0,0,0,,它能计算一个数的正弦也许令人吃惊 Dialogue: 0,0:05:53.53,0:05:58.97,Default,,0,0,0,,但它显然是机械式的 Dialogue: 0,0:05:58.97,0:06:01.71,Default,,0,0,0,,至少 我可以像打开GCD机器一样打开它 Dialogue: 0,0:06:02.69,0:06:04.36,Default,,0,0,0,,也就是说 它其中可能有一整台计算机 Dialogue: 0,0:06:04.68,0:06:05.69,Default,,0,0,0,,但这并不有趣 Dialogue: 0,0:06:05.94,0:06:07.10,Default,,0,0,0,,加法相当简单 Dialogue: 0,0:06:08.20,0:06:09.84,Default,,0,0,0,,不借助额外机制就可以完成 Dialogue: 0,0:06:10.89,0:06:15.64,Default,,0,0,0,,现在 如果我们来看另外的一部分:控制器 Dialogue: 0,0:06:15.93,0:06:17.39,Default,,0,0,0,,这一部分也非常简单 Dialogue: 0,0:06:18.19,0:06:19.16,Default,,0,0,0,,它负责按下按钮 Dialogue: 0,0:06:20.35,0:06:21.52,Default,,0,0,0,,它根据指令序列来按按钮 Dialogue: 0,0:06:21.55,0:06:22.84,Default,,0,0,0,,指令是写在纸上的 Dialogue: 0,0:06:24.27,0:06:25.64,Default,,0,0,0,,控制器还会观察指示灯 Dialogue: 0,0:06:26.29,0:06:29.44,Default,,0,0,0,,而且每隔一段 它就会来到指令序列中的一处 Dialogue: 0,0:06:29.47,0:06:32.37,Default,,0,0,0,,如果指示灯A亮 则执行某段指令 Dialogue: 0,0:06:32.37,0:06:33.85,Default,,0,0,0,,否则执行另外的指令 Dialogue: 0,0:06:34.62,0:06:37.45,Default,,0,0,0,,因此 这其中也没有什么复杂的 Dialogue: 0,0:06:38.35,0:06:39.32,Default,,0,0,0,,那么 让我们来画一下 Dialogue: 0,0:06:39.34,0:06:40.57,Default,,0,0,0,,然后来感受一下它 Dialogue: 0,0:06:42.51,0:06:44.84,Default,,0,0,0,,为了计算GCD Dialogue: 0,0:06:45.88,0:06:49.52,Default,,0,0,0,,你们要知道:这其中有一些寄存器 Dialogue: 0,0:06:50.56,0:06:53.02,Default,,0,0,0,,这里 寄存器就是一个存储数值的地方 Dialogue: 0,0:06:53.52,0:06:54.65,Default,,0,0,0,,这个寄存器存储的是A Dialogue: 0,0:06:56.81,0:06:58.70,Default,,0,0,0,,而另外的这个存储的是B Dialogue: 0,0:07:03.17,0:07:05.45,Default,,0,0,0,,现在我们来看看 有了这些寄存器后能做什么 Dialogue: 0,0:07:05.98,0:07:08.73,Default,,0,0,0,,至于你能利用它做什么 并不是很明显 Dialogue: 0,0:07:09.84,0:07:11.72,Default,,0,0,0,,那么 我们必须看看需要用它们做什么 Dialogue: 0,0:07:11.82,0:07:13.87,Default,,0,0,0,,我们来看看尝试求解的问题 Dialogue: 0,0:07:14.03,0:07:16.09,Default,,0,0,0,,计算机设计的一个要点就是 Dialogue: 0,0:07:17.10,0:07:19.58,Default,,0,0,0,,我想大多数设计师都不会照做 Dialogue: 0,0:07:20.20,0:07:21.88,Default,,0,0,0,,也就是专注于待解的问题 Dialogue: 0,0:07:22.62,0:07:25.18,Default,,0,0,0,,然后使用你研究问题所学到的东西 Dialogue: 0,0:07:25.44,0:07:27.28,Default,,0,0,0,,把那些求解问题所需要的机制 Dialogue: 0,0:07:27.53,0:07:28.70,Default,,0,0,0,,融入正在构建的计算机中 Dialogue: 0,0:07:28.81,0:07:30.08,Default,,0,0,0,,不多也不少 Dialogue: 0,0:07:32.14,0:07:33.96,Default,,0,0,0,,现在 可能你所要解决的问题 Dialogue: 0,0:07:34.24,0:07:35.40,Default,,0,0,0,,是大家共有的问题 Dialogue: 0,0:07:36.06,0:07:37.58,Default,,0,0,0,,这种情况下你需要构建 Dialogue: 0,0:07:37.60,0:07:39.29,Default,,0,0,0,,某种语言的通用解释器 Dialogue: 0,0:07:40.19,0:07:42.32,Default,,0,0,0,,但是你添加的机制不能比 Dialogue: 0,0:07:42.35,0:07:44.25,Default,,0,0,0,,想构建的语言解释器的需求多 Dialogue: 0,0:07:44.44,0:07:45.85,Default,,0,0,0,,这一点 我们稍后来讨论 Dialogue: 0,0:07:47.23,0:07:49.93,Default,,0,0,0,,好了 让我们回到这里 Dialogue: 0,0:07:49.93,0:07:51.24,Default,,0,0,0,,我们必须能够做什么? Dialogue: 0,0:07:51.79,0:07:54.14,Default,,0,0,0,,首先 我们能把B的值赋给A Dialogue: 0,0:07:56.08,0:07:59.60,Default,,0,0,0,,我们要能够把B的旧值赋给A Dialogue: 0,0:08:00.38,0:08:03.32,Default,,0,0,0,,因此 我们需要某种能够让数据流通的“路径” Dialogue: 0,0:08:03.34,0:08:04.76,Default,,0,0,0,,而不管数据具体是什么 Dialogue: 0,0:08:05.37,0:08:06.57,Default,,0,0,0,,从B到A的通路 Dialogue: 0,0:08:07.39,0:08:09.26,Default,,0,0,0,,我箭头来指示 Dialogue: 0,0:08:09.52,0:08:12.62,Default,,0,0,0,,我们能够把B的值赋给A Dialogue: 0,0:08:12.96,0:08:14.57,Default,,0,0,0,,从而替换A的旧值 Dialogue: 0,0:08:15.12,0:08:16.73,Default,,0,0,0,,当你按下这里的按钮后 Dialogue: 0,0:08:17.48,0:08:18.56,Default,,0,0,0,,就能够实现这个效果 Dialogue: 0,0:08:19.71,0:08:20.78,Default,,0,0,0,,这个按钮就在这里 Dialogue: 0,0:08:23.07,0:08:23.93,Default,,0,0,0,,同样的 Dialogue: 0,0:08:23.95,0:08:26.28,Default,,0,0,0,,我还需要能够计算A除B的余数 Dialogue: 0,0:08:27.00,0:08:28.49,Default,,0,0,0,,这可能混乱而又复杂 Dialogue: 0,0:08:28.86,0:08:30.86,Default,,0,0,0,,但另一方面 我会把它放到一个小盒子中 Dialogue: 0,0:08:31.96,0:08:33.92,Default,,0,0,0,,如果有必要的话 我们可以打开那个盒子 Dialogue: 0,0:08:34.12,0:08:35.63,Default,,0,0,0,,看看其中有些什么 Dialogue: 0,0:08:37.77,0:08:39.16,Default,,0,0,0,,这就是那个小盒子 Dialogue: 0,0:08:39.20,0:08:40.38,Default,,0,0,0,,我这么来画它 Dialogue: 0,0:08:43.16,0:08:44.38,Default,,0,0,0,,我把它叫做REM Dialogue: 0,0:08:46.44,0:08:48.60,Default,,0,0,0,,它接受A Dialogue: 0,0:08:50.91,0:08:52.16,Default,,0,0,0,,同时也要接受B Dialogue: 0,0:08:54.37,0:08:56.51,Default,,0,0,0,,它有一个输出 Dialogue: 0,0:08:58.89,0:09:00.46,Default,,0,0,0,,也就是A除以B的余数 Dialogue: 0,0:09:02.29,0:09:03.61,Default,,0,0,0,,在这里 我们同样需要能够 Dialogue: 0,0:09:03.64,0:09:06.06,Default,,0,0,0,,判断B是否等于0 Dialogue: 0,0:09:08.00,0:09:09.66,Default,,0,0,0,,也就是说 总得有个东西 Dialogue: 0,0:09:10.00,0:09:12.30,Default,,0,0,0,,去查询B的值 Dialogue: 0,0:09:13.39,0:09:14.40,Default,,0,0,0,,这是一个指示灯 Dialogue: 0,0:09:15.85,0:09:17.39,Default,,0,0,0,,当B等于0时 它就会点亮 Dialogue: 0,0:09:21.11,0:09:22.01,Default,,0,0,0,,它就是干这个的 Dialogue: 0,0:09:24.03,0:09:26.78,Default,,0,0,0,,最后 因为我们希望 Dialogue: 0,0:09:26.96,0:09:30.43,Default,,0,0,0,,A的新值是B的旧值 Dialogue: 0,0:09:30.46,0:09:34.41,Default,,0,0,0,,同时B的新值是有关于A的 Dialogue: 0,0:09:35.28,0:09:37.60,Default,,0,0,0,,如果我打算让机器 Dialogue: 0,0:09:37.80,0:09:39.74,Default,,0,0,0,,一次只发生一件事 Dialogue: 0,0:09:40.20,0:09:41.40,Default,,0,0,0,,一次执行一个动作 Dialogue: 0,0:09:41.61,0:09:43.42,Default,,0,0,0,,并且我不能在一个寄存器中放两个数字 Dialogue: 0,0:09:44.03,0:09:46.30,Default,,0,0,0,,那么进行互换时 必须有另外的地方放置一个数字 Dialogue: 0,0:09:49.29,0:09:49.60,Default,,0,0,0,,对吧? Dialogue: 0,0:09:50.00,0:09:51.85,Default,,0,0,0,,我不能同时交换两手的东西 Dialogue: 0,0:09:52.11,0:09:53.72,Default,,0,0,0,,除非我一手拿两个 Dialogue: 0,0:09:53.72,0:09:55.13,Default,,0,0,0,,然后从中取另外一个 Dialogue: 0,0:09:55.50,0:09:56.91,Default,,0,0,0,,或者我先放下一个 Dialogue: 0,0:09:57.02,0:09:58.68,Default,,0,0,0,,取得另一个后再像这样捡起来 Dialogue: 0,0:09:59.64,0:10:00.94,Default,,0,0,0,,除非我是耍杂技的 Dialogue: 0,0:10:01.66,0:10:03.50,Default,,0,0,0,,当然正如大家所见 我并不是 Dialogue: 0,0:10:04.65,0:10:07.36,Default,,0,0,0,,这种情况下 我就会遇到时序错误 Dialogue: 0,0:10:08.85,0:10:11.04,Default,,0,0,0,,事实上 人们所做的许多类型的计算机设计 Dialogue: 0,0:10:11.07,0:10:12.68,Default,,0,0,0,,都遇到了时序错误 Dialogue: 0,0:10:13.12,0:10:15.00,Default,,0,0,0,,或者潜在的时序错误 Dialogue: 0,0:10:15.24,0:10:16.43,Default,,0,0,0,,我不太喜欢这种错误 Dialogue: 0,0:10:17.34,0:10:18.64,Default,,0,0,0,,因此 出于这个原因 Dialogue: 0,0:10:18.68,0:10:21.21,Default,,0,0,0,,我需要有一个地方来放置 Dialogue: 0,0:10:22.06,0:10:23.29,Default,,0,0,0,,其中的一个元素 Dialogue: 0,0:10:23.41,0:10:24.72,Default,,0,0,0,,因此 这里有一个寄存器 Dialogue: 0,0:10:24.75,0:10:26.84,Default,,0,0,0,,用来存放临时值T Dialogue: 0,0:10:28.59,0:10:29.63,Default,,0,0,0,,上面有一个按钮 Dialogue: 0,0:10:30.47,0:10:31.88,Default,,0,0,0,,我会使用它的结果 Dialogue: 0,0:10:31.90,0:10:34.14,Default,,0,0,0,,因为我需要把这个结果送入B Dialogue: 0,0:10:34.68,0:10:36.73,Default,,0,0,0,,我们会把结果像这样给送过来 Dialogue: 0,0:10:38.41,0:10:39.30,Default,,0,0,0,,这里同样有一个按钮 Dialogue: 0,0:10:42.43,0:10:45.84,Default,,0,0,0,,这就是GCD机器的数据通路 Dialogue: 0,0:10:47.60,0:10:48.57,Default,,0,0,0,,那么 控制器又是怎样的呢? Dialogue: 0,0:10:49.74,0:10:51.28,Default,,0,0,0,,控制器同样很简单 Dialogue: 0,0:10:52.28,0:10:53.26,Default,,0,0,0,,机器具有状态 Dialogue: 0,0:10:54.38,0:10:57.72,Default,,0,0,0,,我喜欢形象地把它们比作迷宫 Dialogue: 0,0:10:59.01,0:11:03.20,Default,,0,0,0,,这个迷宫的各处是通过直接的箭头连接的 Dialogue: 0,0:11:04.43,0:11:05.60,Default,,0,0,0,,而我有一颗弹珠 Dialogue: 0,0:11:06.46,0:11:09.07,Default,,0,0,0,,它代表了控制器的状态 Dialogue: 0,0:11:10.74,0:11:12.27,Default,,0,0,0,,弹珠在迷宫中四处滚动 Dialogue: 0,0:11:13.74,0:11:17.15,Default,,0,0,0,,当然 这种类比因能量的原因而不成立 Dialogue: 0,0:11:17.15,0:11:19.08,Default,,0,0,0,,有时我不得不将弹珠泵到顶部 Dialogue: 0,0:11:19.12,0:11:21.85,Default,,0,0,0,,不然它就会成为一台永动机 Dialogue: 0,0:11:22.00,0:11:23.32,Default,,0,0,0,,但不用担心那么多 Dialogue: 0,0:11:23.90,0:11:25.90,Default,,0,0,0,,这并不是一个物理比喻 Dialogue: 0,0:11:26.08,0:11:27.42,Default,,0,0,0,,弹珠到处滚动 Dialogue: 0,0:11:27.68,0:11:29.56,Default,,0,0,0,,就像弹球机一样 Dialogue: 0,0:11:29.68,0:11:30.97,Default,,0,0,0,,每次当它滚动到一些缓冲器时 Dialogue: 0,0:11:31.26,0:11:32.60,Default,,0,0,0,,它就会按下这些按钮 Dialogue: 0,0:11:34.83,0:11:37.50,Default,,0,0,0,,它也会经常来到一个分支区域 Dialogue: 0,0:11:38.62,0:11:39.68,Default,,0,0,0,,它要在这里做选择 Dialogue: 0,0:11:40.25,0:11:42.36,Default,,0,0,0,,然后有一个由这个组件控制的挡板 Dialogue: 0,0:11:46.00,0:11:48.82,Default,,0,0,0,,所以这是一个非常机械化的思考方式 Dialogue: 0,0:11:48.82,0:11:51.05,Default,,0,0,0,,当然 真实计算机中的控制器 Dialogue: 0,0:11:51.08,0:11:51.84,Default,,0,0,0,,并不是这样的 Dialogue: 0,0:11:51.84,0:11:56.01,Default,,0,0,0,,而是由一些ROM和状态寄存器构成 Dialogue: 0,0:11:56.61,0:11:58.73,Default,,0,0,0,,但曾几何时 像DEC、PDP-6这些个机器 Dialogue: 0,0:11:59.29,0:12:01.02,Default,,0,0,0,,它们的控制器就是我们说的那样 Dialogue: 0,0:12:01.80,0:12:03.61,Default,,0,0,0,,延迟线上有一些比特信息 Dialogue: 0,0:12:05.69,0:12:08.14,Default,,0,0,0,,它随着时间的推移而触发事件 Dialogue: 0,0:12:08.58,0:12:10.70,Default,,0,0,0,,然后回到开始并再次轮回 Dialogue: 0,0:12:11.99,0:12:13.72,Default,,0,0,0,,当然 还有各种各样的错误 Dialogue: 0,0:12:13.74,0:12:17.67,Default,,0,0,0,,比如两个比特的信息 -- 对应两个弹珠 Dialogue: 0,0:12:17.67,0:12:19.26,Default,,0,0,0,,机器也会丢失弹珠 Dialogue: 0,0:12:19.45,0:12:20.20,Default,,0,0,0,,这也会发生 Dialogue: 0,0:12:20.98,0:12:21.58,Default,,0,0,0,,好吧 Dialogue: 0,0:12:22.27,0:12:24.22,Default,,0,0,0,,无论如何 对于这台机器 Dialogue: 0,0:12:24.27,0:12:25.48,Default,,0,0,0,,我想要这么来做 Dialogue: 0,0:12:25.80,0:12:27.74,Default,,0,0,0,,迷宫从这里开始 Dialogue: 0,0:12:30.52,0:12:32.73,Default,,0,0,0,,我首先要做的是 Dialogue: 0,0:12:33.76,0:12:36.75,Default,,0,0,0,,用一个你们非常熟悉的流程图记号 Dialogue: 0,0:12:37.07,0:12:39.85,Default,,0,0,0,,这是一个判断:B是否为0 Dialogue: 0,0:12:41.50,0:12:43.79,Default,,0,0,0,,如果判断为是的话 Dialogue: 0,0:12:43.93,0:12:45.58,Default,,0,0,0,,那我就做完了 Dialogue: 0,0:12:49.79,0:12:51.26,Default,,0,0,0,,否则的话 Dialogue: 0,0:12:52.70,0:12:54.32,Default,,0,0,0,,我就不得不滚动一些缓冲器 Dialogue: 0,0:12:55.00,0:12:56.46,Default,,0,0,0,,按照下列顺序执行 Dialogue: 0,0:12:57.42,0:13:03.40,Default,,0,0,0,,我想向这样来做一个互换游戏 Dialogue: 0,0:13:04.05,0:13:05.80,Default,,0,0,0,,首先 因为我需要A和B Dialogue: 0,0:13:06.32,0:13:08.57,Default,,0,0,0,,但首先 -- 虽然并不是必要的 Dialogue: 0,0:13:08.65,0:13:09.72,Default,,0,0,0,,我需要先把它们收集起来 Dialogue: 0,0:13:11.07,0:13:12.62,Default,,0,0,0,,这里的值要送入到B中 Dialogue: 0,0:13:13.24,0:13:14.03,Default,,0,0,0,,因此 我会说 Dialogue: 0,0:13:14.28,0:13:16.27,Default,,0,0,0,,用A和B的值来计算这个 Dialogue: 0,0:13:16.36,0:13:18.67,Default,,0,0,0,,并把算得的余数放到这里 Dialogue: 0,0:13:19.15,0:13:20.33,Default,,0,0,0,,因此 我首先要按下这个按钮 Dialogue: 0,0:13:21.53,0:13:24.43,Default,,0,0,0,,然后我要把B的值送入A Dialogue: 0,0:13:24.44,0:13:25.60,Default,,0,0,0,,通过按这个钮来实现 Dialogue: 0,0:13:25.82,0:13:27.63,Default,,0,0,0,,然后我再把临时值送入B Dialogue: 0,0:13:28.76,0:13:29.42,Default,,0,0,0,,通过这个按钮实现 Dialogue: 0,0:13:32.03,0:13:34.97,Default,,0,0,0,,这是一个相当时序化的机器 Dialogue: 0,0:13:35.39,0:13:36.52,Default,,0,0,0,,它非常的低效 Dialogue: 0,0:13:37.75,0:13:39.05,Default,,0,0,0,,但目前来说还好 Dialogue: 0,0:13:39.81,0:13:40.97,Default,,0,0,0,,我们来为按钮命名 Dialogue: 0,0:13:41.47,0:13:42.72,Default,,0,0,0,,T←R Dialogue: 0,0:13:46.75,0:13:48.73,Default,,0,0,0,,A←B Dialogue: 0,0:13:50.03,0:13:54.81,Default,,0,0,0,,B←T Dialogue: 0,0:13:55.47,0:13:57.63,Default,,0,0,0,,然后我要来到这里 Dialogue: 0,0:13:58.78,0:13:59.88,Default,,0,0,0,,也就是回到开始的地方 Dialogue: 0,0:14:01.62,0:14:03.87,Default,,0,0,0,,在这里 我们看到了什么? Dialogue: 0,0:14:03.87,0:14:04.91,Default,,0,0,0,,我们看到各种各样的 -- Dialogue: 0,0:14:05.05,0:14:07.16,Default,,0,0,0,,我们真正拥有的是某种机械连接 Dialogue: 0,0:14:07.42,0:14:13.63,Default,,0,0,0,,其中T←R控制了这个东西 Dialogue: 0,0:14:16.83,0:14:21.48,Default,,0,0,0,,A←B控制了这个东西 Dialogue: 0,0:14:26.96,0:14:28.12,Default,,0,0,0,,而这里的这个东西 Dialogue: 0,0:14:28.12,0:14:31.08,Default,,0,0,0,,同学们 这简直太恶劣了 Dialogue: 0,0:14:31.48,0:14:32.48,Default,,0,0,0,,一点也没有优化 Dialogue: 0,0:14:32.63,0:14:34.59,Default,,0,0,0,,我画的所有线条都相互交叉 Dialogue: 0,0:14:38.54,0:14:41.15,Default,,0,0,0,,我想B←T控制的是这个 Dialogue: 0,0:14:45.69,0:14:47.95,Default,,0,0,0,,现在 我就要运行这台机器了 Dialogue: 0,0:14:48.04,0:14:49.34,Default,,0,0,0,,但是在我运行它之前 Dialogue: 0,0:14:49.37,0:14:51.40,Default,,0,0,0,,我想写下它的控制器的描述 Dialogue: 0,0:14:51.63,0:14:52.81,Default,,0,0,0,,以便使你们相信 Dialogue: 0,0:14:52.84,0:14:55.63,Default,,0,0,0,,这些东西可以组织成某种良好的语言 Dialogue: 0,0:14:56.08,0:14:58.08,Default,,0,0,0,,这样我们就不必总是像这样画图 Dialogue: 0,0:14:58.36,0:15:00.68,Default,,0,0,0,,图示的缺陷之一 就是占用了太多空间 Dialogue: 0,0:15:00.89,0:15:01.98,Default,,0,0,0,,对于这样的一个小型机器来说 Dialogue: 0,0:15:02.00,0:15:03.05,Default,,0,0,0,,它占用了两块黑板 Dialogue: 0,0:15:03.22,0:15:05.24,Default,,0,0,0,,而一台求值器机器 Dialogue: 0,0:15:05.40,0:15:07.10,Default,,0,0,0,,我就很难将它画在这间屋子里了 Dialogue: 0,0:15:07.95,0:15:09.16,Default,,0,0,0,,尽管它还不是非常大 Dialogue: 0,0:15:09.90,0:15:11.28,Default,,0,0,0,,因此我要为它构造一门小型语言 Dialogue: 0,0:15:11.29,0:15:12.51,Default,,0,0,0,,用来描述这个机器 Dialogue: 0,0:15:13.10,0:15:23.29,Default,,0,0,0,,(DEFIME-MACHINE GCD Dialogue: 0,0:15:24.42,0:15:25.66,Default,,0,0,0,,当然 一旦我们有了像这样的描述 Dialogue: 0,0:15:25.68,0:15:26.83,Default,,0,0,0,,我们就能够模拟该机器 Dialogue: 0,0:15:27.22,0:15:29.42,Default,,0,0,0,,我之所以想构建这种形式的语言 Dialogue: 0,0:15:29.56,0:15:32.94,Default,,0,0,0,,是因为我们能够立即操纵这些表达式 Dialogue: 0,0:15:33.21,0:15:34.91,Default,,0,0,0,,因此 我也就能够 Dialogue: 0,0:15:35.29,0:15:38.16,Default,,0,0,0,,代数地操作 或者模拟这些东西 Dialogue: 0,0:15:38.20,0:15:39.96,Default,,0,0,0,,以及各种各样我想进行的操作 Dialogue: 0,0:15:40.12,0:15:42.59,Default,,0,0,0,,或者还可以把它们转换成布局图 谁知道呢? Dialogue: 0,0:15:43.63,0:15:48.38,Default,,0,0,0,,一旦我有了寄存器的良好表示 Dialogue: 0,0:15:48.51,0:15:49.61,Default,,0,0,0,,它有一些寄存器 Dialogue: 0,0:15:53.00,0:15:55.64,Default,,0,0,0,,记作(REGISTERS A B T) Dialogue: 0,0:15:56.75,0:15:57.80,Default,,0,0,0,,它还有控制器 Dialogue: 0,0:16:02.19,0:16:04.46,Default,,0,0,0,,实际上 更好的做法是让它更显式一些 Dialogue: 0,0:16:04.49,0:16:06.97,Default,,0,0,0,,也就是说 为每一个按钮命名 Dialogue: 0,0:16:08.14,0:16:10.17,Default,,0,0,0,,并指明它们的操作 Dialogue: 0,0:16:10.42,0:16:11.37,Default,,0,0,0,,比如说这个按钮 Dialogue: 0,0:16:11.55,0:16:14.19,Default,,0,0,0,,会让T的值送入到B中 Dialogue: 0,0:16:15.10,0:16:16.09,Default,,0,0,0,,但我却不想这么做 Dialogue: 0,0:16:16.11,0:16:17.95,Default,,0,0,0,,因为这样会让代码难以阅读 Dialogue: 0,0:16:18.20,0:16:19.34,Default,,0,0,0,,也会占用更多空间 Dialogue: 0,0:16:19.51,0:16:22.36,Default,,0,0,0,,所以我会把相关的指令写在控制器中 Dialogue: 0,0:16:23.29,0:16:25.24,Default,,0,0,0,,这样就隐式地指明了具体的操作 Dialogue: 0,0:16:26.32,0:16:28.57,Default,,0,0,0,,可以通过阅读代码推断出来 Dialogue: 0,0:16:29.16,0:16:31.39,Default,,0,0,0,,并收集所有可以完成的不同事情 Dialogue: 0,0:16:31.69,0:16:33.50,Default,,0,0,0,,我们来看一看 Dialogue: 0,0:16:33.50,0:16:34.70,Default,,0,0,0,,我们来看下这些东西是什么吧 Dialogue: 0,0:16:35.71,0:16:37.29,Default,,0,0,0,,首先是一个循环 Dialogue: 0,0:16:38.24,0:16:40.20,Default,,0,0,0,,先是一条分支指令 Dialogue: 0,0:16:42.64,0:16:46.46,Default,,0,0,0,,这个就对应了机器中的小挡板 Dialogue: 0,0:16:46.89,0:16:48.49,Default,,0,0,0,,它决定了你在此处的走向 Dialogue: 0,0:16:49.10,0:16:58.00,Default,,0,0,0,,判断 -- 取B的值 并判断是否为0 Dialogue: 0,0:16:58.65,0:17:00.06,Default,,0,0,0,,如果B的值是0 Dialogue: 0,0:17:00.32,0:17:01.72,Default,,0,0,0,,那么就跳转到一个叫DONE的地方 Dialogue: 0,0:17:03.64,0:17:05.29,Default,,0,0,0,,现在 你们在这里看到的是 Dialogue: 0,0:17:05.29,0:17:07.40,Default,,0,0,0,,这个看起来非常像传统计算机语言 Dialogue: 0,0:17:08.17,0:17:09.55,Default,,0,0,0,,但你们所见的是 Dialogue: 0,0:17:10.03,0:17:12.00,Default,,0,0,0,,一些个标签 Dialogue: 0,0:17:12.99,0:17:16.86,Default,,0,0,0,,它们代表着存放了一系列指令的地方 Dialogue: 0,0:17:17.60,0:17:18.94,Default,,0,0,0,,之所以需要它们 Dialogue: 0,0:17:19.48,0:17:21.15,Default,,0,0,0,,是因为在这里 Dialogue: 0,0:17:21.45,0:17:22.81,Default,,0,0,0,,我表达了“循环”的概念 Dialogue: 0,0:17:23.32,0:17:26.11,Default,,0,0,0,,但是如果我是在写英文之类的文本 Dialogue: 0,0:17:26.44,0:17:28.09,Default,,0,0,0,,就很难去引用一个位置 Dialogue: 0,0:17:28.58,0:17:29.53,Default,,0,0,0,,我没有箭头 Dialogue: 0,0:17:30.80,0:17:33.02,Default,,0,0,0,,箭头是通过 Dialogue: 0,0:17:33.05,0:17:34.44,Default,,0,0,0,,给箭头所指的地方命名来表示的 Dialogue: 0,0:17:34.57,0:17:36.28,Default,,0,0,0,,并通过名字来引用 Dialogue: 0,0:17:37.40,0:17:38.59,Default,,0,0,0,,这只是一种编码 Dialogue: 0,0:17:39.86,0:17:41.88,Default,,0,0,0,,而不是某种魔法 Dialogue: 0,0:17:43.15,0:17:44.96,Default,,0,0,0,,接下来我们要做的是 Dialogue: 0,0:17:45.02,0:17:46.84,Default,,0,0,0,,我们如何来实现T←R Dialogue: 0,0:17:47.45,0:17:49.76,Default,,0,0,0,,非常简单 用ASSIGN Dialogue: 0,0:17:52.19,0:17:55.55,Default,,0,0,0,,我们把余数赋值给T Dialogue: 0,0:17:56.32,0:17:59.24,Default,,0,0,0,,ASSIGN就是按钮的名字 Dialogue: 0,0:18:01.47,0:18:02.64,Default,,0,0,0,,就是按按钮的家伙 Dialogue: 0,0:18:03.14,0:18:04.97,Default,,0,0,0,,把余数赋给T Dialogue: 0,0:18:04.99,0:18:06.76,Default,,0,0,0,,这个操作是这样表示的 Dialogue: 0,0:18:11.74,0:18:17.53,Default,,0,0,0,,取A、B的值 相除得到余数 Dialogue: 0,0:18:23.85,0:18:30.99,Default,,0,0,0,,同时 我们也要取B的值 赋给A Dialogue: 0,0:18:34.99,0:18:47.88,Default,,0,0,0,,再取T的值赋给B Dialogue: 0,0:18:49.61,0:18:51.85,Default,,0,0,0,,现在 我需要引用这个开头 Dialogue: 0,0:18:53.18,0:18:55.92,Default,,0,0,0,,呃 我为什么不把这里叫做LOOP呢? Dialogue: 0,0:19:04.09,0:19:07.04,Default,,0,0,0,,这就是如何引用这个箭头 Dialogue: 0,0:19:07.61,0:19:08.95,Default,,0,0,0,,当执行到DONE时 就完成了所有操作 Dialogue: 0,0:19:09.02,0:19:13.07,Default,,0,0,0,,我们来到了这里 所有指令的结尾 Dialogue: 0,0:19:15.26,0:19:17.04,Default,,0,0,0,,这段文字化描述的就是 Dialogue: 0,0:19:17.69,0:19:20.86,Default,,0,0,0,,我们在这里画的一小部分机器 Dialogue: 0,0:19:21.66,0:19:24.84,Default,,0,0,0,,下面 我就要运行它 Dialogue: 0,0:19:25.49,0:19:26.65,Default,,0,0,0,,我想让你们感受一下它的运行 Dialogue: 0,0:19:27.62,0:19:29.80,Default,,0,0,0,,从来没有做过这个 你必须做一次 Dialogue: 0,0:19:31.01,0:19:32.62,Default,,0,0,0,,让我们以一个具体的问题来演示 Dialogue: 0,0:19:33.10,0:19:34.70,Default,,0,0,0,,假设我们想要计算 Dialogue: 0,0:19:35.04,0:19:40.68,Default,,0,0,0,,30和42的最大公约数 Dialogue: 0,0:19:42.21,0:19:44.92,Default,,0,0,0,,我现在不知道结果是多少 Dialogue: 0,0:19:45.86,0:19:47.60,Default,,0,0,0,,但我知道A=30而B=42 Dialogue: 0,0:19:50.96,0:19:52.09,Default,,0,0,0,,我就这么着开始 Dialogue: 0,0:19:52.60,0:19:53.90,Default,,0,0,0,,那么 我首先要做些什么呢? Dialogue: 0,0:19:54.24,0:19:56.86,Default,,0,0,0,,我先判断B是否为0:否 Dialogue: 0,0:19:57.59,0:20:02.11,Default,,0,0,0,,然后计算A除B的余数 并赋给T Dialogue: 0,0:20:02.80,0:20:07.60,Default,,0,0,0,,当然 30除以42的余数就是30自己 Dialogue: 0,0:20:11.13,0:20:12.03,Default,,0,0,0,,按下那个按钮 Dialogue: 0,0:20:12.92,0:20:15.10,Default,,0,0,0,,现在弹珠就滚动到了这里 Dialogue: 0,0:20:17.10,0:20:18.06,Default,,0,0,0,,A←B Dialogue: 0,0:20:19.02,0:20:20.76,Default,,0,0,0,,又按下了这个按钮 Dialogue: 0,0:20:21.22,0:20:22.54,Default,,0,0,0,,因此42来到了这里 Dialogue: 0,0:20:26.59,0:20:27.60,Default,,0,0,0,,B←T Dialogue: 0,0:20:28.36,0:20:29.34,Default,,0,0,0,,按下了这个按钮 Dialogue: 0,0:20:29.87,0:20:30.96,Default,,0,0,0,,30来到了这里 Dialogue: 0,0:20:32.57,0:20:33.69,Default,,0,0,0,,这样我就交换了它们 Dialogue: 0,0:20:34.66,0:20:38.27,Default,,0,0,0,,我们再来看看 回到开始 Dialogue: 0,0:20:38.64,0:20:39.72,Default,,0,0,0,,B为0么?不 Dialogue: 0,0:20:40.19,0:20:41.50,Default,,0,0,0,,将余数赋给T Dialogue: 0,0:20:43.23,0:20:46.30,Default,,0,0,0,,我想 42除以30的余数是12 Dialogue: 0,0:20:47.24,0:20:48.30,Default,,0,0,0,,按下这个钮 Dialogue: 0,0:20:48.53,0:20:51.40,Default,,0,0,0,,下面 我想让30来到这里 Dialogue: 0,0:20:53.90,0:20:55.95,Default,,0,0,0,,按下这个钮 让12来到这里 Dialogue: 0,0:20:58.41,0:21:00.38,Default,,0,0,0,,然后继续 Dialogue: 0,0:21:00.38,0:21:01.31,Default,,0,0,0,,程序执行完了么? Dialogue: 0,0:21:01.53,0:21:02.12,Default,,0,0,0,,并没有 Dialogue: 0,0:21:02.36,0:21:08.22,Default,,0,0,0,,现在 我需要求解30除以12的余数 Dialogue: 0,0:21:08.85,0:21:10.67,Default,,0,0,0,,我想答案是6 Dialogue: 0,0:21:12.42,0:21:15.13,Default,,0,0,0,,按下这个钮 6就到了这里 Dialogue: 0,0:21:16.20,0:21:18.25,Default,,0,0,0,,然后我又按下这个钮 Dialogue: 0,0:21:18.30,0:21:19.61,Default,,0,0,0,,这就让12来到了这里 Dialogue: 0,0:21:23.73,0:21:25.09,Default,,0,0,0,,然后我又按下这个按钮 Dialogue: 0,0:21:25.09,0:21:26.00,Default,,0,0,0,,6就来到了这里 Dialogue: 0,0:21:29.85,0:21:31.68,Default,,0,0,0,,6等于0么? Dialogue: 0,0:21:31.88,0:21:32.49,Default,,0,0,0,,不等于 Dialogue: 0,0:21:33.42,0:21:33.98,Default,,0,0,0,,好的 Dialogue: 0,0:21:34.38,0:21:36.80,Default,,0,0,0,,因此这时 Dialogue: 0,0:21:36.89,0:21:38.12,Default,,0,0,0,,接下来又要计算余数 Dialogue: 0,0:21:38.14,0:21:39.80,Default,,0,0,0,,哦 这个的余数是0 Dialogue: 0,0:21:40.66,0:21:41.74,Default,,0,0,0,,看起来我们就快完成了 Dialogue: 0,0:21:42.36,0:21:44.36,Default,,0,0,0,,将6从这里挪到这里 Dialogue: 0,0:21:47.00,0:21:48.27,Default,,0,0,0,,0移动到这里 Dialogue: 0,0:21:49.09,0:21:50.20,Default,,0,0,0,,0等于0么? Dialogue: 0,0:21:50.20,0:21:50.73,Default,,0,0,0,,是的 Dialogue: 0,0:21:51.34,0:21:53.36,Default,,0,0,0,,B的值等于0 因此答案就是A的值 Dialogue: 0,0:21:54.28,0:21:55.76,Default,,0,0,0,,因此答案就是6 Dialogue: 0,0:21:56.61,0:21:57.61,Default,,0,0,0,,这确实是正确的答案 Dialogue: 0,0:21:57.63,0:21:59.47,Default,,0,0,0,,因为如果我们回过头审视最初的问题 Dialogue: 0,0:22:00.08,0:22:06.64,Default,,0,0,0,,我们知道30=2×3×5 Dialogue: 0,0:22:07.00,0:22:11.12,Default,,0,0,0,,42=2×3×7 Dialogue: 0,0:22:11.67,0:22:14.11,Default,,0,0,0,,因此最大公约数就是2×3 Dialogue: 0,0:22:14.20,0:22:15.08,Default,,0,0,0,,也就是6 Dialogue: 0,0:22:18.38,0:22:20.56,Default,,0,0,0,,我们通常在这里画另外一条线 Dialogue: 0,0:22:20.59,0:22:22.52,Default,,0,0,0,,为了使它更清晰一点 Dialogue: 0,0:22:22.89,0:22:27.71,Default,,0,0,0,,在这两者之间建立了联系 Dialogue: 0,0:22:27.85,0:22:31.01,Default,,0,0,0,,小挡板需要根据这个指示灯来工作 Dialogue: 0,0:22:34.00,0:22:37.32,Default,,0,0,0,,当然 跟我给你们展示的东西相比 Dialogue: 0,0:22:37.85,0:22:40.00,Default,,0,0,0,,真实计算机的组件更加复杂 Dialogue: 0,0:22:41.35,0:22:47.16,Default,,0,0,0,,让我们来看看第一张幻灯片 Dialogue: 0,0:22:47.98,0:22:48.81,Default,,0,0,0,,哇 Dialogue: 0,0:22:50.19,0:22:52.43,Default,,0,0,0,,我们看到 我们想要做的就是 Dialogue: 0,0:22:52.65,0:22:55.85,Default,,0,0,0,,IO形式的操作 Dialogue: 0,0:22:56.84,0:23:01.42,Default,,0,0,0,,我们需要从外部搜集一些东西 Dialogue: 0,0:23:01.98,0:23:03.93,Default,,0,0,0,,因此 对我们的状态机器来说 Dialogue: 0,0:23:04.30,0:23:07.02,Default,,0,0,0,,它们的控制器 Dialogue: 0,0:23:07.26,0:23:10.56,Default,,0,0,0,,可能会从某处取得某值 Dialogue: 0,0:23:10.78,0:23:12.41,Default,,0,0,0,,将它们放入寄存器并从中读取 Dialogue: 0,0:23:13.49,0:23:15.92,Default,,0,0,0,,我还可以把另外的值加载到寄存器B中 Dialogue: 0,0:23:17.07,0:23:18.60,Default,,0,0,0,,稍后 当执行完毕后 Dialogue: 0,0:23:18.99,0:23:20.52,Default,,0,0,0,,我想要输出结果 Dialogue: 0,0:23:21.20,0:23:25.23,Default,,0,0,0,,当然 答案或简单或复杂 Dialogue: 0,0:23:26.09,0:23:28.03,Default,,0,0,0,,我写代码的时候 总假设PRINT很简单 Dialogue: 0,0:23:28.09,0:23:29.29,Default,,0,0,0,,READ也很简单 Dialogue: 0,0:23:29.88,0:23:31.08,Default,,0,0,0,,但实际上 在真实世界中 Dialogue: 0,0:23:31.12,0:23:32.89,Default,,0,0,0,,这些都是非常复杂的操作 Dialogue: 0,0:23:33.08,0:23:35.52,Default,,0,0,0,,跟你尝试求解的问题相比 Dialogue: 0,0:23:35.55,0:23:38.33,Default,,0,0,0,,它们通常更加庞大而复杂 Dialogue: 0,0:23:41.67,0:23:43.90,Default,,0,0,0,,另一方面 我犹记得 Dialogue: 0,0:23:44.89,0:23:48.78,Default,,0,0,0,,使用IBM 7090一类的计算机的时候 Dialogue: 0,0:23:49.05,0:23:53.04,Default,,0,0,0,,它的READ和WRITE只能操作单个对象 Dialogue: 0,0:23:53.08,0:23:54.62,Default,,0,0,0,,也就是一个数字 Dialogue: 0,0:23:55.84,0:23:58.54,Default,,0,0,0,,这就是一个基本的IO操作 Dialogue: 0,0:23:59.63,0:24:02.04,Default,,0,0,0,,我们这里有同样的操作 Dialogue: 0,0:24:02.33,0:24:04.67,Default,,0,0,0,,在这样的一台机器中 Dialogue: 0,0:24:05.44,0:24:06.89,Default,,0,0,0,,我们实际上在做什么? Dialogue: 0,0:24:07.12,0:24:11.60,Default,,0,0,0,,我们看到 这个叫做“READ”的组件是数据源头 Dialogue: 0,0:24:12.20,0:24:14.46,Default,,0,0,0,,这个操作总是返回一个值 Dialogue: 0,0:24:14.66,0:24:17.13,Default,,0,0,0,,我们可以把它看做 总是返回一个值 Dialogue: 0,0:24:17.21,0:24:19.84,Default,,0,0,0,,它可以赋给寄存器A或B Dialogue: 0,0:24:21.66,0:24:23.23,Default,,0,0,0,,而PRINT这个过程呢 Dialogue: 0,0:24:23.37,0:24:25.02,Default,,0,0,0,,当你正确连接它的时候 Dialogue: 0,0:24:25.24,0:24:26.43,Default,,0,0,0,,当你按下上面的按钮 Dialogue: 0,0:24:26.65,0:24:29.61,Default,,0,0,0,,就会打印出当前寄存器A中的值 Dialogue: 0,0:24:31.66,0:24:32.73,Default,,0,0,0,,这非常普通 Dialogue: 0,0:24:33.32,0:24:35.20,Default,,0,0,0,,这是我们想要的一种功能 Dialogue: 0,0:24:35.88,0:24:38.32,Default,,0,0,0,,但这里还有些其它事情需要我们担忧 Dialogue: 0,0:24:38.32,0:24:40.67,Default,,0,0,0,,比如说 这里我使用了一些复杂的机制 Dialogue: 0,0:24:41.05,0:24:42.48,Default,,0,0,0,,我们这里有REMAINDER组件 Dialogue: 0,0:24:43.85,0:24:44.44,Default,,0,0,0,,这是个什么东西呢? Dialogue: 0,0:24:44.69,0:24:46.41,Default,,0,0,0,,求取余数的计算过程并不是那么“显然” Dialogue: 0,0:24:46.92,0:24:48.92,Default,,0,0,0,,如果我们把这个组件给拆开 Dialogue: 0,0:24:49.48,0:24:50.62,Default,,0,0,0,,就会得到一整台机器 Dialogue: 0,0:24:51.84,0:24:53.66,Default,,0,0,0,,事实就是这样的 Dialogue: 0,0:24:54.54,0:24:59.15,Default,,0,0,0,,举例来说 如果要编程实现REMAINDER Dialogue: 0,0:24:59.44,0:25:02.44,Default,,0,0,0,,最简单的算法就是 不断地做减法 Dialogue: 0,0:25:04.78,0:25:05.95,Default,,0,0,0,,这是因为 除法可以通过 Dialogue: 0,0:25:05.96,0:25:08.99,Default,,0,0,0,,对整数不断做减法来实现 Dialogue: 0,0:25:09.80,0:25:23.58,Default,,0,0,0,,N除以D的余数不外乎就是 Dialogue: 0,0:25:24.99,0:25:31.44,Default,,0,0,0,,如果N小于D的话 Dialogue: 0,0:25:32.24,0:25:33.66,Default,,0,0,0,,答案就是N Dialogue: 0,0:25:34.30,0:25:35.90,Default,,0,0,0,,否则的话就是 Dialogue: 0,0:25:41.15,0:25:47.60,Default,,0,0,0,,N先减去D Dialogue: 0,0:25:48.27,0:25:49.32,Default,,0,0,0,,再除以D的余数 Dialogue: 0,0:25:51.28,0:25:55.05,Default,,0,0,0,,天啊 这个看起来就像是GCD程序 Dialogue: 0,0:25:56.89,0:25:59.48,Default,,0,0,0,,当然 这个不是求余数的最优算法 Dialogue: 0,0:25:59.75,0:26:00.91,Default,,0,0,0,,在实际中 你应该使用那些 Dialogue: 0,0:26:00.92,0:26:05.42,Default,,0,0,0,,二进制运算、移位运算等操作 Dialogue: 0,0:26:05.55,0:26:06.97,Default,,0,0,0,,但关键点就是 Dialogue: 0,0:26:07.13,0:26:08.48,Default,,0,0,0,,如果我把这些组件打开 Dialogue: 0,0:26:08.92,0:26:10.64,Default,,0,0,0,,我可能会发现其中有一台计算机 Dialogue: 0,0:26:11.88,0:26:12.99,Default,,0,0,0,,现在我们就知道它的原理了 Dialogue: 0,0:26:13.51,0:26:14.33,Default,,0,0,0,,因为我们就造过一台 Dialogue: 0,0:26:15.64,0:26:17.10,Default,,0,0,0,,这些个机器都大同小异 Dialogue: 0,0:26:17.40,0:26:18.06,Default,,0,0,0,,另外一方面 Dialogue: 0,0:26:18.08,0:26:20.00,Default,,0,0,0,,我们可能想要构建一台更高效 Dialogue: 0,0:26:20.01,0:26:21.68,Default,,0,0,0,,组织更精良的机器 Dialogue: 0,0:26:21.85,0:26:23.96,Default,,0,0,0,,比如说 多次利用其中的寄存器 Dialogue: 0,0:26:24.00,0:26:27.05,Default,,0,0,0,,或者是硬件设计者能想到的其它可怕混乱 Dialogue: 0,0:26:27.31,0:26:28.60,Default,,0,0,0,,等等原因 Dialogue: 0,0:26:29.25,0:26:31.56,Default,,0,0,0,,比如说 你们所见的这台机器 Dialogue: 0,0:26:32.52,0:26:34.91,Default,,0,0,0,,不是让你们去细读它的结构的 Dialogue: 0,0:26:35.05,0:26:37.52,Default,,0,0,0,,它有些复杂 对吧? Dialogue: 0,0:26:37.52,0:26:39.87,Default,,0,0,0,,但它实际上是 Dialogue: 0,0:26:40.09,0:26:43.82,Default,,0,0,0,,整合了REMAINDER的GCD机器 Dialogue: 0,0:26:44.46,0:26:46.02,Default,,0,0,0,,并且实际上 它没有多余的寄存器 Dialogue: 0,0:26:46.02,0:26:48.62,Default,,0,0,0,,数据通路上有三个寄存器 Dialogue: 0,0:26:49.05,0:26:50.64,Default,,0,0,0,,但现在 这里有个减法器 Dialogue: 0,0:26:51.55,0:26:52.99,Default,,0,0,0,,又有两个东西被测试 Dialogue: 0,0:26:53.02,0:26:55.07,Default,,0,0,0,,B等于0么? Dialogue: 0,0:26:55.23,0:26:56.56,Default,,0,0,0,,T小于B么? Dialogue: 0,0:26:57.25,0:26:59.45,Default,,0,0,0,,而至于这一块的控制器 Dialogue: 0,0:27:00.22,0:27:01.76,Default,,0,0,0,,并不会更加复杂 Dialogue: 0,0:27:01.85,0:27:03.87,Default,,0,0,0,,它有两个循环 Dialogue: 0,0:27:04.52,0:27:08.33,Default,,0,0,0,,最主要的循环是计算GCD的 Dialogue: 0,0:27:08.40,0:27:10.14,Default,,0,0,0,,而另一条是减法循环 Dialogue: 0,0:27:10.43,0:27:12.80,Default,,0,0,0,,是用来计算余数的子操作 Dialogue: 0,0:27:14.03,0:27:15.80,Default,,0,0,0,,当然 还有一种思考方式 Dialogue: 0,0:27:15.96,0:27:18.68,Default,,0,0,0,,就是把求余数程序 Dialogue: 0,0:27:19.92,0:27:21.71,Default,,0,0,0,,如果我把那边的REMAINDER机器 Dialogue: 0,0:27:21.72,0:27:22.83,Default,,0,0,0,,当作LAMBDA表达式 Dialogue: 0,0:27:23.56,0:27:27.02,Default,,0,0,0,,代换到GCD程序的REMAINDER中 Dialogue: 0,0:27:28.20,0:27:30.12,Default,,0,0,0,,然后再做一些化简 Dialogue: 0,0:27:30.32,0:27:33.66,Default,,0,0,0,,代换其中的A和B Dialogue: 0,0:27:34.46,0:27:35.95,Default,,0,0,0,,那么 我就可以展开这个循环 Dialogue: 0,0:27:36.63,0:27:39.42,Default,,0,0,0,,那么我就可以通过 Dialogue: 0,0:27:40.73,0:27:42.94,Default,,0,0,0,,LAMBDA表达式的基本代数化简 Dialogue: 0,0:27:43.36,0:27:45.21,Default,,0,0,0,,来得到这台机器 Dialogue: 0,0:27:48.55,0:27:51.20,Default,,0,0,0,,我想 你们已经见识了一个非常简单的机器了 Dialogue: 0,0:27:51.95,0:27:53.28,Default,,0,0,0,,有什么疑问么? Dialogue: 0,0:28:02.70,0:28:03.10,Default,,0,0,0,,很好 Dialogue: 0,0:28:05.36,0:28:06.54,Default,,0,0,0,,看起来很容易 难道不是吗? Dialogue: 0,0:28:10.14,0:28:11.32,Default,,0,0,0,,好吧 休息一下 谢谢大家 Dialogue: 0,0:28:12.54,0:28:24.94,Default,,0,0,0,,[音乐] Dialogue: 0,0:28:25.13,0:28:28.08,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:28:31.37,0:28:34.70,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:28:34.76,0:28:38.00,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:28:38.00,0:28:43.29,Declare,,0,0,0,,{\an2\fad(500,500)}寄存机器 Dialogue: 0,0:28:47.93,0:28:48.70,Default,,0,0,0,,教授:好吧 Dialogue: 0,0:28:49.37,0:28:52.46,Default,,0,0,0,,现在 你们已经知道如何去把迭代过程 Dialogue: 0,0:28:52.54,0:28:54.54,Default,,0,0,0,,或者是产生迭代计算的过程 Dialogue: 0,0:28:55.18,0:28:56.52,Default,,0,0,0,,变成一台机器 Dialogue: 0,0:28:57.77,0:29:00.04,Default,,0,0,0,,我想 接下来我们就应该考虑 Dialogue: 0,0:29:00.54,0:29:02.30,Default,,0,0,0,,如何来处理递归过程了 Dialogue: 0,0:29:02.81,0:29:05.05,Default,,0,0,0,,我们先从一个简单的阶乘过程开始 Dialogue: 0,0:29:11.20,0:29:16.94,Default,,0,0,0,,(DEFINE (FACT N) Dialogue: 0,0:29:19.63,0:29:24.25,Default,,0,0,0,,如果N=1 那么结果就是1 Dialogue: 0,0:29:24.62,0:29:27.69,Default,,0,0,0,,为了减少模拟它的工作量 我就使用1 Dialogue: 0,0:29:28.12,0:29:33.94,Default,,0,0,0,,否则结果就是(* N (FACT (- N 1))) Dialogue: 0,0:29:42.52,0:29:46.04,Default,,0,0,0,,正如你们所知 这个程序的不同之处在于 Dialogue: 0,0:29:46.65,0:29:50.36,Default,,0,0,0,,这里 我在计算(FACT (- N 1))之后 Dialogue: 0,0:29:50.67,0:29:52.26,Default,,0,0,0,,我要对结果做一些运算 Dialogue: 0,0:29:52.26,0:29:53.68,Default,,0,0,0,,我要将它与N相乘 Dialogue: 0,0:29:56.00,0:30:00.67,Default,,0,0,0,,将这台机器可视化的唯一途径就是 Dialogue: 0,0:30:01.08,0:30:02.01,Default,,0,0,0,,首先 由于-- Dialogue: 0,0:30:02.35,0:30:03.18,Default,,0,0,0,,请你们这么来想 Dialogue: 0,0:30:03.36,0:30:04.94,Default,,0,0,0,,这里 我有一台机器 Dialogue: 0,0:30:05.08,0:30:08.11,Default,,0,0,0,,而这台机器又需要某个阶乘机器来计算结果 Dialogue: 0,0:30:09.32,0:30:11.16,Default,,0,0,0,,但外面的这台机器 Dialogue: 0,0:30:11.20,0:30:13.02,Default,,0,0,0,,又需要在调用内部阶乘机器 Dialogue: 0,0:30:13.92,0:30:15.72,Default,,0,0,0,,的前后都要存在 Dialogue: 0,0:30:16.80,0:30:17.90,Default,,0,0,0,,然而在迭代情况中 Dialogue: 0,0:30:18.75,0:30:20.52,Default,,0,0,0,,外面的机器不需要 Dialogue: 0,0:30:20.91,0:30:24.01,Default,,0,0,0,,在内部机器运行后保持存在 Dialogue: 0,0:30:24.83,0:30:26.16,Default,,0,0,0,,这是因为你不需要回到 Dialogue: 0,0:30:26.19,0:30:27.53,Default,,0,0,0,,外部机器来进行其它操作 Dialogue: 0,0:30:28.64,0:30:30.06,Default,,0,0,0,,因此 我们这里的问题是 Dialogue: 0,0:30:30.27,0:30:30.97,Default,,0,0,0,,我们的机器内部 Dialogue: 0,0:30:31.00,0:30:32.73,Default,,0,0,0,,有一个同样的机器 Dialogue: 0,0:30:33.87,0:30:35.52,Default,,0,0,0,,一台无穷大的机器 Dialogue: 0,0:30:40.39,0:30:43.12,Default,,0,0,0,,这里面也有其它的东西 比如乘法器 Dialogue: 0,0:30:44.76,0:30:46.03,Default,,0,0,0,,它接收输入 Dialogue: 0,0:30:46.27,0:30:47.77,Default,,0,0,0,,这是-1操作 Dialogue: 0,0:30:48.12,0:30:49.31,Default,,0,0,0,,等等 Dialogue: 0,0:30:50.69,0:30:53.72,Default,,0,0,0,,你们可以想象 -- 它就是这个样子的 Dialogue: 0,0:30:54.37,0:30:56.76,Default,,0,0,0,,但重要之处就在于 Dialogue: 0,0:30:57.02,0:30:58.70,Default,,0,0,0,,内部机器执行之前与执行之后 Dialogue: 0,0:30:58.78,0:31:01.60,Default,,0,0,0,,外部机器中都进行了一些运算 Dialogue: 0,0:31:02.54,0:31:04.08,Default,,0,0,0,,因此这台机器必须有“生命” Dialogue: 0,0:31:05.47,0:31:11.44,Default,,0,0,0,,外部机器需要在内部机器的两个时间点保持存在 Dialogue: 0,0:31:13.49,0:31:15.80,Default,,0,0,0,,因此 我就需要有一个地方来保存 Dialogue: 0,0:31:16.19,0:31:18.19,Default,,0,0,0,,维持外部机器运转的数据 Dialogue: 0,0:31:20.03,0:31:22.09,Default,,0,0,0,,现实世界中不存在无穷的对象 Dialogue: 0,0:31:24.14,0:31:25.58,Default,,0,0,0,,我们要做的就是营造一种假象 Dialogue: 0,0:31:26.12,0:31:27.48,Default,,0,0,0,,一种无穷对象的假象 Dialogue: 0,0:31:27.98,0:31:29.77,Default,,0,0,0,,我们在某处有无穷的硬件资源 Dialogue: 0,0:31:31.83,0:31:35.34,Default,,0,0,0,,现在 这个假象非常重要 Dialogue: 0,0:31:36.28,0:31:37.37,Default,,0,0,0,,如果我们能保证 Dialogue: 0,0:31:38.00,0:31:39.84,Default,,0,0,0,,每次当你查看某个无穷对象时 Dialogue: 0,0:31:39.88,0:31:42.96,Default,,0,0,0,,你所要观察的那部分存在 Dialogue: 0,0:31:44.49,0:31:46.04,Default,,0,0,0,,那么就不需要实际上的“无穷” Dialogue: 0,0:31:47.39,0:31:49.44,Default,,0,0,0,,当然 这里面我们想做的就是 Dialogue: 0,0:31:49.82,0:31:52.49,Default,,0,0,0,,来看下这里的东西 Dialogue: 0,0:31:53.00,0:31:54.97,Default,,0,0,0,,这是我们目前为止的结构 Dialogue: 0,0:31:56.04,0:31:57.64,Default,,0,0,0,,这些结构呢 Dialogue: 0,0:31:57.92,0:32:01.37,Default,,0,0,0,,是机器的几大部分 Dialogue: 0,0:32:01.40,0:32:02.33,Default,,0,0,0,,比如控制器 Dialogue: 0,0:32:03.18,0:32:04.46,Default,,0,0,0,,它在这里 Dialogue: 0,0:32:04.78,0:32:07.61,Default,,0,0,0,,它相当简单 并且是有穷的 Dialogue: 0,0:32:09.17,0:32:10.44,Default,,0,0,0,,我们还有数据通路 Dialogue: 0,0:32:10.46,0:32:12.75,Default,,0,0,0,,它由寄存器和运算器组成 Dialogue: 0,0:32:13.08,0:32:15.20,Default,,0,0,0,,现在我提议 Dialogue: 0,0:32:15.48,0:32:16.96,Default,,0,0,0,,把机器分成两部分 Dialogue: 0,0:32:17.36,0:32:19.79,Default,,0,0,0,,这样 其中一部分全部是有穷的 Dialogue: 0,0:32:20.78,0:32:23.53,Default,,0,0,0,,而另一部分 可以保存无穷数据中的一部分 Dialogue: 0,0:32:24.23,0:32:25.90,Default,,0,0,0,,换句话说 这部分也非常简单 Dialogue: 0,0:32:26.41,0:32:28.72,Default,,0,0,0,,但并非无穷 只是非常大而已 Dialogue: 0,0:32:29.43,0:32:30.40,Default,,0,0,0,,但它非常简单 Dialogue: 0,0:32:30.52,0:32:32.92,Default,,0,0,0,,以至于能够廉价地大量生产 Dialogue: 0,0:32:34.09,0:32:34.92,Default,,0,0,0,,它就是内存 Dialogue: 0,0:32:35.95,0:32:39.07,Default,,0,0,0,,我们可以利用它来构造栈结构 Dialogue: 0,0:32:39.40,0:32:41.23,Default,,0,0,0,,事实上 这就使得我们 Dialogue: 0,0:32:41.45,0:32:43.63,Default,,0,0,0,,能够模拟无穷机器的存在 Dialogue: 0,0:32:43.64,0:32:46.96,Default,,0,0,0,,也就是那些递归嵌套的机器 Dialogue: 0,0:32:48.34,0:32:50.43,Default,,0,0,0,,而它的原理则是 Dialogue: 0,0:32:50.56,0:32:52.97,Default,,0,0,0,,我们要在栈上存放必要的信息 Dialogue: 0,0:32:54.30,0:32:57.58,Default,,0,0,0,,用于内部机器执行完毕后 Dialogue: 0,0:32:59.18,0:33:01.07,Default,,0,0,0,,继续外部机器的操作 Dialogue: 0,0:33:03.84,0:33:05.48,Default,,0,0,0,,因此它会记住 Dialogue: 0,0:33:05.63,0:33:07.95,Default,,0,0,0,,关于外部机器生命期的重要数据 Dialogue: 0,0:33:08.04,0:33:10.30,Default,,0,0,0,,这些是进行计算所必需的 Dialogue: 0,0:33:11.39,0:33:12.48,Default,,0,0,0,,当然 Dialogue: 0,0:33:12.75,0:33:16.33,Default,,0,0,0,,由于这些机器是通过递归的方式嵌套的 Dialogue: 0,0:33:18.33,0:33:23.39,Default,,0,0,0,,因此 栈的存取方式也会是 Dialogue: 0,0:33:23.45,0:33:26.44,Default,,0,0,0,,也会是后进先出的 Dialogue: 0,0:33:29.33,0:33:30.64,Default,,0,0,0,,因此我们只需要存取 Dialogue: 0,0:33:30.80,0:33:32.52,Default,,0,0,0,,这个栈内存的一小部分 Dialogue: 0,0:33:34.93,0:33:35.92,Default,,0,0,0,,好吧 让我们来试一试 Dialogue: 0,0:33:36.81,0:33:38.41,Default,,0,0,0,,我已经给你们画好了数据通路 Dialogue: 0,0:33:38.44,0:33:39.68,Default,,0,0,0,,现在该布置控制器了 Dialogue: 0,0:33:40.37,0:33:42.86,Default,,0,0,0,,然后我们来运行一下 观察实际工作原理 Dialogue: 0,0:33:43.51,0:33:46.88,Default,,0,0,0,,还好阶乘机器不是特别的复杂 Dialogue: 0,0:33:47.90,0:33:50.16,Default,,0,0,0,,它有一个VAL寄存器 Dialogue: 0,0:33:52.22,0:33:53.88,Default,,0,0,0,,这是用来存储答案的 Dialogue: 0,0:33:54.89,0:33:56.67,Default,,0,0,0,,还有一个寄存器N Dialogue: 0,0:33:59.85,0:34:04.16,Default,,0,0,0,,它里面存储的是要计算阶乘的数 Dialogue: 0,0:34:04.51,0:34:06.57,Default,,0,0,0,,为了满足某些情况 Dialogue: 0,0:34:07.48,0:34:10.52,Default,,0,0,0,,我们要连接VAL和N Dialogue: 0,0:34:11.74,0:34:15.63,Default,,0,0,0,,事实上 如果我在这里返回N Dialogue: 0,0:34:16.38,0:34:19.53,Default,,0,0,0,,也是正确的 因为这时N就等于1 Dialogue: 0,0:34:20.09,0:34:23.26,Default,,0,0,0,,这样的话 我就可以把结果移动过去 Dialogue: 0,0:34:23.90,0:34:25.55,Default,,0,0,0,,但我现在不考虑这个问题 Dialogue: 0,0:34:26.98,0:34:28.60,Default,,0,0,0,,我还需要做一些事情 Dialogue: 0,0:34:29.06,0:34:31.02,Default,,0,0,0,,就像我们在这里看到的 我们还需要 Dialogue: 0,0:34:31.21,0:34:34.67,Default,,0,0,0,,用VAL的值乘以N Dialogue: 0,0:34:34.91,0:34:37.45,Default,,0,0,0,,因为VAL是计算阶乘的结果 Dialogue: 0,0:34:38.68,0:34:40.44,Default,,0,0,0,,我需要把算得的结果送回VAL Dialogue: 0,0:34:41.48,0:34:42.65,Default,,0,0,0,,所以这里我们看到 Dialogue: 0,0:34:42.83,0:34:46.43,Default,,0,0,0,,N的阶乘就是 Dialogue: 0,0:34:46.57,0:34:49.20,Default,,0,0,0,,N乘以某个阶乘 Dialogue: 0,0:34:50.69,0:34:53.77,Default,,0,0,0,,而VAL就代表了内部阶乘的结果 Dialogue: 0,0:34:55.19,0:35:00.25,Default,,0,0,0,,因此 在这里我需要有一个乘法器 Dialogue: 0,0:35:02.36,0:35:07.18,Default,,0,0,0,,它的参数有:N以及VAL Dialogue: 0,0:35:08.64,0:35:15.60,Default,,0,0,0,,并且 像这样把计算结果送回VAL Dialogue: 0,0:35:17.17,0:35:19.39,Default,,0,0,0,,我也需要知道N是否为1 Dialogue: 0,0:35:21.32,0:35:22.38,Default,,0,0,0,,因此我需要一个指示灯 Dialogue: 0,0:35:28.20,0:35:30.40,Default,,0,0,0,,另外 我想我还需要 Dialogue: 0,0:35:31.02,0:35:32.84,Default,,0,0,0,,一个组件来减小N Dialogue: 0,0:35:34.84,0:35:36.09,Default,,0,0,0,,所以这里有一个递减器 Dialogue: 0,0:35:38.19,0:35:41.39,Default,,0,0,0,,它接收参数N 将结果送回N Dialogue: 0,0:35:46.62,0:35:48.40,Default,,0,0,0,,这基本上就是我的机器所需要的东西了 Dialogue: 0,0:35:49.55,0:35:51.64,Default,,0,0,0,,然而 我还需要一些个东西 Dialogue: 0,0:35:52.30,0:35:53.58,Default,,0,0,0,,一个稍微复杂一点的东西 Dialogue: 0,0:35:55.16,0:35:56.88,Default,,0,0,0,,因为我需要有一种方式能够存储 Dialogue: 0,0:35:57.16,0:35:59.69,Default,,0,0,0,,必要的一些信息 Dialogue: 0,0:36:01.02,0:36:03.07,Default,,0,0,0,,以便计算完子阶乘后 Dialogue: 0,0:36:03.10,0:36:04.89,Default,,0,0,0,,恢复原始阶乘的计算 Dialogue: 0,0:36:06.25,0:36:06.86,Default,,0,0,0,,需要哪些信息呢? Dialogue: 0,0:36:07.23,0:36:08.73,Default,,0,0,0,,首先就是N Dialogue: 0,0:36:09.85,0:36:12.04,Default,,0,0,0,,因此 我要在这里构造一个栈 Dialogue: 0,0:36:14.70,0:36:15.77,Default,,0,0,0,,所谓的栈就是 Dialogue: 0,0:36:17.98,0:36:24.97,Default,,0,0,0,,一大堆连续的空间 Dialogue: 0,0:36:27.15,0:36:28.59,Default,,0,0,0,,我不知道它到底有多深 Dialogue: 0,0:36:29.15,0:36:31.48,Default,,0,0,0,,栈越深 无穷的假象营造得就越好 Dialogue: 0,0:36:33.23,0:36:35.56,Default,,0,0,0,,我还需要有一种方法 能够把 Dialogue: 0,0:36:35.60,0:36:37.02,Default,,0,0,0,,N中的值放入栈中 Dialogue: 0,0:36:38.12,0:36:39.08,Default,,0,0,0,,反过来也是 Dialogue: 0,0:36:39.93,0:36:41.74,Default,,0,0,0,,因此我需要一条像这样的连接 Dialogue: 0,0:36:44.41,0:36:45.48,Default,,0,0,0,,它是双向的 Dialogue: 0,0:36:50.44,0:36:52.22,Default,,0,0,0,,通过它 我就可以在某个时间 Dialogue: 0,0:36:52.24,0:36:55.50,Default,,0,0,0,,把N的值存储起来 Dialogue: 0,0:36:56.04,0:36:56.84,Default,,0,0,0,,这就是栈 Dialogue: 0,0:36:58.10,0:37:01.71,Default,,0,0,0,,我还需要一种方法来记住 Dialogue: 0,0:37:01.84,0:37:07.72,Default,,0,0,0,,我现在计算到外部程序的哪个地方了 Dialogue: 0,0:37:08.53,0:37:10.06,Default,,0,0,0,,现在 对于这台机器来说 Dialogue: 0,0:37:10.76,0:37:13.34,Default,,0,0,0,,这并不是什么问题 Dialogue: 0,0:37:14.17,0:37:16.24,Default,,0,0,0,,FACT总是返回在 Dialogue: 0,0:37:16.86,0:37:19.07,Default,,0,0,0,,一个跟N相乘的地方 Dialogue: 0,0:37:19.34,0:37:20.72,Default,,0,0,0,,除了最后的一次 Dialogue: 0,0:37:21.15,0:37:23.02,Default,,0,0,0,,它返回到需要FACT最终答案的地方 Dialogue: 0,0:37:23.04,0:37:24.04,Default,,0,0,0,,或者是'DONE、'STOP之类的 Dialogue: 0,0:37:25.66,0:37:26.67,Default,,0,0,0,,然而 通常来说 Dialogue: 0,0:37:27.16,0:37:28.73,Default,,0,0,0,,我需要记住我去过哪些地方 Dialogue: 0,0:37:29.13,0:37:31.24,Default,,0,0,0,,因为 我可能从其它地方调用FACT Dialogue: 0,0:37:32.08,0:37:34.89,Default,,0,0,0,,我需要返回到那个地方 并从那里继续 Dialogue: 0,0:37:36.07,0:37:38.00,Default,,0,0,0,,因此 我需要有一种方法能够 Dialogue: 0,0:37:38.01,0:37:40.86,Default,,0,0,0,,记住有穷状态控制器中弹珠的位置 Dialogue: 0,0:37:41.32,0:37:42.64,Default,,0,0,0,,也就是控制器的状态 Dialogue: 0,0:37:44.22,0:37:46.35,Default,,0,0,0,,并将它存储在栈中 Dialogue: 0,0:37:47.40,0:37:49.10,Default,,0,0,0,,我也需要有一种方法 Dialogue: 0,0:37:49.45,0:37:51.12,Default,,0,0,0,,能够恢复弹珠的状态 Dialogue: 0,0:37:52.14,0:37:54.28,Default,,0,0,0,,因此 我需要有一种将弹珠归位的能力 Dialogue: 0,0:37:54.70,0:37:56.52,Default,,0,0,0,,现在 我们有一个地方用于存储弹珠 Dialogue: 0,0:37:57.87,0:37:59.34,Default,,0,0,0,,它被称作“继续”寄存器 Dialogue: 0,0:38:03.61,0:38:04.52,Default,,0,0,0,,记作CONTINUE Dialogue: 0,0:38:09.16,0:38:10.68,Default,,0,0,0,,下一次调用(GOTO CONTINUE)时 Dialogue: 0,0:38:11.00,0:38:13.05,Default,,0,0,0,,弹珠就会去向这个地方 Dialogue: 0,0:38:14.91,0:38:15.92,Default,,0,0,0,,它就是用来干这个的 Dialogue: 0,0:38:16.14,0:38:18.48,Default,,0,0,0,,因此 它和控制器之间应该有一条通路 Dialogue: 0,0:38:22.91,0:38:27.12,Default,,0,0,0,,我也能够将它存储在栈上 Dialogue: 0,0:38:29.45,0:38:33.10,Default,,0,0,0,,我也能够把它设置成各种常量 Dialogue: 0,0:38:34.01,0:38:35.69,Default,,0,0,0,,某一些常量 Dialogue: 0,0:38:36.86,0:38:38.20,Default,,0,0,0,,这非常容易实现 Dialogue: 0,0:38:38.84,0:38:40.14,Default,,0,0,0,,我们现在这里设一些常量 Dialogue: 0,0:38:40.18,0:38:41.50,Default,,0,0,0,,我们把这个记作AFTER-FACT Dialogue: 0,0:38:47.32,0:38:48.75,Default,,0,0,0,,这个常量 Dialogue: 0,0:38:48.84,0:38:51.50,Default,,0,0,0,,会送入CONTINUE寄存器 Dialogue: 0,0:38:52.59,0:38:54.43,Default,,0,0,0,,另外一个寄存器是FACT-DONE Dialogue: 0,0:39:05.21,0:39:07.82,Default,,0,0,0,,这就是我想要构建的机器 Dialogue: 0,0:39:08.13,0:39:09.48,Default,,0,0,0,,至少是数据通路部分 Dialogue: 0,0:39:09.92,0:39:11.69,Default,,0,0,0,,这里还混合了一些控制器 Dialogue: 0,0:39:11.85,0:39:14.59,Default,,0,0,0,,这是因为我需要记住我当前的位置 Dialogue: 0,0:39:14.70,0:39:16.35,Default,,0,0,0,,并将我恢复到该位置 Dialogue: 0,0:39:17.30,0:39:19.93,Default,,0,0,0,,现在 让我们来编写控制器对应的程序 Dialogue: 0,0:39:20.39,0:39:23.47,Default,,0,0,0,,我就把DEFINE-MACHINE和寄存器列表给省略了 Dialogue: 0,0:39:23.48,0:39:24.89,Default,,0,0,0,,因为它们无关紧要 Dialogue: 0,0:39:25.13,0:39:27.79,Default,,0,0,0,,我就直接写那些跟控制器有关的 Dialogue: 0,0:39:27.82,0:39:29.02,Default,,0,0,0,,指令序列 Dialogue: 0,0:39:31.48,0:39:41.85,Default,,0,0,0,,首先是(ASSIGN CONTINUE DONE) Dialogue: 0,0:39:45.15,0:39:45.82,Default,,0,0,0,,然后是一个循环 Dialogue: 0,0:39:47.34,0:39:56.08,Default,,0,0,0,,先判断 如果1=N 那么就跳转 Dialogue: 0,0:40:00.94,0:40:04.11,Default,,0,0,0,,那么就进入归纳的基本步骤 Dialogue: 0,0:40:06.06,0:40:07.20,Default,,0,0,0,,也就是最简单的情况 Dialogue: 0,0:40:08.05,0:40:08.76,Default,,0,0,0,,否则的话 Dialogue: 0,0:40:08.88,0:40:10.84,Default,,0,0,0,,我就要记住那些 Dialogue: 0,0:40:10.88,0:40:13.84,Default,,0,0,0,,计算子阶乘所必须的信息 Dialogue: 0,0:40:14.67,0:40:16.75,Default,,0,0,0,,我需要来带这里 以便计算子阶乘 Dialogue: 0,0:40:17.57,0:40:19.29,Default,,0,0,0,,所以我需要记住 完成它需要些什么 Dialogue: 0,0:40:19.71,0:40:22.52,Default,,0,0,0,,需要记住我计算完之后需要哪些东西 Dialogue: 0,0:40:24.00,0:40:25.51,Default,,0,0,0,,看到了吗 我要做些糟糕的事儿 Dialogue: 0,0:40:25.72,0:40:27.39,Default,,0,0,0,,我要去修改N的值 Dialogue: 0,0:40:28.57,0:40:30.40,Default,,0,0,0,,但是它又需要记住N的旧值 Dialogue: 0,0:40:32.14,0:40:33.64,Default,,0,0,0,,但是为了计算子阶乘 Dialogue: 0,0:40:33.66,0:40:34.92,Default,,0,0,0,,我又需要修改N的值 Dialogue: 0,0:40:35.60,0:40:37.10,Default,,0,0,0,,因此 我就得记住N的旧值 Dialogue: 0,0:40:38.00,0:40:39.60,Default,,0,0,0,,我也需要记住我的位置 Dialogue: 0,0:40:40.85,0:40:42.32,Default,,0,0,0,,因此 我保存CONTINUE的值 Dialogue: 0,0:40:47.70,0:40:51.29,Default,,0,0,0,,这条指令 就是用来将数据入栈的 Dialogue: 0,0:40:53.12,0:40:55.53,Default,,0,0,0,,将CONTINUE寄存器的值保存起来 Dialogue: 0,0:40:56.51,0:40:58.00,Default,,0,0,0,,在本例中也就是DONE Dialogue: 0,0:40:58.88,0:41:00.25,Default,,0,0,0,,因为稍后我也会修改它 Dialogue: 0,0:41:00.27,0:41:02.78,Default,,0,0,0,,因为我也需要回到AFTER-FACT Dialogue: 0,0:41:03.55,0:41:04.19,Default,,0,0,0,,我们来看看 Dialogue: 0,0:41:05.04,0:41:09.71,Default,,0,0,0,,我们需要存储N 因为稍后会用到 Dialogue: 0,0:41:10.38,0:41:20.54,Default,,0,0,0,,(ASSIGN N (-1+ (FETCH N))) Dialogue: 0,0:41:23.26,0:41:28.97,Default,,0,0,0,,(ASSIGN CONTINUE ... Dialogue: 0,0:41:32.12,0:41:33.42,Default,,0,0,0,,我看一下 -- Dialogue: 0,0:41:34.06,0:41:35.61,Default,,0,0,0,,AFT) Dialogue: 0,0:41:37.69,0:41:38.70,Default,,0,0,0,,这个名字很好 Dialogue: 0,0:41:38.73,0:41:40.65,Default,,0,0,0,,因为它短小精炼 很适合用在这里 Dialogue: 0,0:41:53.36,0:41:54.64,Default,,0,0,0,,现在 来看看我怎么做 Dialogue: 0,0:41:55.33,0:41:57.02,Default,,0,0,0,,我说 如果ANSWER是1的话 Dialogue: 0,0:41:58.72,0:41:59.66,Default,,0,0,0,,那程序就结束了 Dialogue: 0,0:42:00.46,0:42:01.66,Default,,0,0,0,,我只需要取得这个答案 Dialogue: 0,0:42:02.15,0:42:04.88,Default,,0,0,0,,否则我就要保存当前的继续以及N的值 Dialogue: 0,0:42:05.77,0:42:07.32,Default,,0,0,0,,然后让N减1 Dialogue: 0,0:42:07.60,0:42:09.63,Default,,0,0,0,,注意 我先要跳转到某处 Dialogue: 0,0:42:09.64,0:42:11.48,Default,,0,0,0,,然后来到这里 计算另外的阶乘 Dialogue: 0,0:42:13.50,0:42:15.74,Default,,0,0,0,,然而 这之中又有了另外的机器 Dialogue: 0,0:42:16.05,0:42:18.38,Default,,0,0,0,,其中N=1 CONTINUE是其它值 Dialogue: 0,0:42:22.11,0:42:23.21,Default,,0,0,0,,N=N-1 Dialogue: 0,0:42:23.77,0:42:25.28,Default,,0,0,0,,再我完成这个之后 Dialogue: 0,0:42:26.94,0:42:27.76,Default,,0,0,0,,我会来到这里 Dialogue: 0,0:42:28.66,0:42:30.46,Default,,0,0,0,,我会恢复N的旧值 Dialogue: 0,0:42:32.68,0:42:36.56,Default,,0,0,0,,也就是这里SAVE的逆运算 Dialogue: 0,0:42:38.36,0:42:39.88,Default,,0,0,0,,然后恢复CONTINUE Dialogue: 0,0:42:49.66,0:42:52.57,Default,,0,0,0,,然后我又会来到这里 Dialogue: 0,0:42:54.32,0:43:00.86,Default,,0,0,0,,(ASSIGN VAL Dialogue: 0,0:43:01.16,0:43:08.13,Default,,0,0,0,,(* (FETCH N) (FETCH VAL))) Dialogue: 0,0:43:13.44,0:43:18.30,Default,,0,0,0,,(闭合括号中) Dialogue: 0,0:43:19.79,0:43:21.44,Default,,0,0,0,,这样操作就完成了 Dialogue: 0,0:43:21.44,0:43:25.68,Default,,0,0,0,,子阶乘的结果就存储在了VAL中 Dialogue: 0,0:43:26.57,0:43:27.37,Default,,0,0,0,,这个时候 Dialogue: 0,0:43:27.66,0:43:28.75,Default,,0,0,0,,我就要返回到 Dialogue: 0,0:43:29.28,0:43:31.61,Default,,0,0,0,,CONTINUE所指向的地方 Dialogue: 0,0:43:33.64,0:43:35.77,Default,,0,0,0,,也就是(GOTO (FETCH CONTINUE)) Dialogue: 0,0:43:45.87,0:43:47.40,Default,,0,0,0,,最后就是基本情况的那步 Dialogue: 0,0:43:49.31,0:43:50.51,Default,,0,0,0,,也就是一个立即值 Dialogue: 0,0:43:50.68,0:43:56.88,Default,,0,0,0,,(ASSIGN VAL (FETCH N)) Dialogue: 0,0:44:01.36,0:44:02.75,Default,,0,0,0,,(GOTO (FETCH CONTINUE)) Dialogue: 0,0:44:12.67,0:44:13.55,Default,,0,0,0,,这样我就完成了 Dialogue: 0,0:44:18.64,0:44:21.21,Default,,0,0,0,,现在 我们用一个非常简单的例子来运行一下 Dialogue: 0,0:44:22.51,0:44:23.53,Default,,0,0,0,,因为这样我们就将看到 Dialogue: 0,0:44:23.66,0:44:26.52,Default,,0,0,0,,栈是如何帮助我们完成计算的 Dialogue: 0,0:44:26.89,0:44:28.22,Default,,0,0,0,,这是计算的静态描述 Dialogue: 0,0:44:28.22,0:44:29.80,Default,,0,0,0,,我们需要动态地观察它 Dialogue: 0,0:44:31.34,0:44:32.09,Default,,0,0,0,,因此 让我们来看看 Dialogue: 0,0:44:32.30,0:44:34.56,Default,,0,0,0,,首先我们要把CONTINUE设置为DONE Dialogue: 0,0:44:36.73,0:44:38.09,Default,,0,0,0,,这是我通过按下这个钮来实现的 Dialogue: 0,0:44:38.30,0:44:39.60,Default,,0,0,0,,我们还是把它记作DONE吧 Dialogue: 0,0:44:46.22,0:44:47.03,Default,,0,0,0,,我按下这个按钮 Dialogue: 0,0:44:47.03,0:44:48.11,Default,,0,0,0,,DONE就进到了这里 Dialogue: 0,0:44:48.95,0:44:53.71,Default,,0,0,0,,现在 我还要为这些东西设置初始值 Dialogue: 0,0:44:53.85,0:44:58.08,Default,,0,0,0,,让我们考虑3的阶乘 Dialogue: 0,0:44:58.38,0:44:59.24,Default,,0,0,0,,这个例子非常简单 Dialogue: 0,0:45:00.54,0:45:04.04,Default,,0,0,0,,我们的栈从这里开始增长 Dialogue: 0,0:45:05.90,0:45:07.76,Default,,0,0,0,,栈有它们自己的内部状态 Dialogue: 0,0:45:07.79,0:45:09.05,Default,,0,0,0,,用来标识栈顶位置 Dialogue: 0,0:45:09.80,0:45:11.64,Default,,0,0,0,,也就是下一个可写位置 Dialogue: 0,0:45:12.77,0:45:14.59,Default,,0,0,0,,现在我们问 N=1么? Dialogue: 0,0:45:14.76,0:45:15.71,Default,,0,0,0,,当然不等于 Dialogue: 0,0:45:16.11,0:45:18.56,Default,,0,0,0,,因此现在我要保存CONTINUE Dialogue: 0,0:45:19.15,0:45:20.65,Default,,0,0,0,,现在 DONE就来到了这里 Dialogue: 0,0:45:22.08,0:45:23.55,Default,,0,0,0,,然后 这个指针移动到了这里 Dialogue: 0,0:45:24.88,0:45:26.14,Default,,0,0,0,,下次我要把数据写到这里 Dialogue: 0,0:45:26.66,0:45:28.78,Default,,0,0,0,,保存N的值--也就是3 Dialogue: 0,0:45:29.95,0:45:30.32,Default,,0,0,0,,对吧? Dialogue: 0,0:45:30.67,0:45:33.61,Default,,0,0,0,,N←N-1 Dialogue: 0,0:45:33.96,0:45:35.37,Default,,0,0,0,,也就是说 我得按下这个钮 Dialogue: 0,0:45:35.94,0:45:37.32,Default,,0,0,0,,这就变成了2 Dialogue: 0,0:45:38.73,0:45:42.28,Default,,0,0,0,,COUNTINUE←AFT Dialogue: 0,0:45:42.58,0:45:43.61,Default,,0,0,0,,因此我要按下这个钮 Dialogue: 0,0:45:43.61,0:45:44.54,Default,,0,0,0,,AFT就进入了这里 Dialogue: 0,0:45:49.14,0:45:53.93,Default,,0,0,0,,然后 跳转到LOOP 我们就来到了这里 Dialogue: 0,0:45:54.83,0:45:57.08,Default,,0,0,0,,N=1么?当然不 Dialogue: 0,0:45:57.78,0:45:59.23,Default,,0,0,0,,因此我又要保存CONTINUE Dialogue: 0,0:45:59.49,0:46:00.27,Default,,0,0,0,,CONTINUE的值是什么呢? Dialogue: 0,0:46:00.60,0:46:01.53,Default,,0,0,0,,目前是AFT Dialogue: 0,0:46:01.53,0:46:02.32,Default,,0,0,0,,按下这个按钮 Dialogue: 0,0:46:02.78,0:46:03.95,Default,,0,0,0,,这个指针移动到了这里 Dialogue: 0,0:46:08.49,0:46:09.74,Default,,0,0,0,,我还要保存N Dialogue: 0,0:46:10.51,0:46:12.12,Default,,0,0,0,,N在那里 它的值是2 Dialogue: 0,0:46:12.28,0:46:13.37,Default,,0,0,0,,按下这个按钮 Dialogue: 0,0:46:13.85,0:46:15.24,Default,,0,0,0,,2就进入了这里 Dialogue: 0,0:46:16.05,0:46:17.64,Default,,0,0,0,,然后这个指针移动到了这里 Dialogue: 0,0:46:20.06,0:46:22.60,Default,,0,0,0,,保存N之后 又赋N←N-1 Dialogue: 0,0:46:24.60,0:46:25.46,Default,,0,0,0,,它就变成了1 Dialogue: 0,0:46:29.24,0:46:30.54,Default,,0,0,0,,CONTINUE←AFT Dialogue: 0,0:46:31.37,0:46:34.48,Default,,0,0,0,,AFT又进入了这里 Dialogue: 0,0:46:34.96,0:46:35.64,Default,,0,0,0,,然后又跳转到LOOP Dialogue: 0,0:46:36.52,0:46:37.74,Default,,0,0,0,,N等于1么? Dialogue: 0,0:46:37.93,0:46:39.52,Default,,0,0,0,,是的 那么答案就是1 Dialogue: 0,0:46:41.04,0:46:43.26,Default,,0,0,0,,跳转到BASE那一步 Dialogue: 0,0:46:44.16,0:46:45.77,Default,,0,0,0,,(ASSIGN VAL (FETCH N)) Dialogue: 0,0:46:46.56,0:46:50.72,Default,,0,0,0,,按下这个 1就进入到了这里 Dialogue: 0,0:46:51.10,0:46:52.20,Default,,0,0,0,,(GOTO (FETCH CONTINUE)) Dialogue: 0,0:46:52.20,0:46:53.53,Default,,0,0,0,,来看下CONTINUE寄存器 Dialogue: 0,0:46:53.68,0:46:56.06,Default,,0,0,0,,基本上来说 我按下这里的按钮 进入到控制器 Dialogue: 0,0:46:56.67,0:46:58.28,Default,,0,0,0,,CONTINUE寄存器就变成了AFT Dialogue: 0,0:46:58.32,0:47:00.25,Default,,0,0,0,,这样一下子 程序就运行到了这里 Dialogue: 0,0:47:02.64,0:47:05.63,Default,,0,0,0,,现在 我就需要恢复外部的阶乘了 Dialogue: 0,0:47:06.65,0:47:07.55,Default,,0,0,0,,因此我们来到这里 Dialogue: 0,0:47:07.55,0:47:09.48,Default,,0,0,0,,我们先要恢复N Dialogue: 0,0:47:10.32,0:47:13.04,Default,,0,0,0,,这就意味着 我们要使用这里的内容 Dialogue: 0,0:47:13.94,0:47:18.17,Default,,0,0,0,,按下这个按钮 2就会来到这里 Dialogue: 0,0:47:18.56,0:47:20.04,Default,,0,0,0,,然后指针会向上移动 Dialogue: 0,0:47:21.98,0:47:24.49,Default,,0,0,0,,恢复CONTINUE寄存器也非常简单 Dialogue: 0,0:47:24.81,0:47:26.49,Default,,0,0,0,,来按下这个按钮 Dialogue: 0,0:47:27.02,0:47:28.92,Default,,0,0,0,,然后 AFT又一次进入到这里 Dialogue: 0,0:47:31.28,0:47:32.64,Default,,0,0,0,,同时 这个指针也要上移 Dialogue: 0,0:47:32.64,0:47:35.19,Default,,0,0,0,,这样就避开了栈上的其它东西 Dialogue: 0,0:47:42.24,0:47:43.47,Default,,0,0,0,,然后我来到这里 Dialogue: 0,0:47:43.87,0:47:47.15,Default,,0,0,0,,也就是(ASSIGN VAL (* N VAL)) Dialogue: 0,0:47:47.85,0:47:50.57,Default,,0,0,0,,然后我按下这个按钮 Dialogue: 0,0:47:50.97,0:47:52.91,Default,,0,0,0,,2乘以1等于2 Dialogue: 0,0:47:54.01,0:47:54.75,Default,,0,0,0,,我写到这里 Dialogue: 0,0:47:55.76,0:47:57.20,Default,,0,0,0,,然后是(GOTO (FETCH CONTINUE)) Dialogue: 0,0:47:57.54,0:47:59.85,Default,,0,0,0,,CONTINUE现在是AFT 我跳转到AFT Dialogue: 0,0:48:01.15,0:48:03.88,Default,,0,0,0,,AFT首先要恢复N Dialogue: 0,0:48:04.36,0:48:05.72,Default,,0,0,0,,恢复N指的是 Dialogue: 0,0:48:05.87,0:48:08.44,Default,,0,0,0,,我把这里的值 也就是3 Dialogue: 0,0:48:09.24,0:48:10.33,Default,,0,0,0,,按下这里的按钮 Dialogue: 0,0:48:10.60,0:48:15.50,Default,,0,0,0,,然后把它放到这里 N Dialogue: 0,0:48:16.25,0:48:17.34,Default,,0,0,0,,然后 我们按下这个钮 Dialogue: 0,0:48:18.01,0:48:19.90,Default,,0,0,0,,接下来我就要恢复CONTINUE Dialogue: 0,0:48:20.20,0:48:22.20,Default,,0,0,0,,CONTINUE寄存器现在成为了DONE Dialogue: 0,0:48:22.83,0:48:26.78,Default,,0,0,0,,当我按下这个钮后 指针就移动到了这里 Dialogue: 0,0:48:27.13,0:48:29.72,Default,,0,0,0,,DONE可能从此之后不在这里了 Dialogue: 0,0:48:29.72,0:48:31.55,Default,,0,0,0,,对此我并不感兴趣 但它现在一定在这里 Dialogue: 0,0:48:35.80,0:48:38.12,Default,,0,0,0,,下一步 我将要把VAL赋值为 Dialogue: 0,0:48:38.43,0:48:40.76,Default,,0,0,0,,N乘以VAL的值 Dialogue: 0,0:48:41.44,0:48:44.30,Default,,0,0,0,,按下这里的按钮就可以实现 Dialogue: 0,0:48:44.30,0:48:45.77,Default,,0,0,0,,2乘以3等于6 Dialogue: 0,0:48:46.52,0:48:47.87,Default,,0,0,0,,所以这里我就得到了6 Dialogue: 0,0:48:50.97,0:48:53.40,Default,,0,0,0,,下一步是(GOTO (FETCH CONTINUE)) Dialogue: 0,0:48:53.48,0:48:54.83,Default,,0,0,0,,哦 跳转到DONE 这样我就完成了 Dialogue: 0,0:48:55.02,0:48:56.09,Default,,0,0,0,,最后的答案是6 Dialogue: 0,0:48:56.60,0:48:57.82,Default,,0,0,0,,你们可以在VAL寄存器中看到 Dialogue: 0,0:48:58.95,0:48:59.82,Default,,0,0,0,,事实上 Dialogue: 0,0:49:00.91,0:49:03.34,Default,,0,0,0,,栈又回到了它初始的状态 Dialogue: 0,0:49:08.20,0:49:10.70,Default,,0,0,0,,在使用像栈这样的东西中 有一些原则 Dialogue: 0,0:49:11.20,0:49:12.27,Default,,0,0,0,,我们需要注意 Dialogue: 0,0:49:13.62,0:49:15.52,Default,,0,0,0,,我们会在下一小节中介绍 Dialogue: 0,0:49:16.26,0:49:18.46,Default,,0,0,0,,但首先 对于这一小节所讲的内容 Dialogue: 0,0:49:28.56,0:49:29.64,Default,,0,0,0,,有什么问题么? Dialogue: 0,0:49:30.17,0:49:30.63,Default,,0,0,0,,Ron 请讲 Dialogue: 0,0:49:30.63,0:49:33.37,Default,,0,0,0,,学生:当你越过了栈的顶端会怎样-- Dialogue: 0,0:49:33.39,0:49:34.62,Default,,0,0,0,,教授:你所谓的“越过”是指什么? Dialogue: 0,0:49:35.03,0:49:37.50,Default,,0,0,0,,学生:如果我们的N是一个很大的数 Dialogue: 0,0:49:37.52,0:49:38.72,Default,,0,0,0,,就需要更多的内存 对吧? Dialogue: 0,0:49:38.86,0:49:39.44,Default,,0,0,0,,教授:是的 Dialogue: 0,0:49:39.44,0:49:41.12,Default,,0,0,0,,这样 我就需要一个足够大的栈 Dialogue: 0,0:49:41.53,0:49:43.20,Default,,0,0,0,,你想问 如果破坏了无穷存储的假象会发生什么? Dialogue: 0,0:49:43.84,0:49:44.12,Default,,0,0,0,,学生:是的 Dialogue: 0,0:49:44.55,0:49:46.73,Default,,0,0,0,,教授:那么 这些魔法就不再起效了 Dialogue: 0,0:49:47.96,0:49:51.00,Default,,0,0,0,,真相就是 任何机器都是有穷的 Dialogue: 0,0:49:51.64,0:49:53.72,Default,,0,0,0,,而对于像这样的过程 Dialogue: 0,0:49:54.17,0:49:58.86,Default,,0,0,0,,我只能进行有限数量的子阶乘计算 Dialogue: 0,0:49:59.95,0:50:02.48,Default,,0,0,0,,想一想 我们之前讲解的Y组合子 Dialogue: 0,0:50:02.80,0:50:06.22,Default,,0,0,0,,我们指出 存在一系列的指数过程 Dialogue: 0,0:50:06.25,0:50:08.09,Default,,0,0,0,,其中每一个都要比前一个更精准 Dialogue: 0,0:50:08.72,0:50:11.60,Default,,0,0,0,,现在 我们看到了如何实现这个数学理念 Dialogue: 0,0:50:13.09,0:50:14.19,Default,,0,0,0,,这个取极限的过程 Dialogue: 0,0:50:14.35,0:50:16.33,Default,,0,0,0,,只有当你取到极限时才足够精准 Dialogue: 0,0:50:17.99,0:50:19.42,Default,,0,0,0,,如果你仔细想想 我这里用了什么 Dialogue: 0,0:50:19.42,0:50:22.65,Default,,0,0,0,,对于这个过程的每一次递归 Dialogue: 0,0:50:23.04,0:50:27.07,Default,,0,0,0,,我用了大概两块内存 Dialogue: 0,0:50:29.10,0:50:31.71,Default,,0,0,0,,如果我们尝试计算10000的阶乘 Dialogue: 0,0:50:31.72,0:50:32.81,Default,,0,0,0,,这并不会花掉很多内存 Dialogue: 0,0:50:33.18,0:50:34.68,Default,,0,0,0,,虽然这是一个很大的数 Dialogue: 0,0:50:35.95,0:50:38.41,Default,,0,0,0,,因此 实际的问题就是值不值得 Dialogue: 0,0:50:39.18,0:50:42.19,Default,,0,0,0,,但这并不是这种实现的局限 Dialogue: 0,0:50:42.22,0:50:43.53,Default,,0,0,0,,因为内存非常低廉 Dialogue: 0,0:50:44.16,0:50:45.34,Default,,0,0,0,,但人力资源却相当昂贵 Dialogue: 0,0:50:48.13,0:50:50.22,Default,,0,0,0,,好吧 我们先休息一下 谢谢大家 Dialogue: 0,0:50:50.78,0:51:07.60,Default,,0,0,0,,[音乐] Dialogue: 0,0:51:07.60,0:51:12.19,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:51:39.93,0:51:43.69,Declare,,0,0,0,,{\an2\fad(500,500)}讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:51:43.71,0:51:47.93,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:51:47.93,0:51:53.08,Declare,,0,0,0,,{\an2\fad(500,500)}寄存机器 Dialogue: 0,0:51:56.11,0:51:57.04,Default,,0,0,0,,教授:我们讲解了 Dialogue: 0,0:51:58.70,0:52:03.37,Default,,0,0,0,,如果进行简单的迭代计算 Dialogue: 0,0:52:03.69,0:52:05.31,Default,,0,0,0,,以及简单的递归计算 Dialogue: 0,0:52:05.64,0:52:08.68,Default,,0,0,0,,我只想通过向你们展示一些针对特定应用的 Dialogue: 0,0:52:09.63,0:52:11.12,Default,,0,0,0,,更加复杂的设计 Dialogue: 0,0:52:11.21,0:52:13.58,Default,,0,0,0,,来总结简单机器的设计 Dialogue: 0,0:52:13.96,0:52:17.13,Default,,0,0,0,,也就是同时递归地调用两个斐波那契函数 Dialogue: 0,0:52:17.23,0:52:19.88,Default,,0,0,0,,因为它会向我们表明 并且我们会理解 Dialogue: 0,0:52:20.04,0:52:22.68,Default,,0,0,0,,一些关于栈正常工作 Dialogue: 0,0:52:22.76,0:52:25.04,Default,,0,0,0,,所需要遵守的约定 Dialogue: 0,0:52:26.40,0:52:27.11,Default,,0,0,0,,现在 让我们来看看 Dialogue: 0,0:52:27.11,0:52:28.27,Default,,0,0,0,,先让我在黑板上写下 Dialogue: 0,0:52:28.30,0:52:29.71,Default,,0,0,0,,将要翻译的程序 Dialogue: 0,0:52:34.15,0:52:36.52,Default,,0,0,0,,这是一个斐波那契过程 Dialogue: 0,0:52:39.23,0:52:41.58,Default,,0,0,0,,它非常的简单 Dialogue: 0,0:52:44.60,0:52:48.56,Default,,0,0,0,,如果N小于2 那么结果就是N Dialogue: 0,0:52:49.26,0:52:55.34,Default,,0,0,0,,否则就是(FIB (- N 1))加上 Dialogue: 0,0:52:58.44,0:52:59.85,Default,,0,0,0,,(FIB (- N 2)) Dialogue: 0,0:53:07.05,0:53:09.29,Default,,0,0,0,,这就是我的计划 Dialogue: 0,0:53:09.29,0:53:12.56,Default,,0,0,0,,现在 我们要来写下这台机器的控制器 Dialogue: 0,0:53:13.07,0:53:15.53,Default,,0,0,0,,首先 我们假设有一个寄存器N Dialogue: 0,0:53:15.56,0:53:19.15,Default,,0,0,0,,里面存放的是斐波那契函数的自变量 Dialogue: 0,0:53:19.82,0:53:21.80,Default,,0,0,0,,而计算结果会存放在VAL寄存器中 Dialogue: 0,0:53:22.17,0:53:24.97,Default,,0,0,0,,CONTINUE寄存器会和控制器相连 Dialogue: 0,0:53:26.11,0:53:26.81,Default,,0,0,0,,就跟之前一样 Dialogue: 0,0:53:26.96,0:53:29.21,Default,,0,0,0,,但我不会再去画数据通路了 Dialogue: 0,0:53:31.53,0:53:34.00,Default,,0,0,0,,因为它和之前的那个差不多 Dialogue: 0,0:53:34.36,0:53:37.84,Default,,0,0,0,,当然 关于计算的最神奇的事情之一 Dialogue: 0,0:53:38.75,0:53:39.88,Default,,0,0,0,,就是一段时间后 Dialogue: 0,0:53:40.08,0:53:41.93,Default,,0,0,0,,你构建了一个又一个的小功能 Dialogue: 0,0:53:41.95,0:53:43.32,Default,,0,0,0,,你就一下子拥有了需要的一切 Dialogue: 0,0:53:44.75,0:53:47.60,Default,,0,0,0,,这种效率是非常了不起的 Dialogue: 0,0:53:48.17,0:53:50.84,Default,,0,0,0,,构造制作一台通用计算机不需要太多的东西 Dialogue: 0,0:53:51.81,0:53:54.68,Default,,0,0,0,,总之 我们来看看斐波那契机器的控制器 Dialogue: 0,0:53:55.06,0:53:57.07,Default,,0,0,0,,我首先要做的是 Dialogue: 0,0:53:57.32,0:54:02.52,Default,,0,0,0,,通过为CONTINUE寄存器赋值 Dialogue: 0,0:54:07.13,0:54:10.28,Default,,0,0,0,,赋FIB-DONE来启动计算 Dialogue: 0,0:54:14.14,0:54:15.53,Default,,0,0,0,,这就意味着在这里 Dialogue: 0,0:54:15.55,0:54:18.48,Default,,0,0,0,,我需要有一个标签 FIB-DONE Dialogue: 0,0:54:19.71,0:54:21.10,Default,,0,0,0,,当我来到这个地方后 Dialogue: 0,0:54:21.23,0:54:22.44,Default,,0,0,0,,机器就停止了 Dialogue: 0,0:54:24.00,0:54:24.86,Default,,0,0,0,,这就是这个标签的作用 Dialogue: 0,0:54:25.92,0:54:26.89,Default,,0,0,0,,然后我要创建一个循环 Dialogue: 0,0:54:31.11,0:54:34.25,Default,,0,0,0,,我要来到这里来启动FIB的计算 Dialogue: 0,0:54:35.47,0:54:36.86,Default,,0,0,0,,无论这时 N等于多少 Dialogue: 0,0:54:37.39,0:54:38.99,Default,,0,0,0,,斐波那契函数都会被计算 Dialogue: 0,0:54:39.13,0:54:42.01,Default,,0,0,0,,然后会返回到由CONTINUE寄存器指向的地方 Dialogue: 0,0:54:44.80,0:54:48.40,Default,,0,0,0,,因此你们将在这里看到 Dialogue: 0,0:54:48.44,0:54:50.48,Default,,0,0,0,,我想要在做一个约定 Dialogue: 0,0:54:50.97,0:54:54.25,Default,,0,0,0,,我用注释的形式来说明这个约定 Dialogue: 0,0:54:54.57,0:55:00.99,Default,,0,0,0,,也就是N中存储的是参数 Dialogue: 0,0:55:02.10,0:55:09.82,Default,,0,0,0,,而CONTINUE存储的是接收者 Dialogue: 0,0:55:13.36,0:55:14.29,Default,,0,0,0,,这个约定就是这样的 Dialogue: 0,0:55:15.71,0:55:18.96,Default,,0,0,0,,因此每当我来到这里 Dialogue: 0,0:55:19.24,0:55:21.04,Default,,0,0,0,,我希望这个约定是成立的 Dialogue: 0,0:55:21.52,0:55:23.32,Default,,0,0,0,,这些计算斐波那契函数所需要的参数 Dialogue: 0,0:55:24.82,0:55:26.83,Default,,0,0,0,,接下来我想做的是分支 Dialogue: 0,0:55:30.22,0:55:32.22,Default,,0,0,0,,如果N小于2 Dialogue: 0,0:55:35.07,0:55:37.44,Default,,0,0,0,,随便说一下 我使用的语法看起来像Lisp Dialogue: 0,0:55:38.73,0:55:39.63,Default,,0,0,0,,但它并不是Lisp Dialogue: 0,0:55:41.31,0:55:42.38,Default,,0,0,0,,它们运行不起来 Dialogue: 0,0:55:42.75,0:55:45.47,Default,,0,0,0,,我在这里写的并不是一个简单的Lisp程序 Dialogue: 0,0:55:46.12,0:55:49.31,Default,,0,0,0,,这是另一门语言的表示形式 Dialogue: 0,0:55:49.71,0:55:52.25,Default,,0,0,0,,我之所以使用这种满是括号的语法 Dialogue: 0,0:55:52.40,0:55:54.70,Default,,0,0,0,,是因为我刚好使用Lisp系统 Dialogue: 0,0:55:55.32,0:55:57.34,Default,,0,0,0,,来为这门语言编写解释器 Dialogue: 0,0:55:57.82,0:55:59.18,Default,,0,0,0,,这就使得我们能够模拟 Dialogue: 0,0:55:59.29,0:56:00.91,Default,,0,0,0,,我想要构建的机器 Dialogue: 0,0:56:03.38,0:56:06.24,Default,,0,0,0,,我不想让你们感到困惑 认为这是Lisp代码 Dialogue: 0,0:56:06.94,0:56:08.60,Default,,0,0,0,,只是我用了很多Lisp组件 Dialogue: 0,0:56:09.51,0:56:10.84,Default,,0,0,0,,我在Lisp中嵌入了一门语言 Dialogue: 0,0:56:11.02,0:56:12.44,Default,,0,0,0,,把Lisp当作组件 Dialogue: 0,0:56:12.72,0:56:15.12,Default,,0,0,0,,这样就能让我的模拟工作变得简单 Dialogue: 0,0:56:16.62,0:56:18.56,Default,,0,0,0,,我从Lisp中继承了这些属性 Dialogue: 0,0:56:19.10,0:56:21.53,Default,,0,0,0,,(FETCH N) 2) Dialogue: 0,0:56:21.77,0:56:23.72,Default,,0,0,0,,成立的话 我想要跳转到IMMEDIATE-ANSWER这个地方 Dialogue: 0,0:56:26.20,0:56:27.29,Default,,0,0,0,,这是基本步骤 Dialogue: 0,0:56:33.15,0:56:34.35,Default,,0,0,0,,它对应在这里 Dialogue: 0,0:56:35.92,0:56:36.89,Default,,0,0,0,,也就是在FIB-DONE的上方 Dialogue: 0,0:56:37.75,0:56:38.64,Default,,0,0,0,,我们稍后就会看到 Dialogue: 0,0:56:39.42,0:56:40.70,Default,,0,0,0,,现在 对于一般情况来说 Dialogue: 0,0:56:40.72,0:56:42.44,Default,,0,0,0,,也就是我现在要写的 Dialogue: 0,0:56:43.13,0:56:44.19,Default,,0,0,0,,是这样的 Dialogue: 0,0:56:44.91,0:56:48.20,Default,,0,0,0,,首先呢 我需要调用斐波那契函数两次 Dialogue: 0,0:56:49.42,0:56:52.54,Default,,0,0,0,,在每一次中 -- 至少在其中一次 Dialogue: 0,0:56:52.78,0:56:53.95,Default,,0,0,0,,我得需要知道该怎么做 Dialogue: 0,0:56:53.96,0:56:55.36,Default,,0,0,0,,才能回过头来进行另外一个计算 Dialogue: 0,0:56:56.31,0:56:58.36,Default,,0,0,0,,我需要记住 Dialogue: 0,0:56:59.20,0:57:01.23,Default,,0,0,0,,我计算完第一个FIB了么? Dialogue: 0,0:57:01.26,0:57:02.54,Default,,0,0,0,,或者第二个也计算完了? Dialogue: 0,0:57:04.50,0:57:07.04,Default,,0,0,0,,我是该返回到计算第二个FIB的地方 Dialogue: 0,0:57:07.07,0:57:09.08,Default,,0,0,0,,还是回到执行ADD的地方 Dialogue: 0,0:57:10.12,0:57:12.11,Default,,0,0,0,,无论哪种情况 我都需要-- Dialogue: 0,0:57:12.14,0:57:14.46,Default,,0,0,0,,在第一个计算第一个FIB时 Dialogue: 0,0:57:14.51,0:57:16.98,Default,,0,0,0,,我需要保存N的值 来计算第二个FIB Dialogue: 0,0:57:19.84,0:57:21.58,Default,,0,0,0,,因此我要把这些东西保存起来 Dialogue: 0,0:57:23.36,0:57:24.89,Default,,0,0,0,,首先要保存CONTINUE Dialogue: 0,0:57:26.19,0:57:27.32,Default,,0,0,0,,也就是答案的接收者 Dialogue: 0,0:57:31.32,0:57:32.46,Default,,0,0,0,,我之所以要这么做 Dialogue: 0,0:57:32.48,0:57:34.20,Default,,0,0,0,,是因为我现在要把CONTINUE赋值为 Dialogue: 0,0:57:40.11,0:57:44.32,Default,,0,0,0,,我待会儿想要返回的地方 Dialogue: 0,0:57:46.83,0:57:50.27,Default,,0,0,0,,我们把它叫做AFTER-FIB-N-1 Dialogue: 0,0:57:51.04,0:57:53.76,Default,,0,0,0,,这个长名字 非常具有Lisp的命名特点 Dialogue: 0,0:57:57.36,0:58:00.22,Default,,0,0,0,,这是因为我先要计算第一个(FIB (- N 1)) Dialogue: 0,0:58:00.84,0:58:01.72,Default,,0,0,0,,计算完成之后 Dialogue: 0,0:58:01.72,0:58:03.29,Default,,0,0,0,,我想要回过头来做些其它事 Dialogue: 0,0:58:03.96,0:58:06.52,Default,,0,0,0,,而AFTER-FIB-N-1这个地方 Dialogue: 0,0:58:07.55,0:58:09.48,Default,,0,0,0,,就是我计算完第一个FIB后应该返回的地方 Dialogue: 0,0:58:11.52,0:58:13.13,Default,,0,0,0,,接下来我要保存N Dialogue: 0,0:58:14.41,0:58:17.26,Default,,0,0,0,,因为我稍后需要用到它 Dialogue: 0,0:58:19.13,0:58:20.54,Default,,0,0,0,,在这里 我就已经 Dialogue: 0,0:58:20.67,0:58:22.84,Default,,0,0,0,,准备好计算(FIB (- N 1))了 Dialogue: 0,0:58:23.02,0:58:33.95,Default,,0,0,0,,(ASSIGN N (- (FETCH N) 1)) Dialogue: 0,0:58:38.11,0:58:40.27,Default,,0,0,0,,现在 该跳转到FIB-LOOP了 Dialogue: 0,0:58:47.18,0:58:49.87,Default,,0,0,0,,我满足我立下的约定么? Dialogue: 0,0:58:50.40,0:58:51.50,Default,,0,0,0,,答案是是的 Dialogue: 0,0:58:51.77,0:58:55.12,Default,,0,0,0,,N现在存储的是N-1 这是我需要的 Dialogue: 0,0:58:56.43,0:59:00.09,Default,,0,0,0,,而CONTINUE包含的是计算完成后 返回的目的地 Dialogue: 0,0:59:01.28,0:59:03.07,Default,,0,0,0,,也就是计算(FIB (- N 1))完成之后 Dialogue: 0,0:59:04.10,0:59:05.44,Default,,0,0,0,,因此我满足了这些约定 Dialogue: 0,0:59:05.44,0:59:09.02,Default,,0,0,0,,因此 我就可以在这里写下一个标签 Dialogue: 0,0:59:11.47,0:59:17.56,Default,,0,0,0,,AFTER-FIB-N-1 Dialogue: 0,0:59:20.49,0:59:21.63,Default,,0,0,0,,在这里 我又该做些什么呢? Dialogue: 0,0:59:22.69,0:59:23.61,Default,,0,0,0,,在这里 Dialogue: 0,0:59:23.95,0:59:26.75,Default,,0,0,0,,我已经准备好去计算(FIB (- N 2))了 Dialogue: 0,0:59:29.27,0:59:30.72,Default,,0,0,0,,但是为了计算(FIB (- N 2)) Dialogue: 0,0:59:30.75,0:59:31.63,Default,,0,0,0,,首先 我不知道 Dialogue: 0,0:59:31.78,0:59:33.40,Default,,0,0,0,,这里 我已经改变了N Dialogue: 0,0:59:33.81,0:59:35.47,Default,,0,0,0,,或者在这个时候 我的N总是不断地 Dialogue: 0,0:59:37.85,0:59:38.80,Default,,0,0,0,,向1或者0递减 Dialogue: 0,0:59:39.78,0:59:42.51,Default,,0,0,0,,所以我不知道N寄存器中存储的到底是什么 Dialogue: 0,0:59:43.03,0:59:44.75,Default,,0,0,0,,我想要保存在栈中的N的值 Dialogue: 0,0:59:44.80,0:59:46.00,Default,,0,0,0,,也就是我在这里保存的值 Dialogue: 0,0:59:46.17,0:59:47.88,Default,,0,0,0,,这样我就可以在这里恢复它 Dialogue: 0,0:59:49.52,0:59:51.02,Default,,0,0,0,,我在这里存储的N Dialogue: 0,0:59:51.15,0:59:54.49,Default,,0,0,0,,是这个时间点N的值 Dialogue: 0,0:59:54.89,0:59:57.37,Default,,0,0,0,,因此计算完(FIB (- N 1))之后我可以恢复它 Dialogue: 0,0:59:57.53,0:59:59.36,Default,,0,0,0,,这样的话 我就可以计算(- N 2) Dialogue: 0,0:59:59.39,1:00:00.86,Default,,0,0,0,,然后就可以计算(FIB (- N 2))的值 Dialogue: 0,1:00:01.81,1:00:02.75,Default,,0,0,0,,现在让我们来恢复它 Dialogue: 0,1:00:08.83,1:00:09.77,Default,,0,0,0,,(RESTORE N) Dialogue: 0,1:00:11.13,1:00:15.98,Default,,0,0,0,,现在我要做一件很教条的事 Dialogue: 0,1:00:16.00,1:00:17.40,Default,,0,0,0,,我们会尽快将其删除 Dialogue: 0,1:00:18.52,1:00:20.48,Default,,0,0,0,,如果你们愿意的话 Dialogue: 0,1:00:20.59,1:00:23.44,Default,,0,0,0,,我将要结束子过程调用 Dialogue: 0,1:00:24.80,1:00:25.95,Default,,0,0,0,,接下来我会说 Dialogue: 0,1:00:26.06,1:00:27.90,Default,,0,0,0,,因为我保存了CONTINUE Dialogue: 0,1:00:28.48,1:00:30.43,Default,,0,0,0,,现在就要去恢复它 Dialogue: 0,1:00:31.60,1:00:32.60,Default,,0,0,0,,但实际上 我并不需要这么做 Dialogue: 0,1:00:32.64,1:00:33.55,Default,,0,0,0,,因为我并不需要用到它 Dialogue: 0,1:00:34.61,1:00:35.72,Default,,0,0,0,,我们稍后会修正它 Dialogue: 0,1:00:36.26,1:00:37.95,Default,,0,0,0,,现在我们来恢复CONTINUE Dialogue: 0,1:00:46.04,1:00:48.02,Default,,0,0,0,,通常来说 我都会这么做 Dialogue: 0,1:00:48.02,1:00:49.23,Default,,0,0,0,,我们将要看到 Dialogue: 0,1:00:49.31,1:00:52.14,Default,,0,0,0,,编译器领域中的“窥孔优化” Dialogue: 0,1:00:52.27,1:00:53.72,Default,,0,0,0,,来帮我们消除这个不必要的步骤 Dialogue: 0,1:00:55.42,1:00:57.10,Default,,0,0,0,,因此 我即将要做的就是 Dialogue: 0,1:00:58.46,1:01:02.28,Default,,0,0,0,,准备好计算(FIB (- N 2)) Dialogue: 0,1:01:02.77,1:01:04.49,Default,,0,0,0,,但是我不再需要保存N了 Dialogue: 0,1:01:05.05,1:01:06.72,Default,,0,0,0,,原因就是 Dialogue: 0,1:01:06.80,1:01:09.34,Default,,0,0,0,,计算完(FIB (- N 2))之后 我就不需要N了 Dialogue: 0,1:01:09.36,1:01:10.72,Default,,0,0,0,,因为 我接下来要做的就是ADD Dialogue: 0,1:01:13.54,1:01:15.85,Default,,0,0,0,,因此 我会这么来设置N Dialogue: 0,1:01:16.60,1:01:28.99,Default,,0,0,0,,(ASSIGN N (- (FETCH N) 2)) Dialogue: 0,1:01:31.85,1:01:34.01,Default,,0,0,0,,现在我需要结束 Dialogue: 0,1:01:34.27,1:01:36.73,Default,,0,0,0,,调用(FIB (- N 2))的设置过程了 Dialogue: 0,1:01:36.95,1:01:38.33,Default,,0,0,0,,我需要保存CONTINUE Dialogue: 0,1:01:44.22,1:01:49.02,Default,,0,0,0,,然后把CONTINUE赋值为 Dialogue: 0,1:01:52.30,1:01:59.95,Default,,0,0,0,,AFTER-FIB-N-2 Dialogue: 0,1:02:02.57,1:02:04.03,Default,,0,0,0,,对应了那边代码的某处 Dialogue: 0,1:02:05.32,1:02:07.23,Default,,0,0,0,,然而 我需要非常小心 Dialogue: 0,1:02:08.65,1:02:11.42,Default,,0,0,0,,而(FIB (- N 1))的值 Dialogue: 0,1:02:12.06,1:02:13.12,Default,,0,0,0,,我稍后会用到 Dialogue: 0,1:02:15.30,1:02:17.37,Default,,0,0,0,,(FIB (- N 1))的值 Dialogue: 0,1:02:17.61,1:02:18.48,Default,,0,0,0,,我需要它的值 Dialogue: 0,1:02:18.78,1:02:19.80,Default,,0,0,0,,我不能去改变它 Dialogue: 0,1:02:21.07,1:02:23.60,Default,,0,0,0,,因为我需要用它来加上(FIB (- N 2)) Dialogue: 0,1:02:24.15,1:02:25.88,Default,,0,0,0,,它是存放在寄存器中的 因此我需要保存它 Dialogue: 0,1:02:27.79,1:02:32.60,Default,,0,0,0,,所以现在我要用(SAVE VAL)来保存它 Dialogue: 0,1:02:33.78,1:02:35.44,Default,,0,0,0,,现在我就可以调用子过程了 Dialogue: 0,1:02:36.67,1:02:39.54,Default,,0,0,0,,(GOTO FIB-LOOP) Dialogue: 0,1:02:44.22,1:02:46.57,Default,,0,0,0,,现在 在进行更进一步计算之前 Dialogue: 0,1:02:46.80,1:02:49.36,Default,,0,0,0,,在结束这个程序之前 Dialogue: 0,1:02:49.39,1:02:51.05,Default,,0,0,0,,我想审视一下目前的代码片段 Dialogue: 0,1:02:51.23,1:02:56.00,Default,,0,0,0,,这里有一系列的指令 Dialogue: 0,1:02:57.84,1:02:59.08,Default,,0,0,0,,我可以对它们进行某些操作 Dialogue: 0,1:03:01.58,1:03:03.20,Default,,0,0,0,,这里 我有一个操作用来恢复CONTINUE Dialogue: 0,1:03:04.25,1:03:05.48,Default,,0,0,0,,一个操作用来保存CONTINUE Dialogue: 0,1:03:06.01,1:03:07.40,Default,,0,0,0,,然后给CONTINUE赋值 Dialogue: 0,1:03:08.70,1:03:10.64,Default,,0,0,0,,但这之中没有CONTINUE的其它引用 Dialogue: 0,1:03:13.84,1:03:15.48,Default,,0,0,0,,恢复之后又保存 Dialogue: 0,1:03:15.50,1:03:16.67,Default,,0,0,0,,使得栈没有被修改 Dialogue: 0,1:03:19.09,1:03:21.72,Default,,0,0,0,,唯一的区别就是 我给CONTINUE寄存器赋了值 Dialogue: 0,1:03:21.96,1:03:23.28,Default,,0,0,0,,一个存放在栈上的值 Dialogue: 0,1:03:24.33,1:03:25.79,Default,,0,0,0,,由于我现在改变了这个值 Dialogue: 0,1:03:26.44,1:03:27.93,Default,,0,0,0,,但这之间并没有引用这个值 Dialogue: 0,1:03:28.59,1:03:30.09,Default,,0,0,0,,这些指令就是不必要的 Dialogue: 0,1:03:31.76,1:03:35.39,Default,,0,0,0,,因此我们会移除它们 Dialogue: 0,1:03:38.88,1:03:40.78,Default,,0,0,0,,但我只有先把它们写出来 才会发现这个情况 Dialogue: 0,1:03:43.78,1:03:44.72,Default,,0,0,0,,真是这样吗? Dialogue: 0,1:03:45.77,1:03:46.60,Default,,0,0,0,,我并不知道 Dialogue: 0,1:03:48.61,1:03:52.91,Default,,0,0,0,,现在 我们要开始计算(FIB (- N 2))了 Dialogue: 0,1:03:53.66,1:03:54.59,Default,,0,0,0,,计算完毕后 Dialogue: 0,1:04:02.96,1:04:03.85,Default,,0,0,0,,我们又要做什么呢? Dialogue: 0,1:04:05.07,1:04:06.76,Default,,0,0,0,,我想 我们首先要做的就是 Dialogue: 0,1:04:06.99,1:04:07.88,Default,,0,0,0,,我们有两件事要做 Dialogue: 0,1:04:07.96,1:04:10.49,Default,,0,0,0,,目前VAL寄存器中的值 是有意义的 Dialogue: 0,1:04:10.92,1:04:11.98,Default,,0,0,0,,然而 栈上也有一个数据 Dialogue: 0,1:04:12.04,1:04:13.63,Default,,0,0,0,,需要恢复到VAL寄存器中 Dialogue: 0,1:04:14.81,1:04:16.57,Default,,0,0,0,,现在我需要非常小心的是 Dialogue: 0,1:04:16.88,1:04:18.99,Default,,0,0,0,,正确地给它们排序 以便计算乘法 Dialogue: 0,1:04:19.47,1:04:21.24,Default,,0,0,0,,现在 我可能会使用不同的约定 Dialogue: 0,1:04:21.47,1:04:23.52,Default,,0,0,0,,但我现在会采用非常挑剔的一种 Dialogue: 0,1:04:23.55,1:04:25.88,Default,,0,0,0,,栈上数据来自于哪个寄存器 就恢复到那个寄存器中 Dialogue: 0,1:04:26.74,1:04:28.28,Default,,0,0,0,,如果是这样的话 在这里我就要进行洗牌 Dialogue: 0,1:04:29.24,1:04:31.84,Default,,0,0,0,,这跟我有多少只手是同样的问题 Dialogue: 0,1:04:32.68,1:04:37.13,Default,,0,0,0,,现在我要给N赋值 Dialogue: 0,1:04:37.16,1:04:39.37,Default,,0,0,0,,因为我现在不再需要N了 N是无用的 Dialogue: 0,1:04:39.92,1:04:41.21,Default,,0,0,0,,获取当前VAL寄存器的值 Dialogue: 0,1:04:45.21,1:04:47.34,Default,,0,0,0,,也就是(FIB (- N 2))的值 Dialogue: 0,1:04:52.95,1:04:56.35,Default,,0,0,0,,现在 我就要恢复VAL寄存器了 Dialogue: 0,1:05:01.85,1:05:03.92,Default,,0,0,0,,这个RESTORE匹配这里的SAVE Dialogue: 0,1:05:05.58,1:05:08.83,Default,,0,0,0,,如果你非常仔细地研究发生了什么 Dialogue: 0,1:05:09.21,1:05:11.96,Default,,0,0,0,,会发现 RESTORE和SAVE总是成对的 Dialogue: 0,1:05:13.84,1:05:15.15,Default,,0,0,0,,现在 这里有个额外的SAVE Dialogue: 0,1:05:15.18,1:05:16.38,Default,,0,0,0,,当然 我们很快就会消灭它 Dialogue: 0,1:05:19.00,1:05:20.59,Default,,0,0,0,,恢复完VAL寄存器后 Dialogue: 0,1:05:20.94,1:05:22.57,Default,,0,0,0,,我就要恢复CONTINUE寄存器了 Dialogue: 0,1:05:31.15,1:05:32.40,Default,,0,0,0,,它匹配了这个 Dialogue: 0,1:05:34.80,1:05:37.85,Default,,0,0,0,,从这里到这里 Dialogue: 0,1:05:40.59,1:05:42.46,Default,,0,0,0,,这样就恢复了继续 Dialogue: 0,1:05:42.86,1:05:45.71,Default,,0,0,0,,这个表达式继续是由(FIB N)产生的 Dialogue: 0,1:05:46.46,1:05:47.84,Default,,0,0,0,,也就是我正尝试求解的 Dialogue: 0,1:05:47.85,1:05:49.32,Default,,0,0,0,,最主要的问题 Dialogue: 0,1:05:49.98,1:05:52.35,Default,,0,0,0,,我需要把(FIB N)的答案返回给这个继续 Dialogue: 0,1:05:52.54,1:05:54.03,Default,,0,0,0,,在我意识到N并不小于2之前 Dialogue: 0,1:05:54.16,1:05:56.60,Default,,0,0,0,,我一直保存着它们 Dialogue: 0,1:05:57.36,1:05:59.07,Default,,0,0,0,,因此 我需要进行一个复杂的运算 Dialogue: 0,1:06:00.84,1:06:02.57,Default,,0,0,0,,现在万事俱备 Dialogue: 0,1:06:03.24,1:06:04.36,Default,,0,0,0,,因此我要恢复它们 Dialogue: 0,1:06:05.42,1:06:21.08,Default,,0,0,0,,(ASSIGN VAL (+ (FETCH VAL) (FETCH N))) Dialogue: 0,1:06:27.44,1:06:28.60,Default,,0,0,0,,然后跳转到CONTINUE Dialogue: 0,1:06:38.26,1:06:44.78,Default,,0,0,0,,然后我就从(FIB N)中返回了出来 Dialogue: 0,1:06:45.39,1:06:46.57,Default,,0,0,0,,也就是FIB的一般情况 Dialogue: 0,1:06:47.11,1:06:50.60,Default,,0,0,0,,现在还有一些细节 需要我们填充 Dialogue: 0,1:06:50.99,1:06:55.53,Default,,0,0,0,,比如归纳的基本情况:可以立即得到答案 Dialogue: 0,1:07:02.54,1:07:06.59,Default,,0,0,0,,这不过就是 Dialogue: 0,1:07:06.60,1:07:11.85,Default,,0,0,0,,(ASSIGN VAL (FETCH N) Dialogue: 0,1:07:13.64,1:07:15.47,Default,,0,0,0,,因为N小于2 Dialogue: 0,1:07:15.50,1:07:16.89,Default,,0,0,0,,因此答案就是N Dialogue: 0,1:07:16.99,1:07:18.19,Default,,0,0,0,,跟源程序是一致的 Dialogue: 0,1:07:19.23,1:07:26.48,Default,,0,0,0,,(GOTO (FETCH CONTINUE)) Dialogue: 0,1:07:31.24,1:07:36.13,Default,,0,0,0,,最后就结束了 Dialogue: 0,1:07:43.46,1:07:45.64,Default,,0,0,0,,这是个相当复杂的程序 Dialogue: 0,1:07:45.64,1:07:47.34,Default,,0,0,0,,我之所以给你们演示这个程序 Dialogue: 0,1:07:47.50,1:07:49.21,Default,,0,0,0,,是因为我想让你们见识 Dialogue: 0,1:07:49.45,1:07:52.67,Default,,0,0,0,,我所遵守的栈使用准则 Dialogue: 0,1:07:53.32,1:07:55.21,Default,,0,0,0,,第一点就是 我不想保存那些 Dialogue: 0,1:07:56.92,1:07:58.12,Default,,0,0,0,,稍后不需要的值 Dialogue: 0,1:08:00.57,1:08:01.85,Default,,0,0,0,,我非常地小心 Dialogue: 0,1:08:01.85,1:08:02.91,Default,,0,0,0,,这非常重要 Dialogue: 0,1:08:03.94,1:08:06.52,Default,,0,0,0,,当然 人们还制定了其它的准则 Dialogue: 0,1:08:07.37,1:08:09.61,Default,,0,0,0,,来操作栈帧之类的东西 Dialogue: 0,1:08:10.19,1:08:11.39,Default,,0,0,0,,这些准则中 那些不再需要的东西 Dialogue: 0,1:08:11.40,1:08:12.64,Default,,0,0,0,,也需要保存并恢复 Dialogue: 0,1:08:12.67,1:08:15.26,Default,,0,0,0,,因为从某种意义上来说 这样做更容易些 Dialogue: 0,1:08:15.83,1:08:17.40,Default,,0,0,0,,但这会带来各种灾难 Dialogue: 0,1:08:18.59,1:08:20.25,Default,,0,0,0,,我们稍后就会见识一些 Dialogue: 0,1:08:21.44,1:08:24.24,Default,,0,0,0,,只保存那些你稍后需要的值 这很关键 Dialogue: 0,1:08:26.89,1:08:28.01,Default,,0,0,0,,这是非常重要的理念 Dialogue: 0,1:08:29.87,1:08:33.36,Default,,0,0,0,,无论谁保存了一个值 都应该由他来恢复 Dialogue: 0,1:08:33.76,1:08:35.32,Default,,0,0,0,,因为他需要这个值 Dialogue: 0,1:08:36.93,1:08:38.54,Default,,0,0,0,,在这样的准则中 Dialogue: 0,1:08:38.86,1:08:40.76,Default,,0,0,0,,你可以发现哪些数据是不必要的 Dialogue: 0,1:08:43.45,1:08:44.73,Default,,0,0,0,,哪些操作又是不重要的 Dialogue: 0,1:08:47.15,1:08:50.40,Default,,0,0,0,,我还想告诉你们 Dialogue: 0,1:08:51.66,1:08:54.67,Default,,0,0,0,,当然 你们看到的并不是全部的图景 Dialogue: 0,1:08:55.35,1:08:56.68,Default,,0,0,0,,假设我的系统中 Dialogue: 0,1:08:56.80,1:09:01.52,Default,,0,0,0,,具有像CAR、CDR、CONS这样的运算 Dialogue: 0,1:09:03.53,1:09:05.60,Default,,0,0,0,,或者创建一个向量 Dialogue: 0,1:09:05.88,1:09:07.32,Default,,0,0,0,,并引用它的第N个元素 Dialogue: 0,1:09:08.30,1:09:09.21,Default,,0,0,0,,等等运算 Dialogue: 0,1:09:10.40,1:09:13.60,Default,,0,0,0,,然而 就在这个层次的细节来说 Dialogue: 0,1:09:13.87,1:09:17.85,Default,,0,0,0,,我们可以在数据通路中把它们视为基本运算 Dialogue: 0,1:09:18.75,1:09:21.95,Default,,0,0,0,,换句话说 我们可以认为 有一台机器 Dialogue: 0,1:09:22.32,1:09:24.11,Default,,0,0,0,,包含了APPEND机器 Dialogue: 0,1:09:24.20,1:09:26.46,Default,,0,0,0,,它通过(CONS (CAR X) Dialogue: 0,1:09:26.64,1:09:29.80,Default,,0,0,0,,(APPEND (CDR X) Y)来实现 Dialogue: 0,1:09:29.88,1:09:33.18,Default,,0,0,0,,哦 天啊 这就跟阶乘机器有相同的结构 Dialogue: 0,1:09:33.63,1:09:35.29,Default,,0,0,0,,当然 它有相同的结构 Dialogue: 0,1:09:36.54,1:09:37.27,Default,,0,0,0,,我们有什么呢? Dialogue: 0,1:09:37.27,1:09:39.39,Default,,0,0,0,,我们有某种东西 其中有 Dialogue: 0,1:09:39.76,1:09:42.48,Default,,0,0,0,,诸如X、Y之类的寄存器 Dialogue: 0,1:09:42.51,1:09:45.12,Default,,0,0,0,,有时X会移动到Y中 Dialogue: 0,1:09:45.28,1:09:46.75,Default,,0,0,0,,或者X会取得Y的值 Dialogue: 0,1:09:46.93,1:09:50.11,Default,,0,0,0,,我们或许要需要能够进行CONS运算 Dialogue: 0,1:09:51.70,1:09:57.74,Default,,0,0,0,,我记不清这个系统中是否需要这样的东西 Dialogue: 0,1:09:57.76,1:10:01.10,Default,,0,0,0,,但CONS有点类似于减法器或加法器之类的东西 Dialogue: 0,1:10:01.42,1:10:02.70,Default,,0,0,0,,它把两个东西结合起来 Dialogue: 0,1:10:02.73,1:10:04.27,Default,,0,0,0,,然后产生一个序对 Dialogue: 0,1:10:04.51,1:10:06.49,Default,,0,0,0,,然后会把输出结果送入到这里 Dialogue: 0,1:10:07.60,1:10:09.72,Default,,0,0,0,,可能还有一个叫做CAR的组件 Dialogue: 0,1:10:12.88,1:10:16.22,Default,,0,0,0,,它的结果是 -- 某个东西的CAR部分 Dialogue: 0,1:10:16.92,1:10:19.55,Default,,0,0,0,,我还可以取得某物的CDR部分 等等 Dialogue: 0,1:10:20.15,1:10:22.30,Default,,0,0,0,,但我们不应该害怕这么说 Dialogue: 0,1:10:22.92,1:10:24.24,Default,,0,0,0,,因为最坏的情况不过 Dialogue: 0,1:10:24.94,1:10:26.41,Default,,0,0,0,,当我们打开CONS后 Dialogue: 0,1:10:27.31,1:10:29.82,Default,,0,0,0,,会发现其中存在某台机器 Dialogue: 0,1:10:31.88,1:10:34.44,Default,,0,0,0,,CONS可能会与CAR和CDR有所重叠 Dialogue: 0,1:10:35.50,1:10:38.12,Default,,0,0,0,,就像加法和减法有所重叠一样 Dialogue: 0,1:10:38.57,1:10:39.85,Default,,0,0,0,,它们本质上都是一样的 Dialogue: 0,1:10:41.21,1:10:42.60,Default,,0,0,0,,CONS、CAR和CDR将会有所重叠 Dialogue: 0,1:10:42.62,1:10:44.52,Default,,0,0,0,,我们会发现其中有小型控制器 Dialogue: 0,1:10:45.50,1:10:46.54,Default,,0,0,0,,小型的数据通路 Dialogue: 0,1:10:48.03,1:10:49.64,Default,,0,0,0,,其中还有一些寄存器 Dialogue: 0,1:10:50.00,1:10:52.86,Default,,0,0,0,,一些其它的像这样的东西 Dialogue: 0,1:10:53.30,1:10:54.41,Default,,0,0,0,,并且 也许在这之中 Dialogue: 0,1:10:54.43,1:10:56.16,Default,,0,0,0,,可能也有无穷的部分 Dialogue: 0,1:10:56.46,1:10:58.70,Default,,0,0,0,,又或者是半无穷的 之类的 Dialogue: 0,1:10:58.81,1:11:00.65,Default,,0,0,0,,这些都是统一的东西 Dialogue: 0,1:11:00.96,1:11:02.03,Default,,0,0,0,,也就是我们所谓的“内存” Dialogue: 0,1:11:06.57,1:11:08.83,Default,,0,0,0,,有限的内存也能无穷地存储 对此我一点也不吃惊 Dialogue: 0,1:11:09.33,1:11:11.07,Default,,0,0,0,,实际上它就是这样的 我们之后就会了解 Dialogue: 0,1:11:13.32,1:11:14.57,Default,,0,0,0,,那么 有什么疑问么? Dialogue: 0,1:11:24.34,1:11:25.80,Default,,0,0,0,,天啊!你们都一言不发 Dialogue: 0,1:11:28.67,1:11:30.33,Default,,0,0,0,,假设我说得都是谎言吧! Dialogue: 0,1:11:39.69,1:11:40.38,Default,,0,0,0,,好吧 Dialogue: 0,1:11:41.99,1:11:42.52,Default,,0,0,0,,谢谢大家 Dialogue: 0,1:11:42.52,1:11:43.28,Default,,0,0,0,,我们下课吧! Dialogue: 0,1:11:44.23,1:11:55.15,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:11:44.23,1:11:55.15,Default,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec9a.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: EN Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 535 Active Line: 539 Video Position: 51787 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:12.03,0:00:14.03,EN,,0,0,0,,Register Machines Dialogue: 0,0:00:17.26,0:00:19.07,EN,,0,0,0,,PROFESSOR: Well, up 'til now, I suppose, Dialogue: 0,0:00:19.32,0:00:23.93,EN,,0,0,0,,we've been learning about a lot of techniques for Dialogue: 0,0:00:24.09,0:00:28.83,EN,,0,0,0,,organizing big programs, symbolic manipulation a bit, Dialogue: 0,0:00:30.84,0:00:35.60,EN,,0,0,0,,some of the technology that you use for establishing languages, Dialogue: 0,0:00:35.63,0:00:36.78,EN,,0,0,0,,one in terms of another, Dialogue: 0,0:00:37.10,0:00:39.92,EN,,0,0,0,,which is used for organizing very large programs. Dialogue: 0,0:00:39.96,0:00:42.30,EN,,0,0,0,,In fact, the nicest programs I know Dialogue: 0,0:00:42.44,0:00:44.43,EN,,0,0,0,,look more like a pile of languages Dialogue: 0,0:00:44.91,0:00:47.96,EN,,0,0,0,,than like a decomposition of a problem into parts. Dialogue: 0,0:00:49.90,0:00:51.45,EN,,0,0,0,,Well, I suppose at this point, Dialogue: 0,0:00:52.08,0:00:53.58,EN,,0,0,0,,there are still, however, a few mysteries Dialogue: 0,0:00:53.61,0:00:55.32,EN,,0,0,0,,about how this sort of stuff works. Dialogue: 0,0:00:56.26,0:00:59.68,EN,,0,0,0,,And so what we'd like to do now is Dialogue: 0,0:01:00.03,0:01:02.60,EN,,0,0,0,,diverge from the plan of Dialogue: 0,0:01:02.96,0:01:05.42,EN,,0,0,0,,telling you how to organize big programs, Dialogue: 0,0:01:05.45,0:01:08.19,EN,,0,0,0,,and rather tell you something about the mechanisms Dialogue: 0,0:01:08.52,0:01:11.71,EN,,0,0,0,,by which these things can be made to work. Dialogue: 0,0:01:12.19,0:01:14.83,EN,,0,0,0,,The main reason for this is Dialogue: 0,0:01:15.80,0:01:17.87,EN,,0,0,0,,demystification, if you will, Dialogue: 0,0:01:18.65,0:01:20.54,EN,,0,0,0,,that we have a lot of mysteries left, Dialogue: 0,0:01:21.08,0:01:25.48,EN,,0,0,0,,like exactly how it is the case that a program is controlled, Dialogue: 0,0:01:26.08,0:01:30.38,EN,,0,0,0,,how a computer knows what the next thing to do is, Dialogue: 0,0:01:30.52,0:01:31.74,EN,,0,0,0,,or something like that. Dialogue: 0,0:01:32.43,0:01:35.56,EN,,0,0,0,,And what I'd like to do now is make that clear to you Dialogue: 0,0:01:35.85,0:01:39.10,EN,,0,0,0,,that even if you've never played with a physical computer before, Dialogue: 0,0:01:39.56,0:01:43.50,EN,,0,0,0,,the mechanism is really very simple, Dialogue: 0,0:01:44.33,0:01:46.35,EN,,0,0,0,,and that you can understand it completely with no trouble. Dialogue: 0,0:01:47.65,0:01:51.24,EN,,0,0,0,,So I'd like to start by imagining that we-- Dialogue: 0,0:01:51.32,0:01:52.91,EN,,0,0,0,,well, the way we're going to do this, by the way, Dialogue: 0,0:01:52.96,0:01:55.80,EN,,0,0,0,,is we're going to take some very simple Lisp programs, Dialogue: 0,0:01:56.54,0:01:58.12,EN,,0,0,0,,very simple Lisp programs, Dialogue: 0,0:01:59.04,0:02:00.62,EN,,0,0,0,,and transform them into hardware. Dialogue: 0,0:02:02.16,0:02:04.16,EN,,0,0,0,,I'm not going to worry about some intermediate step Dialogue: 0,0:02:04.70,0:02:07.45,EN,,0,0,0,,of going through some existing computer machine language Dialogue: 0,0:02:07.47,0:02:09.05,EN,,0,0,0,,and then showing you how that computer works, Dialogue: 0,0:02:09.82,0:02:12.00,EN,,0,0,0,,because that's not as illuminating. Dialogue: 0,0:02:12.75,0:02:14.17,EN,,0,0,0,,So what I'm really going to show you Dialogue: 0,0:02:14.51,0:02:17.48,EN,,0,0,0,,is how a piece of machinery can be built Dialogue: 0,0:02:18.03,0:02:22.04,EN,,0,0,0,,to do a job that you have written down as a program. Dialogue: 0,0:02:22.04,0:02:24.03,EN,,0,0,0,,That program is, in fact, a description of a machine. Dialogue: 0,0:02:25.76,0:02:27.69,EN,,0,0,0,,We're going to start with a very simple program, Dialogue: 0,0:02:28.09,0:02:30.81,EN,,0,0,0,,proceed to show you some simple mechanisms, Dialogue: 0,0:02:31.39,0:02:33.68,EN,,0,0,0,,proceed to a few more complicated programs, Dialogue: 0,0:02:34.30,0:02:37.42,EN,,0,0,0,,and then later show you a not very complicated program, Dialogue: 0,0:02:37.44,0:02:41.23,EN,,0,0,0,,how the evaluator transforms into a piece of hardware. Dialogue: 0,0:02:41.23,0:02:42.06,EN,,0,0,0,,And of course at that point, Dialogue: 0,0:02:42.08,0:02:44.08,EN,,0,0,0,,you have made the universal transition Dialogue: 0,0:02:44.22,0:02:46.88,EN,,0,0,0,,and can execute any program imaginable Dialogue: 0,0:02:47.16,0:02:48.80,EN,,0,0,0,,with a piece of well-defined hardware. Dialogue: 0,0:02:51.72,0:02:52.91,EN,,0,0,0,,Well, let's start up now, Dialogue: 0,0:02:53.05,0:02:55.31,EN,,0,0,0,,give you a real concrete feeling for this sort of thing. Dialogue: 0,0:02:55.44,0:02:57.66,EN,,0,0,0,,Let's start with a very simple program. Dialogue: 0,0:02:59.60,0:03:00.85,EN,,0,0,0,,Here's Euclid's algorithm. Dialogue: 0,0:03:03.88,0:03:07.00,EN,,0,0,0,,It's actually a little bit more modern than Euclid's algorithm. Dialogue: 0,0:03:07.02,0:03:10.09,EN,,0,0,0,,Euclid's algorithm for computing the greatest common divisor of two numbers Dialogue: 0,0:03:10.41,0:03:13.60,EN,,0,0,0,,was invented 350 BC, I think. Dialogue: 0,0:03:14.30,0:03:15.69,EN,,0,0,0,,It's the oldest known algorithm. Dialogue: 0,0:03:19.32,0:03:23.34,EN,,0,0,0,,But here we're going to talk about GCD of A and B, Dialogue: 0,0:03:23.36,0:03:25.61,EN,,0,0,0,,the Greatest Common Divisor or two numbers, A and B. Dialogue: 0,0:03:26.20,0:03:28.91,EN,,0,0,0,,And the algorithm is extremely simple. Dialogue: 0,0:03:29.50,0:03:31.08,EN,,0,0,0,,If B is 0, Dialogue: 0,0:03:34.16,0:03:36.83,EN,,0,0,0,,then the result is going to be A. Dialogue: 0,0:03:37.52,0:03:43.61,EN,,0,0,0,,Otherwise, the result is the GCD of B Dialogue: 0,0:03:44.49,0:03:53.39,EN,,0,0,0,,and the remainder when A is divided by B. Dialogue: 0,0:03:58.53,0:04:01.90,EN,,0,0,0,,So this we have here is a very simple iterative process. Dialogue: 0,0:04:02.03,0:04:04.08,EN,,0,0,0,,This a simple recursive procedure, Dialogue: 0,0:04:04.38,0:04:07.53,EN,,0,0,0,,recursively defined procedure, recursive definition, Dialogue: 0,0:04:07.71,0:04:09.26,EN,,0,0,0,,which yields an iterative process. Dialogue: 0,0:04:09.95,0:04:12.46,EN,,0,0,0,,And the way it works is that every step, Dialogue: 0,0:04:12.80,0:04:15.10,EN,,0,0,0,,it determines whether B was zero. Dialogue: 0,0:04:16.24,0:04:18.80,EN,,0,0,0,,And if B is 0, we got the answer in A. Dialogue: 0,0:04:19.63,0:04:22.46,EN,,0,0,0,,Otherwise, we make another step Dialogue: 0,0:04:22.49,0:04:23.87,EN,,0,0,0,,where A is the old B, Dialogue: 0,0:04:23.88,0:04:27.04,EN,,0,0,0,,and B is the remainder of the old A divided by the old B. Dialogue: 0,0:04:28.76,0:04:29.55,EN,,0,0,0,,Very simple. Dialogue: 0,0:04:31.11,0:04:32.72,EN,,0,0,0,,Now this, I've already told you Dialogue: 0,0:04:32.99,0:04:34.86,EN,,0,0,0,,some of the mechanism by just saying it that way. Dialogue: 0,0:04:34.86,0:04:35.90,EN,,0,0,0,,I said it in time. Dialogue: 0,0:04:36.36,0:04:37.72,EN,,0,0,0,,I said there are certain steps, Dialogue: 0,0:04:38.14,0:04:39.32,EN,,0,0,0,,and that, in fact, Dialogue: 0,0:04:39.52,0:04:40.86,EN,,0,0,0,,one of the things you can see here Dialogue: 0,0:04:41.18,0:04:43.69,EN,,0,0,0,,is that one of the reasons why this is iterative Dialogue: 0,0:04:43.95,0:04:47.68,EN,,0,0,0,,is nothing is needed of the last step to get the answer. Dialogue: 0,0:04:49.44,0:04:55.29,EN,,0,0,0,,All of the information that's needed to run this algorithm is in A and B. Dialogue: 0,0:04:55.74,0:04:57.80,EN,,0,0,0,,It has two well-defined state variables. Dialogue: 0,0:05:00.47,0:05:02.33,EN,,0,0,0,,So I'm going to define a machine for you Dialogue: 0,0:05:03.98,0:05:05.55,EN,,0,0,0,,can compute you GCDs. Dialogue: 0,0:05:06.56,0:05:07.12,EN,,0,0,0,,Now let's see. Dialogue: 0,0:05:07.12,0:05:11.28,EN,,0,0,0,,Every computer that's ever been made that's a single-process computer, Dialogue: 0,0:05:11.80,0:05:14.08,EN,,0,0,0,,as opposed to a multiprocessor of some sort, Dialogue: 0,0:05:15.04,0:05:16.59,EN,,0,0,0,,is made according to the same plan. Dialogue: 0,0:05:17.84,0:05:19.53,EN,,0,0,0,,The plan is the computer has two parts, Dialogue: 0,0:05:20.57,0:05:22.35,EN,,0,0,0,,a part called the datapaths, Dialogue: 0,0:05:23.10,0:05:24.36,EN,,0,0,0,,and a part called the controller. Dialogue: 0,0:05:25.91,0:05:29.28,EN,,0,0,0,,The datapaths correspond to a calculator that you might have. Dialogue: 0,0:05:29.71,0:05:31.87,EN,,0,0,0,,It contains certain registers that remember things, Dialogue: 0,0:05:31.90,0:05:33.13,EN,,0,0,0,,and you've all used calculators. Dialogue: 0,0:05:33.56,0:05:35.34,EN,,0,0,0,,It has some buttons on it and some lights. Dialogue: 0,0:05:37.03,0:05:38.49,EN,,0,0,0,,And so by pushing the various buttons, Dialogue: 0,0:05:38.52,0:05:41.34,EN,,0,0,0,,you can cause operations to happen inside there among the registers, Dialogue: 0,0:05:41.87,0:05:43.48,EN,,0,0,0,,and some of the results to be displayed. Dialogue: 0,0:05:45.16,0:05:46.25,EN,,0,0,0,,That's completely mechanical. Dialogue: 0,0:05:46.25,0:05:49.55,EN,,0,0,0,,You could imagine that box has no intelligence in it. Dialogue: 0,0:05:50.90,0:05:53.28,EN,,0,0,0,,Now it might be very impressive that it can produce the sine of a number, Dialogue: 0,0:05:53.53,0:05:58.97,EN,,0,0,0,,but that at least is apparently possibly mechanical. Dialogue: 0,0:05:58.97,0:06:01.71,EN,,0,0,0,,At least, I could open that up in the same way I'm about to open GCD. Dialogue: 0,0:06:02.69,0:06:04.36,EN,,0,0,0,,So this may have a whole computer inside of it, Dialogue: 0,0:06:04.68,0:06:05.69,EN,,0,0,0,,but that's not interesting. Dialogue: 0,0:06:05.94,0:06:07.10,EN,,0,0,0,,Addition is certainly simple. Dialogue: 0,0:06:08.20,0:06:09.84,EN,,0,0,0,,That can be done without any further mechanism. Dialogue: 0,0:06:10.89,0:06:15.64,EN,,0,0,0,,Now also, if we were to look at the other half, the controller, Dialogue: 0,0:06:15.93,0:06:17.39,EN,,0,0,0,,that's a part that's dumb, too. Dialogue: 0,0:06:18.19,0:06:19.16,EN,,0,0,0,,It pushes the buttons. Dialogue: 0,0:06:20.35,0:06:21.52,EN,,0,0,0,,It pushes them according to the sequence, Dialogue: 0,0:06:21.55,0:06:22.84,EN,,0,0,0,,which is written down on a piece of paper, Dialogue: 0,0:06:24.27,0:06:25.64,EN,,0,0,0,,and observes the lights. Dialogue: 0,0:06:26.29,0:06:29.44,EN,,0,0,0,,And every so often, it comes to a place in a sequence that says, Dialogue: 0,0:06:29.47,0:06:32.37,EN,,0,0,0,,if light A is on, do this sequence. Dialogue: 0,0:06:32.37,0:06:33.85,EN,,0,0,0,,Otherwise, do that sequence. Dialogue: 0,0:06:34.62,0:06:37.45,EN,,0,0,0,,And thereby, there's no complexity there either. Dialogue: 0,0:06:38.35,0:06:39.32,EN,,0,0,0,,Well, let's just draw that Dialogue: 0,0:06:39.34,0:06:40.57,EN,,0,0,0,,and see what we feel about that. Dialogue: 0,0:06:42.51,0:06:44.84,EN,,0,0,0,,So for computing GCDs, Dialogue: 0,0:06:45.88,0:06:49.52,EN,,0,0,0,,what I want you to think about is that there are these registers. Dialogue: 0,0:06:50.56,0:06:53.02,EN,,0,0,0,,A register is a place where I store a number, in this case. Dialogue: 0,0:06:53.52,0:06:54.65,EN,,0,0,0,,And this one's called a. Dialogue: 0,0:06:56.81,0:06:58.70,EN,,0,0,0,,And then there's another one for storing b. Dialogue: 0,0:07:03.17,0:07:05.45,EN,,0,0,0,,Now we have to see what things we can do with these registers, Dialogue: 0,0:07:05.98,0:07:08.73,EN,,0,0,0,,and they're not entirely obvious what you can do with them. Dialogue: 0,0:07:09.84,0:07:11.72,EN,,0,0,0,,Well, we have to see what things we need to do with them. Dialogue: 0,0:07:11.82,0:07:13.87,EN,,0,0,0,,We're looking at the problem we're trying to solve. Dialogue: 0,0:07:14.03,0:07:16.09,EN,,0,0,0,,One of the important things for designing a computer, Dialogue: 0,0:07:17.10,0:07:19.58,EN,,0,0,0,,which I think most designers don't do, Dialogue: 0,0:07:20.20,0:07:21.88,EN,,0,0,0,,is you stay the problem you want to solve Dialogue: 0,0:07:22.62,0:07:25.18,EN,,0,0,0,,and then use what you learn from studying the problem you want to solve Dialogue: 0,0:07:25.44,0:07:27.28,EN,,0,0,0,,to put in the mechanisms needed to solve it Dialogue: 0,0:07:27.53,0:07:28.70,EN,,0,0,0,,in the computer you're building, Dialogue: 0,0:07:28.81,0:07:30.08,EN,,0,0,0,,no more no less. Dialogue: 0,0:07:32.14,0:07:33.96,EN,,0,0,0,,Now it may be that the problem you're trying to solve Dialogue: 0,0:07:34.24,0:07:35.40,EN,,0,0,0,,is everybody's problem, Dialogue: 0,0:07:36.06,0:07:37.58,EN,,0,0,0,,in which case you have to build in a universal Dialogue: 0,0:07:37.60,0:07:39.29,EN,,0,0,0,,interpreter of some language. Dialogue: 0,0:07:40.19,0:07:42.32,EN,,0,0,0,,But you shouldn't put any more in than required Dialogue: 0,0:07:42.35,0:07:44.25,EN,,0,0,0,,to build the universal interpreter of some language. Dialogue: 0,0:07:44.44,0:07:45.85,EN,,0,0,0,,We'll worry about that in a second. Dialogue: 0,0:07:47.23,0:07:49.93,EN,,0,0,0,,OK, going back to here, let's see. Dialogue: 0,0:07:49.93,0:07:51.24,EN,,0,0,0,,What do we have to be able to do? Dialogue: 0,0:07:51.79,0:07:54.14,EN,,0,0,0,,Well, somehow, we have to be able to get B into A. Dialogue: 0,0:07:56.08,0:07:59.60,EN,,0,0,0,,We have to be able to get the old value of B into the value of A. Dialogue: 0,0:08:00.38,0:08:03.32,EN,,0,0,0,,So we have to have some path by which stuff can flow Dialogue: 0,0:08:03.34,0:08:04.76,EN,,0,0,0,,whatever this information is, Dialogue: 0,0:08:05.37,0:08:06.57,EN,,0,0,0,,OK? from b to a. Dialogue: 0,0:08:07.39,0:08:09.26,EN,,0,0,0,,I'm going to draw that with by an arrow Dialogue: 0,0:08:09.52,0:08:12.62,EN,,0,0,0,,saying that it is possible to move the contents of b into a, Dialogue: 0,0:08:12.96,0:08:14.57,EN,,0,0,0,,replacing the value of a. Dialogue: 0,0:08:15.12,0:08:16.73,EN,,0,0,0,,And there's a little button here which you push Dialogue: 0,0:08:17.48,0:08:18.56,EN,,0,0,0,,which allows that to happen. Dialogue: 0,0:08:19.71,0:08:20.78,EN,,0,0,0,,That's what the little x is here. Dialogue: 0,0:08:23.07,0:08:23.93,EN,,0,0,0,,Now it's also the case Dialogue: 0,0:08:23.95,0:08:26.28,EN,,0,0,0,,that I have to be able to compute the remainder of a and b. Dialogue: 0,0:08:27.00,0:08:28.49,EN,,0,0,0,,Now that may be a complicated mess. Dialogue: 0,0:08:28.86,0:08:30.86,EN,,0,0,0,,On the other hand, I'm going to make it a small box. Dialogue: 0,0:08:31.96,0:08:33.92,EN,,0,0,0,,If we have to, we may open up that box Dialogue: 0,0:08:34.12,0:08:35.63,EN,,0,0,0,,and look inside and see what it is. Dialogue: 0,0:08:37.77,0:08:39.16,EN,,0,0,0,,So here, I'm going to have a little box, Dialogue: 0,0:08:39.20,0:08:40.38,EN,,0,0,0,,which I'm going to draw this way, Dialogue: 0,0:08:43.16,0:08:44.38,EN,,0,0,0,,which we'll call the remainder. Dialogue: 0,0:08:46.44,0:08:48.60,EN,,0,0,0,,And it's going to take in a. Dialogue: 0,0:08:50.91,0:08:52.16,EN,,0,0,0,,That's going to take in b. Dialogue: 0,0:08:54.37,0:08:56.51,EN,,0,0,0,,And it's going to put out something, Dialogue: 0,0:08:58.89,0:09:00.46,EN,,0,0,0,,the remainder of a divided by b. Dialogue: 0,0:09:02.29,0:09:03.61,EN,,0,0,0,,Another thing we have to see here is Dialogue: 0,0:09:03.64,0:09:06.06,EN,,0,0,0,,that we have to be able to test whether b is equal to 0. Dialogue: 0,0:09:08.00,0:09:09.66,EN,,0,0,0,,Well, that means somebody's got to be looking at-- Dialogue: 0,0:09:10.00,0:09:12.30,EN,,0,0,0,,a thing that's looking at the value of b. Dialogue: 0,0:09:13.39,0:09:14.40,EN,,0,0,0,,I have a light bulb here Dialogue: 0,0:09:15.85,0:09:17.39,EN,,0,0,0,,which lights up if b equals 0. Dialogue: 0,0:09:21.11,0:09:22.01,EN,,0,0,0,,That's its job. Dialogue: 0,0:09:24.03,0:09:26.78,EN,,0,0,0,,And finally, I suppose, because of the fact Dialogue: 0,0:09:26.96,0:09:30.43,EN,,0,0,0,,that we want the new value of a to be the old value of b, Dialogue: 0,0:09:30.46,0:09:34.41,EN,,0,0,0,,and simultaneously the new value of b to be something I've done with a, Dialogue: 0,0:09:35.28,0:09:37.60,EN,,0,0,0,,and if I plan to make my machine Dialogue: 0,0:09:37.80,0:09:39.74,EN,,0,0,0,,such that everything happens one at a time, Dialogue: 0,0:09:40.20,0:09:41.40,EN,,0,0,0,,one motion at a time, Dialogue: 0,0:09:41.61,0:09:43.42,EN,,0,0,0,,and I can't put two numbers in a register, Dialogue: 0,0:09:44.03,0:09:46.30,EN,,0,0,0,,then I have to have another place to put one while I'm interchanging. Dialogue: 0,0:09:49.29,0:09:49.60,EN,,0,0,0,,OK? Dialogue: 0,0:09:50.00,0:09:51.85,EN,,0,0,0,,I can't interchange the two things in my hands, Dialogue: 0,0:09:52.11,0:09:53.72,EN,,0,0,0,,unless I either put two in one hand Dialogue: 0,0:09:53.72,0:09:55.13,EN,,0,0,0,,and then pull it back the other way, Dialogue: 0,0:09:55.50,0:09:56.91,EN,,0,0,0,,or unless I put one down, Dialogue: 0,0:09:57.02,0:09:58.68,EN,,0,0,0,,pick it up, and put the other one, like that Dialogue: 0,0:09:59.64,0:10:00.94,EN,,0,0,0,,unless I'm a juggler, Dialogue: 0,0:10:01.66,0:10:03.50,EN,,0,0,0,,which I'm not, as you can see, Dialogue: 0,0:10:04.65,0:10:07.36,EN,,0,0,0,,in which case I have a possibility of timing errors. Dialogue: 0,0:10:08.85,0:10:11.04,EN,,0,0,0,,In fact, much of the type of computer design Dialogue: 0,0:10:11.07,0:10:12.68,EN,,0,0,0,,people do involves timing errors, Dialogue: 0,0:10:13.12,0:10:15.00,EN,,0,0,0,,of some potential timing errors, Dialogue: 0,0:10:15.24,0:10:16.43,EN,,0,0,0,,which I don't much like. Dialogue: 0,0:10:17.34,0:10:18.64,EN,,0,0,0,,But. So for that reason, Dialogue: 0,0:10:18.68,0:10:21.21,EN,,0,0,0,,I have to have a place to put the third thing down Dialogue: 0,0:10:22.06,0:10:23.29,EN,,0,0,0,,the second one of them down. Dialogue: 0,0:10:23.41,0:10:24.72,EN,,0,0,0,,So I have a place called t, Dialogue: 0,0:10:24.75,0:10:26.84,EN,,0,0,0,,which is a register just for temporary, t, Dialogue: 0,0:10:28.59,0:10:29.63,EN,,0,0,0,,with a button on it. Dialogue: 0,0:10:30.47,0:10:31.88,EN,,0,0,0,,And then I'll take the result of that, Dialogue: 0,0:10:31.90,0:10:34.14,EN,,0,0,0,,since I have to take that and put into b, over here, Dialogue: 0,0:10:34.68,0:10:36.73,EN,,0,0,0,,we'll take the result of that and go like this, Dialogue: 0,0:10:38.41,0:10:39.30,EN,,0,0,0,,and a button here. Dialogue: 0,0:10:42.43,0:10:45.84,EN,,0,0,0,,So that's the datapaths of a GCD machine. Dialogue: 0,0:10:47.60,0:10:48.57,EN,,0,0,0,,Now what's the controller? Dialogue: 0,0:10:49.74,0:10:51.28,EN,,0,0,0,,Controller's a very simple thing, too. Dialogue: 0,0:10:52.28,0:10:53.26,EN,,0,0,0,,The machine has a state. Dialogue: 0,0:10:54.38,0:10:57.72,EN,,0,0,0,,The way I like to visualize that is that I've got a maze. Dialogue: 0,0:10:59.01,0:11:03.20,EN,,0,0,0,,And the maze has a bunch of places connected by directed arrows. Dialogue: 0,0:11:04.43,0:11:05.60,EN,,0,0,0,,And what I have is a marble, Dialogue: 0,0:11:06.46,0:11:09.07,EN,,0,0,0,,which represents the state of the controller. Dialogue: 0,0:11:10.74,0:11:12.27,EN,,0,0,0,,The marble rolls around in the maze. Dialogue: 0,0:11:13.74,0:11:17.15,EN,,0,0,0,,Of course, this analogy breaks down for energy reasons. Dialogue: 0,0:11:17.15,0:11:19.08,EN,,0,0,0,,I sometimes have to pump the marble up to the top, Dialogue: 0,0:11:19.12,0:11:21.85,EN,,0,0,0,,because it's going to otherwise be a perpetual motion machine. Dialogue: 0,0:11:22.00,0:11:23.32,EN,,0,0,0,,But not worrying about that, Dialogue: 0,0:11:23.90,0:11:25.90,EN,,0,0,0,,this is not a physical analogy. Dialogue: 0,0:11:26.08,0:11:27.42,EN,,0,0,0,,This marble rolls around. Dialogue: 0,0:11:27.68,0:11:29.56,EN,,0,0,0,,And every time it rolls around certain bumpers, Dialogue: 0,0:11:29.68,0:11:30.97,EN,,0,0,0,,like in a pinball machine, Dialogue: 0,0:11:31.26,0:11:32.60,EN,,0,0,0,,it pushes one of these buttons. Dialogue: 0,0:11:34.83,0:11:37.50,EN,,0,0,0,,And every so often, it comes to a place, which is a division, Dialogue: 0,0:11:38.62,0:11:39.68,EN,,0,0,0,,where it has to make a choice. Dialogue: 0,0:11:40.25,0:11:42.36,EN,,0,0,0,,And there's a flap, which is controlled by this. Dialogue: 0,0:11:46.00,0:11:48.82,EN,,0,0,0,,So that's a really mechanical way of thinking about it. Dialogue: 0,0:11:48.82,0:11:51.05,EN,,0,0,0,,Of course, controllers not these days, are not built that way Dialogue: 0,0:11:51.08,0:11:51.84,EN,,0,0,0,,in real computers. Dialogue: 0,0:11:51.84,0:11:56.01,EN,,0,0,0,,They're built with a little bit of ROM and a state register. Dialogue: 0,0:11:56.61,0:11:58.73,EN,,0,0,0,,But there was a time, like the DEC PDP-6, Dialogue: 0,0:11:59.29,0:12:01.02,EN,,0,0,0,,where that's how you built the controller of a machine. Dialogue: 0,0:12:01.80,0:12:03.61,EN,,0,0,0,,There was a bit that ran around the delay line, Dialogue: 0,0:12:05.69,0:12:08.14,EN,,0,0,0,,and it triggered things as it went by. Dialogue: 0,0:12:08.58,0:12:10.70,EN,,0,0,0,,And it would come back to the beginning and get fed round again. Dialogue: 0,0:12:11.99,0:12:13.72,EN,,0,0,0,,And of course, there were all sorts of great bugs you could have Dialogue: 0,0:12:13.74,0:12:17.67,EN,,0,0,0,,like two bits going around, two marbles. Dialogue: 0,0:12:17.67,0:12:19.26,EN,,0,0,0,,And then the machine has lost its marbles. Dialogue: 0,0:12:19.45,0:12:20.20,EN,,0,0,0,,That happens, too. Dialogue: 0,0:12:20.98,0:12:21.58,EN,,0,0,0,,Oh, well. Dialogue: 0,0:12:22.27,0:12:24.22,EN,,0,0,0,,So anyway, for this machine, Dialogue: 0,0:12:24.27,0:12:25.48,EN,,0,0,0,,what I have to do is the following. Dialogue: 0,0:12:25.80,0:12:27.74,EN,,0,0,0,,I'm going to start my maze here. Dialogue: 0,0:12:30.52,0:12:32.73,EN,,0,0,0,,And the first thing I've got to do, Dialogue: 0,0:12:33.76,0:12:36.75,EN,,0,0,0,,is in a notation which many of you are familiar with, Dialogue: 0,0:12:37.07,0:12:39.85,EN,,0,0,0,,is b equal to zero, a test. Dialogue: 0,0:12:41.50,0:12:43.79,EN,,0,0,0,,And there's a possibility, either yes, Dialogue: 0,0:12:43.93,0:12:45.58,EN,,0,0,0,,in which case I'm done. Dialogue: 0,0:12:49.79,0:12:51.26,EN,,0,0,0,,Otherwise, if no, Dialogue: 0,0:12:52.70,0:12:54.32,EN,,0,0,0,,then I'm going have to roll over some bumpers. Dialogue: 0,0:12:55.00,0:12:56.46,EN,,0,0,0,,I'm going to do it in the following order. Dialogue: 0,0:12:57.42,0:13:03.40,EN,,0,0,0,,I want to, I want to do this interchange game. Dialogue: 0,0:13:04.05,0:13:05.80,EN,,0,0,0,,Now first, since I need both a and b, Dialogue: 0,0:13:06.32,0:13:08.57,EN,,0,0,0,,but then the first-- and this is not necessary-- Dialogue: 0,0:13:08.65,0:13:09.72,EN,,0,0,0,,I want to collect this. Dialogue: 0,0:13:11.07,0:13:12.62,EN,,0,0,0,,This is the thing that's going to go into b. Dialogue: 0,0:13:13.24,0:13:14.03,EN,,0,0,0,,So I'm going to say, Dialogue: 0,0:13:14.28,0:13:16.27,EN,,0,0,0,,take this, which depends upon both a and b, Dialogue: 0,0:13:16.36,0:13:18.67,EN,,0,0,0,,and put the remainder into here. Dialogue: 0,0:13:19.15,0:13:20.33,EN,,0,0,0,,So I'm going to push this button first. Dialogue: 0,0:13:21.53,0:13:24.43,EN,,0,0,0,,Then, I'm going to transfer b to a, Dialogue: 0,0:13:24.44,0:13:25.60,EN,,0,0,0,,push that button, Dialogue: 0,0:13:25.82,0:13:27.63,EN,,0,0,0,,and then I transfer the temporary into b, Dialogue: 0,0:13:28.76,0:13:29.42,EN,,0,0,0,,push that button. Dialogue: 0,0:13:32.03,0:13:34.97,EN,,0,0,0,,So a very sequential machine, Dialogue: 0,0:13:35.39,0:13:36.52,EN,,0,0,0,,it's very inefficient. Dialogue: 0,0:13:37.75,0:13:39.05,EN,,0,0,0,,But that's fine right now. Dialogue: 0,0:13:39.81,0:13:40.97,EN,,0,0,0,,We're going to name the buttons, Dialogue: 0,0:13:41.47,0:13:42.72,EN,,0,0,0,,t gets remainder. Dialogue: 0,0:13:46.75,0:13:48.73,EN,,0,0,0,,a gets b. Dialogue: 0,0:13:50.03,0:13:54.81,EN,,0,0,0,,And b gets t. Dialogue: 0,0:13:55.47,0:13:57.63,EN,,0,0,0,,And then I'm going to go around here Dialogue: 0,0:13:58.78,0:13:59.88,EN,,0,0,0,,and it's to go back to start. Dialogue: 0,0:14:01.62,0:14:03.87,EN,,0,0,0,,And if you look, what are we seeing here? Dialogue: 0,0:14:03.87,0:14:04.91,EN,,0,0,0,,We're seeing the various-- Dialogue: 0,0:14:05.05,0:14:07.16,EN,,0,0,0,,what I really have is some sort of mechanical connection, Dialogue: 0,0:14:07.42,0:14:13.63,EN,,0,0,0,,where t gets r controls this thing. Dialogue: 0,0:14:16.83,0:14:21.48,EN,,0,0,0,,And I have here that a gets b controls this fellow over here, Dialogue: 0,0:14:26.96,0:14:28.12,EN,,0,0,0,,and this fellow over here. Dialogue: 0,0:14:28.12,0:14:31.08,EN,,0,0,0,,Boy, that's absolutely pessimal, Dialogue: 0,0:14:31.48,0:14:32.48,EN,,0,0,0,,the inverse of optimal. Dialogue: 0,0:14:32.63,0:14:34.59,EN,,0,0,0,,Every line heads across every other line the way I drew it. Dialogue: 0,0:14:38.54,0:14:41.15,EN,,0,0,0,,I suppose this goes here, b gets t. Dialogue: 0,0:14:45.69,0:14:47.95,EN,,0,0,0,,Now I'd like to run this machine. Dialogue: 0,0:14:48.04,0:14:49.34,EN,,0,0,0,,But before I run the machine, Dialogue: 0,0:14:49.37,0:14:51.40,EN,,0,0,0,,I want to write down a description of this controller, Dialogue: 0,0:14:51.63,0:14:52.81,EN,,0,0,0,,just so you can see that these things, Dialogue: 0,0:14:52.84,0:14:55.63,EN,,0,0,0,,of course, as usual, can be written down in some nice language, Dialogue: 0,0:14:56.08,0:14:58.08,EN,,0,0,0,,so that we don't have to always draw these diagrams. Dialogue: 0,0:14:58.36,0:15:00.68,EN,,0,0,0,,One of the problems with diagrams is that they take up a lot of space. Dialogue: 0,0:15:00.89,0:15:01.98,EN,,0,0,0,,And for a machine this small, Dialogue: 0,0:15:02.00,0:15:03.05,EN,,0,0,0,,it takes two blackboards. Dialogue: 0,0:15:03.22,0:15:05.24,EN,,0,0,0,,For a machine that's the evaluator machine, Dialogue: 0,0:15:05.40,0:15:07.10,EN,,0,0,0,,I have trouble putting it into this room, Dialogue: 0,0:15:07.95,0:15:09.16,EN,,0,0,0,,even though it isn't very big. Dialogue: 0,0:15:09.90,0:15:11.28,EN,,0,0,0,,So I'm going to make a little language for this Dialogue: 0,0:15:11.29,0:15:12.51,EN,,0,0,0,,that's just a description of that, Dialogue: 0,0:15:13.10,0:15:23.29,EN,,0,0,0,,saying define a machine we'll call GCD. Dialogue: 0,0:15:24.42,0:15:25.66,EN,,0,0,0,,Of course, once we have something like this, Dialogue: 0,0:15:25.68,0:15:26.83,EN,,0,0,0,,we have a simulator for it. Dialogue: 0,0:15:27.22,0:15:29.42,EN,,0,0,0,,And the reason why we want to build a language in this form, Dialogue: 0,0:15:29.56,0:15:32.94,EN,,0,0,0,,is because all of a sudden we can manipulate these expressions that I'm writing down. Dialogue: 0,0:15:33.21,0:15:34.91,EN,,0,0,0,,And then of course I can write things I can Dialogue: 0,0:15:35.29,0:15:38.16,EN,,0,0,0,,algebraically manipulate these things, simulate them Dialogue: 0,0:15:38.20,0:15:39.96,EN,,0,0,0,,all that sort of things that I might want to do, Dialogue: 0,0:15:40.12,0:15:42.59,EN,,0,0,0,,perhaps transform them as a layout, who knows. Dialogue: 0,0:15:43.63,0:15:48.38,EN,,0,0,0,,Once I have a nice representation of registers, Dialogue: 0,0:15:48.51,0:15:49.61,EN,,0,0,0,,it has certain registers, Dialogue: 0,0:15:53.00,0:15:55.64,EN,,0,0,0,,which we can call A, B, and T. Dialogue: 0,0:15:56.75,0:15:57.80,EN,,0,0,0,,And there's a controller. Dialogue: 0,0:16:02.19,0:16:04.46,EN,,0,0,0,,Actually, a better language, which would be more explicit, Dialogue: 0,0:16:04.49,0:16:06.97,EN,,0,0,0,,would be one which named every button Dialogue: 0,0:16:08.14,0:16:10.17,EN,,0,0,0,,also and said what it did. Dialogue: 0,0:16:10.42,0:16:11.37,EN,,0,0,0,,Like, this button Dialogue: 0,0:16:11.55,0:16:14.19,EN,,0,0,0,,causes the contents of T to go to the contents of B. Dialogue: 0,0:16:15.10,0:16:16.09,EN,,0,0,0,,Well I don't want to do that, Dialogue: 0,0:16:16.11,0:16:17.95,EN,,0,0,0,,because it's actually harder to read to do that, Dialogue: 0,0:16:18.20,0:16:19.34,EN,,0,0,0,,and it takes up more space. Dialogue: 0,0:16:19.51,0:16:22.36,EN,,0,0,0,,So I'm going to have that in the instructions written in the controller. Dialogue: 0,0:16:23.29,0:16:25.24,EN,,0,0,0,,It's going to be implicit what the operations are. Dialogue: 0,0:16:26.32,0:16:28.57,EN,,0,0,0,,They can be deduced by reading these Dialogue: 0,0:16:29.16,0:16:31.39,EN,,0,0,0,,and collecting together all the different things that can be done. Dialogue: 0,0:16:31.69,0:16:33.50,EN,,0,0,0,,We look and see, see... Dialogue: 0,0:16:33.50,0:16:34.70,EN,,0,0,0,,Well, let's just look at what these things are. Dialogue: 0,0:16:35.71,0:16:37.29,EN,,0,0,0,,There's a little loop that we go around Dialogue: 0,0:16:38.24,0:16:40.20,EN,,0,0,0,,which says branch, Dialogue: 0,0:16:42.64,0:16:46.46,EN,,0,0,0,,this is the representation of the little flap Dialogue: 0,0:16:46.89,0:16:48.49,EN,,0,0,0,,that decides which way you go here, Dialogue: 0,0:16:49.10,0:16:58.00,EN,,0,0,0,,if 0, OK, fetch of B, the contents of B, Dialogue: 0,0:16:58.65,0:17:00.06,EN,,0,0,0,,and if the contents of B is 0, Dialogue: 0,0:17:00.32,0:17:01.72,EN,,0,0,0,,then go to a place called done. Dialogue: 0,0:17:03.64,0:17:05.29,EN,,0,0,0,,Now, one thing you're seeing here, Dialogue: 0,0:17:05.29,0:17:07.40,EN,,0,0,0,,this looks very much like a traditional computer language. Dialogue: 0,0:17:08.17,0:17:09.55,EN,,0,0,0,,And what you're seeing here Dialogue: 0,0:17:10.03,0:17:12.00,EN,,0,0,0,,is things like labels Dialogue: 0,0:17:12.99,0:17:16.86,EN,,0,0,0,,that represent places in a sequence written down as a sequence. Dialogue: 0,0:17:17.60,0:17:18.94,EN,,0,0,0,,The reason why they're needed Dialogue: 0,0:17:19.48,0:17:21.15,EN,,0,0,0,,is because over here, Dialogue: 0,0:17:21.45,0:17:22.81,EN,,0,0,0,,I've written something with loops. Dialogue: 0,0:17:23.32,0:17:26.11,EN,,0,0,0,,But if I'm writing English text, or something like that, Dialogue: 0,0:17:26.44,0:17:28.09,EN,,0,0,0,,it's hard to refer to a place. Dialogue: 0,0:17:28.58,0:17:29.53,EN,,0,0,0,,I don't have arrows. Dialogue: 0,0:17:30.80,0:17:33.02,EN,,0,0,0,,Arrows are represented by giving names Dialogue: 0,0:17:33.05,0:17:34.44,EN,,0,0,0,,to the places where the arrows terminate, Dialogue: 0,0:17:34.57,0:17:36.28,EN,,0,0,0,,and then referring to them by those names. Dialogue: 0,0:17:37.40,0:17:38.59,EN,,0,0,0,,Now this is just an encoding. Dialogue: 0,0:17:39.86,0:17:41.88,EN,,0,0,0,,There's nothing magical about things like that. Dialogue: 0,0:17:43.15,0:17:44.96,EN,,0,0,0,,Next thing we're going to do is we're going to say, Dialogue: 0,0:17:45.02,0:17:46.84,EN,,0,0,0,,how do we do T gets R? Dialogue: 0,0:17:47.45,0:17:49.76,EN,,0,0,0,,Oh, that's easy enough, assign. Dialogue: 0,0:17:52.19,0:17:55.55,EN,,0,0,0,,We assign to T the remainder. Dialogue: 0,0:17:56.32,0:17:59.24,EN,,0,0,0,,Assign is the name of the button. Dialogue: 0,0:18:01.47,0:18:02.64,EN,,0,0,0,,That's the button-pusher. Dialogue: 0,0:18:03.14,0:18:04.97,EN,,0,0,0,,Assign to T the remainder, Dialogue: 0,0:18:04.99,0:18:06.76,EN,,0,0,0,,and here's the representation of the operation, Dialogue: 0,0:18:11.74,0:18:17.53,EN,,0,0,0,,when we divide the fetch of A by the fetch of B. Dialogue: 0,0:18:23.85,0:18:30.99,EN,,0,0,0,,And we're also going to assign to A the fetch of B, Dialogue: 0,0:18:34.99,0:18:47.88,EN,,0,0,0,,assign to B the result of getting the contents of T. Dialogue: 0,0:18:49.61,0:18:51.85,EN,,0,0,0,,And now I have to refer to the beginning here. Dialogue: 0,0:18:53.18,0:18:55.92,EN,,0,0,0,,I see, why don't I call that loop like I have here? Dialogue: 0,0:19:04.09,0:19:07.04,EN,,0,0,0,,OK? So that's that reference to that arrow. Dialogue: 0,0:19:07.61,0:19:08.95,EN,,0,0,0,,And when we're done, we're done. Dialogue: 0,0:19:09.02,0:19:13.07,EN,,0,0,0,,We go to here, which is the end of the thing. Dialogue: 0,0:19:15.26,0:19:17.04,EN,,0,0,0,,So here's just a written representation Dialogue: 0,0:19:17.69,0:19:20.86,EN,,0,0,0,,of this fragment of machinery that we've drawn here. Dialogue: 0,0:19:21.66,0:19:24.84,EN,,0,0,0,,Now the next thing I'd like to do is run this. Dialogue: 0,0:19:25.49,0:19:26.65,EN,,0,0,0,,I want us to feel it running. Dialogue: 0,0:19:27.62,0:19:29.80,EN,,0,0,0,,Never done this before, you got to do it once. Dialogue: 0,0:19:31.01,0:19:32.62,EN,,0,0,0,,So let's take a particular problem. Dialogue: 0,0:19:33.10,0:19:34.70,EN,,0,0,0,,Suppose we want to compute the GCD Dialogue: 0,0:19:35.04,0:19:40.68,EN,,0,0,0,,of a equals 30 and b equals 42. Dialogue: 0,0:19:42.21,0:19:44.92,EN,,0,0,0,,I have no idea what that is right now. Dialogue: 0,0:19:45.86,0:19:47.60,EN,,0,0,0,,But a 30 and b is 42. Dialogue: 0,0:19:50.96,0:19:52.09,EN,,0,0,0,,So that's how I start this thing up. Dialogue: 0,0:19:52.60,0:19:53.90,EN,,0,0,0,,Well, what's the first thing I do? Dialogue: 0,0:19:54.24,0:19:56.86,EN,,0,0,0,,I say is B equal to 0, no. Dialogue: 0,0:19:57.59,0:20:02.11,EN,,0,0,0,,Then assign to T the remainder of the fetch of A and the fetch of B. Dialogue: 0,0:20:02.80,0:20:07.60,EN,,0,0,0,,Well the remainder of 30 when divided by 42 is itself 30. Dialogue: 0,0:20:11.13,0:20:12.03,EN,,0,0,0,,Push that button. Dialogue: 0,0:20:12.92,0:20:15.10,EN,,0,0,0,,Now the marble has rolled to here. Dialogue: 0,0:20:17.10,0:20:18.06,EN,,0,0,0,,A gets B. Dialogue: 0,0:20:19.02,0:20:20.76,EN,,0,0,0,,That pushes this button. Dialogue: 0,0:20:21.22,0:20:22.54,EN,,0,0,0,,So 42 moves into here. Dialogue: 0,0:20:26.59,0:20:27.60,EN,,0,0,0,,B gets T. Dialogue: 0,0:20:28.36,0:20:29.34,EN,,0,0,0,,Push that button. Dialogue: 0,0:20:29.87,0:20:30.96,EN,,0,0,0,,The 30 goes here. Dialogue: 0,0:20:32.57,0:20:33.69,EN,,0,0,0,,Let met just interchange them. Dialogue: 0,0:20:34.66,0:20:38.27,EN,,0,0,0,,Now let's see, go back to the beginning. Dialogue: 0,0:20:38.64,0:20:39.72,EN,,0,0,0,,B 0, no. Dialogue: 0,0:20:40.19,0:20:41.50,EN,,0,0,0,,T gets the remainder. Dialogue: 0,0:20:43.23,0:20:46.30,EN,,0,0,0,,I suppose the remainder when dividing 42 by 30 is 12. Dialogue: 0,0:20:47.24,0:20:48.30,EN,,0,0,0,,I push that one. Dialogue: 0,0:20:48.53,0:20:51.40,EN,,0,0,0,,Next thing I do is allow the 30 to go to here, Dialogue: 0,0:20:53.90,0:20:55.95,EN,,0,0,0,,push this one, allow the 12 to go to here. Dialogue: 0,0:20:58.41,0:21:00.38,EN,,0,0,0,,OK? Go around this thing. Dialogue: 0,0:21:00.38,0:21:01.31,EN,,0,0,0,,Is that done? Dialogue: 0,0:21:01.53,0:21:02.12,EN,,0,0,0,,No. Dialogue: 0,0:21:02.36,0:21:08.22,EN,,0,0,0,,How about-- so now I have to find out the remainder of 30 divided by 12. Dialogue: 0,0:21:08.85,0:21:10.67,EN,,0,0,0,,And I believe that's 6. Dialogue: 0,0:21:12.42,0:21:15.13,EN,,0,0,0,,So 6 goes here on this button push. Dialogue: 0,0:21:16.20,0:21:18.25,EN,,0,0,0,,Then the next thing I push is this one, Dialogue: 0,0:21:18.30,0:21:19.61,EN,,0,0,0,,which the 12 goes into here. Dialogue: 0,0:21:23.73,0:21:25.09,EN,,0,0,0,,Then I push this button. Dialogue: 0,0:21:25.09,0:21:26.00,EN,,0,0,0,,The 6 gets into here. Dialogue: 0,0:21:29.85,0:21:31.68,EN,,0,0,0,,Is 6 equal to 0? Dialogue: 0,0:21:31.88,0:21:32.49,EN,,0,0,0,,No. Dialogue: 0,0:21:33.42,0:21:33.98,EN,,0,0,0,,OK. Dialogue: 0,0:21:34.38,0:21:36.80,EN,,0,0,0,,So then at that point, Dialogue: 0,0:21:36.89,0:21:38.12,EN,,0,0,0,,the next thing to do is divide it. Dialogue: 0,0:21:38.14,0:21:39.80,EN,,0,0,0,,Ooh, this has got a remainder of 0. Dialogue: 0,0:21:40.66,0:21:41.74,EN,,0,0,0,,Looks like we're almost done. Dialogue: 0,0:21:42.36,0:21:44.36,EN,,0,0,0,,Move the 6 over here next. Dialogue: 0,0:21:47.00,0:21:48.27,EN,,0,0,0,,0 over here. Dialogue: 0,0:21:49.09,0:21:50.20,EN,,0,0,0,,Is the answer 0? Dialogue: 0,0:21:50.20,0:21:50.73,EN,,0,0,0,,Yes. Dialogue: 0,0:21:51.34,0:21:53.36,EN,,0,0,0,,B is 0, therefore the answer is in A. Dialogue: 0,0:21:54.28,0:21:55.76,EN,,0,0,0,,The answer is 6. Dialogue: 0,0:21:56.61,0:21:57.61,EN,,0,0,0,,And indeed that's right, Dialogue: 0,0:21:57.63,0:21:59.47,EN,,0,0,0,,because if we look at the original problem, Dialogue: 0,0:22:00.08,0:22:06.64,EN,,0,0,0,,what we have is 30 is 2 times 3 times 5, Dialogue: 0,0:22:07.00,0:22:11.12,EN,,0,0,0,,and 42 is 2 times 3 times 7. Dialogue: 0,0:22:11.67,0:22:14.11,EN,,0,0,0,,So the greatest common divisor is 2 times 3, Dialogue: 0,0:22:14.20,0:22:15.08,EN,,0,0,0,,which is 6. Dialogue: 0,0:22:18.38,0:22:20.56,EN,,0,0,0,,Now normally, we write one other little line here, Dialogue: 0,0:22:20.59,0:22:22.52,EN,,0,0,0,,just to make it a little bit clearer, Dialogue: 0,0:22:22.89,0:22:27.71,EN,,0,0,0,,which is that we leave in a connection saying Dialogue: 0,0:22:27.85,0:22:31.01,EN,,0,0,0,,that this light is the guy that that flap looks at. Dialogue: 0,0:22:34.00,0:22:37.32,EN,,0,0,0,,Of course, any real machine has a lot more Dialogue: 0,0:22:37.85,0:22:40.00,EN,,0,0,0,,complicated things in it than what I've just shown you. Dialogue: 0,0:22:41.35,0:22:47.16,EN,,0,0,0,,Let's look for a second at the first still store. Dialogue: 0,0:22:47.98,0:22:48.81,EN,,0,0,0,,Wow. Dialogue: 0,0:22:50.19,0:22:52.43,EN,,0,0,0,,Well you see, for example, one thing we might want to do Dialogue: 0,0:22:52.65,0:22:55.85,EN,,0,0,0,,is worry about the operations that are of IO form. Dialogue: 0,0:22:56.84,0:23:01.42,EN,,0,0,0,,And we may have to collect something from the outside. Dialogue: 0,0:23:01.98,0:23:03.93,EN,,0,0,0,,So a state machine that we might have, Dialogue: 0,0:23:04.30,0:23:07.02,EN,,0,0,0,,the controller may have to, Dialogue: 0,0:23:07.26,0:23:10.56,EN,,0,0,0,,may have to, for example, get a value from something Dialogue: 0,0:23:10.78,0:23:12.41,EN,,0,0,0,,and put register a to load it up. Dialogue: 0,0:23:13.49,0:23:15.92,EN,,0,0,0,,I have to master load up register b with another value. Dialogue: 0,0:23:17.07,0:23:18.60,EN,,0,0,0,,And then later, when I'm done, Dialogue: 0,0:23:18.99,0:23:20.52,EN,,0,0,0,,I might want to print the answer out. Dialogue: 0,0:23:21.20,0:23:25.23,EN,,0,0,0,,And of course, that might be either simple or complicated. Dialogue: 0,0:23:26.09,0:23:28.03,EN,,0,0,0,,I'm writing, assuming print is very simple, Dialogue: 0,0:23:28.09,0:23:29.29,EN,,0,0,0,,and read is very simple. Dialogue: 0,0:23:29.88,0:23:31.08,EN,,0,0,0,,But in fact, in the real world, Dialogue: 0,0:23:31.12,0:23:32.89,EN,,0,0,0,,those are very complicated operations, Dialogue: 0,0:23:33.08,0:23:35.52,EN,,0,0,0,,fairly, usually much, much larger and more complicated Dialogue: 0,0:23:35.55,0:23:38.33,EN,,0,0,0,,than the thing you're doing as your problem you're trying to solve. Dialogue: 0,0:23:41.67,0:23:43.90,EN,,0,0,0,,On the other hand, I can remember a time when, Dialogue: 0,0:23:44.89,0:23:48.78,EN,,0,0,0,,I remember using IBM 7090 computer of sorts, Dialogue: 0,0:23:49.05,0:23:53.04,EN,,0,0,0,,where things like read and write of a single object, Dialogue: 0,0:23:53.08,0:23:54.62,EN,,0,0,0,,a single number, a number, Dialogue: 0,0:23:55.84,0:23:58.54,EN,,0,0,0,,is a primitive operation of the IO controller. Dialogue: 0,0:23:59.63,0:24:02.04,EN,,0,0,0,,OK? And so we have that kind of thing in there. Dialogue: 0,0:24:02.33,0:24:04.67,EN,,0,0,0,,And in such a machine, Dialogue: 0,0:24:05.44,0:24:06.89,EN,,0,0,0,,well, what are we really doing? Dialogue: 0,0:24:07.12,0:24:11.60,EN,,0,0,0,,We're just saying that there's a source over here called "read" Dialogue: 0,0:24:12.20,0:24:14.46,EN,,0,0,0,,which is an operation which always has a value. Dialogue: 0,0:24:14.66,0:24:17.13,EN,,0,0,0,,We have to think about this as always having a value Dialogue: 0,0:24:17.21,0:24:19.84,EN,,0,0,0,,which can be gated into either register a or b. Dialogue: 0,0:24:21.66,0:24:23.23,EN,,0,0,0,,And print is some sort of thing Dialogue: 0,0:24:23.37,0:24:25.02,EN,,0,0,0,,which when you gate it appropriately, Dialogue: 0,0:24:25.24,0:24:26.43,EN,,0,0,0,,when you push the button on it, Dialogue: 0,0:24:26.65,0:24:29.61,EN,,0,0,0,,will cause a print of the value that's currently in register a. Dialogue: 0,0:24:31.66,0:24:32.73,EN,,0,0,0,,Nothing very exciting. Dialogue: 0,0:24:33.32,0:24:35.20,EN,,0,0,0,,So that's one sort of thing you might want to have. Dialogue: 0,0:24:35.88,0:24:38.32,EN,,0,0,0,,But these are also other things that are a little bit worrisome. Dialogue: 0,0:24:38.32,0:24:40.67,EN,,0,0,0,,Like I've used here some complicated mechanisms. Dialogue: 0,0:24:41.05,0:24:42.48,EN,,0,0,0,,What you see here is remainder. Dialogue: 0,0:24:43.85,0:24:44.44,EN,,0,0,0,,What is that? Dialogue: 0,0:24:44.69,0:24:46.41,EN,,0,0,0,,That may not be so obvious how to compute. Dialogue: 0,0:24:46.92,0:24:48.92,EN,,0,0,0,,It may be something which when you open it up, Dialogue: 0,0:24:49.48,0:24:50.62,EN,,0,0,0,,you get a whole machine. Dialogue: 0,0:24:51.84,0:24:53.66,EN,,0,0,0,,OK? In fact, that's true. Dialogue: 0,0:24:54.54,0:24:59.15,EN,,0,0,0,,For example, if I write down the program for remainder, Dialogue: 0,0:24:59.44,0:25:02.44,EN,,0,0,0,,the simplest program for it is by repeated subtraction. Dialogue: 0,0:25:04.78,0:25:05.95,EN,,0,0,0,,Because of course, division can be done Dialogue: 0,0:25:05.96,0:25:08.99,EN,,0,0,0,,by repeated subtraction of numbers, of integers. Dialogue: 0,0:25:09.80,0:25:23.58,EN,,0,0,0,,So the remainder of N divided by D Dialogue: 0,0:25:24.99,0:25:31.44,EN,,0,0,0,,is nothing more than if N is less than D, Dialogue: 0,0:25:32.24,0:25:33.66,EN,,0,0,0,,then the result is N. Dialogue: 0,0:25:34.30,0:25:35.90,EN,,0,0,0,,Otherwise, it's the remainder Dialogue: 0,0:25:41.15,0:25:47.60,EN,,0,0,0,,when we subtract D from N with respect to D, Dialogue: 0,0:25:48.27,0:25:49.32,EN,,0,0,0,,when divided by D. Dialogue: 0,0:25:51.28,0:25:55.05,EN,,0,0,0,,Gee, this looks just like the GCD program. Dialogue: 0,0:25:56.89,0:25:59.48,EN,,0,0,0,,Of course, it's not a very nice way to do remainders. Dialogue: 0,0:25:59.75,0:26:00.91,EN,,0,0,0,,You'd really want to use something like Dialogue: 0,0:26:00.92,0:26:05.42,EN,,0,0,0,,binary notation and shift and things like that in a practical computer. Dialogue: 0,0:26:05.55,0:26:06.97,EN,,0,0,0,,But the point of that is Dialogue: 0,0:26:07.13,0:26:08.48,EN,,0,0,0,,that if I open this thing up, Dialogue: 0,0:26:08.92,0:26:10.64,EN,,0,0,0,,I might find inside of it a computer. Dialogue: 0,0:26:11.88,0:26:12.99,EN,,0,0,0,,Oh, we know how to do that. Dialogue: 0,0:26:13.51,0:26:14.33,EN,,0,0,0,,We just made one. Dialogue: 0,0:26:15.64,0:26:17.10,EN,,0,0,0,,And it could be another thing just like this. Dialogue: 0,0:26:17.40,0:26:18.06,EN,,0,0,0,,On the other hand, Dialogue: 0,0:26:18.08,0:26:20.00,EN,,0,0,0,,we might want to make a more efficient Dialogue: 0,0:26:20.01,0:26:21.68,EN,,0,0,0,,or better-structured machine, Dialogue: 0,0:26:21.85,0:26:23.96,EN,,0,0,0,,or maybe make use of some of the registers more than once, Dialogue: 0,0:26:24.00,0:26:27.05,EN,,0,0,0,,or some horrible mess like that that hardware designers like to do, Dialogue: 0,0:26:27.31,0:26:28.60,EN,,0,0,0,,and for very good reasons. Dialogue: 0,0:26:29.25,0:26:31.56,EN,,0,0,0,,So for example, here's a machine that you see, Dialogue: 0,0:26:32.52,0:26:34.91,EN,,0,0,0,,which you're not supposed to be able to read. Dialogue: 0,0:26:35.05,0:26:37.52,EN,,0,0,0,,It's a little bit complicated. OK? Dialogue: 0,0:26:37.52,0:26:39.87,EN,,0,0,0,,But what it is is the integration of Dialogue: 0,0:26:40.09,0:26:43.82,EN,,0,0,0,,remainder into the GCD machine. Dialogue: 0,0:26:44.46,0:26:46.02,EN,,0,0,0,,And it takes, in fact, no more registers. Dialogue: 0,0:26:46.02,0:26:48.62,EN,,0,0,0,,There are three registers in the datapaths. OK? Dialogue: 0,0:26:49.05,0:26:50.64,EN,,0,0,0,,But now there's a subtractor. Dialogue: 0,0:26:51.55,0:26:52.99,EN,,0,0,0,,There are two things that are tested. Dialogue: 0,0:26:53.02,0:26:55.07,EN,,0,0,0,,Is b equal to 0, Dialogue: 0,0:26:55.23,0:26:56.56,EN,,0,0,0,,or is t less than b? Dialogue: 0,0:26:57.25,0:26:59.45,EN,,0,0,0,,And then the controller, which you see over here, Dialogue: 0,0:27:00.22,0:27:01.76,EN,,0,0,0,,is not much more complicated. Dialogue: 0,0:27:01.85,0:27:03.87,EN,,0,0,0,,But it has two loops in it, Dialogue: 0,0:27:04.52,0:27:08.33,EN,,0,0,0,,one of which is the main one for doing the GCD, Dialogue: 0,0:27:08.40,0:27:10.14,EN,,0,0,0,,and one of which is the subtraction loop Dialogue: 0,0:27:10.43,0:27:12.80,EN,,0,0,0,,for doing the remainder sub-operation. Dialogue: 0,0:27:14.03,0:27:15.80,EN,,0,0,0,,And there are ways, of course, of, Dialogue: 0,0:27:15.96,0:27:18.68,EN,,0,0,0,,if you think about it, taking the remainder program. Dialogue: 0,0:27:19.92,0:27:21.71,EN,,0,0,0,,If I take remainder, as you see over there Dialogue: 0,0:27:21.72,0:27:22.83,EN,,0,0,0,,as a lambda expression, Dialogue: 0,0:27:23.56,0:27:27.02,EN,,0,0,0,,substitute it in for remainder over here in the GCD program, Dialogue: 0,0:27:28.20,0:27:30.12,EN,,0,0,0,,OK, then do some simplification Dialogue: 0,0:27:30.32,0:27:33.66,EN,,0,0,0,,by substituting a and b for remainder in there, Dialogue: 0,0:27:34.46,0:27:35.95,EN,,0,0,0,,then I can unwind this loop. Dialogue: 0,0:27:36.63,0:27:39.42,EN,,0,0,0,,And I can get this piece of machinery Dialogue: 0,0:27:40.73,0:27:42.94,EN,,0,0,0,,by basically, a little bit of simplification Dialogue: 0,0:27:43.36,0:27:45.21,EN,,0,0,0,,algebraic simplification on the lambda expressions. Dialogue: 0,0:27:48.55,0:27:51.20,EN,,0,0,0,,So I suppose you've seen your first very simple machines now. Dialogue: 0,0:27:51.95,0:27:53.28,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:28:02.70,0:28:03.10,EN,,0,0,0,,Good. Dialogue: 0,0:28:05.36,0:28:06.54,EN,,0,0,0,,This looks easy, doesn't it? Dialogue: 0,0:28:10.14,0:28:11.32,EN,,0,0,0,,Thank you. I suppose, take a break. Dialogue: 0,0:28:12.54,0:28:24.94,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:28:47.93,0:28:48.70,EN,,0,0,0,,PROFESSOR: Well, let's see. Dialogue: 0,0:28:49.37,0:28:52.46,EN,,0,0,0,,Now you know how to make an iterative procedure, Dialogue: 0,0:28:52.54,0:28:54.54,EN,,0,0,0,,or a procedure that yields an iterative process, Dialogue: 0,0:28:55.18,0:28:56.52,EN,,0,0,0,,turn into a machine. Dialogue: 0,0:28:57.77,0:29:00.04,EN,,0,0,0,,I suppose the next thing we want to do is worry about things Dialogue: 0,0:29:00.54,0:29:02.30,EN,,0,0,0,,that reveal recursive processes. Dialogue: 0,0:29:02.81,0:29:05.05,EN,,0,0,0,,So let's play with a simple factorial procedure. Dialogue: 0,0:29:11.20,0:29:16.94,EN,,0,0,0,,We define factorial of N to be Dialogue: 0,0:29:19.63,0:29:24.25,EN,,0,0,0,,if n is 1, the result is 1, Dialogue: 0,0:29:24.62,0:29:27.69,EN,,0,0,0,,using 1 right now to decrease the amount of work I have to do to simulate it, Dialogue: 0,0:29:28.12,0:29:33.94,EN,,0,0,0,,else it's times N factorial N minus 1. Dialogue: 0,0:29:42.52,0:29:46.04,EN,,0,0,0,,And what's different with this program, as you know, Dialogue: 0,0:29:46.65,0:29:50.36,EN,,0,0,0,,is that after I've computed factorial of N minus 1 here, Dialogue: 0,0:29:50.67,0:29:52.26,EN,,0,0,0,,I have to do something to the result. Dialogue: 0,0:29:52.26,0:29:53.68,EN,,0,0,0,,I have to multiply it by N. Dialogue: 0,0:29:56.00,0:30:00.67,EN,,0,0,0,,So the only way I can visualize what this machine is doing, Dialogue: 0,0:30:01.08,0:30:02.01,EN,,0,0,0,,because of the fact-- Dialogue: 0,0:30:02.35,0:30:03.18,EN,,0,0,0,,think of it this way, Dialogue: 0,0:30:03.36,0:30:04.94,EN,,0,0,0,,that I have a machine out here Dialogue: 0,0:30:05.08,0:30:08.11,EN,,0,0,0,,which somehow needs a factorial machine in order to compute its answer. Dialogue: 0,0:30:09.32,0:30:11.16,EN,,0,0,0,,But this machine, the outer machine, Dialogue: 0,0:30:11.20,0:30:13.02,EN,,0,0,0,,has to exist before and after Dialogue: 0,0:30:13.92,0:30:15.72,EN,,0,0,0,,the factorial machine, which is inside. Dialogue: 0,0:30:16.80,0:30:17.90,EN,,0,0,0,,Whereas in the iterative case, Dialogue: 0,0:30:18.75,0:30:20.52,EN,,0,0,0,,the outer machine doesn't need to exist Dialogue: 0,0:30:20.91,0:30:24.01,EN,,0,0,0,,after the inner machine is running, Dialogue: 0,0:30:24.83,0:30:26.16,EN,,0,0,0,,because you never need to go back Dialogue: 0,0:30:26.19,0:30:27.53,EN,,0,0,0,,to the outer machine to do anything. Dialogue: 0,0:30:28.64,0:30:30.06,EN,,0,0,0,,So here we have a problem Dialogue: 0,0:30:30.27,0:30:30.97,EN,,0,0,0,,where we have a machine Dialogue: 0,0:30:31.00,0:30:32.73,EN,,0,0,0,,which has the same machine inside of it, Dialogue: 0,0:30:33.87,0:30:35.52,EN,,0,0,0,,an infinitely large machine. Dialogue: 0,0:30:40.39,0:30:43.12,EN,,0,0,0,,And it's got other things inside of it, like a multiplier, Dialogue: 0,0:30:44.76,0:30:46.03,EN,,0,0,0,,which takes some inputs, Dialogue: 0,0:30:46.27,0:30:47.77,EN,,0,0,0,,and there's a minus 1 box, Dialogue: 0,0:30:48.12,0:30:49.31,EN,,0,0,0,,and things like that. Dialogue: 0,0:30:50.69,0:30:53.72,EN,,0,0,0,,You know, You can imagine that's what it looks like. Dialogue: 0,0:30:54.37,0:30:56.76,EN,,0,0,0,,But the important thing is that here I have Dialogue: 0,0:30:57.02,0:30:58.70,EN,,0,0,0,,something that happens before and after, Dialogue: 0,0:30:58.78,0:31:01.60,EN,,0,0,0,,in the outer machine, the execution of the inner machine. Dialogue: 0,0:31:02.54,0:31:04.08,EN,,0,0,0,,So this machine has to have a life. Dialogue: 0,0:31:05.47,0:31:11.44,EN,,0,0,0,,It has to exist on both times sides of this machine. Dialogue: 0,0:31:13.49,0:31:15.80,EN,,0,0,0,,So somehow, I have to have a place to store Dialogue: 0,0:31:16.19,0:31:18.19,EN,,0,0,0,,the things that this thing needs to run. Dialogue: 0,0:31:20.03,0:31:22.09,EN,,0,0,0,,Infinite objects don't exist in the real world. Dialogue: 0,0:31:24.14,0:31:25.58,EN,,0,0,0,,What we have to do is arrange an illusion Dialogue: 0,0:31:26.12,0:31:27.48,EN,,0,0,0,,that we have an infinite object, Dialogue: 0,0:31:27.98,0:31:29.77,EN,,0,0,0,,we have an infinite amount of hardware somewhere. Dialogue: 0,0:31:31.83,0:31:35.34,EN,,0,0,0,,Now of course, illusion's all that really matters. Dialogue: 0,0:31:36.28,0:31:37.37,EN,,0,0,0,,If we can arrange Dialogue: 0,0:31:38.00,0:31:39.84,EN,,0,0,0,,that every time you look at some infinite object, Dialogue: 0,0:31:39.88,0:31:42.96,EN,,0,0,0,,the part of it that you look at is there, Dialogue: 0,0:31:44.49,0:31:46.04,EN,,0,0,0,,then it's as infinite as you need it to be. Dialogue: 0,0:31:47.39,0:31:49.44,EN,,0,0,0,,And of course, one of the things we might want to do, Dialogue: 0,0:31:49.82,0:31:52.49,EN,,0,0,0,,just look at this thing over here, Dialogue: 0,0:31:53.00,0:31:54.97,EN,,0,0,0,,is the organization that we've had so far Dialogue: 0,0:31:56.04,0:31:57.64,EN,,0,0,0,,organization that we've had so far Dialogue: 0,0:31:57.92,0:32:01.37,EN,,0,0,0,,involves having a part of the machine, Dialogue: 0,0:32:01.40,0:32:02.33,EN,,0,0,0,,which is the controller, Dialogue: 0,0:32:03.18,0:32:04.46,EN,,0,0,0,,which sits right over here, Dialogue: 0,0:32:04.78,0:32:07.61,EN,,0,0,0,,which is perfectly finite and very simple. Dialogue: 0,0:32:09.17,0:32:10.44,EN,,0,0,0,,We have some datapaths, Dialogue: 0,0:32:10.46,0:32:12.75,EN,,0,0,0,,which consist of registers and operators. Dialogue: 0,0:32:13.08,0:32:15.20,EN,,0,0,0,,And what I propose to do here is decompose Dialogue: 0,0:32:15.48,0:32:16.96,EN,,0,0,0,,the machine into two parts, Dialogue: 0,0:32:17.36,0:32:19.79,EN,,0,0,0,,such that there is a part which is fundamentally finite, Dialogue: 0,0:32:20.78,0:32:23.53,EN,,0,0,0,,and some part where a certain amount of infinite stuff can be kept. Dialogue: 0,0:32:24.23,0:32:25.90,EN,,0,0,0,,On the other hand this is very simple Dialogue: 0,0:32:26.41,0:32:28.72,EN,,0,0,0,,and really isn't infinite, but it's just very large. Dialogue: 0,0:32:29.43,0:32:30.40,EN,,0,0,0,,But it's so simple Dialogue: 0,0:32:30.52,0:32:32.92,EN,,0,0,0,,that it could be cheaply reproduced in such large amounts, Dialogue: 0,0:32:34.09,0:32:34.92,EN,,0,0,0,,we call it memory, Dialogue: 0,0:32:35.95,0:32:39.07,EN,,0,0,0,,OK? that we can make a structure called a stack out of it Dialogue: 0,0:32:39.40,0:32:41.23,EN,,0,0,0,,which will allow us to, in fact, Dialogue: 0,0:32:41.45,0:32:43.63,EN,,0,0,0,,simulate the existence of an infinite machine Dialogue: 0,0:32:43.64,0:32:46.96,EN,,0,0,0,,which is made out of a recursive nest of many machines. Dialogue: 0,0:32:48.34,0:32:50.43,EN,,0,0,0,,And the way it's going to work is that Dialogue: 0,0:32:50.56,0:32:52.97,EN,,0,0,0,,we're going to store in this place called the stack Dialogue: 0,0:32:54.30,0:32:57.58,EN,,0,0,0,,the information required after the inner machine runs Dialogue: 0,0:32:59.18,0:33:01.07,EN,,0,0,0,,to resume the operation of the outer machine. Dialogue: 0,0:33:03.84,0:33:05.48,EN,,0,0,0,,So it will remember Dialogue: 0,0:33:05.63,0:33:07.95,EN,,0,0,0,,the important things about the life of the outer machine Dialogue: 0,0:33:08.04,0:33:10.30,EN,,0,0,0,,that will be needed for this computation. Dialogue: 0,0:33:11.39,0:33:12.48,EN,,0,0,0,,Since, of course, Dialogue: 0,0:33:12.75,0:33:16.33,EN,,0,0,0,,these machines are nested in a recursive manner, Dialogue: 0,0:33:18.33,0:33:23.39,EN,,0,0,0,,then in fact the stack will only be accessed in a manner Dialogue: 0,0:33:23.45,0:33:26.44,EN,,0,0,0,,which is the last thing that goes in is the first thing that comes out. Dialogue: 0,0:33:29.33,0:33:30.64,EN,,0,0,0,,So we'll only need to access Dialogue: 0,0:33:30.80,0:33:32.52,EN,,0,0,0,,some little part of this stack memory. Dialogue: 0,0:33:34.93,0:33:35.92,EN,,0,0,0,,OK, well, let's do it. Dialogue: 0,0:33:36.81,0:33:38.41,EN,,0,0,0,,I'm going to build you a datapath now, Dialogue: 0,0:33:38.44,0:33:39.68,EN,,0,0,0,,and I'm going to write the controller. Dialogue: 0,0:33:40.37,0:33:42.86,EN,,0,0,0,,And then we're going to execute this to see how you do it. Dialogue: 0,0:33:43.51,0:33:46.88,EN,,0,0,0,,So the factorial machine isn't so bad. Dialogue: 0,0:33:47.90,0:33:50.16,EN,,0,0,0,,It's going to have a register called the value, Dialogue: 0,0:33:52.22,0:33:53.88,EN,,0,0,0,,where the answer is going to be stored, Dialogue: 0,0:33:54.89,0:33:56.67,EN,,0,0,0,,and a registered called N, Dialogue: 0,0:33:59.85,0:34:04.16,EN,,0,0,0,,which is where the number I'm taking factorial will be stored, factorial of. Dialogue: 0,0:34:04.51,0:34:06.57,EN,,0,0,0,,And it will be necessary in some instances Dialogue: 0,0:34:07.48,0:34:10.52,EN,,0,0,0,,to connect VAL to N. Dialogue: 0,0:34:11.74,0:34:15.63,EN,,0,0,0,,In fact, one nice case of this is if I just said over here, Dialogue: 0,0:34:16.38,0:34:19.53,EN,,0,0,0,,N, because that would be right for N equal 1N. Dialogue: 0,0:34:20.09,0:34:23.26,EN,,0,0,0,,And I could just move the answer over there if that's important. Dialogue: 0,0:34:23.90,0:34:25.55,EN,,0,0,0,,I'm not worried about that right now. Dialogue: 0,0:34:26.98,0:34:28.60,EN,,0,0,0,,And there are things I have to be able to do. Dialogue: 0,0:34:29.06,0:34:31.02,EN,,0,0,0,,Like I have to be able to, as we see here, Dialogue: 0,0:34:31.21,0:34:34.67,EN,,0,0,0,,multiply N by something in VAL, Dialogue: 0,0:34:34.91,0:34:37.45,EN,,0,0,0,,because VAL is the result of computing factorial. Dialogue: 0,0:34:38.68,0:34:40.44,EN,,0,0,0,,And I have to put the result back into VAL. Dialogue: 0,0:34:41.48,0:34:42.65,EN,,0,0,0,,So here we can see Dialogue: 0,0:34:42.83,0:34:46.43,EN,,0,0,0,,that the result of computing a factorial Dialogue: 0,0:34:46.57,0:34:49.20,EN,,0,0,0,,is N times the result of computing a factorial. Dialogue: 0,0:34:50.69,0:34:53.77,EN,,0,0,0,,VAL will be the representation of the answer of the inner factorial. Dialogue: 0,0:34:55.19,0:35:00.25,EN,,0,0,0,,And so I'm going to have to have a multiplier here, Dialogue: 0,0:35:02.36,0:35:07.18,EN,,0,0,0,,which is going to sample the value of N and the value of VAL Dialogue: 0,0:35:08.64,0:35:15.60,EN,,0,0,0,,OK? and put the result back into VAL like that. Dialogue: 0,0:35:17.17,0:35:19.39,EN,,0,0,0,,I'm also going to have to be able to see if N is 1. Dialogue: 0,0:35:21.32,0:35:22.38,EN,,0,0,0,,So I need a light bulb. Dialogue: 0,0:35:28.20,0:35:30.40,EN,,0,0,0,,And I suppose the other thing I'm going to need to have Dialogue: 0,0:35:31.02,0:35:32.84,EN,,0,0,0,,is a way of decrementing N. Dialogue: 0,0:35:34.84,0:35:36.09,EN,,0,0,0,,So I'm going to have a decrementer, Dialogue: 0,0:35:38.19,0:35:41.39,EN,,0,0,0,,which takes N and is going to put back the result into N. Dialogue: 0,0:35:46.62,0:35:48.40,EN,,0,0,0,,That's pretty much what I need in my machine. Dialogue: 0,0:35:49.55,0:35:51.64,EN,,0,0,0,,Now, there's a little bit else I need. Dialogue: 0,0:35:52.30,0:35:53.58,EN,,0,0,0,,It's a little bit more complicated, Dialogue: 0,0:35:55.16,0:35:56.88,EN,,0,0,0,,because I'm also going to need a way to store, Dialogue: 0,0:35:57.16,0:35:59.69,EN,,0,0,0,,to save away, the things that are going to be needed Dialogue: 0,0:36:01.02,0:36:03.07,EN,,0,0,0,,for resuming the computation of a factorial Dialogue: 0,0:36:03.10,0:36:04.89,EN,,0,0,0,,after I've done a sub-factorial. Dialogue: 0,0:36:06.25,0:36:06.86,EN,,0,0,0,,What's that? Dialogue: 0,0:36:07.23,0:36:08.73,EN,,0,0,0,,One thing I need is N. Dialogue: 0,0:36:09.85,0:36:12.04,EN,,0,0,0,,So I'm going to build here a thing called a stack. Dialogue: 0,0:36:14.70,0:36:15.77,EN,,0,0,0,,The stack is Dialogue: 0,0:36:17.98,0:36:24.97,EN,,0,0,0,,a bunch of stuff that I'm going to write in sequentially. Dialogue: 0,0:36:27.15,0:36:28.59,EN,,0,0,0,,I don't know how long it is. Dialogue: 0,0:36:29.15,0:36:31.48,EN,,0,0,0,,The longer it is, the better my illusion of infinity. Dialogue: 0,0:36:33.23,0:36:35.56,EN,,0,0,0,,And I'm going to have to have a way of getting stuff Dialogue: 0,0:36:35.60,0:36:37.02,EN,,0,0,0,,out of N and into the stack Dialogue: 0,0:36:38.12,0:36:39.08,EN,,0,0,0,,and vice versa. Dialogue: 0,0:36:39.93,0:36:41.74,EN,,0,0,0,,So I'm going to need a connection like this, Dialogue: 0,0:36:44.41,0:36:45.48,EN,,0,0,0,,which is two-way, Dialogue: 0,0:36:50.44,0:36:52.22,EN,,0,0,0,,whereby I can save the value of N Dialogue: 0,0:36:52.24,0:36:55.50,EN,,0,0,0,,and then restore it some other time through that connection. Dialogue: 0,0:36:56.04,0:36:56.84,EN,,0,0,0,,This is the stack. Dialogue: 0,0:36:58.10,0:37:01.71,EN,,0,0,0,,I also need a way of remembering Dialogue: 0,0:37:01.84,0:37:07.72,EN,,0,0,0,,where I was in the computation of factorial in the outer program. Dialogue: 0,0:37:08.53,0:37:10.06,EN,,0,0,0,,Now in the case of this machine, Dialogue: 0,0:37:10.76,0:37:13.34,EN,,0,0,0,,it isn't very much a problem. Dialogue: 0,0:37:14.17,0:37:16.24,EN,,0,0,0,,Factorial always returns, Dialogue: 0,0:37:16.86,0:37:19.07,EN,,0,0,0,,has to go back to the place where we multiply by N, Dialogue: 0,0:37:19.34,0:37:20.72,EN,,0,0,0,,except for the last time, Dialogue: 0,0:37:21.15,0:37:23.02,EN,,0,0,0,,when it has to return to whatever needs the factorial Dialogue: 0,0:37:23.04,0:37:24.04,EN,,0,0,0,,or go to done or stop. Dialogue: 0,0:37:25.66,0:37:26.67,EN,,0,0,0,,However, in general, Dialogue: 0,0:37:27.16,0:37:28.73,EN,,0,0,0,,I'm going to have to remember where I have been, Dialogue: 0,0:37:29.13,0:37:31.24,EN,,0,0,0,,because I might have computed factorial from somewhere else. Dialogue: 0,0:37:32.08,0:37:34.89,EN,,0,0,0,,I have to go back to that place and continue there. Dialogue: 0,0:37:36.07,0:37:38.00,EN,,0,0,0,,So I'm going to have to have some way of taking the place Dialogue: 0,0:37:38.01,0:37:40.86,EN,,0,0,0,,where the marble is in the finite state controller, Dialogue: 0,0:37:41.32,0:37:42.64,EN,,0,0,0,,the state of the controller, Dialogue: 0,0:37:44.22,0:37:46.35,EN,,0,0,0,,and storing that in the stack as well. Dialogue: 0,0:37:47.40,0:37:49.10,EN,,0,0,0,,And I'm going to have to have ways of restoring that Dialogue: 0,0:37:49.45,0:37:51.12,EN,,0,0,0,,back to the state of the-- the marble. Dialogue: 0,0:37:52.14,0:37:54.28,EN,,0,0,0,,So I have to have something that moves the marble to the right place. Dialogue: 0,0:37:54.70,0:37:56.52,EN,,0,0,0,,Well, we're going to have a place which is the marble now. Dialogue: 0,0:37:57.87,0:37:59.34,EN,,0,0,0,,And it's called the continue register, Dialogue: 0,0:38:03.61,0:38:04.52,EN,,0,0,0,,called continue, Dialogue: 0,0:38:09.16,0:38:10.68,EN,,0,0,0,,which is the place to put the marble Dialogue: 0,0:38:11.00,0:38:13.05,EN,,0,0,0,,next time I go to continue. Dialogue: 0,0:38:14.91,0:38:15.92,EN,,0,0,0,,That's what that's for. Dialogue: 0,0:38:16.14,0:38:18.48,EN,,0,0,0,,And so there's got to be some path from that into the controller. Dialogue: 0,0:38:22.91,0:38:27.12,EN,,0,0,0,,I also have to have some way of saving that on the stack. Dialogue: 0,0:38:29.45,0:38:33.10,EN,,0,0,0,,And I have to have some way of setting that up to have various constants, Dialogue: 0,0:38:34.01,0:38:35.69,EN,,0,0,0,,a certain fixed number of constants. Dialogue: 0,0:38:36.86,0:38:38.20,EN,,0,0,0,,And that's very easy to arrange. Dialogue: 0,0:38:38.84,0:38:40.14,EN,,0,0,0,,So let's have some constants here. Dialogue: 0,0:38:40.18,0:38:41.50,EN,,0,0,0,,We'll call this one after-fact. Dialogue: 0,0:38:47.32,0:38:48.75,EN,,0,0,0,,And that's a constant Dialogue: 0,0:38:48.84,0:38:51.50,EN,,0,0,0,,which will get into the continue register, Dialogue: 0,0:38:52.59,0:38:54.43,EN,,0,0,0,,and also another one called fact-done. Dialogue: 0,0:39:05.21,0:39:07.82,EN,,0,0,0,,So this is the machine I want to build. Dialogue: 0,0:39:08.13,0:39:09.48,EN,,0,0,0,,That's its datapaths, at least. Dialogue: 0,0:39:09.92,0:39:11.69,EN,,0,0,0,,And it mixes a little with the controller here, Dialogue: 0,0:39:11.85,0:39:14.59,EN,,0,0,0,,because of the fact that I have to remember where I was Dialogue: 0,0:39:14.70,0:39:16.35,EN,,0,0,0,,and restore myself to that place. Dialogue: 0,0:39:17.30,0:39:19.93,EN,,0,0,0,,But let's write the program now which represents the controller. Dialogue: 0,0:39:20.39,0:39:23.47,EN,,0,0,0,,I'm not going to write the define machine thing and the register list, Dialogue: 0,0:39:23.48,0:39:24.89,EN,,0,0,0,,because that's not very interesting. Dialogue: 0,0:39:25.13,0:39:27.79,EN,,0,0,0,,I'm just going to write down the sequence of instructions Dialogue: 0,0:39:27.82,0:39:29.02,EN,,0,0,0,,that constitute the controller. Dialogue: 0,0:39:31.48,0:39:41.85,EN,,0,0,0,,So we have assign, to set up, continue to done. Dialogue: 0,0:39:45.15,0:39:45.82,EN,,0,0,0,,We have a loop Dialogue: 0,0:39:47.34,0:39:56.08,EN,,0,0,0,,which says branch if equal 1 fetch N, Dialogue: 0,0:40:00.94,0:40:04.11,EN,,0,0,0,,if N is 1, then go to the base step of the induction, Dialogue: 0,0:40:06.06,0:40:07.20,EN,,0,0,0,,the simple case. Dialogue: 0,0:40:08.05,0:40:08.76,EN,,0,0,0,,Otherwise, Dialogue: 0,0:40:08.88,0:40:10.84,EN,,0,0,0,,I have to remember the things that are necessary Dialogue: 0,0:40:10.88,0:40:13.84,EN,,0,0,0,,to perform a sub-factorial. Dialogue: 0,0:40:14.67,0:40:16.75,EN,,0,0,0,,I'm going to go over here, and I have to perform a sub-factorial. Dialogue: 0,0:40:17.57,0:40:19.29,EN,,0,0,0,,So I have to remember what's needed to do that Dialogue: 0,0:40:19.71,0:40:22.52,EN,,0,0,0,,remember what's needed after I will be done with that. Dialogue: 0,0:40:24.00,0:40:25.51,EN,,0,0,0,,See, I'm about to do something terrible. Dialogue: 0,0:40:25.72,0:40:27.39,EN,,0,0,0,,I'm about to change the value of N. Dialogue: 0,0:40:28.57,0:40:30.40,EN,,0,0,0,,But this guy has to know the old value of N. Dialogue: 0,0:40:32.14,0:40:33.64,EN,,0,0,0,,But in order to make the sub-factorial work, Dialogue: 0,0:40:33.66,0:40:34.92,EN,,0,0,0,,I have to change the value of N. Dialogue: 0,0:40:35.60,0:40:37.10,EN,,0,0,0,,So I have to remember the old value. Dialogue: 0,0:40:38.00,0:40:39.60,EN,,0,0,0,,And I also have to remember where I've been. Dialogue: 0,0:40:40.85,0:40:42.32,EN,,0,0,0,,So I save up continue. Dialogue: 0,0:40:47.70,0:40:51.29,EN,,0,0,0,,And this is an instruction that says, put something in the stack. Dialogue: 0,0:40:53.12,0:40:55.53,EN,,0,0,0,,Save the contents of the continuation register, Dialogue: 0,0:40:56.51,0:40:58.00,EN,,0,0,0,,which in this case is done, Dialogue: 0,0:40:58.88,0:41:00.25,EN,,0,0,0,,because later I'm going to change that, too, Dialogue: 0,0:41:00.27,0:41:02.78,EN,,0,0,0,,because I need to go back to after-fact, as well. Dialogue: 0,0:41:03.55,0:41:04.19,EN,,0,0,0,,We'll see that. Dialogue: 0,0:41:05.04,0:41:09.71,EN,,0,0,0,,We save N, because I'm going to need that for later. Dialogue: 0,0:41:10.38,0:41:20.54,EN,,0,0,0,,Assign to N the decrement of fetch N. Dialogue: 0,0:41:23.26,0:41:28.97,EN,,0,0,0,,Assign continue, Dialogue: 0,0:41:32.12,0:41:33.42,EN,,0,0,0,,we're going to look at this now, Dialogue: 0,0:41:34.06,0:41:35.61,EN,,0,0,0,,to after, we'll call it. Dialogue: 0,0:41:37.69,0:41:38.70,EN,,0,0,0,,That's a good name for this, Dialogue: 0,0:41:38.73,0:41:40.65,EN,,0,0,0,,a little bit easier and shorter, and fits in here. Dialogue: 0,0:41:53.36,0:41:54.64,EN,,0,0,0,,Now look what I'm doing here. Dialogue: 0,0:41:55.33,0:41:57.02,EN,,0,0,0,,I'm saying, if the answer is 1, Dialogue: 0,0:41:58.72,0:41:59.66,EN,,0,0,0,,OK, I'm done. Dialogue: 0,0:42:00.46,0:42:01.66,EN,,0,0,0,,I'm going to have to just get the answer. Dialogue: 0,0:42:02.15,0:42:04.88,EN,,0,0,0,,Otherwise, I'm going to save the continuation, save N, Dialogue: 0,0:42:05.77,0:42:07.32,EN,,0,0,0,,make N one less than N, Dialogue: 0,0:42:07.60,0:42:09.63,EN,,0,0,0,,remember I'm going to come back to someplace else, Dialogue: 0,0:42:09.64,0:42:11.48,EN,,0,0,0,,and go back and start doing another factorial. Dialogue: 0,0:42:13.50,0:42:15.74,EN,,0,0,0,,OK? However, I've got a different machine in me now. Dialogue: 0,0:42:16.05,0:42:18.38,EN,,0,0,0,,N is 1, and continue is something else. Dialogue: 0,0:42:22.11,0:42:23.21,EN,,0,0,0,,N is N minus 1. Dialogue: 0,0:42:23.77,0:42:25.28,EN,,0,0,0,,Now after I'm done with that, Dialogue: 0,0:42:26.94,0:42:27.76,EN,,0,0,0,,I can go there. Dialogue: 0,0:42:28.66,0:42:30.46,EN,,0,0,0,,I will restore the old value of N, Dialogue: 0,0:42:32.68,0:42:36.56,EN,,0,0,0,,which is the opposite of this save over here. Dialogue: 0,0:42:38.36,0:42:39.88,EN,,0,0,0,,I will restore the continuation. Dialogue: 0,0:42:49.66,0:42:52.57,EN,,0,0,0,,I will then go to here. Dialogue: 0,0:42:54.32,0:43:00.86,EN,,0,0,0,,I will assign to the VAL register Dialogue: 0,0:43:01.16,0:43:08.13,EN,,0,0,0,,the product of N and fetch VAL. Dialogue: 0,0:43:13.44,0:43:18.30,EN,,0,0,0,,VAL fetch product assign. Dialogue: 0,0:43:19.79,0:43:21.44,EN,,0,0,0,,And then I will be done. Dialogue: 0,0:43:21.44,0:43:25.68,EN,,0,0,0,,I will have my answer to the sub-factorial in VAL. Dialogue: 0,0:43:26.57,0:43:27.37,EN,,0,0,0,,At that point, Dialogue: 0,0:43:27.66,0:43:28.75,EN,,0,0,0,,I'm going to return Dialogue: 0,0:43:29.28,0:43:31.61,EN,,0,0,0,,by going to the place where the continuation is pointing. Dialogue: 0,0:43:33.64,0:43:35.77,EN,,0,0,0,,That says, go to fetch continue. Dialogue: 0,0:43:45.87,0:43:47.40,EN,,0,0,0,,And then I have finally a base step, Dialogue: 0,0:43:49.31,0:43:50.51,EN,,0,0,0,,which is the immediate answer. Dialogue: 0,0:43:50.68,0:43:56.88,EN,,0,0,0,,Assign to VAL fetch N, Dialogue: 0,0:44:01.36,0:44:02.75,EN,,0,0,0,,and go to fetch continue. Dialogue: 0,0:44:12.67,0:44:13.55,EN,,0,0,0,,And then I'm done. Dialogue: 0,0:44:18.64,0:44:21.21,EN,,0,0,0,,Now let's see how this executes on a very simple case, Dialogue: 0,0:44:22.51,0:44:23.53,EN,,0,0,0,,because then we'll see Dialogue: 0,0:44:23.66,0:44:26.52,EN,,0,0,0,,the use of this stack to do the job we need. Dialogue: 0,0:44:26.89,0:44:28.22,EN,,0,0,0,,This is statically what it's doing, Dialogue: 0,0:44:28.22,0:44:29.80,EN,,0,0,0,,but we have look dynamically at this. Dialogue: 0,0:44:31.34,0:44:32.09,EN,,0,0,0,,So let's see. Dialogue: 0,0:44:32.30,0:44:34.56,EN,,0,0,0,,First thing we do is continue gets done. Dialogue: 0,0:44:36.73,0:44:38.09,EN,,0,0,0,,The way that happened is I pushed this. Dialogue: 0,0:44:38.30,0:44:39.60,EN,,0,0,0,,Let's call that done the way I have it. Dialogue: 0,0:44:46.22,0:44:47.03,EN,,0,0,0,,I push that button. Dialogue: 0,0:44:47.03,0:44:48.11,EN,,0,0,0,,Done goes into there. Dialogue: 0,0:44:48.95,0:44:53.71,EN,,0,0,0,,Now I also have to set this thing up to have an initial value. Dialogue: 0,0:44:53.85,0:44:58.08,EN,,0,0,0,,Let's consider a factorial of three, Dialogue: 0,0:44:58.38,0:44:59.24,EN,,0,0,0,,a simple case. Dialogue: 0,0:45:00.54,0:45:04.04,EN,,0,0,0,,And we're going to start out with our stack growing over here. Dialogue: 0,0:45:05.90,0:45:07.76,EN,,0,0,0,,Stacks have their own little internal state Dialogue: 0,0:45:07.79,0:45:09.05,EN,,0,0,0,,saying where they are, Dialogue: 0,0:45:09.80,0:45:11.64,EN,,0,0,0,,where the next place I'm going to write is. Dialogue: 0,0:45:12.77,0:45:14.59,EN,,0,0,0,,So now we say, is N 1? Dialogue: 0,0:45:14.76,0:45:15.71,EN,,0,0,0,,The answer is no. Dialogue: 0,0:45:16.11,0:45:18.56,EN,,0,0,0,,So now I'm going to save continue, bang. Dialogue: 0,0:45:19.15,0:45:20.65,EN,,0,0,0,,Now that done goes in here. Dialogue: 0,0:45:22.08,0:45:23.55,EN,,0,0,0,,And this moves to here, Dialogue: 0,0:45:24.88,0:45:26.14,EN,,0,0,0,,the next place I'm going to write. Dialogue: 0,0:45:26.66,0:45:28.78,EN,,0,0,0,,Save N 3. Dialogue: 0,0:45:29.95,0:45:30.32,EN,,0,0,0,,OK? Dialogue: 0,0:45:30.67,0:45:33.61,EN,,0,0,0,,Assign to N the decrement of N. Dialogue: 0,0:45:33.96,0:45:35.37,EN,,0,0,0,,That means I've pushed this button. Dialogue: 0,0:45:35.94,0:45:37.32,EN,,0,0,0,,This becomes 2. Dialogue: 0,0:45:38.73,0:45:42.28,EN,,0,0,0,,OK? Assign to continue aft. Dialogue: 0,0:45:42.58,0:45:43.61,EN,,0,0,0,,So I've pushed that button. Dialogue: 0,0:45:43.61,0:45:44.54,EN,,0,0,0,,Aft goes in here. Dialogue: 0,0:45:49.14,0:45:53.93,EN,,0,0,0,,OK, now go to loop, bang, so up to here. Dialogue: 0,0:45:54.83,0:45:57.08,EN,,0,0,0,,Is N 1? No Dialogue: 0,0:45:57.78,0:45:59.23,EN,,0,0,0,,So I have to save continue. Dialogue: 0,0:45:59.49,0:46:00.27,EN,,0,0,0,,What's continue? Dialogue: 0,0:46:00.60,0:46:01.53,EN,,0,0,0,,Continue is aft. Dialogue: 0,0:46:01.53,0:46:02.32,EN,,0,0,0,,Push this button. Dialogue: 0,0:46:02.78,0:46:03.95,EN,,0,0,0,,So this moves to here. Dialogue: 0,0:46:08.49,0:46:09.74,EN,,0,0,0,,I have to save N. Dialogue: 0,0:46:10.51,0:46:12.12,EN,,0,0,0,,N is over here. I got to 2. Dialogue: 0,0:46:12.28,0:46:13.37,EN,,0,0,0,,Push that button. Dialogue: 0,0:46:13.85,0:46:15.24,EN,,0,0,0,,So a 2 gets written there. Dialogue: 0,0:46:16.05,0:46:17.64,EN,,0,0,0,,And then this thing moves down here. Dialogue: 0,0:46:20.06,0:46:22.60,EN,,0,0,0,,OK, save N. Assign N to the decrement of N. Dialogue: 0,0:46:24.60,0:46:25.46,EN,,0,0,0,,This becomes a 1. Dialogue: 0,0:46:29.24,0:46:30.54,EN,,0,0,0,,Assign continue to aft. Dialogue: 0,0:46:31.37,0:46:34.48,EN,,0,0,0,,A-F-T gets written there again. Dialogue: 0,0:46:34.96,0:46:35.64,EN,,0,0,0,,Go to loop. Dialogue: 0,0:46:36.52,0:46:37.74,EN,,0,0,0,,Is N equal to 1? Dialogue: 0,0:46:37.93,0:46:39.52,EN,,0,0,0,,Oh, yes, the answer is 1. Dialogue: 0,0:46:41.04,0:46:43.26,EN,,0,0,0,,OK, go to base step. Dialogue: 0,0:46:44.16,0:46:45.77,EN,,0,0,0,,Assign to VAL fetch of N. Dialogue: 0,0:46:46.56,0:46:50.72,EN,,0,0,0,,Bang, 1 gets put in there. OK? Dialogue: 0,0:46:51.10,0:46:52.20,EN,,0,0,0,,Go to fetch continue. Dialogue: 0,0:46:52.20,0:46:53.53,EN,,0,0,0,,So we look in continue. Dialogue: 0,0:46:53.68,0:46:56.06,EN,,0,0,0,,Basically, I'm pushing a button over here that goes to the controller. Dialogue: 0,0:46:56.67,0:46:58.28,EN,,0,0,0,,The continue becomes aft, Dialogue: 0,0:46:58.32,0:47:00.25,EN,,0,0,0,,and all of a sudden, the program's running here. Dialogue: 0,0:47:02.64,0:47:05.63,EN,,0,0,0,,I now have to restore the outer version of factorial. Dialogue: 0,0:47:06.65,0:47:07.55,EN,,0,0,0,,So we go here. Dialogue: 0,0:47:07.55,0:47:09.48,EN,,0,0,0,,We say, restore N. Dialogue: 0,0:47:10.32,0:47:13.04,EN,,0,0,0,,So restore N means take the contents that's here. Dialogue: 0,0:47:13.94,0:47:18.17,EN,,0,0,0,,Push this button, and it goes into here, 2, Dialogue: 0,0:47:18.56,0:47:20.04,EN,,0,0,0,,and the pointer moves up. Dialogue: 0,0:47:21.98,0:47:24.49,EN,,0,0,0,,Restore continue, pretty easy. Dialogue: 0,0:47:24.81,0:47:26.49,EN,,0,0,0,,Go push this button. Dialogue: 0,0:47:27.02,0:47:28.92,EN,,0,0,0,,And then aft gets written in here again. Dialogue: 0,0:47:31.28,0:47:32.64,EN,,0,0,0,,That means this thing moves up. Dialogue: 0,0:47:32.64,0:47:35.19,EN,,0,0,0,,I've gotten rid of something else on my stack. Dialogue: 0,0:47:42.24,0:47:43.47,EN,,0,0,0,,Right, then I go to here, Dialogue: 0,0:47:43.87,0:47:47.15,EN,,0,0,0,,which says, assign to VAL the product of N and VAL. Dialogue: 0,0:47:47.85,0:47:50.57,EN,,0,0,0,,So I push this button over here, bang. Dialogue: 0,0:47:50.97,0:47:52.91,EN,,0,0,0,,2 times 1 gives me a 2, Dialogue: 0,0:47:54.01,0:47:54.75,EN,,0,0,0,,get written there. Dialogue: 0,0:47:55.76,0:47:57.20,EN,,0,0,0,,OK? Go to fetch continue. Dialogue: 0,0:47:57.54,0:47:59.85,EN,,0,0,0,,Continue is aft. I go to aft. Dialogue: 0,0:48:01.15,0:48:03.88,EN,,0,0,0,,OK? Aft says restore N. Dialogue: 0,0:48:04.36,0:48:05.72,EN,,0,0,0,,Do your restore N, Dialogue: 0,0:48:05.87,0:48:08.44,EN,,0,0,0,,means I take the value over here, which is 3, Dialogue: 0,0:48:09.24,0:48:10.33,EN,,0,0,0,,push this up to here, Dialogue: 0,0:48:10.60,0:48:15.50,EN,,0,0,0,,and move it into here, N. Dialogue: 0,0:48:16.25,0:48:17.34,EN,,0,0,0,,Now it's pushing that button. Dialogue: 0,0:48:18.01,0:48:19.90,EN,,0,0,0,,The next thing I do is restore continue. Dialogue: 0,0:48:20.20,0:48:22.20,EN,,0,0,0,,Continue is now going to become done. Dialogue: 0,0:48:22.83,0:48:26.78,EN,,0,0,0,,So this moves up here when I push this button. Dialogue: 0,0:48:27.13,0:48:29.72,EN,,0,0,0,,Done may or may be there anymore, Dialogue: 0,0:48:29.72,0:48:31.55,EN,,0,0,0,,I'm not interested, but it certainly is here. Dialogue: 0,0:48:35.80,0:48:38.12,EN,,0,0,0,,Next thing I do is assign to VAL Dialogue: 0,0:48:38.43,0:48:40.76,EN,,0,0,0,,the product of the fetch of N and the fetch of VAL. Dialogue: 0,0:48:41.44,0:48:44.30,EN,,0,0,0,,That's pushing this button over here, bang. Dialogue: 0,0:48:44.30,0:48:45.77,EN,,0,0,0,,2 times 3 is 6. Dialogue: 0,0:48:46.52,0:48:47.87,EN,,0,0,0,,So I get a 6 over here. Dialogue: 0,0:48:50.97,0:48:53.40,EN,,0,0,0,,OK? And go to fetch continue, Dialogue: 0,0:48:53.48,0:48:54.83,EN,,0,0,0,,whoops, I go to done, and I'm done. Dialogue: 0,0:48:55.02,0:48:56.09,EN,,0,0,0,,And my answer is 6, Dialogue: 0,0:48:56.60,0:48:57.82,EN,,0,0,0,,as you can see in the VAL register. Dialogue: 0,0:48:58.95,0:48:59.82,EN,,0,0,0,,And in fact, Dialogue: 0,0:49:00.91,0:49:03.34,EN,,0,0,0,,the stack is in the state it originally was in. Dialogue: 0,0:49:08.20,0:49:10.70,EN,,0,0,0,,Now there's a bit of discipline in using these things like stacks Dialogue: 0,0:49:11.20,0:49:12.27,EN,,0,0,0,,that we have to be careful of. Dialogue: 0,0:49:13.62,0:49:15.52,EN,,0,0,0,,And we'll see that in the next segment. Dialogue: 0,0:49:16.26,0:49:18.46,EN,,0,0,0,,But first I want to ask if there are any questions for this. Dialogue: 0,0:49:28.56,0:49:29.64,EN,,0,0,0,,Are there any questions? Dialogue: 0,0:49:30.17,0:49:30.63,EN,,0,0,0,,Yes, Ron. Dialogue: 0,0:49:30.63,0:49:33.37,EN,,0,0,0,,AUDIENCE: What happens when you roll off the end of the stack with-- Dialogue: 0,0:49:33.39,0:49:34.62,EN,,0,0,0,,PROFESSOR: What do you mean, roll off of? Dialogue: 0,0:49:35.03,0:49:37.50,EN,,0,0,0,,AUDIENCE: Well, the largest number-- a larger starting point of N Dialogue: 0,0:49:37.52,0:49:38.72,EN,,0,0,0,,requires more memory, correct? Dialogue: 0,0:49:38.86,0:49:39.44,EN,,0,0,0,,PROFESSOR: Oh, yes. Dialogue: 0,0:49:39.44,0:49:41.12,EN,,0,0,0,,Well, I need to have a long enough stack. Dialogue: 0,0:49:41.53,0:49:43.20,EN,,0,0,0,,You say, what if I violate my illusion? Dialogue: 0,0:49:43.84,0:49:44.12,EN,,0,0,0,,AUDIENCE: Yes. Dialogue: 0,0:49:44.55,0:49:46.73,EN,,0,0,0,,PROFESSOR: Well, then the magic doesn't work. OK? Dialogue: 0,0:49:47.96,0:49:51.00,EN,,0,0,0,,The truth of the matter is that every machine is finite. Dialogue: 0,0:49:51.64,0:49:53.72,EN,,0,0,0,,And for a procedure like this, Dialogue: 0,0:49:54.17,0:49:58.86,EN,,0,0,0,,there's a limit to the number of sub-factorials I could have. Dialogue: 0,0:49:59.95,0:50:02.48,EN,,0,0,0,,Remember when we were doing the y-operator a while ago, Dialogue: 0,0:50:02.80,0:50:06.22,EN,,0,0,0,,we pointed out that there was a sequence of exponentiation procedures, Dialogue: 0,0:50:06.25,0:50:08.09,EN,,0,0,0,,each of which was a little better than the previous one. Dialogue: 0,0:50:08.72,0:50:11.60,EN,,0,0,0,,Well, we're now seeing how we implement that mathematical idea. Dialogue: 0,0:50:13.09,0:50:14.19,EN,,0,0,0,,The limiting process Dialogue: 0,0:50:14.35,0:50:16.33,EN,,0,0,0,,is only so good as as far as you take the limit. Dialogue: 0,0:50:17.99,0:50:19.42,EN,,0,0,0,,If you think about it, what am I using here? Dialogue: 0,0:50:19.42,0:50:22.65,EN,,0,0,0,,I'm using about two chunks, pieces of memory Dialogue: 0,0:50:23.04,0:50:27.07,EN,,0,0,0,,for iteration for every recursion of this process. Dialogue: 0,0:50:29.10,0:50:31.71,EN,,0,0,0,,If we try to compute factorial of 10,000, Dialogue: 0,0:50:31.72,0:50:32.81,EN,,0,0,0,,that's not a lot of memory. Dialogue: 0,0:50:33.18,0:50:34.68,EN,,0,0,0,,On the other hand, it's an awful big number. Dialogue: 0,0:50:35.95,0:50:38.41,EN,,0,0,0,,So the question is, is that a valuable thing in this case. Dialogue: 0,0:50:39.18,0:50:42.19,EN,,0,0,0,,But it really turns out not to be a terrible limit, Dialogue: 0,0:50:42.22,0:50:43.53,EN,,0,0,0,,because memory is el cheapo, Dialogue: 0,0:50:44.16,0:50:45.34,EN,,0,0,0,,and people are pretty expensive. Dialogue: 0,0:50:48.13,0:50:50.22,EN,,0,0,0,,OK, thank you, let's take a break. Dialogue: 0,0:50:50.78,0:51:07.60,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:51:56.11,0:51:57.04,EN,,0,0,0,,PROFESSOR: Well, let's see. Dialogue: 0,0:51:58.70,0:52:03.37,EN,,0,0,0,,What I've shown you now is how to do a simple iterative process Dialogue: 0,0:52:03.69,0:52:05.31,EN,,0,0,0,,and a simple recursive process. Dialogue: 0,0:52:05.64,0:52:08.68,EN,,0,0,0,,I just want to summarize the design of simple machines Dialogue: 0,0:52:09.63,0:52:11.12,EN,,0,0,0,,for specific applications Dialogue: 0,0:52:11.21,0:52:13.58,EN,,0,0,0,,by showing you a little bit more complicated design, Dialogue: 0,0:52:13.96,0:52:17.13,EN,,0,0,0,,that of a thing that does doubly recursive Fibonacci, Dialogue: 0,0:52:17.23,0:52:19.88,EN,,0,0,0,,because it will indicate to us, and we'll understand, Dialogue: 0,0:52:20.04,0:52:22.68,EN,,0,0,0,,a bit about the conventions required Dialogue: 0,0:52:22.76,0:52:25.04,EN,,0,0,0,,for making stacks operate correctly. Dialogue: 0,0:52:26.40,0:52:27.11,EN,,0,0,0,,So let's see. Dialogue: 0,0:52:27.11,0:52:28.27,EN,,0,0,0,,I'm just going to write down, first of all, Dialogue: 0,0:52:28.30,0:52:29.71,EN,,0,0,0,,the program I'm going to translate. Dialogue: 0,0:52:34.15,0:52:36.52,EN,,0,0,0,,I need a Fibonacci procedure, Dialogue: 0,0:52:39.23,0:52:41.58,EN,,0,0,0,,it's very simple, which says, if Dialogue: 0,0:52:44.60,0:52:48.56,EN,,0,0,0,,N is less than 2, the result is N, Dialogue: 0,0:52:49.26,0:52:55.34,EN,,0,0,0,,otherwise it's the sum of Fib of N minus 1 Dialogue: 0,0:52:58.44,0:52:59.85,EN,,0,0,0,,and Fib of N minus 2. Dialogue: 0,0:53:07.05,0:53:09.29,EN,,0,0,0,,That's the plan I have here. Dialogue: 0,0:53:09.29,0:53:12.56,EN,,0,0,0,,And we're just going to write down the controller for such a machine. Dialogue: 0,0:53:13.07,0:53:15.53,EN,,0,0,0,,We're going to assume that there are registers, N, Dialogue: 0,0:53:15.56,0:53:19.15,EN,,0,0,0,,which holds the number we're taking Fibonacci of, Dialogue: 0,0:53:19.82,0:53:21.80,EN,,0,0,0,,VAL, which is where the answer is going to get put, Dialogue: 0,0:53:22.17,0:53:24.97,EN,,0,0,0,,and continue, which is the thing that's linked to the controller, Dialogue: 0,0:53:26.11,0:53:26.81,EN,,0,0,0,,like before. Dialogue: 0,0:53:26.96,0:53:29.21,EN,,0,0,0,,But I'm not going to draw another physical datapath, Dialogue: 0,0:53:31.53,0:53:34.00,EN,,0,0,0,,because it's pretty much the same as the last one you've seen. Dialogue: 0,0:53:34.36,0:53:37.84,EN,,0,0,0,,And of course, one of the most amazing things about computation Dialogue: 0,0:53:38.75,0:53:39.88,EN,,0,0,0,,is that after a while, Dialogue: 0,0:53:40.08,0:53:41.93,EN,,0,0,0,,you build up a little more features and a few more features, Dialogue: 0,0:53:41.95,0:53:43.32,EN,,0,0,0,,and all of the sudden, you've got everything you need. Dialogue: 0,0:53:44.75,0:53:47.60,EN,,0,0,0,,So it's remarkable that it just gets there so fast. Dialogue: 0,0:53:48.17,0:53:50.84,EN,,0,0,0,,I don't need much more to make a universal computer. Dialogue: 0,0:53:51.81,0:53:54.68,EN,,0,0,0,,But in any case, let's look at the controller for the Fibonacci thing. Dialogue: 0,0:53:55.06,0:53:57.07,EN,,0,0,0,,First thing I want to do is Dialogue: 0,0:53:57.32,0:54:02.52,EN,,0,0,0,,start the thing up by assign to continue Dialogue: 0,0:54:07.13,0:54:10.28,EN,,0,0,0,,a place called done, called Fib-done here. Dialogue: 0,0:54:14.14,0:54:15.53,EN,,0,0,0,,So that means that somewhere over here, Dialogue: 0,0:54:15.55,0:54:18.48,EN,,0,0,0,,I'm going to have a label, Fib-done, Dialogue: 0,0:54:19.71,0:54:21.10,EN,,0,0,0,,which is the place where I go Dialogue: 0,0:54:21.23,0:54:22.44,EN,,0,0,0,,when I want the machine to stop. Dialogue: 0,0:54:24.00,0:54:24.86,EN,,0,0,0,,That's what that is. Dialogue: 0,0:54:25.92,0:54:26.89,EN,,0,0,0,,And I'm going to make up a loop. Dialogue: 0,0:54:31.11,0:54:34.25,EN,,0,0,0,,It's a place I'm going to go to in order to start up computing a Fib. Dialogue: 0,0:54:35.47,0:54:36.86,EN,,0,0,0,,Whatever is in N at this point, Dialogue: 0,0:54:37.39,0:54:38.99,EN,,0,0,0,,Fibonacci will be computed of, Dialogue: 0,0:54:39.13,0:54:42.01,EN,,0,0,0,,and we will return to the place specified by continue. Dialogue: 0,0:54:44.80,0:54:48.40,EN,,0,0,0,,So what you're going to see here at this place, Dialogue: 0,0:54:48.44,0:54:50.48,EN,,0,0,0,,what I want here is the contract Dialogue: 0,0:54:50.97,0:54:54.25,EN,,0,0,0,,that says, I'm going to write this with a comment syntax, Dialogue: 0,0:54:54.57,0:55:00.99,EN,,0,0,0,,the contract is N contains arg, the argument. Dialogue: 0,0:55:02.10,0:55:09.82,EN,,0,0,0,,Continue is the recipient. Dialogue: 0,0:55:13.36,0:55:14.29,EN,,0,0,0,,And that's where it is. Dialogue: 0,0:55:15.71,0:55:18.96,EN,,0,0,0,,At this point, if I ever go to this place, Dialogue: 0,0:55:19.24,0:55:21.04,EN,,0,0,0,,I'm expecting this to be true, Dialogue: 0,0:55:21.52,0:55:23.32,EN,,0,0,0,,the argument for computing the Fibonacci. Dialogue: 0,0:55:24.82,0:55:26.83,EN,,0,0,0,,Now the next thing I want to do is to branch. Dialogue: 0,0:55:30.22,0:55:32.22,EN,,0,0,0,,And if N is less than 2-- Dialogue: 0,0:55:35.07,0:55:37.44,EN,,0,0,0,,by the way, I'm using what looks like Lisp syntax. Dialogue: 0,0:55:38.73,0:55:39.63,EN,,0,0,0,,This is not Lisp. Dialogue: 0,0:55:41.31,0:55:42.38,EN,,0,0,0,,This does not run. Dialogue: 0,0:55:42.75,0:55:45.47,EN,,0,0,0,,What I'm writing here does not run as a simple Lisp program. Dialogue: 0,0:55:46.12,0:55:49.31,EN,,0,0,0,,This is a representation of another language. Dialogue: 0,0:55:49.71,0:55:52.25,EN,,0,0,0,,The reason I'm using the syntax of parentheses and so on Dialogue: 0,0:55:52.40,0:55:54.70,EN,,0,0,0,,is because I tend to use a Lisp system Dialogue: 0,0:55:55.32,0:55:57.34,EN,,0,0,0,,to write an interpreter for this Dialogue: 0,0:55:57.82,0:55:59.18,EN,,0,0,0,,which allows me to simulate Dialogue: 0,0:55:59.29,0:56:00.91,EN,,0,0,0,,the machine I'm trying to build. Dialogue: 0,0:56:03.38,0:56:06.24,EN,,0,0,0,,I don't want to confuse this to think that this is Lisp code. Dialogue: 0,0:56:06.94,0:56:08.60,EN,,0,0,0,,It's just I'm using a lot of the pieces of Lisp. Dialogue: 0,0:56:09.51,0:56:10.84,EN,,0,0,0,,I'm embedding a language in Lisp, Dialogue: 0,0:56:11.02,0:56:12.44,EN,,0,0,0,,using Lisp as pieces Dialogue: 0,0:56:12.72,0:56:15.12,EN,,0,0,0,,to make my process of making my simulator easy. Dialogue: 0,0:56:16.62,0:56:18.56,EN,,0,0,0,,So I'm inheriting from Lisp all of its properties. Dialogue: 0,0:56:19.10,0:56:21.53,EN,,0,0,0,,Fetch of N 2, Dialogue: 0,0:56:21.77,0:56:23.72,EN,,0,0,0,,I want to go to a place called immediate answer. Dialogue: 0,0:56:26.20,0:56:27.29,EN,,0,0,0,,It's the base step. Dialogue: 0,0:56:33.15,0:56:34.35,EN,,0,0,0,,Now, that's somewhere over here, Dialogue: 0,0:56:35.92,0:56:36.89,EN,,0,0,0,,just above done. Dialogue: 0,0:56:37.75,0:56:38.64,EN,,0,0,0,,And we'll see it later. Dialogue: 0,0:56:39.42,0:56:40.70,EN,,0,0,0,,Now, in the general case, Dialogue: 0,0:56:40.72,0:56:42.44,EN,,0,0,0,,which is the part I'm going to write down now, Dialogue: 0,0:56:43.13,0:56:44.19,EN,,0,0,0,,let's just do it. Dialogue: 0,0:56:44.91,0:56:48.20,EN,,0,0,0,,Well, first of all, I'm going to have to call Fibonacci twice. Dialogue: 0,0:56:49.42,0:56:52.54,EN,,0,0,0,,In each case-- well, in one case at least, Dialogue: 0,0:56:52.78,0:56:53.95,EN,,0,0,0,,I'm going to have to know what to do Dialogue: 0,0:56:53.96,0:56:55.36,EN,,0,0,0,,to come back and do the next one. Dialogue: 0,0:56:56.31,0:56:58.36,EN,,0,0,0,,I have to remember, Dialogue: 0,0:56:59.20,0:57:01.23,EN,,0,0,0,,have I done the first Fib, Dialogue: 0,0:57:01.26,0:57:02.54,EN,,0,0,0,,or have I done the second one? Dialogue: 0,0:57:04.50,0:57:07.04,EN,,0,0,0,,Do I have to come back to the place where I do the second Fib, Dialogue: 0,0:57:07.07,0:57:09.08,EN,,0,0,0,,or do I have to come back to the place where I do the add? Dialogue: 0,0:57:10.12,0:57:12.11,EN,,0,0,0,,In both cases I going to need, I don't Dialogue: 0,0:57:12.14,0:57:14.46,EN,,0,0,0,,In the first case, over the first Fibonacci, Dialogue: 0,0:57:14.51,0:57:16.98,EN,,0,0,0,,I'm going to need the value of N for computing for the second one. Dialogue: 0,0:57:19.84,0:57:21.58,EN,,0,0,0,,So I have to store some of these things up. Dialogue: 0,0:57:23.36,0:57:24.89,EN,,0,0,0,,So first I'm going to save continue. Dialogue: 0,0:57:26.19,0:57:27.32,EN,,0,0,0,,That's who needs the answer. Dialogue: 0,0:57:31.32,0:57:32.46,EN,,0,0,0,,And the reason I'm doing that Dialogue: 0,0:57:32.48,0:57:34.20,EN,,0,0,0,,is because I'm about to assign continue Dialogue: 0,0:57:40.11,0:57:44.32,EN,,0,0,0,,to the place which is the place I want to go to after. Dialogue: 0,0:57:46.83,0:57:50.27,EN,,0,0,0,,Let's call it Fib-N-minus-1, Dialogue: 0,0:57:51.04,0:57:53.76,EN,,0,0,0,,big long name, classic Lisp name. Dialogue: 0,0:57:57.36,0:58:00.22,EN,,0,0,0,,Because I'm going to compute the first Fib of N minus 1, Dialogue: 0,0:58:00.84,0:58:01.72,EN,,0,0,0,,and then after that, Dialogue: 0,0:58:01.72,0:58:03.29,EN,,0,0,0,,I want to come back and do something else. Dialogue: 0,0:58:03.96,0:58:06.52,EN,,0,0,0,,That's the place I want to go to after I've done Dialogue: 0,0:58:07.55,0:58:09.48,EN,,0,0,0,,the first Fibonacci calculation. Dialogue: 0,0:58:11.52,0:58:13.13,EN,,0,0,0,,And I want to do a save of N, Dialogue: 0,0:58:14.41,0:58:17.26,EN,,0,0,0,,because I'm going to need it later, after that. Dialogue: 0,0:58:19.13,0:58:20.54,EN,,0,0,0,,Now I'm going to, at this point, Dialogue: 0,0:58:20.67,0:58:22.84,EN,,0,0,0,,get ready to do the Fibonacci of N minus 1. Dialogue: 0,0:58:23.02,0:58:33.95,EN,,0,0,0,,So assign to N the difference of the fetch of N and 1. Dialogue: 0,0:58:38.11,0:58:40.27,EN,,0,0,0,,Now I'm ready to go back to doing the Fib loop. Dialogue: 0,0:58:47.18,0:58:49.87,EN,,0,0,0,,Do I have... Have I satisfied my contract? Dialogue: 0,0:58:50.40,0:58:51.50,EN,,0,0,0,,And the answer is yes. Dialogue: 0,0:58:51.77,0:58:55.12,EN,,0,0,0,,N contains N minus 1, which is what I need. Dialogue: 0,0:58:56.43,0:59:00.09,EN,,0,0,0,,OK? Continue contains a place I want to go to when I'm done Dialogue: 0,0:59:01.28,0:59:03.07,EN,,0,0,0,,with calculating FIB N minus 1. Dialogue: 0,0:59:04.10,0:59:05.44,EN,,0,0,0,,So I've satisfied the contract. Dialogue: 0,0:59:05.44,0:59:09.02,EN,,0,0,0,,And therefore, I can write down here a tag, after, a label, Dialogue: 0,0:59:11.47,0:59:17.56,EN,,0,0,0,,after-Fib-N-minus-1. Dialogue: 0,0:59:20.49,0:59:21.63,EN,,0,0,0,,Now what am I going to do here? Dialogue: 0,0:59:22.69,0:59:23.61,EN,,0,0,0,,Here's a place Dialogue: 0,0:59:23.95,0:59:26.75,EN,,0,0,0,,where I now have to get ready to do Fib of N minus 2. Dialogue: 0,0:59:29.27,0:59:30.72,EN,,0,0,0,,But in order to do a Fib of N minus 2, Dialogue: 0,0:59:30.75,0:59:31.63,EN,,0,0,0,,look, I don't know. Dialogue: 0,0:59:31.78,0:59:33.40,EN,,0,0,0,,I've clobbered my N over here. Dialogue: 0,0:59:33.81,0:59:35.47,EN,,0,0,0,,And presumably my N is counted down Dialogue: 0,0:59:37.85,0:59:38.80,EN,,0,0,0,,all the way to 1 or 0 or something at this point. Dialogue: 0,0:59:39.78,0:59:42.51,EN,,0,0,0,,So I don't know what the value of N in the N register is. Dialogue: 0,0:59:43.03,0:59:44.75,EN,,0,0,0,,I want the value of N that was on the stack Dialogue: 0,0:59:44.80,0:59:46.00,EN,,0,0,0,,that I saved over here Dialogue: 0,0:59:46.17,0:59:47.88,EN,,0,0,0,,so that could restore it over here. Dialogue: 0,0:59:49.52,0:59:51.02,EN,,0,0,0,,I saved up the value of N, Dialogue: 0,0:59:51.15,0:59:54.49,EN,,0,0,0,,which is this value of N at this point, Dialogue: 0,0:59:54.89,0:59:57.37,EN,,0,0,0,,so that I could restore it after computing Fib of N minus 1, Dialogue: 0,0:59:57.53,0:59:59.36,EN,,0,0,0,,so that I could count that down to N minus 2 Dialogue: 0,0:59:59.39,1:00:00.86,EN,,0,0,0,,and then compute Fib of N minus 2. Dialogue: 0,1:00:01.81,1:00:02.75,EN,,0,0,0,,So let's restore that. Dialogue: 0,1:00:08.83,1:00:09.77,EN,,0,0,0,,Restore of N. Dialogue: 0,1:00:11.13,1:00:15.98,EN,,0,0,0,,Now I'm about to do something which is superstitious, Dialogue: 0,1:00:16.00,1:00:17.40,EN,,0,0,0,,and we will remove it shortly. Dialogue: 0,1:00:18.52,1:00:20.48,EN,,0,0,0,,I am about to finish the sequence Dialogue: 0,1:00:20.59,1:00:23.44,EN,,0,0,0,,of doing the subroutine call, if you will. Dialogue: 0,1:00:24.80,1:00:25.95,EN,,0,0,0,,I'm going to say, well, Dialogue: 0,1:00:26.06,1:00:27.90,EN,,0,0,0,,I also saved up the continuation, Dialogue: 0,1:00:28.48,1:00:30.43,EN,,0,0,0,,since I'm going to restore it now. Dialogue: 0,1:00:31.60,1:00:32.60,EN,,0,0,0,,But actually, I don't have to, Dialogue: 0,1:00:32.64,1:00:33.55,EN,,0,0,0,,because I'm not going to need it. Dialogue: 0,1:00:34.61,1:00:35.72,EN,,0,0,0,,We'll fix that in a second. Dialogue: 0,1:00:36.26,1:00:37.95,EN,,0,0,0,,So we'll do a restore of continue, Dialogue: 0,1:00:46.04,1:00:48.02,EN,,0,0,0,,which is what I would in general need to do. Dialogue: 0,1:00:48.02,1:00:49.23,EN,,0,0,0,,And we're just going to see whats called Dialogue: 0,1:00:49.31,1:00:52.14,EN,,0,0,0,,what you would call in the compiler world a peephole optimization, Dialogue: 0,1:00:52.27,1:00:53.72,EN,,0,0,0,,which says, whoops, you didn't have to do that. Dialogue: 0,1:00:55.42,1:00:57.10,EN,,0,0,0,,OK, so the next thing I see here Dialogue: 0,1:00:58.46,1:01:02.28,EN,,0,0,0,,is that I have to get ready now to do Fibonacci of N minus 2. Dialogue: 0,1:01:02.77,1:01:04.49,EN,,0,0,0,,But I don't have to save N anymore. Dialogue: 0,1:01:05.05,1:01:06.72,EN,,0,0,0,,The reason why I don't have to save N anymore Dialogue: 0,1:01:06.80,1:01:09.34,EN,,0,0,0,,is because I don't need N after I've done Fib of N minus 2, Dialogue: 0,1:01:09.36,1:01:10.72,EN,,0,0,0,,because the next thing I do is add. Dialogue: 0,1:01:13.54,1:01:15.85,EN,,0,0,0,,So I'm just going to set up my N that way. Dialogue: 0,1:01:16.60,1:01:28.99,EN,,0,0,0,,Assign N minus difference of fetch N and 2. Dialogue: 0,1:01:31.85,1:01:34.01,EN,,0,0,0,,Now I have to finish the setup Dialogue: 0,1:01:34.27,1:01:36.73,EN,,0,0,0,,for calling Fibonacci of N minus 2. Dialogue: 0,1:01:36.95,1:01:38.33,EN,,0,0,0,,Well, I have to save up continue Dialogue: 0,1:01:44.22,1:01:49.02,EN,,0,0,0,,and assign continue, continue, Dialogue: 0,1:01:52.30,1:01:59.95,EN,,0,0,0,,to the place which is after Fib N 2, Dialogue: 0,1:02:02.57,1:02:04.03,EN,,0,0,0,,that place over here somewhere. Dialogue: 0,1:02:05.32,1:02:07.23,EN,,0,0,0,,However, I've got to be very careful. Dialogue: 0,1:02:08.65,1:02:11.42,EN,,0,0,0,,The old value, the value of Fib of N minus 1, Dialogue: 0,1:02:12.06,1:02:13.12,EN,,0,0,0,,I'm going to need later. Dialogue: 0,1:02:15.30,1:02:17.37,EN,,0,0,0,,The value of Fibonacci of N minus 1, Dialogue: 0,1:02:17.61,1:02:18.48,EN,,0,0,0,,I'm going to need. Dialogue: 0,1:02:18.78,1:02:19.80,EN,,0,0,0,,And I can't clobber it, Dialogue: 0,1:02:21.07,1:02:23.60,EN,,0,0,0,,because I'm going to have to add it to the value of Fib of N minus 2. Dialogue: 0,1:02:24.15,1:02:25.88,EN,,0,0,0,,That's in the value register, so I'm going to save it. Dialogue: 0,1:02:27.79,1:02:32.60,EN,,0,0,0,,So I have to save this right now, save up VAL. Dialogue: 0,1:02:33.78,1:02:35.44,EN,,0,0,0,,And now I can go off to my subroutine, Dialogue: 0,1:02:36.67,1:02:39.54,EN,,0,0,0,,go to Fib loop. Dialogue: 0,1:02:44.22,1:02:46.57,EN,,0,0,0,,Now before I go any further Dialogue: 0,1:02:46.80,1:02:49.36,EN,,0,0,0,,and finish this program, Dialogue: 0,1:02:49.39,1:02:51.05,EN,,0,0,0,,I just want to look at this segment so far Dialogue: 0,1:02:51.23,1:02:56.00,EN,,0,0,0,,and see, oh yes, there's a sequence of instructions here, if you will Dialogue: 0,1:02:57.84,1:02:59.08,EN,,0,0,0,,that I can do something about. Dialogue: 0,1:03:01.58,1:03:03.20,EN,,0,0,0,,Here I have a restore of continue, Dialogue: 0,1:03:04.25,1:03:05.48,EN,,0,0,0,,a save of continue, Dialogue: 0,1:03:06.01,1:03:07.40,EN,,0,0,0,,and then an assign of continue, Dialogue: 0,1:03:08.70,1:03:10.64,EN,,0,0,0,,with no other references to continue in between. Dialogue: 0,1:03:13.84,1:03:15.48,EN,,0,0,0,,The restore followed by the save Dialogue: 0,1:03:15.50,1:03:16.67,EN,,0,0,0,,leaves the stack unchanged. Dialogue: 0,1:03:19.09,1:03:21.72,EN,,0,0,0,,The only difference is that I set the continue register to a value, Dialogue: 0,1:03:21.96,1:03:23.28,EN,,0,0,0,,which is the value that was on the stack. Dialogue: 0,1:03:24.33,1:03:25.79,EN,,0,0,0,,Since I now clobber that value, Dialogue: 0,1:03:26.44,1:03:27.93,EN,,0,0,0,,as in it was never referenced, Dialogue: 0,1:03:28.59,1:03:30.09,EN,,0,0,0,,these instructions are unnecessary. Dialogue: 0,1:03:31.76,1:03:35.39,EN,,0,0,0,,So we will remove these. Dialogue: 0,1:03:38.88,1:03:40.78,EN,,0,0,0,,But I couldn't have seen that unless I had written them down. Dialogue: 0,1:03:43.78,1:03:44.72,EN,,0,0,0,,Was that really true? Dialogue: 0,1:03:45.77,1:03:46.60,EN,,0,0,0,,Well, I don't know. Dialogue: 0,1:03:48.61,1:03:52.91,EN,,0,0,0,,OK, so we've now gone off to compute Fibonacci of N minus 2. Dialogue: 0,1:03:53.66,1:03:54.59,EN,,0,0,0,,So after that, Dialogue: 0,1:04:02.96,1:04:03.85,EN,,0,0,0,,what are we going to do? Dialogue: 0,1:04:05.07,1:04:06.76,EN,,0,0,0,,Well, I suppose the first thing we have to do-- Dialogue: 0,1:04:06.99,1:04:07.88,EN,,0,0,0,,we've got two things. Dialogue: 0,1:04:07.96,1:04:10.49,EN,,0,0,0,,We've got a thing in the value register which is now valuable. Dialogue: 0,1:04:10.92,1:04:11.98,EN,,0,0,0,,We also have a thing on the stack Dialogue: 0,1:04:12.04,1:04:13.63,EN,,0,0,0,,can be restored into the value register. Dialogue: 0,1:04:14.81,1:04:16.57,EN,,0,0,0,,And what I have to be careful with now Dialogue: 0,1:04:16.88,1:04:18.99,EN,,0,0,0,,is I want to shuffle this right so I can do the multiply. Dialogue: 0,1:04:19.47,1:04:21.24,EN,,0,0,0,,Now there are various conventions I might use, Dialogue: 0,1:04:21.47,1:04:23.52,EN,,0,0,0,,but I'm going to be very picky and say, Dialogue: 0,1:04:23.55,1:04:25.88,EN,,0,0,0,,I'm only going to restore into a register I've saved from. Dialogue: 0,1:04:26.74,1:04:28.28,EN,,0,0,0,,If that's the case, I have to do a shuffle here. Dialogue: 0,1:04:29.24,1:04:31.84,EN,,0,0,0,,It's the same problem with how many hands I have. Dialogue: 0,1:04:32.68,1:04:37.13,EN,,0,0,0,,So I'm going to assign to N, Dialogue: 0,1:04:37.16,1:04:39.37,EN,,0,0,0,,because I'm not going to need N anymore, N is useless, Dialogue: 0,1:04:39.92,1:04:41.21,EN,,0,0,0,,the current value of VAL, Dialogue: 0,1:04:45.21,1:04:47.34,EN,,0,0,0,,which was the value of Fib of N minus 2. Dialogue: 0,1:04:52.95,1:04:56.35,EN,,0,0,0,,And I'm going to restore the value register now. Dialogue: 0,1:05:01.85,1:05:03.92,EN,,0,0,0,,This restore matches this save. Dialogue: 0,1:05:05.58,1:05:08.83,EN,,0,0,0,,And if you're very careful and examine very carefully what goes on, Dialogue: 0,1:05:09.21,1:05:11.96,EN,,0,0,0,,OK? restores and saves are always matched. Dialogue: 0,1:05:13.84,1:05:15.15,EN,,0,0,0,,Now there's an outstanding save, Dialogue: 0,1:05:15.18,1:05:16.38,EN,,0,0,0,,of course, that we have to get rid of soon. Dialogue: 0,1:05:19.00,1:05:20.59,EN,,0,0,0,,And so I restored the value register. Dialogue: 0,1:05:20.94,1:05:22.57,EN,,0,0,0,,Now I restore the continue one, Dialogue: 0,1:05:31.15,1:05:32.40,EN,,0,0,0,,which matches this one, Dialogue: 0,1:05:34.80,1:05:37.85,EN,,0,0,0,,dot, dot, dot, dot, dot, dot, dot, down to here, Dialogue: 0,1:05:40.59,1:05:42.46,EN,,0,0,0,,Now restoring that continuation. Dialogue: 0,1:05:42.86,1:05:45.71,EN,,0,0,0,,That continuation is a continuation of Fib of N, Dialogue: 0,1:05:46.46,1:05:47.84,EN,,0,0,0,,which is the problem I was trying to solve, Dialogue: 0,1:05:47.85,1:05:49.32,EN,,0,0,0,,a major problem I'm trying to solve. Dialogue: 0,1:05:49.98,1:05:52.35,EN,,0,0,0,,So that's the guy I have to go back to who wants Fib of N. Dialogue: 0,1:05:52.54,1:05:54.03,EN,,0,0,0,,I saved them all the way up here Dialogue: 0,1:05:54.16,1:05:56.60,EN,,0,0,0,,when I realized N was not less than 2. Dialogue: 0,1:05:57.36,1:05:59.07,EN,,0,0,0,,And so I had to do a complicated operation. Dialogue: 0,1:06:00.84,1:06:02.57,EN,,0,0,0,,Now I've got everything I need to do it. Dialogue: 0,1:06:03.24,1:06:04.36,EN,,0,0,0,,So I'm going to restore that, Dialogue: 0,1:06:05.42,1:06:21.08,EN,,0,0,0,,assign to VAL the sum of fetch VAL and fetch of N Dialogue: 0,1:06:27.44,1:06:28.60,EN,,0,0,0,,and go to continue. Dialogue: 0,1:06:38.26,1:06:44.78,EN,,0,0,0,,So now I've returned from computing Fibonacci of N, Dialogue: 0,1:06:45.39,1:06:46.57,EN,,0,0,0,,the general case. Dialogue: 0,1:06:47.11,1:06:50.60,EN,,0,0,0,,Now what's left is we have to fix up a few details, Dialogue: 0,1:06:50.99,1:06:55.53,EN,,0,0,0,,like there's the base case of this induction, immediate answer, Dialogue: 0,1:07:02.54,1:07:06.59,EN,,0,0,0,,as, which is nothing more than Dialogue: 0,1:07:06.60,1:07:11.85,EN,,0,0,0,,assign to VAL fetch of N, Dialogue: 0,1:07:13.64,1:07:15.47,EN,,0,0,0,,because N was less than 2, Dialogue: 0,1:07:15.50,1:07:16.89,EN,,0,0,0,,and therefore, the answer is N Dialogue: 0,1:07:16.99,1:07:18.19,EN,,0,0,0,,in our original program, Dialogue: 0,1:07:19.23,1:07:26.48,EN,,0,0,0,,and return continue-- Dialogue: 0,1:07:31.24,1:07:36.13,EN,,0,0,0,,bobble, bobble almost-- and finally Fib done. Dialogue: 0,1:07:43.46,1:07:45.64,EN,,0,0,0,,So that's a fairly complicated program. Dialogue: 0,1:07:45.64,1:07:47.34,EN,,0,0,0,,And the reason I wanted you see to that Dialogue: 0,1:07:47.50,1:07:49.21,EN,,0,0,0,,is because I want you to see the particular Dialogue: 0,1:07:49.45,1:07:52.67,EN,,0,0,0,,flavors of stack discipline that I was obeying. Dialogue: 0,1:07:53.32,1:07:55.21,EN,,0,0,0,,It was first of all, I don't want to save anything Dialogue: 0,1:07:56.92,1:07:58.12,EN,,0,0,0,,that I'm not going to need later. Dialogue: 0,1:08:00.57,1:08:01.85,EN,,0,0,0,,I was being very careful. Dialogue: 0,1:08:01.85,1:08:02.91,EN,,0,0,0,,And it's very important. Dialogue: 0,1:08:03.94,1:08:06.52,EN,,0,0,0,,And there are all sorts of other disciplines people make Dialogue: 0,1:08:07.37,1:08:09.61,EN,,0,0,0,,with frames and things like that of some sort, Dialogue: 0,1:08:10.19,1:08:11.39,EN,,0,0,0,,where you save all sorts of junk Dialogue: 0,1:08:11.40,1:08:12.64,EN,,0,0,0,,you're not going to need later and restore it Dialogue: 0,1:08:12.67,1:08:15.26,EN,,0,0,0,,because, in some sense, it's easier to do that. Dialogue: 0,1:08:15.83,1:08:17.40,EN,,0,0,0,,That's going to lead to various disasters, Dialogue: 0,1:08:18.59,1:08:20.25,EN,,0,0,0,,which we'll see a little later. Dialogue: 0,1:08:21.44,1:08:24.24,EN,,0,0,0,,It's crucial to save exactly what you're going to need later. Dialogue: 0,1:08:26.89,1:08:28.01,EN,,0,0,0,,It's an important idea. Dialogue: 0,1:08:29.87,1:08:33.36,EN,,0,0,0,,And the responsibility of that is whoever saves something Dialogue: 0,1:08:33.76,1:08:35.32,EN,,0,0,0,,is the guy who restores it, because he needs it. Dialogue: 0,1:08:36.93,1:08:38.54,EN,,0,0,0,,And in such discipline, Dialogue: 0,1:08:38.86,1:08:40.76,EN,,0,0,0,,you can see what things are unnecessary, Dialogue: 0,1:08:43.45,1:08:44.73,EN,,0,0,0,,operations that are unimportant. Dialogue: 0,1:08:47.15,1:08:50.40,EN,,0,0,0,,Now, one other thing I want to tell you about is very simple Dialogue: 0,1:08:51.66,1:08:54.67,EN,,0,0,0,,is that, of course, the picture you see is not the whole picture. Dialogue: 0,1:08:55.35,1:08:56.68,EN,,0,0,0,,Supposing I had systems Dialogue: 0,1:08:56.80,1:09:01.52,EN,,0,0,0,,had things like other operations, CAR, CDR, CONS, Dialogue: 0,1:09:03.53,1:09:05.60,EN,,0,0,0,,building a vector Dialogue: 0,1:09:05.88,1:09:07.32,EN,,0,0,0,,and referencing the nth element of it, Dialogue: 0,1:09:08.30,1:09:09.21,EN,,0,0,0,,or things like that. Dialogue: 0,1:09:10.40,1:09:13.60,EN,,0,0,0,,Well, at this level of detail, whatever it is, Dialogue: 0,1:09:13.87,1:09:17.85,EN,,0,0,0,,we can conceptualize those as primitive operations in the datapath. Dialogue: 0,1:09:18.75,1:09:21.95,EN,,0,0,0,,In other words, we could say that some machine that, for example, has Dialogue: 0,1:09:22.32,1:09:24.11,EN,,0,0,0,,has the append machine, Dialogue: 0,1:09:24.20,1:09:26.46,EN,,0,0,0,,which has to do cons of the CAR of x Dialogue: 0,1:09:26.64,1:09:29.80,EN,,0,0,0,,with the append of the CDR of x and y, Dialogue: 0,1:09:29.88,1:09:33.18,EN,,0,0,0,,well, gee, that's exactly the same as the factorial structure. Dialogue: 0,1:09:33.63,1:09:35.29,EN,,0,0,0,,Well, it's got about the same structure. Dialogue: 0,1:09:36.54,1:09:37.27,EN,,0,0,0,,And what do we have? Dialogue: 0,1:09:37.27,1:09:39.39,EN,,0,0,0,,We have some sort of things in it Dialogue: 0,1:09:39.76,1:09:42.48,EN,,0,0,0,,which may be registers, x and y, Dialogue: 0,1:09:42.51,1:09:45.12,EN,,0,0,0,,and then x has to somehow move to y sometimes, Dialogue: 0,1:09:45.28,1:09:46.75,EN,,0,0,0,,x has to get the value of y. Dialogue: 0,1:09:46.93,1:09:50.11,EN,,0,0,0,,And then we may have to be able to do something which is a cons. Dialogue: 0,1:09:51.70,1:09:57.74,EN,,0,0,0,,I don't remember if I need to like this is in this system, Dialogue: 0,1:09:57.76,1:10:01.10,EN,,0,0,0,,but cons is sort of like subtract or add or something. Dialogue: 0,1:10:01.42,1:10:02.70,EN,,0,0,0,,It combines two things, Dialogue: 0,1:10:02.73,1:10:04.27,EN,,0,0,0,,producing a thing which is the cons, Dialogue: 0,1:10:04.51,1:10:06.49,EN,,0,0,0,,which we may then think goes into there. Dialogue: 0,1:10:07.60,1:10:09.72,EN,,0,0,0,,And then maybe a thing called the CAR, Dialogue: 0,1:10:12.88,1:10:16.22,EN,,0,0,0,,which will produce-- I can get the CAR or something. Dialogue: 0,1:10:16.92,1:10:19.55,EN,,0,0,0,,And maybe I can get the CDR of something, and so on. Dialogue: 0,1:10:20.15,1:10:22.30,EN,,0,0,0,,But we shouldn't be too afraid of saying things this way, Dialogue: 0,1:10:22.92,1:10:24.24,EN,,0,0,0,,because the worst that could happen Dialogue: 0,1:10:24.94,1:10:26.41,EN,,0,0,0,,is if we open up cons, Dialogue: 0,1:10:27.31,1:10:29.82,EN,,0,0,0,,what we're going to find is some machine. Dialogue: 0,1:10:31.88,1:10:34.44,EN,,0,0,0,,And cons may in fact overlap with CAR and CDR, and it always does, Dialogue: 0,1:10:35.50,1:10:38.12,EN,,0,0,0,,in the same way that plus and minus overlap, Dialogue: 0,1:10:38.57,1:10:39.85,EN,,0,0,0,,and really the same business. Dialogue: 0,1:10:41.21,1:10:42.60,EN,,0,0,0,,CONS, CAR, and CDR are going to overlap, Dialogue: 0,1:10:42.62,1:10:44.52,EN,,0,0,0,,and we're going to find a little controller, Dialogue: 0,1:10:45.50,1:10:46.54,EN,,0,0,0,,a little datapath, Dialogue: 0,1:10:48.03,1:10:49.64,EN,,0,0,0,,which may have some registers in it, Dialogue: 0,1:10:50.00,1:10:52.86,EN,,0,0,0,,some stuff like that. Dialogue: 0,1:10:53.30,1:10:54.41,EN,,0,0,0,,And maybe inside it, Dialogue: 0,1:10:54.43,1:10:56.16,EN,,0,0,0,,there may also be an infinite part, Dialogue: 0,1:10:56.46,1:10:58.70,EN,,0,0,0,,a part that's semi-infinite or something, Dialogue: 0,1:10:58.81,1:11:00.65,EN,,0,0,0,,which is a lot of very uniform stuff, Dialogue: 0,1:11:00.96,1:11:02.03,EN,,0,0,0,,which we'll call memory. Dialogue: 0,1:11:06.57,1:11:08.83,EN,,0,0,0,,And I wouldn't be so horrified if that were the way it works. Dialogue: 0,1:11:09.33,1:11:11.07,EN,,0,0,0,,In fact, it does, and we'll talk about that later. Dialogue: 0,1:11:13.32,1:11:14.57,EN,,0,0,0,,So are there any questions? Dialogue: 0,1:11:24.34,1:11:25.80,EN,,0,0,0,,Gee, what an unquestioning audience. Dialogue: 0,1:11:28.67,1:11:30.33,EN,,0,0,0,,Suppose I tell you a horrible pile of lies. Dialogue: 0,1:11:39.69,1:11:40.38,EN,,0,0,0,,OK. Dialogue: 0,1:11:41.99,1:11:42.52,EN,,0,0,0,,Well, thank you. Dialogue: 0,1:11:42.52,1:11:43.28,EN,,0,0,0,,Let's take our break. ================================================ FILE: Ass/lec9b.chn+eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:16.30,0:00:18.08,EN,,0,0,0,,PROFESSOR: Well, I hope you appreciate that we have Dialogue: 0,0:00:20.01,0:00:22.73,EN,,0,0,0,,we have inducted you into some real magic, Dialogue: 0,0:00:24.20,0:00:27.24,EN,,0,0,0,,the magic of building languages Dialogue: 0,0:00:27.42,0:00:28.72,EN,,0,0,0,,really building new languages. Dialogue: 0,0:00:29.69,0:00:30.40,EN,,0,0,0,,What have we looked at? Dialogue: 0,0:00:30.43,0:00:32.78,EN,,0,0,0,,We've looked at an Escher picture language. Dialogue: 0,0:00:38.92,0:00:41.15,EN,,0,0,0,,OK? this language invented by Peter Henderson. Dialogue: 0,0:00:42.01,0:00:46.49,EN,,0,0,0,,We looked at digital logic language. Dialogue: 0,0:00:53.16,0:00:55.55,EN,,0,0,0,,Let's see.We've looked at the query language. Dialogue: 0,0:00:59.70,0:01:00.78,EN,,0,0,0,,And the thing you should realize is, Dialogue: 0,0:01:00.81,0:01:03.10,EN,,0,0,0,,even though these were toy examples, Dialogue: 0,0:01:04.70,0:01:07.61,EN,,0,0,0,,they really are the kernels of really useful things. Dialogue: 0,0:01:08.25,0:01:09.48,EN,,0,0,0,,So, for instance, Dialogue: 0,0:01:10.12,0:01:11.18,EN,,0,0,0,,the Escher picture language Dialogue: 0,0:01:11.20,0:01:14.33,EN,,0,0,0,,was taken byHenry Wu, who's a student at MIT, Dialogue: 0,0:01:14.88,0:01:16.43,EN,,0,0,0,,and developed into a real Dialogue: 0,0:01:16.97,0:01:19.45,EN,,0,0,0,,language for laying out PC boards, Dialogue: 0,0:01:20.35,0:01:22.56,EN,,0,0,0,,based just on extending those structures. Dialogue: 0,0:01:23.24,0:01:24.65,EN,,0,0,0,,And the digital logic language, Dialogue: 0,0:01:24.68,0:01:26.08,EN,,0,0,0,,Gerry mentioned when he showed it to you, Dialogue: 0,0:01:26.43,0:01:29.92,EN,,0,0,0,,was really extended to be used as the basis for a simulator Dialogue: 0,0:01:30.85,0:01:32.96,EN,,0,0,0,,that was used to design a real computer. Dialogue: 0,0:01:33.46,0:01:34.32,EN,,0,0,0,,And the query language, Dialogue: 0,0:01:34.35,0:01:36.44,EN,,0,0,0,,of course, is kind of the germ of prolog. Dialogue: 0,0:01:37.51,0:01:39.07,EN,,0,0,0,,So we built all of these languages, Dialogue: 0,0:01:39.55,0:01:40.65,EN,,0,0,0,,they're all based on LISP. Dialogue: 0,0:01:43.63,0:01:44.59,EN,,0,0,0,,A lot of people ask Dialogue: 0,0:01:45.27,0:01:48.73,EN,,0,0,0,,what particular problems is LISP good for solving for? Dialogue: 0,0:01:48.75,0:01:49.93,EN,,0,0,0,,The answer is LISP is not... Dialogue: 0,0:01:50.33,0:01:52.65,EN,,0,0,0,,LISP is not good for solving any particular problems. Dialogue: 0,0:01:53.53,0:01:54.60,EN,,0,0,0,,What LISP is good for Dialogue: 0,0:01:54.73,0:01:57.15,EN,,0,0,0,,is constructing within it the right language Dialogue: 0,0:01:57.18,0:01:58.57,EN,,0,0,0,,to solve the problems you want to solve, Dialogue: 0,0:01:59.17,0:02:00.44,EN,,0,0,0,,and that's how you should think about it. Dialogue: 0,0:02:01.47,0:02:03.39,EN,,0,0,0,,So all of these languages were based on LISP. Dialogue: 0,0:02:04.57,0:02:05.72,EN,,0,0,0,,Now, what's LISP based on? Dialogue: 0,0:02:06.97,0:02:07.88,EN,,0,0,0,,Where's that come from? Dialogue: 0,0:02:07.90,0:02:09.40,EN,,0,0,0,,Well, we looked at that too. Dialogue: 0,0:02:09.58,0:02:16.09,EN,,0,0,0,,We looked at the meta-circular evaluator Dialogue: 0,0:02:21.53,0:02:23.40,EN,,0,0,0,,the meta-circular evaluator and sort of said Dialogue: 0,0:02:23.42,0:02:25.76,EN,,0,0,0,,well, LISP is based on LISP. Dialogue: 0,0:02:25.80,0:02:27.48,EN,,0,0,0,,And when we start looking at that, Dialogue: 0,0:02:28.27,0:02:29.95,EN,,0,0,0,,we've got to do some real magic, right? Dialogue: 0,0:02:29.95,0:02:31.74,EN,,0,0,0,,So what does that mean, right? Dialogue: 0,0:02:31.74,0:02:34.96,EN,,0,0,0,,Y operators, and fixed points, Dialogue: 0,0:02:35.76,0:02:38.33,EN,,0,0,0,,and the idea that what this means is Dialogue: 0,0:02:38.36,0:02:41.44,EN,,0,0,0,,that LISP is somehow the fixed-point equation for the Dialogue: 0,0:02:42.20,0:02:45.42,EN,,0,0,0,,for this funny set of things which are defined in terms of themselves. Dialogue: 0,0:02:47.40,0:02:48.56,EN,,0,0,0,,Now, it's real magic. Dialogue: 0,0:02:49.07,0:02:52.35,EN,,0,0,0,,Well, today, for a final piece of magic, Dialogue: 0,0:02:52.62,0:02:54.03,EN,,0,0,0,,we're going to make all the magic go away. Dialogue: 0,0:03:06.80,0:03:07.98,EN,,0,0,0,,We already know how to do that. Dialogue: 0,0:03:09.77,0:03:10.76,EN,,0,0,0,,The idea is, we're going to take Dialogue: 0,0:03:11.13,0:03:12.73,EN,,0,0,0,,the register machine architecture Dialogue: 0,0:03:13.36,0:03:15.50,EN,,0,0,0,,and show how to implement LISP on terms of that. Dialogue: 0,0:03:15.50,0:03:17.93,EN,,0,0,0,,And, remember, the idea of the register machine Dialogue: 0,0:03:19.60,0:03:24.68,EN,,0,0,0,,is that there's a fixed and finite part of the machine. Dialogue: 0,0:03:24.72,0:03:26.12,EN,,0,0,0,,There's a finite-state controller, Dialogue: 0,0:03:26.12,0:03:27.87,EN,,0,0,0,,which dose particular thing Dialogue: 0,0:03:27.88,0:03:29.31,EN,,0,0,0,,with a particular amount of hardware. Dialogue: 0,0:03:30.51,0:03:31.74,EN,,0,0,0,,There are particular data paths, Dialogue: 0,0:03:31.76,0:03:33.24,EN,,0,0,0,,the operation the machine does Dialogue: 0,0:03:33.55,0:03:35.29,EN,,0,0,0,,And then, in order to implement recursion Dialogue: 0,0:03:35.53,0:03:37.60,EN,,0,0,0,,and sustain the illusion of infinity, Dialogue: 0,0:03:37.82,0:03:39.77,EN,,0,0,0,,there's some large amount of memory, which is the stack. Dialogue: 0,0:03:42.06,0:03:43.72,EN,,0,0,0,,So, if we implement LISP Dialogue: 0,0:03:43.92,0:03:45.50,EN,,0,0,0,,in terms of a register machine, Dialogue: 0,0:03:47.02,0:03:48.35,EN,,0,0,0,,then everything ought to become, Dialogue: 0,0:03:48.40,0:03:49.85,EN,,0,0,0,,at this point,completely concrete. Dialogue: 0,0:03:49.85,0:03:51.23,EN,,0,0,0,,All the magic should go away. Dialogue: 0,0:03:51.65,0:03:53.52,EN,,0,0,0,,And, by the end of this talk, Dialogue: 0,0:03:53.53,0:03:54.78,EN,,0,0,0,,I want you get the feeling Dialogue: 0,0:03:55.14,0:03:59.05,EN,,0,0,0,,that, as opposed to this very mysterious meta-circular evaluator Dialogue: 0,0:03:59.67,0:04:02.60,EN,,0,0,0,,that a LISP evaluator really is something that's concrete enough Dialogue: 0,0:04:02.85,0:04:04.57,EN,,0,0,0,,that you can hold in the palm of your hand. Dialogue: 0,0:04:04.76,0:04:06.24,EN,,0,0,0,,You should be able to imagine holding Dialogue: 0,0:04:06.57,0:04:07.90,EN,,0,0,0,,holding a LISP interpreter there. Dialogue: 0,0:04:09.63,0:04:10.94,EN,,0,0,0,,All right, how are we going to do this? Dialogue: 0,0:04:10.95,0:04:12.76,EN,,0,0,0,,We already have all the ingredients. Dialogue: 0,0:04:13.96,0:04:17.45,EN,,0,0,0,,See, what you learned last time from Gerry Dialogue: 0,0:04:17.60,0:04:21.47,EN,,0,0,0,,is how to take any particular couple of LISP procedures. Dialogue: 0,0:04:22.60,0:04:24.28,EN,,0,0,0,,and hand-translate them Dialogue: 0,0:04:24.75,0:04:26.67,EN,,0,0,0,,into something that runs on a register machine. Dialogue: 0,0:04:28.20,0:04:30.52,EN,,0,0,0,,So, to implement all of LISP on a register machine, Dialogue: 0,0:04:30.57,0:04:31.44,EN,,0,0,0,,all we have to do Dialogue: 0,0:04:31.69,0:04:33.45,EN,,0,0,0,,is take the particular procedures Dialogue: 0,0:04:33.68,0:04:35.42,EN,,0,0,0,,that are the meta-circular evaluator Dialogue: 0,0:04:36.17,0:04:38.11,EN,,0,0,0,,and hand-translate them for a register machine. Dialogue: 0,0:04:39.04,0:04:40.25,EN,,0,0,0,,And that does all of LISP Dialogue: 0,0:04:42.14,0:04:43.00,EN,,0,0,0,,Right? So, in principle, Dialogue: 0,0:04:43.02,0:04:44.43,EN,,0,0,0,,we already know how to do this. Dialogue: 0,0:04:45.38,0:04:46.54,EN,,0,0,0,,And, indeed, it's going to be no Dialogue: 0,0:04:46.68,0:04:48.86,EN,,0,0,0,,no different, in kind, Dialogue: 0,0:04:50.00,0:04:53.40,EN,,0,0,0,,from in say recursive factorial Dialogue: 0,0:04:53.42,0:04:54.67,EN,,0,0,0,,or recursive Fibonacci. Dialogue: 0,0:04:54.67,0:04:56.00,EN,,0,0,0,,It's just bigger and there's more of it. Dialogue: 0,0:04:56.84,0:04:58.03,EN,,0,0,0,,So it'd just be more details, Dialogue: 0,0:04:58.04,0:04:59.66,EN,,0,0,0,,but nothing really conceptually new. Dialogue: 0,0:05:01.48,0:05:03.02,EN,,0,0,0,,And also, when we've done that, Dialogue: 0,0:05:03.08,0:05:04.76,EN,,0,0,0,,and the thing is completely explicit, Dialogue: 0,0:05:04.87,0:05:06.91,EN,,0,0,0,,and we see how to implement LISP Dialogue: 0,0:05:06.94,0:05:10.08,EN,,0,0,0,,in terms of the actual sequential register operations, Dialogue: 0,0:05:10.16,0:05:11.63,EN,,0,0,0,,that's going to be our final Dialogue: 0,0:05:11.95,0:05:14.16,EN,,0,0,0,,most explicit model of LISP in this course. Dialogue: 0,0:05:14.81,0:05:16.95,EN,,0,0,0,,And, remember, that's a progression through this course. Dialogue: 0,0:05:16.95,0:05:18.25,EN,,0,0,0,,We started out with substitution, Dialogue: 0,0:05:18.28,0:05:19.58,EN,,0,0,0,,which is sort of like algebra. Dialogue: 0,0:05:20.24,0:05:21.87,EN,,0,0,0,,And then we went to the environment model, Dialogue: 0,0:05:21.88,0:05:24.00,EN,,0,0,0,,which talked about the actual frames Dialogue: 0,0:05:24.03,0:05:25.31,EN,,0,0,0,,and how they got linked together. Dialogue: 0,0:05:26.32,0:05:27.88,EN,,0,0,0,,And then we made that more concrete Dialogue: 0,0:05:27.90,0:05:29.36,EN,,0,0,0,,in the meta-circular evaluator. Dialogue: 0,0:05:31.05,0:05:31.64,EN,,0,0,0,,There are things Dialogue: 0,0:05:31.87,0:05:33.98,EN,,0,0,0,,the meta-circular evaluator doesn't tell us. Dialogue: 0,0:05:34.36,0:05:35.34,EN,,0,0,0,,You should realize that. Dialogue: 0,0:05:36.09,0:05:38.64,EN,,0,0,0,,For instance, it left unanswered the question Dialogue: 0,0:05:38.73,0:05:42.67,EN,,0,0,0,,of how a procedure, like recursive factorial here, Dialogue: 0,0:05:45.17,0:05:47.13,EN,,0,0,0,,somehow takes space that grows. Dialogue: 0,0:05:47.21,0:05:47.98,EN,,0,0,0,,On the other hand, Dialogue: 0,0:05:48.16,0:05:51.94,EN,,0,0,0,,a procedure which also looks syntactically recursive, Dialogue: 0,0:05:52.11,0:05:55.07,EN,,0,0,0,,called fact-iter, somehow doesn't take space. Dialogue: 0,0:05:55.10,0:05:59.16,EN,,0,0,0,,We justify that it doesn't need to take space Dialogue: 0,0:06:00.50,0:06:01.96,EN,,0,0,0,,by showing the substitution model. Dialogue: 0,0:06:01.96,0:06:02.94,EN,,0,0,0,,But we didn't really say Dialogue: 0,0:06:03.42,0:06:06.76,EN,,0,0,0,,how it happens that the machine manages to do that, Dialogue: 0,0:06:07.31,0:06:08.91,EN,,0,0,0,,that that has to do with the details Dialogue: 0,0:06:09.02,0:06:11.12,EN,,0,0,0,,of how arguments are passed to procedures Dialogue: 0,0:06:12.48,0:06:13.69,EN,,0,0,0,,And that's the thing we didn't see Dialogue: 0,0:06:13.71,0:06:15.34,EN,,0,0,0,,in the meta-circular evaluator Dialogue: 0,0:06:15.36,0:06:17.40,EN,,0,0,0,,precisely because the way arguments Dialogue: 0,0:06:17.42,0:06:19.20,EN,,0,0,0,,got passed to procedures in this LISP Dialogue: 0,0:06:19.70,0:06:20.59,EN,,0,0,0,,depended on Dialogue: 0,0:06:21.02,0:06:23.50,EN,,0,0,0,,the way arguments got passed to procedures in this LISP. Dialogue: 0,0:06:25.87,0:06:29.02,EN,,0,0,0,,But, now, that's going to become extremely explicit. Dialogue: 0,0:06:30.74,0:06:31.12,EN,,0,0,0,,OK. Dialogue: 0,0:06:31.23,0:06:34.30,EN,,0,0,0,,Well, before going on to the evaluator, Dialogue: 0,0:06:34.36,0:06:35.53,EN,,0,0,0,,let me just give you a sense of Dialogue: 0,0:06:35.55,0:06:37.00,EN,,0,0,0,,what a whole LISP system looks like Dialogue: 0,0:06:37.60,0:06:39.36,EN,,0,0,0,,so you can see the parts we're going to talk about Dialogue: 0,0:06:39.40,0:06:40.81,EN,,0,0,0,,and the parts we're not going to talk about. Dialogue: 0,0:06:43.18,0:06:47.42,EN,,0,0,0,,Let's see, over here is a happy LISP user, Dialogue: 0,0:06:48.67,0:06:52.65,EN,,0,0,0,,and the LISP user is talking to something called the reader. Dialogue: 0,0:07:00.36,0:07:01.53,EN,,0,0,0,,The reader's job in life Dialogue: 0,0:07:01.95,0:07:13.23,EN,,0,0,0,,is to take characters from the user Dialogue: 0,0:07:14.17,0:07:16.62,EN,,0,0,0,,and turn them into data structures Dialogue: 0,0:07:17.20,0:07:19.37,EN,,0,0,0,,in something called a list structure memory. Dialogue: 0,0:07:30.00,0:07:31.72,EN,,0,0,0,,All right, so the reader is going to take Dialogue: 0,0:07:32.65,0:07:33.95,EN,,0,0,0,,symbols, parentheses, Dialogue: 0,0:07:34.48,0:07:37.12,EN,,0,0,0,,and A's and B's, and 1s and 3s that you type in, Dialogue: 0,0:07:37.18,0:07:39.04,EN,,0,0,0,,and turn these into actual list structure: Dialogue: 0,0:07:39.15,0:07:40.54,EN,,0,0,0,,pairs, and pointers, and things. Dialogue: 0,0:07:42.35,0:07:43.92,EN,,0,0,0,,And so, by the time evaluator is going, Dialogue: 0,0:07:43.93,0:07:45.10,EN,,0,0,0,,there are no characters in the world. Dialogue: 0,0:07:45.85,0:07:48.16,EN,,0,0,0,,And, of course, in more modern Lisp systems, there's Dialogue: 0,0:07:49.00,0:07:50.44,EN,,0,0,0,,there's sort a big morass here Dialogue: 0,0:07:50.44,0:07:52.17,EN,,0,0,0,,that might sit between the user and the reader: Dialogue: 0,0:07:52.41,0:07:54.52,EN,,0,0,0,,you know, Windows systems, in top levels, Dialogue: 0,0:07:54.77,0:07:56.03,EN,,0,0,0,,and mice, and all kinds of things. Dialogue: 0,0:07:56.28,0:07:58.20,EN,,0,0,0,,But conceptually, characters are coming in. Dialogue: 0,0:07:59.93,0:08:04.32,EN,,0,0,0,,All right, the reader transforms these into pointers Dialogue: 0,0:08:05.56,0:08:07.28,EN,,0,0,0,,pointers to stuff in this memory, Dialogue: 0,0:08:08.27,0:08:10.94,EN,,0,0,0,,and that's what the evaluator sees Dialogue: 0,0:08:15.55,0:08:16.04,EN,,0,0,0,,OK? Dialogue: 0,0:08:17.02,0:08:18.88,EN,,0,0,0,,The evaluator has a bunch of helpers. Dialogue: 0,0:08:19.78,0:08:23.16,EN,,0,0,0,,It has all possible primitive operators you might want. Dialogue: 0,0:08:23.16,0:08:24.91,EN,,0,0,0,,So there's a completely separate box, Dialogue: 0,0:08:28.40,0:08:30.25,EN,,0,0,0,,a floating point unit, Dialogue: 0,0:08:32.22,0:08:34.40,EN,,0,0,0,,or all sorts of things, which do the primitive operators. Dialogue: 0,0:08:35.39,0:08:37.68,EN,,0,0,0,,there's and, if you want more special primitives, Dialogue: 0,0:08:37.71,0:08:39.02,EN,,0,0,0,,you build more primitive operators, Dialogue: 0,0:08:39.05,0:08:40.48,EN,,0,0,0,,but they're separate from the evaluator. Dialogue: 0,0:08:42.08,0:08:43.77,EN,,0,0,0,,The evaluator finally gets an answer Dialogue: 0,0:08:45.16,0:08:46.76,EN,,0,0,0,,and communicates that to the printer. Dialogue: 0,0:08:50.62,0:08:52.01,EN,,0,0,0,,And now, the printer's job in life Dialogue: 0,0:08:52.01,0:08:54.54,EN,,0,0,0,,is this list structure coming from the evaluator, Dialogue: 0,0:08:55.39,0:08:56.99,EN,,0,0,0,,and turn it back into characters, Dialogue: 0,0:09:01.85,0:09:04.07,EN,,0,0,0,,and communicate them to the user through Dialogue: 0,0:09:04.28,0:09:05.66,EN,,0,0,0,,whatever interface there is. Dialogue: 0,0:09:08.05,0:09:11.23,EN,,0,0,0,,OK. Well, today, what we're going to talk about is this evaluator. Dialogue: 0,0:09:12.67,0:09:15.20,EN,,0,0,0,,The primitive operators have nothing particular to do with LISP, Dialogue: 0,0:09:15.20,0:09:18.14,EN,,0,0,0,,they're however you like to implement primitive operations. Dialogue: 0,0:09:19.36,0:09:22.18,EN,,0,0,0,,The reader and printer are actually complicated, Dialogue: 0,0:09:22.18,0:09:23.55,EN,,0,0,0,,but we're not going to talk about them. Dialogue: 0,0:09:24.68,0:09:27.10,EN,,0,0,0,,They sort of have to do with details of how you might build Dialogue: 0,0:09:27.10,0:09:28.92,EN,,0,0,0,,build up list structure from characters. Dialogue: 0,0:09:29.90,0:09:31.18,EN,,0,0,0,,So that is a long story, Dialogue: 0,0:09:31.18,0:09:32.32,EN,,0,0,0,,but we're not going to talk about it, Dialogue: 0,0:09:32.49,0:09:33.69,EN,,0,0,0,,the list structure memory, Dialogue: 0,0:09:34.36,0:09:35.63,EN,,0,0,0,,we'll talk about next time. Dialogue: 0,0:09:36.93,0:09:39.72,EN,,0,0,0,,So, pretty much, except for the details of reading and printing, Dialogue: 0,0:09:40.12,0:09:41.71,EN,,0,0,0,,the only mystery that's going to be left Dialogue: 0,0:09:41.72,0:09:43.05,EN,,0,0,0,,after you see the evaluator Dialogue: 0,0:09:43.25,0:09:45.85,EN,,0,0,0,,is how you build list structure on conventional memories. Dialogue: 0,0:09:46.65,0:09:48.20,EN,,0,0,0,,But we'll worry about that next time too. Dialogue: 0,0:09:50.58,0:09:51.04,EN,,0,0,0,,OK. Dialogue: 0,0:09:53.34,0:09:56.11,EN,,0,0,0,,Well, let's start talking about the evaluator. Dialogue: 0,0:09:56.20,0:09:58.32,EN,,0,0,0,,The one that we're going to show you, Dialogue: 0,0:09:58.49,0:10:01.12,EN,,0,0,0,,of course, is not, I think, nothing special about it. Dialogue: 0,0:10:01.15,0:10:04.56,EN,,0,0,0,,It's just a particular register machine that runs LISP. Dialogue: 0,0:10:04.81,0:10:06.09,EN,,0,0,0,,And it has seven registers, Dialogue: 0,0:10:07.88,0:10:09.26,EN,,0,0,0,,and here are the seven registers. Dialogue: 0,0:10:09.89,0:10:12.38,EN,,0,0,0,,There's a register, called EXP Dialogue: 0,0:10:14.12,0:10:15.53,EN,,0,0,0,,and its job is to hold Dialogue: 0,0:10:16.36,0:10:18.03,EN,,0,0,0,,the expression to be evaluated. Dialogue: 0,0:10:18.37,0:10:19.80,EN,,0,0,0,,And by that, I mean Dialogue: 0,0:10:20.38,0:10:21.64,EN,,0,0,0,,it's going to hold a pointer Dialogue: 0,0:10:22.03,0:10:23.55,EN,,0,0,0,,to someplace in list structure memory Dialogue: 0,0:10:23.56,0:10:25.32,EN,,0,0,0,,the expression to be evaluated. Dialogue: 0,0:10:26.55,0:10:27.82,EN,,0,0,0,,There's a register, called ENV, Dialogue: 0,0:10:28.88,0:10:30.28,EN,,0,0,0,,which holds the environment Dialogue: 0,0:10:31.00,0:10:33.05,EN,,0,0,0,,in which this expression is to be evaluated. Dialogue: 0,0:10:34.07,0:10:35.02,EN,,0,0,0,,And, again, I made a pointer. Dialogue: 0,0:10:35.02,0:10:36.75,EN,,0,0,0,,The environment is some data structure. Dialogue: 0,0:10:38.24,0:10:40.14,EN,,0,0,0,,There's a register, called FUN, which will Dialogue: 0,0:10:40.75,0:10:42.54,EN,,0,0,0,,which will hold the procedure to be applied Dialogue: 0,0:10:42.57,0:10:43.96,EN,,0,0,0,,when you go to apply a procedure. Dialogue: 0,0:10:44.56,0:10:46.24,EN,,0,0,0,,A register, called ARGL, Dialogue: 0,0:10:47.36,0:10:49.34,EN,,0,0,0,,which holds the list of evaluated arguments. Dialogue: 0,0:10:50.54,0:10:51.60,EN,,0,0,0,,What you can start seeing here is Dialogue: 0,0:10:51.63,0:10:53.14,EN,,0,0,0,,the basic structure of the evaluator. Dialogue: 0,0:10:53.14,0:10:54.49,EN,,0,0,0,,Remember how evaluators work. Dialogue: 0,0:10:54.49,0:10:56.62,EN,,0,0,0,,There's a piece that takes expressions and environments, Dialogue: 0,0:10:57.67,0:10:59.71,EN,,0,0,0,,and there's a piece that takes functions Dialogue: 0,0:10:59.74,0:11:02.14,EN,,0,0,0,,or procedures and arguments. Dialogue: 0,0:11:03.48,0:11:06.30,EN,,0,0,0,,And going back and forth around here is the eval/apply loop. Dialogue: 0,0:11:07.40,0:11:09.69,EN,,0,0,0,,So those are the basic pieces of the eval and apply. Dialogue: 0,0:11:10.20,0:11:10.99,EN,,0,0,0,,Then there's some other things, Dialogue: 0,0:11:11.00,0:11:11.61,EN,,0,0,0,,there's continue. Dialogue: 0,0:11:11.61,0:11:15.34,EN,,0,0,0,,You just saw before how the continue register is used to Dialogue: 0,0:11:15.34,0:11:18.04,EN,,0,0,0,,implement recursion and stack discipline. Dialogue: 0,0:11:18.94,0:11:20.68,EN,,0,0,0,,There's a register that's going to hold the Dialogue: 0,0:11:20.94,0:11:22.52,EN,,0,0,0,,result of some evaluation. Dialogue: 0,0:11:24.14,0:11:24.89,EN,,0,0,0,,And then, besides that, Dialogue: 0,0:11:24.89,0:11:26.43,EN,,0,0,0,,there's one temporary register, Dialogue: 0,0:11:26.70,0:11:27.29,EN,,0,0,0,,called UNEV, Dialogue: 0,0:11:27.29,0:11:29.04,EN,,0,0,0,,which typically, in the evaluator, Dialogue: 0,0:11:29.28,0:11:32.72,EN,,0,0,0,,is going to be used to hold temporary pieces of the Dialogue: 0,0:11:32.89,0:11:33.95,EN,,0,0,0,,expression you're working on, Dialogue: 0,0:11:33.95,0:11:35.72,EN,,0,0,0,,which you haven't gotten around to evaluate yet Dialogue: 0,0:11:36.97,0:11:39.82,EN,,0,0,0,,Right? So there's my machine: a seven-register machine. Dialogue: 0,0:11:40.96,0:11:42.98,EN,,0,0,0,,And, of course, you might want to make a machine with Dialogue: 0,0:11:42.98,0:11:44.96,EN,,0,0,0,,a lot more registers to get better performance, Dialogue: 0,0:11:44.97,0:11:47.05,EN,,0,0,0,,but this is just a tiny, minimal one. Dialogue: 0,0:11:48.48,0:11:49.58,EN,,0,0,0,,Well, how about the data paths? Dialogue: 0,0:11:49.78,0:11:53.66,EN,,0,0,0,,This machine has a lot of special operations for LISP. Dialogue: 0,0:11:55.10,0:11:58.08,EN,,0,0,0,,So, here are some typical data paths. Dialogue: 0,0:12:00.12,0:12:01.04,EN,,0,0,0,,A typical one might be, Dialogue: 0,0:12:01.37,0:12:03.40,EN,,0,0,0,,oh, assign to the VAL register Dialogue: 0,0:12:03.40,0:12:04.80,EN,,0,0,0,,the contents of the EXP register. Dialogue: 0,0:12:05.71,0:12:08.01,EN,,0,0,0,,That's in terms of those diagrams you saw, Dialogue: 0,0:12:08.03,0:12:10.81,EN,,0,0,0,,that's a little button on some arrow. Dialogue: 0,0:12:11.90,0:12:13.13,EN,,0,0,0,,Here's a more complicated one. Dialogue: 0,0:12:13.69,0:12:14.80,EN,,0,0,0,,It says branch, Dialogue: 0,0:12:15.23,0:12:19.58,EN,,0,0,0,,if the thing in the expression register is a conditional Dialogue: 0,0:12:20.49,0:12:22.72,EN,,0,0,0,,to some label here, called the ev-conditional. Dialogue: 0,0:12:23.80,0:12:26.23,EN,,0,0,0,,And you can imagine this implemented in a lot of different ways. Dialogue: 0,0:12:26.23,0:12:28.36,EN,,0,0,0,,You might imagine this conditional test Dialogue: 0,0:12:28.36,0:12:29.98,EN,,0,0,0,,as a special purpose sub-routine, Dialogue: 0,0:12:30.60,0:12:33.95,EN,,0,0,0,,and conditional might be represented as some data abstraction Dialogue: 0,0:12:33.96,0:12:36.00,EN,,0,0,0,,that you don't care about at this level of detail. Dialogue: 0,0:12:36.61,0:12:37.98,EN,,0,0,0,,So that might be done as a sub-routine. Dialogue: 0,0:12:37.98,0:12:40.67,EN,,0,0,0,,This might be a machine with hardware-types, Dialogue: 0,0:12:40.90,0:12:44.04,EN,,0,0,0,,and conditional might be testing some bits for a particular code. Dialogue: 0,0:12:45.35,0:12:46.41,EN,,0,0,0,,There are all sorts of ways that's Dialogue: 0,0:12:46.41,0:12:48.48,EN,,0,0,0,,beneath the level of abstraction we're looking at. Dialogue: 0,0:12:50.19,0:12:51.71,EN,,0,0,0,,Another kind of operation, Dialogue: 0,0:12:51.71,0:12:53.24,EN,,0,0,0,,and there are a lot of different operations Dialogue: 0,0:12:53.24,0:12:56.65,EN,,0,0,0,,assigned to EXP, the first clause of what's in EXP. Dialogue: 0,0:12:56.84,0:12:58.89,EN,,0,0,0,,This might be part of processing a conditional. Dialogue: 0,0:12:59.26,0:13:01.80,EN,,0,0,0,,And, again, first clause is some selector Dialogue: 0,0:13:03.07,0:13:04.48,EN,,0,0,0,,whose details we don't care about. Dialogue: 0,0:13:04.49,0:13:06.46,EN,,0,0,0,,And you can, again, imagine that as a sub-routine Dialogue: 0,0:13:06.46,0:13:07.90,EN,,0,0,0,,which'll do some list operations, Dialogue: 0,0:13:08.22,0:13:09.18,EN,,0,0,0,,or you can imagine that as Dialogue: 0,0:13:09.18,0:13:10.73,EN,,0,0,0,,something that's built directly into hardware. Dialogue: 0,0:13:12.17,0:13:13.71,EN,,0,0,0,,The reason I keep saying you can imagine it Dialogue: 0,0:13:14.03,0:13:15.22,EN,,0,0,0,,built directly into hardware Dialogue: 0,0:13:15.22,0:13:17.80,EN,,0,0,0,,is even though there are a lot of operations, Dialogue: 0,0:13:18.36,0:13:19.74,EN,,0,0,0,,there are still a fixed number of them. Dialogue: 0,0:13:20.12,0:13:21.80,EN,,0,0,0,,I forget how many, maybe 150. Dialogue: 0,0:13:22.37,0:13:25.39,EN,,0,0,0,,So, it's plausible to think of building these directly into hardware. Dialogue: 0,0:13:26.41,0:13:27.68,EN,,0,0,0,,Here's a more complicated one. Dialogue: 0,0:13:28.27,0:13:29.47,EN,,0,0,0,,You can see this has to do with Dialogue: 0,0:13:29.47,0:13:31.10,EN,,0,0,0,,looking up the values of variables. Dialogue: 0,0:13:31.50,0:13:33.28,EN,,0,0,0,,It says assign to the VAL register Dialogue: 0,0:13:33.45,0:13:36.91,EN,,0,0,0,,the result of looking up the variable value Dialogue: 0,0:13:36.99,0:13:38.52,EN,,0,0,0,,of some particular expression, Dialogue: 0,0:13:39.18,0:13:40.30,EN,,0,0,0,,which, in this case, is supposed to be Dialogue: 0,0:13:40.33,0:13:42.00,EN,,0,0,0,,a variable in some environment. Dialogue: 0,0:13:42.80,0:13:44.68,EN,,0,0,0,,And this'll be some operation Dialogue: 0,0:13:45.21,0:13:47.50,EN,,0,0,0,,that search through the environment structure, Dialogue: 0,0:13:47.52,0:13:48.97,EN,,0,0,0,,however it is represented, Dialogue: 0,0:13:49.37,0:13:50.91,EN,,0,0,0,,and goes and looks up that variable. Dialogue: 0,0:13:52.17,0:13:53.95,EN,,0,0,0,,And, again, that's below the level of detail Dialogue: 0,0:13:53.96,0:13:54.86,EN,,0,0,0,,that we're thinking about. Dialogue: 0,0:13:54.89,0:13:57.30,EN,,0,0,0,,This is... this has to do with the details of Dialogue: 0,0:13:57.55,0:13:59.44,EN,,0,0,0,,the data structures for representing environments. Dialogue: 0,0:14:00.07,0:14:01.21,EN,,0,0,0,,But, anyway, there is this Dialogue: 0,0:14:01.31,0:14:03.47,EN,,0,0,0,,there is this fixed and finite number Dialogue: 0,0:14:04.11,0:14:06.08,EN,,0,0,0,,of operations in the register machine. Dialogue: 0,0:14:08.50,0:14:11.60,EN,,0,0,0,,Well, what's its overall structure? Dialogue: 0,0:14:11.72,0:14:13.23,EN,,0,0,0,,Those are some typical operations. Dialogue: 0,0:14:14.76,0:14:16.33,EN,,0,0,0,,Remember what we have to do, Dialogue: 0,0:14:16.44,0:14:18.40,EN,,0,0,0,,we have to take the meta-circular evaluator-- Dialogue: 0,0:14:20.43,0:14:22.76,EN,,0,0,0,,and here's a piece of the meta-circular evaluator. Dialogue: 0,0:14:22.76,0:14:26.89,EN,,0,0,0,,This is the one using abstract syntax that's in the book. Dialogue: 0,0:14:28.22,0:14:31.53,EN,,0,0,0,,It's a little bit different from the one that Gerry shows you. Dialogue: 0,0:14:33.50,0:14:35.10,EN,,0,0,0,,And the main thing Dialogue: 0,0:14:35.13,0:14:37.87,EN,,0,0,0,,to remember about the evaluator is that Dialogue: 0,0:14:37.87,0:14:40.96,EN,,0,0,0,,it's doing some sort of case analysis on the kinds of expressions: Dialogue: 0,0:14:43.76,0:14:45.90,EN,,0,0,0,,so if it's either self-evaluated, or quoted, Dialogue: 0,0:14:45.92,0:14:46.86,EN,,0,0,0,,or whatever else. Dialogue: 0,0:14:48.56,0:14:50.57,EN,,0,0,0,,And then, in the general case where Dialogue: 0,0:14:50.86,0:14:52.96,EN,,0,0,0,,the expression it's looking at is an application, Dialogue: 0,0:14:53.55,0:14:55.36,EN,,0,0,0,,there's some tricky recursions going on. Dialogue: 0,0:14:55.75,0:14:59.36,EN,,0,0,0,,First of all, eval has to call itself Dialogue: 0,0:14:59.79,0:15:01.45,EN,,0,0,0,,both to evaluate the operator Dialogue: 0,0:15:02.14,0:15:04.04,EN,,0,0,0,,and to evaluate all the operands. Dialogue: 0,0:15:05.88,0:15:07.40,EN,,0,0,0,,So there's this sort of red recursion Dialogue: 0,0:15:07.63,0:15:09.28,EN,,0,0,0,,of values walking down the tree Dialogue: 0,0:15:10.94,0:15:12.27,EN,,0,0,0,,that's sort of the easy recursion. Dialogue: 0,0:15:12.27,0:15:14.44,EN,,0,0,0,,That's just eval walking down this tree of expressions. Dialogue: 0,0:15:14.75,0:15:15.53,EN,,0,0,0,,Then, in the evaluator, Dialogue: 0,0:15:15.53,0:15:16.46,EN,,0,0,0,,there's a hard recursion. Dialogue: 0,0:15:16.49,0:15:17.92,EN,,0,0,0,,There's the red to green. Dialogue: 0,0:15:18.00,0:15:19.66,EN,,0,0,0,,Eval calls apply. Dialogue: 0,0:15:22.47,0:15:26.45,EN,,0,0,0,,That's the case where evaluating a procedure argument Dialogue: 0,0:15:26.45,0:15:28.72,EN,,0,0,0,,reduces to applying the procedure Dialogue: 0,0:15:28.94,0:15:29.93,EN,,0,0,0,,to the list of arguments. Dialogue: 0,0:15:30.37,0:15:31.76,EN,,0,0,0,,And then, apply comes over here. Dialogue: 0,0:15:34.77,0:15:36.67,EN,,0,0,0,,Apply takes a procedure and arguments Dialogue: 0,0:15:37.65,0:15:39.45,EN,,0,0,0,,and, in the general case Dialogue: 0,0:15:39.48,0:15:40.81,EN,,0,0,0,,where there's a compound procedure, Dialogue: 0,0:15:41.05,0:15:42.19,EN,,0,0,0,,apply goes around and Dialogue: 0,0:15:42.25,0:15:43.15,EN,,0,0,0,,green calls red. Dialogue: 0,0:15:43.34,0:15:46.44,EN,,0,0,0,,Eval-- Apply comes around and calls eval again. Dialogue: 0,0:15:48.17,0:15:49.79,EN,,0,0,0,,Eval's the body of the procedure Dialogue: 0,0:15:50.24,0:15:52.59,EN,,0,0,0,,in the result of extending the environment Dialogue: 0,0:15:53.69,0:15:55.28,EN,,0,0,0,,with the parameters of the procedure Dialogue: 0,0:15:55.48,0:15:56.92,EN,,0,0,0,,by binding the arguments. Dialogue: 0,0:15:59.62,0:16:00.62,EN,,0,0,0,,Except in the primitive case, Dialogue: 0,0:16:00.64,0:16:02.52,EN,,0,0,0,,where it just calls something else primitive-apply Dialogue: 0,0:16:02.73,0:16:04.70,EN,,0,0,0,,which is not really the business of the evaluator. Dialogue: 0,0:16:05.98,0:16:07.47,EN,,0,0,0,,So this sort of red to green, Dialogue: 0,0:16:07.47,0:16:08.40,EN,,0,0,0,,to red to green, Dialogue: 0,0:16:09.79,0:16:12.72,EN,,0,0,0,,Right? That's the that's the eval/apply loop, Dialogue: 0,0:16:14.06,0:16:15.74,EN,,0,0,0,,and that's the thing that we're going to want to see Dialogue: 0,0:16:16.19,0:16:17.72,EN,,0,0,0,,in the evaluator. Dialogue: 0,0:16:19.69,0:16:21.07,EN,,0,0,0,,Well, it won't surprise you at all that Dialogue: 0,0:16:21.07,0:16:23.52,EN,,0,0,0,,the two big pieces of this evaluator Dialogue: 0,0:16:25.34,0:16:27.04,EN,,0,0,0,,are correspond to eval and apply. Dialogue: 0,0:16:27.47,0:16:29.44,EN,,0,0,0,,There's a piece called eval-dispatch, Dialogue: 0,0:16:29.60,0:16:31.20,EN,,0,0,0,,and a piece called apply-dispatch. Dialogue: 0,0:16:32.00,0:16:34.09,EN,,0,0,0,,And, before we get into the details of the code, Dialogue: 0,0:16:34.20,0:16:35.76,EN,,0,0,0,,the way to understand this is to think, Dialogue: 0,0:16:36.09,0:16:39.02,EN,,0,0,0,,again, in terms of these pieces of evaluator Dialogue: 0,0:16:39.02,0:16:40.97,EN,,0,0,0,,having contracts with the rest of the world. Dialogue: 0,0:16:41.87,0:16:43.18,EN,,0,0,0,,What do they do from the outside Dialogue: 0,0:16:43.20,0:16:45.50,EN,,0,0,0,,before getting into the grungy details? Dialogue: 0,0:16:45.78,0:16:49.32,EN,,0,0,0,,Well, the contract for eval-dispatch-- Dialogue: 0,0:16:50.01,0:16:51.40,EN,,0,0,0,,remember, it corresponds to eval. Dialogue: 0,0:16:51.55,0:16:54.10,EN,,0,0,0,,It's got to evaluate an expression in an environment. Dialogue: 0,0:16:54.10,0:16:55.88,EN,,0,0,0,,So, in particular, what this one is going to do, Dialogue: 0,0:16:56.52,0:16:58.68,EN,,0,0,0,,eval-dispatch will assume that, when you call it, Dialogue: 0,0:16:59.68,0:17:01.48,EN,,0,0,0,,that the expression you want to evaluate Dialogue: 0,0:17:01.48,0:17:02.52,EN,,0,0,0,,is in the EXP register. Dialogue: 0,0:17:03.64,0:17:07.39,EN,,0,0,0,,The environment in which you want the evaluation Dialogue: 0,0:17:07.45,0:17:09.05,EN,,0,0,0,,to take place is in the ENV register. Dialogue: 0,0:17:09.56,0:17:10.67,EN,,0,0,0,,And continue tells you Dialogue: 0,0:17:10.84,0:17:12.46,EN,,0,0,0,,the place where the machine should go next Dialogue: 0,0:17:12.52,0:17:13.92,EN,,0,0,0,,when the evaluation is done. Dialogue: 0,0:17:17.28,0:17:19.18,EN,,0,0,0,,Eval-dispatch's contract is that Dialogue: 0,0:17:19.28,0:17:21.26,EN,,0,0,0,,it'll actually perform that evaluation, Dialogue: 0,0:17:21.40,0:17:22.46,EN,,0,0,0,,and, at the end of which, Dialogue: 0,0:17:23.28,0:17:25.63,EN,,0,0,0,,it'll end up at the place specified by continue. Dialogue: 0,0:17:26.61,0:17:29.16,EN,,0,0,0,,The result of the evaluation will be in the VAL register. Dialogue: 0,0:17:29.82,0:17:30.96,EN,,0,0,0,,And it just warns you, Dialogue: 0,0:17:30.99,0:17:32.91,EN,,0,0,0,,it makes no promises about Dialogue: 0,0:17:32.96,0:17:34.60,EN,,0,0,0,,what happens to rest the registers. Dialogue: 0,0:17:35.23,0:17:36.81,EN,,0,0,0,,All other registers might be destroyed. Dialogue: 0,0:17:37.49,0:17:40.14,EN,,0,0,0,,So, there's one piece, OK? Dialogue: 0,0:17:41.55,0:17:43.48,EN,,0,0,0,,Together, the pieces, apply-dispatch Dialogue: 0,0:17:43.52,0:17:44.92,EN,,0,0,0,,that corresponds to apply, Dialogue: 0,0:17:46.09,0:17:48.43,EN,,0,0,0,,it's got to apply a procedure to some arguments, Dialogue: 0,0:17:48.73,0:17:51.43,EN,,0,0,0,,so it assumes that this register, ARGL, Dialogue: 0,0:17:51.68,0:17:53.77,EN,,0,0,0,,contains a list of the evaluated arguments. Dialogue: 0,0:17:54.54,0:17:55.96,EN,,0,0,0,,FUN contains the procedure. Dialogue: 0,0:17:57.22,0:17:58.83,EN,,0,0,0,,Those correspond to the arguments to Dialogue: 0,0:17:58.94,0:18:01.36,EN,,0,0,0,,the apply procedure in the meta-circular evaluator. Dialogue: 0,0:18:03.97,0:18:06.04,EN,,0,0,0,,And apply, in this particular evaluator, Dialogue: 0,0:18:06.06,0:18:07.58,EN,,0,0,0,,we're going to use a discipline which says Dialogue: 0,0:18:07.72,0:18:08.97,EN,,0,0,0,,the place that apply Dialogue: 0,0:18:09.47,0:18:11.20,EN,,0,0,0,,the place the machine should go to next Dialogue: 0,0:18:11.79,0:18:13.45,EN,,0,0,0,,when apply is done, is at the moment Dialogue: 0,0:18:13.55,0:18:15.92,EN,,0,0,0,,apply-dispatch is called at the top of the stack Dialogue: 0,0:18:17.07,0:18:21.24,EN,,0,0,0,,that's just discipline for the way this particular machine's organized. Dialogue: 0,0:18:21.84,0:18:23.70,EN,,0,0,0,,And now apply's contract is given all that. Dialogue: 0,0:18:23.93,0:18:25.37,EN,,0,0,0,,It'll perform the application. Dialogue: 0,0:18:25.54,0:18:27.85,EN,,0,0,0,,The result of that application will end up in VAL. Dialogue: 0,0:18:28.89,0:18:29.95,EN,,0,0,0,,The stack will be popped. Dialogue: 0,0:18:31.12,0:18:31.66,EN,,0,0,0,,And, again, Dialogue: 0,0:18:31.71,0:18:34.03,EN,,0,0,0,,the contents of all the other registers may be destroyed. Dialogue: 0,0:18:34.84,0:18:37.82,EN,,0,0,0,,All right? So that's the basic organization of this machine. Dialogue: 0,0:18:38.99,0:18:41.50,EN,,0,0,0,,Let's break for a little bit and see if there are any questions Dialogue: 0,0:18:41.52,0:18:42.70,EN,,0,0,0,,and then we'll do a real example. Dialogue: 0,0:18:43.53,0:19:08.11,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:19:08.14,0:19:13.47,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:19:33.10,0:19:35.87,EN,,0,0,0,,By: Prof. Harold Abelson && Sussman Jay Sussman Dialogue: 0,0:19:35.87,0:19:40.38,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:19:47.85,0:19:49.95,EN,,0,0,0,,Well, let's take the register machine now, Dialogue: 0,0:19:50.41,0:19:51.77,EN,,0,0,0,,and actually step through, Dialogue: 0,0:19:52.27,0:19:56.94,EN,,0,0,0,,and really, in real detail, Dialogue: 0,0:19:57.07,0:19:58.52,EN,,0,0,0,,so you see completely concrete Dialogue: 0,0:19:58.86,0:20:01.24,EN,,0,0,0,,how some expressions are evaluated, Dialogue: 0,0:20:03.15,0:20:06.86,EN,,0,0,0,,Alright? So, let's start with a very simple expression. Dialogue: 0,0:20:07.45,0:20:13.52,EN,,0,0,0,,Let's evaluate the expression 1. Dialogue: 0,0:20:18.77,0:20:20.40,EN,,0,0,0,,And we need an environment, Dialogue: 0,0:20:20.43,0:20:22.35,EN,,0,0,0,,so let's imagine that somewhere there's an environment Dialogue: 0,0:20:22.38,0:20:23.39,EN,,0,0,0,,we'll call it E0. Dialogue: 0,0:20:30.06,0:20:34.56,EN,,0,0,0,,And just, since we'll use these later, Dialogue: 0,0:20:35.62,0:20:37.04,EN,,0,0,0,,we obviously don't really need anything Dialogue: 0,0:20:37.07,0:20:37.93,EN,,0,0,0,,to evaluate 1. Dialogue: 0,0:20:38.36,0:20:39.45,EN,,0,0,0,,But, just for reference later, Dialogue: 0,0:20:39.45,0:20:40.94,EN,,0,0,0,,let's assume that E0 has in it Dialogue: 0,0:20:41.44,0:20:43.15,EN,,0,0,0,,an X that's bound to 3 Dialogue: 0,0:20:43.72,0:20:45.37,EN,,0,0,0,,and a Y that's bound to 4, Dialogue: 0,0:20:48.27,0:20:48.78,EN,,0,0,0,,OK? Dialogue: 0,0:20:49.14,0:20:50.12,EN,,0,0,0,,And now what we're going to do Dialogue: 0,0:20:50.51,0:20:54.59,EN,,0,0,0,,is we're going to evaluate 1 in this environment Dialogue: 0,0:20:55.74,0:20:58.54,EN,,0,0,0,,and so the ENV register has a pointer Dialogue: 0,0:20:59.65,0:21:01.04,EN,,0,0,0,,to this environment, E0, all right? Dialogue: 0,0:21:03.31,0:21:05.65,EN,,0,0,0,,Right? So let's watch that thing go. Dialogue: 0,0:21:05.65,0:21:07.26,EN,,0,0,0,,What I'm going to do is step through the code. Dialogue: 0,0:21:08.26,0:21:10.00,EN,,0,0,0,,And, let's see, I'll be the controller. Dialogue: 0,0:21:10.04,0:21:10.80,EN,,0,0,0,,And now what I need, Dialogue: 0,0:21:11.02,0:21:12.49,EN,,0,0,0,,since this gets rather complicated, Dialogue: 0,0:21:12.98,0:21:16.83,EN,,0,0,0,,is a very little execution unit. Dialogue: 0,0:21:16.83,0:21:18.16,EN,,0,0,0,,So here's the execution unit, OK? Dialogue: 0,0:21:22.62,0:21:23.12,EN,,0,0,0,,OK. Dialogue: 0,0:21:28.59,0:21:29.96,EN,,0,0,0,,All right, now we're going to start. Dialogue: 0,0:21:30.53,0:21:32.48,EN,,0,0,0,,We're going to start the machine at eval-dispatch。 Dialogue: 0,0:21:33.26,0:21:34.62,EN,,0,0,0,,Right? That's the beginning of this. Dialogue: 0,0:21:35.87,0:21:38.75,EN,,0,0,0,,Eval-dispatch is going to look at the expression and dispatch, Dialogue: 0,0:21:39.32,0:21:40.06,EN,,0,0,0,,just like eval Dialogue: 0,0:21:40.87,0:21:42.00,EN,,0,0,0,,where we look at the very first thing. Dialogue: 0,0:21:42.04,0:21:47.95,EN,,0,0,0,,We branch on whether or not this expression is self-evaluating. Dialogue: 0,0:21:47.95,0:21:49.96,EN,,0,0,0,,Self-evaluating is some abstraction Dialogue: 0,0:21:49.96,0:21:51.10,EN,,0,0,0,,we put into the machine-- Dialogue: 0,0:21:52.22,0:21:53.51,EN,,0,0,0,,it's going to be true for numbers-- Dialogue: 0,0:21:53.64,0:21:55.52,EN,,0,0,0,,to a place called ev-self-eval, Dialogue: 0,0:21:56.77,0:21:58.20,EN,,0,0,0,,So me, being the controller, Dialogue: 0,0:21:58.22,0:21:59.55,EN,,0,0,0,,looks at ev-self-eval, Dialogue: 0,0:22:00.06,0:22:01.07,EN,,0,0,0,,so we'll go over to there. Dialogue: 0,0:22:02.60,0:22:04.76,EN,,0,0,0,,Ev-self-eval says fine, Dialogue: 0,0:22:06.54,0:22:09.90,EN,,0,0,0,,assign to val whatever is in the expression unit. Dialogue: 0,0:22:15.24,0:22:16.51,EN,,0,0,0,,And I have a bug Dialogue: 0,0:22:17.93,0:22:20.59,EN,,0,0,0,,because what I didn't do when I initialized this machine Dialogue: 0,0:22:21.62,0:22:22.89,EN,,0,0,0,,is also say what's supposed Dialogue: 0,0:22:22.91,0:22:24.19,EN,,0,0,0,,to happen when it's done, Dialogue: 0,0:22:24.65,0:22:26.83,EN,,0,0,0,,so I should have started out the machine Dialogue: 0,0:22:27.37,0:22:29.85,EN,,0,0,0,,with done being in the continue register, Dialogue: 0,0:22:31.18,0:22:33.26,EN,,0,0,0,,OK? So we assign to VAL. Dialogue: 0,0:22:33.37,0:22:35.56,EN,,0,0,0,,And now go to fetch of continue, Dialogue: 0,0:22:35.63,0:22:36.56,EN,,0,0,0,,and now change-- Dialogue: 0,0:22:38.09,0:22:38.60,EN,,0,0,0,,OK. Dialogue: 0,0:22:40.00,0:22:41.16,EN,,0,0,0,,OK, let's try something harder. Dialogue: 0,0:22:42.16,0:22:43.45,EN,,0,0,0,,Let's reset the machine here, Dialogue: 0,0:22:44.86,0:22:50.88,EN,,0,0,0,,and we'll put in the expression register, X, OK? Dialogue: 0,0:22:56.71,0:22:58.20,EN,,0,0,0,,Start again at eval-dispatch. Dialogue: 0,0:22:59.61,0:23:01.69,EN,,0,0,0,,Check, is it self-evaluating? Dialogue: 0,0:23:01.69,0:23:02.03,EN,,0,0,0,,No. Dialogue: 0,0:23:02.65,0:23:03.61,EN,,0,0,0,,Is it a variable? Dialogue: 0,0:23:04.63,0:23:05.02,EN,,0,0,0,,Yes. Dialogue: 0,0:23:05.56,0:23:07.07,EN,,0,0,0,,We go off to ev-variable. Dialogue: 0,0:23:08.38,0:23:10.97,EN,,0,0,0,,It says assign to VAL, Dialogue: 0,0:23:12.13,0:23:15.69,EN,,0,0,0,,look up the variable value in the expression register Dialogue: 0,0:23:21.23,0:23:22.91,EN,,0,0,0,,Go to fetch of continue. Dialogue: 0,0:23:23.96,0:23:24.48,EN,,0,0,0,,PROFESSOR: Done. Dialogue: 0,0:23:27.61,0:23:28.09,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:23:29.31,0:23:30.76,EN,,0,0,0,,Alright, Well, that's the basic idea. Those're Dialogue: 0,0:23:31.33,0:23:32.65,EN,,0,0,0,,That's a simple operation of the machine. Dialogue: 0,0:23:32.68,0:23:35.07,EN,,0,0,0,,Now, let's actually do something a little bit more interesting. Dialogue: 0,0:23:36.07,0:23:38.64,EN,,0,0,0,,Let's look at the expression Dialogue: 0,0:23:43.58,0:23:47.93,EN,,0,0,0,,the sum of x and y. Dialogue: 0,0:23:49.69,0:23:51.28,EN,,0,0,0,,OK. And now we'll see how you start Dialogue: 0,0:23:52.41,0:23:54.01,EN,,0,0,0,,unrolling these expression trees. Dialogue: 0,0:23:57.13,0:23:58.68,EN,,0,0,0,,Well, start again at eval-dispatch. Dialogue: 0,0:24:04.61,0:24:05.80,EN,,0,0,0,,Self-evaluating? Dialogue: 0,0:24:05.95,0:24:06.52,EN,,0,0,0,,No. Dialogue: 0,0:24:06.70,0:24:07.71,EN,,0,0,0,,Variable? No. Dialogue: 0,0:24:07.82,0:24:08.99,EN,,0,0,0,,All the other special forms Dialogue: 0,0:24:08.99,0:24:10.12,EN,,0,0,0,,which I didn't write down, Dialogue: 0,0:24:10.27,0:24:12.48,EN,,0,0,0,,like quote, and lambda, and set, and whatever, Dialogue: 0,0:24:12.48,0:24:13.08,EN,,0,0,0,,it's none of those. Dialogue: 0,0:24:13.26,0:24:14.73,EN,,0,0,0,,It turns out to be an application, Dialogue: 0,0:24:15.88,0:24:17.42,EN,,0,0,0,,so we go off to ev-application. Dialogue: 0,0:24:19.97,0:24:24.94,EN,,0,0,0,,Ev-application, remember what it's going to do overall. Dialogue: 0,0:24:25.58,0:24:28.19,EN,,0,0,0,,It is going to evaluate the operator. Dialogue: 0,0:24:28.27,0:24:31.40,EN,,0,0,0,,It's going to evaluate the arguments, Dialogue: 0,0:24:32.36,0:24:34.30,EN,,0,0,0,,and then it's going to go apply them. Dialogue: 0,0:24:35.06,0:24:36.09,EN,,0,0,0,,So, before we start, Dialogue: 0,0:24:36.94,0:24:37.88,EN,,0,0,0,,since we're being very literal, Dialogue: 0,0:24:37.88,0:24:38.88,EN,,0,0,0,,we'd better remember that, Dialogue: 0,0:24:39.07,0:24:40.54,EN,,0,0,0,,somewhere in this environment, Dialogue: 0,0:24:40.57,0:24:42.36,EN,,0,0,0,,it's linked to another environment Dialogue: 0,0:24:43.98,0:24:44.94,EN,,0,0,0,,in which plus Dialogue: 0,0:24:45.72,0:24:49.16,EN,,0,0,0,,is bound to the primitive procedure plus Dialogue: 0,0:24:51.63,0:24:54.03,EN,,0,0,0,,before we get an unknown variable in our machine. Dialogue: 0,0:24:55.34,0:24:56.84,EN,,0,0,0,,OK, so we're at ev-application. Dialogue: 0,0:24:59.85,0:25:04.32,EN,,0,0,0,,OK, assign to UNEV the operands Dialogue: 0,0:25:04.92,0:25:06.89,EN,,0,0,0,,of what's in the expression register. Dialogue: 0,0:25:07.61,0:25:08.83,EN,,0,0,0,,OK. Those are the operands. Dialogue: 0,0:25:09.23,0:25:11.66,EN,,0,0,0,,UNEV's a temporary register Dialogue: 0,0:25:11.68,0:25:12.59,EN,,0,0,0,,where we're going to save them. Dialogue: 0,0:25:13.22,0:25:13.86,EN,,0,0,0,,PROFESSOR: I'm assigning. Dialogue: 0,0:25:14.28,0:25:16.62,EN,,0,0,0,,PROFESSOR: Assign to EXP the operator. Dialogue: 0,0:25:18.07,0:25:20.09,EN,,0,0,0,,Now, notice we've destroyed that expression in EXP, Dialogue: 0,0:25:21.84,0:25:23.61,EN,,0,0,0,,but the piece that we need is now in UNEV. Dialogue: 0,0:25:25.82,0:25:26.81,EN,,0,0,0,,Now, we're going to get set up to Dialogue: 0,0:25:26.81,0:25:28.59,EN,,0,0,0,,to recursively evaluate the operator. Dialogue: 0,0:25:28.75,0:25:31.69,EN,,0,0,0,,Save the continue register on the stack. Dialogue: 0,0:25:34.86,0:25:36.09,EN,,0,0,0,,Save the environment. Dialogue: 0,0:25:40.48,0:25:41.69,EN,,0,0,0,,Save UNEV. Dialogue: 0,0:25:49.53,0:25:54.64,EN,,0,0,0,,OK, assign to continue a label called eval-args. Dialogue: 0,0:26:01.40,0:26:01.95,EN,,0,0,0,,Now, what have we done? Dialogue: 0,0:26:01.95,0:26:04.38,EN,,0,0,0,,We've set up for a recursive call. Dialogue: 0,0:26:04.38,0:26:05.88,EN,,0,0,0,,We're about to go to eval-dispatch. Dialogue: 0,0:26:06.28,0:26:08.83,EN,,0,0,0,,We've set up for a recursive call to eval-dispatch. Dialogue: 0,0:26:10.23,0:26:10.86,EN,,0,0,0,,What did we do? Dialogue: 0,0:26:11.02,0:26:13.64,EN,,0,0,0,,We took the things we're going to need later, Dialogue: 0,0:26:14.48,0:26:15.98,EN,,0,0,0,,those operands that were in UNEV; Dialogue: 0,0:26:16.36,0:26:18.99,EN,,0,0,0,,the environment in which we're going to eventually have to, Dialogue: 0,0:26:19.16,0:26:20.72,EN,,0,0,0,,maybe, evaluate those operands; Dialogue: 0,0:26:22.28,0:26:23.93,EN,,0,0,0,,the place we eventually want to go to, Dialogue: 0,0:26:23.95,0:26:25.07,EN,,0,0,0,,which, in this case, was done; Dialogue: 0,0:26:25.34,0:26:26.70,EN,,0,0,0,,we've saved them on the stack. Dialogue: 0,0:26:27.10,0:26:28.41,EN,,0,0,0,,The reason we saved them on the stack Dialogue: 0,0:26:28.43,0:26:30.67,EN,,0,0,0,,is because eval-dispatch makes no promises Dialogue: 0,0:26:30.94,0:26:32.54,EN,,0,0,0,,about what registers it may destroy. Dialogue: 0,0:26:33.55,0:26:35.02,EN,,0,0,0,,So all that stuff is saved on the stack. Dialogue: 0,0:26:35.02,0:26:36.91,EN,,0,0,0,,Now, we've set up eval-dispatch's contract. Dialogue: 0,0:26:37.38,0:26:38.75,EN,,0,0,0,,There's a new expression, Dialogue: 0,0:26:38.78,0:26:40.04,EN,,0,0,0,,which is the operator plus; Dialogue: 0,0:26:41.07,0:26:41.95,EN,,0,0,0,,a new environment, Dialogue: 0,0:26:41.98,0:26:43.60,EN,,0,0,0,,although, in this case, it's the same one; Dialogue: 0,0:26:44.25,0:26:45.87,EN,,0,0,0,,and a new place to go to when you're done, Dialogue: 0,0:26:45.87,0:26:46.91,EN,,0,0,0,,which is eval-args. Dialogue: 0,0:26:47.60,0:26:48.13,EN,,0,0,0,,So that's set up. Dialogue: 0,0:26:48.13,0:26:49.68,EN,,0,0,0,,Now, we're going to go off to eval-dispatch. Dialogue: 0,0:26:50.89,0:26:52.36,EN,,0,0,0,,Here we are back at eval-dispatch. Dialogue: 0,0:26:53.05,0:26:54.40,EN,,0,0,0,,It's not self-evaluating. Dialogue: 0,0:26:54.44,0:26:55.47,EN,,0,0,0,,Oh, it's a variable, Dialogue: 0,0:26:56.32,0:26:58.06,EN,,0,0,0,,so we'd better go off to ev-variable, Dialogue: 0,0:26:59.79,0:27:02.65,EN,,0,0,0,,Right? Ev-variable is assigned to VAL. Dialogue: 0,0:27:02.70,0:27:06.33,EN,,0,0,0,,Look up the variable value of the expression, Dialogue: 0,0:27:08.49,0:27:10.75,EN,,0,0,0,,OK? So VAL is the primitive procedure plus. Dialogue: 0,0:27:13.37,0:27:15.16,EN,,0,0,0,,And go to fetch of continue. Dialogue: 0,0:27:15.23,0:27:16.11,EN,,0,0,0,,PROFESSOR: Eval-args. Dialogue: 0,0:27:16.20,0:27:18.73,EN,,0,0,0,,PROFESSOR: Right, which is now eval-args not done. Dialogue: 0,0:27:19.42,0:27:21.26,EN,,0,0,0,,So we come back here at eval-args, Dialogue: 0,0:27:22.16,0:27:23.02,EN,,0,0,0,,and what do we do? Dialogue: 0,0:27:23.07,0:27:24.84,EN,,0,0,0,,We're going to restore the stuff that we saved, Dialogue: 0,0:27:25.20,0:27:26.57,EN,,0,0,0,,so we restore UNEV. Dialogue: 0,0:27:29.21,0:27:31.69,EN,,0,0,0,,And notice, there, it wasn't necessary, Dialogue: 0,0:27:31.74,0:27:32.90,EN,,0,0,0,,although, in general, it would be. Dialogue: 0,0:27:32.90,0:27:35.16,EN,,0,0,0,,It might be some arbitrary evaluation that happened. Dialogue: 0,0:27:35.43,0:27:36.70,EN,,0,0,0,,We restore ENV. Dialogue: 0,0:27:47.87,0:27:52.04,EN,,0,0,0,,OK, we assign to FUN fetch of VAL. Dialogue: 0,0:27:59.95,0:28:02.81,EN,,0,0,0,,OK, now, we're going to go off and start evaluating some arguments. Dialogue: 0,0:28:04.34,0:28:06.48,EN,,0,0,0,,Well, first thing we'd better do is save FUN Dialogue: 0,0:28:07.42,0:28:10.62,EN,,0,0,0,,because some arbitrary stuff might happen in that evaluation. Dialogue: 0,0:28:15.33,0:28:16.88,EN,,0,0,0,,We initialize the argument list. Dialogue: 0,0:28:16.91,0:28:19.29,EN,,0,0,0,,Assign to argl an empty argument list, Dialogue: 0,0:28:20.88,0:28:22.17,EN,,0,0,0,,and go to eval-arg-loop, Dialogue: 0,0:28:24.86,0:28:26.27,EN,,0,0,0,,At eval-arg-loop, Dialogue: 0,0:28:27.77,0:28:31.53,EN,,0,0,0,,the idea of this is we're going to evaluate the pieces of the Dialogue: 0,0:28:31.61,0:28:33.37,EN,,0,0,0,,expressions that are in UNEV, one by one, Dialogue: 0,0:28:33.54,0:28:35.68,EN,,0,0,0,,and move them from unevaluated in UNEV Dialogue: 0,0:28:35.90,0:28:37.26,EN,,0,0,0,,to evaluated in the arg list. Dialogue: 0,0:28:37.84,0:28:39.18,EN,,0,0,0,,OK. So we save argl. Dialogue: 0,0:28:43.95,0:28:47.26,EN,,0,0,0,,We assign to EXP the first operand Dialogue: 0,0:28:47.37,0:28:48.38,EN,,0,0,0,,of the stuff in UNEV. Dialogue: 0,0:28:53.77,0:28:55.89,EN,,0,0,0,,Now, we check and see if that was the last operand. Dialogue: 0,0:28:55.89,0:28:56.91,EN,,0,0,0,,In this case, it is not. Dialogue: 0,0:28:58.99,0:29:01.55,EN,,0,0,0,,So we save the environment. Dialogue: 0,0:29:08.00,0:29:10.06,EN,,0,0,0,,We save UNEV Dialogue: 0,0:29:11.61,0:29:13.50,EN,,0,0,0,,because those are all things we might need later. Dialogue: 0,0:29:13.50,0:29:14.40,EN,,0,0,0,,We're going to need the environment Dialogue: 0,0:29:14.44,0:29:15.64,EN,,0,0,0,,to do some more evaluations. Dialogue: 0,0:29:15.80,0:29:16.60,EN,,0,0,0,,We're going to need UNEV Dialogue: 0,0:29:16.62,0:29:19.20,EN,,0,0,0,,to look at what the rest of those arguments were. Dialogue: 0,0:29:20.34,0:29:21.55,EN,,0,0,0,,We're going to assign continue Dialogue: 0,0:29:21.56,0:29:24.44,EN,,0,0,0,,a place called accumulate-args, or accumulate-arg. Dialogue: 0,0:29:31.13,0:29:34.01,EN,,0,0,0,,OK, now, we've set up for another call to eval-dispatch, Dialogue: 0,0:29:37.07,0:29:38.54,EN,,0,0,0,,All right, now, let me short-circuit this Dialogue: 0,0:29:39.12,0:29:41.09,EN,,0,0,0,,so we don't go through the details of eval-dispatch. Dialogue: 0,0:29:41.09,0:29:42.64,EN,,0,0,0,,Eval-dispatch's contract says Dialogue: 0,0:29:42.97,0:29:45.00,EN,,0,0,0,,i'm going to end up, Dialogue: 0,0:29:45.13,0:29:45.96,EN,,0,0,0,,the world will end up, Dialogue: 0,0:29:46.03,0:29:48.20,EN,,0,0,0,,with the value of evaluating this expression Dialogue: 0,0:29:48.24,0:29:50.27,EN,,0,0,0,,in this environment in the VAL register, Dialogue: 0,0:29:50.27,0:29:51.07,EN,,0,0,0,,and I'll end up there. Dialogue: 0,0:29:51.32,0:29:52.62,EN,,0,0,0,,So we short-circuit all of this, Dialogue: 0,0:29:54.43,0:29:56.36,EN,,0,0,0,,and a 3 ends up in VAL. Dialogue: 0,0:29:58.01,0:29:59.76,EN,,0,0,0,,And, when we return from eval-dispatch, Dialogue: 0,0:29:59.76,0:30:01.76,EN,,0,0,0,,we're going to return to accumulate-arg. Dialogue: 0,0:30:02.30,0:30:03.23,EN,,0,0,0,,PROFESSOR: Accumulate-arg. Dialogue: 0,0:30:06.22,0:30:08.20,EN,,0,0,0,,PROFESSOR: With 3 in the VAL register, OK? Dialogue: 0,0:30:08.72,0:30:10.59,EN,,0,0,0,,So that short-circuited that evaluation. Dialogue: 0,0:30:10.65,0:30:11.32,EN,,0,0,0,,Now, what do we do? Dialogue: 0,0:30:11.32,0:30:13.68,EN,,0,0,0,,We're going to go back and look at the rest of the arguments, Dialogue: 0,0:30:13.68,0:30:14.83,EN,,0,0,0,,so we restore UNEV. Dialogue: 0,0:30:17.51,0:30:19.00,EN,,0,0,0,,We restore ENV. Dialogue: 0,0:30:25.79,0:30:27.05,EN,,0,0,0,,We restore argl. Dialogue: 0,0:30:28.65,0:30:29.17,EN,,0,0,0,,One thing. Dialogue: 0,0:30:30.06,0:30:31.45,EN,,0,0,0,,PROFESSOR: Oops! Parity error. Dialogue: 0,0:30:33.76,0:30:34.83,EN,,0,0,0,,PROFESSOR: Restore argl. Dialogue: 0,0:30:45.57,0:30:49.76,EN,,0,0,0,,OK, we assign to argl consing on Dialogue: 0,0:30:50.65,0:30:52.64,EN,,0,0,0,,fetch of the value register to what's in argl. Dialogue: 0,0:30:59.36,0:31:02.96,EN,,0,0,0,,OK, we assign to UNEV the rest of the operands Dialogue: 0,0:31:03.34,0:31:04.52,EN,,0,0,0,,in fetch of UNEV, Dialogue: 0,0:31:08.91,0:31:10.76,EN,,0,0,0,,and we go back to eval-arg-loop. Dialogue: 0,0:31:11.51,0:31:12.28,EN,,0,0,0,,PROFESSOR: Eval-arg-loop. Dialogue: 0,0:31:12.28,0:31:12.86,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:31:15.88,0:31:17.08,EN,,0,0,0,,Now, we're about to do the next argument, Dialogue: 0,0:31:17.58,0:31:19.31,EN,,0,0,0,,so the first thing we do is save argl. Dialogue: 0,0:31:25.40,0:31:28.27,EN,,0,0,0,,OK, we assign to EXP the first operand Dialogue: 0,0:31:29.15,0:31:30.81,EN,,0,0,0,,of fetch of UNEV. Dialogue: 0,0:31:34.72,0:31:37.02,EN,,0,0,0,,OK, we test and see if that's the last operand. Dialogue: 0,0:31:37.02,0:31:38.00,EN,,0,0,0,,In this case, it is Dialogue: 0,0:31:39.08,0:31:40.27,EN,,0,0,0,,so we're going to go to a special place Dialogue: 0,0:31:40.28,0:31:42.06,EN,,0,0,0,,that says evaluate the last argument Dialogue: 0,0:31:43.37,0:31:45.07,EN,,0,0,0,,because, notice,after evaluating the argument, Dialogue: 0,0:31:45.10,0:31:46.62,EN,,0,0,0,,we don't need the environment any more. Dialogue: 0,0:31:47.64,0:31:48.78,EN,,0,0,0,,That's going to be the difference. Dialogue: 0,0:31:50.25,0:31:51.85,EN,,0,0,0,,So here, at eval-last-arg, Dialogue: 0,0:31:52.24,0:31:54.92,EN,,0,0,0,,which is assigned to continue accumulate-last-arg, Dialogue: 0,0:32:04.27,0:32:06.90,EN,,0,0,0,,now, we're set up again for eval-dispatch. Dialogue: 0,0:32:06.90,0:32:08.51,EN,,0,0,0,,We've got a place to go to when we're done. Dialogue: 0,0:32:08.62,0:32:09.84,EN,,0,0,0,,We've got an expression. Dialogue: 0,0:32:09.84,0:32:10.80,EN,,0,0,0,,We've got an environment. Dialogue: 0,0:32:11.33,0:32:13.64,EN,,0,0,0,,OK, so we'll short-circuit the call to eval-dispatch. Dialogue: 0,0:32:14.37,0:32:16.41,EN,,0,0,0,,And what'll happen is there's a y there, Dialogue: 0,0:32:16.70,0:32:18.56,EN,,0,0,0,,it's 4 in that environment, Dialogue: 0,0:32:18.60,0:32:20.09,EN,,0,0,0,,so VAL will end up with 4 in it. Dialogue: 0,0:32:21.06,0:32:22.86,EN,,0,0,0,,And, then, we're going to end up at accumulate-last-arg, OK? Dialogue: 0,0:32:25.45,0:32:26.91,EN,,0,0,0,,So, at accumulate-last-arg, Dialogue: 0,0:32:29.28,0:32:30.52,EN,,0,0,0,,we restore argl. Dialogue: 0,0:32:37.69,0:32:42.76,EN,,0,0,0,,We assign to argl, we assign to argl cons, Dialogue: 0,0:32:43.60,0:32:45.83,EN,,0,0,0,,of fetch of the new value onto it, Dialogue: 0,0:32:45.93,0:32:47.39,EN,,0,0,0,,so we cons a 4 onto that. Dialogue: 0,0:32:49.85,0:32:52.52,EN,,0,0,0,,We restore what was saved in the function register. Dialogue: 0,0:32:53.77,0:32:54.99,EN,,0,0,0,,And notice, in this case, Dialogue: 0,0:32:55.00,0:32:56.27,EN,,0,0,0,,it had not been destroyed, Dialogue: 0,0:32:56.38,0:32:57.72,EN,,0,0,0,,but in general, it will be. Dialogue: 0,0:32:59.13,0:33:01.50,EN,,0,0,0,,And now, we're ready to go off to apply-dispatch, Dialogue: 0,0:33:02.65,0:33:04.40,EN,,0,0,0,,Alright? So we've just gone through the eval. Dialogue: 0,0:33:04.51,0:33:05.85,EN,,0,0,0,,We evaluated the argument, Dialogue: 0,0:33:06.46,0:33:07.98,EN,,0,0,0,,the operator, and the arguments, Dialogue: 0,0:33:07.98,0:33:09.24,EN,,0,0,0,,and now, we're about to apply them. Dialogue: 0,0:33:09.58,0:33:11.37,EN,,0,0,0,,So we come off to apply-dispatch here Dialogue: 0,0:33:18.03,0:33:19.29,EN,,0,0,0,,We come off to apply-dispatch, Dialogue: 0,0:33:21.05,0:33:22.41,EN,,0,0,0,,and we're going to check whether it's a primitive Dialogue: 0,0:33:22.41,0:33:23.45,EN,,0,0,0,,or a compound procedure. Dialogue: 0,0:33:23.64,0:33:24.20,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,0:33:24.54,0:33:24.83,EN,,0,0,0,,PROFESSOR: All right. Dialogue: 0,0:33:24.89,0:33:26.52,EN,,0,0,0,,So, in this case, it's a primitive procedure, Dialogue: 0,0:33:27.45,0:33:28.91,EN,,0,0,0,,and we go off to primitive-apply. Dialogue: 0,0:33:29.79,0:33:31.36,EN,,0,0,0,,So we go off to primitive-apply, Dialogue: 0,0:33:33.71,0:33:35.37,EN,,0,0,0,,that says assign to VAL Dialogue: 0,0:33:35.69,0:33:38.25,EN,,0,0,0,,result of applying primitive procedure Dialogue: 0,0:33:38.36,0:33:40.30,EN,,0,0,0,,of the function to the argument list. Dialogue: 0,0:33:41.31,0:33:42.43,EN,,0,0,0,,PROFESSOR: I don't know how to add. Dialogue: 0,0:33:42.54,0:33:43.80,EN,,0,0,0,,I'm just an execution unit. Dialogue: 0,0:33:44.14,0:33:45.35,EN,,0,0,0,,PROFESSOR: Well, I don't know how to add either. Dialogue: 0,0:33:45.35,0:33:46.51,EN,,0,0,0,,I'm just the evaluator, Dialogue: 0,0:33:47.08,0:33:48.36,EN,,0,0,0,,so we need a primitive operator. Dialogue: 0,0:33:48.36,0:33:49.72,EN,,0,0,0,,Let's see, so the primitive operator, Dialogue: 0,0:33:49.76,0:33:52.36,EN,,0,0,0,,What's the... what's the sum of 3 and 4? Dialogue: 0,0:33:52.86,0:33:53.32,EN,,0,0,0,,AUDIENCE: 7. Dialogue: 0,0:33:53.71,0:33:54.65,EN,,0,0,0,,PROFESSOR: OK, 7. Dialogue: 0,0:33:55.32,0:33:55.99,EN,,0,0,0,,PROFESSOR: Thank you. Dialogue: 0,0:33:59.20,0:34:00.60,EN,,0,0,0,,PROFESSOR: Now, we restore continue, Dialogue: 0,0:34:11.58,0:34:12.90,EN,,0,0,0,,and we go to fetch of continue. Dialogue: 0,0:34:13.07,0:34:13.47,EN,,0,0,0,,PROFESSOR: Done. Dialogue: 0,0:34:14.20,0:34:14.67,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:34:14.92,0:34:18.41,EN,,0,0,0,,Well, that was in as much detail as you will ever see. Dialogue: 0,0:34:18.41,0:34:20.19,EN,,0,0,0,,We'll never do it in as much detail again. Dialogue: 0,0:34:21.59,0:34:23.92,EN,,0,0,0,,One very important thing to notice Dialogue: 0,0:34:24.91,0:34:27.55,EN,,0,0,0,,is that we just executed a recursive procedure, Dialogue: 0,0:34:29.56,0:34:31.17,EN,,0,0,0,,Right? This whole thing, we used a stack Dialogue: 0,0:34:31.17,0:34:32.75,EN,,0,0,0,,and the evaluator was recursive. Dialogue: 0,0:34:33.07,0:34:35.88,EN,,0,0,0,,A lot of people think the reason that you need a stack Dialogue: 0,0:34:36.48,0:34:37.85,EN,,0,0,0,,and recursion in an evaluator Dialogue: 0,0:34:37.87,0:34:38.97,EN,,0,0,0,,is because you might be Dialogue: 0,0:34:39.09,0:34:42.15,EN,,0,0,0,,evaluating recursive procedures like factorial or Fibonacci. Dialogue: 0,0:34:42.15,0:34:42.92,EN,,0,0,0,,It's not true. Dialogue: 0,0:34:43.67,0:34:44.99,EN,,0,0,0,,So you notice we did recursion here, Dialogue: 0,0:34:45.00,0:34:46.86,EN,,0,0,0,,and all we evaluated was (+ x y) Dialogue: 0,0:34:47.77,0:34:50.65,EN,,0,0,0,,Right? The reason that you need recursion in the evaluator Dialogue: 0,0:34:50.96,0:34:52.97,EN,,0,0,0,,is because the evaluation process, Dialogue: 0,0:34:52.99,0:34:54.06,EN,,0,0,0,,itself, is recursive. Dialogue: 0,0:34:54.45,0:34:56.17,EN,,0,0,0,,Right? It's not because the procedure Dialogue: 0,0:34:56.32,0:34:58.09,EN,,0,0,0,,that you might be evaluating in LISP Dialogue: 0,0:34:58.12,0:34:59.27,EN,,0,0,0,,is a recursive procedure. Dialogue: 0,0:34:59.27,0:35:00.52,EN,,0,0,0,,So that's an important thing Dialogue: 0,0:35:00.52,0:35:02.14,EN,,0,0,0,,that people get confused about a lot. Dialogue: 0,0:35:03.01,0:35:04.27,EN,,0,0,0,,The other thing to notice is that, Dialogue: 0,0:35:04.27,0:35:05.64,EN,,0,0,0,,when we're done here, Dialogue: 0,0:35:06.28,0:35:07.12,EN,,0,0,0,,we're really done. Dialogue: 0,0:35:07.12,0:35:08.49,EN,,0,0,0,,Not only are we at done, Dialogue: 0,0:35:09.45,0:35:13.23,EN,,0,0,0,,but there's no accumulated stuff on the stack, Dialogue: 0,0:35:13.60,0:35:15.71,EN,,0,0,0,,Right? The machine is back to its initial state. Dialogue: 0,0:35:17.00,0:35:18.75,EN,,0,0,0,,So that's part of what it means to be done. Dialogue: 0,0:35:19.71,0:35:21.04,EN,,0,0,0,,Another way to say that is Dialogue: 0,0:35:22.72,0:35:26.04,EN,,0,0,0,,the evaluation process has reduced Dialogue: 0,0:35:26.41,0:35:28.32,EN,,0,0,0,,the expression, plus X, Y, Dialogue: 0,0:35:30.54,0:35:32.78,EN,,0,0,0,,to the value here, 7. Dialogue: 0,0:35:33.24,0:35:35.45,EN,,0,0,0,,And by reduced, I mean a very particular thing. Dialogue: 0,0:35:36.01,0:35:38.18,EN,,0,0,0,,It means that there's nothing left on the stack. Dialogue: 0,0:35:38.18,0:35:40.36,EN,,0,0,0,,The machine is now in the same state, Dialogue: 0,0:35:40.92,0:35:42.65,EN,,0,0,0,,except there's something in the value register. Dialogue: 0,0:35:42.72,0:35:44.52,EN,,0,0,0,,It's not part of a sub-problem of anything. Dialogue: 0,0:35:44.52,0:35:45.63,EN,,0,0,0,,There's nothing to go back to. Dialogue: 0,0:35:46.12,0:35:46.96,EN,,0,0,0,,OK. Let's break. Dialogue: 0,0:35:50.16,0:35:50.76,EN,,0,0,0,,Question? Dialogue: 0,0:35:51.08,0:35:54.02,EN,,0,0,0,,AUDIENCE: The question here, in the stack, Dialogue: 0,0:35:54.02,0:35:55.82,EN,,0,0,0,,is because the data may be recursive. Dialogue: 0,0:35:56.20,0:35:58.75,EN,,0,0,0,,You may have embedded expressions, for instance. Dialogue: 0,0:35:59.31,0:36:02.08,EN,,0,0,0,,PROFESSOR: Yes, because you might have embedded expressions. Dialogue: 0,0:36:02.08,0:36:04.77,EN,,0,0,0,,But, again, don't confuse that Dialogue: 0,0:36:04.77,0:36:07.98,EN,,0,0,0,,with what people sometimes mean by the data may be recursive, Dialogue: 0,0:36:08.00,0:36:10.35,EN,,0,0,0,,which is to say you have these list-structured, Dialogue: 0,0:36:11.04,0:36:12.93,EN,,0,0,0,,recursive data list operations. Dialogue: 0,0:36:12.93,0:36:13.96,EN,,0,0,0,,That has nothing to do with it. Dialogue: 0,0:36:13.98,0:36:16.16,EN,,0,0,0,,It's simply that the expressions contain sub-expressions. Dialogue: 0,0:36:20.04,0:36:23.52,EN,,0,0,0,,AUDIENCE: Why is it that the order of the arguments in the arg list got reversed? Dialogue: 0,0:36:23.55,0:36:25.29,EN,,0,0,0,,PROFESSOR: Ah! Yes, I should've mentioned that. Dialogue: 0,0:36:27.26,0:36:29.07,EN,,0,0,0,,Here, the reason the order is reversed-- Dialogue: 0,0:36:32.78,0:36:35.37,EN,,0,0,0,,it's a question of what you mean by reversed. Dialogue: 0,0:36:36.05,0:36:39.90,EN,,0,0,0,,I believe it was Newton. Dialogue: 0,0:36:40.91,0:36:42.41,EN,,0,0,0,,In the very early part of optics, Dialogue: 0,0:36:42.43,0:36:43.26,EN,,0,0,0,,people realized Dialogue: 0,0:36:43.61,0:36:45.36,EN,,0,0,0,,that when you look through the lens of your eye, Dialogue: 0,0:36:45.50,0:36:46.73,EN,,0,0,0,,the image was up-side down. Dialogue: 0,0:36:46.73,0:36:48.04,EN,,0,0,0,,And there was a lot of argument about Dialogue: 0,0:36:48.04,0:36:50.48,EN,,0,0,0,,why that didn't mean you saw things up-side down. Dialogue: 0,0:36:51.28,0:36:52.65,EN,,0,0,0,,So it's sort of the same issue. Dialogue: 0,0:36:52.86,0:36:53.90,EN,,0,0,0,,Reversed from what? Dialogue: 0,0:36:54.81,0:36:56.24,EN,,0,0,0,,So we just need some convention. Dialogue: 0,0:36:56.59,0:37:00.35,EN,,0,0,0,,So all we.. The reason that they're coming at 4, 3 Dialogue: 0,0:37:00.80,0:37:02.49,EN,,0,0,0,,is because taking UNEV Dialogue: 0,0:37:02.52,0:37:04.03,EN,,0,0,0,,and consing the result onto argl. Dialogue: 0,0:37:04.52,0:37:06.68,EN,,0,0,0,,So you have to realize you've made that convention. Dialogue: 0,0:37:06.86,0:37:09.37,EN,,0,0,0,,The place that you have to realize that-- Dialogue: 0,0:37:09.98,0:37:11.23,EN,,0,0,0,,well, there's actually two places. Dialogue: 0,0:37:11.23,0:37:12.91,EN,,0,0,0,,One is in apply-primitive-operator, Dialogue: 0,0:37:12.91,0:37:14.06,EN,,0,0,0,,which has to realize that Dialogue: 0,0:37:15.12,0:37:16.75,EN,,0,0,0,,the arguments to primitives go in, Dialogue: 0,0:37:16.78,0:37:18.72,EN,,0,0,0,,the opposite order from the way you're writing them down. Dialogue: 0,0:37:19.49,0:37:21.00,EN,,0,0,0,,And the other one is, we'll see later Dialogue: 0,0:37:21.07,0:37:23.80,EN,,0,0,0,,when you actually go to bind a function's parameters, Dialogue: 0,0:37:24.01,0:37:25.74,EN,,0,0,0,,you should realize the arguments are going to come in Dialogue: 0,0:37:25.74,0:37:28.54,EN,,0,0,0,,from the opposite order of the variables to which you're binding them. Dialogue: 0,0:37:28.87,0:37:30.17,EN,,0,0,0,,So, if you just keep track of that, Dialogue: 0,0:37:31.08,0:37:31.83,EN,,0,0,0,,there's no problem. Dialogue: 0,0:37:31.83,0:37:33.69,EN,,0,0,0,,Also, this is completely arbitrary Dialogue: 0,0:37:33.90,0:37:34.96,EN,,0,0,0,,because, if we'd done, Dialogue: 0,0:37:35.10,0:37:37.15,EN,,0,0,0,,say, an iteration through a vector assigning them, Dialogue: 0,0:37:37.42,0:37:38.73,EN,,0,0,0,,they might come out in the other order. Dialogue: 0,0:37:40.41,0:37:42.04,EN,,0,0,0,,OK. So it's just a convention of the way Dialogue: 0,0:37:42.06,0:37:43.53,EN,,0,0,0,,this particular evaluator works. Dialogue: 0,0:37:45.39,0:37:46.24,EN,,0,0,0,,All right, let's take a break. Dialogue: 0,0:37:46.33,0:38:02.44,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:38:02.44,0:38:07.64,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:38:28.62,0:38:32.51,EN,,0,0,0,,By: Prof. Harold Abelson && Sussman Jay Sussman Dialogue: 0,0:38:32.51,0:38:35.68,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:38:41.84,0:38:45.31,EN,,0,0,0,,Professor: We just saw evaluating an expression Dialogue: 0,0:38:45.60,0:38:47.08,EN,,0,0,0,,and, of course, that was very simple one. But Dialogue: 0,0:38:48.81,0:38:50.24,EN,,0,0,0,,in essence, it would be no different Dialogue: 0,0:38:50.24,0:38:52.03,EN,,0,0,0,,if it was some big nested expression, Dialogue: 0,0:38:52.03,0:38:54.57,EN,,0,0,0,,so there would just be deeper recursion on the stack. Dialogue: 0,0:38:55.13,0:38:56.03,EN,,0,0,0,,But what I want to do now Dialogue: 0,0:38:56.04,0:38:56.91,EN,,0,0,0,,is show you the last piece. Dialogue: 0,0:38:56.92,0:38:59.82,EN,,0,0,0,,I want to walk you around this eval and apply loop, Dialogue: 0,0:39:01.01,0:39:02.81,EN,,0,0,0,,That's the thing we haven't seen, really. Dialogue: 0,0:39:03.00,0:39:04.75,EN,,0,0,0,,We haven't seen any compound procedures Dialogue: 0,0:39:05.20,0:39:07.79,EN,,0,0,0,,where evalutation of procedure reduces to Dialogue: 0,0:39:07.92,0:39:10.11,EN,,0,0,0,,where applying of procedure reduces to Dialogue: 0,0:39:10.12,0:39:11.64,EN,,0,0,0,,evaluating the body of the procedure, Dialogue: 0,0:39:12.44,0:39:15.88,EN,,0,0,0,,so let's just suppose we had this. Dialogue: 0,0:39:15.93,0:39:17.44,EN,,0,0,0,,Suppose we were looking at the procedure Dialogue: 0,0:39:18.07,0:39:31.60,EN,,0,0,0,,define F of A and B to be the sum of A and B. Dialogue: 0,0:39:33.99,0:39:37.32,EN,,0,0,0,,So, as we typed in that procedure previously, Dialogue: 0,0:39:37.69,0:39:41.64,EN,,0,0,0,,and now we're going to evaluate F of X and Y Dialogue: 0,0:39:42.27,0:39:44.20,EN,,0,0,0,,again, in this environment, E,0, Dialogue: 0,0:39:44.35,0:39:47.02,EN,,0,0,0,,where X is bound to 3 and Y is bound to 4. Dialogue: 0,0:39:50.78,0:39:52.11,EN,,0,0,0,,When the defined is executed, Dialogue: 0,0:39:52.12,0:39:53.69,EN,,0,0,0,,remember, there's a lambda here, Dialogue: 0,0:39:53.82,0:39:55.53,EN,,0,0,0,,and lambdas create procedures. Dialogue: 0,0:39:55.95,0:39:58.49,EN,,0,0,0,,And, basically, what will happen is, Dialogue: 0,0:39:59.63,0:40:00.68,EN,,0,0,0,,in E0, Dialogue: 0,0:40:01.00,0:40:02.65,EN,,0,0,0,,we'll end up with a binding for F, Dialogue: 0,0:40:03.56,0:40:05.61,EN,,0,0,0,,which will say F is a procedure, Dialogue: 0,0:40:07.15,0:40:11.28,EN,,0,0,0,,and its args are A and B, Dialogue: 0,0:40:12.57,0:40:16.19,EN,,0,0,0,,and its body is plus a,b. Dialogue: 0,0:40:18.11,0:40:20.99,EN,,0,0,0,,So that's what the environment would have looked like Dialogue: 0,0:40:21.21,0:40:22.52,EN,,0,0,0,,had we made that definition. Dialogue: 0,0:40:24.22,0:40:27.28,EN,,0,0,0,,Then, when we go to evaluate F of X and Y, Dialogue: 0,0:40:28.80,0:40:30.89,EN,,0,0,0,,we'll go through exactly the same process Dialogue: 0,0:40:31.02,0:40:31.85,EN,,0,0,0,,that we did before. Dialogue: 0,0:40:31.88,0:40:33.09,EN,,0,0,0,,It's even the same expression. Dialogue: 0,0:40:33.28,0:40:34.38,EN,,0,0,0,,The only difference is that Dialogue: 0,0:40:34.40,0:40:36.64,EN,,0,0,0,,F, instead of having primitive "plus" in it Dialogue: 0,0:40:37.24,0:40:38.99,EN,,0,0,0,,will have this thing. Dialogue: 0,0:40:41.04,0:40:43.60,EN,,0,0,0,,And so we'll go through exactly the same process, Dialogue: 0,0:40:43.60,0:40:44.92,EN,,0,0,0,,except this time, when we end up Dialogue: 0,0:40:45.26,0:40:47.42,EN,,0,0,0,,at apply-dispatch, Dialogue: 0,0:40:47.86,0:40:50.28,EN,,0,0,0,,the function register, instead of having primitive plus, Dialogue: 0,0:40:50.44,0:40:53.58,EN,,0,0,0,,will have a thing that will represent it saying procedure, Dialogue: 0,0:40:54.30,0:40:59.00,EN,,0,0,0,,where the args are A and B, Dialogue: 0,0:41:00.64,0:41:06.27,EN,,0,0,0,,and the body is plus A, B. Dialogue: 0,0:41:07.87,0:41:09.92,EN,,0,0,0,,And, again, what I mean, by its ENV, Dialogue: 0,0:41:09.96,0:41:11.12,EN,,0,0,0,,I mean there's a pointer to it, Dialogue: 0,0:41:11.24,0:41:13.07,EN,,0,0,0,,so don't worry that I'm writing a lot of stuff there. Dialogue: 0,0:41:13.28,0:41:15.63,EN,,0,0,0,,There's a pointer to this procedure data structure. Dialogue: 0,0:41:17.17,0:41:19.77,EN,,0,0,0,,OK, so, we're in exactly the same situation. Dialogue: 0,0:41:20.27,0:41:22.43,EN,,0,0,0,,We get to apply-dispatch, Dialogue: 0,0:41:23.98,0:41:26.48,EN,,0,0,0,,so, here, we come to apply-dispatch. Dialogue: 0,0:41:26.48,0:41:28.73,EN,,0,0,0,,Last time, we branched off to a primitive procedure. Dialogue: 0,0:41:30.01,0:41:30.70,EN,,0,0,0,,Here, it says oh, Dialogue: 0,0:41:30.84,0:41:32.80,EN,,0,0,0,,we now have a compound procedure, Dialogue: 0,0:41:34.55,0:41:36.60,EN,,0,0,0,,so we're going to go off to compound-apply. Dialogue: 0,0:41:38.47,0:41:39.92,EN,,0,0,0,,Now, what's compound-apply? Dialogue: 0,0:41:41.92,0:41:44.54,EN,,0,0,0,,Well, remember what the meta-circular evaluator did? Dialogue: 0,0:41:45.09,0:41:47.40,EN,,0,0,0,,Compound-apply said we're going to evaluate Dialogue: 0,0:41:49.90,0:41:51.60,EN,,0,0,0,,the body of the procedure Dialogue: 0,0:41:52.94,0:41:54.12,EN,,0,0,0,,in some new environment. Dialogue: 0,0:41:54.12,0:41:55.87,EN,,0,0,0,,Where does that new environment come from? Dialogue: 0,0:41:56.73,0:42:01.36,EN,,0,0,0,,We take the environment that was packaged with the procedure, Dialogue: 0,0:42:03.02,0:42:05.79,EN,,0,0,0,,we bind the parameters of the procedure Dialogue: 0,0:42:06.00,0:42:07.63,EN,,0,0,0,,to the arguments that we're passing in, Dialogue: 0,0:42:09.75,0:42:11.95,EN,,0,0,0,,and use that as a new frame to extend Dialogue: 0,0:42:12.59,0:42:13.79,EN,,0,0,0,,the procedure environment. Dialogue: 0,0:42:14.99,0:42:16.08,EN,,0,0,0,,And that's the environment Dialogue: 0,0:42:16.30,0:42:18.88,EN,,0,0,0,,in which we evaluate the procedure body, Dialogue: 0,0:42:20.12,0:42:24.47,EN,,0,0,0,,Right? That's going around the apply/eval loop. Dialogue: 0,0:42:24.47,0:42:26.25,EN,,0,0,0,,That's apply coming back to call eval, Dialogue: 0,0:42:32.86,0:42:34.92,EN,,0,0,0,,So, now, that's all we have to do in compound-apply. Dialogue: 0,0:42:36.78,0:42:37.72,EN,,0,0,0,,What are we going to do? Dialogue: 0,0:42:37.72,0:42:40.97,EN,,0,0,0,,We're going to manufacture a new environment. Dialogue: 0,0:42:43.55,0:42:45.64,EN,,0,0,0,,And we're going to manufacture a new environment that, Dialogue: 0,0:42:46.76,0:42:48.11,EN,,0,0,0,,let's see, that we'll call E1. Dialogue: 0,0:42:52.90,0:42:55.63,EN,,0,0,0,,E1 is going to be some environment where the Dialogue: 0,0:42:57.31,0:42:59.15,EN,,0,0,0,,where the parameters of the procedure, Dialogue: 0,0:42:59.21,0:43:03.26,EN,,0,0,0,,Nwhere A is bound to 3, and B is bound to 4, Dialogue: 0,0:43:04.27,0:43:05.76,EN,,0,0,0,,and it's linked to E0 Dialogue: 0,0:43:05.76,0:43:08.08,EN,,0,0,0,,because that's where f is defined. Dialogue: 0,0:43:09.27,0:43:10.27,EN,,0,0,0,,And, in this environment, Dialogue: 0,0:43:10.27,0:43:11.96,EN,,0,0,0,,we're going to evaluate the body of the procedure. Dialogue: 0,0:43:12.05,0:43:14.48,EN,,0,0,0,,So let's look at that, we're going Dialogue: 0,0:43:16.52,0:43:18.32,EN,,0,0,0,,Here we are at compound-apply, Dialogue: 0,0:43:20.30,0:43:23.47,EN,,0,0,0,,which says assign to the expression register Dialogue: 0,0:43:24.50,0:43:25.98,EN,,0,0,0,,the body of the procedure Dialogue: 0,0:43:25.98,0:43:27.26,EN,,0,0,0,,that's in the function register. Dialogue: 0,0:43:28.38,0:43:30.64,EN,,0,0,0,,So I assign to the expression register Dialogue: 0,0:43:31.29,0:43:32.33,EN,,0,0,0,,the procedure body, Dialogue: 0,0:43:40.75,0:43:41.10,EN,,0,0,0,,OK? Dialogue: 0,0:43:42.64,0:43:44.97,EN,,0,0,0,,That's going to be evaluated in an environment Dialogue: 0,0:43:45.82,0:43:48.32,EN,,0,0,0,,which is formed by making some bindings Dialogue: 0,0:43:51.30,0:43:53.67,EN,,0,0,0,,using information determined by the procedure-- Dialogue: 0,0:43:53.67,0:43:56.25,EN,,0,0,0,,that's what's in FUN-- and the argument list. Dialogue: 0,0:43:57.80,0:44:00.00,EN,,0,0,0,,And let's not worry about exactly what that does, Dialogue: 0,0:44:00.08,0:44:01.63,EN,,0,0,0,,but you can see the information's there. Dialogue: 0,0:44:01.93,0:44:03.32,EN,,0,0,0,,So make bindings will say oh, Dialogue: 0,0:44:04.04,0:44:07.90,EN,,0,0,0,,the procedure, itself, had an environment attached to it. Dialogue: 0,0:44:07.96,0:44:09.32,EN,,0,0,0,,I didn't write that quite here. Dialogue: 0,0:44:09.36,0:44:10.56,EN,,0,0,0,,I should've said in environment Dialogue: 0,0:44:11.30,0:44:12.73,EN,,0,0,0,,because every procedure gets built Dialogue: 0,0:44:12.76,0:44:13.44,EN,,0,0,0,,with an environment. Dialogue: 0,0:44:13.66,0:44:14.83,EN,,0,0,0,,So, from that environment, Dialogue: 0,0:44:15.68,0:44:16.35,EN,,0,0,0,,it knows Dialogue: 0,0:44:16.60,0:44:18.65,EN,,0,0,0,,what the procedure's definition environment is. Dialogue: 0,0:44:19.29,0:44:20.75,EN,,0,0,0,,It knows what the arguments are. Dialogue: 0,0:44:21.83,0:44:22.49,EN,,0,0,0,,It looks at argl, Dialogue: 0,0:44:22.49,0:44:24.28,EN,,0,0,0,,and then you see a reversal convention here. Dialogue: 0,0:44:24.28,0:44:26.62,EN,,0,0,0,,It just has to know that argl is reversed, Dialogue: 0,0:44:27.06,0:44:28.81,EN,,0,0,0,,and it builds this frame, E,1. Dialogue: 0,0:44:29.99,0:44:31.08,EN,,0,0,0,,All right, so, let's assume that Dialogue: 0,0:44:31.10,0:44:32.92,EN,,0,0,0,,that's what make bindings returns, Dialogue: 0,0:44:33.36,0:44:36.22,EN,,0,0,0,,so it assigns to ENV this thing, E,1. Dialogue: 0,0:44:41.34,0:44:42.54,EN,,0,0,0,,The next thing it says Dialogue: 0,0:44:43.95,0:44:45.84,EN,,0,0,0,,is restore continue. Dialogue: 0,0:44:46.89,0:44:48.19,EN,,0,0,0,,Remember what continue was here? Dialogue: 0,0:44:48.76,0:44:50.43,EN,,0,0,0,,It got put up in the last segment. Dialogue: 0,0:44:52.24,0:44:54.02,EN,,0,0,0,,Continue got stored. Dialogue: 0,0:44:54.02,0:44:55.18,EN,,0,0,0,,That was the original done, Dialogue: 0,0:44:55.32,0:44:56.56,EN,,0,0,0,,which said what are you going to do Dialogue: 0,0:44:56.73,0:44:59.44,EN,,0,0,0,,after you're done with this particular application? Dialogue: 0,0:45:00.14,0:45:01.72,EN,,0,0,0,,It was one of the very first things that happened Dialogue: 0,0:45:01.76,0:45:03.18,EN,,0,0,0,,when we evaluated the application. Dialogue: 0,0:45:03.88,0:45:05.87,EN,,0,0,0,,And now, finally, we're going to restore continue. Dialogue: 0,0:45:06.86,0:45:09.55,EN,,0,0,0,,Remember apply-dispatch's contract. Dialogue: 0,0:45:09.58,0:45:11.20,EN,,0,0,0,,It assumes that where it should go to next Dialogue: 0,0:45:11.23,0:45:11.98,EN,,0,0,0,,was on the stack, Dialogue: 0,0:45:12.03,0:45:13.12,EN,,0,0,0,,and there it was on the stack. Dialogue: 0,0:45:13.59,0:45:14.76,EN,,0,0,0,,Continue has done, Dialogue: 0,0:45:17.82,0:45:19.90,EN,,0,0,0,,and now we're going to go back to eval-dispatch. Dialogue: 0,0:45:19.94,0:45:20.84,EN,,0,0,0,,We're set up again. Dialogue: 0,0:45:20.97,0:45:24.41,EN,,0,0,0,,We have an expression, an environment, and a place to go to. Dialogue: 0,0:45:25.80,0:45:26.89,EN,,0,0,0,,We're not going to go through that Dialogue: 0,0:45:27.88,0:45:29.55,EN,,0,0,0,,because it's sort of the same expression. Dialogue: 0,0:45:35.40,0:45:37.79,EN,,0,0,0,,OK, but the thing, again, to notice Dialogue: 0,0:45:37.82,0:45:38.73,EN,,0,0,0,,is, at this point, Dialogue: 0,0:45:39.34,0:45:43.72,EN,,0,0,0,,we have reduced the original expression, F,X,Y, Dialogue: 0,0:45:44.64,0:45:47.92,EN,,0,0,0,,We've reduced evaluating F,X,Y in environment E,0 Dialogue: 0,0:45:48.89,0:45:52.67,EN,,0,0,0,,to evaluate plus A, B in E,1. Dialogue: 0,0:45:52.78,0:45:55.92,EN,,0,0,0,,And notice, nothing's on the stack, right? Dialogue: 0,0:45:56.11,0:45:56.83,EN,,0,0,0,,It's a reduction. Dialogue: 0,0:45:56.84,0:45:59.80,EN,,0,0,0,,At this point, the machine does not contain, Dialogue: 0,0:45:59.84,0:46:01.20,EN,,0,0,0,,as part of its state, Dialogue: 0,0:46:01.76,0:46:03.71,EN,,0,0,0,,the fact that it's in the middle of evaluating Dialogue: 0,0:46:03.72,0:46:04.88,EN,,0,0,0,,some procedure called f, Dialogue: 0,0:46:05.49,0:46:06.28,EN,,0,0,0,,that's gone, Dialogue: 0,0:46:07.66,0:46:09.55,EN,,0,0,0,,Right? There's no accumulated state? Dialogue: 0,0:46:13.07,0:46:14.37,EN,,0,0,0,,Again, that's a very important idea. Dialogue: 0,0:46:14.37,0:46:16.33,EN,,0,0,0,,That's the meaning of, Dialogue: 0,0:46:16.76,0:46:18.39,EN,,0,0,0,,when we used to write in the substitution model, Dialogue: 0,0:46:18.39,0:46:20.86,EN,,0,0,0,,this expression reduces to that expression. Dialogue: 0,0:46:21.35,0:46:22.66,EN,,0,0,0,,And you don't have to remember anything. Dialogue: 0,0:46:22.66,0:46:24.50,EN,,0,0,0,,And here, you see the meaning of reduction. Dialogue: 0,0:46:24.56,0:46:26.16,EN,,0,0,0,,At this point, there is nothing on the stack. Dialogue: 0,0:46:31.59,0:46:33.63,EN,,0,0,0,,See, that has very important consequences. Dialogue: 0,0:46:35.24,0:46:37.90,EN,,0,0,0,,Let's go back and look at iterative factorial, Dialogue: 0,0:46:40.42,0:46:42.76,EN,,0,0,0,,all right? Remember, this was some sort of loop Dialogue: 0,0:46:44.01,0:46:44.88,EN,,0,0,0,,and doing iter. Dialogue: 0,0:46:45.13,0:46:47.36,EN,,0,0,0,,And we kept saying that's an iterative procedure, Dialogue: 0,0:46:49.26,0:46:53.84,EN,,0,0,0,,And what we wrote, remember, Dialogue: 0,0:46:58.44,0:47:03.13,EN,,0,0,0,,are things like, we said, Dialogue: 0,0:47:04.35,0:47:11.07,EN,,0,0,0,,fact-iter of 5. Dialogue: 0,0:47:12.36,0:47:18.67,EN,,0,0,0,,We wrote things like reduces to iter of 1, and 1, and 5, Dialogue: 0,0:47:19.03,0:47:25.15,EN,,0,0,0,,which reduces to iter of 1, and 2, and 5, Dialogue: 0,0:47:25.32,0:47:27.07,EN,,0,0,0,,and so on, and so on, and so on. Dialogue: 0,0:47:27.07,0:47:28.17,EN,,0,0,0,,And we kept saying well, look, Dialogue: 0,0:47:28.17,0:47:30.35,EN,,0,0,0,,you don't have to build up any storage to do that. Dialogue: 0,0:47:31.72,0:47:32.73,EN,,0,0,0,,And we waved our hands, Dialogue: 0,0:47:32.75,0:47:34.59,EN,,0,0,0,,and said in principle, there's no storage needed. Dialogue: 0,0:47:35.04,0:47:36.17,EN,,0,0,0,,Now, you see no storage needed. Dialogue: 0,0:47:36.17,0:47:39.09,EN,,0,0,0,,Each of these is a real reduction, right? Dialogue: 0,0:47:39.09,0:47:42.60,EN,,0,0,0,,As you walk through these expressions, Dialogue: 0,0:47:47.30,0:47:50.51,EN,,0,0,0,,As you walk through these expressions, Dialogue: 0,0:47:50.83,0:47:51.37,EN,,0,0,0,,what you'll see Dialogue: 0,0:47:51.37,0:47:52.81,EN,,0,0,0,,are these expressions on the stack Dialogue: 0,0:47:53.75,0:47:55.64,EN,,0,0,0,,in some particular environment, Dialogue: 0,0:47:56.42,0:48:00.02,EN,,0,0,0,,and then these expressions, sorry, in the EXP register Dialogue: 0,0:48:00.02,0:48:01.50,EN,,0,0,0,,in some particular environment. Dialogue: 0,0:48:01.57,0:48:02.19,EN,,0,0,0,,And, at each point, Dialogue: 0,0:48:02.19,0:48:04.00,EN,,0,0,0,,there'll be no accumulated stuff on the stack Dialogue: 0,0:48:04.36,0:48:05.68,EN,,0,0,0,,because each one's a real reduction. Dialogue: 0,0:48:09.28,0:48:10.51,EN,,0,0,0,,All right, so, for example, Dialogue: 0,0:48:10.58,0:48:12.51,EN,,0,0,0,,just to go through it in a little bit more care, Dialogue: 0,0:48:13.46,0:48:16.88,EN,,0,0,0,,if I start out with an expression that says something like, Dialogue: 0,0:48:22.44,0:48:34.25,EN,,0,0,0,,oh, say, fact-iter of 5 in some environment Dialogue: 0,0:48:42.11,0:48:46.30,EN,,0,0,0,,that will, at some point, create an environment Dialogue: 0,0:48:46.81,0:48:48.38,EN,,0,0,0,,in which n is down to 5. Dialogue: 0,0:48:51.47,0:48:52.01,EN,,0,0,0,,Let's call that-- Dialogue: 0,0:48:55.68,0:48:56.59,EN,,0,0,0,,And, at some point, Dialogue: 0,0:48:56.89,0:49:02.56,EN,,0,0,0,,the machine will reduce this whole thing Dialogue: 0,0:49:02.91,0:49:04.35,EN,,0,0,0,,to a thing that says that's really Dialogue: 0,0:49:04.76,0:49:09.85,EN,,0,0,0,,iter of 1, and 1, and n, Dialogue: 0,0:49:10.68,0:49:13.72,EN,,0,0,0,,evaluated in this environment, E,1 Dialogue: 0,0:49:15.87,0:49:17.16,EN,,0,0,0,,with nothing on the stack. Dialogue: 0,0:49:17.16,0:49:19.55,EN,,0,0,0,,See, at this moment, the machine is not remembering Dialogue: 0,0:49:20.71,0:49:22.50,EN,,0,0,0,,that evaluating this expression, iter-- Dialogue: 0,0:49:25.00,0:49:25.63,EN,,0,0,0,,which is the loop-- Dialogue: 0,0:49:25.79,0:49:28.57,EN,,0,0,0,,is part of this thing called iterative factorial. Dialogue: 0,0:49:29.68,0:49:30.59,EN,,0,0,0,,It's not remembering that. Dialogue: 0,0:49:30.59,0:49:33.17,EN,,0,0,0,,It's just reducing the expression to that, right? Dialogue: 0,0:49:33.17,0:49:36.56,EN,,0,0,0,,If we look again at the body of iterative factorial, Dialogue: 0,0:49:38.05,0:49:41.08,EN,,0,0,0,,this expression has reduced to that expression. Dialogue: 0,0:49:42.81,0:49:43.87,EN,,0,0,0,,Oh, I shouldn't have the n there. Dialogue: 0,0:49:46.59,0:49:47.74,EN,,0,0,0,,It's a slightly different convention Dialogue: 0,0:49:47.74,0:49:49.13,EN,,0,0,0,,from the slide to the program. Dialogue: 0,0:49:53.34,0:49:56.25,EN,,0,0,0,,And, then, what's the body of iter? Dialogue: 0,0:49:56.28,0:49:57.40,EN,,0,0,0,,Well, iter's going to be an if, Dialogue: 0,0:49:58.75,0:50:00.19,EN,,0,0,0,,and I won't go through the details of if. Dialogue: 0,0:50:00.24,0:50:01.63,EN,,0,0,0,,It'll evaluate the predicate. Dialogue: 0,0:50:02.40,0:50:03.71,EN,,0,0,0,,In this case, it'll be false. Dialogue: 0,0:50:03.81,0:50:08.64,EN,,0,0,0,,And this iter will now reduce to the expression Dialogue: 0,0:50:09.85,0:50:20.20,EN,,0,0,0,,iter of whatever it says, star, counter product, and-- Dialogue: 0,0:50:21.62,0:50:22.24,EN,,0,0,0,,what does it say-- Dialogue: 0,0:50:22.68,0:50:24.56,EN,,0,0,0,,plus counter 1 Dialogue: 0,0:50:28.72,0:50:31.42,EN,,0,0,0,,in some other environment, by this time, E,2, Dialogue: 0,0:50:32.97,0:50:35.98,EN,,0,0,0,,where E,2 will be set up having bindings Dialogue: 0,0:50:36.49,0:50:39.39,EN,,0,0,0,,for product and counter. Dialogue: 0,0:50:42.92,0:50:44.33,EN,,0,0,0,,And it'll reduce to that. Dialogue: 0,0:50:44.94,0:50:46.04,EN,,0,0,0,,Right? It won't be remembering Dialogue: 0,0:50:46.06,0:50:48.75,EN,,0,0,0,,that it's part of something that it has to return to. Dialogue: 0,0:50:49.34,0:50:50.43,EN,,0,0,0,,And when iter calls iter again, Dialogue: 0,0:50:50.44,0:50:52.56,EN,,0,0,0,,it'll reduce to another thing that looks like this Dialogue: 0,0:50:53.05,0:50:54.68,EN,,0,0,0,,in some environment, E,3, Dialogue: 0,0:50:54.83,0:50:56.67,EN,,0,0,0,,which has new bindings for product and counter. Dialogue: 0,0:50:58.80,0:51:05.29,EN,,0,0,0,,OK? So, if you're wondering, Dialogue: 0,0:51:06.09,0:51:07.53,EN,,0,0,0,,if you've always been queasy about Dialogue: 0,0:51:08.25,0:51:10.67,EN,,0,0,0,,about how it is we've been saying those procedures Dialogue: 0,0:51:10.67,0:51:12.45,EN,,0,0,0,,that look syntactically recursive, Dialogue: 0,0:51:13.20,0:51:15.69,EN,,0,0,0,,are, in fact, iterative, Dialogue: 0,0:51:15.87,0:51:17.24,EN,,0,0,0,,run in constant space, Dialogue: 0,0:51:18.40,0:51:19.75,EN,,0,0,0,,well, I don't know if this makes you less queasy, Dialogue: 0,0:51:19.75,0:51:21.23,EN,,0,0,0,,but at least it shows you what's happening. Dialogue: 0,0:51:21.23,0:51:22.81,EN,,0,0,0,,There really isn't any buildup there. Dialogue: 0,0:51:25.91,0:51:27.58,EN,,0,0,0,,Now, you might ask well, is there buildup Dialogue: 0,0:51:27.98,0:51:30.08,EN,,0,0,0,,in principle in these environment frames? Dialogue: 0,0:51:31.71,0:51:32.37,EN,,0,0,0,,And the answer is yeah, Dialogue: 0,0:51:32.40,0:51:33.84,EN,,0,0,0,,you have to make these new environment frames, Dialogue: 0,0:51:33.84,0:51:35.26,EN,,0,0,0,,but you don't have to hang onto them Dialogue: 0,0:51:35.42,0:51:36.19,EN,,0,0,0,,when you're done. Dialogue: 0,0:51:36.44,0:51:37.61,EN,,0,0,0,,They can be garbage collected, Dialogue: 0,0:51:37.92,0:51:39.47,EN,,0,0,0,,or the space can be reused automatically. Dialogue: 0,0:51:40.72,0:51:42.99,EN,,0,0,0,,But you see the control structure of the evaluator Dialogue: 0,0:51:43.25,0:51:46.12,EN,,0,0,0,,is really using this idea that you actually have a reduction, Dialogue: 0,0:51:47.02,0:51:49.29,EN,,0,0,0,,so these procedures really are iterative procedures. Dialogue: 0,0:51:50.13,0:51:51.38,EN,,0,0,0,,All right, let's stop for questions. Dialogue: 0,0:52:02.68,0:52:03.23,EN,,0,0,0,,All right, let's break. Dialogue: 0,0:52:04.12,0:52:24.56,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:52:24.60,0:52:29.69,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:52:35.20,0:52:38.36,EN,,0,0,0,,By: Prof. Harold Abelson && Sussman Jay Sussman Dialogue: 0,0:52:38.36,0:52:42.14,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:52:48.77,0:52:51.55,EN,,0,0,0,,PROFESSOR: Let me contrast the iterative procedure Dialogue: 0,0:52:52.77,0:52:54.89,EN,,0,0,0,,just so you'll see where space does build up Dialogue: 0,0:52:55.12,0:52:56.14,EN,,0,0,0,,with a recursive procedure, Dialogue: 0,0:52:56.17,0:52:57.29,EN,,0,0,0,,so you can see the difference. Dialogue: 0,0:52:58.03,0:53:01.20,EN,,0,0,0,,Let's look at the evaluation of recursive factorial. Dialogue: 0,0:53:02.65,0:53:05.53,EN,,0,0,0,,So, here's fact-recursive, Dialogue: 0,0:53:05.55,0:53:07.22,EN,,0,0,0,,or standard factorial definition. Dialogue: 0,0:53:07.22,0:53:10.01,EN,,0,0,0,,We said this one is still a recursive procedure, Dialogue: 0,0:53:10.01,0:53:12.57,EN,,0,0,0,,but this is actually a recursive process. Dialogue: 0,0:53:13.75,0:53:16.56,EN,,0,0,0,,And then, just to link it back to the way we started, Dialogue: 0,0:53:16.83,0:53:20.53,EN,,0,0,0,,we said oh, you can see that it's going to be recursive process Dialogue: 0,0:53:20.53,0:53:21.82,EN,,0,0,0,,by the substitution model Dialogue: 0,0:53:22.36,0:53:28.00,EN,,0,0,0,,because, if I say recursive factorial of 5, Dialogue: 0,0:53:30.45,0:53:34.94,EN,,0,0,0,,that turns into 5 times-- Dialogue: 0,0:53:36.28,0:53:37.82,EN,,0,0,0,,what is it, fact-rec, or record fact-- Dialogue: 0,0:53:42.62,0:53:47.93,EN,,0,0,0,,5 times recursive factorial of 4, Dialogue: 0,0:53:49.66,0:53:58.22,EN,,0,0,0,,which turns into 5 times 4 times fact-rec of 3, Dialogue: 0,0:54:00.22,0:54:08.60,EN,,0,0,0,,which returns into 5 times 4 times 3 times Dialogue: 0,0:54:13.45,0:54:15.31,EN,,0,0,0,,and so on, right? Dialogue: 0,0:54:15.39,0:54:17.39,EN,,0,0,0,,The idea is there was this chain of stuff building up, Dialogue: 0,0:54:18.10,0:54:20.06,EN,,0,0,0,,which justified, in the substitution model, Dialogue: 0,0:54:20.08,0:54:21.28,EN,,0,0,0,,the fact that it's recursive. Dialogue: 0,0:54:21.52,0:54:24.18,EN,,0,0,0,,And now, let's actually see that chain of stuff build up Dialogue: 0,0:54:24.18,0:54:25.29,EN,,0,0,0,,and where it is in the machine, OK? Dialogue: 0,0:54:27.68,0:54:29.95,EN,,0,0,0,,All right, well, let's imagine we're going to start out again. Dialogue: 0,0:54:30.44,0:54:40.01,EN,,0,0,0,,We'll tell it to evaluate recursive factorial of 5 Dialogue: 0,0:54:41.45,0:54:43.39,EN,,0,0,0,,in some environment, again, E0, where Dialogue: 0,0:54:45.08,0:54:48.97,EN,,0,0,0,,where recursive factorial is defined, OK? Dialogue: 0,0:54:49.55,0:54:51.23,EN,,0,0,0,,Well, now we know what's eventually going to happen. Dialogue: 0,0:54:52.25,0:54:53.64,EN,,0,0,0,,This is going to come along, Dialogue: 0,0:54:53.92,0:54:55.64,EN,,0,0,0,,it'll evaluate those things, Dialogue: 0,0:54:55.68,0:54:56.99,EN,,0,0,0,,figure out it's a procedure, Dialogue: 0,0:54:57.18,0:55:00.16,EN,,0,0,0,,build somewhere over here an environment, E1, Dialogue: 0,0:55:00.88,0:55:03.69,EN,,0,0,0,,which has n bound to 5, Dialogue: 0,0:55:04.33,0:55:06.54,EN,,0,0,0,,which hangs off of E0, Dialogue: 0,0:55:07.80,0:55:08.97,EN,,0,0,0,,which would be, presumably, Dialogue: 0,0:55:08.99,0:55:12.30,EN,,0,0,0,,the definition environment of recursive factorial. Dialogue: 0,0:55:14.11,0:55:15.74,EN,,0,0,0,,OK? And, in this environment, Dialogue: 0,0:55:15.76,0:55:17.48,EN,,0,0,0,,it's going to go off and evaluate the body. Dialogue: 0,0:55:19.67,0:55:25.92,EN,,0,0,0,,So, again, the evaluation here will reduce to Dialogue: 0,0:55:27.00,0:55:28.92,EN,,0,0,0,,evaluating the body in E1. Dialogue: 0,0:55:30.16,0:55:31.34,EN,,0,0,0,,That's going to look at an if, Dialogue: 0,0:55:32.17,0:55:33.53,EN,,0,0,0,,and I won't go through the details of if. Dialogue: 0,0:55:33.53,0:55:34.88,EN,,0,0,0,,It'll look at the predicate. Dialogue: 0,0:55:34.88,0:55:37.53,EN,,0,0,0,,It'll decide it eventually has to evaluate the alternative. Dialogue: 0,0:55:37.84,0:55:40.41,EN,,0,0,0,,So this whole thing, again, will reduce to Dialogue: 0,0:55:41.30,0:55:45.53,EN,,0,0,0,,the alternative of recursive factorial, Dialogue: 0,0:55:45.82,0:55:46.97,EN,,0,0,0,,the alternative clause, Dialogue: 0,0:55:47.23,0:55:51.16,EN,,0,0,0,,which says that this whole thing reduces to times n Dialogue: 0,0:55:53.07,0:55:59.96,EN,,0,0,0,,of recursive factorial of n minus 1 Dialogue: 0,0:56:03.48,0:56:05.55,EN,,0,0,0,,in the environment E1 Dialogue: 0,0:56:08.38,0:56:10.91,EN,,0,0,0,,OK? So the original expression, now, is going to reduce Dialogue: 0,0:56:11.04,0:56:12.52,EN,,0,0,0,,to evaluating that expression, all right? Dialogue: 0,0:56:13.75,0:56:16.28,EN,,0,0,0,,OK? Now we have an application. Dialogue: 0,0:56:16.28,0:56:17.63,EN,,0,0,0,,We did an application before. Dialogue: 0,0:56:18.22,0:56:20.25,EN,,0,0,0,,Remember what happens in an application? Dialogue: 0,0:56:20.36,0:56:21.69,EN,,0,0,0,,The first thing you do is you go off and you Dialogue: 0,0:56:21.74,0:56:24.81,EN,,0,0,0,,you save the value of the continue register on the stack. Dialogue: 0,0:56:25.35,0:56:27.18,EN,,0,0,0,,So the stack here is going to have done in it. Dialogue: 0,0:56:29.98,0:56:32.88,EN,,0,0,0,,And then you're going to set up to evaluate the sub-parts. Dialogue: 0,0:56:35.00,0:56:37.20,EN,,0,0,0,,OK? So here we go off to evaluate the sub-parts. Dialogue: 0,0:56:39.47,0:56:41.45,EN,,0,0,0,,First thing we're going to do is evaluate the operator. Dialogue: 0,0:56:44.60,0:56:46.32,EN,,0,0,0,,What happens when we evaluate an operator? Dialogue: 0,0:56:47.25,0:56:48.99,EN,,0,0,0,,Well, we arrange things so that Dialogue: 0,0:56:49.00,0:56:51.04,EN,,0,0,0,,the operator ends up in the expression register. Dialogue: 0,0:56:51.48,0:56:53.15,EN,,0,0,0,,The environments in the ENV register Dialogue: 0,0:56:53.66,0:56:54.60,EN,,0,0,0,,continue someplace Dialogue: 0,0:56:54.62,0:56:56.22,EN,,0,0,0,,where we're going to go evaluate the arguments. Dialogue: 0,0:56:56.59,0:56:57.37,EN,,0,0,0,,And, on the stack, Dialogue: 0,0:56:57.40,0:56:59.29,EN,,0,0,0,,we've saved the original continue, Dialogue: 0,0:56:59.52,0:57:01.02,EN,,0,0,0,,which is where we wanted to be when we're all done. Dialogue: 0,0:57:01.72,0:57:02.86,EN,,0,0,0,,And then the things we needed Dialogue: 0,0:57:03.58,0:57:05.80,EN,,0,0,0,,when we're going to get done evaluating the operator, Dialogue: 0,0:57:05.90,0:57:07.66,EN,,0,0,0,,the things we'll need to evaluate the arguments, Dialogue: 0,0:57:07.69,0:57:12.01,EN,,0,0,0,,namely the environment and those arguments, Dialogue: 0,0:57:12.14,0:57:13.44,EN,,0,0,0,,those unevaluated arguments, Dialogue: 0,0:57:14.20,0:57:15.62,EN,,0,0,0,,so there they are sitting on the stack. Dialogue: 0,0:57:15.62,0:57:18.59,EN,,0,0,0,,And we're about to go off to evaluate the operator. Dialogue: 0,0:57:23.26,0:57:26.73,EN,,0,0,0,,Well, when we return from this particular call-- Dialogue: 0,0:57:26.92,0:57:28.64,EN,,0,0,0,,so we're about to call eval-dispatch here-- Dialogue: 0,0:57:29.38,0:57:30.83,EN,,0,0,0,,when we return from this call, Dialogue: 0,0:57:31.45,0:57:32.70,EN,,0,0,0,,the value of that operator, Dialogue: 0,0:57:32.73,0:57:33.52,EN,,0,0,0,,which, in this case, Dialogue: 0,0:57:33.55,0:57:35.44,EN,,0,0,0,,is going to be the primitive multiplier procedure, Dialogue: 0,0:57:36.44,0:57:37.93,EN,,0,0,0,,will end up in the FUN register. Dialogue: 0,0:57:43.02,0:57:44.53,EN,,0,0,0,,We're going to evaluate some arguments. Dialogue: 0,0:57:44.53,0:57:45.85,EN,,0,0,0,,They will evaluate n here. Dialogue: 0,0:57:47.73,0:57:49.87,EN,,0,0,0,,That'll give us 5, in this case. Dialogue: 0,0:57:50.25,0:57:52.04,EN,,0,0,0,,We're going to put that in the argl register, Dialogue: 0,0:57:53.00,0:57:55.88,EN,,0,0,0,,and then we'll go off to evaluate the second operand. Dialogue: 0,0:57:57.46,0:58:00.48,EN,,0,0,0,,So, at the point where we go off to evaluate the second operand-- Dialogue: 0,0:58:00.52,0:58:02.19,EN,,0,0,0,,and I'll skip details like computing, Dialogue: 0,0:58:02.20,0:58:03.58,EN,,0,0,0,,N minus 1, and all of that-- Dialogue: 0,0:58:03.71,0:58:05.88,EN,,0,0,0,,but, when we go off to evaluate the second operand, Dialogue: 0,0:58:06.62,0:58:10.44,EN,,0,0,0,,that will eventually reduce to another call to fact-recursive. Dialogue: 0,0:58:12.00,0:58:14.20,EN,,0,0,0,,And, what we've got on the stack here is Dialogue: 0,0:58:16.52,0:58:19.94,EN,,0,0,0,,the operator from that combination that we're going to use it in Dialogue: 0,0:58:20.12,0:58:21.07,EN,,0,0,0,,and the other argument. Dialogue: 0,0:58:23.40,0:58:27.61,EN,,0,0,0,,OK? So, now, we're set up for another call Dialogue: 0,0:58:28.49,0:58:29.69,EN,,0,0,0,,to recursive factorial. Dialogue: 0,0:58:30.20,0:58:31.43,EN,,0,0,0,,And, when we're done with this one, Dialogue: 0,0:58:31.56,0:58:33.64,EN,,0,0,0,,we're going to go to accumulate the last arg. Dialogue: 0,0:58:34.12,0:58:35.20,EN,,0,0,0,,and remember what that'll do? Dialogue: 0,0:58:35.20,0:58:35.93,EN,,0,0,0,,That'll say oh, Dialogue: 0,0:58:36.45,0:58:39.28,EN,,0,0,0,,whatever the result of this has to get combined with that, Dialogue: 0,0:58:39.28,0:58:40.40,EN,,0,0,0,,and we're going to multiply them. Dialogue: 0,0:58:41.69,0:58:42.38,EN,,0,0,0,,But, notice now, Dialogue: 0,0:58:42.73,0:58:44.81,EN,,0,0,0,,we're at another recursive factorial. Dialogue: 0,0:58:45.72,0:58:48.92,EN,,0,0,0,,We're about to call eval-dispatch again, Dialogue: 0,0:58:49.32,0:58:50.60,EN,,0,0,0,,except we haven't really reduced it Dialogue: 0,0:58:50.64,0:58:52.08,EN,,0,0,0,,because there's stuff on the stack now. Dialogue: 0,0:58:53.70,0:58:55.39,EN,,0,0,0,,The stuff on the stack says oh, when you get back, Dialogue: 0,0:58:55.40,0:58:57.52,EN,,0,0,0,,you'd better multiply it by the 5 you had hanging there. Dialogue: 0,0:58:58.43,0:59:05.77,EN,,0,0,0,,So, when we go off to make another call, Dialogue: 0,0:59:07.12,0:59:08.84,EN,,0,0,0,,we evaluate the n minus 1. Dialogue: 0,0:59:09.30,0:59:11.05,EN,,0,0,0,,That gives us another environment which Dialogue: 0,0:59:11.25,0:59:13.84,EN,,0,0,0,,in which the new n's going to be down to 4. Dialogue: 0,0:59:14.60,0:59:16.22,EN,,0,0,0,,And we're about to call eval-dispatch again. Dialogue: 0,0:59:19.20,0:59:20.22,EN,,0,0,0,,We get another call. Dialogue: 0,0:59:21.35,0:59:24.44,EN,,0,0,0,,That 4 is going to end up in the same situation. Dialogue: 0,0:59:26.04,0:59:28.62,EN,,0,0,0,,We'll end up with another call to fact-recursive n. Dialogue: 0,0:59:30.02,0:59:32.68,EN,,0,0,0,,And sitting on the stack will be the stuff from the original one Dialogue: 0,0:59:32.88,0:59:34.51,EN,,0,0,0,,and, now, the subsidiary one we're doing. Dialogue: 0,0:59:35.36,0:59:36.91,EN,,0,0,0,,And both of them are waiting for the same thing. Dialogue: 0,0:59:36.91,0:59:39.16,EN,,0,0,0,,They're going to go to accumulate a last argument. Dialogue: 0,0:59:40.51,0:59:42.94,EN,,0,0,0,,And then, of course, when we go to the fourth call, Dialogue: 0,0:59:43.25,0:59:44.38,EN,,0,0,0,,the same thing happens. Dialogue: 0,0:59:45.64,0:59:47.07,EN,,0,0,0,,And this goes on, and on, and on. Dialogue: 0,0:59:47.30,0:59:48.60,EN,,0,0,0,,And what you see here on the stack, Dialogue: 0,0:59:50.30,0:59:52.22,EN,,0,0,0,,exactly what's sitting here on the stack, Dialogue: 0,0:59:52.22,0:59:54.59,EN,,0,0,0,,the thing that says times and 5. Dialogue: 0,0:59:54.96,0:59:56.40,EN,,0,0,0,,And what you're going to do with that Dialogue: 0,0:59:56.59,0:59:58.54,EN,,0,0,0,,accumulate that into a last argument. Dialogue: 0,1:00:00.47,1:00:02.01,EN,,0,0,0,,That's exactly this, right? Dialogue: 0,1:00:02.01,1:00:04.75,EN,,0,0,0,,This is exactly where that stuff is hanging. Dialogue: 0,1:00:05.65,1:00:10.65,EN,,0,0,0,,Effectively, the operator you're going to apply, Dialogue: 0,1:00:11.72,1:00:14.30,EN,,0,0,0,,the other argument that it's got Dialogue: 0,1:00:14.32,1:00:15.79,EN,,0,0,0,,to be multiplied by when you get back Dialogue: 0,1:00:15.80,1:00:16.91,EN,,0,0,0,,and sort of the parentheses, Dialogue: 0,1:00:16.94,1:00:18.96,EN,,0,0,0,,which says yeah, what you wanted to do was accumulate them. Dialogue: 0,1:00:19.62,1:00:21.88,EN,,0,0,0,,So, you see, the substitution model is not such a lie. Dialogue: 0,1:00:22.56,1:00:23.63,EN,,0,0,0,,That really is, in some sense, Dialogue: 0,1:00:23.64,1:00:25.31,EN,,0,0,0,,what's sitting right on the stack. Dialogue: 0,1:00:29.37,1:00:30.40,EN,,0,0,0,,All right, so that, Dialogue: 0,1:00:30.81,1:00:32.48,EN,,0,0,0,,in some sense, should explain for you, Dialogue: 0,1:00:33.26,1:00:34.52,EN,,0,0,0,,or at least convince you, Dialogue: 0,1:00:35.93,1:00:38.72,EN,,0,0,0,,that somehow, this evaluator is managing Dialogue: 0,1:00:40.06,1:00:42.86,EN,,0,0,0,,to take these procedures and execute some of them iteratively Dialogue: 0,1:00:42.95,1:00:44.25,EN,,0,0,0,,and some of them recursively, Dialogue: 0,1:00:45.26,1:00:47.45,EN,,0,0,0,,even though, as syntactically, Dialogue: 0,1:00:47.45,1:00:49.05,EN,,0,0,0,,they look like recursive procedures. Dialogue: 0,1:00:49.40,1:00:50.64,EN,,0,0,0,,How's it managing to do that? Dialogue: 0,1:00:50.66,1:00:53.72,EN,,0,0,0,,Well, the basic reason it's managing to do that Dialogue: 0,1:00:53.80,1:00:55.68,EN,,0,0,0,,is the evaluator is set up Dialogue: 0,1:00:56.04,1:00:59.26,EN,,0,0,0,,to save only what it needs later. Dialogue: 0,1:01:01.09,1:01:04.25,EN,,0,0,0,,So, for example, at the point where you've reduced Dialogue: 0,1:01:04.67,1:01:07.39,EN,,0,0,0,,evaluating an expression and an environment Dialogue: 0,1:01:07.87,1:01:09.87,EN,,0,0,0,,to applying a procedure to some arguments, Dialogue: 0,1:01:10.52,1:01:12.49,EN,,0,0,0,,it doesn't need that original environment anymore Dialogue: 0,1:01:13.37,1:01:16.65,EN,,0,0,0,,because any environment stuff will be packaged inside the procedures Dialogue: 0,1:01:17.88,1:01:19.36,EN,,0,0,0,,where the application's going to happen. Dialogue: 0,1:01:20.75,1:01:21.61,EN,,0,0,0,,All right, similarly, Dialogue: 0,1:01:21.63,1:01:23.65,EN,,0,0,0,,when you're going along evaluating an argument list, Dialogue: 0,1:01:23.65,1:01:25.20,EN,,0,0,0,,when you've finished evaluating the list, Dialogue: 0,1:01:25.91,1:01:28.03,EN,,0,0,0,,when you're finished evaluating the last argument, Dialogue: 0,1:01:28.20,1:01:31.61,EN,,0,0,0,,you don't need that argument list any more, right? Dialogue: 0,1:01:31.63,1:01:32.94,EN,,0,0,0,,And you don't need the environment where Dialogue: 0,1:01:33.04,1:01:34.64,EN,,0,0,0,,those arguments would be evaluated. Dialogue: 0,1:01:36.69,1:01:40.89,EN,,0,0,0,,So the basic reason that this interpreter is being so smart Dialogue: 0,1:01:40.89,1:01:42.88,EN,,0,0,0,,is that it's not being smart at all, it's being stupid. Dialogue: 0,1:01:43.05,1:01:45.74,EN,,0,0,0,,It's just saying I'm only going to save what I really need. Dialogue: 0,1:01:48.70,1:01:51.00,EN,,0,0,0,,Well, let me show you here. Dialogue: 0,1:01:53.07,1:01:57.20,EN,,0,0,0,,Here's the actual thing that's making a tail recursive. Dialogue: 0,1:01:58.31,1:02:00.20,EN,,0,0,0,,Remember, it's the restore of continue. Dialogue: 0,1:02:00.22,1:02:06.94,EN,,0,0,0,,It's saying when I go off to evaluate the procedure body, Dialogue: 0,1:02:08.96,1:02:11.00,EN,,0,0,0,,I should tell eval to come back to Dialogue: 0,1:02:11.25,1:02:12.54,EN,,0,0,0,,the place where that original Dialogue: 0,1:02:12.54,1:02:14.25,EN,,0,0,0,,evaluation was supposed to come back to. Dialogue: 0,1:02:15.17,1:02:15.95,EN,,0,0,0,,So, in some sense, Dialogue: 0,1:02:16.17,1:02:18.84,EN,,0,0,0,,you want to say what's the actual line that makes tail recursive Dialogue: 0,1:02:18.89,1:02:19.44,EN,,0,0,0,,It's that one. Dialogue: 0,1:02:19.92,1:02:21.53,EN,,0,0,0,,If I wanted to build a non- Dialogue: 0,1:02:21.77,1:02:24.80,EN,,0,0,0,,tail recursive evaluator, for some strange reason, Dialogue: 0,1:02:25.69,1:02:26.86,EN,,0,0,0,,all I would need to do Dialogue: 0,1:02:27.12,1:02:29.29,EN,,0,0,0,,is, instead of restoring continue at this point, Dialogue: 0,1:02:30.06,1:02:31.66,EN,,0,0,0,,I'd set up a label down here Dialogue: 0,1:02:32.75,1:02:36.25,EN,,0,0,0,,called, "Where to come back after you've finished applying the procedure." Dialogue: 0,1:02:37.64,1:02:39.71,EN,,0,0,0,,Instead, I'd set continue to that. Dialogue: 0,1:02:39.92,1:02:41.21,EN,,0,0,0,,I'd go to eval-dispatch, Dialogue: 0,1:02:41.40,1:02:43.21,EN,,0,0,0,,and then eval-dispatch would come back here. Dialogue: 0,1:02:43.79,1:02:44.30,EN,,0,0,0,,At that point, Dialogue: 0,1:02:44.32,1:02:45.28,EN,,0,0,0,,I would restore continue Dialogue: 0,1:02:45.29,1:02:46.52,EN,,0,0,0,,and go to the original one. Dialogue: 0,1:02:47.92,1:02:51.00,EN,,0,0,0,,So here, the only consequence of that Dialogue: 0,1:02:51.15,1:02:52.68,EN,,0,0,0,,would be to make it non-tail recursive. Dialogue: 0,1:02:52.84,1:02:54.62,EN,,0,0,0,,It would give you exactly the same answers, Dialogue: 0,1:02:54.72,1:02:57.02,EN,,0,0,0,,except if you did that iterative factorial Dialogue: 0,1:02:57.05,1:02:58.36,EN,,0,0,0,,and all those iterative procedures, Dialogue: 0,1:02:58.60,1:02:59.80,EN,,0,0,0,,it would execute recursively. Dialogue: 0,1:03:03.04,1:03:05.40,EN,,0,0,0,,Well, I lied to you a little bit, but just a little bit, Dialogue: 0,1:03:05.76,1:03:06.99,EN,,0,0,0,,because I showed you a slightly Dialogue: 0,1:03:07.02,1:03:08.33,EN,,0,0,0,,over-simplified evaluator Dialogue: 0,1:03:08.72,1:03:10.38,EN,,0,0,0,,where it assumes that each procedure -- Dialogue: 0,1:03:11.36,1:03:13.66,EN,,0,0,0,,each procedure body has only one expression. Dialogue: 0,1:03:13.89,1:03:14.54,EN,,0,0,0,,Remember, in general, Dialogue: 0,1:03:14.56,1:03:16.57,EN,,0,0,0,,a procedure has a sequence of expressions in it. Dialogue: 0,1:03:17.87,1:03:20.49,EN,,0,0,0,,So there's nothing really conceptually new. Dialogue: 0,1:03:20.49,1:03:22.28,EN,,0,0,0,,Let me just show you the actual evaluator Dialogue: 0,1:03:22.89,1:03:24.73,EN,,0,0,0,,that handles sequences of expressions. Dialogue: 0,1:03:28.47,1:03:29.74,EN,,0,0,0,,This is compound-apply now, Dialogue: 0,1:03:29.74,1:03:31.31,EN,,0,0,0,,and the only difference from the old one Dialogue: 0,1:03:32.07,1:03:34.33,EN,,0,0,0,,is that, instead of going off to eval directly, Dialogue: 0,1:03:35.98,1:03:38.03,EN,,0,0,0,,it takes the whole body of the procedure, Dialogue: 0,1:03:38.03,1:03:40.15,EN,,0,0,0,,which, in this case, is a sequence of expressions, Dialogue: 0,1:03:40.28,1:03:41.71,EN,,0,0,0,,and goes off to eval-sequence. Dialogue: 0,1:03:42.60,1:03:45.32,EN,,0,0,0,,And eval-sequence is a little loop Dialogue: 0,1:03:46.83,1:03:49.98,EN,,0,0,0,,that, basically, does these evaluations one at a time. Dialogue: 0,1:03:52.63,1:03:53.85,EN,,0,0,0,,So it does an evaluation. Dialogue: 0,1:03:53.90,1:03:54.94,EN,,0,0,0,,Says oh, when I come back, Dialogue: 0,1:03:54.97,1:03:56.86,EN,,0,0,0,,I'd better come back here to do the next one. Dialogue: 0,1:03:58.44,1:03:59.29,EN,,0,0,0,,And, when I'm all done, Dialogue: 0,1:03:59.29,1:04:01.02,EN,,0,0,0,,when I want to get the last expression, Dialogue: 0,1:04:01.31,1:04:03.28,EN,,0,0,0,,I just restore my continue Dialogue: 0,1:04:03.92,1:04:05.28,EN,,0,0,0,,and go off to eval-dispatch. Dialogue: 0,1:04:06.41,1:04:08.20,EN,,0,0,0,,And, again, if you wanted for some reason Dialogue: 0,1:04:08.20,1:04:10.35,EN,,0,0,0,,to break tail recursion in this evaluator, Dialogue: 0,1:04:10.64,1:04:13.71,EN,,0,0,0,,all you need to do is not handle the last expression, especially. Dialogue: 0,1:04:14.90,1:04:17.34,EN,,0,0,0,,Just say, after you've done the last expression, Dialogue: 0,1:04:17.36,1:04:18.65,EN,,0,0,0,,come back to some other place Dialogue: 0,1:04:19.15,1:04:20.68,EN,,0,0,0,,after which you restore continue. Dialogue: 0,1:04:21.90,1:04:23.26,EN,,0,0,0,,And, for some reason, Dialogue: 0,1:04:23.26,1:04:25.74,EN,,0,0,0,,a lot of LISP evaluators tended to work that way. Dialogue: 0,1:04:26.55,1:04:28.44,EN,,0,0,0,,And the only consequence of that is that Dialogue: 0,1:04:28.86,1:04:30.72,EN,,0,0,0,,iterative procedures built up stack. Dialogue: 0,1:04:31.88,1:04:33.61,EN,,0,0,0,,And it's not clear why that happened. Dialogue: 0,1:04:35.92,1:04:37.98,EN,,0,0,0,,All right. Well, let me just sort of summarize, Dialogue: 0,1:04:38.09,1:04:39.60,EN,,0,0,0,,since this is a lot of details Dialogue: 0,1:04:39.98,1:04:41.04,EN,,0,0,0,,in a big program. Dialogue: 0,1:04:41.12,1:04:42.25,EN,,0,0,0,,But the main point is that Dialogue: 0,1:04:43.04,1:04:43.87,EN,,0,0,0,,it's no different, Dialogue: 0,1:04:44.04,1:04:46.08,EN,,0,0,0,,conceptually, from translating any other program. Dialogue: 0,1:04:47.06,1:04:48.06,EN,,0,0,0,,And the main idea is that Dialogue: 0,1:04:48.06,1:04:50.28,EN,,0,0,0,,we have this universal evaluator program, Dialogue: 0,1:04:50.33,1:04:51.71,EN,,0,0,0,,the meta-circular evaluator. Dialogue: 0,1:04:51.87,1:04:53.07,EN,,0,0,0,,If we translate that into LISP, Dialogue: 0,1:04:53.10,1:04:53.95,EN,,0,0,0,,then we have all of LISP. Dialogue: 0,1:04:54.33,1:04:55.15,EN,,0,0,0,,And that's all we did. Dialogue: 0,1:04:57.98,1:04:59.68,EN,,0,0,0,,The second point is that the magic's gone away. Dialogue: 0,1:04:59.68,1:05:01.97,EN,,0,0,0,,There should be no more magic in this whole system, right? Dialogue: 0,1:05:01.97,1:05:07.79,EN,,0,0,0,,In principle, it should all be very clear Dialogue: 0,1:05:07.82,1:05:10.08,EN,,0,0,0,,except, maybe, for how list structured memory works, Dialogue: 0,1:05:10.80,1:05:11.80,EN,,0,0,0,,and we'll see that later. Dialogue: 0,1:05:12.64,1:05:14.20,EN,,0,0,0,,But that's not very hard. Dialogue: 0,1:05:15.45,1:05:16.35,EN,,0,0,0,,The third point is that Dialogue: 0,1:05:16.35,1:05:17.52,EN,,0,0,0,,all this tail recursion Dialogue: 0,1:05:18.24,1:05:21.96,EN,,0,0,0,,came from the discipline of eval being very careful Dialogue: 0,1:05:22.55,1:05:24.51,EN,,0,0,0,,to save only what it needs next time. Dialogue: 0,1:05:25.87,1:05:27.72,EN,,0,0,0,,It's not some arbitrary thing Dialogue: 0,1:05:27.76,1:05:29.86,EN,,0,0,0,,where we're saying well, whenever we call a sub-routine, Dialogue: 0,1:05:29.86,1:05:32.16,EN,,0,0,0,,we'll save all the registers in the world and come back? Dialogue: 0,1:05:33.94,1:05:36.49,EN,,0,0,0,,See, sometimes it pays to really worry about efficiency. Dialogue: 0,1:05:37.15,1:05:39.96,EN,,0,0,0,,And, when you're down in the guts of your evaluator machine, Dialogue: 0,1:05:40.45,1:05:42.56,EN,,0,0,0,,it really pays to think about things like that Dialogue: 0,1:05:42.56,1:05:43.96,EN,,0,0,0,,because it makes big consequences. Dialogue: 0,1:05:45.23,1:05:47.69,EN,,0,0,0,,Well, I hope what this has done Dialogue: 0,1:05:47.90,1:05:52.30,EN,,0,0,0,,is really made the evaluator seem concrete. Dialogue: 0,1:05:52.56,1:05:53.90,EN,,0,0,0,,I hope you really believe Dialogue: 0,1:05:54.32,1:05:56.27,EN,,0,0,0,,that somebody could hold a LISP Dialogue: 0,1:05:56.84,1:05:58.56,EN,,0,0,0,,LISP evaluator in the palm of their hand. Dialogue: 0,1:05:59.07,1:06:00.49,EN,,0,0,0,,Maybe to help you believe that, here's a Dialogue: 0,1:06:00.80,1:06:01.96,EN,,0,0,0,,here's a LISP evaluator Dialogue: 0,1:06:02.54,1:06:04.06,EN,,0,0,0,,that I'm holding the palm of my hand. Dialogue: 0,1:06:06.16,1:06:10.56,EN,,0,0,0,,And this is a chip which is actually Dialogue: 0,1:06:10.89,1:06:13.70,EN,,0,0,0,,quite a bit more complicated than the evaluator I showed you. Dialogue: 0,1:06:16.86,1:06:19.20,EN,,0,0,0,,Uh.. maybe, here's a better picture of it. Dialogue: 0,1:06:22.07,1:06:22.57,EN,,0,0,0,,What there is, Dialogue: 0,1:06:22.60,1:06:24.38,EN,,0,0,0,,is you can see the same overall structure. Dialogue: 0,1:06:24.73,1:06:25.93,EN,,0,0,0,,This is a register array. Dialogue: 0,1:06:26.80,1:06:27.71,EN,,0,0,0,,These are the data paths. Dialogue: 0,1:06:27.72,1:06:29.07,EN,,0,0,0,,Here's a finite state controller. Dialogue: 0,1:06:29.80,1:06:31.04,EN,,0,0,0,,And again, finite state, Dialogue: 0,1:06:31.96,1:06:32.80,EN,,0,0,0,,that's all there is. Dialogue: 0,1:06:32.81,1:06:34.16,EN,,0,0,0,,And somewhere there's external memory Dialogue: 0,1:06:34.16,1:06:35.23,EN,,0,0,0,,that'll worry about things. Dialogue: 0,1:06:35.75,1:06:37.63,EN,,0,0,0,,And this particular one is very complicated Dialogue: 0,1:06:37.64,1:06:39.16,EN,,0,0,0,,because it's trying to run LISP fast. Dialogue: 0,1:06:39.66,1:06:42.97,EN,,0,0,0,,And it has some very, very fast parallel operations in there Dialogue: 0,1:06:43.07,1:06:46.32,EN,,0,0,0,,like, if you want to index into an array, Dialogue: 0,1:06:46.70,1:06:50.40,EN,,0,0,0,,simultaneously check that the index is an integer, Dialogue: 0,1:06:50.43,1:06:52.86,EN,,0,0,0,,check that it doesn't exceed the array bands, Dialogue: 0,1:06:53.04,1:06:55.02,EN,,0,0,0,,and go off and do the memory access, Dialogue: 0,1:06:55.05,1:06:56.70,EN,,0,0,0,,and do all those things simultaneously. Dialogue: 0,1:06:57.12,1:06:58.40,EN,,0,0,0,,And then, later, if they're all OK, Dialogue: 0,1:06:58.44,1:06:59.96,EN,,0,0,0,,actually get the value there. Dialogue: 0,1:07:00.42,1:07:02.46,EN,,0,0,0,,So there are a lot of complicated operations Dialogue: 0,1:07:02.48,1:07:04.65,EN,,0,0,0,,in these data paths for making LISP run in parallel. Dialogue: 0,1:07:05.26,1:07:08.41,EN,,0,0,0,,It's a completely non-risk Dialogue: 0,1:07:08.76,1:07:10.36,EN,,0,0,0,,philosophy of evaluating LISP. Dialogue: 0,1:07:10.64,1:07:13.20,EN,,0,0,0,,And then, this microcode is pretty complicated. Dialogue: 0,1:07:13.45,1:07:17.56,EN,,0,0,0,,Let's see, there's what? Dialogue: 0,1:07:17.60,1:07:21.10,EN,,0,0,0,,There's about 389 instructions of Dialogue: 0,1:07:21.68,1:07:23.85,EN,,0,0,0,,of 220-bit microcode sitting here Dialogue: 0,1:07:24.07,1:07:27.94,EN,,0,0,0,,because these are very complicated data paths. Dialogue: 0,1:07:27.94,1:07:32.25,EN,,0,0,0,,And the whole thing has about 89,000 transistors, OK? Dialogue: 0,1:07:33.56,1:07:36.86,EN,,0,0,0,,OK. Well, I hope that that takes away a lot of the mystery. Dialogue: 0,1:07:37.97,1:07:39.24,EN,,0,0,0,,Maybe somebody wants to look at this. Dialogue: 0,1:07:46.14,1:07:46.89,EN,,0,0,0,,OK. Let's stop. Dialogue: 0,1:07:56.46,1:07:56.75,EN,,0,0,0,,Questions? Dialogue: 0,1:07:59.00,1:08:00.42,EN,,0,0,0,,AUDIENCE: OK, now, it sounds like what you're saying is that, Dialogue: 0,1:08:00.42,1:08:03.48,EN,,0,0,0,,with the restore continue put in the proper place, Dialogue: 0,1:08:03.58,1:08:09.42,EN,,0,0,0,,that procedures that would invoke a recursive process Dialogue: 0,1:08:09.42,1:08:11.95,EN,,0,0,0,,now invoke an iterative process Dialogue: 0,1:08:12.67,1:08:15.36,EN,,0,0,0,,just by the way that the eval-sequence source? Dialogue: 0,1:08:15.60,1:08:17.54,EN,,0,0,0,,PROFESSOR: I think the way I'd prefer to put it is that, Dialogue: 0,1:08:17.54,1:08:19.82,EN,,0,0,0,,with restore continue put in the wrong place, Dialogue: 0,1:08:20.55,1:08:25.48,EN,,0,0,0,,you can cause any syntactically-looking recursive procedure, Dialogue: 0,1:08:25.52,1:08:27.28,EN,,0,0,0,,in fact, to build up stack as it runs. Dialogue: 0,1:08:28.64,1:08:30.52,EN,,0,0,0,,But there's no reason for that, Dialogue: 0,1:08:33.15,1:08:35.12,EN,,0,0,0,,so you might want to play around with it. Dialogue: 0,1:08:35.15,1:08:38.09,EN,,0,0,0,,You can just switch around two or three instructions Dialogue: 0,1:08:38.18,1:08:40.78,EN,,0,0,0,,in the way compound-apply comes back, Dialogue: 0,1:08:41.31,1:08:43.26,EN,,0,0,0,,and you'll get something which isn't tail recursive. Dialogue: 0,1:08:45.06,1:08:46.14,EN,,0,0,0,,But the thing I wanted to emphasize Dialogue: 0,1:08:46.16,1:08:47.40,EN,,0,0,0,,is there's no magic. there's no Dialogue: 0,1:08:47.67,1:08:48.57,EN,,0,0,0,,It's not as if Dialogue: 0,1:08:49.31,1:08:52.17,EN,,0,0,0,,there's some very clever pre-processing program Dialogue: 0,1:08:52.65,1:08:55.45,EN,,0,0,0,,that's looking at this procedure, factorial iter, Dialogue: 0,1:08:55.47,1:08:56.73,EN,,0,0,0,,and say oh, gee, um Dialogue: 0,1:08:57.42,1:08:58.86,EN,,0,0,0,,I really notice that Dialogue: 0,1:08:58.88,1:09:01.13,EN,,0,0,0,,I don't have to push stack in order to do this. Dialogue: 0,1:09:01.13,1:09:02.88,EN,,0,0,0,,Some people think that that's what's going on. Dialogue: 0,1:09:03.76,1:09:05.38,EN,,0,0,0,,It's something much, much more dumb than that, Dialogue: 0,1:09:05.38,1:09:07.50,EN,,0,0,0,,it's this one place you're putting the restore instruction. Dialogue: 0,1:09:08.56,1:09:09.79,EN,,0,0,0,,It's just automatic. Dialogue: 0,1:09:14.72,1:09:17.55,EN,,0,0,0,,AUDIENCE: But that's not affecting the time complexity is it? Dialogue: 0,1:09:17.58,1:09:17.87,EN,,0,0,0,,PROFESSOR: No. Dialogue: 0,1:09:18.60,1:09:21.77,EN,,0,0,0,,AUDIENCE: It's just that it's handling it recursively Dialogue: 0,1:09:21.80,1:09:23.02,EN,,0,0,0,,instead of iteratively. Dialogue: 0,1:09:23.02,1:09:27.34,EN,,0,0,0,,But, in terms of the order of time it takes to finish the operation, Dialogue: 0,1:09:27.37,1:09:29.22,EN,,0,0,0,,it's the same one way or the other, right? Dialogue: 0,1:09:29.47,1:09:29.76,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,1:09:29.79,1:09:32.68,EN,,0,0,0,,Tail recursion is not going to change the time complexity of anything Dialogue: 0,1:09:32.72,1:09:33.29,EN,,0,0,0,,because, in some sense, Dialogue: 0,1:09:33.34,1:09:35.15,EN,,0,0,0,,it's the same algorithm that's going on. Dialogue: 0,1:09:36.02,1:09:39.37,EN,,0,0,0,,What it's doing is really making this thing run as an iteration. Dialogue: 0,1:09:41.00,1:09:42.64,EN,,0,0,0,,Right? Not going to run out of memory Dialogue: 0,1:09:42.68,1:09:44.22,EN,,0,0,0,,you know counting up to a giant number Dialogue: 0,1:09:44.75,1:09:46.40,EN,,0,0,0,,simply because the stack would get pushed. Dialogue: 0,1:09:48.35,1:09:50.24,EN,,0,0,0,,See, the thing you really have to believe is that, Dialogue: 0,1:09:50.56,1:09:51.13,EN,,0,0,0,,when we write-- Dialogue: 0,1:09:51.64,1:09:53.78,EN,,0,0,0,,see, we've been writing all these things called iterations, Dialogue: 0,1:09:53.93,1:09:57.99,EN,,0,0,0,,infinite loops, define loop to be called loop. Dialogue: 0,1:10:00.32,1:10:03.36,EN,,0,0,0,,That's is as much an iteration Dialogue: 0,1:10:03.65,1:10:05.66,EN,,0,0,0,,you know as if we wrote do forever loop. Dialogue: 0,1:10:07.63,1:10:09.28,EN,,0,0,0,,It's just syntactic sugar as the difference. Dialogue: 0,1:10:09.28,1:10:11.32,EN,,0,0,0,,These things are real, honest to god, iterations? Dialogue: 0,1:10:14.73,1:10:16.08,EN,,0,0,0,,They don't change the time complexity, Dialogue: 0,1:10:16.11,1:10:18.53,EN,,0,0,0,,but they turn them into real iterations. Dialogue: 0,1:10:21.68,1:10:23.80,EN,,0,0,0,,All right, thank you. Dialogue: 0,0:00:00.03,0:00:00.97,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP 学习小组\N倾情制作 Dialogue: 0,0:00:01.05,0:00:09.09,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:01.05,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N刘殊君 Dialogue: 0,0:00:01.05,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:01.05,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:01.05,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:09.21,0:00:13.12,Declare,,0,0,0,,{\an2\fad(500,500)}显示控制求值器 Dialogue: 0,0:00:16.30,0:00:18.08,Default,,0,0,0,,教授:我想大家已经意识到 Dialogue: 0,0:00:20.01,0:00:22.73,Default,,0,0,0,,我们介绍了一些真正的魔法 Dialogue: 0,0:00:24.20,0:00:27.24,Default,,0,0,0,,创造新语言的魔法 Dialogue: 0,0:00:27.42,0:00:28.72,Default,,0,0,0,,用来创造全新的语言 Dialogue: 0,0:00:29.69,0:00:30.40,Default,,0,0,0,,我们学了些什么? Dialogue: 0,0:00:30.43,0:00:32.78,Default,,0,0,0,,我们学习了一门用来操作图片的Escher的语言 Dialogue: 0,0:00:38.92,0:00:41.15,Default,,0,0,0,,这门语言由Peter Henderson发明 Dialogue: 0,0:00:42.01,0:00:46.49,Default,,0,0,0,,我们还学习了数字逻辑语言 Dialogue: 0,0:00:53.16,0:00:55.55,Default,,0,0,0,,以及 我们还学习了查询语言 Dialogue: 0,0:00:59.70,0:01:00.78,Default,,0,0,0,,然而你需要明白的是 Dialogue: 0,0:01:00.81,0:01:03.10,Default,,0,0,0,,尽管它们都是“玩具级”的语言示例 Dialogue: 0,0:01:04.70,0:01:07.61,Default,,0,0,0,,但也确实是实用工具的核心 Dialogue: 0,0:01:08.25,0:01:09.48,Default,,0,0,0,,比如说 Dialogue: 0,0:01:10.12,0:01:11.18,Default,,0,0,0,,Escher图片语言 Dialogue: 0,0:01:11.20,0:01:14.33,Default,,0,0,0,,就被MIT的学生Henry Wu拿去 Dialogue: 0,0:01:14.88,0:01:16.43,Default,,0,0,0,,开发成了一门用于 Dialogue: 0,0:01:16.97,0:01:19.45,Default,,0,0,0,,为电路板布局的语言 Dialogue: 0,0:01:20.35,0:01:22.56,Default,,0,0,0,,它就是在这些结构上扩展而来 Dialogue: 0,0:01:23.24,0:01:24.65,Default,,0,0,0,,至于数字逻辑语言 Dialogue: 0,0:01:24.68,0:01:26.08,Default,,0,0,0,,Gerry教授在上课的时候也提到过 Dialogue: 0,0:01:26.43,0:01:29.92,Default,,0,0,0,,它被扩展为了一个仿真器的基础 Dialogue: 0,0:01:30.85,0:01:32.96,Default,,0,0,0,,用来设计真实的计算机 Dialogue: 0,0:01:33.46,0:01:34.32,Default,,0,0,0,,至于查询语言 Dialogue: 0,0:01:34.35,0:01:36.44,Default,,0,0,0,,当然就是Prolog语言的一种核心 Dialogue: 0,0:01:37.51,0:01:39.07,Default,,0,0,0,,我们构造的这些语言 Dialogue: 0,0:01:39.55,0:01:40.65,Default,,0,0,0,,全都是用Lisp编写 Dialogue: 0,0:01:43.63,0:01:44.59,Default,,0,0,0,,很多人问 Dialogue: 0,0:01:45.27,0:01:48.73,Default,,0,0,0,,Lisp适合用来解决哪一类问题? Dialogue: 0,0:01:48.75,0:01:49.93,Default,,0,0,0,,答案就是 Dialogue: 0,0:01:50.33,0:01:52.65,Default,,0,0,0,,Lisp不适合解决任何一类问题 Dialogue: 0,0:01:53.53,0:01:54.60,Default,,0,0,0,,Lisp擅长的是 Dialogue: 0,0:01:54.73,0:01:57.15,Default,,0,0,0,,用它来构造一门合适的语言 Dialogue: 0,0:01:57.18,0:01:58.57,Default,,0,0,0,,来解决你的问题 Dialogue: 0,0:01:59.17,0:02:00.44,Default,,0,0,0,,你应该像这样看待Lisp Dialogue: 0,0:02:01.47,0:02:03.39,Default,,0,0,0,,那么既然这些语言都基于Lisp Dialogue: 0,0:02:04.57,0:02:05.72,Default,,0,0,0,,那Lisp又基于什么? Dialogue: 0,0:02:06.97,0:02:07.88,Default,,0,0,0,,它又从何而来? Dialogue: 0,0:02:07.90,0:02:09.40,Default,,0,0,0,,这个我们也学过 Dialogue: 0,0:02:09.58,0:02:16.09,Default,,0,0,0,,我们学过元循环求值器 Dialogue: 0,0:02:21.53,0:02:23.40,Default,,0,0,0,,学习了元循环求值器后 我们说 Dialogue: 0,0:02:23.42,0:02:25.76,Default,,0,0,0,,Lisp就是基于Lisp的 Dialogue: 0,0:02:25.80,0:02:27.48,Default,,0,0,0,,而当我们研究它的时候 Dialogue: 0,0:02:28.27,0:02:29.95,Default,,0,0,0,,我们必须得施展一些真正的魔法 对吧? Dialogue: 0,0:02:29.95,0:02:31.74,Default,,0,0,0,,这又是什么意思呢? Dialogue: 0,0:02:31.74,0:02:34.96,Default,,0,0,0,,Y算子、不动点 Dialogue: 0,0:02:35.76,0:02:38.33,Default,,0,0,0,,以及这样的一个观念-- Dialogue: 0,0:02:38.36,0:02:41.44,Default,,0,0,0,,Lisp实际上是一个方程的不动点 Dialogue: 0,0:02:42.20,0:02:45.42,Default,,0,0,0,,一个通过自身来定义的有趣方程 Dialogue: 0,0:02:47.40,0:02:48.56,Default,,0,0,0,,这确实是神奇的魔法 Dialogue: 0,0:02:49.07,0:02:52.35,Default,,0,0,0,,那么今天 作为魔法的最后一步 Dialogue: 0,0:02:52.62,0:02:54.03,Default,,0,0,0,,我们要把它们通通消除掉 Dialogue: 0,0:03:06.80,0:03:07.98,Default,,0,0,0,,我们已经知道怎么做了 Dialogue: 0,0:03:09.77,0:03:10.76,Default,,0,0,0,,核心要思想是 Dialogue: 0,0:03:11.13,0:03:12.73,Default,,0,0,0,,将Lisp语言 Dialogue: 0,0:03:13.36,0:03:15.50,Default,,0,0,0,,实现在使用寄存器架构的机器上 Dialogue: 0,0:03:15.50,0:03:17.93,Default,,0,0,0,,回想一下 寄存器机器的关键之处在于 Dialogue: 0,0:03:19.60,0:03:24.68,Default,,0,0,0,,机器的一部分是确定且有穷的 Dialogue: 0,0:03:24.72,0:03:26.12,Default,,0,0,0,,它有一个有穷状态控制器 Dialogue: 0,0:03:26.12,0:03:27.87,Default,,0,0,0,,它用特定的硬件 Dialogue: 0,0:03:27.88,0:03:29.31,Default,,0,0,0,,去完成特定的事情 Dialogue: 0,0:03:30.51,0:03:31.74,Default,,0,0,0,,其中还有一些运算所需的 Dialogue: 0,0:03:31.76,0:03:33.24,Default,,0,0,0,,特殊数据通路 Dialogue: 0,0:03:33.55,0:03:35.29,Default,,0,0,0,,然后 为了实现递归 Dialogue: 0,0:03:35.53,0:03:37.60,Default,,0,0,0,,并且维持无穷的假象 Dialogue: 0,0:03:37.82,0:03:39.77,Default,,0,0,0,,还使用了一种称作“栈”的大内存 Dialogue: 0,0:03:42.06,0:03:43.72,Default,,0,0,0,,所以如果我们在 Dialogue: 0,0:03:43.92,0:03:45.50,Default,,0,0,0,,寄存器机器上实现了Lisp Dialogue: 0,0:03:47.02,0:03:48.35,Default,,0,0,0,,那么这个时候 Dialogue: 0,0:03:48.40,0:03:49.85,Default,,0,0,0,,所有的东西都会完全具体化 Dialogue: 0,0:03:49.85,0:03:51.23,Default,,0,0,0,,所有的魔法都会消除 Dialogue: 0,0:03:51.65,0:03:53.52,Default,,0,0,0,,这堂课结束时 Dialogue: 0,0:03:53.53,0:03:54.78,Default,,0,0,0,,我想让你感觉到 Dialogue: 0,0:03:55.14,0:03:59.05,Default,,0,0,0,,相对于神秘的元循环求值器 Dialogue: 0,0:03:59.67,0:04:02.60,Default,,0,0,0,,Lisp求值器是非常具体的东西 Dialogue: 0,0:04:02.85,0:04:04.57,Default,,0,0,0,,你甚至可以把它放在手心中 Dialogue: 0,0:04:04.76,0:04:06.24,Default,,0,0,0,,你可以想象一下 Dialogue: 0,0:04:06.57,0:04:07.90,Default,,0,0,0,,手里拿着一个Lisp解释器的情景 Dialogue: 0,0:04:09.63,0:04:10.94,Default,,0,0,0,,好 那我们怎么做呢? Dialogue: 0,0:04:10.95,0:04:12.76,Default,,0,0,0,,所有的原料都已经齐全 Dialogue: 0,0:04:13.96,0:04:17.45,Default,,0,0,0,,上节课Gerry教了你们 Dialogue: 0,0:04:17.60,0:04:21.47,Default,,0,0,0,,对一个任意的Lisp过程 Dialogue: 0,0:04:22.60,0:04:24.28,Default,,0,0,0,,如何手动地把它们 Dialogue: 0,0:04:24.75,0:04:26.67,Default,,0,0,0,,翻译成在寄存器机器上运行的代码 Dialogue: 0,0:04:28.20,0:04:30.52,Default,,0,0,0,,那么 要在寄存器机器上实现Lisp本身 Dialogue: 0,0:04:30.57,0:04:31.44,Default,,0,0,0,,我们只需要 Dialogue: 0,0:04:31.69,0:04:33.45,Default,,0,0,0,,把最关键的过程 Dialogue: 0,0:04:33.68,0:04:35.42,Default,,0,0,0,,也就是元循环求值器 Dialogue: 0,0:04:36.17,0:04:38.11,Default,,0,0,0,,手工翻译成寄存器机器的代码 Dialogue: 0,0:04:39.04,0:04:40.25,Default,,0,0,0,,这就实现了整个Lisp Dialogue: 0,0:04:42.14,0:04:43.00,Default,,0,0,0,,因此 我们已经知道了 Dialogue: 0,0:04:43.02,0:04:44.43,Default,,0,0,0,,实现的原理 Dialogue: 0,0:04:45.38,0:04:46.54,Default,,0,0,0,,而且实际上 Dialogue: 0,0:04:46.68,0:04:48.86,Default,,0,0,0,,这跟翻译 Dialogue: 0,0:04:50.00,0:04:53.40,Default,,0,0,0,,递归版的阶乘或斐波那契数列 Dialogue: 0,0:04:53.42,0:04:54.67,Default,,0,0,0,,没什么区别 Dialogue: 0,0:04:54.67,0:04:56.00,Default,,0,0,0,,只是它规模更大 代码更多 Dialogue: 0,0:04:56.84,0:04:58.03,Default,,0,0,0,,只是包含了更多细节 Dialogue: 0,0:04:58.04,0:04:59.66,Default,,0,0,0,,但是没有任何新的概念 Dialogue: 0,0:05:01.48,0:05:03.02,Default,,0,0,0,,当我们完成这个以后 Dialogue: 0,0:05:03.08,0:05:04.76,Default,,0,0,0,,所有的东西都变得明确了 Dialogue: 0,0:05:04.87,0:05:06.91,Default,,0,0,0,,当我们看到如何用一系列的 Dialogue: 0,0:05:06.94,0:05:10.08,Default,,0,0,0,,寄存器操作来实现Lisp之后 Dialogue: 0,0:05:10.16,0:05:11.63,Default,,0,0,0,,它就成为了我们整个课程中 Dialogue: 0,0:05:11.95,0:05:14.16,Default,,0,0,0,,最明确的Lisp模型 Dialogue: 0,0:05:14.81,0:05:16.95,Default,,0,0,0,,回忆一下 这个过程贯穿了整个课程 Dialogue: 0,0:05:16.95,0:05:18.25,Default,,0,0,0,,我们先从代换模型开始 Dialogue: 0,0:05:18.28,0:05:19.58,Default,,0,0,0,,它和代数有点相似 Dialogue: 0,0:05:20.24,0:05:21.87,Default,,0,0,0,,然后学习了环境模型 Dialogue: 0,0:05:21.88,0:05:24.00,Default,,0,0,0,,它引入了“框架”的概念 Dialogue: 0,0:05:24.03,0:05:25.31,Default,,0,0,0,,以及框架之间的关联 Dialogue: 0,0:05:26.32,0:05:27.88,Default,,0,0,0,,然后我们在元循环求值器中 Dialogue: 0,0:05:27.90,0:05:29.36,Default,,0,0,0,,把它变得更具体了 Dialogue: 0,0:05:31.05,0:05:31.64,Default,,0,0,0,,但是有的事情 Dialogue: 0,0:05:31.87,0:05:33.98,Default,,0,0,0,,元循环求值器没有告诉我们 Dialogue: 0,0:05:34.36,0:05:35.34,Default,,0,0,0,,你应该认识到这点 Dialogue: 0,0:05:36.09,0:05:38.64,Default,,0,0,0,,比如说 我们还不知道 Dialogue: 0,0:05:38.73,0:05:42.67,Default,,0,0,0,,像这里的递归阶乘过程 Dialogue: 0,0:05:45.17,0:05:47.13,Default,,0,0,0,,为何不断地申请新的空间 Dialogue: 0,0:05:47.21,0:05:47.98,Default,,0,0,0,,另一方面 Dialogue: 0,0:05:48.16,0:05:51.94,Default,,0,0,0,,一个语法上看起来像是递归的过程 Dialogue: 0,0:05:52.11,0:05:55.07,Default,,0,0,0,,比如FACT-ITER 并不占用栈空间 Dialogue: 0,0:05:55.10,0:05:59.16,Default,,0,0,0,,我们通过代换模型来证明 Dialogue: 0,0:06:00.50,0:06:01.96,Default,,0,0,0,,它不占用空间 Dialogue: 0,0:06:01.96,0:06:02.94,Default,,0,0,0,,但我们并没有说清楚 Dialogue: 0,0:06:03.42,0:06:06.76,Default,,0,0,0,,机器是如何做到这一点的 Dialogue: 0,0:06:07.31,0:06:08.91,Default,,0,0,0,,这涉及到一些细节 Dialogue: 0,0:06:09.02,0:06:11.12,Default,,0,0,0,,比如参数是如何传递给过程的 Dialogue: 0,0:06:12.48,0:06:13.69,Default,,0,0,0,,这是我们在元循环求值器中 Dialogue: 0,0:06:13.71,0:06:15.34,Default,,0,0,0,,没有看到的 Dialogue: 0,0:06:15.36,0:06:17.40,Default,,0,0,0,,完全是因为在所实现的Lisp中 Dialogue: 0,0:06:17.42,0:06:19.20,Default,,0,0,0,,把参数传递给过程的方式 Dialogue: 0,0:06:19.70,0:06:20.59,Default,,0,0,0,,取决于 Dialogue: 0,0:06:21.02,0:06:23.50,Default,,0,0,0,,外部Lisp的传参方式 Dialogue: 0,0:06:25.87,0:06:29.02,Default,,0,0,0,,但现在 这一点将变得非常明确 Dialogue: 0,0:06:30.74,0:06:31.12,Default,,0,0,0,,好 Dialogue: 0,0:06:31.23,0:06:34.30,Default,,0,0,0,,在开始研究求值器之前 Dialogue: 0,0:06:34.36,0:06:35.53,Default,,0,0,0,,我先让你们感受一下 Dialogue: 0,0:06:35.55,0:06:37.00,Default,,0,0,0,,一个完整Lisp系统是怎么样的 Dialogue: 0,0:06:37.60,0:06:39.36,Default,,0,0,0,,这样你就可以知道 我们要讨论哪部分 Dialogue: 0,0:06:39.40,0:06:40.81,Default,,0,0,0,,不讨论哪些部分 Dialogue: 0,0:06:43.18,0:06:47.42,Default,,0,0,0,,首先 这里有一个快乐的Lisp用户 Dialogue: 0,0:06:48.67,0:06:52.65,Default,,0,0,0,,他正在和一个叫做读取器的东西交流 Dialogue: 0,0:07:00.36,0:07:01.53,Default,,0,0,0,,读取器的工作是 Dialogue: 0,0:07:01.95,0:07:13.23,Default,,0,0,0,,读取用户输入的字符串 Dialogue: 0,0:07:14.17,0:07:16.62,Default,,0,0,0,,把它们转化成一种称作 Dialogue: 0,0:07:17.20,0:07:19.37,Default,,0,0,0,,表结构内存的数据结构 Dialogue: 0,0:07:30.00,0:07:31.72,Default,,0,0,0,,读取器会读取-- Dialogue: 0,0:07:32.65,0:07:33.95,Default,,0,0,0,,你敲出来的符号、括号 Dialogue: 0,0:07:34.48,0:07:37.12,Default,,0,0,0,,A和B、1和3这些东西 Dialogue: 0,0:07:37.18,0:07:39.04,Default,,0,0,0,,并把它们变成表结构 Dialogue: 0,0:07:39.15,0:07:40.54,Default,,0,0,0,,变成序对、指针等等 Dialogue: 0,0:07:42.35,0:07:43.92,Default,,0,0,0,,所以当求值器运行的时候 Dialogue: 0,0:07:43.93,0:07:45.10,Default,,0,0,0,,环境里已经不存在原始字符了 Dialogue: 0,0:07:45.85,0:07:48.16,Default,,0,0,0,,当然 在更现代的Lisp系统中 Dialogue: 0,0:07:49.00,0:07:50.44,Default,,0,0,0,,可能还有一大团东西 Dialogue: 0,0:07:50.44,0:07:52.17,Default,,0,0,0,,存在于在读取器和用户之间 Dialogue: 0,0:07:52.41,0:07:54.52,Default,,0,0,0,,最顶层首先是视窗系统 Dialogue: 0,0:07:54.77,0:07:56.03,Default,,0,0,0,,以及鼠标之类的东西 Dialogue: 0,0:07:56.28,0:07:58.20,Default,,0,0,0,,但从概念上来说 都是在输入字符 Dialogue: 0,0:07:59.93,0:08:04.32,Default,,0,0,0,,总之 读取器把它们都变成指针 Dialogue: 0,0:08:05.56,0:08:07.28,Default,,0,0,0,,指向内存中的对象 Dialogue: 0,0:08:08.27,0:08:10.94,Default,,0,0,0,,这是求值器的所能看到的东西 Dialogue: 0,0:08:15.55,0:08:16.04,Default,,0,0,0,,明白吗? Dialogue: 0,0:08:17.02,0:08:18.88,Default,,0,0,0,,求值器有一些辅助函数 Dialogue: 0,0:08:19.78,0:08:23.16,Default,,0,0,0,,包括你需要的所有基本运算 Dialogue: 0,0:08:23.16,0:08:24.91,Default,,0,0,0,,也就是说这里另有一盒子东西 Dialogue: 0,0:08:28.40,0:08:30.25,Default,,0,0,0,,比如浮点单元 Dialogue: 0,0:08:32.22,0:08:34.40,Default,,0,0,0,,或者其它类似的东西来执行这些运算 Dialogue: 0,0:08:35.39,0:08:37.68,Default,,0,0,0,,如果你需要支持更多的基本运算 Dialogue: 0,0:08:37.71,0:08:39.02,Default,,0,0,0,,你就实现更多的运算符执行器 Dialogue: 0,0:08:39.05,0:08:40.48,Default,,0,0,0,,但它们和求值器都是分离的 Dialogue: 0,0:08:42.08,0:08:43.77,Default,,0,0,0,,求值器最终算出结果 Dialogue: 0,0:08:45.16,0:08:46.76,Default,,0,0,0,,并且把它们告诉打印程序 Dialogue: 0,0:08:50.62,0:08:52.01,Default,,0,0,0,,现在 打印程序的任务就是 Dialogue: 0,0:08:52.01,0:08:54.54,Default,,0,0,0,,从求值器取得这个表结构 Dialogue: 0,0:08:55.39,0:08:56.99,Default,,0,0,0,,再把它们变回字符 Dialogue: 0,0:09:01.85,0:09:04.07,Default,,0,0,0,,然后通过某种界面 Dialogue: 0,0:09:04.28,0:09:05.66,Default,,0,0,0,,展示给用户 Dialogue: 0,0:09:08.05,0:09:11.23,Default,,0,0,0,,那么 今天我们要讨论的是这个求值器 Dialogue: 0,0:09:12.67,0:09:15.20,Default,,0,0,0,,基本运算和Lisp没有什么特别的关系 Dialogue: 0,0:09:15.20,0:09:18.14,Default,,0,0,0,,它们只取决于你怎么实现基本运算 Dialogue: 0,0:09:19.36,0:09:22.18,Default,,0,0,0,,读取器和打印程序实际上很复杂 Dialogue: 0,0:09:22.18,0:09:23.55,Default,,0,0,0,,但是我们不去讨论它们 Dialogue: 0,0:09:24.68,0:09:27.10,Default,,0,0,0,,从字符构建表的过程中 Dialogue: 0,0:09:27.10,0:09:28.92,Default,,0,0,0,,它们需要处理很多细节 Dialogue: 0,0:09:29.90,0:09:31.18,Default,,0,0,0,,说来话长 Dialogue: 0,0:09:31.18,0:09:32.32,Default,,0,0,0,,我们就不讨论它了 Dialogue: 0,0:09:32.49,0:09:33.69,Default,,0,0,0,,关于表结构内存 Dialogue: 0,0:09:34.36,0:09:35.63,Default,,0,0,0,,我们下次再来讨论 Dialogue: 0,0:09:36.93,0:09:39.72,Default,,0,0,0,,那么去除了读取和打印的细节 Dialogue: 0,0:09:40.12,0:09:41.71,Default,,0,0,0,,关于这个求值器 Dialogue: 0,0:09:41.72,0:09:43.05,Default,,0,0,0,,所剩下的唯一谜团 Dialogue: 0,0:09:43.25,0:09:45.85,Default,,0,0,0,,几乎就只有怎么在传统内存上构建表结构了 Dialogue: 0,0:09:46.65,0:09:48.20,Default,,0,0,0,,不过我们把那也放到下次来讨论 Dialogue: 0,0:09:50.58,0:09:51.04,Default,,0,0,0,,好 Dialogue: 0,0:09:53.34,0:09:56.11,Default,,0,0,0,,那么 我们先来看看这个求值器 Dialogue: 0,0:09:56.20,0:09:58.32,Default,,0,0,0,,我将要展示的这个求值器 Dialogue: 0,0:09:58.49,0:10:01.12,Default,,0,0,0,,我想 它并没有什么特别的 Dialogue: 0,0:10:01.15,0:10:04.56,Default,,0,0,0,,它只是一台专门运行Lisp的寄存器机器 Dialogue: 0,0:10:04.81,0:10:06.09,Default,,0,0,0,,它有七个寄存器 Dialogue: 0,0:10:07.88,0:10:09.26,Default,,0,0,0,,这是它的七个寄存器 Dialogue: 0,0:10:09.89,0:10:12.38,Default,,0,0,0,,这个寄存器叫EXP Dialogue: 0,0:10:14.12,0:10:15.53,Default,,0,0,0,,它的任务是存放 Dialogue: 0,0:10:16.36,0:10:18.03,Default,,0,0,0,,将要被求值的表达式 Dialogue: 0,0:10:18.37,0:10:19.80,Default,,0,0,0,,具体来说 Dialogue: 0,0:10:20.38,0:10:21.64,Default,,0,0,0,,它存放的是一个指针 Dialogue: 0,0:10:22.03,0:10:23.55,Default,,0,0,0,,指针指向存放着求值的表达式 Dialogue: 0,0:10:23.56,0:10:25.32,Default,,0,0,0,,的一处表结构内存 Dialogue: 0,0:10:26.55,0:10:27.82,Default,,0,0,0,,还有一个叫做ENV的寄存器 Dialogue: 0,0:10:28.88,0:10:30.28,Default,,0,0,0,,它存放着环境 Dialogue: 0,0:10:31.00,0:10:33.05,Default,,0,0,0,,也就是表达式的求值环境 Dialogue: 0,0:10:34.07,0:10:35.02,Default,,0,0,0,,同样的 这也是一个指针 Dialogue: 0,0:10:35.02,0:10:36.75,Default,,0,0,0,,环境是一种数据结构 Dialogue: 0,0:10:38.24,0:10:40.14,Default,,0,0,0,,这个叫做FUN的寄存器-- Dialogue: 0,0:10:40.75,0:10:42.54,Default,,0,0,0,,当你在应用一个过程时 Dialogue: 0,0:10:42.57,0:10:43.96,Default,,0,0,0,,它会存放这个过程 Dialogue: 0,0:10:44.56,0:10:46.24,Default,,0,0,0,,还有寄存器ARGL Dialogue: 0,0:10:47.36,0:10:49.34,Default,,0,0,0,,它存放的是已求值的参数 Dialogue: 0,0:10:50.54,0:10:51.60,Default,,0,0,0,,从这里开始你能看到 Dialogue: 0,0:10:51.63,0:10:53.14,Default,,0,0,0,,求值器的基本构造 Dialogue: 0,0:10:53.14,0:10:54.49,Default,,0,0,0,,回忆一下它是怎么工作的 Dialogue: 0,0:10:54.49,0:10:56.62,Default,,0,0,0,,对这一块输入表达式和环境 Dialogue: 0,0:10:57.67,0:10:59.71,Default,,0,0,0,,而这一块接收函数 Dialogue: 0,0:10:59.74,0:11:02.14,Default,,0,0,0,,或者说 过程以及参数 Dialogue: 0,0:11:03.48,0:11:06.30,Default,,0,0,0,,EVAL-APPLY循环使用这些寄存器工作 Dialogue: 0,0:11:07.40,0:11:09.69,Default,,0,0,0,,所以这些是EVAL-APPLY的基本组成部分 Dialogue: 0,0:11:10.20,0:11:10.99,Default,,0,0,0,,还有一些别的东西 Dialogue: 0,0:11:11.00,0:11:11.61,Default,,0,0,0,,比如CONTINUE寄存器 Dialogue: 0,0:11:11.61,0:11:15.34,Default,,0,0,0,,你之前已经见过CONTINUE寄存器 Dialogue: 0,0:11:15.34,0:11:18.04,Default,,0,0,0,,是如何实现递归以及栈操作的 Dialogue: 0,0:11:18.94,0:11:20.68,Default,,0,0,0,,还有个寄存器用来存放 Dialogue: 0,0:11:20.94,0:11:22.52,Default,,0,0,0,,某个求值的结果 Dialogue: 0,0:11:24.14,0:11:24.89,Default,,0,0,0,,然后 除了这些以外 Dialogue: 0,0:11:24.89,0:11:26.43,Default,,0,0,0,,还有一个临时寄存器 Dialogue: 0,0:11:26.70,0:11:27.29,Default,,0,0,0,,它就是UNEV Dialogue: 0,0:11:27.29,0:11:29.04,Default,,0,0,0,,一般来讲 在求值器中 Dialogue: 0,0:11:29.28,0:11:32.72,Default,,0,0,0,,它是用来存放正在求值的表达式 Dialogue: 0,0:11:32.89,0:11:33.95,Default,,0,0,0,,的临时部分 Dialogue: 0,0:11:33.95,0:11:35.72,Default,,0,0,0,,就是那些尚未求值的部分 Dialogue: 0,0:11:36.97,0:11:39.82,Default,,0,0,0,,那么 这就是我的七寄存器机器 Dialogue: 0,0:11:40.96,0:11:42.98,Default,,0,0,0,,当然 你可能想造一台 Dialogue: 0,0:11:42.98,0:11:44.96,Default,,0,0,0,,有更多寄存器的机器 来取得更好性能 Dialogue: 0,0:11:44.97,0:11:47.05,Default,,0,0,0,,但我们这个只是一台小型机器 Dialogue: 0,0:11:48.48,0:11:49.58,Default,,0,0,0,,那么数据通路呢? Dialogue: 0,0:11:49.78,0:11:53.66,Default,,0,0,0,,这台机器有很多专为Lisp设计的运算 Dialogue: 0,0:11:55.10,0:11:58.08,Default,,0,0,0,,这里有几条典型的数据通路 Dialogue: 0,0:12:00.12,0:12:01.04,Default,,0,0,0,,其中一条可能是 Dialogue: 0,0:12:01.37,0:12:03.40,Default,,0,0,0,,将EXP寄存器的值 Dialogue: 0,0:12:03.40,0:12:04.80,Default,,0,0,0,,赋给VAL寄存器 Dialogue: 0,0:12:05.71,0:12:08.01,Default,,0,0,0,,用我们之前的数据通路图来说 Dialogue: 0,0:12:08.03,0:12:10.81,Default,,0,0,0,,就是一条箭头上的小按钮 Dialogue: 0,0:12:11.90,0:12:13.13,Default,,0,0,0,,这还有一个更复杂的 Dialogue: 0,0:12:13.69,0:12:14.80,Default,,0,0,0,,它判断 Dialogue: 0,0:12:15.23,0:12:19.58,Default,,0,0,0,,如果EXP寄存器的内容是COND语句 Dialogue: 0,0:12:20.49,0:12:22.72,Default,,0,0,0,,那么这里就会跳转到EV-COND标号处 Dialogue: 0,0:12:23.80,0:12:26.23,Default,,0,0,0,,你可以想象出很多种实现它的方法 Dialogue: 0,0:12:26.23,0:12:28.36,Default,,0,0,0,,你可以把这个判断看作是 Dialogue: 0,0:12:28.36,0:12:29.98,Default,,0,0,0,,一个特殊意图的子过程 Dialogue: 0,0:12:30.60,0:12:33.95,Default,,0,0,0,,而条件被表示成某种数据抽象 Dialogue: 0,0:12:33.96,0:12:36.00,Default,,0,0,0,,你在这个层面上不用考虑它 Dialogue: 0,0:12:36.61,0:12:37.98,Default,,0,0,0,,那么它可以用子过程实现 Dialogue: 0,0:12:37.98,0:12:40.67,Default,,0,0,0,,如果机器通过硬件来判断表达式类型 Dialogue: 0,0:12:40.90,0:12:44.04,Default,,0,0,0,,那么某些特定比特就代表了COND语句 Dialogue: 0,0:12:45.35,0:12:46.41,Default,,0,0,0,,有很多种实现办法 Dialogue: 0,0:12:46.41,0:12:48.48,Default,,0,0,0,,它们都低于我们关注的这一层抽象 Dialogue: 0,0:12:50.19,0:12:51.71,Default,,0,0,0,,然后还有另一种操作 Dialogue: 0,0:12:51.71,0:12:53.24,Default,,0,0,0,,以及其它很多操作 Dialogue: 0,0:12:53.24,0:12:56.65,Default,,0,0,0,,把EXP的第一个子句赋值给EXP Dialogue: 0,0:12:56.84,0:12:58.89,Default,,0,0,0,,这可能是处理COND语句的一部分 Dialogue: 0,0:12:59.26,0:13:01.80,Default,,0,0,0,,同样 FIRST-SELECTOR这个选择子 Dialogue: 0,0:13:03.07,0:13:04.48,Default,,0,0,0,,我们也不需要关心它的细节 Dialogue: 0,0:13:04.49,0:13:06.46,Default,,0,0,0,,同样可以把那也看成一个子过程 Dialogue: 0,0:13:06.46,0:13:07.90,Default,,0,0,0,,用来进行一些表操作 Dialogue: 0,0:13:08.22,0:13:09.18,Default,,0,0,0,,或者你也可以想象成 Dialogue: 0,0:13:09.18,0:13:10.73,Default,,0,0,0,,一个直接构建在硬件中的东西 Dialogue: 0,0:13:12.17,0:13:13.71,Default,,0,0,0,,我之所以强调 Dialogue: 0,0:13:14.03,0:13:15.22,Default,,0,0,0,,你可以把它想象成硬件直接实现 Dialogue: 0,0:13:15.22,0:13:17.80,Default,,0,0,0,,是因为尽管有很多的运算 Dialogue: 0,0:13:18.36,0:13:19.74,Default,,0,0,0,,但也它们的数量也是固定的 Dialogue: 0,0:13:20.12,0:13:21.80,Default,,0,0,0,,我记不清有多少 大概有150个 Dialogue: 0,0:13:22.37,0:13:25.39,Default,,0,0,0,,所以假设用硬件实现它们是合理的 Dialogue: 0,0:13:26.41,0:13:27.68,Default,,0,0,0,,而这一条更加复杂 Dialogue: 0,0:13:28.27,0:13:29.47,Default,,0,0,0,,你会发现 这条涉及到 Dialogue: 0,0:13:29.47,0:13:31.10,Default,,0,0,0,,查找变量的值 Dialogue: 0,0:13:31.50,0:13:33.28,Default,,0,0,0,,它会查找某条表达式中 Dialogue: 0,0:13:33.45,0:13:36.91,Default,,0,0,0,,某个变量的值 Dialogue: 0,0:13:36.99,0:13:38.52,Default,,0,0,0,,并赋值给VAL寄存器 Dialogue: 0,0:13:39.18,0:13:40.30,Default,,0,0,0,,在本例中 也就是 Dialogue: 0,0:13:40.33,0:13:42.00,Default,,0,0,0,,在某个环境中查找变量 Dialogue: 0,0:13:42.80,0:13:44.68,Default,,0,0,0,,然后这个操作 Dialogue: 0,0:13:45.21,0:13:47.50,Default,,0,0,0,,会搜索整个环境结构 Dialogue: 0,0:13:47.52,0:13:48.97,Default,,0,0,0,,无论环境是如何表示的 Dialogue: 0,0:13:49.37,0:13:50.91,Default,,0,0,0,,并查找该变量 Dialogue: 0,0:13:52.17,0:13:53.95,Default,,0,0,0,,同样 它也不在我们思考的 Dialogue: 0,0:13:53.96,0:13:54.86,Default,,0,0,0,,的抽象层面上 Dialogue: 0,0:13:54.89,0:13:57.30,Default,,0,0,0,,它需要处理的细节是 Dialogue: 0,0:13:57.55,0:13:59.44,Default,,0,0,0,,用来表示环境的数据结构 Dialogue: 0,0:14:00.07,0:14:01.21,Default,,0,0,0,,但是不管怎么说 Dialogue: 0,0:14:01.31,0:14:03.47,Default,,0,0,0,,这就是这台寄存器机器的 Dialogue: 0,0:14:04.11,0:14:06.08,Default,,0,0,0,,有穷数量的固定操作 Dialogue: 0,0:14:08.50,0:14:11.60,Default,,0,0,0,,那么 它的整体结构是什么样子的? Dialogue: 0,0:14:11.72,0:14:13.23,Default,,0,0,0,,这有几个典型的运算 Dialogue: 0,0:14:14.76,0:14:16.33,Default,,0,0,0,,想一想 我们要做什么 Dialogue: 0,0:14:16.44,0:14:18.40,Default,,0,0,0,,我们需要把元循环求值器 Dialogue: 0,0:14:20.43,0:14:22.76,Default,,0,0,0,,这就是元循环求值器的一部分 Dialogue: 0,0:14:22.76,0:14:26.89,Default,,0,0,0,,这是书中使用抽象代码的版本 Dialogue: 0,0:14:28.22,0:14:31.53,Default,,0,0,0,,它和Gerry教授给你们展示的有些不同 Dialogue: 0,0:14:33.50,0:14:35.10,Default,,0,0,0,,关于求值器 Dialogue: 0,0:14:35.13,0:14:37.87,Default,,0,0,0,,主要需要记住的是 Dialogue: 0,0:14:37.87,0:14:40.96,Default,,0,0,0,,它是某种针对表达式类型的分情况分析 Dialogue: 0,0:14:43.76,0:14:45.90,Default,,0,0,0,,看它是否为自求值的 或被引用的 Dialogue: 0,0:14:45.92,0:14:46.86,Default,,0,0,0,,或是别的什么 Dialogue: 0,0:14:48.56,0:14:50.57,Default,,0,0,0,,而在大部分情况下 Dialogue: 0,0:14:50.86,0:14:52.96,Default,,0,0,0,,它处理的是一个过程应用 Dialogue: 0,0:14:53.55,0:14:55.36,Default,,0,0,0,,那么里面有一些技巧性的递归过程 Dialogue: 0,0:14:55.75,0:14:59.36,Default,,0,0,0,,首先 EVAL要调用它自己 Dialogue: 0,0:14:59.79,0:15:01.45,Default,,0,0,0,,来求值运算符以及 Dialogue: 0,0:15:02.14,0:15:04.04,Default,,0,0,0,,所有的运算对象 Dialogue: 0,0:15:05.88,0:15:07.40,Default,,0,0,0,,因此这些标红线的地方 Dialogue: 0,0:15:07.63,0:15:09.28,Default,,0,0,0,,就是某种在语法树上的递归 Dialogue: 0,0:15:10.94,0:15:12.27,Default,,0,0,0,,这是很简单的递归 Dialogue: 0,0:15:12.27,0:15:14.44,Default,,0,0,0,,只是EVAL在递归地遍历语法树 Dialogue: 0,0:15:14.75,0:15:15.53,Default,,0,0,0,,然后在求值器中 Dialogue: 0,0:15:15.53,0:15:16.46,Default,,0,0,0,,有一个复杂的递归 Dialogue: 0,0:15:16.49,0:15:17.92,Default,,0,0,0,,由绿线到红线的递归 Dialogue: 0,0:15:18.00,0:15:19.66,Default,,0,0,0,,由EVAL调用APPLY Dialogue: 0,0:15:22.47,0:15:26.45,Default,,0,0,0,,也就是把过程调用 Dialogue: 0,0:15:26.45,0:15:28.72,Default,,0,0,0,,归约为了 将过程应用在 Dialogue: 0,0:15:28.94,0:15:29.93,Default,,0,0,0,,实参表上 Dialogue: 0,0:15:30.37,0:15:31.76,Default,,0,0,0,,然后请看APPLY Dialogue: 0,0:15:34.77,0:15:36.67,Default,,0,0,0,,APPLY需要过程PROC和参数ARGS Dialogue: 0,0:15:37.65,0:15:39.45,Default,,0,0,0,,一般情况下 Dialogue: 0,0:15:39.48,0:15:40.81,Default,,0,0,0,,PROC都是一个复合过程 Dialogue: 0,0:15:41.05,0:15:42.19,Default,,0,0,0,,随着APPLY不断被调用 Dialogue: 0,0:15:42.25,0:15:43.15,Default,,0,0,0,,绿线处会调用红线处 Dialogue: 0,0:15:43.34,0:15:46.44,Default,,0,0,0,,APPLY被调用并再次调用EVAL Dialogue: 0,0:15:48.17,0:15:49.79,Default,,0,0,0,,EVAL会求值过程体 Dialogue: 0,0:15:50.24,0:15:52.59,Default,,0,0,0,,基于一个扩展了的环境 Dialogue: 0,0:15:53.69,0:15:55.28,Default,,0,0,0,,这个环境通过将过程的形式参数 Dialogue: 0,0:15:55.48,0:15:56.92,Default,,0,0,0,,与实际参数绑定起来而得 Dialogue: 0,0:15:59.62,0:16:00.62,Default,,0,0,0,,而对于最基本的情况 Dialogue: 0,0:16:00.64,0:16:02.52,Default,,0,0,0,,它会调用PRIMITIVE-APPLY过程 Dialogue: 0,0:16:02.73,0:16:04.70,Default,,0,0,0,,而那又不是求值器的工作了 Dialogue: 0,0:16:05.98,0:16:07.47,Default,,0,0,0,,那么像这样从红到绿 Dialogue: 0,0:16:07.47,0:16:08.40,Default,,0,0,0,,又到红又到绿 Dialogue: 0,0:16:09.79,0:16:12.72,Default,,0,0,0,,这就是EVAL-APPLY循环 Dialogue: 0,0:16:14.06,0:16:15.74,Default,,0,0,0,,这就是我们在求值器中 Dialogue: 0,0:16:16.19,0:16:17.72,Default,,0,0,0,,想要看到的东西 Dialogue: 0,0:16:19.69,0:16:21.07,Default,,0,0,0,,这样 你不会惊异于 Dialogue: 0,0:16:21.07,0:16:23.52,Default,,0,0,0,,这个求值器的两大部分 Dialogue: 0,0:16:25.34,0:16:27.04,Default,,0,0,0,,对应于EVAL-APPLY Dialogue: 0,0:16:27.47,0:16:29.44,Default,,0,0,0,,一个部分叫EVAL-DISPATCH Dialogue: 0,0:16:29.60,0:16:31.20,Default,,0,0,0,,另一部分叫做APPLY-DISPATCH Dialogue: 0,0:16:32.00,0:16:34.09,Default,,0,0,0,,在我们关注代码细节之前 Dialogue: 0,0:16:34.20,0:16:35.76,Default,,0,0,0,,理解它们的方法就是 Dialogue: 0,0:16:36.09,0:16:39.02,Default,,0,0,0,,假设这些求值器的各个部分 Dialogue: 0,0:16:39.02,0:16:40.97,Default,,0,0,0,,和这个世界中其它的部分有一些约定 Dialogue: 0,0:16:41.87,0:16:43.18,Default,,0,0,0,,在进入这些肮脏的细节前 Dialogue: 0,0:16:43.20,0:16:45.50,Default,,0,0,0,,它们在外部做了什么? Dialogue: 0,0:16:45.78,0:16:49.32,Default,,0,0,0,,针对EVAL-DISPATCH的约定 Dialogue: 0,0:16:50.01,0:16:51.40,Default,,0,0,0,,还记得吗 它对应的是EVAL Dialogue: 0,0:16:51.55,0:16:54.10,Default,,0,0,0,,它要在环境中求值一个表达式 Dialogue: 0,0:16:54.10,0:16:55.88,Default,,0,0,0,,那么 这部分要做的就是 Dialogue: 0,0:16:56.52,0:16:58.68,Default,,0,0,0,,EVAL-DISPATCH会假设当你调用它的时候 Dialogue: 0,0:16:59.68,0:17:01.48,Default,,0,0,0,,你想要求值的表达式 Dialogue: 0,0:17:01.48,0:17:02.52,Default,,0,0,0,,就存放在EXP寄存器中 Dialogue: 0,0:17:03.64,0:17:07.39,Default,,0,0,0,,而求值所基于的环境 Dialogue: 0,0:17:07.45,0:17:09.05,Default,,0,0,0,,则存放在ENV环境中 Dialogue: 0,0:17:09.56,0:17:10.67,Default,,0,0,0,,而CONTINUE寄存器用来指示 Dialogue: 0,0:17:10.84,0:17:12.46,Default,,0,0,0,,当求值完成后 Dialogue: 0,0:17:12.52,0:17:13.92,Default,,0,0,0,,机器需要去向何方 Dialogue: 0,0:17:17.28,0:17:19.18,Default,,0,0,0,,EVAL-DISPATCH的约定实际上就是 Dialogue: 0,0:17:19.28,0:17:21.26,Default,,0,0,0,,它会执行实际的求值 Dialogue: 0,0:17:21.40,0:17:22.46,Default,,0,0,0,,并且在求值结束后 Dialogue: 0,0:17:23.28,0:17:25.63,Default,,0,0,0,,它会转到由CONTINUE寄存器指定的位置 Dialogue: 0,0:17:26.61,0:17:29.16,Default,,0,0,0,,求值的结果会存放在VAL寄存器中 Dialogue: 0,0:17:29.82,0:17:30.96,Default,,0,0,0,,需要提醒的是 Dialogue: 0,0:17:30.99,0:17:32.91,Default,,0,0,0,,它对其余的寄存器 Dialogue: 0,0:17:32.96,0:17:34.60,Default,,0,0,0,,不做任何承诺 Dialogue: 0,0:17:35.23,0:17:36.81,Default,,0,0,0,,其它所有的寄存器都可能被修改 Dialogue: 0,0:17:37.49,0:17:40.14,Default,,0,0,0,,那么这是一部分 Dialogue: 0,0:17:41.55,0:17:43.48,Default,,0,0,0,,这些部分一块构成了APPLY-DISPATCH Dialogue: 0,0:17:43.52,0:17:44.92,Default,,0,0,0,,它们对应了APPLY Dialogue: 0,0:17:46.09,0:17:48.43,Default,,0,0,0,,用来把一个过程应用在一些参数上 Dialogue: 0,0:17:48.73,0:17:51.43,Default,,0,0,0,,因此它假设ARGL寄存器 Dialogue: 0,0:17:51.68,0:17:53.77,Default,,0,0,0,,存放着求值后的参数列表 Dialogue: 0,0:17:54.54,0:17:55.96,Default,,0,0,0,,FUN寄存器存放着那个过程 Dialogue: 0,0:17:57.22,0:17:58.83,Default,,0,0,0,,它们对应于元循环求值器中的 Dialogue: 0,0:17:58.94,0:18:01.36,Default,,0,0,0,,参数应用部分 Dialogue: 0,0:18:03.97,0:18:06.04,Default,,0,0,0,,在我们的这个求值器中 Dialogue: 0,0:18:06.06,0:18:07.58,Default,,0,0,0,,我们APPLY时采用的约定是 Dialogue: 0,0:18:07.72,0:18:08.97,Default,,0,0,0,,当APPLY完成后-- Dialogue: 0,0:18:09.47,0:18:11.20,Default,,0,0,0,,机器应该跳转到 Dialogue: 0,0:18:11.79,0:18:13.45,Default,,0,0,0,,的下一个地方应该是 Dialogue: 0,0:18:13.55,0:18:15.92,Default,,0,0,0,,APPLY-DISPATCH被调用时的栈顶元素 Dialogue: 0,0:18:17.07,0:18:21.24,Default,,0,0,0,,这只是针对这台机器的约定 Dialogue: 0,0:18:21.84,0:18:23.70,Default,,0,0,0,,现在已经给出了APPLY的所有约定 Dialogue: 0,0:18:23.93,0:18:25.37,Default,,0,0,0,,它会去执行应用 Dialogue: 0,0:18:25.54,0:18:27.85,Default,,0,0,0,,这个应用的结果将会保存在VAL寄存器中 Dialogue: 0,0:18:28.89,0:18:29.95,Default,,0,0,0,,栈会被弹出 Dialogue: 0,0:18:31.12,0:18:31.66,Default,,0,0,0,,同样的 Dialogue: 0,0:18:31.71,0:18:34.03,Default,,0,0,0,,其它所有寄存器的内容都可能被修改 Dialogue: 0,0:18:34.84,0:18:37.82,Default,,0,0,0,,那么 这就是这台机器的基本结构 Dialogue: 0,0:18:38.99,0:18:41.50,Default,,0,0,0,,我们先课间休息一下 Dialogue: 0,0:18:41.52,0:18:42.70,Default,,0,0,0,,然后再来研究一个真实的例子 Dialogue: 0,0:18:43.53,0:19:08.11,Default,,0,0,0,,[音乐] Dialogue: 0,0:19:08.14,0:19:13.47,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:19:33.10,0:19:35.87,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:19:35.87,0:19:40.38,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:19:40.38,0:19:45.29,Declare,,0,0,0,,{\an2\fad(500,500)}显式控制求值器 Dialogue: 0,0:19:47.85,0:19:49.95,Default,,0,0,0,,现在 我们来研究一下这台寄存器机器 Dialogue: 0,0:19:50.41,0:19:51.77,Default,,0,0,0,,我们一步一步地跟进 Dialogue: 0,0:19:52.27,0:19:56.94,Default,,0,0,0,,具体到每一处细节 Dialogue: 0,0:19:57.07,0:19:58.52,Default,,0,0,0,,这样你就能完全具体地看到 Dialogue: 0,0:19:58.86,0:20:01.24,Default,,0,0,0,,表达式是如何求值的 Dialogue: 0,0:20:03.15,0:20:06.86,Default,,0,0,0,,那么我们从一个非常简单的表达式开始 Dialogue: 0,0:20:07.45,0:20:13.52,Default,,0,0,0,,我们要求值的表达式只有一个1 Dialogue: 0,0:20:18.77,0:20:20.40,Default,,0,0,0,,我们需要一个环境 Dialogue: 0,0:20:20.43,0:20:22.35,Default,,0,0,0,,因此我们假设某处有一个环境 Dialogue: 0,0:20:22.38,0:20:23.39,Default,,0,0,0,,我们把它记作E0 Dialogue: 0,0:20:30.06,0:20:34.56,Default,,0,0,0,,由于我们之后也要用到它 Dialogue: 0,0:20:35.62,0:20:37.04,Default,,0,0,0,,而且显然不需要任何东西 Dialogue: 0,0:20:37.07,0:20:37.93,Default,,0,0,0,,就可以求值1 Dialogue: 0,0:20:38.36,0:20:39.45,Default,,0,0,0,,但是为了方便以后引用 Dialogue: 0,0:20:39.45,0:20:40.94,Default,,0,0,0,,我们假设环境E0中有 Dialogue: 0,0:20:41.44,0:20:43.15,Default,,0,0,0,,X=3 Dialogue: 0,0:20:43.72,0:20:45.37,Default,,0,0,0,,Y=4 Dialogue: 0,0:20:48.27,0:20:48.78,Default,,0,0,0,,好吗? Dialogue: 0,0:20:49.14,0:20:50.12,Default,,0,0,0,,现在 我们要做的就是 Dialogue: 0,0:20:50.51,0:20:54.59,Default,,0,0,0,,在这个环境中求值表达式1 Dialogue: 0,0:20:55.74,0:20:58.54,Default,,0,0,0,,这样 ENV寄存器就存放了一个指针 Dialogue: 0,0:20:59.65,0:21:01.04,Default,,0,0,0,,指向这个环境E0 Dialogue: 0,0:21:03.31,0:21:05.65,Default,,0,0,0,,那么我们来看它是怎么进行的 Dialogue: 0,0:21:05.65,0:21:07.26,Default,,0,0,0,,我要步步跟进代码 Dialogue: 0,0:21:08.26,0:21:10.00,Default,,0,0,0,,这样的话 我会充当控制器 Dialogue: 0,0:21:10.04,0:21:10.80,Default,,0,0,0,,现在我需要的是-- Dialogue: 0,0:21:11.02,0:21:12.49,Default,,0,0,0,,由于这台机器已经变得相当复杂 Dialogue: 0,0:21:12.98,0:21:16.83,Default,,0,0,0,,我需要一个小小的执行单元 Dialogue: 0,0:21:16.83,0:21:18.16,Default,,0,0,0,,那么请上我们的执行单元 Dialogue: 0,0:21:22.62,0:21:23.12,Default,,0,0,0,,好的 Dialogue: 0,0:21:28.59,0:21:29.96,Default,,0,0,0,,好 现在我们要开始了 Dialogue: 0,0:21:30.53,0:21:32.48,Default,,0,0,0,,我们要从EVAL-DISPATCH启动机器 Dialogue: 0,0:21:33.26,0:21:34.62,Default,,0,0,0,,这是整个过程的开始 Dialogue: 0,0:21:35.87,0:21:38.75,Default,,0,0,0,,EVAL-DISPATCH会查看表达式并进行分派 Dialogue: 0,0:21:39.32,0:21:40.06,Default,,0,0,0,,就像EVAL Dialogue: 0,0:21:40.87,0:21:42.00,Default,,0,0,0,,先从第一句看起 Dialogue: 0,0:21:42.04,0:21:47.95,Default,,0,0,0,,先判断表达式是不是自求值的 Dialogue: 0,0:21:47.95,0:21:49.96,Default,,0,0,0,,SELF-EVALUATING?是我们放入机器的 Dialogue: 0,0:21:49.96,0:21:51.10,Default,,0,0,0,,一个抽象过程 Dialogue: 0,0:21:52.22,0:21:53.51,Default,,0,0,0,,它对于数字1来说为真 Dialogue: 0,0:21:53.64,0:21:55.52,Default,,0,0,0,,因此跳转的目的是EV-SELF-EVAL Dialogue: 0,0:21:56.77,0:21:58.20,Default,,0,0,0,,那么我作为控制器 Dialogue: 0,0:21:58.22,0:21:59.55,Default,,0,0,0,,会去查看EV-SELF-EVAL Dialogue: 0,0:22:00.06,0:22:01.07,Default,,0,0,0,,所以我们要跳到那里 Dialogue: 0,0:22:02.60,0:22:04.76,Default,,0,0,0,,EV-SELF-EAVL的代码是-- Dialogue: 0,0:22:06.54,0:22:09.90,Default,,0,0,0,,把EXP寄存器的值赋值给VAL寄存器 Dialogue: 0,0:22:15.24,0:22:16.51,Default,,0,0,0,,我遇到一个BUG Dialogue: 0,0:22:17.93,0:22:20.59,Default,,0,0,0,,因为我初始化机器的时候没有做一件事情 Dialogue: 0,0:22:21.62,0:22:22.89,Default,,0,0,0,,也就是指定当它执行完毕后 Dialogue: 0,0:22:22.91,0:22:24.19,Default,,0,0,0,,应该做什么 Dialogue: 0,0:22:24.65,0:22:26.83,Default,,0,0,0,,所以在启动机器的时候 Dialogue: 0,0:22:27.37,0:22:29.85,Default,,0,0,0,,应该将CONTINUE寄存器设置为DONE Dialogue: 0,0:22:31.18,0:22:33.26,Default,,0,0,0,,所以我们给VAL赋值 Dialogue: 0,0:22:33.37,0:22:35.56,Default,,0,0,0,,然后执行(GOTO (FETCH CONTINUE)) Dialogue: 0,0:22:35.63,0:22:36.56,Default,,0,0,0,,并且修改-- Dialogue: 0,0:22:38.09,0:22:38.60,Default,,0,0,0,,好 Dialogue: 0,0:22:40.00,0:22:41.16,Default,,0,0,0,,好 我们来看一个更复杂的 Dialogue: 0,0:22:42.16,0:22:43.45,Default,,0,0,0,,我们先重置机器 Dialogue: 0,0:22:44.86,0:22:50.88,Default,,0,0,0,,然后把X放入EXP寄存器中 Dialogue: 0,0:22:56.71,0:22:58.20,Default,,0,0,0,,重新从EVAL-DISPATCH开始 Dialogue: 0,0:22:59.61,0:23:01.69,Default,,0,0,0,,先检查它是自求值的么? Dialogue: 0,0:23:01.69,0:23:02.03,Default,,0,0,0,,不是 Dialogue: 0,0:23:02.65,0:23:03.61,Default,,0,0,0,,它是变量吗 Dialogue: 0,0:23:04.63,0:23:05.02,Default,,0,0,0,,是的 Dialogue: 0,0:23:05.56,0:23:07.07,Default,,0,0,0,,我们跳转到EV-VARIABLE Dialogue: 0,0:23:08.38,0:23:10.97,Default,,0,0,0,,它说:查找EXP寄存器中变量的值 Dialogue: 0,0:23:12.13,0:23:15.69,Default,,0,0,0,,并把它赋值给VAL寄存器 Dialogue: 0,0:23:21.23,0:23:22.91,Default,,0,0,0,,(GOTO (FETCH CONTINUE)) Dialogue: 0,0:23:23.96,0:23:24.48,Default,,0,0,0,,Sussman教授:DONE Dialogue: 0,0:23:27.61,0:23:28.09,Default,,0,0,0,,Abelson教授:好 Dialogue: 0,0:23:29.31,0:23:30.76,Default,,0,0,0,,这些都是最基本的理念 Dialogue: 0,0:23:31.33,0:23:32.65,Default,,0,0,0,,这是这台机器上的简单运算 Dialogue: 0,0:23:32.68,0:23:35.07,Default,,0,0,0,,现在 我们来做些有意义的事情 Dialogue: 0,0:23:36.07,0:23:38.64,Default,,0,0,0,,我们看这条表达式 Dialogue: 0,0:23:43.58,0:23:47.93,Default,,0,0,0,,(+ X Y) Dialogue: 0,0:23:49.69,0:23:51.28,Default,,0,0,0,,现在我们会看到 Dialogue: 0,0:23:52.41,0:23:54.01,Default,,0,0,0,,如何展开这些表达式树 Dialogue: 0,0:23:57.13,0:23:58.68,Default,,0,0,0,,我们再次从EVAL-DISPATCH开始 Dialogue: 0,0:24:04.61,0:24:05.80,Default,,0,0,0,,是自求值的吗? Dialogue: 0,0:24:05.95,0:24:06.52,Default,,0,0,0,,不是 Dialogue: 0,0:24:06.70,0:24:07.71,Default,,0,0,0,,是变量吗?不是 Dialogue: 0,0:24:07.82,0:24:08.99,Default,,0,0,0,,它也不是我在这里 Dialogue: 0,0:24:08.99,0:24:10.12,Default,,0,0,0,,没有列出的特殊形式 Dialogue: 0,0:24:10.27,0:24:12.48,Default,,0,0,0,,比如引用、LAMBDA、SET! 等等 Dialogue: 0,0:24:12.48,0:24:13.08,Default,,0,0,0,,它都不是 Dialogue: 0,0:24:13.26,0:24:14.73,Default,,0,0,0,,它是一个过程应用 Dialogue: 0,0:24:15.88,0:24:17.42,Default,,0,0,0,,所以我们要跳转到EV-APPLICATION Dialogue: 0,0:24:19.97,0:24:24.94,Default,,0,0,0,,回忆一下EV-APPLICATION要做什么 Dialogue: 0,0:24:25.58,0:24:28.19,Default,,0,0,0,,它先要求值运算符 Dialogue: 0,0:24:28.27,0:24:31.40,Default,,0,0,0,,然后求值运算对象 Dialogue: 0,0:24:32.36,0:24:34.30,Default,,0,0,0,,然后再进行应用 Dialogue: 0,0:24:35.06,0:24:36.09,Default,,0,0,0,,所以在我们开始之前 Dialogue: 0,0:24:36.94,0:24:37.88,Default,,0,0,0,,由于我们是严格按照代码来执行的 Dialogue: 0,0:24:37.88,0:24:38.88,Default,,0,0,0,,我们最好记住 Dialogue: 0,0:24:39.07,0:24:40.54,Default,,0,0,0,,在这个环境中的某处 Dialogue: 0,0:24:40.57,0:24:42.36,Default,,0,0,0,,连接到了另一个环境 Dialogue: 0,0:24:43.98,0:24:44.94,Default,,0,0,0,,其中符号'+ Dialogue: 0,0:24:45.72,0:24:49.16,Default,,0,0,0,,跟基本的加法过程绑定在了一起 Dialogue: 0,0:24:51.63,0:24:54.03,Default,,0,0,0,,这样 求值+时就不会导致“变量未定义” Dialogue: 0,0:24:55.34,0:24:56.84,Default,,0,0,0,,现在我们来到了EV-APPLICATION Dialogue: 0,0:24:59.85,0:25:04.32,Default,,0,0,0,,把EXP寄存器对应的运算对象 Dialogue: 0,0:25:04.92,0:25:06.89,Default,,0,0,0,,赋值给UNEV寄存器 Dialogue: 0,0:25:07.61,0:25:08.83,Default,,0,0,0,,这些是运算对象 Dialogue: 0,0:25:09.23,0:25:11.66,Default,,0,0,0,,UNEV这个临时寄存器 Dialogue: 0,0:25:11.68,0:25:12.59,Default,,0,0,0,,就是用来暂存它们的 Dialogue: 0,0:25:13.22,0:25:13.86,Default,,0,0,0,,Sussman教授:我正在赋值 Dialogue: 0,0:25:14.28,0:25:16.62,Default,,0,0,0,,Abelson教授:把运算符赋值给EXP寄存器 Dialogue: 0,0:25:18.07,0:25:20.09,Default,,0,0,0,,注意 现在我们已经修改了EXP中的表达式 Dialogue: 0,0:25:21.84,0:25:23.61,Default,,0,0,0,,但是我们需要的部分在UNEV中 Dialogue: 0,0:25:25.82,0:25:26.81,Default,,0,0,0,,现在 我们要准备好 Dialogue: 0,0:25:26.81,0:25:28.59,Default,,0,0,0,,去递归地求值运算符 Dialogue: 0,0:25:28.75,0:25:31.69,Default,,0,0,0,,把CONTINUE寄存器保存在栈上 Dialogue: 0,0:25:34.86,0:25:36.09,Default,,0,0,0,,保存ENV Dialogue: 0,0:25:40.48,0:25:41.69,Default,,0,0,0,,保存UNEV Dialogue: 0,0:25:49.53,0:25:54.64,Default,,0,0,0,,把标号EVAL-ARGS赋值给CONTINUE寄存器 Dialogue: 0,0:26:01.40,0:26:01.95,Default,,0,0,0,,我们做了什么 Dialogue: 0,0:26:01.95,0:26:04.38,Default,,0,0,0,,我们为递归调用做了必要的准备 Dialogue: 0,0:26:04.38,0:26:05.88,Default,,0,0,0,,我们要开始执行EVAL-DISPATCH Dialogue: 0,0:26:06.28,0:26:08.83,Default,,0,0,0,,我们为递归调用EVAL-DISPATCH做好了准备 Dialogue: 0,0:26:10.23,0:26:10.86,Default,,0,0,0,,我们做了哪些事情 Dialogue: 0,0:26:11.02,0:26:13.64,Default,,0,0,0,,我们把之后要用到的东西 Dialogue: 0,0:26:14.48,0:26:15.98,Default,,0,0,0,,也就是UNEV中的运算对象 Dialogue: 0,0:26:16.36,0:26:18.99,Default,,0,0,0,,以及我们最终求值运算对象时 Dialogue: 0,0:26:19.16,0:26:20.72,Default,,0,0,0,,会用到的环境 Dialogue: 0,0:26:22.28,0:26:23.93,Default,,0,0,0,,以及我们最终想要去的位置 Dialogue: 0,0:26:23.95,0:26:25.07,Default,,0,0,0,,本例中 也就是DONE Dialogue: 0,0:26:25.34,0:26:26.70,Default,,0,0,0,,我们把它们保存在栈上 Dialogue: 0,0:26:27.10,0:26:28.41,Default,,0,0,0,,我们之所以把它们保存在栈上 Dialogue: 0,0:26:28.43,0:26:30.67,Default,,0,0,0,,是因为EVAL-DISPATCH并不会保证 Dialogue: 0,0:26:30.94,0:26:32.54,Default,,0,0,0,,不会去修改这些寄存器 Dialogue: 0,0:26:33.55,0:26:35.02,Default,,0,0,0,,那么所有这些东西都存在了栈上 Dialogue: 0,0:26:35.02,0:26:36.91,Default,,0,0,0,,现在我们满足了EVAL-DISPATCH的约定 Dialogue: 0,0:26:37.38,0:26:38.75,Default,,0,0,0,,这是一条新的表达式 Dialogue: 0,0:26:38.78,0:26:40.04,Default,,0,0,0,,也就是+运算符 Dialogue: 0,0:26:41.07,0:26:41.95,Default,,0,0,0,,以及一个新的环境 Dialogue: 0,0:26:41.98,0:26:43.60,Default,,0,0,0,,尽管在本例中是同一个环境 Dialogue: 0,0:26:44.25,0:26:45.87,Default,,0,0,0,,以及在完成后要返回的位置 Dialogue: 0,0:26:45.87,0:26:46.91,Default,,0,0,0,,也就是EVAL-ARGS Dialogue: 0,0:26:47.60,0:26:48.13,Default,,0,0,0,,这样就满足了 Dialogue: 0,0:26:48.13,0:26:49.68,Default,,0,0,0,,现在我们来执行EVAL-DISPATCH Dialogue: 0,0:26:50.89,0:26:52.36,Default,,0,0,0,,我们回到了EVAL-DISPATCH Dialogue: 0,0:26:53.05,0:26:54.40,Default,,0,0,0,,它不是自求值的 Dialogue: 0,0:26:54.44,0:26:55.47,Default,,0,0,0,,但它是一个变量 Dialogue: 0,0:26:56.32,0:26:58.06,Default,,0,0,0,,因此我们最好跳转到EV-VARIABLE Dialogue: 0,0:26:59.79,0:27:02.65,Default,,0,0,0,,EV-VARIABLE首先要给VAL赋值 Dialogue: 0,0:27:02.70,0:27:06.33,Default,,0,0,0,,查找表达式中变量的值 Dialogue: 0,0:27:08.49,0:27:10.75,Default,,0,0,0,,那么VAL寄存器中应该是基本的加法运算 Dialogue: 0,0:27:13.37,0:27:15.16,Default,,0,0,0,,然后(GOTO (FETCH CONTINUE)) Dialogue: 0,0:27:15.23,0:27:16.11,Default,,0,0,0,,Sussman教授:它是EVAL-ARGS Dialogue: 0,0:27:16.20,0:27:18.73,Default,,0,0,0,,Abelson教授:现在它是EVAL-ARGS而不是DONE了 Dialogue: 0,0:27:19.42,0:27:21.26,Default,,0,0,0,,然后我们来到EVAL-ARGS Dialogue: 0,0:27:22.16,0:27:23.02,Default,,0,0,0,,看看它要做什么 Dialogue: 0,0:27:23.07,0:27:24.84,Default,,0,0,0,,我们要恢复之前保存的东西 Dialogue: 0,0:27:25.20,0:27:26.57,Default,,0,0,0,,因此调用(RESTORE UNEV) Dialogue: 0,0:27:29.21,0:27:31.69,Default,,0,0,0,,注意 这里并不是必要的 Dialogue: 0,0:27:31.74,0:27:32.90,Default,,0,0,0,,但通常来说都会有这么一步 Dialogue: 0,0:27:32.90,0:27:35.16,Default,,0,0,0,,它可以是任意的求值过程 Dialogue: 0,0:27:35.43,0:27:36.70,Default,,0,0,0,,恢复ENV寄存器 Dialogue: 0,0:27:47.87,0:27:52.04,Default,,0,0,0,,然后把(FETCH VAL)赋值给FUN Dialogue: 0,0:27:59.95,0:28:02.81,Default,,0,0,0,,现在我们要开始求值参数了 Dialogue: 0,0:28:04.34,0:28:06.48,Default,,0,0,0,,首先 我们最好把FUN寄存器保存起来 Dialogue: 0,0:28:07.42,0:28:10.62,Default,,0,0,0,,因为求值过程中可能发生任何事情 Dialogue: 0,0:28:15.33,0:28:16.88,Default,,0,0,0,,我们初始化参数列表 Dialogue: 0,0:28:16.91,0:28:19.29,Default,,0,0,0,,给ARGL赋值一个空的参数列表 Dialogue: 0,0:28:20.88,0:28:22.17,Default,,0,0,0,,然后跳转到EVAL-ARG-LOOP Dialogue: 0,0:28:24.86,0:28:26.27,Default,,0,0,0,,在EVAL-ARG-LOOP中 Dialogue: 0,0:28:27.77,0:28:31.53,Default,,0,0,0,,我们想要去一条一条的求值 Dialogue: 0,0:28:31.61,0:28:33.37,Default,,0,0,0,,UNEV中的表达式 Dialogue: 0,0:28:33.54,0:28:35.68,Default,,0,0,0,,然后把它们从UNEV中的待求值表 Dialogue: 0,0:28:35.90,0:28:37.26,Default,,0,0,0,,移动到ARGL中的已求值表中 Dialogue: 0,0:28:37.84,0:28:39.18,Default,,0,0,0,,然后我们保存ARGL Dialogue: 0,0:28:43.95,0:28:47.26,Default,,0,0,0,,然后我们把UNEV中的第一个运算对象 Dialogue: 0,0:28:47.37,0:28:48.38,Default,,0,0,0,,赋值给EXP Dialogue: 0,0:28:53.77,0:28:55.89,Default,,0,0,0,,然后我们检查它是否为最后一个运算对象 Dialogue: 0,0:28:55.89,0:28:56.91,Default,,0,0,0,,在这里 它还不是 Dialogue: 0,0:28:58.99,0:29:01.55,Default,,0,0,0,,然后我们保存环境 Dialogue: 0,0:29:08.00,0:29:10.06,Default,,0,0,0,,我们之所以保存UNEV Dialogue: 0,0:29:11.61,0:29:13.50,Default,,0,0,0,,是因为稍后我们可能会需要它们 Dialogue: 0,0:29:13.50,0:29:14.40,Default,,0,0,0,,我们需要环境 Dialogue: 0,0:29:14.44,0:29:15.64,Default,,0,0,0,,来进行一些求值 Dialogue: 0,0:29:15.80,0:29:16.60,Default,,0,0,0,,我们需要UNEV寄存器来指示 Dialogue: 0,0:29:16.62,0:29:19.20,Default,,0,0,0,,其余的待求值参数 Dialogue: 0,0:29:20.34,0:29:21.55,Default,,0,0,0,,我们要把CONTINUE寄存器赋值为 Dialogue: 0,0:29:21.56,0:29:24.44,Default,,0,0,0,,ACCUMULATE-ARG这个标号 Dialogue: 0,0:29:31.13,0:29:34.01,Default,,0,0,0,,现在 我们已经准备好再次调用EVAL-DISPATCH了 Dialogue: 0,0:29:37.07,0:29:38.54,Default,,0,0,0,,现在让我把这个短路掉 Dialogue: 0,0:29:39.12,0:29:41.09,Default,,0,0,0,,这里我们不跟进EVAL-DISPATCH的细节 Dialogue: 0,0:29:41.09,0:29:42.64,Default,,0,0,0,,EVAL-DISPATCH的约定说: Dialogue: 0,0:29:42.97,0:29:45.00,Default,,0,0,0,,我的调用完成后 Dialogue: 0,0:29:45.13,0:29:45.96,Default,,0,0,0,,整个机器的状态会变为 Dialogue: 0,0:29:46.03,0:29:48.20,Default,,0,0,0,,也就是在ENV环境中求值EXP表达式 Dialogue: 0,0:29:48.24,0:29:50.27,Default,,0,0,0,,求值结果会保存在VAL寄存器中 Dialogue: 0,0:29:50.27,0:29:51.07,Default,,0,0,0,,结束状态就是这样 Dialogue: 0,0:29:51.32,0:29:52.62,Default,,0,0,0,,那么我们把这些全都省略掉 Dialogue: 0,0:29:54.43,0:29:56.36,Default,,0,0,0,,最后VAL的内容是3 Dialogue: 0,0:29:58.01,0:29:59.76,Default,,0,0,0,,并且当我们从EVAL-DISPATCH返回的时候 Dialogue: 0,0:29:59.76,0:30:01.76,Default,,0,0,0,,我们会返回到ACCUMULAT-ARG这里 Dialogue: 0,0:30:02.30,0:30:03.23,Default,,0,0,0,,Sussman教授:跳转到ACCUMULATE-ARG Dialogue: 0,0:30:06.22,0:30:08.20,Default,,0,0,0,,Abelson教授:VAL寄存器里是3 对吧? Dialogue: 0,0:30:08.72,0:30:10.59,Default,,0,0,0,,我们跳过了求值的细节 Dialogue: 0,0:30:10.65,0:30:11.32,Default,,0,0,0,,现在我们要做什么? Dialogue: 0,0:30:11.32,0:30:13.68,Default,,0,0,0,,我们返回继续看剩下的参数 Dialogue: 0,0:30:13.68,0:30:14.83,Default,,0,0,0,,我们恢复UNEV Dialogue: 0,0:30:17.51,0:30:19.00,Default,,0,0,0,,恢复ENV Dialogue: 0,0:30:25.79,0:30:27.05,Default,,0,0,0,,然后恢复ARGL Dialogue: 0,0:30:28.65,0:30:29.17,Default,,0,0,0,,这件事 Dialogue: 0,0:30:30.06,0:30:31.45,Default,,0,0,0,,Sussman教授:糟糕 奇偶错误 Dialogue: 0,0:30:33.76,0:30:34.83,Default,,0,0,0,,Abelson教授:恢复ARGL Dialogue: 0,0:30:45.57,0:30:49.76,Default,,0,0,0,,然后 我们把VAL寄存器和ARGL给CONS起来 Dialogue: 0,0:30:50.65,0:30:52.64,Default,,0,0,0,,然后赋值给ARGL寄存器 Dialogue: 0,0:30:59.36,0:31:02.96,Default,,0,0,0,,我们把UNEV中剩余的运算对象 Dialogue: 0,0:31:03.34,0:31:04.52,Default,,0,0,0,,赋值给UNEV Dialogue: 0,0:31:08.91,0:31:10.76,Default,,0,0,0,,然后我们返回到EVAL-ARG-LOOP Dialogue: 0,0:31:11.51,0:31:12.28,Default,,0,0,0,,Sussman教授:EVAL-ARG-LOOP Dialogue: 0,0:31:12.28,0:31:12.86,Default,,0,0,0,,Abelson教授:好 Dialogue: 0,0:31:15.88,0:31:17.08,Default,,0,0,0,,现在我们处理下一个参数 Dialogue: 0,0:31:17.58,0:31:19.31,Default,,0,0,0,,所以首先我们要保存ARGL Dialogue: 0,0:31:25.40,0:31:28.27,Default,,0,0,0,,然后我们把UNEV中的第一个运算对象 Dialogue: 0,0:31:29.15,0:31:30.81,Default,,0,0,0,,赋给EXP Dialogue: 0,0:31:34.72,0:31:37.02,Default,,0,0,0,,然后我们检查它是否为最后一个运算对象 Dialogue: 0,0:31:37.02,0:31:38.00,Default,,0,0,0,,这里它是最后一个 Dialogue: 0,0:31:39.08,0:31:40.27,Default,,0,0,0,,所以我们跳到一个特殊的地方 Dialogue: 0,0:31:40.28,0:31:42.06,Default,,0,0,0,,来求值最后一个参数 Dialogue: 0,0:31:43.37,0:31:45.07,Default,,0,0,0,,因为请注意 在求值这个参数之后 Dialogue: 0,0:31:45.10,0:31:46.62,Default,,0,0,0,,我们就不再需要这个环境了 Dialogue: 0,0:31:47.64,0:31:48.78,Default,,0,0,0,,这就是区别 Dialogue: 0,0:31:50.25,0:31:51.85,Default,,0,0,0,,在这里 在EVAL-LAST-ARG这里 Dialogue: 0,0:31:52.24,0:31:54.92,Default,,0,0,0,,CONTINUE被赋值为了ACCUMULATE-LAST-ARG Dialogue: 0,0:32:04.27,0:32:06.90,Default,,0,0,0,,现在我们再次为EVAL-DISPATCH做准备 Dialogue: 0,0:32:06.90,0:32:08.51,Default,,0,0,0,,我们有一个完成时要跳转的目的地 Dialogue: 0,0:32:08.62,0:32:09.84,Default,,0,0,0,,我们有一条表达式 Dialogue: 0,0:32:09.84,0:32:10.80,Default,,0,0,0,,还有一个环境 Dialogue: 0,0:32:11.33,0:32:13.64,Default,,0,0,0,,好 那么我们略过对EVAL-DISPATCH的调用 Dialogue: 0,0:32:14.37,0:32:16.41,Default,,0,0,0,,现在情况是这里有一个Y Dialogue: 0,0:32:16.70,0:32:18.56,Default,,0,0,0,,在这个环境中 它的值是4 Dialogue: 0,0:32:18.60,0:32:20.09,Default,,0,0,0,,所以最终VAL寄存器将会是4 Dialogue: 0,0:32:21.06,0:32:22.86,Default,,0,0,0,,然后我们就要以ACCUMULATE-LAST-ARG结束了 Dialogue: 0,0:32:25.45,0:32:26.91,Default,,0,0,0,,因此 在ACCUMULATE-LAST-ARG中 Dialogue: 0,0:32:29.28,0:32:30.52,Default,,0,0,0,,我们恢复ARGL寄存器 Dialogue: 0,0:32:37.69,0:32:42.76,Default,,0,0,0,,我们把ARGL赋值为 Dialogue: 0,0:32:43.60,0:32:45.83,Default,,0,0,0,,将一个新值CONS在它上面的结果 Dialogue: 0,0:32:45.93,0:32:47.39,Default,,0,0,0,,所以我们在它的旧值前CONS一个4 Dialogue: 0,0:32:49.85,0:32:52.52,Default,,0,0,0,,我们恢复FUN寄存器中的内容 Dialogue: 0,0:32:53.77,0:32:54.99,Default,,0,0,0,,需要注意的是 在则个例子中 Dialogue: 0,0:32:55.00,0:32:56.27,Default,,0,0,0,,FUN寄存器还没有被修改过 Dialogue: 0,0:32:56.38,0:32:57.72,Default,,0,0,0,,但是通常来说 它会的 Dialogue: 0,0:32:59.13,0:33:01.50,Default,,0,0,0,,现在 我们将要调用APPLY-DISPATCH Dialogue: 0,0:33:02.65,0:33:04.40,Default,,0,0,0,,所以我们刚刚步步跟进了EVAL过程 Dialogue: 0,0:33:04.51,0:33:05.85,Default,,0,0,0,,我们求值了运算符 Dialogue: 0,0:33:06.46,0:33:07.98,Default,,0,0,0,,以及实际参数 Dialogue: 0,0:33:07.98,0:33:09.24,Default,,0,0,0,,现在我们要应用它们了 Dialogue: 0,0:33:09.58,0:33:11.37,Default,,0,0,0,,因此 我们来到APPLY-DISPATCH这里 Dialogue: 0,0:33:18.03,0:33:19.29,Default,,0,0,0,,这是APPLY-DISPATCH的代码 Dialogue: 0,0:33:21.05,0:33:22.41,Default,,0,0,0,,我们要检查它是一个基本过程 Dialogue: 0,0:33:22.41,0:33:23.45,Default,,0,0,0,,还是一个复合过程 Dialogue: 0,0:33:23.64,0:33:24.20,Default,,0,0,0,,Sussman教授:基本过程 Dialogue: 0,0:33:24.54,0:33:24.83,Default,,0,0,0,,Abelson教授:好的 Dialogue: 0,0:33:24.89,0:33:26.52,Default,,0,0,0,,这里 它是一个基本过程 Dialogue: 0,0:33:27.45,0:33:28.91,Default,,0,0,0,,因此 我们跳转到PRIMITIVE-APPLY Dialogue: 0,0:33:29.79,0:33:31.36,Default,,0,0,0,,我们来到PRIMITIVE-APPLY Dialogue: 0,0:33:33.71,0:33:35.37,Default,,0,0,0,,它说:把VAL赋值为 Dialogue: 0,0:33:35.69,0:33:38.25,Default,,0,0,0,,把基本过程 Dialogue: 0,0:33:38.36,0:33:40.30,Default,,0,0,0,,应用在参数表的结果 Dialogue: 0,0:33:41.31,0:33:42.43,Default,,0,0,0,,Sussman教授:我不知道怎么做加法 Dialogue: 0,0:33:42.54,0:33:43.80,Default,,0,0,0,,我只是一个执行单元 Dialogue: 0,0:33:44.14,0:33:45.35,Default,,0,0,0,,Abelson教授:我也不知道 Dialogue: 0,0:33:45.35,0:33:46.51,Default,,0,0,0,,我只是一个求值器 Dialogue: 0,0:33:47.08,0:33:48.36,Default,,0,0,0,,因此 我们需要一个基本运算执行器 Dialogue: 0,0:33:48.36,0:33:49.72,Default,,0,0,0,,那么 请问基本运算执行器 Dialogue: 0,0:33:49.76,0:33:52.36,Default,,0,0,0,,3+4等于多少? Dialogue: 0,0:33:52.86,0:33:53.32,Default,,0,0,0,,学生:7 Dialogue: 0,0:33:53.71,0:33:54.65,Default,,0,0,0,,Abelson教授:好 是7 Dialogue: 0,0:33:55.32,0:33:55.99,Default,,0,0,0,,Sussman教授:谢谢 Dialogue: 0,0:33:59.20,0:34:00.60,Default,,0,0,0,,Abelson教授:现在 我们恢复CONTINUE Dialogue: 0,0:34:11.58,0:34:12.90,Default,,0,0,0,,执行(GOTO (FETCH CONTINUE)) Dialogue: 0,0:34:13.07,0:34:13.47,Default,,0,0,0,,Sussman教授:'DONE Dialogue: 0,0:34:14.20,0:34:14.67,Default,,0,0,0,,Abelson教授:好 Dialogue: 0,0:34:14.92,0:34:18.41,Default,,0,0,0,,这些是你能看到的最细致的过程了 Dialogue: 0,0:34:18.41,0:34:20.19,Default,,0,0,0,,我们再也不会讲得这么细了 Dialogue: 0,0:34:21.59,0:34:23.92,Default,,0,0,0,,有一件重要的事需要注意 Dialogue: 0,0:34:24.91,0:34:27.55,Default,,0,0,0,,我们刚刚执行了一个递归过程 Dialogue: 0,0:34:29.56,0:34:31.17,Default,,0,0,0,,我们在整个过程中使用了栈 Dialogue: 0,0:34:31.17,0:34:32.75,Default,,0,0,0,,而且求值器是递归的 Dialogue: 0,0:34:33.07,0:34:35.88,Default,,0,0,0,,有很多人以为在求值器中 Dialogue: 0,0:34:36.48,0:34:37.85,Default,,0,0,0,,会用到栈和递归 Dialogue: 0,0:34:37.87,0:34:38.97,Default,,0,0,0,,或许是因为 Dialogue: 0,0:34:39.09,0:34:42.15,Default,,0,0,0,,回去求值像阶乘或者FIB那样的递归过程 Dialogue: 0,0:34:42.15,0:34:42.92,Default,,0,0,0,,这并不正确 Dialogue: 0,0:34:43.67,0:34:44.99,Default,,0,0,0,,注意 我们在这里进行了递归 Dialogue: 0,0:34:45.00,0:34:46.86,Default,,0,0,0,,而仅仅是去求值(+ X Y) Dialogue: 0,0:34:47.77,0:34:50.65,Default,,0,0,0,,在求值器中需要递归 实际上是因为 Dialogue: 0,0:34:50.96,0:34:52.97,Default,,0,0,0,,是因为求值过程本身 Dialogue: 0,0:34:52.99,0:34:54.06,Default,,0,0,0,,就是递归的 Dialogue: 0,0:34:54.45,0:34:56.17,Default,,0,0,0,,并不是因为你在Lisp中 Dialogue: 0,0:34:56.32,0:34:58.09,Default,,0,0,0,,要求值的那个过程 Dialogue: 0,0:34:58.12,0:34:59.27,Default,,0,0,0,,是一个递归过程 Dialogue: 0,0:34:59.27,0:35:00.52,Default,,0,0,0,,这一点很重要 Dialogue: 0,0:35:00.52,0:35:02.14,Default,,0,0,0,,人们经常在这里被弄糊涂 Dialogue: 0,0:35:03.01,0:35:04.27,Default,,0,0,0,,另一点要注意的是 Dialogue: 0,0:35:04.27,0:35:05.64,Default,,0,0,0,,我们在这里完成之后 Dialogue: 0,0:35:06.28,0:35:07.12,Default,,0,0,0,,真正完成以后 Dialogue: 0,0:35:07.12,0:35:08.49,Default,,0,0,0,,不仅仅是指我们在'DONE这个标号 Dialogue: 0,0:35:09.45,0:35:13.23,Default,,0,0,0,,栈上也没有累积的东西了 Dialogue: 0,0:35:13.60,0:35:15.71,Default,,0,0,0,,对吧?机器又回到了它的初始状态 Dialogue: 0,0:35:17.00,0:35:18.75,Default,,0,0,0,,那就是“完成”的其中一部分意义 Dialogue: 0,0:35:19.71,0:35:21.04,Default,,0,0,0,,换句话说就是 Dialogue: 0,0:35:22.72,0:35:26.04,Default,,0,0,0,,整个求值过程是把 Dialogue: 0,0:35:26.41,0:35:28.32,Default,,0,0,0,,(+ X Y)这条表达式 Dialogue: 0,0:35:30.54,0:35:32.78,Default,,0,0,0,,归约为这里的7 Dialogue: 0,0:35:33.24,0:35:35.45,Default,,0,0,0,,我所指的“归约”有特殊的意义 Dialogue: 0,0:35:36.01,0:35:38.18,Default,,0,0,0,,也就是栈上没剩下任何东西了 Dialogue: 0,0:35:38.18,0:35:40.36,Default,,0,0,0,,机器现在与初始状态相同 Dialogue: 0,0:35:40.92,0:35:42.65,Default,,0,0,0,,只是VAL寄存器里有一些东西 Dialogue: 0,0:35:42.72,0:35:44.52,Default,,0,0,0,,它不是任何问题的子问题 Dialogue: 0,0:35:44.52,0:35:45.63,Default,,0,0,0,,不需要返回到其它地方 Dialogue: 0,0:35:46.12,0:35:46.96,Default,,0,0,0,,好 这节课就讲到这里 Dialogue: 0,0:35:50.16,0:35:50.76,Default,,0,0,0,,有问题吗 Dialogue: 0,0:35:51.08,0:35:54.02,Default,,0,0,0,,学生:关于栈有一个问题 Dialogue: 0,0:35:54.02,0:35:55.82,Default,,0,0,0,,由于数据有可能是递归的 Dialogue: 0,0:35:56.20,0:35:58.75,Default,,0,0,0,,例如 嵌套的表达式 Dialogue: 0,0:35:59.31,0:36:02.08,Default,,0,0,0,,教授:是的 因为你可能遇到嵌套的表达式 Dialogue: 0,0:36:02.08,0:36:04.77,Default,,0,0,0,,但是再说一遍 不要搞混 Dialogue: 0,0:36:04.77,0:36:07.98,Default,,0,0,0,,有时候人们说数据是递归的 Dialogue: 0,0:36:08.00,0:36:10.35,Default,,0,0,0,,他们说的是对于这些表结构的 Dialogue: 0,0:36:11.04,0:36:12.93,Default,,0,0,0,,一些递归运算 Dialogue: 0,0:36:12.93,0:36:13.96,Default,,0,0,0,,那和这没有关系 Dialogue: 0,0:36:13.98,0:36:16.16,Default,,0,0,0,,这只是包含子表达式的表达式而已 Dialogue: 0,0:36:20.04,0:36:23.52,Default,,0,0,0,,学生:为什么ARGL中参数的顺序是反过来的 Dialogue: 0,0:36:23.55,0:36:25.29,Default,,0,0,0,,教授:对 我应该提一嘴这个 Dialogue: 0,0:36:27.26,0:36:29.07,Default,,0,0,0,,之所以在这里把顺序反过来 Dialogue: 0,0:36:32.78,0:36:35.37,Default,,0,0,0,,你首先定义怎么算“逆序” Dialogue: 0,0:36:36.05,0:36:39.90,Default,,0,0,0,,我记得应该是牛顿 Dialogue: 0,0:36:40.91,0:36:42.41,Default,,0,0,0,,在光学发展的很早期 Dialogue: 0,0:36:42.43,0:36:43.26,Default,,0,0,0,,人们意识到 Dialogue: 0,0:36:43.61,0:36:45.36,Default,,0,0,0,,当你用眼睛通过透镜看东西的时候 Dialogue: 0,0:36:45.50,0:36:46.73,Default,,0,0,0,,图像是上下颠倒的 Dialogue: 0,0:36:46.73,0:36:48.04,Default,,0,0,0,,当时有很多的争论说 Dialogue: 0,0:36:48.04,0:36:50.48,Default,,0,0,0,,为什么不能是你眼睛平时看见的都是上下颠倒的 Dialogue: 0,0:36:51.28,0:36:52.65,Default,,0,0,0,,这实际上是一样的道理 Dialogue: 0,0:36:52.86,0:36:53.90,Default,,0,0,0,,和什么相比反过来了 Dialogue: 0,0:36:54.81,0:36:56.24,Default,,0,0,0,,我们只是需要一个约定 Dialogue: 0,0:36:56.59,0:37:00.35,Default,,0,0,0,,它们作为(4 3)出现的原因是 Dialogue: 0,0:37:00.80,0:37:02.49,Default,,0,0,0,,是因为我们从UNEV中取出东西 Dialogue: 0,0:37:02.52,0:37:04.03,Default,,0,0,0,,并且把它CONS到了ARGL上面 Dialogue: 0,0:37:04.52,0:37:06.68,Default,,0,0,0,,那么你要意识到你已经做了这个约定 Dialogue: 0,0:37:06.86,0:37:09.37,Default,,0,0,0,,你需要意识到这点的地方有 Dialogue: 0,0:37:09.98,0:37:11.23,Default,,0,0,0,,实际上有两个地方 Dialogue: 0,0:37:11.23,0:37:12.91,Default,,0,0,0,,首先是在APPLY-PRIMITIVE-OPERATOR Dialogue: 0,0:37:12.91,0:37:14.06,Default,,0,0,0,,你要意识到 Dialogue: 0,0:37:15.12,0:37:16.75,Default,,0,0,0,,参数传入基本运算的顺序 Dialogue: 0,0:37:16.78,0:37:18.72,Default,,0,0,0,,是和你的书写顺序相反的 Dialogue: 0,0:37:19.49,0:37:21.00,Default,,0,0,0,,我们之后会在另外一处看到 Dialogue: 0,0:37:21.07,0:37:23.80,Default,,0,0,0,,当你实际绑定绑定函数的形式参数时 Dialogue: 0,0:37:24.01,0:37:25.74,Default,,0,0,0,,你要意识到参数进入的顺序 Dialogue: 0,0:37:25.74,0:37:28.54,Default,,0,0,0,,和你要绑定这些变量时的顺序相反 Dialogue: 0,0:37:28.87,0:37:30.17,Default,,0,0,0,,所以如果你注意这些 Dialogue: 0,0:37:31.08,0:37:31.83,Default,,0,0,0,,就没有问题了 Dialogue: 0,0:37:31.83,0:37:33.69,Default,,0,0,0,,同样 这完全是随意的 Dialogue: 0,0:37:33.90,0:37:34.96,Default,,0,0,0,,因为如果我们做了一个 Dialogue: 0,0:37:35.10,0:37:37.15,Default,,0,0,0,,比如 给向量的各个维度赋值的迭代 Dialogue: 0,0:37:37.42,0:37:38.73,Default,,0,0,0,,它们可能会以其它顺序输出 Dialogue: 0,0:37:40.41,0:37:42.04,Default,,0,0,0,,那么这只是这个求值器 Dialogue: 0,0:37:42.06,0:37:43.53,Default,,0,0,0,,工作时的一个约定 Dialogue: 0,0:37:45.39,0:37:46.24,Default,,0,0,0,,好 我们休息一下 Dialogue: 0,0:37:46.33,0:38:02.44,Default,,0,0,0,,[音乐] Dialogue: 0,0:38:02.44,0:38:07.64,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:38:28.62,0:38:32.51,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:38:32.51,0:38:35.68,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:38:35.68,0:38:39.61,Declare,,0,0,0,,{\an2\fad(500,500)}显式控制求值器 Dialogue: 0,0:38:41.84,0:38:45.31,Default,,0,0,0,,教授:我们已经学习了表达式的求值 Dialogue: 0,0:38:45.60,0:38:47.08,Default,,0,0,0,,虽然这只是一个非常简单的例子 Dialogue: 0,0:38:48.81,0:38:50.24,Default,,0,0,0,,但从本质上来说 Dialogue: 0,0:38:50.24,0:38:52.03,Default,,0,0,0,,它跟那些大型嵌套表达式没什么不同 Dialogue: 0,0:38:52.03,0:38:54.57,Default,,0,0,0,,后者只是在栈上递归得更深而已 Dialogue: 0,0:38:55.13,0:38:56.03,Default,,0,0,0,,我现在要为你们 Dialogue: 0,0:38:56.04,0:38:56.91,Default,,0,0,0,,讲解最后一部分 Dialogue: 0,0:38:56.92,0:38:59.82,Default,,0,0,0,,我要带着你们观察EVAL-APPLY循环 Dialogue: 0,0:39:01.01,0:39:02.81,Default,,0,0,0,,我们还没有仔细研究过它 Dialogue: 0,0:39:03.00,0:39:04.75,Default,,0,0,0,,我们还没有见过一个复合程序 Dialogue: 0,0:39:05.20,0:39:07.79,Default,,0,0,0,,对它的求值会归约为 Dialogue: 0,0:39:07.92,0:39:10.11,Default,,0,0,0,,对一个过程的应用 Dialogue: 0,0:39:10.12,0:39:11.64,Default,,0,0,0,,进而是对过程体的求值 Dialogue: 0,0:39:12.44,0:39:15.88,Default,,0,0,0,,因此 假设我们有这个 Dialogue: 0,0:39:15.93,0:39:17.44,Default,,0,0,0,,假设我们正在考察 Dialogue: 0,0:39:18.07,0:39:31.60,Default,,0,0,0,,(DEFINE (F A B) (+ A B) Dialogue: 0,0:39:33.99,0:39:37.32,Default,,0,0,0,,假设我们预先定义好了这个过程 Dialogue: 0,0:39:37.69,0:39:41.64,Default,,0,0,0,,现在 我们将要求值(F X Y) Dialogue: 0,0:39:42.27,0:39:44.20,Default,,0,0,0,,基于的环境是E0 Dialogue: 0,0:39:44.35,0:39:47.02,Default,,0,0,0,,其中X=3 Y=4 Dialogue: 0,0:39:50.78,0:39:52.11,Default,,0,0,0,,当执行DEFINE的时候 Dialogue: 0,0:39:52.12,0:39:53.69,Default,,0,0,0,,还记得么 这里是一个LAMBDA Dialogue: 0,0:39:53.82,0:39:55.53,Default,,0,0,0,,LAMBDA会创建一个过程 Dialogue: 0,0:39:55.95,0:39:58.49,Default,,0,0,0,,基本上 会发生的事情是 Dialogue: 0,0:39:59.63,0:40:00.68,Default,,0,0,0,,在环境E0中 Dialogue: 0,0:40:01.00,0:40:02.65,Default,,0,0,0,,我们会得到F的绑定 Dialogue: 0,0:40:03.56,0:40:05.61,Default,,0,0,0,,它指出F是一个过程 Dialogue: 0,0:40:07.15,0:40:11.28,Default,,0,0,0,,这个过程的参数是A和B Dialogue: 0,0:40:12.57,0:40:16.19,Default,,0,0,0,,而过程体是(+ A B) Dialogue: 0,0:40:18.11,0:40:20.99,Default,,0,0,0,,这就是环境大概的样子 Dialogue: 0,0:40:21.21,0:40:22.52,Default,,0,0,0,,我们之前就定义过了 Dialogue: 0,0:40:24.22,0:40:27.28,Default,,0,0,0,,然后 我们去求值(F X Y) Dialogue: 0,0:40:28.80,0:40:30.89,Default,,0,0,0,,我们会仔细地解释每一步 Dialogue: 0,0:40:31.02,0:40:31.85,Default,,0,0,0,,就像之前那样 Dialogue: 0,0:40:31.88,0:40:33.09,Default,,0,0,0,,不会跳过重复的表达式 Dialogue: 0,0:40:33.28,0:40:34.38,Default,,0,0,0,,唯一的不同是 Dialogue: 0,0:40:34.40,0:40:36.64,Default,,0,0,0,,它的内部不再是基本的“+”过程 Dialogue: 0,0:40:37.24,0:40:38.99,Default,,0,0,0,,它还有这个东西 Dialogue: 0,0:40:41.04,0:40:43.60,Default,,0,0,0,,因此我们要进行相同的过程 Dialogue: 0,0:40:43.60,0:40:44.92,Default,,0,0,0,,只不过这次 Dialogue: 0,0:40:45.26,0:40:47.42,Default,,0,0,0,,当我们停在APPLY-DISPATCH时 Dialogue: 0,0:40:47.86,0:40:50.28,Default,,0,0,0,,FUN寄存器中不再是基本的“+”过程 Dialogue: 0,0:40:50.44,0:40:53.58,Default,,0,0,0,,而是一个代表过程的东西 Dialogue: 0,0:40:54.30,0:40:59.00,Default,,0,0,0,,其中参数为A和B Dialogue: 0,0:41:00.64,0:41:06.27,Default,,0,0,0,,过程体是(+ A B) Dialogue: 0,0:41:07.87,0:41:09.92,Default,,0,0,0,,再强调一下 我所谓的ENV Dialogue: 0,0:41:09.96,0:41:11.12,Default,,0,0,0,,是一个指向环境的指针 Dialogue: 0,0:41:11.24,0:41:13.07,Default,,0,0,0,,所以不用担心我在这里写了很多东西 Dialogue: 0,0:41:13.28,0:41:15.63,Default,,0,0,0,,这是一个指向代表过程的数据结构的指针 Dialogue: 0,0:41:17.17,0:41:19.77,Default,,0,0,0,,因此 我们现在面临着相同的情况 Dialogue: 0,0:41:20.27,0:41:22.43,Default,,0,0,0,,我们来到了APPLY-DISPATCH Dialogue: 0,0:41:23.98,0:41:26.48,Default,,0,0,0,,这是APPLY-DISPATCH的代码 Dialogue: 0,0:41:26.48,0:41:28.73,Default,,0,0,0,,上一次 我们分支跳转到了一个基本过程 Dialogue: 0,0:41:30.01,0:41:30.70,Default,,0,0,0,,然而这一次 Dialogue: 0,0:41:30.84,0:41:32.80,Default,,0,0,0,,我们遇到的是一个复合过程 Dialogue: 0,0:41:34.55,0:41:36.60,Default,,0,0,0,,因此我们要跳转到COMPOUND-APPLY Dialogue: 0,0:41:38.47,0:41:39.92,Default,,0,0,0,,COMPOUND-APPLY又是怎样定义的呢? Dialogue: 0,0:41:41.92,0:41:44.54,Default,,0,0,0,,还记得元循环求值器是怎么做的么? Dialogue: 0,0:41:45.09,0:41:47.40,Default,,0,0,0,,COMPOUND-APPLY的执行步骤则是 Dialogue: 0,0:41:49.90,0:41:51.60,Default,,0,0,0,,在一个新的环境中 Dialogue: 0,0:41:52.94,0:41:54.12,Default,,0,0,0,,求值一个过程的体 Dialogue: 0,0:41:54.12,0:41:55.87,Default,,0,0,0,,这个新的环境来自于哪里呢? Dialogue: 0,0:41:56.73,0:42:01.36,Default,,0,0,0,,我们把跟过程一同打包的环境 Dialogue: 0,0:42:03.02,0:42:05.79,Default,,0,0,0,,我们把过程的形式参数 Dialogue: 0,0:42:06.00,0:42:07.63,Default,,0,0,0,,同传递进来的实际参数给绑定起来 Dialogue: 0,0:42:09.75,0:42:11.95,Default,,0,0,0,,把这个作为新的框架 Dialogue: 0,0:42:12.59,0:42:13.79,Default,,0,0,0,,来扩展过程附带的环境 Dialogue: 0,0:42:14.99,0:42:16.08,Default,,0,0,0,,我们就是在这个环境中 Dialogue: 0,0:42:16.30,0:42:18.88,Default,,0,0,0,,求值过程的体 Dialogue: 0,0:42:20.12,0:42:24.47,Default,,0,0,0,,对吧?这就是APPLY-EVAL循环做的事 Dialogue: 0,0:42:24.47,0:42:26.25,Default,,0,0,0,,这就是APPLY回过头来调用EVAL Dialogue: 0,0:42:32.86,0:42:34.92,Default,,0,0,0,,因此 这就是我们要在COMPOUND-APPLY中要做的所有事 Dialogue: 0,0:42:36.78,0:42:37.72,Default,,0,0,0,,要怎么来实现呢? Dialogue: 0,0:42:37.72,0:42:40.97,Default,,0,0,0,,我们要构造一个新的环境 Dialogue: 0,0:42:43.55,0:42:45.64,Default,,0,0,0,,而我们构造的这个新环境呢 Dialogue: 0,0:42:46.76,0:42:48.11,Default,,0,0,0,,我们把它记作E1 Dialogue: 0,0:42:52.90,0:42:55.63,Default,,0,0,0,,E1这个环境呢 Dialogue: 0,0:42:57.31,0:42:59.15,Default,,0,0,0,,存储了过程的参数绑定 Dialogue: 0,0:42:59.21,0:43:03.26,Default,,0,0,0,,其中A=3 B=4 Dialogue: 0,0:43:04.27,0:43:05.76,Default,,0,0,0,,并且它跟E0相连 Dialogue: 0,0:43:05.76,0:43:08.08,Default,,0,0,0,,这是因为 F就是在E0中定义的 Dialogue: 0,0:43:09.27,0:43:10.27,Default,,0,0,0,,因此 在这个环境中 Dialogue: 0,0:43:10.27,0:43:11.96,Default,,0,0,0,,我们要来求值过程的体 Dialogue: 0,0:43:12.05,0:43:14.48,Default,,0,0,0,,让我们来看一看 Dialogue: 0,0:43:16.52,0:43:18.32,Default,,0,0,0,,我们来看COMPOUND-APPLY的代码 Dialogue: 0,0:43:20.30,0:43:23.47,Default,,0,0,0,,首先是给EXP寄存器赋值 Dialogue: 0,0:43:24.50,0:43:25.98,Default,,0,0,0,,所赋的值是FUN寄存器 Dialogue: 0,0:43:25.98,0:43:27.26,Default,,0,0,0,,所指向过程的体 Dialogue: 0,0:43:28.38,0:43:30.64,Default,,0,0,0,,这样 我就将过程的体 Dialogue: 0,0:43:31.29,0:43:32.33,Default,,0,0,0,,赋值给了EXP寄存器 Dialogue: 0,0:43:40.75,0:43:41.10,Default,,0,0,0,,对吧? Dialogue: 0,0:43:42.64,0:43:44.97,Default,,0,0,0,,而这将在某个环境中求值 Dialogue: 0,0:43:45.82,0:43:48.32,Default,,0,0,0,,这个环境是通过将FUN寄存器 Dialogue: 0,0:43:51.30,0:43:53.67,Default,,0,0,0,,所指向的过程中的形式参数 Dialogue: 0,0:43:53.67,0:43:56.25,Default,,0,0,0,,与实际参数绑定起来 得到的 Dialogue: 0,0:43:57.80,0:44:00.00,Default,,0,0,0,,我们先不要关系它的具体细节 Dialogue: 0,0:44:00.08,0:44:01.63,Default,,0,0,0,,你可以知道它的最后结果 Dialogue: 0,0:44:01.93,0:44:03.32,Default,,0,0,0,,因此MAKE-BINDINGS会说 Dialogue: 0,0:44:04.04,0:44:07.90,Default,,0,0,0,,过程本身就附带有一个环境 Dialogue: 0,0:44:07.96,0:44:09.32,Default,,0,0,0,,在这里 我没有写出来 Dialogue: 0,0:44:09.36,0:44:10.56,Default,,0,0,0,,但我应该说过它有一个环境 Dialogue: 0,0:44:11.30,0:44:12.73,Default,,0,0,0,,因为每个过程在构造时 Dialogue: 0,0:44:12.76,0:44:13.44,Default,,0,0,0,,都有一个环境 Dialogue: 0,0:44:13.66,0:44:14.83,Default,,0,0,0,,因此 通过这个环境 Dialogue: 0,0:44:15.68,0:44:16.35,Default,,0,0,0,,它能够知道 Dialogue: 0,0:44:16.60,0:44:18.65,Default,,0,0,0,,定义该过程时的环境是怎样的 Dialogue: 0,0:44:19.29,0:44:20.75,Default,,0,0,0,,它知道实际参数是什么 Dialogue: 0,0:44:21.83,0:44:22.49,Default,,0,0,0,,它查看ARGL Dialogue: 0,0:44:22.49,0:44:24.28,Default,,0,0,0,,然后你会在这里看到逆序的约定 Dialogue: 0,0:44:24.28,0:44:26.62,Default,,0,0,0,,它需要知道ARGL是逆序的 Dialogue: 0,0:44:27.06,0:44:28.81,Default,,0,0,0,,然后它构造了这个框架 E1 Dialogue: 0,0:44:29.99,0:44:31.08,Default,,0,0,0,,因此我们假设 Dialogue: 0,0:44:31.10,0:44:32.92,Default,,0,0,0,,MAKE-BINDINGS返回的就是这些东西 Dialogue: 0,0:44:33.36,0:44:36.22,Default,,0,0,0,,然后 它把E1赋值给ENV Dialogue: 0,0:44:41.34,0:44:42.54,Default,,0,0,0,,下一步就是 Dialogue: 0,0:44:43.95,0:44:45.84,Default,,0,0,0,,恢复CONTINUE Dialogue: 0,0:44:46.89,0:44:48.19,Default,,0,0,0,,还记得CONTINUE之前是什么吗? Dialogue: 0,0:44:48.76,0:44:50.43,Default,,0,0,0,,在最后一段中 Dialogue: 0,0:44:52.24,0:44:54.02,Default,,0,0,0,,CONTINUE被保存了 Dialogue: 0,0:44:54.02,0:44:55.18,Default,,0,0,0,,它的值是最初的'DONE Dialogue: 0,0:44:55.32,0:44:56.56,Default,,0,0,0,,这代表了 Dialogue: 0,0:44:56.73,0:44:59.44,Default,,0,0,0,,在完成这项特定应用后要做的事 Dialogue: 0,0:45:00.14,0:45:01.72,Default,,0,0,0,,这是在求值整个应用时 Dialogue: 0,0:45:01.76,0:45:03.18,Default,,0,0,0,,最先发生的事儿 Dialogue: 0,0:45:03.88,0:45:05.87,Default,,0,0,0,,现在 我们要恢复CONTINUE了 Dialogue: 0,0:45:06.86,0:45:09.55,Default,,0,0,0,,还记得APPLY-DISPATCH的约定么? Dialogue: 0,0:45:09.58,0:45:11.20,Default,,0,0,0,,它假设下一步的跳转目标 Dialogue: 0,0:45:11.23,0:45:11.98,Default,,0,0,0,,已经存放在栈上了 Dialogue: 0,0:45:12.03,0:45:13.12,Default,,0,0,0,,并且 这里确实存放在栈上了 Dialogue: 0,0:45:13.59,0:45:14.76,Default,,0,0,0,,CONTINUE被赋值成了DONE Dialogue: 0,0:45:17.82,0:45:19.90,Default,,0,0,0,,现在我们要回到EVAL-DISPATCH了 Dialogue: 0,0:45:19.94,0:45:20.84,Default,,0,0,0,,我们要再次进行寄存器设置 Dialogue: 0,0:45:20.97,0:45:24.41,Default,,0,0,0,,我们有表达式、环境、下一步 Dialogue: 0,0:45:25.80,0:45:26.89,Default,,0,0,0,,我不会再细讲了 Dialogue: 0,0:45:27.88,0:45:29.55,Default,,0,0,0,,因为它基本上就是相同的表达式 Dialogue: 0,0:45:35.40,0:45:37.79,Default,,0,0,0,,但是需要注意的是 Dialogue: 0,0:45:37.82,0:45:38.73,Default,,0,0,0,,在这个时候 Dialogue: 0,0:45:39.34,0:45:43.72,Default,,0,0,0,,我们已经归约了原始表达式(F X Y) Dialogue: 0,0:45:44.64,0:45:47.92,Default,,0,0,0,,通过在E0中求值(F X Y) Dialogue: 0,0:45:48.89,0:45:52.67,Default,,0,0,0,,将其归约为在E1中求值(+ A B) Dialogue: 0,0:45:52.78,0:45:55.92,Default,,0,0,0,,要注意 栈上并没有什么东西 对吧? Dialogue: 0,0:45:56.11,0:45:56.83,Default,,0,0,0,,这是一个归约 Dialogue: 0,0:45:56.84,0:45:59.80,Default,,0,0,0,,这个时候 机器的状态中 Dialogue: 0,0:45:59.84,0:46:01.20,Default,,0,0,0,,并没有包含 Dialogue: 0,0:46:01.76,0:46:03.71,Default,,0,0,0,,它是求值过程F的 Dialogue: 0,0:46:03.72,0:46:04.88,Default,,0,0,0,,中间状态的事实 Dialogue: 0,0:46:05.49,0:46:06.28,Default,,0,0,0,,它消失了 Dialogue: 0,0:46:07.66,0:46:09.55,Default,,0,0,0,,这里面没有积累的状态 Dialogue: 0,0:46:13.07,0:46:14.37,Default,,0,0,0,,注意 这个思想非常重要 Dialogue: 0,0:46:14.37,0:46:16.33,Default,,0,0,0,,这意味着 Dialogue: 0,0:46:16.76,0:46:18.39,Default,,0,0,0,,当我们使用代换模型时 Dialogue: 0,0:46:18.39,0:46:20.86,Default,,0,0,0,,一条表达式会归约到另一条表达式 Dialogue: 0,0:46:21.35,0:46:22.66,Default,,0,0,0,,而你不需要记住任何东西 Dialogue: 0,0:46:22.66,0:46:24.50,Default,,0,0,0,,这里 你就见到了归约的真谛 Dialogue: 0,0:46:24.56,0:46:26.16,Default,,0,0,0,,这个时候 栈上没有任何东西 Dialogue: 0,0:46:31.59,0:46:33.63,Default,,0,0,0,,这样就有一个非常重要的结果 Dialogue: 0,0:46:35.24,0:46:37.90,Default,,0,0,0,,让我们回过头来看看迭代式阶乘 Dialogue: 0,0:46:40.42,0:46:42.76,Default,,0,0,0,,还记得吗?这是某种循环 Dialogue: 0,0:46:44.01,0:46:44.88,Default,,0,0,0,,用来进行迭代 Dialogue: 0,0:46:45.13,0:46:47.36,Default,,0,0,0,,我们不断强调 它是一个迭代过程 Dialogue: 0,0:46:49.26,0:46:53.84,Default,,0,0,0,,还记得吗 Dialogue: 0,0:46:58.44,0:47:03.13,Default,,0,0,0,,我们使用它的时候 Dialogue: 0,0:47:04.35,0:47:11.07,Default,,0,0,0,,是像(FACT-ITER 5)这样调用它的 Dialogue: 0,0:47:12.36,0:47:18.67,Default,,0,0,0,,然后我们把它归约成(ITER 1 1 5) Dialogue: 0,0:47:19.03,0:47:25.15,Default,,0,0,0,,然后它归约成(ITER 1 2 5) Dialogue: 0,0:47:25.32,0:47:27.07,Default,,0,0,0,,等等等等 Dialogue: 0,0:47:27.07,0:47:28.17,Default,,0,0,0,,然后我们又说 看 Dialogue: 0,0:47:28.17,0:47:30.35,Default,,0,0,0,,为了实现这个效果 不需要存储任何东西 Dialogue: 0,0:47:31.72,0:47:32.73,Default,,0,0,0,,我们摆了摆手 说 Dialogue: 0,0:47:32.75,0:47:34.59,Default,,0,0,0,,“原则上 这不需要任何存储” Dialogue: 0,0:47:35.04,0:47:36.17,Default,,0,0,0,,现在你们发现 确实不需要 Dialogue: 0,0:47:36.17,0:47:39.09,Default,,0,0,0,,这里的每一步都是真正的归约 对吧? Dialogue: 0,0:47:39.09,0:47:42.60,Default,,0,0,0,,随着你求值这些表达式 Dialogue: 0,0:47:47.30,0:47:50.51,Default,,0,0,0,,在求值这些表达式的过程中 Dialogue: 0,0:47:50.83,0:47:51.37,Default,,0,0,0,,你会发现 Dialogue: 0,0:47:51.37,0:47:52.81,Default,,0,0,0,,栈上的这些表达式 Dialogue: 0,0:47:53.75,0:47:55.64,Default,,0,0,0,,都在一个特定的环境中 Dialogue: 0,0:47:56.42,0:48:00.02,Default,,0,0,0,,抱歉 是EXP寄存器中的表达式 Dialogue: 0,0:48:00.02,0:48:01.50,Default,,0,0,0,,是在某个特定的环境中 Dialogue: 0,0:48:01.57,0:48:02.19,Default,,0,0,0,,并且 在每一步 Dialogue: 0,0:48:02.19,0:48:04.00,Default,,0,0,0,,栈上不会积累任何东西 Dialogue: 0,0:48:04.36,0:48:05.68,Default,,0,0,0,,因为每一步都是真正的归约 Dialogue: 0,0:48:09.28,0:48:10.51,Default,,0,0,0,,因此 举例来说 Dialogue: 0,0:48:10.58,0:48:12.51,Default,,0,0,0,,说得更仔细一点 Dialogue: 0,0:48:13.46,0:48:16.88,Default,,0,0,0,,如果我从这样的一条表达式开始 Dialogue: 0,0:48:22.44,0:48:34.25,Default,,0,0,0,,比如说 在某个环境中计算(FACT-ITER 5) Dialogue: 0,0:48:42.11,0:48:46.30,Default,,0,0,0,,它将在某个时刻创建一个环境 Dialogue: 0,0:48:46.81,0:48:48.38,Default,,0,0,0,,其中N=5 Dialogue: 0,0:48:51.47,0:48:52.01,Default,,0,0,0,,我们把它写下来 Dialogue: 0,0:48:55.68,0:48:56.59,Default,,0,0,0,,然后 在某个时候 Dialogue: 0,0:48:56.89,0:49:02.56,Default,,0,0,0,,机器会归约这整个东西 Dialogue: 0,0:49:02.91,0:49:04.35,Default,,0,0,0,,将它归约为 Dialogue: 0,0:49:04.76,0:49:09.85,Default,,0,0,0,,(ITER 1 1 N) Dialogue: 0,0:49:10.68,0:49:13.72,Default,,0,0,0,,然后在环境E1中求值这条表达式 Dialogue: 0,0:49:15.87,0:49:17.16,Default,,0,0,0,,而不在栈上存放任何东西 Dialogue: 0,0:49:17.16,0:49:19.55,Default,,0,0,0,,看到了么 这时机器并不会记住 Dialogue: 0,0:49:20.71,0:49:22.50,Default,,0,0,0,,求值这条ITER表达式-- Dialogue: 0,0:49:25.00,0:49:25.63,Default,,0,0,0,,也就是某种循环-- Dialogue: 0,0:49:25.79,0:49:28.57,Default,,0,0,0,,并不是FACT-ITER的一部分 Dialogue: 0,0:49:29.68,0:49:30.59,Default,,0,0,0,,它不会记住这个事实 Dialogue: 0,0:49:30.59,0:49:33.17,Default,,0,0,0,,它只是归约了该表达式 Dialogue: 0,0:49:33.17,0:49:36.56,Default,,0,0,0,,如果我们再来看迭代式阶乘的体 Dialogue: 0,0:49:38.05,0:49:41.08,Default,,0,0,0,,这条表达式归约为了这条表达式 Dialogue: 0,0:49:42.81,0:49:43.87,Default,,0,0,0,,哦 这里漏了一个N Dialogue: 0,0:49:46.59,0:49:47.74,Default,,0,0,0,,幻灯片中的约定 Dialogue: 0,0:49:47.74,0:49:49.13,Default,,0,0,0,,和实际程序中稍有不同 Dialogue: 0,0:49:53.34,0:49:56.25,Default,,0,0,0,,那么 ITER的体又是什么? Dialogue: 0,0:49:56.28,0:49:57.40,Default,,0,0,0,,ITER的体首先是一个IF-- Dialogue: 0,0:49:58.75,0:50:00.19,Default,,0,0,0,,我不会再深入IF语句的细节了 Dialogue: 0,0:50:00.24,0:50:01.63,Default,,0,0,0,,它会对谓词求值 Dialogue: 0,0:50:02.40,0:50:03.71,Default,,0,0,0,,本例中 会返回FALSE Dialogue: 0,0:50:03.81,0:50:08.64,Default,,0,0,0,,然后这里的ITER会归约为表达式-- Dialogue: 0,0:50:09.85,0:50:20.20,Default,,0,0,0,,(ITER (* COUNTER PRODUCT) Dialogue: 0,0:50:21.62,0:50:22.24,Default,,0,0,0,,按照它代码写的-- Dialogue: 0,0:50:22.68,0:50:24.56,Default,,0,0,0,,(+ COUNTER 1)) Dialogue: 0,0:50:28.72,0:50:31.42,Default,,0,0,0,,在另外的一个环境E2中求值 Dialogue: 0,0:50:32.97,0:50:35.98,Default,,0,0,0,,其中 E2会记录着 Dialogue: 0,0:50:36.49,0:50:39.39,Default,,0,0,0,,PRODUCT和COUNTER的值 Dialogue: 0,0:50:42.92,0:50:44.33,Default,,0,0,0,,它会被归约为这条语句 Dialogue: 0,0:50:44.94,0:50:46.04,Default,,0,0,0,,它不会记得 Dialogue: 0,0:50:46.06,0:50:48.75,Default,,0,0,0,,它是一个需要返回到某处的一部分 Dialogue: 0,0:50:49.34,0:50:50.43,Default,,0,0,0,,当ITER再次调用ITER时 Dialogue: 0,0:50:50.44,0:50:52.56,Default,,0,0,0,,它会归约为另一个像这样的东西 Dialogue: 0,0:50:53.05,0:50:54.68,Default,,0,0,0,,只是会在新环境E3中 Dialogue: 0,0:50:54.83,0:50:56.67,Default,,0,0,0,,里面有关于PRODUCT和COUNTER新的绑定 Dialogue: 0,0:50:58.80,0:51:05.29,Default,,0,0,0,,因此 如果你想知道 Dialogue: 0,0:51:06.09,0:51:07.53,Default,,0,0,0,,如果你一直感到不安 Dialogue: 0,0:51:08.25,0:51:10.67,Default,,0,0,0,,不知道为什么我们说这些过程 Dialogue: 0,0:51:10.67,0:51:12.45,Default,,0,0,0,,虽然从语法上看起来是递归的 Dialogue: 0,0:51:13.20,0:51:15.69,Default,,0,0,0,,但实际上是迭代的 Dialogue: 0,0:51:15.87,0:51:17.24,Default,,0,0,0,,可以在常量空间中运行 Dialogue: 0,0:51:18.40,0:51:19.75,Default,,0,0,0,,我不知道这么说是否打消了你们的疑虑 Dialogue: 0,0:51:19.75,0:51:21.23,Default,,0,0,0,,但至少让你们知道发生了什么 Dialogue: 0,0:51:21.23,0:51:22.81,Default,,0,0,0,,这其中没有任何构造 Dialogue: 0,0:51:25.91,0:51:27.58,Default,,0,0,0,,但你也会说 这里面还是有一些构造 Dialogue: 0,0:51:27.98,0:51:30.08,Default,,0,0,0,,从原则上来说 我们也构造了环境框架 Dialogue: 0,0:51:31.71,0:51:32.37,Default,,0,0,0,,答案则是 Dialogue: 0,0:51:32.40,0:51:33.84,Default,,0,0,0,,你确实需要构建这些环境框架 Dialogue: 0,0:51:33.84,0:51:35.26,Default,,0,0,0,,但是 等你求值完毕后 Dialogue: 0,0:51:35.42,0:51:36.19,Default,,0,0,0,,不必保留它们 Dialogue: 0,0:51:36.44,0:51:37.61,Default,,0,0,0,,它们可以被废料收集 Dialogue: 0,0:51:37.92,0:51:39.47,Default,,0,0,0,,这些空间也可以被自动地重用 Dialogue: 0,0:51:40.72,0:51:42.99,Default,,0,0,0,,但你们可以看到求值器控制流 Dialogue: 0,0:51:43.25,0:51:46.12,Default,,0,0,0,,的中心思想就是进行归约 Dialogue: 0,0:51:47.02,0:51:49.29,Default,,0,0,0,,因此这些过程实际上是迭代过程 Dialogue: 0,0:51:50.13,0:51:51.38,Default,,0,0,0,,好吧 有什么问题么? Dialogue: 0,0:52:02.68,0:52:03.23,Default,,0,0,0,,好吧 课件休息吧 Dialogue: 0,0:52:04.12,0:52:24.56,Default,,0,0,0,,[音乐] Dialogue: 0,0:52:24.60,0:52:29.69,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:52:35.20,0:52:38.36,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:52:38.36,0:52:42.14,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:52:42.14,0:52:46.44,Declare,,0,0,0,,{\an2\fad(500,500)}显示控制求值器 Dialogue: 0,0:52:48.77,0:52:51.55,Default,,0,0,0,,教授:跟迭代过程形成对比的是 Dialogue: 0,0:52:52.77,0:52:54.89,Default,,0,0,0,,确实会占用空间的 Dialogue: 0,0:52:55.12,0:52:56.14,Default,,0,0,0,,递归过程 Dialogue: 0,0:52:56.17,0:52:57.29,Default,,0,0,0,,你们可以看到其中的区别 Dialogue: 0,0:52:58.03,0:53:01.20,Default,,0,0,0,,让我们来看看递归式阶乘的求值 Dialogue: 0,0:53:02.65,0:53:05.53,Default,,0,0,0,,这里的FACT-REC Dialogue: 0,0:53:05.55,0:53:07.22,Default,,0,0,0,,就是阶乘的标准定义 Dialogue: 0,0:53:07.22,0:53:10.01,Default,,0,0,0,,这个当然是一个递归过程 Dialogue: 0,0:53:10.01,0:53:12.57,Default,,0,0,0,,它的计算过程也是递归的 Dialogue: 0,0:53:13.75,0:53:16.56,Default,,0,0,0,,然后 只要把它和我们开始的方式联系起来 Dialogue: 0,0:53:16.83,0:53:20.53,Default,,0,0,0,,我们会通过代换模型发现 Dialogue: 0,0:53:20.53,0:53:21.82,Default,,0,0,0,,这是一个递归过程 Dialogue: 0,0:53:22.36,0:53:28.00,Default,,0,0,0,,因为 如果我调用(REC-FACT 5) Dialogue: 0,0:53:30.45,0:53:34.94,Default,,0,0,0,,会变成(* 5 Dialogue: 0,0:53:36.28,0:53:37.82,Default,,0,0,0,,哦 这里是FACT-REC Dialogue: 0,0:53:42.62,0:53:47.93,Default,,0,0,0,,(* 5 (FACT-REC 4)) Dialogue: 0,0:53:49.66,0:53:58.22,Default,,0,0,0,,又会变成(* 5 (* 4 (FACT-REC 3))) Dialogue: 0,0:54:00.22,0:54:08.60,Default,,0,0,0,,又会变成(* 5 (* 4 (* 3 (* ... Dialogue: 0,0:54:13.45,0:54:15.31,Default,,0,0,0,,以此类推 Dialogue: 0,0:54:15.39,0:54:17.39,Default,,0,0,0,,关键点就是 有一条链条被不断构造出来 Dialogue: 0,0:54:18.10,0:54:20.06,Default,,0,0,0,,这就在代换模型中证明了 Dialogue: 0,0:54:20.08,0:54:21.28,Default,,0,0,0,,FACT-REC是递归的 Dialogue: 0,0:54:21.52,0:54:24.18,Default,,0,0,0,,现在 让我们来看看这条构造起来的链条 Dialogue: 0,0:54:24.18,0:54:25.29,Default,,0,0,0,,它又是在机器中的什么地方? Dialogue: 0,0:54:27.68,0:54:29.95,Default,,0,0,0,,好吧 让我们想象一下要从哪里开始 Dialogue: 0,0:54:30.44,0:54:40.01,Default,,0,0,0,,我们告诉机器 求值(FACT-REC 5) Dialogue: 0,0:54:41.45,0:54:43.39,Default,,0,0,0,,基于的环境是E0 Dialogue: 0,0:54:45.08,0:54:48.97,Default,,0,0,0,,也就是定义FACT-REC时的环境 Dialogue: 0,0:54:49.55,0:54:51.23,Default,,0,0,0,,现在 我们知道最终要发生什么 Dialogue: 0,0:54:52.25,0:54:53.64,Default,,0,0,0,,首先 Dialogue: 0,0:54:53.92,0:54:55.64,Default,,0,0,0,,它会对这些东西求值 Dialogue: 0,0:54:55.68,0:54:56.99,Default,,0,0,0,,发现它是一个过程 Dialogue: 0,0:54:57.18,0:55:00.16,Default,,0,0,0,,在这里创建一个新环境E1 Dialogue: 0,0:55:00.88,0:55:03.69,Default,,0,0,0,,其中N=5 Dialogue: 0,0:55:04.33,0:55:06.54,Default,,0,0,0,,并且与E0相连 Dialogue: 0,0:55:07.80,0:55:08.97,Default,,0,0,0,,这个E0也就是 Dialogue: 0,0:55:08.99,0:55:12.30,Default,,0,0,0,,定义FACT-REC的那个环境 Dialogue: 0,0:55:14.11,0:55:15.74,Default,,0,0,0,,然后 在E1这个环境中 Dialogue: 0,0:55:15.76,0:55:17.48,Default,,0,0,0,,求值过程的体 Dialogue: 0,0:55:19.67,0:55:25.92,Default,,0,0,0,,因此 在这里求值会归约为 Dialogue: 0,0:55:27.00,0:55:28.92,Default,,0,0,0,,在E1中求值过程的体 Dialogue: 0,0:55:30.16,0:55:31.34,Default,,0,0,0,,这就需要求值IF语句 Dialogue: 0,0:55:32.17,0:55:33.53,Default,,0,0,0,,而我不会讲解IF语句的细节 Dialogue: 0,0:55:33.53,0:55:34.88,Default,,0,0,0,,IF语句会求值谓词 Dialogue: 0,0:55:34.88,0:55:37.53,Default,,0,0,0,,最后发现需要求值ELSE子句 Dialogue: 0,0:55:37.84,0:55:40.41,Default,,0,0,0,,因此 这里的整个部分 会归约为 Dialogue: 0,0:55:41.30,0:55:45.53,Default,,0,0,0,,FACT-REC的ELSE子句 Dialogue: 0,0:55:45.82,0:55:46.97,Default,,0,0,0,,也就是谓词为假的部分 Dialogue: 0,0:55:47.23,0:55:51.16,Default,,0,0,0,,整个表达式就归约为了(* N Dialogue: 0,0:55:53.07,0:55:59.96,Default,,0,0,0,,(FACT-REC (- N 1)) Dialogue: 0,0:56:03.48,0:56:05.55,Default,,0,0,0,,求值的环境是E1 Dialogue: 0,0:56:08.38,0:56:10.91,Default,,0,0,0,,因此 最初的表达式现在就会归约为 Dialogue: 0,0:56:11.04,0:56:12.52,Default,,0,0,0,,求值这样的一个表达式 Dialogue: 0,0:56:13.75,0:56:16.28,Default,,0,0,0,,而现在 我们面对的是一个应用 Dialogue: 0,0:56:16.28,0:56:17.63,Default,,0,0,0,,我们之前求值过应用 Dialogue: 0,0:56:18.22,0:56:20.25,Default,,0,0,0,,还记得要怎么求值应用么? Dialogue: 0,0:56:20.36,0:56:21.69,Default,,0,0,0,,正式求值一个应用之前 Dialogue: 0,0:56:21.74,0:56:24.81,Default,,0,0,0,,你需要把CONTINUE寄存器的值保存在栈上 Dialogue: 0,0:56:25.35,0:56:27.18,Default,,0,0,0,,此时 栈上会有一个值'DONE Dialogue: 0,0:56:29.98,0:56:32.88,Default,,0,0,0,,接下来 你要为求值子部分做准备 Dialogue: 0,0:56:35.00,0:56:37.20,Default,,0,0,0,,因此 我们在这里开始求值子部分 Dialogue: 0,0:56:39.47,0:56:41.45,Default,,0,0,0,,首先要做的是求值运算符 Dialogue: 0,0:56:44.60,0:56:46.32,Default,,0,0,0,,运算符是怎样求值的呢? Dialogue: 0,0:56:47.25,0:56:48.99,Default,,0,0,0,,我们通过一些手段 Dialogue: 0,0:56:49.00,0:56:51.04,Default,,0,0,0,,将EXP寄存器指向运算符对应的过程 Dialogue: 0,0:56:51.48,0:56:53.15,Default,,0,0,0,,并且让ENV寄存器指向求值的环境 Dialogue: 0,0:56:53.66,0:56:54.60,Default,,0,0,0,,而把CONTINUE寄存器赋值为 Dialogue: 0,0:56:54.62,0:56:56.22,Default,,0,0,0,,用于求值参数的EVAL-ARGS Dialogue: 0,0:56:56.59,0:56:57.37,Default,,0,0,0,,并且 我们把 Dialogue: 0,0:56:57.40,0:56:59.29,Default,,0,0,0,,CONTINUE的原始值保存在栈上 Dialogue: 0,0:56:59.52,0:57:01.02,Default,,0,0,0,,我们完成所有工作后 就会跳转到这个地方 Dialogue: 0,0:57:01.72,0:57:02.86,Default,,0,0,0,,在我们求值完运算符后 Dialogue: 0,0:57:03.58,0:57:05.80,Default,,0,0,0,,需要做的则是 Dialogue: 0,0:57:05.90,0:57:07.66,Default,,0,0,0,,求值对实际参数进行求值 Dialogue: 0,0:57:07.69,0:57:12.01,Default,,0,0,0,,也就是这个环境和这些参数 Dialogue: 0,0:57:12.14,0:57:13.44,Default,,0,0,0,,这些尚未求值的实际参数 Dialogue: 0,0:57:14.20,0:57:15.62,Default,,0,0,0,,它们现在都还在栈上 Dialogue: 0,0:57:15.62,0:57:18.59,Default,,0,0,0,,我们现在就要先来求值运算符 Dialogue: 0,0:57:23.26,0:57:26.73,Default,,0,0,0,,当我们从这个调用返回时 Dialogue: 0,0:57:26.92,0:57:28.64,Default,,0,0,0,,在这里 我们将要去调用EVAL-DISPATCH Dialogue: 0,0:57:29.38,0:57:30.83,Default,,0,0,0,,当我们从这个调用返回时 Dialogue: 0,0:57:31.45,0:57:32.70,Default,,0,0,0,,这个运算符所对应的值 Dialogue: 0,0:57:32.73,0:57:33.52,Default,,0,0,0,,在本例中 Dialogue: 0,0:57:33.55,0:57:35.44,Default,,0,0,0,,也就是基本的乘法过程 Dialogue: 0,0:57:36.44,0:57:37.93,Default,,0,0,0,,会存放在FUN寄存器中 Dialogue: 0,0:57:43.02,0:57:44.53,Default,,0,0,0,,我们要去求值实际参数 Dialogue: 0,0:57:44.53,0:57:45.85,Default,,0,0,0,,现在这里求值N Dialogue: 0,0:57:47.73,0:57:49.87,Default,,0,0,0,,本例中 会返回5 Dialogue: 0,0:57:50.25,0:57:52.04,Default,,0,0,0,,然后我们会把它放入ARGL寄存器 Dialogue: 0,0:57:53.00,0:57:55.88,Default,,0,0,0,,然后我们会去求值第二个运算对象 Dialogue: 0,0:57:57.46,0:58:00.48,Default,,0,0,0,,就在我们准备求值第二个运算对象之时 Dialogue: 0,0:58:00.52,0:58:02.19,Default,,0,0,0,,我会省略计算 Dialogue: 0,0:58:02.20,0:58:03.58,Default,,0,0,0,,(- N 1)之类的细节 Dialogue: 0,0:58:03.71,0:58:05.88,Default,,0,0,0,,但是 当我们去求值第二个运算对象时 Dialogue: 0,0:58:06.62,0:58:10.44,Default,,0,0,0,,会最终归约为对FACT-REC的另一个调用 Dialogue: 0,0:58:12.00,0:58:14.20,Default,,0,0,0,,现在 我们在栈上有 Dialogue: 0,0:58:16.52,0:58:19.94,Default,,0,0,0,,来自于这个组合式的运算符 Dialogue: 0,0:58:20.12,0:58:21.07,Default,,0,0,0,,以及其它的参数 Dialogue: 0,0:58:23.40,0:58:27.61,Default,,0,0,0,,现在 我们已经准备好 Dialogue: 0,0:58:28.49,0:58:29.69,Default,,0,0,0,,去调用另外的FACT-REC了 Dialogue: 0,0:58:30.20,0:58:31.43,Default,,0,0,0,,而让我们完成了这个调用以后 Dialogue: 0,0:58:31.56,0:58:33.64,Default,,0,0,0,,我们就要跳转到ACCUMULATE-LAST-ARG Dialogue: 0,0:58:34.12,0:58:35.20,Default,,0,0,0,,还记得这是做什么的么? Dialogue: 0,0:58:35.20,0:58:35.93,Default,,0,0,0,,它会说 Dialogue: 0,0:58:36.45,0:58:39.28,Default,,0,0,0,,我们会把这个调用的结果 Dialogue: 0,0:58:39.28,0:58:40.40,Default,,0,0,0,,和这个5相乘 Dialogue: 0,0:58:41.69,0:58:42.38,Default,,0,0,0,,但是请注意 Dialogue: 0,0:58:42.73,0:58:44.81,Default,,0,0,0,,我们现在处于另一个递归阶乘中 Dialogue: 0,0:58:45.72,0:58:48.92,Default,,0,0,0,,我们又要再次调用EVAL-DISPATCH Dialogue: 0,0:58:49.32,0:58:50.60,Default,,0,0,0,,然而我们并没有真正地“归约”它 Dialogue: 0,0:58:50.64,0:58:52.08,Default,,0,0,0,,因为现在栈上还有东西 Dialogue: 0,0:58:53.70,0:58:55.39,Default,,0,0,0,,栈上的这些东西说:“当你返回时” Dialogue: 0,0:58:55.40,0:58:57.52,Default,,0,0,0,,你最好把结果和放在这里的5相乘 Dialogue: 0,0:58:58.43,0:59:05.77,Default,,0,0,0,,所以当我们进行另外的调用 Dialogue: 0,0:59:07.12,0:59:08.84,Default,,0,0,0,,求值(- N 1) Dialogue: 0,0:59:09.30,0:59:11.05,Default,,0,0,0,,这会返回给我们另一个环境 Dialogue: 0,0:59:11.25,0:59:13.84,Default,,0,0,0,,其中N的新值为4 Dialogue: 0,0:59:14.60,0:59:16.22,Default,,0,0,0,,然后又将调用EVAL-DISPATCH Dialogue: 0,0:59:19.20,0:59:20.22,Default,,0,0,0,,我们又创建了另一个调用 Dialogue: 0,0:59:21.35,0:59:24.44,Default,,0,0,0,,这个4又会遇到相同的情况 Dialogue: 0,0:59:26.04,0:59:28.62,Default,,0,0,0,,我们最后会遇到对(FACT-REC N)的又一次调用 Dialogue: 0,0:59:30.02,0:59:32.68,Default,,0,0,0,,而这时候 栈上会有从最初的调用 Dialogue: 0,0:59:32.88,0:59:34.51,Default,,0,0,0,,到最近一次调用的东西 Dialogue: 0,0:59:35.36,0:59:36.91,Default,,0,0,0,,它们都在等待同一个东西 Dialogue: 0,0:59:36.91,0:59:39.16,Default,,0,0,0,,它们都要跳转到ACCUMULATE-LAST-ARG Dialogue: 0,0:59:40.51,0:59:42.94,Default,,0,0,0,,当然 当我们进行第四次调用时 Dialogue: 0,0:59:43.25,0:59:44.38,Default,,0,0,0,,会发生同样的事 Dialogue: 0,0:59:45.64,0:59:47.07,Default,,0,0,0,,如此往复 Dialogue: 0,0:59:47.30,0:59:48.60,Default,,0,0,0,,在这里 你在栈上看到的 Dialogue: 0,0:59:50.30,0:59:52.22,Default,,0,0,0,,栈上面实际存放的是 Dialogue: 0,0:59:52.22,0:59:54.59,Default,,0,0,0,,基本过程*以及5 Dialogue: 0,0:59:54.96,0:59:56.40,Default,,0,0,0,,而你要把它用来 Dialogue: 0,0:59:56.59,0:59:58.54,Default,,0,0,0,,调用ACCUMULATE-LAST-ARG Dialogue: 0,1:00:00.47,1:00:02.01,Default,,0,0,0,,就是这样 对吧? Dialogue: 0,1:00:02.01,1:00:04.75,Default,,0,0,0,,这跟它们在表达式中的顺序是一致的 Dialogue: 0,1:00:05.65,1:00:10.65,Default,,0,0,0,,实际上 你将要应用的运算符 Dialogue: 0,1:00:11.72,1:00:14.30,Default,,0,0,0,,以及当你返回时 Dialogue: 0,1:00:14.32,1:00:15.79,Default,,0,0,0,,需要去求积的参数 Dialogue: 0,1:00:15.80,1:00:16.91,Default,,0,0,0,,以及这里的括号 Dialogue: 0,1:00:16.94,1:00:18.96,Default,,0,0,0,,都在告诉你 在对它们进行积累 Dialogue: 0,1:00:19.62,1:00:21.88,Default,,0,0,0,,因此 你可以看到代换模型并不是这样的谎言 Dialogue: 0,1:00:22.56,1:00:23.63,Default,,0,0,0,,从某种意义上来说 它实际上是 Dialogue: 0,1:00:23.64,1:00:25.31,Default,,0,0,0,,存在于栈上的那些东西 Dialogue: 0,1:00:29.37,1:00:30.40,Default,,0,0,0,,好吧 从某种意义上来说 Dialogue: 0,1:00:30.81,1:00:32.48,Default,,0,0,0,,应该给你们解释了 Dialogue: 0,1:00:33.26,1:00:34.52,Default,,0,0,0,,或者 至少让你们相信 Dialogue: 0,1:00:35.93,1:00:38.72,Default,,0,0,0,,求值器会通过某些方式 Dialogue: 0,1:00:40.06,1:00:42.86,Default,,0,0,0,,迭代地去求值某些过程 Dialogue: 0,1:00:42.95,1:00:44.25,Default,,0,0,0,,而递归地去求值另外的过程 Dialogue: 0,1:00:45.26,1:00:47.45,Default,,0,0,0,,尽管从语法上看 Dialogue: 0,1:00:47.45,1:00:49.05,Default,,0,0,0,,它们都是递归过程 Dialogue: 0,1:00:49.40,1:00:50.64,Default,,0,0,0,,它又是如何做到的呢? Dialogue: 0,1:00:50.66,1:00:53.72,Default,,0,0,0,,其中的基本原因就是 Dialogue: 0,1:00:53.80,1:00:55.68,Default,,0,0,0,,求值器被设置为 Dialogue: 0,1:00:56.04,1:00:59.26,Default,,0,0,0,,只保存那些稍后会用到的东西 Dialogue: 0,1:01:01.09,1:01:04.25,Default,,0,0,0,,比如说 当你在把 Dialogue: 0,1:01:04.67,1:01:07.39,Default,,0,0,0,,在一个环境中求值表达式归约为 Dialogue: 0,1:01:07.87,1:01:09.87,Default,,0,0,0,,将某个过程应用在参数上时 Dialogue: 0,1:01:10.52,1:01:12.49,Default,,0,0,0,,它就不再需要最初的环境了 Dialogue: 0,1:01:13.37,1:01:16.65,Default,,0,0,0,,因为所需要的环境信息都被打包到 Dialogue: 0,1:01:17.88,1:01:19.36,Default,,0,0,0,,需要应用的那个过程中了 Dialogue: 0,1:01:20.75,1:01:21.61,Default,,0,0,0,,同样 类似地 Dialogue: 0,1:01:21.63,1:01:23.65,Default,,0,0,0,,当你求值一个参数表时 Dialogue: 0,1:01:23.65,1:01:25.20,Default,,0,0,0,,当你完成对表的求值时 Dialogue: 0,1:01:25.91,1:01:28.03,Default,,0,0,0,,当你求值完最后一个参数时 Dialogue: 0,1:01:28.20,1:01:31.61,Default,,0,0,0,,你就不再需要这个参数表了 对吧? Dialogue: 0,1:01:31.63,1:01:32.94,Default,,0,0,0,,你也就不再需要 Dialogue: 0,1:01:33.04,1:01:34.64,Default,,0,0,0,,求值这些参数所需的环境了 Dialogue: 0,1:01:36.69,1:01:40.89,Default,,0,0,0,,所以这个解释器如此“智能”的根本原因 Dialogue: 0,1:01:40.89,1:01:42.88,Default,,0,0,0,,根本不是因为它“智能” 只是因为它老实 Dialogue: 0,1:01:43.05,1:01:45.74,Default,,0,0,0,,它的原则就是:“只保存那些需要的” Dialogue: 0,1:01:48.70,1:01:51.00,Default,,0,0,0,,这里 让我来给你们展示 Dialogue: 0,1:01:53.07,1:01:57.20,Default,,0,0,0,,这是致使尾递归的根本原因 Dialogue: 0,1:01:58.31,1:02:00.20,Default,,0,0,0,,要记住 (RESOTRE CONTINUE)这条代码 Dialogue: 0,1:02:00.22,1:02:06.94,Default,,0,0,0,,它指的是 当我去求值过程体的时候 Dialogue: 0,1:02:08.96,1:02:11.00,Default,,0,0,0,,我应该告诉EVAL返回到 Dialogue: 0,1:02:11.25,1:02:12.54,Default,,0,0,0,,最初的求值 Dialogue: 0,1:02:12.54,1:02:14.25,Default,,0,0,0,,应该返回的地方 Dialogue: 0,1:02:15.17,1:02:15.95,Default,,0,0,0,,因此 从某种角度来说 Dialogue: 0,1:02:16.17,1:02:18.84,Default,,0,0,0,,你想知道是哪一行代码致使了尾递归 Dialogue: 0,1:02:18.89,1:02:19.44,Default,,0,0,0,,那么就是这一行 Dialogue: 0,1:02:19.92,1:02:21.53,Default,,0,0,0,,出于某些奇怪的原因 Dialogue: 0,1:02:21.77,1:02:24.80,Default,,0,0,0,,如果我想构建一个没有尾递归的求值器 Dialogue: 0,1:02:25.69,1:02:26.86,Default,,0,0,0,,我需要做的就是 Dialogue: 0,1:02:27.12,1:02:29.29,Default,,0,0,0,,在这里先不要去恢复CONTINUE Dialogue: 0,1:02:30.06,1:02:31.66,Default,,0,0,0,,而是在这里建立一个标号 Dialogue: 0,1:02:32.75,1:02:36.25,Default,,0,0,0,,用来标识完成过程应用后的返回位置 Dialogue: 0,1:02:37.64,1:02:39.71,Default,,0,0,0,,而我会把CONTINUE设置为这个标号 Dialogue: 0,1:02:39.92,1:02:41.21,Default,,0,0,0,,然后跳转到EVAL-DISPATCH Dialogue: 0,1:02:41.40,1:02:43.21,Default,,0,0,0,,然后EVAL-DISPATCH会回到这里 Dialogue: 0,1:02:43.79,1:02:44.30,Default,,0,0,0,,而这时 Dialogue: 0,1:02:44.32,1:02:45.28,Default,,0,0,0,,我会恢复CONTINUE Dialogue: 0,1:02:45.29,1:02:46.52,Default,,0,0,0,,并回到最初的返回位置 Dialogue: 0,1:02:47.92,1:02:51.00,Default,,0,0,0,,因此 这里唯一的后果就是 Dialogue: 0,1:02:51.15,1:02:52.68,Default,,0,0,0,,解释器不再是尾递归的了 Dialogue: 0,1:02:52.84,1:02:54.62,Default,,0,0,0,,它会给你完全相同的答案 Dialogue: 0,1:02:54.72,1:02:57.02,Default,,0,0,0,,只是当你执行迭代式阶乘 Dialogue: 0,1:02:57.05,1:02:58.36,Default,,0,0,0,,或者其它迭代过程时 Dialogue: 0,1:02:58.60,1:02:59.80,Default,,0,0,0,,它都会递归地去执行 Dialogue: 0,1:03:03.04,1:03:05.40,Default,,0,0,0,,然而 我对你们撒了一个小谎 Dialogue: 0,1:03:05.76,1:03:06.99,Default,,0,0,0,,因为我演示的 Dialogue: 0,1:03:07.02,1:03:08.33,Default,,0,0,0,,一个有些过于简化的解释器 Dialogue: 0,1:03:08.72,1:03:10.38,Default,,0,0,0,,这个解释器假设每个过程 Dialogue: 0,1:03:11.36,1:03:13.66,Default,,0,0,0,,只含有一条表达式 Dialogue: 0,1:03:13.89,1:03:14.54,Default,,0,0,0,,还记得吗 通常来说 Dialogue: 0,1:03:14.56,1:03:16.57,Default,,0,0,0,,过程的体是多条表达式组成的序列 Dialogue: 0,1:03:17.87,1:03:20.49,Default,,0,0,0,,所以没有什么新概念 Dialogue: 0,1:03:20.49,1:03:22.28,Default,,0,0,0,,让我来展示一下实际的求值器 Dialogue: 0,1:03:22.89,1:03:24.73,Default,,0,0,0,,是怎么来处理表达式序列的 Dialogue: 0,1:03:28.47,1:03:29.74,Default,,0,0,0,,这是现在的COMPOUND-APPLY Dialogue: 0,1:03:29.74,1:03:31.31,Default,,0,0,0,,和之前的唯一不同是 Dialogue: 0,1:03:32.07,1:03:34.33,Default,,0,0,0,,它不再直接地跳转到EVAL Dialogue: 0,1:03:35.98,1:03:38.03,Default,,0,0,0,,它先获取整个过程的体 Dialogue: 0,1:03:38.03,1:03:40.15,Default,,0,0,0,,在本例中 也就是表达式序列 Dialogue: 0,1:03:40.28,1:03:41.71,Default,,0,0,0,,然后跳转到EVAL-SEQUENCE Dialogue: 0,1:03:42.60,1:03:45.32,Default,,0,0,0,,EVAL-SEQUENCE是一个小型的循环 Dialogue: 0,1:03:46.83,1:03:49.98,Default,,0,0,0,,然后每次求值一条表达式 Dialogue: 0,1:03:52.63,1:03:53.85,Default,,0,0,0,,就是这样来求值的-- Dialogue: 0,1:03:53.90,1:03:54.94,Default,,0,0,0,,当它求值完一条表达式后 Dialogue: 0,1:03:54.97,1:03:56.86,Default,,0,0,0,,会跳转到这里 去求值下一条 Dialogue: 0,1:03:58.44,1:03:59.29,Default,,0,0,0,,当我完成了所有的求值后 Dialogue: 0,1:03:59.29,1:04:01.02,Default,,0,0,0,,我想要跳转到LAST-EXP Dialogue: 0,1:04:01.31,1:04:03.28,Default,,0,0,0,,我就只需要恢复CONTINUE寄存器 Dialogue: 0,1:04:03.92,1:04:05.28,Default,,0,0,0,,然后跳转到EVAL-DISPATCH Dialogue: 0,1:04:06.41,1:04:08.20,Default,,0,0,0,,同样的 如果你想要在这种求值器中 Dialogue: 0,1:04:08.20,1:04:10.35,Default,,0,0,0,,破坏尾递归机制 Dialogue: 0,1:04:10.64,1:04:13.71,Default,,0,0,0,,你只需要在LAST-EXP中不做特殊处理即可 Dialogue: 0,1:04:14.90,1:04:17.34,Default,,0,0,0,,也就是说 当你处理完最后一条表达式 Dialogue: 0,1:04:17.36,1:04:18.65,Default,,0,0,0,,你跳转到另外一个地方 Dialogue: 0,1:04:19.15,1:04:20.68,Default,,0,0,0,,在那个地方去恢复CONTINUE Dialogue: 0,1:04:21.90,1:04:23.26,Default,,0,0,0,,出于某些原因 Dialogue: 0,1:04:23.26,1:04:25.74,Default,,0,0,0,,很多Lisp求值器倾向于这么做 Dialogue: 0,1:04:26.55,1:04:28.44,Default,,0,0,0,,这样做的后果就是 Dialogue: 0,1:04:28.86,1:04:30.72,Default,,0,0,0,,迭代式过程也会使栈增长 Dialogue: 0,1:04:31.88,1:04:33.61,Default,,0,0,0,,还不清楚为什么会这样 Dialogue: 0,1:04:35.92,1:04:37.98,Default,,0,0,0,,好吧 我稍微来总结一下 Dialogue: 0,1:04:38.09,1:04:39.60,Default,,0,0,0,,毕竟这是一个大程序 Dialogue: 0,1:04:39.98,1:04:41.04,Default,,0,0,0,,又有很多细节 Dialogue: 0,1:04:41.12,1:04:42.25,Default,,0,0,0,,但关键点就是 Dialogue: 0,1:04:43.04,1:04:43.87,Default,,0,0,0,,从概念上来说 Dialogue: 0,1:04:44.04,1:04:46.08,Default,,0,0,0,,这跟翻译其它程序没什么不同 Dialogue: 0,1:04:47.06,1:04:48.06,Default,,0,0,0,,核心思想就是 Dialogue: 0,1:04:48.06,1:04:50.28,Default,,0,0,0,,我们已经有了通用求值器程序 Dialogue: 0,1:04:50.33,1:04:51.71,Default,,0,0,0,,一个元循环求值器 Dialogue: 0,1:04:51.87,1:04:53.07,Default,,0,0,0,,如果我们把它翻译为了Lisp Dialogue: 0,1:04:53.10,1:04:53.95,Default,,0,0,0,,那么我们就有了Lisp的所有东西 Dialogue: 0,1:04:54.33,1:04:55.15,Default,,0,0,0,,我们就是这么来做的 Dialogue: 0,1:04:57.98,1:04:59.68,Default,,0,0,0,,第二点则是 魔法消失了 Dialogue: 0,1:04:59.68,1:05:01.97,Default,,0,0,0,,这整个系统不再神秘了 对吧? Dialogue: 0,1:05:01.97,1:05:07.79,Default,,0,0,0,,原则上来说 这应该相当清楚了 Dialogue: 0,1:05:07.82,1:05:10.08,Default,,0,0,0,,只是还不太了解表结构的内存管理 Dialogue: 0,1:05:10.80,1:05:11.80,Default,,0,0,0,,我们后面会讲 Dialogue: 0,1:05:12.64,1:05:14.20,Default,,0,0,0,,这也并不困难 Dialogue: 0,1:05:15.45,1:05:16.35,Default,,0,0,0,,第三点就是 Dialogue: 0,1:05:16.35,1:05:17.52,Default,,0,0,0,,所有的这些尾递归 Dialogue: 0,1:05:18.24,1:05:21.96,Default,,0,0,0,,来自于严格的求值纪律 Dialogue: 0,1:05:22.55,1:05:24.51,Default,,0,0,0,,也就是只保存那些后面会用到的东西 Dialogue: 0,1:05:25.87,1:05:27.72,Default,,0,0,0,,而不是一些比较随意的原则 Dialogue: 0,1:05:27.76,1:05:29.86,Default,,0,0,0,,比如 无论什么时候我们调用一个子过程 Dialogue: 0,1:05:29.86,1:05:32.16,Default,,0,0,0,,我们会保存所有的寄存器并且返回 Dialogue: 0,1:05:33.94,1:05:36.49,Default,,0,0,0,,有些时候为了提效 这样做很值得 Dialogue: 0,1:05:37.15,1:05:39.96,Default,,0,0,0,,当你研究求值机器的内部原理时 Dialogue: 0,1:05:40.45,1:05:42.56,Default,,0,0,0,,这类东西就很值得去研究 Dialogue: 0,1:05:42.56,1:05:43.96,Default,,0,0,0,,因为它会带来显著的不同 Dialogue: 0,1:05:45.23,1:05:47.69,Default,,0,0,0,,我想现在基本上已经 Dialogue: 0,1:05:47.90,1:05:52.30,Default,,0,0,0,,把这个求值器讲得很清楚了 Dialogue: 0,1:05:52.56,1:05:53.90,Default,,0,0,0,,我希望你们能相信 Dialogue: 0,1:05:54.32,1:05:56.27,Default,,0,0,0,,真的有人能够 Dialogue: 0,1:05:56.84,1:05:58.56,Default,,0,0,0,,将一个Lisp求值器放在掌心之中 Dialogue: 0,1:05:59.07,1:06:00.49,Default,,0,0,0,,为了让你们死心塌地 Dialogue: 0,1:06:00.80,1:06:01.96,Default,,0,0,0,,我给你们看一个Lisp求值器 Dialogue: 0,1:06:02.54,1:06:04.06,Default,,0,0,0,,它就在我的手掌中 Dialogue: 0,1:06:06.16,1:06:10.56,Default,,0,0,0,,这块求值器芯片实际上 Dialogue: 0,1:06:10.89,1:06:13.70,Default,,0,0,0,,比我给你们展示的求值器还要复杂 Dialogue: 0,1:06:16.86,1:06:19.20,Default,,0,0,0,,这张图片效果更好 Dialogue: 0,1:06:22.07,1:06:22.57,Default,,0,0,0,,在这上面 Dialogue: 0,1:06:22.60,1:06:24.38,Default,,0,0,0,,你可以看到相同的宏观结构 Dialogue: 0,1:06:24.73,1:06:25.93,Default,,0,0,0,,这是寄存器阵列 Dialogue: 0,1:06:26.80,1:06:27.71,Default,,0,0,0,,这些是数据通路 Dialogue: 0,1:06:27.72,1:06:29.07,Default,,0,0,0,,这里有是有穷状态控制器 Dialogue: 0,1:06:29.80,1:06:31.04,Default,,0,0,0,,再强调一下 是有穷状态 Dialogue: 0,1:06:31.96,1:06:32.80,Default,,0,0,0,,全都在这里了 Dialogue: 0,1:06:32.81,1:06:34.16,Default,,0,0,0,,在另外的地方还有外部存储 Dialogue: 0,1:06:34.16,1:06:35.23,Default,,0,0,0,,用来存储数据 Dialogue: 0,1:06:35.75,1:06:37.63,Default,,0,0,0,,而这块芯片非常复杂 Dialogue: 0,1:06:37.64,1:06:39.16,Default,,0,0,0,,是因为它尝试更快地运行Lisp Dialogue: 0,1:06:39.66,1:06:42.97,Default,,0,0,0,,它具有非常非常之快的并行运算 Dialogue: 0,1:06:43.07,1:06:46.32,Default,,0,0,0,,比如说 如果你想要索引一个数组 Dialogue: 0,1:06:46.70,1:06:50.40,Default,,0,0,0,,同时又要检查该索引是否为一个整数 Dialogue: 0,1:06:50.43,1:06:52.86,Default,,0,0,0,,以及该索引没有越界 Dialogue: 0,1:06:53.04,1:06:55.02,Default,,0,0,0,,同时还要进行内存存取 Dialogue: 0,1:06:55.05,1:06:56.70,Default,,0,0,0,,它会同时进行这些事 Dialogue: 0,1:06:57.12,1:06:58.40,Default,,0,0,0,,如果这些操作都没有问题的话 Dialogue: 0,1:06:58.44,1:06:59.96,Default,,0,0,0,,最终就会在这里得到结果 Dialogue: 0,1:07:00.42,1:07:02.46,Default,,0,0,0,,因此 数据通路中大量的 Dialogue: 0,1:07:02.48,1:07:04.65,Default,,0,0,0,,复杂运算使得Lisp能够并行运行 Dialogue: 0,1:07:05.26,1:07:08.41,Default,,0,0,0,,这完全是求值Lisp的 Dialogue: 0,1:07:08.76,1:07:10.36,Default,,0,0,0,,一种无冒险的哲学 Dialogue: 0,1:07:10.64,1:07:13.20,Default,,0,0,0,,并且 这个的微指令也相当复杂 Dialogue: 0,1:07:13.45,1:07:17.56,Default,,0,0,0,,让我先看一看 Dialogue: 0,1:07:17.60,1:07:21.10,Default,,0,0,0,,这其中有大概389条 Dialogue: 0,1:07:21.68,1:07:23.85,Default,,0,0,0,,220比特的微指令 Dialogue: 0,1:07:24.07,1:07:27.94,Default,,0,0,0,,只因为这些数据通路非常复杂 Dialogue: 0,1:07:27.94,1:07:32.25,Default,,0,0,0,,整个芯片大概有89,000支晶体管 Dialogue: 0,1:07:33.56,1:07:36.86,Default,,0,0,0,,好吧 我希望通过这节课解答了大部分疑惑 Dialogue: 0,1:07:37.97,1:07:39.24,Default,,0,0,0,,也许你们想看一看这块芯片 Dialogue: 0,1:07:46.14,1:07:46.89,Default,,0,0,0,,好吧 先讲到这里 Dialogue: 0,1:07:56.46,1:07:56.75,Default,,0,0,0,,有问题吗? Dialogue: 0,1:07:59.00,1:08:00.42,Default,,0,0,0,,学生:您所讲的 听起来像是 Dialogue: 0,1:08:00.42,1:08:03.48,Default,,0,0,0,,如果把(RESTORE CONTINUE)放在合适的地方 Dialogue: 0,1:08:03.58,1:08:09.42,Default,,0,0,0,,这样之前递归求值的过程 Dialogue: 0,1:08:09.42,1:08:11.95,Default,,0,0,0,,现在就会变成迭代求值的 Dialogue: 0,1:08:12.67,1:08:15.36,Default,,0,0,0,,(意义不明) Dialogue: 0,1:08:15.60,1:08:17.54,Default,,0,0,0,,教授:我想我应该这么来说 Dialogue: 0,1:08:17.54,1:08:19.82,Default,,0,0,0,,如果把(RESTORE CONTINUE)放在了错误的位置 Dialogue: 0,1:08:20.55,1:08:25.48,Default,,0,0,0,,你就会让那些语法上看起来像递归的过程 Dialogue: 0,1:08:25.52,1:08:27.28,Default,,0,0,0,,在运行的时候不断地扩张栈 Dialogue: 0,1:08:28.64,1:08:30.52,Default,,0,0,0,,但这样是没有原因的 Dialogue: 0,1:08:33.15,1:08:35.12,Default,,0,0,0,,你可以自己去试一试 Dialogue: 0,1:08:35.15,1:08:38.09,Default,,0,0,0,,你可以在COMPOND-APPLY返回后 Dialogue: 0,1:08:38.18,1:08:40.78,Default,,0,0,0,,交换两、三条语句的顺序 Dialogue: 0,1:08:41.31,1:08:43.26,Default,,0,0,0,,那么你得到的就不再是尾递归了 Dialogue: 0,1:08:45.06,1:08:46.14,Default,,0,0,0,,我只是想强调 Dialogue: 0,1:08:46.16,1:08:47.40,Default,,0,0,0,,这其中没有什么魔法 Dialogue: 0,1:08:47.67,1:08:48.57,Default,,0,0,0,,这并不是 Dialogue: 0,1:08:49.31,1:08:52.17,Default,,0,0,0,,有什么智能的预处理程序 Dialogue: 0,1:08:52.65,1:08:55.45,Default,,0,0,0,,它会分析FACT-ITER这个程序 Dialogue: 0,1:08:55.47,1:08:56.73,Default,,0,0,0,,然后说 Dialogue: 0,1:08:57.42,1:08:58.86,Default,,0,0,0,,我注意到 Dialogue: 0,1:08:58.88,1:09:01.13,Default,,0,0,0,,完成这个调用 不需要我进行压栈 Dialogue: 0,1:09:01.13,1:09:02.88,Default,,0,0,0,,但是有些人是这么认为的 Dialogue: 0,1:09:03.76,1:09:05.38,Default,,0,0,0,,而是一种比这个还要蠢的机制 Dialogue: 0,1:09:05.38,1:09:07.50,Default,,0,0,0,,就是在合适的地方插入RESTORE指令 Dialogue: 0,1:09:08.56,1:09:09.79,Default,,0,0,0,,就可以自动地实现 Dialogue: 0,1:09:14.72,1:09:17.55,Default,,0,0,0,,学生:但这不会影响到时间复杂度 对吧? Dialogue: 0,1:09:17.58,1:09:17.87,Default,,0,0,0,,教授:不会 Dialogue: 0,1:09:18.60,1:09:21.77,Default,,0,0,0,,学生:它不会迭代地处理 Dialogue: 0,1:09:21.80,1:09:23.02,Default,,0,0,0,,而是会递归地处理 Dialogue: 0,1:09:23.02,1:09:27.34,Default,,0,0,0,,但就从完成这两个运算的时间来说 Dialogue: 0,1:09:27.37,1:09:29.22,Default,,0,0,0,,它们都是相同的 对吧? Dialogue: 0,1:09:29.47,1:09:29.76,Default,,0,0,0,,教授 :是的 Dialogue: 0,1:09:29.79,1:09:32.68,Default,,0,0,0,,尾递归不会改变任何东西的时间复杂度 Dialogue: 0,1:09:32.72,1:09:33.29,Default,,0,0,0,,因为 从某种意义上来说 Dialogue: 0,1:09:33.34,1:09:35.15,Default,,0,0,0,,两者都是相同的算法 Dialogue: 0,1:09:36.02,1:09:39.37,Default,,0,0,0,,它只是让这个过程迭代地运行 Dialogue: 0,1:09:41.00,1:09:42.64,Default,,0,0,0,,这样 当参数很大时 Dialogue: 0,1:09:42.68,1:09:44.22,Default,,0,0,0,,它不会耗尽所有的内存 Dialogue: 0,1:09:44.75,1:09:46.40,Default,,0,0,0,,因为这其中没有压栈 Dialogue: 0,1:09:48.35,1:09:50.24,Default,,0,0,0,,事实上 你们需要相信 Dialogue: 0,1:09:50.56,1:09:51.13,Default,,0,0,0,,当我们编写-- Dialogue: 0,1:09:51.64,1:09:53.78,Default,,0,0,0,,我们一直把这些代码称作“迭代” Dialogue: 0,1:09:53.93,1:09:57.99,Default,,0,0,0,,把(DEFINE (LOOP) (LOOP))称作无穷循环 Dialogue: 0,1:10:00.32,1:10:03.36,Default,,0,0,0,,这就是一个迭代 Dialogue: 0,1:10:03.65,1:10:05.66,Default,,0,0,0,,跟我们用DO语句来写无穷循环是一样的 Dialogue: 0,1:10:07.63,1:10:09.28,Default,,0,0,0,,它们只是语法上不同而已 Dialogue: 0,1:10:09.28,1:10:11.32,Default,,0,0,0,,它们实际上都是迭代 Dialogue: 0,1:10:14.73,1:10:16.08,Default,,0,0,0,,它们并不改变时间复杂度 Dialogue: 0,1:10:16.11,1:10:18.53,Default,,0,0,0,,但是它会把它们变成真正的迭代 Dialogue: 0,1:10:21.68,1:10:23.80,Default,,0,0,0,,好吧 下课 Dialogue: 0,1:10:24.25,1:10:40.73,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:10:24.25,1:10:40.73,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec9b.chn.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [Aegisub Project Garbage] Scroll Position: 707 Active Line: 1394 Video Position: 126316 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.03,0:00:00.97,Declare,,0,0,0,,{\an2\fad(500,500)}Learning-SICP 学习小组\N倾情制作 Dialogue: 0,0:00:01.05,0:00:09.09,title,,0,0,0,,{\fad(600,800)\pos(324,32)}《计算机程序的构造和解释》 Dialogue: 0,0:00:01.05,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(110.666,403.334)}翻译&&时间轴\N邓雄飞\N刘殊君 Dialogue: 0,0:00:01.05,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(534.666,404)}压制&&特效\N邓雄飞\N(Dysprosium) Dialogue: 0,0:00:01.05,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(574.667,277.333)}校对\N邓雄飞 Dialogue: 0,0:00:01.05,0:00:09.09,staff,,0,0,0,,{\fad(600,800)\pos(89.334,273.333)}特别感谢\N裘宗燕教授 Dialogue: 0,0:00:09.21,0:00:13.12,Declare,,0,0,0,,{\an2\fad(500,500)}显示控制求值器 Dialogue: 0,0:00:16.30,0:00:18.08,Default,,0,0,0,,教授:我想大家已经意识到 Dialogue: 0,0:00:20.01,0:00:22.73,Default,,0,0,0,,我们介绍了一些真正的魔法 Dialogue: 0,0:00:24.20,0:00:27.24,Default,,0,0,0,,创造新语言的魔法 Dialogue: 0,0:00:27.42,0:00:28.72,Default,,0,0,0,,用来创造全新的语言 Dialogue: 0,0:00:29.69,0:00:30.40,Default,,0,0,0,,我们学了些什么? Dialogue: 0,0:00:30.43,0:00:32.78,Default,,0,0,0,,我们学习了一门用来操作图片的Escher的语言 Dialogue: 0,0:00:38.92,0:00:41.15,Default,,0,0,0,,这门语言由Peter Henderson发明 Dialogue: 0,0:00:42.01,0:00:46.49,Default,,0,0,0,,我们还学习了数字逻辑语言 Dialogue: 0,0:00:53.16,0:00:55.55,Default,,0,0,0,,以及 我们还学习了查询语言 Dialogue: 0,0:00:59.70,0:01:00.78,Default,,0,0,0,,然而你需要明白的是 Dialogue: 0,0:01:00.81,0:01:03.10,Default,,0,0,0,,尽管它们都是“玩具级”的语言示例 Dialogue: 0,0:01:04.70,0:01:07.61,Default,,0,0,0,,但也确实是实用工具的核心 Dialogue: 0,0:01:08.25,0:01:09.48,Default,,0,0,0,,比如说 Dialogue: 0,0:01:10.12,0:01:11.18,Default,,0,0,0,,Escher图片语言 Dialogue: 0,0:01:11.20,0:01:14.33,Default,,0,0,0,,就被MIT的学生Henry Wu拿去 Dialogue: 0,0:01:14.88,0:01:16.43,Default,,0,0,0,,开发成了一门用于 Dialogue: 0,0:01:16.97,0:01:19.45,Default,,0,0,0,,为电路板布局的语言 Dialogue: 0,0:01:20.35,0:01:22.56,Default,,0,0,0,,它就是在这些结构上扩展而来 Dialogue: 0,0:01:23.24,0:01:24.65,Default,,0,0,0,,至于数字逻辑语言 Dialogue: 0,0:01:24.68,0:01:26.08,Default,,0,0,0,,Gerry教授在上课的时候也提到过 Dialogue: 0,0:01:26.43,0:01:29.92,Default,,0,0,0,,它被扩展为了一个仿真器的基础 Dialogue: 0,0:01:30.85,0:01:32.96,Default,,0,0,0,,用来设计真实的计算机 Dialogue: 0,0:01:33.46,0:01:34.32,Default,,0,0,0,,至于查询语言 Dialogue: 0,0:01:34.35,0:01:36.44,Default,,0,0,0,,当然就是Prolog语言的一种核心 Dialogue: 0,0:01:37.51,0:01:39.07,Default,,0,0,0,,我们构造的这些语言 Dialogue: 0,0:01:39.55,0:01:40.65,Default,,0,0,0,,全都是用Lisp编写 Dialogue: 0,0:01:43.63,0:01:44.59,Default,,0,0,0,,很多人问 Dialogue: 0,0:01:45.27,0:01:48.73,Default,,0,0,0,,Lisp适合用来解决哪一类问题? Dialogue: 0,0:01:48.75,0:01:49.93,Default,,0,0,0,,答案就是 Dialogue: 0,0:01:50.33,0:01:52.65,Default,,0,0,0,,Lisp不适合解决任何一类问题 Dialogue: 0,0:01:53.53,0:01:54.60,Default,,0,0,0,,Lisp擅长的是 Dialogue: 0,0:01:54.73,0:01:57.15,Default,,0,0,0,,用它来构造一门合适的语言 Dialogue: 0,0:01:57.18,0:01:58.57,Default,,0,0,0,,来解决你的问题 Dialogue: 0,0:01:59.17,0:02:00.44,Default,,0,0,0,,你应该像这样看待Lisp Dialogue: 0,0:02:01.47,0:02:03.39,Default,,0,0,0,,那么既然这些语言都基于Lisp Dialogue: 0,0:02:04.57,0:02:05.72,Default,,0,0,0,,那Lisp又基于什么? Dialogue: 0,0:02:06.97,0:02:07.88,Default,,0,0,0,,它又从何而来? Dialogue: 0,0:02:07.90,0:02:09.40,Default,,0,0,0,,这个我们也学过 Dialogue: 0,0:02:09.58,0:02:16.09,Default,,0,0,0,,我们学过元循环求值器 Dialogue: 0,0:02:21.53,0:02:23.40,Default,,0,0,0,,学习了元循环求值器后 我们说 Dialogue: 0,0:02:23.42,0:02:25.76,Default,,0,0,0,,Lisp就是基于Lisp的 Dialogue: 0,0:02:25.80,0:02:27.48,Default,,0,0,0,,而当我们研究它的时候 Dialogue: 0,0:02:28.27,0:02:29.95,Default,,0,0,0,,我们必须得施展一些真正的魔法 对吧? Dialogue: 0,0:02:29.95,0:02:31.74,Default,,0,0,0,,这又是什么意思呢? Dialogue: 0,0:02:31.74,0:02:34.96,Default,,0,0,0,,Y算子、不动点 Dialogue: 0,0:02:35.76,0:02:38.33,Default,,0,0,0,,以及这样的一个观念-- Dialogue: 0,0:02:38.36,0:02:41.44,Default,,0,0,0,,Lisp实际上是一个方程的不动点 Dialogue: 0,0:02:42.20,0:02:45.42,Default,,0,0,0,,一个通过自身来定义的有趣方程 Dialogue: 0,0:02:47.40,0:02:48.56,Default,,0,0,0,,这确实是神奇的魔法 Dialogue: 0,0:02:49.07,0:02:52.35,Default,,0,0,0,,那么今天 作为魔法的最后一步 Dialogue: 0,0:02:52.62,0:02:54.03,Default,,0,0,0,,我们要把它们通通消除掉 Dialogue: 0,0:03:06.80,0:03:07.98,Default,,0,0,0,,我们已经知道怎么做了 Dialogue: 0,0:03:09.77,0:03:10.76,Default,,0,0,0,,核心要思想是 Dialogue: 0,0:03:11.13,0:03:12.73,Default,,0,0,0,,将Lisp语言 Dialogue: 0,0:03:13.36,0:03:15.50,Default,,0,0,0,,实现在使用寄存器架构的机器上 Dialogue: 0,0:03:15.50,0:03:17.93,Default,,0,0,0,,回想一下 寄存器机器的关键之处在于 Dialogue: 0,0:03:19.60,0:03:24.68,Default,,0,0,0,,机器的一部分是确定且有穷的 Dialogue: 0,0:03:24.72,0:03:26.12,Default,,0,0,0,,它有一个有穷状态控制器 Dialogue: 0,0:03:26.12,0:03:27.87,Default,,0,0,0,,它用特定的硬件 Dialogue: 0,0:03:27.88,0:03:29.31,Default,,0,0,0,,去完成特定的事情 Dialogue: 0,0:03:30.51,0:03:31.74,Default,,0,0,0,,其中还有一些运算所需的 Dialogue: 0,0:03:31.76,0:03:33.24,Default,,0,0,0,,特殊数据通路 Dialogue: 0,0:03:33.55,0:03:35.29,Default,,0,0,0,,然后 为了实现递归 Dialogue: 0,0:03:35.53,0:03:37.60,Default,,0,0,0,,并且维持无穷的假象 Dialogue: 0,0:03:37.82,0:03:39.77,Default,,0,0,0,,还使用了一种称作“栈”的大内存 Dialogue: 0,0:03:42.06,0:03:43.72,Default,,0,0,0,,所以如果我们在 Dialogue: 0,0:03:43.92,0:03:45.50,Default,,0,0,0,,寄存器机器上实现了Lisp Dialogue: 0,0:03:47.02,0:03:48.35,Default,,0,0,0,,那么这个时候 Dialogue: 0,0:03:48.40,0:03:49.85,Default,,0,0,0,,所有的东西都会完全具体化 Dialogue: 0,0:03:49.85,0:03:51.23,Default,,0,0,0,,所有的魔法都会消除 Dialogue: 0,0:03:51.65,0:03:53.52,Default,,0,0,0,,这堂课结束时 Dialogue: 0,0:03:53.53,0:03:54.78,Default,,0,0,0,,我想让你感觉到 Dialogue: 0,0:03:55.14,0:03:59.05,Default,,0,0,0,,相对于神秘的元循环求值器 Dialogue: 0,0:03:59.67,0:04:02.60,Default,,0,0,0,,Lisp求值器是非常具体的东西 Dialogue: 0,0:04:02.85,0:04:04.57,Default,,0,0,0,,你甚至可以把它放在手心中 Dialogue: 0,0:04:04.76,0:04:06.24,Default,,0,0,0,,你可以想象一下 Dialogue: 0,0:04:06.57,0:04:07.90,Default,,0,0,0,,手里拿着一个Lisp解释器的情景 Dialogue: 0,0:04:09.63,0:04:10.94,Default,,0,0,0,,好 那我们怎么做呢? Dialogue: 0,0:04:10.95,0:04:12.76,Default,,0,0,0,,所有的原料都已经齐全 Dialogue: 0,0:04:13.96,0:04:17.45,Default,,0,0,0,,上节课Gerry教了你们 Dialogue: 0,0:04:17.60,0:04:21.47,Default,,0,0,0,,对一个任意的Lisp过程 Dialogue: 0,0:04:22.60,0:04:24.28,Default,,0,0,0,,如何手动地把它们 Dialogue: 0,0:04:24.75,0:04:26.67,Default,,0,0,0,,翻译成在寄存器机器上运行的代码 Dialogue: 0,0:04:28.20,0:04:30.52,Default,,0,0,0,,那么 要在寄存器机器上实现Lisp本身 Dialogue: 0,0:04:30.57,0:04:31.44,Default,,0,0,0,,我们只需要 Dialogue: 0,0:04:31.69,0:04:33.45,Default,,0,0,0,,把最关键的过程 Dialogue: 0,0:04:33.68,0:04:35.42,Default,,0,0,0,,也就是元循环求值器 Dialogue: 0,0:04:36.17,0:04:38.11,Default,,0,0,0,,手工翻译成寄存器机器的代码 Dialogue: 0,0:04:39.04,0:04:40.25,Default,,0,0,0,,这就实现了整个Lisp Dialogue: 0,0:04:42.14,0:04:43.00,Default,,0,0,0,,因此 我们已经知道了 Dialogue: 0,0:04:43.02,0:04:44.43,Default,,0,0,0,,实现的原理 Dialogue: 0,0:04:45.38,0:04:46.54,Default,,0,0,0,,而且实际上 Dialogue: 0,0:04:46.68,0:04:48.86,Default,,0,0,0,,这跟翻译 Dialogue: 0,0:04:50.00,0:04:53.40,Default,,0,0,0,,递归版的阶乘或斐波那契数列 Dialogue: 0,0:04:53.42,0:04:54.67,Default,,0,0,0,,没什么区别 Dialogue: 0,0:04:54.67,0:04:56.00,Default,,0,0,0,,只是它规模更大 代码更多 Dialogue: 0,0:04:56.84,0:04:58.03,Default,,0,0,0,,只是包含了更多细节 Dialogue: 0,0:04:58.04,0:04:59.66,Default,,0,0,0,,但是没有任何新的概念 Dialogue: 0,0:05:01.48,0:05:03.02,Default,,0,0,0,,当我们完成这个以后 Dialogue: 0,0:05:03.08,0:05:04.76,Default,,0,0,0,,所有的东西都变得明确了 Dialogue: 0,0:05:04.87,0:05:06.91,Default,,0,0,0,,当我们看到如何用一系列的 Dialogue: 0,0:05:06.94,0:05:10.08,Default,,0,0,0,,寄存器操作来实现Lisp之后 Dialogue: 0,0:05:10.16,0:05:11.63,Default,,0,0,0,,它就成为了我们整个课程中 Dialogue: 0,0:05:11.95,0:05:14.16,Default,,0,0,0,,最明确的Lisp模型 Dialogue: 0,0:05:14.81,0:05:16.95,Default,,0,0,0,,回忆一下 这个过程贯穿了整个课程 Dialogue: 0,0:05:16.95,0:05:18.25,Default,,0,0,0,,我们先从代换模型开始 Dialogue: 0,0:05:18.28,0:05:19.58,Default,,0,0,0,,它和代数有点相似 Dialogue: 0,0:05:20.24,0:05:21.87,Default,,0,0,0,,然后学习了环境模型 Dialogue: 0,0:05:21.88,0:05:24.00,Default,,0,0,0,,它引入了“框架”的概念 Dialogue: 0,0:05:24.03,0:05:25.31,Default,,0,0,0,,以及框架之间的关联 Dialogue: 0,0:05:26.32,0:05:27.88,Default,,0,0,0,,然后我们在元循环求值器中 Dialogue: 0,0:05:27.90,0:05:29.36,Default,,0,0,0,,把它变得更具体了 Dialogue: 0,0:05:31.05,0:05:31.64,Default,,0,0,0,,但是有的事情 Dialogue: 0,0:05:31.87,0:05:33.98,Default,,0,0,0,,元循环求值器没有告诉我们 Dialogue: 0,0:05:34.36,0:05:35.34,Default,,0,0,0,,你应该认识到这点 Dialogue: 0,0:05:36.09,0:05:38.64,Default,,0,0,0,,比如说 我们还不知道 Dialogue: 0,0:05:38.73,0:05:42.67,Default,,0,0,0,,像这里的递归阶乘过程 Dialogue: 0,0:05:45.17,0:05:47.13,Default,,0,0,0,,为何不断地申请新的空间 Dialogue: 0,0:05:47.21,0:05:47.98,Default,,0,0,0,,另一方面 Dialogue: 0,0:05:48.16,0:05:51.94,Default,,0,0,0,,一个语法上看起来像是递归的过程 Dialogue: 0,0:05:52.11,0:05:55.07,Default,,0,0,0,,比如FACT-ITER 并不占用栈空间 Dialogue: 0,0:05:55.10,0:05:59.16,Default,,0,0,0,,我们通过代换模型来证明 Dialogue: 0,0:06:00.50,0:06:01.96,Default,,0,0,0,,它不占用空间 Dialogue: 0,0:06:01.96,0:06:02.94,Default,,0,0,0,,但我们并没有说清楚 Dialogue: 0,0:06:03.42,0:06:06.76,Default,,0,0,0,,机器是如何做到这一点的 Dialogue: 0,0:06:07.31,0:06:08.91,Default,,0,0,0,,这涉及到一些细节 Dialogue: 0,0:06:09.02,0:06:11.12,Default,,0,0,0,,比如参数是如何传递给过程的 Dialogue: 0,0:06:12.48,0:06:13.69,Default,,0,0,0,,这是我们在元循环求值器中 Dialogue: 0,0:06:13.71,0:06:15.34,Default,,0,0,0,,没有看到的 Dialogue: 0,0:06:15.36,0:06:17.40,Default,,0,0,0,,完全是因为在所实现的Lisp中 Dialogue: 0,0:06:17.42,0:06:19.20,Default,,0,0,0,,把参数传递给过程的方式 Dialogue: 0,0:06:19.70,0:06:20.59,Default,,0,0,0,,取决于 Dialogue: 0,0:06:21.02,0:06:23.50,Default,,0,0,0,,外部Lisp的传参方式 Dialogue: 0,0:06:25.87,0:06:29.02,Default,,0,0,0,,但现在 这一点将变得非常明确 Dialogue: 0,0:06:30.74,0:06:31.12,Default,,0,0,0,,好 Dialogue: 0,0:06:31.23,0:06:34.30,Default,,0,0,0,,在开始研究求值器之前 Dialogue: 0,0:06:34.36,0:06:35.53,Default,,0,0,0,,我先让你们感受一下 Dialogue: 0,0:06:35.55,0:06:37.00,Default,,0,0,0,,一个完整Lisp系统是怎么样的 Dialogue: 0,0:06:37.60,0:06:39.36,Default,,0,0,0,,这样你就可以知道 我们要讨论哪部分 Dialogue: 0,0:06:39.40,0:06:40.81,Default,,0,0,0,,不讨论哪些部分 Dialogue: 0,0:06:43.18,0:06:47.42,Default,,0,0,0,,首先 这里有一个快乐的Lisp用户 Dialogue: 0,0:06:48.67,0:06:52.65,Default,,0,0,0,,他正在和一个叫做读取器的东西交流 Dialogue: 0,0:07:00.36,0:07:01.53,Default,,0,0,0,,读取器的工作是 Dialogue: 0,0:07:01.95,0:07:13.23,Default,,0,0,0,,读取用户输入的字符串 Dialogue: 0,0:07:14.17,0:07:16.62,Default,,0,0,0,,把它们转化成一种称作 Dialogue: 0,0:07:17.20,0:07:19.37,Default,,0,0,0,,表结构内存的数据结构 Dialogue: 0,0:07:30.00,0:07:31.72,Default,,0,0,0,,读取器会读取-- Dialogue: 0,0:07:32.65,0:07:33.95,Default,,0,0,0,,你敲出来的符号、括号 Dialogue: 0,0:07:34.48,0:07:37.12,Default,,0,0,0,,A和B、1和3这些东西 Dialogue: 0,0:07:37.18,0:07:39.04,Default,,0,0,0,,并把它们变成表结构 Dialogue: 0,0:07:39.15,0:07:40.54,Default,,0,0,0,,变成序对、指针等等 Dialogue: 0,0:07:42.35,0:07:43.92,Default,,0,0,0,,所以当求值器运行的时候 Dialogue: 0,0:07:43.93,0:07:45.10,Default,,0,0,0,,环境里已经不存在原始字符了 Dialogue: 0,0:07:45.85,0:07:48.16,Default,,0,0,0,,当然 在更现代的Lisp系统中 Dialogue: 0,0:07:49.00,0:07:50.44,Default,,0,0,0,,可能还有一大团东西 Dialogue: 0,0:07:50.44,0:07:52.17,Default,,0,0,0,,存在于在读取器和用户之间 Dialogue: 0,0:07:52.41,0:07:54.52,Default,,0,0,0,,最顶层首先是视窗系统 Dialogue: 0,0:07:54.77,0:07:56.03,Default,,0,0,0,,以及鼠标之类的东西 Dialogue: 0,0:07:56.28,0:07:58.20,Default,,0,0,0,,但从概念上来说 都是在输入字符 Dialogue: 0,0:07:59.93,0:08:04.32,Default,,0,0,0,,总之 读取器把它们都变成指针 Dialogue: 0,0:08:05.56,0:08:07.28,Default,,0,0,0,,指向内存中的对象 Dialogue: 0,0:08:08.27,0:08:10.94,Default,,0,0,0,,这是求值器的所能看到的东西 Dialogue: 0,0:08:15.55,0:08:16.04,Default,,0,0,0,,明白吗? Dialogue: 0,0:08:17.02,0:08:18.88,Default,,0,0,0,,求值器有一些辅助函数 Dialogue: 0,0:08:19.78,0:08:23.16,Default,,0,0,0,,包括你需要的所有基本运算 Dialogue: 0,0:08:23.16,0:08:24.91,Default,,0,0,0,,也就是说这里另有一盒子东西 Dialogue: 0,0:08:28.40,0:08:30.25,Default,,0,0,0,,比如浮点单元 Dialogue: 0,0:08:32.22,0:08:34.40,Default,,0,0,0,,或者其它类似的东西来执行这些运算 Dialogue: 0,0:08:35.39,0:08:37.68,Default,,0,0,0,,如果你需要支持更多的基本运算 Dialogue: 0,0:08:37.71,0:08:39.02,Default,,0,0,0,,你就实现更多的运算符执行器 Dialogue: 0,0:08:39.05,0:08:40.48,Default,,0,0,0,,但它们和求值器都是分离的 Dialogue: 0,0:08:42.08,0:08:43.77,Default,,0,0,0,,求值器最终算出结果 Dialogue: 0,0:08:45.16,0:08:46.76,Default,,0,0,0,,并且把它们告诉打印程序 Dialogue: 0,0:08:50.62,0:08:52.01,Default,,0,0,0,,现在 打印程序的任务就是 Dialogue: 0,0:08:52.01,0:08:54.54,Default,,0,0,0,,从求值器取得这个表结构 Dialogue: 0,0:08:55.39,0:08:56.99,Default,,0,0,0,,再把它们变回字符 Dialogue: 0,0:09:01.85,0:09:04.07,Default,,0,0,0,,然后通过某种界面 Dialogue: 0,0:09:04.28,0:09:05.66,Default,,0,0,0,,展示给用户 Dialogue: 0,0:09:08.05,0:09:11.23,Default,,0,0,0,,那么 今天我们要讨论的是这个求值器 Dialogue: 0,0:09:12.67,0:09:15.20,Default,,0,0,0,,基本运算和Lisp没有什么特别的关系 Dialogue: 0,0:09:15.20,0:09:18.14,Default,,0,0,0,,它们只取决于你怎么实现基本运算 Dialogue: 0,0:09:19.36,0:09:22.18,Default,,0,0,0,,读取器和打印程序实际上很复杂 Dialogue: 0,0:09:22.18,0:09:23.55,Default,,0,0,0,,但是我们不去讨论它们 Dialogue: 0,0:09:24.68,0:09:27.10,Default,,0,0,0,,从字符构建表的过程中 Dialogue: 0,0:09:27.10,0:09:28.92,Default,,0,0,0,,它们需要处理很多细节 Dialogue: 0,0:09:29.90,0:09:31.18,Default,,0,0,0,,说来话长 Dialogue: 0,0:09:31.18,0:09:32.32,Default,,0,0,0,,我们就不讨论它了 Dialogue: 0,0:09:32.49,0:09:33.69,Default,,0,0,0,,关于表结构内存 Dialogue: 0,0:09:34.36,0:09:35.63,Default,,0,0,0,,我们下次再来讨论 Dialogue: 0,0:09:36.93,0:09:39.72,Default,,0,0,0,,那么去除了读取和打印的细节 Dialogue: 0,0:09:40.12,0:09:41.71,Default,,0,0,0,,关于这个求值器 Dialogue: 0,0:09:41.72,0:09:43.05,Default,,0,0,0,,所剩下的唯一谜团 Dialogue: 0,0:09:43.25,0:09:45.85,Default,,0,0,0,,几乎就只有怎么在传统内存上构建表结构了 Dialogue: 0,0:09:46.65,0:09:48.20,Default,,0,0,0,,不过我们把那也放到下次来讨论 Dialogue: 0,0:09:50.58,0:09:51.04,Default,,0,0,0,,好 Dialogue: 0,0:09:53.34,0:09:56.11,Default,,0,0,0,,那么 我们先来看看这个求值器 Dialogue: 0,0:09:56.20,0:09:58.32,Default,,0,0,0,,我将要展示的这个求值器 Dialogue: 0,0:09:58.49,0:10:01.12,Default,,0,0,0,,我想 它并没有什么特别的 Dialogue: 0,0:10:01.15,0:10:04.56,Default,,0,0,0,,它只是一台专门运行Lisp的寄存器机器 Dialogue: 0,0:10:04.81,0:10:06.09,Default,,0,0,0,,它有七个寄存器 Dialogue: 0,0:10:07.88,0:10:09.26,Default,,0,0,0,,这是它的七个寄存器 Dialogue: 0,0:10:09.89,0:10:12.38,Default,,0,0,0,,这个寄存器叫EXP Dialogue: 0,0:10:14.12,0:10:15.53,Default,,0,0,0,,它的任务是存放 Dialogue: 0,0:10:16.36,0:10:18.03,Default,,0,0,0,,将要被求值的表达式 Dialogue: 0,0:10:18.37,0:10:19.80,Default,,0,0,0,,具体来说 Dialogue: 0,0:10:20.38,0:10:21.64,Default,,0,0,0,,它存放的是一个指针 Dialogue: 0,0:10:22.03,0:10:23.55,Default,,0,0,0,,指针指向存放着求值的表达式 Dialogue: 0,0:10:23.56,0:10:25.32,Default,,0,0,0,,的一处表结构内存 Dialogue: 0,0:10:26.55,0:10:27.82,Default,,0,0,0,,还有一个叫做ENV的寄存器 Dialogue: 0,0:10:28.88,0:10:30.28,Default,,0,0,0,,它存放着环境 Dialogue: 0,0:10:31.00,0:10:33.05,Default,,0,0,0,,也就是表达式的求值环境 Dialogue: 0,0:10:34.07,0:10:35.02,Default,,0,0,0,,同样的 这也是一个指针 Dialogue: 0,0:10:35.02,0:10:36.75,Default,,0,0,0,,环境是一种数据结构 Dialogue: 0,0:10:38.24,0:10:40.14,Default,,0,0,0,,这个叫做FUN的寄存器-- Dialogue: 0,0:10:40.75,0:10:42.54,Default,,0,0,0,,当你在应用一个过程时 Dialogue: 0,0:10:42.57,0:10:43.96,Default,,0,0,0,,它会存放这个过程 Dialogue: 0,0:10:44.56,0:10:46.24,Default,,0,0,0,,还有寄存器ARGL Dialogue: 0,0:10:47.36,0:10:49.34,Default,,0,0,0,,它存放的是已求值的参数 Dialogue: 0,0:10:50.54,0:10:51.60,Default,,0,0,0,,从这里开始你能看到 Dialogue: 0,0:10:51.63,0:10:53.14,Default,,0,0,0,,求值器的基本构造 Dialogue: 0,0:10:53.14,0:10:54.49,Default,,0,0,0,,回忆一下它是怎么工作的 Dialogue: 0,0:10:54.49,0:10:56.62,Default,,0,0,0,,对这一块输入表达式和环境 Dialogue: 0,0:10:57.67,0:10:59.71,Default,,0,0,0,,而这一块接收函数 Dialogue: 0,0:10:59.74,0:11:02.14,Default,,0,0,0,,或者说 过程以及参数 Dialogue: 0,0:11:03.48,0:11:06.30,Default,,0,0,0,,EVAL-APPLY循环使用这些寄存器工作 Dialogue: 0,0:11:07.40,0:11:09.69,Default,,0,0,0,,所以这些是EVAL-APPLY的基本组成部分 Dialogue: 0,0:11:10.20,0:11:10.99,Default,,0,0,0,,还有一些别的东西 Dialogue: 0,0:11:11.00,0:11:11.61,Default,,0,0,0,,比如CONTINUE寄存器 Dialogue: 0,0:11:11.61,0:11:15.34,Default,,0,0,0,,你之前已经见过CONTINUE寄存器 Dialogue: 0,0:11:15.34,0:11:18.04,Default,,0,0,0,,是如何实现递归以及栈操作的 Dialogue: 0,0:11:18.94,0:11:20.68,Default,,0,0,0,,还有个寄存器用来存放 Dialogue: 0,0:11:20.94,0:11:22.52,Default,,0,0,0,,某个求值的结果 Dialogue: 0,0:11:24.14,0:11:24.89,Default,,0,0,0,,然后 除了这些以外 Dialogue: 0,0:11:24.89,0:11:26.43,Default,,0,0,0,,还有一个临时寄存器 Dialogue: 0,0:11:26.70,0:11:27.29,Default,,0,0,0,,它就是UNEV Dialogue: 0,0:11:27.29,0:11:29.04,Default,,0,0,0,,一般来讲 在求值器中 Dialogue: 0,0:11:29.28,0:11:32.72,Default,,0,0,0,,它是用来存放正在求值的表达式 Dialogue: 0,0:11:32.89,0:11:33.95,Default,,0,0,0,,的临时部分 Dialogue: 0,0:11:33.95,0:11:35.72,Default,,0,0,0,,就是那些尚未求值的部分 Dialogue: 0,0:11:36.97,0:11:39.82,Default,,0,0,0,,那么 这就是我的七寄存器机器 Dialogue: 0,0:11:40.96,0:11:42.98,Default,,0,0,0,,当然 你可能想造一台 Dialogue: 0,0:11:42.98,0:11:44.96,Default,,0,0,0,,有更多寄存器的机器 来取得更好性能 Dialogue: 0,0:11:44.97,0:11:47.05,Default,,0,0,0,,但我们这个只是一台小型机器 Dialogue: 0,0:11:48.48,0:11:49.58,Default,,0,0,0,,那么数据通路呢? Dialogue: 0,0:11:49.78,0:11:53.66,Default,,0,0,0,,这台机器有很多专为Lisp设计的运算 Dialogue: 0,0:11:55.10,0:11:58.08,Default,,0,0,0,,这里有几条典型的数据通路 Dialogue: 0,0:12:00.12,0:12:01.04,Default,,0,0,0,,其中一条可能是 Dialogue: 0,0:12:01.37,0:12:03.40,Default,,0,0,0,,将EXP寄存器的值 Dialogue: 0,0:12:03.40,0:12:04.80,Default,,0,0,0,,赋给VAL寄存器 Dialogue: 0,0:12:05.71,0:12:08.01,Default,,0,0,0,,用我们之前的数据通路图来说 Dialogue: 0,0:12:08.03,0:12:10.81,Default,,0,0,0,,就是一条箭头上的小按钮 Dialogue: 0,0:12:11.90,0:12:13.13,Default,,0,0,0,,这还有一个更复杂的 Dialogue: 0,0:12:13.69,0:12:14.80,Default,,0,0,0,,它判断 Dialogue: 0,0:12:15.23,0:12:19.58,Default,,0,0,0,,如果EXP寄存器的内容是COND语句 Dialogue: 0,0:12:20.49,0:12:22.72,Default,,0,0,0,,那么这里就会跳转到EV-COND标号处 Dialogue: 0,0:12:23.80,0:12:26.23,Default,,0,0,0,,你可以想象出很多种实现它的方法 Dialogue: 0,0:12:26.23,0:12:28.36,Default,,0,0,0,,你可以把这个判断看作是 Dialogue: 0,0:12:28.36,0:12:29.98,Default,,0,0,0,,一个特殊意图的子过程 Dialogue: 0,0:12:30.60,0:12:33.95,Default,,0,0,0,,而条件被表示成某种数据抽象 Dialogue: 0,0:12:33.96,0:12:36.00,Default,,0,0,0,,你在这个层面上不用考虑它 Dialogue: 0,0:12:36.61,0:12:37.98,Default,,0,0,0,,那么它可以用子过程实现 Dialogue: 0,0:12:37.98,0:12:40.67,Default,,0,0,0,,如果机器通过硬件来判断表达式类型 Dialogue: 0,0:12:40.90,0:12:44.04,Default,,0,0,0,,那么某些特定比特就代表了COND语句 Dialogue: 0,0:12:45.35,0:12:46.41,Default,,0,0,0,,有很多种实现办法 Dialogue: 0,0:12:46.41,0:12:48.48,Default,,0,0,0,,它们都低于我们关注的这一层抽象 Dialogue: 0,0:12:50.19,0:12:51.71,Default,,0,0,0,,然后还有另一种操作 Dialogue: 0,0:12:51.71,0:12:53.24,Default,,0,0,0,,以及其它很多操作 Dialogue: 0,0:12:53.24,0:12:56.65,Default,,0,0,0,,把EXP的第一个子句赋值给EXP Dialogue: 0,0:12:56.84,0:12:58.89,Default,,0,0,0,,这可能是处理COND语句的一部分 Dialogue: 0,0:12:59.26,0:13:01.80,Default,,0,0,0,,同样 FIRST-SELECTOR这个选择子 Dialogue: 0,0:13:03.07,0:13:04.48,Default,,0,0,0,,我们也不需要关心它的细节 Dialogue: 0,0:13:04.49,0:13:06.46,Default,,0,0,0,,同样可以把那也看成一个子过程 Dialogue: 0,0:13:06.46,0:13:07.90,Default,,0,0,0,,用来进行一些表操作 Dialogue: 0,0:13:08.22,0:13:09.18,Default,,0,0,0,,或者你也可以想象成 Dialogue: 0,0:13:09.18,0:13:10.73,Default,,0,0,0,,一个直接构建在硬件中的东西 Dialogue: 0,0:13:12.17,0:13:13.71,Default,,0,0,0,,我之所以强调 Dialogue: 0,0:13:14.03,0:13:15.22,Default,,0,0,0,,你可以把它想象成硬件直接实现 Dialogue: 0,0:13:15.22,0:13:17.80,Default,,0,0,0,,是因为尽管有很多的运算 Dialogue: 0,0:13:18.36,0:13:19.74,Default,,0,0,0,,但也它们的数量也是固定的 Dialogue: 0,0:13:20.12,0:13:21.80,Default,,0,0,0,,我记不清有多少 大概有150个 Dialogue: 0,0:13:22.37,0:13:25.39,Default,,0,0,0,,所以假设用硬件实现它们是合理的 Dialogue: 0,0:13:26.41,0:13:27.68,Default,,0,0,0,,而这一条更加复杂 Dialogue: 0,0:13:28.27,0:13:29.47,Default,,0,0,0,,你会发现 这条涉及到 Dialogue: 0,0:13:29.47,0:13:31.10,Default,,0,0,0,,查找变量的值 Dialogue: 0,0:13:31.50,0:13:33.28,Default,,0,0,0,,它会查找某条表达式中 Dialogue: 0,0:13:33.45,0:13:36.91,Default,,0,0,0,,某个变量的值 Dialogue: 0,0:13:36.99,0:13:38.52,Default,,0,0,0,,并赋值给VAL寄存器 Dialogue: 0,0:13:39.18,0:13:40.30,Default,,0,0,0,,在本例中 也就是 Dialogue: 0,0:13:40.33,0:13:42.00,Default,,0,0,0,,在某个环境中查找变量 Dialogue: 0,0:13:42.80,0:13:44.68,Default,,0,0,0,,然后这个操作 Dialogue: 0,0:13:45.21,0:13:47.50,Default,,0,0,0,,会搜索整个环境结构 Dialogue: 0,0:13:47.52,0:13:48.97,Default,,0,0,0,,无论环境是如何表示的 Dialogue: 0,0:13:49.37,0:13:50.91,Default,,0,0,0,,并查找该变量 Dialogue: 0,0:13:52.17,0:13:53.95,Default,,0,0,0,,同样 它也不在我们思考的 Dialogue: 0,0:13:53.96,0:13:54.86,Default,,0,0,0,,的抽象层面上 Dialogue: 0,0:13:54.89,0:13:57.30,Default,,0,0,0,,它需要处理的细节是 Dialogue: 0,0:13:57.55,0:13:59.44,Default,,0,0,0,,用来表示环境的数据结构 Dialogue: 0,0:14:00.07,0:14:01.21,Default,,0,0,0,,但是不管怎么说 Dialogue: 0,0:14:01.31,0:14:03.47,Default,,0,0,0,,这就是这台寄存器机器的 Dialogue: 0,0:14:04.11,0:14:06.08,Default,,0,0,0,,有穷数量的固定操作 Dialogue: 0,0:14:08.50,0:14:11.60,Default,,0,0,0,,那么 它的整体结构是什么样子的? Dialogue: 0,0:14:11.72,0:14:13.23,Default,,0,0,0,,这有几个典型的运算 Dialogue: 0,0:14:14.76,0:14:16.33,Default,,0,0,0,,想一想 我们要做什么 Dialogue: 0,0:14:16.44,0:14:18.40,Default,,0,0,0,,我们需要把元循环求值器 Dialogue: 0,0:14:20.43,0:14:22.76,Default,,0,0,0,,这就是元循环求值器的一部分 Dialogue: 0,0:14:22.76,0:14:26.89,Default,,0,0,0,,这是书中使用抽象代码的版本 Dialogue: 0,0:14:28.22,0:14:31.53,Default,,0,0,0,,它和Gerry教授给你们展示的有些不同 Dialogue: 0,0:14:33.50,0:14:35.10,Default,,0,0,0,,关于求值器 Dialogue: 0,0:14:35.13,0:14:37.87,Default,,0,0,0,,主要需要记住的是 Dialogue: 0,0:14:37.87,0:14:40.96,Default,,0,0,0,,它是某种针对表达式类型的分情况分析 Dialogue: 0,0:14:43.76,0:14:45.90,Default,,0,0,0,,看它是否为自求值的 或被引用的 Dialogue: 0,0:14:45.92,0:14:46.86,Default,,0,0,0,,或是别的什么 Dialogue: 0,0:14:48.56,0:14:50.57,Default,,0,0,0,,而在大部分情况下 Dialogue: 0,0:14:50.86,0:14:52.96,Default,,0,0,0,,它处理的是一个过程应用 Dialogue: 0,0:14:53.55,0:14:55.36,Default,,0,0,0,,那么里面有一些技巧性的递归过程 Dialogue: 0,0:14:55.75,0:14:59.36,Default,,0,0,0,,首先 EVAL要调用它自己 Dialogue: 0,0:14:59.79,0:15:01.45,Default,,0,0,0,,来求值运算符以及 Dialogue: 0,0:15:02.14,0:15:04.04,Default,,0,0,0,,所有的运算对象 Dialogue: 0,0:15:05.88,0:15:07.40,Default,,0,0,0,,因此这些标红线的地方 Dialogue: 0,0:15:07.63,0:15:09.28,Default,,0,0,0,,就是某种在语法树上的递归 Dialogue: 0,0:15:10.94,0:15:12.27,Default,,0,0,0,,这是很简单的递归 Dialogue: 0,0:15:12.27,0:15:14.44,Default,,0,0,0,,只是EVAL在递归地遍历语法树 Dialogue: 0,0:15:14.75,0:15:15.53,Default,,0,0,0,,然后在求值器中 Dialogue: 0,0:15:15.53,0:15:16.46,Default,,0,0,0,,有一个复杂的递归 Dialogue: 0,0:15:16.49,0:15:17.92,Default,,0,0,0,,由绿线到红线的递归 Dialogue: 0,0:15:18.00,0:15:19.66,Default,,0,0,0,,由EVAL调用APPLY Dialogue: 0,0:15:22.47,0:15:26.45,Default,,0,0,0,,也就是把过程调用 Dialogue: 0,0:15:26.45,0:15:28.72,Default,,0,0,0,,归约为了 将过程应用在 Dialogue: 0,0:15:28.94,0:15:29.93,Default,,0,0,0,,实参表上 Dialogue: 0,0:15:30.37,0:15:31.76,Default,,0,0,0,,然后请看APPLY Dialogue: 0,0:15:34.77,0:15:36.67,Default,,0,0,0,,APPLY需要过程PROC和参数ARGS Dialogue: 0,0:15:37.65,0:15:39.45,Default,,0,0,0,,一般情况下 Dialogue: 0,0:15:39.48,0:15:40.81,Default,,0,0,0,,PROC都是一个复合过程 Dialogue: 0,0:15:41.05,0:15:42.19,Default,,0,0,0,,随着APPLY不断被调用 Dialogue: 0,0:15:42.25,0:15:43.15,Default,,0,0,0,,绿线处会调用红线处 Dialogue: 0,0:15:43.34,0:15:46.44,Default,,0,0,0,,APPLY被调用并再次调用EVAL Dialogue: 0,0:15:48.17,0:15:49.79,Default,,0,0,0,,EVAL会求值过程体 Dialogue: 0,0:15:50.24,0:15:52.59,Default,,0,0,0,,基于一个扩展了的环境 Dialogue: 0,0:15:53.69,0:15:55.28,Default,,0,0,0,,这个环境通过将过程的形式参数 Dialogue: 0,0:15:55.48,0:15:56.92,Default,,0,0,0,,与实际参数绑定起来而得 Dialogue: 0,0:15:59.62,0:16:00.62,Default,,0,0,0,,而对于最基本的情况 Dialogue: 0,0:16:00.64,0:16:02.52,Default,,0,0,0,,它会调用PRIMITIVE-APPLY过程 Dialogue: 0,0:16:02.73,0:16:04.70,Default,,0,0,0,,而那又不是求值器的工作了 Dialogue: 0,0:16:05.98,0:16:07.47,Default,,0,0,0,,那么像这样从红到绿 Dialogue: 0,0:16:07.47,0:16:08.40,Default,,0,0,0,,又到红又到绿 Dialogue: 0,0:16:09.79,0:16:12.72,Default,,0,0,0,,这就是EVAL-APPLY循环 Dialogue: 0,0:16:14.06,0:16:15.74,Default,,0,0,0,,这就是我们在求值器中 Dialogue: 0,0:16:16.19,0:16:17.72,Default,,0,0,0,,想要看到的东西 Dialogue: 0,0:16:19.69,0:16:21.07,Default,,0,0,0,,这样 你不会惊异于 Dialogue: 0,0:16:21.07,0:16:23.52,Default,,0,0,0,,这个求值器的两大部分 Dialogue: 0,0:16:25.34,0:16:27.04,Default,,0,0,0,,对应于EVAL-APPLY Dialogue: 0,0:16:27.47,0:16:29.44,Default,,0,0,0,,一个部分叫EVAL-DISPATCH Dialogue: 0,0:16:29.60,0:16:31.20,Default,,0,0,0,,另一部分叫做APPLY-DISPATCH Dialogue: 0,0:16:32.00,0:16:34.09,Default,,0,0,0,,在我们关注代码细节之前 Dialogue: 0,0:16:34.20,0:16:35.76,Default,,0,0,0,,理解它们的方法就是 Dialogue: 0,0:16:36.09,0:16:39.02,Default,,0,0,0,,假设这些求值器的各个部分 Dialogue: 0,0:16:39.02,0:16:40.97,Default,,0,0,0,,和这个世界中其它的部分有一些约定 Dialogue: 0,0:16:41.87,0:16:43.18,Default,,0,0,0,,在进入这些肮脏的细节前 Dialogue: 0,0:16:43.20,0:16:45.50,Default,,0,0,0,,它们在外部做了什么? Dialogue: 0,0:16:45.78,0:16:49.32,Default,,0,0,0,,针对EVAL-DISPATCH的约定 Dialogue: 0,0:16:50.01,0:16:51.40,Default,,0,0,0,,还记得吗 它对应的是EVAL Dialogue: 0,0:16:51.55,0:16:54.10,Default,,0,0,0,,它要在环境中求值一个表达式 Dialogue: 0,0:16:54.10,0:16:55.88,Default,,0,0,0,,那么 这部分要做的就是 Dialogue: 0,0:16:56.52,0:16:58.68,Default,,0,0,0,,EVAL-DISPATCH会假设当你调用它的时候 Dialogue: 0,0:16:59.68,0:17:01.48,Default,,0,0,0,,你想要求值的表达式 Dialogue: 0,0:17:01.48,0:17:02.52,Default,,0,0,0,,就存放在EXP寄存器中 Dialogue: 0,0:17:03.64,0:17:07.39,Default,,0,0,0,,而求值所基于的环境 Dialogue: 0,0:17:07.45,0:17:09.05,Default,,0,0,0,,则存放在ENV环境中 Dialogue: 0,0:17:09.56,0:17:10.67,Default,,0,0,0,,而CONTINUE寄存器用来指示 Dialogue: 0,0:17:10.84,0:17:12.46,Default,,0,0,0,,当求值完成后 Dialogue: 0,0:17:12.52,0:17:13.92,Default,,0,0,0,,机器需要去向何方 Dialogue: 0,0:17:17.28,0:17:19.18,Default,,0,0,0,,EVAL-DISPATCH的约定实际上就是 Dialogue: 0,0:17:19.28,0:17:21.26,Default,,0,0,0,,它会执行实际的求值 Dialogue: 0,0:17:21.40,0:17:22.46,Default,,0,0,0,,并且在求值结束后 Dialogue: 0,0:17:23.28,0:17:25.63,Default,,0,0,0,,它会转到由CONTINUE寄存器指定的位置 Dialogue: 0,0:17:26.61,0:17:29.16,Default,,0,0,0,,求值的结果会存放在VAL寄存器中 Dialogue: 0,0:17:29.82,0:17:30.96,Default,,0,0,0,,需要提醒的是 Dialogue: 0,0:17:30.99,0:17:32.91,Default,,0,0,0,,它对其余的寄存器 Dialogue: 0,0:17:32.96,0:17:34.60,Default,,0,0,0,,不做任何承诺 Dialogue: 0,0:17:35.23,0:17:36.81,Default,,0,0,0,,其它所有的寄存器都可能被修改 Dialogue: 0,0:17:37.49,0:17:40.14,Default,,0,0,0,,那么这是一部分 Dialogue: 0,0:17:41.55,0:17:43.48,Default,,0,0,0,,这些部分一块构成了APPLY-DISPATCH Dialogue: 0,0:17:43.52,0:17:44.92,Default,,0,0,0,,它们对应了APPLY Dialogue: 0,0:17:46.09,0:17:48.43,Default,,0,0,0,,用来把一个过程应用在一些参数上 Dialogue: 0,0:17:48.73,0:17:51.43,Default,,0,0,0,,因此它假设ARGL寄存器 Dialogue: 0,0:17:51.68,0:17:53.77,Default,,0,0,0,,存放着求值后的参数列表 Dialogue: 0,0:17:54.54,0:17:55.96,Default,,0,0,0,,FUN寄存器存放着那个过程 Dialogue: 0,0:17:57.22,0:17:58.83,Default,,0,0,0,,它们对应于元循环求值器中的 Dialogue: 0,0:17:58.94,0:18:01.36,Default,,0,0,0,,参数应用部分 Dialogue: 0,0:18:03.97,0:18:06.04,Default,,0,0,0,,在我们的这个求值器中 Dialogue: 0,0:18:06.06,0:18:07.58,Default,,0,0,0,,我们APPLY时采用的约定是 Dialogue: 0,0:18:07.72,0:18:08.97,Default,,0,0,0,,当APPLY完成后-- Dialogue: 0,0:18:09.47,0:18:11.20,Default,,0,0,0,,机器应该跳转到 Dialogue: 0,0:18:11.79,0:18:13.45,Default,,0,0,0,,的下一个地方应该是 Dialogue: 0,0:18:13.55,0:18:15.92,Default,,0,0,0,,APPLY-DISPATCH被调用时的栈顶元素 Dialogue: 0,0:18:17.07,0:18:21.24,Default,,0,0,0,,这只是针对这台机器的约定 Dialogue: 0,0:18:21.84,0:18:23.70,Default,,0,0,0,,现在已经给出了APPLY的所有约定 Dialogue: 0,0:18:23.93,0:18:25.37,Default,,0,0,0,,它会去执行应用 Dialogue: 0,0:18:25.54,0:18:27.85,Default,,0,0,0,,这个应用的结果将会保存在VAL寄存器中 Dialogue: 0,0:18:28.89,0:18:29.95,Default,,0,0,0,,栈会被弹出 Dialogue: 0,0:18:31.12,0:18:31.66,Default,,0,0,0,,同样的 Dialogue: 0,0:18:31.71,0:18:34.03,Default,,0,0,0,,其它所有寄存器的内容都可能被修改 Dialogue: 0,0:18:34.84,0:18:37.82,Default,,0,0,0,,那么 这就是这台机器的基本结构 Dialogue: 0,0:18:38.99,0:18:41.50,Default,,0,0,0,,我们先课间休息一下 Dialogue: 0,0:18:41.52,0:18:42.70,Default,,0,0,0,,然后再来研究一个真实的例子 Dialogue: 0,0:18:43.53,0:19:08.11,Default,,0,0,0,,[音乐] Dialogue: 0,0:19:08.14,0:19:13.47,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:19:33.10,0:19:35.87,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:19:35.87,0:19:40.38,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:19:40.38,0:19:45.29,Declare,,0,0,0,,{\an2\fad(500,500)}显式控制求值器 Dialogue: 0,0:19:47.85,0:19:49.95,Default,,0,0,0,,现在 我们来研究一下这台寄存器机器 Dialogue: 0,0:19:50.41,0:19:51.77,Default,,0,0,0,,我们一步一步地跟进 Dialogue: 0,0:19:52.27,0:19:56.94,Default,,0,0,0,,具体到每一处细节 Dialogue: 0,0:19:57.07,0:19:58.52,Default,,0,0,0,,这样你就能完全具体地看到 Dialogue: 0,0:19:58.86,0:20:01.24,Default,,0,0,0,,表达式是如何求值的 Dialogue: 0,0:20:03.15,0:20:06.86,Default,,0,0,0,,那么我们从一个非常简单的表达式开始 Dialogue: 0,0:20:07.45,0:20:13.52,Default,,0,0,0,,我们要求值的表达式只有一个1 Dialogue: 0,0:20:18.77,0:20:20.40,Default,,0,0,0,,我们需要一个环境 Dialogue: 0,0:20:20.43,0:20:22.35,Default,,0,0,0,,因此我们假设某处有一个环境 Dialogue: 0,0:20:22.38,0:20:23.39,Default,,0,0,0,,我们把它记作E0 Dialogue: 0,0:20:30.06,0:20:34.56,Default,,0,0,0,,由于我们之后也要用到它 Dialogue: 0,0:20:35.62,0:20:37.04,Default,,0,0,0,,而且显然不需要任何东西 Dialogue: 0,0:20:37.07,0:20:37.93,Default,,0,0,0,,就可以求值1 Dialogue: 0,0:20:38.36,0:20:39.45,Default,,0,0,0,,但是为了方便以后引用 Dialogue: 0,0:20:39.45,0:20:40.94,Default,,0,0,0,,我们假设环境E0中有 Dialogue: 0,0:20:41.44,0:20:43.15,Default,,0,0,0,,X=3 Dialogue: 0,0:20:43.72,0:20:45.37,Default,,0,0,0,,Y=4 Dialogue: 0,0:20:48.27,0:20:48.78,Default,,0,0,0,,好吗? Dialogue: 0,0:20:49.14,0:20:50.12,Default,,0,0,0,,现在 我们要做的就是 Dialogue: 0,0:20:50.51,0:20:54.59,Default,,0,0,0,,在这个环境中求值表达式1 Dialogue: 0,0:20:55.74,0:20:58.54,Default,,0,0,0,,这样 ENV寄存器就存放了一个指针 Dialogue: 0,0:20:59.65,0:21:01.04,Default,,0,0,0,,指向这个环境E0 Dialogue: 0,0:21:03.31,0:21:05.65,Default,,0,0,0,,那么我们来看它是怎么进行的 Dialogue: 0,0:21:05.65,0:21:07.26,Default,,0,0,0,,我要步步跟进代码 Dialogue: 0,0:21:08.26,0:21:10.00,Default,,0,0,0,,这样的话 我会充当控制器 Dialogue: 0,0:21:10.04,0:21:10.80,Default,,0,0,0,,现在我需要的是-- Dialogue: 0,0:21:11.02,0:21:12.49,Default,,0,0,0,,由于这台机器已经变得相当复杂 Dialogue: 0,0:21:12.98,0:21:16.83,Default,,0,0,0,,我需要一个小小的执行单元 Dialogue: 0,0:21:16.83,0:21:18.16,Default,,0,0,0,,那么请上我们的执行单元 Dialogue: 0,0:21:22.62,0:21:23.12,Default,,0,0,0,,好的 Dialogue: 0,0:21:28.59,0:21:29.96,Default,,0,0,0,,好 现在我们要开始了 Dialogue: 0,0:21:30.53,0:21:32.48,Default,,0,0,0,,我们要从EVAL-DISPATCH启动机器 Dialogue: 0,0:21:33.26,0:21:34.62,Default,,0,0,0,,这是整个过程的开始 Dialogue: 0,0:21:35.87,0:21:38.75,Default,,0,0,0,,EVAL-DISPATCH会查看表达式并进行分派 Dialogue: 0,0:21:39.32,0:21:40.06,Default,,0,0,0,,就像EVAL Dialogue: 0,0:21:40.87,0:21:42.00,Default,,0,0,0,,先从第一句看起 Dialogue: 0,0:21:42.04,0:21:47.95,Default,,0,0,0,,先判断表达式是不是自求值的 Dialogue: 0,0:21:47.95,0:21:49.96,Default,,0,0,0,,SELF-EVALUATING?是我们放入机器的 Dialogue: 0,0:21:49.96,0:21:51.10,Default,,0,0,0,,一个抽象过程 Dialogue: 0,0:21:52.22,0:21:53.51,Default,,0,0,0,,它对于数字1来说为真 Dialogue: 0,0:21:53.64,0:21:55.52,Default,,0,0,0,,因此跳转的目的是EV-SELF-EVAL Dialogue: 0,0:21:56.77,0:21:58.20,Default,,0,0,0,,那么我作为控制器 Dialogue: 0,0:21:58.22,0:21:59.55,Default,,0,0,0,,会去查看EV-SELF-EVAL Dialogue: 0,0:22:00.06,0:22:01.07,Default,,0,0,0,,所以我们要跳到那里 Dialogue: 0,0:22:02.60,0:22:04.76,Default,,0,0,0,,EV-SELF-EAVL的代码是-- Dialogue: 0,0:22:06.54,0:22:09.90,Default,,0,0,0,,把EXP寄存器的值赋值给VAL寄存器 Dialogue: 0,0:22:15.24,0:22:16.51,Default,,0,0,0,,我遇到一个BUG Dialogue: 0,0:22:17.93,0:22:20.59,Default,,0,0,0,,因为我初始化机器的时候没有做一件事情 Dialogue: 0,0:22:21.62,0:22:22.89,Default,,0,0,0,,也就是指定当它执行完毕后 Dialogue: 0,0:22:22.91,0:22:24.19,Default,,0,0,0,,应该做什么 Dialogue: 0,0:22:24.65,0:22:26.83,Default,,0,0,0,,所以在启动机器的时候 Dialogue: 0,0:22:27.37,0:22:29.85,Default,,0,0,0,,应该将CONTINUE寄存器设置为DONE Dialogue: 0,0:22:31.18,0:22:33.26,Default,,0,0,0,,所以我们给VAL赋值 Dialogue: 0,0:22:33.37,0:22:35.56,Default,,0,0,0,,然后执行(GOTO (FETCH CONTINUE)) Dialogue: 0,0:22:35.63,0:22:36.56,Default,,0,0,0,,并且修改-- Dialogue: 0,0:22:38.09,0:22:38.60,Default,,0,0,0,,好 Dialogue: 0,0:22:40.00,0:22:41.16,Default,,0,0,0,,好 我们来看一个更复杂的 Dialogue: 0,0:22:42.16,0:22:43.45,Default,,0,0,0,,我们先重置机器 Dialogue: 0,0:22:44.86,0:22:50.88,Default,,0,0,0,,然后把X放入EXP寄存器中 Dialogue: 0,0:22:56.71,0:22:58.20,Default,,0,0,0,,重新从EVAL-DISPATCH开始 Dialogue: 0,0:22:59.61,0:23:01.69,Default,,0,0,0,,先检查它是自求值的么? Dialogue: 0,0:23:01.69,0:23:02.03,Default,,0,0,0,,不是 Dialogue: 0,0:23:02.65,0:23:03.61,Default,,0,0,0,,它是变量吗 Dialogue: 0,0:23:04.63,0:23:05.02,Default,,0,0,0,,是的 Dialogue: 0,0:23:05.56,0:23:07.07,Default,,0,0,0,,我们跳转到EV-VARIABLE Dialogue: 0,0:23:08.38,0:23:10.97,Default,,0,0,0,,它说:查找EXP寄存器中变量的值 Dialogue: 0,0:23:12.13,0:23:15.69,Default,,0,0,0,,并把它赋值给VAL寄存器 Dialogue: 0,0:23:21.23,0:23:22.91,Default,,0,0,0,,(GOTO (FETCH CONTINUE)) Dialogue: 0,0:23:23.96,0:23:24.48,Default,,0,0,0,,Sussman教授:DONE Dialogue: 0,0:23:27.61,0:23:28.09,Default,,0,0,0,,Abelson教授:好 Dialogue: 0,0:23:29.31,0:23:30.76,Default,,0,0,0,,这些都是最基本的理念 Dialogue: 0,0:23:31.33,0:23:32.65,Default,,0,0,0,,这是这台机器上的简单运算 Dialogue: 0,0:23:32.68,0:23:35.07,Default,,0,0,0,,现在 我们来做些有意义的事情 Dialogue: 0,0:23:36.07,0:23:38.64,Default,,0,0,0,,我们看这条表达式 Dialogue: 0,0:23:43.58,0:23:47.93,Default,,0,0,0,,(+ X Y) Dialogue: 0,0:23:49.69,0:23:51.28,Default,,0,0,0,,现在我们会看到 Dialogue: 0,0:23:52.41,0:23:54.01,Default,,0,0,0,,如何展开这些表达式树 Dialogue: 0,0:23:57.13,0:23:58.68,Default,,0,0,0,,我们再次从EVAL-DISPATCH开始 Dialogue: 0,0:24:04.61,0:24:05.80,Default,,0,0,0,,是自求值的吗? Dialogue: 0,0:24:05.95,0:24:06.52,Default,,0,0,0,,不是 Dialogue: 0,0:24:06.70,0:24:07.71,Default,,0,0,0,,是变量吗?不是 Dialogue: 0,0:24:07.82,0:24:08.99,Default,,0,0,0,,它也不是我在这里 Dialogue: 0,0:24:08.99,0:24:10.12,Default,,0,0,0,,没有列出的特殊形式 Dialogue: 0,0:24:10.27,0:24:12.48,Default,,0,0,0,,比如引用、LAMBDA、SET! 等等 Dialogue: 0,0:24:12.48,0:24:13.08,Default,,0,0,0,,它都不是 Dialogue: 0,0:24:13.26,0:24:14.73,Default,,0,0,0,,它是一个过程应用 Dialogue: 0,0:24:15.88,0:24:17.42,Default,,0,0,0,,所以我们要跳转到EV-APPLICATION Dialogue: 0,0:24:19.97,0:24:24.94,Default,,0,0,0,,回忆一下EV-APPLICATION要做什么 Dialogue: 0,0:24:25.58,0:24:28.19,Default,,0,0,0,,它先要求值运算符 Dialogue: 0,0:24:28.27,0:24:31.40,Default,,0,0,0,,然后求值运算对象 Dialogue: 0,0:24:32.36,0:24:34.30,Default,,0,0,0,,然后再进行应用 Dialogue: 0,0:24:35.06,0:24:36.09,Default,,0,0,0,,所以在我们开始之前 Dialogue: 0,0:24:36.94,0:24:37.88,Default,,0,0,0,,由于我们是严格按照代码来执行的 Dialogue: 0,0:24:37.88,0:24:38.88,Default,,0,0,0,,我们最好记住 Dialogue: 0,0:24:39.07,0:24:40.54,Default,,0,0,0,,在这个环境中的某处 Dialogue: 0,0:24:40.57,0:24:42.36,Default,,0,0,0,,连接到了另一个环境 Dialogue: 0,0:24:43.98,0:24:44.94,Default,,0,0,0,,其中符号'+ Dialogue: 0,0:24:45.72,0:24:49.16,Default,,0,0,0,,跟基本的加法过程绑定在了一起 Dialogue: 0,0:24:51.63,0:24:54.03,Default,,0,0,0,,这样 求值+时就不会导致“变量未定义” Dialogue: 0,0:24:55.34,0:24:56.84,Default,,0,0,0,,现在我们来到了EV-APPLICATION Dialogue: 0,0:24:59.85,0:25:04.32,Default,,0,0,0,,把EXP寄存器对应的运算对象 Dialogue: 0,0:25:04.92,0:25:06.89,Default,,0,0,0,,赋值给UNEV寄存器 Dialogue: 0,0:25:07.61,0:25:08.83,Default,,0,0,0,,这些是运算对象 Dialogue: 0,0:25:09.23,0:25:11.66,Default,,0,0,0,,UNEV这个临时寄存器 Dialogue: 0,0:25:11.68,0:25:12.59,Default,,0,0,0,,就是用来暂存它们的 Dialogue: 0,0:25:13.22,0:25:13.86,Default,,0,0,0,,Sussman教授:我正在赋值 Dialogue: 0,0:25:14.28,0:25:16.62,Default,,0,0,0,,Abelson教授:把运算符赋值给EXP寄存器 Dialogue: 0,0:25:18.07,0:25:20.09,Default,,0,0,0,,注意 现在我们已经修改了EXP中的表达式 Dialogue: 0,0:25:21.84,0:25:23.61,Default,,0,0,0,,但是我们需要的部分在UNEV中 Dialogue: 0,0:25:25.82,0:25:26.81,Default,,0,0,0,,现在 我们要准备好 Dialogue: 0,0:25:26.81,0:25:28.59,Default,,0,0,0,,去递归地求值运算符 Dialogue: 0,0:25:28.75,0:25:31.69,Default,,0,0,0,,把CONTINUE寄存器保存在栈上 Dialogue: 0,0:25:34.86,0:25:36.09,Default,,0,0,0,,保存ENV Dialogue: 0,0:25:40.48,0:25:41.69,Default,,0,0,0,,保存UNEV Dialogue: 0,0:25:49.53,0:25:54.64,Default,,0,0,0,,把标号EVAL-ARGS赋值给CONTINUE寄存器 Dialogue: 0,0:26:01.40,0:26:01.95,Default,,0,0,0,,我们做了什么 Dialogue: 0,0:26:01.95,0:26:04.38,Default,,0,0,0,,我们为递归调用做了必要的准备 Dialogue: 0,0:26:04.38,0:26:05.88,Default,,0,0,0,,我们要开始执行EVAL-DISPATCH Dialogue: 0,0:26:06.28,0:26:08.83,Default,,0,0,0,,我们为递归调用EVAL-DISPATCH做好了准备 Dialogue: 0,0:26:10.23,0:26:10.86,Default,,0,0,0,,我们做了哪些事情 Dialogue: 0,0:26:11.02,0:26:13.64,Default,,0,0,0,,我们把之后要用到的东西 Dialogue: 0,0:26:14.48,0:26:15.98,Default,,0,0,0,,也就是UNEV中的运算对象 Dialogue: 0,0:26:16.36,0:26:18.99,Default,,0,0,0,,以及我们最终求值运算对象时 Dialogue: 0,0:26:19.16,0:26:20.72,Default,,0,0,0,,会用到的环境 Dialogue: 0,0:26:22.28,0:26:23.93,Default,,0,0,0,,以及我们最终想要去的位置 Dialogue: 0,0:26:23.95,0:26:25.07,Default,,0,0,0,,本例中 也就是DONE Dialogue: 0,0:26:25.34,0:26:26.70,Default,,0,0,0,,我们把它们保存在栈上 Dialogue: 0,0:26:27.10,0:26:28.41,Default,,0,0,0,,我们之所以把它们保存在栈上 Dialogue: 0,0:26:28.43,0:26:30.67,Default,,0,0,0,,是因为EVAL-DISPATCH并不会保证 Dialogue: 0,0:26:30.94,0:26:32.54,Default,,0,0,0,,不会去修改这些寄存器 Dialogue: 0,0:26:33.55,0:26:35.02,Default,,0,0,0,,那么所有这些东西都存在了栈上 Dialogue: 0,0:26:35.02,0:26:36.91,Default,,0,0,0,,现在我们满足了EVAL-DISPATCH的约定 Dialogue: 0,0:26:37.38,0:26:38.75,Default,,0,0,0,,这是一条新的表达式 Dialogue: 0,0:26:38.78,0:26:40.04,Default,,0,0,0,,也就是+运算符 Dialogue: 0,0:26:41.07,0:26:41.95,Default,,0,0,0,,以及一个新的环境 Dialogue: 0,0:26:41.98,0:26:43.60,Default,,0,0,0,,尽管在本例中是同一个环境 Dialogue: 0,0:26:44.25,0:26:45.87,Default,,0,0,0,,以及在完成后要返回的位置 Dialogue: 0,0:26:45.87,0:26:46.91,Default,,0,0,0,,也就是EVAL-ARGS Dialogue: 0,0:26:47.60,0:26:48.13,Default,,0,0,0,,这样就满足了 Dialogue: 0,0:26:48.13,0:26:49.68,Default,,0,0,0,,现在我们来执行EVAL-DISPATCH Dialogue: 0,0:26:50.89,0:26:52.36,Default,,0,0,0,,我们回到了EVAL-DISPATCH Dialogue: 0,0:26:53.05,0:26:54.40,Default,,0,0,0,,它不是自求值的 Dialogue: 0,0:26:54.44,0:26:55.47,Default,,0,0,0,,但它是一个变量 Dialogue: 0,0:26:56.32,0:26:58.06,Default,,0,0,0,,因此我们最好跳转到EV-VARIABLE Dialogue: 0,0:26:59.79,0:27:02.65,Default,,0,0,0,,EV-VARIABLE首先要给VAL赋值 Dialogue: 0,0:27:02.70,0:27:06.33,Default,,0,0,0,,查找表达式中变量的值 Dialogue: 0,0:27:08.49,0:27:10.75,Default,,0,0,0,,那么VAL寄存器中应该是基本的加法运算 Dialogue: 0,0:27:13.37,0:27:15.16,Default,,0,0,0,,然后(GOTO (FETCH CONTINUE)) Dialogue: 0,0:27:15.23,0:27:16.11,Default,,0,0,0,,Sussman教授:它是EVAL-ARGS Dialogue: 0,0:27:16.20,0:27:18.73,Default,,0,0,0,,Abelson教授:现在它是EVAL-ARGS而不是DONE了 Dialogue: 0,0:27:19.42,0:27:21.26,Default,,0,0,0,,然后我们来到EVAL-ARGS Dialogue: 0,0:27:22.16,0:27:23.02,Default,,0,0,0,,看看它要做什么 Dialogue: 0,0:27:23.07,0:27:24.84,Default,,0,0,0,,我们要恢复之前保存的东西 Dialogue: 0,0:27:25.20,0:27:26.57,Default,,0,0,0,,因此调用(RESTORE UNEV) Dialogue: 0,0:27:29.21,0:27:31.69,Default,,0,0,0,,注意 这里并不是必要的 Dialogue: 0,0:27:31.74,0:27:32.90,Default,,0,0,0,,但通常来说都会有这么一步 Dialogue: 0,0:27:32.90,0:27:35.16,Default,,0,0,0,,它可以是任意的求值过程 Dialogue: 0,0:27:35.43,0:27:36.70,Default,,0,0,0,,恢复ENV寄存器 Dialogue: 0,0:27:47.87,0:27:52.04,Default,,0,0,0,,然后把(FETCH VAL)赋值给FUN Dialogue: 0,0:27:59.95,0:28:02.81,Default,,0,0,0,,现在我们要开始求值参数了 Dialogue: 0,0:28:04.34,0:28:06.48,Default,,0,0,0,,首先 我们最好把FUN寄存器保存起来 Dialogue: 0,0:28:07.42,0:28:10.62,Default,,0,0,0,,因为求值过程中可能发生任何事情 Dialogue: 0,0:28:15.33,0:28:16.88,Default,,0,0,0,,我们初始化参数列表 Dialogue: 0,0:28:16.91,0:28:19.29,Default,,0,0,0,,给ARGL赋值一个空的参数列表 Dialogue: 0,0:28:20.88,0:28:22.17,Default,,0,0,0,,然后跳转到EVAL-ARG-LOOP Dialogue: 0,0:28:24.86,0:28:26.27,Default,,0,0,0,,在EVAL-ARG-LOOP中 Dialogue: 0,0:28:27.77,0:28:31.53,Default,,0,0,0,,我们想要去一条一条的求值 Dialogue: 0,0:28:31.61,0:28:33.37,Default,,0,0,0,,UNEV中的表达式 Dialogue: 0,0:28:33.54,0:28:35.68,Default,,0,0,0,,然后把它们从UNEV中的待求值表 Dialogue: 0,0:28:35.90,0:28:37.26,Default,,0,0,0,,移动到ARGL中的已求值表中 Dialogue: 0,0:28:37.84,0:28:39.18,Default,,0,0,0,,然后我们保存ARGL Dialogue: 0,0:28:43.95,0:28:47.26,Default,,0,0,0,,然后我们把UNEV中的第一个运算对象 Dialogue: 0,0:28:47.37,0:28:48.38,Default,,0,0,0,,赋值给EXP Dialogue: 0,0:28:53.77,0:28:55.89,Default,,0,0,0,,然后我们检查它是否为最后一个运算对象 Dialogue: 0,0:28:55.89,0:28:56.91,Default,,0,0,0,,在这里 它还不是 Dialogue: 0,0:28:58.99,0:29:01.55,Default,,0,0,0,,然后我们保存环境 Dialogue: 0,0:29:08.00,0:29:10.06,Default,,0,0,0,,我们之所以保存UNEV Dialogue: 0,0:29:11.61,0:29:13.50,Default,,0,0,0,,是因为稍后我们可能会需要它们 Dialogue: 0,0:29:13.50,0:29:14.40,Default,,0,0,0,,我们需要环境 Dialogue: 0,0:29:14.44,0:29:15.64,Default,,0,0,0,,来进行一些求值 Dialogue: 0,0:29:15.80,0:29:16.60,Default,,0,0,0,,我们需要UNEV寄存器来指示 Dialogue: 0,0:29:16.62,0:29:19.20,Default,,0,0,0,,其余的待求值参数 Dialogue: 0,0:29:20.34,0:29:21.55,Default,,0,0,0,,我们要把CONTINUE寄存器赋值为 Dialogue: 0,0:29:21.56,0:29:24.44,Default,,0,0,0,,ACCUMULATE-ARG这个标号 Dialogue: 0,0:29:31.13,0:29:34.01,Default,,0,0,0,,现在 我们已经准备好再次调用EVAL-DISPATCH了 Dialogue: 0,0:29:37.07,0:29:38.54,Default,,0,0,0,,现在让我把这个短路掉 Dialogue: 0,0:29:39.12,0:29:41.09,Default,,0,0,0,,这里我们不跟进EVAL-DISPATCH的细节 Dialogue: 0,0:29:41.09,0:29:42.64,Default,,0,0,0,,EVAL-DISPATCH的约定说: Dialogue: 0,0:29:42.97,0:29:45.00,Default,,0,0,0,,我的调用完成后 Dialogue: 0,0:29:45.13,0:29:45.96,Default,,0,0,0,,整个机器的状态会变为 Dialogue: 0,0:29:46.03,0:29:48.20,Default,,0,0,0,,也就是在ENV环境中求值EXP表达式 Dialogue: 0,0:29:48.24,0:29:50.27,Default,,0,0,0,,求值结果会保存在VAL寄存器中 Dialogue: 0,0:29:50.27,0:29:51.07,Default,,0,0,0,,结束状态就是这样 Dialogue: 0,0:29:51.32,0:29:52.62,Default,,0,0,0,,那么我们把这些全都省略掉 Dialogue: 0,0:29:54.43,0:29:56.36,Default,,0,0,0,,最后VAL的内容是3 Dialogue: 0,0:29:58.01,0:29:59.76,Default,,0,0,0,,并且当我们从EVAL-DISPATCH返回的时候 Dialogue: 0,0:29:59.76,0:30:01.76,Default,,0,0,0,,我们会返回到ACCUMULAT-ARG这里 Dialogue: 0,0:30:02.30,0:30:03.23,Default,,0,0,0,,Sussman教授:跳转到ACCUMULATE-ARG Dialogue: 0,0:30:06.22,0:30:08.20,Default,,0,0,0,,Abelson教授:VAL寄存器里是3 对吧? Dialogue: 0,0:30:08.72,0:30:10.59,Default,,0,0,0,,我们跳过了求值的细节 Dialogue: 0,0:30:10.65,0:30:11.32,Default,,0,0,0,,现在我们要做什么? Dialogue: 0,0:30:11.32,0:30:13.68,Default,,0,0,0,,我们返回继续看剩下的参数 Dialogue: 0,0:30:13.68,0:30:14.83,Default,,0,0,0,,我们恢复UNEV Dialogue: 0,0:30:17.51,0:30:19.00,Default,,0,0,0,,恢复ENV Dialogue: 0,0:30:25.79,0:30:27.05,Default,,0,0,0,,然后恢复ARGL Dialogue: 0,0:30:28.65,0:30:29.17,Default,,0,0,0,,这件事 Dialogue: 0,0:30:30.06,0:30:31.45,Default,,0,0,0,,Sussman教授:糟糕 奇偶错误 Dialogue: 0,0:30:33.76,0:30:34.83,Default,,0,0,0,,Abelson教授:恢复ARGL Dialogue: 0,0:30:45.57,0:30:49.76,Default,,0,0,0,,然后 我们把VAL寄存器和ARGL给CONS起来 Dialogue: 0,0:30:50.65,0:30:52.64,Default,,0,0,0,,然后赋值给ARGL寄存器 Dialogue: 0,0:30:59.36,0:31:02.96,Default,,0,0,0,,我们把UNEV中剩余的运算对象 Dialogue: 0,0:31:03.34,0:31:04.52,Default,,0,0,0,,赋值给UNEV Dialogue: 0,0:31:08.91,0:31:10.76,Default,,0,0,0,,然后我们返回到EVAL-ARG-LOOP Dialogue: 0,0:31:11.51,0:31:12.28,Default,,0,0,0,,Sussman教授:EVAL-ARG-LOOP Dialogue: 0,0:31:12.28,0:31:12.86,Default,,0,0,0,,Abelson教授:好 Dialogue: 0,0:31:15.88,0:31:17.08,Default,,0,0,0,,现在我们处理下一个参数 Dialogue: 0,0:31:17.58,0:31:19.31,Default,,0,0,0,,所以首先我们要保存ARGL Dialogue: 0,0:31:25.40,0:31:28.27,Default,,0,0,0,,然后我们把UNEV中的第一个运算对象 Dialogue: 0,0:31:29.15,0:31:30.81,Default,,0,0,0,,赋给EXP Dialogue: 0,0:31:34.72,0:31:37.02,Default,,0,0,0,,然后我们检查它是否为最后一个运算对象 Dialogue: 0,0:31:37.02,0:31:38.00,Default,,0,0,0,,这里它是最后一个 Dialogue: 0,0:31:39.08,0:31:40.27,Default,,0,0,0,,所以我们跳到一个特殊的地方 Dialogue: 0,0:31:40.28,0:31:42.06,Default,,0,0,0,,来求值最后一个参数 Dialogue: 0,0:31:43.37,0:31:45.07,Default,,0,0,0,,因为请注意 在求值这个参数之后 Dialogue: 0,0:31:45.10,0:31:46.62,Default,,0,0,0,,我们就不再需要这个环境了 Dialogue: 0,0:31:47.64,0:31:48.78,Default,,0,0,0,,这就是区别 Dialogue: 0,0:31:50.25,0:31:51.85,Default,,0,0,0,,在这里 在EVAL-LAST-ARG这里 Dialogue: 0,0:31:52.24,0:31:54.92,Default,,0,0,0,,CONTINUE被赋值为了ACCUMULATE-LAST-ARG Dialogue: 0,0:32:04.27,0:32:06.90,Default,,0,0,0,,现在我们再次为EVAL-DISPATCH做准备 Dialogue: 0,0:32:06.90,0:32:08.51,Default,,0,0,0,,我们有一个完成时要跳转的目的地 Dialogue: 0,0:32:08.62,0:32:09.84,Default,,0,0,0,,我们有一条表达式 Dialogue: 0,0:32:09.84,0:32:10.80,Default,,0,0,0,,还有一个环境 Dialogue: 0,0:32:11.33,0:32:13.64,Default,,0,0,0,,好 那么我们略过对EVAL-DISPATCH的调用 Dialogue: 0,0:32:14.37,0:32:16.41,Default,,0,0,0,,现在情况是这里有一个Y Dialogue: 0,0:32:16.70,0:32:18.56,Default,,0,0,0,,在这个环境中 它的值是4 Dialogue: 0,0:32:18.60,0:32:20.09,Default,,0,0,0,,所以最终VAL寄存器将会是4 Dialogue: 0,0:32:21.06,0:32:22.86,Default,,0,0,0,,然后我们就要以ACCUMULATE-LAST-ARG结束了 Dialogue: 0,0:32:25.45,0:32:26.91,Default,,0,0,0,,因此 在ACCUMULATE-LAST-ARG中 Dialogue: 0,0:32:29.28,0:32:30.52,Default,,0,0,0,,我们恢复ARGL寄存器 Dialogue: 0,0:32:37.69,0:32:42.76,Default,,0,0,0,,我们把ARGL赋值为 Dialogue: 0,0:32:43.60,0:32:45.83,Default,,0,0,0,,将一个新值CONS在它上面的结果 Dialogue: 0,0:32:45.93,0:32:47.39,Default,,0,0,0,,所以我们在它的旧值前CONS一个4 Dialogue: 0,0:32:49.85,0:32:52.52,Default,,0,0,0,,我们恢复FUN寄存器中的内容 Dialogue: 0,0:32:53.77,0:32:54.99,Default,,0,0,0,,需要注意的是 在则个例子中 Dialogue: 0,0:32:55.00,0:32:56.27,Default,,0,0,0,,FUN寄存器还没有被修改过 Dialogue: 0,0:32:56.38,0:32:57.72,Default,,0,0,0,,但是通常来说 它会的 Dialogue: 0,0:32:59.13,0:33:01.50,Default,,0,0,0,,现在 我们将要调用APPLY-DISPATCH Dialogue: 0,0:33:02.65,0:33:04.40,Default,,0,0,0,,所以我们刚刚步步跟进了EVAL过程 Dialogue: 0,0:33:04.51,0:33:05.85,Default,,0,0,0,,我们求值了运算符 Dialogue: 0,0:33:06.46,0:33:07.98,Default,,0,0,0,,以及实际参数 Dialogue: 0,0:33:07.98,0:33:09.24,Default,,0,0,0,,现在我们要应用它们了 Dialogue: 0,0:33:09.58,0:33:11.37,Default,,0,0,0,,因此 我们来到APPLY-DISPATCH这里 Dialogue: 0,0:33:18.03,0:33:19.29,Default,,0,0,0,,这是APPLY-DISPATCH的代码 Dialogue: 0,0:33:21.05,0:33:22.41,Default,,0,0,0,,我们要检查它是一个基本过程 Dialogue: 0,0:33:22.41,0:33:23.45,Default,,0,0,0,,还是一个复合过程 Dialogue: 0,0:33:23.64,0:33:24.20,Default,,0,0,0,,Sussman教授:基本过程 Dialogue: 0,0:33:24.54,0:33:24.83,Default,,0,0,0,,Abelson教授:好的 Dialogue: 0,0:33:24.89,0:33:26.52,Default,,0,0,0,,这里 它是一个基本过程 Dialogue: 0,0:33:27.45,0:33:28.91,Default,,0,0,0,,因此 我们跳转到PRIMITIVE-APPLY Dialogue: 0,0:33:29.79,0:33:31.36,Default,,0,0,0,,我们来到PRIMITIVE-APPLY Dialogue: 0,0:33:33.71,0:33:35.37,Default,,0,0,0,,它说:把VAL赋值为 Dialogue: 0,0:33:35.69,0:33:38.25,Default,,0,0,0,,把基本过程 Dialogue: 0,0:33:38.36,0:33:40.30,Default,,0,0,0,,应用在参数表的结果 Dialogue: 0,0:33:41.31,0:33:42.43,Default,,0,0,0,,Sussman教授:我不知道怎么做加法 Dialogue: 0,0:33:42.54,0:33:43.80,Default,,0,0,0,,我只是一个执行单元 Dialogue: 0,0:33:44.14,0:33:45.35,Default,,0,0,0,,Abelson教授:我也不知道 Dialogue: 0,0:33:45.35,0:33:46.51,Default,,0,0,0,,我只是一个求值器 Dialogue: 0,0:33:47.08,0:33:48.36,Default,,0,0,0,,因此 我们需要一个基本运算执行器 Dialogue: 0,0:33:48.36,0:33:49.72,Default,,0,0,0,,那么 请问基本运算执行器 Dialogue: 0,0:33:49.76,0:33:52.36,Default,,0,0,0,,3+4等于多少? Dialogue: 0,0:33:52.86,0:33:53.32,Default,,0,0,0,,学生:7 Dialogue: 0,0:33:53.71,0:33:54.65,Default,,0,0,0,,Abelson教授:好 是7 Dialogue: 0,0:33:55.32,0:33:55.99,Default,,0,0,0,,Sussman教授:谢谢 Dialogue: 0,0:33:59.20,0:34:00.60,Default,,0,0,0,,Abelson教授:现在 我们恢复CONTINUE Dialogue: 0,0:34:11.58,0:34:12.90,Default,,0,0,0,,执行(GOTO (FETCH CONTINUE)) Dialogue: 0,0:34:13.07,0:34:13.47,Default,,0,0,0,,Sussman教授:'DONE Dialogue: 0,0:34:14.20,0:34:14.67,Default,,0,0,0,,Abelson教授:好 Dialogue: 0,0:34:14.92,0:34:18.41,Default,,0,0,0,,这些是你能看到的最细致的过程了 Dialogue: 0,0:34:18.41,0:34:20.19,Default,,0,0,0,,我们再也不会讲得这么细了 Dialogue: 0,0:34:21.59,0:34:23.92,Default,,0,0,0,,有一件重要的事需要注意 Dialogue: 0,0:34:24.91,0:34:27.55,Default,,0,0,0,,我们刚刚执行了一个递归过程 Dialogue: 0,0:34:29.56,0:34:31.17,Default,,0,0,0,,我们在整个过程中使用了栈 Dialogue: 0,0:34:31.17,0:34:32.75,Default,,0,0,0,,而且求值器是递归的 Dialogue: 0,0:34:33.07,0:34:35.88,Default,,0,0,0,,有很多人以为在求值器中 Dialogue: 0,0:34:36.48,0:34:37.85,Default,,0,0,0,,会用到栈和递归 Dialogue: 0,0:34:37.87,0:34:38.97,Default,,0,0,0,,或许是因为 Dialogue: 0,0:34:39.09,0:34:42.15,Default,,0,0,0,,回去求值像阶乘或者FIB那样的递归过程 Dialogue: 0,0:34:42.15,0:34:42.92,Default,,0,0,0,,这并不正确 Dialogue: 0,0:34:43.67,0:34:44.99,Default,,0,0,0,,注意 我们在这里进行了递归 Dialogue: 0,0:34:45.00,0:34:46.86,Default,,0,0,0,,而仅仅是去求值(+ X Y) Dialogue: 0,0:34:47.77,0:34:50.65,Default,,0,0,0,,在求值器中需要递归 实际上是因为 Dialogue: 0,0:34:50.96,0:34:52.97,Default,,0,0,0,,是因为求值过程本身 Dialogue: 0,0:34:52.99,0:34:54.06,Default,,0,0,0,,就是递归的 Dialogue: 0,0:34:54.45,0:34:56.17,Default,,0,0,0,,并不是因为你在Lisp中 Dialogue: 0,0:34:56.32,0:34:58.09,Default,,0,0,0,,要求值的那个过程 Dialogue: 0,0:34:58.12,0:34:59.27,Default,,0,0,0,,是一个递归过程 Dialogue: 0,0:34:59.27,0:35:00.52,Default,,0,0,0,,这一点很重要 Dialogue: 0,0:35:00.52,0:35:02.14,Default,,0,0,0,,人们经常在这里被弄糊涂 Dialogue: 0,0:35:03.01,0:35:04.27,Default,,0,0,0,,另一点要注意的是 Dialogue: 0,0:35:04.27,0:35:05.64,Default,,0,0,0,,我们在这里完成之后 Dialogue: 0,0:35:06.28,0:35:07.12,Default,,0,0,0,,真正完成以后 Dialogue: 0,0:35:07.12,0:35:08.49,Default,,0,0,0,,不仅仅是指我们在'DONE这个标号 Dialogue: 0,0:35:09.45,0:35:13.23,Default,,0,0,0,,栈上也没有累积的东西了 Dialogue: 0,0:35:13.60,0:35:15.71,Default,,0,0,0,,对吧?机器又回到了它的初始状态 Dialogue: 0,0:35:17.00,0:35:18.75,Default,,0,0,0,,那就是“完成”的其中一部分意义 Dialogue: 0,0:35:19.71,0:35:21.04,Default,,0,0,0,,换句话说就是 Dialogue: 0,0:35:22.72,0:35:26.04,Default,,0,0,0,,整个求值过程是把 Dialogue: 0,0:35:26.41,0:35:28.32,Default,,0,0,0,,(+ X Y)这条表达式 Dialogue: 0,0:35:30.54,0:35:32.78,Default,,0,0,0,,归约为这里的7 Dialogue: 0,0:35:33.24,0:35:35.45,Default,,0,0,0,,我所指的“归约”有特殊的意义 Dialogue: 0,0:35:36.01,0:35:38.18,Default,,0,0,0,,也就是栈上没剩下任何东西了 Dialogue: 0,0:35:38.18,0:35:40.36,Default,,0,0,0,,机器现在与初始状态相同 Dialogue: 0,0:35:40.92,0:35:42.65,Default,,0,0,0,,只是VAL寄存器里有一些东西 Dialogue: 0,0:35:42.72,0:35:44.52,Default,,0,0,0,,它不是任何问题的子问题 Dialogue: 0,0:35:44.52,0:35:45.63,Default,,0,0,0,,不需要返回到其它地方 Dialogue: 0,0:35:46.12,0:35:46.96,Default,,0,0,0,,好 这节课就讲到这里 Dialogue: 0,0:35:50.16,0:35:50.76,Default,,0,0,0,,有问题吗 Dialogue: 0,0:35:51.08,0:35:54.02,Default,,0,0,0,,学生:关于栈有一个问题 Dialogue: 0,0:35:54.02,0:35:55.82,Default,,0,0,0,,由于数据有可能是递归的 Dialogue: 0,0:35:56.20,0:35:58.75,Default,,0,0,0,,例如 嵌套的表达式 Dialogue: 0,0:35:59.31,0:36:02.08,Default,,0,0,0,,教授:是的 因为你可能遇到嵌套的表达式 Dialogue: 0,0:36:02.08,0:36:04.77,Default,,0,0,0,,但是再说一遍 不要搞混 Dialogue: 0,0:36:04.77,0:36:07.98,Default,,0,0,0,,有时候人们说数据是递归的 Dialogue: 0,0:36:08.00,0:36:10.35,Default,,0,0,0,,他们说的是对于这些表结构的 Dialogue: 0,0:36:11.04,0:36:12.93,Default,,0,0,0,,一些递归运算 Dialogue: 0,0:36:12.93,0:36:13.96,Default,,0,0,0,,那和这没有关系 Dialogue: 0,0:36:13.98,0:36:16.16,Default,,0,0,0,,这只是包含子表达式的表达式而已 Dialogue: 0,0:36:20.04,0:36:23.52,Default,,0,0,0,,学生:为什么ARGL中参数的顺序是反过来的 Dialogue: 0,0:36:23.55,0:36:25.29,Default,,0,0,0,,教授:对 我应该提一嘴这个 Dialogue: 0,0:36:27.26,0:36:29.07,Default,,0,0,0,,之所以在这里把顺序反过来 Dialogue: 0,0:36:32.78,0:36:35.37,Default,,0,0,0,,你首先定义怎么算“逆序” Dialogue: 0,0:36:36.05,0:36:39.90,Default,,0,0,0,,我记得应该是牛顿 Dialogue: 0,0:36:40.91,0:36:42.41,Default,,0,0,0,,在光学发展的很早期 Dialogue: 0,0:36:42.43,0:36:43.26,Default,,0,0,0,,人们意识到 Dialogue: 0,0:36:43.61,0:36:45.36,Default,,0,0,0,,当你用眼睛通过透镜看东西的时候 Dialogue: 0,0:36:45.50,0:36:46.73,Default,,0,0,0,,图像是上下颠倒的 Dialogue: 0,0:36:46.73,0:36:48.04,Default,,0,0,0,,当时有很多的争论说 Dialogue: 0,0:36:48.04,0:36:50.48,Default,,0,0,0,,为什么不能是你眼睛平时看见的都是上下颠倒的 Dialogue: 0,0:36:51.28,0:36:52.65,Default,,0,0,0,,这实际上是一样的道理 Dialogue: 0,0:36:52.86,0:36:53.90,Default,,0,0,0,,和什么相比反过来了 Dialogue: 0,0:36:54.81,0:36:56.24,Default,,0,0,0,,我们只是需要一个约定 Dialogue: 0,0:36:56.59,0:37:00.35,Default,,0,0,0,,它们作为(4 3)出现的原因是 Dialogue: 0,0:37:00.80,0:37:02.49,Default,,0,0,0,,是因为我们从UNEV中取出东西 Dialogue: 0,0:37:02.52,0:37:04.03,Default,,0,0,0,,并且把它CONS到了ARGL上面 Dialogue: 0,0:37:04.52,0:37:06.68,Default,,0,0,0,,那么你要意识到你已经做了这个约定 Dialogue: 0,0:37:06.86,0:37:09.37,Default,,0,0,0,,你需要意识到这点的地方有 Dialogue: 0,0:37:09.98,0:37:11.23,Default,,0,0,0,,实际上有两个地方 Dialogue: 0,0:37:11.23,0:37:12.91,Default,,0,0,0,,首先是在APPLY-PRIMITIVE-OPERATOR Dialogue: 0,0:37:12.91,0:37:14.06,Default,,0,0,0,,你要意识到 Dialogue: 0,0:37:15.12,0:37:16.75,Default,,0,0,0,,参数传入基本运算的顺序 Dialogue: 0,0:37:16.78,0:37:18.72,Default,,0,0,0,,是和你的书写顺序相反的 Dialogue: 0,0:37:19.49,0:37:21.00,Default,,0,0,0,,我们之后会在另外一处看到 Dialogue: 0,0:37:21.07,0:37:23.80,Default,,0,0,0,,当你实际绑定绑定函数的形式参数时 Dialogue: 0,0:37:24.01,0:37:25.74,Default,,0,0,0,,你要意识到参数进入的顺序 Dialogue: 0,0:37:25.74,0:37:28.54,Default,,0,0,0,,和你要绑定这些变量时的顺序相反 Dialogue: 0,0:37:28.87,0:37:30.17,Default,,0,0,0,,所以如果你注意这些 Dialogue: 0,0:37:31.08,0:37:31.83,Default,,0,0,0,,就没有问题了 Dialogue: 0,0:37:31.83,0:37:33.69,Default,,0,0,0,,同样 这完全是随意的 Dialogue: 0,0:37:33.90,0:37:34.96,Default,,0,0,0,,因为如果我们做了一个 Dialogue: 0,0:37:35.10,0:37:37.15,Default,,0,0,0,,比如 给向量的各个维度赋值的迭代 Dialogue: 0,0:37:37.42,0:37:38.73,Default,,0,0,0,,它们可能会以其它顺序输出 Dialogue: 0,0:37:40.41,0:37:42.04,Default,,0,0,0,,那么这只是这个求值器 Dialogue: 0,0:37:42.06,0:37:43.53,Default,,0,0,0,,工作时的一个约定 Dialogue: 0,0:37:45.39,0:37:46.24,Default,,0,0,0,,好 我们休息一下 Dialogue: 0,0:37:46.33,0:38:02.44,Default,,0,0,0,,[音乐] Dialogue: 0,0:38:02.44,0:38:07.64,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:38:28.62,0:38:32.51,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:38:32.51,0:38:35.68,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:38:35.68,0:38:39.61,Declare,,0,0,0,,{\an2\fad(500,500)}显式控制求值器 Dialogue: 0,0:38:41.84,0:38:45.31,Default,,0,0,0,,教授:我们已经学习了表达式的求值 Dialogue: 0,0:38:45.60,0:38:47.08,Default,,0,0,0,,虽然这只是一个非常简单的例子 Dialogue: 0,0:38:48.81,0:38:50.24,Default,,0,0,0,,但从本质上来说 Dialogue: 0,0:38:50.24,0:38:52.03,Default,,0,0,0,,它跟那些大型嵌套表达式没什么不同 Dialogue: 0,0:38:52.03,0:38:54.57,Default,,0,0,0,,后者只是在栈上递归得更深而已 Dialogue: 0,0:38:55.13,0:38:56.03,Default,,0,0,0,,我现在要为你们 Dialogue: 0,0:38:56.04,0:38:56.91,Default,,0,0,0,,讲解最后一部分 Dialogue: 0,0:38:56.92,0:38:59.82,Default,,0,0,0,,我要带着你们观察EVAL-APPLY循环 Dialogue: 0,0:39:01.01,0:39:02.81,Default,,0,0,0,,我们还没有仔细研究过它 Dialogue: 0,0:39:03.00,0:39:04.75,Default,,0,0,0,,我们还没有见过一个复合程序 Dialogue: 0,0:39:05.20,0:39:07.79,Default,,0,0,0,,对它的求值会归约为 Dialogue: 0,0:39:07.92,0:39:10.11,Default,,0,0,0,,对一个过程的应用 Dialogue: 0,0:39:10.12,0:39:11.64,Default,,0,0,0,,进而是对过程体的求值 Dialogue: 0,0:39:12.44,0:39:15.88,Default,,0,0,0,,因此 假设我们有这个 Dialogue: 0,0:39:15.93,0:39:17.44,Default,,0,0,0,,假设我们正在考察 Dialogue: 0,0:39:18.07,0:39:31.60,Default,,0,0,0,,(DEFINE (F A B) (+ A B) Dialogue: 0,0:39:33.99,0:39:37.32,Default,,0,0,0,,假设我们预先定义好了这个过程 Dialogue: 0,0:39:37.69,0:39:41.64,Default,,0,0,0,,现在 我们将要求值(F X Y) Dialogue: 0,0:39:42.27,0:39:44.20,Default,,0,0,0,,基于的环境是E0 Dialogue: 0,0:39:44.35,0:39:47.02,Default,,0,0,0,,其中X=3 Y=4 Dialogue: 0,0:39:50.78,0:39:52.11,Default,,0,0,0,,当执行DEFINE的时候 Dialogue: 0,0:39:52.12,0:39:53.69,Default,,0,0,0,,还记得么 这里是一个LAMBDA Dialogue: 0,0:39:53.82,0:39:55.53,Default,,0,0,0,,LAMBDA会创建一个过程 Dialogue: 0,0:39:55.95,0:39:58.49,Default,,0,0,0,,基本上 会发生的事情是 Dialogue: 0,0:39:59.63,0:40:00.68,Default,,0,0,0,,在环境E0中 Dialogue: 0,0:40:01.00,0:40:02.65,Default,,0,0,0,,我们会得到F的绑定 Dialogue: 0,0:40:03.56,0:40:05.61,Default,,0,0,0,,它指出F是一个过程 Dialogue: 0,0:40:07.15,0:40:11.28,Default,,0,0,0,,这个过程的参数是A和B Dialogue: 0,0:40:12.57,0:40:16.19,Default,,0,0,0,,而过程体是(+ A B) Dialogue: 0,0:40:18.11,0:40:20.99,Default,,0,0,0,,这就是环境大概的样子 Dialogue: 0,0:40:21.21,0:40:22.52,Default,,0,0,0,,我们之前就定义过了 Dialogue: 0,0:40:24.22,0:40:27.28,Default,,0,0,0,,然后 我们去求值(F X Y) Dialogue: 0,0:40:28.80,0:40:30.89,Default,,0,0,0,,我们会仔细地解释每一步 Dialogue: 0,0:40:31.02,0:40:31.85,Default,,0,0,0,,就像之前那样 Dialogue: 0,0:40:31.88,0:40:33.09,Default,,0,0,0,,不会跳过重复的表达式 Dialogue: 0,0:40:33.28,0:40:34.38,Default,,0,0,0,,唯一的不同是 Dialogue: 0,0:40:34.40,0:40:36.64,Default,,0,0,0,,它的内部不再是基本的“+”过程 Dialogue: 0,0:40:37.24,0:40:38.99,Default,,0,0,0,,它还有这个东西 Dialogue: 0,0:40:41.04,0:40:43.60,Default,,0,0,0,,因此我们要进行相同的过程 Dialogue: 0,0:40:43.60,0:40:44.92,Default,,0,0,0,,只不过这次 Dialogue: 0,0:40:45.26,0:40:47.42,Default,,0,0,0,,当我们停在APPLY-DISPATCH时 Dialogue: 0,0:40:47.86,0:40:50.28,Default,,0,0,0,,FUN寄存器中不再是基本的“+”过程 Dialogue: 0,0:40:50.44,0:40:53.58,Default,,0,0,0,,而是一个代表过程的东西 Dialogue: 0,0:40:54.30,0:40:59.00,Default,,0,0,0,,其中参数为A和B Dialogue: 0,0:41:00.64,0:41:06.27,Default,,0,0,0,,过程体是(+ A B) Dialogue: 0,0:41:07.87,0:41:09.92,Default,,0,0,0,,再强调一下 我所谓的ENV Dialogue: 0,0:41:09.96,0:41:11.12,Default,,0,0,0,,是一个指向环境的指针 Dialogue: 0,0:41:11.24,0:41:13.07,Default,,0,0,0,,所以不用担心我在这里写了很多东西 Dialogue: 0,0:41:13.28,0:41:15.63,Default,,0,0,0,,这是一个指向代表过程的数据结构的指针 Dialogue: 0,0:41:17.17,0:41:19.77,Default,,0,0,0,,因此 我们现在面临着相同的情况 Dialogue: 0,0:41:20.27,0:41:22.43,Default,,0,0,0,,我们来到了APPLY-DISPATCH Dialogue: 0,0:41:23.98,0:41:26.48,Default,,0,0,0,,这是APPLY-DISPATCH的代码 Dialogue: 0,0:41:26.48,0:41:28.73,Default,,0,0,0,,上一次 我们分支跳转到了一个基本过程 Dialogue: 0,0:41:30.01,0:41:30.70,Default,,0,0,0,,然而这一次 Dialogue: 0,0:41:30.84,0:41:32.80,Default,,0,0,0,,我们遇到的是一个复合过程 Dialogue: 0,0:41:34.55,0:41:36.60,Default,,0,0,0,,因此我们要跳转到COMPOUND-APPLY Dialogue: 0,0:41:38.47,0:41:39.92,Default,,0,0,0,,COMPOUND-APPLY又是怎样定义的呢? Dialogue: 0,0:41:41.92,0:41:44.54,Default,,0,0,0,,还记得元循环求值器是怎么做的么? Dialogue: 0,0:41:45.09,0:41:47.40,Default,,0,0,0,,COMPOUND-APPLY的执行步骤则是 Dialogue: 0,0:41:49.90,0:41:51.60,Default,,0,0,0,,在一个新的环境中 Dialogue: 0,0:41:52.94,0:41:54.12,Default,,0,0,0,,求值一个过程的体 Dialogue: 0,0:41:54.12,0:41:55.87,Default,,0,0,0,,这个新的环境来自于哪里呢? Dialogue: 0,0:41:56.73,0:42:01.36,Default,,0,0,0,,我们把跟过程一同打包的环境 Dialogue: 0,0:42:03.02,0:42:05.79,Default,,0,0,0,,我们把过程的形式参数 Dialogue: 0,0:42:06.00,0:42:07.63,Default,,0,0,0,,同传递进来的实际参数给绑定起来 Dialogue: 0,0:42:09.75,0:42:11.95,Default,,0,0,0,,把这个作为新的框架 Dialogue: 0,0:42:12.59,0:42:13.79,Default,,0,0,0,,来扩展过程附带的环境 Dialogue: 0,0:42:14.99,0:42:16.08,Default,,0,0,0,,我们就是在这个环境中 Dialogue: 0,0:42:16.30,0:42:18.88,Default,,0,0,0,,求值过程的体 Dialogue: 0,0:42:20.12,0:42:24.47,Default,,0,0,0,,对吧?这就是APPLY-EVAL循环做的事 Dialogue: 0,0:42:24.47,0:42:26.25,Default,,0,0,0,,这就是APPLY回过头来调用EVAL Dialogue: 0,0:42:32.86,0:42:34.92,Default,,0,0,0,,因此 这就是我们要在COMPOUND-APPLY中要做的所有事 Dialogue: 0,0:42:36.78,0:42:37.72,Default,,0,0,0,,要怎么来实现呢? Dialogue: 0,0:42:37.72,0:42:40.97,Default,,0,0,0,,我们要构造一个新的环境 Dialogue: 0,0:42:43.55,0:42:45.64,Default,,0,0,0,,而我们构造的这个新环境呢 Dialogue: 0,0:42:46.76,0:42:48.11,Default,,0,0,0,,我们把它记作E1 Dialogue: 0,0:42:52.90,0:42:55.63,Default,,0,0,0,,E1这个环境呢 Dialogue: 0,0:42:57.31,0:42:59.15,Default,,0,0,0,,存储了过程的参数绑定 Dialogue: 0,0:42:59.21,0:43:03.26,Default,,0,0,0,,其中A=3 B=4 Dialogue: 0,0:43:04.27,0:43:05.76,Default,,0,0,0,,并且它跟E0相连 Dialogue: 0,0:43:05.76,0:43:08.08,Default,,0,0,0,,这是因为 F就是在E0中定义的 Dialogue: 0,0:43:09.27,0:43:10.27,Default,,0,0,0,,因此 在这个环境中 Dialogue: 0,0:43:10.27,0:43:11.96,Default,,0,0,0,,我们要来求值过程的体 Dialogue: 0,0:43:12.05,0:43:14.48,Default,,0,0,0,,让我们来看一看 Dialogue: 0,0:43:16.52,0:43:18.32,Default,,0,0,0,,我们来看COMPOUND-APPLY的代码 Dialogue: 0,0:43:20.30,0:43:23.47,Default,,0,0,0,,首先是给EXP寄存器赋值 Dialogue: 0,0:43:24.50,0:43:25.98,Default,,0,0,0,,所赋的值是FUN寄存器 Dialogue: 0,0:43:25.98,0:43:27.26,Default,,0,0,0,,所指向过程的体 Dialogue: 0,0:43:28.38,0:43:30.64,Default,,0,0,0,,这样 我就将过程的体 Dialogue: 0,0:43:31.29,0:43:32.33,Default,,0,0,0,,赋值给了EXP寄存器 Dialogue: 0,0:43:40.75,0:43:41.10,Default,,0,0,0,,对吧? Dialogue: 0,0:43:42.64,0:43:44.97,Default,,0,0,0,,而这将在某个环境中求值 Dialogue: 0,0:43:45.82,0:43:48.32,Default,,0,0,0,,这个环境是通过将FUN寄存器 Dialogue: 0,0:43:51.30,0:43:53.67,Default,,0,0,0,,所指向的过程中的形式参数 Dialogue: 0,0:43:53.67,0:43:56.25,Default,,0,0,0,,与实际参数绑定起来 得到的 Dialogue: 0,0:43:57.80,0:44:00.00,Default,,0,0,0,,我们先不要关系它的具体细节 Dialogue: 0,0:44:00.08,0:44:01.63,Default,,0,0,0,,你可以知道它的最后结果 Dialogue: 0,0:44:01.93,0:44:03.32,Default,,0,0,0,,因此MAKE-BINDINGS会说 Dialogue: 0,0:44:04.04,0:44:07.90,Default,,0,0,0,,过程本身就附带有一个环境 Dialogue: 0,0:44:07.96,0:44:09.32,Default,,0,0,0,,在这里 我没有写出来 Dialogue: 0,0:44:09.36,0:44:10.56,Default,,0,0,0,,但我应该说过它有一个环境 Dialogue: 0,0:44:11.30,0:44:12.73,Default,,0,0,0,,因为每个过程在构造时 Dialogue: 0,0:44:12.76,0:44:13.44,Default,,0,0,0,,都有一个环境 Dialogue: 0,0:44:13.66,0:44:14.83,Default,,0,0,0,,因此 通过这个环境 Dialogue: 0,0:44:15.68,0:44:16.35,Default,,0,0,0,,它能够知道 Dialogue: 0,0:44:16.60,0:44:18.65,Default,,0,0,0,,定义该过程时的环境是怎样的 Dialogue: 0,0:44:19.29,0:44:20.75,Default,,0,0,0,,它知道实际参数是什么 Dialogue: 0,0:44:21.83,0:44:22.49,Default,,0,0,0,,它查看ARGL Dialogue: 0,0:44:22.49,0:44:24.28,Default,,0,0,0,,然后你会在这里看到逆序的约定 Dialogue: 0,0:44:24.28,0:44:26.62,Default,,0,0,0,,它需要知道ARGL是逆序的 Dialogue: 0,0:44:27.06,0:44:28.81,Default,,0,0,0,,然后它构造了这个框架 E1 Dialogue: 0,0:44:29.99,0:44:31.08,Default,,0,0,0,,因此我们假设 Dialogue: 0,0:44:31.10,0:44:32.92,Default,,0,0,0,,MAKE-BINDINGS返回的就是这些东西 Dialogue: 0,0:44:33.36,0:44:36.22,Default,,0,0,0,,然后 它把E1赋值给ENV Dialogue: 0,0:44:41.34,0:44:42.54,Default,,0,0,0,,下一步就是 Dialogue: 0,0:44:43.95,0:44:45.84,Default,,0,0,0,,恢复CONTINUE Dialogue: 0,0:44:46.89,0:44:48.19,Default,,0,0,0,,还记得CONTINUE之前是什么吗? Dialogue: 0,0:44:48.76,0:44:50.43,Default,,0,0,0,,在最后一段中 Dialogue: 0,0:44:52.24,0:44:54.02,Default,,0,0,0,,CONTINUE被保存了 Dialogue: 0,0:44:54.02,0:44:55.18,Default,,0,0,0,,它的值是最初的'DONE Dialogue: 0,0:44:55.32,0:44:56.56,Default,,0,0,0,,这代表了 Dialogue: 0,0:44:56.73,0:44:59.44,Default,,0,0,0,,在完成这项特定应用后要做的事 Dialogue: 0,0:45:00.14,0:45:01.72,Default,,0,0,0,,这是在求值整个应用时 Dialogue: 0,0:45:01.76,0:45:03.18,Default,,0,0,0,,最先发生的事儿 Dialogue: 0,0:45:03.88,0:45:05.87,Default,,0,0,0,,现在 我们要恢复CONTINUE了 Dialogue: 0,0:45:06.86,0:45:09.55,Default,,0,0,0,,还记得APPLY-DISPATCH的约定么? Dialogue: 0,0:45:09.58,0:45:11.20,Default,,0,0,0,,它假设下一步的跳转目标 Dialogue: 0,0:45:11.23,0:45:11.98,Default,,0,0,0,,已经存放在栈上了 Dialogue: 0,0:45:12.03,0:45:13.12,Default,,0,0,0,,并且 这里确实存放在栈上了 Dialogue: 0,0:45:13.59,0:45:14.76,Default,,0,0,0,,CONTINUE被赋值成了DONE Dialogue: 0,0:45:17.82,0:45:19.90,Default,,0,0,0,,现在我们要回到EVAL-DISPATCH了 Dialogue: 0,0:45:19.94,0:45:20.84,Default,,0,0,0,,我们要再次进行寄存器设置 Dialogue: 0,0:45:20.97,0:45:24.41,Default,,0,0,0,,我们有表达式、环境、下一步 Dialogue: 0,0:45:25.80,0:45:26.89,Default,,0,0,0,,我不会再细讲了 Dialogue: 0,0:45:27.88,0:45:29.55,Default,,0,0,0,,因为它基本上就是相同的表达式 Dialogue: 0,0:45:35.40,0:45:37.79,Default,,0,0,0,,但是需要注意的是 Dialogue: 0,0:45:37.82,0:45:38.73,Default,,0,0,0,,在这个时候 Dialogue: 0,0:45:39.34,0:45:43.72,Default,,0,0,0,,我们已经归约了原始表达式(F X Y) Dialogue: 0,0:45:44.64,0:45:47.92,Default,,0,0,0,,通过在E0中求值(F X Y) Dialogue: 0,0:45:48.89,0:45:52.67,Default,,0,0,0,,将其归约为在E1中求值(+ A B) Dialogue: 0,0:45:52.78,0:45:55.92,Default,,0,0,0,,要注意 栈上并没有什么东西 对吧? Dialogue: 0,0:45:56.11,0:45:56.83,Default,,0,0,0,,这是一个归约 Dialogue: 0,0:45:56.84,0:45:59.80,Default,,0,0,0,,这个时候 机器的状态中 Dialogue: 0,0:45:59.84,0:46:01.20,Default,,0,0,0,,并没有包含 Dialogue: 0,0:46:01.76,0:46:03.71,Default,,0,0,0,,它是求值过程F的 Dialogue: 0,0:46:03.72,0:46:04.88,Default,,0,0,0,,中间状态的事实 Dialogue: 0,0:46:05.49,0:46:06.28,Default,,0,0,0,,它消失了 Dialogue: 0,0:46:07.66,0:46:09.55,Default,,0,0,0,,这里面没有积累的状态 Dialogue: 0,0:46:13.07,0:46:14.37,Default,,0,0,0,,注意 这个思想非常重要 Dialogue: 0,0:46:14.37,0:46:16.33,Default,,0,0,0,,这意味着 Dialogue: 0,0:46:16.76,0:46:18.39,Default,,0,0,0,,当我们使用代换模型时 Dialogue: 0,0:46:18.39,0:46:20.86,Default,,0,0,0,,一条表达式会归约到另一条表达式 Dialogue: 0,0:46:21.35,0:46:22.66,Default,,0,0,0,,而你不需要记住任何东西 Dialogue: 0,0:46:22.66,0:46:24.50,Default,,0,0,0,,这里 你就见到了归约的真谛 Dialogue: 0,0:46:24.56,0:46:26.16,Default,,0,0,0,,这个时候 栈上没有任何东西 Dialogue: 0,0:46:31.59,0:46:33.63,Default,,0,0,0,,这样就有一个非常重要的结果 Dialogue: 0,0:46:35.24,0:46:37.90,Default,,0,0,0,,让我们回过头来看看迭代式阶乘 Dialogue: 0,0:46:40.42,0:46:42.76,Default,,0,0,0,,还记得吗?这是某种循环 Dialogue: 0,0:46:44.01,0:46:44.88,Default,,0,0,0,,用来进行迭代 Dialogue: 0,0:46:45.13,0:46:47.36,Default,,0,0,0,,我们不断强调 它是一个迭代过程 Dialogue: 0,0:46:49.26,0:46:53.84,Default,,0,0,0,,还记得吗 Dialogue: 0,0:46:58.44,0:47:03.13,Default,,0,0,0,,我们使用它的时候 Dialogue: 0,0:47:04.35,0:47:11.07,Default,,0,0,0,,是像(FACT-ITER 5)这样调用它的 Dialogue: 0,0:47:12.36,0:47:18.67,Default,,0,0,0,,然后我们把它归约成(ITER 1 1 5) Dialogue: 0,0:47:19.03,0:47:25.15,Default,,0,0,0,,然后它归约成(ITER 1 2 5) Dialogue: 0,0:47:25.32,0:47:27.07,Default,,0,0,0,,等等等等 Dialogue: 0,0:47:27.07,0:47:28.17,Default,,0,0,0,,然后我们又说 看 Dialogue: 0,0:47:28.17,0:47:30.35,Default,,0,0,0,,为了实现这个效果 不需要存储任何东西 Dialogue: 0,0:47:31.72,0:47:32.73,Default,,0,0,0,,我们摆了摆手 说 Dialogue: 0,0:47:32.75,0:47:34.59,Default,,0,0,0,,“原则上 这不需要任何存储” Dialogue: 0,0:47:35.04,0:47:36.17,Default,,0,0,0,,现在你们发现 确实不需要 Dialogue: 0,0:47:36.17,0:47:39.09,Default,,0,0,0,,这里的每一步都是真正的归约 对吧? Dialogue: 0,0:47:39.09,0:47:42.60,Default,,0,0,0,,随着你求值这些表达式 Dialogue: 0,0:47:47.30,0:47:50.51,Default,,0,0,0,,在求值这些表达式的过程中 Dialogue: 0,0:47:50.83,0:47:51.37,Default,,0,0,0,,你会发现 Dialogue: 0,0:47:51.37,0:47:52.81,Default,,0,0,0,,栈上的这些表达式 Dialogue: 0,0:47:53.75,0:47:55.64,Default,,0,0,0,,都在一个特定的环境中 Dialogue: 0,0:47:56.42,0:48:00.02,Default,,0,0,0,,抱歉 是EXP寄存器中的表达式 Dialogue: 0,0:48:00.02,0:48:01.50,Default,,0,0,0,,是在某个特定的环境中 Dialogue: 0,0:48:01.57,0:48:02.19,Default,,0,0,0,,并且 在每一步 Dialogue: 0,0:48:02.19,0:48:04.00,Default,,0,0,0,,栈上不会积累任何东西 Dialogue: 0,0:48:04.36,0:48:05.68,Default,,0,0,0,,因为每一步都是真正的归约 Dialogue: 0,0:48:09.28,0:48:10.51,Default,,0,0,0,,因此 举例来说 Dialogue: 0,0:48:10.58,0:48:12.51,Default,,0,0,0,,说得更仔细一点 Dialogue: 0,0:48:13.46,0:48:16.88,Default,,0,0,0,,如果我从这样的一条表达式开始 Dialogue: 0,0:48:22.44,0:48:34.25,Default,,0,0,0,,比如说 在某个环境中计算(FACT-ITER 5) Dialogue: 0,0:48:42.11,0:48:46.30,Default,,0,0,0,,它将在某个时刻创建一个环境 Dialogue: 0,0:48:46.81,0:48:48.38,Default,,0,0,0,,其中N=5 Dialogue: 0,0:48:51.47,0:48:52.01,Default,,0,0,0,,我们把它写下来 Dialogue: 0,0:48:55.68,0:48:56.59,Default,,0,0,0,,然后 在某个时候 Dialogue: 0,0:48:56.89,0:49:02.56,Default,,0,0,0,,机器会归约这整个东西 Dialogue: 0,0:49:02.91,0:49:04.35,Default,,0,0,0,,将它归约为 Dialogue: 0,0:49:04.76,0:49:09.85,Default,,0,0,0,,(ITER 1 1 N) Dialogue: 0,0:49:10.68,0:49:13.72,Default,,0,0,0,,然后在环境E1中求值这条表达式 Dialogue: 0,0:49:15.87,0:49:17.16,Default,,0,0,0,,而不在栈上存放任何东西 Dialogue: 0,0:49:17.16,0:49:19.55,Default,,0,0,0,,看到了么 这时机器并不会记住 Dialogue: 0,0:49:20.71,0:49:22.50,Default,,0,0,0,,求值这条ITER表达式-- Dialogue: 0,0:49:25.00,0:49:25.63,Default,,0,0,0,,也就是某种循环-- Dialogue: 0,0:49:25.79,0:49:28.57,Default,,0,0,0,,并不是FACT-ITER的一部分 Dialogue: 0,0:49:29.68,0:49:30.59,Default,,0,0,0,,它不会记住这个事实 Dialogue: 0,0:49:30.59,0:49:33.17,Default,,0,0,0,,它只是归约了该表达式 Dialogue: 0,0:49:33.17,0:49:36.56,Default,,0,0,0,,如果我们再来看迭代式阶乘的体 Dialogue: 0,0:49:38.05,0:49:41.08,Default,,0,0,0,,这条表达式归约为了这条表达式 Dialogue: 0,0:49:42.81,0:49:43.87,Default,,0,0,0,,哦 这里漏了一个N Dialogue: 0,0:49:46.59,0:49:47.74,Default,,0,0,0,,幻灯片中的约定 Dialogue: 0,0:49:47.74,0:49:49.13,Default,,0,0,0,,和实际程序中稍有不同 Dialogue: 0,0:49:53.34,0:49:56.25,Default,,0,0,0,,那么 ITER的体又是什么? Dialogue: 0,0:49:56.28,0:49:57.40,Default,,0,0,0,,ITER的体首先是一个IF-- Dialogue: 0,0:49:58.75,0:50:00.19,Default,,0,0,0,,我不会再深入IF语句的细节了 Dialogue: 0,0:50:00.24,0:50:01.63,Default,,0,0,0,,它会对谓词求值 Dialogue: 0,0:50:02.40,0:50:03.71,Default,,0,0,0,,本例中 会返回FALSE Dialogue: 0,0:50:03.81,0:50:08.64,Default,,0,0,0,,然后这里的ITER会归约为表达式-- Dialogue: 0,0:50:09.85,0:50:20.20,Default,,0,0,0,,(ITER (* COUNTER PRODUCT) Dialogue: 0,0:50:21.62,0:50:22.24,Default,,0,0,0,,按照它代码写的-- Dialogue: 0,0:50:22.68,0:50:24.56,Default,,0,0,0,,(+ COUNTER 1)) Dialogue: 0,0:50:28.72,0:50:31.42,Default,,0,0,0,,在另外的一个环境E2中求值 Dialogue: 0,0:50:32.97,0:50:35.98,Default,,0,0,0,,其中 E2会记录着 Dialogue: 0,0:50:36.49,0:50:39.39,Default,,0,0,0,,PRODUCT和COUNTER的值 Dialogue: 0,0:50:42.92,0:50:44.33,Default,,0,0,0,,它会被归约为这条语句 Dialogue: 0,0:50:44.94,0:50:46.04,Default,,0,0,0,,它不会记得 Dialogue: 0,0:50:46.06,0:50:48.75,Default,,0,0,0,,它是一个需要返回到某处的一部分 Dialogue: 0,0:50:49.34,0:50:50.43,Default,,0,0,0,,当ITER再次调用ITER时 Dialogue: 0,0:50:50.44,0:50:52.56,Default,,0,0,0,,它会归约为另一个像这样的东西 Dialogue: 0,0:50:53.05,0:50:54.68,Default,,0,0,0,,只是会在新环境E3中 Dialogue: 0,0:50:54.83,0:50:56.67,Default,,0,0,0,,里面有关于PRODUCT和COUNTER新的绑定 Dialogue: 0,0:50:58.80,0:51:05.29,Default,,0,0,0,,因此 如果你想知道 Dialogue: 0,0:51:06.09,0:51:07.53,Default,,0,0,0,,如果你一直感到不安 Dialogue: 0,0:51:08.25,0:51:10.67,Default,,0,0,0,,不知道为什么我们说这些过程 Dialogue: 0,0:51:10.67,0:51:12.45,Default,,0,0,0,,虽然从语法上看起来是递归的 Dialogue: 0,0:51:13.20,0:51:15.69,Default,,0,0,0,,但实际上是迭代的 Dialogue: 0,0:51:15.87,0:51:17.24,Default,,0,0,0,,可以在常量空间中运行 Dialogue: 0,0:51:18.40,0:51:19.75,Default,,0,0,0,,我不知道这么说是否打消了你们的疑虑 Dialogue: 0,0:51:19.75,0:51:21.23,Default,,0,0,0,,但至少让你们知道发生了什么 Dialogue: 0,0:51:21.23,0:51:22.81,Default,,0,0,0,,这其中没有任何构造 Dialogue: 0,0:51:25.91,0:51:27.58,Default,,0,0,0,,但你也会说 这里面还是有一些构造 Dialogue: 0,0:51:27.98,0:51:30.08,Default,,0,0,0,,从原则上来说 我们也构造了环境框架 Dialogue: 0,0:51:31.71,0:51:32.37,Default,,0,0,0,,答案则是 Dialogue: 0,0:51:32.40,0:51:33.84,Default,,0,0,0,,你确实需要构建这些环境框架 Dialogue: 0,0:51:33.84,0:51:35.26,Default,,0,0,0,,但是 等你求值完毕后 Dialogue: 0,0:51:35.42,0:51:36.19,Default,,0,0,0,,不必保留它们 Dialogue: 0,0:51:36.44,0:51:37.61,Default,,0,0,0,,它们可以被废料收集 Dialogue: 0,0:51:37.92,0:51:39.47,Default,,0,0,0,,这些空间也可以被自动地重用 Dialogue: 0,0:51:40.72,0:51:42.99,Default,,0,0,0,,但你们可以看到求值器控制流 Dialogue: 0,0:51:43.25,0:51:46.12,Default,,0,0,0,,的中心思想就是进行归约 Dialogue: 0,0:51:47.02,0:51:49.29,Default,,0,0,0,,因此这些过程实际上是迭代过程 Dialogue: 0,0:51:50.13,0:51:51.38,Default,,0,0,0,,好吧 有什么问题么? Dialogue: 0,0:52:02.68,0:52:03.23,Default,,0,0,0,,好吧 课件休息吧 Dialogue: 0,0:52:04.12,0:52:24.56,Default,,0,0,0,,[音乐] Dialogue: 0,0:52:24.60,0:52:29.69,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:52:35.20,0:52:38.36,Declare,,0,0,0,,{\an2\fad(500,500)}讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 Dialogue: 0,0:52:38.36,0:52:42.14,Declare,,0,0,0,,{\an2\fad(500,500)}《计算机程序的构造和解释》 Dialogue: 0,0:52:42.14,0:52:46.44,Declare,,0,0,0,,{\an2\fad(500,500)}显示控制求值器 Dialogue: 0,0:52:48.77,0:52:51.55,Default,,0,0,0,,教授:跟迭代过程形成对比的是 Dialogue: 0,0:52:52.77,0:52:54.89,Default,,0,0,0,,确实会占用空间的 Dialogue: 0,0:52:55.12,0:52:56.14,Default,,0,0,0,,递归过程 Dialogue: 0,0:52:56.17,0:52:57.29,Default,,0,0,0,,你们可以看到其中的区别 Dialogue: 0,0:52:58.03,0:53:01.20,Default,,0,0,0,,让我们来看看递归式阶乘的求值 Dialogue: 0,0:53:02.65,0:53:05.53,Default,,0,0,0,,这里的FACT-REC Dialogue: 0,0:53:05.55,0:53:07.22,Default,,0,0,0,,就是阶乘的标准定义 Dialogue: 0,0:53:07.22,0:53:10.01,Default,,0,0,0,,这个当然是一个递归过程 Dialogue: 0,0:53:10.01,0:53:12.57,Default,,0,0,0,,它的计算过程也是递归的 Dialogue: 0,0:53:13.75,0:53:16.56,Default,,0,0,0,,然后 只要把它和我们开始的方式联系起来 Dialogue: 0,0:53:16.83,0:53:20.53,Default,,0,0,0,,我们会通过代换模型发现 Dialogue: 0,0:53:20.53,0:53:21.82,Default,,0,0,0,,这是一个递归过程 Dialogue: 0,0:53:22.36,0:53:28.00,Default,,0,0,0,,因为 如果我调用(REC-FACT 5) Dialogue: 0,0:53:30.45,0:53:34.94,Default,,0,0,0,,会变成(* 5 Dialogue: 0,0:53:36.28,0:53:37.82,Default,,0,0,0,,哦 这里是FACT-REC Dialogue: 0,0:53:42.62,0:53:47.93,Default,,0,0,0,,(* 5 (FACT-REC 4)) Dialogue: 0,0:53:49.66,0:53:58.22,Default,,0,0,0,,又会变成(* 5 (* 4 (FACT-REC 3))) Dialogue: 0,0:54:00.22,0:54:08.60,Default,,0,0,0,,又会变成(* 5 (* 4 (* 3 (* ... Dialogue: 0,0:54:13.45,0:54:15.31,Default,,0,0,0,,以此类推 Dialogue: 0,0:54:15.39,0:54:17.39,Default,,0,0,0,,关键点就是 有一条链条被不断构造出来 Dialogue: 0,0:54:18.10,0:54:20.06,Default,,0,0,0,,这就在代换模型中证明了 Dialogue: 0,0:54:20.08,0:54:21.28,Default,,0,0,0,,FACT-REC是递归的 Dialogue: 0,0:54:21.52,0:54:24.18,Default,,0,0,0,,现在 让我们来看看这条构造起来的链条 Dialogue: 0,0:54:24.18,0:54:25.29,Default,,0,0,0,,它又是在机器中的什么地方? Dialogue: 0,0:54:27.68,0:54:29.95,Default,,0,0,0,,好吧 让我们想象一下要从哪里开始 Dialogue: 0,0:54:30.44,0:54:40.01,Default,,0,0,0,,我们告诉机器 求值(FACT-REC 5) Dialogue: 0,0:54:41.45,0:54:43.39,Default,,0,0,0,,基于的环境是E0 Dialogue: 0,0:54:45.08,0:54:48.97,Default,,0,0,0,,也就是定义FACT-REC时的环境 Dialogue: 0,0:54:49.55,0:54:51.23,Default,,0,0,0,,现在 我们知道最终要发生什么 Dialogue: 0,0:54:52.25,0:54:53.64,Default,,0,0,0,,首先 Dialogue: 0,0:54:53.92,0:54:55.64,Default,,0,0,0,,它会对这些东西求值 Dialogue: 0,0:54:55.68,0:54:56.99,Default,,0,0,0,,发现它是一个过程 Dialogue: 0,0:54:57.18,0:55:00.16,Default,,0,0,0,,在这里创建一个新环境E1 Dialogue: 0,0:55:00.88,0:55:03.69,Default,,0,0,0,,其中N=5 Dialogue: 0,0:55:04.33,0:55:06.54,Default,,0,0,0,,并且与E0相连 Dialogue: 0,0:55:07.80,0:55:08.97,Default,,0,0,0,,这个E0也就是 Dialogue: 0,0:55:08.99,0:55:12.30,Default,,0,0,0,,定义FACT-REC的那个环境 Dialogue: 0,0:55:14.11,0:55:15.74,Default,,0,0,0,,然后 在E1这个环境中 Dialogue: 0,0:55:15.76,0:55:17.48,Default,,0,0,0,,求值过程的体 Dialogue: 0,0:55:19.67,0:55:25.92,Default,,0,0,0,,因此 在这里求值会归约为 Dialogue: 0,0:55:27.00,0:55:28.92,Default,,0,0,0,,在E1中求值过程的体 Dialogue: 0,0:55:30.16,0:55:31.34,Default,,0,0,0,,这就需要求值IF语句 Dialogue: 0,0:55:32.17,0:55:33.53,Default,,0,0,0,,而我不会讲解IF语句的细节 Dialogue: 0,0:55:33.53,0:55:34.88,Default,,0,0,0,,IF语句会求值谓词 Dialogue: 0,0:55:34.88,0:55:37.53,Default,,0,0,0,,最后发现需要求值ELSE子句 Dialogue: 0,0:55:37.84,0:55:40.41,Default,,0,0,0,,因此 这里的整个部分 会归约为 Dialogue: 0,0:55:41.30,0:55:45.53,Default,,0,0,0,,FACT-REC的ELSE子句 Dialogue: 0,0:55:45.82,0:55:46.97,Default,,0,0,0,,也就是谓词为假的部分 Dialogue: 0,0:55:47.23,0:55:51.16,Default,,0,0,0,,整个表达式就归约为了(* N Dialogue: 0,0:55:53.07,0:55:59.96,Default,,0,0,0,,(FACT-REC (- N 1)) Dialogue: 0,0:56:03.48,0:56:05.55,Default,,0,0,0,,求值的环境是E1 Dialogue: 0,0:56:08.38,0:56:10.91,Default,,0,0,0,,因此 最初的表达式现在就会归约为 Dialogue: 0,0:56:11.04,0:56:12.52,Default,,0,0,0,,求值这样的一个表达式 Dialogue: 0,0:56:13.75,0:56:16.28,Default,,0,0,0,,而现在 我们面对的是一个应用 Dialogue: 0,0:56:16.28,0:56:17.63,Default,,0,0,0,,我们之前求值过应用 Dialogue: 0,0:56:18.22,0:56:20.25,Default,,0,0,0,,还记得要怎么求值应用么? Dialogue: 0,0:56:20.36,0:56:21.69,Default,,0,0,0,,正式求值一个应用之前 Dialogue: 0,0:56:21.74,0:56:24.81,Default,,0,0,0,,你需要把CONTINUE寄存器的值保存在栈上 Dialogue: 0,0:56:25.35,0:56:27.18,Default,,0,0,0,,此时 栈上会有一个值'DONE Dialogue: 0,0:56:29.98,0:56:32.88,Default,,0,0,0,,接下来 你要为求值子部分做准备 Dialogue: 0,0:56:35.00,0:56:37.20,Default,,0,0,0,,因此 我们在这里开始求值子部分 Dialogue: 0,0:56:39.47,0:56:41.45,Default,,0,0,0,,首先要做的是求值运算符 Dialogue: 0,0:56:44.60,0:56:46.32,Default,,0,0,0,,运算符是怎样求值的呢? Dialogue: 0,0:56:47.25,0:56:48.99,Default,,0,0,0,,我们通过一些手段 Dialogue: 0,0:56:49.00,0:56:51.04,Default,,0,0,0,,将EXP寄存器指向运算符对应的过程 Dialogue: 0,0:56:51.48,0:56:53.15,Default,,0,0,0,,并且让ENV寄存器指向求值的环境 Dialogue: 0,0:56:53.66,0:56:54.60,Default,,0,0,0,,而把CONTINUE寄存器赋值为 Dialogue: 0,0:56:54.62,0:56:56.22,Default,,0,0,0,,用于求值参数的EVAL-ARGS Dialogue: 0,0:56:56.59,0:56:57.37,Default,,0,0,0,,并且 我们把 Dialogue: 0,0:56:57.40,0:56:59.29,Default,,0,0,0,,CONTINUE的原始值保存在栈上 Dialogue: 0,0:56:59.52,0:57:01.02,Default,,0,0,0,,我们完成所有工作后 就会跳转到这个地方 Dialogue: 0,0:57:01.72,0:57:02.86,Default,,0,0,0,,在我们求值完运算符后 Dialogue: 0,0:57:03.58,0:57:05.80,Default,,0,0,0,,需要做的则是 Dialogue: 0,0:57:05.90,0:57:07.66,Default,,0,0,0,,求值对实际参数进行求值 Dialogue: 0,0:57:07.69,0:57:12.01,Default,,0,0,0,,也就是这个环境和这些参数 Dialogue: 0,0:57:12.14,0:57:13.44,Default,,0,0,0,,这些尚未求值的实际参数 Dialogue: 0,0:57:14.20,0:57:15.62,Default,,0,0,0,,它们现在都还在栈上 Dialogue: 0,0:57:15.62,0:57:18.59,Default,,0,0,0,,我们现在就要先来求值运算符 Dialogue: 0,0:57:23.26,0:57:26.73,Default,,0,0,0,,当我们从这个调用返回时 Dialogue: 0,0:57:26.92,0:57:28.64,Default,,0,0,0,,在这里 我们将要去调用EVAL-DISPATCH Dialogue: 0,0:57:29.38,0:57:30.83,Default,,0,0,0,,当我们从这个调用返回时 Dialogue: 0,0:57:31.45,0:57:32.70,Default,,0,0,0,,这个运算符所对应的值 Dialogue: 0,0:57:32.73,0:57:33.52,Default,,0,0,0,,在本例中 Dialogue: 0,0:57:33.55,0:57:35.44,Default,,0,0,0,,也就是基本的乘法过程 Dialogue: 0,0:57:36.44,0:57:37.93,Default,,0,0,0,,会存放在FUN寄存器中 Dialogue: 0,0:57:43.02,0:57:44.53,Default,,0,0,0,,我们要去求值实际参数 Dialogue: 0,0:57:44.53,0:57:45.85,Default,,0,0,0,,现在这里求值N Dialogue: 0,0:57:47.73,0:57:49.87,Default,,0,0,0,,本例中 会返回5 Dialogue: 0,0:57:50.25,0:57:52.04,Default,,0,0,0,,然后我们会把它放入ARGL寄存器 Dialogue: 0,0:57:53.00,0:57:55.88,Default,,0,0,0,,然后我们会去求值第二个运算对象 Dialogue: 0,0:57:57.46,0:58:00.48,Default,,0,0,0,,就在我们准备求值第二个运算对象之时 Dialogue: 0,0:58:00.52,0:58:02.19,Default,,0,0,0,,我会省略计算 Dialogue: 0,0:58:02.20,0:58:03.58,Default,,0,0,0,,(- N 1)之类的细节 Dialogue: 0,0:58:03.71,0:58:05.88,Default,,0,0,0,,但是 当我们去求值第二个运算对象时 Dialogue: 0,0:58:06.62,0:58:10.44,Default,,0,0,0,,会最终归约为对FACT-REC的另一个调用 Dialogue: 0,0:58:12.00,0:58:14.20,Default,,0,0,0,,现在 我们在栈上有 Dialogue: 0,0:58:16.52,0:58:19.94,Default,,0,0,0,,来自于这个组合式的运算符 Dialogue: 0,0:58:20.12,0:58:21.07,Default,,0,0,0,,以及其它的参数 Dialogue: 0,0:58:23.40,0:58:27.61,Default,,0,0,0,,现在 我们已经准备好 Dialogue: 0,0:58:28.49,0:58:29.69,Default,,0,0,0,,去调用另外的FACT-REC了 Dialogue: 0,0:58:30.20,0:58:31.43,Default,,0,0,0,,而让我们完成了这个调用以后 Dialogue: 0,0:58:31.56,0:58:33.64,Default,,0,0,0,,我们就要跳转到ACCUMULATE-LAST-ARG Dialogue: 0,0:58:34.12,0:58:35.20,Default,,0,0,0,,还记得这是做什么的么? Dialogue: 0,0:58:35.20,0:58:35.93,Default,,0,0,0,,它会说 Dialogue: 0,0:58:36.45,0:58:39.28,Default,,0,0,0,,我们会把这个调用的结果 Dialogue: 0,0:58:39.28,0:58:40.40,Default,,0,0,0,,和这个5相乘 Dialogue: 0,0:58:41.69,0:58:42.38,Default,,0,0,0,,但是请注意 Dialogue: 0,0:58:42.73,0:58:44.81,Default,,0,0,0,,我们现在处于另一个递归阶乘中 Dialogue: 0,0:58:45.72,0:58:48.92,Default,,0,0,0,,我们又要再次调用EVAL-DISPATCH Dialogue: 0,0:58:49.32,0:58:50.60,Default,,0,0,0,,然而我们并没有真正地“归约”它 Dialogue: 0,0:58:50.64,0:58:52.08,Default,,0,0,0,,因为现在栈上还有东西 Dialogue: 0,0:58:53.70,0:58:55.39,Default,,0,0,0,,栈上的这些东西说:“当你返回时” Dialogue: 0,0:58:55.40,0:58:57.52,Default,,0,0,0,,你最好把结果和放在这里的5相乘 Dialogue: 0,0:58:58.43,0:59:05.77,Default,,0,0,0,,所以当我们进行另外的调用 Dialogue: 0,0:59:07.12,0:59:08.84,Default,,0,0,0,,求值(- N 1) Dialogue: 0,0:59:09.30,0:59:11.05,Default,,0,0,0,,这会返回给我们另一个环境 Dialogue: 0,0:59:11.25,0:59:13.84,Default,,0,0,0,,其中N的新值为4 Dialogue: 0,0:59:14.60,0:59:16.22,Default,,0,0,0,,然后又将调用EVAL-DISPATCH Dialogue: 0,0:59:19.20,0:59:20.22,Default,,0,0,0,,我们又创建了另一个调用 Dialogue: 0,0:59:21.35,0:59:24.44,Default,,0,0,0,,这个4又会遇到相同的情况 Dialogue: 0,0:59:26.04,0:59:28.62,Default,,0,0,0,,我们最后会遇到对(FACT-REC N)的又一次调用 Dialogue: 0,0:59:30.02,0:59:32.68,Default,,0,0,0,,而这时候 栈上会有从最初的调用 Dialogue: 0,0:59:32.88,0:59:34.51,Default,,0,0,0,,到最近一次调用的东西 Dialogue: 0,0:59:35.36,0:59:36.91,Default,,0,0,0,,它们都在等待同一个东西 Dialogue: 0,0:59:36.91,0:59:39.16,Default,,0,0,0,,它们都要跳转到ACCUMULATE-LAST-ARG Dialogue: 0,0:59:40.51,0:59:42.94,Default,,0,0,0,,当然 当我们进行第四次调用时 Dialogue: 0,0:59:43.25,0:59:44.38,Default,,0,0,0,,会发生同样的事 Dialogue: 0,0:59:45.64,0:59:47.07,Default,,0,0,0,,如此往复 Dialogue: 0,0:59:47.30,0:59:48.60,Default,,0,0,0,,在这里 你在栈上看到的 Dialogue: 0,0:59:50.30,0:59:52.22,Default,,0,0,0,,栈上面实际存放的是 Dialogue: 0,0:59:52.22,0:59:54.59,Default,,0,0,0,,基本过程*以及5 Dialogue: 0,0:59:54.96,0:59:56.40,Default,,0,0,0,,而你要把它用来 Dialogue: 0,0:59:56.59,0:59:58.54,Default,,0,0,0,,调用ACCUMULATE-LAST-ARG Dialogue: 0,1:00:00.47,1:00:02.01,Default,,0,0,0,,就是这样 对吧? Dialogue: 0,1:00:02.01,1:00:04.75,Default,,0,0,0,,这跟它们在表达式中的顺序是一致的 Dialogue: 0,1:00:05.65,1:00:10.65,Default,,0,0,0,,实际上 你将要应用的运算符 Dialogue: 0,1:00:11.72,1:00:14.30,Default,,0,0,0,,以及当你返回时 Dialogue: 0,1:00:14.32,1:00:15.79,Default,,0,0,0,,需要去求积的参数 Dialogue: 0,1:00:15.80,1:00:16.91,Default,,0,0,0,,以及这里的括号 Dialogue: 0,1:00:16.94,1:00:18.96,Default,,0,0,0,,都在告诉你 在对它们进行积累 Dialogue: 0,1:00:19.62,1:00:21.88,Default,,0,0,0,,因此 你可以看到代换模型并不是这样的谎言 Dialogue: 0,1:00:22.56,1:00:23.63,Default,,0,0,0,,从某种意义上来说 它实际上是 Dialogue: 0,1:00:23.64,1:00:25.31,Default,,0,0,0,,存在于栈上的那些东西 Dialogue: 0,1:00:29.37,1:00:30.40,Default,,0,0,0,,好吧 从某种意义上来说 Dialogue: 0,1:00:30.81,1:00:32.48,Default,,0,0,0,,应该给你们解释了 Dialogue: 0,1:00:33.26,1:00:34.52,Default,,0,0,0,,或者 至少让你们相信 Dialogue: 0,1:00:35.93,1:00:38.72,Default,,0,0,0,,求值器会通过某些方式 Dialogue: 0,1:00:40.06,1:00:42.86,Default,,0,0,0,,迭代地去求值某些过程 Dialogue: 0,1:00:42.95,1:00:44.25,Default,,0,0,0,,而递归地去求值另外的过程 Dialogue: 0,1:00:45.26,1:00:47.45,Default,,0,0,0,,尽管从语法上看 Dialogue: 0,1:00:47.45,1:00:49.05,Default,,0,0,0,,它们都是递归过程 Dialogue: 0,1:00:49.40,1:00:50.64,Default,,0,0,0,,它又是如何做到的呢? Dialogue: 0,1:00:50.66,1:00:53.72,Default,,0,0,0,,其中的基本原因就是 Dialogue: 0,1:00:53.80,1:00:55.68,Default,,0,0,0,,求值器被设置为 Dialogue: 0,1:00:56.04,1:00:59.26,Default,,0,0,0,,只保存那些稍后会用到的东西 Dialogue: 0,1:01:01.09,1:01:04.25,Default,,0,0,0,,比如说 当你在把 Dialogue: 0,1:01:04.67,1:01:07.39,Default,,0,0,0,,在一个环境中求值表达式归约为 Dialogue: 0,1:01:07.87,1:01:09.87,Default,,0,0,0,,将某个过程应用在参数上时 Dialogue: 0,1:01:10.52,1:01:12.49,Default,,0,0,0,,它就不再需要最初的环境了 Dialogue: 0,1:01:13.37,1:01:16.65,Default,,0,0,0,,因为所需要的环境信息都被打包到 Dialogue: 0,1:01:17.88,1:01:19.36,Default,,0,0,0,,需要应用的那个过程中了 Dialogue: 0,1:01:20.75,1:01:21.61,Default,,0,0,0,,同样 类似地 Dialogue: 0,1:01:21.63,1:01:23.65,Default,,0,0,0,,当你求值一个参数表时 Dialogue: 0,1:01:23.65,1:01:25.20,Default,,0,0,0,,当你完成对表的求值时 Dialogue: 0,1:01:25.91,1:01:28.03,Default,,0,0,0,,当你求值完最后一个参数时 Dialogue: 0,1:01:28.20,1:01:31.61,Default,,0,0,0,,你就不再需要这个参数表了 对吧? Dialogue: 0,1:01:31.63,1:01:32.94,Default,,0,0,0,,你也就不再需要 Dialogue: 0,1:01:33.04,1:01:34.64,Default,,0,0,0,,求值这些参数所需的环境了 Dialogue: 0,1:01:36.69,1:01:40.89,Default,,0,0,0,,所以这个解释器如此“智能”的根本原因 Dialogue: 0,1:01:40.89,1:01:42.88,Default,,0,0,0,,根本不是因为它“智能” 只是因为它老实 Dialogue: 0,1:01:43.05,1:01:45.74,Default,,0,0,0,,它的原则就是:“只保存那些需要的” Dialogue: 0,1:01:48.70,1:01:51.00,Default,,0,0,0,,这里 让我来给你们展示 Dialogue: 0,1:01:53.07,1:01:57.20,Default,,0,0,0,,这是致使尾递归的根本原因 Dialogue: 0,1:01:58.31,1:02:00.20,Default,,0,0,0,,要记住 (RESOTRE CONTINUE)这条代码 Dialogue: 0,1:02:00.22,1:02:06.94,Default,,0,0,0,,它指的是 当我去求值过程体的时候 Dialogue: 0,1:02:08.96,1:02:11.00,Default,,0,0,0,,我应该告诉EVAL返回到 Dialogue: 0,1:02:11.25,1:02:12.54,Default,,0,0,0,,最初的求值 Dialogue: 0,1:02:12.54,1:02:14.25,Default,,0,0,0,,应该返回的地方 Dialogue: 0,1:02:15.17,1:02:15.95,Default,,0,0,0,,因此 从某种角度来说 Dialogue: 0,1:02:16.17,1:02:18.84,Default,,0,0,0,,你想知道是哪一行代码致使了尾递归 Dialogue: 0,1:02:18.89,1:02:19.44,Default,,0,0,0,,那么就是这一行 Dialogue: 0,1:02:19.92,1:02:21.53,Default,,0,0,0,,出于某些奇怪的原因 Dialogue: 0,1:02:21.77,1:02:24.80,Default,,0,0,0,,如果我想构建一个没有尾递归的求值器 Dialogue: 0,1:02:25.69,1:02:26.86,Default,,0,0,0,,我需要做的就是 Dialogue: 0,1:02:27.12,1:02:29.29,Default,,0,0,0,,在这里先不要去恢复CONTINUE Dialogue: 0,1:02:30.06,1:02:31.66,Default,,0,0,0,,而是在这里建立一个标号 Dialogue: 0,1:02:32.75,1:02:36.25,Default,,0,0,0,,用来标识完成过程应用后的返回位置 Dialogue: 0,1:02:37.64,1:02:39.71,Default,,0,0,0,,而我会把CONTINUE设置为这个标号 Dialogue: 0,1:02:39.92,1:02:41.21,Default,,0,0,0,,然后跳转到EVAL-DISPATCH Dialogue: 0,1:02:41.40,1:02:43.21,Default,,0,0,0,,然后EVAL-DISPATCH会回到这里 Dialogue: 0,1:02:43.79,1:02:44.30,Default,,0,0,0,,而这时 Dialogue: 0,1:02:44.32,1:02:45.28,Default,,0,0,0,,我会恢复CONTINUE Dialogue: 0,1:02:45.29,1:02:46.52,Default,,0,0,0,,并回到最初的返回位置 Dialogue: 0,1:02:47.92,1:02:51.00,Default,,0,0,0,,因此 这里唯一的后果就是 Dialogue: 0,1:02:51.15,1:02:52.68,Default,,0,0,0,,解释器不再是尾递归的了 Dialogue: 0,1:02:52.84,1:02:54.62,Default,,0,0,0,,它会给你完全相同的答案 Dialogue: 0,1:02:54.72,1:02:57.02,Default,,0,0,0,,只是当你执行迭代式阶乘 Dialogue: 0,1:02:57.05,1:02:58.36,Default,,0,0,0,,或者其它迭代过程时 Dialogue: 0,1:02:58.60,1:02:59.80,Default,,0,0,0,,它都会递归地去执行 Dialogue: 0,1:03:03.04,1:03:05.40,Default,,0,0,0,,然而 我对你们撒了一个小谎 Dialogue: 0,1:03:05.76,1:03:06.99,Default,,0,0,0,,因为我演示的 Dialogue: 0,1:03:07.02,1:03:08.33,Default,,0,0,0,,一个有些过于简化的解释器 Dialogue: 0,1:03:08.72,1:03:10.38,Default,,0,0,0,,这个解释器假设每个过程 Dialogue: 0,1:03:11.36,1:03:13.66,Default,,0,0,0,,只含有一条表达式 Dialogue: 0,1:03:13.89,1:03:14.54,Default,,0,0,0,,还记得吗 通常来说 Dialogue: 0,1:03:14.56,1:03:16.57,Default,,0,0,0,,过程的体是多条表达式组成的序列 Dialogue: 0,1:03:17.87,1:03:20.49,Default,,0,0,0,,所以没有什么新概念 Dialogue: 0,1:03:20.49,1:03:22.28,Default,,0,0,0,,让我来展示一下实际的求值器 Dialogue: 0,1:03:22.89,1:03:24.73,Default,,0,0,0,,是怎么来处理表达式序列的 Dialogue: 0,1:03:28.47,1:03:29.74,Default,,0,0,0,,这是现在的COMPOUND-APPLY Dialogue: 0,1:03:29.74,1:03:31.31,Default,,0,0,0,,和之前的唯一不同是 Dialogue: 0,1:03:32.07,1:03:34.33,Default,,0,0,0,,它不再直接地跳转到EVAL Dialogue: 0,1:03:35.98,1:03:38.03,Default,,0,0,0,,它先获取整个过程的体 Dialogue: 0,1:03:38.03,1:03:40.15,Default,,0,0,0,,在本例中 也就是表达式序列 Dialogue: 0,1:03:40.28,1:03:41.71,Default,,0,0,0,,然后跳转到EVAL-SEQUENCE Dialogue: 0,1:03:42.60,1:03:45.32,Default,,0,0,0,,EVAL-SEQUENCE是一个小型的循环 Dialogue: 0,1:03:46.83,1:03:49.98,Default,,0,0,0,,然后每次求值一条表达式 Dialogue: 0,1:03:52.63,1:03:53.85,Default,,0,0,0,,就是这样来求值的-- Dialogue: 0,1:03:53.90,1:03:54.94,Default,,0,0,0,,当它求值完一条表达式后 Dialogue: 0,1:03:54.97,1:03:56.86,Default,,0,0,0,,会跳转到这里 去求值下一条 Dialogue: 0,1:03:58.44,1:03:59.29,Default,,0,0,0,,当我完成了所有的求值后 Dialogue: 0,1:03:59.29,1:04:01.02,Default,,0,0,0,,我想要跳转到LAST-EXP Dialogue: 0,1:04:01.31,1:04:03.28,Default,,0,0,0,,我就只需要恢复CONTINUE寄存器 Dialogue: 0,1:04:03.92,1:04:05.28,Default,,0,0,0,,然后跳转到EVAL-DISPATCH Dialogue: 0,1:04:06.41,1:04:08.20,Default,,0,0,0,,同样的 如果你想要在这种求值器中 Dialogue: 0,1:04:08.20,1:04:10.35,Default,,0,0,0,,破坏尾递归机制 Dialogue: 0,1:04:10.64,1:04:13.71,Default,,0,0,0,,你只需要在LAST-EXP中不做特殊处理即可 Dialogue: 0,1:04:14.90,1:04:17.34,Default,,0,0,0,,也就是说 当你处理完最后一条表达式 Dialogue: 0,1:04:17.36,1:04:18.65,Default,,0,0,0,,你跳转到另外一个地方 Dialogue: 0,1:04:19.15,1:04:20.68,Default,,0,0,0,,在那个地方去恢复CONTINUE Dialogue: 0,1:04:21.90,1:04:23.26,Default,,0,0,0,,出于某些原因 Dialogue: 0,1:04:23.26,1:04:25.74,Default,,0,0,0,,很多Lisp求值器倾向于这么做 Dialogue: 0,1:04:26.55,1:04:28.44,Default,,0,0,0,,这样做的后果就是 Dialogue: 0,1:04:28.86,1:04:30.72,Default,,0,0,0,,迭代式过程也会使栈增长 Dialogue: 0,1:04:31.88,1:04:33.61,Default,,0,0,0,,还不清楚为什么会这样 Dialogue: 0,1:04:35.92,1:04:37.98,Default,,0,0,0,,好吧 我稍微来总结一下 Dialogue: 0,1:04:38.09,1:04:39.60,Default,,0,0,0,,毕竟这是一个大程序 Dialogue: 0,1:04:39.98,1:04:41.04,Default,,0,0,0,,又有很多细节 Dialogue: 0,1:04:41.12,1:04:42.25,Default,,0,0,0,,但关键点就是 Dialogue: 0,1:04:43.04,1:04:43.87,Default,,0,0,0,,从概念上来说 Dialogue: 0,1:04:44.04,1:04:46.08,Default,,0,0,0,,这跟翻译其它程序没什么不同 Dialogue: 0,1:04:47.06,1:04:48.06,Default,,0,0,0,,核心思想就是 Dialogue: 0,1:04:48.06,1:04:50.28,Default,,0,0,0,,我们已经有了通用求值器程序 Dialogue: 0,1:04:50.33,1:04:51.71,Default,,0,0,0,,一个元循环求值器 Dialogue: 0,1:04:51.87,1:04:53.07,Default,,0,0,0,,如果我们把它翻译为了Lisp Dialogue: 0,1:04:53.10,1:04:53.95,Default,,0,0,0,,那么我们就有了Lisp的所有东西 Dialogue: 0,1:04:54.33,1:04:55.15,Default,,0,0,0,,我们就是这么来做的 Dialogue: 0,1:04:57.98,1:04:59.68,Default,,0,0,0,,第二点则是 魔法消失了 Dialogue: 0,1:04:59.68,1:05:01.97,Default,,0,0,0,,这整个系统不再神秘了 对吧? Dialogue: 0,1:05:01.97,1:05:07.79,Default,,0,0,0,,原则上来说 这应该相当清楚了 Dialogue: 0,1:05:07.82,1:05:10.08,Default,,0,0,0,,只是还不太了解表结构的内存管理 Dialogue: 0,1:05:10.80,1:05:11.80,Default,,0,0,0,,我们后面会讲 Dialogue: 0,1:05:12.64,1:05:14.20,Default,,0,0,0,,这也并不困难 Dialogue: 0,1:05:15.45,1:05:16.35,Default,,0,0,0,,第三点就是 Dialogue: 0,1:05:16.35,1:05:17.52,Default,,0,0,0,,所有的这些尾递归 Dialogue: 0,1:05:18.24,1:05:21.96,Default,,0,0,0,,来自于严格的求值纪律 Dialogue: 0,1:05:22.55,1:05:24.51,Default,,0,0,0,,也就是只保存那些后面会用到的东西 Dialogue: 0,1:05:25.87,1:05:27.72,Default,,0,0,0,,而不是一些比较随意的原则 Dialogue: 0,1:05:27.76,1:05:29.86,Default,,0,0,0,,比如 无论什么时候我们调用一个子过程 Dialogue: 0,1:05:29.86,1:05:32.16,Default,,0,0,0,,我们会保存所有的寄存器并且返回 Dialogue: 0,1:05:33.94,1:05:36.49,Default,,0,0,0,,有些时候为了提效 这样做很值得 Dialogue: 0,1:05:37.15,1:05:39.96,Default,,0,0,0,,当你研究求值机器的内部原理时 Dialogue: 0,1:05:40.45,1:05:42.56,Default,,0,0,0,,这类东西就很值得去研究 Dialogue: 0,1:05:42.56,1:05:43.96,Default,,0,0,0,,因为它会带来显著的不同 Dialogue: 0,1:05:45.23,1:05:47.69,Default,,0,0,0,,我想现在基本上已经 Dialogue: 0,1:05:47.90,1:05:52.30,Default,,0,0,0,,把这个求值器讲得很清楚了 Dialogue: 0,1:05:52.56,1:05:53.90,Default,,0,0,0,,我希望你们能相信 Dialogue: 0,1:05:54.32,1:05:56.27,Default,,0,0,0,,真的有人能够 Dialogue: 0,1:05:56.84,1:05:58.56,Default,,0,0,0,,将一个Lisp求值器放在掌心之中 Dialogue: 0,1:05:59.07,1:06:00.49,Default,,0,0,0,,为了让你们死心塌地 Dialogue: 0,1:06:00.80,1:06:01.96,Default,,0,0,0,,我给你们看一个Lisp求值器 Dialogue: 0,1:06:02.54,1:06:04.06,Default,,0,0,0,,它就在我的手掌中 Dialogue: 0,1:06:06.16,1:06:10.56,Default,,0,0,0,,这块求值器芯片实际上 Dialogue: 0,1:06:10.89,1:06:13.70,Default,,0,0,0,,比我给你们展示的求值器还要复杂 Dialogue: 0,1:06:16.86,1:06:19.20,Default,,0,0,0,,这张图片效果更好 Dialogue: 0,1:06:22.07,1:06:22.57,Default,,0,0,0,,在这上面 Dialogue: 0,1:06:22.60,1:06:24.38,Default,,0,0,0,,你可以看到相同的宏观结构 Dialogue: 0,1:06:24.73,1:06:25.93,Default,,0,0,0,,这是寄存器阵列 Dialogue: 0,1:06:26.80,1:06:27.71,Default,,0,0,0,,这些是数据通路 Dialogue: 0,1:06:27.72,1:06:29.07,Default,,0,0,0,,这里有是有穷状态控制器 Dialogue: 0,1:06:29.80,1:06:31.04,Default,,0,0,0,,再强调一下 是有穷状态 Dialogue: 0,1:06:31.96,1:06:32.80,Default,,0,0,0,,全都在这里了 Dialogue: 0,1:06:32.81,1:06:34.16,Default,,0,0,0,,在另外的地方还有外部存储 Dialogue: 0,1:06:34.16,1:06:35.23,Default,,0,0,0,,用来存储数据 Dialogue: 0,1:06:35.75,1:06:37.63,Default,,0,0,0,,而这块芯片非常复杂 Dialogue: 0,1:06:37.64,1:06:39.16,Default,,0,0,0,,是因为它尝试更快地运行Lisp Dialogue: 0,1:06:39.66,1:06:42.97,Default,,0,0,0,,它具有非常非常之快的并行运算 Dialogue: 0,1:06:43.07,1:06:46.32,Default,,0,0,0,,比如说 如果你想要索引一个数组 Dialogue: 0,1:06:46.70,1:06:50.40,Default,,0,0,0,,同时又要检查该索引是否为一个整数 Dialogue: 0,1:06:50.43,1:06:52.86,Default,,0,0,0,,以及该索引没有越界 Dialogue: 0,1:06:53.04,1:06:55.02,Default,,0,0,0,,同时还要进行内存存取 Dialogue: 0,1:06:55.05,1:06:56.70,Default,,0,0,0,,它会同时进行这些事 Dialogue: 0,1:06:57.12,1:06:58.40,Default,,0,0,0,,如果这些操作都没有问题的话 Dialogue: 0,1:06:58.44,1:06:59.96,Default,,0,0,0,,最终就会在这里得到结果 Dialogue: 0,1:07:00.42,1:07:02.46,Default,,0,0,0,,因此 数据通路中大量的 Dialogue: 0,1:07:02.48,1:07:04.65,Default,,0,0,0,,复杂运算使得Lisp能够并行运行 Dialogue: 0,1:07:05.26,1:07:08.41,Default,,0,0,0,,这完全是求值Lisp的 Dialogue: 0,1:07:08.76,1:07:10.36,Default,,0,0,0,,一种无冒险的哲学 Dialogue: 0,1:07:10.64,1:07:13.20,Default,,0,0,0,,并且 这个的微指令也相当复杂 Dialogue: 0,1:07:13.45,1:07:17.56,Default,,0,0,0,,让我先看一看 Dialogue: 0,1:07:17.60,1:07:21.10,Default,,0,0,0,,这其中有大概389条 Dialogue: 0,1:07:21.68,1:07:23.85,Default,,0,0,0,,220比特的微指令 Dialogue: 0,1:07:24.07,1:07:27.94,Default,,0,0,0,,只因为这些数据通路非常复杂 Dialogue: 0,1:07:27.94,1:07:32.25,Default,,0,0,0,,整个芯片大概有89,000支晶体管 Dialogue: 0,1:07:33.56,1:07:36.86,Default,,0,0,0,,好吧 我希望通过这节课解答了大部分疑惑 Dialogue: 0,1:07:37.97,1:07:39.24,Default,,0,0,0,,也许你们想看一看这块芯片 Dialogue: 0,1:07:46.14,1:07:46.89,Default,,0,0,0,,好吧 先讲到这里 Dialogue: 0,1:07:56.46,1:07:56.75,Default,,0,0,0,,有问题吗? Dialogue: 0,1:07:59.00,1:08:00.42,Default,,0,0,0,,学生:您所讲的 听起来像是 Dialogue: 0,1:08:00.42,1:08:03.48,Default,,0,0,0,,如果把(RESTORE CONTINUE)放在合适的地方 Dialogue: 0,1:08:03.58,1:08:09.42,Default,,0,0,0,,这样之前递归求值的过程 Dialogue: 0,1:08:09.42,1:08:11.95,Default,,0,0,0,,现在就会变成迭代求值的 Dialogue: 0,1:08:12.67,1:08:15.36,Default,,0,0,0,,(意义不明) Dialogue: 0,1:08:15.60,1:08:17.54,Default,,0,0,0,,教授:我想我应该这么来说 Dialogue: 0,1:08:17.54,1:08:19.82,Default,,0,0,0,,如果把(RESTORE CONTINUE)放在了错误的位置 Dialogue: 0,1:08:20.55,1:08:25.48,Default,,0,0,0,,你就会让那些语法上看起来像递归的过程 Dialogue: 0,1:08:25.52,1:08:27.28,Default,,0,0,0,,在运行的时候不断地扩张栈 Dialogue: 0,1:08:28.64,1:08:30.52,Default,,0,0,0,,但这样是没有原因的 Dialogue: 0,1:08:33.15,1:08:35.12,Default,,0,0,0,,你可以自己去试一试 Dialogue: 0,1:08:35.15,1:08:38.09,Default,,0,0,0,,你可以在COMPOND-APPLY返回后 Dialogue: 0,1:08:38.18,1:08:40.78,Default,,0,0,0,,交换两、三条语句的顺序 Dialogue: 0,1:08:41.31,1:08:43.26,Default,,0,0,0,,那么你得到的就不再是尾递归了 Dialogue: 0,1:08:45.06,1:08:46.14,Default,,0,0,0,,我只是想强调 Dialogue: 0,1:08:46.16,1:08:47.40,Default,,0,0,0,,这其中没有什么魔法 Dialogue: 0,1:08:47.67,1:08:48.57,Default,,0,0,0,,这并不是 Dialogue: 0,1:08:49.31,1:08:52.17,Default,,0,0,0,,有什么智能的预处理程序 Dialogue: 0,1:08:52.65,1:08:55.45,Default,,0,0,0,,它会分析FACT-ITER这个程序 Dialogue: 0,1:08:55.47,1:08:56.73,Default,,0,0,0,,然后说 Dialogue: 0,1:08:57.42,1:08:58.86,Default,,0,0,0,,我注意到 Dialogue: 0,1:08:58.88,1:09:01.13,Default,,0,0,0,,完成这个调用 不需要我进行压栈 Dialogue: 0,1:09:01.13,1:09:02.88,Default,,0,0,0,,但是有些人是这么认为的 Dialogue: 0,1:09:03.76,1:09:05.38,Default,,0,0,0,,而是一种比这个还要蠢的机制 Dialogue: 0,1:09:05.38,1:09:07.50,Default,,0,0,0,,就是在合适的地方插入RESTORE指令 Dialogue: 0,1:09:08.56,1:09:09.79,Default,,0,0,0,,就可以自动地实现 Dialogue: 0,1:09:14.72,1:09:17.55,Default,,0,0,0,,学生:但这不会影响到时间复杂度 对吧? Dialogue: 0,1:09:17.58,1:09:17.87,Default,,0,0,0,,教授:不会 Dialogue: 0,1:09:18.60,1:09:21.77,Default,,0,0,0,,学生:它不会迭代地处理 Dialogue: 0,1:09:21.80,1:09:23.02,Default,,0,0,0,,而是会递归地处理 Dialogue: 0,1:09:23.02,1:09:27.34,Default,,0,0,0,,但就从完成这两个运算的时间来说 Dialogue: 0,1:09:27.37,1:09:29.22,Default,,0,0,0,,它们都是相同的 对吧? Dialogue: 0,1:09:29.47,1:09:29.76,Default,,0,0,0,,教授 :是的 Dialogue: 0,1:09:29.79,1:09:32.68,Default,,0,0,0,,尾递归不会改变任何东西的时间复杂度 Dialogue: 0,1:09:32.72,1:09:33.29,Default,,0,0,0,,因为 从某种意义上来说 Dialogue: 0,1:09:33.34,1:09:35.15,Default,,0,0,0,,两者都是相同的算法 Dialogue: 0,1:09:36.02,1:09:39.37,Default,,0,0,0,,它只是让这个过程迭代地运行 Dialogue: 0,1:09:41.00,1:09:42.64,Default,,0,0,0,,这样 当参数很大时 Dialogue: 0,1:09:42.68,1:09:44.22,Default,,0,0,0,,它不会耗尽所有的内存 Dialogue: 0,1:09:44.75,1:09:46.40,Default,,0,0,0,,因为这其中没有压栈 Dialogue: 0,1:09:48.35,1:09:50.24,Default,,0,0,0,,事实上 你们需要相信 Dialogue: 0,1:09:50.56,1:09:51.13,Default,,0,0,0,,当我们编写-- Dialogue: 0,1:09:51.64,1:09:53.78,Default,,0,0,0,,我们一直把这些代码称作“迭代” Dialogue: 0,1:09:53.93,1:09:57.99,Default,,0,0,0,,把(DEFINE (LOOP) (LOOP))称作无穷循环 Dialogue: 0,1:10:00.32,1:10:03.36,Default,,0,0,0,,这就是一个迭代 Dialogue: 0,1:10:03.65,1:10:05.66,Default,,0,0,0,,跟我们用DO语句来写无穷循环是一样的 Dialogue: 0,1:10:07.63,1:10:09.28,Default,,0,0,0,,它们只是语法上不同而已 Dialogue: 0,1:10:09.28,1:10:11.32,Default,,0,0,0,,它们实际上都是迭代 Dialogue: 0,1:10:14.73,1:10:16.08,Default,,0,0,0,,它们并不改变时间复杂度 Dialogue: 0,1:10:16.11,1:10:18.53,Default,,0,0,0,,但是它会把它们变成真正的迭代 Dialogue: 0,1:10:21.68,1:10:23.80,Default,,0,0,0,,好吧 下课 Dialogue: 0,1:10:24.25,1:10:40.73,Declare,,0,0,0,,{\fad(500,500)}MIT OpenCourseWare\Nhttp://ocw.mit.edu Dialogue: 0,1:10:24.25,1:10:40.73,Declare,,0,0,0,,{\an2\fad(500,500)}本项目主页\Nhttps://github.com/DeathKing/Learning-SICP ================================================ FILE: Ass/lec9b.eng.ass ================================================ [Script Info] ; Script generated by Aegisub 3.2.2 ; http://www.aegisub.org/ Title: Default Aegisub file ScriptType: v4.00+ WrapStyle: 0 ScaledBorderAndShadow: yes YCbCr Matrix: TV.601 PlayResX: 640 PlayResY: 480 [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: EN,Calisto MT,21,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 Style: Declare,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,8,10,10,10,1 Style: staff,微软雅黑,30,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,2,5,10,10,10,1 Style: title,微软雅黑,35,&H001D64D9,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,1,5,10,10,10,1 Style: Default,雅黑宋体,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,1,0,2,10,10,30,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:16.30,0:00:18.08,EN,,0,0,0,,PROFESSOR: Well, I hope you appreciate that we have Dialogue: 0,0:00:20.01,0:00:22.73,EN,,0,0,0,,we have inducted you into some real magic, Dialogue: 0,0:00:24.20,0:00:27.24,EN,,0,0,0,,the magic of building languages Dialogue: 0,0:00:27.42,0:00:28.72,EN,,0,0,0,,really building new languages. Dialogue: 0,0:00:29.69,0:00:30.40,EN,,0,0,0,,What have we looked at? Dialogue: 0,0:00:30.43,0:00:32.78,EN,,0,0,0,,We've looked at an Escher picture language. Dialogue: 0,0:00:38.92,0:00:41.15,EN,,0,0,0,,OK? this language invented by Peter Henderson. Dialogue: 0,0:00:42.01,0:00:46.49,EN,,0,0,0,,We looked at digital logic language. Dialogue: 0,0:00:53.16,0:00:55.55,EN,,0,0,0,,Let's see.We've looked at the query language. Dialogue: 0,0:00:59.70,0:01:00.78,EN,,0,0,0,,And the thing you should realize is, Dialogue: 0,0:01:00.81,0:01:03.10,EN,,0,0,0,,even though these were toy examples, Dialogue: 0,0:01:04.70,0:01:07.61,EN,,0,0,0,,they really are the kernels of really useful things. Dialogue: 0,0:01:08.25,0:01:09.48,EN,,0,0,0,,So, for instance, Dialogue: 0,0:01:10.12,0:01:11.18,EN,,0,0,0,,the Escher picture language Dialogue: 0,0:01:11.20,0:01:14.33,EN,,0,0,0,,was taken byHenry Wu, who's a student at MIT, Dialogue: 0,0:01:14.88,0:01:16.43,EN,,0,0,0,,and developed into a real Dialogue: 0,0:01:16.97,0:01:19.45,EN,,0,0,0,,language for laying out PC boards, Dialogue: 0,0:01:20.35,0:01:22.56,EN,,0,0,0,,based just on extending those structures. Dialogue: 0,0:01:23.24,0:01:24.65,EN,,0,0,0,,And the digital logic language, Dialogue: 0,0:01:24.68,0:01:26.08,EN,,0,0,0,,Gerry mentioned when he showed it to you, Dialogue: 0,0:01:26.43,0:01:29.92,EN,,0,0,0,,was really extended to be used as the basis for a simulator Dialogue: 0,0:01:30.85,0:01:32.96,EN,,0,0,0,,that was used to design a real computer. Dialogue: 0,0:01:33.46,0:01:34.32,EN,,0,0,0,,And the query language, Dialogue: 0,0:01:34.35,0:01:36.44,EN,,0,0,0,,of course, is kind of the germ of prolog. Dialogue: 0,0:01:37.51,0:01:39.07,EN,,0,0,0,,So we built all of these languages, Dialogue: 0,0:01:39.55,0:01:40.65,EN,,0,0,0,,they're all based on LISP. Dialogue: 0,0:01:43.63,0:01:44.59,EN,,0,0,0,,A lot of people ask Dialogue: 0,0:01:45.27,0:01:48.73,EN,,0,0,0,,what particular problems is LISP good for solving for? Dialogue: 0,0:01:48.75,0:01:49.93,EN,,0,0,0,,The answer is LISP is not... Dialogue: 0,0:01:50.33,0:01:52.65,EN,,0,0,0,,LISP is not good for solving any particular problems. Dialogue: 0,0:01:53.53,0:01:54.60,EN,,0,0,0,,What LISP is good for Dialogue: 0,0:01:54.73,0:01:57.15,EN,,0,0,0,,is constructing within it the right language Dialogue: 0,0:01:57.18,0:01:58.57,EN,,0,0,0,,to solve the problems you want to solve, Dialogue: 0,0:01:59.17,0:02:00.44,EN,,0,0,0,,and that's how you should think about it. Dialogue: 0,0:02:01.47,0:02:03.39,EN,,0,0,0,,So all of these languages were based on LISP. Dialogue: 0,0:02:04.57,0:02:05.72,EN,,0,0,0,,Now, what's LISP based on? Dialogue: 0,0:02:06.97,0:02:07.88,EN,,0,0,0,,Where's that come from? Dialogue: 0,0:02:07.90,0:02:09.40,EN,,0,0,0,,Well, we looked at that too. Dialogue: 0,0:02:09.58,0:02:16.09,EN,,0,0,0,,We looked at the meta-circular evaluator Dialogue: 0,0:02:21.53,0:02:23.40,EN,,0,0,0,,the meta-circular evaluator and sort of said Dialogue: 0,0:02:23.42,0:02:25.76,EN,,0,0,0,,well, LISP is based on LISP. Dialogue: 0,0:02:25.80,0:02:27.48,EN,,0,0,0,,And when we start looking at that, Dialogue: 0,0:02:28.27,0:02:29.95,EN,,0,0,0,,we've got to do some real magic, right? Dialogue: 0,0:02:29.95,0:02:31.74,EN,,0,0,0,,So what does that mean, right? Dialogue: 0,0:02:31.74,0:02:34.96,EN,,0,0,0,,Y operators, and fixed points, Dialogue: 0,0:02:35.76,0:02:38.33,EN,,0,0,0,,and the idea that what this means is Dialogue: 0,0:02:38.36,0:02:41.44,EN,,0,0,0,,that LISP is somehow the fixed-point equation for the Dialogue: 0,0:02:42.20,0:02:45.42,EN,,0,0,0,,for this funny set of things which are defined in terms of themselves. Dialogue: 0,0:02:47.40,0:02:48.56,EN,,0,0,0,,Now, it's real magic. Dialogue: 0,0:02:49.07,0:02:52.35,EN,,0,0,0,,Well, today, for a final piece of magic, Dialogue: 0,0:02:52.62,0:02:54.03,EN,,0,0,0,,we're going to make all the magic go away. Dialogue: 0,0:03:06.80,0:03:07.98,EN,,0,0,0,,We already know how to do that. Dialogue: 0,0:03:09.77,0:03:10.76,EN,,0,0,0,,The idea is, we're going to take Dialogue: 0,0:03:11.13,0:03:12.73,EN,,0,0,0,,the register machine architecture Dialogue: 0,0:03:13.36,0:03:15.50,EN,,0,0,0,,and show how to implement LISP on terms of that. Dialogue: 0,0:03:15.50,0:03:17.93,EN,,0,0,0,,And, remember, the idea of the register machine Dialogue: 0,0:03:19.60,0:03:24.68,EN,,0,0,0,,is that there's a fixed and finite part of the machine. Dialogue: 0,0:03:24.72,0:03:26.12,EN,,0,0,0,,There's a finite-state controller, Dialogue: 0,0:03:26.12,0:03:27.87,EN,,0,0,0,,which dose particular thing Dialogue: 0,0:03:27.88,0:03:29.31,EN,,0,0,0,,with a particular amount of hardware. Dialogue: 0,0:03:30.51,0:03:31.74,EN,,0,0,0,,There are particular data paths, Dialogue: 0,0:03:31.76,0:03:33.24,EN,,0,0,0,,the operation the machine does Dialogue: 0,0:03:33.55,0:03:35.29,EN,,0,0,0,,And then, in order to implement recursion Dialogue: 0,0:03:35.53,0:03:37.60,EN,,0,0,0,,and sustain the illusion of infinity, Dialogue: 0,0:03:37.82,0:03:39.77,EN,,0,0,0,,there's some large amount of memory, which is the stack. Dialogue: 0,0:03:42.06,0:03:43.72,EN,,0,0,0,,So, if we implement LISP Dialogue: 0,0:03:43.92,0:03:45.50,EN,,0,0,0,,in terms of a register machine, Dialogue: 0,0:03:47.02,0:03:48.35,EN,,0,0,0,,then everything ought to become, Dialogue: 0,0:03:48.40,0:03:49.85,EN,,0,0,0,,at this point,completely concrete. Dialogue: 0,0:03:49.85,0:03:51.23,EN,,0,0,0,,All the magic should go away. Dialogue: 0,0:03:51.65,0:03:53.52,EN,,0,0,0,,And, by the end of this talk, Dialogue: 0,0:03:53.53,0:03:54.78,EN,,0,0,0,,I want you get the feeling Dialogue: 0,0:03:55.14,0:03:59.05,EN,,0,0,0,,that, as opposed to this very mysterious meta-circular evaluator Dialogue: 0,0:03:59.67,0:04:02.60,EN,,0,0,0,,that a LISP evaluator really is something that's concrete enough Dialogue: 0,0:04:02.85,0:04:04.57,EN,,0,0,0,,that you can hold in the palm of your hand. Dialogue: 0,0:04:04.76,0:04:06.24,EN,,0,0,0,,You should be able to imagine holding Dialogue: 0,0:04:06.57,0:04:07.90,EN,,0,0,0,,holding a LISP interpreter there. Dialogue: 0,0:04:09.63,0:04:10.94,EN,,0,0,0,,All right, how are we going to do this? Dialogue: 0,0:04:10.95,0:04:12.76,EN,,0,0,0,,We already have all the ingredients. Dialogue: 0,0:04:13.96,0:04:17.45,EN,,0,0,0,,See, what you learned last time from Gerry Dialogue: 0,0:04:17.60,0:04:21.47,EN,,0,0,0,,is how to take any particular couple of LISP procedures. Dialogue: 0,0:04:22.60,0:04:24.28,EN,,0,0,0,,and hand-translate them Dialogue: 0,0:04:24.75,0:04:26.67,EN,,0,0,0,,into something that runs on a register machine. Dialogue: 0,0:04:28.20,0:04:30.52,EN,,0,0,0,,So, to implement all of LISP on a register machine, Dialogue: 0,0:04:30.57,0:04:31.44,EN,,0,0,0,,all we have to do Dialogue: 0,0:04:31.69,0:04:33.45,EN,,0,0,0,,is take the particular procedures Dialogue: 0,0:04:33.68,0:04:35.42,EN,,0,0,0,,that are the meta-circular evaluator Dialogue: 0,0:04:36.17,0:04:38.11,EN,,0,0,0,,and hand-translate them for a register machine. Dialogue: 0,0:04:39.04,0:04:40.25,EN,,0,0,0,,And that does all of LISP Dialogue: 0,0:04:42.14,0:04:43.00,EN,,0,0,0,,Right? So, in principle, Dialogue: 0,0:04:43.02,0:04:44.43,EN,,0,0,0,,we already know how to do this. Dialogue: 0,0:04:45.38,0:04:46.54,EN,,0,0,0,,And, indeed, it's going to be no Dialogue: 0,0:04:46.68,0:04:48.86,EN,,0,0,0,,no different, in kind, Dialogue: 0,0:04:50.00,0:04:53.40,EN,,0,0,0,,from in say recursive factorial Dialogue: 0,0:04:53.42,0:04:54.67,EN,,0,0,0,,or recursive Fibonacci. Dialogue: 0,0:04:54.67,0:04:56.00,EN,,0,0,0,,It's just bigger and there's more of it. Dialogue: 0,0:04:56.84,0:04:58.03,EN,,0,0,0,,So it'd just be more details, Dialogue: 0,0:04:58.04,0:04:59.66,EN,,0,0,0,,but nothing really conceptually new. Dialogue: 0,0:05:01.48,0:05:03.02,EN,,0,0,0,,And also, when we've done that, Dialogue: 0,0:05:03.08,0:05:04.76,EN,,0,0,0,,and the thing is completely explicit, Dialogue: 0,0:05:04.87,0:05:06.91,EN,,0,0,0,,and we see how to implement LISP Dialogue: 0,0:05:06.94,0:05:10.08,EN,,0,0,0,,in terms of the actual sequential register operations, Dialogue: 0,0:05:10.16,0:05:11.63,EN,,0,0,0,,that's going to be our final Dialogue: 0,0:05:11.95,0:05:14.16,EN,,0,0,0,,most explicit model of LISP in this course. Dialogue: 0,0:05:14.81,0:05:16.95,EN,,0,0,0,,And, remember, that's a progression through this course. Dialogue: 0,0:05:16.95,0:05:18.25,EN,,0,0,0,,We started out with substitution, Dialogue: 0,0:05:18.28,0:05:19.58,EN,,0,0,0,,which is sort of like algebra. Dialogue: 0,0:05:20.24,0:05:21.87,EN,,0,0,0,,And then we went to the environment model, Dialogue: 0,0:05:21.88,0:05:24.00,EN,,0,0,0,,which talked about the actual frames Dialogue: 0,0:05:24.03,0:05:25.31,EN,,0,0,0,,and how they got linked together. Dialogue: 0,0:05:26.32,0:05:27.88,EN,,0,0,0,,And then we made that more concrete Dialogue: 0,0:05:27.90,0:05:29.36,EN,,0,0,0,,in the meta-circular evaluator. Dialogue: 0,0:05:31.05,0:05:31.64,EN,,0,0,0,,There are things Dialogue: 0,0:05:31.87,0:05:33.98,EN,,0,0,0,,the meta-circular evaluator doesn't tell us. Dialogue: 0,0:05:34.36,0:05:35.34,EN,,0,0,0,,You should realize that. Dialogue: 0,0:05:36.09,0:05:38.64,EN,,0,0,0,,For instance, it left unanswered the question Dialogue: 0,0:05:38.73,0:05:42.67,EN,,0,0,0,,of how a procedure, like recursive factorial here, Dialogue: 0,0:05:45.17,0:05:47.13,EN,,0,0,0,,somehow takes space that grows. Dialogue: 0,0:05:47.21,0:05:47.98,EN,,0,0,0,,On the other hand, Dialogue: 0,0:05:48.16,0:05:51.94,EN,,0,0,0,,a procedure which also looks syntactically recursive, Dialogue: 0,0:05:52.11,0:05:55.07,EN,,0,0,0,,called fact-iter, somehow doesn't take space. Dialogue: 0,0:05:55.10,0:05:59.16,EN,,0,0,0,,We justify that it doesn't need to take space Dialogue: 0,0:06:00.50,0:06:01.96,EN,,0,0,0,,by showing the substitution model. Dialogue: 0,0:06:01.96,0:06:02.94,EN,,0,0,0,,But we didn't really say Dialogue: 0,0:06:03.42,0:06:06.76,EN,,0,0,0,,how it happens that the machine manages to do that, Dialogue: 0,0:06:07.31,0:06:08.91,EN,,0,0,0,,that that has to do with the details Dialogue: 0,0:06:09.02,0:06:11.12,EN,,0,0,0,,of how arguments are passed to procedures Dialogue: 0,0:06:12.48,0:06:13.69,EN,,0,0,0,,And that's the thing we didn't see Dialogue: 0,0:06:13.71,0:06:15.34,EN,,0,0,0,,in the meta-circular evaluator Dialogue: 0,0:06:15.36,0:06:17.40,EN,,0,0,0,,precisely because the way arguments Dialogue: 0,0:06:17.42,0:06:19.20,EN,,0,0,0,,got passed to procedures in this LISP Dialogue: 0,0:06:19.70,0:06:20.59,EN,,0,0,0,,depended on Dialogue: 0,0:06:21.02,0:06:23.50,EN,,0,0,0,,the way arguments got passed to procedures in this LISP. Dialogue: 0,0:06:25.87,0:06:29.02,EN,,0,0,0,,But, now, that's going to become extremely explicit. Dialogue: 0,0:06:30.74,0:06:31.12,EN,,0,0,0,,OK. Dialogue: 0,0:06:31.23,0:06:34.30,EN,,0,0,0,,Well, before going on to the evaluator, Dialogue: 0,0:06:34.36,0:06:35.53,EN,,0,0,0,,let me just give you a sense of Dialogue: 0,0:06:35.55,0:06:37.00,EN,,0,0,0,,what a whole LISP system looks like Dialogue: 0,0:06:37.60,0:06:39.36,EN,,0,0,0,,so you can see the parts we're going to talk about Dialogue: 0,0:06:39.40,0:06:40.81,EN,,0,0,0,,and the parts we're not going to talk about. Dialogue: 0,0:06:43.18,0:06:47.42,EN,,0,0,0,,Let's see, over here is a happy LISP user, Dialogue: 0,0:06:48.67,0:06:52.65,EN,,0,0,0,,and the LISP user is talking to something called the reader. Dialogue: 0,0:07:00.36,0:07:01.53,EN,,0,0,0,,The reader's job in life Dialogue: 0,0:07:01.95,0:07:13.23,EN,,0,0,0,,is to take characters from the user Dialogue: 0,0:07:14.17,0:07:16.62,EN,,0,0,0,,and turn them into data structures Dialogue: 0,0:07:17.20,0:07:19.37,EN,,0,0,0,,in something called a list structure memory. Dialogue: 0,0:07:30.00,0:07:31.72,EN,,0,0,0,,All right, so the reader is going to take Dialogue: 0,0:07:32.65,0:07:33.95,EN,,0,0,0,,symbols, parentheses, Dialogue: 0,0:07:34.48,0:07:37.12,EN,,0,0,0,,and A's and B's, and 1s and 3s that you type in, Dialogue: 0,0:07:37.18,0:07:39.04,EN,,0,0,0,,and turn these into actual list structure: Dialogue: 0,0:07:39.15,0:07:40.54,EN,,0,0,0,,pairs, and pointers, and things. Dialogue: 0,0:07:42.35,0:07:43.92,EN,,0,0,0,,And so, by the time evaluator is going, Dialogue: 0,0:07:43.93,0:07:45.10,EN,,0,0,0,,there are no characters in the world. Dialogue: 0,0:07:45.85,0:07:48.16,EN,,0,0,0,,And, of course, in more modern Lisp systems, there's Dialogue: 0,0:07:49.00,0:07:50.44,EN,,0,0,0,,there's sort a big morass here Dialogue: 0,0:07:50.44,0:07:52.17,EN,,0,0,0,,that might sit between the user and the reader: Dialogue: 0,0:07:52.41,0:07:54.52,EN,,0,0,0,,you know, Windows systems, in top levels, Dialogue: 0,0:07:54.77,0:07:56.03,EN,,0,0,0,,and mice, and all kinds of things. Dialogue: 0,0:07:56.28,0:07:58.20,EN,,0,0,0,,But conceptually, characters are coming in. Dialogue: 0,0:07:59.93,0:08:04.32,EN,,0,0,0,,All right, the reader transforms these into pointers Dialogue: 0,0:08:05.56,0:08:07.28,EN,,0,0,0,,pointers to stuff in this memory, Dialogue: 0,0:08:08.27,0:08:10.94,EN,,0,0,0,,and that's what the evaluator sees Dialogue: 0,0:08:15.55,0:08:16.04,EN,,0,0,0,,OK? Dialogue: 0,0:08:17.02,0:08:18.88,EN,,0,0,0,,The evaluator has a bunch of helpers. Dialogue: 0,0:08:19.78,0:08:23.16,EN,,0,0,0,,It has all possible primitive operators you might want. Dialogue: 0,0:08:23.16,0:08:24.91,EN,,0,0,0,,So there's a completely separate box, Dialogue: 0,0:08:28.40,0:08:30.25,EN,,0,0,0,,a floating point unit, Dialogue: 0,0:08:32.22,0:08:34.40,EN,,0,0,0,,or all sorts of things, which do the primitive operators. Dialogue: 0,0:08:35.39,0:08:37.68,EN,,0,0,0,,there's and, if you want more special primitives, Dialogue: 0,0:08:37.71,0:08:39.02,EN,,0,0,0,,you build more primitive operators, Dialogue: 0,0:08:39.05,0:08:40.48,EN,,0,0,0,,but they're separate from the evaluator. Dialogue: 0,0:08:42.08,0:08:43.77,EN,,0,0,0,,The evaluator finally gets an answer Dialogue: 0,0:08:45.16,0:08:46.76,EN,,0,0,0,,and communicates that to the printer. Dialogue: 0,0:08:50.62,0:08:52.01,EN,,0,0,0,,And now, the printer's job in life Dialogue: 0,0:08:52.01,0:08:54.54,EN,,0,0,0,,is this list structure coming from the evaluator, Dialogue: 0,0:08:55.39,0:08:56.99,EN,,0,0,0,,and turn it back into characters, Dialogue: 0,0:09:01.85,0:09:04.07,EN,,0,0,0,,and communicate them to the user through Dialogue: 0,0:09:04.28,0:09:05.66,EN,,0,0,0,,whatever interface there is. Dialogue: 0,0:09:08.05,0:09:11.23,EN,,0,0,0,,OK. Well, today, what we're going to talk about is this evaluator. Dialogue: 0,0:09:12.67,0:09:15.20,EN,,0,0,0,,The primitive operators have nothing particular to do with LISP, Dialogue: 0,0:09:15.20,0:09:18.14,EN,,0,0,0,,they're however you like to implement primitive operations. Dialogue: 0,0:09:19.36,0:09:22.18,EN,,0,0,0,,The reader and printer are actually complicated, Dialogue: 0,0:09:22.18,0:09:23.55,EN,,0,0,0,,but we're not going to talk about them. Dialogue: 0,0:09:24.68,0:09:27.10,EN,,0,0,0,,They sort of have to do with details of how you might build Dialogue: 0,0:09:27.10,0:09:28.92,EN,,0,0,0,,build up list structure from characters. Dialogue: 0,0:09:29.90,0:09:31.18,EN,,0,0,0,,So that is a long story, Dialogue: 0,0:09:31.18,0:09:32.32,EN,,0,0,0,,but we're not going to talk about it, Dialogue: 0,0:09:32.49,0:09:33.69,EN,,0,0,0,,the list structure memory, Dialogue: 0,0:09:34.36,0:09:35.63,EN,,0,0,0,,we'll talk about next time. Dialogue: 0,0:09:36.93,0:09:39.72,EN,,0,0,0,,So, pretty much, except for the details of reading and printing, Dialogue: 0,0:09:40.12,0:09:41.71,EN,,0,0,0,,the only mystery that's going to be left Dialogue: 0,0:09:41.72,0:09:43.05,EN,,0,0,0,,after you see the evaluator Dialogue: 0,0:09:43.25,0:09:45.85,EN,,0,0,0,,is how you build list structure on conventional memories. Dialogue: 0,0:09:46.65,0:09:48.20,EN,,0,0,0,,But we'll worry about that next time too. Dialogue: 0,0:09:50.58,0:09:51.04,EN,,0,0,0,,OK. Dialogue: 0,0:09:53.34,0:09:56.11,EN,,0,0,0,,Well, let's start talking about the evaluator. Dialogue: 0,0:09:56.20,0:09:58.32,EN,,0,0,0,,The one that we're going to show you, Dialogue: 0,0:09:58.49,0:10:01.12,EN,,0,0,0,,of course, is not, I think, nothing special about it. Dialogue: 0,0:10:01.15,0:10:04.56,EN,,0,0,0,,It's just a particular register machine that runs LISP. Dialogue: 0,0:10:04.81,0:10:06.09,EN,,0,0,0,,And it has seven registers, Dialogue: 0,0:10:07.88,0:10:09.26,EN,,0,0,0,,and here are the seven registers. Dialogue: 0,0:10:09.89,0:10:12.38,EN,,0,0,0,,There's a register, called EXP Dialogue: 0,0:10:14.12,0:10:15.53,EN,,0,0,0,,and its job is to hold Dialogue: 0,0:10:16.36,0:10:18.03,EN,,0,0,0,,the expression to be evaluated. Dialogue: 0,0:10:18.37,0:10:19.80,EN,,0,0,0,,And by that, I mean Dialogue: 0,0:10:20.38,0:10:21.64,EN,,0,0,0,,it's going to hold a pointer Dialogue: 0,0:10:22.03,0:10:23.55,EN,,0,0,0,,to someplace in list structure memory Dialogue: 0,0:10:23.56,0:10:25.32,EN,,0,0,0,,the expression to be evaluated. Dialogue: 0,0:10:26.55,0:10:27.82,EN,,0,0,0,,There's a register, called ENV, Dialogue: 0,0:10:28.88,0:10:30.28,EN,,0,0,0,,which holds the environment Dialogue: 0,0:10:31.00,0:10:33.05,EN,,0,0,0,,in which this expression is to be evaluated. Dialogue: 0,0:10:34.07,0:10:35.02,EN,,0,0,0,,And, again, I made a pointer. Dialogue: 0,0:10:35.02,0:10:36.75,EN,,0,0,0,,The environment is some data structure. Dialogue: 0,0:10:38.24,0:10:40.14,EN,,0,0,0,,There's a register, called FUN, which will Dialogue: 0,0:10:40.75,0:10:42.54,EN,,0,0,0,,which will hold the procedure to be applied Dialogue: 0,0:10:42.57,0:10:43.96,EN,,0,0,0,,when you go to apply a procedure. Dialogue: 0,0:10:44.56,0:10:46.24,EN,,0,0,0,,A register, called ARGL, Dialogue: 0,0:10:47.36,0:10:49.34,EN,,0,0,0,,which holds the list of evaluated arguments. Dialogue: 0,0:10:50.54,0:10:51.60,EN,,0,0,0,,What you can start seeing here is Dialogue: 0,0:10:51.63,0:10:53.14,EN,,0,0,0,,the basic structure of the evaluator. Dialogue: 0,0:10:53.14,0:10:54.49,EN,,0,0,0,,Remember how evaluators work. Dialogue: 0,0:10:54.49,0:10:56.62,EN,,0,0,0,,There's a piece that takes expressions and environments, Dialogue: 0,0:10:57.67,0:10:59.71,EN,,0,0,0,,and there's a piece that takes functions Dialogue: 0,0:10:59.74,0:11:02.14,EN,,0,0,0,,or procedures and arguments. Dialogue: 0,0:11:03.48,0:11:06.30,EN,,0,0,0,,And going back and forth around here is the eval/apply loop. Dialogue: 0,0:11:07.40,0:11:09.69,EN,,0,0,0,,So those are the basic pieces of the eval and apply. Dialogue: 0,0:11:10.20,0:11:10.99,EN,,0,0,0,,Then there's some other things, Dialogue: 0,0:11:11.00,0:11:11.61,EN,,0,0,0,,there's continue. Dialogue: 0,0:11:11.61,0:11:15.34,EN,,0,0,0,,You just saw before how the continue register is used to Dialogue: 0,0:11:15.34,0:11:18.04,EN,,0,0,0,,implement recursion and stack discipline. Dialogue: 0,0:11:18.94,0:11:20.68,EN,,0,0,0,,There's a register that's going to hold the Dialogue: 0,0:11:20.94,0:11:22.52,EN,,0,0,0,,result of some evaluation. Dialogue: 0,0:11:24.14,0:11:24.89,EN,,0,0,0,,And then, besides that, Dialogue: 0,0:11:24.89,0:11:26.43,EN,,0,0,0,,there's one temporary register, Dialogue: 0,0:11:26.70,0:11:27.29,EN,,0,0,0,,called UNEV, Dialogue: 0,0:11:27.29,0:11:29.04,EN,,0,0,0,,which typically, in the evaluator, Dialogue: 0,0:11:29.28,0:11:32.72,EN,,0,0,0,,is going to be used to hold temporary pieces of the Dialogue: 0,0:11:32.89,0:11:33.95,EN,,0,0,0,,expression you're working on, Dialogue: 0,0:11:33.95,0:11:35.72,EN,,0,0,0,,which you haven't gotten around to evaluate yet Dialogue: 0,0:11:36.97,0:11:39.82,EN,,0,0,0,,Right? So there's my machine: a seven-register machine. Dialogue: 0,0:11:40.96,0:11:42.98,EN,,0,0,0,,And, of course, you might want to make a machine with Dialogue: 0,0:11:42.98,0:11:44.96,EN,,0,0,0,,a lot more registers to get better performance, Dialogue: 0,0:11:44.97,0:11:47.05,EN,,0,0,0,,but this is just a tiny, minimal one. Dialogue: 0,0:11:48.48,0:11:49.58,EN,,0,0,0,,Well, how about the data paths? Dialogue: 0,0:11:49.78,0:11:53.66,EN,,0,0,0,,This machine has a lot of special operations for LISP. Dialogue: 0,0:11:55.10,0:11:58.08,EN,,0,0,0,,So, here are some typical data paths. Dialogue: 0,0:12:00.12,0:12:01.04,EN,,0,0,0,,A typical one might be, Dialogue: 0,0:12:01.37,0:12:03.40,EN,,0,0,0,,oh, assign to the VAL register Dialogue: 0,0:12:03.40,0:12:04.80,EN,,0,0,0,,the contents of the EXP register. Dialogue: 0,0:12:05.71,0:12:08.01,EN,,0,0,0,,That's in terms of those diagrams you saw, Dialogue: 0,0:12:08.03,0:12:10.81,EN,,0,0,0,,that's a little button on some arrow. Dialogue: 0,0:12:11.90,0:12:13.13,EN,,0,0,0,,Here's a more complicated one. Dialogue: 0,0:12:13.69,0:12:14.80,EN,,0,0,0,,It says branch, Dialogue: 0,0:12:15.23,0:12:19.58,EN,,0,0,0,,if the thing in the expression register is a conditional Dialogue: 0,0:12:20.49,0:12:22.72,EN,,0,0,0,,to some label here, called the ev-conditional. Dialogue: 0,0:12:23.80,0:12:26.23,EN,,0,0,0,,And you can imagine this implemented in a lot of different ways. Dialogue: 0,0:12:26.23,0:12:28.36,EN,,0,0,0,,You might imagine this conditional test Dialogue: 0,0:12:28.36,0:12:29.98,EN,,0,0,0,,as a special purpose sub-routine, Dialogue: 0,0:12:30.60,0:12:33.95,EN,,0,0,0,,and conditional might be represented as some data abstraction Dialogue: 0,0:12:33.96,0:12:36.00,EN,,0,0,0,,that you don't care about at this level of detail. Dialogue: 0,0:12:36.61,0:12:37.98,EN,,0,0,0,,So that might be done as a sub-routine. Dialogue: 0,0:12:37.98,0:12:40.67,EN,,0,0,0,,This might be a machine with hardware-types, Dialogue: 0,0:12:40.90,0:12:44.04,EN,,0,0,0,,and conditional might be testing some bits for a particular code. Dialogue: 0,0:12:45.35,0:12:46.41,EN,,0,0,0,,There are all sorts of ways that's Dialogue: 0,0:12:46.41,0:12:48.48,EN,,0,0,0,,beneath the level of abstraction we're looking at. Dialogue: 0,0:12:50.19,0:12:51.71,EN,,0,0,0,,Another kind of operation, Dialogue: 0,0:12:51.71,0:12:53.24,EN,,0,0,0,,and there are a lot of different operations Dialogue: 0,0:12:53.24,0:12:56.65,EN,,0,0,0,,assigned to EXP, the first clause of what's in EXP. Dialogue: 0,0:12:56.84,0:12:58.89,EN,,0,0,0,,This might be part of processing a conditional. Dialogue: 0,0:12:59.26,0:13:01.80,EN,,0,0,0,,And, again, first clause is some selector Dialogue: 0,0:13:03.07,0:13:04.48,EN,,0,0,0,,whose details we don't care about. Dialogue: 0,0:13:04.49,0:13:06.46,EN,,0,0,0,,And you can, again, imagine that as a sub-routine Dialogue: 0,0:13:06.46,0:13:07.90,EN,,0,0,0,,which'll do some list operations, Dialogue: 0,0:13:08.22,0:13:09.18,EN,,0,0,0,,or you can imagine that as Dialogue: 0,0:13:09.18,0:13:10.73,EN,,0,0,0,,something that's built directly into hardware. Dialogue: 0,0:13:12.17,0:13:13.71,EN,,0,0,0,,The reason I keep saying you can imagine it Dialogue: 0,0:13:14.03,0:13:15.22,EN,,0,0,0,,built directly into hardware Dialogue: 0,0:13:15.22,0:13:17.80,EN,,0,0,0,,is even though there are a lot of operations, Dialogue: 0,0:13:18.36,0:13:19.74,EN,,0,0,0,,there are still a fixed number of them. Dialogue: 0,0:13:20.12,0:13:21.80,EN,,0,0,0,,I forget how many, maybe 150. Dialogue: 0,0:13:22.37,0:13:25.39,EN,,0,0,0,,So, it's plausible to think of building these directly into hardware. Dialogue: 0,0:13:26.41,0:13:27.68,EN,,0,0,0,,Here's a more complicated one. Dialogue: 0,0:13:28.27,0:13:29.47,EN,,0,0,0,,You can see this has to do with Dialogue: 0,0:13:29.47,0:13:31.10,EN,,0,0,0,,looking up the values of variables. Dialogue: 0,0:13:31.50,0:13:33.28,EN,,0,0,0,,It says assign to the VAL register Dialogue: 0,0:13:33.45,0:13:36.91,EN,,0,0,0,,the result of looking up the variable value Dialogue: 0,0:13:36.99,0:13:38.52,EN,,0,0,0,,of some particular expression, Dialogue: 0,0:13:39.18,0:13:40.30,EN,,0,0,0,,which, in this case, is supposed to be Dialogue: 0,0:13:40.33,0:13:42.00,EN,,0,0,0,,a variable in some environment. Dialogue: 0,0:13:42.80,0:13:44.68,EN,,0,0,0,,And this'll be some operation Dialogue: 0,0:13:45.21,0:13:47.50,EN,,0,0,0,,that search through the environment structure, Dialogue: 0,0:13:47.52,0:13:48.97,EN,,0,0,0,,however it is represented, Dialogue: 0,0:13:49.37,0:13:50.91,EN,,0,0,0,,and goes and looks up that variable. Dialogue: 0,0:13:52.17,0:13:53.95,EN,,0,0,0,,And, again, that's below the level of detail Dialogue: 0,0:13:53.96,0:13:54.86,EN,,0,0,0,,that we're thinking about. Dialogue: 0,0:13:54.89,0:13:57.30,EN,,0,0,0,,This is... this has to do with the details of Dialogue: 0,0:13:57.55,0:13:59.44,EN,,0,0,0,,the data structures for representing environments. Dialogue: 0,0:14:00.07,0:14:01.21,EN,,0,0,0,,But, anyway, there is this Dialogue: 0,0:14:01.31,0:14:03.47,EN,,0,0,0,,there is this fixed and finite number Dialogue: 0,0:14:04.11,0:14:06.08,EN,,0,0,0,,of operations in the register machine. Dialogue: 0,0:14:08.50,0:14:11.60,EN,,0,0,0,,Well, what's its overall structure? Dialogue: 0,0:14:11.72,0:14:13.23,EN,,0,0,0,,Those are some typical operations. Dialogue: 0,0:14:14.76,0:14:16.33,EN,,0,0,0,,Remember what we have to do, Dialogue: 0,0:14:16.44,0:14:18.40,EN,,0,0,0,,we have to take the meta-circular evaluator-- Dialogue: 0,0:14:20.43,0:14:22.76,EN,,0,0,0,,and here's a piece of the meta-circular evaluator. Dialogue: 0,0:14:22.76,0:14:26.89,EN,,0,0,0,,This is the one using abstract syntax that's in the book. Dialogue: 0,0:14:28.22,0:14:31.53,EN,,0,0,0,,It's a little bit different from the one that Gerry shows you. Dialogue: 0,0:14:33.50,0:14:35.10,EN,,0,0,0,,And the main thing Dialogue: 0,0:14:35.13,0:14:37.87,EN,,0,0,0,,to remember about the evaluator is that Dialogue: 0,0:14:37.87,0:14:40.96,EN,,0,0,0,,it's doing some sort of case analysis on the kinds of expressions: Dialogue: 0,0:14:43.76,0:14:45.90,EN,,0,0,0,,so if it's either self-evaluated, or quoted, Dialogue: 0,0:14:45.92,0:14:46.86,EN,,0,0,0,,or whatever else. Dialogue: 0,0:14:48.56,0:14:50.57,EN,,0,0,0,,And then, in the general case where Dialogue: 0,0:14:50.86,0:14:52.96,EN,,0,0,0,,the expression it's looking at is an application, Dialogue: 0,0:14:53.55,0:14:55.36,EN,,0,0,0,,there's some tricky recursions going on. Dialogue: 0,0:14:55.75,0:14:59.36,EN,,0,0,0,,First of all, eval has to call itself Dialogue: 0,0:14:59.79,0:15:01.45,EN,,0,0,0,,both to evaluate the operator Dialogue: 0,0:15:02.14,0:15:04.04,EN,,0,0,0,,and to evaluate all the operands. Dialogue: 0,0:15:05.88,0:15:07.40,EN,,0,0,0,,So there's this sort of red recursion Dialogue: 0,0:15:07.63,0:15:09.28,EN,,0,0,0,,of values walking down the tree Dialogue: 0,0:15:10.94,0:15:12.27,EN,,0,0,0,,that's sort of the easy recursion. Dialogue: 0,0:15:12.27,0:15:14.44,EN,,0,0,0,,That's just eval walking down this tree of expressions. Dialogue: 0,0:15:14.75,0:15:15.53,EN,,0,0,0,,Then, in the evaluator, Dialogue: 0,0:15:15.53,0:15:16.46,EN,,0,0,0,,there's a hard recursion. Dialogue: 0,0:15:16.49,0:15:17.92,EN,,0,0,0,,There's the red to green. Dialogue: 0,0:15:18.00,0:15:19.66,EN,,0,0,0,,Eval calls apply. Dialogue: 0,0:15:22.47,0:15:26.45,EN,,0,0,0,,That's the case where evaluating a procedure argument Dialogue: 0,0:15:26.45,0:15:28.72,EN,,0,0,0,,reduces to applying the procedure Dialogue: 0,0:15:28.94,0:15:29.93,EN,,0,0,0,,to the list of arguments. Dialogue: 0,0:15:30.37,0:15:31.76,EN,,0,0,0,,And then, apply comes over here. Dialogue: 0,0:15:34.77,0:15:36.67,EN,,0,0,0,,Apply takes a procedure and arguments Dialogue: 0,0:15:37.65,0:15:39.45,EN,,0,0,0,,and, in the general case Dialogue: 0,0:15:39.48,0:15:40.81,EN,,0,0,0,,where there's a compound procedure, Dialogue: 0,0:15:41.05,0:15:42.19,EN,,0,0,0,,apply goes around and Dialogue: 0,0:15:42.25,0:15:43.15,EN,,0,0,0,,green calls red. Dialogue: 0,0:15:43.34,0:15:46.44,EN,,0,0,0,,Eval-- Apply comes around and calls eval again. Dialogue: 0,0:15:48.17,0:15:49.79,EN,,0,0,0,,Eval's the body of the procedure Dialogue: 0,0:15:50.24,0:15:52.59,EN,,0,0,0,,in the result of extending the environment Dialogue: 0,0:15:53.69,0:15:55.28,EN,,0,0,0,,with the parameters of the procedure Dialogue: 0,0:15:55.48,0:15:56.92,EN,,0,0,0,,by binding the arguments. Dialogue: 0,0:15:59.62,0:16:00.62,EN,,0,0,0,,Except in the primitive case, Dialogue: 0,0:16:00.64,0:16:02.52,EN,,0,0,0,,where it just calls something else primitive-apply Dialogue: 0,0:16:02.73,0:16:04.70,EN,,0,0,0,,which is not really the business of the evaluator. Dialogue: 0,0:16:05.98,0:16:07.47,EN,,0,0,0,,So this sort of red to green, Dialogue: 0,0:16:07.47,0:16:08.40,EN,,0,0,0,,to red to green, Dialogue: 0,0:16:09.79,0:16:12.72,EN,,0,0,0,,Right? That's the that's the eval/apply loop, Dialogue: 0,0:16:14.06,0:16:15.74,EN,,0,0,0,,and that's the thing that we're going to want to see Dialogue: 0,0:16:16.19,0:16:17.72,EN,,0,0,0,,in the evaluator. Dialogue: 0,0:16:19.69,0:16:21.07,EN,,0,0,0,,Well, it won't surprise you at all that Dialogue: 0,0:16:21.07,0:16:23.52,EN,,0,0,0,,the two big pieces of this evaluator Dialogue: 0,0:16:25.34,0:16:27.04,EN,,0,0,0,,are correspond to eval and apply. Dialogue: 0,0:16:27.47,0:16:29.44,EN,,0,0,0,,There's a piece called eval-dispatch, Dialogue: 0,0:16:29.60,0:16:31.20,EN,,0,0,0,,and a piece called apply-dispatch. Dialogue: 0,0:16:32.00,0:16:34.09,EN,,0,0,0,,And, before we get into the details of the code, Dialogue: 0,0:16:34.20,0:16:35.76,EN,,0,0,0,,the way to understand this is to think, Dialogue: 0,0:16:36.09,0:16:39.02,EN,,0,0,0,,again, in terms of these pieces of evaluator Dialogue: 0,0:16:39.02,0:16:40.97,EN,,0,0,0,,having contracts with the rest of the world. Dialogue: 0,0:16:41.87,0:16:43.18,EN,,0,0,0,,What do they do from the outside Dialogue: 0,0:16:43.20,0:16:45.50,EN,,0,0,0,,before getting into the grungy details? Dialogue: 0,0:16:45.78,0:16:49.32,EN,,0,0,0,,Well, the contract for eval-dispatch-- Dialogue: 0,0:16:50.01,0:16:51.40,EN,,0,0,0,,remember, it corresponds to eval. Dialogue: 0,0:16:51.55,0:16:54.10,EN,,0,0,0,,It's got to evaluate an expression in an environment. Dialogue: 0,0:16:54.10,0:16:55.88,EN,,0,0,0,,So, in particular, what this one is going to do, Dialogue: 0,0:16:56.52,0:16:58.68,EN,,0,0,0,,eval-dispatch will assume that, when you call it, Dialogue: 0,0:16:59.68,0:17:01.48,EN,,0,0,0,,that the expression you want to evaluate Dialogue: 0,0:17:01.48,0:17:02.52,EN,,0,0,0,,is in the EXP register. Dialogue: 0,0:17:03.64,0:17:07.39,EN,,0,0,0,,The environment in which you want the evaluation Dialogue: 0,0:17:07.45,0:17:09.05,EN,,0,0,0,,to take place is in the ENV register. Dialogue: 0,0:17:09.56,0:17:10.67,EN,,0,0,0,,And continue tells you Dialogue: 0,0:17:10.84,0:17:12.46,EN,,0,0,0,,the place where the machine should go next Dialogue: 0,0:17:12.52,0:17:13.92,EN,,0,0,0,,when the evaluation is done. Dialogue: 0,0:17:17.28,0:17:19.18,EN,,0,0,0,,Eval-dispatch's contract is that Dialogue: 0,0:17:19.28,0:17:21.26,EN,,0,0,0,,it'll actually perform that evaluation, Dialogue: 0,0:17:21.40,0:17:22.46,EN,,0,0,0,,and, at the end of which, Dialogue: 0,0:17:23.28,0:17:25.63,EN,,0,0,0,,it'll end up at the place specified by continue. Dialogue: 0,0:17:26.61,0:17:29.16,EN,,0,0,0,,The result of the evaluation will be in the VAL register. Dialogue: 0,0:17:29.82,0:17:30.96,EN,,0,0,0,,And it just warns you, Dialogue: 0,0:17:30.99,0:17:32.91,EN,,0,0,0,,it makes no promises about Dialogue: 0,0:17:32.96,0:17:34.60,EN,,0,0,0,,what happens to rest the registers. Dialogue: 0,0:17:35.23,0:17:36.81,EN,,0,0,0,,All other registers might be destroyed. Dialogue: 0,0:17:37.49,0:17:40.14,EN,,0,0,0,,So, there's one piece, OK? Dialogue: 0,0:17:41.55,0:17:43.48,EN,,0,0,0,,Together, the pieces, apply-dispatch Dialogue: 0,0:17:43.52,0:17:44.92,EN,,0,0,0,,that corresponds to apply, Dialogue: 0,0:17:46.09,0:17:48.43,EN,,0,0,0,,it's got to apply a procedure to some arguments, Dialogue: 0,0:17:48.73,0:17:51.43,EN,,0,0,0,,so it assumes that this register, ARGL, Dialogue: 0,0:17:51.68,0:17:53.77,EN,,0,0,0,,contains a list of the evaluated arguments. Dialogue: 0,0:17:54.54,0:17:55.96,EN,,0,0,0,,FUN contains the procedure. Dialogue: 0,0:17:57.22,0:17:58.83,EN,,0,0,0,,Those correspond to the arguments to Dialogue: 0,0:17:58.94,0:18:01.36,EN,,0,0,0,,the apply procedure in the meta-circular evaluator. Dialogue: 0,0:18:03.97,0:18:06.04,EN,,0,0,0,,And apply, in this particular evaluator, Dialogue: 0,0:18:06.06,0:18:07.58,EN,,0,0,0,,we're going to use a discipline which says Dialogue: 0,0:18:07.72,0:18:08.97,EN,,0,0,0,,the place that apply Dialogue: 0,0:18:09.47,0:18:11.20,EN,,0,0,0,,the place the machine should go to next Dialogue: 0,0:18:11.79,0:18:13.45,EN,,0,0,0,,when apply is done, is at the moment Dialogue: 0,0:18:13.55,0:18:15.92,EN,,0,0,0,,apply-dispatch is called at the top of the stack Dialogue: 0,0:18:17.07,0:18:21.24,EN,,0,0,0,,that's just discipline for the way this particular machine's organized. Dialogue: 0,0:18:21.84,0:18:23.70,EN,,0,0,0,,And now apply's contract is given all that. Dialogue: 0,0:18:23.93,0:18:25.37,EN,,0,0,0,,It'll perform the application. Dialogue: 0,0:18:25.54,0:18:27.85,EN,,0,0,0,,The result of that application will end up in VAL. Dialogue: 0,0:18:28.89,0:18:29.95,EN,,0,0,0,,The stack will be popped. Dialogue: 0,0:18:31.12,0:18:31.66,EN,,0,0,0,,And, again, Dialogue: 0,0:18:31.71,0:18:34.03,EN,,0,0,0,,the contents of all the other registers may be destroyed. Dialogue: 0,0:18:34.84,0:18:37.82,EN,,0,0,0,,All right? So that's the basic organization of this machine. Dialogue: 0,0:18:38.99,0:18:41.50,EN,,0,0,0,,Let's break for a little bit and see if there are any questions Dialogue: 0,0:18:41.52,0:18:42.70,EN,,0,0,0,,and then we'll do a real example. Dialogue: 0,0:18:43.53,0:19:08.11,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:19:08.14,0:19:13.47,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:19:33.10,0:19:35.87,EN,,0,0,0,,By: Prof. Harold Abelson && Sussman Jay Sussman Dialogue: 0,0:19:35.87,0:19:40.38,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:19:47.85,0:19:49.95,EN,,0,0,0,,Well, let's take the register machine now, Dialogue: 0,0:19:50.41,0:19:51.77,EN,,0,0,0,,and actually step through, Dialogue: 0,0:19:52.27,0:19:56.94,EN,,0,0,0,,and really, in real detail, Dialogue: 0,0:19:57.07,0:19:58.52,EN,,0,0,0,,so you see completely concrete Dialogue: 0,0:19:58.86,0:20:01.24,EN,,0,0,0,,how some expressions are evaluated, Dialogue: 0,0:20:03.15,0:20:06.86,EN,,0,0,0,,Alright? So, let's start with a very simple expression. Dialogue: 0,0:20:07.45,0:20:13.52,EN,,0,0,0,,Let's evaluate the expression 1. Dialogue: 0,0:20:18.77,0:20:20.40,EN,,0,0,0,,And we need an environment, Dialogue: 0,0:20:20.43,0:20:22.35,EN,,0,0,0,,so let's imagine that somewhere there's an environment Dialogue: 0,0:20:22.38,0:20:23.39,EN,,0,0,0,,we'll call it E0. Dialogue: 0,0:20:30.06,0:20:34.56,EN,,0,0,0,,And just, since we'll use these later, Dialogue: 0,0:20:35.62,0:20:37.04,EN,,0,0,0,,we obviously don't really need anything Dialogue: 0,0:20:37.07,0:20:37.93,EN,,0,0,0,,to evaluate 1. Dialogue: 0,0:20:38.36,0:20:39.45,EN,,0,0,0,,But, just for reference later, Dialogue: 0,0:20:39.45,0:20:40.94,EN,,0,0,0,,let's assume that E0 has in it Dialogue: 0,0:20:41.44,0:20:43.15,EN,,0,0,0,,an X that's bound to 3 Dialogue: 0,0:20:43.72,0:20:45.37,EN,,0,0,0,,and a Y that's bound to 4, Dialogue: 0,0:20:48.27,0:20:48.78,EN,,0,0,0,,OK? Dialogue: 0,0:20:49.14,0:20:50.12,EN,,0,0,0,,And now what we're going to do Dialogue: 0,0:20:50.51,0:20:54.59,EN,,0,0,0,,is we're going to evaluate 1 in this environment Dialogue: 0,0:20:55.74,0:20:58.54,EN,,0,0,0,,and so the ENV register has a pointer Dialogue: 0,0:20:59.65,0:21:01.04,EN,,0,0,0,,to this environment, E0, all right? Dialogue: 0,0:21:03.31,0:21:05.65,EN,,0,0,0,,Right? So let's watch that thing go. Dialogue: 0,0:21:05.65,0:21:07.26,EN,,0,0,0,,What I'm going to do is step through the code. Dialogue: 0,0:21:08.26,0:21:10.00,EN,,0,0,0,,And, let's see, I'll be the controller. Dialogue: 0,0:21:10.04,0:21:10.80,EN,,0,0,0,,And now what I need, Dialogue: 0,0:21:11.02,0:21:12.49,EN,,0,0,0,,since this gets rather complicated, Dialogue: 0,0:21:12.98,0:21:16.83,EN,,0,0,0,,is a very little execution unit. Dialogue: 0,0:21:16.83,0:21:18.16,EN,,0,0,0,,So here's the execution unit, OK? Dialogue: 0,0:21:22.62,0:21:23.12,EN,,0,0,0,,OK. Dialogue: 0,0:21:28.59,0:21:29.96,EN,,0,0,0,,All right, now we're going to start. Dialogue: 0,0:21:30.53,0:21:32.48,EN,,0,0,0,,We're going to start the machine at eval-dispatch。 Dialogue: 0,0:21:33.26,0:21:34.62,EN,,0,0,0,,Right? That's the beginning of this. Dialogue: 0,0:21:35.87,0:21:38.75,EN,,0,0,0,,Eval-dispatch is going to look at the expression and dispatch, Dialogue: 0,0:21:39.32,0:21:40.06,EN,,0,0,0,,just like eval Dialogue: 0,0:21:40.87,0:21:42.00,EN,,0,0,0,,where we look at the very first thing. Dialogue: 0,0:21:42.04,0:21:47.95,EN,,0,0,0,,We branch on whether or not this expression is self-evaluating. Dialogue: 0,0:21:47.95,0:21:49.96,EN,,0,0,0,,Self-evaluating is some abstraction Dialogue: 0,0:21:49.96,0:21:51.10,EN,,0,0,0,,we put into the machine-- Dialogue: 0,0:21:52.22,0:21:53.51,EN,,0,0,0,,it's going to be true for numbers-- Dialogue: 0,0:21:53.64,0:21:55.52,EN,,0,0,0,,to a place called ev-self-eval, Dialogue: 0,0:21:56.77,0:21:58.20,EN,,0,0,0,,So me, being the controller, Dialogue: 0,0:21:58.22,0:21:59.55,EN,,0,0,0,,looks at ev-self-eval, Dialogue: 0,0:22:00.06,0:22:01.07,EN,,0,0,0,,so we'll go over to there. Dialogue: 0,0:22:02.60,0:22:04.76,EN,,0,0,0,,Ev-self-eval says fine, Dialogue: 0,0:22:06.54,0:22:09.90,EN,,0,0,0,,assign to val whatever is in the expression unit. Dialogue: 0,0:22:15.24,0:22:16.51,EN,,0,0,0,,And I have a bug Dialogue: 0,0:22:17.93,0:22:20.59,EN,,0,0,0,,because what I didn't do when I initialized this machine Dialogue: 0,0:22:21.62,0:22:22.89,EN,,0,0,0,,is also say what's supposed Dialogue: 0,0:22:22.91,0:22:24.19,EN,,0,0,0,,to happen when it's done, Dialogue: 0,0:22:24.65,0:22:26.83,EN,,0,0,0,,so I should have started out the machine Dialogue: 0,0:22:27.37,0:22:29.85,EN,,0,0,0,,with done being in the continue register, Dialogue: 0,0:22:31.18,0:22:33.26,EN,,0,0,0,,OK? So we assign to VAL. Dialogue: 0,0:22:33.37,0:22:35.56,EN,,0,0,0,,And now go to fetch of continue, Dialogue: 0,0:22:35.63,0:22:36.56,EN,,0,0,0,,and now change-- Dialogue: 0,0:22:38.09,0:22:38.60,EN,,0,0,0,,OK. Dialogue: 0,0:22:40.00,0:22:41.16,EN,,0,0,0,,OK, let's try something harder. Dialogue: 0,0:22:42.16,0:22:43.45,EN,,0,0,0,,Let's reset the machine here, Dialogue: 0,0:22:44.86,0:22:50.88,EN,,0,0,0,,and we'll put in the expression register, X, OK? Dialogue: 0,0:22:56.71,0:22:58.20,EN,,0,0,0,,Start again at eval-dispatch. Dialogue: 0,0:22:59.61,0:23:01.69,EN,,0,0,0,,Check, is it self-evaluating? Dialogue: 0,0:23:01.69,0:23:02.03,EN,,0,0,0,,No. Dialogue: 0,0:23:02.65,0:23:03.61,EN,,0,0,0,,Is it a variable? Dialogue: 0,0:23:04.63,0:23:05.02,EN,,0,0,0,,Yes. Dialogue: 0,0:23:05.56,0:23:07.07,EN,,0,0,0,,We go off to ev-variable. Dialogue: 0,0:23:08.38,0:23:10.97,EN,,0,0,0,,It says assign to VAL, Dialogue: 0,0:23:12.13,0:23:15.69,EN,,0,0,0,,look up the variable value in the expression register Dialogue: 0,0:23:21.23,0:23:22.91,EN,,0,0,0,,Go to fetch of continue. Dialogue: 0,0:23:23.96,0:23:24.48,EN,,0,0,0,,PROFESSOR: Done. Dialogue: 0,0:23:27.61,0:23:28.09,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:23:29.31,0:23:30.76,EN,,0,0,0,,Alright, Well, that's the basic idea. Those're Dialogue: 0,0:23:31.33,0:23:32.65,EN,,0,0,0,,That's a simple operation of the machine. Dialogue: 0,0:23:32.68,0:23:35.07,EN,,0,0,0,,Now, let's actually do something a little bit more interesting. Dialogue: 0,0:23:36.07,0:23:38.64,EN,,0,0,0,,Let's look at the expression Dialogue: 0,0:23:43.58,0:23:47.93,EN,,0,0,0,,the sum of x and y. Dialogue: 0,0:23:49.69,0:23:51.28,EN,,0,0,0,,OK. And now we'll see how you start Dialogue: 0,0:23:52.41,0:23:54.01,EN,,0,0,0,,unrolling these expression trees. Dialogue: 0,0:23:57.13,0:23:58.68,EN,,0,0,0,,Well, start again at eval-dispatch. Dialogue: 0,0:24:04.61,0:24:05.80,EN,,0,0,0,,Self-evaluating? Dialogue: 0,0:24:05.95,0:24:06.52,EN,,0,0,0,,No. Dialogue: 0,0:24:06.70,0:24:07.71,EN,,0,0,0,,Variable? No. Dialogue: 0,0:24:07.82,0:24:08.99,EN,,0,0,0,,All the other special forms Dialogue: 0,0:24:08.99,0:24:10.12,EN,,0,0,0,,which I didn't write down, Dialogue: 0,0:24:10.27,0:24:12.48,EN,,0,0,0,,like quote, and lambda, and set, and whatever, Dialogue: 0,0:24:12.48,0:24:13.08,EN,,0,0,0,,it's none of those. Dialogue: 0,0:24:13.26,0:24:14.73,EN,,0,0,0,,It turns out to be an application, Dialogue: 0,0:24:15.88,0:24:17.42,EN,,0,0,0,,so we go off to ev-application. Dialogue: 0,0:24:19.97,0:24:24.94,EN,,0,0,0,,Ev-application, remember what it's going to do overall. Dialogue: 0,0:24:25.58,0:24:28.19,EN,,0,0,0,,It is going to evaluate the operator. Dialogue: 0,0:24:28.27,0:24:31.40,EN,,0,0,0,,It's going to evaluate the arguments, Dialogue: 0,0:24:32.36,0:24:34.30,EN,,0,0,0,,and then it's going to go apply them. Dialogue: 0,0:24:35.06,0:24:36.09,EN,,0,0,0,,So, before we start, Dialogue: 0,0:24:36.94,0:24:37.88,EN,,0,0,0,,since we're being very literal, Dialogue: 0,0:24:37.88,0:24:38.88,EN,,0,0,0,,we'd better remember that, Dialogue: 0,0:24:39.07,0:24:40.54,EN,,0,0,0,,somewhere in this environment, Dialogue: 0,0:24:40.57,0:24:42.36,EN,,0,0,0,,it's linked to another environment Dialogue: 0,0:24:43.98,0:24:44.94,EN,,0,0,0,,in which plus Dialogue: 0,0:24:45.72,0:24:49.16,EN,,0,0,0,,is bound to the primitive procedure plus Dialogue: 0,0:24:51.63,0:24:54.03,EN,,0,0,0,,before we get an unknown variable in our machine. Dialogue: 0,0:24:55.34,0:24:56.84,EN,,0,0,0,,OK, so we're at ev-application. Dialogue: 0,0:24:59.85,0:25:04.32,EN,,0,0,0,,OK, assign to UNEV the operands Dialogue: 0,0:25:04.92,0:25:06.89,EN,,0,0,0,,of what's in the expression register. Dialogue: 0,0:25:07.61,0:25:08.83,EN,,0,0,0,,OK. Those are the operands. Dialogue: 0,0:25:09.23,0:25:11.66,EN,,0,0,0,,UNEV's a temporary register Dialogue: 0,0:25:11.68,0:25:12.59,EN,,0,0,0,,where we're going to save them. Dialogue: 0,0:25:13.22,0:25:13.86,EN,,0,0,0,,PROFESSOR: I'm assigning. Dialogue: 0,0:25:14.28,0:25:16.62,EN,,0,0,0,,PROFESSOR: Assign to EXP the operator. Dialogue: 0,0:25:18.07,0:25:20.09,EN,,0,0,0,,Now, notice we've destroyed that expression in EXP, Dialogue: 0,0:25:21.84,0:25:23.61,EN,,0,0,0,,but the piece that we need is now in UNEV. Dialogue: 0,0:25:25.82,0:25:26.81,EN,,0,0,0,,Now, we're going to get set up to Dialogue: 0,0:25:26.81,0:25:28.59,EN,,0,0,0,,to recursively evaluate the operator. Dialogue: 0,0:25:28.75,0:25:31.69,EN,,0,0,0,,Save the continue register on the stack. Dialogue: 0,0:25:34.86,0:25:36.09,EN,,0,0,0,,Save the environment. Dialogue: 0,0:25:40.48,0:25:41.69,EN,,0,0,0,,Save UNEV. Dialogue: 0,0:25:49.53,0:25:54.64,EN,,0,0,0,,OK, assign to continue a label called eval-args. Dialogue: 0,0:26:01.40,0:26:01.95,EN,,0,0,0,,Now, what have we done? Dialogue: 0,0:26:01.95,0:26:04.38,EN,,0,0,0,,We've set up for a recursive call. Dialogue: 0,0:26:04.38,0:26:05.88,EN,,0,0,0,,We're about to go to eval-dispatch. Dialogue: 0,0:26:06.28,0:26:08.83,EN,,0,0,0,,We've set up for a recursive call to eval-dispatch. Dialogue: 0,0:26:10.23,0:26:10.86,EN,,0,0,0,,What did we do? Dialogue: 0,0:26:11.02,0:26:13.64,EN,,0,0,0,,We took the things we're going to need later, Dialogue: 0,0:26:14.48,0:26:15.98,EN,,0,0,0,,those operands that were in UNEV; Dialogue: 0,0:26:16.36,0:26:18.99,EN,,0,0,0,,the environment in which we're going to eventually have to, Dialogue: 0,0:26:19.16,0:26:20.72,EN,,0,0,0,,maybe, evaluate those operands; Dialogue: 0,0:26:22.28,0:26:23.93,EN,,0,0,0,,the place we eventually want to go to, Dialogue: 0,0:26:23.95,0:26:25.07,EN,,0,0,0,,which, in this case, was done; Dialogue: 0,0:26:25.34,0:26:26.70,EN,,0,0,0,,we've saved them on the stack. Dialogue: 0,0:26:27.10,0:26:28.41,EN,,0,0,0,,The reason we saved them on the stack Dialogue: 0,0:26:28.43,0:26:30.67,EN,,0,0,0,,is because eval-dispatch makes no promises Dialogue: 0,0:26:30.94,0:26:32.54,EN,,0,0,0,,about what registers it may destroy. Dialogue: 0,0:26:33.55,0:26:35.02,EN,,0,0,0,,So all that stuff is saved on the stack. Dialogue: 0,0:26:35.02,0:26:36.91,EN,,0,0,0,,Now, we've set up eval-dispatch's contract. Dialogue: 0,0:26:37.38,0:26:38.75,EN,,0,0,0,,There's a new expression, Dialogue: 0,0:26:38.78,0:26:40.04,EN,,0,0,0,,which is the operator plus; Dialogue: 0,0:26:41.07,0:26:41.95,EN,,0,0,0,,a new environment, Dialogue: 0,0:26:41.98,0:26:43.60,EN,,0,0,0,,although, in this case, it's the same one; Dialogue: 0,0:26:44.25,0:26:45.87,EN,,0,0,0,,and a new place to go to when you're done, Dialogue: 0,0:26:45.87,0:26:46.91,EN,,0,0,0,,which is eval-args. Dialogue: 0,0:26:47.60,0:26:48.13,EN,,0,0,0,,So that's set up. Dialogue: 0,0:26:48.13,0:26:49.68,EN,,0,0,0,,Now, we're going to go off to eval-dispatch. Dialogue: 0,0:26:50.89,0:26:52.36,EN,,0,0,0,,Here we are back at eval-dispatch. Dialogue: 0,0:26:53.05,0:26:54.40,EN,,0,0,0,,It's not self-evaluating. Dialogue: 0,0:26:54.44,0:26:55.47,EN,,0,0,0,,Oh, it's a variable, Dialogue: 0,0:26:56.32,0:26:58.06,EN,,0,0,0,,so we'd better go off to ev-variable, Dialogue: 0,0:26:59.79,0:27:02.65,EN,,0,0,0,,Right? Ev-variable is assigned to VAL. Dialogue: 0,0:27:02.70,0:27:06.33,EN,,0,0,0,,Look up the variable value of the expression, Dialogue: 0,0:27:08.49,0:27:10.75,EN,,0,0,0,,OK? So VAL is the primitive procedure plus. Dialogue: 0,0:27:13.37,0:27:15.16,EN,,0,0,0,,And go to fetch of continue. Dialogue: 0,0:27:15.23,0:27:16.11,EN,,0,0,0,,PROFESSOR: Eval-args. Dialogue: 0,0:27:16.20,0:27:18.73,EN,,0,0,0,,PROFESSOR: Right, which is now eval-args not done. Dialogue: 0,0:27:19.42,0:27:21.26,EN,,0,0,0,,So we come back here at eval-args, Dialogue: 0,0:27:22.16,0:27:23.02,EN,,0,0,0,,and what do we do? Dialogue: 0,0:27:23.07,0:27:24.84,EN,,0,0,0,,We're going to restore the stuff that we saved, Dialogue: 0,0:27:25.20,0:27:26.57,EN,,0,0,0,,so we restore UNEV. Dialogue: 0,0:27:29.21,0:27:31.69,EN,,0,0,0,,And notice, there, it wasn't necessary, Dialogue: 0,0:27:31.74,0:27:32.90,EN,,0,0,0,,although, in general, it would be. Dialogue: 0,0:27:32.90,0:27:35.16,EN,,0,0,0,,It might be some arbitrary evaluation that happened. Dialogue: 0,0:27:35.43,0:27:36.70,EN,,0,0,0,,We restore ENV. Dialogue: 0,0:27:47.87,0:27:52.04,EN,,0,0,0,,OK, we assign to FUN fetch of VAL. Dialogue: 0,0:27:59.95,0:28:02.81,EN,,0,0,0,,OK, now, we're going to go off and start evaluating some arguments. Dialogue: 0,0:28:04.34,0:28:06.48,EN,,0,0,0,,Well, first thing we'd better do is save FUN Dialogue: 0,0:28:07.42,0:28:10.62,EN,,0,0,0,,because some arbitrary stuff might happen in that evaluation. Dialogue: 0,0:28:15.33,0:28:16.88,EN,,0,0,0,,We initialize the argument list. Dialogue: 0,0:28:16.91,0:28:19.29,EN,,0,0,0,,Assign to argl an empty argument list, Dialogue: 0,0:28:20.88,0:28:22.17,EN,,0,0,0,,and go to eval-arg-loop, Dialogue: 0,0:28:24.86,0:28:26.27,EN,,0,0,0,,At eval-arg-loop, Dialogue: 0,0:28:27.77,0:28:31.53,EN,,0,0,0,,the idea of this is we're going to evaluate the pieces of the Dialogue: 0,0:28:31.61,0:28:33.37,EN,,0,0,0,,expressions that are in UNEV, one by one, Dialogue: 0,0:28:33.54,0:28:35.68,EN,,0,0,0,,and move them from unevaluated in UNEV Dialogue: 0,0:28:35.90,0:28:37.26,EN,,0,0,0,,to evaluated in the arg list. Dialogue: 0,0:28:37.84,0:28:39.18,EN,,0,0,0,,OK. So we save argl. Dialogue: 0,0:28:43.95,0:28:47.26,EN,,0,0,0,,We assign to EXP the first operand Dialogue: 0,0:28:47.37,0:28:48.38,EN,,0,0,0,,of the stuff in UNEV. Dialogue: 0,0:28:53.77,0:28:55.89,EN,,0,0,0,,Now, we check and see if that was the last operand. Dialogue: 0,0:28:55.89,0:28:56.91,EN,,0,0,0,,In this case, it is not. Dialogue: 0,0:28:58.99,0:29:01.55,EN,,0,0,0,,So we save the environment. Dialogue: 0,0:29:08.00,0:29:10.06,EN,,0,0,0,,We save UNEV Dialogue: 0,0:29:11.61,0:29:13.50,EN,,0,0,0,,because those are all things we might need later. Dialogue: 0,0:29:13.50,0:29:14.40,EN,,0,0,0,,We're going to need the environment Dialogue: 0,0:29:14.44,0:29:15.64,EN,,0,0,0,,to do some more evaluations. Dialogue: 0,0:29:15.80,0:29:16.60,EN,,0,0,0,,We're going to need UNEV Dialogue: 0,0:29:16.62,0:29:19.20,EN,,0,0,0,,to look at what the rest of those arguments were. Dialogue: 0,0:29:20.34,0:29:21.55,EN,,0,0,0,,We're going to assign continue Dialogue: 0,0:29:21.56,0:29:24.44,EN,,0,0,0,,a place called accumulate-args, or accumulate-arg. Dialogue: 0,0:29:31.13,0:29:34.01,EN,,0,0,0,,OK, now, we've set up for another call to eval-dispatch, Dialogue: 0,0:29:37.07,0:29:38.54,EN,,0,0,0,,All right, now, let me short-circuit this Dialogue: 0,0:29:39.12,0:29:41.09,EN,,0,0,0,,so we don't go through the details of eval-dispatch. Dialogue: 0,0:29:41.09,0:29:42.64,EN,,0,0,0,,Eval-dispatch's contract says Dialogue: 0,0:29:42.97,0:29:45.00,EN,,0,0,0,,i'm going to end up, Dialogue: 0,0:29:45.13,0:29:45.96,EN,,0,0,0,,the world will end up, Dialogue: 0,0:29:46.03,0:29:48.20,EN,,0,0,0,,with the value of evaluating this expression Dialogue: 0,0:29:48.24,0:29:50.27,EN,,0,0,0,,in this environment in the VAL register, Dialogue: 0,0:29:50.27,0:29:51.07,EN,,0,0,0,,and I'll end up there. Dialogue: 0,0:29:51.32,0:29:52.62,EN,,0,0,0,,So we short-circuit all of this, Dialogue: 0,0:29:54.43,0:29:56.36,EN,,0,0,0,,and a 3 ends up in VAL. Dialogue: 0,0:29:58.01,0:29:59.76,EN,,0,0,0,,And, when we return from eval-dispatch, Dialogue: 0,0:29:59.76,0:30:01.76,EN,,0,0,0,,we're going to return to accumulate-arg. Dialogue: 0,0:30:02.30,0:30:03.23,EN,,0,0,0,,PROFESSOR: Accumulate-arg. Dialogue: 0,0:30:06.22,0:30:08.20,EN,,0,0,0,,PROFESSOR: With 3 in the VAL register, OK? Dialogue: 0,0:30:08.72,0:30:10.59,EN,,0,0,0,,So that short-circuited that evaluation. Dialogue: 0,0:30:10.65,0:30:11.32,EN,,0,0,0,,Now, what do we do? Dialogue: 0,0:30:11.32,0:30:13.68,EN,,0,0,0,,We're going to go back and look at the rest of the arguments, Dialogue: 0,0:30:13.68,0:30:14.83,EN,,0,0,0,,so we restore UNEV. Dialogue: 0,0:30:17.51,0:30:19.00,EN,,0,0,0,,We restore ENV. Dialogue: 0,0:30:25.79,0:30:27.05,EN,,0,0,0,,We restore argl. Dialogue: 0,0:30:28.65,0:30:29.17,EN,,0,0,0,,One thing. Dialogue: 0,0:30:30.06,0:30:31.45,EN,,0,0,0,,PROFESSOR: Oops! Parity error. Dialogue: 0,0:30:33.76,0:30:34.83,EN,,0,0,0,,PROFESSOR: Restore argl. Dialogue: 0,0:30:45.57,0:30:49.76,EN,,0,0,0,,OK, we assign to argl consing on Dialogue: 0,0:30:50.65,0:30:52.64,EN,,0,0,0,,fetch of the value register to what's in argl. Dialogue: 0,0:30:59.36,0:31:02.96,EN,,0,0,0,,OK, we assign to UNEV the rest of the operands Dialogue: 0,0:31:03.34,0:31:04.52,EN,,0,0,0,,in fetch of UNEV, Dialogue: 0,0:31:08.91,0:31:10.76,EN,,0,0,0,,and we go back to eval-arg-loop. Dialogue: 0,0:31:11.51,0:31:12.28,EN,,0,0,0,,PROFESSOR: Eval-arg-loop. Dialogue: 0,0:31:12.28,0:31:12.86,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:31:15.88,0:31:17.08,EN,,0,0,0,,Now, we're about to do the next argument, Dialogue: 0,0:31:17.58,0:31:19.31,EN,,0,0,0,,so the first thing we do is save argl. Dialogue: 0,0:31:25.40,0:31:28.27,EN,,0,0,0,,OK, we assign to EXP the first operand Dialogue: 0,0:31:29.15,0:31:30.81,EN,,0,0,0,,of fetch of UNEV. Dialogue: 0,0:31:34.72,0:31:37.02,EN,,0,0,0,,OK, we test and see if that's the last operand. Dialogue: 0,0:31:37.02,0:31:38.00,EN,,0,0,0,,In this case, it is Dialogue: 0,0:31:39.08,0:31:40.27,EN,,0,0,0,,so we're going to go to a special place Dialogue: 0,0:31:40.28,0:31:42.06,EN,,0,0,0,,that says evaluate the last argument Dialogue: 0,0:31:43.37,0:31:45.07,EN,,0,0,0,,because, notice,after evaluating the argument, Dialogue: 0,0:31:45.10,0:31:46.62,EN,,0,0,0,,we don't need the environment any more. Dialogue: 0,0:31:47.64,0:31:48.78,EN,,0,0,0,,That's going to be the difference. Dialogue: 0,0:31:50.25,0:31:51.85,EN,,0,0,0,,So here, at eval-last-arg, Dialogue: 0,0:31:52.24,0:31:54.92,EN,,0,0,0,,which is assigned to continue accumulate-last-arg, Dialogue: 0,0:32:04.27,0:32:06.90,EN,,0,0,0,,now, we're set up again for eval-dispatch. Dialogue: 0,0:32:06.90,0:32:08.51,EN,,0,0,0,,We've got a place to go to when we're done. Dialogue: 0,0:32:08.62,0:32:09.84,EN,,0,0,0,,We've got an expression. Dialogue: 0,0:32:09.84,0:32:10.80,EN,,0,0,0,,We've got an environment. Dialogue: 0,0:32:11.33,0:32:13.64,EN,,0,0,0,,OK, so we'll short-circuit the call to eval-dispatch. Dialogue: 0,0:32:14.37,0:32:16.41,EN,,0,0,0,,And what'll happen is there's a y there, Dialogue: 0,0:32:16.70,0:32:18.56,EN,,0,0,0,,it's 4 in that environment, Dialogue: 0,0:32:18.60,0:32:20.09,EN,,0,0,0,,so VAL will end up with 4 in it. Dialogue: 0,0:32:21.06,0:32:22.86,EN,,0,0,0,,And, then, we're going to end up at accumulate-last-arg, OK? Dialogue: 0,0:32:25.45,0:32:26.91,EN,,0,0,0,,So, at accumulate-last-arg, Dialogue: 0,0:32:29.28,0:32:30.52,EN,,0,0,0,,we restore argl. Dialogue: 0,0:32:37.69,0:32:42.76,EN,,0,0,0,,We assign to argl, we assign to argl cons, Dialogue: 0,0:32:43.60,0:32:45.83,EN,,0,0,0,,of fetch of the new value onto it, Dialogue: 0,0:32:45.93,0:32:47.39,EN,,0,0,0,,so we cons a 4 onto that. Dialogue: 0,0:32:49.85,0:32:52.52,EN,,0,0,0,,We restore what was saved in the function register. Dialogue: 0,0:32:53.77,0:32:54.99,EN,,0,0,0,,And notice, in this case, Dialogue: 0,0:32:55.00,0:32:56.27,EN,,0,0,0,,it had not been destroyed, Dialogue: 0,0:32:56.38,0:32:57.72,EN,,0,0,0,,but in general, it will be. Dialogue: 0,0:32:59.13,0:33:01.50,EN,,0,0,0,,And now, we're ready to go off to apply-dispatch, Dialogue: 0,0:33:02.65,0:33:04.40,EN,,0,0,0,,Alright? So we've just gone through the eval. Dialogue: 0,0:33:04.51,0:33:05.85,EN,,0,0,0,,We evaluated the argument, Dialogue: 0,0:33:06.46,0:33:07.98,EN,,0,0,0,,the operator, and the arguments, Dialogue: 0,0:33:07.98,0:33:09.24,EN,,0,0,0,,and now, we're about to apply them. Dialogue: 0,0:33:09.58,0:33:11.37,EN,,0,0,0,,So we come off to apply-dispatch here Dialogue: 0,0:33:18.03,0:33:19.29,EN,,0,0,0,,We come off to apply-dispatch, Dialogue: 0,0:33:21.05,0:33:22.41,EN,,0,0,0,,and we're going to check whether it's a primitive Dialogue: 0,0:33:22.41,0:33:23.45,EN,,0,0,0,,or a compound procedure. Dialogue: 0,0:33:23.64,0:33:24.20,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,0:33:24.54,0:33:24.83,EN,,0,0,0,,PROFESSOR: All right. Dialogue: 0,0:33:24.89,0:33:26.52,EN,,0,0,0,,So, in this case, it's a primitive procedure, Dialogue: 0,0:33:27.45,0:33:28.91,EN,,0,0,0,,and we go off to primitive-apply. Dialogue: 0,0:33:29.79,0:33:31.36,EN,,0,0,0,,So we go off to primitive-apply, Dialogue: 0,0:33:33.71,0:33:35.37,EN,,0,0,0,,that says assign to VAL Dialogue: 0,0:33:35.69,0:33:38.25,EN,,0,0,0,,result of applying primitive procedure Dialogue: 0,0:33:38.36,0:33:40.30,EN,,0,0,0,,of the function to the argument list. Dialogue: 0,0:33:41.31,0:33:42.43,EN,,0,0,0,,PROFESSOR: I don't know how to add. Dialogue: 0,0:33:42.54,0:33:43.80,EN,,0,0,0,,I'm just an execution unit. Dialogue: 0,0:33:44.14,0:33:45.35,EN,,0,0,0,,PROFESSOR: Well, I don't know how to add either. Dialogue: 0,0:33:45.35,0:33:46.51,EN,,0,0,0,,I'm just the evaluator, Dialogue: 0,0:33:47.08,0:33:48.36,EN,,0,0,0,,so we need a primitive operator. Dialogue: 0,0:33:48.36,0:33:49.72,EN,,0,0,0,,Let's see, so the primitive operator, Dialogue: 0,0:33:49.76,0:33:52.36,EN,,0,0,0,,What's the... what's the sum of 3 and 4? Dialogue: 0,0:33:52.86,0:33:53.32,EN,,0,0,0,,AUDIENCE: 7. Dialogue: 0,0:33:53.71,0:33:54.65,EN,,0,0,0,,PROFESSOR: OK, 7. Dialogue: 0,0:33:55.32,0:33:55.99,EN,,0,0,0,,PROFESSOR: Thank you. Dialogue: 0,0:33:59.20,0:34:00.60,EN,,0,0,0,,PROFESSOR: Now, we restore continue, Dialogue: 0,0:34:11.58,0:34:12.90,EN,,0,0,0,,and we go to fetch of continue. Dialogue: 0,0:34:13.07,0:34:13.47,EN,,0,0,0,,PROFESSOR: Done. Dialogue: 0,0:34:14.20,0:34:14.67,EN,,0,0,0,,PROFESSOR: OK. Dialogue: 0,0:34:14.92,0:34:18.41,EN,,0,0,0,,Well, that was in as much detail as you will ever see. Dialogue: 0,0:34:18.41,0:34:20.19,EN,,0,0,0,,We'll never do it in as much detail again. Dialogue: 0,0:34:21.59,0:34:23.92,EN,,0,0,0,,One very important thing to notice Dialogue: 0,0:34:24.91,0:34:27.55,EN,,0,0,0,,is that we just executed a recursive procedure, Dialogue: 0,0:34:29.56,0:34:31.17,EN,,0,0,0,,Right? This whole thing, we used a stack Dialogue: 0,0:34:31.17,0:34:32.75,EN,,0,0,0,,and the evaluator was recursive. Dialogue: 0,0:34:33.07,0:34:35.88,EN,,0,0,0,,A lot of people think the reason that you need a stack Dialogue: 0,0:34:36.48,0:34:37.85,EN,,0,0,0,,and recursion in an evaluator Dialogue: 0,0:34:37.87,0:34:38.97,EN,,0,0,0,,is because you might be Dialogue: 0,0:34:39.09,0:34:42.15,EN,,0,0,0,,evaluating recursive procedures like factorial or Fibonacci. Dialogue: 0,0:34:42.15,0:34:42.92,EN,,0,0,0,,It's not true. Dialogue: 0,0:34:43.67,0:34:44.99,EN,,0,0,0,,So you notice we did recursion here, Dialogue: 0,0:34:45.00,0:34:46.86,EN,,0,0,0,,and all we evaluated was (+ x y) Dialogue: 0,0:34:47.77,0:34:50.65,EN,,0,0,0,,Right? The reason that you need recursion in the evaluator Dialogue: 0,0:34:50.96,0:34:52.97,EN,,0,0,0,,is because the evaluation process, Dialogue: 0,0:34:52.99,0:34:54.06,EN,,0,0,0,,itself, is recursive. Dialogue: 0,0:34:54.45,0:34:56.17,EN,,0,0,0,,Right? It's not because the procedure Dialogue: 0,0:34:56.32,0:34:58.09,EN,,0,0,0,,that you might be evaluating in LISP Dialogue: 0,0:34:58.12,0:34:59.27,EN,,0,0,0,,is a recursive procedure. Dialogue: 0,0:34:59.27,0:35:00.52,EN,,0,0,0,,So that's an important thing Dialogue: 0,0:35:00.52,0:35:02.14,EN,,0,0,0,,that people get confused about a lot. Dialogue: 0,0:35:03.01,0:35:04.27,EN,,0,0,0,,The other thing to notice is that, Dialogue: 0,0:35:04.27,0:35:05.64,EN,,0,0,0,,when we're done here, Dialogue: 0,0:35:06.28,0:35:07.12,EN,,0,0,0,,we're really done. Dialogue: 0,0:35:07.12,0:35:08.49,EN,,0,0,0,,Not only are we at done, Dialogue: 0,0:35:09.45,0:35:13.23,EN,,0,0,0,,but there's no accumulated stuff on the stack, Dialogue: 0,0:35:13.60,0:35:15.71,EN,,0,0,0,,Right? The machine is back to its initial state. Dialogue: 0,0:35:17.00,0:35:18.75,EN,,0,0,0,,So that's part of what it means to be done. Dialogue: 0,0:35:19.71,0:35:21.04,EN,,0,0,0,,Another way to say that is Dialogue: 0,0:35:22.72,0:35:26.04,EN,,0,0,0,,the evaluation process has reduced Dialogue: 0,0:35:26.41,0:35:28.32,EN,,0,0,0,,the expression, plus X, Y, Dialogue: 0,0:35:30.54,0:35:32.78,EN,,0,0,0,,to the value here, 7. Dialogue: 0,0:35:33.24,0:35:35.45,EN,,0,0,0,,And by reduced, I mean a very particular thing. Dialogue: 0,0:35:36.01,0:35:38.18,EN,,0,0,0,,It means that there's nothing left on the stack. Dialogue: 0,0:35:38.18,0:35:40.36,EN,,0,0,0,,The machine is now in the same state, Dialogue: 0,0:35:40.92,0:35:42.65,EN,,0,0,0,,except there's something in the value register. Dialogue: 0,0:35:42.72,0:35:44.52,EN,,0,0,0,,It's not part of a sub-problem of anything. Dialogue: 0,0:35:44.52,0:35:45.63,EN,,0,0,0,,There's nothing to go back to. Dialogue: 0,0:35:46.12,0:35:46.96,EN,,0,0,0,,OK. Let's break. Dialogue: 0,0:35:50.16,0:35:50.76,EN,,0,0,0,,Question? Dialogue: 0,0:35:51.08,0:35:54.02,EN,,0,0,0,,AUDIENCE: The question here, in the stack, Dialogue: 0,0:35:54.02,0:35:55.82,EN,,0,0,0,,is because the data may be recursive. Dialogue: 0,0:35:56.20,0:35:58.75,EN,,0,0,0,,You may have embedded expressions, for instance. Dialogue: 0,0:35:59.31,0:36:02.08,EN,,0,0,0,,PROFESSOR: Yes, because you might have embedded expressions. Dialogue: 0,0:36:02.08,0:36:04.77,EN,,0,0,0,,But, again, don't confuse that Dialogue: 0,0:36:04.77,0:36:07.98,EN,,0,0,0,,with what people sometimes mean by the data may be recursive, Dialogue: 0,0:36:08.00,0:36:10.35,EN,,0,0,0,,which is to say you have these list-structured, Dialogue: 0,0:36:11.04,0:36:12.93,EN,,0,0,0,,recursive data list operations. Dialogue: 0,0:36:12.93,0:36:13.96,EN,,0,0,0,,That has nothing to do with it. Dialogue: 0,0:36:13.98,0:36:16.16,EN,,0,0,0,,It's simply that the expressions contain sub-expressions. Dialogue: 0,0:36:20.04,0:36:23.52,EN,,0,0,0,,AUDIENCE: Why is it that the order of the arguments in the arg list got reversed? Dialogue: 0,0:36:23.55,0:36:25.29,EN,,0,0,0,,PROFESSOR: Ah! Yes, I should've mentioned that. Dialogue: 0,0:36:27.26,0:36:29.07,EN,,0,0,0,,Here, the reason the order is reversed-- Dialogue: 0,0:36:32.78,0:36:35.37,EN,,0,0,0,,it's a question of what you mean by reversed. Dialogue: 0,0:36:36.05,0:36:39.90,EN,,0,0,0,,I believe it was Newton. Dialogue: 0,0:36:40.91,0:36:42.41,EN,,0,0,0,,In the very early part of optics, Dialogue: 0,0:36:42.43,0:36:43.26,EN,,0,0,0,,people realized Dialogue: 0,0:36:43.61,0:36:45.36,EN,,0,0,0,,that when you look through the lens of your eye, Dialogue: 0,0:36:45.50,0:36:46.73,EN,,0,0,0,,the image was up-side down. Dialogue: 0,0:36:46.73,0:36:48.04,EN,,0,0,0,,And there was a lot of argument about Dialogue: 0,0:36:48.04,0:36:50.48,EN,,0,0,0,,why that didn't mean you saw things up-side down. Dialogue: 0,0:36:51.28,0:36:52.65,EN,,0,0,0,,So it's sort of the same issue. Dialogue: 0,0:36:52.86,0:36:53.90,EN,,0,0,0,,Reversed from what? Dialogue: 0,0:36:54.81,0:36:56.24,EN,,0,0,0,,So we just need some convention. Dialogue: 0,0:36:56.59,0:37:00.35,EN,,0,0,0,,So all we.. The reason that they're coming at 4, 3 Dialogue: 0,0:37:00.80,0:37:02.49,EN,,0,0,0,,is because taking UNEV Dialogue: 0,0:37:02.52,0:37:04.03,EN,,0,0,0,,and consing the result onto argl. Dialogue: 0,0:37:04.52,0:37:06.68,EN,,0,0,0,,So you have to realize you've made that convention. Dialogue: 0,0:37:06.86,0:37:09.37,EN,,0,0,0,,The place that you have to realize that-- Dialogue: 0,0:37:09.98,0:37:11.23,EN,,0,0,0,,well, there's actually two places. Dialogue: 0,0:37:11.23,0:37:12.91,EN,,0,0,0,,One is in apply-primitive-operator, Dialogue: 0,0:37:12.91,0:37:14.06,EN,,0,0,0,,which has to realize that Dialogue: 0,0:37:15.12,0:37:16.75,EN,,0,0,0,,the arguments to primitives go in, Dialogue: 0,0:37:16.78,0:37:18.72,EN,,0,0,0,,the opposite order from the way you're writing them down. Dialogue: 0,0:37:19.49,0:37:21.00,EN,,0,0,0,,And the other one is, we'll see later Dialogue: 0,0:37:21.07,0:37:23.80,EN,,0,0,0,,when you actually go to bind a function's parameters, Dialogue: 0,0:37:24.01,0:37:25.74,EN,,0,0,0,,you should realize the arguments are going to come in Dialogue: 0,0:37:25.74,0:37:28.54,EN,,0,0,0,,from the opposite order of the variables to which you're binding them. Dialogue: 0,0:37:28.87,0:37:30.17,EN,,0,0,0,,So, if you just keep track of that, Dialogue: 0,0:37:31.08,0:37:31.83,EN,,0,0,0,,there's no problem. Dialogue: 0,0:37:31.83,0:37:33.69,EN,,0,0,0,,Also, this is completely arbitrary Dialogue: 0,0:37:33.90,0:37:34.96,EN,,0,0,0,,because, if we'd done, Dialogue: 0,0:37:35.10,0:37:37.15,EN,,0,0,0,,say, an iteration through a vector assigning them, Dialogue: 0,0:37:37.42,0:37:38.73,EN,,0,0,0,,they might come out in the other order. Dialogue: 0,0:37:40.41,0:37:42.04,EN,,0,0,0,,OK. So it's just a convention of the way Dialogue: 0,0:37:42.06,0:37:43.53,EN,,0,0,0,,this particular evaluator works. Dialogue: 0,0:37:45.39,0:37:46.24,EN,,0,0,0,,All right, let's take a break. Dialogue: 0,0:37:46.33,0:38:02.44,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:38:02.44,0:38:07.64,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:38:28.62,0:38:32.51,EN,,0,0,0,,By: Prof. Harold Abelson && Sussman Jay Sussman Dialogue: 0,0:38:32.51,0:38:35.68,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:38:41.84,0:38:45.31,EN,,0,0,0,,Professor: We just saw evaluating an expression Dialogue: 0,0:38:45.60,0:38:47.08,EN,,0,0,0,,and, of course, that was very simple one. But Dialogue: 0,0:38:48.81,0:38:50.24,EN,,0,0,0,,in essence, it would be no different Dialogue: 0,0:38:50.24,0:38:52.03,EN,,0,0,0,,if it was some big nested expression, Dialogue: 0,0:38:52.03,0:38:54.57,EN,,0,0,0,,so there would just be deeper recursion on the stack. Dialogue: 0,0:38:55.13,0:38:56.03,EN,,0,0,0,,But what I want to do now Dialogue: 0,0:38:56.04,0:38:56.91,EN,,0,0,0,,is show you the last piece. Dialogue: 0,0:38:56.92,0:38:59.82,EN,,0,0,0,,I want to walk you around this eval and apply loop, Dialogue: 0,0:39:01.01,0:39:02.81,EN,,0,0,0,,That's the thing we haven't seen, really. Dialogue: 0,0:39:03.00,0:39:04.75,EN,,0,0,0,,We haven't seen any compound procedures Dialogue: 0,0:39:05.20,0:39:07.79,EN,,0,0,0,,where evalutation of procedure reduces to Dialogue: 0,0:39:07.92,0:39:10.11,EN,,0,0,0,,where applying of procedure reduces to Dialogue: 0,0:39:10.12,0:39:11.64,EN,,0,0,0,,evaluating the body of the procedure, Dialogue: 0,0:39:12.44,0:39:15.88,EN,,0,0,0,,so let's just suppose we had this. Dialogue: 0,0:39:15.93,0:39:17.44,EN,,0,0,0,,Suppose we were looking at the procedure Dialogue: 0,0:39:18.07,0:39:31.60,EN,,0,0,0,,define F of A and B to be the sum of A and B. Dialogue: 0,0:39:33.99,0:39:37.32,EN,,0,0,0,,So, as we typed in that procedure previously, Dialogue: 0,0:39:37.69,0:39:41.64,EN,,0,0,0,,and now we're going to evaluate F of X and Y Dialogue: 0,0:39:42.27,0:39:44.20,EN,,0,0,0,,again, in this environment, E,0, Dialogue: 0,0:39:44.35,0:39:47.02,EN,,0,0,0,,where X is bound to 3 and Y is bound to 4. Dialogue: 0,0:39:50.78,0:39:52.11,EN,,0,0,0,,When the defined is executed, Dialogue: 0,0:39:52.12,0:39:53.69,EN,,0,0,0,,remember, there's a lambda here, Dialogue: 0,0:39:53.82,0:39:55.53,EN,,0,0,0,,and lambdas create procedures. Dialogue: 0,0:39:55.95,0:39:58.49,EN,,0,0,0,,And, basically, what will happen is, Dialogue: 0,0:39:59.63,0:40:00.68,EN,,0,0,0,,in E0, Dialogue: 0,0:40:01.00,0:40:02.65,EN,,0,0,0,,we'll end up with a binding for F, Dialogue: 0,0:40:03.56,0:40:05.61,EN,,0,0,0,,which will say F is a procedure, Dialogue: 0,0:40:07.15,0:40:11.28,EN,,0,0,0,,and its args are A and B, Dialogue: 0,0:40:12.57,0:40:16.19,EN,,0,0,0,,and its body is plus a,b. Dialogue: 0,0:40:18.11,0:40:20.99,EN,,0,0,0,,So that's what the environment would have looked like Dialogue: 0,0:40:21.21,0:40:22.52,EN,,0,0,0,,had we made that definition. Dialogue: 0,0:40:24.22,0:40:27.28,EN,,0,0,0,,Then, when we go to evaluate F of X and Y, Dialogue: 0,0:40:28.80,0:40:30.89,EN,,0,0,0,,we'll go through exactly the same process Dialogue: 0,0:40:31.02,0:40:31.85,EN,,0,0,0,,that we did before. Dialogue: 0,0:40:31.88,0:40:33.09,EN,,0,0,0,,It's even the same expression. Dialogue: 0,0:40:33.28,0:40:34.38,EN,,0,0,0,,The only difference is that Dialogue: 0,0:40:34.40,0:40:36.64,EN,,0,0,0,,F, instead of having primitive "plus" in it Dialogue: 0,0:40:37.24,0:40:38.99,EN,,0,0,0,,will have this thing. Dialogue: 0,0:40:41.04,0:40:43.60,EN,,0,0,0,,And so we'll go through exactly the same process, Dialogue: 0,0:40:43.60,0:40:44.92,EN,,0,0,0,,except this time, when we end up Dialogue: 0,0:40:45.26,0:40:47.42,EN,,0,0,0,,at apply-dispatch, Dialogue: 0,0:40:47.86,0:40:50.28,EN,,0,0,0,,the function register, instead of having primitive plus, Dialogue: 0,0:40:50.44,0:40:53.58,EN,,0,0,0,,will have a thing that will represent it saying procedure, Dialogue: 0,0:40:54.30,0:40:59.00,EN,,0,0,0,,where the args are A and B, Dialogue: 0,0:41:00.64,0:41:06.27,EN,,0,0,0,,and the body is plus A, B. Dialogue: 0,0:41:07.87,0:41:09.92,EN,,0,0,0,,And, again, what I mean, by its ENV, Dialogue: 0,0:41:09.96,0:41:11.12,EN,,0,0,0,,I mean there's a pointer to it, Dialogue: 0,0:41:11.24,0:41:13.07,EN,,0,0,0,,so don't worry that I'm writing a lot of stuff there. Dialogue: 0,0:41:13.28,0:41:15.63,EN,,0,0,0,,There's a pointer to this procedure data structure. Dialogue: 0,0:41:17.17,0:41:19.77,EN,,0,0,0,,OK, so, we're in exactly the same situation. Dialogue: 0,0:41:20.27,0:41:22.43,EN,,0,0,0,,We get to apply-dispatch, Dialogue: 0,0:41:23.98,0:41:26.48,EN,,0,0,0,,so, here, we come to apply-dispatch. Dialogue: 0,0:41:26.48,0:41:28.73,EN,,0,0,0,,Last time, we branched off to a primitive procedure. Dialogue: 0,0:41:30.01,0:41:30.70,EN,,0,0,0,,Here, it says oh, Dialogue: 0,0:41:30.84,0:41:32.80,EN,,0,0,0,,we now have a compound procedure, Dialogue: 0,0:41:34.55,0:41:36.60,EN,,0,0,0,,so we're going to go off to compound-apply. Dialogue: 0,0:41:38.47,0:41:39.92,EN,,0,0,0,,Now, what's compound-apply? Dialogue: 0,0:41:41.92,0:41:44.54,EN,,0,0,0,,Well, remember what the meta-circular evaluator did? Dialogue: 0,0:41:45.09,0:41:47.40,EN,,0,0,0,,Compound-apply said we're going to evaluate Dialogue: 0,0:41:49.90,0:41:51.60,EN,,0,0,0,,the body of the procedure Dialogue: 0,0:41:52.94,0:41:54.12,EN,,0,0,0,,in some new environment. Dialogue: 0,0:41:54.12,0:41:55.87,EN,,0,0,0,,Where does that new environment come from? Dialogue: 0,0:41:56.73,0:42:01.36,EN,,0,0,0,,We take the environment that was packaged with the procedure, Dialogue: 0,0:42:03.02,0:42:05.79,EN,,0,0,0,,we bind the parameters of the procedure Dialogue: 0,0:42:06.00,0:42:07.63,EN,,0,0,0,,to the arguments that we're passing in, Dialogue: 0,0:42:09.75,0:42:11.95,EN,,0,0,0,,and use that as a new frame to extend Dialogue: 0,0:42:12.59,0:42:13.79,EN,,0,0,0,,the procedure environment. Dialogue: 0,0:42:14.99,0:42:16.08,EN,,0,0,0,,And that's the environment Dialogue: 0,0:42:16.30,0:42:18.88,EN,,0,0,0,,in which we evaluate the procedure body, Dialogue: 0,0:42:20.12,0:42:24.47,EN,,0,0,0,,Right? That's going around the apply/eval loop. Dialogue: 0,0:42:24.47,0:42:26.25,EN,,0,0,0,,That's apply coming back to call eval, Dialogue: 0,0:42:32.86,0:42:34.92,EN,,0,0,0,,So, now, that's all we have to do in compound-apply. Dialogue: 0,0:42:36.78,0:42:37.72,EN,,0,0,0,,What are we going to do? Dialogue: 0,0:42:37.72,0:42:40.97,EN,,0,0,0,,We're going to manufacture a new environment. Dialogue: 0,0:42:43.55,0:42:45.64,EN,,0,0,0,,And we're going to manufacture a new environment that, Dialogue: 0,0:42:46.76,0:42:48.11,EN,,0,0,0,,let's see, that we'll call E1. Dialogue: 0,0:42:52.90,0:42:55.63,EN,,0,0,0,,E1 is going to be some environment where the Dialogue: 0,0:42:57.31,0:42:59.15,EN,,0,0,0,,where the parameters of the procedure, Dialogue: 0,0:42:59.21,0:43:03.26,EN,,0,0,0,,Nwhere A is bound to 3, and B is bound to 4, Dialogue: 0,0:43:04.27,0:43:05.76,EN,,0,0,0,,and it's linked to E0 Dialogue: 0,0:43:05.76,0:43:08.08,EN,,0,0,0,,because that's where f is defined. Dialogue: 0,0:43:09.27,0:43:10.27,EN,,0,0,0,,And, in this environment, Dialogue: 0,0:43:10.27,0:43:11.96,EN,,0,0,0,,we're going to evaluate the body of the procedure. Dialogue: 0,0:43:12.05,0:43:14.48,EN,,0,0,0,,So let's look at that, we're going Dialogue: 0,0:43:16.52,0:43:18.32,EN,,0,0,0,,Here we are at compound-apply, Dialogue: 0,0:43:20.30,0:43:23.47,EN,,0,0,0,,which says assign to the expression register Dialogue: 0,0:43:24.50,0:43:25.98,EN,,0,0,0,,the body of the procedure Dialogue: 0,0:43:25.98,0:43:27.26,EN,,0,0,0,,that's in the function register. Dialogue: 0,0:43:28.38,0:43:30.64,EN,,0,0,0,,So I assign to the expression register Dialogue: 0,0:43:31.29,0:43:32.33,EN,,0,0,0,,the procedure body, Dialogue: 0,0:43:40.75,0:43:41.10,EN,,0,0,0,,OK? Dialogue: 0,0:43:42.64,0:43:44.97,EN,,0,0,0,,That's going to be evaluated in an environment Dialogue: 0,0:43:45.82,0:43:48.32,EN,,0,0,0,,which is formed by making some bindings Dialogue: 0,0:43:51.30,0:43:53.67,EN,,0,0,0,,using information determined by the procedure-- Dialogue: 0,0:43:53.67,0:43:56.25,EN,,0,0,0,,that's what's in FUN-- and the argument list. Dialogue: 0,0:43:57.80,0:44:00.00,EN,,0,0,0,,And let's not worry about exactly what that does, Dialogue: 0,0:44:00.08,0:44:01.63,EN,,0,0,0,,but you can see the information's there. Dialogue: 0,0:44:01.93,0:44:03.32,EN,,0,0,0,,So make bindings will say oh, Dialogue: 0,0:44:04.04,0:44:07.90,EN,,0,0,0,,the procedure, itself, had an environment attached to it. Dialogue: 0,0:44:07.96,0:44:09.32,EN,,0,0,0,,I didn't write that quite here. Dialogue: 0,0:44:09.36,0:44:10.56,EN,,0,0,0,,I should've said in environment Dialogue: 0,0:44:11.30,0:44:12.73,EN,,0,0,0,,because every procedure gets built Dialogue: 0,0:44:12.76,0:44:13.44,EN,,0,0,0,,with an environment. Dialogue: 0,0:44:13.66,0:44:14.83,EN,,0,0,0,,So, from that environment, Dialogue: 0,0:44:15.68,0:44:16.35,EN,,0,0,0,,it knows Dialogue: 0,0:44:16.60,0:44:18.65,EN,,0,0,0,,what the procedure's definition environment is. Dialogue: 0,0:44:19.29,0:44:20.75,EN,,0,0,0,,It knows what the arguments are. Dialogue: 0,0:44:21.83,0:44:22.49,EN,,0,0,0,,It looks at argl, Dialogue: 0,0:44:22.49,0:44:24.28,EN,,0,0,0,,and then you see a reversal convention here. Dialogue: 0,0:44:24.28,0:44:26.62,EN,,0,0,0,,It just has to know that argl is reversed, Dialogue: 0,0:44:27.06,0:44:28.81,EN,,0,0,0,,and it builds this frame, E,1. Dialogue: 0,0:44:29.99,0:44:31.08,EN,,0,0,0,,All right, so, let's assume that Dialogue: 0,0:44:31.10,0:44:32.92,EN,,0,0,0,,that's what make bindings returns, Dialogue: 0,0:44:33.36,0:44:36.22,EN,,0,0,0,,so it assigns to ENV this thing, E,1. Dialogue: 0,0:44:41.34,0:44:42.54,EN,,0,0,0,,The next thing it says Dialogue: 0,0:44:43.95,0:44:45.84,EN,,0,0,0,,is restore continue. Dialogue: 0,0:44:46.89,0:44:48.19,EN,,0,0,0,,Remember what continue was here? Dialogue: 0,0:44:48.76,0:44:50.43,EN,,0,0,0,,It got put up in the last segment. Dialogue: 0,0:44:52.24,0:44:54.02,EN,,0,0,0,,Continue got stored. Dialogue: 0,0:44:54.02,0:44:55.18,EN,,0,0,0,,That was the original done, Dialogue: 0,0:44:55.32,0:44:56.56,EN,,0,0,0,,which said what are you going to do Dialogue: 0,0:44:56.73,0:44:59.44,EN,,0,0,0,,after you're done with this particular application? Dialogue: 0,0:45:00.14,0:45:01.72,EN,,0,0,0,,It was one of the very first things that happened Dialogue: 0,0:45:01.76,0:45:03.18,EN,,0,0,0,,when we evaluated the application. Dialogue: 0,0:45:03.88,0:45:05.87,EN,,0,0,0,,And now, finally, we're going to restore continue. Dialogue: 0,0:45:06.86,0:45:09.55,EN,,0,0,0,,Remember apply-dispatch's contract. Dialogue: 0,0:45:09.58,0:45:11.20,EN,,0,0,0,,It assumes that where it should go to next Dialogue: 0,0:45:11.23,0:45:11.98,EN,,0,0,0,,was on the stack, Dialogue: 0,0:45:12.03,0:45:13.12,EN,,0,0,0,,and there it was on the stack. Dialogue: 0,0:45:13.59,0:45:14.76,EN,,0,0,0,,Continue has done, Dialogue: 0,0:45:17.82,0:45:19.90,EN,,0,0,0,,and now we're going to go back to eval-dispatch. Dialogue: 0,0:45:19.94,0:45:20.84,EN,,0,0,0,,We're set up again. Dialogue: 0,0:45:20.97,0:45:24.41,EN,,0,0,0,,We have an expression, an environment, and a place to go to. Dialogue: 0,0:45:25.80,0:45:26.89,EN,,0,0,0,,We're not going to go through that Dialogue: 0,0:45:27.88,0:45:29.55,EN,,0,0,0,,because it's sort of the same expression. Dialogue: 0,0:45:35.40,0:45:37.79,EN,,0,0,0,,OK, but the thing, again, to notice Dialogue: 0,0:45:37.82,0:45:38.73,EN,,0,0,0,,is, at this point, Dialogue: 0,0:45:39.34,0:45:43.72,EN,,0,0,0,,we have reduced the original expression, F,X,Y, Dialogue: 0,0:45:44.64,0:45:47.92,EN,,0,0,0,,We've reduced evaluating F,X,Y in environment E,0 Dialogue: 0,0:45:48.89,0:45:52.67,EN,,0,0,0,,to evaluate plus A, B in E,1. Dialogue: 0,0:45:52.78,0:45:55.92,EN,,0,0,0,,And notice, nothing's on the stack, right? Dialogue: 0,0:45:56.11,0:45:56.83,EN,,0,0,0,,It's a reduction. Dialogue: 0,0:45:56.84,0:45:59.80,EN,,0,0,0,,At this point, the machine does not contain, Dialogue: 0,0:45:59.84,0:46:01.20,EN,,0,0,0,,as part of its state, Dialogue: 0,0:46:01.76,0:46:03.71,EN,,0,0,0,,the fact that it's in the middle of evaluating Dialogue: 0,0:46:03.72,0:46:04.88,EN,,0,0,0,,some procedure called f, Dialogue: 0,0:46:05.49,0:46:06.28,EN,,0,0,0,,that's gone, Dialogue: 0,0:46:07.66,0:46:09.55,EN,,0,0,0,,Right? There's no accumulated state? Dialogue: 0,0:46:13.07,0:46:14.37,EN,,0,0,0,,Again, that's a very important idea. Dialogue: 0,0:46:14.37,0:46:16.33,EN,,0,0,0,,That's the meaning of, Dialogue: 0,0:46:16.76,0:46:18.39,EN,,0,0,0,,when we used to write in the substitution model, Dialogue: 0,0:46:18.39,0:46:20.86,EN,,0,0,0,,this expression reduces to that expression. Dialogue: 0,0:46:21.35,0:46:22.66,EN,,0,0,0,,And you don't have to remember anything. Dialogue: 0,0:46:22.66,0:46:24.50,EN,,0,0,0,,And here, you see the meaning of reduction. Dialogue: 0,0:46:24.56,0:46:26.16,EN,,0,0,0,,At this point, there is nothing on the stack. Dialogue: 0,0:46:31.59,0:46:33.63,EN,,0,0,0,,See, that has very important consequences. Dialogue: 0,0:46:35.24,0:46:37.90,EN,,0,0,0,,Let's go back and look at iterative factorial, Dialogue: 0,0:46:40.42,0:46:42.76,EN,,0,0,0,,all right? Remember, this was some sort of loop Dialogue: 0,0:46:44.01,0:46:44.88,EN,,0,0,0,,and doing iter. Dialogue: 0,0:46:45.13,0:46:47.36,EN,,0,0,0,,And we kept saying that's an iterative procedure, Dialogue: 0,0:46:49.26,0:46:53.84,EN,,0,0,0,,And what we wrote, remember, Dialogue: 0,0:46:58.44,0:47:03.13,EN,,0,0,0,,are things like, we said, Dialogue: 0,0:47:04.35,0:47:11.07,EN,,0,0,0,,fact-iter of 5. Dialogue: 0,0:47:12.36,0:47:18.67,EN,,0,0,0,,We wrote things like reduces to iter of 1, and 1, and 5, Dialogue: 0,0:47:19.03,0:47:25.15,EN,,0,0,0,,which reduces to iter of 1, and 2, and 5, Dialogue: 0,0:47:25.32,0:47:27.07,EN,,0,0,0,,and so on, and so on, and so on. Dialogue: 0,0:47:27.07,0:47:28.17,EN,,0,0,0,,And we kept saying well, look, Dialogue: 0,0:47:28.17,0:47:30.35,EN,,0,0,0,,you don't have to build up any storage to do that. Dialogue: 0,0:47:31.72,0:47:32.73,EN,,0,0,0,,And we waved our hands, Dialogue: 0,0:47:32.75,0:47:34.59,EN,,0,0,0,,and said in principle, there's no storage needed. Dialogue: 0,0:47:35.04,0:47:36.17,EN,,0,0,0,,Now, you see no storage needed. Dialogue: 0,0:47:36.17,0:47:39.09,EN,,0,0,0,,Each of these is a real reduction, right? Dialogue: 0,0:47:39.09,0:47:42.60,EN,,0,0,0,,As you walk through these expressions, Dialogue: 0,0:47:47.30,0:47:50.51,EN,,0,0,0,,As you walk through these expressions, Dialogue: 0,0:47:50.83,0:47:51.37,EN,,0,0,0,,what you'll see Dialogue: 0,0:47:51.37,0:47:52.81,EN,,0,0,0,,are these expressions on the stack Dialogue: 0,0:47:53.75,0:47:55.64,EN,,0,0,0,,in some particular environment, Dialogue: 0,0:47:56.42,0:48:00.02,EN,,0,0,0,,and then these expressions, sorry, in the EXP register Dialogue: 0,0:48:00.02,0:48:01.50,EN,,0,0,0,,in some particular environment. Dialogue: 0,0:48:01.57,0:48:02.19,EN,,0,0,0,,And, at each point, Dialogue: 0,0:48:02.19,0:48:04.00,EN,,0,0,0,,there'll be no accumulated stuff on the stack Dialogue: 0,0:48:04.36,0:48:05.68,EN,,0,0,0,,because each one's a real reduction. Dialogue: 0,0:48:09.28,0:48:10.51,EN,,0,0,0,,All right, so, for example, Dialogue: 0,0:48:10.58,0:48:12.51,EN,,0,0,0,,just to go through it in a little bit more care, Dialogue: 0,0:48:13.46,0:48:16.88,EN,,0,0,0,,if I start out with an expression that says something like, Dialogue: 0,0:48:22.44,0:48:34.25,EN,,0,0,0,,oh, say, fact-iter of 5 in some environment Dialogue: 0,0:48:42.11,0:48:46.30,EN,,0,0,0,,that will, at some point, create an environment Dialogue: 0,0:48:46.81,0:48:48.38,EN,,0,0,0,,in which n is down to 5. Dialogue: 0,0:48:51.47,0:48:52.01,EN,,0,0,0,,Let's call that-- Dialogue: 0,0:48:55.68,0:48:56.59,EN,,0,0,0,,And, at some point, Dialogue: 0,0:48:56.89,0:49:02.56,EN,,0,0,0,,the machine will reduce this whole thing Dialogue: 0,0:49:02.91,0:49:04.35,EN,,0,0,0,,to a thing that says that's really Dialogue: 0,0:49:04.76,0:49:09.85,EN,,0,0,0,,iter of 1, and 1, and n, Dialogue: 0,0:49:10.68,0:49:13.72,EN,,0,0,0,,evaluated in this environment, E,1 Dialogue: 0,0:49:15.87,0:49:17.16,EN,,0,0,0,,with nothing on the stack. Dialogue: 0,0:49:17.16,0:49:19.55,EN,,0,0,0,,See, at this moment, the machine is not remembering Dialogue: 0,0:49:20.71,0:49:22.50,EN,,0,0,0,,that evaluating this expression, iter-- Dialogue: 0,0:49:25.00,0:49:25.63,EN,,0,0,0,,which is the loop-- Dialogue: 0,0:49:25.79,0:49:28.57,EN,,0,0,0,,is part of this thing called iterative factorial. Dialogue: 0,0:49:29.68,0:49:30.59,EN,,0,0,0,,It's not remembering that. Dialogue: 0,0:49:30.59,0:49:33.17,EN,,0,0,0,,It's just reducing the expression to that, right? Dialogue: 0,0:49:33.17,0:49:36.56,EN,,0,0,0,,If we look again at the body of iterative factorial, Dialogue: 0,0:49:38.05,0:49:41.08,EN,,0,0,0,,this expression has reduced to that expression. Dialogue: 0,0:49:42.81,0:49:43.87,EN,,0,0,0,,Oh, I shouldn't have the n there. Dialogue: 0,0:49:46.59,0:49:47.74,EN,,0,0,0,,It's a slightly different convention Dialogue: 0,0:49:47.74,0:49:49.13,EN,,0,0,0,,from the slide to the program. Dialogue: 0,0:49:53.34,0:49:56.25,EN,,0,0,0,,And, then, what's the body of iter? Dialogue: 0,0:49:56.28,0:49:57.40,EN,,0,0,0,,Well, iter's going to be an if, Dialogue: 0,0:49:58.75,0:50:00.19,EN,,0,0,0,,and I won't go through the details of if. Dialogue: 0,0:50:00.24,0:50:01.63,EN,,0,0,0,,It'll evaluate the predicate. Dialogue: 0,0:50:02.40,0:50:03.71,EN,,0,0,0,,In this case, it'll be false. Dialogue: 0,0:50:03.81,0:50:08.64,EN,,0,0,0,,And this iter will now reduce to the expression Dialogue: 0,0:50:09.85,0:50:20.20,EN,,0,0,0,,iter of whatever it says, star, counter product, and-- Dialogue: 0,0:50:21.62,0:50:22.24,EN,,0,0,0,,what does it say-- Dialogue: 0,0:50:22.68,0:50:24.56,EN,,0,0,0,,plus counter 1 Dialogue: 0,0:50:28.72,0:50:31.42,EN,,0,0,0,,in some other environment, by this time, E,2, Dialogue: 0,0:50:32.97,0:50:35.98,EN,,0,0,0,,where E,2 will be set up having bindings Dialogue: 0,0:50:36.49,0:50:39.39,EN,,0,0,0,,for product and counter. Dialogue: 0,0:50:42.92,0:50:44.33,EN,,0,0,0,,And it'll reduce to that. Dialogue: 0,0:50:44.94,0:50:46.04,EN,,0,0,0,,Right? It won't be remembering Dialogue: 0,0:50:46.06,0:50:48.75,EN,,0,0,0,,that it's part of something that it has to return to. Dialogue: 0,0:50:49.34,0:50:50.43,EN,,0,0,0,,And when iter calls iter again, Dialogue: 0,0:50:50.44,0:50:52.56,EN,,0,0,0,,it'll reduce to another thing that looks like this Dialogue: 0,0:50:53.05,0:50:54.68,EN,,0,0,0,,in some environment, E,3, Dialogue: 0,0:50:54.83,0:50:56.67,EN,,0,0,0,,which has new bindings for product and counter. Dialogue: 0,0:50:58.80,0:51:05.29,EN,,0,0,0,,OK? So, if you're wondering, Dialogue: 0,0:51:06.09,0:51:07.53,EN,,0,0,0,,if you've always been queasy about Dialogue: 0,0:51:08.25,0:51:10.67,EN,,0,0,0,,about how it is we've been saying those procedures Dialogue: 0,0:51:10.67,0:51:12.45,EN,,0,0,0,,that look syntactically recursive, Dialogue: 0,0:51:13.20,0:51:15.69,EN,,0,0,0,,are, in fact, iterative, Dialogue: 0,0:51:15.87,0:51:17.24,EN,,0,0,0,,run in constant space, Dialogue: 0,0:51:18.40,0:51:19.75,EN,,0,0,0,,well, I don't know if this makes you less queasy, Dialogue: 0,0:51:19.75,0:51:21.23,EN,,0,0,0,,but at least it shows you what's happening. Dialogue: 0,0:51:21.23,0:51:22.81,EN,,0,0,0,,There really isn't any buildup there. Dialogue: 0,0:51:25.91,0:51:27.58,EN,,0,0,0,,Now, you might ask well, is there buildup Dialogue: 0,0:51:27.98,0:51:30.08,EN,,0,0,0,,in principle in these environment frames? Dialogue: 0,0:51:31.71,0:51:32.37,EN,,0,0,0,,And the answer is yeah, Dialogue: 0,0:51:32.40,0:51:33.84,EN,,0,0,0,,you have to make these new environment frames, Dialogue: 0,0:51:33.84,0:51:35.26,EN,,0,0,0,,but you don't have to hang onto them Dialogue: 0,0:51:35.42,0:51:36.19,EN,,0,0,0,,when you're done. Dialogue: 0,0:51:36.44,0:51:37.61,EN,,0,0,0,,They can be garbage collected, Dialogue: 0,0:51:37.92,0:51:39.47,EN,,0,0,0,,or the space can be reused automatically. Dialogue: 0,0:51:40.72,0:51:42.99,EN,,0,0,0,,But you see the control structure of the evaluator Dialogue: 0,0:51:43.25,0:51:46.12,EN,,0,0,0,,is really using this idea that you actually have a reduction, Dialogue: 0,0:51:47.02,0:51:49.29,EN,,0,0,0,,so these procedures really are iterative procedures. Dialogue: 0,0:51:50.13,0:51:51.38,EN,,0,0,0,,All right, let's stop for questions. Dialogue: 0,0:52:02.68,0:52:03.23,EN,,0,0,0,,All right, let's break. Dialogue: 0,0:52:04.12,0:52:24.56,EN,,0,0,0,,[JESU, JOY OF MAN'S DESIRING] Dialogue: 0,0:52:24.60,0:52:29.69,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:52:35.20,0:52:38.36,EN,,0,0,0,,By: Prof. Harold Abelson && Sussman Jay Sussman Dialogue: 0,0:52:38.36,0:52:42.14,EN,,0,0,0,,The Structure And Interpretation of Computer Programs Dialogue: 0,0:52:48.77,0:52:51.55,EN,,0,0,0,,PROFESSOR: Let me contrast the iterative procedure Dialogue: 0,0:52:52.77,0:52:54.89,EN,,0,0,0,,just so you'll see where space does build up Dialogue: 0,0:52:55.12,0:52:56.14,EN,,0,0,0,,with a recursive procedure, Dialogue: 0,0:52:56.17,0:52:57.29,EN,,0,0,0,,so you can see the difference. Dialogue: 0,0:52:58.03,0:53:01.20,EN,,0,0,0,,Let's look at the evaluation of recursive factorial. Dialogue: 0,0:53:02.65,0:53:05.53,EN,,0,0,0,,So, here's fact-recursive, Dialogue: 0,0:53:05.55,0:53:07.22,EN,,0,0,0,,or standard factorial definition. Dialogue: 0,0:53:07.22,0:53:10.01,EN,,0,0,0,,We said this one is still a recursive procedure, Dialogue: 0,0:53:10.01,0:53:12.57,EN,,0,0,0,,but this is actually a recursive process. Dialogue: 0,0:53:13.75,0:53:16.56,EN,,0,0,0,,And then, just to link it back to the way we started, Dialogue: 0,0:53:16.83,0:53:20.53,EN,,0,0,0,,we said oh, you can see that it's going to be recursive process Dialogue: 0,0:53:20.53,0:53:21.82,EN,,0,0,0,,by the substitution model Dialogue: 0,0:53:22.36,0:53:28.00,EN,,0,0,0,,because, if I say recursive factorial of 5, Dialogue: 0,0:53:30.45,0:53:34.94,EN,,0,0,0,,that turns into 5 times-- Dialogue: 0,0:53:36.28,0:53:37.82,EN,,0,0,0,,what is it, fact-rec, or record fact-- Dialogue: 0,0:53:42.62,0:53:47.93,EN,,0,0,0,,5 times recursive factorial of 4, Dialogue: 0,0:53:49.66,0:53:58.22,EN,,0,0,0,,which turns into 5 times 4 times fact-rec of 3, Dialogue: 0,0:54:00.22,0:54:08.60,EN,,0,0,0,,which returns into 5 times 4 times 3 times Dialogue: 0,0:54:13.45,0:54:15.31,EN,,0,0,0,,and so on, right? Dialogue: 0,0:54:15.39,0:54:17.39,EN,,0,0,0,,The idea is there was this chain of stuff building up, Dialogue: 0,0:54:18.10,0:54:20.06,EN,,0,0,0,,which justified, in the substitution model, Dialogue: 0,0:54:20.08,0:54:21.28,EN,,0,0,0,,the fact that it's recursive. Dialogue: 0,0:54:21.52,0:54:24.18,EN,,0,0,0,,And now, let's actually see that chain of stuff build up Dialogue: 0,0:54:24.18,0:54:25.29,EN,,0,0,0,,and where it is in the machine, OK? Dialogue: 0,0:54:27.68,0:54:29.95,EN,,0,0,0,,All right, well, let's imagine we're going to start out again. Dialogue: 0,0:54:30.44,0:54:40.01,EN,,0,0,0,,We'll tell it to evaluate recursive factorial of 5 Dialogue: 0,0:54:41.45,0:54:43.39,EN,,0,0,0,,in some environment, again, E0, where Dialogue: 0,0:54:45.08,0:54:48.97,EN,,0,0,0,,where recursive factorial is defined, OK? Dialogue: 0,0:54:49.55,0:54:51.23,EN,,0,0,0,,Well, now we know what's eventually going to happen. Dialogue: 0,0:54:52.25,0:54:53.64,EN,,0,0,0,,This is going to come along, Dialogue: 0,0:54:53.92,0:54:55.64,EN,,0,0,0,,it'll evaluate those things, Dialogue: 0,0:54:55.68,0:54:56.99,EN,,0,0,0,,figure out it's a procedure, Dialogue: 0,0:54:57.18,0:55:00.16,EN,,0,0,0,,build somewhere over here an environment, E1, Dialogue: 0,0:55:00.88,0:55:03.69,EN,,0,0,0,,which has n bound to 5, Dialogue: 0,0:55:04.33,0:55:06.54,EN,,0,0,0,,which hangs off of E0, Dialogue: 0,0:55:07.80,0:55:08.97,EN,,0,0,0,,which would be, presumably, Dialogue: 0,0:55:08.99,0:55:12.30,EN,,0,0,0,,the definition environment of recursive factorial. Dialogue: 0,0:55:14.11,0:55:15.74,EN,,0,0,0,,OK? And, in this environment, Dialogue: 0,0:55:15.76,0:55:17.48,EN,,0,0,0,,it's going to go off and evaluate the body. Dialogue: 0,0:55:19.67,0:55:25.92,EN,,0,0,0,,So, again, the evaluation here will reduce to Dialogue: 0,0:55:27.00,0:55:28.92,EN,,0,0,0,,evaluating the body in E1. Dialogue: 0,0:55:30.16,0:55:31.34,EN,,0,0,0,,That's going to look at an if, Dialogue: 0,0:55:32.17,0:55:33.53,EN,,0,0,0,,and I won't go through the details of if. Dialogue: 0,0:55:33.53,0:55:34.88,EN,,0,0,0,,It'll look at the predicate. Dialogue: 0,0:55:34.88,0:55:37.53,EN,,0,0,0,,It'll decide it eventually has to evaluate the alternative. Dialogue: 0,0:55:37.84,0:55:40.41,EN,,0,0,0,,So this whole thing, again, will reduce to Dialogue: 0,0:55:41.30,0:55:45.53,EN,,0,0,0,,the alternative of recursive factorial, Dialogue: 0,0:55:45.82,0:55:46.97,EN,,0,0,0,,the alternative clause, Dialogue: 0,0:55:47.23,0:55:51.16,EN,,0,0,0,,which says that this whole thing reduces to times n Dialogue: 0,0:55:53.07,0:55:59.96,EN,,0,0,0,,of recursive factorial of n minus 1 Dialogue: 0,0:56:03.48,0:56:05.55,EN,,0,0,0,,in the environment E1 Dialogue: 0,0:56:08.38,0:56:10.91,EN,,0,0,0,,OK? So the original expression, now, is going to reduce Dialogue: 0,0:56:11.04,0:56:12.52,EN,,0,0,0,,to evaluating that expression, all right? Dialogue: 0,0:56:13.75,0:56:16.28,EN,,0,0,0,,OK? Now we have an application. Dialogue: 0,0:56:16.28,0:56:17.63,EN,,0,0,0,,We did an application before. Dialogue: 0,0:56:18.22,0:56:20.25,EN,,0,0,0,,Remember what happens in an application? Dialogue: 0,0:56:20.36,0:56:21.69,EN,,0,0,0,,The first thing you do is you go off and you Dialogue: 0,0:56:21.74,0:56:24.81,EN,,0,0,0,,you save the value of the continue register on the stack. Dialogue: 0,0:56:25.35,0:56:27.18,EN,,0,0,0,,So the stack here is going to have done in it. Dialogue: 0,0:56:29.98,0:56:32.88,EN,,0,0,0,,And then you're going to set up to evaluate the sub-parts. Dialogue: 0,0:56:35.00,0:56:37.20,EN,,0,0,0,,OK? So here we go off to evaluate the sub-parts. Dialogue: 0,0:56:39.47,0:56:41.45,EN,,0,0,0,,First thing we're going to do is evaluate the operator. Dialogue: 0,0:56:44.60,0:56:46.32,EN,,0,0,0,,What happens when we evaluate an operator? Dialogue: 0,0:56:47.25,0:56:48.99,EN,,0,0,0,,Well, we arrange things so that Dialogue: 0,0:56:49.00,0:56:51.04,EN,,0,0,0,,the operator ends up in the expression register. Dialogue: 0,0:56:51.48,0:56:53.15,EN,,0,0,0,,The environments in the ENV register Dialogue: 0,0:56:53.66,0:56:54.60,EN,,0,0,0,,continue someplace Dialogue: 0,0:56:54.62,0:56:56.22,EN,,0,0,0,,where we're going to go evaluate the arguments. Dialogue: 0,0:56:56.59,0:56:57.37,EN,,0,0,0,,And, on the stack, Dialogue: 0,0:56:57.40,0:56:59.29,EN,,0,0,0,,we've saved the original continue, Dialogue: 0,0:56:59.52,0:57:01.02,EN,,0,0,0,,which is where we wanted to be when we're all done. Dialogue: 0,0:57:01.72,0:57:02.86,EN,,0,0,0,,And then the things we needed Dialogue: 0,0:57:03.58,0:57:05.80,EN,,0,0,0,,when we're going to get done evaluating the operator, Dialogue: 0,0:57:05.90,0:57:07.66,EN,,0,0,0,,the things we'll need to evaluate the arguments, Dialogue: 0,0:57:07.69,0:57:12.01,EN,,0,0,0,,namely the environment and those arguments, Dialogue: 0,0:57:12.14,0:57:13.44,EN,,0,0,0,,those unevaluated arguments, Dialogue: 0,0:57:14.20,0:57:15.62,EN,,0,0,0,,so there they are sitting on the stack. Dialogue: 0,0:57:15.62,0:57:18.59,EN,,0,0,0,,And we're about to go off to evaluate the operator. Dialogue: 0,0:57:23.26,0:57:26.73,EN,,0,0,0,,Well, when we return from this particular call-- Dialogue: 0,0:57:26.92,0:57:28.64,EN,,0,0,0,,so we're about to call eval-dispatch here-- Dialogue: 0,0:57:29.38,0:57:30.83,EN,,0,0,0,,when we return from this call, Dialogue: 0,0:57:31.45,0:57:32.70,EN,,0,0,0,,the value of that operator, Dialogue: 0,0:57:32.73,0:57:33.52,EN,,0,0,0,,which, in this case, Dialogue: 0,0:57:33.55,0:57:35.44,EN,,0,0,0,,is going to be the primitive multiplier procedure, Dialogue: 0,0:57:36.44,0:57:37.93,EN,,0,0,0,,will end up in the FUN register. Dialogue: 0,0:57:43.02,0:57:44.53,EN,,0,0,0,,We're going to evaluate some arguments. Dialogue: 0,0:57:44.53,0:57:45.85,EN,,0,0,0,,They will evaluate n here. Dialogue: 0,0:57:47.73,0:57:49.87,EN,,0,0,0,,That'll give us 5, in this case. Dialogue: 0,0:57:50.25,0:57:52.04,EN,,0,0,0,,We're going to put that in the argl register, Dialogue: 0,0:57:53.00,0:57:55.88,EN,,0,0,0,,and then we'll go off to evaluate the second operand. Dialogue: 0,0:57:57.46,0:58:00.48,EN,,0,0,0,,So, at the point where we go off to evaluate the second operand-- Dialogue: 0,0:58:00.52,0:58:02.19,EN,,0,0,0,,and I'll skip details like computing, Dialogue: 0,0:58:02.20,0:58:03.58,EN,,0,0,0,,N minus 1, and all of that-- Dialogue: 0,0:58:03.71,0:58:05.88,EN,,0,0,0,,but, when we go off to evaluate the second operand, Dialogue: 0,0:58:06.62,0:58:10.44,EN,,0,0,0,,that will eventually reduce to another call to fact-recursive. Dialogue: 0,0:58:12.00,0:58:14.20,EN,,0,0,0,,And, what we've got on the stack here is Dialogue: 0,0:58:16.52,0:58:19.94,EN,,0,0,0,,the operator from that combination that we're going to use it in Dialogue: 0,0:58:20.12,0:58:21.07,EN,,0,0,0,,and the other argument. Dialogue: 0,0:58:23.40,0:58:27.61,EN,,0,0,0,,OK? So, now, we're set up for another call Dialogue: 0,0:58:28.49,0:58:29.69,EN,,0,0,0,,to recursive factorial. Dialogue: 0,0:58:30.20,0:58:31.43,EN,,0,0,0,,And, when we're done with this one, Dialogue: 0,0:58:31.56,0:58:33.64,EN,,0,0,0,,we're going to go to accumulate the last arg. Dialogue: 0,0:58:34.12,0:58:35.20,EN,,0,0,0,,and remember what that'll do? Dialogue: 0,0:58:35.20,0:58:35.93,EN,,0,0,0,,That'll say oh, Dialogue: 0,0:58:36.45,0:58:39.28,EN,,0,0,0,,whatever the result of this has to get combined with that, Dialogue: 0,0:58:39.28,0:58:40.40,EN,,0,0,0,,and we're going to multiply them. Dialogue: 0,0:58:41.69,0:58:42.38,EN,,0,0,0,,But, notice now, Dialogue: 0,0:58:42.73,0:58:44.81,EN,,0,0,0,,we're at another recursive factorial. Dialogue: 0,0:58:45.72,0:58:48.92,EN,,0,0,0,,We're about to call eval-dispatch again, Dialogue: 0,0:58:49.32,0:58:50.60,EN,,0,0,0,,except we haven't really reduced it Dialogue: 0,0:58:50.64,0:58:52.08,EN,,0,0,0,,because there's stuff on the stack now. Dialogue: 0,0:58:53.70,0:58:55.39,EN,,0,0,0,,The stuff on the stack says oh, when you get back, Dialogue: 0,0:58:55.40,0:58:57.52,EN,,0,0,0,,you'd better multiply it by the 5 you had hanging there. Dialogue: 0,0:58:58.43,0:59:05.77,EN,,0,0,0,,So, when we go off to make another call, Dialogue: 0,0:59:07.12,0:59:08.84,EN,,0,0,0,,we evaluate the n minus 1. Dialogue: 0,0:59:09.30,0:59:11.05,EN,,0,0,0,,That gives us another environment which Dialogue: 0,0:59:11.25,0:59:13.84,EN,,0,0,0,,in which the new n's going to be down to 4. Dialogue: 0,0:59:14.60,0:59:16.22,EN,,0,0,0,,And we're about to call eval-dispatch again. Dialogue: 0,0:59:19.20,0:59:20.22,EN,,0,0,0,,We get another call. Dialogue: 0,0:59:21.35,0:59:24.44,EN,,0,0,0,,That 4 is going to end up in the same situation. Dialogue: 0,0:59:26.04,0:59:28.62,EN,,0,0,0,,We'll end up with another call to fact-recursive n. Dialogue: 0,0:59:30.02,0:59:32.68,EN,,0,0,0,,And sitting on the stack will be the stuff from the original one Dialogue: 0,0:59:32.88,0:59:34.51,EN,,0,0,0,,and, now, the subsidiary one we're doing. Dialogue: 0,0:59:35.36,0:59:36.91,EN,,0,0,0,,And both of them are waiting for the same thing. Dialogue: 0,0:59:36.91,0:59:39.16,EN,,0,0,0,,They're going to go to accumulate a last argument. Dialogue: 0,0:59:40.51,0:59:42.94,EN,,0,0,0,,And then, of course, when we go to the fourth call, Dialogue: 0,0:59:43.25,0:59:44.38,EN,,0,0,0,,the same thing happens. Dialogue: 0,0:59:45.64,0:59:47.07,EN,,0,0,0,,And this goes on, and on, and on. Dialogue: 0,0:59:47.30,0:59:48.60,EN,,0,0,0,,And what you see here on the stack, Dialogue: 0,0:59:50.30,0:59:52.22,EN,,0,0,0,,exactly what's sitting here on the stack, Dialogue: 0,0:59:52.22,0:59:54.59,EN,,0,0,0,,the thing that says times and 5. Dialogue: 0,0:59:54.96,0:59:56.40,EN,,0,0,0,,And what you're going to do with that Dialogue: 0,0:59:56.59,0:59:58.54,EN,,0,0,0,,accumulate that into a last argument. Dialogue: 0,1:00:00.47,1:00:02.01,EN,,0,0,0,,That's exactly this, right? Dialogue: 0,1:00:02.01,1:00:04.75,EN,,0,0,0,,This is exactly where that stuff is hanging. Dialogue: 0,1:00:05.65,1:00:10.65,EN,,0,0,0,,Effectively, the operator you're going to apply, Dialogue: 0,1:00:11.72,1:00:14.30,EN,,0,0,0,,the other argument that it's got Dialogue: 0,1:00:14.32,1:00:15.79,EN,,0,0,0,,to be multiplied by when you get back Dialogue: 0,1:00:15.80,1:00:16.91,EN,,0,0,0,,and sort of the parentheses, Dialogue: 0,1:00:16.94,1:00:18.96,EN,,0,0,0,,which says yeah, what you wanted to do was accumulate them. Dialogue: 0,1:00:19.62,1:00:21.88,EN,,0,0,0,,So, you see, the substitution model is not such a lie. Dialogue: 0,1:00:22.56,1:00:23.63,EN,,0,0,0,,That really is, in some sense, Dialogue: 0,1:00:23.64,1:00:25.31,EN,,0,0,0,,what's sitting right on the stack. Dialogue: 0,1:00:29.37,1:00:30.40,EN,,0,0,0,,All right, so that, Dialogue: 0,1:00:30.81,1:00:32.48,EN,,0,0,0,,in some sense, should explain for you, Dialogue: 0,1:00:33.26,1:00:34.52,EN,,0,0,0,,or at least convince you, Dialogue: 0,1:00:35.93,1:00:38.72,EN,,0,0,0,,that somehow, this evaluator is managing Dialogue: 0,1:00:40.06,1:00:42.86,EN,,0,0,0,,to take these procedures and execute some of them iteratively Dialogue: 0,1:00:42.95,1:00:44.25,EN,,0,0,0,,and some of them recursively, Dialogue: 0,1:00:45.26,1:00:47.45,EN,,0,0,0,,even though, as syntactically, Dialogue: 0,1:00:47.45,1:00:49.05,EN,,0,0,0,,they look like recursive procedures. Dialogue: 0,1:00:49.40,1:00:50.64,EN,,0,0,0,,How's it managing to do that? Dialogue: 0,1:00:50.66,1:00:53.72,EN,,0,0,0,,Well, the basic reason it's managing to do that Dialogue: 0,1:00:53.80,1:00:55.68,EN,,0,0,0,,is the evaluator is set up Dialogue: 0,1:00:56.04,1:00:59.26,EN,,0,0,0,,to save only what it needs later. Dialogue: 0,1:01:01.09,1:01:04.25,EN,,0,0,0,,So, for example, at the point where you've reduced Dialogue: 0,1:01:04.67,1:01:07.39,EN,,0,0,0,,evaluating an expression and an environment Dialogue: 0,1:01:07.87,1:01:09.87,EN,,0,0,0,,to applying a procedure to some arguments, Dialogue: 0,1:01:10.52,1:01:12.49,EN,,0,0,0,,it doesn't need that original environment anymore Dialogue: 0,1:01:13.37,1:01:16.65,EN,,0,0,0,,because any environment stuff will be packaged inside the procedures Dialogue: 0,1:01:17.88,1:01:19.36,EN,,0,0,0,,where the application's going to happen. Dialogue: 0,1:01:20.75,1:01:21.61,EN,,0,0,0,,All right, similarly, Dialogue: 0,1:01:21.63,1:01:23.65,EN,,0,0,0,,when you're going along evaluating an argument list, Dialogue: 0,1:01:23.65,1:01:25.20,EN,,0,0,0,,when you've finished evaluating the list, Dialogue: 0,1:01:25.91,1:01:28.03,EN,,0,0,0,,when you're finished evaluating the last argument, Dialogue: 0,1:01:28.20,1:01:31.61,EN,,0,0,0,,you don't need that argument list any more, right? Dialogue: 0,1:01:31.63,1:01:32.94,EN,,0,0,0,,And you don't need the environment where Dialogue: 0,1:01:33.04,1:01:34.64,EN,,0,0,0,,those arguments would be evaluated. Dialogue: 0,1:01:36.69,1:01:40.89,EN,,0,0,0,,So the basic reason that this interpreter is being so smart Dialogue: 0,1:01:40.89,1:01:42.88,EN,,0,0,0,,is that it's not being smart at all, it's being stupid. Dialogue: 0,1:01:43.05,1:01:45.74,EN,,0,0,0,,It's just saying I'm only going to save what I really need. Dialogue: 0,1:01:48.70,1:01:51.00,EN,,0,0,0,,Well, let me show you here. Dialogue: 0,1:01:53.07,1:01:57.20,EN,,0,0,0,,Here's the actual thing that's making a tail recursive. Dialogue: 0,1:01:58.31,1:02:00.20,EN,,0,0,0,,Remember, it's the restore of continue. Dialogue: 0,1:02:00.22,1:02:06.94,EN,,0,0,0,,It's saying when I go off to evaluate the procedure body, Dialogue: 0,1:02:08.96,1:02:11.00,EN,,0,0,0,,I should tell eval to come back to Dialogue: 0,1:02:11.25,1:02:12.54,EN,,0,0,0,,the place where that original Dialogue: 0,1:02:12.54,1:02:14.25,EN,,0,0,0,,evaluation was supposed to come back to. Dialogue: 0,1:02:15.17,1:02:15.95,EN,,0,0,0,,So, in some sense, Dialogue: 0,1:02:16.17,1:02:18.84,EN,,0,0,0,,you want to say what's the actual line that makes tail recursive Dialogue: 0,1:02:18.89,1:02:19.44,EN,,0,0,0,,It's that one. Dialogue: 0,1:02:19.92,1:02:21.53,EN,,0,0,0,,If I wanted to build a non- Dialogue: 0,1:02:21.77,1:02:24.80,EN,,0,0,0,,tail recursive evaluator, for some strange reason, Dialogue: 0,1:02:25.69,1:02:26.86,EN,,0,0,0,,all I would need to do Dialogue: 0,1:02:27.12,1:02:29.29,EN,,0,0,0,,is, instead of restoring continue at this point, Dialogue: 0,1:02:30.06,1:02:31.66,EN,,0,0,0,,I'd set up a label down here Dialogue: 0,1:02:32.75,1:02:36.25,EN,,0,0,0,,called, "Where to come back after you've finished applying the procedure." Dialogue: 0,1:02:37.64,1:02:39.71,EN,,0,0,0,,Instead, I'd set continue to that. Dialogue: 0,1:02:39.92,1:02:41.21,EN,,0,0,0,,I'd go to eval-dispatch, Dialogue: 0,1:02:41.40,1:02:43.21,EN,,0,0,0,,and then eval-dispatch would come back here. Dialogue: 0,1:02:43.79,1:02:44.30,EN,,0,0,0,,At that point, Dialogue: 0,1:02:44.32,1:02:45.28,EN,,0,0,0,,I would restore continue Dialogue: 0,1:02:45.29,1:02:46.52,EN,,0,0,0,,and go to the original one. Dialogue: 0,1:02:47.92,1:02:51.00,EN,,0,0,0,,So here, the only consequence of that Dialogue: 0,1:02:51.15,1:02:52.68,EN,,0,0,0,,would be to make it non-tail recursive. Dialogue: 0,1:02:52.84,1:02:54.62,EN,,0,0,0,,It would give you exactly the same answers, Dialogue: 0,1:02:54.72,1:02:57.02,EN,,0,0,0,,except if you did that iterative factorial Dialogue: 0,1:02:57.05,1:02:58.36,EN,,0,0,0,,and all those iterative procedures, Dialogue: 0,1:02:58.60,1:02:59.80,EN,,0,0,0,,it would execute recursively. Dialogue: 0,1:03:03.04,1:03:05.40,EN,,0,0,0,,Well, I lied to you a little bit, but just a little bit, Dialogue: 0,1:03:05.76,1:03:06.99,EN,,0,0,0,,because I showed you a slightly Dialogue: 0,1:03:07.02,1:03:08.33,EN,,0,0,0,,over-simplified evaluator Dialogue: 0,1:03:08.72,1:03:10.38,EN,,0,0,0,,where it assumes that each procedure -- Dialogue: 0,1:03:11.36,1:03:13.66,EN,,0,0,0,,each procedure body has only one expression. Dialogue: 0,1:03:13.89,1:03:14.54,EN,,0,0,0,,Remember, in general, Dialogue: 0,1:03:14.56,1:03:16.57,EN,,0,0,0,,a procedure has a sequence of expressions in it. Dialogue: 0,1:03:17.87,1:03:20.49,EN,,0,0,0,,So there's nothing really conceptually new. Dialogue: 0,1:03:20.49,1:03:22.28,EN,,0,0,0,,Let me just show you the actual evaluator Dialogue: 0,1:03:22.89,1:03:24.73,EN,,0,0,0,,that handles sequences of expressions. Dialogue: 0,1:03:28.47,1:03:29.74,EN,,0,0,0,,This is compound-apply now, Dialogue: 0,1:03:29.74,1:03:31.31,EN,,0,0,0,,and the only difference from the old one Dialogue: 0,1:03:32.07,1:03:34.33,EN,,0,0,0,,is that, instead of going off to eval directly, Dialogue: 0,1:03:35.98,1:03:38.03,EN,,0,0,0,,it takes the whole body of the procedure, Dialogue: 0,1:03:38.03,1:03:40.15,EN,,0,0,0,,which, in this case, is a sequence of expressions, Dialogue: 0,1:03:40.28,1:03:41.71,EN,,0,0,0,,and goes off to eval-sequence. Dialogue: 0,1:03:42.60,1:03:45.32,EN,,0,0,0,,And eval-sequence is a little loop Dialogue: 0,1:03:46.83,1:03:49.98,EN,,0,0,0,,that, basically, does these evaluations one at a time. Dialogue: 0,1:03:52.63,1:03:53.85,EN,,0,0,0,,So it does an evaluation. Dialogue: 0,1:03:53.90,1:03:54.94,EN,,0,0,0,,Says oh, when I come back, Dialogue: 0,1:03:54.97,1:03:56.86,EN,,0,0,0,,I'd better come back here to do the next one. Dialogue: 0,1:03:58.44,1:03:59.29,EN,,0,0,0,,And, when I'm all done, Dialogue: 0,1:03:59.29,1:04:01.02,EN,,0,0,0,,when I want to get the last expression, Dialogue: 0,1:04:01.31,1:04:03.28,EN,,0,0,0,,I just restore my continue Dialogue: 0,1:04:03.92,1:04:05.28,EN,,0,0,0,,and go off to eval-dispatch. Dialogue: 0,1:04:06.41,1:04:08.20,EN,,0,0,0,,And, again, if you wanted for some reason Dialogue: 0,1:04:08.20,1:04:10.35,EN,,0,0,0,,to break tail recursion in this evaluator, Dialogue: 0,1:04:10.64,1:04:13.71,EN,,0,0,0,,all you need to do is not handle the last expression, especially. Dialogue: 0,1:04:14.90,1:04:17.34,EN,,0,0,0,,Just say, after you've done the last expression, Dialogue: 0,1:04:17.36,1:04:18.65,EN,,0,0,0,,come back to some other place Dialogue: 0,1:04:19.15,1:04:20.68,EN,,0,0,0,,after which you restore continue. Dialogue: 0,1:04:21.90,1:04:23.26,EN,,0,0,0,,And, for some reason, Dialogue: 0,1:04:23.26,1:04:25.74,EN,,0,0,0,,a lot of LISP evaluators tended to work that way. Dialogue: 0,1:04:26.55,1:04:28.44,EN,,0,0,0,,And the only consequence of that is that Dialogue: 0,1:04:28.86,1:04:30.72,EN,,0,0,0,,iterative procedures built up stack. Dialogue: 0,1:04:31.88,1:04:33.61,EN,,0,0,0,,And it's not clear why that happened. Dialogue: 0,1:04:35.92,1:04:37.98,EN,,0,0,0,,All right. Well, let me just sort of summarize, Dialogue: 0,1:04:38.09,1:04:39.60,EN,,0,0,0,,since this is a lot of details Dialogue: 0,1:04:39.98,1:04:41.04,EN,,0,0,0,,in a big program. Dialogue: 0,1:04:41.12,1:04:42.25,EN,,0,0,0,,But the main point is that Dialogue: 0,1:04:43.04,1:04:43.87,EN,,0,0,0,,it's no different, Dialogue: 0,1:04:44.04,1:04:46.08,EN,,0,0,0,,conceptually, from translating any other program. Dialogue: 0,1:04:47.06,1:04:48.06,EN,,0,0,0,,And the main idea is that Dialogue: 0,1:04:48.06,1:04:50.28,EN,,0,0,0,,we have this universal evaluator program, Dialogue: 0,1:04:50.33,1:04:51.71,EN,,0,0,0,,the meta-circular evaluator. Dialogue: 0,1:04:51.87,1:04:53.07,EN,,0,0,0,,If we translate that into LISP, Dialogue: 0,1:04:53.10,1:04:53.95,EN,,0,0,0,,then we have all of LISP. Dialogue: 0,1:04:54.33,1:04:55.15,EN,,0,0,0,,And that's all we did. Dialogue: 0,1:04:57.98,1:04:59.68,EN,,0,0,0,,The second point is that the magic's gone away. Dialogue: 0,1:04:59.68,1:05:01.97,EN,,0,0,0,,There should be no more magic in this whole system, right? Dialogue: 0,1:05:01.97,1:05:07.79,EN,,0,0,0,,In principle, it should all be very clear Dialogue: 0,1:05:07.82,1:05:10.08,EN,,0,0,0,,except, maybe, for how list structured memory works, Dialogue: 0,1:05:10.80,1:05:11.80,EN,,0,0,0,,and we'll see that later. Dialogue: 0,1:05:12.64,1:05:14.20,EN,,0,0,0,,But that's not very hard. Dialogue: 0,1:05:15.45,1:05:16.35,EN,,0,0,0,,The third point is that Dialogue: 0,1:05:16.35,1:05:17.52,EN,,0,0,0,,all this tail recursion Dialogue: 0,1:05:18.24,1:05:21.96,EN,,0,0,0,,came from the discipline of eval being very careful Dialogue: 0,1:05:22.55,1:05:24.51,EN,,0,0,0,,to save only what it needs next time. Dialogue: 0,1:05:25.87,1:05:27.72,EN,,0,0,0,,It's not some arbitrary thing Dialogue: 0,1:05:27.76,1:05:29.86,EN,,0,0,0,,where we're saying well, whenever we call a sub-routine, Dialogue: 0,1:05:29.86,1:05:32.16,EN,,0,0,0,,we'll save all the registers in the world and come back? Dialogue: 0,1:05:33.94,1:05:36.49,EN,,0,0,0,,See, sometimes it pays to really worry about efficiency. Dialogue: 0,1:05:37.15,1:05:39.96,EN,,0,0,0,,And, when you're down in the guts of your evaluator machine, Dialogue: 0,1:05:40.45,1:05:42.56,EN,,0,0,0,,it really pays to think about things like that Dialogue: 0,1:05:42.56,1:05:43.96,EN,,0,0,0,,because it makes big consequences. Dialogue: 0,1:05:45.23,1:05:47.69,EN,,0,0,0,,Well, I hope what this has done Dialogue: 0,1:05:47.90,1:05:52.30,EN,,0,0,0,,is really made the evaluator seem concrete. Dialogue: 0,1:05:52.56,1:05:53.90,EN,,0,0,0,,I hope you really believe Dialogue: 0,1:05:54.32,1:05:56.27,EN,,0,0,0,,that somebody could hold a LISP Dialogue: 0,1:05:56.84,1:05:58.56,EN,,0,0,0,,LISP evaluator in the palm of their hand. Dialogue: 0,1:05:59.07,1:06:00.49,EN,,0,0,0,,Maybe to help you believe that, here's a Dialogue: 0,1:06:00.80,1:06:01.96,EN,,0,0,0,,here's a LISP evaluator Dialogue: 0,1:06:02.54,1:06:04.06,EN,,0,0,0,,that I'm holding the palm of my hand. Dialogue: 0,1:06:06.16,1:06:10.56,EN,,0,0,0,,And this is a chip which is actually Dialogue: 0,1:06:10.89,1:06:13.70,EN,,0,0,0,,quite a bit more complicated than the evaluator I showed you. Dialogue: 0,1:06:16.86,1:06:19.20,EN,,0,0,0,,Uh.. maybe, here's a better picture of it. Dialogue: 0,1:06:22.07,1:06:22.57,EN,,0,0,0,,What there is, Dialogue: 0,1:06:22.60,1:06:24.38,EN,,0,0,0,,is you can see the same overall structure. Dialogue: 0,1:06:24.73,1:06:25.93,EN,,0,0,0,,This is a register array. Dialogue: 0,1:06:26.80,1:06:27.71,EN,,0,0,0,,These are the data paths. Dialogue: 0,1:06:27.72,1:06:29.07,EN,,0,0,0,,Here's a finite state controller. Dialogue: 0,1:06:29.80,1:06:31.04,EN,,0,0,0,,And again, finite state, Dialogue: 0,1:06:31.96,1:06:32.80,EN,,0,0,0,,that's all there is. Dialogue: 0,1:06:32.81,1:06:34.16,EN,,0,0,0,,And somewhere there's external memory Dialogue: 0,1:06:34.16,1:06:35.23,EN,,0,0,0,,that'll worry about things. Dialogue: 0,1:06:35.75,1:06:37.63,EN,,0,0,0,,And this particular one is very complicated Dialogue: 0,1:06:37.64,1:06:39.16,EN,,0,0,0,,because it's trying to run LISP fast. Dialogue: 0,1:06:39.66,1:06:42.97,EN,,0,0,0,,And it has some very, very fast parallel operations in there Dialogue: 0,1:06:43.07,1:06:46.32,EN,,0,0,0,,like, if you want to index into an array, Dialogue: 0,1:06:46.70,1:06:50.40,EN,,0,0,0,,simultaneously check that the index is an integer, Dialogue: 0,1:06:50.43,1:06:52.86,EN,,0,0,0,,check that it doesn't exceed the array bands, Dialogue: 0,1:06:53.04,1:06:55.02,EN,,0,0,0,,and go off and do the memory access, Dialogue: 0,1:06:55.05,1:06:56.70,EN,,0,0,0,,and do all those things simultaneously. Dialogue: 0,1:06:57.12,1:06:58.40,EN,,0,0,0,,And then, later, if they're all OK, Dialogue: 0,1:06:58.44,1:06:59.96,EN,,0,0,0,,actually get the value there. Dialogue: 0,1:07:00.42,1:07:02.46,EN,,0,0,0,,So there are a lot of complicated operations Dialogue: 0,1:07:02.48,1:07:04.65,EN,,0,0,0,,in these data paths for making LISP run in parallel. Dialogue: 0,1:07:05.26,1:07:08.41,EN,,0,0,0,,It's a completely non-risk Dialogue: 0,1:07:08.76,1:07:10.36,EN,,0,0,0,,philosophy of evaluating LISP. Dialogue: 0,1:07:10.64,1:07:13.20,EN,,0,0,0,,And then, this microcode is pretty complicated. Dialogue: 0,1:07:13.45,1:07:17.56,EN,,0,0,0,,Let's see, there's what? Dialogue: 0,1:07:17.60,1:07:21.10,EN,,0,0,0,,There's about 389 instructions of Dialogue: 0,1:07:21.68,1:07:23.85,EN,,0,0,0,,of 220-bit microcode sitting here Dialogue: 0,1:07:24.07,1:07:27.94,EN,,0,0,0,,because these are very complicated data paths. Dialogue: 0,1:07:27.94,1:07:32.25,EN,,0,0,0,,And the whole thing has about 89,000 transistors, OK? Dialogue: 0,1:07:33.56,1:07:36.86,EN,,0,0,0,,OK. Well, I hope that that takes away a lot of the mystery. Dialogue: 0,1:07:37.97,1:07:39.24,EN,,0,0,0,,Maybe somebody wants to look at this. Dialogue: 0,1:07:46.14,1:07:46.89,EN,,0,0,0,,OK. Let's stop. Dialogue: 0,1:07:56.46,1:07:56.75,EN,,0,0,0,,Questions? Dialogue: 0,1:07:59.00,1:08:00.42,EN,,0,0,0,,AUDIENCE: OK, now, it sounds like what you're saying is that, Dialogue: 0,1:08:00.42,1:08:03.48,EN,,0,0,0,,with the restore continue put in the proper place, Dialogue: 0,1:08:03.58,1:08:09.42,EN,,0,0,0,,that procedures that would invoke a recursive process Dialogue: 0,1:08:09.42,1:08:11.95,EN,,0,0,0,,now invoke an iterative process Dialogue: 0,1:08:12.67,1:08:15.36,EN,,0,0,0,,just by the way that the eval-sequence source? Dialogue: 0,1:08:15.60,1:08:17.54,EN,,0,0,0,,PROFESSOR: I think the way I'd prefer to put it is that, Dialogue: 0,1:08:17.54,1:08:19.82,EN,,0,0,0,,with restore continue put in the wrong place, Dialogue: 0,1:08:20.55,1:08:25.48,EN,,0,0,0,,you can cause any syntactically-looking recursive procedure, Dialogue: 0,1:08:25.52,1:08:27.28,EN,,0,0,0,,in fact, to build up stack as it runs. Dialogue: 0,1:08:28.64,1:08:30.52,EN,,0,0,0,,But there's no reason for that, Dialogue: 0,1:08:33.15,1:08:35.12,EN,,0,0,0,,so you might want to play around with it. Dialogue: 0,1:08:35.15,1:08:38.09,EN,,0,0,0,,You can just switch around two or three instructions Dialogue: 0,1:08:38.18,1:08:40.78,EN,,0,0,0,,in the way compound-apply comes back, Dialogue: 0,1:08:41.31,1:08:43.26,EN,,0,0,0,,and you'll get something which isn't tail recursive. Dialogue: 0,1:08:45.06,1:08:46.14,EN,,0,0,0,,But the thing I wanted to emphasize Dialogue: 0,1:08:46.16,1:08:47.40,EN,,0,0,0,,is there's no magic. there's no Dialogue: 0,1:08:47.67,1:08:48.57,EN,,0,0,0,,It's not as if Dialogue: 0,1:08:49.31,1:08:52.17,EN,,0,0,0,,there's some very clever pre-processing program Dialogue: 0,1:08:52.65,1:08:55.45,EN,,0,0,0,,that's looking at this procedure, factorial iter, Dialogue: 0,1:08:55.47,1:08:56.73,EN,,0,0,0,,and say oh, gee, um Dialogue: 0,1:08:57.42,1:08:58.86,EN,,0,0,0,,I really notice that Dialogue: 0,1:08:58.88,1:09:01.13,EN,,0,0,0,,I don't have to push stack in order to do this. Dialogue: 0,1:09:01.13,1:09:02.88,EN,,0,0,0,,Some people think that that's what's going on. Dialogue: 0,1:09:03.76,1:09:05.38,EN,,0,0,0,,It's something much, much more dumb than that, Dialogue: 0,1:09:05.38,1:09:07.50,EN,,0,0,0,,it's this one place you're putting the restore instruction. Dialogue: 0,1:09:08.56,1:09:09.79,EN,,0,0,0,,It's just automatic. Dialogue: 0,1:09:14.72,1:09:17.55,EN,,0,0,0,,AUDIENCE: But that's not affecting the time complexity is it? Dialogue: 0,1:09:17.58,1:09:17.87,EN,,0,0,0,,PROFESSOR: No. Dialogue: 0,1:09:18.60,1:09:21.77,EN,,0,0,0,,AUDIENCE: It's just that it's handling it recursively Dialogue: 0,1:09:21.80,1:09:23.02,EN,,0,0,0,,instead of iteratively. Dialogue: 0,1:09:23.02,1:09:27.34,EN,,0,0,0,,But, in terms of the order of time it takes to finish the operation, Dialogue: 0,1:09:27.37,1:09:29.22,EN,,0,0,0,,it's the same one way or the other, right? Dialogue: 0,1:09:29.47,1:09:29.76,EN,,0,0,0,,PROFESSOR: Yes. Dialogue: 0,1:09:29.79,1:09:32.68,EN,,0,0,0,,Tail recursion is not going to change the time complexity of anything Dialogue: 0,1:09:32.72,1:09:33.29,EN,,0,0,0,,because, in some sense, Dialogue: 0,1:09:33.34,1:09:35.15,EN,,0,0,0,,it's the same algorithm that's going on. Dialogue: 0,1:09:36.02,1:09:39.37,EN,,0,0,0,,What it's doing is really making this thing run as an iteration. Dialogue: 0,1:09:41.00,1:09:42.64,EN,,0,0,0,,Right? Not going to run out of memory Dialogue: 0,1:09:42.68,1:09:44.22,EN,,0,0,0,,you know counting up to a giant number Dialogue: 0,1:09:44.75,1:09:46.40,EN,,0,0,0,,simply because the stack would get pushed. Dialogue: 0,1:09:48.35,1:09:50.24,EN,,0,0,0,,See, the thing you really have to believe is that, Dialogue: 0,1:09:50.56,1:09:51.13,EN,,0,0,0,,when we write-- Dialogue: 0,1:09:51.64,1:09:53.78,EN,,0,0,0,,see, we've been writing all these things called iterations, Dialogue: 0,1:09:53.93,1:09:57.99,EN,,0,0,0,,infinite loops, define loop to be called loop. Dialogue: 0,1:10:00.32,1:10:03.36,EN,,0,0,0,,That's is as much an iteration Dialogue: 0,1:10:03.65,1:10:05.66,EN,,0,0,0,,you know as if we wrote do forever loop. Dialogue: 0,1:10:07.63,1:10:09.28,EN,,0,0,0,,It's just syntactic sugar as the difference. Dialogue: 0,1:10:09.28,1:10:11.32,EN,,0,0,0,,These things are real, honest to god, iterations? Dialogue: 0,1:10:14.73,1:10:16.08,EN,,0,0,0,,They don't change the time complexity, Dialogue: 0,1:10:16.11,1:10:18.53,EN,,0,0,0,,but they turn them into real iterations. Dialogue: 0,1:10:21.68,1:10:23.80,EN,,0,0,0,,All right, thank you. ================================================ FILE: Preface/pre1.txt ================================================ 心智的活动,除了尽力产生各种简单的认识之外,主要表现在如下三个方面:1)将若干简单认识组合为一个复合认识,由此产生出各种复杂的认识。2)将两个认识放在一起对照,不管它们如何简单或者复杂,在这样做时并不将它们合而为一。由此得到有关它们的相互关系的认识。3)将有关认识与那些在实际中和它们同在的所有其他认识隔离开,这就是抽象,所有具有普遍性的认识都是这样得到的。 John Locke, An Essay Concerning Human Understanding (有关人类理解的随笔,1690) The acts of the mind, wherein it exerts its power over simple ideas, are chiefly these three: 1. Combining several simple ideas into one compound one, and thus all complex ideas are made. 2. The second is bringing two ideas, whether simple or complex, together, and setting them by one another so as to take a view of them at once, without uniting them into one, by which it gets all its ideas of relations. 3. The third is separating them from all other ideas that accompany them in their real existence: this is called abstraction, and thus all its general ideas are made. John Locke, An Essay Concerning Human Understanding (1690) ================================================ FILE: Preface/pre2.txt ================================================ 现在到了数学抽象中最关键的一步:让我们忘记这些符号所表示的对象。……(数学家)不应在这里停步,有许多操作可以应用与这些符号,而根本不必考虑它们到底代表着什么东西。 Hermann Weyl, The Mathematical Way of Thinking (思维的数学方式) We now come to the decisive step of mathematical abstraction: we forget about what the symbols stand for. ...[The mathematician] need not be idle; there are many operations which he may carry out with these symbols, without ever having to look at the things they stand for. Hermann Weyl, The Mathematical Way of Thinking ================================================ FILE: Preface/pre3.txt ================================================ 即使在变化中,它也丝毫未变。 ——赫拉克立特(Heraclitus) 变得越多,它就越是原来的样子。 ——阿尔芬斯·卡尔(Alphonse Karr) (Even while it changes, it stands still.) Heraclitus Plus ça change, plus c'est la même chose. Alphonse Karr ================================================ FILE: Preface/pre4.txt ================================================ 用普通的话来说,这个咒语就是——阿巴拉卡达巴拉,芝麻开门,而且还有另外的东西——在一个故事里的咒语在另一故事里就不灵了。真正的魔力在于知道哪个咒语有用,在什么时候,用于做什么,其诀窍就在于学会有关的诀窍。 而这些咒语也是用我们的字母表里的字母拼出来的,这个字母表中不过是几十个可以用笔画出来的弯弯曲线。这就是最关键的!而那些珍宝也是如此,如果我们能将它们拿到手中的话!这就像是说,就像通向珍宝的钥匙就是珍宝! ——John Barth, Chimera(奇想) ... It's in words that the magic is -- Abracadabra, Open Sesame, and the rest -- but the magic words in one story aren't magical in the next. The real magic is to understand which words work, and when, and for what; the trick is to learn the trick. ... And those words are made from the letters of our alphabet: a couple-dozen squiggles we can draw with the pen. This is the key! And the treasure, too, if we can only get our hands on it! It's as if -- as if the key to the treasure is the treasure! John Barth, Chimera ================================================ FILE: Preface/pre5.txt ================================================ 我的目的是想说明,这一天空机器并不是一种天赐造物或者生命体,它只不过是钟表一类的机械装置(而那些相信钟表有灵魂的人却将这一工作说成是其创造者的荣耀),在很大程度上,这里多种多样的运动都是由最简单的物质力量产生的,就像钟表里所有活动都是由一个发条产生的一样。 ——约翰尼斯·开普勒(给Herwart von Hohenburg的信,1605) My aim is to show that the heavenly machine is not a kind of divine, live being, but a kind of clockwork (and he who believes that a clock has soul attributes the maker's glory to the work), insofar as nearly all the manifold motions are caused by a most simple and material force, just as all motions of the clock are caused by a single weight. Johannes Kepler (letter to Herwart von Hohenburg, 1605) ================================================ FILE: README.md ================================================ # 《计算机程序的结构和解释》公开课 翻译项目 MIT OCW [MIT OpenCourseWare](https://ocw.mit.edu/index.htm)      HIT IBMTC [哈尔滨工业大学 IBM技术中心](https://github.com/HIT-IBMTC)      HIT PT [哈尔滨工业大学 清影PT](https://hitpt.org/index.php)

SICP

《计算机程序的构造和解释》系列公开课,视频是两位作者(Harold Abelson、Gerald Jay Sussman)在1986年7月给**Hewlett-Packard**公司员工培训时的录像。你可以在[这里](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/)获得这门课程的视频。 这门课程只提供了英文字幕,本项目旨在将这些英文字幕翻译为中文,方便广大的`Scheme/Lisp`学习者。 ## 教辅资料 这里收集了一些有用的学习资料,包括SICP原书、Scheme新手教程、教学环境搭建、相关拓展习题等资料。 | 教学辅导 | 环境配置 | 深入阅读 | | ------- | ------ | ------- | | [SICP原书全文·英文](https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book.html) |[MIT Scheme基本使用](http://www.math.pku.edu.cn/teachers/qiuzy/progtech/scheme/mit_scheme.htm)|[程序设计语言理论资料汇编](https://steshaw.org/plt/) | | [SICP原书PDF版·英文](https://github.com/sarabander/sicp-pdf) | [PLT Scheme的基本使用](http://www.math.pku.edu.cn/teachers/qiuzy/progtech/scheme/plt_scheme.htm) | [程序设计语言研究资料](http://www.cs.cmu.edu/afs/cs.cmu.edu/user/mleone/web/language-research.html) | | [Scheme入门教程·中文](https://github.com/DeathKing/yast-cn) | [DrRacket 的安装与配置](https://zhuanlan.zhihu.com/p/37056659) | [程序设计语言与逻辑研究领域经典论文](http://www.cs.cmu.edu/~crary/819-f09/) | | [MIT 6.945/6.905 课程作业](http://groups.csail.mit.edu/mac/users/gjs/6.945/assignments.html) | [Racket 常见问题](https://syntacticlosure.github.io/) | [Oleg's FTP](http://okmij.org/ftp/) | SICP的习题解答可参考 SchemeWiki 的 [SICP Solutions](http://community.schemewiki.org/?SICP-Solutions) 页面。如果您在学习过程中遇到任何疑问,欢迎使用 [Issues](https://github.com/DeathKing/Learning-SICP/issues) 功能提问。 ## 视频地址
🏠 主页
🎥 播放列表 优酷 YouTube BiliBili AcFun
📂 网盘 百度网盘 Google Drive
> **注意** > * 由于 MKV 格式的视频文件需要额外安装字幕,我们不再提供 MKV 格式的视频; > * 中国大陆以外的用户,可尝试通过Google Drive下载以获得更高的下载速度。 | 编号 | 标题 | 下载地址 | 译者 | | ---- | ---- |:-----------------------:| ---- | | Lec1a | 《Lisp概览》 | [ [优酷] ](https://v.youku.com/v_show/id_XNTEzMDAyMTU2.html) [ [YouTube] ](https://youtu.be/IcZSFewqr9k) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=1) [ [MP4] ](https://pan.baidu.com/s/109WuY4ONSZddFXyE2hQGwg) | [DeathKing](https://github.com/DeathKing) | | Lec1b | 《计算过程》 | [ [优酷] ](https://v.youku.com/v_show/id_XNTMxODY1NTg4.html) [ [YouTube] ](https://youtu.be/WuK9NmA3aq0) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=2) [ [MP4] ](https://pan.baidu.com/s/1C3muRwhMdK8yioHWw5P-1Q) | [ChingfanTsou](https://github.com/ChingfanTsou) | | Lec2a | 《高阶过程》 | [ [优酷] ](https://v.youku.com/v_show/id_XNzAzNjI1NjU2.html) [ [YouTube] ](https://youtu.be/mrgcGvOI1bs) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=3) [ [MP4] ](https://pan.baidu.com/s/1MHiHVHfwq6x8rylBVDGV0A) | [endyul](https://github.com/endyul) | | Lec2b | 《复合数据》 | [ [优酷] ](https://v.youku.com/v_show/id_XNzAzNjg4Mjk2.html) [ [YouTube] ](https://youtu.be/ufTdeiz9dMw) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=4) [ [MP4] ](https://pan.baidu.com/s/1DfX7DJ_pMd7AtMlJwqyoRg) | [DeathKing](https://github.com/DeathKing) | | Lec3a | 《Henderson-Escher的例子》 | [ [优酷] ](https://v.youku.com/v_show/id_XODk4NjUwODMy.html) [ [YouTube] ](https://youtu.be/YCR03O5EUdI) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=5) [ [MP4] ](https://pan.baidu.com/s/1bOJvDO) | [DeathKing](https://github.com/DeathKing), [Michael Savior](https://github.com/mut0u) | | Lec3b | 《符号化求导系统:引用》 | [ [优酷] ](https://v.youku.com/v_show/id_XODk4NjUwODA0.html) [ [YouTube] ](https://youtu.be/cgGbiMptQM0) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=6) [ [MP4] ](https://pan.baidu.com/s/1mhS2EV2) | [DeathKing](https://github.com/DeathKing) | | Lec4a | 《模式匹配:基于规则的代换》 | [ [优酷] ](https://v.youku.com/v_show/id_XMTM4NTY5NzE3Ng.html) [ [YouTube] ](https://youtu.be/zSxepaPtNQY) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=7) [ [MP4] ](https://pan.baidu.com/s/1U9E33yRr5mIqrdTOjnJeGA) | [DeathKing](https://github.com/DeathKing), [Michael Savior](https://github.com/mut0u) | | Lec4b | 《通用运算符》 | [ [优酷] ](https://v.youku.com/v_show/id_XMTQ3NDEwODUyNA==.html) [ [YouTube] ](https://youtu.be/RlfZridRcw0) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=8) [ [MP4] ](https://pan.baidu.com/s/1vAv8Hi46f9ku2y7LHPpzzw) | [rtmagic](https://github.com/rtmagic) | | Lec5a | 《赋值,状态和副作用》 | [ [优酷] ](https://v.youku.com/v_show/id_XMTczMjIxNTM2NA==.html) [ [YouTube] ](https://youtu.be/ozss6dvq7ZU) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=9) [ [MP4] ](https://pan.baidu.com/s/1boWiMWB) | [Windfarer](https://github.com/Windfarer) | | Lec5b | 《计算对象》 | [ [优酷] ](https://v.youku.com/v_show/id_XMjY0NzE3NzQ2MA==.html) [ [YouTube] ](https://youtu.be/2Iz7agtk614) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=10) [ [MP4] ](https://pan.baidu.com/s/1c1FRLIg) | [DreamAndDead](https://github.com/DreamAndDead) | | Lec6a | 《流 I》 | [ [优酷] ](https://v.youku.com/v_show/id_XMjg4NTkwNzU3Ng==.html) [ [YouTube] ](https://youtu.be/z7jvvATswFE) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=11) [ [MP4] ](https://pan.baidu.com/s/1pLlvcLH) | [DreamAndDead](https://github.com/DreamAndDead) | | Lec6b | 《流 II》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzAyMjI0MjAzNg==.html) [ [YouTube] ](https://youtu.be/0lQ6fThLhYw) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=12) [ [MP4] ](https://pan.baidu.com/s/1b3kbWq) | [DreamAndDead](https://github.com/DreamAndDead) | | Lec7a | 《元循环求值器 I》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzAzODg2ODczNg==.html) [ [YouTube] ](https://youtu.be/RXUqgWJES0w) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=13) [ [MP4] ](https://pan.baidu.com/s/1kV1M0ab) | [DeathKing](https://github.com/DeathKing), [DreamAndDead](https://github.com/DreamAndDead) | | Lec7b | 《元循环求值器 II》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzA2NDQ5MjkxMg==.html) [ [YouTube] ](https://youtu.be/HNaAEv8Xjx8) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=14) [ [MP4] ](https://pan.baidu.com/s/1qYBgrIO) | [DeathKing](https://github.com/DeathKing), [DreamAndDead](https://github.com/DreamAndDead) | | Lec8a | 《逻辑式程序设计 I》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzIyODg0NTEwNA==.html) [ [YouTube] ](https://youtu.be/VNH95lmCHdE) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=15) [ [MP4] ](https://pan.baidu.com/s/1dFlOqrB) | [DeathKing](https://github.com/DeathKing) | | Lec8b | 《逻辑式程序设计 II》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzQ4MDA1OTE3Mg==.html) [ [YouTube] ](https://youtu.be/mcik1gEEyqA) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=16) [ [MP4] ](https://pan.baidu.com/s/1MN5ZDrnnKeE0XeMqAY6x0Q) | [DeathKing](https://github.com/DeathKing) | | Lec9a | 《寄存机器》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzU3MzA5Mzg0OA==.html) [ [YouTube] ](https://youtu.be/oR2PwG0xh_g) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=17) [ [MP4] ](https://pan.baidu.com/s/1AFM6__x4oGq3XtI_fa3ZGQ) | [DeathKing](https://github.com/DeathKing) | | Lec9b | 《显式控制求值器》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzcxMDAzMTA1Mg==.html) [ [YouTube] ](https://youtu.be/mrRcB4uY75M) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=18) [ [MP4] ](https://pan.baidu.com/s/1bHhuJdEQyE9Fyw06Y6tOZw) | [DeathKing](https://github.com/DeathKing), [rtmagic](https://github.com/rtmagic) | | Lec10a | 《编译》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzYyNTcxNDYwOA==.html) [ [YouTube] ](https://youtu.be/vBEkYVrtfBE) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=19) [ [MP4] ](https://pan.baidu.com/s/1IWkeR7gM5jiVFPMVhdZ4fg) | [Windfarer](https://github.com/Windfarer) | | Lec10b | 《存储分配与垃圾收集》 | [ [优酷] ](https://v.youku.com/v_show/id_XMzc3NjI4MzQ4NA==.html) [ [YouTube] ](https://youtu.be/HNjPAzmSho8) [ [bilibili] ](https://www.bilibili.com/video/av8515129?p=20) [ [MP4] ](https://pan.baidu.com/s/1LKoXNWFD9lFclgNKeCBxsg) | [Windfarer](https://github.com/Windfarer) | ## 加入我们 + Learning-SICP 主群:97747648 + Learning-SICP 2 群:573877085 (加群请注明理由,否则一概拒绝) ## 声明与致谢 我们由衷感谢 Harold Abelson 及 Gerald Jay Sussman 教授为我们讲授这一门公开课,感谢 [MIT OCW](http://ocw.mit.edu ) 项目允许我们以 Creative Commons 的方式分发本课的中译版本,以下是原课中的许可与声明。 > http://ocw.mit.edu > License: Creative Commons Attribution-Noncommercial-Share Alike. > `Eric Grimson`, `Peter Szolovits`, and `Trevor Darrell`, > 6.001 Structure and Interpretation of Computer Programs, Spring 2005. > (Massachusetts Institute of Technology: MIT OpenCourseWare). ================================================ FILE: SrtCN/lec10a.eng.srt ================================================ 1 00:00:05,580 --> 00:00:20,180 [MUSIC PLAYING] 2 00:00:20,180 --> 00:00:36,640 PROFESSOR: Last time, we took a look at an explicit control evaluator for Lisp, and that bridged the gap between all these high-level languages like Lisp and the query language and all of that stuff, bridged the gap between that and a conventional register machine. 3 00:00:36,640 --> 00:00:55,340 And in fact, you can think of the explicit control evaluator either as, say, the code for a Lisp interpreter if you wanted to implement it in the assembly language of some conventional register transfer machine, or, if you like, you can think of it as the microcode of some machine that's going to be specially designed to run Lisp. 4 00:00:55,340 --> 00:01:08,230 In either case, what we're doing is we're taking a machine that speaks some low-level language, and we're raising the machine to a high-level language like Lisp by writing an interpreter. 5 00:01:08,230 --> 00:01:23,910 So for instance, here, conceptually, is a special purpose machine for computing factorials. 6 00:01:23,910 --> 00:01:29,000 It takes in five and puts out 120. 7 00:01:29,000 --> 00:01:42,410 And what this special purpose machine is is actually a Lisp interpreter that's configured itself to run factorials, because you fit into it a description of the factorial machine. 8 00:01:42,410 --> 00:01:43,610 So that's what an interpreter is. 9 00:01:43,610 --> 00:01:50,120 It configures itself to emulate a machine whose description you read in. 10 00:01:50,120 --> 00:01:52,110 Now, inside the Lisp interpreter, what's that? 11 00:01:52,110 --> 00:02:03,410 Well, that might be your general register language interpreter that configures itself to behave like a Lisp interpreter, because you put in a whole bunch of instructions in register language. 12 00:02:03,410 --> 00:02:07,070 This is the explicit control evaluator. 13 00:02:07,070 --> 00:02:12,780 And then it also has some sort of library, a library of primitive operators and Lisp operations and all sorts of things like that. 14 00:02:12,780 --> 00:02:17,350 That's the general strategy of interpretation. 15 00:02:17,350 --> 00:02:25,430 And the point is, what we're doing is we're writing an interpreter to raise the machine to the level of the programs that we want to write. 16 00:02:25,430 --> 00:02:29,030 Well, there's another strategy, a different one, which is compilation. 17 00:02:29,030 --> 00:02:31,090 Compilation's a little bit different. 18 00:02:31,090 --> 00:02:47,870 Here--here we might have produced a special purpose machine for, for computing factorials, starting with some sort of machine that speaks register language, except we're going to do a different strategy. 19 00:02:47,870 --> 00:02:51,680 We take our factorial program. 20 00:02:51,680 --> 00:02:53,780 We use that as the source code into a compiler. 21 00:02:53,780 --> 00:02:59,926 What the compiler will do is translate that factorial program into some register machine language. 22 00:02:59,926 --> 00:03:06,760 And this will now be not the explicit control evaluator for Lisp, this will be some register language for computing factorials. 23 00:03:06,760 --> 00:03:10,460 So this is the translation of that. 24 00:03:10,460 --> 00:03:19,970 That will go into some sort of loader which will combine this code with code selected from the library to do things like primitive multiplication. 25 00:03:19,970 --> 00:03:28,320 And then we'll produce a load module which configures the register language machine to be a special purpose factorial machine. 26 00:03:28,320 --> 00:03:29,905 So that's a, that's a different strategy. 27 00:03:29,905 --> 00:03:35,360 In interpretation, we're raising the machine to the level of our language, like Lisp. 28 00:03:35,360 --> 00:03:42,040 In compilation, we're taking our program and lowering it to the language that's spoken by the machine. 29 00:03:42,040 --> 00:03:44,280 Well, how do these two strategies compare? 30 00:03:44,280 --> 00:03:50,140 The compiler can produce code that will execute more efficiently. 31 00:03:52,490 --> 00:04:10,260 The essential reason for that is that if you think about the register operations that are running, the interpreter has to produce register operations which, in principle, are going to be general enough to execute any Lisp procedure. 32 00:04:10,260 --> 00:04:20,209 Whereas the compiler only has to worry about producing a special bunch of register operations for, for doing the particular Lisp procedure that you've compiled. 33 00:04:20,209 --> 00:04:31,160 Or another way to say that is that the interpreter is a general purpose simulator, that when you read in a Lisp procedure, then those can simulate the program described by that, by that procedure. 34 00:04:31,160 --> 00:04:40,000 So the interpreter is worrying about making a general purpose simulator, whereas the compiler, in effect, is configuring the thing to be the machine that the interpreter would have been simulating. 35 00:04:40,000 --> 00:04:41,340 So the compiler can be faster. 36 00:04:52,830 --> 00:04:59,340 On the other hand, the interpreter is a nicer environment for debugging. 37 00:04:59,340 --> 00:05:02,960 And the reason for that is that we've got the source code actually there. 38 00:05:02,960 --> 00:05:03,740 We're interpreting it. 39 00:05:03,740 --> 00:05:06,010 That's what we're working with. 40 00:05:06,010 --> 00:05:07,880 And we also have the library around. 41 00:05:07,880 --> 00:05:11,140 See, the interpreter--the library sitting there is part of the interpreter. 42 00:05:11,140 --> 00:05:14,830 The compiler only pulls out from the library what it needs to run the program. 43 00:05:14,830 --> 00:05:29,670 So if you're in the middle of debugging, and you might like to write a little extra program to examine some run time data structure or to produce some computation that you didn't think of when you wrote the program, the interpreter can do that perfectly well, whereas the compiler can't. 44 00:05:29,670 --> 00:05:31,850 So there are sort of dual, dual advantages. 45 00:05:31,850 --> 00:05:34,720 The compiler will produce code that executes faster. 46 00:05:34,720 --> 00:05:39,030 The interpreter is a better environment for debugging. 47 00:05:39,030 --> 00:05:46,930 And most Lisp systems end up having both, end up being configured so you have an interpreter that you use when you're developing your code. 48 00:05:46,930 --> 00:05:49,060 Then you can speed it up by compiling. 49 00:05:49,060 --> 00:05:54,810 And very often, you can arrange that compiled code and interpreted code can call each other. 50 00:05:54,810 --> 00:05:55,700 We'll see how to do that. 51 00:05:55,700 --> 00:05:56,950 That's not hard. 52 00:06:01,040 --> 00:06:14,320 In fact, the way we'll-- in the compiler we're going to make, the way we'll arrange for compiled coding and interpreted code to call, to call each other, is that we'll have the compiler use exactly the same register conventions as the interpreter. 53 00:06:18,680 --> 00:06:25,490 Well, the idea of a compiler is very much like the idea of an interpreter or evaluator. 54 00:06:25,490 --> 00:06:27,070 It's the same thing. 55 00:06:27,070 --> 00:06:33,840 See, the evaluator walks over the code and performs some register operations. 56 00:06:33,840 --> 00:06:37,040 That's what we did yesterday. 57 00:06:37,040 --> 00:06:48,890 Well, the compiler essentially would like to walk over the code and produce the register operations that the evaluator would have done were it evaluating the thing. 58 00:06:48,890 --> 00:06:58,330 And that gives us a model for how to implement a zeroth-order compiler, a very bad compiler but essentially a compiler. 59 00:06:58,330 --> 00:07:07,550 A model for doing that is you just take the evaluator, you run it over the code, but instead of executing the actual operations, you just save them away. 60 00:07:07,550 --> 00:07:08,820 And that's your compiled code. 61 00:07:08,820 --> 00:07:10,140 So let me give you an example of that. 62 00:07:15,130 --> 00:07:18,010 Suppose we're going to compile--suppose we want to compile the expression f of x. 63 00:07:25,100 --> 00:07:30,170 So let's assume that we've got f of x in the x register and something in the environment register. 64 00:07:30,170 --> 00:07:31,745 And now imagine starting up the evaluator. 65 00:07:34,560 --> 00:07:38,000 Well, it looks at the expression and it sees that it's an application. 66 00:07:38,000 --> 00:07:44,980 And it branches to a place in the evaluator code we saw called ev-application. 67 00:07:47,230 --> 00:07:48,190 And then it begins. 68 00:07:48,190 --> 00:07:54,410 It stores away the operands and unev, and then it's going to put the operator in exp, and it's going to go recursively evaluate it. 69 00:07:54,410 --> 00:07:56,385 That's the process that we walk through. 70 00:07:56,385 --> 00:08:00,200 And if you start looking at the code, you start seeing some register operations. 71 00:08:00,200 --> 00:08:06,770 You see assign to unev the operands, assign to exp the operator, save the environment, generate that, and so on. 72 00:08:10,310 --> 00:08:20,860 Well, if we look on the overhead here, we can see, we can see those operations starting to be produced. 73 00:08:20,860 --> 00:08:24,910 Here's sort of the first real operation that the evaluator would have done. 74 00:08:24,910 --> 00:08:34,740 It pulls the operands out of the exp register and assigns it to unev. And then it assigns something to the expression register, and it saves continue, and it saves env. 75 00:08:34,740 --> 00:08:42,010 And all I'm doing here is writing down the register assignments that the evaluator would have done in executing that code. 76 00:08:42,010 --> 00:08:44,280 And can zoom out a little bit. 77 00:08:44,280 --> 00:08:49,430 Altogether, there are about 19 operations there. 78 00:08:49,430 --> 00:08:57,940 And this is the--this will be the piece of code up until the point where the evaluator branches off to apply-dispatch. 79 00:08:57,940 --> 00:09:01,450 And in fact, in this compiler, we're not going to worry about apply-dispatch at all. 80 00:09:01,450 --> 00:09:06,160 We're going to have everything--we're going to have both interpreted code and compiled code. 81 00:09:06,160 --> 00:09:10,240 Always evaluate procedures, always apply procedures by going to apply-dispatch. 82 00:09:10,240 --> 00:09:13,970 That will easily allow interpreted code and compiled code to call each other. 83 00:09:18,330 --> 00:09:21,220 Well, in principle, that's all we need to do. 84 00:09:21,220 --> 00:09:22,620 You just run the evaluator. 85 00:09:22,620 --> 00:09:24,320 So the compiler's a lot like the evaluator. 86 00:09:24,320 --> 00:09:29,480 You run it, except it stashes away these operations instead of actually executing them. 87 00:09:29,480 --> 00:09:32,680 Well, that's not, that's not quite true. 88 00:09:32,680 --> 00:09:36,370 There's only one little lie in that. 89 00:09:36,370 --> 00:09:40,480 What you have to worry about is if you have a, a predicate. 90 00:09:40,480 --> 00:09:51,400 If you have some kind of test you want to do, obviously, at the point when you're compiling it, you don't know which branch of these--of a conditional like this you're going to do. 91 00:09:51,400 --> 00:09:55,010 So you can't say which one the evaluator would have done. 92 00:09:55,010 --> 00:09:57,190 So all you do there is very simple. 93 00:09:57,190 --> 00:09:58,985 You compile both branches. 94 00:09:58,985 --> 00:10:02,050 So you compile a structure that looks like this. 95 00:10:02,050 --> 00:10:18,140 That'll compile into something that says, the code, the code for P. And it puts its results in, say, the val register. 96 00:10:18,140 --> 00:10:24,770 So you walk the interpreter over the predicate and make sure that the result would go into the val register. 97 00:10:24,770 --> 00:10:38,670 And then you compile an instruction that says, branch if, if val is true, to a place we'll call label one. 98 00:10:44,950 --> 00:11:04,920 Then we, we will put the code for B to walk the interpreter--walk the interpreter over B. And then go to put in an instruction that says, go to the next thing, whatever, whatever was supposed to happen after this thing was done. 99 00:11:04,920 --> 00:11:06,900 You put in that instruction. 100 00:11:06,900 --> 00:11:08,280 And here you put label one. 101 00:11:11,521 --> 00:11:25,870 And here you put the code for A. And you put go to next thing. 102 00:11:31,420 --> 00:11:33,090 So that's how you treat a conditional. 103 00:11:33,090 --> 00:11:35,890 You generate a little block like that. 104 00:11:35,890 --> 00:11:42,310 And other than that, this zeroth-order compiler is the same as the evaluator. 105 00:11:42,310 --> 00:11:46,380 It's just stashing away the instructions instead of executing them. 106 00:11:46,380 --> 00:11:50,120 That seems pretty simple, but we've gained something by that. 107 00:11:50,120 --> 00:11:53,630 See, already that's going to be more efficient than the evaluator. 108 00:11:53,630 --> 00:12:04,740 Because, if you watch the evaluator run, it's not only generating the register operations we wrote down, it's also doing things to decide which ones to generate. 109 00:12:04,740 --> 00:12:16,780 So the very first thing it does, say, here for instance, is go do some tests and decide that this is an application, and then branch off to the place that, that handles applications. 110 00:12:16,780 --> 00:12:25,580 In other words, what the evaluator's doing is simultaneously analyzing the code to see what to do, and running these operations. 111 00:12:25,580 --> 00:12:34,900 And when you-- if you run the evaluator a million times, that analysis phase happens a million times, whereas in the compiler, it's happened once, and then you just have the register operations themselves. 112 00:12:39,730 --> 00:12:44,550 Ok, that's a, a zeroth-order compiler, but it is a wretched, wretched compiler. 113 00:12:44,550 --> 00:12:47,200 It's really dumb. 114 00:12:47,200 --> 00:12:52,040 Let's--let's go back and, and look at this overhead. 115 00:12:52,040 --> 00:12:56,020 So look at look at some of the operations this thing is doing. 116 00:12:56,020 --> 00:13:03,710 We're supposedly looking at the operations and interpreting f of x. 117 00:13:03,710 --> 00:13:05,220 Now, look here what it's doing. 118 00:13:05,220 --> 00:13:13,850 For example, here it assigns to exp the operator in fetch of exp. 119 00:13:13,850 --> 00:13:23,310 But see, there's no reason to do that, because this is-- the compiler knows that the operator, fetch of exp, is f right here. 120 00:13:23,310 --> 00:13:25,850 So there's no reason why this instruction should say that. 121 00:13:25,850 --> 00:13:29,580 It should say, we'll assign to exp, f. 122 00:13:29,580 --> 00:13:32,000 Or in fact, you don't need exp at all. 123 00:13:32,000 --> 00:13:33,670 There's no reason it should have exp at all. 124 00:13:33,670 --> 00:13:35,170 What, what did exp get used for? 125 00:13:35,170 --> 00:13:48,620 Well, if we come down here, we're going to assign to val, look up the stuff in exp in the environment. 126 00:13:48,620 --> 00:13:58,850 So what we really should do is get rid of the exp register altogether, and just change this instruction to say, assign to val, look up the variable value of the symbol f in the environment. 127 00:14:01,100 --> 00:14:09,150 Similarly, back up here, we don't need unev at all, because we know what the operands of fetch of exp are for this piece of code. 128 00:14:09,150 --> 00:14:10,630 It's the, it's the list x. 129 00:14:13,270 --> 00:14:19,660 So in some sense, you don't want unev and exp at all. 130 00:14:19,660 --> 00:14:25,230 See, what they really are in some sense, those aren't registers of the actual machine that's supposed to run. 131 00:14:25,230 --> 00:14:30,760 Those are registers that have to do with arranging the thing that can simulate that machine. 132 00:14:30,760 --> 00:14:39,510 So they're always going to hold expressions which, from the compiler's point of view, are just constants, so can be put right into the code. 133 00:14:39,510 --> 00:14:44,000 So you can forget about all the operations worrying about exp and unev and just use those constants. 134 00:14:44,000 --> 00:14:50,510 Similarly, again, if we go, go back and look here, there are things like assign to continue eval-args. 135 00:14:53,890 --> 00:14:55,440 Now, that has nothing to do with anything. 136 00:14:55,440 --> 00:15:06,920 That was just the evaluator keeping track of where it should go next, to evaluate the arguments in some, in some application. 137 00:15:06,920 --> 00:15:15,220 But of course, that's irrelevant to the compiler, because you-- the analysis phase will have already done that. 138 00:15:15,220 --> 00:15:17,680 So this is completely irrelevant. 139 00:15:17,680 --> 00:15:26,120 So a lot of these, these assignments to continue have not to do where the running machine is supposed to continue in keeping track of its state. 140 00:15:26,120 --> 00:15:30,080 It has to, to do with where the evaluator analysis should continue, and those are completely irrelevant. 141 00:15:30,080 --> 00:15:31,330 So we can get rid of them. 142 00:15:44,330 --> 00:16:08,540 Ok, well, if we, if we simply do that, make those kinds of optimizations, get rid, get rid of worrying about exp and unev, and get rid of these irrelevant register assignments to continue, then we can take this literal code, these sort of 19 instructions that the, that the evaluator would have done, and then replace them. 143 00:16:08,540 --> 00:16:09,865 Let's look at the, at the slide. 144 00:16:13,490 --> 00:16:15,180 Replace them by--we get rid of about half of them. 145 00:16:18,370 --> 00:16:25,200 And again, this is just sort of filtering what the evaluator would have done by getting rid of the irrelevant stuff. 146 00:16:25,200 --> 00:16:35,470 And you see, for instance, here the--where the evaluator said, assign val, look up variable value, fetch of exp, here we have put in the constant f. 147 00:16:35,470 --> 00:16:37,020 Here we've put in the constant x. 148 00:16:39,770 --> 00:16:43,860 So there's a, there's a little better compiler. 149 00:16:43,860 --> 00:16:47,930 It's still pretty dumb. 150 00:16:47,930 --> 00:16:50,560 It's still doing a lot of dumb things. 151 00:16:50,560 --> 00:17:03,430 Again, if we go look at the slide again, look at the very beginning here, we see a save the environment, assign something to the val register, and restore the environment. 152 00:17:03,430 --> 00:17:05,030 Where'd that come from? 153 00:17:05,030 --> 00:17:11,160 That came from the evaluator back here saying, oh, I'm in the middle of evaluating an application. 154 00:17:11,160 --> 00:17:15,940 So I'm going to recursively call eval dispatch. 155 00:17:15,940 --> 00:17:19,849 So I'd better save the thing I'm going to need later, which is the environment. 156 00:17:19,849 --> 00:17:23,520 This was the result of recursively calling eval dispatch. 157 00:17:23,520 --> 00:17:26,540 It was evaluating the symbol f in that case. 158 00:17:26,540 --> 00:17:31,380 Then it came back from eval dispatch, restored the environment. 159 00:17:31,380 --> 00:17:38,740 But in fact, the actual thing it ended up doing in the evaluation is not going to hurt the environment at all. 160 00:17:38,740 --> 00:17:42,170 So there's no reason to be saving the environment and restoring the environment here. 161 00:17:46,020 --> 00:17:58,090 Similarly, here I'm saving the argument list. That's a piece of the argument evaluation loop, saving the argument list, and here you restore it. 162 00:17:58,090 --> 00:18:04,090 But the actual thing that you ended up doing didn't trash the argument list. So there was no reason to save it. 163 00:18:08,690 --> 00:18:23,180 So another way to say, another way to say that is that the, the evaluator has to be maximally pessimistic, because as far from its point of view it's just going off to evaluate something. 164 00:18:23,180 --> 00:18:26,200 So it better save what it's going to need later. 165 00:18:26,200 --> 00:18:32,140 But once you've done the analysis, the compiler is in a position to say, well, what actually did I need to save? 166 00:18:32,140 --> 00:18:39,950 And doesn't need to do any-- it doesn't need to be as careful as the evaluator, because it knows what it actually needs. 167 00:18:39,950 --> 00:18:49,400 Well, in any case, if we do that and eliminate all those redundant saves and restores, then we can get it down to this. 168 00:18:49,400 --> 00:19:00,070 And you see there are actually only three instructions that we actually need, down from the initial 11 or so, or the initial 20 or so in the original one. 169 00:19:00,070 --> 00:19:04,870 And that's just saying, of those register operations, which ones did we actually need? 170 00:19:09,490 --> 00:19:13,450 Let me just sort of summarize that in another way, just to show you in a little better picture. 171 00:19:16,010 --> 00:19:20,530 Here's a picture of starting-- This is looking at all the saves and restores. 172 00:19:23,770 --> 00:19:38,160 So here's the expression, f of x, and then this traces through, on the bottom here, the various places in the evaluator that were passed when the evaluation happened. 173 00:19:38,160 --> 00:19:40,250 And then here, here you see arrows. 174 00:19:40,250 --> 00:19:42,320 Arrow down means register saved. 175 00:19:42,320 --> 00:19:46,860 So the first thing that happened is the environment got saved. 176 00:19:46,860 --> 00:19:48,305 And over here, the environment got restored. 177 00:19:52,380 --> 00:19:56,220 And these-- so there are all the pairs of stack operations. 178 00:19:56,220 --> 00:20:03,320 Now, if you go ahead and say, well, let's remember that we don't--that unev, for instance, is a completely useless register. 179 00:20:07,550 --> 00:20:13,020 And if we use the constant structure of the code, well, we don't need, we don't need to save unev. We don't need unev at all. 180 00:20:16,220 --> 00:20:23,860 And then, depending on how we set up the discipline of the--of calling other things that apply, we may or may not need to save continue. 181 00:20:27,360 --> 00:20:28,800 That's the first step I did. 182 00:20:28,800 --> 00:20:32,960 And then we can look and see what's actually, what's actually needed. 183 00:20:32,960 --> 00:20:40,040 See, we don't-- didn't really need to save env or cross-evaluating f, because it wouldn't, it wouldn't trash it. 184 00:20:40,040 --> 00:21:03,320 So if we take advantage of that, and see the evaluation of f here, doesn't really need to worry about, about hurting env. And similarly, the evaluation of x here, when the evaluator did that it said, oh, I'd better preserve the function register around that, because I might need it later. 185 00:21:03,320 --> 00:21:07,140 And I better preserve the argument list. 186 00:21:07,140 --> 00:21:12,730 Whereas the compiler is now in a position to know, well, we didn't really need to save-- to do those saves and restores. 187 00:21:12,730 --> 00:21:19,670 So in fact, all of the stack operations done by the evaluator turned out to be unnecessary or overly pessimistic. 188 00:21:19,670 --> 00:21:21,390 And the compiler is in a position to know that. 189 00:21:27,470 --> 00:21:29,980 Well that's the basic idea. 190 00:21:29,980 --> 00:21:40,460 We take the evaluator, we eliminate the things that you don't need, that in some sense have nothing to do with the compiler at all, just the evaluator, and then you see which stack operations are unnecessary. 191 00:21:40,460 --> 00:21:45,130 That's the basic structure of the compiler that's described in the book. 192 00:21:45,130 --> 00:21:51,280 Let me just show you how that examples a little bit too simple. 193 00:21:51,280 --> 00:21:55,765 To see how you, how you actually save a lot, let's look at a little bit more complicated expression. 194 00:21:58,330 --> 00:22:03,542 F of G of X and 1. 195 00:22:03,542 --> 00:22:06,410 And I'm not going to go through all the code. 196 00:22:06,410 --> 00:22:09,830 There's a, there's a fair pile of it. 197 00:22:09,830 --> 00:22:17,270 I think there are, there are something like 16 pairs of register saves and restores as the evaluator walks through that. 198 00:22:17,270 --> 00:22:20,680 Here's a diagram of them. 199 00:22:20,680 --> 00:22:21,060 Let's see. 200 00:22:21,060 --> 00:22:24,210 You see what's going on. 201 00:22:24,210 --> 00:22:26,480 You start out by--the evaluator says, oh, I'm about to do an application. 202 00:22:26,480 --> 00:22:28,010 I'll preserve the environment. 203 00:22:28,010 --> 00:22:30,261 I'll restore it here. 204 00:22:30,261 --> 00:22:33,900 Then I'm about to do the first operand. 205 00:22:36,790 --> 00:22:38,970 Here it recursively goes to the evaluator. 206 00:22:38,970 --> 00:22:46,740 The evaluator says, oh, this is an application, I'll save the environment, do the operator of that combination, restore it here. 207 00:22:46,740 --> 00:22:51,720 This save--this restore matches that save. And so on. 208 00:22:51,720 --> 00:22:57,240 There's unev here, which turns out to be completely unnecessary, continues getting bumped around here. 209 00:22:57,240 --> 00:23:05,330 The function register is getting, getting saved across the first operands, across the operands. 210 00:23:05,330 --> 00:23:06,680 All sorts of things are going on. 211 00:23:06,680 --> 00:23:14,320 But if you say, well, what of those really were the business of the compiler as opposed to the evaluator, you get rid of a whole bunch. 212 00:23:14,320 --> 00:23:34,570 And then on top of that, if you say things like, the evaluation of F doesn't hurt the environment register, or simply looking up the symbol X, you don't have to protect the function register against that. 213 00:23:34,570 --> 00:23:37,530 So you come down to just a couple of, a couple of pairs here. 214 00:23:40,280 --> 00:23:42,160 And still, you can do a little better. 215 00:23:42,160 --> 00:23:44,962 Look what's going on here with the environment register. 216 00:23:44,962 --> 00:23:52,600 The environment register comes along and says, oh, here's a combination. 217 00:23:54,280 --> 00:23:58,580 This evaluator, by the way, doesn't know anything about G. 218 00:23:58,580 --> 00:24:15,540 So here it says, so it says, I'd better save the environment register, because evaluating G might be some arbitrary piece of code that would trash it, and I'm going to need it later, after this argument, for doing the second argument. 219 00:24:15,540 --> 00:24:22,550 So that's why this one didn't go away, because the compiler made no assumptions about what G would do. 220 00:24:22,550 --> 00:24:27,710 On the other hand, if you look at what the second argument is, that's just looking up one. 221 00:24:27,710 --> 00:24:30,810 That doesn't need this environment register. 222 00:24:30,810 --> 00:24:32,070 So there's no reason to save it. 223 00:24:32,070 --> 00:24:35,020 So in fact, you can get rid of that one, too. 224 00:24:35,020 --> 00:24:45,170 And from this whole pile of, of register operations, if you simply do a little bit of reasoning like that, you get down to, I think, just two pairs of saves and restores. 225 00:24:45,170 --> 00:24:56,650 And those, in fact, could go away further if you, if you knew something about G. 226 00:24:56,650 --> 00:25:03,310 So again, the general idea is that the reason the compiler can be better is that the interpreter doesn't know what it's about to encounter. 227 00:25:03,310 --> 00:25:07,750 It has to be maximally pessimistic in saving things to protect itself. 228 00:25:07,750 --> 00:25:13,410 The compiler only has to deal with what actually had to be saved. 229 00:25:13,410 --> 00:25:17,920 And there are two reasons that something might not have to be saved. 230 00:25:17,920 --> 00:25:24,210 One is that what you're protecting it against, in fact, didn't trash the register, like it was just a variable look-up. 231 00:25:24,210 --> 00:25:30,800 And the other one is, that the thing that you were saving it for might turn out not to actually need it. 232 00:25:30,800 --> 00:25:38,260 So those are the two basic pieces of knowledge that the compiler can take advantage of in making the code more efficient. 233 00:25:44,570 --> 00:25:45,820 Let's break for questions. 234 00:25:51,280 --> 00:25:56,350 AUDIENCE: You kept saying that the uneval register, unev register didn't need to be used at all. 235 00:25:56,350 --> 00:25:58,590 Does that mean that you could just map a six-register machine? 236 00:25:58,590 --> 00:26:01,860 Or is that, in this particular example, it didn't need to be used? 237 00:26:01,860 --> 00:26:07,580 PROFESSOR: For the compiler, you could generate code for the six-register, five, right? 238 00:26:07,580 --> 00:26:08,930 Because that exp goes away also. 239 00:26:11,750 --> 00:26:17,380 Assuming--yeah, you can get rid of both exp and unev, because, see, those are data structures of the evaluator. 240 00:26:17,380 --> 00:26:21,410 Those are all things that would be constants from the point of view of the compiler. 241 00:26:21,410 --> 00:26:29,330 The only thing is this particular compiler is set up so that interpreted code and compiled code can coexist. 242 00:26:29,330 --> 00:26:39,920 So the way to think about it is, is maybe you build a chip which is the evaluator, and what the compiler might do is generate code for that chip. 243 00:26:39,920 --> 00:26:41,550 It just wouldn't use two of the registers. 244 00:26:51,158 --> 00:26:53,326 All right, let's take a break. 245 00:26:53,326 --> 00:27:28,576 [MUSIC PLAYING] 246 00:27:28,576 --> 00:27:32,900 We just looked at what the compiler is supposed to do. 247 00:27:32,900 --> 00:27:38,120 Now let's very briefly look at how, how this gets accomplished. 248 00:27:38,120 --> 00:27:39,600 And I'm going to give no details. 249 00:27:39,600 --> 00:27:43,440 There's, there's a giant pile of code in the book that gives all the details. 250 00:27:43,440 --> 00:27:49,590 But what I want to do is just show you the, the essential idea here. 251 00:27:49,590 --> 00:27:51,450 Worry about the details some other time. 252 00:27:51,450 --> 00:27:58,900 Let's imagine that we're compiling an expression that looks like there's some operator, and there are two arguments. 253 00:28:03,660 --> 00:28:08,940 Now, the-- what's the code that the compiler should generate? 254 00:28:08,940 --> 00:28:14,192 Well, first of all, it should recursively go off and compile the operator. 255 00:28:14,192 --> 00:28:18,650 So it says, I'll compile the operator. 256 00:28:21,250 --> 00:28:28,400 And where I'm going to need that is to be in the function register, eventually. 257 00:28:28,400 --> 00:28:38,890 So I'll compile some instructions that will compile the operator and end up with the result in the function register. 258 00:28:45,420 --> 00:28:55,140 The next thing it's going to do, another piece is to say, well, I have to compile the first argument. 259 00:28:55,140 --> 00:28:58,100 So it calls itself recursively. 260 00:28:58,100 --> 00:29:03,010 And let's say the result will go into val. 261 00:29:09,150 --> 00:29:35,430 And then what it's going to need to do is start setting up the argument list. So it'll say, assign to argl cons of fetch-- so it generates this literal instruction-- fetch of val onto empty list. 262 00:29:35,430 --> 00:29:43,950 However, it might have to work-- when it gets here, it's going to need the environment. 263 00:29:43,950 --> 00:29:49,030 It's going to need whatever environment was here in order to do this evaluation of the first argument. 264 00:29:49,030 --> 00:30:01,220 So it has to ensure that the compilation of this operand, or it has to protect the function register against whatever might happen in the compilation of this operand. 265 00:30:01,220 --> 00:30:12,650 So it puts a note here and says, oh, this piece should be done preserving the environment register. 266 00:30:17,350 --> 00:30:27,930 Similarly, here, after it gets done compiling the first operand, it's going to say, I better compile-- I'm going to need to know the environment for the second operand. 267 00:30:27,930 --> 00:30:50,760 So it puts a little note here, saying, yeah, this is also done preserving env. Now it goes on and says, well, the next chunk of code is the one that's going to compile the second argument. 268 00:30:50,760 --> 00:30:59,360 And let's say it'll compile it with a targeted to val, as they say. 269 00:31:03,940 --> 00:31:34,060 And then it'll generate the literal instruction, building up the argument list. So it'll say, assign to argl cons of the new value it just got onto the old argument list. 270 00:31:34,060 --> 00:31:43,510 However, in order to have the old argument list, it better have arranged that the argument list didn't get trashed by whatever happened in here. 271 00:31:43,510 --> 00:31:51,400 So it puts a little note here and says, oh, this has to be done preserving argl. 272 00:31:54,380 --> 00:31:58,090 Now it's got the argument list set up. 273 00:31:58,090 --> 00:32:02,520 And it's all ready to go to apply dispatch. 274 00:32:06,450 --> 00:32:10,440 It generates this literal instruction. 275 00:32:14,990 --> 00:32:29,600 Because now it's got the arguments in argl and the operator in fun, but wait, it's only got the operator in fun if it had ensured that this block of code didn't trash what was in the function register. 276 00:32:29,600 --> 00:32:40,710 So it puts a little note here and says, oh, yes, all this stuff here had better be done preserving the function register. 277 00:32:46,110 --> 00:32:53,432 So that's the little--so when it starts ticking--so basically, what the compiler does is append a whole bunch of code sequences. 278 00:32:53,432 --> 00:33:02,560 See, what it's got in it is little primitive pieces of things, like how to look up a symbol, how to do a conditional. 279 00:33:02,560 --> 00:33:05,530 Those are all little pieces of things. 280 00:33:05,530 --> 00:33:08,810 And then it appends them together in this sort of discipline. 281 00:33:08,810 --> 00:33:13,140 So the basic means of combining things is to append two code sequences. 282 00:33:21,610 --> 00:33:22,860 That's what's going on here. 283 00:33:25,690 --> 00:33:27,590 And it's a little bit tricky. 284 00:33:27,590 --> 00:33:35,670 The idea is that it appends two code sequences, taking care to preserve a register. 285 00:33:35,670 --> 00:33:39,250 So the actual append operation looks like this. 286 00:33:39,250 --> 00:33:44,450 What it wants to do is say, if-- here's what it means to append two code sequences. 287 00:33:44,450 --> 00:33:54,720 So if sequence one needs register-- I should change this. 288 00:33:54,720 --> 00:34:03,815 Append sequence one to sequence two, preserving some register. 289 00:34:08,370 --> 00:34:11,080 Let me say, and. 290 00:34:11,080 --> 00:34:13,719 So it's clear that sequence one comes first. 291 00:34:13,719 --> 00:34:43,380 So if sequence two needs the register and sequence one modifies the register, then the instructions that the compiler spits out are, save the register. 292 00:34:43,380 --> 00:34:44,440 Here's the code. 293 00:34:44,440 --> 00:34:45,280 You generate this code. 294 00:34:45,280 --> 00:34:53,389 Save the register, and then you put out the recursively compiled stuff for sequence one. 295 00:34:53,389 --> 00:34:54,639 And then you restore the register. 296 00:35:00,440 --> 00:35:07,330 And then you put out the recursively compiled stuff for sequence two. 297 00:35:07,330 --> 00:35:09,610 That's in the case where you need to do it. 298 00:35:09,610 --> 00:35:15,430 Sequence two actually needs the register, and sequence one actually clobbers it. 299 00:35:15,430 --> 00:35:16,320 So that's sort of if. 300 00:35:16,320 --> 00:35:28,240 Otherwise, all you spit out is sequence one followed by sequence two. 301 00:35:28,240 --> 00:35:36,960 So that's the basic operation for sticking together these bits of code fragments, these bits of instructions into a sequence. 302 00:35:36,960 --> 00:35:59,550 And you see, from this point of view, the difference between the interpreter and the compiler, in some sense, is that where the compiler has these preserving notes, and says, maybe I'll actually generate the saves and restores and maybe I won't, the interpreter being maximally pessimistic always has a save and restore here. 303 00:35:59,550 --> 00:36:04,140 That's the essential difference. 304 00:36:04,140 --> 00:36:12,025 Well, in order to do this, of course, the compiler needs some theory of what code sequences need and modifier registers. 305 00:36:14,330 --> 00:36:27,120 So the tiny little fragments that you put in, like the basic primitive code fragments, say, what are the operations that you do when you look up a variable? 306 00:36:27,120 --> 00:36:32,900 What are the sequence of things that you do when you compile a constant or apply a function? 307 00:36:32,900 --> 00:36:36,850 Those have little notations in there about what they need and what they modify. 308 00:36:38,760 --> 00:36:44,330 So the bottom-level data structures-- Well, I'll say this. 309 00:36:44,330 --> 00:36:48,070 A code sequence to the compiler looks like this. 310 00:36:48,070 --> 00:36:50,945 It has the actual sequence of instructions. 311 00:36:55,780 --> 00:37:02,195 And then, along with it, there's the set of registers modified. 312 00:37:10,630 --> 00:37:12,335 And then there's the set of registers needed. 313 00:37:19,910 --> 00:37:25,965 So that's the information the compiler has that it draws on in order to be able to do this operation. 314 00:37:29,420 --> 00:37:30,650 And where do those come from? 315 00:37:30,650 --> 00:37:37,230 Well, those come from, you might expect, for the very primitive ones, we're going to put them in by hand. 316 00:37:37,230 --> 00:37:42,080 And then, when we combine two sequences, we'll figure out what these things should be. 317 00:37:42,080 --> 00:37:48,460 So for example, a very primitive one, let's see. 318 00:37:48,460 --> 00:37:51,790 How about doing a register assignment. 319 00:37:51,790 --> 00:37:56,040 So a primitive sequence might say, oh, it's code fragment. 320 00:37:56,040 --> 00:38:03,050 Its code instruction is assigned to R1, fetch of R2. 321 00:38:03,050 --> 00:38:05,000 So this is an example. 322 00:38:05,000 --> 00:38:08,510 That might be an example of a sequence of instructions. 323 00:38:08,510 --> 00:38:20,670 And along with that, it'll say, oh, what I need to remember is that that modifies R1, and then it needs R2. 324 00:38:24,630 --> 00:38:31,030 So when you're first building this compiler, you put in little fragments of stuff like that. 325 00:38:31,030 --> 00:38:50,950 And now, when it combines two sequences, if I'm going to combine, let's say, sequence one, that modifies a bunch of registers M1, and needs a bunch of registers N1. 326 00:38:54,940 --> 00:39:00,800 And I'm going to combine that with sequence two. 327 00:39:00,800 --> 00:39:09,570 That modifies a bunch of registers M2, and needs a bunch of registers N2. 328 00:39:12,590 --> 00:39:15,035 Then, well, we can reason it out. 329 00:39:15,035 --> 00:39:27,760 The new code fragment, sequence one, and-- followed by sequence two, well, what's it going to modify? 330 00:39:27,760 --> 00:39:33,990 The things that it will modify are the things that are modified either by sequence one or sequence two. 331 00:39:33,990 --> 00:39:40,530 So the union of these two sets are what the new thing modifies. 332 00:39:40,530 --> 00:39:47,870 And then you say, well, what is this--what registers is it going to need? 333 00:39:47,870 --> 00:39:52,790 It's going to need the things that are, first of all, needed by sequence one. 334 00:39:52,790 --> 00:39:55,250 So what it needs is sequence one. 335 00:39:55,250 --> 00:39:59,760 And then, well, not quite all of the ones that are needed by sequence one. 336 00:39:59,760 --> 00:40:08,070 What it needs are the ones that are needed by sequence two that have not been set up by sequence one. 337 00:40:08,070 --> 00:40:19,370 So it's sort of the union of the things that sequence two needs minus the ones that sequence one modifies. 338 00:40:19,370 --> 00:40:20,910 Because it worries about setting them up. 339 00:40:24,230 --> 00:40:26,740 So there's the basic structure of the compiler. 340 00:40:26,740 --> 00:40:34,010 The way you do register optimizations is you have some strategies for what needs to be preserved. 341 00:40:34,010 --> 00:40:35,450 That depends on a data structure. 342 00:40:35,450 --> 00:40:39,080 Well, it depends on the operation of what it means to put things together. 343 00:40:39,080 --> 00:40:48,900 Preserving something, that depends on knowing what registers are needed and modified by these code fragments. 344 00:40:48,900 --> 00:40:57,350 That depends on having little data structures, which say, a code sequence is the actual instructions, what they modify and what they need. 345 00:40:57,350 --> 00:41:00,240 That comes from, at the primitive level, building it in. 346 00:41:00,240 --> 00:41:04,850 At the primitive level, it's going to be completely obvious what something needs and modifies. 347 00:41:04,850 --> 00:41:15,010 Plus, this particular way that says, when I build up bigger ones, here's how I generate the new set of registers modified and the new set of registers needed. 348 00:41:15,010 --> 00:41:17,810 And that's the whole-- well, I shouldn't say that's the whole thing. 349 00:41:17,810 --> 00:41:21,860 That's the whole thing except for about 30 pages of details in the book. 350 00:41:21,860 --> 00:41:28,880 But it is a perfectly usable rudimentary compiler. 351 00:41:28,880 --> 00:41:31,390 Let me kind of show you what it does. 352 00:41:31,390 --> 00:41:36,330 Suppose we start out with recursive factorial. 353 00:41:36,330 --> 00:41:38,590 And these slides are going to be much too small to read. 354 00:41:38,590 --> 00:41:41,620 I just want to flash through the code and show you about how much it is. 355 00:41:44,460 --> 00:41:48,740 That starts out with--here's a first block of it, where it compiles a procedure entry and does a bunch of assignments. 356 00:41:48,740 --> 00:41:56,830 And this thing is basically up through the part where it sets up to do the predicate and test whether the predicate's true. 357 00:41:56,830 --> 00:42:04,210 The second part is what results from-- in the recursive call to fact of n minus one. 358 00:42:04,210 --> 00:42:09,890 And this last part is coming back from that and then taking care of the constant case. 359 00:42:09,890 --> 00:42:13,760 So that's about how much code it would produce for factorial. 360 00:42:13,760 --> 00:42:18,380 We could make this compiler much, much better, of course. 361 00:42:18,380 --> 00:42:26,990 The main way we could make it better is to allow the compiler to make any assumptions at all about what happens when you call a procedure. 362 00:42:26,990 --> 00:42:36,030 So this compiler, for instance, doesn't even know, say, that multiplication is something that could be coded in line. 363 00:42:36,030 --> 00:42:37,670 Instead, it sets up this whole mechanism. 364 00:42:37,670 --> 00:42:38,920 It goes to apply-dispatch. 365 00:42:41,430 --> 00:42:49,170 That's a tremendous waste, because what you do every time you go to apply-dispatch is you have to concept this argument list, because it's a very general thing you're going to. 366 00:42:49,170 --> 00:42:53,830 In any real compiler, of course, you're going to have registers for holding arguments. 367 00:42:53,830 --> 00:43:02,442 And you're going to start preserving and saving the way you use those registers similar to the same strategy here. 368 00:43:02,442 --> 00:43:08,940 So that's probably the very main way that this particular compiler in the book could be fixed. 369 00:43:08,940 --> 00:43:14,490 There are other things like looking up variable values and making more efficient primitive operations and all sorts of things. 370 00:43:14,490 --> 00:43:19,780 Essentially, a good Lisp compiler can absorb an arbitrary amount of effort. 371 00:43:19,780 --> 00:43:34,520 And probably one of the reasons that Lisp is slow with compared to languages like FORTRAN is that, if you look over history at the amount of effort that's gone into building Lisp compilers, it's nowhere near the amount of effort that's gone into FORTRAN compilers. 372 00:43:34,520 --> 00:43:38,250 And maybe that's something that will change over the next couple of years. 373 00:43:38,250 --> 00:43:39,500 OK, let's break. 374 00:43:43,950 --> 00:43:45,200 Questions? 375 00:43:48,370 --> 00:44:00,720 AUDIENCE: One of the very first classes-- I don't know if it was during class or after class- you showed me the, say, addition has a primitive that we don't see, and-percent add or something like that. 376 00:44:00,720 --> 00:44:08,540 Is that because, if you're doing inline code you'd want to just do it for two operators, operands? 377 00:44:08,540 --> 00:44:12,800 But if you had more operands, you'd want to do something special? 378 00:44:12,800 --> 00:44:15,980 PROFESSOR: Yeah, you're looking in the actual scheme implementation. 379 00:44:15,980 --> 00:44:17,880 There's a plus, and a plus is some operator. 380 00:44:17,880 --> 00:44:24,640 And then if you go look inside the code for plus, you see something called-- I forget-- and-percent plus or something like that. 381 00:44:24,640 --> 00:44:28,540 And what's going on there is that particular kind of optimization. 382 00:44:28,540 --> 00:44:31,770 Because, see, general plus takes an arbitrary number of arguments. 383 00:44:34,750 --> 00:44:44,880 So the most general plus says, oh, if I have an argument list, I'd better cons it up in some list and then figure out how many there were or something like that. 384 00:44:44,880 --> 00:44:49,200 That's terribly inefficient, especially since most of the time you're probably adding two numbers. 385 00:44:49,200 --> 00:44:58,170 You don't want to really have to cons this argument list. So what you'd like to do is build the code for plus with a bunch of entries. 386 00:44:58,170 --> 00:45:00,170 So most of what it's doing is the same. 387 00:45:00,170 --> 00:45:04,640 However, there might be a special entry that you'd go to if you knew there were only two arguments. 388 00:45:04,640 --> 00:45:05,910 And those you'll put in registers. 389 00:45:05,910 --> 00:45:09,080 They won't be in an argument list and you won't have to [UNINTELLIGIBLE]. 390 00:45:09,080 --> 00:45:12,570 That's how a lot of these things work. 391 00:45:12,570 --> 00:45:13,948 OK, let's take a break. 392 00:45:13,948 --> 00:45:15,696 [MUSIC PLAYING] ================================================ FILE: SrtCN/lec10a.srt ================================================ 1 00:00:00,016 --> 00:00:05,024 Learning-SICP学习小组 倾情制作 2 00:00:05,376 --> 00:00:07,840 翻译&&时间轴:杨启钊(windfarer) 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:07,840 --> 00:00:09,840 特别感谢:裘宗燕教授 4 00:00:09,840 --> 00:00:11,840 计算机程序的构造和解释 5 00:00:11,840 --> 00:00:13,840 编译 Compilation 6 00:00:19,360 --> 00:00:22,650 教授: 上节课 我们学习了 PROFESSOR: Last time, we took a look at 7 00:00:22,650 --> 00:00:25,675 一个显式控制的Lisp求值器 an explicit control evaluator for Lisp 8 00:00:25,670 --> 00:00:28,976 它弥合了像Lisp and that bridged the gap between all these high-level languages 9 00:00:29,056 --> 00:00:32,144 或者查询语言之类的高级语言 like Lisp and query language all that stuff 10 00:00:32,500 --> 00:00:36,160 与传统寄存器机器之间的鸿沟 bridged the gap between that and a conventional register machine. 11 00:00:36,700 --> 00:00:40,144 事实上 你可以将显式控制求值器 And in fact, you can think of the explicit control evaluator 12 00:00:40,160 --> 00:00:44,384 看作是 在一台常见的 either as, say the code for a Lisp interpreter 13 00:00:44,400 --> 00:00:45,950 寄存机器上实现的 if you wanted to implement it in the 14 00:00:46,525 --> 00:00:49,500 Lisp求值器的汇编代码 assembly language of some conventional register transfer machine, 15 00:00:49,500 --> 00:00:51,504 或者 你可以把它看做是 or, if you like, you can think of it as the microcode 16 00:00:52,080 --> 00:00:54,560 某台专门运行Lisp的机器的微程序 of some machine that's going to be specially designed to run Lisp. 17 00:00:55,200 --> 00:00:55,925 无论是那种情况 In either case, 18 00:00:55,920 --> 00:00:58,688 我们都是把一台 Nwhat we're doing is we're taking a machine 19 00:00:58,944 --> 00:01:00,512 处理低级语言的机器 that speaks some low-level language 20 00:01:01,420 --> 00:01:03,328 抬高到一个层次 and we're raising the machine 21 00:01:03,376 --> 00:01:04,880 以便处理像Lisp这样的高级语言 to a high-level language like Lisp 22 00:01:05,360 --> 00:01:06,352 这是通过编写解释器来实现的 by writing an interpreter. 23 00:01:08,220 --> 00:01:09,584 来看个例子 So for instance 24 00:01:11,820 --> 00:01:13,776 这里 从概念上来说 here, conceptually, 25 00:01:18,016 --> 00:01:19,470 从概念上来说 这是一台 here conceptually is a 26 00:01:20,544 --> 00:01:23,440 专用于计算阶乘的机器 a special purpose machine for computing factorials. 27 00:01:24,090 --> 00:01:27,392 输入5 输出120 It takes in five and puts out 120. 28 00:01:28,920 --> 00:01:30,832 这个专用机器实际上 And what this special purpose machine is 29 00:01:30,970 --> 00:01:32,720 是一个Lisp解释器 actually a Lisp interpreter 30 00:01:33,500 --> 00:01:36,176 它将自己配置为计算阶乘 that's configured itself to run factorials 31 00:01:38,350 --> 00:01:40,992 因为你向它送入了一台阶乘机器的描述 because you feed into it a description of the factorial machine. 32 00:01:42,125 --> 00:01:43,700 这就是解释器 So that's what an interpreter is. 33 00:01:43,700 --> 00:01:45,664 它将自己配置为 It configures itself to 34 00:01:46,370 --> 00:01:49,248 模拟你所输入描述的机器 emulate a machine whose description you read in. 35 00:01:50,070 --> 00:01:51,936 那么 在Lisp解释器里是什么? Now, inside the Lisp interpreter, what's that? 36 00:01:52,040 --> 00:01:55,440 里面可能是通用的寄存器语言解释器 Well, that might be your general register language interpreter 37 00:01:56,987 --> 00:02:00,180 它将自己配置成像Lisp解释器那样 that configures itself to behave like a Lisp interpreter 38 00:02:00,180 --> 00:02:02,032 因为你输入了一系列用寄存器语言 because you put in a whole bunch of instructions 39 00:02:02,128 --> 00:02:03,040 编写的指令 in register language. 40 00:02:03,370 --> 00:02:05,168 这就是显式控制求值器 This is the explicit control evaluator. 41 00:02:07,050 --> 00:02:08,704 它里面也有一些库 And then it also has some sort of library 42 00:02:08,730 --> 00:02:11,088 由基本运算符和Lisp运算 a library of primitive operators and Lisp operations 43 00:02:11,120 --> 00:02:12,288 等等要素组成 all sorts of things like that. 44 00:02:12,750 --> 00:02:16,896 这是解释执行的一般策略 That's the general strategy of interpretation. 45 00:02:17,320 --> 00:02:18,512 事实上 我们所做的是 And the point is, what we're doing 46 00:02:18,608 --> 00:02:20,140 通过编写解释器 is we're writing an interpreter 47 00:02:21,620 --> 00:02:23,408 将机器抬升到 to raise the machine 48 00:02:23,424 --> 00:02:25,240 我们程序所在的层次 to the level of the programs that we want to write. 49 00:02:25,240 --> 00:02:26,720 当然 还有另外一种策略 Well, there's another strategy 50 00:02:27,424 --> 00:02:28,896 这种不同的策略就是编译 a different one, which is compilation. 51 00:02:29,040 --> 00:02:30,432 编译有一些不同 Compilation's a little bit different. 52 00:02:31,040 --> 00:02:31,504 这里 Here-- 53 00:02:33,370 --> 00:02:34,752 我们可能已经实现了 here we might have produced 54 00:02:35,679 --> 00:02:38,525 一个特定用途的机器 a special purpose machine for, 55 00:02:38,624 --> 00:02:39,984 用来计算阶乘 for computing factorials 56 00:02:43,625 --> 00:02:46,260 从某种使用寄存器语言的机器开始 starting with some sort of machine that speaks register language 57 00:02:46,260 --> 00:02:47,720 但是 我们将让它执行不同的策略 except we're going to do a different strategy. 58 00:02:47,720 --> 00:02:50,384 把我们的阶乘程序 We take our factorial program. 59 00:02:51,550 --> 00:02:53,920 作为源代码输入编译器 We use that as the source code into a compiler. 60 00:02:53,920 --> 00:02:55,150 编译器就会 What the compiler will do 61 00:02:55,150 --> 00:02:57,625 把这个阶乘程序 is translate that factorial program 62 00:02:57,620 --> 00:02:59,072 翻译成某种寄存器机器语言 into some register machine language. 63 00:03:00,250 --> 00:03:03,400 现在它并不是Lisp的显式控制求值器 And this will now be not the explicit control evaluator for Lisp 64 00:03:03,400 --> 00:03:06,176 而是某种用来计算阶乘的寄存器语言 this will be some register language for computing factorials. 65 00:03:06,496 --> 00:03:08,368 这就是翻译的过程 So this is the translation of that. 66 00:03:10,544 --> 00:03:12,416 它将进入某种加载器 That will go into some sort of loader 67 00:03:13,350 --> 00:03:15,216 它会把这些代码 which will combine this code 68 00:03:15,312 --> 00:03:16,848 和从程序库中选取的代码 with code selected from the library 69 00:03:16,864 --> 00:03:18,656 比如乘法运算等 结合在一起 to do things like primitive multiplication. 70 00:03:19,820 --> 00:03:21,696 随后我们将生成一个加载模块 And then we'll produce a load module 71 00:03:22,225 --> 00:03:25,060 它把寄存器语言机器配置成 which configures the register language machine 72 00:03:25,060 --> 00:03:27,248 一个专门用来计算阶乘的机器 to be a special purpose factorial machine. 73 00:03:28,125 --> 00:03:30,220 这就是不同的策略 So that's a, that's a different strategy. 74 00:03:30,220 --> 00:03:31,225 在解释中 In interpretation, 75 00:03:31,220 --> 00:03:32,016 我们把机器 we're raising 76 00:03:32,912 --> 00:03:35,232 抬升到Lisp语言的层次 the machine to the level of our language, like Lisp. 77 00:03:35,320 --> 00:03:36,340 而在编译中 In compilation 78 00:03:36,340 --> 00:03:38,432 我们将我们的程序下降到 we're taking our program and lowering 79 00:03:38,480 --> 00:03:40,560 机器语言的层次 it to the language that's spoken by the machine. 80 00:03:41,968 --> 00:03:43,840 那么 这两个策略有什么区别呢? Well, how do these two strategies compare? 81 00:03:44,300 --> 00:03:49,424 编译器可以生成执行起来更有效率的代码 The compiler can produce code that will execute more efficiently. 82 00:03:52,050 --> 00:03:53,904 主要原因是 The essential reason for that 83 00:03:54,170 --> 00:03:58,896 如果你考虑运行中的寄存器操作 is that if you think about the register operations that are running 84 00:04:01,920 --> 00:04:04,496 解释器需要生成寄存器的操作 the interpreter has to produce register operations 85 00:04:04,970 --> 00:04:06,752 从原则上来讲 它需要足够通用 which, in principle, are going to be general enough 86 00:04:07,328 --> 00:04:08,944 以支持任何Lisp过程的执行 to execute any Lisp procedure. 87 00:04:10,220 --> 00:04:12,256 而编译器只需要 Whereas the compiler only has to worry about 88 00:04:12,272 --> 00:04:14,920 生成一组特定的寄存器操作 producing a special bunch of register operations for 89 00:04:15,520 --> 00:04:18,224 用来执行你所编译的那部分特定的Lisp过程 for doing the particular Lisp procedure that you've compiled. 90 00:04:20,175 --> 00:04:21,200 换一种说法 Or another way to say that 91 00:04:21,200 --> 00:04:25,312 解释器是一种通用的模拟器 is that the interpreter is a general purpose simulator 92 00:04:25,925 --> 00:04:27,580 当你输入一个Lisp过程时 that when you read in a Lisp procedure 93 00:04:27,580 --> 00:04:31,325 它们就会模拟那个过程所描述的程序 then those can simulate the program described by that, by that procedure. 94 00:04:31,320 --> 00:04:33,872 所以解释器旨在成为一个通用模拟器 So the interpreter is worrying about making a general purpose simulator 95 00:04:34,620 --> 00:04:35,968 而编译器 实际上 whereas the compiler, in effect, 96 00:04:36,000 --> 00:04:37,680 只需要将东西配置成 is configuring the thing to be the machine 97 00:04:37,712 --> 00:04:39,344 解释器将要去模拟的机器 that the interpreter would have been simulating. 98 00:04:40,020 --> 00:04:41,344 所以编译器可以运行得更快 So the compiler can be faster. 99 00:04:52,550 --> 00:04:53,648 另一方面 OK, On the other hand 100 00:04:55,970 --> 00:04:58,288 解释器更适合用来排查错误 the interpreter is a nicer environment for debugging. 101 00:04:59,438 --> 00:05:01,250 这是因为 And the reason for that is that we've got the 102 00:05:01,575 --> 00:05:03,020 我们的源代码实际上就在那里 the source code actually there. 103 00:05:03,020 --> 00:05:04,816 我们正在解释它们 We're interpreting it That's what we're working with. 104 00:05:05,870 --> 00:05:07,696 并且库也在其中 And we also have the library around. 105 00:05:07,900 --> 00:05:10,896 看 库是解释器的一部分 See, the interpreter--the library sitting there is part of the interpreter. 106 00:05:11,300 --> 00:05:13,168 而编译器只会拉取 The compiler only pulls out from the library 107 00:05:13,200 --> 00:05:14,560 运行程序所需要的代码 what it needs to run the program. 108 00:05:14,870 --> 00:05:17,008 所以 如果你在排查错误的途中 So if you're in the middle of debugging 109 00:05:18,000 --> 00:05:20,720 你想写一些额外的代码 and you might like to write a little extra program 110 00:05:20,800 --> 00:05:22,570 来考察运行过程中的数据类型 to examine some run time data structure 111 00:05:23,050 --> 00:05:24,256 或者做一些 or to produce some computation 112 00:05:24,304 --> 00:05:25,920 在写程序时没有想到的计算 that you didn't think of when you wrote the program 113 00:05:25,952 --> 00:05:27,536 解释器可以完美搞定这些 the interpreter can do that perfectly well 114 00:05:28,050 --> 00:05:29,216 而编译器不行 whereas the compiler can't. 115 00:05:29,625 --> 00:05:31,900 所以它们各有优点 So there are sort of dual, dual advantages. 116 00:05:31,900 --> 00:05:34,480 编译器将生成运行更快的代码 The compiler will produce code that executes faster. 117 00:05:34,850 --> 00:05:37,024 而解释器是一种更适合排错的环境 The interpreter is a better environment for debugging. 118 00:05:38,950 --> 00:05:41,408 大多数Lisp系统最终将二者都实现了 And most Lisp systems end up having both 119 00:05:42,920 --> 00:05:45,232 这样你就可以在开发阶段 end up being configured so you have an interpreter 120 00:05:45,248 --> 00:05:47,080 可以使用解释器 that you use when you're developing your code. 121 00:05:47,080 --> 00:05:48,624 随后通过编译加速代码的运行 Then you can speed it up by compiling. 122 00:05:49,020 --> 00:05:50,032 并且通常 And very often, 123 00:05:50,048 --> 00:05:51,680 你能够让被编译的代码 you can arrange that compiled code 124 00:05:51,696 --> 00:05:53,568 和被解释的代码互相调用 and interpreted code can call each other. 125 00:05:54,600 --> 00:05:56,336 我们将学习如何做到 其实不难 We'll see how to do that, That's not hard. 126 00:05:59,270 --> 00:05:59,856 好 OK 127 00:06:00,970 --> 00:06:02,096 事实上 In fact, the way we'll-- 128 00:06:04,304 --> 00:06:05,750 在我们将要构建的编译器中 in the compiler we're going to make 129 00:06:05,750 --> 00:06:07,584 我们实现编译的代码和解释的代码 the way we'll arrange for compiled coding 130 00:06:07,584 --> 00:06:09,456 互相调用的方式是 and interpreted code to call to call each other 131 00:06:09,900 --> 00:06:12,064 我们让编译器和解释器使用 is that we'll have the compiler use exactly 132 00:06:12,112 --> 00:06:14,400 使用完全一致的寄存器约定 the same register conventions as the interpreter. 133 00:06:18,420 --> 00:06:21,728 编译器的理念 Well, the idea of a compiler 134 00:06:21,760 --> 00:06:25,744 与解释器或求值器的理念很像 is very much like the idea of an interpreter or evaluator. 135 00:06:25,870 --> 00:06:26,464 它们是相同的 It's the same thing. 136 00:06:27,050 --> 00:06:29,392 求值器遍历代码 See, the evaluator walks over the code 137 00:06:29,820 --> 00:06:32,352 产生一些寄存器操作 and performs some register operations. 138 00:06:33,650 --> 00:06:34,976 就是我们昨天做的事情 That's what we did yesterday. 139 00:06:37,100 --> 00:06:40,272 而编译器会读取代码 Well, the compiler essentially would like to walk over the code 140 00:06:40,520 --> 00:06:43,008 生成一些进行求值时 and produce the register operations 141 00:06:43,040 --> 00:06:44,672 求值器会进行的 that the evaluator would have done 142 00:06:45,232 --> 00:06:46,640 相关寄存器操作 were it evaluating the thing. 143 00:06:48,600 --> 00:06:49,952 这就给我们提供了一个模型 And that gives us some model 144 00:06:50,608 --> 00:06:53,776 来实现一个零阶编译器 for how to implement a zeroth-order compiler 145 00:06:55,300 --> 00:06:58,320 一个很差劲但是能用的编译器 a very bad compiler but essentially a compiler. 146 00:06:58,320 --> 00:06:59,328 这种模型就是 A model for doing that 147 00:06:59,360 --> 00:07:00,592 你用求值器 is you just take the evaluator, 148 00:07:00,688 --> 00:07:01,888 把代码跑一遍 you run it over the code 149 00:07:02,800 --> 00:07:06,060 但不去执行实际的操作 but instead of executing the actual operations 150 00:07:06,060 --> 00:07:07,152 只是把它们保存下来 you just save them away. 151 00:07:07,550 --> 00:07:08,825 那就是你编译后的代码 And that's your compiled code. 152 00:07:08,820 --> 00:07:10,240 让我举个例子 So let me give you an example of that. 153 00:07:12,700 --> 00:07:14,144 假设我们要编译 Suppose we're going to compile-- 154 00:07:15,100 --> 00:07:17,904 编译(F X) 这个表达式 Suppose we want to compile the expression f of x. 155 00:07:25,070 --> 00:07:25,968 我们假设 So let's assume that 156 00:07:25,960 --> 00:07:28,064 EXP寄存器中保存着(F X) we've got f of x in the exp register 157 00:07:28,064 --> 00:07:29,552 而ENV寄存器又保存着其它东西 and something in the environment register. 158 00:07:30,100 --> 00:07:32,208 想象我们启动了求值器 And now imagine starting up the evaluator. 159 00:07:34,608 --> 00:07:35,712 它读取了表达式 Well, it looks at the expression 160 00:07:35,712 --> 00:07:37,360 判断它是一个应用 and it sees that it's an application. 161 00:07:37,920 --> 00:07:41,904 它分支到求值器代码中的一个地方 And it branches to a place in the 162 00:07:42,520 --> 00:07:45,152 我们之前见过的叫EV-APPLICATION的地方 in the evaluator code we saw called ev-application. 163 00:07:47,120 --> 00:07:48,128 然后继续处理 And then it begins. 164 00:07:48,160 --> 00:07:50,080 恢复运算对象和UNEV It stores away the operands and unev 165 00:07:50,080 --> 00:07:52,448 然后之后它将运算符放在EXP寄存器中 and then it's going to put the operator in exp, 166 00:07:52,480 --> 00:07:54,272 递归地对它求值 and it's going to go recursively evaluate it. 167 00:07:54,470 --> 00:07:56,080 这就是我们经历的过程 That's the process that we walk through. 168 00:07:56,670 --> 00:07:57,840 如果你看代码 And if you start looking at the code, 169 00:07:57,872 --> 00:07:59,744 会看到一些寄存器操作 you start seeing some register operations. 170 00:08:00,200 --> 00:08:02,300 你会看到将运算对象赋值给UNEV寄存器 You see assign to unev the operands 171 00:08:02,300 --> 00:08:03,952 把运算符赋值给EXP assign to exp the operator, 172 00:08:04,096 --> 00:08:06,208 保存环境、生成新环境 等等 save the environment, generate that, and so on. 173 00:08:10,220 --> 00:08:11,936 如果我们来看下这里的投影 Well, if we look on the overhead here 174 00:08:15,750 --> 00:08:19,584 我们会看到产生的这些操作 we can see those operations starting to be produced. 175 00:08:20,820 --> 00:08:22,528 这是求值器实际要进行的 Here's sort of the first real operation 176 00:08:22,720 --> 00:08:24,800 第一个操作 that the evaluator would have done. 177 00:08:25,000 --> 00:08:27,200 它将运算对象从EXP寄存器里取出来 It pulls the operands out of the exp register 178 00:08:27,470 --> 00:08:28,624 并将它赋值给UNEV and assigns it to unev. 179 00:08:30,030 --> 00:08:32,272 然后它给EXP寄存器赋了某个值 And then it assigns something to the expression register, 180 00:08:32,304 --> 00:08:33,460 然后保存CONTINUE and it saves continue 181 00:08:33,460 --> 00:08:34,620 保存ENV and it saves env. 182 00:08:34,620 --> 00:08:38,656 我在这里就只是寄存器赋值 And all I'm doing here is writing down the register assignments 183 00:08:39,570 --> 00:08:42,320 这就是求值器求值代码时进行的操作 that the evaluator would have done in executing that code. 184 00:08:42,770 --> 00:08:43,792 我们缩小画面看看 And can zoom out a little bit. 185 00:08:44,300 --> 00:08:47,136 总计有19个操作 Altogether, there are about 19 operations there. 186 00:08:49,400 --> 00:08:51,648 这些代码 And this is the--this will be the piece of code 187 00:08:52,050 --> 00:08:53,904 对应着 up until the point where 188 00:08:54,752 --> 00:08:57,100 求值器跳转到APPLY-DISPATCH代码之前 the evaluator branches off to apply-dispatch. 189 00:08:57,860 --> 00:08:59,168 事实上 在这个编译器中 And in fact, in this compiler 190 00:08:59,200 --> 00:09:01,184 我们不需要再关心APPLY-DISPATCH了 we're not going to worry about apply-dispatch at all. 191 00:09:01,300 --> 00:09:02,112 我们有所有东西 We're going to have everything 192 00:09:02,352 --> 00:09:05,040 我们拥有解释后和编译后的所有代码 we're going to have both interpreted code and compiled code. 193 00:09:06,075 --> 00:09:07,611 通常求值过程 Always evaluate procedures, 194 00:09:07,610 --> 00:09:09,856 是由APPLY-DISPATCH处理的 always apply procedures by going to apply-dispatch. 195 00:09:10,270 --> 00:09:12,320 这将让被解释后代码与编译后代码 That will easily allow interpreted code and 196 00:09:12,368 --> 00:09:13,712 很容易互相调用 compiled code to call each other. 197 00:09:18,270 --> 00:09:19,872 从原理上来说 这样做足矣 Well, in principle, that's all we need to do. 198 00:09:21,050 --> 00:09:22,660 只需运行求值器 You just run the evaluator. 199 00:09:22,660 --> 00:09:24,500 因而编译器非常像求值器 So the compiler's a lot like the evaluator. 200 00:09:24,500 --> 00:09:26,475 你运行它 唯一不同是你把操作存下来 You run it, except it stashes away these operations 201 00:09:26,470 --> 00:09:28,400 而不是实际执行它们 instead of actually executing them. 202 00:09:29,350 --> 00:09:31,392 这其实不完全正确 Well, that's not, that's not quite true. there's 203 00:09:32,910 --> 00:09:34,992 这里面我们撒了个小谎 There's only one little lie in that. 204 00:09:36,240 --> 00:09:39,296 你需要关心的是:如果有个谓词 What you have to worry about is if you have a, a predicate. 205 00:09:40,120 --> 00:09:42,160 如果你要进行某种测试 If you have some kind of test you want to do 206 00:09:43,450 --> 00:09:46,032 显然 在你编译时 obviously, at the point when you're compiling it 207 00:09:46,520 --> 00:09:47,984 你不知道这些分支中 you don't know which branch of these-- 208 00:09:48,320 --> 00:09:50,144 哪条分支会被执行 of a conditional like this you're going to do. 209 00:09:51,130 --> 00:09:53,920 所以你不能确定求值器将对哪个求值 So you can't say which one the evaluator would have done. 210 00:09:54,909 --> 00:09:57,125 因此在这里就很简单 So all you do there is very simple. 211 00:09:57,120 --> 00:09:58,496 你把两个分支全编译了 You compile both branches. 212 00:09:59,328 --> 00:10:01,296 因此你编译出一个这样的结构 So you compile a structure that looks like this. 213 00:10:02,000 --> 00:10:03,984 它们都会被编译成 That'll compile into something that says, 214 00:10:05,312 --> 00:10:09,152 首先是P的代码 the code, the code for P. 215 00:10:10,710 --> 00:10:16,512 它把结果存入VAL寄存器 And it puts its results in, say, the val register. 216 00:10:18,170 --> 00:10:20,640 解释器对谓词求值 So you walk the interpreter over the predicate 217 00:10:21,350 --> 00:10:24,192 并保证结果会放到VAL寄存器中 and make sure that the result would go into the val register. 218 00:10:24,703 --> 00:10:27,220 随后你编译一条指令 And then you compile an instruction that says 219 00:10:27,220 --> 00:10:33,792 如果VAL是TRUE branch if, if val is true 220 00:10:37,170 --> 00:10:38,752 就转到LABEL1这个地方 to a place we'll call label one. 221 00:10:44,970 --> 00:10:47,520 然后我们写下B的代码 Then we, we will put the code for B 222 00:10:49,420 --> 00:10:52,320 让解释器对B进行求值 to walk the interpreter--walk the interpreter over B. 223 00:10:53,620 --> 00:10:57,216 然后写一句指令 And then go to put in an instruction that says, 224 00:10:57,232 --> 00:10:58,752 用来跳转到下一条指令 go to the next thing, whatever 225 00:11:02,200 --> 00:11:04,560 就是它结束之后要去的地方 whatever was supposed to happen after this thing was done. 226 00:11:04,950 --> 00:11:06,096 你放入那个指令 You put in that instruction. 227 00:11:06,880 --> 00:11:08,624 这里你写下LABEL1 And here you put label one. 228 00:11:12,120 --> 00:11:13,808 这里写A的代码 And here you put the code for A. 229 00:11:19,470 --> 00:11:25,856 然后又是跳转到下一条指令 And you put go to next thing. 230 00:11:31,420 --> 00:11:32,880 这就是处理条件分支的办法 So that's how you treat a conditional. 231 00:11:32,980 --> 00:11:34,656 你生成一小段这样的代码 You generate a little block like that. 232 00:11:35,750 --> 00:11:38,128 除此之外 And other than that 233 00:11:38,950 --> 00:11:41,552 这个零阶编译器与求值器一模一样 this zeroth-order compiler is the same as the evaluator. 234 00:11:42,550 --> 00:11:45,120 它只是把指令存起来 而不执行它们 It's just stashing away the instructions instead of executing them. 235 00:11:46,550 --> 00:11:47,600 看起来很简单 That seems pretty simple, 236 00:11:47,648 --> 00:11:49,088 但我们已经取得了某些收获 but we've gained something by that. 237 00:11:50,120 --> 00:11:52,624 它会比求值器更有效率 See, already that's going to be more efficient than the evaluator. 238 00:11:53,520 --> 00:11:56,144 因为 如果你观察求值器的运行 Because, if you watch the evaluator run 239 00:11:56,350 --> 00:12:01,056 它并不只是进行寄存器操作 it's not only generating the register operations we wrote down 240 00:12:01,270 --> 00:12:03,504 它还会决定执行哪个 it's also doing things to decide which ones to generate. 241 00:12:04,700 --> 00:12:07,232 它做的第一件事就是 So the very first thing it does, say here 242 00:12:07,925 --> 00:12:09,775 以它为例 就是进行某些测试 here for instance, is go do some tests 243 00:12:09,770 --> 00:12:11,568 确定它是一个应用 and decide that this is an application 244 00:12:13,570 --> 00:12:15,056 然后就跳转到 and then branch off to the place that, 245 00:12:15,392 --> 00:12:16,624 处理应用的地方去 that handles applications. 246 00:12:16,620 --> 00:12:18,448 换句话说 求值器做的事情是 In other words, what the evaluator's doing 247 00:12:18,620 --> 00:12:22,768 分析代码需要进行的运算 is simultaneously analyzing the code to see what to do 248 00:12:23,470 --> 00:12:24,992 同时并执行它们 and running these operations. 249 00:12:25,550 --> 00:12:28,280 当你运行求值器一百万次 And when you-- if you run the evaluator a million times 250 00:12:28,280 --> 00:12:30,304 这个分析过程就进行一百万次 that analysis phase happens a million times 251 00:12:30,850 --> 00:12:32,580 而在编译器中 它只会进行一次 whereas in the compiler, it's happened once 252 00:12:32,580 --> 00:12:34,816 之后就只有寄存器操作了 and then you just have the register operations themselves. 253 00:12:39,200 --> 00:12:41,680 这就是零阶编译器了 Ok, that's a, a zeroth-order compiler 254 00:12:41,800 --> 00:12:44,048 但它是个拙劣的编译器 but it is a wretched, wretched compiler. 255 00:12:44,450 --> 00:12:45,280 它挺蠢的 It's really dumb. 256 00:12:46,900 --> 00:12:48,416 让我们回过头来 Let's--let's go back and, 257 00:12:49,888 --> 00:12:50,976 看看这张投影 and look at this overhead. 258 00:12:52,020 --> 00:12:55,296 看看这个东西做的一些操作 So look at look at some of the operations this thing is doing. 259 00:12:55,850 --> 00:12:56,880 我们想看看 We're supposedly 260 00:12:59,728 --> 00:13:02,288 在解释(F X)时的操作 looking at the operations in interpreting f of x. 261 00:13:03,520 --> 00:13:04,848 这里就是它做了什么 Now, look here what it's doing. 262 00:13:05,170 --> 00:13:06,112 举个例子 这里 For example, here 263 00:13:07,150 --> 00:13:11,984 它将(OPERATOR (FETCH EXP))赋值给EXP it assigns to exp the operator in fetch of exp. 264 00:13:13,750 --> 00:13:15,872 其实没必要这样做 But see, there's no reason to do that, because this is-- 265 00:13:16,220 --> 00:13:17,472 因为编译器知道 the compiler knows 266 00:13:17,660 --> 00:13:21,840 (OPERATOR (FETCH EXP))的值就是F that the operator, fetch of exp, is f right here. 267 00:13:23,350 --> 00:13:25,568 因此这个指令没理由存在 So there's no reason why this instruction should say that. 268 00:13:25,700 --> 00:13:28,880 应该改为:要把F赋值给EXP It should say, we'll assign to exp, f. 269 00:13:29,450 --> 00:13:31,088 或者实际上 你完全不需要EXP Or in fact, you don't need exp at all. 270 00:13:31,875 --> 00:13:33,560 没有理由需要EXP There's no reason it should have exp at all. 271 00:13:33,560 --> 00:13:35,168 EXP是用来做什么的? What, what did exp get used for? 272 00:13:35,184 --> 00:13:36,330 我们看这里 Well, if we come down here 273 00:13:40,770 --> 00:13:42,208 我们对VAL赋值 we're going to assign to val 274 00:13:43,050 --> 00:13:47,344 在环境里的EXP里寻找东西 look up the stuff in exp in the environment. 275 00:13:48,680 --> 00:13:49,536 因此 我们实际上是要 So what we really should do 276 00:13:49,552 --> 00:13:51,540 替换掉所有的EXP寄存器 get rid of the exp register altogether 277 00:13:51,540 --> 00:13:53,328 把这个指令修改为 and just change this instruction to say, 278 00:13:53,344 --> 00:13:54,160 给VAL赋值 assign to val 279 00:13:54,450 --> 00:13:56,064 在环境中查找 look up the variable value 280 00:13:56,368 --> 00:13:58,400 符号F的值 of the symbol f in the environment. 281 00:14:01,090 --> 00:14:01,776 类似地 Similarly 282 00:14:02,570 --> 00:14:04,272 回到这里 我们也完全不需要UNEV back up here, we don't need unev at all 283 00:14:04,720 --> 00:14:05,792 因为我们知道 because we know 284 00:14:06,225 --> 00:14:09,160 因为我们知道 (FETCH EXP)取出的运算对象 what the operands of fetch of exp are for this piece of code. 285 00:14:09,160 --> 00:14:10,624 就是'(X) It's the, it's the list x. 286 00:14:13,250 --> 00:14:14,064 从某种意义上来说 So in some sense 287 00:14:16,170 --> 00:14:19,392 你完全不需要UNEV和EXP you don't want unev and exp at all. 288 00:14:19,670 --> 00:14:21,056 看看它们实际上是什么 See, what they really are in some sense, 289 00:14:21,088 --> 00:14:25,300 它们不是实际运行机器的寄存器 those aren't registers of the actual machine that's supposed to run. 290 00:14:25,300 --> 00:14:26,400 它们实际上是 Those are registers 291 00:14:26,608 --> 00:14:29,504 为了模拟该机器的而设置的寄存器 that have to do with arranging the thing that can simulate that machine. 292 00:14:30,720 --> 00:14:33,776 所以它们保存一些表达式 So they're always going to hold expressions 293 00:14:34,000 --> 00:14:36,048 以编译器的视角看来 which from the compiler's point of view, 294 00:14:36,064 --> 00:14:36,816 它们就是常量 are just constants, 295 00:14:36,950 --> 00:14:38,480 因此可以直接把它们放到代码中 so can be put right into the code. 296 00:14:39,470 --> 00:14:41,344 你可以忘掉那些关于 So you can forget about all the operations 297 00:14:41,360 --> 00:14:42,544 EXP和UNEV的操作 worrying about exp and unev 298 00:14:42,576 --> 00:14:43,776 只用那些常量 and just use those constants. 299 00:14:44,025 --> 00:14:48,000 与之相似 如果我们回顾这里 Similarly, again, if we go, go back and look here 300 00:14:48,000 --> 00:14:51,328 有像(ASSIGN CONTINUE EVAL-ARGS)之类的语句 there are things like assign to continue eval-args. 301 00:14:53,750 --> 00:14:55,392 现在 它和任何东西都没有关系 Now, that has nothing to do with anything. 302 00:14:55,620 --> 00:14:57,760 它只是求值器 That was just the evaluator 303 00:14:58,080 --> 00:15:00,176 维护了下一步需要去哪 keeping track of where it should go next 304 00:15:02,700 --> 00:15:05,968 在某些应用中对参数进行求值 to evaluate the arguments in some, in some application. 305 00:15:06,825 --> 00:15:08,650 当然 这与编译器没关系 But of course, that's irrelevant to the compiler, 306 00:15:08,650 --> 00:15:13,888 因为这个分析过程已经被编译器做完了 because you-- the analysis phase will have already done that. 307 00:15:15,050 --> 00:15:16,832 所以编译后的代码完全不需要它 So this is completely irrelevant. 308 00:15:17,700 --> 00:15:19,328 因此许多向CONTINUE寄存器 So a lot of these, these assignments 309 00:15:19,328 --> 00:15:21,300 赋值的操作都是无用的 to continue have not to do 310 00:15:21,300 --> 00:15:24,624 运行着的机器留着它们 where the running machine is supposed to continue 311 00:15:24,640 --> 00:15:25,776 是为了跟踪它的状态 in keeping track of its state. 312 00:15:26,075 --> 00:15:28,725 是为了知道求值器的下一步分析 It has to, to do with where the evaluator analysis should continue 313 00:15:28,720 --> 00:15:30,032 而它们是完全无关的 and those are completely irrelevant. 314 00:15:30,064 --> 00:15:31,232 因此我们可以去掉它们 So we can get rid of them. 315 00:15:43,900 --> 00:15:45,984 那么 如果我们简单地 Ok, well, if we, if we simply do that, 316 00:15:46,160 --> 00:15:47,750 进行这类优化 make those kinds of optimizations 317 00:15:47,750 --> 00:15:51,648 不再考虑EXP和UNEV get rid, get rid of worrying about exp and unev 318 00:15:51,750 --> 00:15:56,224 去掉这些无关的寄存器赋值 and get rid of these irrelevant register assignments to continue 319 00:15:57,250 --> 00:15:59,968 我们就可以找到这些代码 then we can take this literal code 320 00:16:01,480 --> 00:16:06,208 也就是求值器会执行的这19条指令 these sort of 19 instructions that the evaluator would have done 321 00:16:06,912 --> 00:16:08,128 给替换掉 and then replace them. 322 00:16:08,360 --> 00:16:10,336 请看幻灯片 Let's look at the, at the slide. 323 00:16:12,270 --> 00:16:15,344 我们去掉了大概一半 Replace them by--we get rid of about half of them. 324 00:16:18,288 --> 00:16:20,752 同样 这就是某种过滤 And again, this is just sort of filtering 325 00:16:21,070 --> 00:16:24,464 把无关的东西去掉 what the evaluator would have done by getting rid of the irrelevant stuff. 326 00:16:25,170 --> 00:16:26,224 你们看 比如说 And you see, for instance 327 00:16:27,470 --> 00:16:29,664 这里 求值器说 here the--where the evaluator said, 328 00:16:29,680 --> 00:16:32,432 (ASSIGN VAL (LOOKUP 'F (FETCH ENV))) assign val, look up variable value, fetch of exp 329 00:16:32,464 --> 00:16:34,224 这里 我们放入了一个常量F here we have put in the constant f. 330 00:16:35,440 --> 00:16:37,024 这里又放了一个常量X Here we've put in the constant x. 331 00:16:40,020 --> 00:16:42,416 因此 这个编译器又稍微好一点 So there's a, there's a little better compiler. 332 00:16:43,790 --> 00:16:46,768 但它还是比较蠢 It's still pretty dumb. 333 00:16:47,950 --> 00:16:49,584 它仍会做很多蠢事 It's still doing a lot of dumb things. 334 00:16:50,450 --> 00:16:52,528 我们再看幻灯片 Again, if we go look at the slide again 335 00:16:52,880 --> 00:16:53,936 看最开头的地方 look at the very beginning here 336 00:16:56,340 --> 00:16:58,176 我们调用(SAVE ENV)保存环境 we see a save the environment 337 00:16:59,350 --> 00:17:01,728 然后给VAL寄存器赋某个值 assign something to the val register 338 00:17:01,800 --> 00:17:03,350 然后恢复环境 and restore the environment. 339 00:17:03,350 --> 00:17:04,416 它是从哪来的 Where'd that come from? 340 00:17:04,910 --> 00:17:07,104 它来自求值器的这个地方 That came from the evaluator back here saying 341 00:17:07,152 --> 00:17:10,288 哦 我在正在对一个应用求值 oh, I'm in the middle of evaluating an application. 342 00:17:11,100 --> 00:17:14,688 因此我要递归调用EVAL-DISPATCH So I'm going to recursively call eval dispatch. 343 00:17:15,872 --> 00:17:17,984 我最好把接下来要用到的东西 So I'd better save the thing I'm going to need later, 344 00:17:17,984 --> 00:17:19,088 保存到环境中 which is the environment. 345 00:17:19,770 --> 00:17:22,864 这就是递归调用EVAL-DISPATCH的结果 This was the result of recursively calling eval dispatch. 346 00:17:23,472 --> 00:17:25,776 刚才那个例子就是对符号F求值的结果 It was evaluating the symbol f in that case. 347 00:17:26,500 --> 00:17:28,272 从EVAL-DISPATCH中返回 Then it came back from eval dispatch, 348 00:17:28,288 --> 00:17:29,664 将环境恢复 restored the environment. 349 00:17:31,250 --> 00:17:32,288 但是实际上 But in fact, 350 00:17:32,590 --> 00:17:35,888 这个求值过程中 所进行的操作 the actual thing it ended up doing in the evaluation 351 00:17:35,920 --> 00:17:37,712 完全不会影响环境 is not going to hurt the environment at all. 352 00:17:38,670 --> 00:17:40,800 所以这里没必要先保存环境 So there's no reason to be saving the environment 353 00:17:40,848 --> 00:17:42,220 再恢复环境 and restoring the environment here. 354 00:17:45,670 --> 00:17:46,624 与之类似 Similarly 355 00:17:49,792 --> 00:17:51,392 这里 我们保存了参数表 here I'm saving the argument list. 356 00:17:53,070 --> 00:17:55,808 那是一个求值参数的循环 That's a piece of the argument evaluation loop, 357 00:17:55,824 --> 00:17:56,864 先保存参数表 saving the argument list 358 00:17:57,200 --> 00:17:58,032 然后在这里恢复 and here you restore it. 359 00:17:58,080 --> 00:18:00,512 但事实上最后 But the actual thing that you ended up doing 360 00:18:00,800 --> 00:18:02,288 并没有变更参数表 didn't trash the argument list. 361 00:18:02,840 --> 00:18:04,176 所以不需要保存它 So there was no reason to save it. 362 00:18:08,650 --> 00:18:12,880 换种方式来说 So another way to say, another way to say that 363 00:18:13,770 --> 00:18:14,800 怎么说呢 is that the, 364 00:18:16,432 --> 00:18:19,136 求值器需要最大限度地保持悲观 the evaluator has to be maximally pessimistic 365 00:18:19,870 --> 00:18:21,072 因为 从它的视角来看 because as far from its point of view 366 00:18:21,088 --> 00:18:23,060 只知道接下来是要对某些东西进行求值 it's just going off to evaluate something. 367 00:18:23,248 --> 00:18:24,976 所以最好把稍后要用的都存下来 So it better save what it's going to need later. 368 00:18:26,120 --> 00:18:27,792 一旦你完成了分析 But once you've done the analysis, 369 00:18:27,824 --> 00:18:29,680 从编译器的角度就会考虑 the compiler is in a position to say 370 00:18:29,728 --> 00:18:31,472 哪些是我真正需要存下来的? well, what actually did I need to save? 371 00:18:32,120 --> 00:18:33,312 我们需要去 -- And doesn't need to do any-- 372 00:18:33,424 --> 00:18:37,300 它不需要像求值器一样小心翼翼 it doesn't need to be as careful as the evaluator 373 00:18:37,300 --> 00:18:38,800 因为它知道 实际需要什么 because it knows what it actually needs 374 00:18:39,690 --> 00:18:41,168 无论如何 如果我们完成了优化 Well, in any case, if we do that 375 00:18:42,500 --> 00:18:45,712 消除掉所有多余的保存和恢复 and eliminate all those redundant saves and restores 376 00:18:46,400 --> 00:18:49,056 那么我们可以得到这样的结果 then we can get it down to this. 377 00:18:49,900 --> 00:18:51,536 我们可以发现 And you see there are actually only three 378 00:18:51,648 --> 00:18:53,712 只有三条指令是必须的 only three instructions that we actually need 379 00:18:54,070 --> 00:18:55,728 从刚才的11条指令优化成这样 down from the initial 11 or so 380 00:18:55,970 --> 00:18:58,816 或是从原始的20条指令优化而来 or the initial 20 or so in the original one. 381 00:18:59,870 --> 00:19:00,928 这告诉我们 And that's just saying, 382 00:19:01,120 --> 00:19:03,184 对于这些寄存器操作 of those register operations 383 00:19:03,270 --> 00:19:04,944 哪些是必需的? which ones did we actually need? 384 00:19:09,420 --> 00:19:11,744 让我换个方式来总结一下 Let me just sort of summarize that in another way, 385 00:19:11,744 --> 00:19:13,488 我先给你们看一张图 just to show you in a little better picture. 386 00:19:16,000 --> 00:19:17,520 这张图片 Here's a picture of starting-- 387 00:19:18,770 --> 00:19:20,816 展示了所有的保存和恢复 This is looking at all the saves and restores. 388 00:19:23,500 --> 00:19:25,232 这里是表达式(F X) So here's the expression, f of x 389 00:19:25,320 --> 00:19:27,872 在下面这里 and then this traces through, on the bottom here 390 00:19:28,750 --> 00:19:31,808 是对求值器中各种地方的跟踪 the various places in the evaluator 391 00:19:34,975 --> 00:19:38,040 在求值发生时会使用这些地方 that were passed when the evaluation happened. 392 00:19:38,040 --> 00:19:40,016 在这里 你可以看到箭头 And then here, here you see arrows. 393 00:19:40,220 --> 00:19:42,080 下箭头代表寄存器的保存 Arrow down means register saved. 394 00:19:42,400 --> 00:19:44,848 所以最先保存的是ENV寄存器 So the first thing that happened is the environment got saved. 395 00:19:46,820 --> 00:19:48,688 然后 在这里恢复ENV And over here, the environment got restored. 396 00:19:52,384 --> 00:19:54,540 这些都是成对的栈操作 so there are all the pairs of stack operations. 397 00:19:56,120 --> 00:19:57,568 如果你更进一步 Now, if you go ahead and say 398 00:19:58,125 --> 00:20:00,780 我们记得 well, let's remember that we don't--that unev 399 00:20:00,896 --> 00:20:03,024 UNEV是个完全没用的寄存器 for instance, is a completely useless register. 400 00:20:07,800 --> 00:20:09,780 如果我们用固定结构的代码 And if we use the constant structure of the code 401 00:20:09,780 --> 00:20:12,528 就不需要保存UNEV 因为完全用不上 well, we don't need, we don't need to save unev. 402 00:20:16,200 --> 00:20:19,152 然后 根据我们约定的 And then, depending on how we set up the discipline of the-- 403 00:20:19,160 --> 00:20:21,888 应用过程的准则 of calling other things that apply, 404 00:20:21,888 --> 00:20:23,850 我们会选择是否保存CONTINUE we may or may not need to save continue. 405 00:20:27,400 --> 00:20:28,740 这就是我们做的第一件事 That's the first step I did. 406 00:20:28,740 --> 00:20:30,512 然后我们可以看看 And then we can look and see what's actually, 407 00:20:31,712 --> 00:20:32,704 实际需要些什么 what's actually needed. 408 00:20:33,070 --> 00:20:35,568 其实在求值F的过程中 See, we don't-- didn't really need to save env 409 00:20:36,040 --> 00:20:37,824 我们不需要保存ENV across-evaluating f 410 00:20:38,088 --> 00:20:39,920 因为它不会被破坏 because it wouldn't, it wouldn't trash it. 411 00:20:39,920 --> 00:20:41,312 因此 如果我们利用这点 So if we take advantage of that 412 00:20:44,120 --> 00:20:47,568 这里对F的求值 and see the evaluation of f here 413 00:20:48,570 --> 00:20:50,448 完全不需要担心 doesn't really need to worry about, 414 00:20:51,616 --> 00:20:52,600 会破坏ENV about hurting env. 415 00:20:52,600 --> 00:20:54,944 类似地 这里对X的求值 And similarly, the evaluation of x here 416 00:20:57,170 --> 00:20:58,896 当求值器进行求值时 它会说 when the evaluator did that it said 417 00:20:58,912 --> 00:21:01,648 我最好保存好与之有关的FUN寄存器 Oh, I'd better preserve the function register around that 418 00:21:02,072 --> 00:21:03,220 因为后面也许会用得着 because I might need it later. 419 00:21:03,280 --> 00:21:04,896 我最好也保存参数表 And I better preserve the argument list. 420 00:21:06,900 --> 00:21:09,056 然而 在这如果是编译器的话 Whereas the compiler is now in a position to know 421 00:21:09,050 --> 00:21:10,384 实际需要哪些寄存器 well, we didn't really need to save-- 422 00:21:10,528 --> 00:21:11,840 从而进行相关的保存与恢复 to do those saves and restores. 423 00:21:12,700 --> 00:21:16,096 事实上 这里求值器做的所有栈操作 So in fact, all of the stack operations done by the evaluator 424 00:21:16,320 --> 00:21:19,584 都证明是过于悲观而不必要 turned out to be unnecessary or overly pessimistic. 425 00:21:19,620 --> 00:21:21,456 而编译器在这里是知道这一点的 And the compiler is in a position to know that. 426 00:21:27,350 --> 00:21:28,480 这是最基础的想法 Well that's the basic idea. 427 00:21:29,800 --> 00:21:31,000 我们把求值器 We take the evaluator 428 00:21:31,000 --> 00:21:33,240 剔除那些不需要的东西 we eliminate the things that you don't need 429 00:21:33,240 --> 00:21:35,240 去除那些对于编译器完全无用的东西 that in some sense have nothing to do with the compiler at all 430 00:21:35,240 --> 00:21:36,192 只保留求值的部分 just the evaluator 431 00:21:37,408 --> 00:21:40,400 然后你可以看到哪些栈操作是不必要的 and then you see which stack operations are unnecessary. 432 00:21:40,820 --> 00:21:43,760 这就是书中所描述的编译器 That's the basic structure of the compiler that's 433 00:21:43,856 --> 00:21:45,040 的基本结构 that's described in the book. 434 00:21:45,040 --> 00:21:47,008 我给你们展示一下这 Let me just show you how a 435 00:21:47,760 --> 00:21:49,680 这个简单的例子 that examples a little bit too simple. 436 00:21:51,200 --> 00:21:53,264 为了说清楚 多余的东西是怎样保存的 To see how you, how you actually save a lot 437 00:21:53,296 --> 00:21:56,064 我们来看一个稍复杂的表达式 let's look at a little bit more complicated expression. 438 00:21:58,150 --> 00:22:01,936 (F (G X) 1) (F (G X) 1) 439 00:22:03,870 --> 00:22:05,520 我们不会讲解所有的代码 And I'm not going to go through all the code. 440 00:22:06,400 --> 00:22:08,560 因为代码有点多 There's a, there's a fair pile of it. 441 00:22:09,725 --> 00:22:12,350 我认为在求值器在处理它时 I think there are, there are something like 16 442 00:22:12,350 --> 00:22:14,672 大概会产生 16 pairs of register saves and restores 443 00:22:14,704 --> 00:22:16,256 16对保存-恢复操作 as the evaluator walks through that. 444 00:22:17,000 --> 00:22:18,576 这有一张图表 Here's a diagram of them. 445 00:22:20,570 --> 00:22:21,952 演示了其中的过程 Let's see. You see what's going on. 446 00:22:22,970 --> 00:22:23,904 你从这里开始-- You start out by-- 447 00:22:24,250 --> 00:22:26,624 求值器说:“我要求值一个应用” the evaluator says, oh, I'm about to do an application. 448 00:22:26,900 --> 00:22:29,136 在这里保存ENV 又在这里恢复 I'll preserve the environment. I'll restore it here. 449 00:22:30,650 --> 00:22:34,448 然后处理第一个运算对象 Then I'm about to do the first operand. 450 00:22:36,816 --> 00:22:39,280 这是求值器的递归调用 Here it recursively goes to the evaluator. 451 00:22:39,280 --> 00:22:40,896 求值器发现 这是一个应用 The evaluator says, oh, this is an application, 452 00:22:40,912 --> 00:22:42,100 又会保存环境 I'll save the environment 453 00:22:42,100 --> 00:22:44,976 求值组合式的运算符 然后在这里恢复环境 do the operator of that combination, restore it here. 454 00:22:45,800 --> 00:22:48,928 这个恢复匹配的是这个保存操作 This save--this restore matches that save. 455 00:22:49,770 --> 00:22:50,784 以此类推 And so on. 456 00:22:51,650 --> 00:22:52,512 这里的UNEV There's unev here, 457 00:22:52,528 --> 00:22:54,620 完全没有必要存在 which turns out to be completely unnecessary 458 00:22:54,970 --> 00:22:56,608 CONTINUE寄存器不断地被保存-恢复 continues getting bumped around here. 459 00:22:57,420 --> 00:23:00,416 而FUN寄存器则是在 The function register is getting, getting saved 460 00:23:00,784 --> 00:23:04,368 处理运算对象期间被保存 across the first operands, across the operands. 461 00:23:05,100 --> 00:23:06,528 这类的事情一直在发生 All sorts of things are going on. 462 00:23:06,782 --> 00:23:09,390 但如果你问 跟求值器相比 But if you say, well, what of those really were the business of 463 00:23:09,872 --> 00:23:11,664 编译器究竟要做什么? the compiler as opposed to the evaluator 464 00:23:12,270 --> 00:23:13,552 你会去掉一大堆东西 you get rid of a whole bunch. 465 00:23:14,300 --> 00:23:16,640 在这个的基础上 如果你说 And then on top of that, if you say things like 466 00:23:19,400 --> 00:23:22,544 对F的求值不会修改ENV寄存器 the evaluation of F doesn't hurt the environment register, 467 00:23:23,820 --> 00:23:26,512 或者对符号X的查找 or simply looking up the symbol X, 468 00:23:29,280 --> 00:23:32,096 不需要特别保护FUN寄存器 you don't have to protect the function register against that. 469 00:23:34,300 --> 00:23:37,600 就得到了只有几对的保存-恢复操作 So you come down to just a couple of, a couple of pairs here. 470 00:23:40,250 --> 00:23:42,275 然而 你还可以再优化一下 And still, you can do a little better. 471 00:23:42,275 --> 00:23:44,330 看看这里的ENV寄存器发生了什么 Look what's going on here with the environment register. 472 00:23:45,210 --> 00:23:47,392 我们观察ENV寄存器的操作 发现 The environment register comes along and says, oh, 473 00:23:51,000 --> 00:23:52,256 这是一个组合式 here's a combination. 474 00:23:54,336 --> 00:23:55,696 而这个求值器 This evaluator, by the way, 475 00:23:55,780 --> 00:23:57,270 对G一无所知 doesn't know anything about G. 476 00:23:58,570 --> 00:24:00,736 所以在这 它说 So here it says, so it says, 477 00:24:01,296 --> 00:24:03,456 我最好保存ENV寄存器 I'd better save the environment register, 478 00:24:03,968 --> 00:24:05,424 因为对G的求值 because evaluating G might be 479 00:24:05,424 --> 00:24:07,424 可能会修改ENV寄存器的值 some arbitrary piece of code that would trash it 480 00:24:07,550 --> 00:24:09,456 而我稍后可能会需要它 and I'm going to need it later, 481 00:24:10,176 --> 00:24:11,408 在这个参数之后 after this argument, 482 00:24:12,224 --> 00:24:13,376 在处理第二个参数的时候 for doing the second argument. 483 00:24:15,600 --> 00:24:17,248 这就是为什么它没被优化掉 So that's why this one didn't go away, 484 00:24:19,075 --> 00:24:22,540 因为编译器没有对G将要做的事情做任何假设 because the compiler made no assumptions about what G would do. 485 00:24:22,540 --> 00:24:23,600 另一方面 On the other hand, 486 00:24:24,610 --> 00:24:26,528 如果你看看这里的第二个参数 if you look at what the second argument is, 487 00:24:26,640 --> 00:24:27,700 它只是查找“1”这个常量 that's just looking up one. 488 00:24:27,700 --> 00:24:29,600 这不需要ENV寄存器 That doesn't need this environment register. 489 00:24:30,770 --> 00:24:32,048 因此没必要保存它 So there's no reason to save it. 490 00:24:32,064 --> 00:24:33,776 事实上 你也可以把这个也去掉 So in fact, you can get rid of that one, too. 491 00:24:34,850 --> 00:24:37,810 这一堆寄存器操作 And from this whole pile of, of register operations, 492 00:24:37,984 --> 00:24:40,080 如果你像这样简单地推理的话 if you simply do a little bit of reasoning like that, 493 00:24:40,550 --> 00:24:43,056 只会剩下两对保存-恢复操作 you get down to, I think, just two pairs of saves and restores. 494 00:24:45,104 --> 00:24:46,976 而这些 如果你知道关于G的某些信息的话 And those, in fact, could go away further if you, 495 00:24:47,520 --> 00:24:49,088 可以进一步优化 if you knew something about G. 496 00:24:56,270 --> 00:24:57,856 基本的理念是 So again, the general idea 497 00:24:57,950 --> 00:24:59,980 编译器之所以更好 is that the reason the compiler can be better 498 00:24:59,980 --> 00:25:02,560 是因为解释器对于将要处理的东西一无所知 is that the interpreter doesn't know what it's about to encounter. 499 00:25:03,250 --> 00:25:05,040 它不得不以最悲观的方式保存东西 It has to be maximally pessimistic 500 00:25:05,056 --> 00:25:06,704 来保护它自己 to protect itself. 501 00:25:07,900 --> 00:25:08,768 而编译器 The compiler 502 00:25:09,488 --> 00:25:12,384 只需要保存实际需要的东西 only has to deal with what actually had to be saved. 503 00:25:13,370 --> 00:25:15,200 某个东西是否需要保存 And there are two reasons that something 504 00:25:15,248 --> 00:25:17,370 有两种原因 might not have to be saved. 505 00:25:17,820 --> 00:25:18,700 一种是 One is that 506 00:25:18,700 --> 00:25:19,824 你保护的东西 what you're protecting it against, 507 00:25:19,952 --> 00:25:21,440 不会修改寄存器 in fact, didn't trash the register, 508 00:25:22,080 --> 00:25:23,584 例如 变量查找 like it was just a variable look-up. 509 00:25:24,120 --> 00:25:25,200 另一种原因是 And the other one is, 510 00:25:25,320 --> 00:25:27,104 你所保存的东西 that the thing that you were saving it for 511 00:25:28,288 --> 00:25:29,920 最后并不会被用到 might turn out not to actually need it. 512 00:25:30,810 --> 00:25:34,272 因此 编译器正是利用了 So those are the two basic pieces of knowledge 513 00:25:34,304 --> 00:25:35,880 这两条基本原则 that the compiler can take advantage of 514 00:25:36,272 --> 00:25:37,760 来让代码变得更高效的 in making the code more efficient. 515 00:25:44,270 --> 00:25:45,328 有什么问题吗? Let's break for questions. 516 00:25:51,200 --> 00:25:53,100 学生: 你一直在说UNEV寄存器 AUDIENCE: You kept saying that the uneval register, 517 00:25:53,130 --> 00:25:56,400 UNEV寄存器完全不会被用到 unev register didn't need to be used at all. 518 00:25:56,416 --> 00:25:58,688 是否意味着 机器只需要6个寄存器足矣? Does that mean that you could just map a six-register machine? 519 00:25:58,700 --> 00:26:00,080 或者是说 在这个特定的例子里 Or is that, in this particular example, 520 00:26:00,112 --> 00:26:01,180 它没有被用到? it didn't need to be used? 521 00:26:01,725 --> 00:26:02,810 教授: 对于编译器 PROFESSOR: For the compiler, 522 00:26:04,310 --> 00:26:07,424 你可以生成6个或5个寄存器的代码 you could generate code for the six-register, five, right? 523 00:26:07,568 --> 00:26:09,024 因为EXP寄存器也没有用到 Because that exp goes away also. 524 00:26:09,408 --> 00:26:14,570 是的 你可以把EXP和UNEV都去掉 Assuming--yeah, you can get rid of both exp and unev 525 00:26:14,575 --> 00:26:16,875 因为这些是求值器的数据结构 because, see, those are data structures of the evaluator. 526 00:26:17,360 --> 00:26:19,360 以编译器的视角来看 Those are all things that would be constants 527 00:26:19,392 --> 00:26:20,870 这些东西都是常量 from the point of view of the compiler. 528 00:26:21,650 --> 00:26:22,448 关键在于 The only thing is 529 00:26:22,480 --> 00:26:24,592 这个特定编译器是被构造出来的 this particular compiler is set up 530 00:26:24,790 --> 00:26:27,920 因此被解释的代码和被编译的代码可以共存 so that interpreted code and compiled code can coexist. 531 00:26:29,320 --> 00:26:30,720 可以这样看待它 So the way to think about it is, 532 00:26:30,970 --> 00:26:32,290 你构建了一个芯片 is maybe you build a chip 533 00:26:34,300 --> 00:26:35,500 它就是求值器 which is the evaluator, 534 00:26:35,880 --> 00:26:37,280 而编译器可以做的就是 and what the compiler might do 535 00:26:37,312 --> 00:26:39,024 为这个芯片生成代码 is generate code for that chip. 536 00:26:40,400 --> 00:26:41,904 只是它不会用到两个寄存器而已 It just wouldn't use two of the registers. 537 00:26:51,520 --> 00:26:52,470 好 休息一会 All right, let's take a break. 538 00:26:53,550 --> 00:27:07,184 [音乐] [JESU, JOY OF MAN'S DESIRING] 539 00:27:07,370 --> 00:27:11,424 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 540 00:27:14,570 --> 00:27:18,128 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 541 00:27:18,170 --> 00:27:22,080 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 542 00:27:22,220 --> 00:27:26,480 编译 Compilation 543 00:27:29,216 --> 00:27:32,432 我们刚才研究了编译器应该要做什么 We just looked at what the compiler is supposed to do. 544 00:27:32,780 --> 00:27:36,048 现在我们来简略地看看 Now let's very briefly look at how, 545 00:27:36,150 --> 00:27:37,472 这些目标如何达成 how this gets accomplished. 546 00:27:38,260 --> 00:27:39,584 而我不会给出细节 And I'm going to give no details. 547 00:27:39,600 --> 00:27:42,176 在书中有一大堆代码 There's, there's a giant pile of code in the book 548 00:27:42,224 --> 00:27:43,420 展示了所有细节 that gives all the details. 549 00:27:43,456 --> 00:27:45,310 我要做的 是给你们展示 But what I want to do is just show you the, 550 00:27:45,968 --> 00:27:47,264 其中的关键思想 the essential idea here. 551 00:27:49,490 --> 00:27:51,360 换个时间再来关心细节 Worry about the details some other time. 552 00:27:51,510 --> 00:27:55,300 设想我们正在编译一条表达式 Let's imagine that we're compiling an expression 553 00:27:55,300 --> 00:27:57,010 这里有一些运算符 that looks like there's some operator 554 00:27:57,480 --> 00:27:58,560 和两个参数 and there are two arguments. 555 00:28:03,560 --> 00:28:04,240 现在 Now, the-- 556 00:28:06,275 --> 00:28:08,140 这个编译器会生成什么代码? what's the code that the compiler should generate? 557 00:28:08,850 --> 00:28:09,780 首先 Well, first of all, 558 00:28:09,830 --> 00:28:11,200 它会递归运行 it should recursively go off 559 00:28:11,900 --> 00:28:13,280 编译运算符 and compile the operator. 560 00:28:14,370 --> 00:28:19,024 它说 我要编译运算符 So it says, I'll compile the operator. 561 00:28:21,160 --> 00:28:24,544 最后我需要让它们的结果 And where I'm going to need that 562 00:28:24,848 --> 00:28:27,950 存放在FUN寄存器中 is to be in the function register, eventually. 563 00:28:28,420 --> 00:28:29,600 所以我编译一些指令 So I'll compile some instructions 564 00:28:29,648 --> 00:28:31,568 它们会编译运算符 that will compile the operator 565 00:28:31,690 --> 00:28:38,624 最后把结果放在FUN寄存器中 and end up with the result in the function register. 566 00:28:45,510 --> 00:28:46,940 接下来我要做的是 The next thing it's going to do, 567 00:28:47,710 --> 00:28:49,680 另一个代码片段则说 another piece is to say, 568 00:28:49,680 --> 00:28:55,175 我要编译第一个参数 I have to compile the first argument. 569 00:28:55,170 --> 00:28:56,800 因此它递归调地用自己 So it calls itself recursively. 570 00:28:58,040 --> 00:29:03,360 而结果会被放在VAL中 And let's say the result will go into val. 571 00:29:09,070 --> 00:29:10,750 接下来需要做的是 And then what it's going to need to do is 572 00:29:10,750 --> 00:29:12,260 建立起参数表 start setting up the argument list. 573 00:29:12,950 --> 00:29:25,504 (ASSIGN ARGL (CONS (FETCH -- So it'll say, assign to argl cons of fetch-- 574 00:29:25,552 --> 00:29:27,104 它会生成这些代码 so it generates this literal instruction-- 575 00:29:27,504 --> 00:29:32,512 (FETCH VAL) '())) fetch of val onto empty list. 576 00:29:35,000 --> 00:29:36,050 然而 However, 577 00:29:37,990 --> 00:29:40,610 当它到这里时 it might have to work-- when it gets here, 578 00:29:41,325 --> 00:29:42,820 它可能需要环境 it's going to need the environment. 579 00:29:43,950 --> 00:29:45,296 它需要环境 It's going to need whatever environment was here 580 00:29:45,328 --> 00:29:48,210 这是求值第一个参数所需要的 in order to do this evaluation of the first argument. 581 00:29:49,040 --> 00:29:51,184 因此 它需要保证 So it has to ensure that 582 00:29:51,920 --> 00:29:53,760 对运算对象的编译 the compilation of this operand, 583 00:29:55,320 --> 00:29:57,850 或者说它需要保护FUN寄存器 or it has to protect the function register 584 00:29:58,016 --> 00:30:00,980 来应对编译运算对象时发生的各种情况 against whatever might happen in the compilation of this operand. 585 00:30:01,300 --> 00:30:03,080 因此它在这做了个标注说 So it puts a note here and says, oh, 586 00:30:03,370 --> 00:30:12,896 这个片段需要保护ENV寄存器 this piece should be done preserving the environment register. 587 00:30:17,390 --> 00:30:18,448 与之类似 这里 Similarly, here, 588 00:30:21,024 --> 00:30:23,300 在完成第一个运算对象的编译后 after it gets done compiling the first operand, 589 00:30:23,570 --> 00:30:24,672 它会说 我最好-- it's going to say, I'd better-- 590 00:30:24,710 --> 00:30:27,925 我需要知道第二个运算对象的环境 I'm going to need to know the environment for the second operand. 591 00:30:27,925 --> 00:30:29,460 所以它在这做了个标注 So it puts a little note here, saying, 592 00:30:29,710 --> 00:30:35,968 这里也需要保护ENV yeah, this is also done preserving env. 593 00:30:39,420 --> 00:30:41,020 现在它继续运行 Now it goes on and says, well, 594 00:30:41,120 --> 00:30:42,832 下一段代码 the next chunk of code 595 00:30:43,312 --> 00:30:49,744 是要编译第二个参数 is the one that's going to compile the second argument. 596 00:30:50,820 --> 00:30:52,640 它将会 And let's say 597 00:30:52,992 --> 00:30:59,280 把编译的结果按约定放入到VAL中 And let's say it'll compile it with a targeted to val, as they say. 598 00:31:03,860 --> 00:31:06,704 随后它会生成一条指令 And then it'll generate the literal instruction, 599 00:31:07,840 --> 00:31:09,250 从而建立起参数表 building up the argument list. 600 00:31:09,550 --> 00:31:15,280 (ASSIGN ARGL So it'll say, assign to argl 601 00:31:20,224 --> 00:31:28,944 (CONS (FETCH VAL) (FETCH ARGL)) cons of the new value it just got onto the old argument list. 602 00:31:33,970 --> 00:31:34,640 然而 However, 603 00:31:34,810 --> 00:31:36,580 为了取得旧的参数表 in order to have the old argument list, 604 00:31:37,150 --> 00:31:40,992 它最好保证这期间发生的任何事情 it better have arranged that the argument list didn't get trashed 605 00:31:41,300 --> 00:31:42,690 都不影响旧的参数表 by whatever happened in here. 606 00:31:43,500 --> 00:31:45,170 因此它在这做了个标注说 So it puts a little note here and says, 607 00:31:45,344 --> 00:31:51,648 哦 这里需要保护ARGL oh, this has to be done preserving argl. 608 00:31:54,160 --> 00:31:56,030 现在参数表就建立好了 Now it's got the argument list set up. 609 00:31:58,016 --> 00:32:02,864 现在可以准备去APPLY-DISPATCH了 And it's all ready to go to apply dispatch. 610 00:32:07,020 --> 00:32:10,800 它生成了这条指令 It generates this literal instruction. 611 00:32:15,190 --> 00:32:17,370 因为现在参数都在ARGL中 Because now it's got the arguments in argl 612 00:32:18,150 --> 00:32:20,590 运算符在FUN中 and the operator in fun, 613 00:32:20,590 --> 00:32:22,890 如果只是单纯地把运算符放到FUN寄存器中 but wait, it's only got the operator in fun 614 00:32:23,270 --> 00:32:26,640 就需要它保证这块代码 if it had ensured that this block of code 615 00:32:27,096 --> 00:32:29,270 不会破坏FUN寄存器里的东西 didn't trash what was in the function register. 616 00:32:29,670 --> 00:32:31,248 所以它在这做了个标注说 So it puts a little note here and says, 617 00:32:31,550 --> 00:32:32,736 这里的所有东西 oh, yes, all this stuff here 618 00:32:34,880 --> 00:32:40,736 最好能够在保护FUN寄存器的情况下完成 had better be done preserving the function register. 619 00:32:43,710 --> 00:32:46,150 所以这就是-- So that's the little--so when it starts ticking-- 620 00:32:46,150 --> 00:32:47,104 基本上来说 so basically, what the 621 00:32:48,200 --> 00:32:50,240 编译器所做的就是 what the compiler does is 622 00:32:50,544 --> 00:32:52,460 追加一大堆的代码 append a whole bunch of code sequences. 623 00:32:53,500 --> 00:32:58,832 而这些代码之中都是一些基本运算 See, what it's got in it is little primitive pieces of things 624 00:32:58,864 --> 00:33:00,128 比如符号查找 like how to look up a symbol, 625 00:33:01,440 --> 00:33:02,608 条件分支的处理 how to do a conditional. 626 00:33:02,640 --> 00:33:05,440 都是一些琐碎的事情 Those are all little pieces of things. 627 00:33:05,440 --> 00:33:07,990 然后按照这种准则将它们追加到一起 And then it appends them together in this sort of discipline. 628 00:33:08,780 --> 00:33:10,790 因此 组合的基本手段就是 So the basic means of combining things 629 00:33:10,864 --> 00:33:13,184 将一段代码追加到另一段的后面 is to append two code sequences. 630 00:33:21,550 --> 00:33:22,864 就是这里发生的事情 That's what's going on here. 631 00:33:25,580 --> 00:33:27,240 这有点取巧 And it's a little bit tricky. 632 00:33:27,560 --> 00:33:30,370 向一段代码后面追加代码的思路是 The idea is that it appends two code sequences, 633 00:33:31,600 --> 00:33:33,760 小心保护寄存器 taking care to preserve a register. 634 00:33:35,630 --> 00:33:37,930 追加操作看起来像这样 So the actual append operation looks like this. 635 00:33:39,150 --> 00:33:40,656 它要做的是 What it wants to do is say, if-- 636 00:33:41,200 --> 00:33:44,110 代码的追加是这么来做的 here's what it means to append two code sequences. 637 00:33:44,530 --> 00:33:53,632 如果SEQ1需要寄存器-- So if sequence one needs register-- 638 00:33:53,664 --> 00:33:54,720 我应该改一下这个 I should change this. 639 00:33:54,725 --> 00:33:56,870 在SEQ1后面追加SEQ2 Append sequence one to sequence two, 640 00:33:57,420 --> 00:34:03,968 并保护一些寄存器 preserving some register. 641 00:34:08,525 --> 00:34:09,910 这里改成AND Let me say, and. 642 00:34:11,360 --> 00:34:13,030 这样的话前后顺序就清楚了 So it's clear that sequence one comes first. 643 00:34:13,888 --> 00:34:19,870 如果SEQ2需要寄存器 So if sequence two needs the register 644 00:34:21,120 --> 00:34:27,856 而SEQ1又修改了寄存器 and sequence one modifies the register, 645 00:34:33,680 --> 00:34:36,304 那么编译器生成的指令是 then the instructions that the compiler spits out, 646 00:34:36,976 --> 00:34:41,344 保存寄存器 are save the register. 647 00:34:43,025 --> 00:34:44,190 这就是代码 Here's the code. 648 00:34:44,350 --> 00:34:45,350 生成这段代码 You generate this code. 649 00:34:45,350 --> 00:34:46,288 保存寄存器 Save the register, 650 00:34:46,725 --> 00:34:52,975 然后写下递归编译SEQ1的结果 and then you put out the recursively compiled stuff for sequence one. 651 00:34:53,300 --> 00:34:54,848 然后恢复寄存器 And then you restore the register. 652 00:35:00,520 --> 00:35:03,920 再写下递归编译 And then you put out the recursively compiled stuff 653 00:35:04,464 --> 00:35:05,472 SEQ2的结果 for sequence two. 654 00:35:07,075 --> 00:35:09,625 这就是你需要做的 That's in the case where you need to do it. 655 00:35:09,625 --> 00:35:11,820 实际上SEQ2需要寄存器 Sequence two actually needs the register, 656 00:35:11,820 --> 00:35:13,744 而SEQ1改动了它 and sequence one actually clobbers it. 657 00:35:15,120 --> 00:35:17,072 否则的话 So that's sort of if. Otherwise, 658 00:35:20,500 --> 00:35:26,576 得到的就是SEQ1后面跟着SEQ2 all you spit out is sequence one followed by sequence two. 659 00:35:28,170 --> 00:35:30,304 这就是把两个代码片段 So that's the basic operation 660 00:35:30,592 --> 00:35:33,520 连接到一起的基本操作 for sticking together these bits of code fragments, 661 00:35:33,935 --> 00:35:35,935 把这些指令组合成序列 these bits of instructions into a sequence. 662 00:35:36,890 --> 00:35:38,870 我们可以发现 从这个角度看 And you see, from this point of view, 663 00:35:40,940 --> 00:35:45,960 解释器和编译器的区别 the difference between the interpreter and the compiler, in some sense, 664 00:35:46,825 --> 00:35:49,340 是编译器有保护寄存器的标注 is that where the compiler has these preserving notes, 665 00:35:50,140 --> 00:35:52,224 上面记录着 and says, maybe I'll actually generate the 666 00:35:52,496 --> 00:35:54,220 是否需要生成保存-恢复代码 saves and restores and maybe I won't, 667 00:35:55,190 --> 00:35:57,248 而解释器会以最悲观的方式处理 the interpreter being maximally pessimistic 668 00:35:57,280 --> 00:35:58,900 总是会进行保存-恢复 always has a save and restore here. 669 00:36:00,768 --> 00:36:01,930 这就是关键的区别 That's the essential difference. 670 00:36:04,160 --> 00:36:06,050 为了实现这个 Well, in order to do this, of course, 671 00:36:06,650 --> 00:36:09,408 编译器需要一些理论 the compiler needs some theory of 672 00:36:09,568 --> 00:36:11,968 来确定代码序列会需要、又会修改哪些寄存器 what code sequences need and modifier registers. 673 00:36:14,260 --> 00:36:17,280 所以你放入的小片段 So the tiny little fragments that you put in, like 674 00:36:17,480 --> 00:36:21,008 例如这段基础代码 the basic primitive code fragments, 675 00:36:22,740 --> 00:36:24,592 当你查找一个变量时 say, what are the operations that you do 676 00:36:24,928 --> 00:36:26,048 进行了哪些操作? when you look up a variable? 677 00:36:26,890 --> 00:36:29,024 你又是做了些什么 What are the sequence of things that you do 678 00:36:29,056 --> 00:36:30,688 来编译一个常量 when you compile a constant 679 00:36:30,976 --> 00:36:32,100 或者应用一个函数 or apply a function? 680 00:36:32,970 --> 00:36:34,480 它们都会带有一些标注 Those have little notations in there 681 00:36:34,672 --> 00:36:36,464 说明了它们需要的和修改的寄存器 about what they need and what they modify. 682 00:36:38,780 --> 00:36:41,500 所以底层的数据结构 So the bottom-level data structures-- 683 00:36:42,660 --> 00:36:44,330 我会这样讲 Well, I'll say this. 684 00:36:44,390 --> 00:36:47,910 传递给编译器的代码序列大概是这样 A code sequence to the compiler looks like this. 685 00:36:48,070 --> 00:36:51,424 它里面有实际的指令序列 It has the actual sequence of instructions. 686 00:36:55,670 --> 00:36:56,816 跟它一起的还有 And then, along with it, 687 00:36:57,184 --> 00:37:02,608 一组被修改的寄存器 there's the set of registers modified. 688 00:37:10,540 --> 00:37:12,608 还有一组需要的寄存器 And then there's the set of registers needed. 689 00:37:20,000 --> 00:37:22,464 为了能够执行此操作 So that's the information the compiler has 690 00:37:23,000 --> 00:37:26,416 编译器必须要掌握这些信息 that it draws on in order to be able to do this operation. 691 00:37:29,300 --> 00:37:31,088 它们从哪来呢 And where do those come from? Well. 692 00:37:32,910 --> 00:37:34,496 它们来自于--你们可能也想到了 Well, those come from, you might expect, 693 00:37:34,512 --> 00:37:35,536 对于那些最基本的片段 for the very primitive ones, 694 00:37:35,552 --> 00:37:36,840 我们会手工添加 we're going to put them in by hand. 695 00:37:37,240 --> 00:37:38,864 然后 当我们组合两个序列时 And then, when we combine two sequences, 696 00:37:38,896 --> 00:37:41,020 我们会计算出这两个集合 we'll figure out what these things should be. 697 00:37:42,160 --> 00:37:44,128 举一个非常基本的例子 So for example, a very primitive one, let's see. 698 00:37:48,430 --> 00:37:51,408 例如做一个寄存器赋值 How about doing a register assignment. 699 00:37:51,770 --> 00:37:53,504 因此 基本代码片段会说 So a primitive sequence might say, 700 00:37:53,520 --> 00:37:56,220 噢 它是个代码片段 oh, it's code fragment. 701 00:37:56,225 --> 00:38:03,175 代码的指令部分是(ASSIGN R1 (FETCH R2)) Its code instruction is assigned to R1, fetch of R2. 702 00:38:03,170 --> 00:38:04,272 这个例子就是这样的 So this is an example. 703 00:38:05,425 --> 00:38:08,520 一段指令序列大概就是这样 That might be an example of a sequence of instructions. 704 00:38:08,770 --> 00:38:10,530 和它在一起的是 And along with that, it'll say, Oh 705 00:38:10,640 --> 00:38:15,760 它需要记得修改了R1 oh, what I need to remember is that that modifies R1 706 00:38:18,600 --> 00:38:21,168 然后它需要R2 and then it needs R2. 707 00:38:24,690 --> 00:38:26,992 因此当你开始构建编译器时 So when you're first building this compiler, 708 00:38:27,100 --> 00:38:29,350 你放入这样的一个片段 you put in little fragments of stuff like that. 709 00:38:30,950 --> 00:38:33,200 当它组合两个序列时 And now, when it combines two sequences, 710 00:38:36,704 --> 00:38:38,048 我要组合 if I'm going to combine, 711 00:38:38,920 --> 00:38:41,584 代码片段S1 let's say, sequence one, 712 00:38:42,880 --> 00:38:47,168 修改了一组寄存器M1 that modifies a bunch of registers M1, 713 00:38:48,450 --> 00:38:51,420 并且需要一组寄存器N1 and needs a bunch of registers N1. 714 00:38:54,850 --> 00:38:59,488 并且我要把它和序列S2组合到一起 And I'm going to combine that with sequence two. 715 00:39:00,810 --> 00:39:05,968 后者修改了一组寄存器M2 That modifies a bunch of registers M2, 716 00:39:07,110 --> 00:39:10,000 并且需要一组寄存器N2 and needs a bunch of registers N2. 717 00:39:12,440 --> 00:39:14,830 这样我们就能得出结果 Then, well, we can reason it out. 718 00:39:15,110 --> 00:39:16,320 新的代码片段是这样的 The new code fragment, 719 00:39:17,184 --> 00:39:21,824 指令序列S1后面跟着S2 sequence one, and-- followed by sequence two, 720 00:39:24,090 --> 00:39:26,450 它要修改什么? well, what's it going to modify? 721 00:39:27,800 --> 00:39:29,184 它要修改的是 The things that it will modify are the things 722 00:39:29,200 --> 00:39:32,688 被S1或者被S2修改的寄存器 that are modified either by sequence one or sequence two. 723 00:39:34,000 --> 00:39:36,352 N1和N2的并集 So the union of these two 724 00:39:37,680 --> 00:39:39,640 就是新的修改集 sets are what the new thing modifies. 725 00:39:40,460 --> 00:39:41,790 然后你问 And then you say, well, what is this-- 726 00:39:44,660 --> 00:39:46,416 又需要哪些寄存器? what registers is it going to need? 727 00:39:47,950 --> 00:39:49,776 需要这些寄存器的是 It's going to need the things that are, 728 00:39:49,930 --> 00:39:51,850 首先 一定是序列S1需要的 first of all, needed by sequence one. 729 00:39:52,912 --> 00:39:54,496 因此必然有N1 So what it needs is sequence one. 730 00:39:55,190 --> 00:39:58,288 然后 并不是N2里面的所有元素 And then, well, not quite all of the ones 731 00:39:58,320 --> 00:39:59,616 我们都需要 that are needed by sequence two. 732 00:39:59,750 --> 00:40:03,490 新的修改集需要N2中那些 What it needs are the ones that are needed by sequence two 733 00:40:03,880 --> 00:40:06,880 没有被S1修改过的寄存器 that have not been set up by sequence one. 734 00:40:08,140 --> 00:40:09,728 所以 这个并集是N1并上 So it's sort of the union of 735 00:40:11,664 --> 00:40:13,408 序列S2的需要集N2 the things that sequence two needs 736 00:40:14,512 --> 00:40:18,528 减去序列S1的修改集M1 minus the ones that sequence one modifies. 737 00:40:19,310 --> 00:40:20,880 因为它关心的是如何设置它们 Because it worries about setting them up. 738 00:40:23,950 --> 00:40:26,260 这就是编译器的基本结构 So there's the basic structure of the compiler. 739 00:40:26,700 --> 00:40:29,824 我们进行寄存器优化的方式是 The way you do register optimizations is you 740 00:40:30,220 --> 00:40:32,704 一些策略来应对需要保护的东西 you have some strategies for what needs to be preserved. 741 00:40:34,100 --> 00:40:35,632 这取决于数据结构 That depends on a data structure. 742 00:40:35,728 --> 00:40:38,512 这取决于将东西组合在一起的操作 Well, it depends on the operation of what it means to put things together. 743 00:40:39,030 --> 00:40:41,632 想知道要保护哪些东西 Preserving something, that depends on knowing 744 00:40:41,930 --> 00:40:47,280 就需要知道这段代码需要以及修改的寄存器 what registers are needed and modified by these code fragments. 745 00:40:48,750 --> 00:40:51,260 这就需要我们有一个数据结构 That depends on having little data structures, 746 00:40:51,424 --> 00:40:55,430 它不但要存放实际的指令序列 which say, a code sequence is the actual instructions, 747 00:40:55,600 --> 00:40:57,330 它修改了什么 又需要什么 what they modify and what they need. 748 00:40:57,330 --> 00:40:59,776 这些信息来自于--最基本的情况是内置的 That comes from, at the primitive level, building it in. 749 00:40:59,790 --> 00:41:01,360 对于最基本的情况 At the primitive level, 750 00:41:01,376 --> 00:41:02,528 我们可以容易地知道 it's going to be completely obvious 751 00:41:03,008 --> 00:41:04,448 需要哪些寄存器 又修改了哪些 what something needs and modifies. 752 00:41:04,820 --> 00:41:05,350 另外 Plus, 753 00:41:05,440 --> 00:41:08,608 利用这个特定的方法构建复杂指令时 this particular way that says, when I build up bigger ones, 754 00:41:09,280 --> 00:41:11,890 我们可以像这样生成新的修改集 here's how I generate the new set of registers modified 755 00:41:11,930 --> 00:41:13,370 以及新的需要集 and the new set of registers needed. 756 00:41:15,275 --> 00:41:17,770 这就是全部的内容 -- 我不该这么说 And that's the whole-- well, I shouldn't say that's the whole thing. 757 00:41:17,770 --> 00:41:19,344 这就是书里面大概30页的细节 That's the whole thing except for about 758 00:41:19,744 --> 00:41:21,870 的核心内容了 about 30 pages of details in the book. 759 00:41:22,310 --> 00:41:27,690 但它是一个完全可用的初级编译器 But it is a perfectly usable rudimentary compiler. 760 00:41:28,760 --> 00:41:31,376 让我给你展示一下它能做什么 Let me kind of show you what it does. 761 00:41:31,392 --> 00:41:35,568 假设我们从一个递归阶乘开始 Suppose we start out with recursive factorial. 762 00:41:36,208 --> 00:41:38,608 这些幻灯片的字太小不适合阅读 And these slides are going to be much too small to read. 763 00:41:38,600 --> 00:41:39,792 我只想快速翻一下代码 I just want to flash through the code 764 00:41:39,792 --> 00:41:41,280 让你们看看它有多少代码 and show you about how much it is. 765 00:41:42,250 --> 00:41:43,296 代码从这开始-- That starts out with-- 766 00:41:44,320 --> 00:41:45,680 这是代码的第一部分 here's a first block of it, 767 00:41:45,950 --> 00:41:47,680 这里编译了一个过程入口 where it compiles a procedure entry 768 00:41:47,696 --> 00:41:48,736 并进行了一些赋值操作 and does a bunch of assignments. 769 00:41:48,752 --> 00:41:51,488 这基本上对应了解释器中 And this thing is basically up through the part where 770 00:41:52,650 --> 00:41:53,904 进行判断之前的部分 sets up to do the predicate 771 00:41:54,310 --> 00:41:56,590 并判断谓词是否成立 and test whether the predicate's true. 772 00:41:56,970 --> 00:41:57,856 第二部分是 The second part 773 00:41:58,460 --> 00:42:03,730 递归调用N-1的阶乘的结果 is what results from-- in the recursive call to fact of n minus one. 774 00:42:04,120 --> 00:42:05,056 最后一部分是 And this last part 775 00:42:06,070 --> 00:42:07,488 从那里返回 is coming back from that 776 00:42:07,872 --> 00:42:09,900 并处理递归的基本情况 and then taking care of the constant case. 777 00:42:09,900 --> 00:42:13,168 这就是编译阶乘会生成的代码量 So that's about how much code it would produce for factorial. 778 00:42:13,720 --> 00:42:17,696 当然 我们可以把这个编译器做得更好 We could make this compiler much, much better, of course. 779 00:42:18,675 --> 00:42:21,240 优化它的主要方式是 The main way we could make it better is 780 00:42:21,240 --> 00:42:24,000 当你调用一个过程时 to allow the compiler to make any assumptions at all 781 00:42:24,352 --> 00:42:26,272 允许编译器做任何假设 about what happens when you call a procedure. 782 00:42:26,970 --> 00:42:28,288 举例来说 So this compiler, for instance, 783 00:42:28,300 --> 00:42:32,320 这个编译器甚至不知道 doesn't even know, say, that multiplication 784 00:42:33,120 --> 00:42:36,140 乘法可以被内联执行 you say, is something that could be coded in line. 785 00:42:36,144 --> 00:42:37,872 它则会自行构建起整个机制 Instead, it sets up this whole mechanism. 786 00:42:38,000 --> 00:42:39,344 进行APPLY-DISPATCH It goes to apply-dispatch. 787 00:42:41,370 --> 00:42:42,496 这是极大的浪费 That's a tremendous waste, 788 00:42:42,544 --> 00:42:45,020 因为 每当你进行APPLY-DISPATCH时 because what you do every time you go to apply-dispatch 789 00:42:45,020 --> 00:42:46,800 你都要关心这个参数表 is you have to concern about this argument list, 790 00:42:47,400 --> 00:42:49,104 因为它是个很普遍的操作 because it's a very general thing you're going to. 791 00:42:49,136 --> 00:42:51,072 在任何真实的编译器中 In any real compiler, of course, 792 00:42:51,088 --> 00:42:53,296 你会有寄存器来暂存参数 you're going to have registers for holding arguments. 793 00:42:53,770 --> 00:42:55,312 你要开始保护 And you're going to start preserving 794 00:42:56,380 --> 00:42:58,050 保存这些寄存器 saving the way you use those registers 795 00:42:58,050 --> 00:43:01,616 和这里的策略相近 similar to the same strategy here. 796 00:43:02,850 --> 00:43:05,936 因此 我们可能主要通过这个方法 So that's probably the very main way 797 00:43:05,952 --> 00:43:08,300 来优化书中这个特定的编译器 this particular compiler in the book could be fixed. 798 00:43:08,690 --> 00:43:09,700 还有其它的一些方法 There are other things like 799 00:43:09,700 --> 00:43:11,824 比如查找变量的值 looking up variable values and 800 00:43:11,830 --> 00:43:13,872 使用更高效的基本操作 making more efficient primitive operations, 801 00:43:13,888 --> 00:43:14,560 等等方法 and all sorts of things. 802 00:43:14,590 --> 00:43:16,608 本质上来说 一个好的Lisp编译器 Essentially, a good Lisp compiler 803 00:43:16,624 --> 00:43:18,496 可以吸收任意数量的努力 can absorb an arbitrary amount of effort. 804 00:43:19,720 --> 00:43:21,632 可能这其中的一个原因是 And probably one of the reasons 805 00:43:21,890 --> 00:43:23,040 跟FORTRAN这类语言相比 Lisp is slow 806 00:43:23,632 --> 00:43:25,440 Lisp就要慢一些 with compared to languages like FORTRAN 807 00:43:25,900 --> 00:43:28,192 如果你回头审视历史 is that, if you look over history 808 00:43:28,224 --> 00:43:31,120 会发现人们为构建Lisp编译器而呕心沥血 the amount of effort that's gone into building Lisp compilers, 809 00:43:31,160 --> 00:43:32,352 但也远远没有接近 it's nowhere near the amount of effort 810 00:43:32,368 --> 00:43:33,900 构建FORTRAN编译器的工作量 that's gone into FORTRAN compilers. 811 00:43:34,430 --> 00:43:35,792 在接下来的几年 And maybe that's something that will 812 00:43:35,920 --> 00:43:37,680 情况可能会发生变化 that will change over the next couple of years. 813 00:43:38,000 --> 00:43:38,832 好吧 就讲到这里 OK, let's break. 814 00:43:43,800 --> 00:43:44,650 有问题吗 Questions? 815 00:43:48,270 --> 00:43:49,950 学生: 很早的一个课时里-- AUDIENCE: One of the very first classes-- 816 00:43:49,950 --> 00:43:51,408 我不记得是课上还是课后-- I don't know if it was during class or after class- 817 00:43:51,470 --> 00:43:53,888 你向我们展示了 you showed me the, the 818 00:43:54,000 --> 00:43:57,520 ADD操作有一些我们看不到的基本运算 say, addition has a primitive that we don't see, 819 00:43:57,696 --> 00:43:59,216 类似于ADD%之类的 and-percent add or something like that. 820 00:43:59,825 --> 00:44:01,650 这是因为 Is that because, 821 00:44:01,650 --> 00:44:02,608 你想把代码内联为 if you're doing inline code 822 00:44:02,608 --> 00:44:08,192 专门针对二元运算对象的运算么? you'd want to just do it for two operators, operands? 823 00:44:08,700 --> 00:44:10,256 但如果你有更多的运算对象 But if you had more operands, 824 00:44:10,288 --> 00:44:11,472 你会做什么特殊的事情吗? you'd want to do something special? 825 00:44:12,710 --> 00:44:16,048 教授: 你看的是Scheme的实际实现 PROFESSOR: Yeah, you're looking in the actual scheme implementation. 826 00:44:16,064 --> 00:44:17,840 其中有一个‘+’ 这是一个运算符 There's a plus, and a plus is some operator. 827 00:44:17,904 --> 00:44:20,190 如果你看‘+’的源代码 And then if you go look inside the code for plus, 828 00:44:20,336 --> 00:44:21,376 你会看到一些叫做-- you see something called-- 829 00:44:21,570 --> 00:44:24,144 我记不清了--可能叫ADD%、PLUS之类的东西 I forget-- and-percent plus or something like that. 830 00:44:24,550 --> 00:44:25,792 这里所进行的 And what's going on there is 831 00:44:25,792 --> 00:44:27,920 就是你说的那种优化 is that particular kind of optimization. 832 00:44:28,470 --> 00:44:31,872 因为 广义的‘+’接受任意数量的参数 Because, see, general plus takes an arbitrary number of arguments. 833 00:44:35,020 --> 00:44:36,384 所以 广义加法 So the most general plus 834 00:44:36,760 --> 00:44:38,256 会说:如果我有一个参数表 says, oh, if I have an argument list, 835 00:44:38,288 --> 00:44:40,624 我最好将它们用CONS连接到表里 I'd better cons it up in some list 836 00:44:41,630 --> 00:44:44,144 并指出有多少个参数 and then figure out how many there were or something like that. 837 00:44:44,720 --> 00:44:46,160 这样效率非常低下 That's terribly inefficient, 838 00:44:46,810 --> 00:44:49,250 因为大部分时间你在把两个数相加 especially since most of the time you're probably adding two numbers. 839 00:44:49,250 --> 00:44:51,248 你不必把整个参数表连接到一起 You don't want to really have to cons this argument list. 840 00:44:52,048 --> 00:44:53,936 所以你想做的是 So what you'd like to do is build 841 00:44:55,664 --> 00:44:57,712 构建把一堆东西相加的代码 the code for plus with a bunch of entries. 842 00:44:58,150 --> 00:45:00,176 所以它做的大部分事情是一样的 So most of what it's doing is the same. 843 00:45:00,490 --> 00:45:01,952 但这里可能有个特殊的入口 However, there might be a special entry 844 00:45:01,984 --> 00:45:03,920 如果你知道只有两个参数 that you'd go to if you knew there were only two arguments. 845 00:45:04,560 --> 00:45:05,875 你会把它们放到寄存器中 And those you'll put in registers. 846 00:45:05,870 --> 00:45:06,976 它们不需要参数表 they won't be in an argument list 847 00:45:06,992 --> 00:45:07,984 你也不必用CONS连接它们 and you won't have to CONS. 848 00:45:08,675 --> 00:45:10,425 这就是这些东西工作的原理 That's how a lot of these things work. 849 00:45:12,300 --> 00:45:13,725 好吧 下课吧 OK, let's take a break. 850 00:45:14,100 --> 00:45:36,688 [音乐] [JESU, JOY OF MAN'S DESIRING] 851 00:45:36,688 --> 00:45:38,680 MIT OpenCourseWare http://ocw.mit.edu 852 00:45:38,680 --> 00:45:42,976 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec10b.eng.srt ================================================ 1 00:00:04,970 --> 00:00:06,535 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] 2 00:00:18,910 --> 00:00:24,440 PROFESSOR: Well, there's one bit of mystery left, which I'd like to get rid of right now. 3 00:00:24,440 --> 00:00:33,660 And that's that we've been blithely doing things like cons assuming there's always another one. 4 00:00:33,660 --> 00:00:40,020 That we've been doing these things like car-ing and cdr-ing and assuming that we had some idea how this can be done. 5 00:00:40,020 --> 00:00:45,780 Now indeed we said that that's equivalent to having procedures. 6 00:00:45,780 --> 00:00:53,010 But that doesn't really solve the problem, because the procedure need all sorts of complicated mechanisms like environment structures and things like that to work. 7 00:00:53,010 --> 00:00:59,380 And those were ultimately made out of conses in the model that we had, so that really doesn't solve the problem. 8 00:00:59,380 --> 00:01:04,760 Now the problem here is the glue the data structure's made out of. 9 00:01:04,760 --> 00:01:07,370 What kind of possible thing could it be? 10 00:01:07,370 --> 00:01:16,980 We've been showing you things like a machine, a computer that has a controller, and some registers, and maybe a stack. 11 00:01:16,980 --> 00:01:20,570 And we haven't said anything about, for example, larger memory. 12 00:01:20,570 --> 00:01:23,740 And I think that's what we have to worry about right now. 13 00:01:23,740 --> 00:01:34,800 But just to make it perfectly clear that this is an inessential, purely implementational thing, I'd like to show you, for example, how you can do it all with the numbers. 14 00:01:34,800 --> 00:01:37,590 That's an easy one. 15 00:01:37,590 --> 00:01:54,320 Famous fellow by the name of Godel, a logician at the end of the 1930s, invented a very clever way of encoding the complicated expressions as numbers. 16 00:01:54,320 --> 00:01:59,660 For example-- I'm not saying exactly what Godel's scheme is, because he didn't use words like cons. 17 00:01:59,660 --> 00:02:03,090 He had other kinds of ways of combining to make expressions. 18 00:02:03,090 --> 00:02:07,920 But he said, I'm going to assign a number to every algebraic expression. 19 00:02:07,920 --> 00:02:12,470 And the way I'm going to manufacture these numbers is by combining the numbers of the parts. 20 00:02:12,470 --> 00:02:46,130 So for example, what we were doing our world, we could say that if objects are represented by numbers, then cons of x and y could be represented by 2 to the x times 2 to the y. 21 00:02:46,130 --> 00:02:49,560 Because then we could extract the parts. 22 00:02:49,560 --> 00:03:06,690 We could say, for example, that then car of, say, x is the number of factors of 2 in x. 23 00:03:06,690 --> 00:03:10,690 And of course cdr is the same thing. 24 00:03:10,690 --> 00:03:16,510 It's the number of factors of 3 in x. 25 00:03:16,510 --> 00:03:27,950 Now this is a perfectly reasonable scheme, except for the fact that the numbers rapidly get to be much larger in number of digits than the number of protons in the universe. 26 00:03:27,950 --> 00:03:33,430 So there's no easy way to use this scheme other than the theoretical one. 27 00:03:33,430 --> 00:03:38,450 On the other hand, there are other ways of representing these things. 28 00:03:38,450 --> 00:03:44,010 We have been thinking in terms of little boxes. 29 00:03:44,010 --> 00:03:50,280 We've been thinking about our cons structures as looking sort of like this. 30 00:03:50,280 --> 00:03:53,610 They're little pigeon holes with things in them. 31 00:03:53,610 --> 00:03:57,210 And of course we arrange them in little trees. 32 00:03:57,210 --> 00:04:09,380 I wish that the semiconductor manufacturers would supply me with something appropriate for this, but actually what they do supply me with is a linear memory. 33 00:04:09,380 --> 00:04:17,720 Memory is sort of a big pile of pigeonholes, pigeonholes like this. 34 00:04:17,720 --> 00:04:23,390 Each of which can hold a certain sized object, a fixed size object. 35 00:04:23,390 --> 00:04:28,550 So, for example, a complicated list with 25 elements won't fit in one of these. 36 00:04:28,550 --> 00:04:30,600 However, each of these is indexed by an address. 37 00:04:33,970 --> 00:04:38,060 So the address might be zero here, one here, two here, three here, and so on. 38 00:04:38,060 --> 00:04:40,400 That we write these down as numbers is unimportant. 39 00:04:40,400 --> 00:04:44,970 What matters is that they're distinct as a way to get to the next one. 40 00:04:44,970 --> 00:04:49,530 And inside of each of these, we can stuff something into these pigeonholes. 41 00:04:49,530 --> 00:04:53,550 That's what memory is like, for those of you who haven't built a computer. 42 00:04:56,690 --> 00:05:03,290 Now the problem is how are we going to impose on this type of structure, this nice tree structure. 43 00:05:03,290 --> 00:05:06,630 Well it's not very hard, and there have been numerous schemes involved in this. 44 00:05:06,630 --> 00:05:21,706 The most important one is to say, well assuming that the semiconductor manufacturer allows me to arrange my memory so that one of these pigeonholes is big enough to hold the address of another I haven't made. 45 00:05:21,706 --> 00:05:30,390 Now it actually has to be a little bit bigger because I have to also install or store some information as to a tag which describes the kind of thing that's there. 46 00:05:30,390 --> 00:05:32,350 And we'll see that in a second. 47 00:05:32,350 --> 00:05:43,770 And of course if the semiconductor manufacturer doesn't arrange it so I can do that, then of course I can, with some cleverness, arrange combinations of these to fit together in that way. 48 00:05:43,770 --> 00:05:51,740 So we're going to have to imagine imposing this complicated tree structure on our nice linear memory. 49 00:05:51,740 --> 00:05:59,490 If we look at the first still store, we see a classic scheme for doing that. 50 00:05:59,490 --> 00:06:05,980 It's a standard way of representing Lisp structures in a linear memory. 51 00:06:05,980 --> 00:06:12,030 What we do is we divide this memory into two parts. 52 00:06:12,030 --> 00:06:17,580 An array called the cars, and an array called the cdrs. 53 00:06:17,580 --> 00:06:22,560 Now whether those happen to be sequential addresses or whatever, it's not important. 54 00:06:22,560 --> 00:06:25,800 That's somebody's implementation details. 55 00:06:25,800 --> 00:06:28,960 But there are two arrays here. 56 00:06:28,960 --> 00:06:34,840 Linear arrays indexed by sequential indices like this. 57 00:06:34,840 --> 00:06:41,430 What is stored in each of these pigeonholes is a typed object. 58 00:06:41,430 --> 00:06:47,790 And what we have here are types which begin with letters like p, standing for a pair. 59 00:06:47,790 --> 00:06:50,040 Or n, standing for a number. 60 00:06:50,040 --> 00:07:06,430 Or e, standing for an empty list. The end of the list. And so if we wish to represent an object like this, the list beginning with 1, 2 and then having a 3 and a 4 as its second and third elements. 61 00:07:06,430 --> 00:07:12,610 A list containing a list as its first part and then two numbers as a second and third parts. 62 00:07:12,610 --> 00:07:17,320 Then of course we draw it sort of like this these days, in box-and-pointer notation. 63 00:07:17,320 --> 00:07:28,390 And you see, these are the three cells that have as their car pointer the object which is either 1, 2 or 3 or 4. 64 00:07:28,390 --> 00:07:35,940 And then of course the 1, 2, the car of this entire structure, is itself a substructure which contains a sublist like that. 65 00:07:35,940 --> 00:07:41,880 What I'm about to do is put down places which are-- I'm going to assign indices. 66 00:07:41,880 --> 00:07:46,850 Like this 1, over here, represents the index of this cell. 67 00:07:49,850 --> 00:08:02,000 But that pointer that we see here is a reference to the pair of pigeonholes in the cars and the cdrs that are labeled by 1 in my linear memory down here. 68 00:08:02,000 --> 00:08:12,220 So if I wish to impose this structure on my linear memory, what I do is I say, oh yes, why don't we drop this into cell 1? 69 00:08:12,220 --> 00:08:12,660 I pick one. 70 00:08:12,660 --> 00:08:14,270 There's 1. 71 00:08:14,270 --> 00:08:17,950 And that says that its car, I'm going to assign it to be a pair. 72 00:08:17,950 --> 00:08:22,590 It's a pair, which is in index 5. 73 00:08:22,590 --> 00:08:28,340 And the cdr, which is this one over here, is a pair which I'm going to stick into place 2. 74 00:08:28,340 --> 00:08:30,890 p2. 75 00:08:30,890 --> 00:08:32,950 And take a look at p2. 76 00:08:32,950 --> 00:08:39,520 Oh yes, well p2 is a thing whose car is the number 3, so as you see, an n3. 77 00:08:39,520 --> 00:08:46,640 And whose cdr, over here, is a pair, which lives in place 4. 78 00:08:46,640 --> 00:08:48,650 So that's what this p4 is. 79 00:08:48,650 --> 00:08:59,170 p4 is a number whose value is 4 in its car and whose cdr is an empty list right there. 80 00:08:59,170 --> 00:09:00,690 And that ends it. 81 00:09:00,690 --> 00:09:11,620 So this is the traditional way of representing this kind of binary tree in a linear memory. 82 00:09:11,620 --> 00:09:18,440 Now the next question, of course, that we might want to worry about is just a little bit of implementation. 83 00:09:18,440 --> 00:09:30,140 That means that when I write procedures of the form assigned a, [UNINTELLIGIBLE] procedures-- lines of register machine code of the form assigned a, the car of [UNINTELLIGIBLE] 84 00:09:30,140 --> 00:09:38,740 b, what I really mean is addressing these elements. 85 00:09:38,740 --> 00:09:44,470 And so we're going to think of that as a abbreviation for it. 86 00:09:44,470 --> 00:09:49,140 Now of course in order to write that down I'm going to introduce some sort of a structure called a vector. 87 00:09:52,120 --> 00:09:58,710 And we're going to have something which will reference a vector, just so we can write it down. 88 00:09:58,710 --> 00:10:03,970 Which takes the name of the vector, or the-- I don't think that name is the right word. 89 00:10:03,970 --> 00:10:16,280 Which takes the vector and the index, and I have to have a way of setting one of those with something called a vector set, I don't really care. 90 00:10:16,280 --> 00:10:26,470 But let's look, for example, at then that kind of implementation of car and cdr. 91 00:10:26,470 --> 00:10:44,490 So for example if I happen to have a register b, which contains the type index of a pair, and therefore it is the pointer to a pair, then I could take the car of that and if I-- write this down-- I might put that in register a. 92 00:10:44,490 --> 00:11:02,650 What that really is is a representation of the assign to a, the value of vector reffing-- or array indexing, if you will-- or something, the cars object-- whatever that is-- with the index, b. 93 00:11:02,650 --> 00:11:11,840 And similarly for cdr. And we can do the same thing for assignment to data structures, if we need to do that sort of thing at all. 94 00:11:11,840 --> 00:11:14,580 It's not too hard to build that. 95 00:11:14,580 --> 00:11:18,010 Well now the next question is how are we going to do allocation. 96 00:11:18,010 --> 00:11:21,550 And every so often I say I want a cons. 97 00:11:21,550 --> 00:11:23,790 Now conses don't grow on trees. 98 00:11:23,790 --> 00:11:25,340 Or maybe they should. 99 00:11:25,340 --> 00:11:29,980 But I have to have some way of getting the next one. 100 00:11:29,980 --> 00:11:35,630 I have to have some idea of if their memory is unused that I might want to allocate from. 101 00:11:35,630 --> 00:11:37,380 And there are many schemes for doing this. 102 00:11:37,380 --> 00:11:42,100 And the particular thing I'm showing you right now is not essential. 103 00:11:42,100 --> 00:11:44,960 However it's convenient and has been done many times. 104 00:11:44,960 --> 00:11:47,660 One scheme's was called the free list allocation scheme. 105 00:11:47,660 --> 00:11:56,960 What that means is that all of the free memory that there is in the world is linked together in a linked list, just like all the other stuff. 106 00:11:56,960 --> 00:12:06,030 And whenever you need a free cell to make a new cons, you grab the first, one make the free list be the cdr of it, and then allocate that. 107 00:12:06,030 --> 00:12:09,530 And so what that looks like is something like this. 108 00:12:09,530 --> 00:12:18,510 Here we have the free list starting in 6. 109 00:12:18,510 --> 00:12:24,860 And what that is is a pointer-off to say 8. 110 00:12:24,860 --> 00:12:28,870 So what it says is, this one is free and the next one is an 8. 111 00:12:28,870 --> 00:12:33,930 This one is free and the next one is in 3, the next one that's free. 112 00:12:33,930 --> 00:12:37,680 That one's free and the next one is in 0. 113 00:12:37,680 --> 00:12:40,940 That one's free and the next one's in 15. 114 00:12:40,940 --> 00:12:42,780 Something like that. 115 00:12:42,780 --> 00:12:46,400 We can imagine having such a structure. 116 00:12:46,400 --> 00:12:53,940 Given that we have something like that, then it's possible to just get one when you need it. 117 00:12:53,940 --> 00:12:59,320 And so a program for doing cons, this is what cons might turn into. 118 00:12:59,320 --> 00:13:25,680 To assign to a register A the result of cons-ing, a B onto C, the value in this containing B and the value containing C, what we have to do is get the current [? type ?] ahead of the freelist, make the free list be its cdr. Then we have to change the cars to be the thing we're making up to be in A to be the B, the thing in B. 119 00:13:25,680 --> 00:13:36,650 And we have to make change the cdrs of the thing that's in A to be C. And then what we have in A is the right new frob, whatever it is. 120 00:13:36,650 --> 00:13:40,470 The object that we want. 121 00:13:40,470 --> 00:13:53,510 Now there's a little bit of a cheat here that I haven't told you about, which is somewhere around here I haven't set that I've the type of the thing that I'm cons-ing up to be a pair, and I ought to. 122 00:13:53,510 --> 00:13:59,810 So there should be some sort of bits here are being set, and I just haven't written that down. 123 00:13:59,810 --> 00:14:03,100 We could have arranged it, of course, for the free lift to be made out of pairs. 124 00:14:03,100 --> 00:14:06,430 And so then there's no problem with that. 125 00:14:06,430 --> 00:14:17,540 But that sort of-- again, an inessential detail in a way some particular programmer or architect or whatever might manufacture his machine or Lisp system. 126 00:14:17,540 --> 00:14:43,430 So for example, just looking at this, to allocate given that I had already the structure that you saw before, supposing I wanted to allocate a new cell, which is going to be representation of list one, one, two, where already one two was the car of the list we were playing with before. 127 00:14:43,430 --> 00:14:44,780 Well that's not so hard. 128 00:14:44,780 --> 00:14:49,530 I stored that one and one, so p1 one is the representation of this. 129 00:14:49,530 --> 00:14:51,690 This is p5. 130 00:14:51,690 --> 00:14:54,070 That's going to be the cdr of this. 131 00:14:54,070 --> 00:14:57,780 Now we're going to pull something off the free list, but remember the free list started at six. 132 00:14:57,780 --> 00:15:02,890 The new free list after this allocation is eight, a free list beginning at eight. 133 00:15:02,890 --> 00:15:13,330 And of course in six now we have a number one, which is what we wanted, with its cdr being the pair starting in location five. 134 00:15:13,330 --> 00:15:16,810 And that's no big deal. 135 00:15:16,810 --> 00:15:25,080 So the only problem really remaining here is, well, I don't have an infinitely large memory. 136 00:15:25,080 --> 00:15:38,000 If I do this for a little while, say, for example, supposing it takes me a microsecond to do a cons, and I have a million cons memory then I'm only going to run out in a second, and that's pretty bad. 137 00:15:38,000 --> 00:15:44,300 So what we do to prevent that disaster, that ecological disaster, talk about right after questions. 138 00:15:44,300 --> 00:15:45,550 Are there any questions? 139 00:15:51,500 --> 00:15:52,030 Yes. 140 00:15:52,030 --> 00:16:04,930 AUDIENCE: In the environment diagrams that we were drawing we would use the body of procedures, and you would eventually wind up with things that were no longer useful in that structure. 141 00:16:04,930 --> 00:16:06,890 How is that represented? 142 00:16:06,890 --> 00:16:09,180 PROFESSOR: There's two problems here. 143 00:16:09,180 --> 00:16:13,870 One you were asking is that material becomes useless. 144 00:16:13,870 --> 00:16:14,920 We'll talk about that in a second. 145 00:16:14,920 --> 00:16:18,100 That has to do with how to prevent ecological disasters. 146 00:16:18,100 --> 00:16:21,820 If I make a lot of garbage I have to somehow be able to clean up after myself. 147 00:16:21,820 --> 00:16:23,430 And we'll talk about that in a second. 148 00:16:23,430 --> 00:16:27,210 The other question you're asking is how you represent the environments, I think. 149 00:16:27,210 --> 00:16:27,600 AUDIENCE: Yes. 150 00:16:27,600 --> 00:16:28,190 PROFESSOR: OK. 151 00:16:28,190 --> 00:16:30,860 And the environment structures can be represented in arbitrary ways. 152 00:16:30,860 --> 00:16:31,780 There are lots of them. 153 00:16:31,780 --> 00:16:33,630 I mean, here I'm just telling you about list cells. 154 00:16:33,630 --> 00:16:41,080 Of course every real system has vectors of arbitrary length as well as the vectors of length, too, which represent list cells. 155 00:16:41,080 --> 00:16:58,290 And the environment structures that one uses in a professionally written Lisp system tend to be vectors which contain a number of elements approximately equal to the number of arguments-- a little bit more because you need certain glue. 156 00:16:58,290 --> 00:17:00,360 So remember, the environment [UNINTELLIGIBLE] 157 00:17:00,360 --> 00:17:00,740 frames. 158 00:17:00,740 --> 00:17:03,980 The frames are constructed by applying a procedure. 159 00:17:03,980 --> 00:17:11,270 In doing so, an allocation is made of a place which is the number of arguments long plus [? unglue ?] 160 00:17:11,270 --> 00:17:13,859 that gets linked into a chain. 161 00:17:13,859 --> 00:17:15,660 It's just like algol at that level. 162 00:17:19,810 --> 00:17:21,060 There any other questions? 163 00:17:23,700 --> 00:17:23,920 OK. 164 00:17:23,920 --> 00:17:26,106 Thank you, and let's take a short break. 165 00:17:26,106 --> 00:17:27,699 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] 166 00:18:12,270 --> 00:18:19,420 PROFESSOR: Well, as I just said, computer memories supplied by the semiconductor manufacturers are finite. 167 00:18:19,420 --> 00:18:21,620 And that's quite a pity. 168 00:18:21,620 --> 00:18:24,030 It might not always be that way. 169 00:18:24,030 --> 00:18:28,860 Just for a quick calculation, you can see that it's possible that if [? memory ?] 170 00:18:28,860 --> 00:18:39,450 prices keep going at the rate they're going that if you still took a microsecond second to do a cons, then-- first of all, everybody should know that there's about pi times ten to the seventh seconds in a year. 171 00:18:39,450 --> 00:18:43,940 And so that would be ten to the seventh plus ten to the sixth is ten to the thirteenth. 172 00:18:43,940 --> 00:18:47,520 So there's maybe ten to the fourteenth conses in the life of a machine. 173 00:18:47,520 --> 00:18:54,020 If there was ten to the fourteenth words of memory on your machine, you'd never run out. 174 00:18:54,020 --> 00:18:56,310 And that's not completely unreasonable. 175 00:18:56,310 --> 00:18:58,460 Ten to the fourteenth is not a very large number. 176 00:19:03,860 --> 00:19:05,180 I don't think it is. 177 00:19:05,180 --> 00:19:08,700 But then again I like to play with astronomy. 178 00:19:08,700 --> 00:19:12,930 It's at least ten to the eighteenth centimeters between us and the nearest star. 179 00:19:12,930 --> 00:19:24,200 But the thing I'm about to worry about is, at least in the current economic state of affairs, ten to the fourteenth pieces of memory is expensive. 180 00:19:24,200 --> 00:19:28,120 And so I suppose what we have to do is make do with much smaller. 181 00:19:28,120 --> 00:19:35,800 Memories Now in general we want to have an illusion of infinity. 182 00:19:35,800 --> 00:19:40,100 All we need to do is arrange it so that whenever you look, the thing is there. 183 00:19:42,670 --> 00:19:45,105 That's really an important idea. 184 00:19:49,540 --> 00:19:55,280 A person or a computer lives only a finite amount of time and can only take a finite number of looks at something. 185 00:19:55,280 --> 00:19:58,190 And so you really only need a finite amount of stuff. 186 00:19:58,190 --> 00:20:06,900 But you have to arrange it so no matter how much there is, how much you really claim there is, there's always enough stuff so that when you take a look, it's there. 187 00:20:06,900 --> 00:20:08,750 And so you only need a finite amount. 188 00:20:08,750 --> 00:20:11,630 But let's see. 189 00:20:11,630 --> 00:20:19,410 One problem is, as was brought up, that there are possible ways that there is lots of stuff that we make that we don't need. 190 00:20:19,410 --> 00:20:22,760 And we could recycle the material out of which its made. 191 00:20:22,760 --> 00:20:30,470 An example is the fact that we're building environment structures, and we do so every time we call a procedure. 192 00:20:30,470 --> 00:20:32,810 We have built in it a environment frame. 193 00:20:32,810 --> 00:20:36,730 That environment frame doesn't necessarily have a very long lifetime. 194 00:20:36,730 --> 00:20:42,850 Its lifetime, meaning its usefulness, may exist only over the invocation of the procedure. 195 00:20:42,850 --> 00:20:58,530 Or if the procedure exports another procedure by returning it as a value and that procedure is defined inside of it, well then the lifetime of the frame of the outer procedure still is only the lifetime of the procedure which was exported. 196 00:20:58,530 --> 00:21:01,960 And so ultimately, a lot of that is garbage. 197 00:21:01,960 --> 00:21:05,370 There are other ways of producing garbage as well. 198 00:21:05,370 --> 00:21:07,240 Users produce garbage. 199 00:21:07,240 --> 00:21:10,930 An example of user garbage is something like this. 200 00:21:10,930 --> 00:21:28,160 If we write a program to, for example, append two lists together, well one way to do it is to reverse the first list onto the empty list and reverse that onto the second list. Now that's not terribly bad way of doing it. 201 00:21:28,160 --> 00:21:41,010 And however, the intermediate result, which is the reversal of the first list as done by this program, is never going to be accessed ever again after it's copied back on to the second. 202 00:21:41,010 --> 00:21:43,580 It's an intermediate result. 203 00:21:43,580 --> 00:21:48,600 It's going to be hard to ever see how anybody would ever be able to access it. 204 00:21:48,600 --> 00:21:51,050 In fact, it will go away. 205 00:21:51,050 --> 00:21:58,800 Now if we make a lot of garbage like that, and we should be allowed to, then there's got to be some way to reclaim that garbage. 206 00:21:58,800 --> 00:22:17,410 Well, what I'd like to tell you about now is a very clever technique whereby a Lisp system can prove a small theorem every so often on the [? forum, ?] the following piece of junk will never be accessed again. 207 00:22:17,410 --> 00:22:21,400 It can have no affect on the future of the computation. 208 00:22:21,400 --> 00:22:24,920 It's actually based on a very simple idea. 209 00:22:24,920 --> 00:22:28,570 We've designed our computers to look sort of like this. 210 00:22:28,570 --> 00:22:35,280 There's some data path, which contains the registers. 211 00:22:35,280 --> 00:22:42,610 There are things like x, and env, and val, and so on. 212 00:22:42,610 --> 00:22:50,240 And there's one here called stack, some sort which points off to a structure somewhere, which is the stack. 213 00:22:50,240 --> 00:22:51,740 And we'll worry about that in a second. 214 00:22:51,740 --> 00:22:56,730 There's some finite controller, finite state machine controller. 215 00:22:56,730 --> 00:23:04,260 And there's some control signals that go this way and predicate results that come this way, not the interesting part. 216 00:23:04,260 --> 00:23:10,460 There's some sort of structured memory, which I just told you how to make, which may contain a stack. 217 00:23:10,460 --> 00:23:13,450 I didn't tell you how to make things of arbitrary shape, only pairs. 218 00:23:13,450 --> 00:23:20,360 But in fact with what I've told you can simulate a stack by a big list. I don't plan to do that, it's not a nice way to do it. 219 00:23:20,360 --> 00:23:22,990 But we could have something like that. 220 00:23:22,990 --> 00:23:27,470 We have all sorts of little data structures in here that are hooked together in funny ways. 221 00:23:30,115 --> 00:23:32,560 They connect to other things. 222 00:23:32,560 --> 00:23:33,250 And so on. 223 00:23:33,250 --> 00:23:37,190 And ultimately things up there are pointers to these. 224 00:23:37,190 --> 00:23:44,910 The things that are in the registers are pointers off to the data structures that live in this Lisp structure memory. 225 00:23:44,910 --> 00:23:55,550 Now the truth of the matter is that the entire consciousness of this machine is in these registers. 226 00:23:55,550 --> 00:24:15,070 There is no possible way that the machine, if done correctly, if built correctly, can access anything in this Lisp structure memory unless the thing in that Lisp structure memory is connected by a sequence of data structures to the registers. 227 00:24:15,070 --> 00:24:22,280 If it's accessible by legitimate data structure selectors from the pointers that are stored in these registers. 228 00:24:22,280 --> 00:24:24,940 Things like array references, perhaps. 229 00:24:24,940 --> 00:24:28,790 Or cons cell references, cars and cdrs. 230 00:24:28,790 --> 00:24:32,740 But I can't just talk about a random place in this memory, because I can't get to it. 231 00:24:32,740 --> 00:24:38,985 These are being arbitrary names I'm not allowed to count, at least as I'm evaluating expressions. 232 00:24:41,620 --> 00:24:47,160 If that's the case then there's a very simple theorem to be proved. 233 00:24:47,160 --> 00:25:00,750 Which is, if I start with all lead pointers that are in all these registers and recursively chase out, marking all the places I can get to by selectors, then eventually I mark everything they can be gotten to. 234 00:25:00,750 --> 00:25:05,560 Anything which is not so marked is garbage and can be recycled. 235 00:25:05,560 --> 00:25:07,200 Very simple. 236 00:25:07,200 --> 00:25:11,180 Cannot affect the future of the computation. 237 00:25:11,180 --> 00:25:16,616 So let me show you that in a particular example. 238 00:25:16,616 --> 00:25:23,640 Now that means I'm going to have to append to my description of the list structure a mark. 239 00:25:23,640 --> 00:25:29,080 And so here, for example, is a Lisp structured memory. 240 00:25:29,080 --> 00:25:38,590 And in this Lisp structured memory is a Lisp structure beginning in a place I'm going to call-- this is the root. 241 00:25:38,590 --> 00:25:40,120 Now it doesn't really have to have a root. 242 00:25:40,120 --> 00:25:42,670 It could be a bunch of them, like all the registers. 243 00:25:42,670 --> 00:25:51,850 But I could cleverly arrange it so all the registers, all the things that are in old registers are also at the right moment put into this root structure, and then we've got one pointer to it. 244 00:25:51,850 --> 00:25:54,570 I don't really care. 245 00:25:54,570 --> 00:25:58,720 So the idea is we're going to cons up stuff until our free list is empty. 246 00:25:58,720 --> 00:26:00,950 We've run out of things. 247 00:26:00,950 --> 00:26:07,850 Now we're going to do this process of proving the theorem that a certain percentage of the memory has got crap in it. 248 00:26:07,850 --> 00:26:14,570 And then we're going to recycle that to grow new trees, a standard use of such garbage. 249 00:26:17,090 --> 00:26:18,840 So in any case, what do we have here? 250 00:26:18,840 --> 00:26:27,502 Well we have some data structure which starts out over here one. 251 00:26:27,502 --> 00:26:33,980 And in fact it has a car in five, and its cdr is in two. 252 00:26:33,980 --> 00:26:36,700 And all the marks start out at zero. 253 00:26:36,700 --> 00:26:39,920 Well let's start marking, just to play this game. 254 00:26:39,920 --> 00:26:42,540 OK. 255 00:26:42,540 --> 00:26:48,390 So for example, since I can access one from the root I will mark that. 256 00:26:48,390 --> 00:26:50,960 Let me mark it. 257 00:26:50,960 --> 00:26:52,430 Bang. 258 00:26:52,430 --> 00:26:54,560 That's marked. 259 00:26:54,560 --> 00:27:01,450 Now since I have a five here I can go to five and see, well I'll mark that. 260 00:27:01,450 --> 00:27:01,760 Bang. 261 00:27:01,760 --> 00:27:02,900 That's useful stuff. 262 00:27:02,900 --> 00:27:08,700 But five references as a number in its car, I'm not interested in marking numbers but its cdr is seven. 263 00:27:08,700 --> 00:27:10,450 So I can mark that. 264 00:27:10,450 --> 00:27:12,260 Bang. 265 00:27:12,260 --> 00:27:17,120 Seven is the empty list, the only thing that references, and it's got a number in its car. 266 00:27:17,120 --> 00:27:19,490 Not interesting. 267 00:27:19,490 --> 00:27:20,500 Well now let's go back here. 268 00:27:20,500 --> 00:27:21,650 I forgot about something. 269 00:27:21,650 --> 00:27:22,840 Two. 270 00:27:22,840 --> 00:27:30,370 See in other words, if I'm looking at cell one, cell one contains a two right over here. 271 00:27:30,370 --> 00:27:31,730 A reference to two. 272 00:27:31,730 --> 00:27:35,700 That means I should go mark two. 273 00:27:35,700 --> 00:27:37,140 Bang. 274 00:27:37,140 --> 00:27:38,960 Two contains a reference to four. 275 00:27:38,960 --> 00:27:43,780 It's got a number in its car, I'm not interested in that, so I'm going to go mark that. 276 00:27:43,780 --> 00:27:51,400 Four refers to seven through its car, and is empty in its cdr, but I've already marked that one so I don't have to mark it again. 277 00:27:51,400 --> 00:27:55,000 This is all the accessible structure from that place. 278 00:27:55,000 --> 00:27:58,710 Simple recursive mark algorithm. 279 00:27:58,710 --> 00:28:04,920 Now there are some unhappinesses about that algorithm, and we can worry about that a second. 280 00:28:04,920 --> 00:28:14,220 But basically you'll see that all the things that have not been marked are places that are free, and I could recycle. 281 00:28:14,220 --> 00:28:21,180 So the next stage after that is going to be to scan through all of my memory, looking for things that are not marked. 282 00:28:21,180 --> 00:28:28,770 Every time I come across a marked thing I unmark it, and every time I come across an unmarked thing I'm going to link it together in my free list. 283 00:28:28,770 --> 00:28:32,120 Classic, very simple algorithm. 284 00:28:32,120 --> 00:28:33,840 So let's see. 285 00:28:33,840 --> 00:28:34,770 Is that very simple? 286 00:28:34,770 --> 00:28:35,570 Yes it is. 287 00:28:35,570 --> 00:28:40,090 I'm not going to go through the code in any detail, but I just want to show you about how long it is. 288 00:28:40,090 --> 00:28:42,490 Let's look at the mark phase. 289 00:28:42,490 --> 00:28:45,060 Here's the first part of the mark phase. 290 00:28:45,060 --> 00:28:48,280 We pick up the root. 291 00:28:48,280 --> 00:28:52,380 We're going to use that as a recursive procedure call. 292 00:28:52,380 --> 00:28:57,380 We're going to sweep from there, after when we're done with marking. 293 00:28:57,380 --> 00:29:05,500 And then we're going to do a little couple of instructions that do this checking out on the marks and changing the marks and things like that, according to the algorithm I've just shown you. 294 00:29:05,500 --> 00:29:06,470 It comes out here. 295 00:29:06,470 --> 00:29:10,660 You have to mark the cars of things and you also have to be able to mark the cdrs of things. 296 00:29:10,660 --> 00:29:14,370 That's the entire mark phase. 297 00:29:14,370 --> 00:29:16,590 I'll just tell you a little story about this. 298 00:29:16,590 --> 00:29:26,740 The old DEC PDP-6 computer, this was the way that the mark-sweep garbage collection, as it was, was written. 299 00:29:26,740 --> 00:29:39,280 The program was so small that with the data that it needed, with the registers that it needed to manipulate the memory, it fit into the fast registers of the machine, which were 16. 300 00:29:39,280 --> 00:29:39,800 The whole program. 301 00:29:39,800 --> 00:29:43,170 And you could execute instructions in the fast registers. 302 00:29:43,170 --> 00:29:48,870 So it's an extremely small program, and it could run very fast. 303 00:29:48,870 --> 00:30:03,410 Now unfortunately, of course, this program, because the fact that it's recursive in the way that you do something first and then you do something after that, you have to work on the cars and then the cdrs, it requires auxiliary memory. 304 00:30:03,410 --> 00:30:08,260 So Lisp systems-- those requires a stack for marking. 305 00:30:08,260 --> 00:30:19,930 Lisp systems that are built this way have a limit to the depth of recursion you can have in data structures in either the car or the cdr, and that doesn't work very nicely. 306 00:30:19,930 --> 00:30:23,180 On the other hand, you never notice it if it's big enough. 307 00:30:23,180 --> 00:30:33,560 And that's certainly been the case for most Maclisp, for example, which ran Macsyma where you could deal with expressions of thousands of elements long. 308 00:30:33,560 --> 00:30:39,490 These are algebraic expressions with thousand of terms. And there's no problem with that. 309 00:30:39,490 --> 00:30:42,190 Such, the garbage collector does work. 310 00:30:42,190 --> 00:30:55,380 On the other hand, there's a very clever modification to this algorithm, which I will not describe, by Peter Deutsch and Schorr and Waite-- Herb Schorr from IBM and Waite, who I don't know. 311 00:30:55,380 --> 00:31:07,520 That algorithm allows you to build-- you do can do this without auxiliary memory, by remembering as you walk the data structures where you came from by reversing the pointers as you go down and crawling up the reverse pointers as you go up. 312 00:31:07,520 --> 00:31:09,130 It's a rather tricky algorithm. 313 00:31:09,130 --> 00:31:14,350 The first time you write it-- or in fact, the first three times you write it it has a terrible bug in it. 314 00:31:14,350 --> 00:31:18,110 And it's also rather slow, because it's complicated. 315 00:31:18,110 --> 00:31:24,580 It takes about six times as many memory references to do the sorts of things that we're talking about. 316 00:31:24,580 --> 00:31:31,510 Well now once I've done this marking phase, and I get into a position where things look like this, let's look-- yes. 317 00:31:31,510 --> 00:31:35,590 Here we have the mark done, just as I did it. 318 00:31:35,590 --> 00:31:37,330 Now we have to perform the sweep phase. 319 00:31:37,330 --> 00:31:39,820 And I described to you what this sweep is like. 320 00:31:39,820 --> 00:31:46,836 I'm going to walk down from one end of memory or the other, I don't care where, scanning every cell that's in the memory. 321 00:31:46,836 --> 00:31:57,500 And as I scan these cells, I'm going to link them together, if they are free, into the free list. And if they're not free, I'm going to unmark them so the marks become zero. 322 00:31:57,500 --> 00:32:00,460 And in fact what I get-- well the program is not very complicated. 323 00:32:00,460 --> 00:32:02,780 It looks sort of like this-- it's a little longer. 324 00:32:02,780 --> 00:32:04,820 Here's the first piece of it. 325 00:32:04,820 --> 00:32:06,710 This one's coming down from the top of memory. 326 00:32:06,710 --> 00:32:09,580 I don't want you to try to understand this at this point. 327 00:32:09,580 --> 00:32:11,030 It's rather simple. 328 00:32:11,030 --> 00:32:15,970 It's a very simple algorithm, but there's pieces of it that just sort of look like this. 329 00:32:15,970 --> 00:32:18,600 They're all sort of obvious. 330 00:32:18,600 --> 00:32:22,310 And after we've done the sweep, we get an answer that looks like that. 331 00:32:25,330 --> 00:32:29,590 Now there are some disadvantages with mark-sweep algorithms of this sort. 332 00:32:29,590 --> 00:32:31,940 Serious ones. 333 00:32:31,940 --> 00:32:36,498 One important disadvantage is that your memories get larger and larger. 334 00:32:36,498 --> 00:32:46,360 As you say, address spaces get larger and larger, you're willing to represent more and more stuff, then it gets very costly to scan all of memory. 335 00:32:46,360 --> 00:32:50,490 What you'd really like to do is only scan useful stuff. 336 00:32:50,490 --> 00:33:00,370 It would even be better if you realized that some stuff was known to be good and useful, and you don't have to look at it more than once or twice. 337 00:33:00,370 --> 00:33:01,550 Or very rarely. 338 00:33:01,550 --> 00:33:11,910 Whereas other stuff that you're not so sure about, you can look at more detail every time you want to do this, want to garbage collect. 339 00:33:11,910 --> 00:33:15,660 Well there are algorithms that are organized in this way. 340 00:33:15,660 --> 00:33:22,800 Let me tell you about a famous old algorithm which allows you only look at the part of memory which is known to be useful. 341 00:33:22,800 --> 00:33:26,310 And which happens to be the fastest known garbage collector algorithm. 342 00:33:26,310 --> 00:33:30,150 This is the Minsky-Feinchel-Yochelson garbage collector algorithm. 343 00:33:30,150 --> 00:33:48,480 It was invented by Minsky in 1961 or '60 or something, for the RLE PDP-1 Lisp, which had 4,096 words of list memory, and a drum. 344 00:33:48,480 --> 00:33:53,380 And the whole idea was to garbage collect this terrible memory. 345 00:33:53,380 --> 00:34:06,350 What Minsky realized was the easiest way to do this is to scan the memory in the same sense, walking the good structure, copying it out into the drum, compacted. 346 00:34:06,350 --> 00:34:12,300 And then when we were done copying it all out, then you swap that back into your memory. 347 00:34:12,300 --> 00:34:17,030 Now whether or you not use a drum, or another piece of memory, or something like that isn't important. 348 00:34:17,030 --> 00:34:20,350 In fact, I don't think people use drums anymore for anything. 349 00:34:20,350 --> 00:34:30,270 But this algorithm basically depends upon having about twice as much address space as you're actually using. 350 00:34:30,270 --> 00:34:37,110 And so what you have is some, initially, some mixture of useful data and garbage. 351 00:34:37,110 --> 00:34:38,560 So this is called fromspace. 352 00:34:45,179 --> 00:34:47,800 And this is a mixture of crud. 353 00:34:47,800 --> 00:34:52,000 Some of it's important and some of it isn't. 354 00:34:52,000 --> 00:34:58,240 Now there's another place which is hopefully big enough, if we recall, tospace, which is where we're copying to. 355 00:35:01,590 --> 00:35:04,970 And what happens is-- and I'm not going to go through this detail. 356 00:35:04,970 --> 00:35:07,590 It's in our book quite explicitly. 357 00:35:07,590 --> 00:35:11,030 There's a root point where you start from. 358 00:35:11,030 --> 00:35:14,600 And the idea is that you start with the root. 359 00:35:14,600 --> 00:35:22,810 You copy the first thing you see, the first thing that the root points at, to the beginning of tospace. 360 00:35:22,810 --> 00:35:27,560 The first thing is a pair or something like, a data structure. 361 00:35:27,560 --> 00:35:37,800 You then also leave behind a broken heart saying, I moved this object from here to here, giving the place where it moved to. 362 00:35:37,800 --> 00:35:46,760 This is called a broken heart because a friend of mine who implemented one of these in 1966 was a very romantic character and called it a broken heart. 363 00:35:49,580 --> 00:35:57,840 But in any case, the next thing you do is now you have a new free pointer which is here, and you start scanning. 364 00:35:57,840 --> 00:36:00,235 You scan this data structure you just copied. 365 00:36:00,235 --> 00:36:04,000 And every time you encounter a pointer in it, you treat it as if it was the root pointer here. 366 00:36:04,000 --> 00:36:05,170 Oh, I'm sorry. 367 00:36:05,170 --> 00:36:09,220 The other thing you do is you now move the root pointer to there. 368 00:36:09,220 --> 00:36:14,110 So now you scan this, and everything you see you treat as it were the root pointer. 369 00:36:14,110 --> 00:36:18,510 So if you see something, well it points up into there somewhere. 370 00:36:18,510 --> 00:36:21,780 Is it pointing at a thing which you've not copied yet? 371 00:36:21,780 --> 00:36:23,880 Is there a broken heart there? 372 00:36:23,880 --> 00:36:30,620 If there's a broken heart there and it's something you have copied, you've just replaced this pointer with the thing a broken heart points at. 373 00:36:30,620 --> 00:36:34,430 If this thing has not been copied, you copy it to the next place over here. 374 00:36:34,430 --> 00:36:43,670 Move your free pointer over here, and then leave a broken heart behind and scan. 375 00:36:43,670 --> 00:36:50,140 And eventually when the scant pointer hits the free pointer, everything in memory has been copied. 376 00:36:50,140 --> 00:36:54,470 And then there's a whole bunch of empty space up here, which you could either make into a free list, if that's what you want to do. 377 00:36:54,470 --> 00:36:56,270 But generally you don't in this kind of system. 378 00:36:56,270 --> 00:37:00,910 In this system you sequentially allocate your memory. 379 00:37:00,910 --> 00:37:06,790 That is a very, very nice algorithm, and sort of the one we use in the scheme that you've been using. 380 00:37:06,790 --> 00:37:12,400 And it's expected-- I believe no one has found a faster algorithm than that. 381 00:37:12,400 --> 00:37:22,010 There are very simple modifications to this algorithm invented by Henry Baker which allow one to run this algorithm in real time, meaning you don't have to stop to garbage collect. 382 00:37:22,010 --> 00:37:34,640 But you could interleave the consing that the machine does when its running with steps of the garbage collection process, so that the garbage collector's distributed, and the machine doesn't have to stop, and garbage collecting can start. 383 00:37:34,640 --> 00:37:44,460 Of course in the case of machines with virtual memory where a lot of it is in inaccessible places, this becomes a very expensive process. 384 00:37:44,460 --> 00:37:49,190 And there have been numerous attempts to make this much better. 385 00:37:49,190 --> 00:38:08,340 There is a nice paper, for those of you who are interested, by Moon and other people which describes a modification to the incremental Minsky-Feinchel-Yochelson algorithm, and modification the Baker algorithm which is more efficient for virtual memory systems. 386 00:38:08,340 --> 00:38:12,840 Well I think now the mystery to this is sort of gone. 387 00:38:12,840 --> 00:38:14,090 And I'd like to see if there are any questions. 388 00:38:19,780 --> 00:38:20,810 Yes. 389 00:38:20,810 --> 00:38:31,880 AUDIENCE: I saw one of you run the garbage collector on the systems upstairs, and it seemed to me to run extremely fast. Did the whole thing take-- does it sweep through all of memory? 390 00:38:31,880 --> 00:38:32,510 PROFESSOR: No. 391 00:38:32,510 --> 00:38:37,320 It swept through exactly what was needed to copy the useful structure. 392 00:38:37,320 --> 00:38:40,030 It's a copying collector. 393 00:38:40,030 --> 00:38:56,800 And it is very fast. On the whole, I suppose to copy-- in a Bobcat-- to copy, I think, a three megabyte thing or something is less than a second, real time. 394 00:38:56,800 --> 00:39:05,400 Really, these are very small programs. One thing you should realise is that garbage collectors have to be small. 395 00:39:05,400 --> 00:39:11,340 Not because they have to be fast, but because no one can debug a complicated garbage collector. 396 00:39:11,340 --> 00:39:18,350 A garbage collector, if it doesn't work, will trash your memory in such a way that you cannot figure out what the hell happened. 397 00:39:18,350 --> 00:39:20,660 You need an audit trail. 398 00:39:20,660 --> 00:39:23,740 Because it rearranges everything, and how do you know what happened there? 399 00:39:23,740 --> 00:39:31,970 So this is the only kind of program that it really, seriously matters if you stare at it long enough so you believe that it works. 400 00:39:31,970 --> 00:39:35,100 And sort of prove it to yourself. 401 00:39:35,100 --> 00:39:36,940 So there's no way to debug it. 402 00:39:36,940 --> 00:39:41,690 And that takes it being small enough so you can hold it in your head. 403 00:39:41,690 --> 00:39:45,020 Garbage collectors are special in this way. 404 00:39:45,020 --> 00:39:52,430 So every reasonable garbage collector has gotten small, and generally small programs are fast. Yes. 405 00:39:52,430 --> 00:39:54,510 AUDIENCE: Can you repeat the name of this technique once again? 406 00:39:54,510 --> 00:39:58,420 PROFESSOR: That's the Minsky-Feinchel-Yochelson garbage collector. 407 00:39:58,420 --> 00:39:59,340 AUDIENCE: You got that? 408 00:39:59,340 --> 00:40:02,210 PROFESSOR: Minsky invented it in '61 for the RLE PDP-1. 409 00:40:02,210 --> 00:40:19,570 A version of it was developed and elaborated to be used in Multics Maclisp by Feinchel and Yochelson in somewhere around 1968 or '69. 410 00:40:19,570 --> 00:40:20,650 OK. 411 00:40:20,650 --> 00:40:22,640 Let's take a break. 412 00:40:22,640 --> 00:40:24,184 [MUSIC: "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] 413 00:41:17,310 --> 00:41:26,740 PROFESSOR: Well we've come to the end of this subject, and we've already shown you a universal machine which is down to evaluator. 414 00:41:26,740 --> 00:41:30,420 It's down to the level of detail you could imagine you could make one. 415 00:41:30,420 --> 00:41:39,180 This is a particular implementation of Lisp, built on one of those scheme chips that was talked about yesterday, sitting over here. 416 00:41:39,180 --> 00:41:45,010 This is mostly interface to somebody's memory with a little bit of timing and other such stuff. 417 00:41:45,010 --> 00:41:50,610 But this fellow actually ran Lisp at a fairly reasonable rate, as interpretive. 418 00:41:50,610 --> 00:41:56,500 It ran Lisp as fast as a DEC PDP-10 back in 1979. 419 00:41:56,500 --> 00:41:59,870 And so it's gotten pretty hardware. 420 00:41:59,870 --> 00:42:02,470 Pretty concrete. 421 00:42:02,470 --> 00:42:07,370 We've also downed you a bit with the things you can compute. 422 00:42:07,370 --> 00:42:11,850 But is it the case that there are things we can't compute? 423 00:42:11,850 --> 00:42:18,190 And so I'd like to end this with showing you some things that you'd like be able to compute that you can't. 424 00:42:18,190 --> 00:42:22,720 The answer is yes, there are things you can't compute. 425 00:42:22,720 --> 00:42:34,630 For example, something you'd really like is-- if you're writing [UNINTELLIGIBLE], you'd like a program that would check that the thing you're going to do will work. 426 00:42:34,630 --> 00:42:36,080 Wouldn't that be nice? 427 00:42:36,080 --> 00:42:43,190 You'd like something that would catch infinite loops, for example, in programs that were written by users. 428 00:42:43,190 --> 00:42:50,990 But in general you can't write such a program that will read any program and determine whether or not it's an infinite loop. 429 00:42:50,990 --> 00:42:51,685 Let me show you that. 430 00:42:51,685 --> 00:42:53,340 It's a little bit of a minor mathematics. 431 00:42:58,780 --> 00:43:02,620 Let's imagine that we just had a mathematical function before we start. 432 00:43:02,620 --> 00:43:14,230 And there is one, called s, which takes a procedure and its argument, a. 433 00:43:19,320 --> 00:43:26,632 And what s does is it determines whether or not it's safe to run p on a. 434 00:43:26,632 --> 00:43:45,330 And what I mean by that is this: it's true if p applied to a will converge to a value without an error. 435 00:43:52,365 --> 00:44:06,890 And it's false if p of a loops forever or makes an error. 436 00:44:15,000 --> 00:44:18,780 Now that's surely a function. 437 00:44:18,780 --> 00:44:28,440 There is some for every procedure and for every argument you could give it that is either true or false that it converges without making an error. 438 00:44:28,440 --> 00:44:31,770 And you could make a giant table of them. 439 00:44:31,770 --> 00:44:37,430 But the question is, can you write a procedure that compute the values of this function? 440 00:44:37,430 --> 00:44:39,720 Well let's assume that we can. 441 00:44:39,720 --> 00:44:59,990 Suppose that we have a procedure called "safe" that computes the value of s. 442 00:45:12,170 --> 00:45:19,760 Now I'm going to show you by several methods that you can't do this. 443 00:45:19,760 --> 00:45:23,810 The easiest one, or the first one, let's define a procedure called diag1. 444 00:45:23,810 --> 00:45:44,780 Given that we have safe, we can define diag1 to be the procedure of one argument, p, which has the following properties. 445 00:45:44,780 --> 00:45:55,870 If if it's safe to apply p to itself, then I wish to have an infinite loop. 446 00:45:59,330 --> 00:46:00,715 Otherwise I'm going to return 3. 447 00:46:03,680 --> 00:46:04,470 Remember it was 42. 448 00:46:04,470 --> 00:46:07,060 What's the answer to the big question? 449 00:46:07,060 --> 00:46:08,525 Where of course we know what an infinite loop is. 450 00:46:12,050 --> 00:46:18,430 Infinite loop, to be a procedure of no arguments, which is that nice lambda calculus loop. 451 00:46:18,430 --> 00:46:24,680 Lambda of x, x of x, applied to lambda of x, x of x. 452 00:46:24,680 --> 00:46:26,550 So there's nothing left to the imagination here. 453 00:46:29,830 --> 00:46:32,500 Well let's see what the story is. 454 00:46:32,500 --> 00:46:43,180 I'm supposing it's the case that we worry about the procedure called diag1 applied to diag1. 455 00:46:45,860 --> 00:46:49,970 Well what could it possibly be? 456 00:46:49,970 --> 00:46:51,390 Well I don't know. 457 00:46:51,390 --> 00:46:57,310 We're going to substitute diag1 for p in the body here. 458 00:46:57,310 --> 00:47:00,220 Well is it safe to compute diag1 of diag1? 459 00:47:00,220 --> 00:47:00,780 I don't know. 460 00:47:00,780 --> 00:47:03,400 There are two possibilities. 461 00:47:03,400 --> 00:47:08,490 If it's safe to compute diag1 of diag1 that means it shouldn't loop. 462 00:47:08,490 --> 00:47:10,560 That means I go to here, but then I produce an infinite loop. 463 00:47:10,560 --> 00:47:12,210 So it can't be safe. 464 00:47:12,210 --> 00:47:16,020 But if it's not safe to compute diag1 of diag1 then the answer to this is 3. 465 00:47:16,020 --> 00:47:20,530 But that's diag1 of diag1, so it had to be safe. 466 00:47:20,530 --> 00:47:27,470 So therefore by contradiction you cannot produce safe. 467 00:47:27,470 --> 00:47:32,820 For those of you who were boggled by that one I'm going to say it again, in a different way. 468 00:47:32,820 --> 00:47:35,530 Listen to one more alternative. 469 00:47:35,530 --> 00:47:36,780 Let's define diag2. 470 00:47:39,840 --> 00:47:45,260 These are named diag because of Cantor's diagonal argument. 471 00:47:45,260 --> 00:48:00,190 These are instances of a famous argument which was originally used by Cantor in the late part of the last century to prove that the real numbers were not countable, that there are too many real numbers to be counted by integers. 472 00:48:00,190 --> 00:48:05,260 That there are more points on a line, for example, than there are counting numbers. 473 00:48:05,260 --> 00:48:08,440 It may or may not be obvious, and I don't want to get into that now. 474 00:48:10,900 --> 00:48:15,820 But diag2 is again a procedure of one argument p. 475 00:48:15,820 --> 00:48:38,960 It's almost the same as the previous one, which is, if it's safe to compute p on p, then I'm going to produce-- then I want to compute some other things other than p of p. 476 00:48:38,960 --> 00:48:40,210 Otherwise I'm going to put out false. 477 00:48:43,600 --> 00:48:48,880 Where other then it says, whatever p of p, I'm going to put out something else. 478 00:48:48,880 --> 00:48:53,890 I can give you an example of a definition of other than which I think works. 479 00:48:53,890 --> 00:48:55,640 Let's see. 480 00:48:55,640 --> 00:48:56,330 Yes. 481 00:48:56,330 --> 00:49:15,720 Where other than be a procedure of one argument x which says, if its eq x to, say, quote a, then the answer is quote b. 482 00:49:15,720 --> 00:49:16,970 Otherwise it's quote a. 483 00:49:20,090 --> 00:49:25,350 That always produces something which is not what its argument is. 484 00:49:25,350 --> 00:49:26,540 That's all it is. 485 00:49:26,540 --> 00:49:28,250 That's all I wanted. 486 00:49:28,250 --> 00:49:30,640 Well now let's consider this one, diag2 of diag2. 487 00:49:38,220 --> 00:49:39,560 Well look. 488 00:49:39,560 --> 00:49:47,470 This only does something dangerous, like calling p of p, if it's safe to do so. 489 00:49:47,470 --> 00:49:57,225 So if safe defined at all, if you can define such a procedure, safe, then this procedure is always defined and therefore safe on any inputs. 490 00:50:01,540 --> 00:50:11,770 So diag2 of diag2 must reduce to other than diag2 of diag2. 491 00:50:15,496 --> 00:50:22,950 And that doesn't make sense, so we have a contradiction, and therefore we can't define safe. 492 00:50:22,950 --> 00:50:32,260 I just waned to do that twice, slightly differently, so you wouldn't feel that the first one was a trick. 493 00:50:32,260 --> 00:50:37,300 They may be both tricks, but they're at least slightly different. 494 00:50:37,300 --> 00:50:40,080 So I suppose that pretty much wraps it up. 495 00:50:40,080 --> 00:50:46,720 I've just proved what we call the halting theorem, and I suppose with that we're going to halt. 496 00:50:46,720 --> 00:50:47,970 I hope you have a good time. 497 00:50:50,900 --> 00:50:53,300 Are there any questions? 498 00:50:53,300 --> 00:50:53,810 Yes. 499 00:50:53,810 --> 00:50:56,940 AUDIENCE: What is the value of s of diag1? 500 00:50:56,940 --> 00:50:57,430 PROFESSOR: Of what? 501 00:50:57,430 --> 00:51:00,120 AUDIENCE: S of diag1. 502 00:51:00,120 --> 00:51:02,620 If you said s is a function and we can [INTERPOSING VOICES] 503 00:51:02,620 --> 00:51:03,870 PROFESSOR: Oh, I don't know. 504 00:51:03,870 --> 00:51:04,350 I don't know. 505 00:51:04,350 --> 00:51:06,850 It's a function, but I don't know how to compute it. 506 00:51:06,850 --> 00:51:08,610 I can't do it. 507 00:51:08,610 --> 00:51:11,530 I'm just a machine, too. 508 00:51:11,530 --> 00:51:12,210 Right? 509 00:51:12,210 --> 00:51:18,580 There's no machine that in principle-- it might be that in that particular case you just asked, with some thinking I could figure it out. 510 00:51:18,580 --> 00:51:23,780 But in general I can't compute the value of s any better than any other machine can. 511 00:51:23,780 --> 00:51:29,580 There is such a function, it's just that no machine can be built to compute it. 512 00:51:29,580 --> 00:51:35,350 Now there's a way of saying that that should not be surprising. 513 00:51:35,350 --> 00:51:44,600 Going through this-- I mean, I don't have time to do this here, but the number of functions is very large. 514 00:51:44,600 --> 00:51:54,720 If there's a certain number of answers possible and a certain number of inputs possible, then it's the number of answers raised to the number inputs is the number of possible functions. 515 00:51:54,720 --> 00:51:55,970 On one variable. 516 00:51:58,150 --> 00:52:05,480 Now that's always bigger than the thing you're raising to, the exponent. 517 00:52:05,480 --> 00:52:17,840 The number of functions is larger than the number of programs that one can write, by an infinity counting argument. 518 00:52:17,840 --> 00:52:19,475 And it's much larger. 519 00:52:19,475 --> 00:52:26,280 So there must be a lot of functions that can't be computed by programs. 520 00:52:26,280 --> 00:52:30,640 AUDIENCE: A few moments ago you were talking about specifications and automatic generation of solutions. 521 00:52:30,640 --> 00:52:33,360 Do you see any steps between specifications and solutions? 522 00:52:37,250 --> 00:52:38,720 PROFESSOR: Steps between. 523 00:52:38,720 --> 00:52:45,205 You mean, you're saying, how you go about constructing devices given that have specifications for the device? 524 00:52:45,205 --> 00:52:45,500 Sure. 525 00:52:45,500 --> 00:52:52,430 AUDIENCE: There's a lot of software engineering that goes through specifications through many layers of design and then implementation. 526 00:52:52,430 --> 00:52:52,850 PROFESSOR: Yes? 527 00:52:52,850 --> 00:52:55,600 AUDIENCE: I was curious if you think that's realistic. 528 00:52:55,600 --> 00:52:58,100 PROFESSOR: Well I think that some of it's realistic and some of it isn't. 529 00:52:58,100 --> 00:53:07,160 I mean, surely if I want to build an electrical filter and I have a rather interesting possibility. 530 00:53:07,160 --> 00:53:19,906 Supposing I want to build a thing that matches some power output to the radio transmitter, to some antenna. 531 00:53:19,906 --> 00:53:23,230 And I'm really out of this power-- it's output tube out here. 532 00:53:23,230 --> 00:53:25,920 And the problem is that they have different impedances. 533 00:53:25,920 --> 00:53:27,550 I want them to match the impedances. 534 00:53:27,550 --> 00:53:32,780 I also want to make a filter in there which is going to get rid of some harmonic radiation. 535 00:53:32,780 --> 00:53:38,860 Well one old-fashioned technique for doing this is called image impedances, or something like that. 536 00:53:38,860 --> 00:53:43,300 And what you do is you say you have a basic module called an L-section. 537 00:53:43,300 --> 00:53:44,550 Looks like this. 538 00:53:47,080 --> 00:54:02,110 If I happen to connect this to some resistance, r, and if I make this impedance x, xl, and if it happens to be q times r, then this produces a low pass filter with a q square plus one impedance match. 539 00:54:02,110 --> 00:54:03,120 Just what I need. 540 00:54:03,120 --> 00:54:06,510 Because now I can take two of these, hook them together like this. 541 00:54:11,660 --> 00:54:18,290 OK, and I take another one and I'll hook them together like that. 542 00:54:18,290 --> 00:54:20,320 And I have two L-sections hooked together. 543 00:54:20,320 --> 00:54:25,530 And this will step the impedance down to one that I know, and this will step it up to one I know. 544 00:54:25,530 --> 00:54:28,090 Each of these is a low pass filter getting rid of some harmonics. 545 00:54:28,090 --> 00:54:30,270 It's good filter, it's called a pie-section filter. 546 00:54:30,270 --> 00:54:31,700 Great. 547 00:54:31,700 --> 00:54:38,620 Except for the fact that in doing what I just did, I've made a terrible inefficiency in this system. 548 00:54:38,620 --> 00:54:41,620 I've made two coils where I should have made one. 549 00:54:41,620 --> 00:54:55,350 And the problem with most software engineering art is that there's no mechanism, other than peephole optimization and compilers, for getting rid of the redundant parts that are constructed when doing top down design. 550 00:54:55,350 --> 00:55:01,110 It's even worse, there are lots of very important structures that you can't construct at all this way. 551 00:55:01,110 --> 00:55:05,710 So I think that the standard top down design is a rather shallow business. 552 00:55:05,710 --> 00:55:08,315 Doesn't really capture what people want to do in design. 553 00:55:08,315 --> 00:55:10,100 I'll give you another electrical example. 554 00:55:10,100 --> 00:55:17,220 Electrical examples are so much clearer than computational examples, because computation examples require a certain degree of complexity to explain them. 555 00:55:17,220 --> 00:55:27,530 But one of my favorite examples in the electrical world is how would I ever come up with the output stage of this inter-stage connection in an IF amplifier. 556 00:55:27,530 --> 00:55:32,410 It's a little transistor here, and let's see. 557 00:55:32,410 --> 00:55:44,850 Well I'm going to have a tank, and I'm going to hook this up to, say, I'm going to link-couple that to the input of the next stage. 558 00:55:44,850 --> 00:55:53,170 Here's a perfectly plausible plan-- well except for the fact that since I put that going up I should make that going that way. 559 00:55:53,170 --> 00:55:57,270 Here's a perfectly plausible plan for a-- no I shouldn't. 560 00:55:57,270 --> 00:55:57,940 I'm dumb. 561 00:55:57,940 --> 00:55:59,690 Excuse me. 562 00:55:59,690 --> 00:56:00,730 Doesn't matter. 563 00:56:00,730 --> 00:56:01,540 The point is [UNINTELLIGIBLE] 564 00:56:01,540 --> 00:56:02,560 plan for a couple [UNINTELLIGIBLE] 565 00:56:02,560 --> 00:56:04,590 stages together. 566 00:56:04,590 --> 00:56:07,620 Now what the problem is is what's this hierarchically? 567 00:56:07,620 --> 00:56:09,480 It's not one thing. 568 00:56:09,480 --> 00:56:11,990 Hierarchically it doesn't make any sense at all. 569 00:56:11,990 --> 00:56:26,460 It's the inductance of a tuned circuit, it's the primary of a transformer, and it's also the DC path by which bias conditions get to the collector of that transistor. 570 00:56:26,460 --> 00:56:34,530 And there's no simple top-down design that's going to produce a structure like that with so many overlapping uses for a particular thing. 571 00:56:34,530 --> 00:56:44,950 Playing Scrabble, where you have to do triple word scores, or whatever, is not so easy in top-down design strategy. 572 00:56:44,950 --> 00:56:52,140 Yet most of real engineering is based on getting the most oomph for effort. 573 00:56:52,140 --> 00:56:54,860 And that's what you're seeing here. 574 00:56:54,860 --> 00:56:55,550 Yeah? 575 00:56:55,550 --> 00:56:56,810 AUDIENCE: Is this the last question? 576 00:57:00,282 --> 00:57:18,640 [LAUGHTER] 577 00:57:18,640 --> 00:57:19,890 PROFESSOR: Apparently so. 578 00:57:23,240 --> 00:57:26,092 Thank you. 579 00:57:26,092 --> 00:57:39,040 [APPLAUSE] 580 00:57:39,040 --> 00:57:40,633 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] ================================================ FILE: SrtCN/lec10b.srt ================================================ 1 00:00:00,000 --> 00:00:00,720 Learning-SICP学习小组 倾情制作 2 00:00:00,720 --> 00:00:02,720 翻译&&时间轴:杨启钊(windfarer) 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:02,720 --> 00:00:04,725 特别感谢:裘宗燕教授 4 00:00:04,720 --> 00:00:11,808 计算机程序的构造和解释 5 00:00:11,888 --> 00:00:18,112 存储分配与垃圾收集 6 00:00:18,910 --> 00:00:20,612 教授: 接下来我要解开 PROFESSOR: Well, there's one bit of mystery left, 7 00:00:21,168 --> 00:00:23,360 目前仅剩的谜团 which I'd like to get rid of right now. 8 00:00:24,440 --> 00:00:28,804 我们能毫无顾虑地进行CONS And that's that we've been blithely doing things like cons 9 00:00:30,000 --> 00:00:31,620 就好像空间足够多一样 assuming there's always another one. 10 00:00:32,800 --> 00:00:36,320 我们总是在使用 That we've been doing these things like 11 00:00:36,510 --> 00:00:37,440 CAR和CDR car-ing and cdr-ing 12 00:00:37,470 --> 00:00:38,720 并假设知道我们知道 and assuming that we had some idea 13 00:00:38,752 --> 00:00:39,740 它们是如何实现的 how this can be done. 14 00:00:40,020 --> 00:00:40,675 事实上 Now indeed 15 00:00:41,075 --> 00:00:44,403 我们认为它们是基本过程 we said that that's equivalent to having procedures. 16 00:00:45,376 --> 00:00:47,570 但这没有真正解决问题 OK? But that doesn't really solve the problem, 17 00:00:47,730 --> 00:00:50,256 因为过程依赖各种复杂的机制 because the procedure need all sorts of complicated mechanisms 18 00:00:50,272 --> 00:00:51,376 需要诸如环境结构之类的东西 like environment structures 19 00:00:51,640 --> 00:00:52,768 才能运行起来 and things like that to work. 20 00:00:53,010 --> 00:00:54,890 而归根结底它们也是 And those were ultimately made out of conses 21 00:00:54,890 --> 00:00:56,425 由CONS之类的东西构成的 in the model that we had, 22 00:00:56,700 --> 00:00:58,473 这的确没有解决问题 so that really doesn't solve the problem. 23 00:00:59,380 --> 00:01:01,136 目前的问题是 Now the problem here is 24 00:01:01,312 --> 00:01:03,970 粘合这些数据结构的是什么东西? is the glue the data structure's made out of. 25 00:01:04,760 --> 00:01:06,409 它可能是怎样的一个东西? What kind of possible thing could it be? 26 00:01:07,040 --> 00:01:10,460 我们已经见过了一台机器 OK? We've been showing you things like a machine, 27 00:01:10,460 --> 00:01:13,968 一台计算机具有一个控制器 a computer that has a controller, 28 00:01:14,275 --> 00:01:15,450 和一些寄存器 and some registers, 29 00:01:15,450 --> 00:01:16,475 还可能有一个栈 and maybe a stack. 30 00:01:16,980 --> 00:01:18,128 但是我们还没提到一些东西 And we haven't said anything about, 31 00:01:18,160 --> 00:01:19,950 例如 大内存 for example, larger memory. 32 00:01:20,570 --> 00:01:22,382 我想 现在是时候讨论它们了 And I think that's what we have to worry about right now. 33 00:01:23,740 --> 00:01:26,560 但是先要说清楚 But just to make it perfectly clear 34 00:01:26,592 --> 00:01:27,888 这个并不是必须的 that this is an inessential, 35 00:01:28,825 --> 00:01:30,791 只是一些实现上的细节 purely implementational thing, 36 00:01:31,100 --> 00:01:32,600 让我举个例子 I'd like to show you, for example, 37 00:01:32,600 --> 00:01:34,208 如何用数字来表示这些东西 how you can do it all with the numbers. 38 00:01:35,232 --> 00:01:36,820 有个比较简单的方法 That's an easy one. 39 00:01:37,590 --> 00:01:39,000 一位著名的逻辑学家 哥德尔 Famous fellow by the name of Godel, 40 00:01:44,096 --> 00:01:46,016 在20世纪30年代末 a logician at the end of the 1930s, 41 00:01:46,384 --> 00:01:48,700 发明了一个很巧妙的方法 invented a very clever way 42 00:01:48,700 --> 00:01:52,275 能够把复杂的表达式 of encoding the complicated expressions 43 00:01:52,816 --> 00:01:53,520 表示成数字 as numbers. 44 00:01:54,320 --> 00:01:55,050 例如 For example-- 45 00:01:55,050 --> 00:01:58,000 我不会照搬哥德尔的方法 I'm not saying exactly what Godel's scheme is, 46 00:01:58,000 --> 00:01:59,488 因为他没有使用CONS之类的术语 because he didn't use words like cons. 47 00:01:59,660 --> 00:02:00,608 他使用了其它的组合手段 He had other kinds of 48 00:02:00,912 --> 00:02:02,600 来编码表达式 of ways of combining to make expressions. 49 00:02:03,090 --> 00:02:03,888 他的思路是 But he said, 50 00:02:03,920 --> 00:02:06,816 用不同数字分别代表每个代数式 I'm going to assign a number to every algebraic expression. 51 00:02:07,920 --> 00:02:09,725 通过组合各个部分的数字 And the way I'm going to manufacture these numbers 52 00:02:09,725 --> 00:02:11,650 来形成新的表达式 is by combining the numbers of the parts. 53 00:02:12,470 --> 00:02:13,456 举例来说 So for example, 54 00:02:13,625 --> 00:02:15,350 我们在创造世界的时候 what we were doing our world, 55 00:02:15,350 --> 00:02:18,016 如果用数字 we could say that if objects 56 00:02:20,784 --> 00:02:22,220 来表示对象 are represented by numbers, 57 00:02:30,670 --> 00:02:37,936 那么(CONS X Y) then cons of x and y 58 00:02:38,040 --> 00:02:41,072 就可以表示为 could be represented by, 59 00:02:41,552 --> 00:02:43,770 2^X * 3^Y 2 to the x times 3 to the y. 60 00:02:46,130 --> 00:02:48,032 因为这样我们还能取出它的每一部分 Because then we could extract the parts. 61 00:02:49,560 --> 00:02:50,976 举例来说 We could say, for example, 62 00:02:51,184 --> 00:02:55,888 (CAR X) that then car of, say, x 63 00:02:56,550 --> 00:03:05,184 就是X中因数2的个数 is the number of factors of 2 in x. 64 00:03:06,690 --> 00:03:08,784 当然(CDR X)是一样的 OK? And of course cdr is the same thing. 65 00:03:10,690 --> 00:03:15,579 它就X中因数3的个数 It's the number of factors of 3 in x. 66 00:03:16,510 --> 00:03:18,651 这是个非常合理的方案 Now this is a perfectly reasonable scheme, 67 00:03:19,100 --> 00:03:20,112 只不过就是 except for the fact that 68 00:03:20,120 --> 00:03:22,528 数字的位数 the numbers rapidly get to be much larger 69 00:03:22,832 --> 00:03:23,980 会急剧地增大 in number of digits 70 00:03:24,320 --> 00:03:26,550 甚至比宇宙中的粒子还多 than the number of protons in the universe. 71 00:03:27,950 --> 00:03:29,888 所以除了在理论中 So there's no easy way to use this scheme 72 00:03:29,904 --> 00:03:31,216 没有实现这种方案的好办法 other than the theoretical one. 73 00:03:33,430 --> 00:03:34,486 另一方面 On the other hand, 74 00:03:35,125 --> 00:03:37,558 也有其它的表示方式 there are other ways of representing these things. 75 00:03:38,450 --> 00:03:40,016 我们把它们表示为 We have been thinking in terms 76 00:03:40,256 --> 00:03:42,420 一些小盒子 of little boxes, boxes. 77 00:03:43,320 --> 00:03:46,432 我们把CONS结构 We've been thinking about our cons structures 78 00:03:46,500 --> 00:03:48,054 想象为这样的东西 as looking sort of like this. 79 00:03:50,280 --> 00:03:52,576 它们是里面装着东西的小隔间 They're little pigeon holes with things in them. 80 00:03:53,568 --> 00:03:55,470 这些格子组成一个树 And of course we arrange them in little trees. 81 00:03:57,210 --> 00:03:59,975 我希望半导体制造商 I wish that the semiconductor manufacturers 82 00:03:59,975 --> 00:04:02,075 能够提供适配这样需求的芯片 would supply me with something appropriate for this, 83 00:04:02,700 --> 00:04:03,760 但事实上 but actually 84 00:04:03,850 --> 00:04:05,312 他们提供给我的却是 what they do supply me with 85 00:04:06,208 --> 00:04:07,960 线性的内存 is a linear memory. 86 00:04:09,380 --> 00:04:13,467 内存是一串小隔间 Memory is sort of a big pile of pigeonholes, 87 00:04:15,120 --> 00:04:16,340 像这样的小隔间 pigeonholes like this. 88 00:04:17,720 --> 00:04:20,251 每个小隔间里可以保存确定大小的对象 Each of which can hold a certain sized object, 89 00:04:20,944 --> 00:04:22,200 一个尺寸固定的对象 a fixed size object. 90 00:04:23,390 --> 00:04:24,075 例如 So, for example, 91 00:04:24,070 --> 00:04:25,664 一个含25个元素的表 a complicated list with 25 elements 92 00:04:25,664 --> 00:04:26,640 就放不进这里 won't fit in one of these. 93 00:04:28,550 --> 00:04:29,264 然而 它们中的每一个 However, each of these 94 00:04:29,296 --> 00:04:30,880 都是由地址索引的 is indexed by an address. 95 00:04:33,970 --> 00:04:34,992 因此它们的地址可能是 So the address might be 96 00:04:35,024 --> 00:04:35,500 这里是0 zero here, 97 00:04:35,500 --> 00:04:36,225 这里是1 one here, 98 00:04:36,225 --> 00:04:36,700 这里是2 two here, 99 00:04:36,700 --> 00:04:37,250 这里是3 three here, 100 00:04:37,250 --> 00:04:37,944 以此类推 and so on. 101 00:04:38,060 --> 00:04:40,400 这里写的数字并不重要 That we write these down as numbers is unimportant. 102 00:04:40,400 --> 00:04:41,680 重要的是 它们不重复 What matters is that they're distinct 103 00:04:41,950 --> 00:04:43,425 有了它们就能找到下一个在哪 as a way to get to the next one. 104 00:04:44,970 --> 00:04:46,144 在其中每一个小隔间里面 And inside of each of these, 105 00:04:46,366 --> 00:04:49,110 我们可以把东西放进去 we can stuff something into these pigeonholes. 106 00:04:49,530 --> 00:04:50,774 对于没有造过计算机的我们来说 That's what memory is like, 107 00:04:51,020 --> 00:04:53,664 内存就是这样子的 for those of you who haven't built a computer. 108 00:04:54,150 --> 00:04:54,650 现在 Now. 109 00:04:56,690 --> 00:04:57,536 现在的问题是 Now the problem is 110 00:04:57,536 --> 00:04:59,970 如何用这样的结构 how are we going to impose on this type of structure, 111 00:05:00,425 --> 00:05:01,725 来实现这个树形结构 this nice tree structure. 112 00:05:03,290 --> 00:05:04,575 其实并不难 Well it's not very hard, 113 00:05:04,575 --> 00:05:06,350 已经有大量的方案来做这个了 and there have been numerous schemes involved in this. 114 00:05:06,875 --> 00:05:08,800 最重要的一个方案是 The most important one is to say, 115 00:05:08,800 --> 00:05:11,184 假设半导体制造商 well assuming that the semiconductor manufacturer 116 00:05:11,200 --> 00:05:13,904 允许我安排自己的内存 allows me to arrange my memory 117 00:05:13,984 --> 00:05:15,770 使得其中每个小隔间都足够大 so that one of these pigeonholes is big enough 118 00:05:16,280 --> 00:05:18,208 能够装得下另一个的地址 to hold the address of another 119 00:05:19,350 --> 00:05:20,831 我需要这么来安排 OK. I have been made. 120 00:05:22,050 --> 00:05:23,456 事实上它需要更大一点 Now it actually has to be a little bit bigger 121 00:05:23,480 --> 00:05:27,520 因为我还要在里面存放一些信息 because I have to also install or store some information 122 00:05:27,568 --> 00:05:30,096 它标示了这里面是什么东西 as to a tag which describes the kind of thing that's there. 123 00:05:30,390 --> 00:05:31,647 我们过一会就能看到 And we'll see that in a second. 124 00:05:32,620 --> 00:05:34,400 当然 如果半导体制造商 And of course if the semiconductor manufacturer 125 00:05:34,432 --> 00:05:35,888 没有这么来制造 doesn't arrange it so I can do that, 126 00:05:36,080 --> 00:05:38,448 我就需要用一些机智的方式 then of course I can, with some cleverness, 127 00:05:38,575 --> 00:05:41,823 把它们组合起来以供使用 arrange combinations of these to fit together in that way. 128 00:05:43,770 --> 00:05:47,050 我们想象一下 So we're going to have to imagine 129 00:05:47,050 --> 00:05:49,546 把这个复杂的树形结构 imposing this complicated tree structure 130 00:05:49,546 --> 00:05:51,200 塞进线性内存里 on our nice linear memory. 131 00:05:51,740 --> 00:05:54,475 我们来看第一张幻灯片 If we look at the first still store, 132 00:05:54,475 --> 00:05:58,304 可以看到一个传统的实现方案 we see a classic scheme for doing that. 133 00:05:59,490 --> 00:06:02,625 它是把表结构放入线性内存 It's a standard way of representing list structures 134 00:06:03,225 --> 00:06:05,875 的标准方式 in a linear memory. 135 00:06:06,275 --> 00:06:08,325 我们把这块内存 What we do is we divide this memory 136 00:06:08,880 --> 00:06:11,120 分为两部分 into two parts. 137 00:06:12,030 --> 00:06:13,427 一个叫THE-CARS的数组 An array called the cars, 138 00:06:14,450 --> 00:06:15,888 一个叫THE-CDRS的数组 and an array called the cdrs. 139 00:06:17,580 --> 00:06:18,864 无论它们是 Now whether those happen to be 140 00:06:18,880 --> 00:06:21,040 顺序的地址或是其它的 sequential addresses or whatever, 141 00:06:21,120 --> 00:06:22,000 其实并不重要 it's not important. 142 00:06:22,875 --> 00:06:25,203 这是实现细节了 That's somebody's implementation details. 143 00:06:25,800 --> 00:06:28,403 但有两个数组 But there are two arrays here. 144 00:06:28,960 --> 00:06:30,368 线性数组是由 Linear arrays indexed 145 00:06:30,464 --> 00:06:32,590 顺序的下标索引的 by sequential indices like this. 146 00:06:34,840 --> 00:06:36,851 每个小格子里存的 What is stored in each of these pigeonholes 147 00:06:37,467 --> 00:06:39,859 是一个带类型的对象 is a typed object. 148 00:06:41,430 --> 00:06:42,575 这里的类型 And what we have here 149 00:06:42,570 --> 00:06:45,712 以字母P开头 are types which begin with letters like p, 150 00:06:45,712 --> 00:06:46,576 表示序对 standing for a pair. 151 00:06:47,790 --> 00:06:49,375 以N开头 表示数字 Or n, standing for a number. 152 00:06:50,040 --> 00:06:52,255 E开头 表示空表 Or e, standing for an empty list. 153 00:06:54,813 --> 00:06:55,839 也就是表尾标志 The end of the list. 154 00:06:57,020 --> 00:06:58,592 如果我们想表示 And so if we wish to represent 155 00:06:58,992 --> 00:06:59,970 这样一个对象 an object like this, 156 00:07:00,016 --> 00:07:02,160 首元素为(1 2) the list beginning with 1, 2 157 00:07:02,650 --> 00:07:04,016 然后3、4分别作为 and then having a 3 and a 4 158 00:07:04,016 --> 00:07:05,500 它的第二和第三个元素 and then having a 3 and a 4 as its second and third elements. 159 00:07:06,430 --> 00:07:08,831 这个表的第一部分也是一个表 A list containing a list as its first part 160 00:07:09,350 --> 00:07:10,650 后面接着是两个数字 and then two numbers 161 00:07:10,650 --> 00:07:12,000 分别为第二和第三部分 as a second and third parts. 162 00:07:12,870 --> 00:07:14,816 现在我们用盒子-指针表示法 Then of course we draw it sort of like this these days, 163 00:07:14,848 --> 00:07:16,670 来描绘它 in box-and-pointer notation. 164 00:07:17,320 --> 00:07:18,000 你能发现 And you see, 165 00:07:18,000 --> 00:07:20,048 这里有三个单元 these are the three cells 166 00:07:20,256 --> 00:07:22,016 它们的CAR指针 that have as their car pointer 167 00:07:22,275 --> 00:07:27,104 分别指向对象(1 2)、3以及4 the object which is either 1, 2 or 3 or 4. 168 00:07:28,390 --> 00:07:29,750 当然这个(1 2) And then of course the 1, 2, 169 00:07:29,750 --> 00:07:31,325 即整个结构的CAR the car of this entire structure, 170 00:07:31,320 --> 00:07:32,656 本身就是一个子结构 is itself a substructure 171 00:07:32,880 --> 00:07:34,752 包含一个像这样的子表 which contains a sublist like that. 172 00:07:35,940 --> 00:07:37,072 我要做的是 What I'm about to do 173 00:07:37,200 --> 00:07:39,920 就是按照下标 is put down places which are-- 174 00:07:39,952 --> 00:07:41,460 把它们放进去 I'm going to assign indices. 175 00:07:41,840 --> 00:07:43,408 像这里的1 Like this 1, over here, 176 00:07:43,560 --> 00:07:47,056 代表了这个格子的下标 represents the index of this cell. 177 00:07:49,850 --> 00:07:51,475 这里的指针 But that pointer that we see here 178 00:07:52,370 --> 00:07:54,864 是对THE-CARS is a reference to the 179 00:07:55,072 --> 00:07:57,296 和THE-CDRS里的小格子的引用 pair of pigeonholes in the cars and the cdrs 180 00:07:57,400 --> 00:07:58,675 它在我的线性内存中 that are labeled by 1 181 00:07:58,768 --> 00:08:00,336 被标记为1的地方 in my linear memory down here. 182 00:08:02,000 --> 00:08:04,064 如果我想把这个结构 So if I wish to impose this structure 183 00:08:04,160 --> 00:08:05,264 塞进线性内存中 on my linear memory, 184 00:08:05,850 --> 00:08:07,525 要做的是 what I do is I say, oh yes, 185 00:08:07,520 --> 00:08:11,888 把它放进格子1中 why don't we drop this into cell 1? 186 00:08:11,952 --> 00:08:12,660 我要选取1号格子 Well I said, I pick 1. 187 00:08:12,660 --> 00:08:13,856 这个就是1号格子 There's 1. OK? 188 00:08:14,270 --> 00:08:16,225 这是它的CAR And that says that its car, 189 00:08:16,220 --> 00:08:17,744 我要把它赋值给一个序对 I'm going to assign it to be a pair. 190 00:08:17,950 --> 00:08:18,725 这个序对 It's a pair, 191 00:08:20,025 --> 00:08:21,555 序号是5 which is in index 5. 192 00:08:22,590 --> 00:08:23,900 它的CDR And the cdr, 193 00:08:23,900 --> 00:08:25,139 就是这个 which is this one over here, 194 00:08:25,390 --> 00:08:26,135 它是个序对 is a pair 195 00:08:26,135 --> 00:08:27,700 我会把它放到2的位置 which I'm going to stick into place 2. 196 00:08:28,340 --> 00:08:28,980 即P2 p2. 197 00:08:30,890 --> 00:08:32,950 我们看P2 And take a look at p2. 198 00:08:32,950 --> 00:08:34,725 P2的CAR Oh yes, well p2 is a thing 199 00:08:34,900 --> 00:08:37,225 是数字3 whose car is the number 3, 200 00:08:37,344 --> 00:08:38,640 如你所见N3 so as you see, an n3. 201 00:08:39,520 --> 00:08:41,524 这里 它的CDR And whose cdr, over here, 202 00:08:41,727 --> 00:08:43,400 是一个序对 is a pair, 203 00:08:43,975 --> 00:08:45,812 在位置4 which lives in place 4. 204 00:08:46,640 --> 00:08:47,796 这就是P4 So that's what this p4 is. 205 00:08:48,650 --> 00:08:51,167 P4是一个数字 p4 is a number 206 00:08:51,850 --> 00:08:53,876 它的CAR部分是数字4 whose value is 4 in its car 207 00:08:54,608 --> 00:08:55,650 它的CDR and whose cdr 208 00:08:55,840 --> 00:08:58,480 是个空表 就在这儿 is an empty list right there. 209 00:08:59,170 --> 00:08:59,904 这个表就结束了 And that ends it. 210 00:09:00,690 --> 00:09:04,576 这就是在线性内存中 So this is the traditional way of representing 211 00:09:04,900 --> 00:09:09,552 表示二叉树的传统方式 this kind of binary tree in a linear memory. 212 00:09:11,620 --> 00:09:15,100 那么 下一个问题是 Now the next question, of course, 213 00:09:15,100 --> 00:09:16,368 我们需要关心 that we might want to worry about 214 00:09:16,608 --> 00:09:18,192 如何去实现 is just a little bit of implementation. 215 00:09:18,440 --> 00:09:20,336 这意味着当我写下一个过程 That means that when I write procedures 216 00:09:20,368 --> 00:09:23,620 用来给A赋值时 of the form assigned a, 217 00:09:24,544 --> 00:09:27,104 使用寄存机器的代码来编写的 lines of register machine code 218 00:09:27,216 --> 00:09:30,140 (ASSIGN A (FETCH B)) of the form assigned a, the car of fetch of b, 219 00:09:30,848 --> 00:09:31,856 我实际上想做的是 what I really mean 220 00:09:31,975 --> 00:09:37,100 定位这些元素 is addressing these elements. 221 00:09:38,740 --> 00:09:40,256 那段机器代码只是 And so we're going to think of that as 222 00:09:40,688 --> 00:09:42,944 这个复杂过程的简写 a abbreviation for it. 223 00:09:44,470 --> 00:09:46,336 当然 为了把它“写下来” Now of course in order to write that down 224 00:09:46,350 --> 00:09:48,592 我要引入一种 I'm going to introduce some sort of a structure 225 00:09:48,624 --> 00:09:49,424 称为“向量”的结构 called a vector. 226 00:09:52,120 --> 00:09:53,312 我们得有一种东西 And we're going to have something which will 227 00:09:53,480 --> 00:09:54,544 用来引用向量 reference a vector, 228 00:09:56,840 --> 00:09:58,512 这样我们就能把它写下来 just so we can write it down. 229 00:09:58,710 --> 00:10:00,224 它的参数之一是向量的名字 Which takes the name of the vector, 230 00:10:01,025 --> 00:10:03,970 我觉得这个名字起得不太靠谱 or the-- I don't think that name is the right word. 231 00:10:03,970 --> 00:10:09,400 它接受VECTOR和INDEX两个参数 Which takes the vector and the index, 232 00:10:11,200 --> 00:10:13,056 我可以用VECTOR-SET! and I have to have a way of setting one of those 233 00:10:13,104 --> 00:10:14,272 来为其中的分量赋值 with something called a vector set, 234 00:10:14,657 --> 00:10:15,608 我不太在意 I don't really care. 235 00:10:16,280 --> 00:10:17,550 我们来看一看 But let's look, for example, 236 00:10:18,113 --> 00:10:20,425 在这种实现中 at then that kind of implementation 237 00:10:21,250 --> 00:10:23,182 CAR和CDR是什么样子的 of car and cdr. 238 00:10:26,470 --> 00:10:28,416 比如说 如果我刚好有 So for example if I happen to have 239 00:10:28,880 --> 00:10:30,800 一个寄存器B a register b, 240 00:10:31,150 --> 00:10:34,640 它存了一个序对的下标 which contains the type index of a pair, 241 00:10:35,950 --> 00:10:38,800 即它是指向一个序对的指针 and therefore it is the pointer to a pair, 242 00:10:39,350 --> 00:10:40,850 我可以取它的CAR then I could take the car of that and 243 00:10:41,552 --> 00:10:44,110 存到寄存器A里面 OK if I-- write this down-- I might put that in register a. 244 00:10:44,490 --> 00:10:46,864 事实上它是 What that really is is a representation of 245 00:10:47,375 --> 00:10:50,191 把A赋值为-- the assign to a, 246 00:10:50,190 --> 00:10:51,920 引用向量的一个分量-- the value of vector reffing-- 247 00:10:52,800 --> 00:10:55,248 或者你可以把它叫做索引一个数组 or array indexing, if you will-- or something, 248 00:10:55,420 --> 00:10:57,632 目标向量为THE-CARS the cars object-- 249 00:10:58,400 --> 00:11:00,928 而目标分量是B whatever that is-- with the index, b. 250 00:11:02,650 --> 00:11:03,632 CDR的操作也类似 And similarly for cdr. 251 00:11:04,100 --> 00:11:05,725 我们可以用同样的方式 And we can do the same thing 252 00:11:05,904 --> 00:11:08,320 来对数据结构赋值 for assignment to data structures, 253 00:11:08,925 --> 00:11:10,925 如果我们需要这么做的话 If we need to do that sort of things at all. 254 00:11:11,840 --> 00:11:13,808 构建这个并不太难 It's not too hard to build that. 255 00:11:14,580 --> 00:11:15,728 下一个问题是 Well now the next question is 256 00:11:15,728 --> 00:11:17,000 我们如何分配它们 how are we going to do allocation. 257 00:11:18,010 --> 00:11:20,138 我们经常需要一个新的序对 And every so often I say I want a cons. 258 00:11:21,400 --> 00:11:23,424 当然 CONS并没有长在树上 Now conses don't grow on trees. 259 00:11:23,790 --> 00:11:24,816 或许它们应该那样 Or maybe they should. 260 00:11:25,340 --> 00:11:26,560 我必须得有某种方法 But I have to have some way 261 00:11:26,704 --> 00:11:28,970 来获得一个可用的序对 I have to have some way of getting the next one. 262 00:11:29,980 --> 00:11:31,475 我需要某种方案 I have to have some idea of 263 00:11:31,470 --> 00:11:33,040 当内存不再使用的时候 if their memory is unused 264 00:11:33,690 --> 00:11:35,056 我可以重新分配它们 that I might want to allocate from. 265 00:11:35,630 --> 00:11:37,380 有很多方案可以实现这一点 And there are many schemes for doing this. 266 00:11:37,380 --> 00:11:39,072 现在我给你们展示的这个东西 And the particular thing I'm showing you right now 267 00:11:39,232 --> 00:11:40,450 并是不必要的 is not essential. 268 00:11:42,100 --> 00:11:43,184 然而它很方便 However it's convenient 269 00:11:43,200 --> 00:11:44,448 并且被实现很多次了 and has been done many times. 270 00:11:44,608 --> 00:11:47,200 其中一种基于“空闲表”的分配方案 It's one schemes called the free list allocation scheme. 271 00:11:47,660 --> 00:11:48,684 它的意思就是 What that means is 272 00:11:48,680 --> 00:11:51,120 世界上所有的空闲内存 that all of the free memory that there is in the world 273 00:11:51,550 --> 00:11:53,088 都连在一个链表中 is linked together in a linked list, 274 00:11:54,550 --> 00:11:56,224 就像其它东西一样 just like all the other stuff. 275 00:11:56,960 --> 00:11:59,075 每当你需要一个新的格子 And whenever you need a free cell 276 00:11:59,070 --> 00:12:00,128 来进行CONS的时候 to make a new cons, 277 00:12:00,950 --> 00:12:02,264 你选择第一个格子 you grab the first one 278 00:12:02,264 --> 00:12:03,825 将它的CDR指向空闲表 make the free list be the cdr of it, 279 00:12:04,325 --> 00:12:05,553 然后分配它 and then allocate that. 280 00:12:06,030 --> 00:12:08,325 就像这样 And so what that looks like is something like this. 281 00:12:09,530 --> 00:12:13,328 这里 我们的空闲表 Here we have the free list 282 00:12:13,952 --> 00:12:16,810 就是从6开始 starting in 6. 283 00:12:18,510 --> 00:12:23,472 它是一个指向8的指针 And what that is is a pointer-off to say 8. 284 00:12:24,860 --> 00:12:25,628 它表示 So what it says is, 285 00:12:25,628 --> 00:12:26,553 当前这个是空闲的 this one is free 286 00:12:26,553 --> 00:12:27,953 下一个在位置8 and the next one is an 8. 287 00:12:28,870 --> 00:12:29,881 这个是空闲的 This one is free 288 00:12:30,048 --> 00:12:32,080 下一个在位置3 and the next one is in 3, 289 00:12:32,320 --> 00:12:33,450 下一个是空闲的 the next one that's free. 290 00:12:33,930 --> 00:12:34,950 这个是空闲的 That one's free 291 00:12:35,040 --> 00:12:37,680 下一个在位置0 and the next one is in 0. 292 00:12:37,872 --> 00:12:38,496 这个是空闲的 That one's free 293 00:12:38,528 --> 00:12:39,824 下一个在位置15 and the next one's in 15. 294 00:12:40,940 --> 00:12:41,840 以此类推 Something like that. 295 00:12:42,780 --> 00:12:44,640 我们可以想象有这样的结构 We can imagine having such a structure. 296 00:12:46,400 --> 00:12:48,032 一旦我们有了这样的机制 Given that we have something like that, 297 00:12:49,456 --> 00:12:50,920 那么当你需要空间的时候 then it's possible to 298 00:12:50,920 --> 00:12:52,224 就能获取一个 just get one when you need it. 299 00:12:53,825 --> 00:12:56,466 那些使用了CONS的程序 And so a program for doing cons, 300 00:12:57,450 --> 00:12:59,136 内存可能就是像这样的 this is what cons might turn into. 301 00:12:59,320 --> 00:13:02,573 把B和C进行CONS之后的值 To assign to a register A the result of cons-ing, 302 00:13:02,950 --> 00:13:05,825 赋值给A寄存器 a B onto C, 303 00:13:06,200 --> 00:13:09,040 结果包括B和C the value in this containing B and the value containing C, 304 00:13:09,270 --> 00:13:10,528 我们要做的是 what we have to do is 305 00:13:10,560 --> 00:13:12,240 把当前的尾部格子 即空闲表的前个格子 get the current tail ahead of the freelist, 306 00:13:12,475 --> 00:13:14,300 让它的CDR指向空闲表 make the free list be its cdr. 307 00:13:15,640 --> 00:13:18,336 我们要把THE-CARS中 Then we have to change the cars 308 00:13:18,410 --> 00:13:22,496 由A索引的格子 to be the thing we're making up to be in A 309 00:13:23,136 --> 00:13:25,450 修改为B中的内容 to be the B, the thing in B. 310 00:13:25,900 --> 00:13:28,656 THE-CDRS中由A索引的格子 And we have to make change the cdrs of 311 00:13:29,200 --> 00:13:31,720 修改为C的值 the thing that's in A to be C. 312 00:13:33,200 --> 00:13:34,768 现在A所指的格子里面 And then what we have in A 313 00:13:34,784 --> 00:13:36,650 就是新构建好的对象了 is the right new frob, whatever it is. 314 00:13:36,816 --> 00:13:37,920 这就是我们要的对象 The object that we want. 315 00:13:40,470 --> 00:13:42,500 我之前告诉过你们 Now there's a little bit of 316 00:13:42,500 --> 00:13:43,975 这里撒了个谎 a cheat here that I haven't told you about, 317 00:13:43,970 --> 00:13:45,328 也就是在这里的某处 which is somewhere around here 318 00:13:45,536 --> 00:13:47,320 我本来应该 I haven't set the type of the thing that I've 319 00:13:48,450 --> 00:13:50,480 把我CONS起来的对象 the type of the thing 320 00:13:50,510 --> 00:13:51,872 设置为序对类型 that I'm cons-ing up to be a pair, 321 00:13:52,304 --> 00:13:53,050 但我没有 and I ought to. 322 00:13:53,510 --> 00:13:56,576 因此这里应该需要设置一些比特位 So there should be some sort of bits here are being set, 323 00:13:56,608 --> 00:13:57,760 我只是还没把它写下来 and I just haven't written that down. 324 00:13:59,810 --> 00:14:00,864 当然 这个很好实现 We could have arranged it, of course, 325 00:14:00,896 --> 00:14:02,450 因为空闲表本来就是用序对实现的 for the free list to be made out of pairs. 326 00:14:03,100 --> 00:14:04,882 因此这是没问题的 And so then there's no problem with that. 327 00:14:06,430 --> 00:14:07,744 但这也就是-- But that sort of-- 328 00:14:07,824 --> 00:14:09,920 这些都是无关紧要的细节 again, an inessential detail in a way 329 00:14:10,220 --> 00:14:12,880 取决于那些想要自制 some particular programmer or architect 330 00:14:12,920 --> 00:14:14,272 计算机或Lisp系统的 or whatever might manufacture 331 00:14:14,336 --> 00:14:16,680 程序员或架构师 his machine or Lisp system. 332 00:14:17,540 --> 00:14:18,711 例如 So for example, 333 00:14:19,075 --> 00:14:20,247 看这个 just looking at this, 334 00:14:20,650 --> 00:14:23,456 假设我们要为 to allocate 335 00:14:23,550 --> 00:14:26,834 这个之前见过的数据结构分配空间 given that I had already the structure that you saw before, 336 00:14:27,216 --> 00:14:30,260 假设我要分配一个新格子 supposing I wanted to allocate a new cell, 337 00:14:30,550 --> 00:14:36,617 来表示表(1 1 2) which is going to be representation of list one, one, two, 338 00:14:37,240 --> 00:14:39,872 其中(1 2)又是 where already one two was the car 339 00:14:40,288 --> 00:14:42,160 之前一个表的CAR元素 of the list we were playing with before. 340 00:14:43,430 --> 00:14:44,450 这不怎么难 Well that's not so hard. 341 00:14:44,780 --> 00:14:46,200 我用1号单元来存放数字“1” I stored that one in one, 342 00:14:46,200 --> 00:14:49,175 那么P1表示的就是这个单元 so p1 one is the representation of this. 343 00:14:49,530 --> 00:14:50,839 这个是P5 This is p5. 344 00:14:51,675 --> 00:14:53,512 它是应该是这个的CDR That's going to be the cdr of this. 345 00:14:54,070 --> 00:14:55,525 现在我们要从空闲表中取出一些东西 Now we're going to pull something off the free list, 346 00:14:55,525 --> 00:14:57,303 空闲表现在是从6开始的 but remember the free list started at six. 347 00:14:57,780 --> 00:15:00,183 而在分配之后 空闲表将从8开始 The new free list after this allocation is eight, 348 00:15:00,600 --> 00:15:02,551 一个从8开始的空闲表 a free list beginning at eight. 349 00:15:02,890 --> 00:15:03,520 当然 And of course 350 00:15:03,720 --> 00:15:06,048 现在6里面是数字1 in six now we have a number one, 351 00:15:06,150 --> 00:15:07,104 就是我们想要的 which is what we wanted, 352 00:15:07,392 --> 00:15:11,560 它的CDR是在位置5的序对 with its cdr being the pair starting in location five. 353 00:15:13,330 --> 00:15:14,506 没费多少力气 And that's no big deal. 354 00:15:16,810 --> 00:15:20,450 这里依然存在的一个问题是 So the only problem really remaining here is, 355 00:15:21,000 --> 00:15:23,402 我们没有无限大的内存 well, I don't have an infinitely large memory. 356 00:15:25,080 --> 00:15:26,666 如果我像这么操作了一会儿 If I do this for a little while, 357 00:15:27,250 --> 00:15:28,000 比如说 say, for example, 358 00:15:28,016 --> 00:15:30,144 假设进行一次CONS花费1微秒 supposing it takes me a microsecond to do a cons, 359 00:15:30,600 --> 00:15:32,975 如果要进行一百万次CONS and I have a million cons memory 360 00:15:33,600 --> 00:15:35,279 那么我就要消耗1秒钟的时间 then I'm only going to run out in a second, 361 00:15:35,950 --> 00:15:37,007 这就很糟糕了 and that's pretty bad. 362 00:15:38,000 --> 00:15:40,625 如何预防这样的灾难 So what we do to prevent that disaster, 363 00:15:40,625 --> 00:15:42,191 这种生态灾难 that ecological disaster, 364 00:15:42,600 --> 00:15:44,300 在提问环节之后我们再继续讨论 talk about right after questions. 365 00:15:44,300 --> 00:15:45,263 有人要提问吗? Are there any questions? 366 00:15:51,500 --> 00:15:51,696 请讲 Yes. 367 00:15:52,030 --> 00:15:54,675 学生:在环境图表中 AUDIENCE: In the environment diagrams that we were drawing 368 00:15:54,675 --> 00:15:58,250 我们画了过程体 we would use the body of procedures, 369 00:15:58,250 --> 00:16:00,672 但是在过程应用结束后 and you would eventually wind up with 370 00:16:00,800 --> 00:16:03,600 这些环境中的东西就不再有用了 things that were no longer useful in that structure. 371 00:16:03,600 --> 00:16:04,160 教授:说得很对 PROFESSOR: Yes, madam. 372 00:16:04,930 --> 00:16:06,672 学生:它是如何表示的? AUDIENCE: How is that represented? 373 00:16:06,768 --> 00:16:08,750 教授:这其实是两个问题 PROFESSOR: There's two problems here. OK? 374 00:16:09,180 --> 00:16:10,250 第一个问题是 One you were asking 375 00:16:10,250 --> 00:16:13,438 材料没用了 is that material becomes useless. 376 00:16:13,870 --> 00:16:14,920 我们稍后就会讲 We'll talk about that in a second. 377 00:16:14,920 --> 00:16:17,008 如何预防生态灾难 That has to do with how to prevent ecological disasters. 378 00:16:17,632 --> 00:16:19,200 如果我制造了一堆垃圾 Right? If I make a lot of garbage 379 00:16:19,200 --> 00:16:21,399 我需要自己清理掉 I have to somehow be able to clean up after myself. 380 00:16:21,820 --> 00:16:22,976 我们一会儿就要讲 And we'll talk about that in a second. 381 00:16:23,430 --> 00:16:24,575 第二个问题 The other question you're asking 382 00:16:24,575 --> 00:16:27,210 你问的是如何表示环境 is how you represent the environments, I think. 383 00:16:27,280 --> 00:16:27,600 学生:对 AUDIENCE: Yes. 384 00:16:27,600 --> 00:16:28,190 教授:好 PROFESSOR: OK. 385 00:16:28,190 --> 00:16:30,624 环境结构能够以任意的方式表示 And the environment structures can be represented in arbitrary ways. 386 00:16:30,928 --> 00:16:31,780 有很多种表示方式 There are lots of them. 387 00:16:31,780 --> 00:16:33,344 这里 我只讲了基于表结构的内存 I mean, here I'm just telling you about list cells. 388 00:16:33,630 --> 00:16:34,925 当然 每个真实的系统 Of course every real system 389 00:16:34,925 --> 00:16:36,725 都有任意长度的向量 has vectors of arbitrary length 390 00:16:36,720 --> 00:16:39,152 也有固定长度的向量 as well as the vectors of length, too, 391 00:16:39,312 --> 00:16:40,512 它们都可以作为内存的表示方法 which represent list cells. 392 00:16:41,080 --> 00:16:44,909 在一个专业的Lisp系统中 And the environment structures that one uses in a 393 00:16:44,900 --> 00:16:46,992 环境结构是用 professionally written Lisp system 394 00:16:47,300 --> 00:16:49,699 向量表示的 tend to be vectors 395 00:16:49,699 --> 00:16:51,925 它所包含的元素的数量 which contain a number of elements approximately 396 00:16:51,925 --> 00:16:54,601 比参数的个数稍微多一点 equal to the number of arguments-- a little bit more 397 00:16:55,350 --> 00:16:56,864 因为你需要某种“粘合剂” because you need sort of glue. 398 00:16:57,408 --> 00:17:00,740 记住环境是在框架里的 OK? So remember, the environment is in a frame. 399 00:17:00,740 --> 00:17:03,980 框架是应用过程时被构建出来的 The frames are constructed by applying a procedure. 400 00:17:03,980 --> 00:17:04,784 这种情况下 In doing so, 401 00:17:04,800 --> 00:17:07,600 所分配的空间大小为 an allocation is made of a place 402 00:17:07,648 --> 00:17:11,270 实际参数加上“粘合剂”占用的空间 which is the number of arguments long plus some glue 403 00:17:11,270 --> 00:17:12,713 然后将它连接到某条链上 that gets linked into a chain. 404 00:17:13,325 --> 00:17:15,660 在这个层次上 和ALGOL差不多 It's just like algol at that level. 405 00:17:19,810 --> 00:17:20,725 还有其它问题吗? There any other questions? 406 00:17:23,700 --> 00:17:23,920 好 OK. 407 00:17:23,920 --> 00:17:25,552 谢谢 我们休息一下 Thank you, and let's take a short break. 408 00:17:26,350 --> 00:17:45,488 [音乐] [JESU, JOY OF MAN'S DESIRING] 409 00:17:45,530 --> 00:17:50,016 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 410 00:17:55,740 --> 00:17:59,040 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Sussman Jay Sussman 411 00:17:59,130 --> 00:18:04,224 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 412 00:18:04,320 --> 00:18:09,870 存储分配与垃圾收集 Storage Allocation & Garbage Collection 413 00:18:12,270 --> 00:18:14,240 教授:如同我刚才说过的那样 PROFESSOR: Well, as I just said, 414 00:18:14,550 --> 00:18:15,504 半导体厂商 computer memories 415 00:18:15,824 --> 00:18:17,968 所生产的计算机内存 supplied by the semiconductor manufacturers 416 00:18:18,160 --> 00:18:19,000 容量是有限的 are finite. 417 00:18:19,420 --> 00:18:20,408 这的确很可惜 And that's quite a pity. 418 00:18:21,620 --> 00:18:23,352 但它也可能不总是这样 It might not always be that way. 419 00:18:24,030 --> 00:18:25,408 简单算一下 Just for a quick calculation, 420 00:18:25,440 --> 00:18:28,860 你可以看到 如果内存的价格 you can see that it's possible that if memory's 421 00:18:28,860 --> 00:18:30,800 继续保持当前的趋势的话 prices keep going at the rate they're going 422 00:18:31,220 --> 00:18:33,680 如果你执行CONS的时候也只需要1微秒 that if you still took a microsecond second to do a cons, 423 00:18:34,425 --> 00:18:35,900 那么 首先大家知道 then-- first of all, everybody 424 00:18:35,900 --> 00:18:37,072 一年大约有 should know that there's about pi 425 00:18:37,104 --> 00:18:38,860 PI*10^7秒 times ten to the seventh seconds in a year. 426 00:18:39,450 --> 00:18:41,120 那么就有 And so that would be 427 00:18:41,504 --> 00:18:42,730 10^6乘以10^7 ten to the seventh plus ten to the sixth 428 00:18:42,733 --> 00:18:43,940 也就是10^13 is ten to the thirteenth. 429 00:18:43,940 --> 00:18:45,506 那么在机器的一生中 So there's maybe ten to the fourteenth conses 430 00:18:45,506 --> 00:18:46,800 就能有10^14个CONS in the life of a machine. 431 00:18:47,520 --> 00:18:49,408 如果你的机器上 If there was ten to the fourteenth words of memory 432 00:18:49,680 --> 00:18:50,570 有10^14个字的内存 on your machine, 433 00:18:51,200 --> 00:18:52,160 你就永远不会用完 you'd never run out. 434 00:18:53,040 --> 00:18:53,856 这样就会…… OK so that will be, 435 00:18:53,952 --> 00:18:55,760 这并不是完全没有道理 And that's not completely unreasonable. 436 00:18:56,310 --> 00:18:58,460 10^14次方不是个非常大的数字 Ten to the fourteenth is not a very large number. 437 00:19:01,450 --> 00:19:04,704 我不觉得它是个很大的数字 Even for... I don't think it is. 438 00:19:05,180 --> 00:19:07,392 但我喜欢在天文学领域进行比较 But then again I like to play with astronomy. 439 00:19:07,930 --> 00:19:11,040 距离我们最近的星星 It's at least ten to the eighteenth centimeters 440 00:19:11,104 --> 00:19:12,450 至少有10^18次方厘米远 between us and the nearest star. 441 00:19:12,930 --> 00:19:18,850 我担心的是 But the thing I'm about to worry about is, 442 00:19:19,150 --> 00:19:21,275 至少以现在的经济状况 at least in the current economic state of affairs, 443 00:19:21,275 --> 00:19:23,575 10^14大小的内存很贵 ten to the fourteenth pieces of memory is expensive. 444 00:19:24,200 --> 00:19:26,624 因此我认为我们需要 And so I suppose what we have to do 445 00:19:26,816 --> 00:19:28,512 适应更小的内存 is make do with much smaller memories. 446 00:19:30,020 --> 00:19:30,592 现在 Now 447 00:19:32,848 --> 00:19:35,072 广义地说 我们营造一种无限内存的假象 in general we want to have an illusion of infinity. 448 00:19:35,800 --> 00:19:37,225 我们需要整理它 All we need to do is arrange it 449 00:19:37,825 --> 00:19:39,689 以便在我们需要内存的时候就能获得它 so that whenever you look, the thing is there. 450 00:19:41,920 --> 00:19:45,550 这个想法非常重要 That's, that's really an important idea. 451 00:19:49,540 --> 00:19:51,975 人或者计算机只能存在有限的时间 A person or a computer lives only a finite amount of time 452 00:19:52,325 --> 00:19:54,599 只能看有限的东西 and can only take a finite number of looks at something. 453 00:19:55,280 --> 00:19:57,375 因此你只需要有限的东西 And so you really only need a finite amount of stuff. 454 00:19:58,190 --> 00:19:59,000 只要你合理地安排它们 But you have to arrange it 455 00:19:59,000 --> 00:20:00,383 使得不管实际有多少内存 so no matter how much there is, 456 00:20:00,773 --> 00:20:03,461 你要求这里有多少 how much you really claim there is, 457 00:20:03,461 --> 00:20:04,749 当你去看的时候 there's always enough stuff 458 00:20:04,749 --> 00:20:06,900 总有足够的东西 so that when you take a look, it's there. 459 00:20:06,900 --> 00:20:08,157 因此你只需要有限的数量 And so you only need a finite amount. 460 00:20:08,750 --> 00:20:09,949 我们来看看 But let's see. 461 00:20:11,630 --> 00:20:13,328 我们之前提过一个问题 One problem is, as was brought up, 462 00:20:13,925 --> 00:20:15,450 在很多情况下 that there are possible ways 463 00:20:15,720 --> 00:20:17,840 我们制造了大量 that there is lots of stuff 464 00:20:17,888 --> 00:20:19,168 不需要的东西 that we make that we don't need. 465 00:20:19,410 --> 00:20:21,813 我们可以进行回收再利用 And we could recycle the material out of which its made. 466 00:20:22,625 --> 00:20:23,533 举个例子 An example 467 00:20:24,150 --> 00:20:25,792 事实上 for is, is the fact 468 00:20:25,792 --> 00:20:28,400 当我们调用一个过程的时候 when we're building environment structures, 469 00:20:28,400 --> 00:20:30,470 都会构建环境结构 and we do so every time we call a procedure. 470 00:20:30,470 --> 00:20:32,565 我们把它构建在一个环境框架中 We have built in it a environment frame. 471 00:20:33,140 --> 00:20:34,032 这个环境框架 That environment frame 472 00:20:34,224 --> 00:20:36,070 不用存在很长时间 doesn't necessarily have a very long lifetime. 473 00:20:36,730 --> 00:20:38,699 只有在进行过程调用的时候 Its lifetime, meaning its usefulness, 474 00:20:39,425 --> 00:20:42,603 它的存在才是有用的 may exist only over the invocation of the procedure. 475 00:20:42,850 --> 00:20:45,275 如果过程把另一个过程 Or if the procedure exports another procedure 476 00:20:45,270 --> 00:20:46,672 作为返回值返回 by returning it as a value 477 00:20:46,875 --> 00:20:48,525 并且这个过程是在它的内部定义的 and that procedure is defined inside of it, 478 00:20:48,520 --> 00:20:50,800 那么外层过程的 well then the lifetime of the 479 00:20:51,072 --> 00:20:53,392 存活时间仍然是 frame of the outer procedure still is 480 00:20:53,500 --> 00:20:56,128 被返回的过程的 only the lifetime of the procedure 481 00:20:57,024 --> 00:20:57,900 存活时间 which was exported. 482 00:20:58,530 --> 00:20:59,575 最终 And so ultimately, 483 00:20:59,575 --> 00:21:00,972 就会制造很多垃圾 a lot of that is garbage. 484 00:21:01,960 --> 00:21:04,108 还有其它的途径可以制造垃圾 There are other ways of producing garbage as well. 485 00:21:05,370 --> 00:21:06,675 用户也会制造垃圾 Users produce garbage. 486 00:21:07,240 --> 00:21:08,075 举例来说 An example of 487 00:21:08,075 --> 00:21:10,225 用户制造的垃圾像是这样 user garbage is something like this. 488 00:21:10,930 --> 00:21:14,000 如果我们写个程序 If we write a program to, for example, 489 00:21:14,000 --> 00:21:15,800 把两个表连接到一起 append two lists together, 490 00:21:16,050 --> 00:21:18,144 唯一的办法是 well one way to do it is to 491 00:21:18,325 --> 00:21:21,375 把第一个表逆序塞到空表中 reverse the first list onto the empty list 492 00:21:21,375 --> 00:21:23,725 再把新表逆序塞到第二个表中 and reverse that onto the second list. 493 00:21:24,703 --> 00:21:26,925 这种解法并不是很糟糕 Now that's not terribly bad way of doing it. 494 00:21:28,160 --> 00:21:28,850 然而 And however, 495 00:21:28,850 --> 00:21:30,096 程序所生成的 the intermediate result, 496 00:21:30,112 --> 00:21:32,020 中间结果 which is the reversal of the first list 497 00:21:33,875 --> 00:21:35,576 即第一个表的逆序表 as done by this program, 498 00:21:36,700 --> 00:21:38,525 在它被复制到第二个表之后 is never going to be accessed ever again 499 00:21:38,525 --> 00:21:40,568 就再也不会被用到了 after it's copied back on to the second. 500 00:21:41,010 --> 00:21:42,232 它是个中间结果 It's an intermediate result. 501 00:21:43,580 --> 00:21:45,432 它很难被找到 It's going to be hard to ever see 502 00:21:46,075 --> 00:21:48,056 没有人能访问到它 how anybody would ever be able to access it. 503 00:21:48,600 --> 00:21:49,848 事实上 它会消失掉 In fact, it will go away. 504 00:21:51,050 --> 00:21:52,900 如果我们像这样制造了大量的垃圾 Now if we make a lot of garbage like that, 505 00:21:52,900 --> 00:21:54,200 系统也应该允许我们这么干 and we should be allowed to, 506 00:21:54,800 --> 00:21:57,296 但应该有某些方法去回收这些垃圾 then there's got to be some way to reclaim that garbage. 507 00:21:58,800 --> 00:22:00,900 现在 我要告诉你 Well, what I'd like to tell you about now 508 00:22:01,700 --> 00:22:03,775 一个非常聪明的技巧 is a very clever technique 509 00:22:04,320 --> 00:22:07,584 一个Lisp系统 whereby a Lisp system 510 00:22:07,952 --> 00:22:11,216 通常可以证明一条小定理 can prove a small theorem every so often 511 00:22:11,296 --> 00:22:13,504 也就是 某段内存中的值 on the form the following piece of junk 512 00:22:14,720 --> 00:22:16,096 之后不再会被用到 will never be accessed again. 513 00:22:17,410 --> 00:22:19,809 它对以后的计算没有任何影响 It can have no affect on the future of the computation. 514 00:22:21,400 --> 00:22:23,616 事实上 这基于一个很简单的想法 It's actually based on a very simple idea. 515 00:22:24,725 --> 00:22:28,065 我们已经把计算机设计成这个样子 We've designed our computers to look sort of like this. 516 00:22:28,950 --> 00:22:30,672 有一些数据通路 There's some data path, 517 00:22:31,872 --> 00:22:33,408 其中有寄存器 which contains the registers. 518 00:22:34,920 --> 00:22:38,048 有EXP、ENV You know, there are things like exp, and env, 519 00:22:39,040 --> 00:22:42,192 和VAL之类的寄存器 and val, and so on. 520 00:22:42,610 --> 00:22:44,025 这里有个叫STACK的东西 And there's one here called stack, 521 00:22:46,020 --> 00:22:49,456 某种指向一个结构的东西 some sort which points off to a structure somewhere, 522 00:22:49,504 --> 00:22:50,224 它是个栈 which is the stack. 523 00:22:50,240 --> 00:22:51,488 我们过一会再研究它 And we'll worry about that in a second. 524 00:22:51,648 --> 00:22:53,620 这里有一些 There's some finite controller, 525 00:22:54,380 --> 00:22:56,576 有穷状态控制器 finite state machine controller. 526 00:22:56,730 --> 00:22:59,513 控制信号在这之间流通 And there's some control signals that go this way and 527 00:22:59,800 --> 00:23:01,440 比如谓词的返回结果 predicate results that come this way, 528 00:23:01,872 --> 00:23:03,136 这部分并不太有趣 not the interesting part. 529 00:23:03,350 --> 00:23:06,512 这里有某种结构化的内存 There's some sort of structured memory, 530 00:23:06,806 --> 00:23:08,271 我刚才给你讲过如何构建它 which I just told you how to make, 531 00:23:08,270 --> 00:23:10,176 它可能包括一个栈 which may contain a stack. 532 00:23:10,460 --> 00:23:11,488 我没有告诉你如何把东西 I didn't tell you how to make things 533 00:23:11,488 --> 00:23:12,430 构建成任意形状 of arbitrary shape, 534 00:23:12,560 --> 00:23:13,392 只有序对 only pairs. 535 00:23:13,600 --> 00:23:14,208 但事实上 But in fact 536 00:23:14,350 --> 00:23:15,440 我告诉过你 with what I've told you can 537 00:23:15,472 --> 00:23:16,960 可以用一张大表来模拟栈 with what I've told you can simulate a stack by a big list. 538 00:23:17,775 --> 00:23:18,850 我没准备干这个 I don't plan to do that, 539 00:23:18,850 --> 00:23:20,016 这不是个好办法 it's not a nice way to do it. 540 00:23:20,360 --> 00:23:22,608 但是我们可以有这样一个东西 But we could have something like that. 541 00:23:22,990 --> 00:23:25,280 这里有各种数据结构 We have all sorts of little data structures in here 542 00:23:25,647 --> 00:23:27,750 它们通过有趣的方式互相连接 that are hooked together in funny ways. 543 00:23:30,115 --> 00:23:32,025 它们和其它东西连接到一起 They connect to other things. 544 00:23:32,560 --> 00:23:33,250 以此类推 And so on. 545 00:23:33,250 --> 00:23:34,225 归根结底 And ultimately 546 00:23:34,455 --> 00:23:37,190 这里的东西是指向这里的指针 things up there are pointers to these. 547 00:23:37,190 --> 00:23:38,873 寄存器里的指针 The things that are in the registers 548 00:23:39,400 --> 00:23:41,408 指向的是表结构内存中 are pointers off to the data structures 549 00:23:41,440 --> 00:23:43,088 数据结构 that live in this list structure memory. 550 00:23:44,910 --> 00:23:49,808 现在 我们的问题是 Now the truth of the matter is 551 00:23:51,050 --> 00:23:52,560 机器的整个意识 that the entire consciousness 552 00:23:52,576 --> 00:23:53,920 是在寄存器里的 of this machine is in these registers. 553 00:23:55,760 --> 00:23:58,512 如果这个机器 There is no possible way that the machine, 554 00:23:58,750 --> 00:24:01,072 构建得正确的话 if done correctly, if built correctly, 555 00:24:01,374 --> 00:24:03,418 它无法访问表结构内存中任何的东西 can access anything in this list structure memory 556 00:24:04,570 --> 00:24:07,056 除非这个表结构内存中的数据 unless the thing in that list structure memory is 557 00:24:08,090 --> 00:24:10,880 通过一系列的数据结构 is connected by a sequence of data structures 558 00:24:11,648 --> 00:24:13,060 与寄存器相连接 to the registers. 559 00:24:15,070 --> 00:24:15,984 如果它能够 If it's accessible 560 00:24:16,224 --> 00:24:18,310 被合法的数据结构选择函数访问到 by legitimate data structure selectors 561 00:24:19,080 --> 00:24:21,120 通过寄存器里保存的指针能够访问它 from the pointers that are stored in these registers. 562 00:24:22,280 --> 00:24:24,464 比如说 数组引用 Things like array references, perhaps. 563 00:24:24,940 --> 00:24:27,920 或者针对序对的引用--CAR或者CDR Or cons cell references, cars and cdrs. 564 00:24:29,088 --> 00:24:30,950 但我不能随意访问内存中的位置 But I can't just talk about a random place in this memory, 565 00:24:30,950 --> 00:24:31,950 因为我找不到它 because I can't get to it. 566 00:24:32,740 --> 00:24:34,904 至少在我求值某条表达式的时候 These are being arbitrary names I'm not allowed to count, 567 00:24:37,000 --> 00:24:39,168 我是不允许去访问那个任意名字的 at least as I'm evaluating expressions. 568 00:24:41,620 --> 00:24:42,576 如果是这样的话 If that's the case 569 00:24:43,270 --> 00:24:45,072 就可以证明一个简单的理论 then there's a very simple theorem to be proved. 570 00:24:47,160 --> 00:24:47,696 就是说 Which is, 571 00:24:47,900 --> 00:24:50,520 如果我从这些寄存器指向的地方开始 if I start with all lead pointers that are in all these registers 572 00:24:51,164 --> 00:24:52,550 递归地遍历 and recursively chase out, 573 00:24:52,825 --> 00:24:56,150 标记选择函数所有能访问到内存 marking all the places I can get to by selectors, 574 00:24:56,900 --> 00:24:59,400 最终就能标记所有能访问的东西 then eventually I mark everything they can be gotten to. 575 00:25:00,650 --> 00:25:02,699 任何未标记的都是垃圾 Anything which is not so marked is garbage 576 00:25:02,699 --> 00:25:03,750 它们可以被回收 and can be recycled. 577 00:25:05,560 --> 00:25:06,208 非常简单 Very simple. 578 00:25:07,200 --> 00:25:09,100 不会影响之后的计算 Cannot affect the future of the computation. 579 00:25:11,180 --> 00:25:12,848 我来举一个 So let me show you that in a particular 580 00:25:13,936 --> 00:25:15,750 具体的例子 in a particular example. 581 00:25:17,120 --> 00:25:19,376 在此之前 需要给我的表结构内存 Now that means I'm going to have to append to my 582 00:25:19,696 --> 00:25:22,080 添加一个叫MARK的标志位 description of the list structure a mark. 583 00:25:23,640 --> 00:25:24,896 因此 在这里 And so here, for example, 584 00:25:25,376 --> 00:25:27,280 就有一个表结构内存 is a list structured memory. 585 00:25:29,080 --> 00:25:30,320 这块表内存中 And in this list structured memory 586 00:25:30,336 --> 00:25:31,330 存放了一个表数据结构 is a list structure 587 00:25:31,330 --> 00:25:33,952 我们把这个起始位置 beginning in a place I'm going to call-- 588 00:25:35,870 --> 00:25:36,624 称为“根” this is the root. 589 00:25:38,590 --> 00:25:40,120 不一定只有一个根 Now it doesn't really have to have a root. 590 00:25:40,120 --> 00:25:41,950 与寄存器类似 可以有很多这种东西 It could be a bunch of them, like all the registers. 591 00:25:42,670 --> 00:25:43,984 但我可以巧妙地安排它们 But I could cleverly arrange it 592 00:25:44,138 --> 00:25:46,300 把所有在旧寄存器里的东西 so all the registers, all the things that are in old registers 593 00:25:46,300 --> 00:25:47,776 在何时的时间点 are also at the right moment 594 00:25:48,288 --> 00:25:50,460 放入到这个根结构中 put into this root structure, 595 00:25:50,460 --> 00:25:51,850 然后用一个指针指向它 and then we've got one pointer to it. 596 00:25:51,850 --> 00:25:52,675 这不是重点 I don't really care. 597 00:25:54,570 --> 00:25:55,632 思路就是 So the idea is 598 00:25:55,648 --> 00:25:56,656 我们要不断地进行CONS we're going to cons up stuff 599 00:25:56,672 --> 00:25:58,016 直到空闲表为空 until our free list is empty. 600 00:25:58,720 --> 00:25:59,675 这样就用尽了所有空间 We've run out of things. 601 00:26:00,950 --> 00:26:04,475 现在我们要证明这个理论 Now we're going to do this process of proving the theorem 602 00:26:04,470 --> 00:26:05,904 也就是一部分的内存 that a certain percentage of the memory 603 00:26:05,952 --> 00:26:06,900 已经没有用了 is got crap in it. 604 00:26:07,850 --> 00:26:09,152 然后我们要回收它 And then we're going to recycle that 605 00:26:09,787 --> 00:26:10,875 构建一个新的树 to grow new trees, 606 00:26:12,192 --> 00:26:14,570 这是这些垃圾的标准使用方式 a standard use of such garbage. 607 00:26:17,090 --> 00:26:18,640 那么我们要做什么呢? So in any case, what do we have here? 608 00:26:18,840 --> 00:26:20,784 从P5这个位置开始 Well we have some data structure 609 00:26:20,896 --> 00:26:24,270 存了一些数据结构 which starts out over here in p5. 610 00:26:25,150 --> 00:26:26,750 说错了--是从1开始 Sorry, and it will start at one 611 00:26:27,270 --> 00:26:28,512 事实上 And in fact 612 00:26:28,896 --> 00:26:32,200 它的CAR部分存放在P5这个位置 it has a car in p5, 613 00:26:32,272 --> 00:26:33,584 而CDR部分存在在P2这个位置 and its cdr is in two. 614 00:26:33,980 --> 00:26:35,648 最开始 所有的标记都是0 And all the marks start out at zero. 615 00:26:36,700 --> 00:26:39,000 我们要开始标记了 Well let's start marking, just to play this game. 616 00:26:39,920 --> 00:26:40,525 好 OK. 617 00:26:42,540 --> 00:26:44,272 例如 So for example, 618 00:26:44,475 --> 00:26:46,950 因为我可以从根访问到位置P1 since I can access one from the root 619 00:26:46,950 --> 00:26:47,824 我就标记一下 I will mark that. 620 00:26:48,390 --> 00:26:49,175 我来标一下 Let me mark it. 621 00:26:50,960 --> 00:26:51,450 好了 Bang. 622 00:26:52,224 --> 00:26:52,944 这个被标记了 That's marked. 623 00:26:54,416 --> 00:26:57,510 因为它指向位置P5 OK. Now since I have a five here 624 00:26:57,648 --> 00:26:58,640 所以我来到了5号格子 I can go to five 625 00:26:59,025 --> 00:27:00,725 然后 我要标记这个 and see, well I'll mark that. 626 00:27:01,450 --> 00:27:01,760 标好了 Bang. 627 00:27:01,760 --> 00:27:02,600 这个笔真好用 That's useful stuff. 628 00:27:02,900 --> 00:27:05,104 但是5号位置的CAR部分是一个数字 But five references as a number in its car, 629 00:27:05,270 --> 00:27:06,656 我对标记数字不感兴趣 I'm not interested in marking numbers 630 00:27:06,912 --> 00:27:08,170 但它的CDR部分是P7 but its cdr is seven. 631 00:27:08,700 --> 00:27:09,750 所以我可以标记它 So I can mark that. 632 00:27:10,450 --> 00:27:10,816 又标好了 Bang. 633 00:27:11,808 --> 00:27:13,400 P7的CDR部分是空表 OK? Seven is the empty list, 634 00:27:13,675 --> 00:27:15,100 而它唯一所引用的元素则是 the only thing that references, 635 00:27:15,595 --> 00:27:17,120 它的CAR部分是个数字 and it's got a number in its car. 636 00:27:17,120 --> 00:27:17,850 我对它不感兴趣 Not interesting. 637 00:27:19,490 --> 00:27:20,500 让我们回到这里 Well now let's go back here. 638 00:27:20,500 --> 00:27:21,650 我忘记了一些事情 I forgot about something. 639 00:27:21,650 --> 00:27:22,175 P2 Two. 640 00:27:22,840 --> 00:27:24,850 换句话说 如果我看1号格子 See in other words, if I'm looking at cell one, 641 00:27:25,425 --> 00:27:29,450 1号格子的CDR部分指向P2 cell one contains a two right over here. 642 00:27:30,370 --> 00:27:31,300 一个指向P2的引用 A reference to two. 643 00:27:32,016 --> 00:27:34,970 这意味着我应该标记P2 That means I should go mark two. 644 00:27:35,700 --> 00:27:36,275 好了 Bang. 645 00:27:37,140 --> 00:27:38,896 P2包含了了一个到P4的引用 Two contains a reference to four. 646 00:27:39,136 --> 00:27:40,270 而P2的CAR部分是个数字 It's got a number in its car, 647 00:27:40,279 --> 00:27:41,200 我对它不感兴趣 I'm not interested in that 648 00:27:41,475 --> 00:27:42,600 所以我要标记P4 so I'm going to go mark that. 649 00:27:43,780 --> 00:27:46,100 P4的CAR部分引用了P7 Four refers to seven through its car, 650 00:27:46,750 --> 00:27:48,176 它的CDR是空的 and is empty in its cdr, 651 00:27:48,475 --> 00:27:49,576 但由于我已经标记过P7了 but I've already marked that one 652 00:27:49,576 --> 00:27:50,750 就不再次标记它了 so I don't have to mark it again. 653 00:27:51,400 --> 00:27:53,056 这就是这个地方 This is all the accessible structure 654 00:27:53,072 --> 00:27:53,870 所能访问的所有单元 from that place. 655 00:27:55,000 --> 00:27:56,575 很简单的递归标记算法 Simple recursive mark algorithm. 656 00:27:58,710 --> 00:28:01,792 这个算法有一些不足的地方 Now there are some unhappinesses about that algorithm, 657 00:28:01,900 --> 00:28:04,025 我们稍后会说 and we can worry about that a second. 658 00:28:04,920 --> 00:28:06,160 但基本上你能看到 But basically you'll see 659 00:28:06,192 --> 00:28:07,850 所有没被标记的地方 that all the things that have not been marked 660 00:28:09,625 --> 00:28:11,504 都是无用的 are places that are free, 661 00:28:11,500 --> 00:28:12,416 可以回收 and I could recycle. 662 00:28:14,250 --> 00:28:15,750 所以下一步就是 So the next stage after that is going to be 663 00:28:15,750 --> 00:28:17,050 扫描整个内存 to scan through all of my memory, 664 00:28:17,945 --> 00:28:20,350 寻找未被标记的格子 looking for things that are not marked. 665 00:28:21,180 --> 00:28:22,450 每当遇到一个已标记的格子 Every time I come across a marked thing 666 00:28:22,450 --> 00:28:23,225 就把标记去掉 I unmark it, 667 00:28:23,220 --> 00:28:24,864 每当遇到未标记的格子时 and every time I come across an unmarked thing 668 00:28:25,072 --> 00:28:27,820 我就把它连接到我的空闲表中 I'm going to link it together in my free list. 669 00:28:28,770 --> 00:28:30,300 传统而且非常简单的算法 Classic, very simple algorithm. 670 00:28:32,120 --> 00:28:33,100 我们来看看 So let's see. 671 00:28:33,840 --> 00:28:34,770 它很简单吗? Is that very simple? 672 00:28:34,770 --> 00:28:35,424 是的 Yes it is. 673 00:28:35,570 --> 00:28:37,792 我不会深入代码细节 I'm not going to go through the code in any detail, 674 00:28:38,009 --> 00:28:39,650 只是想给你看看它有多长 but I just want to show you about how long it is. 675 00:28:40,090 --> 00:28:41,100 看这个标记阶段 Let's look at the mark phase. 676 00:28:41,728 --> 00:28:43,984 这是标记阶段的第一部分 Here's the first part of the mark phase. 677 00:28:45,060 --> 00:28:46,000 我们找到根 We pick up the root. 678 00:28:46,320 --> 00:28:47,520 我们要 We're going to do some 679 00:28:47,675 --> 00:28:51,050 对它进行递归过程调用 We're going to use that as a recursive procedure call. 680 00:28:52,380 --> 00:28:54,475 当我们完成标记之后 We're going to sweep from there, 681 00:28:54,775 --> 00:28:56,950 就从这里开始清除 after when we're done with marking. 682 00:28:57,380 --> 00:28:59,792 然后我们将执行一些指令 And then we're going to do a little couple of instructions 683 00:28:59,808 --> 00:29:01,360 来检查这些标记 that do this checking out on the marks 684 00:29:01,392 --> 00:29:03,070 或者更改这些标记 and changing the marks and things like that, 685 00:29:03,075 --> 00:29:04,900 按照我刚才讲的那个算法进行 according to the algorithm I've just shown you. 686 00:29:05,232 --> 00:29:06,470 代码在这里 OK? It comes out here. 687 00:29:06,470 --> 00:29:07,650 你需要标记它们的CAR You have to mark the cars of things 688 00:29:07,875 --> 00:29:10,212 也需要标记它们的CDR and you also have to be able to mark the cdrs of things. 689 00:29:10,660 --> 00:29:12,100 这就是整个标记阶段 That's the entire mark phase. 690 00:29:14,370 --> 00:29:16,164 我给你讲个关于它的小故事 I'll just tell you a little story about this. 691 00:29:16,590 --> 00:29:19,375 古董货DEC PDP-6计算机 The old DEC PDP-6 computer, 692 00:29:20,930 --> 00:29:22,096 它上面的 this was the way that 693 00:29:22,352 --> 00:29:24,850 标记-清除垃圾回收系统就是这么写的 the mark-sweep garbage collection, as it was, was written. 694 00:29:26,912 --> 00:29:28,400 程序很短 The program was so small 695 00:29:29,257 --> 00:29:31,600 以至于它需要的数据 that with the data that it needed, 696 00:29:32,201 --> 00:29:34,875 以及用来操作内存的所需的寄存器 with the registers that it needed to manipulate the memory, 697 00:29:36,160 --> 00:29:38,144 都能够放入到计算机的 it fit into the fast registers of the machine, 698 00:29:38,160 --> 00:29:38,970 16个快速寄存器中 which were 16. 699 00:29:39,280 --> 00:29:39,800 整个程序 The whole program. 700 00:29:40,016 --> 00:29:42,016 你可以在快速寄存器里执行指令 And you could execute instructions in the fast registers. 701 00:29:43,170 --> 00:29:44,832 所以这是个非常小的程序 So it's an extremely small program, 702 00:29:45,850 --> 00:29:46,880 它跑得飞快 and it could run very fast. 703 00:29:48,870 --> 00:29:51,300 然而很不幸 Now unfortunately, of course, 704 00:29:51,610 --> 00:29:54,025 因为这个程序是递归的 this program, because the fact that it's recursive 705 00:29:54,800 --> 00:29:57,552 因为你需要先做某件事儿 in the way that you do something first 706 00:29:57,552 --> 00:29:58,992 然后再去做另外一件事儿 and then you do something after that, 707 00:29:59,210 --> 00:30:00,880 你得先处理CAR 再处理CDR you have to work on the cars and then the cdrs, 708 00:30:01,150 --> 00:30:02,750 这就需要辅助内存 it requires auxiliary memory. 709 00:30:03,410 --> 00:30:05,232 所以Lisp系统 So Lisp systems-- 710 00:30:05,440 --> 00:30:07,420 需要一个栈来进行标记 those requires a stack for marking. 711 00:30:08,260 --> 00:30:11,050 Lisp系统通过这样的方式 Lisp systems that are built this way 712 00:30:11,570 --> 00:30:14,160 限制了你在数据结构上 have a limit to the depth of recursion you can have 713 00:30:14,425 --> 00:30:17,375 进行CAR或者CDR递归的深度 in data structures in either the car or the cdr, 714 00:30:17,817 --> 00:30:19,350 这并不太靠谱 and that doesn't work very nicely. 715 00:30:19,930 --> 00:30:20,608 另外一方面 On the other hand, 716 00:30:20,640 --> 00:30:22,128 当它足够大的时候你不会发现 you never notice it if it's big enough. 717 00:30:23,180 --> 00:30:25,136 例如 这样的情况 And that's certainly been 718 00:30:25,552 --> 00:30:28,176 发生在大多数MacLisp系统上 the case for most Maclisp, for example, 719 00:30:28,690 --> 00:30:29,888 在它上面运行的Macsyma which ran Macsyma 720 00:30:29,960 --> 00:30:31,104 允许你处理 where you could deal with expressions 721 00:30:31,104 --> 00:30:32,720 有成千上万个元素的表达式 of thousands of elements long. 722 00:30:33,560 --> 00:30:36,025 有很多代数式有大量的项 These are algebraic expressions with thousand of terms. 723 00:30:36,825 --> 00:30:38,100 这没什么问题 And there's no problem with that. 724 00:30:39,490 --> 00:30:40,825 垃圾回收器能正常工作 Such, the garbage collector does work. 725 00:30:42,190 --> 00:30:42,925 另一方面 On the other hand, 726 00:30:42,925 --> 00:30:45,375 这个算法有个很精妙的修改版 there's a very clever modification to this algorithm, 727 00:30:45,375 --> 00:30:46,475 但我不会去讲 which I will not describe, 728 00:30:46,800 --> 00:30:48,220 它是由Peter Deutsch by Peter Deutsch and Schorr and Waite-- 729 00:30:48,640 --> 00:30:51,824 来自IBM的Herb Schorr and Schorr and Waite, Herb Schorr from IBM 730 00:30:51,872 --> 00:30:53,520 和我不太认识的Waite所提出 and Waite who I don't know. 731 00:30:54,016 --> 00:30:56,512 这个算法 Whrere... That algorithm 732 00:30:56,670 --> 00:30:57,792 可以不使用 allows you build 733 00:30:57,840 --> 00:30:59,550 额外的辅助内存 you do can do this without auxiliary memory, 734 00:31:00,500 --> 00:31:02,800 只需要在遍历整个数据结构的时候 by remembering as you walk the data structures 735 00:31:02,975 --> 00:31:05,525 记住你是从哪里来的并反转指针 where you came from by reversing the pointers as you go down 736 00:31:05,525 --> 00:31:07,520 回溯的时候 再去反转这个指针 and crawling up the reverse pointers as you go up. 737 00:31:07,792 --> 00:31:08,992 这是个很取巧的算法 It's a rather tricky algorithm. 738 00:31:09,130 --> 00:31:10,240 你第一次写它的时候 The first time you write it-- 739 00:31:10,256 --> 00:31:11,712 事实上 你前三次写它的时候 or in fact, the first three times you write it it 740 00:31:11,712 --> 00:31:12,720 都会遇到严重的BUG it has a terrible bug in it. 741 00:31:14,350 --> 00:31:16,725 也可能奇慢无比 And it's also about, it's quite rather slow, 742 00:31:16,725 --> 00:31:17,675 因为这个算法太复杂了 because it's complicated. 743 00:31:18,110 --> 00:31:20,304 它用了大概六倍的内存引用 It takes about six times as many memory references 744 00:31:20,850 --> 00:31:23,225 来完成我们刚才讨论的任务 to do the sorts of things that we're talking about. 745 00:31:24,580 --> 00:31:27,075 一旦我完成了标记阶段 Well now once I've done this marking phase, 746 00:31:27,500 --> 00:31:30,128 我们就面临着这样的状况 and I get into a position where things look like this, 747 00:31:30,176 --> 00:31:31,264 请看 let's look-- yes. 748 00:31:31,510 --> 00:31:34,032 这里完成了标记工作 Here we have the mark done, 749 00:31:34,080 --> 00:31:35,008 和我刚才描述的一样 just as I did it. 750 00:31:35,590 --> 00:31:37,330 现在我们要进行清除阶段 Now we have to perform the sweep phase. 751 00:31:37,600 --> 00:31:39,320 我刚才已经讲过如何清除了 And I described to you what this sweep is like. 752 00:31:39,820 --> 00:31:42,348 我要从内存的一端开始 I'm going to walk down from one end of memory or the other, 753 00:31:42,340 --> 00:31:43,344 哪一端都可以 I don't care where, 754 00:31:43,628 --> 00:31:46,175 扫描内存中的每个格子 scanning every cell that's in the memory. 755 00:31:47,175 --> 00:31:48,675 在扫描的同时 And as I scan these cells, 756 00:31:49,200 --> 00:31:50,976 如果是空闲内存 I'm going to link them together, 757 00:31:50,992 --> 00:31:52,840 就把它们连接到空闲表中 if they are free, into the free list. 758 00:31:53,150 --> 00:31:54,050 如果它们不是空闲内存 And if they're not free, 759 00:31:54,050 --> 00:31:56,075 我就把它们的标记清除掉 I'm going to unmark them so the marks become zero. 760 00:31:57,500 --> 00:31:58,576 事实上 And in fact what I get-- 761 00:31:58,700 --> 00:32:00,460 最终的程序并不很复杂 well the program is not very complicated. 762 00:32:00,460 --> 00:32:02,225 它只是变长了一些 It looks sort of like this-- it's a little longer. 763 00:32:02,780 --> 00:32:04,175 这是第一部分 Here's the first piece of it. 764 00:32:04,820 --> 00:32:06,710 它从内存的顶端向下遍历 This one's coming down from the top of memory. 765 00:32:06,710 --> 00:32:09,580 我不期望你现在就搞懂它 I don't want you to try to understand this at this point. 766 00:32:09,580 --> 00:32:10,550 它挺简单的 It's rather simple. 767 00:32:11,030 --> 00:32:12,525 这是个非常简单的算法 It's a very simple algorithm, 768 00:32:13,075 --> 00:32:15,970 其中的一段代码像是这样 but there's pieces of it that just sort of look like this. 769 00:32:15,970 --> 00:32:17,375 非常显而易见 They're all sort of obvious. 770 00:32:18,600 --> 00:32:20,080 在清理结束后 And after we've done the sweep, 771 00:32:20,300 --> 00:32:21,776 我们就得到了像这样的结果 we get an answer that looks like that. 772 00:32:25,330 --> 00:32:26,544 这种标记-清除算法 Now there are some disadvantages 773 00:32:26,560 --> 00:32:28,208 有一些缺点 with mark-sweep algorithms of this sort. 774 00:32:29,590 --> 00:32:30,350 最严重的一个是 Serious ones. 775 00:32:31,450 --> 00:32:33,203 最严重的缺点是 One important disadvantage is 776 00:32:33,203 --> 00:32:34,975 当你的内存越来越大 that your memories get larger and larger. 777 00:32:36,826 --> 00:32:38,875 地址空间也就会越来越大 As you say, address spaces get larger and larger, 778 00:32:38,875 --> 00:32:40,800 你想用它存更多东西 you're willing to represent more and more stuff, 779 00:32:41,370 --> 00:32:44,528 那么扫描整个内存就会非常耗时 then it gets very costly to scan all of memory. 780 00:32:46,360 --> 00:32:47,392 你真正想做的是 What you'd really like to do 781 00:32:47,408 --> 00:32:48,688 只扫描有用的东西 is only scan useful stuff. 782 00:32:50,490 --> 00:32:51,550 这样就会好一点 It would even be better 783 00:32:52,070 --> 00:32:53,904 如果你意识到 if you realized that some stuff 784 00:32:54,480 --> 00:32:57,720 哪些东西已知是有用的 was known to be good and useful, 785 00:32:58,283 --> 00:33:00,370 你就没必要去多次检查它 and you don't have to look at it more than once or twice. 786 00:33:00,370 --> 00:33:01,200 或者不用经常去检查它 Or very rarely. 787 00:33:01,550 --> 00:33:04,325 对于那些你不太确定的 Whereas other stuff that you're not so sure about, 788 00:33:05,000 --> 00:33:06,224 你可以在每次需要的时候 you can look at more detail 789 00:33:07,100 --> 00:33:08,750 进行仔细检查 every time you want to do this, 790 00:33:09,931 --> 00:33:10,850 也就是垃圾收集的时候 want to garbage collect. 791 00:33:11,910 --> 00:33:13,744 这些算法 Well there are algorithms 792 00:33:13,760 --> 00:33:15,100 就是用了这样的方法 that are organized in this way. 793 00:33:15,660 --> 00:33:18,160 我要介绍一个著名的古老算法 Let me tell you about a famous old algorithm 794 00:33:18,280 --> 00:33:19,472 这种算法允许你 which allows you only look at 795 00:33:19,504 --> 00:33:21,370 只检查内存中已知是有用的部分 the part of memory which is known to be useful. 796 00:33:23,120 --> 00:33:23,856 这让它成为了 And which happens to be 797 00:33:23,872 --> 00:33:25,290 目前已知最快的垃圾收集算法 the fastest known garbage collector algorithm. 798 00:33:26,310 --> 00:33:29,450 它就是 Minsky-Fenichel-Yochelson 垃圾收集算法 This is the Minsky-Fenichel-Yochelson garbage collector algorithm. 799 00:33:30,400 --> 00:33:33,184 它是由Minsky It was invented by Minsky 800 00:33:33,200 --> 00:33:36,064 在1960、61年左右发明的 in 1961 or '60 or something, 801 00:33:36,520 --> 00:33:40,480 当时是给RLE PDP-1 Lisp用的 for the RLE PDP-1 Lisp, 802 00:33:40,512 --> 00:33:43,440 这个机器只有4096个字的线性内存 which had 4,096 words of list memory, 803 00:33:45,792 --> 00:33:46,768 还有个磁鼓 and a drum. 804 00:33:48,480 --> 00:33:49,392 为了能够 And the whole idea 805 00:33:50,032 --> 00:33:51,870 在这种恶劣的条件下进行垃圾收集 was to garbage collect this terrible memory. 806 00:33:53,050 --> 00:33:54,352 Minsky意识到 What Minsky realized 807 00:33:54,384 --> 00:33:55,620 达成目的最容易的方法是 was the easiest way to do this 808 00:33:56,200 --> 00:33:58,475 在扫描内存的同时 is to scan the memory in the same sense, 809 00:33:58,475 --> 00:34:00,600 遍历那些好的数据结构 walking the good structure, 810 00:34:01,575 --> 00:34:03,525 把它复制到磁鼓中 copying it out into the drum, 811 00:34:04,700 --> 00:34:05,475 压缩一下 compacted. 812 00:34:06,350 --> 00:34:08,864 之后把它们复制出来 And then when we were done copying it all out, 813 00:34:09,127 --> 00:34:10,900 并把它们交换回内存里 then you swap that back into your memory. 814 00:34:12,300 --> 00:34:13,680 不管是使用的是磁鼓 Now whether or you not use a drum, 815 00:34:13,728 --> 00:34:14,710 或者其它的内存 or another piece of memory, 816 00:34:14,710 --> 00:34:16,425 这都不重要 or something like that isn't important. 817 00:34:17,030 --> 00:34:17,424 事实上 In fact, 818 00:34:17,440 --> 00:34:19,600 我觉得现在应该没人用磁鼓了吧 I don't think people use drums anymore for anything. 819 00:34:20,350 --> 00:34:23,776 但这个算法基本上 But this algorithm basically 820 00:34:24,032 --> 00:34:25,420 要依赖于 depends upon having 821 00:34:25,420 --> 00:34:27,424 大约两倍于 about twice as much address space 822 00:34:27,488 --> 00:34:28,570 你实际使用的内存 you're actually using. 823 00:34:30,270 --> 00:34:32,960 最开始的情况是 And so what you have is some, initially, 824 00:34:33,125 --> 00:34:36,600 有用的数据和垃圾混在了一起 some mixture of useful data and garbage. 825 00:34:37,110 --> 00:34:38,975 它被称为FROMSPACE So this is called fromspace. 826 00:34:45,179 --> 00:34:47,050 这是CRUD的混合 And this is a mixture of crud. 827 00:34:47,872 --> 00:34:49,792 有些是有用的 有些没有用 Some of it's important and some of it isn't. 828 00:34:52,000 --> 00:34:53,856 现在还有另外一块空间 Now there's another place 829 00:34:54,176 --> 00:34:55,616 它需要足够大 which is hopefully big enough, 830 00:34:55,770 --> 00:34:57,008 这个地方叫TOSPACE if we recall, tospace, 831 00:34:57,123 --> 00:34:58,240 要把东西复制进去 which is where we're copying to. 832 00:35:01,590 --> 00:35:02,600 接下来会发生的是 And what happens is-- 833 00:35:02,600 --> 00:35:04,064 我不会深入细节 and I'm not going to go through this detail. 834 00:35:04,160 --> 00:35:07,070 书上写得很清楚了 It's in our book quite explicitly. 835 00:35:07,590 --> 00:35:10,400 这里有一个根节点 There's a root point where you start from. 836 00:35:11,030 --> 00:35:14,300 你从根节点开始 And the idea is that you start with the root. 837 00:35:14,600 --> 00:35:16,425 复制你看到的第一个东西 You copy the first thing you see, 838 00:35:17,830 --> 00:35:19,376 根指针指向的第一个东西 the first thing that the root points at, 839 00:35:19,750 --> 00:35:21,312 复制到TOSPACE的头部 to the beginning of tospace. 840 00:35:22,810 --> 00:35:24,128 这些东西一般是一个序对 The first thing is a pair 841 00:35:24,160 --> 00:35:25,600 或者是类似的数据结构 or something like, a data structure. 842 00:35:27,560 --> 00:35:30,192 然后在那里留下 You then also leave behind 843 00:35:30,384 --> 00:35:31,568 一颗“破碎的心” a broken heart saying, 844 00:35:31,775 --> 00:35:35,743 表示我把东西从这里移动到了这里 I moved this object from here to here, 845 00:35:35,743 --> 00:35:37,050 指示了移动的目的地 giving the place where it moved to. 846 00:35:37,800 --> 00:35:39,650 叫作破碎的心是因为 This is called a broken heart because 847 00:35:39,650 --> 00:35:40,784 我的一个朋友 a friend of mine who implemented 848 00:35:40,784 --> 00:35:43,392 在1966年实现了这个算法 one of these in 1966 849 00:35:43,825 --> 00:35:45,262 而他是个文艺青年 was a very romantic character 850 00:35:45,262 --> 00:35:46,760 就取名叫“破碎的心” and called it a broken heart. 851 00:35:49,580 --> 00:35:50,544 不论如何 But in any case, 852 00:35:51,150 --> 00:35:52,720 接下来要做的是 the next thing you do 853 00:35:52,940 --> 00:35:55,008 FREE指针现在指向这里 is now you have a new free pointer which is here, 854 00:35:55,170 --> 00:35:56,384 然后开始扫描 and you start scanning. 855 00:35:56,880 --> 00:35:59,680 扫描这个刚复制过来的数据结构 You scan this data structure you just copied. 856 00:36:00,551 --> 00:36:02,195 每当你遇到其中的指针 And every time you encounter a pointer in it, 857 00:36:02,190 --> 00:36:03,920 你把它当作是这里的根指针 you treat it as if it was the root pointer here. 858 00:36:04,000 --> 00:36:04,592 哦 不好意思 Oh, I'm sorry. 859 00:36:04,600 --> 00:36:05,696 我们还需要做的是 The other thing you do 860 00:36:05,712 --> 00:36:07,088 你将根指针移动到这里 is you now move the root pointer to there. 861 00:36:09,220 --> 00:36:10,175 因此在扫描的过程中 So now you scan this, 862 00:36:10,170 --> 00:36:10,992 把遇到的每个指针 and everything you see 863 00:36:11,008 --> 00:36:12,416 都可以当作是ROOT指针 you treat as it were the root pointer. 864 00:36:14,110 --> 00:36:15,450 如果你遇到了某个指针 So if you see something, 865 00:36:15,450 --> 00:36:17,400 指向了这里的某个地方 well it points up into there somewhere. 866 00:36:18,510 --> 00:36:19,920 它指向的东西 Is it pointing at a thing 867 00:36:19,936 --> 00:36:20,992 你复制过了吗? which you've not copied yet? 868 00:36:21,780 --> 00:36:22,875 这里是“破碎的心”吗 Is there a broken heart there? 869 00:36:23,880 --> 00:36:24,844 如果那里是破碎的心 If there's a broken heart there 870 00:36:24,840 --> 00:36:26,112 就说明那里的东西复制过了 and it's something you have copied, 871 00:36:26,200 --> 00:36:27,344 只需要用破碎的心所指向的地址 you've just replaced this pointer 872 00:36:27,360 --> 00:36:28,750 来替换它指针即可 with the thing a broken heart points at. 873 00:36:29,820 --> 00:36:32,032 如果它还没被复制 If this thing has not been copied, 874 00:36:32,120 --> 00:36:34,080 你把它复制到这里 you copy it to the next place over here. 875 00:36:34,430 --> 00:36:35,950 把FREE指针移到这里 Move your free pointer over here, 876 00:36:37,050 --> 00:36:40,608 然后在那里放置一颗破碎的心 and then leave a broken heart behind 877 00:36:41,050 --> 00:36:41,800 继续扫描 and scan. 878 00:36:43,670 --> 00:36:46,400 最终SCAN指针追上了FREE指针 And eventually when the scant pointer hits the free pointer, 879 00:36:46,825 --> 00:36:48,525 内存里的所有东西都被复制了 everything in memory has been copied. 880 00:36:50,140 --> 00:36:51,040 这样这里就剩下了 And then there's a whole bunch 881 00:36:51,056 --> 00:36:51,950 大量的空闲空间 of empty space up here, 882 00:36:51,960 --> 00:36:53,280 如果你需要的话 which you could either make into a free list, 883 00:36:53,312 --> 00:36:54,470 你可以把它组织为空闲表 if that's what you want to do. 884 00:36:54,470 --> 00:36:56,270 但这种系统通常不这么来做 But generally you don't in this kind of system. 885 00:36:56,270 --> 00:36:59,150 这类系统中 内存是顺序分配的 In this system you sequentially allocate your memory. 886 00:37:00,910 --> 00:37:02,480 这是个非常 非常好的算法 That is a very, very nice algorithm, 887 00:37:02,970 --> 00:37:04,576 你们现在使用的Scheme系统中 and sort of the one we use in the 888 00:37:04,672 --> 00:37:05,970 就使用了这种算法 the scheme that you've been using. 889 00:37:06,790 --> 00:37:09,475 它应该是-- And it's known to be... it's expected-- 890 00:37:09,470 --> 00:37:10,864 我相信还没有人发现 I believe no one has found 891 00:37:10,896 --> 00:37:12,120 比它跑得更快的算法 a faster algorithm than that. 892 00:37:12,400 --> 00:37:14,850 有一些对这个算法的简单修改 There are very simple modifications to this algorithm 893 00:37:14,850 --> 00:37:16,775 由Henry Baker发明 invented by Henry Baker 894 00:37:17,175 --> 00:37:20,311 它让你能实时运行这个算法 which allow one to run this algorithm in real time, 895 00:37:20,310 --> 00:37:21,920 也就是说进行回收时不需要暂停程序 meaning you don't have to stop to garbage collect. 896 00:37:22,144 --> 00:37:24,336 你能够让机器运行时 But you could interleave the consing 897 00:37:24,368 --> 00:37:26,176 进行的各种CONS操作 that the machine does when its running 898 00:37:26,327 --> 00:37:28,400 与垃圾回收过程交错进行 with steps of the garbage collection process, 899 00:37:28,850 --> 00:37:31,200 垃圾回收器是分散的 so that the thing, the garbage collector's distributed 900 00:37:31,200 --> 00:37:32,192 机器不需要停下来 and the machine doesn't have to stop, 901 00:37:32,416 --> 00:37:33,475 再让垃圾回收开始运作 and garbage collecting can start. 902 00:37:34,640 --> 00:37:37,872 当然 在使用虚拟内存的机器中 Of course in the case of machines with virtual memory 903 00:37:38,900 --> 00:37:41,200 有很多内存无法访问 where a lot of it is in inaccessible places, 904 00:37:41,509 --> 00:37:43,600 这会让整个过程变得耗时 this becomes a very expensive process. 905 00:37:44,280 --> 00:37:46,432 有很多人尝试 And there have been numerous 906 00:37:47,168 --> 00:37:48,650 将它改进得更好 attempts to make this much better. 907 00:37:49,190 --> 00:37:51,152 对于感兴趣的同学 There is a nice paper, 908 00:37:51,168 --> 00:37:52,416 这有一篇论文 for those of you who are interested, 909 00:37:52,640 --> 00:37:54,272 作者是Moon等人 by Moon and other people 910 00:37:54,650 --> 00:37:56,896 这篇论文描述了 which describes a modification to 911 00:37:56,928 --> 00:37:59,440 增量式Minsky-Fenichel-Yochelson算法 the incremental Minsky-Fenichel-Yochelson algorithm, 912 00:37:59,510 --> 00:38:01,200 和Baker算法的修改 and modification the Baker algorithm 913 00:38:01,420 --> 00:38:06,544 让使用虚拟内存的系统更加高效 which is more efficient for virtual memory systems. 914 00:38:08,272 --> 00:38:12,320 现在最后一个谜团也解开了 Well I think now the mystery to this is sort of gone. 915 00:38:12,840 --> 00:38:14,090 有什么疑惑吗? And I'd like to see if there are any questions. 916 00:38:19,780 --> 00:38:19,952 请讲 Yes. 917 00:38:20,600 --> 00:38:23,584 学生:我在楼上的系统上 AUDIENCE: I saw one of you run the garbage collector 918 00:38:23,648 --> 00:38:25,050 你们运行垃圾收集器的时候 on the systems upstairs, 919 00:38:25,930 --> 00:38:27,880 它看起来跑得飞快 and it seemed to me to run extremely fast. 920 00:38:27,968 --> 00:38:28,400 教授:是的 PROFESSOR: Yes 921 00:38:28,490 --> 00:38:29,520 学生:整个过程花费了-- AUDIENCE: Did the whole thing take-- 922 00:38:30,112 --> 00:38:31,880 它真的扫描了整个内存吗? does it sweep through all of memory? 923 00:38:31,880 --> 00:38:32,224 教授:没有 PROFESSOR: No. 924 00:38:32,250 --> 00:38:34,112 它只扫描了那些需要的 It swept through exactly what was needed 925 00:38:34,336 --> 00:38:35,632 去复制那些有用的数据结构 to copy the useful structure. 926 00:38:37,320 --> 00:38:38,360 它是个复制收集器 It's a copying collector. 927 00:38:38,448 --> 00:38:38,912 学生:好吧 AUDIENCE: OK. 928 00:38:39,300 --> 00:38:40,880 教授:但它确实很快 PROFESSOR: And it's rather... it is very fast. 929 00:38:41,850 --> 00:38:45,888 整体来说 我想如果要复制 On the whole, I suppose to copy in a Bobcat 930 00:38:47,120 --> 00:38:51,568 一个大约3MB的东西 to copy, I think, a three megabyte thing or something 931 00:38:52,430 --> 00:38:53,240 将在一秒内完成 is less than a second, 932 00:38:55,008 --> 00:38:55,696 而且是实时的 real time 933 00:38:56,544 --> 00:38:58,464 它们是非常小的程序 Really, these are very small programs. 934 00:38:58,620 --> 00:39:01,504 你需要注意到的一件事是 One thing you should realise is that 935 00:39:02,913 --> 00:39:04,400 垃圾收集器必须要小 garbage collectors have to be small. 936 00:39:05,400 --> 00:39:07,100 不是因为它们需要运行得快 Not because they have to be fast, 937 00:39:07,900 --> 00:39:09,232 因为没有人能够调试 but because no one can debug 938 00:39:09,264 --> 00:39:10,480 复杂的垃圾收集器 a complicated garbage collector. 939 00:39:11,340 --> 00:39:12,912 如果一个垃圾收集器不能正常工作 A garbage collector, if it doesn't work, 940 00:39:14,049 --> 00:39:15,933 它会把你的内存搞得一团糟 will trash your memory in such a way 941 00:39:15,930 --> 00:39:17,392 而你却束手无策 that you cannot figure out what the hell happened. 942 00:39:18,350 --> 00:39:19,675 你需要跟踪审计 You need an audit trail. 943 00:39:20,660 --> 00:39:22,016 因为它把所有东西都换了位置 Because it rearranges everything, 944 00:39:22,048 --> 00:39:23,248 你需要知道那里发生了什么 and how do you know what happened there? 945 00:39:23,740 --> 00:39:26,587 所以这是唯一一种 So this is the only kind of program that 946 00:39:26,920 --> 00:39:28,400 真正非常重要的程序 it really, seriously matters 947 00:39:28,540 --> 00:39:29,792 如果你盯着它看足够久 if you stare at it long enough 948 00:39:29,824 --> 00:39:31,070 那么你就相信它有效 so you believe that it works. 949 00:39:31,344 --> 00:39:33,360 这意味着某种“自我证明” That means and sort of prove it to yourself. 950 00:39:33,920 --> 00:39:36,112 因此我们无法对它进行查错 And that, that... So there's no way to debug it. 951 00:39:36,940 --> 00:39:38,960 这意味着它需要足够小 And that takes it being small enough 952 00:39:38,960 --> 00:39:39,975 你的大脑能够思考它的工作情况 so you can hold it in your head. 953 00:39:41,456 --> 00:39:43,904 正因如此 垃圾收集器十分特殊 So garbage collectors are special in this way. 954 00:39:45,020 --> 00:39:47,120 所以实用的垃圾收集器一定要短小 So every reasonable garbage collector has gotten small, 955 00:39:47,136 --> 00:39:48,450 而通常短小的程序运行得就快 and generally small programs are fast. 956 00:39:52,050 --> 00:39:52,430 请讲 Yes. 957 00:39:52,430 --> 00:39:54,510 学生:您能再重复一遍这个技术的名字吗? AUDIENCE: Can you repeat the name of this technique once again? 958 00:39:54,688 --> 00:39:56,920 教授:Minsky-Fenichel-Yochelson垃圾回收器 PROFESSOR: That's the Minsky-Fenichel-Yochelson garbage collector. 959 00:39:57,888 --> 00:39:58,432 学生:什么? AUDIENCE: You got that? 960 00:39:59,000 --> 00:40:00,784 教授:Minsky在1961年 PROFESSOR: Minsky invented it in '61 961 00:40:00,816 --> 00:40:02,210 为RLE PDP-1设计了这个算法 for the RLE PDP-1. 962 00:40:02,210 --> 00:40:06,176 Fenichel和Yochelson改进并精化了算法 A version of it was developed and elaborated 963 00:40:06,450 --> 00:40:10,275 将它用在了Multics平台的MacLisp中 to be used in Multics Maclisp by Fenichel and Yochelson 964 00:40:11,378 --> 00:40:14,750 那时大约是1968或者1969年 in somewhere around 1968 or '69. 965 00:40:19,570 --> 00:40:21,360 好吧 我们休息一下 OK. Let's take a break. 966 00:40:22,640 --> 00:40:32,368 [音乐] [JESU, JOY OF MAN'S DESIRING] 967 00:40:32,416 --> 00:40:36,192 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 968 00:41:03,150 --> 00:41:07,184 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Sussman Jay Sussman 969 00:41:07,200 --> 00:41:10,176 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 970 00:41:10,208 --> 00:41:14,224 计算的极限 Not Everything Can Be Computed 971 00:41:17,310 --> 00:41:19,675 教授:我们已经到课程的最后一部分了 PROFESSOR: Well we've come to the end of this subject, 972 00:41:20,080 --> 00:41:23,850 我已经给你们展示了一台通用机器 and we've already shown you a universal machine 973 00:41:24,475 --> 00:41:26,740 它被简化为求值器 which is down to evaluator. 974 00:41:27,025 --> 00:41:28,388 它被简化到 It's down to the level of detail 975 00:41:28,388 --> 00:41:29,675 你自己也能构造出来 you could imagine you could make one. 976 00:41:30,192 --> 00:41:33,320 这是一个特定的Lisp实现 This is a particular implementation of Lisp, 977 00:41:33,900 --> 00:41:36,016 它是用 built on one of those 978 00:41:36,160 --> 00:41:38,050 昨天讲过的Scheme芯片制作的 scheme chips that was talked about yesterday, 979 00:41:38,208 --> 00:41:38,912 就是这个 sitting over here. 980 00:41:39,350 --> 00:41:42,000 这基本上就是暴露给他人内存的接口了 This is mostly interface to somebody's memory 981 00:41:42,600 --> 00:41:44,750 里面有节拍发生器等组件 with a little bit of timing and other such stuff. 982 00:41:45,225 --> 00:41:47,250 尽管是解释执行 But this fellow actually ran Lisp 983 00:41:47,775 --> 00:41:50,175 但它们运行Lisp的速度还算不错 at a fairly reasonable rate, as interpretive. 984 00:41:50,610 --> 00:41:53,825 它跑得像1979年的 It ran Lisp as fast as a DEC PDP-10 985 00:41:54,225 --> 00:41:55,650 DEC PDP-10一样快 back in 1979. 986 00:41:56,500 --> 00:41:59,675 作为一个十足的硬件 And so it's gotten pretty hardware. 987 00:42:00,020 --> 00:42:00,896 算是十分“实在”了 Pretty concrete. 988 00:42:02,470 --> 00:42:04,704 我们为你们讲解了一些 We've also downed you a bit 989 00:42:04,720 --> 00:42:06,070 可以被计算的东西 with the things you can compute. 990 00:42:07,370 --> 00:42:08,768 但我们是否可能遇到 But is it the case that 991 00:42:09,328 --> 00:42:10,550 我们无法计算的情况? there are things we can't compute? 992 00:42:11,850 --> 00:42:13,500 课程的最后 And so I'd like to end this with 993 00:42:13,750 --> 00:42:15,872 我想展示一些你认为可以被计算 showing you some things that you'd like be able to compute 994 00:42:16,608 --> 00:42:17,220 但实际上不能的东西 that you can't. 995 00:42:18,190 --> 00:42:19,456 实际上 The answer is yes, 996 00:42:19,456 --> 00:42:20,820 确实有我们无法计算的东西 there are things you can't compute. 997 00:42:22,720 --> 00:42:23,471 例如 For example, 998 00:42:24,450 --> 00:42:25,825 我们想要这样的一种东西 something you'd really like is-- 999 00:42:27,800 --> 00:42:29,360 当我们在编写编译器时 if you're writing a compiler 1000 00:42:29,775 --> 00:42:31,425 你想用一个程序检查 you'd like a program that would check 1001 00:42:32,000 --> 00:42:33,975 你的代码能否正常运行 that the thing you're going to do will work. 1002 00:42:34,630 --> 00:42:35,400 这不是很棒吗? Wouldn't that be nice? 1003 00:42:36,080 --> 00:42:37,875 你希望能够捕获死循环 You'd like something that would catch infinite loops, 1004 00:42:37,870 --> 00:42:38,544 例如 for example, 1005 00:42:39,450 --> 00:42:42,425 用户编写的程序里的死循环 in programs that were written by users. 1006 00:42:43,190 --> 00:42:45,125 但通常来说 你写不出这样的程序 But in general you can't write such a program 1007 00:42:45,350 --> 00:42:46,496 它读取某个程序 that will read any program 1008 00:42:46,512 --> 00:42:47,456 并检测它 and determine whether or not 1009 00:42:48,350 --> 00:42:49,300 是不是死循环 it's an infinite loop. 1010 00:42:50,990 --> 00:42:51,712 我来展示一下 Let me show you that. 1011 00:42:51,760 --> 00:42:53,808 这个需要涉及到数学知识 It's a little bit of a minor mathematics. 1012 00:42:58,780 --> 00:42:59,650 设想 Let's imagine 1013 00:43:00,050 --> 00:43:01,781 在我们开始之前 that we just had a mathematical function 1014 00:43:01,781 --> 00:43:02,620 有一个数学函数 before we start. 1015 00:43:02,620 --> 00:43:03,425 这里就有一个 And there is one, 1016 00:43:03,840 --> 00:43:04,672 记作S called s, 1017 00:43:05,475 --> 00:43:07,546 它接受一个过程 which takes a procedure 1018 00:43:12,640 --> 00:43:14,230 和它的参数A and its argument, a. 1019 00:43:19,175 --> 00:43:20,525 S所做的是 And what s does 1020 00:43:21,650 --> 00:43:24,014 检测以A为参数运行P时 is it determines whether or not 1021 00:43:24,014 --> 00:43:25,975 是否安全 it's safe to run p on a. 1022 00:43:26,900 --> 00:43:28,175 换句话说就是 And what I mean by that is this: 1023 00:43:28,768 --> 00:43:35,120 如果(P A) it's true if p applied to a 1024 00:43:35,625 --> 00:43:36,740 在没有出错的情况下 will converge 1025 00:43:41,400 --> 00:43:42,450 能够返回一个值 to a value 1026 00:43:44,350 --> 00:43:45,330 那么S就为TRUE without an error. 1027 00:43:52,700 --> 00:43:53,680 但如果(P A) And it's false 1028 00:43:56,100 --> 00:43:57,040 是死循环 if p of a 1029 00:43:59,675 --> 00:44:00,765 或者抛出错误 loops forever 1030 00:44:05,875 --> 00:44:06,950 那么S就为FALSE or makes an error. 1031 00:44:15,232 --> 00:44:17,220 这确实是个函数 Now that's surely a function. 1032 00:44:18,780 --> 00:44:20,725 对于你输入的任何过程 There is some for every procedure 1033 00:44:21,200 --> 00:44:22,850 或者任何参数 and for every argument you could give it 1034 00:44:23,920 --> 00:44:25,456 它只能返回TRUE或FALSE that is either true or false 1035 00:44:25,925 --> 00:44:27,850 它会返回一个值而且不会报错 that it converges without making an error. 1036 00:44:28,440 --> 00:44:30,150 你可以为它们画一张巨大的表格 And you could make a giant table of them. 1037 00:44:32,225 --> 00:44:32,925 但问题是 But the question is, 1038 00:44:32,925 --> 00:44:34,093 你能写一个过程 can you write a procedure 1039 00:44:34,093 --> 00:44:35,925 来计算这个函数的值吗? that compute the values of this function? 1040 00:44:37,430 --> 00:44:38,928 假设我们能做到 Well let's assume that we can. 1041 00:44:39,720 --> 00:44:40,550 假设 Suppose 1042 00:44:44,336 --> 00:44:45,584 我们有个过程 that we have a procedure 1043 00:44:48,550 --> 00:44:52,736 一个叫作SAFE?的过程 procedure called "safe" 1044 00:44:56,544 --> 00:44:59,900 它能计算S的值 that computes the value of s. 1045 00:45:12,656 --> 00:45:14,896 现在我要用几种方法 Now I'm going to show you by several methods 1046 00:45:15,900 --> 00:45:18,512 证明你做不到 that you can't do this. 1047 00:45:19,760 --> 00:45:20,626 最简单的一个 The easiest one, 1048 00:45:20,620 --> 00:45:21,280 或者说第一个 or the first one, 1049 00:45:21,312 --> 00:45:23,450 我们定义一个叫DIAG1的过程 let's define a procedure called diag1. 1050 00:45:23,760 --> 00:45:24,864 给定了SAFE?过程 Given that we have safe, 1051 00:45:25,200 --> 00:45:26,993 我们可以把DIAG1定义为 we can define diag1 1052 00:45:34,425 --> 00:45:35,550 把DIAG1定义为 diag1 1053 00:45:37,824 --> 00:45:41,600 只含有参数P的过程 to be the procedure of one argument, p, 1054 00:45:42,450 --> 00:45:44,050 它有着这样的属性 which has the following properties. 1055 00:45:44,780 --> 00:45:50,675 如果(SAFE? P P)为真 If it's safe to apply p to itself, 1056 00:45:53,325 --> 00:45:55,325 那么我就主动陷入死循环 then I wish to have an infinite loop. 1057 00:45:59,225 --> 00:46:00,925 否则我会返回3 Otherwise I'm going to return 3. 1058 00:46:03,680 --> 00:46:04,470 它也可能是42 Maybe it was 42. 1059 00:46:04,470 --> 00:46:06,425 宇宙的终极答案是什么? What's the answer to the big question? 1060 00:46:07,060 --> 00:46:08,875 我们当然知道死循环是什么 Where of course we know what an infinite loop is. 1061 00:46:12,050 --> 00:46:12,964 死循环INF是 Infinite loop, 1062 00:46:13,825 --> 00:46:16,025 一个无参过程 to be a procedure of no arguments, 1063 00:46:16,025 --> 00:46:18,075 这是一个极好的LAMBADA演算循环 which is that nice lambda calculus loop. 1064 00:46:18,352 --> 00:46:20,448 (LAMBDA (X) (X X)) Lambda of x, 1065 00:46:21,300 --> 00:46:24,680 应用到(LAMBDA (X) (X X)) applied to lambda of x, x of x. 1066 00:46:24,680 --> 00:46:26,550 没什么想象的余地了 So there's nothing left to the imagination here. 1067 00:46:29,830 --> 00:46:31,175 我们来看下会发生什么 Well let's see what the story is. 1068 00:46:32,500 --> 00:46:33,908 我假设 I'm supposing it's the case 1069 00:46:35,450 --> 00:46:38,772 我们考虑 that we worry about the procedure 1070 00:46:39,000 --> 00:46:43,450 把DIAG1应用到DIAG1上 called diag1 applied to diag1. 1071 00:46:46,275 --> 00:46:47,775 那会发生什么呢? Well what could it possibly be? 1072 00:46:49,970 --> 00:46:51,390 我不知道 Well I don't know. 1073 00:46:51,390 --> 00:46:53,213 将DIAG1代换为 We're going to substitute diag1 1074 00:46:53,550 --> 00:46:55,500 P的过程体 for p in the body here. 1075 00:46:57,310 --> 00:47:00,220 (SAFE? DIAG1 DIAG1)会返回什么呢? Well is it safe to compute diag1 of diag1? 1076 00:47:00,220 --> 00:47:00,780 我不知道 I don't know. 1077 00:47:00,780 --> 00:47:01,825 有两种可能 There are two possibilities. 1078 00:47:03,400 --> 00:47:05,501 如果计算(DIAG1 DIAG1)是安全的 If it's safe to compute diag1 of diag1 1079 00:47:05,920 --> 00:47:06,896 这意味着没有死循环 that means it shouldn't loop. 1080 00:47:08,490 --> 00:47:09,225 那么我就要来到这里 That means I go to here, 1081 00:47:09,225 --> 00:47:10,350 但是随即我就陷入了死循环 but then I produce an infinite loop. 1082 00:47:10,560 --> 00:47:11,575 所以它不是安全的 So it can't be safe. 1083 00:47:12,210 --> 00:47:14,781 但如果计算(DIAG1 DIAG1)不安全 But if it's not safe to compute diag1 of diag1 1084 00:47:14,900 --> 00:47:16,020 那么它的结果是3 then the answer to this is 3. 1085 00:47:16,020 --> 00:47:17,267 但是调用(DIAG1 DIAG1)又必须能够返回 But that's diag1 of diag1, 1086 00:47:17,260 --> 00:47:17,936 所以它必须安全才行 so it had to be safe. 1087 00:47:20,530 --> 00:47:23,600 因此 通过归纳出这个矛盾 So therefore by contradiction 1088 00:47:24,325 --> 00:47:26,300 我们无法写出这个SAFE?过程 you cannot produce safe. 1089 00:47:27,400 --> 00:47:29,805 如果大家没有听明白这种表述 For those of you who were boggled by that one 1090 00:47:30,250 --> 00:47:32,150 我换个方式再讲一遍 I'm going to say it again, in a different way. 1091 00:47:32,820 --> 00:47:34,000 请听另一个版本 Listen to one more alternative. 1092 00:47:35,530 --> 00:47:36,950 我们定义DIAG2 Let's define diag2. 1093 00:47:39,840 --> 00:47:41,600 取名叫DIAG是因为 These are named diag because 1094 00:47:42,650 --> 00:47:44,725 它来源于康托尔的对角论证法 of Cantor's diagonal argument. 1095 00:47:45,000 --> 00:47:47,050 这些事例最初都来自于 These are instances of 1096 00:47:47,050 --> 00:47:49,056 一个著名的论证 a famous argument which was originally used by 1097 00:47:49,450 --> 00:47:52,650 也就是康托尔在19世纪末 Cantor in the late part of the last century 1098 00:47:52,775 --> 00:47:56,106 证明了实数是不可数的 to prove that the real numbers were not countable, 1099 00:47:56,670 --> 00:47:58,000 整数与实数 that there are too many real numbers 1100 00:47:58,064 --> 00:47:59,420 无法形成一一映射 to be counted by integers. 1101 00:48:00,190 --> 00:48:01,741 数轴上的点 That there are more points on a line, 1102 00:48:01,741 --> 00:48:02,500 举例来说 for example, 1103 00:48:02,506 --> 00:48:04,425 比数轴上的刻度还要多 than there are counting numbers. 1104 00:48:05,260 --> 00:48:06,858 这或许不是个显而易见的结论 It may or may not be obvious, 1105 00:48:06,858 --> 00:48:08,175 但我不想深入讨论这个 and I don't want to get into that now. 1106 00:48:10,900 --> 00:48:12,450 但是DIAG2 But diag2 1107 00:48:13,300 --> 00:48:15,820 也是一个参数为P的单参过程 is again a procedure of one argument p. 1108 00:48:15,820 --> 00:48:17,475 这几乎与之前的例子相同 It's almost the same as the previous one, 1109 00:48:17,725 --> 00:48:24,323 如果计算(P P)是安全的 which is, if it's safe to compute p on p, 1110 00:48:25,175 --> 00:48:26,675 那么我就要 then I'm going to produce-- 1111 00:48:27,260 --> 00:48:28,144 哦 漏了一个IF Oops, if 1112 00:48:29,312 --> 00:48:31,020 那么我就去计算 then I want to compute 1113 00:48:31,570 --> 00:48:37,584 一些(P P)之外的东西 some other things 1114 00:48:38,960 --> 00:48:40,210 否则我就返回FALSE Otherwise I'm going to put out false. 1115 00:48:43,600 --> 00:48:45,300 这里的OTHER-THAN意思是 Where other then it says, 1116 00:48:45,472 --> 00:48:46,350 不管这个(P P)是什么 whatever p of p, 1117 00:48:46,352 --> 00:48:47,475 我都返回一些别的东西 I'm going to put out something else. 1118 00:48:48,880 --> 00:48:50,032 我来给出一个 I can give you an example of 1119 00:48:50,075 --> 00:48:51,525 OTHER-THAN的一个定义 a definition of other than 1120 00:48:51,600 --> 00:48:52,570 我觉得它是可用的 which I think works. 1121 00:48:53,890 --> 00:48:54,512 来看看 Let's see. 1122 00:48:55,640 --> 00:48:56,080 好 Yes. 1123 00:48:56,330 --> 00:48:57,266 定义OTHER-THAN Where other than 1124 00:49:04,030 --> 00:49:06,112 参数为X的单参过程 be a procedure of one argument x 1125 00:49:06,576 --> 00:49:07,260 过程体是 which says, 1126 00:49:08,050 --> 00:49:12,961 如果(EQ? X 'A) if its eq x to, say, quote a, 1127 00:49:13,472 --> 00:49:15,070 那么结果是'B then the answer is quote b. 1128 00:49:15,720 --> 00:49:16,800 否则结果是'A Otherwise it's quote a. 1129 00:49:20,272 --> 00:49:21,900 这样无论参数是什么 That always produces something 1130 00:49:22,075 --> 00:49:23,450 返回值跟参数总是不相同的 which is not what its argument is. 1131 00:49:25,200 --> 00:49:26,120 就是这样了 That's all it is. 1132 00:49:26,540 --> 00:49:27,375 这就是我要的 That's all I wanted. 1133 00:49:28,250 --> 00:49:29,587 我们考虑一下这个 Well now let's consider this one, 1134 00:49:29,587 --> 00:49:31,150 (DIAG2 DIAG2) diag2 of diag2. 1135 00:49:38,288 --> 00:49:38,944 看 Well look. 1136 00:49:39,950 --> 00:49:41,725 这个东西会做些危险的事情 This only does something dangerous, 1137 00:49:42,000 --> 00:49:43,450 比如求值(P P) like calling p of p, 1138 00:49:44,750 --> 00:49:45,950 如果它是安全的 if it's safe to do so. 1139 00:49:47,470 --> 00:49:49,168 如果SAFE?能够被定义的话 So if safe defined at all, 1140 00:49:50,300 --> 00:49:52,496 如果你能定义SAFE?过程 if you can define such a procedure, safe, 1141 00:49:52,975 --> 00:49:54,325 那么这个过程 then this procedure 1142 00:49:54,608 --> 00:49:56,400 也就顺理成章地是安全的 is always defined and therefore safe 1143 00:49:56,525 --> 00:49:57,225 对于任意输入来说都是 on any inputs. 1144 00:50:01,540 --> 00:50:03,504 那么(DIAG2 DIAG2) So diag2 of diag2 1145 00:50:03,875 --> 00:50:12,200 就会返回(OTHER-THAN (DIAG2 DIAG2)) must reduce to other than diag2 of diag2. 1146 00:50:15,825 --> 00:50:16,975 这说不通 And that doesn't make sense, 1147 00:50:17,800 --> 00:50:19,024 又产生了悖论 so we have a contradiction, 1148 00:50:19,850 --> 00:50:21,575 因此我们不能定义SAFE? and therefore we can't define safe. 1149 00:50:22,950 --> 00:50:24,237 我只想这样证明两次 I just waned to do that twice, 1150 00:50:24,784 --> 00:50:25,820 有些许不同 slightly differently, 1151 00:50:26,848 --> 00:50:27,900 你不会感到 so you wouldn't feel 1152 00:50:29,072 --> 00:50:30,864 第一个证明是个把戏 that the first one was a trick. 1153 00:50:32,544 --> 00:50:33,450 它们可能都是把戏 They may be both tricks, 1154 00:50:33,800 --> 00:50:35,152 但它们稍微有些不同 but they're at least slightly different. 1155 00:50:37,300 --> 00:50:39,200 因此 我想这就基本上讲清楚了 So I suppose that pretty much wraps it up. 1156 00:50:40,032 --> 00:50:41,970 我们刚刚证明了所谓的“停机问题” I've just proved what we call the halting theorem, 1157 00:50:43,000 --> 00:50:44,704 我想 本课程也即将画上句号 and I suppose with that we're going to halt. 1158 00:50:46,720 --> 00:50:47,632 希望你们有所收获 I hope you have a good time. 1159 00:50:50,900 --> 00:50:51,765 有什么问题吗? Are there any questions? 1160 00:50:53,300 --> 00:50:53,568 请讲 Yes. 1161 00:50:53,810 --> 00:50:56,275 学生: (S DIAG1)的值是什么? AUDIENCE: What is the value of s of diag1? 1162 00:50:56,750 --> 00:50:57,232 教授: 什么的值? PROFESSOR: Of what? 1163 00:50:57,504 --> 00:50:58,800 学生: (S DIAG1)的值 AUDIENCE: S of diag1. 1164 00:51:00,120 --> 00:51:02,208 如果你说S是个函数 我们就可以-- If you said s is a function, and then we can 1165 00:51:02,304 --> 00:51:03,632 教授: 噢 我不知道啊 PROFESSOR: Oh, I don't know. 1166 00:51:03,870 --> 00:51:04,350 我不知道 I don't know. 1167 00:51:04,350 --> 00:51:04,882 它是一个函数 It's a function, 1168 00:51:04,880 --> 00:51:05,856 但我不知道如何计算它 but I don't know how to compute it. 1169 00:51:06,800 --> 00:51:08,000 我做不到 I can't do it. 1170 00:51:08,610 --> 00:51:09,648 我也只是个机器 I'm just a machine, too. 1171 00:51:11,530 --> 00:51:11,888 对吧? Right? 1172 00:51:11,904 --> 00:51:13,370 原则上来说 And there's no machine 1173 00:51:13,375 --> 00:51:14,050 没有机器 that in principle-- 1174 00:51:14,475 --> 00:51:16,875 当然 也有可能会处在你刚才问的那个情况中 it might be that in that particular case you just asked, 1175 00:51:16,870 --> 00:51:18,320 花点时间还是可以计算出来 with some thinking I could figure it out. 1176 00:51:18,580 --> 00:51:19,375 但通常情况下 But in general 1177 00:51:19,600 --> 00:51:21,050 我无法计算S的值 I can't compute the value of s 1178 00:51:21,050 --> 00:51:22,525 别的机器也做不到 any better than any other machine can. 1179 00:51:23,780 --> 00:51:24,925 存在这样一个函数 There is such a function, 1180 00:51:25,925 --> 00:51:28,000 没有任何机器能够计算它 it's just that no machine can be built to compute it. 1181 00:51:29,580 --> 00:51:30,050 现在 Now 1182 00:51:30,672 --> 00:51:33,675 我这么来说也不会让你们吃惊 there's a way of saying that that should not be surprising. 1183 00:51:35,225 --> 00:51:36,250 来想一想 Going through this-- 1184 00:51:36,250 --> 00:51:38,362 现在我没有时间给你们展示 I mean, I don't have time to do this here, 1185 00:51:38,450 --> 00:51:43,000 但这样的函数非常多 but the number of functions is very large. 1186 00:51:44,400 --> 00:51:47,584 如果有一定量的可能输入 If there's a certain number of answers possible 1187 00:51:47,754 --> 00:51:49,626 和一定量可能的结果 and a certain number of inputs possible, 1188 00:51:49,875 --> 00:51:51,800 那么结果数量的输入数量次幂 then it's the number of answers raised to the number inputs 1189 00:51:51,800 --> 00:51:53,200 就是可能的函数的数量 is the number of possible functions. 1190 00:51:54,500 --> 00:51:55,488 这还是单参的函数 On one variable. 1191 00:51:56,510 --> 00:51:59,248 而多参函数的个数 Now that's always bigger 1192 00:52:00,090 --> 00:52:03,216 又比这个幂次方 than the thing you're raising to, 1193 00:52:03,584 --> 00:52:04,320 这个指数还要大 the exponent. 1194 00:52:05,480 --> 00:52:09,800 函数的数量 The number of functions is larger 1195 00:52:09,950 --> 00:52:12,725 比一个人能写出的 than the number of programs 1196 00:52:13,306 --> 00:52:14,100 程序的数量更多 that one can write, 1197 00:52:14,825 --> 00:52:16,450 因为有无穷多的参数 by an infinity counting argument. 1198 00:52:17,575 --> 00:52:19,000 可能会更多 And it's much larger. 1199 00:52:19,475 --> 00:52:22,124 所以不可计算的函数数量 So there must be a lot of functions 1200 00:52:22,120 --> 00:52:23,488 一定会非常多 that can't be computed by programs. 1201 00:52:25,920 --> 00:52:26,592 学生:不久前 AUDIENCE: A few moments ago 1202 00:52:26,640 --> 00:52:28,256 你讲了规范 you were talking about specifications 1203 00:52:28,304 --> 00:52:30,048 和自动生成解决方案 and automatic generation of solutions. 1204 00:52:30,640 --> 00:52:31,616 您觉得通过规范 Do you see any steps 1205 00:52:31,824 --> 00:52:33,360 能够生成解决方案么? between specifications and solutions? 1206 00:52:37,250 --> 00:52:38,225 教授:“生成” PROFESSOR: Steps between. 1207 00:52:38,720 --> 00:52:39,375 你是说 You mean, you're saying, 1208 00:52:39,375 --> 00:52:42,603 如何按照规范 how you go about constructing 1209 00:52:42,600 --> 00:52:44,784 构建相应的装置吗? devices given that have specifications for the device? 1210 00:52:45,056 --> 00:52:48,360 学生:软件工程中有很多 AUDIENCE: There's a lot of software engineering 1211 00:52:48,361 --> 00:52:49,900 层次化的设计 that goes through specifications through 1212 00:52:49,900 --> 00:52:51,900 并进行实现的规范 many layers of design and then implementation. 1213 00:52:52,430 --> 00:52:52,850 教授:是的 PROFESSOR: Yes? 1214 00:52:52,850 --> 00:52:53,700 学生:我很好奇 AUDIENCE: I was curious 1215 00:52:53,700 --> 00:52:54,625 您觉得这现实吗? if you think that's realistic. 1216 00:52:55,600 --> 00:52:57,175 教授:我觉得其中一些是现实的 PROFESSOR: Well I think that some of it's realistic 1217 00:52:57,175 --> 00:52:58,100 另一些不现实 and some of it isn't. 1218 00:52:58,100 --> 00:53:00,320 如果你想制造一个滤波器 I mean, surely if I want to build an electrical filter 1219 00:53:01,175 --> 00:53:07,160 我这有个挺有趣的例子 and I have a rather interesting possibility. 1220 00:53:07,160 --> 00:53:09,424 假设我想制造一个东西 Supposing I want to build a thing that matches 1221 00:53:09,648 --> 00:53:14,070 把无线电发射器的输出 that matches some power output to the radio transmitter, 1222 00:53:14,475 --> 00:53:18,750 连接到某条天线上 to some antenna. 1223 00:53:19,900 --> 00:53:21,472 我先把它引出来 And I'm really out of this power-- 1224 00:53:21,488 --> 00:53:23,040 这里是输出管线 it's output tube out here. 1225 00:53:23,230 --> 00:53:25,264 问题是它们的阻抗不同 And the problem is that they have different impedances. 1226 00:53:25,920 --> 00:53:27,550 我希望能够匹配阻抗 I want them to match the impedances. 1227 00:53:27,550 --> 00:53:28,976 我也想在其中加入一个滤波器 I also want to make a filter in there 1228 00:53:29,150 --> 00:53:31,712 用来过滤一些谐波辐射 which is going to get rid of some harmonic radiation. 1229 00:53:32,780 --> 00:53:36,638 一种老派的技术叫作 Well one old-fashioned technique for doing this is called 1230 00:53:36,820 --> 00:53:38,672 “影像阻抗”之类的东西 image impedances, or something like that. 1231 00:53:38,860 --> 00:53:39,500 你要做的是 And what you do 1232 00:53:39,500 --> 00:53:40,850 你有个基础的模块 is you say you have a basic module 1233 00:53:40,850 --> 00:53:42,750 称为L型滤波器 called an L-section. 1234 00:53:43,300 --> 00:53:43,984 就像这样 Looks like this. 1235 00:53:47,080 --> 00:53:49,800 如果把它连接到某些电阻R上 If I happen to connect this to some resistance, r, 1236 00:53:50,050 --> 00:53:52,600 如果我把它的阻抗记作X_L and if I make this impedance x, xl, 1237 00:53:52,720 --> 00:53:55,200 而它的值刚好又等于Q*R and if it happens to be q times r, 1238 00:53:55,264 --> 00:53:58,520 这就成了一个低通滤波器 then this produces a low pass filter 1239 00:53:58,520 --> 00:54:00,720 有Q^2+1的等效阻抗 with a q square plus one impedance match. 1240 00:54:02,110 --> 00:54:02,864 这就是我想要的 Just what I need. 1241 00:54:03,120 --> 00:54:04,288 因为这样我就可以 Because now I can take two of these, 1242 00:54:04,304 --> 00:54:05,088 把它们匹配到一起了 hook them together 1243 00:54:05,824 --> 00:54:06,384 就像这样 like this. 1244 00:54:11,660 --> 00:54:13,150 我拿来另一个 OK, and I take another one 1245 00:54:16,000 --> 00:54:17,456 想这样把它们连到一起 and I'll hook them together like that. 1246 00:54:18,290 --> 00:54:19,950 有两个L型滤波器连接起来 And I have two L-sections hooked together. 1247 00:54:20,320 --> 00:54:23,070 这能让它的阻抗降到我知道的值 And this will step the impedance down to one that I know, 1248 00:54:23,375 --> 00:54:25,225 让它的阻抗升到我知道的值 and this will step it up to one I know. 1249 00:54:25,530 --> 00:54:26,640 这两个低通滤波器 Each of these is a low pass filter 1250 00:54:26,672 --> 00:54:27,824 都过滤掉了一些谐波 getting rid of some harmonics. 1251 00:54:28,090 --> 00:54:29,072 这是个不错的滤波器 It's good filter, 1252 00:54:29,072 --> 00:54:30,270 这就是π型滤波器 it's called a pie-section filter. 1253 00:54:30,270 --> 00:54:30,624 很好 Great. 1254 00:54:31,700 --> 00:54:34,096 除了实际上 Except for the fact that in doing what I just did, 1255 00:54:34,128 --> 00:54:37,850 我在系统里放了些无用的东西 I've made a terrible inefficiency in this system. 1256 00:54:38,620 --> 00:54:39,600 我在本该只用一个的地方 I've made two coils 1257 00:54:39,616 --> 00:54:40,592 用了两个线圈 where I should have made one. 1258 00:54:41,620 --> 00:54:44,600 在大多数软件工程技艺中 And the problem with most software engineering art 1259 00:54:44,890 --> 00:54:46,880 在人工优化和编译之外 is that there's no mechanism, 1260 00:54:46,928 --> 00:54:48,656 不存在一种机制 other than people optimization and compilers, 1261 00:54:48,800 --> 00:54:51,344 能在自顶向下的设计中 for getting rid of the redundant parts 1262 00:54:51,344 --> 00:54:53,550 去掉冗余的部分 that are constructed when doing top down design. 1263 00:54:55,350 --> 00:54:56,076 或许会更糟 It's even worse, 1264 00:54:56,070 --> 00:54:57,584 有很多重要的结构 there are lots of very important structures 1265 00:54:57,600 --> 00:54:59,020 你无法采用这种方式构建 that you can't construct at all this way. 1266 00:55:01,110 --> 00:55:03,535 我觉得标准的自上而下的设计方式 So I think that the standard top down design 1267 00:55:03,535 --> 00:55:04,875 是一种很短视的手段 is a rather shallow business. 1268 00:55:05,710 --> 00:55:06,600 它不会真的抓到 Doesn't really capture 1269 00:55:06,600 --> 00:55:08,100 设计者真正想要的结果 what people want to do in design. 1270 00:55:08,315 --> 00:55:10,100 我再举一个电子学的例子 I'll give you another electrical example. 1271 00:55:10,100 --> 00:55:11,750 电子学的例子 Electrical examples are so much clearer 1272 00:55:11,900 --> 00:55:13,136 要比计算的例子直观得多 than computational examples, 1273 00:55:13,168 --> 00:55:14,784 因为计算的例子 because computation examples require 1274 00:55:14,800 --> 00:55:16,520 解释起来比较复杂 a certain degree of complexity to explain them. 1275 00:55:17,220 --> 00:55:19,168 在电子学世界中 But one of my favorite examples 1276 00:55:19,168 --> 00:55:20,040 我最喜欢的例子之一是 in the electrical world 1277 00:55:20,600 --> 00:55:22,800 是如何设计中频放大器中 is how would I ever come up with the output stage 1278 00:55:23,280 --> 00:55:26,550 输入级和输出级的连接方式 of this inter-stage connection in an IF amplifier. 1279 00:55:27,530 --> 00:55:29,440 这是一个三极管 It's a little transistor here, 1280 00:55:29,520 --> 00:55:31,500 我们来看看 and let's see. 1281 00:55:32,410 --> 00:55:33,400 这有个LC震荡电路 Well I'm going to have a tank, 1282 00:55:36,450 --> 00:55:39,175 我要把它 and I'm going to hook this up to, say, 1283 00:55:41,375 --> 00:55:43,975 把它与下一级的输入线圈耦合在一起 I'm going to link-couple that to the input of the next stage. 1284 00:55:44,368 --> 00:55:47,470 这是个完美的可行方案 Here's a perfectly plausible plan-- 1285 00:55:48,225 --> 00:55:50,875 除了我这个电流方向画错了 well except for the fact that since I put that going up 1286 00:55:50,875 --> 00:55:52,925 电流应该是这个方向 I should make that going that way. OK? 1287 00:55:53,170 --> 00:55:55,456 这是个完美的可行方案 Here's a perfectly plausible plan for a-- 1288 00:55:55,984 --> 00:55:56,576 不对 no I shouldn't. 1289 00:55:57,120 --> 00:55:57,792 我犯蠢了 I'm dumb. 1290 00:55:58,400 --> 00:55:59,075 对不起 Excuse me. 1291 00:55:59,690 --> 00:56:00,425 这不重要 Doesn't matter. 1292 00:56:00,730 --> 00:56:01,540 关键在于这是一个 The point is it's a perfect 1293 00:56:01,540 --> 00:56:03,425 把两级耦合起来的完美方案 plan for a couple two stages together. 1294 00:56:04,544 --> 00:56:06,920 分层来看时会产生什么问题? Now what the problem is what's this hierarchically? 1295 00:56:07,620 --> 00:56:08,800 它就不是同一个东西了 It's not one thing. 1296 00:56:09,480 --> 00:56:11,990 当分层来看时它就没有任何意义了 Hierarchically it doesn't make any sense at all. 1297 00:56:11,990 --> 00:56:14,325 这是一个调谐电路的电感 It's the inductance of a tuned circuit, 1298 00:56:15,550 --> 00:56:18,025 这是变压器的初级线圈 it's the primary of a transformer, 1299 00:56:19,100 --> 00:56:21,825 这是直流的通路 and it's also the DC path by 1300 00:56:21,825 --> 00:56:23,575 它是三极管的集电极 which bias conditions get to the 1301 00:56:23,575 --> 00:56:25,100 的偏置条件 collector of that transistor. 1302 00:56:26,460 --> 00:56:28,352 没有任何简单的自顶向下设计 And there's no simple top-down design 1303 00:56:28,384 --> 00:56:30,170 能够得到这样的结构 that's going to produce a structure like that 1304 00:56:30,225 --> 00:56:34,025 对于同一个东西有大量的复用 with so many overlapping uses for a particular thing. 1305 00:56:34,530 --> 00:56:36,729 玩拼字游戏 Playing Scrabble, 1306 00:56:36,960 --> 00:56:39,888 当你要完成三倍分数的词时 where you have to do triple word scores, or whatever, 1307 00:56:40,496 --> 00:56:43,600 自顶向下的设计策略并不容易 is not so easy in top-down design strategy. 1308 00:56:44,950 --> 00:56:47,088 然而 大多数实际的工程学都是 Yet most of real engineering is based on 1309 00:56:47,360 --> 00:56:50,700 秉承着“尽其力而为之” on getting the most oomph for effort. 1310 00:56:52,140 --> 00:56:53,525 那就是你所看到的东西 And that's what you're seeing here. 1311 00:56:54,860 --> 00:56:55,550 嗯? Yeah? 1312 00:56:55,550 --> 00:56:56,810 学生:这是最后一个问题吗? AUDIENCE: Is this the last question? 1313 00:57:00,280 --> 00:57:02,032 [笑声] [LAUGHTER] 1314 00:57:18,640 --> 00:57:19,632 教授:看起来是 PROFESSOR: Apparently so. 1315 00:57:23,575 --> 00:57:24,125 谢谢大家 Thank you. 1316 00:57:25,300 --> 00:57:36,500 [掌声] [APPLAUSE] 1317 00:57:39,040 --> 00:58:52,200 [音乐] [JESU, JOY OF MAN'S DESIRING] 1318 00:58:52,200 --> 00:58:54,200 MIT OpenCourseWare http://ocw.mit.edu 1319 00:58:54,200 --> 00:58:56,200 本项目主页 https://github.com/DeathKing/Learning-SICP 1320 00:58:56,200 --> 00:58:58,200 你所知道的有关计算的东西,其他人也都能学到。绝不要认为似乎成功计算的钥匙就掌握在你的手里。你所掌握的,也是我认为并希望的,也就是智慧:那种看到这一机器比你第一次站在它面前时能做得更多的能力,这样你才能将它向前推进。 Alan J. Perlis ================================================ FILE: SrtCN/lec1a.srt ================================================ 1 00:00:01,100 --> 00:00:04,500 哈尔滨工业大学 IBM技术中心 倾情制作 2 00:00:04,600 --> 00:00:09,400 压制&&特效:蔡钟敏(Tacitus) 字幕&&时间轴:邓雄飞(Dysprosium) 3 00:00:09,500 --> 00:00:13,000 特别感谢:裘宗燕 4 00:00:14,264 --> 00:00:17,440 欢迎大家来一起学习这门计算机科学的基础课程 I'd like to welcome you to this course on computer science. 5 00:00:27,952 --> 00:00:29,408 事实上 以这样的方式来表述并不恰当 Actually, that's a terrible way to start. 6 00:00:29,408 --> 00:00:31,890 于此来说 计算机科学是个糟糕的名字 Computer science is a terrible name for this business. 7 00:00:32,384 --> 00:00:33,856 首先 它不算是一门科学 First of all, it's not a science. 8 00:00:35,472 --> 00:00:39,020 它更应该被称为工程或者是艺术 It might be engineering or it might be art, 9 00:00:39,648 --> 00:00:42,464 但我们实际上会发现 这个所谓的计算机科学 but we'll actually see that computer so-called science 10 00:00:42,480 --> 00:00:44,528 却与魔法一样的有众多神奇之处 actually has a lot in common with magic, 11 00:00:44,560 --> 00:00:45,904 这些将会在课程中一一体现 and we'll see that in this course. 12 00:00:46,832 --> 00:00:47,776 所以 不能称其为一门科学 So it's not a science. 13 00:00:48,648 --> 00:00:51,854 这门学科和“计算机”也并非紧密相关 It's also not really very much about computers. 14 00:00:52,944 --> 00:00:55,024 类似的 就像我们说 And it's not about computers in the same sense 15 00:00:55,024 --> 00:00:59,600 物理学中并不仅仅有关粒子加速器 that physics is not really about particle accelerators, 16 00:01:00,352 --> 00:01:05,136 生物学中并不全然是显微镜和培养皿一样 and biology is not really about microscopes and petri dishes. 17 00:01:06,010 --> 00:01:09,800 同理 And it's not about computers in the same sense 18 00:01:09,860 --> 00:01:14,432 几何学中也并不全是介绍如何使用测量仪器 that geometry is not really about using surveying instruments. 19 00:01:16,032 --> 00:01:18,560 事实上 计算机科学和几何学 In fact, there's a lot of commonality 20 00:01:18,880 --> 00:01:21,000 有很多共性 between computer science and geometry. 21 00:01:21,000 --> 00:01:22,213 首先 几何学 Geometry, first of all, 22 00:01:22,579 --> 00:01:24,535 只是另一个有个糟糕名字的学科 is another subject with a lousy name. 23 00:01:25,136 --> 00:01:27,400 这个名字来自于Gaia 意为土地 The name comes from Gaia, meaning the Earth, 24 00:01:27,450 --> 00:01:28,640 以及metron 意为测量 and metron, meaning to measure. 25 00:01:29,376 --> 00:01:32,944 几何学最初意为测地或者勘探 Geometry originally meant measuring the Earth or surveying. 26 00:01:33,920 --> 00:01:36,440 这是因为数千年前的埃及祭司 And the reason for that was that, thousands of years ago, 27 00:01:37,248 --> 00:01:41,248 为了计算如何去修复年年被尼罗河的洪水 the Egyptian priesthood developed the rudiments of geometry 28 00:01:42,144 --> 00:01:45,888 所毁坏的牧田边界 in order to figure out how to restore the boundaries of fields 29 00:01:45,888 --> 00:01:45,904 而建立了几何学基础 that were destroyed in the annual flooding of the Nile. 30 00:01:45,904 --> 00:01:48,240 而建立了几何学基础 that were destroyed in the annual flooding of the Nile. 31 00:01:49,024 --> 00:01:50,208 而对出于这个目的的埃及人来说 And to the Egyptians who did that, 32 00:01:50,208 --> 00:01:53,488 几何学的确是掌握对测量仪器的使用 geometry really was the use of surveying instruments. 33 00:01:55,184 --> 00:01:58,100 现在 我们以为计算机科学就是介绍计算机的使用 Now, the reason that we think computer science is about computers 34 00:01:58,120 --> 00:02:02,048 就正如埃及人认为 is pretty much the same reason that the Egyptians thought geometry 35 00:02:02,064 --> 00:02:03,650 几何学是介绍如何使用测量仪器的 was about surveying instruments. 36 00:02:04,140 --> 00:02:06,928 换句话说 任何一门学科起步的时候 And that is, when some field is just getting started 37 00:02:06,940 --> 00:02:09,410 你都对它了解不深 and you don't really understand it very well, 38 00:02:10,656 --> 00:02:16,192 这很容易使你混淆所做的事与所用之物 it's very easy to confuse the essence of what you're doing with the tools that you use. 39 00:02:17,200 --> 00:02:19,856 确实 就绝对规模来说 And indeed, on some absolute scale of things, 40 00:02:19,856 --> 00:02:24,370 我们对计算机科学的实质的了解 we probably know less about the essence of computer science 41 00:02:24,384 --> 00:02:27,040 比埃及人对几何学的了解还少 than the ancient Egyptians really knew about geometry. 42 00:02:29,808 --> 00:02:32,192 那么 我所谓的计算机科学的本质是什么呢 Well, what do I mean by the essence of computer science? 43 00:02:32,208 --> 00:02:33,960 我所谓的几何学本质又是什么呢 What do I mean by the essence of geometry? 44 00:02:33,968 --> 00:02:36,000 看 可以确认的是 古埃及人确实使用测量仪器 See, it's certainly true that these Egyptians went off 45 00:02:36,016 --> 00:02:37,220 并且已经消失多年 and used surveying instruments, 46 00:02:37,248 --> 00:02:41,104 但当我们在几千年后回过头来重新审视这段历史 but when we look back on them after a couple of thousand years, 47 00:02:41,120 --> 00:02:41,408 我们会说 we say, 48 00:02:41,424 --> 00:02:43,190 天啊 看他们在做什么 gee, what they were doing, 49 00:02:43,264 --> 00:02:45,030 他们的工作是多么的重要 the important stuff they were doing, 50 00:02:45,170 --> 00:02:50,000 已经开始对时间和空间进行形式化表述 was to begin to formalize notions about space and time, 51 00:02:51,136 --> 00:02:57,080 并归纳出一套讨论数学真理的形式化方法 to start a way of talking about mathematical truths formally. 52 00:02:57,568 --> 00:02:59,168 这直接导致了公理化方法 That led to the axiomatic method. 53 00:02:59,168 --> 00:03:02,080 以及各种现代数学的产生 That led to sort of all of modern mathematics, 54 00:03:03,712 --> 00:03:06,450 同时也指明了一种精确讨论 figuring out a way to talk precisely about 55 00:03:06,800 --> 00:03:09,740 所谓的描述真理的陈述性知识的方法 so-called declarative knowledge, what is true. 56 00:03:12,000 --> 00:03:15,808 与此相似的 我认为未来人们会回过头来审视并说 Well, similarly, I think in the future people will look back and say, 57 00:03:15,824 --> 00:03:18,912 啊 这些20世纪的原始人 yes, those primitives in the 20th century were fiddling around 58 00:03:18,912 --> 00:03:20,750 不务正业地玩弄着叫计算机的小玩意 with these gadgets called computers, 59 00:03:21,328 --> 00:03:25,800 但它们真正在做的是开始学习 but really what they were doing is starting to learn 60 00:03:25,808 --> 00:03:32,100 如何去对计算过程进行形式化表述 how to formalize intuitions about process, 61 00:03:32,192 --> 00:03:33,680 如何去解决问题 how to do things, 62 00:03:38,576 --> 00:03:50,800 并结合两者发展一套对问题处理过程精确表述的方法 starting to develop a way to talk precisely about how-to knowledge, 63 00:03:51,312 --> 00:03:55,580 这与讨论真理的几何学形成了对照 as opposed to geometry that talks about what is true. 64 00:03:56,080 --> 00:03:58,120 让我给你们举个例子吧 Let me give you an example of that. 65 00:04:01,856 --> 00:04:02,240 来瞧瞧 Let's take a look 66 00:04:02,256 --> 00:04:09,376 数学中是这样来定义平方根的: Here is a piece of mathematics that says what a square root is. 67 00:04:09,648 --> 00:04:13,900 定义X的平方根Y是这样一个数 The square root of X is the number Y, 68 00:04:15,536 --> 00:04:19,936 Y的平方等于X 且Y大于等于0 such that Y squared is equal to X and Y is greater than 0. 69 00:04:19,984 --> 00:04:22,050 这是一个很好的定义 Now, that's a fine piece of mathematics, 70 00:04:22,432 --> 00:04:24,800 但它只告诉了你平方根是什么 but just telling you what a square root is 71 00:04:25,184 --> 00:04:29,840 却没有告诉你如何去求取一个平方根 doesn't really say anything about how you might go out and find one. 72 00:04:30,976 --> 00:04:35,456 那么我们将其与一条指令性知识做比较 So let's contrast that with a piece of imperative knowledge, 73 00:04:36,688 --> 00:04:39,472 你如何去求取一个平方根 how you might go out and find a square root. 74 00:04:39,504 --> 00:04:45,296 事实上 这来自于埃及 不太久远的埃及 This, in fact, also comes from Egypt, not ancient, ancient Egypt. 75 00:04:45,310 --> 00:04:48,430 亚历山大的Heron提出的一个算法 This is an algorithm due to Heron of Alexandria, 76 00:04:49,456 --> 00:04:52,320 称作连续取均值求平方根法 called how to find a square root by successive averaging. 77 00:04:52,448 --> 00:04:54,688 这个算法是说 And what it says is that, 78 00:04:54,704 --> 00:04:57,616 为了算出平方根 in order to find a square root, 79 00:05:02,896 --> 00:05:07,880 首先你应该给出一个猜测值guess 并不断改进 you make a guess, you improve that guess -- 80 00:05:09,744 --> 00:05:10,992 改进的方法是通过 and the way you improve the guess 81 00:05:11,008 --> 00:05:13,500 不断求猜测值guess与X/guess的平均值 is to average the guess and X over the guess, 82 00:05:13,968 --> 00:05:15,152 我们稍后将会讨论 and we'll talk a little bit later about 83 00:05:15,168 --> 00:05:16,670 为什么这是合理的 why that's a reasonable thing-- 84 00:05:16,690 --> 00:05:18,920 通过不断改进 直到它足够精确 and you keep improving the guess until it's good enough. 85 00:05:19,280 --> 00:05:20,400 这就是实现方法 That's a method. 86 00:05:20,540 --> 00:05:24,208 这也是如何完成一项工作与 That's how to do something as opposed to 87 00:05:24,272 --> 00:05:26,880 其对应的陈述性知识的对照 declarative knowledge that says what you're looking for. 88 00:05:27,600 --> 00:05:29,310 这就是一个过程 That's a process. 89 00:05:33,952 --> 00:05:37,808 那么 通常来说什么是过程呢? Well, what's a process in general? 90 00:05:38,560 --> 00:05:39,690 这定义起来非常困难 It's kind of hard to say. 91 00:05:39,712 --> 00:05:43,270 你可以将它象征性地看成一个活在计算机内 You can think of it as like a magical spirit 92 00:05:44,320 --> 00:05:46,880 并且可以完成一些操作的精灵 that sort of lives in the computer and does something. 93 00:05:47,568 --> 00:05:53,664 一些被称为程序的规则模式 And the thing that directs a process is 94 00:05:53,680 --> 00:05:57,530 指导着这类过程的进行 a pattern of rules called a procedure. 95 00:06:01,536 --> 00:06:04,280 程序可以被认为是符咒 So procedures are the spells, if you like, 96 00:06:04,784 --> 00:06:08,950 使用程序来控制这些精灵完成一些操作就叫做过程 that control these magical spirits that are the processes. 97 00:06:10,304 --> 00:06:12,304 你们知道人人都需要一门魔法语言 I guess you know everyone needs a magical language, 98 00:06:12,320 --> 00:06:14,100 那些魔术师 真正的魔术师 用远古的阿卡狄亚语 and sorcerers, real sorcerers, 99 00:06:14,128 --> 00:06:18,140 或者苏美尔语 或者巴比伦语 或者其它的 use ancient Arcadian or Sumerian or Babylonian or whatever. 100 00:06:18,176 --> 00:06:19,640 而我们将用一门叫Lisp的魔法语言 We're going to conjure our spirits 101 00:06:19,680 --> 00:06:22,260 来召唤出我们的精灵 in a magical language called Lisp, 102 00:06:23,920 --> 00:06:27,568 这门语言是被设计用来 which is a language designed for talking about, 103 00:06:28,128 --> 00:06:31,390 编写如咒语版的程序 来指导过程的进行 for casting the spells that are procedures to direct the processes. 104 00:06:31,424 --> 00:06:33,460 学习Lisp非常容易 Now, it's very easy to learn Lisp. 105 00:06:33,520 --> 00:06:35,536 事实上 我会在几分钟内教会你 In fact, in a few minutes, I'm going to teach you, 106 00:06:35,552 --> 00:06:36,710 整个Lisp essentially, all of Lisp. 107 00:06:36,926 --> 00:06:38,515 及其所有的规则 I'm going to teach you, essentially, all of the rules. 108 00:06:40,320 --> 00:06:43,200 你不必感到很惊讶 And you shouldn't find that particularly surprising. 109 00:06:43,240 --> 00:06:45,424 这就像你在学习象棋时 That's sort of like saying it's very easy 110 00:06:45,456 --> 00:06:46,560 认为象棋的规则十分简单一样 to learn the rules of chess. 111 00:06:46,592 --> 00:06:47,680 事实也如此 几分钟内 And indeed, in a few minutes, 112 00:06:47,728 --> 00:06:49,250 你可以与任何人谈论象棋的规则 you can tell somebody the rules of chess. 113 00:06:50,368 --> 00:06:51,792 但是 这全然不等同于说 But of course, that's very different from 114 00:06:51,808 --> 00:06:54,928 你所知道这些规则所蕴含的东西 saying you understand the implications of those rules 115 00:06:54,970 --> 00:06:57,600 以及如何利用这些规则去成为象棋大师 and how to use those rules to become a masterful chess player. 116 00:06:58,048 --> 00:06:59,370 Lisp也是如此 Well, Lisp is the same way. 117 00:06:59,968 --> 00:07:01,730 我将在几分钟内道清规则 We're going to state the rules in a few minutes, 118 00:07:01,910 --> 00:07:03,104 这说起来非常容易 and it'll be very easy to see. 119 00:07:03,170 --> 00:07:06,640 但真正困难的是如何运用这些规则 But what's really hard is going to be the implications of those rules, 120 00:07:06,870 --> 00:07:10,010 以及你如何利用这些规则成为编程大师 how you exploit those rules to be a master programmer. 121 00:07:11,610 --> 00:07:14,848 这些规则的应用将占据我们 And the implications of those rules are going to take us the, 122 00:07:14,860 --> 00:07:18,110 余下的课程 甚至更多 well, the whole rest of the subject and, of course, way beyond. 123 00:07:21,008 --> 00:07:22,660 所以 在计算机科学中 OK, so in computer science, 124 00:07:24,048 --> 00:07:25,744 我们的任务则是 we're in the business of 125 00:07:25,760 --> 00:07:30,130 形式化这种如有关“怎么做”的指令性知识 formalizing this sort of how-to imperative knowledge, 126 00:07:30,176 --> 00:07:31,650 并将之付诸实际 how to do stuff. 127 00:07:32,928 --> 00:07:34,944 这也便是计算机科学的真正的议题 And the real issues of computer science are, of course, 128 00:07:34,960 --> 00:07:37,910 当然 并不是告诉人们如何去求平方根 not telling people how to do square roots. 129 00:07:38,640 --> 00:07:39,616 因为如果那是计算机科学的全部的的话 Because if that was all it was, 130 00:07:39,648 --> 00:07:40,896 就不会有什么大问题了 there wouldn't be no big deal. 131 00:07:41,120 --> 00:07:43,600 真正的问题来自于当我们尝试 The real problems come when we try to 132 00:07:43,632 --> 00:07:45,710 构建非常非常大的系统时 build very, very large systems, 133 00:07:46,160 --> 00:07:49,080 程序可能会长达数千页 computer programs that are thousands of pages long, 134 00:07:49,136 --> 00:07:53,536 长得没有人能马上将其装入脑中 so long that nobody can really hold them in their heads all at once. 135 00:07:54,288 --> 00:07:58,360 而使这些得以实现则是因为 And the only reason that that's possible is because 136 00:07:58,410 --> 00:08:18,528 我们有在大系统中控制复杂度的技术 there are techniques for controlling the complexity of these large systems. 137 00:08:19,850 --> 00:08:22,240 这些控制复杂度的技术 And these techniques that are controlling complexity 138 00:08:22,272 --> 00:08:23,728 正是我们课程所讨论的 are what this course is really about. 139 00:08:24,208 --> 00:08:25,024 从某种意义上来说 And in some sense, 140 00:08:25,056 --> 00:08:27,020 这也正是计算机科学的关键所在 that's really what computer science is about. 141 00:08:29,180 --> 00:08:31,440 这样说听起来或许很奇怪 Now, that may seem like a very strange thing to say. 142 00:08:31,472 --> 00:08:35,168 毕竟 除了计算机科学家外 Because after all, a lot of people besides computer scientists 143 00:08:35,200 --> 00:08:37,370 仍然有很多人在做复杂度控制相关的工作 deal with controlling complexity. 144 00:08:37,390 --> 00:08:40,570 一个航班就是一个非常复杂的系统 A large airliner is an extremely complex system, 145 00:08:41,376 --> 00:08:43,344 设计它的航空工程师 and the aeronautical engineers who design that 146 00:08:43,600 --> 00:08:45,680 便在处理这个巨大的复杂度 are dealing with immense complexity. 147 00:08:46,640 --> 00:08:49,740 但这种复杂度又与 But there's a difference between that kind of complexity 148 00:08:50,304 --> 00:08:52,150 计算机科学中的(复杂度)有别 and what we deal with in computer science. 149 00:08:54,736 --> 00:08:57,280 从某种意义上来说 And that is that computer science, 150 00:08:57,344 --> 00:08:59,648 因为计算机科学不是“现实”的 in some sense, isn't real. 151 00:09:02,240 --> 00:09:06,170 例如 当一名工程师设计物理系统时 You see, when an engineer is designing a physical system, 152 00:09:06,690 --> 00:09:08,040 这些都是由实在的物理部件构成 that's made out of real parts. 153 00:09:08,950 --> 00:09:10,736 负责的该工作的工程师 The engineers who worry about that 154 00:09:11,400 --> 00:09:16,208 就得对付系统中的公差、近似值以及噪声 have to address problems of tolerance and approximation and noise in the system. 155 00:09:16,224 --> 00:09:18,576 譬如说 作为一名电气工程师 So for example, as an electrical engineer, 156 00:09:18,640 --> 00:09:21,264 可以很容易的做一个单极放大器 I can go off and easily build a one-stage amplifier 157 00:09:21,280 --> 00:09:22,580 或者是一个双极放大器 or a two-stage amplifier, 158 00:09:22,960 --> 00:09:24,944 也可想象将其大量串联 and I can imagine cascading a lot of them 159 00:09:25,008 --> 00:09:26,464 来建造一个百万极的放大器 to build a million-stage amplifier. 160 00:09:26,540 --> 00:09:28,304 但这样做是不可行的 But it's ridiculous to build such a thing, 161 00:09:28,530 --> 00:09:31,700 因为在远没到百万数量级的时候 because long before the millionth stage, 162 00:09:31,710 --> 00:09:34,112 这种组合方法打从头产生的热噪声 the thermal noise in those components way at the beginning 163 00:09:34,120 --> 00:09:36,352 会慢慢增强 并使得我们的幸苦付之一炬 is going to get amplified and make the whole thing meaningless. 164 00:09:38,650 --> 00:09:42,670 计算机科学处理的是理想化组件 Computer science deals with idealized components. 165 00:09:43,670 --> 00:09:47,184 我们对将要结合在一起的 We know as much as we want about these little program 166 00:09:47,200 --> 00:09:49,110 程序和数据了如指掌 and data pieces that we're fitting things together. 167 00:09:51,456 --> 00:09:52,752 我们不需要去关心公差 We don't have to worry about tolerance. 168 00:09:52,760 --> 00:09:56,540 也就是说 在构建大系统时 And that means that, in building a large program, 169 00:09:57,680 --> 00:09:59,580 在我理想和现实之间 there's not all that much difference 170 00:09:59,900 --> 00:10:03,730 并不没有太大的不同 between what I can build and what I can imagine, 171 00:10:05,088 --> 00:10:07,152 因为这些部分都是抽象单元 because the parts are these abstract entities 172 00:10:07,184 --> 00:10:09,872 可以随心所欲的组合 that I know as much as I want. 173 00:10:09,888 --> 00:10:11,940 可以据目前所知而自由构建 I know about them as precisely as I'd like. 174 00:10:13,008 --> 00:10:15,050 就是与其它的工程不同之处 So as opposed to other kinds of engineering, 175 00:10:15,210 --> 00:10:16,976 (在其它的工程中)对你所构建系统的约束 where the constraints on what you can build 176 00:10:16,990 --> 00:10:18,450 来自于物理系统以及 are the constraints of physical systems, 177 00:10:18,490 --> 00:10:20,576 物理定律 噪声 近似值等 the constraints of physics and noise and approximation, 178 00:10:20,760 --> 00:10:25,152 而建立大型软件系统时所施加的约束 the constraints imposed in building large software systems 179 00:10:25,190 --> 00:10:27,130 就是对我们大脑的限制 are the limitations of our own minds. 180 00:10:28,670 --> 00:10:29,536 从这个角度来看 So in that sense, 181 00:10:29,550 --> 00:10:33,220 计算机科学就像是工程中的一种抽象形式 computer science is like an abstract form of engineering. 182 00:10:33,350 --> 00:10:35,280 在这种工程中 我们忽略 It's the kind of engineering where you ignore 183 00:10:35,310 --> 00:10:37,570 现实所施加的约束 the constraints that are imposed by reality. 184 00:10:41,520 --> 00:10:45,700 那么 这其中有哪些技术呢 Well, what are some of these techniques? 185 00:10:45,830 --> 00:10:47,940 计算机科学中并没有特别的技术 They're not special to computer science. 186 00:10:49,940 --> 00:10:52,100 第一个技术是在很多工程中都使用的 First technique, which is used in all of engineering, 187 00:10:52,910 --> 00:10:58,464 被称为“黑盒抽象”的方法 is a kind of abstraction called black-box abstraction. 188 00:11:07,264 --> 00:11:12,130 即将一些东西组合并封装起来 Take something and build a box about it. 189 00:11:13,920 --> 00:11:19,648 以之前我们提到的求取平方根的方法为例 Let's see, for example, if we looked at that square root method, 190 00:11:22,190 --> 00:11:28,080 我将这些操作视为一个“盒子” I might want to take that and build a box. 191 00:11:29,440 --> 00:11:37,072 也就是说 为了找到X的平方根 That sort of says, to find the square root of X. 192 00:11:38,416 --> 00:11:40,820 或许会有一系列的复杂规则 And that might be a whole complicated set of rules. 193 00:11:42,192 --> 00:11:46,240 我们将规则封装 输入数据即可获得结果 And that might end up being a kind of thing where I can put in, 194 00:11:46,368 --> 00:11:49,610 比如说 输入36 然后说36的平方根是多少呢 say, 36 and say, what's the square root of 36? 195 00:11:49,808 --> 00:11:51,010 则给出结果 6 And out comes 6. 196 00:11:53,440 --> 00:11:55,776 重点是 And the important thing is that 197 00:11:55,790 --> 00:11:59,584 通过这样的设计 I'd like to design that so that 198 00:11:59,612 --> 00:12:03,633 可以方便他人的使用 if George comes along and would like to compute, 199 00:12:04,656 --> 00:12:08,928 例如Goerge想计算A的平方根加上B的平方根 say, the square root of A plus the square root of B, 200 00:12:10,896 --> 00:12:13,936 他无需了解“盒子”内部的构成 he can take this thing and use it as a module 201 00:12:13,984 --> 00:12:15,296 而直接可以以模块的形式使用它 without having to look inside 202 00:12:15,328 --> 00:12:16,864 也可以利用它去构建新的“盒子” and build something that looks like this, 203 00:12:18,000 --> 00:12:23,750 例如构建一个 A和B以及一个平方根和或者另一个平方根盒子 like an A and a B and a square root box and another square root box 204 00:12:24,080 --> 00:12:33,420 然后将这些结果加在一起并输出答案 and then something that adds that would put out the answer. 205 00:12:33,510 --> 00:12:37,700 如你所见 就我想实现的功能的层面来看 And you can see, just from the fact that I want to do that, 206 00:12:38,470 --> 00:12:39,970 对于George来说 is from George's point of view, 207 00:12:40,060 --> 00:12:42,650 盒子内部是什么样并不重要 the internals of what's in here should not be important. 208 00:12:43,740 --> 00:12:46,800 例如 以下这些说法都没什么问题 So for instance, it shouldn't matter that, when I wrote this, 209 00:12:46,820 --> 00:12:49,984 我说求X的平方根 I said I want to find the square root of X. 210 00:12:50,160 --> 00:12:51,820 也可以说计算Y的平方根 I could have said the square root of Y, 211 00:12:52,272 --> 00:12:55,170 或者其它任何数的平方根 or the square root of A, or anything at all 212 00:12:56,256 --> 00:13:01,904 黑盒抽象的基本规则是 That's the fundamental notion of putting something in a box 213 00:13:03,088 --> 00:13:05,990 将处理过程放入盒子里以隐藏细节 using black-box abstraction to suppress detail. 214 00:13:07,152 --> 00:13:10,540 这样做的原因则是你可以脱身去构建更大的盒子 And the reason for that is you want to go off and build bigger boxes. 215 00:13:11,600 --> 00:13:14,128 现在 除了隐藏细节外 Now, there's another reason for doing black-box abstraction 216 00:13:14,140 --> 00:13:17,968 使用黑盒抽象还有另外一个原因 other than you want to suppress detail for building bigger boxes. 217 00:13:18,030 --> 00:13:24,576 有的时候 你想要用你的方法去完成一件事 Sometimes you want to say that your way of doing something, 218 00:13:24,590 --> 00:13:26,430 你的方法 your how-to method, 219 00:13:27,990 --> 00:13:30,340 就是一个通法的具体实例 is an instance of a more general thing, 220 00:13:30,710 --> 00:13:34,120 同时 你也希望你的表述方式能够具有普遍性 and you'd like your language to be able to express that generality. 221 00:13:35,120 --> 00:13:37,488 我们接着用实例来说明 Let me show you another example 222 00:13:37,520 --> 00:13:38,416 继续刚才关于平方根的讨论 sticking with square roots. 223 00:13:38,448 --> 00:13:41,712 让我们回过头再来看看 Let's go back and take another look at that slide 224 00:13:41,744 --> 00:13:43,300 求平方根的算法 with the square root algorithm on it. 225 00:13:43,712 --> 00:13:45,170 想一想之前是怎么说的 Remember what that says. 226 00:13:45,344 --> 00:13:49,376 为了求解 首先要作出猜测 That says, in order to do something, I make a guess, 227 00:13:50,176 --> 00:13:54,390 然后基于这个猜测 做出持续不断的改进 and I improve that guess, and I sort of keep improving that guess. 228 00:13:55,216 --> 00:13:59,690 因此就存在一个找到某个到结果的通用方法 So there's the general strategy of, I'm looking for something, 229 00:14:00,704 --> 00:14:03,550 就是持续不断地改进结果 and the way I find it is that I keep improving it. 230 00:14:03,712 --> 00:14:09,800 求取不动点的方法有很多 Now, that's a particular case of another kind of strategy 231 00:14:10,528 --> 00:14:12,780 这种方法只是其中的一个特例 for finding a fixed point of something. 232 00:14:14,128 --> 00:14:16,140 每个函数都有一个不动点 So you have a fixed point of a function. 233 00:14:16,688 --> 00:14:25,580 函数的不动点是一个值 A fixed point of a function is something, is a value. 234 00:14:25,680 --> 00:14:31,340 F的不动点Y满足F(Y)=Y A fixed point of a function F is a value Y, such that F of Y equals Y. 235 00:14:32,528 --> 00:14:40,448 首先要做是做出一个猜测 And the way I might do that is start with a guess. 236 00:14:41,552 --> 00:14:45,408 在迭代函数F时不会改变的东西则是我们所求的结果 And then if I want something that doesn't change when I keep applying F, 237 00:14:45,510 --> 00:14:49,008 我会不断迭代函数F直到结果不会有很大改变 is I'll keep applying F over and over until that result doesn't change very much. 238 00:14:49,600 --> 00:14:51,480 这就是一个通法 So there's a general strategy. 239 00:14:51,792 --> 00:14:55,728 因此 为了计算X的平方根 And then, for example, to compute the square root of X, 240 00:14:55,792 --> 00:15:03,000 我可以试着找到Y与X/Y的平均值函数的不动点 I can try and find a fixed point of the function which takes Y to the average of X/Y. 241 00:15:03,104 --> 00:15:07,072 因为如果我真有一个等于X平方根的Y And the idea that is that if I really had Y equal to the square root of X, 242 00:15:07,568 --> 00:15:11,350 那么Y和X/Y应为同一值 then Y and X/Y would be the same value. 243 00:15:11,552 --> 00:15:13,450 它们俩都是X的平方根 They'd both be the square root of X, 244 00:15:14,416 --> 00:15:18,400 因为X除根号X得根号X because X over the square root of X is the square root of X. 245 00:15:18,640 --> 00:15:21,390 如果平均值Y等于X的平方根 And so the average if Y were equal to the square of X, 246 00:15:21,808 --> 00:15:24,760 那么这个平均值就不会改变 then the average wouldn't change. 247 00:15:25,536 --> 00:15:28,480 因此X的平方根即是某一特定函数的不动点 So the square root of X is a fixed point of that particular function. 248 00:15:29,648 --> 00:15:33,408 现在 我将要描述 Now, what I'd like to have, I'd like to express 249 00:15:33,536 --> 00:15:35,970 寻找不动点的通法 the general strategy for finding fixed points. 250 00:15:36,128 --> 00:15:39,680 我所希望做的就是 So what I might imagine doing, is to find, 251 00:15:40,576 --> 00:15:46,000 用我自己的语言定义一个可以获得不动点的“盒子” is to be able to use my language to define a box that says "fixed point," 252 00:15:49,136 --> 00:15:51,740 正如我可以定义一个输出平方根的盒子一样 just like I could make a box that says "square root." 253 00:15:51,760 --> 00:15:54,736 我想要用自己的语言来表述 And I'd like to be able to express this in my language. 254 00:15:55,632 --> 00:16:00,928 因此 对于这种“怎么做”的指令性知识 So I'd like to express not only the imperative how-to knowledge 255 00:16:00,976 --> 00:16:02,768 我不仅是想表达具体应该如何求平方根 of a particular thing like square root, 256 00:16:03,136 --> 00:16:05,152 我也希望能够表述更加通用问题 but I'd like to be able to express the imperative knowledge 257 00:16:05,216 --> 00:16:07,820 例如 怎么求取不动点 of how to do a general thing like how to find fixed point. 258 00:16:09,376 --> 00:16:11,808 让我们再回过头来看看之前的幻灯片 And in fact, let's go back and look at that slide again. 259 00:16:14,576 --> 00:16:22,832 不但如何去求取一个不动点 See, not only is this a piece of imperative knowledge, 260 00:16:22,880 --> 00:16:24,870 是一种指令性知识 how to find a fixed point, 261 00:16:25,808 --> 00:16:26,944 在这下面 这里 but over here on the bottom, 262 00:16:26,976 --> 00:16:29,870 这儿还有另一种指令性知识 说的是 there's another piece of imperative knowledge which says, 263 00:16:29,968 --> 00:16:35,400 计算平方根的一种方法就是应用找不动点的方法 one way to compute square root is to apply this general fixed point method. 264 00:16:35,728 --> 00:16:38,440 如果 也想要表述这种指令性知识 So I'd like to also be able to express that imperative knowledge. 265 00:16:39,296 --> 00:16:40,256 那结果会是什么样呢? What would that look like? 266 00:16:40,288 --> 00:16:44,450 这个不动点盒子可能会是这样 That would say, this fixed point box is such that 267 00:16:45,310 --> 00:16:57,760 如果我输入一个函数 该函数从Y映射到Y和X/Y的平均值 if I input to it the function that takes Y to the average of Y and X/Y, 268 00:16:59,328 --> 00:17:05,780 然后我们将会得到求不动点的盒子就是求平方根的一个方法 then what should come out of that fixed point box is a method for finding square roots. 269 00:17:08,464 --> 00:17:09,792 因此在这些我们构建的盒子中 So in these boxes we're building, 270 00:17:09,824 --> 00:17:14,624 输入和输出都不局限于数字 we're not only building boxes that you input numbers and output numbers, 271 00:17:15,952 --> 00:17:18,090 我们将要构建能够 we're going to be building in boxes that, 272 00:17:18,220 --> 00:17:20,896 找到平方根计算方法的盒子 in effect, compute methods like finding square root. 273 00:17:21,776 --> 00:17:25,408 我输入的是一个函数 And my take is their inputs functions, 274 00:17:26,048 --> 00:17:28,840 比如Y映射到Y和X/Y的平均值的函数 like Y goes to the average of Y and X/Y. 275 00:17:29,264 --> 00:17:31,040 我们之所以采用这种方式是希望 The reason we want to do that, 276 00:17:31,760 --> 00:17:35,152 输入是一个过程 输出也是一个过程 the reason this is a procedure, will end up being a procedure, 277 00:17:35,184 --> 00:17:38,160 如我们所见 一个过程输出了另一个过程 as we'll see, whose value is another procedure, 278 00:17:38,864 --> 00:17:40,650 之所以这样做是因为 the reason we want to do that is because 279 00:17:41,072 --> 00:17:45,820 我们将通过程序来讨论指令性知识 procedures are going to be our ways of talking about imperative knowledge. 280 00:17:47,552 --> 00:17:49,488 这种处理方式很强大 And the way to make that very powerful is 281 00:17:49,488 --> 00:17:51,680 我们将可以基于此来讨论其它类型的知识 to be able to talk about other kinds of knowledge. 282 00:17:52,976 --> 00:17:56,070 实际上 我们讨论的是一种生成过程的过程 So here is a procedure that, in effect, talks about another procedure, 283 00:17:56,656 --> 00:17:59,890 一种生成通法的通法 a general strategy that itself talks about general strategies. 284 00:18:03,120 --> 00:18:07,790 那么 我们将主要讨论三个主题的内容 Well, our first topic in this course-- 285 00:18:07,808 --> 00:18:09,248 而首个主题则是 there'll be three major topics-- 286 00:18:09,296 --> 00:18:10,496 黑盒抽象 will be black-box abstraction. 287 00:18:10,528 --> 00:18:12,864 让我们稍稍深入一点 Let's look at that in a little bit more detail. 288 00:18:14,672 --> 00:18:23,590 我们将讨论 What we're going to do is we will start out talking about 289 00:18:23,632 --> 00:18:26,270 Lisp是如何通过基本对象建立起来的 how Lisp is built up out of primitive objects. 290 00:18:26,912 --> 00:18:28,750 以及Lisp的构成 What does the language supply with us? 291 00:18:29,040 --> 00:18:33,136 接下来 将会涉及到一些基本过程和基础数据 And we'll see that there are primitive procedures and primitive data. 292 00:18:35,712 --> 00:18:36,592 然后我们将会看到 Then we're going to see, 293 00:18:36,608 --> 00:18:38,320 我们如何使用这些基本对象 how do you take those primitives and 294 00:18:38,368 --> 00:18:40,310 并把它们组合起来构建更复杂的东西 combine them to make more complicated things, 295 00:18:41,008 --> 00:18:42,470 及相应的组合方法 means of combination? 296 00:18:42,752 --> 00:18:45,850 后续将讨论各种进行组合的方法以及 And what we'll see is that there are ways of putting things together, 297 00:18:46,000 --> 00:18:50,032 如何用基本过程来构建更复杂的过程 putting primitive procedures together to make more complicated procedures. 298 00:18:50,512 --> 00:18:53,980 同时 我们也将看到如何将基本数据组合成复合数据 And we'll see how to put primitive data together to make compound data. 299 00:18:55,760 --> 00:18:58,896 然后我们将会介绍如何对复合数据 Then we'll say, well, having made those compounds things, 300 00:18:59,344 --> 00:19:00,848 如何将它们抽象出来 how do you abstract them? 301 00:19:02,464 --> 00:19:04,528 如何用黑盒对它们进行封装 How do you put those black boxes around them 302 00:19:04,592 --> 00:19:07,280 使得你可以将它们作为组件用于更复杂的东西 so you can use them as components in more complex things? 303 00:19:07,712 --> 00:19:10,480 我们会发现这些都是通过定义程序 And we'll see that's done by defining procedures and 304 00:19:11,072 --> 00:19:14,340 以及一种处理复合数据的数据抽象技术完成的 a technique for dealing with compound data called data abstraction. 305 00:19:15,168 --> 00:19:16,910 最重要的是 And then, what's maybe the most important thing, 306 00:19:17,472 --> 00:19:21,040 我们可以从中了解到专家是如何工作的 is going from just the rules to how does an expert work? 307 00:19:21,168 --> 00:19:26,672 对于找不动点的方法来讲 How do you express common patterns of doing things, like saying, well, 308 00:19:26,704 --> 00:19:28,192 找平方根的方式是它的一个特例 there's a general method of fixed point and 309 00:19:28,240 --> 00:19:30,420 你如何表述完成工作中所存在的通用模式呢? square root is a particular case of that? 310 00:19:31,456 --> 00:19:33,968 我们将会使用 And we're going to use-- 311 00:19:34,144 --> 00:19:35,184 之前已经提到过的 I've already hinted at it-- 312 00:19:35,216 --> 00:19:36,850 某种叫做高阶过程的东西 something called higher-order procedures, 313 00:19:36,896 --> 00:19:41,600 也就是说 它的输入、输出和它本身都是过程 namely procedures whose inputs and outputs are themselves procedures. 314 00:19:42,512 --> 00:19:44,416 我们将会看到一些有趣的东西 And then we'll also see something very interesting. 315 00:19:44,416 --> 00:19:48,040 随着学习的深入 将会越发抽象 We'll see, as we go further and further on and become more abstract, 316 00:19:48,352 --> 00:19:49,860 那么将会发现 there'll be very-- 317 00:19:49,980 --> 00:19:53,168 我们认为是数据和我们认为是过程之间的 well, the line between what we consider to be data and 318 00:19:53,184 --> 00:19:57,350 分界线将变得模糊到难以置信的程度 what we consider to be procedures is going to blur at an incredible rate. 319 00:20:02,448 --> 00:20:06,670 这便是我们的第一个主题 黑盒抽象 Well, that's our first subject, black-box abstraction. 320 00:20:06,672 --> 00:20:08,170 让我们来看看第二个主题 Let's look at the second topic. 321 00:20:10,656 --> 00:20:13,430 这样说吧 I can introduce it like this. 322 00:20:13,440 --> 00:20:17,640 假设我想表达某个想法 See, suppose I want to express the idea-- 323 00:20:18,976 --> 00:20:22,064 请注意 我们讨论的是想法 remember, we're talking about ideas-- 324 00:20:22,464 --> 00:20:25,088 比如说 suppose I want to express the idea that 325 00:20:25,968 --> 00:20:34,672 我想将某个元素与另两个元素之和相乘 I can take something and multiply it by the sum of two other things. 326 00:20:35,648 --> 00:20:37,480 举例来说 So for example, I might say, 327 00:20:37,664 --> 00:20:41,070 我用1和3(之和)乘2 得8 if I had 1 and 3 and multiply that by 2, I get 8. 328 00:20:41,584 --> 00:20:44,660 但我这里想讨论的是关于线性组合的基本想法 But I'm talking about the general idea of what's called linear combination, 329 00:20:44,992 --> 00:20:47,530 是说你可以将两个元素的和乘以另一个元素 that you can add two things and multiply them by something else. 330 00:20:48,832 --> 00:20:50,560 在数集内思考这个问题是很容易的 It's very easy when I think about it for numbers, 331 00:20:50,608 --> 00:20:54,960 但假设我想将这个想法应用于 but suppose I also want to use that same idea to think about, 332 00:20:55,632 --> 00:20:58,130 对两向量a1和a2相加 I could add two vectors, a1 and a2, 333 00:20:59,440 --> 00:21:02,816 乘以某一因子x然后得到另一向量 and then scale them by some factor x and get another vector. 334 00:21:02,880 --> 00:21:09,300 我甚至可以说 若a1和a2皆为多项式 Or I might say, I want to think about a1 and a2 as being polynomials, 335 00:21:10,620 --> 00:21:13,456 我想对这两个多项式求和 and I might want to add those two polynomials and 336 00:21:13,472 --> 00:21:16,416 然后乘以2得到一个多项式 then multiply them by 2 to get a more complicated one. 337 00:21:19,710 --> 00:21:23,380 同理 a1或a2也可以是电信号 Or a1 and a2 might be electrical signals, 338 00:21:24,110 --> 00:21:27,328 我想将二个信号加和 and I might want to think about summing those two electrical signals and 339 00:21:27,360 --> 00:21:29,824 并将结果放入一个放大器 then putting the whole thing through an amplifier, 340 00:21:29,824 --> 00:21:29,830 用一个类似于2的因子乘以它们 multiplying it by some factor of 2 or something. 并将结果放入一个放大器 then putting the whole thing through an amplifier, 341 00:21:29,830 --> 00:21:32,580 用一个类似于2的因子乘以它们 multiplying it by some factor of 2 or something. 342 00:21:33,376 --> 00:21:36,480 这种想法的基本点是 我希望用一个通用记号表示它们 The idea is I want to think about the general notion of that. 343 00:21:37,872 --> 00:21:44,976 假如我们的语言可以很好的表述这类想法 Now, if our language is going to be good language for expressing those kind of general ideas, 344 00:21:46,624 --> 00:21:48,864 如果真可以这样的话 if I really, really can do that, 345 00:21:50,208 --> 00:21:51,648 我将会以这样的方式表述 I'd like to be able to say 346 00:21:54,544 --> 00:21:59,960 用x乘以a1和a2的和 I'm going to multiply by x the sum of a1 and a2, 347 00:22:02,352 --> 00:22:04,624 更进一步 我希望做更抽象更基本的表述 and I'd like that to express the general idea of 348 00:22:05,584 --> 00:22:08,784 使其可以适应各个不同类型的a1和a2 all different kinds of things that a1 and a2 could be. 349 00:22:09,584 --> 00:22:11,136 现在回过头来想想 似乎有点问题 Now, if you think about that, there's a problem, 350 00:22:11,136 --> 00:22:15,728 毕竟 对两个数字和两个多项式进行加和运算 because after all, the actual primitive operations 351 00:22:15,760 --> 00:22:17,888 所用的基本操作 that go on in the machine are obviously going to be different 352 00:22:17,936 --> 00:22:22,530 在机器内部显然是不同的 if I'm adding two numbers than if I'm adding two polynomials, 353 00:22:22,848 --> 00:22:27,040 对两个电信号或声波加和也有同样的问题 or if I'm adding the representation of two electrical signals or wave forms. 354 00:22:27,440 --> 00:22:32,080 无论怎样 对不同类型的元素进行求和运算 Somewhere, there has to be the knowledge of the kinds of various things 355 00:22:32,420 --> 00:22:33,808 总是需要使用不同的方法 that you can add and the ways of adding them. 356 00:22:36,640 --> 00:22:38,192 现在 为了构建这样一个系统 Now, to construct such a system, 357 00:22:38,336 --> 00:22:40,224 我们将如何使用这些知识呢? the question is, where do I put that knowledge? 358 00:22:40,752 --> 00:22:43,968 如何在各种方法中进行选择? How do I think about the different kinds of choices I have? 359 00:22:44,112 --> 00:22:47,970 而如果明天George又想出了一种新类型的对象 And if tomorrow George comes up with a new kind of object 360 00:22:48,000 --> 00:22:49,872 并将它用于加和以及乘积 that might be added and multiplied, 361 00:22:50,560 --> 00:22:52,870 我又该如何把这个新类型引入到系统中 how do I add George's new object to the system 362 00:22:53,072 --> 00:22:55,230 而且能够做到不把已有的系统弄得一团糟? without screwing up everything that was already there? 363 00:22:57,360 --> 00:23:00,096 这便是我们的第二大主题 Well, that's going to be the second big topic, 364 00:23:00,128 --> 00:23:02,710 控制复杂度的方法 the way of controlling that kind of complexity. 365 00:23:03,392 --> 00:23:07,980 我们实现的方法是按照约定来实现相应的接口 And the way you do that is by establishing conventional interfaces, 366 00:23:16,992 --> 00:23:19,760 并以此将各部分组合起来 agreed upon ways of plugging things together. 367 00:23:19,808 --> 00:23:21,590 就如同电气工程中 Just like in electrical engineering, 368 00:23:22,496 --> 00:23:24,944 人们为连接器规定标准阻抗 people have standard impedances for connectors, 369 00:23:25,712 --> 00:23:28,176 如果用符合这个标准的东西来构建系统 and then you know if you build something with one of those standard impedances, 370 00:23:28,224 --> 00:23:29,952 你就知道你可以把各个部件组合在一起 you can plug it together with something else. 371 00:23:32,336 --> 00:23:35,230 这就是我们将要讨论的第二个主题:约定接口 So that's going to be our second large topic, conventional interfaces. 372 00:23:35,280 --> 00:23:40,496 如我之前提到的 What we're going to see is, first, we're going to talk about the problem of generic operations, 373 00:23:40,528 --> 00:23:41,776 接下来我们将讨论通用操作中的问题 which is the one I alluded to, 374 00:23:42,144 --> 00:23:46,832 例如对各种不同类型数据进行均适用的加法操作 things like "plus" that have to work with all different kinds of data. 375 00:23:52,160 --> 00:23:54,128 随后则会讨论通用操作 So we talk about generic operations. 376 00:23:54,160 --> 00:23:56,544 然后我们将讨论大型架构问题 Then we're going to talk about really large-scale structures. 377 00:23:57,872 --> 00:24:00,380 如果通过对现实世界的复杂系统建模 How do you put together very large programs 378 00:24:00,576 --> 00:24:04,440 来构建大型程序 that model the kinds of complex systems in the real world that you'd like to model? 379 00:24:05,088 --> 00:24:06,080 我们将看到 在构建这样的系统时 And what we're going to see is that 380 00:24:06,128 --> 00:24:11,360 有两种非常重要的方法 there are two very important metaphors for putting together such systems. 381 00:24:11,408 --> 00:24:13,456 其一是面向对象编程 One is called object-oriented programming, 382 00:24:13,648 --> 00:24:18,496 在这种模式中 你把你的系统想象成一个社区 where you sort of think of your system as a kind of society 383 00:24:18,928 --> 00:24:21,910 社区中的各个部分都是通过相互间传递消息联系起来的 full of little things that interact by sending information between them. 384 00:24:22,992 --> 00:24:27,360 其二是关于聚集的操作 称作“流” And then the second one is operations on aggregates, called streams, 385 00:24:27,536 --> 00:24:31,056 使用这种方式构建大型系统 where you think of a large system put together kind of 386 00:24:31,056 --> 00:24:34,840 类似于电气工程师构造大型电气系统 like a signal processing engineer puts together a large electrical system. 387 00:24:38,480 --> 00:24:40,048 这就是我们的第二个话题 That's going to be our second topic. 388 00:24:42,928 --> 00:24:45,488 现在 我们将要讨论第三个话题 Now, the third thing we're going to come to, 389 00:24:45,504 --> 00:24:49,250 控制复杂度的第三个技术 the third basic technique for controlling complexity, 390 00:24:49,296 --> 00:24:50,496 便是定义新的语言 is making new languages. 391 00:24:51,248 --> 00:24:54,976 因为有时 当你有点受不了设计的复杂度时 Because sometimes, when you're sort of overwhelmed by the complexity of a design, 392 00:24:55,024 --> 00:24:59,240 你可以通过定义一门新的语言来控制系统复杂度 the way that you control that complexity is to pick a new design language. 393 00:25:00,960 --> 00:25:05,152 新语言的设计意图是为了强调系统的某个方面 And the purpose of the new design language will be to highlight different aspects of the system. 394 00:25:05,344 --> 00:25:08,912 它一方面隐藏了部分细节 另一方面则但强调一些其他的细节 It will suppress some kinds of details and emphasize other kinds of details. 395 00:25:12,544 --> 00:25:15,488 这部分将是课程中最神奇的部分 This is going to be the most magical part of the course. 396 00:25:15,584 --> 00:25:20,750 我们将开始于构建新的计算机语言 We're going to start out by actually looking at the technology for building new computer languages. 397 00:25:21,376 --> 00:25:25,850 实际上我们首先要完成的工作已经内建于Lisp之中了 The first thing we're going to do is actually build in Lisp. 398 00:25:28,784 --> 00:25:33,570 我们将展现如何用Lisp来解释Lisp We're going to express in Lisp the process of interpreting Lisp itself. 399 00:25:33,840 --> 00:25:36,496 这是一个非常类似于自循环的过程 And that's going to be a very sort of self-circular thing. 400 00:25:36,510 --> 00:25:39,472 这与(Lisp中)一个神奇的符号有关 There's a little mystical symbol that has to do with that. 401 00:25:40,528 --> 00:25:45,936 解释Lisp的步骤是 The process of interpreting Lisp is sort of a giant wheel of two processes, 402 00:25:46,128 --> 00:25:47,264 应用和求值——这两大步骤的轮转 apply and eval, 403 00:25:47,440 --> 00:25:50,420 这两者不断地互相交替进行 which sort of constantly reduce expressions to each other. 404 00:25:52,096 --> 00:25:53,792 接下来 我们将看到其余神奇的东西 Then we're going to see all sorts of other magical things. 405 00:25:53,808 --> 00:25:56,400 譬如另一种魔法符号 Here's another magical symbol. 406 00:25:56,672 --> 00:26:01,070 一种叫做Y运算符的东西 This is sort of the Y operator, 407 00:26:01,100 --> 00:26:06,000 某种意义上 它在过程式语言中用于 表达无限 which is, in some sense, the expression of infinity inside our procedural language. 408 00:26:06,064 --> 00:26:06,992 我们也会谈论到它 We'll take a look at that. 409 00:26:07,952 --> 00:26:13,280 总之 这部分课程被称作“元语言抽象” In any case, this section of the course is called Metalinguistic Abstraction, 410 00:26:15,728 --> 00:26:25,780 主要讨论如何构建一门新语言 abstracting by talking about how you construct new languages. 411 00:26:29,776 --> 00:26:35,264 如我所言 我们将从了解解释的过程开始 As I said, we're going to start out by looking at the process of interpretation. 412 00:26:35,296 --> 00:26:41,670 随后则一起讨论应用-求值循环和构建Lisp We're going to look at this apply-eval loop, and build Lisp. 413 00:26:41,712 --> 00:26:43,720 你将发现这种方法具有相当的普遍性 Then, just to show you that this is very general, 414 00:26:43,920 --> 00:26:47,810 我们将用同样的技术去构建一门全完不同的语言 we're going to use exactly the same technology to build a very different kind of language, 415 00:26:48,080 --> 00:26:49,860 一种所谓的逻辑编程语言 a so-called logic programming language, 416 00:26:50,080 --> 00:26:54,380 一种无关具有输入和输出的过程 where you don't really talk about procedures at all that have inputs and outputs. 417 00:26:54,416 --> 00:26:56,800 而仅关注元素之间关系的语言 What you do is talk about relations between things. 418 00:26:56,864 --> 00:27:03,470 最终 我们将讨论如何将这些东西 And then finally, we're going to talk about how you implement these things very concretely 419 00:27:03,504 --> 00:27:05,152 实实在在的实现在简单的机器上 on the very simplest kind of machines. 420 00:27:05,200 --> 00:27:07,940 比如说这个 We'll see something like this. 421 00:27:08,688 --> 00:27:11,690 如图所示的芯片 This is a picture of a chip, 422 00:27:11,712 --> 00:27:17,024 就是我们在硬件部分谈及的Lisp解释器 which is the Lisp interpreter that we will be talking about then in hardware. 423 00:27:20,432 --> 00:27:23,340 这三大主题就是本课的提纲 Well, there's an outline of the course, three big topics. 424 00:27:24,432 --> 00:27:28,960 黑盒抽象 约定接口 元语言抽象 Black-box abstraction, conventional interfaces, metalinguistic abstraction. 425 00:27:31,136 --> 00:27:33,120 好 先休息一会儿 然后正式开始 Now, let's take a break now and then we'll get started. 426 00:27:51,744 --> 00:28:02,976 [音乐] [JESU, JOY OF MAN'S DESIRING] 427 00:28:03,472 --> 00:28:06,390 现在让我们正式开始学习Lisp Let's actually start in learning Lisp now. 428 00:28:07,616 --> 00:28:10,304 事实上 我们将开始学习一些非常重要的内容 Actually, we'll start out by learning something much more important, 429 00:28:10,352 --> 00:28:13,888 在这门课程中最重要的 不是Lisp本身 maybe the very most important thing in this course, which is not Lisp, 430 00:28:13,936 --> 00:28:17,960 而是一种的通用框架体系 in particular, of course, but rather a general framework 431 00:28:18,176 --> 00:28:21,440 我们用它来组织我之前提到的语言 for thinking about languages that I already alluded to. 432 00:28:21,671 --> 00:28:24,650 当有人要向你展示一门新语言 When somebody tells you they're going to show you a language, 433 00:28:24,688 --> 00:28:25,712 你应该问他 what you should say is, 434 00:28:25,744 --> 00:28:32,420 (构成语言的)基本元素有哪些? what I'd like you to tell me is what are the primitive elements? 435 00:28:37,056 --> 00:28:38,330 这门语言使用哪些基本元素? What does the language come with? 436 00:28:38,512 --> 00:28:43,088 你是如何将这些元素组合在一起的? Then, what are the ways you put those together? 437 00:28:43,232 --> 00:28:46,976 组合的方法是什么? What are the means of combination? 438 00:28:49,728 --> 00:28:53,730 允许你将这些基本元素整合在一起 What are the things that allow you to take these primitive elements 439 00:28:53,920 --> 00:28:56,064 以构建更大的对象的又是什么? and build bigger things out of them? 440 00:28:57,568 --> 00:28:59,168 把东西构建在一起的方法是什么? What are the ways of putting things together? 441 00:29:00,944 --> 00:29:05,248 以及 抽象的方法是什么? And then, what are the means of abstraction? 442 00:29:07,904 --> 00:29:16,400 我们如何利用这些元素并把它们封装成盒子? How do we take those complicated things and draw those boxes around them? 443 00:29:16,432 --> 00:29:19,216 我们如何为它们命名使得我们可以 How do we name them so that we can now use them 444 00:29:19,232 --> 00:29:23,408 把它们当作基本元素来用于构建更复杂的东西? as if they were primitive elements in making still more complex things? 445 00:29:23,440 --> 00:29:25,216 等等 等等 等等 And so on, and so on, and so on. 446 00:29:26,448 --> 00:29:27,632 因此 当有人告诉你 So when someone says to you, gee, 447 00:29:27,648 --> 00:29:29,104 嘿 我发明了一种新的计算机语言 I have a great new computer language, 448 00:29:30,416 --> 00:29:34,256 你不应该问 用你的语言编写求逆矩阵需要多少代码 you don't say, how many characters does it take to invert a matrix? 449 00:29:35,280 --> 00:29:36,432 这是风马牛不相及的 It's irrelevant. 450 00:29:36,944 --> 00:29:41,850 如果该语言没有内建了矩阵或者类似的东西 What you say is, if the language did not come with matrices built in 451 00:29:41,888 --> 00:29:42,928 那你就应该问他 or with something else built in, 452 00:29:42,928 --> 00:29:45,584 应该如何构建矩阵? how could I then build that thing? 453 00:29:45,600 --> 00:29:48,020 如何通过组合来构建? What are the means of combination which would allow me to do that? 454 00:29:48,176 --> 00:29:50,260 如何对其进行抽象 And then, what are the means of abstraction 455 00:29:51,232 --> 00:29:53,760 把它作为基本元素 which allow me then to use those as elements 456 00:29:53,776 --> 00:29:56,070 来构建更复杂的东西? in making more complicated things yet? 457 00:29:58,304 --> 00:30:04,160 我们将了解到Lisp的一些基本数据和基本过程 Well, we're going to see that Lisp has some primitive data and some primitive procedures. 458 00:30:04,800 --> 00:30:07,056 好吧 这次是真的开始了 In fact, let's really start. 459 00:30:07,104 --> 00:30:14,448 这里有一个Lisp的基本数据 数字3 And here's a piece of primitive data in Lisp, number 3. 460 00:30:15,824 --> 00:30:19,420 事实上 如果打破沙锅问到底的话 这不是数字3 Actually, if I'm being very pedantic, that's not the number 3. 461 00:30:19,488 --> 00:30:25,120 这只是一个符号 用以代表柏拉图观念下的数字3的 That's some symbol that represents Plato's concept of the number 3. 462 00:30:26,224 --> 00:30:28,480 这又是另一个 And here's another. 463 00:30:30,032 --> 00:30:35,616 这个是Lisp中又一个基本数据 17.4 Here's some more primitive data in Lisp, 17.4. 464 00:30:35,632 --> 00:30:38,976 又或者说 代表17.4 Or actually, some representation of 17.4. 465 00:30:40,544 --> 00:30:44,032 这儿还有一个5 And here's another one, 5. 466 00:30:46,416 --> 00:30:51,760 然后这儿又有一个内建于Lisp的基本对象“+” Here's another primitive object that's built in Lisp, addition. 467 00:30:51,808 --> 00:30:55,232 如果又要继续深究的话 Actually, to use the same kind of pedantic-- 468 00:30:55,264 --> 00:31:00,020 这只是一个名字 代表对元素进行加和的基本方法而已 this is a name for the primitive method of adding things. 469 00:31:00,080 --> 00:31:02,080 就像这个是柏拉图式的3 Just like this is a name for Plato's number 3, 470 00:31:02,160 --> 00:31:08,870 这也只是一个代表柏拉图观念下的将某些元素加和起来 this is a name for Plato's concept of how you add things. 471 00:31:09,872 --> 00:31:11,530 这些都是基本元素 So those are some primitive elements. 472 00:31:11,696 --> 00:31:13,310 我可以将它们放在一起 I can put them together. 473 00:31:13,696 --> 00:31:17,840 我可以说 3加17.4加5的和是多少 I can say, gee, what's the sum of 3 and 17.4 and 5? 474 00:31:18,240 --> 00:31:20,864 这等同于说 And the way I do that is to say, 475 00:31:20,880 --> 00:31:27,264 让我们把求和运算符应用于这三个数 let's apply the sum operator to these three numbers. 476 00:31:27,296 --> 00:31:30,700 我可以得到什么呢 是8 是17 还是25.4 And I should get, what? 8, 17. 25.4. 477 00:31:33,984 --> 00:31:37,600 因此 我可以问Lisp这个的值是多少 So I should be able to ask Lisp what the value of this is, 478 00:31:38,496 --> 00:31:40,320 (表达式)返回25.4 and it will return 25.4. 479 00:31:43,136 --> 00:31:44,384 介绍一些术语吧 Let's introduce some names. 480 00:31:44,432 --> 00:31:51,024 我所写的这些东西就叫做组合式 This thing that I typed is called a combination. 481 00:31:56,432 --> 00:32:01,490 通常 一个组合式是由运算符 And a combination consists, in general, of applying an operator-- 482 00:32:02,944 --> 00:32:04,272 这些就是运算符 so this is an operator-- 483 00:32:09,264 --> 00:32:11,600 和应用该运算符的运算对象组成 to some operands. 484 00:32:12,800 --> 00:32:14,096 这些是运算对象 These are the operands. 485 00:32:21,440 --> 00:32:23,340 当然 我可以完成更复杂的事 And of course, I can make more complex things. 486 00:32:23,376 --> 00:32:28,110 我可以使之更复杂是因为 这些运算对象 The reason I can get complexity out of this is because the operands themselves, 487 00:32:29,072 --> 00:32:30,640 通常来说 也可以是组合式 in general, can be combinations. 488 00:32:30,704 --> 00:32:44,020 比如 3加上5乘以6乘以8乘以2的积的和是多少 So for instance, I could say, what is the sum of 3 and the product of 5 and 6 and 8 and 2? 489 00:32:45,216 --> 00:32:51,712 而我应该得到 我算一下 30 40 43 And I should get-- let's see-- 30, 40, 43. 490 00:32:52,288 --> 00:32:54,368 因此Lisp会返回这个表达式的值是43 So Lisp should tell me that that's 43. 491 00:32:56,112 --> 00:33:02,352 后续我们将看到构造组合式是组合的基本需求 Forming combinations is the basic needs of combination that we'll be looking at. 492 00:33:04,208 --> 00:33:08,770 你所看到的这些语法 And then, well, you see some syntax here. 493 00:33:10,112 --> 00:33:12,592 就是Lisp用的所谓的前缀表示法 Lisp uses what's called prefix notation, 494 00:33:15,776 --> 00:33:24,760 意即操作符在操作数的左端 which means that the operator is written to the left of the operands. 495 00:33:25,024 --> 00:33:26,032 这只是个约定 It's just a convention. 496 00:33:27,216 --> 00:33:29,320 注意 这些都被括起来了 And notice, it's fully parenthesized. 497 00:33:29,632 --> 00:33:31,872 这些括号使得它们区别开来 And the parentheses make it completely unambiguous. 498 00:33:31,872 --> 00:33:36,544 因此只要看看这个 我就可以知道这个是运算符 So by looking at this, I can see that there's the operator, 499 00:33:36,560 --> 00:33:40,540 以及这有1个 2个 3个 4个运算对象 and there are 1, 2, 3, 4 operands. 500 00:33:41,936 --> 00:33:47,520 而且我也可以发现第二个运算对象是个组合式 And I can see that the second operand here is itself some combination 501 00:33:48,432 --> 00:33:51,100 该组合式有一个运算符和两个运算对象 that has one operator and two operands. 502 00:33:51,984 --> 00:33:53,824 Lisp中的括号 有点或者非常不同于 Parentheses in Lisp are a little bit, 503 00:33:54,160 --> 00:33:57,260 通常数学中的括号 or are very unlike parentheses in conventional mathematics. 504 00:33:57,328 --> 00:33:59,664 数学中 我们常将其用于分组 In mathematics, we sort of use them to mean grouping, 505 00:34:00,768 --> 00:34:03,300 如果有时你忘了闭合括号 但其他人能理解你的意图 and it sort of doesn't hurt if sometimes you leave out parentheses 506 00:34:03,328 --> 00:34:05,110 这也无关紧要 if people understand that that's a group. 507 00:34:05,312 --> 00:34:08,064 通常的 你多加了括号也无所谓 And in general, it doesn't hurt if you put in extra parentheses, 508 00:34:08,416 --> 00:34:10,496 因为这样只会使得分组更加明确 because that maybe makes the grouping more distinct. 509 00:34:10,512 --> 00:34:11,328 Lisp可不像这样 Lisp is not like that. 510 00:34:12,672 --> 00:34:14,928 Lisp中你既不能不闭合括号 In Lisp, you cannot leave out parentheses, 511 00:34:15,936 --> 00:34:18,112 亦不能添加多余的括号 and you cannot put in extra parentheses, 512 00:34:18,880 --> 00:34:20,832 因为加括号总是意味着 because putting in parentheses always means, 513 00:34:20,928 --> 00:34:26,600 确切的来说 所括之物是一个组合式 exactly and precisely, this is a combination which has meaning, 514 00:34:26,640 --> 00:34:28,368 表示将运算符应用于运算对象 applying operators to operands. 515 00:34:28,592 --> 00:34:32,176 如果我不闭合这个括号 And if I left this out, if I left those parentheses out, 516 00:34:32,208 --> 00:34:33,510 这个就变成其它的意思了 it would mean something else. 517 00:34:34,960 --> 00:34:36,800 事实上 我们可以这么来理解这个问题 In fact, the way to think about this, 518 00:34:36,960 --> 00:34:41,200 把我写的这些东西想作一个树 is really what I'm doing when I write something like this is writing a tree. 519 00:34:41,920 --> 00:34:46,850 这个组合式实际上是一个树 树具有一个“+” So this combination is a tree that has a plus and 520 00:34:46,928 --> 00:34:54,016 以及 一个3和一些其它的东西和一个8 还有一个2 then a 3 and then a something else and an 8 and a 2. 521 00:34:54,032 --> 00:34:55,904 而这里的其它的东西 And then this something else here is 522 00:34:55,904 --> 00:35:02,770 它本身是一个有一个“*”一个5和一个6的子树 itself a little subtree that has a star and a 5 and a 6. 523 00:35:03,504 --> 00:35:05,088 我们可以这样认为 And the way to think of that is, really, 524 00:35:05,104 --> 00:35:08,550 我们只是在构建这些树而已 what's going on are we're writing these trees, 525 00:35:08,768 --> 00:35:14,656 括号只是将这种二维结构写作线性字符串 and parentheses are just a way to write this two-dimensional structure 526 00:35:15,344 --> 00:35:16,896 的一种方法罢了 as a linear character string. 527 00:35:18,784 --> 00:35:23,360 因为至少在Lisp发明时 人们还在用电传打字机或者打孔卡 Because at least when Lisp first started and people had teletypes or punch cards or whatever, 528 00:35:23,728 --> 00:35:25,150 这种记法方便多了 this was more convenient. 529 00:35:25,520 --> 00:35:30,070 如果Lisp是在当下被发明的 语法可能会像树那样 Maybe if Lisp started today, the syntax of Lisp would look like that. 530 00:35:31,312 --> 00:35:34,620 那么 让我们看看在计算机里面它究竟是什么样 Well, let's look at what that actually looks like on the computer. 531 00:35:35,840 --> 00:35:38,928 这里有个Lisp解释套件 Here I have a Lisp interaction set up. 532 00:35:38,960 --> 00:35:39,984 这是个编辑器 There's a editor. 533 00:35:40,688 --> 00:35:44,410 我将要在上方写一些表达式并让Lisp对其求值 And on the top, I'm going to type some values and ask Lisp what they are. 534 00:35:44,672 --> 00:35:46,300 比如 我可以问Lisp So for instance, I can say to Lisp, 535 00:35:46,384 --> 00:35:48,080 这个符号的值是多少 what's the value of that symbol? 536 00:35:48,992 --> 00:35:50,050 我键入3 That's 3. 537 00:35:50,128 --> 00:35:51,750 然后叫Lisp对其求值 And I ask Lisp to evaluate it. 538 00:35:51,872 --> 00:35:54,320 然后你就会看到Lisp在下面返回了一些信息 And there you see Lisp has returned on the bottom, 539 00:35:54,944 --> 00:35:56,390 这个值就是3 and said, oh yeah, that's 3. 540 00:35:57,136 --> 00:36:04,510 我也可以问 3加上4加上8的和是多少 Or I can say, what's the sum of 3 and 4 and 8? 541 00:36:06,000 --> 00:36:07,600 键入这个组合式 What's that combination? 542 00:36:08,480 --> 00:36:10,210 让Lisp对其求值 And ask Lisp to evaluate it. 543 00:36:14,048 --> 00:36:15,232 返回15 That's 15. 544 00:36:16,128 --> 00:36:18,352 我可以键入一些更复杂的东西 Or I can type in something more complicated. 545 00:36:18,800 --> 00:36:33,690 将3乘以7加19.5的和的乘积求和得多少 I can say, what's the sum of the product of 3 and the sum of 7 and 19.5? 546 00:36:34,768 --> 00:36:37,552 你会发现Lisp内建了一些功能 And you'll notice here that Lisp has something built in 547 00:36:37,568 --> 00:36:39,312 帮你跟踪这些括号 that helps me keep track of all these parentheses. 548 00:36:39,328 --> 00:36:41,680 看我键入下一个右圆括号 Watch as I type the next closed parentheses, 549 00:36:41,760 --> 00:36:44,560 用于闭合以“*”开头的那个组合式 which is going to close the combination starting with the star. 550 00:36:45,072 --> 00:36:46,850 开头的那个左括号会闪一下 The opening one will flash. 551 00:36:47,312 --> 00:36:49,240 我把这些括号擦去 再示范一次 Here, I'll rub those out and do it again. 552 00:36:49,696 --> 00:36:52,250 键入右括号 闭合了“+”组合式 Type close, and you see that closes the plus. 553 00:36:53,136 --> 00:36:55,968 再键入右括号 闭合了“*”组合式 Close again, that closes the star. 554 00:36:57,456 --> 00:37:00,310 现在我又回到了加 我将它们与4相加 Now I'm back to the sum, and maybe I'm going to add that all to 4. 555 00:37:01,216 --> 00:37:02,240 闭合了“+”组合式 That closes the plus. 556 00:37:02,288 --> 00:37:06,624 现在我补全了组合式 然后我问Lisp它们的值是多少 Now I have a complete combination, and I can ask Lisp for the value of that. 557 00:37:06,816 --> 00:37:11,216 这种内建于各种Lisp系统的 That kind of paren balancing is something that's built into 558 00:37:11,312 --> 00:37:12,840 括号匹配工具帮你跟进(括号匹配) a lot of Lisp systems to help you keep track, 559 00:37:12,912 --> 00:37:16,100 因为手工闭合这些括号太辛苦了 because it is kind of hard just by hand doing all these parentheses. 560 00:37:16,368 --> 00:37:20,752 这又是另外一种保持括号跟进的约定 There's another kind of convention for keeping track of parentheses. 561 00:37:20,800 --> 00:37:23,232 我另外写一个复杂的组合式 Let me write another complicated combination. 562 00:37:24,320 --> 00:37:33,552 将3和5的积与某个元素求和 Let's take the sum of the product of 3 and 5 and add that to something. 563 00:37:33,584 --> 00:37:34,784 现在我将要缩进 And now what I'm going to do is 564 00:37:34,832 --> 00:37:39,408 使得这些运算对象都是垂直书写的 I'm going to indent so that the operands are written vertically. 565 00:37:39,856 --> 00:37:45,200 将这些加上47乘以 Which the sum of that and the product of 47 and-- 566 00:37:46,576 --> 00:37:54,144 恩…… 47乘以20和6.8的差 let's say the product of 47 with a difference of 20 and 6.8. 567 00:37:54,176 --> 00:37:56,640 意即从20中减去6.8 That means subtract 6.8 from 20. 568 00:37:58,528 --> 00:37:59,744 然后 这个括号闭合了 And then you see the parentheses close. 569 00:37:59,776 --> 00:38:03,020 闭合“-” 闭合“*” Close the minus. Close the star. 570 00:38:03,312 --> 00:38:04,976 现在 我们再写一个运算符 And now let's get another operator. 571 00:38:04,992 --> 00:38:09,040 Lisp编辑器自动缩进到正确的位置 You see the Lisp editor here is indenting to the right position automatically 572 00:38:09,952 --> 00:38:11,056 来帮助我保持跟进 to help me keep track. 573 00:38:12,160 --> 00:38:13,648 我再示范一次 I'll do that again. 574 00:38:13,680 --> 00:38:15,440 这样就又闭合了最后一个括号 I'll close that last parentheses again. 575 00:38:15,808 --> 00:38:17,260 它匹配了这个“+”(的括号) You see it balances the plus. 576 00:38:19,952 --> 00:38:22,190 现在我想问 这个的值是多少 Now I can say, what's the value of that? 577 00:38:23,424 --> 00:38:28,832 因此 这两件事 缩进到正确的位置 So those two things, indenting to the right level, 578 00:38:28,864 --> 00:38:30,410 也就是所谓的美观的输出 which is called pretty printing, 579 00:38:31,104 --> 00:38:33,136 以及闭合提示 and flashing parentheses, 580 00:38:33,440 --> 00:38:37,280 是许多Lisp系统所内建用于帮你保持跟进的工具 are two things that a lot of Lisp systems have built in to help you keep track. 581 00:38:37,312 --> 00:38:38,560 你应该学习如何使用它们 And you should learn how to use them. 582 00:38:41,072 --> 00:38:42,720 好 这些都是基本的内容 Ok, those are the primitives. 583 00:38:44,288 --> 00:38:45,860 这就是一种组合的方法 There's a means of combination. 584 00:38:45,888 --> 00:38:47,488 现在让我们来看看抽象的方法 Now let's go up to the means of abstraction. 585 00:38:48,992 --> 00:38:53,390 我希望我能够写一些像这样的组合式 I'd like to be able to take the idea that I do some combination like this, 586 00:38:53,408 --> 00:38:55,320 将它抽象化并给它命名 and abstract it and give it a simple name, 587 00:38:55,360 --> 00:38:56,810 使得我可以将其作为一个(我们语言的)元素 so I can use that as an element. 588 00:38:56,864 --> 00:38:59,472 在Lisp中 我可以用“define”来实现 And I do that in Lisp with "define." 589 00:39:00,720 --> 00:39:01,980 比如说 So I can say, for example, 590 00:39:02,288 --> 00:39:14,608 定义A为5乘以5 define A to be the product of 5 and 5. 591 00:39:17,952 --> 00:39:21,904 现在我可以问Lisp And now I could say, for example, to Lisp, 592 00:39:21,936 --> 00:39:25,568 A和A的乘积是多少 what is the product of A and A? 593 00:39:26,736 --> 00:39:29,360 这个是25所以这个就是625 And this should be 25, and this should be 625. 594 00:39:31,520 --> 00:39:35,560 但更重要的则是 我现在可以使用A And then, crucial thing, I can now use A-- 595 00:39:35,760 --> 00:39:37,470 我已经在这个组合式里面用过了 here I've used it in a combination-- 596 00:39:37,968 --> 00:39:43,104 但我也可以在更复杂的组合式里面使用它 but I could use that in other more complicated things that I name in turn. 597 00:39:43,136 --> 00:39:50,480 我也可以说 定义B为 So I could say, define B to be the sum of, 598 00:39:50,528 --> 00:39:57,008 A与5乘以A的积的和 we'll say, A and the product of 5 and A. 599 00:39:58,992 --> 00:40:00,272 闭合“+” And then close the plus. 600 00:40:03,008 --> 00:40:05,408 让我们来看看它在计算机中是怎样的吧 Let's take a look at that on the computer and see how that looks. 601 00:40:06,832 --> 00:40:10,230 我就像黑板上写的那样键入就可以了 So I'll just type what I wrote on the board. 602 00:40:10,384 --> 00:40:21,280 我告诉Lisp I could say, define A to be the product of 5 and 5. 603 00:40:23,296 --> 00:40:24,930 定义A为5乘以5的积 And I'll tell that to Lisp. 604 00:40:25,072 --> 00:40:28,490 注意Lisp在下方回应了一个A And notice what Lisp responded there with was an A in the bottom. 605 00:40:28,640 --> 00:40:30,930 通常来说 你如果在Lisp中键入了一个定义 In general, when you type in a definition in Lisp, 606 00:40:31,056 --> 00:40:34,570 它返回被定义的符号 it responds with the symbol being defined. 607 00:40:35,184 --> 00:40:39,216 现在我问Lisp A乘以A的积是多少 Now I could say to Lisp, what is the product of A and A? 608 00:40:42,368 --> 00:40:43,888 Lisp返回625 And it says that's 625. 609 00:40:45,600 --> 00:40:59,890 我也可以定义B为A加上5乘以A的积的和 I can define B to be the sum of A and the product of 5 and A. 610 00:41:00,032 --> 00:41:05,250 闭合“*” 闭合“+” 闭合“define” Close a paren closes the star. Close the plus. Close the "define." 611 00:41:07,184 --> 00:41:09,920 Lisp在下方正常返回B Lisp says, OK, B, there on the bottom. 612 00:41:10,592 --> 00:41:12,790 现在我可以问Lisp B的值是多少 And now I can say to Lisp, what's the value of B? 613 00:41:16,736 --> 00:41:18,432 我也可以问一些更复杂的事 And I can say something more complicated, 614 00:41:18,480 --> 00:41:26,240 比如A加上B除以5的商的和是多少 like what's the sum of A and the quotient of B and 5? 615 00:41:26,288 --> 00:41:29,808 这个“/”是另一个基本运算符 代表除 That slash is divide, another primitive operator. 616 00:41:29,936 --> 00:41:32,330 我让B除以5 并加在A上 I've divided B by 5, added it to A. 617 00:41:33,200 --> 00:41:34,784 Lisp正常返回55 Lisp says, OK, that's 55. 618 00:41:36,120 --> 00:41:37,472 就像这样 So there's what it looks like. 619 00:41:39,376 --> 00:41:42,950 这是定义东西的基本方法 There's the basic means of defining something. 620 00:41:42,992 --> 00:41:48,570 这是最简单的命名方法 但并不是很强大 It's the simplest kind of naming, but it's not really very powerful. 621 00:41:49,616 --> 00:41:51,152 注意我们讨论的是通用方法 See, what I'd really like to name-- 622 00:41:51,392 --> 00:41:52,928 因此我真正想定义的是 remember, we're talking about general methods-- 623 00:41:53,120 --> 00:41:57,232 一种通用方法 可以 I'd like to name, oh, the general idea that, for example, 624 00:41:57,664 --> 00:42:17,088 得到 5乘5 6乘6 1001乘1001 1001.7乘1001.7 I could multiply 5 by 5, or 6 by 6, or 1,001 by 1,001, 1,001.7 by 1,001.7. 625 00:42:17,312 --> 00:42:23,712 我想给一个数与其自身相乘这种想法一个名字 I'd like to be able to name the general idea of multiplying something by itself. 626 00:42:28,032 --> 00:42:29,664 你应该知道 这叫做平方 Well, you know what that is. That's called squaring. 627 00:42:31,248 --> 00:42:35,184 而在Lisp中我应该这样实现 And the way I can do that in Lisp is I can say, 628 00:42:37,520 --> 00:42:55,808 定义 square某个叫x的东西 为 将x乘以x自己 define to square something x, multiply x by itself. 629 00:42:57,424 --> 00:43:00,672 定义完毕后 我可以问Lisp And then having done that, I could say to Lisp, 630 00:43:00,672 --> 00:43:05,040 比如 10的平方是多少 for example, what's the square of 10? 631 00:43:06,224 --> 00:43:07,424 Lisp返回100 And Lisp will say 100. 632 00:43:10,256 --> 00:43:13,790 让我们深入讨论一下 So now let's actually look at that a little more closely. 633 00:43:14,848 --> 00:43:16,430 这儿是square的定义 Right, there's the definition of square. 634 00:43:17,056 --> 00:43:22,100 square某个元素 即是将该元素进行自乘 To square something, multiply it by itself. 635 00:43:23,248 --> 00:43:24,896 这里的x You see this x here. 636 00:43:25,840 --> 00:43:27,360 应该算是一种代词 That x is kind of a pronoun, 637 00:43:27,424 --> 00:43:29,080 指代了我要做平方的元素 which is the something that I'm going to square. 638 00:43:31,040 --> 00:43:36,960 实际上我将其乘以x 即是乘以它自己 And what I do with it is I multiply x, I multiply it by itself. 639 00:43:41,776 --> 00:43:47,820 这些就是定义一个过程的记法 OK. So there's the notation for defining a procedure. 640 00:43:47,840 --> 00:43:49,840 这样说可能把你搞糊涂了 Actually, this is a little bit confusing, 641 00:43:50,368 --> 00:43:53,520 因为这就像我在用square一样 because this is sort of how I might use square. 642 00:43:53,552 --> 00:43:56,352 但如果我说x的平方根或者10的平方根 And I say square root of x or square root of 10, 643 00:43:57,104 --> 00:44:00,360 并没有说清楚我对什么做了定义 but it's not making it very clear that I'm actually naming something. 644 00:44:02,656 --> 00:44:04,464 所以让我换个方式来进行定义 So let me write this definition in another way 645 00:44:05,296 --> 00:44:07,760 这样可以清楚的看到定义的具体内容 that makes it a little bit more clear that I'm naming something. 646 00:44:08,096 --> 00:44:28,944 我定义“square”为“(lambda (x) (* x x))” I'll say, "define" square to be lambda of x times xx. 647 00:44:36,112 --> 00:44:41,600 这里 我定义square就像我某命名为A一样 Here, I'm naming something square, just like over here, I'm naming something A. 648 00:44:42,784 --> 00:44:44,272 我定义square The thing that I'm naming square-- 649 00:44:44,304 --> 00:44:47,940 这里 我把这个组合式的值命名为A here, the thing I named A was the value of this combination. 650 00:44:48,848 --> 00:44:51,968 在这里 我把这个东西命名为square Here, the thing that I'm naming square is this thing 651 00:44:51,984 --> 00:44:52,992 以lambda开头 that begins with lambda, 652 00:44:53,008 --> 00:44:56,320 lambda在Lisp中用以构建一个过程 and lambda is Lisp's way of saying make a procedure. 653 00:44:59,792 --> 00:45:02,464 请仔细看一下幻灯片上的内容 Let's look at that more closely on the slide. 654 00:45:03,820 --> 00:45:05,360 这个定义读作 The way I read that definition is to say, 655 00:45:05,408 --> 00:45:09,880 将square定义为 I define square to be make a procedure-- 656 00:45:12,336 --> 00:45:13,520 一个由lambda构造的 that's what the lambda is-- 657 00:45:13,616 --> 00:45:17,040 一个有带有参数x的过程 make a procedure with an argument named x. 658 00:45:18,816 --> 00:45:23,648 而该过程返回将x自乘的结果 And what it does is return the results of multiplying x by itself. 659 00:45:24,528 --> 00:45:32,672 一般来讲 这是最佳的定义方式 Now, in general, we're going to be using this top form of defining, 660 00:45:32,960 --> 00:45:34,752 因为这个更加方便一点 just because it's a little bit more convenient. 661 00:45:34,752 --> 00:45:34,768 但是也别忘了它实质上也是这个 But don't lose sight of the fact that it's really this. 因为这个更加方便一点 just because it's a little bit more convenient. 662 00:45:34,768 --> 00:45:38,224 但是也别忘了它实质上也是这个 But don't lose sight of the fact that it's really this. 663 00:45:38,416 --> 00:45:40,960 事实上 就Lisp解释器而言 In fact, as far as the Lisp interpreter's concerned, 664 00:45:41,168 --> 00:45:45,104 这两种方法没有区别 there's no difference between typing this to it and typing this to it. 665 00:45:46,064 --> 00:45:52,848 换句话说 这只是一种语法糖 And there's a word for that, sort of syntactic sugar. 666 00:45:53,968 --> 00:45:55,350 语法糖的意思就是 What syntactic sugar means, 667 00:45:55,904 --> 00:46:00,384 这种形式输入更方便一些 it's having somewhat more convenient surface forms for typing something. 668 00:46:00,672 --> 00:46:05,664 这只是这下面的有lambda的表达式的语法糖而已 So this is just really syntactic sugar for this underlying Greek thing with the lambda. 669 00:46:06,864 --> 00:46:10,176 你应该记住 And the reason you should remember that is don't forget that, 670 00:46:10,352 --> 00:46:13,420 当我这样写的时候 其实是在对某个东西进行命名 when I write something like this, I'm really naming something. 671 00:46:14,016 --> 00:46:15,776 我将其命名为square I'm naming something square, 672 00:46:15,792 --> 00:46:19,456 square代表一个构建好的过程 and the something that I'm naming square is a procedure that's getting constructed. 673 00:46:20,752 --> 00:46:23,456 让我们看看在计算机里面又是 怎样的吧 Well, let's look at that on the computer, too. 674 00:46:24,336 --> 00:46:35,504 定义“(square x)”为x乘以x的积 So I'll come and I'll say, define square of x to be times xx. 675 00:46:49,200 --> 00:46:51,872 将它送入Lisp Now I'll tell Lisp that. 676 00:46:53,040 --> 00:46:53,472 返回square It says "square." 677 00:46:53,488 --> 00:46:55,840 现在 我已经将某个东西命名为square了 See, I've named something "square." 678 00:46:56,000 --> 00:47:02,430 完毕后 我就可以问Lisp 1001的平方是多少 Now, having done that, I can ask Lisp for, what's the square of 1,001? 679 00:47:04,816 --> 00:47:17,248 或者更通常的来说 我可以问 5加上7的和的平方是多少 Or in general, I could say, what's the square of the sum of 5 and 7? 680 00:47:22,368 --> 00:47:24,500 12的平方是144 The square of 12's 144. 681 00:47:24,624 --> 00:47:28,416 在某些组合式中我亦可把square当作一个元素 Or I can use square itself as an element in some combination. 682 00:47:28,432 --> 00:47:37,056 3的平方加上4的平方的和是多少 I can say, what's the sum of the square of 3 and the square of 4? 683 00:47:42,080 --> 00:47:43,648 9加上16得25 9 and 16 is 25. 684 00:47:44,464 --> 00:47:50,096 我可以将square作为元素用于更复杂的式子 Or I can use square as an element in some much more complicated thing. 685 00:47:50,144 --> 00:48:00,064 比如 1001的平方点的平方的平方是多少 I can say, what's the square of, the sqare of, the square of 1,001? 686 00:48:07,440 --> 00:48:10,180 这就是1001点的平方的平方的平方 And there's the square of the square of the square of 1,001. 687 00:48:10,752 --> 00:48:15,008 我也可以问Lisp square本身是什么 Or I can say to Lisp, what is square itself? 688 00:48:15,232 --> 00:48:16,710 它的值是是什么 What's the value of that? 689 00:48:16,992 --> 00:48:21,690 Lisp用一种约定的方法告诉我这是一个过程 And Lisp returns some conventional way of telling me that that's a procedure. 690 00:48:21,824 --> 00:48:23,536 它返回 复合过程square It says, "compound procedure square." 691 00:48:23,808 --> 00:48:27,470 记住 square的值是一个过程 Remember, the value of square is this procedure, 692 00:48:28,704 --> 00:48:30,448 而那些用星号和括号的记法 and the thing with the stars and the brackets 693 00:48:30,656 --> 00:48:34,330 只是Lisp用来描述这个过程的约定 are just Lisp's conventional way of describing that. 694 00:48:35,664 --> 00:48:40,880 让我们再看两个关于define的例子 Let's look at two more examples of defining. 695 00:48:44,464 --> 00:48:46,464 这有两个过程 Here are two more procedures. 696 00:48:46,912 --> 00:48:52,390 定义x和y的平均值为x加上y的和除以2的商 I can define the average of x and y to be the sum of x and y divided by 2. 697 00:48:54,224 --> 00:49:01,040 以及定义好平方和平均值后 我可以定义均方 Or having had average and mean square, having had average and square, 698 00:49:01,200 --> 00:49:04,260 我可以用它们来讨论某元素的均方 I can use that to talk about the mean square of something, 699 00:49:04,464 --> 00:49:08,810 即x的平方与y的平方的平均值 which is the average of the square of x and the square of y. 700 00:49:10,528 --> 00:49:13,184 当定义好它们后 我可以问 So for example, having done that, I could say, 701 00:49:13,216 --> 00:49:24,432 2和3的均方是多少 what's the mean square of 2 and 3? 702 00:49:24,784 --> 00:49:29,790 我将会得到 4和9的平均值 即6.5 And I should get the average of 4 and 9, which is 6.5. 703 00:49:32,400 --> 00:49:36,192 关键点在于 定义了square后 The key thing here is that, having defined square, 704 00:49:36,192 --> 00:49:38,224 我可以把它当作一个基本元素来使用 I can use it as if it were primitive. 705 00:49:40,960 --> 00:49:42,624 因此在这里 So if we look here on the slide, 706 00:49:44,208 --> 00:49:45,296 我在讨论均方的时候 if I look at mean square, 707 00:49:46,848 --> 00:49:52,112 从这点来说 定义均方的人没有必要知道 the person defining mean square doesn't have to know, at this point, 708 00:49:52,160 --> 00:49:55,312 究竟square是由语言内建支持 whether square was something built into the language 709 00:49:56,496 --> 00:49:58,480 还是自定义的过程 or whether it was a procedure that was defined. 710 00:49:59,280 --> 00:50:00,832 这是Lisp的关键之一 And that's a key thing in Lisp, 711 00:50:01,850 --> 00:50:07,072 你无法准确区别 that you do not make arbitrary distinctions between things 712 00:50:07,088 --> 00:50:11,370 哪些是语言的基本对象 哪些是语言的内建支持 that happen to be primitive in the language and things that happen to be built in. 713 00:50:12,384 --> 00:50:14,288 用户使用时则无需关心这些 A person using that shouldn't even have to know. 714 00:50:14,480 --> 00:50:18,064 你自己构建的东西看起来就像是语言自带的基本对象 So the things you construct get used with all the power and flexibility 715 00:50:18,064 --> 00:50:19,088 具有同样的能力和灵活性 as if they were primitives. 716 00:50:19,120 --> 00:50:22,128 大家可以在课后上机做做测试 In fact, you can drive that home by looking on the computer one more time. 717 00:50:24,304 --> 00:50:25,856 我们接下来讨论一下“+”吧 We talked about plus. 718 00:50:26,272 --> 00:50:29,648 好的 让我们在计算机中看看 And in fact, if I come here on the computer screen and say, 719 00:50:29,664 --> 00:50:31,888 “+”的值是什么 what is the value of plus? 720 00:50:33,952 --> 00:50:36,752 注意Lisp在下面的输出 Notice what Lisp types out. On the bottom there, it typed out, 721 00:50:36,800 --> 00:50:38,368 复合过程“+” "compound procedure plus." 722 00:50:39,440 --> 00:50:41,840 因为在此系统中 Because, in this system, 723 00:50:41,888 --> 00:50:45,040 “+”运算符是一个复合过程 it turns out that the addition operator is itself a compound procedure. 724 00:50:45,520 --> 00:50:47,520 但如果我不输入进去做下测试 你永远不会知道 And if I didn't just type that in, you'd never know that, 725 00:50:47,616 --> 00:50:49,232 所以这没什么不同 and it wouldn't make any difference anyway. 726 00:50:49,392 --> 00:50:50,064 我们并不关心这些 We don't care. 727 00:50:50,112 --> 00:50:52,940 它比我们日常处理的问题更加抽象一些 It's below the level of the abstraction that we're dealing with. 728 00:50:53,728 --> 00:50:58,660 其关键点在于你无法分辨出 So the key thing is you cannot tell, should not be able to tell, in general, 729 00:50:58,720 --> 00:51:03,370 内建元素与复合元素之间的不同 the difference between things that are built in and things that are compound. 730 00:51:03,392 --> 00:51:03,936 为什么会这样呢? Why is that? 731 00:51:03,936 --> 00:51:07,620 因为复合元素经过了一次抽象封装 (以致于无法分辨) Because the things that are compound have an abstraction wrapper wrapped around them. 732 00:51:08,608 --> 00:51:11,168 我们已经介绍了Lisp的大多数元素了 We've seen almost all the elements of Lisp now. 733 00:51:12,224 --> 00:51:14,080 还有一个需要进行讨论的 There's only one more we have to look at, 734 00:51:14,128 --> 00:51:16,080 就是如何进行分情况分析 and that is how to make a case analysis. 735 00:51:16,144 --> 00:51:17,250 举个例子 Let me show you what I mean. 736 00:51:18,512 --> 00:51:23,632 让我们考虑绝对值函数的数学定义 We might want to think about the mathematical definition of the absolute value functions. 737 00:51:23,664 --> 00:51:29,580 我或许会说x的绝对值这样是一个函数 I might say the absolute value of x is the function 738 00:51:29,712 --> 00:51:36,790 若x小于0 则为-x which has the property that it's negative of x. For x less than 0, 739 00:51:37,472 --> 00:51:40,680 若x等于0 则为0 it's 0 for x equal to 0. 740 00:51:42,192 --> 00:51:46,170 若x大于0 则就是x And it's x for x greater than 0. 741 00:51:48,704 --> 00:51:51,456 而Lisp则有一套分情况分析方法 And Lisp has a way of making case analyses. 742 00:51:51,664 --> 00:51:53,408 以绝对值定义为例 我给大家说明一下 Let me define for you absolute value. 743 00:51:55,104 --> 00:52:01,960 定义绝对值为 x是有多种情况的 Say define the absolute value of x is conditional. 744 00:52:02,576 --> 00:52:05,220 这就是分情况分析 This means case analysis, COND. 745 00:52:08,784 --> 00:52:18,640 如果x小于0 则结果为-x If x is less than 0, the answer is negate x. 746 00:52:22,544 --> 00:52:24,430 我这里写的是一个子句 What I've written here is a clause. 747 00:52:24,544 --> 00:52:35,090 这整个是一个由两部分组成的条件表达式 This whole thing is a conditional clause, and it has two parts. 748 00:52:35,904 --> 00:52:44,250 这个部分叫做谓词或者条件 This part here is a predicate or a condition. 749 00:52:44,384 --> 00:52:45,456 这就是一种情况(条件) That's a condition. 750 00:52:45,664 --> 00:52:47,840 用以表达条件的东西叫做谓词 And the condition is expressed by something called a predicate, 751 00:52:47,888 --> 00:52:50,600 Lisp中的谓词是一种 and a predicate in Lisp is some sort of thing 752 00:52:50,928 --> 00:52:52,420 可以返回true或者false的东西 that returns either true or false. 753 00:52:53,088 --> 00:52:55,680 比如说“小于”是Lisp中的一个基本过程 And you see Lisp has a primitive procedure, less-than, 754 00:52:56,848 --> 00:52:58,630 它返回true或者false that tests whether something is true or false. 755 00:53:00,090 --> 00:53:05,872 子句其余部分为一个动作或者需要做的事 And the other part of a clause is an action or a thing to do, 756 00:53:06,480 --> 00:53:07,696 本例中为true in the case where that's true. 757 00:53:07,728 --> 00:53:09,360 在这里 我则是取x的相反数 And here, what I'm doing is negating x. 758 00:53:09,632 --> 00:53:13,960 有趣的是 Lisp中减运算符符与相反数运算符相同 The negation operator, the minus sign in Lisp is a little bit funny. 759 00:53:14,112 --> 00:53:17,980 如果有两个及两个以上的参数 If there's two or more arguments, 760 00:53:18,130 --> 00:53:22,048 正如我们看到的 假设刚好有两个参数 就从第一个中减去第二个 if there's two arguments it subtracts the second one from the first, and we saw that. 761 00:53:22,080 --> 00:53:23,680 如果只有一个参数 则取其相反数 And if there's one argument, it negates it. 762 00:53:24,688 --> 00:53:27,420 这与前面相符合 So this corresponds to that. 763 00:53:27,424 --> 00:53:29,240 这又是一个COND子句 And then there's another COND clause. 764 00:53:30,192 --> 00:53:35,424 这是说 在x等于0的时候 结果为0 It says, in the case where x is equal to 0, the answer is 0. 765 00:53:37,504 --> 00:53:44,300 在x大于0的时候 结果为x And in the case where x is greater than 0, the answer is x. 766 00:53:44,880 --> 00:53:48,930 闭合子句 闭合COND 闭合define Close that clause. Close the COND. Close the definition. 767 00:53:49,120 --> 00:53:50,848 这就是绝对值的定义 And there's the definition of absolute value. 768 00:53:50,864 --> 00:53:53,216 你会发现分情况分析 And you see it's the case analysis that looks very much 769 00:53:53,216 --> 00:53:55,590 与数学中所用的非常相似 like the case analysis you use in mathematics. 770 00:53:57,696 --> 00:54:02,624 当然还有一些不常用的受限的分情况分析方法 There's a somewhat different way of writing a restricted case analysis. 771 00:54:02,624 --> 00:54:05,792 很多时候 你在进行分情况分析时只有一种情况 Often, you have a case analysis where you only have one case, 772 00:54:06,480 --> 00:54:07,620 你首先进行测试 where you test something, 773 00:54:07,888 --> 00:54:10,300 然后根据返回的为true或false来决定如何处理 and then depending on whether it's true or false, you do something. 774 00:54:10,560 --> 00:54:15,450 这是另外一种定义绝对值的方法 And here's another definition of absolute value 775 00:54:15,552 --> 00:54:16,740 但看起来是几乎一样的 which looks almost the same, 776 00:54:17,216 --> 00:54:22,112 像这样 如果x小于0 结果则为x的相反数 which says, if x is less than 0, the result is negate x. 777 00:54:23,960 --> 00:54:25,520 否则 结果即为x Otherwise, the answer is x. 778 00:54:25,600 --> 00:54:26,800 我们将会大量的使用“if” And we'll be using "if" a lot. 779 00:54:26,848 --> 00:54:28,688 再次声明 But again, the thing to remember is that 780 00:54:28,688 --> 00:54:32,256 你们在这里看到的绝对值形式 this form of absolute value that you're looking at here, 781 00:54:33,856 --> 00:54:36,530 和我在黑板上写的那种 and then this one over here that I wrote on the board, 782 00:54:37,072 --> 00:54:38,352 本质上是一样的 are essentially the same. 783 00:54:38,640 --> 00:54:41,810 而“if”和“COND”则是—— And "if" and COND are-- well, whichever way you like it. 784 00:54:41,856 --> 00:54:44,000 你可以把“COND”当做“if”的语法糖 You can think of COND as syntactic sugar for "if", 785 00:54:44,544 --> 00:54:46,912 或者“if”是“COND”的语法糖 or you can think of "if" as syntactic sugar for COND, 786 00:54:46,944 --> 00:54:48,200 这没什么区别 and it doesn't make any difference. 787 00:54:48,768 --> 00:54:50,900 Lisp系统的设计者会从中会选择一个 The person implementing a Lisp system will pick one 788 00:54:50,944 --> 00:54:52,528 然后依照这个来实现另外一个 and implement the other in terms of that. 789 00:54:52,704 --> 00:54:54,224 你首先实现哪一个都无所谓 And it doesn't matter which one you pick. 790 00:55:01,824 --> 00:55:04,910 让我们停下来 解决几点疑问 Why don't we break now, and then take some questions. 791 00:55:05,248 --> 00:55:09,632 为什么我有时用define时 How come sometimes when I write define, 792 00:55:10,640 --> 00:55:14,300 我在这里使用了一个左括号 I put an open paren here and say, 793 00:55:14,368 --> 00:55:16,000 输入 define (XXX define open paren something or other, 794 00:55:16,416 --> 00:55:20,368 而有时我这样写时却没加左括号 and sometimes when I write this, I don't put an open paren? 795 00:55:21,616 --> 00:55:26,784 是因为你所见的 The answer is, this particular form of "define", 796 00:55:26,816 --> 00:55:28,960 这种“define”表达式 where you say define some expression, 797 00:55:29,024 --> 00:55:31,680 对于定义过程来讲是非常特殊 is this very special thing for defining procedures. 798 00:55:33,168 --> 00:55:39,760 再次强调 这实际上是说我定义这个叫square的符号为这个 But again, what it really means is I'm defining this symbol, square, to be that. 799 00:55:41,008 --> 00:55:45,536 你所知道的则是 你先写一个“define” So the way you should think about it is what "define" does is you write "define", 800 00:55:46,704 --> 00:55:49,616 然后你再写一个符号 没有左括号 and the second thing you write is the symbol here-- no open paren-- 801 00:55:49,728 --> 00:55:51,040 这是你将要定义的符号 the symbol you're defining 802 00:55:51,632 --> 00:55:53,250 这又是你要将其定义为什么 and what you're defining it to be. 803 00:55:54,208 --> 00:55:57,104 就像这儿和这儿 That's like here and like here. 804 00:55:57,168 --> 00:55:59,840 这是“define”的基本使用方法 That's sort of the basic way you use "define." 805 00:56:00,672 --> 00:56:03,200 然而 这种特殊的语法技巧 And then, there's this special syntactic trick 806 00:56:03,840 --> 00:56:06,592 使得你可以定义像这样的过程 which allows you to define procedures that look like this. 807 00:56:07,728 --> 00:56:11,040 因此区别就在于你是否定义了一个过程 So the difference is, it's whether or not you're defining a procedure. 808 00:56:12,464 --> 00:56:37,152 [音乐] [JESU, JOY OF MAN'S DESIRING] 809 00:56:37,600 --> 00:56:41,536 信不信由你 你们已经学了足够多的Lisp的知识了 Well, believe it or not, you actually now know enough Lisp 810 00:56:42,336 --> 00:56:44,976 现在你基本上可以编写 to write essentially any numerical procedure 811 00:56:45,808 --> 00:56:49,184 FORTRAN、Basic或者其它语言中一样的 that you'd write in a language like FORTRAN or Basic or whatever, 812 00:56:49,216 --> 00:56:50,560 数值计算过程了 or, essentially, any other language. 813 00:56:51,600 --> 00:56:54,310 或许你会说 这不可能 And you're probably saying, that's not believable, 814 00:56:54,368 --> 00:56:56,208 因为你知道这些语言有 because you know that these languages have things 815 00:56:56,208 --> 00:56:59,770 像“for”语句和“do-until-while”语句的东西 like "for statements", and "do until while" or something. 816 00:57:00,544 --> 00:57:04,144 实际上这些我们一点也用不着 But we don't really need any of that. 817 00:57:04,608 --> 00:57:06,680 本课中我们一点也不会使用这些东西 In fact, we're not going to use any of that in this course. 818 00:57:07,808 --> 00:57:09,712 我给你们来个下马威 Let me show you. 819 00:57:09,808 --> 00:57:13,168 回过头来看看平方根 Again, looking back at square root, 820 00:57:13,200 --> 00:57:18,580 让我们看看亚历山大的Heron提出的平方根算法 let's go back to this square root algorithm of Heron of Alexandria. 821 00:57:18,640 --> 00:57:19,520 想想它是怎么说的 Remember what that said. 822 00:57:19,616 --> 00:57:23,220 算法说 为了找到X的平方根的近似值 It said, to find an approximation to the square root of X, 823 00:57:24,624 --> 00:57:25,712 你做出猜测 you make a guess, 824 00:57:27,008 --> 00:57:31,430 然后通过取guess和X/guess的平均数来改进猜测 you improve that guess by averaging the guess and X over the guess. 825 00:57:32,496 --> 00:57:35,616 你不断改进猜测 直到这个猜测足够好 You keep improving that until the guess is good enough. 826 00:57:36,272 --> 00:57:37,984 我已经提到过这种想法 I already alluded to the idea. 827 00:57:38,112 --> 00:57:41,792 这种想法是说 如果你最初采用的猜测 The idea is that, if the initial guess that you took 828 00:57:42,592 --> 00:57:46,460 真真切切的等于X的平方根 was actually equal to the square root of X, 829 00:57:46,704 --> 00:57:49,616 那么G就会等于X/G then G here would be equal to X/G. 830 00:57:52,448 --> 00:57:54,880 如果你算出平方根 对其取平均数并不会改变它 So if you hit the square root, averaging them wouldn't change it. 831 00:57:55,248 --> 00:57:59,170 如果你所采用的G比X的平方根大 If the G that you picked was larger than the square root of X, 832 00:57:59,936 --> 00:58:02,490 那么X/G就会比X的平方根小 then X/G will be smaller than the square root of X, 833 00:58:02,768 --> 00:58:04,928 因此当你取G与X/G的平均值时 so that when you average G and X/G, 834 00:58:05,184 --> 00:58:07,120 就得到了两者之间的某数 you get something in between. 835 00:58:08,512 --> 00:58:12,500 同理 若你采用的G过小 答案则会过大 So if you pick a G that's too small, your answer will be too large. 836 00:58:12,672 --> 00:58:14,368 如果你采用了一个太大的G If you pick a G that's too large, 837 00:58:15,872 --> 00:58:17,616 如果你的G比X的平方根还要大的话 if your G is larger than the square root of X 838 00:58:17,632 --> 00:58:19,904 X/G就会比X的平方根还要小 and X/G will be smaller than the square root of X. 839 00:58:20,784 --> 00:58:23,200 因此取平均值使得你总可以得到两者间的某数 So averaging always gives you something in between. 840 00:58:24,080 --> 00:58:27,680 这不是毫无意义的 它表明 And then, it's not quite trivial, but it's possible to show that, 841 00:58:27,728 --> 00:58:31,310 事实上 如果G只差X的平方根一点的话 in fact, if G misses the square root of X by a little bit, 842 00:58:31,360 --> 00:58:37,540 G和X/G的平均值就会慢慢的向X的平方根靠近 the average of G and X/G will actually keep getting closer to the square root of X. 843 00:58:37,584 --> 00:58:38,544 只要你不断的这样做 So if you keep doing this enough, 844 00:58:38,976 --> 00:58:40,736 最终就可以不断地靠近 you'll eventually get as close as you want. 845 00:58:41,264 --> 00:58:42,400 另外一个事实则是 And then there's another fact, 846 00:58:42,576 --> 00:58:47,200 你总可以使用1作为一个初始猜测值来开始计算 that you can always start out this process by using 1 as an initial guess. 847 00:58:48,784 --> 00:58:50,900 它总是朝X的平方根聚拢 And it'll always converge to the square root of X. 848 00:58:51,792 --> 00:58:56,320 这就是亚历山大的Heron的连续求平均值法 So that's this method of successive averaging due to Heron of Alexandria. 849 00:58:56,368 --> 00:58:58,760 让我们在Lisp中实现 Let's write it in Lisp. 850 00:59:00,120 --> 00:59:02,160 中心思想是 Well, the central idea is, 851 00:59:02,208 --> 00:59:06,740 尝试将guess作为X的平方根的一个猜想意味着什么 what does it mean to try a guess for the square root of X? 852 00:59:07,856 --> 00:59:08,928 我来编码 Let's write that. 853 00:59:09,344 --> 00:59:24,576 定义(try guess x) So we'll say, define to try a guess for the square root of X, 854 00:59:26,000 --> 00:59:27,790 我们该如何做 我们会说 what do we do? We'll say, 855 00:59:27,840 --> 00:59:44,816 如果猜测精确到可以作为X的平方根 if the guess is good enough to be a guess for the square root of X, 856 00:59:46,096 --> 00:59:49,070 那么我们就可以将这个猜测作为答案 then, as an answer, we'll take the guess. 857 00:59:51,168 --> 00:59:56,560 否则 我们就会尝试改进猜测 Otherwise, we will try the improved guess. 858 00:59:57,744 --> 01:00:03,792 我们将通过改进这个猜测来作为X的平方根 We'll improve that guess for the square root of X, 859 01:00:04,816 --> 01:00:08,880 并尝试是否为X平方根 and we'll try that as a guess for the square root of X. 860 01:00:08,912 --> 01:00:12,512 闭合try 闭合if 闭合define Close the "try." Close the "if." Close the "define." 861 01:00:12,864 --> 01:00:14,368 这就是我们如何尝试一个猜测 So that's how we try a guess. 862 01:00:15,408 --> 01:00:17,150 然后 这个过程的下一步是说 And then, the next part of the process said, 863 01:00:17,280 --> 01:00:21,450 为了计算平方根 in order to compute square roots, we'll say, 864 01:00:21,488 --> 01:00:29,728 定义计算X的平方根为 define to compute the square root of X, 865 01:00:30,352 --> 01:00:35,344 从1作为X的平方根的一个猜测开始尝试 we will try 1 as a guess for the square root of X. 866 01:00:36,976 --> 01:00:39,140 我们必须定义一些其它的东西 Well, we have to define a couple more things. 867 01:00:39,632 --> 01:00:42,912 我们必须说明 一个猜测如何才叫“足够好” We have to say, how is a guess good enough? 868 01:00:43,392 --> 01:00:44,848 我们又该如何改进这个猜测 And how do we improve a guess? 869 01:00:45,408 --> 01:00:46,656 那么让我们来看看 So let's look at that. 870 01:00:46,944 --> 01:00:53,792 而改进一个X的平方根的一个猜测的算法则是 The algorithm to improve a guess for the square root of X, 871 01:00:54,192 --> 01:00:56,736 取平均数 we average-- that was the algorithm-- 872 01:00:56,736 --> 01:01:01,712 我们取guess和X/guess的平均数 we average the guess with the quotient of dividing X by the guess. 873 01:01:02,544 --> 01:01:04,128 这就是我们如何改进一个猜测 That's how we improve a guess. 874 01:01:05,408 --> 01:01:08,352 为了确定一个猜测是否足够精确 我们需要做一下规定 And to tell whether a guess is good enough, well, we have to decide something. 875 01:01:08,416 --> 01:01:10,912 假设这个是X的平方根的一个猜测 This is supposed to be a guess for the square root of X, 876 01:01:10,928 --> 01:01:13,584 你可能做的一件事就是 so one possible thing you can do is say, 877 01:01:13,616 --> 01:01:15,620 当你采用这个猜测并将其平方 when you take that guess and square it, 878 01:01:16,192 --> 01:01:17,968 你会得到一个非常接近于X的数 do you get something very close to X? 879 01:01:18,144 --> 01:01:20,650 而表达这个想法的一种方式是 So one way to say that is to say, 880 01:01:20,672 --> 01:01:23,860 我们用X减去guess的平方 I square the guess, subtract X from that, 881 01:01:24,704 --> 01:01:26,700 并且确认所得结果的绝对值是否 and see if the absolute value of that 882 01:01:26,752 --> 01:01:31,600 比一个由你规定的很小的数还要小 whole thing is less than some small number, which depends on my purposes. 883 01:01:34,256 --> 01:01:40,970 因此 我们就有了计算X的平方根的一整套过程 So there's a complete procedure for how to compute the square root of X. 884 01:01:41,024 --> 01:01:43,088 我们再来深入观察一下这个结构 Let's look at the structure of that a little bit. 885 01:01:47,392 --> 01:01:48,672 我搞定了整件事 I have the whole thing. 886 01:01:48,700 --> 01:01:54,992 我有一个用于计算X的平方根的记号 I have the notion of how to compute a square root. 887 01:01:55,088 --> 01:01:56,432 这是一种模块 That's some kind of module. 888 01:01:56,608 --> 01:01:58,016 也是一种黑盒 That's some kind of black box. 889 01:01:58,272 --> 01:02:07,570 它的定义依赖于如何尝试将一个猜测值作为X的平方根 It's defined in terms of how to try a guess for the square root of X. 890 01:02:08,864 --> 01:02:13,650 定义try是用来 "Try" is defined in terms of, well, 891 01:02:14,160 --> 01:02:17,584 确认某数是否足够精确以及如何去改进该数 telling whether something is good enough and telling how to improve something. 892 01:02:18,288 --> 01:02:19,232 这是good-enogh? So good enough. 893 01:02:19,440 --> 01:02:28,400 try的定义依赖于good-enough?和improve "Try" is defined in terms of "good enough" and "improve". 894 01:02:30,512 --> 01:02:32,110 让我们来看看我填入了些什么 And let's see what else I fill in. 895 01:02:32,264 --> 01:02:33,844 如果我向下拓展这棵树 Well, I'll go down this tree. 896 01:02:34,288 --> 01:02:38,048 good-enough?的定义依赖于abs和square "Good enough" was defined in terms of absolute value, and square. 897 01:02:40,528 --> 01:02:43,680 而improve的定义依赖于averaging And improve was defined in terms of something called averaging 898 01:02:44,720 --> 01:02:46,256 而其它的都是一些基本运算符 and then some other primitive operator. 899 01:02:46,272 --> 01:02:48,432 平方根的定义依赖于try Square root's defined in terms of "try". 900 01:02:48,432 --> 01:02:52,864 try的定义依赖于good-enough?和improve "Try" is defined in terms of "good enough" and "improve", 901 01:02:53,568 --> 01:02:54,944 甚至依赖于try本身 but also "try" itself. 902 01:02:55,136 --> 01:03:00,416 因此try也按照它如何应用于自身而进行定义 So "try" is also defined in terms of how to try itself. 903 01:03:02,304 --> 01:03:04,272 额 这可能会使你有点糊涂 Well, that may give you some problems. 904 01:03:04,272 --> 01:03:07,712 你的高中几何老师或许告诉过你 Your high school geometry teacher probably told you 905 01:03:08,224 --> 01:03:12,128 用一个东西自己去定义自己是很不对的 that it's naughty to try and define things in terms of themselves, 906 01:03:12,432 --> 01:03:13,472 因为这根本行不通 because it doesn't make sense. 907 01:03:13,472 --> 01:03:14,272 这(种说法)是错的 But that's false. 908 01:03:15,584 --> 01:03:19,232 有时候用一个东西自己来定义自己非常有意义 Sometimes it makes perfect sense to define things in terms of themselves. 909 01:03:19,712 --> 01:03:23,930 我们来看看这个例子 And this is the case. And we can look at that. 910 01:03:23,936 --> 01:03:26,448 假设我问Lisp:2的平方根是多少 We could write down what this means, and say, 911 01:03:26,464 --> 01:03:29,888 我们可以写出它究竟是什么意思 suppose I asked Lisp what the square root of 2 is. 912 01:03:32,208 --> 01:03:34,220 2的平方根是什么意思 What's the square root of 2 mean? 913 01:03:35,344 --> 01:03:43,168 意思就是我将用1作为2的平方根的一个猜测 Well, that means I try 1 as a guess for the square root of 2. 914 01:03:46,528 --> 01:03:50,470 然后我考虑 对于2的平方根来说 1是一个足够好的猜测么 Now I look. I say, gee, is 1 a good enough guess for the square root of 2? 915 01:03:51,200 --> 01:03:53,240 这取决于good-enough?是如何判断的 And that depends on the test that "good enough" does. 916 01:03:54,160 --> 01:03:56,112 本例中 good-enough?会说 And in this case, "good enough" will say, 917 01:03:56,208 --> 01:03:58,600 不 对于2的平方根来说 1不是一个足够好的猜测 no, 1 is not a good enough guess for the square root of 2. 918 01:03:59,344 --> 01:04:07,770 因此我会继续说 我试试一个改进值 So that will reduce to saying, I have to try an improved-- 919 01:04:08,192 --> 01:04:12,180 改进猜测值1 improve 1 as a guess for the square root of 2, 920 01:04:14,704 --> 01:04:17,010 然后将其作为2的平方根的一个猜测 and try that as a guess for the square root of 2. 921 01:04:18,688 --> 01:04:21,620 改进猜测值1用作2的平方根 Improving 1 as a guess for the square root of 2 922 01:04:21,648 --> 01:04:24,630 也就是说我取1和2/1的平均值 means I average 1 and 2 divided by 1. 923 01:04:26,656 --> 01:04:28,656 因此我们将取平均数 So this is going to be average. 924 01:04:29,136 --> 01:04:38,990 这段代码将会取1和2/1的平均数 This piece here will be the average of 1 and the quotient of 2 by 1. 925 01:04:40,384 --> 01:04:42,300 那么这段代码 That's this piece here. 926 01:04:43,408 --> 01:04:46,270 我算算 结果是1.5 And I'm gonna try... And this is 1.5. 927 01:04:48,624 --> 01:04:53,952 因此这个(sqrt 2)归约到(try 1 2) So this square root of 2 reduces to trying 1 for the square root of 2, 928 01:04:54,112 --> 01:05:04,380 然后归约到(try 1.5 2) which reduces to trying 1.5 as a guess for the square root of 2. 929 01:05:05,584 --> 01:05:07,616 因此这行得通 So that makes sense. 930 01:05:07,664 --> 01:05:09,072 让我们看下剩下的步骤 Let's look at the rest of the process. 931 01:05:09,280 --> 01:05:14,550 如果我尝试1.5 则会归约到 If I try 1.5, that reduces. 932 01:05:14,560 --> 01:05:18,608 1.5作为2的平方根的猜测 并不是足够好 1.5 turns out to be not good enough as a guess for the square root of 2. 933 01:05:19,776 --> 01:05:21,552 然后又归约到 So that reduces to trying the average of 934 01:05:21,568 --> 01:05:25,720 (try (average 1.5 (/ 2 1.5))) 1.5 and 2 divided by 1.5 as a guess for the square root of 2. 935 01:05:27,840 --> 01:05:29,920 平均值是1.333 That average turns out to be 1.333. 936 01:05:30,736 --> 01:05:34,790 然后整个事又归约到(try 1.3333 2) So this whole thing reduces to trying 1.333 as a guess for the square root of 2. 937 01:05:34,832 --> 01:05:35,616 如此进行下去 And then so on. 938 01:05:37,568 --> 01:05:41,216 然后又归约到(good-enough? 1.4)或者其它的 That reduces to another called a "good enough", 1.4 something or other. 939 01:05:41,280 --> 01:05:44,020 然后这个(步骤)会持续进行到 And then it keeps going until the process finally stops 940 01:05:44,400 --> 01:05:47,472 good-enough?认为足够好了才停止 with something that "good enough" thinks is good enough, which, 941 01:05:47,520 --> 01:05:50,832 本例中 是1.4242或者其它的东西 in this case, is 1.4142 something or other. 942 01:05:52,064 --> 01:05:55,600 因此这个这个过程运行得非常完美 So the process makes perfect sense. 943 01:05:59,488 --> 01:06:02,656 这种定义方法叫做“递归定义” This, by the way, is called a recursive definition. 944 01:06:13,952 --> 01:06:20,510 进行递归定义将会给你带来无穷威力 And the ability to make recursive definitions is a source of incredible power. 945 01:06:21,504 --> 01:06:22,608 之前我已提到过 And as you can already see I've hinted at, 946 01:06:22,640 --> 01:06:26,768 递归定义可以在不增加任何负担的前提下 it's the thing that effectively allows you to do these infinite computations 947 01:06:26,800 --> 01:06:28,380 仅仅通过调用过程 在达到条件之前 that go on until something is true, 948 01:06:29,280 --> 01:06:33,216 完成无限次的计算 without having any other constricts other than the ability to call a procedure. 949 01:06:35,520 --> 01:06:37,020 还有一点要说明的 Well, let's see, there's one more thing. 950 01:06:37,264 --> 01:06:43,760 我再在这里给你们演示另外一种平方根的定义方法 Let me show you a variant of this definition of square root here on the slide. 951 01:06:43,984 --> 01:06:47,712 这两种方法看起来像是一样的 Here's sort of the same thing. 952 01:06:47,952 --> 01:06:51,040 在这儿 我把improve、good-enough?、try的定义 What I've done here is packaged the definitions of 953 01:06:51,072 --> 01:06:55,712 全都封装在了sqrt里面 "improve" and "good enough" and "try" inside "square root". 954 01:06:56,304 --> 01:07:00,544 因此实际上 我们构建了一个平方根盒子 So, in effect, what I've done is I've built a square root box. 955 01:07:01,360 --> 01:07:08,080 我构建了一个其它人可以使用的平方根盒子 So I've built a box that's the square root procedure that someone can use. 956 01:07:08,128 --> 01:07:11,024 它们输入36 然后(盒子)输出6 They might put in 36 and get out 6. 957 01:07:11,360 --> 01:07:13,380 但是 盒子里面封装的过程 And then, packaged inside this box 958 01:07:13,712 --> 01:07:23,400 就是try、good-enough?和improve的定义 are the definitions of "try" and "good enough" and "improve." 959 01:07:26,336 --> 01:07:27,904 它们都隐藏在盒子里面 So they're hidden inside this box. 960 01:07:27,952 --> 01:07:30,310 这样做是因为 And the reason for doing that is that, 961 01:07:30,736 --> 01:07:32,400 如果有人正在使用这个平方根 if someone's using this square root, 962 01:07:32,768 --> 01:07:34,288 如果George正在使用这个平方根 if George is using this square root, 963 01:07:34,304 --> 01:07:36,910 George并不会关心 George probably doesn't care very much that, 964 01:07:37,840 --> 01:07:39,584 当我在实现平方根时 when I implemented square root, 965 01:07:39,760 --> 01:07:44,000 我定义了盒子内的那些try、good-enough?和improve过程 I had things inside there called "try" and "good enough" and "improve". 966 01:07:45,952 --> 01:07:48,880 事实上 Harry可能会实现一个也具有 And in fact, Harry might have a cube root procedure 967 01:07:48,928 --> 01:07:50,512 try、good-enough?和improve的立方根盒子 that has "try" and "good enough" and "improve". 968 01:07:50,992 --> 01:07:52,896 因此 为了不让整个系统变得混乱 And in order to not get the whole system confused, 969 01:07:52,912 --> 01:07:57,216 Harry最好把这些内部过程封装在它的立方根过程里 it'd be good for Harry to package his internal procedures inside his cube root procedure. 970 01:07:57,952 --> 01:07:59,616 这个叫做块结构 Well, this is called block structure, 971 01:07:59,872 --> 01:08:08,510 这是把东西打包到定义内部的一种方法 this particular way of packaging internals inside of a definition. 972 01:08:09,520 --> 01:08:12,512 让我们回过头来再看看 And let's go back and look at the slide again. 973 01:08:12,672 --> 01:08:18,128 这种过程的定义读作 定义“sqrt”为 The way to read this kind of procedure is to say, to define "square root", 974 01:08:19,424 --> 01:08:21,392 那么 在其内部 well, inside that definition, 975 01:08:21,680 --> 01:08:25,040 我们已有improve的定义 I'll have the definition of an "improve" and 976 01:08:25,110 --> 01:08:28,432 我们已有good-enough?和try的定义 the definition of "good enough" and the definition of "try." 977 01:08:29,280 --> 01:08:31,930 以及这些定义的实体 And then, subject to those definitions, 978 01:08:32,032 --> 01:08:34,624 我求平方根的定义实体是从1开始尝试 the way I do square root is to try 1. 979 01:08:35,630 --> 01:08:38,880 注意这里 我不必将X当做参数传递 And notice here, I don't have to say 1 as a guess for the square root of X, 980 01:08:39,424 --> 01:08:41,872 因为它们都在平方根内部 because since it's all inside the square root, 981 01:08:42,391 --> 01:08:44,201 它相当于已知这个X了 it sort of has this X known. 982 01:08:53,616 --> 01:08:55,920 我来总结下 Let me summarize. 983 01:08:56,048 --> 01:08:59,040 我们从表述指令性知识 We started out with the idea that 984 01:08:59,060 --> 01:09:02,736 开始学习 what we're going to be doing is expressing imperative knowledge. 985 01:09:04,544 --> 01:09:09,296 这张幻灯片总结了一些关于Lisp的知识 And in fact, here's a slide that summarizes the way we looked at Lisp. 986 01:09:09,296 --> 01:09:14,670 我们从基本元素如“+”和“*”开始 We started out by looking at some primitive elements in addition and multiplication, 987 01:09:15,408 --> 01:09:19,056 一些用于测试某物小于或等于的谓词 some predicates for testing whether something is less-than or something's equal. 988 01:09:19,072 --> 01:09:22,544 事实上 我们正在使用的系统掩盖了很多细节 And in fact, we saw really sneakily in the system we're actually using, 989 01:09:22,576 --> 01:09:25,408 这些并不是系统的基本元素 但这无所谓 these aren't actually primitives, but it doesn't matter. 990 01:09:26,176 --> 01:09:28,144 重要的是我们会把它们当作是基本元素 What matters is we're going to use them as if they're primitives. 991 01:09:28,160 --> 01:09:29,360 我们不会去研究系统的内部 We're not going to look inside. 992 01:09:29,840 --> 01:09:32,700 我们也有一些基本数据和一些数 We also have some primitive data and some numbers. 993 01:09:34,176 --> 01:09:37,216 我们学习了合成的手段 组合的手段 We saw some means of composition, means of combination, 994 01:09:37,290 --> 01:09:40,928 用运算符和运算对象合成函数 the basic one being composing functions and 995 01:09:40,960 --> 01:09:43,312 和构建组合式的基本方法 building combinations with operators and operands. 996 01:09:44,368 --> 01:09:47,980 还有一些像是“COND”、“if”和“define”的东西 And there were some other things, like COND and "if" and "define". 997 01:09:50,848 --> 01:09:53,248 具体来说 关于“define”的重点则是 But the main thing about "define," in particular, 998 01:09:53,424 --> 01:09:55,264 它是一种进行抽象的方法 was that it was the means of abstraction. 999 01:09:55,280 --> 01:09:57,250 它是我们为某物命名的方法 It was the way that we name things. 1000 01:09:57,340 --> 01:09:59,856 我们之前提到过 从这里也可以看出来 You can also see from this slide not only where we've been, 1001 01:10:01,120 --> 01:10:05,830 有时候 我们需要研究如何通过组合基本数据来得到复合数据 At some point, we'll have to talk about how you combine primitive data to get compound data, 1002 01:10:06,112 --> 01:10:11,584 以及如何抽象数据 使得你可以在一个更大的环境中 and how you abstract data so you can use large globs of data 1003 01:10:11,616 --> 01:10:12,624 将其当作基本数据使用 as if they were primitive. 1004 01:10:13,456 --> 01:10:15,424 这也是我们的目的所在 So that's where we're going. 1005 01:10:15,936 --> 01:10:21,600 在我们讨论这个问题之前 下节课我们首先将会讨论 But before we do that, for the next couple of lectures we're going to be talking about, 1006 01:10:22,816 --> 01:10:26,310 我们编写的过程与机器内部 first of all, how it is that you make a link 1007 01:10:26,432 --> 01:10:30,320 进程之间的联系 between these procedures we write and the processes that happen in the machine. 1008 01:10:31,696 --> 01:10:35,530 接着 我们将跳出小规模的计算问题 And then, how it is that you start using the power of Lisp 1009 01:10:35,936 --> 01:10:39,328 来学习如何发挥Lisp的威力 to talk not only about these individual little computations, 1010 01:10:39,637 --> 01:10:43,701 来解决更加通用的计算问题 but about general conventional methods of doing things. 1011 01:10:44,368 --> 01:10:45,720 好了 大家还有什么问题么 OK, are there any questions? 1012 01:10:46,304 --> 01:10:51,820 学生:在定义A时 如果我们用一个括号将A括起来 AUDIENCE: Yes. If we defined A using parentheses instead of as we did, 1013 01:10:51,872 --> 01:10:53,050 会与不使用括号不同么? what would be the difference? 1014 01:10:53,152 --> 01:10:56,432 教授:如果我这样写 PROFESSOR: If I wrote this, if I wrote that, 1015 01:10:57,088 --> 01:11:01,680 我则会是定义一个过程并命名为A what I would be doing is defining a procedure named A. 1016 01:11:02,768 --> 01:11:06,400 本例中 这个过程没有参数 In this case, a procedure of no arguments, which, 1017 01:11:06,400 --> 01:11:09,160 而当我运行它 则会返回5乘以5 when I ran it, would give me back 5 times 5. 1018 01:11:10,624 --> 01:11:11,840 学生:它们俩完成了相同的事 AUDIENCE: Right. I mean, you come up with the same thing, 1019 01:11:11,872 --> 01:11:13,470 但本质上是否相同? except for you really got a different-- 1020 01:11:13,600 --> 01:11:16,180 教授:好 的确会有不同 之前的那一个 PROFESSOR: Right. And the difference would be, in the old one-- 1021 01:11:16,576 --> 01:11:17,904 我还是在这里写清楚一点吧 Let me be a little bit clearer here. 1022 01:11:18,688 --> 01:11:22,992 我们还是把这个叫做A Let's call this A, like here. 1023 01:11:23,680 --> 01:11:27,312 作为对比 我们假装这里有一个 And pretend here, just for contrast, I wrote, 1024 01:11:27,344 --> 01:11:37,110 我定义D为5乘以5 define D to be the product of 5 and 5. 1025 01:11:39,776 --> 01:11:41,120 这两者的区别则是 And the difference between those, 1026 01:11:41,510 --> 01:11:43,792 让我们看看它们在Lisp解释器中是怎样的 let's think about interactions with the Lisp interpreter. 1027 01:11:45,296 --> 01:11:48,680 我在Lisp中键入A 返回25 I could type in A and Lisp would return 25. 1028 01:11:52,384 --> 01:11:57,360 如果我仅仅键入D I could type in D, if I just typed in D, 1029 01:11:58,048 --> 01:12:05,104 Lisp返回复合过程D Lisp would return compound procedure D, 1030 01:12:06,672 --> 01:12:08,680 因为D就是一个过程 because that's what it is. It's a procedure. 1031 01:12:09,248 --> 01:12:12,144 我可以运行D 我可以问运行D的结果是什么 I could run D. I could say, what's the value of running D? 1032 01:12:12,144 --> 01:12:14,780 这是一个没有运算数的组合式 Here is a combination with no operands. 1033 01:12:16,000 --> 01:12:18,620 我考虑到它没有运算数 所以我在D后面没有键入任何东西 I see there are no operands. I didn't put any after D. 1034 01:12:18,944 --> 01:12:20,890 Lisp则会说结果是25 And it would say, oh, that's 25. 1035 01:12:22,560 --> 01:12:29,072 我再说周全一点 如果我键入 A的运行结果是多少 Or I could say, just for completeness, if I typed in, what's the value of running A? 1036 01:12:29,090 --> 01:12:30,120 只能得到一个错误 I get an error. 1037 01:12:31,344 --> 01:12:34,848 跟这里的错误一样 The error would be the same one as over there. 1038 01:12:34,880 --> 01:12:40,060 这个错误是因为 A的值——25 It'd be the error would say, sorry, 25, which is the value of A, 1039 01:12:40,112 --> 01:12:42,790 并不是我可以应用于某物的运算符 is not an operator that I can apply to something. 1040 01:12:43,392 --> 01:12:48,432 MIT OpenCourseWare http://ocw.mit.edu 1041 01:12:48,688 --> 01:12:54,416 本项目主页 https://github.com/FoOTOo/Learning-SICP ================================================ FILE: SrtCN/lec1b.srt ================================================ 1 00:00:01,840 --> 00:00:02,800 哈尔滨工业大学 IBM技术中心 倾情制作 2 00:00:02,800 --> 00:00:04,800 压制&&特效:蔡钟毓(JohnTitor) 字幕&&时间轴:曹竞帆(ChingfanTsou) 3 00:00:04,800 --> 00:00:06,800 特别感谢:裘宗燕教授 校对:匿名 4 00:00:08,920 --> 00:00:13,080 过程及计算过程: 代换模型 5 00:00:14,160 --> 00:00:14,700 大家好 Hi. 6 00:00:15,960 --> 00:00:17,820 大家都已经知道 程序员的工作 You've seen that the job of a programmer 7 00:00:19,060 --> 00:00:22,080 就是设计出能够达成特定目标的程序 is to design processes that accomplish particular goals, 8 00:00:23,400 --> 00:00:25,200 比如求出一个数的平方根 such as finding the square roots of numbers, 9 00:00:25,940 --> 00:00:27,720 或者其它一些你想要做的事 or other sorts of things you might want to do. 10 00:00:28,460 --> 00:00:30,140 目前为止我们还没介绍别的什么东西 We haven't introduced anything else yet. 11 00:00:31,760 --> 00:00:32,370 当然了 Of course, 12 00:00:32,380 --> 00:00:35,310 程序员完成工作的方式就是构造“咒语” the way in which a programmer does this is by constructing spells, 13 00:00:36,080 --> 00:00:39,960 通过过程和表达式构造出来的“咒语” which are constructed out of procedures and expressions. 14 00:00:40,700 --> 00:00:45,380 这些“咒语”一定程度上指明了 And that these spells are somehow direct a process 15 00:00:45,480 --> 00:00:47,680 程序员想要的达成目标的方式 to accomplish the goal that was intended by the programmer. 16 00:00:48,840 --> 00:00:50,660 程序员为了使整个过程变得高效 In order for the programmer to do this effectively, 17 00:00:50,940 --> 00:00:52,660 必须理解他写下的代码 he has to understand the relationship 18 00:00:52,880 --> 00:00:54,730 这些“咒语” between the particular things that he writes, 19 00:00:54,800 --> 00:00:55,940 和他想要控制的程序的行为 these particular spells, 20 00:00:56,200 --> 00:00:59,020 之间的联系 and the behavior of the process that he's attempting to control. 21 00:01:01,300 --> 00:01:03,180 所以我们在这门课中要做的就是试图 So what we're doing this lecture is attempt to 22 00:01:03,180 --> 00:01:06,000 以尽可能清晰的方式建立这样的联系 establish that connection in as clear a way as possible. 23 00:01:07,260 --> 00:01:09,330 我们尤其要理解 What we will particularly do is understand 24 00:01:09,330 --> 00:01:13,390 特定过程和表达式的模式 how particular patterns of procedures and expressions 25 00:01:14,280 --> 00:01:16,210 将会导致怎样的特定程序执行模式 cause particular patterns of execution, 26 00:01:16,460 --> 00:01:19,000 和计算过程的特定的行为 particular behaviors from the processes. 27 00:01:22,100 --> 00:01:23,230 让我们开始吧 Let's get down to that. 28 00:01:23,860 --> 00:01:25,770 我将会从一个非常简单的程序开始 I'm going to start with a very simple program. 29 00:01:27,920 --> 00:01:31,000 这是一个计算两个数的平方和的程序 This is a program to compute the sum of the squares of two numbers. 30 00:01:33,320 --> 00:01:44,600 我们将x和y的平方和定义为 And we'll define the sum of the squares of x and y to be 31 00:01:45,700 --> 00:01:49,720 x的平方 the sum of the square of x 32 00:01:49,720 --> 00:01:50,780 我这么写 -- I'm going to write it that way-- 33 00:01:51,440 --> 00:01:53,630 加上y的平方的和 and the square of y, 34 00:01:56,260 --> 00:02:11,000 这里的x的平方是指x和x的乘积 where the square of x is the product of x and x. 35 00:02:13,840 --> 00:02:16,080 现在 设想这么一件事 Now,supposing I were to say something to this, 36 00:02:16,780 --> 00:02:19,970 比如 在这个程序这么定义好之后 like,to the system after having defined these things, 37 00:02:20,180 --> 00:02:24,300 跟据定义的形式 求3和4的平方和 of the form,the sum of the squares of 3 and 4, 38 00:02:25,240 --> 00:02:28,560 我希望得到25 I am hoping that I will get out a 25. 39 00:02:29,120 --> 00:02:30,610 因为3的平方是9 Because the square of 3 is 9, 40 00:02:30,610 --> 00:02:31,880 4的平方是16 and the square of 4 is 16, 41 00:02:32,580 --> 00:02:33,970 它们的和是25 and 25 is the sum of those. 42 00:02:34,980 --> 00:02:35,960 但这都是怎么回事呢 But how does that happen? 43 00:02:36,380 --> 00:02:39,660 如果我们要理解程序的执行以及它的控制方法 If we're going to understand processes and how we control them, 44 00:02:39,660 --> 00:02:45,060 那么我们就得把过程的机制 then we have to have a mapping from the mechanisms of this procedure 45 00:02:45,680 --> 00:02:48,260 与过程执行时所产生的行为对应起来 into the way in which these processes behave. 46 00:02:49,160 --> 00:02:50,720 我们将要得到的是一个正式的 What we're going to have is a formal, 47 00:02:50,960 --> 00:02:53,140 或者说半正式的机械的模型 or semi-formal mechanical model, 48 00:02:53,820 --> 00:02:57,280 你要理解计算机如何事实上 大体上实现这个机制 whereby you understand how a machine could,in fact,in principle,do this. 49 00:02:57,600 --> 00:03:00,060 不论实际的计算机究竟是怎么实现的 Whether or not the actual machine really does 50 00:03:00,080 --> 00:03:02,720 我此刻要告诉你们的都与实际的实现完全没有关系 what I'm about to tell you is completely irrelevant at this moment. 51 00:03:03,490 --> 00:03:04,920 实际上 这是一个工程模型 In fact,this is an engineering model 52 00:03:05,440 --> 00:03:07,630 就好像电阻 in the same way that,electrical resistor, 53 00:03:07,840 --> 00:03:09,810 我们写出一个模型V=IR we write down a model v equals i r, 54 00:03:10,360 --> 00:03:11,410 这大致正确 it's approximately true. 55 00:03:12,020 --> 00:03:13,060 但不完全正确的 It's not really true. 56 00:03:13,540 --> 00:03:15,450 当电流通过电阻时 电阻会增加 If I put up current through the resistor it goes boom. 57 00:03:16,560 --> 00:03:19,820 所以电压并不总与电流成线性关系 So the voltage is not always proportional to the current, 58 00:03:20,120 --> 00:03:23,220 但是对于部分情况来说这个模型是适用的 but for some purposes the model is appropriate. 59 00:03:23,860 --> 00:03:26,260 比如我们将要介绍的这个模型 In particular,the model we're going to describe right now, 60 00:03:26,260 --> 00:03:27,850 我把这个模型称作代换模型 which I call the substitution model, 61 00:03:28,180 --> 00:03:30,280 这是我们能接触到的最简单的模型 is the simplest model that we have 62 00:03:30,500 --> 00:03:33,020 它可以帮助我们理解过程和程序执行的原理 for understanding how procedures work and how processes work. 63 00:03:33,770 --> 00:03:35,470 以及过程如何使得程序执行 How procedures yield processes. 64 00:03:36,000 --> 00:03:38,110 代换模型 对接下来几天 And that substitution model will be accurate 65 00:03:38,240 --> 00:03:40,770 我们将要接触到的东西都是适用的 for most of the things we'll be dealing with in the next few days. 66 00:03:41,580 --> 00:03:45,490 但最终 幻想总会破灭 But eventually,it will become impossible to sustain the illusion 67 00:03:45,500 --> 00:03:46,250 如果你认为计算机实际就是这么工作的 that that's the way the machine works, 68 00:03:46,490 --> 00:03:49,600 并且我们将要学习其它的更特殊的模型 and we'll go to other more specific and particular models 69 00:03:49,920 --> 00:03:51,020 届时会讨论更多的细节 that will show more detail. 70 00:03:53,200 --> 00:03:57,640 好了 接下来 我们来看下 OK,well,the first thing,of course,is we say, 71 00:03:57,640 --> 00:03:58,780 黑板上的这些内容 what are the things we have here? 72 00:03:58,780 --> 00:04:00,030 这里已经有了一些神秘的符号 We have some cryptic symbols. 73 00:04:00,900 --> 00:04:03,770 这些神秘的符号是由几块组成的 And these cryptic symbols are made out of pieces. 74 00:04:04,090 --> 00:04:05,380 还有几种表达式 There are kinds of expressions. 75 00:04:05,720 --> 00:04:08,100 现在我们看一看都有哪些类型的表达式 So let's write down here the kinds of expressions there are. 76 00:04:17,580 --> 00:04:18,180 有 And we have-- 77 00:04:18,260 --> 00:04:20,180 首先有数字 and so far I see things like numbers. 78 00:04:25,060 --> 00:04:27,550 有像那样的符号 I see things like symbols like that. 79 00:04:31,790 --> 00:04:34,940 我们之前见过Lambda表达式 We have seen things before like lambda expressions, 80 00:04:34,940 --> 00:04:36,760 当然了没出现在黑板上 先撇开不谈 but they're not here.I'm going to leave them out. 81 00:04:36,800 --> 00:04:39,260 Lambda表达式 稍后再讨论 Lambda expressions,we'll worry about them later. 82 00:04:44,500 --> 00:04:45,640 还有定义 Things like definitions. 83 00:04:51,550 --> 00:04:52,660 还有条件表达式 Things like conditionals. 84 00:04:58,040 --> 00:05:00,050 最后还有组合式 And finally,things like combinations. 85 00:05:06,660 --> 00:05:09,050 这些表达式 These kinds of expressions are 86 00:05:10,090 --> 00:05:14,090 我们稍后再讨论 它们是特殊形式 -- I'll worry about later-- these are special forms. 87 00:05:14,740 --> 00:05:16,920 它们有一些专门的规则 There are particular rules for each of these. 88 00:05:17,320 --> 00:05:20,420 然而我要告诉你们的是 处理通常情况的规则 I'm going to tell you,however,the rules for doing a general case. 89 00:05:20,750 --> 00:05:22,370 通常是怎样对一个组合式求值的 How does one evaluate a combination? 90 00:05:23,200 --> 00:05:24,370 因为 实际上 在黑板的那边 Because,in fact,over here, 91 00:05:24,760 --> 00:05:27,800 全都是一些组合式以及一些符号和数字 all I really have are combinations and some symbols and numbers. 92 00:05:28,990 --> 00:05:30,610 而简单的 比如一个数字 And the simple things like a number,well, 93 00:05:30,610 --> 00:05:32,090 求值的结果就是这个数字所代表的数值 it will evaluate to itself. 94 00:05:33,000 --> 00:05:34,680 在我将要介绍的模型中 In the model I will have for you, 95 00:05:34,700 --> 00:05:35,860 符号的概念将不会出现 the symbols will disappear. 96 00:05:36,810 --> 00:05:39,450 只有当你需要了解 They won't be there at the time when you need them, 97 00:05:39,450 --> 00:05:40,970 当你需要真正理解它的时候才讨论 when you need to get at them. 98 00:05:41,420 --> 00:05:43,530 所以我只需要向大家讲解 So the only thing I really have to explain to you is, 99 00:05:43,530 --> 00:05:44,850 如何对组合式求值 how do we evaluate combinations? 100 00:05:47,950 --> 00:05:49,010 好吧 继续 OK,let's see 101 00:05:50,010 --> 00:05:52,540 先看下第一张幻灯片 So first I want to get the first slide. 102 00:05:53,310 --> 00:05:58,440 这是对一个表达式求值的规则 Here is the rule for evaluating an application. 103 00:06:01,040 --> 00:06:06,140 我们看到这条规则指出 What we have is a rule that says, 104 00:06:06,140 --> 00:06:07,050 要对一个组合式求值 to evaluate a combination, 105 00:06:07,050 --> 00:06:08,900 主要有三个部分 there are two parts,three parts to the rule. 106 00:06:09,540 --> 00:06:11,790 组合式有若干个部分 The combination has several parts. 107 00:06:12,020 --> 00:06:15,090 有运算符和运算对象 It has operators and it has operands. 108 00:06:16,420 --> 00:06:19,060 运算符返回一个过程 The operator returns into a procedure. 109 00:06:19,810 --> 00:06:20,910 也就是说如果我们对运算符求值 If we evaluate the operator, 110 00:06:20,930 --> 00:06:21,890 结果是一个过程 we will get a procedure. 111 00:06:22,100 --> 00:06:23,200 比如你们也看到了 And you saw,for example, 112 00:06:23,200 --> 00:06:24,980 我向计算机输入一个“+” how I'll type "+" at the machine 113 00:06:24,980 --> 00:06:27,170 然后产生了一些复合的过程以及其它的一些东西 and out came compound procedure something or other. 114 00:06:28,520 --> 00:06:30,260 而对运算对象求值就会得到参数 And the operands produce arguments. 115 00:06:31,620 --> 00:06:35,250 一旦我们完成了对运算符的求值得到了一个过程 Once we've gotten the operator evaluated to get a procedure, 116 00:06:35,250 --> 00:06:37,540 并且对运算对象也完成求值得到了参数 and the argument is evaluated to get argument 117 00:06:37,550 --> 00:06:39,090 也就是运算对象作为参数的值 -- the operand's value to get arguments-- 118 00:06:39,090 --> 00:06:41,170 我们通过复制过程体 we apply the procedure to these arguments 119 00:06:41,880 --> 00:06:43,950 来将其应用到这些参数上 by copying the body of the procedure, 120 00:06:44,240 --> 00:06:46,940 用术语来说 过程体指的就是定义这个过程的表达式 which is the expression that the procedure is defined in terms of. 121 00:06:47,220 --> 00:06:48,570 接下来要做的是 What is it supposed to do? 122 00:06:49,280 --> 00:06:53,950 用求得的实际参数代换过程的形式参数 Substituting the argument supplied for the formal parameters of the procedure, 123 00:06:54,680 --> 00:06:56,220 形式参数就是 the formal parameters being the names 124 00:06:56,220 --> 00:06:58,220 过程定义中声明的变量名 defined by the declaration of the procedure. 125 00:06:58,760 --> 00:07:00,850 然后我们对产生的新过程体求值 Then we evaluate the resulting new body, 126 00:07:01,020 --> 00:07:04,770 这个新过程体是由将代换模型应用到之前的过程体而产生的 the body resulting from copying the old body with the substitutions made. 127 00:07:06,990 --> 00:07:08,270 这个规则非常简单 It's a very simple rule, 128 00:07:09,370 --> 00:07:11,650 并且我们会非常形式化地应用这个规则一段时间 and we're going to do it very formally for a little while. 129 00:07:11,980 --> 00:07:14,420 因为接下来几节课 Because for the next few lectures, 130 00:07:14,730 --> 00:07:15,740 我想让各位做的是 what I want you to do is to say, 131 00:07:15,740 --> 00:07:18,930 如果有什么不能理解的 if I don't understand something,if I don't understand something, 132 00:07:19,280 --> 00:07:20,930 就直接机械化地应用这个规则 be very mechanical and do this. 133 00:07:23,570 --> 00:07:24,160 接下来 So let's see. 134 00:07:25,970 --> 00:07:27,630 考虑这么一个求值过程 Let's consider a particular evaluation, 135 00:07:27,740 --> 00:07:28,990 之前讨论过的 the one we were talking about before. 136 00:07:29,210 --> 00:07:32,960 3和4的平方和 The sum of the squares of 3 and 4. 137 00:07:35,560 --> 00:07:36,660 这是什么意思呢 What does that mean? 138 00:07:36,660 --> 00:07:37,760 这是说 It says,take 139 00:07:38,260 --> 00:07:40,660 其实 我已经知道求平方的过程是怎样的 -- well,I could find out what's on the square-- 140 00:07:40,660 --> 00:07:41,860 是某个过程 it's some procedure, 141 00:07:42,140 --> 00:07:43,710 但我并不关心这个过程的具体表述 and I'm not going to worry about the representation, 142 00:07:43,710 --> 00:07:45,710 并且我也不会在黑板上写出来 and I'm not going to write it on the blackboard for you. 143 00:07:46,810 --> 00:07:48,530 还有3 代表某个数字 And I have that 3,represents some number, 144 00:07:49,250 --> 00:07:51,360 但如果要我重复这个数字 but if I have to repeat that number, 145 00:07:51,360 --> 00:07:52,280 我并不知道这个数字是什么 I can't tell you the number. 146 00:07:52,410 --> 00:07:54,190 这个数字本身是抽象的 The number itself is some abstract thing. 147 00:07:54,490 --> 00:07:55,860 只知道有个数词能代表它 There's a numeral which represents it, 148 00:07:55,890 --> 00:07:56,690 我把这个它叫作3 which I'll call 3, 149 00:07:56,960 --> 00:07:59,000 并且会在代换中用到它 and I'll use that in my substitution. 150 00:07:59,370 --> 00:08:01,400 4也是个数字 And 4 is also a number. 151 00:08:01,570 --> 00:08:07,680 我在这个过程体中用3代换x 用4代换y I'm going to substitute 3 for x and 4 for y in the body of this procedure 152 00:08:07,680 --> 00:08:08,570 看黑板这里 that you see over here. 153 00:08:09,170 --> 00:08:10,580 这是过程体 Here's the body of the procedure. 154 00:08:11,180 --> 00:08:13,780 它关联到这个组合式 It corresponds to this combination, 155 00:08:13,790 --> 00:08:14,520 这个组合式是个求和过程 which is an addition. 156 00:08:17,160 --> 00:08:18,480 而它就转化成这样一个过程 So what that reduces to, 157 00:08:18,820 --> 00:08:19,870 我们把这个转化 as a reduction step, 158 00:08:19,870 --> 00:08:20,370 称为归约 we call it, 159 00:08:20,670 --> 00:08:28,740 这样就变成了求3和4的平方和 it's the sum of the square of 3 and the square of 4. 160 00:08:30,000 --> 00:08:33,710 接下来我要做的是 Now,what's the next step I have to do here? 161 00:08:33,710 --> 00:08:35,710 对它求值 I say,well,I have to evaluate this. 162 00:08:35,710 --> 00:08:37,010 根据之前给出的求值规则 According to my rule, 163 00:08:37,010 --> 00:08:40,640 就是各位刚刚在幻灯片上看到的 which you just saw on that overhead or slide, 164 00:08:41,410 --> 00:08:45,780 我们要对运算对象求值 what we had was that we have to evaluate the operands 165 00:08:45,930 --> 00:08:47,080 就是这些运算对象 -- and here are the operands, 166 00:08:47,340 --> 00:08:49,080 这是第一个运算对象 这是第二个运算对象 here's one and here's the next operand-- 167 00:08:49,400 --> 00:08:50,770 我们还得对运算符求值 and how we have to evaluate procedure. 168 00:08:50,770 --> 00:08:51,850 对它们求值的顺序无关紧要 The order doesn't matter. 169 00:08:52,510 --> 00:08:55,710 然后我们要应用这个过程 And then we're going to apply the procedure, 170 00:08:55,710 --> 00:08:56,280 即求和过程 which is plus, 171 00:08:56,280 --> 00:08:58,620 然后很神奇的 不知怎么回事就能得到答案 and magically somehow that's going to produce the answer. 172 00:08:58,880 --> 00:09:01,050 我不会深究求和过程的实现 I'm not to open up plus and look inside of it. 173 00:09:02,140 --> 00:09:04,500 然而 为了对运算对象求值 However,in order to evaluate the operand, 174 00:09:04,510 --> 00:09:05,970 我们采用任意一种顺序来求值 let's pick some arbitrary order and do them. 175 00:09:06,430 --> 00:09:07,580 我会从右到左求值 I'm going to go from right to left. 176 00:09:08,190 --> 00:09:09,840 好了 为了对这个运算对象求值 Well,in order to evaluate this operand, 177 00:09:09,840 --> 00:09:13,410 我得用同样的规则对这运算对象的每个部分求值 I have to evaluate the parts of it by the same rule. 178 00:09:13,970 --> 00:09:15,850 首先需要弄清楚求平方是什么 And the parts are I have to find out what square is-- 179 00:09:15,850 --> 00:09:16,580 是某个过程 it's some procedure, 180 00:09:16,580 --> 00:09:18,120 有个形式参数x which has a formal parameter x. 181 00:09:19,180 --> 00:09:22,580 然后还有个运算对象是4 And also,I have an operand which is 4, 182 00:09:23,560 --> 00:09:27,550 用4代换求平方过程的形式参数x which I have to substitute for x in the body of square. 183 00:09:28,410 --> 00:09:30,370 接下来基本上可以这么说 So the next step is basically to say that 184 00:09:30,370 --> 00:09:38,180 这就变成了求3的平方以及4与4乘积的和 this is the sum of the square of 3 and the product of 4 and 4. 185 00:09:40,600 --> 00:09:43,710 当然了 还可以接着深入分析乘法 Of course,I could open up asterisk if I liked 186 00:09:43,720 --> 00:09:45,970 这个求乘积的操作 -- the multiplication operation-- 187 00:09:46,680 --> 00:09:47,480 但现在这个不重要 but I'm not going to do that. 188 00:09:47,500 --> 00:09:48,610 先把乘法过程看作是基本过程 I'm going to consider that primitive. 189 00:09:49,790 --> 00:09:53,250 其实 如果你深究计算机的抽象层次 So,and,of course,at any level of detail,if you look inside this machine, 190 00:09:53,250 --> 00:09:54,320 你会发现无论在具体哪一个层次 you're going to find that 191 00:09:54,320 --> 00:09:56,820 在其下都还有若干个你不清楚的抽象层次 there's multiple levels below that that you don't know about. 192 00:09:57,980 --> 00:10:00,650 但我们必须明白要学会忽略细节 But one of the things we have to learn how to do is ignore details. 193 00:10:01,980 --> 00:10:03,960 理解复杂事物的关键是 The key to understanding complicated things 194 00:10:04,280 --> 00:10:08,290 避免不必要的观察 计算和思考 is to know what not to look at and what not compute and what not to think. 195 00:10:09,260 --> 00:10:10,840 所以对这个乘法过程的细节我们不深入研究 So we're going to stop this one here and say, 196 00:10:10,840 --> 00:10:13,560 就直接看作两个数的乘积 oh,yes,this is the product of two things. 197 00:10:13,970 --> 00:10:15,000 现在把两个4乘起来 We're going to do it now. 198 00:10:15,660 --> 00:10:22,320 于是就有3的平方与16的和 So this is nothing more than the sum of the square of 3 and 16. 199 00:10:22,960 --> 00:10:25,640 还有一个求平方的表达式要求值 And now I have another thing I have to evaluate, 200 00:10:27,010 --> 00:10:28,120 注意这是3的平方 but that square of 3, 201 00:10:28,120 --> 00:10:29,080 这与之前求4的平方是一个过程 well,it's the same thing. 202 00:10:29,080 --> 00:10:35,200 于是整个表达式就变成了求3和3乘积与16的和 That's the sum of the product of 3 and 3 and 16, 203 00:10:35,960 --> 00:10:41,810 也就是求9和16的和 结果是25 which is the sum of 9 and 16,which is 25. 204 00:10:44,500 --> 00:10:48,570 大家现在看到了应用代换模型的基本方法 So now you see the basic method of doing substitutions. 205 00:10:49,800 --> 00:10:51,730 但我提醒大家 And I warn you that 206 00:10:52,110 --> 00:10:55,410 代换模型并不能准确描述计算机实际的运行方式 this is not a perfect description of what the computer does. 207 00:10:56,800 --> 00:10:58,200 但这个模型对于接下来几节课我们要讨论的问题 But it's a good enough description 208 00:10:58,200 --> 00:11:02,000 已经可以描述得足够清楚 for the problems that we're going to have in the next few lectures 209 00:11:02,510 --> 00:11:04,120 你可以先认为这是正确的 that you should think about this religiously. 210 00:11:04,820 --> 00:11:07,230 认为计算机就是这么运行的 And this is how the machine works for now. 211 00:11:07,520 --> 00:11:08,920 之后我们的讨论会变得更加严谨 Later we'll get more detailed. 212 00:11:11,700 --> 00:11:12,280 好了 现在可以看到 Now,of course, 213 00:11:12,280 --> 00:11:15,020 我在这个例子中采用了从右到左的求值顺序 I made a specific choice of the order of evaluation here. 214 00:11:15,530 --> 00:11:16,530 当然还有别的选择 There are other possibilities. 215 00:11:17,020 --> 00:11:20,580 如果我们回过头来再看幻灯片 If we go back to this,ah,to the telestrator here 216 00:11:20,580 --> 00:11:21,870 上所写的代换模型应用规则 and look at the substitution rule, 217 00:11:22,800 --> 00:11:25,650 可以发现刚才我对运算符求值得到了一个过程 we see that I evaluated the operator to get the procedures, 218 00:11:25,900 --> 00:11:28,690 对运算对象求值得到了过程的实际参数 and I evaluated the operands to get the arguments first, 219 00:11:28,690 --> 00:11:29,950 然后才将参数应用到过程 before I do the application. 220 00:11:30,730 --> 00:11:32,030 这样做是完全可行的 It's entirely possible, 221 00:11:32,030 --> 00:11:34,650 还有别的求值顺序比如正则序求值 and there are alternate rules called normal order evaluation 222 00:11:35,020 --> 00:11:37,470 应用正则序你可以先用表达式去代换 whereby you can do the substitution of the expressions 223 00:11:37,470 --> 00:11:44,640 将其作为过程的形式参数的运算对象 然后再求值 which are the operands for the formal parameters inside the body first. 224 00:11:45,970 --> 00:11:47,650 这么做会得到同样的答案 And you'll get also the same answer. 225 00:11:48,560 --> 00:11:50,110 但是现在 考虑到实际情况 But right now,for concreteness, 226 00:11:50,110 --> 00:11:52,240 因为计算机实际是这么运行的 and because this is the way our machine really does it, 227 00:11:52,900 --> 00:11:54,000 我还是会给出在黑板上演示的方式 I'm going to give you this rule, 228 00:11:54,000 --> 00:11:55,130 这种方式给出了明确的顺序 which has a particular order. 229 00:11:56,120 --> 00:11:58,140 当然了这些顺序一定程度上也是灵活可变的 But that order is to some extent arbitrary,too. 230 00:11:59,620 --> 00:12:01,340 归根到底 In the long run,in the long run, 231 00:12:01,340 --> 00:12:03,760 采用哪种求值顺序来理解 都有各自的依据 there are some reasons why you might pick one order or another, 232 00:12:03,760 --> 00:12:05,760 以后我们会继续讨论这个问题 and we'll get to that later in the subject. 233 00:12:11,930 --> 00:12:15,130 好了 为了让大家理解这都是怎么回事 OK,well now the only other thing I have to tell you about 234 00:12:15,150 --> 00:12:16,420 还需要给大家介绍一个东西 ejust to understand what's going on 235 00:12:16,440 --> 00:12:18,670 来看幻灯片上对条件表达式的解释 is let's look at the rule for conditionals. 236 00:12:19,470 --> 00:12:21,620 条件表达式很简单 Conditionals are very simple, 237 00:12:22,490 --> 00:12:25,440 我给大家详细解释一下 and I'd like to examine this. 238 00:12:26,890 --> 00:12:31,380 条件表达式就是if表达式 A conditional is something that is if 239 00:12:31,980 --> 00:12:33,380 当然还有cond表达式 -- there's also cond of course-- 240 00:12:33,570 --> 00:12:35,700 我会把条件表达式各部分的名称都写下来 but I'm going to give names to the parts of the expression. 241 00:12:35,700 --> 00:12:36,490 首先有一个判断表达式 There's a predicate, 242 00:12:38,080 --> 00:12:40,050 这是个求值结果为真或假的表达式 which is a thing that is either true or false. 243 00:12:41,010 --> 00:12:42,010 然后有一个结果子句 And there's a consequent, 244 00:12:45,600 --> 00:12:47,490 当判断表达式的结果为真就对这个表达式求值 which is the thing you do if the predicate is true. 245 00:12:48,010 --> 00:12:49,020 还有个选择表达式 And there's an alternative, 246 00:12:52,520 --> 00:12:54,610 当判断表达式结果为假 就对这个表达式求值 which is the thing you do if the predicate is false. 247 00:12:55,090 --> 00:12:56,350 顺便提一句 It's important,by the way, 248 00:12:56,760 --> 00:12:59,960 知道事物各部分的名称 to get names for,to get names for, 249 00:13:00,260 --> 00:13:01,390 或者表达式各部分的名称 the parts of things, 250 00:13:01,390 --> 00:13:02,730 很重要 or the parts of expressions. 251 00:13:03,420 --> 00:13:05,660 每个“魔法师”都会告诉你 One of the things that every sorcerer will tell you 252 00:13:05,690 --> 00:13:07,140 如果你能叫出一个“精灵”的名字 is if you have the name of a spirit, 253 00:13:07,140 --> 00:13:08,110 你就有控制它的能力 you have power over it. 254 00:13:10,050 --> 00:13:11,080 所以你得掌握这些名称 So you have to learn these names 255 00:13:11,080 --> 00:13:12,560 以便之后的讨论 so that we can discuss these things. 256 00:13:13,370 --> 00:13:15,410 现在我们有了一个判断表达式 So here we have a predicate, 257 00:13:15,410 --> 00:13:16,100 一个结果表达式 a consequent, 258 00:13:16,100 --> 00:13:16,810 还有个选择表达式 and an alternative. 259 00:13:17,420 --> 00:13:21,060 用这些名称 我们发现对于一个if表达式 And,using such words,we see that an if expression, 260 00:13:21,360 --> 00:13:23,500 关键的问题是对判断表达式的求值 the problems you evaluate to the predicate expression, 261 00:13:24,360 --> 00:13:25,580 如果结果为真 if that yields true, 262 00:13:26,840 --> 00:13:28,860 就对结果表达式求值 then you then go on to evaluate the consequent. 263 00:13:29,280 --> 00:13:31,920 否则 就对选择表达式求值 Otherwise,you evaluate the alternative expression. 264 00:13:34,530 --> 00:13:35,840 我想通过一个具体的程序 So I'd like to illustrate that 265 00:13:36,170 --> 00:13:42,250 来进一步说明这个问题 now in the context of a particular,of a particular,little program. 266 00:13:43,200 --> 00:13:45,280 就写一个我们会经常遇到的程序吧 Going to write down a program which we're going to see many times. 267 00:13:51,470 --> 00:13:58,430 这是由皮亚诺算术定义的求x和y之和的过程 This is the sum of x and y done by what's called Peano arithmetic, 268 00:13:58,430 --> 00:14:00,430 其实就是加1和减1 which is all we're doing is incrementing and decrementing. 269 00:14:01,500 --> 00:14:02,660 来看看这个 And we're going to see this for a little bit. 270 00:14:02,660 --> 00:14:03,980 这是个非常重要的程序 It's a very important program. 271 00:14:06,020 --> 00:14:07,120 如果x等于0 If x equals 0, 272 00:14:09,680 --> 00:14:11,260 那么结果就是y then the result is y. 273 00:14:11,580 --> 00:14:12,270 否则 Otherwise, 274 00:14:12,270 --> 00:14:20,350 结果就是x减1与y加1的和 this is the sum of the decrement of x and the increment of y. 275 00:14:23,220 --> 00:14:26,110 以后我们会继续研究这个加法过程 We're going to look at this a lot more in the future. 276 00:14:27,580 --> 00:14:28,740 现在看前面 Let's look at the overhead. 277 00:14:28,980 --> 00:14:31,090 现在有了这么个过程 So here we have this procedure, 278 00:14:31,090 --> 00:14:33,180 我们看看怎么应用代换模型 and we're going to look at how we do the substitutions, 279 00:14:33,180 --> 00:14:34,270 以及代换的顺序 the sequence of substitutions. 280 00:14:35,760 --> 00:14:37,700 我现在想要求3和4的和 Well,I'm going to try and add together 3 and 4. 281 00:14:38,280 --> 00:14:40,200 根据我演示给大家步骤 Well,using the first rule that I showed you, 282 00:14:40,420 --> 00:14:43,900 第一步 在过程体中 we substitute 3 for x and 4 four y 283 00:14:44,180 --> 00:14:45,620 用3代换x 用4代换y in the body of this procedure. 284 00:14:45,800 --> 00:14:47,360 过程体 The body of the procedure is the thing 285 00:14:47,360 --> 00:14:49,690 由if表达式开始 在这儿结束 that begins with if and finishes over here. 286 00:14:51,020 --> 00:14:51,940 于是我们就有了 So what we get is, 287 00:14:51,940 --> 00:14:53,390 如果3是0 of course,if 3 is 0, 288 00:14:53,390 --> 00:14:54,600 那么结果就是4 then the result is 4. 289 00:14:55,570 --> 00:14:56,350 否则 Otherwise, 290 00:14:56,450 --> 00:14:58,360 结果就是3减1 it's the sum of the decrement of 3 291 00:14:58,360 --> 00:14:59,320 与4加1的和 and the increment of 4. 292 00:15:01,080 --> 00:15:02,490 但这部份我不会去管它 But I'm not going to worry about these yet 293 00:15:03,020 --> 00:15:04,820 因为3不等于0 because 3 is not 0. 294 00:15:05,290 --> 00:15:06,540 于是答案不是4 So the answer is not 4. 295 00:15:07,970 --> 00:15:08,430 因此 Therefore, 296 00:15:08,450 --> 00:15:10,960 于是整个if表达式就可以归约成 this if reduces to 297 00:15:10,960 --> 00:15:12,610 对这个表达式的求值 an evaluation of the expression, 298 00:15:12,850 --> 00:15:14,010 求3减1 the sum to the decrement of 3 299 00:15:14,010 --> 00:15:14,920 与4加1的和 and the increment of 4. 300 00:15:16,580 --> 00:15:17,800 继续求值 Continuing with my evaluation, 301 00:15:17,800 --> 00:15:19,800 先认为加1的过程是基本过程 the increment I presume to be primitive, 302 00:15:20,380 --> 00:15:21,800 然后就有了5 and so I get a 5 there. 303 00:15:22,680 --> 00:15:24,530 同样把减1也认为是基本过程 OK,and then the decrement is also primitive, 304 00:15:24,530 --> 00:15:25,330 然后就有了2 and I get a 2. 305 00:15:25,680 --> 00:15:28,080 于是我把问题化简了 And so I change the problem into a simpler problem. 306 00:15:28,080 --> 00:15:30,080 不是3加4的问题了 Instead of adding 3 to 4, 307 00:15:30,840 --> 00:15:32,080 而是2加5的问题了 I'm adding 2 to 5. 308 00:15:33,130 --> 00:15:34,600 为什么这样就变简单了呢 The reason why this is a simpler problem 309 00:15:34,600 --> 00:15:37,310 因为我在减小x is because I'm counting down on x, 310 00:15:37,780 --> 00:15:40,160 最终x会变为0 and eventually,then,x will be 0. 311 00:15:43,070 --> 00:15:44,990 这就是代换模型了 So,so much for the substitution rule. 312 00:15:45,690 --> 00:15:46,420 通常来讲 In general, 313 00:15:46,420 --> 00:15:48,900 在对if表达式使用代换模型的时候 I'm not going to write down intermediate steps 314 00:15:48,900 --> 00:15:50,900 我不会写下所有中间步骤 when using substitutions having to do with ifs, 315 00:15:51,500 --> 00:15:54,660 因为这么做只能把事情复杂化 because they just expand things to become complicated. 316 00:15:55,120 --> 00:15:56,400 我们要做的是 What we will be doing is saying, 317 00:15:56,400 --> 00:15:58,190 把求3和4的和 oh,yes,the sum of 3 and 4 318 00:15:58,190 --> 00:16:00,780 归约到求2和5的和 results in the sum of 2 and 5 319 00:16:01,390 --> 00:16:02,920 在那之后 and reduces to the sum of 2 and 5. 320 00:16:03,160 --> 00:16:06,040 归约到求1和6的和 which,in fact,reduces to the sum of 1 and 6, 321 00:16:06,740 --> 00:16:09,700 最后归约到求0和7的和 which reduces to the sum of 0 and 7 322 00:16:09,700 --> 00:16:10,360 看这儿 over here, 323 00:16:10,860 --> 00:16:11,960 最后归约到7 which reduces to a 7. 324 00:16:13,730 --> 00:16:14,680 这就是我们想要的结果 That's what we're going to be seeing. 325 00:16:16,180 --> 00:16:17,850 现在 各位对第一部分的内容有疑问么 Are there any questions for the first segment yet? 326 00:16:20,180 --> 00:16:20,680 有吗 Yes? 327 00:16:21,010 --> 00:16:23,530 学生 你用了1+过程和-1+过程 STUDENT: You're using 1 plus and minus 1 plus 328 00:16:23,530 --> 00:16:25,460 它们都是基本过程么 Are those primitive operations? 329 00:16:25,460 --> 00:16:26,100 教授 是的 PROFESSOR: Yes 330 00:16:26,410 --> 00:16:28,450 你们在这门课中要明白的是 One of the things you're going to be seeing in this subject 331 00:16:28,970 --> 00:16:32,110 我绝对不会考虑 is I'm going to,without thinking about it, 332 00:16:32,260 --> 00:16:35,680 给大家介绍越来越多的基本过程 introduce more and more primitive operations 333 00:16:35,920 --> 00:16:37,710 可以假定 There's presumably some large library 334 00:16:37,710 --> 00:16:39,260 有一些庞大的基本过程的程序库 of primitive operations somewhere. 335 00:16:39,450 --> 00:16:41,100 不用过分追究这些基本过程 But it doesn't matter that they're primitive-- 336 00:16:41,100 --> 00:16:43,100 可能有一些手册有这些基本过程的索引 便于我们查找 there may be some manual that lists them all. 337 00:16:43,100 --> 00:16:44,860 如果我向你解释基本过程的作用 你应该说 If I tell you what they do,you should say, 338 00:16:44,860 --> 00:16:46,300 啊 是这样 我明白它们的作用了 oh,yes,I know what they do. 339 00:16:46,660 --> 00:16:48,300 比如 这个减1的过程 So one of them is the decrementor 340 00:16:48,670 --> 00:16:49,490 -1+ -- minus 1 plus-- 341 00:16:49,790 --> 00:16:50,890 另一个加1的过程 and the other operation is increment, 342 00:16:50,890 --> 00:16:51,780 1+ which is 1 plus. 343 00:16:53,140 --> 00:16:53,480 谢谢大家 Thank you. 344 00:16:53,490 --> 00:16:54,900 第一部分结束 That's the end of the first segment. 345 00:17:05,540 --> 00:17:19,170 [音乐] [MUSIC PLAYING BY J.S. BACH] 346 00:17:19,310 --> 00:17:21,540 教授 现在我们有了一个合理的 机械的方式 PROFESSOR: Now that we have a reasonably mechanical way 347 00:17:21,540 --> 00:17:27,300 去理解一个由过程 of understanding how a program made out of procedures 348 00:17:27,300 --> 00:17:30,700 和表达式组成的程序是如何演化成计算过程的 and expressions evolves a process, 349 00:17:31,160 --> 00:17:32,700 我想要大家培养出一些直觉 I'd like to develop some intuition 350 00:17:33,460 --> 00:17:37,150 有关程序如何演化成计算过程的直觉 about how particular programs evolve particular processes, 351 00:17:37,380 --> 00:17:39,150 有关程序到底是什么“形状”的直觉 what the shapes of programs have to be 352 00:17:39,150 --> 00:17:41,150 这样才能产生特定“形状”的计算过程 in order to get particular shaped processes. 353 00:17:42,430 --> 00:17:46,000 这让我想到了 画面预览 This is a question about,really,pre-visualizing. 354 00:17:47,140 --> 00:17:48,670 这是个摄影专业术语 That's a word from photography. 355 00:17:48,670 --> 00:17:51,020 我曾经对摄影十分着迷 I used to be interested in photography a lot, 356 00:17:51,890 --> 00:17:53,700 你会发现 and one of the things you discover 357 00:17:53,700 --> 00:17:55,250 初学摄影的时候 when you start trying to learn about photography 358 00:17:55,250 --> 00:17:57,860 你很想成为一名有创意的摄影师 is that you say,gee,I'd like to be a creative photographer. 359 00:17:58,520 --> 00:18:00,100 我知道怎么做 按快门 Now,I know the rules,I push buttons, 360 00:18:00,100 --> 00:18:02,800 调整光圈什么的 and I adjust the aperture and things like that. 361 00:18:03,140 --> 00:18:06,320 但要想有创意 But the key to being a creative person,partly, 362 00:18:06,320 --> 00:18:09,400 一定程度上靠的是能在一定层次上进行分析 is to be able to do analysis at some level. 363 00:18:09,400 --> 00:18:12,540 比如 在按下快门前 To say,how do I know what it is 364 00:18:12,540 --> 00:18:15,320 我怎么知道交卷上最终是怎样的画面呢 that I'm going to get on the film before I push the button. 365 00:18:16,920 --> 00:18:18,770 我能在心中 Can I imagine in my mind 366 00:18:20,290 --> 00:18:23,340 非常准确清晰地刻画出拍好的照片么 the resulting image very precisely and clearly 367 00:18:24,970 --> 00:18:27,700 那精心地取景 as a consequence of the particular framing, 368 00:18:27,700 --> 00:18:29,120 仔细地调整光圈 of the aperture I choose, 369 00:18:29,120 --> 00:18:30,140 仔细地对焦 of the focus, 370 00:18:30,140 --> 00:18:31,210 而拍出来的照片 and things like that? 371 00:18:32,480 --> 00:18:35,070 一定程度来说 这就是摄影的艺术 That's part of the art of doing this sort of thing. 372 00:18:35,600 --> 00:18:38,480 而要掌握摄影的艺术牵涉到许多方面 And a lot of that involves,learning a lot of that 373 00:18:38,480 --> 00:18:40,050 比如曝光试验片 involves things like test strips. 374 00:18:40,580 --> 00:18:42,400 比如拍摄非常几张简单的画面 You take very simple images 375 00:18:42,970 --> 00:18:46,050 每张都有不同的影像密度 that have varying degrees of density in them,for example, 376 00:18:46,340 --> 00:18:49,330 然后把它们打印在一张纸上 and examine what those look like on a piece of paper 377 00:18:49,330 --> 00:18:50,190 观察它们都有什么不同 when you print them out. 378 00:18:51,180 --> 00:18:53,520 你能发现实际可见的对比度 You find out what is the range of contrasts 379 00:18:53,520 --> 00:18:54,610 都是怎样的范围内 that you can actually see. 380 00:18:55,470 --> 00:18:56,880 还能发现 从实际角度来讲 And what,in a real scene, 381 00:18:56,880 --> 00:18:59,160 都是哪些因素与同一张照片中不同层次 would correspond to the various levels 382 00:18:59,160 --> 00:19:03,640 不同区块的影像密度的产生有关 and zones that you have of density in an image. 383 00:19:05,020 --> 00:19:08,540 今天这节课我就想让大家看一些特别的 “曝光试验片” Well,today I want to look at some very particular test strips, 384 00:19:09,290 --> 00:19:12,280 下面通过幻灯片来看第一张 and I suppose one of them I see here is up on the telestrator, 385 00:19:12,280 --> 00:19:14,040 请看 so we should switch to that. 386 00:19:14,810 --> 00:19:18,840 有两个非常非常重要的程序 There's a very important,very important pair of programs 387 00:19:18,840 --> 00:19:24,050 用来理解在程序执行时 for understanding what's going on in the evolution of a process 388 00:19:24,190 --> 00:19:25,600 计算过程中的求值都是怎样的 by the execution of a program. 389 00:19:26,900 --> 00:19:30,010 大家看到的是两个几乎相同的过程 What we have here are two procedures that are almost identical. 390 00:19:32,110 --> 00:19:34,580 基本上没有区别 Almost no difference between them at all. 391 00:19:35,080 --> 00:19:37,260 只有几个字符不同 It's a few characters that distinguish them. 392 00:19:38,610 --> 00:19:41,010 这两个过程表示的是 两种不同的求两数之和的方法 These are two ways of adding numbers together. 393 00:19:42,110 --> 00:19:43,010 第一个 The first one, 394 00:19:43,610 --> 00:19:45,700 看这里 which you see here, 395 00:19:46,170 --> 00:19:48,900 是求两数之和 the first one is the sum of two numbers 396 00:19:48,900 --> 00:19:49,940 和我们上节课讲到的一样 -- just what we did before-- 397 00:19:50,440 --> 00:19:51,650 如果第一个参数是0 is if the first one is 0, 398 00:19:51,650 --> 00:19:52,960 第二个参数就是答案 it's the answer of the second one. 399 00:19:53,210 --> 00:19:53,840 否则 Otherwise, 400 00:19:53,840 --> 00:19:55,840 就是第一个参数减1 it's the sum of the decrement of the first 401 00:19:55,840 --> 00:19:56,940 和第二个参数加1的和 and the increment of the second. 402 00:19:57,610 --> 00:20:03,360 你可以这么考虑 有两堆弹珠 And you may think of that as having two piles,having two piles. 403 00:20:04,090 --> 00:20:07,180 把这两堆加在一块儿形成新的一堆的办法就是 And the way I'm adding these numbers together to make a third pile is by 404 00:20:07,180 --> 00:20:09,180 把弹珠从一堆挪到另一堆去 moving marbles from one to the other. 405 00:20:10,130 --> 00:20:11,070 仅此而已 Nothing more than that. 406 00:20:11,290 --> 00:20:12,850 最终 有一堆会被搬空 And eventually,when I run out of one 407 00:20:12,850 --> 00:20:13,900 另一堆就是加和的结果了 then the other is the sum. 408 00:20:15,330 --> 00:20:19,240 然而 第二个过程不是这样做的 However,the second procedure here doesn't do it that way. 409 00:20:20,340 --> 00:20:22,380 它是这样做的 如果第一个参数是0 It says if the first number is 0, 410 00:20:22,380 --> 00:20:23,550 答案就是第二个 then the answer is the second. 411 00:20:24,020 --> 00:20:24,530 否则 Otherwise, 412 00:20:24,530 --> 00:20:26,990 答案就是 第一个参数减1 it's the increment of the sum 413 00:20:26,990 --> 00:20:28,900 和第二个参数的和 of the decrement of the first number 414 00:20:28,900 --> 00:20:29,560 然后再加1 and the second. 415 00:20:31,020 --> 00:20:32,010 这种方式就是 So what this says is 416 00:20:32,020 --> 00:20:36,490 把第一个参数减1和第二个数加起来 add together,add together the decrement of the first number and the second 417 00:20:36,490 --> 00:20:38,320 毫无疑问 简化了问题 -- a simpler problem,no doubt-- 418 00:20:38,320 --> 00:20:41,540 然后把这个和再加1 and then change that result to increment it. 419 00:20:42,780 --> 00:20:46,060 这就意味着如果你用两堆弹珠的方式来思考 And so this means that if you think about this in terms of piles, 420 00:20:46,480 --> 00:20:50,100 就是说 我左手右手各有一堆弹珠 it means I'm holding in my hand the things to be added later. 421 00:20:51,450 --> 00:20:53,020 然后我要把它们加在一起 And then I'm going to add them in. 422 00:20:53,610 --> 00:20:56,060 然后我慢慢地把其中一堆搬空 As I slowly decrease one pile to 0, 423 00:20:56,430 --> 00:20:57,710 然后把这些拿出来的弹珠 I've got what's left here, 424 00:20:57,710 --> 00:20:58,890 再放回另一堆弹珠中 and then I'm going to add them back. 425 00:20:59,960 --> 00:21:01,170 两种不同的加法 Two different ways of adding. 426 00:21:02,160 --> 00:21:04,200 关于这两个程序 有趣的是 The nice thing about these two programs 427 00:21:04,460 --> 00:21:05,850 它们几乎一样 is that they're almost identical. 428 00:21:06,450 --> 00:21:08,260 唯一的区别是把加1这个过程放哪儿 The only thing is where I put the increment. 429 00:21:09,140 --> 00:21:10,570 把几个字符挪挪地方 A couple of characters moved around. 430 00:21:11,490 --> 00:21:14,280 现在我想弄明白 Now I want to understand,I want to understand the kind of behavior 431 00:21:14,760 --> 00:21:16,820 我们会从这两个程序中看到怎样的行为 we're going to get from each of these programs. 432 00:21:17,330 --> 00:21:19,040 加深大家对这个问题的印象 Just to get them firmly in your mind 433 00:21:19,280 --> 00:21:21,680 我通常不想这么谨慎 -- I usually don't want to be this careful-- 434 00:21:21,680 --> 00:21:23,610 但是还是要加深大家的印象 but just to get them firmly in your mind, 435 00:21:23,610 --> 00:21:25,330 我在黑板上把程序再写一遍 I'm going to write the programs again on the blackboard, 436 00:21:25,330 --> 00:21:27,100 然后我会演化出一个计算过程 and then I'm going to evolve a process. 437 00:21:27,770 --> 00:21:29,100 大家都注意观察 看看是怎么回事 And you're going to see what happens. 438 00:21:29,460 --> 00:21:31,340 看看过程演化是怎样的“形状” We're going to look at the shape of the process 439 00:21:31,340 --> 00:21:32,740 这是程序导致的一个结果 as a consequence of the program. 440 00:21:34,040 --> 00:21:35,730 我们从这个程序开始 So the program we started with is this: 441 00:21:40,510 --> 00:21:44,160 求x与y的和 the sum of x and y says 442 00:21:44,160 --> 00:21:49,410 如果x等于0 if x is 0, 443 00:21:49,410 --> 00:21:50,670 那么答案就是y then the result is y. 444 00:21:50,670 --> 00:21:51,520 否则 Otherwise, 445 00:21:51,520 --> 00:21:58,220 答案就是x减1和y加1的和 it's the sum of the decrement of x and the increment of y. 446 00:22:01,260 --> 00:22:05,490 现在 假设我们要求3与4的和 Now,supposing we wish to do this addition of 3 and 4, 447 00:22:06,610 --> 00:22:09,120 3与4的和 the sum of 3 and 4, 448 00:22:09,530 --> 00:22:10,300 接下来呢 well,what is that? 449 00:22:10,530 --> 00:22:13,690 我要代换这两个参数 It says that I have to substitute the arguments 450 00:22:14,030 --> 00:22:16,040 代换过程定义中的形式参数 for the formal parameters in the body. 451 00:22:17,380 --> 00:22:18,920 我在脑海中想像这个过程 I'm doing that in my mind. 452 00:22:19,560 --> 00:22:20,660 然后说 啊 这样 And I say,oh,yes, 453 00:22:20,660 --> 00:22:21,920 3代换了x 3 is substituted for x, 454 00:22:21,920 --> 00:22:23,280 但3不是0 but 3 is not 0, 455 00:22:24,650 --> 00:22:27,000 于是直接进入这一部分 so I'm going to go directly to this part 456 00:22:27,000 --> 00:22:30,400 然后只用关心这一部分就行 and write down the simplified consequent here. 457 00:22:30,400 --> 00:22:31,980 因为我只关心加法过程的行为 Because I'm really interested in the behavior of addition. 458 00:22:33,100 --> 00:22:33,840 好了 接下来 Well,what is that? 459 00:22:34,080 --> 00:22:37,760 就变成了求2和5的过程 That therefore turns into the sum of 2 and 5. 460 00:22:38,400 --> 00:22:38,610 换句话说 In other words, 461 00:22:38,610 --> 00:22:40,270 我把这个问题归约成这个问题 I've reduced this problem to this problem. 462 00:22:41,410 --> 00:22:46,280 然后我又把这个问题化归约成求1和6的和 Then I reduce this problem to the sum of 1 and 6, 463 00:22:47,220 --> 00:22:49,340 再接着归约 and then,going around again once, 464 00:22:49,600 --> 00:22:52,480 就有了0和7的和 I get the sum of 0 and 7. 465 00:22:52,970 --> 00:22:54,930 于是x就等于0了 And that's one where x equals 0 466 00:22:54,930 --> 00:22:56,220 答案是y so the result is y, 467 00:22:56,220 --> 00:22:58,220 也就是7 and so I write down here a 7. 468 00:22:59,920 --> 00:23:02,780 这就是这个程序把3和4相加 So this is the behavior of the process evolved 469 00:23:02,780 --> 00:23:05,360 而演化出的计算过程的行为 by trying to add together 3 and 4 with this program. 470 00:23:07,390 --> 00:23:08,680 另一个程序 For the other program, 471 00:23:09,630 --> 00:23:10,610 写在这边 which is over here, 472 00:23:17,800 --> 00:23:22,250 如此定义x与y的和 I will define the sum of x and y. 473 00:23:23,360 --> 00:23:23,980 怎么定义的呢 And what is it? 474 00:23:26,480 --> 00:23:29,170 如果x是0 If x is 0, 475 00:23:29,620 --> 00:23:30,810 答案就是y then the result is y 476 00:23:30,810 --> 00:23:31,630 这和上一个程序一样 -- almost the same-- 477 00:23:31,630 --> 00:23:34,800 否则就是x减1与y的和 otherwise the increment of the sum 478 00:23:35,550 --> 00:23:40,260 再加上1 of the decrement of x and y. 479 00:23:47,370 --> 00:23:54,640 写错了 黑板不能自动匹配括号 No.I don't have my balancer in front of me. 480 00:23:56,080 --> 00:23:57,330 好了 接下来 OK,well,let's do it now. 481 00:23:58,800 --> 00:24:00,100 求3与4的和 The sum of 3 and 4. 482 00:24:01,160 --> 00:24:02,690 其实这样更有趣 来看 Well,this is actually a little more interesting. 483 00:24:03,310 --> 00:24:05,630 3当然不等于0 和之前一样 Of course,3 is not 0 as before, 484 00:24:06,160 --> 00:24:12,130 于是答案就是 x减1与y的和再加1 so that results in the increment of the sum of the decrement of x, 485 00:24:12,130 --> 00:24:14,260 也就是2与4的和 which is 2 and 4, 486 00:24:15,800 --> 00:24:22,650 接着变成 1与 which is the increment of the sum of 1 and-- 487 00:24:22,850 --> 00:24:24,990 噢 弄错了 加1再加1 whoops: the increment of the increment. 488 00:24:25,650 --> 00:24:29,170 现在要做的是计算这一部分 What I have to do now is compute what this means. 489 00:24:29,470 --> 00:24:30,590 我要对这一部分求值 I have to evaluate this. 490 00:24:30,810 --> 00:24:31,720 也就是 Or what that is, 491 00:24:31,870 --> 00:24:34,720 用2和4代换x和y的结果 the result of substituting 2 and 4 for x and y here. 492 00:24:35,200 --> 00:24:40,840 变成了1与4的和再加1 But that is the increment of the sum of 1 and 4, 493 00:24:43,490 --> 00:24:45,920 现在我得展开这部份 which is-- well,now I have to expand this. 494 00:24:47,160 --> 00:24:51,230 啊 然后就变成了0与4的和加1加1 Ah,but that's the increment of the increment 495 00:24:53,520 --> 00:24:56,130 再加1 of the increment of the sum of 0 and 4. 496 00:24:59,390 --> 00:25:02,380 现在来看看都能做些什么 Ah,but now I'm beginning to find things I can do. 497 00:25:02,860 --> 00:25:06,850 加1加1再加1 The increment of the increment of the increment of-- 498 00:25:06,850 --> 00:25:08,590 0和4的和是4 well,the sum of 0 and 4 is 4. 499 00:25:12,030 --> 00:25:13,610 4加1是5 The increment of 4 is 5. 500 00:25:14,560 --> 00:25:18,760 这就变成了5加1再加1 So this is the increment of the increment of 5, 501 00:25:20,180 --> 00:25:23,200 也就是6再加1 which is the increment of 6, 502 00:25:23,900 --> 00:25:24,970 最后答案就是7 which is 7. 503 00:25:26,100 --> 00:25:28,060 两种不同的求和方法 Two different ways of computing sums. 504 00:25:29,540 --> 00:25:30,330 现在来看看 Now,let's see. 505 00:25:31,260 --> 00:25:33,260 这两种计算过程有不同的“形状” These processes have very different shapes. 506 00:25:33,920 --> 00:25:35,400 我想让各位去感受这些“形状” I want you to feel these shapes. 507 00:25:36,350 --> 00:25:38,370 这种感觉很关键 It's the feeling for the shapes that matters. 508 00:25:40,340 --> 00:25:42,030 从这里我们能发现什么 What's some things we can see about this? 509 00:25:42,660 --> 00:25:44,120 不知怎么回事 这个有点“直” Well somehow this is sort of straight. 510 00:25:45,250 --> 00:25:46,600 就这样一路直着下来 It goes this way-- straight. 511 00:25:47,340 --> 00:25:51,930 右边界并没有特别的变化 This right edge doesn't vary particularly in size. 512 00:25:53,770 --> 00:25:54,700 而这边这个呢 Whereas this one, 513 00:25:54,990 --> 00:25:58,320 右边界先变大又变小 I see that this thing gets bigger and then it gets smaller. 514 00:26:00,910 --> 00:26:02,620 我还不知道这意味着什么 So I don't know what that means yet, 515 00:26:02,620 --> 00:26:03,630 我们看到的是什么 but what are we seeing? 516 00:26:03,630 --> 00:26:05,900 是不知怎么回事 We're seeing here that somehow 517 00:26:07,170 --> 00:26:10,940 这些加1的过程先展开后收缩 these increments are expanding out and then contracting back. 518 00:26:12,760 --> 00:26:14,570 我构造出一个推迟进行的操作的链条 I'm building up a bunch of them to do later. 519 00:26:16,090 --> 00:26:17,070 我不能马上求值 I can't do them now. 520 00:26:18,720 --> 00:26:19,860 有的过程需要推迟 There's things to be deferred. 521 00:26:21,400 --> 00:26:22,160 好了 我们继续 Well,let's see, 522 00:26:22,670 --> 00:26:24,290 我可以想象一个抽象的计算机 I can imagine an abstract machine. 523 00:26:24,290 --> 00:26:25,480 也许能制造一些实际的计算机 There's some physical machine, 524 00:26:25,480 --> 00:26:26,840 能像我这样求值 perhaps,that could be built to do it, 525 00:26:26,840 --> 00:26:30,010 能像我演示给大家的一样执行程序 which,in fact,executes these programs exactly as I tell you, 526 00:26:30,010 --> 00:26:32,850 像这样代换字符串 substituting character strings in like this. 527 00:26:34,210 --> 00:26:35,080 这样的计算机 Such a machine, 528 00:26:35,780 --> 00:26:38,750 计算中的步骤与计算所花费的时间近似相等 the number of such steps is an approximation of the amount of time it takes. 529 00:26:39,730 --> 00:26:40,830 用纵轴表示时间 So this way is time. 530 00:26:43,630 --> 00:26:46,420 横轴的宽度表示 And the width of the thing is 531 00:26:46,970 --> 00:26:49,700 进行计算需要保存的信息量 how much I have to remember in order to continue the process. 532 00:26:50,110 --> 00:26:51,150 也就是表示进行计算所需要的空间 And this much is space. 533 00:26:53,540 --> 00:26:56,180 我们看到的是一个计算过程 And what we see here is a process 534 00:26:57,090 --> 00:27:00,910 其时间消耗正比于参数x that takes a time which is proportional to the argument x. 535 00:27:02,420 --> 00:27:04,350 因为如果我让x增大一倍 Because if I made x larger by 1, 536 00:27:04,350 --> 00:27:05,520 就得把这个表示时间的纵轴再加长一倍 then I'd had an extra line. 537 00:27:08,480 --> 00:27:12,260 于是这就是个计算过程 它的空间 抱歉 时间 So this is a process which is space-- sorry-- time. 538 00:27:14,520 --> 00:27:19,160 这个计算过程消耗的时间为O(x) The time of this process is what we say order of x. 539 00:27:20,540 --> 00:27:24,890 也就是正比于x That means it is proportional to x by some constant of proportionality 540 00:27:24,890 --> 00:27:27,150 不要刻意追究这个常比例系数是多少 and I'm not particularly interested in what the constant is. 541 00:27:28,360 --> 00:27:29,530 我们还会发现 The other thing we see here 542 00:27:29,540 --> 00:27:32,280 这个计算过程消耗的空间是固定不变的 is that the amount of space this takes up is constant. 543 00:27:33,370 --> 00:27:34,530 即与1成正比 it's proportional to 1. 544 00:27:35,200 --> 00:27:40,420 于是这个计算过程的空间复杂度就是O(1)的 So the space complexity of this is order of 1. 545 00:27:41,710 --> 00:27:43,360 对这样的计算过程我们有个名字 We have a name for such a process. 546 00:27:43,870 --> 00:27:45,810 叫迭代计算过程 Such a process is called an iteration. 547 00:27:50,800 --> 00:27:51,900 关键的地方 And what matters here 548 00:27:51,900 --> 00:27:55,820 不是什么我设计的 is not that some particular machine I designed here 549 00:27:56,450 --> 00:27:57,960 之前提到的 and talked to you about 550 00:27:57,960 --> 00:27:59,320 代换字符计算机 and called a substitution machine 551 00:27:59,320 --> 00:28:00,720 或者 代换模型 or whatever-- substitution model-- 552 00:28:01,060 --> 00:28:03,880 怎么设法在常数空间复杂度内完成计算过程 managed to do this in constant space. 553 00:28:04,220 --> 00:28:06,090 关键的地方是这给出了一个界限 What really matters is this tells us a bound. 554 00:28:06,750 --> 00:28:09,200 任何计算机 都应该在常数空间复杂度内完成计算过程 Any machine could do this in constant space. 555 00:28:09,360 --> 00:28:12,030 这个过程代表的算法 This algorithm represented by this procedure 556 00:28:12,440 --> 00:28:14,030 在常数空间复杂度内是可执行的 is executable in constant space. 557 00:28:14,840 --> 00:28:17,330 当然了这种说法忽略了一些细节 Now,of course,the model is ignoring some things, 558 00:28:17,630 --> 00:28:18,640 却量化了一些东西 standard sorts of things. 559 00:28:18,640 --> 00:28:21,980 忽略了比如数值越大越消耗空间等等 Like numbers that are bigger take up more space and so on. 560 00:28:21,980 --> 00:28:24,010 但那确实是抽象过程中我要忽略的一个层次 But that's a level of abstraction at which I'm cutting off. 561 00:28:24,010 --> 00:28:24,920 如何表示数值 How do you represent numbers? 562 00:28:24,920 --> 00:28:26,640 我假定所有的数值都具有同样的字长 I'm considering every number to be the same size. 563 00:28:27,710 --> 00:28:31,420 事实上数值的字长的增长 和它们占用的存储空间的增长都非常缓慢 And numbers grow slowly for the amount of space they take up and their size. 564 00:28:33,860 --> 00:28:36,680 而这个算法的复杂度就不同了 Now,this algorithm is different in its complexity. 565 00:28:37,390 --> 00:28:38,680 我们看到 As we can see here, 566 00:28:40,370 --> 00:28:43,210 这个算法时间复杂度 this algorithm has a time complexity 567 00:28:44,680 --> 00:28:48,560 也是正比于输入参数x的 which is also proportional to the input argument x. 568 00:28:49,130 --> 00:28:51,610 因为如果我把这个3再加1 That's because if I were to add 1 to 3, 569 00:28:51,610 --> 00:28:53,320 如果我把问题规模扩大 if I made a larger problem 570 00:28:53,320 --> 00:28:54,980 扩大了1 which is larger by 1 here, 571 00:28:54,980 --> 00:28:56,170 那我就要在上面再加一行 then I'd add a line at the top 572 00:28:56,170 --> 00:28:57,290 在底下再加一行 and I'd add a line at the bottom. 573 00:29:00,280 --> 00:29:01,980 而且事实上这是个常量 And the fact that it's a constant amount, 574 00:29:01,980 --> 00:29:04,050 就像这个计算过程的步骤数是那个的两倍 like this is twice as many lines as that 575 00:29:04,290 --> 00:29:06,600 我不会关心这个层次的细节 也不会关心那个常量 is not interesting at the level of detail I'm talking about right now. 576 00:29:07,730 --> 00:29:12,020 所以这个计算过程的时间复杂度也是O(x) So this is a time complexity order of the input argument x. 577 00:29:12,640 --> 00:29:13,950 而空间复杂度呢 And space complexity, 578 00:29:15,880 --> 00:29:17,060 这个比较有趣 well,this is more interesting. 579 00:29:17,390 --> 00:29:19,970 有一些东西是固定不变的 I happen to have some overhead, 580 00:29:20,180 --> 00:29:21,000 比如这些 which you see over here, 581 00:29:21,000 --> 00:29:22,720 是近似保持不变的 which is constant approximately. 582 00:29:23,290 --> 00:29:24,090 是常量的 Constant overhead. 583 00:29:24,340 --> 00:29:27,210 但也有一些增加和减少 But then I have something which increases and decreases 584 00:29:27,210 --> 00:29:29,460 是正比于参数x的 and is proportional to the input argument x. 585 00:29:29,710 --> 00:29:31,060 输入参数x是3 The input argument x is 3. 586 00:29:31,060 --> 00:29:34,690 也就是这里为何有3个推迟操作的加1过程 That's why there are three deferred increments sitting around here. 587 00:29:36,360 --> 00:29:36,650 发现了么 See? 588 00:29:37,400 --> 00:29:40,060 于是这个计算过程的空间复杂度也是O(x)的 So the space complexity here is also order x. 589 00:29:41,400 --> 00:29:43,150 这种计算过程 And this kind of process, 590 00:29:43,410 --> 00:29:44,640 给它取个名字 named for the kind of process, 591 00:29:44,640 --> 00:29:45,850 是递归计算过程 this is a recursion. 592 00:29:50,410 --> 00:29:51,280 更准确地来说 A linear recursion 593 00:29:51,280 --> 00:29:51,870 是线性递归计算过程 I will call it. 594 00:29:54,600 --> 00:29:56,680 因为它的时间和空间复杂度 because of the fact that it's proportional 595 00:29:56,680 --> 00:29:58,520 都是正比于输入参数的 to the input argument in both time and space. 596 00:30:01,360 --> 00:30:03,070 那么这个就可以称为一个线性迭代过程 This could have been a linear iteration. 597 00:30:13,630 --> 00:30:15,070 那么 这两种计算过程的本质是什么 So then what's the essence of this matter? 598 00:30:16,190 --> 00:30:17,780 不太容易看出来 This matter isn't so obvious. 599 00:30:18,750 --> 00:30:19,690 可能还有别的模型 Maybe there are other models 600 00:30:19,690 --> 00:30:21,630 可以用来描述 by which we can describe the differences 601 00:30:21,630 --> 00:30:23,390 迭代和递归计算过程的不同之处 between iterative and recursive processes. 602 00:30:23,390 --> 00:30:24,410 但这就有些困难了 Because this is hard now. 603 00:30:25,150 --> 00:30:25,390 记住 Remember, 604 00:30:25,390 --> 00:30:27,140 这两种计算过程都是递归定义的 we have-- those are both recursive definitions. 605 00:30:28,010 --> 00:30:28,940 我们看到的是 What we're seeing there 606 00:30:29,980 --> 00:30:31,380 两种过程在定义上都使用了递归 are both recursive definitions, 607 00:30:31,680 --> 00:30:34,370 也就是两个过程的定义中都引用了该过程本身 definitions that refer to the thing being defined in the definition. 608 00:30:35,050 --> 00:30:36,620 但是它们却产生了不同“形状”的计算过程 But they lead to different shape processes. 609 00:30:37,440 --> 00:30:41,250 过程定义是递归的 There's nothing special about the fact 610 00:30:41,250 --> 00:30:42,540 而产生的计算过程也是递归的 that the definition is recursive 611 00:30:42,540 --> 00:30:44,170 这没什么特别的 that leads to a recursive process. 612 00:30:45,770 --> 00:30:49,490 好了 来看看另一种有趣的解释 OK.Let's think of another model. 613 00:30:49,850 --> 00:30:51,490 我会和大家谈谈 官僚主义 I'm going to talk to you about bureaucracy. 614 00:30:52,620 --> 00:30:54,290 官僚主义 挺有趣儿的 Bureaucracy is sort of interesting. 615 00:30:54,650 --> 00:30:58,890 在幻灯片上我们看到有关迭代计算过程的解释 Here we see on a slide an iteration. 616 00:31:00,120 --> 00:31:02,220 迭代是一种挺好玩儿的计算过程 An iteration is sort of a fun kind of process. 617 00:31:03,820 --> 00:31:06,210 想象一下有个叫GJS的家伙 Imagine that there's a fellow called GJS 618 00:31:06,330 --> 00:31:07,160 也就是我 -- that stands for me-- 619 00:31:08,400 --> 00:31:09,260 遇到了一个问题 and he's got a problem: 620 00:31:09,260 --> 00:31:10,770 他想求3与4的和 he wants to add together 3 and 4. 621 00:31:13,010 --> 00:31:14,820 这个家伙想把3和4加一块儿 This fella here wants to add together 3 and 4. 622 00:31:16,260 --> 00:31:17,170 他打算这么办 Well,the way he's going to do it 623 00:31:17,170 --> 00:31:17,900 他挺懒的 -- he's lazy-- 624 00:31:18,260 --> 00:31:20,180 他想找别人帮忙 is he's going to find somebody else to help him do it. 625 00:31:21,060 --> 00:31:22,210 他是这样找人帮忙的 The way he finds someone else to-- 626 00:31:22,210 --> 00:31:24,210 他找了个人帮忙 对他说 he finds someone else to help him do it and says, 627 00:31:24,210 --> 00:31:25,970 算出3和4的和 well,give me the answer to 3 and 4 628 00:31:26,010 --> 00:31:27,260 然后把答案返回给我 and return the result to me. 629 00:31:28,010 --> 00:31:30,180 他写了一张小纸条递给这个人然后说 He makes a little piece of paper and says, 630 00:31:30,460 --> 00:31:31,770 给 这是一张纸条 here,here's a piece of paper-- 631 00:31:31,770 --> 00:31:32,620 你去解决这个问题 you go ahead and solve this problem 632 00:31:32,620 --> 00:31:33,800 然后把答案返回给我 and give the result back to me. 633 00:31:35,480 --> 00:31:36,000 而这个找来帮忙的家伙呢 And this guy, 634 00:31:36,000 --> 00:31:36,930 也很懒 of course,is lazy,too. 635 00:31:38,010 --> 00:31:39,630 他可不想再看见这张小纸条了 He doesn't want to see this piece of paper again. 636 00:31:40,960 --> 00:31:42,210 他说 啊 好吧 He says,oh,yes, 637 00:31:44,450 --> 00:31:45,480 然后出了个新问题 produce a new problem 638 00:31:45,480 --> 00:31:46,940 是求2和5的和 which is the sum of 2 ad 5 639 00:31:46,940 --> 00:31:49,120 并把答案返回给GJS and return the result back to GJS. 640 00:31:50,080 --> 00:31:51,210 我不想再看见这张纸条了 I don't want to see it again. 641 00:31:52,000 --> 00:31:53,700 这个家伙不想再看见这张纸条了 This guy does not want to see this piece of paper. 642 00:31:55,860 --> 00:31:59,940 于是就出了一个新问题 And then this fellow makes a new problem, 643 00:32:00,260 --> 00:32:02,030 也就是求1与6的和的问题 which is the addition of the sum of 1 and 6, 644 00:32:02,030 --> 00:32:04,260 他又把纸条传给了这个家伙 并说到 and he give it to this fella and says, 645 00:32:04,260 --> 00:32:06,820 算出答案然后把答案告诉GJS produce that answer and returned it to GJS. 646 00:32:08,100 --> 00:32:09,740 那个家伙又接着出了个新问题 And that produces a problem, 647 00:32:09,740 --> 00:32:11,310 求0与7的和 which is to add together 0 and 7 648 00:32:11,310 --> 00:32:13,090 然后把答案返回给GJS and give the result to GJS. 649 00:32:13,810 --> 00:32:15,010 最后这个家伙直接说 This fella finally just says, 650 00:32:15,010 --> 00:32:16,120 啊 好吧 答案是7 oh,yeah,the answer is 7, 651 00:32:16,120 --> 00:32:17,340 然后把答案返回给了GJS and sends it back to GJS. 652 00:32:18,140 --> 00:32:19,170 迭代计算过程就是这样的 That's what an iteration is. 653 00:32:19,870 --> 00:32:20,800 相对而言 By contrast, 654 00:32:21,260 --> 00:32:23,570 递归计算过程就有些不同了 a recursion is a slightly different kind of process. 655 00:32:26,060 --> 00:32:27,610 它更加“官僚主义” This one involves more bureaucracy. 656 00:32:28,140 --> 00:32:29,380 它使得更多的人变得忙碌 It keeps more people busy. 657 00:32:30,190 --> 00:32:31,900 更多的人被雇佣 It keeps more people employed. 658 00:32:32,400 --> 00:32:34,860 当然了能增加就业也许更好 Perhaps it's better for that reason. 659 00:32:35,600 --> 00:32:36,160 请看幻灯片 But here it is: 660 00:32:36,160 --> 00:32:38,160 我想要知道3与4的和 I want the answer to the problem 3 and 4. 661 00:32:38,520 --> 00:32:39,900 于是写了张纸条 说到 So I make a piece of paper that says, 662 00:32:39,900 --> 00:32:40,990 把答案返回给我 give the result back to me. 663 00:32:42,840 --> 00:32:43,610 然后我把纸条给了这个家伙 Give it to this fella. 664 00:32:44,330 --> 00:32:45,080 这个家伙说 This fellow says, 665 00:32:45,220 --> 00:32:45,860 好吧我会记得 oh,yes,I will remember 666 00:32:46,440 --> 00:32:48,170 一会儿要加1 that I have to add later, 667 00:32:49,040 --> 00:32:51,560 而我又得知道2加4的和是多少 and I want to get the answer the problem 2 plus 4, 668 00:32:52,020 --> 00:32:54,740 于是把这个问题给了Harry give that one to Harry, 669 00:32:54,740 --> 00:32:57,040 然后把结果返回给我 Joe and have the results sent back to me-- I'm Joe. 670 00:32:58,520 --> 00:33:00,260 一旦Harry返回了答案 When the answer comes back from Harry, 671 00:33:00,260 --> 00:33:01,050 也就是6 which is a 6, 672 00:33:01,300 --> 00:33:02,500 我就会把答案加1 I will then do the increment 673 00:33:04,120 --> 00:33:05,650 然后把结果返回给GJS and give that 7 back to GJS. 674 00:33:07,290 --> 00:33:09,050 大家可以发现 在递归计算过程中 需要保留的纸条 So there are more pieces of paper outstanding 675 00:33:09,660 --> 00:33:12,290 比迭代计算过程的多 in the recursive process than the iteration. 676 00:33:16,540 --> 00:33:18,660 还有一种方法可以用来理解迭代计算过程 There's another way to think about what an iteration is 677 00:33:19,300 --> 00:33:20,990 以及迭代计算过程和递归计算过程的不同之处 and the difference between an iteration and a recursion. 678 00:33:21,420 --> 00:33:22,760 问题的关键在于 You see,the question is, 679 00:33:22,760 --> 00:33:24,780 有多少东西是不可见的 how much stuff is under the table? 680 00:33:26,000 --> 00:33:27,550 如果我要停止 something,if I were to stop-- 681 00:33:28,360 --> 00:33:32,130 假设我现在要关闭计算机 supposing I were to kill this computer right now,OK? 682 00:33:32,130 --> 00:33:35,180 此时我丢失了事务的状态 And at this point I lose the state of affairs, 683 00:33:36,680 --> 00:33:38,690 但我能接着进行运算 well,I could continue the computation from this point 684 00:33:39,390 --> 00:33:44,290 因为继续运算所需要的所有信息都在参数变量中 cause everything I need to continue the computation is in the variables 685 00:33:44,290 --> 00:33:48,540 即程序员编写过程时定义的变量 that were defined in the procedure that the programmer wrote for me. 686 00:33:49,440 --> 00:33:53,810 迭代计算过程能用明确的变量 保存计算过程中的状态 An iteration is a system that has all of its state in explicit variables. 687 00:33:56,670 --> 00:34:00,020 这一点递归计算过程就不同 Whereas the recursion is not quite the same. 688 00:34:00,940 --> 00:34:04,040 如果我弄丢了这堆垃圾 If I were to lose this pile of junk over here 689 00:34:04,880 --> 00:34:06,850 那就只剩下求1与4的和了 and all I was left with was the sum of 1 and 4, 690 00:34:07,000 --> 00:34:09,530 这些信息不足以继续 that's not enough information to continue the process 691 00:34:09,530 --> 00:34:11,870 从初始的求3与4的和的问题 of computing out the 7 from the original problem 692 00:34:11,870 --> 00:34:13,130 求出7的计算过程 of adding together 3 of 4. 693 00:34:14,580 --> 00:34:18,350 除了保存在过程中的 Besides the information that's in the variables 694 00:34:19,290 --> 00:34:21,420 形式参数变量中的信息 of the formal parameters of the program, 695 00:34:22,830 --> 00:34:25,920 计算机还保存了一些不可见的信息 there is also information under the table belonging to the computer, 696 00:34:26,500 --> 00:34:28,280 也就是都有哪些过程被推迟计算了 which is what things have been deferred for later. 697 00:34:30,100 --> 00:34:30,680 当然了 And,of course, 698 00:34:30,930 --> 00:34:32,680 有个实际的比喻 there's a physical analogy to this, 699 00:34:33,220 --> 00:34:37,080 比如微分方程 which is in differential equations,for example, 700 00:34:37,740 --> 00:34:40,560 当我们说到画一个圆的时候 when we talk about something like drawing a circle. 701 00:34:41,760 --> 00:34:42,990 试图画一个圆 Try to draw a circle, 702 00:34:42,990 --> 00:34:46,030 你从一个微分方程中解得它 you make that out of a differential equation 703 00:34:46,030 --> 00:34:52,440 即状态的改变是我当前状态的一个函数 which says the change in my state as a function of my current state. 704 00:34:52,890 --> 00:34:56,920 于是如果我当前的状态由y和x的特定值表征 So if my current state corresponds to particular values of y and x 705 00:34:57,630 --> 00:35:01,100 那么我就能求出一个导数 表征状态如何改变 then I can compute from them a derivative which says how the state must change. 706 00:35:03,150 --> 00:35:03,570 并且 实际上 And,in fact 707 00:35:03,580 --> 00:35:05,630 大家可以看出这是一个圆 this,you can see this was a circle 708 00:35:06,010 --> 00:35:09,760 因为如果碰巧 because if I happen to be, 709 00:35:09,760 --> 00:35:11,100 在这个点 say,at this place over here, 710 00:35:11,770 --> 00:35:15,500 比如在(1,0)这个点 at (1,0),for example 711 00:35:15,530 --> 00:35:16,210 在这个图像上 on this graph, 712 00:35:16,730 --> 00:35:22,180 那就是说y的导数是x then it means that the derivative of y is x, 713 00:35:22,240 --> 00:35:23,160 我们也看见了 which we see over here. 714 00:35:23,160 --> 00:35:24,040 是1 That's 1, 715 00:35:24,040 --> 00:35:25,100 接着向上走 so I'm going up. 716 00:35:25,780 --> 00:35:28,640 x的导数是-y And the derivative of x is minus y, 717 00:35:28,640 --> 00:35:29,700 意味着要走回来 which means I'm going backwards. 718 00:35:30,860 --> 00:35:32,520 实际在这点什么也没做 I'm actually doing nothing at this point, 719 00:35:32,680 --> 00:35:36,220 然后开始走回来使y增加 then I start going backwards as y increases. 720 00:35:37,720 --> 00:35:39,440 这样就画出了一个圆 So that's how you make a circle. 721 00:35:39,720 --> 00:35:41,940 有趣的是 And the interesting thing to see is 722 00:35:41,940 --> 00:35:44,900 这儿有一个程序能用这种方法画出一个圆 a little program that will draw a circle by this method. 723 00:35:44,940 --> 00:35:46,180 实际上 不会画一出一个圆 Actually,this won't draw a circle 724 00:35:46,200 --> 00:35:48,320 因为这个程序实际是一个积分器 because it's a forward oil or integrator 725 00:35:48,320 --> 00:35:50,480 并且最终会陷入死循环 and will eventually spiral out and all that. 726 00:35:50,480 --> 00:35:52,900 但陷入死循环前还是能画出一个圆的 But it'll draw a circle for a while before it starts spiraling. 727 00:35:54,080 --> 00:35:55,920 然而 我们在这儿看到的是两个表征状态的变量 However,what we see here is two state variables, 728 00:35:55,920 --> 00:35:56,660 x和y x and y. 729 00:35:57,740 --> 00:35:59,220 还有个迭代计算过程表明 And there's an iteration that says, 730 00:35:59,600 --> 00:36:00,520 要画一个圆 in order to circle, 731 00:36:00,760 --> 00:36:01,740 已经有了x和y given an x and y, 732 00:36:02,100 --> 00:36:04,520 我想要的是x和y的下一组取值以用来画圆 what I want is to circle with the next values of x and y 733 00:36:04,520 --> 00:36:08,580 也就是x原有的值减去y和dt的乘积 being the old value of x decrement by y times dt 734 00:36:08,580 --> 00:36:09,760 dt就是时间变化 where dt is the time step 735 00:36:10,320 --> 00:36:15,780 还有y原有的值加上x的dt的乘积 and the old value of y being implemented by x times dt, 736 00:36:16,080 --> 00:36:17,780 然后就得到了x和y的新的取值 giving me the new values of x and y. 737 00:36:21,160 --> 00:36:22,940 好了 现在大家对于两种不同的计算过程的感觉 So now you have a feeling 738 00:36:23,620 --> 00:36:25,740 应该都有了一个直观的感觉 for at least two different kinds of processes 739 00:36:26,920 --> 00:36:29,720 而这两种计算过程却可能是由几乎相同的程序产生的 that can be evolved by almost the same program. 740 00:36:32,300 --> 00:36:34,560 像这样做了一点扰动分析之后 And with a little bit of perturbation analysis like this, 741 00:36:35,340 --> 00:36:37,880 如何小小地修改一下程序观察计算过程是怎样变化的 how you change a program a little bit and see how the process changes, 742 00:36:38,680 --> 00:36:39,800 这样才能有直观的感受 that's how we get some intuition. 743 00:36:41,620 --> 00:36:43,080 之后我们就会用到这样的直观感受 Pretty soon we're going to use that intuition 744 00:36:43,520 --> 00:36:45,180 来构建大型的 恼人的 复杂的系统 to build big,hairy,complicated systems. 745 00:36:46,360 --> 00:36:46,800 谢谢 Thank you. 746 00:36:56,880 --> 00:37:06,660 [音乐] [MUSIC PLAYING BY J.S.BACH] 747 00:37:06,660 --> 00:37:06,920 教授 好了 PROFESSOR: Well, 748 00:37:06,920 --> 00:37:11,100 各位之前已经见过一次 对若干程序的简单的扰动分析 you've just seen a simple perturbational analysis of some programs. 749 00:37:11,600 --> 00:37:14,300 我拿一个程序与另一个很相似的程序进行比较 I took a program that was very similar to another program 750 00:37:14,300 --> 00:37:17,340 观察他们如何演化出计算过程 and looked at them both and saw how they evolved processes. 751 00:37:18,220 --> 00:37:19,520 我想再给大家介绍点不同的东西 I want to show you some variety 752 00:37:19,520 --> 00:37:22,720 向大家展示程序可能具有的 别的一些计算过程和“形状” by showing you some other processes and shapes they may have. 753 00:37:24,280 --> 00:37:25,860 同样地 我们将要举例非常简单的程序 Again,we're going to take very simple things, 754 00:37:26,140 --> 00:37:27,860 简单到你都不想写的程序 programs that you wouldn't want to ever write. 755 00:37:29,040 --> 00:37:30,460 那可能是最糟糕的方式 They would be probably the worst way 756 00:37:31,420 --> 00:37:33,060 去进行一些计算过程 of computing some of the things we're going to compute. 757 00:37:33,740 --> 00:37:35,060 但我还是要展示给大家 But I'm just going to show you these things 758 00:37:35,400 --> 00:37:36,520 是想要展现 for the purpose of feeling out 759 00:37:37,420 --> 00:37:41,320 一个程序如何 how a program represents itself 760 00:37:41,600 --> 00:37:44,520 在计算过程的求值中表现出自己的相应规则 as the rule for the evolution of a process. 761 00:37:46,760 --> 00:37:48,800 考虑一个有趣的问题 So let's consider a fun thing, 762 00:37:48,800 --> 00:37:49,920 斐波那契数列 the Fibonacci numbers. 763 00:37:50,400 --> 00:37:52,020 大家可能已经知道斐波那契数列了 You probably know about the Fibonacci numbers. 764 00:37:53,000 --> 00:37:54,280 我记不清是谁了 Somebody,I can't remember who, 765 00:37:54,660 --> 00:37:59,060 有一个人对兔群的繁殖问题很感兴趣 was interested in the growth of piles of rabbits. 766 00:37:59,920 --> 00:38:01,140 不管怎样 And for some reason or other, 767 00:38:01,380 --> 00:38:04,820 我们都知道兔群趋向于指数式增长 the piles of rabbits tend to grow exponentially,as we know. 768 00:38:05,520 --> 00:38:08,620 对于这个过程我们有个不错的模型来解释 And we have a nice model for this process, 769 00:38:08,620 --> 00:38:11,520 由两个数开始算起 is that we start with two numbers, 770 00:38:11,520 --> 00:38:12,360 0和1 0 and 1. 771 00:38:13,420 --> 00:38:16,560 之后的每个数都是前两个数之和 And then every number after this is the sum of the two previous. 772 00:38:17,840 --> 00:38:19,600 于是接下来就是1 So we have here a 1. 773 00:38:20,100 --> 00:38:21,900 然后这两数之和就是2 Then the sum of these two is 2. 774 00:38:22,380 --> 00:38:23,900 那两数之和是3 The sum of those two is 3. 775 00:38:24,300 --> 00:38:25,900 那两数之和是5 The sum of those two is 5. 776 00:38:26,400 --> 00:38:27,900 那两数之和是8 The sum of those two is 8. 777 00:38:28,280 --> 00:38:30,540 那两数之和是13 The sum of those two is 13. 778 00:38:31,360 --> 00:38:33,260 这是21 This is 21. 779 00:38:34,360 --> 00:38:37,740 34 55 34.55. 780 00:38:38,000 --> 00:38:38,520 等等 Et cetera. 781 00:38:40,300 --> 00:38:41,900 如果给这些数字标上序号 If we start numbering these numbers, 782 00:38:42,360 --> 00:38:43,720 第0个 say this is the zeroth one, 783 00:38:43,720 --> 00:38:44,380 第1个 the first one, 784 00:38:44,380 --> 00:38:45,060 第2个 the second one, 785 00:38:45,060 --> 00:38:45,620 第3个 the third one, 786 00:38:45,620 --> 00:38:46,580 第4个 the fourth one, 787 00:38:46,580 --> 00:38:47,040 等等 et cetera. 788 00:38:47,420 --> 00:38:48,420 这是第10个 This is the 10th one, 789 00:38:49,000 --> 00:38:50,040 第10个斐波那契数 the 10th Fibonacci number. 790 00:38:51,620 --> 00:38:53,000 这些数字增长很快 These numbers grow very fast 791 00:38:54,620 --> 00:38:55,360 就像兔子们一样 Just like rabbits. 792 00:38:55,640 --> 00:38:56,760 为什么兔群是这样增长的呢 Why rabbits grow this way 793 00:38:56,760 --> 00:38:58,140 我不会瞎猜 I'm not going to hazard a guess. 794 00:38:59,320 --> 00:39:00,960 接下来我要为大家展示 Now,I'm going to try to write for you 795 00:39:01,280 --> 00:39:05,260 写一个极简单的程序来计算斐波那契数 the very simplest program that computes Fibonacci numbers. 796 00:39:07,040 --> 00:39:09,620 我想要的是一个程序 It's,ah,what I want is a program that, 797 00:39:09,620 --> 00:39:11,160 输入一个n given an n, 798 00:39:12,320 --> 00:39:13,900 就能输出第n个斐波那契数 will produce for me Fibonacci event. 799 00:39:17,860 --> 00:39:22,320 我就写在这儿了 OK?I'll write it right here. 800 00:39:27,860 --> 00:39:30,740 想要得到第n个斐波那契数 I want the Fibonacci of n, 801 00:39:30,740 --> 00:39:32,500 也就是说 这是那个n which means the-- this is the n, 802 00:39:33,860 --> 00:39:34,880 这是第n个斐波那契数 and this is Fibonacci of n. 803 00:39:36,080 --> 00:39:37,080 我这么写 And here's the story. 804 00:39:37,400 --> 00:39:42,280 如果n小于2 If n is less than 2, 805 00:39:42,740 --> 00:39:43,940 那么答案就是n then the result is n. 806 00:39:45,060 --> 00:39:46,040 因为此时斐波那契数和序号相等 Because that's what these are. 807 00:39:46,920 --> 00:39:47,660 这是最开始的规定 That's how you start it up. 808 00:39:48,700 --> 00:39:49,420 否则 Otherwise, 809 00:39:49,760 --> 00:39:55,180 答案就是第n-1个斐波那契数 the result is the sum of Fib of n minus 1 810 00:39:58,220 --> 00:40:00,420 和第n-2个斐波那契数的和 and the Fibonacci number,n minus 2. 811 00:40:10,220 --> 00:40:11,260 这是个很简单的 So this is a very simple, 812 00:40:11,440 --> 00:40:12,680 很直接的 direct specification 813 00:40:12,960 --> 00:40:14,900 求斐波那契数的实现 of the description of Fibonacci numbers 814 00:40:15,540 --> 00:40:17,140 就是根据斐波那契数的定义直接写出这个过程 that I gave you when I introduced those numbers. 815 00:40:19,260 --> 00:40:21,940 用最简单可行的方式 直接描述了定义中的递归关系 It represents the recurrence relation in the simplest possible way. 816 00:40:23,260 --> 00:40:24,720 现在 我们又如何解释这个过程呢 Now,how do we use such a thing? 817 00:40:25,080 --> 00:40:25,980 我们来分析一下这个过程所演化出的计算过程 Let's draw this process. 818 00:40:26,840 --> 00:40:27,980 让我们来看看这个过程都做了些什么 Let's figure out what this does. 819 00:40:29,240 --> 00:40:32,080 举一个简单的例子 求第4个斐波那契数 Let's consider something very simple by computing Fibonacci of 4. 820 00:40:35,840 --> 00:40:37,020 要求第4个斐波那契数 To compute Fibonacci of 4, 821 00:40:37,020 --> 00:40:37,620 我应该怎么做呢 what do I do? 822 00:40:38,720 --> 00:40:41,960 根据过程的定义 4并不比2小 Well,it says I have-- it's not less than 2. 823 00:40:42,740 --> 00:40:44,320 因此答案就是两个数之和 Therefore it's the sum of two things 824 00:40:45,160 --> 00:40:47,000 然后 我又要求出 Well,in order to compute that I have to compute,then, 825 00:40:47,460 --> 00:40:52,520 第3个和第2个斐波那契数 Fibonacci of 3 and Fibonacci of 2 826 00:40:56,880 --> 00:40:58,620 要求出第3个斐波那契数 In order to compute Fibonacci of 3, 827 00:40:58,960 --> 00:41:04,020 我就得求出第2个斐波那契数和第1个斐波那契数 I have to compute Fibonacci of 2 and Fibonacci of 1. 828 00:41:07,640 --> 00:41:09,280 而为了求出第2个斐波那契数 In order to compute Fibonacci of 2, 829 00:41:09,800 --> 00:41:12,140 就得求出第1个和第0个斐波那契数 I have to compute Fibonacci of 1 and Fibonacci of 0. 830 00:41:16,500 --> 00:41:17,900 要求第1个斐波那契数 In order to compute Fibonacci of 1, 831 00:41:17,900 --> 00:41:18,960 答案就是1 well,the answer is 1. 832 00:41:19,880 --> 00:41:24,520 这正是递归的边界条件 That's from the base case of this recursion. 833 00:41:25,740 --> 00:41:28,140 而第0个斐波那契数 And in order to compute Fibonacci of 0, 834 00:41:28,140 --> 00:41:29,080 是0 well,that answer is 0, 835 00:41:29,080 --> 00:41:29,860 也是递归的边界条件 from the same base. 836 00:41:30,100 --> 00:41:31,660 然后这儿有个1 And here is a 1. 837 00:41:32,800 --> 00:41:36,140 第2个斐波那契数就是第1个斐波那契数 And Fibonacci of 2 is really the sum of Fibonacci of 1. 838 00:41:38,300 --> 00:41:39,220 和第0个斐波那契数的和 And Fib of 0, 839 00:41:40,580 --> 00:41:41,440 分别求出它们 in order to compute that, 840 00:41:41,480 --> 00:41:42,180 就有了一个1 I get a 1, 841 00:41:42,840 --> 00:41:43,860 和一个0 and here I've got a 0. 842 00:41:46,680 --> 00:41:47,500 我画出了一棵树 I've built a tree. 843 00:41:49,880 --> 00:41:52,440 通过这棵树我们能看出一些结果 Now,we can observe some things about this tree. 844 00:41:53,300 --> 00:41:53,920 我们能发现为何 We can see why 845 00:41:53,920 --> 00:41:55,540 这是个非常糟糕的 this is an extremely bad way 846 00:41:55,540 --> 00:41:56,720 求斐波那契数的办法 to compute Fibonacci numbers. 847 00:41:58,120 --> 00:42:00,020 因为 为了求第4个斐波那契数 Because in order to compute Fibonacci of 4, 848 00:42:00,180 --> 00:42:02,740 就得求两次第2个斐波那契数 I had to compute Fibonacci of 2's sub-tree twice. 849 00:42:07,300 --> 00:42:09,000 实际上 如果再多求一个斐波那契数 In fact,in order to add one more, 850 00:42:09,400 --> 00:42:11,000 假设我想要求第5个斐波那契数 supposing I want to do Fibonacci of 5, 851 00:42:12,480 --> 00:42:13,540 那我要做的就是 what I really have to do then 852 00:42:13,540 --> 00:42:16,180 求第4个斐波那契数和第3个斐波那契数的和 is compute Fibonacci of 4 plus Fibonacci of 3. 853 00:42:17,760 --> 00:42:20,900 但第3个斐波那契数已经求过一遍了 But Fibonacci of 3's sub-tree has already been built. 854 00:42:24,500 --> 00:42:29,200 整个递归树描述了一个 指数时间复杂度的递归计算过程 This is a prescription for a process that's exponential in time. 855 00:42:30,220 --> 00:42:31,100 只要多求一个斐波那契数 To add 1, 856 00:42:31,360 --> 00:42:32,800 时间复杂度就得乘上一个数 I have to multiply by something 857 00:42:32,800 --> 00:42:33,920 因为多求一个斐波那契数 需要把已经计算过的过程 because I take a proportion 858 00:42:33,920 --> 00:42:34,660 再计算一次 of the existing thing 859 00:42:34,660 --> 00:42:38,660 时间复杂度就成比例地急剧增长 and add it to itself to add one more step. 860 00:42:40,200 --> 00:42:47,760 于是这个过程的时间复杂度就是 So this is a thing whose time complexity is order of 861 00:42:47,940 --> 00:42:50,600 实际上就是O(Fib(n)) (Fib(n)指第n个斐波那契数) -- actually,it turns out to be Fibonacci-- of n. 862 00:42:55,940 --> 00:42:58,240 这个过程的时间复杂度就是按斐波那契数列增长 There's a thing that grows exactly at Fibonacci numbers. 863 00:43:00,760 --> 00:43:01,560 这很恐怖 It's a horrible thing. 864 00:43:02,240 --> 00:43:03,040 你都不想这么求斐波那契数 You wouldn't want to do it. 865 00:43:03,440 --> 00:43:05,180 时间复杂度这么增长 The reason why the time has to grow that way 866 00:43:05,180 --> 00:43:06,680 是因为在这个模型中 is because we're presuming in the model 867 00:43:06,680 --> 00:43:08,140 之前给出的代换模型 --the substitution model that I gave you, 868 00:43:08,140 --> 00:43:09,580 我没在这儿形式化地应用代换模型 which I'm not doing formally here, 869 00:43:10,280 --> 00:43:13,200 只是简单地表示了一下 I sort of now spit it out in a simple way-- 870 00:43:14,000 --> 00:43:16,200 我们假设所有事情都是按顺序完成的 but presuming that everything is done sequentially. 871 00:43:17,560 --> 00:43:21,180 即这个递归树中每个节点都会被检查 That every one of these nodes in this tree has to be examined. 872 00:43:24,420 --> 00:43:25,580 于是 由于树的节点数 And so since the number of nodes 873 00:43:25,580 --> 00:43:27,660 是按指数增长的 in this tree grows exponentially, 874 00:43:28,080 --> 00:43:30,020 因为要多求一个斐波那契数 because I add a proportion of the existing nodes 875 00:43:30,760 --> 00:43:32,440 就要把已经遍历过的节点再遍历一遍 to the nodes I already have to add 1, 876 00:43:33,880 --> 00:43:36,800 然后就发现时间复杂度呈爆炸式的指数增长 then I know I've got an exponential explosion here. 877 00:43:38,460 --> 00:43:39,840 现在 再来考虑 Now,let's see if we can think of 878 00:43:39,840 --> 00:43:41,200 这个过程的空间复杂度 how much space this takes up. 879 00:43:44,160 --> 00:43:45,180 空间复杂度不算太高 Well,it's not so bad. 880 00:43:45,800 --> 00:43:47,360 它主要取决于我们要记录多少信息 It depends on how much we have to remember 881 00:43:47,360 --> 00:43:48,620 才能使整个计算过程得以持续进行 in order to continue this thing running. 882 00:43:50,280 --> 00:43:51,220 这个并不难 Well,that's not so hard. 883 00:43:51,500 --> 00:43:52,220 从这里看出 It says,gee, 884 00:43:52,400 --> 00:43:54,220 想要知道我现在处于树中的什么位置 in order to know where I am in this tree, 885 00:43:54,340 --> 00:43:55,880 就要记录一条回到根节点的路径 I have to have a path back to the root. 886 00:43:56,720 --> 00:43:57,160 也就是说 In other words, 887 00:43:57,340 --> 00:43:57,800 为了 in order to-- 888 00:43:57,800 --> 00:43:58,720 考虑一下路径 let's consider the path. 889 00:43:58,720 --> 00:43:59,680 我要把这个过程执行一遍 I would have to execute this. 890 00:44:00,400 --> 00:44:01,180 我说 啊 好吧 I'd say,oh,yes 891 00:44:01,180 --> 00:44:02,220 我向下走到这儿 I'm going to go down here. 892 00:44:02,580 --> 00:44:03,940 不用管方向 I don't care which direction I go. 893 00:44:04,620 --> 00:44:05,660 我这么走 I have to do this. 894 00:44:06,100 --> 00:44:06,880 这么走 I have to then do this. 895 00:44:06,880 --> 00:44:08,880 用一种有趣的方式遍历这棵树 I have to traverse this tree in a sort of funny way. 896 00:44:11,660 --> 00:44:13,180 又接着走这条有趣的小路 I'm going to walk this nice little path. 897 00:44:13,580 --> 00:44:14,680 回到了这里 I come back to here. 898 00:44:15,400 --> 00:44:17,420 好了我已经记住接下来要去哪儿了 Well,I've got to remember where I'm going to be next. 899 00:44:18,180 --> 00:44:19,200 我记在心里了 I've got to keep that in mind. 900 00:44:19,800 --> 00:44:20,860 于是我得知道已经遍历过的节点 So I have to know what I've done. 901 00:44:20,860 --> 00:44:22,020 还得知道未遍历的节点 I have to know what's left. 902 00:44:22,400 --> 00:44:25,600 为了计算出第4个斐波那契数 In order to compute Fibonacci of 4, 903 00:44:25,600 --> 00:44:27,600 某一时刻我会向下走到这儿 at some point I'm going to have to be down here. 904 00:44:28,260 --> 00:44:29,740 我还要记得 And I have to remember 905 00:44:30,080 --> 00:44:31,360 要回到这儿 that I have to go back to here 906 00:44:31,540 --> 00:44:32,960 又回到这儿做一次加法 and then go back to here to do an addition. 907 00:44:33,380 --> 00:44:34,420 然后又走到这儿做一次加法 And then go back to here to do an addition 908 00:44:34,420 --> 00:44:35,440 之前还需要检查这个尚未检查的节点 to something I haven't touched yet. 909 00:44:37,880 --> 00:44:40,340 消耗的空间就是路径的长度 The amount of space that takes up is the path, 910 00:44:40,340 --> 00:44:41,160 最长路径的长度 the longest path. 911 00:44:42,400 --> 00:44:43,360 它有多长 How long it is. 912 00:44:45,620 --> 00:44:46,860 长度就是n And that grows as n. 913 00:44:48,080 --> 00:44:48,860 于是消耗的空间 So the space 914 00:44:50,640 --> 00:44:53,620 因为那是树的最长下降深度 -- because that's the length of the deepest line through the tree-- 915 00:44:54,280 --> 00:44:56,220 空间复杂度就是O(n) the space is order of n. 916 00:44:58,880 --> 00:44:59,920 可以看出这个过程时空效率都很低 It's a pretty bad process. 917 00:45:08,660 --> 00:45:10,260 我想让各位获得的是 Now,one thing I want to see from this 918 00:45:11,860 --> 00:45:13,520 一种直观的感觉 is a feeling 919 00:45:13,540 --> 00:45:14,440 关于整个计算过程的直观感觉 of what's going on here. 920 00:45:15,380 --> 00:45:16,560 为何 Why are there-- 921 00:45:17,140 --> 00:45:19,420 这个程序是如何与整个计算过程联系起来的 how is this program related to this process? 922 00:45:20,800 --> 00:45:21,620 在这儿 我们看到了什么 Well,what are we seeing here? 923 00:45:21,800 --> 00:45:22,820 这个程序实际上 There really are 924 00:45:23,740 --> 00:45:25,640 只做了两件事 only two sorts of things this program does. 925 00:45:27,080 --> 00:45:28,620 这个程序由两条规则组成 This program consists of two rules, 926 00:45:28,620 --> 00:45:29,100 假如你也这么认为的话 if you will. 927 00:45:29,560 --> 00:45:31,700 第一条规则是 第n个斐波那契数 One rule that says Fibonacci of n 928 00:45:32,200 --> 00:45:36,200 就是这里求和过程的结果 is this sum that you see over here, 929 00:45:37,240 --> 00:45:39,400 对应递归树中这样的一个节点 which is a node that's shaped like this. 930 00:45:41,900 --> 00:45:44,880 它指出要把整个过程分为两部分 It says that I break up something into two parts. 931 00:45:46,340 --> 00:45:49,340 在有的情况下 看这里 Under some condition,under some condition over here 932 00:45:49,860 --> 00:45:51,040 n比2大 that n is greater than 2, 933 00:45:56,500 --> 00:45:56,520 比2小 Less than 2. 934 00:45:56,520 --> 00:45:57,040 递归树中对应节点就分为两部分 then the node breaks up into two parts. 比2小 Less than 2. 935 00:45:57,580 --> 00:45:58,560 不 比2大 是的 No.Greater than 2.Yes. 936 00:46:01,600 --> 00:46:03,600 还有一种可能 The other possibility is that 937 00:46:03,600 --> 00:46:05,140 有的归约导致节点没有分成两部分 I have a reduction that looks like this. 938 00:46:08,920 --> 00:46:09,780 也就是这样的情况 And that's this case. 939 00:46:10,960 --> 00:46:11,740 如果比2小 If it's less than 2, 940 00:46:11,740 --> 00:46:12,780 答案就是n本身 the answer is n itself. 941 00:46:14,200 --> 00:46:15,200 我们在这儿看到的是 So what we're seeing here is that 942 00:46:15,360 --> 00:46:16,860 构建起的计算过程 the process that got built 943 00:46:17,440 --> 00:46:18,740 局部来看 每个节点 locally at every place 944 00:46:19,260 --> 00:46:20,440 都是这条规则的实际体现 is an instance of this rule. 945 00:46:21,920 --> 00:46:23,220 这里是规则的一次实际体现 Here's one instance of the rule. 946 00:46:23,800 --> 00:46:25,220 这里是规则的又一次实际体现 Here is another instance of the rule. 947 00:46:26,080 --> 00:46:27,380 人们之所以认为 And the reason why people think of 948 00:46:27,380 --> 00:46:29,260 编程很难 确实挺难的 programming as being hard,of course, 949 00:46:29,900 --> 00:46:32,160 是因为编程实际是在编写一种通用规则 is because you're writing down a general rule, 950 00:46:34,720 --> 00:46:36,340 这种通用规则会被应用于很多实际情况 which is going to be used for lots of instances, 951 00:46:37,000 --> 00:46:38,200 而某一个特定的实际情况 that a particular instance-- 952 00:46:38,840 --> 00:46:41,540 而编写好的程序会为你处理每种特定的实际情况 it's going to control each particular instance for you. 953 00:46:43,560 --> 00:46:44,640 你必须写出这样的程序 You've got to write down something 954 00:46:44,640 --> 00:46:47,180 它是通用的 并且考虑到变量 that's a general and in terms of variables, 955 00:46:47,180 --> 00:46:48,160 你要考虑那些变量 and you have to think of all the things 956 00:46:48,160 --> 00:46:49,540 所有可能的取值 that could possibly fit in those variables, 957 00:46:49,800 --> 00:46:50,760 所有这些最终都必须通向 and all those have to lead to 958 00:46:50,760 --> 00:46:52,180 你想要实现的计算过程 the process you want to work. 959 00:46:53,200 --> 00:46:55,400 局部看来 你又得把计算过程分成 Locally,you have to break up your process 960 00:46:56,100 --> 00:46:58,240 可以表示出来的若干部分 into things that can be represented 961 00:46:58,240 --> 00:47:00,340 考虑到这些非常特定的局部规则 in terms of these very specific local rules. 962 00:47:03,220 --> 00:47:03,800 好了 来看一下 Well,let's see. 963 00:47:04,660 --> 00:47:06,800 斐波那契数 当然了 不太有趣 Fibonaccis are,of course,not much fun. 964 00:47:07,820 --> 00:47:08,440 不 其实还是挺有趣的 Yes,they are. 965 00:47:09,160 --> 00:47:10,920 大家还会学习黄金分割等概念 You get something called the golden ratio, 966 00:47:12,100 --> 00:47:14,060 并且说不定什么时候我们还有可能接触 更多的类似的东西 and we may even see a lot of that some time. 967 00:47:15,080 --> 00:47:16,140 好了 下面来讨论另一件事 Well,let's talk about another thing. 968 00:47:16,600 --> 00:47:19,640 有个很有名的游戏叫汉诺塔 There's a famous game called the Towers of Hanoi, 969 00:47:19,640 --> 00:47:20,280 举这个例子是因为我教会大家 because I want to teach you 970 00:47:20,280 --> 00:47:21,980 如何递归地思考问题 how to think about things recursively. 971 00:47:23,860 --> 00:47:25,940 游戏是这样的 The problem is this one: 972 00:47:26,860 --> 00:47:28,040 我有一堆盘子 I have a bunch of disks, 973 00:47:29,040 --> 00:47:30,060 又有几根柱子 I have a bunch of spikes, 974 00:47:31,500 --> 00:47:34,300 传说在遥远的东方某地 and it's rumored that somewhere in the Orient 975 00:47:35,100 --> 00:47:36,760 有一个有64个盘子的汉诺塔 there is a 64-high tower, 976 00:47:37,080 --> 00:47:39,100 僧侣们每天的工作就是 and the job of various monks or something 977 00:47:39,200 --> 00:47:40,600 移动盘子从一个柱子到另一个 is to move these spikes 978 00:47:40,600 --> 00:47:41,860 移动的规则很复杂 in some complicated pattern 979 00:47:42,040 --> 00:47:44,540 然后最终这些盘子 so eventually-- these disks-- 980 00:47:44,940 --> 00:47:48,520 最终我把所有的盘子 so eventually I moved all of the disks 981 00:47:48,660 --> 00:47:49,840 从一个柱子移到了另一个柱子 from one spike to the other. 982 00:47:50,380 --> 00:47:51,540 如果有64个盘子 And if it's 64 high, 983 00:47:52,000 --> 00:47:54,180 就要移动2的64次方(减1 译者注)次 and it's going to take 2 to the 64th moves, 984 00:47:54,980 --> 00:47:56,180 要花费很长时间 then it's a long time. 985 00:47:57,820 --> 00:48:01,500 僧侣们声称盘子移完之时即是宇宙终结之时 They claim that the universe ends when this is done. 986 00:48:03,420 --> 00:48:04,060 好了 Well,let's see. 987 00:48:05,580 --> 00:48:08,120 构造一个递归过程的方法其实很简单 The way in which you would construct a recursive process 988 00:48:08,720 --> 00:48:09,660 就是“想当然” is by wishful thinking. 989 00:48:11,580 --> 00:48:12,440 你们要相信 You have to believe. 990 00:48:14,340 --> 00:48:15,240 这个主意 So,the idea. 991 00:48:15,320 --> 00:48:18,360 假如我想把这一堆盘子从这儿移到这儿 Supposing I want to move this pile from here to here, 992 00:48:19,500 --> 00:48:21,360 从1号柱移动到2号柱 from spike one to spike two, 993 00:48:23,460 --> 00:48:24,540 好吧 其实不怎么难 well,that's not so hard. 994 00:48:25,100 --> 00:48:26,540 假如 不知怎么回事 See,supposing somehow, 995 00:48:27,000 --> 00:48:27,780 好像有魔法在作用 by some magic-- 996 00:48:27,860 --> 00:48:28,860 因为有个更简单的问题 because I've got a simpler problem 997 00:48:29,020 --> 00:48:30,600 我把3个盘子移到这里 -- I move a three-high pile to here-- 998 00:48:30,860 --> 00:48:32,000 一次只能移动一个盘子 I can only move one disk at a time, 999 00:48:32,000 --> 00:48:32,960 不管我是怎么做到的 so I don't even think how I did it. 1000 00:48:33,640 --> 00:48:34,800 但假设我做到了 But supposing I could do that, 1001 00:48:36,300 --> 00:48:38,080 那我只用拿起这个盘子 well,then I could just pick up this disk 1002 00:48:38,080 --> 00:48:38,680 把它移到这里 and move it here. 1003 00:48:41,140 --> 00:48:42,520 现在问题就简单了 And now I have a simple problem, 1004 00:48:42,620 --> 00:48:43,940 把这3个盘子移到这里 I have to move a three-high tower to here, 1005 00:48:44,680 --> 00:48:45,420 之前已经做过了 which is no problem. 1006 00:48:45,780 --> 00:48:47,780 于是通过两次对3个盘子的移动 So by two moves of a three high tower 1007 00:48:47,780 --> 00:48:49,180 再加上1次对一个盘子的移动 plus one move of a single object. 1008 00:48:50,700 --> 00:48:52,760 我就能把整堆盘子从这儿移动到这儿 I can move the tower from here to here. 1009 00:48:55,260 --> 00:48:56,440 不管怎样 Now,whether or not-- 1010 00:48:57,180 --> 00:48:58,440 不管探究到什么程度 this is not obvious 1011 00:48:59,240 --> 00:49:00,980 都不能明显看出整个过程是正确的 in any deep way that this works. 1012 00:49:02,360 --> 00:49:02,980 还有 为什么呢 And why? 1013 00:49:03,900 --> 00:49:06,520 为什么我就能假设 Now why is it the case that I can presume,maybe, 1014 00:49:06,640 --> 00:49:07,920 假设我能把成功移动这三个盘子 that I can move the three-high tower. 1015 00:49:11,080 --> 00:49:12,260 好吧 这是因为 Well the answer is because 1016 00:49:12,540 --> 00:49:13,660 我总能减小问题的规模 I'm always counting down, 1017 00:49:14,080 --> 00:49:15,960 然后最终是0个盘子的移动问题 and eventually I get down to zero-high tower, 1018 00:49:16,200 --> 00:49:17,800 0个盘子不需要移动 and a zero-high tower requires no moves. 1019 00:49:19,800 --> 00:49:21,680 现在可以写出整个过程的算法了 So let's write the algorithm for that. 1020 00:49:23,820 --> 00:49:24,400 很简单 Very easy. 1021 00:49:26,120 --> 00:49:28,720 我会给这些柱子编号 I'm going to label these towers with numbers, 1022 00:49:28,720 --> 00:49:30,120 但它们各自编号成什么无关紧要 but it doesn't matter what they're labelled with. 1023 00:49:30,780 --> 00:49:32,800 问题就是把n个盘子 And the problem is to move an n-high tower 1024 00:49:33,800 --> 00:49:36,440 从一个起始柱移到终点柱 from a spike called From to a spike called To 1025 00:49:36,620 --> 00:49:38,240 另一个柱子作为中转 称作中转柱 with a particular spike called Spare. 1026 00:49:39,520 --> 00:49:40,200 这就是主要的过程 That's what we're going to do. 1027 00:49:48,700 --> 00:49:52,120 用这个我非形式化描述的算法 Using the algorithm I informally described to you, 1028 00:49:52,720 --> 00:50:01,700 把n个盘子从起始柱移到终点柱 另一个柱子作为中转 move of a n-high tower from From to To with a Spare. 1029 00:50:05,940 --> 00:50:08,480 接着就有两种情况了 Well,I've got two cases, 1030 00:50:09,220 --> 00:50:10,480 就要分析都是怎样的情况 and this is a case analysis, 1031 00:50:10,940 --> 00:50:14,360 就像之前所做的分析一样 just like it is in all the other things we've done. 1032 00:50:20,920 --> 00:50:21,840 如果n等于0 那么 If n is 0,then 1033 00:50:22,780 --> 00:50:24,940 我会输出一些东西 输出"Done" -- I'm going to put out some answers-- Done,we'll say. 1034 00:50:26,560 --> 00:50:27,560 我不知道那代表什么意思 I don't know what that means 1035 00:50:29,360 --> 00:50:31,160 因为我们也不会遇到这样的情况 Because we'll never use that answer for anything. 1036 00:50:31,640 --> 00:50:32,620 我们还是会移动盘子的 We're going to do these moves. 1037 00:50:34,000 --> 00:50:34,380 否则 Else. 1038 00:50:36,280 --> 00:50:37,320 就移动一次 I'm going to do a move. 1039 00:50:39,900 --> 00:50:42,360 移动少于n个盘子 Move a tower of height less than n, 1040 00:50:44,160 --> 00:50:46,300 也就是n-1个盘子 the decrement of n height. 1041 00:50:47,740 --> 00:50:50,080 把它们移到中转柱上 Now,I'm going to move it to the Spare tower. 1042 00:50:50,720 --> 00:50:51,720 整体的思想就是 The whole idea now 1043 00:50:52,020 --> 00:50:53,880 把它们从这里移到这里 is to move this from here to here, 1044 00:50:54,940 --> 00:50:55,600 移到中转柱 to the Spare tower 1045 00:50:55,860 --> 00:50:57,160 从起始柱到中转柱 -- so from From to Spare-- 1046 00:51:02,340 --> 00:51:04,380 用终点柱作为中转 using To as a spare tower. 1047 00:51:08,560 --> 00:51:10,080 之后某个时候 Later,somewhere later, 1048 00:51:10,080 --> 00:51:14,800 我就会移动之前的那n个盘子 I'm going to move that same n-high tower, 1049 00:51:15,240 --> 00:51:16,160 在那之前已经完成了这个盘子的移动 after I've done this. 1050 00:51:17,340 --> 00:51:20,200 要移动n个盘子同样的道理就要上面的n-1个盘子 Going to move that same n minus one-high tower 1051 00:51:20,620 --> 00:51:23,540 从中转柱移到终点柱 from the Spare tower to the To tower 1052 00:51:23,940 --> 00:51:25,860 用起始柱作为中转 using the From tower as my spare. 1053 00:51:29,060 --> 00:51:39,040 编写成代码就是从中转柱移动到终点柱 So the Spare tower to the To tower 1054 00:51:40,040 --> 00:51:44,140 用起始柱作为中转 using the From as the spare. 1055 00:51:48,440 --> 00:51:49,580 当进行到这种情况 All I have to do now 1056 00:51:50,020 --> 00:51:51,840 剩下要做的事情就是 is when I've gotten it in this condition, 1057 00:51:52,100 --> 00:51:55,080 现在就是这种情况 between these two moves of a whole tower 1058 00:51:56,260 --> 00:51:57,420 在两次移动同一堆盘子之间 -- I've got it into that condition-- 1059 00:51:57,580 --> 00:52:00,480 只需移动一个盘子 now I just have to move one disk. 1060 00:52:02,820 --> 00:52:03,380 所以我想要说的就是 So I'm going to say that 1061 00:52:03,380 --> 00:52:04,300 有个什么过程输出一条信息 表示做了一次盘子的移动 some things are printing a move 1062 00:52:04,300 --> 00:52:05,200 不管这个过程具体怎么实现的 and I don't care how it works. 1063 00:52:11,340 --> 00:52:13,900 把盘子从起始柱移动到终点柱 From to To. 1064 00:52:17,420 --> 00:52:19,780 现在大家就能明白为何我在这个时候举这样一个例子 Now,you see the reason why I'm bringing this up 1065 00:52:19,780 --> 00:52:23,060 是因为在某种程度上 at this moment is this is an almost identical program 1066 00:52:23,060 --> 00:52:25,060 这个程序和之前这个程序几乎一样 to this one in some sense. 1067 00:52:26,600 --> 00:52:28,940 尽管它们所求解的问题不一样 It's not computing the same mathematical quantity, 1068 00:52:29,240 --> 00:52:30,940 演化出的递归树也不尽相同 it's not exactly the same tree, 1069 00:52:31,220 --> 00:52:32,320 但不管怎样都会在计算过程中演化出一棵递归树 but it's going to produce a tree. 1070 00:52:34,300 --> 00:52:36,180 移动这些盘子的过程 The general way of making these moves 1071 00:52:36,920 --> 00:52:39,580 会导致生成一棵指数树 is going to lead to an exponential tree. 1072 00:52:41,380 --> 00:52:43,060 好了 接下来试着来移动4个盘子 Well,let's do this four-high. 1073 00:52:44,100 --> 00:52:47,220 我还是得看着小抄来移盘子 I have my little crib sheet here 1074 00:52:49,240 --> 00:52:50,400 不然会弄错 otherwise I get confused. 1075 00:52:54,360 --> 00:52:56,480 好了 下面形式化地提出这个问题 Well,what I'm going to put in is the question of 1076 00:52:56,700 --> 00:53:05,400 把4个摞在一起的盘子 move a tower of height four 1077 00:53:06,240 --> 00:53:08,500 从1号柱子移动到2号 from one to spike two 1078 00:53:08,660 --> 00:53:10,460 用3号柱子作为中转 using spike three as a spare. 1079 00:53:11,680 --> 00:53:12,720 这就是接下来我要做的 That's all I'm really going to do. 1080 00:53:13,860 --> 00:53:15,140 好吧 开始吧 You know,let's just do it. 1081 00:53:15,140 --> 00:53:16,120 我不打算写出 I'm not going to worry about 1082 00:53:16,120 --> 00:53:17,580 过程执行的具体步骤 writing out the trace of this. 1083 00:53:17,620 --> 00:53:18,540 你自己可以做到 You can do that yourself 1084 00:53:19,560 --> 00:53:20,380 因为那很简单 because it's very simple. 1085 00:53:21,620 --> 00:53:24,580 我要把1号柱子上的一个盘子移动到3号柱子上 I'm going to move disk one to disk three. 1086 00:53:26,300 --> 00:53:28,100 这是怎么回事呢 And how do I get to move disk one to disk three? 1087 00:53:28,280 --> 00:53:28,940 我怎么知道要这么做呢 How do I know that? 1088 00:53:29,180 --> 00:53:30,820 好吧 我想还是得查看一下程序执行的具体步骤 Well,I suppose I have to look at the trace a little bit. 1089 00:53:32,420 --> 00:53:33,220 才能明白我这是在做什么 What am I doing here? 1090 00:53:33,520 --> 00:53:34,440 好吧 这个不等于 Well,and this is not-- 1091 00:53:34,440 --> 00:53:35,340 n不等于0 n is not zero. 1092 00:53:36,400 --> 00:53:37,860 那我看一下这里过程的定义 So I'm going to look down here. 1093 00:53:38,340 --> 00:53:40,220 这得需要两次移动 This is going to require doing two moves. 1094 00:53:40,640 --> 00:53:41,680 只观察第一次吧 I'm only going to look at the first one. 1095 00:53:41,940 --> 00:53:43,160 第一次是说把 It's going to require moving-- 1096 00:53:47,500 --> 00:53:48,880 我怎么写成了移动一座塔 why do I have move tower? 1097 00:53:48,880 --> 00:53:50,340 塔可不好移 It makes it harder for me to move. 1098 00:53:52,580 --> 00:53:56,280 我要移动摞成一摞的3个盘子 I'm going to move a three-high tower 1099 00:53:57,560 --> 00:53:59,460 从起始柱 from the From place, 1100 00:53:59,580 --> 00:54:00,340 也就是4号柱(教授不小心犯错 译者注) which is four, 1101 00:54:01,400 --> 00:54:02,160 移动到中转柱 to the Spare, 1102 00:54:02,320 --> 00:54:03,140 即2号柱 which is two, 1103 00:54:03,900 --> 00:54:06,400 用3号柱 using three as my 1104 00:54:07,960 --> 00:54:09,800 不 用 用 -- no,using,using-- 1105 00:54:09,980 --> 00:54:15,740 学生 [听不清] STUDENT: [INAUDIBLE PHRASE] 1106 00:54:15,820 --> 00:54:16,920 教授 啊 是这样 抱歉 PROFESSOR: Yes,I'm sorry. 1107 00:54:17,540 --> 00:54:18,880 从2号柱 From two-- 1108 00:54:19,340 --> 00:54:25,680 从1号柱到3号柱用2号柱作为中转 from one to three using two as my spare. 1109 00:54:25,900 --> 00:54:26,200 这就对了 That's right. 1110 00:54:27,140 --> 00:54:31,200 之后这儿还有一次移动 And then there's another move over here afterwards. 1111 00:54:32,800 --> 00:54:33,580 现在可以说 So now I say, 1112 00:54:33,880 --> 00:54:34,320 啊 是的 oh,yes, 1113 00:54:34,420 --> 00:54:37,880 接下来还得把之上两个盘子 that requires me moving a two-high tower 1114 00:54:38,680 --> 00:54:42,140 从1号柱移动到2号柱 用3号柱作为中转 from one to two using three as a spare. 1115 00:54:43,000 --> 00:54:43,960 同样的还得再移一次 And so,are the same, 1116 00:54:44,580 --> 00:54:45,980 接下来 又要移动 and that's going to require me moving 1117 00:54:47,540 --> 00:54:52,000 一个盘子 从1号柱到2号柱 a one-high tower from one to three 1118 00:54:52,180 --> 00:54:53,220 用2号柱作为中转 using two as a spare. 1119 00:54:57,500 --> 00:54:59,300 好了 当然之后还得再移一次 Well,and then there's lots of other things to be done. 1120 00:55:03,260 --> 00:55:05,080 于是我把1个盘子 So I move my one-high tower 1121 00:55:06,160 --> 00:55:09,220 从1号柱移动到3号柱 用2号柱作为中转 from one to three using two as a spare, 1122 00:55:09,220 --> 00:55:10,300 实际上没用到2号柱 which I didn't do anything with. 1123 00:55:11,140 --> 00:55:12,800 好了 整个过程还是非常简单的 Well,this thing just proceeds very simply. 1124 00:55:15,300 --> 00:55:16,660 接下来我把这个盘子从1号柱移到2号柱 I move this from one to two. 1125 00:55:17,360 --> 00:55:19,260 然后把这个盘子从3号柱移动到2号柱 And I move this disk from three to two. 1126 00:55:20,980 --> 00:55:22,120 其实我不想移了 And I don't really want to do it, 1127 00:55:22,520 --> 00:55:23,800 但还得继续 从1到3 but I move from one to three. 1128 00:55:24,680 --> 00:55:26,480 然后从2到1 Then I move two to one. 1129 00:55:29,040 --> 00:55:30,400 从2到3 Then I move two to three. 1130 00:55:31,940 --> 00:55:34,900 从1到3 Then one to three. 1131 00:55:35,940 --> 00:55:36,820 1到2 One to two. 1132 00:55:39,360 --> 00:55:41,040 3到2 Three to two. 1133 00:55:41,800 --> 00:55:42,560 3到1 Three to one. 1134 00:55:44,060 --> 00:55:45,540 当然了这是因为我之前已经准备好了 This all got worked out beforehand,of course. 1135 00:55:46,040 --> 00:55:46,700 2到1 Two to one. 1136 00:55:47,480 --> 00:55:48,980 3到2 Three to two. 1137 00:55:49,780 --> 00:55:51,420 1到3 One to three. 1138 00:55:52,920 --> 00:55:54,040 学生: [听不清] STUDENT: [INAUDIBLE PHRASE]. 1139 00:55:54,060 --> 00:55:54,840 教授:噢 从1到3 PROFESSOR: Oh,one to three. 1140 00:55:54,840 --> 00:55:55,780 抱歉 谢谢提醒 Excuse me.Thank you. 1141 00:55:56,080 --> 00:55:56,840 1到2 One to two. 1142 00:55:58,720 --> 00:56:01,520 然后3到2 呼 And then three to two.Whew. 1143 00:56:03,880 --> 00:56:05,920 现在请大家思考 Now what I'd like you to think about, 1144 00:56:07,120 --> 00:56:08,820 你们刚才看到的是解决这个问题的递归算法 you just saw a recursive algorithm for doing this, 1145 00:56:09,100 --> 00:56:10,340 显然要耗费指数级的时间 and it takes exponential time,of course. 1146 00:56:11,120 --> 00:56:12,220 不知道是否有别的算法 Now,I don't know if there's any algorithm 1147 00:56:12,220 --> 00:56:14,060 不用耗费指数级的时间 它一定会耗费指数级的时间 that doesn't take exponential time-- it has to. 1148 00:56:14,440 --> 00:56:15,920 因为我每次只能移动一个盘子 As I'm doing one operation 1149 00:56:15,920 --> 00:56:17,240 每次只能移动一个盘子 -- I can only move one thing at a time-- 1150 00:56:17,540 --> 00:56:19,240 没有什么算法不用耗费指数级的时间 there's no algorithm that's not going to take exponential time. 1151 00:56:21,420 --> 00:56:22,640 但是 你能写出迭代的算法 But can you write an iterative algorithm 1152 00:56:23,640 --> 00:56:25,160 而不是递归的算法么 rather than a recursive algorithm for doing this? 1153 00:56:28,360 --> 00:56:30,260 我一直爱琢磨 One of the sort of little things I like to think about 1154 00:56:32,320 --> 00:56:34,840 能否给出一个算法 Can you write one that, 1155 00:56:35,040 --> 00:56:39,060 不是像我描述的这样 in fact,doesn't break this problem 1156 00:56:39,080 --> 00:56:40,560 把一个问题分解成两个子问题 into two sub-problems the way I described, 1157 00:56:41,020 --> 00:56:43,200 而是用一个更局部的规则 but rather proceeds a step at a time 1158 00:56:43,260 --> 00:56:44,800 一次演化出整个计算过程 using a more local rule. 1159 00:56:47,760 --> 00:56:48,480 那可能会很有趣 That might be fun. 1160 00:56:50,340 --> 00:56:51,720 谢谢大家 第三部分结束 Thank you so much for the third segment. 1161 00:56:55,880 --> 00:56:56,380 有什么问题要问么 Are there questions? 1162 00:56:57,400 --> 00:56:58,280 学生 我想知道有没有什么办法 STUDENT: I wonder if there's a way 1163 00:56:58,280 --> 00:57:01,660 能减小递归过程的代价 to reduce a tree or recursion problem, 1164 00:57:02,060 --> 00:57:05,660 能否把中间过程 how do you save the intermediate work 1165 00:57:05,760 --> 00:57:08,180 计算出的斐波那契数保存下来 you have done in computing the Fibonacci number? 1166 00:57:09,000 --> 00:57:10,100 教授 呃 好吧 实际上 PROFESSOR: Oh,well,in fact,one way,that 1167 00:57:11,200 --> 00:57:13,120 你刚才说的就是一种办法 one of the ways to do is what you just said. 1168 00:57:13,580 --> 00:57:16,500 你说 把中间过程的结果保存下来 是吧 You said,I save the intermediate work.OK? 1169 00:57:16,620 --> 00:57:18,360 好的 我告诉你 Well,let me tell you 1170 00:57:18,940 --> 00:57:20,100 再次说一下 我们后面会见到 -- this,again,we'll see later-- 1171 00:57:20,720 --> 00:57:21,820 但现在假设就是这种情形 but suppose it's the case 1172 00:57:22,360 --> 00:57:24,060 不论何时做怎样的计算 that anytime I compute anything, 1173 00:57:24,340 --> 00:57:25,720 所有的这些斐波那契数 any one of these Fibonacci numbers, 1174 00:57:26,400 --> 00:57:27,620 我记录一个表 I remember the table 1175 00:57:27,900 --> 00:57:28,920 在表中查询 that takes only linear time 1176 00:57:28,920 --> 00:57:31,580 只用线性的时间 to look up the answer. 1177 00:57:32,720 --> 00:57:33,660 如果我已经计算过了 Then if I ever see it again, 1178 00:57:33,660 --> 00:57:35,340 就不再递归地求解了 instead of doing the expansional tree, 1179 00:57:35,620 --> 00:57:36,100 是直接在表中查询 I look it up. 1180 00:57:36,700 --> 00:57:37,940 我把问题 I've just transformed my problem 1181 00:57:38,780 --> 00:57:39,840 变得简单多了 into a problem that's much simpler. 1182 00:57:40,980 --> 00:57:41,620 当然 Now,of course, 1183 00:57:42,260 --> 00:57:43,560 这种方法已经被使用了 there are the way to do this,as well. 1184 00:57:44,240 --> 00:57:45,340 这种方法叫作记忆化 That one's called memoization, 1185 00:57:45,340 --> 00:57:47,620 这学期你们就会遇到 and you'll see it sometime later in this term. 1186 00:57:48,240 --> 00:57:53,280 但我认为还有个方法是线性时间复杂度的 But I suppose there's a very simple linear time and, 1187 00:57:53,360 --> 00:57:55,920 实际上 是用迭代模型计算斐波那契数 in fact,iterative model for computing Fibonaccis, 1188 00:57:56,660 --> 00:57:58,200 这也是需要各位坐下来仔细思考的 and that's another thing you should sit down and work out. 1189 00:58:00,080 --> 00:58:00,720 这很重要 That's important. 1190 00:58:01,260 --> 00:58:02,620 明白怎么运用迭代模型很重要 It's important to see how to do this. 1191 00:58:05,200 --> 00:58:06,060 希望大家多练习一下 I want you to practice. 1192 00:58:06,500 --> 00:58:08,100 MIT OpenCourseWare http://ocw.mit.edu 1193 00:58:08,100 --> 00:58:10,240 本项目主页 https://github.com/FoOTOo/Learning-SICP ================================================ FILE: SrtCN/lec2a.srt ================================================ 1 00:00:00,000 --> 00:00:05,000 哈尔滨工业大学 IBM技术中心 倾情制作 2 00:00:05,100 --> 00:00:10,000 压制&&特效:蔡钟毓(JohnTitor) 翻译:徐梓翔(Dyul) 3 00:00:10,000 --> 00:00:15,000 特别感谢:裘宗燕教授 时间&&轴校对:邓雄飞(Dysprosium) 4 00:00:15,800 --> 00:00:20,500 高阶过程 Higher-order Procedures 5 00:00:25,280 --> 00:00:26,580 教授:昨天的内容还算容易 PROFESSOR: Well, yesterday was easy. 6 00:00:27,600 --> 00:00:29,440 你们了解到了所有的编程规则 You learned all of the rules of programming 7 00:00:30,740 --> 00:00:33,440 那些几乎是所有的规则了 and lived Almost all of them. 8 00:00:34,600 --> 00:00:37,100 所以此刻 你们算得上是所谓的--- And so at this point, you're now certified programmers 9 00:00:38,060 --> 00:00:38,740 合格的程序员了 -- it says. 10 00:00:39,700 --> 00:00:43,860 不过 我觉得其实是 啊... However, I suppose what we did is we, aah, 11 00:00:46,720 --> 00:00:50,660 其实只是给你们尝了点甜头 sort of got you a little bit of into an easy state. 12 00:00:51,280 --> 00:00:54,840 此时此刻 你可能还在认为这门课就像 Here, you still believe it's possible that this might be programming 13 00:00:54,840 --> 00:00:57,640 用BASIC语言或者Pascal语言的某种奇葩语法写程序 in BASIC or Pascal with just a funny syntax. 14 00:00:59,140 --> 00:01:04,440 然而就在今天 这种错觉将会被颠覆 Today, that illusion-- or you can no longer support that belief. 15 00:01:04,780 --> 00:01:07,140 我们即将做的事 就是要彻底粉碎这种想法 What we're going to do today is going to completely smash that. 16 00:01:08,080 --> 00:01:13,420 接下来 我会先在黑板上写一些程序 So let's start out by writing a few programs on the blackboard 17 00:01:13,420 --> 00:01:15,020 它们之间有很多相似之处 that have a lot in common with each other 18 00:01:15,960 --> 00:01:18,360 我们要做的是尝试将它们抽象出来 What we're going to do is try to make them abstractions 19 00:01:18,820 --> 00:01:22,960 这过程并不如在其它大多数语言中那么显而易见 that are not ones that are easy to make in most languages. 20 00:01:23,740 --> 00:01:25,080 让我们先从其它语言也能完成的 Let's start with some very simple ones 21 00:01:25,080 --> 00:01:26,520 简单的例子开始 that you can make in most languages. 22 00:01:27,640 --> 00:01:33,680 假设 我有一个求和一组整数的数学表达式 Supposing I want to write the mathematical expression which adds up a bunch of integers. 23 00:01:34,140 --> 00:01:41,100 比如 我写下的这个表达式 以I为索引 求和从A到B的整数 So if I wanted to write down and say the sum from i equal a to b on i. 24 00:01:41,100 --> 00:01:44,820 你们知道用数学公式可以很方便地计算出它的结果 Now, you know that that's an easy thing to compute in a closed form for it, 25 00:01:44,820 --> 00:01:45,760 但我的重点不在此 and I'm not interested in that. 26 00:01:45,760 --> 00:01:48,180 我想要写一个能够求和那些整数程序 But I'm going to write a program that adds up those integers. 27 00:01:48,960 --> 00:01:52,880 我们能够很容易地想到 Well, that's rather easy to do to say 28 00:01:53,300 --> 00:02:07,400 定义求和从A到B的整数的过程SUM-INT为 I want to define the sum of the integers from a to b to be 29 00:02:07,780 --> 00:02:10,640 接下来有两种可能性 well, it's the following two possibilities. 30 00:02:10,900 --> 00:02:13,420 如果A大于B If a is greater than b, 31 00:02:15,100 --> 00:02:18,220 毋庸置疑 答案就是0 well, then there's nothing to be done and the answer is zero. 32 00:02:18,980 --> 00:02:21,220 你要以递归的方式思考问题 This is how you're going to have to think recursively. 33 00:02:22,160 --> 00:02:25,020 比如 假如我知道某个简单情形的答案 You're going to say if I have an easy case that I know the answer to, 34 00:02:25,140 --> 00:02:25,980 就可以直接将其作为结果 just write it down. 35 00:02:26,220 --> 00:02:30,420 否则 我就需要将这个问题简化 Otherwise, I'm going to try to reduce this problem to a simpler problem. 36 00:02:30,620 --> 00:02:31,560 比如在这个程序里 And maybe in this case, 37 00:02:31,560 --> 00:02:33,240 我要简化出一个子问题 I'm going to make a subproblem of the simpler problem 38 00:02:33,240 --> 00:02:34,620 然后再做一些工作从而得出结果 and then do something to the result. 39 00:02:35,160 --> 00:02:38,700 所以针对这个程序 最简单的处理方式是 So the easiest way to do this is say that 40 00:02:38,700 --> 00:02:43,340 将下标 在这里是A I'm going to add the index, which in this case is a, 41 00:02:44,520 --> 00:02:57,500 加上A+1到B的整数的求和结果 to the result of adding up the integers from a plus 1 to b. 42 00:03:02,360 --> 00:03:04,860 现在你们应该都能看懂这个定义了 Now, at this point, you should have no trouble looking at such a definition. 43 00:03:05,740 --> 00:03:09,860 实际上 总的来说 要想得出这个过程定义还是有一些困难的 Indeed, coming up with such a thing might be a little hard in synthesis, 44 00:03:10,180 --> 00:03:12,500 但要想读明白还是比较容易的 but being able to read it at this point should be easy. 45 00:03:13,400 --> 00:03:15,880 现在我想告诉你们的是 And what it says to you is, well, 46 00:03:16,440 --> 00:03:18,960 这个是我想要求解的子问题 here is the subproblem I'm going to solve. 47 00:03:19,120 --> 00:03:21,560 我要求和的是 I'm going to try to add up the integers, 48 00:03:21,880 --> 00:03:25,540 比整个问题的规模少一的整数序列 one fewer integer than I added up for the the whole problem. 49 00:03:26,440 --> 00:03:28,100 接下来需要求和的整数序列的数目会一个个减少 I'm adding up the one fewer one, 50 00:03:28,820 --> 00:03:32,680 最后 当这个子问题求解完毕后 只要再加上a and that subproblem, once I've solved it, I'm going to add a to that, 51 00:03:34,200 --> 00:03:35,920 就能得到整个问题的答案了 and that will be the answer to this problem. 52 00:03:38,140 --> 00:03:40,400 并且 这里的最简单的情形 我不用做任何处理 And the simplest case, I don't have to do any work. 53 00:03:41,560 --> 00:03:45,160 接下来 我要给出另一个类似的简单问题--- Now, I'm also going to write down another simple one just like this, 54 00:03:46,260 --> 00:03:53,400 以I为下标 求和A到B的整数的平方的数学表达式 which is the mathematical expression, the sum of the square from i equal a to b. 55 00:03:55,340 --> 00:03:58,060 同样的 这个程序也很简单 And again, it's a very simple program. 56 00:04:11,180 --> 00:04:13,060 实际上 这个程序一开始和刚才是一样的 And indeed, it starts the same way. 57 00:04:16,220 --> 00:04:19,820 如果A大于B 那么答案就是0 If a is greater than b, then the answer is zero. 58 00:04:20,820 --> 00:04:25,980 显然 你会发现我又把这部分重复写了一遍 And, of course, we're beginning to see that there's something wrong with me writing this down again. 59 00:04:27,280 --> 00:04:28,860 这段程序和之前是相同的 It's the same program. 60 00:04:29,320 --> 00:04:45,900 这里是A的平方加上A+1到B的平方和 It's the sum of the square of a and the sum of the square of the increment and b. 61 00:04:50,440 --> 00:04:54,480 现在 你们再看看这两个程序 它们几乎是完全一样的 Now, if you look at these things, these programs are almost identical. 62 00:04:56,000 --> 00:04:58,860 并没有太大区别 There's not much to distinguish them. 63 00:04:59,760 --> 00:05:04,240 它们有相同的条件表达式、谓词和CONSEQUENCE子句 They have the same first clause of the conditional and the same predicate and the same consequence, 64 00:05:05,580 --> 00:05:07,880 ALTERNATIVE子句也非常地相似 and the alternatives are very similar, too. 65 00:05:08,660 --> 00:05:16,220 事实上 唯一区别是 这里是A 而这里是A的平方 They only differ by the fact that where here I have a, here, I have the square of a. 66 00:05:17,200 --> 00:05:21,620 另一个区别 有些无关紧要 The only other difference, but this one's sort of unessential 67 00:05:21,740 --> 00:05:23,860 是这个过程的名字是SUM-INT is in the name of this procedure is sum int, 68 00:05:24,540 --> 00:05:26,460 而这个过程的名字是SUM-SQUARE whereas the name of the procedure is sum square. 69 00:05:27,420 --> 00:05:31,140 所以这两个程序的区别微乎其微 So the things that vary between these two are very small. 70 00:05:32,760 --> 00:05:36,360 现在来看 如果你重复地写了相同的东西 Now, wherever you see yourself writing the same thing down more than once, 71 00:05:36,840 --> 00:05:38,740 这就有些问题 你并不应该那样做 there's something wrong, and you shouldn't be doing it. 72 00:05:39,800 --> 00:05:43,940 问题并不在于你重复的劳动带来时间浪费 And the reason is not because it's a waste of time to write something down more than once. 73 00:05:45,000 --> 00:05:48,900 而是在于里面的一些思想 非常简单的思想 It's because there's some idea here, a very simple idea, 74 00:05:50,260 --> 00:05:55,160 与求和记法相关的思想 就是这一部分 which has to do with the sigma notation-- this much-- 75 00:05:56,820 --> 00:05:59,400 其并不依赖于我待求和的内容 not depending upon what it is I'm adding up. 76 00:06:01,280 --> 00:06:05,900 无论何时 当要设计一个复杂的系统并且要弄明白它时 And I would like to be able to-- always, whenever trying to make complicated systems and understand them, 77 00:06:06,220 --> 00:06:09,440 将问题拆分成尽量多的模块是很重要的 it's crucial to divide the things up into as many pieces as I can, 78 00:06:09,640 --> 00:06:11,100 并且每一个模块要能够被独立地解释 each of which I understand separately. 79 00:06:12,640 --> 00:06:16,200 我知道在不依赖具体内容的情况下 把东西加起来的方法 I would like to understand the way of adding things up independently of what it is I'm adding up 80 00:06:17,040 --> 00:06:22,320 这样我就只需要做一次调试 做一次分析 so I can do that having debugged it once and understood it once 81 00:06:23,360 --> 00:06:27,300 还能够与其他用户分享这段程序 and having been able to share that among many different uses of it. 82 00:06:29,040 --> 00:06:30,420 接下来 我有另外一个例子 Here, we have another example. 83 00:06:31,520 --> 00:06:38,800 这是莱布尼茨公式 用来求π/8的值 This is Leibnitz's formula for finding pi over 8. 84 00:06:39,940 --> 00:06:43,500 这一团糟的式子是什么意思? It's a funny, ugly mess. What is it? 85 00:06:43,500 --> 00:06:54,220 大致是1/(1*3)+1/(5*7)+1/(7*9)+...这样子 It's something like 1 over 1 times 3 plus 1 over 5 times 7 plus 1 over 9 times 11 plus-- 86 00:06:54,220 --> 00:07:00,960 有趣的是 根据一些证明 它将收敛到π/8 and for some reason, things like this tend to have interesting values like pi over 8. 87 00:07:01,740 --> 00:07:04,020 我们能发现什么? But what do we see here? 88 00:07:04,020 --> 00:07:06,980 这个程序或多或少和之前的程序相同 It's the same program or almost the same program. 89 00:07:07,460 --> 00:07:08,920 也是一个求和过程 对吧? It's a sum. Okay? 90 00:07:08,920 --> 00:07:16,300 这个表达里有一些细微的差别 它的递增的值是4 So we're seeing the figure notation, although over here, we're dealing with incrementing by 4 91 00:07:16,620 --> 00:07:18,040 只是细微的差别而已 so it's a slightly different problem, 92 00:07:18,200 --> 00:07:23,580 所以我们需要在这里将A加4 就在这里 which means that over here, I have to change a by 4, as you see right over here. 93 00:07:25,080 --> 00:07:26,200 不再是加1了 It's not by 1. 94 00:07:27,920 --> 00:07:28,960 当然 另一个区别是 The other thing, of course, 95 00:07:29,260 --> 00:07:33,960 在之前的求平方和的程序里 求和项是平方值 is that the thing that's represented by square in the previous sum of squares, 96 00:07:33,960 --> 00:07:35,640 求整数和的程序里 求和项是整数本身 or a when adding up the integers. 97 00:07:36,020 --> 00:07:38,380 在这里 我用了不同的求和项 Well, here, I have a different thing I'm adding up, a different term, 98 00:07:38,680 --> 00:07:43,060 即1 / (A * (A + 2)) which is 1 over a times a plus 2. 99 00:07:43,940 --> 00:07:45,740 但是 其余部分的程序是相同的 But the rest of this program is identical. 100 00:07:48,140 --> 00:07:50,800 总之 每当我们发现有一些过程是相同的 Well, any time we have a bunch of things like this that are identical, 101 00:07:51,360 --> 00:07:54,240 我们就需要做一些抽象来概括它们 we're going to have to come up with some sort of abstraction to cover them. 102 00:07:55,580 --> 00:08:00,460 回想一下 到目前为止 你们学到的只是一些语法规则 If you think about this, what you've learned so far is the rules of some language, 103 00:08:00,520 --> 00:08:07,600 一些基本表达式 组合的方法 抽象的方法 大概就是这些 some primitive, some means of combination, almost all of them, the means of abstraction, almost all of them. 104 00:08:09,360 --> 00:08:11,700 但是 你们还没学到的是 使用的公共模式 But what you haven't learned is common patterns of usage. 105 00:08:12,880 --> 00:08:15,120 大多时候 你要学习的是一门语言习惯用法 Now, most of the time, you learn idioms when learning a language, 106 00:08:15,120 --> 00:08:19,820 它是一种有价值的公共模式 which is a common pattern that mean things that are useful to know in a flash. 107 00:08:20,780 --> 00:08:23,160 如果你是一个经验丰富的FORTRAN程序员 And if you build a great number of them, if you're a FORTRAN programmer, 108 00:08:23,160 --> 00:08:26,420 你肯定知道 of course, everybody knows how to-- what do you do, 109 00:08:27,240 --> 00:08:30,260 比如 如何求某个数列中的最大值 for example, to get an integer which is the biggest integer in something. 110 00:08:30,860 --> 00:08:32,080 这是经典的问题 It's a classic thing. 111 00:08:32,220 --> 00:08:33,420 每个FORTRAN程序员都知道怎么做 Every FORTRAN programmer knows how to do that. 112 00:08:33,880 --> 00:08:36,820 如果你不知道的话 你可能会陷于困境并花很长的时间想出答案 And if you don't know that, you're in real hot water because it takes a long time to think it out. 113 00:08:37,700 --> 00:08:38,380 然而 However, 114 00:08:39,380 --> 00:08:41,780 在这门语言中我们想展示给你的 one of the things you can do in this language that we're showing you 115 00:08:41,980 --> 00:08:45,600 不是"鱼" 而是"渔" is not only do you know something like that, but you give the knowledge of that a name. 116 00:08:48,040 --> 00:08:50,040 这就是我们接下来要做的事 And so that's what we're going to be going after right now. 117 00:08:53,020 --> 00:08:55,460 好吧 让我们先看看这些程序的共同点 OK, well, let's see what these things have in common. 118 00:08:58,060 --> 00:09:02,680 在这里我们有一个看似一般的模式 Right over here we have what appears to be a general pattern, 119 00:09:04,040 --> 00:09:07,020 它概括了到目前为止所有的例子 a general pattern which covers all of the cases we've seen so far. 120 00:09:09,380 --> 00:09:13,100 这里定义了一个求和过程 There is a sum procedure, which is being defined. 121 00:09:14,380 --> 00:09:18,040 它有两个参数 代表求和的下界和上界 It has two arguments, which are a lower bound and an upper bound. 122 00:09:19,380 --> 00:09:22,980 首先判断下界是否大于上界 The lower bound is tested to be greater than the upper bound, 123 00:09:22,980 --> 00:09:26,680 如果下界大于上界的话 结果就是0 and if it is greater, then the result is zero. 124 00:09:27,200 --> 00:09:31,080 否则 我们要对下界做一些处理 Otherwise, we're going to do something to the lower bound, 125 00:09:31,080 --> 00:09:33,540 也就是下标 which is the index of the conversation, 126 00:09:34,200 --> 00:09:40,540 将处理后的结果与后面这个过程的结果递归地相加 and add that result to the result of following the procedure recursively 127 00:09:41,300 --> 00:09:45,340 这个过程的参数是NEXT操作处理后的下界 on our lower bound incremented by some next operation 128 00:09:47,560 --> 00:09:49,400 以及与之前相同的上界 with the same upper bound as I had before. 129 00:09:53,380 --> 00:09:56,760 这即是公共模式 So this is a general pattern, 130 00:09:57,540 --> 00:10:00,980 我想给这个公共模式命名 and what I'd like to do is be able to name this general pattern a bit. 131 00:10:03,180 --> 00:10:04,120 这还挺简单 Well, that's sort of easy, 132 00:10:05,000 --> 00:10:08,020 因为我要做的是... because one of the things I'm going to do right now is-- 133 00:10:08,020 --> 00:10:10,020 数字不是非常特殊的东西 there's nothing very special about numbers. 134 00:10:11,340 --> 00:10:13,100 数字仅仅是一种数据 Numbers are just one kind of data. 135 00:10:14,280 --> 00:10:20,300 为各种数据命名看上去也是很合理的事情 It seems to be perfectly reasonable to give all sorts of names to all kinds of data, 136 00:10:21,000 --> 00:10:22,140 比如说 “过程” for example, procedures. 137 00:10:22,700 --> 00:10:25,680 并且当今很多语言都允许使用过程参数 And now many languages allow you have procedural arguments, 138 00:10:25,900 --> 00:10:28,460 现在 我们即将讨论过程参数 and right now, we're going to talk about procedural arguments. 139 00:10:29,020 --> 00:10:30,100 它们很容易处理 They're very easy to deal with. 140 00:10:30,860 --> 00:10:33,880 我们首先不去考虑过程参数 来做一些很特别的事情 And shortly, we'll do some remarkable things that are not like procedural arguments. 141 00:10:35,420 --> 00:10:41,700 这里 定义我们的求和记法 So here, we'll define our sigma notation. 142 00:10:42,780 --> 00:10:59,740 过程名叫做SUM 参数为TERM A NEXT和B This is called sum and it takes a term, an A, a next term, and B as arguments. 143 00:10:59,740 --> 00:11:00,900 所以 它有四个参数 So it takes four arguments, 144 00:11:02,460 --> 00:11:05,520 这里我写成小写没有特殊的含义 and there was nothing particularly special about me writing this in lowercase. 145 00:11:06,020 --> 00:11:09,440 我不希望它迷惑你 所以我现在把它改成大写 I hope that it doesn't confuse you, so I'll write it in uppercase right now. 146 00:11:09,780 --> 00:11:10,680 机器并不关心大小写 The machine doesn't care. 147 00:11:14,140 --> 00:11:17,860 但这两个参数并不同 它们不是数字 But these two arguments are different. These are not numbers. 148 00:11:18,840 --> 00:11:22,140 它们是对数字进行计算的过程 These are going to be procedures for computing something given a number. 149 00:11:23,300 --> 00:11:25,700 TERM是这样一个过程 提供它一个下标 Term will be a procedure which, when given an index, 150 00:11:26,140 --> 00:11:28,660 TERM会计算出这个下标所对应的项的值 produce the value of the term for that index. 151 00:11:29,440 --> 00:11:32,420 NEXT过程会根据一个下标计算下一个下标 Next will be given an index, which will produce the next index. 152 00:11:33,560 --> 00:11:34,740 这是用来计数的 This will be for counting. 153 00:11:35,540 --> 00:11:36,720 这很简单 And it's very simple. 154 00:11:40,060 --> 00:11:41,740 就是字面的意思 It's exactly what you see. 155 00:11:42,900 --> 00:11:50,800 如果A大于B 结果就是0 If A is greater than B, then the result is 0. 156 00:11:51,820 --> 00:12:10,000 否则 结果是(TERM A)与(SUM TERM (NEXT A)...)的和 Otherwise, it's the sum of term applied to A and the sum of term, next index. 157 00:12:15,120 --> 00:12:16,140 我换个方式写 Let me write it this way. 158 00:12:29,580 --> 00:12:31,660 现在 首先我要你们看一些东西 Now, I'd like you to see something, first of all. 159 00:12:31,820 --> 00:12:33,640 我写到黑板这 然后写不下了 I was writing here, and I ran out of space. 160 00:12:34,740 --> 00:12:38,640 于是我使用了缩进 依据的是整齐打印规则 What I did is I start indenting according to the Pretty-printing rule, 161 00:12:38,640 --> 00:12:41,980 意思是我把过程的每个参数对齐 which says that I align all of the arguments of the procedure 162 00:12:43,360 --> 00:12:45,280 这样我就能看清它们的层次 so I can see which ones go together. 163 00:12:46,600 --> 00:12:48,400 这是我刚才无意识地做下的 And this is just something I do automatically, 164 00:12:49,080 --> 00:12:50,220 并且我也希望你们学会这样做 and I want you to learn how to do that, too, 165 00:12:50,220 --> 00:12:51,940 这样你的程序就便于阅读和理解 so your programs can be read and understood. 166 00:12:53,800 --> 00:12:56,900 现在 看看我们有什么 However, what do we have here? 167 00:12:57,200 --> 00:13:02,100 我们有四个参数:过程、下界的下标、 We have four arguments: the procedure, the lower index- - lower bound index-- 168 00:13:03,260 --> 00:13:06,180 获得下一个下标的方法 以及上界 the way to get the next index, and the upper bound. 169 00:13:08,440 --> 00:13:14,300 在递归调用的部分实际上传递的是同一个过程 What's passed along on the recursive call is indeed the same procedure 170 00:13:14,960 --> 00:13:16,120 因为我再一次需要它了 because I'm going to need it again, 171 00:13:17,120 --> 00:13:20,140 下一个下标 是用NEXT过程计算出的 the next index, which is using the next procedure to compute it, 172 00:13:20,840 --> 00:13:24,100 计算下一个下标的过程 我也单独地需要 因为这两者是不同的 the procedure for computing next, which I also have to have separately, and that's different. 173 00:13:24,820 --> 00:13:28,200 计算下一个下标的过程与下一个下标是不同的 The procedure for computing next is different from the next index, 174 00:13:28,680 --> 00:13:30,920 下一个下标是NEXT过程应用于上一个下标所产生的结果 which is the result of using next on the last index. 175 00:13:31,960 --> 00:13:33,800 最后我也需要传递上界 And I also have to pass along the upper bound. 176 00:13:36,600 --> 00:13:45,300 于是 这就囊括了所有的这些 以及我们写过的其它的漂亮的程序 So this captures both of these and the other nice program that we are playing with. 177 00:13:47,440 --> 00:13:55,860 利用这个 我们就可以很容易地写出SUM的原始实例程序 So using this, we can write down the original program as instances of sum very simply. 178 00:14:08,700 --> 00:14:10,000 A和B A and B. 179 00:14:15,260 --> 00:14:20,180 好吧 我在这需要一个IDENTITY过程 因为... Well, I'm going to need an identity procedure here because ,ahh, 180 00:14:25,520 --> 00:14:31,740 整数的求和需要我在这里对每一个整数计算一次TERM the sum of the integers requires me to in this case compute a term for every integer, 181 00:14:32,060 --> 00:14:34,380 但是这个TERM过程并不对这个整数做任何改变 but the term procedure doesn't want to do anything to that integer. 182 00:14:35,240 --> 00:14:37,920 所以关于A的IDENTITY过程结果就是A So the identity procedure on A is A 183 00:14:39,000 --> 00:14:40,280 写成X或者其它的符号也没关系 or X or whatever, 184 00:14:40,840 --> 00:14:46,400 接下来 将IDENTITY作为SUM的TERM过程 and I want to say the sum of using identity of the term procedure 185 00:14:52,040 --> 00:14:53,860 用A作为初始下标 and using A as the initial index 186 00:14:55,300 --> 00:15:00,780 1+过程用来获取下一个下标 and the incrementer being the way to get the next index 187 00:15:01,620 --> 00:15:06,360 B作为上界 and B being the high bound, the upper bound. 188 00:15:07,460 --> 00:15:12,340 这个过程与这里的SUM-INT过程工作方式相同 This procedure does exactly the same as the sum of the integers over here, 189 00:15:12,580 --> 00:15:13,720 计算出的答案也相同 computes the same answer. 190 00:15:17,200 --> 00:15:20,220 现在 值得注意的一点是 Now, one thing you should see, of course, 191 00:15:20,620 --> 00:15:25,380 这里的形式参数写成什么都无所谓 is that there's nothing very special over here about what I used as the formal parameter. 192 00:15:25,380 --> 00:15:28,800 比如 我可以把它写成X 也没关系 I could have, for example, written this X. It doesn't matter. 193 00:15:29,060 --> 00:15:34,240 注意到这个X和那个X并不冲突 I just wanted you to see that this name does not conflict with this one at all. 194 00:15:34,620 --> 00:15:35,820 这是一个内部名称 It's an internal name. 195 00:15:37,480 --> 00:15:41,060 对于第二个过程---平方和 它甚至更简单一些 For the second procedure here, the sum of the squares, it's even a little bit easier. 196 00:15:53,280 --> 00:15:58,020 我们需要做的仅仅是将平方项加起来 And what do we have to do? Nothing more than add up the squares, 197 00:16:00,740 --> 00:16:05,500 这个过程会对每个下标生效 this is the procedure that each index will be given, will be given each-- yes. 198 00:16:06,180 --> 00:16:09,220 每个下标使用这个过程来产生一个项 Each index will have this done to it to get the term. 199 00:16:09,940 --> 00:16:12,420 它对应了那里的TERM That's the thing that maps against term over here. 200 00:16:13,140 --> 00:16:14,840 然后将A作为下界 Then I have A as the lower bound, 201 00:16:16,300 --> 00:16:19,300 1+过程作为产生下一个项的方法 the incrementer as the next term method, 202 00:16:19,700 --> 00:16:21,140 B作为上界 and B as the upper bound. 203 00:16:26,520 --> 00:16:29,120 最后 来看看之前的PI-SUM过程 And finally, just for the thing that we did about pi sums, 204 00:16:30,740 --> 00:16:32,560 PI-SUM是... pi sums are sort of-- 205 00:16:32,880 --> 00:16:36,240 用这种方法考虑的话 它简单到明显不过了 well, it's even easier to think about them this way because I don't have to think. 206 00:16:36,240 --> 00:16:41,980 其实只要把累加的每一项从累加过程中独立出来 What I'm doing is separating the thing I'm adding up from the method of doing the addition. 207 00:16:42,720 --> 00:16:57,880 来看看 比如说(PI-SUM A B)这个过程 And so we have here, for example, pi sum A B of the sum of things. 208 00:16:59,480 --> 00:17:03,900 我接下来想要写出这个TERM过程 但不给它命名 I'm going to write the terms procedure here explicitly without giving it a name. 209 00:17:05,180 --> 00:17:06,700 用匿名的方式 This is done anonymously. 210 00:17:06,700 --> 00:17:11,460 如果我只是想一次性的使用它 我并不需要给它一个名字 I don't necessarily have to give a name to something if I just want to use it once. 211 00:17:12,360 --> 00:17:18,640 当然 我可以写出某个表达式来产生一个过程 And, of course, I can write sort of a expression that produces a procedure. 212 00:17:19,180 --> 00:17:23,820 我这里使用希腊字母的λ 而不是L-A-M-B-D-A的全拼 I'm going to write the Greek lambda letter here instead of L-A-M-B-D-A in general 213 00:17:24,000 --> 00:17:26,480 免得占用太多黑板的空间 to avoid taking up a lot of space on blackboards. 214 00:17:26,760 --> 00:17:29,160 可惜 我们的键盘上没有λ键 But unfortunately, we don't have lambda keys on our keyboards. 215 00:17:29,560 --> 00:17:33,340 或许我们可以说服工业界的朋友意识到(λ键的)重要性 Maybe we can convince our friends in the computer industry that this is an important. 216 00:17:33,560 --> 00:17:45,220 该LAMBADA过程以I为参数 操作是1除以I与I+2的积 Lambda of i is the quotient of 1 and the product of i and the sum of i 2, 217 00:17:51,840 --> 00:17:53,120 下标从A开始 starting at a 218 00:17:53,480 --> 00:18:02,600 递增方法是以I为参数 将I+4的过程 with the way of incrementing being that procedure of an index i, which adds i to 4, 219 00:18:05,980 --> 00:18:09,420 B作为上界 and b being the upper bound. 220 00:18:11,960 --> 00:18:20,060 你可以看到这种记法 将过程用作过程参数 So you can see that this notation, the invention of the procedure that takes a procedural argument, 221 00:18:20,460 --> 00:18:24,300 允许我们将很多过程组合成一个 allows us to compress a lot of these procedures into one thing. 222 00:18:26,040 --> 00:18:30,680 这个过程 SUM 蕴含着一系列的思想 This procedure, sums, covers a whole bunch of ideas. 223 00:18:32,300 --> 00:18:33,740 现在思考一下为什么这是很重要的? Now, just why is this important? 224 00:18:34,240 --> 00:18:38,960 它帮助我们将一个问题拆分成两个 实际上 它做到了这点 I tried to say before that it helps us divide a problem into two pieces, and indeed, it does, 225 00:18:40,740 --> 00:18:44,620 比如说 如果某个人提出了另一个实现这个的方法 for example, if someone came up with a different way of implementing this, 226 00:18:45,920 --> 00:18:47,800 当然 确实有一个 which, of course, one might. 227 00:18:49,600 --> 00:18:51,920 比如 一个SUM过程的迭代实现 Here, for example, an iterative implementation of sum. 228 00:18:55,500 --> 00:19:00,840 迭代实现在某种程度上也许比递归实现更好 Iterative implementation for some reason might be better than the recursive implementation. 229 00:19:03,100 --> 00:19:04,840 但是它还是有很大不同的 But the important thing is that it's different. 230 00:19:05,980 --> 00:19:11,700 如果我现在用黑板上左边的那种方法实现了我的程序 Now, supposing I had written my program this way that you see on the blackboard on the left. 231 00:19:14,100 --> 00:19:15,480 是的 左边那个程序 That's correct, the left. 232 00:19:17,340 --> 00:19:20,000 后来 我想要改变“求和”这个方法 Well, then if I want to change the method of addition, 233 00:19:21,440 --> 00:19:23,280 我就不得不修改这里的每一个程序 then I'd have to change each of these. 234 00:19:24,740 --> 00:19:28,780 然而 如果我用这里这个方法来实现的话 Whereas if I write them like this that you see here, 235 00:19:29,480 --> 00:19:32,940 那么“求和”这个方法就被封装在了SUM过程里 then the method by which I did the addition is encapsulated in the procedure sum. 236 00:19:34,460 --> 00:19:38,400 这个分解允许我只需修改程序的一部分 That decomposition allows me to independently change one part of the program 237 00:19:39,340 --> 00:19:46,140 而不改变用于处理其它问题的那些部分 and prove it perhaps without changing the other part that was written for some of the other cases. 238 00:19:50,280 --> 00:19:51,340 谢谢 大家有问题吗? Thank you. Are there any questions? 239 00:19:51,960 --> 00:19:52,480 那位男士 Yes, sir. 240 00:19:52,560 --> 00:19:54,500 观众:A后面的值会被一个一个遍历的吗…… AUDIENCE: Would you go over next A and next again on-- 241 00:19:54,720 --> 00:19:56,020 教授:是的 PROFESSOR: Yes. It's the same problem. 242 00:19:56,020 --> 00:19:58,680 我确信你们需要花一些时间来想明白 I'm sure you're going to-- you're going to have to work on this. 243 00:19:58,680 --> 00:20:01,540 如果你第一次见到这种写法的话可能会很困惑 This is hard the first time you've ever seen something like this. 244 00:20:01,980 --> 00:20:07,220 这里的过程是可以命名为一个变量 What I have here is a-- procedures can be named by variables. 245 00:20:09,980 --> 00:20:11,180 “过程”这个概念并没有特殊的地方 Procedures are not special. 246 00:20:12,300 --> 00:20:15,420 实际上SUM-SQ也只不过是一个变量 会产生一个值 Actually, sum square is a variable, which has gotten a value, 247 00:20:16,720 --> 00:20:17,580 这就是过程 which is a procedure. 248 00:20:18,200 --> 00:20:21,160 这里其实是定义SUM-SQ为一个参数为A、B的LAMBDA过程 This is define sum square to be lambda of A and B something. 249 00:20:22,880 --> 00:20:23,980 所以过程可以被命名 So the procedure can be named. 250 00:20:24,300 --> 00:20:30,080 那样的话 过程就可以被作为参数传递于过程之间 Therefore, they can be passed from one to another, one procedure to another, as arguments. 251 00:20:31,020 --> 00:20:35,600 在这里 我们做的就是把TERM过程作为参数传递给SUM Well, what we're doing here is we're passing the procedure term as an argument to sum 252 00:20:36,780 --> 00:20:39,440 在下一层的递归中也会用到它 just when we get it around in the next recursive. 253 00:20:41,040 --> 00:20:46,680 同样地 我们也将NEXT过程作为参数传递了 Here, we're passing the procedure next as an argument also. 254 00:20:47,200 --> 00:20:49,180 然而 在这里我们是使用了NEXT过程 However, here we're using the procedure next. 255 00:20:49,540 --> 00:20:50,860 括号体现了这一点 That's what the parentheses mean. 256 00:20:51,300 --> 00:20:55,400 我们将NEXT过程应用于变量A来获得A的下一个值 We're applying next to A to get the next value of A. 257 00:20:56,200 --> 00:20:57,920 如果你想知道NEXT过程映射出了什么 If you look at what next is mapped against, 258 00:20:57,920 --> 00:21:00,520 你可以这样来考虑 remember that the way you think about this is 259 00:21:00,520 --> 00:21:04,620 用实际参数代换过程体中的形式参数 that you substitute the arguments for the formal parameters in the body. 260 00:21:06,040 --> 00:21:09,800 如果你还是困惑的话 就像这样想吧 If you're ever confused, think of the thing that way. 261 00:21:10,080 --> 00:21:13,540 比如在SUM-INT过程中 Well, over here, with sum of the integers. 262 00:21:14,320 --> 00:21:17,040 我用IDENTITY过程代换TERM过程 I substitute identity for a term 263 00:21:19,380 --> 00:21:24,420 用1+增量过程代换过程体中的NEXT过程 and 1 plus the incrementer for next in the body. 264 00:21:25,660 --> 00:21:29,460 在这里我将IDENTITY过程应用于了A Well, the identity procedure on A is what I get here. 265 00:21:30,100 --> 00:21:31,760 IDENTITY过程会被继续传递 Identity is being passed along, 266 00:21:33,740 --> 00:21:38,200 在这里 我将1+过程应用于了A and here, I have increment 1 plus being applied to A 267 00:21:39,740 --> 00:21:41,220 并且1+过程也被传递下去 and 1 plus is being passed along. 268 00:21:42,520 --> 00:21:45,400 清楚这个情况了吗? Does that clarify the situation? 269 00:21:45,600 --> 00:21:50,640 观众:我们也可以显式地定义那两个过程 然后再传递它们 AUDIENCE: We could also define explicitly those two functions, then pass them. 270 00:21:50,640 --> 00:21:51,320 教授:当然可以 PROFESSOR: Sure. 271 00:21:51,320 --> 00:21:55,380 我们的确可以命名这些过程 就如我这里做的一样 What we can do is we could have given names to them, just like I did here. 272 00:21:55,380 --> 00:21:58,500 实际上 我在这里提供了很多种方式给你们 In fact, I gave you various ways so you could see it, a variety. 273 00:21:58,500 --> 00:22:03,140 在这里 我定义了这个过程 并传递了它的名字 Here, I define the thing which I passed the name of. 274 00:22:03,220 --> 00:22:06,560 我用它的名字来引用它 I referenced it by its name. 275 00:22:07,400 --> 00:22:11,020 实际上这个过程的参数是X 结果也是X But the thing is, in fact, that procedure, one argument X, which is X. 276 00:22:12,100 --> 00:22:15,780 IDENTITY过程实际上相当于(LAMBDA (x) x) And the identity procedure is just lambda of X X. 277 00:22:17,600 --> 00:22:19,520 这里就是这样的 And that's what you're seeing here. 278 00:22:20,020 --> 00:22:26,420 在这里 我就给你们写出了它的经典用法 Here, I happened to just write its canonical name there for you to see. 279 00:22:31,760 --> 00:22:33,020 让我们休息5分钟吧 Is it OK if we take our five-minute break? 280 00:22:35,820 --> 00:22:47,240 [音乐] [JESU, JOY OF MAN'S DESIRING] 281 00:23:00,260 --> 00:23:04,500 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 282 00:23:04,620 --> 00:23:07,700 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 283 00:23:08,560 --> 00:23:12,120 高阶过程 Higher-order Procedures 284 00:23:15,360 --> 00:23:18,760 正如我说的 计算机用于满足人们的需求 As I said, computers to make people happy, 285 00:23:18,920 --> 00:23:20,440 而不是让人去满足计算机的需求 not people to make computers happy. 286 00:23:20,640 --> 00:23:23,980 我们介绍抽象概念的大部分原因 And for the most part, the reason why we introduce all this abstraction stuff 287 00:23:24,220 --> 00:23:28,080 是为了让程序更易写易读 is to make it so that programs can be more easily written and more easily read. 288 00:23:30,160 --> 00:23:33,580 让我们用一些关于抽象的例子 Let's try to understand what's the most complicated program we've seen so far 289 00:23:34,040 --> 00:23:37,140 来理解目前为止我们见到的最复杂的程序 using a little bit of this abstraction stuff. 290 00:23:37,940 --> 00:23:39,700 请看幻灯片 If you look at the slide, 291 00:23:39,960 --> 00:23:49,080 这是我们昨天介绍的Heron法 用于计算平方根 this is the Heron of Alexandria's method of computing square roots that we saw yesterday. 292 00:23:51,300 --> 00:23:53,880 看一下这个程序 And let's see. 293 00:23:56,060 --> 00:24:01,180 不管怎样 这个程序有一些复杂 Well, in any case, this program is a little complicated. 294 00:24:01,700 --> 00:24:03,720 现在这种情况下 And at the current state of your thinking, 295 00:24:03,900 --> 00:24:05,240 你肯定不会看着这个程序说 you just can't look at that and say, 296 00:24:05,240 --> 00:24:08,940 哦 这个程序的目的真是显而易见 oh, this obviously means something very clear. 297 00:24:10,000 --> 00:24:14,540 它到底在计算什么一点都不明显 It's not obvious from looking at the program what it's computing. 298 00:24:16,040 --> 00:24:19,540 在TRY过程里有一些循环 There's some loop here inside try, 299 00:24:20,260 --> 00:24:24,200 循环在对Y的IMPROVE应用TRY过程 and a loop does something about trying the improvement of y. 300 00:24:25,800 --> 00:24:28,720 还有一个叫IMPROVE的什么东西 There's something called improve, 301 00:24:29,120 --> 00:24:32,500 做了一些关于AVERAGE和除法的什么工作 which does some averaging and quotienting and things like that. 302 00:24:33,020 --> 00:24:34,580 但是它到底在做什么? But what's the real idea? 303 00:24:34,580 --> 00:24:36,720 我们可以弄明白这个程序的目的吗? Can we make it clear what the idea is? 304 00:24:38,360 --> 00:24:39,680 我认为可以 Well, I think we can. 305 00:24:41,260 --> 00:24:44,940 我们可以用之前学到的关于抽象的知识 I think we can use abstraction that we have learned about so far 306 00:24:45,380 --> 00:24:47,700 来说明它到底在干什么 to clarify what's going on. 307 00:24:48,520 --> 00:24:56,460 现在 我们在数学上有一个对平方根结果的更好猜测 Now, what we have mathematically is a procedure for improving a guess for square roots. 308 00:24:57,480 --> 00:25:04,180 如果Y是平方根的一个猜测值 那么我们有一个函数F And if y is a guess for a square root, then what we want to get we'll call a function f. 309 00:25:04,300 --> 00:25:05,700 用来改进猜测值 This is the means of improvement. 310 00:25:06,400 --> 00:25:13,360 我用(Y+X/Y)/2的结果 I want to get y plus x/y over 2, 311 00:25:14,140 --> 00:25:22,200 作为改进的平方根猜测值 so the average of y and x divided by y as the improved value for the square root of x 312 00:25:23,840 --> 00:25:37,000 值得注意的一点是 F对根号X的求值结果就是根号X such that-- one thing you can notice about this function f is that f of the square root of f is in fact the square root of x. 313 00:25:38,680 --> 00:25:42,500 因为 如果在这里我将Y替换成根号X there, if I take the square root of x and substitute it for y here, 314 00:25:43,120 --> 00:25:46,820 将会得到根号X加上X与根号X的商 I see the square root of x plus x divided by the square of x, which is the square root of x. 315 00:25:47,200 --> 00:25:50,200 是2倍根号X除以2 结果就是根号x That's 2 times the square root of x divided by 2, is the square root of x. 316 00:25:50,920 --> 00:26:12,300 所以 实际上我们在寻找函数F的一个不动点 So, in fact, what we're really looking for is we're looking for a fixed point, a fixed point of the function f. 317 00:26:16,920 --> 00:26:21,240 不动点就是一个值 A fixed point is a place which has the property 318 00:26:21,980 --> 00:26:24,560 将其应用到函数中得到的还是原来的值 that if you put it into the function, you get the same value out. 319 00:26:27,180 --> 00:26:29,680 假设你在上一堂很无聊的课 Now, I suppose if I were giving some nice, boring lecture, 320 00:26:29,680 --> 00:26:35,080 碰巧你面前有一个HP-35计算器 and you happened to have in front of you an HP-35 desk calculator 321 00:26:35,080 --> 00:26:36,920 我过去就在无聊的课上用过 like I used to have when I went to boring lectures. 322 00:26:37,680 --> 00:26:39,500 如果你觉得无事可干 And if you think it was really boring, 323 00:26:39,500 --> 00:26:45,520 你可以进入弧度模式 不停地按COS键 按COS键 按COS键…… you put it into radians mode, and you hit cosine, and you hit cosine, and you hit cosine. 324 00:26:45,760 --> 00:26:50,400 最终 你将会停在大概是0.734这个值 And eventually, you end up with 0.734 or something like that. 0.743 325 00:26:50,460 --> 00:26:51,960 我记不太清了 I don't remember what exactly, 326 00:26:52,160 --> 00:26:53,780 越来越接近那个值 and it gets closer and closer to that. 327 00:26:54,540 --> 00:27:00,620 你可以通过迭代的方法找到一些函数的不动点 Some functions have the property that you can find their fixed point by iterating the function, 328 00:27:02,700 --> 00:27:07,520 实际上在Heron法中发生的就是这个过程 and that's essentially what's happening in the square root program by Heron's method. 329 00:27:11,180 --> 00:27:13,600 看看我们能不能实现这个想法 So let's see if we can write that down, that idea. 330 00:27:14,800 --> 00:27:17,040 现在我不打算讲如何计算出不动点 Now, I'm not going to say how I compute fixed points yet. 331 00:27:17,220 --> 00:27:18,560 那可以有很多种方法 There might be more than one way. 332 00:27:19,200 --> 00:27:23,560 首先让我们回到刚才的话题上 But the first thing to do is I'm going to say what I just said. 333 00:27:23,860 --> 00:27:27,020 回到平方根这个问题上 I'm going to say it specifically, the square root. 334 00:27:31,800 --> 00:27:45,360 X的平方根是一个过程的不动点 The square root of x is the fixed point of that procedure 335 00:27:47,660 --> 00:28:02,140 这个过程以Y作为参数 计算出X/Y和Y的平均值 which takes an argument y and averages of x divided by y with y. 336 00:28:05,160 --> 00:28:09,200 并且假定初始不动点的猜测值为1 And we're going to start up with the initial guess for the fixed point of 1. 337 00:28:09,480 --> 00:28:10,800 初始值为几都无所谓 It doesn't matter where it starts. 338 00:28:11,400 --> 00:28:13,620 理论上证明过了 A theorem having to do with square roots. 339 00:28:18,280 --> 00:28:22,080 在这里我仅仅是按愿望思维写出了程序 So what you're seeing here is I'm just trying to write out by wishful thinking. 340 00:28:22,180 --> 00:28:24,360 我并不知道求不动点的具体细节 I don't know how I'm going to make fixed point happen. 341 00:28:24,360 --> 00:28:25,460 这点我们接下来再涉及 We'll worry about that later. 342 00:28:25,900 --> 00:28:30,900 假如我写出了一个求这个过程的不动点的函数 But if somehow I had a way of finding the fixed point of the function computed by this procedure, 343 00:28:32,440 --> 00:28:35,980 那么我就能得到平方根的值了 then I would have-- that would be the square root that I'm looking for. 344 00:28:39,160 --> 00:28:42,700 现在 我们来看看如何求不动点 OK, well, now let's see how we're going to write-- how we're going to come up with fixed points. 345 00:28:43,060 --> 00:28:44,600 实际上这很简单 Well, it's very simple, actually. 346 00:28:44,600 --> 00:28:47,640 我先写出一个简单的版本便于大家理解 I'm going to write an abbreviated version here just so we understand it. 347 00:29:00,060 --> 00:29:02,300 我要找到函数F的不动点A I'm going to find the fixed point of a function f-- 348 00:29:02,940 --> 00:29:08,240 在这个过程里 求不动点的函数我们命名为F actually, the fixed point of the function computed by the procedure whose name will be f in this procedure. 349 00:29:09,620 --> 00:29:14,520 接下来 需要一个具体的值开始计算 How's that? A long sentence-- starting with a particular starting value. 350 00:29:19,520 --> 00:29:21,580 在过程内部需要一些循环 Well, I'm going to have a little loop inside here, 351 00:29:22,020 --> 00:29:25,120 代表了不停地在计算器上按键的过程 which is going to push the button on the calculator repeatedly, 352 00:29:25,460 --> 00:29:27,380 期待它最终会收敛到一点 hoping that it will eventually converge. 353 00:29:28,600 --> 00:29:35,780 内部的循环我们定义为内部过程 And we will say here internal loops are written by defining internal procedures. 354 00:29:38,980 --> 00:29:42,520 在这里 我需要确定我是否找到了我需要的值 Well, one thing I'm going to have to do is I'm going to have to say whether I'm done. 355 00:29:43,160 --> 00:29:45,140 我将要考察 And the way I'm going to decide when I'm done is when 356 00:29:45,200 --> 00:29:48,660 新旧两值是否接近得无法区分 the old value and the new value are close enough so I can't distinguish them anymore. 357 00:29:50,360 --> 00:29:55,540 相当于你在计算器上看到结果的变化最终超出了精度范围 That's the standard thing you do on the calculator unless you look at more precision, and eventually, you run out of precision. 358 00:29:57,420 --> 00:30:02,940 所以 这里需要旧值和新值 So the old value and new value, 359 00:30:05,400 --> 00:30:10,380 并且如果它们足够接近 and I'm going to stay here if I can't distinguish them if they're close enough, 360 00:30:14,800 --> 00:30:16,640 接下来的操作我马上会提到 and we'll have to worry about what that is soon. 361 00:30:20,320 --> 00:30:22,620 如果旧值和新值足够接近的话 The old value and the new value are close enough to each other 362 00:30:22,620 --> 00:30:24,080 我们就选择新值作为结果 and let's pick the new value as the answer. 363 00:30:25,400 --> 00:30:28,500 否则 我继续迭代这个过程 Otherwise, I'm going to iterate around again 364 00:30:31,000 --> 00:30:36,360 将当前的新值作为下一轮的旧值 with the next value of old being the current value of new 365 00:30:38,260 --> 00:30:42,960 将f作用于新值的结果作为下一轮的新值 and the next value of new being the result of calling f on new. 366 00:30:53,680 --> 00:30:57,900 相当于我不停地按下计算器的键 And so this is my iteration loop that pushes the button on the calculator. 367 00:30:58,240 --> 00:31:01,760 我可以想象计算器中有两个寄存器:旧与新 I basically think of it as having two registers on the calculator: old and new. 368 00:31:02,420 --> 00:31:07,100 在每一步中 新值成为旧值 F作用后的新值成为新的新值 And in each step, new becomes old, and new gets F of new. 369 00:31:08,700 --> 00:31:10,940 这就是得到下一个猜测值的方法 So this is the thing where I'm getting the next value. 370 00:31:12,720 --> 00:31:21,720 现在 我传入两个值来调用这个方法 And now, I'm going to start this thing up by giving two values. 371 00:31:28,060 --> 00:31:31,200 我详细地在黑板上写出了每一个步骤 I wrote down on the blackboard to be slow so you can see this. 372 00:31:31,680 --> 00:31:35,340 这是你们第一次见到这么复杂的程序 This is the first time you've seen something quite this complicated, I think. 373 00:31:37,380 --> 00:31:48,920 我们还是需要在幻灯片上看一下整个程序 However, we might want to see the whole thing over here in this transparency or slide or whatever. 374 00:31:50,100 --> 00:31:57,680 这里详细地写出了程序所有需要的细节 What we have is all of the details that are required to make this thing work. 375 00:31:58,080 --> 00:32:02,700 在这里 我在CLOSE-ENUF?过程里给出了误差 I have a way of getting a tolerance for a close enough procedure, which we see here. 376 00:32:02,980 --> 00:32:06,180 CLOSE-ENUF?过程确定U和V是否足够接近 The close enough procedure, it tests whether u and v are close enough 377 00:32:06,700 --> 00:32:12,140 通过比较U和V的差是否小于一个给定的误差实现 by seeing if the absolute value of the difference in u and v is less than the given tolerance, OK? 378 00:32:12,140 --> 00:32:14,620 这里是我刚才在黑板上写出的循环定义 And here is the iteration loop that I just wrote on the blackboard 379 00:32:15,500 --> 00:32:18,260 它的初始化调用在这 and the initialization for it, which is right there. 380 00:32:21,340 --> 00:32:22,180 非常简单 It's very simple. 381 00:32:33,840 --> 00:32:35,720 其实 我还没有说完 But let's see. I haven't told you enough. 382 00:32:36,160 --> 00:32:37,760 实际上这个程序可以更简单 It's actually easier than this. 383 00:32:39,320 --> 00:32:42,620 对于这个问题 在我讲述的内容背后隐含着更多的原理支撑 There is more structure to this problem than I've already told you. 384 00:32:42,620 --> 00:32:44,620 比如为什么这个方法可行 Like why should this work? 385 00:32:45,340 --> 00:32:46,680 为什么它会收敛 Why should it converge? 386 00:32:47,620 --> 00:32:51,220 在这个程序的背后有复杂的数学原理支撑 There's a hairy theorem in mathematics tied up in what I've written here. 387 00:32:52,320 --> 00:32:58,260 为什么我可以认为迭代计算(Y+X/Y)/2的值就能得到正确的结果 Why is it that I should assume that by iterating averaging the quotient of x and y and y that I should get the right answer? 388 00:32:59,820 --> 00:33:00,820 这些问题的答案都不明显 It isn't so obvious. 389 00:33:03,120 --> 00:33:10,240 当然 除此之外 还会有其他的计算不动点的方法 也能得到平方根的值 Surely there are other things, other procedures, which compute functions whose fixed points would also be the square root. 390 00:33:11,680 --> 00:33:18,620 比如 很明显的 函数G For example, the obvious one will be a new function g, 391 00:33:19,980 --> 00:33:25,720 它将Y映射为X/Y which maps y to x/y. 392 00:33:27,560 --> 00:33:28,620 这甚至更简单 That's even simpler. 393 00:33:30,580 --> 00:33:33,260 函数g的不动点显然也是平方根的值 The fixed point of g is surely the square root also, 394 00:33:33,800 --> 00:33:35,120 并且它使更为简单的过程 and it's a simpler procedure. 395 00:33:36,960 --> 00:33:38,200 为什么我不使用这种方法呢? Why am I not using it? 396 00:33:38,560 --> 00:33:39,880 显而易见 Well, I suppose you know. 397 00:33:40,100 --> 00:33:41,220 假设X是2 Supposing x is 2 398 00:33:41,320 --> 00:33:42,480 并且猜测的初值是1 and I start out with 1, 399 00:33:42,780 --> 00:33:46,980 我将2除以1 得到2 and if I divide 1 into 2, I get 2. 400 00:33:47,300 --> 00:33:49,200 然后我将2除以2 得到1 And then if I divide 2 into 2, I get 1. 401 00:33:49,200 --> 00:33:52,120 再将2除以1得到2 2除以2得到1…… If I divide 1 into 2, I get 2, and 2 into 2, I get 1, 402 00:33:52,120 --> 00:33:53,820 这样 我永远也接近不了2的平方根 and I never get any closer to the square root. 403 00:33:55,140 --> 00:33:56,100 它在真实值上下摆动 It is oscillates. 404 00:33:59,080 --> 00:34:01,600 实际上 这相当于一个信号处理系统 So what we have is a signal processing system, 405 00:34:02,600 --> 00:34:05,500 一个振荡的电路 an electrical circuit which is oscillating, 406 00:34:05,500 --> 00:34:07,160 我想要减小振荡的振幅 and I want to damp out these oscillations. 407 00:34:10,140 --> 00:34:11,000 当然 我可以做到这点 Well, I can do that. 408 00:34:11,500 --> 00:34:14,440 在这里 我实际上用到的是平均值 See, what I'm really doing here when I'm taking my average, 409 00:34:14,680 --> 00:34:18,040 计算的是某个振荡的均值 the average is averaging the last two values of something which oscillates, 410 00:34:18,680 --> 00:34:19,800 得到了中间的某个值 getting something in between. 411 00:34:21,060 --> 00:34:24,940 传统的方法是在信号处理系统中添加阻尼 The classic way is damping out oscillations in a signal processing system. 412 00:34:28,140 --> 00:34:32,540 为什么我们不把刚才讲的策略用一种更清晰的方式表达呢? So why don't we write down the strategy that I just said in a more clear way? 413 00:34:34,180 --> 00:34:35,240 其实 这并不那么复杂 Well, that's easy enough. 414 00:34:38,960 --> 00:34:46,260 定义(SQRT X)为 I'm going to define the square root of x to be 415 00:34:47,080 --> 00:34:56,380 用平均阻尼的方法得到的某个过程的不动点 a fixed point of the procedure resulting from average damping. 416 00:34:58,120 --> 00:35:01,340 即将AVERAGE-DAMP应用于过程 So I have a procedure resulting from average damp 417 00:35:10,000 --> 00:35:20,340 (λ (y) (/ x y)) of the procedure, that procedure of y, which divides x by y 418 00:35:24,560 --> 00:35:25,420 初始猜测值为1 starting out at 1. 419 00:35:29,500 --> 00:35:32,560 AVERAGE-DAMP是一个特殊的过程 Ah, but average damp is a special procedure 420 00:35:32,940 --> 00:35:34,560 它的参数是一个过程 that's going to take a procedure as its argument 421 00:35:34,800 --> 00:35:36,460 其返回值也是一个过程 and return a procedure as its value. 422 00:35:37,700 --> 00:35:39,460 具体来说 It's a generalization that says 423 00:35:39,800 --> 00:35:40,860 给定一个过程 given a procedure, 424 00:35:41,500 --> 00:35:42,940 它产生出另一个过程 it's the thing which produces a procedure 425 00:35:43,000 --> 00:35:45,940 用于计算出某一个值在给定的过程作用下 which averages the last value 426 00:35:46,400 --> 00:35:48,500 结果与它原来的平均值 and the value before and after running the procedure. 427 00:35:50,980 --> 00:35:53,660 你可以在任何需要平均阻尼技术的地方使用它 You can use it for anything if you want to damp out oscillations. 428 00:35:54,560 --> 00:35:55,640 我们把它编写出来 So let's write that down. 429 00:35:56,460 --> 00:35:57,160 这很简单 It's very easy. 430 00:36:00,640 --> 00:36:01,920 在语法上 And stylistically here, 431 00:36:02,100 --> 00:36:03,720 我要使用LAMBDA表达式 I'm going to use lambda notation 432 00:36:04,200 --> 00:36:07,860 因为当你的处理对象是过程的时候 because it's much easier to think when you're dealing with procedure, the mid-line procedures, 433 00:36:07,860 --> 00:36:10,520 这种记法会更易于你的理解 to understand that the procedures are the objects I'm dealing with, 434 00:36:10,860 --> 00:36:13,080 所以在这里我打算使用LAMBDA表达式 so I'm going to use lambda notation here. 435 00:36:13,420 --> 00:36:15,020 我并不是经常使用它 Not always. I don't always use it, 436 00:36:15,640 --> 00:36:21,700 但用在这个过程里来阐明自己的想法是非常合适的 but very specifically here to expand on that idea, to elucidate it. 437 00:36:28,440 --> 00:36:30,260 AVERAGE-DAMP这个过程 Well, average damp is a procedure, 438 00:36:31,720 --> 00:36:35,420 将一个过程作为自己的参数 记作F which takes a procedure as its argument, which we will call f. 439 00:36:37,180 --> 00:36:38,060 它产生什么呢? And what does it produce? 440 00:36:38,280 --> 00:36:44,100 这个过程产生的是一个过程 It produces as its value-- the body of this procedure is a thing which produces a procedure, 441 00:36:44,240 --> 00:36:46,060 产生的过程主体从这里开始 the construct of the procedures right here, 442 00:36:46,620 --> 00:36:48,480 拥有一个参数X of one argument x, 443 00:36:49,900 --> 00:37:00,000 并计算出F(X)和X的平均值 which averages f of x with x. 444 00:37:10,200 --> 00:37:11,940 这是一个很神奇的过程 This is a very special thing. 445 00:37:12,940 --> 00:37:19,320 我猜这是你们第一次见到一个过程产生出另一个过程作为其结果 I think for the first time you're seeing a procedure which produces a procedure as its value. 446 00:37:21,980 --> 00:37:25,660 这个过程接受了过程F 做了一些工作 This procedure takes the procedure f and does something to it 447 00:37:25,920 --> 00:37:28,340 产生出一个新的过程 拥有一个参数X to produce a new procedure of one argument x, 448 00:37:29,140 --> 00:37:30,660 计算出F... which averages f 449 00:37:30,660 --> 00:37:31,200 这里的F -- this f-- 450 00:37:31,460 --> 00:37:33,860 F(X)和X的平均值 applied to x and x itself. 451 00:37:35,640 --> 00:37:37,200 在代码的这个部分 Using the context here, 452 00:37:37,660 --> 00:37:42,760 我将AVERAGE-DAMP应用到过程X/Y上 I apply average damping to the procedure, which just divides x by y. 453 00:37:44,340 --> 00:37:45,100 就是个除法 It's a division. 454 00:37:48,160 --> 00:37:49,760 接着再找到这个过程的不动点 And I'm finding to fixed point of that, 455 00:37:50,180 --> 00:37:54,440 这个写法更清晰的阐明了整个过程 较之于先前这里的写法 and that's a clearer way of writing down what I wrote down over here, 456 00:37:55,520 --> 00:37:56,480 我找找... wherever it was. 457 00:37:57,280 --> 00:37:57,820 先前这里的写法 Here, 458 00:37:59,140 --> 00:38:00,880 因为它做出了更进一步的抽象 because it tells why I am writing this down. 459 00:38:04,740 --> 00:38:11,860 我希望以上这些能在一定程度上阐明Heron法 I suppose this to some extent really clarifies what Heron of Alexandria was up to. 460 00:38:14,000 --> 00:38:15,560 先到此为止吧 有什么问题吗? I suppose I'll stop now. Are there any questions? 461 00:38:17,900 --> 00:38:19,480 观众:在你定义AVERAGE-DAMP过程的时候 AUDIENCE: So when you define average damp, 462 00:38:19,500 --> 00:38:23,340 不需要给F一个变量吗? don't you need to have a variable on f? 463 00:38:24,700 --> 00:38:28,240 教授:啊 你的问题是... PROFESSOR: Ah, the question was, and here we're having-- again, 464 00:38:28,240 --> 00:38:29,480 你应该已经了解语法了 you've got to learn about the syntax. 465 00:38:29,480 --> 00:38:32,480 你的问题是当定义AVERAGE-DAMP的时候 The question was when defining average damp, 466 00:38:32,920 --> 00:38:36,920 是否需要给F一个变量? don't you have to have a variable defined with f? 467 00:38:37,640 --> 00:38:39,840 你的意思是提供F的形式参数? What you are asking about is the formal parameter of f? 468 00:38:40,040 --> 00:38:40,400 观众:是的 AUDIENCE: Yeah. 469 00:38:40,820 --> 00:38:41,540 教授:好的 PROFESSOR: OK. 470 00:38:42,640 --> 00:38:44,140 F的形式参数其实是在这里 The formal parameter of f is here. 471 00:38:44,780 --> 00:38:46,620 F的形式参数... The formal parameter of f-- 472 00:38:47,400 --> 00:38:49,180 观众:我指的是AVERAGE-DAMP的形式参数 AUDIENCE: The formal parameter of average damp. 473 00:38:49,840 --> 00:38:54,100 教授:F在这里被应用到了一个参数上 对吗? PROFESSOR: F is being used to apply it to an argument, right? 474 00:38:54,100 --> 00:38:56,480 实际上F确实需要一个形式参数 It's indeed true that f must have a formal parameter. 475 00:38:57,320 --> 00:38:59,480 我们来找一下F的形式参数在哪 Let's find out what f's formal parameter is. 476 00:39:00,020 --> 00:39:01,760 观众:我想问的是AVERAGE-DAMP的形式参数 AUDIENCE: The formal parameter of average damp. 477 00:39:02,020 --> 00:39:04,160 教授:哦 f应该是AVERAGE-DAMP的形式参数 PROFESSOR: Oh, f is the formal parameter of average damp. 478 00:39:04,240 --> 00:39:04,960 抱歉 I'm sorry. 479 00:39:05,120 --> 00:39:07,040 你被一些语法混淆了 You're just confusing a syntactic thing. 480 00:39:07,440 --> 00:39:09,120 我应该用换一种方式写 I could have written this the other way. 481 00:39:10,080 --> 00:39:11,300 我已经明白你的问题了 Actually, I didn't understand your question. 482 00:39:12,120 --> 00:39:13,620 我应该用这种方式写 Of course, I could have written it this other way. 483 00:39:19,120 --> 00:39:20,400 它们是一样的 Those are identical notations. 484 00:39:21,120 --> 00:39:25,540 这是另一种写法 This is a different way of writing this. 485 00:39:31,260 --> 00:39:32,880 你得习惯这种LAMBDA记法 You're going to have to get used to lambda notation 486 00:39:32,880 --> 00:39:33,860 我以后也会使用 because I'm going to use it. 487 00:39:35,100 --> 00:39:36,100 在这里 What it says here, 488 00:39:36,580 --> 00:39:39,860 我定义了AVERAGE-DAMP这个过程 I'm defining the name average damp 489 00:39:40,060 --> 00:39:43,220 来给这个拥有一个参数F的过程命名 to name the procedure whose of one argument f. 490 00:39:44,160 --> 00:39:46,760 这个F就是AVERAGE-DAMP过程的形式参数 That's the formal parameter of the procedure average damp. 491 00:39:48,840 --> 00:39:55,260 这个DEFINE的作用是赋予这个名字一个值 What define does is it says give this name a value. 492 00:39:56,380 --> 00:39:57,760 这里就是这个值 Here is the value of for it. 493 00:40:00,940 --> 00:40:03,300 这是个有趣的语法 That there happens to be a funny syntax 494 00:40:04,140 --> 00:40:08,040 在一些情况下能带来一些便利 to make that easier in some cases is purely convenience. 495 00:40:10,580 --> 00:40:12,240 我在这里使用这种写法的原因 But the reason why I wrote it this way here 496 00:40:12,460 --> 00:40:15,800 是为了强调我处理的过程 is to emphasize that I'm dealing with a procedure 497 00:40:15,840 --> 00:40:17,020 接受了一个过程作为参数 that takes a procedure as its argument 498 00:40:17,020 --> 00:40:18,780 并且产生出另一个过程作为值 and produces a procedure as its value. 499 00:40:23,220 --> 00:40:25,460 观众:我不太理解你为什么使用两次LAMBDA AUDIENCE: I don't understand why you use lambda twice. 500 00:40:25,460 --> 00:40:28,900 难道不能使用一个LAMBDA 以F和X作为参数吗? Can you just use one lambda and take two arguments f and x? 501 00:40:28,900 --> 00:40:29,260 教授:不能 PROFESSOR: No. 502 00:40:29,260 --> 00:40:29,900 观众:不能? AUDIENCE: You can't? 503 00:40:29,900 --> 00:40:31,440 教授:不 那是不同的东西了 PROFESSOR: No, that would be a different thing. 504 00:40:32,020 --> 00:40:33,840 如果我在这里写成 If I were to write the procedure 505 00:40:34,240 --> 00:40:37,720 (λ (F X) (AVERAGE (F X) X)) lambda of f and x, the average of f of x and x, 506 00:40:38,440 --> 00:40:42,160 那么它就不能接受一个过程作为参数 that would not be something which would be allowed to take a procedure as an argument 507 00:40:42,160 --> 00:40:43,800 并且产生一个过程作为值了 and produce a procedure as its value. 508 00:40:44,260 --> 00:40:47,860 它就成为接受一个参数以及一个数字作为它的参数 That would be a thing that takes a procedure as its argument and numbers its argument 509 00:40:48,040 --> 00:40:49,240 并且产生出的是一个新的数 and produces a new number. 510 00:40:50,480 --> 00:40:52,260 而在这里我需要一个过程 But what I'm producing here is a procedure 511 00:40:52,260 --> 00:40:54,920 来作为这个过程的参数 to fit in the procedure slot over here, 512 00:40:54,920 --> 00:40:56,920 并且在这里使用 which is going to be used over here. 513 00:40:58,480 --> 00:40:59,940 所以数字必须来自这里 So the number has to come from here. 514 00:41:01,220 --> 00:41:03,540 最后直到这里才用上X This is the thing that's going to eventually end up in the x. 515 00:41:04,080 --> 00:41:04,860 如果你仍然很迷惑 And if you're confused, 516 00:41:04,860 --> 00:41:08,520 你可以自己做一些代换 you should do some substitution and see for yourself. 517 00:41:11,580 --> 00:41:11,980 你说 Yes? 518 00:41:12,400 --> 00:41:15,740 观众:你可以展示一下如何不用LAMBDA表达式 AUDIENCE: Will you please show the definition for average damp 519 00:41:15,740 --> 00:41:18,420 来定义AVERAGE-DAMP过程吗? without using lambda notation in both cases. 520 00:41:18,960 --> 00:41:21,080 教授:那样就无法如此简练地实现了 PROFESSOR: I can't make a very simple one like that. 521 00:41:21,080 --> 00:41:22,220 我来定义给你看 Let me do it for you, though. 522 00:41:22,220 --> 00:41:24,220 我可以很容易地去掉这个LAMBDA I can get rid of this lambda easily. 523 00:41:26,160 --> 00:41:27,680 我不希望... I don't want to be-- 524 00:41:32,400 --> 00:41:33,700 好吧 我说谎了 actually, I'm lying to you. 525 00:41:33,700 --> 00:41:35,460 我不想照你那样去实现 I don't want to do what you want 526 00:41:36,080 --> 00:41:37,860 因为这会远比你想象的复杂 because I think it's more confusing than you think. 527 00:41:38,520 --> 00:41:40,140 我就不去实现你的想法了 I'm not going to write what you want. 528 00:41:54,960 --> 00:41:56,200 这里得起个名字 So we'll have to get a name. 529 00:41:56,200 --> 00:42:00,100 (FOO x)为... FOO of x to be 530 00:42:05,220 --> 00:42:09,500 ...(F x)和X of F of x and x 531 00:42:11,420 --> 00:42:13,280 返回值是FOO and return as a value FOO. 532 00:42:16,920 --> 00:42:18,120 这个是等价的写法 This is equivalent, 533 00:42:19,020 --> 00:42:20,560 但我还得另写一个冗余的变量名 but I've had to make an arbitrary name up. 534 00:42:21,280 --> 00:42:23,860 这两个是等价的 但没有使用LAMBDA This is equivalent to this without any lambdas. 535 00:42:26,280 --> 00:42:30,920 LAMBDA非常适合于需要匿名过程的地方 Lambda is very convenient for naming anonymous procedures. 536 00:42:30,920 --> 00:42:32,200 用它来代表一些匿名的事物 It's the anonymous name of something. 537 00:42:33,660 --> 00:42:39,160 其实存在着更优美的解决方法 Now, if you really want to know a cute way of doing this, 538 00:42:39,300 --> 00:42:40,220 我们以后会提到 we'll talk about it later. 539 00:42:41,380 --> 00:42:44,260 匿名过程的定义还是必要的 We're going to have to define the anonymous procedure. 540 00:42:44,780 --> 00:42:45,640 还有问题吗? Any other questions? 541 00:42:49,100 --> 00:42:50,480 休息一下吧 And so we go for our break again. 542 00:42:53,880 --> 00:43:00,940 [音乐] [JESU, JOY OF MAN'S DESIRING] 543 00:43:01,340 --> 00:43:05,180 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 544 00:43:05,260 --> 00:43:10,000 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 545 00:43:16,400 --> 00:43:20,540 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 546 00:43:20,660 --> 00:43:24,480 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 547 00:43:24,640 --> 00:43:28,340 高阶过程 Higher-order Procedures 548 00:43:31,360 --> 00:43:36,120 我们现在已经了解了如何使用高阶过程 So now we've seen how to use high-order procedures, they're called. 549 00:43:36,120 --> 00:43:39,520 用来接受过程参数和产生过程结果 That's procedures that take procedural arguments and produce procedural values 550 00:43:40,140 --> 00:43:44,780 来帮助我们阐明和抽象一些复杂的过程 to help us clarify and abstract some otherwise complicated processes. 551 00:43:46,060 --> 00:43:48,520 我现在打算用它来做一些更有趣的事情 I suppose what I'd like to do now is have a bit of fun with that 552 00:43:49,320 --> 00:43:52,900 也同时作为练习 and sort of a little practice as well. 553 00:43:53,720 --> 00:43:55,920 我们来更深入地研究一下SQRT过程 So let's play with this square root thing even more. 554 00:43:55,920 --> 00:43:58,620 详尽地剖析和理解其中的工作方式 Let's elaborate it and understand what's going on 555 00:43:59,200 --> 00:44:01,800 并且利用一下它的代码结构 and make use of this kind of programming style. 556 00:44:03,940 --> 00:44:07,500 有件事你们已经知道 One thing that you might know is 557 00:44:07,500 --> 00:44:09,720 有一个通用的方法叫做牛顿法 there is a general method called Newton's method 558 00:44:10,640 --> 00:44:13,780 用来计算函数的根 for the purpose of which is to find the roots-- 559 00:44:14,480 --> 00:44:17,780 也就是函数的零点 that's the zeroes-- of functions. 560 00:44:18,740 --> 00:44:19,800 举个例子 So, for example, 561 00:44:20,700 --> 00:44:37,060 求Y 使得F(Y)等于0 to find a y such that f of y equals 0, 562 00:44:37,880 --> 00:44:39,340 首先要从一个猜测值开始 we start with some guess. 563 00:44:40,000 --> 00:44:40,960 这就是牛顿法 This is Newton's method. 564 00:44:50,960 --> 00:44:53,720 将初始的猜测值命名为Y0 And the guess we start with we'll call y0, 565 00:44:54,840 --> 00:44:59,180 然后我们迭代地计算下面这个表达式 and then we will iterate the following expression. 566 00:45:00,580 --> 00:45:02,340 Yn+1 y n plus 1-- 567 00:45:02,340 --> 00:45:03,760 这是另外一个方程 this is a difference equation-- 568 00:45:04,460 --> 00:45:10,040 等于Yn-F(Yn) is yn minus f of yn 569 00:45:12,000 --> 00:45:17,660 除以F对Y的导数 over the derivative with respect to y of f 570 00:45:18,260 --> 00:45:21,760 在Y=Yn点处的值 evaluated at y equal yn. 571 00:45:22,840 --> 00:45:24,180 非常奇怪的式子 Very strange notation. 572 00:45:25,580 --> 00:45:29,340 我得说... I must say ugh. 573 00:45:30,600 --> 00:45:34,620 f对y的求导得到的是一个函数 The derivative of f with respect to y is a function. 574 00:45:35,340 --> 00:45:37,420 感觉上会有些麻烦 I'm having a little bit of unhappiness with that, 575 00:45:37,840 --> 00:45:38,660 不过没关系 but that's all right. 576 00:45:39,140 --> 00:45:40,900 在用程序语言表达以后 It turns out in the programming language world, 577 00:45:40,980 --> 00:45:42,160 会变得非常清晰 the notation is much clearer. 578 00:45:43,560 --> 00:45:44,480 这是什么? Now, what is this? 579 00:45:45,700 --> 00:45:46,860 这就是所谓的牛顿法 People call it Newton's method. 580 00:45:46,900 --> 00:45:52,180 它用来计算函数F的根 It's a method for finding the roots of the function f. 581 00:45:53,860 --> 00:45:57,300 当收敛的时候 它会计算得很快 And it, of course, sometimes converges, and when it does, it does so very fast. 582 00:45:57,980 --> 00:46:00,340 不过有时是不收敛的 And sometimes, it doesn't converge, and, 583 00:46:00,580 --> 00:46:02,260 那样我们就需要做一些其它的工作 oh well, we have to do something else. 584 00:46:02,760 --> 00:46:05,640 先让我们来讨论一下用牛顿法计算平方根 But let's talk about square root by Newton's method. 585 00:46:06,760 --> 00:46:08,320 这会很有趣 Well, that's rather interesting. 586 00:46:08,320 --> 00:46:10,380 我们先使用一下之前用到过的方法 Let's do exactly the same thing we did last time: 587 00:46:10,560 --> 00:46:11,900 按愿望思维的方法 a bit of wishful thinking. 588 00:46:13,020 --> 00:46:14,800 假设我们已经实现了牛顿法 We will apply Newton's method, 589 00:46:14,980 --> 00:46:16,420 可以直接使用它 assuming we knew how to do it. 590 00:46:17,840 --> 00:46:19,200 事实上你还并未实现 You don't know how to do it yet. 591 00:46:20,300 --> 00:46:21,140 让我们开始吧 Well, let's go. 592 00:46:24,880 --> 00:46:26,780 这里要写什么?(SQRT X) What do I have here? The square root of x. 593 00:46:31,000 --> 00:46:39,040 将牛顿法应用到某个作用在Y上的过程上 It's Newton's method applied to a procedure which will represent that function of y, 594 00:46:39,040 --> 00:46:40,500 这个过程用于计算Y对应的函数值 which computes that function of y. 595 00:46:42,100 --> 00:46:45,820 这个过程参数是Y Well, that procedure is that procedure of y, 596 00:46:46,840 --> 00:46:51,400 计算出X和根号Y的差 which is the difference between x and the square of y. 597 00:46:59,660 --> 00:47:05,880 实际上 如果存在Y使得这个式子等于0 Indeed, if I had a value of y for which this was zero, 598 00:47:07,020 --> 00:47:09,740 那么Y就是X的平方根 then y would be the square root of x. 599 00:47:13,340 --> 00:47:13,940 明白吗? See that? 600 00:47:15,160 --> 00:47:18,700 接下来 我令其从1开始尝试 OK, I'm going to start this out searching at 1. 601 00:47:18,880 --> 00:47:24,080 这完全是一个随意写下的猜测值 Again, completely arbitrary property of square roots that I can do that. 602 00:47:24,700 --> 00:47:30,280 现在的问题是 牛顿法应该如何实现? Now, how am I going to compute Newton's method? 603 00:47:31,160 --> 00:47:32,620 方法的过程在这里书写了 Well, this is the method I have it right here. 604 00:47:33,860 --> 00:47:39,580 实际上 我所做的是寻找某个过程的不动点 In fact, what I'm doing is looking for a fixed point of some procedure. 605 00:47:40,940 --> 00:47:44,320 这个过程包含了一些复杂的表达式 This procedure involves some complicated expressions 606 00:47:44,660 --> 00:47:46,740 和一些其它的怪东西 in terms of other complicated things. 607 00:47:47,140 --> 00:47:48,400 我就是要找到这个式子的不动点 Well, I'm trying to find the fixed point of this. 608 00:47:48,400 --> 00:47:52,060 我要找到某个Y的值 I want to find the values of y, 609 00:47:52,300 --> 00:47:55,440 使得在这里带入这个值后 得到的是相同的值 which if I put y in here, I get the same value out here 610 00:47:56,580 --> 00:47:58,400 考虑在一定的误差范围内 up to some degree of accuracy. 611 00:47:59,740 --> 00:48:03,400 好在我已经有一个计算不动点的过程了 Well, I already have a fixed point process around to do that. 612 00:48:04,600 --> 00:48:07,300 我们在这里开始定义牛顿法 And so, let's just define Newton's method over here. 613 00:48:19,640 --> 00:48:21,920 这个过程需要一个函数和一个猜测值 A procedure which computes a function and a guess, 614 00:48:24,440 --> 00:48:25,340 初始的猜测值 initial guess. 615 00:48:26,180 --> 00:48:28,100 我接下来要做一件事 Now, I'm going to have to do something here. 616 00:48:28,520 --> 00:48:32,520 要计算出函数的导数 I'm going to need the derivative of the function. 617 00:48:32,860 --> 00:48:35,100 我需要一个过程来计算出函数的导数 I'm going to need a procedure which computes the derivative 618 00:48:36,120 --> 00:48:39,140 给出的函数由过程F来计算 of the function computed by the given a procedure f. 619 00:48:41,700 --> 00:48:43,780 我接下来会讲的很仔细 I'm trying to be very careful about what I'm saying. 620 00:48:44,160 --> 00:48:45,860 我不想混淆“过程”和“函数”这两个词 I don't want to mix up the word procedure and function. 621 00:48:45,860 --> 00:48:47,180 函数是数学术语 Function is a mathematical word. 622 00:48:47,880 --> 00:48:52,160 将一个值映射到另一个值 It says I'm mapping from values to other values, 623 00:48:52,420 --> 00:48:53,360 有序偶的集合之类的 a set of ordered pairs. 624 00:48:55,060 --> 00:48:58,100 但有时我也会不小心说岔 But sometimes, I'll accidentally mix those up. 625 00:48:59,800 --> 00:49:01,540 而过程是用来计算函数的 Procedures compute functions. 626 00:49:07,360 --> 00:49:10,220 我将dF定义为... So I'm going to define the derivative of f 627 00:49:10,820 --> 00:49:12,720 再使用一下按愿望思维 to be by wishful thinking again. 628 00:49:12,720 --> 00:49:13,560 先不管具体如何实现 I don't know how I'm going to do it. 629 00:49:14,360 --> 00:49:15,540 我们之后再讨论 Let's worry about that later-- 630 00:49:18,360 --> 00:49:19,020 F的导数 of F. 631 00:49:20,160 --> 00:49:21,560 F是一个过程 So if F is a procedure, 632 00:49:23,280 --> 00:49:26,320 在这里的情况指的是开根号 which happens to be this one over here for a square root, 633 00:49:28,780 --> 00:49:31,780 dF就是其的导数 then DF will be the derivative of it, 634 00:49:31,920 --> 00:49:35,500 也就是由过程F计算的函数的导函数 which is also the derivative of the function computed by that procedure. 635 00:49:35,500 --> 00:49:40,620 dF就是一个计算由过程F计算的函数的导数过程 DF will be a procedure that computes the derivative of the function computed by the procedure F. 636 00:49:41,840 --> 00:49:44,520 定义好这个之后 我就要来寻找一个不动点 And then given that, I will just go looking for a fixed point. 637 00:49:51,380 --> 00:49:53,160 我要寻找的不动点是什么的呢? What is the fixed point I'm looking for? 638 00:49:53,300 --> 00:49:56,440 这个过程有一个参数X It's the one for that procedure of one argument x, 639 00:49:57,060 --> 00:50:00,000 计算出X减... which I compute by subtracting x. 640 00:50:00,100 --> 00:50:02,680 X是先前的值 相当于那里的Yn That's the old-- that's the yn here. 641 00:50:04,480 --> 00:50:11,560 F(X)和dF(X)的商 The quotient of f of x and df of x, 642 00:50:20,180 --> 00:50:21,540 从原始的猜测值开始 starting out with the original guess. 643 00:50:29,440 --> 00:50:31,020 整个看上去很简单 That's all very simple. 644 00:50:32,180 --> 00:50:34,220 现在 我还有一个部分没有写 Now, I have one part left that I haven't written, 645 00:50:34,220 --> 00:50:37,380 我先需要你们回顾一下我整个的实现流程 and I want you to see the process by which I write these things, 646 00:50:37,380 --> 00:50:38,520 这在实际经验中是很实用的 because this is really true. 647 00:50:39,820 --> 00:50:41,940 首先我拥有数学的猜想 I start out with some mathematical idea, perhaps. 648 00:50:42,220 --> 00:50:45,480 通过按愿望思维 By wishful thinking, I assume 649 00:50:46,280 --> 00:50:49,200 我假设我已经拥有了一些魔法可以实现一些过程 that by some magic I can do something that I have a name for. 650 00:50:50,580 --> 00:50:52,320 先不关心到底如何去实现它们 I'm not going to worry about how I do it yet. 651 00:50:54,500 --> 00:50:55,860 然后再继续 Then I go walking down here and say, well, 652 00:50:55,860 --> 00:50:59,060 通过这些魔法 我大致实现了整个过程 by some magic, I'm somehow going to figure how to do that, 653 00:51:00,540 --> 00:51:01,960 即使还未实现某些方法 but I'm going to write my program anyway. 654 00:51:03,880 --> 00:51:06,220 这种按愿望思维 对于工程来说是很重要的 Wishful thinking, essential to good engineering, 655 00:51:07,380 --> 00:51:09,700 同样 对于计算机科学也是很重要的 and certainly essential to a good computer science. 656 00:51:12,000 --> 00:51:16,560 那么 有多少人想让你的计算机运行得更快? So anyway, how many of you wished that your computer ran faster? 657 00:51:20,900 --> 00:51:22,520 求导过程的实现并不会很困难 Well, the derivative isn't so bad either. 658 00:51:23,060 --> 00:51:24,280 有点类似于AVERAGE-DAMP过程 Sort of like average damping. 659 00:51:28,980 --> 00:51:35,340 DERIV求导过程接受一个用于计算函数值的过程 The derivative is a procedure that takes a procedure that computes a function as its argument, 660 00:51:36,960 --> 00:51:41,000 然后产生一个过程 and it produces a procedure that computes a function, 661 00:51:41,180 --> 00:51:42,720 接受一个参数X which needs one argument x. 662 00:51:43,700 --> 00:51:45,080 你们应该都清楚导数的定义 Well, you all know this definition. 663 00:51:45,900 --> 00:51:48,400 是(F(X + dX) - F(X)) / dX 对吗? It's f of x plus delta x minus f of x over delta x, right? 664 00:51:48,720 --> 00:51:49,860 dX是一个很小的值 For some small delta x. 665 00:51:50,480 --> 00:52:10,180 即(/ (- (F (+ X dX)) (F X)) dX) So that's the quotient of the difference of f of the sum of x and dx minus f point x divided by dx. 666 00:52:18,040 --> 00:52:21,800 我希望括号没有匹配错误 I think the thing was lining up correctly when I balanced the parentheses. 667 00:52:24,760 --> 00:52:25,840 我希望你们看一下这个 Now, I want you to look at this. 668 00:52:26,660 --> 00:52:27,460 仔细的观察一下 Just look. 669 00:52:30,880 --> 00:52:32,620 我应该还没定义dX I suppose I haven't told you what dx is. 670 00:52:32,860 --> 00:52:35,420 我会在其它某个地方写下 Somewhere in the world I'm going to have to write down 671 00:52:44,240 --> 00:52:45,340 这样的定义 something like that. 672 00:52:45,760 --> 00:52:46,780 这无关紧要 I'm not interested. 673 00:52:47,820 --> 00:52:53,680 这个过程接受一个过程然后产生出一个近似过程 This is a procedure which takes a procedure and produces an approximation, 674 00:52:53,680 --> 00:52:56,480 这个近似过程用于计算出某个函数的导数 a procedure that computes an approximation of the derivative 675 00:52:56,540 --> 00:52:58,540 函数是由给定的过程计算的 of the function computed by the procedure given 676 00:53:00,860 --> 00:53:03,000 其中使用了大家熟悉的求导方法 by the standard methods that you all know and love. 677 00:53:04,360 --> 00:53:10,440 也许这并不是一个很好的估算导数的方法 Now, it may not be the case that doing this operation is such a good way of approximating a derivative. 678 00:53:11,020 --> 00:53:14,700 数值分析学家可能会跳出来对我说 Numerical analysts here should jump on me and say 679 00:53:14,700 --> 00:53:15,360 不要那样做! don't do that. 680 00:53:16,320 --> 00:53:18,700 计算机求导确实会带来一定的误差 Computing derivatives produces noisy answers, which is true. 681 00:53:19,960 --> 00:53:23,460 然而这只是用于理解整个过程 However, this again is for the sake of understanding. 682 00:53:24,380 --> 00:53:25,320 回顾一下 Look what we've got. 683 00:53:26,180 --> 00:53:29,520 我们首先起手于一个复杂的数学方法 We started out with what is apparently a mathematically complex thing. 684 00:53:30,820 --> 00:53:32,560 写满的几个黑板中 and in a few blackboards full, 685 00:53:33,760 --> 00:53:36,840 我们试图将这个求根号的问题分解 we managed to decompose the problem of computing square roots 686 00:53:36,840 --> 00:53:42,300 通过你们在数值课程中学到的牛顿法 by the way you were taught in your college calculus class-- Newton's method-- 687 00:53:43,380 --> 00:53:44,540 分解以后就能很容易处理了 so that it can be understood. 688 00:53:45,480 --> 00:53:46,220 变得清晰了 It's clear. 689 00:53:47,400 --> 00:53:49,780 看一下求解的整个结构 Let's look at the structure of what it is we've got. 690 00:53:51,160 --> 00:53:52,580 请看一下幻灯片 Let's look at this slide. 691 00:53:54,580 --> 00:54:04,140 这是黑板上描述的程序的流程图 This is a diagram of the machine described by the program on the blackboard. 692 00:54:05,440 --> 00:54:06,960 描述了机器执行的过程 There's a machine described here. 693 00:54:08,520 --> 00:54:09,440 有哪些部分呢? And what have I got? 694 00:54:10,240 --> 00:54:16,540 这个部分代表了牛顿法中的函数F Over here is the Newton's method function f 695 00:54:16,840 --> 00:54:19,040 写在了黑板的最左面 that we have on the left-most blackboard. 696 00:54:20,180 --> 00:54:22,520 它接受了一个参数Y It's the thing that takes an argument called y 697 00:54:22,780 --> 00:54:27,160 计算出X与根号Y的差 and puts out the difference between x and the square of y, 698 00:54:29,560 --> 00:54:35,980 通过某种魔法 X作为自由变量从外部进入 where x is some sort of free variable that comes in from the outside by some magic. 699 00:54:37,700 --> 00:54:41,500 所以square-root过程需要获取到X的值 So the square root routine picks up an x, 700 00:54:42,180 --> 00:54:43,640 并给定这个过程 and builds this procedure, 701 00:54:45,280 --> 00:54:48,120 X就被替换到内部的过程中 which I have the x rolled up in it by substitution. 702 00:54:49,720 --> 00:54:54,780 云中的这个过程被作为参数F Now, this procedure in the cloud is fed in as the f 703 00:54:58,080 --> 00:55:01,280 传递进这个框中的牛顿法 into the Newton's method which is here, this box. 704 00:55:04,580 --> 00:55:07,900 F在这里有两个去向 The f is fanned out. 705 00:55:08,400 --> 00:55:10,380 一是被用作参数传递 Part of it goes into something else, 706 00:55:10,900 --> 00:55:14,220 二是被应用到求导过程中 再将求导结果传递 and the other part of it goes through a derivative process into something else 707 00:55:14,980 --> 00:55:17,140 来产生一个新的过程 to produce a procedure, 708 00:55:17,720 --> 00:55:23,360 产生出的过程作为计算牛顿法的迭代函数的过程 which computes the function which is the iteration function of Newton's method 709 00:55:23,360 --> 00:55:24,640 最后将其应用到求不动点的方法上 when we use the fixed point method. 710 00:55:27,120 --> 00:55:29,000 所以这个过程 So this procedure, 711 00:55:29,940 --> 00:55:32,420 通过代换使用了(F和dF) which contains it by substitution-- 712 00:55:32,560 --> 00:55:38,340 记住 是这里的牛顿法构造出了这个过程 remember, Newton's method over here, Newton's method builds this procedure, 713 00:55:39,320 --> 00:55:43,060 并且是在牛顿法中定义了F和dF and Newton's method has in it defined f and df, 714 00:55:44,640 --> 00:55:47,300 所以 F和dF在这里被捕获 so those are captured over here: f and df. 715 00:55:48,600 --> 00:55:49,900 利用这个过程 Starting with this procedure, 716 00:55:50,440 --> 00:55:52,680 传递进FIXED-POINT过程里 I can now feed this to the fixed point process 717 00:55:53,220 --> 00:55:56,840 再利用从SQRT外传递进的初始的猜测值 within an initial guess coming out from the outside from square root 718 00:55:58,140 --> 00:55:59,580 来计算出X的平方根 to produce the square root of x. 719 00:56:03,340 --> 00:56:05,820 于是我们就制造出了一个强大的引擎 So what we've built is a very powerful engine, 720 00:56:06,600 --> 00:56:09,260 通过它我们可以制造出类似的优美的东西 which allows us to make nice things like this. 721 00:56:11,240 --> 00:56:19,160 最后 我想使用Chris Strachey提出的一个基本思想作为结束 Now, I want to end this with basically an idea of Chris Strachey, 722 00:56:19,600 --> 00:56:22,540 他是计算机科学之父之一 one of the grandfathers of computer science. 723 00:56:22,900 --> 00:56:25,180 他是一位逻辑学家 大概... He's a logician who lived in the-- 724 00:56:27,040 --> 00:56:29,700 大概10到15年前他去世了 I suppose about 10 years ago or 15 years ago, he died. 725 00:56:29,860 --> 00:56:31,340 我记不太清了 I don't remember exactly when. 726 00:56:31,500 --> 00:56:34,240 他是指称语义学的发明者之一 He's one of the inventors of something called denotational semantics. 727 00:56:34,600 --> 00:56:42,320 他是将过程或是函数视为程序设计语言中的第一级元素的最主要的提倡者 He was a great advocate of making procedures or functions first-class citizens in a programming language. 728 00:56:43,540 --> 00:56:48,660 这些是程序设计语言中的第一级元素的某些权利或者特权 So here's the rights and privileges of first-class citizens in a programming language. 729 00:56:50,140 --> 00:56:52,080 如果你想要做出任何你想要做出的抽象 It allows you to make any abstraction you like 730 00:56:52,540 --> 00:56:55,460 那么将函数视为第一级元素是必须的 if you have functions as first-class citizens. 731 00:56:57,260 --> 00:57:00,060 第一级元素必须能够可以用变量命名 The first-class citizens must be able to be named by variables. 732 00:57:01,840 --> 00:57:03,660 你们已经见过我这样做过很多次 And you're seeing me doing that all the time. 733 00:57:04,000 --> 00:57:08,200 这里是将某个过程作为变量命名的例子 Here's a nice variable which names a procedure which computes something. 734 00:57:12,820 --> 00:57:15,040 他们必须可以被提供给过程作为参数 They have to be passed as arguments to procedures. 735 00:57:15,040 --> 00:57:16,020 我们之前见过这种情况了 We've certainly seen that. 736 00:57:18,160 --> 00:57:20,940 他们可以由过程作为结果返回 We have to be able to return them as values from procedures. 737 00:57:22,840 --> 00:57:24,320 我们也应该见过了 And I suppose we've seen that. 738 00:57:24,740 --> 00:57:27,040 我们还没有见过关于数据结构的内容 We haven't yet seen anything about data structures. 739 00:57:27,600 --> 00:57:28,440 我们之后会讨论的 We will soon, 740 00:57:29,140 --> 00:57:33,140 这也是作为程序设计语言的第一级元素必要的性质 but it's also the case that in order to have a first-class citizen in a programming language, 741 00:57:33,520 --> 00:57:35,980 它们可以包含在数据结构中 the object has to be allowed to be part of a data structure. 742 00:57:36,760 --> 00:57:37,880 我们马上就会见到 We're going to see that soon. 743 00:57:39,040 --> 00:57:40,320 所以就先到此为止吧 So I just want to close with this 744 00:57:40,820 --> 00:57:46,380 我们见识到了像过程这样的第一级元素 and say having things like procedures as first-class data structures, first-class data, 745 00:57:46,960 --> 00:57:49,800 可以带来如此强大的抽象能力 allows one to make powerful abstractions, 746 00:57:50,220 --> 00:57:53,720 像牛顿法这样的通用方法可以被非常清晰地编写出来 which encode general methods like Newton's method in very clear way. 747 00:57:54,380 --> 00:57:55,280 有什么问题吗? Are there any questions? 748 00:57:56,960 --> 00:57:57,440 请 Yes. 749 00:57:57,980 --> 00:58:01,920 观众:(DERIV F)可以直接写到FIXED-POINT方法中取代dF吗 AUDIENCE: Could you put derivative instead of df directly in the fixed point? 750 00:58:02,120 --> 00:58:02,700 教授:哦 当然 PROFESSOR: Oh, sure. 751 00:58:03,420 --> 00:58:07,400 当然可以直接把(DERIV F)放到这里 Yes, I could have put deriv of f right here, 752 00:58:08,180 --> 00:58:09,080 没有问题 no question. 753 00:58:11,360 --> 00:58:13,320 每当你见到定义了什么东西 Any time you see something defined, 754 00:58:14,180 --> 00:58:17,240 你就可以直接把定义写到这里 you can put the thing that the definition is there 755 00:58:18,380 --> 00:58:19,320 你会得到相同的结果 and you should get the same result. 756 00:58:20,620 --> 00:58:22,700 实际上 那样就会看上去很有趣 In fact, what that would look like, it's interesting. 757 00:58:22,700 --> 00:58:23,040 观众:LAMBDA AUDIENCE: Lambda. 758 00:58:23,240 --> 00:58:23,660 教授:嗯? PROFESSOR: Huh? 759 00:58:23,760 --> 00:58:25,300 观众:你可以把LAMBDA表达式写在那 AUDIENCE: You could put the lambda expression in there. 760 00:58:25,480 --> 00:58:28,340 教授:我也可以把(DERIV F)写在这 PROFESSOR: I could also put derivative of f here. 761 00:58:29,940 --> 00:58:30,820 这看上去会很有意思 It would look interesting 762 00:58:31,100 --> 00:58:36,620 即((DERIV F) X) because of the open paren, open paren, deriv of f, closed paren on an x. 763 00:58:38,140 --> 00:58:41,840 那样就会冗余地重复计算导数 Now, that would have the bad property of computing the derivative many times, 764 00:58:42,480 --> 00:58:43,840 因为每当我执行这个过程的时候 because every time I would run this procedure, 765 00:58:43,840 --> 00:58:45,120 都要重新计算导数 I would compute the derivative again. 766 00:58:47,840 --> 00:58:51,800 这里的两个左括号都有意义 However, the two open parens here both would be meaningful. 767 00:58:52,100 --> 00:58:54,960 我希望你们理解这里细节的语法 I want you to understand syntactically that that's a sensible thing. 768 00:58:55,820 --> 00:58:57,460 如果我重写这个程序 Because if was to rewrite this program-- 769 00:58:57,460 --> 00:58:58,920 在这里按照你的想法重写 and I should do it right here just so you see 770 00:58:59,760 --> 00:59:00,800 这个问题问得好 because that's a good question-- 771 00:59:10,200 --> 00:59:12,260 ...F和GUESS of F and guess 772 00:59:15,800 --> 00:59:26,080 结果是求参数为X to be fixed point of that procedure of one argument x, 773 00:59:26,380 --> 00:59:44,720 结果为(- X (/ (F X)((DERIV F) X)))的过程的不动点 which subtracts from x the quotient of F applied to x and the deriv of F applied to x. 774 00:59:52,940 --> 00:59:54,220 这里是GUESS Um, This is guess. 775 00:59:59,500 --> 01:00:01,420 这是一个完全正确的程序 This is a perfectly legitimate program, 776 01:00:02,260 --> 01:00:03,540 因为在这里... because what I have here-- 777 01:00:03,860 --> 01:00:05,300 记住求值规则 remember the evaluation rule. 778 01:00:05,780 --> 01:00:09,040 求值规则是求值每个组合式的所有部分 The evaluation rule is evaluate all of the parts of the combination: 779 01:00:09,040 --> 01:00:11,040 包括运算符和运算对象 the operator and the operands. 780 01:00:11,720 --> 01:00:14,640 这是这个组合式的运算符 This is the operator of this combination. 781 01:00:16,540 --> 01:00:22,120 求值这个运算符会产生F的导数 Evaluating this operator will, of course, produce the derivative of F. 782 01:00:28,080 --> 01:00:31,160 观众:甚者 是否可以在那里写成LAMBDA表达式 AUDIENCE: To get it one step further, you could put the lambda expression there, too. 783 01:00:31,220 --> 01:00:32,020 教授:哦当然 PROFESSOR: Oh, of course. 784 01:00:32,780 --> 01:00:35,720 每当我在某处使用了定义好的东西 Any time I take something which is define, 785 01:00:35,720 --> 01:00:40,760 我也可以将其替换成它定义的具体内容 I can put the thing it's defined to be in the place where the thing defined is. 786 01:00:41,960 --> 01:00:44,820 不用去区分哪个是被定义项 哪个是定义项 I can't remember which is definiens and which is definiendum. 787 01:00:45,460 --> 01:00:51,600 每当我在思考如何在课堂上向新手解释这个问题 When I'm trying to figure out how to do a lecture about this in a freshman class, 788 01:00:51,600 --> 01:00:55,120 我觉得这种概念游戏是很有意思的 I use such words and tell everybody it's fun to tell their friends. 789 01:00:59,200 --> 01:01:00,040 那么就到此为止吧 OK, I think that's it. 790 01:01:01,700 --> 01:01:08,220 MIT OpenCourseWare http://ocw.mit.edu 791 01:01:08,300 --> 01:01:17,940 本项目主页 https://github.com/FoOTOo/Learning-SICP ================================================ FILE: SrtCN/lec2b.srt ================================================ 1 00:00:00,000 --> 00:00:04,000 哈尔滨工业大学 IBM技术中心 倾情制作 2 00:00:04,100 --> 00:00:08,000 压制&&特效:蔡钟毓(JohnTitor) 翻译&&时间轴:邓雄飞(Dysprosium) 3 00:00:08,100 --> 00:00:12,000 特别感谢:裘宗燕教授 校对:邓雄飞(Dysprosium) 4 00:00:13,000 --> 00:00:16,500 复合数据 Compound Data 5 00:00:21,720 --> 00:00:25,020 到目前为止 这门课都在讨论过程 Well, so far in this course we've been talking about procedures, 6 00:00:25,920 --> 00:00:27,900 我想提醒大家 我们介绍的这个框架 and then just to remind you of this framework 7 00:00:29,040 --> 00:00:30,840 是用来讨论语言的 that we introduced for talking about languages, 8 00:00:30,840 --> 00:00:34,800 我们讨论内建于系统中的基本元素 we talked about the primitive things that are built into the system. 9 00:00:35,540 --> 00:00:37,620 我们介绍了一些组合的方法 We mentioned some means of combination 10 00:00:38,660 --> 00:00:41,540 这些方法用来组合基本元素 使你能够构造更复杂的东西 by which you take the primitive thingsand you make more complicated things. 11 00:00:42,200 --> 00:00:43,960 然后我们讨论了抽象的方法 And then we talked about the means of abstraction, 12 00:00:43,960 --> 00:00:46,220 你如何去取用这些复杂的东西 how you can take those complicated things and name them 13 00:00:46,560 --> 00:00:48,220 给它们命名 这样就可以像简单单元那样使用 so you can use them as simple building blocks. 14 00:00:49,320 --> 00:00:51,560 上节课最后 我们甚至做了更超前的东西 And then last time you saw we went even beyond that. 15 00:00:51,560 --> 00:00:54,140 我们看到 通过使用高阶过程 We saw that by using higher order procedures, 16 00:00:55,200 --> 00:00:57,800 我们甚至可以表达计算的通用方法 you can actually express general methods for computing things. 17 00:00:57,800 --> 00:01:02,160 这就像求不动点的方法和牛顿法 Like the method of doing something by fixed points, or Newton's method, 18 00:01:02,940 --> 00:01:05,500 你可以通过组合这些抽象的方法 and so the incredible expressive power you can get 19 00:01:05,760 --> 00:01:08,280 来得到这种难以置信的表达力 just by combining these means of abstraction. 20 00:01:08,280 --> 00:01:11,820 这样做的中心点是 And the crucial idea in all of this is 21 00:01:11,820 --> 00:01:14,220 我们要构建一个层次系统 the one that we build a layered system. 22 00:01:14,900 --> 00:01:15,940 譬如说 So for instance, 23 00:01:16,180 --> 00:01:18,080 如果我们编写平方根过程 if we're writing the square root procedure, 24 00:01:20,880 --> 00:01:25,920 而这个平方根过程又用到了一个叫GOOD-ENOUGH的过程 somewhere the square root procedure uses a procedure called good-enough, 25 00:01:31,080 --> 00:01:35,060 而这两者之间就有某种抽象屏障 and between those there is some sort of abstraction boundary. 26 00:01:37,640 --> 00:01:40,980 这大概就像是我们开始编写平方根程序 It's almost as if we go out and in writing square root, 27 00:01:40,980 --> 00:01:43,640 先要与George订好“契约” we go and make a contract with George, 28 00:01:44,760 --> 00:01:46,940 告诉他 他的工作是编写GOOD-ENOUGH过程 and tell George that his job is to write good-enough, 29 00:01:48,660 --> 00:01:50,320 因此只要GOOD-ENOUGH按我们的预期运作 and so long as good-enough works, 30 00:01:50,320 --> 00:01:51,460 我们就不管它是如何运作的 we don't care what it does. 31 00:01:52,320 --> 00:01:54,220 我们不关心(它的内部)实现 We don't care exactly how it's implemented. 32 00:01:54,220 --> 00:01:58,880 实现层面是Goerge操心的 和我们无关 There are levels of detail here that are George's concern and not ours. 33 00:02:00,100 --> 00:02:00,900 又比如 So for instance, 34 00:02:00,900 --> 00:02:05,440 George可能用了Harry写的绝对值过程 George might use an absolute value procedure that's written by Harry, 35 00:02:06,240 --> 00:02:07,440 但我们不会去关心这些 and we don't much care about that 36 00:02:07,440 --> 00:02:09,940 我们甚至可能还不知道有Harry这号人 or even know that, maybe, Harry exists. 37 00:02:13,500 --> 00:02:16,320 关键就是 当我们在构造东西时 So the crucial idea is that when we're building things, 38 00:02:16,320 --> 00:02:23,740 我们将构造整体的任务划分为了实现部件的任务 we divorce the task of building things from the task of implementing the parts. 39 00:02:26,340 --> 00:02:28,740 当然 在一个大型系统中 And in a large system, of course, 40 00:02:28,740 --> 00:02:30,580 我们有像这样的抽象屏障 we have abstraction barriers like this 41 00:02:30,920 --> 00:02:32,580 在很高很高很高层次上的抽象屏障 at lots, and lots, and lots of levels. 42 00:02:33,780 --> 00:02:35,980 这也是我们到目前为止一直在使用的思想 And that's the idea that we've been using so far 43 00:02:35,980 --> 00:02:37,740 贯彻到每次编写过程之中 over and over in implementing procedures. 44 00:02:37,740 --> 00:02:42,360 言归正传 我们将要在数据中看到同样的问题 Well, now what we're going to do is look at the same issues for data. 45 00:02:43,760 --> 00:02:46,100 我们发现系统中有基本数据 We're going to see that the system has primitive data. 46 00:02:46,100 --> 00:02:47,180 实际上我们已经注意了 In fact, we've already seen that. 47 00:02:47,180 --> 00:02:48,960 我们已经讨论了作为基本对象的数 We've talked about numbers as primitive data. 48 00:02:49,940 --> 00:02:52,120 我们将看到适用于数据的组合方法 And then we're going to see their means of combination for data. 49 00:02:52,120 --> 00:02:55,620 有一种“胶水” 能让你把基本数据粘合在一起 There's glue that allows you to put primitive data together 50 00:02:56,040 --> 00:02:58,720 来构造一种更复杂的符合数据 to make more complicated, kind of compound data. 51 00:02:59,160 --> 00:03:03,700 然后我们将看到一种抽象方法学 And then we're going to see a methodology for abstraction 52 00:03:04,600 --> 00:03:06,040 这种方法十分好用 尤其是 that's a very good thing to use 53 00:03:06,040 --> 00:03:08,480 当你用简易的数据构造复杂数据时 when you start building up data in terms of simpler data. 54 00:03:08,480 --> 00:03:12,560 再次强调 中心思想是要建立层次化的系统 And again, the key idea is that you're going to build the system in layers 55 00:03:13,420 --> 00:03:17,860 建立抽象屏障将细节隔离在底层 and set up abstraction barriers that isolate the details at the lower layers 56 00:03:19,560 --> 00:03:21,280 将细节与你所工作的高层环境隔离开 from the thing that's going on at the upper layers. 57 00:03:21,280 --> 00:03:24,120 底层的细节 底层的思想 都不重要 The details at the lower layers, the ideas, they won't matter. 58 00:03:24,920 --> 00:03:26,260 那是George该操心的 They're going to be George's concern 59 00:03:26,520 --> 00:03:28,160 因为他跟我们“订好契约” because he signed this contract with us 60 00:03:28,480 --> 00:03:30,560 他负责实现这些行为 for how the stuff that he implements behaves, 61 00:03:31,640 --> 00:03:34,120 怎么实现都是他的事 and how he implements the thing is his problem. 62 00:03:35,960 --> 00:03:37,360 好了 来看一个实例吧 All right, well let's look at an example. 63 00:03:37,480 --> 00:03:40,320 我们将会讨论一个系统 And the example I'm going to talk about is a system 64 00:03:40,400 --> 00:03:42,560 一个在有理数域上做算术运算的系统 that does arithmetic on rational numbers. 65 00:03:42,560 --> 00:03:44,300 我现在所想到的是 And what I have in mind is that 66 00:03:44,660 --> 00:03:46,520 计算机中应该有某种东西 we should have something in the computer 67 00:03:46,860 --> 00:03:50,340 使得我们可以查询 that allows us to ask it, 68 00:03:50,340 --> 00:03:55,160 类似于 1/2加上1/4的和是多少 like, what's the sum of 1/2 and 1/4, 69 00:03:55,520 --> 00:04:01,220 系统说 是3/4 and somehow the system should say, yeah, that's 3/4. 70 00:04:02,520 --> 00:04:09,400 我们也可以查询3/4乘以2/3的积 Or we should be able to say what's 3/4 times 2/3, 71 00:04:10,720 --> 00:04:13,400 系统因该能够回答 结果是1/2 and the system should be able to say, yeah, that's 1/2. 72 00:04:16,100 --> 00:04:17,700 对吧? 你知道我想表达的意思 Right? And you know what I have in mind. 73 00:04:17,700 --> 00:04:20,240 我不太确定你们是多久掌握这些运算的 And you also know how to do this from, I don't know, 74 00:04:20,240 --> 00:04:21,480 五年级或者六年级吧? fifth grade or sixth grade. 75 00:04:21,900 --> 00:04:23,420 这里的一些公式说 There are these formulas that say 76 00:04:23,420 --> 00:04:28,020 如果有形式为分子除以分母的分数 if I have some fraction which is a numerator over a denominator, 77 00:04:28,200 --> 00:04:31,100 而如果我要将这个分数与另一个分数相加的话 and I want to add that to some other fraction 78 00:04:31,360 --> 00:04:34,600 当然 这个分数也是分子除以分母 which is another numerator over another denominator, 79 00:04:34,980 --> 00:04:38,380 那么结果将会是 第一个分数的分子 then the answer is the numerator of the first 80 00:04:39,020 --> 00:04:40,980 乘以第二个分数的分母 times the denominator of the second, 81 00:04:41,680 --> 00:04:46,300 加上第二个分数的分子乘以第一个分数的分母 plus the numerator of the second times the denominator of the first. 82 00:04:48,100 --> 00:04:49,380 当然 这只是答案的分子 That's the numerator of the answer, 83 00:04:49,380 --> 00:04:52,860 答案的分母是两个分数的分母之积 and the denominator is the product of the two denominators. 84 00:04:52,860 --> 00:04:57,040 对吧? 这大概就是五、六年级课程的分数算术 Right? So there's something from fifth or sixth grade fraction arithmetic. 85 00:04:57,040 --> 00:04:59,360 类似地 如果我想要将两个数乘起来 And then similarly, if I want to multiply two things, 86 00:04:59,360 --> 00:05:04,600 N1除以D1的商 乘以 N2除以D2的商 n1 over d1 multiplied by n2 over d2 87 00:05:05,460 --> 00:05:10,600 就是两个分数的分子之积除以两个分母之积的商 is the product of the numerators over the product of the denominators. 88 00:05:14,020 --> 00:05:15,160 所以这些都不构成问题 So it's no problem at all, 89 00:05:16,380 --> 00:05:17,860 当然 理解这些 but it's absolutely no problem to 90 00:05:18,420 --> 00:05:20,580 你想进行的分数运算 think about what computation you want to make 91 00:05:20,580 --> 00:05:22,480 是完全没问题的 in adding and multiplying these fractions. 92 00:05:23,460 --> 00:05:26,840 但是当我们实现这个功能的时候 我们似乎遗漏了什么 But as soon as we go to implement it, we run up across something. 93 00:05:27,560 --> 00:05:31,560 我们连有理数都没有 We don't have what a rational number is. 94 00:05:32,960 --> 00:05:38,220 系统只提供给我们了单个数字 比如5和3 so we said that the system gives us individuals number so we can have 5 and 3, 95 00:05:38,840 --> 00:05:42,700 但我们没法去表达 but somehow we don't have a way of 96 00:05:43,180 --> 00:05:46,820 一个同时具有3和4的东西 saying there's a thing that has both a 3 and a 4 in it, 97 00:05:47,380 --> 00:05:49,340 或者同时具有2和3的东西 or both a 2 and a 3. 98 00:05:49,340 --> 00:05:53,220 但只要我们去想象 It's almost as if we'd like to imagine 99 00:05:53,380 --> 00:05:55,640 我们就会看到一些云彩 that somehow there are these clouds, 100 00:05:57,280 --> 00:06:01,840 某个云彩不知咋的就有分子和分母 and a cloud somehow has both a numerator and a denominator in it, 101 00:06:02,060 --> 00:06:03,960 这就是我们想让拥有的功能 and that's what we'd like to work in terms of. 102 00:06:06,500 --> 00:06:07,980 那么 我们要怎么解决这个问题呢? Well, how are we going to solve that problem? 103 00:06:07,980 --> 00:06:13,100 我们将使用一种强大的设计策略来解决这个问题 We're going to solve that problem by using this incredibly powerful design strategy 104 00:06:13,520 --> 00:06:15,560 这种策略我们已经反复使用过了 that you've already seen us use over and over. 105 00:06:16,180 --> 00:06:18,160 这就是按愿望思维的策略 And that's the strategy of wishful thinking. 106 00:06:25,340 --> 00:06:27,340 假设现在还没有任何过程 Just like before when we didn't have a procedure, 107 00:06:27,340 --> 00:06:30,380 我们就想象确实存在着某个过程 we said, well, let's imagine that that procedure already exists. 108 00:06:30,980 --> 00:06:34,040 那么 我们就来想象我们有了这些(有理数)云彩吧 We'll say, well, let's imagine that we have these clouds. 109 00:06:35,720 --> 00:06:37,820 更准确一点来说 Now more precisely what I mean is 110 00:06:38,820 --> 00:06:43,180 让我们假设我们有了三个过程 let's imagine that we have three procedures, 111 00:06:43,960 --> 00:06:45,240 其一为MAKE-RAT one called MAKE-RAT. 112 00:06:47,340 --> 00:06:53,120 MAKE-RAT有两个参数 MAKE-RAT is going to take as arguments two numbers, 113 00:06:54,200 --> 00:06:55,820 我们分别把它们叫作分子和分母 so I'll call them numerator and denominator, 114 00:06:57,620 --> 00:07:03,400 它给我们返回一朵——我们需要的云彩 and it'll return for us a cloud-- one of these clouds. 115 00:07:04,860 --> 00:07:06,420 我并不知道云彩是什么 I don't really know what a cloud is. 116 00:07:06,660 --> 00:07:09,160 无论MAKE-RAT返回什么 那都是它的事 It's whatever MAKE-RAT returns, that's its business. 117 00:07:11,060 --> 00:07:11,960 并且我们会说 And then we're going to say, 118 00:07:12,080 --> 00:07:13,520 假设我们有了这样的一个云彩 suppose we've got one of these clouds, 119 00:07:13,780 --> 00:07:15,740 我们有个叫NUMER的过程 we have a procedure called NUMER, 120 00:07:16,720 --> 00:07:19,900 这个过程需要我们传递具有N和D的云彩 which takes in a cloud that has an n and a d in it, 121 00:07:19,920 --> 00:07:21,820 不管这个云彩是什么 我也不知道这个云彩是什么 whatever a cloud is, and I don't know what it is, 122 00:07:22,780 --> 00:07:24,440 但NUMER过程会返回(云彩的)分子部分 and returns for us the numerator part. 123 00:07:26,760 --> 00:07:28,900 我们也会假设我们有个叫DENOM的过程 And then we'll assume we have a procedure DENOM, 124 00:07:30,820 --> 00:07:33,560 该过程需要我们传递一个云彩 不管云彩是什么 which again takes in a cloud, whatever a cloud is, 125 00:07:34,880 --> 00:07:37,480 并返回(云彩的)分母部分 and returns for us the denominator part. 126 00:07:37,480 --> 00:07:42,480 就像之前我们构造平方根过程一样 This is just like before, when if we're building a square root, 127 00:07:42,560 --> 00:07:43,860 我们假设我们有GOOD-ENOUGH过程 we assume that we have good-enough. 128 00:07:45,020 --> 00:07:48,520 对吧? 我们会找到George 对他说 Right? And what we'll say is, we'll go find George, and we'll say to George, 129 00:07:48,700 --> 00:07:50,780 那么 你的任务就是实现这三个过程 well, it's your business to make us these procedures. 130 00:07:51,920 --> 00:07:54,440 你选择如何实现这些云彩 就是你的事了 And how you choose to implement these clouds, that's your problem. 131 00:07:54,660 --> 00:07:55,380 我们不想深究 We don't want to know. 132 00:07:58,500 --> 00:08:02,100 这样 把这些杂事都推给George后 Well, having pushed this task off onto George, 133 00:08:03,120 --> 00:08:05,080 完成其它部分就相当容易了 then it's pretty easy to do the other part. 134 00:08:05,080 --> 00:08:08,180 一旦我们有了这些云彩后 编写那些 Once we've got the clouds, it's pretty easy to write the thing 135 00:08:08,180 --> 00:08:10,500 把有理数加起来的程序就变得容易多了 that does say addition of rational numbers. 136 00:08:11,340 --> 00:08:17,980 你可以定义 这么说吧 定义+RAT You can just say define, well, let's say +RAT. 137 00:08:22,080 --> 00:08:27,660 定义+RAT过程 该过程需要两个有理数参数 X和Y Define +RAT, which will take in two rational numbers, x and y. 138 00:08:27,760 --> 00:08:30,340 X和Y就是这些云彩 x and y are each these clouds. 139 00:08:31,520 --> 00:08:32,460 这个过程干些啥呢? And what does it do? Well 140 00:08:32,760 --> 00:08:35,580 它将返回给我们一个有理数 it's going to return for us a rational number. 141 00:08:39,980 --> 00:08:41,340 这个有理数是怎么得来的呢? What rational number is it? Well, 142 00:08:41,880 --> 00:08:43,220 依据这里的公式 we've got the formulas there. 143 00:08:43,340 --> 00:08:45,760 答案的分子的一部分为 The numerator of it is the sum of 144 00:08:47,020 --> 00:08:56,340 X的分子与Y的分母之积 the product of the numerator of x and the denominator of y. 145 00:09:02,220 --> 00:09:03,360 这只是答案的分子的一部分 It's one thing in the sum. 146 00:09:03,600 --> 00:09:06,180 结果的分子剩下的一部分是 And the other thing in the numerator is 147 00:09:06,260 --> 00:09:16,960 Y的分子与X的分母之积 the product of the numerator of y and the denominator of x. 148 00:09:18,800 --> 00:09:20,080 闭合* 闭合+ The star, close the plus. 149 00:09:20,500 --> 00:09:23,380 好了 这是MAKE-RAT的第一个参数 Right, that's the first argument to MAKE-RAT, 150 00:09:23,380 --> 00:09:25,380 这是我将要构造的云彩的分子 which is the numerator of the thing I'm constructing. 151 00:09:26,220 --> 00:09:28,460 而MAKE-RAT剩下的参数 And then the rest of the thing goes into MAKE-RAT is 152 00:09:28,460 --> 00:09:30,340 则是答案的分母 the denominator of the answer, 153 00:09:30,380 --> 00:09:40,860 也就是X的分母乘以Y的分母 which is the product of the denominator of x and the denominator of y. 154 00:09:41,960 --> 00:09:42,600 像这样 Like that. 155 00:09:45,440 --> 00:09:51,320 好 这就是对有理数加法的一个模拟 OK? So there is the analog of doing rational number addition. 156 00:09:51,380 --> 00:09:54,780 在假设我们有了这些云彩后 就变得完全没有问题 And it's no problem at all, assuming that we have these clouds. 157 00:09:59,000 --> 00:10:02,060 当然 我们可以用同样的方法把它们乘起来 And of course, we can do multiplication in the same way. 158 00:10:05,240 --> 00:10:11,900 我们把将两个有理数乘起来定义为*RAT过程 Define how to get the product of two rational numbers, call it *RAT. 159 00:10:12,800 --> 00:10:16,140 该过程需要两朵云彩 X和Y Takes in two of these clouds, x and y, 160 00:10:19,540 --> 00:10:21,540 返回一个用MAKE-RAT构造的有理数 it returns a rational number, MAKE-RAT, 161 00:10:24,280 --> 00:10:27,460 这个有理数的分子是 whose numerator is the product of the numerators-- 162 00:10:30,040 --> 00:10:36,220 X的分子与Y的分子之积 numerator of x times the numerator of y. 163 00:10:37,820 --> 00:10:40,780 而这个有理数的分母则是 And the denominator of the thing it's going to return 164 00:10:41,200 --> 00:10:42,780 X的分母与Y的分母之积 is the product of the denominators. 165 00:10:57,120 --> 00:11:01,520 好了 现在就差告诉你这些云彩是什么了 Well, except that I haven't told you what these clouds are, 166 00:11:02,560 --> 00:11:04,860 所有操作都是围绕它展开的 看到我做了什么吗? that's all there is to it. See, what did I do? 167 00:11:04,960 --> 00:11:09,180 我按照我的愿望假设我有一种新的数据类型 I assumed by wishful thinking that I had a new kind of data object. 168 00:11:09,940 --> 00:11:15,100 特别地 我假设我有创建这些数据类型的能力 And in particular, I assumed I had ways of creating these data objects. 169 00:11:15,920 --> 00:11:17,780 这里的MAKE-RAT就创建了一个新的数据类型 MAKE-RAT creates one of these things. 170 00:11:17,780 --> 00:11:18,940 这叫作“构造函数” This is called a constructor. 171 00:11:25,300 --> 00:11:28,980 我现在有了可以构造这些数据类型的东西了 All right, I have a thing that constructs such data objects. 172 00:11:29,380 --> 00:11:34,200 然后我假设我有某些东西 有了这些东西后 And then I assume I have things that, having made these things, 173 00:11:34,200 --> 00:11:37,680 我就有从中抽取部分信息的方法了 这些叫作“选择函数” I have ways of getting the parts out. Those are called selectors. 174 00:11:42,460 --> 00:11:44,540 说得更正式一点 就是说 And so formally, what I said is I assumed 175 00:11:44,540 --> 00:11:48,660 我假设有了用于处理这些数据类型的构造函数和选择函数 I had procedures that are constructors and selectors for these data objects, 176 00:11:48,660 --> 00:11:49,940 我就可以靠它们来编程了 and then I went off and used them. 177 00:11:51,700 --> 00:11:55,580 这就好比我说假设我有GOOD-ENOUGH?过程 That's no different in kind from saying I assume I have a procedure GOOD-ENOUGH?, 178 00:11:56,000 --> 00:11:57,800 并用它来实现平方根这种做法 and I go use it to implement square root. 179 00:12:00,420 --> 00:12:01,840 好 在我们继续之前 OK, well before we go on, 180 00:12:04,520 --> 00:12:08,020 让我们来想想 为什么我们首先就在这个地方实现了这些东西? let's ask the question of why do we want to do this in the first place? 181 00:12:08,360 --> 00:12:12,200 为什么我们需要一个像+RAT这样的过程 See, why do we want a procedure like, like +RAT 182 00:12:13,260 --> 00:12:19,280 一个需要两个有理数作为参数并返回一个有理数的过程 that takes in two rational numbers and returns a rational number? 183 00:12:19,960 --> 00:12:22,620 换一种想法就是 我们实现的是这里的这个公式 See, another way to think about this is, well, here's this formula. 184 00:12:24,780 --> 00:12:28,760 这里我也实现了用于加和两个有理数的东西 And I've also got to implement something that adds rational numbers. 185 00:12:29,520 --> 00:12:31,680 再换一种想法就是 这有这么一个东西 One other way to think about is, well, there's this thing, 186 00:12:31,860 --> 00:12:35,660 可以让我输入四个数 N1 D1 N2 D2 and I type in four numbers, an n1, and a d1, and an n2, and a d2. 187 00:12:36,240 --> 00:12:38,020 然后这个东西就修改机器里的寄存器 And it sets some registers in the machine 188 00:12:38,300 --> 00:12:42,120 来代表分子和分母 to a, this numerator and this denominator. 189 00:12:42,120 --> 00:12:42,920 所以你大概会问 So I might say, well, 190 00:12:43,020 --> 00:12:45,600 你为什么不用四个分别代表分子和分母的数 why don't I just add rational numbers by I type in four numbers, 191 00:12:45,740 --> 00:12:46,880 来做有理数加法 numerators and denominators, 192 00:12:46,880 --> 00:12:49,340 这个加法返回两个数 分别代表分子和分母 and get out two numbers, which is a numerator and a denominator. 193 00:12:50,480 --> 00:12:54,840 我们为什么要像这样构造“云彩”? Why are we worrying about building things like this anyway? 194 00:12:58,380 --> 00:12:59,700 呃 那是因为 Well, the answer is, 195 00:12:59,820 --> 00:13:05,720 假设你想表达像这样的东西 suppose you want to think about expressing something like this, 196 00:13:05,780 --> 00:13:11,740 假设我想表达让两个有理数 suppose I'd like to express the idea of taking two rational numbers, 197 00:13:12,980 --> 00:13:21,340 X加Y的和 乘以 另外两个有理数S、T的和 x plus y, say, and multiplying that by the sum of two other rational numbers. 198 00:13:23,300 --> 00:13:27,380 然而 当我有了像+RAT和*RAT这样的东西后 Well, the way I do it, having things like +RAT and *RAT, 199 00:13:28,200 --> 00:13:33,520 我就会将其考虑为乘积 is I'd say, oh yeah, what that is is just the product. 200 00:13:33,600 --> 00:13:49,060 就是将*RAT应用于X和Y的和以及S和T的和上 That's *RAT of the sum of x and y and the sum of s and t. 201 00:13:51,260 --> 00:13:55,320 我就得到了一个表达式 如果不考虑语法的话 So except for syntax, I get an expression 202 00:13:55,620 --> 00:13:59,200 这个表达式看起来像是按照数学思想表达的 that looks like the way I want to think about it mathematically. 203 00:13:59,540 --> 00:14:03,420 我说这有两个数 这个东西代表了这两个数的和 I want to say there are two numbers. There's a thing which is the sum of them, 204 00:14:05,300 --> 00:14:07,360 然而这个东西又代表了另两个数的和 and there's a thing which is the sum of these two. 205 00:14:08,000 --> 00:14:10,440 就是这个和这个 That's this and this. 206 00:14:10,440 --> 00:14:11,700 然后我把它们乘起来 And then I multiply them. 207 00:14:12,200 --> 00:14:14,200 所以我有了一个和这里的表达式相匹配的表达式 So I get an expression that matches this expression. 208 00:14:14,200 --> 00:14:16,680 而如果我用其它的方式去表达 我说 If I did the other thing, if I said, well, 209 00:14:16,680 --> 00:14:20,160 我向机器传递四个数 the way I want to think about this is I type into my machine four numbers, 210 00:14:20,320 --> 00:14:22,860 四个分别代表X和Y的分子、分母的数 which are the numerators and the denominators of x and y, 211 00:14:23,800 --> 00:14:28,000 然后又是四个分别代表S和T的分子、分母的数 and then four more numbers, which are the numerators and denominators of s and t. 212 00:14:28,780 --> 00:14:30,780 我现在又该干什么呢? And then what I'd be sitting with is, well, what would I do? 213 00:14:31,000 --> 00:14:34,560 我把这些加起来 然后我们就得到了两个临时变量 I'd add these, and somehow I'd have to have two temporary variables, 214 00:14:35,240 --> 00:14:37,440 分别代表了和的分子、分母 which are the numerators and denominators of this sum, 215 00:14:37,960 --> 00:14:39,600 我又得去找个地方把它们存储起来 and I'd go off and store them someplace. 216 00:14:42,140 --> 00:14:44,200 然后到了这里 我又传入了四个数 And then I'd go over here, I'd type in four more numbers, 217 00:14:44,200 --> 00:14:45,960 我得到了两个临时变量 I'd get two more temporary variables, 218 00:14:46,480 --> 00:14:48,720 分别代表了S和T之和的分子和分母 which are the numerators and denominators of s and t. 219 00:14:49,820 --> 00:14:52,860 最后 我通过把它们乘起来来将其结合在一起 And then finally, I put those together by multiplying them. 220 00:14:54,620 --> 00:14:56,120 如你所见 麻烦出来了 You see, what's starting to happen, 221 00:14:56,140 --> 00:14:57,700 这里满是临时变量 there are all these temporary variables, 222 00:14:58,180 --> 00:15:02,780 这些应该是这些有理数内部的“内脏”吧 which are sort of the guts of the internals of these rational numbers 223 00:15:02,780 --> 00:15:04,900 但却显露在我们的系统中 that start hanging out all over the system. 224 00:15:05,860 --> 00:15:08,240 当然 随着表达式变得越来越复杂 And of course, if I had more and more complicated expressions, 225 00:15:08,240 --> 00:15:11,500 这些“内脏”就会显露得越来越多 使我编程时感到困惑 there'd be more and more guts hanging out that confuse my programming. 226 00:15:12,620 --> 00:15:15,540 像这样写程序的人 And those of you who sort of programmed things like that, 227 00:15:15,540 --> 00:15:18,140 你只是在用汇编语言的思想来加和两数 where you're just adding numbers in assembly language, 228 00:15:18,140 --> 00:15:21,060 你也发现 你突然之间需要关注这些临时变量了 you sort of see you have to suddenly be concerned with these temporary variables. 229 00:15:22,680 --> 00:15:29,200 而这些对我大脑造成的困惑 要比对编程造成的困惑更严重 But more importantly than confusing my programming, they're going to confuse my mind. 230 00:15:29,620 --> 00:15:31,480 而编程的本质就是 Because the whole name of this game 231 00:15:33,140 --> 00:15:35,420 我们希望程序设计语言能够表达 is that we'd like the programming language 232 00:15:36,820 --> 00:15:39,100 我们脑中的概念 to express the concepts that we have in our heads, 233 00:15:39,320 --> 00:15:41,780 有理数就是这些概念 like rational numbers are things that you can add 234 00:15:42,620 --> 00:15:44,540 我们可以先把它们加起来然后再乘起来 and then take that result and multiply them. 235 00:15:48,360 --> 00:15:49,300 有疑问吗? Let's break for questions. 236 00:15:57,380 --> 00:15:57,780 恩 Yeah? 237 00:15:59,680 --> 00:16:01,480 学生:我不太明白为什么 AUDIENCE: Ya, I don't quite see the need- 238 00:16:01,480 --> 00:16:04,140 我们既然有MAKE-RAT过程了 when we had MAKE-RAT with the numerator and denominator, 239 00:16:04,140 --> 00:16:08,440 我们传递两个参数作为分子和分母来构造一朵云彩 we had to have the numerator and denominator to pass as parameters to create the cloud, 240 00:16:08,440 --> 00:16:11,040 但最后我们又从中将这些东西原原本本地给抽取出来 and then we extracted to get back what we had to have originally. 241 00:16:11,360 --> 00:16:11,980 教授:是这样的 PROFESSOR: That's right. 242 00:16:13,380 --> 00:16:16,600 我们的问题是 既然我们是用分子和分母构造云彩 So the question is, I sort of have the numerator and the denominator, 243 00:16:17,080 --> 00:16:21,720 但我为什么又想从云彩里面把它们取出来呢? why am I worrying about having the cloud given that I have to get the pieces out? 244 00:16:23,280 --> 00:16:26,640 这个是我在后面提到过的 不过让先说下吧 That's sort of what I tried to say at the end, but let me try and say it again, 245 00:16:26,640 --> 00:16:28,040 这个问题非常关键 because that's really the crucial question. 246 00:16:29,260 --> 00:16:32,980 关键点就是 我想让分子和分母 The point is, I want to carry this numerator and denominator around 247 00:16:34,100 --> 00:16:35,220 总是在绑一起 together all the time. 248 00:16:36,840 --> 00:16:38,740 我完完全全知道 And it's almost as if I want to know, 249 00:16:38,740 --> 00:16:40,640 这里面有分子和分母 yeah, there's a numerator and denominator in there, 250 00:16:40,640 --> 00:16:44,940 同样的 我也想表达 but also, I would like to say, fine, 251 00:16:45,400 --> 00:16:48,640 但是 从另一个角度来看 这就是X but from another point of view, that's x. 252 00:16:49,860 --> 00:16:52,460 我可以取用X 我给它命名为X 我就可以控制它了 And I carry x around, and I name it as x, and I hold it. 253 00:16:52,680 --> 00:16:55,160 然后我就可以说 X加上Y的和 And I can say things like, the sum of x and y, 254 00:16:55,800 --> 00:16:58,540 我只考虑一个X的时候 使用两个数来代表分子、分母并无大碍 rather than just have-- see, it's not so bad when I only think about x, 255 00:16:59,260 --> 00:17:01,300 但是当我有10个有理数时 but if I have a system with 10 rational numbers, 256 00:17:01,600 --> 00:17:03,500 如果我不把它们联系起来 suddenly I have 20 numerators and denominators, 257 00:17:03,920 --> 00:17:06,220 我一下子就有了20个不必要的分子和分母 which are not necessarily-- if I don't link them, 258 00:17:06,220 --> 00:17:09,900 它们只是20个没有以一种特定方式联系起来的任意数而已 then it's just 20 arbitrary numbers that are not linked in any particular way. 259 00:17:10,080 --> 00:17:13,100 这就像是说 It's a lot like saying, well, 260 00:17:13,100 --> 00:17:15,260 我要把这些过程体的指令 I have these instructions that are the body of the procedures, 261 00:17:15,260 --> 00:17:17,220 把它们封装起来作为一个过程 why do I want to package them and say it's the procedure? 262 00:17:17,620 --> 00:17:18,820 这是一码子事儿 It's exactly the same idea. 263 00:17:30,800 --> 00:17:34,100 没问题了 好吧 No more? OK. 264 00:17:34,560 --> 00:17:36,460 那休息一下 活动一下吧 [听不清] Let's break, let's just stretch and get somebody-- [INAUDIBLE] 265 00:17:37,880 --> 00:17:43,240 [音乐] [JESU, JOY OF MAN'S DESIRING] 266 00:17:45,380 --> 00:17:50,320 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 267 00:17:50,580 --> 00:17:55,440 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 268 00:18:09,000 --> 00:18:16,680 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 269 00:18:18,800 --> 00:18:22,020 复合数据 Compound Data 270 00:18:26,700 --> 00:18:30,460 好吧 回到我们的有理数算术系统来 OK, well, we've been working on this rational number arithmetic system, 271 00:18:31,700 --> 00:18:35,240 而我们做的 最重要的是 and then what we did, the important thing about what we did, 272 00:18:35,320 --> 00:18:38,300 我们我们把这个问题分解为了两部分 is we thought about the problem by breaking it into two pieces. 273 00:18:39,780 --> 00:18:42,460 我们假设跟George“订好契约” We said, assume there is this contract with George, 274 00:18:43,040 --> 00:18:46,320 George已经给出了如何去构造这些云彩 and George has figured out the way to how to construct these clouds, 275 00:18:47,640 --> 00:18:51,260 他向我们提供了一个作为构造函数的MAKE-RAT过程 provided us procedures MAKE-RAT, which was a constructor, 276 00:18:51,740 --> 00:18:54,600 相应的 用于提取分子和分母的选择函数 and selectors, which are numerator and denominator. 277 00:18:54,660 --> 00:18:55,460 然后 我们用这些东西 And then in terms of that, 278 00:18:55,460 --> 00:18:59,060 我们实现了有理数的加法和乘法 we went off and implemented addition and multiplication of rational numbers. 279 00:19:00,220 --> 00:19:02,420 好了 我们来看看George面临的问题吧 Well, now let's go look at George's problem. 280 00:19:03,100 --> 00:19:07,200 我们如何来把分子和分母给封装起来 How can we go and package together a numerator and a denominator 281 00:19:07,200 --> 00:19:08,540 并把它们放在“云彩”里 and actually make one of these clouds? 282 00:19:09,020 --> 00:19:11,160 我们需要的是一种胶水 See, what we need is a kind of glue, 283 00:19:12,440 --> 00:19:16,940 一种可以让我们把数据结合在一起的胶水 kind of a glue that, a glue for data objects that allows us to put things together. 284 00:19:17,740 --> 00:19:20,460 幸而Lisp提供了这样的胶水 And Lisp provides such a glue, 285 00:19:21,680 --> 00:19:24,160 我们把它叫作“表结构” and that glue is called list structure. 286 00:19:30,000 --> 00:19:33,060 表结构是一种将数据粘合在一起的工具 List structure is a way of gluing things together, 287 00:19:35,200 --> 00:19:36,080 说得更准确一点 and more precisely, 288 00:19:36,280 --> 00:19:41,260 就是Lisp提供了一种构造序对的方法 Lisp provides a way of constructing things called pairs. 289 00:19:44,660 --> 00:19:50,800 Lisp里面有一个叫CONS的基本过程 There's a primitive operator in Lisp called CONS. 290 00:19:52,120 --> 00:19:53,140 让我们来看一下 We can take a look at it. 291 00:19:54,900 --> 00:19:56,940 这个就是CONS There's a thing called CONS. 292 00:19:59,620 --> 00:20:04,160 CONS是一个运算符 它需要两个参数X和Y Cons is an operator which takes in two arguments called x and y, 293 00:20:06,180 --> 00:20:08,400 它返回给我们一种叫作“序对”的东西 and it returns for us a thing called a pair. 294 00:20:11,220 --> 00:20:17,760 而所谓的“序对” 就是具有“首部分”和“次部分” All right, so a thing called a pair that has a first part a second part. 295 00:20:21,540 --> 00:20:23,120 这也解释了为什么CONS需要两个参数 So CONS takes two objects. 296 00:20:25,080 --> 00:20:26,140 如果我们有一个序对的话 There's a thing called a pair. 297 00:20:26,460 --> 00:20:31,140 X就是首部分 而Y就是次部分 The first part of the cons is X, and the second part of the cons is Y. 298 00:20:31,140 --> 00:20:32,120 这就是它的构造方式 And that's what it builds. 299 00:20:33,760 --> 00:20:36,220 我们同样也有把东西取出来的方法 And then we also assume we have ways of getting things out. 300 00:20:36,520 --> 00:20:38,880 给定一个序对 我们有一个叫CAR的东西 If you're given a pair, there's a thing called CAR, 301 00:20:41,600 --> 00:20:45,240 使得 序对P的CAR就是序对P的首部分 and car of a pair, P, gives you out the first part of the pair, P. 302 00:20:46,320 --> 00:20:47,280 也有一个叫CDR的东西 And there's a thing called CDR, 303 00:20:47,780 --> 00:20:51,620 使得序对P的CDR 就是序对P的次部分 and CDR of the pair, P, gives you the second part of the pair, p. 304 00:20:54,440 --> 00:20:56,020 这些就是我们构造数据的方法 OK, so that's how we construct things. 305 00:20:56,460 --> 00:21:01,900 在将这些数据用图画表示时 我们也有一种俗成的方法 There's also a conventional way of drawing pictures of these things. 306 00:21:02,480 --> 00:21:11,260 这类似于我们用俗成的方法书写柏拉图概念下的2 Just like we write down that as the conventional way of writing Plato's idea of two, 307 00:21:13,440 --> 00:21:20,920 我们像这样画个图来表示 (CONS 2 3) the way we could draw a diagram to represent cons of two and three is like this. 308 00:21:21,600 --> 00:21:22,580 先画个小盒子 We draw a little box. 309 00:21:23,860 --> 00:21:25,600 这个就是我们讨论的(序对) And so here's the box we're talking about, 310 00:21:26,300 --> 00:21:28,320 盒子“放出”两个箭头 and this box has two arrows coming out of it. 311 00:21:29,620 --> 00:21:34,560 我们说 这个序对的首部分是2 And say the first part of this pair is 2, 312 00:21:34,800 --> 00:21:36,520 而这个序对的次部分是3 and the second part of this pair is 3. 313 00:21:37,920 --> 00:21:44,960 这种记法叫作“盒子—指针”记法 And this notation has a name, it's called box and pointer notation. 314 00:21:55,220 --> 00:21:56,940 顺带一提 我现在就来说说 Ok, By the way, let me say right now 315 00:21:57,140 --> 00:21:58,400 困惑了很多人的一点 that a lot of people get confused 316 00:21:58,400 --> 00:22:03,240 我画这些指针时 重要的仅仅是指针的指向 that there's some significance to the geometric way I drew these pointers, the directions. 317 00:22:03,240 --> 00:22:05,960 一些人可能会认为 如果我这样画箭头 Like some people think it'd be different if I took this pointer 318 00:22:05,960 --> 00:22:08,360 并把3放在这里 结果会不一样 and turned it up here, and put the 3 out here. 319 00:22:08,360 --> 00:22:10,660 这实际上是没区别的 能理解吗? That has no significance. Right? 320 00:22:11,200 --> 00:22:14,700 只不过是在这一大堆的箭头、指针和盒子中 It's merely you have a bunch of arrows, these pointers, and the boxes. 321 00:22:14,700 --> 00:22:16,840 唯一的区别就在于它们是如何联接的 The only issue is how they're connected, 322 00:22:16,840 --> 00:22:21,300 而不是我把它们怎么放置 譬如向上放 向下放 或者交叉放 not the geometric arrangement of whether I write the pointer across, or up, or down. 323 00:22:23,220 --> 00:22:24,720 关于它们为什么叫做表结构 Now it's completely un-obvious, 324 00:22:25,720 --> 00:22:27,680 或许现在就完全不清楚了 probably, why that's called list structure. 325 00:22:28,500 --> 00:22:31,560 我们今天不会讨论这个问题 我们下次再讨论吧 We're not actually going to talk about that today. We'll see that next time. 326 00:22:37,620 --> 00:22:40,920 所以 我们可以用CONS构造序对 So those are pairs, there's CONS that constructs them. 327 00:22:41,480 --> 00:22:44,920 我准确地知道CONS、CAR和CDR的行为是 And what I'm going to know about CONS, and CAR, and CDR, 328 00:22:45,260 --> 00:22:49,320 如果我有任意的X和Y is precisely that if I have any X and Y, 329 00:22:50,240 --> 00:22:52,280 对任意的X和Y right, if I have any things X and Y, 330 00:22:53,680 --> 00:22:55,980 我可以用CONS来构造一个序对 and I use CONS to construct a pair, 331 00:22:59,000 --> 00:23:03,140 那么该序对的CAR就是X 就是我的构造时的一个输入 then the CAR of that pair is going to be X, the thing I put in, 332 00:23:03,600 --> 00:23:05,700 而该序对的CDR就是Y and the CDR of that pair is going to be Y. 333 00:23:07,260 --> 00:23:10,660 这就是CONS、CAR、CDR这些运算符的行为 That's the behavior of these operators, CONS, CAR, and CDR. 334 00:23:12,020 --> 00:23:15,740 有了这些东西 George构造有理数就明了多了 Given them, it's pretty clear how George can go off and construct his rational numbers. 335 00:23:17,200 --> 00:23:18,480 言归正传 George要—— After all, all he has to do-- 336 00:23:19,000 --> 00:23:22,720 记得吗 George的任务是实现MAKE-RAT、NUMER、DENOM过程 remember George's problem was to implement MAKE-RAT, numerator, and denom. 337 00:23:23,020 --> 00:23:36,180 George这样编写代码 (DEFINE (MAKE-RAT N D) So all George has to do is say define MAKE-RAT of some N and a D-- 338 00:23:36,640 --> 00:23:38,640 就是将CONS应用于这二者 Well, all I have to do is CONS them. 339 00:23:40,580 --> 00:23:42,520 也就是(CONS N D) That's CONS of N and D. 340 00:23:45,220 --> 00:23:46,900 而如果我想取出分子 And then if I want to get the numerator out, 341 00:23:47,440 --> 00:23:59,140 代码我这样写 (DEFINE (NUMER X) I would say define the numerator, numer, of some rational number, X. 342 00:23:59,960 --> 00:24:02,000 如果我们是用序对来实现有理数的话 If the rational number's implemented as a pair, 343 00:24:02,440 --> 00:24:04,320 我只需要用CAR来获得X的首部分 then all I have to do is get out the CAR of X. 344 00:24:06,240 --> 00:24:18,860 类似的 DENOM就是用CDR运算符了 And then similarly, define the denom is going to be the cdr, 345 00:24:19,020 --> 00:24:21,000 也就是我用于构造序对的另一个数据 the other thing I put into the pair. 346 00:24:26,700 --> 00:24:27,640 我们现在就是在干这件事 Well, now we're in business. 347 00:24:28,400 --> 00:24:32,860 这就是有理数的一种实现 That's a complete implementation of rational numbers. 348 00:24:33,460 --> 00:24:34,900 我们来实践一下 假设我想要 Let's use it. Suppose I want to say, 349 00:24:35,780 --> 00:24:43,080 我想要求取1/2加上1/4 并观察系统是怎么运作的 so I want to think about how to add 1/2 plus 1/4 and watch the system work. 350 00:24:43,080 --> 00:24:50,340 那么 我或许会定义一个A Well, the way I'd use that is I'd say, well, maybe define A. 351 00:24:50,380 --> 00:24:51,760 我需要构造一个1/2 I have to make a 1/2. 352 00:24:52,760 --> 00:24:56,780 也就是一个分子为1 分母为2的有理数 Well, that's a rational number with numerator 1 and denominator 2, 353 00:24:59,320 --> 00:25:02,540 也就是 A为(MAKE-RAT 1 2) so a will be MAKE-RAT of 1 and 2. 354 00:25:05,280 --> 00:25:07,160 然后我来构造1/4 And then I'll construct the 1/4. 355 00:25:07,260 --> 00:25:20,220 我定义B为(MAKE-RAT 1 4) I'll say define B to be MAKE-RAT of 1 and 4. 356 00:25:23,360 --> 00:25:24,860 如果我想解得答案的话 And if I'd like to look at the answer-- 357 00:25:25,060 --> 00:25:28,100 先假设我们没有一个专门用于打印有理数的东西 well, assuming I don't have a special thing that prints rational numbers, 358 00:25:28,100 --> 00:25:29,020 我可以自己编写一个 or I could make one-- 359 00:25:29,740 --> 00:25:31,380 比如说 我可以这样写 I could say, for instance, 360 00:25:31,380 --> 00:25:43,740 定义答案为(+RAT A B) define the answer to be +RAT of A and B, 361 00:25:45,980 --> 00:25:47,100 那么我就可以问 答案是多少? and now I can say, what's the answer? 362 00:25:47,100 --> 00:25:50,120 答案的分子和分母分别是多少? What are the numerators and denominators of the answer? 363 00:25:50,640 --> 00:26:00,280 因此 我把1/2和1/4加起来后 我会问 答案的分子是多少? So if I'm adding 1/2 and 1/4, I'll say, what is the numerator of the answer? 364 00:26:03,880 --> 00:26:10,260 系统就就会打印出 6 And the system is going to type out, well, 6. 365 00:26:10,560 --> 00:26:11,240 糟糕了 Bad news. 366 00:26:12,860 --> 00:26:14,960 而如果我问答案的分母是多少 And if I say what's the denominator of the answer, 367 00:26:22,340 --> 00:26:24,480 系统就就会打印出8 the system's going to type out 8. 368 00:26:26,100 --> 00:26:28,740 我们本来希望能得到 So instead of what I would really like, 369 00:26:29,560 --> 00:26:32,380 1/2加1/4是3/4 which is for it to say that 1/2 and 1/4 is 3/4, 370 00:26:35,200 --> 00:26:38,340 但这台愚蠢的机器却说 不 应该是6/8 this foolish machine is going to say, no, it's 6/8. 371 00:26:40,100 --> 00:26:41,480 恩 这的确有点糟糕 Well, that's sort of bad news. 372 00:26:43,040 --> 00:26:43,880 问题在哪里呢? Where's the bug? 373 00:26:46,940 --> 00:26:48,400 是什么导致的呢? Why does it do that, after all? 374 00:26:48,400 --> 00:26:51,040 问题出在+RAT上 Well, it's the way that we just had +RAT. 375 00:26:51,040 --> 00:26:56,620 +RAT只是把A的分子和B分母之积与 +RAT just took the-- it said you add the numerator times the denominator, 376 00:26:57,860 --> 00:27:00,100 B的分子和A的分母之积加在一起 you add that to the numerator times the denominator, 377 00:27:00,440 --> 00:27:02,420 并把它们除以两分母之积 and put that over the product of the two denominators, 378 00:27:02,420 --> 00:27:03,580 这就是为什么得到6/8的原因 and that's why you get 6/8. 379 00:27:05,560 --> 00:27:09,680 那么 我们的+RAT实现有什么问题呢? So what was wrong with our implementation of +RAT? 380 00:27:10,260 --> 00:27:13,720 我们在此之前所做的有理数算术又有什么错误呢? What's wrong with that rational number arithmetic stuff that we did before the break? 381 00:27:15,500 --> 00:27:17,940 当然 从一方面来看 这一点都没有错 Well, the answer is one way to look at it is absolutely nothing's wrong. 382 00:27:19,360 --> 00:27:21,120 这其实是一个相当好的实现 That's perfectly good implementation. 383 00:27:21,120 --> 00:27:26,900 这个实现完完全全遵守了分数加法法则 It follows the sixth grade, fifth grade mathematic for adding fractions. 384 00:27:29,620 --> 00:27:31,820 我们可以这样说 这就是George的问题了 One thing we can say is, well, that's George's problem. 385 00:27:32,980 --> 00:27:37,560 如果George只是简单地通过把分子和分母放在一起 Like, boy, wasn't George dumb to say that he can make a rational number 386 00:27:37,800 --> 00:27:40,780 来构造有理数的话 岂不是站不住脚? simply by sticking together the numerator and the denominator? 387 00:27:42,480 --> 00:27:46,460 在构造有理数时 如果George把这些东西化到最简 Wouldn't it be better for George, when he made a rational number, 388 00:27:47,640 --> 00:27:49,240 难道不是会跟好一点吗? to reduce the stuff to lowest terms? 389 00:27:51,080 --> 00:27:55,540 我想说的是 对George来说 And what I mean is, wouldn't it be better for George, 390 00:27:55,540 --> 00:28:01,800 用这个版本的MAKE-RAT 难道会比幻灯片上的这个好么? instead of using this version of MAKE-RAT, to use this one on the slide? 391 00:28:03,160 --> 00:28:06,660 不是简单地通过CONS 把N和D结合起来 Or instead of just saying CONS together N and D, 392 00:28:07,240 --> 00:28:11,680 我们先寻找N和D的最大公约数 what you do is compute the greatest common divisor of N and D, 393 00:28:12,420 --> 00:28:14,000 我们用GCD过程来找 and GCD is the procedure which, 394 00:28:14,700 --> 00:28:16,040 我们只需知道GCD是一个基本过程 well, for all we care is a primitive, 395 00:28:16,040 --> 00:28:18,520 它返回的是两个数的最大公约数 which computes the greatest common divisor of two numbers. 396 00:28:20,700 --> 00:28:22,900 因此 这种构造有理数的方法就是 So the way I can construct a rational number is 397 00:28:24,160 --> 00:28:26,520 先找到两数的最大公约数 get the greatest common divisor of the two numbers, 398 00:28:26,520 --> 00:28:27,580 先用G来表示吧 and I'm going to call that G, 399 00:28:29,920 --> 00:28:33,720 不是简单通过CONS结合N、D 而是先让它们除以G and then instead of consing together N and D, I'll divide them through. 400 00:28:33,720 --> 00:28:38,940 然后我再用CONS结合N/G和D/G的商 I'll CONS together the quotient of N by the the GCD and the quotient of D by the GCD. 401 00:28:40,400 --> 00:28:42,600 这样就把我们的有理数化到了最简 And that will reduce the rational number to lowest terms. 402 00:28:43,740 --> 00:28:53,600 因此 当我在做加法时 当+RAT调用MAKE-RAT过程时 So that when, when I do this addition, when +RAT calls MAKE-RAT-- 403 00:28:53,980 --> 00:28:56,320 +RAT的定义里面有对MAKE-RAT的调用 and for the definition of +RAT it had a MAKE-RAT in there-- 404 00:28:57,400 --> 00:28:59,240 因此 当+RAT构造有理数时 just by the fact that it's constructing that, 405 00:28:59,240 --> 00:29:01,440 MAKE-RAT就自动将其化为最简了 the thing will get reduced to lowest terms automatically. 406 00:29:08,780 --> 00:29:13,460 好了 这就是一个完整的系统 OK, that is a complete system. 407 00:29:14,640 --> 00:29:16,900 让我们来看看我们完成的这个有理数算术系统吧 For rational number arithmetic, let's look at what we've done. 408 00:29:19,240 --> 00:29:22,480 好吧 我们说过我们想要构造一个有理数算术系统 All right, we said we want to build rational number arithmetic, 409 00:29:25,220 --> 00:29:27,920 我们实现了+RAT and we had a thing called +RAT. We implemented that. 410 00:29:29,620 --> 00:29:33,200 我也给你们展示了*RAT的实现 And I showed you multiplying rational numbers, and 411 00:29:34,100 --> 00:29:35,200 虽然我并没有去实现-RAT although I didn't put them up there, 412 00:29:35,200 --> 00:29:38,280 就姑且假设我们实现了-RAT吧 presumably we'd like to have something that subtracts rational numbers, 413 00:29:38,960 --> 00:29:40,500 事实上有些东西我并不知道 and I don't know, all sorts of things. 414 00:29:40,500 --> 00:29:42,220 比如通过除法来判断相等 Things that test equality in division, 415 00:29:42,220 --> 00:29:45,140 或者用某种特定方式打印有理数的函数 and maybe things that print rational numbers in some particular way. 416 00:29:45,820 --> 00:29:49,960 我们用序对的方式实现了它们 And we implemented those in terms of pairs. 417 00:29:52,440 --> 00:29:54,600 序对、CONS、CAR和CDR 这些都是内建于Lisp中的 These pairs, CONS, CAR, and CDR that are built into Lisp. 418 00:29:55,560 --> 00:30:03,840 而两者之间最重要的则是 这个和这个 But the important thing is that between these and these, 419 00:30:04,680 --> 00:30:09,240 我们在其间构筑了一道抽象屏障 一个抽象层 we set up an abstraction barrier. We set up a layer of abstraction. 420 00:30:16,960 --> 00:30:18,640 那么 “抽象层”又是什么呢? And what was that layer of abstraction? 421 00:30:18,640 --> 00:30:22,340 准确的说 构造函数和选择函数就是抽象层 That layer of abstraction was precisely the constructor and the selectors. 422 00:30:25,420 --> 00:30:34,360 MAKE-RAT、NUMER、DENOM就是抽象层 This layer was MAKE-RAT, and NUMER, and DENOM. 423 00:30:38,620 --> 00:30:42,920 这种方法学 也就是我们的做法 This methodology, another way to say what it's doing, 424 00:30:43,120 --> 00:30:51,000 就是“分离” 分离对象的使用方法 is that we are separating, we are separating the way something is used, 425 00:30:53,240 --> 00:30:55,000 我们把数据对象的使用 separating the use of data objects, 426 00:30:56,140 --> 00:30:59,040 和它们的表示分离开来 from the representation of data objects. 427 00:31:07,060 --> 00:31:12,040 就目前来说 我们有了使用有理数做计算的方法 So up here, we have the way that rational numbers are used, do arithmetic on them. 428 00:31:12,220 --> 00:31:14,760 在这儿 我们有它们表示的方法 Down here, we have the way that they're represented, 429 00:31:14,760 --> 00:31:16,300 它们通过这条边界分隔开 and they're separated by this boundary. 430 00:31:17,480 --> 00:31:19,500 这条边界就是构造函数和选择函数 The boundary is the constructors and selectors. 431 00:31:23,440 --> 00:31:25,420 这种方法学有个名字 And this methodology has a name. 432 00:31:25,420 --> 00:31:26,960 叫做数据抽象 This is called data abstraction. 433 00:31:35,880 --> 00:31:39,760 数据抽象是一种通过假定的构造函数和选择函数将数据对象 Data abstraction is sort of the programming methodology of setting up data objects 434 00:31:39,760 --> 00:31:44,080 与它的表示分隔开来的编程方法学 by postulating constructors and selectors to isolate use from representation. 435 00:31:47,140 --> 00:31:50,420 我们也完全可以不这样做 这又有什么干系呢? Well, so what? I mean, after all, we didn't have to do it this way. 436 00:31:51,580 --> 00:31:55,000 当然就算不用任何复合对象 It's perfectly possible to do rational number addition 437 00:31:55,000 --> 00:31:56,800 做有理数加法也是完全可行的 without having any compound data objects, 438 00:31:56,800 --> 00:31:59,560 幻灯片上就是一个例子 and here on the slide is one example. 439 00:31:59,560 --> 00:32:02,620 我们当然可以这样定义+RAT We certainly could have defined +RAT, 440 00:32:02,820 --> 00:32:05,920 它需要两个参数X和Y which takes in things x and y, 441 00:32:05,920 --> 00:32:08,940 而我们会问 这些有理数到底是什么呢? and we'll say, well what are these rational numbers really? 442 00:32:09,380 --> 00:32:11,160 实质上 它们只是序对 So really, they're just pairs, 443 00:32:11,680 --> 00:32:13,960 分子是序对的CAR部分 分母是CDR部分 and the numerator's the car and the denominator's the cdr. 444 00:32:14,180 --> 00:32:18,800 我们要做的 就是取出X的CAR部分乘以Y的CDR部分 So what we'll do is we'll take the car of x times the cdr of y, 445 00:32:21,920 --> 00:32:22,760 并把它们乘起来 multiply them. 446 00:32:23,020 --> 00:32:26,600 取出Y的CAR部分和CDR部分相乘 再与之前的结果相加 Take the car of y times the cdr of x, multiply them.Add them. 447 00:32:28,340 --> 00:32:31,080 取出X的CDR部分乘以Y的CDR部分 Take the cdr of x and the cdr of y, multiply them, 448 00:32:31,300 --> 00:32:32,540 并把最终结果构造起来 and then constitute together. 449 00:32:33,900 --> 00:32:36,700 这其实是一样的 Well, that sort of does the same thing. 450 00:32:41,080 --> 00:32:44,000 但这种方法忽略了把对象归约到最低阶项的问题 But this ignores the problem of reducing things to lowest terms, 451 00:32:44,000 --> 00:32:46,620 让我们花点时间 仔细思考一下 but let's not worry about that for a minute. 452 00:32:47,400 --> 00:32:48,920 我们为什么不这样做呢? But so what? Why don't we do it that way? 453 00:32:50,420 --> 00:32:52,920 对吧 毕竟这样看起来会少定义很多过程 Right? After all, there are sort of fewer procedures to define, 454 00:32:52,920 --> 00:32:54,360 并且更加直白 and it's a lot more straightforward. 455 00:32:55,080 --> 00:33:00,600 它省去了很多我们关于“数据抽象”的“自以为是”的方法 Ah It saves all this self-righteous BS about talking about data abstraction. 456 00:33:00,600 --> 00:33:01,660 而我们就不是这样做的 We just sort of do it. 457 00:33:01,900 --> 00:33:04,660 我的意思是这样或许会稍微高效一点 I mean, who knows, maybe it's even marginally more efficient 458 00:33:04,660 --> 00:33:06,900 如果我们用的编译器对此有优化的话 depending on whatever compiler were using for this. 459 00:33:07,460 --> 00:33:11,920 而将数据的使用与表示分离开来的意图是什么呢? What's the point of isolating the use from the representation? 460 00:33:13,660 --> 00:33:16,840 这就将回到命名的记号了 Well, it goes back to this notion of naming. 461 00:33:16,840 --> 00:33:21,180 还记得吗 编程中最重要的原理 Remember, one of the most important principles in programming 462 00:33:21,180 --> 00:33:25,180 和魔法中最重要的原理是一样的 对吧? is the same as one of the most important principles in sorcery, all right? 463 00:33:25,180 --> 00:33:28,600 如果你知道某个精灵的名字 你就可以控制它 That's if you have the name of the spirit, you get control over it. 464 00:33:30,000 --> 00:33:31,860 如果你回过头来看幻灯片 And if you go back and look at the slide, 465 00:33:33,380 --> 00:33:35,680 你会发现这里我们就有一个+RAT you see what's in there is we have this thing +RAT, 466 00:33:36,580 --> 00:33:40,900 如果我们有+RAT -RAT *RAT 或者和这些类似的过程 but nowhere in the system, if I have a +RAT and a -RAT and a *RAT, 467 00:33:40,900 --> 00:33:42,060 但在这个系统的任何地方 and things that look like that, 468 00:33:42,060 --> 00:33:50,460 我无法找出任何一个有理数 nowhere in the system do I have a thing that I can point at which is a rational number. 469 00:33:53,240 --> 00:33:55,900 在像这样的一个系统中 我并没有 I don't have, in a system like that, 470 00:33:56,800 --> 00:33:59,720 没有一个有理数的概念实体 the idea of rational number as a conceptual entity. 471 00:34:01,480 --> 00:34:02,960 那么 这样做的优势是什么呢? Well, what's the advantage of that? 472 00:34:03,920 --> 00:34:08,000 把有理数的概念和实体分离开来 What's the advantage of isolating the idea of rational numbers as a conceptual entity, 473 00:34:08,000 --> 00:34:11,420 然后用MAKE-RAT、NUMER、DENOM来控制它们有什么优势么? and really naming it with make-RAT, numerator, and denominator. 474 00:34:13,000 --> 00:34:19,180 优势之一就是你可以使用其它的方法表示(数据) Well, one advantage is you might want to have alternative representations. 475 00:34:20,420 --> 00:34:23,320 之前我不是给你们看过 See, before I showed you that one way George can solve this 476 00:34:24,080 --> 00:34:26,560 George解决分数化简的方法么? things not reduced to lowest terms problem, 477 00:34:26,560 --> 00:34:28,180 当他在构建有理数时 is when you build a rational number, 478 00:34:28,780 --> 00:34:30,780 将分子分母同时除以最大公约数 you divide up by the greatest common denominator. 479 00:34:30,780 --> 00:34:35,960 另一种解决办法在这里 Another way to do that is shown over here. 480 00:34:36,300 --> 00:34:38,840 我可以用另一种方法表示有理数 I can have an alternative representation for rational numbers 481 00:34:39,020 --> 00:34:41,560 也就是直接使用CONS来构建有理数 where when you make a rational number, you just cons them. 482 00:34:43,120 --> 00:34:45,420 而当你在析取去分子时 However, when you go to select out the numerator, 483 00:34:45,720 --> 00:34:51,260 在那个时候再计算分子分母的最大公约数 at that point you compute the gcd of the stuff that's sitting in that pair, 484 00:34:52,000 --> 00:34:53,580 然后再用分子除以这个最大公约数 and divide out by the gcd. 485 00:34:57,480 --> 00:34:59,400 类似地 当我析取分母时 And similarly, when I get the denominator, 486 00:35:00,740 --> 00:35:04,760 当我在析取出分母时 我将它除以最大公约数 at that point when I go to get the denominator, I'll divide out by the gcd. 487 00:35:05,260 --> 00:35:07,360 所以在旧的表示法中 So the difference would be in the old representation, 488 00:35:08,540 --> 00:35:10,200 当ANS在这里被构造时 when ans was constructed here, 489 00:35:11,080 --> 00:35:13,680 在第一种方法中 也就是6和8 say what's 6 and 8, in the first way, 490 00:35:14,100 --> 00:35:16,940 在6和8被装入表中时 它们已经被化到最简 the 6 and 8 would have got reduced when they got stuck into that pair, 491 00:35:16,940 --> 00:35:18,480 析取分子会得到3 numerator would select out 3. 492 00:35:20,040 --> 00:35:21,440 而在我给你们展示的方法中 And in the way I just showed you, well, 493 00:35:21,800 --> 00:35:24,300 我们放入的是6和8 ans would get 6 and 8 put in, 494 00:35:24,780 --> 00:35:26,880 然后在我析取分子时会进行一些计算 and then at the point where I said numerator, 495 00:35:27,320 --> 00:35:30,360 使得我得到3而非6 some computation would get done to put out 3 instead of 6. 496 00:35:32,280 --> 00:35:33,920 这就是我可以使用的两种不同方法 So those are two different ways I might do it. 497 00:35:33,920 --> 00:35:34,880 哪种更好呢? Which one's better? 498 00:35:37,200 --> 00:35:38,320 这得看情况 对吧? Well, it depends, right? 499 00:35:38,320 --> 00:35:41,640 如果我的系统中我经常构造有理数 If I'm making a system where I am mostly constructing rational numbers 500 00:35:41,640 --> 00:35:42,780 而不常去析取它们 and hardly ever looking at them, 501 00:35:42,780 --> 00:35:46,660 那么在构造它们时就最好不要化简 then it's probably better not to do that gcd computation when I construct them. 502 00:35:47,840 --> 00:35:51,500 如果在我的系统中 比起构造 我更经常去析取它们 If I'm doing a system where I look at things a lot more than I construct them, 503 00:35:51,720 --> 00:35:54,840 那在构造时就将它们化简就一劳永逸了 then it's probably better to do the work when I construct them. 504 00:35:56,940 --> 00:35:58,020 这得视情况做出选择 So there's a choice there. 505 00:35:58,020 --> 00:36:02,320 但真正的问题是 在你实现这些有理数时 But the real issue is that you might not be able to decide 506 00:36:04,220 --> 00:36:06,440 没法决定要用哪种表示法 at the moment you're worrying about these rational numbers. 507 00:36:07,320 --> 00:36:10,220 通常来说 作为一名系统设计师 See, in general, as systems designers, 508 00:36:13,040 --> 00:36:16,740 你被强迫去做出 关于如何解决问题的决定 you're forced with the necessity to make decisions about how you're going to do things, 509 00:36:17,680 --> 00:36:20,340 通常来说 你用于保持系统弹性的方法 and in general, the way you'd like to retain flexibility 510 00:36:20,500 --> 00:36:24,720 就是在你被迫做出决定前不要做任何事 is to never make up your mind about anything until you're forced to do it. 511 00:36:26,560 --> 00:36:31,500 但问题是 在推迟决定和彻底推延之间 The problem is, there's a very, very narrow line between 512 00:36:31,500 --> 00:36:34,960 并没有太明显的界限 deferring decisions and outright procrastination. 513 00:36:38,500 --> 00:36:43,720 你想要继续前进 但与此同时 So you'd like to make progress, but also at the same time, 514 00:36:43,720 --> 00:36:46,080 你也希望不要被你决定的结果给限制住 never be bound by the consequences of your decisions. 515 00:36:48,280 --> 00:36:50,060 数据抽象就是解决方法之一 Data abstraction's one way of doing this. 516 00:36:50,160 --> 00:36:52,080 我的做的就是“按愿望思维” What we did is we used wishful thinking. 517 00:36:54,100 --> 00:36:55,800 我们给结果命了个名字 See, we gave a name to the decision. 518 00:36:56,800 --> 00:37:02,040 我们让MAKE-RAT、NUMER、DENOM代表它们运作的结果 We said, make-RAT, numerator, and denominator will stand for however it's going to be done, 519 00:37:02,040 --> 00:37:03,740 但它们如何运作则是George的事 and however it's going to be done is George's problem. 520 00:37:03,740 --> 00:37:08,000 实际上 我们只是用几个名字代表我们期望运作的结果 But really, what that was doing is giving a name to the decision of how we're going to do it, 521 00:37:09,980 --> 00:37:12,700 然后继续编程 就像我们的确得到了结果 and then continuing as if we made the decision. 522 00:37:13,700 --> 00:37:16,820 到了最后 我们确实必须计算它时 And then eventually, when we really wanted it to work, 523 00:37:16,820 --> 00:37:18,820 再回过头来完成必要的计算 coming back and facing what we really had to do. 524 00:37:20,320 --> 00:37:22,120 事实上从现在起 我们将会三番五次地看到 And in fact, we'll see a couple times from now 525 00:37:22,480 --> 00:37:25,640 我们不会非得选定一个特定的表示方式 从来都不会 that you may never have to choose any particular representation, ever, ever. 526 00:37:27,420 --> 00:37:29,600 不管如何 这都是一种非常有用的设计技术 Anyway, that's a very powerful design technique. 527 00:37:30,380 --> 00:37:32,240 这也是人们使用数据抽象的原因 It's the key to the reason people use data abstraction. 528 00:37:34,560 --> 00:37:36,660 我们会不断的看到这个理念 And we're going to see that idea again and again. 529 00:37:38,480 --> 00:37:39,680 有什么问题吗? Let's stop for questions. 530 00:37:40,180 --> 00:37:44,360 学生:通过抽象层做出决定与 AUDIENCE: What does this decision making through abstraction layers 531 00:37:44,820 --> 00:37:48,040 编码前做完成设计的信条相比 哪个更好呢? do to the axiom of do all your design before any of your code? 532 00:37:49,420 --> 00:37:51,840 教授:这只是少数人的信条 PROFESSOR: Well, that's someone's axiom, 533 00:37:51,840 --> 00:37:56,080 我打赌这是那些不经常实现大型计算机系统的家伙的信条 and I bet that's the axiom of someone who hasn't implemented very large computer systems very much. 534 00:38:00,880 --> 00:38:02,800 我曾说过计算机科学非常像魔法 I said that computer science is a lot like magic, 535 00:38:03,560 --> 00:38:05,020 像魔法这一点非常好 and it's sort of good that it's like magic. 536 00:38:05,020 --> 00:38:07,580 但是计算机科学也非常像宗教 这就不好了 There's a bad part of computer science that's a lot like religion. 537 00:38:08,220 --> 00:38:15,120 通常来说 我认为那些相信在编码前就能把系统设计完美 And in general, I think people who really believe that you design everything before you implement it 538 00:38:15,920 --> 00:38:18,140 大多都是一些没有设计过大规模系统的人 basically are people who haven't designed very many things. 539 00:38:20,980 --> 00:38:24,700 我们的方法 厉害之处就在于可以假设我们已经得到结果了 The real power is that you can pretend that you've made the decision 540 00:38:25,700 --> 00:38:27,920 然后再讨论到底是哪个是对的 and then later on figure out which one is right, 541 00:38:28,260 --> 00:38:29,800 或者你应该得到怎样的结果 which decision you ought to have made. 542 00:38:30,460 --> 00:38:32,480 当你学会这招了 你会发现这个是最棒的一招 And when you can do that, you have the best of both worlds. 543 00:38:35,660 --> 00:38:39,140 学生:您能解释一下LET和DEFINE的区别吗? AUDIENCE: Can you explain the difference between let and define? 544 00:38:39,860 --> 00:38:41,060 教授:好的 PROFESSOR: Oh, OK. 545 00:38:41,540 --> 00:38:48,900 LET是用来建立一个局部的名字 Let is a way to establish local names. 546 00:38:53,100 --> 00:38:56,760 嗯 我就先大概给你说下 So there... Let me give you sort of the half answer. 547 00:38:57,200 --> 00:39:01,640 然后我们再来讨论这整个复杂的过程 And I'll say, later on we can talk about the whole very complicated thing. 548 00:39:02,620 --> 00:39:06,540 就现在来说 区别就在于 当你在Lisp中编程时 But the big difference for now is that, see, when you're typing at Lisp, 549 00:39:07,600 --> 00:39:10,920 编写定义是与所在环境有关的 you're typing in this environment where you're making definitions. 550 00:39:11,720 --> 00:39:19,100 当你想把A定义为5时 我写(DEFINE A 5) And when you say define a to be 5, if I say define a to be 5, 551 00:39:20,420 --> 00:39:22,760 从此以后我们就会记得A就是5 then from then on the thing will remember that a is 5. 552 00:39:25,280 --> 00:39:29,840 LET会建立一个包含一个定义的局部上下文 Let is a way to set up a local context where there's a definition. 553 00:39:30,800 --> 00:39:36,640 所以当我键入 比如(LET ((A So if I type something like, saying let a-- 554 00:39:36,640 --> 00:39:44,880 或者我写(LET ((Z 10))) no, I shouldn't say a-- if I said let z be 10, 555 00:39:48,020 --> 00:39:53,660 然后在这个上下文中 我们计算Z加上Z的和 and within that context, tell me what the sum of z and z is. 556 00:39:54,000 --> 00:39:56,260 如果我在Lisp中这样写的话 So if I typed in this expression to Lisp, 557 00:39:58,220 --> 00:40:00,840 Lisp会输出20 and then this would put out 20. 558 00:40:01,960 --> 00:40:05,460 然而 如果我再问Z是什么 However, then if I said what's z, 559 00:40:06,140 --> 00:40:09,140 计算机会告诉我Z是一个未绑定的变量 the computer would say that's an unbound variable. 560 00:40:10,600 --> 00:40:14,040 因此LET可以创建一个上下文 你可以在这个上下文中进行定义 So let is a way of setting up a context where you can make definitions. 561 00:40:15,840 --> 00:40:18,420 但是这些都是这个上下文中的局部定义 But those definitions are local to this context. 562 00:40:19,100 --> 00:40:27,720 当然啦 我把这个改为A的话 我依旧会得到20 And of course, if I'd said a in here, I'd still get 20. 563 00:40:27,720 --> 00:40:31,520 但是这个A与这个A一点也不冲突 But this a would not interfere at all with this one. 564 00:40:33,640 --> 00:40:36,040 所以我键入这个 再键入这个 再问A是什么 So if I type this, and then type this, and then say what's a? 565 00:40:36,040 --> 00:40:36,940 A还会是5 a will still be 5. 566 00:40:39,020 --> 00:40:42,120 因此在LET和DEFINE之间有这另一种代换模型 So there's some other subtle differences between let and define, 567 00:40:42,120 --> 00:40:44,120 但这(LET的有效域是局部的)才是最重要的 but that's the most important one. 568 00:40:44,120 --> 00:40:50,700 [音乐] [JESU, JOY OF MAN'S DESIRING] 569 00:41:03,760 --> 00:41:07,420 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 570 00:41:07,580 --> 00:41:10,980 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 571 00:41:11,460 --> 00:41:14,440 复合数据 Compound Data 572 00:41:19,780 --> 00:41:23,220 好了 我们已经看过作为数据抽象技术的示例 All right, well, we've looked at implementing this little system 573 00:41:23,500 --> 00:41:29,100 在有理数域上做算术的小型系统的实现 for doing arithmetic on rational numbers as an example of this methodology of data abstraction. 574 00:41:30,880 --> 00:41:35,000 这就是一种在大型系统中控制复杂度的方法 And that's a way of controlling complexity in large systems. 575 00:41:36,560 --> 00:41:38,660 就像定义过程 But, see, like procedure definition, 576 00:41:38,820 --> 00:41:41,680 以及我们谈论的所有的控制复杂度的方法 and like all the ways we're going to talk about for controlling complexity, 577 00:41:41,980 --> 00:41:47,100 这些东西的真正厉害之处不是体现在实现它们本身 the real power of these things show up not when you sort of do these things in themselves, 578 00:41:47,780 --> 00:41:51,220 我们构建的有理数运算系统并不是什么了不起的事 like it's not such a great thing that we've done rational number arithmetic, 579 00:41:52,140 --> 00:41:57,860 而是你可以将这些东西用于构建更复杂的东西 it's that you can use these as building blocks for making more complicated things. 580 00:42:00,340 --> 00:42:04,020 你把两个数放在一起构成一个序对 这也一点不新奇 So it's no wonderful idea that you can just put two numbers together to form a pair. 581 00:42:04,020 --> 00:42:05,560 如果你真想那么做的话 If that's all you ever wanted to do, 582 00:42:05,720 --> 00:42:07,400 我们有各式各样的方法 there are tons of ways that you can do that. 583 00:42:08,200 --> 00:42:10,240 我们的问题是 我们能否找到一种方法 The real issue is can you do that in such a way 584 00:42:11,220 --> 00:42:12,420 可以让我们构建的东西作为一个块 so that the things that you build 585 00:42:12,700 --> 00:42:16,100 用来构建更复杂的东西? become building blocks for doing something even more complex? 586 00:42:16,900 --> 00:42:19,060 因此无论何时有人向你展示控制复杂度的方法 So whenever someone shows you a method for controlling complexity, 587 00:42:19,060 --> 00:42:21,600 你都应该说 嗯 这很不错 但我可以用它来构建什么呢? you should say, yeah, that's great, but what can I build with it? 588 00:42:24,960 --> 00:42:25,760 举个例子吧 So for example, 589 00:42:27,540 --> 00:42:31,740 我举一个很像刚才那个有理数系统的例子 let me just run through another thing that's a lot like the rational number one. 590 00:42:31,740 --> 00:42:34,780 假设我们想要在平面中表示一个点 Suppose we would like to represent points in the plane. 591 00:42:35,300 --> 00:42:36,780 好吧 这里有一个点 You sort of say, well, there's a point, 592 00:42:37,440 --> 00:42:39,060 我们把它叫做点P and we're going to call that point p. 593 00:42:40,520 --> 00:42:45,100 这个点可能会有一个坐标 And that point might have coordinates, 594 00:42:47,000 --> 00:42:50,020 比如点P就是(1,2) like this might be the point 1 comma 2. 595 00:42:50,020 --> 00:42:53,500 X坐标为1 Y坐标为2 The x-coordinate might be 1, and it's y-coordinate might be 2. 596 00:42:54,220 --> 00:42:57,920 我们将要构建一个用于在平面中处理这些点的小型系统 And we'll make a little system for manipulating points in the plane. 597 00:43:00,080 --> 00:43:03,800 我们当然可以 可以像这样 And again, we can do that-- here's a little example of that. 598 00:43:06,680 --> 00:43:09,360 用向量来表示 就和点在平面中的表示是一样的 It can represent vectors, the same as points in the plane, 599 00:43:09,720 --> 00:43:11,260 我们也会说 嗯 and we'll say, yep, 600 00:43:11,620 --> 00:43:17,820 这里有一个叫做MAKE-VECTOR的构造函数 there's a constructor called make-vector, 601 00:43:17,820 --> 00:43:19,420 函数MAKE-VECTOR需要两个坐标 make-vector's going to take two coordinates, 602 00:43:20,700 --> 00:43:23,300 当然 如果我们愿意的话可以将其实现为序对 and here we can implement them if we like as pairs, 603 00:43:23,680 --> 00:43:25,540 但是最重点的是我们有一个构造函数 but the important thing is that there's a constructor. 604 00:43:26,780 --> 00:43:28,320 当我们传递了向量P后 And then given some vector, p, 605 00:43:29,200 --> 00:43:30,600 我们可以得到它的X坐标 we can find its x-coordinate, 606 00:43:31,980 --> 00:43:33,220 我们也可以得到它的Y坐标 or we can get its y-coordinate. 607 00:43:33,220 --> 00:43:36,900 所以这里就有了点在平面系统中的构造函数和选择函数 So there's a constructor and selectors for points in the plane. 608 00:43:38,660 --> 00:43:41,820 那么 我们有了平面中的点 就希望将它们用来构建事物 Well, given points in the plane, we might want to use them to build something. 609 00:43:42,060 --> 00:43:44,060 比如说 我们想要 So for instance, we might want to talk about, 610 00:43:44,680 --> 00:43:47,560 我们有一个点P 一个点Q we might have a point, p, and a point, q, 611 00:43:48,140 --> 00:43:52,460 点P为(1,2) 点Q为(2,3) and p might be the point 1, 2, and q might be the point 2, 3. 612 00:43:54,460 --> 00:44:00,120 我们想要得到从P开始 到Q截止的线段 And we might want to talk about the line segment that starts at p and ends at q. 613 00:44:01,660 --> 00:44:03,100 我们把它叫做线段S And that might be the segment s. 614 00:44:04,920 --> 00:44:12,340 我们想用数字来表示点 并用点来构造向量 So we might want to build points for vectors in terms of numbers, 615 00:44:12,540 --> 00:44:13,940 用向量来表示线段 and segments in terms of vectors. 616 00:44:16,140 --> 00:44:19,000 因此我们也可以对线段如法炮制 So we can represent line segments in exactly the same way. 617 00:44:19,700 --> 00:44:21,420 因此 对于从P到Q的线段 All right, so the line segment from p to q, 618 00:44:21,420 --> 00:44:23,740 我们这里有一个构造函数MAKE-SEGMENT we'll say there's a constructor, make-segment. 619 00:44:26,680 --> 00:44:29,160 然后是为选择函数取名 And make up names for the selectors, 620 00:44:29,160 --> 00:44:32,240 取得线段起点的函数 和取得终点的函数 the starting point of the segment and the ending point of the segment. 621 00:44:32,240 --> 00:44:35,400 当然了 我们可以将线段实现为两个点构造成的序对 And again, we can implement a segment using cons as a pair of points, 622 00:44:36,840 --> 00:44:40,340 CAR和CDR可以分别取得构成线段的两个点 and car and cdr get out the two points that we put together to get the segment. 623 00:44:44,540 --> 00:44:45,560 好了 我们已经完成这个系统了 Well, now having done that, 624 00:44:47,660 --> 00:44:49,160 我们可以进行一些此操作 we can have some operations on them. 625 00:44:51,440 --> 00:44:56,120 比如说 某个线段的中点是什么? Like we could say, what's the midpoint of a line segment? 626 00:44:57,320 --> 00:44:59,560 这就是某个线段的中点 So here's the midpoint of a line segment, 627 00:44:59,880 --> 00:45:06,840 该点的X、Y坐标分别为起点和终点X、Y坐标和的一半 that's going to be the points whose coordinates are the averages of the coordinates of the endpoints. 628 00:45:07,740 --> 00:45:08,780 嗯 这就是中点 OK, there's the midpoint. 629 00:45:09,840 --> 00:45:12,100 因此 为了得到线段S的中点 So to get the midpoint of a line segment, s, 630 00:45:13,600 --> 00:45:17,020 我们先要取得该线段的起点 we'll just say grab the starting point to the segment, 631 00:45:17,260 --> 00:45:18,680 取得该线段的终点 grab the ending point of the segment, 632 00:45:19,960 --> 00:45:21,980 然后构建一个向量 也就是一个点 and now make a vector--make a point 633 00:45:22,680 --> 00:45:28,980 该点的X坐标为起点、终点X坐标和的一半 whose coordinates are the average of the x-coordinate of the first point and the x-coordinate of the second point, 634 00:45:29,880 --> 00:45:32,300 Y坐标为起点、终点Y坐标和的一半 and whose y-coordinate is the average of the y-coordinates. 635 00:45:33,480 --> 00:45:35,760 这就是函数MIDPOINT一种实现 So there's an implementation of midpoint. 636 00:45:37,440 --> 00:45:42,980 类似的 我们可以编写类似于求取线段长度的函数 And then similarly, we can build something like the length of the segment. 637 00:45:43,960 --> 00:45:51,780 线段的长度 可以根据勾股定理算得 The length of the segment is a thing whose-- use Pythagoras's rule, 638 00:45:51,780 --> 00:45:56,100 线段的长度是dX的平方加dY的平方的和的平方根 the length of the segment is the square root of the d x squared plus d y squared. 639 00:45:56,680 --> 00:45:59,000 当我们说计算某线段S的长度时 We'll say to get the length of a line segment, 640 00:45:59,920 --> 00:46:10,200 我们令dX为起点、终点X坐标之差 we'll let dx be the difference of the x-coordinate of one endpoint and the x-coordinate of the other endpoint, 641 00:46:11,180 --> 00:46:14,500 令dY为起点、终点Y坐标之差 and we'll let dy be the difference of the y-coordinates. 642 00:46:15,880 --> 00:46:19,960 然后我们求取dX、dY平方和的平方根 And then we'll take the square root of the sum of the squares of dx and dy, 643 00:46:19,960 --> 00:46:20,780 就是这样了 that's what this says. 644 00:46:22,020 --> 00:46:24,600 好了 这就是函数LENGTH的一种实现 All right, so there's an implementation of length. 645 00:46:25,840 --> 00:46:33,940 再次强调 我们构建的是一种层次系统 And again, what we built is a layered system. 646 00:46:35,340 --> 00:46:40,200 我们构建了一个有 呃 现在有线段 We built a system which has, well, say up here there's segments. 647 00:46:47,060 --> 00:46:48,620 这里就有了一道抽象屏障 And then there's an abstraction barrier. 648 00:46:50,160 --> 00:46:54,840 这道抽象屏障把 The abstraction barrier separates the implementation 649 00:46:56,480 --> 00:46:58,920 线段同向量、点的实现分离开来 of segments from the implementation of vectors and points, 650 00:46:59,120 --> 00:47:03,580 而这道抽象屏障 就是构造函数和选择函数 and what that abstraction barrier is are the constructors and selectors. 651 00:47:03,580 --> 00:47:14,860 也就是 MAKE-SEG SEG-START 和 SEG-END It's make-segment, and segment-start, and segment-end. 652 00:47:17,700 --> 00:47:18,600 这里是向量 And then there are vectors. 653 00:47:19,720 --> 00:47:24,080 而向量则是建立在序对和数的基础上 And vectors in turn are built on top of pairs and numbers. 654 00:47:25,080 --> 00:47:29,080 所以这里是序对和数 So I'll say pairs and numbers. 655 00:47:29,340 --> 00:47:31,760 这又是它们的抽象屏障 And that has its own abstraction barrier, 656 00:47:32,420 --> 00:47:42,620 也就是 MAKE-VECT XCOR 和 YCOR which is make-vector, and x-coordinate, and y-coordinate. 657 00:47:46,440 --> 00:47:48,520 如此可见 这就是一个层次系统 So we have, again, a layered system. 658 00:47:48,520 --> 00:47:51,460 你可以清楚的看出这些分明的层次 You're starting to see that there are layers here. 659 00:47:51,720 --> 00:47:58,920 我提一下 这里有一个非常重要但是又理所当然的东西 I ought to mention, there is a very important thing that I kind of took for granted. 660 00:48:00,240 --> 00:48:07,120 这点非常自然 但从另外一方面来说又非常重要 And it's sort of so natural, but on the other hand it's a very important thing. 661 00:48:07,120 --> 00:48:10,220 我们为了表示某线段S Notice that in order to represent this segment s, 662 00:48:11,600 --> 00:48:13,940 我说这个线段就是由点构成的序对 I said this segment is a pair of points. 663 00:48:16,260 --> 00:48:17,980 而一个点又是由数构成的序对 And a point is a pair of numbers. 664 00:48:18,800 --> 00:48:22,320 如果要把这个结构的盒子—指针模型给画出来的话 And if I were going to draw the box and pointers structure for that, 665 00:48:23,620 --> 00:48:25,060 那么我会说 嗯 这个线段是 I would say, oh, the segment is, 666 00:48:26,000 --> 00:48:29,260 用我之前给你们说过的表示法来演示 given those particular representations that I showed you, 667 00:48:29,260 --> 00:48:32,500 线段就是一个序对 I'd say this segment s is a pair, 668 00:48:33,720 --> 00:48:38,520 序对的第一个元素是一个向量 and the first thing in the pair is a vector, 669 00:48:40,200 --> 00:48:43,800 向量是由数构成的序对 and the vector is a pair of numbers. 670 00:48:45,460 --> 00:48:46,720 这就是它 这就是点P And that's this, that's p. 671 00:48:49,920 --> 00:48:52,380 线段中的另一个东西就是点Q And the other thing in the segment is q, 672 00:48:52,960 --> 00:48:58,160 它本身就是一个由数构成的序对 which is itself a pair of numbers. 673 00:48:59,800 --> 00:49:02,520 当我说CONS可以让你把东西组合在一起的时候 So I almost took it for granted when I said that 674 00:49:03,260 --> 00:49:06,480 就把它视作理所当然了 cons allows you to put things together. 675 00:49:08,600 --> 00:49:13,020 但有一点也很容易搞不明白 请注意 But it's very easy to not appreciate that, because notice, 676 00:49:13,020 --> 00:49:18,380 我也可以把一些序对给组合在一起 some of the things I can put together can themselves be pairs. 677 00:49:20,360 --> 00:49:23,520 我以后会经常用一个术语来表示 And let me introduce a word that I'll talk about more next time, 678 00:49:24,100 --> 00:49:26,920 一个我最喜欢的术语 这称作“闭包” it's one of my favorite words, called closure. 679 00:49:30,280 --> 00:49:35,460 这种所谓具有“闭包性质”的组合方法 And by closure I mean that the means of combination in your system 680 00:49:36,220 --> 00:49:39,320 就是哪些当你用它们把东西组合在一起时 are such that when you put things together using them, 681 00:49:39,320 --> 00:49:40,240 这就像我们构建序对的时候 like we make a pair, 682 00:49:41,760 --> 00:49:44,500 你可以继续用同样的方法把组合物继续进行组合 you can then put those together with the same means of combination. 683 00:49:44,940 --> 00:49:48,420 因此我不仅可以有由数构成的序对 也可有由序对构成的序对 So I can have not only a pair of numbers, but I can have a pair of pairs. 684 00:49:51,460 --> 00:49:59,220 比如说 在Fortran中的数组并不具有闭包性质 So for instance, making arrays in a language like Fortran is not a closed means of combination, 685 00:49:59,220 --> 00:50:00,800 因为我可以有元素为数的数组 because I can make an array of numbers, 686 00:50:01,560 --> 00:50:02,980 但不能有以数组为元素的数组 but I can't make an array of arrays. 687 00:50:05,560 --> 00:50:07,000 当某人给你展示组合的方法时 And one of the things that you should ask, 688 00:50:07,420 --> 00:50:12,300 你也应该这样问 通过该种组合方法 one of your tests of quality for a means of combination that someone shows you, 689 00:50:12,600 --> 00:50:17,120 构建出的东西是否封闭 is gee, are the things you make closed under that means of combination? 690 00:50:18,040 --> 00:50:22,280 如果序对仅仅只能是由数构成的序对的话 就不是那么有趣了 So pairs would not be nearly so interesting if all I could do was make a pair of numbers. 691 00:50:22,820 --> 00:50:24,400 我并不能用它构建出太多的结构 I couldn't build very much structure at all. 692 00:50:26,520 --> 00:50:27,780 好了 言归正传 OK, well, we'll come back to that. 693 00:50:28,080 --> 00:50:30,760 我现在只是提一下 后面我们还会详细讨论 I just wanted to mention it now. You'll hear a lot about closure later on. 694 00:50:31,780 --> 00:50:38,840 你也可以看到在我们有了层次系统后 如果不使用数据抽象 You can also see the potential for losing control of complexity 695 00:50:38,840 --> 00:50:42,120 系统复杂度会有失控的隐患 as you have a layered system if you don't use data abstraction. 696 00:50:43,680 --> 00:50:46,520 让我们回过头来看看LENGTH函数的幻灯片 Let's go back and look at this slide for length. 697 00:50:47,740 --> 00:50:51,880 LENGTH函数简单而有效是因为 Length works and is a simple thing because I can say, 698 00:50:52,840 --> 00:50:55,060 当我使用它时 我确信 when I want to get this value, I can say, oh, 699 00:50:55,300 --> 00:51:00,320 这个是第一个端点的X坐标 that is the x-coordinate of the first endpoint of the segment. 700 00:51:02,700 --> 00:51:06,560 这些东西 这些选择函数 XCOR 和 SEG-END And each of these things, each of these selectors, x-coordinate and endpoint, 701 00:51:07,140 --> 00:51:10,960 都代表了一个决策选择 我不用关心它们的内部细节 stand for a decision choice whose details I don't have to look at. 702 00:51:11,940 --> 00:51:16,000 因此就和之前的有理数系统一样 我可以说 So I could perfectly well, again, just like rational numbers I did before, 703 00:51:16,000 --> 00:51:19,900 我可以认为 嗯 线段实际上就是由序对构成的序对 I could say, oh well, gee, a segment really is a pair of pairs. 704 00:51:20,800 --> 00:51:27,040 线段第一个端点的X坐标实际上是什么 是什么呢? And the x-coordinate of the first endpoint or the segment really is the-- well, what is it? 705 00:51:27,040 --> 00:51:33,040 它的线段的CAR部分的CAR部分 It's the car of the car of the segment. 706 00:51:33,640 --> 00:51:36,640 所以我可以这样完美地重定义LENGTH So I could perfectly well go and redefine length. 707 00:51:37,140 --> 00:51:46,420 我可以定义某线段S的长度为 I could say, define the length of some segment s. 708 00:51:48,640 --> 00:51:50,280 我这样来写 I can start off writing something like, 709 00:51:50,280 --> 00:51:56,000 我们令dX为 令dX为什么呢? well, we'll let dx be-- well, what's it have to be? 710 00:51:56,000 --> 00:51:57,920 为两个坐标之差 It's got to be the difference of the two coordinates, 711 00:51:57,920 --> 00:52:05,820 坐标之一为(CAR (CAR S)) so that's the difference of, the first one is the car of the car of s, 712 00:52:08,140 --> 00:52:11,620 从第一个坐标中减去 subtracted from the first one, 713 00:52:11,620 --> 00:52:15,820 减去另一个点的坐标 也就是(CAR (CDR S)) the car of the other half of it, the cdr of s. 714 00:52:21,080 --> 00:52:24,920 好了 那么dY也就是 我看看 and then dy would be-- well, let's see, 715 00:52:25,920 --> 00:52:33,060 那么Y坐标也就是 (CDR (CAR S)) I'd get the y-coordinate, so it'd be the difference of the cdr of the car of s, 716 00:52:34,040 --> 00:52:41,260 减去(CDR (CDR S)) 诸如此类 and the cdr of the cdr of s, sort of go on. 717 00:52:43,760 --> 00:52:47,640 你可以发现同之前那个程序相比 这个更难度 You can see that's much harder to read than the program I had before. 718 00:52:47,920 --> 00:52:52,900 但比这个还糟的是 假设你这样实现了LENGTH函数 But worse than that, suppose you'd gone and implemented length? 719 00:52:56,520 --> 00:53:00,240 而第二天 George来和你说 抱歉 我改变主意了 And then the next day, George comes to you and says, I'm sorry, I changed my mind. 720 00:53:00,740 --> 00:53:03,940 我想把点的X坐标放在前面 I want to write points with the x-coordinate first. 721 00:53:04,860 --> 00:53:06,460 然后您回过头来看代码 找啊找啊 So you come back you stare at this code and say, 722 00:53:06,460 --> 00:53:10,100 那是什么呢 哦 是CAR oh gee, what was that? That was the car, 723 00:53:10,100 --> 00:53:15,820 因此我要把这个改为CDR 把这个改为CDR so I have to change this to cdr, and this is cdr, 724 00:53:17,020 --> 00:53:21,960 这个要改为CAR 这个也要改为CAR and this now has to be car. And this has to be car. 725 00:53:23,480 --> 00:53:26,800 你也就这么做了 然后第二天George又跑来说 抱歉 抱歉 And you sort of do that, and then the next day George comes back and says, sorry, 726 00:53:27,120 --> 00:53:35,080 设计显示的那个家伙想要让线段指向反方向 Ah the guys designing the display would like lines to be painted in the opposite direction, 727 00:53:35,080 --> 00:53:37,260 因此我必须让截止点放到第一位 so I have to write the endpoint first in the order. 728 00:53:37,260 --> 00:53:38,820 然后你又回过头来审视这些代码 And then you come back and you stare at this code, 729 00:53:38,820 --> 00:53:42,040 哦 这又改怎么弄? and say, gee, what was it talking about? 730 00:53:42,040 --> 00:53:44,080 嗯 把这个改为CDR Oh yeah, well I've got to change this one to cdr, 731 00:53:45,020 --> 00:53:50,500 这个改为CAR 改为CAR 把这个改为CDR and this one becomes car, this one comes car, and this becomes cdr. 732 00:53:50,500 --> 00:53:51,420 你又这么做了 And you go up and do that, 733 00:53:52,040 --> 00:53:53,820 第二天 George又跑过来说 太抱歉了 and then the next day, George comes back and says, I'm sorry, 734 00:53:53,820 --> 00:53:58,680 我其实只是想让线段总是在屏幕上从左向右描绘 what I really meant is that the segments always have to be painted from left to right on the screen. 735 00:53:59,220 --> 00:54:03,220 这时候 毫无疑问 你一定会给George一个耳光 And then you sort of, it's clear, you just go and punch George in the mouth at that point. 736 00:54:03,220 --> 00:54:08,940 正如你所见 一旦我们有了一个10层的系统 But you see, as soon as we have a 10 layer system, 737 00:54:08,940 --> 00:54:11,040 复杂度也就突增 you see how that complexity immediately builds up 738 00:54:11,500 --> 00:54:14,240 甚至达到像这里一样失控的地步 to the point where even something like this gets out of control. 739 00:54:15,940 --> 00:54:20,820 因此 为了避免发生这样的事 我们就要为精灵命名 So again, the way we've gotten out of that is we've named that spirit. 740 00:54:20,820 --> 00:54:24,400 我们构建一个系统 这个系统中有一个 We built a system where there is a thing, 741 00:54:25,140 --> 00:54:30,220 关于你要如何显示向量的选择 which is the representation choice for how you're going to talk about vectors. 742 00:54:31,180 --> 00:54:34,620 这个选择在这里 And choices about that representation are localized right there. 743 00:54:35,340 --> 00:54:37,460 它们不必将其完全显露出来 They don't have their guts spilling over into things like 744 00:54:37,460 --> 00:54:39,460 就像这里你计算长度和中点 how you compute the length and how you compute the midpoint. 745 00:54:41,000 --> 00:54:43,900 这才是这个系统真正强大之处 And that's the real power of this system. 746 00:54:45,320 --> 00:54:49,480 我们对它们很清楚 这样我们能控制它们 OK, we're explicit about them, so that we have control over them. 747 00:54:50,840 --> 00:54:51,460 好了 有疑问吗? All right, questions? 748 00:54:51,600 --> 00:54:55,900 学生:在那些无法使用序对来表示的情况中会如何呢? AUDIENCE: What happens in the case where you don't want to be treating objects in terms of pairs? 749 00:54:55,900 --> 00:55:01,180 比如说在三维空间里 一个序对无法表示三维坐标 For instance, in three-dimensional space, you'd have three coordinates. 750 00:55:01,180 --> 00:55:03,800 也就是说在N维空间中 我们该如何做呢? Or even in the case where you have n-dimensional space, what happens? 751 00:55:03,800 --> 00:55:04,800 教授:啊 嗯 PROFESSOR: Right, OK. 752 00:55:04,800 --> 00:55:07,180 好吧 你提到了一点明天的内容 Well, this is a preview of what I'll say tomorrow. 753 00:55:08,020 --> 00:55:15,760 但关键点就是 一旦你有了二元的东西 就可以有多元的东西 But the point is, once you have two things, you have as many things as you want. 754 00:55:16,800 --> 00:55:18,640 能理解吗? 如果我想要组合三个东西 All right? Because if I want to make three things, 755 00:55:19,040 --> 00:55:21,020 我构建一个序对 I could start making things like a pair 756 00:55:24,680 --> 00:55:25,980 该序对第一个元素是1 whose first thing is 1, 757 00:55:26,620 --> 00:55:32,380 第二个元素则又是一个序对 一个有2和3的序对 and whose second thing is another pair that, say, has 2 and 3 in it. 758 00:55:34,700 --> 00:55:36,620 以此类推 十个百个的东西 我可以把序对嵌套起来 And so on, a hundred things. I can nest them out of pairs. 759 00:55:37,180 --> 00:55:40,040 这里 我相当随意地使用了一种方法 Here I made a pretty arbitrary decision about how to do it, 760 00:55:40,040 --> 00:55:42,320 不久后你将看到更多地方法 and you can immediately see there are lots of ways to do that. 761 00:55:42,680 --> 00:55:45,920 而我们下节课将会讨论处理类似问题的约定 What we'll start talking about next time are conventions for how to do things like that. 762 00:55:47,320 --> 00:55:50,360 只要注意到我可以构建由序对构成的序对就好了 But notice that what this really depends on is I can make pairs of pairs. 763 00:55:51,580 --> 00:55:53,900 因为我只能构建由数构成的序对的话 我就没法了 If all I could do was make pairs of numbers, I'd be stuck. 764 00:56:06,780 --> 00:56:10,040 好吧 休息 OK. Let's break. 765 00:56:11,060 --> 00:56:20,460 [音乐] [JESU, JOY OF MAN'S DESIRING] 766 00:56:21,860 --> 00:56:28,000 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 767 00:56:38,000 --> 00:56:41,720 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 768 00:56:42,000 --> 00:56:45,600 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 769 00:56:46,440 --> 00:56:49,940 复合数据 Compound Data 770 00:56:55,240 --> 00:56:57,340 好吧 我们刚才只是做了 All right, well, we've just gone off and done 771 00:56:59,240 --> 00:57:01,800 一个数据抽象的简单示例 a couple of simple examples of data abstraction. 772 00:57:03,620 --> 00:57:05,060 现在我想做点更复杂的事儿 Now I want to do something more complicated. 773 00:57:05,640 --> 00:57:07,120 稍后我会详细说明这意味着什么 We're going to talk about what it means. 774 00:57:07,900 --> 00:57:08,860 这也将更困难 And this will be harder, 775 00:57:08,860 --> 00:57:12,940 因为在计算机程序设计中 because it's always much harder in computer programming 776 00:57:12,940 --> 00:57:15,500 说明某件事的的意义远比实现它难 to talk about what something means than to go off and do it. 777 00:57:16,460 --> 00:57:21,600 让我们回到最最开始的地方 But let's go back to almost the very beginning. 778 00:57:21,600 --> 00:57:24,640 还记得当时我说过的话么? Let's go back to the point where I said, 779 00:57:25,400 --> 00:57:27,900 我说 我们假设已经存在一些过程 we just assumed that there were procedures, 780 00:57:29,800 --> 00:57:36,620 MAKE-RAT、NUMER以及DENOM make-rat, and numer, and denom. 781 00:57:38,120 --> 00:57:40,700 好吧 我们就回到那里 回到最开始的地方 Let's go back to where we had this, at the very beginning, 782 00:57:41,740 --> 00:57:47,020 有构造函数和选择函数 以及定义有理数算术的地方 constructors and selectors, and when often defined the rational number arithmetic. 783 00:57:47,020 --> 00:57:50,220 我那时说过 假设我们已经有了那些需要George实现的东西了 And remember, I said at that point we were sort of done, except for George. 784 00:57:51,620 --> 00:57:54,340 那么 在那个时候我们实际上干了什么呢? Well, what is it that we'd actually done at that point? 785 00:57:55,580 --> 00:57:56,740 做了些什么东西呢? What was it that was done? 786 00:57:59,040 --> 00:58:00,100 我想说的就是 Well, what I want to say is, 787 00:58:00,920 --> 00:58:05,240 我们用这些东西实现了有理数操作后又做了什么呢 what was done after we'd implemented the operations and terms of these, 788 00:58:05,720 --> 00:58:12,000 我们用抽象数据来定义了有理数的表示 was that we had defined a rational number representation in terms of abstract data. 789 00:58:18,060 --> 00:58:19,560 通过数据抽象我想表达什么? What do I mean by abstract data? 790 00:58:20,700 --> 00:58:22,060 关键点就是 Well, the idea is that 791 00:58:24,520 --> 00:58:27,140 在那个时候 当我们有了+RAT和*RAT at that point, when we had our +RAT and our *RAT, 792 00:58:28,580 --> 00:58:36,260 任何George提供给我们的MAKE-RAT NUMER和DENOM函数 that any implementation of make-RAT, and numerator, and denominator that George supplied us with, 793 00:58:37,700 --> 00:58:39,840 都可以是有理数的表示基础 could be the basis for a rational number representation. 794 00:58:40,620 --> 00:58:42,280 因为你并不应该关心 Like, it wasn't our concern where you 795 00:58:42,900 --> 00:58:46,460 应该在那里获得最大公约数 等等 divided through to get the greatest common denominator, or any of that. 796 00:58:48,540 --> 00:58:53,800 关键点就是 我们构建了一个有理数算术系统 So the idea is that what we built is a rational arithmetic system 797 00:58:53,800 --> 00:58:56,200 一个可以基于任何表示方法的系统 that would sit on top of any representation. 798 00:58:56,880 --> 00:58:58,360 “任何表示方法”又是什么意思呢? What do I mean by any representation? 799 00:58:59,620 --> 00:59:01,160 我当然不会是指 I mean, certainly it can't be the case 800 00:59:01,820 --> 00:59:05,380 George从一个包里面 随便取出3个过程 that all I mean is George can reach in a bag and pull out three arbitrary procedures 801 00:59:07,140 --> 00:59:10,860 然后说 这就是那些实现 and say, well, fine, now that's the implementation. 802 00:59:11,460 --> 00:59:12,740 不是这样的 That can't be what I mean. 803 00:59:13,740 --> 00:59:19,000 我指的是这里有一种衡量方法 What I've got to mean is that there's some way of saying whether 804 00:59:20,820 --> 00:59:25,760 可以判定这三个过程用于有理数的表示是否合适 three procedures are going to be suitable as a basis for rational number representation. 805 00:59:25,760 --> 00:59:27,320 如果我们仔细思考这个问题 If we think about it, 806 00:59:28,340 --> 00:59:31,800 我应该像这样定义 所谓的“合适” what suitable might mean is if I have to assume something like this, 807 00:59:31,800 --> 00:59:45,400 我会说 如果X是(MAKE-RAT N D) I have to say that if x is the result of say, doing make-RAT of n and d, 808 00:59:48,540 --> 01:00:07,060 那么(NUMER X)除以(DENOM X)等同于N除以D then the numerator of x divided by the denominator of x is equal to n over d. 809 01:00:09,360 --> 01:00:11,940 看到了吗 这就和George订的契约 See, what that is is that's George's contract. 810 01:00:13,400 --> 01:00:16,100 而我们契约中订好的有理数规则 What we mean by writing a contract for rational numbers, 811 01:00:16,100 --> 01:00:17,680 你仔细想想的话 也是正确的 if you think about it, this is the right thing. 812 01:00:18,480 --> 01:00:21,220 我给你演示的这两个东西也是正确地 And the two ones we showed do the right thing. 813 01:00:21,220 --> 01:00:23,220 这样的话 就算我要考虑最大公约数 See, if I'm taking out greatest common divisors, 814 01:00:25,400 --> 01:00:28,800 我除不除、在哪里除 都无所谓 it doesn't matter whether I take them out or not, or the place where I take them, 815 01:00:28,800 --> 01:00:30,520 因为我这里进行了约分 because the idea is I'm going to divide through. 816 01:00:32,060 --> 01:00:33,540 嗯 这就是George的契约 But see, this is George's contract. 817 01:00:33,540 --> 01:00:39,920 我们要告诉George的就是 提供给我三个过程 So what we really say to George is your business is to go off and find us three procedures, 818 01:00:40,620 --> 01:00:42,240 MAKE-RAT NUMER 和 DENOM make-RAT, and numerator, and denominator, 819 01:00:42,520 --> 01:00:46,520 使得无论N和D如何选择 都可以满足这个契约 that fulfill this contract for any choice of n and d. 820 01:00:46,740 --> 01:00:52,140 这也就是我所谓的我们可以用来作为有理数表示的基础 And that's what we mean by we can use that as the basis for a rational number representation. 821 01:00:54,240 --> 01:00:56,540 并且只要它们能满足契约 And other than that, it fulfills this contract. 822 01:00:56,740 --> 01:00:58,040 我们不关心他是如何实现的 We don't care how he does it. 823 01:00:59,380 --> 01:01:02,320 这不关我们的事儿 这在抽象层之下 It's not our business. It's below the layer of abstraction. 824 01:01:06,620 --> 01:01:12,000 事实上 如果我们想知道 有理数真正是什么 In fact, if we want to say, what is a rational number really? 825 01:01:13,520 --> 01:01:16,940 那么 如果不在抽象层之下来讨论的话 See, what's it really, without having to talk about going below the layer of abstraction, 826 01:01:16,940 --> 01:01:21,340 我们必须得说有理数实际上是 what we're forced into saying is a rational number really 827 01:01:23,760 --> 01:01:25,100 这里的这些公理 is sort of this axiom, 828 01:01:25,800 --> 01:01:30,900 就是MAKE-RAT NUMER 和 DENOM这三个满足这条公理的过程 is three procedures, make-RAT, numerator, and denominator, that satisfy this axiom. 829 01:01:32,040 --> 01:01:36,880 从某种抽象的意义来说 这就是真正的有理数 In some sense, abstractly, that's what a rational number is really. 830 01:01:41,240 --> 01:01:45,760 这听起来很容易 因为你脑中已经有了 That's sort of easy words to listen to, because what you have in your head, of course, is well, 831 01:01:46,200 --> 01:01:49,480 关于有理数是什么的知识 for all this thing about saying that's what a rational number is really, 832 01:01:50,420 --> 01:01:52,800 因为你已经看到了我们是如何构建有理数的 you actually just saw that we built rational numbers. 833 01:01:58,480 --> 01:02:04,000 对 我们是在序对的基础上构建有理数的 See, what we really did is we built rational numbers on top of pairs. 834 01:02:08,520 --> 01:02:13,640 因此 抽象地来说 我们可以认为有理数实际上就是这些公理 So for all I'm saying abstractly, we can say a rational number really is just this axiom. 835 01:02:15,000 --> 01:02:19,160 你可以很自然把有理数理解为序对 因为这正也是你们见到的 You can listen to that comfortably, because you're saying, well, yeah, but really it's actually pairs, 836 01:02:19,960 --> 01:02:22,640 我把它说得抽象后反而影响你理解 and I'm just annoying you by trying to be abstract. 837 01:02:24,520 --> 01:02:27,700 那么为了让你们明白 Well, let me, as an antidote for that, 838 01:02:28,600 --> 01:02:31,720 我会展示一个吓到你们的东西 let me do something that I think is really going to terrify you. 839 01:02:32,620 --> 01:02:35,580 我讲带领你们零距离地面对 I mean, it's really going to bring you face to face 840 01:02:36,400 --> 01:02:40,620 我们讨论的抽象的真实存在性 with the sort of existential reality of this abstraction that we're talking about. 841 01:02:41,260 --> 01:02:44,100 我们将讨论“序对”到底是什么? And what I'm going to talk about is, what are pairs really? 842 01:02:45,700 --> 01:02:47,020 说说 我是怎么给你们讲“序对”的? See, what did I tell you about pairs? 843 01:02:48,340 --> 01:02:49,080 我耍了你们 对吧? I tricked you, right? 844 01:02:49,080 --> 01:02:52,160 我说 Lisp有一个叫CONS的基本过程可以构建序对 I said that Lisp has this primitive called cons that builds pairs. 845 01:02:53,340 --> 01:02:54,740 但我真正告诉你们什么呢? But what did I really tell you about? 846 01:02:56,180 --> 01:02:58,740 如果你回过头来看 看这些幻灯片 If you go back and said, let's look on this slide, 847 01:02:59,280 --> 01:03:04,680 会发现我真正告诉你们的是序对应该具有这些属性 all I really told you about pairs is that there happens to be this property, 848 01:03:04,680 --> 01:03:06,380 这些CONS CAR 和 CDR构成的属性 these properties of cons, car, and cdr. 849 01:03:06,540 --> 01:03:07,940 而我说的“序对” And all I really said about pairs 850 01:03:08,520 --> 01:03:12,740 只是说这里面有叫CONS 叫CAR 和叫CDR的东西 is that there's a thing called cons, and a thing called car, and a thing called cdr. 851 01:03:14,520 --> 01:03:18,720 在这个例子中 我构建了由X和Y构成的序对 取CAR部分得X And it is the case that if I build cons of x, y and take car of it, I get x. 852 01:03:20,440 --> 01:03:24,140 构建由X和Y构成的序对 取CDR部分得Y And if I build cons of x, y and get cdr of it, I get y. 853 01:03:25,520 --> 01:03:32,460 尽管如此 我也对你们谎称Lisp中有个东西能这么做 And even though I lulled you into thinking that there's something in Lisp that does that, 854 01:03:32,460 --> 01:03:34,200 因此你们也就假装确实有这么个东西 so you pretended you knew what it was, 855 01:03:34,380 --> 01:03:38,100 事实上 关于序对 我告诉你们的跟有理数一样多 in fact, I didn't tell you any more about pairs than this tells you about rational numbers. 856 01:03:39,400 --> 01:03:41,020 都是序对的一些公理 It's just some axiom for pairs. 857 01:03:44,320 --> 01:03:49,380 言归正传 我马上要大显身手了 Well, to drive that home, let me really scare you, 858 01:03:51,360 --> 01:03:53,660 我会用某个神秘的东西来构建序对 and show you what we might build pairs in terms of. 859 01:03:55,760 --> 01:04:00,580 你们将会看见 我们可以构建有理数 And what you're going to see is that we can build rational numbers, 860 01:04:00,580 --> 01:04:03,740 直线段、向量以及任何由序对构建起的东西 and line segments, and vectors, and all of this stuff in terms of pairs, 861 01:04:04,720 --> 01:04:07,840 我们在低于抽象层的这里看到 序对可以凭空产生 and we're going to see below here that pairs can be built out of nothing at all. 862 01:04:10,640 --> 01:04:11,340 纯粹的抽象 Pure abstraction. 863 01:04:12,440 --> 01:04:18,440 幻灯片中展示了CONS CAR和CDR的一种实现 So let me show you on this slide an implementation of cons, car, and cdr. 864 01:04:21,140 --> 01:04:22,720 等会儿我们会回来细看 And we'll look at it again in a second, 865 01:04:23,160 --> 01:04:26,520 但一定要注意过程CONS CAR和CDR的定义 but notice that their procedure definitions of cons, car, and cdr, 866 01:04:27,060 --> 01:04:32,300 这里你看不到任何数据 你只能看到一个lambda you don't see any data in there, what you see is a lambda. 867 01:04:34,860 --> 01:04:40,320 这里的CONS将返回 一个返回值为新的过程的过程 Cons, So cons here is going to return-- is a procedure that returns a procedure, 868 01:04:41,080 --> 01:04:42,400 就像函数AVERAGE-ADPT just like average-adpt. 869 01:04:44,280 --> 01:04:49,340 (CONS A B)返回一个具有单个参数的过程pick Cons of a and b returns a procedure of an argument called pick, 870 01:04:51,720 --> 01:04:52,300 它的定义是 and it says, 871 01:04:52,780 --> 01:04:55,860 如果pick等于1 那么该过程返回a if pick is equal to 1, I'm going to return a, 872 01:04:57,080 --> 01:04:59,520 而如果pick等于2 那么该过程返回b and if pick is equal to 2, I'm going to return b, 873 01:05:00,220 --> 01:05:01,660 这就是CONS的定义 and that's what cons is going to be. 874 01:05:04,460 --> 01:05:10,100 取X的CAR部分 (CAR X) Car of a thing x, car of a pair x, 875 01:05:10,500 --> 01:05:13,020 就是把X应用于1 注意了 这完全行得通 is going to be x applied to 1. And notice that makes sense. 876 01:05:13,020 --> 01:05:17,360 你现在还不太明白我为什么要这样做 但至少这样行得通 You might not understand why or how I'm doing such a thing, but at least it makes sense, 877 01:05:17,760 --> 01:05:20,700 因为我通过CONS构造出了一个过程 because the thing constructed by cons is a procedure, 878 01:05:21,260 --> 01:05:22,620 而CAR将其应用于1 and car applies that to 1. 879 01:05:24,260 --> 01:05:26,760 类似的 CDR将其应用于2 And similarly, cdr applies that thing to 2. 880 01:05:29,060 --> 01:05:32,800 好了 现在我已经给出了CONS CAR和CDR的一种表示法 OK, now I claimed that this is a representation of cons, car, and cdr, 881 01:05:32,800 --> 01:05:34,100 注意这里面没有任何数据 and notice there's no data in it. 882 01:05:35,600 --> 01:05:37,940 这就是“凭空”产生的 它们仅仅是过程 All right, it's built out of air. It's just procedures. 883 01:05:39,220 --> 01:05:42,220 这种表示法中没有任何数据对象 There's no data objects at all in that representation. 884 01:05:43,460 --> 01:05:45,120 那么 这又可能意味着什么呢? Well, what could that possibly mean? 885 01:05:49,260 --> 01:05:51,140 嗯 如果你承认这些东西的话 Well, if you really believe this stuff, 886 01:05:54,000 --> 01:05:59,340 那么接下来 一旦我证明了CONS CAR CDR的这种表示法 then you have to believe that in order to show that that's a representation for cons, car, and cdr, 887 01:05:59,640 --> 01:06:02,180 能满足我们的公理的话 你就对此不容置疑了 all I have to do is show that it satisfies the axiom. 888 01:06:03,220 --> 01:06:05,320 那么 我来举一个例子 See, all I should have to convince you of is, 889 01:06:05,560 --> 01:06:23,000 例如 (CAR (CONS 37 49))应该返回37 for example, that gee, that car of cons of 37 and 49 is 37 890 01:06:23,000 --> 01:06:25,700 37和49是我随意挑选的任意值 Right? for arbitrary values of 37 and 49. 891 01:06:26,460 --> 01:06:28,820 CDR也是如此 If I really.... And cdr the same way. 892 01:06:31,800 --> 01:06:36,140 如果我能用这个凭空构造的怪异过程 See, if I really can demonstrate to you that that weird procedure definition, 893 01:06:36,640 --> 01:06:40,180 来向你们演示它能满足这些公理 in terms of the air, has the property that it satisfies this, 894 01:06:41,480 --> 01:06:47,080 那么你就应该认为这是CONS CAR和CDR的可行实现 then you just have to grant me that that is a possible implementation of cons, car, and cdr, 895 01:06:47,080 --> 01:06:48,700 也就可以用它们来构造其它东西了 on which I can build everything else. 896 01:06:49,640 --> 01:06:53,360 好了 让我们回过头来看看 这里将用到代换模型 Well, let's look at that. And this will be practice in the substitution model. 897 01:06:53,480 --> 01:07:00,280 我们该怎么来说清这个过程呢? How would I actually, How could we check this? 898 01:07:00,280 --> 01:07:03,180 我们好像知道点怎么做 这都是同一个代换模型 We sort of know how to do that. It's just the same substitution model. 899 01:07:04,640 --> 01:07:09,320 我们来瞧瞧 首先 我们考虑(CAR (CONS 37 49))是什么 Let's look. We start out, and we say, what's car of cons of 37 and 49? 900 01:07:10,800 --> 01:07:13,140 接下来该怎么做? CONS只是一个过程 What do we do? Cons is some procedure. 901 01:07:15,600 --> 01:07:18,760 它的值也就是一个有A和B的过程 Its value is cons was a procedure of a and b. 902 01:07:19,580 --> 01:07:22,820 CONS返回的是一个过程体 The thing returned by cons is its procedure body 903 01:07:23,140 --> 01:07:26,820 该过程体的参数被37和49代换掉了 with 37 and 49 substituted for the parameters. 904 01:07:26,820 --> 01:07:31,080 用37代换A 用49代换B It'll be 37 substituted for a and 49 substituted for b. 905 01:07:32,520 --> 01:07:36,700 所以这个表达式和这个表达式的意思是相同的 So this expression has the same meaning as this expression. 906 01:07:36,720 --> 01:07:40,980 CAR没变 而CONS被代换为了一个以LAMBDA开头的表达式 Its car of, and the body of cons was this thing that started with lambda. 907 01:07:42,780 --> 01:07:47,100 这里PICK是另外一个变量 如果PICK为1的话 And it says, so if pick is equal to 1, where pick is this other argument, 908 01:07:47,260 --> 01:07:50,420 如果PICK等于1 那么就返回37 也就是A的值 if pick is equal to 1, it's 37, that's where a was, 909 01:07:51,120 --> 01:07:53,460 如果PICK等于2 那么就返回49 and if pick is equal to 2, it's 49. 910 01:07:54,820 --> 01:07:55,780 这是代换的第一步 So that's the first step. 911 01:07:55,780 --> 01:07:58,620 我只是进行了机械地代换 I'm just going through mechanical substitution. 912 01:07:59,120 --> 01:08:00,560 注意了 这也是本课的一大要点 And remember, at this point in the course, 913 01:08:00,560 --> 01:08:02,220 当你搞不清楚情况的时候 if you're confused about what things mean, 914 01:08:02,480 --> 01:08:04,820 就按照代换模型进行机械地代换 go mechanically through the substitution model. 915 01:08:05,100 --> 01:08:06,320 那么 这又会被归约为什么呢? Well, what is this reduced to? 916 01:08:07,620 --> 01:08:15,700 而CAR则是 把给定的参数 也就是这些 应用于1 Car said, take your, take your argument, which in this case is this, and apply it to 1. 917 01:08:15,780 --> 01:08:17,120 这也就是CAR的定义 That was the definition of car. 918 01:08:17,700 --> 01:08:22,000 考虑CAR 将其展开 我将得到 So if I look at car, if I do that, the answer is, 919 01:08:22,000 --> 01:08:26,000 就是将CAR的参数 将其应用于1 well, it's that argument, this was the argument to car, applied to 1. 920 01:08:29,180 --> 01:08:30,440 这又是什么意思呢? Well, what does that mean? 921 01:08:30,780 --> 01:08:35,320 在这里的代码体中 我拿1来替换PICK I take 1, and I substitute it in the body here for this value of pick, 922 01:08:35,540 --> 01:08:38,340 也就是这个变量的名字 我们得到什么呢? which is the name of the argument, what do I get? 923 01:08:39,560 --> 01:08:42,840 如果1等于1 那么就得到37 Well, I get the thing that says if 1 equals 1 it's 37, 924 01:08:43,080 --> 01:08:45,620 如果1等于2 那么就得到49 当然答案就是37 and if 1 equals 2 it's 49, so the answer's 37. 925 01:08:46,280 --> 01:08:50,660 类似的 如果是CDR的话 也就是将其应用于2 则得到49 And similarly, if I'd taken cdr, that would apply it to 2, and I'd get 49. 926 01:08:51,460 --> 01:08:56,280 正如你们所见 我给你们演示了相当怪异的实现 So you see, what I've demonstrated is that that completely weird implementation 927 01:08:56,280 --> 01:08:58,740 完全符合这些公理的CONS CAR CDR实现 of cons, car, and cdr, satisfies the axioms. 928 01:08:59,820 --> 01:09:04,360 事实上 用这种方法来构建Lisp中所有的数据对象 非常有效 So it's a perfectly valid way of building, in fact, all of the data objects we're going to see in Lisp. 929 01:09:05,320 --> 01:09:08,760 如果你愿意的话 这一切东西 都可以凭空构建 So they all, if you like, can be built on sort of existential nothing. 930 01:09:09,640 --> 01:09:11,600 就目前为止 你也知道它也正是这样工作的 And as far as you know, that's how it works. 931 01:09:13,880 --> 01:09:16,180 你无法分辨 你如果只是 You couldn't tell. If all you're ever going to do 932 01:09:16,960 --> 01:09:19,860 将它们用CONS构建成序对 再用CAR和CDR取出来 with pairs is construct them with cons and look at them with car and cdr, 933 01:09:19,860 --> 01:09:22,160 你可能还无法分辨它是如何运作的 you couldn't possibly tell how this thing works. 934 01:09:23,920 --> 01:09:26,180 现在 如果我这样说 你们可能会觉得好受一点 Now, it might give you a sort of warm feeling inside if I say, 935 01:09:26,180 --> 01:09:29,840 我说 实际上因为种种原因 Lisp中有几个基本过程 well, yeah, in fact, for various reasons there happens to be a primitive 936 01:09:30,360 --> 01:09:33,200 叫做CONS CAR和CDR 这样不会太吓着你们 called cons, car, and cdr, and if it's too scary, 937 01:09:33,200 --> 01:09:35,820 内部太难以理解 你就不必深究其内部了 if this kind of stuff is too scary, you don't have to look inside of it. 938 01:09:36,440 --> 01:09:37,660 这样可能会使你感觉好点 So that might make you feel better, 939 01:09:38,720 --> 01:09:40,900 但关键点就是 它真是照这样运作的 but the point is, it really could work this way, 940 01:09:41,800 --> 01:09:43,920 但是这对系统而言毫无区别 and it wouldn't make any difference to the system at all. 941 01:09:46,280 --> 01:09:49,740 从某种意义上来说 建立数据抽象不需要数据 So in some sense, we don't need data at all to build these data abstractions. 942 01:09:51,380 --> 01:09:53,280 我们可以用过程来完成所有事儿 We can do everything in terms of procedures. 943 01:09:54,500 --> 01:09:56,320 恩 那么 为什么我这样做吓到你们了呢? OK, well, why did I terrify you in this way? 944 01:09:57,120 --> 01:09:59,880 首先 我想强化大家对抽象的认识 First, I really want to reinforce this idea of abstraction, 945 01:10:01,820 --> 01:10:03,960 也就是我们可以抽象地做事儿 that you really can do these things abstractly. 946 01:10:05,880 --> 01:10:12,000 其次 我给大家介绍了将在本课中不断体现的理念 Secondly, I want to introduce an idea we're going to see more and more of in this course, 947 01:10:13,740 --> 01:10:18,160 也就是数据和过程的边界将变得越来越模糊 which is we're going to blur the line between what's data and what's a procedure. 948 01:10:19,820 --> 01:10:24,600 看到了吧 这个有趣的CONS实现结果是 See, in this funny implementation it turned out that cons of something 949 01:10:24,600 --> 01:10:28,640 我们以为是数据 结果却是用一个过程来表示 happened to be represented in terms of a procedure, even though we think of it as data. 950 01:10:31,560 --> 01:10:33,400 虽然这里只是一个数学技巧 While here that's sort of a mathematical trick, 951 01:10:34,260 --> 01:10:36,260 当我们将看到的则是 but one of the things we'll see is that 952 01:10:36,260 --> 01:10:39,500 一些非常重要的编程技巧 a lot of the very important programming techniques that we're going to get to 953 01:10:40,480 --> 01:10:42,960 都非常依赖于 sort of depend very crucially 954 01:10:43,280 --> 01:10:48,280 模糊这条传统的界定数据和过程的分界线 on blurring this traditional line between what you consider a procedure and what you consider data. 955 01:10:48,620 --> 01:10:50,680 尤其在下次课 我们将接触得越来越多 We're going to see more and more of that, especially next time. 956 01:10:52,580 --> 01:10:53,440 好了 有什么问题吗? OK, questions? 957 01:10:54,720 --> 01:10:59,800 学生:如果让系统打印A 会输出什么呢? AUDIENCE: If you asked the system to print a, what would be the result? 958 01:11:00,260 --> 01:11:04,960 教授:你想问 如果我让系统打印A PROFESSOR: The question is, what would happen if I asked the system to print a. 959 01:11:04,960 --> 01:11:07,900 看看这种表示法 你就知道答案了 Given this representation, you already know the answer. 960 01:11:09,620 --> 01:11:17,980 这是一个复合过程A 像上次一样 The answer is compound procedure a, just like last time. 961 01:11:21,280 --> 01:11:22,600 系统返回“复合过程” It'd say compound procedure. 962 01:11:25,260 --> 01:11:28,280 说着说得更详细一点 像“复合LAMBDA过程”等等 It might say a little bit more. It might say compound procedure lambda or something or other, 963 01:11:29,240 --> 01:11:32,360 这得看我是如何给它命名的 但它归根是个过程 depending on details of how I named it. But it's a procedure. 964 01:11:32,800 --> 01:11:36,520 唯一的解释就是我并没有特别地告诉系统 And the only reason for that is I haven't told the system anything special 965 01:11:37,320 --> 01:11:38,700 如何打印这些东西 about how to print such things. 966 01:11:39,900 --> 01:11:44,840 实际上 根据系统中CONS实现的不同 Now, it's in fact true that with the actual implementation of cons that to be built in the system, 967 01:11:44,840 --> 01:11:45,880 它会打印出不同的东西 it would print something else. 968 01:11:47,000 --> 01:11:48,500 它会打印出这是个序对 It would print, say, this is a pair. 969 01:11:53,200 --> 01:11:55,060 学生:你定义CONS后 AUDIENCE: When you define cons, 970 01:11:57,600 --> 01:11:59,640 你给它传递了几个值 and then you pass it into values, 971 01:12:00,760 --> 01:12:05,920 它怎么知道该去哪里找这些值 毕竟你可以多次使用CONS how does it know where to look for the cons, because you can use cons over and over again? 972 01:12:06,380 --> 01:12:12,100 它是怎么知道我们希望取出的a和b存储在哪里呢? How does it know where to look to know which a and b it's supposed to pull back out? 973 01:12:12,300 --> 01:12:17,060 可能表达得不是很正确 我只是想问它都存放在哪儿? I don't know if I'm expressing that quite right. Where is it stored? 974 01:12:18,720 --> 01:12:20,040 教授:嗯 来想想 PROFESSOR: OK, the question is, 975 01:12:22,800 --> 01:12:28,020 我先用37和49来构造一个序对 在用1和2又构造一个 I sort of have a cons with a 37 and a 49, and I might make another cons with a 1 and a 2, 976 01:12:28,340 --> 01:12:30,800 有一个参数为A 有一个参数为B and I might have one called a, and I might have one called b. 977 01:12:31,560 --> 01:12:34,500 问题是 系统又是怎么知道的呢?它为什么没有弄混淆呢? And the question is, how does it know? And why don't they get confused? 978 01:12:35,280 --> 01:12:37,220 这个问题非常好 And that's a very good question. 979 01:12:40,440 --> 01:12:43,580 首先 你需要认定过程是一种对象 See, you have to really believe that the procedures are objects. 980 01:12:44,760 --> 01:12:47,920 这就像是说——让我来换个更简单的例子 It's sort of like saying-- let's try another simpler example. 981 01:12:49,140 --> 01:12:50,980 我想去求3的平方根 Suppose I ask for the square root of 3. 982 01:12:55,560 --> 01:12:56,820 我这里用5的平方根来演示 So I asked for the square root of 5, 983 01:12:57,920 --> 01:13:01,560 我也可以求20的平方根 and then I ask for the square of 20. 984 01:13:06,120 --> 01:13:10,080 这可能一点也不困扰你 我可以将SQRT应用于5 You're probably not the least bit bothered that I can take square root and apply it to 5, 985 01:13:10,080 --> 01:13:13,080 也可以将其应用于20 and then I can take square root and apply it to 20. 986 01:13:14,580 --> 01:13:18,600 你知道这没问题 它分得清楚应用于哪个 And there's sort of no issue, gee, doesn't it get confused about whether it's working on 5 or 20? 987 01:13:19,320 --> 01:13:25,120 你觉得过程应该是做些事 所以没有问题 There's no issue about that because you're thinking of a procedure which goes off and does something. 988 01:13:26,180 --> 01:13:28,480 从某种方面来说 你问了我一个同样的问题 Now, in some sense you're asking me the same question. 989 01:13:30,240 --> 01:13:31,580 但它使你困惑 But it's really bothering you, 990 01:13:31,580 --> 01:13:33,580 这确实很容易让人困惑 and it's bothering you for a really good reason. 991 01:13:34,240 --> 01:13:38,080 因为我当我这样写的时候 你知道这是一个过程 Because when I write that, you're saying gee, this is, I know, sort of a procedure. 992 01:13:38,080 --> 01:13:41,520 但它不是一个能运行的过程 而是一个定义在这里的过程 But it's not a procedure that's just running. It's just sort of a procedure sitting there. 993 01:13:42,220 --> 01:13:46,380 那这个过程为什么时而能有37和49 And how can it be that sometimes this procedure has 37 and 49, 994 01:13:46,380 --> 01:13:50,680 可能又有一个过程有5和6 但它们为什么不搞混呢 and there might be another one which has 5 and 6 in there, and why don't they get confused? 995 01:13:52,140 --> 01:13:56,200 这里面就有一个非常重要的东西困扰了你 So there's something very, very important that's bothering you. 996 01:13:58,640 --> 01:14:00,420 这东西非常关键 And it's really crucial to what's going on. 997 01:14:00,760 --> 01:14:06,740 这就是 过程并不仅仅是动作的集合 It's, we're suddenly saying that procedures are not just the act of doing something. 998 01:14:07,980 --> 01:14:10,920 过程是概念实体 是对象 Procedures are conceptual entities, objects, 999 01:14:11,400 --> 01:14:16,320 如果我(CONS 37 49) 那么就构建好了一个特定的过程 and if I built cons of 37 and 49, that's a particular procedure that sits there. 1000 01:14:17,680 --> 01:14:20,760 这和(CONS 3 4)的那个不一样 And it's different from cons of 3 and 4. 1001 01:14:21,120 --> 01:14:22,640 这又是一个创立好的过程了 That's another procedure that sits there. 1002 01:14:22,640 --> 01:14:23,840 学生:它们都是独立存在的 AUDIENCE: Both of them exist independently. 1003 01:14:23,840 --> 01:14:25,120 教授:对 独立存在 PROFESSOR: And exists independently. 1004 01:14:25,280 --> 01:14:27,840 学生:可以通过CAR和CDR被引用 AUDIENCE: And they both can be referenced by car and cdr. 1005 01:14:28,040 --> 01:14:30,040 教授:它们都可以通过CAR和CDR被引用。 PROFESSOR: And they both would be referenced by car and cdr. 1006 01:14:30,040 --> 01:14:37,420 我可以增加这个 也可以增加那个 Just like I could increment this, and I could increment that. 1007 01:14:37,900 --> 01:14:41,380 它们都是对象 这也是我们需要的 They're objects. And that's sort of where we're going. 1008 01:14:41,380 --> 01:14:43,320 而你之所以这样问 正是体现了 See, the fact that you're asking the question shows that 1009 01:14:43,320 --> 01:14:47,400 你开始思考它蕴含的东西了 you're really starting to think about the implications of what's going on. 1010 01:14:47,400 --> 01:14:51,520 过程不仅仅只是说做某件事的行为 It's the difference between saying a procedure is just the act of doing something. 1011 01:14:52,620 --> 01:14:55,360 任何过程都是一个存在着的真实对象 And a procedure is a real object that has existence. 1012 01:14:55,960 --> 01:14:57,580 学生:也就是说过程在被构建时 AUDIENCE: So when the procedure gets built, 1013 01:14:58,040 --> 01:15:00,960 A和B的确切值就被代换进去了 the actual values are now substituted for a and b-- 1014 01:15:01,580 --> 01:15:02,020 教授:是的 PROFESSOR: That's right. 1015 01:15:02,020 --> 01:15:04,200 学生:那些以LAMBDA形式存在的过程 AUDIENCE: And then that procedure exists as lambda, 1016 01:15:04,200 --> 01:15:06,200 而PICK实际上已经被传递进去了 and pick is what's actually passed in. 1017 01:15:07,360 --> 01:15:09,580 教授:是的 当CONS过程被调用时 PROFESSOR: Yes, when cons gets called, 1018 01:15:09,580 --> 01:15:13,200 CONS就返回了一个新构造好的过程 and the result of cons is a new procedure that's constructed, 1019 01:15:13,620 --> 01:15:15,740 而这个新过程有一个叫做PICK的参数 that new procedure has an argument that's called pick. 1020 01:15:17,120 --> 01:15:18,460 学生:但是就不再有A和B了 AUDIENCE: But it no longer has an a and b. 1021 01:15:18,460 --> 01:15:20,520 A和B的确切值在那时就被传递进去了 The a and b are the actual values that are passed through. 1022 01:15:20,520 --> 01:15:23,120 教授:根据代换模型 是这样的 PROFESSOR: And it has-- right, according to the substitution model, 1023 01:15:23,120 --> 01:15:25,660 现在它不再具有这些任意的名字A和B what it now has is not those arbitrary names a and b, 1024 01:15:25,960 --> 01:15:28,480 取而代之的则是37和49 it somehow has that 37 and 49 in there. 1025 01:15:31,200 --> 01:15:33,100 但你是对的 把这件事想清楚很困难 But you're right, that's a hard thing to think about it, 1026 01:15:33,100 --> 01:15:35,240 这同我们之前对过程的认识有所不同 and it's different from the way you've been thinking about procedures. 1027 01:15:36,100 --> 01:15:40,880 学生:如果我再次调用(CONS 37 49) 是否得到了一个不同的[听不清] AUDIENCE: And if I have again cons of 37 and 49, it's a different [UNINTELLIGIBLE]? 1028 01:15:40,880 --> 01:15:47,860 教授:如果你再次调用(CONS 37 49) PROFESSOR: And if you make another cons of 37 and 49, 1029 01:15:51,420 --> 01:15:53,700 你就陷入了一个深刻的哲学问题 you're into a wonderful philosophical problem, 1030 01:15:53,700 --> 01:15:58,500 这个将是我们整个课程中段将讨论的问题 which is going to be what the lecture about halfway through this course is about. 1031 01:15:59,720 --> 01:16:02,780 也就是说 我调用(CONS 37 49) 然后我再调用一次 Which is, if I cons 37 and 49, and I do it again, 1032 01:16:02,980 --> 01:16:05,460 这两者是同一个东西还是不同的东西呢? is that the same thing, or is it a different thing? 1033 01:16:06,180 --> 01:16:08,720 我又该如何区别它们呢?这又在什么时候产生影响呢? And how could you tell? And when could it possibly matter? 1034 01:16:09,920 --> 01:16:19,620 这就像说 这个和这个是同一个东西么? And that's sort of like saying, is that the same thing as this? 1035 01:16:20,840 --> 01:16:22,440 那这个和这个呢? Or is this the same thing as that? 1036 01:16:23,480 --> 01:16:24,660 这都是同一种问题 It's the same kind of question. 1037 01:16:24,660 --> 01:16:27,520 这将是一个非常非常深刻的问题 And that's a very, very deep question. 1038 01:16:27,520 --> 01:16:30,520 我没法在一小时内讲清楚 但我们以后会讨论 And I can't answer in less than an hour. But we will. 1039 01:16:37,600 --> 01:16:40,940 MIT OpenCourseWare http://ocw.mit.edu 1040 01:16:41,100 --> 01:16:47,660 本项目主页 https://github.com/FoOTOo/Learning-SICP ================================================ FILE: SrtCN/lec3a.srt ================================================ 1 00:00:00,000 --> 00:00:03,120 Learning-SICP学习小组 倾情制作 2 00:00:04,400 --> 00:00:08,026 翻译&&时间轴:邓雄飞(Dysprosium)、Savior Michael 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:08,060 --> 00:00:12,160 特别感谢:裘宗燕教授 4 00:00:12,370 --> 00:00:16,320 Henderson-Escher的例子 Henderson-Escher Example 5 00:00:20,940 --> 00:00:23,860 上节课我们讨论了复合数据 PROFESSOR: Well, last time we talked about compound data, 6 00:00:24,946 --> 00:00:29,740 其中有两个关键点 and there were two main points to that business. 7 00:00:29,740 --> 00:00:32,480 首先 有一种数据抽象的方法学 First of all, there was a methodology of data abstraction, 8 00:00:32,940 --> 00:00:39,100 其要点是将数据的使用 and the point of that was that you could isolate the way that data objects are used 9 00:00:40,060 --> 00:00:41,500 和表示分离开来 from the way that they're represented: 10 00:00:41,550 --> 00:00:45,200 比如说 我们可以与一个叫做George的人“签订契约” this idea that there's this guy, George, and you go out make a contract with him; 11 00:00:45,200 --> 00:00:47,480 让他负责数据的表示 and it's his business to represent the data objects; 12 00:00:47,480 --> 00:00:49,360 而当我们使用这些数据的时候 and at the moment you are using them, 13 00:00:49,360 --> 00:00:51,360 不需要替George操心他是如何完成数据表示的工作的 you don't think about George's problem. 14 00:00:51,980 --> 00:00:58,440 其次 Lisp中有一种特殊的方式把对象连接在一起 And then secondly, there was this particular way that Lisp has of gluing together things 15 00:00:58,940 --> 00:01:00,520 就是构成“序对” to form objects called pairs, 16 00:01:00,520 --> 00:01:03,540 这是通过CONS CAR CDR实现的 and that's done with cons, car and cdr. 17 00:01:03,540 --> 00:01:07,160 而CONS CAR CDR本身是如何实现的 这不重要 And the way that cons, car and cdr are implemented is basically irrelevant. 18 00:01:07,160 --> 00:01:10,020 George的任务就是如何构建这些东西 That's sort of George's problem of how to build those things. 19 00:01:10,020 --> 00:01:11,160 可以将它们实现为基本过程 It could be done as primitives. 20 00:01:11,160 --> 00:01:13,800 也可以利用一些奇怪的过程来实现 It could be done using procedures in some weird way, 21 00:01:13,800 --> 00:01:15,220 但是我们不用操心这些 but we're not going to worry about that. 22 00:01:16,020 --> 00:01:19,660 举个例子 我们来看下有理数算术 And as an example, we looked at rational number arithmetic. 23 00:01:19,660 --> 00:01:21,500 看下向量 We looked at vectors, 24 00:01:21,500 --> 00:01:24,180 我们简单回顾一下向量 and here's just a review of vectors. 25 00:01:24,180 --> 00:01:27,640 这里有个对两个向量求和的操作 Here's an operation that takes the sum of of two vectors, 26 00:01:27,640 --> 00:01:33,320 我们想要把向量v1和v2相加 so we want to add this vector, v1, and this vector, v2, and we get the sum. 27 00:01:34,460 --> 00:01:40,840 它们的和也是一个向量 其坐标是两个向量的坐标的和 And the sum is the vector whose coordinates are the sum of the coordinates of the pieces you're adding. 28 00:01:41,280 --> 00:01:45,660 所以 定义(+VECT V1 V2)为 So I can say, to define make-vect, right, to add two vectors 29 00:01:45,660 --> 00:01:51,720 我创建一个向量 其X坐标是两向量X坐标的和 I make a vector, whose x coordinate is the sum of the two x coordinates, 30 00:01:52,100 --> 00:01:54,820 而Y坐标是两向量Y坐标的和 and whose y coordinate is the sum of the two y coordinates. 31 00:01:56,060 --> 00:02:04,100 类似地 我们也可以定义一个缩放向量的操作 And then similarly, we could have an operation that scales vectors, 32 00:02:04,940 --> 00:02:12,660 这里的SCALE过程是用数字S乘以向量V so here's a procedure scale that multiplies a vector, v, by some number, s. 33 00:02:13,080 --> 00:02:16,140 向量V从这里到这里 So here's v, v goes from there to there 34 00:02:16,320 --> 00:02:20,220 我放大V 得到了与原来同向但更长的向量 and I scale v, and I get a vector in the same direction that's longer. 35 00:02:21,560 --> 00:02:24,260 为了缩放向量 我需要通过缩放坐标来实现 And again, to scale a vector, I multiply the successive coordinates. 36 00:02:24,260 --> 00:02:30,220 所以我构建了一个向量 它的X坐标是原向量X坐标的S倍 So I make a vector, whose x coordinate is the scale factor times the x coordinate 37 00:02:30,560 --> 00:02:33,540 同时 它的Y坐标是原来向量Y坐标的S倍 and whose y coordinate is the scale factor times the y coordinate. 38 00:02:33,540 --> 00:02:40,280 上述两个操作都是利用了向量的表示来实现的 So those are two operations that are implemented using the representation of vectors. 39 00:02:40,280 --> 00:02:45,020 而这种向量的表示 我们则可以用序对来实现 And the representation of vectors, for instance, is something that we can build in terms of pairs. 40 00:02:45,340 --> 00:02:51,280 因此George需要为我们提供MAKE-VECTOR、XCOR和YCOR So George has gone out and implemented for us make-vector and x coordinate and y coordinate, 41 00:02:53,020 --> 00:02:57,980 他可以使用CONS CAR CDR来实现 and this could be done, for instance, using cons,car and cdr; 42 00:02:58,880 --> 00:03:06,780 但是注意 我这里用了一个略微不同的方式 and notice here, I wrote this in a slightly different way. 43 00:03:08,040 --> 00:03:11,000 这个过程我们之前看过 其中我讲过 The procedures we've seen before, I've said something like 44 00:03:11,140 --> 00:03:16,220 (MAKE-VECTOR X Y)也就是(CONS X Y) say, make-vector of x and y: cons of x and y. 45 00:03:16,220 --> 00:03:17,980 而我这里简单定义MAKE-VECTOR为CONS And here I just wrote make-vector cons. 46 00:03:17,980 --> 00:03:20,480 这就与之前有些不同了 And that means something slightly different. 47 00:03:20,480 --> 00:03:26,220 之前我们我们把MAKE-VECTOR定义为需要两个参数的过程 Previously we'd say, define make-vector to be a procedure that takes two arguments, x and y, 48 00:03:26,220 --> 00:03:28,040 效果是(CONS X Y) and does cons of x and y. 49 00:03:28,040 --> 00:03:34,120 这里 我就把MAKE-VECTOR定义为CONS And here I am saying define make-vector to be the thing that cons is, 50 00:03:35,180 --> 00:03:39,660 这跟我们之前使用的方式基本上是一样的 and that's almost the same as the other way we've been writing things. 51 00:03:39,660 --> 00:03:46,580 大家要习惯于“过程也是对象 而且你可以给他们命名”这种想法 And I just want you to get used to the idea that procedures can be objects, and that you can name them. 52 00:03:48,700 --> 00:03:51,800 这些就是向量的表示方法了 OK, well there's vector representation, and again, 53 00:03:51,800 --> 00:03:55,680 如果仅仅是那样 那就太无趣了 if that was all there was to it,this would all be pretty boring. 54 00:03:57,020 --> 00:04:02,160 要记住 要点是我们不仅可以通过使用CONS将数字组合成序对 And the point is, remember, that you can use cons to glue together not just numbers to form pairs, 55 00:04:02,160 --> 00:04:04,160 也可以组合任何东西 but to glue together arbitrary things. 56 00:04:05,200 --> 00:04:11,600 例如 如果我想表示一个线段 So for instance, if we'd like to represent a line segment, 57 00:04:11,600 --> 00:04:15,640 一个以某个向量为起点的线段 say the line segment that goes from a certain vector: 58 00:04:16,060 --> 00:04:28,300 比如从向量(2,3)所代表的起点到向量(5,1)所代表的终点的线段 say, the segment from the vector 2,3 to the point represented by the vector 5,1. 59 00:04:28,300 --> 00:04:31,820 如果我们想表示这条线段 If we want to represent that line segment, 60 00:04:33,260 --> 00:04:36,200 那么我们可以构建一个序对的序对 then we can build that as a pair of pairs. 61 00:04:40,720 --> 00:04:42,940 这样我们就可以表示一条线段了 So again, we can represent line segments. 62 00:04:42,940 --> 00:04:47,340 我们可以编写一个使用CONS构造线段的构造函数 We can make a constructor that makes a segment using cons, 63 00:04:47,980 --> 00:04:51,600 以及 析取出线段起点、终点的选择函数 selects out the start of a segment, selects out the end point of the segment; 64 00:04:55,240 --> 00:04:59,760 那么如果我们剥开抽象层一探究竟 and then if we actually look at that, if we peel away the abstraction layers, 65 00:04:59,880 --> 00:05:02,100 就会发现线段不过是 序对组成的序对 and see what's that really is a pair of pairs, 66 00:05:04,660 --> 00:05:06,220 它还是一个序对 we'd say well that's a pair. 67 00:05:06,220 --> 00:05:08,220 这里有个线段 Here's the segment. 68 00:05:10,000 --> 00:05:16,720 它的CAR部分是个序对 CDR部分也是个序对 It's car, right, it's car pointer is a pair, and it's cdr is also a pair, 69 00:05:18,320 --> 00:05:25,540 它的CAR部分是由2和3构成的序对 and then what the car is--here's the car, that itself is a pair of 2 and 3. 70 00:05:26,020 --> 00:05:28,080 CDR部分则由5和1构成的序对 And similarly the cdr is a pair of 2 and 3. 71 00:05:28,160 --> 00:05:29,240 这里我再提醒大家一下 And let me remind you again 72 00:05:29,320 --> 00:05:33,460 好多人认为如果我箭头向下画的话 that a lot of people have some idea that if I'd taken this arrow and somehow 73 00:05:33,800 --> 00:05:36,900 会有其它的含意 written it to point down, that would mean something else. 74 00:05:36,980 --> 00:05:38,280 这是不对的 That's irrelevant. 75 00:05:38,580 --> 00:05:43,900 箭头指示的是对象间如何连接 它指向水平或竖直方向都是无关紧要的 It's only how these are connected and not whether this arrow happens to go vertically or horizontally. 76 00:05:47,480 --> 00:05:52,180 还要提醒一下 序对是具有闭包性质的 And again just to remind you, there was this notion of closure. 77 00:05:52,940 --> 00:06:05,620 闭包性质使我们可以构建更复杂的东西 而不仅仅是简单的序对 See, closure was the thing that allowed us to start building up complexity, that didn't trap us in pairs. 78 00:06:06,640 --> 00:06:15,240 在这里我要特别指出 在我们用CONS构建出来的序对的基础上 Particularly what I mean is the things that we make, having combined things using cons to get a pair, 79 00:06:16,440 --> 00:06:22,640 我们也可以进一步用CONS来构造更复杂的对象 those things themselves can be combined using cons to make more complicated things. 80 00:06:23,280 --> 00:06:31,980 或者用数学家的话说 Lisp中的数据对象在CONS运算下是封闭的 Or as a mathematician might say, the set of data objects in Lisp is closed under the operation of forming pairs. 81 00:06:33,820 --> 00:06:36,340 这个性质使我们能够构造更加复杂的数据对象 That's the thing that allows us to build complexity. 82 00:06:36,340 --> 00:06:38,040 这个似乎是显然的 但是要记住 And that seems obvious, but remember 83 00:06:39,060 --> 00:06:42,460 人们使用的编程语言中有很多东西并不是封闭的 a lot of the things in the computer languages that people use are not closed. 84 00:06:42,460 --> 00:06:48,060 举例来说 Basic和Fortran中的构造数组操作 就不是封闭的 So for example, forming arrays in Basic and Fortran is not a closed operation, 85 00:06:48,080 --> 00:06:51,940 因为 虽然你可以用数字、字符或字符串等来构造数组 because you can make an array of numbers or character strings or something, 86 00:06:52,040 --> 00:06:54,180 但是你不能创建数组的数组 but you can't make an array of arrays. 87 00:06:54,640 --> 00:06:56,680 当考察某种组合的方法时 And when you look at means of combination 88 00:06:57,600 --> 00:07:02,780 你应该考察该组合方法是否封闭 you should be asking yourself whether things are closed under that means of combination. 89 00:07:05,060 --> 00:07:08,260 不管怎样 因为我们可以构造序对的序对 Well in any case, because we can form pairs of pairs, 90 00:07:08,860 --> 00:07:12,780 我们就可以用序对将数据以各种各样的方式组合起来 we can start using pairs to glue things together in all sorts of different ways. 91 00:07:14,020 --> 00:07:18,260 比如我想要组合四个数 —— 1 2 3 4 So for instance if I'd like to glue together the four things, 1, 2, 3 and 4, 92 00:07:18,260 --> 00:07:19,820 我有很多方法 there are a lot of ways I can do it. 93 00:07:20,740 --> 00:07:26,120 比如 像构造线段那样 我可以构造一个序对 I could, for example, like we did with that line segment, i could make a pair 94 00:07:29,020 --> 00:07:36,880 它是((1 2) (3 4)) 对吧? that had a 1 and a 2 and a 3 and a 4, right? 95 00:07:36,880 --> 00:07:40,060 或者如果我喜欢 我可以像这样做 Or if I liked, I could do something like this. 96 00:07:40,060 --> 00:07:45,520 我构造一个序对 它的CAR部分也是一个序对 I could make a pair, whose first thing is a pair, 97 00:07:46,440 --> 00:07:53,200 这个序对的CAR部分为1 而CDR部分为由2、3构成的序对 whose car is 1, and his cdr is itself a pair that has the 2 and the 3 98 00:07:53,260 --> 00:07:55,080 最后 我把4放在这里 and then I could put the 4 up here. 99 00:07:56,920 --> 00:08:02,160 所以你可以看到 组合对象的方式有很多种 So you see, there are a lot of different ways that I can start using pairs to glue things together, 100 00:08:02,160 --> 00:08:07,740 因此就有必要建立一些统一的约定 and so it'll be a good idea to establish some kind of conventions,right, 101 00:08:07,740 --> 00:08:11,580 使我们能够用某种的通用的方式处理数据 that allow us to deal with this thing in some conventional way, 102 00:08:11,580 --> 00:08:14,000 而不用总是针对具体问题做一些生硬的选择 so we're not constantly making an ad hoc choice. 103 00:08:15,940 --> 00:08:19,040 Lisp里面就有这样一种约定 And Lisp has a particular convention 104 00:08:20,740 --> 00:08:25,820 这个约定将一系列的东西表示成一个序对组成的链 for representing a sequence of things as, essentially, a chain of pairs, 105 00:08:26,780 --> 00:08:28,180 而这样一个数据序列就叫做一个“表” and that's called a List. 106 00:08:34,720 --> 00:08:40,500 表本质上就是Lisp用来表示序列数据的一个约定而已 And what a list is is essentially just a convention for representing a sequence. 107 00:08:40,700 --> 00:08:47,380 我可以使用序对的序列来表示序列 1 2 3 4 I would represent the sequence 1, 2, 3 and 4 by a sequence of pairs. 108 00:08:48,260 --> 00:08:54,680 我把1放在这里 它的CDR指向另一个序对 I'd put 1 here and then the cdr of this would point to another pair 109 00:08:59,200 --> 00:09:01,400 这个序对的CAR部分是序列中的下一个数 whose car was the next thing in the sequence, 110 00:09:01,520 --> 00:09:03,420 并且它的CDR指向了另一个序对 and the cdr would point to another pair 111 00:09:05,440 --> 00:09:07,300 它的CAR部分是序列的再下一个数 whose car was the next thing in the sequence-- 112 00:09:07,360 --> 00:09:08,440 这个是3 so there's 3-- 113 00:09:08,440 --> 00:09:09,740 以此类推 and then another one. 114 00:09:09,740 --> 00:09:13,220 所以 序列中的每一个元素都对应着一个序对 So for each item in the sequence, I'll get a pair. 115 00:09:15,820 --> 00:09:18,320 而当这个序列中没有其它元素时,我用一个特殊的标记 And now there are no more, so I put a special marker 116 00:09:20,720 --> 00:09:22,740 来表示列表中没有元素了 that means there's nothing more in the List. 117 00:09:24,140 --> 00:09:34,640 好 这就是将序列中的元素组合起来的一种约定方式 OK, so that's a conventional way to glue things together if you want to represent a sequence, right. 118 00:09:34,640 --> 00:09:37,980 而它其实就是一堆序对 And what it is is a bunch of pairs, 119 00:09:39,400 --> 00:09:44,800 每个序对中的CAR部分就是我们想要组合到一起的元素 the successive cars of each pair are the items that you want to glue together, 120 00:09:46,000 --> 00:09:48,460 这些序对的CDR部分则指向下一个序对 and the cdr pointer points to the next pair. 121 00:09:50,020 --> 00:09:56,040 现在 如果我想要构造它 我需要向Lisp中输入 Now if I actually wanted to construct that, what I would type into Lisp is this: 122 00:09:56,620 --> 00:09:58,760 我会像这样来构造 I'd actually construct that as saying, well this thing is 123 00:09:59,220 --> 00:10:15,280 (CONS 1 (CONS 2 (CONS 3 (CONS 4 NIL)))) the cons of 1 onto the cons of 2 onto the cons of 3 onto the cons of 4 onto, well, this thing nil. 124 00:10:15,280 --> 00:10:20,000 NIL是序列末尾标志的名字 And what nil is is a name for the end of List marker. 125 00:10:20,800 --> 00:10:23,240 它是一个特殊的名字 标识以达到表的末尾 It's a special name, which means this is the end of the List. 126 00:10:26,240 --> 00:10:30,260 好 这就是如何构造一个表 OK, so that's how I would actually construct that. 127 00:10:37,546 --> 00:10:41,400 如果每次构造一个表时 都要输入像 Of course, it's a terrible drag to constantly have to write something like 128 00:10:41,453 --> 00:10:45,180 (CONS 1 (CONS 2 (CONS 3...的话 将会非常费力 the cons of 1 onto the cons of 2 onto the cons of 3, whenever you want to make this thing. 129 00:10:45,180 --> 00:10:50,100 因此Lisp提供了一种叫做LIST的操作 So Lisp has an operation that's called LIST, 130 00:10:53,700 --> 00:10:57,720 LIST其实是这种嵌套CONS的缩写 and List is just an abbreviation for this nest of conses. 131 00:10:58,960 --> 00:11:06,320 它可以让我用(LIST 1 2 3 4)来构造表 So I could say, I could construct that by saying that is the List of 1, 2, 3 and 4. 132 00:11:07,780 --> 00:11:11,740 这只是另外一种方式v一个语法糖 And all this is is another way, a piece of syntactic sugar, 133 00:11:11,940 --> 00:11:14,760 用来简便地书写嵌套的CONS a more convenient way for writing that chain of conses-- 134 00:11:14,760 --> 00:11:17,840 (CONS (CONS (CONS (CONS NIL)))) cons of cons of cons of cons of cons of cons onto nil. 135 00:11:18,480 --> 00:11:39,780 举例来说 我将构造一个表(1 2 3 4) 并把它叫做1-TO-4 So for example, I could build this thing and say, I'll define 1-TO-4 to be the List of 1, 2, 3 and 4. 136 00:11:47,960 --> 00:11:53,020 注意使用这种简便写法的结果 OK, well notice some of the consequences of using this convention. 137 00:11:53,800 --> 00:11:56,920 首先 如果我有这个表(1 2 3 4) First of all if I have this List, this 1, 2, 3 and 4, 138 00:11:57,360 --> 00:12:02,640 表的CAR把部分就是这个表的第一个元素 对吧? the car of the whole thing is the first element in the List, right. 139 00:12:04,060 --> 00:12:05,280 那么 如何获得元素2呢? How do I get 2? 140 00:12:05,280 --> 00:12:23,940 2应该是1-TO-4的CDR部分的CAR部分 Well, 2 would be the car of the cdr of this thing 1-TO-4, it would be 2, right. 141 00:12:23,980 --> 00:12:29,480 它的CDR是这个 I take this thing, I take the cdr of it, which is this much, 142 00:12:29,820 --> 00:12:31,680 而它的CAR部分是2 and the car of that is 2, 143 00:12:32,580 --> 00:12:47,420 同理 1-TO-4的CDR的CDR的CAR部分 and then similarly, the car of the cdr of the cdr of 1-TO-4, cdr, cdr, car-- 144 00:12:47,420 --> 00:12:51,360 是3 以此类推 would give me 3, and so on. 145 00:12:52,680 --> 00:12:55,840 我们来看下屏幕 Let's take a look at that on the computer screen for a second. 146 00:12:57,500 --> 00:13:11,180 我定义一个表(1 2 3 4) 命名为1-TO-4 I could come up to List, and I could type define 1-TO-4 to be the List of 1, 2, 3 and 4, right. 147 00:13:13,780 --> 00:13:21,280 我这样写 计算机返回定义完成 这个就是1-TO-4的定义 And I'll tell that to Lisp, and it says, fine, that's the definition of 1-TO-4. 148 00:13:22,300 --> 00:13:36,740 我问 比如 1-TO-4的CDR的CDR的CAR And I could say, for instance, what's the car of the cdr of the cdr of 1-TO-4, close paren, close paren. 149 00:13:38,340 --> 00:13:42,420 嗯 它是3 Right, so the car of the cdr of the cdr would be 3. 150 00:13:44,080 --> 00:13:50,080 或者我问 1-TO-4是什么 Right, or I could say, what's 1-TO-4 itself. 151 00:13:51,260 --> 00:13:57,220 Lisp输出的是用括号包围的 (1 2 3 4) And you see what Lisp typed out is 1, 2, 3, 4, enclosed in parentheses, 152 00:13:57,220 --> 00:14:02,120 用括号将表中的元素包围起来的这种记号 and this notation, typing the elements of the List enclosed in parentheses 153 00:14:02,120 --> 00:14:08,900 通常用来打印输出表示序列的序对链 is Lisp's conventional way for printing back this chain of pairs that represents a sequence. 154 00:14:08,900 --> 00:14:17,140 又比如 我问1-TO-4的CDR部分是什么 So for example, if I said, what's the cdr of 1-TO-4, 155 00:14:19,300 --> 00:14:21,120 结果是表的剩余部分 that's going to be the rest of the List. 156 00:14:21,320 --> 00:14:26,960 这是原表首元素所指向的序对 新序列从2开始 That's the thing pointed to by the first pair, which is, again, a sequence that starts off with 2. 157 00:14:28,520 --> 00:14:37,740 比如 1-TO-4的CDR的CDR部分是什么 Or for example, I go off and say, what's the cdr of the cdr of 1-TO-4; 158 00:14:43,240 --> 00:14:44,680 返回(3 4) then that's 3,4. 159 00:14:44,820 --> 00:14:59,660 或者 1-TO-4的CDR的CDR的CDR的CDR部分是什么 Or if I say, what's the cdr of the cdr of the cdr of the cdr of 1-TO-4, 160 00:15:04,740 --> 00:15:10,460 我们看一下表的尾指针 Lisp返回() and I'm down there looking at the end of List pointer itself, and Lisp prints that as just open paren, close paren. 161 00:15:10,960 --> 00:15:13,480 你们可以认为这是一个空表 You can think of that as a List with nothing in there. 162 00:15:14,120 --> 00:15:21,380 我求取 1-TO-4的CDR的CDR的CDR部分 All right, see at the end what I did there was I looked at the cdr of the cdr of the cdr of 1-TO-4, 163 00:15:21,420 --> 00:15:25,200 这就只剩下表尾指针本身 and I'm just left with the end of List pointer itself. 164 00:15:25,200 --> 00:15:27,200 它的输出是() And that gets printed as open close. 165 00:15:34,140 --> 00:15:39,980 好了 这是处理表的一种常见方式 All right, well that's a conventional way you can see for working down a List 166 00:15:41,500 --> 00:15:43,440 也就是不断地取CDR部分 by taking successive cdrs of things. 167 00:15:43,440 --> 00:15:45,000 这个叫做表的CDRING It's called cdring down a List. 168 00:15:46,640 --> 00:15:49,780 当然手写这些CDR非常费劲 And of course it's pretty much of a drag to type all those cdrs by hand. 169 00:15:49,780 --> 00:15:52,240 我们没必要这么做 我们编写程序来这么做 You don't do that. You write procedures that do that. 170 00:15:52,960 --> 00:15:59,100 事实上 Lisp中非常普遍的事情是写一些过程 And in fact one very, very common thing to do in Lisp is to write procedures that, 171 00:15:59,850 --> 00:16:06,540 表中所有元素进行某种操作 得到的是由结果构成的表 sort of, take a List of things and do something to every element in List, and return you a List of the results. 172 00:16:07,420 --> 00:16:11,920 比如 我写一个SCALE-LIST的过程 So what I mean for example, is I might write a procedure called Scale-List, 173 00:16:16,800 --> 00:16:25,240 我要用SCALE-LIST将表1-TO-4放大10倍 and Scale-List I might say I want to scale by 10 the entire List 1-TO-4, 174 00:16:26,660 --> 00:16:35,320 那么它应该返回表(10 20 30 40) and that would return for me the List 10, 20, 30, 40. 175 00:16:38,250 --> 00:16:40,250 没错 它返回一个表 Right, it returns List, and 176 00:16:44,490 --> 00:16:49,300 我们可以猜想到这当中采用了某种递归策略 well you can see that there's going to be some kind of recursive strategy for doing it. 177 00:16:49,300 --> 00:16:51,300 我应该如何编写这个过程呢? How would I actually write that procedure? 178 00:16:52,520 --> 00:16:59,800 如果要构建一个每个元素都乘以10的列表 The idea would be, well if you'd like to build up a List where you've multiplied every element by 10, 179 00:17:00,440 --> 00:17:04,840 需要做的是—假设已经得到了结果表的剩余元素 what you'd say is well you imagine that you'd taken the rest of the List-- 180 00:17:05,860 --> 00:17:08,420 也就是表的CDR部分 right, the thing represented by the cdr of the List, 181 00:17:08,420 --> 00:17:14,160 这个子表中的每个元素都是原来元素乘以10 and suppose I'd already built a List where each of these was multiplied by 10-- 182 00:17:16,060 --> 00:17:19,680 这是SCALE-LIST对表CDR部分作用的结果 that would be Scale-List of the cdr of the List. 183 00:17:20,120 --> 00:17:23,820 我需要做的 就只有用表的CAR部分乘以10 And then all I have to do is multiply the car of the List by 10, 184 00:17:24,890 --> 00:17:27,240 然后用CONS将它和剩余部分连接起来 并返回这个列表 and then cons that onto the rest, and I'll get a List. 185 00:17:29,020 --> 00:17:33,090 类似地 为了缩放子表 我得先缩放子表的CDR部分 Right and then similarly, to have scaled the cdr of the List, I'll scale the cdr of that 186 00:17:33,300 --> 00:17:36,200 并将其与2*10连接起来 cons onto that 2 multiplied by 10. 187 00:17:36,420 --> 00:17:41,160 最终 当我处理到表尾时 这里就只剩表尾指针了 And finally when I get all the way down to the end, and I only have this end of List pointer. 188 00:17:41,720 --> 00:17:45,280 它叫做NIL 我就直接返回表尾指针 All right, this thing whose name is nil-- well I just returned an end of List pointer. 189 00:17:45,540 --> 00:17:47,680 所以这就是这个过程的递归策略 So there's a recursive strategy for doing that. 190 00:17:47,680 --> 00:17:50,520 这个过程就是这样 Here's the actual procedure that does that. 191 00:17:50,960 --> 00:17:55,040 这个例子就是对表做CDRING操作的通用策略 Right, this is an example of the general strategy of cdr-ing down a List and 192 00:17:55,660 --> 00:17:58,240 也就是所谓的“通过CONS组合结果” so called cons-ing up the result, right. 193 00:17:58,240 --> 00:18:06,040 那么 对表L缩放S倍 我该如何做呢? So to Scale a List l by some scale factor s, what do I do? 194 00:18:06,040 --> 00:18:10,400 首先得做判断 Lisp中有个叫NULL?的谓词 Well there's a test, and Lisp has the predicate called null. 195 00:18:10,400 --> 00:18:13,220 NULL?判断对象是否为表尾 Null means is this thing the end of List pointer, 196 00:18:13,900 --> 00:18:17,160 或者说 对象是否为空表 or another way to think of that is are there any elements in this List, right. 197 00:18:18,170 --> 00:18:23,000 任何情况下 当我处理到表尾时 我就将其返回 But in any case if I'm looking at the end of List pointer, then I just return the end of List pointer. 198 00:18:23,650 --> 00:18:24,600 简单地返回NIL I just return nil, 199 00:18:24,940 --> 00:18:35,140 否则 我就用CONS把列表中的第一个元素经过操作(缩放)后的结果 otherwise I cons together the result of doing what I'm going to do to the first element in the List, 200 00:18:35,540 --> 00:18:39,290 就是说 取L的CAR部分 然后用它乘以S namely taking the car of l and multiplying it by s, 201 00:18:40,360 --> 00:18:46,340 然后我就用CONS将这个结果 与用递归形式缩放后的表的剩下部分 连接在一起 and I cons that onto recursively scaling the rest of the List. 202 00:18:49,980 --> 00:18:52,180 再说一次 总体的思想是 OK, so again, the general idea is that you 203 00:18:52,220 --> 00:18:56,090 你要用递归的方式处理表中的剩余元素 即表的CDR部分 you recursively do something to the rest of the List, to the cdr of the List, 204 00:18:56,480 --> 00:19:01,160 然后你用CONS将那部分的结果 与经过处理后的表的第一个元素连接在一起 and then you cons that onto actually doing something to the first element of the List. 205 00:19:01,160 --> 00:19:05,180 当你处理到结尾的时候 返回表尾标志NIL When you get down to the end here, you return the end of List pointer, 206 00:19:07,340 --> 00:19:11,360 这就是对一个表里的数据做某种操作的通用模式 and that's a general pattern for doing something to a list. 207 00:19:14,053 --> 00:19:19,520 现在 你们应该清楚知道这样一个事实 Well of course you should know by now that the very fact 208 00:19:19,530 --> 00:19:22,620 也就是我不必额外为这种基本模式额外编写过程 that there's a general pattern there means I shouldn't be writing this procedure at all. 209 00:19:22,620 --> 00:19:24,900 我要做的事情就是写一个过程 What I should do is write a procedure 210 00:19:24,900 --> 00:19:26,320 这是这个基本模式 that's the general pattern itself 211 00:19:26,800 --> 00:19:30,300 对表中的元素执行操作 并以表的形式返回结果 that says, do something to everything in the List and define this thing in terms of that. 212 00:19:30,680 --> 00:19:32,300 好了 我们定义一些高阶过程 Right, make some higher order procedure, 213 00:19:32,320 --> 00:19:35,180 我们定义一个叫MAP的高阶过程 来完成这些操作 and here's the higher order procedure that does that. It's called MAP, 214 00:19:36,730 --> 00:19:43,170 MAP以表L和过程P为参数 and what MAP does is it takes a List, takes a List l, and it takes a procedure p, 215 00:19:44,920 --> 00:19:51,080 并返回对表L中每个元素应用过程P后得到的新表 and it returns the List of the elements gotten by applying p to each successive element in the List. 216 00:19:51,810 --> 00:19:55,400 这个新表里的元素是(P E1) (P E2) ... 到(P En) All right, so p of e1, p of e2, p of en. 217 00:19:55,640 --> 00:20:01,540 所以我指的就是对一个表做这样一种变换:将P应用到表的每一个元素上 Right, so I think of taking this List and transforming it by applying p to each element. 218 00:20:02,520 --> 00:20:07,080 你们看到的这些过程正是我提到的通用策略 And you see all this procedure is is exactly the general strategy I said. 219 00:20:07,080 --> 00:20:09,080 我们用它写乘以10的过程 Instead of multiply by 10, it's do the procedure. 220 00:20:09,080 --> 00:20:11,640 如果表是空的 则返回NIL If the List is empty, return nil. 221 00:20:11,860 --> 00:20:16,600 否则 对表的首元素应用P Otherwise, apply p to the first element of the List. 222 00:20:17,140 --> 00:20:18,740 将P应用于L的CAR部分 Right, apply p to car of l, 223 00:20:19,300 --> 00:20:25,400 然后连接它和将P应用于表CDR部分中的剩余元素得到的子表连接起来 and cons that onto the result of applying p to everything in the cdr of the List, 224 00:20:25,610 --> 00:20:28,840 这就是一个通用过程——MAP so that's a general procedure called MAP. 225 00:20:29,860 --> 00:20:39,040 我们可以用MAP来定义SCALE-LIST And I could define Scale-List in terms of MAP. 226 00:20:39,040 --> 00:20:41,040 我给你们展示一下 Let me show you that first. 227 00:20:43,460 --> 00:20:52,500 SCALE-LIST就是对表MAP一个特定的过程 But I could say Scale-List is another way to define it is just MAP along the List by the procedure, 228 00:20:52,500 --> 00:20:55,540 这个过程需要一个参数 返回给定参数乘以S的结果 which takes an item and multiplies it by s. 229 00:20:58,960 --> 00:21:01,900 所以我思考缩放表这个过程的正确方式应该是 Right, so this is really the way I should think about scaling the List, 230 00:21:02,120 --> 00:21:07,400 将这种递归实质实现为通用策略 而不是一个具体针对的过程 build that actual recursion into the general strategy, not to every particular procedure I write. 231 00:21:07,400 --> 00:21:11,280 当然 这样做的意义之一是 是你会开始发现共性 And of course, one of the values of doing this is that you start to see commonality. 232 00:21:12,160 --> 00:21:15,020 我们正在掌握使用通用模式 Right, again you're capturing general patterns of usage. 233 00:21:15,960 --> 00:21:31,180 比如 (MAP SQUARE 1-TO-4) 返回(1 4 9 16) For instance, if I said MAP, the square procedure, down this List 1-TO-4, then I'd end up with 1, 4, 9 and 16. 234 00:21:32,480 --> 00:21:37,170 对这个表做映射 Right, or if I said MAP down this List, 235 00:21:37,570 --> 00:21:46,320 用(LAMBDA (X) (+ X 10))映射表1-TO-4 lambda of x plus x 10, if I MAP that down 1-TO-4, 236 00:21:49,680 --> 00:21:52,860 我让表的每个元素都加了10 then I'd get the List where everything had 10 added to it: 237 00:21:53,340 --> 00:21:58,170 也就是得到了(11 12 13 14) right, so I'd get 11,12, 13, 14. 238 00:22:00,560 --> 00:22:05,760 我们看到对表中每个元素做操作是一种非常普遍的想法 And you can see that's going to be a very, very common idea: doing something to every element in the List. 239 00:22:08,660 --> 00:22:12,220 而大家需要思考如何编写MAP的迭代版本 One thing you might think about is writing MAP in an iterative style. 240 00:22:12,220 --> 00:22:16,040 我碰巧写的是一个递归版本 The one I wrote happens to evolve a recursive process, 241 00:22:16,360 --> 00:22:19,100 但是我们也可以很容易地把它改成迭代过程 but we could just as easily have made one that evolves an iterative process. 242 00:22:19,100 --> 00:22:23,160 有趣的是 一旦你开始用MAP来思考 But see the interesting thing about it is that once you start thinking in terms of MAP-- 243 00:22:24,020 --> 00:22:29,000 比如 一旦把缩放看作是一种MAP 就不用关心是迭代还是递归实现 see, once you say scale is just MAP, you stop thinking about whether it's iterative or recursive, 244 00:22:29,000 --> 00:22:31,820 你只会关心 啊 这里有这样一种数据集合 有这样一个表 and you just say, well there's this aggregate, there's this List, 245 00:22:32,220 --> 00:22:34,520 我要做的是转化表中的每个元素 and what I do is transform every item in the List, 246 00:22:34,560 --> 00:22:38,360 而不去考虑特别的控制流程或顺序 and I stop thinking about the particular control structure in order. 247 00:22:38,880 --> 00:22:41,090 这是个非常非常重要的想法 That's a very, very important idea, 248 00:22:42,360 --> 00:22:46,480 我猜这个想法来自APL语言 and it, I guess it really comes out of APL. 249 00:22:46,480 --> 00:22:49,100 它是APL中非常重要的思想 It's, sort of, the really important idea in APL 250 00:22:49,120 --> 00:22:51,130 即不要去考虑控制结构 that you stop thinking about control structures, 251 00:22:51,410 --> 00:22:53,920 而是关注于策略操作 and you start thinking about operations on aggregates, 252 00:22:55,010 --> 00:23:00,010 在本课程进行到一半的时候 我们将讨论一种叫做流处理的东西 and then about halfway through this course,we'll see when we talk about something called stream processing, 253 00:23:00,260 --> 00:23:02,640 那时我们将看到这种观点的真正威力 how that view of the world really comes into its glory. 254 00:23:02,640 --> 00:23:05,300 这是一种很聪明的思想 This is just us a, sort of, cute idea. 255 00:23:05,300 --> 00:23:08,700 我们可以在以后看到更多应用 But we'll see much more applications of that later on. 256 00:23:09,360 --> 00:23:16,840 还有一些非常有用也非常像MAP的过程 Well let me mention that there's something that's very similar to MAP that's also a useful idea, and that's-- 257 00:23:17,560 --> 00:23:22,540 MAP是将某个过程应用于表中每个元素 see, MAP says I take a List, I apply something to each item, 258 00:23:22,980 --> 00:23:25,620 并返回相应结果构成的表 and I return a List of the successive values. 259 00:23:25,980 --> 00:23:28,690 还有一种与此非常非常相似的操作 There's another thing I might do, which is very, very similar, 260 00:23:29,320 --> 00:23:35,860 也就是给定一个列表和操作 依次将其应用于表中每个元素 which is take a List and some action you want to do and then do it to each item in the List in sequence. 261 00:23:36,290 --> 00:23:39,400 而不会建立由结果构成的表 只是为了完成操作 Don't make a List of the values, just do this particular action, 262 00:23:40,020 --> 00:23:45,100 这个过程非常像MAP and that's something that's very much like MAP. 263 00:23:45,100 --> 00:23:46,026 它就是FOR-EACH It's called for-each, 264 00:23:46,740 --> 00:23:49,480 它接受一个过程和一个表 and for-each takes a procedure and a List, 265 00:23:49,620 --> 00:23:53,860 它实际上是对表中每个元素执行此操作 and what it's going to do is do something to every item in the List. 266 00:23:55,160 --> 00:23:58,530 通常是这样 如果表非空 So basically what it does: it says if the List is not empty, 267 00:23:59,740 --> 00:24:01,120 也就是不为NIL if the List is not null, 268 00:24:01,900 --> 00:24:06,250 我将这个过程应用于表的第一个元素 then what I do is, I apply my procedure to the first item in the List, 269 00:24:07,680 --> 00:24:11,666 然后对表中其余元素做同样的事情 and then I do this thing to the rest of the List. 270 00:24:12,440 --> 00:24:15,253 我将FOR-EACH也应用于表的CDR部分 I apply for-each to the cdr of the List. 271 00:24:15,880 --> 00:24:18,730 我对表的首元素进行处理 然后对表其余部分进行处理 All right, so I do it to the first of the List, do it to the rest of the List, 272 00:24:19,320 --> 00:24:23,920 当然 以此类推 递归地调用 又会对表其余部分的其余部分做处理 and of course, when I call it recursively, that's going to do it to the rest of the rest of the List and so on. 273 00:24:23,920 --> 00:24:28,120 最终 过程结束时 我应该告知系统 And finally, when I get done, I have to just do something to say I'm done, 274 00:24:28,160 --> 00:24:32,400 所以就返回“DONE” 所以这非常像MAP so we'll return the message "done." So that's very, very similar to MAP. 275 00:24:32,800 --> 00:24:35,120 它们之间只是返回值不同 It's mostly different in what it returns. 276 00:24:35,480 --> 00:24:39,900 比如说 如果我有一个可以在屏幕上打印对象的过程 And so for example, if I had some procedure that printed things on the screen, 277 00:24:40,560 --> 00:24:45,810 如果我想打印表中的所有元素 可以调用(FOR-EACH PRINT LIST) if I wanted to print everything in the List, I could say for-each, print this List. 278 00:24:46,780 --> 00:24:51,330 如果我有一系列图表构成的表 想把它们输出在屏幕上 Or if I had a List of figures, and I wanted to draw them on the display, 279 00:24:51,620 --> 00:24:54,860 我可以对这个调用(FOR-EACH DISPLAY FIGURES) I could say for-each, display on the screen this figure. 280 00:24:58,180 --> 00:24:59,320 有问题么? Take questions. 281 00:25:00,620 --> 00:25:04,260 学生:除非你明确地指定 AUDIENCE: Does it create a new copy with something done to it, 282 00:25:04,300 --> 00:25:07,540 Lisp会创建一个你正在处理的对象的新拷贝 是这样么? unless you explicitly tell it to do that? Is that correct? 283 00:25:07,540 --> 00:25:09,180 教授:对 PROFESSOR: Right. Ah. 284 00:25:09,930 --> 00:25:10,940 就是这样 Yeah, that's right. 285 00:25:10,940 --> 00:25:15,140 FOR-EACH不创建新列表 它只是对列表的每一个元素进行处理 For-each does not create a List. It just sort of does something. 286 00:25:15,140 --> 00:25:17,290 所以如果你有一堆事情等着做 So if you have a bunch of things you want to do 287 00:25:18,020 --> 00:25:21,560 并且你并不关心这些值 比如打印 绘图 and you're not worried about values like printing something, or drawing something on the screen, 288 00:25:21,890 --> 00:25:24,600 或者在终端中响铃等等 or ringing the bell on the terminal,or for something, 289 00:25:24,600 --> 00:25:27,640 FOR-EACH对表中每个元素做这些事 you can say for-each, you know, do this for-each of those things in the List, 290 00:25:28,210 --> 00:25:32,420 而MAP其实构建了一个新集合 这个集合也许是你想要用的 whereas MAP actually builds you this new collection of values that you might want to use. 291 00:25:32,420 --> 00:25:34,160 这就是它们之间的微妙关系 It's just a subtle difference between them. 292 00:25:34,160 --> 00:25:36,300 学生:你能否用FOR-EACH来构造MAP AUDIENCE: Could you write MAP using for-each, 293 00:25:36,320 --> 00:25:40,160 其中你用类似CONS的操作将表又构造出来了? so that you did some sort of cons or something to build the List back up? 294 00:25:40,180 --> 00:25:44,460 教授:某种程度上 我也许可以 PROFESSOR: Well, sort of. I mean, I probably could. 295 00:25:44,460 --> 00:25:49,980 我不知道如何随手写出它 但是我可以给一些思路 I can't think of how to do it right offhand, but yeah, I could arrange something. 296 00:25:50,480 --> 00:25:54,733 学生:根据昨天的课程 我认为MAP和FOR-EACH的关键区别在于 AUDIENCE: The vital difference between MAP and for-each is one is recursive and the other is not 297 00:25:54,733 --> 00:26:00,620 它们之中一个是递归的 而另一个不是 in the sense you defined early yesterday, I believe. 298 00:26:01,240 --> 00:26:03,860 教授:是的 关于MAP和FOR-EACH和递归 PROFESSOR: Yeah, about MAP and for-each and recursion. 299 00:26:03,860 --> 00:26:05,480 这个观点很好 Yeah, that's a good point. 300 00:26:05,480 --> 00:26:13,080 我写的MAP过程恰巧是一个递归过程 For the MAP procedure I wrote, that happens to be a recursive process. 301 00:26:13,820 --> 00:26:17,060 这是因为 你需要得到处理完表的剩余部分后的值 And the reason for that is that when you've done this thing to the rest of the List, 302 00:26:17,080 --> 00:26:20,960 使其与表的开头部分相连 you're waiting for that value so that you can stick it on to the beginning of the List, 303 00:26:21,730 --> 00:26:24,530 但是FOR-EACH不需要等待返回值 whereas for-each doesn't really have any values to wait for. 304 00:26:24,840 --> 00:26:26,660 所以它变成了一个迭代的过程 So that turns out to be an iterative process. 305 00:26:26,660 --> 00:26:27,720 这不是本质 That's not fundamental. 306 00:26:27,720 --> 00:26:31,800 我可以用迭代的方式定义MAP过程 I could have defined MAP so that it's evolved by an iterative process. 307 00:26:31,820 --> 00:26:32,820 只是我没那么做 I just didn't happen to. 308 00:26:34,240 --> 00:26:42,900 学生:将FOR-EACH用在一个列表的列表上的话 我想这是可行的吧? AUDIENCE: If you were to call for each with a List that had embedded Lists, I imagine it would work, right? 309 00:26:42,900 --> 00:26:48,100 它会对这些内部列表的元素进行处理么? It would give you the internal elements of each of those internal Lists? 310 00:26:48,700 --> 00:26:50,400 教授:问题是 如果我调用 PROFESSOR: OK, the question is if I call 311 00:26:50,400 --> 00:26:52,280 FOR-EACH或者MAP for-each or map, for that matter 312 00:26:52,810 --> 00:26:55,280 参数是一个嵌套有一个表的表 with a List that had Lists in it 313 00:26:56,690 --> 00:27:00,600 虽然我们还没有讲过这个 但是那是可行的 although we haven't really looked at that yet--would that work. 314 00:27:01,020 --> 00:27:06,560 答案是肯定的 不过我俩对“可行”的定义可能有些不同 The answer is yes in the sense I mean work and no in the sense that you mean work, 315 00:27:06,860 --> 00:27:10,650 来看一下 如果我给你一个表 because all that-- see if I give you a List, 316 00:27:12,800 --> 00:27:14,200 而在个箭头所指的 where hanging off here is, 317 00:27:16,060 --> 00:27:21,460 不是一个数 而是一个表 或者序对 或者是其它东西 you know, is something that's not a number, maybe another List or you know, another cons or something, 318 00:27:21,960 --> 00:27:24,540 FOR-EACH对表中的每个元素做处理 for-each just says do something to each item in this List. 319 00:27:24,540 --> 00:27:26,960 它会不断地处理表CDR部分 It goes down successively looking at the cdrs. 320 00:27:26,960 --> 00:27:27,200 学生:嗯 AUDIENCE: OK. 321 00:27:27,200 --> 00:27:31,060 教授:对FOR-EACH来说 表中的第一个元素就是这个箭头所指的东西 PROFESSOR: And as far as it's concerned, the first item in this List is whatever is hanging off here. 322 00:27:31,060 --> 00:27:31,650 学生:唔 AUDIENCE: Mhm. 323 00:27:31,650 --> 00:27:33,940 教授:这对于你要完成的任务而言 也许是对的 也许不是 PROFESSOR: That might or might not be the right thing. 324 00:27:33,940 --> 00:27:35,570 学生:所以不能进入子表中 AUDIENCE: So it wouldn't go down into the-- 325 00:27:35,570 --> 00:27:36,910 教授:绝对不能 PROFESSOR: Absolutely not. 326 00:27:36,910 --> 00:27:38,510 当然我也可以那样写程序 I could certainly write something else. 327 00:27:38,510 --> 00:27:42,970 你所说的是另一种公共模式 叫做树递归 There's another, what you're looking for is a common pattern of usage called tree recursion, 328 00:27:43,010 --> 00:27:47,940 当你给它一个表 它会不断向深度递归 直到遇到所谓的“树叶” where you take a List, and you actually go all the way down to the what's called the leaves of the tree. 329 00:27:47,940 --> 00:27:51,050 你可以写出来这个过程 但是它既不是FOR-EACH也不是MAP And you could write such a thing, but that's not for-each and it's not MAP. 330 00:27:52,420 --> 00:27:55,050 FOR-EACH和MAP都很简单 Remember, these things are really being very simple minded. 331 00:27:55,770 --> 00:27:56,890 好 还有问题么? OK, no more questions? 332 00:27:57,680 --> 00:27:58,570 好的 大家休息一下吧 All right, let's break. 333 00:27:59,110 --> 00:28:10,990 [音乐] [JESU, JOY OF MAN'S DESIRING] 334 00:28:11,460 --> 00:28:14,293 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 335 00:28:14,320 --> 00:28:17,520 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 336 00:28:27,380 --> 00:28:34,226 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 337 00:28:34,860 --> 00:28:38,586 Henderson-Escher的例子 Henderson Escher Example 338 00:28:41,940 --> 00:28:48,650 教授:我将在本节课余下的时间中 讨论一个实例 PROFESSOR: What I'd like to do now is spend the rest of this time talking about one example, 339 00:28:50,040 --> 00:28:53,920 这个实例 可以充分地总结我们所学的所有东西 and this example, I think, pretty much summarizes everything that we've done up until now: 340 00:28:54,740 --> 00:28:56,290 比如 表结构 all right, and that's List structure 341 00:28:57,170 --> 00:28:59,480 以及抽象的技术 and issues of abstraction, 342 00:28:59,540 --> 00:29:00,820 数据的表示 and representation 343 00:29:01,600 --> 00:29:04,600 和用高阶过程描绘共性 and representation and capturing commonality with higher order procedures, 344 00:29:04,600 --> 00:29:09,800 也会介绍目前为止还没怎么谈论过的 and also is going to introduce something we haven't really talked about a lot yet-- what I said is the major third theme in this course: 345 00:29:09,850 --> 00:29:13,460 也就是这门课的第三大主题 what I said is the major third theme in this course: 346 00:29:13,960 --> 00:29:15,530 元语言抽象 meta-linguistic abstraction, 347 00:29:15,540 --> 00:29:21,900 这种在工程设计中控制复杂度的思想 which is the idea that one of the ways of tackling complexity in engineering design 348 00:29:22,860 --> 00:29:25,800 也就是建立一个合适而强大的语言 is to build a suitable powerful language. 349 00:29:28,170 --> 00:29:34,740 你们或许记得 我说过在这门课程中 你们将要学到的最重要的事情是 You might recall what I said was pretty much the very most important thing that we're going to tell you in this course is that 350 00:29:34,740 --> 00:29:41,170 当我们考察一门语言时 关心的是它的基本元素 when you think about a language, you think about it in terms of what are the primitives; 351 00:29:42,980 --> 00:29:46,690 关心它的组合手段 what are the means of combination-- 352 00:29:49,720 --> 00:29:52,800 关心那些让你能够构建更大东西的东西 right, what are the things that allow you to build bigger things; 353 00:29:53,610 --> 00:29:55,240 以及 抽象的方式 and then what are the means of abstraction. 354 00:30:00,970 --> 00:30:05,160 如何取用这些你构造出来的“大东西” How do you take those bigger things that you've built 355 00:30:05,560 --> 00:30:07,970 并将它们放入“黑盒”中 put black boxes around them 356 00:30:08,450 --> 00:30:11,710 然后用它们来构建更复杂的东西 and use them as elements in making something even more complicated? 357 00:30:13,530 --> 00:30:18,720 我将要介绍的一种语言 就是元语言抽象的一个例子 Now the particular language I'm going to talk about is an example 358 00:30:18,730 --> 00:30:22,700 那是我朋友Peter Handerson发明的 that was made up by a friend of ours called Peter Henderson. 359 00:30:28,240 --> 00:30:31,740 他来自苏格兰的Stirling大学 Peter Henderson is at the University of Stirling in Scotland. 360 00:30:32,780 --> 00:30:40,980 这个语言是用来画这样的图 And what this language is about is making figures that sort of look like this. 361 00:30:41,860 --> 00:30:46,660 这是埃舍尔的木版画 《方形极限》 This is this is a woodcut by Escher called "Square Limit." 362 00:30:49,330 --> 00:30:57,940 正如大家所见 这里面有着很复杂的...图像的递归 You, sort of, see it has this complicated, kind of, recursive, sort of, recursive kind of figure, 363 00:30:58,840 --> 00:31:01,466 其中中间的鱼形图案以自相似的方式 where there's this fish pattern in the middle and things sort of 364 00:31:01,706 --> 00:31:04,560 不断地以更小的形式出现在原来的团案旁边 bleed out smaller and smaller in self similar ways. 365 00:31:08,490 --> 00:31:12,800 总之 Peter Hendersion的语言是用来表述这类图形 Anyway, Peter Henderson's language was for describing figures that look like that 366 00:31:13,370 --> 00:31:18,280 并且设计类似的图形 将它画在显示器上 and designing new ones that look like that and drawing them on a display screen. 367 00:31:20,240 --> 00:31:27,480 这个例子还展示了另外一个主题 There's another theme that we'll see illustrated by this example, 368 00:31:28,090 --> 00:31:32,020 这也是我跟Gerry教授多次强调的 and that's the issue of what Gerry and I have already mentioned a lot: 369 00:31:32,020 --> 00:31:36,170 也就是过程跟数据之间没有本质的区别 that there's no real difference, in some sense, between procedures and data. 370 00:31:37,260 --> 00:31:42,400 不管如何 我希望今早课程结束后 And anyway I hope by the end of this morning, if you're not already, 371 00:31:42,580 --> 00:31:47,600 你们能将过程和数据当作一回事儿 you will be completely confused about what the difference between procedures and data are, 372 00:31:47,960 --> 00:31:49,580 即使现在你们还将它们区别对待 if you're not confused about that already. 373 00:31:50,800 --> 00:31:55,280 那么 先让我们看一下Peter的语言 Well in any case, let's start describing Peter's language. 374 00:31:55,280 --> 00:31:57,260 我先告诉你们基本元素是什么 I should start by telling you what the primitives are. 375 00:31:58,290 --> 00:32:00,920 这个语言非常简单 因为它的基本元素只有一个 This language is very simple because there's only one primitive. 376 00:32:03,330 --> 00:32:06,300 这个基本元素不是大家想象的那样 A primitive is not quite what you think it is. 377 00:32:07,080 --> 00:32:09,180 它唯一的基本元素叫做"图像" There's only one primitive called a picture, 378 00:32:09,700 --> 00:32:12,110 但此“图像”非彼“图像” and a picture is not quite what you think it is. 379 00:32:12,110 --> 00:32:14,170 具体地来说 Here's an example. 380 00:32:14,170 --> 00:32:15,170 这是George的图像 This is a picture of George. 381 00:32:19,010 --> 00:32:20,370 我们的想法是 The idea is that 382 00:32:22,330 --> 00:32:24,573 在这个语言中的图像是这样一个东西 a picture in this language is going to be something 383 00:32:24,893 --> 00:32:31,460 它能在你指定的一个矩形里画出一个缩放好图像 that draws a figure scaled to fit a rectangle that you specify. 384 00:32:33,000 --> 00:32:34,420 这里大家看到的强调线 So here you see emphasis line 385 00:32:34,420 --> 00:32:37,700 是这个矩形的轮廓 但不是图像的一部分 is outline of a rectangle, that's not really part of the picture, 386 00:32:40,490 --> 00:32:47,170 但是一旦指定一个矩形区域 图像会以以填充的方式绘制满区域 but the picture-- you'll give it a rectangle, and it will draw this figure scaled to fit the rectangle. 387 00:32:47,170 --> 00:32:52,160 比如 这个是George 在这里 这个也是George So for example, there's George, and here, this is also George. 388 00:32:53,210 --> 00:32:56,650 它是同一个图像 只是缩放程度不同 It's the same picture, right, just scaled to fit a different rectangle. 389 00:32:57,400 --> 00:32:59,280 这是“胖”George的版本 Here's George as a fat kid. 390 00:33:00,010 --> 00:33:03,440 这个也是George That's the same George. 391 00:33:03,810 --> 00:33:05,140 这是同一个图形 It's all the same figure. 392 00:33:05,140 --> 00:33:09,570 这个语言中 这三个都是同一个图像 All of these three things are the same picture in this language. 393 00:33:09,580 --> 00:33:13,040 仅仅是给了不同的矩形区域让它来填充 I'm just giving it different rectangles to scale itself in. 394 00:33:16,080 --> 00:33:20,650 这就是基本元素 OK, those are the primitives. That is the primitive. 395 00:33:21,440 --> 00:33:25,250 现在 我们来讨论元素组合和操作 Now let's start talking about the means of combination and the operations. 396 00:33:25,900 --> 00:33:30,170 比如 这里有一个叫做旋转的操作 There is, for example, an operation called Rotate. 397 00:33:31,090 --> 00:33:33,660 如果我有一个图像 “旋转”操作就是 And what Rotate does is, if I have a picture, 398 00:33:35,370 --> 00:33:39,930 先假定有一个里面有个“A”的矩形 say a picture that draws an "A" in some rectangle that I give it, 399 00:33:41,840 --> 00:33:45,730 而旋转90度的操作则会 the Rotate of that--say the Rotate by 90 degrees would, 400 00:33:47,020 --> 00:33:50,650 在一个给定的矩形内 绘制同样的图像 if I give it a rectangle, draw the same image, 401 00:33:50,650 --> 00:33:53,880 但是 会缩放图像以适应矩形 but again, scaled to fit that rectangle. 402 00:33:56,110 --> 00:33:58,340 这个就是旋转90度 So that's Rotate by 90 degrees. 403 00:33:58,340 --> 00:34:03,200 另一个操作是“翻转” 可以水平翻转也可以竖直翻转 There's another operation called Flip that can flip something, either horizontally or vertically. 404 00:34:04,770 --> 00:34:06,000 就是这些操作了 All right, so those are, sort of, operations, 405 00:34:06,010 --> 00:34:10,400 或者你可以把它们认为是组合一个元素的各种方式 or you can think of those as means of combination of one element. 406 00:34:10,890 --> 00:34:12,420 我可以把它们混合起来 I can put things together. 407 00:34:13,440 --> 00:34:15,540 我们有一种叫BESIDE的操作 There's a means of combination called Beside, 408 00:34:16,460 --> 00:34:24,780 它做的事情是 给定两个图像A、B -- and what Beside does: it'll take two pictures, let's say A and B-- 409 00:34:29,020 --> 00:34:33,250 这里图像是指能在指定的矩形中画一个图案的东西 -- and by picture I mean something that's going to draw an image in a specified rectangle-- 410 00:34:34,050 --> 00:34:36,510 BESIDE将会做的事情 and what Beside will do-- 411 00:34:37,850 --> 00:34:44,080 类似于调用(BESIDE A B S) 其中S是一个数 I have to say, Beside of A and B, the side of two pictures and some number, s. 412 00:34:45,340 --> 00:34:48,080 是一个在0到1之间的数 And s will be a number between zero and one. 413 00:34:50,510 --> 00:34:52,570 BESIDE绘制像这样的图像 And Beside will draw a picture that looks like this. 414 00:34:52,570 --> 00:34:56,710 以给定的矩形为基础 但会将基底缩放S It will take the rectangle you give it and scale its base by s. 415 00:34:56,710 --> 00:34:58,710 这里S是0.5 Say s is 0.5. 416 00:35:00,180 --> 00:35:07,170 在这里 它会在这里画第一个图案 And then over here it will draw-- it'll put the first picture, and over here it'll put the second picture. 417 00:35:07,810 --> 00:35:12,650 在这里画第二个图案 and over here it'll put the second picture. 418 00:35:13,820 --> 00:35:16,440 又比如说 我另设一个S的值 Or for instance if I gave it a different value of s, 419 00:35:16,810 --> 00:35:23,020 比如调用(BESIDE A B 0.25) Or for instance if I gave it a different value of s, if I said Beside with a 0.25, 420 00:35:25,940 --> 00:35:29,090 效果相同 只不过A更瘦了 it would do the same thing, except the A would be much skinnier. 421 00:35:34,050 --> 00:35:36,280 而B是这样的 So it would draw something like that. 422 00:35:37,820 --> 00:35:40,290 这就是组合手段之一:BESIDE So there's a means of combination Beside, 423 00:35:40,680 --> 00:35:46,050 类似地 ABOVE方法在竖直方向上做这种操作 and similarly there's an Above, which does the same thing except it puts them vertically instead of horizontally. 424 00:35:47,840 --> 00:35:48,890 我们来看一下 Well let's look at that. 425 00:35:50,740 --> 00:35:56,000 这是George和他的"弟弟" All right, there's George and his kid brother, 426 00:35:56,720 --> 00:36:07,050 这是通过将George放在一旁 which is, right, constructed by taking George and putting him Beside 427 00:36:10,360 --> 00:36:14,420 George与空图像的上下组合放在另一旁 The Above, taking the empty picture, and there's a thing called the empty picture, 428 00:36:14,520 --> 00:36:16,140 这样做的意图很明显 which does the obvious thing-- 429 00:36:16,140 --> 00:36:19,140 空图像放在了另一个George的上面 putting the empty picture above a copy of George, 430 00:36:19,140 --> 00:36:21,140 合成的图像又放在了George的旁边 and then putting that whole thing Beside George. 431 00:36:28,960 --> 00:36:30,340 这个是图像P Here's something called P which is, 432 00:36:31,100 --> 00:36:39,040 像之前一样 是George和翻转后George的BESIDE组合 which is, again, George Beside Flipping George, 433 00:36:40,530 --> 00:36:42,080 这里 我们做的是水平翻转 I think, horizontally in this case, 434 00:36:42,370 --> 00:36:44,800 然后整体旋转180度 Rotating the whole result 180 degrees 435 00:36:45,800 --> 00:36:50,820 然后调用BESIDE让它们组合在一起 系数是0.5 putting them Beside one another with the basic rectangle divided at 0.5, 436 00:36:52,560 --> 00:36:53,900 这样 我创建了图像P right, and I can call that P. 437 00:36:55,900 --> 00:36:57,880 然后使用图像P And then I can take P, 438 00:36:59,210 --> 00:37:04,960 与它的翻转图像做ABOVE操作 形成图像Q And then I can take P, and put it above the Flipped copy of itself, and I can call that Q. 439 00:37:09,200 --> 00:37:13,260 请注意 我们是如何快速地增加复杂度 Notice how rapidly that we've built up complexity, 440 00:37:14,360 --> 00:37:21,050 转瞬之间 我们使用George组合得到了Q 这说明了什么? just in, you know, 15 seconds, you've gotten from George to that thing Q. Why is that? 441 00:37:22,050 --> 00:37:24,550 为什么我们可以做得如此迅速呢? How are how we able to do that so fast? 442 00:37:25,850 --> 00:37:28,020 答案是闭包性质 The answer is the closure property. 443 00:37:28,690 --> 00:37:32,980 这是因为 当我将两个图像做BESIDE操作后 See, it's the fact that when I take a picture and put it Beside another picture, 444 00:37:34,300 --> 00:37:35,290 得到的也是图像 that's then, again, a picture 445 00:37:35,330 --> 00:37:37,780 我可以继续执行 ROTATE FLIP 或者 ABOVE操作 that I can go and Rotate and Flip or put Above something else. 446 00:37:39,170 --> 00:37:40,880 而操作的结果P Right, and when I take that element P, 447 00:37:40,893 --> 00:37:44,880 BESIDE FLIP ROTATE操作的结果也是一个图像 which is the Beside or the Flip or the Rotate of something, that's, again, a picture. 448 00:37:45,220 --> 00:37:50,200 在这种组合方法下 图像的世界是封闭的 Right, the world of pictures is closed under those means of combination. 449 00:37:50,770 --> 00:37:52,240 所以 任何时候我都可以 So whenever I have something, 450 00:37:52,480 --> 00:37:55,170 以一个东西为基本元素 去构造别的东西 I can turn right around and use that as an element in something else. 451 00:37:56,330 --> 00:37:58,520 这个例子比表和线段更直观 So maybe better than List and segments, 452 00:37:58,540 --> 00:38:03,280 它揭示了 我们如何用封闭的操作 快速增加复杂度 that just gives you an image for how fast you can build up complexity, because operations are closed. 453 00:38:07,480 --> 00:38:12,020 在构建更多东西之前 OK, well before we go on with building more things, 454 00:38:12,040 --> 00:38:14,770 我们先来看看这个语言是如何实现的 let's talk about how this language is actually implemented. 455 00:38:16,910 --> 00:38:21,500 其中基本的一个元素 The basic element that sits under the table here 456 00:38:21,930 --> 00:38:24,520 是一个称作“矩形”的东西 is a thing called a rectangle, 457 00:38:26,090 --> 00:38:28,280 所谓的矩形就是 and what a rectangle is going to be, 458 00:38:28,280 --> 00:38:33,680 它有一个原点 it's a thing that specified by an origin 459 00:38:36,450 --> 00:38:40,180 原点是一个向量 用以说明矩形是从哪开始 that's going to be some vector that says where the rectangle starts. 460 00:38:40,180 --> 00:38:42,290 至于其它的向量 And then there's going to be some other vector 461 00:38:43,660 --> 00:38:46,330 我们称其为矩形的水平分量 that I'm going to call the horizontal part of the rectangle, 462 00:38:55,760 --> 00:38:59,250 还有就是矩形的竖直分量 and another vector called the vertical part of the rectangle. 463 00:39:00,490 --> 00:39:02,680 这就是构成矩形的三个基本元素 And those three pieces are the elements: 464 00:39:02,680 --> 00:39:04,510 两个向量用作 where the lower vertex is, 465 00:39:04,933 --> 00:39:09,970 计算左上角和右下角的顶点坐标 how you get to the next vertex over here, and how you get to the vertex over there. 466 00:39:09,970 --> 00:39:12,370 这三个向量确定了一个矩形 The three vectors specify a rectangle. 467 00:39:16,000 --> 00:39:18,933 为了构建矩形 我们假设 Now to actually build rectangles, what I'll assume is 468 00:39:19,773 --> 00:39:22,060 假设有个“构建矩形”的构造函数 that we have a constructor called "make rectangle," 469 00:39:23,010 --> 00:39:24,260 也就是MAKE-RECT or "make-rect," 470 00:39:27,560 --> 00:39:35,170 以及选择函数 HORIZ、VERT 和 ORIGIN and selectors for horiz and vert and origin 471 00:39:37,580 --> 00:39:39,650 用于取得对应的矩形属性 that get out the pieces of that rectangle. 472 00:39:39,650 --> 00:39:42,540 我们知道有很多方法可以实现它 And well, you know a lot of ways you can do this now. 473 00:39:42,540 --> 00:39:47,620 可以用序对或者表 或者其它东西 You can do it by using pairs in some way or other standard List or not. 474 00:39:47,620 --> 00:39:51,400 但是 这些东西的实现是George的事 But in any case, the implementation of these things, that's George's problem. 475 00:39:51,400 --> 00:39:53,170 这是一个数据表示的问题 It's just a data representation problem. 476 00:39:53,170 --> 00:39:55,470 现在我们假设已经有了这些矩形了 So let's assume we have these rectangles to work with. 477 00:39:59,053 --> 00:40:05,080 好的 现在来看我们接下来要做的事情 OK. Now the idea of this, remember what's got to happen. 478 00:40:05,080 --> 00:40:08,220 我们需要关心如何取用图像 Somehow we have to worry about taking the figure 479 00:40:09,330 --> 00:40:12,970 将它缩放以适应你给定的矩形 and scaling it to fit some rectangle that you give it, 480 00:40:13,600 --> 00:40:16,600 我们要来安排这些事 that's the basic thing you have to arrange, 481 00:40:16,600 --> 00:40:18,600 来完成图像的缩放 that these pictures can do. 482 00:40:22,220 --> 00:40:23,650 有哪些思路呢? How do we think about that? 483 00:40:23,650 --> 00:40:27,080 一种想法是:无论何时给定一个矩形 Well, one way to think about that is that any time I give you a rectangle, 484 00:40:35,680 --> 00:40:38,680 无论何时给定一个矩形 也就是说 Any time I gave you a rectangle, that defines, 485 00:40:39,250 --> 00:40:45,770 这在某种意义上是把正方形转换成矩形 that defines,in some sense, a transformation from the standard square into that rectangle. 486 00:40:45,770 --> 00:40:46,540 也就是说 Let me say what I mean. 487 00:40:46,540 --> 00:40:48,530 我所谓的正方形 By the standard square, I'll mean something, 488 00:40:49,040 --> 00:40:59,040 它的坐标是(0,0)、(1,0)、(0,1)和(1,1) which is a square whose coordinates are 0,0, and 1,0, and 0,1 and 1,1. 489 00:41:01,400 --> 00:41:05,720 我们有一些显而易见的缩放变换 And there's some sort of the obvious scaling transformation, 490 00:41:06,120 --> 00:41:10,220 可以把这个映射成这个 把这个映射成这个 which maps this to that and this to that, 491 00:41:10,240 --> 00:41:12,080 并且 把所有的东西统一地拉伸 and sort of, stretches everything uniformly. 492 00:41:12,170 --> 00:41:18,250 我们将这样的一条的线段 So we take a line segment like this 493 00:41:19,730 --> 00:41:24,200 将它最终映射到像那样的一条线段 and end up mapping it to a line segment like that, 494 00:41:26,200 --> 00:41:32,680 而点(X,Y)变成了这里的另外一个点 so some point (x,y) goes to some other point up there. 495 00:41:32,680 --> 00:41:39,370 这个不紧要 会点向量运算 就能写出变换公式 And although it's not important, with a little vector algebra, you could write that formula. 496 00:41:39,370 --> 00:41:43,180 初始点(X,Y)将会变换到的点的坐标是 The thing that (x,y) goes to, the point that (x,y) goes to is 497 00:41:43,580 --> 00:41:50,746 以矩形原点为基础做向量加法 gotten by taking the origin of the rectangle and then adding that as a vector to-- 498 00:41:51,160 --> 00:41:55,480 加上 初始点X坐标 一个介于0和1之间的值 well, take x, the x coordinate, which is something between zero and one, 499 00:41:55,986 --> 00:42:01,840 并乘上矩形的水平向量 multiply that by the horizontal vector of the rectangle; 500 00:42:07,626 --> 00:42:11,000 再加上初始点的Y坐标 也是一个介于0和1的值 and take the y coordinate, which is also something between zero and one 501 00:42:11,386 --> 00:42:16,280 并乘上矩形的竖直向量 and multiply that by the vertical vector of the rectangle. 502 00:42:16,740 --> 00:42:19,310 这是简单的线性代数 That's just a little linear algebra. 503 00:42:19,310 --> 00:42:23,480 这个就是正确的变换公式 Anyway, that's the formula, which is the right obvious transformation 504 00:42:23,690 --> 00:42:28,180 它将方形中的物件转化到对应矩形中 that takes things into the unit square, into the interior of that rectangle. 505 00:42:31,340 --> 00:42:34,020 现在 我们把它看作是一个过程 OK well, let's actually look at that as a procedure. 506 00:42:35,160 --> 00:42:36,293 我们想要得到的是 So what we want is 507 00:42:37,800 --> 00:42:40,826 由一个单位正方形到特定矩形的 the thing which tells us that particular transformation 508 00:42:41,013 --> 00:42:42,520 特定变换过程 that a rectangle defines. 509 00:42:43,800 --> 00:42:45,220 这个过程具体是这样的 So here's the procedure. 510 00:42:45,220 --> 00:42:47,220 我叫它COORD-MAP I'll call it coordinate-map. 511 00:42:47,770 --> 00:42:52,000 COORD-MAP以一个矩形作为参数 Coordinate-map is the thing that takes as its argument a rectangle 512 00:42:53,600 --> 00:42:57,850 它返回一个以点为参数的过程 and returns for you a procedure on points. 513 00:43:00,450 --> 00:43:06,820 每个矩形 都对应一个变换点(X, Y)坐标的过程 Right, so for each rectangle you get a way of transforming a point (x,y) into that rectangle., 514 00:43:06,820 --> 00:43:08,020 是怎么得到的呢? And how do you get it? 515 00:43:08,020 --> 00:43:10,920 就如黑板上的Lisp代码所示 Well I just-- writing in Lisp what I wrote there on the blackboard-- 516 00:43:10,920 --> 00:43:16,010 我让矩形的原点加上—— I add to the origin of the rectangle 517 00:43:20,220 --> 00:43:25,020 首先是 矩形水平部分 the result of adding-- I take the horizontal part of the rectangle; 518 00:43:25,020 --> 00:43:27,680 按照点POINT的X坐标缩放 I scale that by the x coordinate of the point. 519 00:43:29,650 --> 00:43:32,620 然后是 矩形竖直部分 I take the vertical vector of the rectangle. 520 00:43:33,510 --> 00:43:37,140 按照点POINT的Y坐标缩放 I scale that by the y coordinate of the point, 521 00:43:37,140 --> 00:43:39,140 然后把它们三个加到一起 and then add all those three things up. 522 00:43:40,130 --> 00:43:41,340 这个过程就是这样 That's the procedure. 523 00:43:41,340 --> 00:43:44,540 这就是我将要应用在点POINT上的过程 That is the procedure that I'm going to apply to a point. 524 00:43:46,540 --> 00:43:52,170 这个过程由每个矩形自己生成 And this whole thing is generated for each rectangle. 525 00:43:52,170 --> 00:43:57,250 每个矩形对应了一个定义在点集上的过程 COORD-MAP So any rectangle defines a Coordinate-MAP, which is a procedure on points. 526 00:44:06,660 --> 00:44:10,426 比如说 这里的George All right, so for example, George here, 527 00:44:11,360 --> 00:44:16,340 最初的George 可能是我在单位正方形中通过线段绘制的 my original George, might have been something that I specified by segments in the unit square, 528 00:44:19,500 --> 00:44:21,960 而当我把它应用到一个新的矩形中 and then for each rectangle I give this thing, 529 00:44:24,140 --> 00:44:28,170 我将会在新矩形中画出组成George的那些线段来 I'm going to draw those segments inside that rectangle. 530 00:44:28,170 --> 00:44:29,880 我是怎么做的呢? How actually do I do that? 531 00:44:30,680 --> 00:44:36,940 我枚举原始George中的每条线段 Well I take each segment in my original reference George that was specified, 532 00:44:38,640 --> 00:44:40,586 我对每条线段的终点 and to each of the end points of those segments, 533 00:44:40,880 --> 00:44:44,450 应用目标矩形对应的COORD-MAP过程 I applied the COORDINATE-MAP of the particular rectangle I want to draw it in. 534 00:44:44,450 --> 00:44:46,066 比如下面的这个矩形 So for example, this lower rectangle, 535 00:44:46,666 --> 00:44:50,880 这个胖George 有它对应的COORD-MAP this George as a fat kid rectangle, has its COORDINATE-MAP. 536 00:44:51,250 --> 00:44:53,693 如果我要绘制这个图像 And if I want to draw this image, 537 00:44:55,380 --> 00:44:57,920 需要做的就是对这里的每条线段 比如这条 And if I want to draw this image, what I do is for each segment here, say for this segment, 538 00:44:59,293 --> 00:45:05,340 用COORD-MAP变换这个点 同时变换这个点 I transformed that point by the coordinate MAP, transform that point by the coordinate MAP. 539 00:45:05,340 --> 00:45:07,093 我就得到了这两个点 That will give me this point and that point 540 00:45:07,386 --> 00:45:08,946 就可以将在两点之间画线 and draw the segment between them. 541 00:45:09,710 --> 00:45:11,520 这就是核心思路 Right, that's the idea. 542 00:45:12,660 --> 00:45:14,780 那么如果我给一个不同的矩形 比如这个 Right, and if I give it a different rectangle like this one, 543 00:45:14,800 --> 00:45:15,760 得到的是不同的COORD-MAP that's a different coordinate-MAP, 544 00:45:15,790 --> 00:45:17,840 因此我得到这些线段的不同图像 so I get a different image of those line segments. 545 00:45:19,280 --> 00:45:22,140 基本图像又该如何表示呢? Well how do we actually get a picture to start with? 546 00:45:22,140 --> 00:45:26,520 可以用线段组成的表来表示 I can build a picture to start with out of a List of line segments initially. 547 00:45:27,613 --> 00:45:32,200 这是用于构建我所谓的“基本图像”的过程 Here's a procedure that builds what I'll call a primitive picture, 548 00:45:33,480 --> 00:45:37,173 意思是 没有用BESIDE ROTATE等操作 meaning one I, sort of, got that didn't come out of Beside or Rotate or something. 549 00:45:37,520 --> 00:45:39,600 它以由线段组成的表为参数 It starts with a List of line segments, 550 00:45:42,946 --> 00:45:44,040 代码具体行为如下 And now it does what I said. 551 00:45:44,040 --> 00:45:45,580 图像会是什么样子呢? What's a picture have to be? 552 00:45:45,580 --> 00:45:49,440 首先 它是一个根据矩形定义的过程 First of all it's a procedure that's defined on rectangles. 553 00:45:51,700 --> 00:45:53,000 这个过程做什么呢? What does it do? 554 00:45:53,000 --> 00:45:56,560 对于由线段组成的表中每个元素 It says for each-- this is going to be a List of line segments-- 555 00:45:57,666 --> 00:46:03,386 表中的每条线段S for each segment, for each s, which is a segment in this List of segments, 556 00:46:05,893 --> 00:46:07,300 都绘制了一条线 well it draws a line. 557 00:46:07,300 --> 00:46:08,820 它画什么样的线段呢? What line does it draw? 558 00:46:10,600 --> 00:46:12,840 先得到线段的起点 It gets the start point of that segment, 559 00:46:15,226 --> 00:46:17,946 用对应的COORD-MAP对其做变换 transforms that by the coordinate MAP of the rectangle. 560 00:46:19,540 --> 00:46:21,760 这是我们想要的第一个点 That's the first new point it wants to do. 561 00:46:21,760 --> 00:46:26,320 然后对线段终点做COORD-MAP操作 Then it takes the endpoint of the segment, transforms that by the coordinate MAP of the rectangle, 562 00:46:26,693 --> 00:46:27,920 并将两点连线 and then draws a line between. 563 00:46:27,920 --> 00:46:30,840 我们假设在屏幕上绘制线段是基本操作 Let's assume drawline is some primitive that's built into the system 564 00:46:31,093 --> 00:46:33,220 已经在系统中实现了 that actually draws a line on the display. 565 00:46:33,960 --> 00:46:37,106 通过COORD-MAP变换了线段终点 All right, so it transforms the endpoints by the coordinate MAP of the rectangle, 566 00:46:37,133 --> 00:46:38,200 再把起点和终点连线 draws a line between them, 567 00:46:39,613 --> 00:46:44,120 对表中每一条线段S都执行这样的操作 does that for each s in this List of segments. 568 00:46:45,960 --> 00:46:51,400 请注意 图像就是一个以矩形为参数的过程 And now remember again, a picture is a procedure that takes a rectangle as argument. 569 00:46:51,400 --> 00:46:55,653 所以当你给图像一个矩形时 它就像这样绘制线段 So when you hand it a rectangle, this is what it does: draws those lines. 570 00:46:57,173 --> 00:47:01,106 那好 我应该如何使用它呢? All right, so there's-- how would I actually use this thing? 571 00:47:01,220 --> 00:47:04,080 我来说得具体一点 Let's make it a little bit more concrete. 572 00:47:05,600 --> 00:47:24,226 就比如说 (DEFINE R (MAKE-RECT ...)) Right, I would say for instance, define R to be make-rectangle of some stuff, 573 00:47:24,506 --> 00:47:28,666 这里需要用MAKE-VECTOR来构造一些向量 and I'd have to specify some vectors here using make-vector. 574 00:47:29,840 --> 00:47:46,180 然后定义G为 (DEFINE G (MAKE-PICT ...)) And then I could say, define say, G to be make-picture, and then some stuff. 575 00:47:46,680 --> 00:47:55,280 我要在这里使用MAKE-SEGMENT来构建线段组成的表 And what I'd have to specify here is a List of line segments, right, using make segment. 576 00:47:55,280 --> 00:47:58,700 MAKE-SEGMENT由向量构成 向量由点构成 Make-segment might be made out of vectors, and vectors might be made out of points. 577 00:47:59,506 --> 00:48:04,600 如果我想在一个矩形中呈现图像G And then if I actually wanted to see the image of G inside a rectangle, 578 00:48:04,653 --> 00:48:11,720 注意 图像是一个过程 它接受一个矩形作为参数 well a picture is a procedure that takes a rectangle as argument. 579 00:48:12,066 --> 00:48:16,373 所以 如果我调用(G R) So if I then called G with an input of R, 580 00:48:17,960 --> 00:48:23,253 那么无论G是什么 都会在矩形R中绘制出来 that would cause whatever image G is worrying about to be drawn inside the rectangle R. 581 00:48:23,620 --> 00:48:25,620 这就是我们如何使用它 Right, so that's how you'd use that. 582 00:48:26,866 --> 00:48:36,293 [音乐] [JESU, JOY OF MAN'S DESIRING] 583 00:48:36,290 --> 00:48:39,786 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 584 00:48:39,820 --> 00:48:43,546 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 585 00:48:51,280 --> 00:48:55,453 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 586 00:48:55,500 --> 00:48:58,733 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 587 00:48:59,346 --> 00:49:03,020 Henderson-Escher的例子 Henderson Escher Example 588 00:49:07,720 --> 00:49:12,480 教授:为什么我说这个例子很好呢? PROFESSOR: Well why is it that I say this example is nice? 589 00:49:12,480 --> 00:49:13,740 也许你们不这么认为 You probably don't think it's nice. 590 00:49:13,740 --> 00:49:15,420 你们可能觉得它很奇怪 You probably think it's more weird than nice. 591 00:49:15,420 --> 00:49:20,920 用来矩形做复杂变换的过程来表示图像 确实奇怪 Right, representing these pictures as procedures, which do complicated things with rectangles. 592 00:49:20,920 --> 00:49:22,720 那么 它好在哪里呢? So why is it nice? 593 00:49:25,360 --> 00:49:26,693 原因就是 The reason it's nice 594 00:49:27,226 --> 00:49:30,400 一旦你按这种方法实现了基本元素 is that once you've implemented the primitives in this way, 595 00:49:30,973 --> 00:49:35,200 组合的手段就是构造Lisp过程 the means of combination just fall out by implementing procedures. 596 00:49:35,980 --> 00:49:37,480 我给你们演示一下 Let me show you what I mean. 597 00:49:37,480 --> 00:49:39,026 假设我想实现BESIDE Suppose we want to implement Beside. 598 00:49:41,560 --> 00:49:47,360 我要做的是 假设有个叫P1的图像 So I'd like to-- suppose I've got a picture. Let's call it P1. 599 00:49:47,360 --> 00:49:50,620 一定要记得:图像本质上是一个过程 P1 is going to be-- and now remember what a picture really is. 600 00:49:50,620 --> 00:49:54,826 当你传递给它一个矩形 It's a thing that if you hand it some rectangle, 601 00:49:56,520 --> 00:50:01,466 它会在你给定的矩形中绘制图形 it will cause an image to be drawn in whatever rectangle you hand it. 602 00:50:03,466 --> 00:50:09,266 假设P2是另一个图像 你传递给它一个矩形 And suppose P2 two is some other picture, and you hand that a rectangle. 603 00:50:09,746 --> 00:50:12,440 无论给它什么矩形 它都会绘制一些图案 And whatever rectangle you hand it, it draws some picture. 604 00:50:14,840 --> 00:50:26,600 现在 我想实现(BESIDE P1 P2 A) A是缩放因子 And now if I'd like to implement Beside of P1 and P2 with a scale factor A, 605 00:50:27,040 --> 00:50:28,380 会得到什么呢? well what does that have to be? 606 00:50:28,380 --> 00:50:29,346 我们会得到一个图像 That's gotta be a picture. 607 00:50:29,920 --> 00:50:33,880 也就是说你传给它一个矩形 它就会在其中绘图 It's gotta be a thing that you handed a rectangle and draw something in that rectangle. 608 00:50:34,770 --> 00:50:37,186 如果我们在一个矩形中执行BESIDE操作 So if hand Beside this rectangle-- 609 00:50:38,586 --> 00:50:40,120 比如这个矩形 let's hand it a rectangle. 610 00:50:41,500 --> 00:50:42,740 要做什么呢? Well what's it going to do? 611 00:50:42,760 --> 00:50:46,360 一部分比例是A 另一部分是1-A It's going to take this rectangle and split it into two 612 00:50:49,293 --> 00:50:51,570 一部分比例是A 另一部分是1-A at a ratio of A and one minus A. 613 00:50:52,653 --> 00:50:55,120 现在 我们就有了两个矩形 And it will say, oh sure, now I've got two rectangles. 614 00:51:02,346 --> 00:51:06,546 然后先让P1在这个矩形中绘制 And now it goes off to P1 and says P1, well draw yourself in this rectangle, 615 00:51:07,360 --> 00:51:11,640 然后让P2在这个矩形中绘制 and goes off to P2, and says, P2, fine, draw yourself in this rectangle. 616 00:51:13,280 --> 00:51:16,880 BESIDE仅仅需要计算出这些矩形来 The only computation it has to do is figure out what these rectangles are. 617 00:51:17,360 --> 00:51:23,973 由于矩形是由原点、水平向量和竖直向量组成 Remember a rectangle is specified by an origin and a horizontal vector and a vertical vector. 618 00:51:23,986 --> 00:51:25,940 BESIDE操作需要计算出这些要素 so it's got to figure out what these things are. 619 00:51:27,373 --> 00:51:32,293 所以对第一个矩形来说 原点变成了矩形的原点 So for this first rectangle, the origin turns out to be the origin of the original rectangle, 620 00:51:33,640 --> 00:51:37,800 竖直向量与原矩形相同 不发生变化 and the vertical vector is the same as the vertical vector of the original rectangle. 621 00:51:38,893 --> 00:51:46,600 水平向量是原始矩形的水平向量缩放A倍得到的 The horizontal vector is the horizontal vector of the original rectangle scaled by A. 622 00:51:47,493 --> 00:51:48,906 这就是第一个矩形 And that's the first rectangle. 623 00:51:49,460 --> 00:51:52,693 第二个矩形的原点是 The second rectangle, the origin 624 00:51:54,066 --> 00:51:59,653 原矩形的原点加上矩形的水平向量缩放A倍 The second rectangle, the origin is the original origin plus that horizontal vector scaled by A. 625 00:52:01,200 --> 00:52:03,400 第二个矩形的水平向量是 The horizontal vector of the second rectangle is 626 00:52:03,770 --> 00:52:06,040 除去前一个矩形水平向量所余下的部分 the rest of the horizontal vector of the first one, 627 00:52:06,346 --> 00:52:11,660 也就是(1-A)*H H是原矩形的水平向量 which is 1 minus A times the original H, 628 00:52:12,053 --> 00:52:13,773 它的竖直向量还是V and the vertical vector is still v. 629 00:52:15,480 --> 00:52:17,986 基本上 BESIDE就是构造这两个矩形 But basically it goes and constructs these two rectangles, 630 00:52:18,000 --> 00:52:20,573 但重要的是 一旦构造好这些矩形 and the important point is having constructed the rectangles, 631 00:52:20,933 --> 00:52:24,586 它就能让P1、P2在正确的位置绘制 it says OK, p1, you draw yourself in there, and p2, you draw yourself in there, 632 00:52:24,626 --> 00:52:26,186 这就是BESIDE需要做的全部工作 and that's all Beside has to do. 633 00:52:27,800 --> 00:52:29,306 我们看一下代码 All right, let's look at that piece of code. 634 00:52:34,333 --> 00:52:35,133 这是BESIDE Beside 635 00:52:39,640 --> 00:52:46,440 (BESIDE P1 P2 A) A是缩放比例 Beside of a picture and another picture with some scaling ratio 636 00:52:47,840 --> 00:52:53,640 因为该过程返回图像 所以结果是一个以矩形为参数的过程 is first of all, since it's a picture, a procedure that's going to take a rectangle as argument. 637 00:52:55,493 --> 00:52:56,560 它做什么呢? What's it going to do? 638 00:52:56,760 --> 00:53:02,320 它让P1在某个矩形中绘制 P2在另一个矩形中绘制 It says, p1 draw yourself in some rectangle and p2 draw yourself in some other rectangle. 639 00:53:03,213 --> 00:53:04,460 现在这些矩形又是什么呢? And now what are those rectangles? 640 00:53:04,460 --> 00:53:05,480 就在这里计算 Well here's the computation. 641 00:53:05,480 --> 00:53:06,546 它创建了一个矩形 It makes a rectangle, 642 00:53:07,520 --> 00:53:10,400 用的是我刚才在黑板上写的几何公式 这是矩形的原点 and this is the algebra I just did on the board: the origin, something; 643 00:53:10,400 --> 00:53:11,840 矩形的水平向量 the horizontal vector, something; 644 00:53:11,840 --> 00:53:13,440 还有矩形的竖直向量 and the vertical vector, something. 645 00:53:13,973 --> 00:53:14,813 对于P2 For p2 646 00:53:15,506 --> 00:53:19,780 矩形需要不同的原点 水平向量和竖直向量 And for p2, the rectangle it wants has some other origin and horizontal vector and vertical vector. 647 00:53:19,780 --> 00:53:20,706 但重要的是 But the important point 648 00:53:21,213 --> 00:53:27,180 BESIDE只是将这两个矩形分别传递给了P1和P2而已 is that all it's saying is, p1, go do your thing in one rectangle, and p2, go do your thing in another rectangle. 649 00:53:27,740 --> 00:53:29,420 这就是BESIDE所需要做的 That's all the Beside has to do. 650 00:53:30,840 --> 00:53:35,620 好 ROTATE也很类似 OK, similarly Rotate-- 651 00:53:36,960 --> 00:53:42,000 假设我有一个图像A see if I have this picture A, 652 00:53:42,973 --> 00:53:46,120 我想让它旋转90度 and I want to look at say rotating A by 90 degrees, 653 00:53:46,373 --> 00:53:51,920 这意味着 给定这个矩形 what that should mean is, well take this rectangle, 654 00:53:53,946 --> 00:53:58,440 它有原点、水平向量和竖直向量 which is origin and horizontal vector and vertical vector, 655 00:53:58,786 --> 00:54:03,186 现在假设已经有了这样的矩形 and now pretend that it's really the rectangle that looks like this, 656 00:54:03,746 --> 00:54:09,120 这个矩形的原点、水平向量和竖直向量在这里 which has an origin and a horizontal vector up here, and a vertical vector there, 657 00:54:09,600 --> 00:54:12,460 然后在矩形里各自绘制自己 and now draw yourself with respect to that rectangle. 658 00:54:13,260 --> 00:54:15,040 我们来看看代码 Let me show you that as a procedure. 659 00:54:17,026 --> 00:54:19,853 那么 ROTATE90过程 All right, so we'll Rotate 90 of the picture, 660 00:54:20,613 --> 00:54:22,960 返回的也是一个以矩形为参数的过程 because again, a procedure for rectangle, 661 00:54:23,253 --> 00:54:26,120 它就是将图像绘制在一个特定矩形中 which says, OK picture, draw yourself in some rectangle; 662 00:54:27,213 --> 00:54:30,660 这个几何公式就是这个矩形的变换规则 and then this algebra is the transformation on the rectangle. 663 00:54:30,660 --> 00:54:33,840 这句代码让矩形看起来像向侧面的 It's the one which makes it look like the rectangle is sideways, 664 00:54:33,860 --> 00:54:36,520 原点在别的地方 竖直向量在别的地方 the origin is someplace else and the vertical vector is someplace else, 665 00:54:37,133 --> 00:54:39,746 水平向量在别的地方 竖直向量在别的地方 and the horizontal vector is someplace else, and vertical vector is someplace else. 666 00:54:46,760 --> 00:54:49,906 再次注意 这里的关键是 OK, again notice, the crucial thing that's going on here 667 00:54:50,533 --> 00:55:00,973 关键是使用过程来表示图像 使其自动地具有闭包性质 is you're using the representation of pictures as procedures to automatically get the closure property, 668 00:55:01,740 --> 00:55:05,220 这是因为 实际上 BESIDE只是接受并使用P1 because what happens is, Beside just has this thing p1. 669 00:55:05,220 --> 00:55:09,400 BESIDE并不关心它是一个基本图像还是一些线段 Beside doesn't care if that's a primitive picture or it's line segments 670 00:55:09,610 --> 00:55:12,693 或者P1还是ABOVE、BESIDE、ROTATE等操作的结果 if p1 is, itself, the result of doing Aboves or Besides or Rotates. 671 00:55:12,720 --> 00:55:16,080 关于P1 BESIDE需要知道的就是 All Beside has to know about, say, p1 672 00:55:16,293 --> 00:55:19,733 给P1传递一个矩形 就会导致某物的绘制 p1 is that if you hand p1 a rectangle, it will cause something to be drawn. 673 00:55:21,040 --> 00:55:25,986 在这个层面上 BESIDE并不关心P1是如何完成绘制 And above that level, Beside just doesn't-- it's none of its business how p1 accomplishes that drawing. 674 00:55:27,733 --> 00:55:32,253 我们使用过程来表示图像 以保持它的闭包性质 All right, so you're using the procedural representation to ensure this closure. 675 00:55:35,640 --> 00:55:40,813 将图像实现为过程 使得组合的方法变得 So implementing pictures as procedures makes these means of combination, 676 00:55:41,186 --> 00:55:43,933 变得简单而优雅 both pretty simple and also, I think, elegant. 677 00:55:45,920 --> 00:55:48,220 但这并不是点睛之笔 But that's not the real punchline. 678 00:55:49,280 --> 00:55:53,520 点睛之笔来自于这门语言中抽象的方法 The real punchline comes when you look at the means of abstraction in this language. 679 00:55:54,700 --> 00:55:56,240 我们做了些什么? Because what have we done? 680 00:55:56,240 --> 00:56:03,720 我们把组合的方法实现为了过程 We've implemented the means of combination themselves as procedures. 681 00:56:05,853 --> 00:56:09,386 这也就意味着 当我们对这个语言进行抽象时 And what that means is that when we go to abstract in this language, 682 00:56:10,170 --> 00:56:15,693 Lisp提供的 操作过程的一切方法 everything that Lisp supplies us for manipulating procedures 683 00:56:16,333 --> 00:56:21,453 都可以自动地在这个图像语言中使用 automatically available to do things in this picture language. 684 00:56:21,920 --> 00:56:29,746 与其用术语“这个语言以Lisp实现” — 虽然确实如此 The technical term I want to say is not only is this language implemented in Lisp, obviously it is, 685 00:56:29,760 --> 00:56:32,580 我想描述为“这个语言嵌入于Lisp” but the language is nicely embedded in Lisp. 686 00:56:37,640 --> 00:56:42,080 也就是说 通过像这样将语言嵌入 What I mean is by embedding the language in this way, 687 00:56:42,906 --> 00:56:48,860 可以以扩展的形式 自动地获得Lisp的所有力量 all the power of Lisp is automatically available as an extension to whatever you want to do. 688 00:56:50,060 --> 00:56:51,680 这又是什么意思呢? And what do I mean by that? 689 00:56:51,973 --> 00:57:02,946 举个例子 假设我想用A B C D四副图像做东西 Example: say, suppose I want to make a thing that takes four pictures A, B, C and D, 690 00:57:03,760 --> 00:57:07,060 让它们呈现像这样的格局 and makes a configuration that looks like this. 691 00:57:12,500 --> 00:57:16,960 可以将其称为FOUR-PICT格局 Well you might call that, you know, four pictures or something, four-pict configuration. 692 00:57:16,960 --> 00:57:17,700 我该如何做呢? How do I do that? 693 00:57:17,700 --> 00:57:18,680 我可以很容易的做到这些 Well I can obviously do that. 694 00:57:18,680 --> 00:57:23,333 写个过程 让B和D做ABOVE I just write a procedure that takes B above D 695 00:57:24,133 --> 00:57:25,853 A和C做ABOVE and A above C 696 00:57:26,093 --> 00:57:27,706 得到的结果做BESIDE and puts those things beside each other. 697 00:57:28,240 --> 00:57:31,820 我自然地拥有Lisp组合过程的能力 So I automatically have Lisp's ability to do procedure composition. 698 00:57:32,920 --> 00:57:35,820 这不需要我为图像语言做些特殊处理 And I didn't have to make that specifically in the picture language. 699 00:57:35,820 --> 00:57:39,920 事实上 这些组合本身就是过程 It's automatic from the fact that the means of combination are themselves procedures. 700 00:57:40,960 --> 00:57:44,180 假设我想做一些更复杂的事情 Or suppose I wanted to do something a little bit more complicated. 701 00:57:44,180 --> 00:57:46,506 我想为这里的每一个传递一个参数 I wanted to put in a parameter so that for each of these, 702 00:57:46,520 --> 00:57:50,080 我可以独立地做旋转90度的操作 I could independently specify a rotation by 90 degrees. 703 00:57:50,413 --> 00:57:52,640 这只需要我在这个过程中加入一个参数 That's just putting a parameter in the procedure. 704 00:57:53,173 --> 00:57:54,560 它自然而然就有了这样的功能 It's automatically there. 705 00:57:54,800 --> 00:57:57,840 它自动地嵌入进去了 Right, it automatically comes from the embedding. 706 00:57:58,160 --> 00:58:05,360 甚至 假设我想使用递归 Or even more, suppose I wanted to, you know, use recursion. 707 00:58:06,160 --> 00:58:10,780 我们看一下图像递归组合的方法 Let's look at a recursive means of combination on pictures. 708 00:58:10,780 --> 00:58:14,640 定义--看看你们能理解这个不 I could say define-- let's see if you can figure out what this one is-- 709 00:58:14,693 --> 00:58:18,973 (DEFINE (RIGHT-PUSH PICT N A)) suppose I say define what it means to right-push a picture, 710 00:58:22,840 --> 00:58:29,800 RIGHT-PUSH需要图片P 整数N和缩放因数A right-push a picture and some integer N and some scale factor A. 711 00:58:31,460 --> 00:58:41,220 定义是:如果N为0 那么返回图像P I'll define this to say if N equals 0, then the answer is the picture. 712 00:58:42,200 --> 00:58:54,020 否则 就-- 哦 这里是P Otherwise I'm going to put-- oops, name change: P. 713 00:58:55,880 --> 00:59:00,213 否则 我用图形P做BESIDE操作 Otherwise, I'm going to take P and put it beside 714 00:59:00,920 --> 00:59:18,306 BESIDE的另一个操作数是(RIGHT-PUSH P (- N 1) A)的结果 the results of recursively right-pushing P with N minus 1 and A and use a scale factor of A. OK, 715 00:59:24,720 --> 00:59:31,120 如果N为0 就返回P 否则就对P进行A倍缩放 so if N 0 , it's P. Otherwise I put P with a scale factor of A-- 716 00:59:31,120 --> 00:59:32,800 抱歉 我这里代码没对齐 I'm sorry I didn't align this right-- 717 00:59:33,666 --> 00:59:38,500 递归地调用(RIGHT-PUSH P (- N 1) A) 将结果用BESIDE连接 recursively beside the result of right-pushing P, N minus 1 times with a scale factor of A. 718 00:59:38,500 --> 00:59:42,000 这就是一种递归组合方法 There's a recursive means of combination. 719 00:59:43,786 --> 00:59:44,760 调用的结果会是怎样的? What's that look like? 720 00:59:44,760 --> 00:59:45,906 我们来看看 Well, here's what it looks like. 721 00:59:46,040 --> 00:59:56,040 这是(RIGHT-PUSH GEORGE 2 0.75)的结果 There's George right-pushed against himself twice with a scale factor of 0.75. 722 00:59:59,260 --> 01:00:00,720 这个是从什么地方来的呢? Where'd that come from? 723 01:00:00,720 --> 01:00:02,340 我是如何想象出这些递归来的呢? How did I get all this fancy recursion? 724 01:00:02,340 --> 01:00:05,240 答案是无意识的 绝对是无意识的 And the answer is just automatic, absolutely automatic. 725 01:00:05,240 --> 01:00:09,800 由于它们都是过程 而嵌入的目标系统中允许定义递归过程 Since these are procedures, the embedding says, well sure, I can define recursive procedures. 726 01:00:10,360 --> 01:00:11,680 我不必自己去做 I didn't have to arrange that. 727 01:00:13,560 --> 01:00:16,420 当然 我们可以模仿这个方法做些更复杂的事 And of course, we can do more complicated things of the same sort. 728 01:00:16,420 --> 01:00:18,213 我可以定义做UP-PUSH的过程 I could make something that does an up-push. 729 01:00:18,420 --> 01:00:22,600 对 它可以递归地把图片放在原来的上面 Right, that sort of goes like this, by recursively putting something above. 730 01:00:22,600 --> 01:00:26,546 我也可以用这种策略来做些其它事 Or I could make something that, sort of, was this scheme. 731 01:00:26,560 --> 01:00:28,853 给定一个图像 I might start out with a picture 732 01:00:29,786 --> 01:00:37,160 然后递归地把它放在原图片的旁边和上面 and then, sort of, recursively both push it aside and above 733 01:00:37,573 --> 01:00:38,920 这里再放一些别的 and that might put something there. 734 01:00:39,520 --> 01:00:41,826 然后我把同样递归的图像放在这里 And then up here I put the same recursive thing, 735 01:00:42,360 --> 01:00:44,200 我可以用这个来终止 and I might end up with something like this. 736 01:00:45,400 --> 01:00:52,500 这个过程比RIGHT-PUSH复杂一点 但也不算太多 Right, so there's a procedure that's a little bit more complicated than right-push but not much. 737 01:00:53,640 --> 01:00:58,140 在BESIDE的基础上 我多加了一个ABOVE操作 I just do an Above and a Beside, rather than just a Beside. 738 01:01:01,120 --> 01:01:06,786 如果我把它应用于四张放在一起的图像上 Now if I take that and apply that with the idea of putting four pictures together, 739 01:01:07,533 --> 01:01:08,653 这样做当然没问题 which I can surely do; 740 01:01:09,013 --> 01:01:14,173 我把它应用于我们之前定义的Q上 and I go and I apply that to Q, which we defined before, right, 741 01:01:15,973 --> 01:01:18,733 我得到的是这个玩意儿 what I end up with this is this thing, 742 01:01:20,146 --> 01:01:25,266 "图像Q的方形极限" 做了两次 which is, sort of, the square limit of Q, done twice. 743 01:01:28,180 --> 01:01:32,253 好 现在我们将其与Escher的"方形极限"对比一下 Right, and then we can compare that with Escher's "Square Limit." 744 01:01:32,880 --> 01:01:34,533 可以看到 这都是基于同样的思想 And you see, it's sort of the same idea. 745 01:01:34,740 --> 01:01:36,940 当然 Escher的图像更加漂亮一些 Escher's is, of course, much, much prettier. 746 01:01:36,940 --> 01:01:44,040 如果我们回过头审视George If we go back and look at George, right, if we go look at George here-- 747 01:01:44,386 --> 01:01:47,373 我最开始用的是非常随意的设计 see, I started with a fairly arbitrary design 748 01:01:47,426 --> 01:01:49,260 用了George的图像 做了一些操作 this picture of George and did things with it. 749 01:01:51,226 --> 01:01:53,146 我们再看看Escher的图片 Right, whereas if we go look at the Escher picture, right, 750 01:01:54,080 --> 01:01:56,140 Escher的图片不是随意设计的 the Escher picture is not an arbitrary design. 751 01:01:56,140 --> 01:01:57,666 这个图案非常精妙 It's this very, very clever thing, 752 01:01:57,893 --> 01:02:00,200 当我们把鱼身 so that when you take this fish body 753 01:02:01,826 --> 01:02:04,973 把鱼身旋转并放缩 就会优美地变成下一条鱼 and Rotate it and shrink it down, it bleeds into the next one really nicely. 754 01:02:07,400 --> 01:02:11,480 当然我没有刻意处理过George And of course with George, I didn't really do anything like that. 755 01:02:12,120 --> 01:02:13,906 就图像George来说 So if we look at George, 756 01:02:15,413 --> 01:02:18,640 也有一些地方匹配 但不够好 比较随意 right, there's a little bit of match up, but not very nice, and it's pretty arbitrary. 757 01:02:18,640 --> 01:02:21,533 顺便说下 一个好的程序 One very nice project, by the way, 758 01:02:22,306 --> 01:02:27,540 应该有个过程 能接受像这里George一样的基本图像 would be to write a procedure that could take some basic figure like this George thing 759 01:02:27,866 --> 01:02:29,626 然后调整其中的线段终点 and start moving the ends of the lines around, 760 01:02:29,866 --> 01:02:31,200 这样可以得到一个好看的图像 so you got a really nice one 761 01:02:32,133 --> 01:02:34,066 在做“方形极限”应该注意这些 when you went and did that "Square Limit" process. 762 01:02:34,680 --> 01:02:36,306 这是一个非常值得思考的事情 That'd be a really nice thing to think about. 763 01:02:38,080 --> 01:02:39,720 同时 我还可以进行组合 Well so, we can combine things. 764 01:02:39,720 --> 01:02:41,040 我们还可以使用递归过程 We can recursive procedures. 765 01:02:41,040 --> 01:02:43,480 我们可以自然而然地做任何事情 We can do all kinds of things, and that's all automatic. 766 01:02:44,600 --> 01:02:48,520 重点在于 在语言中实际实现另一个语言 Right, the important point, the difference between merely implementing something in a language 767 01:02:48,693 --> 01:02:50,440 在语言中嵌入另一个语言的差异 and embedding something in the language, 768 01:02:50,440 --> 01:02:53,720 这可以让你不丢失原有语言的能力 而Lisp强大之处在于 so that you don't lose the original power of the language, and what Lisp is great at, 769 01:02:54,760 --> 01:02:57,620 Lisp是一个强悍的语言 可以处理任何特定问题 see Lisp is a lousy language for doing any particular problem. 770 01:02:57,620 --> 01:03:02,100 把你想要的语言嵌入到Lisp中才是真的好 What it's good for is figuring out the right language that you want and embedding that in Lisp. 771 01:03:02,100 --> 01:03:05,440 这才是这种设计方法的真正力量 That's the real power of this approach to design. 772 01:03:05,693 --> 01:03:06,820 我们可以深入一下 Of course, we can go further. 773 01:03:06,820 --> 01:03:08,813 在Lisp中我们还可以做些其它的事 See, you saw the other thing that we can do in Lisp 774 01:03:09,213 --> 01:03:17,520 就是将通用方法抽象成高阶过程 is capture general methods of doing things as higher order procedures. 775 01:03:19,093 --> 01:03:22,573 在我画那些图像时 你们可能已经发现 And you probably just from me drawing it got the idea that right-push 776 01:03:23,786 --> 01:03:26,613 RIGHT-PUSH和类似的过程 就是一直在上面放东西 and the analogous thing where you push something up and up and up and up 777 01:03:26,933 --> 01:03:33,820 而这个CORNER-PUSH则是一种一般性思想的泛化 and this corner push thing are all generalizations of a common kind of idea. 778 01:03:34,720 --> 01:03:37,200 为了演示并让大家熟悉 So just to illustrate and give you practice in looking at a 779 01:03:37,986 --> 01:03:40,653 使用廊腰缦回的高阶过程 at a fairly convoluted use of higher order procedures, 780 01:03:41,120 --> 01:03:47,240 我给大家示范一下“递归地重复某种组合方法”的一般性思想 let me show you the general idea of pushing some means of combination to recursively repeat it. 781 01:03:48,300 --> 01:03:50,706 这个例子可以说明一切 So here's a good one to puzzle out. 782 01:03:51,220 --> 01:04:00,700 我们可以定义一个依赖于具体组合方式的PUSH过程 We'll define it what it means to push using a means of combination. 783 01:04:01,493 --> 01:04:04,880 COMB的取值可以是BESIDE或ABOVE等 Comb is going to be something like the Beside or Above. 784 01:04:06,186 --> 01:04:07,060 过程的体是什么呢? Well what's that going to be. 785 01:04:07,060 --> 01:04:12,060 它返回一个过程 想一想BESIDE实际上是什么 That's going to be a procedure, remember what Beside actually was, right. 786 01:04:13,220 --> 01:04:15,186 它接受一个图像 It took a picture, 787 01:04:15,960 --> 01:04:18,080 哦 它接受两个图像和一个缩放因数 took two pictures and a scale factor. 788 01:04:18,626 --> 01:04:24,280 利用这个过程 定义一个接受层数、图像和缩放因数的过程 Using that I produced something that took a level number and a picture and a scale factor, 789 01:04:24,280 --> 01:04:25,453 我称之为RIGHT-PUSH that I called right-push. 790 01:04:26,160 --> 01:04:33,660 这个过程接受 图像PICT 层数N和缩放因数A So this is going to be something that takes a picture, a level number and a scale factor, and it's going to say-- 791 01:04:36,160 --> 01:04:39,120 我要做一些重复操作 I'm going to do some repeated operation. 792 01:04:39,450 --> 01:04:46,626 我会重复应用一个接受一个图像P的过程 I'm going to repeatedly apply the procedure which takes a picture 793 01:04:48,400 --> 01:04:50,693 并把组合的方式应用在 and applies the means of combination 794 01:04:51,200 --> 01:04:59,080 应用在图像PICT和在这里接受的图像P以及缩放因数A to the picture and the original picture and the one I took in here and the scale factor, 795 01:05:02,266 --> 01:05:07,280 我要重复应用这个过程N次 and I do the thing which repeats this procedure N times, 796 01:05:12,040 --> 01:05:16,200 我则是把这整个过程应用在原图片PICT上 and I apply that whole thing to my original picture. 797 01:05:19,560 --> 01:05:24,480 虽然之前没提过 这里的REPEATED也是一个高阶过程 Repeated here, in case you haven't seen it, is another higher order procedure 798 01:05:24,533 --> 01:05:28,346 它接受一个过程P和一个数字N that takes a procedure and a number 799 01:05:29,546 --> 01:05:34,293 它返回另一个过程:将给定的过程P重复应用N次的过程 and returns for you another procedure that applies this procedure N times. 800 01:05:36,040 --> 01:05:39,306 可能有些人已经在练习中编写过REPEATED了 And I think some of you have already written repeated as an exercise, 801 01:05:39,706 --> 01:05:43,013 如果还没做的话 这是理解和练习高阶过程的好机会 but if you haven't, it's a very good exercise in thinking about higher order procedures. 802 01:05:43,840 --> 01:05:46,906 无论如何 我将把REPEATED过程的结果应用到PICT上 But in any case, the result of this repeated is what I apply to picture. 803 01:05:49,466 --> 01:05:52,386 定义好PUSH后 这就 And having done that, that's going to capture the -- 804 01:05:53,120 --> 01:05:57,733 这就是从BESIDE、RIGHT-PUSH中总结出来的一般性思想 that is the thing, the way I got from the idea of Beside to the idea of right-push 805 01:05:59,013 --> 01:06:13,173 现在 我就可以把RIGHT-PUSH定义为 用BESIDE来做PUSH操作 So having done that, I could say define right-push to be push of Beside. 806 01:06:17,653 --> 01:06:20,320 我也可以把UP-PUSH定义为 用ABOVE来做PUSH操作 Or if I say, define up-push to be push of Above 807 01:06:20,346 --> 01:06:25,480 类似地 CORNER-PUSH就是用BESIDE和ABOVE的适当组合做PUSH操作 I'd get the analogous thing or define corner-push to be push of some appropriate thing that did both the Beside and Above, 808 01:06:25,493 --> 01:06:26,706 我可以用任何东西做PUSH操作 or I could push anything. 809 01:06:28,266 --> 01:06:34,760 嗯 如果你还不太理解LAMBDA的话 可以参考这个例子 Anyway this is, if you're having trouble with lambdas, this is an excellent exercise in figuring out what this means. 810 01:06:38,986 --> 01:06:41,000 我们可以从这个例子中学到很多东西 OK, well there's a lot to learn from this example. 811 01:06:42,186 --> 01:06:49,800 我主要想要介绍的是在一个语言中嵌入另一个语言 The main point I've been welling on is the notion of nicely embedding a language inside another language. 812 01:06:50,666 --> 01:06:55,626 这样 母体语言--本例中是Lisp--的所有能力 Right, so that all the power of this language like Lisp of the surrounding language 813 01:06:55,920 --> 01:07:00,280 可以作为你所构建语言的一种扩展而取得 is still accessible to you and appears as a natural extension of the language that you built. 814 01:07:00,986 --> 01:07:04,000 这个例子很好地展示了这点 That's one thing that this example shows very well. 815 01:07:08,146 --> 01:07:10,940 另外 当我们回过头去思考 Another thing is, if you go back and think about that, 816 01:07:10,940 --> 01:07:12,280 什么是过程 什么是数据 what's procedures and what's data. 817 01:07:12,280 --> 01:07:16,200 在这里 天啊 发生了什么 You know, by the time we get up to here, my God, what's going on. 818 01:07:16,200 --> 01:07:19,660 在这里 这是一个过程 它接受一个图像和一个参数 I mean, this is some procedure, and it takes a picture and an argument, 819 01:07:19,660 --> 01:07:20,360 但是 什么是图像呢? and what's a picture. 820 01:07:20,360 --> 01:07:23,820 请回想 图像本身 就是一个以矩形为参数的过程 Well, a picture itself, as you remember, was a procedure, and that took a rectangle. 821 01:07:23,820 --> 01:07:25,820 这个矩形是某种抽象 And a rectangle is some abstraction. 822 01:07:26,093 --> 01:07:28,133 我希望你们现在能彻底明白 And I hope now that by now you're completely lost 823 01:07:29,146 --> 01:07:33,740 系统中什么是过程 什么是数据 as to the question of what in the system is procedure and what's data. 824 01:07:33,740 --> 01:07:34,780 我们发现 它们没有任何区别 You see, there isn't any difference. 825 01:07:35,493 --> 01:07:36,440 真的没有区别 There really isn't. 826 01:07:37,933 --> 01:07:41,426 你可以认为图像有时候是过程 有时候是数据 And you might think of a picture sometimes as a procedure and sometimes as data, 827 01:07:41,840 --> 01:07:44,900 但是 这只是让你容易理解的一种方法 but that's just, sort of, you know, making you feel comfortable. 828 01:07:44,900 --> 01:07:47,306 这有一定道理 也没有道理 It's really both in some sense or neither in some sense. 829 01:07:49,920 --> 01:08:02,200 关于系统的结构 一种更普遍的观点将其视作创建一种语言 OK, there's a more general point about the structure of the system as creating a language, 830 01:08:02,520 --> 01:08:06,746 将工程设计过程看作是创建一门语言 viewing the engineering design process as one of creating language or 831 01:08:07,840 --> 01:08:13,973 准确来说 是创建各种层次的语言 or rather one of creating a sort of sequence of layers of language. 832 01:08:14,773 --> 01:08:20,013 众所周知 有一种方法学 或者叫做“神话学” You see, there's this methodology, or maybe I should say mythology, 833 01:08:20,746 --> 01:08:24,900 姑且叫做软件“工程” that's, sort of, charitably called software, quote, engineering. 834 01:08:25,213 --> 01:08:28,040 它声称 你要先计算出你的任务 All right, and what does it say, it's says well, you go and you figure out your task, 835 01:08:28,040 --> 01:08:30,040 精确且正确地计算出你的任务 and you figure out exactly what you want to do. 836 01:08:30,400 --> 01:08:32,200 一但你搞清楚要做的东西 And once you figure out exactly what you want to do, 837 01:08:32,226 --> 01:08:34,540 你把它划分为三个子任务 you find out that it breaks out into three sub-tasks, 838 01:08:34,540 --> 01:08:35,760 然后你开始继续做-- and you go and you start working on-- 839 01:08:35,973 --> 01:08:38,940 你开始处理这个子任务 然后你明确它是什么 and you work on this sub-task, and you figure out exactly what that is. 840 01:08:38,940 --> 01:08:43,040 这个子问题就分裂成三个子任务 你把它们处理完 And you find out that that breaks down into three sub-tasks, and you specify them completely, 841 01:08:43,040 --> 01:08:47,320 然后你先处理这两个任务 and you go and you work on those two, and you work on this sub-one, and you specify that exactly. 842 01:08:47,320 --> 01:08:51,100 解决完子任务后 你后退到这里 处理第二个子任务 And then finally when you're done, you come back way up here, and you work on your second sub-task, 843 01:08:51,100 --> 01:08:53,400 然后把它详细地实现出来 and specify that out and work it out. 844 01:08:53,400 --> 01:08:57,640 结束之后-- 你完成了这个美丽的大厦 And then you end up with-- you end up at the end with this beautiful edifice. 845 01:08:57,640 --> 01:09:00,253 你最后得到了一棵非凡的树 Right, you end up with a marvelous tree, 846 01:09:00,893 --> 01:09:08,240 你把任务划分为子任务 子任务再划分为子任务 that where you've broken your task into sub-tasks and broken each of these into sub-tasks and broken those into sub-tasks, right. 847 01:09:09,880 --> 01:09:15,026 树中的每个结点都被严谨而准确地定义 And each of these nodes is exactly and precisely defined 848 01:09:15,260 --> 01:09:18,666 为奇妙而精美的任务 以构建整栋大厦 to do the wonderful, beautiful task to make it fit into the whole edifice 849 01:09:18,960 --> 01:09:21,140 这个就是所谓的“神话学” Right, that's this mythology. 850 01:09:21,140 --> 01:09:25,920 只有计算机科学家才可能相信你构建的复杂系统像这个样子 See only a computer scientist could possibly believe that you build a complex system like that 851 01:09:27,480 --> 01:09:32,800 好了 我们用Henderson的例子来做对比 Right. Contrast that with this Henderson example. 852 01:09:32,800 --> 01:09:34,300 它的结构不是那样 It didn't work like that. 853 01:09:35,260 --> 01:09:39,333 事实是:这里有一个语言的层次序列 What happened was that there was a sequence of layers of language. 854 01:09:41,066 --> 01:09:42,053 它是什么? What happened? 855 01:09:42,180 --> 01:09:48,760 这里有一层 允许我们构建基本图像 There was a layer of a thing that allowed us to build primitive pictures. 856 01:09:51,693 --> 01:09:56,240 这个语言描述基本图像 There's primitive pictures and that was a language. 857 01:09:56,320 --> 01:09:57,840 我们并没有做过多地讨论 I didn't say much about it. 858 01:09:58,220 --> 01:09:59,586 我们讨论了如何构造George We talked about how to construct George, 859 01:09:59,613 --> 01:10:04,880 这个语言是在单位正方形中讨论点、线和向量 but that was a language where you talked about vectors and line segments and points and where they sat in the unit square. 860 01:10:06,426 --> 01:10:11,293 而在这之上 And then on top of that, right, on top of that-- 861 01:10:11,973 --> 01:10:14,106 这是讨论基本图像的语言 so this is the language of primitive pictures. 862 01:10:17,080 --> 01:10:20,360 讨论在特定单位正方形中线段的构造 Right, talking about line segments in particular pictures in the unit square. 863 01:10:21,400 --> 01:10:23,800 在这个上面是另一个完整的语言 On top of that was a whole language. 864 01:10:24,053 --> 01:10:30,866 关于几何组合子的语言 There was a language of geometric combinators, 865 01:10:32,666 --> 01:10:36,626 关于几何物件的位置 a language of geometric positions, 866 01:10:38,773 --> 01:10:46,500 讨论像ABOVE、BESIDE、RIGHT-PUSH和ROTATE这样的东西 which talks about things like Above and Beside and right-push and Rotate. 867 01:10:48,040 --> 01:10:55,700 这些事情恰巧与我们在这个语言中谈论的事情有关 And those things, sort of, happened with reference to the things that are talked about in this language. 868 01:10:58,570 --> 01:11:00,933 再细化一点 我们发现在这之上 And then if we like, we saw that above that 869 01:11:02,613 --> 01:11:15,100 还有一门语言 描述组合的模式 there was sort of a language of schemes of combination. 870 01:11:21,250 --> 01:11:22,440 比如说PUSH For example, push, 871 01:11:24,453 --> 01:11:27,880 也就是用一个放缩因子重复地做一件事儿 which talked about repeatedly doing something over with a scale factor. 872 01:11:28,380 --> 01:11:31,280 我们在那门语言中讨论的问题 And the things that were being discussed in that language 873 01:11:31,506 --> 01:11:34,346 正是我这里构建的东西 were, sort of, the things that happened down here. 874 01:11:36,306 --> 01:11:42,760 我们在每一层上所讨论的对象 So what you have is, at each level, the objects that are being talked about 875 01:11:44,680 --> 01:11:47,000 都是前一个层次所建立的 are the things that were erected the previous level. 876 01:11:48,080 --> 01:11:52,060 这个和这个有什么区别呢? What's the difference between this thing and this thing? 877 01:11:53,346 --> 01:11:54,186 这是因为 The answer is 878 01:11:56,146 --> 01:12:01,733 实际上在这里 树的每一个结点 每一次分解 that over here in the tree, each node, and in fact, each decomposition down here, 879 01:12:02,146 --> 01:12:05,253 都是旨在分成确定的任务 is being designed to do a specific task, 880 01:12:07,506 --> 01:12:08,880 而在另一个方案中 whereas in the other scheme, 881 01:12:09,213 --> 01:12:14,800 你在每个层级上的完完全全的语言层面的能力 what you have is a full range of linguistic power at each level. 882 01:12:16,000 --> 01:12:18,080 这里的每一个层次 See what's happening there, at any level, 883 01:12:20,240 --> 01:12:22,720 都不是被设计为完成一个特定任务 it's not being set up to do a particular task. 884 01:12:23,146 --> 01:12:26,173 它被设计为讨论整个事情 It's being set up to talk about a whole range of things. 885 01:12:27,620 --> 01:12:30,786 这样设计导致的结果是: The consequence of that for design 886 01:12:31,146 --> 01:12:35,586 用这种设计方法更加健壮 is that something that's designed in that method is likely to be more robust, 887 01:12:36,613 --> 01:12:38,200 我所谓的“健壮”是指 where by robust, I mean 888 01:12:38,440 --> 01:12:41,240 当你在描述中做一些改变 that if you go and make some change in your description, 889 01:12:42,700 --> 01:12:48,040 我们可以做出相应的改变 it's more likely to be captured by a corresponding change, 890 01:12:49,226 --> 01:12:52,600 用上一层语言实现的方法改变即可 in the way that the language is implemented at the next level up, 891 01:12:54,293 --> 01:12:56,586 因为你让每个层次都是完全的 right, because you've made these levels full. 892 01:12:56,620 --> 01:12:59,660 所以你不需要讨论像BESIDE这样的特定操作 So you're not talking about a particular thing like Beside. 893 01:12:59,946 --> 01:13:03,786 你为表达这类事物创造了完备的词汇 You've given yourself a whole vocabulary to express things of that sort, 894 01:13:04,773 --> 01:13:07,020 所以当你轻微修改规格指标时 so if you go and change your specifications a little bit, 895 01:13:07,020 --> 01:13:11,386 这种方法论可以捕捉并适应那些变化 it's more likely that your methodology will able to adapt to capture that change, 896 01:13:12,693 --> 01:13:15,020 然而这种设计却不够健壮 whereas a design like this is not going to be robust, 897 01:13:15,020 --> 01:13:17,080 因为 如果我在这里改变一下 because if I go and change something that's in here, 898 01:13:17,533 --> 01:13:21,693 那可能会影响我划分这些东西的方式 严重地影响 that might affect the entire way that I decomposed everything down, further down the tree. 899 01:13:23,200 --> 01:13:29,740 分解观点的最大不同在于 按层次还是严格继承分解 Right, so very big difference in outlook in decomposition, levels of language rather than, sort of, a strict hierarchy. 900 01:13:30,520 --> 01:13:33,026 不只是如此 当你有多个层次的语言时 Not only that, but when you have levels of language 901 01:13:33,506 --> 01:13:35,920 你就有了不同的词汇储备 you've given yourself a different vocabularies 902 01:13:36,453 --> 01:13:38,740 用于讨论不同层次上的设计 for talking about the design at different levels. 903 01:13:38,740 --> 01:13:40,920 我们再回过头来看看George So if we go back and look at George one last time, 904 01:13:41,906 --> 01:13:44,080 如果我想改变图像George if I wanted to change this picture George, 905 01:13:45,853 --> 01:13:48,680 我立马得到了一种不同的方式来描述变化 see suddenly I have a whole different ways of describing the change. 906 01:13:48,680 --> 01:13:56,080 比如 我想在基本设计的层面上 移动某些向量的终点 Like for example, I may want to go to the basic primitive design and move the endpoint of some vector. 907 01:13:57,760 --> 01:14:00,760 我会在最底层讨论这个改变 That's a change that I would discuss at the lowest level. 908 01:14:01,000 --> 01:14:02,506 我会另外指定终点位置 I would say the endpoint is somewhere else. 909 01:14:03,346 --> 01:14:07,986 我也可以说 我想在这个小的重复元素上做文章 Or I might come up and say, well the next thing I wanted to do, this little replicated element, 910 01:14:09,106 --> 01:14:10,940 我可能想做些其它操作 I might want to do by something else. 911 01:14:10,940 --> 01:14:13,840 我想在BESIDE中使用一个缩放因数 I might want to put a scale factor in that Beside. 912 01:14:13,840 --> 01:14:19,340 这个改变我会在更高的层次上讨论:在组合子的层次 That's a change that I would discuss at the next level of design, the level of combinators. 913 01:14:19,340 --> 01:14:25,053 我也可以改变图像的基本组合模式 Or I might want to say, I might want to change the basic way that I took this pattern 914 01:14:26,493 --> 01:14:30,480 做一些递归地分解 可能不会让它们填充满角落 and made some recursive decomposition, maybe not bleeding out toward the corners or something else. 915 01:14:31,160 --> 01:14:34,180 而这样的一个变化 我会在最高层次讨论 That would be a change that I would discuss at the highest level. 916 01:14:34,180 --> 01:14:36,373 正是因为我按这种结构组织系统 And because I've structured the system to be this way, 917 01:14:36,520 --> 01:14:39,626 我有所有的词汇 可以用不同的方式描述变化 I have all these vocabularies for talking about change in different ways 918 01:14:39,653 --> 01:14:42,480 而且可以灵活地决定哪个更合适 and a lot of flexibility to decide which one's appropriate. 919 01:14:44,740 --> 01:14:51,053 这就是Lisp中不同于软件工程方法论的最大要点 OK, well that's sort of a big point about the difference in software methodology that comes out from Lisp, 920 01:14:51,250 --> 01:14:55,453 它来自于这样一个观点:真正的设计过程 and it all comes again, out of the notion that really, the design process 921 01:14:56,120 --> 01:14:59,620 与其说是在设计程序 不如说是在设计语言 is not so much implementing programs as implementing languages. 922 01:14:59,620 --> 01:15:01,093 而这就是Lisp的力量 And that's really the power of Lisp. 923 01:15:02,213 --> 01:15:03,613 谢谢大家 下课 OK, thank you. Let's take a break. 924 01:15:05,690 --> 01:15:15,626 MIT OpenCourseWare http://ocw.mit.edu 925 01:15:15,653 --> 01:15:23,370 本项目主页 https://github.com/FoOTOo/Learning-SICP ================================================ FILE: SrtCN/lec3b.srt ================================================ 1 00:00:00,000 --> 00:00:02,320 Learning-SICP学习小组 倾情制作 2 00:00:02,573 --> 00:00:06,013 翻译&&时间轴:邓雄飞(Dysprosium) 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:06,066 --> 00:00:08,973 特别感谢:裘宗燕教授 4 00:00:11,240 --> 00:00:14,460 符号化求导系统,引用 Symbolic Differentiation: Quotation 5 00:00:19,100 --> 00:00:23,413 教授:嗯 Harold教授讲解了如何构造健壮的系统 PROFESSOR: Well, Hal just told us how you build robust systems. 6 00:00:23,800 --> 00:00:26,173 关键点就是 The key idea was-- 7 00:00:26,813 --> 00:00:30,200 我想你们大多还没吃透其中的要点 I'm sure that many of you don't really assimilate that yet-- 8 00:00:30,200 --> 00:00:33,773 要点就是 为了让系统具有健壮性 but the key idea is that in order to make a system that's robust, 9 00:00:33,933 --> 00:00:36,480 应该让它对小变化不敏感 it has to be insensitive to small changes, 10 00:00:36,600 --> 00:00:37,373 也就是说 that is, 11 00:00:37,373 --> 00:00:40,906 问题中的小改变只会导致解决方案的小改动 a small change in the problem should lead to only a small change in the solution. 12 00:00:41,320 --> 00:00:42,906 系统应该是连续的 There ought to be a continuity. 13 00:00:42,900 --> 00:00:45,946 在问题空间中 解的空间是连续的 The space of solutions ought to be continuous in this space of problems. 14 00:00:46,253 --> 00:00:48,760 Harold教授给你们解释过 The way he was explaining how to do that 15 00:00:49,460 --> 00:00:54,786 与其在问题分解出的子问题上 求解具体问题 was instead of solving a particular problem at every level of decomposition of the problem at the subproblems, 16 00:00:55,080 --> 00:00:56,780 你不如解决一类问题 where you solve the class of problems, 17 00:00:56,780 --> 00:01:00,400 也就是你想要解决的具体问题的“邻居” which are a neighborhood of the particular problem that you're trying to solve. 18 00:01:01,400 --> 00:01:04,760 解决之道便是在该层次上构造一门语言 The way you do that is by producing a language at that level of detail 19 00:01:04,760 --> 00:01:10,333 使得我们可以用这门语言来表述这类问题 in which the solutions to that class of problems is representable in that language. 20 00:01:11,373 --> 00:01:15,093 因此 当着手解决的问题再发生变动时 Therefore when you change makes more changes to the problem you're trying to solve, 21 00:01:15,090 --> 00:01:19,293 通常 你只需要在已构造好的解决方案上做出微小改动 you generally have to make only small local changes to the solution you've constructed, 22 00:01:19,293 --> 00:01:22,266 因为在你所考虑的层次上 because at the level of detail you're working, 23 00:01:22,266 --> 00:01:24,266 有一门语言可以表达 there's a language where you can express 24 00:01:24,800 --> 00:01:28,146 类似问题的各种解法 the various solutions to alternate problems of the same type. 25 00:01:30,040 --> 00:01:33,746 呃... 这是一个重要思想的萌芽 Well that's the beginning of a very important idea, 26 00:01:34,400 --> 00:01:38,613 该思想的重要性也使得计算机科学比 the most important perhaps idea that makes computer science more powerful 27 00:01:38,613 --> 00:01:42,373 其它大多数工程学科还要强大 than most of the other kinds of engineering disciplines we know about. 28 00:01:43,386 --> 00:01:44,733 目前为止 我们学习的是 What we've seen so far 29 00:01:44,733 --> 00:01:48,786 类似于 如何使用语言内置元素 is sort of how to use embedding of languages. 30 00:01:49,266 --> 00:01:53,360 当然 内置元素的力量一部分来源于 And, of course, the power of embedding languages partly comes from 31 00:01:54,120 --> 00:01:56,866 像这个一样的过程 我昨天给你们展示过了 procedures like this one that I showed you yesterday. 32 00:01:57,373 --> 00:02:02,133 这里 是一份求导程序 昨天给你们描述过了 What you see here is the derivative program that we described yesterday. 33 00:02:02,130 --> 00:02:05,920 这个过程以一个过程为参数 It's a procedure that takes a procedure as an argument 34 00:02:06,000 --> 00:02:07,920 并返回一个过程 and returns a procedure as a value. 35 00:02:09,613 --> 00:02:12,653 用这样的东西棒极了 And using such things is very nice. 36 00:02:12,653 --> 00:02:14,653 你可以像创建PUSH组合子那样构造 You can make things like push combinators 37 00:02:14,650 --> 00:02:16,866 可以像上节课看到的那些奇妙东西那样 and all that sort of wonderful thing that you saw last time. 38 00:02:17,680 --> 00:02:20,546 现在 我要来打个太极 However, now I'm going to really muddy the waters. 39 00:02:21,560 --> 00:02:25,906 这个程序混淆了过程和数据 See this confuses the issue of what's the procedure and what is data, 40 00:02:26,560 --> 00:02:27,813 虽然程度不算太重 but not very badly. 41 00:02:28,426 --> 00:02:30,906 而我们将要严重地混淆两者 What we really want to do is confuse it very badly. 42 00:02:31,186 --> 00:02:32,440 最好的做法就是 And the best way to do that 43 00:02:32,440 --> 00:02:37,626 参与到过程自身所描述的代数表达式的操作中 is to get involved with the manipulation of the algebraic expressions that the procedures themselves are expressed in. 44 00:02:39,733 --> 00:02:45,586 所以 这里我不会讨论这张幻灯片上的东西 So at this point, I want to talk about instead of things like on this slide, 45 00:02:45,893 --> 00:02:49,720 一个通过操作过程的求导程序 the derivative procedure being a thing that manipulates a procedure-- 46 00:02:49,720 --> 00:02:51,946 这只是一个数值化方法而已 this is a numerical method you see here. 47 00:02:51,946 --> 00:02:58,933 你们所看到的是 通过数值方法来近似的求导程序 And what you're seeing is a representation of the numerical approximationto the derivative. 48 00:02:59,293 --> 00:03:00,440 也就是这里的东西了 That's what's here. 49 00:03:00,866 --> 00:03:04,933 事实上 我想讨论的是这些东西 In fact what I'd like to talk about is instead things that look like this. 50 00:03:06,053 --> 00:03:11,333 这是一份从微积分书中摘录的法则 And what we have here are rules from a calculus book. 51 00:03:12,093 --> 00:03:16,173 这对表达式求导的法则 These are rules for finding the derivatives of the expressions 52 00:03:16,706 --> 00:03:20,586 只不过是用代数语言书写的 that one might write in some algebraic language. 53 00:03:21,640 --> 00:03:24,413 法则说 常数的导数是0 It says things like a derivative of a constant is 0. 54 00:03:25,133 --> 00:03:29,093 而代表你所讨论的那个数的变量导数为1 The derivative of the valuable with respect to which you are taking the derivative is 1. 55 00:03:29,320 --> 00:03:31,933 常数乘以函数的导数 The derivative of a constant times the function 56 00:03:32,093 --> 00:03:34,373 其值是常数的值乘以函数导数的值 is the constant times the derivative of the function, 57 00:03:34,773 --> 00:03:36,040 就是这个意思 and things like that. 58 00:03:38,053 --> 00:03:41,386 这些都是精确的表达式 而非数值近似 These are exact expressions. These are not numerical approximations. 59 00:03:42,960 --> 00:03:44,520 我们还能编写程序吗? Can we make programs? 60 00:03:44,520 --> 00:03:52,240 事实上 编写处理这些表达式的程序非常容易 And, in fact, it's very easy to make programs that manipulate these expressions. 61 00:03:56,386 --> 00:03:59,520 让我们仔细地看看这些法则 Well let's see. Let's look at these rules in some detail. 62 00:04:01,080 --> 00:04:05,226 你们曾经在初等微积分课上学过这些法则了 You all have seen these rules in your elementary calculus class at one time or another. 63 00:04:05,980 --> 00:04:12,120 你们知道 微积分中对多元表达式求导很容易 And you know from calculus that it's easy to produce derivatives of arbitrary expressions. 64 00:04:12,533 --> 00:04:16,053 在微积分课上 你们也知道计算积分不容易 You also know from your elementary calculus that it's hard to produce integrals. 65 00:04:16,986 --> 00:04:19,373 虽然积分和求导相对 Yet integrals and derivatives are opposites of each other. 66 00:04:19,520 --> 00:04:21,280 它俩互为逆运算 They're inverse operations. 67 00:04:21,613 --> 00:04:23,306 但它们有同样的法则 And they have the same rules. 68 00:04:24,160 --> 00:04:29,680 但这些法则中又有什么特殊的东西 What is special about these rules that makes it possible for one 69 00:04:29,680 --> 00:04:33,653 使得求导容易 求积分就困难呢? to produce derivatives easily and integrals why it's so hard? 70 00:04:34,853 --> 00:04:36,986 我们浅显地想一想 Let's think about that very simply. 71 00:04:37,400 --> 00:04:38,386 仔细考察法则 Look at these rules. 72 00:04:39,360 --> 00:04:43,066 对于每条法则来说 你求导数时的方向 Every one of these rules, when used in the direction for taking derivatives, 73 00:04:43,060 --> 00:04:44,800 这个箭头的方向 which is in the direction of this arrow, 74 00:04:46,680 --> 00:04:49,160 法则的左边与你的表达式相匹配 the left side is matched against your expression, 75 00:04:49,160 --> 00:04:53,053 法则的右边就是表达式的导数 and the right side is the thing which is the derivative of that expression. 76 00:04:54,026 --> 00:04:55,653 箭头是这个方向的 The arrow is going that way. 77 00:04:57,373 --> 00:05:00,453 每条法则中 In each of these rules, 78 00:05:01,240 --> 00:05:03,720 法则右边的表达式 the expressions on the right-hand side of the rule 79 00:05:03,720 --> 00:05:06,560 都是求导过程中的子表达式 that are contained within derivatives are subexpressions, 80 00:05:06,560 --> 00:05:10,293 都是左边式子的合法子表达式 are proper subexpressions, of the expression on the left-hand side. 81 00:05:10,600 --> 00:05:13,253 这里 我们发现 和的导数 So here we see the derivative of the sum, 82 00:05:13,920 --> 00:05:16,133 也就是左边式子的导数 witch is the expression on the left-hand side 83 00:05:16,133 --> 00:05:18,386 就是两部分导数之和 is the sum of the derivatives of the pieces. 84 00:05:20,080 --> 00:05:24,493 法则从左至右的方向是“归约规则” So the rule of moving to the right are reduction rules. 85 00:05:25,026 --> 00:05:26,613 问题变简单了 The problem becomes easier. 86 00:05:27,560 --> 00:05:31,480 我把一个复杂的问题 转化成了许多小点儿的问题 I make, I turn a big complicated problem it's lots of smaller problems 87 00:05:32,440 --> 00:05:35,760 然后把结果组合起来 这里用递归可以完美地解决 and then combine the results, a perfect place for recursion to work. 88 00:05:36,586 --> 00:05:40,853 但如果我从另外的方向来思考 If I'm going in the other direction like this, 89 00:05:41,813 --> 00:05:45,133 如果我想求积分的话 你会发现有很多问题 if I'm trying to produce integrals, well there are several problems you see here. 90 00:05:45,240 --> 00:05:49,093 就比如 如果我想求一个和的积分 First of all, if I try to integrate an expression like a sum, 91 00:05:49,213 --> 00:05:50,813 就会匹配多条法则 more than one rule matches. 92 00:05:50,810 --> 00:05:52,106 这条匹配 Here's one that matches. 93 00:05:52,480 --> 00:05:53,653 这条也匹配 Here's one that matches. 94 00:05:54,813 --> 00:05:57,093 我不知道该用哪个——它们之间可能不一样 I don't know which one to take. And they may be different. 95 00:05:57,706 --> 00:06:00,000 我得考察两者的不同之处 I may get to explore different things. 96 00:06:00,253 --> 00:06:03,640 所以 在这个方向上 表达式变复杂了 Also, the expressions become larger in that direction. 97 00:06:04,533 --> 00:06:06,306 当表达式变复杂时 And when the expressions become larger, 98 00:06:06,306 --> 00:06:10,560 就没法保证我所选的路径一定能终止了 then there's no guarantee that any particular path I choose will terminate, 99 00:06:10,946 --> 00:06:13,466 因为唯一的可能是偶然的约分 because we will only terminate by accidental cancellation. 100 00:06:14,240 --> 00:06:18,053 这也就是为什么 积分是一种复杂的搜索 而难以完成 So that's why integrals are complicated searches and hard to do. 101 00:06:19,120 --> 00:06:20,960 现在我不想处理这么复杂的东西 Right now I don't want to do anything as hard as that. 102 00:06:21,493 --> 00:06:23,066 我们先来讨论求导数 Let's work on derivatives for a while. 103 00:06:24,146 --> 00:06:28,133 好吧 我就假设你们都大致了解这些法则了 Well, these rules are ones you know for the most part hopefully. 104 00:06:28,786 --> 00:06:31,880 让我们来看看能不能用程序表达这些法则 So let's see if we can write a program which is these rules. 105 00:06:32,226 --> 00:06:33,720 这应该很容易 And that should be very easy. 106 00:06:34,893 --> 00:06:36,213 信手拈来 Just write the program. 107 00:06:36,690 --> 00:06:39,293 因为 我给你们展示的是“归约规则” See, because while I showed you is that it's a reduction rule, 108 00:06:39,293 --> 00:06:41,293 这样用递归来编写会比较合适 it's something appropriate for a recursion. 109 00:06:43,080 --> 00:06:45,720 当然 对每条法则来说就是一种情况 And, of course, what we have for each of these rules is we have a case 110 00:06:46,666 --> 00:06:47,786 我们做“分情况分析” in some case analysis. 111 00:06:48,586 --> 00:06:50,360 我就这么写了 So I'm just going to write this program down. 112 00:06:52,880 --> 00:06:57,693 当然 我得先让大家达成共识 对吧? Now, of course, I'm going to be saying something you have to believe. Right? 113 00:06:57,690 --> 00:07:00,333 你们应该意识到到我可以表示这些代数式 What you have to believe is I can represent these algebraic expressions, 114 00:07:00,680 --> 00:07:03,880 我可以从中抽取式子 也可以将它们组合起来 that I can grab their parts, that I can put them together. 115 00:07:04,240 --> 00:07:06,493 我们发明了表结构来解决这个问题 We've invented list structures so that you can do that. 116 00:07:07,520 --> 00:07:09,146 但现在我们不必关心 But you don't want to worry about that now. 117 00:07:09,666 --> 00:07:12,453 现在 我要编写一个程序来封装这些法则 Right now I'm going to write the program that encapsulates these rules 118 00:07:12,760 --> 00:07:15,853 但它不依赖于代数表达式的表示法 independent of the representation of the algebraic expressions. 119 00:07:20,426 --> 00:07:28,840 (DERIV EXP VAR)表示表达式EXP关于变量VAR的导数 You have a derivative of an expression with respect to a variable. 120 00:07:30,506 --> 00:07:33,080 这和函数的导数是不一样的 This is a different thing than the derivative of the function. 121 00:07:34,826 --> 00:07:38,613 那个是我们上节课看到的数值近似 That's what we saw last time, that numerical approximation. 122 00:07:39,000 --> 00:07:40,826 并不能看到函数内部 It's something you can't open up a function. 123 00:07:40,820 --> 00:07:41,893 它只是一个数值 It's just the answers. 124 00:07:43,093 --> 00:07:45,186 表达式的导数也是一个表达式 The derivative of an expression is the way it's written. 125 00:07:45,746 --> 00:07:47,853 因此 这只是一个语法问题 And therefore it's a syntactic phenomenon. 126 00:07:48,293 --> 00:07:51,626 我们今天要做的大多数工作 就是讨论语法 And so a lot of what we're going to be doing today is worrying about syntax, 127 00:07:52,333 --> 00:07:54,120 表达式的语法或类似 syntax of expressions and things like that. 128 00:07:54,706 --> 00:07:55,933 首先要做“分情况分析” Well, there's a case analysis. 129 00:07:57,500 --> 00:08:01,080 任何时候我们处理复杂事物 需要递归求解时 Anytime we do anything complicated thereby a recursion, 130 00:08:01,080 --> 00:08:02,640 我们很可能需要“按情况分析” we presumably need a case analysis. 131 00:08:03,626 --> 00:08:05,160 通常都是这样开始的 It's the essential way to begin. 132 00:08:05,160 --> 00:08:07,400 复杂的问题都是用“按情况分析” And that's usually a conditional of some large kind. 133 00:08:08,080 --> 00:08:09,973 那么 有哪些可能(的情况)呢? Well, what are their possibilities? 134 00:08:09,973 --> 00:08:12,533 第一条法则说 如果你遇到一个常数 the first rule that you saw is this something a constant? 135 00:08:16,506 --> 00:08:17,506 这里 我就是在判断 And what I'm asking is, 136 00:08:17,506 --> 00:08:22,226 表达式EXP是否为给定变量VAR的常数(常量表达式) is the expression a constant with respect to the variable given? 137 00:08:24,906 --> 00:08:27,080 是的话 结果就是0 If so, the result is 0, 138 00:08:27,506 --> 00:08:30,106 因为导数表征的是某物的变化率 because the derivative represents the rate of change of something. 139 00:08:31,760 --> 00:08:32,653 然而 If, however, 140 00:08:32,893 --> 00:08:40,693 如果我求导的表达式 与我关心的变量有关 the expression that I'm taking the derivative of is the variable I'm varying, 141 00:08:41,720 --> 00:08:50,426 如果判定表达式和变量相同 then this is the same variable, the expression var, 142 00:08:51,146 --> 00:08:54,520 那么关于变量VAR的表达式EXP的变化率就是1 then the rate of change of the expression with respect to the variable is 1. 143 00:08:55,506 --> 00:08:56,546 它俩相同 结果是1 It's the same 1. 144 00:08:58,906 --> 00:09:00,773 当然 还可能有其它的可能性 Well now there are a couple of other possibilities. 145 00:09:01,333 --> 00:09:03,146 比如说 它可能是一个和式 It could, for example, be a sum. 146 00:09:03,866 --> 00:09:05,880 呃 我现在还完全知道该如何表示和式 Well, I don't know how I'm going to express sums yet. 147 00:09:06,090 --> 00:09:08,253 事实上我可以 只是我还没有告诉你们 Actually I do. But I haven't told you yet. 148 00:09:10,346 --> 00:09:11,786 如果表达式是和式 But is it a sum? 149 00:09:12,480 --> 00:09:14,480 我就假想有一种方式可以判别(和式) I'm imagining that there's some way of telling. 150 00:09:15,306 --> 00:09:19,440 这里 我要做一个表达式的类型分派 I'm doing a dispatch on the type of the expression here, 151 00:09:20,773 --> 00:09:23,573 这是在构建语言时绝对必要的 absolutely essential in building languages. 152 00:09:24,720 --> 00:09:26,373 因为语言由不同的表达式构成 Cause languages are made out of different expressions. 153 00:09:26,480 --> 00:09:27,546 我们马上就将看到 And soon we're going to see that 154 00:09:27,840 --> 00:09:31,026 如何用更强大的方法 用语言去构建语言 in our more powerful methods of building languages on languages. 155 00:09:32,533 --> 00:09:34,026 表达式是和式吗? Is an expression a sum? 156 00:09:35,453 --> 00:09:38,826 如果是的话 很好 我们已经知道和式的求导法则了 If it's a sum, well, we know the rule for derivative of the sum 157 00:09:38,826 --> 00:09:41,333 即是各部分导数之和 is the sum of the derivatives of the parts. 158 00:09:42,133 --> 00:09:44,320 其中一个叫做加数 另一个叫做被加数 One of them is called the addend and the other is the augend. 159 00:09:44,320 --> 00:09:46,800 黑板上没那么多空间写这么长的名字了 But I don't have enough space on the blackboard to such long names. 160 00:09:46,800 --> 00:09:48,400 我就姑且把它们叫做 A1和A2 So I'll call them A1 and A2. 161 00:09:49,040 --> 00:09:50,373 把它们求和 I want to make a sum. 162 00:09:53,533 --> 00:09:55,680 (意义不明) Do you remember which is the sub for head or the menu end? 163 00:09:57,146 --> 00:10:01,093 是叫做被除数和除数一类的么? Or was it the dividend and the divisor or something like that? 164 00:10:01,653 --> 00:10:08,480 将A1的导数...加上 Make sum of the derivative of the A1, I'll call it. 165 00:10:08,480 --> 00:10:13,293 这是关于变量VAR的表达式的加数 It's the addend of the expression with respect to the variable, 166 00:10:14,840 --> 00:10:22,760 与A2的导数相加 and the derivative of the A2 of the expression, 167 00:10:24,120 --> 00:10:28,253 这两个参数的和 变量是VAR those the two arguments, the addition. Respect to the variable. 168 00:10:32,360 --> 00:10:34,933 我们知道还有一条乘法的求导法则 And another rule that we know is product rule, 169 00:10:35,200 --> 00:10:37,440 也就是说 如果表达式是乘式 which is, if the expression is a product. 170 00:10:43,213 --> 00:10:46,106 顺便说下 当你定义过程时 有个好习惯 By the way, it's a good idea when you're defining things, 171 00:10:46,960 --> 00:10:48,320 就是在定义谓词时 when you're defining predicates, 172 00:10:48,853 --> 00:10:50,960 将谓词名以问号结尾 to give them a name that ends in a question mark. 173 00:10:51,080 --> 00:10:52,893 问号本身不代表什么 This question mark doesn't mean anything. 174 00:10:53,106 --> 00:10:54,506 但这是俗成的约定 It's for us as an agreement. 175 00:10:54,613 --> 00:10:58,946 这是人们之间约定的接口 以方便他人阅读你的脚本 It's a conventional interface between humans so you can read my programs more easily. 176 00:11:00,053 --> 00:11:01,960 我希望你在写程序的时候 So I want you to, when you write programs, 177 00:11:01,960 --> 00:11:03,733 当你定义谓词的时候 if you define a predicate procedure, 178 00:11:04,013 --> 00:11:05,773 就是那些返回TRUE或FALSE的过程 that's something that returns true of false, 179 00:11:05,946 --> 00:11:07,840 你应该使它们的名字以问号结尾 it should have a name which ends in question mark. 180 00:11:08,026 --> 00:11:10,346 这对Lisp无异 但对人类友好 The lisp doesn't care. I care. 181 00:11:11,626 --> 00:11:13,146 我需要求和 I want to make a sum. 182 00:11:13,146 --> 00:11:17,493 因为积的导数就是... Because the product, the derivative of a product is the sum 183 00:11:17,940 --> 00:11:19,640 M1*DERIV(M2) of the first times the derivative of the second plus 184 00:11:19,666 --> 00:11:20,706 +DERIV(M1)*M2 the second times the derivative of the first. 185 00:11:23,546 --> 00:11:27,066 两者加起来 Make a sum of two things, 186 00:11:29,640 --> 00:11:38,333 求积... 呃 就用表达式中的M1来表示(被乘数)好了 a product of, well, I'm going to say the M1 of the expression, 187 00:11:39,853 --> 00:11:48,973 表达式中M2关于变量VAR的导数 and the derivative of the M2 of the expression with respect to the variable, 188 00:11:51,906 --> 00:12:06,280 以及 M1关于变量VAR的导数乘以 and the product of the derivative of M1, 189 00:12:07,106 --> 00:12:11,920 M1是这里的被乘数 the multiplier of the expression, with respect to the variable. 190 00:12:13,320 --> 00:12:18,053 乘数是表达式中的M2 And the product of that and the multiplicand, M2, of the expression. 191 00:12:20,640 --> 00:12:24,893 求积完毕、求和完毕、乘式分析完毕 Make that product. Make the sum. Close that case. 192 00:12:24,960 --> 00:12:28,026 当然 在这里我可以添加更多的情况 And, of course, I could add as many cases as I like here 193 00:12:28,320 --> 00:12:30,826 微积分书中的完整法则 for a complete set of rules you might find in a calculus book. 194 00:12:34,800 --> 00:12:39,453 我们就是这么来封装这些法则的 So this is what it takes to encapsulate those rules. 195 00:12:41,533 --> 00:12:43,906 如你所见 我们这里用到了大量的“按愿望思维” And you see, you have to realize there's a lot of wishful thinking here. 196 00:12:44,546 --> 00:12:47,560 我们还没有说这些(表达式)是如何表示的 I haven't told you anything about how I'm going to make these representations. 197 00:12:48,466 --> 00:12:51,920 现在 一旦我将其定为我的一套法则 Now, once I've decided that this is my set of rules, 198 00:12:52,520 --> 00:12:55,200 我想是时候考虑表示法了 I think it's time to play with the representation. 199 00:12:55,666 --> 00:12:56,693 我们来拿捏拿捏 Let's attack that. 200 00:12:57,960 --> 00:13:00,000 首先 我要用到一种“双关”思想 Well, first of all, I'm going to play a pun. 201 00:13:00,906 --> 00:13:02,120 这种“双关”思想非常重要 It's an important pun. 202 00:13:02,746 --> 00:13:06,560 它是一种强有力思想的关键 It's a key to a sort of powerful idea. 203 00:13:09,626 --> 00:13:14,413 如果我想表达诸如和、积、差、商的东西 If I want to represent sums, and products, and differences, and quotients, and things like that, 204 00:13:15,226 --> 00:13:18,626 为什么不用和我程序一样的语言呢? why not use the same language as I'm writing my program in? 205 00:13:20,506 --> 00:13:23,640 我程序中 代数表达式是形如 I write my program it algebraic expressions that look like 206 00:13:23,986 --> 00:13:30,453 (+ (* A (* X X)) the sum of the product on a and the product of x and x, 207 00:13:32,600 --> 00:13:33,800 和与之类似的 and things like that. 208 00:13:34,280 --> 00:13:38,506 (* B X)以及C And the product of b and x and c, whatever, 209 00:13:38,500 --> 00:13:39,973 把它们加起来 make that a sum of the product. 210 00:13:40,773 --> 00:13:44,093 现在 我的过程还不能处理多元参数 Right now I don't want to have procedures with unknown numbers of arguments, 211 00:13:44,933 --> 00:13:48,466 (+ (* B X) C) a product of b and x and c. 212 00:13:51,426 --> 00:13:52,440 这是表结构 This is list structure. 213 00:13:54,120 --> 00:13:55,746 这么做很棒 是因为 And the reason why this is nice, 214 00:13:55,906 --> 00:13:58,333 是因为这些对象都有一种性质 is because any one of these objects has a property. 215 00:13:58,920 --> 00:14:01,533 我知道它们的CAR部分是什么 I know where, know where the car is. 216 00:14:01,960 --> 00:14:03,213 CAR部分就是运算符 The car is the operator. 217 00:14:03,920 --> 00:14:06,386 运算数是相继的CDR部分 And the operands are the successive cdrs 218 00:14:07,226 --> 00:14:10,360 也就是不断取表CDR部分的CAR部分 the successive cars of the cdrs of the list that this is. 219 00:14:12,480 --> 00:14:13,880 这样就使它很方便了 It makes it very convenient. 220 00:14:14,013 --> 00:14:16,400 我需要去解析它 但它已经帮我完成了 Ir have to parse it. It's been done for me. 221 00:14:17,426 --> 00:14:20,013 我利用了Lisp中的内建元素 I'm using the embedding in Lisp to advantage. 222 00:14:22,666 --> 00:14:23,773 举个例子 So, for example, 223 00:14:25,080 --> 00:14:33,973 我们用表结构来表示我所暗示的表示法吧! Let's start using list structure to write down the representation that I'm implicitly assuming here. 224 00:14:35,253 --> 00:14:38,346 我需要定义一些东西 这都暗含在这种表示法中 Well I have to define various things that are implied in this representation. 225 00:14:38,546 --> 00:14:40,906 比如如何判定是否为常量 Like I have to find out how to do a constant, 226 00:14:41,210 --> 00:14:42,306 又怎么判断是同一个变量 how you do same variable. 227 00:14:42,400 --> 00:14:45,040 我们先完成这些吧 都相当简单 Let's do those first. That's pretty easy enough. 228 00:14:45,786 --> 00:14:47,706 这里 我要介绍一些基本过程 Now I'm going to be introducing lots of primitives here, 229 00:14:48,600 --> 00:14:50,506 因为它们都是与表结构相关的 because these are the primitives that come with list structure. 230 00:14:51,986 --> 00:14:53,466 CONSTANT?谓词定义为 OK, you define a constant. 231 00:15:02,253 --> 00:15:04,293 我所谓的常量 And what I mean by a constant, 232 00:15:04,293 --> 00:15:07,733 表达式关于变量VAR是一个常量 an expression is constant with respect to a variable. 233 00:15:09,053 --> 00:15:11,600 是一些简单的表达式 is that the expression is something simple. 234 00:15:11,600 --> 00:15:14,466 我无法再细化它 但它也不是我们关心的变量 I can't take it into pieces, and yet it isn't that variable. 235 00:15:16,586 --> 00:15:18,786 我无法分解它 但它也不是我们关心的变量 I can't break it up, and yet it isn't that variable. 236 00:15:18,900 --> 00:15:25,120 这也并不是说 一些复杂的表达式就不是常量表达式 That does not mean that there may be other expressions that are more complicated that are constants. 237 00:15:25,200 --> 00:15:28,920 我只是想用这种方式考察基本常量 It's just that I'm going to look at the primitive constants in this way. 238 00:15:29,746 --> 00:15:33,413 因此 这个谓词是几个条件的合取 So what this is, is it says that's it's the and. 239 00:15:34,026 --> 00:15:37,826 AND语句允许用户组合返回TRUE或者FALSE的谓词 I can combine predicate expressions which return true or false with and. 240 00:15:38,626 --> 00:15:46,826 表达式是原子的么?--原子表达式不可以再被细分 Something atomic, The expression is atomic, meaning it cannot be broken into parts. 241 00:15:46,820 --> 00:15:48,533 它没有CAR部分和CDR部分 It doesn't have a car and a cdr. 242 00:15:49,453 --> 00:15:50,213 它不是表 It's not a list. 243 00:15:50,760 --> 00:15:52,946 系统中内建有特殊测试 And it's a special test built into the system. 244 00:15:53,973 --> 00:16:04,666 并且表达式EXP和变量VAR在EQ?的语义下不相等 And it's not identically equal to that variable. 245 00:16:06,826 --> 00:16:13,360 我用不能被分解的符号来表示变量 I'm representing my variables by things that are symbols which cannot be broken into pieces, 246 00:16:13,906 --> 00:16:17,226 比如'X 'Y 和像这样的 things like x, and y, things like this. 247 00:16:19,746 --> 00:16:22,373 当然 像这样的组合式就可以再被细分 Whereas, of course, something like this can be broken up into pieces. 248 00:16:24,746 --> 00:16:46,400 (SAME-VAR? EXP VAR)定义为 And the same variable of an expression with respect to a variable is, 249 00:16:46,400 --> 00:16:48,400 实际上 一条原子表达式…… in fact, an atomic expression. 250 00:16:48,773 --> 00:16:59,613 该表达式与讨论变量相同 I want to have an atomic expression, which is identical. 251 00:17:07,900 --> 00:17:11,680 我不想深入讨论这些过程内部 I don't want to look inside this, this stuff anymore. 252 00:17:12,520 --> 00:17:15,560 把这些当作基本过程 These are primitive maybe. 253 00:17:15,773 --> 00:17:17,080 这无关紧要 But it doesn't matter. 254 00:17:17,786 --> 00:17:21,746 我用的是语言内置的功能 I'm defining... I'm using things that are given to me with a language. 255 00:17:22,426 --> 00:17:24,040 我并不关心这些(具体实现) I'm not terribly interest in them. 256 00:17:24,426 --> 00:17:26,040 现在 我们要如何处理和式呢? Now how do we deal with sums? 257 00:17:26,600 --> 00:17:28,800 啊哈 好戏就要上演了 Ah, something very interesting will happen. 258 00:17:28,986 --> 00:17:33,120 和式不是原子的 它以‘+’号打头 A sum is something which is not atomic and begins with the plus symbol. 259 00:17:35,160 --> 00:17:36,173 就是这个意思 That's what it means. 260 00:17:36,653 --> 00:17:39,773 这里 我定义 So here, I will define. 261 00:17:45,466 --> 00:17:57,773 表达式为和式 当它不是原子表达式 An expression is a sum if and it's not atomic 262 00:18:04,573 --> 00:18:15,453 并且它的开头 表达式的CAR部分是个‘+’号 and it's head, it's beginning, its car of the expression is the symbol plus. 263 00:18:19,746 --> 00:18:24,040 我将要引入一个你们从未见过的东西--这个引号 Now you're about to see something you haven't seen before, this quotation. 264 00:18:25,893 --> 00:18:28,226 我这里为什么要用引号呢? Why do I have that quotation there? 265 00:18:29,480 --> 00:18:30,520 教授:说你的名字 PROFESSOR: Say your name, 266 00:18:30,680 --> 00:18:31,410 观众:Susanna AUDIENCE: Susanna. 267 00:18:31,410 --> 00:18:32,013 教授:大点声儿 PROFESSOR: Louder. 268 00:18:32,013 --> 00:18:32,720 观众:Susanna AUDIENCE: Susanna 269 00:18:33,253 --> 00:18:34,213 教授:说“你的名字” PROFESSOR: Say your name. 270 00:18:34,213 --> 00:18:34,853 观众:“你的名字” AUDIENCE: Your name. 271 00:18:34,920 --> 00:18:35,680 教授:大点声儿 PROFESSOR: Louder. 272 00:18:35,773 --> 00:18:36,613 观众:“你的名字” AUDIENCE: Your name. 273 00:18:36,826 --> 00:18:37,506 教授:对了 PROFESSOR: OK. 274 00:18:38,280 --> 00:18:44,560 在这里我想告诉大家 英语词汇是有歧义的 What I'm showing you here is that the words of English are ambiguous. 275 00:18:45,506 --> 00:18:50,760 我可能说 “说你的名字” I was saying, say your name. 276 00:18:51,970 --> 00:18:57,213 我也可能说 “说‘你的名字’” I was also possibly saying say, your name. 277 00:19:00,720 --> 00:19:02,986 光从说话上还无法分辨 But that cannot be distinguished in speech. 278 00:19:03,893 --> 00:19:08,013 然而书面上 我们有专门的记号--引号 However, we do have a notation in writing, 279 00:19:08,186 --> 00:19:12,466 用来区别这两种可能的意思 which is quotation for distinguishing these two possible meanings. 280 00:19:14,000 --> 00:19:15,640 具体来说 这里 In particular, over here, 281 00:19:16,493 --> 00:19:20,840 在Lisp中有用于区别这些语义的记号 in Lisp we have a notation for distinguishing these meanings. 282 00:19:21,346 --> 00:19:24,453 如果我只是写下一个加号 If I were to just write a plus here, a plus symbol, 283 00:19:24,640 --> 00:19:28,520 我会问系统 表达式的首元素 I would be asking, is the first element of the expression, 284 00:19:29,066 --> 00:19:33,613 也就是表达式的运算符 是加运算符(一个过程)么? is the operator position of the expression, the addition operator? 285 00:19:34,653 --> 00:19:35,546 我并不知道 I don't know. 286 00:19:36,226 --> 00:19:38,160 我本应该在那里写一个加运算符的 I would have to have written the addition operator there, 287 00:19:39,373 --> 00:19:40,440 但我无法那样做 which I can't write. 288 00:19:41,340 --> 00:19:45,880 而这种方式则是问 这个符号对象是否为 However, this way I'm asking, is this the symbolic object plus, 289 00:19:45,986 --> 00:19:48,146 代表加运算符的符号 which normally stands for the addition operator? 290 00:19:49,573 --> 00:19:51,920 这才是我想要问和知道的问题 That's what I want. That's the question I want to ask. 291 00:19:52,920 --> 00:19:54,453 在我们深入讨论之前 Now before I go any further, 292 00:19:54,450 --> 00:19:57,813 我想要指出 “引用”是一个复杂的概念 I want to point out the quotation is a very complex concept, 293 00:19:58,853 --> 00:20:01,840 语言中引入这个概念将会造成许多麻烦 and adding it to a language causes a great deal of troubles. 294 00:20:03,573 --> 00:20:05,040 请看下面这张幻灯片 Consider the next slide. 295 00:20:06,386 --> 00:20:09,493 这里这个推论没有问题 Here's a deduction which we should all agree with. 296 00:20:11,626 --> 00:20:17,040 这是说 Alyssa聪明而Alyssa是George的妈妈 We have, Alyssa is smart and Alyssa is George's mother. 297 00:20:17,400 --> 00:20:20,600 通过IS建立了一个等式 This is an equality, is. 298 00:20:22,133 --> 00:20:26,306 我们可以从这两个陈述推论出 George的妈妈很聪明 From those two, we can deduce that George's mother is smart. 299 00:20:27,320 --> 00:20:33,160 这是因为我们总可以在表达式中等价替换 Because we can always substitute equals for equals in expressions. 300 00:20:34,093 --> 00:20:35,160 真是这样吗? Or can we? 301 00:20:36,520 --> 00:20:40,373 这个例子说 “Chicago”有七个字母 Here's a case where we have "Chicago" has seven letters. 302 00:20:41,120 --> 00:20:44,866 引用则是强调我讨论的是单词“Chicago” The quotation means that I'm discussing the word Chicago, 303 00:20:44,866 --> 00:20:46,866 而不是单词所代表的意思 not what the word represents. 304 00:20:49,826 --> 00:20:52,773 这里说 Chicago是Illinois州最大的城市 Here I have that Chicago is the biggest city in Illinois. 305 00:20:54,613 --> 00:20:55,800 而(代换的)结果是…… As a consequence of this, 306 00:20:55,800 --> 00:20:59,093 我可能会得到 Illinois州最大的城市有七个字母 I would like to deduce that the biggest city in Illinois has seven letters. 307 00:20:59,320 --> 00:21:01,066 这显然是错的 But that's manifestly false. 308 00:21:05,160 --> 00:21:07,173 喔!手写笔好使了 Wow, it works. 309 00:21:09,293 --> 00:21:12,240 所以 一旦我们有了(引用)这样的东西 OK, so once we have things like that, 310 00:21:12,480 --> 00:21:14,493 我们的语言就会变得复杂 our language gets much more complicated. 311 00:21:14,493 --> 00:21:18,346 因为我们对于语言的一些操作就不再正确 Because it's no longer true that things we tend to like to do with languages, 312 00:21:18,346 --> 00:21:20,760 比如通过等价代换来得到正确答案 like substituting equals for equals and getting right answers, 313 00:21:21,293 --> 00:21:23,506 如果不小心地操作就会出错 are going to work without being very careful. 314 00:21:24,493 --> 00:21:27,346 在一个引用不透明的上下文中 我们无法进行代换 We can't substitute into what's called referentially opaque contexts, 315 00:21:27,893 --> 00:21:32,640 引用就是引用不透明上下文的典型 of which a quotation is the prototypical type of referentially opaque context. 316 00:21:33,173 --> 00:21:35,280 如果你知道那是什么意思……你可以成为一位哲学家 If you know what that means, you can consult a philosopher. 317 00:21:35,426 --> 00:21:37,026 或许我们之中就有一位 Presumably there is one in the room. 318 00:21:37,533 --> 00:21:41,320 言归正传 我们继续 In any case, let's continue now, 319 00:21:41,320 --> 00:21:44,986 现在我们对一个有2000年历史的问题至少有了操作上的理解 now that we at least have an operational understanding of a 2000-year-old issue 320 00:21:45,266 --> 00:21:48,133 关于名称、提及和等等类似的问题 that has to do with name, and mention, and all sorts of things like that. 321 00:21:52,320 --> 00:22:01,600 我得定义如何把两个数加起来 (DEFINE (MAKE-SUM A1 A2)) I have to define what I mean, how to make a sum of two things, an a1 and a2. 322 00:22:02,120 --> 00:22:03,626 我简单实现一下 And I'm going to do this very simply. 323 00:22:03,626 --> 00:22:11,960 '+、A1、A2构成列表 It's a list of the symbol plus, and a1, and a2. 324 00:22:13,866 --> 00:22:17,373 我可以决定如何取出第一个元素 And I can determine the first element. 325 00:22:21,840 --> 00:22:25,320 (DEFINE A1 CADR) Define a1 to be cadr. 326 00:22:33,880 --> 00:22:35,906 这里又给大家介绍了一个基本过程 I've just introduced another primitive. 327 00:22:36,173 --> 00:22:39,106 这个是取出某物CDR部分的CAR部分 This is the car of the cdr of something. 328 00:22:39,800 --> 00:22:44,533 大家或许会好奇 这些基本过程为什么叫做CAR和CDR You might want to know why car and cdr are names of these primitives, 329 00:22:44,666 --> 00:22:48,426 而且传承了下来 尽管叫做LEFT和RIGHT会好一点 and why they've survived, even though they're much better ideas like left and right. 330 00:22:48,760 --> 00:22:50,440 我们本可以那样叫的 We could have called them things like that. 331 00:22:51,280 --> 00:22:56,253 呃 其实 这个名字来自于很久以前 当发明Lisp时 Well, first of all, the names come from the fact that in the great past, when Lisp was invented, 332 00:22:56,360 --> 00:23:00,800 我想大概是58年的样子 是在类似于704之类的机子上实现的 I suppose in '58 or something, it was on a 704 or something like that, 333 00:23:00,800 --> 00:23:05,413 这个机器有个地址寄存器和减量寄存器 which had a machine. It was a machine that had an address register and a decrement register. 334 00:23:05,413 --> 00:23:08,173 而这些就是地址寄存器和减量寄存器的值 And these were the contents of the address register and the decrement register. 335 00:23:08,173 --> 00:23:09,373 所以这是历史遗留问题 So it's an historical accident. 336 00:23:09,640 --> 00:23:11,280 但是这些名字为什么又延续下来了呢? Now why have these names survived? 337 00:23:11,746 --> 00:23:14,760 这是因为Lisp程序员喜欢用电话交流 It's because Lisp programmers like to talk to each other over the phone. 338 00:23:15,680 --> 00:23:19,600 要是你有一长串的CAR和CDR序列 你就可能说“CDADDEDR” And if you want to have a long sequence of cars and cdrs you might say, cdaddedr, 339 00:23:21,013 --> 00:23:22,320 这是可以理解的 which can be understood. 340 00:23:22,320 --> 00:23:27,026 但是左边的右边的右边的左边就不是那么清楚了 But left of right or right of left is not so clear if you get good at it. 341 00:23:27,600 --> 00:23:30,026 这就是我们为什么有这些黑话 So that's why we have these words. 342 00:23:30,546 --> 00:23:34,146 典型的Lisp系统 默认定义到第四层 All of them up to four deep are defined typically in a Lisp system. 343 00:23:38,666 --> 00:23:47,053 而定义A2为……当然 如果我们考察这些表达式中的一个 A2 to be-- and, of course, you can see that if I looked at one of these expressions 344 00:23:47,360 --> 00:23:52,146 比如(+ 3 5) like the sum of 3 and 5, 345 00:23:52,586 --> 00:24:10,453 这个实际上是一个包含有'+、数3和数5的表 what that is is a list containing the symbol plus, and a number 3, and a number 5. 346 00:24:11,720 --> 00:24:15,186 表的CAR部分是'+ Then the car is the symbol plus. 347 00:24:16,133 --> 00:24:18,213 CDR部分的CAR部分 The car of the cdr. 348 00:24:18,210 --> 00:24:20,210 也就是先取CDR部分 然后再取CAR部分 Well I take the cdr and then I take the car. 349 00:24:20,210 --> 00:24:22,210 这就是我如何取得3的 也就是第一个参数 And that's how I get to the 3. That's the first argument. 350 00:24:22,520 --> 00:24:25,693 CDR的CDR部分的CAR部分 就是这个……数5 And the car of the cdr of the cdr gets me to this one, the 5. 351 00:24:28,693 --> 00:24:33,666 当然类似地 对于乘式我可以这样定义 And similarly, of course, I can define what's going on with products. 352 00:24:35,226 --> 00:24:36,560 我快速地演示一下 Let's do that very quickly. 353 00:24:48,973 --> 00:24:50,640 (DEFINE (PRODUCT? EXP)) Is the expression a product? 354 00:24:51,053 --> 00:24:54,693 如果它不是原子的 而且 Yes if and if it's true, that's it's not atomic 355 00:25:01,413 --> 00:25:14,146 EXP的CAR部分与用于表示乘法的符号'*在 EQ?的语义下相等 and it's EQ quote, the asterisk symbol, which is the operator for multiplication. 356 00:25:15,640 --> 00:25:32,000 (DEFINE (MAKE-PRODUCT M1 M2)) Make product of an M1 and an M2 to be list, 357 00:25:34,426 --> 00:25:39,306 (LIST '* M1 M2) quote, the asterisk operation and M1 and M2. 358 00:25:40,826 --> 00:25:56,810 并定义M1为CADR M2为CADDR And I define M1 to be cadr and M2 to be caddr. 359 00:26:00,093 --> 00:26:02,386 当你说行话的时候 你就上道了 You get to be a good Lisp programmer because you start talking that way. 360 00:26:02,533 --> 00:26:05,533 你可以取表的CDR 也可以把它们组合起来 You can cdr thing down lists and cons them up and so on. 361 00:26:06,293 --> 00:26:10,106 现在 我们有了原理上完整的求导程序了 Now, now that we have essentially a complete program for finding derivatives, 362 00:26:10,106 --> 00:26:11,706 如果需要的话 你也可以添加更多的规则 you can add more rules if you like. 363 00:26:12,213 --> 00:26:13,933 它又要怎么用呢? What kind of behavior do we get out of it? 364 00:26:14,640 --> 00:26:16,773 我先把这个笔迹清了 I'll have to clear that x. 365 00:26:17,800 --> 00:26:20,826 恩 假设我在这里定义FOO为 Well, supposing I define foo here 366 00:26:22,160 --> 00:26:30,386 定义FOO为A*X^2+B*X+C to be the sum of the product of ax square and bx plus c. 367 00:26:30,540 --> 00:26:32,080 跟我们这里看到的是一样的 That's the same thing we see here 368 00:26:32,080 --> 00:26:36,360 这里是用更习见的记号书写的代数表达式 as the algebraic expression written in the more conventional notation over there. 369 00:26:37,840 --> 00:26:41,600 那么 表达式FOO关于X的导数 结果在这里 Well, the derivative of foo with respect to x, which we can see over here, 370 00:26:43,466 --> 00:26:45,266 真是乱得一团糟 is this horrible, horrendous mess. 371 00:26:46,160 --> 00:26:49,226 我期望答案是2*A*X+B I would like it to be 2ax plus b. 372 00:26:50,680 --> 00:26:53,440 虽然与结果等价 但它并不是我们希望的结果 But it's not. It's equivalent to it. 373 00:26:54,586 --> 00:26:55,226 这是什么呢? What is it? 374 00:26:55,973 --> 00:26:59,960 我们最初有什么? I have here, what do I have? 375 00:27:00,506 --> 00:27:04,306 我求X*X的导数 I have the derivative of the product of x and x. 376 00:27:04,693 --> 00:27:10,533 答案是X*1+1*X 这当然没错 Over here is, of course, the sum of x times 1 and 1 times x. 377 00:27:12,733 --> 00:27:15,666 这就是乘数的导数乘以被乘数加上乘数乘以被乘数的导数 Now, well, it's the first times the derivative of the second plus the second times the derivative of the first. It's right. 378 00:27:17,226 --> 00:27:28,373 那就是2X、A*2X就是2AX、0X^2省去 再加上0和这里的一大堆0 That's 2x of course. a times 2x is 2ax plus 0X square doesn't count plus B over here plus a bunch of 0's. 379 00:27:28,960 --> 00:27:30,120 答案是对的 Well the answer is right. 380 00:27:30,120 --> 00:27:35,146 当我们还需要用户额外检验一下 真是糟糕透了 But I give people take off points on an exam for that, sadly enough. 381 00:27:35,560 --> 00:27:37,266 我们下一节再考虑这个内容 Let's worry about that in the next segment. 382 00:27:37,680 --> 00:27:38,613 有疑问吗? Are there any questions? 383 00:27:42,773 --> 00:27:43,453 请说 Yes? 384 00:27:43,893 --> 00:27:46,693 观众:写加号时不加引号 AUDIENCE: If you had left the quote when you put the plus, 385 00:27:46,693 --> 00:27:50,826 是表示引用加那个过程么? then would that be referring to the procedure plus 386 00:27:50,826 --> 00:27:55,426 如果有需要的话 是否能在两个过程之间进行比较 and could you do a comparison between that procedure and some other procedure if you wanted to? 387 00:27:56,160 --> 00:27:57,080 教授:问得好! PROFESSOR: Yes. Good question. 388 00:27:57,453 --> 00:28:02,266 如果我这里不用左引号将这个引住 If I had left this quotation off at this point, 389 00:28:03,880 --> 00:28:07,133 如果我这里不用引号 Okay? If I had left that quotation off at that point, 390 00:28:07,333 --> 00:28:14,200 那么这里我就会引用定义好的加法过程 then I would be referring here to the procedure which is the thing that plus is defined to be. 391 00:28:15,386 --> 00:28:24,880 实际上 我可以比较两个过程是否同一 And indeed, I could compare some procedures with each other for identity. 392 00:28:24,880 --> 00:28:27,453 现在很难从语义上解释 Now what that means is not clear right now. 393 00:28:27,853 --> 00:28:29,373 我现在不想考虑这个问题 I don't like to think about it. 394 00:28:29,893 --> 00:28:32,400 因为我不知道比较过程需要什么 Because I don't know exactly what it would need to compare procedures. 395 00:28:32,400 --> 00:28:34,400 这样做没有意义是有很多原因的 There are reasons why that may make no sense at all. 396 00:28:35,520 --> 00:28:37,533 然而 这些符号我们是可以理解的 However, the symbols, we understand. 397 00:28:38,546 --> 00:28:40,560 这也是我为什么我要将它们引住 And so that's why I put that quote in. 398 00:28:41,160 --> 00:28:43,706 我想讨论出现在这些代码中的符号 I want to talk about the symbol that's apparent on the page. 399 00:28:46,160 --> 00:28:46,920 还有什么问题么? Any other questions? 400 00:28:48,520 --> 00:28:51,866 好吧 休息一下 谢谢大家 OK. Thank you. Let's take a break. 401 00:28:55,120 --> 00:29:00,666 [音乐] [JESU, JOY OF MAN'S DESIRING] 402 00:29:00,680 --> 00:29:04,346 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 403 00:29:04,340 --> 00:29:06,680 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 404 00:29:12,210 --> 00:29:19,173 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 405 00:29:20,093 --> 00:29:24,140 符号化导数系统、引用 Symbolic Differentiation: Quotation 406 00:29:29,866 --> 00:29:30,920 教授:好 我们继续 PROFESSOR: Well, let's see. 407 00:29:31,466 --> 00:29:37,760 我们编写了一个貌似可行的代数表达式求导程序 We've just developed a fairly plausible program for computing the derivatives of algebraic expressions. 408 00:29:38,200 --> 00:29:41,560 这个程序是不完整的 你需要添加一些规则 It's an incomplete program, if you would like to add more rules. 409 00:29:42,130 --> 00:29:47,746 你可能需要加强这个系统 使得它能够处理 And perhaps you might extend it to deal with uses of addition with any number of arguments 410 00:29:47,760 --> 00:29:49,700 多元加法和多元乘法 and multiplication with any of the number of arguments. 411 00:29:49,893 --> 00:29:51,386 这些都相当简单 And that's all rather easy. 412 00:29:52,733 --> 00:29:56,933 但这里面也有一些瑕疵 However, there was a little fly in that ointment. 413 00:29:57,480 --> 00:30:02,373 回到这张幻灯片来 We go back to this slide. 414 00:30:02,946 --> 00:30:08,600 我们发现 得到的表达式相当乱 We see that the expressions that we get are rather bad. 415 00:30:08,880 --> 00:30:11,013 这个表达式非常糟糕 This is a rather bad expression. 416 00:30:11,466 --> 00:30:13,106 我们是怎么得到这样的表达式的? How do we get such an expression? 417 00:30:13,840 --> 00:30:15,506 为什么是这样呢? Why do we have that expression? 418 00:30:16,840 --> 00:30:18,746 我们详细地分析一下这个表达式 Let's look at this expression in some detail. 419 00:30:18,920 --> 00:30:20,760 找出这些片段都是出自哪里 Let's find out where all the pieces come from. 420 00:30:21,693 --> 00:30:24,560 如我们所见 这里的和式 As we see here, we have a sum-- 421 00:30:24,560 --> 00:30:26,560 也就是上一小节中给你们提到的 just what I showed you at the end of the last time-- 422 00:30:27,120 --> 00:30:29,093 (+ (* X 1) (* 1 X)) of X times 1 plus 1 time X. 423 00:30:29,586 --> 00:30:31,386 是这个乘式的导数 That is a derivative of this product. 424 00:30:32,520 --> 00:30:36,413 也就是A乘上这个的积 这里A不是X的函数 The product of a times that, where a does not depend upon x, 425 00:30:36,410 --> 00:30:38,410 因此A关于X是一个常数 and therefore is constant with respect to x, 426 00:30:39,040 --> 00:30:44,533 导数为这个和式 从这里到这里 再到这里 is this sum, which goes from here all the way through here and through here. 427 00:30:44,800 --> 00:30:48,893 因为这个是乘数乘以被乘数的导数 Because it is the first thing times the derivative of the second 428 00:30:49,573 --> 00:30:54,453 加上被乘数乘以乘数的导数 plus the derivative of the first times the second 429 00:30:54,666 --> 00:30:59,066 我们在黑板上的程序告诉我们确实是这样的 as the program we wrote on the blackboard indicated we should do. 430 00:31:00,653 --> 00:31:05,360 当然 这里B乘以X的积 And, of course, the product of bx over here 431 00:31:05,493 --> 00:31:09,813 被化成了 B*1+0*X manifests itself as B times 1 plus 0 times X 432 00:31:10,813 --> 00:31:16,066 因为B不是X的函数 because we see that B does not depend upon X. 433 00:31:16,466 --> 00:31:18,560 因此B的导数为0 And so the derivative of B is this 0, 434 00:31:18,773 --> 00:31:21,480 而X对自己求导则为1 and the derivative of X with respect itself is the 1. 435 00:31:23,066 --> 00:31:28,640 这里的加法化成了 这两个导数的和 And, of course, the derivative of the sums over here turn into these two sums of the derivatives of the parts. 436 00:31:29,373 --> 00:31:33,506 所以这里 我想告诉你和之前一样的东西 So what we're seeing here is exactly the thing I was trying to tell you about 437 00:31:33,666 --> 00:31:35,893 也就是在讲斐波那契数那时候 with Fibonacci numbers a while ago, 438 00:31:37,773 --> 00:31:39,493 所谓的 “过程的形状” that the form of the process 439 00:31:41,386 --> 00:31:46,440 就是通过局部的规则向低层次展开 is expanded as low as from the local rules that you see in the procedure, 440 00:31:48,053 --> 00:31:52,573 也就是过程代表了一系列用于演进过程局部规则 that the procedure represents a set of local rules for the expansion of this process. 441 00:31:53,360 --> 00:32:00,093 这里 过程还遗留了一些东西--也就是答案 And here, the process left behind some stuff, which is the answer. 442 00:32:00,253 --> 00:32:06,266 这是通过遍历表达式的树结构构造出来的 And it was constructed by the walk it takes of the tree structure, which is the expression. 443 00:32:08,413 --> 00:32:12,613 答案中的每个部分对应问题中的某个部分 So every part in the answer we see here derives from some part of the problem. 444 00:32:14,466 --> 00:32:17,786 比如说 现在我们考察FOO的导数 Now, we can look at, for example, the derivative of foo, 445 00:32:17,786 --> 00:32:19,653 也就是AX^2+BX+C which is ax square plus bx plus c, 446 00:32:19,840 --> 00:32:23,053 并另令自变量 比如像这里 with respect to other things, like here, for example, 447 00:32:24,146 --> 00:32:27,480 我们令A为自变量 求FOO的导数 we can see that the derivative of foo with respect to a. 448 00:32:28,106 --> 00:32:31,773 这都非常相似 实际上 它们是同样的代数表达式 And it's very similar. It's, in fact, the identical algebraic expression, 449 00:32:32,453 --> 00:32:35,240 只是它们之中0和1的位置不一样罢了 except for the fact that theses 0's and 1's are in different places. 450 00:32:36,066 --> 00:32:38,600 这是因为在这个树结构的遍历中 Because the only degree of freedom we have in this tree walk 451 00:32:38,973 --> 00:32:43,853 只可能是CONSTANT?和SAME-VAR?会因变量的不同 is what's constant with respect to the variable we're taking the derivative with respect to 452 00:32:44,280 --> 00:32:45,813 而造成不同结果 and what's the same variable. 453 00:32:48,266 --> 00:32:52,093 回到黑板上来再看看 In other words, if we go back to this blackboard and we look, 454 00:32:52,653 --> 00:32:57,493 我们在求和式或乘式的导数时根本没有发挥的余地 we have no choice what to do when we take the derivative of the sum or a product. 455 00:32:58,080 --> 00:33:04,480 真正可以做文章的地方 则是表达式和自变量 The only interesting place here is, is the expression the variable, 456 00:33:04,800 --> 00:33:10,106 以及对于那些短小的表达式 是否为关于自变量的常量 or is the expression a constant with respect to that variable for very, very small expressions? 457 00:33:10,360 --> 00:33:12,413 就是这些地方导致了不同的0和1的产生 In which case we get various 1's and 0's, 458 00:33:12,693 --> 00:33:14,490 回过头来看这张幻灯 which if we go back to this slide, 459 00:33:15,120 --> 00:33:18,160 这里就出现了“0” we can see that the 0's that appear here, for example, 460 00:33:18,373 --> 00:33:22,746 这里是求FOO(A)的导数时得到的“1” this 1 over here in derivative of foo with respect to A, 461 00:33:22,960 --> 00:33:24,866 我们得到了X^2 which gets us an X square, 462 00:33:24,960 --> 00:33:32,533 这个1是X*X关于X的导数 关于B求导时1变成了0 because that 1 gets the multiply of X and X into the answer, that 1 is 0. 463 00:33:32,640 --> 00:33:34,893 这里 我们求FOO关于C的导数 Over here, we're not taking the derivative of foo with respect to c. 464 00:33:36,786 --> 00:33:39,306 但是这些表达式的轮廓是一致的 But the shapes of these expressions are the same. 465 00:33:40,546 --> 00:33:43,960 看看这些轮廓 都是相同的 See all those shapes. They're the same. 466 00:33:50,373 --> 00:33:52,280 那么 难道是我们的规则出了问题? Well is there anything wrong with our rules? 467 00:33:53,586 --> 00:33:55,026 不 这些规则都对 No. They're the right rules. 468 00:33:56,120 --> 00:33:57,773 我们曾经遇到过这种问题 We've been through this one before. 469 00:33:58,066 --> 00:34:03,533 你将会发现 这其中缺乏一些非常好的思想 One of the things you're going to begin to discover is that there aren't too many good ideas. 470 00:34:06,320 --> 00:34:09,746 昨天 我们在考察有理数时 When we were looking at rational numbers yesterday, 471 00:34:12,120 --> 00:34:14,480 想要得到3/4却得到6/8 the problem was that we got 6/8 rather then 3/4. 472 00:34:14,973 --> 00:34:16,493 答案没有化简 The answer was unsimplified. 473 00:34:18,093 --> 00:34:20,906 当然 当下的问题也非常类似 The problem, of course, is very similar. 474 00:34:21,186 --> 00:34:25,413 我想把不相同的表达式通过化简来使相同 There are things I'd like to be identical by simplification that don't become identical. 475 00:34:27,573 --> 00:34:31,893 当然 有理数加法和乘法的规则依然正确 And yet the rules for doing addition a multiplication of rational numbers were correct. 476 00:34:33,973 --> 00:34:37,413 因此这里 我们依葫芦画瓢 So the way we might solve this problem is do the thing we did last time, which always works. 477 00:34:37,786 --> 00:34:39,893 上次能行的办法 这次也没问题 If something worked last time it ought to work again. 478 00:34:40,533 --> 00:34:42,053 也就是改换一下它的表示 It's changed representation. 479 00:34:43,133 --> 00:34:46,440 或许在将其表示出来时我们可以进行 Perhaps in the representation we could put in a simplification step 480 00:34:47,880 --> 00:34:49,786 一步产生简化表示的步骤 that produces a simplified representation. 481 00:34:50,173 --> 00:34:51,733 当然啦 这也不是万用万灵 This may not always work, of course. 482 00:34:52,493 --> 00:34:54,146 我也不想证明它是万能的 I'm not trying to say that it always works. 483 00:34:55,120 --> 00:35:00,440 但这也是控制复杂度的一招妙计 But it's one of the pieces of artillery we have in our war against complexity. 484 00:35:01,466 --> 00:35:03,853 我们小心翼翼地解决这些问题 You see, because we solved our problem very carefully. 485 00:35:04,306 --> 00:35:07,200 我们所做的 就是把问题划分为几个部分 What we've done, is we've divided the world in several parts. 486 00:35:07,573 --> 00:35:08,733 分别是求导规则 There are derivatives rules 487 00:35:11,320 --> 00:35:15,800 和在这种层面上的一般代数规则 and general rules for algebra of some sort at this level of detail. 488 00:35:16,380 --> 00:35:21,226 然后就有一道抽象屏障 and i have an abstraction barrier. 489 00:35:22,480 --> 00:35:33,493 这里是代数表达式的表示--表结构 And i have the representation of the algebraic expressions, list structure. 490 00:35:37,333 --> 00:35:42,560 在这道屏障中 我定义了接口过程 And in this barrier, I have the interface procedures. 491 00:35:43,253 --> 00:35:49,826 比如 CONSTANT? SAME-VAR? I have constant, and things like same-var. 492 00:35:54,600 --> 00:35:58,720 又比如 SUM? MAKE-SUM I have things like sum, make-sum. 493 00:36:02,226 --> 00:36:05,573 还有 A1 A2 I have A1, A2. 494 00:36:06,600 --> 00:36:08,586 还有 PRODUCT? 之类的东西 I have products and things like that, 495 00:36:08,746 --> 00:36:11,906 我所需要的、针对各式代数表达式的东西 all the other things I might need for various kinds of algebraic expressions. 496 00:36:12,946 --> 00:36:19,146 构筑这些屏障我可以随意地改换表示法 Making this barrier allows me to arbitrarily change the representation 497 00:36:20,146 --> 00:36:23,200 而不用改变在某种表示法下编写的规则 without changing the rules that are written in terms of that representation. 498 00:36:25,040 --> 00:36:29,080 如果我能通过改变表示法来解决问题 So if I can make the problem go away by changing representation, 499 00:36:30,386 --> 00:36:34,520 那么把问题分解为两个部分则帮了我大忙 the composition of the problem into these two parts has helped me a great deal. 500 00:36:35,653 --> 00:36:37,546 好吧 举一个非常简单的例子 So let's take a very simple case of this. 501 00:36:38,826 --> 00:36:40,080 我们的问题是什么? What was one of the problems? 502 00:36:40,266 --> 00:36:43,613 回到这张幻灯片来 Let's go back to this transparency again. 503 00:36:44,506 --> 00:36:47,346 看这里 哦 这相当糟糕 And we see here, oh yes, there's horrible things 504 00:36:47,626 --> 00:36:51,866 这里是一个表达式与“0”的和 like here is the sum of an expression and 0. 505 00:36:53,146 --> 00:36:56,666 毋庸置疑这应该是该表达式本身 Well that's no reason to think of it as anything other than the expression itself. 506 00:36:57,213 --> 00:37:01,906 为什么这里还会有加号? Why should the summation operation have made up this edition? 507 00:37:03,386 --> 00:37:04,573 这其实可以更智能点 It can be smarter than that. 508 00:37:05,560 --> 00:37:10,080 又比如说这里 是某表达式与“1”的积 Or here, for example, is a multiplication of something by 1. 509 00:37:11,160 --> 00:37:12,293 这和之前一个道理 It's another thing like that. 510 00:37:12,866 --> 00:37:15,680 又像这里 与“0”相乘显然是“0” Or here is a product of something with 0, which is certainly 0. 511 00:37:17,866 --> 00:37:19,520 因此我们也不用去构造这些式子了 So we won't have to make this construction. 512 00:37:21,440 --> 00:37:22,626 我们为什么不这么做呢? So why don't we just do that? 513 00:37:23,666 --> 00:37:27,960 我们需要去修改表示法 基本上就是那里了 We need to change the way the representation works, almost here. 514 00:37:37,400 --> 00:37:41,840 定义 MAKE-SUM 为 Make-sum to be. 515 00:37:42,053 --> 00:37:43,760 呃 现在就不是那么简单了 Well, now it's not something so simple. 516 00:37:44,000 --> 00:37:50,400 除非是有必要 否则我不会简单地把加号和式子组合成表 I'm not going to make a list containing the symbol plus and things unless I need to. 517 00:37:51,720 --> 00:37:53,053 那么 还有哪些可能呢? Well, what are the possibilities? 518 00:37:54,560 --> 00:37:58,533 如果……这里有一些可能的情况 If...I have some sort of cases here. 519 00:37:59,386 --> 00:38:08,200 如果都是数值的话 如果A1是数值的话 If I have numbers, if a1 is a number-- 520 00:38:09,053 --> 00:38:10,933 这个基本过程我刚刚提到过 and here's another primitive I've just introduced, 521 00:38:10,933 --> 00:38:13,186 也就是用来检测参数是否为数值 it's possible to tell whether something's number-- 522 00:38:15,386 --> 00:38:23,826 并且A2也是数值的话 也就是A2不是符号表达式 and if number A2, meaning they're not symbolic expressions, 523 00:38:24,453 --> 00:38:26,200 那么我们就直接把它们加起来 then why not do the addition now? 524 00:38:26,453 --> 00:38:29,920 结果就是A1加上A2的和 The result is just a plus of A1 and A2. 525 00:38:32,320 --> 00:38:33,986 我并不是检查它们代表数值 I'm not asking if these represent numbers. 526 00:38:33,986 --> 00:38:35,986 这里所有的符号都代表数值 Of course all of these symbols represent numbers. 527 00:38:37,333 --> 00:38:41,226 就比如 我想要考察的是这个东西是否为数值3 I'm talking about whether the one I've got is the number 3 right now. 528 00:38:43,400 --> 00:38:44,400 另一种情况 And, for example, 529 00:38:48,773 --> 00:38:59,613 假设A1是数值 并且为0 supposing A1 is a number, and it's equal to 0, 530 00:39:04,200 --> 00:39:06,386 那么答案就是A2 well then the answer is just A2. 531 00:39:06,933 --> 00:39:08,680 不用再构造什么 There is no reason to make anything up. 532 00:39:10,986 --> 00:39:23,413 如果A2是数值 并且为0 And if A2 is a number, and equal A2 0, 533 00:39:27,160 --> 00:39:28,906 那么答案就是A1 then the result is A1. 534 00:39:30,040 --> 00:39:33,653 如果没有比这些更好的情况 And only if I can't figure out something better to do with this situation, 535 00:39:34,133 --> 00:39:35,613 我就需要构造一个表 well, I can construct a list. 536 00:39:37,866 --> 00:39:42,866 构造一个用于表示答案的表 Otherwise I want the representation to be the list 537 00:39:44,133 --> 00:39:52,333 其中有 '+、A1和A2 containing the quoted symbol plus, and A1, and A2. 538 00:39:58,666 --> 00:40:01,653 当然 积的导数也可以类比此法 And, of course, a very similar thing can be done for products. 539 00:40:03,013 --> 00:40:05,040 这里 我就不细讲了 And I think I'll avoid boring you with them. 540 00:40:05,440 --> 00:40:07,240 我就直接在黑板上写出结果 I was going to write it on the blackboard. 541 00:40:07,653 --> 00:40:09,800 这并不是很重要 你们已经了解它的思想了 I don't think it's necessary. You know what to do. 542 00:40:10,760 --> 00:40:11,613 非常简明 It's very simple. 543 00:40:12,866 --> 00:40:19,893 现在 我们来看看用这种方式改造程序后 效果如何 But now, let's just see the kind of results we get out of changing our program in this way. 544 00:40:21,680 --> 00:40:27,880 哦 这是修改表达式构造函数后的求导结果 Well, here's the derivatives after having just changed the constructors for expressions. 545 00:40:28,986 --> 00:40:32,213 对同样地FOO求导:AX^2+BX+C The same foo, aX square plus bX plus c, 546 00:40:33,280 --> 00:40:40,706 我得到了 2AX+B and what I get is nothing more than the derivative of that is 2aX plus B. 547 00:40:40,706 --> 00:40:42,106 虽然它并没有化到最简 Well, it's not completely simplified. 548 00:40:42,600 --> 00:40:44,533 我应该合并同类项和求和 I would like to collect common terms and sums. 549 00:40:45,066 --> 00:40:46,080 但这又是另外一回事了 Well, that's more work. 550 00:40:47,120 --> 00:40:51,866 当然啦 完成这个功能的代码就大而复杂了 And, of course, programs to do this sort of thing are huge and complicated. 551 00:40:52,280 --> 00:40:55,280 代数化简 是一项繁复的工作 Algebraic simplification, it's a very complicated mess. 552 00:40:56,373 --> 00:41:00,133 你们可能听过MIT以前开发的一个非常出名的程序 MAXIMA There's a very famous program you may have heard of called Maxima developed at MIT in the past, 553 00:41:00,426 --> 00:41:03,146 它有5000页的LISP代码 which is 5,000 pages of Lisp code, 554 00:41:03,920 --> 00:41:06,506 大部分是代数化简的操作 mostly the algebraic simplification operations. 555 00:41:08,080 --> 00:41:12,213 这里是FOO的导数 There we see the derivative of foo. 556 00:41:12,213 --> 00:41:16,866 要是我的话 我会在初等微积分课上讲讲“改换主变量”这个东西 In fact, alias is something I wouldn't take off more than 1 point for on an elementary calculus class. 557 00:41:18,386 --> 00:41:22,493 以A为自变量 FOO的导数则是X*X And the derivative of foo with respect to a, well it's gone down to X times X, 558 00:41:22,800 --> 00:41:23,800 看起来还不差 which isn't so bad. 559 00:41:24,746 --> 00:41:27,533 以B为自变量 FOO的导数则是X本身 And the derivative of foo with respect to b is just X itself. 560 00:41:28,066 --> 00:41:30,120 以C为自变量 FOO的导数则为“1” And the derivative of foo with respect to c comes out 1. 561 00:41:30,706 --> 00:41:32,040 我对这些结果很满意 So I'm pretty pleased with this. 562 00:41:34,106 --> 00:41:39,013 你所看到的 都是精心设计、仔细规划的例子 What you've seen is, of course, a little bit contrived, carefully organized example 563 00:41:39,560 --> 00:41:42,600 用以展示如何操作代数表达式 to show you how we can manipulate algebraic expressions, 564 00:41:42,960 --> 00:41:47,933 我们如何不用具体的语法 而用抽象的语法抽象地进行 how we do that abstractly in terms of abstract syntax rather than concrete syntax 565 00:41:49,213 --> 00:41:56,293 以及我们如何使用抽象屏障控制构造这些表达式 and how we can use the abstraction to control what goes on in building these expressions. 566 00:41:57,800 --> 00:42:00,413 真正的奥义并不是如此的简单 But the real story isn't just such a simple thing as that. 567 00:42:01,000 --> 00:42:04,453 实际上 真正的奥义在于我在操作这些表达式时 The real story is, in fact, that I'm manipulating these expressions. 568 00:42:04,453 --> 00:42:06,720 代数表达式和代码表达式-- And the expressions are the same expressions-- 569 00:42:06,720 --> 00:42:07,973 回过头来看看幻灯片 going back to the slide-- 570 00:42:08,080 --> 00:42:10,520 都是同一种Lisp表达式 as the ones that are Lisp expressions. 571 00:42:12,026 --> 00:42:12,973 这样一语双关 一石二鸟 There's a pun here. 572 00:42:13,826 --> 00:42:21,493 我用表示代码相同的方法来作为我的表示法 I've chosen my representation to be the same as the representation in my language of similar things. 573 00:42:22,893 --> 00:42:26,520 为了要这样做 我得付出点代价 By doing so, I've invoked a necessity. 574 00:42:26,906 --> 00:42:30,346 我需要使用类似于“引用”的东西 I created the necessity to have things like quotation 575 00:42:30,973 --> 00:42:38,173 这是因为 我的语言可以编写讨论语言表达式的表达式 because of the fact that my language is capable of writing expressions that talk about expressions of the language. 576 00:42:39,760 --> 00:42:43,226 我需要有某种东西指出 这个是我需要讨论的表达式 I need to have something that says, this is an expression I'm talking about 577 00:42:43,760 --> 00:42:46,133 而不是说 (去求)这个表达式的值 rather than this expression is talking about something, 578 00:42:47,200 --> 00:42:48,440 我想要的是前者 and I want to talk about that. 579 00:42:51,346 --> 00:42:55,360 引用阻止表达式被求值 其语义为“就是表达式本身” So quotation stops and says, I'm talking about this expression itself. 580 00:42:57,973 --> 00:43:00,853 有了这种能力以后 Now, given that power, 581 00:43:01,586 --> 00:43:03,826 如果我可以操作语言的表达式 if I can manipulate expressions of the language, 582 00:43:04,800 --> 00:43:09,000 我可以在语言层之上构建更加有力的层次 I can begin to build even much more powerful layers upon layers of languages. 583 00:43:09,773 --> 00:43:12,640 因为我可以编写不仅仅是内嵌于Lisp的语言 Because I can write languages that not only are embedded in Lisp 584 00:43:13,466 --> 00:43:14,800 或者是其它的语言 or whatever language you start with, 585 00:43:15,266 --> 00:43:17,760 我可以编写一种完全不同的语言 but languages that are completely different, 586 00:43:18,586 --> 00:43:22,240 而其实质上则是被Lisp或其它语言所解释 that are just, if we say, interpreted in Lisp or something like that. 587 00:43:23,173 --> 00:43:25,466 我们以后还会对此有更深入的理解 We'll get to understand those words more in the future. 588 00:43:26,560 --> 00:43:32,093 我现在只是想让你们意识到 But right now I just want to leave you with the fact that we've hit a line 589 00:43:32,360 --> 00:43:34,986 我们已经感触到了一种惊人的力量 which gives us tremendous power. 590 00:43:36,000 --> 00:43:37,826 现在我们有了方天画戟 And this point we've bought a sledgehammer. 591 00:43:38,173 --> 00:43:40,920 当我们使用它时 也得万分小心 We have to be careful to what flies when we apply it. 592 00:43:42,170 --> 00:43:43,000 谢谢大家 Thank you. 593 00:43:44,106 --> 00:43:49,666 MIT OpenCourseWare http://ocw.mit.edu 594 00:43:50,000 --> 00:44:00,546 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec4a.srt ================================================ 1 00:00:00,000 --> 00:00:22,340 [music] 2 00:00:22,340 --> 00:00:24,340 模式匹配:基于规则的代换 Pattern-matching: Rule-based Substitution 3 00:00:24,340 --> 00:00:29,340 教授:昨天 我们学习了一些符号操作 PROFESSOR: Well, yesterday we learned a bit about symbolic manipulation, 4 00:00:29,920 --> 00:00:35,120 编写了一个非常典型的程序 and we wrote a rather stylized program 5 00:00:35,152 --> 00:00:38,976 来实现教材中的微积分规则 to implement a pile of calculus rule from the calculus book. 6 00:00:39,616 --> 00:00:44,592 在这张幻灯片上 Here on the transparencies, 7 00:00:44,960 --> 00:00:48,816 有一些从书中摘录的微积分规则 we see a bunch of calculus rules from such a book. 8 00:00:49,472 --> 00:00:54,624 我们要把这些规则转化成计算机语言 And, of course, what we did is sort of translate these rules into the language of the computer. 9 00:00:55,140 --> 00:00:58,850 当然 这种策略很有趣 But, of course, that's a sort of funny strategy. 10 00:00:59,360 --> 00:01:04,800 但是我们为什么要把它们翻译成计算机语言呢? Why should we have to translate these rules into the language of the computer? 11 00:01:05,008 --> 00:01:06,272 我的意思是--- And what do I really mean by that? 12 00:01:06,620 --> 00:01:11,020 我们昨天写的程序非常典型 These are--the program we wrote yesterday was very stylized. 13 00:01:11,216 --> 00:01:15,984 它是一个按表达式类型做分派的分情况分析语句 It was a conditional, a dispatch on the type of the expression 14 00:01:16,384 --> 00:01:18,480 规则就是这样的 as observed by the rules. 15 00:01:19,680 --> 00:01:21,552 这里的规则是说: What we see here are rules that say 16 00:01:21,744 --> 00:01:25,488 我们考察的表达式如果是--- if the object being the derivative is being taken of, 17 00:01:25,488 --> 00:01:29,424 如果是常量 就做一些事情 if that expression is a constant, then do one thing. 18 00:01:29,420 --> 00:01:31,376 如果是变量 就做另一件事情 If it's a variable, do another thing. 19 00:01:31,600 --> 00:01:35,568 如果它是常量乘以变量 就做另外的事 等等 If it's a product of a constant times a variable, do something and so on. 20 00:01:36,000 --> 00:01:38,960 这是一种按类型的分派 There's sort of a dispatch there on a type. 21 00:01:41,400 --> 00:01:45,160 那么 既然它有如此典型的行为和结构 Well, since it has such a stylized behavior and structure, 22 00:01:45,952 --> 00:01:49,530 有没有其它方式把这个过程写得更加清晰? is there some other way of writing this program that's more clear? 23 00:01:50,832 --> 00:01:53,456 首先要解决的是 这些规则是什么? Well, what's a rule, first of all, What are these rules? 24 00:01:55,560 --> 00:01:58,500 我们来好好想一下 规则有好几个部分 Let's think about that. Rules have parts. 25 00:01:58,944 --> 00:02:02,352 如果仔细观察这些规则 If you look at these rules in detail, 26 00:02:03,712 --> 00:02:04,992 你就会发现 what you see, for example, 27 00:02:05,120 --> 00:02:09,696 这些规则都有左右两部分 is the rule has a left-hand side and a right-hand side. 28 00:02:10,360 --> 00:02:14,360 每一个规则都有左边部分和右边部分 Each of these rules has a left-hand side and the right-hand side. 29 00:02:15,152 --> 00:02:20,304 左边部分用来与对被求导表达式做比较 The left-hand side is somehow compared with the expression you're trying to take the derivative of. 30 00:02:21,520 --> 00:02:25,104 右边部分用于替换原表达式 The right-hand side is the replacement for that expression. 31 00:02:28,496 --> 00:02:33,104 这张纸上的所有规则都可以描述成这样—— So all rules on this page are something like this. 32 00:02:36,512 --> 00:02:38,064 我们有许多模式 I have patterns, 33 00:02:41,488 --> 00:02:48,300 有时候 给定一个模式 我们需要为其生成一个骨架 and somehow, I have to produce, given a pattern, a skeleton. 34 00:02:51,888 --> 00:02:52,816 这就是一个规则 This is a rule. 35 00:02:55,424 --> 00:02:57,136 模式是用于匹配的部分 A pattern is something that matches, 36 00:02:57,888 --> 00:03:03,264 将成功匹配的值代换到骨架里 就得到一个新的表达式 and a skeleton is something you substitute into in order to get a new expression. 37 00:03:06,464 --> 00:03:16,320 我的意思是:模式是用来匹配原表达式的 So what that means is that the pattern is matched against the expression, which is the source expression. 38 00:03:23,728 --> 00:03:28,512 应用规则会产生一个新的表达式 And the result of the application of the rule is to produce a new expression, 39 00:03:33,616 --> 00:03:34,912 我们称之为目标 which I'll call a target, 40 00:03:38,128 --> 00:03:39,888 这是通过骨架的实例化实现的 by instantiation of a skeleton. 41 00:03:41,632 --> 00:03:43,020 这个叫做实例化 That's called instantiation. 42 00:03:50,720 --> 00:03:54,736 这就是这些规则所描述的过程 So that is the process by which these rules are described. 43 00:03:55,696 --> 00:03:57,264 今天我想要做的是 What I'd like to do today 44 00:03:58,736 --> 00:04:01,088 构建一种语言 is build a language 45 00:04:02,200 --> 00:04:05,488 以及它的解释与执行方法 and a means of interpreting that language, a means of executing that language, 46 00:04:05,744 --> 00:04:08,432 使得这种语言可以直接表述这些规则 where that language allows us to directly express these rules. 47 00:04:10,592 --> 00:04:11,584 我们将要做的是 And what we're going to do 48 00:04:11,580 --> 00:04:17,568 与其通过将规则翻译为程序 让计算机理解并执行 instead of bringing the rules to the level of the computer by writing a program that is those rules 49 00:04:18,384 --> 00:04:21,560 这里主要指 Lisp 程序 in the computer's language--at the moment, in a Lisp-- 50 00:04:22,160 --> 00:04:24,496 我们不如让计算机理解我们 we're going to bring the computer to the level of us 51 00:04:25,488 --> 00:04:29,150 我们可以写一些程序让计算机理解这些规则 by writing a way by which the computer can understand rules of this sort. 52 00:04:30,912 --> 00:04:34,768 这又稍微强调了上次的主旨 This is slightly emphasizing the idea that we had last time 53 00:04:35,440 --> 00:04:39,360 与其解决一个特定问题 不如解决一类问题 that we're trying to make a solution to a class of problems rather than a particular one. 54 00:04:39,776 --> 00:04:46,720 如果我为不同的数学运算写规则 The problem is if I want to write rules for a different piece of mathematics, 55 00:04:48,240 --> 00:04:51,392 比如简单代数的化简 say, to simple algebraic simplification or something like that, 56 00:04:51,984 --> 00:04:55,488 或者三角函数运算 or manipulation of trigonometric functions, 57 00:04:56,096 --> 00:05:01,160 如果按照昨天的方法 我就得重新写个不同的程序 I would have to write a different program in using yesterday's method. 58 00:05:01,160 --> 00:05:05,424 与之相反 我把程序中的共有逻辑给封装起来 Whereas I would like to encapsulate all of the things that are common to both of those programs, 59 00:05:06,128 --> 00:05:10,176 也就是匹配、实例化等概念 还有控制结构 meaning the idea of matching, instantiation, the control structure, 60 00:05:10,176 --> 00:05:12,464 这都是非常复杂的事情 which turns out to be very complicated for such a thing, 61 00:05:13,160 --> 00:05:18,460 我想把它们从规则中分开 并封装 I'd like to encapsulate that separately from the rules themselves. 62 00:05:20,064 --> 00:05:22,608 首先让我们看一下表示法 So let's look at, first of all, a representation. 63 00:05:22,624 --> 00:05:24,096 请大家看投影仪上的幻灯片 I'd like to use the overhead here. 64 00:05:24,672 --> 00:05:25,600 已经在这里了 I'd like-- there it is. 65 00:05:26,250 --> 00:05:32,272 我想要把求导的计算规则 I'd like to look at a representation of the rules of calculus for derivatives 66 00:05:33,712 --> 00:05:37,150 表示为我这里写的一种简单语言 in a sort of simple language that I'm writing right here. 67 00:05:38,112 --> 00:05:43,296 我会尽量避免去考虑语法 Now, I'm going to avoid--I'm going to avoid worrying about syntax. 68 00:05:44,280 --> 00:05:49,280 美化它很容易 虽然这个确实挺丑 但我并不关心 We can easily pretty this, and I'm not interested in making-- this is indeed ugly. 69 00:05:49,300 --> 00:05:56,416 这确实不能像dx/dt那样表示 This doesn't look like the beautiful text set dx by dt or something that I'd like to write, 70 00:05:56,768 --> 00:05:58,120 但这并不重要 but that's not essential. 71 00:05:58,880 --> 00:06:00,624 这是一个偶然现象 That's sort of an accidental phenomenon. 72 00:06:01,000 --> 00:06:04,448 这里 我只关心规则的结构 Here, we're just worrying about the fact that the structure of the rules 73 00:06:04,832 --> 00:06:11,700 规则的左边部分代表了我想要匹配的求导表达式 is that there is a left-hand side here, represents the thing I want to match against the derivative expression. 74 00:06:11,808 --> 00:06:13,568 这个表示是说 This is the representation I'm going to say 75 00:06:13,600 --> 00:06:18,320 一个匹配常量的模式变量c for the derivative of a constant, which we will call c 76 00:06:18,848 --> 00:06:21,200 关于匹配任意表达式的模式变量v求导 respect to the variable we will call v. 77 00:06:23,088 --> 00:06:25,552 我们在右边部分得到的是0 And what we will get on the right-hand side is 0. 78 00:06:26,000 --> 00:06:28,064 这就代表了一个规则 So this represents a rule. 79 00:06:29,260 --> 00:06:34,048 下一条规则是 匹配变量的模式变量v The next rule will be the derivative of a variable, which we will call v 80 00:06:34,224 --> 00:06:37,740 对同一个模式变量求导 得到的结果是1 respect to the same variable v, and we get a 1. 81 00:06:38,600 --> 00:06:42,176 然而 如果一个匹配变量的模式变量u However, if we have the derivative of a variable called u 82 00:06:42,410 --> 00:06:44,848 关于另一个模式变量v求导 respect to a different variables v, 83 00:06:45,392 --> 00:06:47,050 那么 结果就是0 we will get 0. 84 00:06:47,840 --> 00:06:52,176 我想让大家看一下 这些规则是如何组织在一起的 I just want you look at these rules a little bit and see how they fit together. 85 00:06:52,512 --> 00:06:54,304 比如说 在这里 For example, over here, 86 00:06:54,736 --> 00:07:01,900 我们要求表达式x1、x2之和的导数 we're going to have the derivative of the sum of an expression called x1 and an expression called x2. 87 00:07:01,900 --> 00:07:05,856 在我们创造的这个语言中 These things that begin with question marks are called pattern variables 88 00:07:06,880 --> 00:07:08,624 以问号开头的叫模式变量 in the language that we're inventing, 89 00:07:08,930 --> 00:07:14,930 我们就像这样来构建这些用来匹配的模式变量 and you see we're just making it up, so pattern variables for matching. 90 00:07:14,930 --> 00:07:20,330 这里 表达式x1加上表达式x2 And so in this-- here we have the derivative of the sum of the expression which we will call x1. 91 00:07:20,330 --> 00:07:26,700 对变量v求导的结果等于右边这里的式子 And the expression we will call x2 with respect to the variable we call v will be-- here is the right-hand side: 92 00:07:26,700 --> 00:07:32,768 右边的式子是一个骨架 表示表达式X1关于变量v求导 the sum of the derivative of that expression x1 with respect to v-- the right-hand side is the skeleton-- 93 00:07:33,824 --> 00:07:37,104 加上表达式X2对变量v求导的和 and the derivative of x2 with respect to v. 94 00:07:37,600 --> 00:07:42,384 这里的冒号表示要代换的对象 Colons here will stand for substitution objects. 95 00:07:43,632 --> 00:07:47,232 我们将它们称作“骨架求值” They're--we'll call them skeleton evaluations. 96 00:07:48,512 --> 00:07:53,072 让我在黑板上写一些语法 So let me put up here on the blackboard for a second some syntax 97 00:07:53,232 --> 00:07:55,568 这样就能知道 在我们这门规则语言中会发生什么 so we'll know what's going on for this rule language. 98 00:07:56,688 --> 00:07:59,888 首先我们要处理模式匹配问题 First of all, we're going to have to worry about the pattern matching. 99 00:08:06,048 --> 00:08:13,120 第一条规则是 形如foo这样的符号与其自身匹配 We're going to have things like a symbol like foo matches exactly itself. 100 00:08:23,520 --> 00:08:31,344 形如(f a b)的表达式 可以匹配这样的表 The expression f of a and b will be used to match any list 101 00:08:36,304 --> 00:08:57,024 表的首元素是f、第二个元素是a、第三个元素是b whose first element is f, whose second element is a, and whose third element is b. 102 00:08:58,624 --> 00:09:06,992 另外 模式中可能还有形如(? x)这样的规则 Also, another thing we might have in a pattern is that--a question mark with some variable like x. 103 00:09:08,576 --> 00:09:18,672 这个规则可以匹配任意表达式 并将其称为x And what that means, it says matches anything, which we will call x. 104 00:09:25,456 --> 00:09:29,984 (?c x) 只匹配常量 Question mark c x will match only constants. 105 00:09:31,500 --> 00:09:40,960 并将匹配的常量记作x So this is something which matches a constant called x. 106 00:09:44,560 --> 00:09:57,072 (?v x)匹配变量 并将匹配的变量记作x And question mark v x will match a variable, which we call x. 107 00:10:01,664 --> 00:10:03,808 这就是我们正在构建的语言 This is sort of the language we're making up now. 108 00:10:04,192 --> 00:10:09,408 两个对象的比较是基于元素与元素间的比较 If I match two things against each other, then they are compared element by element 109 00:10:10,256 --> 00:10:15,856 模式中的元素可以包含这些语法变量、模式变量 But elements in the pattern may contain these syntactic variables, 110 00:10:17,072 --> 00:10:20,432 它们可以用来匹配任意对象 which will be used to match arbitrary objects. 111 00:10:22,128 --> 00:10:29,280 这样 我就可以用x作为名字取得被匹配对象的值 And we'll get that object as the value in the name x here, for example. 112 00:10:31,056 --> 00:10:37,552 现在 当我们为实例化准备骨架的时候 Now, when we make skeletons for instantiation. 113 00:10:39,504 --> 00:10:41,408 我们可能有这样的东西 Well, then we have things like this. 114 00:10:42,272 --> 00:10:46,336 符号foo实例化为它本身 foo, a symbol, instantiates to itself. 115 00:10:55,080 --> 00:11:05,920 形如(f a b)这样的表 实例化为 Something which is a list like f of a and b, instantiates to-- 116 00:11:06,368 --> 00:11:14,752 实例化为一个三元素表 well, f instantiates to a 3-list, a list of three elements, 117 00:11:15,552 --> 00:11:33,376 其元素分别为f、a、b各自实例化后的结果 okay, which are the results of instantiating each of f, a, and b. 118 00:11:36,352 --> 00:11:54,272 (: x) 会被实例化为x的值--也就是被匹配的模式 And x well--we instantiate to the value of x as in the matched pattern. 119 00:12:03,056 --> 00:12:10,080 回头看看这里的幻灯片 我们发现这些都是对象 So going back to the overhead here, we see -- we see that all of those kinds of objects 120 00:12:10,784 --> 00:12:16,060 我们看到 这是一个用来匹配常量的模式变量 we see here a pattern variable which matches a constant, 121 00:12:16,560 --> 00:12:19,024 这是匹配变量的模式变量 a pattern variable which matches a variable, 122 00:12:19,392 --> 00:12:21,744 这是匹配任意表达式的模式变量 a pattern variable which will match anything. 123 00:12:22,720 --> 00:12:24,920 如果我们有了名字一样的两个实例 And if we have two instances of the same name, 124 00:12:25,080 --> 00:12:31,776 想这个是被称作v的单变量表达式 like this is the derivative of the expression which is a variable only whose name will be v 125 00:12:32,864 --> 00:12:36,300 关于一个称作v的任意表达式求导 with respect to some arbitrary expression which we will call v, 126 00:12:36,410 --> 00:12:38,016 因为这个v出现了两次 since this v appears twice, 127 00:12:38,656 --> 00:12:41,072 我们想约束它们相同 we're going to want that to mean they have to be the same. 128 00:12:42,688 --> 00:12:45,008 只有它俩完全一致才算是匹配 The only consistent match is that those are the same. 129 00:12:45,230 --> 00:12:47,230 所以在这里我们在构建一个语言 So here, we're making up a language. 130 00:12:47,600 --> 00:12:50,660 事实上 这是一件非常好的事情 And in fact, that's a very nice thing to be doing. 131 00:12:50,660 --> 00:12:52,600 构建一个语言非常有趣 It's so much fun to make up a language. 132 00:12:52,600 --> 00:12:54,330 并且大家一直在做这些 And you do this all the time. 133 00:12:54,330 --> 00:12:56,896 大家做过的真正强大的设计 And the really most powerful design things you ever do 134 00:12:57,232 --> 00:13:00,208 是构建一个语言来解决这样的问题 are sort of making up a language to solve problems like this. 135 00:13:02,064 --> 00:13:05,344 我们回头看看这些规则 Now, here we go back here and look at some of these rules. 136 00:13:05,808 --> 00:13:07,100 这就是它们的全部 Well, there's a whole set of them. 137 00:13:07,100 --> 00:13:12,430 我们有加法、乘法 就像我们之前看到的一样 I mean, there's one for addition and one for multiplication, just like we had before. 138 00:13:12,430 --> 00:13:17,376 x1+x2 关于变量v的导数等于 The derivative of the product of x1 and x2 with respect to v is 139 00:13:17,680 --> 00:13:26,528 x2对v求导乘以x1 加上 x1对v求导乘以x2 the sum of the product of x1 and the derivative x2 with respect to v and the product of the derivative of x1 and x2. 140 00:13:27,264 --> 00:13:29,100 这是指数运算的求导规则 And here we have exponentiation. 141 00:13:29,248 --> 00:13:32,110 虽然这里展示完了所有的规则 但还可以按照我们意愿添加 And, of course, we run off the end down here. We get as many as we like. 142 00:13:32,704 --> 00:13:39,104 我们在这里 建立了关于求导的规则列表 But the whole thing over here, I'm giving this--this list of rules the name "derivative rules." 143 00:13:40,400 --> 00:13:44,330 一旦我们有了这些 我们应该做什么呢? What would we do with such a thing once we have it? 144 00:13:45,408 --> 00:13:47,840 恩 我将给你们展示最好的思想之一 Well, one of the nicest ideas, first of all, 145 00:13:48,448 --> 00:13:51,680 然后我们将花一整天来鼓捣它 is I'm going to write for you, and we're going to play with it all day. 146 00:13:52,288 --> 00:13:57,376 我将向大家展示一个叫做simplifier的程序 What I'm going to write for you is a program called simplifier, 147 00:13:57,824 --> 00:13:59,472 一个通用的化简器 the general-purpose simplifier. 148 00:14:00,090 --> 00:14:17,104 我们将求导规则deriv-rules送入simplifier从而产生dsimp And we're going to say something like define dsimp to be a simplifier of the derivative rules. 149 00:14:23,744 --> 00:14:28,752 传给simplifier过程一套规则 它会返回给我们一个过程 And what simplifier is going to do is, given a set of rules, it will produce for me a procedure 150 00:14:29,328 --> 00:14:34,592 它根据这些规则对表达式进行化简 which will simplify expressions containing the things that are referred to by these rules. 151 00:14:37,392 --> 00:14:43,936 因此 这里会返回一个按照你制定的规则所构造的过程 So here will be a procedure constructed for your purposes to simplify things with derivatives in them 152 00:14:44,590 --> 00:14:49,568 使得在我们进入 Lisp 系统后 在命令提示符后面 such that, after that, if we're typing at some Lisp system, and we get a prompt, 153 00:14:49,888 --> 00:15:03,936 输入 (DSIMP '(dd (+ x y) x)) and we say dsimp, for example, of the derivative of the sum of x and y with respect to x-- 154 00:15:06,992 --> 00:15:10,976 注意这里的引号 因为我们讨论的是表达式的求导 note the quote here because I'm talking about the expression which is the derivative-- 155 00:15:13,296 --> 00:15:17,760 然后我将得到结果 (+ 1 0) then I will get back as a result plus 1 0. 156 00:15:19,968 --> 00:15:24,600 因为 (x+y)' = x' + y' Because the derivative of x plus y is the derivative of x plus derivative y. 157 00:15:24,600 --> 00:15:26,224 x'=1 The derivative of x with respect to x is 1. 158 00:15:26,384 --> 00:15:27,824 y'=0(关于x求导) The derivative of y with respect to x is 0. 159 00:15:29,424 --> 00:15:30,464 这不是我想要的 It's not what we're going to get. 160 00:15:31,184 --> 00:15:34,656 我还没有在这里做代数化简 I haven't put any simplification at that level-- algebraic simplification--yet. 161 00:15:36,160 --> 00:15:41,536 当然一旦我有了这个东西那么我们可以 -- 我们可以看看其它的规则 Of course, once we have such a thing, then we can--then we can look at other rules. 162 00:15:41,960 --> 00:15:49,360 比如 我们看这张幻灯片 So, for example, we can, if we go to the slide, OK? 163 00:15:49,360 --> 00:15:54,128 这里是其它的规则 代数操作规则 Here, for example, are other rules that we might have, algebraic manipulation rules, 164 00:15:56,000 --> 00:15:58,384 它们可以用来化简代数表达式 ones that would be used for simplifying algebraic expressions. 165 00:15:59,008 --> 00:16:02,064 考察一下这些规则 For example, just looking at some of these, 166 00:16:03,040 --> 00:16:09,200 这条规则的左部分是说 某个运算符应用到常量e1和常量e2上 the left-hand side says any operator applied to a constant e1 and a constant e2 167 00:16:09,328 --> 00:16:14,512 其结果就是求(op e1 e2)的值 is the result of evaluating that operator on the constants e1 and e2. 168 00:16:15,888 --> 00:16:21,568 或者 当一个运算符应用在任意表达式e1和常量e2上 Or an operator, applied to e1, any expression e1 and a constant e2, 169 00:16:21,696 --> 00:16:23,872 化简结果会把常量前置 is going to move the constant forward. 170 00:16:24,528 --> 00:16:27,680 这就变成了((: op) (: e2) (: e1)) So that'll turn into the operator with e2 followed by e1. 171 00:16:28,592 --> 00:16:30,112 为什么要这么做?我不知道 Why I did that, I don't know. 172 00:16:30,224 --> 00:16:33,168 比如说 如果系统中有除法的话 这就不对 It wouldn't work if I had division, for example. 173 00:16:33,530 --> 00:16:35,312 换句话说 规则有漏洞 So there's a bug in the rules, if you like. 174 00:16:36,672 --> 00:16:40,864 所以0与任何表达式e的和 等于表达式e So the sum of 0 and e is e. 175 00:16:42,176 --> 00:16:45,312 1乘以任何表达式e的结果是表达式e The product of 1 and any expression e is e. 176 00:16:46,128 --> 00:16:49,136 0乘以任何表达式e的结果是0 The product of 0 and any expression e is 0. 177 00:16:49,330 --> 00:16:52,720 我们可以有任意复杂的规则 Just looking at some more of these rules, we could have arbitrarily complicated ones. 178 00:16:53,696 --> 00:16:54,816 比如说 We could have things like 179 00:16:55,360 --> 00:17:01,696 常量e1*(常量e2*任意表达式e3) the product of the constant e1 and any constant e2 with e3 180 00:17:02,350 --> 00:17:11,968 可以化简为 (e1*e2)*e3 is the result of multiplying the result of multiplying now the constants e1 and e2 together and putting e3 there. 181 00:17:13,360 --> 00:17:16,768 这个规则是说 先把常量组合起来 So it says combine the constants that I had, 182 00:17:16,768 --> 00:17:22,704 如果有形如 e1*(e2*e3) 的式子 而且e1 e2都是常量 就先把常量乘起来 which was if I had a product of e1 and e2 and e3 just multiply--I mean and e1 and e2 are both constants, multiply them. 183 00:17:23,840 --> 00:17:25,488 你可以根据意愿来构建这些规则 And you can make up the rules as you like. 184 00:17:25,792 --> 00:17:26,944 这里还有很多规则 There are lots of them here. 185 00:17:27,424 --> 00:17:31,040 这些规则是很复杂的 比如-- There are things as complicated, for example, as-- 186 00:17:31,260 --> 00:17:33,930 请看 这条规则是分配律 oh, I suppose down here some distributive law, you see. 187 00:17:33,930 --> 00:17:38,576 任何表达式c乘以d和e The product of any object c and the sum of d and e 188 00:17:39,024 --> 00:17:43,664 等于 c与d的积加上c与e的积 gives the result as the same as the sum of the product of c and d and the product of c and e. 189 00:17:45,312 --> 00:17:48,672 我并不关心这些规则具体描述的什么 Now, what exactly these rules are doesn't very much interest me. 190 00:17:49,168 --> 00:17:52,976 我们将要构建一种语言 用来解释这些规则 We're going to be writing the language that will allow us to interpret these rules 191 00:17:55,504 --> 00:17:57,488 这样我们就可以按我们的意愿编写规则 so that we can, in fact, make up whatever rules we like, 192 00:17:58,352 --> 00:18:00,144 这是另外一种程序设计语言 another whole language of programming. 193 00:18:03,392 --> 00:18:04,048 来看看 Well, let's see. 194 00:18:05,184 --> 00:18:06,960 我还没告诉你我们要怎么做 I haven't told you how we're going to do this. 195 00:18:07,536 --> 00:18:10,064 当然我们马上就要讲了 And, of course, for a while, we're going to work on that. 196 00:18:10,896 --> 00:18:15,408 但真正的问题是:宏观地看 我要做什么? But there's a real question of what is--what am I going to do at all at a large scale? 197 00:18:17,088 --> 00:18:18,224 这些规则是如何运作的? How do these rules work? 198 00:18:19,008 --> 00:18:25,456 化简程序是如何用这些规则来输入的表达式 并返回一个合理的答案? How is the simplifier program going to manipulate these rules with your expression to produce a reasonable answer? 199 00:18:26,224 --> 00:18:29,856 首先 我认为我们有一大堆的规则 Well, first, I'd like to think about these rules as being some sort of deck of them. 200 00:18:32,528 --> 00:18:34,224 这里有全部的规则 So here I have a whole bunch of rules, 201 00:18:42,096 --> 00:18:44,496 这里的每一个规则 --- Each rule-- here's a rule-- 202 00:18:46,976 --> 00:18:49,248 都有一个模式和一个骨架 has a pattern and a skeleton. 203 00:18:49,728 --> 00:18:51,360 我正在努力为它作一个控制结构 I'm trying to make up a control structure for this. 204 00:18:53,376 --> 00:18:56,560 我有一个匹配器 Now, what I have is a matcher, 205 00:19:00,992 --> 00:19:03,760 还有一个实例化器 and I have something which is an instantiater. 206 00:19:09,660 --> 00:19:12,944 我将把一系列模式变量的值 And I'm going to pass from the matcher to the instantiater 207 00:19:14,032 --> 00:19:17,470 从匹配器中传递到实例化器中 some set of meaning for the pattern variables, 208 00:19:18,064 --> 00:19:19,420 我把传递的东西叫做词典 a dictionary, I'll call it. 209 00:19:20,592 --> 00:19:21,520 传递一本词典 A dictionary, 210 00:19:24,928 --> 00:19:27,824 里面记载了:x匹配下列子表达式 which will say x was matched against the following subexpression 211 00:19:29,040 --> 00:19:31,312 而y匹配另一个子表达式 and y was matched against another following subexpression. 212 00:19:32,256 --> 00:19:36,352 我会从实例化器中构造表达式 并送入匹配器 And from the instantiater, I will be making expressions,and they will go into the matcher. 213 00:19:37,168 --> 00:19:38,368 这些是表达式 They will be expressions. 214 00:19:45,008 --> 00:19:48,416 这些规则的模式将要送进匹配器中 And the patterns of the rules will be fed into the matcher, 215 00:19:49,248 --> 00:19:54,400 规则对应的骨架将要送进实例化器中 and the skeletons from the same rule will be fed into the instantiater. 216 00:19:55,216 --> 00:19:56,624 现在变得有点复杂了 Now, this is a little complicated 217 00:19:57,120 --> 00:19:59,536 因为当我们处理代数表达式时 because when you have something like an algebraic expression, 218 00:20:00,448 --> 00:20:03,600 有一些规则使你能够做等价代换 where some of the rules are intended to be able to allow you to substitute equal for equal. 219 00:20:04,240 --> 00:20:05,872 这些是等价代换规则 These are equal transformation rules. 220 00:20:06,880 --> 00:20:09,296 所以需要考察表达式的所有子表达式 So all subexpressions of the expression should be looked at. 221 00:20:11,136 --> 00:20:15,824 给定一个表达式 这些规则应该被不断应用 You give it an expression, this thing, and the rules should be cycled around. 222 00:20:16,032 --> 00:20:19,712 首先 对于传入的表达式的每个子表达式 First of all, for every subexpression of the expression you feed in, 223 00:20:20,224 --> 00:20:22,832 所有的规则都需要考察一次 all of the rules must be tried and looked at. 224 00:20:24,336 --> 00:20:27,072 如果有规则匹配成功 那么就会执行这个过程 And if any rule matches, then this process occurs. 225 00:20:27,300 --> 00:20:30,630 传递一本存储值的词典 The dictionary--the dictionary is to have some values in it. 226 00:20:30,630 --> 00:20:33,392 实例化器产生一个新的表达式 The instantiater makes a new expression, 227 00:20:33,904 --> 00:20:39,104 该表达式基本上只是替换了原表达式中匹配的部分 which is basically replaces that part of the expression that was matched in your original expression. 228 00:20:40,848 --> 00:20:44,464 然后 我们要对它重新检查 And then, then, of course, we're going to recheck that, 229 00:20:44,752 --> 00:20:48,112 重新考察这些规则 看看表达式是否可以更进一步化简 going to go around these rules again, seeing if that could be simplified further. 230 00:20:49,536 --> 00:20:53,712 然后每一个子表达式这样做 直到没有任何变化为止 And then, then we're going to do that for every subexpression until the thing no longer changes. 231 00:20:54,960 --> 00:20:57,504 你可以把它想像成一个有机过程 You can think of this as sort of an organic process. 232 00:20:57,830 --> 00:21:00,208 我们有一锅炖汤 You've got some sort of stew, right? 233 00:21:00,240 --> 00:21:04,320 粘乎乎的汤里面有细菌 有酶 You've got bacteria or something, or enzymes in some, in some gooey mess. 234 00:21:05,632 --> 00:21:10,500 这些酶改变了汤 And there's these--and these enzymes change things. 235 00:21:10,500 --> 00:21:14,384 它们附着在你的表达式上 改变了它 然后就走了 They attach to your expression, change it, and then they go away. 236 00:21:15,280 --> 00:21:17,830 就像钥匙和锁一样 它们需要配对 And they have to match. The key-in-lock phenomenon. 237 00:21:18,000 --> 00:21:19,730 匹配 -- 改变 -- 然后离开 They match, they change it, they go away. 238 00:21:19,730 --> 00:21:21,680 你可以将其想像成一种并行过程 You can imagine it as a parallel process of some sort. 239 00:21:22,704 --> 00:21:24,976 所以你把一个表达式放到这锅“浓汤”中 So you stick an expression into this mess, 240 00:21:25,808 --> 00:21:28,000 过了会儿把它拿出来 它就被简化了 and after a while, you take it out, and it's been simplified. 241 00:21:30,448 --> 00:21:32,640 它会一直变化 直到不能再变化为止 And it just keeps changing until it no longer can be changed. 242 00:21:33,360 --> 00:21:38,336 但这些酶可以附着在表达式的任何部分 But these enzymes can attach to any part of the, of the expression. 243 00:21:39,216 --> 00:21:43,760 课先上到这里 有问题么? OK, at this point, I'd like to stop and ask for questions. 244 00:21:44,928 --> 00:21:45,360 请讲 Yes. 245 00:21:45,430 --> 00:21:52,760 学生:匹配器和实例化器是两个独立的程序 是么? AUDIENCE: This implies that the matching program and the instantiation program are separate programs; is that right? Or is that-- they are. 246 00:21:52,760 --> 00:21:53,856 教授:他们被拆分成很多小片 PROFESSOR: They're separate little pieces. 247 00:21:54,144 --> 00:21:56,600 然后在一个更大的结构中组合起来 They fit together in a larger structure. 248 00:21:57,264 --> 00:21:59,136 学生:先扫描并匹配 AUDIENCE: So I'm going through and matching 249 00:21:59,616 --> 00:22:03,216 并把匹配结果传递给实例化器 and passing the information about what I matched to an instantiater, 250 00:22:03,390 --> 00:22:06,032 实例化器做出更改 并将其返回给匹配器 which makes the changes. And then I pass that back to the matcher? 251 00:22:06,110 --> 00:22:08,496 教授:不是直接更改 而是生成新的表达式 PROFESSOR: It won't make a change. It will make a new expression, 252 00:22:09,616 --> 00:22:18,432 新表达式中的模式变量都被左边式子中所匹配的值所替换 which has, which has substituted the values of the pattern variable that were matched on the left-hand side for the variables that are mentioned, 253 00:22:18,992 --> 00:22:23,808 也就是右边式子中的那些骨架变量 或者说求值变量 the skeleton variables or evaluation variables or whatever I called them, on the right-hand side. 254 00:22:25,200 --> 00:22:27,088 学生:然后它要回传给匹配器么? AUDIENCE: And then that's passed back into the matcher? 255 00:22:27,200 --> 00:22:32,320 教授:然后要再进行一轮 直到表达式不再变化 PROFESSOR: Then this is going to go around again. This is going to go through this mess until it no longer changes. 256 00:22:33,312 --> 00:22:37,008 学生:感觉这样递归循环似乎有些危险 AUDIENCE: And it seems that there would be a danger of getting into a recursive loop. 257 00:22:37,200 --> 00:22:42,000 教授:你说得很对 如果你定义的规则不好-- Yes, if you do not write your rules nicely, you are-- indeed, 258 00:22:42,000 --> 00:22:45,536 你发明的任何语言 如果它可以做任何事情 in any programming language you invent, if it's sufficiently powerful to do anything, 259 00:22:45,728 --> 00:22:48,400 你就可能写出无限循环的程序 you can write programs that will go into infinite loops. 260 00:22:49,376 --> 00:22:55,072 确实 诸如代数处理 这样的过程可能会产生无限循环 And indeed, writing a program for doing algebraic manipulation so on will produce infinite loops. 261 00:23:01,056 --> 00:23:01,520 教授:请讲 Go ahead. 262 00:23:01,790 --> 00:23:05,904 学生:一些语言的设计者觉得这个特性非常重要 AUDIENCE: Some language designers feel that this feature is so important 263 00:23:05,936 --> 00:23:12,030 以至于它应该是语言的一部分 比如Scheme that it should become part of the basic language, for example, scheme in this case. 264 00:23:12,030 --> 00:23:13,960 你的观点是-- What are your thoughts on-- 265 00:23:13,960 --> 00:23:15,088 老师:语言的什么特性? PROFESSOR: Which language feature? 266 00:23:15,792 --> 00:23:17,260 学生:模式匹配 AUDIENCE: The pattern matching. 267 00:23:17,260 --> 00:23:22,030 所有应用的这些规则应该 --- It's all application of such rules should be-- 268 00:23:22,030 --> 00:23:23,700 教授:你是说像 Prolog 那样? PROFESSOR: Oh, you mean like Prolog? 269 00:23:23,700 --> 00:23:26,600 学生:类似 Prolog 但更加通用的-- AUDIENCE: Like Prolog, but it becomes a more general-- 270 00:23:26,600 --> 00:23:27,648 教授:这是可行的 PROFESSOR: It's possible. 271 00:23:28,464 --> 00:23:32,304 好了 我是觉得吧…… 恩…… OK, I think my feeling about that is that 272 00:23:33,168 --> 00:23:36,496 我可以教你怎么做 这样你就不用依靠语言的设计者 I would like to teach you how to do it so you don't depend upon some language designer. 273 00:23:40,928 --> 00:23:42,752 教授:我们可以自己来实现 PROFESSOR: You make it yourself. You can roll your own. 274 00:23:45,280 --> 00:23:45,630 下课 Thank you. 275 00:23:45,630 --> 00:23:50,630 [音乐] [JESU, JOY OF MAN'S DESIRING] 276 00:23:50,630 --> 00:23:53,130 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 277 00:23:53,130 --> 00:23:55,630 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 278 00:24:00,320 --> 00:24:06,768 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 279 00:24:07,070 --> 00:24:10,528 模式匹配:基于规则的代换 Pattern-matching: Rule-based Substitution 280 00:24:14,080 --> 00:24:15,800 好 上课 Well, let's see. 281 00:24:15,800 --> 00:24:17,216 现在 我得告诉你们它是如何运作的 Now we have to tell you how it works. 282 00:24:20,000 --> 00:24:24,112 它很容易分成很多小份 It conveniently breaks up into various pieces. 283 00:24:24,800 --> 00:24:26,544 现在 我们先看一下匹配器 I'd like to look now at the matcher. 284 00:24:28,720 --> 00:24:31,424 匹配器的结构是像下面这样的 The matcher has the following basic structure. 285 00:24:32,860 --> 00:24:45,120 它是一个盒子 它的输入是一个表达式和一个模式 It's a box that takes as its input an expression and a pattern, 286 00:24:52,096 --> 00:24:53,952 还有个输入是一本词典 and it turns out a dictionary. 287 00:25:01,712 --> 00:25:08,672 要记住 词典把模式变量映射到匹配的值上 A dictionary, remember, is a mapping of pattern variables to the values that were found by matching, 288 00:25:09,152 --> 00:25:11,056 它的输出是另一本词典 and it puts out another dictionary, 289 00:25:18,240 --> 00:25:25,536 除了旧词典中已有的内容 新词典中还产生的新的匹配 which is the result of augmenting this dictionary by what was found in matching this expression against this pattern. 290 00:25:28,000 --> 00:25:28,832 这就是匹配器 So that's the matcher. 291 00:25:33,872 --> 00:25:36,544 这是一个相当复杂的程序 Now, this is a rather complicated program, 292 00:25:37,200 --> 00:25:41,584 请大家看看这里的投影 请看 Now, this is a rather complicated program, and we can look at it on the overhead over here and see, 293 00:25:41,984 --> 00:25:43,872 哈哈 真是相当复杂 ha ha, it's very complicated. 294 00:25:44,432 --> 00:25:45,872 我只想让大家看一下它的轮廓 I just want you to look at the shape of it. 295 00:25:46,784 --> 00:25:49,856 其实现细节太复杂了 It's too complicated to look at except in pieces. 296 00:25:51,728 --> 00:25:59,248 然而 这是一个庞大的程序 它有很多这样的缩进的结构 However, it's a fairly large, complicated program with a lot of sort of indented structure. 297 00:26:00,096 --> 00:26:05,280 在最外层 -- 不要去读这些代码 宏观地看 At the largest scale-- you don't try to read those characters, but at the largest scale, 298 00:26:05,430 --> 00:26:10,368 这里有一个分情况分析 而这些就是不同的情况 you see that there is a case analysis, which is all these cases lined up. 299 00:26:12,090 --> 00:26:16,192 现在 我们将要深入细节 What we're now going to do is look at this in a bit more detail, 300 00:26:16,672 --> 00:26:18,600 试图理解它是如何工作的 attempting to understand how it works. 301 00:26:20,080 --> 00:26:22,352 我们来看第一张幻灯片 Let's go now to the first slide, 302 00:26:23,552 --> 00:26:27,936 它展示了匹配器的宏观结构 showing some of the structure of the matcher at a large scale. 303 00:26:28,816 --> 00:26:36,336 我们看到匹配器 它需要的参数有:模式、表达式和词典 And we see that the matcher, the matcher takes as its input a pattern, an expression, and a dictionary. 304 00:26:38,576 --> 00:26:40,400 这里是一个cond语句 And there is a case analysis here, 305 00:26:41,248 --> 00:26:45,616 它有许多不同情况 我们省略了一些代码 which is made out of several cases, some of which have been left out over here, 306 00:26:46,624 --> 00:26:48,624 这个是我想让大家注意的 通用情况 and the general case, which I'd like you to see. 307 00:26:50,528 --> 00:26:53,280 考虑这个通用模式 它是个非常重要的模式 Let's consider this general case. It's a very important pattern. 308 00:26:56,320 --> 00:27:01,616 问题是我们需要同时地检查这两棵树 The problem is that we have to examine two trees simultaneously. 309 00:27:02,500 --> 00:27:08,030 一棵树是表达式 另一棵树是模式 One of the trees is the tree of the expression, and the other is the tree of the pattern. 310 00:27:08,590 --> 00:27:10,112 我们需要在它们之间进行匹配 We have to compare them with each other 311 00:27:11,376 --> 00:27:16,384 使得表达式的子表达式会与模式的子表达式相匹配 so that the subexpressions of the expression are matched against subexpressions of the pattern. 312 00:27:18,384 --> 00:27:23,440 我们深入研究一下 假设我有一个模式 Looking at that in a bit more detail, suppose I had a pattern, a pattern, 313 00:27:23,930 --> 00:27:31,248 这个是模式是 一个叫做x的表达式 乘以 which was the sum of the product of a thing which we will call x 314 00:27:32,448 --> 00:27:35,536 乘以一个我们叫做y的表达式 and a thing which we will call y, 315 00:27:39,120 --> 00:27:42,048 再加上 刚才的表达式y 两个y必须是相同的表达式 and the sum of that, and the same thing we call y. 316 00:27:45,210 --> 00:27:47,536 我们在考察 乘式的和 So we're looking for a sum of a product 317 00:27:48,992 --> 00:27:54,784 其中 乘法和加法的第二个参数都是相同的 whose second--whose second argument is the same as the second argument of the sum. 318 00:27:57,024 --> 00:27:58,848 这是我们想要匹配像这样的表达式 That's a thing you might be looking for. 319 00:27:59,600 --> 00:28:02,048 它作为一个模式看起来像这个样子 Well, that, as a pattern, looks like this. 320 00:28:03,024 --> 00:28:04,016 这是一课树 There is a tree, 321 00:28:04,940 --> 00:28:06,256 它包含了一个加号 which consists of a sum, 322 00:28:08,080 --> 00:28:20,256 还有乘号 以及模式变量(? x)和(? y) and a product with a pattern variable question mark x and question mark y, 323 00:28:21,360 --> 00:28:22,736 还有模式变量(? y) and question mark y, 324 00:28:24,920 --> 00:28:26,944 这只是把表结构换了种写法 两者其实是一样的 just looking at the same, just writing down the list structure in a different way. 325 00:28:28,752 --> 00:28:31,760 我们先演示一个成功的匹配是如何运行的 Now, suppose we were matching that against an expression which matches it, 326 00:28:32,496 --> 00:28:39,856 这个模式匹配表达式 (+ (* 3 x) x) the product of 3 and x and, say, x. 327 00:28:42,416 --> 00:28:43,360 这是另一棵个树 That's another tree. 328 00:28:44,336 --> 00:28:56,064 它是3乘以x的积加上x It's the sum of the product of 3 and x and of x. 329 00:28:59,440 --> 00:29:03,024 所以我要做的是 同时遍历这两棵树 So what I want to do is traverse these two trees simultaneously. 330 00:29:04,416 --> 00:29:07,824 我想这样遍历它们 And what I'd like to do is walk them like this. 331 00:29:08,672 --> 00:29:12,960 我会比较它们是否一样 I'm going to say are these the same? 332 00:29:12,960 --> 00:29:14,320 这是一个复合对象 This is a complicated object. 333 00:29:15,216 --> 00:29:17,260 我们先看它的左分支 Let's look at the left branches. 334 00:29:17,260 --> 00:29:18,144 这可能是car部分 Well, that could be the car. 335 00:29:18,560 --> 00:29:21,216 它们匹配吗?恩 两个加号成功匹配 How does that look? Oh yes, the plus looks just fine. 336 00:29:21,680 --> 00:29:24,200 但是下一个对象是复合的 But the next thing here is a complicated thing. 337 00:29:24,200 --> 00:29:24,848 我们看一下它 Let's look at that. 338 00:29:25,200 --> 00:29:26,800 这个也匹配了 Oh yes, that's pretty fine, too. 339 00:29:26,800 --> 00:29:27,792 它们都是星号 They're both asterisks. 340 00:29:28,512 --> 00:29:30,240 现在……哦! Now, whoops! 341 00:29:30,400 --> 00:29:33,600 这是模式变量 它和3相匹配 My pattern variable, it matches against the 3. 342 00:29:34,272 --> 00:29:35,920 记住 现在x等于3 Remember, x equals 3 now. 343 00:29:36,360 --> 00:29:37,376 把它记录在词典中 That's in my dictionary, 344 00:29:37,568 --> 00:29:40,730 遍历过程中 词典紧随着我们 并告诉我们:x等于3 and the dictionary's going to follow along with me: x equals three. 345 00:29:41,456 --> 00:29:45,872 x等于3 y等于x 但这两个是不同意义上的x Ah yes, x equals 3 and y equals x, different x. 346 00:29:46,832 --> 00:29:51,200 那个是模式变量x 而这个是模式变量y匹配表达式x The pattern x is the expression x, the pattern y. 347 00:29:53,616 --> 00:29:57,760 这是模式变量y 它已经有值了 并且值是x Oh yes, the pattern variable y, I've already got a value for it. It's x. 348 00:29:58,368 --> 00:30:00,060 这是x么? 当然是 Is this an x? Oh yeah, sure it is. 349 00:30:00,060 --> 00:30:00,752 好的 That's fine. 350 00:30:02,032 --> 00:30:02,784 完事儿了 Yep, done. 351 00:30:03,392 --> 00:30:08,096 现在 我有一本词典 它在遍历过程中不断积累 I now have a dictionary, which I've accumulated by making this walk. 352 00:30:11,424 --> 00:30:14,512 现在让我们看看这个一般情况 然后看看它如何工作 Well, now let's look at this general case here and see how that works. 353 00:30:15,888 --> 00:30:16,512 这里.. Here we have it. 354 00:30:17,200 --> 00:30:21,664 我传入一个模式 一个表达式 和一本词典 I take in a pattern variable -- sorry -- a pattern, an expression, and a dictionary. 355 00:30:22,384 --> 00:30:27,504 这里的情况比较复杂 -- 它是通用情况 And now I'm going to do a complicated thing here, which is the general case. 356 00:30:29,984 --> 00:30:34,800 一般来说 表达式由两部分组成:左部分和右部分 The expression is made out of two parts: a left and a right half, in general. 357 00:30:35,456 --> 00:30:38,816 在Lisp系统中 复合对象都是由两部分组成的 Anything that's complicated is made out of two pieces in a Lisp system. 358 00:30:40,032 --> 00:30:41,232 现在我们有什么呢? Well, now what do we have here? 359 00:30:41,888 --> 00:30:48,848 我将会用已有的这本词典 继续匹配模式和表达式的car部分 I'm going to match the car's of the two expressions against each other with respect to the dictionary I already have, 360 00:30:50,300 --> 00:30:53,120 这个匹配过程会产生一本新词典 producing a dictionary as its value, 361 00:30:54,144 --> 00:30:57,264 我将用它来匹配它们的cdr部分 which I will then use for matching the cdr's against each other. 362 00:30:58,512 --> 00:31:02,096 这就是词典是如何在整个结构中遍历、线索的 So that's how the dictionary travels, threads the entire structure. 363 00:31:03,660 --> 00:31:07,536 匹配完car和cdr部分后得到的词典 And then the result of that is the dictionary for the match of the car and the cdr, 364 00:31:10,128 --> 00:31:12,410 会作为值返回给上级 and that's what's going to be returned as a value. 365 00:31:13,616 --> 00:31:15,840 匹配可能会在任何一个地方失败 Now, at any point, a match might fail. 366 00:31:16,620 --> 00:31:18,208 比如说 可能会有这种情况 It may be the case, for example, 367 00:31:18,368 --> 00:31:27,180 我们回过头来把这里改成4 这样就不会完全匹配 if we go back and look at an expression that doesn't quite match, like supposing this was a 4. 368 00:31:29,136 --> 00:31:34,816 现在这两个不再匹配了 因为x应该 Well, now these two don't match any more, because the x that had to be -- 369 00:31:34,930 --> 00:31:37,344 不好意思 这个y是x sorry, the y that had to be x here 370 00:31:37,824 --> 00:31:40,128 但是这里的y却又是4 and this y has to be 4. 371 00:31:40,530 --> 00:31:43,520 语法上来说 x和4显然不相同 But x and 4 were not the same object syntactically. 372 00:31:44,592 --> 00:31:48,816 所以这个不会匹配成功 它会拒绝 匹配会失败 So this wouldn't match, and that would be rejected sometimes, so matches may fail. 373 00:31:50,192 --> 00:31:56,080 那么 因为先前产生的词典会作为输入送入匹配器 Now, of course, because this matcher takes the dictionary from the previous match as input, 374 00:31:56,528 --> 00:31:58,288 所以它必须能够传播失败 it must be able to propagate the failures. 375 00:31:58,576 --> 00:32:01,040 第一条语句就是用来判断失败的 And so that's what the first clause of this conditional does. 376 00:32:03,616 --> 00:32:08,192 如果证实出来这个模式不是原子的--- It's also true that if it turned out that the pattern was not atomic-- 377 00:32:08,500 --> 00:32:11,456 如果模式是原子的 将进入这里 这里我们还没有讨论过 see, if the pattern was atomic, I'd go into this stuff, which we haven't looked at yet. 378 00:32:12,170 --> 00:32:13,568 如果模式不是原子的 But if the pattern is not atomic 379 00:32:15,056 --> 00:32:19,232 但表达式是原子--也就是它不由小部分组成 and the expression is atomic-- it's not made out of pieces-- 380 00:32:20,144 --> 00:32:22,650 那么匹配必然失败 因此我们返回'failed then that must be a failure, and so we go over here. 381 00:32:23,648 --> 00:32:30,784 整理下思路 如果这个模式既不是原子的又不是模式变量的话 程序会来到这里 If the pattern is not atomic and the pattern is not a pattern variable--I have to remind myself of that-- then we go over here. 382 00:32:30,960 --> 00:32:32,512 这是会使匹配失败的情况 So that's way, failures may occur. 383 00:32:35,264 --> 00:32:39,120 好 让我们看这个里面的东西 OK, so now let's look at the insides of this thing. 384 00:32:39,840 --> 00:32:42,930 首先需要知道 如果用原子模式来进行匹配会发生什么? Well, the first place to look is what happens if I have an atomic pattern? 385 00:32:42,930 --> 00:32:43,900 这简单 That's very simple. 386 00:32:43,900 --> 00:32:46,500 不是由其它模式构成的模式 比如:foo A pattern that's not made out of any pieces: foo. 387 00:32:47,376 --> 00:32:48,544 这是个非常好的原子模式 That's a nice atomic pattern. 388 00:32:49,168 --> 00:32:51,248 让我们来看看 Well, here's what we see. 389 00:32:52,080 --> 00:32:55,824 如果模式是原子的 而且表达式也原子的话 If the pattern is atomic, then if the expression is atomic, 390 00:32:56,800 --> 00:33:01,856 并且如果它俩是同一个东西 那么词典就跟之前一样 then if they are the same thing, then the dictionary I get is the same one as I had before. 391 00:33:03,088 --> 00:33:04,000 没有变化 Nothing's changed. 392 00:33:04,608 --> 00:33:10,336 就像刚才 +匹配+ *匹配* x匹配x It's just that I matched plus against plus, asterisk against asterisk, x against x. 393 00:33:11,424 --> 00:33:12,336 就是那样 That's all fine. 394 00:33:13,072 --> 00:33:16,816 然而 如何模式和表达式并不相同的话 However, if the pattern is not the one which is the expression, 395 00:33:17,328 --> 00:33:21,360 如果这是两个不同的原子对象 比如+和*相匹配 if I have two separate atomic objects, then it was matching plus against asterisk, 396 00:33:22,448 --> 00:33:23,408 这样就失败了 which case I fail. 397 00:33:25,600 --> 00:33:34,560 或者说 如果模式是原子 但表达式是复合 那么匹配失败 Or if it turns out that the pattern is atomic but the expression is complicated, it's not atomic, then I get a failure. 398 00:33:37,408 --> 00:33:38,240 这很简单 That's very simple. 399 00:33:38,816 --> 00:33:43,616 那么 那些各种各样的模式变量又是怎么处理的呢? Now, what about the various kinds of pattern variables? 400 00:33:44,090 --> 00:33:46,544 我们有三类被命名了的模式变量 We had three kinds. I give them the names. 401 00:33:47,392 --> 00:33:52,032 它们分别用于匹配:任意常量 任意变量 任意表达式 They're arbitrary constants, arbitrary variables, and arbitrary expressions. 402 00:33:53,824 --> 00:34:00,144 (? x) 表示匹配任意表达式 A question mark x is an arbitrary expression. 403 00:34:01,184 --> 00:34:04,544 (?c x) 表示匹配任意常量 A question mark cx is an arbitrary constant, 404 00:34:04,730 --> 00:34:07,296 (?v x) 表示匹配任意变量 and a question mark vx is an arbitrary variable. 405 00:34:08,960 --> 00:34:09,792 好的 我们要做什么呢? Well, what do we do here? 406 00:34:10,512 --> 00:34:16,944 看这里 如果模式表示的是匹配任意常量 Looking at this, we see that if I have an arbitrary constant, if the pattern is an arbitrary constant, 407 00:34:17,536 --> 00:34:20,576 那么待匹配的表达式最好是一个常量 then it had better be the case that the expression had better be a constant. 408 00:34:21,488 --> 00:34:23,536 不然的话 匹配就会失败 If the expression is not a constant, then that match fails. 409 00:34:23,830 --> 00:34:27,500 如果是一个常量 那么我就需要扩充词典 If it is a constant, however, then I wish to extend the dictionary. 410 00:34:27,500 --> 00:34:29,696 扩充词典的方法则是: I wish to extend the dictionary 411 00:34:30,704 --> 00:34:37,760 在旧词典后 附加一对模式与表达式的配对 with that pattern being remembered to be that expression using the old dictionary as a starting point. 412 00:34:41,160 --> 00:34:42,752 因此 如果是匹配任意变量 So really, for arbitrary variables, 413 00:34:43,728 --> 00:34:47,460 我得通过匹配来核查表达式是否是变量 I have to check first if the expression is a variable by matching against. 414 00:34:47,460 --> 00:34:50,096 如果是的话 我就扩充词典 If so, it's worth extending the dictionary 415 00:34:50,384 --> 00:34:54,650 现在在原有词典基础上 我们又多了一项模式与表达式的匹配 so the pattern is remembered to be matched against that expression, given the original dictionary, 416 00:34:55,280 --> 00:34:56,704 这个过程返回一本新的词典 and this makes a new dictionary. 417 00:34:58,880 --> 00:35:04,160 在这个词典中也有很多失败 因此需要检查 Now, it has to check. There's a sorts of failure inside extend dictionary, which is that-- 418 00:35:04,160 --> 00:35:07,504 就比如 模式变量已经有一个值了 if one of these pattern variables already has a value 419 00:35:09,230 --> 00:35:16,176 但我又用它匹配一个跟之前匹配的表达式不相同的表达式的话 and I'm trying to match the thing against something else which is not equivalent to the one that I've already matched it against once, 420 00:35:16,432 --> 00:35:18,368 那么在这里也会立即产生失败 then a failure will come flying out of here, too. 421 00:35:20,160 --> 00:35:21,568 我们后面再讨论 And I will see that some time. 422 00:35:22,910 --> 00:35:29,360 最后 匹配任意的表达式不需要在语法范畴做什么检查 And finally, an expression does not have to check anything syntactic about the expression that's being matched, 423 00:35:30,112 --> 00:35:32,208 只用扩充词典就行了 so all it does is it's an extension of the dictionary. 424 00:35:34,768 --> 00:35:38,320 这就是一个完整的简单的匹配器 So you've just seen a complete, very simple matcher. 425 00:35:39,280 --> 00:35:41,376 非常具有讽刺意味的一点是 Now, one of the things that's rather remarkable about this 426 00:35:41,660 --> 00:35:45,120 现在 人们花了大价钱来请一些人编写 is people pay an awful lot of money these days for someone to make 427 00:35:45,460 --> 00:35:47,520 所谓的 “人工智能专家系统” a, quote, AI expert system 428 00:35:48,400 --> 00:35:52,032 也不过是像这样的一个匹配器和实例化器罢了 that has nothing more in it than a matcher and maybe an instantiater like this. 429 00:35:53,568 --> 00:35:56,944 这很容易做 现在你也可以创业开个小公司了 But it's very easy to do, and now, of course, you can start up a little start-up company 430 00:35:57,424 --> 00:36:01,728 然后 第二周忽悠风投给你投个几百万 and make a couple of megabucks in the next week taking some people for a ride. 431 00:36:03,792 --> 00:36:08,570 我是想说 这种程序放在20年前是非凡的 I mean, 20 years ago, this was remarkable, this kind of program. 432 00:36:09,740 --> 00:36:12,816 但放到现在 它就是小菜一碟了 大一新生也可以学 But now, this is sort of easy. You can teach it to freshmen. 433 00:36:13,632 --> 00:36:15,472 这里是一个实例化器 Well, now there's an instantiater as well. 434 00:36:20,224 --> 00:36:23,072 可问题是 他们都去了赚钱了 而且比我的还多 The problem is they're all going off and making more money than I do. Alright? 435 00:36:24,976 --> 00:36:26,592 在大学中确实是这样 But that's always been true of universities. 436 00:36:27,104 --> 00:36:39,424 实例化是用来将给定的表达式、词典和骨架生成新的表达式的 As expression, the purpose of the instantiater is to make expressions given a dictionary and a skeleton. 437 00:36:44,352 --> 00:36:45,696 这个不是很难 And that's not very hard at all. 438 00:36:46,608 --> 00:36:53,360 我们在下一张幻灯片中简单地看下 We'll see that very simply in the next, the next slide here. 439 00:36:53,888 --> 00:36:59,296 用一本给定的词典去实例化一个骨架 这很简单 To instantiate a skeleton, given a particular dictionary-- oh, this is easy. 440 00:36:59,680 --> 00:37:03,296 我们要做的 就是对骨架递归地做树遍历 We're going to do a recursive tree walk over the skeleton. 441 00:37:04,080 --> 00:37:08,330 所有的骨架变量---我叫它“骨架求值” And for everything which is a skeleton variable-- I don't know, call it a skeleton evaluation. 442 00:37:08,416 --> 00:37:11,424 这是我在这个程序中定义的抽象语法 That's the name and the abstract syntax that I give it in this program: 443 00:37:11,600 --> 00:37:16,464 在规则中 以冒号打头的就是骨架求值 a skeleton evaluation, a thing beginning with a colon in the rules. 444 00:37:18,256 --> 00:37:24,300 在那种情况下 我要在词典中找答案 我们待会儿再讨论 For anything of that case, I'm going to look up the answer in the dictionary, and we'll worry about that in a second. 445 00:37:24,300 --> 00:37:25,616 我们看整体 Let's look at this as a whole. 446 00:37:27,776 --> 00:37:31,808 这个过程是用一本字典来实例化一个骨架 Here, I have-- I'm going to instantiate a skeleton, given a dictionary. 447 00:37:32,750 --> 00:37:37,152 我在这里定义一个内部循环 Well, I'm going to define some internal loop right there, 448 00:37:38,144 --> 00:37:39,850 它要做的事情很简单 and it's going to do something very simple. 449 00:37:40,176 --> 00:37:43,504 如果这个骨架是原子的 Even if a skeleton--even if a skeleton is simple and atomic, 450 00:37:44,608 --> 00:37:47,456 这种情况 它直接返回一个骨架作为结果 in which case it's nothing more than giving the skeleton back as an answer, 451 00:37:48,840 --> 00:37:51,872 或者在通常情况下它是复合的 or in the general case, it's complicated, 452 00:37:52,608 --> 00:37:59,400 这种情况下 我通过一些实例化的结果构造表达式 in which case I'm going to make up the expression which is the result of instantiating-- 453 00:37:59,400 --> 00:38:04,256 递归调用这个循环 不断实例化骨架的car和cdr部分 calling this loop recursively-- instantiating the car of the skeleton and the cdr. 454 00:38:04,896 --> 00:38:06,240 这就是树的递归遍历 So here is a recursive tree walk. 455 00:38:08,416 --> 00:38:14,368 如果在骨架中有冒号表达式 那么这就是一个骨架求值 However, if it turns out to be a skeleton evaluation, a colon expression in the skeleton, 456 00:38:14,960 --> 00:38:22,640 那么要做的事情是:找到冒号引导的表达式 -- 本例中 也就是CADR部分 then what I'm going to do is find the expression that's in the colon-- the CADR in this case. 457 00:38:22,816 --> 00:38:26,256 这些是抽象语法 因此我能改变规则的表示 It's a piece of abstract syntax here, so I can change my representation of rules. 458 00:38:27,520 --> 00:38:32,736 先不管求值过程如何实现 总之我要用这本词典对表达式求值 I'm going to evaluate that relative to this dictionary, whatever evaluation means. 459 00:38:32,900 --> 00:38:34,656 我们以后再仔细讨论 We'll find out a lot about that sometime. 460 00:38:36,128 --> 00:38:38,352 求值的结果就是答案 And the result of that is my answer. 461 00:38:39,680 --> 00:38:43,664 这条初始化语句 通过给它传递整个骨架循环来启动它 so. I start up this loop-- here's my initialization-- by calling it with the whole skeleton, 462 00:38:44,448 --> 00:38:47,040 这些调用又会被分成小块的递归调用 and this will just do a recursive decomposition into pieces. 463 00:38:49,632 --> 00:38:56,480 那么 求值过程里面发生了些什么 Now, one more little bit of detail is what happens inside evaluate? 464 00:38:57,184 --> 00:38:59,072 我无法详尽地给你们解释 I can't tell you that in great detail. 465 00:38:59,984 --> 00:39:01,344 我就大致说一下 I'll tell you a little bit of it. 466 00:39:01,560 --> 00:39:03,744 之后 我们再深入地讨论 Later, we're going to see--look into this in much more detail. 467 00:39:05,296 --> 00:39:10,816 在一本词典的环境下 求值一个表达式 To evaluate some form, some expression with respect to a dictionary, 468 00:39:11,904 --> 00:39:14,176 如果表达式是原子的 if the expression is an atomic object, well, 469 00:39:15,040 --> 00:39:16,224 就在词典中进行查找 I'm going to go look it up. 470 00:39:18,608 --> 00:39:19,872 这没啥 Nothing very exciting there. 471 00:39:20,576 --> 00:39:23,664 难点在这里 Otherwise, I'm going to do something complicated here, 472 00:39:23,830 --> 00:39:28,288 我将要应用表达式的car部分对应的一个过程 which is I'm going to apply a procedure which is the result of looking up the operator part 473 00:39:29,440 --> 00:39:31,680 这个过程是在“某个地方”查找得到的--我们以后讨论 in something that we're going to find out about someday. 474 00:39:32,144 --> 00:39:34,208 我想请大家注意一下 这之中有一些“魔法” I want you realize you're seeing magic now. 475 00:39:34,672 --> 00:39:38,720 这个魔法将在不久后“施展”出来 但不是在今天 This magic will become clear very soon, but not today. 476 00:39:40,000 --> 00:39:46,510 我们在词典中查找表达式剩余部分对应的值 Then I'm looking at--looking up all the pieces, all the arguments to that in the dictionary. 477 00:39:48,560 --> 00:39:50,880 我还不想让你们关注细节 So I don't want you to look at this in detail. 478 00:39:51,440 --> 00:39:53,440 我想让大家意识到这里还有很多代码 I want you to see that there's more going on here, 479 00:39:54,176 --> 00:39:56,750 我们以后再详细讨论 and we're going to see more about this. 480 00:39:59,040 --> 00:40:00,880 但是 魔法就到此结束了 But it's-- the magic is going to stop. 481 00:40:02,576 --> 00:40:06,960 这部分利用Lisp的神奇力量 不过也就到此为止了 This part has to do with Lisp, and it's the end of that. 482 00:40:10,256 --> 00:40:13,568 我们介绍了匹配和实例化 OK, so now we know about matching and instantiation. 483 00:40:15,056 --> 00:40:16,608 这一节有疑问么? Are there any questions for this segment? 484 00:40:28,100 --> 00:40:29,800 学生:我有一个问题 AUDIENCE: I have a question. 485 00:40:29,800 --> 00:40:30,430 教授:请讲 PROFESSOR: Yes. 486 00:40:30,430 --> 00:40:32,560 学生:您能切到前张幻灯片上吗? AUDIENCE: Is it possible to bring up a previous slide? 487 00:40:33,600 --> 00:40:35,568 是关于定义匹配模式的 It's about this define match pattern. 488 00:40:36,160 --> 00:40:40,760 教授:好的 你想看定义匹配模式的全部的幻灯片 PROFESSOR: Yes. You'd like to see the overall slide define match pattern. 489 00:40:40,760 --> 00:40:43,060 有人能帮我把投影仪--- Can somebody put up the -- no, the overhead. 490 00:40:43,060 --> 00:40:45,160 这是最大的规模 That's the biggest scale one. 491 00:40:45,312 --> 00:40:46,400 你想看哪一部分? What part would you like to see? 492 00:40:46,760 --> 00:40:49,960 学生:呃 最上面吧 AUDIENCE: Well, the top would be fine. 493 00:40:49,960 --> 00:40:53,760 就是传递失败的那一部分 Any of the parts where you're passing failed. 494 00:40:54,528 --> 00:40:55,216 教授:恩 PROFESSOR: Yes. 495 00:40:55,648 --> 00:40:59,330 学生:基本的想法是把错误返回给词典 是么? AUDIENCE: The idea is to pass failed back to the dictionary; is that right? 496 00:40:59,330 --> 00:41:04,256 教授:所谓的词典 就是所是匹配的答案 对吧? PROFESSOR: The dictionary is the answer to a match, right? 497 00:41:05,160 --> 00:41:09,808 要么它是一些配对 And it is either some mapping 498 00:41:11,072 --> 00:41:14,030 要么根本就没有配对 or there's no match. It doesn't match. 499 00:41:14,464 --> 00:41:14,976 学生:对 AUDIENCE: Right. 500 00:41:15,264 --> 00:41:17,830 教授:这里 事实上 PROFESSOR: So what you're seeing over here is, in fact, 501 00:41:17,830 --> 00:41:22,600 因为一个匹配过程会向另一个匹配过程传递词典 because the fact that a match may have another match pass in the dictionary, 502 00:41:22,800 --> 00:41:24,656 可以在这里的一般情况中看到 as you see in the general case down here. 503 00:41:25,120 --> 00:41:27,930 这是一个匹配过程传递词典到另一个匹配过程 Here's the general case where a match passes another match to the dictionary. 504 00:41:28,144 --> 00:41:34,160 我是用匹配car部分得到的词典来匹配cdr部分的 When I match the cdr's, I match them in the dictionary that is resulting from matching the car's. 505 00:41:36,064 --> 00:41:37,088 这里的代码就是这个意思 OK, that's what I have here. 506 00:41:37,296 --> 00:41:40,304 正因为如此 如果对car部分的匹配失败了 So because of that, if the match of the car's fails, 507 00:41:41,232 --> 00:41:45,440 匹配cdr部分的时候就有必要传播失败 then it may be necessary that the match of the cdr's propagates that failure, 508 00:41:45,952 --> 00:41:46,960 第一行就是用于传播失败 and that's what the first line is. 509 00:41:48,260 --> 00:41:51,730 学生:好 但我还是不明白匹配 -- AUDIENCE: OK, well, I'm still unclear what matches-- 510 00:41:51,730 --> 00:41:54,240 从匹配的实例出来的是什么? what comes out of one instance of the match? 511 00:41:54,730 --> 00:41:56,000 教授:有两种可能的情况 PROFESSOR: One of two possibilities. 512 00:41:56,336 --> 00:41:59,152 一种是符号'failed 意味匹配失败 Either the symbol failed, which means there is no match. 513 00:41:59,530 --> 00:41:59,930 学生:对 AUDIENCE: Right. 514 00:41:59,930 --> 00:42:03,872 教授:或者是某种映射 -- 现在这还是一个抽象的东西 PROFESSOR: Or some mapping, which is an abstract thing right now, 515 00:42:04,160 --> 00:42:05,680 你需要知道它的结构 and you should know about the structure of it, 516 00:42:06,496 --> 00:42:13,968 它们把匹配过程中 匹配成功的模式变量和值关联起来 which relates the pattern variables to their values as picked up in the match. 517 00:42:14,688 --> 00:42:16,704 学生:好 那么 AUDIENCE: OK, so it is-- 518 00:42:16,800 --> 00:42:18,576 教授:那是通过扩充词典实现的 PROFESSOR: That's constructed by extend dictionary. 519 00:42:18,800 --> 00:42:28,544 学生:所以根据递归性质 如果匹配过程产生并传递了失败 AUDIENCE: So the recursive nature brings about the fact that if ever a failed gets passed out of any calling of match, 520 00:42:28,688 --> 00:42:30,304 那么第一种情况将捕获它 then the first condition will pick it up-- 521 00:42:30,400 --> 00:42:33,560 教授:并且传播它 不做任何其它处理 PROFESSOR: And just propagate it along without any further ado, right. 522 00:42:33,560 --> 00:42:34,830 学生:哦 懂了 AUDIENCE: Oh, right. 523 00:42:35,504 --> 00:42:37,360 教授:这是传出失败最快的方法 PROFESSOR: That's just the fastest way to get that failure out of there. 524 00:42:42,860 --> 00:42:43,600 请讲 Yes. 525 00:42:43,840 --> 00:42:47,232 学生:如果没有失败 那意味着我匹配了一个模式 AUDIENCE: If I don't fail, that means that I've matched a pattern, 526 00:42:47,840 --> 00:42:53,008 我会扩充词典并且传递表达式中的模式 and I run the procedure extend dict and then pass in the pattern in the expression. 527 00:42:55,216 --> 00:42:58,430 但是 代换并不是发生在这 对吧? But the substitution will not be made at that point; is that right? 528 00:42:58,430 --> 00:42:59,030 是吧? I'm just-- 529 00:42:59,030 --> 00:42:59,460 教授:你是对的 PROFESSOR: No, no. 530 00:42:59,460 --> 00:43:02,400 这里没有可供代换的骨架 因此不会发生代换 There's no substitution being there because there's no skeleton to be substituted in. 531 00:43:02,400 --> 00:43:03,060 学生:好 那么 AUDIENCE: Right. So 532 00:43:03,060 --> 00:43:07,160 教授:我们这里所做的 是为后面的代换准备词典 PROFESSOR: All you've got there is we're making up the dictionary for later substitution. 533 00:43:08,256 --> 00:43:12,432 学生:词典的数据结构是什么呢?是有序对么? AUDIENCE: And what would the dictionary look like? Is it ordered pairs? 534 00:43:12,720 --> 00:43:15,960 教授:那个 那个还没有告诉你 PROFESSOR: Ahhhhh, That's--that's not told to you. 535 00:43:15,960 --> 00:43:16,896 它还是一个抽象的东西 We're being abstract. 536 00:43:17,060 --> 00:43:17,560 学生:哦 AUDIENCE: OK. 537 00:43:17,560 --> 00:43:18,900 教授:你为什么要知道呢? PROFESSOR: Why do you want to know? 538 00:43:18,900 --> 00:43:21,648 它是一个函数 仅仅是一个函数 What it is, it's a function. It's a function. 539 00:43:21,696 --> 00:43:22,330 学生:我想知道它的原因是-- AUDIENCE: Well, the reason I want to know is-- 540 00:43:22,330 --> 00:43:24,176 教授:这个抽象函数表现地像有序对 PROFESSOR: A function abstractly is a set of ordered pairs. 541 00:43:25,120 --> 00:43:28,448 它可以用一系列的表通过链接来实现 It could be implemented as a set of list pairs. 542 00:43:29,060 --> 00:43:32,430 它也可以用一些酷炫的表机制来实现 It could be implemented as some fancy table mechanism. 543 00:43:32,560 --> 00:43:34,160 它也可以实现为一个函数 It could be implemented as a function. 544 00:43:35,808 --> 00:43:37,408 我可以把它写成一个函数 And somehow, I'm building up a function. 545 00:43:39,024 --> 00:43:39,872 但我不会告诉你具体细节 But I'm not telling you. 546 00:43:40,848 --> 00:43:43,088 这是George的事情 由他来构建这个结构 That's up to George, who's going to build that later. 547 00:43:49,568 --> 00:43:52,064 我知道 你特别想知道它的具体结构 I know you really badly want to write concrete things. 548 00:43:52,360 --> 00:43:54,192 但我不打算让你那么做 I'm not going to let you do that. 549 00:43:54,430 --> 00:43:59,232 学生:恩 最后一个问题 扩充到词典中的重要信息是什么? AUDIENCE: Well, let me at least ask, what is the important information there that's being passed to extend dict? 550 00:43:59,744 --> 00:44:02,080 我想 可能是匹配发现的模式 I want to pass the pattern I found-- 551 00:44:02,736 --> 00:44:04,830 教授:是的 那些与表达式相匹配的模式 PROFESSOR: Yes. The pattern that's matched against the expression. 552 00:44:04,830 --> 00:44:09,300 我们想要得到模式 只不过在本例中这些都是模式变量 对吧? You want to have the pattern, which happens to be in those cases pattern variables, right? 553 00:44:09,856 --> 00:44:12,896 这三种扩充词典的情况都是模式变量 All of those three cases for extend dict are pattern variables. 554 00:44:13,200 --> 00:44:13,504 学生:恩 AUDIENCE: Right. 555 00:44:14,480 --> 00:44:18,752 教授:所以 在词典就有一个模式变量与一个值对应 PROFESSOR: So you have a pattern variable that is to be given a value in a dictionary. 556 00:44:19,456 --> 00:44:22,112 这个值是所匹配的表达式 PROFESSOR: The value is the expression that it matched against. 557 00:44:23,312 --> 00:44:29,632 词典就是遍历过程中记录下来的所有匹配 The dictionary is the set of things I've already figured out that I have memorized or learned. 558 00:44:30,540 --> 00:44:34,416 我会以原有词典为基础 创建一本新词典 And I am going to make a new dictionary, which is extended from the original one 559 00:44:35,120 --> 00:44:38,350 新增的内容就是新发现的匹配 by having that pattern variable have a value with the new dictionary. 560 00:44:39,984 --> 00:44:43,730 学生:我不理解为什么不能在发现匹配后立即进行代换 AUDIENCE: I guess what I don't understand is why can't the substitution be made right as soon as you find-- 561 00:44:43,730 --> 00:44:44,800 教授:哦 那时候还不能代换 PROFESSOR: How do I know what I'm going to substitute? 562 00:44:44,816 --> 00:44:46,624 因为我不知道骨架啊! I don't know anything about this skeleton. 563 00:44:47,584 --> 00:44:49,660 模式和匹配器都是独立的单元 This pattern, this matcher is an independent unit. 564 00:44:49,660 --> 00:44:51,000 学生:哦 我明白了 AUDIENCE: Oh, I see. OK. 565 00:44:51,000 --> 00:44:51,500 教授:懂了吧? PROFESSOR: Right? 566 00:44:51,500 --> 00:44:51,900 学生:恩 AUDIENCE: Yeah. 567 00:44:51,900 --> 00:44:57,230 教授:我用这个匹配器进行匹配 如果匹配了就可以实例化 PROFESSOR: I take the matcher. I apply the matcher. If it matches, then it was worth doing instantiation. 568 00:44:58,200 --> 00:44:59,500 学生:知道了 AUDIENCE: OK, good. 569 00:45:00,544 --> 00:45:03,888 学生:您可以再求解一次黑板上的例子么 AUDIENCE: Can you just do that answer again using that example on the board? 570 00:45:04,896 --> 00:45:06,930 什么东西返回给了匹配器 You know, what you just passed back to the matcher. 571 00:45:06,930 --> 00:45:08,000 教授:当然可以 PROFESSOR: Oh yes. OK, yes. 572 00:45:08,260 --> 00:45:09,744 来看这个例子 You're looking at this example. 573 00:45:10,672 --> 00:45:15,456 在这里当我遍历这个结构的时候 我遇到了(? x) At this point when I'm traversing this structure, I get to here: x. 574 00:45:16,672 --> 00:45:20,544 我有一本词典 不过此时假设它是空的 I have some dictionary, presumably an empty dictionary at this point if this is the whole expression. 575 00:45:21,560 --> 00:45:25,360 一本空词典 然后我匹配到了x为3 So I have an empty dictionary, and I've matched x against 3. 576 00:45:26,620 --> 00:45:33,600 从此以后 词典中就记录了 x与3匹配 对吧 So now, after this point,the dictionary contains x is 3, OK? 577 00:45:33,648 --> 00:45:36,096 继续遍历 然后遇到(? y) Now, I continue walking along here. I see y. 578 00:45:36,896 --> 00:45:39,200 它是一个特殊的x 这是模式变量x Now, this is a particular x, a pattern x. 579 00:45:39,792 --> 00:45:41,376 我看到(? y) 模式变量y I see y, a pattern y. 580 00:45:42,176 --> 00:45:47,744 词典说 模式变量y的值是符号x The dictionary says, oh yes, the pattern y is the symbol x 581 00:45:48,992 --> 00:45:51,200 因为这里已经匹配过了 because I've gota match there. 582 00:45:52,432 --> 00:45:54,528 所以此时 词典中包含两个条目 So the dictionary now contains at this point two entries. 583 00:45:55,456 --> 00:45:59,904 模式变量x是数字3 模式变量y是表达式x The pattern x is 3, and the pattern y is the expression x. 584 00:46:01,952 --> 00:46:04,112 现在继续进行遍历 Now, I get that, I can walk along further. 585 00:46:04,230 --> 00:46:07,456 这里 模式变量y想要和4匹配 I say, oh, pattern y also wants to be 4. 586 00:46:08,064 --> 00:46:10,656 但是这个不可能 产生失败 But that isn't possible, producing a failure. 587 00:46:14,304 --> 00:46:15,488 谢谢 下课 Thank you. Let's take a break. 588 00:46:16,760 --> 00:46:25,024 [音乐] [JESU, JOY OF MAN'S DESIRING] 589 00:46:25,070 --> 00:46:27,456 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 590 00:46:27,472 --> 00:46:30,000 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 591 00:46:48,190 --> 00:46:54,752 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 592 00:46:55,200 --> 00:46:58,048 模式匹配:基于规则的代换 Pattern-matching: Rule-based Substitution 593 00:47:02,384 --> 00:47:05,680 这是大家首次看到如此庞大而复杂的程序 OK, you're seeing your first very big and hairy program. 594 00:47:07,344 --> 00:47:09,904 当然 本项课程的目的之一就在于 Now, of course, one of the goals of this subject 595 00:47:09,900 --> 00:47:12,976 是让大家可以读懂这么庞大的程序 而完全不用害怕它 is to get you to be able to read something like this and not be afraid of it. 596 00:47:13,760 --> 00:47:16,336 这个程序仅仅只有4页代码而已 This one's only about four pages of code. 597 00:47:17,080 --> 00:47:19,232 课程结业后 我希望就算是50页长的程序 By the end of the subject, I hope a 50-page program 598 00:47:20,272 --> 00:47:21,800 也吓不倒你们 will not look particularly frightening. 599 00:47:22,976 --> 00:47:28,208 我不是说让你们“左耳朵进 右耳朵出”地读程序 But I don't expect-- and I don't want you to think that I expect you to be getting it as it's coming out. 600 00:47:29,200 --> 00:47:31,700 你应该体会这个程序 You're supposed to feel the flavor of this, OK? 601 00:47:31,700 --> 00:47:34,830 然后好好思考 因为它是一个很大的程序 And then you're supposed to think about it because it is a big program. 602 00:47:35,328 --> 00:47:38,928 在这个程序中有很多东西 There's a lot of stuff inside this program. 603 00:47:41,248 --> 00:47:46,032 我已经介绍了我们正在实现的 -- 基于规则代换的模式匹配语言 Now, I've told you about the language we're implementing, the pattern match substitution language. 604 00:47:46,816 --> 00:47:47,648 给你们看了一些规则 I showed you some rules. 605 00:47:48,360 --> 00:47:51,248 我已经告诉大家匹配和实例化 And I've told you about matching and instantiation, 606 00:47:51,552 --> 00:47:53,320 它们是使规则生效的“阴阳两极” which are the two halves of how a rule works. 607 00:47:54,240 --> 00:47:56,352 现在我们需要理解控制结构 Now we have to understand the control structure 608 00:47:56,864 --> 00:48:00,320 就是这些规则是如何被用在表达式上 by which the rules are applied to the expressions 609 00:48:01,088 --> 00:48:03,840 来指导代数化简的 so as to do algebraic simplification. 610 00:48:06,928 --> 00:48:09,584 这也是非常复杂的 Now, that's also a big complicated mess. 611 00:48:12,096 --> 00:48:19,488 其中有很多循环 相互交织 错综复杂 The problem is that there is a variety of interlocking, interwoven loops, if you will, involved in this. 612 00:48:20,240 --> 00:48:26,992 一方面 我不得不检查 待化简表达式的每个子表达式 For one thing, I have to apply-- I have to examine every subexpression of my expression that I'm trying to simplify. 613 00:48:29,008 --> 00:48:29,930 我们已经讲过了 That we know how to do. 614 00:48:29,930 --> 00:48:36,240 这是在car、cdr部分做某种树形递归 It's a car cdr recursion of some sort, or something like that, and some sort of tree walk. 615 00:48:37,440 --> 00:48:38,592 就是那样 And that's going to be happening. 616 00:48:38,840 --> 00:48:42,464 现在 在我每个遍历到的结点上 Now, for every such place, every node that I get to 617 00:48:43,472 --> 00:48:48,760 也就是我想要化简的(子)表达式 in doing my traversal of the expression I'm trying to simplify, 618 00:48:49,200 --> 00:48:51,072 我需要应用所有的规则 I want to apply all of the rules. 619 00:48:53,424 --> 00:48:55,088 每个规则都需要检查每个节点 Every rule is going to look at every node. 620 00:48:56,000 --> 00:48:57,920 我一直在这些规则中打转(循环) I'm going to rotate the rules around. 621 00:49:01,664 --> 00:49:05,488 一个规则可能匹配 也可能不匹配 Now, either a rule will or will not match. 622 00:49:07,504 --> 00:49:10,624 如果规则不匹配 那我就不关心了 If the rule does not match, then it's not very interesting. 623 00:49:12,288 --> 00:49:19,344 如果规则匹配了 我就在那个结点用另一个表达式替换这个表达式 If the rule does match, then I'm going to replace that node in the expression by an alternate expression. 624 00:49:20,080 --> 00:49:22,896 实际上 我创建了一个新表达式 它包含 I'm actually going to make a new expression, which contains-- 625 00:49:23,550 --> 00:49:28,656 它包含了所有的东西 新的值代换入骨架后的结果 everything contains that new value, the result of substituting into the skeleton, 626 00:49:29,216 --> 00:49:31,920 也就是 在该层次上 把规则所对应的骨架实例化的结果 instantiating the skeleton for that rule at this level. 627 00:49:32,720 --> 00:49:37,376 但我并不知道我所实例化出来的东西 是否是简化形式 But no one knows whether that thing that I instantiated there is in simplified form. 628 00:49:38,752 --> 00:49:43,824 所以我要对我刚刚构建好的东西调用化简器来简化它 So we're going to have to simplify that, somehow to call the simplifier on the thing that I just constructed. 629 00:49:46,128 --> 00:49:50,368 完成后 我就可以将其构建进我想要的表达式中作为答案 And then when that's done, then I sort of can build that into the expression I want as my answer. 630 00:49:51,808 --> 00:49:57,456 这里的基本思想是 我们定义一个 “废料进-废料出”的化简器 Now, there is a basic idea here, which I will call a garbage- in, garbage-out simplifier. 631 00:50:01,472 --> 00:50:02,752 它是一种递归调用的化简器 It's a kind of recursive simplifier. 632 00:50:03,584 --> 00:50:08,848 化简方法是:基本对象 比如变量就是最简形式的了 And what happens is the way simplify something is that simple objects like variables are simple. 633 00:50:10,784 --> 00:50:13,280 复合对象 -- 呃 我也不知道 Compound objects, well, I don't know. 634 00:50:14,096 --> 00:50:16,560 而我要从简单的对象入手 What I'm going to do is I'm going to build up from simple objects, 635 00:50:16,864 --> 00:50:21,232 通过假设它们都是由小块的基本对象组成的 trying to make simple things by assuming that the pieces they're made out of are simple. 636 00:50:24,608 --> 00:50:25,616 这就是思路 That's what's happening here. 637 00:50:27,824 --> 00:50:33,120 现在如果我们看第一张投影 Well, now, if we look at the first slide-- no, overhead, overhead. 638 00:50:33,888 --> 00:50:37,136 我们看到一个非常复杂的程序 就像我们之前看到的匹配器一样 If we look at the overhead, we see a very complicated program like we saw before for the matcher, 639 00:50:37,536 --> 00:50:39,950 它太复杂了 没有必要仔细阅读它 so complicated that you can't read it like that. 640 00:50:41,920 --> 00:50:43,616 我只想让大家感受一下它的轮廓 I just want you to get the feel of the shape of it, 641 00:50:44,448 --> 00:50:50,016 也就是这个程序里面有很多子程序 and the shape of it is that this program has various subprograms in it. 642 00:50:52,110 --> 00:50:57,568 这部分用于遍历表达式 One of them--this part is the part for traversing the expression, 643 00:50:58,976 --> 00:51:01,360 这部分用于尝试规则 and this part is the part for trying rules. 644 00:51:02,528 --> 00:51:05,600 当然 我们也可以看看细节 Now, of course, we can look at that in some more detail. 645 00:51:06,896 --> 00:51:11,808 来看第一张幻灯片 Let's look at--let's look at the first transparency, right? 646 00:51:13,408 --> 00:51:17,360 化简器由数个部分组成 The simplifier is made out of several parts. 647 00:51:17,968 --> 00:51:22,928 回想一下 化简器接收一系列的规则 Now, remember at the very beginning, the simplifier is the thing which takes a rules-- a set of rules 648 00:51:23,920 --> 00:51:27,200 并生成一个使用该规则进行化简的程序 and produces a program which will simplify it relative to them. 649 00:51:30,048 --> 00:51:32,608 化简器在这里定义 So here we have our simplifier. 650 00:51:33,488 --> 00:51:34,816 接受一个规则集合 It takes a rule set. 651 00:51:36,160 --> 00:51:38,688 在the-rules被定义的上下文中 And in the context where that rule set is defined, 652 00:51:39,248 --> 00:51:41,480 还定义了很多其它东西 there are various other definitions that are done here. 653 00:51:42,336 --> 00:51:46,208 而simplifier过程的返回结果则是 And then the result of this simplifier procedure is, 654 00:51:46,410 --> 00:51:50,800 是一个已经定义好的过程 -- simplify-exp in fact, one of the procedures that was defined. Simplify-exp. 655 00:51:52,464 --> 00:51:57,712 调用 (simplifier the-rules) 的返回值是 What I'm returning as the value of calling the simplifier on a set of rules 656 00:51:58,170 --> 00:52:03,216 返回值是一个过程 是在该上下文中定义的simplify-exp过程 is a procedure the simplify exp procedure, which is defined in that context, 657 00:52:05,232 --> 00:52:08,832 这是一个利用这些给定规则进行化简的过程 which is a simplification procedure appropriate for using those set of rules. 658 00:52:15,040 --> 00:52:15,968 定义就是这样的 That's what I have there. 659 00:52:17,450 --> 00:52:21,792 这些过程的前两个 这个和这个 Now, the first two of these procedures, this one and this one, 660 00:52:22,480 --> 00:52:25,744 它们一起 递归地遍历一个表达式 are together going to be the recursive traversal of an expression. 661 00:52:26,970 --> 00:52:30,208 这个是任何表达式的通用化简方法 This one is the general simplification for any expression, 662 00:52:30,944 --> 00:52:33,230 而这个过程用于化简表达式的子部分 and this is the thing which simplifies a list of parts of an expression. 663 00:52:35,536 --> 00:52:36,080 没别的了 Nothing more. 664 00:52:37,040 --> 00:52:39,904 每个过程中 我们会做些复杂操作 包括尝试这些规则 For each of those, we're going to do something complicated, which involves trying the rules. 665 00:52:40,320 --> 00:52:41,712 现在 我们看看这些过程 Now, we should look at the various parts. 666 00:52:45,760 --> 00:52:48,080 我们先来讨论一下表达式的递归遍历 Well let's look first at the recursive traversal of an expression. 667 00:52:48,576 --> 00:52:51,680 这是用一种很简单的方法完成的 And this is done in a sort of simple way. 668 00:52:54,288 --> 00:52:57,936 这是一个小型的、嵌套的递归过程 This is a little nest of recursive procedures. 669 00:52:59,424 --> 00:53:01,776 这里有两个过程 --- And what we have here are two procedures-- 670 00:53:02,590 --> 00:53:05,200 一个是对整个表达式化简 one for simplifying an expression, 671 00:53:06,112 --> 00:53:08,160 另一个是对表达式的某部分化简 and one for simplifying parts of an expression. 672 00:53:09,440 --> 00:53:10,976 它们的原理都很简单 And the way this works is very simple. 673 00:53:12,128 --> 00:53:16,864 如果我想要化简的表达式是复合表达式 If the expression I'm trying to simplify is a compound expression, 674 00:53:17,040 --> 00:53:18,320 那么就对每一个部分进行化简 I'm going to simplify all the parts of it. 675 00:53:19,950 --> 00:53:22,320 调用simplify-parts这个过程 And that's calling--that procedure, simplify parts, 676 00:53:22,336 --> 00:53:25,740 会构造一个新的表达式 其中各个部分都是化简过的 is going to make up a new expression with all the parts simplified, 677 00:53:26,000 --> 00:53:28,640 我会在这里尝试那些应用规则 which I'm then going to try the rules on over here. 678 00:53:30,860 --> 00:53:34,224 如果表达式不是复合的 而是一些简单的表达式 If it turns out that the expression is not compound, if it's simple, 679 00:53:34,768 --> 00:53:37,130 比如说是符号 或者'pi like just a symbol or something like pi, 680 00:53:38,160 --> 00:53:39,792 无论如何 我都需要尝试应用这些规则 then in any case, I'm going to try the rules on it 681 00:53:40,032 --> 00:53:47,560 因为 因为可能有将pi扩展成3.14159265358979....这样的规则 because it might be that I want in my set of rules to expand pi to 3.14159265358979,dot, dot, dot. 682 00:53:48,464 --> 00:53:49,088 也许我不会这样做 But I may not. 683 00:53:50,112 --> 00:53:51,520 但是没有理由不这样做 But there is no reason not to do it. 684 00:53:52,752 --> 00:53:57,536 现在如果我对表达式的各部分化简 那就很简单了 Now, if I want to simplify the parts, well, that's easy too. 685 00:53:58,990 --> 00:54:02,880 要么表达式是空的 它没有更多的部分了 Either the expression is an empty one, there's no more parts, 686 00:54:03,712 --> 00:54:05,080 这种情况我返回一个空表达式 in which case I have the empty expression. 687 00:54:05,728 --> 00:54:10,528 否则 我用cons构建一个新的表达式 Otherwise, I'm going to make a new expression by cons, 688 00:54:11,216 --> 00:54:14,272 新表达式的car部分是原表达式car的化简结果 which is the result of simplifying the first part of the expression, the car, 689 00:54:15,424 --> 00:54:17,392 然后化简表达式的其它其他部分作为新表达式的cdr部分 and simplifying the rest of the expression, which is the cdr. 690 00:54:21,088 --> 00:54:23,888 我用这种方式向大家展示这些的原因是 Now, the reason why I'm showing you this sort of stuff this way 691 00:54:24,880 --> 00:54:30,128 我想让大家感受到 这些不同模式在编程时非常重要 is because I want you get the feeling for the various patterns that are very important when writing programs. 692 00:54:32,208 --> 00:54:34,000 这段程序我可以换种写法 And this could be written a different way. 693 00:54:34,000 --> 00:54:36,992 还有一种化简表达式的方法 There's another way to write simplified expressions so there would be only one of them. 694 00:54:37,728 --> 00:54:39,630 这仅仅是一个小程序 There would only be one little procedure here. 695 00:54:39,630 --> 00:54:42,368 我把它写到黑板上 让大家感受一下 Let me just write that on the blackboard to give you a feeling for that. 696 00:54:49,712 --> 00:54:51,904 你可以用这种惯用法来写程序 This is in another idiom, if you will. 697 00:54:59,300 --> 00:55:03,136 那么 如何化简表达式exp呢? To simplify an expression called exp, what am I going to do? 698 00:55:03,216 --> 00:55:10,144 在以下几种情况下 调用try-rules I'm going to try the rules on the following situation. 699 00:55:11,120 --> 00:55:15,728 就像之前一样 如果表达式是复合的 If-- on the following expression-- compound, just like we had before. 700 00:55:21,520 --> 00:55:24,272 如果是复合的 我要怎么做呢? If the expression is compound, well, what am I going to do? 701 00:55:24,530 --> 00:55:25,408 我要化简它的每个部分 I'm going to simplify all the parts. 702 00:55:26,010 --> 00:55:27,808 但是我已经有对cdr部分递归的过程了 But I already have a cdr recursion, 703 00:55:30,256 --> 00:55:33,180 一个被封装成高阶过程的通用模式 common pattern of usage, which has been captured as a high-order procedure. 704 00:55:34,096 --> 00:55:34,464 也就是map过程 It's called map. 705 00:55:36,080 --> 00:55:36,880 我在这里写出来 So I'll just write that here. 706 00:55:37,160 --> 00:55:48,032 (map simplify-exp exp) Map simplify the expression, all the parts of the expression. 707 00:55:49,008 --> 00:55:54,592 这是说 把simplify-exp这个过程应用在表达式的每个部分 This says apply the simplification operation, which is this one, every part of the expression, 708 00:55:55,344 --> 00:55:57,344 然后把结果用cons组合成表 and then that cons those up into a list. 709 00:56:00,920 --> 00:56:04,384 所以表中的每个元素都是化简过的 It's every element of the list which the expression is assumed to be made out of, 710 00:56:05,456 --> 00:56:08,230 不是复合表达式的话 就不用化简了 and otherwise, I have the expression. 711 00:56:09,050 --> 00:56:12,368 所以不需要再写一个辅助函数来化简各个部分 So I don't need the helper procedure, simplify parts, 712 00:56:12,640 --> 00:56:13,480 这句代码就够了 because that's really this. 713 00:56:15,472 --> 00:56:17,056 所以有时候可以这样写 So sometimes, you just write it this way. 714 00:56:17,840 --> 00:56:18,704 这个无关紧要 It doesn't matter very much. 715 00:56:21,168 --> 00:56:26,272 好现在看一下 -- 如何尝试规则 Well, now let's take a look at-- let's just look at how you try rules. 716 00:56:27,700 --> 00:56:31,600 这里 幻灯片上有一堆复杂的东西 If you look at this slide, we see this is a complicated mess also. 717 00:56:33,680 --> 00:56:35,280 我要尝试对一个表达式施用规则 I'm trying rules on an expression. 718 00:56:36,368 --> 00:56:39,968 我现在尝试的表达式是最初表达式的子表达式 It turns out the expression I'm trying it on is some subexpression now of the expression I started with. 719 00:56:40,430 --> 00:56:43,888 这是因为我之前特意安排要求遍历所有子表达式 Because the thing I just arranged allowed us to try every subexpression. 720 00:56:46,112 --> 00:56:51,900 所以这里的exp 就是最初表达式的子表达式 So now here we're taking in a subexpression of the expression we started with. That's what this is. 721 00:56:52,496 --> 00:56:57,712 这里我们定义一个scan的过程 它用来尝试每一个规则 And what we're going to define here is a procedure called scan, which is going to try every rule. 722 00:56:58,720 --> 00:57:00,336 我们会在整个规则中扫描 And we're going to start it up on the whole set of rules. 723 00:57:01,920 --> 00:57:07,776 它会通过不断取cdr部分来遍历整个规则 查找一条规则来施用 This is going to go cdr-ing down the rules, if you will, looking for a rule to apply. 724 00:57:09,376 --> 00:57:11,968 当找到一条规则 它的任务就完成了 And when it finds one, it'll do the job. 725 00:57:14,096 --> 00:57:16,416 我们来看一下try-rules是如何工作的 Well, let's take a look at how try rules works. 726 00:57:17,744 --> 00:57:21,024 非常简单:就是顺序地扫描规则表 It's very simple: the scan rules. Scan rules, the way of scanning. 727 00:57:21,968 --> 00:57:23,260 它 真的简单吗? Well, is it so simple? 728 00:57:23,260 --> 00:57:24,512 不 这是个很庞大的程序 It's a big program, of course. 729 00:57:25,552 --> 00:57:28,576 接收的参数是一系列的规则--它们是整个规则表的子表 We take a bunch of rules, which is a sublist of the list of rules. 730 00:57:30,752 --> 00:57:35,136 我们已经查找了其中的一些 但它们都不符合 所以试试剩下的 We've tried some of them already, and they've not been appropriate, so we get to some here. 731 00:57:35,872 --> 00:57:36,304 尝试下一条 next one. 732 00:57:36,400 --> 00:57:37,632 如果所有规则都尝试完了 If there are no more rules, 733 00:57:37,904 --> 00:57:40,848 那么 我就不能再对这个表达式做什么了 它已经是最简了 well then, there's nothing I can do with this expression, and it's simplified. 734 00:57:42,352 --> 00:57:47,264 然而 如果还有规则需要扫描 However, if it turns out that there are still rules to be done, 735 00:57:48,010 --> 00:57:51,584 那么从一个空的词典开始 then let's match the pattern of the first rule 736 00:57:52,208 --> 00:57:55,408 用规则表中的第一条规则对表达式进行模式匹配 against the expression using the empty dictionary to start with 737 00:57:57,072 --> 00:57:58,840 将得到的结果作为新的词典 and use that as the dictionary. 738 00:58:00,320 --> 00:58:03,744 如果失败了 就尝试剩余规则 If that happens to be a failure, try the rest of the rules. 739 00:58:06,688 --> 00:58:07,520 这句代码就是这个意思 That's all it says here. 740 00:58:08,528 --> 00:58:10,336 也就是说 丢弃那条规则 How it says, it says discard that rule. 741 00:58:11,104 --> 00:58:15,056 成功的话 我将取出第一条规则对应的骨架 Otherwise, well, I'm going to get the skeleton of the first rule, 742 00:58:15,344 --> 00:58:17,400 利用得到的词典 来将其实例化 instantiate that relative to the dictionary, 743 00:58:17,936 --> 00:58:20,800 然后对结果化简 就得到了我想要的表达式 and simplify the result, and that's the expression I want. 744 00:58:24,200 --> 00:58:25,968 虽然这是一个复杂的程序 So although that was a complicated program, 745 00:58:26,256 --> 00:58:28,720 但是每个复杂程序都是由许多简单部分组成的 every complicated program is made out of a lot of simple pieces. 746 00:58:29,776 --> 00:58:33,120 这里的递归模式非常复杂 Now, the pattern of recursions here is very complicated. 747 00:58:34,784 --> 00:58:36,528 最重要的事情就是:不要去思考它 And one of the most important things is not to think about that. 748 00:58:38,670 --> 00:58:41,808 如果去思考它的实际行为 If you try to think about the actual pattern by which this does something, 749 00:58:42,064 --> 00:58:42,976 大家就会迷惑 you're going to get very confused. 750 00:58:45,312 --> 00:58:45,712 就算是我也会 I would. 751 00:58:47,040 --> 00:58:50,176 没关系 可以多加练习 This is not a matter. you can do this with practice. 752 00:58:51,520 --> 00:58:52,464 这些模式非常难 These patterns are hard. 753 00:58:54,176 --> 00:58:55,424 但是大家不用考虑它 But you don't have to think about it. 754 00:58:55,830 --> 00:58:59,728 关键点就是 好的编程或设计方法需要 The key to this-- it's very good programming and very good design-- 755 00:58:59,744 --> 00:59:00,976 知道什么是不需要考虑的 is to know what not to think about. 756 00:59:03,056 --> 00:59:06,064 回到这张幻灯片上 The fact is, going back to this slide, 757 00:59:06,928 --> 00:59:08,016 我不需要考虑它 I don't have to think about it 758 00:59:08,544 --> 00:59:13,830 是因为我规定了exp化简后的结果是什么样子 because I have specifications in my mind for what simplify x does. 759 00:59:14,000 --> 00:59:15,248 我不需要知道它是如何做的 I don't have to know how it does it. 760 00:59:17,088 --> 00:59:21,248 它也许是像我们这里 又是scan 又是try-rule And it may, in fact, call scan somehow through try rules, which it does. 761 00:59:22,240 --> 00:59:24,096 又或者在这里调用另一个递归程序 And somehow, I've got another recursion going on here. 762 00:59:24,330 --> 00:59:25,696 根据“按愿望思维” 因为我知道simplify-exp But since I know that simplify exp 763 00:59:26,848 --> 00:59:30,400 它会返回exp化简后的结果 is assumed by wishful thinking to produce the simplified result, 764 00:59:31,616 --> 00:59:32,992 那么我就不需要再考虑它的具体实现了 then I don't have to think about it anymore. 765 00:59:33,430 --> 00:59:34,830 我直接使用它 I've used it. 766 00:59:35,072 --> 00:59:36,430 我合情合理地使用它 I've used it in a reasonable way. 767 00:59:36,430 --> 00:59:37,456 就会得到正确的结果 I will get a reasonable answer. 768 00:59:39,952 --> 00:59:42,576 我们必须学会这种程序设计方法 -- 学会放弃 And you have to learn how to program that way-- with abandon. 769 00:59:47,568 --> 00:59:49,056 这里还有一点剩余 Well, there's very little left of this thing. 770 00:59:50,400 --> 00:59:54,464 这里还有一些词典方面的细节 All there is left is a few details associated with what a dictionary is. 771 00:59:55,080 --> 00:59:58,320 你们想知道到底词典是什么 And those of you who've been itching to know what a dictionary is, 772 00:59:58,704 --> 01:00:01,820 但是我会跳过它 无可奉告 well, I will flip it up and not tell you anything about it. 773 01:00:04,144 --> 01:00:05,200 词典很简单 Dictionaries are easy. 774 01:00:06,016 --> 01:00:09,840 它是用一种被称为关联表的东西来表示的 It's represented in terms of something else called an A list, 775 01:00:10,656 --> 01:00:16,048 这是一种特殊使用模式 用来在线性表中存放二维表 which is a particular pattern of usage for making tables in lists. 776 01:00:16,500 --> 01:00:20,176 它们很简单 由序对构成 之前已经有同学问过了 They're easy. They're made out of pairs, as was asked a bit ago. 777 01:00:21,210 --> 01:00:24,624 有个特殊的过程叫做assq 用来处理这些东西 And there are special procedures for dealing with such things called assq, 778 01:00:24,944 --> 01:00:26,360 手册里面有 and you can find them in manuals. 779 01:00:27,040 --> 01:00:28,592 这个都无关紧要 I'm not terribly excited about it. 780 01:00:28,830 --> 01:00:31,216 重要的是如何扩充词典 The only interesting thing here in extend dictionary 781 01:00:31,480 --> 01:00:36,944 要用一个模式、模式对应的数据、一本旧词典来扩充 is I have to extend the dictionary with a pattern, a datum, and a dictionary. 782 01:00:37,424 --> 01:00:42,384 这个模式pat 实际上是一个模式变量 I wish that, this pattern is, in fact, at this point a pattern variable. 783 01:00:43,744 --> 01:00:47,536 我要做什么呢?我先从模式中取出模式变量的名字 And what do I want to do? I want to pull out the name of that pattern variable 784 01:00:48,160 --> 01:00:49,424 把它赋给变量name the pattern variable name, 785 01:00:50,448 --> 01:00:53,712 然后我按照这个名字在词典中查找是否有对应的值 and I'm going to look up in the dictionary and see if it already has a value. 786 01:00:53,792 --> 01:00:56,416 如果没有 就将这对新的模式-值加入到词典中 If not, I'm going to add a new one in. 787 01:00:56,928 --> 01:00:59,232 如果已经存在一个这样名字的词条 并且有值 If it does have one, if it has a value, 788 01:00:59,600 --> 01:01:03,184 那dat的值最好跟已经存储的值相等 then it had better be equal to the one that was already stored away. 789 01:01:03,888 --> 01:01:06,544 这是我心目中期待的情况 And if that's the case, the dictionary is what I expected it to be. 790 01:01:06,896 --> 01:01:09,152 否则 置失败 Otherwise, I fail. 791 01:01:12,080 --> 01:01:12,896 所以它也很简单 So that's easy, too. 792 01:01:13,664 --> 01:01:16,688 打开任何一个程序 你会发现它们都是由数个个小部分组成 If you open up any program, you're going to find inside of it lots of little pieces, 793 01:01:17,184 --> 01:01:18,304 许多简单的小部分 all of which are easy. 794 01:01:20,048 --> 01:01:21,296 我想 到目前为止 So at this point, I suppose, 795 01:01:21,600 --> 01:01:25,680 我已经告诉给你们价值百万的信息了 I've just told you some million-dollar valuable information. 796 01:01:28,416 --> 01:01:30,960 我想这个程序几乎已经讲完了 And I suppose at this point we're pretty much done with this program. 797 01:01:31,856 --> 01:01:32,720 有什么问题么? I'd like to ask about questions. 798 01:01:34,272 --> 01:01:38,160 学生:你描述一下 化简后的表达式的规范么? AUDIENCE: Yes, can you give me the words that describe the specification for a simplified expression? 799 01:01:38,720 --> 01:01:39,024 教授:好的 PROFESSOR: Sure. 800 01:01:39,856 --> 01:01:44,336 simplify-exp接收一个表达式 返回一个化简后的表达式 A simplified expression takes an expression and produces a simplified expression. 801 01:01:45,280 --> 01:01:45,776 就是这样了 That's it, OK? 802 01:01:48,112 --> 01:01:50,272 它的工作方式很简单 How it does it is very easy. 803 01:01:51,600 --> 01:01:56,096 对于复合表达式 先化简各部分后 再尝试化简整体 In compound expressions, all the pieces are simplified, and then the rules are tried on the result. 804 01:01:56,896 --> 01:01:58,496 原子表达式 就直接代规则化简 And for simple expressions, you just try all the rules. 805 01:01:59,520 --> 01:02:02,112 学生:是这些规则把表达式化简了么? AUDIENCE: So an expression is simplified by virtue of the rules? 806 01:02:02,768 --> 01:02:03,584 教授:当然 PROFESSOR: That's, of course, true. 807 01:02:03,760 --> 01:02:03,904 学生:好 AUDIENCE: Right. 808 01:02:04,064 --> 01:02:07,136 教授:它们像你在这里看到的一样化简表达式 PROFESSOR: And the way this works is that simplified expression, as you see here, 809 01:02:08,352 --> 01:02:11,648 它先把表达式划分为小块 what it does is it breaks the expression down into the smallest pieces, 810 01:02:12,608 --> 01:02:17,296 在化简器中使用这些规则 自下而上化简并构造表达式 simplifies building up from the bottom using the rules to be the simplifier, 811 01:02:18,304 --> 01:02:22,480 处理它们 构造一个新的表达式作为结果 to do the manipulations, and constructs a new expression as the result. 812 01:02:24,288 --> 01:02:29,440 最后再尝试调用这些规则化简 Eventually, one of things you see is that the rules themselves, the try rules, 813 01:02:29,700 --> 01:02:35,504 当匹配的结果发生变化时 -- 就调用simplify-exp化简它 call a simplified expression on the results when it changes something, the results of a match. 814 01:02:35,800 --> 01:02:40,640 哦 不对是 骨架的实例化结果发生改变时 I'm sorry, the results of instantiation of a skeleton for a rule that has matched. 815 01:02:42,000 --> 01:02:47,360 所以 规范就是 任何传入的表达式通过这些规则生成化简后的表达式 So the spec of a simplified expression is that any expression you put into it comes out simplified according to those rules. 816 01:02:49,840 --> 01:02:50,768 谢谢大家 下课 Thank you. Let's take a break. ================================================ FILE: SrtCN/lec4b.srt ================================================ 1 00:00:00,000 --> 00:00:02,256 Learning-SICP学习小组 倾情制作 2 00:00:02,320 --> 00:00:03,536 翻译&&时间轴:刘殊君(rtmagic) 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:03,552 --> 00:00:04,240 特别感谢:裘宗燕教授 4 00:00:04,330 --> 00:00:10,352 计算机程序的构造和解释 5 00:00:11,400 --> 00:00:16,500 通用运算符 Generic Operators 6 00:00:20,180 --> 00:00:21,840 教授:到目前为止 我们已经进行了很多 PROFESSOR: So far in this course we've been talking 7 00:00:21,840 --> 00:00:23,780 关于数据抽象的讨论 a lot about data abstraction. 8 00:00:23,780 --> 00:00:27,150 关键理念就是在构造系统的时候 And remember the idea is that we build systems 9 00:00:27,740 --> 00:00:32,560 在其中加入水平的抽象屏障 这些抽象屏障 that have these horizontal barriers in them, these abstraction barriers 10 00:00:33,420 --> 00:00:39,210 把你使用一个数据对象的方式 that separate use, the way you might use some data object, 11 00:00:39,930 --> 00:00:41,180 和表示它的方式区分开来 from the way you might represent it. 12 00:00:49,400 --> 00:00:52,030 或者可以这样理解它 在上层有一个老板 Or another way to think of that is up here you have the boss 13 00:00:52,110 --> 00:00:55,500 想要调用某种数据对象 who's going to be using some sort of data object. 14 00:00:57,110 --> 00:01:02,310 而在下层 George负责它的具体实现 And down here is George who's implemented it. 15 00:01:02,310 --> 00:01:05,420 这种把使用与表示分离的想法 Now this notion of separating use from representation 16 00:01:05,440 --> 00:01:09,760 可以让你分开考虑这两个问题 so you can think about these two problems separately 17 00:01:10,600 --> 00:01:14,760 这是一种非常强大的编程的方法论 -- 数据抽象 is a very,very powerful programming methodology, data abstraction. 18 00:01:15,930 --> 00:01:18,810 但另一方面 数据抽象在那些真正复杂的系统上 On the other hand, it's not really sufficient 19 00:01:19,560 --> 00:01:21,840 并不是很有效 for really complex systems. 20 00:01:22,960 --> 00:01:27,648 这个问题就出在George这里 And the problem with this is George. 21 00:01:28,640 --> 00:01:32,090 或者说 实际上 问题就在于 Or actually, the problem is that 22 00:01:32,090 --> 00:01:32,780 现在有太多的George there are a lot of Georges. 23 00:01:34,630 --> 00:01:35,390 具体地说 Let's be concrete. 24 00:01:35,390 --> 00:01:39,180 假设现在有George和Martha两个人 Let's suppose there is George,and there's also Martha. 25 00:01:41,190 --> 00:01:44,220 他们都是这个系统的开发人员 OK, now George and Martha are both working on this system, 26 00:01:46,040 --> 00:01:47,290 都在设计数据的表示方法 both designing representations, 27 00:01:48,410 --> 00:01:50,670 而且他们完全合不来 and absolutely are incompatible. 28 00:01:51,750 --> 00:01:53,620 他们不会合作开发同一种表示方法 They wouldn't cooperate on a representation 29 00:01:54,010 --> 00:01:55,340 永远也不会 under any circumstances. 30 00:01:57,480 --> 00:01:59,720 现在的问题是 假设你想要这样一个系统 And the problem is you would like to have some system 31 00:02:00,060 --> 00:02:02,600 在这个系统中George和Martha都为它设计了数据表示方法 where both George and Martha are designing representations, 32 00:02:03,820 --> 00:02:08,080 但是如果你在高于这个抽象屏障的层面思考 and, yet, if you're above this abstraction barrier 33 00:02:09,400 --> 00:02:11,040 你就不用去操心这些事情 you don't want to have to worry about that, 34 00:02:11,660 --> 00:02:14,180 不用操心 某个东西是到底是George做的还是Martha做的 whether something is done by George or by Martha. 35 00:02:14,180 --> 00:02:15,430 同时你也不想让George和Martha And you don't want George and Martha to 36 00:02:15,430 --> 00:02:16,480 妨碍彼此的工作 interfere with each other. 37 00:02:16,630 --> 00:02:20,310 你在设计系统的时候 不仅仅需要这些 Somehow in designing a system, you not only want these 38 00:02:20,310 --> 00:02:23,840 水平的抽象屏障 同时也想设置一道 horizontal barriers, but you also want some kind of 39 00:02:25,824 --> 00:02:30,640 垂直的屏障 -- 来把George和Martha分离开 some kind of vertical barrier to keep George and Martha separate. 40 00:02:32,980 --> 00:02:35,400 我们来说得再具体一点 Let me be a little bit more concrete. 41 00:02:36,560 --> 00:02:40,540 想象一个很大的公司的人事记录 Imagine that you're thinking about personnel records 42 00:02:41,180 --> 00:02:46,110 这个公司里有很多部门没什么联系 for a large company with a lot of loosely linked divisions 43 00:02:47,900 --> 00:02:49,710 并且部门之间合作得也不太好 that don't cooperate very well either. 44 00:02:50,430 --> 00:02:57,040 甚至还可以想象这个大公司就是由 And imagine even that this company is formed by merging a 45 00:02:57,040 --> 00:02:59,450 很多公司组成的 而且每个公司 whole bunch of companies that already have their personnel 46 00:02:59,450 --> 00:03:00,700 都有自己的一套人事记录 record system set up. 47 00:03:03,250 --> 00:03:06,570 想象一下突然有一天 这些部门 And imagine that once these divisions are all linked in 48 00:03:06,570 --> 00:03:08,530 被一种神奇的卫星网络连接起来 some kind of very sophisticated satellite 49 00:03:08,530 --> 00:03:10,520 它们各自的数据库都被放到了一起 network, and all these databases are put together. 50 00:03:12,240 --> 00:03:13,850 现在你想要 And what you'd like to do 51 00:03:14,840 --> 00:03:16,330 在公司的任何地方 is from any place in the company, 52 00:03:17,260 --> 00:03:23,130 都能够知道 哦 某一条人事记录里的 to be able to say things like,oh, what's the name in a 53 00:03:23,130 --> 00:03:23,870 “姓名”是什么 personnel record? 54 00:03:26,300 --> 00:03:29,150 或者一条记录里的“工作”是什么 Or, what's the job description in a personnel record? 55 00:03:30,540 --> 00:03:34,400 同时又不需要担心每一个部门 And not have to worry about the fact that each division 56 00:03:34,840 --> 00:03:36,760 对于人事记录的格式 obviously is going to have completely separate 57 00:03:36,760 --> 00:03:39,370 有着完全不同的习惯 conventions for how you might implement these records. 58 00:03:41,580 --> 00:03:43,260 从你的视角上你不想去了解这些东西 From this point you don't want to know about that. 59 00:03:44,960 --> 00:03:47,920 那么怎么才能做到这样呢? Well how could you possibly do that? 60 00:03:48,430 --> 00:03:52,410 当然 一种方法是下发一个告示 One way, of course, is to send down an edict from somewhere 61 00:03:52,640 --> 00:03:56,290 来通知所有人把他们的记录格式 that everybody has to change their format to some fixed 62 00:03:56,290 --> 00:03:57,240 都改成某种标准的格式 compatible thing. 63 00:03:58,070 --> 00:04:00,120 人们经常这样做 但都没有成功 That's what people often try, and of course it never works. 64 00:04:01,820 --> 00:04:07,340 另一个办法则是重新安排这些记录 Another thing that you might want to do is somehow arrange 65 00:04:08,330 --> 00:04:09,900 让它们中间有这种垂直的抽象屏障 it so you can have these vertical barriers. 66 00:04:11,250 --> 00:04:14,400 当你查询一份人事档案里的姓名的时候 So that when you ask for the name of a personnel record, 67 00:04:14,430 --> 00:04:17,970 不管它是什么格式 name这个过程都能设法 somehow, whatever format it happens to be, name will 68 00:04:17,970 --> 00:04:19,420 搞清楚怎么正确地完成这件事 figure out how to do the right thing. 69 00:04:22,730 --> 00:04:25,530 我们把name叫做一个 所谓的“通用运算符” We want name to be, so-called, a generic operator. 70 00:04:26,260 --> 00:04:30,060 通用运算符意味着它会根据数据的种类 Generic operator means what it sort of precisely does depends 71 00:04:30,060 --> 00:04:31,690 准确地做出对应的操作 on the kind of data that it's looking at. 72 00:04:33,650 --> 00:04:36,620 更进一步讲 你想让这个系统在 More than that, you'd like to design the system so that the 73 00:04:36,920 --> 00:04:39,790 下次公司里多了一个新的人员划分的时候 next time a new division comes into the company 74 00:04:42,510 --> 00:04:45,640 人们连接系统的方法不会有很大的变化 they don't have to make any big changes in what they're already doing 75 00:04:45,640 --> 00:04:50,110 并且公司里剩下的部门 to link into this system, and the rest of the company 76 00:04:50,110 --> 00:04:52,010 要把它们的人员记录添加到这个系统 doesn't have to make any big changes 77 00:04:52,270 --> 00:04:53,930 也不需要做什么大的修改 to admit their stuff to the system. 78 00:04:55,520 --> 00:04:57,520 那么这就是你应该考虑的问题 So that's the problem you should be thinking about. 79 00:04:58,700 --> 00:05:00,770 或者这就是你的工作 Like it's sort of just your work. 80 00:05:00,770 --> 00:05:03,776 要让系统可以用最少的改动来拥抱变化 You want to be able to include new things by making minimal changes. 81 00:05:05,980 --> 00:05:08,120 这就是我们今天要讨论的问题 OK, well that's the problem that we'll be talking about today. 82 00:05:09,440 --> 00:05:14,220 你脑子里应该有这个分布式的人事档案系统 And you should have this sort of distributed personnel record system in your mind. 83 00:05:14,240 --> 00:05:16,620 但是实际上 我今天要讨论的是一个 But actually the one I'll be talking about is a problem 84 00:05:16,620 --> 00:05:18,480 比那要更加自成体系的问题 that's a little bit more self-contained than that. 85 00:05:19,290 --> 00:05:21,760 我觉得用它可以把事情说得更清楚一点 that'll bring up the issues, I think, more clearly. 86 00:05:21,870 --> 00:05:26,010 我们要讨论的是 复数域上的算术系统 That's the problem of doing a system that does arithmetic on complex numbers. 87 00:05:27,770 --> 00:05:28,920 我们来看看这个系统 So let's take a look here. 88 00:05:30,690 --> 00:05:31,744 来复习一下 Just as a little review, 89 00:05:32,048 --> 00:05:33,530 什么是“复数” there are things called complex numbers. 90 00:05:35,250 --> 00:05:38,220 复数z可以看做复平面上的一点 Complex number you can think of as a point in the plane, or z. 91 00:05:39,370 --> 00:05:47,190 我们将复数表示为实数部分和虚数部分 And you can represent a point either by its real-part and its imaginary-part. 92 00:05:47,190 --> 00:05:50,830 所以如果这个是复数z 它的实部是这么多 So if this is z and its real-part is this much, 93 00:05:51,500 --> 00:05:53,240 它的虚部是那么多 and its imaginary-part is that much, 94 00:05:54,330 --> 00:05:56,440 我们就可以记z=x+iy and you write z equals x plus iy. 95 00:05:59,110 --> 00:06:03,210 还有另一种方法来表示一个复数 比如说 Or another way to represent a complex number is by saying, 96 00:06:03,210 --> 00:06:09,000 这个点与原点的距离是多少 在原点的什么角度上 what's the distance from the origin, and what's the angle? 97 00:06:11,320 --> 00:06:16,670 像这样 复数也可以表示为半径乘以一个角度 So that represents a complex number as its radius times an angle. 98 00:06:19,520 --> 00:06:21,920 第一种表示法称为 直角坐标系表示 This one's called -- the original one's called rectangular form, 99 00:06:22,590 --> 00:06:25,456 或者说实部-虚部表示 rectangular representation, real- and imaginary-part 100 00:06:26,208 --> 00:06:30,040 而后一种是用模和辐角两部分的极坐标表示 or polar representation magnitude and angle-- 101 00:06:30,040 --> 00:06:31,480 并且如果你知道了一个复数的实部和虚部 and if you know the real- and imaginary-part, 102 00:06:31,530 --> 00:06:33,360 你就能计算出它的模和辐角 you can figure out the magnitude and angle. 103 00:06:33,720 --> 00:06:36,970 如果知道了x和y 就能用这个式子算出r If you know x and y, you can get r by this formula. 104 00:06:37,190 --> 00:06:39,480 等于两个数平方和的平方根 然后就可以 Square root of sum of the squares, and you can get the 105 00:06:39,480 --> 00:06:40,760 用反三角函数算出辐角的值 angle as an arctangent. 106 00:06:41,420 --> 00:06:44,420 或者反过来 如果你知道了r和A Or conversely, if you knew r and A you could 107 00:06:44,420 --> 00:06:45,310 你也能计算出x和y figure out x and y. 108 00:06:45,800 --> 00:06:49,430 x=r·cos(A) y=r·sin(A) x is r times the cosine of A, and y is r times the sine of A. 109 00:06:51,340 --> 00:06:53,660 这是表示复数的两种不同方法 All right, so there's these two. They're complex numbers. 110 00:06:54,130 --> 00:06:57,150 分别是极坐标形式和直角坐标形式 You can think of them either in polar form or rectangular form. 111 00:06:57,150 --> 00:06:58,128 我们要设计的是 What we would like to do 112 00:06:58,320 --> 00:07:01,328 一个复数域上的算术系统 is make a system that does arithmetic on complex numbers. 113 00:07:03,952 --> 00:07:05,120 换句话讲 我们要 In other words, what we'd like-- 114 00:07:05,580 --> 00:07:06,990 就像之前课上有理数运算的例子一样 just like the rational number example-- 115 00:07:07,380 --> 00:07:10,208 是构造一个叫做+c的操作 is to have some operations plus c, 116 00:07:10,736 --> 00:07:13,904 它将两个复数然后把它们相加、相减 which is going to take two complex numbers and add them, subtract them, 117 00:07:14,352 --> 00:07:16,944 相乘或者相除 and multiply them, and divide them. 118 00:07:20,730 --> 00:07:25,280 那么我们要用到一点点数学 OK, well there's little bit of mathematics behind it. 119 00:07:25,280 --> 00:07:28,360 对它们进行操作的具体的算式是什么 What are the actual formulas for manipulating such things? 120 00:07:30,410 --> 00:07:31,920 它们是怎么得出来的 并不重要 And it's sort of not important where they come from, 121 00:07:34,000 --> 00:07:35,790 我们只是用它们实现运算 but just as an implementer let's see-- 122 00:07:35,800 --> 00:07:37,950 如果想要把两个复数相加 if you want to add two complex numbers it's pretty easy to 123 00:07:39,130 --> 00:07:42,660 可以很容易地获取它们的实部和虚部 it's pretty easy to get its real-part and its imaginary-part. 124 00:07:42,660 --> 00:07:45,930 两个复数的和的实部 The real-part of the sum of two complex numbers 125 00:07:47,720 --> 00:07:49,728 z1+z2的实部 real-part of the z1 plus z2 126 00:07:50,064 --> 00:07:54,640 就是z1的实部加上z2的实部 is the real-part of z1 plus the real-part of z2. 127 00:07:57,820 --> 00:08:01,600 然后z1+z2的虚部也就是 And the imaginary-part of z1 plus z2 128 00:08:01,744 --> 00:08:05,664 z1的虚部加上z2的虚部 is the imaginary part of z1 plus the imaginary part of z2. 129 00:08:07,410 --> 00:08:09,480 所以复数相加是非常简单的事情 So it's pretty easy to add complex numbers. 130 00:08:09,480 --> 00:08:10,992 你只要把各个部分分别加起来 You just add the corresponding parts 131 00:08:11,310 --> 00:08:13,180 然后用结果构建一个新的复数 and make a new complex number with those parts. 132 00:08:13,370 --> 00:08:14,736 如果你想要让复数相乘 If you want to multiply them, 133 00:08:15,536 --> 00:08:17,820 那么在极坐标下运算会方便很多 it's kind of nice to do it in polar form. 134 00:08:17,820 --> 00:08:20,384 因为对于两个复数 Because if you have two complex numbers, 135 00:08:20,400 --> 00:08:26,540 两复数积之模 就是它们各自的模的乘积 the magnitude of their product is here, the product of the magnitudes. 136 00:08:28,850 --> 00:08:33,880 它们的积的辐角 就是两个辐角的和 And the angle of the product is the sum of the angles. 137 00:08:35,800 --> 00:08:40,540 这就是复数域上的运算所需的数学知识 So that's sort of mathematics that allows you to do arithmetic on complex numbers. 138 00:08:40,540 --> 00:08:42,380 我们来想一想具体的实现 Let's actually think about the implementation. 139 00:08:43,720 --> 00:08:47,390 我们就像之前运算有理数那样做 Well we do it just like rational numbers. 140 00:08:49,840 --> 00:08:53,470 来到底层 假设有一些构造函数和选择函数 We come down, we assume we have some constructors and selectors. 141 00:08:53,760 --> 00:08:54,528 它们应该是什么样子呢 What would we like? 142 00:08:55,330 --> 00:08:58,160 假设我们制造了一些表示数据对象的“云彩” Well let's assume that we make a data object cloud, 143 00:08:58,540 --> 00:09:00,780 也就是用某种形式表示的复数 which is a complex number that has some stuff in it, 144 00:09:01,790 --> 00:09:04,670 我们能从这个复数中得到它的实部 and that we can get out from a complex number the real-part, 145 00:09:05,520 --> 00:09:09,640 可以获得 虚部、模、或者辐角 or the imaginary-part, or the magnitude, or the angle. 146 00:09:12,150 --> 00:09:14,010 然后我们需要一种方法来构造复数 We want some ways of making complex numbers-- 147 00:09:14,030 --> 00:09:15,640 不仅要有选择函数 还要有构造函数 not only selectors, but constructors. 148 00:09:16,800 --> 00:09:19,520 那么假设我们有一个叫做make-rectangular的过程 So we'll assume we have a thing called make-rectangular. 149 00:09:19,530 --> 00:09:24,270 这个过程的功能是接受一个实部 What make-rectangular is going to do is take a real-part and 150 00:09:24,510 --> 00:09:29,360 和一个虚部 然后把这两个部分组合成一个复数 an imaginary-part and construct a complex number with those parts. 151 00:09:31,920 --> 00:09:35,010 同样我们也可以构造一个make-polar过程 Similarly, we can have make-polar which will taking 152 00:09:35,010 --> 00:09:37,850 它接受一个模和一个辐角 a magnitude and an angle, 153 00:09:40,830 --> 00:09:43,900 然后用这两个值 组成一个复数 and construct a complex number which has that magnitude and angle. 154 00:09:44,680 --> 00:09:45,460 那么这个系统 So here's a system. 155 00:09:45,460 --> 00:09:47,770 里面会有两个构造函数和四个选择函数 We'll have two constructors and four selectors. 156 00:09:48,910 --> 00:09:55,150 现在 就像之前课程中那样 我们基于这个抽象的数据结构 And now, just like before, in terms of that abstract data 157 00:09:55,150 --> 00:09:59,220 继续实现复数的各种运算 we'll go ahead and implement our complex number operations. 158 00:09:59,220 --> 00:10:02,300 而这些Lisp代码 And here you can see translated into Lisp code 159 00:10:03,230 --> 00:10:07,470 是从我之前写的算术公式“翻译”而来的 just the arithmetic formulas I put down before. 160 00:10:08,060 --> 00:10:09,980 如果我想把两个复数相加 If I want to add two complex numbers 161 00:10:11,760 --> 00:10:15,560 我就要用一个实部和一个虚部构造一个复数 I will make a complex number out of its real- and imaginary-parts. 162 00:10:16,720 --> 00:10:19,024 这个新的复数的实部是 The real part of the complex number I'm going to make 163 00:10:19,408 --> 00:10:21,800 两个复数的实部的和 is the sum of the real-parts. 164 00:10:23,310 --> 00:10:25,376 它的虚数部分是 The imaginary part of the complex number I'm going to make 165 00:10:25,408 --> 00:10:27,520 两个复数的虚部的和 is the sum of the imaginary-parts. 166 00:10:30,310 --> 00:10:32,090 我把它们放到一起 构造出一个复数 I put those together, make a complex number. 167 00:10:32,160 --> 00:10:34,440 这就是实现复数加法的方法 That's how I implement complex number addition. 168 00:10:35,780 --> 00:10:38,490 减法实际上是一样的 Subtraction is essentially the same. 169 00:10:39,650 --> 00:10:42,970 只需要把各个部分相加变成把它们相减 All I do is subtract the parts rather than add them. 170 00:10:45,140 --> 00:10:47,072 要把两个复数相乘 To multiply two complex numbers, 171 00:10:47,740 --> 00:10:49,020 要用另外一个式子 I use the other formula. 172 00:10:49,270 --> 00:10:53,840 我会用一个模和一个辐角来构造一个复数 I'll make a complex number out of a magnitude and angle. 173 00:10:55,350 --> 00:10:56,448 z1*z2的模 The magnitude 174 00:10:56,656 --> 00:11:00,970 就是z1的模乘以z2的模 is going to be the product of the magnitudesof the two complex numbers I'm multiplying. 175 00:11:03,710 --> 00:11:05,936 而z1*z2的辐角则是 And the angle is going to be the sum 176 00:11:06,160 --> 00:11:08,510 z1的辐角加上z2的辐角 of the angles of the z1two complex numbers I'm multiplying. 177 00:11:09,620 --> 00:11:10,960 那么这就是乘法的实现 So there's multiplication. 178 00:11:11,230 --> 00:11:12,256 然后是除法 And then division, 179 00:11:14,272 --> 00:11:15,904 除法和乘法几乎是一样的 division is almost the same. 180 00:11:17,370 --> 00:11:19,580 我只要把两个模相除 把辐角相减就可以了 Here I divide the magnitudes and subtract the angles. 181 00:11:28,360 --> 00:11:30,460 现在我已经实现了各种运算 Now I've implemented the operations. 182 00:11:31,870 --> 00:11:33,640 然后我们做什么 And what do we do? 183 00:11:33,640 --> 00:11:34,520 我们把George叫来 We call on George. 184 00:11:36,060 --> 00:11:38,790 我们完成了“使用”的部分 现在应该考虑“表示”了 We've done the use, let's worry about the representation. 185 00:11:38,800 --> 00:11:40,940 我们叫来George然后对他说 We'll call on George and say to George, 186 00:11:40,970 --> 00:11:43,610 “为我们设计一个一套复数的表示方法” go ahead and build us a complex number representation. 187 00:11:45,250 --> 00:11:47,440 很好 Well that's fine...ahhh 188 00:11:47,770 --> 00:11:52,660 George可能会说 我们把一个复数 George can say, we'll implement a complex number 189 00:11:52,660 --> 00:11:57,150 实现为 一个由实部和虚部组成的序对 simply as a pair that has the real-part and the imaginary-part. 190 00:11:57,200 --> 00:12:02,620 那么如果我想用某个实部和虚部来构造复数 So if I want to make a complex number with a certain real-part and an imaginary-part, 191 00:12:03,360 --> 00:12:05,552 我只需要把它们cons起来即可 这样可以-- I'll just use cons to form a pair, and that will-- 192 00:12:06,032 --> 00:12:08,110 这就是George表示复数的方法 that's George's representation of a complex number. 193 00:12:09,780 --> 00:12:12,420 那么如果我想获得它的实部 我只需要 So if I want to get out the real-part of something, I just 194 00:12:12,420 --> 00:12:14,120 提取出序对的car部分 -- 它的首部分 extract the car, the first part. 195 00:12:14,350 --> 00:12:16,670 如果我想要得到虚部 我就提取出它的cdr部分 If I want to get the imaginary-part, I extract the cdr 196 00:12:19,640 --> 00:12:21,770 那对于模和辐角 又该如何取得呢? How do I deal with the magnitude and angle? 197 00:12:22,220 --> 00:12:25,750 如果我想取得某个复数的模 Well if I want to extract the magnitude of one of these things 198 00:12:25,750 --> 00:12:32,300 我需要计算该复数car与cdr的平方和的算术平方根 I get the square root of the sum of the square of the car plus the square of the cdr. 199 00:12:33,790 --> 00:12:39,260 如果我想得到辐角 我就计算它的cdr与car比值的反正切 If I want to get the angle, I compute the arctangent of the cdr in the car. 200 00:12:39,530 --> 00:12:42,860 这个Lisp过程用于计算反正切 This is a lisp procedure for computing arctangent. 201 00:12:44,970 --> 00:12:48,590 要是有人给我一个模和辐角 And if somebody hands me a magnitude and an angle 202 00:12:48,940 --> 00:12:50,560 并说:“给我构造一个复数” and says, make me a complex number,well I compute the 203 00:12:50,890 --> 00:12:56,240 用它们计算出实部 r*cos(a) 和虚部 r*sin(a) well I compute the real-part and the imaginary-part, r * cosine of a and r * sine of a, 204 00:12:57,770 --> 00:12:59,050 连接成一个序对就行了 and stick them together into a pair. 205 00:13:01,460 --> 00:13:02,260 完成了 OK so we're done. 206 00:13:02,260 --> 00:13:04,750 实际上我做的事情 在概念上讲 In fact, what I just did, conceptually, 207 00:13:06,890 --> 00:13:09,376 和我们之前提过的有理数的表示 is absolutely no different from the rational number 208 00:13:10,608 --> 00:13:12,440 是完全没有区别的 representation that we looked at last time. 209 00:13:12,750 --> 00:13:13,910 它们的思想相同 It's the same sort of idea. 210 00:13:13,910 --> 00:13:16,280 实现具体过程 选择一种表示方法 You implement the operators, you pick a representation. 211 00:13:18,070 --> 00:13:18,650 没有什么不同 Nothing different. 212 00:13:20,070 --> 00:13:21,560 现在我们来关心一下Martha Now let's worry about Martha. 213 00:13:23,210 --> 00:13:24,520 嗯 Martha的想法不太一样 See, Martha has a different idea. 214 00:13:26,670 --> 00:13:28,576 她不想把复数表示成 She doesn't want to represent a complex number 215 00:13:28,592 --> 00:13:30,900 由实部和虚部组成的序对 as a pair of a real-part and an imaginary-part. 216 00:13:30,900 --> 00:13:34,170 她比较喜欢把它们表示成 What she would like to do is represent a complex number as 217 00:13:34,170 --> 00:13:37,690 由模和辐角组成的序对 a pair of a magnitude and an angle. 218 00:13:39,550 --> 00:13:42,130 那么如果我们没有让George而是让Martha So if instead of calling up George we ask Martha to design 219 00:13:42,130 --> 00:13:43,740 来设计复数的表示方法 我们就会得到这样的东西 our representation, we get something like this. 220 00:13:44,570 --> 00:13:47,160 有一个make-polar过程 We get make-polar. 221 00:13:47,160 --> 00:13:50,220 当然了 有了一个模和一个辐角之后 Sure, if I give you a magnitude and an angle we're 222 00:13:50,220 --> 00:13:53,070 我们只要把它们组合成一个序对就行了 just going to form a pair that has magnitude and angle. 223 00:13:55,430 --> 00:13:57,680 如果你想取得复数的模 那很简单 If you want to extract the magnitude, that's easy. 224 00:13:58,240 --> 00:13:59,370 你只需要取序对的car部分即可 You just pull out the car or the pair. 225 00:13:59,780 --> 00:14:02,670 当然 想取得复数的辐角 那也很简单 If you want to extract the angle, sure, that's easy. 226 00:14:02,670 --> 00:14:03,630 只需取cdr部分即可 You just pull out the cdr. 227 00:14:04,810 --> 00:14:07,020 但是如果你想要获得实部和虚部 If you want to look for real-parts and imaginary-parts, 228 00:14:07,420 --> 00:14:08,490 那就得费点力气 well then you have to do some work. 229 00:14:08,880 --> 00:14:14,580 想得到实部 你就得计算r*cos(a) If you want the real-part, you have to get r cosine a. 230 00:14:14,580 --> 00:14:19,990 换句话讲 用序对的car部分去乘以 In other words, r, the car of the pair, times the cosine of 231 00:14:19,990 --> 00:14:20,950 cdr部分的余弦值 the cdr of the pair. 232 00:14:20,950 --> 00:14:26,230 然后你就算出了r*cos(a) So this is r times the cosine of a, 233 00:14:26,540 --> 00:14:27,480 这就是这个复数的实部 and that's the real-part. 234 00:14:28,330 --> 00:14:31,400 要是想算出它的虚部 用r乘以sin(a)就可以了 If you want to get the imaginary-part, it's r times the sine of a. 235 00:14:32,660 --> 00:14:37,930 现在如果我给你一个实部和虚部 然后说 And if I hand you a real-part and an imaginary-part and say, 236 00:14:37,930 --> 00:14:42,030 用它们给我构造一个复数 make me a complex number with that real-part and 237 00:14:42,030 --> 00:14:44,170 那就要先算出 imaginary-part, well I figure out what the magnitude and 238 00:14:44,170 --> 00:14:45,540 模和辐角是多少 angle should be. 239 00:14:45,540 --> 00:14:47,850 模是实部和虚部的平方和的算术平方根 The magnitude's the square root of the sum of the squares 240 00:14:48,090 --> 00:14:49,230 辐角是这个反正切 and the angle's the arctangent. 241 00:14:49,230 --> 00:14:50,220 我用这两个数构造一个序对 I put those together to make a pair. 242 00:14:52,090 --> 00:14:54,170 以上就是Martha的想法 So there's Martha's idea. 243 00:14:56,690 --> 00:14:57,370 那么哪种比较好呢? Well which is better? 244 00:14:59,680 --> 00:15:03,150 如果你需要做很多加法 那么George的比较好 Well if you're doing a lot of additions, probably George's is better 245 00:15:03,160 --> 00:15:05,610 因为你总是要用到复数的实部和虚部 is better, because you're doing a lot of real-parts and imaginary-parts. 246 00:15:05,850 --> 00:15:08,400 如果你大多数时间都是在做乘法 If mostly you're going to be doing multiplications and divisions, 247 00:15:09,480 --> 00:15:11,140 那可能Martha的办法就要好一些 then maybe Martha's idea is better. 248 00:15:11,140 --> 00:15:14,840 又或者 -- 这就是问题所在了 -- 你决定不了 Or maybe, and this is the real point, you can't decide. 249 00:15:16,590 --> 00:15:22,320 或者出于某些个人原因 你想让它们同时存在 Or maybe you just have to let them both hang around, for personality reasons. 250 00:15:23,480 --> 00:15:26,760 也可能你是真的无法决定你更喜欢哪种表示法 Maybe you just really can't ever decide what you would like. 251 00:15:28,560 --> 00:15:32,320 回到这个话题 我们真正想要的是这样一个系统 And again, what we would really like is a system that looks like this. 252 00:15:32,650 --> 00:15:36,170 这里面 既有George 他实现了 That somehow there's George over here, who has built 253 00:15:36,830 --> 00:15:39,640 复数的直角坐标表示 rectangular complex numbers. 254 00:15:41,470 --> 00:15:44,250 又有Martha 她实现了复数的极坐标表示 And Martha, who has polar complex numbers. 255 00:15:46,120 --> 00:15:49,696 然后我们有各种运算 And somehow we have operations 256 00:15:50,288 --> 00:15:56,890 用来对复数进行加减乘除 that can add, and subtract, and multiply, and divide 257 00:15:57,560 --> 00:15:58,768 那么这些运算 and it shouldn't matter 258 00:15:59,344 --> 00:16:02,790 不应该被系统中同时存在的两种 that there are two incompatible representations of complex 259 00:16:02,790 --> 00:16:03,980 互不兼容的复数表示方法影响 numbers floating around this system. 260 00:16:04,410 --> 00:16:08,330 或者说 我们不光有像这样的一个抽象屏障 In other words, not only like an abstraction barrier here 261 00:16:09,640 --> 00:16:11,840 它里面有real-part that has things in it like a real-part, 262 00:16:15,770 --> 00:16:21,710 还有 IMAG-PART、MAG 和 ANG 等几个过程 and an imaginary-part, and magnitude,and angle. 263 00:16:23,830 --> 00:16:25,360 不光有一层抽象屏障 So not only is there an abstraction barrier 264 00:16:25,392 --> 00:16:28,380 把实际的数据表示隐藏起来 that hides the actual representation from us, 265 00:16:29,100 --> 00:16:31,520 还有一层垂直的屏障 but also there's some kind of vertical barrier here 266 00:16:32,190 --> 00:16:35,024 容许不同的表示方法彼此共存 that allows both of these representations to exist 267 00:16:35,872 --> 00:16:37,400 而不互相干预 without interfering with each other. 268 00:16:38,570 --> 00:16:41,070 我们的想法是把这些东西 The idea is that the things in here-- 269 00:16:41,900 --> 00:16:44,120 REAL-PART、IMAG-PART、MAG、ANG 这些过程 real-part, imaginary-part,magnitude, and angle-- 270 00:16:44,120 --> 00:16:46,490 设计成通用运算符 will be generic operators. 271 00:16:47,310 --> 00:16:49,450 如果你调用real-part过程 它就会判断 If you ask for the real-part, it will worry about 272 00:16:49,980 --> 00:16:51,310 要在哪一种表示方法中寻找它 what representation it's looking at. 273 00:16:53,880 --> 00:16:55,100 那么我们怎么做到这一点呢 OK, well how can we do that? 274 00:16:56,840 --> 00:16:59,230 实际上有一个很容易想到的办法 There's actually a really obvious idea, 275 00:16:59,840 --> 00:17:01,680 如果你习惯了思考复数的模式 if you're used to thinking about complex numbers. 276 00:17:02,520 --> 00:17:04,440 如果你已经习惯了复合数据的思想 If you're used to thinking about compound data. 277 00:17:06,330 --> 00:17:10,990 假设你只要观察一个复数 See, suppose you could just tell by looking at a complex number 278 00:17:12,170 --> 00:17:13,950 就能看出它是被George还是Martha构造出来的 whether it was constructed by George or Martha. 279 00:17:15,790 --> 00:17:18,900 换句话说 在你眼前漂浮的这些东西 In other words, so it's not that what's floating around 280 00:17:18,900 --> 00:17:20,910 不是普通的复数 对吗? here are ordinary, just complex numbers, right? 281 00:17:20,910 --> 00:17:22,940 它们是被某个设计者“构想”出来的 They're fancy, designer complex numbers. 282 00:17:24,390 --> 00:17:28,040 当考察一个复数 我们会发现它“不仅仅”是个复数 So you look at a complex numbers as it's not just a complex number 283 00:17:28,040 --> 00:17:29,160 它上面有一个标签 it's got a label on it that says, 284 00:17:29,190 --> 00:17:30,750 写着这个是由Martha制造的 that one is by Martha. 285 00:17:31,450 --> 00:17:34,220 或者这个是由George制造的 Or this is a complex number by George. 286 00:17:34,480 --> 00:17:35,390 对吧?它们被签了名字 Right? They're signed. 287 00:17:36,860 --> 00:17:40,150 在这之后 无论何时我们看见一个复数 See, and then whenever we looked at a complex number we 288 00:17:40,150 --> 00:17:45,480 我们只要看它的标签 然后我们就能知道 could just read the label, and then we'd know how you expect 289 00:17:45,800 --> 00:17:46,720 应该怎么对它进行运算 to operate on that. 290 00:17:48,030 --> 00:17:51,190 或者说 我们想要的不只是普通的数据对象 In other words, what we want is not just ordinary data objects. 291 00:17:51,190 --> 00:17:54,370 我们引入一个概念:带类型的数据 We want to introduce the notion of what's called typed data. 292 00:17:59,760 --> 00:18:02,810 带类型的数据就意味着 这里有一朵“云彩” Typed data means, again, there's some sort of cloud. 293 00:18:03,940 --> 00:18:08,930 它里面有我们之前所说的那种 And what it's got in it is an ordinary data object like 294 00:18:08,930 --> 00:18:09,900 普通的数据对象 we've been thinking about. 295 00:18:13,180 --> 00:18:16,540 这是它的内容 就是实际的数据 Pulled out the contents, sort of the actual data. 296 00:18:19,320 --> 00:18:21,568 它里面还有一个叫做类型的东西 But also a thing called a type, 297 00:18:22,560 --> 00:18:25,240 被George或者Martha签了名 but it's signed by either George or Martha. 298 00:18:25,990 --> 00:18:28,270 那么我们现在就要从无类型的数据进入带类型数据的领域 So we're going to go from regular data to type data. 299 00:18:31,950 --> 00:18:32,710 我们怎么构造它 How do we build that? 300 00:18:32,710 --> 00:18:33,500 那很简单 Well that's easy. 301 00:18:33,840 --> 00:18:35,320 我们知道怎么构造“云彩” We know how to build clouds. 302 00:18:35,800 --> 00:18:36,880 我们用序对来组成它们 We can build them out of pairs. 303 00:18:37,920 --> 00:18:41,820 那么我们就有了一种方法来表示带类型的数据 So here's a little representation that supports typed data. 304 00:18:43,510 --> 00:18:49,640 这种方法叫做 把类型附加到内容上 There's a thing called take a type and attach it to a piece of contents, 305 00:18:49,690 --> 00:18:50,640 用cons就可以做到 and we just use cons. 306 00:18:51,640 --> 00:18:54,110 然后面对一个带类型的数据 我们就可以知道它的类型 And if we have a piece of typed data, we can look at the type 307 00:18:55,210 --> 00:18:56,000 也就是序对的car部分 which is the car. 308 00:18:56,290 --> 00:18:58,300 我们也可以知道它的具体内容 就是它的cdr部分 We can look at the contents,which is the cdr. 309 00:18:59,960 --> 00:19:04,280 我们用这种方法使用带类型的数据 Now along with that, the way we use our type data will test, 310 00:19:05,290 --> 00:19:07,260 面对一段类型数据就能知道它是什么类型 when we're given a piece of data, what type it is. 311 00:19:07,520 --> 00:19:09,260 那么我们现在有了几种判断类型的谓词 So we have some type predicates with us. 312 00:19:10,510 --> 00:19:13,730 举例来讲 想要知道一个复数 For example, to see whether a complex number is one of 313 00:19:13,730 --> 00:19:16,860 是不是George构造的 是不是直角坐标表示的 我们只需要看 George's, whether it's rectangular, we just check to 314 00:19:16,860 --> 00:19:21,850 它的“类型”是不是rectangular这个符号 see if the type of that is the symbol rectangular, 315 00:19:23,680 --> 00:19:25,050 对吧?检查 rectangular 符号 right? The symbol rectangular. 316 00:19:27,200 --> 00:19:30,330 同理 想要知道一个复数是不是Martha构造的 And to check whether a complex number is one of Martha's, 317 00:19:30,330 --> 00:19:33,420 我们就看它的“类型”是不是polar这个符号 we check to see whether the type is the symbol polar. 318 00:19:36,460 --> 00:19:39,210 那么这就是一种识别数字的类型的方法 So that's a way to test what kind of number we're looking at. 319 00:19:40,750 --> 00:19:42,810 现在来想想 怎么用这种方法来构建系统 Now let's think about how we can use that to build the system. 320 00:19:43,870 --> 00:19:46,730 我们假设George和Martha分别在做各自的工作 So let's suppose that George and Martha were off working separately, 321 00:19:47,360 --> 00:19:52,640 每一个人都设计了他们的复数表示程序包 and each of them had designed their complex number representation packages. 322 00:19:52,640 --> 00:19:58,520 他们怎么让自己的东西成为系统的一部分 What do they have to do to become part of the system, 323 00:19:58,730 --> 00:20:00,140 和对方友好共存呢 to exist compatibly? 324 00:20:00,140 --> 00:20:02,110 那其实非常简单 Well it's really pretty easy. 325 00:20:02,720 --> 00:20:04,510 回忆一下 George做了这个程序包 Remember, George had this package. 326 00:20:05,970 --> 00:20:08,480 这就是George的程序包 或者说它的一部分 Here's George's original package, or half of it. 327 00:20:08,980 --> 00:20:11,150 然后红色下划线标出的部分是他需要做的修改 And underlined in red are the changes he has to make. 328 00:20:12,090 --> 00:20:16,430 之前 当George用x和y构建了一个复数的时候 So before, when George made a complex number out of an x and y 329 00:20:17,520 --> 00:20:19,850 他只是把它们组合成一个序对 he just put them together to make a pair. 330 00:20:20,930 --> 00:20:23,390 现在唯一不同的地方是 他给它们打了标签 And the only difference is that now he signs them. 331 00:20:24,090 --> 00:20:28,080 他把类型 -- 也就是 rectangular符号 -- 附加到这个序对上面 He attaches the type, which is the symbol rectangular to that pair. 332 00:20:30,600 --> 00:20:33,260 剩下的事情都和之前一样 除了一点 Everything else George does is the same, except that-- 333 00:20:33,920 --> 00:20:38,060 就是George和Martha的程序都有叫做real-part和imaginary-part的过程 see, George and Martha both have procedures named real-part and imaginary-part. 334 00:20:38,700 --> 00:20:42,960 为了这些过程存在于在同一个Lisp环境中 So to allow them both to exist in the same Lisp environment, 335 00:20:44,220 --> 00:20:45,920 George就要修改他的过程名字 George had changed the names of his procedures. 336 00:20:45,920 --> 00:20:49,140 那么我们说 这是George的real-part过程 So we'll say, this is George's real-part procedure. 337 00:20:49,140 --> 00:20:51,168 叫做real-part-rectangular过程 It's the real-part-rectangular procedure, 338 00:20:51,488 --> 00:20:54,060 还有 imag-part-rectangular过程 the imaginary-part-rectangular procedure. 339 00:20:55,420 --> 00:20:57,240 那么这里是George的程序包剩下的部分 And then here's the rest of George's package. 340 00:20:59,130 --> 00:21:02,060 他已经有了magnitude和angle过程 只要把它们改名 He'd had magnitude and angle, just renames them magnitude 341 00:21:02,060 --> 00:21:04,160 叫magnitude-rectangular和angle-rectangular就好了 rectangular and angle rectangular. 342 00:21:06,080 --> 00:21:07,960 Martha要做的事情基本相同 And Martha has to do basically the same thing. 343 00:21:09,860 --> 00:21:16,220 在这之前 当她用模和辐角构造复数的时候 Martha previously, when she made a complex number out of a magnitude and angle, 344 00:21:18,140 --> 00:21:19,270 她只是把这两个东西cons起来 she just cons them. 345 00:21:19,270 --> 00:21:20,860 现在她额外附加类型 polar Now she attaches the type polar, 346 00:21:23,950 --> 00:21:25,610 然后修改过程的名字 and she changes the name 347 00:21:25,660 --> 00:21:29,850 来避免保证她的real-part过程和George的产生冲突 so her real-part procedure won't conflict in name with George's. 348 00:21:30,710 --> 00:21:32,990 分别改为real-part-polar和imaginary-part-polar It's a real-part-polar,imaginary-part-polar, 349 00:21:34,540 --> 00:21:38,060 magnitude-polar和angle-polar这四个过程 magnitude polar, and angle polar. 350 00:21:45,000 --> 00:21:46,130 现在我们的系统 Now we have the system. 351 00:21:46,130 --> 00:21:47,920 在它里面既有George又有Martha Right there's George and Martha. 352 00:21:49,160 --> 00:21:51,680 然后现在我们需要一个经理来对类型进行判断 And now we've got to get some kind of manager to look at these types. 353 00:21:52,830 --> 00:21:56,480 那么在George和Martha给我们提供了类型数据之后 How are these things actually going to work now 354 00:21:57,050 --> 00:21:59,400 这个系统现在怎么工作呢? that George and Martha have supplied us with typed data? 355 00:22:00,530 --> 00:22:04,300 我们手里有的 是一堆通用选择函数 Well what we have are a bunch of generic selectors. 356 00:22:05,260 --> 00:22:10,630 用于复数的通用选择函数比如 real-part、imag-part、magnitude和angle等 Generic selectors for complex numbers real-part,imaginary-part, magnitude, and angle. 357 00:22:14,140 --> 00:22:15,400 让我们更进一步观察它们 Let's look at them more closely. 358 00:22:17,930 --> 00:22:19,000 real-part过程应该做什么 What does a real-part do? 359 00:22:19,310 --> 00:22:22,760 如果我想得到一个复数的实部 If I ask for the real part of a complex number, 360 00:22:24,070 --> 00:22:24,910 那么我先要观察它 well I look at it. 361 00:22:25,800 --> 00:22:26,690 我观察它的类型 I look at its type. 362 00:22:26,690 --> 00:22:28,120 考虑它是用直角坐标表示的吗 I say, is it rectangular? 363 00:22:31,020 --> 00:22:35,360 如果是的话 我就对这个复数的"内容"部分 If so, I apply George's real part procedure 364 00:22:36,060 --> 00:22:37,920 调用George的real-part过程 to the contents of that complex number. 365 00:22:41,070 --> 00:22:42,940 这是一个带有类型的数字 This is a number that has a type on it. 366 00:22:43,720 --> 00:22:47,660 我用contents过程剥掉类型 并且对它应用George的过程 I strip off the type using contents and apply George's procedure. 367 00:22:50,700 --> 00:22:52,860 那如果是一个用极坐标表示的复数呢? Or is this a polar complex number? 368 00:22:53,950 --> 00:22:54,970 如果我想要得到它的实部 If I want the real part, 369 00:22:55,450 --> 00:22:58,780 我就把Martha的real-part过程应用在这个数的内容上 I apply Martha's real-part procedure to the contents of that number. 370 00:22:59,850 --> 00:23:01,150 这就是real-part工作的方式 So that's how real part works. 371 00:23:02,260 --> 00:23:05,660 还有类似的imag-part过程 几乎是一样的 And then similarly there's imaginary-part, which is almost the same. 372 00:23:06,510 --> 00:23:09,600 它先观察这个数字 它是直角坐标表示的 Right? It looks at the number and if it's rectangular, uses 373 00:23:09,600 --> 00:23:11,130 就调用George的imaginary-part过程 George's imaginary-part procedure. 374 00:23:11,130 --> 00:23:12,830 是极坐标表示的 就用Martha的过程 If it's polar, uses Martha's. 375 00:23:13,380 --> 00:23:17,400 同理也可以构造出magnitude和angle两个过程 And then there's a magnitude and an angle. 376 00:23:19,710 --> 00:23:21,020 我们的系统是这个样子 So there's a system. 377 00:23:23,000 --> 00:23:24,260 它里面有三个部分 Has three parts. 378 00:23:24,260 --> 00:23:26,590 有George、Martha和一个经理 There's sort of George, and Martha, and the manager. 379 00:23:26,760 --> 00:23:28,970 这就是实现通用操作符的方法 And that's how you get generic operators implemented. 380 00:23:28,970 --> 00:23:32,920 为了把它说清楚 我们举一个简单的实例 Let's look at just a simple example, just to pin it down. 381 00:23:33,500 --> 00:23:35,120 但是准确描述了它工作的方式 But exactly how this is going to work, 382 00:23:36,540 --> 00:23:43,980 假设你现在 面对一个实部是1 suppose you're going to be looking at the complex number who's real-part is one, 383 00:23:44,520 --> 00:23:46,090 虚部是2的复数 and who's imaginary-part is two. 384 00:23:46,090 --> 00:23:48,440 也就是1+2i So that would be one plus 2i. 385 00:23:50,310 --> 00:23:52,640 现在在这里 What would happen is up here, 386 00:23:55,280 --> 00:23:57,530 在操作发生的上层 up here above where the operations have to happen, 387 00:23:57,630 --> 00:24:08,270 复数被表示成一个由1和2组成的序对加上类型信息 that number would be represented as a pair of 1 and 2 together with type data. 388 00:24:10,480 --> 00:24:11,390 (1和2)是内容 That would be the contents. 389 00:24:11,870 --> 00:24:17,960 整个的数据就是在那之上加上一个rectangular符号 And the whole data would be that thing with the symbol rectangular added onto that. 390 00:24:18,140 --> 00:24:21,530 这就是复数在这个系统里存在的形式 And that's the way that complex number would exist in the system. 391 00:24:22,330 --> 00:24:24,920 你要调取real-part的时候 When you went to take the real-part, 392 00:24:25,840 --> 00:24:28,890 经理会检查这个数然后说 这是George构造的数字 the manager will look at this and say, oh it's one of George's. 393 00:24:30,270 --> 00:24:31,530 他会先把类型拿掉 He'll strip off the type 394 00:24:33,340 --> 00:24:36,910 然后把 (1,2) 这个序对传递给George and hand down to George the pair 1, 2. 395 00:24:38,000 --> 00:24:42,270 这是George的系统可以直接处理的数据 And that's the kind of data that George developed his system to use. 396 00:24:44,360 --> 00:24:45,920 那么它被拆了出来 So it gets stripped down. 397 00:24:46,520 --> 00:24:49,760 之后 如果你让George构造一个复数 Later on, if you ask George to construct a complex number, 398 00:24:51,240 --> 00:24:54,560 George就会把它构造成序对 George would construct some complex number as a pair, 399 00:24:55,070 --> 00:24:58,240 在数据被传递到上层之前 and before he passes it back up through the manager would 400 00:24:59,420 --> 00:25:01,130 经理会再给它加上rectangular类型 attach the type rectangular. 401 00:25:03,920 --> 00:25:04,650 看这个过程 So you see what happens. 402 00:25:04,650 --> 00:25:05,850 这个系统不会发生混乱 There's no confusion in this system. 403 00:25:05,850 --> 00:25:10,840 就算在Martha的世界里 序对(1 2)的含义完全不同 It doesn't matter in the least that the pair 1, 2 404 00:25:13,500 --> 00:25:15,750 也并没有什么影响 means something completely different in Martha's world. 405 00:25:15,750 --> 00:25:18,440 在Martha的世界里这个序对代表了 In Martha's world this pair means the complex number whose 406 00:25:18,440 --> 00:25:20,780 一个模为1 辐角为2的复数 magnitude is 1 and whose angle is 2. 407 00:25:21,190 --> 00:25:22,190 但是这并不会造成混乱 And there's no confusion, 408 00:25:22,220 --> 00:25:27,250 因为每当有一个这样的序对经由经理之手 because by the time any pair like this gets handed back through the manager to the 409 00:25:27,250 --> 00:25:29,610 被交给主系统的时候 它都会被附加上polar的类型标志 main system it's going to have the type polar attached. 410 00:25:31,210 --> 00:25:33,670 而这个就会被贴上rectangular类型的标签 Whereas this one would have the type rectangular attached. 411 00:25:36,930 --> 00:25:37,900 好 我们休息一下 OK, let's take a break. 412 00:25:40,770 --> 00:25:55,552 [音乐] [JESU, JOY OF MAN'S DESIRING] 413 00:25:55,690 --> 00:25:57,776 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 414 00:25:57,776 --> 00:25:59,760 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 415 00:26:05,210 --> 00:26:11,952 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 416 00:26:12,848 --> 00:26:16,750 通用运算符 Generic Operators 417 00:26:20,210 --> 00:26:24,150 我们刚刚提出了一种实现通用运算符的策略 We just looked at a strategy for implementing generic operators. 418 00:26:24,150 --> 00:26:31,400 这种策略有一个名字 叫做“基于类型的分派” That strategy has a name: it's called dispatch on type. 419 00:26:34,310 --> 00:26:39,360 它的想法就是你要把你的系统分成很多小块 And the idea is that you break your system into a bunch of pieces. 420 00:26:39,360 --> 00:26:42,670 里面有George和Martha在设计表示方法 There's George and Martha, who are making representations, 421 00:26:43,370 --> 00:26:44,380 还有一个经理 and then there's the manager. 422 00:26:46,120 --> 00:26:48,060 负责去看数据上的类型是什么 Looks at the types on the data 423 00:26:48,510 --> 00:26:50,590 然后分派给正确的人去处理 and then dispatches them to the right person. 424 00:26:51,990 --> 00:26:56,010 这种组织系统的方法有什么缺点呢? Well what criticisms can we make of that as a system organization? 425 00:26:58,150 --> 00:27:00,400 首先 有个小小的烦人的问题 Well first of all there was this little, annoying problem 426 00:27:00,400 --> 00:27:03,050 George和Martha需要修改他们的过程的名字 that George and Martha had to change the names of their procedures 427 00:27:04,000 --> 00:27:05,950 George一开始写了一个real-part过程 George originally had a real-part procedure, 428 00:27:05,980 --> 00:27:08,280 现在他必须把它的名字改成real-part-rectangular and he had to go name it real-part rectangular 429 00:27:08,300 --> 00:27:10,830 才能让它不与Martha的real-part过程相互冲突 so it wouldn't interfere with Martha's real-part procedure, 430 00:27:10,840 --> 00:27:12,760 而Martha的过程现在改叫real-part-polar which is now named real-part-polar, 431 00:27:13,640 --> 00:27:16,680 这是为了不和经理的那个叫做real-part的过程发生冲突 so it wouldn't interfere with the manager's real-part procedure, who's now named real-part. 432 00:27:17,310 --> 00:27:18,940 这个问题确实很恼人 That's kind of an annoying problem. 433 00:27:19,460 --> 00:27:21,130 但是我现在暂时不讨论这个问题 But I'm not going to talk about that one now. 434 00:27:21,270 --> 00:27:22,350 我们稍后将会看到 We'll see later on 435 00:27:23,260 --> 00:27:26,120 在讨论到Lisp名称与环境的结构的时候 when we think about the structure of Lisp names and environments 436 00:27:26,120 --> 00:27:30,390 我们会有方法把这些所谓的命名空间分开来封装 that there really are ways to package all those so-called name spaces separately so they 437 00:27:30,390 --> 00:27:31,560 然后它们就不会互相影响了 don't interfere with each other. 438 00:27:32,500 --> 00:27:34,010 现在我们暂时不去考虑这个问题 Not going to think about that problem now. 439 00:27:35,720 --> 00:27:38,190 我现在想关注的问题是 The problem that I actually want to focus on is 440 00:27:38,360 --> 00:27:43,240 你把一个新人招纳进系统之中会发生什么 what happens when you bring somebody new into the system. 441 00:27:44,510 --> 00:27:45,320 会发生什么? What has to happen? 442 00:27:45,320 --> 00:27:46,810 George和Martha并不关心 Well George and Martha don't care. 443 00:27:47,420 --> 00:27:50,730 George在他的直角坐标世界里 George is sitting there in his rectangular world, 444 00:27:52,200 --> 00:27:53,840 坐拥着他的过程和数据类型 has his procedures and his types. 445 00:27:54,090 --> 00:27:55,740 而Martha待在她的极坐标世界中 Martha sits in her polar world. 446 00:27:55,930 --> 00:27:57,020 不问世事 She doesn't care. 447 00:27:59,380 --> 00:28:00,540 但是经理呢? But let's look at the manager. 448 00:28:00,620 --> 00:28:02,840 经理需要做什么? What's the manager have to do? 449 00:28:03,180 --> 00:28:06,200 现在经理带着他的运算来了 The manager comes through and had these operations. 450 00:28:07,360 --> 00:28:09,040 有直角坐标的判断 There was a test for rectangular 451 00:28:09,040 --> 00:28:10,140 和极坐标的判断过程 and a test for polar. 452 00:28:10,140 --> 00:28:14,910 如果Harry带着某种新型的复数表示方法 进入这个系统 If Harry comes in with some new kind of complex number, 453 00:28:17,210 --> 00:28:19,960 同时带来了一个新的类型--Harry型复数 and Harry has a new type, Harry type complex number, the 454 00:28:20,270 --> 00:28:23,280 经理就需要修改他所有的过程 manager has to go in and change all those procedures. 455 00:28:25,240 --> 00:28:26,940 所以这个系统的不灵活之处 So the inflexibility in the system, 456 00:28:26,960 --> 00:28:32,410 也就是需要大量工作才能适应变化的地方 就在这个经理身上 the place where work has to happen to accommodate change, is in the manager. 457 00:28:34,890 --> 00:28:35,990 那是非常恼人的事情 That's pretty annoying. 458 00:28:35,990 --> 00:28:37,210 更恼人的是 It's even more annoying 459 00:28:39,050 --> 00:28:41,210 你意识到这个经理实际上什么也不做 It's even more annoying when you realize the manager's not doing anything 460 00:28:42,590 --> 00:28:44,670 这个经理只负责“传递公文”而已 The manager is just being a paper pusher. 461 00:28:45,840 --> 00:28:51,130 我们再来看看这些程序 它们在做什么 Let's look again at these programs. What are they doing? 462 00:28:51,760 --> 00:28:52,720 real-part过程在做什么 What does real-part do? 463 00:28:52,880 --> 00:28:56,170 这个过程说 哦 这个复数是 Real-part says, oh, is it the kind of complex number that 464 00:28:56,170 --> 00:28:57,000 George会处理的那一种吗 George can handle? 465 00:28:57,000 --> 00:28:58,270 如果是的话 好 把它交给George处理 If so, send it off to George. 466 00:28:59,410 --> 00:29:01,760 它是Martha能操作的那一种吗 Is it the kind of complex number that Martha can handle? 467 00:29:01,820 --> 00:29:04,060 是的话 把它交给Martha处理 If so, send it off to Martha. 468 00:29:05,040 --> 00:29:08,720 这个系统真正恼人之处 也就是这个系统的瓶颈 So it's really annoying that the bottleneck in this system, 469 00:29:08,720 --> 00:29:11,660 它降低灵活性 阻碍变化 the thing that's preventing flexibility and change, 470 00:29:12,090 --> 00:29:14,360 完全是一种的官僚主义 is completely in the bureaucracy. 471 00:29:15,000 --> 00:29:17,020 而不是任何做实事的人 It's not in anybody who's doing any of the work. 472 00:29:19,700 --> 00:29:21,800 很可惜这种情况经常发生 Not an uncommon situation, unfortunately. 473 00:29:23,180 --> 00:29:24,410 实际上发生的事情是 See, what's really going on-- 474 00:29:24,480 --> 00:29:26,970 在系统中 有一张抽象的表格 abstractly in the system, there's a table. 475 00:29:28,100 --> 00:29:30,080 实际发生的事情是 有这样一张表格 So what's really happening is somewhere there's a table. 476 00:29:30,840 --> 00:29:33,640 其中有各种类型 There're types. 477 00:29:34,400 --> 00:29:38,960 有polar和rectangular There's polar and rectangular. 478 00:29:41,550 --> 00:29:43,020 可能Harry也在这里 And Harry's may be over here. 479 00:29:44,380 --> 00:29:46,560 然后这里是各种运算符 And there are operators. 480 00:29:48,050 --> 00:29:58,240 各种运算符 比如real-part和imag-part There's an operator like real-part. Or imaginary-part. 481 00:30:00,010 --> 00:30:04,220 还有magnitude、angle这些运算符 Or a magnitude and angle. 482 00:30:05,830 --> 00:30:18,970 单元格中对应的是相应过程 And sitting in this table are the right procedures. 483 00:30:19,280 --> 00:30:21,990 那么填在这里 负责polar类型的real-part过程的是 So sitting here for the type polar and real-part is 484 00:30:21,990 --> 00:30:27,560 Martha的real-part-polar过程 Martha's procedure real-part-polar. 485 00:30:30,570 --> 00:30:36,620 然后在这里是George的real-part-rectangular过程 And over here in the table is George's procedure real-part-rectangular. 486 00:30:37,740 --> 00:30:43,070 然后这里是Martha的magnitude-polar过程 And over here would be, say, Martha's procedure magnitude-polar, 487 00:30:44,460 --> 00:30:49,760 然后是George的magnitude-rectangular过程 等等等等 and George's procedure magnitude-rectangular, right, and so on. 488 00:30:49,760 --> 00:30:51,240 剩下的单元格也像这样填好 The rest of this table's filled in. 489 00:30:52,390 --> 00:30:54,260 这就是实际上发生的事情 And that's really what's going on. 490 00:30:57,630 --> 00:31:01,740 从某种意义上讲 经理做的事情就是 So in some sense, all the manager is doing 491 00:31:02,110 --> 00:31:04,110 去扮演这张表格 is acting as this table. 492 00:31:06,860 --> 00:31:08,700 那我们怎么去修补这个系统呢 Well how do we fix our system? 493 00:31:11,740 --> 00:31:13,770 怎么去消灭这种官僚主义? Well, how do you fix bureaucracies a lot of the time? 494 00:31:13,770 --> 00:31:15,440 你要做的就是让这个经理走人 What you do is you get rid of the manager. 495 00:31:16,010 --> 00:31:19,550 我们用一台计算机来代替他 We just take the manager and replace him by a computer. 496 00:31:20,170 --> 00:31:21,760 我们要让自动操作抹掉他存在的意义 We're going to automate him out of existence. 497 00:31:23,320 --> 00:31:26,570 也就是说 我们不用这个经理去查阅这个表格 Namely, instead of having the manager who basically consults this table, 498 00:31:27,450 --> 00:31:29,320 而是让我们的系统直接去查阅它 we'll have our system use the table directly. 499 00:31:31,020 --> 00:31:32,110 这是什么意思呢? What do I mean by that? 500 00:31:32,110 --> 00:31:36,190 我们来假设 还是用数据抽象的观点 Let's assume, again using data abstraction, 501 00:31:37,710 --> 00:31:40,400 我们有这样一种表格数据结构 that we have some kind of data structure that's a table. 502 00:31:40,880 --> 00:31:43,610 而且我们还有把东西填进去和从中删除的方法 And we have ways of sticking things in and ways of getting things out. 503 00:31:44,350 --> 00:31:49,040 为了把话说清楚 我们假设现在有一个叫put的方法 And to be explicit, let me assume that there's an operation called "put." 504 00:31:50,300 --> 00:31:58,320 本例中put方法接受两个参数 -- 我们称其为“关键字” -- key1和key2 And put is going to take, case two things I'll call "keys." key1 and key2. 505 00:32:00,130 --> 00:32:00,992 还有接受一个值 And a value. 506 00:32:06,200 --> 00:32:11,120 put过程把value存放在表格key1和key2对应的格子里 And that stores the value in the table under key1 and key2. 507 00:32:11,490 --> 00:32:13,168 然后我们假设有另一个叫get的过程 And then we'll assume there's a thing called "get," 508 00:32:15,232 --> 00:32:18,720 它是这样的一个东西 如果我说把表格里 such that if later on I say, get me what's in the table 509 00:32:19,408 --> 00:32:22,768 存储在key1和key2对应的格子中的数据给我 stored under key1 and key2, 510 00:32:23,408 --> 00:32:25,392 它会把存储在那里的东西返回给我 it'll retrieve whatever value was stored there. 511 00:32:26,730 --> 00:32:29,440 我们先不要担心这个表格怎么实现 And let's not worry about how tables are implemented. 512 00:32:30,000 --> 00:32:32,528 那又是另一个数据抽象了 是George需要考虑的问题 That's yet another data abstraction, George's problem. 513 00:32:33,060 --> 00:32:34,368 也许稍后我们还会看到 And maybe we'll see later-- 514 00:32:34,700 --> 00:32:36,970 我们还会讨论怎么用Lisp建立这个表格 talk about how you might actually build tables in Lisp. 515 00:32:40,710 --> 00:32:45,504 我们有了这个组织结构 George和Martha需要做什么呢? Well given this organization,what did George and Martha have to do? 516 00:32:47,380 --> 00:32:49,072 当他们构建自己的系统的时候 Well when they build their system, 517 00:32:49,130 --> 00:32:51,088 都有责任在表格里 they each have the responsibility 518 00:32:51,440 --> 00:32:53,820 正确地添加上自己的那一列 to set up their appropriate column in the table. 519 00:32:55,210 --> 00:32:57,472 比如说 对于George So what George does, for example, 520 00:32:59,790 --> 00:33:02,064 当他定义过程的时候 他需要做的就是 when he defines his procedures all he has to do 521 00:33:02,272 --> 00:33:07,990 把它们放进表格中的rectangular类型的那一列下面 is go off and put into the table under the type-rectangular. 522 00:33:09,820 --> 00:33:12,128 然后操作的名字是real-part And the name of the operation is real-part, 523 00:33:13,312 --> 00:33:15,264 放入他的real-part-rectangular过程 his procedure real-part-rectangular. 524 00:33:16,250 --> 00:33:17,780 注意有什么被放到了表格里 So notice what's going into this table. 525 00:33:17,780 --> 00:33:22,100 这里的两个key是这两个符号:rectangular和real-part The two keys here are symbols, rectangular and real-part. 526 00:33:22,100 --> 00:33:22,752 这是引用 That's the quote. 527 00:33:24,400 --> 00:33:26,752 要被填到表里的东西 And what's going into the table is the actual 528 00:33:26,848 --> 00:33:29,216 是他编写的real-part-rectangular过程 procedure that he wrote, real-part rectangular. 529 00:33:31,856 --> 00:33:34,304 然后把这个获取虚部的过程也放进表里 And then puts an imaginary part into the table, 530 00:33:34,592 --> 00:33:37,808 分类到rectangular和imag-part两个关键字之下 filed under the keys rectangular and imaginary-part, 531 00:33:38,620 --> 00:33:42,880 获取模值的过程放到rectangular和magnitude下面 and magnitude under the keys rectangular magnitude, 532 00:33:43,616 --> 00:33:45,200 获取辐角的过程放到rectangular和angle下面 angle under rectangular-angle. 533 00:33:47,040 --> 00:33:50,840 George作为系统的一部分 就要做以上这些事情 Okay? So that's what George has to do to be part of this system. 534 00:33:54,420 --> 00:33:58,864 Martha用同样的方法填好表格中关于polar的这一列 Martha similarly sets up the column and the table under polar. 535 00:33:59,430 --> 00:34:00,656 在polar和real-part对应的这一栏 Polar and real-part. 536 00:34:01,696 --> 00:34:03,584 应该填的过程是real-part-polar是吧? Right? Is the procedure real-part-polar? 537 00:34:04,340 --> 00:34:07,296 然后分别是imag-part、magnitude和angle过程 And imaginary-part, and magnitude, and angle. 538 00:34:08,912 --> 00:34:11,400 Martha想要加入系统当中就要做这些事情 So this is what Martha has to do to be part of the system. 539 00:34:11,400 --> 00:34:13,550 每个设计了数据表示的人 Everyone who makes a representation has the 540 00:34:13,550 --> 00:34:17,632 都必须在表格里设置自己的一列 responsibility for setting up a column in the table. 541 00:34:17,760 --> 00:34:19,900 那么Harry带着他的绝妙的复数实现方法 And what does Harry do when Harry comes in with his 542 00:34:19,900 --> 00:34:21,800 过来的时候 他需要做什么呢 brilliant idea for implementing complex numbers? 543 00:34:21,800 --> 00:34:23,968 他先把过程写好 Well he makes whatever procedure he wants and 544 00:34:24,048 --> 00:34:26,520 然后在表格里再建立一列 builds a new column in this table. 545 00:34:28,550 --> 00:34:30,048 那么现在经理怎么样了呢 OK, well what happened to the manager? 546 00:34:31,330 --> 00:34:34,610 经理的存在被自动操作所取代 The manager has been automated out of existence and is 547 00:34:34,610 --> 00:34:37,110 被一个叫做operate的过程代替 replaced by a procedure called operate. 548 00:34:37,110 --> 00:34:39,552 这是这个系统最关键的一个过程 And this is the key procedure in the whole system. 549 00:34:40,380 --> 00:34:45,920 (define operate Let's say define operate. 550 00:34:51,060 --> 00:34:56,096 Operate过程接收你想要采取的运算 Operate is going to take an operation that you want to do, 551 00:34:57,750 --> 00:34:58,880 应该说是这个运算的名字 the name of an operation, 552 00:34:59,200 --> 00:35:03,280 和被运算的对象 and an object that you would like to apply that operation to. 553 00:35:04,210 --> 00:35:09,760 那么举例来说 对一个复数调用real-part operate过程会做什么呢 So for example, the real-part of some particular complex number, what does it do? 554 00:35:09,952 --> 00:35:11,904 它要做的第一件事就是去查表 Well the first thing it does, it looks in the table. 555 00:35:12,640 --> 00:35:13,872 它查询这个表格 Goes into the table 556 00:35:14,800 --> 00:35:22,560 试图去找到存储在表格里的一个过程 and tries to find a procedure that's stored in the table. 557 00:35:23,152 --> 00:35:24,800 所以它要对表格调用get过程 So it gets from the table, 558 00:35:25,504 --> 00:35:33,920 用对象的类型和运算的名称作为关键字进行检索 using as keys the type of the object and the operator, 559 00:35:38,920 --> 00:35:40,144 这样就可以知道在表格中 but looks on the table and sees 560 00:35:40,384 --> 00:35:42,720 与数据的类型和要进行的运算相对应的是什么了 what's stored under the type of the object and the operator 561 00:35:42,896 --> 00:35:44,352 对应的这一格里填了什么东西 sees if anything's stored. 562 00:35:44,440 --> 00:35:45,930 我们假设get过程已经被实现好了 Let's assume that get is implemented. 563 00:35:45,930 --> 00:35:47,728 所以如果在那一格什么也没有 So if nothing is stored there, 564 00:35:48,112 --> 00:35:51,792 它就会返回一个空表 it'll return a nil, return the empty list. 565 00:35:52,672 --> 00:35:55,392 如果那里确实有什么东西 So it says, if there's actually something stored there, 566 00:35:56,620 --> 00:36:00,432 如果存储有这样的一个过程 if the procedure here is not no, 567 00:36:03,150 --> 00:36:07,120 那么就会把在表格里找到的这个过程 then it'll take the procedure that it found in the table 568 00:36:09,792 --> 00:36:15,008 应用到对象的具体内容上去 procedure that it found in the table and apply it to the contents of the object. 569 00:36:18,256 --> 00:36:20,400 如果那里没有东西的话 And otherwise if there was nothing stored there, 570 00:36:20,672 --> 00:36:22,512 它就会 -- 我们可以决定 it'll-- well we can decide. 571 00:36:22,816 --> 00:36:27,120 本例中 我们让它输出一个错误消息:“未定义的运算符” In this case let's have it put out an error message saying, undefined operator. 572 00:36:28,480 --> 00:36:30,240 没有支持这种类型的运算符 No operator for this type. 573 00:36:33,072 --> 00:36:34,720 或者其它合适的错误信息 Or some appropriate error message. 574 00:36:39,072 --> 00:36:39,488 对吧? OK? 575 00:36:39,728 --> 00:36:41,040 这个东西替代了经理 And that replaces the manager. 576 00:36:41,890 --> 00:36:42,912 我们怎么去使用它呢 How do we really use it? 577 00:36:43,960 --> 00:36:49,808 我们的想法是用operate过程来定义通用选择函数 Well what we say is we'll go off and define our generic selectors using operate. 578 00:36:50,040 --> 00:36:56,752 我们可以说一个对象的real-part We'll say that the real-part of an object is found by 579 00:36:57,140 --> 00:37:05,664 是这个对象被operate应用了叫做real-part的运算后得到的结果 operating on the object with the name of the operation being real-part. 580 00:37:08,070 --> 00:37:12,224 那么类似地 imag-part是operate对obj应用imag-part运算 And then similarly, imaginary-part is operate using the name imaginary-part 581 00:37:12,224 --> 00:37:13,984 magnitude和angle同理 and magnitude and angle. 582 00:37:15,360 --> 00:37:17,430 这就是我们的实现方法 That's our implementation. 583 00:37:17,430 --> 00:37:20,480 由它们加上类型再加上operate过程组成 That plus the type plus the operate procedure. 584 00:37:21,330 --> 00:37:24,000 这个表格现在就有效地完成了之前经理的工作 And the table effectively replaces what the manager used to do. 585 00:37:24,064 --> 00:37:27,696 我们来梳理一下在这个过程中发生的事情 Let's just go through that slowly to show you what's going on. 586 00:37:27,900 --> 00:37:33,000 假设我有一个由Martha构造的复数 Suppose I have one of Martha's complex numbers. 587 00:37:33,536 --> 00:37:38,800 它的模值是1 辐角是2 It's got magnitude 1 and angle 2. 588 00:37:39,100 --> 00:37:40,220 它是由Martha构造的 And it's one of Martha's. 589 00:37:40,220 --> 00:37:45,456 所以它被贴上了polar的标签 So it's labeled here, polar. 590 00:37:47,248 --> 00:37:48,000 我们叫它z Let's call that z. 591 00:37:48,000 --> 00:37:48,912 假设这就是z Suppose that's z. 592 00:37:51,770 --> 00:37:54,464 然后假设在这种实现方法下 And suppose with this implementation someone comes up 593 00:37:54,800 --> 00:37:57,920 有人想要取z的实部 asks for the real-part of z. 594 00:38:04,870 --> 00:38:07,968 由于real-part现在是用operate来定义的 Well real-part now is defined in terms of operate. 595 00:38:09,160 --> 00:38:10,576 这就等同于说 So that's equivalent to saying 596 00:38:12,096 --> 00:38:24,816 调用 (operate 'real-part z) operate with the name of the operator being real-part, the symbol real-part on z. 597 00:38:27,060 --> 00:38:28,090 然后operate过程 And now operate comes. 598 00:38:28,090 --> 00:38:29,248 就会去查询表格 It's going to look in the table, 599 00:38:31,040 --> 00:38:34,368 然后试图去寻找在表格里存放的 and it's going to try and find something stored under-- 600 00:38:39,008 --> 00:38:46,220 查询表格中与对象的类型相对应的一列 the operation is going to apply by looking in the table under the type of the object. 601 00:38:46,720 --> 00:38:48,224 那么z的类型是polar And the type of z is polar. 602 00:38:48,790 --> 00:38:51,376 所以它就要说 我用polar作为关键字查表 So it's going to look and say, can I get using polar? 603 00:38:52,990 --> 00:38:58,576 然后运算的名称是real-part And the operation name, which was real-part. 604 00:39:05,960 --> 00:39:13,632 它查询对应的过程 然后应用到z的内容上去 It's going to look in there and apply that to the contents of z. 605 00:39:14,830 --> 00:39:17,136 如果所有东西都安排妥当的话 What's that is if everything was set up correctly, 606 00:39:17,744 --> 00:39:21,700 如果它找到的过程就是Martha编写的过程 this thing is the procedure that Martha put there. 607 00:39:21,700 --> 00:39:22,950 也就是real-part-polar This is real-part-polar. 608 00:39:31,056 --> 00:39:35,130 然后这就是z去掉类型之后的东西 And this is z without its type. 609 00:39:35,440 --> 00:39:38,944 是Martha最初设计的数据表示 The thing that Martha originally designed those procedures to work on, 610 00:39:39,408 --> 00:39:40,432 也就是这里的(1 2) which is 1, 2. 611 00:39:43,710 --> 00:39:45,872 所以说在整个系统中 operate过程 And so operate sort of does uniformly 612 00:39:46,464 --> 00:39:48,896 和之前的经理做的事情没什么区别 what the manager used to do sort of all over the system. 613 00:39:49,450 --> 00:39:52,592 它通过查询表格找到正确的东西 然后剥离类型 It finds the right thing, looks in the table, strips off the type, 614 00:39:53,584 --> 00:39:57,520 然后把它传递给能够处理它的人 and passes it down into the person who handles it. 615 00:39:58,880 --> 00:40:05,488 你会发现 这是另一种 在大多数情况下 This is another, and, you can see, more flexible for most purposes, 616 00:40:06,224 --> 00:40:08,048 更灵活地实现通用运算符的方法 way of implementing generic operators. 617 00:40:08,080 --> 00:40:15,696 我们把它叫做“数据导向编程” And it's called data-directed programming. 618 00:40:20,350 --> 00:40:21,968 其理念是 And the idea of that is 619 00:40:23,424 --> 00:40:25,552 在某种意义上 这些数据对象本身 And the idea of that is in some sense the data objects themselves, 620 00:40:26,048 --> 00:40:28,352 这些充斥在系统中的复数 those little complex numbers that are floating around the system, 621 00:40:28,736 --> 00:40:33,168 它们自身就携带着 关于应该怎么去操作它们的信息 are carrying with them the information about how you should operate on them. 622 00:40:35,744 --> 00:40:36,784 有什么疑问吗? Let's break for questions. 623 00:40:41,000 --> 00:40:41,240 请说 Yes. 624 00:40:41,240 --> 00:40:43,390 学生:你在那个数据对象里存储的是什么呢 AUDIENCE: What do you have stored in that data object? 625 00:40:43,390 --> 00:40:47,104 这里面有这个数据本身 还有它的类型 You have the data itself, you have its type, 626 00:40:47,100 --> 00:40:49,600 还有该与该类型对应的运算 the operations for that type? 627 00:40:49,690 --> 00:40:53,088 或者说那些运算是存储在哪里呢? Or where are the operations that you found? 628 00:40:53,600 --> 00:40:54,176 教授:好 让我-- PROFESSOR: OK, let me-- 629 00:40:54,980 --> 00:40:56,500 恩 这是一个好问题 yeah, that's a good question. 630 00:40:56,500 --> 00:41:00,464 通过它暗示了实现我们目标的 其它可行方法 Because it raises other possibilities of how you might do it. 631 00:41:00,750 --> 00:41:02,480 当然可能的方法有很多 And of course there are a lot of possibilities. 632 00:41:04,200 --> 00:41:06,144 在这个特定的实现当中 In this particular implementation, 633 00:41:06,240 --> 00:41:09,728 在这个数据对象里放着 what's sitting in this data object, for example, 634 00:41:10,448 --> 00:41:13,456 就是数据本身 本例中是序对(1, 2) is the data itself-- which in this case is a pair of 1 and 2-- 635 00:41:14,980 --> 00:41:16,550 和一个符号 and also a symbol. 636 00:41:16,550 --> 00:41:19,072 就是这个符号 单词P-O-L-A-R This is the symbol, the word P-O-L-A-R, 637 00:41:20,600 --> 00:41:22,336 这些就是这个数据对象里面的东西 And that what's sitting in this data object. 638 00:41:24,240 --> 00:41:26,690 那么这些运算又是存放在哪里的呢? OK, where are the operations themselves? 639 00:41:26,690 --> 00:41:29,008 那些运算在表格里 The operations are sitting in the table. 640 00:41:29,850 --> 00:41:31,072 在这个表格里 So in this table, 641 00:41:32,304 --> 00:41:36,464 所有行和列的名字都是符号 the rows and columns of the table are labeled by symbols. 642 00:41:38,230 --> 00:41:40,080 所以当我往里面存什么东西的时候 So when I store something in this table, 643 00:41:40,096 --> 00:41:47,020 可以以符号polar或符号magnitude作为关键字 the key might be the symbol polar and the symbol magnitude. 644 00:41:48,240 --> 00:41:51,310 我这样写 可能让你们感到困惑了 And I think by writing it this way I've been very confusing. 645 00:41:51,310 --> 00:41:52,704 因为在这里面放的并不是 Because what's really sitting here isn't-- 646 00:41:53,160 --> 00:41:54,576 当我写下mag-polar的时候 when I wrote magnitude polar, 647 00:41:57,040 --> 00:41:59,230 我指的是那个叫mag-polar的过程 what I mean is the procedure magnitude polar. 648 00:41:59,850 --> 00:42:01,856 可能 我本来应该在这里写上 And probably what I really should have written-- 649 00:42:02,580 --> 00:42:04,200 但是这里空间太小了 except it's too small for me to write 650 00:42:04,200 --> 00:42:05,072 我写不下 in this little space-- 651 00:42:05,580 --> 00:42:08,928 应该写成lambda(z) is something like lambda of z, 652 00:42:10,608 --> 00:42:12,750 然后调用Martha实现的过程 the thing that Martha wrote to implement. 653 00:42:14,710 --> 00:42:15,728 你也可以从这里看出 And then you can see from that, 654 00:42:15,744 --> 00:42:17,440 我已经暗示了另一种方法 there's another way that I alluded to 655 00:42:17,712 --> 00:42:19,824 来解决名字冲突的问题 of solving this name conflict problem 656 00:42:20,048 --> 00:42:23,150 那就是George和Martha根本不用给他们的过程起名字 which is that George and Martha never have to name their procedures at all. 657 00:42:23,150 --> 00:42:25,376 可以直接把由lambda定义的 They can just stick the lambda, the lambda... 658 00:42:25,392 --> 00:42:28,120 由lambda定义的匿名函数放进表格里 the anonymous things generated by lambda directly into the table. 659 00:42:28,660 --> 00:42:31,760 你的问题还引出了另一种可能性 There's also another thing that your question raises, 660 00:42:32,350 --> 00:42:34,064 也就是 is the possibility that maybe 661 00:42:34,830 --> 00:42:37,920 可能我在这个数据对象里存储的 what I would like somehow is to store in this data object 662 00:42:37,952 --> 00:42:39,480 不是符号POLAR not the symbol P-O-L-A-R but 663 00:42:39,936 --> 00:42:42,352 也许是这些运算本身 maybe actually all the operations themselves. 664 00:42:43,900 --> 00:42:45,632 这是组织系统的另一种方法 And that's another way to organize the system, 665 00:42:45,664 --> 00:42:46,608 叫做“消息传递” called message passing. 666 00:42:48,650 --> 00:42:49,920 它们都殊途同归 So there are a lot of ways you can do it. 667 00:42:54,640 --> 00:42:58,040 学生:所以说如果Martha和George AUDIENCE: Therefore if Martha and George had used the same 668 00:42:58,040 --> 00:43:01,230 用了相同的过程名字也没什么问题 procedure names, it would be OK because it wouldn't look 669 00:43:01,230 --> 00:43:02,560 [听不清] it wouldn't look into it 670 00:43:02,560 --> 00:43:04,688 教授:对 你说得很对 PROFESSOR: That's right.That's right. 671 00:43:04,800 --> 00:43:07,856 看 他们甚至根本不需要给他们的过程命名 See, they wouldn't even have to name their procedures at all. 672 00:43:08,040 --> 00:43:09,360 George和Martha可以 -- What George and Martha could writ --, 673 00:43:09,500 --> 00:43:10,624 George可以这么来做 what George could have written 674 00:43:10,832 --> 00:43:15,280 与其在rectangular和real-part对应的格子里放 instead of saying put in the table under rectangular- and real-part, 675 00:43:16,220 --> 00:43:17,984 存放real-part-rectangular这个过程 the procedure real-part rectangular, 676 00:43:18,032 --> 00:43:21,152 George可以在rectangular和real-part对应的格子里放 George could have written put under rectangular real-part, 677 00:43:21,248 --> 00:43:23,696 放一个lambda(z) 然后什么什么 lambda of z, such and such, such and such, 678 00:43:24,540 --> 00:43:26,848 整个系统会以完全相同的方式工作 And the system would work completely the same. 679 00:43:27,330 --> 00:43:29,248 学生:我的问题是 就算Martha在 AUDIENCE: My question is, Martha could put 680 00:43:29,840 --> 00:43:33,600 Martha在key1和key2对应的格子里放了real-part过程 could have put key1 key2 real-part, 681 00:43:33,952 --> 00:43:37,648 George也在key1和key2下放了一个real-part过程 and George could have put key1 key2 real-part, 682 00:43:37,960 --> 00:43:39,600 只要两个过程的定义不一样 and as long as they defined them differently 683 00:43:39,808 --> 00:43:41,264 它们就不会发生任何冲突 对吗? they wouldn't have had any conflicts, right? 684 00:43:41,290 --> 00:43:43,808 教授:对的 这完全没有问题 PROFESSOR: Yes, that would all be OK except for the fact 685 00:43:44,976 --> 00:43:47,130 除非你说的是George和Martha在同一个终端上工作 that if you imagine George and Martha typing at the same 686 00:43:47,130 --> 00:43:49,200 并且他们两个人起的所有名字的含义全部相同 console with the same meanings for all their names, 687 00:43:49,820 --> 00:43:51,232 那么同样的real-part就会造成困扰 and it would get confused by real-part, 688 00:43:51,248 --> 00:43:52,800 但是就算是这种情况也有办法解决 but there are ways to arrange that, too. 689 00:43:52,800 --> 00:43:54,800 从原则上讲你说的完全正确 And in principle you're absolutely right. 690 00:43:54,980 --> 00:43:56,290 如果它们的名字不互相冲突的话 If their names didn't conflict-- 691 00:43:56,290 --> 00:43:58,190 被填到表里的是对象本身 而不是它们的名字 it's the objects that go in the table, not the names. 692 00:44:08,200 --> 00:44:09,056 好 我们休息一下 OK, let's take a break. 693 00:44:12,912 --> 00:44:20,480 [音乐] [JESU, JOY OF MAN'S DESIRING] 694 00:44:20,960 --> 00:44:23,296 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 695 00:44:23,450 --> 00:44:25,296 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 696 00:44:57,420 --> 00:45:05,072 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 697 00:45:05,470 --> 00:45:09,248 通用运算符 Generic Operators 698 00:45:12,880 --> 00:45:16,880 教授:好的 我们刚刚讲了一个数据导向编程的例子 RPOFESSOR: All right, well we just looked at data-directed programming 699 00:45:17,680 --> 00:45:22,840 我们将其用于实现一个复数域上的算术系统 as a way of implementing a system that does arithmetic on complex numbers. 700 00:45:27,600 --> 00:45:32,480 我已经在里面实现了 +c -c 这些运算 So I had these operations in it called plus C and minus C, 701 00:45:32,880 --> 00:45:37,248 *c \c 还有其它的一些过程 and multiply, and divide,and maybe some others. 702 00:45:38,230 --> 00:45:45,728 这些过程存在于上层 -- 这是关键之处 And that sat on top of-- and this is the key point-- 703 00:45:45,740 --> 00:45:49,600 它们存在于两种不同表示方式的上层 sat on top of two different representations. 704 00:45:50,340 --> 00:45:55,440 这是一个直角坐标程序包 这里一个极坐标程序包 A rectangular package here, and a polar package. 705 00:45:58,144 --> 00:45:59,150 可能还有其它的东西 And maybe some more. 706 00:45:59,150 --> 00:46:02,800 关键理念就是 “其它的东西”可以很容易地添加上去 And we saw that the whole idea is that maybe some more are now very easy to add. 707 00:46:04,670 --> 00:46:08,352 但是这并没有真正体现出这种方法学的威力 But that doesn't really show the power of this methodology. 708 00:46:08,900 --> 00:46:10,150 我们看看发生了什么 Shows you what's going on. 709 00:46:10,150 --> 00:46:12,336 这个方法的威力 只有当你 The power of the methodology only becomes apparent 710 00:46:12,944 --> 00:46:15,792 当你把它嵌入于一些更复杂的系统中时才会显现 when you start embedding this in some more complex system. 711 00:46:16,170 --> 00:46:17,744 我现在要做的就是 So let... What I'm going to do now 712 00:46:17,872 --> 00:46:20,016 把它嵌入一个更复杂的系统中 is embed this in some more complex system. 713 00:46:20,250 --> 00:46:25,280 假设我们已经有了一个通用算术系统 Let's assume that what we really have is a general kind of arithmetic system. 714 00:46:25,280 --> 00:46:27,240 所谓的“通用算术系统” So called generic arithmetic system. 715 00:46:27,240 --> 00:46:28,544 然后在系统的最顶层 And at the top level here, 716 00:46:30,760 --> 00:46:35,920 用户可以命令它把两个东西相加 或者相减 somebody can say add twothings, or subtract two things, 717 00:46:37,456 --> 00:46:41,056 或者让两数相乘、相除 or multiply two things, or divide two things. 718 00:46:44,140 --> 00:46:46,528 然后在它们下面是一个抽象屏障 And underneath that there's an abstraction barrier. 719 00:46:47,930 --> 00:46:49,152 抽象屏障的下层 And underneath this barrier, 720 00:46:49,504 --> 00:46:52,480 是一个复数域算术程序包 is, say, a complex arithmetic package. 721 00:46:53,024 --> 00:46:54,960 然后你可以让它把两个复数相加 And you can say, add two complex numbers. 722 00:46:55,040 --> 00:46:58,832 或者你还可以把 有理数域算术程序包 Or you might also have--remember we did a rational number package 723 00:46:58,880 --> 00:46:59,936 给安装进来 you might have that sitting there. 724 00:47:00,190 --> 00:47:01,728 可以放进去有理数 And there might be a rational thing. 725 00:47:04,768 --> 00:47:06,224 然后有理数程序包里面 And the rational number package, 726 00:47:07,168 --> 00:47:14,752 有我们实现的 +rat、*rat等等的这些过程 well, has the things we implemented. Plus rat, and times rat, and so on. 727 00:47:15,392 --> 00:47:17,010 或者你还可以加上通常的Lisp算术系统 Or you might have ordinary Lisp numbers. 728 00:47:17,010 --> 00:47:18,992 你可以让它把3和4加起来 You might say add three and four. 729 00:47:19,420 --> 00:47:20,944 那么我们在这个系统里加入通常的算术系统 So we might have ordinary numbers, 730 00:47:28,288 --> 00:47:34,672 其中有Lisp自带的 + - * / in which case we have the Lisp supplied plus, and minus, and times, and slash. 731 00:47:36,670 --> 00:47:39,120 总而言之 我们可以想象这个复数系统 OK, so we might imagine this complex number system 732 00:47:39,440 --> 00:47:44,448 存在于一个更加复杂的通用运算系统里面 sitting in a more complicated generic operator structure at the next level up. 733 00:47:47,730 --> 00:47:48,736 我们怎么才能做到呢 Well how can we make that? 734 00:47:49,050 --> 00:47:52,320 我们已经有了想法 只要再一次应用它就可以了 We already have the idea, we're just going to do it again. 735 00:47:52,780 --> 00:47:54,720 我们已经实现了一个有理数程序包 We've implemented a rational number package. 736 00:47:54,720 --> 00:47:56,896 那么我们来看看应该怎么修改它 Let's look at how it has to be changed. 737 00:48:01,488 --> 00:48:03,408 实际上 在这个层面 它根本就不需要修改 In fact, at this level it doesn't have to be changed at all. 738 00:48:03,730 --> 00:48:05,888 这完全就是我们上次写的那些代码 This is exactly the code that we wrote last time. 739 00:48:07,180 --> 00:48:08,976 要把两个有理数相加 To add two rational numbers, 740 00:48:09,856 --> 00:48:10,912 回忆一下 我们要用到这个公式 remember there was this formula. 741 00:48:11,140 --> 00:48:13,376 构造一个有理数 它的分子是 You make a rational number whose numerator-- 742 00:48:13,984 --> 00:48:17,568 x的分子乘以y的分母 is the numerator of the first times the denominator of the second 743 00:48:17,936 --> 00:48:21,520 加上 x的分母乘以y的分子 plus the denominator of the first times the numerator of the second. 744 00:48:21,520 --> 00:48:23,792 而结果的分母是 x的分母乘y的分母 And who's denominator is the product of the denominators. 745 00:48:25,760 --> 00:48:29,072 然后是-rat、*rat、/rat这些过程 And minus rat, and star rat, and slash rat. 746 00:48:30,360 --> 00:48:35,120 这就是我们之前写的那个有理数程序包 And this is exactly the rational number package that we made before. 747 00:48:36,310 --> 00:48:38,896 我们忽略最大公约数的问题 先不去考虑那个 We're ignoring the GCD problem,but let's not worry about that. 748 00:48:39,080 --> 00:48:42,592 作为这个有理数包的实现人员 How do we install... As implementers of this rational number package, 749 00:48:42,800 --> 00:48:45,104 怎么把它安装到我们的通用运算系统中呢? how do we install it in the generic arithmetic system? 750 00:48:45,570 --> 00:48:46,224 那很简单 Well that's easy. 751 00:48:47,296 --> 00:48:51,568 我们要做的事只有一件和之前不同 Go off... There's only one thing we have to do differently. 752 00:48:51,840 --> 00:48:55,712 在之前我们说构造一个有理数 Whereas previously we said that to make a rational number 753 00:48:56,270 --> 00:48:59,984 就是构造一个由分子分母组成的序对 you built a pair of the numerator and denominator, 754 00:49:00,960 --> 00:49:03,200 现在我们不光构造这个序对 还要给它贴上标签 here we'll not only build the pair, but we'll sign it. 755 00:49:03,300 --> 00:49:04,560 给它加上rational类型 We'll attach the type rational. 756 00:49:06,368 --> 00:49:08,096 这就是唯一的不同之处 That's the only thing we have to do different, 757 00:49:08,560 --> 00:49:10,096 把它变成带类型的数据 make it a typed data object. 758 00:49:12,380 --> 00:49:14,080 现在 我们要把运算放进表格里 And now we'll stick our operations in the table. 759 00:49:14,368 --> 00:49:18,208 我们在rational符号和add运算对应的格子里 We'll put under the symbol rational and the operation add 760 00:49:18,920 --> 00:49:20,256 放进我们的+rat过程 our procedure -- +rat. 761 00:49:21,820 --> 00:49:23,248 再次强调 这是一个符号 And, again, note this is a symbol. 762 00:49:23,744 --> 00:49:23,930 看到了么? Right? 763 00:49:24,030 --> 00:49:25,296 这是引用 这也是引用 Quote, and quote, 764 00:49:25,312 --> 00:49:28,016 但是实际上放进表里的是+rat过程本身 but the actual thing we're putting in the table is the procedure. 765 00:49:29,824 --> 00:49:31,776 然后怎么做减法 And for how to subtract, 766 00:49:31,790 --> 00:49:36,816 我们用-rat过程做减法 well you subtract rationals with minus rat. 767 00:49:38,270 --> 00:49:40,240 然后是乘法和除法 And multiply, and divide. 768 00:49:41,090 --> 00:49:43,640 这些步骤精准地描述了 我们该怎么做 And that is exactly and precisely what we have to do 769 00:49:44,144 --> 00:49:46,976 来兼容这个通用算术系统 to fit inside this generic arithmetic system. 770 00:49:48,510 --> 00:49:49,888 那么整个系统怎么工作呢 Well how does the whole thing work? 771 00:49:51,560 --> 00:49:58,400 我们想实现的是通用运算符 See, what we want to do is have some generic operators. 772 00:49:59,344 --> 00:50:02,800 为了让add、sub、mul和div变成通用运算符 Right? Have add and sub and mul and div be generic operators. 773 00:50:03,990 --> 00:50:17,360 所以我们要把add过程定义为 (ADD X Y)就是 So we're going to define add and say, to add x and y, 774 00:50:18,620 --> 00:50:22,128 就是调用operate过程 that will be operate-- 775 00:50:26,080 --> 00:50:27,490 我们把这个叫做operate-2 we were going to call it operate-2. 776 00:50:27,490 --> 00:50:30,784 这是我们的操作过程 但是要接收两个参数 This is our operator procedure, but set up for two arguments 777 00:50:31,600 --> 00:50:35,840 对它们应用add 把它们加起来 using add on x and y. 778 00:50:37,600 --> 00:50:39,760 这是和operate类似的一个东西 And so this is the analog to operate. 779 00:50:40,420 --> 00:50:41,680 我们再看看这个代码 Let's look at the code for a second. 780 00:50:41,680 --> 00:50:42,930 它和operate很相似 It's almost like operate. 781 00:50:45,792 --> 00:50:52,496 为了将运算符运用在两个参数arg1和arg2上 Right? To operate with some operator on an argument1 and an argument2 782 00:50:55,040 --> 00:50:56,656 首要任务是 well the first thing we're going to do is check 783 00:50:56,832 --> 00:51:00,730 检查这两个参数的类型是否相同 and see if the two arguments have the same type. 784 00:51:01,900 --> 00:51:02,960 所以我们要问 So we'll say, 785 00:51:02,992 --> 00:51:07,776 第一个参数的类型和第二个的类型一样吗? is the type of the first argument the same as the type of the second argument? 786 00:51:10,350 --> 00:51:13,360 如果不一样 And if they're not, if they're not 787 00:51:13,580 --> 00:51:15,632 我们就停止运行 然后抛出错误 we'll go off and complain, and say, that's an error. 788 00:51:15,670 --> 00:51:16,672 我们不知道怎么对它们进行运算 We don't know how to do that. 789 00:51:19,140 --> 00:51:20,496 如果它们的类型确实是相同的 If they do have the same type, 790 00:51:20,512 --> 00:51:22,080 那就和之前一样了 we'll do exactly what we did before. 791 00:51:22,080 --> 00:51:26,460 我们会查询在参数的类型对应的 We'll go look and filed under the type of the argument-- 792 00:51:26,768 --> 00:51:29,616 参数1和参数2是同样的类型 知道一个就可以 arg 1 and arg 2 have the same type, so it doesn't matter. 793 00:51:30,420 --> 00:51:32,592 我们到表格里去查找对应的过程 So we'll look in the table, find the procedure. 794 00:51:33,640 --> 00:51:35,872 如果找到这样一个过程 If there is a procedure there, 795 00:51:37,536 --> 00:51:41,744 我们就将其应用在参数1和参数2的内容上 then we'll apply it to the contents of the arg1 and the contents of arg2. 796 00:51:43,030 --> 00:51:44,760 如果是其它情况 就报错 And otherwise we'll say, error. 797 00:51:44,760 --> 00:51:45,728 “未定义运算符” Undefined operator. 798 00:51:46,890 --> 00:51:48,160 这就是operate-2过程 And so there's operate-2. 799 00:51:51,728 --> 00:51:54,032 这就是我们要做的全部事情 And that's all we have to do. 800 00:51:55,160 --> 00:51:57,456 我们刚刚才写好了一个复数运算包 We just built the complex number package before. 801 00:51:57,640 --> 00:52:01,008 那么怎么把它放进这个通用系统里面呢? How do we embed that complex number package in this generic system? 802 00:52:02,140 --> 00:52:02,912 方法几乎是一样的 Almost the same. 803 00:52:06,410 --> 00:52:08,592 我们构造一个叫做make-complex的过程 We make a procedure called make-complex 804 00:52:09,952 --> 00:52:12,816 它把George和Martha给我们的东西 that takes whatever George and Martha hand to us 805 00:52:13,648 --> 00:52:15,008 贴上complex的类型标志 and add the type complex. 806 00:52:18,170 --> 00:52:23,872 然后我们说 要把复数相加 这个+complex过程 And then we say, to add complex numbers, plus complex, 807 00:52:25,840 --> 00:52:28,784 用我们的内部过程 +c we use our internal procedure, plus c, 808 00:52:30,784 --> 00:52:32,240 把结果加上类型 and attach a type, 809 00:52:32,240 --> 00:52:33,424 让它变成复数类型 make that a complex number. 810 00:52:37,680 --> 00:52:42,528 那么我们的包里原来有+c和-c这两个过程 So our original package had names plus c and minus c 811 00:52:42,688 --> 00:52:44,752 用来和George和Martha通信 that we're using to communicate with George and Martha. 812 00:52:45,250 --> 00:52:47,392 然后为了与外部通信 And then to communicate with the outside world, 813 00:52:47,408 --> 00:52:53,040 我们还有+complex和-complex we have a thing called plus-complex and minus-complex. 814 00:52:55,920 --> 00:52:56,530 等等 And so on. 815 00:52:56,530 --> 00:52:59,984 它们唯一的不同就在于:后者的返回的是带类型的值 And the only difference is that these return values that are typed 816 00:53:01,120 --> 00:53:02,416 它们可以在这里被查询 So they can be looked at up here. 817 00:53:02,850 --> 00:53:05,024 而这些是内部过程 And these are internal operations. 818 00:53:09,250 --> 00:53:10,680 我们再来看那个幻灯片 Let's go look at that slide again. 819 00:53:10,680 --> 00:53:13,040 我们还有一件事要做 There's one more thing we do. 820 00:53:13,740 --> 00:53:15,616 在定义了+complex之后 After defining plus-complex, 821 00:53:15,680 --> 00:53:20,528 我们在complex类型和add符号对应的格子中 we put under the type complex and the symbol add, 822 00:53:21,312 --> 00:53:22,752 填上过程+complex that procedure plus complex. 823 00:53:23,200 --> 00:53:26,752 对于-complex也类似 And then similarly for subtracting complex numbers, 824 00:53:27,130 --> 00:53:29,130 *complex和/complex亦如此 and multiplying them, and dividing them. 825 00:53:31,700 --> 00:53:33,488 那我们怎么安装寻常算术呢? OK, how do we install ordinary numbers? 826 00:53:35,250 --> 00:53:36,128 方法还是一样的 Exactly the same way. 827 00:53:38,160 --> 00:53:41,360 我们会写一个叫做make-number的过程 Come off and say, well we'll make a thing called make-number 828 00:53:44,340 --> 00:53:48,112 make-number接收一个数 然后给它加上类型 Make-number takes a number and attaches a type, 829 00:53:48,144 --> 00:53:49,296 也就是符号number which is the symbol number. 830 00:53:50,260 --> 00:53:52,112 我们构造一个过程叫做+number We build a procedure called plus-number, 831 00:53:52,928 --> 00:53:58,752 用Lisp自带的加法把两个数加起来 which is simply, add the two things using the ordinary addition, 832 00:53:58,928 --> 00:54:00,784 因为我们现在讨论的是寻常算术 because in this case we're talking about ordinary numbers, 833 00:54:01,312 --> 00:54:03,104 给它加上类型 让它变成number类型 and attach a type to it and make that a number. 834 00:54:04,510 --> 00:54:08,096 然后我们把+number过程放到 And then we put into the table under the symbol number 835 00:54:08,592 --> 00:54:11,008 表格里number和add对应的的格子中 and the operation add, this procedure plus-number, 836 00:54:12,304 --> 00:54:16,160 再用相同的方法把减法 乘法 除法也放进去 and then the same thing for subtracting, and multiplying, and dividing. 837 00:54:22,672 --> 00:54:26,060 我们举一个例子 就看得清楚一点 Let's look at an example, just to make it clear. 838 00:54:26,060 --> 00:54:28,752 假设 比如说 Suppose, for instance, 839 00:54:32,288 --> 00:54:34,150 我要执行这个运算 I'm going to perform the operation. 840 00:54:34,150 --> 00:54:38,220 好 现在我要执行一个运算 So I sit up here and I'm going to perform the operation, 841 00:54:38,220 --> 00:54:40,464 比如说我把两个复数乘起来 which looks like multiplying two complex numbers. 842 00:54:40,930 --> 00:54:48,640 把3+4i和2+6i乘起来 So I would multiply, say, 3 plus 4i and 2 plus 6i. 843 00:54:50,170 --> 00:54:52,608 这就是我调用mul过程要传入的参数 And that's something that I might want to take hand that to mul. 844 00:54:52,840 --> 00:54:55,760 这里就代表通用运算符mul I'll write mul as my generic operator here. 845 00:54:57,170 --> 00:54:57,984 那么它怎么工作呢 How's that going to work? 846 00:54:58,280 --> 00:55:04,608 我们讲3+4i 在整个系统里 Well 3 plus 4i, say, sits in the system at this level 847 00:55:04,832 --> 00:55:06,112 处于这样的一个位置 as something that looks like this. 848 00:55:06,250 --> 00:55:07,520 假设它是George那种方法表示的 Let's say it was one of George's. 849 00:55:08,280 --> 00:55:14,976 所以它的内部有一个3和一个4 So it would have a 3 and a 4. 850 00:55:18,490 --> 00:55:20,976 这上面还贴着George的类型标志 And attached to that would be George's type, 851 00:55:24,336 --> 00:55:28,320 是他构造的rectangular类型 which says rectangular, it came from George. 852 00:55:29,510 --> 00:55:30,576 又附加在那上面的 And attached to that-- 853 00:55:31,230 --> 00:55:35,792 从更上一层的视角来看这一段数据 and this itself would be the data view from the next level up 854 00:55:36,192 --> 00:55:36,784 它又是一个 which it is-- 855 00:55:37,936 --> 00:55:39,968 这整个又是一个带类型的数据 so that itself would be a type-data object 856 00:55:40,608 --> 00:55:41,808 它的类型是complex which would say complex. 857 00:55:44,820 --> 00:55:47,312 那么这就是这个对象 So that's what this object would look like 858 00:55:48,640 --> 00:55:50,240 在最高层视角中的样子 up here at the very highest level, 859 00:55:50,688 --> 00:55:53,568 那些通用运算符看到的对象 就是这样的 where the really super-generic operations are looking at it. 860 00:55:55,560 --> 00:55:58,720 现在 mul过程会过来问 Now what happens, mul eventually's going to come along 861 00:55:58,848 --> 00:56:00,400 它的类型是什么? and say, oh,what's it's type? 862 00:56:00,480 --> 00:56:01,488 它的类型是complex It's type is complex. 863 00:56:04,270 --> 00:56:06,464 然后运行到operate-2 然后说 Go through to operate-2 and say, 864 00:56:06,460 --> 00:56:09,728 啊 我想要把表格里的过程 oh, what I want to do is apply what's in the table, 865 00:56:09,720 --> 00:56:13,040 也就是*complex这个过程 which is going to be the procedure star complex, 866 00:56:15,088 --> 00:56:17,760 应用到 将其类型剥离之后的结果上去 on this thing with the type stripped off. 867 00:56:17,950 --> 00:56:19,280 所以它会把类型剥下来 So it's going to strip off the type, 868 00:56:19,936 --> 00:56:24,240 把剩下的东西传递给复数的世界 take that much, and send that down into the complex world. 869 00:56:26,704 --> 00:56:28,736 复数的世界看了看它有的运算操作 然后说 The complex world looks at its operations and says, 870 00:56:28,768 --> 00:56:30,560 “我得调用*c这个过程” oh, I have to apply star c. 871 00:56:31,280 --> 00:56:32,144 然后*c过程说 Star c might say, 872 00:56:32,224 --> 00:56:37,200 我想知道这个东西的模值是多少 at some point I want to look at the magnitude of this object that it's in, that it's got. 873 00:56:39,420 --> 00:56:40,160 然后它们会说 啊 And they'll say, oh, it's 874 00:56:40,160 --> 00:56:41,712 它是直角坐标表示的 是George的东西 rectangular, it's one of George's. 875 00:56:41,870 --> 00:56:44,416 所以它们又剥掉了一个类型 So it'll then strip off the next version of type, 876 00:56:46,912 --> 00:56:49,808 然后把内容交给George 让他提取出它的模值 and hand that down to George to take the magnitude of. 877 00:56:52,160 --> 00:56:53,136 那么我们看到 So you see what's going on 878 00:56:53,440 --> 00:56:56,990 这其中有一条由类型构成的链条 is that there are these chains of types. 879 00:56:59,320 --> 00:57:01,504 这个链条的长度就是你要 And the length of the chain is sort of the number of levels 880 00:57:01,530 --> 00:57:03,136 在这个表格里上升的层数 that you're going to be going up in this table. 881 00:57:05,090 --> 00:57:05,968 类型的作用则是 And what a type tells you, 882 00:57:05,968 --> 00:57:10,848 每当我们在表格中遇到一道垂直屏障时 every time you have a vertical barrier in this table, 883 00:57:11,056 --> 00:57:14,064 你不知道该如何抉择时 where there's some ambiguity about where you should go down to the next level, 884 00:57:14,416 --> 00:57:15,856 类型就会给你指路 the type is telling you where to go. 885 00:57:17,440 --> 00:57:18,832 然后最底层的过程 And then everybody at the bottom, 886 00:57:18,976 --> 00:57:20,672 它们构造数据结构 对数据进行筛选之后 as they construct data and filter it up, 887 00:57:21,120 --> 00:57:22,810 再把类型贴回去 they stick their type back on. 888 00:57:25,350 --> 00:57:30,750 这就是整个系统的总体结构 So that's the general structure of the system. 889 00:57:33,410 --> 00:57:33,776 好 OK. 890 00:57:34,820 --> 00:57:35,680 明白了这个之后 Now that we've got this, 891 00:57:37,568 --> 00:57:39,440 我们再让这个系统变得更加复杂 let's go and make this thing even more complex. 892 00:57:41,890 --> 00:57:46,544 我们这次不光要在系统里添加新的数域 Let's talk about adding to the system not only these kinds of numbers 893 00:57:46,600 --> 00:57:51,152 我们也来讨论一下怎么把多项式也加进去 numbers, but it's also meaningful to start talking about adding polynomials. 894 00:57:51,510 --> 00:57:52,976 让它能做多项式算术 Might do arithmetic on polynomials. 895 00:57:53,360 --> 00:58:03,712 比如我们可以计算x^15+2x^7+5 Like we could have x to the fifteenth plus 2x to the seventh plus 5. 896 00:58:04,480 --> 00:58:05,840 像这样的多项式 That might be some polynomial. 897 00:58:06,380 --> 00:58:07,936 如果有两个这样的东西 And if we have two such gadgets 898 00:58:07,936 --> 00:58:09,488 我们可以把它们相加或者相乘 we can add them or multiply them. 899 00:58:10,530 --> 00:58:11,792 先不管相除的问题 Let's not worry about dividing them. 900 00:58:12,140 --> 00:58:14,672 只考虑相加相乘和相减 Just add them, multiply them, then we'll subtract them. 901 00:58:15,552 --> 00:58:17,160 我们需要做什么 Auhhh...What do we have to do? Well 902 00:58:18,528 --> 00:58:20,768 我们先来想想怎么表示一个多项式 let's think about how we might represent a polynomial. 903 00:58:21,830 --> 00:58:23,552 它也是一种带类型的数据 It's going to be some typed data object. 904 00:58:24,736 --> 00:58:27,552 这个系统里的一个多项式 So let's say a polynomial to this system 905 00:58:28,544 --> 00:58:31,680 应该是带有polynomial类型的对象 might look like a thing that starts with the type polynomial. 906 00:58:32,000 --> 00:58:34,550 接下来它可能要问这个多项式的变量是哪个 And then maybe it says the next thing is what variable its in. 907 00:58:34,550 --> 00:58:37,696 比如这是一个以x为变量的多项式 So I might say I'm a polynomial in the variable x. 908 00:58:38,960 --> 00:58:41,392 然后 多项式内还有各项的信息 And then it'll have some information about what the terms are. 909 00:58:42,250 --> 00:58:44,160 有很多种方法来实现 And there're just tons of ways to do this, 910 00:58:44,256 --> 00:58:47,632 我们采用的方法是构造一个“项表” but one way is to say we're going to have a thing called a term-list. 911 00:58:51,520 --> 00:58:52,240 所谓的“项表” And a term-list-- 912 00:58:53,700 --> 00:58:55,616 本例中 我们用的是类似这样的东西 well, in our case we'll use something that looks like this. 913 00:58:56,360 --> 00:58:59,680 我们把它写成一系列 按次数排列的序对 We'll make it a bunch of pairs which have an order in a coefficient 914 00:58:59,690 --> 00:59:05,808 那么这个项表就能表示这个多项式了 So this polynomial would be represented by this term-list. 915 00:59:09,424 --> 00:59:10,688 它的意义是 And what that means is that 916 00:59:11,488 --> 00:59:19,710 这个多项式第一项的次数是15 系数是1 this polynomial starts off with a term of order 15 and coefficient 1. 917 00:59:23,820 --> 00:59:27,504 然后下一项的次数是7 系数是2 And the next thing in it is a term of order 7 and coefficient 2, 918 00:59:27,536 --> 00:59:30,496 再下一项是一个常数 它次数是0 系数是5 a term of order 0, which is constant in coefficient 5 919 00:59:31,450 --> 00:59:34,160 实际上有很多很多种方法 And there are lots and lots of ways, 920 00:59:34,256 --> 00:59:35,968 也有很多很多的取舍 and lots and lots of trade-offs 921 00:59:36,016 --> 00:59:39,100 在你认真思考如何实现代数操作程序包时 when you really think about making algebraic manipulation packages 922 00:59:39,440 --> 00:59:41,730 你该如何表示这些东西 that exactly how you should represent these things. 923 00:59:42,016 --> 00:59:43,680 但是我们这种是比较标准的一种 But this is a fairly standard one. 924 00:59:44,180 --> 00:59:45,552 它适用于很多情况 It's useful in a lot of contexts. 925 00:59:47,770 --> 00:59:50,992 好 那么我们怎么实现我们的多项式算术呢 OK, well how do we implement our polynomial arithmetic? 926 00:59:53,472 --> 00:59:54,960 现在开始着手做这个事情 Let's start out. 927 00:59:57,950 --> 01:00:00,288 构造一个多项式 首先要 What we'll do to make a polynomial-- 928 01:00:00,760 --> 01:00:04,128 首先我们得找一个办法来构造多项式 we'll first have a way to make polynomials. 929 01:00:05,690 --> 01:00:10,288 我们可以用一个变量 比如x和一个项表来构造它们 We're going to make a polynomial out of variable like x and term-list. 930 01:00:11,248 --> 01:00:14,096 我们要用某种方法把它们包装起来 And all that does is we'll package them together someway. 931 01:00:14,304 --> 01:00:19,408 我们可以用cons把变量和项表组合起来 We'll put the variable together with the term list using cons 932 01:00:19,824 --> 01:00:21,744 然后把这个序对加上polynomial的类型标志 and then attached to that the type polynomial. 933 01:00:26,270 --> 01:00:27,776 那我们怎么处理多项式相加呢? OK, how do we add two polynomials? 934 01:00:29,280 --> 01:00:31,856 要相加两个多项式 p1和p2 To add a polynomial, p1 and p2, 935 01:00:32,688 --> 01:00:35,184 为了简化问题 假设我们 and then just for simplicity let's say we 936 01:00:35,376 --> 01:00:37,152 我们只相加变量相同的两个式子 we will only add things in the same variable. 937 01:00:37,380 --> 01:00:39,280 那么如果它们的变量相同 So if they have the same variable, 938 01:00:39,696 --> 01:00:42,576 是否相同交由我们编写的选择函数判断 and same variable here is going to be some selector we write, 939 01:00:42,960 --> 01:00:44,384 我们不必在意它的细节 whose details we don't care about. 940 01:00:45,150 --> 01:00:47,040 如果两个多项式的变量相同 If the two polynomials have the same variable, 941 01:00:48,032 --> 01:00:48,810 我们就继续运算 then we'll do something. 942 01:00:48,810 --> 01:00:51,264 如果它们的变量不相同 我们返回一个错误 If they don't have the same variable, we'll give an error, 943 01:00:52,350 --> 01:00:54,016 “两个多项式的变量不相同” polynomials not in the same variable. 944 01:00:55,480 --> 01:00:57,376 如果它们的变量确实是相同 And if they do have the same variable, 945 01:00:57,600 --> 01:00:59,184 我们就要构造一个新的多项式 what we'll do is we'll make a polynomial 946 01:00:59,800 --> 01:01:01,856 它的变量即是原式的变量 whose variable is whatever that variable is, 947 01:01:03,152 --> 01:01:06,560 它的项表则由过程+terms产生 and whose term-list is something we'll call sum-terms. 948 01:01:07,488 --> 01:01:09,808 +terms过程会把两个项表加起来 Plus terms will add the two term lists. 949 01:01:10,170 --> 01:01:12,016 所以我们要把两个多项式的项表合起来 So we'll add the two term lists to the polynomial. 950 01:01:13,500 --> 01:01:14,512 该过程即可返回一个项表 That'll give us a term-list. 951 01:01:15,000 --> 01:01:20,016 我们将变量和得到的项表构造成新的多项式 We'll add on, we'll say it's a polynomial in the variable with that term-list. 952 01:01:20,688 --> 01:01:21,792 这就是+poly过程 That's plus poly. 953 01:01:22,550 --> 01:01:27,008 然后我们要把这个过程放进表格中polynomial那一栏 And then we're going to put in our table under the type polynomial 954 01:01:28,240 --> 01:01:30,144 用+poly实现add操作 add them using plus poly. 955 01:01:30,520 --> 01:01:31,750 当然实际上没做多少事情 And of course we really haven't done much. 956 01:01:31,750 --> 01:01:35,312 我们只是把所有的工作压到+terms的头上 What we've really done is pushed all the work onto this thing, +terms 957 01:01:35,792 --> 01:01:37,024 它会负责把项表相加起来 which is supposed to add term-lists. 958 01:01:37,744 --> 01:01:39,168 我们看看这个过程 Let's look at that. 959 01:01:39,184 --> 01:01:48,032 这是+terms过程的大概结构 Here's an overview of how we might add two term-lists. 960 01:01:48,900 --> 01:01:51,744 L1和L2是两个项表 So L1 and L2 were going to be two term-lists. 961 01:01:52,000 --> 01:01:54,816 所谓“项表”即是按每项次数排序的序对 And a term-list is a bunch of pairs, coefficient in order. 962 01:01:55,700 --> 01:01:56,950 这里有一个大的分情况分析 And it's a big case analysis. 963 01:01:59,860 --> 01:02:04,144 首先 我们要检查项表是否为空 And the first thing we'll check for and see if there are any terms 964 01:02:05,392 --> 01:02:07,552 我们对项表做递归下降处理 We're going to recursively work down these term-lists 965 01:02:08,160 --> 01:02:11,744 最终下降到 L1或L2为空 so eventually we'll get to a place where either L1 or L2 might be empty. 966 01:02:12,270 --> 01:02:14,352 只要其中有一个为空 And if either one is empty, 967 01:02:14,528 --> 01:02:15,850 我们的答案就是剩下的另一个 our answer will be the other one. 968 01:02:15,850 --> 01:02:19,552 就是说如果L1是空表 我们就返回L2 So if L1 is empty we'll return L2, 969 01:02:19,632 --> 01:02:21,712 L2是空表的话就返回L1 and if L2 is empty we'll return L1. 970 01:02:23,264 --> 01:02:25,760 除此之外还有三种情况 Otherwise there are sort of three interesting cases. 971 01:02:27,220 --> 01:02:27,984 我们要做的是 What we're going to do is 972 01:02:29,088 --> 01:02:31,050 取表中的第一项 grab the first term in each of those lists, 973 01:02:33,504 --> 01:02:36,048 记为t1和t2 Right? Called t1 and t2. 974 01:02:37,660 --> 01:02:39,056 我们来分析一下这三种情况 And we're going to look at three cases, 975 01:02:39,600 --> 01:02:45,680 分别是t1的次数大于t2的 depending on whether the order of t1 is greater than the order of t2, 976 01:02:47,230 --> 01:02:50,592 小于t2的 或者等于t2的 or less than t2, or the same. 977 01:02:53,280 --> 01:02:54,910 这就是我们要判断的三种情况 Those are the three cases we're going to look at. 978 01:02:54,910 --> 01:02:55,840 先看看这一种 Let's look at this case. 979 01:02:58,640 --> 01:03:01,312 如果t1的次数比t2的次数要高 If the order of t1 is greater than the order of t2, 980 01:03:03,400 --> 01:03:04,704 就意味着 then what that means is that 981 01:03:06,064 --> 01:03:09,968 答案的第一项的次数就是t1的次数 then what that means is that our answer is going to start with this term of the order of t1. 982 01:03:11,568 --> 01:03:13,808 因为高次项不会和任何低次项相加 Because it won't combine with any lower order terms. 983 01:03:14,176 --> 01:03:16,192 那么我们只需要把低次的项加起来 So what we do is add the lower order terms. 984 01:03:16,760 --> 01:03:18,256 我们递归地把 We recursively add 985 01:03:19,712 --> 01:03:25,070 把L1和L2两个项表里剩下的项相加 together all the terms in the rest of the term-list in L1 and L2. 986 01:03:27,136 --> 01:03:29,328 作为我们的答案中低次项 That's going to be the lower order terms of the answer. 987 01:03:30,120 --> 01:03:32,480 然后我们把它们和最高次的项连接起来 And then we're going to adjoin to that the highest order term. 988 01:03:33,180 --> 01:03:35,456 这里 我用了一对还未定义的过程 And I'm using here a whole bunch of procedures I haven't defined 989 01:03:35,472 --> 01:03:37,552 比如adjoin-term、rest-terms like a adjoin-term, and rest-terms, 990 01:03:38,480 --> 01:03:40,176 还有获取次数的选择函数 and selectors that get order. 991 01:03:41,152 --> 01:03:42,784 但是你可以想象它们是什么样子的 But you can imagine what those are. 992 01:03:44,448 --> 01:03:48,768 那么如果第一个项表的次数比第二个要高 Right? So if the first term-list has a higher order than the second 993 01:03:48,780 --> 01:03:51,088 我们就递归地把所有的低次的项相加 we recursively add all the lower terms 994 01:03:51,280 --> 01:03:53,420 再和最高次项连接起来 and then stick on that last term. 995 01:03:55,540 --> 01:03:56,752 其它情况也是一样的 The other case, the same way. 996 01:03:56,890 --> 01:04:00,288 如果第一个多项式次数比较低 If the first term has a smaller order, 997 01:04:00,540 --> 01:04:08,368 我们就把整个第一个多项式和第二个多项式低次的项相加 well then we add we add the first term-list and the rest of the terms in the second one 998 01:04:08,624 --> 01:04:12,656 然后把结果再和最高次项连起来 and adjoin on this highest order term. 999 01:04:14,570 --> 01:04:15,968 到现在也没多少复杂的事情 So so far nothing's much happened, 1000 01:04:15,968 --> 01:04:19,408 把问题变成 让低次数的项相加 we've just sort of pushed this thing off into adding lower order terms. 1001 01:04:19,470 --> 01:04:21,968 还有最后一种情况是 两个多项式的次数一样 The last case where you actually get to a coefficients 1002 01:04:22,570 --> 01:04:25,184 你必须要把它们的系数加起来 因为它们是同类项 that you have to add, this will be the case where the orders are equal. 1003 01:04:27,240 --> 01:04:30,992 我们的应对方法仍然是 递归地把低次项相加 What we do is, well again recursively add the lower order terms. 1004 01:04:31,008 --> 01:04:32,832 但现在我们需要合并一些项了 But now we have to really combine something. 1005 01:04:33,460 --> 01:04:36,352 我们构造一个项 What we do is we make a term 1006 01:04:37,312 --> 01:04:39,936 其次数为我们正在处理的那一项的次数 whose order is the order of the term we're looking at. 1007 01:04:40,820 --> 01:04:42,720 因为现在t1和t2的次数是相同的 By now t1 and t2 have the same order. 1008 01:04:44,320 --> 01:04:44,992 确定好次数了 That's its order. 1009 01:04:45,090 --> 01:04:52,336 而它的系数是t1和t2系数之和 And its coefficient is gotten by adding the coefficient of t1 and the coefficient of t2. 1010 01:04:55,792 --> 01:04:59,648 这是一个庞大的递归过程 There's... This is a big recursive working down of terms, 1011 01:04:59,680 --> 01:05:03,616 但其中只有一个符号值得玩味 but really there's only one interesting symbol in this procedure, 1012 01:05:04,256 --> 01:05:05,696 它蕴含了重要的思想 only one interesting idea. 1013 01:05:05,900 --> 01:05:08,500 那就是这个ADD过程 The interesting idea is this add. 1014 01:05:12,390 --> 01:05:14,800 说它有趣是因为 And the reason that's interesting is because 1015 01:05:15,424 --> 01:05:17,376 有一件好事发生 something completely wonderful just happened. 1016 01:05:18,220 --> 01:05:21,376 我们没有把多项式加法 We reduced adding polynomials, 1017 01:05:22,560 --> 01:05:26,464 归约为某种加法 而是归约为通用运算符ADD not to sort of plus, but to the generic add. 1018 01:05:28,820 --> 01:05:32,288 换句话说 用这种方法实现它之后 In other words, by implementing it that way, 1019 01:05:32,890 --> 01:05:34,688 我们的系统就不光有 not only do we have our system 1020 01:05:35,920 --> 01:05:41,664 有理数、复数还有寻常算术 where we can have rational numbers, or complex numbers, or ordinary numbers, 1021 01:05:41,856 --> 01:05:43,824 我们同时也让它支持多项式运算了 we've just added on polynomials. 1022 01:05:48,520 --> 01:05:51,136 而多项式的系数可以是 But the coefficients of the polynomials 1023 01:05:51,248 --> 01:05:52,860 这个系统能够相加的任何东西 can be anything that the system can add. 1024 01:05:53,590 --> 01:05:56,736 也就是说多项式的系数 So these could be polynomials whose coefficient 1025 01:05:57,200 --> 01:06:01,200 有理数或者复数 are rational numbers or complex numbers, 1026 01:06:02,768 --> 01:06:06,992 复数同时可支持直角坐标形式和极坐标形式 which in turn could be either rectangular, or polar, 1027 01:06:09,120 --> 01:06:11,392 系数还可以是寻常的数字 or ordinary numbers. 1028 01:06:18,976 --> 01:06:21,216 我想说的是 Rignt? So what I mean precisely is 1029 01:06:22,060 --> 01:06:24,352 我们的系统现在可以自动地 our system right now automatically 1030 01:06:26,600 --> 01:06:31,504 处理像这样的式子 can handle things like adding together polynomials that have this form 1031 01:06:31,536 --> 01:06:39,696 比如2/3x^2+5/17x+11/4这样的式子 2/3 of x squared plus 5/17 x plus 11/4. 1032 01:06:40,940 --> 01:06:43,488 也可以自动处理像是 Or automatically handle polynomials that look like 1033 01:06:43,824 --> 01:06:52,576 (3+2i)x^5+(4+7i)这样的式子 3 plus 2i times x to the fifth plus 4 plus 7i, or something. 1034 01:06:53,888 --> 01:06:56,210 系统可以自动处理这些运算 Right? You can automatically handle those things. 1035 01:06:56,210 --> 01:06:57,072 为什么呢? Why is that? 1036 01:06:57,820 --> 01:07:01,504 仅仅是因为 或者说深层次的原因是 That's merely because, or profoundly because 1037 01:07:02,170 --> 01:07:05,936 我们把多项式相加归约成了把它们的系数相加 we reduced adding polynomials to adding their coefficients. 1038 01:07:06,790 --> 01:07:10,224 而系数的相加是由通用运算符ADD完成的 And adding coefficients was done by the generic add operator 1039 01:07:11,088 --> 01:07:12,944 它说:“我不管你的数据类型是什么” which said, I don't care what your types are 1040 01:07:12,960 --> 01:07:14,080 “只要我能够处理就行” as long as I know how to add you. 1041 01:07:15,232 --> 01:07:18,864 于是我们就“免费”获得了处理这些东西的功能 So automatically for free we get the ability to handle that. 1042 01:07:20,650 --> 01:07:22,048 更神奇的是 What's even better than that, 1043 01:07:24,510 --> 01:07:26,528 我们曾把 one of the things we did 1044 01:07:27,200 --> 01:07:30,528 我们放入表格中 用于处理多项式加法 we put into the table that the way you add polynomials 1045 01:07:31,280 --> 01:07:32,528 是用的+poly过程 is using plus poly. 1046 01:07:34,660 --> 01:07:38,656 这就意味着ADD过程也可以处理多项式了 That means that polynomials themselves are things that can be added. 1047 01:07:39,424 --> 01:07:42,110 我举个例子 So for instance let me write one here. 1048 01:07:43,184 --> 01:07:46,192 这是一个多项式 Here is... Here's a polynomial. 1049 01:07:50,560 --> 01:07:52,416 我正在写的这个东西 So this gadget here I'm writing up, 1050 01:07:54,128 --> 01:07:58,464 它是一个以y作为变量的多项式 this is a polynomial in y 1051 01:08:01,072 --> 01:08:04,690 每项的系数是以x作为变量的多项式 whose coefficients are polynomials in x. 1052 01:08:08,610 --> 01:08:11,120 你将看到 So you see, simply by saying, 1053 01:08:11,760 --> 01:08:14,064 由于 “ADD过程能够处理多项式” polynomials are themselves things that can be added, 1054 01:08:14,416 --> 01:08:17,904 我们可以说 我们的系统现在不光能运算有理数 we can go off and say, well not only can we deal with rationals, 1055 01:08:18,270 --> 01:08:20,336 复数和一般数字 or complex, or ordinary numbers, 1056 01:08:20,350 --> 01:08:21,776 我们还可以处理多项式 but we can deal with polynomials 1057 01:08:22,096 --> 01:08:25,392 多项式的系数可以是有理数、复数、一般数字 whose coefficients are rationals, or complex, or ordinary numbers, 1058 01:08:25,504 --> 01:08:27,520 甚至是多项式 or polynomials 1059 01:08:29,150 --> 01:08:30,960 作为系数的多项式 其系数还可以是有理数 whose coefficients are rationals, 1060 01:08:31,696 --> 01:08:36,760 复数(直角或极坐标形式)或一般数字 or complex, rectangular, polar, or ordinary numbers, 1061 01:08:36,944 --> 01:08:41,136 甚至还可以是系数为有理数的多项式 or ordinary numbers, or polynomials whose coefficients are rationals, 1062 01:08:41,800 --> 01:08:43,328 系数为复数、一般数字的多项式 complex, or ordinary numbers. 1063 01:08:43,670 --> 01:08:45,216 以此类推 And so on, and so on, and so on. 1064 01:08:45,950 --> 01:08:47,552 我们构造出了一座无限延伸的 So this is sort of an infinite 1065 01:08:48,496 --> 01:08:52,880 或者说是递归的类型高塔 or maybe a recursive tower of types that we've built up. 1066 01:08:53,880 --> 01:08:57,120 这一切都来源于那个小小的符号:A-D-D And it's all exactly from that one little symbol, A-D-D. 1067 01:08:57,610 --> 01:09:00,496 来源于在多项式程序里 用“ADD”来代替“+” Writing "add" instead of "plus" in the polynomial thing. 1068 01:09:02,270 --> 01:09:03,776 换一种方式来理解它就是 Slightly different way to think about it 1069 01:09:03,952 --> 01:09:07,744 多项式也是一种类型的构造函数 is that polynomials are a constructor for types. 1070 01:09:08,740 --> 01:09:11,200 也就是说你传递给它一个类型 比如整型 Namely you give it a type, like integer, 1071 01:09:11,488 --> 01:09:15,744 然后它就返回一个以整数作为系数的多项式 and it returns for you polynomials in x whose coefficients are integers. 1072 01:09:16,270 --> 01:09:17,728 过程中很重要的一点是 And the important thing about 1073 01:09:18,650 --> 01:09:20,736 就是多项式上的运算 is that is that the operations on polynomials 1074 01:09:21,280 --> 01:09:23,376 归约成了关于系数的运算 reduce to the operations on the coefficients. 1075 01:09:23,392 --> 01:09:24,960 很多地方都与这里类似 And there are a lot of things like that. 1076 01:09:25,840 --> 01:09:27,920 比如 我们再回头看看有理数 So for example, let's go back and rational numbers. 1077 01:09:28,870 --> 01:09:32,656 我们之前把有理数看做 一个整数在另一个上面 We thought about rational numbers as an integer over an integer 1078 01:09:32,672 --> 01:09:35,660 但这并不是关于有理式的一般性记号 but there's the general notion of a rational object. 1079 01:09:36,240 --> 01:09:42,032 比如我们也可以把3x+7放在上面 x^2+1放在下面 Like we might think about 3x plus 7 over x squared plus 1. 1080 01:09:43,072 --> 01:09:48,864 这是一个分子分母都是多项式的广义有理式 That's general rational object whose numerator and denominator are polynomials. 1081 01:09:50,310 --> 01:09:52,416 有理式相加 和有理数相加一样 And to add two of them we use the same formula, 1082 01:09:52,440 --> 01:09:55,408 分子乘分母 加 分母乘分子 结果作为分子 numerator times denominator plus denominator times numerator 1083 01:09:55,720 --> 01:09:56,992 两个分母相乘 结果作为分母 over product of denominators. 1084 01:09:57,290 --> 01:09:59,376 怎么把它安装到我们的系统中呢? How could we install that in our system? 1085 01:09:59,392 --> 01:10:02,976 这是我们原来的有理数算术程序包 Well here's our original rational number arithmetic package. 1086 01:10:04,250 --> 01:10:08,240 为了让这个系统能够 And all we have to do in order to make the entire system 1087 01:10:08,288 --> 01:10:11,584 支持广义有理式的运算 continue working with general rational objects, 1088 01:10:11,850 --> 01:10:16,448 我们把特定的加法和乘法过程 都改成通用运算符 is replace these particular pluses and stars by the generic operator. 1089 01:10:16,480 --> 01:10:19,184 所以如果我们把原来那个过程变成这个过程 So if we simply change that procedure to this one, 1090 01:10:19,712 --> 01:10:22,048 把+和*换成ADD和MUL here we've changed plus and star to add a mul, 1091 01:10:22,880 --> 01:10:24,480 这些是唯一的改动 those are absolutely the only change, 1092 01:10:24,840 --> 01:10:26,032 然后霎时间 then suddenly 1093 01:10:27,520 --> 01:10:31,408 我们的整个系统 就知道怎么运算这样的东西了 our entire system can start talking about objects that look like this. 1094 01:10:33,728 --> 01:10:38,272 比如说 这里的这个有理式 So for example, here is a rational object 1095 01:10:39,184 --> 01:10:44,864 它的分子是一个系数是有理数的、关于x的多项式 whose numerator is a polynomial in x whose coefficients are rational numbers. 1096 01:10:47,020 --> 01:10:49,568 而这个有理式 Or here is a rational object 1097 01:10:51,104 --> 01:10:54,432 它的分子是关于x的多项式 whose numerator is polynomials in x 1098 01:10:55,152 --> 01:10:58,192 多项式的系数又是有理式 whose coefficients are rational objects 1099 01:10:59,776 --> 01:11:01,536 有理式又由复数组成 constructed out of complex numbers. 1100 01:11:03,390 --> 01:11:04,850 或者别的像这样的东西 And then there are a lot of other things like that. 1101 01:11:04,850 --> 01:11:08,688 看 只要能够归约成针对各部分的运算 See, whenever you have a thing where the operations reduce to operations on the pieces, 1102 01:11:08,896 --> 01:11:10,000 另一个例子是 another example would be 1103 01:11:10,288 --> 01:11:11,424 2*2的矩阵 two by two matrices. 1104 01:11:12,310 --> 01:11:15,440 假如有这样一个矩阵形式的东西 I have the idea, there might be a matrix here 1105 01:11:16,432 --> 01:11:18,336 不管它里面是什么 of general things that I don't care about. 1106 01:11:18,720 --> 01:11:20,144 但是如果我对两个这种东西调用ADD But if I add two of them, 1107 01:11:22,336 --> 01:11:25,180 答案就是 the answer over here is gotten by 1108 01:11:25,180 --> 01:11:28,144 把这个和这个相加 而矩阵是怎么相加的 adding this one and that one,however they like to add. 1109 01:11:29,030 --> 01:11:31,110 那么我可以用同样的方法实现 So I can implement that the same way. 1110 01:11:31,110 --> 01:11:31,712 如果我这么做了 And if I do that, 1111 01:11:31,960 --> 01:11:34,608 整个系统就马上可以处理像这样的东西了 then again suddenly my system can start handling things like this. 1112 01:11:35,296 --> 01:11:39,184 比如说一个矩阵 它的元素都是 So here's a matrix whose elements happen to be-- 1113 01:11:39,460 --> 01:11:42,160 它的元素是一个有理式 we'll say this element here is a rational object 1114 01:11:43,104 --> 01:11:45,152 这个有理式的分子分母都是多项式 whose numerator and denominators are polynomials. 1115 01:11:47,024 --> 01:11:49,568 我们自然而然地获得了这些功能 Right? And all that comes for free. 1116 01:11:51,280 --> 01:11:53,824 整个过程中发生了什么? Right? What's really going on here? 1117 01:11:53,920 --> 01:11:56,176 真正发生的是 What's really going on is 1118 01:11:57,680 --> 01:12:02,448 我们摆脱了凡事都想插一手的经理 getting rid of who's sitting there poking his nose into who everybody's business is. 1119 01:12:03,120 --> 01:12:06,192 我们构造了一个“控制去中心化”的系统 We built a system that has decentralized control. 1120 01:12:14,784 --> 01:12:18,340 你进入这个系统的时候 不会有人一边闲逛一边说 So when you come into and no one's poking around saying, 1121 01:12:18,352 --> 01:12:22,304 我看看官方列表中ADD是否能够处理你 gee, are you in the official list of people who can be added? 1122 01:12:22,440 --> 01:12:26,224 你直接就可以用正确的方法 把你和别的东西加起来 Rather you say, well go off and add yourself how your parts like to be added. 1123 01:12:27,810 --> 01:12:31,030 这么做的好处就是 就连这种非常非常 And the result of that is you can get this very, very, very 1124 01:12:31,030 --> 01:12:33,870 复杂的分层对象也可以被分解后 complex hierarchy where a lot of things just get done and 1125 01:12:33,870 --> 01:12:35,552 自动放到正确的地方去处理 rooted to the right place automatically. 1126 01:12:37,008 --> 01:12:37,792 有什么问题吗? Let's stop for questions. 1127 01:12:40,380 --> 01:12:42,320 学生:你说你“免费”获得了这些功能 AUDIENCE: You say you get this for free. 1128 01:12:42,350 --> 01:12:45,824 但是我在意的是你现在丢掉了 Um..... One thing that strikes me is that now you've lost 1129 01:12:46,480 --> 01:12:50,910 某种上下层之间的清楚界限 kind of the cleanness of the break between what's on top and what's underneath. 1130 01:12:50,910 --> 01:12:52,770 或者说 现在你是在用 In other words, now you're defining some of the 1131 01:12:52,770 --> 01:12:56,080 上层的东西来定义下层的过程 lower-level procedures in terms of things above their own line. 1132 01:12:56,610 --> 01:12:59,456 这不是很危险吗? Isn't that dangerous? 1133 01:13:00,350 --> 01:13:04,496 或者说 结构会变得混乱? Or, if nothing more, a little less structured? 1134 01:13:05,440 --> 01:13:05,952 教授:不 我-- PROFESSOR: No, I-- 1135 01:13:06,416 --> 01:13:07,770 你问它的结构是否混乱 the question is whether that's less structured. 1136 01:13:07,770 --> 01:13:08,690 这得要看你说的“结构”是指什么 Depends on what you mean by structure. 1137 01:13:08,690 --> 01:13:10,176 整个过程里我们都在做递归 All this is doing is recursion. 1138 01:13:11,050 --> 01:13:18,800 看 就是说要把这些东西相加就要用到这个过程 See, it's saying that the way you add these guys is to use that. 1139 01:13:19,152 --> 01:13:21,376 它是一种递归结构 并不混乱 And that's not less structured, it's just a recursive structure. 1140 01:13:22,704 --> 01:13:24,990 所以我不认为它不清楚 So I don't think it's particularly any less clean. 1141 01:13:24,990 --> 01:13:28,160 学生:那么当你修改乘法或加法运算时 AUDIENCE: Now when you want to change the multiplier or the add operator 1142 01:13:29,344 --> 01:13:31,380 可能会导致 suddenly you've got tremendous consequences 1143 01:13:31,380 --> 01:13:34,272 无法预测的灾难性后果 underneath that you're not even sure the extent of. 1144 01:13:34,480 --> 01:13:36,448 教授:你说得对 但是那要看你的意思是什么 PROFESSOR: That's right, but it depends what you mean. 1145 01:13:37,080 --> 01:13:38,470 从两个角度来讨论 See, this goes both ways. 1146 01:13:39,104 --> 01:13:43,248 举个什么例子好呢? Um....What would be a good example? 1147 01:13:44,690 --> 01:13:47,500 比如说 之前我忽略了GCD运算 I ignored greatest common divisor, for instance. 1148 01:13:47,776 --> 01:13:50,080 我们忽略了它 是为了简化我们的例子 I ignored that problem just to keep the example simple. 1149 01:13:50,280 --> 01:13:56,928 但是如果突然我觉得 这里的+rat But if I suddenly decided that plus rat here 1150 01:13:57,820 --> 01:14:01,696 应该把结果约分 然后把这个功能安装到程序里 should do a GCD computation and install that, 1151 01:14:03,340 --> 01:14:07,872 那么这个功能一旦安装 就立刻可以被所有过程调用 then that immediately becomes available to all of these, to that guy, and that guy, 1152 01:14:08,032 --> 01:14:10,080 被这个或者那个 所有的这些 and that guy, and all the way down. 1153 01:14:11,560 --> 01:14:13,890 这取决于你系统的相干性(耦合度) So it depends what you mean by the coherence of your system. 1154 01:14:13,890 --> 01:14:17,030 确实你可能想设计一个 It's certainly true that you might want to have a special 1155 01:14:17,030 --> 01:14:19,568 不这样递归下降的程序 different one that didn't filter down through the coefficients 1156 01:14:19,616 --> 01:14:22,976 但是我举这个例子的好处 就在于我们通常都是这么做的 but the nice thing about this particular example is that mostly you do. 1157 01:14:25,440 --> 01:14:27,630 学生:是不是有一个问题 我想 AUDIENCE: Isn't that the problem, I think, that you're 1158 01:14:27,630 --> 01:14:32,950 就是你会被这个结构捆绑起来 getting to tied in with the fact that the structuring, the 1159 01:14:32,950 --> 01:14:36,330 这个递归的结构是实际上被执行了的 recursiveness of that structuring there is actually 1160 01:14:36,330 --> 01:14:40,340 而不是仅仅是为了定义类型的需要 in execution as opposed to just definition of the actual 1161 01:14:40,340 --> 01:14:41,168 被这个事实所束缚 types themselves? 1162 01:14:44,680 --> 01:14:46,120 教授:我大概明白你的意思 PROFESSOR: I think I understand the question. 1163 01:14:46,120 --> 01:14:47,808 你是想说在这个系统投入运行之后 The point is that these types evolve 1164 01:14:47,824 --> 01:14:50,400 这些类型还会变得越来越复杂 and get more and more complex as the thing's actually running. 1165 01:14:50,400 --> 01:14:50,730 你是不是想…… Is that what-- 1166 01:14:50,730 --> 01:14:50,990 学生:对 AUDIENCE: Yap. 1167 01:14:50,990 --> 01:14:51,790 在它投入运行之后 As it's running. 1168 01:14:52,090 --> 01:14:54,180 学生:而不是作为基本的定义 AUDIENCE: As opposed to the basic definitions. 1169 01:14:54,180 --> 01:14:54,830 教授:对 PROFESSOR: Right. There's... 1170 01:14:54,830 --> 01:14:56,704 我们的类型结构可以说就是递归的 The type structure is sort of recursive. 1171 01:14:57,210 --> 01:15:00,224 它并不是一个 可以在系统投入运行之前 It's not that you can make this finite list of the 1172 01:15:01,584 --> 01:15:04,850 就能把要用到的东西全部包括的列表 actual things they might look like before the system runs. 1173 01:15:04,850 --> 01:15:05,792 它是一个不断演进的东西 It's something that evolves. 1174 01:15:06,780 --> 01:15:08,640 所以如果你想要定制这个系统 So if you want to specify that system, 1175 01:15:08,670 --> 01:15:10,960 你就不能通过有限的表 you have to do in some other way than by this finite list. 1176 01:15:11,008 --> 01:15:13,184 你需要用一个递归结构实现它 You have to do it by a recursive structure. 1177 01:15:13,670 --> 01:15:17,900 学生:因为类型的基本结构是相当简单而明了的 AUDIENCE: Because the basic structure of the types is pretty clean and simple. 1178 01:15:17,900 --> 01:15:18,192 教授:对 PROFESSOR: Right. 1179 01:15:20,400 --> 01:15:20,752 嗯? Yes? 1180 01:15:21,460 --> 01:15:22,870 学生:我有一个问题 AUDIENCE: I have a question. 1181 01:15:22,870 --> 01:15:25,680 我明白一旦你的数据结构被设计好之后 I understand once you have your data structure set up, 1182 01:15:25,712 --> 01:15:28,736 它是怎么把complex标志拿掉 把它传递给下层 how it pulls off complex and passes that down, 1183 01:15:28,736 --> 01:15:30,640 然后把rect类型拿掉 再传递给下层 and then pulls off rect, passes that down. 1184 01:15:30,640 --> 01:15:33,952 但是如果你只是一个用户 并不知道什么rect或者polar类型 But if you're just a user and you don't know anything about rect or polar or whatever, 1185 01:15:34,250 --> 01:15:36,048 你怎么知道如何去设置这个数据结构 how do you initially set up that data structure 1186 01:15:36,090 --> 01:15:38,080 让所有东西正常运转呢 so that everything goes to the right spot? 1187 01:15:38,096 --> 01:15:41,008 如果我只知道左边的这个算式 If I just have the equation over there on the left 1188 01:15:41,024 --> 01:15:42,500 我只是想把复数加起来或者乘起来 And I just want to add, multiply complex numbers-- 1189 01:15:42,500 --> 01:15:43,640 教授:这就是它神奇的地方 PROFESSOR: Well that's the wonderful thing. 1190 01:15:43,640 --> 01:15:45,264 如果你是一个用户 直接调用mul就可以了 If you're just a user you say "mul." 1191 01:15:47,730 --> 01:15:49,952 学生:然后它就能明白我要计算的是复数? AUDIENCE: And it figures out that I mean complex numbers? 1192 01:15:49,968 --> 01:15:51,232 或者我怎么告诉它我想—— Or how do I tell it that I want-- 1193 01:15:51,264 --> 01:15:53,056 教授:只要你给它的是复数它就能明白 PROFESSOR: Well you're going to have in your hands complex numbers. 1194 01:15:53,050 --> 01:15:56,304 作为这个系统的用户 See what you would have at some level, as a real user, 1195 01:15:56,320 --> 01:15:58,144 你能使用的是复数的构造函数 is a constructor for complex numbers. 1196 01:15:58,370 --> 01:15:59,552 学生:那么我需要自己构造复数了? AUDIENCE: So then I have to make complex numbers? 1197 01:15:59,568 --> 01:16:00,350 教授:那么你需要自己构造它们 PROFESSOR: So you have to make them. 1198 01:16:00,350 --> 01:16:04,016 作为用户 你可能只能够操作命令行 What you would probably have as a user is some little thing in the reader loop, 1199 01:16:04,650 --> 01:16:07,568 它会给你提供一些合理的方法 which would give you some plausible way 1200 01:16:07,568 --> 01:16:08,864 来输入复数 to type in a complex number, 1201 01:16:09,312 --> 01:16:11,008 让你用你喜欢的格式输入 in however whatever format you like. 1202 01:16:11,590 --> 01:16:14,360 也可能你根本就不用输入它们 Or it might be that you're never typing them in. 1203 01:16:14,360 --> 01:16:16,170 只是别人给你一个复数让你计算 Someone's just handing you a complex number. 1204 01:16:16,784 --> 01:16:19,824 学生:好 那么如果我有一个含有多项式的复数 AUDIENCE: OK, so if I had a complex number that had a polynomial in it, 1205 01:16:19,824 --> 01:16:21,960 我就要先构造这个多项式 然后再构造我的复数 I'd have to make my polynomial and then make my complex number. 1206 01:16:21,960 --> 01:16:23,968 教授:如果你是从零开始构造它的话 是这样的 PROFESSOR: Right if you wanted it constructed from scratch. 1207 01:16:24,288 --> 01:16:25,710 可以说你是在从零开始构造 At some point you construct them from scratch. 1208 01:16:25,710 --> 01:16:27,056 而你只要有了要计算的东西 But what you don't have to know of that 1209 01:16:27,280 --> 01:16:30,320 可以直接调用mul运算 然后它们就会被乘起来 is when you have the object you can just say "mul." And it'll multiply. 1210 01:16:32,784 --> 01:16:32,992 说吧 Yeah? 1211 01:16:33,270 --> 01:16:35,760 学生:我想提一个问题 就是…… AUDIENCE: I think the question that was being posed here is, 1212 01:16:36,450 --> 01:16:40,016 比如说我想修改我的复数表示方法 say if I want to change my presentation of complexes, 1213 01:16:40,030 --> 01:16:41,440 或者复数的某些运算 or some operation of complex, 1214 01:16:41,520 --> 01:16:47,104 为了修改一个特定的运算 how much real code I will have to gets around with, 1215 01:16:47,152 --> 01:16:51,264 我得考虑多少代码? or change to change it in one specific operation? 1216 01:16:52,270 --> 01:16:53,490 教授:得看你想要修改什么 PROFESSOR: [UNINTELLIGIBLE] what you have to change. 1217 01:16:53,490 --> 01:16:54,990 重点在于你只需要改 And the point is that you only have to change 1218 01:16:55,392 --> 01:16:56,070 你想改的那一部分 what you're changing. 1219 01:16:56,070 --> 01:17:00,048 想象一下如果Martha决定她 See if Martha decides that she would rather-- 1220 01:17:00,320 --> 01:17:01,232 举个不太好的例子 let's see something silly-- 1221 01:17:01,440 --> 01:17:02,912 比如把序对中两个数的顺序调换 like change the order in the pair. 1222 01:17:04,040 --> 01:17:08,720 把模和辐角的顺序反过来 Like angle and magnitude in the other order, 1223 01:17:09,390 --> 01:17:10,800 她只做了局部的修改 she just makes that change locally. 1224 01:17:10,970 --> 01:17:13,296 那么这个改动会准确无误地扩散到整个系统里 And the whole thing will propagate through the system in the right way. 1225 01:17:14,790 --> 01:17:18,768 或者突然你说 我有另一种方法来表示有理数 Or if suddenly you said, gee, I have another representation for rationals. 1226 01:17:19,700 --> 01:17:23,904 我就得不断地在表格中添加运算 And I'm going to stick it here, by filing those operations in the table. 1227 01:17:24,820 --> 01:17:27,220 那么突然之间所有的多项式 Then suddenly all of these polynomials whose coefficients 1228 01:17:27,220 --> 01:17:29,104 它们的系数和系数的系数 或者什么东西 are coefficients of coefficients, or whatever, 1229 01:17:29,240 --> 01:17:32,400 都自动支持用这种表示方法来表示了 also can automatically have available that representation. 1230 01:17:32,704 --> 01:17:34,672 这就是我们这种设计的威力 That's the power of this particular one. 1231 01:17:36,112 --> 01:17:38,700 学生:我提的这个问题可能听起来比较蠢 AUDIENCE: I'm not sure if I can even pose an intelligent sounding question. 1232 01:17:38,700 --> 01:17:42,384 整个这个系统看起来 But somehow this whole thing went really nicely 1233 01:17:42,540 --> 01:17:45,888 非常完美 所有的东西都各就各位 to this beautiful finish where all the things seemed to fall into place. 1234 01:17:46,720 --> 01:17:48,672 完美得有点出乎意料 And sort of seemed a little contrived. 1235 01:17:50,930 --> 01:17:52,528 我相信 这都是为了教学方便 That's all for the sake, I'm sure, of teaching. 1236 01:17:52,560 --> 01:17:54,656 我怀疑的是首先发明了这种做法的人 I doubt that the guys who first did this-- 1237 01:17:55,100 --> 01:17:55,856 我可能说得不对 and I could be wrong-- 1238 01:17:56,608 --> 01:17:59,728 难道一下子就搞清楚了所有这些东西一起 figured it all out so that when they just all put it all together, 1239 01:17:59,776 --> 01:18:03,936 只要把这些放在一起 你就突然可以对各种对象做各种运算 you could all of the sudden, blam, do any kind of arithmetic on any kind of object. 1240 01:18:04,860 --> 01:18:07,200 我觉得他们应该研究了很长时间 It seems like maybe they had to play with it for a while 1241 01:18:07,930 --> 01:18:10,624 不断地推倒重来 and had to bash it and rework it. 1242 01:18:11,800 --> 01:18:14,120 然后我觉得 当我们设计一个非常复杂的系统 And it seems like that's the kind of problem we're really 1243 01:18:14,120 --> 01:18:16,940 我们也要面对这样的问题 faced with we start trying to design a really complex system 1244 01:18:17,310 --> 01:18:20,352 就是有太多各种各样的部件 我们甚至不知道 is having lots of different kinds of parts and not even knowing 1245 01:18:21,088 --> 01:18:24,620 我们甚至不知道要对这些部件做什么样的操作 what kinds of operations we're going to want to do on those parts. 1246 01:18:24,620 --> 01:18:26,544 在这种时候我怎么用这种良好的方法组织操作 How to organize the operations in this nice way 1247 01:18:26,560 --> 01:18:29,630 才能获得这种 不管怎样只要把它们放在一起 so that no matter what you do, when you start putting them together 1248 01:18:29,630 --> 01:18:31,392 所有事情就正常运转 这样的效果呢 everything starts falling out for free. 1249 01:18:31,700 --> 01:18:34,340 教授:很好 这确实是一个非常聪明的问题 PROFESSOR: OK, well that's certainly a very intelligent question... Um 1250 01:18:35,104 --> 01:18:39,520 要说的一点是我们这种方法论 Um....One part is this is a very good methodology 1251 01:18:39,872 --> 01:18:43,888 受到了符号代数的很多启发 that people have discovered a lot coming from symbolic algebra. 1252 01:18:44,590 --> 01:18:45,904 符号代数相当繁复 Because there are a lot of complications. 1253 01:18:47,590 --> 01:18:50,710 允许你在决定各种运算是什么样子之前 To allow you to implement these things before you decide 1254 01:18:50,710 --> 01:18:52,896 来实现这个系统 what you want all the operations to be, and all of that. 1255 01:18:53,310 --> 01:18:57,728 所以从某种意义上讲 这是人们在这方面长期探索之后得出的答案 So in some sense it's an answer that people have discovered by wading through this stuff. 1256 01:18:58,560 --> 01:19:00,752 从另一个角度来说 这确实是精心设计的例子 In another sense, it is a very contrived example. 1257 01:19:02,160 --> 01:19:06,240 学生:看上去想要设计出这样的系统 AUDIENCE: It seems like to be able to do this you do have to 1258 01:19:06,240 --> 01:19:09,010 一开始先要研究一段时间然后才能变熟练 wade through it for a certain amount of time before you can become good at it. 1259 01:19:09,010 --> 01:19:11,888 教授:我给你看看这个东西是多么的勉强 PROFESSOR: Let me show you how terribly contrived this is. 1260 01:19:12,220 --> 01:19:14,130 你现在可以写下所有的这些程序 So you can write all these wonderful things. 1261 01:19:14,130 --> 01:19:16,256 但是我写在这里的这个系统 But the system that I wrote here, 1262 01:19:17,020 --> 01:19:18,960 如果允许我拖堂半小时的话 and if we had another half an hour to give this lecture 1263 01:19:19,310 --> 01:19:20,464 我会给大家讲 I would have given this part of it, 1264 01:19:20,816 --> 01:19:23,024 如果我让它做一个错误操作 which says, notice that it breaks down 1265 01:19:23,200 --> 01:19:29,312 比如一个愚蠢的命令 用3加上7/2 它就会崩溃 if I tell it to do something as foolish as add 3 plus 7/2. 1266 01:19:30,880 --> 01:19:33,424 因为程序首先会调用operate-2这个过程 Because what will happen is you'll get to operate-2, 1267 01:19:33,800 --> 01:19:35,952 然后operate-2会说 这个是数字类型 and operate-2 will say, oh this is type number, 1268 01:19:36,180 --> 01:19:37,376 那个是有理数类型 and that's type rational. 1269 01:19:37,560 --> 01:19:38,810 我不知道怎么把它们加起来 I don't know how to add them. 1270 01:19:41,530 --> 01:19:44,304 那么你想让这个系统至少能够 So you'd like the system at least to be able to say something like, 1271 01:19:45,888 --> 01:19:47,344 比如说 在做这个操作之前 gee,before you do that 1272 01:19:48,592 --> 01:19:50,240 把3提升为3/1 change that to 3/1. 1273 01:19:50,480 --> 01:19:53,216 把它变成一个有理数 然后交给有理数程序包来处理 Turn it into a rational number, hand that to the rational package. 1274 01:19:54,860 --> 01:19:58,704 课堂上我们来不及讲这个问题了 That's the thing I didn't talk about in this lecture. 1275 01:19:58,736 --> 01:20:00,880 书里面讨论了这个问题 It's a little bit in the book,which talks about the problem 1276 01:20:00,880 --> 01:20:01,952 叫做“类型转换” of what's called coercion. 1277 01:20:03,390 --> 01:20:05,152 你想要的是 Where you wanted-- 1278 01:20:05,310 --> 01:20:08,896 看 我们小心翼翼地把对象按类型分好类 see, having so carefully set up all of these types as distinct objects 1279 01:20:08,910 --> 01:20:12,176 但是有时你也想让它 a lot of times you want to also put in knowledge 1280 01:20:12,400 --> 01:20:17,984 知道怎么把一个普通的数字当成有理数 about how to view an ordinary number as a kind of rational. 1281 01:20:19,110 --> 01:20:21,296 或者把普通的数字当成复数 Or view an ordinary number as a kind of complex. 1282 01:20:21,620 --> 01:20:25,168 到那个时候系统就开始变得复杂了 That's where the complexity in the system really starts happening 1283 01:20:25,760 --> 01:20:28,128 就是你去思考 我应该把这些知识放在哪里的时候 where you talk about, see where do I put that knowledge? 1284 01:20:28,420 --> 01:20:32,192 是应该让有理数知道它们是由普通的数字构成的吗? Is it rational to know that ordinary numbers might be pieces of cons of them? 1285 01:20:33,130 --> 01:20:36,384 或者我们举一个更加糟糕的例子 Or they're terrible, terrible examples, like 1286 01:20:38,144 --> 01:20:47,488 比如说我想要把一个复数加到有理数上去 if I might want to add a complex number to a rational number. 1287 01:20:49,872 --> 01:20:50,760 这个不好 Bad example. 1288 01:20:50,760 --> 01:20:51,584 5/7 5/7. 1289 01:20:53,860 --> 01:20:55,728 然后整个系统里必须有人知道 Then somebody's got to know that 1290 01:20:56,060 --> 01:20:58,160 他需要把这个东西变成另一种类型 I have to convert these to another type, 1291 01:20:58,208 --> 01:21:00,656 要把它变成一部分是有理数的复数 which is complex numbers whose parts might be rationals. 1292 01:21:01,540 --> 01:21:02,680 那么谁应该去操心这个事情呢 And who worries about that? 1293 01:21:02,680 --> 01:21:03,950 是complex程序包吗? Does complex worry about that? 1294 01:21:03,950 --> 01:21:05,030 是rational程序包吗? Does rational worry about that? 1295 01:21:05,248 --> 01:21:06,224 还是plus过程要考虑这个问题? Does plus worry about that? 1296 01:21:06,900 --> 01:21:08,520 这就是体现复杂性的地方 That's where the real complexity comes in. 1297 01:21:08,520 --> 01:21:11,380 也是这个问题的特别之处 And that's where it's pretty well sorted out. 1298 01:21:11,380 --> 01:21:14,128 同时很多的 实际上是所有的这样的“消息传递”的想法 And a lot of, in fact, all of this message passing stuff 1299 01:21:14,640 --> 01:21:16,544 都是被这样的问题启发的 was motivated by problems like this. 1300 01:21:18,460 --> 01:21:20,896 当你真正深入进去 And when you really push it, people are-- 1301 01:21:20,912 --> 01:21:24,768 人们发现 代数操作的问题是如此复杂 somehow the algebraic manipulation problem seems to be so complex 1302 01:21:25,184 --> 01:21:27,410 而那些一直围绕它们工作的人们 确实就处在 that the people who are always at the edge of it are exactly in 1303 01:21:27,410 --> 01:21:28,050 你说的那种状态 the state you said. 1304 01:21:28,050 --> 01:21:29,712 他们在这些问题里艰难跋涉 时不时陷进泥里 They're wading through this thing, mucking around, 1305 01:21:29,728 --> 01:21:31,376 寻找好用的工具 并试着提炼一种通用方法 seeing what they use, trying to distill stuff. 1306 01:21:34,200 --> 01:21:37,760 学生:我想再一次回到这个复杂度的问题上来 AUDIENCE: I just want to come back to this issue of complexity once more. 1307 01:21:38,416 --> 01:21:44,550 在修改底层过程的时候 这个系统 Um... It certainly seems to be true that you have a great deal of 1308 01:21:44,550 --> 01:21:48,320 毫无疑问 体现了非常大的灵活性 flexibility in altering the lower level kinds of things. 1309 01:21:49,712 --> 01:21:53,408 但是确实 在某种意义上讲 But it is true that you are, in a sense, 1310 01:21:53,440 --> 01:21:55,264 冻结了高层运算 freezing higher level operations. 1311 01:21:55,450 --> 01:21:58,510 或者至少如果你修改它们 你不知道 Or at least if you change them you don't know where all of 1312 01:21:58,510 --> 01:22:02,060 改动会体现在哪里 会怎么体现出来 the changes are going to show up, or how they are. 1313 01:22:02,208 --> 01:22:04,224 教授:这个问题真是不能再好了 PROFESSOR: OK, that's an extremely good question. 1314 01:22:04,680 --> 01:22:05,872 我要做的事情就是 What I have to do is, 1315 01:22:08,688 --> 01:22:10,848 如果我决定添加一个通用操作 if I decide there's a new general operation 1316 01:22:11,456 --> 01:22:13,072 比如equality-test called equality test, 1317 01:22:14,960 --> 01:22:17,152 那么系统中的其它人就要查表格 then all of these people have to decide 1318 01:22:18,224 --> 01:22:22,544 来看他们需不需要支持equality-test whether or not they would like to have an equality test by looking in the table. 1319 01:22:24,650 --> 01:22:26,848 我们可以让它变得更加去中心化 There're ways to decentralize it even more. 1320 01:22:27,870 --> 01:22:30,704 这就是之前我提示了很多次的事情 That's what I sort of hinted at last time, where I said 1321 01:22:31,088 --> 01:22:33,264 你不但可以通过给对象添加符号标签来体现类型 you could not only have this type as a symbol, 1322 01:22:33,408 --> 01:22:38,704 而是把每一类对象接受的运算也保存在里面 but you actually might store in each object the operations that it knows of that. 1323 01:22:40,450 --> 01:22:43,904 那么你可以添加一个 比如说最大公约数过程 So you might have things like greatest common divisor, 1324 01:22:44,432 --> 01:22:46,816 它只能计算整数 which is a thing here which is defined only for integers, 1325 01:22:47,408 --> 01:22:49,216 而不是对所有有理数都通用 and not in general for rational numbers. 1326 01:22:51,030 --> 01:22:53,110 所以这个系统可能是非常非常碎片化的 So it might be a very, very fragmented system. 1327 01:22:53,110 --> 01:22:55,664 取决于你想让哪一部分比较灵活 And then depending on where you want your flexibility, 1328 01:22:56,224 --> 01:22:59,024 有一系列的地方让你把这个东西放进去 You...there's a whole spectrum of places that you can build that in. 1329 01:22:59,960 --> 01:23:02,560 但是你也指出了这种设计的弱点 But you're pointing at the place where this starts being weak, 1330 01:23:02,608 --> 01:23:06,370 就是必须在顶层 对于这些通用运算符有一些约定 that there has to be some agreement on top here about these general operations. 1331 01:23:06,370 --> 01:23:07,824 或者至少人们要考虑这件事情 Or at least people have to think about them. 1332 01:23:08,390 --> 01:23:10,720 或者你可以决定 把这个表格设计得非常稀疏 Or you might decide, you might have a table that's very sparse 1333 01:23:10,752 --> 01:23:11,968 里面只放很少的一点东西 that only has a few things in it. 1334 01:23:14,010 --> 01:23:15,490 这个游戏有很多种玩法 But there are lot of ways to play that game. 1335 01:23:19,780 --> 01:23:20,432 谢谢大家 OK, thank you. 1336 01:23:23,530 --> 01:23:28,784 MIT OpenCourseWare http://ocw.mit.edu 1337 01:23:28,780 --> 01:23:36,560 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec5a.srt ================================================ 1 00:00:00,000 --> 00:00:01,968 Learning-SICP学习小组 倾情制作 2 00:00:01,980 --> 00:00:04,560 翻译&&时间轴:杨启钊(windfarer) 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:04,560 --> 00:00:06,560 特别感谢:裘宗燕教授 4 00:00:06,656 --> 00:00:09,472 计算机程序的构造和解释 5 00:00:09,920 --> 00:00:13,632 赋值、状态和副作用 Assignment, State, and Side-effects 6 00:00:18,311 --> 00:00:22,000 教授:到目前为止 我们已经教了很多编程技巧 PROFESSOR: Well, so far we've invented enough programming 7 00:00:22,256 --> 00:00:24,064 来编写复杂程序了 to do some very complicated things. 8 00:00:24,768 --> 00:00:29,660 并且 到目前为止 关于编程你们学到了很多 And you surely learned a lot about programming at this point. 9 00:00:29,660 --> 00:00:31,488 你们已经学习了几乎所有的 You've learned almost all the most important tricks 10 00:00:31,860 --> 00:00:35,872 那些拥有大量经验的人 才能领悟的技巧 that usually don't get taught to people until they have had a lot of experience. 11 00:00:36,416 --> 00:00:40,080 例如 数据导向编程就是一个主要的技巧 For example, data directed programming is a major trick, 12 00:00:40,750 --> 00:00:43,152 昨天 你们也学习了一种解释型语言 and yesterday you also saw an interpreted language. 13 00:00:45,024 --> 00:00:48,460 我们所做的这一切 We did this all in a computer language, 14 00:00:48,544 --> 00:00:49,632 目前来讲 at this point, 15 00:00:49,888 --> 00:00:51,952 都是在一种没有赋值语句的计算机语言中完成的 where there was no assignment statement. 16 00:00:53,770 --> 00:00:58,176 对于你们中用过Basic或者Pascal的人 And presumably, for those of you who've seen your Basic or Pascal or whatever, 17 00:00:58,688 --> 00:01:01,232 可能会认为“赋值”是最重要的东西 that's usually considered the most important thing. 18 00:01:01,792 --> 00:01:03,820 今天我们将要做一些糟糕的事情 Well today, we're going to do something horrible. 19 00:01:03,820 --> 00:01:05,456 我们要把赋值语句加进来 We're going to add an assignment statement. 20 00:01:07,216 --> 00:01:09,140 既然在没有赋值语句的时候 我们都可以很好地完成工作 And since we can do all these wonderful things without it, 21 00:01:09,140 --> 00:01:10,176 为什么我们还要把它加进来呢? why should we add it? 22 00:01:10,990 --> 00:01:12,432 为了理解它 An important thing to understand it 23 00:01:12,464 --> 00:01:15,710 我们今天首先要定下一个规则 is that today we're going to first of all, have a rule, 24 00:01:16,480 --> 00:01:17,930 而我们将一直遵守这个规则 which is going to always be obeyed, 25 00:01:17,930 --> 00:01:20,800 这是我们为语言引入新的特性的唯一原因 which is the only reason we ever add a feature to our language 26 00:01:21,536 --> 00:01:23,140 是因为我们有一个好的理由 is because there is a good reason. 27 00:01:23,936 --> 00:01:27,280 好的理由归结为能力 And the good reason is going to boil down to the ability, 28 00:01:27,424 --> 00:01:31,510 你现在获得了把问题分解为不同部分的能力 you now get an ability to break a problem into pieces that are different sets of pieces 29 00:01:31,510 --> 00:01:33,440 在没有相关能力之前可不行 then you could have broken it down without that, 30 00:01:34,384 --> 00:01:36,160 这让你有用来分解问题的另外方法 give you another means of decomposition. 31 00:01:38,304 --> 00:01:39,450 我们这就开始 However, let's just start. 32 00:01:39,450 --> 00:01:41,880 从回顾我们的 Let me quick begin by reviewing 33 00:01:41,880 --> 00:01:47,376 现在已经有的这种语言出发 the kind of language that we have now. 34 00:01:48,160 --> 00:01:50,448 我们之前写的是所谓的函数式程序 We've been writing what's called functional programs. 35 00:01:51,216 --> 00:01:52,528 函数式程序 And functional programs 36 00:01:53,040 --> 00:01:57,952 是一种对数学事实的编码 are a kind of encoding of mathematical truths. 37 00:01:58,880 --> 00:02:00,510 例如 当我们看到 For example, when we look at 38 00:02:00,510 --> 00:02:04,096 像幻灯片上这样阶乘过程时 the factorial procedure that you see on the slide here, 39 00:02:05,072 --> 00:02:06,624 基本上是两个子句 it's basically two clauses. 40 00:02:06,992 --> 00:02:08,640 如果n是1 则结果是1 If n is one, the result is one, 41 00:02:08,640 --> 00:02:11,200 否则返回n乘以n-1的阶乘 otherwise n times factorial n minus one. 42 00:02:11,200 --> 00:02:12,336 这是n的阶乘 That's factorial of n. 43 00:02:12,896 --> 00:02:14,272 它就是阶乘函数 Well, that is factorial of n. 44 00:02:14,832 --> 00:02:16,870 如果用一些其他的记号 And written down in some other obscure notation 45 00:02:16,870 --> 00:02:19,328 那些你在微积分课堂上学到的晦涩的符号来写 that you might have learned in calculus classes, 46 00:02:20,304 --> 00:02:22,110 用数理逻辑来写 Ahh.. mathematical logic, 47 00:02:22,110 --> 00:02:26,368 如果n等于1 what you see there is if n equals one, 48 00:02:27,136 --> 00:02:29,900 那么n的阶乘结果是1 否则 for the result of n factorial is one, otherwise, 49 00:02:29,900 --> 00:02:32,560 如果n大于1 则n的阶乘就是n * (n-1)! greater than one, n factorial is n times n minus one factorial. 50 00:02:32,560 --> 00:02:33,552 数学事实 True statements, 51 00:02:34,928 --> 00:02:36,700 就是我们一直使用的那种语言 that's the kind of language we've been using. 52 00:02:37,008 --> 00:02:39,230 无论何时 我们遇到了这样的数学事实 And whenever we have true statements of that sort, 53 00:02:39,536 --> 00:02:46,656 有一种理解它们工作原理的方法 there is a kind of, a way of understanding how they work 54 00:02:47,408 --> 00:02:51,120 就是这些过程可以由代换演算而来 which is that such processes can be evolved by substitution. 55 00:02:51,296 --> 00:02:53,712 来看第二张幻灯片 And so we see on the second slide here, 56 00:02:54,992 --> 00:02:58,816 我们理解执行的过程 that the way we understand the execution 57 00:02:58,832 --> 00:03:03,500 隐含在表达式的顺序中 implied by those statements in arranged in that order, 58 00:03:04,040 --> 00:03:07,760 也就是你不断地将实际参数 is that you do successive substitutions of arguments 59 00:03:07,870 --> 00:03:10,880 代换到程序体的形式参数中 for formal parameters in the body of a procedure. 60 00:03:12,000 --> 00:03:14,512 这些基本上是一系列的等价代换 This is basically a sequence of equalities. 61 00:03:14,610 --> 00:03:17,250 4的阶乘是4乘以3的阶乘 Factorial four is four times factorial three. 62 00:03:17,250 --> 00:03:20,050 也就是4乘以3乘以2的阶乘 That is four times three times factorial of two 63 00:03:20,050 --> 00:03:21,010 以此类推 and so on. 64 00:03:21,232 --> 00:03:23,872 我们总是保持数学事实成立 We're always preserving truth. 65 00:03:25,232 --> 00:03:28,840 尽管我们正在讨论数学事实 Even though we're talking about true statements, 66 00:03:28,840 --> 00:03:31,960 可能有多种数学事实的组织方式 there might be more than one organization of these true statements 67 00:03:31,960 --> 00:03:35,120 用来描述一个特定的函数的计算 to describe the computation of a particular function, 68 00:03:36,320 --> 00:03:38,420 这个特定的函数的值的计算 the computation of the value of a particular function. 69 00:03:38,420 --> 00:03:40,928 所以 让我来看下这里的例子 So, for example, looking at the next one here. 70 00:03:41,488 --> 00:03:49,020 这有一个计算m与n之和的方法 Here is a way of looking at the sum of n and m. 71 00:03:49,536 --> 00:03:52,048 我们使用一个递归的过程来完成 And we did this one by a recursive process. 72 00:03:52,896 --> 00:03:58,160 也就是(1+ (+ (-1+ n) m)) It's the increment of the sum of the decrement of n and m. 73 00:04:00,080 --> 00:04:05,620 当然 这里也有相应的数理逻辑 解释了这个方法 And, of course, there is some piece of mathematical logic here that describes that. 74 00:04:06,176 --> 00:04:10,496 也就是((n-1)+m)+1 It's the increment of the sum of the decrement of n and m, 75 00:04:11,408 --> 00:04:12,224 跟之前那个一样 just like that. 76 00:04:13,104 --> 00:04:16,400 所以这儿并没有什么特殊的魔法 So there's nothing particularly magic about that. 77 00:04:16,416 --> 00:04:20,010 当然 如果我们可以再来看一个相同的迭代过程 And, of course, if we can also look at an iterative process for the same, 78 00:04:20,192 --> 00:04:24,920 计算同样的函数 但是进行逐步迭代的程序 a program that evolves an iterative process, for the same function. 79 00:04:25,264 --> 00:04:27,568 这两个程序将得到同样的结果 These are two things that compute the same answer. 80 00:04:30,080 --> 00:04:34,832 我们就可以认为这两个程序在数学上是等效的 And we have equivalent mathematical truths that are arranged there. 81 00:04:36,656 --> 00:04:39,936 你对这些数学事实的排序 决定了具体(计算)过程 And just the way you arrange those truths determine the particular process. 82 00:04:40,304 --> 00:04:43,424 我们对于这些数学事实的排序和选择 决定了过程发展的方式 In the way choose and arrange them determines the process that's evolved. 83 00:04:44,336 --> 00:04:48,600 因此我们可以灵活地讨论待计算的函数 So we have the flexibility of talking about both the function to be computed, 84 00:04:48,600 --> 00:04:50,192 以及计算该函数的所用的方法 and the method by which it's computed. 85 00:04:50,600 --> 00:04:52,600 这并不清晰 我们需要再深入一些 So it's not clear we need more. 86 00:04:53,616 --> 00:04:55,500 然而 今天我要来讲这个糟糕的东西 However, today I'm going to this awful thing. 87 00:04:55,500 --> 00:04:58,432 我要给大家介绍赋值操作 I'm going to introduce this assignment operation. 88 00:04:58,896 --> 00:05:00,416 这是什么? Now, what is this? 89 00:05:02,896 --> 00:05:09,220 首先 在编程语言中有另一种语句 Well, first of all, there is going to be another kind of kind of statement, if you will, 90 00:05:09,220 --> 00:05:10,848 这种语句叫做SET! in a programming language called Set! 91 00:05:12,410 --> 00:05:15,968 具有赋值操作的语句 And SET! -- Things that do things like assignment, 92 00:05:15,984 --> 00:05:17,850 我都会在后面加上一个感叹号 I'm going to put exclamation points after. 93 00:05:18,512 --> 00:05:20,960 这个感叹号代表什么意思呢? We'll talk about what that means in a second. 94 00:05:20,960 --> 00:05:23,010 这个感叹号 与问号类似 The exclamation point, again like question mark, 95 00:05:23,010 --> 00:05:25,880 是我们给名字随意加的符号 is an arbitrary thing we attach to the symbol which is the name, 96 00:05:25,880 --> 00:05:27,880 它对于系统来说没有意义 has no significance to the system. 97 00:05:28,080 --> 00:05:30,210 它唯一的意义就是告诉我们 The only significance is to me and you 98 00:05:30,400 --> 00:05:34,416 注意这里是某种赋值操作 to alert you that this is an assignment of some sort. 99 00:05:35,880 --> 00:05:40,064 但是我们要给某个变量赋一个值 But we're going to set a variable to a value. 100 00:05:43,744 --> 00:05:45,130 这意味着 And what that's going to mean 101 00:05:45,130 --> 00:05:48,288 在某个时间点发生了一些事情 is that there is a time at which something happens. 102 00:05:48,656 --> 00:05:49,616 这是一个时间点 Here's a time. 103 00:05:49,860 --> 00:05:52,144 如果时间以这个方向流动 If I have time going this way, 104 00:05:53,504 --> 00:05:54,820 这是个时间轴 it's a time axis. 105 00:05:55,008 --> 00:05:57,820 时间在平面上由上到下地流逝 Time progresses by walking down the page. 106 00:05:58,704 --> 00:06:00,920 赋值是第一个 Then an assignment is the first thing we have 107 00:06:00,920 --> 00:06:04,304 使过去和未来之间产生差别的事物 that produces the difference between a before and an after. 108 00:06:06,592 --> 00:06:08,720 我们之前写的所有程序 All the other programs that we've written, 109 00:06:09,184 --> 00:06:10,680 都不包含赋值 that have no assignments in them, 110 00:06:10,680 --> 00:06:13,120 这些程序以怎样的顺序进行执行都没关系 the order in which they were evaluated didn't matter. 111 00:06:14,704 --> 00:06:15,960 但是赋值比较特殊 But assignment is special, 112 00:06:15,960 --> 00:06:17,696 它使时间中产生了一个时间点 it produces a moment in time. 113 00:06:17,960 --> 00:06:24,736 因此在SET!出现之前和之后中间有一个时间点 So there is a moment before the set occurs and after, 114 00:06:27,616 --> 00:06:32,704 使得在这个时间点之后 such that after this moment in time, 115 00:06:33,600 --> 00:06:43,760 变量有了一个值 即VALUE the variable has the value, value. 116 00:06:49,232 --> 00:06:51,504 与这个变量之前的值无关 Independent of what value it had before, 117 00:06:52,800 --> 00:06:55,792 SET!改变了它的值 set! changes the value of the variable. 118 00:06:57,696 --> 00:06:58,750 在此之前 Until this moment, 119 00:06:58,750 --> 00:07:01,504 什么都没有发生改变 we had nothing that changed. 120 00:07:03,216 --> 00:07:04,112 举例来说 So, for example, 121 00:07:04,848 --> 00:07:06,230 我们可以想到的一件事是 one of the things we can think of 122 00:07:06,230 --> 00:07:09,420 我们写的一些过程 比如阶乘的程序 is that the procedures we write for something like factorial 123 00:07:09,648 --> 00:07:12,752 事实上与数学中的阶乘函数完全相同 are in fact pretty much identical to the function factorial. 124 00:07:13,776 --> 00:07:16,448 比如说4的阶乘 如果我写FACT(4) Factorial of four, if I write fact4, 125 00:07:17,232 --> 00:07:19,152 无论它的上下文是怎样的 independent of what context it's in, 126 00:07:19,696 --> 00:07:21,290 无论我写几遍 and independent of how many times I write it, 127 00:07:21,290 --> 00:07:22,352 我总能得到同样的结果 I always get the same answer. 128 00:07:23,290 --> 00:07:24,128 结果永远是24 It's always 24. 129 00:07:25,376 --> 00:07:28,928 它是参数到到结果的唯一映射 It's a unique map from the argument to the answer. 130 00:07:30,304 --> 00:07:32,656 迄今为止 我们之前写的所有程序都是这样的 And all the programs we've written so far are like that. 131 00:07:33,520 --> 00:07:36,032 然而 当引入赋值后 一切就不同了 However, once I have assignment, that isn't true. 132 00:07:36,960 --> 00:07:38,160 举个例子 So, for example, 133 00:07:39,184 --> 00:07:48,528 如果我将COUNT定义为1 if I were to define count to be one. 134 00:07:50,000 --> 00:07:52,416 然后定义一个过程 And then I'm going to define also a procedure, 135 00:07:55,168 --> 00:07:56,832 一个叫做DEMO的简单过程 a simple procedure called demo, 136 00:07:59,520 --> 00:08:03,840 它接受参数X 并执行下面的操作 which takes argument x and does the following operations. 137 00:08:03,840 --> 00:08:09,620 首先将X修改为X+1 It first sets x to x plus one. 138 00:08:09,620 --> 00:08:11,776 我的天啊! 这看起来就像FORTRAN是吧? My gosh, this looksjust like FORTRAN, right-- 139 00:08:13,168 --> 00:08:14,176 只是用了些有趣的语法 in a funny syntax. 140 00:08:16,800 --> 00:08:21,376 然后返回(+ X COUNT) And then add to x count, 141 00:08:22,144 --> 00:08:24,144 哦 我刚犯了个错 Oh, I just made a mistake. 142 00:08:24,384 --> 00:08:25,232 我的意思是 I want to say, 143 00:08:25,472 --> 00:08:27,120 (SET! COUNT (1+ COUNT)) set! count to one plus count. 144 00:08:30,370 --> 00:08:31,792 就是我在这里定义的这个 It's this thing defined here. 145 00:08:34,416 --> 00:08:36,512 然后X和COUNT相加 And then add and said plus x count. 146 00:08:40,352 --> 00:08:42,064 然后就可以试着运行这个过程了 Then I can try this procedure. 147 00:08:42,480 --> 00:08:43,200 让我们运行它 Let's run it. 148 00:08:43,920 --> 00:08:47,220 假设我可以输入 So, suppose I get a prompt and I say, 149 00:08:47,488 --> 00:08:48,688 输入(DEMO 3) demo 3 150 00:08:52,192 --> 00:08:53,200 这里发生了什么? Well, what happens here? 151 00:08:53,740 --> 00:08:55,280 发生的第一件事情是 The first thing that happens 152 00:08:55,536 --> 00:08:56,890 COUNT现在是1 is count is currently one. 153 00:08:56,890 --> 00:08:58,400 现在 这是一个时间点 Currently, there is a time. 154 00:08:59,120 --> 00:09:00,290 我们在讨论时间点 We're talking about time. 155 00:09:00,624 --> 00:09:01,744 X的值为3 x gets three. 156 00:09:02,928 --> 00:09:04,032 在这个时刻 At this moment, 157 00:09:04,672 --> 00:09:07,536 COUNT增加了 所以COUNT是2 I say, oh yes, count is incremented, so count is two. 158 00:09:09,024 --> 00:09:10,448 2加3等于5 two plus three is five. 159 00:09:10,800 --> 00:09:12,432 所以结果是5 So the answer I get out is five. 160 00:09:14,480 --> 00:09:21,584 然后我再一次 输入(DEMO 3) Then I say, demo of say, three again. 161 00:09:23,600 --> 00:09:24,560 结果是什么? Okay, What do I get? 162 00:09:24,830 --> 00:09:27,408 现在COUNT是2 它不再是1了 Well, now count is two, it's not one anymore, 163 00:09:28,912 --> 00:09:30,352 因为我让COUNT加1了 because I have incremented it. 164 00:09:30,920 --> 00:09:32,640 但现在我执行这个过程 But now I go through this process, 165 00:09:32,720 --> 00:09:33,664 X的值为3 three goes into x, 166 00:09:34,176 --> 00:09:37,408 COUNT变为1+COUNT 因此现在是3了 count becomes one plus count, so that's three now. 167 00:09:38,080 --> 00:09:39,620 这两个相加是6 The sum of those two is six, 168 00:09:39,620 --> 00:09:40,944 所以结果是6 so the answer is six. 169 00:09:41,920 --> 00:09:43,030 我们可以发现 And what we see 170 00:09:43,030 --> 00:09:44,720 同样的表达式 is the same expression 171 00:09:45,088 --> 00:09:46,640 因为时间节点的不同 leads to two different answers, 172 00:09:48,752 --> 00:09:49,968 得到了不同的结果 depending upon time. 173 00:09:52,080 --> 00:09:53,744 所以DEMO不是函数 So demo is not a function, 174 00:09:54,176 --> 00:09:56,128 或者说它并没有计算一个数学意义上的函数 does not compute a mathematical function. 175 00:09:59,888 --> 00:10:02,096 事实上 你可以知道这是为什么 In fact, you could also see why now, of course, 176 00:10:02,848 --> 00:10:06,416 因为这里是第一处代换模型失效的地方 this is the first place where the substitution model isn't going to work. 177 00:10:07,728 --> 00:10:09,552 它给代换模型判了死刑 This kills the substitution model dead. 178 00:10:11,280 --> 00:10:13,824 有些关于引用的一些小问题 You know, with quotation there were some little problems 179 00:10:13,856 --> 00:10:17,180 哲学家可能注意到 特别是与代换有关时 that a philosopher might notice with substitutions, 180 00:10:17,180 --> 00:10:19,872 因为当你在引用中进行代换时 because you have to worry about what deductions you can make 181 00:10:20,912 --> 00:10:22,128 需要考虑你可以得到什么样的推论 when you substitute into quotes, 182 00:10:22,340 --> 00:10:23,920 如果你能够使用代换的话 if you're allowed to do that at all. 183 00:10:25,088 --> 00:10:25,600 但是 But 184 00:10:26,064 --> 00:10:28,000 在这里代换模型已经失效了 here the substitution model is dead, 185 00:10:28,110 --> 00:10:29,408 它什么也不能做了 can't do anything at all. 186 00:10:29,640 --> 00:10:30,570 因为 Because, 187 00:10:30,570 --> 00:10:35,856 假设我想用代换模型来考虑COUNT的代换 Supposing I wanted to use a substitution model to consider substituting for count? 188 00:10:37,104 --> 00:10:41,168 如果我在这里和这里进行代换 Well, my gosh, if I substitute for here and here, 189 00:10:41,696 --> 00:10:42,960 它们是不同的 they're different ones. 190 00:10:44,448 --> 00:10:45,968 它不再是同一个COUNT了 It's not the same count any more. 191 00:10:46,480 --> 00:10:47,648 我得到了错误的结果 I get the wrong answer. 192 00:10:47,970 --> 00:10:50,144 代换模型是一个静态的现象 The substitution model is a static phenomenon 193 00:10:51,184 --> 00:10:52,560 它描述的事实 describes things that are true 194 00:10:53,936 --> 00:10:55,296 而不是变动 and not things that change. 195 00:10:55,500 --> 00:10:57,040 这里 我们的事实变动了 Here, we have truths that change. 196 00:11:00,608 --> 00:11:06,740 那么 在我给出任何解释之前 OK, Well, before I give you any understanding of this, 197 00:11:06,740 --> 00:11:07,790 这很糟糕 this is very bad. 198 00:11:07,790 --> 00:11:09,728 我们失去了我们的计算模型 Now, we've lost our model of computation. 199 00:11:10,288 --> 00:11:10,800 并且 And, 200 00:11:11,488 --> 00:11:13,696 很快 我将不得不构建一个新的计算模型 pretty soon, I'm going to have to build you a new model of computation. 201 00:11:14,660 --> 00:11:17,872 我们现在的讨论 还是从一个不严谨的角度进行的 But ours plays with this, just now, in an informal sense. 202 00:11:18,560 --> 00:11:20,160 当然 你们已经看到的是 Of course, what you already see 203 00:11:20,512 --> 00:11:22,704 当我做一些像赋值之类的事情时 is that when I have something like assignment, 204 00:11:23,120 --> 00:11:24,510 我们所需要的模型 the model that we're going to need 205 00:11:24,510 --> 00:11:26,890 与我们之前模型不同 is different from the model that we had before 206 00:11:26,890 --> 00:11:30,930 在这个的模型中 像COUNT或X这样的符号 in that, the variables, those symbols like count, or x 207 00:11:30,930 --> 00:11:34,070 不再关联于它们的值 are no longer going to refer to the values they have, 208 00:11:34,070 --> 00:11:37,312 而是关联于某个储存这些值的地方 but rather to some sort of place where the value restored. 209 00:11:37,680 --> 00:11:39,472 我们将花些时间来适应这种思想 We're going to have to think that way for a while. 210 00:11:40,208 --> 00:11:42,110 这将是一个很糟糕的事情 And it's going to be a very bad thing 211 00:11:42,110 --> 00:11:43,472 并且会造成很多麻烦 and cause a lot of trouble. 212 00:11:44,496 --> 00:11:48,250 所以 就像我说的 若非理由周全 And so, as I said, the very fact that we're inventing this bad thing, 213 00:11:48,250 --> 00:11:50,096 不然绝不要发明这种糟糕的东西 means that there had better be a good reason for it, 214 00:11:50,370 --> 00:11:52,864 否则 就是劳神费力 otherwise, just a waste of time and a lot of effort. 215 00:11:53,392 --> 00:11:55,552 让我们看看一些可以讨论的东西 Let's just look at some of it just to play. 216 00:11:55,880 --> 00:11:58,590 假设我们写了函数式版本的阶乘函数 Supposing we write down the functional version, 217 00:11:58,590 --> 00:12:00,480 我们以前的就是“函数式”风格 functional meaning in the old style, 218 00:12:01,376 --> 00:12:04,608 具有迭代计算过程的阶乘函数 of factorial by an iterative process. 219 00:12:09,590 --> 00:12:13,280 N的阶乘 Factorial of n. 220 00:12:18,384 --> 00:12:24,352 我们要(ITER M I) we're going to iterate of m and i, 221 00:12:26,128 --> 00:12:33,136 就是说如果I大于N which says if i is greater than n, 222 00:12:33,776 --> 00:12:35,510 则结果是M then the result is m, 223 00:12:36,304 --> 00:12:37,392 否则 otherwise, 224 00:12:39,792 --> 00:12:46,820 结果是(ITER (* I M)) the result of iterating the product of i and m. 225 00:12:46,820 --> 00:12:49,952 所以M将是我累积的结果 So m is going to be the product that I'm accumulating. 226 00:12:51,584 --> 00:12:52,624 M就是这个乘积[注:此处教授笔误] m is the product. 227 00:12:57,970 --> 00:13:00,176 然后我要把COUNT加1 And the count I'm going to increase by one. 228 00:13:04,620 --> 00:13:10,976 (闭合括号中) Plus, ITER, ELSE, COND, define. 229 00:13:11,952 --> 00:13:13,040 我在这里启动这个内部过程 I'm going to start this up. 230 00:13:17,168 --> 00:13:19,792 对于这种代码 我想大家早已驾轻就熟了 And these days, you should have no trouble reading something like this. 231 00:13:20,864 --> 00:13:25,152 这里是一个累积的乘积 和一个计数器 What I have here is a product there being accumulated and a counter. 232 00:13:26,480 --> 00:13:28,464 我让它们都从1开始 I start them up both at one. 233 00:13:28,896 --> 00:13:30,920 我将不断让计数器增加 I'm going to buzz the counter up, 234 00:13:30,920 --> 00:13:33,120 每一轮I变成I+1 i goes to i plus one every time around. 235 00:13:34,560 --> 00:13:37,472 这是我们在这个过程中设置时间的唯一方法 But that's only way our putting a time on the process, 236 00:13:38,480 --> 00:13:40,048 这些都是一系列的事实 each of this is just a set of truths, 237 00:13:40,496 --> 00:13:41,344 真实的规则 true rules. 238 00:13:42,816 --> 00:13:46,130 M将获得一个新的值 就是I乘M And m is going to get a new values of i and m, 239 00:13:46,130 --> 00:13:47,824 每一轮I乘以M i times m each time around, 240 00:13:48,680 --> 00:13:50,480 最终I将大于N and eventually i is going to be bigger than n, 241 00:13:50,496 --> 00:13:52,060 在这种情况下 结果就是M in which case, the answer's going to be m. 242 00:13:52,672 --> 00:13:54,800 我给你们讲课的时候 用到了“时间”这个概念 Now, I'm speaking to you, use time in this. 243 00:13:55,680 --> 00:13:57,456 那是因为我知道计算机是怎么工作的 That's just because I know how the computer works. 244 00:13:58,256 --> 00:13:59,248 但是我没必要这么做 But I didn't have to. 245 00:13:59,264 --> 00:14:02,300 这完全可以有一个纯数学的解释 This could be a purely mathematical description at this point, 246 00:14:02,300 --> 00:14:03,744 因为在这里代换可以工作 because substitution will work for this. 247 00:14:05,104 --> 00:14:08,140 但是我们写一个类似的程序 But let's set right down a similar sort of program, 248 00:14:08,304 --> 00:14:09,952 使用相同的算法 using the same algorithm, 249 00:14:10,736 --> 00:14:12,112 但使用了赋值 but with assignments. 250 00:14:15,696 --> 00:14:17,168 所以这个叫做函数式版本 So this is called the functional version. 251 00:14:23,728 --> 00:14:25,568 我想写个命令式的版本的 I want to write down an imperative version. 252 00:14:34,480 --> 00:14:35,392 N的阶乘 Factorial of n. 253 00:14:35,920 --> 00:14:37,744 我要创建两个变量 I'm going to create my two variables. 254 00:14:40,160 --> 00:14:45,536 把I的值初始化为1 Let i initialize itself to one, 255 00:14:46,320 --> 00:14:49,776 M也初始化为1 and m be initialized to one, similar. 256 00:14:51,152 --> 00:14:52,192 我们创建一个循环 We'll create a loop 257 00:14:59,312 --> 00:15:07,270 如果I比N大 循环结束 which has COND greater than i, and if i is greater than n, we're done. 258 00:15:07,270 --> 00:15:08,870 结果是M And the result is m, 259 00:15:08,870 --> 00:15:10,384 也就是我累积的乘积 the product I'm accumulating. 260 00:15:10,870 --> 00:15:11,776 否则 Otherwise, 261 00:15:15,520 --> 00:15:17,408 我接下来要做三件事 I'm going to write down three things to do. 262 00:15:19,264 --> 00:15:27,056 我要把M赋值为I*M I'm going to set! m to the product of i and m, 263 00:15:29,360 --> 00:15:35,200 把I赋值为I+1 set! i to the sum of i and one, 264 00:15:37,856 --> 00:15:39,312 然后继续循环 and go around the loop again. 265 00:15:40,410 --> 00:15:43,024 你们中的FORTRAN程序员应该觉得眼熟 Looks very familiar to you FORTRAN programmers. 266 00:15:44,736 --> 00:15:46,640 (闭合括号中) ELSE, COND, define, 267 00:15:46,640 --> 00:15:47,888 就是这种语法有点陌生 funny syntax though. 268 00:15:51,136 --> 00:15:52,272 启动循环 Start the loop up, 269 00:15:56,100 --> 00:15:57,568 程序就写完了 and that's the program. 270 00:15:59,152 --> 00:16:00,528 那么 这个程序 Now, this program, 271 00:16:01,312 --> 00:16:02,496 我们应该怎么思考它呢? how do we think about it? 272 00:16:02,710 --> 00:16:04,256 先来看看这里是什么 Well, let's just say what we're seeing here. 273 00:16:04,848 --> 00:16:07,470 这里有两个局部变量 I和M There are two local variables, i and m, 274 00:16:07,470 --> 00:16:09,024 它们都被初始化为1 that have been initialized to one. 275 00:16:10,720 --> 00:16:13,890 在每一次循环里 我检测I是否大于N Every time around the loop, I test to see if i is greater than n, 276 00:16:13,890 --> 00:16:15,088 就是我们传入的参数 which is the input argument, 277 00:16:15,300 --> 00:16:18,144 如果成立的话 结果就是M中所累积的乘积 and if so, the result is the product being accumulated in m. 278 00:16:19,168 --> 00:16:21,210 然而 如果循环没有结束 However, if it's not the end of the loop, 279 00:16:21,210 --> 00:16:22,896 如果我们的工作没有结束 if I'm not done, 280 00:16:23,640 --> 00:16:25,552 则我们要把乘积 then what I'm going to do is change the product 281 00:16:25,840 --> 00:16:28,384 变为i与当前乘积的结果 to be the result of multiplying i times the current product. 282 00:16:29,040 --> 00:16:30,688 就是我们在这里做过的事情 Which is sort of what we were doing here. 283 00:16:31,424 --> 00:16:32,688 除了这里我没有改动 Except here I wasn't changing. 284 00:16:33,632 --> 00:16:35,776 我创建了一个复本 I was making another copy, 285 00:16:36,816 --> 00:16:42,048 因为代换模型就是你复制过程的体 because the substitution model says, you copy the body of the procedure 286 00:16:43,088 --> 00:16:45,888 并用实际参数代换形式参数 with the arguments substituted for the formal parameters. 287 00:16:46,720 --> 00:16:48,420 这里 我考虑的不是副本 Here I'm not worried about copying, 288 00:16:48,420 --> 00:16:50,528 在这里 我已经改变了M的值 here I've changed the value of m. 289 00:16:51,808 --> 00:16:55,120 我也把I的值变成了I+1 I also then change the value of i to i plus one, 290 00:16:55,616 --> 00:16:56,960 然后继续循环 and go buzzing around. 291 00:16:58,224 --> 00:17:00,080 看起来是一样的程序 Seems like essentially the same program, 292 00:17:00,960 --> 00:17:02,840 在今天引入赋值之后 but there are some ways of making errors here 293 00:17:02,840 --> 00:17:05,504 我们在这里有很多种方式犯错 that didn't exist until today. 294 00:17:06,144 --> 00:17:07,024 例如 For example, 295 00:17:07,456 --> 00:17:09,408 如果我在赋值的时候 if I were to do the horrible thing 296 00:17:10,048 --> 00:17:12,144 没有小心地写程序 of not being careful in writing my program 297 00:17:12,640 --> 00:17:16,080 把两个赋值的顺序调换了 and interchange those two assignments, 298 00:17:17,104 --> 00:17:18,912 程序计算的就不是相同的函数了 the program wouldn't compute the same function. 299 00:17:20,336 --> 00:17:22,870 我得到了一个时间错误 因为这儿有个依赖关系 I get a timing error because there's a dependency 300 00:17:22,870 --> 00:17:27,220 因为M依赖于I上一次的值 that m depends upon having the last value of i. 301 00:17:27,344 --> 00:17:28,928 如果我先改变I的值 If I try change i first, 302 00:17:31,312 --> 00:17:33,776 就会在乘以M的时候 得到错误的I值 then I've got the wrong value of i when I multiply by m. 303 00:17:35,968 --> 00:17:38,380 没有赋值的话不会存在这样的BUG It's a bug that wasn't available until this moment, 304 00:17:38,380 --> 00:17:40,592 这是由于我们引入了某些包含时间的东西造成的 until we introduced something that had time in it. 305 00:17:43,440 --> 00:17:44,304 如我所说的 So, as I said, 306 00:17:45,536 --> 00:17:47,390 首先 我们需要一个新的计算模型 first we need a new model of computation, 307 00:17:47,390 --> 00:17:50,864 然后 需要有一个非常好的理由来支持我们做如此丑陋的事 and second, we have to be damn good reason for doing this kind of ugly thing. 308 00:17:52,720 --> 00:17:53,744 有什么问题吗? Are there any questions? 309 00:17:58,832 --> 00:18:00,224 David 大点儿声说 Speak loudly, David 310 00:18:00,400 --> 00:18:03,472 学生:现在 我们引入了SET! AUDIENCE: I'm confused about, we've introduced set now, 311 00:18:03,904 --> 00:18:06,368 但是之前我们已经有LET和DEFINE了 but we had let before and define before. 312 00:18:06,896 --> 00:18:09,700 我不太清楚它们的区别 I'm confused about the difference between the three. 313 00:18:09,700 --> 00:18:13,250 DEFINE不能像SET!一样用吗? Wouldn't define work in the same situation as set! 314 00:18:13,984 --> 00:18:14,830 请详细讲讲 if you introduced it a bit? 315 00:18:14,830 --> 00:18:19,310 教授:不 DEFINE用于创建并初始化 PROFESSOR: No, define is intended for setting something once the first time, 316 00:18:19,310 --> 00:18:21,360 为了创建它 for making it, OK? 317 00:18:22,080 --> 00:18:24,704 你永远也不会见到我在黑板上 You've never seen me write on a blackboard 318 00:18:25,600 --> 00:18:26,944 在同一行写两个DEFINE two defines in a row 319 00:18:27,088 --> 00:18:32,080 只是为了让某个变量的旧值变成一个新的值 whose intention was to change the old value of some variable to a new one. 320 00:18:32,080 --> 00:18:34,510 学生:这是一个约定俗成的规矩 还是-- AUDIENCE: Is that by convention or-- 321 00:18:34,510 --> 00:18:36,350 教授:不 这是有意为之的 PROFESSOR: No, it's intention. 322 00:18:36,350 --> 00:18:38,928 答案是 Okay? The answer is, 323 00:18:39,696 --> 00:18:40,840 举个例子 that, for example, 324 00:18:40,840 --> 00:18:42,272 在一个过程内部 internal to a procedure, 325 00:18:43,200 --> 00:18:45,920 两个DEFINE写在一行里是非法的 two defines in a row are illegal, 326 00:18:46,688 --> 00:18:48,576 对于同一个变量DEFINE两次是非法的 two defines in a row of the same variable. 327 00:18:50,240 --> 00:18:51,740 X不能被DEFINE两次 x can't be defined twice. 328 00:18:51,740 --> 00:18:55,200 而系统会不会捕获这个错误 就是另一个问题了 Whether or not a system catches that error is a different question, 329 00:18:55,936 --> 00:18:57,888 但是我定下规矩 but I legislate to you 330 00:18:58,120 --> 00:19:00,640 任何东西都只能DEFINE一次 that define happens once on anything. 331 00:19:00,736 --> 00:19:02,640 确实 在交互式调试中 Now, indeed, in interactive debugging, 332 00:19:03,376 --> 00:19:07,488 我们打算让你与计算机交互时可以重新DEFINE一些东西 we intend that you interacting with your computer will redefine things, 333 00:19:08,192 --> 00:19:11,216 所以交互式调试时产生的是一个特殊的异常 and so there's a special exception made for interactive debugging. 334 00:19:11,824 --> 00:19:16,480 但是DEFINE的意思是建立某些东西 But define is intended to mean to set up something 335 00:19:18,144 --> 00:19:20,960 在那个时间点后 它的值是永远不变的 which will be forever that value after that point. 336 00:19:22,050 --> 00:19:24,544 好像所有的DEFINE都是在最开始完成的 It's as if all the defines were done at the beginning. 337 00:19:26,090 --> 00:19:30,928 事实上 在Scheme过程中 DEFINE的唯一合法使用地方 In fact, the only legal place to put a define in Scheme internal to a procedure 338 00:19:31,024 --> 00:19:33,360 就是在LAMBDA表达式的开始 is just at the beginning of a lambda expression, 339 00:19:34,470 --> 00:19:37,664 也就是过程体的开始 which is the beginning of the body of a procedure. 340 00:19:40,400 --> 00:19:45,808 LET当然与那个不一样 Now, let of course does nothing like either of that. 341 00:19:48,096 --> 00:19:49,552 如果你想知道LET发生了什么 I mean, if you look at what's happening with a let, 342 00:19:50,176 --> 00:19:52,130 LET只会绑定一次 this happens again exactly once. 343 00:19:52,130 --> 00:19:55,824 它建立了一个I和M的值分别为1的上下文 It sets up a context where i and m are values one and one. 344 00:19:56,832 --> 00:20:00,576 这个上下文存在于整个作用域中 That context exists throughout this scope, 345 00:20:01,310 --> 00:20:02,800 也就是这个程序范围 this region of the program. 346 00:20:04,992 --> 00:20:10,128 然而 你不会认为LET再次设置了I的值 However, you don't think of that let as setting i again. 347 00:20:11,040 --> 00:20:12,160 它没有改变I的值 It doesn't change it. 348 00:20:12,160 --> 00:20:14,016 因为LET的作用 I将永远不会变化 i never changes because of the let. 349 00:20:15,280 --> 00:20:16,816 因为LET的作用 I才被创建 i gets created because of let. 350 00:20:18,512 --> 00:20:19,296 实际上 In fact, 351 00:20:19,730 --> 00:20:21,424 LET是一个非常简单的想法 the let is a very simple idea. 352 00:20:22,240 --> 00:20:23,590 LET不会做别的事情 Let does nothing more, 353 00:20:23,590 --> 00:20:31,620 LET的语义是…… Let a variable one to have value one 354 00:20:31,620 --> 00:20:33,504 我把它写得更准确点 I'll write this down a little bit more neatly; 355 00:20:37,160 --> 00:20:43,730 表达式 (var1 e1) Let's write, var one have value, the value of expression e1, 356 00:20:43,730 --> 00:20:47,360 还有(var2 e2) and variable two, have this value of the expression e2, 357 00:20:48,144 --> 00:20:49,744 在表达式e3中 in an expression e3, 358 00:20:51,600 --> 00:21:05,808 与一个以var1和var2为形式参数的过程一样 is the same thing as a procedure of var one and var two, the formal parameters, 359 00:21:06,944 --> 00:21:08,960 e3成为过程的体 and e3 being the body, 360 00:21:10,912 --> 00:21:14,000 在这里 var1与e1的值绑定 where var one is bound to the value of e1, 361 00:21:14,270 --> 00:21:16,912 var2与e2的值绑定 and var two gets the value of e2. 362 00:21:19,536 --> 00:21:23,264 所以实际上 这是一个从代换的角度来看很容易理解的东西 So this is, in fact, a perfectly understandable thing from a substitution point of view. 363 00:21:24,896 --> 00:21:27,952 其实就是同一个表达式的两种不同的写法 This is really the same expression written in two different ways. 364 00:21:31,690 --> 00:21:33,504 事实上 系统真正的工作方式 In fact, the way the actual system works 365 00:21:33,632 --> 00:21:35,820 就是在运行之前把代码翻译成这种形式 is this gets translated into this before anything happens. 366 00:21:37,648 --> 00:21:41,770 学生:我还是不清楚是什么造成了LET和DEFINE之间的区别 AUDIENCE: OK, I'm still unclear as then what makes the difference between a let and a define. They could-- 367 00:21:41,770 --> 00:21:44,304 教授:DEFINE就是个语法糖 PROFESSOR: A define is a syntactic sugar, 368 00:21:44,624 --> 00:21:49,104 本质上来说 是通过LET创建一系列变量 然后给它们一次性赋值 whereby, essentially a bunch of variables get created by lets and then set up once. 369 00:21:57,104 --> 00:21:59,744 好吧 我们休息一会 OK, time for the first break, I think. Thank you. 370 00:22:02,520 --> 00:22:12,848 [音乐] [JESU, JOY OF MAN'S DESIRING] 371 00:22:12,840 --> 00:22:17,840 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 372 00:22:48,810 --> 00:22:52,672 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 373 00:22:52,670 --> 00:22:56,528 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 374 00:22:56,520 --> 00:23:00,592 赋值、状态和副作用 Assignment, State, and Side-effects 375 00:23:04,288 --> 00:23:06,112 看 Well let's see. 376 00:23:06,448 --> 00:23:09,088 现在 我不得不重建计算模型 I now have to rebuild the model of computation, 377 00:23:09,776 --> 00:23:14,160 使得你能够明白那些机制是如何运作的 so you understand how some such mechanical mechanism could work 378 00:23:14,912 --> 00:23:16,464 来完成我们刚才说的那些工作 that can do what we've just talked about. 379 00:23:17,536 --> 00:23:21,392 我刚刚摧毁了你们的代换模型 I just recently destroyed your substitution model. 380 00:23:22,624 --> 00:23:26,032 不幸的是 这个模型比代换模型要复杂得多 Unfortunately, this model is significantly more complicated than the substitution model. 381 00:23:26,624 --> 00:23:27,936 这个模型叫环境模型 It's called the environment model. 382 00:23:29,024 --> 00:23:31,200 我即将介绍一些术语 And I'm going to have to introduce some terminology, 383 00:23:32,032 --> 00:23:34,510 无论如何 你知道这些术语都是很好的 which is very good terminology for you to know anyway. 384 00:23:34,510 --> 00:23:35,744 它是关于名字的 It's about names. 385 00:23:36,510 --> 00:23:39,632 我们要给事物的各种名字 And we're going to give names to the kinds of names things have 386 00:23:40,000 --> 00:23:41,310 和名字的使用途径以名字 and the way those names are used. 387 00:23:42,480 --> 00:23:47,940 如果硬要说的话 这是一个元描述 So this is a meta-description, if you will. 388 00:23:48,560 --> 00:23:50,850 总之 这里面有一堆糟糕的术语 Anyway, there is a pile of an unfortunate terminology here, 389 00:23:50,850 --> 00:23:53,760 但我们需要利用它们来理解所谓的“环境模型” but we're going to need this to understand what's called the environment model. 390 00:23:54,704 --> 00:23:57,536 我们可能要做一点无聊的事情了 We're about to do a little bit of boring, dog-work here. 391 00:23:58,040 --> 00:24:01,584 我们来看第一张幻灯片 Let's look at the first transparency. 392 00:24:02,256 --> 00:24:06,976 我们看到了术语“约束”的解释 And we see a description of a word called bound. 393 00:24:08,800 --> 00:24:11,000 我们会说一个变量V And we're going to say that a variable, v, 394 00:24:11,000 --> 00:24:12,912 被约束在表达式E中 is bound in an expression, e, 395 00:24:13,410 --> 00:24:21,520 如果用一个没有出现在E中的变量W 对变量V统一换名 if the meaning of e is unchanged by the uniform replacement of a variable w, 396 00:24:21,560 --> 00:24:24,288 表达式语义没有发生改变 not occurrent if for every occurrence of v in e. 397 00:24:25,696 --> 00:24:27,008 这个解释很长 Now that's a long sentence, 398 00:24:27,370 --> 00:24:29,968 在我们在被搞糊涂之前 so, I think, I'm going to have to say a little bit about that 399 00:24:29,984 --> 00:24:32,620 我应该再多解释下 before we even fool around at all here. 400 00:24:33,424 --> 00:24:35,280 我们这里讨论的约束变量 Bound variables we're talking about here. 401 00:24:44,160 --> 00:24:45,568 你们已经看到它们很多次了 And you've seen lots of them. 402 00:24:46,070 --> 00:24:48,176 只是你们可能还没意识到 You may not know that you've seen lots of them. 403 00:24:48,240 --> 00:24:52,240 在逻辑学中 你们看到一个逻辑变量 Well, I suppose in your logic, you saw a logical variables like, 404 00:24:53,270 --> 00:25:00,112 就像微积分课上的 对于任意任何X 存在一个Y 使得P为真 for every x there exists a y such that p is true of x and y from your calculus class. 405 00:25:02,880 --> 00:25:05,824 这个变量X 这个变量Y 它们是约束变量 This variable, x, and this variable, y, are bound, 406 00:25:07,088 --> 00:25:07,920 因为 because, 407 00:25:08,336 --> 00:25:09,980 这个表达式的含义 the meaning of this expression 408 00:25:09,980 --> 00:25:15,616 不取决于我用来描述X和Y的具体字母 does not depend upon the particular letters I used to describe x and y. 409 00:25:16,496 --> 00:25:19,184 如果我用W替换X If I were to change the w for x, 410 00:25:19,840 --> 00:25:25,680 则可以说对于任意W 存在一个Y使得P为真 then said for every w there exists a y such that p is true of w and y, 411 00:25:25,984 --> 00:25:27,088 它们其实是同一句话 it would be the same sentence. 412 00:25:29,440 --> 00:25:30,340 就是这个意思 That's what it means. 413 00:25:30,340 --> 00:25:34,896 又或者说 你们看到这样一个积分 Or another case of this that you've seen is integral say, 414 00:25:35,408 --> 00:25:42,656 对dx/(1+x^2)从0到1积分 from 0 to one of dx over one plus x square. 415 00:25:46,032 --> 00:25:47,920 这就是你们经常见到的那种东西 Well that's something you see all the time. 416 00:25:47,920 --> 00:25:50,928 这个x是一个约束变量 And this x is a bound variable. 417 00:25:52,064 --> 00:25:53,792 如果我把它换成t If I change that to a t, 418 00:25:54,150 --> 00:25:56,256 这个表达式其实没有变化 the expression is still the same thing. 419 00:25:58,060 --> 00:26:02,768 就是arctan(1)/4之类的 This is a 1/4 of the arctan of one or something here, something like that. 420 00:26:04,704 --> 00:26:06,016 是的 就是arctan(1) Yes, that's the arctan of one. 421 00:26:06,624 --> 00:26:08,768 所以约束变量事实上很常见 So bound variables are actually fairly common, 422 00:26:09,080 --> 00:26:12,368 如果你们接触过一些数学的话 for those of you who have played a bit with mathematics. 423 00:26:13,264 --> 00:26:17,472 好 让我们来到编程的世界 Well, let's go into the programming world. 424 00:26:19,024 --> 00:26:21,360 现在量词不再是 Instead of the quantifier being something like, 425 00:26:22,032 --> 00:26:24,060 所有、存在和积分 for every, or there exists, or integral, 426 00:26:24,060 --> 00:26:26,432 我们有一个符号作为量词 用于约束变量 a quantifier is a symbol that binds a variable. 427 00:26:27,472 --> 00:26:28,992 我们要使用量词LAMBDA And we are going to use the quantifier lambda 428 00:26:29,792 --> 00:26:31,808 作为约束变量的一个必要的东西 as being the essential thing that binds variables. 429 00:26:33,808 --> 00:26:36,128 我们有一个极好的例子 And so we have some nice examples here 430 00:26:36,592 --> 00:26:44,140 对于以Y为参数的过程 做了以下的事情 like that procedure of one argument y which does the following thing. 431 00:26:44,140 --> 00:26:46,960 它调用一个含单个参数X的过程 It calls the procedure of one argument x, 432 00:26:47,872 --> 00:26:51,136 该过程 将X乘以Y which multiplies x by y, 433 00:26:52,880 --> 00:26:54,528 并应用于3 and applies that to three. 434 00:26:58,768 --> 00:27:01,664 这个过程中包含两个约束变量 That procedure has the property there of two bound variables in it, 435 00:27:02,016 --> 00:27:02,928 X和Y x and y 436 00:27:04,832 --> 00:27:07,472 这个LAMBDA量词 约束了这个Y This quantifier, lambda here, binds this y, 437 00:27:07,910 --> 00:27:10,784 这个LAMBDA量词 约束了这个X and this quantifier, lambda, binds that x. 438 00:27:12,112 --> 00:27:17,056 因为 如果我用了一个没有出现在表达式中的任意符号 如W Because, if I were to take an arbitrary symbol does not occur in this expression like w 439 00:27:17,984 --> 00:27:21,040 用W替换表达式中的所有Y and replace all y's with w's in this expression, 440 00:27:21,360 --> 00:27:22,752 这个表达式仍与原来的相同 the expression is still the same, 441 00:27:23,664 --> 00:27:24,800 是相同的过程 the same procedure. 442 00:27:26,224 --> 00:27:27,410 这是一个重要的想法 And this is an important idea. 443 00:27:27,410 --> 00:27:29,648 我们有这种东西的原因 The reason why we had such things like that 444 00:27:30,208 --> 00:27:31,410 这是一种模块性 is a kind of modularity. 445 00:27:31,410 --> 00:27:32,864 如果有两个人写程序 If two people are writing programs, 446 00:27:34,032 --> 00:27:35,260 并且他们在合作编程 and they work together, 447 00:27:35,260 --> 00:27:40,560 在他们自己构建的小项目里用什么命名都没有关系 it shouldn't matter what names they use internal to their own little machines that they're building. 448 00:27:42,832 --> 00:27:44,672 所以 实际上我想告诉你们 And so, what I'm really telling you there, 449 00:27:45,440 --> 00:27:46,752 例如 is that, for example, 450 00:27:46,840 --> 00:27:51,264 这个表达式等于 以Y为参数的过程 this is equivalent to that procedure of one argument y which 451 00:27:52,352 --> 00:27:59,232 使用这个对于一个参数Z的过程 这个过程将Z乘以Y uses that procedure of one argument z which multiplies z by y. 452 00:28:01,648 --> 00:28:03,536 因为没人关心我在这用什么 Because nobody cares what I used in here. 453 00:28:06,368 --> 00:28:07,248 这是一个极好的例子 It's a nice example. 454 00:28:08,848 --> 00:28:09,856 另一方面 On the other hand, 455 00:28:11,072 --> 00:28:14,336 我有一些未被约束的变量 I have some variables that are not bound. 456 00:28:15,232 --> 00:28:15,968 举个例子 And example, 457 00:28:20,272 --> 00:28:21,760 这个对于一个以X为参数的过程 that procedure of one argument x 458 00:28:22,096 --> 00:28:25,040 将X乘以Y which multiplies x by y 459 00:28:27,280 --> 00:28:28,160 在这个例子中 In this case, 460 00:28:29,456 --> 00:28:30,752 y没有被约束 y is not bound. 461 00:28:32,464 --> 00:28:34,272 假设Y的值是3 Supposing y had the value three, 462 00:28:35,264 --> 00:28:36,800 Z的值是4 and z had the value four, 463 00:28:38,832 --> 00:28:44,272 那么这个过程就是把它的参数乘以3 then this procedure would be the thing that multiplies its argument by three. 464 00:28:44,864 --> 00:28:47,392 如果我把所有的y都用z来代替 If I were to replace every instance of y with z, 465 00:28:47,520 --> 00:28:51,968 我将得到一个完全不同的过程 它会把参数乘以4 I would have a different procedure which multiplies every argument that's given by four. 466 00:28:53,872 --> 00:28:56,400 事实上 我们给这类变量取了个名字 And, in fact, we have a name for such a variable. 467 00:28:57,760 --> 00:29:04,010 我们把表达式E中的变量V叫做自由变量 Here, we say that a variable, v, is free in the expression, e, 468 00:29:04,010 --> 00:29:09,424 如果用没有出现在E中的变量W统一替换E中所有的V if the meaning of the expression, e, is changed by the uniform replacement of a variable, w, not occurring in e, 469 00:29:09,584 --> 00:29:11,152 使得表达式E的含义发生了改变 for every occurrence of v and e. 470 00:29:13,264 --> 00:29:13,712 所以 So, 471 00:29:14,496 --> 00:29:22,768 所以这就是为什么这个变量Y 是一个自由变量 So that's why this variable over here, y, is a free variable. 472 00:29:29,160 --> 00:29:32,272 所以 这个表达式里的自由变量 And so free variables in this expression-- 473 00:29:33,760 --> 00:29:35,184 另一个例子是 And other examples of that is that 474 00:29:36,176 --> 00:29:39,328 对于一个以Y为参数的过程 is that procedure of one argument y, 475 00:29:40,432 --> 00:29:42,000 就像我们之前的那个一样 which is just what we had before, 476 00:29:42,272 --> 00:29:44,608 调用以X为参数的过程 which uses that procedure of one argument x 477 00:29:45,088 --> 00:29:48,544 将X与Y相乘-- that multiplies x by y-- 478 00:29:51,408 --> 00:29:52,656 并应用于3 use that on three. 479 00:29:57,248 --> 00:30:00,352 这个过程中有一个自由变量 This procedure has a free variable in it 480 00:30:00,928 --> 00:30:01,984 也就是这个星号 which is asterisk. 481 00:30:05,008 --> 00:30:05,890 因为 See, because, 482 00:30:05,890 --> 00:30:08,080 如果它表示正常意义的乘法 if that has a normal meaning of multiplication, 483 00:30:09,440 --> 00:30:12,784 如果我统一地用加号来代替星号 then if I were to replace uniformly all asterisks with pluses, 484 00:30:14,256 --> 00:30:16,384 这个表达式的含义就变了 then the meaning of this expression would change. 485 00:30:19,344 --> 00:30:20,768 这就是自由变量的意思 That's what you mean by a free variable. 486 00:30:22,688 --> 00:30:24,816 现在 你们已经学到了一些逻辑学术语 So, so far you've learned some logician words 487 00:30:25,648 --> 00:30:27,584 用它们可以解释名字的用法 which describe the way names are used. 488 00:30:28,944 --> 00:30:31,264 我们需要更进一步深入 Now, we have to do a little bit more playing around here, 489 00:30:32,960 --> 00:30:33,728 再多了解一些 a little bit more. 490 00:30:35,136 --> 00:30:36,224 我想给你们讲讲 I want to tell you about 491 00:30:36,816 --> 00:30:39,760 变量被定义的区域 about the regions are over which variables are defined. 492 00:30:42,176 --> 00:30:42,880 你瞧 You see, 493 00:30:43,376 --> 00:30:45,696 目前为止 我们已经相当不正式了 we've been very informal about this up till now, 494 00:30:46,336 --> 00:30:50,160 当然 你们中的一些 或者大部分人可能已经理解得很透彻了 and, of course, many of you have probably understood very clearly or most of you, 495 00:30:50,360 --> 00:30:52,848 在这里被声明的X that the x that's being declared here 496 00:30:53,648 --> 00:30:55,184 只被定义在这里 is defined only in here. 497 00:30:58,288 --> 00:31:00,912 这个X 只被定义在这里 This x is the defined only in here, 498 00:31:01,616 --> 00:31:04,336 这个Y 只被定义在这里 and this y is defined only in here. 499 00:31:07,104 --> 00:31:09,168 我们给这个概念取了个名字 叫“作用域” We have a name for such an idea. It's called a scope. 500 00:31:11,616 --> 00:31:13,584 我给你们再讲个术语 And let me give you another piece of terminology. 501 00:31:14,704 --> 00:31:15,776 这个就比较复杂 It's a long story. 502 00:31:15,968 --> 00:31:17,648 如果X是E中的一个约束变量 If x is a bound variable in e, 503 00:31:18,160 --> 00:31:20,240 那么它是约束于一个LAMBDA表达式中 then there is a lambda expression where it is bound. 504 00:31:20,896 --> 00:31:24,910 LAMBDA表达式是约束变量的唯一方式 So the only way you can get a bound variable ultimately is by lambda expression. 505 00:31:24,910 --> 00:31:25,968 你可能会担心 Then you may worry, 506 00:31:26,220 --> 00:31:29,056 DEFINE是它的一个例外吗? does define quite an exception to this? 507 00:31:29,648 --> 00:31:32,920 事实证明 通过巧妙安排 我们可以避免使用DEFINE And it turns out, we could always arrange things so you don't need any defines. 508 00:31:32,920 --> 00:31:33,968 一会我们就能看到了 And we'll see that in a while. 509 00:31:34,240 --> 00:31:35,728 它一个非常神奇的东西 It's a very magical thing. 510 00:31:36,540 --> 00:31:38,400 所以我们完全不需要DEFINE So define really can go away. 511 00:31:38,680 --> 00:31:41,552 实际上 唯一能创建名字的东西是LAMBDA The really, only thing that makes names is lambda . 512 00:31:42,640 --> 00:31:43,408 这就是它的职责 That's its job. 513 00:31:44,304 --> 00:31:46,230 多么的令人惊奇 And what's so amazing about a lot of things 514 00:31:46,230 --> 00:31:47,872 很多东西你只凭借LAMBDA就可以计算 is you can compute with only lambda. 515 00:31:48,736 --> 00:31:49,584 但是 在任何情况下 But, in any case, 516 00:31:51,744 --> 00:31:55,760 一个LAMBDA表达式有一个地方来声明变量 a lambda expression has a place where it declares a variable. 517 00:31:55,760 --> 00:31:57,104 我们把它称为形式参数表 We call it the formal parameter list 518 00:31:58,944 --> 00:32:00,560 或者叫 约束变量表 and we say or the bound variable list. 519 00:32:01,264 --> 00:32:04,512 我们说LAMBDA表达式约束了--这是一个动词 We say that the lambda expression binds -- so it's a verb 520 00:32:05,020 --> 00:32:07,344 --约束了在约束变量表里声明的变量 --binds the variables declared in it's bound variable list. 521 00:32:08,592 --> 00:32:12,480 另外 表达式中定义变量的那些部分 In addition, those parts of the expression where the variable is defined, 522 00:32:13,232 --> 00:32:15,232 是被一些声明所声明的 which was declared by some declaration 523 00:32:15,568 --> 00:32:19,264 这些部分被叫做变量的作用域 is called the scope of that variable. 524 00:32:20,448 --> 00:32:21,920 所以 这些是作用域 So these are scopes. 525 00:32:22,256 --> 00:32:23,680 这是Y的作用域 This is the scope of y. 526 00:32:27,160 --> 00:32:28,544 这是X的作用域-- And this is the scope of x-- 527 00:32:33,104 --> 00:32:34,032 以此类推 that sort of thing. 528 00:32:41,328 --> 00:32:42,080 好 OK, 529 00:32:43,936 --> 00:32:45,632 现在我们有了足够多的术语 well, now we have enough terminology 530 00:32:46,608 --> 00:32:51,760 可以开始理解如何建立一个新的计算模型了 to begin to understand how to make a new model for computation 531 00:32:51,968 --> 00:32:53,776 因为 这里很重要的一点是 because the key thing going on here 532 00:32:54,944 --> 00:32:57,008 我们摧毁了代换模型 is that we destroyed the substitution model, 533 00:32:57,180 --> 00:32:58,384 我们现在不得不需要一个模型 and we now have to have a model 534 00:32:58,624 --> 00:33:02,320 来体现表示名字被关联到某些地方 that represents the names as referring to places. 535 00:33:03,936 --> 00:33:05,344 因为 如果我们要改变某个东西 Because if we are going to change something, 536 00:33:05,984 --> 00:33:07,472 我们就需要一个存它的地方 then we have a place where it's stored. 537 00:33:09,568 --> 00:33:10,352 请想一想 You see, 538 00:33:10,832 --> 00:33:13,312 如果一个名字只是关联于一个值 if a name only refers to a value, 539 00:33:14,040 --> 00:33:16,360 如果我试图改变这个名字的含义 and if I tried to change the name's meaning, 540 00:33:16,736 --> 00:33:20,320 这不怎么明确 well, that's not clear. 541 00:33:20,320 --> 00:33:24,680 因为没有名字可以关联的地方 There's nothing that is the place that that name referred to. 542 00:33:24,992 --> 00:33:25,808 该怎么解释呢…… How am I really saying it? 543 00:33:25,920 --> 00:33:29,540 也就是名字的所有实例之间没有共享任何东西 There're nothing shared among all of the instances of that name. 544 00:33:29,872 --> 00:33:31,680 也就是说 对于一个名字 And what we really mean, by a name, 545 00:33:31,680 --> 00:33:32,976 是用来让我们找到某些东西的 is that we find something out. 546 00:33:34,336 --> 00:33:36,368 我们给某个东西一个名字 然后你得到了它 We've given something a name, and you have it, 547 00:33:36,736 --> 00:33:39,060 你能得到它 是因为我给了你一个它的引用 and you have it, because I'm given you a reference to it, 548 00:33:39,060 --> 00:33:40,448 我把对它的引用给了你 and I've given you a reference to it. 549 00:33:41,024 --> 00:33:42,304 我们会看到很多相关的例子 And we'll see a lot about that. 550 00:33:43,616 --> 00:33:45,216 让我们继续学习“环境” So let me tell you about environments. 551 00:33:46,192 --> 00:33:48,768 我需要用一下头顶上的投影仪 I need the overhead projection machine, 552 00:33:49,312 --> 00:33:49,984 谢谢你 thank you. 553 00:33:52,192 --> 00:33:53,024 这里 And so here 554 00:33:55,488 --> 00:34:00,400 是一堆环境结构 is a bunch of environment structures. 555 00:34:01,536 --> 00:34:05,760 环境就是执行虚拟的代换的一种方法 An environment is a way of doing substitutions virtually. 556 00:34:06,384 --> 00:34:07,890 它代表了一个地方 It represents a place 557 00:34:07,890 --> 00:34:11,392 是存储你的未完成的代换的地方 where something is stored which is the substitutions that you haven't done. 558 00:34:13,344 --> 00:34:16,500 它是一个积累各种东西的地方 It's a place where everything accumulates, 559 00:34:16,500 --> 00:34:21,136 在那里 变量的名字与值关联在一起 where the names of the variables are associated with the values they have 560 00:34:21,792 --> 00:34:22,560 使得 such that, 561 00:34:22,752 --> 00:34:25,900 当你问某个名字是什么意思的时候 when you say, what dose this name mean, 562 00:34:25,900 --> 00:34:27,408 你要在一个环境中寻找答案 you look it up in an environment. 563 00:34:28,080 --> 00:34:29,488 所以环境是一个函数 So an environment is a function, 564 00:34:30,800 --> 00:34:31,488 或一张表 or a table, 565 00:34:32,224 --> 00:34:33,240 或类似的东西 or something like that. 566 00:34:33,240 --> 00:34:34,896 但它是一种结构化的表 But it's a structured sort of table. 567 00:34:35,760 --> 00:34:37,392 它是由框架构成 It's made out of things called frames. 568 00:34:41,136 --> 00:34:44,464 框架是环境的一部分 Frames are pieces of environment, 569 00:34:44,896 --> 00:34:46,016 它们被链接在一起 and they are chained together, 570 00:34:47,072 --> 00:34:48,192 以某种很好的方式 in some nice ways, 571 00:34:49,008 --> 00:34:52,096 用一种叫做父链接之类的东西 by what's called parent links or something like that. 572 00:34:54,032 --> 00:34:55,024 这里 So here, 573 00:34:55,648 --> 00:34:57,620 有一个环境结构 we have an environment structure 574 00:34:57,620 --> 00:35:04,224 它由三个环境组成 分别是A B和C consisting of three environments, basically, A, B, and C. 575 00:35:05,104 --> 00:35:07,632 D也是环境 但它和C是一样的 d is also an environment, but it's the same one, 576 00:35:08,880 --> 00:35:10,176 它们共享了同一个环境 they share. 577 00:35:11,456 --> 00:35:13,968 那就是赋值的本质所在 And that's the essence of assignment. 578 00:35:14,400 --> 00:35:16,100 如果我改变了一个变量 If I change a variable, 579 00:35:16,100 --> 00:35:19,800 比如改变这个变量的值 a value of a valuable that lives here, like that one, 580 00:35:19,800 --> 00:35:23,500 那么它将在所有地方都可见 it should be visible from all places that you're looking at it from. 581 00:35:23,500 --> 00:35:24,840 用x来举例 Take this one, x. 582 00:35:24,840 --> 00:35:28,190 如果我将X改为4 If I change the x to four, 583 00:35:28,190 --> 00:35:30,190 在其他地方也是可见的 it's visible from other places. 584 00:35:30,190 --> 00:35:32,190 但是我们现在不去关心这个 But I'm not going to worry about that right now. 585 00:35:32,190 --> 00:35:33,840 过一会儿会详细讨论这个问题 We're going to talk a lot about that in a little while. 586 00:35:34,560 --> 00:35:35,536 这里有什么? What do we have here? 587 00:35:36,768 --> 00:35:38,848 这些叫做框架 这是一个框架 Well, these are called frames. Here is a frame, 588 00:35:39,408 --> 00:35:40,384 这是一个框架 here's a frame 589 00:35:40,768 --> 00:35:41,840 这也是一个框架 and here's a frame. 590 00:35:43,184 --> 00:35:45,200 A是一个环境 A is an environment which consists of 591 00:35:45,200 --> 00:35:47,824 它由框架II the table label which is frame two, 592 00:35:48,368 --> 00:35:51,056 和框架I组成 followed by the table labeled frame one. 593 00:35:52,528 --> 00:35:54,608 在这个环境中 And, in this environment, 594 00:35:54,992 --> 00:35:59,680 在环境C中 在框架II中 in C, this environment, frame two, 595 00:36:00,480 --> 00:36:03,264 X和Y是被约束的 uh....x and y are bound. 596 00:36:04,064 --> 00:36:04,784 它们具有值 They have values. 597 00:36:05,260 --> 00:36:07,180 对不起 是在框架I中 Sorry, in frame one 598 00:36:07,180 --> 00:36:08,288 而在框架II中 In frame two, 599 00:36:09,728 --> 00:36:10,832 Z被约束 z is bound, 600 00:36:10,992 --> 00:36:12,176 X被约束 and x is bound, 601 00:36:12,448 --> 00:36:13,696 并且Y也是被约束的 and y is bound, 602 00:36:15,248 --> 00:36:17,408 但是我们看到的X的值 but the value of x that we see, 603 00:36:17,420 --> 00:36:19,040 从这个角度来看 looking from this point of view, 604 00:36:20,016 --> 00:36:21,744 是这个X 它的值是7 is this x. It's x is seven, 605 00:36:22,368 --> 00:36:24,840 而不是这个值为3的X rather than this one which is three. 606 00:36:24,840 --> 00:36:27,616 我们称之为 这个X遮蔽了这个X We say that this x shadows this x. 607 00:36:31,056 --> 00:36:32,496 从环境III From environment three-- 608 00:36:33,440 --> 00:36:34,450 从框架III from frame three, 609 00:36:34,450 --> 00:36:35,730 从环境B from environment b, 610 00:36:35,730 --> 00:36:37,184 它引用了框架III which refers to frame three, 611 00:36:37,450 --> 00:36:42,128 变量M和Y被约束 X也被约束 we have variables m and y bound and also x. 612 00:36:44,848 --> 00:36:46,976 这个Y遮蔽了这个Y This y shadow this one. 613 00:36:48,656 --> 00:36:51,000 从这个角度来看 So the value, looking from this point of view, 614 00:36:51,104 --> 00:36:52,650 Y的值是2 of y is two. 615 00:36:53,456 --> 00:36:55,280 从这个角度来看 The value for looking from this point of view 616 00:36:55,280 --> 00:36:58,640 M的值是1 X的值是3 and m is one. And the value, looking from this point of view, of x is three. 617 00:37:02,224 --> 00:37:03,150 所以 我们有了一个 So there we have 618 00:37:03,150 --> 00:37:05,520 由框架构成的非常简单的环境结构 a very simple environment structure made out of frames. 619 00:37:06,384 --> 00:37:09,808 它们与过程的应用相一致 These correspond to the applications of procedures. 620 00:37:10,944 --> 00:37:12,176 我们马上就会看到 And we'll see that in a second. 621 00:37:14,416 --> 00:37:17,600 现在要给你们看看我们构建的一些其他的很好的小结构 So now I have to make you some other nice little structure that we build. 622 00:37:20,752 --> 00:37:21,712 下一张幻灯片 Next slide, 623 00:37:22,144 --> 00:37:24,368 我们可以看到一个对象 we see an object, 624 00:37:24,840 --> 00:37:26,544 我描绘的是一个过程的图像 which I'm going to draw procedures. 625 00:37:27,936 --> 00:37:28,944 这是一个过程 This is a procedure. 626 00:37:30,112 --> 00:37:31,904 过程由两个部分组成 A procedure is made out of two parts. 627 00:37:33,104 --> 00:37:34,800 这有点像CONS It's sort of like a cons. 628 00:37:37,216 --> 00:37:38,384 不管怎样 它有两个部分 However, it's the two parts. 629 00:37:40,848 --> 00:37:44,720 第一个部分指向一些代码 The first part refers to some code, 630 00:37:45,696 --> 00:37:46,944 这些代码将会被执行 something that can be executed, 631 00:37:47,420 --> 00:37:50,000 你可以把它视作一组指令 a set of instructions, if you will. You can think of it that way. 632 00:37:50,688 --> 00:37:52,832 第二部分是环境 And the second part is the environment. 633 00:37:53,888 --> 00:37:55,504 这就是过程的全部了 The procedure is the whole thing. 634 00:37:57,168 --> 00:37:58,400 我们要用它 And we're going to have to use this 635 00:37:58,710 --> 00:38:05,168 来捕获出现在过程中的自由变量的值 to capture the values of the free variables that occur in the procedure. 636 00:38:06,176 --> 00:38:08,096 如果变量出现在过程中 If a variable occurs in the procedure 637 00:38:08,112 --> 00:38:09,920 它不是被约束的就是自由的 it's either bound in that procedure or free. 638 00:38:11,104 --> 00:38:11,968 如果它是被约束的 If it's bound, 639 00:38:12,576 --> 00:38:14,560 则它的值将很容易被找到 then the value will somehow be easy to find. 640 00:38:16,112 --> 00:38:18,640 它将存在于某个很容易找到的环境中 It will be in some easy environment to get at. 641 00:38:18,910 --> 00:38:19,872 如果它是自由的 If it's free, 642 00:38:20,864 --> 00:38:23,020 我们就必须在过程中放入一些东西 we're going to have to have something that goes with the procedure 643 00:38:23,020 --> 00:38:24,816 用来指导我们查询自由变量的值 that says where we'll go look for its value. 644 00:38:27,056 --> 00:38:29,210 相关理由目前还不清楚 And the reasons why are not obvious yet, 645 00:38:29,210 --> 00:38:30,608 但很快就要真相大白了 but will be soon. 646 00:38:32,320 --> 00:38:34,976 这里有一个对象 它是个复合对象 So here's a procedure object. It's a composite object 647 00:38:35,344 --> 00:38:41,648 由一些代码和一个环境结构组成 consisting of a piece of code and a environment structure. 648 00:38:42,720 --> 00:38:45,504 现在我要告诉你们一些全新的规则 Now I will tell you the new rules, the complete new rules, 649 00:38:46,416 --> 00:38:47,472 关于执行的规则 for evaluation. 650 00:38:50,544 --> 00:38:52,208 仅有的两条规则的第一条是-- The first rule is-- there's only two of them. 651 00:38:53,200 --> 00:38:55,392 这些规则与代换模型规则相对应 These correspond to the substitution model rules. 652 00:38:57,264 --> 00:38:59,328 第一条规则是用来解决 And the first one has to do with 653 00:38:59,664 --> 00:39:02,784 如何把一个过程 应用到参数上的问题 how do you apply a procedure to its arguments? 654 00:39:05,280 --> 00:39:08,544 程序对象被应用于一组参数 Okay, And a procedural object is applied to a set of arguments 655 00:39:08,960 --> 00:39:10,432 是通过构建一个新的框架来完成 by constructing a new frame. 656 00:39:11,312 --> 00:39:15,760 那个框架将包含形式参数 That frame will contain the mapping of the former parameters to the actual parameters 657 00:39:15,830 --> 00:39:19,488 到调用中使用的实际参数的映射 of the arguments that were supplied in the call. 658 00:39:21,424 --> 00:39:22,208 如你所知 As you know, 659 00:39:22,310 --> 00:39:26,940 当我们调用一个过程 如(LAMBDA (X) (* X Y)) when we make up a call to a procedure like lambda x times x y, 660 00:39:26,940 --> 00:39:29,136 然后我们以3为参数调用它 and we call that with the argument three, 661 00:39:30,192 --> 00:39:32,752 那么我们需要某个从X到3的映射 then we're going to need some mapping of x to three. 662 00:39:34,190 --> 00:39:37,392 你可以把它想做是代换的一种 It's the same thing as later substituting, if you will 663 00:39:38,272 --> 00:39:40,304 在旧的模型中 用3代换X the three for the x in the old model. 664 00:39:42,000 --> 00:39:44,800 所以我要建立一个框架 So I'm going to build a frame which contains x equals three 665 00:39:45,152 --> 00:39:46,608 在框架中包含X等于3的这个信息 as the information in that frame. 666 00:39:49,120 --> 00:39:49,712 现在 Now, 667 00:39:50,336 --> 00:39:53,312 过程的体即将被执行 the body of the procedure will then have to be evaluated which is this, 668 00:39:54,160 --> 00:39:56,448 它将在一个环境中执行 and will be evaluated in an environment 669 00:39:57,808 --> 00:40:08,032 这个环境是由我们创建的新框架邻接组合而成 which is constructed by adjoining the new frame that we just made 670 00:40:08,544 --> 00:40:11,696 它是我们所应用的过程的一部分 to the environment which was part of the procedure that we applied. 671 00:40:13,152 --> 00:40:15,776 所以 举个例子 So I'm going to make a little example of that here. 672 00:40:19,200 --> 00:40:24,128 假设我有一些环境 Supposing I have some environment. 673 00:40:25,152 --> 00:40:27,232 画个方框代表它 Here's a frame which represents it. 674 00:40:27,968 --> 00:40:32,192 以及一些过程--我画圆来代表它们 因为这比小三角形好画-- And some procedure-- which I'm going to draw with circles here because it's easier than little triangles-- 675 00:40:33,040 --> 00:40:36,368 抱歉 是菱形 Ummm.. sorry, those are rhombuses, 676 00:40:37,664 --> 00:40:40,784 小块菱形的果冻之类的东西 rhomboidal little pieces of fruit jelly or something. 677 00:40:42,688 --> 00:40:45,328 这有一个使用这个环境的过程 So here's a procedure which takes this environment. 678 00:40:45,952 --> 00:40:48,160 这个过程有一些代码 And the procedure has a piece of code, 679 00:40:48,160 --> 00:40:49,680 是一个LAMBDA表达式 which is a lambda expression, 680 00:40:50,120 --> 00:40:51,696 约束了X和Y which binds x and y 681 00:40:53,152 --> 00:40:56,432 然后执行了表达式E and then executes an expression, e. 682 00:40:57,936 --> 00:40:58,992 这个过程就是这样的 And this is the procedure. 683 00:40:59,560 --> 00:41:00,576 我们叫它P We'll call it p. 684 00:41:01,440 --> 00:41:05,792 我希望将这个过程应用于3和4 I wish to apply that procedure to three and four. 685 00:41:06,384 --> 00:41:08,368 所以我在这写(P 3 4) So I want to do p of three and four. 686 00:41:09,760 --> 00:41:12,176 我要做的事情则是 创建一个新的框架 What I'm going to do, of course, is make a new frame. 687 00:41:13,152 --> 00:41:14,128 创建一个框架 I build a frame 688 00:41:15,248 --> 00:41:18,288 框架中X等于3 which contains x equals three, 689 00:41:18,848 --> 00:41:20,512 而Y等于4 and y equals four. 690 00:41:21,696 --> 00:41:23,488 我要把这个框架 I'm going to connect that frame 691 00:41:24,272 --> 00:41:25,376 连接到这一个框架上 to this frame over here. 692 00:41:27,632 --> 00:41:28,992 对于这个环境 And then this environment, 693 00:41:29,680 --> 00:41:30,976 我把它叫做B with I will call b, 694 00:41:31,552 --> 00:41:35,024 我会在这个环境中求值E的体 is the environment in which I will evaluate the body of e. 695 00:41:39,888 --> 00:41:40,336 现在 Now, 696 00:41:41,952 --> 00:41:45,040 E可能包含了X和Y的引用以及一些别的东西 e may contain references to x and y and other things. 697 00:41:46,848 --> 00:41:49,952 X和Y的值在这里 x and y will have values right here. 698 00:41:50,704 --> 00:41:52,528 其他的变量的值在这里 Other things will have their values here. 699 00:41:55,056 --> 00:41:56,256 怎样才能获取这个框架呢? How do we get this frame? 700 00:41:57,264 --> 00:41:59,264 我们通过过程构建来完成 That we do by the construction of procedures 701 00:41:59,616 --> 00:42:00,608 这就是另一条规则了 which is the other rule. 702 00:42:02,032 --> 00:42:04,400 请看下一张幻灯片 And I think that's the next slide. 703 00:42:05,344 --> 00:42:06,128 规则二 Rule two, 704 00:42:07,808 --> 00:42:09,900 当一个LAMBDA表达式被求值时 when a lambda expression is evaluated, 705 00:42:09,900 --> 00:42:11,760 相对于某个特定的环境-- relative to a particular environment-- 706 00:42:14,192 --> 00:42:14,400 例如 See, 707 00:42:15,040 --> 00:42:18,120 获取一个过程的方式就是求值一个LAMBDA表达式 the way I get a procedure is by evaluating the lambda expression. 708 00:42:18,192 --> 00:42:19,360 这里有一个LAMBDA表达式 Here's a lambda expression. 709 00:42:20,048 --> 00:42:21,120 通过对它求值 By evaluating it, 710 00:42:21,904 --> 00:42:23,968 我获得了一个可以应用于3的过程 I get a procedure which I can apply to three. 711 00:42:25,088 --> 00:42:26,650 现在这个LAMBDA表达式 Now this lambda expression 712 00:42:26,650 --> 00:42:30,384 在一个Y已被定义的环境中执行 is evaluated in an environment where y is defined. 713 00:42:31,840 --> 00:42:35,840 我希望这个过程的体中包括的Y是自由的 And I want the body of this which contains a free version of y. 714 00:42:36,390 --> 00:42:38,368 在这里面 Y是自由的 y is free in here, 715 00:42:38,720 --> 00:42:40,384 但是在整个的表达式中却是被约束的 it's bound over the whole thing, 716 00:42:41,360 --> 00:42:42,752 而在这里是自由的 but it's free over here. 717 00:42:43,328 --> 00:42:46,240 我想让这两个Y指称同一个Y I want that y to be this one. 718 00:42:47,440 --> 00:42:55,136 我在Y被创建的环境中求值这个过程的体 I evaluate this body of this procedure in the environment where y was created. 719 00:42:55,328 --> 00:42:58,400 就像这个一样 因为那是通过应用完成的 That's this kind of thing, because that was done by application. 720 00:42:59,008 --> 00:42:59,632 现在 Now, 721 00:43:00,240 --> 00:43:02,608 如果我还想查找Y的值 if I ever want to look up the value of y, 722 00:43:03,104 --> 00:43:04,096 我就必须知道它在哪 I have to know where it is. 723 00:43:04,544 --> 00:43:06,420 因此 这个过程在被创建时 Therefore, this procedural was created, 724 00:43:06,420 --> 00:43:10,060 过程的创建 也就是对LAMBDA表达式求值的结果 the creation of the procedure which is the result of evaluating that lambda expression 725 00:43:10,060 --> 00:43:16,336 最好是获取一个指针或记住Y被约束在哪个框架中 had better capture a pointer or remember the frame in which y was bound. 726 00:43:17,920 --> 00:43:19,760 这就是这个规则的内容 So that's what this rule is telling us. 727 00:43:22,112 --> 00:43:23,136 那么 举个例子 So, for example, 728 00:43:24,448 --> 00:43:29,328 如果我恰好求值了一个LAMBDA表达式 if I happen to be evaluating a lambda expression, 729 00:43:30,896 --> 00:43:33,328 在E中的LAMBDA表达式 lambda expression in e, 730 00:43:34,048 --> 00:43:40,464 在E中求值(LAMBDA (X Y) G) lambda of say, x and y, let's call it g in e, 731 00:43:41,088 --> 00:43:42,368 对其求值 evaluating that. 732 00:43:42,976 --> 00:43:46,176 这些事的意义就是我现在构建了一个过程对象 all that means is I now construct a procedure object. 733 00:43:47,104 --> 00:43:48,288 E是某个环境 e is some environment. 734 00:43:48,848 --> 00:43:50,944 有个指针指向E e is something which has a pointer to it. 735 00:43:51,792 --> 00:43:56,688 我构建了一个过程对象指向了这个环境 I construct a procedure object that points up to that environment, 736 00:43:58,560 --> 00:44:00,112 它的代码 where the code of that 737 00:44:00,544 --> 00:44:03,248 是一个LAMBDA表达式 或者是某种中间代码 is a lambda expression or whatever that translates into. 738 00:44:06,240 --> 00:44:07,568 而这就是一个过程 And this is the procedure. 739 00:44:12,384 --> 00:44:14,704 它为我生成了这个和这个 So this produces for me-- this -- this 740 00:44:14,940 --> 00:44:16,370 这个对象 this object here, 741 00:44:16,370 --> 00:44:18,128 这个环境指针 this environment pointer, 742 00:44:18,370 --> 00:44:22,520 获取了求值LAMBDA表达式时的环境 captures the place where this lambda expression was evaluated, 743 00:44:22,624 --> 00:44:24,592 定义所使用的环境 where the definition was used, 744 00:44:25,584 --> 00:44:27,408 创建一个过程时的定义所用的环境 where the definition was used to make a procedure, 745 00:44:30,320 --> 00:44:31,472 从而创建了过程 to make the procedure. 746 00:44:32,896 --> 00:44:36,304 所以 它将环境从定义过程的地方取出 So it picks up the environment from the place where that procedure was defined, 747 00:44:37,424 --> 00:44:38,928 将它保存在过程自己内部 stores it in the procedure itself, 748 00:44:39,600 --> 00:44:40,976 之后当过程被调用时 and then when the procedure is used, 749 00:44:41,328 --> 00:44:43,472 它在被定义时的环境 the environment where it was defined is extended 750 00:44:43,984 --> 00:44:45,072 将由新的框架扩充 with the new frame. 751 00:44:48,720 --> 00:44:52,336 这给了我们一个放置有值的变量的地方 So this gives us a locus for putting where a variable has a value. 752 00:44:53,040 --> 00:44:53,960 举个例子 And, for example, 753 00:44:53,960 --> 00:44:56,816 如果有很多东西指向那这个环境 if there are lots of guys pointing in at that environment, 754 00:44:57,744 --> 00:45:00,336 它们就会共享这个环境 then they share that place. 755 00:45:01,200 --> 00:45:02,528 我们很快将会见到 And we'll see more of that shortly. 756 00:45:04,016 --> 00:45:05,344 现在你们有了一个新模型 Well, now you have a new model 757 00:45:06,384 --> 00:45:09,920 我们用它来理解程序的执行 for understanding the execution of programs. 758 00:45:11,360 --> 00:45:12,784 我觉得现在我应该解答一些问题了 I suppose I'll take questions now, 759 00:45:13,100 --> 00:45:14,960 之后我们再继续 and then we'll go on and use that for something. 760 00:45:18,192 --> 00:45:19,520 学生:这么说是对的吗? AUDIENCE: Is it right to say then, 761 00:45:19,520 --> 00:45:23,960 环境就是一些被连接在一起的框架 the environment is that linked chain of frames starting with-- 762 00:45:23,960 --> 00:45:25,104 教授:对 PROFESSOR: That's right. 763 00:45:25,480 --> 00:45:26,640 学生:通过它能够访问所有的框架? AUDIENCE: working all the way back? 764 00:45:27,712 --> 00:45:31,456 教授:是的 环境是一系列被连接在一起的框架 PROFESSOR: Yes, the environment is a sequence of frames linked together. 765 00:45:32,432 --> 00:45:35,472 我对它的理解是 它是指向第一个框架的指针 And the way I like to think about it, it's the pointer to the first one, 766 00:45:36,880 --> 00:45:38,720 因为一旦你获得了它 你就能拿到所有的框架 because once you've got that you've got them all. 767 00:45:43,968 --> 00:45:44,656 还有谁有问题吗? Anybody else? 768 00:45:45,200 --> 00:45:49,360 学生:有可能在两个不同的环境中定义或求值一个过程 AUDIENCE: Is it possible to evaluate a procedure or to define a procedure in two different environments 769 00:45:49,360 --> 00:45:53,200 使得它有不同的行为 并且有指向两个环境的指针-- such that it will behave differently, and have pointers to both-- 770 00:45:53,200 --> 00:45:55,776 教授:噢 是的 同一个过程不会有两个不同环境 PROFESSOR: Oh, yes. The same procedure is not going to have two different environments. 771 00:45:56,900 --> 00:45:59,020 同样的代码 The same code, 772 00:45:59,020 --> 00:46:00,820 比如同样的LAMBDA表达式 the same lambda expression 773 00:46:00,820 --> 00:46:03,728 再不同的环境下求值可能产生不同的过程 can be evaluated in two environments producing two different procedures. 774 00:46:06,032 --> 00:46:07,180 每个过程-- Each procedure-- 775 00:46:07,180 --> 00:46:09,950 学生:它们的定义有同样的名字 它们的运算-- AUDIENCE: Their definition has the same name. Their operation-- 776 00:46:09,950 --> 00:46:11,920 教授:它们定义是写起来是一样的 使用同样的字母 PROFESSOR: The definition is written the same, with the same characters. 777 00:46:12,560 --> 00:46:14,624 我能求值那一组字母 I can evaluate that set of characters, 778 00:46:14,930 --> 00:46:18,140 或定义的表结构之类的东西 whatever, that list structure that defines, 779 00:46:18,224 --> 00:46:20,416 那只是文本表示 that is the textual representation. 780 00:46:20,912 --> 00:46:24,864 我可以在两个不同环境种对它求值 产生两个不同的过程 I can evaluate that in two different environments producing two different procedures. 781 00:46:25,552 --> 00:46:26,848 每一个过程 Each of those procedures 782 00:46:27,568 --> 00:46:32,192 有它们自己的一组局部变量 has its own local sets of variables, 783 00:46:32,340 --> 00:46:33,456 我们很快就会看到 and we'll see that right now. 784 00:46:36,704 --> 00:46:37,360 还有问题吗? Anybody else? 785 00:46:42,608 --> 00:46:44,032 好 谢谢大家 我们休息一会 OK, thank you. Let's take a break. 786 00:46:47,980 --> 00:46:57,616 [音乐] [JESU, JOY OF MAN'S DESIRING] 787 00:46:57,610 --> 00:47:02,032 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 788 00:47:05,984 --> 00:47:09,696 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Gerald Jay Sussman 789 00:47:09,690 --> 00:47:13,440 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 790 00:47:13,470 --> 00:47:18,848 赋值、状态和副作用 Assignment, State, and Side-effects 791 00:47:22,670 --> 00:47:25,696 现在 我已经对你们做了一件非常糟糕的事儿 Well, now I've done this terrible thing to you. 792 00:47:26,560 --> 00:47:30,544 我引入了一个非常复杂的东西 I've introduced a very complicated thing, 793 00:47:32,768 --> 00:47:33,424 赋值 assignment, 794 00:47:34,512 --> 00:47:38,080 它摧毁了我们程序中大部分的 有趣的数学特性 which destroys most of the interesting mathematical properties of our programs. 795 00:47:41,072 --> 00:47:42,464 我为什么要做这件事呢 Why should I have done this? 796 00:47:43,184 --> 00:47:45,024 这样做可能有什么好处吗? What possible good could this do? 797 00:47:46,512 --> 00:47:48,864 很明显 这不是一个什么好东西 Clearly not a nice thing, 798 00:47:49,600 --> 00:47:51,232 因此我最好有一个好的理由 so I better have a good excuse. 799 00:47:52,832 --> 00:47:54,800 让我们来小小地玩一下 Well, let's do a little bit of playing, 800 00:47:54,800 --> 00:47:58,352 首先 我们写些非常有趣的带赋值的程序 first of all, with some very interesting programs that have assignment. 801 00:47:58,816 --> 00:48:00,880 来理解它们的特殊之处 Understand something special about them 802 00:48:01,424 --> 00:48:02,832 这些特殊之处使赋值变得有价值 that makes them somewhat valuable. 803 00:48:04,960 --> 00:48:06,704 我们从一个非常简单的程序开始 Start with a very simple program 804 00:48:07,696 --> 00:48:09,280 我把这个程序叫做MAKE-COUNTER I'm going to call make-counter. 805 00:48:10,480 --> 00:48:18,192 我要把它定义为 I'm going to define make-counter 806 00:48:24,176 --> 00:48:28,128 接受一个参数N的过程 to be a procedure of one argument n 807 00:48:29,232 --> 00:48:32,944 并且它的返回值是一个没有参数的过程-- which returns as its value a procedure of no arguments-- 808 00:48:34,368 --> 00:48:36,032 一个生成过程的过程-- a procedure that produces a procedure-- 809 00:48:36,848 --> 00:48:44,352 这个过程把N的值设为N+1 which sets n to the increment of n 810 00:48:47,888 --> 00:48:49,776 并且返回N的值 and returns that value of n. 811 00:48:55,376 --> 00:48:57,540 现在 我们要研究它的行为 Now we're going to investigate the behavior of this. 812 00:48:57,540 --> 00:48:59,024 它很有趣 It's a sort of interesting thing. 813 00:48:59,824 --> 00:49:01,450 为了研究它的行为 In order to investigate the behavior, 814 00:49:01,450 --> 00:49:03,088 我需要建立一个环境模型 I have to make an environment model, 815 00:49:04,112 --> 00:49:05,984 因为我们不能通过其他的方式来理解它 because we can't understand this any other way. 816 00:49:08,656 --> 00:49:09,632 所以我们开始吧 So let's just do that. 817 00:49:10,000 --> 00:49:12,864 我们从这里开始 We start out with some sort of-- 818 00:49:13,240 --> 00:49:15,904 假设机器天生就有一个全局环境 let's say there is a global environment that the machine is born with. 819 00:49:16,130 --> 00:49:17,120 我们把它叫做Global Global we'll call it. 820 00:49:20,032 --> 00:49:24,256 它内部有一堆初始化的东西 And it's going to have in it a bunch of initial things. 821 00:49:24,440 --> 00:49:25,600 我们都知道它里面有什么 We all know what it's got. 822 00:49:25,720 --> 00:49:30,880 这里面有+和* It's got things in it like say, plus, and times, 823 00:49:32,240 --> 00:49:37,264 / -和CAR and quotient, and difference, and CAR, 824 00:49:38,704 --> 00:49:39,744 以此类推 and etcetera, 825 00:49:41,450 --> 00:49:42,480 有很多东西 lots of things. 826 00:49:42,880 --> 00:49:43,984 我不知道它们是什么 I don't know what they are, 827 00:49:44,420 --> 00:49:45,552 一些乱七八糟的符号 some various squiggles 828 00:49:46,080 --> 00:49:48,880 机器一开始就有这些特性 that are the things the machine is born with. 829 00:49:51,216 --> 00:49:53,232 通过在这做定义 And by doing the definition here, 830 00:49:54,688 --> 00:49:55,760 我要做的是-- what I plan to do-- 831 00:49:56,320 --> 00:49:57,310 我在干什么呢? Well, what am I doing? 832 00:49:57,310 --> 00:49:59,584 我要把它关联到全局环境上 I'm doing this relative to the global environment. 833 00:49:59,720 --> 00:50:01,296 这是我的环境指针 So here's my environment pointer. 834 00:50:03,728 --> 00:50:06,704 为了达到那个目的 我要求值这个LAMBDA表达式 In order to do that I have to evaluate this lambda expression. 835 00:50:08,352 --> 00:50:10,016 这意味着我创建了一个过程对象 That means I make a procedure object. 836 00:50:11,504 --> 00:50:13,264 所以 我要在这创建一个过程对象 So I'm going to make a procedure object here. 837 00:50:17,360 --> 00:50:18,688 这个过程对象 And the procedure object has, 838 00:50:18,720 --> 00:50:20,496 由于在它被定义的地方 as the place it's defined, 839 00:50:21,168 --> 00:50:22,352 有一个全局的环境 the global environment. 840 00:50:24,064 --> 00:50:25,792 这个过程对象包括了 The procedure object contains 841 00:50:28,160 --> 00:50:31,472 以N为参数的过程的代码 some code that represents a procedure of one argument n 842 00:50:31,960 --> 00:50:35,344 它返回一个不接受参数的过程 which returns a procedure of no arguments which does something. 843 00:50:38,240 --> 00:50:43,280 DEFINE是一种改变环境的方法 And the define is a way of changing this environment, 844 00:50:44,320 --> 00:50:46,736 所以我把MAKE-COUNTER加入全局环境中 so that I now add to it a make-counter, 845 00:50:52,288 --> 00:50:55,056 这是对于特殊的东西定义的一个特殊的规则 a special rule for the special thing defined. 846 00:50:55,824 --> 00:50:56,944 但它其实是 But what that is, 847 00:50:58,944 --> 00:51:01,968 它给了我们一个指针 指向那个过程 is it gives me that pointer to that procedure. 848 00:51:03,824 --> 00:51:06,320 所以现在全局环境中也有了MAKE-COUNTER So now the global environment contains make-counter as well. 849 00:51:09,280 --> 00:51:11,216 现在 我们要进行一些操作 Now, we're going to do some operations. 850 00:51:11,872 --> 00:51:13,504 我要用它来创建一些计数器 I'm going to use this to make some counters. 851 00:51:14,992 --> 00:51:16,208 我们来看看计数器是什么 We'll see what a counter is. 852 00:51:17,120 --> 00:51:18,512 所以我们定义 So let's define 853 00:51:23,328 --> 00:51:26,656 C1为一个从0开始的计数器 c1 to be a counter beginning at 0. 854 00:51:35,728 --> 00:51:38,384 根据模型 我们知道如何做这个了 Well, we know how to do this now, according to the model. 855 00:51:39,632 --> 00:51:44,336 我需要在全局环境中求值这个表达式 I have to evaluate the expression make-counter in the global environment, 856 00:51:45,408 --> 00:51:46,272 (MAKE-COUNTER 0) make-counter of 0. 857 00:51:47,808 --> 00:51:51,104 我查找MAKE-COUNTER 发现它是一个过程 Well, I look up make-counter and see that it's a procedure. 858 00:51:53,616 --> 00:51:55,296 我将要应用这个过程 I'm going to have to apply that procedure. 859 00:51:56,224 --> 00:51:57,744 应用这个过程的方式 The way I apply the procedure 860 00:51:58,432 --> 00:51:59,968 就是构建一个框架 is by constructing a frame. 861 00:52:01,808 --> 00:52:03,792 所以我构建了一个框架 Okay? So I construct a frame 862 00:52:06,592 --> 00:52:10,448 它内部有一个N的值 which has a value for n in it 863 00:52:11,776 --> 00:52:12,640 这个值是0 which is 0 864 00:52:14,000 --> 00:52:15,344 它的父环境 and the parent environment 865 00:52:15,872 --> 00:52:19,328 就是定义MAKE-COUNTER时的环境 is the one which is the environment of definition of make-counter. 866 00:52:23,936 --> 00:52:28,368 所以我已经通过将MAKE-COUNTER应用于0上 而创建了一个环境 So I've made an environment by applying make-counter to 0. 867 00:52:31,450 --> 00:52:34,400 现在 我需要求值MAKE-COUNTER的体 Now, I have to evaluate the body of make-counter, 868 00:52:34,410 --> 00:52:37,728 就是那个环境中的LAMBDA表达式 which is this lambda expression, in that environment. 869 00:52:40,640 --> 00:52:42,304 求值这个体 Well evaluating this body, 870 00:52:42,768 --> 00:52:44,592 它是一个LAMBDA表达式 this body is a lambda expression. 871 00:52:46,288 --> 00:52:48,864 对LAMBDA表达式求值 意味着创建一个过程对象 Evaluate a lambda expression means make a procedure object. 872 00:52:49,568 --> 00:52:51,008 所以我将创建一个过程对象 So I'm going to make a procedure object. 873 00:52:56,768 --> 00:52:58,290 这个过程对象 And that procedure object has 874 00:52:58,290 --> 00:53:00,464 拥有一个环境 the environment it was defined in being that, 875 00:53:04,208 --> 00:53:05,888 在这个环境中N被定义为0 where n was defined to be 0. 876 00:53:07,680 --> 00:53:08,800 它有一些代码 And it has some code, 877 00:53:08,830 --> 00:53:11,376 这个过程不需要参数 which is the procedure of no arguments 878 00:53:11,408 --> 00:53:15,280 该过程进行一些处理 然后进行赋值 which does something, then sets something, 879 00:53:15,280 --> 00:53:16,736 并返回N and returns n. 880 00:53:17,888 --> 00:53:18,816 这个东西 And this thing 881 00:53:19,424 --> 00:53:21,232 将成为一个对象 is going to be the object, 882 00:53:21,920 --> 00:53:24,672 在全局环境中 它的名字是C1 which in the global environment, will have the name c1. 883 00:53:26,128 --> 00:53:28,336 所以我们在这建立一个名字 C1 So we construct a name here, c1, 884 00:53:28,640 --> 00:53:32,144 并且说C1等于这个过程 and say that equals that. 885 00:53:35,488 --> 00:53:37,360 现在 再来创建另一个计数器 Now, but also make another counter, 886 00:53:43,040 --> 00:53:45,136 通过MAKE-COUNTER创建c2 c2 to be make-counter 887 00:53:50,944 --> 00:53:52,192 让它从10开始 say, starting with 10. 888 00:53:54,250 --> 00:53:55,904 然后我执行同样的步骤 Then I do essentially the same thing. 889 00:53:56,640 --> 00:54:00,400 我应用这个MAKE-COUNTER过程 I apply the make-counter procedure, which I got from here, 890 00:54:00,992 --> 00:54:04,528 建立另一个框架 其中N等于10 to make another frame with n being 10. 891 00:54:05,632 --> 00:54:09,184 全局环境作为它的父环境 That frame has the global environment as its parent. 892 00:54:10,048 --> 00:54:11,808 然后我构建一个过程 I then construct a procedure 893 00:54:13,040 --> 00:54:17,632 以这个框架作为它定义的环境 which has that as it's frame of definition. 894 00:54:18,272 --> 00:54:21,664 它的代码是 The code of it is 895 00:54:21,800 --> 00:54:24,384 完成一些操作的无参过程 the procedure of no arguments which does something. 896 00:54:25,540 --> 00:54:28,600 然后进行赋值 等等 And it does a set, and so on. 897 00:54:28,600 --> 00:54:31,220 然后返回N And n comes out. Okay? 898 00:54:31,456 --> 00:54:34,832 这就是C2 And c2 is this. 899 00:54:36,880 --> 00:54:39,328 好 你们应该发现 某些东西开始变得有趣了 Well, you're already beginning to see something fairly interesting. 900 00:54:40,176 --> 00:54:41,920 这里有两个N There are two n's here. 901 00:54:42,928 --> 00:54:44,192 它们不是同一个N They are not one n. 902 00:54:46,144 --> 00:54:48,160 我每次调用MAKE-COUNTER的时候 Each time I called make-counter, 903 00:54:48,640 --> 00:54:50,256 我就创建了另一个N的实例 I made another instance of n. 904 00:54:52,624 --> 00:54:54,400 它们彼此独立 没有关联 These are distinct and separate from each other. 905 00:54:57,792 --> 00:55:00,288 现在 我们来使用一下这些计数器 Now, let's do some execution, use those counters. 906 00:55:05,920 --> 00:55:15,008 如果此时 我调用C1 会发生什么? Well, what happens if I say, c1 at this point? 907 00:55:15,840 --> 00:55:17,344 我会在这里查找 Well, I go over here, 908 00:55:17,560 --> 00:55:19,984 发现C1是一个过程 and I say, oh yes, c1 is a procedure. 909 00:55:20,640 --> 00:55:22,784 我要不带参数地调用这个过程 I'm going to call this procedure on no arguments, 910 00:55:23,160 --> 00:55:24,960 因为它不需要参数 but it has no parameters. 911 00:55:24,960 --> 00:55:25,632 对吧? That's right. 912 00:55:26,976 --> 00:55:27,840 它的体是什么呢? What's its body? 913 00:55:27,960 --> 00:55:30,020 我得来这里解释 因为我没有给誊过来 Well, I have to look over here, because I didn't write it down. 914 00:55:30,020 --> 00:55:32,656 这个过程体是将N赋值为N+1 It said, set n to one plus n 915 00:55:33,808 --> 00:55:34,896 并且返回N and return n, 916 00:55:37,120 --> 00:55:38,128 就是把N增大1 increment n. 917 00:55:38,976 --> 00:55:41,600 它的N指的是这个 Well, the n it says is this one. 918 00:55:43,088 --> 00:55:44,608 所以我把这个n增大1 So I increment that n. 919 00:55:45,808 --> 00:55:47,008 它变成了1 That becomes one, 920 00:55:48,640 --> 00:55:50,240 然后返回了1 and I return the value one. 921 00:55:53,136 --> 00:55:56,496 之后我调用C2 Supposing I then called c2. 922 00:55:58,384 --> 00:55:59,200 我会做什么? Well, what do I do? 923 00:55:59,232 --> 00:56:03,330 C2是相同的过程 I say c2 is this procedure which does the same thing, 924 00:56:03,330 --> 00:56:04,480 但这个N but here's the n. 925 00:56:05,330 --> 00:56:06,576 它变成了11 It becomes 11. 926 00:56:10,976 --> 00:56:14,592 所以返回值是11 And so I have an 11 which is the value. 927 00:56:15,920 --> 00:56:18,320 然后我们再来调用一下C1 I then can say, let's try c1 again. 928 00:56:20,912 --> 00:56:22,560 C1是这个 hum, c1 is this, 929 00:56:23,280 --> 00:56:24,160 它是2 that's two, 930 00:56:27,248 --> 00:56:28,304 所以结果是2 so the answer is two. 931 00:56:29,664 --> 00:56:30,752 然后调用C2 And c2 932 00:56:33,376 --> 00:56:35,312 然后C2通过同样的方法 返回了12 gives me a 12 by the same method, 933 00:56:35,744 --> 00:56:37,550 它在这里进行查找 by walking down here looking at that 934 00:56:37,550 --> 00:56:39,280 发现了N 并把它加1 and saying, here's the n, I'm incrementing. 935 00:56:41,648 --> 00:56:43,680 我拥有的是可计算的对象 So what I have are computational objects. 936 00:56:45,216 --> 00:56:46,864 它们是两个计数器 There are two counters, 937 00:56:48,960 --> 00:56:51,024 每一个都有各自独立的局部状态 each with its own independent local state. 938 00:56:55,488 --> 00:56:56,624 我们再进一步 Let's talk about this a little. 939 00:56:56,640 --> 00:56:58,528 这是个奇怪的东西 This is a strange thing. 940 00:57:01,120 --> 00:57:02,224 什么是对象? What's an object? 941 00:57:04,112 --> 00:57:06,128 这个概念并不明确 It's not at all obvious what an object is. 942 00:57:07,552 --> 00:57:09,456 我们倾向于以对象的角度思考 We like to think about objects, 943 00:57:11,248 --> 00:57:13,328 因为这样思考比较经济 because it's economical to think that way. 944 00:57:14,624 --> 00:57:17,280 这是一种智力上的经济 It's an intellectual economy. 945 00:57:18,576 --> 00:57:19,616 我是一个对象 I am an object. 946 00:57:20,992 --> 00:57:22,304 你也是一个对象 You are an object. 947 00:57:23,552 --> 00:57:25,296 但我们不是同一个对象 We are not the same object. 948 00:57:27,520 --> 00:57:29,648 我可以把世界分为两部分 I can divide the world into two parts, 949 00:57:29,920 --> 00:57:31,856 我和你 me and you, 950 00:57:31,920 --> 00:57:33,312 以及其它的东西 and there's other things as well, 951 00:57:34,704 --> 00:57:35,264 使得 such that 952 00:57:35,440 --> 00:57:39,504 大多数对于我的讨论 most of the things I might want to discuss about my workings 953 00:57:39,680 --> 00:57:40,896 不会影响到你 do not involve you, 954 00:57:41,392 --> 00:57:44,672 大多数对于你的讨论不会牵涉到我 and most of the things I want to discuss about your workings don't involve me. 955 00:57:45,664 --> 00:57:46,944 我有血压 I have a blood pressure, 956 00:57:47,504 --> 00:57:48,384 体温 a temperature, 957 00:57:49,360 --> 00:57:51,488 呼吸频率 a respiration rate, 958 00:57:53,344 --> 00:57:54,992 血液中有确定的血糖值 certain amount of sugar in my blood, 959 00:57:56,112 --> 00:57:59,344 数不清的 数以千计的状态变量--上百万实际上 and numerous, thousands, of state variables-- millions actually, 960 00:57:59,376 --> 00:58:00,656 我不知道具体有多少 or I don't know how many-- 961 00:58:00,930 --> 00:58:03,488 以物理学观点 我拥有大量的状态变量 huge numbers of state variables in the physical sense 962 00:58:04,912 --> 00:58:07,120 如果将我视为一个粒子的话 which represent the state of me as a particle, 963 00:58:09,152 --> 00:58:10,640 你也有许许多多这样的变量 and you have gazillions of them as well. 964 00:58:12,688 --> 00:58:14,944 我们的大多数变量之间是好无联系的 And most of mine are uncoupled to most of yours. 965 00:58:17,312 --> 00:58:19,504 所以可以计算我的属性 So we can compute the properties of me 966 00:58:20,560 --> 00:58:22,832 而不用太担心你的属性 without worrying too much about the properties of you. 967 00:58:23,824 --> 00:58:25,776 如果把我们两个放在一起计算 If we had to work about both of us together, 968 00:58:25,960 --> 00:58:27,824 那么我们需要考虑的状态的数量 than the number of states that we have to consider 969 00:58:27,824 --> 00:58:30,010 就是你与我的状态的数量的乘积 is the product of the number of states you have and the number of states I have. 970 00:58:30,528 --> 00:58:32,112 按对象解耦的话 则只需考虑你我状态之和 But this way it's almost a sum. 971 00:58:32,656 --> 00:58:35,344 然而 实际上有一种力量把我们耦合起来 Now, indeed there are forces that couple us. 972 00:58:36,000 --> 00:58:37,952 我对你讲话 你的状态就变了 I'm talking to you and your state changes. 973 00:58:38,448 --> 00:58:40,096 我看着你 我的状态就变了 I'm looking at you and my state changes. 974 00:58:41,728 --> 00:58:44,080 因此 我的变量中的一小部分 Some of my state variables, a very few of them, 975 00:58:44,336 --> 00:58:46,070 与你的一些变量是耦合的 therefore, are coupled to yours. 976 00:58:46,070 --> 00:58:47,800 如果你突然大喊大叫 If you were to suddenly yell very loud, 977 00:58:47,800 --> 00:58:48,880 我的血压就会升高 my blood pressure would go up. 978 00:58:54,304 --> 00:58:56,864 然而 将世界看作是由独立的变量 However, and it may not be always appropriate 979 00:58:57,170 --> 00:59:01,168 和独立的粒子组成的是不恰当的 to think about the world as being made out of independent states and independent particles. 980 00:59:02,128 --> 00:59:04,464 在像量子力学这样的东西里存在大量的BUG Lots of the bugs that occur in things like quantum mechanics, 981 00:59:05,230 --> 00:59:08,704 或者当我们思考像量子力学之类的东西的时候 会在我们的脑海中产生bug or the bugs in our minds that occur when we think about things like quantum mechanics, 982 00:59:08,896 --> 00:59:10,970 这是由于 当我们思考事物时 are due the fact that we are trying to think about things 983 00:59:10,970 --> 00:59:12,960 会去将事物分解为相互独立的部分来看待 being broken up into independent pieces, 984 00:59:13,584 --> 00:59:17,328 而事实上事物的耦合程度 远远大于在表面所看到的 when in fact there's more coupling than we see on the surface, 985 00:59:18,016 --> 00:59:19,440 即便这样 我们仍像那样思考 or that we want to believe in, 986 00:59:19,616 --> 00:59:21,696 是因为我们希望高效并且有效的进行计算 because we want to compute efficiently and effectively. 987 00:59:22,192 --> 00:59:23,824 我们被培养成以那种方式进行思考 We've been trained to think that way. 988 00:59:29,760 --> 00:59:30,512 大家看 Well, let's see. 989 00:59:31,504 --> 00:59:33,440 我们如何才能知道我们是否有对象? How would we know if we had objects at all? 990 00:59:35,120 --> 00:59:37,344 如果我们有对象 应该如何分辨呢? How can we tell if we have objects? 991 00:59:37,640 --> 00:59:41,456 通过思考一些光学现象 Consider some possible optical illusions. 992 00:59:42,464 --> 00:59:43,136 就能解答这个问题 This could be done. 993 00:59:45,040 --> 00:59:47,696 这几截粉笔不完全相同 These pieces of chalk are not appropriately identical, 994 00:59:47,760 --> 00:59:50,208 但假设 只通过观察是无法区分它们的 but supposing you couldn't tell the difference of them by looking at them. 995 00:59:52,048 --> 00:59:53,320 有一种可能 Well, there's a possibility 996 00:59:53,320 --> 00:59:55,168 是这一切都是我们与镜子的游戏 that this all a game I'm playing with mirrors. 997 00:59:56,070 --> 00:59:57,600 它们真的是同一截粉笔 It's really the same piece of chalk, 998 00:59:59,360 --> 01:00:00,480 但你看到了两个 but you're seeing two of them. 999 01:00:01,616 --> 01:00:03,872 你怎么知道你看到的是一个还是两个呢? How would you know if you're seeing one or two? 1000 01:00:05,040 --> 01:00:06,704 我只知道有一种方法可以确定 Well, there's only one way I know. 1001 01:00:07,376 --> 01:00:08,944 抓起其中一个并且改变它 You grab one of them and change it 1002 01:00:09,456 --> 01:00:10,672 然后看看另一个有没有跟着变化 and see if the other one changed. 1003 01:00:14,016 --> 01:00:14,672 而另一个没有变化 And it didn't, 1004 01:00:15,504 --> 01:00:16,144 所以它们是两截不同粉笔 so there's two of them. 1005 01:00:19,504 --> 01:00:20,160 另一方面 And, on the other hand, 1006 01:00:20,176 --> 01:00:22,208 事物还有一些其它的类似的纠结属性 there is some other screwy properties of things like that. 1007 01:00:22,576 --> 01:00:24,016 例如 我们怎么才知道某个东西是否改变了呢? Like, how do we know if something changed? 1008 01:00:25,008 --> 01:00:27,936 我们需要在它改变之前和之后进行观察 We have to look at it before and after the change. 1009 01:00:28,650 --> 01:00:30,020 改变就是赋值 The change is an assignment, 1010 01:00:30,020 --> 01:00:31,456 它是时间中的一个时刻 it's a moment in time. 1011 01:00:32,144 --> 01:00:34,608 但是那意味着我们需要知道 我们看到的是否是同一个 But that means we have to know it was the same one that we're looking at. 1012 01:00:36,512 --> 01:00:38,840 所以一些东西非常奇怪 So some very strange, and unusual, 1013 01:00:38,840 --> 01:00:40,384 不同寻常并且晦涩难懂 and obscure, and -- I don't understand 1014 01:00:40,840 --> 01:00:43,520 并且我不理解与赋值 the problems associated with assignment, 1015 01:00:44,450 --> 01:00:46,288 变化以及对象有关的问题 and change, and objects. 1016 01:00:47,296 --> 01:00:48,992 这些东西可能变得非常非常糟糕 These could get very, very bad. 1017 01:00:51,408 --> 01:00:52,128 例如 For example, 1018 01:00:53,312 --> 01:00:55,600 我 一个特定的人 here I am, I am a particular person, 1019 01:00:56,160 --> 01:00:57,728 一个特定的对象 a particular object, okay? 1020 01:00:57,960 --> 01:00:59,312 现在 我可以拿出小刀 Now, I can take out my knife, 1021 01:01:00,688 --> 01:01:01,776 切下一片我的指甲 and cut my fingernail. 1022 01:01:01,890 --> 01:01:04,816 一片指甲掉在了桌子上 Alright? A piece of my fingernail has fallen off onto the table. 1023 01:01:05,936 --> 01:01:10,160 我相信自己和一秒钟之前的自己 是同一个人 I believe I am the same person I was a second ago, 1024 01:01:10,976 --> 01:01:12,816 但在物理上并不是分毫不差 but I'm not physically the same in the slightest. 1025 01:01:14,464 --> 01:01:15,430 我已经改变了 I have changed. 1026 01:01:15,584 --> 01:01:16,656 为什么我还是同一个人呢? Why am I the same? 1027 01:01:18,112 --> 01:01:19,408 什么能认定我的身份呢? What is the identity of me? 1028 01:01:20,960 --> 01:01:23,504 我不知道 I don't know...Okay? 1029 01:01:25,056 --> 01:01:27,888 除非我有某种特征 Except for the fact that I have some sort of identity. 1030 01:01:29,712 --> 01:01:33,040 我觉得 由于引入赋值和对象 And so, I think by introducing assignment and objects, 1031 01:01:33,648 --> 01:01:38,288 我们不得不去面对这种 we have opened ourselves up to all the horrible questions of philosophy 1032 01:01:38,416 --> 01:01:42,240 困扰了哲学家们上千年的哲学问题 that have been plaguing philosophers for some thousands of years about this sort of thing. 1033 01:01:43,424 --> 01:01:44,992 这也是相比之下 为什么数学清晰得多 It's why mathematics is a lot cleaner. 1034 01:01:45,696 --> 01:01:50,240 我将尽我所能地向大家阐述关于动作和身份的理解 Let's look at the best things I know to say about actions and identity. 1035 01:01:52,448 --> 01:01:55,392 我们说动作A 对于对于某个对象X有影响 We say that an action, a, had an effect on an object, x, 1036 01:01:55,776 --> 01:01:56,704 换句话说 or equivalently, 1037 01:01:56,928 --> 01:01:58,416 X被A改变 that x was changed by a, 1038 01:01:58,896 --> 01:02:01,664 如果某个属性P 在P作用于X之前为真 if some property, p, which was true of x before a, 1039 01:02:01,872 --> 01:02:03,760 在A作用于X之后为假 became false of x after a. 1040 01:02:04,992 --> 01:02:05,632 那是个测试 That's test. 1041 01:02:06,624 --> 01:02:09,664 这也意味着 我必须有变动前和变动后的X It still means I have to have the x before and after. 1042 01:02:10,912 --> 01:02:12,544 或者 换句话说 Or, the other way of saying this is, 1043 01:02:12,944 --> 01:02:14,944 我们说对任一动作 两个对象X和Y是同一个对象 we say that two objects x and y are the same for any action 1044 01:02:14,976 --> 01:02:17,936 当且仅当 该动作对X、Y有同样的影响 which has an effect on x has the same effect on y 1045 01:02:19,632 --> 01:02:21,390 然而 就像我说的 However, objects are very useful, 1046 01:02:21,440 --> 01:02:23,184 对象在智力经济上是非常有用的 as I said, for intellectual economy. 1047 01:02:24,640 --> 01:02:27,120 对于它们来说非常有用的东西之一 One of the things that's incredibly useful about them, 1048 01:02:28,272 --> 01:02:29,440 就是对于这个世界 is that the world 1049 01:02:30,784 --> 01:02:34,800 我们习惯于把它认为是由带有独立状态的独立对象所构成的 is made out of independent objects with independent local state. 1050 01:02:35,008 --> 01:02:37,280 虽然那并不完全正确 但我们喜欢以那样的的方式来思考 We like to think that way, although it isn't completely true. 1051 01:02:39,680 --> 01:02:42,030 当我们要写一个非常复杂的程序 When we want to make very complicated programs 1052 01:02:42,030 --> 01:02:43,264 来应对这样一个世界时 that deal with such a world, 1053 01:02:43,984 --> 01:02:46,448 如果我们希望这些程序可以被我们理解 if we want those programs to be understandable by us 1054 01:02:46,912 --> 01:02:48,144 并且也是可修改的 and also to be changeable, 1055 01:02:48,730 --> 01:02:51,120 那么如果世界改变了 我们只需要稍微改动一下程序 so that if we change the world we change the program only a little bit, 1056 01:02:51,392 --> 01:02:53,700 我们希望建立一种联系 一种同构 then we want there to be connections, isomorphism, 1057 01:02:53,824 --> 01:02:56,880 建立在真实世界的对象与我们脑海中的对象之间 between the objects in the world and the objects in our mental model. 1058 01:02:58,768 --> 01:03:01,440 世界的模块化 使我们的程序得以模块化 The modularity of the world can give us the modularity in our programming. 1059 01:03:02,416 --> 01:03:05,360 所以我们发明了面向对象编程 So we invent things called object-oriented programming and things like that 1060 01:03:05,888 --> 01:03:08,368 使我们获得那样的力量 to provide us with that power. 1061 01:03:10,064 --> 01:03:10,944 但是 它甚至更简单 But it's even easier. 1062 01:03:10,944 --> 01:03:12,256 让我们玩一个小游戏 Let's play a little game. 1063 01:03:12,270 --> 01:03:13,184 我想通过这个游戏 I want to play a little game, 1064 01:03:13,390 --> 01:03:15,776 给你展示一个更简单的例子 show you an even easier example 1065 01:03:16,000 --> 01:03:21,744 来说明谨慎地使用赋值语句 可以增强模块性 or where modularity can be enhanced by using an assignment statement, judiciously. 1066 01:03:22,864 --> 01:03:25,350 有一件事 我想让你牢牢地铭记 One thing I want to enforce and impress on you, 1067 01:03:25,450 --> 01:03:27,440 就是不要像在FORTRAN Basic is don't use assignment statements the way 1068 01:03:27,456 --> 01:03:29,790 或者Pascal里一样使用赋值语句 you use it in FORTRAN or Basic or something or Pascal, 1069 01:03:30,000 --> 01:03:31,712 你不那样做 也能达到目的 to do the things you don't have to do with it. 1070 01:03:34,048 --> 01:03:36,624 这不是思考大多数事情的正确方式 It's not the right way to think for most things. 1071 01:03:36,976 --> 01:03:38,288 有些时候它是必要的 Sometimes it's essential, 1072 01:03:38,688 --> 01:03:39,690 或者可能是必要的 or maybe it's essential. 1073 01:03:39,690 --> 01:03:40,976 我们一会更深入地去研究 We'll see more about that too. 1074 01:03:42,240 --> 01:03:44,224 我要给你展示一个有趣的游戏 OK, let me show you a fun game here. 1075 01:03:47,616 --> 01:03:49,424 从前有一个数学家 There was a mathematician 1076 01:03:49,680 --> 01:03:53,696 叫做Cesaro by the name of Cesaro--or Cesaro, Cesaro I suppose it is-- 1077 01:03:54,480 --> 01:03:57,456 他发现了一个计算pi的巧妙方法 who figured out a clever way of computing pi. 1078 01:03:58,380 --> 01:04:04,304 这个方法是说 如果我有两个随机数 It turns out that if I take two random numbers 1079 01:04:05,248 --> 01:04:06,944 两个随机的整数 two integers at random, 1080 01:04:07,744 --> 01:04:09,488 计算它们的最大公约数 and compute the greatest common divisor, 1081 01:04:10,944 --> 01:04:13,248 结果可能是1 或者不是1 their greatest common divisor is either one or it's not one. 1082 01:04:13,840 --> 01:04:15,648 如果是1 它们没有公约数 If it's one, then they have no common divisors. 1083 01:04:18,144 --> 01:04:20,680 如果它们的最大公约数是1 If their greatest common divisor is one-- 1084 01:04:21,120 --> 01:04:23,090 这两个随机数 the probability that two random numbers, 1085 01:04:23,090 --> 01:04:26,384 两个随机生成的数 最大公约数为1的概率 two numbers chosen at random, has as greatest common divisor one 1086 01:04:26,580 --> 01:04:27,824 与pi有关系 is related to pi. 1087 01:04:29,328 --> 01:04:30,112 事实上 In fact-- 1088 01:04:31,110 --> 01:04:32,336 是的 这很奇怪 yes, it's very strange-- 1089 01:04:32,944 --> 01:04:34,416 当然有其他计算pi的方法 of course there are other ways of computing pi, 1090 01:04:34,416 --> 01:04:38,944 像投针法之类的的方法 like dropping pins on flags, and things like that, and sort of the same kind of thing. 1091 01:04:40,192 --> 01:04:48,976 N1和N2的最大公约数是1的概率为 So the probability of that the GCD of number one and number two, 1092 01:04:49,440 --> 01:04:51,024 N1、N2是随机选取的两个数 two random numbers chosen, 1093 01:04:51,712 --> 01:04:53,664 是6/pi^2 is 6 over pi squared. 1094 01:04:55,616 --> 01:04:56,832 我不准备证明这个 I'm not going to try to prove that. 1095 01:04:57,152 --> 01:04:59,648 事实上这不难 并且有些有趣 It's actually not too hard and sort of fun. 1096 01:05:01,072 --> 01:05:03,056 我们要怎样估算这个概率呢? How would we estimate such probability? 1097 01:05:03,536 --> 01:05:06,464 我们估算概率的方法则是 Well, the way we do that, the way we estimate the probabilities, 1098 01:05:07,232 --> 01:05:08,656 是做大量的实验 is by doing lots of experiments, 1099 01:05:09,200 --> 01:05:12,010 去计算成功的试验 and then computing the ratios of the ones that come out one way 1100 01:05:12,010 --> 01:05:13,584 与试验总次数的比率 to the total number of experiments we do. 1101 01:05:16,320 --> 01:05:17,280 这种方法叫做蒙特卡罗方法 It's called Monte Carlo, 1102 01:05:18,048 --> 01:05:22,380 它也可以用于计算包含大量变量的积分 and it's useful in other contexts for doing things like integrals where you have lots and lots of variables-- 1103 01:05:22,944 --> 01:05:25,280 其中积分的面积是限定的 the space which is limiting the dimensions you are doing you integral in. 1104 01:05:26,272 --> 01:05:28,704 回到这里 But going back to here, 1105 01:05:29,760 --> 01:05:31,728 我们来看看这张幻灯片 Let's look at this slide, 1106 01:05:33,968 --> 01:05:36,928 我们可以用Cesaro的方法来估算pi的值 We can use Cesaro's method for estimating pi 1107 01:05:37,190 --> 01:05:43,180 通过N次试验 取结果的六分之一 开根号 with n trials by taking the square root of six over a Monte Carlo, 1108 01:05:43,290 --> 01:05:46,464 用蒙特卡罗方法 a Monte Carlo experiment with n trials, 1109 01:05:46,800 --> 01:05:50,380 进行了N次Cesaro实验 with n trials using Cesaro's experiment, 1110 01:05:51,376 --> 01:05:57,568 这个实验是关于两个随机数的最大公约数的-- where Cesaro's experiment is the test of whether the GCD of two random numbers-- 1111 01:05:58,960 --> 01:06:01,600 你可以看到 我已经在这里进行了一些赋值 And you can see that I've already got some assignments in here, 1112 01:06:01,840 --> 01:06:03,136 就像我写的这样 just by what I wrote. 1113 01:06:04,048 --> 01:06:07,490 这个在括号中的RAND The fact that this word rand, in parentheses, 1114 01:06:07,490 --> 01:06:09,097 这个过程调用 therefore, that procedure call, 1115 01:06:09,090 --> 01:06:11,395 生成了一个与这个RAND不同的值 yields a different value than this one, 1116 01:06:11,390 --> 01:06:13,728 至少是我写的这样所假设的 at least that's what I'm assuming by writing this this way, 1117 01:06:14,624 --> 01:06:16,752 这表明这不是一个函数 indicates that this is not a function, 1118 01:06:18,208 --> 01:06:20,576 这里面会有一个不断改变内部状态 that there's internal state in it which is changing. 1119 01:06:22,272 --> 01:06:28,640 如果两个随机数的最大公约数等于1 If the GCD of those two random numbers is equal to one, 1120 01:06:28,640 --> 01:06:29,792 这就是整个实验过程 that's the experiment. 1121 01:06:31,488 --> 01:06:35,184 那么我有了一个实验方法 用来估算pi的值 So here I have an experimental method for estimating the value of pi. 1122 01:06:36,512 --> 01:06:39,728 我可以轻松地将这个问题分为两个部分 Where, I can easily divide this problem into two parts. 1123 01:06:40,020 --> 01:06:44,704 一部分是使用蒙特卡罗方法进行特定的Cesaro实验 就像你刚才看到那个 One is the specific Monte Carlo experiment of Cesaro, which you just saw, 1124 01:06:44,992 --> 01:06:48,560 另一部分就是一般性蒙特卡罗方法的实现 and the other is the general technique of doing Monte Carlo experiments. 1125 01:06:49,168 --> 01:06:50,272 就是这个 And that's what this is. 1126 01:06:51,040 --> 01:06:55,472 如果我想进行N次蒙特卡罗试验 If I want to do Monte Carlo experiments with n trials, 1127 01:06:55,670 --> 01:06:58,368 即一个确定的试验次数 和一个确定的实验 a certain number of trials, and a particular experiment, 1128 01:06:59,312 --> 01:07:00,336 我进行实验的方法就是 the way I do that 1129 01:07:00,848 --> 01:07:02,704 构建一个迭代过程 is I make a little iterative procedure 1130 01:07:03,312 --> 01:07:07,264 这个过程有两个变量 分别是试验的剩余次数和通过次数 which has variable the number of trials remaining and the number trials that have been passed, 1131 01:07:08,352 --> 01:07:09,440 也就是实验结果为真的次数 that I've gotten true. 1132 01:07:10,130 --> 01:07:12,213 如果剩余次数为0 And if the number remaining is 0, 1133 01:07:12,210 --> 01:07:15,360 结果就是通过的次数除以总次数 then the answer is the number past divided by this whole number of trials, 1134 01:07:16,048 --> 01:07:17,520 也就是该概率的估算值 was the estimate of the probability. 1135 01:07:19,072 --> 01:07:20,040 如果剩余次数不是0 And if it's not, 1136 01:07:20,040 --> 01:07:22,080 如果还有试验要做 if I have more trials to do, 1137 01:07:22,080 --> 01:07:23,824 那么接下来我们就进行一次试验 then let's do one. We do an experiment. 1138 01:07:23,856 --> 01:07:27,300 我们调用一次没有参数的实验的过程 We call the procedure which is experiment on no arguments. 1139 01:07:27,300 --> 01:07:28,432 我们进行这个试验 We do the experiment 1140 01:07:29,104 --> 01:07:30,640 如果实验结果为真 and then, if that turned out to be true, 1141 01:07:30,820 --> 01:07:32,256 我们继续循环 we go around the loop 1142 01:07:32,620 --> 01:07:35,424 试验剩余次数减1 decrementing the number of experiments we have to do by one 1143 01:07:35,700 --> 01:07:37,488 将试验通过次数加1 and incrementing the number that were passed. 1144 01:07:38,576 --> 01:07:40,112 如果试验的结果为假 And if the experiment was false, 1145 01:07:40,416 --> 01:07:42,250 我们继续循环 we just go around the loop 1146 01:07:42,320 --> 01:07:44,380 剩余试验次数减1 decrementing the number of experiments remaining 1147 01:07:44,448 --> 01:07:46,608 试验通过次数保持不变 and keeping the number passed the same. 1148 01:07:48,768 --> 01:07:54,592 我们以TRIAL为剩余次数 以0为通过次数 开始迭代 We start this up iterating over the total number of trials with 0 experiments past. 1149 01:07:55,424 --> 01:07:57,104 多么简洁的小程序啊 A very elegant little program. 1150 01:07:57,744 --> 01:08:00,550 我不一定非要进行Cesaro的实验 And I don't have to just do this with Cesaro's experiment, 1151 01:08:00,550 --> 01:08:02,736 它可以用来进行很多种蒙特卡罗实验 it could be lots of Monte Carlo experiments I might do. 1152 01:08:03,360 --> 01:08:07,120 当然 它依赖于某种随机数生成器的存在 Of course, this depends upon the existence of some sort of random number generator. 1153 01:08:07,344 --> 01:08:10,992 随机数生成器通常是像这种的东西 And random number generators generally look something like this. 1154 01:08:13,600 --> 01:08:16,320 这是一个随机数生成器-- There is a random number generator-- 1155 01:08:17,424 --> 01:08:25,216 它实际上就是一个过程 具体行为跟计数器有些相似 is in fact a procedure which is going to do something just like the counter. 1156 01:08:25,616 --> 01:08:27,520 它会把X的值更新为 It's going to update an x 1157 01:08:28,336 --> 01:08:31,824 将某个函数应用于X的结果 to the result of applying some function to x, 1158 01:08:32,200 --> 01:08:35,280 而这类古怪的函数 where this function is some screwy kind of function 1159 01:08:35,392 --> 01:08:40,160 你可以在Kunth写的关于编程细节的书中找到 that you might find out in Knuth's books on the details of programming. 1160 01:08:41,568 --> 01:08:45,750 他写的书绝妙而充满了编程细节 He does these wonderful books that are full of the details of programming, 1161 01:08:45,750 --> 01:08:48,528 虽然我记不住随机数生成器该怎样写 because I can't remember how to make a random number generator, 1162 01:08:48,630 --> 01:08:50,624 但我可以在书里找出一个来用 but I can look it up there, and I can find out. 1163 01:08:51,648 --> 01:08:54,016 最后 我返回了X的值 And then, eventually, I return the value of x 1164 01:08:54,080 --> 01:08:57,408 也就是随机数生成器的内部状态变量 which is the state variable internal to the random number generator. 1165 01:08:58,288 --> 01:09:00,752 这个状态变量以某种方式被初始化 That state variable is initialized somehow, 1166 01:09:01,328 --> 01:09:02,240 从而获得了一个值 and has a value. 1167 01:09:03,392 --> 01:09:08,112 这个过程被定义在那个变量被约束的上下文中 And this procedure is defined in the context where that variable is bound 1168 01:09:10,416 --> 01:09:15,264 所以你在这看到的 是一个隐藏的局部状态 So this is a hidden piece of local state that you see here. 1169 01:09:15,872 --> 01:09:20,240 这个过程定义在那个上下文中 And this procedure is defined in that context. 1170 01:09:21,568 --> 01:09:23,664 这样做起来非常容易 Now, that's a very simple thing to do. 1171 01:09:24,880 --> 01:09:25,792 而且结果也非常好 And it's very nice. 1172 01:09:25,990 --> 01:09:27,776 设想 我不想用赋值 Supposing, I didn't want to use assignments. 1173 01:09:29,104 --> 01:09:31,472 假设我想写一个不带赋值的程序 Supposing, I wanted to write this program without assignments. 1174 01:09:32,736 --> 01:09:33,936 我将遇到什么困难? What problems would I have? 1175 01:09:35,520 --> 01:09:37,408 让我们来看看 Well, let's see. 1176 01:09:37,824 --> 01:09:41,104 我要用一下头顶上的投影仪了 I'd like to use the overhead machine here, 1177 01:09:42,064 --> 01:09:42,704 多谢 thank you. 1178 01:09:43,472 --> 01:09:47,660 首先 我们来整体看一下 这是一个很庞大的东西 First of all, let's look at the whole thing. It's a big story. Right? 1179 01:09:48,016 --> 01:09:49,904 它告诉你有某些东西出了问题 Unfortunately, which tells you there is something wrong. 1180 01:09:50,960 --> 01:09:52,752 毕竟有这么大一堆东西呢 It's at least that big, 1181 01:09:53,424 --> 01:09:54,608 庞大而单一 and it's monolithic. 1182 01:09:56,768 --> 01:10:00,120 你不需要现在去理解或看这里的文本 You don't have to understand or look at the text there right now 1183 01:10:00,120 --> 01:10:01,392 就把它们看做一个整体 to see that it's monolithic. 1184 01:10:01,920 --> 01:10:04,897 它不是Cesaro的实验 It isn't a thing which is Cesaro's experiment. 1185 01:10:04,890 --> 01:10:07,904 它不是从蒙特卡罗过程中抽取出来的 It's not pulled out from the Monte Carlo process. 1186 01:10:09,872 --> 01:10:11,840 它不是分离的 让我们来看看为什么 It's not separated. Let's look why. 1187 01:10:14,224 --> 01:10:15,850 记住 这里的约束是 Remember, the constraint here 1188 01:10:15,850 --> 01:10:17,872 每个过程 is that every procedure 1189 01:10:18,690 --> 01:10:22,208 对于同样的参数 将返回同样的值 return the same value for the same arguments. 1190 01:10:22,976 --> 01:10:24,752 每个过程就是一个函数 Every procedure represents a function. 1191 01:10:26,928 --> 01:10:28,500 那是另一种约束 That's a different kind of constraint. 1192 01:10:28,500 --> 01:10:31,216 因为当我赋值时 我可以改变一些内部状态变量 Because when I have assignments, I can change some internal state variable. 1193 01:10:31,744 --> 01:10:34,032 所以让我们来看看它是怎么出错的 So let's see how that causes things to go wrong. 1194 01:10:35,040 --> 01:10:36,144 我们从头开始 Well, start at the beginning. 1195 01:10:37,504 --> 01:10:41,920 估算pi的过程看起来是一样的 Ah...The estimate of pi looks sort of the same. 1196 01:10:42,660 --> 01:10:45,888 我取RAMDOM-GCD-TEST应用于N What I'm doing is I take the square root 1197 01:10:46,352 --> 01:10:50,224 的结果分之6的平方根 of six over the random GCD test applied to n 1198 01:10:50,740 --> 01:10:51,936 就是这个 whereas that's what this is. 1199 01:10:52,960 --> 01:10:55,200 在这里 我们开始看到了一些有趣的东西 But here, we are beginning to see something funny. 1200 01:10:55,200 --> 01:10:57,936 对于以TRAILS为参数的RANDOM-GCD-TEST过程 The random GCD test of a certain number of trials 1201 01:10:58,320 --> 01:10:59,984 就像我们之前做的一样 is just like we had before, 1202 01:11:00,460 --> 01:11:04,666 是一个以剩余次数 an iteration on the number of trials remaining, 1203 01:11:04,660 --> 01:11:06,800 通过次数 the number of trials that have been passed, 1204 01:11:08,272 --> 01:11:09,712 另一个变量X为基准的迭代 and another variable x. 1205 01:11:10,752 --> 01:11:11,760 这个X是什么? What's that x? 1206 01:11:12,330 --> 01:11:15,200 X是随机数发生器的状态 That x is the state of the random number generator. 1207 01:11:19,008 --> 01:11:21,160 它会在这里被使用 And it is now going to be used here. 1208 01:11:21,160 --> 01:11:23,791 这里的同样的随机更新函数 The same random update function that I have over here 1209 01:11:23,790 --> 01:11:27,152 来自于一个我另外写的随机数发生器 is the one I would have used in a random number generator if I were building it the other way, 1210 01:11:27,712 --> 01:11:29,328 或者从Knuth的书中找一个 the one I get out of Knuth's books. 1211 01:11:31,560 --> 01:11:33,360 X将转化为X1 x is going to get transformed into x1, 1212 01:11:33,376 --> 01:11:34,360 但我需要两个随机数 I need two random numbers. 1213 01:11:34,816 --> 01:11:36,928 X1将被转化为X2 And x1 is going to get transformed into x2, 1214 01:11:37,264 --> 01:11:38,448 我有两个随机数 I have two random numbers. 1215 01:11:39,504 --> 01:11:42,144 然后进行和之前一样的步骤 I then have to do exactly what I did before. 1216 01:11:42,520 --> 01:11:44,192 取X1和X2的最大公约数 I take the GCD of x1 x2. 1217 01:11:44,224 --> 01:11:47,152 如果结果是1 则将X2作为下一个X的值继续循环 If that's one, then I go around the loop with X2 being the next value of x. 1218 01:11:54,784 --> 01:11:55,984 这里所发生的 You see what's happened here 1219 01:11:56,880 --> 01:11:58,704 随机数发生器的状态 is that the state of the random number generator 1220 01:11:58,736 --> 01:12:01,700 不再被限制于其内部 is no longer confined to the insides of the random number generator. 1221 01:12:01,808 --> 01:12:02,736 它已经暴露了出来 It has leaked out. 1222 01:12:03,330 --> 01:12:05,506 它已经被暴露在 It has leaked out into my procedure 1223 01:12:05,500 --> 01:12:10,080 我们的的蒙特卡罗实验的过程中 that does the Monte Carlo experiment. 1224 01:12:10,704 --> 01:12:11,870 但比那更糟糕的是 But what's worse than that, 1225 01:12:11,870 --> 01:12:16,240 同样的 因为它也被包含在我们的Cesaro实验中 is it's also, because it was contained inside my experiment itself, Cesaro, 1226 01:12:16,784 --> 01:12:19,488 它被暴露了两次 因为Cesaro被调用了两次 It leaked out that two. Because Cesaro called twice, 1227 01:12:20,864 --> 01:12:22,470 每次有不同的值 has to have a different value each time, 1228 01:12:22,470 --> 01:12:25,168 如果我要进行一个合理的实验的话 if I going to have a legitimate experimental test. 1229 01:12:26,320 --> 01:12:28,320 所以Cesaro也不能成为函数了 So Cesaro can't be a function either, 1230 01:12:31,040 --> 01:12:35,696 除非我把随机数发生器的种子传给它 unless I pass it the seed of the random number generator that is going to go wandering around. 1231 01:12:36,528 --> 01:12:39,370 所以很不幸 随机数发生器的种子 So unfortunately, the seed of random number generator 1232 01:12:39,370 --> 01:12:42,777 从随机数发生器中暴露到了Cesaro内部 has leaked out into Cesaro, from the random number generator, 1233 01:12:42,880 --> 01:12:45,168 被暴露在蒙特卡罗实验中 that's leaked into the Monte Carlo experiment. 1234 01:12:45,648 --> 01:12:49,120 很不幸 这里的蒙特卡罗实验不再是通用的了 And, unfortunately, my Monte Carlo experiment here is no longer general. 1235 01:12:50,256 --> 01:12:51,808 这里的蒙特卡罗实验 The Monte Carlo experiment here 1236 01:12:52,032 --> 01:12:54,736 知道了我在实验中需要多少个随机数 knows how many random numbers I need to do the experiment. 1237 01:12:58,960 --> 01:12:59,744 这真的很糟糕 That's sort of horrible. 1238 01:13:00,080 --> 01:13:02,544 我失去了将问题分解开来的能力 I lost an ability to decompose a problem into pieces, 1239 01:13:03,440 --> 01:13:09,120 因为我不愿意接受信息的循环 because I wasn't willing to accept the little loop of information, 1240 01:13:09,504 --> 01:13:12,432 反馈的过程 the feedback process, 1241 01:13:12,880 --> 01:13:15,940 这之前都是发生在随机数发生器内部 that happens inside the random number generator before 1242 01:13:15,940 --> 01:13:21,216 也就是赋值给一个限制在随机数生成器内部的状态变量 that was made by having an assignment to a state variable that was confined to the random number generator. 1243 01:13:22,920 --> 01:13:25,488 所以实际上 随机数发生器是一个对象 So the fact that the random number generator is an object, 1244 01:13:25,920 --> 01:13:27,376 它有一个内部状态变量 with an internal state variable, 1245 01:13:28,064 --> 01:13:29,360 它不受任何东西影响 it's affected by nothing, 1246 01:13:29,376 --> 01:13:31,600 但是它会给你某些东西 把它的力量赐予你 but it'll give you something, and it will apply it's force to you, 1247 01:13:32,800 --> 01:13:34,288 那是我们现在缺少的 that was what we're missing now. 1248 01:13:38,000 --> 01:13:40,730 好 我认为我已经知道了 OK, well I think we've seen 1249 01:13:40,730 --> 01:13:42,304 引入赋值的充分理由 enough reason for doing this, 1250 01:13:42,832 --> 01:13:45,248 并且一些看起来很圆满 and it all sort of looks very wonderful. 1251 01:13:45,380 --> 01:13:50,704 如果赋值是一个好东西 Wouldn't it be nice if assignment was a good thing 1252 01:13:51,740 --> 01:13:53,040 并且赋值是值得的 这不是很好吗? and maybe it's worth it, 1253 01:13:53,280 --> 01:13:54,144 我不是很确定 but I'm not sure. 1254 01:13:55,344 --> 01:13:57,040 Mr. Gilbert和Sullivan说过 As Mr. Gilbert and Sullivan said, 1255 01:13:57,040 --> 01:13:58,515 事物往往不像表面看到的那样 things are seldom what they seem, 1256 01:13:58,510 --> 01:14:00,352 脱脂牛奶也能装成奶油 skim milk masquerades as cream. 1257 01:14:01,872 --> 01:14:03,904 谁有什么问题吗? Are there any questions? 1258 01:14:16,976 --> 01:14:18,304 在座的有哲学家吗? Are there any philosophers here? 1259 01:14:20,064 --> 01:14:22,032 有人想要讨论有关“对象”的问题吗? Anybody want to argue about objects? 1260 01:14:24,320 --> 01:14:25,504 你们已经一头雾水了是吧? You're just floored, right? 1261 01:14:29,720 --> 01:14:30,720 你们还没有完成家庭作业呢 And you haven't done your homework yet. 1262 01:14:30,736 --> 01:14:32,000 你们需要提一个好问题 You haven't come up with a good question. 1263 01:14:36,352 --> 01:14:37,440 好了 Oh, well. 1264 01:14:39,970 --> 01:14:42,336 感谢你们 我们下课吧 Sure, thank you. Let's take the long break now. 1265 01:14:47,900 --> 01:14:56,416 MIT OpenCourseWare http://ocw.mit.edu 1266 01:14:56,448 --> 01:15:05,696 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec5b.srt ================================================ 1 00:00:00,016 --> 00:00:02,464 Learning-SICP学习小组 倾情制作 2 00:00:02,608 --> 00:00:05,376 翻译&&时间轴:张大伟(DreamAndDead) 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:05,408 --> 00:00:08,128 特别感谢:裘宗燕教授 4 00:00:08,144 --> 00:00:12,400 计算机程序的构造和解释 5 00:00:12,496 --> 00:00:17,170 计算对象 Computational Objects 6 00:00:21,170 --> 00:00:24,128 现在我们已经学习了 PROFESSOR: Well, now that we've given you some power 7 00:00:24,432 --> 00:00:27,400 如何创建局部状态和如何建模对象 to make independent local state and to model objects, 8 00:00:28,336 --> 00:00:32,672 我想我们应该找点复杂的东西 I thought we'd do a bit of programming of a very complicated kind, 9 00:00:34,032 --> 00:00:36,368 来实践一下学过的这些知识 just to illustrate what you can do with this sort of thing. 10 00:00:40,430 --> 00:00:43,488 我可以这么说 假设我们处在现实世界中 I suppose, as I said, we were motivated by physical systems 11 00:00:44,112 --> 00:00:46,256 我们把这个世界看作是 the ways we like to think about physical systems, 12 00:00:46,992 --> 00:00:51,088 由许多的事物构成的 which is that there are these things that the world is made out of. 13 00:00:52,060 --> 00:00:55,984 每个事物都有其独立的局部状态 And each of these things has particular independent local state, 14 00:00:57,248 --> 00:00:59,872 正是这些独立的状态使其成为事物 and therefore it is a thing. That's what makes it a thing. 15 00:01:01,280 --> 00:01:04,272 因此我们说 在这个世界的模型中 And then we're going to say that in the model in the world 16 00:01:04,288 --> 00:01:09,900 我们在大脑中和计算机中对那个世界建模 we have a world and a model in our minds and in the computer of that world. 17 00:01:10,940 --> 00:01:12,544 我想要建立一种对应关系 And what I want to make is a correspondence 18 00:01:12,784 --> 00:01:15,216 把现实世界和计算机中的对象联系起来 between the objects in the world and the objects in the computer, 19 00:01:15,870 --> 00:01:17,744 把现实世界中对象间的关系 the relationships between the objects in the world 20 00:01:17,968 --> 00:01:21,720 与计算机中的模型对象间的关系 对应起来 and the relationships between those same obj...--the model objects in the computer, 21 00:01:23,180 --> 00:01:25,520 把现实世界中关联对象的函数 and the functions that relate things in the 22 00:01:25,936 --> 00:01:28,110 与计算机中的函数 对应起来 to the functions that relate things in the computer. 23 00:01:30,840 --> 00:01:33,824 这让我们获得了模块性 This buys us modularity. 24 00:01:34,740 --> 00:01:36,752 如果我们认为现实世界是像那样的 If we really believe the world is like that, 25 00:01:37,360 --> 00:01:38,720 也就是由许多小的事物构成的 that it's made out of these little pieces, 26 00:01:39,200 --> 00:01:41,472 当然 我们可以把世界安排成那样 and of course we could arrange our world to be like that, 27 00:01:42,032 --> 00:01:43,952 我们只能对像那样的事物建模 we could only model those things that are like that, 28 00:01:45,456 --> 00:01:49,024 这样 我们的程序就可以从现实世界中继承模块化 then we can inherit the modularity in the world into our programming. 29 00:01:50,450 --> 00:01:53,584 这就是发明面向对象编程的初衷 That's why we would invent some of this object-oriented programming. 30 00:01:55,420 --> 00:01:58,192 我所见过的最完美的对象(系统) Well, let's take the best kind of objects I know. 31 00:01:58,890 --> 00:02:04,176 电气系统 就是非常非常完美的对象系统 They're completely--they're completely wonderful: electrical systems. 32 00:02:06,400 --> 00:02:12,992 电气系统真的是物理学家构造的非常非常好的一种对象 Electrical systems really are the physicist's best, best objects. 33 00:02:14,220 --> 00:02:16,760 这里 我有一些机器零件 You see over here I have some piece of machinery. 34 00:02:17,120 --> 00:02:18,288 就是这些零件 Right here's a piece of machinery. 35 00:02:20,040 --> 00:02:22,880 有一个电线连接起了 And it's got an electrical wire connecting 36 00:02:23,664 --> 00:02:26,400 零件的两个部分 one part of the machinery with another part of the machinery. 37 00:02:27,568 --> 00:02:30,864 电气世界中 有一个非常棒的特性 And one of the wonderful properties of the electrical world 38 00:02:31,648 --> 00:02:33,120 就是我可以说这是一个对象 is that I can say this is an object, 39 00:02:34,016 --> 00:02:34,976 这又是一个对象 and this is an object, 40 00:02:35,712 --> 00:02:37,536 它们间的关联一目了然 and they're-- the connection between them is clear. 41 00:02:38,240 --> 00:02:43,328 而且 如果我没有用电线连接 它们便没有关联 In principle, there is no connection that I didn't describe with these wires. 42 00:02:44,740 --> 00:02:46,128 比如我有一个灯泡 Let's say if I have light bulbs, 43 00:02:46,528 --> 00:02:50,320 一个灯泡和一个已经接在插座上的电源 Let's say if I have light bulbs, a light bulb and a power supply that's plugged into the outlet. 44 00:02:51,632 --> 00:02:53,536 关联非常明了 Then the connection is perfectly clear. 45 00:02:53,620 --> 00:02:55,424 这就是已知所有的连接方式了 There's no other connections that we know of. 46 00:02:56,220 --> 00:03:02,336 就算我把连接电灯和电源的电线打个结 If I were to tie a knot in the wire that connects the light bulb to the power supply, 47 00:03:02,688 --> 00:03:03,648 灯仍然是亮的 the light remains lit up. 48 00:03:04,040 --> 00:03:04,768 没什么影响 It doesn't care. 49 00:03:07,440 --> 00:03:12,400 物理学上这样安排 可以使连接变成抽象的 That the way the physics is arranged is such that the connection can be made abstract, 50 00:03:13,088 --> 00:03:15,270 至少在低频状态下是可以的 at least for low frequencies and things like that. 51 00:03:17,840 --> 00:03:20,880 而且这就是全部的关联方式了 So in fact, we have captured all of the connections there really are. 52 00:03:22,350 --> 00:03:23,872 当然 我们来进一步 Well, as you can go one step further 53 00:03:23,904 --> 00:03:27,310 讨论一种在电气系统中最为广泛的抽象 and talk about the most abstract types of electrical systems we have, 54 00:03:27,856 --> 00:03:29,420 数字电路 digital to dual circuits. 55 00:03:31,696 --> 00:03:33,664 这里有一些对象 And here there are certain kinds of objects. 56 00:03:34,640 --> 00:03:40,128 例如 在数字电路里中 我们有非门 For example, in digital circuits we have things like inverters. 57 00:03:41,392 --> 00:03:42,784 有与门 We have things like and-gates. 58 00:03:43,990 --> 00:03:45,408 还有或门 We have things like or-gates. 59 00:03:47,210 --> 00:03:50,128 我们用一种特殊的“电线” 把它们连接起来 We connect them together by sort-of wires 60 00:03:52,000 --> 00:03:54,944 这些“电线”代表抽象信号 which represent abstract signals. 61 00:03:55,610 --> 00:03:57,184 我们不关心具体的物理因素 We don't really care as physical variables 62 00:03:57,210 --> 00:03:59,728 像电压、电流或者组合因素等 whether these are voltages or currents or some combination 63 00:04:00,016 --> 00:04:03,440 又或者是水压 等等 or water, water pressure. 64 00:04:05,200 --> 00:04:07,328 这些抽象变量代表某类信号 These abstract variables represent certain signals. 65 00:04:09,420 --> 00:04:12,896 我们用电路连接元件 构建系统 And we build systems by wiring these things together with wires. 66 00:04:14,070 --> 00:04:16,224 现在 我要向你们介绍一门新的语言 So today what I'm going to show you, right now, 67 00:04:17,632 --> 00:04:20,176 我们要构建一门内嵌于Lisp中的语言 we're going to build up an invented language in Lisp, 68 00:04:22,144 --> 00:04:25,088 这是一种内部DSL 是类似于之前讲过的图形语言那种 embedded in the same sense that Henderson's picture language was embedded, 69 00:04:26,160 --> 00:04:27,328 而不是昨天那种 which is not the same sense 70 00:04:27,888 --> 00:04:31,610 那种模式匹配语言 -- 那是外部DSL as the language of pattern match and substitution was done yesterday. 71 00:04:32,800 --> 00:04:36,300 模式匹配语言是由Lisp程序所解释的 The pattern match substitution language was interpreted by a Lisp program. 72 00:04:38,160 --> 00:04:40,528 而之前那种图形语言 But the embedding of Henderson's program 73 00:04:40,560 --> 00:04:44,270 是在Lisp中构造我们想要的过程 来封装图形结构 is that we just build up more and more procedures that encapsulate the structure we want. 74 00:04:45,480 --> 00:04:46,752 举例来说 So for example here, 75 00:04:47,728 --> 00:04:50,640 首先我要有一些基本对象 I'm going to have some various primitive kinds of objects, as you see, 76 00:04:51,056 --> 00:04:52,128 比如这个和这个 that one and that one. 77 00:04:53,504 --> 00:04:55,184 然后用电线去组合它们 I'm going to use wires to combine them. 78 00:04:55,984 --> 00:04:59,376 我用(MAKE-WIRE)来构造一个电线 The way I represent attaching-- I can make wires. 79 00:04:59,870 --> 00:05:01,248 A就代表了一根电线 So let's say A is a wire. 80 00:05:01,740 --> 00:05:02,690 B也是 And B is a wire. 81 00:05:02,690 --> 00:05:03,460 C也是 And C is a wire. 82 00:05:03,460 --> 00:05:04,230 D也是 And D is a wire. 83 00:05:04,230 --> 00:05:04,830 还有E And E is wire. 84 00:05:04,830 --> 00:05:05,648 S也是 And S is a wire. 85 00:05:06,880 --> 00:05:12,752 而或门有两个输入 分别是A和B Well, an or-gate that has both inputs, the inputs being A and B, 86 00:05:13,168 --> 00:05:14,752 它的输出是D and the output being wire D, 87 00:05:15,072 --> 00:05:16,128 我们用这样的记号来表示 you notate like this. 88 00:05:18,140 --> 00:05:22,144 与门 输入是A和B 输出是C An and-gate, which has inputs A and B and output C, 89 00:05:22,224 --> 00:05:23,240 我们这样表示 we notate like that. 90 00:05:24,820 --> 00:05:28,464 通过一系列像这样的声明 By making such a sequence of declarations, 91 00:05:29,296 --> 00:05:31,648 我可以组合出任意的电路 I can wire together an arbitrary circuit. 92 00:05:32,750 --> 00:05:34,640 我已经告诉了你们创建数字电路 So I've just told you a set of primitives 93 00:05:35,312 --> 00:05:38,510 的基本元素和组合方法了 and means of combination for building digital circuits, 94 00:05:40,096 --> 00:05:43,040 然后就该说抽象的方法了 when I need more in a real language than abstraction. 95 00:05:43,690 --> 00:05:52,240 举例来说 这是一个半加器 And so for example, here I have--here I have a half adder. 96 00:05:52,672 --> 00:05:55,552 如果你学过电路设计肯定知道这个东西 It's something you all know if you've done any digital design. 97 00:05:56,930 --> 00:06:00,448 输入两个数A和B It's used for adding numbers together on A and B 98 00:06:00,624 --> 00:06:02,120 输出两者之和以及进位 and putting out a sum and a carry. 99 00:06:04,352 --> 00:06:06,800 事实上 完全可以用我刚刚说的来组合电路 And in fact, the wiring diagram is exactly what I told you. 100 00:06:07,450 --> 00:06:10,992 盒子外面 半加器盒子的外面有一些接口 A half adder with things that come out of the box-- 101 00:06:11,136 --> 00:06:14,112 这些盒子的边界 我们总是抽象成盒子 you see the box, the boundary, the abstraction is always a box. 102 00:06:14,790 --> 00:06:19,700 从盒子里引出A、B、S、C四根线 And there are things that come out of it, A, B, S, and C. 103 00:06:19,700 --> 00:06:21,792 这些是已经声明了的变量 Those are the declared variables-- 104 00:06:23,390 --> 00:06:26,256 由LAMBDA表达式声明的几个变量 declared variables of a lambda expression, 105 00:06:26,288 --> 00:06:28,010 定义了这个半加器 which is the one that defines half adder. 106 00:06:31,400 --> 00:06:35,968 在盒子的内部 我构造了电线D和E And internal to that, I make up some more wires, D and E, 107 00:06:36,000 --> 00:06:37,440 这是为了连接内部结构 which I'm going to use for the interconnect-- 108 00:06:37,744 --> 00:06:40,400 这条是E 这条是D here E is this one and D is this wire, 109 00:06:41,328 --> 00:06:43,504 内部连接的线路并没有引出盒子之外 the interconnect that doesn't come through the walls of the box-- 110 00:06:45,056 --> 00:06:46,832 就像电路图那样连起来 and wire things together as you just saw. 111 00:06:48,790 --> 00:06:50,896 大家可以看得出来 And the nice thing about this that I've just shown you 112 00:06:51,056 --> 00:06:53,024 这个语言非常有层次性 this language is hierarchical in the right way. 113 00:06:53,856 --> 00:06:55,712 如果一门语言没有层次性 If a language isn't hierarchical in the right way, 114 00:06:55,952 --> 00:06:59,968 如果你不能把一个复合对象当成基本对象来使用 if it turns out that a compound object doesn't look like a primitive, 115 00:07:00,384 --> 00:07:01,536 这门语言肯定是有问题的 there's something wrong with the language-- 116 00:07:02,592 --> 00:07:04,224 至少我是这么认为的 at least the way I feel about that. 117 00:07:06,410 --> 00:07:09,584 之前 我们都是在研究数学函数 So here we have--here, instead of starting with mathematical functions, 118 00:07:09,600 --> 00:07:11,120 或者是计算数学函数的东西 or things that compute mathematical functions, 119 00:07:11,152 --> 00:07:12,650 这些都是我们之前研究的东西 which is what we've been doing up until now, 120 00:07:13,850 --> 00:07:16,656 而我们现在 instead of starting with things that look like mathematical functions, 121 00:07:16,672 --> 00:07:17,630 不这么做了 or compute such things, 122 00:07:17,850 --> 00:07:20,880 我们从一些电气对象开始 we are starting with things that are electrical objects 123 00:07:21,040 --> 00:07:22,640 构建更多的对象 and we build up more electrical objects. 124 00:07:23,350 --> 00:07:28,832 我们用Lisp里的LAMBDA将其粘合起来 And the glue we're using is basically the Lisp structure: lambdas. 125 00:07:30,384 --> 00:07:32,930 “LAMBDA: 终极之粘合剂” Lambda is the ultimate glue, if you will. 126 00:07:33,320 --> 00:07:36,352 当然 半加器可以用于 And of course, half adder itself can be used 127 00:07:37,648 --> 00:07:41,040 构造一种更复杂的抽象结构 -- 全加器 in a more complicated abstraction called a full adder, 128 00:07:41,600 --> 00:07:45,056 如这里所示 全加器由两个半加器构成 which in fact involves two half adders, as you see here, 129 00:07:45,470 --> 00:07:47,872 用一些额外的电线连接起来 hooked together with some extra wires, 130 00:07:48,080 --> 00:07:51,290 就像这里所示的S、C1、C2以及一个或门 that you see here, S, C1, and C2, and an or-gate, 131 00:07:52,190 --> 00:07:53,600 而对于一个全加器 to manufacture a full adder, 132 00:07:53,872 --> 00:08:00,780 它的输入有:两个待加的数 一个进位值 which takes a input number, another input number, a carry in, 133 00:08:01,360 --> 00:08:04,176 输出是:两数之和以及进位 and produces output, a sum and a carry out. 134 00:08:05,900 --> 00:08:10,704 构建好全加器以后 还可以把它们链起来组成更大的加法器 And out of full adders, you can make real adder chains and big adders. 135 00:08:12,990 --> 00:08:14,832 现在我们有了一门完整的语言 So we have here a language so far 136 00:08:16,064 --> 00:08:21,760 它有基本元素、组合方法以及抽象方法 That has primitives, means of combination, and means of abstraction to real language. 137 00:08:22,270 --> 00:08:23,360 现在 我们怎样实现这门语言? Now, how are we going to implement this? 138 00:08:25,000 --> 00:08:26,848 其实并不难 Well, let's do it easily. 139 00:08:27,070 --> 00:08:27,968 首先来看基本元素 Let's look at the primitives. 140 00:08:28,128 --> 00:08:30,112 这是唯一的问题 The only problem is we have to implement the primitives. 141 00:08:31,160 --> 00:08:32,560 不需要再做其它事情了 Nothing else has to be implemented, 142 00:08:33,744 --> 00:08:38,000 因为我们直接借用了Lisp中的组合方法以及抽象方法 because we're picking up the means of combination and abstraction from Lisp, 143 00:08:39,968 --> 00:08:41,888 我们的语言 继承自Lisp并内嵌于其中 inheriting them in the embedding. 144 00:08:43,776 --> 00:08:45,440 好 我们先来看一个基本元素 OK, so let's look at a particular primitive. 145 00:08:45,860 --> 00:08:47,400 就拿非门来说吧 An inverter is a nice one. 146 00:08:51,540 --> 00:08:54,672 非门有两个引脚 分别是输入和输出 Now, inverter has two wires coming in, an in and an out. 147 00:08:57,312 --> 00:09:02,624 它要对输入信号做出响应 And somehow, it's going to have to know what to do when a signal comes in. 148 00:09:04,300 --> 00:09:07,008 它需要对输入电线说 -- So somehow it's going to have to tell its input wire-- 149 00:09:07,640 --> 00:09:10,144 我们现在把它们视作对象 and now we're going to talk about objects 150 00:09:10,448 --> 00:09:12,416 其具体细节我们稍后讨论 and we're going to see this in a little more detail soon-- 151 00:09:13,230 --> 00:09:14,848 它对其输入电线的说 but it's going to have to tell its input wire 152 00:09:15,824 --> 00:09:18,480 “当你的值变发生改变时 告诉我一声” that when you change, tell me. 153 00:09:20,120 --> 00:09:22,112 所以非门这个对象 So this object, the object which is the inverter 154 00:09:22,416 --> 00:09:24,384 会对输入电线这个对象说 -- has to tell the object which is the input wire, 155 00:09:25,136 --> 00:09:26,400 “Hi 我是George” hi, my name is George. 156 00:09:26,870 --> 00:09:31,024 “我的工作就是 对你的变化做出响应” And my, my job is to do something with results when you change. 157 00:09:31,720 --> 00:09:34,192 “所以当你变化的时候 告诉我一声” So when you change, you get a change, tell me about it. 158 00:09:34,730 --> 00:09:35,728 “这样我才能进一步的处理” Because I've got to do something with that. 159 00:09:36,880 --> 00:09:40,304 这是通过在这里 在输入电线上 Well, that's done down here by adding an action on the input wire called invert-in, 160 00:09:41,408 --> 00:09:44,640 添加一个叫做INVERT-IN的动作来实现的 Well, that's done down here by adding an action on the input wire called invert-in, 161 00:09:45,070 --> 00:09:46,944 INVERT-IN在这里定义 where invert-in is defined over here 162 00:09:47,056 --> 00:09:48,760 它是一个无参过程 to be a procedure of no arguments, 163 00:09:49,984 --> 00:09:54,592 它将线路上的信号逻辑取反 which gets the logical not of the signal on the input wire. 164 00:09:56,064 --> 00:09:58,640 经过一段时长为INVERTER-DELAT的延时以后 -- And after some delay, which is the inverter delay, 165 00:09:59,264 --> 00:10:01,152 每个电路对象都有延时 -- all these electrical objects have delays, 166 00:10:02,880 --> 00:10:04,460 然后我们会 -- we'll do the following thing-- 167 00:10:04,672 --> 00:10:07,140 我们再把输出设置为新的值 set the signal on the output wire to the new value. 168 00:10:10,160 --> 00:10:11,360 非常简单 A very simple program. 169 00:10:12,400 --> 00:10:15,280 你可以想象输出电线也同样是信号敏感的 Now, you have to imagine that the output wire has to be sensitive 170 00:10:15,770 --> 00:10:18,272 当信号改变的时候 and know that when its signal changes, 171 00:10:19,280 --> 00:10:21,150 它会“告知”其它对象 it may have to tell other guys, 172 00:10:21,792 --> 00:10:24,784 “快醒醒!我的值已经改变啦” Hi, wake up. My value has changed. 173 00:10:26,050 --> 00:10:30,144 所以当你把非门和与门或者元件连在一起的时候 So when you hook together inverter with an and-gate or something like that, 174 00:10:30,464 --> 00:10:32,208 它们之间将会有大量的通信 there has to be a lot of communication going on 175 00:10:32,864 --> 00:10:35,072 以确保信号正确地传播 to make sure that the signal propagates right. 176 00:10:36,810 --> 00:10:38,620 到目前为止 没什么新奇的东西 And down here is nothing very exciting. 177 00:10:38,620 --> 00:10:40,720 我们只是针对某个特定的表示法 This is just the definition of logical not 178 00:10:40,720 --> 00:10:45,240 也就是这个例子中的1、0 -- 实现了LOGICAL-NOT而已 for some particular representations of the logical values-- 1, 0 in this case. 179 00:10:46,736 --> 00:10:49,168 与门就相对复杂一些 And we can look at things more complicated like and-gates. 180 00:10:49,780 --> 00:10:55,808 与门有两个输入A1和A2 输出是OUTPUT And-gates take two inputs, A1 and A2, we'll call them, and produce an output. 181 00:10:56,736 --> 00:11:00,640 但是其结构和非门没有什么大的不同 But the structure of the and-gate is identical to the one we just saw. 182 00:11:00,860 --> 00:11:03,440 只不过是 当输入信号改变的时候 There's one called an and-action procedure that's defined, 183 00:11:04,528 --> 00:11:09,070 与门调用的是AND-ACTION过程罢了 which is the thing that gets called when an input is changed. 184 00:11:10,910 --> 00:11:12,880 当然 它所做的只是 And what it does, of course, is nothing more than 185 00:11:12,912 --> 00:11:15,370 对输入信号进行逻辑“与”运算 compute the logical and of the signals on the inputs. 186 00:11:16,192 --> 00:11:18,768 在经过AND-GATE-DELAY的延时之后 And after some delay, called the and-gate-delay, 187 00:11:20,464 --> 00:11:24,368 调用这个过程 更新输出信号值 calls this procedure, which sets a signal on the output to a new value. 188 00:11:25,470 --> 00:11:28,350 那么 我们如何用“按愿望思维”来构造这一切呢? Now, how I implement these things is all wishful thinking. 189 00:11:28,350 --> 00:11:31,088 如大家所见 这里有一个赋值运算 As you see here, I have an assignment operation. 190 00:11:32,020 --> 00:11:32,784 但并不是SET! It's not set. 191 00:11:34,570 --> 00:11:36,784 这是一个派生出来的运算 It's a derived assignment operation in the same way 192 00:11:36,784 --> 00:11:38,730 就像可以从CAR和CDR派生出其它函数一样 we had functions that were derived from CAR and CDR. 193 00:11:40,800 --> 00:11:44,816 因此 按照约定 我加上“!”(表示这个过程有副作用) So I, by convention, label that with an exclamation point. 194 00:11:46,340 --> 00:11:49,184 这里有个过程ADD-ACTION! And over here, you see there's an add-action!, 195 00:11:49,440 --> 00:11:54,672 它用来提醒与门中的局部线路A1 which is to inform the wire, called A1 locally in this and-gate, 196 00:11:55,632 --> 00:11:58,688 当它改变的时候记得执行过程AND-ACTION-PROCEDURE to call the and-action-procedure when it gets changed, 197 00:11:59,584 --> 00:12:02,912 A2也是一样 and the wire A2 to call the and-action procedure when it gets changed. 198 00:12:06,310 --> 00:12:07,232 非常简单 All very simple. 199 00:12:09,960 --> 00:12:12,096 现在我们再来看看 Well, let's talk a little bit about this communication 200 00:12:12,704 --> 00:12:16,120 各部分间是如何通信的 that must occur between these various parts. 201 00:12:18,544 --> 00:12:19,664 例如 Suppose, for example, 202 00:12:23,120 --> 00:12:24,272 有一个非常简单的电路 I have a very simple circuit 203 00:12:24,272 --> 00:12:30,460 它有一个与门 带有两个输入A、B which contains and-gate with wires a and b. 204 00:12:31,920 --> 00:12:38,000 与门通过电线C跟非门相连 And that connects through a wire called c to an inverter 205 00:12:39,728 --> 00:12:41,536 非门的输出是D which has a wire output called d. 206 00:12:44,208 --> 00:12:47,344 这就是物理世界 What are the comput...--here's the physical world. 207 00:12:47,360 --> 00:12:49,024 一个对物理世界的抽象 It's an abstraction of the physical world. 208 00:12:49,860 --> 00:12:53,408 要不了几分钱就可以从Radio Shack买到这些元件 Now I can buy these out of little pieces that you get at Radio Shack for a few cents. 209 00:12:54,880 --> 00:12:56,320 那些元件的作用和画在这里的差不多 And there are boxes that act like this, 210 00:12:57,168 --> 00:13:00,220 元件上都标有类似于LS04的标签 which have little numbers on them like LS04 or something. 211 00:13:01,530 --> 00:13:08,160 现在来看其中的计算模型 Now supposing I were to try to say what's the computational model. 212 00:13:09,010 --> 00:13:10,944 它又对应着什么 What is the thing that corresponds to that, 213 00:13:11,136 --> 00:13:14,096 计算机中的对象对应着我们思维中的什么 that part of reality in the mind of us and in the computer? 214 00:13:15,850 --> 00:13:19,136 我需要把现实世界中的每个对象与计算机中的对应起来 Well, I have to assign for every object in the world an object in the computer, 215 00:13:19,792 --> 00:13:24,272 把两个世界中对象之间的关系也对应起来 and for every relationship in the world between them a relationship in the computer. 216 00:13:26,064 --> 00:13:26,800 这是我的目标 That's my goal. 217 00:13:28,560 --> 00:13:29,456 让我们来看看怎么做 So let's do that. 218 00:13:30,900 --> 00:13:34,208 这一团东西代表信号A Well, I have some sort of thing called the signal, A. 219 00:13:35,712 --> 00:13:36,944 这是信号A This is A. It's a signal. 220 00:13:37,940 --> 00:13:39,328 画得像一团云 It's a cloudy thing like that. 221 00:13:39,900 --> 00:13:42,800 再画另一个信号 -- B And I have another one down here which I'm going to call B. 222 00:13:46,688 --> 00:13:47,470 它是另一个信号 It's another signal. 223 00:13:49,140 --> 00:13:50,912 这两个信号 Now this signal--these two signals 224 00:13:51,104 --> 00:13:52,816 要通过某种方式连在一起 are somehow going to have to hook together 225 00:13:53,728 --> 00:13:58,752 连在这个盒子上 -- 这就代表与门 into a box, let's call it this, which is the and-gate, action procedure. 226 00:14:00,320 --> 00:14:02,040 这就是与门的动作过程 That's the and-gate's action procedure. 227 00:14:07,660 --> 00:14:08,592 它将产生 And it's going to produce 228 00:14:09,152 --> 00:14:13,296 它将与另外一个称作C的信号对象交互 well, it's going to interact with a signal object, which we call C-- 229 00:14:16,224 --> 00:14:18,880 哦 说错了 是一条电线C a wire object, excuse me, we call C. 230 00:14:20,590 --> 00:14:26,288 这跟电线 又将连在另一个动作过程上 this is going to put out again, or connect to, another action procedure 231 00:14:26,288 --> 00:14:30,330 在我们的电气世界中 这个过程跟一个非门关联 which is one associated with the inverter in the world, not. 232 00:14:32,860 --> 00:14:40,656 我还有另外一根电线 -- D And I'm going to have another--another wire, which we'll call D. 233 00:14:42,970 --> 00:14:45,296 整体布局就是这样 So here's my layout of stuff. 234 00:14:46,000 --> 00:14:49,440 现在必须来研究它们 有关计算的内部机制了 Now we have to say what's inside them and what they have to know to compute. 235 00:14:51,500 --> 00:14:53,696 每一跟电线都必须知道 Well, every--every one of these wires has to know 236 00:14:53,696 --> 00:14:56,360 自己承载的信号是什么 what the value of the signal that's on that wire is. 237 00:14:57,340 --> 00:15:00,000 我们用变量SIGNAL来表示 So there's going to be some variable inside here, we'll call it signal. 238 00:15:02,976 --> 00:15:04,048 SIGNAL的值就是信号 And he owns a value. 239 00:15:05,680 --> 00:15:07,744 也不要忘了它所关联的环境 So there must be some environment associated with this. 240 00:15:08,896 --> 00:15:11,344 对于每个元件来说 一定有一个环境绑定了信号 And for each one of these, there must be an environment that binds signal. 241 00:15:15,400 --> 00:15:16,880 因此 这里也有一个SIGNAL变量 And there must be a signal here, therefore. 242 00:15:19,400 --> 00:15:21,920 SIGNAL的值不是0就是1 And presumably, signal's a value that's either 1 or 0, 243 00:15:22,816 --> 00:15:23,488 这儿也有个SIGNAL and signal. 244 00:15:28,000 --> 00:15:30,560 现在 一旦这里的信号改变 Now, we also have to have some 245 00:15:31,264 --> 00:15:34,112 我们需要通知一系列的对象 list of people to inform if the signal here changes. 246 00:15:36,660 --> 00:15:37,664 我们得通知这个与门 We're going to have to inform this. 247 00:15:39,300 --> 00:15:43,968 这里有个表 我们把它叫做AP So I've got that list. We'll call it the Action Procedures, AP. 248 00:15:44,500 --> 00:15:45,600 它可能是一个表 And it's presumably a list. 249 00:15:46,448 --> 00:15:49,008 在本例中 表里面的第一项条目是这个东西 But the first thing on the list, in this case, is this guy. 250 00:15:50,500 --> 00:15:54,810 这个元件也有一个称为AP的表 And the action procedures of this one happens to have some list of stuff. 251 00:15:54,810 --> 00:15:58,176 也可能有一些其它对象 时刻等待着A来通知“它们” There might be other people who are sharing A, who are looking at it. 252 00:15:59,020 --> 00:16:01,312 所以这里可能有其它对象 比如 So there might be other guys on this list, like 253 00:16:01,728 --> 00:16:03,230 一些其它我们不知道的对象 like somebody over there that we don't know about. 254 00:16:03,630 --> 00:16:04,880 这些是与A连接的其它对象 It's the other guy attached to A. 255 00:16:07,200 --> 00:16:09,648 这里的AP表 And the action procedure here also has to point to that, 256 00:16:11,120 --> 00:16:12,400 也指向这个与门 the list of action procedures. 257 00:16:13,070 --> 00:16:16,352 相类似的 这里的AP表 And of course, that means this one, its action procedures 258 00:16:16,784 --> 00:16:18,530 也要指向这里 has to point up to here. 259 00:16:18,530 --> 00:16:20,896 这里是C要通知的元件 This is the things-- the people it has to inform. 260 00:16:21,770 --> 00:16:23,184 D也一样 And this guy has some too. 261 00:16:24,280 --> 00:16:25,248 但是我不知道它要通知谁 But I don't know what they are 262 00:16:25,264 --> 00:16:26,650 因为我的图中没有画出来 because I didn't draw it in my diagram. 263 00:16:27,190 --> 00:16:28,368 可能是和D连接起来的其它元件 It's the things connected to D. 264 00:16:30,320 --> 00:16:32,624 同样的 Now, it's also the case 265 00:16:33,800 --> 00:16:36,960 当AND-ACTION过程被唤醒时 that when the and-action procedure is awakened, 266 00:16:37,020 --> 00:16:41,312 也就是说 之前你拜托某人将你唤醒 saying one of the people who know that you've told 267 00:16:41,450 --> 00:16:44,848 你拜托它们 当它们的信号发生改变时通知你 one of the people you've told to wake you up if their signal changes, 268 00:16:46,970 --> 00:16:48,816 你得去检查它的信号是什么 you have to go look and ask them what's their signal 269 00:16:49,328 --> 00:16:52,256 这样你就可以计算逻辑与 输出信号给下一个元件 so you can do the and, and produce a signal for this one. 270 00:16:57,090 --> 00:16:58,752 所里 这里就必须要有 So there has to be, for example, 271 00:16:58,848 --> 00:17:03,000 有信息说 A1是这个元件 information here saying A1, my A1 is this guy, 272 00:17:03,900 --> 00:17:06,480 A2就是这个元件 my A1 is this guy, and my A2 is this guy. 273 00:17:08,930 --> 00:17:09,984 不只是这样 And not only that, 274 00:17:11,790 --> 00:17:15,200 当我在计算逻辑与时 我还得告诉这个元件一些信息 when I do my and, I'm going to have to tell this guy something. 275 00:17:16,304 --> 00:17:21,056 还有一个输出 输出给这个元件 So I need an output-- being this guy. 276 00:17:25,800 --> 00:17:30,032 同样地 非门也有一个输入 And similarly, this guy's going to have a thing called the input 277 00:17:32,380 --> 00:17:34,928 当信号被唤醒并告知它信号被修改时 that he interrogates to find out 278 00:17:36,752 --> 00:17:38,640 非门会询问该信号 what the value of the signal on the input is, 279 00:17:38,640 --> 00:17:40,090 你的值是什么 when the signal wakes up and says, I've changed, 280 00:17:41,050 --> 00:17:43,472 信号通过像这样发消息 告知“信号已改变” and sends a message this way saying, I've changed. 281 00:17:43,520 --> 00:17:45,536 它就反过来查询这个新的信号值 This guy says, OK, what's your value now? 282 00:17:46,900 --> 00:17:50,128 取到值之后 它将会 When he gets that value, then he's going to have to say, 283 00:17:50,144 --> 00:17:55,860 计算输出 并改变这个信号的值 OK, output changes this guy, changes this guy. 284 00:18:00,600 --> 00:18:01,248 以此类推 And so on. 285 00:18:02,848 --> 00:18:04,560 因此我也必须有这么多的连接 And so I have to have at least that much connected-ness. 286 00:18:06,240 --> 00:18:09,232 现在我们回头观察一下 这个与门 Now, let's go back and look, for example, at the and-gate. 287 00:18:10,260 --> 00:18:12,096 回到这张幻灯片 Here we are back on this slide. 288 00:18:13,670 --> 00:18:15,040 这几个部分的内容 And we can see some of these parts. 289 00:18:16,040 --> 00:18:19,328 对每个与门 都有A1、A2两个输入 一个OUTPUT输出 For any particular and-gate, there is an A1, there is an A2, and the output. 290 00:18:21,030 --> 00:18:23,536 这些都是 And those are, those are 291 00:18:25,088 --> 00:18:28,160 在AND-GATE被调用时的环境中 an environment that was created at the--those produce a frame 292 00:18:28,416 --> 00:18:31,248 这些参数创建了一个框架 at the time and-gate was called, 293 00:18:33,310 --> 00:18:35,904 这个框架用来存放A1、A2和OUTPUT的值 A frame where A1, A2, and output are-- 294 00:18:36,672 --> 00:18:39,200 它们都要与电线相绑定 have as their values, they're bound to 295 00:18:39,600 --> 00:18:44,256 这些电线就是通过参数传进来的 the wires which, they are--which were passed in. 296 00:18:46,240 --> 00:18:47,312 在这个环境下 In that environment, 297 00:18:47,744 --> 00:18:49,856 我构建一个过程 I constructed a procedure 298 00:18:50,976 --> 00:18:53,680 就在这里 this one right there. 299 00:18:54,590 --> 00:18:57,312 在该环境下定义的AND-ACTION-PROCEDURE And-action-procedure was constructed in that environment. 300 00:18:58,352 --> 00:19:00,704 这个实际上是对一个LAMBDA表达式求值 That was the result of evaluating a lambda expression. 301 00:19:01,620 --> 00:19:05,488 它跟求值该LAMBDA表达式时的环境相绑定 So it hangs onto the frame where these were defined. 302 00:19:07,168 --> 00:19:09,344 找到它的局部环境 Local--part of its local state is that. 303 00:19:11,700 --> 00:19:13,472 因此AND-ACTION-PROCEDURE过程能够 The and-action-procedure, therefore, has 304 00:19:13,648 --> 00:19:16,940 存取这里看到的A1、A2和OUTPUT access to A1, A2, and output as we see here. 305 00:19:17,310 --> 00:19:19,645 A1、A2、OUTPUT A1, A2, and output. 306 00:19:22,360 --> 00:19:23,952 我们还没有深入探索“电线”的内部结构 Now, we haven't looked inside of a wire yet. 307 00:19:26,030 --> 00:19:26,992 那是仅剩的部分 That's all that remains. 308 00:19:29,030 --> 00:19:29,920 来看看“电线” Let's look at a wire. 309 00:19:33,520 --> 00:19:36,256 麻烦请开一下投影仪 Like the overhead, very good. 310 00:19:39,500 --> 00:19:42,560 “电线”是有那么一点复杂 Well, the wire, again, is a, is a somewhat complicated mess. 311 00:19:43,090 --> 00:19:44,640 哦 摁错了 Ooh, wrong one. 312 00:19:47,056 --> 00:19:48,752 是非常复杂 像这样 It's a big complicated mess, like that. 313 00:19:50,064 --> 00:19:53,104 但是还是来看一下 到底是什么 But let's look at it in detail and see what's going on. 314 00:19:54,720 --> 00:19:56,672 “电线”是这样的一种东西 Well, the wire is one of these. 315 00:19:57,760 --> 00:20:03,520 有两个主要部分 都是它的状态 And it has to have two things that are part of it, that it's state. 316 00:20:05,010 --> 00:20:07,390 我们这里看到的 一个是信号值 One of them is the signal we see here. 317 00:20:07,456 --> 00:20:10,064 这里 当我们调用MAKE-WIRE创建一条电线时 Heres, when we call make-wire to make a wire, 318 00:20:10,464 --> 00:20:13,024 我们首先要创建一些变量 then the first thing we do is we create some variables 319 00:20:14,944 --> 00:20:16,080 分别是这条电线的 which are the signal 320 00:20:17,104 --> 00:20:19,296 SIGNAL和ACTION-PROCS and the action procedures for this wire. 321 00:20:22,320 --> 00:20:23,440 在这个上下文中 And in that context, 322 00:20:23,760 --> 00:20:27,040 我们定义了一系列的过程 we define various functions--or procedures, excuse me, procedures. 323 00:20:27,840 --> 00:20:31,152 其中一个是(SET-MY-SIGNAL! NEW) One of them is called set-my-signal to a new value. 324 00:20:32,850 --> 00:20:37,424 它所做的只是 取一个新值NEW And what that does is takes a new value in. 325 00:20:37,930 --> 00:20:40,360 如果NEW和SIGNAL一样 信号没有变化 就没必要做什么了 If that's equal to my current value of my signal, I'm done. 326 00:20:40,360 --> 00:20:42,624 否则 把SIGNAL的值赋值为NEW Otherwise, I set the signal to the new value 327 00:20:42,752 --> 00:20:44,608 再调用ACTION-PROCS里的所有过程 and call each of the action procedures 328 00:20:46,528 --> 00:20:52,512 那些我之前引入的过程 that I've been, that I've been--what's the right word? -- introduced to. 329 00:20:54,630 --> 00:21:01,530 也就是我在定义与门时就定义的过程 I get introduced when the and-gate was applied to me. 330 00:21:04,130 --> 00:21:05,600 是在代码最后调用ADD-ACTION-PROCEDURE实现的 By add action procedure at the bottom. 331 00:21:07,410 --> 00:21:10,800 然后 我还得定义一个过程 用来接受动作 Also, I have to define a way of accepting an action procedure-- 332 00:21:10,816 --> 00:21:11,820 也就是这段代码 which is what you see here--- 333 00:21:12,800 --> 00:21:15,136 它增加了AP表 which increments my action procedures 334 00:21:15,568 --> 00:21:21,630 这是通过使用SET!将PROC与旧的AP表CONS起来实现的 using set to the result of CONSing up a new process--a procedure, 335 00:21:21,792 --> 00:21:24,256 而这个PROC是作为参数传递进来的 which is passed to me, on to my actions procedures list. 336 00:21:25,408 --> 00:21:27,584 由于技术原因 最后还要再运行一次PROC And for technical reasons, I have to call that procedure one. 337 00:21:27,780 --> 00:21:29,200 我不会再对此详细展开 So I'm not going to tell you anything about that, 338 00:21:29,392 --> 00:21:33,152 这是一种事件驱动的模拟 that has to do with event-driven simulations and getting them started, 339 00:21:34,592 --> 00:21:36,000 要想把这个讲清楚还是得花点时间 which takes a little bit of thinking. 340 00:21:36,950 --> 00:21:39,408 最后 我还要定义一个“分派器” And finally, I'm going to define a thing called the dispatcher, 341 00:21:39,968 --> 00:21:43,584 这是一种将消息分派给电线的方法 which is a way of passing a message to a wire, 342 00:21:45,376 --> 00:21:48,656 它将用于从中抽取出不同的信息 which is going to be used to extract from it various information, 343 00:21:49,072 --> 00:21:51,488 比如这里 当前的信号值是多少? like what is the current signal value? 344 00:21:53,820 --> 00:21:55,664 设置新信号值的方法是什么? What is the method of setting your signal? 345 00:21:57,180 --> 00:21:58,288 我想要这个方法 I want to get that out of it. 346 00:22:00,100 --> 00:22:02,600 我怎么样去添加另外的动作过程呢? How do I--how do I add another action procedure? 347 00:22:05,510 --> 00:22:09,360 最后 以DISPATCH过程为返回值返回 And I'm going to return that dispatch, that procedure as a value. 348 00:22:09,940 --> 00:22:11,872 因此 我所构造的电线 So the wire that I've constructed 349 00:22:12,000 --> 00:22:13,552 是一种可以接收消息的对象 is a message accepting object 350 00:22:14,256 --> 00:22:16,016 它接收的消息类似于 which accepts a message like, like 351 00:22:16,448 --> 00:22:18,368 “你的哪个方法可以用来添加动作过程?” what's your method of adding action procedures? 352 00:22:19,920 --> 00:22:21,008 它返回一个过程 That it'll give me a procedure, 353 00:22:21,640 --> 00:22:23,056 它返回ADD-ACTION-PROCUDURE which is the add action procedure, 354 00:22:23,072 --> 00:22:26,540 我可以将其应用在一个动作过程上 which I can then apply to an action procedure 355 00:22:27,056 --> 00:22:29,010 从而实现将一个动作过程加入电线的AP表中 to create another action procedure in the wire. 356 00:22:31,620 --> 00:22:32,820 这是一种“许可” So that's a permission. 357 00:22:33,200 --> 00:22:36,080 使得你可以去修改自身的AP表 So it's given me permission to change your action procedures. 358 00:22:37,824 --> 00:22:40,160 实际上 你可以在这里看到 And in fact, you can see that over here. 359 00:22:41,710 --> 00:22:42,320 下一张幻灯片 Next slide. 360 00:22:43,536 --> 00:22:43,824 噢 Ah. 361 00:22:47,760 --> 00:22:49,120 没什么有意思的 This is nothing very interesting. 362 00:22:49,120 --> 00:22:50,656 CALL-EACH调用每个动作过程 The call each of the action procedures 363 00:22:50,896 --> 00:22:52,576 这只是对一个表不断做CDR is just a CDRing down a list. 364 00:22:52,736 --> 00:22:54,608 没什么好说的 And I'm not going to even talk about that anymore. 365 00:22:54,990 --> 00:22:56,256 我们早就知道了 We're too advanced for that. 366 00:22:57,560 --> 00:23:00,672 然而 如果我想知道线路上的信号值 However, if I want to get a signal from a wire, 367 00:23:01,024 --> 00:23:02,544 我询问该线路:你的 -- I ask the wire-- which is, 368 00:23:02,544 --> 00:23:03,090 回想一下 什么是线路? what is the wire? 369 00:23:03,090 --> 00:23:05,408 线路对象只是在创建它时所返回的分派过程而已 The wire is the dispatch returned by creating the wire. 370 00:23:05,860 --> 00:23:06,480 只是一个过程 It's a procedure. 371 00:23:06,830 --> 00:23:12,272 我向该分派器发送一个消息'GET-SIGNAL I call that dispatch on the message get-signal. 372 00:23:12,912 --> 00:23:15,408 实际得到的是一个方法 用于取得线路信号值 And what I should expect to get is a method of getting a signal. 373 00:23:16,900 --> 00:23:17,968 进一步 我就可以得到信号值 Or actually, I get the signal. 374 00:23:19,220 --> 00:23:20,528 如果我想要设置一个信号值 If I want to set a signal, 375 00:23:22,656 --> 00:23:23,968 我想要改变一个信号值 I want to change a signal, 376 00:23:24,512 --> 00:23:26,768 我要做的是 then what I'm going to do 377 00:23:26,928 --> 00:23:29,696 以一个线路和信号的新值作为参数 is take a wire as an argument and a new value for the signal, 378 00:23:30,016 --> 00:23:32,432 我向线路请求许可 来设置它的信号值 I would ask the wire for permission to set the signal 379 00:23:32,848 --> 00:23:37,616 我会用该许可 -- 也就是一个过程 -- 应用在一个新值上 and use that permission, which is a procedure, on the new value. 380 00:23:38,700 --> 00:23:40,512 我们再过来看投影 And if we go back to the overhead here, 381 00:23:41,648 --> 00:23:43,248 好的 谢谢 Okay, thank you, 382 00:23:44,208 --> 00:23:45,632 我们看这里的投影 we go back to the overhead here, 383 00:23:45,920 --> 00:23:48,752 我们看到 如果我请求设置信号的方法 we see that the method-- if I ask for the method of setting the signal, 384 00:23:49,344 --> 00:23:50,448 也就是这段代码 that's over here, 385 00:23:52,256 --> 00:23:55,696 返回的是一个定义在线路内部的SET-MY-SIGNAL!方法 it's set-my-signal, a procedure that's defined inside the wire, 386 00:23:56,256 --> 00:23:57,696 回过头来看它的定义 which if we look over here 387 00:23:58,720 --> 00:23:59,744 它的定义是 is the thing that says 388 00:24:00,432 --> 00:24:02,688 将我的一个内部变量SIGNAL的值设为 set my internal value called the signal, 389 00:24:02,736 --> 00:24:05,504 这个内部变量 用于存储信号值 my internal variable, which is the signal, 390 00:24:07,616 --> 00:24:10,030 将其值设为通过参数传递的NEW to the new value, which is passed to me as an argument, 391 00:24:10,784 --> 00:24:13,010 然后调用AP表中的过程 来唤醒它们 and then call each of the action procedures waking them up. 392 00:24:16,340 --> 00:24:16,992 非常简单 Very simple. 393 00:24:19,248 --> 00:24:20,768 回头来看刚才的幻灯片 Ok, Going back to that slide, 394 00:24:22,480 --> 00:24:24,320 还有最后一点 we also have the one last thing-- 395 00:24:24,368 --> 00:24:27,310 我想你们现在应该很轻易地就能理解了 which I suppose now you can easily work out for yourself-- 396 00:24:27,776 --> 00:24:29,152 关于我们如何添加新的动作过程 is the way you add an action. 397 00:24:30,100 --> 00:24:35,184 我们需要WIRE和ACTION-PROC两个参数 You take a wire--a wire and an action procedure. 398 00:24:36,470 --> 00:24:39,312 然后请求添加动作过程的许可 And I ask the wire for permission to add an action. 399 00:24:40,050 --> 00:24:44,224 得到许可后 用该许可去添加新的动作过程 Getting that permission, I use that permission to give it an action procedure. 400 00:24:45,840 --> 00:24:47,088 所以 这确实是一个“对象” So that's a real object. 401 00:24:48,570 --> 00:24:50,320 还有些细节 There's a few more details about this. 402 00:24:52,460 --> 00:24:58,390 比如 我怎么来控制它? For example, how am I going to control this thing? 403 00:24:58,390 --> 00:24:59,696 这些延时怎么实现? How do I do these delays? 404 00:25:00,992 --> 00:25:02,540 我们来快速过一遍 Okay? Let's look at that for a second. 405 00:25:05,504 --> 00:25:07,984 下一张 The next one here. 406 00:25:08,360 --> 00:25:08,880 我们来看看 Let's see. 407 00:25:09,570 --> 00:25:14,176 我们细看与门、或门的定义 We know when we looked at the and-gate or the not-gate 408 00:25:15,312 --> 00:25:17,008 会发现当输入信号改变时 that when a signal changed on the input, 409 00:25:17,248 --> 00:25:18,192 会有“延时” there was a delay. 410 00:25:18,770 --> 00:25:21,248 然后它将调用过程 And then it was going to call the procedure, 411 00:25:21,632 --> 00:25:23,008 来改变输出 which was going to change the output. 412 00:25:26,040 --> 00:25:27,920 这个要如何实现? Well, how are we going to do this? 413 00:25:28,120 --> 00:25:29,920 我们将要建立一种机制 We're going to make up some mechanism, 414 00:25:30,304 --> 00:25:32,000 一种相当复杂的机制 a fairly complicated mechanism at that, 415 00:25:32,336 --> 00:25:33,760 我们得非常细心地来看 which we're going to have to be very careful about. 416 00:25:34,720 --> 00:25:37,232 一段延时之后 我们将执行一个动作 But after a delay, we're going to do an action. 417 00:25:37,390 --> 00:25:38,128 DELAY是一个数 A delay is a number, 418 00:25:38,160 --> 00:25:39,230 而ACTION是一个过程 and an action is a procedure. 419 00:25:40,590 --> 00:25:43,728 我们引入一种称为THE-AGENDA的特殊数据结构 What that's going to be is they're going to have a special structure called an agenda, 420 00:25:45,504 --> 00:25:48,800 用于组织时间与动作 which is a thing that organizes time and actions. 421 00:25:49,510 --> 00:25:50,880 一会儿再来仔细研究 And we're going to see that in a while. 422 00:25:50,880 --> 00:25:52,544 先把这里说完 I don't want to get into that right now. 423 00:25:53,070 --> 00:25:58,288 THE-AGENDA将记录执行动作的时刻 But the agenda has a moment at which--at which something happens. 424 00:25:59,130 --> 00:26:02,464 我们把它设定在未来的某个时刻 We're setting up for later at some moment, 425 00:26:02,510 --> 00:26:05,680 也就是在CURRENT-TIME加上DELAT的时刻 which is the sum of the time, which is the delay time plus the current time, 426 00:26:05,696 --> 00:26:07,130 触发关联的动作 which the agenda thinks is now. 427 00:26:09,024 --> 00:26:10,560 我们把准备好要执行的动作 We're going to set up to do this action, 428 00:26:11,024 --> 00:26:12,400 添加入THE-AGENDA中 and add that to the agenda. 429 00:26:15,280 --> 00:26:18,032 要使这个“机器”运行起来并不困难 And the way this machine will now run is very simple. 430 00:26:18,660 --> 00:26:21,488 我们利用这个PROPAGATE过程来完成这件事 We have a thing called propagate, which is the way things run. 431 00:26:22,710 --> 00:26:25,952 如果THE-AGENDA为空 就没有要做的 If the agenda is empty, we're done--if there's nothing more to be done. 432 00:26:27,440 --> 00:26:28,160 否则 Otherwise, 433 00:26:29,760 --> 00:26:31,536 我们就取出THE-AGENDA的第一个元素 we're going to take the first item off the agenda, 434 00:26:31,712 --> 00:26:33,340 它是一个无参过程 and that's a procedure of no arguments. 435 00:26:34,200 --> 00:26:36,030 所以这里有额外的括号 So that we're going to see extra parentheses here. 436 00:26:36,030 --> 00:26:37,856 我们对其进行无参调用 We call that on no arguments. 437 00:26:39,190 --> 00:26:40,176 这就执行了之前存入的动作 That takes the action. 438 00:26:42,200 --> 00:26:44,176 然后我们从THE-AGENDA中删除第一个元素 Then we remove that first item from the agenda, 439 00:26:44,592 --> 00:26:46,144 然后再进入传播循环 and we go around the propagation loop. 440 00:26:48,912 --> 00:26:50,750 这就是整体的结构 So that's the overall structure of this thing. 441 00:26:53,380 --> 00:26:55,936 还有点其它的 Now, there's a, a few other things we can look at. 442 00:26:57,430 --> 00:27:00,016 现在 我们来看看THE-AGENDA的内部结构 And then we're going to look into the agenda a little while from now. 443 00:27:00,576 --> 00:27:01,552 请看投影仪 Now the overhead again. 444 00:27:02,800 --> 00:27:04,672 该如何使用这个玩意儿呢? Well, in order to set this thing going, 445 00:27:04,672 --> 00:27:07,410 我需要给你们说明下这个模拟器的用法 I just want to show you some behavior out of this simulator. 446 00:27:07,856 --> 00:27:09,936 你们可能觉得这个模拟器太简陋了 By the way, you may think this simulator is very simple, 447 00:27:10,400 --> 00:27:12,016 甚至你们认为它根本没什么用 and probably too simple to be useful. 448 00:27:12,576 --> 00:27:13,760 而实际上是 The fact of the matter is 449 00:27:13,984 --> 00:27:15,392 这样的模拟器曾被用于 that this simulator has been used 450 00:27:15,728 --> 00:27:17,440 操纵相当大型的计算机 to manufacture a fairly large computer. 451 00:27:18,680 --> 00:27:20,640 那是一个真实的事例 So this is a real live example. 452 00:27:22,360 --> 00:27:24,064 当然 并不完全是这里的这个模拟器 Actually, not exactly this simulator, 453 00:27:24,064 --> 00:27:25,392 我会告诉你它们的区别 because I'll tell you the difference. 454 00:27:25,840 --> 00:27:28,704 区别就是 操纵大型机的模拟器有更多的基本元素 The difference is that there were many more different kinds of primitives. 455 00:27:29,820 --> 00:27:32,224 不只是有非门 与门之类的 There's not just the word inverter or and-gate. 456 00:27:33,200 --> 00:27:35,728 还有边缘触发器 There were things like edge-triggered, 457 00:27:36,256 --> 00:27:39,888 翻转触发器 锁存器 flip-flops, and latches 458 00:27:40,704 --> 00:27:44,520 电平触发器 加法器等等之类的 transparent latches, and adders, and things like that. 459 00:27:45,170 --> 00:27:47,312 困难之处在于 And the difficulty with that 460 00:27:47,456 --> 00:27:50,864 就在于需要很多页的文档 is there's pages and pages of the definitions of all these primitives 461 00:27:51,200 --> 00:27:52,896 来描述这些基本元素 with numbers like LS04. 462 00:27:54,690 --> 00:27:56,740 同时它们还有很多的参数 And then there's many more parameters for them. 463 00:27:56,740 --> 00:27:57,984 不是只有一个延时这么简单 It's not just one delay. 464 00:27:58,480 --> 00:28:00,816 还有建立时间 维持时间之类的 There's things like set up times and hold times and all that. 465 00:28:01,220 --> 00:28:03,408 但是 如果不算上那部分的复杂度 But with the exception of that part of the complexity, 466 00:28:03,820 --> 00:28:08,208 我们用来构建真实计算机的模拟器的结构 the structure of the simulator that we use for building a real computer, 467 00:28:09,088 --> 00:28:12,896 跟你们在这里看到的的是一致的 that works is exactly what you're seeing here. 468 00:28:15,110 --> 00:28:19,270 无论如何 这里都是一些简单的东西 Well in any case, what we have here is a few simple things. 469 00:28:19,270 --> 00:28:22,592 像这个 设置非门的延时时间 构建一个 AGENDA Like, there's inverter delays being set up and making a new agenda. 470 00:28:23,030 --> 00:28:25,520 我们可以构建一些输入(线路) And then we can make some inputs. 471 00:28:26,032 --> 00:28:29,184 这里的四条线路分别是:INPUT-1、INPUT-2、SUM和CARRY Ok? There's input-1, input-2, a sum and a carry, which are wires. 472 00:28:29,460 --> 00:28:31,888 我将要放置一种被称为“探针”的特殊对象 I'm going to put a special kind of object called a probe 473 00:28:32,512 --> 00:28:34,640 放在一些线路上 onto, onto some of the wires, 474 00:28:34,976 --> 00:28:36,240 放在SUM和CARRY上 onto sum and onto carry. 475 00:28:37,230 --> 00:28:40,560 探针是一种对象 它可以 -- A probe is a, can object that has the property 476 00:28:40,704 --> 00:28:43,600 当你改变它所附着线路的信号时 that when you change a wire it's attached to, 477 00:28:43,728 --> 00:28:44,832 它会输出一条消息 it types out a message. 478 00:28:46,120 --> 00:28:46,928 这很容易实现 It's an easy thing to do. 479 00:28:48,448 --> 00:28:49,520 一旦我们设置好它们 And then once we have that, 480 00:28:49,552 --> 00:28:51,456 当你在放置探针的时候 of course, then when you put the probe on, 481 00:28:51,450 --> 00:28:52,416 它首先会输出 the first thing it does, it says, 482 00:28:52,672 --> 00:28:56,016 SUM在0时刻的值为0 the current value of the sum at time 0 is 0 483 00:28:57,296 --> 00:28:58,432 这个我已经注意到了 And because I just noticed it. 484 00:28:59,400 --> 00:29:04,752 CARRY在0时刻的值也是0 And the value of the carry at time 0, this is the time, is 0. 485 00:29:06,048 --> 00:29:09,280 我们继续来构建更多结构 And then we go off and we build some structure. 486 00:29:09,620 --> 00:29:12,288 比如 可以像这里一样构建一种结构 Like, we can build a structure here that says 487 00:29:14,064 --> 00:29:18,208 用INPUT-1、INPUT-2、SUM和CARRY组成一个半加器 you have a half-adder on input-1, input-2, sum, and carry. 488 00:29:18,420 --> 00:29:20,420 然后我们把INPUT-1上的信号变为1 And we're going to set the signal on input-1 to 1. 489 00:29:20,624 --> 00:29:21,728 然后开始传播 We do some propagation. 490 00:29:21,880 --> 00:29:22,848 在时刻8的时候 At time 8, 491 00:29:23,904 --> 00:29:26,128 如果你想的话 也可以单步跟踪传播过程 which you could see going through this thing if you wanted to, 492 00:29:26,528 --> 00:29:29,200 SUM的值变为1 the new value of sum became 1. 493 00:29:29,520 --> 00:29:30,448 然后就结束了 And the thing says I'm done. 494 00:29:31,168 --> 00:29:32,256 好像没什么意思 That wasn't very interesting. 495 00:29:32,630 --> 00:29:33,904 我们还可以设置信号 But we can send it some more signals. 496 00:29:34,064 --> 00:29:36,736 把INPUT-2也变为1 Like, we set-signal on input-2 to be one. 497 00:29:36,890 --> 00:29:38,096 如果再进行传播 And at that time if we propagate, 498 00:29:38,368 --> 00:29:39,952 在时刻11 then it carried at 11, 499 00:29:40,128 --> 00:29:41,424 CARRY变为1 the carry becomes 1, 500 00:29:41,552 --> 00:29:44,192 在时刻16 SUM变为0 and at 16, the sum's new value becomes 0. 501 00:29:45,392 --> 00:29:48,990 如果你仔细研究那个电路图 And you might want to work out that, if you like, about the digital circuitry. 502 00:29:48,990 --> 00:29:50,128 它确实是这个结果 It's true, and it works. 503 00:29:50,620 --> 00:29:51,535 也并没有什么特别的 And it's not very interesting. 504 00:29:51,530 --> 00:29:54,128 但是却清楚地表明了这一些都是如何运作的 But that's the kind of behavior we get out of this thing. 505 00:30:01,830 --> 00:30:03,296 我现在给你们展示的是 So what I've shown you right now 506 00:30:03,488 --> 00:30:05,520 一种宏观的图景 is a large-scale picture, 507 00:30:06,600 --> 00:30:08,560 你如何在一个很大的规模中 how you, at a bigger, big scale, 508 00:30:08,720 --> 00:30:12,040 你何去实现某种事件驱动的模拟 you implement an event-driven simulation of some sort. 509 00:30:13,296 --> 00:30:14,560 你应该如何去组织 And how you might organize it 510 00:30:14,880 --> 00:30:16,704 来获得良好的层次性结构 to have nice hierarchical structure 511 00:30:16,992 --> 00:30:21,008 使得你可以构建可具体化的抽象盒子 allowing you to build abstract boxes that you can instantiate. 512 00:30:21,568 --> 00:30:24,960 但我还没有告诉你AGENDA是如何运作的 But I haven't told you any of the details about how this agenda and things like that work. 513 00:30:25,780 --> 00:30:26,544 下一小节再说 That we'll do next. 514 00:30:28,630 --> 00:30:32,944 这将涉及到一些关于数据变化之类的事情 And that's going to involve change and mutation of data and things like that. 515 00:30:34,310 --> 00:30:35,860 在我继续之前 有什么问题吗? Are there any questions now, before I go on? 516 00:30:47,160 --> 00:30:48,240 没有的话 那就休息一下 Thank you. Let's take a break. 517 00:30:50,240 --> 00:31:00,624 [音乐] [JESU, JOY OF MAN'S DESIRING] 518 00:31:00,620 --> 00:31:06,000 《计算机程序的构造和解释》 519 00:31:11,230 --> 00:31:17,696 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 520 00:31:17,760 --> 00:31:21,344 《计算机程序的构造和解释》 521 00:31:21,340 --> 00:31:25,184 计算对象 522 00:31:28,940 --> 00:31:35,060 我们已经做了一个模拟器 Well, we've been making a simulation. 523 00:31:35,392 --> 00:31:37,776 这是一种事件驱动的模拟 And the simulation is an event-driven simulation 524 00:31:38,176 --> 00:31:42,752 其中 计算机中的对象与现实中的对象一一对应 where the objects in the world are the objects in the computer. 525 00:31:43,920 --> 00:31:47,280 现实世界中按时发生的状态改变 And the changes of state that are happening in the world in time 526 00:31:47,984 --> 00:31:50,832 被组织成了计算机中的时间 are organized to be time in the computer, 527 00:31:52,992 --> 00:31:56,048 如果现实中某件事后于另一件事发生 so that if something happens after something else in the world, 528 00:31:56,460 --> 00:31:57,968 那么在计算机中 then we have it happen after, 529 00:31:58,896 --> 00:32:02,256 两个事件也保持同样的先后顺序发生 after the corresponding events happen in the same order in the computer. 530 00:32:04,420 --> 00:32:07,168 排列这些时间 就是我们要用到赋值的地方 That's where we have assignments, when we make that alignment. 531 00:32:08,220 --> 00:32:11,216 现在我要介绍一种方法来组织时间 Right now I want to show you a way of organizing time, 532 00:32:11,808 --> 00:32:14,864 AGENDA -- 或者有时候所谓的“优先队列” which is an agenda or priority queue, it's sometimes called. 533 00:32:16,040 --> 00:32:18,576 我们首先需要认识到 We'll do some--we'll do a little bit of just understanding 534 00:32:18,624 --> 00:32:21,008 为了创建AGENDA 我们需要些什么东西? what are the things we need to be able to do to make agendas. 535 00:32:28,330 --> 00:32:31,280 首先我要在这里写下一些 And so we're going to have--and so right now over here, I'm going to write down a bunch 536 00:32:31,392 --> 00:32:33,888 用于操作AGENDA的基本运算 of primitive operations for manipulating agendas. 537 00:32:35,960 --> 00:32:37,952 我不会给出具体代码 I'm not going to show you the code for them 538 00:32:38,144 --> 00:32:39,584 因为它们都非常简单 because they're all very simple, 539 00:32:40,320 --> 00:32:42,608 而且你们手上也有 Iand you've got listings of all that anyway. 540 00:32:43,680 --> 00:32:44,380 有哪些运算呢? So what do we have? 541 00:32:44,380 --> 00:32:53,504 MAKE-AGENDA可以新建一个AGENDA We have things like make-agenda which produces a new agenda. 542 00:32:57,360 --> 00:33:01,770 CURRENT-TIME可以获得一个AGENDA的当前时间 We can ask--we get the current-time of an agenda, 543 00:33:07,472 --> 00:33:12,800 返回一个数 -- 也就是当前时间 of an agenda, which gives me a number, a time. 544 00:33:16,990 --> 00:33:21,376 EMPTY-AGENDA?可用于判断一个AGENDA是否为空 We can get--we can ask whether an agenda is empty, empty-agenda. 545 00:33:30,200 --> 00:33:32,570 返回TRUE或FALSE And that produces either a true or a false. 546 00:33:42,720 --> 00:33:44,720 我们也可以向AGENDA中添加对象 We can add an object to an agenda. 547 00:33:52,710 --> 00:33:56,064 实际上 向AGENDA中添加的是一个运算 -- 或者说是需要完成的操作 Actually, what we add to an agenda is an operation--an action to be done. 548 00:33:56,910 --> 00:33:58,144 它需要时间TIME And that takes a time, 549 00:33:59,632 --> 00:34:00,560 待添加的动作ACTION the action itself, 550 00:34:02,864 --> 00:34:04,640 以及AGENDA本身 and the agenda I want to add it to. 551 00:34:07,584 --> 00:34:10,256 它把ACTION 放入AGENDA中合适的地方 OK? That inserts it in the appropriate place in the agenda. 552 00:34:10,710 --> 00:34:12,736 FIRST-ITEM用于从AGENDA取出第一个事项 I can get the first item off an agenda, 553 00:34:14,240 --> 00:34:15,392 那是我首先需要做的事情 the first thing I have to do, 554 00:34:21,840 --> 00:34:23,840 该事项是一个动作 which is going to give me an action. 555 00:34:26,464 --> 00:34:28,736 我还可以把第一个事项从AGENDA中移除 And I can remove the first item from an agenda. 556 00:34:29,540 --> 00:34:31,168 这是操作AGENDA的一个必要运算 That's what I have to be able to do with agendas. 557 00:34:31,409 --> 00:34:33,020 这个运算实现起来非常繁杂 That is a big complicated mess. 558 00:34:42,530 --> 00:34:43,360 从AGENDA中移除 From an agenda. 559 00:34:45,984 --> 00:34:49,856 现在我们来看如何具体组织数据结构 Well, let's see how we can organize this thing as a data structure a bit. 560 00:34:52,960 --> 00:34:56,048 AGENDA应该是一种表 Well, an agenda is going to be some kind of list. 561 00:34:58,432 --> 00:35:01,200 一种可修改的表 And it's going to be a list that I'm going to have to be able to modify. 562 00:35:01,570 --> 00:35:04,032 因为我们要向其中添加元素 So we have to talk about modifying of lists, 563 00:35:05,808 --> 00:35:06,896 删除元素等等 because I'm going to add things to it, 564 00:35:07,776 --> 00:35:10,272 所以我们需要一种可修改的表 and delete things from it, and things like that. 565 00:35:11,070 --> 00:35:12,512 它通过时间组织起来 It's organized by time. 566 00:35:13,820 --> 00:35:15,570 让它有序 也许会有益处 It's probably good to keep it in sorted order. 567 00:35:18,330 --> 00:35:20,880 但是也有可能同一时间会发生很多事 But sometimes there are lots of things that happen at the same time 568 00:35:22,048 --> 00:35:23,420 或者说几乎同时 approximate same time. 569 00:35:23,800 --> 00:35:24,720 因此我们需要 What I have to do is say, 570 00:35:24,912 --> 00:35:27,520 把它们按发生时间为事件分组 group things by the time at which they're supposed to happen. 571 00:35:29,040 --> 00:35:31,616 所以我要把AGENDA组织成由SEGMENT构成的表 So I'm going to make an agenda as a list of segments. 572 00:35:32,780 --> 00:35:35,696 我来画一下这个结构 And so I'm going to draw you a data structure for an agenda, 573 00:35:36,688 --> 00:35:37,936 方便理解 a perfectly reasonable one. 574 00:35:39,620 --> 00:35:40,496 这是一个AGENDA Here's an agenda. 575 00:35:41,110 --> 00:35:42,870 以一个名字开始 It's a thing that begins with a name. 576 00:35:47,856 --> 00:35:50,192 我把它画在表结构的外部 I'm going to do it right now out of list structure. 577 00:35:52,608 --> 00:35:53,392 这是它的头部 It's got a header. 578 00:35:54,144 --> 00:35:55,440 这个头部的存在也是很必要的 There's a reason for the header. 579 00:35:55,840 --> 00:35:57,630 待会你就会知道 We're going to see the reason soon. 580 00:36:00,680 --> 00:36:03,408 再画一个SEGMENT And it will have a segment. We will have-- 581 00:36:03,968 --> 00:36:05,620 这是一个由SEGMENT构成的表 It will have--it will be a list of segments. 582 00:36:08,310 --> 00:36:10,544 假设这个AGENDA有两个SEGMENT Supposing this agenda has two segments, 583 00:36:11,584 --> 00:36:15,072 不断对这个表取CAR即可得到 OK, they're the car's-- successive car's of this list. 584 00:36:16,416 --> 00:36:20,576 每个SEGMENT都有一个时间 Each segment is going to have a time-- 585 00:36:24,208 --> 00:36:26,640 比如说这里是10 say for example, 10-- 586 00:36:26,832 --> 00:36:30,512 也就是说 这个SEGMENT里的事件发生在10时刻 that says that the things that happen in this segment are at time 10. 587 00:36:33,160 --> 00:36:36,528 这里是另外一种数据结构 And what I'm going to have in here is another data structure 588 00:36:36,560 --> 00:36:38,010 我先不具体描述 which I'm not going to describe, 589 00:36:38,496 --> 00:36:41,088 它是一个队列 表示在10时刻要做的事 which is a queue of things to do at time 10. 590 00:36:42,240 --> 00:36:43,330 它是一个队列 It's a queue. 591 00:36:43,330 --> 00:36:44,704 一会儿再细说 And we'll talk about that in a second. 592 00:36:45,200 --> 00:36:50,352 不过抽象地看 队列就是一系列在固定时间要做的事 But abstractly, the queue is just a list of things to do at a particular time. 593 00:36:50,400 --> 00:36:52,048 我可以向其中添加其它要做的事 And I can add things to a queue. 594 00:36:53,100 --> 00:36:53,808 这是一个队列 This is a queue. 595 00:36:56,140 --> 00:36:59,115 这个是时间 这个是SEGMENT There's a time, there's a segment. 596 00:37:03,232 --> 00:37:06,368 在这个AGENDA中 还有另一个SEGMENT Now, I may have another segment in this agenda. 597 00:37:08,940 --> 00:37:11,200 假设它在30时刻发生 Supposing this is stuff that happens at time 30. 598 00:37:13,500 --> 00:37:15,920 类似地 它也有一个队列 It has, of course, another queue 599 00:37:16,928 --> 00:37:20,240 里面是在30时刻要去做的事 of things that are queued up to be done at time 30. 600 00:37:23,210 --> 00:37:25,664 当然 我们的AGENDA还需要支持其它操作 Well, there are various things I have to be able to do to an agenda. 601 00:37:27,090 --> 00:37:29,200 假设我想将一个在10时刻发生的事 Supposing I want to add to an agenda 602 00:37:29,472 --> 00:37:31,616 添加到AGENDA中 another thing to be done at time 10. 603 00:37:33,030 --> 00:37:34,160 这并不难 Well, that's not very hard. 604 00:37:34,700 --> 00:37:38,656 我遍历到这里 找到时刻是10的SEGMENT I'm going to walk down here, looking for the segment of time 10. 605 00:37:39,730 --> 00:37:42,144 这样的SEGMENT也可能不存在 It is possible that there is no segment of time 10. 606 00:37:42,930 --> 00:37:44,560 一会儿再考虑这种情况 We'll cover that case in a second. 607 00:37:45,420 --> 00:37:47,568 如果我找到了时刻为10的SEGMENT But if I find a segment of time 10, 608 00:37:47,872 --> 00:37:50,432 如果我想要把一个事情放入其中 then if I want to add another thing to be done at time 10, 609 00:37:50,560 --> 00:37:52,160 我只要增加该队列即可 I just increase that queue-- 610 00:37:53,856 --> 00:37:56,224 这个说起来倒是很容易 "just increase" isn't such an obvious idea. 611 00:37:56,576 --> 00:37:59,264 我在这里添加需要在那时做的事 But I increase the things to be done at that time. 612 00:38:01,430 --> 00:38:04,256 现在 假设我想在时刻20做点什么 Now, supposing I want to add something to be done at time 20. 613 00:38:05,312 --> 00:38:07,904 然而并没有时刻是20的SEGMENT There is no segment for time 20. 614 00:38:08,992 --> 00:38:10,640 我不得不构造一个新的SEGMENT I'm going to have to create a new segment. 615 00:38:11,340 --> 00:38:15,648 我想把这个SEGMENT 放在10与30之间 I want my time 20 segment to exist between time 10 and time 30. 616 00:38:17,610 --> 00:38:19,328 这着实要花点功夫 Well, that takes a little work. 617 00:38:20,170 --> 00:38:21,525 先用CONS I'm going to have to do a CONS. 618 00:38:24,260 --> 00:38:29,940 我要为这个AGENDA构建一个新的SEGMENT I'm going to have to make a new element of the agenda list--list of segments. 619 00:38:33,600 --> 00:38:34,816 这里的连接必须要变 I'm going to have to change. 620 00:38:35,400 --> 00:38:36,304 就像这样 Here's change. 621 00:38:37,540 --> 00:38:42,800 我将要修改AGENDA的CDR部分的CDR部分 I'm going to have to change the CDR of the CDR of the agenda 622 00:38:44,880 --> 00:38:49,456 让它指向一个新的CONS单元 point that a new CONS of the new segment 623 00:38:50,112 --> 00:38:54,656 由一个新的SEGMENT和AGENDA的CDDDDR部分所构成的单元 and the CDR of the CDR of the CDR of the agenda, the CD-D-D-DR. 624 00:38:57,180 --> 00:39:01,888 我们有一个发生在20时刻的新的SEGMENT And this is going to have a new segment now of time 20 625 00:39:02,304 --> 00:39:03,728 它自己维护了一个队列 with its own queue, 626 00:39:04,848 --> 00:39:06,290 这个队列中只有一个元素 which now has one element in it. 627 00:39:10,730 --> 00:39:12,528 如果我想在后面添加点什么 If I wanted to add something at the end, 628 00:39:12,544 --> 00:39:15,870 我就需要替换这个东西的CDR部分 I'm going to have to replace the CDR of this, 629 00:39:16,992 --> 00:39:19,216 替换掉这个表的CDR部分 of this list with something. 630 00:39:20,592 --> 00:39:23,312 我们就对该数据结构进行修改 We're have to change that piece of data structure. 631 00:39:24,040 --> 00:39:25,792 因此我需要新的基本运算 So I'm going to need new primitives for doing this. 632 00:39:27,210 --> 00:39:28,624 因为原有的基础运算达不到这一点 But I'm just showing you why I need them. 633 00:39:29,440 --> 00:39:33,888 如果我想在5时刻做点什么事 And finally, if I wanted to add a thing to be done at time 5, 634 00:39:37,120 --> 00:39:39,200 我就得去修改这个东西 I'm going to have to change this one, 635 00:39:40,816 --> 00:39:42,128 因为我得添加到这里 because I'm going to have to add it in over here, 636 00:39:43,290 --> 00:39:46,224 这也就是我预留了一个“头”序对的原因 which is why I planned ahead and had a header cell, 637 00:39:47,568 --> 00:39:48,592 它预留了空间 which has a place. 638 00:39:49,400 --> 00:39:52,112 我需要有空间去做改变 If I'm going to change things, I have to have places for the change. 639 00:39:53,888 --> 00:39:56,560 需要有存储空间 去改变 I have to have a place to make the change. 640 00:39:58,600 --> 00:40:02,540 从AGENDA中删除东西并不困难 If I remove things from the agenda, that's not so hard. 641 00:40:02,540 --> 00:40:04,624 移除第一个元素相当容易 Removing them from the beginning is pretty easy, 642 00:40:04,928 --> 00:40:06,144 这也是我需要考虑的唯一情况 which is the only case I have. 643 00:40:06,496 --> 00:40:10,192 我可以先找到第一个SEGMENT I can go looking for the first, the first segment. 644 00:40:11,220 --> 00:40:14,000 先判断它的队列是否为空 I see if it has a non-empty queue. 645 00:40:14,810 --> 00:40:16,176 如果队列不是空的 If it has a non-empty queue, 646 00:40:16,320 --> 00:40:18,624 那么 我就会把元素从中删除 well, I'm going to delete one element from the queue 647 00:40:19,216 --> 00:40:19,744 像这样 like that. 648 00:40:20,100 --> 00:40:21,920 如果这时队列变为空的 If the queue ever becomes empty, 649 00:40:22,640 --> 00:40:24,220 就还要继续把SEGMENT删掉 then I have to delete the whole segment. 650 00:40:24,220 --> 00:40:26,496 然后 让这个单元指向这里 And then this, this changes to point to here. 651 00:40:28,220 --> 00:40:31,088 这个数据结构操作起来很复杂 So it's quite a complicated data structure manipulation going on, 652 00:40:32,256 --> 00:40:35,376 它的具体实现也不是很有趣 the details of which are not really very exciting. 653 00:40:36,440 --> 00:40:38,480 现在我们来探讨一下队列 Now, let's talk about queues. 654 00:40:38,920 --> 00:40:39,760 它们很相似 They're similar. 655 00:40:41,160 --> 00:40:43,520 每一个AGENDA都有一个队列 Because each of these agendas has a queue in it. 656 00:40:44,340 --> 00:40:45,024 队列是什么? What's a queue? 657 00:40:49,472 --> 00:40:51,856 队列能够进行下述基本运算: A queue is going to have the following primitive operations. 658 00:40:52,784 --> 00:41:02,170 MAKE-QUEUE构建一个新队列 To make a queue, this gives me a new queue. 659 00:41:07,776 --> 00:41:17,104 INSERT-QUEUE!向队列中插入新元素 I'm going to have to be able to insert into a queue a new item. 660 00:41:24,510 --> 00:41:28,656 DELETE-QUEUE!从队列中删除元素 I'm going to have to be able to delete from a queue the first item in the queue. 661 00:41:40,448 --> 00:41:52,048 FRONT-QUEUE查看队列中第一个元素 And I want to be able to get the first thing in the queue from some queue. 662 00:41:53,136 --> 00:41:55,140 还需要检测队列是否为空 I also have to be able to test whether a queue is empty. 663 00:42:07,110 --> 00:42:08,704 当你定义像这样的运算时 And when you invent things like this, 664 00:42:09,024 --> 00:42:10,448 我希望你能够注意 I want you to be very careful 665 00:42:10,640 --> 00:42:14,090 按照我这样的习惯去为它们命名 to use the kinds of conventions I use for naming things. 666 00:42:15,120 --> 00:42:19,152 “!”表示操作具有副作用 “?”代表定义谓词 Notice that I'm careful to say these change something and that tests it. 667 00:42:19,870 --> 00:42:21,856 就比如说 这里应该加上一个“!” And presumably, I did the same thing over here. 668 00:42:24,656 --> 00:42:26,960 嗯 空检测谓词的“?”也不要遗漏了 OK, and there should be an empty test over here. 669 00:42:29,240 --> 00:42:30,720 那么 我要如何构建一个队列呢? OK, well, how would I make a queue? 670 00:42:31,720 --> 00:42:34,112 队列是一种 可以向其尾部添加东西 A queue wants to be something I can add to at the end of, 671 00:42:35,120 --> 00:42:36,830 也可以从前面取出东西的结构 and pick up the thing at the beginning of. 672 00:42:37,840 --> 00:42:40,512 我可以从队列头删除元素 向队列尾添加元素 I should be able to delete from the beginning and add to the end. 673 00:42:41,230 --> 00:42:43,248 我可以用一种很简单的结构来实现 Well, I'm going to show you a very simple structure for that. 674 00:42:43,888 --> 00:42:45,728 我们当然可以使用CONS来构造 We can make this out of CONSes as well. 675 00:42:47,080 --> 00:42:47,792 这是一个队列 Here's a queue. 676 00:42:49,910 --> 00:42:52,368 它有一个队列头 It has--it has a queue header, 677 00:42:53,584 --> 00:42:54,928 它包含两个部分 which contains two parts-- 678 00:42:55,280 --> 00:42:56,256 其中一个是头指针 a front pointer 679 00:42:58,784 --> 00:42:59,824 另一个是尾指针 and a rear pointer. 680 00:43:03,120 --> 00:43:06,336 假设我有一个包含两个元素的队列 And here I have a queue with two items in it. 681 00:43:09,136 --> 00:43:12,090 假设第一个元素是1 The first item, I don't know, it's perhaps a 1. 682 00:43:12,464 --> 00:43:16,530 而第二个元素假定是2 And the second item, I don't know, let's give it a 2. 683 00:43:21,408 --> 00:43:23,520 我之所以要在这里设置两个指针 The reason why I want two pointers in here, 684 00:43:24,096 --> 00:43:25,616 一个头指针和一个尾指针 a front pointer and a rear pointer, 685 00:43:25,720 --> 00:43:27,104 这样 当向尾部添加元素的时候 is so I can add to the end 686 00:43:27,488 --> 00:43:29,450 就不用从最开始开始遍历 without having to chase down from the beginning. 687 00:43:31,850 --> 00:43:34,800 例如 我想要向队列添加入一个新元素 So for example, if I wanted to add one more item to this queue, 688 00:43:35,260 --> 00:43:41,024 如果想添加一个稍后使用的元素 if I want to add on another item to be worried about later, 689 00:43:41,088 --> 00:43:42,400 只需要先用CONS构建一个序对 all I have to do is make a CONS, 690 00:43:43,472 --> 00:43:46,592 假设它包含一个值 -- 3 which contains that item, say a 3. 691 00:43:47,530 --> 00:43:51,340 再添加到队列里 That's for inserting 3 into the queue. 692 00:43:51,520 --> 00:43:53,776 这里就需要把这个元素CDR部分的指针 Then I have to change this pointer here 693 00:43:56,944 --> 00:43:58,760 指向这个元素 Okay? to here. 694 00:44:00,100 --> 00:44:04,320 同时也更新尾指针 让它指向新的地方 And I have to change this one to point to the new rear. 695 00:44:09,120 --> 00:44:12,688 如果我想查看队列的第一个元素 If I wish to take the first element of the queue, the first item, 696 00:44:12,960 --> 00:44:17,120 我只需要通过头指针去寻找 即可轻松找到 I just go chasing down the front pointer until I find the first one and pick it up. 697 00:44:18,890 --> 00:44:23,264 如果我想调用DELETE-QUEUE删除元素 If I wish to delete the first item from the queue, delete-queue, 698 00:44:24,144 --> 00:44:26,352 只需要把头指针向后移到就行 all I do is move the front pointer along this way. 699 00:44:27,712 --> 00:44:29,312 新的头指针指向这里 The new front of the queue is now this. 700 00:44:31,700 --> 00:44:33,136 就是这么简单 So queues are very simple too. 701 00:44:34,480 --> 00:44:35,760 为了实现这些操作 So what you see now 702 00:44:37,248 --> 00:44:40,832 我们还需要一些新的基本运算 is that I need a certain number of new primitive operations. 703 00:44:41,488 --> 00:44:42,560 我先列出它们的名字 And I'm going to give them some names. 704 00:44:42,992 --> 00:44:46,288 然后我们再来看 它们的原理和使用方法 And then we're going to look into how they work, and how they're used. 705 00:44:47,350 --> 00:44:55,040 SET-CAR!能够为序对的CAR部分 We have set the CAR of some pair, 706 00:44:55,888 --> 00:44:59,360 赋予一个新的值 or a thing produced by CONSing, to a new value. 707 00:45:02,370 --> 00:45:09,920 SET-CDR!可以为序对的CDR部分赋新值 And set the CDR of a pair to a new value. 708 00:45:13,024 --> 00:45:14,784 现在来看看它们到底做了什么 And then we're going to look into how they work. 709 00:45:16,030 --> 00:45:20,512 为了删除队列中的第一个元素 我需要修改这里的CAR部分 I needed setting CAR over here to delete the first element of the queue. 710 00:45:20,960 --> 00:45:22,528 这是CAR部分 我需要修改它的值 This is the CAR, and I had to set it. 711 00:45:23,470 --> 00:45:24,960 我需要能够修改CDR部分 I had to be able to set the CDR 712 00:45:25,280 --> 00:45:27,088 以便我能够移动尾指针 to be able to move the rear pointer, 713 00:45:27,216 --> 00:45:28,760 也使得我能够扩充队列 or to be able to increment the queue here. 714 00:45:30,160 --> 00:45:31,600 之前介绍的所有运算 All of the operations I did 715 00:45:31,904 --> 00:45:35,904 上一块黑板上的所有东西 都是基于这些运算的 were made out of those that I just showed you on the, on the last blackboard. 716 00:45:38,176 --> 00:45:40,140 先讲到这里 大家休息一下 Good. Let's pause the time, and take a little break then. 717 00:45:41,240 --> 00:45:52,672 [音乐] [JESU, JOY OF MAN'S DESIRING] 718 00:45:52,670 --> 00:45:57,840 《计算机程序的构造和解释》 719 00:46:18,640 --> 00:46:22,800 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 720 00:46:22,800 --> 00:46:27,152 《计算机程序的构造和解释》 721 00:46:27,168 --> 00:46:30,768 计算对象 722 00:46:38,816 --> 00:46:43,536 最初 我们说序对是通过CONS构造而来的 When we originally introduced pairs made out of CONS, made by CONS, 723 00:46:44,576 --> 00:46:46,800 我们提到了几条公理 we only said a few axioms about them, 724 00:46:48,096 --> 00:46:50,768 它们是怎样的呢? 它们是形如 -- which were of the form-- what were they-- 725 00:46:52,280 --> 00:47:03,648 对于任意的X和Y (CAR (CONS X Y)) = X for all X and Y, the CAR of the CONS of X and Y is X 726 00:47:05,312 --> 00:47:12,928 以及 (CDR (CONS X Y)) = Y and Y is X and the CDR of the CONS of X and Y is Y. 727 00:47:14,800 --> 00:47:20,000 但是 它们并没有陈述CONS单元 是否有像人一样的“身份” Now, these say nothing about whether a CONS has an identity like a person. 728 00:47:21,850 --> 00:47:25,584 实际上 它描述的是一种抽象 In fact, all they say is something sort of abstract, 729 00:47:25,744 --> 00:47:27,952 也就是CONS是由几个部分组成 that a CONS is the parts it's made out of. 730 00:47:29,740 --> 00:47:33,184 如果两个CONS组成部分相同的 它俩则是同样的 And of course, two things are made out of the same parts, they're the same, 731 00:47:33,936 --> 00:47:35,712 至少从这些公理来看是这样的 at least from the point of view of these axioms. 732 00:47:37,328 --> 00:47:39,216 但是引入了赋值以后 But by introducing assignment-- 733 00:47:39,840 --> 00:47:42,320 实际上 可变数据就是一种赋值 in fact, mutable data is a kind of assignment, 734 00:47:42,880 --> 00:47:44,432 我们有SET-CAR!和SET-CDR! we have a set CAR and a set CDR-- 735 00:47:45,552 --> 00:47:48,944 引入这些运算后 这些公理就不完整了 by introducing those, these axioms no longer tell the whole story. 736 00:47:49,830 --> 00:47:52,032 但是这里写的也是对的 And they're still true if written exactly like this. 737 00:47:53,250 --> 00:47:54,944 只不过描述的不再完整 But they don't tell the whole story. 738 00:47:56,070 --> 00:48:01,680 因为如果我要修改一个特定的CONS的CAR部分 Because if I'm going to set a particular CAR in a particular CONS, 739 00:48:03,024 --> 00:48:04,032 问题是 the questions are, 740 00:48:04,240 --> 00:48:08,640 我会同时修改到相同CONS单元的CAR部分么? well, is that setting all CARs and all CONSes of the same two things or not? 741 00:48:10,090 --> 00:48:13,040 假如我用CONS来构建有理数 If I--if we use CONSes to make up things like rational numbers, 742 00:48:14,864 --> 00:48:17,104 比如说3/4 or things like 3 over 4, 743 00:48:17,344 --> 00:48:20,256 假设我有两个3/4 supposing I had two three-fourths. 744 00:48:21,570 --> 00:48:22,752 这两个一样吗? Are they the same one-- 745 00:48:24,064 --> 00:48:24,890 或者又不一样? or are they different? 746 00:48:25,340 --> 00:48:26,960 当然 对于数字来说 这并不重要 Well, in the case of numbers, it doesn't matter. 747 00:48:27,860 --> 00:48:30,496 修改一个数的分母并没有数学意义 Because there's no meaning to changing the denominator of a number. 748 00:48:33,020 --> 00:48:35,328 我们只能够说创建一个数 具有不同的分母 What you could do is make a number which has a different denominator. 749 00:48:36,840 --> 00:48:39,888 而直接修改一个数的分母这种观念 But the concept of changing a number which has to have a different denominator 750 00:48:40,000 --> 00:48:43,584 在数学意义上是一种非常奇怪而不受支持的行为 is sort of a very weird, and sort of not supported by what you think of as mathematics. 751 00:48:44,770 --> 00:48:47,408 然而 当这些CONS单元表示的是现实世界中的事物 However, when these CONSes represent things in the physical world, 752 00:48:48,976 --> 00:48:50,432 那么修改它的CAR部分 then changing something like the CAR 753 00:48:50,608 --> 00:48:52,208 就像除掉指甲壳的一块一样 like removing a piece of the fingernail. 754 00:48:53,690 --> 00:48:56,560 所以 每一个CONS都有自己的“身份” And so CONSes have an identity. 755 00:48:57,770 --> 00:48:59,920 我来先说明“身份”是什么意思 Let me show you what I mean about identity, first of all. 756 00:49:01,280 --> 00:49:03,056 来看些例子 Let's do some little example here. 757 00:49:04,320 --> 00:49:15,200 假如(DEFINE A (CONS 1 2)) Supposing I define A to the CONS of 1 and 2. 758 00:49:18,320 --> 00:49:19,760 这是代表什么呢? 首先 Well, what that means, first of all, 759 00:49:20,672 --> 00:49:25,200 这是说我在某个环境中创建了符号A is that somewhere in some environment I've made a symbol A 760 00:49:25,968 --> 00:49:28,672 而它的值是一个序对 to have a value which is a pair 761 00:49:29,472 --> 00:49:34,064 这个序对由两个分别指向1和2的指针组成 consisting of pointers to a 1 and a pointer to a 2, 762 00:49:35,344 --> 00:49:36,160 就像这样 just like that. 763 00:49:38,120 --> 00:49:39,600 又假设 Now, supposing I also say 764 00:49:40,224 --> 00:49:47,584 (DEFINE B (CONS A A)) define B to be the CONS-- 765 00:49:53,888 --> 00:49:56,816 虽然无所谓 不过我还是更喜欢用大写 it doesn't matter, but I like it better, it's prettier-- 766 00:49:57,632 --> 00:49:59,888 (DEFINE B (CONS A A)) of A and A. 767 00:50:03,970 --> 00:50:06,032 这里用了两次A Well, first of all, I'm using the name A twice. 768 00:50:07,840 --> 00:50:10,576 现在就要考虑序对的身份问题了 At this moment, I'm going to think of CONSes as having identity. 769 00:50:11,300 --> 00:50:12,640 这两个A是同一个东西 This is the same one. 770 00:50:13,690 --> 00:50:14,816 这也就是说 And so what that means 771 00:50:15,296 --> 00:50:17,616 我创建了另一个序对 is I make another pair, 772 00:50:18,810 --> 00:50:20,208 我把它记作B which I'm going to call B. 773 00:50:22,384 --> 00:50:27,600 它由两个指向A的指针组成 And it contains two pointers to A. 774 00:50:28,928 --> 00:50:32,208 对于这个对象来说 此时我有三个名字来指称它 At this point, I have three names for this object. 775 00:50:33,104 --> 00:50:34,160 A是一个 A is its name. 776 00:50:34,880 --> 00:50:36,464 (CAR B)是一个 The CAR of B is its name. 777 00:50:37,230 --> 00:50:38,864 (CDR B)也是一个 And the CDR of B is its name. 778 00:50:39,360 --> 00:50:41,150 都是这个序对的别名 It has several aliases, they're called. 779 00:50:44,230 --> 00:50:49,280 假设现在我要执行 Now, supposing I do something like set-the-CAR, 780 00:50:53,776 --> 00:51:08,380 (SET-CAR! (CAR B) 3) the CAR of the CAR of B to 3. 781 00:51:12,750 --> 00:51:17,456 我先去找B的CAR部分 也就是它 What that means is I find the CAR of B, that's this. 782 00:51:17,830 --> 00:51:20,935 再修改它的CAR部分 修改为3 I set the CAR of that to be 3, changing this. 783 00:51:24,760 --> 00:51:25,696 这样我也就修改了A I've changed A. 784 00:51:27,248 --> 00:51:33,648 如果我问 现在A的CAR部分是多少 If I were to ask what's the CAR of A--of A now? 785 00:51:35,340 --> 00:51:37,568 结果是3 I would get out 3, 786 00:51:38,688 --> 00:51:43,392 尽管在这里 A是由1和2构成的序对 even though here we see that A was the CONS of 1 and 2. 787 00:51:45,290 --> 00:51:47,440 我通过改变B而改变了A I caused A to change by changing B. 788 00:51:48,560 --> 00:51:49,648 它们之间存在共享 There is sharing here. 789 00:51:52,256 --> 00:51:53,472 有时候我们需要这样的结构 That's sometimes what we want. 790 00:51:54,240 --> 00:51:56,128 当然 在类似于队列这类的数据结构中 Surely in the queues and things like that, 791 00:51:56,240 --> 00:52:02,384 我们正是这样来定义、组织数据结果来获得数据共享的 that's exactly what we defined our--organized our data structures to facilitate-- sharing. 792 00:52:04,350 --> 00:52:05,664 但是有一些非预期的共享 But inadvertent sharing, 793 00:52:07,760 --> 00:52:09,728 对象间的非预期交互 unanticipated interactions between objects, 794 00:52:10,784 --> 00:52:14,080 是大型程序中产生的BUG的主要来源 is the source of most of the bugs that occur in complicated programs. 795 00:52:15,440 --> 00:52:21,664 通过使对象具有“身份”、允许共享 So by introducing this possibility of things having identity and sharing 796 00:52:21,870 --> 00:52:23,760 给同一个对象取多个别名 and having multiple names for the same thing, 797 00:52:24,080 --> 00:52:25,056 我们获得了强大的能力 we get a lot of power. 798 00:52:25,136 --> 00:52:28,464 但是同时也为此引出的BUG和复杂度而付出代价 But we're going to pay for it with lots of complexity and bugs. 799 00:52:32,190 --> 00:52:36,240 为了把这个讲透彻一点 我们再举一个例子 So also, for example, if I just looked at this just to drive that home, 800 00:52:37,104 --> 00:52:39,872 比如(CADR B) the CADR of B, 801 00:52:42,464 --> 00:52:46,560 看起来和(CAR B)没有一点关系 which has nothing to do with even the CAR of B, apparently. 802 00:52:46,880 --> 00:52:49,024 但是它的值是什么? The CADR of B, what's that? 803 00:52:49,350 --> 00:52:53,560 先取B的CDR部分 再取结果的CAR部分 Take that CDR of B and now take the CAR of that. 804 00:52:53,560 --> 00:52:54,864 哦 还是3 Oh, that's 3 also. 805 00:52:56,480 --> 00:53:00,432 有了共享这样的机制 局部的含义也不是那么清楚了 So I can have non-local interactions by sharing. 806 00:53:01,120 --> 00:53:02,480 所以我们要非常小心的操作 And I have to be very careful of that. 807 00:53:06,640 --> 00:53:12,640 目前为止 我已经介绍了好几个赋值运算 Well, so far, of course, it seems I've introduced several different assignment operators-- 808 00:53:13,184 --> 00:53:17,616 比如SET!、SET-CAR!、SET-CDR! set, set CAR, set CDR. 809 00:53:18,512 --> 00:53:21,392 或许我应该不用SET-CAR!、SET-CDR! 它们引入太多问题了 Well, maybe I should just get rid of set CAR and set CDR. Maybe they're not worthwhile. 810 00:53:22,820 --> 00:53:23,664 而事实则是 Well, the answer is 811 00:53:24,120 --> 00:53:26,112 一旦把骆驼的鼻子牵进帐篷 that once you let the camel's nose into the tent, 812 00:53:26,240 --> 00:53:27,340 它的身体可就自己跟进来了 the rest of him follows. 813 00:53:30,160 --> 00:53:31,264 只要有SET! All I have to have is set, 814 00:53:31,616 --> 00:53:35,850 这些糟糕的东西都可能发生 and I can make all of the--all of the bad things that can happen. 815 00:53:38,550 --> 00:53:39,808 我们来分析一下 Let's play with that a little bit. 816 00:53:40,690 --> 00:53:43,728 前些日子 讲到复合数据的时候 A couple of days ago, when we introduced compound data, 817 00:53:45,136 --> 00:53:51,200 哈罗德教授向你们展示了 用消息接收的方式来定义CONS you saw Hal show you a definition of CONS in terms of a message acceptor. 818 00:53:52,480 --> 00:53:56,064 我将给你们展示一种更加糟糕的方式 I'm going to show you even a more horrible thing, 819 00:53:57,136 --> 00:54:00,048 凭“空”定义CONS a definition of CONS in terms of nothing but air, 820 00:54:02,560 --> 00:54:03,024 “什么”都不用 hot air. 821 00:54:04,440 --> 00:54:08,128 用传统的函数式的方法如何定义CONS呢? What is the definition of CONS, of the old functional kind, 822 00:54:09,264 --> 00:54:11,664 纯粹只用LAMBDA表达式 in terms of purely lambdic expressions, 823 00:54:13,392 --> 00:54:14,400 把序对表示成过程 procedures? 824 00:54:17,392 --> 00:54:19,664 现在我要修改这个定义 Because I'm going to then modify this definition 825 00:54:20,304 --> 00:54:23,168 使得只具有一种赋值 to get assignment to be only one kind of assignment, 826 00:54:24,288 --> 00:54:27,936 用SET!来代替SET-CAR!和SET-CDR! to get rid of the set CAR and set CDR in terms of set. 827 00:54:28,580 --> 00:54:37,392 如果我把CONS定义为 So what if I define CONS of X and Y 828 00:54:38,910 --> 00:54:42,560 定义为一个过程 该过程接收参数M to be a procedure of one argument called a message M, 829 00:54:43,392 --> 00:54:46,320 该过程将M应用在X与Y上 which calls that message on X and Y? 830 00:54:51,120 --> 00:54:53,104 这是阿隆佐·丘奇发明的方法 This idea was invented by Alonzo Church, 831 00:54:53,776 --> 00:54:55,728 他是20世纪最伟大的程序员 who was the greatest programmer of the 20th century, 832 00:54:55,792 --> 00:54:57,152 尽管当时电脑还没有被发明 although he never saw a computer. 833 00:54:57,870 --> 00:54:59,130 但他在20世纪30年代就提出了这个方法 It was done in the 1930s. 834 00:54:59,424 --> 00:55:02,220 他是一个逻辑学家 在普林斯顿大学做研究 He was a logician, I suppose at Princeton at the time. 835 00:55:08,660 --> 00:55:10,432 定义(CAR X)为 Define CAR of X 836 00:55:13,104 --> 00:55:16,928 把X应用在一个二元过程上 to be the result of applying X to that procedure of two arguments, 837 00:55:17,152 --> 00:55:20,608 参数分别是A和D 而结果是选出A A and D, which selects A. 838 00:55:23,710 --> 00:55:24,976 而(CDR X)则是 I will define CDR of X 839 00:55:33,104 --> 00:55:34,784 这样的一个过程 to be that procedure, 840 00:55:35,088 --> 00:55:40,256 把X应用在一个参数分别是A和D的过程上 to be the result of applying X to that procedure of A and D, 841 00:55:40,928 --> 00:55:42,048 该过程选择出D which selects D. 842 00:55:46,670 --> 00:55:49,888 可能你们还没意识到这些就是CAR、CDR和CONS Now, you may not recognize this as CAR, CDR, and CONS. 843 00:55:50,510 --> 00:55:53,616 但我将要给你们演示它符合之前的公理 But I'm going to demonstrate to you that it satisfies the original axioms 844 00:55:54,112 --> 00:55:54,816 举一个例子 just once. 845 00:55:55,616 --> 00:55:57,568 我们来看一下 And then we're going to do some playing of games. 846 00:55:58,290 --> 00:56:06,272 考虑一下语句语句(CAR (CONS 35 47)) Consider the problem CAR of CONS of, say, 35 and 47. 847 00:56:09,936 --> 00:56:10,960 它的结果是多少呢? Well, what is that? 848 00:56:11,120 --> 00:56:15,248 它是通过把35和47代换进 It is the result of taking car of the result of substituting 35 and 47 849 00:56:15,376 --> 00:56:18,208 语句体中的X和Y得到的 X and Y in the body of this. 850 00:56:19,710 --> 00:56:20,690 非常容易 Well, that's easy enough. 851 00:56:20,690 --> 00:56:30,880 就得到了语句(CAR (LAMBDA (M) (M 35 47))) That's CAR of the result of substituting into lambda of M, M of 35 and 47. 852 00:56:35,530 --> 00:56:39,360 这个的结果是把这个对象 Well, what this is, is the result of substituting this object 853 00:56:39,440 --> 00:56:41,856 代换进这里的X而得到的 for X in the body of that. 854 00:56:42,830 --> 00:56:47,664 代换的结果是((LAMBDA (M -- So that's just lambda of M-- 855 00:56:48,336 --> 00:56:52,192 用这个对象代换这里的X that's substituted, because this object is being substituted for X, 856 00:56:52,880 --> 00:56:54,352 这是表的头部 which is the beginning of a list, 857 00:56:54,880 --> 00:57:00,320 体的部分是(M 35 47) lambda of M-- M of 35 and 47, 858 00:57:03,104 --> 00:57:07,312 把它应用于一个参数分别的A和D的过程上 applied to that procedure of A and D, 859 00:57:07,488 --> 00:57:08,672 后者返回参数A which gives me A. 860 00:57:10,912 --> 00:57:14,624 然后我们用这个来代换这里的M Well, that's the result of substituting this for M here. 861 00:57:15,968 --> 00:57:21,712 这个就相当于把(LAMBDA (A D) A) So that's the same thing as lambda of A, D, A, 862 00:57:22,224 --> 00:57:24,848 应用在35和47上 applied to 35 and 47. 863 00:57:26,330 --> 00:57:27,376 结果就是35 Oh, well that's 35. 864 00:57:27,408 --> 00:57:31,210 它就是用35和47分别代换A、D 最后返回A That's substituting 35 for A and for 47 for D in A. 865 00:57:35,600 --> 00:57:37,248 所以我根本不需要任何数据 So I don't need any data at all. 866 00:57:37,888 --> 00:57:38,752 甚至连数字都不需要 not even numbers. 867 00:57:40,928 --> 00:57:42,640 这就是 阿隆佐·邱奇的技巧 This is Alonso Church's hack. 868 00:57:52,420 --> 00:57:56,176 现在呢我们来对这个定义做点修改 Well, now we're going to do something nasty to him. 869 00:57:56,760 --> 00:57:58,496 作为逻辑学家 他可能会不太开心 Being a logician, he wouldn't like this. 870 00:57:59,200 --> 00:58:01,968 但作为程序员 -- 请看投影仪 But as programmers, let's look at the overhead. 871 00:58:03,260 --> 00:58:04,160 我们来看看 And here we go. 872 00:58:05,390 --> 00:58:07,584 我修改了CONS的定义 I'm going to change the definition of CONS. 873 00:58:09,570 --> 00:58:12,352 和丘奇的定义很相似 但是不完全相同 It's almost the same as Alonzo Church's, but not quite. 874 00:58:14,416 --> 00:58:15,504 具体到底是什么? What do we have here? 875 00:58:16,070 --> 00:58:18,720 CONS有两个参数:X和Y The CONS of two arguments, X and Y, 876 00:58:19,504 --> 00:58:22,512 但它返回一个参数为M的过程 is going to be that procedure of one argument M, 877 00:58:23,392 --> 00:58:25,648 跟之前一样M会应用于X和Y上 which supplies M to X and Y as before, 878 00:58:26,192 --> 00:58:29,296 但它额外还有两个“许可” but also to two permissions, 879 00:58:30,176 --> 00:58:32,016 其中一个是把X赋值为N the permission to set X to N 880 00:58:32,608 --> 00:58:34,400 另一个则是把Y赋值为N and the permission to set Y to N, 881 00:58:34,448 --> 00:58:35,680 只要我提供了相应的N given that I have an N. 882 00:58:40,940 --> 00:58:44,720 所以出了邱奇原本的定义之外 So besides the things that I had here in Church's definition, 883 00:58:45,728 --> 00:58:51,664 最大的不同在于CONS的返回值 what I have is that the thing that CONS returns 884 00:58:52,128 --> 00:58:53,824 不单会把它的参数应用于 will apply its argument 885 00:58:54,912 --> 00:58:59,440 用于构成序对的X和Y之上 to not just the values of the X and Y that the CONS is made of, 886 00:58:59,696 --> 00:59:03,584 它还有用于为X和Y赋值的两个“许可” but also permissions to set X and Y to new values. 887 00:59:06,540 --> 00:59:08,080 当然 就如之前一样 Now, of course, just as before, 888 00:59:08,832 --> 00:59:10,512 CAR看起来也很相似 CAR is exactly the same. 889 00:59:11,690 --> 00:59:14,368 就像邱奇定义的那样 The CAR of X is nothing more than applying X, 890 00:59:14,544 --> 00:59:16,000 (CAR X)只不过是把X应用在 as in Church's definition, 891 00:59:16,864 --> 00:59:19,008 过程上 -- 本例中是四个参数 to a procedure, in this case, of four arguments, 892 00:59:19,296 --> 00:59:21,040 然后从中选出第一个 which selects out the first one. 893 00:59:22,540 --> 00:59:24,160 这就和之前一样 And just as we did before, 894 00:59:25,424 --> 00:59:26,960 结果将会返回X that will be the value of X 895 00:59:29,040 --> 00:59:35,408 X的值被包含在求值这个LAMBDA表达式所产生的过程中 that was contained in the procedure which is the result of evaluating this lambda expression 896 00:59:35,456 --> 00:59:37,840 X和Y的值也是在这个环境中定义的 in the environment where X and Y are defined over here. 897 00:59:41,940 --> 00:59:43,152 这是我们对CONS的定义 That's the value of CONS. 898 00:59:45,640 --> 00:59:47,536 那么 激动人心的地方来了 Now, however, the exciting part. 899 00:59:47,730 --> 00:59:48,960 当然CDR的定义也类似 CDR, of course, is the same. 900 00:59:49,390 --> 00:59:50,352 激动人心的地方 The exciting part, 901 00:59:51,232 --> 00:59:52,528 SET-CAR!和SET-CDR!的实现 set CAR and set CDR. 902 00:59:53,456 --> 00:59:55,520 说实话 它们也不是特别复杂 Well, they're nothing very complicated anymore. 903 00:59:55,800 --> 01:00:00,640 语句(SET-CAR! X Y) Set CAR of a CONS X to a new value Y 904 01:00:01,632 --> 01:00:03,856 无非就是把序对X应用于 is nothing more than applying that CONS, 905 01:00:04,112 --> 01:00:06,768 注意X是一个一元过程 which is the procedure of four--the procedure of one argument 906 01:00:07,696 --> 01:00:09,808 该过程的体是将参数应用在四个对象上 which applies its argument to four things, 907 01:00:11,248 --> 01:00:15,856 我们把X应用于一个四元过程上 to a procedure which is of four arguments-- 908 01:00:16,000 --> 01:00:18,080 X的值、Y的值 the value of X, the value of Y, 909 01:00:18,320 --> 01:00:20,544 修改X的许可、修改Y的许可 permission to set X, the permission to set Y-- 910 01:00:21,320 --> 01:00:26,096 语句的体则是用相应的许可 将X设置为新的值 and using it--using that permission to set X to the new value. 911 01:00:31,650 --> 01:00:33,540 当然SET-CDR!和它类似 And similarly, set-cdr is the same thing. 912 01:00:36,256 --> 01:00:39,440 你也看到了 我这里并没有引入新的基本运算 So what you've just seen is that I didn't introduce any new primitives at all. 913 01:00:40,112 --> 01:00:44,368 具体要不要这样来实现是一个工程性问题 I mean, Whether or not I want to implement it this way is a matter of engineering. 914 01:00:45,340 --> 01:00:47,392 当然出于工程上的考量 And the answer is of course I don't implement it this way 915 01:00:48,096 --> 01:00:49,630 我不会这样来实现 for reasons that have to do with engineering. 916 01:00:51,680 --> 01:00:53,408 但是从原理上来说 However in principle, logically, 917 01:00:54,288 --> 01:00:56,432 一旦引入了赋值运算 I introduced one assignment operator, 918 01:00:56,960 --> 01:00:58,760 我就可以进行各种各样的赋值运算了 I've assigned--I've introduced them all. 919 01:01:05,420 --> 01:01:06,670 有什么问题吗? Are there any questions? 920 01:01:09,200 --> 01:01:10,896 请讲 Yes, David. 921 01:01:12,040 --> 01:01:15,648 我可以跟的上你的思路 直到 -- AUDIENCE: I can follow you up until you get--I can follow all of that. 922 01:01:15,648 --> 01:01:17,616 在许可那里 But when we bring in the permissions, 923 01:01:18,144 --> 01:01:21,648 我们把CONS定义为一个参数为N的过程 defining CONS in terms of the lambda N, 924 01:01:21,808 --> 01:01:24,210 我不知道这个参数是什么时候传进来的 I don't follow where N gets passed. 925 01:01:24,210 --> 01:01:25,696 教授:哦 抱歉 我给你演示一下 PROFESSOR: Oh, I'm sorry. I'll show you. 926 01:01:26,340 --> 01:01:27,056 我们来推演一下 Let's follow it. 927 01:01:27,360 --> 01:01:29,072 虽然在黑板上推演更清晰 Of course, we could do it on the blackboard. 928 01:01:29,180 --> 01:01:30,170 但这并不难懂 It's not so hard. 929 01:01:30,170 --> 01:01:31,472 我就将就用投影仪了 But it's also easy here. 930 01:01:32,450 --> 01:01:35,792 调用(SET-CDR! X Y)会发生什么呢? Supposing I wish to set-cdr of X to Y. 931 01:01:37,790 --> 01:01:39,664 就在这里(SET-CDR! X Y) See that right there. set cdr x to y 932 01:01:40,360 --> 01:01:41,920 X可能是一个序对 X is presumably a CONS, 933 01:01:43,312 --> 01:01:45,248 或者说对一个CONS表达式求值得到的结果 a thing resulting from evaluating CONS. 934 01:01:45,888 --> 01:01:46,352 能跟上吧? right? 935 01:01:46,890 --> 01:01:49,968 也就是说 X是由这里的代码构造出来的 Therefore X comes from a place over here, 936 01:01:52,576 --> 01:01:56,496 这里的X是求值这个LAMBDA表达式得到的 that that X is of the result of evaluating this lambda expression. 937 01:01:58,110 --> 01:01:58,496 对吧 Right? 938 01:01:59,380 --> 01:02:01,632 因此当我对这个LAMBDA表达式求值时 That when I evaluated that lambda expression, 939 01:02:04,016 --> 01:02:08,768 我是在定义CONS时的一个环境里求值的 I evaluated it in an environment where the arguments to CONS were defined. 940 01:02:11,750 --> 01:02:15,184 这也就是说 作为LAMBDA表达式中的自由变量 That means that as free variables in this lambda expression, 941 01:02:16,250 --> 01:02:18,688 X和Y都存储一个框架中 there is the--there are in the frame, 942 01:02:18,720 --> 01:02:22,440 也就是这整个LAMBDA表达式的父框架 which is the parent frame of this lambda expression, 943 01:02:23,232 --> 01:02:25,824 因此在这个LAMBDA语句中 the procedure resulting from this lambda expression, 944 01:02:26,656 --> 01:02:28,512 X和Y都有存储空间 X and Y have places. 945 01:02:29,250 --> 01:02:30,832 也可以对它们赋值 And it's possible to set them. 946 01:02:31,910 --> 01:02:36,080 这里赋值为N是通过参数来传递的 I set them to an N, which is the argument of the permission. 947 01:02:37,264 --> 01:02:39,312 “许可”就是一个过程 The permission is a procedure 948 01:02:41,408 --> 01:02:43,184 它将作为M的一个参数 which is passed to M, 949 01:02:43,296 --> 01:02:46,512 它实际上是CONS生成的对象的一部分 which is the argument that the CONS object gets passed. 950 01:02:47,940 --> 01:02:50,912 我们再来看看SET-CDR! Now, let's go back here in the set-cdr 951 01:02:52,112 --> 01:02:55,424 SET-CDR!的第一个参数X是一个序对 The CONS object, which is the first argument of set-cdr 952 01:02:56,128 --> 01:02:57,480 被传递了一个参数 gets passed an argument. 953 01:02:59,776 --> 01:03:02,224 这个是一个四元过程 That--there's a procedure of four things, indeed, 954 01:03:02,320 --> 01:03:04,656 这是因为 它要作为这里的M because that's the same thing as this M over here, 955 01:03:04,992 --> 01:03:06,560 要应用在四个对象上 which is applied to four objects. 956 01:03:07,920 --> 01:03:13,344 这边的这个SD 就对应于这个过程 The object over here, SD, is, in fact, this permission. 957 01:03:15,470 --> 01:03:19,930 当我执行SD 把它应用于Y When I use SD, I apply it to Y, right there. 958 01:03:22,910 --> 01:03:24,048 这个Y是这里传过来的 So that comes from this. 959 01:03:25,370 --> 01:03:26,928 学生:那-- AUDIENCE: So what do you-- 960 01:03:27,008 --> 01:03:32,192 教授:所以说 这里的N就对应于这里的Y PROFESSOR: So to finish that, the N that was here is the Y which is here. 961 01:03:34,048 --> 01:03:34,528 明白了吧 How's that? 962 01:03:34,810 --> 01:03:35,750 了解了 AUDIENCE: Right, OK. 963 01:03:35,750 --> 01:03:37,296 当你执行SET-CDR!的时候 Now, when you do a set-cdr, 964 01:03:39,072 --> 01:03:41,970 X是CDR部分要赋值的新值 X is the value the CDR is going to become. 965 01:03:41,970 --> 01:03:44,032 教授:这里的X PROFESSOR: The X over here. 966 01:03:44,960 --> 01:03:46,200 哦 指错了 I'm sorry, that's not true. 967 01:03:46,200 --> 01:03:48,336 这里的X是指 -- SET-CDR!有两个参数 The X is--set-cdr has two arguments-- 968 01:03:48,912 --> 01:03:50,368 一个是被修改的序对 The CONS I'm changing 969 01:03:51,344 --> 01:03:53,936 还有就是新值 and the value I'm changing it to. 970 01:03:56,150 --> 01:03:58,320 你可以代换回去看看 就很清楚了 So you have them backwards, that's all. 971 01:04:02,176 --> 01:04:03,168 还有什么问题吗? Are there any other questions? 972 01:04:07,880 --> 01:04:08,640 好的 Well, thank you. 973 01:04:08,640 --> 01:04:09,520 这节课就到这里 It's time for lunch. 974 01:04:10,448 --> 01:04:17,392 MIT OpenCourseWare http://ocw.mit.edu 975 01:04:17,408 --> 01:04:28,736 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec6a.srt ================================================ 1 00:00:00,000 --> 00:00:02,704 Learning-SICP学习小组 倾情制作 2 00:00:02,730 --> 00:00:04,200 翻译&&时间轴:张大伟(DreamAndDead) 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:04,480 --> 00:00:06,530 特别感谢:裘宗燕教授 4 00:00:06,680 --> 00:00:09,620 计算机程序的构造和解释 5 00:00:09,670 --> 00:00:13,340 流 I Stream 6 00:00:18,550 --> 00:00:21,840 上次Gerry教授揭晓了秘密 PROFESSOR: Well, last time Gerry really let the cat out of the bag. 7 00:00:22,496 --> 00:00:24,608 他介绍了赋值的概念 He introduced the idea of assignment. 8 00:00:26,350 --> 00:00:33,616 赋值与状态 Assignment and state. 9 00:00:37,480 --> 00:00:40,032 正如我们所见 And as we started to see, the implications 10 00:00:40,720 --> 00:00:43,168 将赋值和状态引入到语言中 of introducing assignment and state into the language 11 00:00:43,168 --> 00:00:44,410 后果相当糟糕 are absolutely frightening. 12 00:00:45,088 --> 00:00:48,624 首先 代换模型不再能够描述求值过程了 First of all, the substitution model of evaluation breaks down. 13 00:00:49,136 --> 00:00:52,480 为了解释程序中语句的语义 And we have to use this much more complicated environment model 14 00:00:52,480 --> 00:00:54,272 我们不得不使用更复杂的环境模型 this very mechanistic thing with diagrams, 15 00:00:54,288 --> 00:00:57,248 也就是一种跟图表相关的非常机械的东西 even to say what statements in the programming language mean. 16 00:00:58,464 --> 00:01:00,128 并且 这不单纯地是一个技术上的问题 And that's not a mere technical point. 17 00:01:00,260 --> 00:01:03,280 并不是因为代换模型在这里不怎么有效 See, it's not that we had this particular substitution model and, 18 00:01:03,600 --> 00:01:05,680 所以我们得想些其它办法 well, it doesn't quite work, so we have to do something else. 19 00:01:05,712 --> 00:01:09,792 而是代换模型这类机制都不再起效 It's that nothing like the substitution model can work. 20 00:01:10,730 --> 00:01:13,328 这是因为突然间 一个变量 Because suddenly, a variable 21 00:01:14,128 --> 00:01:16,920 不再是代表着一个值了 is not just something that stands for a value. 22 00:01:17,950 --> 00:01:21,760 现在 变量用于指明一个位置 A variable now has to somehow specify a place 23 00:01:22,400 --> 00:01:23,340 一个存放值的位置 that holds a value. 24 00:01:23,630 --> 00:01:26,144 并且 这个位置的值可以发生改变 And the value that's in that place can change. 25 00:01:30,280 --> 00:01:34,096 比如像 (F X) 这样的表达式 Or for instance, an expression like f of x 26 00:01:37,360 --> 00:01:39,648 就可能含有副作用 might have a side effect in it. 27 00:01:40,410 --> 00:01:42,608 如果我们执行 (F X) 得到某个值 So if we say f of x and it has some value, 28 00:01:43,184 --> 00:01:45,344 之后我们再次执行 (F X) and then later we say f of x again, 29 00:01:47,240 --> 00:01:48,432 可能因为求值的顺序 we might get a different value 30 00:01:48,860 --> 00:01:49,744 而得到不同的值 depending on the order. 31 00:01:49,760 --> 00:01:52,140 所以突然间 我们不能仅仅关注于值 So suddenly, we have to think not only about values 32 00:01:52,528 --> 00:01:53,600 也要关注时序 but about time. 33 00:01:57,970 --> 00:01:59,984 序对也不仅仅 And then things like pairs 34 00:02:00,656 --> 00:02:02,520 只是它的CAR和CDR部分 are no longer just their CARs and their CDRs. 35 00:02:02,520 --> 00:02:05,616 不是作为CAR部分和CDR部分的别称 A pair now is not quite its CAR and its CDR. 36 00:02:05,808 --> 00:02:07,056 它也有自己的“身份” It's rather its identity. 37 00:02:08,449 --> 00:02:11,650 序对具有“身份” So a pair has identity. 38 00:02:11,650 --> 00:02:12,592 它是一个对象 It's an object. 39 00:02:21,330 --> 00:02:25,152 两个具有相同CAR和CDR部分的序对 And two pairs that have the same CAR and CDR 40 00:02:25,408 --> 00:02:27,056 可能相同也可能不同 well, might be the same or different, 41 00:02:27,872 --> 00:02:30,512 因为这之中可能存在“共享” because suddenly we have to worry about sharing. 42 00:02:34,960 --> 00:02:39,456 一引入赋值 这些就变成要考虑的问题了 So all of these things enter as soon as we introduce assignment. 43 00:02:40,480 --> 00:02:43,984 确实 这和我们说讲代换的时候差别悬殊 See, this is a really far cry from where we started with substitution. 44 00:02:45,040 --> 00:02:48,912 技术上来看 我们思考起来更加困难了 It's a technically harder way of looking at things 45 00:02:48,940 --> 00:02:53,456 因为我们必须相当机械地思考程序语言 because we have to think more mechanistically about our programming language. 46 00:02:53,472 --> 00:02:55,344 而不能仅仅用数学的方式来思考 We can't just think about it as mathematics. 47 00:02:55,710 --> 00:02:58,608 我们也会遇到哲学问题 It's philosophically harder, 48 00:02:59,152 --> 00:03:00,656 我们会被这样的问题所困扰: because suddenly there are all these funny issues 49 00:03:00,672 --> 00:03:02,384 事物的“改变”指的是什么? what does it mean that something changes 50 00:03:02,384 --> 00:03:03,776 两个事物“同一”又如何判别? or that two things are the same. 51 00:03:03,840 --> 00:03:06,832 并且 这也会给我们编程带来困扰 And also, it's programming harder, because 52 00:03:07,470 --> 00:03:08,544 正如 Sussman 教授上节课中讲的那样 as Gerry showed last time, 53 00:03:08,560 --> 00:03:12,200 错误的表达式顺序和别名会产生BUG there are all these bugs having to do with bad sequencing and aliasing 54 00:03:12,224 --> 00:03:16,190 这些问题在不需要考虑“对象”的语言中 是不存在的 that just don't exist in a language where we don't worry about objects. 55 00:03:18,210 --> 00:03:21,200 我们是怎样陷入这样的困境的呢? Well, how'd we get into this mess? 56 00:03:24,010 --> 00:03:27,200 我们这样做的原因在于 Remember what we did, the reason we got into this is 57 00:03:27,408 --> 00:03:31,472 我们想要构造模块化的系统 because we were looking to build modular systems. 58 00:03:35,150 --> 00:03:37,696 我们想把系统划分为 We wanted to build systems that 59 00:03:38,096 --> 00:03:41,040 数个自然组合的小块 that fall apart into chunks that seem natural. 60 00:03:42,760 --> 00:03:43,824 举例来说 So for instance, 61 00:03:44,064 --> 00:03:46,110 我们想要构造一个随机数发生器 we want to take a random number generator 62 00:03:46,224 --> 00:03:49,408 把该发生器的内部状态封装起来 and package up the state of that random number generator inside of it 63 00:03:50,256 --> 00:03:53,712 这样我们就可以把选取随机数 so that we can separate the idea of picking random numbers 64 00:03:54,656 --> 00:03:57,792 和用于估计的蒙特卡洛方法分离开来 from the general Monte Carlo strategy of estimating something 65 00:03:58,650 --> 00:04:01,520 进一步地把它同由 Ceraso 发明的 and separate that from the particular way that you 66 00:04:01,904 --> 00:04:05,744 求取 π 的公式分离开 work with random numbers in that formula developed by Cesaro for pi. 67 00:04:06,800 --> 00:04:07,920 相似地 And similarly, 68 00:04:09,616 --> 00:04:11,744 当我们着手构建事物的模型时 when we go off and construct some models of things, 69 00:04:12,352 --> 00:04:16,016 我们去构建现实世界中事物的模型 Ah, if we go off and model a system that we see in the real world, 70 00:04:17,310 --> 00:04:19,424 我们想把程序组织成许多自然部分 we'd like our program to break into natural pieces, 71 00:04:19,440 --> 00:04:20,528 这些部分就是 pieces that mirror 72 00:04:21,056 --> 00:04:23,160 现实事物的镜像 the parts of the system that we see in the real world. 73 00:04:24,900 --> 00:04:27,568 举个例子 对于一个数字电路 So for example, if we look at a digital circuit, 74 00:04:28,368 --> 00:04:29,184 我们会说 we say, gee, 75 00:04:30,440 --> 00:04:31,440 这儿有一个电路 there's a circuit 76 00:04:32,080 --> 00:04:35,160 它有一个这样的元件 有一个那样的元件 and it has a piece and it has another piece. 77 00:04:40,100 --> 00:04:43,580 这些元件都有不同的“身份” And these different pieces sort of have identity. 78 00:04:43,580 --> 00:04:44,592 它们都有各自的状态 They have state. 79 00:04:45,550 --> 00:04:47,136 状态附着在电路上 And the state sits on these wires. 80 00:04:48,580 --> 00:04:50,224 我们认为这个元件是一个对象 And we think of this piece as an object 81 00:04:50,496 --> 00:04:51,930 这个元件又是另外一个不同的对象 that's different from that as an object. 82 00:04:52,540 --> 00:04:53,856 当我们观察到系统发生了变化 And when we watch the system change, 83 00:04:53,872 --> 00:04:55,408 信号从这里传递过来 we think about a signal coming in here 84 00:04:55,632 --> 00:04:58,416 改变了可能存放在这里的状态 并向这里继续传播 changing a state that might be here and going here 85 00:04:58,672 --> 00:05:00,752 和一个存储在这里的状态交互 and interacting with a state that might be stored there, 86 00:05:01,248 --> 00:05:02,170 依此类推 and so on and so on. 87 00:05:06,860 --> 00:05:11,248 我们想要在计算机中 So what we'd like is we'd like to build in the computer 88 00:05:12,768 --> 00:05:14,368 构建模块化的系统 systems that fall into pieces 89 00:05:14,688 --> 00:05:17,872 来反映我们对现实的看法 that fall into pieces that mirror our view of reality, 90 00:05:17,880 --> 00:05:19,872 根据我们正在建模的实际系统 of the way that the actual systems we're modeling 91 00:05:19,888 --> 00:05:20,910 来划分子系统 seem to fall into pieces. 92 00:05:23,200 --> 00:05:23,488 然而 Well, 93 00:05:25,744 --> 00:05:28,992 构建像这样的系统 maybe the reason that building systems like this 94 00:05:28,992 --> 00:05:31,504 看起来带来了不少技术上的麻烦 seems to introduce such technical complications 95 00:05:31,520 --> 00:05:32,752 但这不是计算机造成的 has nothing to do with computers. 96 00:05:33,610 --> 00:05:35,600 或许 真正拖累我们 See, maybe the real reason 97 00:05:36,700 --> 00:05:38,656 让我们花了那么大的功夫 that we pay such a price to write programs 98 00:05:38,672 --> 00:05:40,940 才让程序反映现实世界的原因 that mirror our view of reality 99 00:05:41,520 --> 00:05:43,136 是我们对现实世界的认识出了错 is that we have the wrong view of reality. 100 00:05:44,550 --> 00:05:46,752 或许时间只是幻觉 See, maybe time is just an illusion, 101 00:05:47,264 --> 00:05:48,608 什么都没有改变 and nothing ever changes. 102 00:05:50,150 --> 00:05:51,712 就拿这个粉笔来说 See, for example, if I take this chalk, 103 00:05:52,448 --> 00:05:53,776 我们认为它是一个对象 and we say, gee, this is an object 104 00:05:54,016 --> 00:05:54,992 它有自己的状态 and it has a state. 105 00:05:55,820 --> 00:05:59,296 每时每刻 它都有一个位置和速度 At each moment it has a position and a velocity. 106 00:05:59,710 --> 00:06:01,488 如果我们做点什么 就可以改变它的状态 And if we do something, that state can change. 107 00:06:04,340 --> 00:06:07,376 但是你如果了解一点相对性的概念 But if you studied any relativity, for instance, 108 00:06:07,744 --> 00:06:09,712 你可能会认为粉笔的路径 you know that you don't think of the path of that chalk 109 00:06:09,728 --> 00:06:11,340 不是许多瞬时的离散点 as something that goes on instant by instant. 110 00:06:11,340 --> 00:06:14,384 一种深刻的见解是把整个粉笔的存在看作 It's more insightful to think of that whole chalk's existence 111 00:06:14,416 --> 00:06:15,648 时空中的路径 as a path in space-time. 112 00:06:16,020 --> 00:06:17,376 全部都展开了 that's all splayed out. 113 00:06:17,872 --> 00:06:19,840 没有单独的位置与速度 There aren't individual positions and velocities. 114 00:06:19,840 --> 00:06:23,808 在时空中的存在是不会发生改变的 There's just its unchanging existence in space-time. 115 00:06:24,640 --> 00:06:26,512 相似地 如果我们来考察这个电气系统 Similarly, if we look at this electrical system, 116 00:06:27,690 --> 00:06:30,432 我们假设这个系统实现的是 if we imagine this electrical system is implementing 117 00:06:30,592 --> 00:06:33,960 某种信号处理系统 sort of signal processing system, 118 00:06:34,368 --> 00:06:36,688 把这些元件组合在一起的工程师 the signal processing engineer who put that thing together 119 00:06:36,750 --> 00:06:38,608 也不会把它们看作 doesn't think of it as, well, 120 00:06:38,960 --> 00:06:41,400 电压施加于每个独立的元件 at each instance there's a voltage coming in. 121 00:06:41,490 --> 00:06:43,168 转换成了某种东西 And that translates into something. 122 00:06:43,340 --> 00:06:45,520 影响了这里的状态 And that affects the state over here, 123 00:06:45,536 --> 00:06:46,810 还改变了那里的状态 which changes the state over here. 124 00:06:46,810 --> 00:06:50,112 没有一个做信号处理的会这样想 Nobody putting together a signal processing system thinks about it like that. 125 00:06:50,420 --> 00:06:51,840 相反 你会说 Instead, you say there's this signal 126 00:06:54,048 --> 00:06:58,060 这里有一个在时间上伸展的信号 that's splayed out over time. 127 00:06:58,060 --> 00:06:59,488 如果把这个看作一个滤波器 And if this is acting as a filter, 128 00:07:00,208 --> 00:07:04,048 这个滤波器会把整个信号转化成 this whole thing transforms this whole thing 129 00:07:04,288 --> 00:07:07,040 不同的输出信号 for some sort of other output. 130 00:07:09,570 --> 00:07:11,280 你们不要把这些东西的状态 You don't think of it as what's happening 131 00:07:11,280 --> 00:07:13,290 想象成在许多瞬间接连发生 instant by instant as the state of these things. 132 00:07:14,160 --> 00:07:17,328 我们把这个盒子看作一个整体 And somehow you think of this box as a whole thing, 133 00:07:17,320 --> 00:07:20,160 而不是在一个特定的瞬间 not as little pieces sending messages of state 134 00:07:20,400 --> 00:07:21,960 互相发送状态信息的小系统 to each other at particular instants. 135 00:07:28,250 --> 00:07:29,360 今天我们将介绍 Well, today we're going to look at 136 00:07:29,392 --> 00:07:31,130 另一种分解系统的方法 another way to decompose systems 137 00:07:31,360 --> 00:07:35,456 站在信号工程师的角度去看待现实世界 that's more like the signal processing engineer's view of the world 138 00:07:35,696 --> 00:07:38,960 而不再认为对象间通过消息传递来通信 than it is like thinking about objects that communicate sending messages. 139 00:07:41,130 --> 00:07:43,744 它被称为“流处理” That's called stream processing. 140 00:07:54,570 --> 00:07:58,960 我们打算展示 And we're going to start by showing 141 00:08:00,592 --> 00:08:04,160 如何让我们的程序变得更加统一 by showing how we can make our programs more uniform 142 00:08:05,152 --> 00:08:06,544 从中看到更多的共性 and see a lot more commonality 143 00:08:06,656 --> 00:08:09,888 如果我们跳出这些程序 if we throw out of these programs 144 00:08:10,816 --> 00:08:12,304 我们会发现 what you might say is a 145 00:08:12,352 --> 00:08:15,120 我们对时序的考虑过度了 inordinate concern with worrying about time. 146 00:08:16,896 --> 00:08:20,224 我们先来对比两个过程 Let me start by comparing two procedures. 147 00:08:23,552 --> 00:08:25,690 第一个是这样 The first one does this. 148 00:08:25,690 --> 00:08:27,770 想像这有一个树 We imagine that there's a tree. 149 00:08:30,400 --> 00:08:32,144 一个由整数构成的树 Say there's a tree of integers. 150 00:08:33,280 --> 00:08:34,420 一个二叉树 It's a binary tree. 151 00:08:36,128 --> 00:08:36,976 这里是1 Say 1. 152 00:08:39,100 --> 00:08:40,230 看起来就像这样 So it looks like this. 153 00:08:40,230 --> 00:08:42,928 在每个节点上都有一个整数 And there's integers in each of the nodes. 154 00:08:45,184 --> 00:08:47,808 我们想计算 And what we would like to compute is 155 00:08:48,672 --> 00:08:51,568 对这个树中所有的奇数 for each odd number sitting here, 156 00:08:52,304 --> 00:08:55,104 计算它们的平方和 we'd like to find the square and then sum up all those squares. 157 00:08:57,056 --> 00:08:59,480 我们对这类问题很熟悉 Well, that should be a familiar kind of thing. 158 00:08:59,480 --> 00:09:01,952 有一种递归策略求解它 There's a recursive strategy for doing it. 159 00:09:02,930 --> 00:09:04,352 观察每个叶子节点 We look at each leaf, and either 160 00:09:04,560 --> 00:09:06,688 如果是奇数我们就求它的平方 并加和 it's going to contribute the square of the number if it's odd 161 00:09:06,704 --> 00:09:07,770 如果是偶数 就是0 or 0 if it's even. 162 00:09:08,680 --> 00:09:12,112 递归地看 对于每一颗树 我们可以说 And then recursively, we can say at each tree 163 00:09:12,656 --> 00:09:13,840 它的平方和等于 the sum of all of them is 164 00:09:13,920 --> 00:09:15,936 右子树的平方和 加上左子树的平方和 the sum coming from the right branch and the left branch, 165 00:09:16,256 --> 00:09:17,640 就这样沿着节点递归下去 and recursively down through the nodes. 166 00:09:17,640 --> 00:09:18,704 我们已经很熟悉 And that's a familiar way of 167 00:09:19,264 --> 00:09:20,360 这种程序设计的思考方式了 thinking about programming. 168 00:09:20,360 --> 00:09:22,592 我们来幻灯片上看一下 Let's actually look at that on the slide. 169 00:09:23,820 --> 00:09:26,752 为了计算一棵树中奇数的平方和 We say to sum the odd squares in a tree, 170 00:09:27,376 --> 00:09:29,360 我们先要判断它是否是一个叶子节点 there's a test. Either it's a leaf node, 171 00:09:29,824 --> 00:09:31,952 判断方法则是考察该节点是否为整数 and we're going to check to see if it's an integer, 172 00:09:32,880 --> 00:09:36,384 继而判断其奇偶性 以及是否应该求取平方并加和 and then either it's odd, in which we take the square, or else it's 0. 173 00:09:37,160 --> 00:09:38,992 然后 整个的解就是 And then the sum of the whole thing 174 00:09:39,216 --> 00:09:42,120 左、右子树解的总和 is the sum coming from the left branch and the right branch. 175 00:09:46,340 --> 00:09:50,560 好的 让我们再来和下面一个问题对比一下 OK, well, let me contrast that with a second problem. 176 00:09:51,560 --> 00:09:53,680 假如给你一个整数N Suppose I give you an integer n, 177 00:09:54,736 --> 00:09:57,888 再给定一个函数 把它应用在 and then some function to compute of the first of each integer 178 00:09:57,936 --> 00:09:58,832 1到N的每一个数上 1 through n. 179 00:09:59,100 --> 00:10:01,088 我想把其中的一些值收集成一个表 And then I want to collect together in a list 180 00:10:01,280 --> 00:10:04,656 那些满足某种属性的函数值 all those function values that satisfy some property. 181 00:10:05,600 --> 00:10:06,880 这是种一般性的说法 That's a general kind of thing. 182 00:10:06,880 --> 00:10:07,984 说得更具体一点 Let's say to be specific, 183 00:10:08,624 --> 00:10:10,480 假设对于每个整数K let's imagine that for each integer, k, 184 00:10:10,656 --> 00:10:12,512 计算第K个斐波那契数 we're going to compute the k Fibonacci number. 185 00:10:14,210 --> 00:10:16,272 然后挑出其中的奇数 And then we'll see which of those are odd 186 00:10:16,832 --> 00:10:18,400 并把它们组成一个表 and assemble those into a list. 187 00:10:19,050 --> 00:10:20,710 这个过程是这样的 So here's a procedure that does that. 188 00:10:23,730 --> 00:10:26,240 寻找前N个斐波那契数中的奇数 Find the odd Fibonacci numbers among the first n. 189 00:10:26,240 --> 00:10:28,910 这里是我们一直以来采用的循环方法 And here is a standard loop the way we've been writing it. 190 00:10:28,910 --> 00:10:29,824 用到了递归 This is a recursion. 191 00:10:30,800 --> 00:10:31,792 以K为循环变量 It's a loop on k, 192 00:10:32,032 --> 00:10:34,352 如果K大于N 返回空表 and says if k is bigger than n, it's the empty list. 193 00:10:35,136 --> 00:10:37,360 否则计算第K个斐波那契数 Otherwise we compute the k-th Fibonacci number, 194 00:10:37,440 --> 00:10:38,064 将其与变量F绑定 call that f. 195 00:10:40,370 --> 00:10:42,848 如果是奇数 我们把它与 If it's odd, we CONS it on 196 00:10:43,760 --> 00:10:46,010 从K+1计算得到的表相连接 to the list starting with the next one. 197 00:10:47,690 --> 00:10:50,128 否则 我们只取从K+1计算得到的结果 And otherwise, we just take the next one. 198 00:10:50,736 --> 00:10:53,000 这是迭代式循环的标准写法 And this is the standard way we've been writing iterative loops. 199 00:10:53,000 --> 00:10:55,568 我们以1为初值 启动这个循环 And we start off calling that loop with 1. 200 00:10:57,584 --> 00:11:00,064 好的 就是这两个过程 OK, so there are two procedures. 201 00:11:01,600 --> 00:11:02,900 它们看起来非常不同 Those procedures look very different. 202 00:11:02,900 --> 00:11:04,208 完全不同的结构 They have very different structures. 203 00:11:04,250 --> 00:11:06,896 然而 从一个特定的角度来看 Yet from a certain point of view, 204 00:11:06,928 --> 00:11:09,616 两个过程做的事情是一样的 those procedures are really doing very much the same thing. 205 00:11:11,330 --> 00:11:14,672 如果我是一个信号处理工程师 So if I was talking like a signal processing engineer, 206 00:11:14,704 --> 00:11:16,816 我可能会说 what I might say 207 00:11:18,240 --> 00:11:26,768 第一个过程枚举了树的叶节点 the first procedure enumerates the leaves of a tree. 208 00:11:31,160 --> 00:11:34,560 可以认为是信号从一个全是叶节点的地方输出 And then we can think of a signal coming out of that, which is all the leaves. 209 00:11:35,330 --> 00:11:43,392 我们想要过滤出其中的奇数 We'll filter them to see which ones are odd, 210 00:11:43,584 --> 00:11:44,944 把它们放入某种滤波器中 put them through some kind of filter. 211 00:11:45,190 --> 00:11:47,792 然后再把它们放入某种换能器 We'll then put them through a kind of transducer. 212 00:11:49,200 --> 00:11:51,696 对每一个输出 我们对其取平方 And for each one of those things, we'll take the square. 213 00:11:54,448 --> 00:11:57,440 最后把结果累积在一起 And then we'll accumulate all of those. 214 00:11:58,290 --> 00:12:00,048 我们以0为初值 We'll accumulate them by sticking them together 215 00:12:00,352 --> 00:12:03,370 通过加法把它们累积起来 with addition starting from 0. 216 00:12:07,140 --> 00:12:08,210 这是第一个程序 That's the first program. 217 00:12:08,210 --> 00:12:09,184 对于第二个程序 The second program, 218 00:12:09,248 --> 00:12:11,216 我也可以用一种非常类似的方法来描述 I can describe in a very, very similar way. 219 00:12:11,780 --> 00:12:13,424 我们枚举 I'll say, we'll enumerate 220 00:12:15,808 --> 00:12:19,104 从1到N这个区间上的数 the numbers on this interval, for the interval 1 through n. 221 00:12:22,500 --> 00:12:24,400 对于每个数 We'll, for each one, 222 00:12:25,456 --> 00:12:26,928 计算对应的斐波那契数 compute the Fibonacci number, 223 00:12:27,792 --> 00:12:29,270 再放入一个换能器 put them through a transducer. 224 00:12:29,270 --> 00:12:30,784 对于输出的结果 We'll then take the result of that, 225 00:12:31,312 --> 00:12:34,208 再通过奇偶性进行过滤 and we'll filter it for oddness. 226 00:12:36,272 --> 00:12:39,248 最后 我们将这些放入累积函数 And then we'll take those and put them into an accumulator. 227 00:12:39,350 --> 00:12:40,560 这次我们要累积出一个表 This time we'll build up a list, 228 00:12:40,784 --> 00:12:42,176 所以我们用CONS来做积累 so we'll accumulate with CONS 229 00:12:42,592 --> 00:12:43,776 以空表为初始值 starting from the empty list. 230 00:12:47,110 --> 00:12:49,808 从这个角度来看 So this way of looking at the program 231 00:12:49,856 --> 00:12:51,840 这两个程序真的是太相似了 makes the two seem very, very similar. 232 00:12:51,900 --> 00:12:52,848 问题在于 The problem is 233 00:12:53,200 --> 00:12:56,496 两个程序的写法导致 that that commonality is completely obscured 234 00:12:56,640 --> 00:12:58,050 我们看不出其中的共性 when we look at the procedures we wrote. 235 00:12:58,050 --> 00:13:01,440 再回头来看奇数平方和的问题 Let's go back and look at some odd squares again, 236 00:13:02,224 --> 00:13:04,640 问题来了 哪个是枚举函数呢? and say things like, where's the enumerator? 237 00:13:06,352 --> 00:13:08,140 程序中哪一部分有枚举的作用? Where's the enumerator in this program? 238 00:13:08,140 --> 00:13:10,528 枚举不是仅仅在一个地方表现出来的 Well, it's not in one place. 239 00:13:11,020 --> 00:13:15,472 在叶子节点的判断处存在一部分 It's a little bit in this leaf-node test, 240 00:13:16,432 --> 00:13:17,160 在这个判断循环终止的地方 which is going to stop. 241 00:13:17,160 --> 00:13:20,064 也下面的递归结构中也有体现 It's a little bit in the recursive structure of the thing itself. 242 00:13:23,150 --> 00:13:24,120 累积函数又在哪儿呢? Where's the accumulator? 243 00:13:24,120 --> 00:13:25,680 它也不只在一个地方 The accumulator isn't in one place either. 244 00:13:25,680 --> 00:13:30,736 它在 0 和 + 这两个地方分别体现出来 It's partly in this 0 and partly in this plus. 245 00:13:32,000 --> 00:13:34,510 累积函数分散在过程的每个部分 Right? It's not there as a thing that we can look at. 246 00:13:34,510 --> 00:13:39,056 相似地 我们来观察奇数斐波那契数的例子 Similarly, if we look at odd Fibs, 247 00:13:39,050 --> 00:13:42,800 某种意义上 程序中也存在枚举函数与累积函数 that's also, in some sense, an enumerator and an accumulator, 248 00:13:42,800 --> 00:13:44,016 但看起来非常不同 but it looks very different. 249 00:13:44,624 --> 00:13:50,096 枚举部分地表现在(> k n)的判断中 Because partly, the enumerator is here in this greater than sign in the test. 250 00:13:50,384 --> 00:13:52,848 部分地表现在下面的递归调用中 And partly it's in this whole recursive structure in the loop, 251 00:13:53,184 --> 00:13:54,240 还有就是启动循环的地方 and the way that we call it. 252 00:13:55,680 --> 00:13:56,320 同样地 And then similarly, 253 00:13:56,528 --> 00:13:58,768 其中也混杂了累积函数 that's also mixed up in there with the accumulator, 254 00:13:58,912 --> 00:14:00,128 分别在这里 which is partly over there 255 00:14:00,416 --> 00:14:01,408 和这里 and partly over there. 256 00:14:03,600 --> 00:14:06,080 所以这些非常自然的部分 So these very, very natural pieces, 257 00:14:08,736 --> 00:14:12,656 我们之前画的那些方框在程序中完全看不出来 these very natural boxes here don't appear in our programs. 258 00:14:13,264 --> 00:14:14,360 因为它们混杂在一起了 Because they're kind of mixed up. 259 00:14:14,360 --> 00:14:16,290 这些程序并没有很好地对问题进行切分 The programs don't chop things up in the right way. 260 00:14:19,450 --> 00:14:22,176 回到计算机科学的基本原理上来 Going back to this fundamental principle of computer science 261 00:14:22,192 --> 00:14:23,632 为了控制某种东西 that in order to control something, 262 00:14:23,632 --> 00:14:24,960 你需要它的名字 you need the name of it, 263 00:14:25,808 --> 00:14:28,448 我们还没有很好地掌握按这种方式来思考 we don't really have control over thinking about things this way 264 00:14:28,672 --> 00:14:31,060 这是因为我们没有显式地操作它们的手段 because we don't have our hands in them explicitly. 265 00:14:31,060 --> 00:14:33,808 我们没有一门好的语言来讨论它们 We don't have a good language for talking about them. 266 00:14:35,420 --> 00:14:38,864 好吧 我们来创造一门合适的语言 Well, let's invent an appropriate language 267 00:14:42,528 --> 00:14:44,048 用它来构建这些器件 in which we can build these pieces. 268 00:14:44,784 --> 00:14:47,216 这种语言的关键在于 The key to the language is these guys, 269 00:14:47,216 --> 00:14:49,712 这些叫作信号的东西到底是什么? is what is these things I called signals? 270 00:14:50,480 --> 00:14:53,320 这些沿着箭头传递的是什么? What are these things that are flying on the arrows between the boxes? 271 00:14:56,880 --> 00:14:57,712 这些东西 Well, those things 272 00:14:59,856 --> 00:15:03,520 是一种称作“流”的数据结构 are going to be data structures called streams. 273 00:15:03,792 --> 00:15:05,872 这也是发明这门语言的关键 That's going to be the key to inventing this language. 274 00:15:07,980 --> 00:15:08,512 “流”是什么东西呢? What's a stream? 275 00:15:08,528 --> 00:15:11,504 和其它的东西一样 “流”是一种数据抽象 Well, a stream is, like anything else, a data abstraction. 276 00:15:12,220 --> 00:15:15,824 所以 我先说明它的选择函数与构造函数分别是什么 So I should tell you what its selectors and constructors are. 277 00:15:16,870 --> 00:15:19,488 对于流结构 我们有一个构造函数 For a stream, we're going to have one constructor 278 00:15:19,984 --> 00:15:21,430 我们称其为CONS-STREAM that's called CONS-stream. 279 00:15:25,690 --> 00:15:28,112 CONS-STREAM把两个事物放在一起 CONS-stream is going to put two things together 280 00:15:28,592 --> 00:15:30,220 构造出一个流 to form a thing called a stream. 281 00:15:32,040 --> 00:15:33,856 选择函数叫作HEAD And then to extract things from the stream, 282 00:15:33,984 --> 00:15:36,112 用于从流中提取数据 we're going to have a selector called the head of the stream. 283 00:15:38,010 --> 00:15:38,864 如果我有一个流 So if I have a stream, 284 00:15:39,008 --> 00:15:40,416 我可以取它的头部 I can take its head 285 00:15:41,136 --> 00:15:42,384 也可以取它的尾部 or I can take its tail. 286 00:15:44,720 --> 00:15:47,424 我把和George的约定告诉你 And remember, I have to tell you George's contract 287 00:15:48,240 --> 00:15:52,704 让你们知道和这个相关的公理 to tell you what the axioms are that relate these. 288 00:15:53,440 --> 00:16:00,176 对于任何的X与Y And it's going to be for any x and y, 289 00:16:03,408 --> 00:16:05,440 如果我把它们构造成一个流 并取其头部 if I form the CONS-stream and take the head, 290 00:16:05,696 --> 00:16:11,968 (HEAD (CONS-STREAM X Y)) the head of CONS-stream of x and y 291 00:16:13,296 --> 00:16:14,528 结果就是X is going to be x 292 00:16:16,144 --> 00:16:27,456 (TAIL (CONS-STREAM X Y)) = Y and the tail of CONS-stream of x and y is going to be y. 293 00:16:28,440 --> 00:16:34,750 一个构造函数 两个选择函数 一个公理 就是这些 So those are the constructor, two selectors for streams, and an axiom. 294 00:16:34,750 --> 00:16:35,856 这里有点可疑 There's something fishy here. 295 00:16:36,980 --> 00:16:39,008 你可能注意到了 So you might notice that these are exactly 296 00:16:40,192 --> 00:16:42,080 这些就是CONS、CAR和CDR的公理 the axioms for CONS, CAR, and CDR. 297 00:16:43,632 --> 00:16:46,560 把CONS-STREAM换成CONS So if I said instead of writing CONS-stream I wrote CONS 298 00:16:47,104 --> 00:16:49,808 HEAD换成CAR TAIL换成CDR and I said head was the CAR and tail was the CDR, 299 00:16:50,768 --> 00:16:52,810 这些就是序对的公理 those are exactly the axioms for pairs. 300 00:16:52,810 --> 00:16:54,320 事实上 还有另一个东西 And in fact, there's another thing here. 301 00:16:55,130 --> 00:16:56,800 我们有一个叫THE-EMPTY-STREAM(空流)的东西 We're going to have a thing called the-empty-stream 302 00:17:02,800 --> 00:17:04,048 像空表一样 which is like the-empty-list. 303 00:17:08,319 --> 00:17:10,030 为什么我要引入这个术语呢? So why am I introducing this terminology? 304 00:17:10,030 --> 00:17:12,128 为什么我不继续使用序对与表呢? Why don't I just keep talking about pairs and lists? 305 00:17:12,780 --> 00:17:13,792 后面我们就知道了 Well, we'll see. 306 00:17:15,510 --> 00:17:18,240 暂时地 你们可以把术语“流” For now, if you like, why don't you just pretend 307 00:17:18,304 --> 00:17:21,560 当作“表”的另一种说法 that streams really are just a terminology for lists. 308 00:17:21,560 --> 00:17:22,992 一会儿我们就会知道 为什么 And we'll see in a little while why 309 00:17:23,616 --> 00:17:26,096 为什么我们需要这个额外的抽象层 why we want to keep this extra abstraction layer 310 00:17:26,832 --> 00:17:28,150 而不是继续把它看做表 and not just call them lists. 311 00:17:32,300 --> 00:17:33,728 好的 有了流之后 OK, now that we have streams, 312 00:17:33,744 --> 00:17:35,856 我们就开始构建语言的部件了 we can start constructing the pieces of the language 313 00:17:37,040 --> 00:17:38,176 用它来操作流 to operate on streams. 314 00:17:38,752 --> 00:17:42,120 我们可以构建出太多有用的东西了 And there are a whole bunch of very useful things that we could start making. 315 00:17:42,120 --> 00:17:42,816 举例来说 For instance, 316 00:17:44,890 --> 00:17:49,792 我们构建MAP-STREAM 它的一个参数是流S we'll make our map box to take a stream, s, 317 00:17:54,800 --> 00:17:56,624 以及一个过程 and a procedure, 318 00:17:57,808 --> 00:17:59,216 它会生成一个新的流 and to generate a new stream 319 00:18:00,140 --> 00:18:02,288 它的构成元素是 which has as its elements 320 00:18:02,288 --> 00:18:04,880 将PROC应用到S的后续元素得到的结果 the procedure applied to all the successive elements of s. 321 00:18:05,872 --> 00:18:07,400 我们以前见过类似的 In fact, we've seen this before. 322 00:18:07,400 --> 00:18:10,240 就是以前在表上定义的MAP过程 This is the procedure map that we did with lists. 323 00:18:10,950 --> 00:18:12,608 除了判断EMPTY-STREAM的部分 And you see it's exactly map, 324 00:18:12,608 --> 00:18:14,650 完全就和MAP一样 except we're testing for empty-stream. 325 00:18:14,650 --> 00:18:15,560 哦 我忘了说了 Oh, I forgot to mention that. 326 00:18:15,560 --> 00:18:17,152 EMPTY-STREAM?就和NULL?差不多 Empty-stream is like the null test. 327 00:18:18,030 --> 00:18:20,480 如果是空的 就返回一个空的流 So if it's empty, we generate the empty stream. 328 00:18:20,510 --> 00:18:22,288 否则 就生成一个新的流 Otherwise, we form a new stream 329 00:18:23,520 --> 00:18:27,184 其第一个元素是PROC应用在流头部的结果 whose first element is the procedure applied to the head of the stream, 330 00:18:28,512 --> 00:18:29,328 剩下的是 and whose rest 331 00:18:29,600 --> 00:18:32,432 是MAP-STREAM对流尾部应用的结果 is gotten by mapping along with the procedure down the tail of the stream. 332 00:18:33,140 --> 00:18:35,904 太像我们之前讲的MAP了 So that looks exactly like the map procedure we looked at before. 333 00:18:37,030 --> 00:18:38,208 还有一个有用的函数 Here's another useful thing. 334 00:18:38,350 --> 00:18:40,460 过滤函数 就是那个用来过滤的盒子 Filter, this is our filter box. 335 00:18:40,460 --> 00:18:43,890 以一个谓词和一个流作为参数 We're going to have a predicate and a stream. 336 00:18:43,890 --> 00:18:45,088 它将生成一个新的流 We're going to make a new stream 337 00:18:45,808 --> 00:18:48,176 包含了在流S中所有 consists of all the elements of the original one that satisfy the predicate. 338 00:18:48,336 --> 00:18:49,488 满足谓词PRED的元素 that satisfy the predicate. 339 00:18:50,384 --> 00:18:51,312 这是一个“按条件分析语句” That's case analysis. 340 00:18:51,320 --> 00:18:52,736 如果流是空的 When there's nothing in the stream, 341 00:18:53,040 --> 00:18:54,220 就返回一个空流 we return the empty stream. 342 00:18:56,280 --> 00:18:59,184 这里 用谓词来判断流的头元素 We test the predicate on the head of the stream. 343 00:19:00,060 --> 00:19:01,040 如果为真 And if it's true, 344 00:19:01,530 --> 00:19:02,832 就把这个元素 we add the head of the stream onto the result 345 00:19:03,024 --> 00:19:06,220 和过滤流的尾元素得到的结果连接在一起 the result of filtering the tail of the stream. 346 00:19:08,220 --> 00:19:10,048 否则 如果谓词判断为假 And otherwise, if that predicate was false, 347 00:19:10,496 --> 00:19:11,984 就只返回过滤流的尾元素的结果 we just filter the tail of the stream. 348 00:19:13,500 --> 00:19:14,464 这就是过滤函数的原理 Right, so there's filter. 349 00:19:16,595 --> 00:19:18,560 剩下的我快速过一遍 Let me run through a couple more rather quickly. 350 00:19:18,560 --> 00:19:20,704 这些在书上都有 你们可以自己看 They're all in the book and you can look at them. 351 00:19:20,880 --> 00:19:21,808 来马上过一遍 Let me just flash through. 352 00:19:22,110 --> 00:19:22,944 过程ACCUMULATE Here's accumulate. 353 00:19:23,260 --> 00:19:26,928 ACCUMULATE的参数有:一个组合函数 Accumulate takes a way of combining things 354 00:19:27,360 --> 00:19:29,056 一个初始值和一个流 an initial value in a stream 355 00:19:29,968 --> 00:19:31,136 将它们组合在一起 and sticks them all together. 356 00:19:31,560 --> 00:19:33,696 如果流为空 返回初始值 If the stream's empty, it's just the initial value. 357 00:19:33,970 --> 00:19:36,208 否则 我们就把流头部 Otherwise, we combine the head of the stream 358 00:19:36,320 --> 00:19:37,824 和流尾部做ACCUMLATE的结果 with the result of accumulating 359 00:19:38,016 --> 00:19:40,240 组合起来 the tail of the stream starting from the initial value. 360 00:19:40,900 --> 00:19:42,830 这就是把流中元素累积在一起的方法 So that's what I'd use to add up everything in the stream. 361 00:19:42,830 --> 00:19:43,984 我会用加法来累积 I'd accumulate with plus. 362 00:19:45,830 --> 00:19:47,568 如何枚举树上的叶节点呢? How would I enumerate the leaves of a tree? 363 00:19:48,060 --> 00:19:52,896 如果这个树只是一个叶节点 Well, if the tree is just a leaf itself, 364 00:19:53,792 --> 00:19:55,904 我就构造一个只含有一个叶子节点的流 I make something which only has that node in it. 365 00:19:56,640 --> 00:19:59,328 否则的话 我就把 Otherwise, I append together the stuff of enumerating 366 00:19:59,616 --> 00:20:02,352 左、右子树枚举的结果合并起来 the left branch and the right branch. 367 00:20:04,340 --> 00:20:08,320 这里的APPEND-STREAM跟表上的APPEND类似 And then append here is like the ordinary append on lists. 368 00:20:13,190 --> 00:20:13,850 再来看这个 You can look at that. 369 00:20:13,850 --> 00:20:17,536 这跟和合并两个表的过程太相似了 That's analogous to the ordinary procedure for appending two lists. 370 00:20:18,912 --> 00:20:20,608 如何枚举一个区间呢? Ah... How would I enumerate an interval? 371 00:20:21,968 --> 00:20:23,776 它有两个参数 LOW和HIGH This will take two integers, low and high, 372 00:20:23,880 --> 00:20:27,008 生成一个包含从LOW到HIGH的所有整数的流 and generate a stream of the integers going from low to high. 373 00:20:28,320 --> 00:20:29,888 由此 我们就可以构造一大堆的元件 And we can make a whole bunch of pieces. 374 00:20:31,890 --> 00:20:34,480 这就是一门用来讨论流的小型语言 So that's a little language of talking about streams. 375 00:20:34,490 --> 00:20:35,328 当我们有了流 Once we have streams, 376 00:20:35,328 --> 00:20:37,670 就可以构建用于操作它们的过程 we can build things for manipulating them. 377 00:20:37,670 --> 00:20:39,040 请注意 我们正在构建一门语言 Again, we're making a language. 378 00:20:40,200 --> 00:20:42,224 现在 我们可以用这门语言来表达我们的想法 And now we can start expressing things in this language. 379 00:20:43,060 --> 00:20:47,310 这个原始过程是累加树中奇数的平方的 Here's our original procedure for summing the odd squares in a tree. 380 00:20:47,310 --> 00:20:52,624 现在你会发现 它和那些方块图如出一辙 And you'll notice it looks exactly now like the block diagram, 381 00:20:52,640 --> 00:20:54,590 跟我们的信号处理方块图相吻合 like the signal processing block diagram. 382 00:20:54,590 --> 00:20:57,536 要计算树上奇数平方和 So to sum the odd squares in a tree, 383 00:20:58,064 --> 00:21:00,800 先枚举树上的叶子节点 we enumerate the leaves of the tree. 384 00:21:01,320 --> 00:21:03,728 过滤出奇数 We filter that for oddness. 385 00:21:04,830 --> 00:21:06,544 再用平方来做映射 We map that for squareness. 386 00:21:09,320 --> 00:21:13,344 最后用加法来累积 初始值是0 And we accumulate the result of that using addition, starting from 0. 387 00:21:14,760 --> 00:21:17,200 这样我们就可以看到需要的片段 So we can see the pieces that we wanted. 388 00:21:17,290 --> 00:21:19,360 类似地 斐波那契数的那个问题 Similarly, the Fibonacci one, 389 00:21:20,048 --> 00:21:21,888 我们如何获得奇斐波那契数呢? how do we get the odd Fibs? 390 00:21:22,050 --> 00:21:24,576 从1到N枚举整数 Well, we enumerate the interval from 1 to n, 391 00:21:26,320 --> 00:21:28,640 再把FIB过程映射到上面 we map along that, 392 00:21:28,992 --> 00:21:30,704 用来求取每项斐波那契数 computing the Fibonacci of each one. 393 00:21:30,920 --> 00:21:33,792 过滤出奇数的部分 We filter the result of those for oddness. 394 00:21:34,810 --> 00:21:36,640 最后 以空表为初始值 And we accumulate all of that stuff 395 00:21:36,880 --> 00:21:39,120 用CONS将它们积累起来 using CONS starting from the empty-list. 396 00:21:43,650 --> 00:21:47,536 那么 这么做有什么优势呢? OK, what's the advantage of this? 397 00:21:47,680 --> 00:21:48,592 首先一点 Well, for one thing, 398 00:21:48,688 --> 00:21:51,152 我们现在有可以用来混搭的元件了 we now have pieces that we can start mixing and matching. 399 00:21:51,880 --> 00:21:52,640 比如说 So for instance, 400 00:21:52,912 --> 00:21:55,088 如果我想把这里改变一下 if I wanted to change this, if I wanted to ah... 401 00:21:58,192 --> 00:22:00,320 想要计算整数的平方再进行过滤 compute the squares of the integers and then filter them, 402 00:22:00,336 --> 00:22:01,344 我只需要 all I need to do 403 00:22:01,904 --> 00:22:03,648 拿个像这里的MAP SQUARE这样的元件 is pick up a standard piece like this 404 00:22:03,680 --> 00:22:05,408 放进去就行了 it's a map square and put it in. 405 00:22:06,576 --> 00:22:07,600 又或者 如果我们想 Or if we wanted to do 406 00:22:07,690 --> 00:22:11,456 寻找树的叶节点对应的斐波那契数 this whole Fibonacci computation on the leaves of a tree 407 00:22:11,584 --> 00:22:12,360 而不是一个序列所对应的 rather than a sequence, 408 00:22:12,384 --> 00:22:13,248 我只需要 all I need to do 409 00:22:13,408 --> 00:22:15,936 用这个枚举函数替换这个枚举函数 is replace this enumerator with that one. 410 00:22:18,030 --> 00:22:19,824 看到了吧 流处理的优势就是 See, the advantage of this stream processing 411 00:22:20,240 --> 00:22:21,536 我们建立了 -- is that we're establishing-- 412 00:22:22,368 --> 00:22:24,960 这也是本课中的一个重要主题 -- this is one of the big themes of the course-- 413 00:22:25,296 --> 00:22:27,488 我们建立了一个约定的接口 we're establishing conventional interfaces 414 00:22:32,896 --> 00:22:37,152 约定的接口可以让我们把事物粘合起来 conventional interfaces that allow us to glue things together. 415 00:22:38,304 --> 00:22:39,552 像MAP和FILTER这样的东西 Things like map and filter 416 00:22:39,792 --> 00:22:41,648 可以作为一组标准的组件 are a standard set of components 417 00:22:41,680 --> 00:22:44,768 我们可以拿过来随意组合去构造程序 that we can start using for pasting together programs in all sorts of ways. 418 00:22:45,750 --> 00:22:48,816 它让我们看到了程序的共性 It allows us to see the commonality of programs. 419 00:22:49,950 --> 00:22:50,928 虽然在这里 I just ought to mention, 420 00:22:51,088 --> 00:22:53,070 我只是给你们演示了两个过程而已 I've only showed you two procedures. 421 00:22:53,860 --> 00:22:55,168 但是我要告诉你 But let me emphasize 422 00:22:55,200 --> 00:22:57,776 像这种用MAP、FILTER和ACCUMULATE that this way of putting things together 423 00:22:57,808 --> 00:23:01,008 组合起来构建程序的方式是非常非常通用的 with maps, filters, and accumulators is very, very general. 424 00:23:01,410 --> 00:23:07,280 这是一种“生成-测试”的编程范式 It's the generate and test paradigm for programs. 425 00:23:07,770 --> 00:23:09,104 举例来看 And as an example of that, 426 00:23:09,392 --> 00:23:12,940 Richarc Waters -- MIT的一名硕士生 Richard Waters, who was at MIT when he was a graduate student, 427 00:23:12,960 --> 00:23:15,264 他的学位论文的一部分调研了 as part of his thesis research went and analyzed 428 00:23:15,808 --> 00:23:19,210 IBM的科学计算程序库的主要代码 a large chunk of the IBM scientific subroutine library, 429 00:23:19,824 --> 00:23:23,312 发现其中60%的程序 and discovered that about 60% of the programs in it 430 00:23:24,064 --> 00:23:28,256 都可以用这样的范式来准确的表示出来 could be expressed exactly in terms using no more than what we've put here-- 431 00:23:28,864 --> 00:23:30,176 只用MAP、FILTER和ACCUMULATE map, filter, and accumulate. 432 00:23:30,576 --> 00:23:31,504 好 让我们休息一会 All right, let's take a break. 433 00:23:36,592 --> 00:23:37,120 有问题吗? Questions? 434 00:23:41,184 --> 00:23:42,896 学生:整件事情的本质好像只是 AUDIENCE: It seems like the essence of this whole thing 435 00:23:42,896 --> 00:23:45,968 因为你用了一个统一、简单的数据结构 is just that you have a very uniform, simple data structure 436 00:23:46,256 --> 00:23:47,664 也就是流 to work with, the stream. 437 00:23:48,380 --> 00:23:48,920 教授:对 PROFESSOR: Right. 438 00:23:48,920 --> 00:23:50,384 本质就是 The essence is that you, again, 439 00:23:50,400 --> 00:23:53,070 用这种约定的接口 it's this sense of conventional interfaces. 440 00:23:53,710 --> 00:23:55,610 因此你可以把许多东西组合起来 So you can start putting a lot of things together. 441 00:23:56,010 --> 00:23:58,784 流只是 就像你说的 And the stream is as you say, 442 00:23:58,784 --> 00:24:00,890 只是一种可以支持那样操作的统一的数据结构而已 the uniform data structure that supports that. 443 00:24:00,890 --> 00:24:02,848 顺便说下 这非常像APL This is very much like APL, by the way. 444 00:24:03,600 --> 00:24:05,216 APL有着非常相似的思想 APL is very much the same idea, 445 00:24:05,216 --> 00:24:06,960 只是在APL中使用的不是流 except in APL, instead of this stream, 446 00:24:07,136 --> 00:24:08,448 而是使用数组和向量 you have arrays and vectors. 447 00:24:09,560 --> 00:24:14,480 而且APL的威力就在于此 And a lot of the power of APL is exactly the same reason of the power of this. 448 00:24:19,910 --> 00:24:20,910 好吧 谢谢 OK, thank you. 449 00:24:20,910 --> 00:24:21,664 休息一下 Let's take a break. 450 00:24:21,660 --> 00:24:30,352 [音乐] [JESU, JOY OF MAN'S DESIRING] 451 00:24:30,440 --> 00:24:35,776 《计算机程序的构造和解释》 452 00:24:41,000 --> 00:24:45,392 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 453 00:24:45,420 --> 00:24:47,960 《计算机程序的构造和解释》 454 00:24:47,980 --> 00:24:52,700 流 I 455 00:24:57,470 --> 00:24:57,610 好的 All right. 456 00:24:57,610 --> 00:24:58,592 我们已经见识过了 We've been looking at 457 00:25:00,544 --> 00:25:03,200 如何用流来组织计算过程 at ways of organizing computations using streams. 458 00:25:03,856 --> 00:25:05,472 但是现在我想要给你们再演示两个 But what I want to do now is just show you two 459 00:25:05,936 --> 00:25:09,120 更复杂的例子 somewhat more complicated examples of that. 460 00:25:10,848 --> 00:25:14,128 我们先来考虑一下 Let's start by thinking about the following 461 00:25:14,208 --> 00:25:16,810 这样一种有用的过程 kind of utility procedure that will come in useful. 462 00:25:16,810 --> 00:25:18,096 假设我有一个流 Suppose I've got a stream. 463 00:25:19,960 --> 00:25:23,152 流中的元素本身就是一个流 And the elements of this stream are themselves streams. 464 00:25:23,984 --> 00:25:26,530 一开始是1、2、3 So the first thing might be 1, 2, 3. 465 00:25:32,720 --> 00:25:33,880 就是这样的一个流 So I've got a stream. 466 00:25:33,880 --> 00:25:40,100 流中的元素也是一个流 And each element of the stream is itself a stream. 467 00:25:40,976 --> 00:25:43,424 而我想要构建出一个流 And what I'd like to do is build a stream 468 00:25:43,648 --> 00:25:46,752 用来收集所有的元素 that sort of collects together all of the elements, 469 00:25:46,768 --> 00:25:49,248 把所有元素从子流中提取出来 pulls all of the elements out of these sub-streams 470 00:25:50,112 --> 00:25:51,824 最后把它们串接在一起 and strings them all together in one thing. 471 00:25:52,272 --> 00:25:55,616 为了凸显使用这门语言多么简单 So just to show you the use of this language, how easy it is, 472 00:25:56,112 --> 00:25:57,104 我们来定义这个FLATTEN过程 call that flatten. 473 00:25:57,950 --> 00:26:10,640 FLATTEN过程的参数是由流构成的流 And I can define to flatten this stream of streams. 474 00:26:12,896 --> 00:26:13,808 那么 具体定义是怎样的呢? Well, what is that? 475 00:26:13,960 --> 00:26:16,240 它只是一个累积 That's just an accumulation. 476 00:26:16,320 --> 00:26:25,056 我想用APPEND来做累积 I want to accumulate using append, 477 00:26:25,072 --> 00:26:26,450 也就是不断地做APPEND by successively appending. 478 00:26:26,736 --> 00:26:29,296 所以我用APPEND-STREAM做累积 So I accumulate using append streams, 479 00:26:35,900 --> 00:26:48,208 以THE-EMPTY-STREAM为初始值 累积这个流 starting with the-empty-stream down that stream of streams. 480 00:26:54,840 --> 00:26:55,840 这个例子告诉我们 OK, so there's an example of 481 00:26:56,928 --> 00:26:59,232 你可以使用这些高阶过程 how you can start using these higher order things 482 00:26:59,600 --> 00:27:00,830 来做一些有趣的运算 to do some interesting operations. 483 00:27:00,830 --> 00:27:05,100 事实上 我还想定义另一个实用过程 In fact, there's another useful thing that I want to do. 484 00:27:05,100 --> 00:27:07,056 定义一个过程FLAT-MAP I want to define a procedure called flat-map, 485 00:27:17,184 --> 00:27:20,592 它以一个过程和一个流为参数 flat map of some function and a stream. 486 00:27:21,840 --> 00:27:25,720 其中S是一个流 And what this is going to do is s will be a stream of elements. 487 00:27:25,720 --> 00:27:27,696 F是一个过程 f is going to be a function 488 00:27:27,728 --> 00:27:30,624 它作用于流中的每个元素 并产生一个新的流 for each element in the stream produces another stream. 489 00:27:31,950 --> 00:27:34,528 我想从这些流中取出所有的元素 And what I want to do is take all of the elements and all of those streams 490 00:27:35,008 --> 00:27:36,000 并把它们组合在一起 and combine them together. 491 00:27:36,000 --> 00:27:49,136 所以对应的代码就是 (FLATTEN (MAP F S)) So that's just going to be the flatten of map f down s. 492 00:27:51,200 --> 00:27:53,040 每当我将F应用在S的某个元素上 Each time I apply f to an element of s, 493 00:27:53,056 --> 00:27:53,850 我得到了一个流 I get a stream. 494 00:27:54,290 --> 00:27:55,248 执行完这条MAP语句后 If I map it all the way down, 495 00:27:55,248 --> 00:27:56,272 我得到了一个由流构成的流 I get a stream of streams, 496 00:27:56,464 --> 00:27:57,424 再把它进行FLATTEN and I'll flatten that. 497 00:27:58,670 --> 00:28:02,640 我想再使用这种方式 Well, I want to use that to show you a 498 00:28:03,872 --> 00:28:05,840 来解决另一个大家很熟悉的问题 a new way to do a familiar kind of problem. 499 00:28:06,512 --> 00:28:12,272 这个问题和我们以前遇到过的许多问题一样 The problem's going to be like a lot of problems you've seen, 500 00:28:12,288 --> 00:28:13,968 只是有些变型 although maybe not this particular one. 501 00:28:14,190 --> 00:28:15,490 给定整数N I'm going to give you an integer, n. 502 00:28:18,680 --> 00:28:19,936 我们的问题是 And the problem is going to be 503 00:28:21,200 --> 00:28:31,536 找出所有的整数序对(I, J) find all pairs and integers i and j, 504 00:28:32,300 --> 00:28:39,968 其中 0 < J < I <= N between 0 and i, with j less than i, up to n, 505 00:28:42,336 --> 00:28:52,032 使得 I+J 是一个质数 such that i plus j is prime. 506 00:28:55,740 --> 00:28:57,920 如果N=6 So for example, if n equals 6, 507 00:28:59,744 --> 00:29:00,784 我在这儿画个小表格 let's make a little table here, 508 00:29:01,552 --> 00:29:06,672 表头是I、J和I+J i and j and i plus j. 509 00:29:09,700 --> 00:29:14,912 比如说I=2 J=1 那么I+J就是3 So for, say, i equals 2 and j equals 1, I'd get 3. 510 00:29:15,520 --> 00:29:20,384 然后I=3 J=2 那么I+J就是5 And for i equals 3, I could have j equals 2, and that would be 5. 511 00:29:21,210 --> 00:29:26,512 I=4 J=1 I+J=5也是一样的 等等 And 4 and 1 would be 5 and so on, 512 00:29:26,928 --> 00:29:28,112 直到I到了6就终止了 up until i goes to 6. 513 00:29:28,400 --> 00:29:32,544 我想要这个过程产生并返回这样的一个流 And what I'd like to return is to produce a stream 514 00:29:33,200 --> 00:29:37,040 就是像 (I, J, I+J) 这样的三元组组成的流 all the triples like this, let's say i, j, and i plus j. 515 00:29:37,664 --> 00:29:39,552 对于每个整数N 我想得到一个这样流 So for each n, I want to generate this stream. 516 00:29:40,976 --> 00:29:43,680 听起来很简单 OK, well, that's easy. 517 00:29:43,680 --> 00:29:44,352 我们做做看 Let's build it up. 518 00:29:47,230 --> 00:29:48,224 先这样开始 We start like this. 519 00:29:50,150 --> 00:29:54,256 对于每一个整数 I We're going to say for each i, for each i 520 00:29:55,248 --> 00:29:56,440 生成一个流 we're going to generate a stream. 521 00:29:57,000 --> 00:29:58,592 对于I从1取到N For each i in the interval 1 through n, 522 00:29:58,592 --> 00:29:59,760 每个I都生成一个流 we're going to generate a stream. 523 00:30:00,660 --> 00:30:01,808 这个流将会是什么样子? What's that stream going to be? 524 00:30:02,230 --> 00:30:04,048 我们先生成所有的序对 We're going to start by generating all the pairs. 525 00:30:04,180 --> 00:30:07,552 对于每个I 我们先生成 So for each i, we're going to generate, 526 00:30:08,432 --> 00:30:14,528 对于每个从1取到I-1的J for each j in the interval 1 to i minus 1, 527 00:30:16,912 --> 00:30:17,984 我们先生成序对 we'll generate the pair, 528 00:30:18,352 --> 00:30:20,710 也就是只含有I和J的表 or the list with two elements i and j. 529 00:30:23,780 --> 00:30:27,104 因此我们对整个区间做映射 So we map along the interval, 530 00:30:28,608 --> 00:30:29,744 生成序对 generating the pairs. 531 00:30:31,072 --> 00:30:33,170 对于每个I 都生成一个序对流 And for each i, that generates a stream of pairs. 532 00:30:33,408 --> 00:30:34,496 最后进行FLATMAP And we flatmap it. 533 00:30:34,590 --> 00:30:36,208 这样我们就生成了所有的(I, J)序对 Now we have all the pairs i and j, 534 00:30:36,816 --> 00:30:38,080 其中I <= J such that i is less than j. 535 00:30:38,730 --> 00:30:39,850 就是这样 So that builds that. 536 00:30:39,850 --> 00:30:40,768 紧接着就是过滤 Now we're got to test them. 537 00:30:42,990 --> 00:30:45,840 我们对刚才FLATMAP得到的东西 Well, we take that thing we just built, the flatmap, 538 00:30:46,944 --> 00:30:51,376 我们以I -- 这里分别是 I 和 J and we filter it to see whether the i-- see, we had an i and a j. 539 00:30:51,660 --> 00:30:54,176 I是表的第一个元素 i was the first thing in the list, 540 00:30:54,304 --> 00:30:55,600 J是第二个 j was the second thing in the list. 541 00:30:57,216 --> 00:31:00,010 我们用一个谓词来判断 表中的两个元素 So we have a predicate which says in that list of two elements 542 00:31:00,224 --> 00:31:02,000 也就是表的CAR部分与CDR部分之和 是否为质数 is the sum of the CAR and the CDR prime. 543 00:31:02,070 --> 00:31:05,520 用这个谓词来过滤刚刚收集起来的表 And we filter that collection of pairs we just built. 544 00:31:06,540 --> 00:31:07,856 就得到了我们想要的表 So those are the pairs we want. 545 00:31:09,420 --> 00:31:10,240 然后我们继续 Now we go ahead 546 00:31:10,880 --> 00:31:13,104 把过滤得到的结果 再次进行MAP操作 Now we go ahead and we take the result of that filter 547 00:31:13,264 --> 00:31:19,056 用来生成 I、J 和 I+J 构成的表 we map along it, generating the list i and j and i plus j. 548 00:31:19,610 --> 00:31:21,392 这就是过程 PRIME-SUM-PAIRS And that's our procedure prime-sum-pairs. 549 00:31:22,570 --> 00:31:24,768 最后只需要过一遍 这就是整个过程 Ok, and then just to flash it up, here's the whole procedure. 550 00:31:28,080 --> 00:31:30,976 一个MAP、一个FILTER 以及一个FLATMAP A map, a filter, a flatmap. 551 00:31:34,850 --> 00:31:35,664 所有的东西都在这里了 There's the whole thing, 552 00:31:35,664 --> 00:31:37,120 尽管可读性不是那么好 even though this isn't particularly readable. 553 00:31:37,424 --> 00:31:38,944 我们只是把中间过程展开了 It's just expanding that flatmap. 554 00:31:39,840 --> 00:31:40,880 这个例子 So there's an example 555 00:31:43,280 --> 00:31:45,008 向我们展示了 which illustrates the general point 556 00:31:45,120 --> 00:31:46,304 嵌套循环 that nested loops 557 00:31:47,660 --> 00:31:50,096 在这个过程中 它看起来就像 in this procedure start looking like compositions of 558 00:31:50,112 --> 00:31:52,810 各种嵌套的MAP和FLATMAP的组合 flatmaps of flatmaps of flatmaps of maps and things. 559 00:31:54,272 --> 00:31:57,616 所以我们不仅仅可以枚举单个个体 So not only can we enumerate individual things, 560 00:31:57,616 --> 00:31:58,816 通过使用FLATMAP but by using flatmaps, 561 00:31:59,120 --> 00:32:02,240 我们可以实现其它语言中的嵌套循环 we can do what would correspond to nested loops in most other languages. 562 00:32:03,230 --> 00:32:03,760 当然 Of course, 563 00:32:04,912 --> 00:32:08,032 重复写这些FLATMAP很烦人 it's pretty awful to keep writing these flatmaps of flatmaps of flatmaps. 564 00:32:08,410 --> 00:32:13,008 尽管PRIME-SUM-PAIRS其中单独的部分很容易 Prime-sum-pairs you saw looked fairly complicated, 565 00:32:13,568 --> 00:32:15,280 但整体看起来还是十分复杂 even though the individual pieces were easy. 566 00:32:15,480 --> 00:32:17,136 如果你愿意的话 可以 So what you can do, if you like, 567 00:32:17,152 --> 00:32:20,128 引进一个叫COLLECT的语法糖衣 is introduced some syntactic sugar that's called collect. 568 00:32:21,040 --> 00:32:22,688 COLLECT只是一个缩写 And collect is just an abbreviation 569 00:32:22,912 --> 00:32:26,160 用来代表特定顺序的FLATMAP和FILTER操作 for that nest of flatmaps and filters arranged in that particular way. 570 00:32:26,160 --> 00:32:28,608 这里我们用COLLECT把PRIME-SUM-PAIRS写一遍 Here's prime-sum-pairs again, written using collect. 571 00:32:29,450 --> 00:32:36,272 PRIME-SUM-PAIRS过程需要收集这样一个东西 It says to find all those pairs, I'm going to collect together a result, 572 00:32:36,528 --> 00:32:39,200 它的元素是形如(I, J, I+J)这样的表 which is the list i, j, and i plus j, 573 00:32:40,848 --> 00:32:45,392 而这将通过I从1取到N that's going to be generated as i runs through the interval from 1 to n 574 00:32:47,440 --> 00:32:52,320 同时J要从1取到I-1来产生 and as j runs through the interval from 1 to i minus 1 575 00:32:54,160 --> 00:32:56,544 并且要满足I+J是质数 such that i plus j is prime. 576 00:32:58,040 --> 00:33:00,320 课堂上我就不讲解如何定义COLLECT了 So I'm not going to say what collect does in general. 577 00:33:00,690 --> 00:33:02,752 书上面有 You can look at that by looking at it in the book. 578 00:33:03,420 --> 00:33:05,456 不过你可以清楚地看到 这些代码片段 But pretty much, you can see that the pieces of this 579 00:33:05,840 --> 00:33:08,608 就是我原先写的过程中的片段 are the pieces of that original procedure I wrote. 580 00:33:08,820 --> 00:33:11,408 COLLECT过程只是一个语法糖衣 And this collect is just some syntactic sugar 581 00:33:11,440 --> 00:33:14,800 用来自动生成嵌套FLATMAP for automatically generating that nest of flatmaps and flatmaps. 582 00:33:16,310 --> 00:33:20,336 好的 我们再来看另一个例子 OK, well, let me do one more example 583 00:33:20,672 --> 00:33:22,000 也展示了同样的道理 that shows you the same kind of thing. 584 00:33:22,120 --> 00:33:23,536 这是一个非常著名的问题 Here's a very famous problem 585 00:33:24,704 --> 00:33:28,752 经常用来演示所谓的“回溯”算法 that's used to illustrate a lot of so-called backtracking computer algorithms 586 00:33:28,768 --> 00:33:30,200 这就是“八皇后问题” This is the eight queens problem. 587 00:33:30,200 --> 00:33:31,088 这是一个棋盘 This is a chess board. 588 00:33:32,370 --> 00:33:33,648 八皇后问题要求我们 And the eight queens problem says, 589 00:33:33,648 --> 00:33:35,856 找到一种将八个皇后放到棋盘上的摆法 find a way to put down eight queens on a chess board 590 00:33:36,448 --> 00:33:38,000 使得任意的两个皇后不会相互攻击 so that no two are attacking each other. 591 00:33:38,000 --> 00:33:40,608 这里给出了一个解法 And here's a particular solution to the eight queens problem. 592 00:33:41,210 --> 00:33:43,680 我需要保证摆放好后 So I have to make sure to put down queens 593 00:33:43,712 --> 00:33:46,800 任意两个皇后不在同一行或同一列上 no two are in the same row or the same column 594 00:33:47,728 --> 00:33:49,472 也不在同一对角线上 or sit along the same diagonal. 595 00:33:51,410 --> 00:33:56,400 有一个解决这个问题的标准解法 Now, there's sort of a standard way of doing that. 596 00:33:59,740 --> 00:34:01,488 首先我们要做是 Well, first we need to do is 597 00:34:02,544 --> 00:34:04,624 进入底层 站在George的层面 below the surface, at George's level. 598 00:34:04,940 --> 00:34:08,095 找到一种表示棋盘与位置的方式 We have to find some way to represent a board, and represent positions. 599 00:34:08,090 --> 00:34:09,520 这个并不需要太担心 And we'll not worry about that. 600 00:34:09,800 --> 00:34:12,784 假设我们有一个谓词SAFE? But let's assume that there's a predicate called safe. 601 00:34:16,144 --> 00:34:17,552 SAFE?判断的是 And what safe is going to do 602 00:34:17,968 --> 00:34:20,848 假如一些皇后已经放在棋盘上 is going to say given that I have a bunch of queens down on the chess board, 603 00:34:21,360 --> 00:34:24,544 在这个点再放置一个皇后是否是安全? is it OK to put a queen in this particular spot? 604 00:34:25,400 --> 00:34:31,264 所以SAFE?的参数分别为ROW和COLUMN So safe is going to take a row and a column. 605 00:34:32,768 --> 00:34:35,472 我将尝试把下一个皇后放在那个地方 That's going to be a place where I'm going to try and put down the next queen, 606 00:34:36,064 --> 00:34:42,768 另外一个参数是剩下的位置 and the rest of positions. 607 00:34:45,584 --> 00:34:46,752 SAFE?要判断的是 And what safe will say 608 00:34:46,864 --> 00:34:51,680 在这些位置已经放置了皇后的情况下 is given that I already have queens down in these positions, 609 00:34:53,024 --> 00:34:54,768 在这行这列放置皇后 is it safe to put another queen down 610 00:34:55,104 --> 00:34:57,200 是否安全 in that row and that column? 611 00:34:58,300 --> 00:34:59,360 不用过分深究这个 And let's not worry about that. 612 00:34:59,360 --> 00:35:01,380 那是George的问题 也不难写出来 That's George's problem. and it's not hard to write. 613 00:35:01,380 --> 00:35:06,272 只需要检测该行、该列 You just have to check whether this thing contains any things 614 00:35:06,304 --> 00:35:08,528 以及对角线上是否有东西即可 on that row or that column or in that diagonal. 615 00:35:10,530 --> 00:35:13,120 那么 有了这个过程后 我们的程序该如何组织呢? Now, how would you organize the program given that? 616 00:35:13,840 --> 00:35:17,216 有一种传统的方式 And there's sort of a traditional way to organize it 617 00:35:17,936 --> 00:35:18,976 我们称为“回溯” called backtracking. 618 00:35:20,528 --> 00:35:23,216 首先让我们来考虑 And it says, well, let's start off 619 00:35:25,130 --> 00:35:28,880 把第一个皇后放在第一列的 let's think about all the ways of putting the first queen down 620 00:35:30,048 --> 00:35:31,344 所有方式 in the first column. 621 00:35:31,456 --> 00:35:32,240 有8种 There are eight ways. 622 00:35:32,580 --> 00:35:35,008 先试下第一列 Well, let's say try the first column. 623 00:35:35,880 --> 00:35:37,300 第一行第一列 Try column 1, row 1. 624 00:35:37,300 --> 00:35:38,704 每个分支都代表了 These branches are going to represent 625 00:35:40,176 --> 00:35:41,888 在每一个层次的可能解 the possibilities at each level. 626 00:35:43,360 --> 00:35:45,536 我试着把皇后放在第一列 So I'll try and put a queen down in the first column. 627 00:35:46,140 --> 00:35:47,744 现在 我在第一列放置好一个皇后以后 And now given that it's in the first column, 628 00:35:47,776 --> 00:35:49,980 我又尝试在第一列放置下一个皇后 I'll try and put the next queen down in the first column. 629 00:35:50,608 --> 00:35:52,176 并不成功 它们都…… That's no good, they're both... 630 00:35:53,310 --> 00:35:54,608 我尝试把第一个皇后 I'll try and put the first queen, 631 00:35:54,860 --> 00:35:56,800 把在第一列上的那个皇后 放在第一行 the one in the first column, down in the first row. 632 00:35:56,920 --> 00:35:57,472 不好意思 I'm sorry. 633 00:35:59,050 --> 00:36:01,390 放好后 我们再把下一个皇后放在第一行 And then given that, we'll put the next queen down in the first row. 634 00:36:01,390 --> 00:36:02,090 这不行 And that's no good. 635 00:36:02,090 --> 00:36:03,184 所以又回到这里 So I'll back up to here. 636 00:36:04,200 --> 00:36:04,720 然后再考虑 And I'll say, 637 00:36:04,832 --> 00:36:06,860 我们把这个皇后放在第二行吗? oh, can I put the first queen down in the second row? 638 00:36:07,328 --> 00:36:08,384 然而也不行 Well, that's no good. 639 00:36:08,550 --> 00:36:09,760 那么放在第三行呢? Oh, can I put it down in the third row? 640 00:36:09,760 --> 00:36:10,528 这样可以 Well, that's good. 641 00:36:12,790 --> 00:36:15,136 下一个皇后可以放在第一列吗? Well, now can I put the next queen down in the first column? 642 00:36:15,380 --> 00:36:17,824 我不能再画更多的棋盘了 Well, I can't visualize this chess board anymore, 643 00:36:17,824 --> 00:36:18,864 但我先假设这个可行 but I think that's right. 644 00:36:19,195 --> 00:36:20,450 我尝试下一个 And I try the next one. 645 00:36:20,450 --> 00:36:24,170 在每一个地方 尽可能的沿着树往下 And at each place, I go as far down this tree as I can. 646 00:36:24,544 --> 00:36:25,640 然后回退 And I back up. 647 00:36:25,640 --> 00:36:28,976 如果我从这里往下走 发现下面不可能有解 If I get down to here and find no possibilities below there, 648 00:36:29,008 --> 00:36:30,120 我就回溯到这里来 I back all the way up to here, 649 00:36:30,288 --> 00:36:32,448 然后开始生成这个子树 and now start again generating this sub-tree. 650 00:36:33,260 --> 00:36:34,320 我就像这样遍历 And I sort of walk around. 651 00:36:35,050 --> 00:36:37,264 最后 一路求解下来 And finally, if I ever manage to get all the way down, 652 00:36:37,728 --> 00:36:38,592 就会得到答案 I've found a solution. 653 00:36:39,820 --> 00:36:41,984 这种典型的范式 So that's a typical sort of 654 00:36:43,120 --> 00:36:45,930 之前被广泛地使用在人工智能编程中 paradigm that's used a lot in AI programming. 655 00:36:45,930 --> 00:36:47,300 术语叫做 “回溯搜索” It's called backtracking search. 656 00:36:57,470 --> 00:37:03,040 这真的没有必要 And it's really unnecessary. 657 00:37:03,860 --> 00:37:06,550 你们也发现了 我在可视化这个过程时也犯了迷糊 You saw me get confused when I was visualizing this thing. 658 00:37:06,816 --> 00:37:08,256 你们也看到了复杂程度 And you sort of see the complication. 659 00:37:08,550 --> 00:37:10,760 而且这种复杂还很难描述 This is a complicated thing to say. 660 00:37:10,760 --> 00:37:11,824 为什么会这样? Why is it complicated? 661 00:37:12,390 --> 00:37:13,296 这是因为 Its because somehow 662 00:37:13,530 --> 00:37:17,392 这是因为这程序过分地关注于时间了 this program is too inordinately concerned with time. 663 00:37:18,580 --> 00:37:20,432 这之中太多 -- 先试试这个 再试试这个 It's too much-- I try this one, and I try this one, 664 00:37:20,496 --> 00:37:22,380 再回到上一个可行的地方 -- 这种操作太多了 and I go back to the last possibility. 665 00:37:22,896 --> 00:37:24,340 这很复杂 And that's a complicated thing. 666 00:37:24,340 --> 00:37:26,368 如果我们不再如此关注时间 If I stop worrying about time so much, 667 00:37:28,048 --> 00:37:29,760 就有一个更简单的方式来描述 then there's a much simpler way to describe this. 668 00:37:31,200 --> 00:37:32,368 让我们来想象一下 It says, let's imagine 669 00:37:33,312 --> 00:37:36,576 现在我有 that I have in my hands 670 00:37:38,320 --> 00:37:42,160 有一个高达K-1层的树 the tree down to k minus 1 levels. 671 00:37:43,400 --> 00:37:46,320 假设我已经有了 See, suppose I had in my hands all possible ways 672 00:37:48,096 --> 00:37:52,192 把皇后放在前K列的所有解法 to solve... to put down queens in the first k columns. 673 00:37:53,560 --> 00:37:54,610 假设是这样 Suppose I just had that. 674 00:37:54,610 --> 00:37:55,792 不要担心我是怎么得到的 Let's not worry about how we get it. 675 00:37:57,070 --> 00:37:59,200 现在 如何扩充下去呢? Well, then, how do I extend that? 676 00:37:59,200 --> 00:38:02,160 怎样找到在下一列中放皇后的所有可行方法? How do I find all possible ways to put down queens in the next column? 677 00:38:02,480 --> 00:38:03,136 很简单 It's really easy. 678 00:38:03,620 --> 00:38:06,416 对于已有的位置 For each of these positions I have, 679 00:38:07,820 --> 00:38:13,968 我考虑把下一个皇后放在每一行上 I enjoin, I think about putting down a queen in each row 680 00:38:15,088 --> 00:38:16,160 来构建出下一步的棋局 to make the next thing. 681 00:38:16,160 --> 00:38:17,296 然后 把所有放置的位置 And then for each one I put down, 682 00:38:17,440 --> 00:38:19,712 用SAFE?进行过滤 I filter those by the ones that are safe. 683 00:38:21,800 --> 00:38:22,992 不像之前那样 So instead of thinking about 684 00:38:22,992 --> 00:38:24,670 把这个树看做是逐步生成的 this tree as generated step by step, 685 00:38:24,944 --> 00:38:26,860 我们假设所有的东西都生成好了 I say, suppose I had it all there. 686 00:38:29,680 --> 00:38:32,416 为了从K-1层扩展到K层 And to extend it from level k minus 1 to level k, 687 00:38:32,640 --> 00:38:36,240 我只需要扩展所有可能的放置方法 I just need to extend each thing in all possible ways 688 00:38:36,480 --> 00:38:37,800 最后保留安全的排列 and only keep the ones that are safe. 689 00:38:37,800 --> 00:38:39,232 就得到一个K层树的结果 And that will give me the tree to level k. 690 00:38:39,300 --> 00:38:40,672 这是解决八皇后问题 And that's a recursive strategy 691 00:38:40,896 --> 00:38:42,176 的一个递归策略 for solving the eight queens problem. 692 00:38:44,530 --> 00:38:45,344 好的 我们来看看 All right, well, let's look at it. 693 00:38:50,336 --> 00:38:52,688 我们编写子过程FILL-COLS To solve the eight queens problem 694 00:38:53,008 --> 00:38:55,536 来解决在一个特定大小棋盘上的 on a board of some specified size, 695 00:38:58,928 --> 00:39:01,030 八皇后问题 we write a sub-procedure called fill-columns. 696 00:39:01,136 --> 00:39:04,864 这个过程会把皇后放置到K个列中 Fill-columns is going to put down queens up through column k. 697 00:39:06,352 --> 00:39:07,700 这是递归的模式 And here's the pattern of the recursion. 698 00:39:07,700 --> 00:39:10,928 最后会以棋盘的大小为参数 调用FILL-COLS I'm going to call fill-columns with the size eventually. 699 00:39:12,990 --> 00:39:15,280 FILL-COLS是用来说明 So fill-columns says how to put down queens safely 700 00:39:15,296 --> 00:39:17,168 如何安全地把皇后放置在 safely in the first k columns of this chess board 701 00:39:17,200 --> 00:39:19,584 具有SIZE行的棋盘的前K列 with a size number of rows in it. 702 00:39:20,360 --> 00:39:21,648 如果K是0 If k is equal to 0, 703 00:39:22,272 --> 00:39:23,600 就不用做什么 well, then I don't have to put anything down. 704 00:39:23,940 --> 00:39:25,936 结果是一个空棋盘 So my solution is just an empty chess board. 705 00:39:26,710 --> 00:39:28,070 否则就做点别的 Otherwise, I'm going to do some stuff. 706 00:39:28,352 --> 00:39:29,440 这里将要使用COLLECT And I'm going to use collect. 707 00:39:30,816 --> 00:39:31,770 完整的代码在这里 And here's the collect. 708 00:39:34,336 --> 00:39:41,910 我找到了所有在前K-1列中放皇后的方法 I find all ways to put down queens in the first k minus 1 columns. 709 00:39:42,192 --> 00:39:43,320 这是我所假设的 And this was just what I set for. 710 00:39:43,320 --> 00:39:46,368 想像这棵树下降到K-1层 Imagine I have this tree down to k minus 1 levels. 711 00:39:48,880 --> 00:39:52,112 然后我尝试每一行 And then I find all ways of trying a row, 712 00:39:52,528 --> 00:39:54,130 尝试每一个可行的行 that's just each of the possible rows. 713 00:39:54,130 --> 00:39:55,040 总共SIZE行 They're size rows, 714 00:39:55,312 --> 00:39:56,496 这里枚举了所有行数 so that's enumerate interval. 715 00:39:58,040 --> 00:39:59,792 现在要做的是 And now what I do is I collect together 716 00:40:03,152 --> 00:40:05,824 把我将要尝试的新行和第K列 the new row I'm going to try and column k 717 00:40:07,952 --> 00:40:08,950 收集起来 with the rest of the queens. 718 00:40:08,950 --> 00:40:10,096 我邻接一个位置 I adjoin a position. 719 00:40:10,200 --> 00:40:11,290 这是George的问题了 This is George's problem. 720 00:40:11,290 --> 00:40:12,752 实现ADJOIN-POSITION和SAFE?都是George的工作 An adjoined position is like safe. 721 00:40:13,640 --> 00:40:15,280 这个过程需要的参数有 It's a thing that takes a row 722 00:40:15,504 --> 00:40:17,040 ROW、COL以及REST-OF-POS and a column and the rest of the positions 723 00:40:17,072 --> 00:40:19,024 然后返回位置的集合 and makes a new position collection. 724 00:40:19,660 --> 00:40:25,776 我把新的行和列 So I adjoin a position of a new row and a new column 725 00:40:26,064 --> 00:40:27,680 和剩下的皇后邻接起来 to the rest of the queens, 726 00:40:28,576 --> 00:40:29,760 那些剩下的皇后 where the rest of the queens 727 00:40:29,920 --> 00:40:31,456 会尝试所有的 runs through all possible ways 728 00:40:31,872 --> 00:40:34,160 放置在K-1列中的可行解 of solving the problem in k minus 1 columns. 729 00:40:34,620 --> 00:40:37,040 新的行遍历了所有的可能性 And the new row runs through all possible rows 730 00:40:37,856 --> 00:40:40,768 过滤出安全的位置 such that it was safe to put one there. 731 00:40:43,240 --> 00:40:44,704 这就是整个程序了 And that's the whole program. 732 00:40:46,336 --> 00:40:47,312 整个过程 There's the whole procedure. 733 00:40:49,840 --> 00:40:52,432 它不仅找到了八皇后的问题的解 Not only that, that doesn't just solve the eight queens problem, 734 00:40:53,424 --> 00:40:56,680 它还给出了所有的解 Right? It gives you all solutions to the eight queens problem. 735 00:40:56,680 --> 00:40:58,480 运行结束之后 就得到一个流 When you're done, you have a stream. 736 00:40:58,480 --> 00:41:01,900 流中的元素是所有的解 And the elements of that stream are all possible ways of solving that problem. 737 00:41:05,310 --> 00:41:06,260 为什么这个更简单一点呢? Why is that simpler? 738 00:41:06,260 --> 00:41:08,544 我们完全没有把这个当做 Well, we threw away the whole idea that 739 00:41:08,880 --> 00:41:11,520 按时间发生的、具有状态的过程 is some process that happens in time with state. 740 00:41:12,720 --> 00:41:14,420 我们只说 这是一些东西的集合 And we just said it's a whole collection of stuff. 741 00:41:14,944 --> 00:41:16,000 这是它更加简单的原因 And that's why it's simpler. 742 00:41:18,000 --> 00:41:20,110 我们已经转变了观念 Right? We've changed our view. 743 00:41:20,110 --> 00:41:22,592 还记得吗 这节课开始我们就讲过 Remember, that's where we started today. 744 00:41:22,820 --> 00:41:26,230 我们转变了建模的观念 We've changed our view of what it is we're trying to model. 745 00:41:26,230 --> 00:41:29,200 我们不再把事物看做按时间演进 we stop modeling things that evolve in time 746 00:41:29,376 --> 00:41:31,312 也不再具有不同的阶段与状态 have steps and have state. 747 00:41:31,750 --> 00:41:33,792 取而代之的是 我们对全局进行建模 And instead, we're trying to model this global thing 748 00:41:33,808 --> 00:41:35,936 我们关注粉笔的整个飞行过程 like the whole flight of the chalk, 749 00:41:36,288 --> 00:41:38,880 而不是专注于每个瞬时状态 rather than its state at each instant. 750 00:41:40,750 --> 00:41:41,440 有什么问题吗? Any questions? 751 00:41:44,080 --> 00:41:46,208 学生:在我看来回溯会 AUDIENCE: It looks to me like backtracking would be 752 00:41:46,224 --> 00:41:48,960 搜索到它所能找到的第一个解 searching for the first solution it can find, 753 00:41:49,310 --> 00:41:51,488 而这个递归搜索 whereas this recursive search 754 00:41:51,488 --> 00:41:53,260 会去寻找所有的解 would be looking for all solutions. 755 00:41:53,328 --> 00:41:53,600 教授:是这样的 PROFESSOR: Right. 756 00:41:54,030 --> 00:41:55,264 学生:但问题是 AUDIENCE: And it seems that 757 00:41:55,264 --> 00:41:57,920 如果需要搜索的空间足够的大 if you have a large enough area to search, 758 00:41:57,920 --> 00:42:00,928 第二种搜索方式就会变得不现实 that the second is going to become impossible. 759 00:42:01,360 --> 00:42:05,936 教授:呃 这个问题其实是 PROFESSOR: OK, the answer to that question 760 00:42:07,136 --> 00:42:08,448 这一节课剩下的内容 is the whole rest of this lecture. 761 00:42:08,570 --> 00:42:10,540 这个问题很好 It's exactly the right question. 762 00:42:13,872 --> 00:42:15,744 先不要尝试去预知后面的课 And without trying to anticipate the lecture too much, 763 00:42:15,968 --> 00:42:19,232 只是在现在 你们要保持谨慎 you should start being suspicious at this point, 764 00:42:19,840 --> 00:42:21,840 这里确实有点奇怪 难道不是么? and exactly those kinds of suspicions. Isn't it? 765 00:42:22,220 --> 00:42:24,512 尽管这个看起来不错 但是难道它不低效吗? It's wonderful, but isn't it so terribly inefficient? 766 00:42:24,830 --> 00:42:26,032 这是我们待会儿要解决的问题 That's where we're going. 767 00:42:28,100 --> 00:42:30,020 就让我们稍后来揭晓秘密吧 So I won't answer now, but I'll answer later. 768 00:42:33,350 --> 00:42:34,600 好吧 休息一下 OK, let's take a break. 769 00:42:34,600 --> 00:42:44,512 [音乐] [JESU, JOY OF MAN'S DESIRING] 770 00:42:44,510 --> 00:42:49,040 《计算机程序的构造和解释》 771 00:43:10,570 --> 00:43:17,056 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 772 00:43:17,050 --> 00:43:21,216 《计算机程序的构造和解释》 773 00:43:21,216 --> 00:43:25,210 流 I 774 00:43:29,650 --> 00:43:33,760 你可能现在开始怀疑了 Well, by now you should be starting to get suspicious. 775 00:43:35,600 --> 00:43:39,264 我已经展示了这种简单而优雅的 See, I've showed your this simple, elegant 776 00:43:40,512 --> 00:43:42,288 组合程序的方法 of putting programs together, 777 00:43:42,864 --> 00:43:46,912 这跟那些传统程序非常不同 very unlike these other traditional programs 778 00:43:46,920 --> 00:43:48,192 那些求奇数的平方和 that sum the odd squares 779 00:43:48,720 --> 00:43:51,320 或者求奇数项斐波那契数之类的程序 or compute the odd Fibonacci numbers. 780 00:43:53,740 --> 00:43:55,488 也不像那些混合了 Very unlike these programs that mix up 781 00:43:55,856 --> 00:43:58,848 枚举函数、过滤函数和累积函数的程序 the enumerator and the filter and the accumulator. 782 00:44:00,440 --> 00:44:01,824 通过把它们混合起来 And by mixing it up, 783 00:44:02,200 --> 00:44:04,592 通过这种混搭式的 we don't have all of these wonderful 784 00:44:04,624 --> 00:44:07,344 组合程序的方法 conceptual advantages of these streams pieces, 785 00:44:07,824 --> 00:44:09,536 我们并没有获得 these wonderful mix and match components 786 00:44:09,552 --> 00:44:11,776 流式程序设计的理论优势 for putting together lots and lots of programs. 787 00:44:13,800 --> 00:44:14,256 另一方面 On the other hand, 788 00:44:14,288 --> 00:44:16,880 你们所见过的大多数程序是那种丑陋的风格 most of the programs you've seen look like these ugly ones. 789 00:44:18,340 --> 00:44:18,944 为什么会这样? Why's that? 790 00:44:19,200 --> 00:44:20,592 难道计算机科学家们 Can it possibly be 791 00:44:21,168 --> 00:44:24,304 愚蠢得无以复加 that computer scientists are so obtuse 792 00:44:25,420 --> 00:44:26,448 以至于他们没有注意到这个现象么? that they don't notice 793 00:44:27,072 --> 00:44:28,752 如果你仅仅只是做了这些事 that if you'd merely did this thing, 794 00:44:29,632 --> 00:44:31,936 你就能让程序变得极其优雅么? then you can get this great programming elegance? 795 00:44:33,620 --> 00:44:34,784 肯定有什么缺陷 There's got to be a catch. 796 00:44:36,760 --> 00:44:39,056 事实上这一缺陷也很容易发现 And it's actually pretty easy to see what the catch is. 797 00:44:39,510 --> 00:44:41,744 我们来看看接下来的这个问题 Let's think about the following problem. 798 00:44:42,030 --> 00:44:45,472 假设我让你去找 Suppose I tell you to find the second prime 799 00:44:46,160 --> 00:44:48,160 1,000到1,000,000之间的第二个素数 between 10,000 and 1 million, 800 00:44:49,120 --> 00:44:50,560 如果你的计算机性能更强劲的话 or if your computer's larger, 801 00:44:50,592 --> 00:44:53,056 或者可以去找10,000到100,000,000之间的 say between 10,000 and 100 billion, or something. 802 00:44:54,320 --> 00:44:55,456 你可能觉得这很容易 And you say, oh, that's easy. 803 00:44:55,472 --> 00:44:56,656 我可以用流来解决 I can do that with a stream. 804 00:44:57,080 --> 00:44:59,872 我需要做的就是 All I do is I enumerate 805 00:45:00,576 --> 00:45:02,896 从10,000枚举到1,000,000 the interval from 10,000 to 1 million. 806 00:45:04,160 --> 00:45:06,512 我就获得了从10,000到1,000,000的所有整数 So I get all those integers from 10,000 to 1 million. 807 00:45:06,800 --> 00:45:08,640 我过滤出所有的质数 I filter them for prime-ness, 808 00:45:09,392 --> 00:45:11,104 也就是对这些数做素性检测 so test all of them and see if they're prime. 809 00:45:11,760 --> 00:45:12,832 然后从中取出第二个元素 And I take the second element. 810 00:45:12,848 --> 00:45:14,048 也就是 TAIL的HEAD部分 Right? That's the head of the tail. 811 00:45:15,792 --> 00:45:17,380 这显然是非常荒谬的 OK? Well, that's clearly pretty ridiculous. 812 00:45:21,660 --> 00:45:23,200 我们的机器没有这么大的空间 We'd not even have room in the machine 813 00:45:23,584 --> 00:45:25,248 来存放这些整数 Right? To store the integers in the first place, 814 00:45:25,280 --> 00:45:26,352 更别说来测试它们了 much less to test them. 815 00:45:27,040 --> 00:45:28,640 而且我也只是取第二个数而已 And then I only want the second one. 816 00:45:29,810 --> 00:45:34,944 这种传统程序设计风格的威力 See, the power of this traditional programming style 817 00:45:36,432 --> 00:45:37,680 (虽然)也正是其弱点 is exactly its weakness, 818 00:45:37,960 --> 00:45:38,944 这种程序设计风格 that we're mixing up 819 00:45:39,616 --> 00:45:43,500 混合了枚举、测试以及累积 the enumerating and the testing and the accumulating. 820 00:45:44,880 --> 00:45:46,464 我们不需要做全部的事 Right? We sort of don't do it all. 821 00:45:46,670 --> 00:45:49,184 所以说 实际上这是这种 So by the actual... so the very thing 822 00:45:49,456 --> 00:45:51,744 概念上丑陋的风格 makes it conceptually ugly 823 00:45:52,208 --> 00:45:53,808 正是让它运行起来高效 is the very thing that makes it efficient. 824 00:45:54,912 --> 00:45:55,840 就是像这样来混合 Right? It's this mixing up. 825 00:45:57,800 --> 00:45:59,344 我今天一早上所做的好像都是在 So it seems that all I've done this morning so far 826 00:45:59,344 --> 00:46:00,420 把你们搞糊涂一样 is just confuse you. 827 00:46:00,420 --> 00:46:03,104 我为你们展示了一种貌似可行的优雅程序设计方法 I showed you this wonderful way that programming might work, 828 00:46:03,104 --> 00:46:03,968 但它却不可行 except that it doesn't. 829 00:46:05,840 --> 00:46:08,320 但是 接下来就是见证奇迹的时刻 Well, here's where the wonderful thing happens. 830 00:46:09,040 --> 00:46:10,576 结果却是 这个游戏里 It turns out in this game 831 00:46:11,216 --> 00:46:13,840 我们真的可以得到蛋糕并吃掉它 that we really can have our cake and eat it too. 832 00:46:14,870 --> 00:46:16,112 我的意思是 And what I mean by that 833 00:46:18,096 --> 00:46:21,152 我们完全可以用流来组织程序 is that we really can write stream programs 834 00:46:21,168 --> 00:46:22,480 就像我之前编写的那样 exactly like the ones I wrote 835 00:46:23,552 --> 00:46:27,744 以至于当机器真正运行的时候 and arrange things so that when the machine actually runs, 836 00:46:28,336 --> 00:46:31,520 它可以和传统风格的程序一样高效 it's as efficient as running this traditional programming style 837 00:46:31,712 --> 00:46:34,288 那些混合了生成与测试的程序 that mixes up the generation and the test. 838 00:46:36,160 --> 00:46:38,800 听起来不可思议 Well, that sounds pretty magic. 839 00:46:40,770 --> 00:46:41,824 关键在就于 The key to this 840 00:46:42,000 --> 00:46:43,690 流不是表 is that streams are not lists. 841 00:46:48,090 --> 00:46:49,792 一会儿我们就会看到 但是现在 We'll see this carefully in a second, but for now, 842 00:46:49,808 --> 00:46:51,776 先让我们来看看幻灯片 let's take a look at that slide again. 843 00:46:52,240 --> 00:46:53,808 你们对这个 The image you should have here 844 00:46:53,840 --> 00:46:55,584 信号处理系统的印象是 of this signal processing system 845 00:46:57,264 --> 00:46:58,720 你们认为要发生的是 is that what's going to happen 846 00:46:59,136 --> 00:47:00,928 在这类盒子中 is there's sort of this box 847 00:47:01,184 --> 00:47:03,584 事先产生好了整数 that has the integers sitting in it. 848 00:47:05,360 --> 00:47:06,400 这里有个过滤函数 And there's this filter 849 00:47:07,456 --> 00:47:09,376 它和那个盒子相连 并从中拉取东西 that's connected to it and it's tugging on them. 850 00:47:10,940 --> 00:47:13,152 这里还有人从这整个系统中 And then there's someone who's tugging on this stuff 851 00:47:13,312 --> 00:47:14,912 拉取东西 saying what comes out of the filter. 852 00:47:16,790 --> 00:47:18,704 你们应该这么来理解: And the image you should have is that 853 00:47:18,992 --> 00:47:20,720 有人想要得到第一个质数 someone says, well, what's the first prime, 854 00:47:22,672 --> 00:47:24,144 他从这个过滤函数这儿拉取 and tugs on this filter. 855 00:47:24,590 --> 00:47:26,128 FILTER从枚举函数中去拉取 And the filter tugs on the integers. 856 00:47:28,020 --> 00:47:29,152 你只需要在固定范围内寻找 And you look only at that much, 857 00:47:29,168 --> 00:47:30,930 然后从里面取出第二个数 and then say, oh, I really wanted the second one. 858 00:47:30,930 --> 00:47:31,952 第二个质数是多少? What's the second prime? 859 00:47:33,710 --> 00:47:35,376 没有额外的计算 And that no other computation 860 00:47:35,376 --> 00:47:36,640 只要你不去拉取东西 no computation gets done 861 00:47:36,640 --> 00:47:38,320 就不会产生进行额外计算 except when you tug on these things. 862 00:47:40,500 --> 00:47:41,410 我来用实物演示一下 Let me try that again. 863 00:47:41,410 --> 00:47:43,888 这个小设备 This is a little device. 864 00:47:43,900 --> 00:47:44,976 这是个小型的流机器 This is a little stream machine 865 00:47:45,504 --> 00:47:46,832 这是Eric Grimson发明的 invented by Eric Grimson 866 00:47:47,600 --> 00:47:49,248 他也在MIT教这门课 who's been teaching this course at MIT. 867 00:47:49,830 --> 00:47:52,512 实际的流程是 -- 这里有某种流 And the image is ... here's a stream of stuff, 868 00:47:52,544 --> 00:47:53,824 就像一串整数一样 like a whole bunch of the integers. 869 00:47:54,780 --> 00:47:56,336 这些是一些处理单元 And here's some processing elements. 870 00:47:58,700 --> 00:48:02,600 就像是FILTER、MAP之类的东西 And if, say, it's filter of filter of map, or something. 871 00:48:03,984 --> 00:48:09,184 如果我把流实现为表 来进行处理 And if I really tried to implement that with streams as lists, 872 00:48:09,248 --> 00:48:11,264 我拥有的是一个表 what I'd say is, well, I've got this list of things, 873 00:48:11,472 --> 00:48:12,670 现在 我先执行第一个过滤函数 and now I do the first filter. 874 00:48:12,670 --> 00:48:14,070 我像这样完全处理 So I sort of do all this processing. 875 00:48:14,880 --> 00:48:15,776 针对这个流 And I take this 876 00:48:16,320 --> 00:48:19,216 不断地处理、处理、处理、处理 and I process and I process and I process and I process. 877 00:48:19,610 --> 00:48:21,056 然后得到一个新的流 And now I'm got this new stream. 878 00:48:21,632 --> 00:48:24,070 现在 我把得到的结果拿在我手中 Right? Now I take that result in my hand someplace. 879 00:48:24,070 --> 00:48:25,260 然后把它放进第二个 And I put that through the second one. 880 00:48:25,568 --> 00:48:26,944 又处理了全部的流 And I process the whole thing. 881 00:48:28,272 --> 00:48:29,510 得到一个新流 And there's this new stream. 882 00:48:32,130 --> 00:48:33,360 然后我再把结果 And then I take the result 883 00:48:34,288 --> 00:48:36,360 用相同的方式再次处理 and I put it all the way through this one the same way. 884 00:48:36,360 --> 00:48:40,992 如果仅仅把流当做表的话 That's what would happen to these stream programs 885 00:48:41,696 --> 00:48:42,976 计算的过程就是这样的 if streams were just lists. 886 00:48:43,860 --> 00:48:45,648 但是事实上 流不是表 流就是流 But in fact, streams aren't lists, they're streams. 887 00:48:45,824 --> 00:48:48,112 而你们应该这样来想像 And the image you should have is something a little bit more like this. 888 00:48:50,230 --> 00:48:52,528 我把这些小玩意连接起来 I've got these gadgets connected up 889 00:48:55,264 --> 00:48:56,768 数据在其中流动 by this data that's flowing out of them. 890 00:49:00,336 --> 00:49:02,304 这里是流的源头 And here's my original source of the streams. 891 00:49:02,320 --> 00:49:02,928 它可能在 It might be 892 00:49:04,192 --> 00:49:05,728 产生一些整数 starting to generate the integers. 893 00:49:05,980 --> 00:49:07,392 如果我想要拉取一个结果 会发生什么? And now, what happens if I want a result? 894 00:49:07,580 --> 00:49:08,912 我从尾部这里拉取 I tug on the end here. 895 00:49:10,200 --> 00:49:11,072 而这个单元会说 And this element says, 896 00:49:11,088 --> 00:49:12,208 我需要更多的数据 gee, I need some more data. 897 00:49:13,090 --> 00:49:15,520 所以 它就到这个单元去拉取数据 So it's sort of, this one comes here and tugs on that one. 898 00:49:15,830 --> 00:49:17,392 它说:“我需要更多的数据” And it says, gee, I need some more data. 899 00:49:17,890 --> 00:49:19,568 然后这个又从下一个单元拉取 And this one tugs on this thing, 900 00:49:19,568 --> 00:49:20,288 可能是一个过滤函数 which might be a filter, 901 00:49:20,288 --> 00:49:21,408 从它那里取得更多数据 and says, gee, I need some more data. 902 00:49:21,640 --> 00:49:23,152 我在这一端拉取数据时 And only as much of this 903 00:49:23,536 --> 00:49:25,568 只会生成这么多的数据 thing at the end here gets generated as I tugged. 904 00:49:25,780 --> 00:49:28,304 我在另一端请求一定量的数据时 And only as much of this stuff goes through the processing units 905 00:49:28,560 --> 00:49:29,984 只有相当数量的数据被生成并处理 as I'm pulling on the end I need. 906 00:49:30,760 --> 00:49:32,096 这就是你们需要知道的 That's the image you should have 907 00:49:32,800 --> 00:49:34,384 把流实现为表 of the difference between implementing 908 00:49:34,560 --> 00:49:35,920 和流真实的工作方式 what we're actually going to do 909 00:49:36,160 --> 00:49:37,504 的区别 and if streams were lists. 910 00:49:40,784 --> 00:49:42,144 那么 到底怎么来实现呢? Well, how do we make this thing? 911 00:49:42,352 --> 00:49:43,328 知道了流的真实工作方式 I hope you have the image. 912 00:49:43,400 --> 00:49:44,528 构造流有什么窍门呢? The trick is how to make it. 913 00:49:47,930 --> 00:49:50,320 我们想要把流组织成 We want to arrange for a stream 914 00:49:50,416 --> 00:49:51,584 一种数据结构 to be a data structure 915 00:49:52,000 --> 00:49:54,224 它能够增量式地计算自己 that sorts of computes itself incrementally, 916 00:49:54,224 --> 00:49:56,224 一种“按需”数据结构 sort of on-demand data structure. 917 00:49:58,960 --> 00:50:00,512 基本思想在于 Right? And the basic idea 918 00:50:00,976 --> 00:50:02,704 再次强调 这是贯穿整个课程的 is again, one of the very basic ideas 919 00:50:02,720 --> 00:50:04,128 几大基本思想之一 that we're seeing throughout the whole course. 920 00:50:04,490 --> 00:50:05,008 这就是 And that is 921 00:50:05,520 --> 00:50:06,976 数据与过程之间 that there's not a firm distinction 922 00:50:06,992 --> 00:50:08,448 并没有绝对的界限 between programs and data. 923 00:50:09,240 --> 00:50:10,544 流会是这样的一种结构 So what a stream is going to be 924 00:50:10,592 --> 00:50:13,408 它既是一种传统意义上的“数据结构” is simultaneously this data structure that you think of, 925 00:50:13,456 --> 00:50:15,920 比如树的叶子结点组成的流 like the stream of the leaves of this tree. 926 00:50:16,864 --> 00:50:17,856 但是同时 But at the same time, 927 00:50:17,856 --> 00:50:19,328 它又是一种非常聪明的过程 it's going to be a very clever procedure 928 00:50:20,240 --> 00:50:22,224 它包含了如何计算的方法 that has the method of computing in it. 929 00:50:23,744 --> 00:50:25,930 好吧 实际来看一下 Well, let me try this. 930 00:50:25,930 --> 00:50:26,624 事实上 It's going to turn out 931 00:50:26,800 --> 00:50:28,330 我们不需要其它的机制 that we don't need any more mechanism. 932 00:50:28,460 --> 00:50:29,872 我们已经有了所需要的一切东西 We already have everything we need 933 00:50:30,144 --> 00:50:30,992 这是因为 simply from the fact 934 00:50:31,020 --> 00:50:33,936 我们已经能够 把过程当作第一级对象来处理了 that we know how to handle procedures as first-class objects. 935 00:50:35,460 --> 00:50:36,880 来看看这个关键之处 Well, let's go back to the key. 936 00:50:36,880 --> 00:50:39,030 关键在于 -- 回想一下 我们有这些运算 The key is, remember, we had these operations. 937 00:50:39,030 --> 00:50:47,520 CONS-STREAM、HEAD和TAIL CONS-stream and head and tail. 938 00:50:48,080 --> 00:50:49,360 刚开始的时候我说 When I started, I said 939 00:50:49,920 --> 00:50:51,360 你们可以把这个看作CONS you can think about this as CONS 940 00:50:51,400 --> 00:50:52,624 把HEAD看作CAR and think about this as CAR 941 00:50:52,624 --> 00:50:53,520 把TAIL看作CDR and think about that as CDR 942 00:50:53,552 --> 00:50:54,160 事实上没这么简单 but it's not. 943 00:50:55,080 --> 00:50:56,320 现在 来看看它们到底是什么 Now, let's look at what they really are. 944 00:50:57,712 --> 00:51:05,840 (CONS-STREAM X Y) Well, CONS-stream of x and y 945 00:51:07,488 --> 00:51:17,792 是这个东西的缩写形式 is going to be an abbreviation for the following thing. 946 00:51:19,540 --> 00:51:28,320 (CONS X (DELAY Y)) CONS form a pair, ordinary CONS, of x to a thing called delay of y. 947 00:51:31,680 --> 00:51:33,536 我先把它们写完再来解释 And before I explain that, let me go and write the rest. 948 00:51:34,528 --> 00:51:35,536 而(HEAD S) The head of a stream 949 00:51:38,096 --> 00:51:39,790 就是 (CAR S) is going to be just the CAR. 950 00:51:42,380 --> 00:51:44,256 而(TAIL S) And the tail of a stream 951 00:51:46,680 --> 00:51:54,608 则是(FORCE (CDR S)) is going to be a thing called force the CDR of the stream. 952 00:51:56,120 --> 00:51:57,040 我来解释一下 Now let me explain this. 953 00:51:58,060 --> 00:51:59,888 DELAY是一个特殊而神奇的东西 Delay is going to be a special magic thing. 954 00:52:01,420 --> 00:52:02,336 DELAY所做是 What delay does 955 00:52:03,856 --> 00:52:05,312 取一个表达式 is take an expression 956 00:52:05,504 --> 00:52:06,864 然后产生一个PROMISE and produce a promise 957 00:52:07,120 --> 00:52:09,152 在你有需要时 这个PROMISE会计算那个表达式 to compute that expression when you ask for it. 958 00:52:10,600 --> 00:52:11,980 但在此时没有做任何计算 It doesn't do any computation here. 959 00:52:11,980 --> 00:52:14,320 只是一个延期的PROMISE Just sort of... It just gives you a rain check. 960 00:52:14,820 --> 00:52:16,208 承诺要做这样的事 It produces a promise. 961 00:52:17,110 --> 00:52:18,208 CONS-STREAM所做的就是 And CONS-stream says 962 00:52:18,816 --> 00:52:21,968 把X和一个计算Y的PROMISE I'm going to put together in a pair x 963 00:52:23,312 --> 00:52:25,360 放在在一个序对里 and a promise to compute y. 964 00:52:28,230 --> 00:52:28,992 如果我需要头部分 Now, if I want the head, 965 00:52:28,992 --> 00:52:30,750 那么就是这个序对的CAR部分 that's just the CAR that I put in the pair. 966 00:52:31,840 --> 00:52:33,712 关键在于 它的尾部分 And the key is that the tail is going to be-- 967 00:52:34,624 --> 00:52:36,656 强制会调用该PROMISE force calls in that promise. 968 00:52:38,220 --> 00:52:39,888 而TAIL会说 Force -- Tail says, well, 969 00:52:40,032 --> 00:52:41,024 好吧 取出该PROMISE well, take that promise 970 00:52:41,850 --> 00:52:44,528 然后调用该PROMISE and now call in that promise. 971 00:52:44,560 --> 00:52:46,032 这才开始实际的计算 And then we compute that thing. 972 00:52:47,696 --> 00:52:48,720 这就是它的实际工作方式 That's how this is going to work. 973 00:52:48,740 --> 00:52:51,550 这就是CONS-STREAM、HEAD和TAIL的真正定义 That's what CONS-stream, head, and tail really are. 974 00:52:54,608 --> 00:52:55,570 具体演示一下 Now, let's see how this works. 975 00:52:55,570 --> 00:52:57,504 我们小心翼翼地来审查一遍 And we'll go through this fairly carefully. Let's -- 976 00:52:58,768 --> 00:53:00,624 现在从计算10,000到1,000,000中的 We're going to see how this 977 00:53:01,328 --> 00:53:03,664 第二个质数这个实例来看 example of computing the second prime 978 00:53:05,504 --> 00:53:07,168 看看是怎么运行的 right? between 10,000 and a million. 979 00:53:08,650 --> 00:53:12,032 好的 我们从这个表达式开始 OK, so we start off and we have this expression. 980 00:53:15,360 --> 00:53:16,624 第二个质数就是 Right? The second prime-- 981 00:53:16,640 --> 00:53:21,904 就是(HEAD (TAIL (FILTER PRIME? ... ))) the head of the tail of the result of filtering for primality 982 00:53:22,832 --> 00:53:25,312 枚举的范围是(E-I 10000 1000000) the integers between 10,000 and 1 million. 983 00:53:26,710 --> 00:53:27,616 这是什么呢? Now, what is that? 984 00:53:28,400 --> 00:53:29,200 那就是 What that is, 985 00:53:31,632 --> 00:53:34,176 枚举的这个10,000至1,000,000的区间 that interval between 10,000 and 1 million, 986 00:53:35,728 --> 00:53:37,328 如果你追踪这个枚举区间 well, if you trace through enumerate interval, 987 00:53:37,344 --> 00:53:38,780 会发现它构造了一个流 there builds a CONS-stream. 988 00:53:39,920 --> 00:53:41,392 CONS-STREAM实际代换过来是 And the CONS-stream is 989 00:53:41,968 --> 00:53:43,616 把10,000 the CONS of 10,000 990 00:53:44,512 --> 00:53:48,928 和一个计算10,001到1,000,000之间整数的PROMISE结合起来 to a promise to compute the integers between 10,001 and 1 million. 991 00:53:54,000 --> 00:53:55,750 这也就是上面这个表达式 Okay? So that's what this expression is. 992 00:53:55,750 --> 00:53:57,328 现在我使用代换模型 Here I'm using the substitution model. 993 00:53:57,640 --> 00:53:59,328 我们可以用代换模型的原因是 And we can use the substitution model 994 00:53:59,344 --> 00:54:01,010 这里并没有涉及状态和副作用 because we don't have side effects and state. 995 00:54:03,560 --> 00:54:06,384 所以我有10,000 Okay? So I have CONS of 10,000 996 00:54:06,416 --> 00:54:08,272 和一个计算剩余整数构成的流 to a promise to compute the rest of the integers. 997 00:54:08,320 --> 00:54:10,496 而到现在为止 只有一个整数被枚举了出来 So only one integer, so far, got enumerated. 998 00:54:14,380 --> 00:54:16,960 然后过滤函数会对它做素性测试 Well, I'm going to filter that thing for primality. 999 00:54:19,440 --> 00:54:21,904 我们再来仔细看看过滤函数的代码 Again, you go back and look at the filter code. 1000 00:54:22,360 --> 00:54:24,464 过滤函数首先测试流的首部分 What the filter will first do is test the head. 1001 00:54:25,460 --> 00:54:28,256 这里 过滤函数会测试10,000 So in this case, the filter will test 10,000 1002 00:54:30,304 --> 00:54:32,976 然后输出:10,000不是质数 oh, 10,000's not prime. 1003 00:54:33,500 --> 00:54:35,856 因此我只需要 Therefore, what I have to do recursively 1004 00:54:36,256 --> 00:54:37,390 递归地过滤尾部分 is filter the tail. 1005 00:54:39,220 --> 00:54:40,144 尾部分是什么呢? And what's the tail of it, 1006 00:54:40,160 --> 00:54:43,760 就是这个流的尾部分 -- 一个PROMISE well, that's the tail of this pair with a promise in it. 1007 00:54:46,340 --> 00:54:48,064 我们进入到尾部分 Tail now comes in and says, 1008 00:54:48,288 --> 00:54:49,504 强制(计算)该PROMISE well, I'm going to force that. 1009 00:54:49,680 --> 00:54:50,944 我强制计算该PROMISE I'm going to force that promise, 1010 00:54:52,304 --> 00:54:54,368 这就意味着 我现在要 which means now I'm going to compute 1011 00:54:55,584 --> 00:54:57,968 枚举10,001到1,000,000之间的整数 the integers between 10,001 and 1 million. 1012 00:55:00,800 --> 00:55:02,970 现在 过滤函数处理的是这个东西 OK? So this filter now is looking at that. 1013 00:55:07,810 --> 00:55:08,928 这个枚举函数枚举了它自己 That enumerate itself, 1014 00:55:08,944 --> 00:55:11,230 我们又回到了最初那种枚举情况 now we're back in the original enumerate situation. 1015 00:55:11,960 --> 00:55:13,008 我们的枚举函数的 The enumerate is 1016 00:55:14,128 --> 00:55:16,448 首部分是整数10,001 CONS of the first thing, 10,001, 1017 00:55:16,608 --> 00:55:18,208 尾部分是计算剩余部分的PROMISE onto a promise to compute the rest. 1018 00:55:19,740 --> 00:55:22,752 因此现在素性过滤函数将会测试10,001 So now the primality filter is going to go look at 10,001. 1019 00:55:23,232 --> 00:55:25,120 开始判断它是不是质数 It's going to decide if it likes that or not. 1020 00:55:25,120 --> 00:55:27,088 结果10,001不是质数 It turns out 10,001 isn't prime. 1021 00:55:27,550 --> 00:55:29,610 然后再不断地强制求值PROMISE So it'll force it again and again and again. 1022 00:55:32,920 --> 00:55:35,808 最后 我觉得它找到的第一个质数可能是10,009 And finally, I think the first prime it hits is 10,009. 1023 00:55:37,100 --> 00:55:38,336 它会在这个时候停止 And at that point, it'll stop. 1024 00:55:40,848 --> 00:55:41,936 这只是第一个质数 And that will be the first prime, 1025 00:55:41,968 --> 00:55:43,488 然而 我们需要的是第二个 and then eventually, it'll need the second prime. 1026 00:55:45,240 --> 00:55:46,848 所以 这时它又启动了 So at that point, it will go again. 1027 00:55:47,030 --> 00:55:48,256 你会发现 So you see what happens is that 1028 00:55:48,528 --> 00:55:50,496 你需要多少 no more gets generated 1029 00:55:51,856 --> 00:55:52,912 它就只会生成多少 than you actually need. 1030 00:55:56,480 --> 00:55:59,920 枚举函数生成整数的数量 That enumerator is not going to generate any more integers 1031 00:56:00,128 --> 00:56:01,450 不会比过滤函数所要求的多 than the filter asks it for 1032 00:56:01,472 --> 00:56:03,456 因为它只是取一部分数来做素性测试 as it's pulling in things to check for primality. 1033 00:56:04,700 --> 00:56:06,512 过滤函数也不会生成 And the filter is not going to generate 1034 00:56:06,544 --> 00:56:08,048 比你的要求更多的东西 any more stuff than you ask it for, 1035 00:56:08,064 --> 00:56:09,104 也就是尾部分的首部分 which is the head of the tail. 1036 00:56:11,616 --> 00:56:13,264 你们看 You see, what's happened is 1037 00:56:14,704 --> 00:56:18,240 我们把计算机运行中实际进行的 we've put that mixing of generation and test 1038 00:56:18,672 --> 00:56:20,656 生成与测试的过程 混合在了一起 into what actually happens in the computer, 1039 00:56:21,520 --> 00:56:22,672 尽管 even though 1040 00:56:23,184 --> 00:56:25,630 我们的程序“看起来”显然不是这样 that's not apparently what's happening from looking at our programs. 1041 00:56:28,128 --> 00:56:29,408 看起来都很简单 OK, well, that seemed easy. 1042 00:56:30,230 --> 00:56:32,672 这种机制的神奇之处在于DELAY All of this mechanism got put into this magic delay. 1043 00:56:33,680 --> 00:56:35,664 所以你也许会说 这全是因为DELAY很强大 So you're saying, gee, that must be where the magic is. 1044 00:56:36,900 --> 00:56:38,576 但其实并不是 But see there's no magic there either. 1045 00:56:39,070 --> 00:56:39,984 DELAY其实很简单 You know what delay is. 1046 00:56:40,610 --> 00:56:45,072 (DELAY ) Delay on some expression 1047 00:56:48,256 --> 00:56:50,048 只是一个缩略表达 is just an abbreviation for-- 1048 00:56:53,360 --> 00:56:55,632 它是-- 创建一个用于计算表达式的PROMISE well, what's a promise to compute an expression? 1049 00:56:56,490 --> 00:57:01,120 (LAMBDA () ) 这样的一个表达式 Lambda of nil, procedure of no arguments, which is that expression. 1050 00:57:02,832 --> 00:57:03,840 这就是整个过程 Right? That's what a procedure is. 1051 00:57:03,984 --> 00:57:05,530 这个PROMISE将要计算表达式 It says I'm going to compute an expression. 1052 00:57:06,050 --> 00:57:06,736 FORCE过程又是什么? What's force? 1053 00:57:07,344 --> 00:57:10,800 如何处理这个PROMISE Right, how do I take up a promise? 1054 00:57:10,800 --> 00:57:14,112 FROCE一个PROMISE -- 也就是某个过程 Well, force of some procedure, a promise, 1055 00:57:14,784 --> 00:57:15,408 只是简单地运行它 is just run it. 1056 00:57:19,232 --> 00:57:19,568 就是这样 Done. 1057 00:57:20,240 --> 00:57:21,376 所以这里并没有什么魔法 So there's no magic there at all. 1058 00:57:23,520 --> 00:57:24,240 总结一下 我们都干了些什么? Well, what have we done? 1059 00:57:26,440 --> 00:57:27,504 我们说 We said the old style, 1060 00:57:28,144 --> 00:57:30,816 传统的编程方式更有效 traditional style of programming is more efficient. 1061 00:57:30,960 --> 00:57:33,920 而流程序却更加清晰 And the stream thing is more perspicacious. 1062 00:57:35,504 --> 00:57:38,720 我们设法用DELAY And we managed to make the stream procedures 1063 00:57:38,816 --> 00:57:43,232 使流程序和其它过程一样高效 run like the other procedures by using delay. 1064 00:57:43,350 --> 00:57:46,432 DELAY所做的就是把 And the thing that delay did for us was to de-couple 1065 00:57:46,688 --> 00:57:50,400 我们程序中 事件发生的逻辑顺序 the apparent order of events in our programs 1066 00:57:51,216 --> 00:57:53,840 和机器中 事件发生的实际顺序 解耦开来 from the actual order of events that happened in the machine. 1067 00:57:54,440 --> 00:57:55,936 这是DELAY的实质作用 That's really what delay is doing. 1068 00:57:57,152 --> 00:57:58,290 也是全部的重点 That's exactly the whole point. 1069 00:57:58,290 --> 00:58:01,920 我们放弃了那种想法 We've given up, right, we've given up the idea 1070 00:58:02,300 --> 00:58:04,176 即程序的运行 that our procedures, as they run, 1071 00:58:04,672 --> 00:58:05,952 或者源码的编排 or as we look at them, 1072 00:58:06,336 --> 00:58:08,256 反映了时间的明确概念 mirror some clear notion of time. 1073 00:58:09,456 --> 00:58:10,576 一旦放弃了这种想法 And by giving that up, 1074 00:58:11,216 --> 00:58:13,328 我们能使用DELAY we give delay the freedom to arrange the order 1075 00:58:13,344 --> 00:58:15,200 自由地安排计算顺序 of events in the computation the way it likes. 1076 00:58:16,690 --> 00:58:17,610 整个思想就是这样 That's the whole idea. 1077 00:58:17,610 --> 00:58:19,456 我们解耦了 We de-couple the apparent order 1078 00:58:19,952 --> 00:58:21,136 程序的逻辑顺序 of events in our programs 1079 00:58:21,168 --> 00:58:22,896 和其实际运行的顺序 from the actual order of events in the computer. 1080 00:58:24,096 --> 00:58:25,770 对了 还有一个细节 OK, well there's one more detail. 1081 00:58:25,770 --> 00:58:27,216 一个技术性的细节 It's just a technical detail, 1082 00:58:27,216 --> 00:58:28,432 但是也非常重要 but it's actually an important one. 1083 00:58:29,730 --> 00:58:32,016 当你们运行这些递归程序的时候 As you run through these recursive programs unwinding, 1084 00:58:32,160 --> 00:58:33,584 你会看到很多像是 you'll see a lot of things that look like 1085 00:58:33,648 --> 00:58:37,872 (TAIL (TAIL (TAIL ... 这样的东西 tail of the tail of the tail. 1086 00:58:39,200 --> 00:58:41,024 如果流是通过嵌套的CONS构造起来的 Right. That's the kind of thing that would happen 1087 00:58:41,024 --> 00:58:42,880 就会出现这种情况 as I go CONSing down a stream all the way. 1088 00:58:43,860 --> 00:58:46,096 如果我每次都要执行一次 And if each time I'm doing that, 1089 00:58:46,144 --> 00:58:47,584 如果我每次都要计算TAIL each time to compute a tail, 1090 00:58:48,224 --> 00:58:50,880 我对一个过程求值 I evaluate a procedure 1091 00:58:51,072 --> 00:58:53,072 这个过程又将重新计算它的TAIL which then has to go re-compute its tail, 1092 00:58:53,100 --> 00:58:55,408 它的TAIL又将重新计算TAIL的TAIL and re-compute its tail and recompute its tail each time, 1093 00:58:55,504 --> 00:58:56,880 你们可以发现这非常低效 you can see that's very inefficient 1094 00:58:57,776 --> 00:59:00,560 尤其是跟已经存放了所有元素的表相比 compared to just having a list where the elements are all there, 1095 00:59:01,168 --> 00:59:04,000 因为那样 在取得下一个TAIL的时候不需要重新计算 and I don't have to re-compute each tail every time I get the next tail. 1096 00:59:05,290 --> 00:59:08,288 因此 这里有一个小技巧 So there's one little hack 1097 00:59:09,660 --> 00:59:13,136 通过稍微修改DELAY的定义 to slightly change the abbreviation, change what delay is 1098 00:59:14,960 --> 00:59:18,208 就可以让整件事变得 -- 我先写一下 and make it a thing which is-- I'll write it this way. 1099 00:59:19,680 --> 00:59:22,048 DELAY实际的实现是 Delay -- The actual implementation, 1100 00:59:24,528 --> 00:59:27,936 (DELAY )是这样一个表达式的简写 delay is an abbreviation for this thing, 1101 00:59:28,112 --> 00:59:30,864 (MEMO-PROC (LAMBDA () )) memo-proc of a procedure. 1102 00:59:31,000 --> 00:59:34,064 MEMO-PROC是一个可以改变过程的特殊过程 Memo-proc is a special thing that transforms a procedure. 1103 00:59:35,150 --> 00:59:37,808 它接受一个无参过程 What it does is it takes a procedure of no arguments 1104 00:59:39,024 --> 00:59:41,056 并把该过程变为 and it transforms it into a procedure 1105 00:59:41,360 --> 00:59:43,552 只需要执行一次计算的过程 that'll only have to do its computation once. 1106 00:59:45,104 --> 00:59:47,456 我们意思是 你给它一个过程 And what I mean by that is, you give it a procedure. 1107 00:59:48,700 --> 00:59:50,864 MEMO-PROC返回一个新的过程 The result of memo-proc will be a new procedure, 1108 00:59:51,392 --> 00:59:53,008 当你首次调用这个新过程 which the first time you call it, 1109 00:59:53,712 --> 00:59:55,072 它会运行原始过程 will run the original procedure, 1110 00:59:55,312 --> 00:59:56,912 并记下结果 remember what result it got, 1111 00:59:58,560 --> 01:00:00,688 从那之后 每次你再运行这个过程 and then from ever on after, when you call it, 1112 01:00:00,688 --> 01:00:02,176 就不用再计算了 it just won't have to do the computation. 1113 01:00:02,192 --> 01:00:04,432 它会把结果存储在一个地方 It will have cached that result someplace. 1114 01:00:05,200 --> 01:00:06,928 可以这样来实现MEMO-PROC And here's an implementation of memo-proc. 1115 01:00:11,210 --> 01:00:12,710 一旦你了解怎么做 实现就很容易了 Once you have the idea, it's easy to implement. 1116 01:00:12,710 --> 01:00:16,768 MEMO-PROC中有两个标记变量 Memo-proc is this little thing that has two little flags in there. 1117 01:00:17,390 --> 01:00:19,200 ALREADY-RUN?用于记录是否运行过 It says, have I already been run? 1118 01:00:20,320 --> 01:00:22,480 初始值是NIL 指示没运行过 And initially it says, no, I haven't already been run. 1119 01:00:23,620 --> 01:00:27,040 RESULT用于存储上一次计算的结果 And what was the result I got the last time I was run? 1120 01:00:29,070 --> 01:00:31,072 MEMO-PROC接收一个过程PROC So memo-proc takes a procedure called proc, 1121 01:00:31,568 --> 01:00:34,016 返回一个新的无参过程 and it returns a new procedure of no arguments. 1122 01:00:34,360 --> 01:00:36,384 PROC也是一个无参过程 Proc is supposed to be a procedure of no arguments. 1123 01:00:38,610 --> 01:00:41,376 它会判断 -- 如果没有运行过 And it says, oh, if I'm not already run, 1124 01:00:42,592 --> 01:00:44,064 就进行一系列的运算 then I'm going to do a sequence of things. 1125 01:00:44,430 --> 01:00:46,560 先计算PROC I'm going to compute proc, 1126 01:00:47,504 --> 01:00:48,450 然后存储它的值 I'm going to save that. 1127 01:00:48,450 --> 01:00:50,480 存储在变量RESULT中 I'm going to stash that in the variable result. 1128 01:00:51,140 --> 01:00:53,904 然后对ALREADY-RUN?赋值 提醒自己已经运行过了 I'm going to make a note to myself that I've already been run, 1129 01:00:54,288 --> 01:00:55,472 最后返回RESULT and then I'll return the result. 1130 01:00:56,610 --> 01:00:59,010 所以之前如果没运行过 就执行一次计算 So that's if you compute it if it's not already run. 1131 01:00:59,010 --> 01:01:01,888 当你调用它 但已经运行过了 就直接返回结果 If you call it and it's already been run, it just returns the result. 1132 01:01:03,420 --> 01:01:07,120 这种聪明的小技巧被称作“记忆化” So that's a little clever hack called memoization. 1133 01:01:08,400 --> 01:01:09,136 这样的话 And in this case, 1134 01:01:10,352 --> 01:01:14,144 就不会重复的计算TAIL了 it short circuits having to re-compute the tail of the tail of the tail of the tail of the tail. 1135 01:01:15,270 --> 01:01:17,810 不再那样的没效率了 So there isn't even that kind of inefficiency. 1136 01:01:17,810 --> 01:01:18,720 事实上 流式程序设计 And in fact, the streams 1137 01:01:19,200 --> 01:01:22,752 甚至和传统的那种程序一样有效 will run with pretty much the same efficiency as the other programs precisely. 1138 01:01:24,016 --> 01:01:26,208 再强调一下 整个的思想在于 And remember, again, the whole idea of this 1139 01:01:27,480 --> 01:01:28,608 我们已经讲过 is that we've used 1140 01:01:29,264 --> 01:01:32,400 过程与数据之间 the fact that there's no really good dividing line 1141 01:01:32,416 --> 01:01:33,610 没有一个明确的分界线 between procedures and data. 1142 01:01:33,610 --> 01:01:35,616 事实上 我们把数据结构组织得 We've written data structures that, in fact, 1143 01:01:36,000 --> 01:01:37,312 像一个过程 are sort of like procedures. 1144 01:01:38,760 --> 01:01:40,736 它使得我们能够 And what that's allowed us to do 1145 01:01:41,584 --> 01:01:46,544 可以实现一种常见的控制结构 is take an example of a common control structure, 1146 01:01:46,688 --> 01:01:48,912 在本例中是迭代 in this place iteration. 1147 01:01:49,620 --> 01:01:51,056 我们创建了一种数据结构 And we've built a data structure 1148 01:01:51,328 --> 01:01:52,848 由于这种数据结构本身是一个过程 which, since itself is a procedure, 1149 01:01:52,864 --> 01:01:55,120 它其中就可以有某种控制结构 kind of has this iteration control structure in it. 1150 01:01:55,792 --> 01:01:57,136 这就是流的实质 And that's really what streams are. 1151 01:01:58,912 --> 01:01:59,760 好 大家有什么问题吗? OK, questions? 1152 01:02:03,950 --> 01:02:05,840 学生:你刚才说(TAIL (TAIL (TAIL ... AUDIENCE: Your description of tail-tail-tail, 1153 01:02:05,856 --> 01:02:07,168 如果我没理解错的话 if I understand it correctly, 1154 01:02:07,280 --> 01:02:10,768 没有没有MEMO-PROC的话 force is actually execution of a procedure, 1155 01:02:10,784 --> 01:02:12,832 FORCE实际上执行了一个过程 if it's done without this memo-proc thing. 1156 01:02:12,896 --> 01:02:13,152 教授:是的 PROFESSOR: Right. 1157 01:02:13,440 --> 01:02:16,380 学生:你说使用那个MEMO-PROC就不会有那样的问题 AUDIENCE: And you implied that memo-proc gets around that problem. 1158 01:02:16,380 --> 01:02:18,736 这难道不需要保证 Doesn't it only get around it if 1159 01:02:19,344 --> 01:02:22,192 (TAIL (TAIL (TAIL 每次的计算结构都是一致的么? tail-tail-tail is always executing exactly the same-- 1160 01:02:22,416 --> 01:02:23,910 教授:哦 当然 PROFESSOR: Oh, that's-- sure. 1161 01:02:23,910 --> 01:02:25,840 学生:我可能是漏了什么知识点 AUDIENCE: I guess I missed that point. 1162 01:02:26,050 --> 01:02:27,216 教授:你说得很对 这里 -- PROFESSOR: Oh, sure. I mean the point is-- yeah. 1163 01:02:31,120 --> 01:02:33,648 首先 为了获得结果需要进行一次计算 Yeah, I mean I have to do a computation to get the answer. 1164 01:02:34,096 --> 01:02:36,768 关键在于 一旦得到 (TAIL STREAM) But the point is, once I've found the tail of the stream, 1165 01:02:37,584 --> 01:02:38,704 再计算 (TAIL (TAIL STREAM)) 的时候 to get the tail of the tail, 1166 01:02:38,704 --> 01:02:40,512 就不用再计算最内部的TAIL了 I shouldn't have had to re-compute the first tail. 1167 01:02:42,980 --> 01:02:44,320 明白了吧 如果我没有用MEMO-PROC See, and if I didn't use memo-proc, 1168 01:02:44,352 --> 01:02:46,096 还要再计算一遍 (TAIL STREAM) that re-computation would have been done. 1169 01:02:46,460 --> 01:02:47,136 学生:明白了 AUDIENCE: I understand now. 1170 01:02:50,830 --> 01:02:52,560 学生:之前的例子中你提到过 AUDIENCE: In one of your examples, you mentioned that 1171 01:02:52,608 --> 01:02:54,224 我们之所以可以使用代换模型 we were able to use the substitution model 1172 01:02:54,224 --> 01:02:56,112 是因为这里没有副作用 because there are no side effects. 1173 01:02:56,830 --> 01:03:00,736 如果我们的信号处理单元 What if we had a signal processing unit-- 1174 01:03:00,784 --> 01:03:02,032 具有副作用 if we had a side effect, 1175 01:03:02,048 --> 01:03:03,040 具有内部状态 if we had a state? 1176 01:03:03,620 --> 01:03:06,848 我们还有效地构建流模型么? Could we still practically build the stream model? 1177 01:03:08,464 --> 01:03:10,592 教授:可能吧 这是一个很困难的问题 PROFESSOR: Hum... Maybe, That's a hard question. 1178 01:03:11,200 --> 01:03:13,424 关于代换模型和副作用并不是很兼容这一点 I'm going to talk a little bit later about the places where 1179 01:03:14,368 --> 01:03:18,240 我以后会稍稍地讲解一下 where substitution and side effects don't really mix very well. 1180 01:03:18,960 --> 01:03:20,480 但大体来说 我认为 But in general, I think the answer is 1181 01:03:20,496 --> 01:03:21,632 除非你非常小心 unless you're very careful, 1182 01:03:21,904 --> 01:03:24,464 否则副作用会把一切弄得很糟糕 any amount of side effect is going to mess up everything. 1183 01:03:35,040 --> 01:03:38,256 学生:我不是很理解MEMO-PROC这个过程 AUDIENCE: Sorry, I didn't quite understand the memo-proc operation. Uh... 1184 01:03:39,680 --> 01:03:41,120 你是什么时候执行那个LAMBDA的? When do you execute the lambda? 1185 01:03:41,990 --> 01:03:43,216 换句话说 In other words, 1186 01:03:43,680 --> 01:03:45,152 当MEMO-PROC执行的时候 when memo-proc is executed, 1187 01:03:45,184 --> 01:03:47,712 只生成了LAMBDA表达式 just this lambda expression is being generated. 1188 01:03:48,010 --> 01:03:49,680 但我不太清楚它是什么时候被执行的 But it's not clear to me when it's executed. 1189 01:03:50,390 --> 01:03:51,120 教授:好的 PROFESSOR: Right. 1190 01:03:51,350 --> 01:03:52,688 MEMO-PROC所做的 -- What memo-proc does-- remember, 1191 01:03:53,072 --> 01:03:55,856 MEMO-PROC的一个参数是PROC the thing that's going into memo-proc, the thing proc, 1192 01:03:56,384 --> 01:03:57,930 一个没有参数的过程 is a procedure of no arguments. 1193 01:03:57,930 --> 01:03:59,056 某个时刻 你会调用它 And someday, you're going to call it. 1194 01:04:00,390 --> 01:04:02,752 MEMO-PROC把该过程转化为 Memo-proc translates that procedure 1195 01:04:02,752 --> 01:04:04,560 另一个无参过程 into another procedure of no arguments, 1196 01:04:04,592 --> 01:04:05,808 某个时刻你会调用到它 which someday you're going to call. 1197 01:04:06,620 --> 01:04:07,424 LAMBDA语句做的是这个 That's that lambda. 1198 01:04:09,890 --> 01:04:14,080 所以在这里 我最初构造 So here, where I initially built as my 1199 01:04:15,856 --> 01:04:17,920 构造流的TAIL的时候 I built as my tail of the stream, 1200 01:04:18,304 --> 01:04:20,480 这里的这个无参过程 say, this procedure of no arguments, 1201 01:04:20,512 --> 01:04:21,616 会在之后的某个时刻调用 which someday I'll call. 1202 01:04:24,100 --> 01:04:28,016 相对应的 我要对(TAIL STREAM)调用MEMO-PROC Instead, I'm going to have the tail of the stream be memo-proc of it, 1203 01:04:28,128 --> 01:04:29,248 以后我会调用生成的过程 which someday I'll call. 1204 01:04:30,650 --> 01:04:31,904 所以这个无参的LAMBDA So that lambda of nil, 1205 01:04:32,032 --> 01:04:36,064 是当你在调用MEMO-PROC时调用的 that gets called when you call the memo-proc, 1206 01:04:38,976 --> 01:04:40,960 当你调用MEMP-PROC返回的过程时 when you call the result of that memo-proc, 1207 01:04:40,970 --> 01:04:42,288 也就会像通常的过程调用那样 which would be ordinarily 1208 01:04:42,368 --> 01:04:45,760 调用你最初设定的那个函数 when you would have called the original thing that you set it. 1209 01:04:47,640 --> 01:04:48,864 学生:我想问的是 AUDIENCE: OK, my ask is 1210 01:04:48,864 --> 01:04:50,864 当你调用MEMO-PROC的时候 I had a feeling that when you call memo-proc, 1211 01:04:50,864 --> 01:04:52,304 你返回了这个LAMBDA you just return this lambda. 1212 01:04:52,610 --> 01:04:53,072 教授:是的 PROFESSOR: That's right. 1213 01:04:53,770 --> 01:04:58,100 你调用MEMO-PROC的时候 返回了一个LAMBDA When you call memo-proc, you return the lambda. 1214 01:04:58,100 --> 01:04:59,840 直到你第一次需要执行它的时候 You never evaluate the expression at all, 1215 01:04:59,872 --> 01:05:02,270 你才去求值 until the first time that you would have evaluated it. 1216 01:05:07,760 --> 01:05:09,104 学生:我这样理解对吗? AUDIENCE: Do I understand it right 1217 01:05:09,184 --> 01:05:11,408 你构造了一个表 you actually have to build the list up, 1218 01:05:11,472 --> 01:05:14,176 但表中的元素还没有被求值 but the elements of the list don't get evaluated? 1219 01:05:14,240 --> 01:05:15,630 表达式没有被求值? The expressions don't get evaluated? 1220 01:05:15,630 --> 01:05:18,540 但在每个阶段 你还是构造了一个表 But at each stage, you actually are building a list. 1221 01:05:18,540 --> 01:05:20,700 教授:啊 我应该这样说 PROFESSOR: That's-- I really should have said this. 1222 01:05:20,700 --> 01:05:22,270 这个想法很好 That's a really good point. 1223 01:05:22,270 --> 01:05:23,184 但是 也不全对 No, it's not quite right. 1224 01:05:23,660 --> 01:05:25,080 因为实际发生的事情是这样的 See, cause what happens is this. 1225 01:05:25,080 --> 01:05:26,352 我先把这个画成序对 Let me draw this as pairs. 1226 01:05:26,890 --> 01:05:28,032 假设我要构造一个特别大的流 Suppose I'm going to make a big stream, 1227 01:05:28,960 --> 01:05:30,128 比如枚举一段区间 like enumerate interval, 1228 01:05:30,320 --> 01:05:31,488 从1到1,000,000,000 1 through 1 billion. 1229 01:05:32,740 --> 01:05:35,744 这实际上是一个序对 What that is, is a pair 1230 01:05:39,344 --> 01:05:43,360 由1和一个PROMISE组成 a 1 and a promise. 1231 01:05:46,736 --> 01:05:47,890 就是这样 That's exactly what it is. 1232 01:05:47,890 --> 01:05:48,768 什么都没有构造 Nothing got built up. 1233 01:05:51,600 --> 01:05:53,296 当我继续FORCE这个PROMISE When I go and force this, 1234 01:05:54,512 --> 01:05:56,370 再来看看 会发生什么 and see, what happens? 1235 01:05:56,370 --> 01:05:59,664 这个东西现在就成为了一个递归CONS Well, this thing is now also recursively a CONS. 1236 01:06:00,530 --> 01:06:02,160 所以这个PROMISE现在就变成了 So that this promise now is 1237 01:06:04,620 --> 01:06:08,960 一个2和做更多事情的PROMISE the next thing, which is a 2 and a promise to do more. 1238 01:06:11,350 --> 01:06:12,736 一直这样下去 And so on and so on and so on. 1239 01:06:14,470 --> 01:06:17,632 直到你走完整个流才完整地构建了一个表 So nothing gets built up until you walk down the stream. 1240 01:06:18,200 --> 01:06:19,584 因为这个东西不是表 Because what's sitting here is not the list, 1241 01:06:20,032 --> 01:06:21,488 只是一个生成表的PROMISE but a promise to generate the list. 1242 01:06:23,392 --> 01:06:25,500 技术上来说 PROMISE就是一个过程 And by promise, technically I mean procedure. 1243 01:06:27,808 --> 01:06:29,104 因此并没有直接构造好一个表 So it doesn't get built up. 1244 01:06:30,768 --> 01:06:32,720 我应该早点说的 Yeah, I should have said that before that. 1245 01:06:34,280 --> 01:06:35,344 好吧 就到这里 下课 OK. That you. Let's take a break. 1246 01:06:35,824 --> 01:06:42,960 MIT OpenCourseWare http://ocw.mit.edu 1247 01:06:42,960 --> 01:06:51,152 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec6b.srt ================================================ 1 00:00:00,032 --> 00:00:03,728 Learning-SICP学习小组 倾情制作 2 00:00:03,984 --> 00:00:07,264 翻译&&时间轴:张大伟(DreamAndDead) 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:07,408 --> 00:00:10,272 特别感谢:裘宗燕教授 4 00:00:10,400 --> 00:00:14,928 计算机程序的构造和解释 5 00:00:15,056 --> 00:00:19,408 流 II Stream 6 00:00:20,970 --> 00:00:24,080 教授:上节课 我们介绍了流 PROFESSOR: OK, well, we've been looking at streams, 7 00:00:24,080 --> 00:00:27,824 按照信号处理的方式来组织系统 this signal processing way of putting systems together. 8 00:00:28,870 --> 00:00:31,424 要记住的是 关键点在于 And remember, the key idea is that 9 00:00:31,904 --> 00:00:32,960 我们分离开 we decouple 10 00:00:34,208 --> 00:00:37,312 程序中 事件表面上的顺序 the apparent order of events in our programs 11 00:00:37,584 --> 00:00:40,176 与机器中的实际计算顺序 from the actual order of events in the computer. 12 00:00:41,072 --> 00:00:42,288 那就意味着 我们可以 And that means that we can start 13 00:00:42,576 --> 00:00:44,144 着手处理非常长的流 dealing with very long streams 14 00:00:44,896 --> 00:00:47,392 并且只有在需要的时候才生成其中的元素 and only having to generate the elements on demand. 15 00:00:47,536 --> 00:00:49,392 这种按需计算的方式 That sort of on-demand computation 16 00:00:49,520 --> 00:00:51,408 是内建在流的数据结构中的 is built into the stream's data structure. 17 00:00:54,110 --> 00:00:55,648 即使这个流非常之长 So if we have a very long stream, 18 00:00:55,664 --> 00:00:57,080 我们只计算所需要的 we only compute what we need. 19 00:00:58,040 --> 00:01:00,750 只有当我们要求的时候 新的数据才会生成 The things only get computed when we actually ask for them. 20 00:01:00,750 --> 00:01:01,744 要举个什么样的例子呢? Well, what are examples? 21 00:01:02,110 --> 00:01:03,600 这个“按需”是什么个情况呢? Are they actually asking for them? 22 00:01:05,024 --> 00:01:06,016 举个例子 For instance, we might 23 00:01:09,216 --> 00:01:11,376 我们可能会想要一个流中的第N个元素 might ask for the n-th element of a stream. 24 00:01:15,360 --> 00:01:18,928 这个过程可以用于计算流的第N个元素 Here's a procedure that computes the n-th element of a stream. 25 00:01:20,090 --> 00:01:21,232 一个参数为索引N An integer n, 26 00:01:21,248 --> 00:01:22,848 另一个参数是流S the n-th element of some stream s, 27 00:01:23,408 --> 00:01:25,424 递归遍历这个流即可求解 and we just recursively walk down the stream. 28 00:01:25,570 --> 00:01:27,392 如果N为0 我们就计算头部分 And if n is 0, we compute the head. 29 00:01:27,960 --> 00:01:30,992 否则 就在流的尾部分 Otherwise, it's the n-th the minus 1 element 30 00:01:31,744 --> 00:01:32,800 查找第N-1个元素 of the stream. 31 00:01:34,310 --> 00:01:36,432 看起来是Lisp中很普通的编程方式 但是不同的是 Those two are just like for Lisp, but the difference 32 00:01:36,624 --> 00:01:38,768 直到我们不断遍历 取得相继的N个元素 is those elements aren't going to get computed 33 00:01:38,864 --> 00:01:40,992 这些元素才被计算出来 until we walk down, taking successive n-ths. 34 00:01:41,520 --> 00:01:44,784 这是这些流元素可能被FORCE的一种方式 So that's one way that the stream elements might get forced. 35 00:01:45,776 --> 00:01:46,640 另外一种方式则是 And another way, 36 00:01:47,184 --> 00:01:48,928 这里有个简单的过程 用来打印一个流 here's a little procedure that prints a stream. 37 00:01:49,300 --> 00:01:50,384 它的定义是 We say print a stream, 38 00:01:51,904 --> 00:01:53,280 过程PRINT-STREAM的定义是 so to print a stream s. 39 00:01:54,150 --> 00:01:55,120 我们要怎么做呢? Well, what do we do? We'll 40 00:01:55,744 --> 00:01:56,864 先打印流的头部分 We print the head of the stream, 41 00:01:57,744 --> 00:01:59,328 流的头部分在这时就被计算出来 and that will cause the head to be computed. 42 00:01:59,720 --> 00:02:02,848 然后我们再递归地打印流的尾部分 And then we recursively print stream the tail of the stream. 43 00:02:04,990 --> 00:02:06,032 完成以后 And if we're already done, 44 00:02:06,048 --> 00:02:08,576 就返回一个的表示完成的消息 “DONE” maybe we have to return something about the message done. 45 00:02:09,660 --> 00:02:11,392 如果你构造了一个流 OK, and then so if you make a stream, 46 00:02:11,648 --> 00:02:13,648 这个流非常的长 you could say here's the stream, this very long stream. 47 00:02:14,310 --> 00:02:16,336 当你调用这个过程 And then you say print the stream, 48 00:02:16,416 --> 00:02:19,776 流中的元素会随着PRINT-STREAM的调用 and the elements of the stream will get computed successively 49 00:02:19,872 --> 00:02:21,120 而被依次计算出来 as that print calls them. 50 00:02:21,320 --> 00:02:22,816 不会在一开始就全部计算出来 They won't get all computed initially. 51 00:02:24,300 --> 00:02:25,664 正因为如此 我们能够 So in this way, we can 52 00:02:27,504 --> 00:02:29,610 我们能够处理非常长的流 So in this way, we can deal with some very long streams. 53 00:02:30,190 --> 00:02:31,920 多长呢? Well, how long can a stream be? 54 00:02:33,744 --> 00:02:35,120 可以是无限长 Well, it can be infinitely long. 55 00:02:35,904 --> 00:02:38,048 我们在计算机上实践一下 Let's look at an example here on the computer. 56 00:02:38,920 --> 00:02:41,968 我可以在计算机前输入 I could walk up to this computer, and I could say-- 57 00:02:43,488 --> 00:02:53,312 我先定义一个函数 (INTEGERS-FROM N) how about we'll define the stream of integers starting with some number N, 58 00:02:54,240 --> 00:02:57,136 用于生成一个从N开始的正整数流 the stream of positive integers starting with some number n. 59 00:03:00,360 --> 00:03:19,168 也就是 (CONS-STREAM N (INTEGERS-FROM (+ N 1)))) And that's cons-stream of n onto the integers from one more. 60 00:03:24,416 --> 00:03:25,616 这样就我们要的全部整数 So there are the integers. 61 00:03:28,992 --> 00:03:31,500 现在我来尝试得到所有的整数 Then I could say let's get all the integers. 62 00:03:34,570 --> 00:03:44,336 (DEFINE INTEGERS (INTEGERS-FROM 1)) define the stream of integers to be the integers starting with 1. 63 00:03:48,840 --> 00:03:50,944 如果现在我执行 (NTH-STREAM 20 INTEGERS) And now if I say something like 64 00:03:54,416 --> 00:03:55,800 来查看第20个元素 what's the what's the 20th integer. 65 00:04:03,424 --> 00:04:05,536 得到21 因为索引是从0开始的 So it's 21 because we start counting at 0. 66 00:04:06,848 --> 00:04:08,880 或者我们来点更复杂的 Or I can do more complicated things. 67 00:04:09,450 --> 00:04:10,840 我再来定义一个谓词 Let me to define a little predicate here. 68 00:04:11,776 --> 00:04:18,512 谓词NO-SEVEN用来检测是否为7的倍数 How about define no-seven. 69 00:04:19,580 --> 00:04:20,752 它的判定方法是这样的: It's going to test an integer, 70 00:04:21,792 --> 00:04:23,168 如果整数X不是7的倍数 and it's going to say it's not. 71 00:04:28,820 --> 00:04:33,968 我取X除7的余数 I take the remainder of x by 7, 72 00:04:36,624 --> 00:04:38,352 余数不应该为0 I don't get 0. 73 00:04:43,808 --> 00:04:49,776 这时用NO-SEVEN这个谓词 And then I could say define the integers with no sevens 74 00:04:50,224 --> 00:04:59,120 过滤全部的整数 take all the integers and filter them to have no sevens. 75 00:05:11,570 --> 00:05:13,344 这样我就得到了所有的 So now I've got the stream of all the integers 76 00:05:13,632 --> 00:05:15,056 不是7的倍数的整数构成的流 that are not divisible by seven. 77 00:05:16,490 --> 00:05:23,440 如果我问 这些不是7的倍数的整数中 So if I say what's the 100th integer 78 00:05:24,704 --> 00:05:26,480 的第100个数是多少? and the list not divisible by seven, 79 00:05:26,864 --> 00:05:28,112 结果是117 I get 117. 80 00:05:28,320 --> 00:05:30,672 或者我也可以问 Or if I'd like to say well, I could say ah. 81 00:05:32,304 --> 00:05:34,384 这个流的所有元素都是些什么? well, gee, what are all of them? 82 00:05:35,270 --> 00:05:40,352 我可以用(PRINT-STREAM NS)来尝试打印这个流 So I could say print stream all these integers with no seven, 83 00:05:40,832 --> 00:05:41,792 它就会输出个不停 it goes off printing. 84 00:05:45,100 --> 00:05:47,070 你可能需要等上很久才能得到全部结果 You may have to wait a very long time to see them all. 85 00:05:52,670 --> 00:05:53,840 你可能会问了 Well, you can start asking, gee, 86 00:05:54,816 --> 00:05:57,008 这个数据结构 you know, is it really true that this data structure 87 00:05:58,288 --> 00:06:00,656 真的全部是由整数构成的吗? with the integers is really all the integers? 88 00:06:01,100 --> 00:06:04,053 现在我画一个图来演示下刚写的那个程序 And let me draw a picture of that program I just wrote. 89 00:06:04,960 --> 00:06:10,570 这是我刚才键入的整数定义 Here's the, right, here's the definition of the integers again that I just typed in, 90 00:06:12,336 --> 00:06:15,984 它是一个由第一个整数和由下一个整数生成的流 所构成的序对 Right it's a cons of the first integer under the integer starting with the rest. 91 00:06:17,616 --> 00:06:19,770 现在我们画个图来看看它到底是什么样 Now, we can make a picture of that and see what it looks like. 92 00:06:22,720 --> 00:06:24,320 从概念上来说 这应该是一个盒子 Conceptually, what I have is a box 93 00:06:25,536 --> 00:06:27,184 这个盒子是(INTEGER-FROM N) that's the integer starting with n. 94 00:06:27,420 --> 00:06:29,088 它接受一个参数N It takes in some number n, 95 00:06:31,424 --> 00:06:32,976 然后返回一个流 and it's going to return a stream of-- 96 00:06:35,024 --> 00:06:37,360 这个无穷流表示从N开始的所有整数 this infinite stream of all integers starting with n. 97 00:06:38,080 --> 00:06:38,736 我要做什么呢? And what do I do? 98 00:06:38,752 --> 00:06:42,384 呃 这个是INT-FROM盒子 Well, this is an integers-from box. 99 00:06:45,070 --> 00:06:45,800 里面是什么样子呢? What's it got in it? 100 00:06:45,800 --> 00:06:48,608 取得参数N之后 Well, it takes in this n, 101 00:06:52,272 --> 00:06:53,920 将其 +1 and it increments it. 102 00:06:57,952 --> 00:07:03,150 然后把结果递归地传递给另一个INT-FROM盒子 And then it puts the result into recursively another integer's from box. 103 00:07:06,870 --> 00:07:09,600 把这个盒子的结果和最初的N It takes the result of that and the original n 104 00:07:10,240 --> 00:07:12,784 用CONS组合起来 and puts those together with a cons 105 00:07:13,392 --> 00:07:14,360 就形成了一个流 and forms a stream. 106 00:07:14,576 --> 00:07:17,264 我刚才写的那个过程 画出来就是这样子 So that's a picture of that program I wrote. And this is a ... 107 00:07:18,528 --> 00:07:20,320 我们看到的这类图像 Let's see. These kind of diagrams we first saw 108 00:07:20,784 --> 00:07:21,740 首先是由Peter Henderson提出的 drawn by Peter Henderson, 109 00:07:21,760 --> 00:07:23,320 也就是前面课程中绘图语言的发明者 the same guy who did the Escher language. 110 00:07:23,320 --> 00:07:24,752 我们把这种图叫做Henderson图 We call them Henderson diagrams. 111 00:07:25,376 --> 00:07:27,904 画这种图需要遵守一定的约定 And the convention here is that you put these things together. 112 00:07:28,530 --> 00:07:32,512 这些实线代表输出的流 And the solid lines are things coming out are streams, 113 00:07:33,024 --> 00:07:36,208 这些虚线则是初始的输入值 and dotted lines are initial values going in. 114 00:07:37,270 --> 00:07:39,024 而这个图描述的形状是—— So this one has the shape of-- 115 00:07:39,408 --> 00:07:41,600 它会取一个整数作为初始值 it takes in some integer, some initial value, 116 00:07:41,808 --> 00:07:42,912 然后输出一个流 and outputs a stream. 117 00:07:46,352 --> 00:07:48,224 现在 你可能又要问了 Again, you can ask. You know it's really 118 00:07:48,380 --> 00:07:50,880 那个INTEGERS的数据结构真的全部都是整数吗? Is that data structure integers really all the integers? 119 00:07:52,090 --> 00:07:54,912 或者它只是经过了精心组织 Alright? Or is it is something that's cleverly arranged 120 00:07:54,940 --> 00:07:56,432 以至于总可以在其中找到 so that whenever you look for an integer 121 00:07:56,448 --> 00:07:57,240 我们需要的那个整数? you find it there? 122 00:07:57,950 --> 00:07:59,744 这有点像个哲学问题 不是么? That's sort of a philosophical question, right? 123 00:07:59,780 --> 00:08:01,696 如果有一个东西 If something is there 124 00:08:02,144 --> 00:08:03,968 你不去观测它 能否知道它“存在”呢? whenever you look, is it really there or not? 125 00:08:04,450 --> 00:08:07,344 这就有点像 It's sort of the same sense in which 126 00:08:07,360 --> 00:08:09,420 你在银行中的存款那样 the money in your savings account is in the bank. 127 00:08:12,380 --> 00:08:12,640 好吧 Well 128 00:08:16,352 --> 00:08:17,488 我们再来看一个例子 let me do another example. 129 00:08:18,680 --> 00:08:20,704 这门课的第一节课 Umm, Gee, we started the course 130 00:08:20,720 --> 00:08:22,720 我们就讲了一个来自于亚历山大的算法 with an algorithm from Alexandria, 131 00:08:23,296 --> 00:08:25,800 来自亚历山大的Heron提出的 which was Heron of Alexandria's algorithm 132 00:08:25,824 --> 00:08:26,944 一个用于计算平方根的算法 for computing the square root. 133 00:08:28,470 --> 00:08:32,030 现在再来看一个 同样来自于亚力山大的算法 Let's take a look at another Alexandrian algorithm. 134 00:08:32,030 --> 00:08:35,088 这个被称为Eratosthenes算法的方法 This one is Eratosthenes method for 135 00:08:36,192 --> 00:08:38,448 用于计算所有的质数 for computing all of the primes. 136 00:08:41,169 --> 00:08:42,830 它被称为Eratosthenes筛法 It is called the Sieve of Eratosthenes. 137 00:08:42,830 --> 00:08:49,728 它是这样的 一开始 And what you do is you start out, 138 00:08:50,992 --> 00:08:52,288 先列举所有的整数 and you list all the integers, 139 00:08:52,608 --> 00:08:53,536 从2开始 say, starting with 2. 140 00:08:53,880 --> 00:08:55,040 然后取第一个整数 And then you take the first integer, and you say, 141 00:08:55,088 --> 00:08:56,670 然后你发现 哦 2是一个质数 and you say, oh, that's prime. 142 00:08:57,310 --> 00:08:58,352 然后你考察剩余的整数 And then you go look at the rest, 143 00:08:58,688 --> 00:09:00,880 划掉其中可以被2整除的数 and you cross out all the things divisible by 2. 144 00:09:01,520 --> 00:09:04,736 我把这个划掉 还有这个 这个 So I cross out this and this and this. 145 00:09:05,250 --> 00:09:06,352 有点费时 This takes a long time 146 00:09:06,368 --> 00:09:08,912 我要对所有的整数进行这样的操作 because I have to do it for all of the integers. 147 00:09:11,160 --> 00:09:15,392 我遍历整个整数表 So I go through the entire list of integers, 148 00:09:18,272 --> 00:09:20,944 划掉所有被2整除的数 crossing the ones divisible by 2. 149 00:09:22,112 --> 00:09:24,384 所有的整数都操作完后 And now when I finish with all of the integers, 150 00:09:24,784 --> 00:09:26,720 回过头再来看还剩些什么 I go back and look and say what am I left with? 151 00:09:27,040 --> 00:09:28,800 好的 下一个数就是3了 Well, the first thing that starts there is 3. 152 00:09:29,330 --> 00:09:30,336 3也是一个质数 So 3 is a prime. 153 00:09:30,770 --> 00:09:33,056 现在 我会继续在剩下的数中 And now I go back through what I'm left with, 154 00:09:33,360 --> 00:09:35,072 划掉所有被3整除的数 and I cross out all the things divisible by 3. 155 00:09:35,080 --> 00:09:43,808 划掉 9、15、21、27、33 等等 So let's see, 9 and 15 and 21 and 27 and 33 and so on. 156 00:09:44,336 --> 00:09:45,120 我就不往下划了 I won't finish. 157 00:09:45,350 --> 00:09:46,528 然后看看我们还剩下什么 Then I see what I'm left with. 158 00:09:47,250 --> 00:09:49,840 而下一个就是5了 And the next one I have is 5. 159 00:09:50,496 --> 00:09:52,048 我又遍历剩下的数 Now I can through the rest, 160 00:09:52,432 --> 00:09:54,512 找到第一个能被5整除的数 and I find the first one that's divisible by 5. 161 00:09:54,540 --> 00:09:57,616 把剩下的能被5整除的数都划掉 I cross out from the remainder all the ones that are divisible by 5. 162 00:09:58,352 --> 00:09:59,248 做完这个之后 And I did that, 163 00:09:59,824 --> 00:10:01,890 下一个数就是7 and then I go through and find 7. 164 00:10:01,890 --> 00:10:02,720 再遍历剩下的数 Go through all the rest, 165 00:10:02,760 --> 00:10:03,952 划掉所有被7整除的数 cross out things divisible 7, 166 00:10:03,984 --> 00:10:05,470 然后一直这样下去 and I keep doing that forever. 167 00:10:06,810 --> 00:10:07,408 全部结束的时候 And when I'm done, 168 00:10:07,408 --> 00:10:09,104 我也就得到了所有的质数 what I'm left with is a list of all the primes. 169 00:10:09,904 --> 00:10:13,312 这就是Eratosthenes筛法 So that's the Sieve of Eratosthenes. 170 00:10:15,430 --> 00:10:17,696 我们来看下实际代码 Let's look at it as a computer program. 171 00:10:17,930 --> 00:10:19,856 这个过程命名为SIEVE It's a procedure called sieve. 172 00:10:27,910 --> 00:10:29,408 这是对应的代码 Now, I just write what I did. 173 00:10:30,336 --> 00:10:34,480 SIEVE过程 以一个流S为参数 I'll say to sieve some stream s. 174 00:10:38,770 --> 00:10:39,936 返回一个新的流 I'm going to build a stream 175 00:10:40,272 --> 00:10:41,840 新的流的头部分 就是流S的头部分 whose first element is the head of this. 176 00:10:41,870 --> 00:10:44,432 回忆一下 我总是取剩下的数中的第一个 Remember, I always found the first thing I was left with, 177 00:10:44,912 --> 00:10:48,752 而尾部分则是把流S的尾部分 and the rest of it is the result of taking the tail of S, 178 00:10:51,080 --> 00:10:53,728 过滤掉所有 filtering it to throw away all the things 179 00:10:53,744 --> 00:10:55,320 能被S头部分整除的数 that are divisible by the head of S, 180 00:10:56,416 --> 00:10:57,568 然后再对结果筛选 and now sieving the result. 181 00:10:59,020 --> 00:11:00,096 这个代码就是这样 That's just what I did. 182 00:11:01,980 --> 00:11:04,688 现在 为了得到由质数构成的无穷流 And now to get the infinite stream of times, 183 00:11:05,024 --> 00:11:06,900 我们对从2开始的整数流进行SIEVE we just sieve all the integers starting from 2. 184 00:11:14,920 --> 00:11:15,568 我们来实践一下 Let's try that. 185 00:11:16,300 --> 00:11:18,304 实际上 我们可以在计算机中运行 We can actually do it. 186 00:11:19,760 --> 00:11:22,128 我希望我已经预先输入过SIEVE的定义了 I typed in the definition of sieve before, I hope, 187 00:11:22,864 --> 00:11:24,064 所以我可以定义 so I can say something like 188 00:11:24,928 --> 00:11:33,456 我可以把PRIMES定义为 define the primes to be 189 00:11:34,640 --> 00:11:41,456 (SIEVE (INTEGERS-FROM 2)) the result of sieving the integers starting with 2. 190 00:11:46,760 --> 00:11:48,100 现在我就得到了质数构成的表 So now I've got this list of primes. 191 00:11:48,100 --> 00:11:50,990 这样就得到了所有的质数 对吧? That's all of the primes, right? 192 00:11:50,990 --> 00:11:53,520 比如我可以问 第20个质数是什么? So, if for example, what's the 20th prime in that list? 193 00:12:00,736 --> 00:12:01,680 结果是73 73. 194 00:12:02,540 --> 00:12:03,344 那个短促的停顿 See, and that little pause, 195 00:12:03,360 --> 00:12:04,928 这是因为 it was only at the point 196 00:12:04,940 --> 00:12:06,432 在我询问第20个元素时 when I started asking for the 20th prime 197 00:12:06,464 --> 00:12:07,680 它才进行实际的计算 is that it started computing. 198 00:12:10,370 --> 00:12:11,296 在这里 我也可以要求 Or I can say here 199 00:12:13,808 --> 00:12:14,880 打印所有的质数 Or I can say here let's look at all of the primes. 200 00:12:22,640 --> 00:12:24,400 解释器就开始计算并打印所有的质数 And there it goes computing all of the primes. 201 00:12:25,350 --> 00:12:26,288 得花上好一会儿 Of course, it will take a while 202 00:12:26,288 --> 00:12:27,610 才能打赢完整 again if I want to look at all of them, 203 00:12:27,792 --> 00:12:28,570 所以先把它停掉 so let's stop it. 204 00:12:32,030 --> 00:12:33,130 让我来画图演示一下 Let me draw you a picture of that. 205 00:12:33,130 --> 00:12:34,176 我已经画好了 Well, I've got a picture of that. 206 00:12:34,890 --> 00:12:36,192 这个过程的图形应该是什么样子呢? What's that program really look like? 207 00:12:37,900 --> 00:12:39,776 用这类图形的约定来说 Again, some practice with these diagrams, 208 00:12:39,824 --> 00:12:40,544 我有一个叫SIEVE的盒子 I have a sieve box. 209 00:12:42,610 --> 00:12:43,560 它是如何运作的呢? How does sieve work? 210 00:12:43,560 --> 00:12:44,810 它以一个流作为输入 It takes in a stream. 211 00:12:48,850 --> 00:12:50,592 分离流的头、尾部分 It splits off the head from the tail. 212 00:12:50,870 --> 00:12:53,264 从SIEVE盒子出来的第一个东西 And the first thing that's going to come out of the sieve 213 00:12:53,488 --> 00:12:54,976 就是原来流的头部分 is the head of the original stream. 214 00:12:58,208 --> 00:13:00,928 头部分同样也用于这个盒子 Then it also takes the head and uses that. 215 00:13:02,550 --> 00:13:05,104 这个盒子会过滤流的尾部分 It takes the stream. It filters the tail 216 00:13:05,552 --> 00:13:08,336 过滤的依据是 能否被头部分整除 It filters the tail and uses the head to filter for nondivisibility. 217 00:13:09,536 --> 00:13:11,184 过滤得到的不可整除的那些数 It takes the result of nondivisibility 218 00:13:11,248 --> 00:13:13,120 再放入另一个SIEVE盒子 and puts it through another sieve box 219 00:13:13,904 --> 00:13:15,130 然后把它们组合输出 and puts the result together. 220 00:13:15,130 --> 00:13:16,896 你可以把SIEVE想象为一个过滤器 So you can think of this sieve a filter, 221 00:13:17,200 --> 00:13:19,232 只不过它是一个无穷递归的过滤器 but notice that it's an infinitely recursive filter. 222 00:13:19,650 --> 00:13:20,880 这是因为在SIEVE盒子中 Because inside the sieve box 223 00:13:21,520 --> 00:13:22,608 还有另外一个SIEVE盒子 is another sieve box, 224 00:13:23,376 --> 00:13:25,856 内部的盒子里面还有另外一个SIEVE盒子 and inside that is another sieve box and another sieve box. 225 00:13:27,130 --> 00:13:28,960 我们现在逐渐有了非常厉害的能力 So you see we start getting some very powerful things. 226 00:13:28,960 --> 00:13:32,848 我们开始把 信号处理的方法 We're starting to mix this signal processing view of the world 227 00:13:33,904 --> 00:13:36,416 和计算中的递归结合在一起 来建模世界 with things like recursion that come from computation. 228 00:13:37,424 --> 00:13:39,824 还有很多像是这样的事 And there are all sorts of interesting things you can do that are like this. 229 00:13:40,970 --> 00:13:42,096 好的 有什么问题吗? All right, any questions? 230 00:13:48,190 --> 00:13:49,168 好吧 那我们休息一下 OK, let's take a break. 231 00:13:49,640 --> 00:14:04,128 [音乐] [JESU, JOY OF MAN'S DESIRING] 232 00:14:04,464 --> 00:14:08,120 《计算机程序的构造和解释》 233 00:14:12,080 --> 00:14:16,384 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 234 00:14:16,448 --> 00:14:20,220 《计算机程序的构造和解释》 235 00:14:20,352 --> 00:14:25,056 流 II 236 00:14:28,650 --> 00:14:30,368 我们已经看了 Well, we've been looking at a couple 237 00:14:30,368 --> 00:14:32,090 好几个流式程序设计的例子 of examples of stream programming. 238 00:14:34,790 --> 00:14:39,216 我们目前接触到的流过程 All the stream procedures that we've looked at so far 239 00:14:39,728 --> 00:14:41,328 都有一个共同的特征 have the same kind of character. 240 00:14:41,490 --> 00:14:43,632 这些过程总是递归地 We've been writing these recursive procedures 241 00:14:44,160 --> 00:14:46,496 一次生成一个元素 that kind of generate these stream elements one at a time 242 00:14:46,510 --> 00:14:48,720 再用CONS-STREAM连接起来 and put them together in cons-streams. 243 00:14:49,152 --> 00:14:50,864 因此 我们一直把它当作是生成器 So we've been thinking a lot about generators. 244 00:14:50,928 --> 00:14:53,632 还有一种思考流式程序设计的方式 There's another way to think about stream processing, 245 00:14:53,790 --> 00:14:56,960 我们不认为程序是 and that's to focus not on programs that sort of 246 00:14:57,360 --> 00:14:59,930 沿着流逐一处理元素 process these elements as you walk down the stream, 247 00:15:00,256 --> 00:15:05,680 而是一下子处理了整个流 but on things that kind of process the streams all at once. 248 00:15:07,180 --> 00:15:09,168 我先来定义两个非常有用的过程 To show you what I mean, let me start by defining 249 00:15:09,232 --> 00:15:11,500 来帮助我说明 two procedures that will come in handy. 250 00:15:12,410 --> 00:15:13,600 第一个过程是ADD-STREAMS The first one's called add streams. 251 00:15:15,360 --> 00:15:18,256 它接受两个流作为参数 Add streams takes two streams: 252 00:15:18,816 --> 00:15:20,880 S1和S2 s1 and s2. 253 00:15:22,300 --> 00:15:24,672 它生成一个新的流 And it's going to produce a stream 254 00:15:24,992 --> 00:15:28,176 其元素是两个流相应位置元素的和 whose elements are the are the corresponding sums 255 00:15:30,224 --> 00:15:31,888 相当于是“按元素”的加 We just sort of add them element-wise. 256 00:15:32,970 --> 00:15:33,952 如果其中一个流是空的 If either stream is empty, 257 00:15:33,968 --> 00:15:35,390 我们就返回另一个 we just return the other one. 258 00:15:36,810 --> 00:15:38,960 否则 我们就构建一个新的流 Otherwise, we're going to make a new stream 259 00:15:39,904 --> 00:15:42,960 新流的头部分是两个流头部分之和 whose head is the sum of the two heads 260 00:15:44,000 --> 00:15:44,880 而新流的尾部分 whose tail 261 00:15:46,000 --> 00:15:48,624 则是递归地加和尾部分 is the result of recursively adding the tails. 262 00:15:50,090 --> 00:15:52,736 这就会产生“按元素”地加的效果 So that will produce the element-wise sum of two streams. 263 00:15:53,150 --> 00:15:57,040 另一个过程是SCALE-STREAM And then another useful thing to have around is scale stream. 264 00:15:57,500 --> 00:16:01,664 SCALE-STREAM有两个参数 常数C和流S Scale stream takes some constant number in a stream s 265 00:16:04,112 --> 00:16:06,624 结果生成的流 and is going to produce the stream 266 00:16:07,184 --> 00:16:09,504 就是将流S的所有元素乘上了C of elements of s multiplied by this constant. 267 00:16:09,710 --> 00:16:11,216 这很简单 就是一个MAP And that's easy, that's just a map 268 00:16:12,208 --> 00:16:16,224 用到的函数是 X*C of the function of an element that multiplies it by the constant, 269 00:16:16,352 --> 00:16:17,808 把这个函数MAP于整个流 and we map that down the stream. 270 00:16:20,064 --> 00:16:21,472 有了这两个过程 So given those two, 271 00:16:22,640 --> 00:16:24,368 我来给你们解释 什么叫做 let me show you what I mean by programs that 272 00:16:24,704 --> 00:16:27,008 “一下子处理整个流” that operate on streams all at once. 273 00:16:28,128 --> 00:16:28,736 我们来看这个 Let's look at this. 274 00:16:30,200 --> 00:16:30,928 假设这样 Suppose I write this. 275 00:16:31,680 --> 00:16:52,352 (DEFINE ONES (CONS-STREAM 1 ONES)) I say define-- I'll call it ones-- to be cons-stream of 1 onto ones. 276 00:16:54,860 --> 00:16:55,520 这是什么? What's that? 277 00:16:56,950 --> 00:16:58,944 这是一个表示无穷个1的流 That's going to be an infinite stream of ones 278 00:16:59,968 --> 00:17:01,440 因为第一个元素是1 because the first thing is 1. 279 00:17:03,330 --> 00:17:05,152 尾部分则是这样的 And the tail of it is a thing 280 00:17:05,552 --> 00:17:06,832 它的头部分是1 whose first thing is 1 281 00:17:07,630 --> 00:17:09,024 它的尾部分 whose tail is a thing 282 00:17:09,120 --> 00:17:10,240 的头部分又为1 whose first thing is 1 283 00:17:10,528 --> 00:17:11,780 以此类推 and so on and so on. 284 00:17:11,780 --> 00:17:13,328 这就是无穷个1的流 So that's an infinite stream of ones. 285 00:17:15,130 --> 00:17:15,936 现在根据ONES And now using that, 286 00:17:16,128 --> 00:17:18,032 我再给出另一种定义整数的方式 let me give you another definition of the integers. 287 00:17:19,472 --> 00:17:27,360 (DEFINE INTEGERS We can define the integers to be-- 288 00:17:28,240 --> 00:17:30,768 当然 第一个数是1 well, the first integer we'll take to be 1, 289 00:17:32,752 --> 00:17:38,576 (CONS-STREAM 1 (ADD-STREAM his cons-stream of 1 onto the element-wise sum 290 00:17:40,224 --> 00:17:48,270 INTEGERS ONES))) onto add streams of the integers to ones. 291 00:17:55,100 --> 00:17:56,352 整数流是这样的: The integers are a thing 292 00:17:57,248 --> 00:17:59,984 它的第一个元素是1 whose first element is 1, 293 00:18:00,880 --> 00:18:02,320 而其余部分则是 and the rest of them you get 294 00:18:03,120 --> 00:18:06,144 依次把每个整数加1 by taking those integers and incrementing each one by one. 295 00:18:06,640 --> 00:18:08,192 因此 整数流的第二个元素则是 So the second element of the integers 296 00:18:08,512 --> 00:18:11,968 整数流的第一个元素加1 is the first element of the integers incremented by one. 297 00:18:13,920 --> 00:18:15,184 下一个数又要加1 And the rest of that is the next one, 298 00:18:15,200 --> 00:18:16,480 第三个元素则是 and the third element of that 299 00:18:16,620 --> 00:18:20,416 INTEGER流尾部分的第一个元素 is the same as the first element of the tail of the integers 300 00:18:20,848 --> 00:18:21,960 加1 incremented by one, 301 00:18:22,512 --> 00:18:23,760 这也就相当于 which is the same as the 302 00:18:25,088 --> 00:18:28,656 最初整数流的第一个元素加1 first element of the original integers incremented by one 303 00:18:28,864 --> 00:18:31,250 然后再加1 以此类推 and incremented by one again and so on. 304 00:18:35,240 --> 00:18:36,310 这看起来有点匪夷所思 That looks pretty suspicious. 305 00:18:36,310 --> 00:18:37,472 这样的过程可以正常运行 See, notice that it works 306 00:18:38,128 --> 00:18:38,990 关键在于延时求值 because of delay. 307 00:18:40,150 --> 00:18:43,328 我们来看这个ONES See, this looks like-- let's take a look at ones. 308 00:18:43,870 --> 00:18:45,920 这看起来根本不可能 This looks like it couldn't even be processed 309 00:18:46,256 --> 00:18:47,632 因为它突然说 because it's suddenly saying 310 00:18:47,792 --> 00:18:48,960 在定义ONES的时候 in order to know what ones is, 311 00:18:49,008 --> 00:18:50,912 发现它依赖于它本身 I say it's cons-stream of something onto ones. 312 00:18:51,130 --> 00:18:52,080 它之所以可以运行是因为 The reason that works 313 00:18:52,096 --> 00:18:54,040 这里暗中隐藏着延时求值 because of that very sneaky hidden delay in there. 314 00:18:55,250 --> 00:18:56,560 这个代码实际上是 Because what this really is, 315 00:18:57,792 --> 00:18:59,696 回忆下 CONS-STREAM是只是一个缩写 remember, cons-stream is just an abbreviation. 316 00:19:00,290 --> 00:19:01,152 实际上则是 This really is 317 00:19:01,856 --> 00:19:08,992 (CONS 1 (DELAY ONES)) cons of 1 onto delay of ones. 318 00:19:12,140 --> 00:19:13,216 它又是怎么运作的呢? So how does that work? 319 00:19:15,500 --> 00:19:16,880 你想要定义ONES You say I'm going to define ones. 320 00:19:18,020 --> 00:19:20,240 我来看看ONES要被定义成什么样 First I see what ones is supposed to be defined as. 321 00:19:20,700 --> 00:19:23,408 ONES被定义为一个序对 Well, ones is supposed to be defined as 322 00:19:24,896 --> 00:19:28,112 其CAR部分为1 a cons whose first part is 1 323 00:19:28,320 --> 00:19:29,456 而CDR部分则是 and the second part is, 324 00:19:29,450 --> 00:19:30,736 是一个计算某物的PROMISE well, it's a promise to compute something 325 00:19:30,752 --> 00:19:31,690 我现在还不用关心 that I don't worry about yet. 326 00:19:32,710 --> 00:19:34,256 所以虽然这时ONES还没有定义 So it doesn't bother me that at the point 327 00:19:34,288 --> 00:19:36,300 但对我并不造成什么影响 I do this definition, ones isn't defined. 328 00:19:37,270 --> 00:19:39,456 一旦运行了整个定义 ONES就被定义了 Having run the definition, now ones is defined. 329 00:19:40,670 --> 00:19:42,832 所以 访问它尾部的时候 它就有定义了 So that when I go and look at the tail of it, it's defined. 330 00:19:44,920 --> 00:19:46,064 这一点非常隐讳 It's very sneaky. 331 00:19:46,590 --> 00:19:47,904 整数流的定义也是如此 And an integer is the same way. 332 00:19:48,470 --> 00:19:50,464 我可以在这里引用INTEGERS是因为 I can refer to integers here because 333 00:19:51,136 --> 00:19:53,210 是因为这个CONS-STREAM的缘故 hidden way down-- because of this cons-stream. 334 00:19:53,850 --> 00:19:55,248 用CONS-STREAM把1 It's the cons-stream of 1 335 00:19:55,376 --> 00:19:57,050 和一个不立即需要的东西组合起来 onto something that I don't worry that yet. 336 00:19:57,050 --> 00:19:59,600 所以我在运行INTEGERS的定义的时候 So I don't look at it, and I don't notice that integers isn't defined 337 00:20:00,224 --> 00:20:01,904 并不会发现INTEGER没有定义过 at the point where I try and run the definition. 338 00:20:06,320 --> 00:20:08,272 听上去非常玄乎 OK, let me draw a picture of that integers thing 339 00:20:08,448 --> 00:20:11,504 让我用图像来演示一下INTEGERS的原理 because it still maybe seems a little bit shaky. 340 00:20:12,430 --> 00:20:14,720 怎么画呢? What do I do? Uh... 341 00:20:15,020 --> 00:20:16,304 首先是ONES这个流 I've got the stream of ones, 342 00:20:20,510 --> 00:20:21,888 它作为参数输入 and that sort of comes in 343 00:20:23,260 --> 00:20:24,928 进入一个加法器 comes in and goes into an adder 344 00:20:24,960 --> 00:20:26,590 进行流的加法运算 that's going to be this add streams thing. 345 00:20:29,310 --> 00:20:35,872 输出则是整数流INTEGERS And that goes in-- that's going to put out the integers. 346 00:20:40,760 --> 00:20:42,704 这里 这个整数流又重新进入加法器 And the other thing that goes into the adder here 347 00:20:44,944 --> 00:20:46,976 形成了一个小型的反馈回路 is the integer, so there's a little feedback loop. 348 00:20:48,060 --> 00:20:49,424 我需要在某处接入最初的ONES And all I need to start it off 349 00:20:50,096 --> 00:20:52,880 才能让它生效 is someplace I've got a stick that initial 1. 350 00:20:57,100 --> 00:20:58,640 在真实的信号处理中 In a real signal processing thing, 351 00:20:58,720 --> 00:21:02,480 这里是一个被初始化为1的延时元件 this might be a delay element with that was initialized to 1. 352 00:21:02,910 --> 00:21:05,904 这就是ONES程序的图示 But there's a picture of that ones program. 353 00:21:07,860 --> 00:21:09,632 事实上 这个非常像 And in fact, that looks a lot like-- 354 00:21:09,808 --> 00:21:13,776 如果你见过真正的信号方块图的话 if you've seen real signal block diagram things, 355 00:21:13,776 --> 00:21:16,304 这个图形非常像累加器 that looks a lot like accumulators, 356 00:21:16,352 --> 00:21:17,488 有穷状态累加器 finite state accumulators. 357 00:21:17,980 --> 00:21:20,064 事实上 我们可以稍加修改 And in fact, we can modify this a little bit 358 00:21:21,184 --> 00:21:23,968 就可以让它对一个流做积分 to change this into something that integrates a stream 359 00:21:25,370 --> 00:21:26,976 或者说是有穷状态累加器 or a finite state accumulator, 360 00:21:27,008 --> 00:21:28,040 你怎么认为都可以 however you like to think about it. 361 00:21:28,440 --> 00:21:30,864 现在 不再是输入ONES 输出INTEGERS So instead of the ones coming in and getting out the integers, 362 00:21:31,680 --> 00:21:32,384 我们要做的是 what we'll do is 363 00:21:32,912 --> 00:21:34,832 这里有一个流S为输入 say there's a stream s coming in, 364 00:21:35,760 --> 00:21:40,560 我们要计算这个流的积分 and we're going to get out the integral of this. 365 00:21:42,600 --> 00:21:44,096 也就是累加这个流的值 successive values of that, 366 00:21:44,448 --> 00:21:45,630 这看起来几乎就是一样的 and it looks almost the same. 367 00:21:45,660 --> 00:21:46,848 我们要做的就是 The only thing we're going to do is 368 00:21:47,024 --> 00:21:48,080 当S从这里输入时 when s comes in here, 369 00:21:49,216 --> 00:21:50,640 在把它求和之前 before we just add it in 370 00:21:50,912 --> 00:21:54,260 先将其乘以dt we're going to multiply it by some number dt. 371 00:21:57,680 --> 00:22:00,000 剩下的就不用改了 And now what we have here, this is exactly the same thing. 372 00:22:00,000 --> 00:22:00,912 我们就得到了一个盒子 We have a box, 373 00:22:03,360 --> 00:22:04,560 一个积分器 which is an integrator. 374 00:22:09,790 --> 00:22:11,264 对一个流S进行积分 And it takes in a stream s, 375 00:22:11,904 --> 00:22:14,512 把这里的1替换为 and instead of 1 here, 376 00:22:14,944 --> 00:22:18,352 该积分的初始值 we can put the additional value for the integral. 377 00:22:19,980 --> 00:22:21,600 这个看起来就非常像 And that one looks very much like a 378 00:22:22,352 --> 00:22:24,860 信号处理中的方框图了 a signal processing block diagram program. 379 00:22:25,270 --> 00:22:28,112 事实上 这个图示对应的是这样一个过程 In fact, here's the procedure that looks exactly like that. 380 00:22:31,490 --> 00:22:33,616 对一个流进行积分 Find the integral of a stream. 381 00:22:34,010 --> 00:22:35,488 INTEGRAL函数接收一个流 So an integral's going to take a stream 382 00:22:35,680 --> 00:22:36,864 返回一个新的流 Sand produce a new stream, 383 00:22:37,530 --> 00:22:40,672 它还接收一个初始值和某个时间常量 and it takes in an initial value and some time constant. 384 00:22:42,230 --> 00:22:42,976 然后呢? And what do we do? 385 00:22:43,040 --> 00:22:45,056 首先在内部定义一个流INT Well, we internally define this thing int, 386 00:22:45,200 --> 00:22:46,320 之所以要给它一个内部名字 and we make this internal name 387 00:22:46,336 --> 00:22:48,860 原因在于可以使它反馈 以形成循环 so we can feed it back, loop it around itself. 388 00:22:49,400 --> 00:22:50,800 INT的定义是 And int is defined to be 389 00:22:51,104 --> 00:22:53,328 一个以INITIA-VALUE开始的流 something that starts out at the initial value, 390 00:22:54,976 --> 00:23:00,144 而其余的元素则是把它们加起来 and the rest of it is gotten by adding together. 391 00:23:01,280 --> 00:23:03,616 我们把输入流乘以dt We take our input stream, scale it by dt, 392 00:23:03,872 --> 00:23:04,928 然后和INT相加 and add that to int. 393 00:23:06,880 --> 00:23:09,664 整个INTEGRAL函数的结果就是这个INT And now we'll return from all that the value of integral is this thing int. 394 00:23:10,690 --> 00:23:12,944 我们使用这种内部定义的语法 And we use this internal definition syntax so we could 395 00:23:13,344 --> 00:23:15,664 是为了可以在内部引用它自己 write a little internal definition that refers to itself. 396 00:23:21,880 --> 00:23:23,710 我们还可以做更多的事情 Well, there are all sorts of things we can do. 397 00:23:23,710 --> 00:23:24,512 来看这个 Let's try this one. 398 00:23:25,632 --> 00:23:26,890 斐波那契数 how about the Fibonacci numbers. 399 00:23:26,895 --> 00:23:32,625 (DEFINE FIBS You can say define fibs. 400 00:23:36,350 --> 00:23:37,632 斐波那契数是什么呢? Well, what are the Fibonacci numbers? 401 00:23:37,980 --> 00:23:46,544 它从0开始 They're something that starts out with 0, 402 00:23:48,656 --> 00:23:50,090 下一个是1 and the next one is 1. 403 00:23:56,260 --> 00:23:59,168 的其余的斐波那契数是通过 And the rest of the Fibonacci numbers are gotten by 404 00:23:59,872 --> 00:24:11,000 把它们的尾部分求和而得来 adding the Fibonacci numbers to their own tail. 405 00:24:17,570 --> 00:24:19,280 这样来定义斐波那契数 There's a definition of the Fibonacci numbers. 406 00:24:20,580 --> 00:24:21,430 这是如何运作的呢? How does that work? 407 00:24:21,430 --> 00:24:24,192 我们来试试 Well, we start off, 408 00:24:24,208 --> 00:24:26,490 假如开始计算斐波那契数 and someone says compute for us the Fibonacci numbers, 409 00:24:29,648 --> 00:24:31,920 首先告诉你 它以0和1开始 and we're going to tell you it starts out with 0 and 1. 410 00:24:35,790 --> 00:24:38,224 而0和1之后的数则是 And everything after the 0 and 1 411 00:24:39,184 --> 00:24:40,864 通过加和两个流而得 is gotten by summing two streams. 412 00:24:41,120 --> 00:24:42,592 一个流是FIBS本身 One is the fibs themselves, 413 00:24:44,064 --> 00:24:45,696 另一个是FIBS的尾部分 and the other one is the tail of the fibs. 414 00:24:49,120 --> 00:24:51,168 如果我知道这是以0和1起始的 So if I know that these start out with 0 and 1, 415 00:24:51,790 --> 00:24:55,424 我就能知道 FIBS是以0和1起始的 I know that the fibs now start out with 0 and 1, 416 00:24:55,744 --> 00:24:57,408 那么 FIBS的尾部分则应该以1开始 and the tail of the fibs start out with 1. 417 00:24:58,360 --> 00:24:59,456 一旦我知道了这点 So as soon as I know that, 418 00:24:59,664 --> 00:25:02,112 我就知道 FIBS的下一个数就是0+1=1 I know that the next one here is 0 plus 1 is 1, 419 00:25:02,960 --> 00:25:04,608 它也同样告诉我这里是1 and that tells me that the next one here is 1 420 00:25:04,624 --> 00:25:05,728 这里也是1 and the next one here is 1. 421 00:25:06,300 --> 00:25:07,280 知道了这些之后 And as soon as I know that, 422 00:25:07,296 --> 00:25:08,760 我就知道下一个是2 I know that the next one is 2. 423 00:25:09,390 --> 00:25:11,700 这里是2 这里也是2 So the next one here is 2 and the next one here is 2. 424 00:25:11,700 --> 00:25:12,560 下一个是3 And this is 3. 425 00:25:14,720 --> 00:25:15,792 这里是3 This one goes to 3, 426 00:25:16,192 --> 00:25:17,136 这里是5 and this is 5. 427 00:25:18,672 --> 00:25:19,968 这个定义完全说得通 So it's a perfectly sensible definition. 428 00:25:21,500 --> 00:25:22,784 这个定义只有一行 It's a one-line definition. 429 00:25:22,830 --> 00:25:25,008 当然 我也可以在计算机中 And again, I could walk over to the computer 430 00:25:25,008 --> 00:25:26,624 原原本本地键入计算机中 and type that in, exactly that, 431 00:25:27,040 --> 00:25:28,944 然后要求输出斐波那契数 and then say print stream the Fibonacci numbers, 432 00:25:28,944 --> 00:25:30,150 然后它就会不断输出 and they all come flying out. 433 00:25:32,790 --> 00:25:35,200 这又像是在学习递归 See, this is a lot like learning about recursion again. 434 00:25:36,810 --> 00:25:39,792 过程可以被递归定义 Instead of thinking that recursive procedures, 435 00:25:40,992 --> 00:25:43,504 我们也可以递归地定义数据对象 we have recursively defined data objects. 436 00:25:45,160 --> 00:25:46,928 但你们一点儿不应该感到吃惊 But that shouldn't surprise you at all, 437 00:25:47,120 --> 00:25:49,504 因为现在 你们应该真正相信 because by now, you should be coming to really believe 438 00:25:49,520 --> 00:25:53,056 过程与数据之间没有区别 that there's no difference really between procedures and data. 439 00:25:53,090 --> 00:25:53,920 事实上 就某种意义上来说 In fact, in some sense, 440 00:25:53,936 --> 00:25:56,416 流也是由过程来实现的 the underlying streams are procedures sitting there, 441 00:25:56,432 --> 00:25:57,790 只不过我们不把它看做过程而已 although we don't think of them that way. 442 00:25:58,210 --> 00:26:00,384 因此既然我们有递归过程 So the fact that we have recursive procedures, 443 00:26:00,704 --> 00:26:03,630 那么 有递归数据也就不足为奇了 well, then it should be natural that we have recursive data, too. 444 00:26:07,728 --> 00:26:09,696 虽然流非常简洁 OK, well, this is all pretty neat. 445 00:26:09,720 --> 00:26:13,920 但不幸的是 有些问题流无法解决 Unfortunately, there are problems that streams aren't going to solve. 446 00:26:14,990 --> 00:26:16,480 我来举个例子 Let me show you one of them. 447 00:26:17,580 --> 00:26:20,352 同样地 我们来想象一下 See, in the same way, let's imagine that we're 448 00:26:20,768 --> 00:26:23,616 我们正在构建求解微分方程的模拟计算机 building an analog computer to solve some differential equation 449 00:26:25,200 --> 00:26:34,304 比如求解方程 y' = y^2 like, say, we want to solve the equation y prime dy dt is y squared, 450 00:26:34,760 --> 00:26:36,160 我会给你一个初值 and I'm going to give you some initial value. 451 00:26:36,390 --> 00:26:38,030 y(0) = 1 I'll tell you y of 0 equals 1. 452 00:26:41,488 --> 00:26:44,064 dt = .0001 Let's say dt is equal to something. 453 00:26:46,770 --> 00:26:47,536 很久之前 Now, in the old days, 454 00:26:48,000 --> 00:26:50,650 就有人构建模拟计算机 来解决这类问题 people built analog computers to solve these kinds of things. 455 00:26:51,360 --> 00:26:53,020 原理非常简单 And the way you do that is really simple. 456 00:26:53,020 --> 00:26:54,416 你首先需要一个积分器 You get yourself an integrator, 457 00:27:00,048 --> 00:27:01,696 比如这个INT盒子 like that one, an integrator box. 458 00:27:03,050 --> 00:27:06,480 我们设定初始值 y(0) = 1 And we put in the initial value y of 0 is 1. 459 00:27:08,530 --> 00:27:10,928 现在如果我们送入一个输入 就会得到输出 And now if we feed something in and get something out, 460 00:27:10,960 --> 00:27:13,168 输出的结果就是y we'll say, gee, what we're getting out is the answer. 461 00:27:14,256 --> 00:27:16,960 输入的是y的导数 And what we're going to feed in is the derivative, 462 00:27:17,520 --> 00:27:20,528 在这里 导数 y' = y^2 and the derivative is supposed to be the square of the answer. 463 00:27:21,490 --> 00:27:27,072 如果我们用MAP把SQUARE映射在这些值上 So if we take these values and map using square, 464 00:27:30,736 --> 00:27:32,096 然后把这个引过来 and if I feed this around, 465 00:27:36,280 --> 00:27:38,480 这个方块图 that's how I build a block diagram 466 00:27:38,576 --> 00:27:41,088 就是用于求解这个微分方程的模拟计算机 for an analog computer that solves this differential equation. 467 00:27:42,910 --> 00:27:44,800 现在我们用代码 Now, what we'd like to do is write a stream 468 00:27:44,800 --> 00:27:46,780 来表示下这个过程 program that looks exactly like that. 469 00:27:47,230 --> 00:27:48,720 这个图究竟表示的是什么呢? And what do I mean exactly like that? 470 00:27:49,390 --> 00:27:58,304 (DEFINE Y Well, I'd say define y to be the integral 471 00:28:04,288 --> 00:28:11,680 (INTEGRAL DY 1 .001)) of dy starting at 1 with 0.001 as a time step. 472 00:28:13,790 --> 00:28:15,456 接下来 And I'd like to say that says this. 473 00:28:16,805 --> 00:28:20,850 通过MAP SQUARE 来表示dy And then I'd like to say, well, dy is gotten by mapping the square along y. 474 00:28:20,850 --> 00:28:32,816 (DEFINE DY (MAP SQUARE Y)) So define dy to be map square along y. 475 00:28:33,510 --> 00:28:36,800 这就是这个模拟计算机的流式描述 So there's a stream description of this analog computer, 476 00:28:38,624 --> 00:28:40,320 不幸的是 它并不起效 and unfortunately, it doesn't work. 477 00:28:41,410 --> 00:28:42,672 你也可以发现这是为什么 And you can see why it doesn't work 478 00:28:42,970 --> 00:28:44,992 因为我把Y定义为 because when I come in and say define y 479 00:28:46,432 --> 00:28:47,850 DY 的积分 to be the integral of dy 480 00:28:49,040 --> 00:28:50,656 它会问 对什么的积分? it says, oh, the integral of what-- huh? 481 00:28:51,190 --> 00:28:52,128 没定义啊 Oh, that's undefined. 482 00:28:53,710 --> 00:28:57,632 所以这个定义必须写在这个定义的后面 So I can't write this definition before I've written this one. 483 00:28:58,770 --> 00:29:00,512 另一方面 如果先定义了dy On the other hand, if I try and write this one first, 484 00:29:00,512 --> 00:29:03,024 定义为 (MAP SQUARE 某个东西) it says, oh, I define y to be the map of square along what? 485 00:29:03,580 --> 00:29:04,640 这个也还没有定义 Oh, that's not defined yet. 486 00:29:05,770 --> 00:29:08,176 我既不能先写这个 又不能先写那个 So I can't write this one first, and I can't write that one first. 487 00:29:09,088 --> 00:29:11,580 这个游戏就没法玩了 So I can't quite play this game. 488 00:29:17,560 --> 00:29:18,512 怎样来解决呢? Well, is there a way out? 489 00:29:20,608 --> 00:29:21,840 我们可以用ONES来解决 See, we can do that with ones. 490 00:29:22,200 --> 00:29:25,824 所以 我们在这里定义的ONES See, over here, we did this thing ones, 491 00:29:27,248 --> 00:29:29,904 我们之所以可以使用ONES来定义ONES and we were able to define ones in terms of ones because 492 00:29:30,400 --> 00:29:32,032 这是因为其中的延时求值 of this delay that was built inside 493 00:29:32,432 --> 00:29:34,128 CONS-STREAM是延时求值的 because cons-stream had a delay. 494 00:29:34,770 --> 00:29:35,792 那么 这又为什么说得通呢? Now, why's it sensible? 495 00:29:35,920 --> 00:29:38,512 为什么CONS-STREAM是延时求值的是合理的呢? Why's it sensible for cons-stream to be built with this delay? 496 00:29:40,730 --> 00:29:43,136 原因在于 CONS-STREAM不需要其尾部分 The reason is that cons-stream can do a useful thing 497 00:29:43,488 --> 00:29:44,880 就可以完成有意义的事 without looking at its tail. 498 00:29:45,950 --> 00:29:46,848 比如我说 See, if I say 499 00:29:47,488 --> 00:29:49,648 这个是1和某个东西组成的流 this is cons-stream of 1 onto something 500 00:29:49,920 --> 00:29:51,696 虽然我对它一无所知 without knowing anything about something, 501 00:29:52,160 --> 00:29:54,032 但我却知道整个流是以1开始的 I know that the stream starts off with 1. 502 00:29:54,870 --> 00:29:57,296 所以用CONS-STREAM来构造是有意义的 That's why it was sensible to build something like cons-stream. 503 00:29:59,960 --> 00:30:01,248 我们在这里放了一个DELAY So we put a delay in there, 504 00:30:01,424 --> 00:30:04,656 这就使得我们能够进行某种自引用的定义 and that allows us to have this sort of self-referential definition. 505 00:30:06,320 --> 00:30:07,952 INTEGRAL也可以用这种方式来解决 Well, integral is a little bit the same way. 506 00:30:08,190 --> 00:30:12,528 注意 对于INTEGRAL来说 我可以 See, notice for an integral, I can-- 507 00:30:14,608 --> 00:30:16,080 让我们回过头来再看看INTEGRAL的定义 let's go back and look at integral for a second. 508 00:30:17,580 --> 00:30:18,560 求积分的时候 See, notice integral, 509 00:30:21,392 --> 00:30:25,008 知道INTEGRAL的第一个元素是合理的 it makes sense to say what's the first thing in the integral 510 00:30:26,048 --> 00:30:27,872 尽管还不知道整个流是什么样的 without knowing the stream that you're integrating. 511 00:30:28,970 --> 00:30:30,176 这是因为INTEGRAL中第一个元素 Because the first thing in the integral 512 00:30:30,200 --> 00:30:32,160 总会是你传递过来的INITIAL-VALUE is always going to be the initial value that you're handed. 513 00:30:33,140 --> 00:30:36,112 所以INTEGRAL可以用CONS-STREAM来实现 So integral could be a procedure like cons-stream. 514 00:30:37,090 --> 00:30:37,984 我们可以定义它 You could define it, 515 00:30:38,256 --> 00:30:40,880 甚至不用知道要积分的流是什么 and then even before it knows what it's supposed to be integrating, 516 00:30:42,848 --> 00:30:45,184 只需要知道初始值是什么就行了 it knows enough to say what its initial value is. 517 00:30:46,710 --> 00:30:48,176 INTEGRAL还可以修改得更为智能 So we can make a smarter integral, 518 00:30:48,416 --> 00:30:50,688 我们给它一个待积分的流 which is aha, you're going to give me a stream to integrate 519 00:30:50,832 --> 00:30:51,920 以及一个初值 and an initial value, 520 00:30:52,112 --> 00:30:54,992 直到你要求沿着这个流求解积分时 but I really don't have to look at that stream that I'm supposed to integrate 521 00:30:55,216 --> 00:30:56,976 我才关心这个流是什么 until you ask me to work down the stream. 522 00:30:58,430 --> 00:31:00,512 换句话说INTEGRAL可以像CONS-STREAM一样 In other words, integral can be like cons-stream, 523 00:31:00,570 --> 00:31:03,744 你可以认为INTEGRAL被放在DELAY之中 and you can expect that there's going to be a delay around its integrand. 524 00:31:03,760 --> 00:31:04,864 我们这样修改 And we can write that. 525 00:31:05,610 --> 00:31:07,024 这个过程是像这样的 Here's a procedure that does that. 526 00:31:07,650 --> 00:31:08,752 这是另一个版本的INTEGRAL Another version of integral, 527 00:31:08,896 --> 00:31:10,544 这个跟之前的版本非常相似 and this is almost like the previous one, 528 00:31:11,104 --> 00:31:13,344 只不过作为参数的流 except the stream it's going to get in 529 00:31:13,776 --> 00:31:15,696 必须要是一个延时对象 is going to expect to be a delayed object. 530 00:31:17,110 --> 00:31:18,432 这个INTEGRAL又是如何运作的呢? And how does this integral work? 531 00:31:18,850 --> 00:31:21,792 我们在内部定义的INT则是 Well, the little thing it's going to define inside of itself 532 00:31:22,144 --> 00:31:24,192 用CONS-STREAM构造一个流 says on the cons-stream, 533 00:31:24,736 --> 00:31:26,448 初值还是INITIAL-VALUE the initial value is the initial value, 534 00:31:27,160 --> 00:31:29,680 但是在CONS-STREAM中 but only inside of that cons-stream, 535 00:31:29,744 --> 00:31:32,300 要注意 这里面有个隐藏的DELAY and remember, there's going to be a hidden delay inside here. 536 00:31:34,950 --> 00:31:39,072 只有在这个CONS-STREAM的内部 Only inside of that cons-stream will I start looking at 537 00:31:39,824 --> 00:31:42,110 我才会查看延时对象的实际内容 what the actual delayed object is. 538 00:31:43,180 --> 00:31:45,792 所以 答案的第一个元素将会是初值 So my answer is the first thing's the initial value. 539 00:31:45,970 --> 00:31:47,904 如果有人想访问我的尾部分 If anybody now asks me for my tail, 540 00:31:48,400 --> 00:31:49,424 此时 at that point, 541 00:31:50,000 --> 00:31:51,728 我会FORCE该延迟对象 I'm going to force that delayed object-- 542 00:31:52,624 --> 00:31:53,600 把结果记作S and I'll call that s-- 543 00:31:54,448 --> 00:31:55,600 然后再进行ADD-STREAMS and I do the add streams. 544 00:31:56,368 --> 00:31:59,260 这个INTEGRAL就有点像CONS-STREAM So this is an integral which is sort of like cons-stream. 545 00:31:59,260 --> 00:32:02,592 直到你确实需要知道第一个元素的时候 It's not going to actually try and see what you handed it 546 00:32:03,888 --> 00:32:07,136 它才会去查看DELAYED-S是什么 as the thing to integrate until you look past the first element. 547 00:32:10,120 --> 00:32:11,024 如果这样的话 And if we do that 548 00:32:11,520 --> 00:32:12,832 也就能求解 y' = y^2 了 and we can make this work, 549 00:32:13,360 --> 00:32:15,200 这里我们只需要 all we have to do here is 550 00:32:16,000 --> 00:32:25,312 把Y定义为对延时对象DY的积分 define y to the integral of delay of y, of delay of dy. 551 00:32:27,090 --> 00:32:28,224 所以Y的定义就变成了 So y is going to be 552 00:32:28,400 --> 00:32:34,368 (INTEGRAL (DELAY DY) 1 .001) the integral of delay of dy starting at 1, 553 00:32:34,384 --> 00:32:35,130 这样一来就可以了 and now this will work. 554 00:32:35,280 --> 00:32:37,440 因为我输入Y的定义 Because I type in the definition of y, 555 00:32:38,000 --> 00:32:39,680 它是某个东西的积分 and that says, oh, I'm supposed to use the integral of 556 00:32:40,208 --> 00:32:42,688 但这是个延迟对象 我现在还不用关心 something I don't care about right now because it's a delay. 557 00:32:44,600 --> 00:32:46,320 这之后 再定义DY And these things, now you define dy. 558 00:32:46,320 --> 00:32:47,376 现在Y就有定义了 Now, y is defined. 559 00:32:47,550 --> 00:32:48,896 所以我在定义DY时 So when I define dy, 560 00:32:49,136 --> 00:32:50,672 它可以知道Y的定义 it can see that definition for y. 561 00:32:51,700 --> 00:32:52,840 一切都正常了 Everything is now started up. 562 00:32:52,840 --> 00:32:54,336 两个流都有第一个元素 Both streams have their first element. 563 00:32:54,920 --> 00:32:56,256 当我不断取得下一个元素 And then when I start mapping down, 564 00:32:56,272 --> 00:32:57,312 沿着流做MAP运算时 looking at successive elements, 565 00:32:57,376 --> 00:32:58,880 Y和DY都被定义过了 both y and dy are defined. 566 00:33:00,590 --> 00:33:04,240 所以为了继续这个游戏 我们不能仅仅 So there's a little game you can play that goes a little bit beyond 567 00:33:04,670 --> 00:33:07,136 只使用隐藏在流中的DELAY just using the delay that's hidden inside streams. 568 00:33:08,368 --> 00:33:08,976 有问题么? Questions? 569 00:33:13,520 --> 00:33:14,272 休息一下吧 OK, let's take a break. 570 00:33:14,720 --> 00:33:26,864 [音乐] [JESU, JOY OF MAN'S DESIRING] 571 00:33:27,370 --> 00:33:30,944 《计算机程序的构造和解释》 572 00:33:52,160 --> 00:33:55,264 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 573 00:33:55,420 --> 00:33:59,264 《计算机程序的构造和解释》 574 00:34:00,384 --> 00:34:03,930 流 II 575 00:34:07,300 --> 00:34:10,048 上节课的最后 Well, just before the break, um.. 576 00:34:10,890 --> 00:34:11,808 不知道你们注意到没有 I'm not sure if you noticed it, 577 00:34:11,824 --> 00:34:13,550 事情正变得糟糕起来 but something nasty started to happen. 578 00:34:14,832 --> 00:34:18,400 我们讲了很多关于 流 We've been going along with the streams 579 00:34:19,168 --> 00:34:22,688 以及分离程序中的时间和计算机中的时间 and divorcing time in the programs from time in the computers, 580 00:34:22,864 --> 00:34:26,288 这些分离都被隐藏在流中了 and all that divorcing got hidden inside the streams. 581 00:34:27,280 --> 00:34:29,504 上节课快结束时我们发现 And then at the very end, we saw that sometimes 582 00:34:29,710 --> 00:34:32,192 为了真正发挥这种方法的优势 in order to really take advantage of this method, 583 00:34:32,224 --> 00:34:34,380 我们需要另外的DELAY you have to pull out other delays. 584 00:34:34,380 --> 00:34:35,856 不只需要隐藏在CONS-STREAM中的DELAY You have to write some explicit delays 585 00:34:36,096 --> 00:34:37,950 还需要显式地使用DELAY that are not hidden inside that cons-stream. 586 00:34:39,030 --> 00:34:41,888 我只是用微分方程举了一个很简单的例子 And I did a very simple example with differential equations, 587 00:34:42,350 --> 00:34:44,080 但是如果你有一个非常复杂的系统 but if you have some very complicated system 588 00:34:44,128 --> 00:34:45,408 里面充斥着各种各样的自循环 with all kinds of self-loops, 589 00:34:45,950 --> 00:34:47,840 那就很难再发现 it becomes very, very difficult to 590 00:34:47,904 --> 00:34:49,310 在什么地方需要额外的DELAY了 see where you need those delays. 591 00:34:49,920 --> 00:34:51,184 假如你一不小心漏了一个 And if you leave them out by mistake, 592 00:34:51,456 --> 00:34:54,368 就很难发现程序为什么不起效 it becomes very, very difficult to see why the thing maybe isn't working. 593 00:34:55,550 --> 00:34:57,152 这是一种混乱 So that's kind of mess, 594 00:34:57,792 --> 00:35:01,712 让我们能够使用DELAY that by getting this power and allowing us to use delay, 595 00:35:02,080 --> 00:35:04,704 有时却会让程序设计变得非常复杂 we end up with some very complicated programming sometimes, 596 00:35:04,720 --> 00:35:06,800 因为它们不能完全隐藏在流中 because it can't all be hidden inside the streams. 597 00:35:08,512 --> 00:35:09,792 那么 有没有什么解决方案呢? Well, is there a way out of that? 598 00:35:11,136 --> 00:35:12,672 所幸的是 有 Yeah, there is a way out of that. 599 00:35:13,480 --> 00:35:16,080 我们可以修改整个语言 We could change the language so that 600 00:35:16,144 --> 00:35:18,192 使得所有的过程都表现得像CONS-STREAM一样 all procedures acted like cons-stream, 601 00:35:19,104 --> 00:35:21,488 这样所有的过程都会 so that every procedure automatically 602 00:35:22,320 --> 00:35:25,450 自动、隐式地为它的参数加上DELAY has an implicit delay around its arguments. 603 00:35:25,450 --> 00:35:26,432 这是什么意思呢? And what would that mean? 604 00:35:27,520 --> 00:35:29,536 就是说 当你调用一个过程时 That would mean when you call a procedure, 605 00:35:30,160 --> 00:35:31,888 参数并不会立即求值 the arguments wouldn't get evaluated. 606 00:35:32,210 --> 00:35:34,704 只有在需要被求值的时候 它们才会被求值 Instead, they'd only be evaluated when you need them, 607 00:35:34,896 --> 00:35:36,720 它们也可能被传递给其它的过程 so they might be passed off to some other procedure, 608 00:35:36,768 --> 00:35:38,128 而这个过程也不会求值这些参数 which wouldn't evaluate them either. 609 00:35:39,260 --> 00:35:41,904 因此这些过程间传递的是PROMISE So all these procedures would be passing promises around. 610 00:35:42,150 --> 00:35:44,464 直到最后 And then finally maybe when you finally got down 611 00:35:44,656 --> 00:35:47,344 你需要查看某个值的时候 to having to look at the value of something 612 00:35:47,360 --> 00:35:48,992 可能是因为一个基本运算所需要 that was handed to a primitive operator 613 00:35:49,376 --> 00:35:51,488 这是你才实际求值这些PROMISE which you actually start calling in all those promises. 614 00:35:52,380 --> 00:35:53,168 像这样修改语言之后 If we did that, 615 00:35:53,360 --> 00:35:55,376 由于所有的东西都是统一被延时的 since everything would have a uniform delay, 616 00:35:57,168 --> 00:35:59,008 就不需要任何显式的DELAY了 then you wouldn't have to write any explicit delays, 617 00:35:59,040 --> 00:36:01,552 因为它自动地内建在语言之中了 because it would be automatically built into the way the language works. 618 00:36:03,248 --> 00:36:04,384 换句话来说 Or another way to say that, 619 00:36:05,100 --> 00:36:08,144 从技术上来说 我所描述的 technically what I'm describing is what's called 620 00:36:09,024 --> 00:36:10,768 如果修改后的语言被称作 if we did that, our language would be 621 00:36:12,192 --> 00:36:16,576 所谓的“正则序求值”语言 so-called normal-order evaluation language 622 00:36:20,208 --> 00:36:23,470 这个跟我们一直使用的语言不同 versus what we've actually been working with, 623 00:36:23,872 --> 00:36:33,792 我们所用的是“应用序求值”语言 which is called applicative order-- versus applicative-order evaluation. 624 00:36:34,560 --> 00:36:36,835 还记得应用序求值的代换模型吧 And remember the substitution model for applicative order. 625 00:36:36,830 --> 00:36:40,496 当你求值一个组合式的时候 It says when you go and evaluate a combination, 626 00:36:40,512 --> 00:36:42,112 你需要先计算出每一个元素的值 you find the values of all the pieces. 627 00:36:43,590 --> 00:36:45,408 先求值所有的参数 You evaluate the arguments and then you 628 00:36:45,720 --> 00:36:47,424 再把它们代换入过程的体 substitute them in the body of the procedure. 629 00:36:47,600 --> 00:36:49,552 正则序则不是这样 Normal order says no, don't do that. 630 00:36:49,890 --> 00:36:51,904 你所做的则是 What you do is effectively 631 00:36:52,768 --> 00:36:54,416 直接将参数代换入过程的体 substitute in the body of the procedure, 632 00:36:54,448 --> 00:36:56,192 而不先对参数求值 but instead of evaluating the arguments, 633 00:36:56,544 --> 00:36:58,080 只是代换入了一个计算参数的PROMISE you just put a promise to compute them there. 634 00:36:58,816 --> 00:36:59,904 换句话说就是 Or another way to say that 635 00:36:59,920 --> 00:37:02,096 把作为参数的整个表达式 you take the expressions for the arguments, if you like, 636 00:37:02,288 --> 00:37:04,848 直接代入过程的体进行代换 and substitute them in the body of the procedure and go on, 637 00:37:05,168 --> 00:37:06,880 在此之间从不进行任何化简 and never really simplify anything 638 00:37:07,168 --> 00:37:08,768 直到遇到一个基本运算符 until you get down to a primitive operator. 639 00:37:09,472 --> 00:37:10,992 这就是所谓的正则序求值语言 So that would be a normal-order language. 640 00:37:12,176 --> 00:37:13,120 我们为什么不这样做呢? Well, why don't we do that? 641 00:37:13,824 --> 00:37:14,608 这样做了之后 Because if we did, 642 00:37:15,008 --> 00:37:17,344 我们就获得了延时求值的所有优点 we'd get all the advantages of delayed evaluation 643 00:37:17,904 --> 00:37:18,800 而不会一片混乱 with none of the mess. 644 00:37:18,940 --> 00:37:20,192 事实上 如果我们这样做了之后 In fact, if we did that 645 00:37:20,432 --> 00:37:22,672 CONS也会是延时求值的 and cons was just a delayed procedure, 646 00:37:22,688 --> 00:37:24,570 就和CONS-STREAM一样 that would make cons the same as cons-stream. 647 00:37:24,710 --> 00:37:25,824 我们就不再需要流了 We wouldn't need streams at all 648 00:37:26,368 --> 00:37:28,544 因为表自动成为了流 because lists would automatically be streams. 649 00:37:29,552 --> 00:37:30,704 表和流有一样的行为 That's how lists would behave, 650 00:37:30,752 --> 00:37:32,350 所有的数据结构也会像那样 all data structures would behave that way. 651 00:37:32,350 --> 00:37:33,648 所有的都是 Everything would behave that way. 652 00:37:35,070 --> 00:37:37,632 直到需要答案的时候 Right, You'd never really do any computation 653 00:37:37,664 --> 00:37:39,424 才会去实际的求值 until you actually needed the answer. 654 00:37:40,800 --> 00:37:43,584 不必再担心 什么时候需要显式地标注DELAY You wouldn't have to worry about all these explicit annoying delays. 655 00:37:44,790 --> 00:37:46,160 为什么不这样做呢? Well, why don't we do that? 656 00:37:47,160 --> 00:37:48,816 首先 已经有人这样做过了 First of all, I should say people do do that. 657 00:37:49,230 --> 00:37:51,850 有一些十分优雅的语言 There's some very beautiful languages. 658 00:37:51,850 --> 00:37:55,216 其中最为人称道的是一门名为 Miranda 的语言 One of the very nicest is a language called Miranda, 659 00:37:55,776 --> 00:37:56,768 它是由 which is, um.. 660 00:37:57,440 --> 00:37:59,808 肯特大学的 David Turner 开发的 developed by David Turner at the University of Kent. 661 00:38:00,710 --> 00:38:01,930 它就是用这样的原理实现的 And that's how this language works. 662 00:38:01,930 --> 00:38:03,344 Miranda是正则序求值语言 It's a normal-order language 663 00:38:04,272 --> 00:38:05,552 它的数据结构 and its data structures, 664 00:38:06,160 --> 00:38:08,416 看起来像表 实际上确实流 which look like lists, are actually streams. 665 00:38:08,960 --> 00:38:10,912 你不需要任何特殊的功能 And you write ordinary procedures in Miranda, 666 00:38:11,280 --> 00:38:13,280 就可以在Miranda中编写普通的过程 and they do these prime things and eight queens things, 667 00:38:13,328 --> 00:38:14,970 来解决质数、八皇后这样的问题 just without anything special. 668 00:38:14,970 --> 00:38:16,352 这些都是语言的内建功能 It's all built in there. 669 00:38:17,936 --> 00:38:18,912 但这样做也要付出代价 But there's a price. 670 00:38:21,190 --> 00:38:22,368 还记得我们为什么引入流了吗? Remember how we got here. 671 00:38:23,170 --> 00:38:27,480 我们分离了程序的时间和它实际执行的时间 We're decoupling time in the programs from time in the machines. 672 00:38:27,968 --> 00:38:28,880 如果我们引入了DELAY And if we put delay, 673 00:38:29,040 --> 00:38:30,336 这样就在所有的地方完成了解耦 that sort of decouples it everywhere, 674 00:38:30,400 --> 00:38:31,424 而不单单是在流中 not just in streams. 675 00:38:32,192 --> 00:38:33,140 我们的初衷是什么? Remember what we're trying to do. 676 00:38:33,140 --> 00:38:38,112 我们把程序设计看做是指定计算过程 We're trying to think about programming as a way to specify processes. 677 00:38:39,300 --> 00:38:40,624 如果我们放弃了对时间的控制 And if we give up too much time, 678 00:38:40,656 --> 00:38:42,416 尽管语言变得优雅起来 our language becomes more elegant, 679 00:38:43,744 --> 00:38:45,872 但是它的表达力却有所下降 but it becomes a little bit less expressive. 680 00:38:47,030 --> 00:38:49,840 这里面还有一些我们无法消除的区别 There are certain distinctions that we can't draw. 681 00:38:51,480 --> 00:38:53,152 其中之一就是迭代 One of them, for instance, is iteration. 682 00:38:53,980 --> 00:38:56,448 还记得这个程序吗? Remember this old procedure, 683 00:38:56,960 --> 00:38:58,288 迭代式的阶乘 iterative factorial, 684 00:38:58,448 --> 00:39:00,480 这是我们很早之前就研究过的 that we looked at quite a long time ago. 685 00:39:01,230 --> 00:39:02,976 过程FACT-ITER Iterative factorial had a thing, 686 00:39:03,040 --> 00:39:04,912 有一个内部过程ITER and it said there was an internal procedure, 687 00:39:05,184 --> 00:39:07,504 它含有两个状态PRODUCT和COUNTER and there was a state which was a product and a counter, 688 00:39:08,704 --> 00:39:10,960 它们随着循环不断迭代 and we iterate that going around the loop. 689 00:39:12,120 --> 00:39:13,680 之所以说这个过程是迭代的 And we said that was an iterative procedure 690 00:39:13,712 --> 00:39:14,832 是因为它没有创建新状态 because it didn't build up state. 691 00:39:15,730 --> 00:39:17,456 之所以没有创建新状态 And the reason it didn't build up state is 692 00:39:17,472 --> 00:39:20,256 是因为在调用ITER时 because this iter that's called 693 00:39:20,304 --> 00:39:22,864 作为参数传递给它自己的始终是这些东西 is just passing these things around to itself. 694 00:39:23,900 --> 00:39:25,392 在代换模型中 Or in the substitution model that, 695 00:39:25,552 --> 00:39:27,792 Gerald教授给你们讲解过 you could see in the substitution model that Jerry did, 696 00:39:28,720 --> 00:39:30,016 在迭代过程中 that in an iterative procedure, 697 00:39:30,032 --> 00:39:31,440 状态并不需要增长 that state doesn't have to grow. 698 00:39:31,824 --> 00:39:34,224 因此这是一个迭代过程 And in fact, we said it doesn't, so this is an iteration. 699 00:39:34,992 --> 00:39:37,472 但是如果用正则序语言 But now think about this exact same text 700 00:39:37,472 --> 00:39:39,104 来运行这段程序 if we had a normal-order language. 701 00:39:41,150 --> 00:39:42,176 这就会导致 What would happen is 702 00:39:42,880 --> 00:39:44,960 这个过程不再是迭代式了 this would no longer be an iterative procedure 703 00:39:45,650 --> 00:39:48,672 如果你仔细地思考代换模型 And if you really think about the details of the substitution model, 704 00:39:48,672 --> 00:39:49,904 在这里我就不细说了 which I'm not going to do here, 705 00:39:51,200 --> 00:39:52,352 这个表达式会不断增长 this expression would grow. 706 00:39:52,368 --> 00:39:53,184 为什么会这样? Why would it grow? 707 00:39:53,280 --> 00:39:55,200 因为当ITER调用自己时 It's because when iter calls itself, 708 00:39:55,856 --> 00:39:57,312 参数是这个乘法表达式 it calls itself with this product. 709 00:39:58,080 --> 00:39:59,360 而在正则序语言中 If it's a normal-order language, 710 00:39:59,392 --> 00:40:01,168 这个乘法并不会在这里求值 that multiplication is not going to get done. 711 00:40:02,510 --> 00:40:03,824 传递给自己并代换的 That's going to say I'm to call myself 712 00:40:03,936 --> 00:40:05,680 只是这个乘法计算的PROMISE with a promise to compute this product. 713 00:40:06,670 --> 00:40:08,032 然后继续代换下去 And now iter goes around again. 714 00:40:09,760 --> 00:40:11,552 我调用自己 And I'm going to call myself 715 00:40:11,840 --> 00:40:14,048 用的是计算这个乘法的PROMISE with a promise to compute this product 716 00:40:14,048 --> 00:40:17,820 但其中的一个因数也是个PROMISE where now one of the one factors is a promise. 717 00:40:18,400 --> 00:40:19,430 然后我又自调用 And I call myself again. 718 00:40:19,430 --> 00:40:21,136 如果你用代换模型 And if you write out the substitution model 719 00:40:21,984 --> 00:40:23,600 来推演这个迭代步骤 for that iterative process, 720 00:40:23,776 --> 00:40:26,832 你会发现同样的状态增长 you'll see exactly the same growth in state, 721 00:40:27,160 --> 00:40:28,960 所有的PROMISE都需要被记住 all those promises that are getting remembered 722 00:40:28,976 --> 00:40:30,760 以便在最后被调用 that have to get called in at the very end. 723 00:40:31,790 --> 00:40:35,024 所以 正则序的缺点之一 So one of the disadvantages 724 00:40:35,056 --> 00:40:36,864 就是无法有效地表达迭代 is that you can't really express iteration. 725 00:40:36,980 --> 00:40:39,600 也许这个理由有点偏理论 Maybe that's a little theoretical reason why not, 726 00:40:39,616 --> 00:40:43,904 但事实上 那些使用这类语言来编写 but in fact, people who are trying to write real operating systems 727 00:40:44,272 --> 00:40:47,568 实际操作系统的人 也都遇到了这类问题 in these languages are running into exactly these types of problems. 728 00:40:48,208 --> 00:40:50,752 当然 完全可以 Like it's perfectly possible to 729 00:40:51,648 --> 00:40:54,384 用这类语言实现一个文本编辑器 implement a text editor in languages like these. 730 00:40:54,610 --> 00:40:56,080 但是你才用了一会儿 But after you work a while, 731 00:40:56,720 --> 00:40:59,392 就发现已经占用了3MB空间 you suddenly have 3 megabytes of stuff, 732 00:40:59,440 --> 00:41:02,048 我想 那些遇到这类问题的人 which is-- I guess they call them 733 00:41:02,160 --> 00:41:05,600 把它叫做 “拖尾问题” the dragging tail problem who are looking at these, 734 00:41:05,824 --> 00:41:08,208 由于不能有效地表达迭代计算 of stuff of promises that sort of haven't been called in 735 00:41:08,240 --> 00:41:10,464 导致堆积了一堆没有被调用的PROMISE because you couldn't quite express an iteration. 736 00:41:10,720 --> 00:41:14,816 针对这类语言的一个研究方向就是 And one of the research questions in these kinds of languages 737 00:41:14,832 --> 00:41:17,488 找出一种有效的编译器技术 are figuring out the right compiler technology 738 00:41:17,824 --> 00:41:19,856 来避免这种所谓的“拖尾问题” to get rid of the so-called dragging tails. 739 00:41:20,176 --> 00:41:21,616 这并不简单 It's not simple. 740 00:41:23,940 --> 00:41:27,312 但是 还有一个很突出的问题 But there's another kind of more striking issue 741 00:41:27,968 --> 00:41:31,040 使你的语言不能变成正则序 about why you just don't go ahead and make your language normal order. 742 00:41:32,512 --> 00:41:33,296 问题就在于 And the reason is 743 00:41:35,056 --> 00:41:38,096 正则序和副作用 that normal-order evaluation and side effects 744 00:41:38,896 --> 00:41:40,192 是不相容的 just don't mix. 745 00:41:42,000 --> 00:41:43,968 它们不能很好地相互配合 They just don't go together very well. 746 00:41:45,440 --> 00:41:46,656 这是因为 你不能 Somehow, you can't- 747 00:41:48,288 --> 00:41:50,800 你不能一边 it's sort of you can't simultaneously 748 00:41:51,008 --> 00:41:54,336 建模具有局部状态的对象 go around trying to model objects with local state and change 749 00:41:55,728 --> 00:41:56,960 同时又 at the same time 750 00:41:57,184 --> 00:41:59,552 使用正则序的技巧来解耦时间 do these normal-order tricks of de-coupling time. 751 00:42:00,400 --> 00:42:03,552 我来举一个非常简单的例子 Let me just show you a really simple example, very, very simple. 752 00:42:03,790 --> 00:42:05,504 假设语言是正则序求值 Suppose we had a normal-order language. 753 00:42:07,520 --> 00:42:09,550 例子是这样的 And I'm going to start out in this language. 754 00:42:09,550 --> 00:42:10,520 注意现在是正则序求值 This is now normal order. 755 00:42:10,520 --> 00:42:12,224 (DEFINE X 0) I'm going to define x to be 0. 756 00:42:13,570 --> 00:42:15,568 这只是变量的初始化 It's just some variable I'll initialize. 757 00:42:15,750 --> 00:42:17,696 现在我要定义一个有趣的函数 And now I'm going to define this little funny function, 758 00:42:18,576 --> 00:42:20,448 它就是恒等函数ID which is an identity function. 759 00:42:22,640 --> 00:42:23,904 它所做的就是 And what it does, 760 00:42:24,112 --> 00:42:26,608 用X来记录上一次调用它时N的值 it keeps track of the last time you called it using x. 761 00:42:31,400 --> 00:42:34,160 因此(ID N)就返回N Right? So the identity of n just returns n, 762 00:42:34,176 --> 00:42:35,390 但还要把X赋值为N but it sets x to be n. 763 00:42:36,760 --> 00:42:38,544 最后再定义一个过程INC And now I'll define a little increment function, 764 00:42:39,552 --> 00:42:42,304 也非常简单 which is a very little, simple scenario. 765 00:42:42,580 --> 00:42:45,344 假设在正则序求值的语言里 Now, imagine I'm interacting with this in the normal-order language, 766 00:42:46,272 --> 00:42:47,230 求值下面的表达式 and I type the following. 767 00:42:47,230 --> 00:42:52,832 我输入 (DEFINE Y (INC (ID 3))) I say define y to be increment the identity function of 3, 768 00:42:52,832 --> 00:42:53,968 因此Y的值应该是4 so y is going to be 4. 769 00:42:57,410 --> 00:42:58,352 X应该是多少呢? Now, I say what's x? 770 00:42:59,520 --> 00:43:02,160 X应该是最后一次被记住的值 Well, x should have been the value that was remembered last 771 00:43:02,640 --> 00:43:04,016 也就是我调用函数ID的时候 when I called the identity function. 772 00:43:04,710 --> 00:43:06,736 你可能会想 这里X应该是3 So you'd expect to say, well, x is 3 at this point, 773 00:43:06,912 --> 00:43:07,520 但是并不是这样 but it's not. 774 00:43:08,530 --> 00:43:11,152 这是因为当我在这里定义Y的时候 Because when I defined here, y here, 775 00:43:11,792 --> 00:43:13,456 Y的真正定义却是 what I really defined y to be 776 00:43:13,472 --> 00:43:15,712 一个调用函数ID的PROMISE的增量 increment of a promise to do this thing. 777 00:43:17,000 --> 00:43:18,176 因为我没有访问Y So I didn't look at y, 778 00:43:18,368 --> 00:43:20,256 所以ID没有运行 so that identity function didn't get run. 779 00:43:21,560 --> 00:43:23,200 我输入这个定义之后 So if I type in this definition 780 00:43:23,312 --> 00:43:24,800 然后查询X得到的结果是0 and look at x, I'm going to get 0. 781 00:43:28,360 --> 00:43:31,200 现在 我输入Y查询它的值 Now, if I go look at y and say what's y, 782 00:43:31,520 --> 00:43:32,432 就会得到结果4 say y is 4, 783 00:43:32,670 --> 00:43:35,168 对Y的主动查询 looking at y, that very active looking at y 784 00:43:35,296 --> 00:43:37,424 会导致ID运行 caused the identity function to be run. 785 00:43:38,720 --> 00:43:40,480 现在X=3就被记住 And now x will get remembered as 3. 786 00:43:40,740 --> 00:43:41,872 所以上面这里的X就应该是0 So here x will be 0. 787 00:43:41,936 --> 00:43:42,960 下面这里是3 Here, x will be 3. 788 00:43:43,280 --> 00:43:46,160 这是一个非常简单的场景 That's a tiny, little, simple scenario, 789 00:43:46,304 --> 00:43:49,280 但你会发现 调试正则序语言 but you can see what kind of a mess that's going to make 790 00:43:50,368 --> 00:43:53,344 的交互式程序 for debugging interactive programs 791 00:43:54,128 --> 00:43:55,888 会变得相当混乱 when you have normal-order evaluation. 792 00:43:57,100 --> 00:43:58,128 很令人迷惑 It's very confusing. 793 00:43:59,690 --> 00:44:02,048 导致这样的深层次的原因 But it's very confusing for a very deep reason, 794 00:44:02,800 --> 00:44:06,416 也就是引入DELAY的根本理念 which is that the whole idea of putting in delays 795 00:44:06,928 --> 00:44:08,432 是因为我们抛弃了时间的概念 is that you throw away time. 796 00:44:09,780 --> 00:44:11,750 也因为如此我们可以处理一些无穷的情况 That's why we can have these infinite processes. 797 00:44:11,750 --> 00:44:12,976 我们抛弃了时间 Since we've thrown away time, 798 00:44:12,992 --> 00:44:14,270 就没有必要等它们运行 we don't have to wait for them to run, 799 00:44:17,550 --> 00:44:20,448 我们把计算机中事件发生的顺序 Right? We decouple the order of events in the computer 800 00:44:20,832 --> 00:44:22,112 与程序中的顺序 分离开来 from what we write in our programs. 801 00:44:22,352 --> 00:44:25,280 但是当我们谈及状态、赋值和改变的时候 But when we talk about state and set and change, 802 00:44:25,488 --> 00:44:27,424 这些又都是我们想要控制的 that's exactly what we do want control of. 803 00:44:28,760 --> 00:44:33,824 我们的目的有着根本性的矛盾 So it's almost as if there's this fundamental contradiction in what you want. 804 00:44:34,570 --> 00:44:39,120 这又让我们进入了一个哲学问题 And that brings us back to these sort of philosophical mutterings 805 00:44:39,136 --> 00:44:40,752 用什么样的模型 what is it that you're trying to model 806 00:44:40,784 --> 00:44:41,776 和从什么角度来看这个世界 and how do you look at the world. 807 00:44:42,410 --> 00:44:44,304 有时这也被称为 Or sometimes this is called the 808 00:44:44,768 --> 00:44:46,608 “函数式程序设计的争论” the debate over functional programming. 809 00:44:54,192 --> 00:44:56,608 所谓的“纯函数式语言” A so-called purely functional language 810 00:44:57,072 --> 00:44:59,200 是完全没有副作用的 is one that just doesn't have any side effects. 811 00:45:00,440 --> 00:45:01,632 不需要副作用 Since you have no side effects, 812 00:45:01,648 --> 00:45:03,020 也就不需要赋值运算符 there's no assignment operator, 813 00:45:03,344 --> 00:45:05,728 也就没有什么糟糕的后果 so there are no terrible consequences of it. 814 00:45:06,360 --> 00:45:07,930 可以使用类似代换模型 You can use a substitution-like thing. 815 00:45:07,930 --> 00:45:10,480 程序更像是数学 Programs really are like mathematics and not like 816 00:45:10,768 --> 00:45:13,824 而不像现实世界中的模型和对象 not like models in the real world, not like objects in the real world. 817 00:45:15,050 --> 00:45:17,170 函数式语言有很多了不起的特性 There are a lot of wonderful things about functional languages. 818 00:45:17,170 --> 00:45:19,632 没有时间的概念 所以完全不用担心同步的问题 Since there's no time, you never have any synchronization problems. 819 00:45:20,640 --> 00:45:23,728 如果你想在并行算法中应用一些东西 And if you want to put something into a parallel algorithm, 820 00:45:24,720 --> 00:45:28,208 你可以在这些并行过程中随心所欲地使用 you can run the pieces of that parallel processing any way you want. 821 00:45:29,408 --> 00:45:31,440 从来不担心同步问题 There's just never any synchronization to worry that, 822 00:45:31,504 --> 00:45:33,344 在这种环境下这样做是非常方便的 and it's a very congenial environment for doing this. 823 00:45:33,640 --> 00:45:35,712 代价则是 放弃了赋值 The price is you give up assignment. 824 00:45:39,104 --> 00:45:41,328 函数式语言的支持者会认为 So an advocate of a functional language would say, 825 00:45:41,344 --> 00:45:43,040 这点代价算不了什么 gee, that's just a tiny price to pay. 826 00:45:44,520 --> 00:45:46,510 在大部分情况下 你都不应该使用赋值 You probably shouldn't use assignment most of the time anyway. 827 00:45:46,880 --> 00:45:48,272 如果用你放弃了赋值 And if you just give up assignment, 828 00:45:48,432 --> 00:45:51,408 你可以得到一个比对象世界 you can be in this much, much nicer world 829 00:45:51,968 --> 00:45:53,248 好得多的世界 than this place with objects. 830 00:45:54,190 --> 00:45:56,300 怎么来反驳这个观点呢? Well, what's the rejoinder to that? 831 00:45:56,300 --> 00:45:58,592 想想 我们如何走到这一步的 Remember how we got into this mess. 832 00:46:00,064 --> 00:46:03,792 我们尝试建模具有局部状态的对象 We started trying to model things that had local state. 833 00:46:04,440 --> 00:46:06,496 想一想Gerald教授给你们讲的随机数生成器 So remember Gerry's random number generator. 834 00:46:07,168 --> 00:46:08,672 这里有一个随机数生成器 There was this random number generator 835 00:46:09,280 --> 00:46:10,624 它内部有一些状态 that had some little state in it 836 00:46:10,830 --> 00:46:12,080 用来计算下一个随机数 to compute the next random number 837 00:46:12,128 --> 00:46:14,080 下下一个 以及再下一个 and the next random number and the next random number. 838 00:46:14,288 --> 00:46:16,144 我们想要把这些状态跟 And we wanted to hide that state away from the 839 00:46:16,432 --> 00:46:18,960 计算π的Cesaro算法分离开来 the Cesaro compute pi process, 840 00:46:19,840 --> 00:46:20,928 这就是我们为什么需要赋值 and that's why we needed set! 841 00:46:20,976 --> 00:46:22,912 我们想要把状态封装在模块中 We wanted to package that stated modularly. 842 00:46:24,070 --> 00:46:26,368 函数式语言程序员可能会说 Well, a functional programming person would say, 843 00:46:26,384 --> 00:46:27,560 “你搞错了” well, you're just all wet. 844 00:46:27,560 --> 00:46:29,840 “我的意思是 你能写出另一种更具模块化的程序” I mean, you can write a perfectly good modular program. 845 00:46:29,840 --> 00:46:32,464 “你对模块化的认识并不正确” It's just you're thinking about modularity wrong. 846 00:46:33,080 --> 00:46:35,024 你太执着于 “生成一个随机数 You're hung up in this next random number 847 00:46:35,072 --> 00:46:36,880 再生成一个 再生成一个” 这种范式了 and the next random number and the next random number. 848 00:46:36,880 --> 00:46:39,424 为什么不写一个这样的程序 Why don't you just say let's write a program. 849 00:46:40,090 --> 00:46:41,296 构造一个枚举器 Let's write an enumerator 850 00:46:41,952 --> 00:46:44,480 它会生成一个随机数的无穷流 which just generates an infinite stream of random numbers. 851 00:46:49,010 --> 00:46:50,912 我们可以立即生成这个流 We can sort of have that stream all at once, 852 00:46:52,640 --> 00:46:54,540 这样就可以用作随机数的源泉 and that's going to be our source of random numbers. 853 00:46:54,540 --> 00:46:55,248 如果有需要的话 And then if you like, 854 00:46:55,536 --> 00:46:57,472 你可以把它跟某个处理过程相连 you can put that through some sort of processor, 855 00:46:57,776 --> 00:47:01,168 比如说Cesaro测试 which is-- I don't know-- a Cesaro test, 856 00:47:04,944 --> 00:47:06,224 然后这个处理过程进行自己的计算 and that can do what it wants. 857 00:47:06,880 --> 00:47:08,560 从这里出来的则是 And what would come out of there 858 00:47:08,720 --> 00:47:27,456 其中是一串的对π的估计值组成的流 would be a stream of successive approximations to pi. 859 00:47:28,140 --> 00:47:30,656 随着我们深入访问这个流 So as we looked further down this stream, 860 00:47:30,768 --> 00:47:32,384 相当于去拽这个Cesaro盒子 we'd tug on this Cesaro thing, 861 00:47:33,120 --> 00:47:35,360 它就会拉取出许多随机数 and it would pull out more and more random numbers. 862 00:47:35,540 --> 00:47:37,216 随着我们对流的深入访问 And the further and further we look down the stream, 863 00:47:37,232 --> 00:47:38,960 得到的对π的估计值就越准 the better an approximation we'd get to pi. 864 00:47:39,720 --> 00:47:41,664 具体的计算过程还是一样的 And it would do exactly the same as the other computation, 865 00:47:41,664 --> 00:47:43,792 只不过使用了另一种模块化的方式 except we're thinking about the modularity different. 866 00:47:43,890 --> 00:47:45,552 我们可以想象成一下子 We're saying imagine we had all that 867 00:47:45,560 --> 00:47:47,472 就有了这所有的随机数 infinite streams of random numbers all at once. 868 00:47:49,280 --> 00:47:52,240 这个过程的细节在书上有 You can see the details of this procedure in the book. 869 00:47:53,610 --> 00:47:57,856 我们同样也陷于另外一些类似的事情中 But similarly, there are other things that we tend to get locked into 870 00:47:58,272 --> 00:48:01,200 这种关于 这个、下一个以及再下一个的范式 on this one and that one and the next one and the next one, 871 00:48:01,376 --> 00:48:02,816 完全可以不这么来做 which don't have to be that way. 872 00:48:03,280 --> 00:48:06,544 我们来思考一下银行系统 Like you might think about like a banking system, 873 00:48:07,680 --> 00:48:08,900 有个非常简单的场景 which is a very simple idea. 874 00:48:08,900 --> 00:48:12,210 我们假设这个程序代表了银行帐户 Imagine we have a program that sort of represents a bank account. 875 00:48:18,810 --> 00:48:20,848 银行账户中可能有 The bank account might have in it-- 876 00:48:22,784 --> 00:48:26,224 如果我们以消息传递的角度来看 if we looked at this in a sort of message-passing view of the world, 877 00:48:26,448 --> 00:48:28,128 我们认为银行账户是一个对象 we'd say a bank account is an object 878 00:48:28,592 --> 00:48:31,510 内部保存着标识余额的局部状态BALANCE that has some local state in there, which is the balance, say. 879 00:48:34,110 --> 00:48:36,000 如果一个用户使用这个系统 And a user using this system comes 880 00:48:36,448 --> 00:48:38,144 发出交易请求 and sends a transaction request. 881 00:48:39,312 --> 00:48:41,056 用户发出的交易请求可能是 So the user sends a transaction request, 882 00:48:41,072 --> 00:48:42,208 存一些钱 like deposit some money, 883 00:48:42,288 --> 00:48:43,536 银行账户就会 and the bank account maybe-- 884 00:48:43,920 --> 00:48:46,784 我们假设银行账户总是以当前余额作为回应 let's say the bank account always responds with what the current balance is. 885 00:48:48,220 --> 00:48:50,048 用户存了一些钱 The user says let's deposits some money, 886 00:48:50,064 --> 00:48:53,210 银行账户就会返回一个消息指明当前余额 and the bank account sends back a message which is the balance. 887 00:48:54,350 --> 00:48:57,424 用户再存一些钱 And the user says deposit some more, 888 00:48:57,456 --> 00:48:58,816 银行就再返回消息 and the bank account sends back a message. 889 00:48:59,150 --> 00:49:00,752 就像生成随机数一样 And just like the random number generating 890 00:49:00,784 --> 00:49:02,128 我们想使用赋值来实现 you'd say, gee, we would like to use set. 891 00:49:03,200 --> 00:49:06,880 帐户的内部保存了局部状态BALANCE We'd like to have balance be a piece of local state inside this bank account 892 00:49:06,880 --> 00:49:08,400 因为我们想要把用户状态 because we want to separate the state of the user 893 00:49:08,416 --> 00:49:09,570 和银行账户的状态分离开来 from the state of the bank account. 894 00:49:13,280 --> 00:49:16,420 这是从消息传递的角度来看 Well, that's the message-processing view. 895 00:49:16,420 --> 00:49:18,208 如果从流的角度来看 There's a stream view with that thing, 896 00:49:19,488 --> 00:49:22,192 不需要赋值或副作用就可以达到同样的效果 which does the same thing without any set or side effects. 897 00:49:22,740 --> 00:49:26,736 再次强调 想法是这样的 And the idea is again 898 00:49:27,376 --> 00:49:30,256 我们认为它们都没有局部状态 we don't think about anything having local state. 899 00:49:31,180 --> 00:49:33,088 我们把银行账户看作是 We think about the bank account as something 900 00:49:33,408 --> 00:49:37,712 能够处理一系列交易请求的东西 that's going to process a stream of transaction requests. 901 00:49:38,640 --> 00:49:40,160 不把银行账户看做 So think about this bank account not 902 00:49:40,224 --> 00:49:42,000 逐个消息地处理 as something that goes message by message, 903 00:49:42,448 --> 00:49:45,856 而是处理某种交易请求流的东西 but something that takes in a stream of transaction requests 904 00:49:45,872 --> 00:49:48,496 这个请求流可能是一些列的存款声明 like maybe successive deposit announced. 905 00:49:49,490 --> 00:49:54,944 比如 1 2 2 4 这样的连续存钱请求 1, 2, 2, 4, those might be successive amounts to deposit. 906 00:49:55,940 --> 00:50:02,448 从帐户出来的流应该是 1 3 5 9 And then coming out of it is the successive balances 1, 3, 5, 9. 907 00:50:03,770 --> 00:50:06,144 我们不把银行账户看做某种具有状态的东西 So we think of the bank account not as something that has state, 908 00:50:06,400 --> 00:50:07,264 而是某种能够处理 but something that acts 909 00:50:08,928 --> 00:50:10,820 有关请求的无穷流的东西 sort of on the infinite stream of requests. 910 00:50:10,820 --> 00:50:12,304 但要注意 我们抛弃了时间 But remember, we've thrown away time. 911 00:50:12,370 --> 00:50:14,272 如果这里有一个用户 So what we can do is if the user's here, 912 00:50:16,120 --> 00:50:19,136 这个无穷请求流的元素 we can have this infinite stream of requests 913 00:50:19,184 --> 00:50:22,540 我们可以一次生成一个 being generated one at a time coming from the user 914 00:50:24,064 --> 00:50:26,576 而这个交易流 and this transaction stream 915 00:50:26,570 --> 00:50:28,800 则会逐个打印在屏幕上 coming back on a printer being printed one at a time. 916 00:50:30,010 --> 00:50:31,376 如果在这里画一条线 And if we drew a little line here, 917 00:50:32,560 --> 00:50:33,088 就在这里 right there to the user, 918 00:50:33,280 --> 00:50:34,912 对用户来说 他根本无法分辨 the user couldn't tell that this system doesn't have state. 919 00:50:36,192 --> 00:50:37,712 这个系统是否有内部状态 that this system doesn't have state. 920 00:50:39,560 --> 00:50:41,136 这个跟消息传递那种是一样的 It looks just like the other one, 921 00:50:41,296 --> 00:50:42,464 只不过这个没有状态 but there's no state in there. 922 00:50:42,848 --> 00:50:45,872 哦 顺便提一下 And by the way, 923 00:50:46,720 --> 00:50:49,472 这是具体的代码实现 just to show you, here's an actual implementation 924 00:50:50,528 --> 00:50:52,304 我们把它叫做MAKE-DEPOSIT-ACCOUNT of this-- we'll call it make deposit account 925 00:50:52,320 --> 00:50:53,328 因为它只能够存钱 because you can only deposit. 926 00:50:54,176 --> 00:50:55,776 这个过程接受一个初始余额 It takes an initial balance 927 00:50:56,096 --> 00:50:58,096 以及一个可能发起的存款流 and then a stream of deposits you might make. 928 00:51:00,020 --> 00:51:00,820 具体怎么做呢? And what is it? 929 00:51:00,820 --> 00:51:02,544 它只是用CONS-STREAM把余额BALANCE Well, it's just cons-stream of the balance 930 00:51:03,232 --> 00:51:05,312 和一个新的存款账户流组合在一起 onto make a new account stream 931 00:51:06,240 --> 00:51:07,328 新存款流的初始余额 whose initial balance 932 00:51:07,488 --> 00:51:10,272 就是之前BALANCE的值加上存款流的第一个元素 is the old balance plus the first thing in the deposit stream 933 00:51:10,864 --> 00:51:13,408 而其余部分则是 whose rest, right and, 934 00:51:13,760 --> 00:51:17,376 存款流的尾部分 make deposit account works on the rest of which is the tail of the deposit stream. 935 00:51:18,300 --> 00:51:23,840 因此这种非常典型的消息传递式、面向对象的问题 So there's sort of a very typical message-passing, 936 00:51:23,952 --> 00:51:27,552 完全可以不用副作用来解决 message-passing, object-oriented thing that's done without side effects at all. 937 00:51:29,056 --> 00:51:30,768 很多地方都可以这样做 There are very many things you can do this way. 938 00:51:32,250 --> 00:51:35,232 那么 我们可以完全不用赋值么? Well, can you do everything without assignment? 939 00:51:36,400 --> 00:51:39,008 可以只用纯函数式语言吗? Can everybody go over to purely functional languages? 940 00:51:40,050 --> 00:51:42,048 这个问题谁也说不清 Well, we don't know, 941 00:51:42,272 --> 00:51:43,440 好像有些地方 but there seem to be places 942 00:51:43,920 --> 00:51:46,032 纯函数式语言无法派上用场 where purely functional programming breaks down. 943 00:51:48,100 --> 00:51:50,272 当遇到像这样的系统时 问题就变得棘手起来 Where it starts hurting is when you have things like this, 944 00:51:50,432 --> 00:51:52,320 特别是当你 but you also mix it up with 945 00:51:52,608 --> 00:51:54,272 还需要考虑其它因素的时候 the other things that we had to worry that, 946 00:51:54,304 --> 00:51:55,648 有关对象和共享 which are objects and sharing 947 00:51:55,904 --> 00:51:58,528 以及两个独立的主体共享同一个东西 and two independent agents being the same. 948 00:51:58,850 --> 00:51:59,936 举一个典型的例子 So under a typical one, 949 00:51:59,968 --> 00:52:01,632 假如你来扩展这个帐户 suppose you want to extend this bank account. 950 00:52:03,248 --> 00:52:04,272 这是一个帐户 So here's a bank account. 951 00:52:12,220 --> 00:52:14,752 帐户接受一个交易请求流 Bank accounts take in a stream of transaction requests 952 00:52:15,200 --> 00:52:18,448 输出的流则是关于余额的回复 and put out streams of, say, balances or responses to that. 953 00:52:18,780 --> 00:52:20,160 假设你所建模的是联合账户 But suppose you want to model the fact 954 00:52:20,176 --> 00:52:24,368 而由两个独立用户共享 that this is a joint bank account between two independent people. 955 00:52:25,680 --> 00:52:28,656 我们假设 假设有两个人 Right? I don't know. So suppose there are two people, 956 00:52:28,976 --> 00:52:30,960 比如说Bill和Dave say, Bill and Dave, 957 00:52:31,776 --> 00:52:33,140 他们俩共享一个帐户 who have a joint bank account. 958 00:52:35,960 --> 00:52:36,850 怎么来建模呢? How would you model this? 959 00:52:36,880 --> 00:52:39,800 你或许会让Bill输出一个交易请求流 Well, you might, Bill puts out a stream of transaction requests, 960 00:52:40,240 --> 00:52:42,256 Dave也产生一个这样的流 and Dave puts out a stream of transaction requests, 961 00:52:42,256 --> 00:52:45,168 这两个流需要以某种方式合并到银行账户中 and somehow, they have to merge into this bank account. 962 00:52:45,880 --> 00:52:47,856 因此你需要编写一个MERGE过程 So what you might do is write a little stream 963 00:52:47,904 --> 00:52:50,650 来处理这些流 processing thing called merge, 964 00:52:57,232 --> 00:52:59,136 它把这些流合并在一起 which sort of takes these, merges them together, 965 00:52:59,344 --> 00:53:01,190 形成单个流 送入银行账户 produces a single stream for the bank account. 966 00:53:01,190 --> 00:53:02,992 现在他们就共享一个帐户了 Now they're both talking to the same bank account. 967 00:53:03,610 --> 00:53:05,488 看起来不错 问题是怎么来实现MERGE That's all great, but how do you write merge? 968 00:53:05,936 --> 00:53:08,240 MERGE怎么来合并? What, What's this procedure merge? 969 00:53:09,730 --> 00:53:11,424 需要合理的合并依据 You want to do something that's reasonable. 970 00:53:12,380 --> 00:53:13,808 你可能首先会想 Your first guess might be to say, 971 00:53:13,808 --> 00:53:16,688 我们从Bill和Dave中选一个请求来处理 well, we'll take alternate requests from Bill and Dave. 972 00:53:18,190 --> 00:53:20,976 但是如果在这中途 But what happens if But what happens if suddenly in the middle thing 973 00:53:21,184 --> 00:53:23,088 Dave突然外出度假两年 会怎么样? Dave goes away on vacation for two years? 974 00:53:24,150 --> 00:53:25,408 Bill的交易就完全被阻塞了 Then Bill's sort of stuck. 975 00:53:27,690 --> 00:53:29,750 你想要的是 So what you want to do is-- well, it's hard to describe. 976 00:53:29,750 --> 00:53:33,648 是一种公平的合并 What you want to do is what people call fair merge. 977 00:53:38,410 --> 00:53:40,176 这个所谓公平的合并 The idea of fair merge is 978 00:53:40,736 --> 00:53:42,464 应该是交替地一次处理一个 is it sort of should do them alternately, 979 00:53:42,496 --> 00:53:43,920 但是如果一个人没有了交易 but if there's nothing waiting here, 980 00:53:43,968 --> 00:53:44,912 应该继续去处理另一个人的交易 it should take one twice. 981 00:53:46,010 --> 00:53:48,450 但是没有时间 我就不能这样做 Notice I can't even say that without talking about time. 982 00:53:51,300 --> 00:53:56,416 函数式语言的另一个活跃研究领域就是 So one of the other active researcher areas in functional languages 983 00:53:56,432 --> 00:53:59,488 发明类似于“公平合并”的算法 is inventing little things like fair merge 984 00:54:00,350 --> 00:54:01,312 又或者是其它的东西 maybe some others, 985 00:54:01,568 --> 00:54:06,256 用于取代原来需要副作用和对象的地方 which will take the places where I used to need side effects and objects 986 00:54:06,800 --> 00:54:10,528 用一种良好定义的模块化系统来隐藏它们 and sort of hide them away in some very well-defined modules of the system 987 00:54:10,860 --> 00:54:13,504 这样 系统中就不会到处产生 so that all the problems of assignment 988 00:54:13,520 --> 00:54:15,344 赋值所带来的问题 don't sort of leak out all over the system but 989 00:54:15,408 --> 00:54:17,880 因为它可以被理解透彻的概念所描述 are captured in some fairly well-understood things. 990 00:54:20,780 --> 00:54:22,704 推而广之 我想你们也发现了 More generally, I think what you're seeing 991 00:54:23,120 --> 00:54:24,064 我们正面对 我所认为的 is that we're running across 992 00:54:24,080 --> 00:54:26,670 计算机科学中最基本的问题 what I think is a very basic problem in computer science, 993 00:54:26,976 --> 00:54:27,824 也就是 which is how to 994 00:54:28,240 --> 00:54:32,032 我们如何定义一门支持延迟求值的语言 how to define languages that somehow can talk about delayed evaluation 995 00:54:34,144 --> 00:54:35,088 但同时又能够 But also 996 00:54:35,872 --> 00:54:38,256 又能够把事物看做对象来操作 be able to reflect this view that there are objects in the world. 997 00:54:38,360 --> 00:54:40,368 怎么样才能两者兼有之? How do we somehow get both? 998 00:54:41,230 --> 00:54:43,040 我认为这个问题很困难 And I think that's a very hard problem. 999 00:54:43,040 --> 00:54:45,520 但是这个很困难的问题 And it may be that it's a very hard problem 1000 00:54:45,856 --> 00:54:48,176 却和计算机科学的关系不大 that has almost nothing to do with computer science, 1001 00:54:48,590 --> 00:54:50,240 它真正涉及的是 that it really is a problem having to do with 1002 00:54:50,272 --> 00:54:52,736 两种不相容的看待世界的方式 two very incompatible ways of looking at the world. 1003 00:54:54,144 --> 00:54:54,720 有问题吗? OK, questions? 1004 00:55:17,550 --> 00:55:19,200 学生:你之前提到过 AUDIENCE: You mentioned earlier that 1005 00:55:20,112 --> 00:55:21,328 一旦引入了赋值 once you introduce assignment, 1006 00:55:21,328 --> 00:55:25,890 就不能使用代换模型了 the general rule for using the substitution model is you can't. 1007 00:55:25,890 --> 00:55:27,570 除非你非常小心 Unless you're very careful, you can't. 1008 00:55:27,570 --> 00:55:27,968 教授:对的 PROFESSOR: Right. 1009 00:55:28,260 --> 00:55:33,280 学生:有什么技术或者指导方针 AUDIENCE: Is there a set of techniques or a set of guidelines 1010 00:55:33,424 --> 00:55:35,920 来确定赋值的影响 for localizing the effects of assignment 1011 00:55:36,528 --> 00:55:40,300 以便说清楚这个“很小心”是怎么回事吗? so that the very careful becomes defined? 1012 00:55:40,300 --> 00:55:42,608 教授:我不知道 PROFESSOR: I don't know. Um... 1013 00:55:42,890 --> 00:55:43,584 我想想 Let me think. 1014 00:55:45,430 --> 00:55:48,944 当然 实现MEM-PROC也使用了赋值 Well, certainly, there was an assignment inside memo proc, 1015 00:55:50,128 --> 00:55:51,480 但是它被隐藏了起来 but that was sort of hidden away. 1016 00:55:51,480 --> 00:55:53,008 因为它没有对结果造成影响 It ended up not making any difference. 1017 00:55:53,480 --> 00:55:56,448 部分原因之一在于 一旦触发这个过程 Part of the reason for that is once this thing triggered 1018 00:55:57,152 --> 00:55:58,832 它被求值并得到结果 that it had run and gotten an answer, 1019 00:55:58,832 --> 00:56:00,064 这个结果不会再变化 that answer will never change. 1020 00:56:00,608 --> 00:56:02,336 有点像单次赋值 So that was sort of a one-time assignment. 1021 00:56:02,350 --> 00:56:03,856 一个一般性原则就是 So one very general thing you can do 1022 00:56:04,304 --> 00:56:06,352 如果你只用这种单次赋值 is if you only do what's called a one-time assignment 1023 00:56:08,040 --> 00:56:09,248 并且它不再改变 and never change anything, 1024 00:56:09,632 --> 00:56:10,540 我想应该不会有太大问题 then you can do better. 1025 00:56:11,250 --> 00:56:14,128 还有一个问题在于MERGE -- One of the problems in this merge thing, people have-- 1026 00:56:14,672 --> 00:56:18,320 让我想想对不对 people have-- let me see if this is right. 1027 00:56:18,490 --> 00:56:21,552 我认为有了公平合并这一技术 I think it's true that with fair merge, 1028 00:56:22,256 --> 00:56:26,096 你可以在语言的其它地方 with just fair merge, you can begin effectively simulating 1029 00:56:27,024 --> 00:56:28,896 有效地模拟赋值 assignment in the rest of the language. 1030 00:56:30,820 --> 00:56:33,296 这就像为了解决问题你会引入一些东西 It seems like anything you do to go outside-- 1031 00:56:33,504 --> 00:56:35,504 我不清楚对公平合并来说是否成立 I'm not quite sure that's true for fair merge, 1032 00:56:35,536 --> 00:56:39,312 但是对人们正在尝试的一些一般性事情是成立的 but it's true of a little bit more general things that people have been doing. 1033 00:56:39,520 --> 00:56:41,344 所以 这可能是你引入的这一点点东西 So it might be that any little bit you put in, 1034 00:56:41,616 --> 00:56:44,144 突然间 使你能构建任何东西 suddenly if they allow you to build arbitrary stuff, 1035 00:56:44,160 --> 00:56:46,512 这就几乎跟有了赋值一样糟糕了 it's almost as bad as having assignment altogether. 1036 00:56:47,970 --> 00:56:50,672 这也是人们在研究的一个领域 But that's an area that people are thinking about now. 1037 00:56:51,590 --> 00:56:54,304 学生:我还没有太明白MERGE的问题 AUDIENCE: I guess I don't see the problem here with merge 1038 00:56:54,830 --> 00:56:59,200 如果我调用Bill它是个过程 if, you know the sense, I call Bill, if Bill is a procedure, 1039 00:56:59,216 --> 00:57:02,416 那么Bill就会增加银行账户 then Bill is going to increment the bank account 1040 00:57:02,448 --> 00:57:04,730 或者创建一个表 用于放置下一个存款 or build the list that 's going to put in the next element. 1041 00:57:04,730 --> 00:57:06,848 如果我连续调用Dave两次 他肯定也会那样 If I call Dave twice in a row, that will do that. 1042 00:57:07,170 --> 00:57:09,350 我并不清楚为什么需要公平合并 I'm not sure where fair merge has to be involved. 1043 00:57:09,350 --> 00:57:11,200 教授:关键在于你得把这些当作真人一样 PROFESSOR: The problem is imagine these really as people. 1044 00:57:11,200 --> 00:57:14,208 这里有一个用户在操作帐户 See, here I have the user who's interacting with this bank account. 1045 00:57:14,850 --> 00:57:17,070 请求一次 得到结果 Put in a request, get an answer. Put in a request, get an answer. 1046 00:57:17,200 --> 00:57:17,568 学生:对 AUDIENCE: Right. 1047 00:57:18,200 --> 00:57:20,624 教授:如果我只能通过从两个流中选择一个 PROFESSOR: But if the only way I can process request 1048 00:57:20,656 --> 00:57:22,250 来处理请求的话 is to alternate them from two people-- 1049 00:57:22,912 --> 00:57:24,220 学生:为什么要二选一呢? AUDIENCE: Well, why would you alternate them? 1050 00:57:24,220 --> 00:57:25,232 教授:为什么不呢? PROFESSOR: Why don't I? 1051 00:57:25,456 --> 00:57:25,808 学生:对啊 为什么要这样呢? AUDIENCE: Yes. Why do you? 1052 00:57:26,608 --> 00:57:27,728 教授:假设这些是现实中的人 对吗? PROFESSOR: Think of them as real people, right? 1053 00:57:27,760 --> 00:57:28,976 这个人外出一年 This guy might go away for a year. 1054 00:57:29,280 --> 00:57:31,744 你只能在银行账户窗口旁边等待 And you're sitting here at the bank account window, 1055 00:57:32,430 --> 00:57:33,728 就是不能处理两个请求 and you can't put in two requests 1056 00:57:33,744 --> 00:57:34,944 因为你还得等这个人 because it's waiting for this guy. 1057 00:57:35,480 --> 00:57:37,072 学生:为什么非得等他呢? AUDIENCE: Why does it have to be waiting for one? 1058 00:57:37,380 --> 00:57:39,110 教授:因为这里是在计算一个函数 PROFESSOR: Because it's trying to compute a function. 1059 00:57:39,110 --> 00:57:40,928 我必须定义一个函数 I have to define a function. 1060 00:57:41,720 --> 00:57:42,608 换种方式来说 Another way to say that 1061 00:57:42,848 --> 00:57:44,992 这个MERGE盒子的输出 is the answer to what comes out of this merge box 1062 00:57:46,240 --> 00:57:49,488 并不是输入的函数 is not a function of what goes in. 1063 00:57:51,690 --> 00:57:53,490 明白了吗?再来看看这个MERGE是怎么运行的 Because, see, what would the function be? 1064 00:57:53,490 --> 00:57:58,864 假设Bill输入 1 1 1 1 Suppose he puts in 1, 1, 1, 1, 1065 00:57:59,824 --> 00:58:02,784 Dave输入2 2 2 2 and he puts in 2, 2, 2, 2. 1066 00:58:03,470 --> 00:58:04,800 MERGE应该输出什么呢? What's the answer supposed to be? 1067 00:58:05,584 --> 00:58:08,740 这里并不一定是 1 2 1 2 1 2 It's not good enough to say it's 1, 2, 1, 2, 1, 2. 1068 00:58:08,740 --> 00:58:09,390 学生:我明白了 AUDIENCE: I understand. 1069 00:58:09,390 --> 00:58:11,560 当Bill输入1 1也就进去了 But when Bill puts in 1, 1 goes in. 1070 00:58:11,560 --> 00:58:13,950 Dave再输入两个2 MERGE就输出两个2 When Dave puts in 2, twice 2 goes in twice. 1071 00:58:13,950 --> 00:58:14,736 学生:当Bill输入 AUDIENCE: When Bill puts in-- 1072 00:58:14,768 --> 00:58:15,088 教授:对的 PROFESSOR: Right. 1073 00:58:15,130 --> 00:58:18,432 学生:为什么不能在输入的数据上 AUDIENCE: Why can't it be hooked to the time of the input-- 1074 00:58:18,592 --> 00:58:20,064 加上时间信息呢? the actual procedural-- 1075 00:58:20,128 --> 00:58:21,840 教授:因为这里没有时间这个概念 PROFESSOR: Because I don't have time. 1076 00:58:23,980 --> 00:58:26,900 我只是定义一个函数 See, all I can say is I'm going to define a function. 1077 00:58:26,900 --> 00:58:28,150 没有时间概念 I don't have time. 1078 00:58:32,000 --> 00:58:34,192 如果是二选一的话 There's no concept if it's going to alternate, 1079 00:58:34,192 --> 00:58:36,544 如果选中的流没有人 就得等待它 except if nobody's there, it's going to wait a while for him. 1080 00:58:38,420 --> 00:58:41,360 它只会说 我有一个请求流 It's just going to say I have the stream of requests, 1081 00:58:41,740 --> 00:58:43,344 这是是Dave生成的 the timeless infinite streams 1082 00:58:43,360 --> 00:58:45,296 没有时刻的、无穷长度的请求流 of all the requests that Dave would have made, right? 1083 00:58:47,550 --> 00:58:50,416 Bill可能生成 没有时刻的无穷请求流 And the timeless infinite stream of all the requests Bill would have made, 1084 00:58:50,544 --> 00:58:51,690 我想对这些东西做运算 and I want to operate on them. 1085 00:58:51,690 --> 00:58:53,510 这就是银行帐户的工作原理 See, that's how this bank account is working. 1086 00:58:56,710 --> 00:58:57,584 问题是 And the problem is 1087 00:58:57,610 --> 00:59:00,752 这些坐在银行窗口前的倒霉蛋们 that these poor people who are sitting at the bank account windows 1088 00:59:00,768 --> 00:59:03,824 来得并不是时候 have the misfortune to exist in time. 1089 00:59:05,296 --> 00:59:07,136 它们才看不到这个无穷流 They don't see their infinite stream 1090 00:59:07,696 --> 00:59:09,536 什么时候其中会有请求 of all the requests they would have ever made. 1091 00:59:10,070 --> 00:59:11,550 他们只是等着 等待帐户的响应 They're waiting now, and they want an answer. 1092 00:59:14,480 --> 00:59:15,760 假设你坐在屏幕前 So if you're sitting there-- 1093 00:59:16,240 --> 00:59:20,864 操作着一台分时系统的计算机 if this is the screen operation on some time-sharing system 1094 00:59:21,520 --> 00:59:22,608 而且它还是函数式的 and it's working functionally, 1095 00:59:22,640 --> 00:59:24,592 输入指令后你就希望看到结果 you want an answer then when you talk the character. 1096 00:59:25,290 --> 00:59:27,424 但是你并不想主机在处理完所有其它人的命令 You don't want it to have to wait for everybody in the whole system 1097 00:59:27,456 --> 00:59:29,920 之后再来处理你的命令 to have typed one character before it can get around to service you. 1098 00:59:30,910 --> 00:59:31,920 这就是问题所在 So that's the problem. 1099 00:59:34,000 --> 00:59:36,384 我的意思就是 用户的世界当然是存在时间概念的 I mean, the fact that people live in time, apparently. 1100 00:59:37,216 --> 00:59:38,620 如果没有 这就不构成问题 If they didn't, it wouldn't be a problem. 1101 00:59:49,100 --> 00:59:51,024 学生:我想我还是不太理解 AUDIENCE: I'm afraid I miss the point of 1102 00:59:51,088 --> 00:59:54,240 银行交易中为什么没有时间概念这一要点 having no time in this banking transaction. 1103 00:59:54,740 --> 00:59:56,656 难道时间不是非常重要吗? Isn't time very important? 1104 00:59:56,880 --> 00:59:59,056 举例说 有一系列事件 For instance, the sequence of events. 1105 00:59:59,950 --> 01:00:05,024 比如Dave取款$100 As if, If Dave take out $100, and then 1106 01:00:06,304 --> 01:00:08,400 这些顺序应该很重要才对 then the timing sequence should be important. 1107 01:00:08,400 --> 01:00:10,864 你怎么能把它们看作是流呢? How do you treat transactions as streams? 1108 01:00:11,260 --> 01:00:14,260 教授:这就是我一直在强调的 PROFESSOR: Well, that's the thing I'm saying. 1109 01:00:14,260 --> 01:00:15,616 在这个例子中确实做不到那一点 This is an example where you can't. 1110 01:00:17,510 --> 01:00:18,128 做不到 You can't. 1111 01:00:18,160 --> 01:00:20,080 关键在于 这里的输出 What goes, The point is what comes out of here 1112 01:00:20,240 --> 01:00:21,888 并不是这两个输入流 is simply not a function of the stream going in here 1113 01:00:21,920 --> 01:00:23,600 的函数 going in here and the stream going in here. 1114 01:00:24,170 --> 01:00:25,984 这个函数跟这个输入流有关 It's a function of the stream going in here 1115 01:00:26,192 --> 01:00:27,264 还跟这个输入流有关 and the stream going in here 1116 01:00:27,360 --> 01:00:29,072 还包括某种有关时间的信息 and some kind of information about time, 1117 01:00:29,376 --> 01:00:32,368 这也正是正则序语言不想让你知道的 which is precisely what a normal-order language won't let you say. 1118 01:00:34,810 --> 01:00:37,952 学生:为了让这个系统更加函数式 AUDIENCE: In order to brings this back into a more functional perspective, 1119 01:00:38,544 --> 01:00:42,048 我们能不能把Bill和Dave的交易请求附上时间戳 could we just explicitly time stamp all the inputs from Bill and Dave 1120 01:00:42,544 --> 01:00:46,400 而使用时间戳作为公平合并的依据? and define fair merge to just be the sort on those time stamps? 1121 01:00:48,416 --> 01:00:49,550 教授:当然 当然可以 PROFESSOR: Yeah, you can do that. 1122 01:00:49,550 --> 01:00:50,600 你可以那样做 You can do that sort of thing. 1123 01:00:50,600 --> 01:00:52,560 或者 我们可以这样来想象 Another thing you could say is imagine 1124 01:00:52,768 --> 01:00:54,448 我们把这个函数看作是 that really what this function is, 1125 01:00:54,784 --> 01:00:56,880 MERGE每毫秒读一次输入 is that it does a read every microsecond, 1126 01:00:58,860 --> 01:00:59,936 如果没有读到东西 and then if there's none there, 1127 01:00:59,936 --> 01:01:00,970 就认为没有请求 that's considered an empty one. 1128 01:01:00,970 --> 01:01:03,392 这和你刚刚说的那种方式是等价的 That's about equivalent to what you said. 1129 01:01:03,610 --> 01:01:06,080 当然可以这样做 但有点旁门左道 And yes, you can do that, but that's a glitch. 1130 01:01:07,110 --> 01:01:10,144 我们不只是关心函数的具体实现 So it's not quite only implementation we're worried about. 1131 01:01:10,768 --> 01:01:12,736 我们关心的是语言的表达力 We're worried about expressive power in the language, 1132 01:01:12,752 --> 01:01:14,672 我们遇到的困难是 and what we're running across is a real mismatch 1133 01:01:14,992 --> 01:01:17,440 我们不能很容易地表达我们想要表达的东西 between what we can say easily and what we'd like to say. 1134 01:01:19,880 --> 01:01:22,016 学生:听起来好像如果两个人同时发出请求 AUDIENCE: It sounds like where we're getting hung up with that 1135 01:01:22,064 --> 01:01:26,090 这个方法就会出问题 one input from both Bill and Dave at the same time. 1136 01:01:26,120 --> 01:01:28,432 教授:并不只是这个 只要是你定义的都可能出问题 PROFESSOR: It's not quite one, but it's anything you define. 1137 01:01:28,530 --> 01:01:30,576 你当然可以说Dave经常发起两个请求 So you can say Dave can go twice as often, 1138 01:01:30,720 --> 01:01:32,320 但是你如果预先定义了什么 but if anything you predefine, 1139 01:01:32,688 --> 01:01:33,872 这样做也不正确 it's not the right thing. 1140 01:01:36,110 --> 01:01:40,704 你不能确定某些特定函数的输入请求 You can't decide at some particular function of their input requests. 1141 01:01:41,930 --> 01:01:43,376 但是还有更坏的情况 Worse yet, I mean, worse yet, 1142 01:01:44,128 --> 01:01:45,728 有一些情况甚至MERGE也处理不了 there are things that even merge can't do. 1143 01:01:47,290 --> 01:01:49,696 比如突然有一天你想要 One thing you might want to do that's even more general is suddenly 1144 01:01:50,240 --> 01:01:52,470 把另一个人关联在这个银行帐户上 you add somebody else to this bank account system. 1145 01:01:52,470 --> 01:01:54,512 假如这个人是John You go and you add John to this bank account system. 1146 01:01:56,030 --> 01:01:58,896 现在图上就要多一个流 And now there's yet another stream that's going to come into the picture 1147 01:01:58,912 --> 01:02:00,704 在一个我们未曾指定的时候 at some time which we haven't prespecified. 1148 01:02:02,040 --> 01:02:04,000 这种情况甚至公平合并也无法给出合理的合并 So that's something even fair merge can't do, 1149 01:02:04,000 --> 01:02:08,256 还需要有MANAGER一类的东西 and they're things called-- I forget-- manager or something. 1150 01:02:08,860 --> 01:02:11,790 需要一种更一般性的公平合并来解决 That's a generalization of fair merge to allow that. 1151 01:02:11,790 --> 01:02:13,984 有很多研究都在讨论 There's a whole sort of research discipline saying 1152 01:02:14,000 --> 01:02:16,300 通过不断引入新机制 how far can you push this functional perspective 1153 01:02:16,592 --> 01:02:18,720 函数式思维能应用到哪种程度? by adding more and more mechanism? 1154 01:02:19,580 --> 01:02:21,792 在我们不得不使用赋值之前 And how far does that go before the whole thing breaks down 1155 01:02:21,824 --> 01:02:23,408 函数式程序设计能干成什么样? and you might as well been using set anyway. 1156 01:02:25,984 --> 01:02:28,000 学生:看来自动存款就不行 AUDIENCE: But not automatic deposit. 1157 01:02:39,328 --> 01:02:40,496 教授:好的 下课 PROFESSOR: OK, thank you. 1158 01:02:41,328 --> 01:02:51,088 MIT OpenCourseWare http://ocw.mit.edu 1159 01:02:51,080 --> 01:03:00,080 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec7a.srt ================================================ 1 00:00:00,030 --> 00:00:02,688 Learning-SICP学习小组 倾情制作 2 00:00:02,752 --> 00:00:05,968 翻译&&时间轴:邓雄飞、张大伟 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:06,000 --> 00:00:08,752 特别感谢:裘宗燕教授 4 00:00:08,848 --> 00:00:11,408 计算机程序的构造和解释 5 00:00:11,420 --> 00:00:13,248 元循环求值器 I Metacircular Evaluator 6 00:00:15,792 --> 00:00:17,328 教授:今天我们将学习一些 PROFESSOR: Well today we're going to learn about something 7 00:00:17,520 --> 00:00:18,410 非同一般的东西 quite amazing. 8 00:00:19,200 --> 00:00:21,888 我们将对计算机程序 We're going to understand what we mean by a program 9 00:00:22,592 --> 00:00:25,216 有更深层次的理解 a little bit more profoundly than we have up till now. 10 00:00:26,800 --> 00:00:29,120 目前为止 我们一直把程序看作 Up till now, we've been thinking 11 00:00:29,264 --> 00:00:32,096 对机器的描述 programs as describing machines. 12 00:00:32,720 --> 00:00:37,216 举个例子 在这个幻灯片上 So for example, looking at this still store 13 00:00:37,936 --> 00:00:41,776 我们可以看到一个计算阶乘的程序 we see here is a program for factorial. 14 00:00:42,800 --> 00:00:47,312 当然 你可以认为这些字符串描述了 And what it is, is a character string description, if you will, 15 00:00:47,664 --> 00:00:51,984 这个线路图所表示的无穷机器 of the wiring diagram of a potentially infinite machine. 16 00:00:52,496 --> 00:00:54,800 我们可以稍稍地看下 它描述的是什么 And we can look at that a little bit and just see the idea. 17 00:00:55,130 --> 00:00:58,208 这种紧凑的记法 描述的是: That this is a sort of compact notation which says, 18 00:00:58,544 --> 00:01:00,170 如果N是0 结果就是1 if n is 0, the result is one. 19 00:01:00,170 --> 00:01:02,000 N是从这里进入机器的 Well here comes n coming into this machine, 20 00:01:02,336 --> 00:01:03,520 如果它是0的话 and if it's 0, 21 00:01:03,744 --> 00:01:05,200 那么我就控制这个开关 then I control this switch 22 00:01:05,472 --> 00:01:08,208 把它掰到输出为1的那一端 in such a way that the switch allows the output to be one. 23 00:01:09,340 --> 00:01:10,080 否则的话 Otherwise, 24 00:01:10,384 --> 00:01:12,832 就是(* N (FACT (- N 1))) it's n times factorial of n minus one. 25 00:01:12,970 --> 00:01:15,136 我先计算(FACT (- N 1)) Well, I'm computing factorial of n minus one 26 00:01:15,290 --> 00:01:16,688 再把结果乘以N and multiplying that by n, 27 00:01:16,848 --> 00:01:18,912 这样如果N不为0的话 in the case that it's not 0, 28 00:01:18,912 --> 00:01:20,608 这个开关就会输出这里的结果 this switch makes the output come from there. 29 00:01:21,900 --> 00:01:22,320 当然了 Of course, 30 00:01:22,368 --> 00:01:25,130 这个机器可能有无穷多个部件 this is a machine with a potentially infinite number of parts, 31 00:01:25,488 --> 00:01:28,128 因为FACT内部又调用了FACT because factorial occurs within factorial, 32 00:01:28,432 --> 00:01:30,176 因此我们不知道调用栈有多深 so we don't know how deep it has to be. 33 00:01:31,070 --> 00:01:33,552 但到目前为止 But that's basically what our notation 34 00:01:34,224 --> 00:01:37,696 代码对我们来说就是这样的东西了 for programs really means to us at this point. 35 00:01:38,310 --> 00:01:40,592 你可以认为代码是用字符串来描述 It's a character string description, if you will, 36 00:01:41,280 --> 00:01:44,160 某种用其它方式描画的线路图 of a wiring diagram that could also be drawn some other way. 37 00:01:44,900 --> 00:01:46,608 事实上 很多人都向我提议 And, in fact, many people have proposed to me, 38 00:01:46,848 --> 00:01:49,040 说程序设计语言应该像这个一样 是图像化的 programming languages look graphical like this. 39 00:01:49,490 --> 00:01:51,808 不过我不认为用图形表示会有很多优势 I'm not sure I believe there are many advantages. 40 00:01:52,000 --> 00:01:53,792 当然 最主要的劣势就是 The major disadvantage, of course, 41 00:01:53,808 --> 00:01:55,632 它需要占用很大的平面空间 is that it takes up more space on a page, 42 00:01:55,968 --> 00:01:59,952 所以展示和修改起来就非常麻烦 and, therefore, it's harder to pack into a listing or to edit very well. 43 00:02:01,344 --> 00:02:02,160 但是不管怎样 But in any case, 44 00:02:03,580 --> 00:02:05,152 在计算的世界中 there's something very remarkable 45 00:02:05,184 --> 00:02:07,050 还有一个非常重要的东西 that can happen in the computation world 46 00:02:07,648 --> 00:02:10,640 也就是所谓的“通用机器” which is that you can have something called a universal machine. 47 00:02:10,730 --> 00:02:15,248 我们再来看第二张幻灯片 If we look at the second slide, 48 00:02:16,048 --> 00:02:17,184 我们看到的就是 what we see is 49 00:02:18,144 --> 00:02:19,888 名为EVAL的特殊机器 a special machine called eval. 50 00:02:21,260 --> 00:02:22,864 这个叫做EVAL的机器 There is a machine called eval, 51 00:02:22,880 --> 00:02:24,240 也就是我今天要讲解的 and I'm going to show it to you today. 52 00:02:25,824 --> 00:02:26,672 它非常简单 It's very simple. 53 00:02:27,780 --> 00:02:30,800 最了不起的是 它简单得可以写在黑板上 What is remarkable is that it will fit on the blackboard. 54 00:02:33,350 --> 00:02:35,792 然而 EVAL这个机器 However, eval is a machine 55 00:02:36,000 --> 00:02:39,840 是以其它机器的描述作为输入的 which takes as input a description of another machine. 56 00:02:40,450 --> 00:02:42,128 它可以接收一个 It could take the wiring diagram 57 00:02:42,400 --> 00:02:45,584 阶乘机器的线路图作为输入 of a factorial machine as input. 58 00:02:46,490 --> 00:02:47,664 这样一来 Having done so, 59 00:02:48,496 --> 00:02:52,570 它就可以模拟那台阶乘机器 it becomes a simulator for the factorial machine 60 00:02:53,136 --> 00:02:53,792 这样的话 such that, 61 00:02:54,160 --> 00:02:56,368 如果输入6 就会得到720 if you put a six in, out comes a 720. 62 00:02:58,910 --> 00:03:01,680 这是一个非常了不起的机器 That's a very remarkable sort of machine. 63 00:03:02,130 --> 00:03:03,584 而最让人惊奇的是 And the most amazing part of it 64 00:03:03,776 --> 00:03:05,136 它竟然可以写在一个黑板内 it is that it fits on a blackboard. 65 00:03:05,590 --> 00:03:06,656 与之相反的是 By contrast, 66 00:03:07,320 --> 00:03:10,448 我们可以想象一下模拟电子世界中的 one could imagine in the analog electronics world 67 00:03:11,552 --> 00:03:12,864 一台非常不同的机器 a very different machine. 68 00:03:14,576 --> 00:03:16,336 这台机器呢 a machine where, a machine 69 00:03:16,528 --> 00:03:18,816 某种意义上 同样也是“通用机器” which also was, in some sense, universal, 70 00:03:19,260 --> 00:03:23,120 只要你输入一个电路图 where you gave a circuit diagram as one of the inputs, 71 00:03:23,824 --> 00:03:25,744 比如这个小型的低通滤波器 for example, of this little low-pass filter, 72 00:03:26,016 --> 00:03:27,488 单极低通滤波器之类的 one-pole low-pass filter. 73 00:03:28,050 --> 00:03:29,536 你可以想像 And you can imagine that 74 00:03:29,710 --> 00:03:33,152 如果我们扫描这个元件得到扫描线 you could, for example, scan this out-- the scan lines 75 00:03:34,432 --> 00:03:37,130 得到的信号描述的就是 Right? are the signal that's describing 76 00:03:37,392 --> 00:03:40,400 这个机器所模拟的 what this machine is to simulate-- 77 00:03:40,784 --> 00:03:43,392 这个模拟机器EVAL是由电路构成 then the analog of eval which is made out of electrical circuits, 78 00:03:43,680 --> 00:03:45,152 它可以把自己配置成一个滤波器 which configure itself into a filter 79 00:03:45,184 --> 00:03:48,040 响应由电路图指定的频率 has the frequency response specified by the circuit diagram. 80 00:03:49,890 --> 00:03:51,488 这种机器很难制造出来 That's a very hard machine to make, 81 00:03:51,616 --> 00:03:54,064 当然 更不可能用一个黑板就把它说清楚 and, surely, there's no chance that I could put it on a blackboard. 82 00:03:55,670 --> 00:03:57,584 所以今天我们将学习一些神奇的东西 So we're going to see an amazing thing today. 83 00:03:58,430 --> 00:04:00,816 我们将在黑板上见证 We're going to see, on the blackboard, 84 00:04:01,168 --> 00:04:02,496 通用机器 the universal machine. 85 00:04:02,790 --> 00:04:04,416 跟其它程序比起来 And we'll see that among other things, 86 00:04:04,528 --> 00:04:05,808 它真是非常简单 it's extremely simple. 87 00:04:06,780 --> 00:04:08,752 现在 我们已经非常接近 Now, we're getting very close 88 00:04:09,088 --> 00:04:10,976 计算机中真正的精灵了 the real spirit in the computer at this point. 89 00:04:11,280 --> 00:04:14,624 所以为了保持足够的尊重 So I have to show a certain amount of reverence and respect, 90 00:04:15,184 --> 00:04:17,328 我特地穿上外套 so I'm going to wear a suit jacket for the only time 91 00:04:17,520 --> 00:04:19,296 你们应该从没见我穿过 that you'll ever see me wear a suit jacket here. 92 00:04:20,470 --> 00:04:22,736 在这个盛重的场合 And I think I'm also going to 93 00:04:23,552 --> 00:04:26,704 我还得戴上一顶合适的帽子 put on an appropriate hat for the occasion. 94 00:04:28,780 --> 00:04:31,440 开讲前再给大家提个醒 Now, this is a lecturer which I have to warn you-- 95 00:04:34,140 --> 00:04:36,912 那些40岁以下 let's see, normally, people under 40 96 00:04:37,168 --> 00:04:38,490 以及没有孩子的人 and who don't have several children 97 00:04:38,672 --> 00:04:40,496 你们可要小心了 are advised to be careful. 98 00:04:40,490 --> 00:04:41,968 如果真的受不了 可以选择离开 If they're really worried, they should leave. 99 00:04:43,340 --> 00:04:45,568 因为一会儿要发生一些 Because there's a certain amount of 100 00:04:45,728 --> 00:04:47,130 非常神秘的事情 mysticism that will appear here 101 00:04:47,744 --> 00:04:51,056 可能使你的大脑异常混乱 which may be disturbing and cause trouble in your minds. 102 00:04:51,820 --> 00:04:54,288 好了 无论如何 Well in any case, let's see, 103 00:04:55,712 --> 00:05:01,104 我要带着你们写一个Lisp求值器 I wish to write for you the evaluator for Lisp. 104 00:05:02,510 --> 00:05:04,288 求值器并不复杂 Now the evaluator isn't very complicated. 105 00:05:05,020 --> 00:05:07,632 很像我们以前见到过的程序 It's very much like all the programs we've seen already. 106 00:05:08,240 --> 00:05:09,488 这也是它令人吃惊的地方 That's the amazing part of it. 107 00:05:10,860 --> 00:05:13,104 现在我开始写这个程序 It's going to be-- and I'm going to write it right here-- 108 00:05:15,280 --> 00:05:16,620 我把这个程序叫做EVAL it's a program called eval. 109 00:05:22,900 --> 00:05:26,240 这个过程接收两个参数 And it's a procedure of two arguments 110 00:05:26,280 --> 00:05:29,440 表达式EXP和环境ENV expression and an environment. 111 00:05:31,860 --> 00:05:33,792 跟所有实用过程一样 And like every interesting procedure, 112 00:05:34,016 --> 00:05:35,136 它是个“按情况分析”语句 it's a case analysis. 113 00:05:40,460 --> 00:05:41,872 但是在我开始之前 But before I start on this, 114 00:05:42,528 --> 00:05:43,904 我还想你们注意一下 I want to tell you some things. 115 00:05:44,448 --> 00:05:46,064 我将要在黑板上写的程序 The program we're going to write on the blackboard 116 00:05:46,560 --> 00:05:50,240 非常丑陋、混乱、令人作呕 is ugly, dirty, disgusting, 117 00:05:50,944 --> 00:05:53,168 并不是一种专业的写法 not the way I would write this is a professional. 118 00:05:54,320 --> 00:05:56,576 它是用具体语法写就的 It is written with concrete syntax, 119 00:05:57,248 --> 00:05:58,832 也就是说用了很多CAR、CDR meaning you've got really to use lots of CARs and CDRs 120 00:05:58,848 --> 00:06:00,624 我之前告诉过你们这样写并不好 which is exactly what I told you not to do. 121 00:06:02,944 --> 00:06:05,616 在这里是故意这样来写的 That's on purpose in this case, 122 00:06:06,110 --> 00:06:09,024 因为我想让它尽量精简 because I want it to be small, compact, 123 00:06:09,344 --> 00:06:10,400 能塞在黑板内 fit on the blackboard 124 00:06:10,432 --> 00:06:11,856 你们就可以看到整个代码 so you can get the whole thing. 125 00:06:12,420 --> 00:06:14,800 我就不像平时那样实用长变量名了 So I don't want to use long names like I normally use. 126 00:06:15,600 --> 00:06:17,296 就用CAR、CDR 因为它们短小 I want to use CAR-CDR because it's short. 127 00:06:18,060 --> 00:06:20,784 这算是一种取舍 Okay, I wanna, it's a whole, that's a trade-off. 128 00:06:20,896 --> 00:06:22,816 我不希望你们这样来写程序 I don't want you writing programs like this. 129 00:06:23,570 --> 00:06:25,088 这里单纯地想达到一种简洁的效果 This is purely for an effect. 130 00:06:25,850 --> 00:06:27,616 因此你们读起来可能有些费力 Now, you're going to have to work a little harder to read it, 131 00:06:27,776 --> 00:06:30,192 我尽量写得清楚一些 but I'm going to try to make it clear as I'm writing it. 132 00:06:31,270 --> 00:06:34,400 这个解释器已经比较完整了 I'm also-- this is a pretty much complete interpreter, 133 00:06:34,512 --> 00:06:36,240 但是还是缺少一些功能 but there's going to be room for putting in more things-- 134 00:06:36,256 --> 00:06:38,608 我就不写定义和赋值的部分了 I'm going to leave out definition and assignment, 135 00:06:39,104 --> 00:06:42,416 因为它们都不是最本质的 just because they are not essential, 136 00:06:42,880 --> 00:06:46,464 稍后我就会解释 这是数学上的原因 and a, for a mathematical reason I'll show you later 137 00:06:46,928 --> 00:06:49,968 当然啦 黑板也没有那么大 and also they take up more space. 138 00:06:51,888 --> 00:06:53,648 但是 我们怎么做呢? But, in any case, what do we have to do? 139 00:06:53,952 --> 00:06:55,664 我们需要一个分派 We have to do a dispatch 140 00:06:56,096 --> 00:06:57,904 它根据表达式的类型 which breaks the types of expressions up 141 00:06:58,288 --> 00:07:00,384 把它们划分为几类 into particular classes. 142 00:07:01,728 --> 00:07:03,264 这就是现在要做的 Okay? So that's what we're going to have here. 143 00:07:03,824 --> 00:07:05,150 我们都有哪些表达式? Well, what expressions are there? 144 00:07:05,150 --> 00:07:06,368 我们先来看几种表达式 Let's look at the kinds of expressions. 145 00:07:06,810 --> 00:07:09,600 比如说 数字“3”就是一个表达式 We can have things like the numeral three. 146 00:07:10,420 --> 00:07:11,584 我想让它代表什么呢? What do I want that to do? 147 00:07:12,720 --> 00:07:14,752 我有很多选择 但是就现在而言 I can make choices, but I think right now, 148 00:07:15,056 --> 00:07:16,208 我就想让它表示数字3 I want it to be a three. 149 00:07:17,050 --> 00:07:17,888 这就是我要的 That's what I want. 150 00:07:18,720 --> 00:07:19,696 这个足够简单 So that's easy enough. 151 00:07:20,032 --> 00:07:22,912 那就意味着 如果表达式是数字 That means I want, if the thing is a number, 152 00:07:27,290 --> 00:07:31,680 表达式本身就应该是求值结果 that I want the expression itself as the answer. 153 00:07:35,420 --> 00:07:36,768 另外一种情况是 Now the next possibility 154 00:07:36,896 --> 00:07:38,864 表达式还可能是符号 is things that we represent as symbols. 155 00:07:39,390 --> 00:07:46,752 比如EXP、ENV、EVAL、NUMBER、X之类 Examples of symbols are things like x, n, eval, number, x. 156 00:07:48,016 --> 00:07:49,184 它们意味着什么? What do I mean them to be? 157 00:07:50,160 --> 00:07:51,632 它们是一类代表其它事物的事物 Those are things that stand for other things. 158 00:07:51,632 --> 00:07:53,232 也就是我们语言中所谓的变量 Those are the variables of our language. 159 00:07:54,770 --> 00:07:56,880 因此我想要能够 比如说 And so I want to be able to say, for example, 160 00:07:57,056 --> 00:08:01,040 对X求值 可能会得到3 that x, for example, transforms to it's value which might be three. 161 00:08:02,640 --> 00:08:05,760 又可能是CAR Or I might ask something like car. 162 00:08:07,760 --> 00:08:09,408 我希望它的值是 I want to have as its value-- 163 00:08:09,632 --> 00:08:11,344 某种类似于过程的东西 be something like some procedure, 164 00:08:16,512 --> 00:08:18,432 我不需要知道它内部是什么 which I don't know what is inside there, 165 00:08:18,640 --> 00:08:21,152 可能是一些机器码 或者类似的东西 perhaps a machine language code or something like that. 166 00:08:22,848 --> 00:08:24,272 到这是还是相对简单的 Ok? So, well, that's easy enough. 167 00:08:24,430 --> 00:08:26,896 我想把这部分交给其他人来写 I'm going to push that off on someone else. 168 00:08:27,808 --> 00:08:28,896 如果我们有一个符号 If something is a symbol, 169 00:08:30,800 --> 00:08:32,480 假如表达式是符号 if the expression is a symbol, 170 00:08:33,424 --> 00:08:34,880 那么我求值它的结果就应该是 then I want the answer to be the result, 171 00:08:34,912 --> 00:08:40,240 在环境ENV中查找该表达式的值 looking up the expression in the environment. 172 00:08:46,480 --> 00:08:48,992 环境是一个字典 Now the environment is a dictionary 173 00:08:49,968 --> 00:08:54,060 它把符号映射成一个值 which maps the symbol names to their values. 174 00:08:54,288 --> 00:08:55,168 就这么简单 And that's all it is. 175 00:08:56,280 --> 00:08:57,200 怎么完成的呢? How it's done? 176 00:08:57,530 --> 00:08:58,528 稍后我们再谈这个 Well, we'll see that later. 177 00:08:59,680 --> 00:09:00,576 其实并不难 It's very easy. 178 00:09:01,670 --> 00:09:04,288 编写类似于表的数据结构非常容易 It's easy to make data structures that are tables of various sorts. 179 00:09:04,840 --> 00:09:05,744 但它只是一个表 But it's only a table, 180 00:09:05,776 --> 00:09:07,560 而这是存取某个表的过程 and this is the access routine for some table. 181 00:09:09,550 --> 00:09:10,816 好的 接下来 Ok? Well, the next thing, 182 00:09:11,312 --> 00:09:12,560 另一类表达式 another kind of expression-- 183 00:09:12,672 --> 00:09:15,568 表达式可能是一些不是数字的常量 you have things that are described constants that are not numbers, 184 00:09:16,064 --> 00:09:17,430 比如 'FOO like 'foo. 185 00:09:20,170 --> 00:09:21,296 为了方便起见 Well, for my convenience, 186 00:09:21,312 --> 00:09:23,360 我想在语法上 I want to syntactically transform that 187 00:09:24,736 --> 00:09:26,800 把它转换成表结构 into a list structure which is, 188 00:09:26,848 --> 00:09:31,520 比如说是(QUOTE FOO) which is, quote foo. 189 00:09:33,728 --> 00:09:37,180 一个被引用起来的对象 无论它是什么 Or it's -- A quoted object, whatever it is, 190 00:09:38,352 --> 00:09:40,832 都实际上是一个缩写 is going to be actually an abbreviation, 191 00:09:41,040 --> 00:09:42,592 这一部分并不由求值器负责 which is not part of the evaluator 192 00:09:43,216 --> 00:09:44,464 这是在其它地方完成的 but happens somewhere else, 193 00:09:44,752 --> 00:09:47,792 左边的符号就是右边表达式的缩略形式 an abbreviation for an expression that looks like this. 194 00:09:48,780 --> 00:09:50,480 这样 我就可以 This way, I can test for 195 00:09:50,576 --> 00:09:53,120 依据表达式的CAR部分 the type of the expression as being a quotation 196 00:09:53,312 --> 00:09:55,952 来判断它的类型了 by examining the car of the expression. 197 00:09:58,460 --> 00:10:01,088 因此这一部分也不会出现在求值器中 So I'm not going to worry about that in the evaluator. 198 00:10:01,650 --> 00:10:02,688 这在更早时候 It's happening somewhere earlier 199 00:10:02,700 --> 00:10:03,968 比如源代码读取阶段完成 in the reader or something. 200 00:10:05,540 --> 00:10:15,040 如果是引用表达式 If the expression of the expression is quote, 201 00:10:18,272 --> 00:10:19,104 那么求值的结果就是 then what I want, 202 00:10:19,630 --> 00:10:25,136 我想让(QUOTE FOO)求值为自身FOO I want quote foo to itself evaluate to foo. 203 00:10:25,140 --> 00:10:25,952 一个常量 It's a constant. 204 00:10:27,530 --> 00:10:28,928 这条代码是说 This is just a way of saying 205 00:10:29,088 --> 00:10:30,736 这类表达式求值为它自己 that this evaluates to itself. 206 00:10:31,792 --> 00:10:33,660 怎么才能把它取出来呢? Ok? So thats the. What is that? 207 00:10:33,660 --> 00:10:36,368 这是列表第二个元素的第一个部分 That's the first of the second of the list. 208 00:10:36,592 --> 00:10:37,584 也就是表的第二个元素 That's the second of the list. 209 00:10:38,496 --> 00:10:40,320 也就是CADR The second element of the list is it's CADR. 210 00:10:41,280 --> 00:10:42,384 所以这里我就写CADR So I'm just going to write here, CADR. 211 00:10:51,088 --> 00:10:52,352 表达式还可能是什么类型呢? OK? What else do we have here? 212 00:10:52,510 --> 00:10:53,808 还有LAMBDA表达式 We have lambda expressions, 213 00:10:55,008 --> 00:11:03,296 比如 (LAMBDA (X) (+ X Y)) for example, lambda of x plus x y. 214 00:11:04,160 --> 00:11:06,336 我还得找到某种表示方法 Well, I going have to have some representation for the procedure 215 00:11:06,336 --> 00:11:07,856 LAMBDA表达式求值的结果 which is the value of an expression, 216 00:11:08,112 --> 00:11:09,088 也就是如何表示过程 of a lambda expression. 217 00:11:09,600 --> 00:11:12,624 过程并不就是表达式(LAMBDA (x)) The procedure here is not the expression lambda x. 218 00:11:13,136 --> 00:11:15,568 表达式只是过程的代码描述 That's the description of it, the textual description. 219 00:11:16,416 --> 00:11:18,330 如果在词法作用域的语言中实现过程 However, what what I going to expect to see here 220 00:11:18,560 --> 00:11:21,200 那么我希望在表示过程的时候 is something which contains an environment as one of its parts 221 00:11:23,232 --> 00:11:25,360 能够把当前的求值环境包括进来 if I'm implementing a lexical language. 222 00:11:25,840 --> 00:11:29,072 所以这里我还需要 And so what I'd like to see 223 00:11:29,200 --> 00:11:30,672 一些类型标志 is some type flags. 224 00:11:30,704 --> 00:11:33,904 这样后面我就可以用它们来区分过程 I'm going to have to be able to distinguish procedures later, 225 00:11:34,304 --> 00:11:36,592 看哪些是由LAMBDA表达式生成的 procedures which were produced by lambdas, 226 00:11:36,816 --> 00:11:38,032 哪些是基本过程 from ones that may be primitive. 227 00:11:39,060 --> 00:11:41,968 所以这里是个类型标志 And so I'm going to have some flag, 228 00:11:41,984 --> 00:11:43,568 出于历史原因 which I'll just arbitrarily call closure, 229 00:11:43,568 --> 00:11:45,104 我用CLOSURE作为类型标志 just for historical reasons. 230 00:11:47,680 --> 00:11:49,600 现在来看看 哪部分比较重要 Now, to say what parts of this are important. 231 00:11:49,920 --> 00:11:51,120 我需要知道 I'm going to need to know 232 00:11:51,248 --> 00:11:52,928 绑定变量表和过程的体 the bound variable list and the body. 233 00:11:54,220 --> 00:11:55,408 这是它的CDR部分 Well, that's the CDR of this, 234 00:11:56,096 --> 00:12:01,856 这里就是((X) (+ X Y)) so it's going to be x and plus x y and some environment. 235 00:12:03,040 --> 00:12:03,872 以及某个环境 and some environment. 236 00:12:08,170 --> 00:12:12,208 用户不应该看到这个东西 Now this is not something that users should ever see, 237 00:12:13,536 --> 00:12:16,192 这只是过程对象的 this is purely a representation, internally, 238 00:12:16,768 --> 00:12:18,304 一种内部表示 for a procedure object. 239 00:12:18,520 --> 00:12:20,528 它包括绑定变量表 It contains a bound variable list, 240 00:12:20,704 --> 00:12:22,624 过程的体和某个环境 a body, and an environment, 241 00:12:23,536 --> 00:12:25,808 以及一个类型标签 表示这是一个过程 and some type tag saying, I am a procedure. 242 00:12:26,340 --> 00:12:27,376 接下来写代码 I'm going to make one now. 243 00:12:28,080 --> 00:12:38,720 如果表达式的CAR部分是'LAMBDA So if the CAR of the expression is quote lambda, 244 00:12:43,472 --> 00:12:44,816 这里 我就要 then what I'm going to put here 245 00:12:45,648 --> 00:12:51,840 创建一个表 表头是'CLOSURE is-- I'm going to make a list of closure, 246 00:12:55,150 --> 00:13:00,736 接着是 过程代码的CDR部分 the CDR of the procedure description 247 00:13:01,568 --> 00:13:02,976 也就是除开LAMBDA的其它部分 was everything except the lambda, 248 00:13:07,744 --> 00:13:08,864 以及当前的环境 and the current environment. 249 00:13:10,250 --> 00:13:15,328 这样就实现了环境模型中的那些规则 This implements the rule for environments in the environment model. 250 00:13:15,456 --> 00:13:18,528 这是从LAMBDA表达式中构建过程所必须遵守的 It has to do with construction of procedures from lambda expressions. 251 00:13:19,408 --> 00:13:20,976 那个求值器在遇到 The environment that was around 252 00:13:21,488 --> 00:13:24,320 LAMBDA表达式时的环境 at the time the evaluator encountered the lambda expression 253 00:13:25,040 --> 00:13:28,464 在过程运行的时候 is the environment where the lambda expression gets 254 00:13:28,688 --> 00:13:31,776 会去这个环境中查找自由变量的值 where the procedure resulting interprets it's free variables. 255 00:13:34,720 --> 00:13:35,824 所以需要把它囊括进来 So that's part of that. 256 00:13:35,920 --> 00:13:37,552 因此我们必须把求值时的环境 And so we have to capture that environment 257 00:13:37,568 --> 00:13:38,860 作为过程对象的一部分 as part of the procedure object. 258 00:13:39,210 --> 00:13:40,624 之后再来看它的作用 And we'll see how that gets used later. 259 00:13:42,032 --> 00:13:43,776 我们也有COND表达式 There are also conditional expressions 260 00:13:44,592 --> 00:13:52,816 像是(COND (P1 E1) (P2 E2) ...)这样的 of things like COND of say, p one, e one, p two, e two. 261 00:13:54,400 --> 00:13:56,096 P1是谓词 Where this is a predicate, 262 00:13:56,352 --> 00:13:58,432 谓词总是返回TRUE或者FALSE a predicate is a thing that is either true or false, 263 00:13:58,992 --> 00:14:01,760 如果谓词P1为真时 表达式E1才被求值 and the expression to be evaluated if the predicate is true. 264 00:14:03,440 --> 00:14:06,080 当然 你也可以列这么一组子句 A set of clauses, if you will, that's the name for such a thing. 265 00:14:06,790 --> 00:14:09,360 我会把它封装在另一个过程中 So I'm going put that somewhere else. 266 00:14:09,360 --> 00:14:11,568 我们稍后在那个过程中进行处理 We're going to worry about that in another piece of code. 267 00:14:12,420 --> 00:14:21,280 如果表达式的CAR部分是'COND的话 So EQ-- if the CAR of the expression is COND, 268 00:14:24,000 --> 00:14:26,848 那么我就用EVCOND来求值这个表达式 then I'm going to do nothing more than evaluate the COND, 269 00:14:30,208 --> 00:14:31,424 求值表达式的CDR部分 the CDR of the expression. 270 00:14:34,400 --> 00:14:38,496 记得带上环境 That's all the clauses in the environment that I'm given. 271 00:14:41,430 --> 00:14:42,608 好的 还有一种情况 Well, there's one more case, 272 00:14:44,096 --> 00:14:48,224 任意的像(+ X 3)这样的表达式 arbitrary thing like the sum of x and three, 273 00:14:50,624 --> 00:14:53,952 这是把运算符应用在运算对象上 where this is an operator applied to operands, 274 00:14:55,136 --> 00:14:56,590 这并没有什么特殊的 and there's nothing special about it. 275 00:14:56,590 --> 00:14:59,632 就是说 它不属于这里的特殊形式 It's not one of the special cases, the special forms. 276 00:14:59,850 --> 00:15:01,424 上面写的这些都是特殊形式 These are the special forms. 277 00:15:09,650 --> 00:15:12,128 再说明一下 如果我要把这个程序写得专业一点 And if I were writing here a professional program, again, 278 00:15:12,368 --> 00:15:14,176 我会把它设计成数据导向的 I would somehow make this data directed. 279 00:15:14,480 --> 00:15:16,528 那样的话 这里就不会是一系列的条件判断 So there wouldn't be a sequence of conditionals here, 280 00:15:16,656 --> 00:15:18,208 而是根据一些比特位来做分派 there'd be a dispatch on some bits 281 00:15:19,424 --> 00:15:22,256 这样来设计会更加专业一些 if I were trying to do this in a more professional way. 282 00:15:22,360 --> 00:15:24,144 并且 我不用大量修改程序 So that, in fact, I can add to the thing 283 00:15:24,688 --> 00:15:26,384 就可以添加规则 without changing my program much. 284 00:15:26,710 --> 00:15:28,464 这样来做可能运行得更快 So, for example, they would run fast, 285 00:15:29,040 --> 00:15:30,432 但这里我并不打算这么做 but I'm not worried about that. 286 00:15:31,280 --> 00:15:33,984 现在的目的是把握EVAL过程的整体 Here we're trying to look at this in its entirety. 287 00:15:35,072 --> 00:15:35,808 那么 最后一种情况 So it's else. 288 00:15:37,696 --> 00:15:38,560 要怎么做呢? Well, what do we do? 289 00:15:38,560 --> 00:15:41,232 在这种情况下 我需要进行加法运算 In this case, I have to somehow do an addition. 290 00:15:44,350 --> 00:15:46,160 那么我就得搞清楚 '+到底是什么 Well, I could find out what the plus is. 291 00:15:46,848 --> 00:15:49,296 我还得知道X和3又代表什么 I have to find out what the x and the three are. 292 00:15:50,550 --> 00:15:53,968 然后再把'+的所代表的东西 And then I have to apply the result of finding what the plus is 293 00:15:54,432 --> 00:15:57,008 应用于'X与3所代表的东西上 to the result of finding out what the x and the three are. 294 00:15:58,112 --> 00:15:59,392 具体来写一下 We'll have a name for that. 295 00:15:59,872 --> 00:16:09,550 我要把表达式CAR部分的求值结果 So I'm going to apply the result of evaluating the CAR 296 00:16:11,200 --> 00:16:12,140 应用在 of the expression-- 297 00:16:13,216 --> 00:16:15,504 表达式的CAR部分就是运算符 the car of the expression is the operator-- 298 00:16:17,200 --> 00:16:18,512 要在给定的环境中进行 in the environment given. 299 00:16:20,512 --> 00:16:22,896 对运算符求值会得到一个过程 So evaluating the operator gets me the procedure. 300 00:16:24,050 --> 00:16:26,784 现在 我要求值所有运算对象来取得参数 Now I have to evaluate all the operands to get the arguments. 301 00:16:27,290 --> 00:16:28,224 我将调用EVLIST I'll call that EVLIST, 302 00:16:31,264 --> 00:16:35,536 来求值表达式的CDR部分 也就是运算对象 the CDR of the operands, of the expression, 303 00:16:36,768 --> 00:16:39,008 当然是在相应的环境中 with respect to the environment. 304 00:16:41,940 --> 00:16:43,136 我们待会儿再定义EVLIST EVLIST will come up later-- 305 00:16:43,264 --> 00:16:48,070 (闭合括号中) EVLIST, apply, COND pair, COND, lambda, define. 306 00:16:50,900 --> 00:16:52,336 你现在看到的 So that what you are seeing here 307 00:16:52,670 --> 00:16:56,112 基本上就是一个完整的求值器 is pretty much all there is in the evaluator itself. 308 00:16:56,496 --> 00:17:01,000 它根据表达式的类型分情况处理 It's the case dispatch on the type of the expression 309 00:17:01,240 --> 00:17:02,112 默认的情况是 with the default 310 00:17:04,992 --> 00:17:07,950 表达式应用或者说是组合式 being a general application or a combination. 311 00:17:17,520 --> 00:17:19,520 不过还有好些过程 我们没有定义 Now there is lots of things we haven't defined yet. 312 00:17:20,080 --> 00:17:21,600 接下来就看这些未定义的部分 Let's just look at them and see what they are. 313 00:17:21,780 --> 00:17:24,128 我们还要定义EVCOND We're going to have to do this later, evcond. 314 00:17:25,480 --> 00:17:26,672 我得定义APPLY We have to write apply. 315 00:17:27,570 --> 00:17:28,624 还有EVLIST We're going to have to write EVLIST. 316 00:17:28,944 --> 00:17:30,208 以及LOOKUP We're going to write LOOKUP. 317 00:17:31,790 --> 00:17:33,430 我看看 没别的了吧? I think that's everything, isn't there? 318 00:17:33,430 --> 00:17:35,168 剩下的东西都很简单 Everything else is something which is simple, 319 00:17:35,168 --> 00:17:37,184 比如基本元素之类的东西 or primitive, or something like that. 320 00:17:38,570 --> 00:17:39,488 当然 And, of course, 321 00:17:39,696 --> 00:17:42,064 在这里 可以扩充很多特殊形式 we could many more special forms here, 322 00:17:42,256 --> 00:17:44,450 但如果在通用语言中这么做就很糟糕 but that would be a bad idea in general in a language. 323 00:17:44,450 --> 00:17:45,920 在这里添加大量的东西 You make a language very complicated 324 00:17:46,000 --> 00:17:47,488 会让语言变得复杂 by putting a lot of things in there. 325 00:17:47,690 --> 00:17:50,352 语言中的保留字 The number of reserve words that should exist in a language 326 00:17:50,768 --> 00:17:53,616 不该比你能用几个手指、脚指记住的数目多 should be no more than a person could remember on his fingers and toes. 327 00:17:54,160 --> 00:17:55,536 有些语言的保留字有成百上千个 And I get very upset with languages 328 00:17:55,568 --> 00:17:58,208 我都不知道该说什么了 which have hundreds of reserve words. 329 00:17:59,410 --> 00:18:00,710 保留字就是在这里定义的 But that's where the reserve words go. 330 00:18:03,152 --> 00:18:06,540 好 接下来 我们来看下一个部分 Okay. Well, now let's get to the next part of this, 331 00:18:06,560 --> 00:18:07,690 求值器的核心 APPLY the kernel, apply. 332 00:18:09,640 --> 00:18:10,752 它还做些什么呢? What else is this doing? 333 00:18:11,590 --> 00:18:17,536 APPLY把还是符号状态的求值运算符和运算对象 Well, apply's job is to take a procedure and apply it to its arguments 334 00:18:17,664 --> 00:18:20,688 求值为相应的过程以及参数值 after both have been evaluated to come up with a procedure and the arguments 335 00:18:20,912 --> 00:18:23,856 然后把得到的过程应用在参数上 rather the operator symbols and the operand symbols, 336 00:18:24,096 --> 00:18:26,960 无论它们是什么符号表达式 whatever they are-- symbolic expressions. 337 00:18:33,270 --> 00:18:35,088 我们把APPLY定义为 So we will define apply 338 00:18:38,352 --> 00:18:40,656 接收两个参数的过程 to be a procedure of two arguments, 339 00:18:40,752 --> 00:18:43,440 一个过程和对应的参数 a procedure and arguments. 340 00:18:47,248 --> 00:18:48,128 它要怎么做呢? And what does it do? 341 00:18:48,144 --> 00:18:49,552 其实并不复杂 It does nothing very complicated. 342 00:18:49,936 --> 00:18:50,784 分两种情况就够了 It's got two cases. 343 00:18:53,580 --> 00:18:55,168 如果这个过程是基本过程-- Either the procedure is primitive-- 344 00:19:03,424 --> 00:19:06,416 我不知道这个谓词具体是如何判断的 And I don't know exactly how that is done. 345 00:19:06,864 --> 00:19:10,240 可能这里面有某种类型信息 It's possible there's some type information 346 00:19:10,384 --> 00:19:12,416 就像我们在这里用'CLOSURE just like we made closure for, here, 347 00:19:12,688 --> 00:19:15,056 来描述一些复合对象一样 being the description of the type of a compound thing-- 348 00:19:16,336 --> 00:19:17,792 我想可能是这样 OK? probably so. 349 00:19:18,550 --> 00:19:20,208 但是具体怎么判断并不重要 But it is not essential how that works, 350 00:19:20,688 --> 00:19:22,016 事实上 in fact, it turns out, 351 00:19:22,192 --> 00:19:23,856 你可能已经知道或者推断过 as you probably know or have deduced, 352 00:19:23,872 --> 00:19:25,472 我们并不需要任何基本过程 that you don't need any primitives anyway. 353 00:19:27,350 --> 00:19:29,280 就算没有它们 照样可以进行计算 You can compute anything because without 354 00:19:30,464 --> 00:19:33,190 因为我们可以用一直在用的LAMBDA because some of the lambda that I've been playing with. 355 00:19:33,616 --> 00:19:34,768 但是有它们总归方便点儿 But it's nice to have them. 356 00:19:34,810 --> 00:19:36,272 我在这儿略施魔法 So here we're going to do some magic 357 00:19:36,304 --> 00:19:37,470 但不会去解释 which I'm not going to explain. 358 00:19:38,060 --> 00:19:41,440 转到机器语言 执行APPLY-PRIMOP Go to machine language, apply primop. 359 00:19:42,912 --> 00:19:43,808 加法是在这里运算的 Here's how it adds. 360 00:19:44,784 --> 00:19:46,100 执行加法指令 Execute an add instruction. 361 00:19:50,620 --> 00:19:52,112 然而一门语言有趣的部分 However, the interesting part of a language 362 00:19:52,144 --> 00:19:54,270 在于组合基本元素的粘合剂 is the glue by which the primitives are glued together. 363 00:19:54,912 --> 00:19:55,904 我们接着往下看 So let's look at that. 364 00:19:56,910 --> 00:19:58,384 另一种可能就是 Well, the other possibility 365 00:19:58,752 --> 00:20:04,128 这个复合对象是求值LAMBDA表达式得到的 this is a compound made up by executing a lambda expression, 366 00:20:04,976 --> 00:20:07,056 这是个复合过程 this is a compound procedure. 367 00:20:07,620 --> 00:20:09,360 检测它的类型标志 Well, we'll check its type. 368 00:20:10,110 --> 00:20:17,072 如果是'CLOSURE If it is closure, 369 00:20:20,512 --> 00:20:24,096 如果是的话 我就得求值这个过程的体 if it's one of those, then I have to do an eval of the body. 370 00:20:24,190 --> 00:20:27,392 过程的体的求值方式则是 The way I do this, the way I deal with this at all 371 00:20:28,080 --> 00:20:31,696 我求值过程的应用是通过 is the way I evaluate the application of a procedure to its arguments, 372 00:20:31,720 --> 00:20:33,710 先扩充程序的求值环境 is by evaluating the body of the procedure 373 00:20:34,192 --> 00:20:37,808 在这个环境中 把过程的形式参数 in the environment resulting from extending the environment of the procedure 374 00:20:37,920 --> 00:20:40,480 跟传递过来的实际参数绑定在一起 with the bindings of the formal parameters 375 00:20:41,024 --> 00:20:43,680 在这个环境中求值过程的体 of the procedure to the arguments that were passed to it. 376 00:20:46,704 --> 00:20:47,872 这句话很长 That was a long sentence. 377 00:20:51,130 --> 00:20:52,160 但其实简单 Well that's easy enough. 378 00:20:52,820 --> 00:20:54,480 一会儿可能会出现许多CAR CDR... Now here's going to be a lot of CAR-CDRing. 379 00:20:56,464 --> 00:20:58,110 现在我先要得到过程体 I have to get the body of the procedure. 380 00:20:59,400 --> 00:21:02,304 如何取出过程体呢? Where's the body of the procedure in here? 381 00:21:02,960 --> 00:21:04,080 这里是CAR部分 Well here's the CAR, 382 00:21:04,496 --> 00:21:06,130 这一块是剩下部分的CDR部分 here's the CDR is the whole rest of this. 383 00:21:06,130 --> 00:21:06,960 因此这就是CADR So here's the CADR. 384 00:21:07,400 --> 00:21:09,456 所以这里我得到的过程体 And so I see, what I have here is the body 385 00:21:09,456 --> 00:21:13,040 是过程对象第二个元素的第二个元素 is the second element of the second element of the procedure. 386 00:21:13,200 --> 00:21:15,152 因此CADR的CADR 也就是CADADR So it's the CADR of the CADR or the CADADR. 387 00:21:19,170 --> 00:21:27,680 这里取过程对象的CADADR部分 It's the C-A-D-A-D-R, CADADR of the procedure. 388 00:21:30,260 --> 00:21:31,560 为了求值过程体 To evaluate the body 389 00:21:31,984 --> 00:21:36,480 要在参数绑定后的新环境之中进行 in the result of binding that's making up more environment, 390 00:21:38,096 --> 00:21:42,064 我还得获取过程的形式参数 well I need the formal parameters of the of the procedure, 391 00:21:42,064 --> 00:21:42,720 要怎么取呢? what is that? 392 00:21:43,500 --> 00:21:45,136 就是CADR部分的CAR部分 That's the CAR of the CADR. 393 00:21:46,528 --> 00:21:48,780 这很糟糕不是吗? OK? It's horrible isn't it? 394 00:21:52,656 --> 00:21:53,632 过程的CADR部分 --of the procedure. 395 00:21:55,440 --> 00:22:00,864 在随着过程一起传递过来的环境中 Bind that to the arguments that were passed in the environment, 396 00:22:00,896 --> 00:22:04,144 把形参和由环境传递过来的实参绑定起来 which is passed also as part of the procedure. 397 00:22:04,540 --> 00:22:07,904 也就是CDR的CDR的CAR Well, that's the CAR of the CDR of the CDR of this, 398 00:22:09,792 --> 00:22:16,624 也就是过程的CADDR部分 CADDR, of the procedure. 399 00:22:20,290 --> 00:22:24,960 (闭合括号中) Bind, eval, pair, COND, lamda, define-- 400 00:22:26,144 --> 00:22:29,680 当然 如果我非常追求整洁 Now, of course, if I were being really a neat character, 401 00:22:29,872 --> 00:22:31,344 并且又非常谨慎 and I was being very careful, 402 00:22:32,240 --> 00:22:34,128 我会在后面多加一个情况 I would actually put an extra case here 403 00:22:34,384 --> 00:22:35,984 来判断是否出错 for checking for certain errors like, 404 00:22:36,176 --> 00:22:38,416 比如应用在参数上的是一个过程吗? did you try to apply one to an argument? 405 00:22:39,000 --> 00:22:41,696 如果不是 这里就是未定义的过程类型 You get a undefined procedure type. 406 00:22:42,570 --> 00:22:44,096 我在这里也会这么做 So I may as well do that anyway. 407 00:22:45,808 --> 00:22:55,968 像这样 在ELSE子句中返回错误 --else, some sort of error, like that. 408 00:22:57,610 --> 00:23:01,616 当然 在现实中的一些系统中 Now, of course, again, in some sort of more real system, 409 00:23:02,560 --> 00:23:04,224 出于专业设计的考虑 written for professional reasons, 410 00:23:05,320 --> 00:23:08,000 这里可能会根据某种分派 this would be written with a case analysis 411 00:23:08,368 --> 00:23:09,900 来进行“分情况处理” done by some sort of dispatch. 412 00:23:10,750 --> 00:23:12,688 回到这里 我可能还会添加新的条件来检查 Over here, I would probably have other cases 413 00:23:12,704 --> 00:23:14,144 比如 这是编译过的代码吗? like, is this compiled code? 414 00:23:16,220 --> 00:23:16,848 这很重要 It's very important. 415 00:23:16,880 --> 00:23:18,352 这样的话我就可以区分 I might have distinguished the kind of code 416 00:23:18,384 --> 00:23:22,336 过程是直接由解释LAMBDA表达式而来 that's produced by a directly evaluating a lambda in interpretation 417 00:23:22,944 --> 00:23:25,872 还是从另外的编译器中得到的 等等 from code that was produced by somebody's compiler or something like that. 418 00:23:26,112 --> 00:23:27,230 之后再讨论这个话题 And we'll talk about that later. 419 00:23:27,230 --> 00:23:29,616 又或许是 我必须要执行的一段Frotran代码 Or is this a piece Fortran program I have to go off and execute. 420 00:23:30,510 --> 00:23:32,512 这完全是可能的 It's a perfectly possible thing, at this point, to do that. 421 00:23:32,920 --> 00:23:36,416 实际上 我用具体语法写的这个求值器 In fact, in this concrete syntax evaluator I'm writing here, 422 00:23:37,456 --> 00:23:40,864 假定了它是用Lisp来编写的 there's an assumption built in that this is Lisp, 423 00:23:42,304 --> 00:23:43,824 这是因为我用了CAR和CDR because I'm using CARs and CDRs. 424 00:23:43,840 --> 00:23:45,104 用CAR来取运算符 CAR means the operator, 425 00:23:45,280 --> 00:23:46,640 用CDR来取运算对象 and CDR means the operand. 426 00:23:46,750 --> 00:23:49,968 教科书上给出了一个用抽象语法编写的求值器 In the text, there is an abstract syntax evaluator 427 00:23:50,350 --> 00:23:53,152 它使用的都是抽象的名字 which these could be-- these are given abstract names 428 00:23:53,160 --> 00:23:54,096 比如OPERATOR、OPERAND like operator, and operand, 429 00:23:54,144 --> 00:23:55,820 以及类似的名字 and all these other things are like that. 430 00:23:56,160 --> 00:23:56,864 那样的话 And, in that case, 431 00:23:57,024 --> 00:24:00,912 你可以毫无问题地用ALGOL来重新实现 you could reprogram it to be ALGOL with no problem. 432 00:24:03,360 --> 00:24:06,400 写完APPLY之后 Well, here we have added another couple of things 433 00:24:07,200 --> 00:24:08,432 又有一些东西没有定义 that we haven't defined. 434 00:24:10,810 --> 00:24:12,576 我先不操心这两个 I don't think I'll worry about these at all, 435 00:24:13,392 --> 00:24:15,050 我们稍后讨论这个很重要的BIND however, this one will be interesting later. 436 00:24:17,184 --> 00:24:19,760 现在我们来快速过一遍 结束这一部分 Let's just proceed through this and get it done. 437 00:24:20,550 --> 00:24:22,656 只剩下两块黑板了 不能够写太长 There's only two more blackboards so it can't be very long. 438 00:24:27,408 --> 00:24:29,088 我还得悉心裁剪才能刚好写下 It's carefully tailored to exactly fit. 439 00:24:30,070 --> 00:24:30,980 嗯 还剩下点什么? Well, what do we have left? 440 00:24:30,980 --> 00:24:33,200 我们得定义这里的EVLIST We have to define EVLIST, which is over here. 441 00:24:33,730 --> 00:24:35,072 EVLIST只不过是 And EVLIST is nothing more 442 00:24:35,264 --> 00:24:43,088 在运算对象上映射某个函数得到参数 than a map down a bunch of operands producing arguments. 443 00:24:44,304 --> 00:24:45,408 但是我还是要写出来看看 But I'm going to write it out. 444 00:24:45,820 --> 00:24:48,304 我把它写出来的原因有点神秘 And one of the reasons I'm going to write this out is for a mystical reason, 445 00:24:49,888 --> 00:24:52,048 我想让这个求值器简单得 which is I want to make this evaluator so simple 446 00:24:52,064 --> 00:24:53,568 可以求值自身 that it can understand itself. 447 00:24:56,450 --> 00:24:58,096 我真的很在意这一点 I'm going to really worry about that a little bit. 448 00:25:00,230 --> 00:25:01,744 现在我就把它完全写在这里 So let's write it out completely. 449 00:25:02,850 --> 00:25:04,240 我并不关心 See, I don't want to worry about 450 00:25:04,272 --> 00:25:06,080 它能否把过程作为参数传递 whether or not the thing can pass functional arguments. 451 00:25:06,272 --> 00:25:08,064 求值器并不会用到这些参数 The value evaluator is not going to use them. 452 00:25:08,980 --> 00:25:10,784 求值器也不会生成一个是过程的值 The evaluator is not going to produce functional values. 453 00:25:10,880 --> 00:25:12,672 因此 如果另外有个不同的语言 So even if there were a different, alternative language 454 00:25:12,800 --> 00:25:13,968 跟这个又非常相似 that were very close to this, 455 00:25:15,160 --> 00:25:17,792 这个求值器能够求值像Scheme这样的复杂语言 this evaluates a complex language like Scheme 456 00:25:17,808 --> 00:25:23,120 Scheme是能够把过程当做参数传递的 which does allow procedural arguments, procedural values, and procedural data. 457 00:25:24,070 --> 00:25:25,952 但当我在求值ALGOL时 But even if I were evaluating ALGOL, 458 00:25:27,344 --> 00:25:28,960 尽管ALGOL并不支持过程值 which doesn't allow procedural values, 459 00:25:29,472 --> 00:25:30,592 这个求值器也能正常工作 I could use this evaluator. 460 00:25:31,580 --> 00:25:33,920 因为这个解释器 并没有对这个做过什么假定 And this evaluator is not making any assumptions about that. 461 00:25:34,270 --> 00:25:36,032 实际上 就算这个求值器 And, in fact, if this evaluator were to be restricted 462 00:25:36,270 --> 00:25:37,504 被限制不允许那么做 也没有什么关系 to not being able to that, it wouldn't matter 463 00:25:37,520 --> 00:25:40,030 因为它没有使用那些高级功能 because it doesn't use any of those clever things. 464 00:25:40,640 --> 00:25:42,416 这就是我为什么要把它设计得非常简单 So that's why I'm arranging this to be super simple. 465 00:25:44,070 --> 00:25:46,464 这几乎是所有可能的语言求值器的核心 This is sort of the kernel of all possible language evaluators. 466 00:25:47,810 --> 00:25:48,480 回到这个定义上来 How about that? 467 00:25:49,420 --> 00:25:53,568 EVLIST -- 它是什么呢? Evlist-- well, what is it? 468 00:25:53,820 --> 00:25:57,040 这个过程接收两个参数 L和ENV It's the procedure of two arguments, l and an environment, 469 00:25:58,096 --> 00:25:59,088 其中L是个表 where l is a list 470 00:25:59,584 --> 00:26:08,272 这样的话 如果参数表是空表 such that if the list of arguments is the empty list, 471 00:26:10,192 --> 00:26:12,688 那么结果就是空表 then the result is the empty list. 472 00:26:14,032 --> 00:26:19,232 否则的话 我就要组合 Otherwise, I want to cons up 473 00:26:20,752 --> 00:26:26,672 在ENV中求值运算对象表的CAR部分 result of evaluating the CAR of the 474 00:26:28,160 --> 00:26:32,512 在ENV中求值运算对象CAR部分的结果 the CAR of the list of operands in the environment. 475 00:26:33,344 --> 00:26:35,712 我想先求值第一个运算对象 So I want the first operand evaluated, 476 00:26:35,984 --> 00:26:38,400 返回的结果将是一个新表 and I'm going to make a list of the results 477 00:26:38,970 --> 00:26:40,768 是通过把这个和 by CONSing that onto the result 478 00:26:41,088 --> 00:26:45,420 用CDR递归EVLIST的结果组合得到的 of this EVLISTing as a CDR recursion, 479 00:26:46,224 --> 00:26:50,130 在同样的ENV下 L的CDR部分 the CDR of the list relative to the same environment. 480 00:26:53,088 --> 00:26:58,240 (闭合括号中) Evlist, cons, else, COND, lambda, define-- 481 00:26:59,660 --> 00:27:01,840 还有一个过程 OK? And I have one more 482 00:27:01,840 --> 00:27:03,360 我也想写在这里 that I want to put on the blackboard. 483 00:27:03,620 --> 00:27:05,216 它是这整个的关键 It's the essence of this whole thing. 484 00:27:05,648 --> 00:27:08,130 还要深入一个层次 And there's some sort of next layer down. 485 00:27:14,540 --> 00:27:15,440 也就是COND语句 Conditionals-- 486 00:27:15,690 --> 00:27:16,992 在剩下的东西中 conditionals are the only thing left 487 00:27:17,024 --> 00:27:18,170 EVCOND是唯一的重要过程 that are sort of substantial. 488 00:27:18,880 --> 00:27:20,752 解决完这个后 Then below that, we have to worry about 489 00:27:21,072 --> 00:27:22,944 我们再讨论LOOKUP和BIND things like lookup and bind, 490 00:27:23,568 --> 00:27:25,360 稍后再来讨论 and we'll look at that in a second. 491 00:27:25,530 --> 00:27:27,936 在这个层次上 这是非常重要的 But of the substantial stuff at this level of detail, 492 00:27:28,656 --> 00:27:30,624 下一个重要的事就是如何处理COND语句 next important thing is how you deal with conditionals. 493 00:27:31,600 --> 00:27:33,330 那么 我们怎么来处理呢? Well, how do we have a conditional thing? 494 00:27:36,970 --> 00:27:38,560 它是一个过程 It's a procedure 495 00:27:39,488 --> 00:27:45,000 参数是一组子句CLAUSES和环境ENV of clauses and an environment. 496 00:27:47,712 --> 00:27:48,512 它做些什么呢? And what does it do? 497 00:27:49,820 --> 00:27:55,472 如果子句为空 It says, if I've no more clauses, 498 00:28:02,608 --> 00:28:03,968 我得有一个返回值 well, I have to give this a value. 499 00:28:04,704 --> 00:28:05,872 可能是一个错误 It could be that it was an error. 500 00:28:06,540 --> 00:28:08,592 如果遍历完了所有条件 都没有符合的 Supposing it run off the end of a conditional, 501 00:28:09,152 --> 00:28:10,060 那么它可能有任意的行为 it's pretty arbitrary. 502 00:28:10,060 --> 00:28:12,880 这完全取决于程序员要怎么处理 It's up to me as programmer to choose what I want to happen. 503 00:28:13,650 --> 00:28:15,456 现在对我来说最方便的是 It's convenient for me, right now, to write down 504 00:28:15,632 --> 00:28:17,536 让它返回一个空表 this has a value which is the empty list, 505 00:28:18,144 --> 00:28:18,832 这无所谓 doesn't matter. 506 00:28:20,100 --> 00:28:20,880 为了检查出错误 For error checking, 507 00:28:20,896 --> 00:28:22,760 有些人喜欢在这里写点别的 some people might prefer something else. 508 00:28:23,110 --> 00:28:24,816 下面的更有意思 But the interesting things are the following ones. 509 00:28:25,392 --> 00:28:27,248 如果我遇到了ELSE子句 If I've got an else clause-- 510 00:28:31,000 --> 00:28:32,736 请看 我们有一个由子句组成的表 You see, if I have a list of clauses, 511 00:28:33,216 --> 00:28:34,416 其中每个子句也是一个表 then each clause is a list. 512 00:28:35,440 --> 00:28:40,528 因此谓词就应该是CLAUSES的CAAR部分 And so the predicate part is the CAAR of the clauses. 513 00:28:43,560 --> 00:28:45,024 它是 It's the CAR, 514 00:28:45,040 --> 00:28:49,008 CLAUSES表中第一个元素的CAR部分 which is the first part of the first clause in the list of clauses. 515 00:28:51,090 --> 00:28:51,840 如果它是'ELSE的话 If it's an else, 516 00:28:54,320 --> 00:28:56,510 就意味着整个COND表达式的结果 then it means I want my result of the conditional 517 00:28:56,640 --> 00:28:59,152 就是求值匹配表达式的结果 to be the result of evaluating the matching expression. 518 00:29:00,128 --> 00:29:04,320 所以我求值CADAR部分 So I eval the CADAR. 519 00:29:07,008 --> 00:29:09,568 这是第一个子句的 So this is the first clause, 520 00:29:10,128 --> 00:29:11,632 第二个元素 也就是CADAR the second element of it, CADAR-- 521 00:29:12,810 --> 00:29:17,088 也就是CLAUSES的CAR部分的CADR部分 CADR of a CAR-- of the clauses, 522 00:29:21,232 --> 00:29:22,576 求值的环境是ENV with respect to the environment. 523 00:29:26,620 --> 00:29:28,608 下一种可能性更有意思 Now the next possibility is more interesting. 524 00:29:29,630 --> 00:29:30,448 如果它返回FALSE的话 If it's false, 525 00:29:33,056 --> 00:29:35,104 如果谓词表中的第一个谓词 if the first predicate in the predicate list 526 00:29:35,744 --> 00:29:37,680 既不是ELSE子句 又不为FALSE is not an else, and it's not false, 527 00:29:38,320 --> 00:29:39,504 也就是它不是保留字ELSE if it's not the word else, 528 00:29:40,160 --> 00:29:42,000 并且也不是一个值为FALSE的东西 and if it's not a false thing-- 529 00:29:42,032 --> 00:29:43,664 如果为FALSE又要怎么处理呢? Let's write down what it is if it's a false thing. 530 00:29:44,360 --> 00:29:50,080 如果在相应的环境中 If the result of evaluating the first clause -- first predicate, 531 00:29:52,336 --> 00:29:56,768 求值子句中第一个谓词的结果 the clauses-- respect the environment, 532 00:29:58,190 --> 00:30:01,008 如果求值的结果是FALSE的话 if that evaluation yields false, 533 00:30:01,696 --> 00:30:03,824 这就意味着 还得接着判断后面的子句 then it means, I want to look at the next clause. 534 00:30:04,368 --> 00:30:05,744 第一个就扔掉不管了 So I want to discard the first one. 535 00:30:06,250 --> 00:30:08,336 所以就进入下一个EVCOND循环 So we just go around loop, evcond, 536 00:30:09,952 --> 00:30:16,496 在对应的环境中继续判断子句的CDR部分 the CDR of the clauses relative to that environment. 537 00:30:19,952 --> 00:30:25,150 又或者 我遇到了求值为TRUE的子句 And otherwise, I had a true clause, 538 00:30:26,848 --> 00:30:28,960 这样的话 我想在对应的环境中 what I want is to evaluate 539 00:30:31,856 --> 00:30:41,456 求值CLAUSES的CADAR部分 the CADAR of the clauses relative to that environment. 540 00:30:48,208 --> 00:30:49,616 快了 快完成了 Boy, it's almost done. 541 00:30:51,210 --> 00:30:52,800 基本上完整了 It's quite close to done. 542 00:30:53,730 --> 00:30:55,872 把这一部分结束 I think we're going to finish this part off. 543 00:30:56,210 --> 00:30:58,576 再回顾一下这个求值器 So just buzzing through this evaluator, 544 00:30:58,816 --> 00:31:00,704 它基本上就是这样了 but so far you're seeing almost everything. 545 00:31:01,088 --> 00:31:04,040 接着来看一张幻灯片 Let's look at the next transparency here. 546 00:31:06,320 --> 00:31:10,432 这是BIND的定义 And see IS, Here is bind. 547 00:31:11,980 --> 00:31:14,544 BIND用于在环境中添加新的绑定 Bind is for making more table. 548 00:31:15,460 --> 00:31:18,672 我们要在这里 And what we are going to do here is make a-- 549 00:31:19,248 --> 00:31:22,800 为环境结构创建一个新框架 we're going to make a new frame for an environment structure. 550 00:31:22,800 --> 00:31:25,424 环境结构是通过由框架组成的表 The environment structure is going to be represented 551 00:31:25,936 --> 00:31:27,200 来表示的 as a list of frames. 552 00:31:28,080 --> 00:31:30,192 给定一个已有的环境 So given an existing environment structure, 553 00:31:30,320 --> 00:31:32,112 我可以通过把一个新建的框架 I'm going to make a new environment structure 554 00:31:32,256 --> 00:31:33,824 CONS在已有的环境上 by consing a new frame 555 00:31:33,936 --> 00:31:35,696 来获得新的环境 onto the existing environment structure, 556 00:31:36,624 --> 00:31:40,368 正在应用的过程中 那些被绑定变量 where the new frame consists of the result of pairing up the variables, 557 00:31:41,050 --> 00:31:43,790 与传递给过程的参数值结合在一起 which are the bound variables of the procedure I'm applying, 558 00:31:44,128 --> 00:31:48,256 组成了我们所创建的新框架 to the values which are the arguments that were passed that procedure. 559 00:31:49,690 --> 00:31:50,656 BIND其实就是创建表 This is just making a list, 560 00:31:51,648 --> 00:31:54,064 环境就是一组由框架组成的表 adding a new element to our list of frames, 561 00:31:54,300 --> 00:31:55,600 把新的元素加入其中 which is an environment structure, 562 00:31:55,744 --> 00:31:56,896 也就形成了新的环境 to make a new environment. 563 00:31:58,656 --> 00:32:00,656 而PAIR-UP的定义非常简单 Where pair-up is very simple. 564 00:32:01,540 --> 00:32:02,848 PAIR-UP只不过是 Pair-up is nothing more 565 00:32:03,136 --> 00:32:05,568 如果我们有一个变量表和一个值表 than if I have a list of variables and a list of values, 566 00:32:05,936 --> 00:32:08,624 那么 如果它俩的元素个数又相同 well, if I run out of variables and if I run out of values, 567 00:32:08,624 --> 00:32:09,584 就可以让它们一一对应 everything's OK. 568 00:32:09,720 --> 00:32:11,488 否则的话 就是参数传递多了 Otherwise, I've given too many arguments. 569 00:32:12,512 --> 00:32:15,984 如果值的个数比变量的个数多 If I've not run out of variables, but I've run out of values, 570 00:32:16,064 --> 00:32:17,376 那就说明参数传递少了 that I have too few arguments. 571 00:32:18,512 --> 00:32:19,632 通常的情况是 And in the general case, 572 00:32:19,632 --> 00:32:21,488 如果没有出错 又没有完成的话 where I don't have any errors, and I'm not done, 573 00:32:22,060 --> 00:32:25,616 我就添加一个由第一个变量 OK? Then I really am just adding a new pair 574 00:32:25,760 --> 00:32:30,176 和第一个参数组成的新序对 of the first variable with the first argument, 575 00:32:30,944 --> 00:32:32,128 这是第一个值 the first value, 576 00:32:32,760 --> 00:32:36,400 把它们CONS在 onto a list resulting from pairing-up 577 00:32:37,120 --> 00:32:40,640 剩余变量和值组成的表上 the rest of the variables with the rest of the values. 578 00:32:42,950 --> 00:32:44,784 LOOKUP也同样简单 Lookup is of course equally simple. 579 00:32:46,288 --> 00:32:49,632 加入我要在环境中查找一个符号 If I have to look up a symbol in an environment, 580 00:32:49,936 --> 00:32:51,392 那么 如果是空环境 well, if the environment is empty, 581 00:32:51,568 --> 00:32:53,008 那么就说明 该变量尚未绑定 then I've got an unbound variable. 582 00:32:54,650 --> 00:32:55,472 否则 Otherwise, 583 00:32:56,864 --> 00:33:00,368 我就要使用一个特殊的关联表查找过程 what I'm going to do is use a special pair list lookup procedure, 584 00:33:00,384 --> 00:33:01,872 我们不久就会看到它的定义 which we'll have very shortly, 585 00:33:02,240 --> 00:33:05,440 用它在环境的第一个框架中查找该符号 of the symbol in the first frame of the environment. 586 00:33:05,930 --> 00:33:07,216 由于我知道这个环境不是空的 Since I know the environment is not empty, 587 00:33:07,232 --> 00:33:08,400 因此 它至少有一个框架 it must have a first frame. 588 00:33:09,200 --> 00:33:11,140 所以 我就在它第一个框架中查找 So I lookup the symbol in the first frame. 589 00:33:11,568 --> 00:33:13,584 找到的序对会传递给这里的VCELL That becomes the value cell here. 590 00:33:14,380 --> 00:33:17,616 如果VCELL为空 OK? And then, if the value cell is empty, 591 00:33:18,448 --> 00:33:20,576 那就说明当前框架中没有这个符号 if there is no such value cell, 592 00:33:20,704 --> 00:33:22,848 我就需要在环境中剩下的框架中查找 then I have to continue and look at the rest of the frames. 593 00:33:23,720 --> 00:33:25,040 VCELL为空 意味着当前框架没有相应的符号 It means there was nothing found there. 594 00:33:25,990 --> 00:33:28,896 如果没有找到 So that's a property of ASSQ is it returns emptiness 595 00:33:29,520 --> 00:33:30,800 ASSQ就会返回空表 if it doesn't find something. 596 00:33:32,320 --> 00:33:33,856 如果找到了 but if it did find something, 597 00:33:33,856 --> 00:33:36,064 那么我就使用VCELL的CDR部分 then I'm going to use the CDR of the value cell here, 598 00:33:36,464 --> 00:33:40,256 因为VCELL是变量和值组成的序对 which is the thing that was the pair consisting of the variable and the value. 599 00:33:41,050 --> 00:33:43,936 因此可以用CDR取得对应的值 So the CDR of it is the value part. OK? 600 00:33:45,000 --> 00:33:47,824 ASSQ这个过程你们之前见过 Finally, ASSQ is something you've probably seen already. 601 00:33:47,970 --> 00:33:50,832 ASSQ的参数是一个符号和一个由序对组成的表 ASSQ takes a symbol and a list of pairs, 602 00:33:51,424 --> 00:33:53,408 如果表为空 它就返回空表 and if the list is empty, it's empty. 603 00:33:53,520 --> 00:33:56,304 如果这个符号是ALIST的第一个元素 If the symbol is the first thing in the list-- 604 00:33:58,064 --> 00:33:58,912 这里写错了 That's an error. 605 00:33:59,820 --> 00:34:02,176 应该是CAAR That should be CAAR, C-A-A-R. 606 00:34:03,168 --> 00:34:04,160 大家注意一下 Everybody note that. 607 00:34:07,632 --> 00:34:09,376 就是这里 看到了吗? Right there, OK? 608 00:34:13,424 --> 00:34:14,416 总之 And in any case, 609 00:34:14,560 --> 00:34:16,816 如果符号等于表的CAAR f the symbol is the CAAR of the A list, 610 00:34:17,160 --> 00:34:20,976 那么我就返回ALIST中第一个序对 then I want the first, the first pair, in the alist. 611 00:34:22,080 --> 00:34:25,504 换句话说 这个键匹配了正确的条目 So, in other words, if this is the key matching the right entry, 612 00:34:26,240 --> 00:34:26,976 否则的话 otherwise, 613 00:34:27,088 --> 00:34:28,944 我就需要在剩下的表中继续查找 I want to look up that symbol in the rest. 614 00:34:30,080 --> 00:34:33,312 这里有个笔误 很抱歉 Sorry for producing a bug, bugs appear. 615 00:34:35,190 --> 00:34:36,288 好了 不管如何 Well, in any case, 616 00:34:37,056 --> 00:34:39,488 你们基本上已经看到了全貌 you're pretty much seeing the whole thing now. 617 00:34:41,880 --> 00:34:43,296 虽然我们的代码风格非常丑陋 It's a very beautiful thing, 618 00:34:44,192 --> 00:34:46,000 但是作为所有语言的核心 even though it's written in an ugly style, 619 00:34:46,768 --> 00:34:48,304 它却是非常美妙 being the kernel of every language. 620 00:34:49,600 --> 00:34:51,376 我提议 让我们再欣赏一会儿 I suggest that we just-- let's look at it for a while. 621 00:35:00,320 --> 00:35:47,024 [音乐] [ALSO SPRACH ZARATHUSTRA] 622 00:35:49,750 --> 00:35:50,912 大家有什么问题吗? Are there any questions? 623 00:36:01,180 --> 00:36:03,296 没有的话就休息一会儿吧 Alright, I suppose it's time to take a small break then. 624 00:36:04,040 --> 00:36:10,736 [音乐] [JESU, JOY OF MAN'S DESIRING] 625 00:36:13,880 --> 00:36:17,648 《计算机程序的构造和解释》 626 00:36:40,800 --> 00:36:43,936 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 627 00:36:43,950 --> 00:36:47,984 《计算机程序的构造和解释》 628 00:36:48,060 --> 00:36:51,936 元循环求值器 I 629 00:36:56,780 --> 00:36:58,992 现在 我们将用一个实例 OK, now we're just going to do a little bit of practice 630 00:36:59,296 --> 00:37:02,672 来理解一下求值器的运作过程 understanding what it is we've just shown you. OK? 631 00:37:03,470 --> 00:37:05,488 我们通过手工进行代换 What we're going to do is go through, in detail, 632 00:37:05,504 --> 00:37:10,368 来深入解释器的详细工作原理 an evaluation by informally substituting through the interpreter. 633 00:37:11,500 --> 00:37:14,944 由于我们的求值器不支持赋值和定义 And since we have no assignments or definitions in this interpreter, 634 00:37:15,200 --> 00:37:17,344 我们也就不用担心副作用 we have no possible side effects, 635 00:37:17,984 --> 00:37:22,032 因此我们可以放心大胆地进行代换 and so the we can do substitution with impunity 636 00:37:22,528 --> 00:37:24,592 不用担心任何副作用 and not worry about results. 637 00:37:25,330 --> 00:37:27,808 我们将要尝试去手工代换 So the particular problem I'd like to look at 638 00:37:28,064 --> 00:37:29,632 这个复杂的表达式 is it an interesting one. 639 00:37:30,690 --> 00:37:34,096 (EVAL It's the evaluation of 640 00:37:34,910 --> 00:37:48,080 '(((LAMBDA (X) (LAMBDA (Y) (+ X Y))) quote, open, open, open, lambda of x, lambda of y plus x y, 641 00:37:50,300 --> 00:37:52,624 (闭合括号中) lambda, lambda, 642 00:37:53,040 --> 00:37:56,128 要把它应用在3和4上 applied to three, applied to four, 643 00:37:56,944 --> 00:37:59,580 求值过程是发生在全局环境E0中的 in some global environment which I'll call e0. 644 00:38:04,930 --> 00:38:05,968 这里的这个表达式 So what we have here 645 00:38:06,368 --> 00:38:08,048 是个参数为X的一元过程 is a procedure of one argument x, 646 00:38:08,090 --> 00:38:11,056 返回一个参数为Y的一元过程 which produces as its value a procedure of one argument y, 647 00:38:11,072 --> 00:38:12,128 后者计算X+Y which adds x to y. 648 00:38:14,300 --> 00:38:17,960 外层的这个过程应用于数字3 We are applying the procedure of one argument x to three. 649 00:38:17,960 --> 00:38:19,392 所以X应该是3 So x should become three. 650 00:38:21,400 --> 00:38:23,984 返回的结果是一个参数为Y的一元过程 And the result of that should be procedure of one argument y, 651 00:38:24,336 --> 00:38:25,824 该过程将应用于数字4 which will then apply to 4. 652 00:38:28,910 --> 00:38:30,320 然后要做的也很简单 And there is a very simple case, 653 00:38:31,040 --> 00:38:32,736 计算X+Y即可 they will then add those results. 654 00:38:34,790 --> 00:38:35,824 具体做之前 And now in order to do that, 655 00:38:35,840 --> 00:38:37,760 先来构造一个非常简单的环境模型 I want to make a very simple environment model. 656 00:38:37,904 --> 00:38:40,480 到了现在 我相信你们已经想到 And at this point, you should already have in your mind 657 00:38:40,992 --> 00:38:42,592 这个过程产生的环境了 the environments that this produces. 658 00:38:44,460 --> 00:38:46,624 我们从全局环境开始 But we're going to start out with a global environment, 659 00:38:48,592 --> 00:38:50,064 我们把它记作E0 which I'll call e0, 660 00:38:54,608 --> 00:38:55,472 就像这样 which is that. 661 00:38:56,740 --> 00:39:02,464 里面应该有过程+、*的定义 And it's going to have in it things, definitions for plus, and times, 662 00:39:06,304 --> 00:39:10,368 这里 我们用希腊字母来表示过程对象 这样有趣点 and-- using Greek letters, isn't that interesting, for the objects-- 663 00:39:11,216 --> 00:39:27,936 -、/、CAR、CDR、CONS以及EQ? and minus, and quotient, and CAR, and CDR, and CONS, and EQ, 664 00:39:28,592 --> 00:39:31,056 其它需要的基本过程都在全局环境中 and everything else you might imagine in a global environment. 665 00:39:31,270 --> 00:39:33,824 每个符号都对应着一个过程对象 It's got something there for each of those things, 666 00:39:34,620 --> 00:39:36,096 这些都是解释器自带的 something the machine is born with, 667 00:39:37,104 --> 00:39:38,090 这就是E0 that's e0. 668 00:39:39,220 --> 00:39:41,840 现在 这个求值要怎样进行呢? Now what does it mean to do this evaluation? 669 00:39:42,940 --> 00:39:45,184 我们来看看这些特殊形式 Well, we go through the set of special forms. 670 00:39:45,696 --> 00:39:47,056 首先 这不是数字 First of all, this is not a number. 671 00:39:48,670 --> 00:39:50,380 也不是符号 This is not a symbol. 672 00:39:53,136 --> 00:39:55,600 这不是一个引用表达式 Gee, it's not a quoted expression. 673 00:39:56,608 --> 00:39:58,384 虽然外层是一个引用表达式 This is a quoted expression, 674 00:39:59,470 --> 00:40:00,800 但并不是我想要去求值的那个 but that's not what I mentioned. 675 00:40:00,832 --> 00:40:01,360 我想问的是 The question is, 676 00:40:01,392 --> 00:40:04,960 被引用的这个表达式 是否也是个引用表达式? whether or not the thing which is quoted is quoted expression? 677 00:40:05,890 --> 00:40:07,960 我是在求值一个表达式 I'm evaluating an expression. 678 00:40:07,960 --> 00:40:09,984 这个引号是为了引用这个特定表达式 This just says it's this particular expression. 679 00:40:11,410 --> 00:40:12,660 而被引用的并非引用表达式 This is not a quoted expression. 680 00:40:13,712 --> 00:40:17,216 当然 它也不是以LAMBDA开头 OK? It's not a thing that begins with lambda. 681 00:40:19,120 --> 00:40:20,672 也不以COND开头 It's not a thing that begins with COND. 682 00:40:22,030 --> 00:40:25,952 因此它是过程的应用 Therefore, it's an application of its of an operated operands. 683 00:40:26,310 --> 00:40:27,120 这是一个组合式 It's a combination. 684 00:40:28,570 --> 00:40:30,704 既然它是组合式 The combination thus has 685 00:40:30,890 --> 00:40:34,000 这就是它的运算符 this as the operator 686 00:40:34,640 --> 00:40:36,080 而这是它的运算对象 and this is the operands. 687 00:40:40,130 --> 00:40:42,416 这就意味着 我要 Well, that means that what I'm going to do is 688 00:40:42,570 --> 00:40:47,904 把它转换成 transform this into apply of eval, 689 00:40:50,128 --> 00:40:57,616 (APPLY (EVAL '((LAMBDA (X) (LAMBDA (y) of quote, open, open lambda of x, lambda of y-- 690 00:40:57,880 --> 00:40:59,120 也就是在E0环境中 I'm evaluating the operator-- 691 00:40:59,952 --> 00:41:04,192 求值(+ X Y) plus x y, in the environment, 692 00:41:07,264 --> 00:41:08,640 不要漏了 also e0, 693 00:41:12,784 --> 00:41:15,200 要应用到的运算对象则是 with the operands that I'm going to apply this to, 694 00:41:15,260 --> 00:41:17,280 用EVLIST求值参数的结果 the arguments being the result of EVLIST, 695 00:41:21,216 --> 00:41:24,496 也就是'(4) the list containing four, fin e0. 696 00:41:29,010 --> 00:41:31,264 我用这个特殊的记号来表示 I'm using this funny notation here for e0 697 00:41:32,320 --> 00:41:34,832 这是为了指代那个环境 because this should be that environment. 698 00:41:35,450 --> 00:41:37,770 我无法为它命名 I haven't a name for it, 699 00:41:37,808 --> 00:41:39,152 因为我没有环境来存放的名字 because I have no environment to name it in. 700 00:41:41,960 --> 00:41:44,090 你当然可以把看作是 So this is just a representation 701 00:41:44,176 --> 00:41:46,176 某种引用表达式 what would be a quoted expression, if you will. 702 00:41:47,730 --> 00:41:51,168 在那里 它表示环境这种数据结构 The data structure, which is the environment, goes there. 703 00:41:53,040 --> 00:41:55,040 好的 这是变换后的结果 Well, that's what we're seeing here. 704 00:41:55,850 --> 00:41:56,672 为了执行这个表达式 Well in order to do this, 705 00:41:56,688 --> 00:41:58,048 我还得求值这两个表达式 I have to do this, and I have to do that. 706 00:41:59,610 --> 00:42:00,496 EVLIST简单点 Well this one's easy, 707 00:42:00,576 --> 00:42:03,184 我们先计算这个吧 so why don't we do that one first. OK? 708 00:42:03,770 --> 00:42:07,440 这就被归约为 This turns into apply of eval-- 709 00:42:07,456 --> 00:42:08,832 上面的某些部分直接抄过来就好 just copying something now. 710 00:42:09,424 --> 00:42:11,000 代换的过程中少不了照抄 Most of the substitution rule is copying. 711 00:42:18,530 --> 00:42:21,248 抄写的时候我就不多加解释了 So I'm going to not say the words when I copy, 712 00:42:21,712 --> 00:42:23,872 这样能快一点儿 because it's faster. 713 00:42:26,410 --> 00:42:28,640 EVLIST的部分就代换成为 And then the EVLIST is going to turn into a 714 00:42:28,656 --> 00:42:36,720 (CONS (EVAL '4 ) cons, of eval, of four, in e0-- 715 00:42:38,784 --> 00:42:40,176 因为它不是空表 because it was not an empty list-- 716 00:42:41,440 --> 00:42:49,392 (EVLIST '() )) onto the result of EVLISTing, on the empty list, in e0. 717 00:42:52,580 --> 00:42:54,208 我要省略一些步骤了 And I'm going to start leaving out steps soon, 718 00:42:54,240 --> 00:42:55,360 因为太详细就有些无聊了 because it's going to get boring. 719 00:42:59,870 --> 00:43:05,424 下一步跟上面基本上一样 But this is basically the same thing as apply, of eval-- 720 00:43:07,504 --> 00:43:08,544 继续照抄 I'm going to keep doing this-- 721 00:43:10,688 --> 00:43:20,240 (((LAMBDA (X) (LAMBDA (Y) (+ X Y)) 3) 4) ) the lambda of x, the lambda of y, plus xy, 3, close, e0. 722 00:43:20,240 --> 00:43:21,200 看来我还宝刀未老嘛 I'm a pretty good machine. 723 00:43:24,240 --> 00:43:26,240 下面对4求值 Well, eval of four, 724 00:43:26,560 --> 00:43:28,440 4是一个数字 that's meets the question, is it a number. 725 00:43:29,008 --> 00:43:33,904 结果就应该是(CONS 4 So that's cons, right, cons of 4. 726 00:43:34,032 --> 00:43:37,472 EVLIST对空表求值 结果也是空表 And EVLIST of the empty list is the empty list, 727 00:43:38,336 --> 00:43:39,240 也就是这个 so that's this. 728 00:43:42,620 --> 00:43:45,088 这个非常容易理解 OK. And that's very simple to understand, 729 00:43:45,104 --> 00:43:47,440 就是一个只含有4的表 because that means the list containing four itself. 730 00:43:48,710 --> 00:43:53,840 继续代换为 (APPLY (EVAL So this is nothing more than apply of eval, 731 00:43:55,280 --> 00:44:02,512 '((LAMBDA (X) (LAMBDA (Y) (+ X Y)) quote, open, open, lambda of x, lambda of y, plus x y, 732 00:44:03,400 --> 00:44:07,488 3) 4) ) three applied to, e0, applied to the list four-- 733 00:44:08,688 --> 00:44:12,608 应用在'(4)上 这样就完成了 applied to the list four-- bang 734 00:44:13,940 --> 00:44:15,056 这是这一步的结果 So that's that step. 735 00:44:17,008 --> 00:44:19,968 现在让我们进行下一步 更有意思的一步 Now let's look at the next, more interesting thing. 736 00:44:20,360 --> 00:44:21,728 这行代码要如何求值? What do I do to evaluate that? 737 00:44:23,070 --> 00:44:24,448 为了求值这一部分 Evaluating this means 738 00:44:25,200 --> 00:44:28,656 我得先求值-- 首先 它不是-- means I have to evaluate-- Well, it's not. 739 00:44:29,460 --> 00:44:31,040 这是一个应用 It's nothing but an application. 740 00:44:31,680 --> 00:44:33,104 它并不是特殊形式 It's not one of the special things. 741 00:44:33,570 --> 00:44:36,512 如果应用中的运算符 If the application of this operator, 742 00:44:36,510 --> 00:44:37,376 就是这里 which we see here-- 743 00:44:37,664 --> 00:44:38,944 这就是运算符 here's the operator-- 744 00:44:40,190 --> 00:44:41,770 应用在这个运算对象上 applied to this operands, 745 00:44:44,544 --> 00:44:45,744 形成了一个组合式 that combination. 746 00:44:46,720 --> 00:44:48,256 现在我们要如何来求值呢? But we know how to do that, 747 00:44:48,848 --> 00:44:52,370 它是COND语句中的最后一种情况 because that's the last case of the conditional. 748 00:44:52,370 --> 00:44:55,520 在这步求值中 进行的代换是 So substituting in for this evaluation, 749 00:44:55,710 --> 00:44:57,472 把运算符的求值结果 it's apply of eval of the operator 750 00:44:57,504 --> 00:44:59,000 应用在EVLIST的运算对象上 in the EVLIST of the operands. 751 00:45:01,160 --> 00:45:08,208 这也就是 (APPLY (APPLY (EVAL Well, it's apply, of apply, of eval, 752 00:45:10,576 --> 00:45:21,072 '(LAMBDA (X) (LAMBDA (Y) (+ X Y))) of quote, open, lambda of x, lambda of y, plus x y, 753 00:45:21,800 --> 00:45:23,450 (闭合括号中) lambda, lambda, 754 00:45:23,744 --> 00:45:25,424 ) in environment e0. 755 00:45:30,520 --> 00:45:32,672 我就直接给出运算对象的求值结果了 I'm going to short circuit the evaluation of the operands, 756 00:45:32,688 --> 00:45:34,144 具体过程跟之前是一样的 because they're the same as they were before. 757 00:45:35,230 --> 00:45:36,480 我有一个表'(3) I got a list containing three, 758 00:45:36,512 --> 00:45:39,160 把它应用于'(4) apply that, and apply that to four. 759 00:45:42,448 --> 00:45:43,568 我们接着看 Well let's see. 760 00:45:44,410 --> 00:45:46,384 对一个LAMBDA表达式求值 Eval of a lambda expression 761 00:45:48,016 --> 00:45:49,450 会产生一个过程对象 produces a procedure object. 762 00:45:52,030 --> 00:45:57,888 继续变换就是 (APPLY (APPLY So this is apply, of apply, 763 00:46:00,304 --> 00:46:02,272 然后是一个过程对象 '(CLOSURE of the procedure object closure, 764 00:46:04,520 --> 00:46:08,688 它里面包含了过程的体 which contains the body of the procedure, x, 765 00:46:08,944 --> 00:46:11,920 它绑定了变量X which is lambda, which binds x [UNINTELLIGIBLE] 766 00:46:12,130 --> 00:46:15,408 然后是函数体内部 the internals of the body, 767 00:46:15,808 --> 00:46:18,176 它返回一个参数为Y的单参过程 it returns the procedure of one argument y, 768 00:46:18,560 --> 00:46:20,630 这个过程计算X+Y which adds x to y. 769 00:46:23,210 --> 00:46:25,504 这个过程对象捕获了环境 Environment e0 is now captured in it, 770 00:46:27,248 --> 00:46:29,632 因为这些求值都是在中发生的 because this was evaluated with respect to e0. 771 00:46:30,112 --> 00:46:32,432 现在 也是CLOSURE对象的一部分 e0 is part now of the closure object. 772 00:46:33,040 --> 00:46:38,192 先应用于'(3) Apply that to open, three, close, apply, 773 00:46:38,816 --> 00:46:41,300 再应用于'(4) to open, 4, close, apply. 774 00:46:47,390 --> 00:46:49,296 在这步到这步的过程中 So going from this step to this step 775 00:46:49,312 --> 00:46:50,896 我构建了一个过程对象 meant that I made up a procedure object 776 00:46:50,910 --> 00:46:52,032 它捕获了 which captured in it 777 00:46:53,888 --> 00:46:55,980 并将其作为本身的一部分 e0 as part of the procedure object. 778 00:46:57,150 --> 00:46:58,512 现在 要把它们传递给APPLY了 Now, we're going to pass those to apply. 779 00:46:58,520 --> 00:46:59,712 我们得把这个过程 We have to apply this procedure 780 00:47:00,480 --> 00:47:01,580 应用在对应的参数上 to that set of arguments. 781 00:47:02,710 --> 00:47:06,512 这里的过程并不是基本过程 Well, but that procedure is not primitive. 782 00:47:07,380 --> 00:47:09,888 它有一个类型标志'CLOSURE It's, in fact, a thing which has got the tag closure, 783 00:47:10,240 --> 00:47:12,096 因此还需要进行参数绑定 and, therefore, what we have to do is do a bind. 784 00:47:13,710 --> 00:47:14,720 必须要绑定 We have to bind. 785 00:47:15,830 --> 00:47:19,408 在这里构造的新环境 A new environment is made at this point, 786 00:47:20,448 --> 00:47:22,800 它有一个父环境 which has as its parent environment 787 00:47:22,944 --> 00:47:27,568 父环境是这里的 the one over here, e0, that environment. 788 00:47:30,320 --> 00:47:31,570 我们把新环境记作 And we'll call this one, e1. 789 00:47:34,620 --> 00:47:35,744 这里要绑定些什么呢? Now what's bound in there? 790 00:47:36,040 --> 00:47:37,488 变量X绑定为值3 x is bound to three. 791 00:47:38,620 --> 00:47:40,448 这里写X=3 So I have x equal three. 792 00:47:41,480 --> 00:47:42,336 就是这些 That's what's in there. 793 00:47:44,940 --> 00:47:46,240 新环境记作E1 And we'll call that e1. 794 00:47:46,240 --> 00:47:48,448 而这个表达式会变换为 So what this transforms into 795 00:47:49,130 --> 00:47:50,720 对一个过程体的求值 is an eval of the body 796 00:47:51,728 --> 00:47:53,070 就是这个 在这里 of this, which is this, 797 00:47:54,400 --> 00:47:55,728 这个过程的体 the body of that procedure, 798 00:47:56,448 --> 00:47:58,528 在刚才创建的中进行求值 in the environment that you just saw. 799 00:48:00,290 --> 00:48:05,056 也就是 (APPLY (EVAL So that's an apply, of eval, 800 00:48:06,920 --> 00:48:16,432 '(LAMBDA (Y) (+ X Y)) ) quote, open, lambda of y, plus x y-- the body-- in e1. 801 00:48:20,496 --> 00:48:22,480 把求值的结果应用于4 And apply the result of that to four, 802 00:48:23,680 --> 00:48:26,736 也就是'(4) open, close, 4-- list of arguments. 803 00:48:28,432 --> 00:48:29,872 到了这里就很清晰了 Well, that's sensible enough 804 00:48:30,080 --> 00:48:32,272 我知道该如何求值LAMBDA表达式 because evaluating a lambda, I know what to do. 805 00:48:33,110 --> 00:48:34,176 也就是(APPLY That means I apply, 806 00:48:37,168 --> 00:48:38,928 一个过程对象'(CLOSURE the procedure which is closure, 807 00:48:43,744 --> 00:48:46,848 它绑定参数Y 计算X+Y binds one argument y, adds x to y, 808 00:48:49,280 --> 00:48:52,150 并且捕获了环境 with e1 captured in it. 809 00:48:55,790 --> 00:48:57,424 你应该已经见过了 对吧? And you should really see this. Right? 810 00:48:57,800 --> 00:49:00,140 我构造了一个CLOSURE对象 I somehow manufactured a closure. 811 00:49:00,140 --> 00:49:01,168 放在这里 I should've put this here. 812 00:49:01,790 --> 00:49:03,040 之前的那个也是 There was one over here too. 813 00:49:05,904 --> 00:49:07,472 这是现在的这个 OK? Well, there's one here now. 814 00:49:08,080 --> 00:49:09,808 它捕获了环境 I've captured e1, 815 00:49:10,416 --> 00:49:14,256 而这个是参数为Y的一元过程 and this is the procedure of one argument y, 816 00:49:15,456 --> 00:49:16,704 先不管它具体是什么 whatever this is. 817 00:49:18,096 --> 00:49:20,720 我们只知道它是一个CLOSURE That's what that is there, that closure. 818 00:49:22,576 --> 00:49:26,464 将这个过程应用于'(4) OK? I'm going to apply that to four. 819 00:49:30,288 --> 00:49:31,776 很简单 OK. Well, that's easy enough. 820 00:49:36,830 --> 00:49:38,736 我需要通过复制一个指针 That means I have to make a new environment 821 00:49:38,864 --> 00:49:40,528 就是这个过程的指针 by copying this pointer, 822 00:49:41,568 --> 00:49:43,216 来构造一个新环境 which was the pointer of the procedure, 823 00:49:44,944 --> 00:49:48,960 同时还得把参数Y跟值4绑定 which binds y equal 4 with that environment. 824 00:49:49,824 --> 00:49:52,224 我把这个新环境 记作 And here's my new environment, which I'll call e2. 825 00:49:56,030 --> 00:49:58,120 当然 这里的这个应用 And, of course, this application then 826 00:49:58,224 --> 00:50:00,336 其过程体的求值 是在中进行的 is evaluate the body in e2. 827 00:50:01,584 --> 00:50:07,872 所以这就变成了对过程体的求值 So this is eval, the body, 828 00:50:07,900 --> 00:50:11,856 也就是 (EVAL '(+ X Y) ) which is plus x y, in the environment e2. 829 00:50:13,710 --> 00:50:14,944 但由于这是一个应用 But this is an application, 830 00:50:15,480 --> 00:50:23,888 所以又代换为 (APPLY (EVAL '+ ) so this is the apply, of eval, plus in e2, 831 00:50:26,336 --> 00:50:37,340 (EVLIST '(X Y) )) an EVLIST, quote, open, x y, in e2. 832 00:50:44,880 --> 00:50:45,590 我们来看 Well, but let's see. 833 00:50:45,590 --> 00:50:51,712 下一步代换为 (APPLY That is apply, the object 834 00:50:52,080 --> 00:50:53,872 求值‘+得到的结果 which is a result of that and plus. 835 00:50:54,190 --> 00:50:55,664 所以我们从开始找 So here we are in e2, 836 00:50:55,696 --> 00:50:57,728 '+既不在 也不在 plus is not here, it's not here, 837 00:50:57,744 --> 00:51:01,056 ‘+是中的基本运算符 yes, but's here as some primitive operator. 838 00:51:01,780 --> 00:51:04,745 这个基本运算符是用于加法的 So it's the primitive operator for addition. 839 00:51:07,472 --> 00:51:14,128 把它应用于 在中求值X和Y的结果 Apply that to the result of evaluating x and y in e2. 840 00:51:14,370 --> 00:51:17,008 我们知道X是3 Y是4 But we can see that x is three and y is four. 841 00:51:18,112 --> 00:51:23,312 所以这里是'(3 4) So that's a three and four, here. 842 00:51:24,160 --> 00:51:26,280 然后就神奇地得到结果7 And that magically produces for me a seven. 843 00:51:30,520 --> 00:51:32,448 我再来整理一下这个过程 这样你们 I wanted to go through this so you would see, 844 00:51:32,704 --> 00:51:34,736 就能了解这其中的重要本质 essentially, one important ingredient, 845 00:51:35,760 --> 00:51:37,296 这个过程中传递了些什么? which is what's being passed around, 846 00:51:37,312 --> 00:51:39,568 每个模块持有什么 又负责什么? and who owns what, and what his job is. 847 00:51:40,470 --> 00:51:41,616 有哪些模块呢? So what do we have here? 848 00:51:41,700 --> 00:51:42,624 一个是EVAL We have eval, 849 00:51:44,800 --> 00:51:45,640 还有个APPLY We have eval, and we have apply, 850 00:51:45,664 --> 00:51:46,624 两个主要角色 the two main players. 851 00:51:49,370 --> 00:51:51,568 它们之间有个像这样的大循环 And there is a big loop the goes around like this. 852 00:51:52,320 --> 00:52:04,576 其中 EVAL为APPLY生成过程和参数 Which is eval produces a procedure and arguments for apply. 853 00:52:06,270 --> 00:52:08,576 也有些事情 EVAL也可以自己做 Now some things eval could do by itself. 854 00:52:09,504 --> 00:52:10,860 都是一些细小的事情 Those are little self things here. 855 00:52:10,860 --> 00:52:11,744 并不十分有趣 They're not interesting. 856 00:52:12,700 --> 00:52:15,600 同时 EVAL也逐个求值所有的参数 Also eval evaluates all of the arguments, one after another. 857 00:52:16,240 --> 00:52:17,280 也没什么意思 That's not very interesting. 858 00:52:17,650 --> 00:52:20,096 APPLY可以应用像+这类的过程 Apply can apply some procedures like plus, 859 00:52:21,024 --> 00:52:22,040 这很普通 not very interesting. 860 00:52:22,300 --> 00:52:24,640 然而 如果APPLY不能应用像+这样的过程 However, if apply can't apply a procedure like plus, 861 00:52:25,312 --> 00:52:33,312 它就为EVAL生成一个表达式及相应的环境 it produces an expression and environment for eval. 862 00:52:35,470 --> 00:52:37,616 过程的参数封装了 The procedural arguments wrap up 863 00:52:38,240 --> 00:52:40,608 计算所必需的状态 essentially the state of a computation 864 00:52:41,664 --> 00:52:43,424 以及相应的环境 and, certainly, the expression of environment. 865 00:52:43,740 --> 00:52:45,312 但我们接下来要做的 And so what we're actually going to do next 866 00:52:45,328 --> 00:52:46,464 并不是完整的状态 is not the complete state, 867 00:52:46,480 --> 00:52:48,820 因为它没有说明谁需要返回的结果 because it doesn't say who wants the answers. 868 00:52:51,280 --> 00:52:52,208 我们要做的就是 But what we're going to do-- 869 00:52:52,240 --> 00:52:54,800 总是把某个表达式以及相应的环境 it's always got something like an expression of environment 870 00:52:54,992 --> 00:52:56,144 或者过程对象以及其参数 or procedure and arguments 871 00:52:56,288 --> 00:52:58,080 在这个循环之间不断传递 as the main loop that we're going around. 872 00:52:58,970 --> 00:53:01,808 这里还有一些小型的子循环 比如EVLIST There are minor little sub loops like eval through EVLIST, 873 00:53:04,496 --> 00:53:06,768 又或者是EVAL中的EVCOND循环 or eval through evcond, 874 00:53:09,104 --> 00:53:11,968 甚至于APPLY调用PRIMITIVE-APPLY or apply through a primitive apply. 875 00:53:16,140 --> 00:53:17,648 但是它们并不是最主要的 But they're not the essential things. 876 00:53:18,864 --> 00:53:20,288 这整个就是我想让你们看到的 So that's what I wanted you to see. 877 00:53:21,860 --> 00:53:22,880 有什么问题吗? Are there any questions? 878 00:53:25,930 --> 00:53:27,376 David 请说 Yes. David 879 00:53:27,740 --> 00:53:33,310 学生:我不明白为什么X是3 AUDIENCE: I'm trying to understand how x got down to three 880 00:53:34,016 --> 00:53:36,304 而不是4 instead of four. 881 00:53:37,070 --> 00:53:38,520 在那个部分 At the early part of the-- 882 00:53:38,560 --> 00:53:40,544 教授:是在这里 PROFESSOR: Here. 883 00:53:41,310 --> 00:53:43,310 你想知道X是如何跟3绑定的 You want to know how x got down to three? 884 00:53:43,520 --> 00:53:47,424 学生:因为X是外层过程的参数 AUDIENCE: Because x is the outer procedure, 885 00:53:48,464 --> 00:53:50,992 而内层过程中既有X又有Y and x and y are the inner procedure. 886 00:53:51,264 --> 00:53:51,888 教授:明白了 PROFESSOR: Fine. 887 00:53:52,848 --> 00:53:54,624 代换的过程中 我已经非常小心了 Well, I was very careful and mechanical. 888 00:53:55,020 --> 00:53:56,928 或许首先 我应该把这些过程 First of all, I should write those procedures 889 00:53:56,944 --> 00:53:58,410 重新编排得更易读一点 again for you, pretty printed. 890 00:54:00,610 --> 00:54:01,472 你之所以有所疑惑 First order of business, 891 00:54:01,488 --> 00:54:02,990 或许是因为你把程序看岔了 because you're probably not reading them well. 892 00:54:03,830 --> 00:54:04,704 所以这里应该是 So I have here 893 00:54:05,150 --> 00:54:09,600 一个以X为参数的过程 that procedure of-- was it x over there-- 894 00:54:11,216 --> 00:54:14,990 它返回一个以Y为参数的过程 which is -- value of that procedure of y 895 00:54:15,728 --> 00:54:18,440 后者计算X+Y which adds x to y, 896 00:54:19,824 --> 00:54:21,104 (闭合括号中) lambda, lambda, 897 00:54:21,408 --> 00:54:22,896 外面的过程应用到3上 applied that to three, 898 00:54:24,080 --> 00:54:26,128 把得到的结果应用到4上 takes the result of that, and applied that to four. 899 00:54:26,140 --> 00:54:28,810 这个和之前那个是一样的 对吧? Is that not what I wrote? OK? 900 00:54:28,810 --> 00:54:32,336 现在 你可以立马发现 Now, you should immediately see that 901 00:54:33,776 --> 00:54:34,944 这里是一个应用 here is an application-- 902 00:54:35,168 --> 00:54:36,464 我先换根白粉笔 let me get a white piece of chalk-- 903 00:54:37,328 --> 00:54:41,120 这一部分是应用 是一个组合式 here is an application, a combination. 904 00:54:43,440 --> 00:54:46,400 这部分是组合式的运算符 OK? That combination has this as the operator 905 00:54:48,144 --> 00:54:49,552 而这是运算对象 and this as the operand. 906 00:54:51,040 --> 00:54:53,056 这个3会跟这里的X绑定 The three is going in for the x here. 907 00:54:54,900 --> 00:54:56,368 而这个组合式的结果 The result of this 908 00:54:56,560 --> 00:54:58,464 是一个参数为Y的一元过程 is a procedure of one argument y, 909 00:54:58,736 --> 00:54:59,792 它将应用于4 which gets applied to four. 910 00:55:00,880 --> 00:55:01,584 明白了吧? OK? 911 00:55:02,208 --> 00:55:04,080 所以你可能只是看岔了 So you just weren't reading the expression right. 912 00:55:04,400 --> 00:55:07,856 而你们在这里看到的 The way you see that over here. OK. 913 00:55:09,424 --> 00:55:12,960 是一个实际的过程对象 它有一个参数X is that here I have the actual procedure object, x. 914 00:55:13,340 --> 00:55:15,312 这个CLOSURE将应用于3 It's getting applied to three, 915 00:55:15,952 --> 00:55:17,072 也就是'(3) the list containing three. 916 00:55:18,980 --> 00:55:21,344 得到的结果再应用于'(4) What I'm left over with is something which gets applied to four. 917 00:55:24,080 --> 00:55:25,200 还有疑问吗? Are there any other questions? 918 00:55:28,350 --> 00:55:30,384 那就休息一下吧 Time for our next small break then. 919 00:55:30,832 --> 00:55:31,370 谢谢大家 Thank you. 920 00:55:33,730 --> 00:55:41,408 [音乐] [JESU, JOY OF MAN'S DESIRING] 921 00:55:42,128 --> 00:55:47,440 《计算机程序的构造和解释》 922 00:55:50,700 --> 00:55:54,080 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 923 00:55:54,120 --> 00:55:59,168 《计算机程序的构造和解释》 924 00:55:59,232 --> 00:56:03,952 元循环求值器 I 925 00:56:08,410 --> 00:56:11,296 教授:课上到这里 PROFESSOR: Let's see, at this point, 926 00:56:13,328 --> 00:56:14,592 你们可能开始觉得 you should be getting the feeling, 927 00:56:14,752 --> 00:56:17,960 Sussman教授又在胡说八道些什么 what's this nonsense this Sussman character is feeding me? 928 00:56:20,740 --> 00:56:23,920 他讲的东西奇怪、愚蠢又毫无意义 There's an awful lot of strange nonsense here. 929 00:56:24,800 --> 00:56:27,408 他还宣称要给我们解释Lisp After all, he purported to explain to me Lisp, 930 00:56:28,016 --> 00:56:29,904 然后在黑板上给我们写了一个Lisp程序 and he wrote me a Lisp program on the blackboard. 931 00:56:31,232 --> 00:56:33,536 他还说:“这个Lisp程序就是Lisp解释器” The Lisp program was intended to be interpreted for Lisp, 932 00:56:33,850 --> 00:56:35,024 但是为了运行这个Lisp程序 but you need a Lisp interpreter 933 00:56:35,040 --> 00:56:36,300 你还先得有一个Lisp解释器啊 in order to understand that program. 934 00:56:38,370 --> 00:56:40,192 那个程序怎么能告诉我 How could that program have told me anything 935 00:56:40,224 --> 00:56:43,200 有关于Lisp的知识呢? there is to be known about Lisp? 936 00:56:44,150 --> 00:56:46,224 它为什么又不是空中楼阁呢? How is that not completely vacuous? 937 00:56:48,490 --> 00:56:50,256 这件事非常奇怪 It's a very strange thing. 938 00:56:50,990 --> 00:56:52,430 它究竟告诉了我什么? Does it tell me anything at all? 939 00:56:56,070 --> 00:56:57,200 我们发现 其实这整件事 Well, you see, the whole thing 940 00:56:57,328 --> 00:56:59,790 非常像我们在这张幻灯片上看到的 is sort of like these Escher's hands 941 00:57:00,464 --> 00:57:03,552 Escher所画的手 that we see on this slide. 942 00:57:06,180 --> 00:57:07,728 是的 EVAL和APPLY Yes, eval and apply 943 00:57:07,760 --> 00:57:10,160 彼此画出彼此 each sort of draw each other 944 00:57:11,504 --> 00:57:14,160 并且构造出了真实的东西 and construct the real thing, 945 00:57:14,864 --> 00:57:16,304 它完全是自己画出了自己 which can sit out and draw itself. 946 00:57:17,110 --> 00:57:18,464 Escher真是绝顶聪明 Escher was a very brilliant man, 947 00:57:18,688 --> 00:57:20,416 他只不过叫不出这些精灵的名字 he just didn't know the names of these spirits. 948 00:57:23,910 --> 00:57:25,008 我现在要做的就是 Well, I'm going to do now, 949 00:57:26,096 --> 00:57:28,000 使你们相信 is I'm going to try to convince you 950 00:57:28,160 --> 00:57:29,872 这一切都是有意义的 that both this mean something, 951 00:57:30,160 --> 00:57:31,980 并且 and, as a aside, 952 00:57:32,992 --> 00:57:34,720 我将要解释为什么我们不需要DEFINE I'm going to show you why you don't need definitions. 953 00:57:36,090 --> 00:57:37,712 事实证明 我们并不需要DEFINE Just turns out that sort of falls out, 954 00:57:38,096 --> 00:57:41,120 为了进行数学意义上的计算 why definitions are not essential in a mathematical sense 955 00:57:42,512 --> 00:57:44,890 DEFINE并不是必需的 for doing all the things we need to do for computing. 956 00:57:49,104 --> 00:57:50,032 我们来看一下 Well, let's see here. 957 00:57:50,690 --> 00:57:53,312 考虑下面的一小段程序 Consider the following small program, 958 00:57:53,744 --> 00:57:54,640 它有什么作用? what does it mean? 959 00:57:54,870 --> 00:57:57,648 这是一个计算指数的程序 This is a program for computing exponentials. 960 00:58:07,270 --> 00:58:13,232 EXPT计算X的N次方 The exponential of x to the nth power is if-- 961 00:58:16,832 --> 00:58:18,128 如果N为0 n is zero, 962 00:58:19,200 --> 00:58:20,768 那么结果就是1 then the result is one. 963 00:58:22,070 --> 00:58:22,816 否则 Otherwise, 964 00:58:25,568 --> 00:58:28,480 结果就是X乘以 I want the product of x 965 00:58:28,752 --> 00:58:33,930 (EXPT X (- N 1)))) and the result of exponentiating x to the n minus one power. 966 00:58:43,696 --> 00:58:44,560 应该没错 I think I got it right. 967 00:58:46,630 --> 00:58:48,720 一个递归定义 Now this is a recursive definition. 968 00:58:49,470 --> 00:58:52,176 用EXPT自身 It's a definition of the exponentiation 969 00:58:52,464 --> 00:58:54,780 来定义EXPT过程自己 procedure in terms of itself. 970 00:58:56,410 --> 00:58:58,320 就像我之前说的那样 And, as it has been mentioned before, 971 00:58:59,280 --> 00:59:01,680 你们高中数学老师在教这些东西的时候 your high school geometry teacher 972 00:59:01,840 --> 00:59:04,048 你们一定学得很痛苦 probably gave you a hard time about things like that. 973 00:59:05,650 --> 00:59:06,736 这样定义合理吗? Was that justified? 974 00:59:07,910 --> 00:59:10,848 为什么这种自引用的定义 Why does this self referential definition 975 00:59:10,960 --> 00:59:12,040 能够说得通呢? make any sense? 976 00:59:13,430 --> 00:59:15,104 首先我要说的是 Well, first of all, I'm going to convince you that 977 00:59:15,136 --> 00:59:17,600 你们高中数学老师并非在胡说八道 your high school geometry teacher was not telling you nonsense. 978 00:59:20,370 --> 00:59:23,424 考虑下面的几组定义 Consider the following set of definitions here. 979 00:59:24,270 --> 00:59:27,424 X+Y=3 x plus y equals three, 980 00:59:28,240 --> 00:59:32,240 X-Y=1 and x minus y equal one. 981 00:59:33,070 --> 00:59:35,568 这个方程用Y来告诉你X Well, gee, this tells you x in terms of y, 982 00:59:35,584 --> 00:59:37,840 而这个方程或许是用X来告诉你Y and this one tells you y in terms of x, presumably. 983 00:59:40,150 --> 00:59:42,950 碰巧这组方程有唯一的解 And yet this happens to have a unique solution in x and y. 984 00:59:55,910 --> 00:59:58,112 然而 我也可能有这样的方程 However, I could also write 985 00:59:59,872 --> 01:00:04,256 2X+2Y=6 two x plus two y is six. 986 01:00:06,832 --> 01:00:09,872 这两个方程有无穷多个解 These two equations have an infinite number solutions. 987 01:00:15,730 --> 01:00:17,424 我还可以有像这样的方程 And I could write you, for example, 988 01:00:18,896 --> 01:00:21,536 X-Y=2 x minus y equal 2, 989 01:00:22,144 --> 01:00:24,416 而下面的这两个方程没有解 and these two equations have no solutions. 990 01:00:29,820 --> 01:00:33,040 这里 我有三组线性方程组 Well, I have here three sets of simultaneous linear equations, 991 01:00:35,456 --> 01:00:39,510 分别是这组、这组和这组 this set, this set, and this set. 992 01:00:39,888 --> 01:00:41,792 它们的解的数目完全不同 But they have different numbers of solutions. 993 01:00:42,900 --> 01:00:45,760 解的数目并不取决于方程的形式 The number of solutions is not in the form of the equations. 994 01:00:46,336 --> 01:00:48,208 三组方程都有一样的形式 They all three sets have the same form. 995 01:00:48,544 --> 01:00:50,416 解的数目取决于方程的内容 The number of solutions is in the content. 996 01:00:53,000 --> 01:00:55,152 我不能通过观察方程的形式 I can't tell by looking at the form of a definition 997 01:00:55,168 --> 01:00:56,240 来判断解的数目 whether it makes sense, 998 01:00:56,864 --> 01:00:58,608 必须要看它的内容 only by its detailed content. 999 01:00:59,660 --> 01:01:00,880 比如 对于线性方程组 What are the coefficients, 1000 01:01:01,344 --> 01:01:03,392 它的系数都是什么? for example, in the case of linear equations? 1001 01:01:05,100 --> 01:01:06,720 我不能够通过观察 So I shouldn't expect to be able to tell 1002 01:01:06,992 --> 01:01:08,336 像这样的简单情况 looking at something like this, 1003 01:01:08,592 --> 01:01:09,952 来判定 from some simple things like, 1004 01:01:10,080 --> 01:01:14,496 EXPT就是这个递归方程的解 oh yes, EXPT is the solution of this recursion equation. 1005 01:01:16,030 --> 01:01:18,416 我不能说 EXPT就是那个过程 Expt is the procedure 1006 01:01:18,912 --> 01:01:21,104 如果我们把它代换入其中 which if substituted in here, 1007 01:01:22,048 --> 01:01:24,064 它就能给我们返回EXPT gives me expt back. 1008 01:01:25,328 --> 01:01:25,680 能跟上吗? OK? 1009 01:01:26,040 --> 01:01:29,248 通过观察这个形式 我也无法判别 I can't tell, looking at this form, 1010 01:01:29,808 --> 01:01:32,608 EXPT是否有唯一解 whether or not there's a single, unique solution for EXPT, 1011 01:01:33,232 --> 01:01:35,312 有无穷个解 还是根本没有解 an infinite number of solutions, or no solutions. 1012 01:01:37,200 --> 01:01:38,624 我们要了解它是如何计数的 It's got to be how it counts 1013 01:01:38,640 --> 01:01:40,144 或者是一些类似的计算细节 and things like that, the details. 1014 01:01:40,608 --> 01:01:42,752 这可比在线性代数难多了 And it's harder in programming than linear algebra. 1015 01:01:43,280 --> 01:01:45,210 程序设计中可用的定理并不多 There aren't too many theorems about it in programming. 1016 01:01:48,450 --> 01:01:51,216 我想把这些方程稍稍重写一下 Well, I want to rewrite these equations a little bit, 1017 01:01:51,936 --> 01:01:53,776 就是这里的方程 these over here. 1018 01:01:53,970 --> 01:01:56,624 因为我们要研究的是这种形式的方程 Because what we're investigating is equations like this. 1019 01:01:57,000 --> 01:01:58,384 但是我想用我们比较了解的方程 But I want to play a little with equations 1020 01:01:58,400 --> 01:01:59,530 来做演示 like this that we understand, 1021 01:02:00,704 --> 01:02:02,912 以便于对于这类问题有深入的洞见 just so we get some insight into this kind of question. 1022 01:02:04,720 --> 01:02:06,432 我们可以把这里的方程 改写为 We could rewrite our equations here, 1023 01:02:06,752 --> 01:02:08,672 这样的一种有趣形式 say these two, the ones that are interesting, 1024 01:02:09,776 --> 01:02:14,864 X=3-Y as x equals three minus y, 1025 01:02:15,888 --> 01:02:19,680 Y=X-1 and y equals x minus one. 1026 01:02:22,010 --> 01:02:24,050 我们把这种变换叫什么来着? What do we call this transformation? 1027 01:02:24,050 --> 01:02:26,528 这是一个线性变换 记为T This is a linear transformation, t. 1028 01:02:29,430 --> 01:02:32,256 我们这里就得到了一个方程 Then what we're getting here is an equation 1029 01:02:32,976 --> 01:02:37,370 = T x y equals t of x y. 1030 01:02:42,990 --> 01:02:43,984 我要去找什么呢? What am I looking for? 1031 01:02:44,560 --> 01:02:46,016 我在找T的不动点 I'm looking for a fixed point of t. 1032 01:02:46,976 --> 01:02:59,424 T的不动点就是方程的解 The solution is a fixed point of t. 1033 01:03:01,910 --> 01:03:05,536 所以 如果我们能通过找不动点 So the methods we should have for looking for solutions to equations, 1034 01:03:05,904 --> 01:03:07,488 来求解方程 if I can do it by fixed points, 1035 01:03:08,656 --> 01:03:09,872 这看来是可行的 might be applicable. 1036 01:03:10,880 --> 01:03:12,368 如果我可以用不动点 If I have a means of finding a solution 1037 01:03:12,384 --> 01:03:14,320 来求解方程 to an equations by fixed points-- 1038 01:03:15,520 --> 01:03:18,192 当然 也许它不可行 just, might not work-- 1039 01:03:18,570 --> 01:03:19,800 不过也可以借鉴来 but it might be applicable 1040 01:03:20,096 --> 01:03:22,272 研究如何求解这类方程 to investigating solutions of equations like this. 1041 01:03:27,240 --> 01:03:29,488 重要的是 我想让你们把它看成一个方程 But what I want you to feel is that this is an equation. 1042 01:03:30,260 --> 01:03:31,216 它是一个表达式 It's an expression 1043 01:03:31,360 --> 01:03:33,580 其中有不同的变量 with several instances of various names 1044 01:03:34,704 --> 01:03:37,664 只不过这些名字还得满足一定的约束 which puts a constraint on the name, 1045 01:03:38,432 --> 01:03:40,528 这些名字限定了对应变量的取值 saying what that name could have as its value, 1046 01:03:41,488 --> 01:03:45,010 我们不能够随意、机械地代换 rather than some sort of mechanical process of substitution right now. 1047 01:03:47,740 --> 01:03:49,776 这就是我尝试求解的方程 This is an equation which I'm going to try to solve. 1048 01:03:51,220 --> 01:03:52,432 我们来试试看 Well, let's play around and solve it. 1049 01:03:53,960 --> 01:03:55,664 首先我需要写下 First of all, I want to write down 1050 01:03:56,640 --> 01:03:59,008 跟T相对应的函数 the function which corresponds to t. 1051 01:04:00,320 --> 01:04:03,008 我写下的这个T对应的函数 First I want to write down the function which corresponds to t 1052 01:04:04,496 --> 01:04:06,960 它的不动点就是这个方程的解 whose fixed point is the answer to this question. 1053 01:04:10,760 --> 01:04:11,280 能明白吗? OK? 1054 01:04:12,256 --> 01:04:14,304 让我们来看下面这个过程F Well, let's consider the following procedure f. 1055 01:04:16,870 --> 01:04:18,304 我说 F计算的是这样一个函数 I claim it computes that function. 1056 01:04:19,340 --> 01:04:22,912 F本身是一个参数为G的一元过程 f is that procedure of one argument g, 1057 01:04:25,232 --> 01:04:25,936 它返回 which is 1058 01:04:26,400 --> 01:04:32,000 一个参数为X和N的过程 that procedure of two arguments x and n. 1059 01:04:33,430 --> 01:04:34,736 这个过程的定义是: Which have the property that 1060 01:04:36,720 --> 01:04:40,432 如果N为0 if n is zero, 1061 01:04:41,728 --> 01:04:43,200 那么结果就是1 then the result is one, 1062 01:04:45,344 --> 01:04:46,176 否则的话 otherwise, 1063 01:04:49,900 --> 01:05:01,408 结果就是(* X (G X (- N 1))) the result is the product of x and g, applied to x, and minus n1. 1064 01:05:03,370 --> 01:05:07,808 (闭合括号中) g, times, else, COND, lambda, lambda-- 1065 01:05:08,944 --> 01:05:09,408 没问题吧 OK? 1066 01:05:12,304 --> 01:05:14,624 这里 F是一个过程 Here f is a procedure, 1067 01:05:15,050 --> 01:05:17,792 如果我能解出这个方程 which if I had a solution to that equation, 1068 01:05:19,040 --> 01:05:22,048 如果我找到了一个良好的指数过程 if I had a good exponentiation procedure, 1069 01:05:23,420 --> 01:05:26,320 我把这个F应用到那个过程上 and I applied f to that procedure, 1070 01:05:27,600 --> 01:05:31,248 那么返回的应该也是一个良好的指数过程 then the result would be a good exponentiation procedure. 1071 01:05:37,460 --> 01:05:38,576 这是为什么呢? Because, what does it do? 1072 01:05:39,420 --> 01:05:40,880 这是因为 Well, all it is 1073 01:05:42,368 --> 01:05:44,640 F假设G是一个良好的指数过程 is exposing g were a good exponentiation procedure, 1074 01:05:45,632 --> 01:05:47,584 那么这里就会返回 well then this would produce, as its value, 1075 01:05:47,840 --> 01:05:49,680 一个参数为X和N的过程 a procedure to arguments x and n, 1076 01:05:50,490 --> 01:05:51,520 其中如果N=0 such that if n were 0, 1077 01:05:51,552 --> 01:05:52,416 结果就是1 the result would be one, 1078 01:05:52,448 --> 01:05:54,160 这是非常符合定义的 which is certainly true of exponentiation. 1079 01:05:54,640 --> 01:05:57,056 否则 就返回X乘以 Otherwise, it will be the result of multiplying x 1080 01:05:57,264 --> 01:05:59,264 用给定的指数过程G by the exponentiation procedure given to me 1081 01:06:00,176 --> 01:06:02,448 计算(G X (- N 1)) with x and n minus one as arguments. 1082 01:06:03,470 --> 01:06:04,784 因此如果G能够 So if this computed the correct 1083 01:06:04,816 --> 01:06:06,300 正确计算X^(N-1) exponentiation for n minus one, 1084 01:06:07,872 --> 01:06:11,280 那么这个表达式就能正确计算X^N then this would be the correct exponentiation for exponent n, 1085 01:06:12,176 --> 01:06:14,416 所以整个就会是一个正确的求指数过程 so this would have been the right exponentiation procedure. 1086 01:06:17,500 --> 01:06:19,824 因此 我在这里真正想指出的是 So what I really want to say here is 1087 01:06:21,020 --> 01:06:32,448 过程EXPT是函数F的不动点 E-X-P-T is a fixed point of f. 1088 01:06:36,990 --> 01:06:38,352 现在我们的问题在于 Now our problem is 1089 01:06:38,352 --> 01:06:39,680 不动点可能不止一个 there might be more than one fixed point. 1090 01:06:40,060 --> 01:06:42,192 也可能没有不动点 There might be no fixed points. 1091 01:06:43,270 --> 01:06:44,810 所以我们必须求出不动点 I have to go hunting for the fixed points. 1092 01:06:48,224 --> 01:06:49,376 需要来解这个方程 Got to solve this equation. 1093 01:06:52,160 --> 01:06:54,288 求不动点的方法有很多种 Well there are various ways to hunt for fixed points. 1094 01:06:55,580 --> 01:06:57,088 本门课程的第一节课 Of course, the one we played with 1095 01:06:57,248 --> 01:07:01,160 我们就用余弦函数做了演示 at the beginning of this term worked for cosine. 1096 01:07:02,736 --> 01:07:07,690 先把你的计算器调成弧度制 Going to. Go into radians mode on your calculator 1097 01:07:07,856 --> 01:07:10,512 然后一直按COS键 and push cosine, and just keep doing it, 1098 01:07:11,840 --> 01:07:15,456 最后数字会稳定在0.73、0.74左右 and you get to some number which is about 0.73 or 0.74. 1099 01:07:16,090 --> 01:07:17,184 我记不清是哪个了 I can't remember which. 1100 01:07:20,576 --> 01:07:22,640 通过迭代一个过程 By iterating a procedure, which has 1101 01:07:22,816 --> 01:07:24,400 我们不断迭代 By iterating a function, 1102 01:07:25,600 --> 01:07:27,168 想要寻找不动点的函数 whose fixed point I'm searching for, 1103 01:07:27,500 --> 01:07:31,136 有时候 它就会收敛在一个点上 it is sometimes the case that that function will converge 1104 01:07:31,872 --> 01:07:33,088 这就是不动点 in producing the fixed point. 1105 01:07:33,770 --> 01:07:35,440 碰碰运气 I think we luck out in this case, 1106 01:07:36,448 --> 01:07:37,216 来试试这种方法 so let's look for it. 1107 01:07:39,910 --> 01:07:46,288 来看这张幻灯片 Let's look at this overhead, this slide. 1108 01:07:48,030 --> 01:07:51,712 考虑这么一连串的过程 Consider the following sequence of procedures. 1109 01:07:56,400 --> 01:07:57,792 这里的E0 e0 over here 1110 01:07:59,248 --> 01:08:01,632 这个E0过程什么也不做 the procedure which does nothing at all. 1111 01:08:02,890 --> 01:08:05,104 无论你给它传递什么参数 It's the procedure which produces an error 1112 01:08:05,104 --> 01:08:06,240 它都会产生ERROR for any arguments you give it. 1113 01:08:07,780 --> 01:08:09,030 基本上没什么用 It's basically useless. 1114 01:08:14,480 --> 01:08:20,080 然而 我可以做近似 Well, however, I can make an approximation. 1115 01:08:20,080 --> 01:08:23,936 让我们考虑下 指数过程的最差近似 Let's consider it the worst possible approximation to exponentiation, 1116 01:08:24,736 --> 01:08:25,536 因为它什么也做不了 because it does nothing. 1117 01:08:26,990 --> 01:08:29,680 假设我调用F Well, supposing I substituted e0 1118 01:08:30,352 --> 01:08:33,260 用E0去代换G for g by calling f, 1119 01:08:33,792 --> 01:08:36,304 这里 G就被代换为了E0 as you see over here on e0. 1120 01:08:37,380 --> 01:08:39,776 所以在这里就是E0 So you see over here, have e0 there. 1121 01:08:40,848 --> 01:08:42,352 那么E1又成了什么呢? Then gee, what's e1? 1122 01:08:43,630 --> 01:08:46,032 如果用E1来计算X^0 e1 is a procedure which exponentiate things 1123 01:08:46,672 --> 01:08:48,784 没什么问题 to the 0th power, with no trouble. 1124 01:08:49,600 --> 01:08:50,752 它返回的结果是正确的 It gets the right answer, 1125 01:08:51,050 --> 01:08:52,352 任何数的0次幂都是1 anything to the zero is one, 1126 01:08:52,688 --> 01:08:54,250 然而计算其它次幂就会出错 and it makes an error on anything else. 1127 01:08:57,390 --> 01:09:01,568 现在如果我用E1来调用F Well, now what if I take e1 1128 01:09:02,304 --> 01:09:07,408 把G代换为E1 会发生什么? and substituted it for g by calling f on e1? 1129 01:09:09,580 --> 01:09:11,180 这样的话 Oh gosh, 1130 01:09:12,016 --> 01:09:15,024 我就会得到这个二元过程 I have here a procedure of two arguments. 1131 01:09:15,670 --> 01:09:16,848 想一想 E1这个过程 Now remember e1 1132 01:09:16,960 --> 01:09:19,664 只能正确计算X^0 was appropriate for taking exponentiations of 0, 1133 01:09:21,472 --> 01:09:23,376 它只能计算0次幂 for raising to the 0 exponent. 1134 01:09:24,200 --> 01:09:25,008 所以这里 So here, 1135 01:09:25,520 --> 01:09:27,280 如果N为0 结果就是1 if is n is 0, the result is one, 1136 01:09:27,296 --> 01:09:28,672 E2的这部分也正确 so this guy is good for that too. 1137 01:09:29,520 --> 01:09:32,016 然而 我可以通过把0次幂乘以X However, I can use something for raising to the 0th power 1138 01:09:32,512 --> 01:09:35,264 来计算1次幂 to multiply it by x to raise something to the first power. 1139 01:09:35,979 --> 01:09:39,670 所以E2可以正确计算0次幂和1次幂 So e2 is good for both power 0 and 1. 1140 01:09:41,600 --> 01:09:41,920 对吧? OK? 1141 01:09:43,712 --> 01:09:46,672 E3的构造过程和E2是类似的 And e3 is constructed from e2 in the same way. 1142 01:09:47,890 --> 01:09:50,240 当然 E3具有同样的参数 And e3, of course, by the same argument 1143 01:09:50,320 --> 01:09:53,370 能够正确计算0、1、2次幂 is good for powers 0, one, and two. 1144 01:09:55,120 --> 01:09:55,408 对吧? OK? 1145 01:09:56,090 --> 01:09:59,080 因此我就不加证明地告诉你结论 And so I will assert for you, without proof, 1146 01:09:59,664 --> 01:10:01,728 因为这个证明过程太难了 because the proof is horribly difficult. 1147 01:10:02,520 --> 01:10:03,600 这种事情 And that's the sort of thing that 1148 01:10:03,632 --> 01:10:06,368 是由人们所谓“指称语义学家”完成的 people called denotational semanticists do. 1149 01:10:06,590 --> 01:10:07,648 这个伟大的想法 I suppose it was invented 1150 01:10:07,872 --> 01:10:10,592 应该是由Scott和Strachey提出的 This great idea was invented by Scott and Strachey. 1151 01:10:11,648 --> 01:10:16,320 他们是非常著名的数学家 Ah, sort of. They're very famous mathematician types 1152 01:10:16,864 --> 01:10:21,216 他们发明了这些程序的解释方式 who invented the interpretation for these programs that we have 1153 01:10:22,368 --> 01:10:24,000 就是我刚才讲的那些 that I'm talking to you about right now. 1154 01:10:24,240 --> 01:10:26,176 他们通过拓扑学的方法证明了 And they proved, by topology 1155 01:10:27,040 --> 01:10:29,328 在我们刚才那种情况下 that there is such a fixed point 1156 01:10:29,824 --> 01:10:31,264 不动点是存在的 in the cases that we want. 1157 01:10:32,220 --> 01:10:33,248 这个结论就是: But the assertion is 1158 01:10:33,400 --> 01:10:44,240 当N趋近于无穷时 EXPT是E(N)的极限 E-X-P-T is limit as n goes to infinity of em. 1159 01:10:45,520 --> 01:10:47,900 我们是通过下面这种方式来构造这个极限的 and And that we've constructed this by the following way. 1160 01:10:50,520 --> 01:10:55,664 EXPT=(F (F (F (F .... --is Well, it's f of, f of, f of, f of, f of-- 1161 01:10:57,616 --> 01:11:00,192 (F 丄) f applied to anything at all. 1162 01:11:01,120 --> 01:11:02,464 它是什么都无所谓 It didn't matter what that was, 1163 01:11:03,184 --> 01:11:05,008 因为它总会生成一个错误 because, in fact, this always produces an error. 1164 01:11:07,456 --> 01:11:08,416 (闭合括号中) Applied to this-- 1165 01:11:12,896 --> 01:11:14,480 这是F无穷嵌套调用 That's by infinite nesting of f's. 1166 01:11:16,380 --> 01:11:17,712 现在我们的问题 So now my problem 1167 01:11:18,224 --> 01:11:19,760 又变成了如何构造出无穷调用 is to make some infinite things. 1168 01:11:22,590 --> 01:11:24,080 我们需要它们 We need some infinite things. 1169 01:11:24,920 --> 01:11:26,256 我怎样才能把F How am I going to nest up an f 1170 01:11:26,560 --> 01:11:27,808 嵌套无穷层呢? an infinite number of times? 1171 01:11:28,980 --> 01:11:30,128 我得把它构造出来 I'd better construct this. 1172 01:11:32,380 --> 01:11:32,930 好吧 我不知道 Well, I don't know. 1173 01:11:32,930 --> 01:11:34,320 到底怎么样构建一个无穷循环呢? How would I make an infinite loop at all? 1174 01:11:34,810 --> 01:11:36,320 我们先来看个非常简单的无穷循环 Let's take a very simple infinite loop, 1175 01:11:36,576 --> 01:11:38,340 能想到的最简单的无穷循环 the simplest infinite loop imaginable. 1176 01:11:43,550 --> 01:11:47,552 把这样一个参数为X的函数过程 If I were to take that procedure of one argument x 1177 01:11:48,000 --> 01:11:49,792 过程体是(X X) which applies x to x 1178 01:11:53,552 --> 01:11:53,920 看到了吧? OK? 1179 01:11:55,056 --> 01:11:58,416 应用在一个参数为X过程上 and apply that to the procedure of one argument x 1180 01:11:59,360 --> 01:12:01,056 后者的过程体也是(X X) which applies x to x, 1181 01:12:04,832 --> 01:12:06,000 这就形成了一个无穷循环 then this is an infinite loop. 1182 01:12:07,216 --> 01:12:09,312 这个循环之所以是无穷的 The reason why this is an infinite loop is as follows. 1183 01:12:09,980 --> 01:12:11,312 是因为 The way I understand this 1184 01:12:11,520 --> 01:12:13,696 我用实际参数代换掉 is I substitute the argument 1185 01:12:14,224 --> 01:12:16,592 过程体的形式参数 for the formal parameter in the body. 1186 01:12:18,850 --> 01:12:21,600 这样做了以后 这里的每个X But if I do that, I take for each of these x's, 1187 01:12:22,400 --> 01:12:23,760 都被代换为了这个 I substitute one of these, 1188 01:12:24,368 --> 01:12:26,960 相当于把最初的表达式又复制了一遍 making a copy of the original expression I just started with, 1189 01:12:28,352 --> 01:12:29,376 这就是最简单的无穷循环 the simplest infinite loop. 1190 01:12:35,440 --> 01:12:39,296 现在 我要介绍一个特殊的运算符 Now I want to tell you about a particular operator 1191 01:12:40,384 --> 01:12:43,090 它是通过对这个无穷循环稍作修改而来 which is constructed by a perturbation from this infinite loop. 1192 01:12:46,960 --> 01:12:47,920 我把它记作“Y” I'll call it y. 1193 01:12:50,896 --> 01:12:55,820 它的全称是:Curry的矛盾Y组合子 OK y -- This is called Curry's Paradoxical Combinator of y 1194 01:12:56,624 --> 01:12:58,992 这是用二十世纪三十年代的逻辑学家 after a fellow by the name of Curry, 1195 01:12:59,344 --> 01:13:01,856 Curry的名字来命名的 who was a logician of the 1930s also. 1196 01:13:04,480 --> 01:13:06,880 Y组合子是一个参数为f的过程 And if I have a procedure of one argument f, 1197 01:13:08,176 --> 01:13:09,330 它的过程体是什么呢? what's it going to have in it? 1198 01:13:09,330 --> 01:13:11,200 它的内部是某种无穷循环 It's going to have a kind of infinite loop in it, 1199 01:13:11,984 --> 01:13:15,472 是一个参数为x的过程 which is that procedure of one argument x 1200 01:13:15,952 --> 01:13:18,800 它调用(f (x x)) which applies f to x of x, 1201 01:13:21,630 --> 01:13:24,750 这个过程应用在一个参数为X的过程上 applied to that procedure of one argument x, 1202 01:13:25,104 --> 01:13:27,344 后者调用(f (x x)) which applies f to f of x. 1203 01:13:32,300 --> 01:13:33,136 这个是怎么运作的? Now what's this do? 1204 01:13:34,800 --> 01:13:36,060 假设执行(Y F) Suppose we apply y to F. 1205 01:13:41,312 --> 01:13:42,576 这非常简单 OK? Well, that's easy enough. 1206 01:13:43,152 --> 01:13:44,624 这里大写的F跟那边的是同一个 That's this capital F over here. 1207 01:13:46,910 --> 01:13:48,160 在这里 很简单 Well, the easiest thing to say there 1208 01:13:48,304 --> 01:13:49,920 我把F代换到这里来 is, I substitute F for here. 1209 01:13:55,320 --> 01:13:57,072 基本上 我就会得到 So that's going to give me, basically-- 1210 01:13:58,750 --> 01:14:00,848 因为我待会儿要用这个表达式 because then I'm going to substitute this 1211 01:14:01,456 --> 01:14:02,800 代换这里的x for x in here. 1212 01:14:04,176 --> 01:14:05,232 这里就是(F That F of 1213 01:14:08,970 --> 01:14:10,096 我还是把这步写出来吧 Let me actually do it in steps, 1214 01:14:10,224 --> 01:14:11,456 这样你们就能看得更全面 so you can see it completely. 1215 01:14:11,920 --> 01:14:14,272 我会非常小心 好吗? I'm going to be very careful. OK? 1216 01:14:15,020 --> 01:14:18,256 这里是 ((LAMBDA (x) This is open, open, lambda of x , 1217 01:14:19,088 --> 01:14:22,112 (F (x x)) capital F, x, x, 1218 01:14:26,880 --> 01:14:35,552 把它应用到自身 (LAMBDA (x) (F (x x))) applied to itself, F of x of x. 1219 01:14:37,910 --> 01:14:39,664 把这个表达式代换进去 Substituting this for this in here, 1220 01:14:40,064 --> 01:14:40,912 就得到 this is 1221 01:14:43,130 --> 01:14:48,352 把这个代进去 得到什么呢? F applied to-- what is it-- substituting this in here 1222 01:14:48,656 --> 01:14:54,810 (F (LAMBDA (x) (F (x x))) open, open, lambda of x, F, of x and x, 1223 01:14:57,072 --> 01:14:58,176 应用到 applied to 1224 01:14:59,180 --> 01:15:06,480 (LAMBDA (x) (F (x x)))) lambda of x, F of x of x, F, 1225 01:15:06,992 --> 01:15:10,448 (闭合括号中) lambda, pair, F. 1226 01:15:11,510 --> 01:15:12,400 哇 这又是什么? Oh, but what is this? 1227 01:15:13,420 --> 01:15:16,352 我刚才计算的这一部分 This thing over here that I just computed, 1228 01:15:17,136 --> 01:15:18,560 就是这里的这部分 is this thing over here. 1229 01:15:20,192 --> 01:15:21,840 只不过它被包在另一个F里面 But I just wrapped another F around it. 1230 01:15:23,370 --> 01:15:24,672 因此 通过把Y应用在F上 So by applying y to F, 1231 01:15:24,688 --> 01:15:26,224 我构造出了F的无穷嵌套 I make an infinite series of F's. 1232 01:15:27,850 --> 01:15:29,450 我如果让它一直这样进行下去 If I just let this run forever, 1233 01:15:29,696 --> 01:15:31,776 我在外层就会得到越来越多的F I'll just keep making more and more F's outside. 1234 01:15:33,170 --> 01:15:34,800 我运行一个无用的循环 I ran an infinite loop which is useless, 1235 01:15:35,200 --> 01:15:37,024 但内部是无用的并不重要 but it doesn't matter that the inside is useless. 1236 01:15:39,856 --> 01:15:47,856 因此 我们有 (Y F)=(F (Y F)) OK? So y of F is F applied to y of F. 1237 01:15:50,336 --> 01:15:52,144 Y组合子十分神奇 So y is a magical thing 1238 01:15:53,856 --> 01:15:56,256 如果把它应用于某个函数 which, when applied to some function, 1239 01:15:57,376 --> 01:16:00,384 它就会返回这个函数的不动点 produces the object which is the fixed point of that function, 1240 01:16:01,696 --> 01:16:04,256 当然是在不动点存在的前提下 if it exists, and if this all works. 1241 01:16:07,910 --> 01:16:10,080 这是因为 如果我把(Y F)带入F Because, indeed, if I take y of F 1242 01:16:10,128 --> 01:16:11,120 结果还是(Y F) I get y of F out. 1243 01:16:16,240 --> 01:16:18,864 现在我想让你们在 Now I want you to think this in terms of 1244 01:16:19,856 --> 01:16:22,384 EVAL-APPLY解释器方面思考一下 the eval-apply interpreter for a bit. 1245 01:16:23,860 --> 01:16:26,272 我在这里写了一大堆递归方程组 I wrote down a whole bunch of recursion equations out there. 1246 01:16:28,540 --> 01:16:30,224 那些联立方程组像 They're simultaneous in the same way 1247 01:16:30,224 --> 01:16:31,232 这些方程一样联立起来 these are simultaneous equations. 1248 01:16:31,470 --> 01:16:33,310 但EXPT不是联立方程 Exponentiation was not a simultaneous equation. 1249 01:16:33,310 --> 01:16:35,792 只是一个需要我赋义的变量 It was only one variable I was looking for a meaning for. 1250 01:16:38,150 --> 01:16:40,768 而Lisp则是某个过程的不动点 But what Lisp is is the fixed point of the process 1251 01:16:40,816 --> 01:16:42,570 对这个过程来说 如果我知道Lisp的定义 that's which says, if I knew what Lisp was 1252 01:16:42,592 --> 01:16:46,512 然后在递归方程等号的右边 and substituted it in for eval, and apply, and so on, 1253 01:16:46,590 --> 01:16:49,792 用它来代换EVAL、APPLY等变量 on the right hand sides of all those recursion equations, 1254 01:16:50,940 --> 01:16:53,968 如果它是一个良好定义的Lisp的话 then if it was a real good Lisp, is a real one, 1255 01:16:54,368 --> 01:16:56,304 那么递归方程等号左边 也是一个良好定义的Lisp then the left hand side would also be Lisp. 1256 01:16:58,220 --> 01:16:59,824 这样 那个定义就讲得通了 So I made sense of that definition. 1257 01:17:02,420 --> 01:17:05,410 不过是否有解却不太明显 Now whether or not there's an answer isn't so obvious. 1258 01:17:05,696 --> 01:17:06,752 我也说不清 I can't attack that. 1259 01:17:07,740 --> 01:17:09,216 现在我要介绍的论证 Now these arguments that I'm giving you now 1260 01:17:09,264 --> 01:17:10,272 相当危险 are quite dangerous. 1261 01:17:10,660 --> 01:17:11,648 具体看这里 Let's look over here. 1262 01:17:13,056 --> 01:17:14,610 这些是关于极限的论证 On the. These are limit arguments. 1263 01:17:14,610 --> 01:17:15,392 我们要讨论的极限 We're talking about limits, 1264 01:17:15,456 --> 01:17:17,680 是微积分或者拓扑学的概念 and it's really calculus, or topology, 1265 01:17:17,872 --> 01:17:20,032 或者说是类似的 数学分析中的概念 or something like that, a kind of analysis. 1266 01:17:20,768 --> 01:17:23,380 这个论证是你们都承认的 OK?Now here's an argument that you all believe. 1267 01:17:23,380 --> 01:17:25,296 我想让你们意识到 And I want to make sure you realize 1268 01:17:25,424 --> 01:17:27,664 我可以把你们耍得团团转 that I could be bullshitting you. 1269 01:17:28,864 --> 01:17:30,480 准备好了吗? 这是什么? Alright? What is this? 1270 01:17:34,250 --> 01:17:39,520 u = 1 + 1/2 + 1/4 + ....... u is the sum of 1/2, 1/4, and 1/8, and so on, 1271 01:17:39,744 --> 01:17:41,328 这是几何级数求和 the sum of a geometric series. 1272 01:17:42,820 --> 01:17:44,688 当然 我也可以耍点小把戏 And, of course, I could play a game here. 1273 01:17:44,820 --> 01:17:47,570 u - 1 = 1/2 + 1/4 + 1/8 ...... u minus one is 1/2, plus 1/4, plus 1/8, and so on. 1274 01:17:51,904 --> 01:17:54,464 这里我可以 But now if I multiple. What I could do here-- 1275 01:17:56,096 --> 01:17:57,936 糟糕了 这里漏掉了括号 Ooops. There is a parentheses error here. 1276 01:17:58,920 --> 01:18:01,456 这里应该是 But I can put here two times u minus one 1277 01:18:01,744 --> 01:18:03,990 2(u - 1) = 1 + 1/2 + 1/4 + 1/8 ........ is one plus 1/2, plus 1/4, plus 1/8. 1278 01:18:07,570 --> 01:18:08,544 这里能修改一下吗? Can I fix that? 1279 01:18:14,010 --> 01:18:16,430 哦 可以 Yes, well. 1280 01:18:18,192 --> 01:18:18,656 看到了吗? OK? 1281 01:18:19,520 --> 01:18:20,640 这样 我就得到 But that gives me back 1282 01:18:23,536 --> 01:18:26,640 2(u - 1) = u two times u minus one is u, 1283 01:18:27,808 --> 01:18:29,584 因此我们推断出 u=2 therefore, we conclude that u is two. 1284 01:18:30,300 --> 01:18:31,376 这是正确的 And this actually is true. 1285 01:18:31,968 --> 01:18:33,328 这个推理过程没有问题 There's no problem like that. 1286 01:18:34,048 --> 01:18:37,552 但如果我要是做点别的什么呢? But supposing I did something different. 1287 01:18:38,540 --> 01:18:39,488 假设我要求和的式子 Supposing I start up with something 1288 01:18:39,504 --> 01:18:41,200 明显没有和 which manifestly has no sum. 1289 01:18:41,568 --> 01:18:46,992 v = 1 + 2 + 4 + ........ v is one, plus two, plus four, plus 8, plus dot, dot, dot. OK? 1290 01:18:47,390 --> 01:18:51,392 v - 1 = 2 + 4 + 8 + ...... Well, v minus one is surely two, plus four, plus eight, plus dot, dot, dot. Right? 1291 01:18:52,272 --> 01:18:56,032 (v - 1)/2 = v v minus one over two, gee, that looks like v again. 1292 01:18:57,410 --> 01:19:00,544 这里我就可以推断出 From that I should be able to conclude that-- 1293 01:19:01,376 --> 01:19:02,912 显然这里又写错了 that's also wrong, apparently. 1294 01:19:03,070 --> 01:19:04,510 应该是 v = -1 v equals minus one. 1295 01:19:12,450 --> 01:19:13,824 这里应该是-1 That should be a minus one. 1296 01:19:15,280 --> 01:19:16,912 这个结论明显是错误的 And that's certainly a false conclusion. 1297 01:19:22,000 --> 01:19:23,472 当你处理极限的时候 So when you play with limits, 1298 01:19:24,224 --> 01:19:27,856 在某种方式下可行的论证 arguments that may work in one case 1299 01:19:29,424 --> 01:19:30,750 在其它情况下可能又不行了 they may not work in some other case. 1300 01:19:30,750 --> 01:19:31,696 要多加注意 You have to be very careful. 1301 01:19:32,240 --> 01:19:33,872 参数必须具有良好的形式 The arguments have to be well-formed. 1302 01:19:36,144 --> 01:19:39,232 但我不清楚 通常来说 And I don't know, in general, 1303 01:19:39,856 --> 01:19:41,936 像这样的论证有什么样的要求 what the story is about arguments like this. 1304 01:19:43,270 --> 01:19:45,248 我们要研习一大堆拓扑学文献来寻找答案 We can read a pile of topology and find out. 1305 01:19:46,272 --> 01:19:48,640 但是至少你们现在理解了 But, surely, at least you understand now, 1306 01:19:49,104 --> 01:19:51,136 为什么我们在黑板上写的这些东西 why it might be some meaning 1307 01:19:51,152 --> 01:19:52,768 是有一定语义的 to the things we've been writing on the blackboard. 1308 01:19:53,664 --> 01:19:55,616 你们也理解了它的语义 And you understand what that might mean. 1309 01:19:56,480 --> 01:19:58,352 我想现在是时候 So, I suppose, it's almost about time 1310 01:19:59,070 --> 01:20:03,840 祝贺你们成为 for you to merit being made a member 1311 01:20:04,280 --> 01:20:05,552 神圣的递归秩序中的 of the grand recursive order 1312 01:20:05,568 --> 01:20:07,040 一名LAMBDA演算黑客了 of lambda calculus hackers. 1313 01:20:08,848 --> 01:20:10,176 这是我们的徽章 I would. This is the badge. 1314 01:20:10,820 --> 01:20:12,544 因为你已经理解了 Because you now understand, for example, 1315 01:20:13,400 --> 01:20:15,200 它上面的那句话 what it says at the very top, 1316 01:20:16,896 --> 01:20:18,416 (Y F) = (F (Y F)) y F equals F y F. 1317 01:20:21,040 --> 01:20:21,664 这节课讲完了 Thank you. 1318 01:20:21,856 --> 01:20:22,752 有什么问题吗? Are there any questions? 1319 01:20:24,710 --> 01:20:25,150 Lev 请说 Yes, Lev. 1320 01:20:25,370 --> 01:20:27,392 学生:目前的状况来看 AUDIENCE: With this, it seems that 1321 01:20:27,408 --> 01:20:30,224 正如你指出的那样 我们不再需要DEFINE there's no need to define, as you imply, 1322 01:20:30,240 --> 01:20:32,704 不需要先存储一个值 以后再用 to just remember a value, to apply it later. 1323 01:20:32,992 --> 01:20:33,328 教授:对 PROFESSOR: Yeah. 1324 01:20:33,504 --> 01:20:36,448 学生:DEFINE在语言中好像有一些副作用 AUDIENCE: Defines were kind of a side-effect it seemed in the language. 1325 01:20:36,490 --> 01:20:38,528 (听不清)并且依赖于时序 [INTERPOSING] are order dependent. 1326 01:20:39,300 --> 01:20:42,064 不用DEFINE 是否消除了副作用? Does this eliminate the side-effect from the. 1327 01:20:42,280 --> 01:20:44,688 教授: 实际上 PROFESSOR: Well. The answer is, 1328 01:20:44,880 --> 01:20:46,440 解释器并不是像这样实现的 this is not the way these things were implemented. 1329 01:20:47,520 --> 01:20:47,936 明白了吧? OK? 1330 01:20:48,920 --> 01:20:53,152 在实际的实现中 DEFINE这个运算 Define, indeed is implemented as an operation 1331 01:20:53,184 --> 01:20:55,536 确实修改了环境 that actually modifies an environment structure, 1332 01:20:57,952 --> 01:21:02,336 改变了执行DEFINE的那个框架 changes the frame that the define is executed in. 1333 01:21:03,690 --> 01:21:06,512 这样做是有很多原因的 And there are many reasons for that, 1334 01:21:07,390 --> 01:21:08,640 其中之一就是 but a lot of this has to do with 1335 01:21:08,672 --> 01:21:10,090 方便交互式系统 making an interactive system. 1336 01:21:11,340 --> 01:21:14,128 就是说 如果你构造了一个系统 What this is saying is that if you've made a system, 1337 01:21:14,350 --> 01:21:15,200 而且你知道 and you know 1338 01:21:15,420 --> 01:21:16,608 你不打算进行调试 and you know you're not going to do any debugging 1339 01:21:16,608 --> 01:21:17,550 或之类的事儿 or anything like that, 1340 01:21:17,840 --> 01:21:20,720 你想立马知道所有的东西 and you know everything there is all at once, 1341 01:21:20,750 --> 01:21:21,248 你想知道的是 and you want to say, 1342 01:21:21,264 --> 01:21:23,120 方程组的最终解是什么? what is the meaning of a final set of equations? 1343 01:21:24,090 --> 01:21:25,264 然后系统返回你相应的值 This gives you a meaning for it. 1344 01:21:25,790 --> 01:21:27,456 但如果想要让系统变成交互式的 But in order to make an interactive system, 1345 01:21:27,456 --> 01:21:28,752 这样你可以在不影响其它部分的情况下 where you can change the meaning of one 1346 01:21:28,768 --> 01:21:31,680 增量式地修改某一部分 without changing everything else, incrementally, 1347 01:21:32,336 --> 01:21:35,040 没有DEFINE的话 就不能这么做了 you can't do that by implementing it this way. 1348 01:21:40,990 --> 01:21:41,248 你说 Yes. 1349 01:21:42,304 --> 01:21:44,256 学生:就是那张“危险”的幻灯片 AUDIENCE: Another question on your danger slide. 1350 01:21:44,650 --> 01:21:47,136 好像你举的两个例子 It seemed that the two examples that you gave 1351 01:21:47,160 --> 01:21:49,070 与其收敛与否有关系? had to do with convergence and non-convergence? 1352 01:21:49,184 --> 01:21:49,568 教授:是的 PROFESSOR: Right. 1353 01:21:50,300 --> 01:21:52,624 学生:函数理论中是否有 AUDIENCE: And that may or may not have something to do with 1354 01:21:52,760 --> 01:21:54,688 像线性系统 with function theory in a way which 1355 01:21:54,720 --> 01:21:56,600 或者非线性系统中的 would lead you to think of it in terms of linear systems, 1356 01:21:57,744 --> 01:21:59,008 那种思考方式 or non-linear systems. 1357 01:21:59,344 --> 01:22:01,760 函数的收敛性能否先验地知道 How does this convergence relate to being able to 1358 01:22:02,352 --> 01:22:05,536 哪些属性可能被违反? see a priori what properties of that might be violated? 1359 01:22:05,792 --> 01:22:06,576 教授:我不知道 PROFESSOR: I don't know. 1360 01:22:07,680 --> 01:22:10,096 我也不知道它需要什么条件 The answer is, I don't know under what circumstances. 1361 01:22:10,610 --> 01:22:12,048 我不知道怎么在一节课内 I don't know how to translate that 1362 01:22:12,528 --> 01:22:14,736 就给你们讲清楚 into less than an hour of talk more. 1363 01:22:16,910 --> 01:22:18,480 有什么条件来判别它们 What are the conditions under which, 1364 01:22:18,864 --> 01:22:20,768 是否收敛? for which we know that these things converge? 1365 01:22:22,864 --> 01:22:23,312 确实 And indeed, 1366 01:22:23,328 --> 01:22:26,350 这些都是为了告诉你 基于收敛的论证 all that was telling you that arguments that are based on convergence 1367 01:22:28,240 --> 01:22:29,472 都不可靠 are flaky 1368 01:22:29,664 --> 01:22:31,584 如果你事先不知道收敛性的话 if you don't know the convergence beforehand. 1369 01:22:32,810 --> 01:22:34,208 你可能做出错误的论证 You can make wrong arguments. 1370 01:22:34,440 --> 01:22:37,312 你可以先假设知道了答案 然后进行演绎 You can make deductions, as if you know the answer, 1371 01:22:37,392 --> 01:22:39,936 看它会不会产生什么明显的矛盾 and not be stopped somewhere by some obvious contradiction. 1372 01:22:40,976 --> 01:22:42,288 学生:我们是否可以说 AUDIENCE: So can we say then that 1373 01:22:42,336 --> 01:22:44,880 如果数学表达式F收敛 if F is a convergent mathematical expression, 1374 01:22:45,008 --> 01:22:47,360 那么它的递归性质就-- then the recursion property can be-- 1375 01:22:47,584 --> 01:22:51,296 教授:我认为 在技术上有一类F PROFESSOR: Well, I think there's a technical kind of F, 1376 01:22:52,120 --> 01:22:54,224 通过一些技术准则 OK? There is a technical description 1377 01:22:54,240 --> 01:22:55,900 我们可以找到这样的F of those F's that have the property 1378 01:22:55,984 --> 01:23:01,312 当你像这样迭代地应用它们时 that when you iteratively apply them like this, 1379 01:23:01,520 --> 01:23:02,256 它一定会收敛 you converge. 1380 01:23:03,020 --> 01:23:06,512 这类准则包括:单调、连续 Things that are monotonic, and continuous, 1381 01:23:07,328 --> 01:23:07,952 我想想 OK? 1382 01:23:08,384 --> 01:23:09,370 我把其它的准则忘了 and I forgot what else. 1383 01:23:09,370 --> 01:23:11,136 还有一些列像这样的 There is a whole bunch of little conditions like that 1384 01:23:11,680 --> 01:23:12,992 判别准则 which have this property. 1385 01:23:13,430 --> 01:23:16,000 现在的难点是 给定F然后进行推理 Now the real problem is deducing from looking at the F, 1386 01:23:16,928 --> 01:23:17,888 这是F的定义 its definition here, 1387 01:23:18,170 --> 01:23:19,660 它满足这些准则吗? whether not it has those properties, 1388 01:23:20,272 --> 01:23:21,328 这很难判断 and that's very hard. 1389 01:23:22,010 --> 01:23:24,000 那些准则都很简单得可以写下来 The properties are easy. You can write them down. 1390 01:23:24,580 --> 01:23:26,320 你可以看Joe Stoy写的一本书 You can look in a book by Joe Stoy. 1391 01:23:26,672 --> 01:23:29,584 那本书非常不错 It's a great book-- Stoy. 1392 01:23:32,220 --> 01:23:34,064 叫做The Scott-Strachey It's called, The Scott-Strachey 1393 01:23:34,496 --> 01:23:38,460 《指称语义:基于Scott-Strachey方法》 The Scott-Strachey Method of Denotational Semantics, 1394 01:23:39,552 --> 01:23:40,768 作者是Joe Stoy and it's by Joe Stoy, 1395 01:23:40,800 --> 01:23:41,760 由MIT出版社出版 MIT Press. 1396 01:23:48,064 --> 01:23:49,888 他把这一方面讲得非常详细 And he works out all this in great detail, 1397 01:23:50,208 --> 01:23:51,376 绝对会让你吓一大跳 enough to horrify you. 1398 01:23:55,056 --> 01:23:56,192 但是这本书仍然值得一读 But it really is readable. 1399 01:24:09,150 --> 01:24:10,080 好吧 谢谢大家 OK, well, thank you. 1400 01:24:11,490 --> 01:24:12,992 这节课到此为止 Time for the bigger break, I suppose. 1401 01:24:14,176 --> 01:24:20,928 MIT OpenCourseWare http://ocw.mit.edu 1402 01:24:20,920 --> 01:24:34,496 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec7b.srt ================================================ 1 00:00:00,010 --> 00:00:01,632 Learning-SICP学习小组 倾情制作 2 00:00:01,630 --> 00:00:04,336 翻译&&时间轴:邓雄飞、张大伟 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:04,384 --> 00:00:07,344 特别感谢:裘宗燕教授 4 00:00:07,360 --> 00:00:09,488 计算机程序的构造和解释 5 00:00:09,520 --> 00:00:13,664 元循环求值器 II Metacircular Evaluator II 6 00:00:17,216 --> 00:00:17,968 教授:目前为止 PROFESSOR: Well, let's see. 7 00:00:19,520 --> 00:00:21,296 我们学的东西都非常有趣 What we did so far was a lot of fun, 8 00:00:21,520 --> 00:00:23,050 但它有什么实际的用途吗? was it useful for anything? 9 00:00:26,330 --> 00:00:27,968 我想答案是“是的” I suppose the answer is going to be yes. 10 00:00:29,380 --> 00:00:31,920 这些元循环解释器 If these metacircular interpreters 11 00:00:32,960 --> 00:00:34,608 非常值得琢磨 are a valuable thing to play with. 12 00:00:34,624 --> 00:00:36,176 我花了大概 I spend, say 13 00:00:38,050 --> 00:00:41,856 曾几何时 我花了半年的功夫 there have been times I spend 50% of my time, over a year, 14 00:00:42,864 --> 00:00:45,264 用上节课讲的那种 trying various design alternatives 15 00:00:45,760 --> 00:00:48,192 元循环解释器来试验 by experimenting with them with metacircular interpreters-- 16 00:00:49,472 --> 00:00:52,016 各种各样的设计变种 metacircular interpreters like the sort you just saw. 17 00:00:52,570 --> 00:00:54,112 用元循环解释器是因为 Metacircular is because 18 00:00:54,720 --> 00:00:56,944 它们通过自己定义自己 they are defined in terms of themselves in such a way 19 00:00:56,976 --> 00:00:59,712 因此被解释的语言也包含了自己 that the language they interpret contains itself. 20 00:01:01,270 --> 00:01:03,872 这样的解释器是一种的媒介 Such interpreters are a convenient medium 21 00:01:03,888 --> 00:01:05,584 方便我们探索语言问题 for exploring language issues. 22 00:01:06,800 --> 00:01:09,440 如果你想添加一个新的FEATURE If you want to try adding a new feature, 23 00:01:10,512 --> 00:01:12,384 这就是小菜一碟 it's sort of a snap, it's easy, 24 00:01:12,736 --> 00:01:15,104 你只需要稍作修改 然后观察结果 you just do it and see what happens. 25 00:01:15,490 --> 00:01:17,200 在尝试了一会儿新语言后 You play with that language for a while you say, 26 00:01:17,240 --> 00:01:18,240 你可能觉得它不好 gee, I'm didn't like that, 27 00:01:18,528 --> 00:01:19,470 就把它扔到一边去了 you throw it away. 28 00:01:20,960 --> 00:01:23,552 或者你也想研究 Or you might want to see what 29 00:01:23,648 --> 00:01:27,376 不同绑定策略的差异 the difference is if you'd make a slight difference in the binding strategy, 30 00:01:28,816 --> 00:01:31,904 或者是一些更复杂的东西 or some more complicated things that might occur. 31 00:01:33,720 --> 00:01:35,488 事实上 这些元循环解释器 In fact, these metacircular interpreters 32 00:01:36,170 --> 00:01:37,888 非常适合作为交换媒介 are an excellent medium for people 33 00:01:38,208 --> 00:01:42,560 用于承载人们关于语言设计想法 exchanging ideas about language design, 34 00:01:43,984 --> 00:01:45,744 因为它们易于理解 because they're pretty easy to understand, 35 00:01:46,288 --> 00:01:48,464 它们短小、紧凑而且简洁 and they're short, and compact, and simple. 36 00:01:49,328 --> 00:01:50,800 如果我有一些点子 If I have some idea 37 00:01:51,536 --> 00:01:53,776 想让其它人评论一下 that I want somebody to criticize 38 00:01:54,256 --> 00:01:58,320 比如Indiana大学的Dan Friedman教授 like say, Dan Friedman at Indiana, 39 00:01:59,050 --> 00:02:02,000 我就编写一个小型元循环解释器 I'd write a little metacircular interpreter 40 00:02:02,560 --> 00:02:03,792 然后给他发一封电子邮件 send him some network mail 41 00:02:04,656 --> 00:02:05,450 并附上解释器 with this interpreter in it. 42 00:02:05,450 --> 00:02:07,904 他就可以在计算机上安装并运行 He could whip it up on his machine and play with it 43 00:02:07,920 --> 00:02:09,824 可能他会觉得这个设计并不好 and say, that's no good. 44 00:02:11,940 --> 00:02:13,104 然后他会给我回一封邮件 And then send it back to me and say, 45 00:02:13,136 --> 00:02:14,830 “为什么不试试这个 这个更好一点” well, why don't you try this one, it's a little better. 46 00:02:16,880 --> 00:02:19,360 所以我将会讲一些这方面的技术 So I want to show you some of that technology. 47 00:02:20,160 --> 00:02:24,208 因为在设计你自己的特定用途语言时 See, because, really, it's the essential, simple technology 48 00:02:24,720 --> 00:02:28,688 这种简单的技术非常重要 for getting started in designing your own languages for particular purposes. 49 00:02:30,790 --> 00:02:32,080 我们试着先在Lisp中 Let's start by adding 50 00:02:32,512 --> 00:02:34,210 添加一个非常简单的FEATURE a very simple feature to a Lisp. 51 00:02:40,640 --> 00:02:44,370 在这之前 我先来谈谈FEATURE吧 Now, one thing I want to tell you about is features, before I start. 52 00:02:49,560 --> 00:02:52,176 很多语言添加了大量的FEATURE There are many languages that have made a mess of themselves 53 00:02:53,056 --> 00:02:54,912 把它们本身搞得混乱不堪 by adding huge numbers of features. 54 00:02:56,864 --> 00:02:58,384 计算机科学家有一个笑话 Computer scientists have a joke 55 00:02:59,280 --> 00:03:02,520 “这不是BUG 这是FEATURE” about bugs that transform it to features all the time. 56 00:03:05,030 --> 00:03:06,464 而我宁愿认为 But I like to think of it is that 57 00:03:08,912 --> 00:03:11,440 很多系统都在遭受着“功能蔓延”的影响 many systems suffer from what's called creeping featurism. 58 00:03:12,820 --> 00:03:13,440 比方说 Which is that 59 00:03:14,944 --> 00:03:18,160 George希望系统中有某个FEATURE George has a pet feature he'd like in the system, 60 00:03:18,720 --> 00:03:19,360 他就加了进来 so he adds it. 61 00:03:20,170 --> 00:03:22,144 Harry也想着 And then Harry says, go says 62 00:03:22,176 --> 00:03:24,208 这个系统现在也不是我喜欢的那个了 gee, this system is no longer what exactly I like, 63 00:03:24,240 --> 00:03:25,920 然后加入了自己最喜欢的FEATURE so I'm going to add my favorite feature. 64 00:03:26,640 --> 00:03:30,240 Jim也这样做 And then Jim adds his favorite feature. 65 00:03:30,832 --> 00:03:31,792 一段时间过后 And, after a while, 66 00:03:31,808 --> 00:03:34,816 操作手册就多达500页 the thing has a manual 500 pages long 67 00:03:35,152 --> 00:03:36,512 以至于没人能看得懂 that no one can understand. 68 00:03:37,790 --> 00:03:39,328 有时候也可能只是 And sometimes it's the same person 69 00:03:39,904 --> 00:03:41,376 同一个人在添加FEATURE who writes all of these features 70 00:03:41,392 --> 00:03:43,232 也会导致同样糟糕的结果 and produces this terribly complicated thing. 71 00:03:44,140 --> 00:03:46,096 很多情况下 比如编辑器 In some cases, like editors, 72 00:03:47,376 --> 00:03:49,120 具有很多FEATURE就很合理 it's sort of reasonable to have lots of features, 73 00:03:50,920 --> 00:03:52,656 因为你想要能够完成 because there are a lot of things you want to be able to do 74 00:03:52,688 --> 00:03:53,760 各种不同的事情 and many of them arbitrary. 75 00:03:56,112 --> 00:03:57,296 但对计算机语言来说 But in computer languages, 76 00:03:57,850 --> 00:03:58,912 我认为太多的FEATURE I think it's a disaster 77 00:04:00,016 --> 00:04:01,290 是一个灾难 to have too much stuff in them. 78 00:04:04,032 --> 00:04:08,000 另外 系统也可能变成某种“尖叫的怪物” The other alternative you get into is something called feeping creaturism, 79 00:04:09,520 --> 00:04:11,392 假设你有一个盒子 which is where you have a box 80 00:04:11,808 --> 00:04:15,290 它有一个鼠标和花哨的显示器 which has a display, a fancy display, and a mouse, 81 00:04:15,952 --> 00:04:20,048 这些花哨的IO带来了各种各样的复杂性 and there is all sorts of complexity associated with all this fancy IO. 82 00:04:21,010 --> 00:04:22,800 你的程序语言就变成了 And your computer language becomes 83 00:04:23,344 --> 00:04:25,376 阴暗无用的小玩意儿 a dismal, little, tiny thing that barely works 84 00:04:25,408 --> 00:04:27,904 这是由计算机上的视窗系统进行的 because of all the swapping, and disk twitching, and so on, 85 00:04:28,096 --> 00:04:29,360 内存换页和磁盘抖动所导致的 caused by your Window system. 86 00:04:30,080 --> 00:04:31,824 每当你使用计算机的时候 And every time you go near the computer, 87 00:04:31,936 --> 00:04:33,456 鼠标处理进程就会唤醒 the mouse process wakes up and says, 88 00:04:33,850 --> 00:04:35,950 你有什么事情要我做的吗? gee do you have something for me to do, 89 00:04:36,144 --> 00:04:37,232 然后又回去休眠 and then it goes back to sleep. 90 00:04:37,440 --> 00:04:39,440 如果你的胳膊肘不小心碰到了鼠标 And if you accidentally push mouse with you elbow, 91 00:04:39,616 --> 00:04:42,320 一大堆烟雾就会从你的电脑出来 类似于这样 a big puff of smoke comes out of your computer and things like that. 92 00:04:42,940 --> 00:04:45,296 这就是由于添加FEATURE So two ways to disastrously 93 00:04:45,552 --> 00:04:47,216 导致系统不能用的两种典型情况 destroy a system by adding features. 94 00:04:47,500 --> 00:04:49,730 现在我们要添加的是 一个非常简单的FEATURE But try right now to add a little, simple feature. 95 00:04:52,608 --> 00:04:53,776 这个FEATURE非常好 This actually is a good one, 96 00:04:53,856 --> 00:04:56,176 事实上 Lisp中就有这个FEATURE and in fact, real Lisps have it. 97 00:04:57,250 --> 00:04:58,176 我们都知道 As you've seen, 98 00:04:59,296 --> 00:05:03,136 像+、*这样的过程 there are procedures like plus and times 99 00:05:03,376 --> 00:05:04,896 可以接受不定数目的参数 that take any number of arguments. 100 00:05:05,430 --> 00:05:06,448 因此我们就可以写 So we can write things 101 00:05:06,576 --> 00:05:10,944 (+ (* A X X) like the sum of the product of a and x and x, 102 00:05:12,096 --> 00:05:16,992 (* B X) C) and the product of b and x and c. 103 00:05:17,540 --> 00:05:18,688 这里可以看到 As you can see here, 104 00:05:18,928 --> 00:05:21,760 +有两到三个参数 addition takes three arguments or two arguments, 105 00:05:22,304 --> 00:05:24,816 *也有两到三个参数 multiplication takes two arguments or three arguments, 106 00:05:25,080 --> 00:05:26,768 不管多少个参数 taking numbers of arguments 107 00:05:26,784 --> 00:05:28,490 都应该用同样的方式对待 all of which are to be treated in the same way. 108 00:05:30,000 --> 00:05:32,176 支持不定数目的参数 This is a valuable thing, 109 00:05:32,288 --> 00:05:34,010 这一点非常有用 indefinite numbers of arguments. 110 00:05:34,960 --> 00:05:38,416 而我上节课所讲的Lisp求值器 Yet the particular Lisp system that I show you 111 00:05:39,232 --> 00:05:41,856 只能处理固定数目的参数 is one where the numbers of arguments is fixed, 112 00:05:42,620 --> 00:05:45,280 因为我要用BIND过程中的PAIR-UP过程 because I had to match the arguments against the formal parameters 113 00:05:45,632 --> 00:05:47,920 让形式参数与实际参数一一对应 in the binder, where there's a pairup. 114 00:05:50,810 --> 00:05:53,808 假如我想能够定义像这样的过程 Well, I'd like to be able to define new procedures like this 115 00:05:54,896 --> 00:05:57,328 它们可以接收任意个数的参数 that can have any number of arguments. 116 00:05:58,752 --> 00:06:00,400 这个问题有好几部分 Well there's several parts to this problem. 117 00:06:01,344 --> 00:06:04,816 首先是挑选合适的语法描述 The first part is coming up with the syntactic specification, 118 00:06:05,720 --> 00:06:11,216 我们需要能够标注额外的参数 some way of notating the additional arguments, 119 00:06:12,176 --> 00:06:13,632 标注那些不知道个数的参数 of which you don't know how many there are. 120 00:06:15,480 --> 00:06:16,624 另外就是 And then there's the other thing, 121 00:06:17,104 --> 00:06:18,704 一旦我们标注出来后 which is once we've notated it, 122 00:06:19,072 --> 00:06:20,784 我们怎样解释这些个记号 how are we going to interpret that notation 123 00:06:21,740 --> 00:06:23,100 才能得到 so as to do the right thing, 124 00:06:23,856 --> 00:06:25,376 正确的结果呢? whatever the right thing is? 125 00:06:26,980 --> 00:06:28,800 让我们来考虑一种 So let's consider an example of a sort of thing 126 00:06:28,848 --> 00:06:30,272 我们可能会遇到的情况 we might want to be able to do. 127 00:06:33,070 --> 00:06:34,512 比如说 So an example might be, 128 00:06:35,424 --> 00:06:37,344 我想要定义这样的一个过程 that I might want to be able to define a procedure 129 00:06:37,952 --> 00:06:41,360 它有一个必选参数X which is a procedure of one required argument x 130 00:06:42,200 --> 00:06:45,264 还有个可选参数 -- 或者说一堆参数 and a non-required -- bunch of arguments, 131 00:06:45,280 --> 00:06:47,230 我不知道它们的数目 就记作Y吧 I don't know how many there are, called y. 132 00:06:49,090 --> 00:06:50,368 X是必选的 So x is required, 133 00:06:55,888 --> 00:06:57,440 然而有很多参数Y and there are many y's, 134 00:06:59,536 --> 00:07:05,990 这些参数形成的表 -- 我就记作Y many arguments-- y will be the list of them. 135 00:07:14,480 --> 00:07:16,064 写好了参数表 Now, with such a thing, 136 00:07:16,096 --> 00:07:17,680 我现在要这样定义过程体 we might be able to say something like, 137 00:07:19,024 --> 00:07:21,984 我要对每一个元素都做同样的处理 map-- I'm going to do something to every one-- 138 00:07:22,520 --> 00:07:25,760 (MAP (LAMBDA (U) of that procedure of one argument u, 139 00:07:27,000 --> 00:07:34,544 (* X U)) Y) which multiplies x by u, and we'll apply that to y. 140 00:07:36,890 --> 00:07:38,048 这里 我用了一个“点号” I've used a dot here 141 00:07:38,592 --> 00:07:41,312 来表明点号后面的东西 to indicate that the thing after this 142 00:07:42,192 --> 00:07:44,304 是剩下的所有参数构成的表 is a list of all the rest of the arguments. 143 00:07:46,300 --> 00:07:48,128 这就是一个语法规范 I'm making a syntactic specification. 144 00:07:53,320 --> 00:07:54,640 为什么这样来写呢? Now, what this depends upon, 145 00:07:55,712 --> 00:07:58,064 这种语法规范之所以合理 the reason why this is sort of a reasonable thing to do, 146 00:07:59,776 --> 00:08:01,968 是因为Lisp的源码读取器 is because this happens to be a syntax 147 00:08:02,000 --> 00:08:03,600 刚好使用这种语法 that's used in the Lisp reader 148 00:08:04,416 --> 00:08:07,152 来表示序对 for representing conses. 149 00:08:08,944 --> 00:08:11,080 我们之前没有介绍过 We've never introduced that before.You never see. 150 00:08:11,080 --> 00:08:12,784 你在自己尝试的时候可能遇到过 You may have seen when playing with the system 151 00:08:13,040 --> 00:08:14,624 当你调用(CONS X Y)时 if you cons two things together, you get the 152 00:08:14,896 --> 00:08:18,128 你会得到 X . Y first, space, dot, the second, space-- 153 00:08:19,790 --> 00:08:22,832 准确来说是(X . Y) the first, space, dot, space, the second 154 00:08:23,088 --> 00:08:24,640 两边还有括号 with parentheses around the whole thing. 155 00:08:26,980 --> 00:08:28,160 举例来说吧 So that, for example, 156 00:08:28,970 --> 00:08:35,040 这里的(X . Y)对应着一个序对 this x dot y corresponds to a pair, 157 00:08:36,336 --> 00:08:39,296 X是CAR部分 Y是CDR部分 which has got an x in it and a y in it. 158 00:08:41,488 --> 00:08:43,984 你们目前为止见过的其它记号 The other notations that you've seen so far 159 00:08:44,944 --> 00:08:46,672 是像 are things like, like 160 00:08:46,920 --> 00:08:55,248 (LAMBDA (X Y Z) ...)这样的 a procedure of arguments x and y and z which do things 161 00:08:55,710 --> 00:08:57,630 它们则是像这样的 and that looks like-- 162 00:09:02,000 --> 00:09:03,616 就拿形式参数表来说 Just looking at the bound variable list, 163 00:09:04,224 --> 00:09:05,296 它实际上是这样 it looks like this, 164 00:09:09,936 --> 00:09:17,328 这里分别是 X、Y、Z和空表 x, y, z, and the empty thing. 165 00:09:18,280 --> 00:09:21,088 如果我有一个想要与之匹配的参数表的话 If I have a list of arguments I wish to match this against, 166 00:09:22,608 --> 00:09:25,600 假设实际参数表是'(1 2 3) I have a list of arguments one, two, three, 167 00:09:25,872 --> 00:09:27,264 我想把它们和形参相匹配 I want to match these against. 168 00:09:28,384 --> 00:09:37,104 所以这里 可能有个三个元素的表 OK? So I might have here a list of three things, 169 00:09:42,448 --> 00:09:46,944 分别是1、2、3 one, two, three. 170 00:09:48,990 --> 00:09:53,168 用'(1 2 3)来匹配'(X Y Z) And I want to match x, y, z against one, two, three. 171 00:09:54,220 --> 00:09:56,288 很显然1和X相匹配 Well, it's clear that the one matches the x, 172 00:09:56,320 --> 00:09:58,016 因为我可以顺着这个结构来 because I can just sort of follow the structure, 173 00:09:58,864 --> 00:10:01,568 2和Y相匹配 and the two matches the y, 174 00:10:02,464 --> 00:10:04,048 3和Z相匹配 and the three matches the z. 175 00:10:05,480 --> 00:10:09,536 假设我现在要把这个(X . Y) But now, supposing I were to compare this x dot y. 176 00:10:09,552 --> 00:10:11,840 这个是(X . Y) this is x dot y-- 177 00:10:12,512 --> 00:10:16,912 如果我想把它跟'(1 2 3)相匹配的话 supposing I compare that with a list of three arguments, one, two, three. 178 00:10:19,088 --> 00:10:20,000 我们再来看 Let's look at that again. 179 00:10:28,000 --> 00:10:30,320 这里是1、2、3 One, two, three-- 180 00:10:30,864 --> 00:10:32,880 我可以沿着这里遍历 Well, I can walk along here 181 00:10:32,992 --> 00:10:35,504 会发现 1和X相匹配 and say, oh yes, x matches the one, 182 00:10:37,568 --> 00:10:41,840 而Y和表'(2 3)相匹配 Ah, the y matches the list, which is two and three. 183 00:10:43,740 --> 00:10:46,224 所以这里选用的表示法 So the notation I'm choosing here 184 00:10:46,416 --> 00:10:50,160 对于Lisp来说是非常自然的 is one that's very natural for Lisp system. 185 00:10:52,660 --> 00:10:54,144 所以我就选择用这个记号 But I'm going to choose this as a notation 186 00:10:54,176 --> 00:10:55,808 来表示数目不定的参数 for representing a bunch of arguments. 187 00:10:58,290 --> 00:11:00,096 还有一种可能性 Now, there's an alternative possibility. 188 00:11:00,592 --> 00:11:02,784 如果我不是特别想命名某个参数 If I don't want to take one special out, 189 00:11:03,008 --> 00:11:05,008 或者是命名某两个参数之类的 or two special ones out or something like that, 190 00:11:06,544 --> 00:11:07,568 如果我不想那样的话 if I don't want to do that, 191 00:11:08,780 --> 00:11:10,448 如果我想像+那样 if I want to talk about 192 00:11:10,528 --> 00:11:12,520 一下子引用所有的参数 just the list of all the arguments like in addition, 193 00:11:13,880 --> 00:11:17,960 那么我就应该把参数表写成 well then the argument list I'm going to choose to be 194 00:11:18,200 --> 00:11:23,456 (LAMBDA X ...) that procedure of all the arguments x, which does something with x 195 00:11:25,140 --> 00:11:26,304 举例来说 And which, for example, 196 00:11:26,816 --> 00:11:27,968 如果我定义一个过程 if I take the procedure, 197 00:11:28,064 --> 00:11:30,448 它把接收所有的参数 which takes all the arguments x 198 00:11:31,120 --> 00:11:32,704 然后返回一个由它们组成的表X and returned the list of them, 199 00:11:34,810 --> 00:11:38,672 返回的结果就是过程的参数表 明白吗? OK? That's list. That's the procedure list. 200 00:11:45,850 --> 00:11:46,672 这又是怎么回事呢? How does this work? 201 00:11:46,840 --> 00:11:50,064 实际上 无论我们的参数表是何种形式 Well, indeed what I had as the bound variable list in this case, 202 00:11:50,600 --> 00:11:51,456 无论是何种形式 whatever it is, 203 00:11:51,616 --> 00:11:53,680 都要与实际参数表相匹配 is being matched against a list of arguments. 204 00:11:55,140 --> 00:11:57,145 现在 这个符号就是所有的实际参数了 This symbol now is all of the arguments. 205 00:12:01,490 --> 00:12:05,136 所以 我选择使用这个特定的语法规范 And so this is the choice I'm making for a particular syntactic specification, 206 00:12:05,648 --> 00:12:07,632 来描述那些 for the description of procedures 207 00:12:08,048 --> 00:12:10,560 接收不定数目参数的过程 which take indefinite numbers of arguments. 208 00:12:13,456 --> 00:12:14,608 一共有两种情况 There are two cases of it, 209 00:12:15,400 --> 00:12:16,350 上面这种和下面这种 this one and this one. 210 00:12:17,440 --> 00:12:18,368 这两种都 -- And none of this. 211 00:12:18,420 --> 00:12:20,112 当你们在制定语法规范时 When you make syntactic specifications, 212 00:12:20,448 --> 00:12:22,544 千万注意不要有歧义 it's important that it's unambiguous, 213 00:12:23,568 --> 00:12:27,360 就比如说这里的两种情况 that neither of these can be confused with 214 00:12:27,664 --> 00:12:31,200 就不要与这里我们已有的这种混淆了 a representation we already have, this one. 215 00:12:33,610 --> 00:12:35,824 我总是可以区分出 I can always tell whether I have 216 00:12:36,544 --> 00:12:39,808 过程的形式参数 a fixed number of explicitly named arguments 217 00:12:40,288 --> 00:12:41,760 是数目固定的具名参数 made by these formal parameters, 218 00:12:42,640 --> 00:12:43,130 还是 or 219 00:12:43,280 --> 00:12:45,360 既有数目固定的具名参数 a fixed number of named formal parameters 220 00:12:45,440 --> 00:12:48,016 又跟着数目可变的参数 followed by a thing which picks up all the rest of them, 221 00:12:49,424 --> 00:12:53,520 又或者是所有参数组成的表 or a list of all the arguments 222 00:12:53,680 --> 00:12:56,528 这个表会和这里的形式参数X相匹配 which will be matched against this particular formal parameter called x, 223 00:12:56,992 --> 00:12:58,848 我都是可以从语法上区分它们 because these are syntactically distinguishable. 224 00:13:02,250 --> 00:13:04,624 由于语言中存在语法歧义 Many languages make terrible errors in that form 225 00:13:05,040 --> 00:13:08,032 整个待解释的程序被错误地分段 where whole segments of interpretation are cut off, 226 00:13:08,640 --> 00:13:13,920 从而导致了可怕的错误 because there are syntactic ambiguities in the language. 227 00:13:14,560 --> 00:13:16,672 类Algol语言中就有些传统问题 They are the traditional problems with ALGOL like languages 228 00:13:16,672 --> 00:13:23,472 就跟谓词部分的嵌套IF语句有关 having to do with the nesting of ifs in the predicate part. 229 00:13:25,060 --> 00:13:25,936 总之 In any case, 230 00:13:27,520 --> 00:13:29,440 我现在已经把语法告诉你们了 now, so I've told you about the syntax, 231 00:13:30,272 --> 00:13:34,832 我们要怎么来处理它的语义呢? now, what are we going to do about the semantics of this? 232 00:13:35,250 --> 00:13:36,112 我们如何来解释它? How do we interpret it? 233 00:13:36,590 --> 00:13:37,968 其实很简单 Well this is just super easy. 234 00:13:38,440 --> 00:13:42,576 我修改一下元循环解释器就行 I'm going to modify the metacircular interpreter to do it. 235 00:13:43,712 --> 00:13:44,768 只需修改一行 And that's a one liner. 236 00:13:45,984 --> 00:13:46,576 在这里 There it is. 237 00:13:47,536 --> 00:13:49,560 我修改一下PAIR-UP过程 I'm changing the way you pair things up. 238 00:13:50,816 --> 00:13:54,192 这里的PAIR-UP过程把 OK? Here we have procedure that pairs -- 239 00:13:56,760 --> 00:14:02,032 这是从上节课的元循环求值器中 Here's the procedure that pairs the 240 00:14:04,810 --> 00:14:09,568 摘录过来的PAIR-UP过程 the variables, the formal parameters, with the arguments that were passed 241 00:14:12,160 --> 00:14:16,688 它把形式参数与传递过来的实际参数匹配起来 from the last description of the metacircular interpreter. 242 00:14:18,960 --> 00:14:21,936 大部分地方都和以前一样 And here's some things that are the same as they were before. 243 00:14:22,670 --> 00:14:23,232 也就是说 In other words, 244 00:14:23,312 --> 00:14:25,072 如果变量表为空 if the list of variables is empty, 245 00:14:25,520 --> 00:14:27,312 并且值表也为空 then if the list of values is empty, 246 00:14:27,456 --> 00:14:29,616 就返回空表 then I have an empty list. 247 00:14:31,050 --> 00:14:33,008 否则就是参数过多 Otherwise, I have too many arguments, 248 00:14:33,980 --> 00:14:40,192 如果变量表为空 但值表非空 If I have, that is if I have empty variables but not empty values. 249 00:14:41,580 --> 00:14:44,000 如果值表为空 If I have empty values, 250 00:14:44,960 --> 00:14:47,472 但是变量表又非空 OK? But the variables are not empty, 251 00:14:47,488 --> 00:14:48,560 那就是实际参数少了 that I have too few arguments. 252 00:14:48,944 --> 00:14:51,312 然而如果我有一个变量是符号的话 However if I have a variable -- the variables are a symbol-- 253 00:14:55,536 --> 00:14:56,496 这就有意思了 interesting case-- 254 00:14:58,300 --> 00:15:04,400 那么 我就认为遇到了特殊情况 then, what I should do is say, oh yes, this is the special case 255 00:15:04,592 --> 00:15:06,510 也就是尾部分为符号的情况 that I have a symbolic tail. 256 00:15:08,350 --> 00:15:14,112 情况就像这里的一样 OK. I have here a thing just like we looked over here. 257 00:15:14,900 --> 00:15:17,872 这个尾部分就是一个符号Y This is a tail which is a symbol, y. 258 00:15:18,630 --> 00:15:19,392 它不是NIL It's not a nil. 259 00:15:20,730 --> 00:15:21,728 不是个空表 It's not the empty list. 260 00:15:23,264 --> 00:15:25,600 而这个一开始就是个符号 Here's a symbolic tail that is just the very beginning of the tail. 261 00:15:25,984 --> 00:15:26,816 就没有别的东西了 There is nothing else. 262 00:15:27,790 --> 00:15:28,720 这种情况下 In that case, 263 00:15:29,960 --> 00:15:37,200 我就用这个符号去匹配所有的值 I wish to match that variable with all the values 264 00:15:38,032 --> 00:15:42,520 并把它们添加到要返回的结果中 and add that to the pairing that I'm making. 265 00:15:44,500 --> 00:15:46,912 否则的话 我就像正常情况那样 Otherwise, I go through the normal arrangement 266 00:15:47,152 --> 00:15:48,528 来创建所有的配对 of making up the whole pairing. 267 00:15:52,020 --> 00:15:53,824 我认为这很容易理解 I suppose that's very simple. 268 00:15:54,510 --> 00:15:55,840 就是这些 And that's all there is to it. 269 00:15:57,080 --> 00:15:58,330 现在 答疑时间 And now I'll answer some questions. 270 00:16:02,620 --> 00:16:05,056 有什么问题吗? The first one-- Are there any questions? 271 00:16:06,600 --> 00:16:06,944 你说 Yes? 272 00:16:07,376 --> 00:16:09,920 学生:你能再解释一下第三种形式吗? AUDIENCE: Could you explain that third form? 273 00:16:09,980 --> 00:16:12,128 教授:第三种?这个? PROFESSOR: Third form. This one? OK. 274 00:16:12,590 --> 00:16:14,272 或许你用表结构来思考 Well, maybe we should look at the thing 275 00:16:14,300 --> 00:16:16,240 会更容易理解一些 as a piece of list structure. 276 00:16:18,570 --> 00:16:22,736 这是一个过程 包含一个LAMBDA This is a procedure which contains a lambda. 277 00:16:25,856 --> 00:16:29,616 我画出来的这个表结构就代表上面的这个 I'm just looking at the list structure which represents this. 278 00:16:31,264 --> 00:16:32,448 这里是X Here's x. 279 00:16:32,730 --> 00:16:33,980 这些是我们的符号 These are our symbols. 280 00:16:37,410 --> 00:16:39,580 过程体就是X而已 And then the body is nothing but x. 281 00:16:44,840 --> 00:16:48,752 如果我需要这个过程的形式参数表 If I were looking for the bound variable list part of this procedure, 282 00:16:50,096 --> 00:16:51,584 我就取它的CADR部分 I would go looking at the CADR, 283 00:16:52,144 --> 00:16:53,168 我会得到一个符号 and I'd find a symbol. 284 00:16:54,010 --> 00:16:57,168 所以我们的匹配器 -- 也就是我给你们展示的PAIR-UP过程 So the, matcher, which is this pairup thing I just showed you, 285 00:16:58,240 --> 00:17:00,448 就会把这个符号对象 is going to be matching a symbolic object 286 00:17:01,568 --> 00:17:04,400 跟我们传递的实际参数表相匹配了 against a list of arguments that were passed. 287 00:17:05,760 --> 00:17:09,559 这个符号与实际参数表相绑定 And it will bind that symbol to the list of arguments. 288 00:17:11,376 --> 00:17:16,480 而在这个例子中 如果我去取它的话 The -- In this case, if I'm looking for it, 289 00:17:16,928 --> 00:17:20,976 匹配器就会把它与变量表的这个部分相匹配 the match will be against this in the bound variable list position. 290 00:17:24,140 --> 00:17:26,144 如果一个过程只是 Now, if what this does is 291 00:17:26,170 --> 00:17:29,130 直接返回得到的参数表的话 返回的就是一个表 it gets a list of arguments and returns it, that's list 292 00:17:30,400 --> 00:17:31,392 这个过程就是这样的 That's the procedure is. 293 00:17:34,510 --> 00:17:35,488 好吧 谢谢大家 Oh well, thank you. 294 00:17:36,140 --> 00:17:37,280 大家休息一下吧 Let's take a break. 295 00:17:37,830 --> 00:17:55,360 [音乐] [JESU, JOY OF MAN'S DESIRING] 296 00:17:55,360 --> 00:17:59,024 《计算机程序的构造和解释》 297 00:18:03,530 --> 00:18:07,568 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 298 00:18:07,560 --> 00:18:11,696 《计算机程序的构造和解释》 299 00:18:12,256 --> 00:18:16,110 元循环求值器 II 300 00:18:20,864 --> 00:18:21,616 教授:我们接着来看 PROFESSOR: Well let's see. 301 00:18:23,260 --> 00:18:26,320 现在 我将介绍一种相当重要的变种 Now, I'm going to tell you about a rather more substantial variation 302 00:18:27,456 --> 00:18:31,040 这种变体非常有名 one that's a famous variation 303 00:18:31,600 --> 00:18:36,800 早期的很多Lisp都支持它 hat many early Lisps had. 304 00:18:38,256 --> 00:18:40,064 它被称为变量的动态绑定 It's called dynamic binding of variables. 305 00:18:41,770 --> 00:18:44,680 我们现在来研究一下它 And we'll investigate a little bit about that right now. 306 00:18:47,620 --> 00:18:50,160 我先来介绍一下是什么导致 I'm going to first introduce this by showing you the sort of thing 307 00:18:50,352 --> 00:18:52,368 人们产生这样的想法 that would make someone want this idea. 308 00:18:53,740 --> 00:18:55,232 然而我并不会直接点明原因 I'm not going to tell what it is yet, 309 00:18:55,408 --> 00:18:57,600 我来举一个例子 你们来感受一下 I'm going to show you why you might want it. 310 00:18:58,640 --> 00:18:59,936 假设 Suppose, for example, 311 00:19:00,750 --> 00:19:02,592 我们再来考察一下 we looked at the sum procedure again 312 00:19:05,024 --> 00:19:06,430 计算一系列数之和的SUM过程 for summing up a bunch of things. 313 00:19:08,140 --> 00:19:09,472 它的参数为 To be that procedure, 314 00:19:09,600 --> 00:19:10,784 计算当前项的TERM of a term, 315 00:19:13,040 --> 00:19:14,416 下界A lower bound, 316 00:19:15,240 --> 00:19:17,040 计算下一项索引的NEXT method of computing the next index, 317 00:19:17,248 --> 00:19:18,560 上界B and upper bound, 318 00:19:19,360 --> 00:19:20,160 过程体是 such that, 319 00:19:23,160 --> 00:19:26,940 如果A>B if a is greater than b 320 00:19:27,150 --> 00:19:28,640 那么结果就是0 then the result is 0, 321 00:19:30,240 --> 00:19:31,088 否则就是 otherwise, 322 00:19:33,680 --> 00:19:39,824 (+ (TERM A) it's the sum, of the term, procedure, applied to a 323 00:19:40,608 --> 00:19:44,240 (SUM TERM and the result of adding up, terms, 324 00:19:47,680 --> 00:19:52,640 (NEXT A) with the next a being the a, 325 00:20:00,300 --> 00:20:03,560 这个NEXT过程直接传递过去 the next procedure passed along, 326 00:20:06,400 --> 00:20:08,256 上界B也直接传递过去 and the upper bound being passed along. 327 00:20:14,510 --> 00:20:15,760 (闭合括号中) Blink, blink, blink-- 328 00:20:17,824 --> 00:20:21,450 当我使用SUM过程的时候 OK? Now, when I use this sum procedure, 329 00:20:21,968 --> 00:20:24,352 我可以像这样来用 I can use it, for example, like this. 330 00:20:25,450 --> 00:20:38,048 我们可以把SUM-POWERS过程定义为 We can define the sum of the powers to be, 331 00:20:38,080 --> 00:20:40,330 这个函数是用来计算Σ(X^N)的 for example, sum of a bunch of powers x to the n, 332 00:20:41,104 --> 00:20:45,936 它的参数有A、B以及N to be that procedure of a, b, and n-- 333 00:20:45,952 --> 00:20:47,696 分别指下界、上界以及指数 lower bound, the upper bound, and n-- 334 00:20:48,060 --> 00:20:53,344 它的定义是(SUM (LAMBDA (X) which is sum, of lambda of x, 335 00:20:53,600 --> 00:20:59,310 这个参数为X的过程计算(EXPT X N) the procedure of one argument x, which exponentiates x to the n, 336 00:21:02,190 --> 00:21:09,296 我们还要传递A、1+还有B with the a, the incrementer, and b, being passed along. 337 00:21:11,824 --> 00:21:15,760 因此 给定一系列X 我们计算Σ(X^N)的值 So we're adding up x to n, given an x. 338 00:21:16,144 --> 00:21:19,740 X从A到B取值 步长为1 x takes on values from a to b, incrementing by one. 339 00:21:22,940 --> 00:21:24,384 我也可以定义-- I can also write the-- 340 00:21:27,680 --> 00:21:28,200 好像这里有点问题 That's right. 341 00:21:29,780 --> 00:21:31,024 不好意思 Product, excuse me. 342 00:21:31,910 --> 00:21:33,360 这里应该是PRODUCT-POWERS The product of a bunch of powers. 343 00:21:38,080 --> 00:21:39,120 名字有点奇怪 It's a strange name. 344 00:21:40,020 --> 00:21:40,800 还是不改了 I'm going to leave it there. 345 00:21:41,960 --> 00:21:46,320 有点怪 就按原来的吧 Weird-- OK? I write up what I have. 346 00:21:49,344 --> 00:21:50,192 这回应该对了 I'm sure that's right. 347 00:21:51,376 --> 00:21:53,824 而PRODUCT-POWERS的定义则是 And if I want the product of a bunch of powers-- 348 00:21:58,416 --> 00:22:02,368 (意义不明) That was 12 brain cells, that double-take. 349 00:22:03,000 --> 00:22:06,816 我可以用像SUM一样的过程 I can for example use the procedure which is like sum, 350 00:22:06,816 --> 00:22:08,220 只不过是用来计算乘积的 which is for making products, 351 00:22:08,560 --> 00:22:11,056 但是很类似 就跟你们在那里见到的一样 but it's similar to that, that you've seen before. 352 00:22:11,450 --> 00:22:16,384 它也是一个三参数的过程 There's a procedure of three arguments again. 353 00:22:17,000 --> 00:22:25,424 求积的因数是通过构造而来 Which is the product of terms that are constructed, or factors in this case, 354 00:22:25,664 --> 00:22:31,600 也就是(PRODUCT (LAMBDA (X) (EXPT X N)) constructed from exponentiating x to the n, 355 00:22:34,432 --> 00:22:37,856 下界是A 步长为1 上界为B where I start with a, I increment, and I go to b. 356 00:22:41,530 --> 00:22:41,888 现在 Now, 357 00:22:46,832 --> 00:22:49,504 你可能马上就意识到一些问题 there's some sort of thing here that should disturb you immediately. 358 00:22:50,750 --> 00:22:52,016 它们看起来几乎一样 These look the same. 359 00:22:53,180 --> 00:22:55,200 为什么要重复写代码呢? Why am I writing this code so many times? 360 00:22:56,590 --> 00:22:59,728 现在就很像我们之前遇到的情况了 Here I am, in the same boat I've been in before. 361 00:23:01,008 --> 00:23:03,152 构建一个抽象不是更好吗? Right? Wouldn't it be nice to make an abstraction here? 362 00:23:03,810 --> 00:23:05,760 如何构建良好的抽象呢? What's an example of a good abstraction to make? 363 00:23:05,856 --> 00:23:07,552 我看到有一些完全相同的代码 Well, I see some codes that's identical. 364 00:23:08,470 --> 00:23:09,328 这有一段 Here's one, 365 00:23:09,984 --> 00:23:11,080 这是另一段 and here's another. 366 00:23:14,450 --> 00:23:16,224 所以我应该把它们提取出来 And so maybe I should be able to pull that out. 367 00:23:17,090 --> 00:23:19,232 我就会想 I should be able to say, oh yes, 368 00:23:20,512 --> 00:23:22,672 SUM-POWERS可以用 the sum of the powers could be written in terms of 369 00:23:22,880 --> 00:23:24,528 NTH-POWERS的过程来编写 something called the nth power procedure. 370 00:23:25,710 --> 00:23:27,408 假如有人想写一个 Imagine somebody wanted to write 371 00:23:27,744 --> 00:23:30,030 稍微不同的过程 就像这个一样 a slightly different procedure that looks like this. 372 00:23:37,630 --> 00:23:45,184 (DEFINE SUM-POWERS The sum powers to be a procedure 373 00:23:46,448 --> 00:23:48,460 (LAMBDA (A B N) of a, b, and n, 374 00:23:48,752 --> 00:23:52,272 (SUM (NTH-POWER which the result of summing up the nth power. 375 00:23:53,888 --> 00:23:55,424 我们调用过程NTH-POWER We're going to give a name to that idea, 376 00:23:58,352 --> 00:24:02,272 下界为A 步长为1 上界为B for starting at a, going by one, and ending at b. 377 00:24:05,744 --> 00:24:06,912 类似地 And similarly, 378 00:24:10,656 --> 00:24:12,768 我想用这种方式来重写PRODUCT-POWERS I might want to write the product powers this way, 379 00:24:12,896 --> 00:24:15,248 把求幂指数从这里抽象出来 abstracting out this idea. 380 00:24:16,270 --> 00:24:17,376 可以这样写 I might want this. 381 00:24:22,100 --> 00:24:23,024 (DEFINE PRODUCT-POWERS Product powers, 382 00:24:29,488 --> 00:24:34,944 (LAMBDA (A B N) to be a procedure of a, b, and n, 383 00:24:35,312 --> 00:24:42,336 (PRODUCT NTH-POWERS which is the product of the nth power operation 384 00:24:46,448 --> 00:24:50,304 A 1+ B))) on a with the incrementation and b being 385 00:24:53,504 --> 00:24:57,568 把NTH-POWER的结果作为PRODUCT的参数 being my arguments for the analogous-thing product. 386 00:24:58,380 --> 00:25:00,240 我们还需要定义 And I'd like to be able to define, 387 00:25:02,048 --> 00:25:03,888 还需要定义过程NTH-POWERS I'd like to be able to define nth power-- 388 00:25:04,896 --> 00:25:05,930 我把它写在这边 I'll put it over here. 389 00:25:12,224 --> 00:25:12,990 写在上面 I'll put it at the top. 390 00:25:25,410 --> 00:25:29,040 它是一个参数为X的过程 --to be, in fact, my procedure of one argument x 391 00:25:29,600 --> 00:25:34,560 计算(EXPT X N) which is the result of exponentiating x to the n. 392 00:25:35,936 --> 00:25:36,960 但是我遇到一个问题 But I have a problem. 393 00:25:38,640 --> 00:25:39,936 我们使用的环境模型 My environment model, 394 00:25:40,576 --> 00:25:43,232 我们用来解释 that is my means of interpretation 395 00:25:44,000 --> 00:25:45,952 目前所定义的语言的这种手段 of interpretation for the language that we've defined so far, 396 00:25:46,272 --> 00:25:48,810 并没有给我说明这个N的值 does not give me a meaning for this n. 397 00:25:52,768 --> 00:25:59,264 因为 正如大家所知 Because, as you know, the, as you know 398 00:26:00,768 --> 00:26:04,256 在这个过程中 N是自由变量 this n is free in this procedure. 399 00:26:06,410 --> 00:26:07,984 环境模型告诉我们 The environment model tells us 400 00:26:08,608 --> 00:26:10,208 自由变量的值 that the meaning of a free variable 401 00:26:11,216 --> 00:26:14,992 取决于过程被定义时所在的环境 is determined in the environment in which this procedure is defined. 402 00:26:16,640 --> 00:26:17,472 在我编写它们的时候 In a way I have written it, 403 00:26:17,488 --> 00:26:19,840 就假设它们已经在黑板上被定义了 assuming these things are defined on the blackboard as is, 404 00:26:21,648 --> 00:26:23,632 NTH-POWER是定义在全局环境下的 this is defined in the global environment, 405 00:26:24,064 --> 00:26:25,152 其中没有N的定义 where there is no n. 406 00:26:25,936 --> 00:26:27,632 因此 N是未绑定的变量 Therefore, n is unbound variable. 407 00:26:28,720 --> 00:26:31,664 但对我们来说 But it's perfectly clear, to most of us, 408 00:26:32,608 --> 00:26:36,320 我们明确希望它是这里和这里的N that we would like it to be this n and this n. 409 00:26:38,990 --> 00:26:42,672 另外一方面 On the other hand, OK, it would be nice. 410 00:26:42,840 --> 00:26:44,288 当然我们要十分小心地确保 Certainly we've got to be careful here 411 00:26:44,560 --> 00:26:46,064 这里的N是这里的N of keeping this to be this, 412 00:26:48,960 --> 00:26:52,832 还有这里的这个 要跟这里的一致 and this one over here, wherever it is to be this one. 413 00:26:57,390 --> 00:26:59,744 这种想法造就了 Well, the desire to make this work 414 00:27:00,672 --> 00:27:02,720 一个非常著名的BUG has led to a very famous bug. 415 00:27:04,656 --> 00:27:06,048 我来细说下这个BUG I'll tell you about the famous bug. 416 00:27:07,152 --> 00:27:09,408 请看这张幻灯片 Look at this slide. 417 00:27:10,660 --> 00:27:12,704 这种想法被称作“动态绑定” This is an idea called dynamic binding. 418 00:27:13,990 --> 00:27:16,912 在这种情况下 自由变量不再被 Where, instead of the free variable being interpreted 419 00:27:17,760 --> 00:27:21,232 定义过程时的环境所解释 in the environment of definition of a procedure, 420 00:27:22,400 --> 00:27:25,168 这种情况下 自由变量的值 the free variable is interpreted as having its value 421 00:27:25,440 --> 00:27:29,312 就像是存储在过程调用者的环境中一样 in the environment of the caller of the procedure. 422 00:27:31,850 --> 00:27:34,848 所以在这个系统中 So what you have is a system 423 00:27:34,860 --> 00:27:39,680 你需要不断地搜索调用过程的调用者的环境 where you search up the chain of callers of a particular procedure, 424 00:27:40,432 --> 00:27:42,656 当然 在本例中 and, of course, in this case, 425 00:27:42,840 --> 00:27:44,304 无论NTH-POWER在何处定义 since nth power is called 426 00:27:44,336 --> 00:27:45,980 它都是在PRODUCT过程中被调用的 from inside product whatever it is-- 427 00:27:46,416 --> 00:27:48,688 我就需要在SUM过程中再编写一个类似的过程 I had to write our own sum which is the analogous procedure-- 428 00:27:50,512 --> 00:27:54,928 而PRODUCT又是被PRODUCT-POWERS所调用 and product is presumably called from product powers, 429 00:27:55,136 --> 00:27:56,144 就是你们在这里看到的 as you see over here, 430 00:27:56,832 --> 00:27:59,376 由于PRODUCT-POWERS过程绑定了变量N then since product powers bind with variable n , 431 00:28:00,096 --> 00:28:04,096 因此NTH-POWER中的N会从这个链中派生出来 then nth powers n would be derived through that chain. 432 00:28:08,140 --> 00:28:09,648 相似地 这个N Similarly, this n, 433 00:28:10,112 --> 00:28:12,016 NTH-POWER中的N在这种情况下 the nth power in n in this case, 434 00:28:12,320 --> 00:28:15,800 可能是来自于这里SUM过程的调用 would come through nth power here being called from inside sum. 435 00:28:15,800 --> 00:28:18,272 你们可以从这里看到 它在SUM内部被调用 You can see it being called from inside sum here. 436 00:28:20,736 --> 00:28:21,696 对应这里的TERM It's called term here. 437 00:28:22,900 --> 00:28:25,728 而SUM是在SUM-POWERS的内部被调用 But sum was called from inside of sum powers, 438 00:28:26,944 --> 00:28:27,968 后者绑定了N which bound n. 439 00:28:28,930 --> 00:28:30,656 因此这里就有一个N Therefore, there would be an n available 440 00:28:32,752 --> 00:28:36,112 可供NTH-POWER中的N取值 that n to get it's value from. 441 00:28:37,950 --> 00:28:39,248 这就是动态 -- This is called dynamic -- 442 00:28:39,280 --> 00:28:43,104 这条白线以下的东西 再加上这部分 What we have below this white line plus over here 443 00:28:43,312 --> 00:28:46,048 就是我们所谓的动态绑定 is what's called a dynamic binding view of the world. 444 00:28:46,592 --> 00:28:49,008 用动态绑定的角度来解释 就可以正常运行 If that works, that's a dynamic binding view. 445 00:28:50,850 --> 00:28:52,656 现在 让我们来看一个例子 Now, let's take a look, for example, 446 00:28:54,544 --> 00:28:55,990 要怎么实现这个功能 at just what it takes to implement that. 447 00:28:55,990 --> 00:28:56,960 非常简单 That's real easy. 448 00:28:57,480 --> 00:28:59,344 事实上 最早的Lisp实现 In fact, the very first Lisps 449 00:29:00,016 --> 00:29:02,528 对自由变量有各种形式的解释 had any form of interpretations of the free variables at all, 450 00:29:03,312 --> 00:29:05,984 包括用动态绑定来解释自由变量 had dynamic binding interpretations for the free variables. 451 00:29:06,400 --> 00:29:10,144 APL也是用动态绑定来解释自由变量的 APL has dynamic binding interpretation for the free variables, 452 00:29:11,680 --> 00:29:14,320 而不是词法绑定 或者说静态绑定 not lexical or static binding. 453 00:29:15,220 --> 00:29:17,008 当然 要从EVAL开始修改 So, of course, the change is in eval. 454 00:29:19,312 --> 00:29:20,592 只需修改两个地方就行 And it's really in two places. 455 00:29:22,780 --> 00:29:25,616 首先我们会发现 First of all, one thing we see, 456 00:29:26,528 --> 00:29:28,496 事情变得更简单了 is that things become a little simpler. 457 00:29:29,390 --> 00:29:33,632 如果我不需要 If I don't have to have the -- If I don't have to have the 458 00:29:33,648 --> 00:29:36,200 在定义过程的那个环境中求值 environment be the environment of definition for procedure, 459 00:29:36,448 --> 00:29:38,048 过程在定义的时候就无需 the procedure need not capture 460 00:29:38,432 --> 00:29:40,176 捕获当时的环境了 the environment at the time it's defined. 461 00:29:42,030 --> 00:29:44,960 所以我们可以在幻灯片的这里看到 And so if we look here at this slide, 462 00:29:45,840 --> 00:29:50,080 这条用于判断是否为LAMBDA表达式的子句 we see that the clause for a lambda expression, 463 00:29:50,736 --> 00:29:52,432 过程就是在这个时候创建的 which is the way a procedure is defined, 464 00:29:53,920 --> 00:29:56,736 就不会返回一个带有类型标签 does not make up a thing which has a type closure 465 00:29:56,752 --> 00:30:01,050 和环境结构的过程对象了 and a attached environment structure. 466 00:30:01,290 --> 00:30:02,540 就是EXP本身 It's just the expression itself. 467 00:30:02,540 --> 00:30:04,768 而我们会在其它地方用某种方式来解耦 And we'll decompose that some other way somewhere else. 468 00:30:06,440 --> 00:30:09,408 另外一处修改就是组合式的应用 The other thing we see is the applicator 469 00:30:10,368 --> 00:30:13,696 应用的时候必须要取得调用者的环境 applicator must be able to get the environment of the caller. 470 00:30:14,290 --> 00:30:17,240 调用者的环境就在这里 The caller of a procedure is right here. 471 00:30:17,260 --> 00:30:19,456 如果表达式是一个过程应用-- If the procedure is a application-- 472 00:30:19,560 --> 00:30:21,632 如果我们求值的是一个组合式 If the expression we're evaluating is a combination, 473 00:30:21,792 --> 00:30:23,712 我们就会调用一个组合式 then we're going to call a combination 474 00:30:23,936 --> 00:30:25,504 调用一个过程 then we're going to call a procedure 475 00:30:25,664 --> 00:30:27,376 来取得运算符的值 which is the value of the operator. 476 00:30:29,840 --> 00:30:31,440 调用者的环境 The environment of the caller 477 00:30:31,984 --> 00:30:34,512 就是我们当前的环境 is the environment we have right here, available now. 478 00:30:35,890 --> 00:30:40,720 所以 我只需要要把这个环境传递给APPLY So all I have to do is pass that environment to the applicator, to apply. 479 00:30:41,490 --> 00:30:42,752 我们再来看看APPLY And if we look at that here, 480 00:30:43,584 --> 00:30:44,976 我们只需要 the only change we have to make 481 00:30:45,712 --> 00:30:48,416 把参数列表加上一个环境ENV is that fellow takes that environment 482 00:30:48,780 --> 00:30:55,680 然后用这个环境来扩展环境 uses that environment for the purpose of extending that environment 483 00:30:56,670 --> 00:30:59,024 扩展把形式参数 when abiding the formal parameters 484 00:30:59,024 --> 00:31:01,370 和传递过来的实际参数绑定在一起的环境 of the procedure to the arguments that were passed, 485 00:31:03,088 --> 00:31:05,984 而不再是之前由过程捕获的环境了 not an environment that was captured in the procedure. 486 00:31:06,810 --> 00:31:09,456 最早的Lisp偶然地采用了 The reason why the first Lisps were implemented this way, 487 00:31:09,664 --> 00:31:11,968 这种最显然的方式实现 is the sort of the obvious, accidental implementation. 488 00:31:14,130 --> 00:31:16,680 当然 像往常一样 人们习惯了并喜欢上了它 And, of course, as usual, people got used to it and liked it. 489 00:31:17,250 --> 00:31:18,272 因此就有一些人说 And there were some people said, 490 00:31:18,400 --> 00:31:19,504 “就应该这么来做” this is the way to do it. 491 00:31:21,590 --> 00:31:24,096 不幸的是 这导致一些严重的问题 Unfortunately that causes some serious problems. 492 00:31:25,408 --> 00:31:27,248 最严重的一点是 The most important, serious problem 493 00:31:27,536 --> 00:31:29,840 采用动态绑定 in using dynamic binding 494 00:31:31,008 --> 00:31:33,568 破坏了模块性 is there's a modularity crisis that's involved it. 495 00:31:35,460 --> 00:31:37,664 如果有两个人在一个大型系统上协同工作 If two people are working together on some big system, 496 00:31:38,576 --> 00:31:40,016 那么一个重要的原则就是 then an important thing to one 497 00:31:40,352 --> 00:31:42,192 每个人所使用的名字 is that the names used by each one 498 00:31:42,992 --> 00:31:44,580 都不应该干扰到对方的名字 don't interfere with the names of the other. 499 00:31:47,930 --> 00:31:50,784 如果我写了一段代码 It's important that when I invent some segment of code 500 00:31:51,072 --> 00:31:53,136 别人就不能通过在他代码内部 that no one can make my code stop working 501 00:31:53,880 --> 00:31:56,576 使用我代码中的名字来破坏我的代码 by using my names that I use internal to my code, 502 00:31:56,752 --> 00:31:57,710 这一点很重要 internal to his code. 503 00:31:59,850 --> 00:32:00,464 然而 However, 504 00:32:01,040 --> 00:32:05,184 动态绑定明显地违背了这种特定的模块化约束 dynamic binding violates that particular modularity constraint in a clear way. 505 00:32:06,670 --> 00:32:08,080 我们考虑一下 Consider, for example, 506 00:32:09,184 --> 00:32:10,352 这段代码会有什么效果? what happens over here. 507 00:32:12,540 --> 00:32:13,792 假设我想要把 Suppose it was the case 508 00:32:15,472 --> 00:32:19,810 我想要把变量NEXT换个名字 that I decided to change the word next. 509 00:32:19,810 --> 00:32:24,416 假设某个人要编写SUM过程 Supposing somebody is writing, somebody is writing sum, 510 00:32:25,104 --> 00:32:26,688 而别人则会使用这个SUM过程 and somebody else is going to use sum. 511 00:32:28,970 --> 00:32:30,320 编写SUM的那个人 The writer of sum 512 00:32:30,496 --> 00:32:32,304 可以选择他想要使用的名字 has a choice of what names he may use. 513 00:32:33,664 --> 00:32:34,848 假设我就是那个编写者 Let's say, I'm that writer. 514 00:32:36,832 --> 00:32:39,300 刚巧 这里我不想用NEXT来表示 Well, by gosh, just happens I didn't want to call this next. 515 00:32:39,300 --> 00:32:40,096 而是用N来表示 I called it n. 516 00:32:41,740 --> 00:32:43,104 所以我把所有出现NEXT的地方 So all places where you see next, 517 00:32:44,288 --> 00:32:45,260 都换成N I called it n. 518 00:32:48,140 --> 00:32:48,480 哎呀 Whoops. 519 00:32:49,940 --> 00:32:52,224 我没有改变这个程序的规范 I changed nothing about the specifications of this program, 520 00:32:53,328 --> 00:32:54,864 但是整个程序就崩溃了 but this program stops working. 521 00:32:56,110 --> 00:32:57,968 不仅如此 这边也出现了问题 Not only that, unfortunately, this one does too. 522 00:32:59,504 --> 00:33:01,408 为什么会这样? Why do these programs stop working? 523 00:33:02,260 --> 00:33:03,248 答案非常明显 Well, it's sort of clear. 524 00:33:04,480 --> 00:33:09,296 NTH-POWER中的变量N的值 Instead of chasing out the value of the n 525 00:33:09,310 --> 00:33:13,728 也就是这个N和这个N that occurs in nth power over here or over here, 526 00:33:14,976 --> 00:33:17,168 根据环境模型的定义 through the environment of definition, 527 00:33:17,200 --> 00:33:19,580 这两个N总是相关的 where this one is always linked to this one, 528 00:33:19,870 --> 00:33:21,488 如果是根据环境模型的定义的话 if it was through the environment of definition, 529 00:33:21,552 --> 00:33:23,630 因为N在这里被绑定 because here is the definition. 530 00:33:24,370 --> 00:33:26,256 这个LAMBDA表达式是在 This lambda expression was executed 531 00:33:26,592 --> 00:33:28,592 N被绑定的环境中执行的 in the environment where that n was defined. 532 00:33:30,700 --> 00:33:31,840 如果不用环境模型的话 If instead of doing that, 533 00:33:32,016 --> 00:33:33,680 我必须追踪过程的调用链 I have to chase through the call chain, 534 00:33:34,784 --> 00:33:36,272 那么就会发生糟糕的事儿 then look what horrible thing happens. 535 00:33:37,320 --> 00:33:41,184 在SUM内部 这个是作为TERM调用的 Well, this was called from inside sum as term, term a. 536 00:33:41,760 --> 00:33:42,384 这里的(TERM A) term a. 537 00:33:44,780 --> 00:33:46,192 这时再来查找N的值 I'm looking for a value of n. 538 00:33:47,350 --> 00:33:48,400 我得到的不知这个值 Instead of getting this one, 539 00:33:48,848 --> 00:33:49,760 而是这个值 I get that one. 540 00:33:50,700 --> 00:33:52,544 因此 只是这个程序的内部做了修改 So by changing the insides of this program, 541 00:33:52,864 --> 00:33:54,096 这个程序却崩溃了 this program stops working. 542 00:33:56,770 --> 00:34:00,080 LAMBDA就不再像我以前说得那样是个量词了 So I no longer have a quantifier, as I described before. 543 00:34:01,120 --> 00:34:05,136 LAMBDA应该是一个量词 Which is a symbol -- The lambda symbol is supposed to be a quantifier. 544 00:34:05,430 --> 00:34:06,704 量词有一个性质 A thing which has the property 545 00:34:06,896 --> 00:34:11,424 被它绑定的名字都不重要 that the names that are bound by it are unimportant, 546 00:34:12,656 --> 00:34:15,712 只要我用不在过程体中的新名字 that I can uniformly substitute any names for these 547 00:34:16,928 --> 00:34:19,984 统一地在过程体中代换旧名字 throughout this thing, so long as they don't occur in here, the new names, 548 00:34:20,944 --> 00:34:23,168 就不会改变表达式的语义 and the meaning of this expression should remain unchanged. 549 00:34:24,040 --> 00:34:25,504 而我刚才却通过修改一个名字 I've just changed the meaning of the expression 550 00:34:25,536 --> 00:34:27,200 改变了表达式的语义 by changing the one of the names. 551 00:34:28,690 --> 00:34:30,896 因此LAMBDA就不再是一个良好定义的量词了 So lambda is no longer a well defined idea. 552 00:34:32,170 --> 00:34:33,376 这个问题非常严重 It's a very serious problem. 553 00:34:34,550 --> 00:34:35,552 正是因为这个原因 So for that reason, 554 00:34:36,640 --> 00:34:42,512 我和同事放弃了这种抽象方法 I and my buddies have given up this particular kind of abstraction, 555 00:34:43,136 --> 00:34:44,368 相对的 我更喜欢 which I would like to have, 556 00:34:45,616 --> 00:34:47,504 模块化原则 in favor of a modularity principle. 557 00:34:48,090 --> 00:34:50,208 如果你愿意探索解释器 But this is the kind of experiment you can do 558 00:34:51,968 --> 00:34:53,680 那就非常值得做这类实验 if you want to play with these interpreters. 559 00:34:54,832 --> 00:34:56,912 你可以尝试多种设计 You can try them out this way, that way, and the other way. 560 00:34:58,112 --> 00:35:00,256 探索更优雅的语言设计 You see what makes a nicer language. 561 00:35:02,680 --> 00:35:04,496 这是元循环求值器非常重要的功能 So that's a very important thing to be able to do. 562 00:35:04,990 --> 00:35:06,688 现在 我也想讲一讲 Now, I would like to give you a feeling 563 00:35:06,720 --> 00:35:08,496 这种情况下的正确做法 for I think the right thing to do is here. 564 00:35:09,328 --> 00:35:12,912 我又如何来获得这种 How are you going to, how are you going to I get this kind of 565 00:35:13,040 --> 00:35:15,344 词法作用域的能力呢? of power in a lexical system? 566 00:35:16,280 --> 00:35:17,392 当然 实际情况是 And the answer is, of course, 567 00:35:17,552 --> 00:35:20,032 在这里我想要的是 what I really want is a something that makes up for me 568 00:35:20,688 --> 00:35:22,608 针对特定N的求指数函数 an exponentiator for a particular n. 569 00:35:23,690 --> 00:35:24,288 给定一个N Given an n, 570 00:35:24,320 --> 00:35:25,664 它会返回给我一个特定的求指数过程 it will make me an exponentiator. 571 00:35:26,280 --> 00:35:27,408 这非常简单 Oh, but that's easy too. 572 00:35:28,170 --> 00:35:30,570 换言之 我可以这样来写 In other words, I can write my program this way. 573 00:35:35,840 --> 00:35:37,840 我要定义一个过程PGEN I'm going to define a thing called PGEN, 574 00:35:40,256 --> 00:35:42,544 它有一个参数N which is a procedure of n 575 00:35:43,168 --> 00:35:45,952 返回一个指数过程 which produces for me an exponentiator. 576 00:35:50,240 --> 00:35:51,232 计算X^N --x to the n. 577 00:35:56,800 --> 00:35:57,984 有了这个以后 Given that I have that, 578 00:35:58,592 --> 00:36:00,880 我就可以进行想要的那种抽象 then I can capture the abstraction I wanted 579 00:36:01,424 --> 00:36:03,936 甚至于现在的封装方法还要更好一些 even better, because now it's encapsulated in a way 580 00:36:04,096 --> 00:36:06,608 因为系统现在不会因改名而崩溃了 where I can't be destroyed by a change of names. 581 00:36:07,890 --> 00:36:12,352 (DEFINE SUM-POWERS I can define some powers 582 00:36:17,280 --> 00:36:20,704 (LAMBDA (A B N) I can define some powers to be a procedure again of a, b, and n 583 00:36:21,616 --> 00:36:26,832 (SUM which is the sum of the term function 584 00:36:26,880 --> 00:36:32,320 (PGEN N) generated by using this generator, PGEN, n, 585 00:36:34,400 --> 00:36:38,010 A 1+ B))) with a, incrementer, and b. 586 00:36:42,490 --> 00:36:47,952 (DEFINE PRODUCT-POWERS And I can define the product of powers 587 00:36:54,112 --> 00:36:58,840 (LAMBDA (A B N) to be a procedure of a, b, and n 588 00:36:59,808 --> 00:37:09,968 (PRODUCT (PGEN N) A 1+ B))) which is the product PGEN, n, with a, increment, and b. 589 00:37:11,280 --> 00:37:13,280 当然 这只是一个非常简单的例子 Now, of course, this is a very simple example 590 00:37:13,600 --> 00:37:16,352 这里 我想要抽象的对象也十分简单 where this object that I'm trying to abstract over is small. 591 00:37:17,280 --> 00:37:18,832 但它也有可能是长达100行的代码 But it could be a 100 lines of code. 592 00:37:20,100 --> 00:37:23,670 我这么写是为了保持简单 And so, the purpose of this is, of course, to make it simple. 593 00:37:23,670 --> 00:37:24,576 我给它命了名 I'd give a name to it, 594 00:37:24,736 --> 00:37:26,944 这里它只是一个参数化的名字 it's just that here it's a parameterized name. 595 00:37:28,200 --> 00:37:30,272 这个名字显式地依赖于 It's a name that depends upon, explicitly, 596 00:37:30,496 --> 00:37:33,632 词法作用域下N的值 the lexically apparent value of n. 597 00:37:37,130 --> 00:37:38,592 因此可以把它看做一个很长的名字 So you can think of this as a long name. 598 00:37:40,210 --> 00:37:41,584 这里 我是通过 And here, I've solved my problem 599 00:37:41,760 --> 00:37:45,824 为计算TERM的过程命名 by naming my... by naming the term generation 600 00:37:46,128 --> 00:37:49,220 来解决问题的 procedures within an n in them. 601 00:37:55,080 --> 00:37:55,872 有什么问题吗? Are there any questions? 602 00:37:57,008 --> 00:37:58,380 David 你说 Oh, yes, David. 603 00:37:58,570 --> 00:38:02,270 学生:刚才那个问题 AUDIENCE: Is the only solution to um... 604 00:38:03,070 --> 00:38:06,464 只能通过新建一个过程来解决吗? the problem you raise to create another procedure? 605 00:38:06,470 --> 00:38:08,928 换句话说 是不是必须要语言能够 In other words, can this only work in languages that are 606 00:38:08,992 --> 00:38:11,568 把对象定义为过程? capable of defining objects as procedures? 607 00:38:12,416 --> 00:38:13,760 教授:我明白了 PROFESSOR: Oh, I see. 608 00:38:15,904 --> 00:38:19,744 我构建抽象的这种方法 My solution to making this abstraction, 609 00:38:20,144 --> 00:38:22,864 需要过程能够返回或者导出一个过程 when I didn't want include the procedure inside the body, 610 00:38:23,264 --> 00:38:26,816 以便我不想让过程体中包含特定过程 depends upon my ability to return a procedure or export one. 611 00:38:27,040 --> 00:38:27,248 学生:没错 AUDIENCE: And that's right. 612 00:38:28,190 --> 00:38:28,880 教授:是这样的 PROFESSOR: And that's right. 613 00:38:29,536 --> 00:38:31,520 如果我不能这么做的话 If I don't have that, 614 00:38:32,240 --> 00:38:35,136 那么我就无法去构造一个抽象 then I just don't have this ability to make an abstraction in a way 615 00:38:35,536 --> 00:38:41,776 使得符号之间不会出现冲突 where I don't have possibilities of symbol conflicts that were unanticipated. 616 00:38:43,000 --> 00:38:43,488 你说得对 That's right. 617 00:38:44,144 --> 00:38:46,512 我认为 So one of the, the essential -- I consider, I consider 618 00:38:46,540 --> 00:38:48,912 能够把过程作为返回值 being able to return the procedural value and, therefore, 619 00:38:49,200 --> 00:38:58,288 更一般地说是支持“第一级过程” and therefore, to sort of have first class procedures, in general, 620 00:38:59,136 --> 00:39:02,464 是模块化程序程序设计所必须的 as being essential to doing very good modular programming. 621 00:39:03,700 --> 00:39:06,432 有很多种方式来解决这个问题 Now, indeed there are many other ways to skin this cat. 622 00:39:07,440 --> 00:39:09,168 你可以的做的就是 What you can do is take for each of the 623 00:39:09,184 --> 00:39:11,840 针对你所需要关心的每一种糟糕情况 for each of the bad things that you have to worry about, 624 00:39:12,272 --> 00:39:15,200 你可以添加一个特殊的FEATURE来解决它 you can make a special feature that covers that thing. 625 00:39:15,840 --> 00:39:17,120 你可以做一个包系统 You can make a package system. 626 00:39:17,744 --> 00:39:21,168 或者像Ada中的模块系统 等等 You can make a module system as in Ada, et cetera. OK? 627 00:39:22,240 --> 00:39:24,880 这些都可以 可能区别只是解决的程度不一 And all of those work, or they cover little regions of it. 628 00:39:26,440 --> 00:39:28,384 而能够把过程作为返回值 The thing is that returning procedures as values 629 00:39:28,416 --> 00:39:29,740 可以解决这所有的问题 cover all of those problems. 630 00:39:32,688 --> 00:39:34,608 这种最简单的机制 And so it's the simplest mechanism 631 00:39:35,584 --> 00:39:37,792 却可以给予你最好的模块性 that gives you the best modularity, 632 00:39:39,216 --> 00:39:41,312 它赋予你所有已知的模块机制 gives you all of the known modularity mechanisms. 633 00:39:45,590 --> 00:39:48,248 好的 该休息一会儿了 谢谢大家 Well, I suppose it's time for the next break, thank you. 634 00:39:48,240 --> 00:40:01,088 [音乐] [JESU, JOY OF MAN'S DESIRING] 635 00:40:01,280 --> 00:40:04,752 《计算机程序的构造和解释》 636 00:40:25,690 --> 00:40:29,424 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 637 00:40:30,010 --> 00:40:33,280 《计算机程序的构造和解释》 638 00:40:34,170 --> 00:40:37,616 元循环求值器 II 639 00:40:42,320 --> 00:40:44,288 教授:昨天你们学习流的时候 PROFESSOR: Well, yesterday when you learned about streams, 640 00:40:46,016 --> 00:40:51,168 Hal教授告诉了你们求值顺序 Hal worried to you about the order of evaluation 641 00:40:51,952 --> 00:40:53,872 以及过程的延迟求值 and delayed arguments to procedures. 642 00:40:55,616 --> 00:40:58,304 昨天在讲流的时候 我们说 The way we played with streams yesterday, 643 00:41:00,250 --> 00:41:04,224 调用者和被调者都应该认同 it was the responsibility of the caller and the callee 644 00:41:05,776 --> 00:41:08,848 参数是被延迟了的 both agree that an argument was delayed, 645 00:41:09,424 --> 00:41:13,440 如果被调者需要结果 就需要对参数FORCE and the callee must force the argument if it needs the answer. 646 00:41:15,130 --> 00:41:17,872 因此在过程的设计者和使用者之间 So there had to be a lot of hand shaking between 647 00:41:18,176 --> 00:41:24,320 就有很多关于延时求值的握手 the designer of a procedure and user of it over delayedness. 648 00:41:26,368 --> 00:41:28,720 当然 这看起来相当糟糕 That turns out, of course, to be a fairly bad thing, 649 00:41:29,488 --> 00:41:30,960 虽说对于流没什么不妥 it works all right with streams. 650 00:41:31,740 --> 00:41:32,864 但作为一般性的原则来说 But as a general thing, 651 00:41:32,928 --> 00:41:36,320 我们希望能有个地方 what you want is an idea to have a locus, 652 00:41:36,464 --> 00:41:38,496 能够把我们的设计考虑 a decision, a design decision in general, 653 00:41:38,890 --> 00:41:41,280 显式地、清晰地 to have a place where it's made, explicitly, 654 00:41:41,632 --> 00:41:43,930 标注出来 and notated in a clear way. 655 00:41:45,888 --> 00:41:49,280 因此就不必在过程编写者 And so it's not a very good idea to have to have an agreement, 656 00:41:50,464 --> 00:41:54,896 和使用者之间达成共识 between the person who writes a procedure and the person who calls it, 657 00:41:55,088 --> 00:41:57,984 有关于参数求值 about such details as, maybe, the arguments of evaluation, 658 00:41:58,432 --> 00:41:59,500 以及求值顺序等细节 the order of evaluation. 659 00:41:59,500 --> 00:42:00,750 虽然 这也不是太糟糕 Although, that's not so bad. 660 00:42:01,024 --> 00:42:03,952 我的意思是 可能还有像“输入是一个数字”这样的共识 I mean, we have other such agreements like, the input's a number. 661 00:42:05,200 --> 00:42:06,080 但是 But it would be nice if 662 00:42:06,352 --> 00:42:09,200 如果其中一个人可以全权负责 就再好不过了 one of these guys could take responsibility, completely. 663 00:42:11,020 --> 00:42:13,312 这个想法已经不算新潮了 Now this is not a new idea. 664 00:42:15,510 --> 00:42:21,168 Algol60就支持两种不同的过程调用方法 ALGOL 60 had two different ways of calling a procedure. 665 00:42:22,020 --> 00:42:24,288 参数可以按名或按值传递 The arguments could be passed by name or by value. 666 00:42:25,590 --> 00:42:27,488 按名传递就意味着 And what that meant was that 667 00:42:27,632 --> 00:42:29,720 参数会延时求值 a name argument was delayed. 668 00:42:31,110 --> 00:42:32,848 当你按名传递一个参数时 That when you passed an argument by name, 669 00:42:33,648 --> 00:42:36,528 只有你去取它的值的时候 that its value would only be obtained 670 00:42:36,960 --> 00:42:39,552 它的值才会被计算出来 if you accessed that argument. 671 00:42:42,290 --> 00:42:44,208 所以 现在我就要 So what I'd like to do now is show you, 672 00:42:44,432 --> 00:42:46,960 像之前那样 first of all, a little bit about, again, 673 00:42:46,992 --> 00:42:48,656 对语言做出一些小小的修改 we're going to make a modification to a language. 674 00:42:50,320 --> 00:42:51,792 这里 我们再添加一个新的FEATURE In this case, we're going to add a feature. 675 00:42:53,370 --> 00:42:55,056 我们要添加的FEATURE是 We're going to add the feature of, 676 00:42:55,360 --> 00:42:58,736 “按名传递参数” 或者可以叫做“延迟求值参数” by name parameters, if you will, or delayed parameters. 677 00:43:00,430 --> 00:43:04,416 因为事实上 Lisp系统中默认 Because, in fact, the default in our Lisp system 678 00:43:04,768 --> 00:43:06,608 传递的是一个指针 is by the value of a pointer. 679 00:43:08,220 --> 00:43:09,152 指针被复制了一份 A pointer is copied, 680 00:43:09,152 --> 00:43:10,910 但所指的数据结构却没有被复制 but the data structure it points at is not. 681 00:43:13,410 --> 00:43:14,848 现在我要告诉你们 But I'd like to, in fact, show you 682 00:43:15,040 --> 00:43:18,384 如何来添加按名传递参数 is how you add name arguments as well. 683 00:43:19,990 --> 00:43:22,128 为什么我们需要这样的FEATURE呢? Now again, why would we need such a thing? 684 00:43:23,100 --> 00:43:24,720 假设我们想要开发 Well supposing we wanted to invent 685 00:43:25,248 --> 00:43:28,448 像是某种特殊形式的功能 certain kinds of what otherwise would be special forms, 686 00:43:28,736 --> 00:43:29,720 类似于“保留字” reserve words? 687 00:43:29,720 --> 00:43:31,488 但不是用保留字的方式来实现 But I'd rather not take up reserve words. 688 00:43:32,180 --> 00:43:34,768 我想用过程来实现类似IF的效果 I want procedures that can do things like if. 689 00:43:36,360 --> 00:43:39,420 无论是IF还是COND 都是特殊形式 If is special, or cond, or whatever it is. 690 00:43:39,420 --> 00:43:40,432 它俩是一样的 It's the same thing. 691 00:43:40,590 --> 00:43:42,864 这个特殊形式用于 It's special in that it determines whether or not 692 00:43:42,928 --> 00:43:45,020 根据谓词返回真假 to evaluate the consequent or the alternative 693 00:43:46,224 --> 00:43:49,760 决定求值真子句还是假子句 based on the value of the predicate part of an expression. 694 00:43:50,840 --> 00:43:53,120 它们都是根据某个值 So taking the value of one thing 695 00:43:53,440 --> 00:43:55,360 来决定是否去做另外的某件事 determines whether or not to do something else. 696 00:43:57,270 --> 00:43:58,880 然而像+之类的过程 Whereas all the procedures like plus, 697 00:43:59,152 --> 00:44:01,200 也就是那些我们现在可以定义的过程 evaluate... the ones that we can define right now, 698 00:44:01,424 --> 00:44:06,560 是在应用前就求值所有的参数 evaluate all of their arguments before application. 699 00:44:08,670 --> 00:44:09,648 因此 举例来说 So, for example, 700 00:44:10,464 --> 00:44:12,416 假设我想定义一个过程 supposing I wish to be able to define something like 701 00:44:15,392 --> 00:44:18,752 用IF来实现与IF相反的效果 the reverse of if in terms of if. 702 00:44:19,856 --> 00:44:20,700 我叫它UNLESS Call it unless. 703 00:44:24,890 --> 00:44:27,472 参数是 谓词P、真子句C和假子句A We've a predicate, a consequent, and an alternative. 704 00:44:28,672 --> 00:44:30,448 接下来 我想 Now what I would like to sort of be able to do is 705 00:44:30,464 --> 00:44:32,080 用COND来实现 say-- oh, I'll do it in terms of cond. 706 00:44:32,640 --> 00:44:36,720 (COND ((NOT P) Cond, if not the predicate, 707 00:44:38,960 --> 00:44:40,320 结果就是真子句C then take the consequent, 708 00:44:41,584 --> 00:44:45,632 否则就是假子句A otherwise, take the alternative. 709 00:44:51,290 --> 00:44:52,768 我定义这个过程是为了 Now, what I'd like this to mean, 710 00:44:53,328 --> 00:44:55,408 请考虑下面这种情况 is supposing I do something like this. 711 00:44:56,920 --> 00:45:04,128 (UNLESS (= 1 0) I'd like this unless say if equals one, 0, 712 00:45:05,088 --> 00:45:06,640 那么结果就是2 then the answer is two, 713 00:45:07,904 --> 00:45:11,350 否则 结果就是(/ 1 0) otherwise, the quotient of one and 0. 714 00:45:15,920 --> 00:45:18,912 这段代码相当于进行这样的代换: What I'd like that to mean is the result of substituting 715 00:45:20,000 --> 00:45:23,264 用(= 1 0)、2和(/ 1 0) equal one, 0, and the quotient of one, 0 716 00:45:23,664 --> 00:45:24,760 分别代换上面的P、C以及A for p, c, and a. 717 00:45:25,580 --> 00:45:27,584 这样很有趣 I'd like that to mean, and this is funny, 718 00:45:28,112 --> 00:45:30,336 代换后就变成了 I'd like it to transform into or mean 719 00:45:30,752 --> 00:45:38,448 (COND ((NOT (= 1 0)) cond not equal one, 0, 720 00:45:40,624 --> 00:45:42,544 结果就是2 then the result is two, 721 00:45:44,280 --> 00:45:45,104 否则就是 otherwise 722 00:45:48,224 --> 00:45:51,160 (/ 1 0) I want it to be the quotient one and 0. 723 00:45:54,480 --> 00:45:56,480 你们也知道 如果向Lisp中输入这段代码 Now, you know that if I were to type this into Lisp, 724 00:45:57,744 --> 00:45:58,592 结果会是2 I'd get a two. 725 00:45:59,970 --> 00:46:01,328 这没问题 There's no problem with that. 726 00:46:02,910 --> 00:46:04,640 但如果我输入的是这段代码 However, if I were to type this into Lisp, 727 00:46:05,280 --> 00:46:07,792 由于参数会在过程调用前求值 because all the arguments are evaluated before I start, 728 00:46:09,120 --> 00:46:10,736 那么这段代码就会报错 then I'm going to get an error out of this. 729 00:46:13,380 --> 00:46:15,616 当然 如果成功进行代换的话 So that if the substitutions work at all, of course, 730 00:46:16,032 --> 00:46:16,880 我可以得到正确的结果 I would get the right answer. 731 00:46:16,880 --> 00:46:20,160 但是这里这种情况 代换并不能进行 But here's a case where the substitutions don't work. 732 00:46:22,176 --> 00:46:23,860 我连错误的结果都无法得到 I don't get the wrong answer. 733 00:46:23,860 --> 00:46:24,670 没有结果 I get no answer. 734 00:46:24,800 --> 00:46:25,600 只能得到错误 I get an error. 735 00:46:28,420 --> 00:46:31,216 现在 我要想办法 Now, however, I'd like to be able to make my definition 736 00:46:31,616 --> 00:46:32,992 使这样的定义可以成功运行 so that this kind of thing works. 737 00:46:34,480 --> 00:46:36,512 但我想标注出 What I want to do is say something special 738 00:46:36,704 --> 00:46:38,760 C和A是特殊的东西 about c and a. 739 00:46:39,930 --> 00:46:43,152 我想使它们自动地延时求值 I want them to be delayed automatically. 740 00:46:44,272 --> 00:46:48,080 我不想它们在我调用过程的时候 I don't want them to be, I don't want them to be evaluated 741 00:46:48,528 --> 00:46:49,744 就被求值 at the time I call. 742 00:46:51,520 --> 00:46:52,720 所以我得先制定一种声明 So I'm going to make a declaration, 743 00:46:52,752 --> 00:46:55,328 然后再考虑如何实现此种声明 and then I'm going to see how to implement such a declaration. 744 00:46:55,600 --> 00:46:57,632 再次强调 希望你们能够提醒自己 But again, I want you to say to yourself, 745 00:46:57,792 --> 00:47:00,256 我们这里添加的是临时组件 oh, this is an interesting kluge he's adding in here. 746 00:47:00,760 --> 00:47:02,160 必须要知道 A kluge, you know. 747 00:47:02,256 --> 00:47:04,720 滥用临时组件会造成大混乱 The piles of kluges make a big complicated mess. 748 00:47:05,750 --> 00:47:09,792 还会破坏一些已有的东西 And is this going to foul up something else that might occur. 749 00:47:10,120 --> 00:47:12,704 首先 它会造成语法歧义性么? First of all, is it syntactically unambiguous? 750 00:47:13,860 --> 00:47:15,504 就我们目前已有的语法来说 Well, it will be syntactically unambiguous 751 00:47:15,712 --> 00:47:16,910 它不会造成什么歧义 with what we've seen so far. 752 00:47:17,840 --> 00:47:20,768 但接下来要做的却可能招来麻烦 But what I'm going to do may, in fact, cause trouble. 753 00:47:21,670 --> 00:47:24,672 我要添加的东西可能会跟 It may be that the thing I had will conflict with 754 00:47:25,152 --> 00:47:27,104 我以后添加的类型声明冲突 type declarations I might want to add in the future 755 00:47:28,192 --> 00:47:31,088 类型系统通过提供已知的类型信息 for giving some system, some compiler or something, 756 00:47:31,216 --> 00:47:33,664 使得语言系统或者编译器可以做出优化 the ability to optimize given the types are known. 757 00:47:34,750 --> 00:47:36,976 当然也会与我想添加的形式参数的 Or it might conflict with other types of declarations 758 00:47:37,008 --> 00:47:39,710 其它类型的声明相冲突 that I might want to make about the formal parameters. 759 00:47:40,570 --> 00:47:42,560 所以这里我并不打算做一个一般性的机制 So I'm not making a general mechanism here 760 00:47:43,770 --> 00:47:45,248 使得我可以添加声明 where I can add declarations. 761 00:47:45,280 --> 00:47:46,544 虽然我很想那么做 And I would like to be able to do that. 762 00:47:46,896 --> 00:47:48,816 但现在并不打算这么做 But I don't want to talk about that right now. 763 00:47:51,010 --> 00:47:53,888 接下来 我要添加某种临时的解决方法 So here I'm going to do, I'm going to build a kluge. 764 00:47:57,568 --> 00:48:08,384 (DEFINE (UNLESS P So we're going to define unless of a predicate-- 765 00:48:08,810 --> 00:48:10,272 后面的参数都是按名调用 and I'm going to call these by name-- 766 00:48:12,784 --> 00:48:15,280 分别记作(NAME C)和(NAME A) the consequent, and name the alternative. 767 00:48:19,850 --> 00:48:25,280 哈 哈 卡在黑板边了 Huh, huh-- I got caught in the corner. 768 00:48:31,760 --> 00:48:35,616 (COND ((NOT P) C) If not p then the result is c, 769 00:48:36,800 --> 00:48:41,168 (ELSE A))) else-- that's what I'd like. 770 00:48:44,670 --> 00:48:46,880 我可以显式地声明 Where I can explicitly declare 771 00:48:47,552 --> 00:48:51,650 哪些参数按名称传递或延时求值 certain of the parameters to be delayed, to be computed later. 772 00:48:55,600 --> 00:48:58,480 对解释器的这个修改并不简单 Now, this is actually a very complicated modification to an interpreter 773 00:48:58,704 --> 00:48:59,776 反而相当复杂 rather than a simple one. 774 00:49:00,450 --> 00:49:03,104 我们之前介绍的动态绑定 The ones you saw before, dynamic binding 775 00:49:03,408 --> 00:49:06,896 或者让过程支持不定数目的参数 or adding indefinite argument procedures, 776 00:49:07,504 --> 00:49:08,528 都相对简单 is relatively simple. 777 00:49:09,280 --> 00:49:11,280 这次的修改涉及基本策略 But this one changes a basic strategy. 778 00:49:12,320 --> 00:49:13,392 这里的问题是 The problem here 779 00:49:13,968 --> 00:49:17,630 我们的解释器 就如代码所写的那样 is that our interpreter, as written 780 00:49:17,960 --> 00:49:23,408 在求值组合式时 evaluates a combination by evaluating the procedure, 781 00:49:24,240 --> 00:49:25,920 先通过求值运算符取得过程 the operator producing the procedure, 782 00:49:26,208 --> 00:49:30,352 然后再求值运算对象得到参数 and evaluating the operands producing the arguments, 783 00:49:30,768 --> 00:49:35,264 再把过程应用到参数上 and then doing apply of the procedure to the arguments. 784 00:49:36,384 --> 00:49:37,072 然而这里 However, here, 785 00:49:37,360 --> 00:49:41,488 直到我检查了整个过程 I don't want to evaluate the operands to produce the arguments 786 00:49:41,740 --> 00:49:43,660 确定了程序的声明 until after I examined the procedure 787 00:49:44,624 --> 00:49:46,864 才会去求值程序的参数 to see what the procedure's declarations look like. 788 00:49:49,590 --> 00:49:50,592 我们来看这个 So let's look at that. 789 00:49:52,680 --> 00:49:56,544 这是修改后的求值器 Here we have a changed evaluator. 790 00:49:57,480 --> 00:50:01,152 我是基于那个最简单的词法作用域求值器 I'm starting with the simple lexical evaluator, 791 00:50:01,728 --> 00:50:02,650 不是动态绑定的那个 not dynamic 792 00:50:04,144 --> 00:50:08,208 但是却要做一些类似于动态绑定的修改 but we're going to have to do something sort of similar in some ways. 793 00:50:09,750 --> 00:50:11,456 这是因为 Because of the fact that, 794 00:50:11,904 --> 00:50:13,344 如果我延时一个过程 -- if I delay a procedure-- 795 00:50:13,664 --> 00:50:15,152 哦说错了 -- 延时一个过程的参数 I'm sorry-- delay an argument to a procedure, 796 00:50:15,408 --> 00:50:17,520 就必须把当前的环境和参数关联在一起 I'm going to have to attach and environment to it. 797 00:50:19,360 --> 00:50:21,552 还记得Hal教授如何实现DELAY的吧? Remember how Hal implemented delay. 798 00:50:23,380 --> 00:50:25,440 Hal教授把DELAY实现为 Hal implemented delay as being 799 00:50:25,504 --> 00:50:27,472 一个无参过程 a procedure of no arguments 800 00:50:28,560 --> 00:50:30,528 用来执行某些表达式 which does some expression. 801 00:50:31,180 --> 00:50:36,944 就是这样让表达式延迟求值的 That's what delay of the expression is. --of that expression. 802 00:50:39,296 --> 00:50:40,992 (DELAY E)实际上是这个 This turned into something like this. 803 00:50:44,520 --> 00:50:46,928 然而 如果我求值这个LAMBDA表达式 Now, however, if I evaluate a lambda expression, 804 00:50:47,424 --> 00:50:49,200 我就必须得捕获当前环境 I have to capture the environment. 805 00:50:51,410 --> 00:50:53,456 这是因为 The reason why is because there are 806 00:50:54,608 --> 00:50:56,320 我想让这其中的变量的值 there are variables in there 807 00:50:57,024 --> 00:51:00,832 取决于它们被定义时的上下文 who's meaning I wish to derive from the context where this was written. 808 00:51:04,010 --> 00:51:05,760 这也就是为什么要用LAMBDA表达式 So that's why a lambda does the job. 809 00:51:06,624 --> 00:51:07,504 这才是正确的 It's the right thing. 810 00:51:08,070 --> 00:51:15,120 (FORCE E)则相当于 And such that the forcing of a delayed expression 811 00:51:16,528 --> 00:51:20,080 无参地调用这个过程 was same thing as calling that with no arguments. 812 00:51:21,090 --> 00:51:22,288 恰恰和上面相对 It's just the opposite of this. 813 00:51:24,100 --> 00:51:26,944 这个调用产生的环境则是 Producing an environment of the call 814 00:51:27,360 --> 00:51:29,904 定义这个过程时的环境 which is, in fact, the environment where this was defined 815 00:51:30,816 --> 00:51:32,368 额外加上一个空框架 with an extra frame in it that's empty. 816 00:51:33,232 --> 00:51:34,416 我并不在意它 I don't care about that. 817 00:51:36,240 --> 00:51:39,408 我们再来看这张幻灯片 Well, if we go back to this slide, 818 00:51:40,992 --> 00:51:43,728 仔细观察一会儿 since it's the case, if we look at this for a second, 819 00:51:44,144 --> 00:51:46,128 会发现大部分跟以前相同 everything is the same as it was before 820 00:51:46,350 --> 00:51:50,656 只是对应用或组合式的处理不同 except the case of applications or combinations. 821 00:51:51,980 --> 00:51:53,712 处理组合式分两步 And combinations are going to do two things. 822 00:51:54,680 --> 00:51:57,792 首先要求值这个过程 One, is I have to evaluate the procedure-- 823 00:51:57,920 --> 00:51:59,888 我就必须通过求值运算符来得到对应过程 I have to get the procedure-- by evaluating the operator. 824 00:52:00,704 --> 00:52:01,696 也就是这一部分 That's what you see right here. 825 00:52:02,380 --> 00:52:04,352 我得这个值是计算求出的现值 I have to make sure that that's current, 826 00:52:04,464 --> 00:52:05,760 而不是一个延时对象 that is not a delayed object, 827 00:52:06,368 --> 00:52:09,856 也就要求值它在被延时前的表达式 and evaluate that to the point where became it's forced now. 828 00:52:10,730 --> 00:52:12,080 接下来我就要 And then I have to somehow 829 00:52:12,240 --> 00:52:17,328 把它应用于运算对象 apply that to the, to the operands. 830 00:52:18,030 --> 00:52:19,616 但我仍然要保持这个环境 But I have to keep the environment, 831 00:52:19,632 --> 00:52:20,920 并将其传递过去 pass that environmental along. 832 00:52:21,530 --> 00:52:23,710 如果有一些运算对象是延时了的 So some of those operands I may have to delay. 833 00:52:23,710 --> 00:52:27,536 我就需要为这些运算对象附上相应的环境 I may have to attach that environment to those operands. 834 00:52:29,664 --> 00:52:31,520 这里的处理相当复杂 This is a rather complicated thing happening here. 835 00:52:32,990 --> 00:52:34,240 来看看APPLY中对应的部分 Looking at that in apply. 836 00:52:36,400 --> 00:52:38,720 APPLY这一部分处理基本过程 Apply, well it has a primitive procedure 837 00:52:39,360 --> 00:52:40,600 这和之前一样 thing just like before. 838 00:52:42,610 --> 00:52:44,688 但复合过程部分就比较有意思了 But the compound one is a little more interesting. 839 00:52:47,250 --> 00:52:49,520 和之前一样 我需要求值过程体 I have to evaluate the body, just as before, 840 00:52:50,480 --> 00:52:51,984 基于的环境是 in an environment which is 841 00:52:52,288 --> 00:52:54,976 把形式参数和 which is the result of binding some 842 00:52:55,616 --> 00:53:00,290 实际参数绑定在一起的结果 formal parameters to arguments in the environment. 843 00:53:00,290 --> 00:53:01,072 是这样的 That's true. 844 00:53:01,530 --> 00:53:03,820 环境来自于过程对象 The environment is the one that comes from the procedure now. 845 00:53:03,820 --> 00:53:06,656 因为我们的语言是词法作用域、静态绑定的 It's a lexical language, statically bound. 846 00:53:08,040 --> 00:53:11,824 然而 我还需要去掉NAME声明 However, one thing I have to do is strip off the declarations 847 00:53:11,840 --> 00:53:12,840 获得变量的实际名字 to get the names of the variables. 848 00:53:12,848 --> 00:53:15,200 这是由VNAMES过程完成的 That's what this guy does, vnames. 849 00:53:15,450 --> 00:53:16,672 然后要做的就是 And the other thing I have to do 850 00:53:16,976 --> 00:53:18,864 处理这些声明 is process these declarations, 851 00:53:19,136 --> 00:53:21,520 决定这些运算对象中 deciding which of these operands-- 852 00:53:21,760 --> 00:53:23,920 现在它们还是形式参数 而非实际参数 that's the operands now, as opposed to the arguments-- 853 00:53:24,096 --> 00:53:25,872 哪些运算对象需要立即求值 which of these operands to evaluate, 854 00:53:26,624 --> 00:53:30,208 而哪些运算对象又要 and which of them are to be 855 00:53:30,992 --> 00:53:33,770 用某种方式封装为延时对象 encapsulated in delays of some sort. 856 00:53:37,280 --> 00:53:40,080 另外 在处理基本过程这里 The other thing you see here is that we got a primitive, 857 00:53:40,600 --> 00:53:42,384 当遇到像+这样的基本过程 a primitive like plus, 858 00:53:42,688 --> 00:53:45,580 它们的参数最好立即求值 had better get at the real operands. 859 00:53:45,820 --> 00:53:47,392 也就我们需要是这里FORCE这些表达式 So here is a place where we're going to have to force them. 860 00:53:47,920 --> 00:53:50,384 EVLIST中完成了很多FORCE操作 And we're going to look at what evlist is going to have to do a bunch of forces. 861 00:53:51,340 --> 00:53:52,780 现在 我们有了两种不同的EVLIST So we have two different kinds of evlist now. 862 00:53:52,780 --> 00:53:54,096 EVLIST和GEVLIST We have evlist and gevlist. 863 00:53:54,520 --> 00:53:57,168 GEVLIST封装延迟参数 Gevlist is going to wrap delays around some things 864 00:53:57,184 --> 00:53:59,740 而对另外的参数立即求值 and force others, evaluate others. 865 00:53:59,870 --> 00:54:05,856 而EVLIST则会FORCE所有的表达式 And this guy's going to do some forcing of things. 866 00:54:07,900 --> 00:54:09,168 简单地看下EVLIST的代码 Just looking at this a little bit, 867 00:54:09,696 --> 00:54:11,984 课后你们一定要亲自上手试试 this is a game you must play for yourself, you know. 868 00:54:12,250 --> 00:54:14,672 光是听我在这里讲课 It's not something that you're going to see all possible 869 00:54:14,720 --> 00:54:18,200 可不能够学到求值器的不同变种 variations on an evaluator talking to me. 870 00:54:19,520 --> 00:54:21,248 你们需要上手亲自实践一下。 What you have to do is do this for yourself. 871 00:54:21,376 --> 00:54:23,840 你试验过后 对它们有了感悟 And after you feel this, you play this a bit, 872 00:54:24,224 --> 00:54:27,024 你才能理解各种可能的设计决策 you get to see all the possible design decisions and what they might mean, 873 00:54:27,776 --> 00:54:29,168 才能清楚它们如何相互关联 and how they interact with each other. 874 00:54:29,930 --> 00:54:32,384 了解求值器描述的是何种语言 So what languages might have in them. 875 00:54:33,160 --> 00:54:34,640 以及构建一门合理的语言 And what are some of the consistent sets 876 00:54:34,944 --> 00:54:36,320 需要哪些一致性集合 that make a legitimate language. 877 00:54:37,200 --> 00:54:40,064 哪些临时方案又是复杂而无用 Whereas what things are complicated kluges that are just piles of junk. 878 00:54:41,850 --> 00:54:44,688 就和我说得一样 这里的EVLIST So evlist of course, over here, just as I said, 879 00:54:44,816 --> 00:54:46,032 参数之一为运算对象表 is a list of operands 880 00:54:46,704 --> 00:54:50,280 表中的元素会在求值之后被取消延时 which are going to be undelayed after evaluation. 881 00:54:50,750 --> 00:54:51,904 它们都会被FORCE So these are going to be forced, 882 00:54:53,280 --> 00:54:54,448 无论它们是否为延时对象 whatever that's going to mean. 883 00:54:56,050 --> 00:54:58,512 下一个 GEVLIST And gevlist, which is the next thing-- 884 00:55:01,264 --> 00:55:01,856 谢谢 Thank you. 885 00:55:04,040 --> 00:55:06,350 我们在这里会发现 What we see here, uh 886 00:55:07,808 --> 00:55:09,616 这里面有多种可能 well there's a couple of possibilities. 887 00:55:09,810 --> 00:55:11,520 要么是普通的情况 Either it's a normal, ordinary thing, 888 00:55:12,480 --> 00:55:13,696 比如元素直接是一个符号 a symbol sitting there 889 00:55:13,744 --> 00:55:16,200 就像UNLESS中的参数P那样 like the predicate in the unless, 890 00:55:17,648 --> 00:55:18,816 对应这一部分代码 and that's what we have here. 891 00:55:19,390 --> 00:55:22,496 在这种情况下 我们就用应用序来求值 In which case, this is intended to be evaluated in applicative order. 892 00:55:23,340 --> 00:55:25,456 基本上就像以前一样 And it's, essentially, just what we had before. 893 00:55:25,630 --> 00:55:28,848 就是将EVAL映射在这个表上 It's mapping eval down the list. 894 00:55:29,952 --> 00:55:32,144 换言之 就是先求值第一个表达式 In other words, I evaluate the first expression 895 00:55:32,656 --> 00:55:37,360 然后在ENV中 求值(GEVLIST (CDR EXPRS)) and continue gevlisting the CDR of the expression in the environment. 896 00:55:37,936 --> 00:55:43,200 然而 我们也可能遇到按名传递的参数 However, it's possible that this is a name parameter. 897 00:55:44,000 --> 00:55:45,056 如果参数是按名传递 If it's a name parameter, 898 00:55:45,200 --> 00:55:46,592 我就需要给它包裹上一个DELAY I want to put a delay in 899 00:55:47,008 --> 00:55:50,976 DELAY里面就是我想按名调用的表达式 which combines that expression, which I'm calling by name, 900 00:55:52,144 --> 00:55:57,740 还要附上定义过程时的环境 with the environment that's available at this time 901 00:55:59,056 --> 00:56:00,592 把它们作为实际参数 and passing that as the parameter. 902 00:56:02,790 --> 00:56:05,040 然后像这样继续递归处理 And this is part of the mapping process that you see here. 903 00:56:09,070 --> 00:56:11,310 这个解释器中另外一个有意思的地方 The only other interesting place in this procedure 904 00:56:11,376 --> 00:56:13,536 就在于COND in this interpreter is cond. 905 00:56:14,700 --> 00:56:15,920 人们可能就这么来写 People tend to write this thing, 906 00:56:15,936 --> 00:56:17,248 然后就不管了 and then they leave this one out. 907 00:56:18,550 --> 00:56:19,984 你需要在一处FORCE There's a place where you have to force. 908 00:56:20,510 --> 00:56:23,104 COND表达式需要知道 Conditionals have to know 909 00:56:24,208 --> 00:56:25,904 谓词判定结果的真假 whether or not the answer is true or false. 910 00:56:25,990 --> 00:56:26,832 就像基本过程那样 It's like a primitive. 911 00:56:28,550 --> 00:56:30,560 求值COND语句时 需要FORCE When you do a conditional, you have to force. 912 00:56:31,728 --> 00:56:33,952 剩下的细节就没什么特别的了 Now, I'm not going to look at any more of this in any detail. 913 00:56:34,624 --> 00:56:36,288 就先不深究了 It isn't very exciting. 914 00:56:36,750 --> 00:56:38,990 剩下的就是如何实现MAKE-DELAY And what's left is how you make delays. 915 00:56:38,990 --> 00:56:40,912 延时对象是一种数据结构 Well, delays are data structures 916 00:56:41,312 --> 00:56:44,752 它包括:类型标识、表达式以及环境 which contain an expression, an environment, and a type on them. 917 00:56:44,840 --> 00:56:46,368 它的类型标识是'THUNK And it says they're a thunk. 918 00:56:46,960 --> 00:56:48,464 这个术语来自于Algol语言 That comes from ALGOL language, 919 00:56:49,072 --> 00:56:50,816 据说这是个拟声词 and it's claimed to be the sound of 920 00:56:50,832 --> 00:56:52,064 是把东西压栈的声音 of something being pushed on a stack. 921 00:56:52,970 --> 00:56:53,410 我不太清楚 I don't know. 922 00:56:53,410 --> 00:56:57,120 我既不是Algol学家 又不是Algol程序员 I was not an ALGOLician, so or an ALGOLite or whatever, 923 00:56:57,600 --> 00:56:58,384 所以我不太清楚 so I don't know. 924 00:56:58,740 --> 00:56:59,648 但据说它是那样的 But that's what was claimed. 925 00:57:00,270 --> 00:57:01,568 而UNDELAY的定义则是 And undelay is something 926 00:57:01,770 --> 00:57:03,664 递归地UNDELAY这些THUNK which will recursively undelay thunks 927 00:57:03,696 --> 00:57:06,000 直到得到一个非THUNK对象 until the thunk becomes something which isn't a thunk. 928 00:57:07,728 --> 00:57:10,944 这就是如何实现Algol中的按名调用 This is the way you implement a call by name like thing in ALGOL. 929 00:57:12,050 --> 00:57:13,760 差不多就是这样了 And that's about all there is. 930 00:57:15,210 --> 00:57:16,256 有什么问题吗? Are there any questions? 931 00:57:26,688 --> 00:57:27,520 学生:Gerry? AUDIENCE: Gerry? 932 00:57:28,096 --> 00:57:28,800 教授:你说 Vesko PROFESSOR: Yes, Vesko? 933 00:57:30,030 --> 00:57:32,992 学生:我注意到 对于基本过程 AUDIENCE: I noticed you avoided calling by name 934 00:57:33,440 --> 00:57:34,890 你是避免按名调用的 in the primitive procedures, 935 00:57:36,410 --> 00:57:38,384 我很想知道 你为什么要这样? I was wondering what cause you have on that? 936 00:57:38,416 --> 00:57:39,216 需要这样吗? You never need that? 937 00:57:40,070 --> 00:57:41,616 教授:Vesko想问的是 PROFESSOR: Vesko is asking 938 00:57:42,064 --> 00:57:46,000 基本过程也按名调用是否合理? if it's ever reasonable to call a primitive procedure by name? 939 00:57:47,140 --> 00:57:48,704 答案是:是的 The answer is, yes. 940 00:57:49,270 --> 00:57:52,320 有一种情况下是可以的 实际上是两种 There's one particular case where it's reasonable, actually two. 941 00:57:55,536 --> 00:57:58,272 比如用CONS来构造一个数据结构 Construction of a data structure like cons 942 00:57:59,020 --> 00:58:02,000 构建一个元素个数不定的数组时 where making an array if you have arrays with any number of elements. 943 00:58:03,264 --> 00:58:07,440 就没必要求值参数 OK? It's unnecessary to evaluate those arguments. 944 00:58:07,440 --> 00:58:08,832 你只需要创建一些PROMISE All you need is promises 945 00:58:09,104 --> 00:58:10,816 在确实需要时才来求值这些参数 to evaluate those arguments if you look at them. 946 00:58:11,504 --> 00:58:15,088 如果我把两个对象CONS起来 If I cons together a, two things, 947 00:58:16,240 --> 00:58:17,776 那么我CONS这些PROMISE then I could cons together the promises 948 00:58:17,808 --> 00:58:19,936 就和CONS这些对象一样容易 just as easily as I can cons together the things. 949 00:58:21,150 --> 00:58:23,376 甚至在对它们进行CAR CDR的时候 And it's not even when I CAR CDR them 950 00:58:23,392 --> 00:58:24,304 也不用进行实际的计算 that I have to look at them. 951 00:58:24,840 --> 00:58:26,976 取出PROMISE 并直接传递给其它人 That just gets out the promises and passes them to somebody. 952 00:58:28,260 --> 00:58:30,512 这也就是为什么Alonzo Church用LAMBDA演算 That's why the lambda calculus definition, the 953 00:58:30,576 --> 00:58:34,032 定义的CAR、CDR和CONS说得通的原因 the Alonzo Church definition of CAR, CDR, and cons makes sense. 954 00:58:34,420 --> 00:58:36,320 这是因为CAR、CDR以及CONS并没有执行计算 It's because no work is done in CAR, CDR, and cons, 955 00:58:36,380 --> 00:58:40,064 你们可以认为它是在重组数据而已 it's just shuffling data, it's just routing, if you will. 956 00:58:40,990 --> 00:58:42,208 然而像 + 这样的过程 However, the things that do have 957 00:58:42,240 --> 00:58:43,840 必须要了解参数是什么 to look at data are things like plus. 958 00:58:45,280 --> 00:58:46,912 它们需要确认 Because they have a look at the bits 959 00:58:47,120 --> 00:58:48,304 构成这些数字的比特 that the numbers are made out of, 960 00:58:48,320 --> 00:58:50,448 除非它们处理的是LAMBDA演算中的数字 unless they're lambda calculus numbers 961 00:58:50,448 --> 00:58:51,880 这就是另外一码事了 which are funny. OK? 962 00:58:52,430 --> 00:58:53,584 为了运算加法 They have to look at the bits to 963 00:58:53,776 --> 00:58:55,530 它需要知道构成数字的比特 be able to crunch them together to do the add. 964 00:58:59,210 --> 00:58:59,920 因此 实际上 So, in fact, 965 00:59:00,192 --> 00:59:02,784 数据的构造过程和选择过程 data constructors, data selectors, 966 00:59:03,248 --> 00:59:05,504 以及具有副作用的数据对象 in fact, things that side-effect data objects 967 00:59:06,270 --> 00:59:09,760 在最极端的惰性解释器中 don't need to do, don't need to do any forcing 968 00:59:11,344 --> 00:59:13,392 也不需要被FORCE in the laziest possible interpreters. 969 00:59:16,460 --> 00:59:16,992 另外一方面 On the other hand 970 00:59:17,024 --> 00:59:18,700 针对数据结构的谓词需要被FORCE predicates on data structures have to. 971 00:59:19,616 --> 00:59:22,656 如果你想判断 这是一个序对吗? If you want to say, is this a, is this a pair? 972 00:59:23,560 --> 00:59:24,400 或者是一个符号? Or is it a symbol? 973 00:59:24,640 --> 00:59:26,576 最好搞清楚是什么 Well, you better find out. You got to look at it then. 974 00:59:30,300 --> 00:59:31,184 还有问题吗? Any other questions? 975 00:59:40,050 --> 00:59:41,610 那好吧 下课 Oh, well, I suppose it's time for a break. 976 00:59:42,100 --> 00:59:55,840 MIT OpenCourseWare http://ocw.mit.edu 977 00:59:55,840 --> 01:00:04,560 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec8a.chn.srt ================================================ 1 00:00:00,000 --> 00:00:17,814 【背景音乐:巴赫】 2 00:00:17,814 --> 00:00:22,132 教授:上次课我们学习了如何构建一门语言。 3 00:00:22,132 --> 00:00:26,050 要点是解释器(比如lisp解释器) 4 00:00:26,050 --> 00:00:27,580 是由两个主要部分构成的。 5 00:00:27,580 --> 00:00:36,350 一个是EVAL。EVAL负责接收一个表达式(expression)和环境(environment) 6 00:00:36,350 --> 00:00:43,820 并将其转换成一个过程和一些参数, 7 00:00:43,820 --> 00:00:46,635 然后传递给APPLY。 8 00:00:49,410 --> 00:00:52,250 APP接收该过程和参数,再将其 9 00:00:52,250 --> 00:00:55,680 转换为(一般情况下)另一个表达式。 10 00:00:55,680 --> 00:00:58,280 该表达式将结合另外一个环境求值。APPLY将表达式回传给EVAL, 11 00:00:58,280 --> 00:01:00,770 EVAL再传给APPLY, 12 00:01:00,770 --> 00:01:02,750 形成一个大的循环, 13 00:01:02,750 --> 00:01:05,519 直至被翻译成基本数据 14 00:01:05,519 --> 00:01:07,740 或基本过程 15 00:01:07,740 --> 00:01:12,080 这个循环所作的工作就是分解 16 00:01:12,080 --> 00:01:15,020 语言当中的组合和抽象。 17 00:01:15,020 --> 00:01:17,870 比如,你有一个LISP过程 -- 18 00:01:17,870 --> 00:01:21,320 一个通用的,可以用来 19 00:01:21,320 --> 00:01:25,392 对这个表达式代入任何参数进行求值, 20 00:01:25,392 --> 00:01:27,670 和我们正在做的差不多。 21 00:01:27,670 --> 00:01:28,510 这就是APPLY的工作。 22 00:01:28,510 --> 00:01:30,770 它规定将所有作为参数传进来的值 23 00:01:30,770 --> 00:01:33,380 归约为表达式的主体。 24 00:01:33,380 --> 00:01:35,790 如果这是一个复合表达式,或调用了 25 00:01:35,790 --> 00:01:40,440 另外一个过程,就会一直循环下去。 26 00:01:40,440 --> 00:01:43,040 哇,这就是几乎所有 27 00:01:43,040 --> 00:01:45,120 解释器的基本结构了。 28 00:01:45,120 --> 00:01:46,720 另外就是,当你拿到一个解释器后, 29 00:01:46,720 --> 00:01:49,080 你就可以随心所欲的摆布 30 00:01:49,080 --> 00:01:49,870 你的语言了。 31 00:01:49,870 --> 00:01:53,390 你可以加入对动态范围的支持, 32 00:01:53,390 --> 00:01:55,960 正常次序求值,或者为语言增加一种 33 00:01:55,960 --> 00:01:57,680 新的变形,随便怎样都行。 34 00:01:57,680 --> 00:02:00,570 更一般的,我们遇到了元语言抽象 35 00:02:00,570 --> 00:02:07,930 就是说你作为一个工程师,一个软件工程师, 36 00:02:07,930 --> 00:02:09,970 而不仅是一个一般的工程师,经常可以通过发明 37 00:02:09,970 --> 00:02:15,270 新的语言以对复杂度 38 00:02:15,270 --> 00:02:18,010 进行控制。 39 00:02:18,010 --> 00:02:22,830 从某个角度上看,计算机编程 40 00:02:22,830 --> 00:02:25,170 仅仅是偶然的,刚好利用到了 41 00:02:25,170 --> 00:02:26,440 计算机来做事情。 42 00:02:26,440 --> 00:02:29,220 计算机程序主要是一种 43 00:02:29,220 --> 00:02:33,270 表达,交流想法的方法。 44 00:02:33,270 --> 00:02:36,300 有时,为了表达新的想法, 45 00:02:36,300 --> 00:02:39,770 你会更喜欢发明一种新的模式。 46 00:02:39,770 --> 00:02:44,300 好,今天我们将使用这个框架来 47 00:02:44,300 --> 00:02:45,730 构建一门新语言。 48 00:02:45,730 --> 00:02:48,140 一旦我们掌握了解释器的基本原理, 49 00:02:48,140 --> 00:02:50,830 你就可以构建任何你喜欢的语言。 50 00:02:50,830 --> 00:02:54,370 比如我们可以构建Pascal。 51 00:02:54,370 --> 00:02:58,820 确实有很多需要考虑的东西:语法,解析, 52 00:02:58,820 --> 00:03:01,450 各种各样的编译器优化,而且有很多人 53 00:03:01,450 --> 00:03:05,580 以此为生,过着诚实的生活。 54 00:03:05,580 --> 00:03:09,100 但在我们讨论的抽象层级上,一个Pascal解释器 55 00:03:09,100 --> 00:03:13,020 和上次Gerry做的那个, 56 00:03:13,020 --> 00:03:15,350 没有任何区别。 57 00:03:15,350 --> 00:03:18,190 今天我们不做那个。我们要构建一门 58 00:03:18,190 --> 00:03:23,400 真正与众不同的语言。 59 00:03:23,400 --> 00:03:26,980 它可以引导你跳出过程(procedure), 60 00:03:26,980 --> 00:03:29,090 以一种完全不同的方式去看待程序设计。 61 00:03:29,090 --> 00:03:33,650 今天的课程会同时在两个层面上展开。 62 00:03:34,810 --> 00:03:37,210 一方面,我会介绍这门语言长什么样, 63 00:03:37,210 --> 00:03:40,410 另一方面,我会向你们展示如何实现它。 64 00:03:41,010 --> 00:03:43,250 我们会用LISP去实现它, 65 00:03:43,250 --> 00:03:44,220 并研究它如何工作。 66 00:03:44,220 --> 00:03:48,730 你们将从两个层面上学习。 67 00:03:48,730 --> 00:03:52,190 一个是要认识到语言可以如此的与众不同, 68 00:03:53,790 --> 00:03:57,830 以至于如果你们认为从Fortran到LISP 69 00:03:57,830 --> 00:04:01,560 是一个巨大的跨越,那实际上你们还没开眼。 70 00:04:01,560 --> 00:04:05,660 第二,你们会看到,即使是 71 00:04:05,660 --> 00:04:08,590 这样一门特立独行的语言, 72 00:04:08,590 --> 00:04:12,260 它完全没有过程,也没有函数, 73 00:04:12,260 --> 00:04:16,570 但它背后还是基本的求值(eval)、应用(apply)循环, 74 00:04:16,570 --> 00:04:19,170 负责分解组合以及抽象的各种方法。 75 00:04:20,950 --> 00:04:24,430 第三点,作为一个很小但很优雅的技术点, 76 00:04:24,430 --> 00:04:27,720 你们会看到如何使用流(Stream)避免回溯(backtracking)。 77 00:04:32,330 --> 00:04:35,860 好了,我说过这门语言非常特别。 78 00:04:35,860 --> 00:04:41,620 为了解释它为什么特别,让我们回到在课程之初 79 00:04:41,620 --> 00:04:44,710 提到的第一个观点, 80 00:04:44,710 --> 00:04:48,780 关于声明式知识和数学之间的差异。 81 00:04:50,240 --> 00:04:55,470 对平方根的定义是一个数学真理-- 82 00:04:55,470 --> 00:04:59,080 而计算机科学是关于“怎么做”的知识-- 83 00:04:59,810 --> 00:05:03,700 对比一下平方根的定义 84 00:05:03,700 --> 00:05:05,970 和一个用来计算平方根的程序。 85 00:05:05,970 --> 00:05:08,042 我们从这里开始。 86 00:05:08,042 --> 00:05:11,830 如果我们能做到这样,是不是很伟大: 87 00:05:11,830 --> 00:05:16,030 发明一种新的语言填平这道沟。它可以执行计算, 88 00:05:16,030 --> 00:05:20,510 但我们用声明式的,用描述事实的方法去和它交流。 89 00:05:22,380 --> 00:05:24,110 在这样的语言里 90 00:05:24,110 --> 00:05:27,690 你们定义事实 91 00:05:27,690 --> 00:05:28,880 你们告诉它“是什么” 92 00:05:28,880 --> 00:05:30,950 你们告诉它“什么是真” 93 00:05:30,950 --> 00:05:34,220 然后当你们需要答案时, 94 00:05:34,220 --> 00:05:38,560 植语言已经入了一般性的 95 00:05:38,560 --> 00:05:41,200 关于“怎么做”的知识。它就可以接受你们输入的事实 96 00:05:41,200 --> 00:05:44,180 并基于这些事实,以及一些通用的逻辑规则, 97 00:05:44,180 --> 00:05:46,200 一步步去行演算。 98 00:05:49,330 --> 00:05:53,920 举个例子,我可以对这个程序说: 99 00:05:55,645 --> 00:06:08,920 我告诉它Adam的儿子是Abel。 100 00:06:08,920 --> 00:06:17,660 Adam的儿子是Cain。 101 00:06:17,660 --> 00:06:24,670 Cain的儿子是Enoch。 102 00:06:27,502 --> 00:06:37,550 Enoch的儿子是Irad, 103 00:06:37,550 --> 00:06:41,190 以及创世纪中提到的所有信息, 104 00:06:41,190 --> 00:06:45,010 一直到Adah结束。 105 00:06:45,010 --> 00:06:48,760 这就是从Cain到Adah的完整谱系。 106 00:06:48,760 --> 00:06:52,520 总之,一旦你告诉了它这些事实 107 00:06:52,520 --> 00:06:53,510 你就可以向它提问。 108 00:06:53,510 --> 00:06:58,560 你可以向这门语言提问: 109 00:06:58,560 --> 00:07:00,420 谁是Adam的儿子? 110 00:07:00,420 --> 00:07:03,480 很容易你就能想到 111 00:07:03,480 --> 00:07:06,460 用一个通用的搜索程序 112 00:07:06,460 --> 00:07:08,800 进行搜索并回答,yeah,有两个答案 113 00:07:08,800 --> 00:07:10,930 Adam的儿子是Abel 114 00:07:10,930 --> 00:07:14,140 Adam的儿子是Cain。 115 00:07:14,140 --> 00:07:19,350 或者你可以问,基于同样的事实, 116 00:07:19,350 --> 00:07:21,950 Cain是谁的儿子? 117 00:07:21,950 --> 00:07:25,520 然后你又可以想象一下产生一段 118 00:07:25,520 --> 00:07:29,510 稍微有些不同的搜索程序,可以查询事实 119 00:07:29,510 --> 00:07:33,760 并发现谁是Cain,他是谁的儿子, 120 00:07:33,760 --> 00:07:35,890 然后找到Adam。 121 00:07:35,890 --> 00:07:40,300 或者你可以问 122 00:07:40,300 --> 00:07:42,070 Cain和Enoch是什么关系? 123 00:07:42,070 --> 00:07:46,340 再一次的,该搜索程序又有一个小变种 124 00:07:46,340 --> 00:07:48,160 你能得到他们是父子关系。 125 00:07:52,880 --> 00:07:56,960 即使在这个简单的例子里 126 00:07:56,960 --> 00:08:00,460 你们可以发现,同一个简单的事实,比如 127 00:08:00,460 --> 00:08:04,230 Adam的儿子是Cain,可以被用来 128 00:08:04,230 --> 00:08:06,520 回答很多个不同的问题。 129 00:08:06,520 --> 00:08:10,540 你可以问,谁是Adam的儿子 130 00:08:10,540 --> 00:08:12,220 或者你可以问亚当和该隐是什么关系 131 00:08:12,970 --> 00:08:17,370 这些问题由依据同样的事实的 132 00:08:17,370 --> 00:08:22,474 一些不同的传统过程所回答。 133 00:08:22,474 --> 00:08:24,960 这就是这种编程风格的精华所在 134 00:08:24,960 --> 00:08:30,050 一条声明式的知识 135 00:08:30,050 --> 00:08:33,150 可以被用做许多不同种类的”怎么做“ 136 00:08:33,150 --> 00:08:36,440 的问题的基础,而不是我们以前写的那种过程 137 00:08:36,440 --> 00:08:39,010 告诉它输入是什么 138 00:08:39,010 --> 00:08:41,490 期望什么样的答案。 139 00:08:41,490 --> 00:08:43,710 比如,我们的平方根程序可以完美的 140 00:08:43,710 --> 00:08:48,900 回答这样的问题,144的平方根是多少? 141 00:08:48,900 --> 00:08:51,290 但本质上,平方根的数学定义 142 00:08:51,290 --> 00:08:52,830 可以回答更多的问题 143 00:08:52,830 --> 00:08:57,590 比如17是哪个数的平方根? 144 00:08:57,590 --> 00:08:58,590 这个问题可能需要使用一个 145 00:08:58,590 --> 00:09:01,920 不同的程序来回答。 146 00:09:01,920 --> 00:09:05,700 所以数学定义,或者更一般的, 147 00:09:05,700 --> 00:09:09,540 我们告诉语言的事实, 148 00:09:09,540 --> 00:09:10,900 跟问题没有强绑定关系。 149 00:09:10,900 --> 00:09:13,240 但是我们习惯与特定的程序,因为 150 00:09:13,240 --> 00:09:15,230 它们是关于”怎么做“的知识, 151 00:09:15,230 --> 00:09:17,700 查找某个特定的答案。 152 00:09:17,700 --> 00:09:19,530 所以这将是我们将要讨论的一个特征。 153 00:09:21,810 --> 00:09:23,480 我们继续。 154 00:09:23,480 --> 00:09:26,420 设想我们已经给我们的语言 155 00:09:26,420 --> 00:09:27,710 输入了一些事实。 156 00:09:27,710 --> 00:09:30,020 现在让我们再给它一些推导规则。 157 00:09:30,020 --> 00:09:35,100 举个例子,我们可以说,如果--- 158 00:09:35,100 --> 00:09:36,510 这里编一些语法--- 159 00:09:36,510 --> 00:09:41,580 如果x的儿子是y-- 160 00:09:41,580 --> 00:09:45,650 我用问号表示这是一个变量-- 161 00:09:45,650 --> 00:10:01,800 如果x的儿子是y,且y的儿子是z, 162 00:10:01,800 --> 00:10:09,320 那么x的孙子是z。 163 00:10:09,320 --> 00:10:15,370 所以我可以设想一下,把规则告诉机器 164 00:10:15,370 --> 00:10:17,680 然后问它,比如说, 165 00:10:17,680 --> 00:10:20,610 谁是亚当的孙子? 166 00:10:20,610 --> 00:10:24,790 或者Irad是谁的孙子? 167 00:10:24,790 --> 00:10:28,080 或者基于已知信息, 168 00:10:28,080 --> 00:10:29,330 找出所有的祖孙关系。 169 00:10:31,220 --> 00:10:34,580 我们不妨设想一下,语言知道如何 170 00:10:34,580 --> 00:10:35,830 自动的回答这些问题。 171 00:10:42,640 --> 00:10:45,200 让我在举几个更具体的例子。 172 00:10:49,610 --> 00:10:53,700 这是一个用来合并两个有序列表的过程。 173 00:10:53,700 --> 00:11:01,370 x和y是两个数字的列表,每个列表中没有重复元素。 174 00:11:01,370 --> 00:11:04,780 然后,如果你们愿意的话,按升序排列。 175 00:11:04,780 --> 00:11:08,560 merge的作用是取两个列表, 176 00:11:08,560 --> 00:11:10,040 合并成一个列表,仍然按升序排列。 177 00:11:10,040 --> 00:11:15,330 这么简单的程序,你们应该 178 00:11:15,330 --> 00:11:16,390 都会写。 179 00:11:16,390 --> 00:11:18,860 如果x为空,结果为y。 180 00:11:18,860 --> 00:11:21,180 如果y为空,结果为x。 181 00:11:21,180 --> 00:11:22,990 否则,比较各自的第一个元素。 182 00:11:22,990 --> 00:11:25,540 取出x的第一个元素和y中的第一个元素 183 00:11:25,540 --> 00:11:31,060 哪个小,就把哪个元素放到一边,然后对剩余部分 184 00:11:31,060 --> 00:11:35,500 (或者把x的头去掉,或者把y的头去掉) 185 00:11:35,500 --> 00:11:40,150 再和刚才取出来的元素合并。 186 00:11:42,400 --> 00:11:43,960 这是一个标准的程序。 187 00:11:46,470 --> 00:11:48,620 我们看一下它的逻辑。 188 00:11:48,620 --> 00:11:51,660 忘掉刚才的程序。看看这个过程所 189 00:11:51,660 --> 00:11:53,820 基于的逻辑。 190 00:11:53,820 --> 00:11:56,860 看,这里逻辑是,如果第一个 191 00:11:56,860 --> 00:12:00,240 更小一些,我们就把某个东西和 192 00:12:00,240 --> 00:12:03,350 剩余的部分递归合并的结果进行合并。 193 00:12:03,350 --> 00:12:05,420 我们试一下准确的说出使程序工作的逻辑。 194 00:12:08,430 --> 00:12:10,130 这一块, 195 00:12:10,130 --> 00:12:13,820 这块程序递归的 196 00:12:13,820 --> 00:12:19,980 当x更小的时候消去x的首元素。 197 00:12:19,980 --> 00:12:22,030 如果我们想要更准确的给出这里的逻辑 198 00:12:22,030 --> 00:12:27,120 那么这实际上是一个推导过程, 199 00:12:27,120 --> 00:12:31,790 即,如果我们知道cdr x和y合并等于z, 200 00:12:40,480 --> 00:12:47,570 且a比y的首元素小,我们就知道 201 00:12:47,570 --> 00:12:55,820 如果把a合并到cdr x的之前,再与y合并,结果就等于a+z。 202 00:12:55,820 --> 00:12:58,720 这就是背后的逻辑。 203 00:12:58,720 --> 00:13:01,620 我没有把它写成程序,而是写成一种推导。 204 00:13:01,620 --> 00:13:05,480 它是这段话背后的东西。 205 00:13:05,480 --> 00:13:09,410 它决定了在这里可以使用递归。 206 00:13:09,410 --> 00:13:11,910 类似地,看另外一段, 207 00:13:11,910 --> 00:13:14,000 把它做完。 208 00:13:14,000 --> 00:13:16,880 另外一段基于几乎相同的逻辑 209 00:13:16,880 --> 00:13:19,460 我就不细说了。 210 00:13:19,460 --> 00:13:22,730 然后这是我们要测试的n个场景。它基于这样的思想: 211 00:13:22,730 --> 00:13:26,920 任何x与空list合并还是x 212 00:13:26,920 --> 00:13:30,740 任何y与空list合并还是y 213 00:13:33,360 --> 00:13:39,340 好。我们看到了一段过程,以及它所基于的逻辑。 214 00:13:41,740 --> 00:13:44,750 注意一个巨大的差异 215 00:13:44,750 --> 00:13:51,050 过程是这样的。 216 00:13:51,050 --> 00:13:52,900 它规定这里有一个盒子。 217 00:13:52,900 --> 00:13:55,410 我们做的所有的事情都有这样的特点 218 00:13:55,410 --> 00:13:57,890 一个盒子,有东西进来,有东西出去。 219 00:13:57,890 --> 00:14:04,480 这个盒子叫merge,进来了x和y 220 00:14:04,480 --> 00:14:07,550 出来一个答案 221 00:14:07,550 --> 00:14:09,340 这就是过程的特点。 222 00:14:13,160 --> 00:14:14,660 规则就不一样 223 00:14:14,660 --> 00:14:17,620 规则讲的是关系 224 00:14:17,620 --> 00:14:23,030 这些胶片里有一些我称为 225 00:14:23,030 --> 00:14:25,370 "合并"的规则 226 00:14:25,370 --> 00:14:29,200 我说x和y合并等于z 227 00:14:29,200 --> 00:14:32,610 这还是个函数 228 00:14:32,610 --> 00:14:32,850 对吧? 229 00:14:32,850 --> 00:14:36,070 答案是x和y的函数。这里我看到的 230 00:14:36,070 --> 00:14:39,720 是三个东西之间的关系 231 00:14:39,720 --> 00:14:43,120 我不会规定哪些是输入 232 00:14:43,120 --> 00:14:44,200 那些是输出 233 00:14:44,200 --> 00:14:48,690 我这样说的原因是因为,原则上 234 00:14:48,690 --> 00:14:51,300 我们可以用这些同样的逻辑规则去回答 235 00:14:51,300 --> 00:14:54,570 很多个不同的问题 236 00:14:54,570 --> 00:14:56,750 所以我们可以,比如, 237 00:14:56,750 --> 00:14:59,050 假设把这些逻辑规则交给机器。 238 00:14:59,050 --> 00:15:01,400 不是程序,而是背后的逻辑规则 239 00:15:01,400 --> 00:15:04,750 于是它就可以回答, 240 00:15:04,750 --> 00:15:06,770 比如我们可以问-- 241 00:15:06,770 --> 00:15:20,910 1, 3, 7和2, 4, 8合并等于什么? 242 00:15:20,910 --> 00:15:23,880 这个问题它应该可以回答 243 00:15:23,880 --> 00:15:26,480 这恰恰是我们的lisp 244 00:15:26,480 --> 00:15:28,180 过程所回答的问题 245 00:15:28,180 --> 00:15:33,750 它同样的规则还可以回答 246 00:15:33,750 --> 00:15:41,760 这样的问题:1, 3, 7和什么合并可以得到 247 00:15:41,760 --> 00:15:45,560 1, 2, 3, 4, 7, 8? 248 00:15:45,560 --> 00:15:48,120 同样的一组规则可以回答它,但是 249 00:15:48,120 --> 00:15:50,880 刚才写的过程就不行 250 00:15:50,880 --> 00:15:56,070 或者我们可以说 251 00:15:56,070 --> 00:16:07,900 什么与什么合并得到---- 252 00:16:07,900 --> 00:16:13,780 什么与什么合并得到1,2,3,4,7,8? 253 00:16:13,780 --> 00:16:16,320 如果这个东西真的可以应用刚才的逻辑,它可以一直跑下去 254 00:16:16,320 --> 00:16:20,470 推导出第2~6个问题的答案 255 00:16:25,600 --> 00:16:28,790 它可以是1和其它,或者1,2与其它 256 00:16:28,790 --> 00:16:32,490 或者1,3,7与其它。 257 00:16:32,490 --> 00:16:33,410 有很多个答案。 258 00:16:33,410 --> 00:16:36,830 原则上,这个逻辑 259 00:16:36,830 --> 00:16:38,550 足以推导出它们。 260 00:16:38,550 --> 00:16:44,540 所以,在我们将要研究的程序 261 00:16:44,540 --> 00:16:48,370 和其它程序 262 00:16:48,370 --> 00:16:49,850 包括lisp和差不多你们之前见过的所有程序之间 263 00:16:49,850 --> 00:16:54,150 存在着两个巨大的差异 264 00:16:54,150 --> 00:16:57,620 首先,我们不会去计算函数。 265 00:17:00,800 --> 00:17:03,770 我们不会去关注接受输入返回输出的东西。 266 00:17:04,410 --> 00:17:06,890 我们将讨论关系。 267 00:17:06,890 --> 00:17:09,180 原则上,这些关系 268 00:17:09,180 --> 00:17:11,089 是没有方向的。 269 00:17:11,089 --> 00:17:14,569 所以你们所定义的,用来回答这个问题的知识 270 00:17:14,569 --> 00:17:19,220 可以同样的用来回答这些问题 271 00:17:19,220 --> 00:17:21,345 以及反过来的问题。 272 00:17:26,310 --> 00:17:30,590 第二个问题是,因为我们讨论的是关系 273 00:17:30,590 --> 00:17:33,150 那么这些关系就未必 274 00:17:33,150 --> 00:17:35,610 只有一个答案 275 00:17:35,610 --> 00:17:37,480 所以底下的第三个问题 276 00:17:37,480 --> 00:17:39,415 没有一个唯一的答案,它有一堆答案。 277 00:17:42,270 --> 00:17:44,640 OK, 这就是我们下面要学习的。 278 00:17:44,640 --> 00:17:48,620 另外,这种编程风格, 279 00:17:48,620 --> 00:17:51,310 称为逻辑编程。原因很明显。 280 00:17:56,160 --> 00:18:02,440 使用逻辑编程的人这么说 --- 281 00:18:02,440 --> 00:18:04,150 ---逻辑编程的关键就在于: 282 00:18:04,150 --> 00:18:10,190 用逻辑表达什么是真 283 00:18:10,190 --> 00:18:15,190 用逻辑去检查什么为真 284 00:18:15,190 --> 00:18:19,200 用逻辑去寻找什么为真。 285 00:18:19,200 --> 00:18:23,300 已知的最好的逻辑编程语言 286 00:18:23,300 --> 00:18:25,780 你们可能听说过,是Prolog. 287 00:18:25,780 --> 00:18:31,010 今天上午我们将要实现的语言, 288 00:18:31,010 --> 00:18:33,110 叫做query语言 289 00:18:33,110 --> 00:18:35,320 它具有Prolog的精华。 290 00:18:35,320 --> 00:18:38,340 它能做同样的事。当然它很慢 291 00:18:38,340 --> 00:18:42,390 因为我们将要用LISP去实现它 292 00:18:42,390 --> 00:18:44,210 而不是去开发一个专用的编译器。 293 00:18:44,210 --> 00:18:47,510 我们将要在LISP解释器的基础上实现新语言的解释器。 294 00:18:47,510 --> 00:18:48,950 除此以外,新语言的功能 295 00:18:48,950 --> 00:18:49,750 和prolog是一样的。 296 00:18:49,750 --> 00:18:52,160 它的能力和限制 297 00:18:52,160 --> 00:18:54,696 几乎都一样。 298 00:18:54,696 --> 00:18:56,120 我们暂停一下,问题时间 299 00:19:00,040 --> 00:19:04,010 学生:能否请您重复一下 300 00:19:04,010 --> 00:19:06,720 使用逻辑编程的三个目的? 301 00:19:06,720 --> 00:19:09,120 换句话说,是不是“寻找什么是真”, 302 00:19:09,120 --> 00:19:09,840 “学习什么是真”,“什么是真”? 303 00:19:09,840 --> 00:19:10,520 教授:是的。 304 00:19:10,520 --> 00:19:15,850 可以说是逻辑程序员的教义吧。 305 00:19:15,850 --> 00:19:22,610 你用逻辑来表达什么是真,就像这些规则一样。 306 00:19:22,610 --> 00:19:26,120 你使用逻辑来检查某些东西是否为真。这是一些我还没有回答过的问题。 307 00:19:28,550 --> 00:19:29,720 我可以说 -- 308 00:19:29,720 --> 00:19:33,620 我来写另一个问题, 309 00:19:33,620 --> 00:19:41,400 1,3,7和2,4,8是否合并成1,2,6,10? 310 00:19:41,400 --> 00:19:45,690 同样的逻辑足以判断出这是假的。 311 00:19:45,690 --> 00:19:49,190 所以我使用逻辑来判断什么是真, 312 00:19:49,190 --> 00:19:50,480 你还可以用逻辑查找什么是真。 313 00:20:04,060 --> 00:20:04,570 好。 314 00:20:04,570 --> 00:20:06,138 我们休息。 315 00:20:06,138 --> 00:20:22,106 【巴赫的音乐】 316 00:20:22,106 --> 00:20:47,590 音乐结束 317 00:20:47,590 --> 00:21:02,901 【巴赫的音乐】 318 00:21:02,901 --> 00:21:06,810 教授:继续。 319 00:21:06,810 --> 00:21:10,520 看一下这个查询语言和操作。 320 00:21:10,520 --> 00:21:12,890 当你看到这个小圣经数据库时, 321 00:21:12,890 --> 00:21:15,390 你注意到的第一点可能是 322 00:21:15,390 --> 00:21:18,900 能向这门语言提一些基于某些事实集合的问题, 323 00:21:18,900 --> 00:21:21,330 真的很好。 324 00:21:21,330 --> 00:21:26,060 现在我们开始,先制作一些事实的集合。 325 00:21:26,060 --> 00:21:31,700 这是一家位于波士顿的高科技公司的员工记录的一部分。 326 00:21:34,440 --> 00:21:37,500 这是Ben Bitdiddle的记录。 327 00:21:37,500 --> 00:21:41,470 Ben Bitdiddle是计算机巫师。 328 00:21:41,470 --> 00:21:44,660 薪水超低的计算机巫师。 329 00:21:46,420 --> 00:21:49,330 他的领导是Oliver Warbucks 330 00:21:49,330 --> 00:21:52,150 这是他的地址。 331 00:21:52,150 --> 00:21:55,220 我们记录信息的格式是这样的: 332 00:21:55,220 --> 00:21:57,300 职位,薪资,上级,地址。 333 00:21:57,300 --> 00:21:59,250 我们还有一些约定。 334 00:21:59,250 --> 00:22:01,570 这里的Computer表示Ben在计算机部门工作, 335 00:22:01,570 --> 00:22:03,590 它在计算机部门的岗位 336 00:22:03,590 --> 00:22:06,440 是巫师。 337 00:22:06,440 --> 00:22:07,580 这是另外一个人。 338 00:22:07,580 --> 00:22:13,860 Alyssa, Alyssa P. Hacker是一个程序员, 339 00:22:13,860 --> 00:22:17,550 在Ben手底下工作,她住在剑桥。 340 00:22:17,550 --> 00:22:19,990 Ben手下还有另外一个程序员, 341 00:22:19,990 --> 00:22:22,820 Lem E. Tweakit。 342 00:22:22,820 --> 00:22:26,330 这是另外一个程序员教练, 343 00:22:26,330 --> 00:22:30,100 Louis Reasoner,为Alyssa工作。 344 00:22:30,100 --> 00:22:34,830 公司的大老板, 345 00:22:34,830 --> 00:22:37,010 谁也管不了他,对吧? 346 00:22:37,010 --> 00:22:38,110 Oliver Warbucks。 347 00:22:38,110 --> 00:22:43,080 好了,我们要做的就是 348 00:22:43,080 --> 00:22:44,971 围绕着这个小世界开始提问。 349 00:22:44,971 --> 00:22:47,410 这就是我们要进行逻辑演算的 350 00:22:47,410 --> 00:22:48,660 小世界。 351 00:22:51,420 --> 00:22:55,810 让我在这里写一下,最后一次, 352 00:22:55,810 --> 00:22:57,600 你们应该从这们课里学到的最重要的东西 353 00:22:57,600 --> 00:23:00,760 当有人问到你们某一门语言时, 354 00:23:00,760 --> 00:23:03,440 你能说,好吧 -- 355 00:23:03,440 --> 00:23:15,050 它的原语是什么,组合的方式是什么, 356 00:23:15,050 --> 00:23:18,480 你怎么把原语组合起来, 357 00:23:18,480 --> 00:23:24,690 如何进行抽象,如何对复合的零件进行抽象, 358 00:23:24,690 --> 00:23:26,740 以便可以把它们当作零件,来搭建更复杂的东西? 359 00:23:28,500 --> 00:23:31,440 这些我们已经讲了很多次了, 360 00:23:31,440 --> 00:23:32,690 但还是值得再说一次。 361 00:23:36,210 --> 00:23:36,670 开始。 362 00:23:36,670 --> 00:23:38,040 原语。 363 00:23:38,040 --> 00:23:41,660 好吧,事实上原语只有一条, 364 00:23:41,660 --> 00:23:44,400 叫做查询。 365 00:23:44,400 --> 00:23:46,810 查询原语。 366 00:23:46,810 --> 00:23:48,060 让我们看一些查询原语的例子。 367 00:23:52,160 --> 00:23:53,100 Job x. 368 00:23:53,100 --> 00:23:55,550 谁是程序员? 369 00:23:55,550 --> 00:24:04,700 或者查找所有符合以下模式的事实: 370 00:24:04,700 --> 00:24:06,640 Job of the x is computer programmer. 371 00:24:06,640 --> 00:24:08,470 这里有一点小小的语法了。 372 00:24:08,470 --> 00:24:11,330 不带问号的东西是字面量, 373 00:24:11,330 --> 00:24:13,940 问号 x表示变量,这个东西会匹配 374 00:24:13,940 --> 00:24:18,110 这样的事实:Alyssa P. Hacker是一个程序员, 375 00:24:18,110 --> 00:24:21,930 或者x是Alyssa P. Hacker。 376 00:24:26,820 --> 00:24:29,170 或者更一般的,我们可以在 377 00:24:29,170 --> 00:24:30,750 一条语句里包含两个变量。 378 00:24:30,750 --> 00:24:39,530 我可以这样写:x的工作是computer XXX. 379 00:24:39,530 --> 00:24:42,140 这会匹配计算机巫师。 380 00:24:42,140 --> 00:24:44,865 注意这里:类型匹配巫师, 381 00:24:44,865 --> 00:24:49,390 或者程序员,或者x可以匹配 382 00:24:49,390 --> 00:24:50,370 很多东西。 383 00:24:50,370 --> 00:24:53,270 所以在我们的例子里, 384 00:24:53,270 --> 00:24:55,150 数据库里只有3条事实符合查询。 385 00:24:59,210 --> 00:25:04,910 我们看一下同样的查询。这是为了给你们看一下语法。 386 00:25:04,910 --> 00:25:11,490 这个查询不匹配job of x, 387 00:25:11,490 --> 00:25:13,200 不匹配Lewis Reasoner。原因是 388 00:25:13,200 --> 00:25:17,160 当我这样写的时候,表示这里有两个符号, 389 00:25:17,160 --> 00:25:22,730 第一个词是computer, 390 00:25:22,730 --> 00:25:24,810 第二个可以是任何东西。 391 00:25:24,810 --> 00:25:28,130 Lewis的职位描述有三个符号, 392 00:25:28,130 --> 00:25:30,340 所以不匹配。 393 00:25:30,340 --> 00:25:35,360 再给你们看一点语法, 394 00:25:35,360 --> 00:25:37,920 我想写的更一般类型是一个东西 395 00:25:37,920 --> 00:25:42,550 后面加一个点,这中方法表示 396 00:25:42,550 --> 00:25:46,560 这回死一个list,其中第一个元素 397 00:25:46,560 --> 00:25:49,350 是computer,其它的东西, 398 00:25:49,350 --> 00:25:50,600 我称之为类型。 399 00:25:53,730 --> 00:25:56,930 所以这一个是匹配的。 400 00:25:56,930 --> 00:26:00,000 Lewis's 的工作是程序员教练, 401 00:26:00,000 --> 00:26:04,690 这里的类型是list的身体部分,就是 402 00:26:04,690 --> 00:26:06,960 程序员教练列表。 403 00:26:06,960 --> 00:26:08,410 像这样对“点”的处理会 404 00:26:08,410 --> 00:26:10,460 由Lisp解释器自动完成。 405 00:26:15,900 --> 00:26:17,760 好了,让我们正式试一试吧。 406 00:26:17,760 --> 00:26:20,810 我用这门语言进行输入, 407 00:26:20,810 --> 00:26:23,630 然后答案就会出来。 408 00:26:23,630 --> 00:26:25,180 看这。 409 00:26:25,180 --> 00:26:30,000 我来问:谁在计算机部门工作? 410 00:26:30,000 --> 00:26:39,730 Job of x is computer dot y. 411 00:26:39,730 --> 00:26:42,562 这个变量叫什么没关系。 412 00:26:42,562 --> 00:26:45,690 答案出来了。有4个答案。 413 00:26:48,650 --> 00:26:51,380 我再问:告诉我所有人的领导。 414 00:26:52,505 --> 00:26:56,610 我这样写查询,一条查询原语, 415 00:26:56,610 --> 00:26:59,390 the supervisor of x is y. 416 00:27:02,860 --> 00:27:05,540 这就是所有我们能了解的上下级关系。 417 00:27:05,540 --> 00:27:08,830 我还可以输入:谁住在剑桥? 418 00:27:08,830 --> 00:27:20,670 像这样:address of x is cambridge . 随便什么 419 00:27:25,090 --> 00:27:26,585 只有一个人住在剑桥。 420 00:27:30,820 --> 00:27:32,170 这些都是查询原语。 421 00:27:32,170 --> 00:27:34,460 和系统的间的基本交互就是 422 00:27:34,460 --> 00:27:38,140 你输入查询,系统 423 00:27:38,140 --> 00:27:39,620 输出所有可能的答案。 424 00:27:39,620 --> 00:27:43,100 或者说,系统找出 425 00:27:43,100 --> 00:27:45,330 所有x和y或者t或者随便什么名字的变量的所有可能的取值 426 00:27:45,330 --> 00:27:50,380 ,并按所有满足查询的方式 427 00:27:50,380 --> 00:27:53,080 填充原语并输出 --- 428 00:27:53,080 --> 00:27:56,250 回想一下系统规则那堂课里讲的-- 429 00:27:56,250 --> 00:27:59,150 用所有变量的所有可能的取值实例化查询 430 00:27:59,150 --> 00:28:01,000 并输出。 431 00:28:01,000 --> 00:28:02,370 对一门逻辑语言, 432 00:28:02,370 --> 00:28:03,350 存在很多种排列方式 433 00:28:03,350 --> 00:28:06,010 比如Prolog就略有差异。 434 00:28:06,010 --> 00:28:08,980 它不是输出查询语句,而是输出 435 00:28:08,980 --> 00:28:12,230 x等于这个,y等于这个, 436 00:28:12,230 --> 00:28:12,650 或者x=这个,y=这个。 437 00:28:12,650 --> 00:28:16,430 这些是一些表层的东西,你可以 438 00:28:16,430 --> 00:28:19,070 选择你喜欢的方式。 439 00:28:19,070 --> 00:28:20,760 好。 440 00:28:20,760 --> 00:28:21,340 就这样。 441 00:28:21,340 --> 00:28:23,390 这门语言里有哪些原语? 442 00:28:23,390 --> 00:28:24,570 就一个,对吗? 443 00:28:24,570 --> 00:28:27,230 查询原语。 444 00:28:31,360 --> 00:28:31,650 好。 445 00:28:31,650 --> 00:28:34,330 组合的方法。 446 00:28:34,330 --> 00:28:39,770 我们看一些这门语言里的复合查询。 447 00:28:39,770 --> 00:28:41,790 这里有一个。 448 00:28:41,790 --> 00:28:47,250 它说:告诉我所有在 449 00:28:47,250 --> 00:28:49,810 计算机部门工作的人。 450 00:28:49,810 --> 00:28:52,610 告诉我所有在计算机部门工作 451 00:28:52,610 --> 00:28:53,860 的人,以及他们的领导。 452 00:28:56,800 --> 00:29:00,220 我写这条语句的方式是这样的: .. and ... 453 00:29:00,220 --> 00:29:04,920 而且x是computer或者别的什么东西。 454 00:29:04,920 --> 00:29:07,560 而且x的职位是computer . y。 455 00:29:07,560 --> 00:29:11,650 x的主观是z。 456 00:29:11,650 --> 00:29:13,570 告诉我所有在计算机部门工作的人-- 457 00:29:13,570 --> 00:29:16,460 就是这个--以及他们的领导。 458 00:29:16,460 --> 00:29:20,290 注意在这条查询里我使用了3个变量-- 459 00:29:20,290 --> 00:29:23,660 x, y, 和z. 460 00:29:23,660 --> 00:29:29,450 这个x和这个x相同。 461 00:29:29,450 --> 00:29:31,560 所以x在计算机部门工作, 462 00:29:31,560 --> 00:29:34,810 而且x的领导是z。 463 00:29:34,810 --> 00:29:37,250 我们再试一下另外一个。 464 00:29:37,250 --> 00:29:39,005 所以一种组合的方式是 and。 465 00:29:41,540 --> 00:29:45,790 都有哪些人收入超过3万美元? 466 00:29:45,790 --> 00:29:51,640 员工p的收入是a。 467 00:29:54,590 --> 00:30:00,600 我们再看一下a,a大于3万美元。 468 00:30:00,600 --> 00:30:06,300 lisp-value在这的作用是 469 00:30:06,300 --> 00:30:10,600 作为查询语言和底层LISP的接口。 470 00:30:10,600 --> 00:30:13,540 lisp-value可以允许你在一条查询中 471 00:30:13,540 --> 00:30:17,180 调用任何LISP谓词。 472 00:30:17,180 --> 00:30:19,110 我在这使用了LISP谓词greater than, 473 00:30:19,110 --> 00:30:21,020 所以我用lisp-value。 474 00:30:21,020 --> 00:30:21,750 我这样写。 475 00:30:21,750 --> 00:30:28,190 所有收入超过3万美元的人。 476 00:30:28,190 --> 00:30:31,270 或者这里有一个跟复杂的。 477 00:30:31,270 --> 00:30:36,150 告诉我所有这样的人:他在计算机部工作, 478 00:30:36,150 --> 00:30:38,560 但他的领导不在 479 00:30:38,560 --> 00:30:39,810 计算机部。 480 00:30:42,790 --> 00:30:45,510 x在计算机部。 481 00:30:45,510 --> 00:30:47,780 The job of x is computer dot y. x的工作是computer 点。 482 00:30:47,780 --> 00:30:55,570 and 不能满足这个条件: 483 00:30:55,570 --> 00:30:59,620 x有领导z,而且z的工作是computer加随便什么东西。 484 00:30:59,620 --> 00:31:04,050 好的,这一次这个x还是和这个x相等。 485 00:31:04,050 --> 00:31:05,710 这个z和这个z相等。 486 00:31:09,390 --> 00:31:11,380 你们看到了另外一种组合的方式:not(非)。 487 00:31:17,272 --> 00:31:20,880 好的,让我们再看一下。 488 00:31:20,880 --> 00:31:22,400 它工作的方式是一样的。 489 00:31:22,400 --> 00:31:33,110 我可以对机器说 x的工作是computer点y。 490 00:31:33,110 --> 00:31:35,400 computer dot y. 491 00:31:38,480 --> 00:31:46,600 x的领导是z。 492 00:31:46,600 --> 00:31:50,794 我把这些作为查询输进去。 493 00:31:50,794 --> 00:31:55,680 得到的输出是使用所有可能的答案 494 00:31:55,680 --> 00:31:58,930 填充输进去的查询。 495 00:31:58,930 --> 00:32:02,000 你们看这里有很多个答案。 496 00:32:02,000 --> 00:32:02,190 好吧。 497 00:32:02,190 --> 00:32:05,230 所以在这门语言里的组合方式是逻辑运算。 498 00:32:05,230 --> 00:32:07,550 这也是为什么它被称为逻辑语言。 499 00:32:09,800 --> 00:32:16,120 组合的方式是 AND和NOT。 500 00:32:16,120 --> 00:32:18,490 还有一个我还没讲的,OR(或)。 501 00:32:18,490 --> 00:32:24,310 我还介绍了lisp-value。 502 00:32:24,310 --> 00:32:26,365 当然它不是逻辑运算,而是一个小技巧,用于 503 00:32:26,365 --> 00:32:29,250 和LISP对接以便获得更多的功能。 504 00:32:29,250 --> 00:32:32,690 这些就是组合的方式。 505 00:32:32,690 --> 00:32:34,160 OK。 抽象的方式。 506 00:32:34,160 --> 00:32:35,410 我们想要做的是-- 507 00:32:38,330 --> 00:32:42,260 我们往回看上一张胶片。 508 00:32:42,260 --> 00:32:45,010 我们的问题很复杂, 509 00:32:45,010 --> 00:32:48,800 那些在一个部门工作, 510 00:32:48,800 --> 00:32:52,400 但是领导却不在这个部门的人。 511 00:32:52,400 --> 00:32:56,090 和之前一样,给它起个名字。 512 00:32:56,090 --> 00:32:58,800 如果一个人在某部门工作,但他的 513 00:32:58,800 --> 00:33:00,950 领导却不在这个部门工作, 514 00:33:00,950 --> 00:33:02,750 我们就叫他大腕(big shot)。 515 00:33:02,750 --> 00:33:08,370 我们定义一条规则,x满足一下条件时是一个大腕: 516 00:33:08,370 --> 00:33:16,760 x在某部门工作,同时x的领导 517 00:33:16,760 --> 00:33:19,610 在同一部门工作不成立。 518 00:33:21,510 --> 00:33:22,940 这就是我们的抽象方式。 519 00:33:22,940 --> 00:33:24,190 这是一条规则。 520 00:33:26,220 --> 00:33:27,580 一条规则有3个部分。 521 00:33:30,970 --> 00:33:33,450 这个规定了它是一条规则。 522 00:33:33,450 --> 00:33:37,530 这是规则的结论。 523 00:33:37,530 --> 00:33:40,000 这是规则的主体。 524 00:33:40,000 --> 00:33:42,150 你们可以把这个当作一条逻辑: 525 00:33:42,150 --> 00:33:46,940 如果规则的主体为真,则 526 00:33:46,940 --> 00:33:49,470 规则的结论部分也为真。 527 00:33:49,470 --> 00:33:52,640 想要得出x是一个大腕的结论, 528 00:33:52,640 --> 00:33:57,480 验证它就可以了。 529 00:33:57,480 --> 00:33:58,820 规则就是长这个样子的。 530 00:34:03,280 --> 00:34:07,180 再回去看我们休息之前我给出的 531 00:34:07,180 --> 00:34:08,110 合并的例子。 532 00:34:08,110 --> 00:34:11,610 我们看一下如果用规则来表示会是什么样子。 533 00:34:11,610 --> 00:34:14,030 我要把我给出的逻辑 534 00:34:14,030 --> 00:34:15,500 转换成一组像这样的格式的规则。 535 00:34:18,739 --> 00:34:19,350 这是一条规则。 536 00:34:19,350 --> 00:34:21,710 记住,这是“合并成为”。 537 00:34:21,710 --> 00:34:28,489 这里有一条规则:空list和y合并 538 00:34:28,489 --> 00:34:29,620 的结果是y。 539 00:34:29,620 --> 00:34:30,870 这是规则的结论。 540 00:34:33,210 --> 00:34:36,650 注意这条规则没有主体部分。 541 00:34:36,650 --> 00:34:40,010 在这门语言里,一条没有主体的规则 542 00:34:40,010 --> 00:34:41,239 永远为真。 543 00:34:41,239 --> 00:34:42,510 你可以始终认为它为真。 544 00:34:45,190 --> 00:34:47,530 这里是另外一条逻辑,它说空list中的anything 545 00:34:47,530 --> 00:34:49,460 合并得到的结果是anything。 546 00:34:49,460 --> 00:34:50,900 就是这个。 547 00:34:50,900 --> 00:34:55,510 规则:y和空list合并得到y。 548 00:34:55,510 --> 00:34:58,060 这对应于我们的合并过程中的最后两个case。 549 00:34:58,060 --> 00:35:00,890 但我们现在说的是规则,而不是过程。 550 00:35:03,490 --> 00:35:07,560 然后我们还有另外一条规则:如果你知道 551 00:35:07,560 --> 00:35:09,830 短一点的东西如何合并,你就可以把它们放到一起。 552 00:35:09,830 --> 00:35:15,340 这就是说,如果你有一个list x,y,和z,而且 553 00:35:15,340 --> 00:35:19,530 你想知道a.x--这表示常量a加上x,或者 554 00:35:19,530 --> 00:35:23,160 一个list,第一个元素是a,剩余部分是x -- 555 00:35:23,160 --> 00:35:26,230 如果你想得到它: a.x和b.y合并 556 00:35:26,230 --> 00:35:27,480 得到b.c。 557 00:35:30,570 --> 00:35:34,070 就是说你合并list a.x和b.x并且 558 00:35:34,070 --> 00:35:37,680 你将得到一个以b开始的东西-- 559 00:35:37,680 --> 00:35:41,880 如果你知道, 560 00:35:41,880 --> 00:35:48,690 a.x和y合并得到z,以及a大于b同时成立。 561 00:35:48,690 --> 00:35:52,610 于是当我们合并它们时,b会在list的前面。 562 00:35:52,610 --> 00:35:56,050 这是从我前面用伪英语描述 563 00:35:56,050 --> 00:35:57,960 的逻辑翻译过来的。 564 00:35:57,960 --> 00:35:59,870 为了更完备的描述这个问题, 565 00:35:59,870 --> 00:36:03,130 再看另一种情况。 566 00:36:03,130 --> 00:36:08,170 如果x和b.y合并等于z而且b大于a,则 567 00:36:08,170 --> 00:36:12,190 a.x和b.y合并等于a.z。 568 00:36:12,190 --> 00:36:15,610 这就是我用这门语言写的一个小程序, 569 00:36:15,610 --> 00:36:17,416 我们看一下它运行起来是什么样子。 570 00:36:21,900 --> 00:36:27,740 我把前面的合并规则输进去, 571 00:36:27,740 --> 00:36:28,510 并把它做为一个过程使用。 572 00:36:28,510 --> 00:36:39,590 我可以说:合并1,3和2,7。 573 00:36:39,590 --> 00:36:43,330 我现在就像一个lisp过程一样使用它。 574 00:36:43,330 --> 00:36:46,940 它现在需要思考一下, 575 00:36:46,940 --> 00:36:48,190 并应用这些规则。 576 00:36:50,780 --> 00:36:52,800 它找到了一个答案。 577 00:36:52,800 --> 00:36:55,370 它还要再找一找有没有别的答案。 578 00:36:55,370 --> 00:36:57,810 它事先并不知道只有一个答案。 579 00:36:57,810 --> 00:37:00,790 所以它正在检查所有的可能性, 580 00:37:00,790 --> 00:37:01,970 然后它回答:没有别的了。 581 00:37:01,970 --> 00:37:02,775 完。 582 00:37:02,775 --> 00:37:05,210 这里我像使用过程一样使用这些规则。 583 00:37:05,210 --> 00:37:08,340 记住全部的要点在于, 584 00:37:08,340 --> 00:37:10,220 我可以问不同形式的问题。 585 00:37:10,220 --> 00:37:24,590 我可以问,比如,2和a合并。 586 00:37:24,590 --> 00:37:29,440 有些2元素列表我已经知道以2开始, 587 00:37:29,440 --> 00:37:34,600 其它的我不知道,而且x和某些别的list 588 00:37:34,600 --> 00:37:39,510 合并得到a, 1, 2, 3, 4。 589 00:37:42,760 --> 00:37:44,590 它又在开始思考了。 590 00:37:44,590 --> 00:37:45,840 它会找到答案的 -- 591 00:37:48,070 --> 00:37:49,095 它找到了一个。 592 00:37:49,095 --> 00:37:53,830 它说a可以是3,x是list 1, 4. 593 00:37:53,830 --> 00:37:57,220 现在它还要继续查找,因为 594 00:37:57,220 --> 00:37:59,050 它事先并不知道 595 00:37:59,050 --> 00:38:00,300 并没有其它的可能性了。 596 00:38:03,680 --> 00:38:10,660 我前面说过,我可以问一些类似合并的问题: 597 00:38:10,660 --> 00:38:17,275 比如,谁和谁合并得到1,2,3,4,5? 598 00:38:24,340 --> 00:38:25,590 它正在思考。 599 00:38:28,490 --> 00:38:30,310 它应该会找到很多个答案。 600 00:38:35,180 --> 00:38:37,920 你们看到了,你们需要付出 601 00:38:37,920 --> 00:38:39,170 运行速度作为代价。 602 00:38:42,210 --> 00:38:43,880 有3个原因。 603 00:38:43,880 --> 00:38:47,630 首先这门语言被解释了两次。 604 00:38:47,630 --> 00:38:50,100 在现实环境中,你们会 605 00:38:50,100 --> 00:38:52,190 把它编译成原子操作。 606 00:38:52,190 --> 00:38:56,410 另一个原因是我们用的合并算法 607 00:38:56,410 --> 00:38:58,380 是双重递归的。 608 00:38:58,380 --> 00:39:01,020 所以它会占用很长的时间。 609 00:39:01,020 --> 00:39:06,710 最后,它会跑完并找到-- 610 00:39:06,710 --> 00:39:07,130 找到什么? 611 00:39:07,130 --> 00:39:08,730 第2到第5个可能的答案。 612 00:39:12,140 --> 00:39:14,830 你们看,它们的顺序是相当随机的, 613 00:39:14,830 --> 00:39:17,100 这取决于它按什么顺序 614 00:39:17,100 --> 00:39:20,160 去试验这些规则。 615 00:39:20,160 --> 00:39:21,530 实际上,当我们编辑视频时, 616 00:39:21,530 --> 00:39:24,310 会把这块的速度加快。 617 00:39:24,310 --> 00:39:26,600 你们自己做demo的时候 618 00:39:26,600 --> 00:39:28,250 也会想要把这些等待时间刨掉吧? 619 00:39:32,840 --> 00:39:34,260 它还在那里推磨呢。 620 00:39:39,220 --> 00:39:41,170 一共有32中可能呢-- 621 00:39:41,170 --> 00:39:42,630 我们不等它把所有的答案都打出来了。 622 00:39:47,850 --> 00:39:49,410 所以在这门语言里, 623 00:39:49,410 --> 00:39:50,660 抽象的方法是规则。 624 00:39:53,630 --> 00:39:57,410 我们把一堆用逻辑联系在一起的东西 625 00:39:57,410 --> 00:40:00,350 起个名字。 626 00:40:00,350 --> 00:40:02,080 你们可以把这看作是为一个 627 00:40:02,080 --> 00:40:03,410 特定的逻辑模式起名。 628 00:40:03,410 --> 00:40:05,810 或者可以把它看作是这样的:如果你想要得到某些结论, 629 00:40:05,810 --> 00:40:10,660 你可以应用那些逻辑的规则。 630 00:40:10,660 --> 00:40:13,420 这些是这门语言的三个元素。 631 00:40:13,420 --> 00:40:15,670 我们休息一下,接下来我们将要讲 632 00:40:15,670 --> 00:40:16,920 如何实现它。 633 00:40:22,747 --> 00:40:27,380 学生: 使用lisp-value一类的东西 634 00:40:27,380 --> 00:40:31,770 是否会影响我们在一个查询的两个方向间的转换? 635 00:40:31,770 --> 00:40:33,530 教授: OK, 这是一个-- 636 00:40:33,530 --> 00:40:37,840 这个问题是,使用lisp-value是否会干扰 637 00:40:37,840 --> 00:40:40,090 在查询的两个方向上转换的能力? 638 00:40:40,090 --> 00:40:43,850 我们还没有讲到具体的实现, 639 00:40:43,850 --> 00:40:46,890 但答案是“yes”,会影响的。 640 00:40:46,890 --> 00:40:50,510 一般的,我们在后面会看到的 -- 641 00:40:50,510 --> 00:40:53,330 尽管我不会进入具体的细节 -- 642 00:40:53,330 --> 00:40:58,140 这确实很复杂,尤其是当你们使用 643 00:40:58,140 --> 00:40:59,780 not(非)或lisp-value时-- 644 00:40:59,780 --> 00:41:04,310 或者说,实际上如果你们想使用任何“AND”以外的东西时, 645 00:41:04,310 --> 00:41:07,350 都会变得很复杂,很难判断 646 00:41:07,350 --> 00:41:08,700 这些东西好不好使。 647 00:41:08,700 --> 00:41:10,360 我们不能保证他们在所有的情况下都能正常工作。 648 00:41:10,360 --> 00:41:14,300 今天的后半堂课快结束时我会将这个问题。 649 00:41:14,300 --> 00:41:17,180 但你的问题的答案是:yes。 650 00:41:17,180 --> 00:41:22,000 当我们通过lisp-value获得了更多的能力时, 651 00:41:22,000 --> 00:41:24,170 我们也失去了一些逻辑编程的关键能力。 652 00:41:24,170 --> 00:41:28,090 这是一个必须接受的交换。 653 00:41:28,090 --> 00:41:30,390 OK。我们休息一下。 ================================================ FILE: SrtCN/lec8a.srt ================================================ 1 00:00:00,000 --> 00:00:02,672 Learning-SICP学习小组 倾情制作 2 00:00:18,270 --> 00:00:19,680 教授:上节课中 我们学习了 PROFESSOR: The last time we began having a look 3 00:00:19,728 --> 00:00:21,264 如何构造语言 at how languages are constructed. 4 00:00:22,416 --> 00:00:25,888 核心点就是 像Lisp这样的求值器 Remember the main point that an evaluator for, LISP, say, 5 00:00:26,080 --> 00:00:27,580 有两个主要部分 has two main elements. 6 00:00:27,580 --> 00:00:28,400 一个是EVAL There is EVAL, 7 00:00:31,040 --> 00:00:37,424 EVAL接受一个表达式EXP和环境ENV and EVAL's job is to take in an expression and an environment 8 00:00:38,912 --> 00:00:44,448 然后返回一个过程和相关的实际参数 and turn that into a procedure and some arguments 9 00:00:45,424 --> 00:00:47,056 并把它们传递给APPLY and pass that off to APPLY. 10 00:00:49,410 --> 00:00:51,296 APPLY接收这些过程和实际参数 And APPLY takes the procedure in the arguments, 11 00:00:51,696 --> 00:00:55,120 通常来说 APPLY会返回另一个表达式 turns that back into, in a general case, another expression 12 00:00:55,392 --> 00:00:57,712 返回一个在其它环境中求值的表达式 to be evaluated in another environment 13 00:00:57,744 --> 00:01:00,000 表达式就像这样在EVAL-APPLY之间传递 and passes that off to EVAL, which passes it to APPLY, 14 00:01:00,272 --> 00:01:01,440 这就是整个元循环 and there's this whole big circle 15 00:01:01,470 --> 00:01:02,944 表达式在这里面循环往复 where things go around and around and around 16 00:01:03,024 --> 00:01:06,560 直到最后求值为基本数据或基本过程 until you get either to some very primitive data or to a primitive procedure. 17 00:01:07,740 --> 00:01:09,248 这个循环要做的就是 See, what this cycle has to do with 18 00:01:09,440 --> 00:01:12,576 把语言中的组合手段 is unwinding the means of combination 19 00:01:12,590 --> 00:01:14,368 和抽象手段展开 and the means of abstraction in the language. 20 00:01:15,020 --> 00:01:17,728 比如说在Lisp中 你有一个过程 So for instance, you have a procedure in LISP-- 21 00:01:17,744 --> 00:01:20,528 定义过程是为了 a procedure is a general way of saying, 22 00:01:20,540 --> 00:01:22,576 让表达式的计算过程 I want to be able to evaluate this expression 23 00:01:22,672 --> 00:01:24,410 适用于任意的参数 for any value of the arguments, 24 00:01:25,760 --> 00:01:27,184 这就是这里面发生的事情 and that's sort of what's going on here. 25 00:01:27,670 --> 00:01:28,510 这就是APPLY做的事 That's what APPLY does. 26 00:01:28,510 --> 00:01:30,688 当一个带参数的一般性表达式进入以后 It says the general thing coming in with the arguments 27 00:01:30,720 --> 00:01:32,704 它将其归约为过程体的表达式 reduces to the expression that's the body, 28 00:01:33,056 --> 00:01:34,720 如果归约得到的是复合表达式 and then if that's a compound expression 29 00:01:34,832 --> 00:01:36,464 或者是另外的过程应用 or another procedure application, 30 00:01:36,784 --> 00:01:38,448 那么这个循环就会不断地进行 the thing will go around and around the circle. 31 00:01:40,336 --> 00:01:44,080 这基本上就是 -- 大部分解释器的基本结构了 Anyway, that's sort of the basic structure of gee, pretty much any interpreter. 32 00:01:45,200 --> 00:01:46,256 另外一点就是 The other thing that you saw 33 00:01:46,288 --> 00:01:47,660 一旦你有了一个解释器 once you have the interpreter in your hands, 34 00:01:47,696 --> 00:01:49,870 你就有了操作这门语言的所有能力 you have all this power to start playing with the language. 35 00:01:49,870 --> 00:01:51,520 因此你可以让它成为动态作用域 So you can make it dynamically scoped, 36 00:01:51,840 --> 00:01:54,560 你也可以引入正则序求值 or you can put in normal order evaluation, 37 00:01:54,590 --> 00:01:56,480 你也可以为语言添加新的形式 or you can add new forms to the language, 38 00:01:56,860 --> 00:01:57,504 想怎么样都行 whatever you like. 39 00:01:57,584 --> 00:01:58,624 或者更一般地说 Or more generally, 40 00:01:58,768 --> 00:02:01,328 这种元语言抽象的概念 there's this notion of metalinguistic abstraction, 41 00:02:02,640 --> 00:02:06,016 它告诉我们 作为一名软件工程师 which says that part of your perspective 42 00:02:07,616 --> 00:02:10,528 从广义的“工程师”的角度来看 as an engineer, as a software engineer, but as an engineer in general 43 00:02:11,392 --> 00:02:13,888 有时你可以通过发明新的语言 is that you can gain control of complexity 44 00:02:14,960 --> 00:02:17,168 来获得控制复杂度的能力 by inventing new languages sometimes. 45 00:02:18,010 --> 00:02:20,816 一种思考计算机程序设计的方法就是 See, one way to think about computer programming 46 00:02:21,552 --> 00:02:26,270 它只是偶然地让计算机执行某事儿 is that it only incidentally has to do with getting a computer to do something. 47 00:02:26,440 --> 00:02:28,976 计算机程序的主要工作却是 Primarily what a computer program has to do with, 48 00:02:29,008 --> 00:02:32,520 用来表达和交换想法 it's a way of expressing ideas with communicating ideas. 49 00:02:33,168 --> 00:02:34,048 有时 And sometimes 50 00:02:34,896 --> 00:02:36,624 当我们想要表达新的想法时 when you want to communicate new kinds of ideas, 51 00:02:36,656 --> 00:02:38,736 我们就想要发明新的模式来表达它们 you'd like to invent new modes of expressing that. 52 00:02:39,824 --> 00:02:44,992 那么 今天我们就将按照这个框架来创建新语言 Well, today we're going to apply this framework to build a new language. 53 00:02:45,730 --> 00:02:48,000 一旦我们了解了解释器的基本结构 See, once we have the basic idea of the interpreter, 54 00:02:48,032 --> 00:02:50,272 我们就可以按意愿来构造任意的语言 you can pretty much go build any language that you like. 55 00:02:50,830 --> 00:02:53,216 比如说 我们可以构造Pascal(的解释器) So for example, we can go off and build Pascal. 56 00:02:54,370 --> 00:02:55,152 以及 And... 57 00:02:56,170 --> 00:02:58,192 我们需要操心语法的表示与解析 gee, we would worry about syntax and parsing 58 00:02:58,192 --> 00:03:00,510 还有一大堆的编译器优化 and various kinds of compiler optimizations, 59 00:03:01,120 --> 00:03:03,296 还有一些人会这样做 and there are people who make honest livings doing that, 60 00:03:03,856 --> 00:03:07,600 但是就在我们所讨论的抽象层次来说 but at the level of abstraction that we're talking, 61 00:03:08,048 --> 00:03:10,992 一个Pascal语言的解释器看起来 a Pascal interpreter would not look very different at all 62 00:03:12,032 --> 00:03:13,760 跟Gerry教授上节课所讲的大同小异 from what you saw Gerry do last time. 63 00:03:15,024 --> 00:03:18,960 但是今天 我们要构建一门与众不同的语言 Instead of that, we'll spend today building a really different language, 64 00:03:20,510 --> 00:03:22,816 这门语言 a language that encourages you 65 00:03:23,056 --> 00:03:26,040 不推荐你用过程式的思维来思考程序设计 to think about programming not in terms of procedures, 66 00:03:26,240 --> 00:03:27,648 而是用一种非常不同的方式 but in a really different way. 67 00:03:29,090 --> 00:03:31,024 今天的课程呢 And the lecture today is 68 00:03:31,744 --> 00:03:34,640 将会在两个层次中同时进行 going to be at two levels simultaneously. 69 00:03:34,810 --> 00:03:35,520 一方面 On the one hand, 70 00:03:35,904 --> 00:03:37,710 我会向大家介绍这门语言是如何使用的 I'm going to show you what this language looks like, 71 00:03:38,960 --> 00:03:41,080 另一方面呢 我会带领大家实现这门语言 and on the other hand, I'll show you how it's implemented. 72 00:03:41,320 --> 00:03:42,960 我们将会用Lisp来实现 And we'll build an implementation in LISP 73 00:03:42,992 --> 00:03:43,900 并观察它的运行原理 and see how that works. 74 00:03:44,048 --> 00:03:48,256 你应该在两个层次上学到知识 And you should be drawing lessons on two levels. 75 00:03:48,688 --> 00:03:53,000 首先要认识到 语言之间可以有多么地“不同” The first is to realize just how different a language can be. 76 00:03:53,790 --> 00:03:58,144 如果你认为Fortran和Lisp算是天差地别的话 So if you think that the jump from Fortran to LISP is a big deal, 77 00:03:58,240 --> 00:03:59,360 那就小巫见大巫了 you haven't seen anything yet. 78 00:04:01,560 --> 00:04:03,680 其次 And secondly, 79 00:04:03,776 --> 00:04:06,544 甚至于在这门与众不同的语言中 you'll see that even with such a very different language, 80 00:04:07,360 --> 00:04:09,520 这门既不讨论函数 which will turn out to not have procedures at all 81 00:04:09,920 --> 00:04:11,648 也没有过程的语言中 and not talk about functions at all, 82 00:04:12,200 --> 00:04:15,720 其中也有基本的EVAL-APPLY循环 there will still be this basic cycle of eval and apply 83 00:04:16,192 --> 00:04:19,984 也就是对组合手段和抽象手段的展开 that's unwinds the means of combination and the means an abstraction. 84 00:04:20,950 --> 00:04:24,688 第三点 是一个不太重要但非常优雅的技术技巧 And then thirdly, as kind of a minor but elegant technical point, 85 00:04:24,890 --> 00:04:28,528 就是如何巧妙地使用流来避免回溯 you'll see a nice use of streams to avoid backtracking. 86 00:04:32,330 --> 00:04:34,400 好吧 我说过这门语言与众不同 OK, well, I said that this language is very different. 87 00:04:35,860 --> 00:04:36,640 为了解释这点 To explain that, 88 00:04:37,050 --> 00:04:42,816 让我们回到这门课最初的理念上 let's go back to the very first idea that we talked about in this course, 89 00:04:43,260 --> 00:04:46,544 就是要区别 and that was the idea of the distinction between 90 00:04:46,720 --> 00:04:49,520 数学中“陈述性”的知识 the declarative knowledge of mathematics-- 91 00:04:50,192 --> 00:04:54,144 比如平方根的定义就是一条数学事实 the definition of a square root as a mathematical truth-- 92 00:04:55,488 --> 00:04:59,568 而计算机科学讨论的是“如何做”的知识 and the idea that computer science talks about the how to knowledge-- 93 00:04:59,760 --> 00:05:04,592 “什么是平方根”和“如何计算平方根”是不同的 contrast that definition of square root with a program to compute a square root. 94 00:05:05,970 --> 00:05:07,072 我们是从这里开始的 That's where we started off. 95 00:05:08,512 --> 00:05:09,520 如果我们能够通过某种方式 Well, wouldn't it be great 96 00:05:09,888 --> 00:05:12,160 弥合这种差距 岂不是更好么? if you could somehow bridge this gap 97 00:05:12,810 --> 00:05:16,432 我们创建一门这样的语言 and make a programming language which sort of did things, 98 00:05:16,672 --> 00:05:21,610 以声明式的方式、用数学事实来完成计算 but you talked about it in terms of truth, in declarative terms? 99 00:05:22,380 --> 00:05:25,504 你用这种该语言来指定事实 So that would be a programming language in which you specify facts. 100 00:05:27,690 --> 00:05:28,880 你告诉它 You tell it what is. 101 00:05:28,880 --> 00:05:29,968 什么是事实 You say what is true. 102 00:05:30,950 --> 00:05:33,072 而当你需要一个答案时 And then when you want an answer, 103 00:05:33,216 --> 00:05:36,384 语言已经自动地内建了 somehow the language has built into it automatically 104 00:05:37,600 --> 00:05:39,456 有关于“如何做”的一般性知识 general kinds of how to knowledge 105 00:05:39,472 --> 00:05:40,640 这样它就可以根据你给出的事实 so it can just take your facts 106 00:05:40,896 --> 00:05:42,832 自行地演进这些方法 and it can evolve these methods on its own 107 00:05:43,312 --> 00:05:46,128 通过你给定的事实和某种一般性的逻辑规则 using the facts you gave it and maybe some general rules of logic. 108 00:05:49,330 --> 00:05:50,544 就比如说 So for instance, 109 00:05:52,064 --> 00:05:55,120 我会告诉程序下述事实 I might go up to this program and start telling it some things. 110 00:05:56,000 --> 00:06:07,080 我告诉它 (SON-OF ADAM ABEL) So I might tell it that the son of Adam is Abel. 111 00:06:08,920 --> 00:06:16,512 同时告诉它 (SON-OF ADAM CAIN) And I might tell it that the son of Adam is Cain. 112 00:06:17,660 --> 00:06:25,088 以及 (SON-OF CAIN ENOCH) And I might tell it that the son of Cain is Enoch. 113 00:06:27,792 --> 00:06:34,896 还有 (SON-OF ENOCH IRAD) And I might tell it that the son of Enoch is Irad, 114 00:06:37,024 --> 00:06:40,720 以及《创世纪》章节中的其它人物 and all through the rest of our chapter whatever of Genesis, 115 00:06:41,152 --> 00:06:43,184 最后终止于ADAH which ends up ending in Adah, by the way, 116 00:06:43,328 --> 00:06:46,784 这些是从ADAH到CAIN的家谱 and this shows the genealogy of Adah from Cain. 117 00:06:48,440 --> 00:06:50,672 总之 一旦你指明了这些事实 Anyway, once you tell it these facts, 118 00:06:52,352 --> 00:06:53,408 你就可以提出问题 you might ask it things. 119 00:06:53,510 --> 00:06:55,056 你可以对语言系统发问 You might go up to your language and say, 120 00:06:56,064 --> 00:06:59,296 谁是ADAM的孩子? who's the son of Adam? 121 00:07:00,420 --> 00:07:04,912 可以很容易地想到一个通用搜索程序 And you can very easily imagine having a little general purpose search program 122 00:07:05,520 --> 00:07:06,960 它会遍历所有的事实 which would be able to go through 123 00:07:07,008 --> 00:07:09,260 然后回答:“哦 有两个答案” and in response to that say, oh yeah, there are two answers: 124 00:07:09,296 --> 00:07:10,448 ABEL是ADAM的孩子 the son of Adam is Abel 125 00:07:10,688 --> 00:07:12,176 CAIN也是ADAM的孩子 and the son of Adam is Cain. 126 00:07:14,140 --> 00:07:14,976 你也可以这样问 Or you might say, 127 00:07:15,070 --> 00:07:16,890 基于同样的事实 based on the very same facts, 128 00:07:18,048 --> 00:07:19,952 CAIN是谁的孩子? who is Cain the son of? 129 00:07:21,950 --> 00:07:27,024 你们就会想到生成另外一个略微不同的搜索程序 And then you can imagine generating another slightly different search program 130 00:07:27,920 --> 00:07:29,216 它也会遍历所有的事实 which would be able to go through 131 00:07:29,450 --> 00:07:33,056 检查谁的孩子是CAIN and checked for who is Cain, and son of, 132 00:07:33,520 --> 00:07:34,440 发现结果是ADAM and come up with Adam. 133 00:07:35,890 --> 00:07:36,992 你也可以问 Or you might say, 134 00:07:38,016 --> 00:07:41,408 CAIN和ENOCH之间是什么关系? what's the relationship between Cain and Enoch? 135 00:07:42,070 --> 00:07:45,088 又会生成另一个略微不同的搜索程序 And again, a minor variant on that search program. 136 00:07:46,340 --> 00:07:48,160 得到的结果是亲子关系(SON-OF) You could figure out that it said son of. 137 00:07:52,880 --> 00:07:54,928 在这个非常简单的例子中 But even here in this very simple example, 138 00:07:56,144 --> 00:07:58,448 我们发现 即使是单条事实 what you see is that a single fact, 139 00:07:58,816 --> 00:08:01,520 比如说 (SON-OF ADAM CAIN) see, a single fact like the son of Adam is Cain 140 00:08:02,848 --> 00:08:05,520 可以被用来回答不同种类的问题 can be used to answer different kinds of questions. 141 00:08:06,520 --> 00:08:08,128 你可以问CAIN是谁的孩子? You can say, who's Cain the son of, 142 00:08:08,144 --> 00:08:10,928 你也可以问ADAM的孩子是谁? or you can say who's the son of Adam, 143 00:08:10,944 --> 00:08:12,864 你也可以问ADAM和CAIN之间的关系是什么? or you can say what's the relation between Adam and Cain? 144 00:08:12,880 --> 00:08:14,480 这些由不同的传统程序 Those are different questions 145 00:08:15,536 --> 00:08:18,544 所解答的不同的问题 being run by different traditional procedures 146 00:08:18,688 --> 00:08:20,720 都基于同样的事实 all based on the same fact. 147 00:08:22,752 --> 00:08:25,920 这正是这种程序设计风格的威力所在 And that's going to be the essence of the power of this programming style, 148 00:08:26,912 --> 00:08:29,504 也就是一条陈述性知识 that one piece of declarative knowledge 149 00:08:30,040 --> 00:08:34,016 可以作为大量关于“如何做”的各种知识的基础 can be used as the basis for a lot of different kinds of how-to knowledge, 150 00:08:34,816 --> 00:08:37,088 这跟我们正在编写的过程是不同的 as opposed to the kinds of procedures we're writing 151 00:08:37,152 --> 00:08:39,552 我们编写的过程描述了输入 where you sort of tell it what input you're giving in 152 00:08:39,616 --> 00:08:40,656 以及想要的输出 and what answer you want. 153 00:08:41,490 --> 00:08:44,704 比如说 我们的平方根程序可以完美地回答 So for instance, our square root program can perfectly well answer the question, 154 00:08:44,768 --> 00:08:47,168 144的平方根是多少? what's the square root of 144? 155 00:08:48,900 --> 00:08:49,776 但从原理上来说 But in principle, 156 00:08:49,824 --> 00:08:52,830 平方根的数学定义告诉了你另外的东西 the mathematical definition of square root tells you other things. 157 00:08:52,848 --> 00:08:56,430 就比如说 17是谁的平方根 Like it could say, what is 17 the square root of? 158 00:08:57,590 --> 00:08:59,712 这就需要另外一个程序来解答 And that would be have to be answered by a different program. 159 00:09:01,920 --> 00:09:03,504 因此 数学定义 So the mathematical definition, 160 00:09:03,980 --> 00:09:05,120 或者更一般地说 or in general, the 161 00:09:05,536 --> 00:09:10,300 你给定的事实 对于问题是没有偏向性的 the facts that you give it are somehow unbiased as to what the question is. 162 00:09:10,900 --> 00:09:12,816 而我们倾向于编写专门的程序 Whereas the programs we tend to write specifically 163 00:09:12,830 --> 00:09:14,208 因为它们是关于“如何做”的知识 because they are how-to knowledge 164 00:09:14,240 --> 00:09:16,368 倾向于寻找特定的答案 tend to be looking for a specific answer. 165 00:09:17,568 --> 00:09:20,120 所以这是我们正在讨论的一个特点 So that's going to be one characteristic of what we're talking about. 166 00:09:21,810 --> 00:09:22,608 然而我们可以更进一步 We can go on. 167 00:09:23,480 --> 00:09:27,520 想象一下 我们可以向语言给定一些事实 We can imagine that we've given our language some sort of facts. 168 00:09:27,710 --> 00:09:29,616 现在 我们给它一些推理规则 Now let's give it some rules of inference. 169 00:09:30,020 --> 00:09:31,360 比如说 We can say, for instance, 170 00:09:31,952 --> 00:09:36,192 这里 我们先用某种语法表示 if the-- make up some syntax here-- 171 00:09:36,448 --> 00:09:41,536 如果(SON-OF ?X ?Y)成立 if the son of x is y-- 172 00:09:41,680 --> 00:09:45,210 在这里 我用问号来标识变量 I'll put question marks to indicate variables here-- 173 00:09:45,616 --> 00:09:56,060 如果(SON-OF ?X ?Y)和(SON-OF ?Y ?Z)都成立 if the son of x is y and the son of y is z, 174 00:09:58,960 --> 00:10:08,464 那么就有(GRANSON ?X ?Z) then the grandson of x is z. 175 00:10:09,320 --> 00:10:13,408 想象一下 如果把这条规则告诉机器 So I can imagine telling my machine that rule 176 00:10:15,008 --> 00:10:17,280 那么我们就可以这么来询问 and then being able to say, for instance, 177 00:10:17,440 --> 00:10:18,688 谁是ADAM的孙子? who's the grandson of Adam? 178 00:10:20,610 --> 00:10:23,648 或者说 IRAD是谁的孙子? Or who is Irad the grandson of? 179 00:10:24,790 --> 00:10:29,088 或者从这些信息中尽可能地推断出所有的祖孙关系 Or deduce all grandson relationships you possibly can from this information. 180 00:10:31,136 --> 00:10:35,600 我们可以想象 语言知道如何自动求解 We can imagine somehow the language knowing how to do that automatically. 181 00:10:40,224 --> 00:10:45,200 好吧 我再举一个更具体一点的例子 Ok, Let me give you maybe a little bit more concrete example. 182 00:10:45,776 --> 00:10:51,952 这是个用来合并两个有序表的过程 Here's a procedure that merges two sorted lists. 183 00:10:53,920 --> 00:11:00,272 X和Y是两个由数字构成的表 So x and y are two, say, lists of numbers, 184 00:11:00,304 --> 00:11:04,208 我们可以认为它们是严格升序的表 lists of distinct numbers, if you like, that are in increasing order. 185 00:11:04,768 --> 00:11:07,530 MERGE会把这两个表 And what merge does is take two such lists 186 00:11:07,712 --> 00:11:10,384 合并成一个有序的表 and combine them into a list where everything's in increasing order, 187 00:11:11,210 --> 00:11:15,000 这个程序非常简单 and this is a pretty easy programs 188 00:11:15,024 --> 00:11:16,144 你们可以轻松地写出来 that you ought to be able to write. 189 00:11:16,390 --> 00:11:18,640 也就是 如果X为空 那么结果就是Y It says, if x is empty, the answer is y. 190 00:11:18,860 --> 00:11:20,464 如果Y为空 那结果就是X If y is empty, the answer is x. 191 00:11:21,180 --> 00:11:22,990 否则的话 就要比较为首的两个元素 Otherwise, you compare the first two elements. 192 00:11:22,990 --> 00:11:24,464 取出X中的第一个元素 So you pick out the first thing in x 193 00:11:24,848 --> 00:11:26,016 以及Y中的第一个元素 and the first thing in y, 194 00:11:26,810 --> 00:11:31,680 把它们当中谁是最小的那一个 and then depending on which of those first elements is less, 195 00:11:32,832 --> 00:11:36,608 CONS在递归地调用MERGE的结果上 you stick the lower one on to the result a recursively merging, 196 00:11:37,872 --> 00:11:39,920 要么就是(MERGE (CDR X) Y) either chopping the first one off x 197 00:11:40,112 --> 00:11:41,616 要么就是(MERGE X (CDR Y)) or chopping the first one off y. 198 00:11:42,400 --> 00:11:43,960 这是标准的程序 That's a standard kind of program. 199 00:11:46,470 --> 00:11:48,416 我们来考察下其中的逻辑 Let's look at the logic. 200 00:11:48,620 --> 00:11:49,792 先不考虑程序 Let's forget about the program 201 00:11:50,288 --> 00:11:52,768 来看看这个过程所基于的逻辑 and look at the logic on which that procedure is based. 202 00:11:53,820 --> 00:11:55,008 这其中的逻辑是 See, there's some logic which says, 203 00:11:55,024 --> 00:11:57,210 如果第一个元素较小 gee, if the first one is less, 204 00:11:57,536 --> 00:12:00,000 那么最后的结果就是把它 then we get the answer by sticking something onto the 205 00:12:00,160 --> 00:12:02,128 跟递归MERGE的结果CONS起来 the result of recursively merging the rest. 206 00:12:02,848 --> 00:12:04,096 让我们试着把 So let's try and be explicit about 207 00:12:04,240 --> 00:12:06,416 使这个程序运作的逻辑说清楚一点 what that logic is that's making the program work. 208 00:12:08,304 --> 00:12:09,440 这是一部分 So here's one piece. 209 00:12:10,130 --> 00:12:11,536 这段程序 Here's the piece of the program which 210 00:12:12,640 --> 00:12:15,264 递归地剥离X recursively chops down x 211 00:12:15,664 --> 00:12:17,824 如果X中的首元素较小的话 if the first thing in x is smaller. 212 00:12:19,980 --> 00:12:22,544 如果要显式地指出其中的逻辑的话 And if you want to be very explicit about what the logic is there, 213 00:12:23,450 --> 00:12:26,496 它其实就是演绎推理 what's really going on is a deduction, 214 00:12:26,720 --> 00:12:32,384 其中 如果知道表CDR-X和表Y which says, if you know that some list, that we'll call cdr of x, and y 215 00:12:33,290 --> 00:12:35,440 能够通过MERGE-TO-FORM形成Z merged to form z, 216 00:12:37,840 --> 00:12:41,520 并且还知道A比Y中的第一个元素小 And you know that a is less than the first thing in y. 217 00:12:43,600 --> 00:12:48,520 那么你就知道 如果你把A和CDR-X给CONS起来 then you know that if you put a onto the cdr of x. 218 00:12:49,740 --> 00:12:51,850 得到的结果和Y一起 and that result and y 219 00:12:52,608 --> 00:12:54,992 可以通过MERGE-TO-FORM形成Z merge-to-form a onto z. 220 00:12:55,820 --> 00:12:58,096 这就是它所基于的逻辑 And what that is, that's the underlying piece of logic-- 221 00:12:58,720 --> 00:12:59,952 我没有把它写成程序 I haven't written it as a program, 222 00:12:59,968 --> 00:13:02,000 我把它写成了某种演绎 I wrote it a sort of deduction 223 00:13:02,032 --> 00:13:04,896 正是属于这个特定子句的 that sits underneath this particular clause 224 00:13:05,216 --> 00:13:07,264 它告诉我们可以在这里使用递归 that says we can use the recursion there. 225 00:13:09,410 --> 00:13:12,784 同样地 这里还有些句子来补全其中的逻辑 And then similar, here's the other clause just to complete it. 226 00:13:14,000 --> 00:13:15,872 其它的句子都是基于这些逻辑 The other clause is based on this piece of logic, 227 00:13:15,920 --> 00:13:18,352 由于它们大部分是相同的 我就不细讲了 which is almost the same and I won't go through it, 228 00:13:19,008 --> 00:13:20,352 然后就是终止条件 and then there's the end cases 229 00:13:20,416 --> 00:13:22,016 是用来检查NULL的 where we tested for null, 230 00:13:22,032 --> 00:13:24,048 其基本想法是 对于任意的X and that's based on the idea that for any x, 231 00:13:24,510 --> 00:13:27,200 X和空表可以通过MERGE-TO-FORM形成X x and the empty list merge to form an x, 232 00:13:28,048 --> 00:13:30,864 而空表可以和任意的Y通过MERGE-TO-FORM形成Y or for any y, the empty list and y merge to form y. 233 00:13:33,360 --> 00:13:38,128 这就是一段过程的代码 OK, so there's a piece of procedure 234 00:13:38,432 --> 00:13:40,112 以及它所基于的逻辑 and the logic on which it's based. 235 00:13:41,740 --> 00:13:42,976 请注意其中的巨大差异 And notice a big difference. 236 00:13:45,104 --> 00:13:50,528 过程看起来是像这样的: The procedure looked like this: 237 00:13:50,656 --> 00:13:52,288 首先这有一个盒子 it said there was a box-- 238 00:13:52,860 --> 00:13:55,392 我们到目前为止所做的事都有这样的特征 and all the things we've been doing have the characteristic 239 00:13:55,408 --> 00:13:57,690 我们有一个盒子 有东西进去 也有东西出来 we have boxes and things going in and things going out-- 240 00:13:58,080 --> 00:13:59,610 这儿有个MERGE盒子 there was this box called merge, 241 00:14:01,296 --> 00:14:03,856 输入是X和Y and in came an x and y, 242 00:14:04,448 --> 00:14:05,376 输出ANS and out came an answer. 243 00:14:07,632 --> 00:14:09,488 这是我们所编写的程序的特征 That's the character of the procedure that we wrote. 244 00:14:13,024 --> 00:14:14,660 但是规则并不像这样 These rules don't look like that. 245 00:14:14,660 --> 00:14:16,768 规则讨论的是关系 These rules talk about a relation. 246 00:14:17,920 --> 00:14:24,160 也就是在幻灯片中我称作MERGE-TO-FORM的关系 There's some sort of relation that in those slides I called mrege-to-form. 247 00:14:25,370 --> 00:14:28,768 每当我说X和Y通过MERGE-TO-FORM形成Z So I said x and y merge to form z, 248 00:14:29,008 --> 00:14:32,336 这个是一个函数 and somehow this is not -- this is a function. 249 00:14:32,610 --> 00:14:32,850 对吧? Right? 250 00:14:32,850 --> 00:14:34,416 ANS是X和Y的函数 The answer is a function of x and y, 251 00:14:34,592 --> 00:14:38,192 而我这里得到的是三个东西之间的关系 and here what I have is a relation between three things. 252 00:14:39,720 --> 00:14:41,328 我不会指明 And I'm not going to specify 253 00:14:42,096 --> 00:14:43,770 哪个是输入 哪个是输出 which is the input and which is the output. 254 00:14:44,200 --> 00:14:47,408 我之所以这么说 是因为原理上 And the reason I want to say that is because in principle, 255 00:14:48,640 --> 00:14:50,832 我们可以用同样的逻辑规则 we could use exactly those same logic rules 256 00:14:50,848 --> 00:14:52,448 来回答相当多的问题 answer a lot of different questions. 257 00:14:54,570 --> 00:14:56,304 比如 我们可以问 So we can say, for instance-- giving 258 00:14:56,720 --> 00:14:59,050 想象一下 如果把这些逻辑规则输入机器 imagine giving our machine those rules of logic. 259 00:14:59,050 --> 00:15:01,200 不是输入程序 而是其中依赖的逻辑 Not the program, the underlying rules of logic. 260 00:15:01,400 --> 00:15:03,120 那么 它也就应该回答-- Then it ought to be able to say-- 261 00:15:04,752 --> 00:15:05,520 我们可以问它 we could ask it-- 262 00:15:06,736 --> 00:15:19,184 (1 3 7)和(2 4 8)可以通过MERGE-TO-FORM形成什么? 1, 3, 7 and 2, 4, 8 merge to form what? 263 00:15:20,910 --> 00:15:23,424 机器能够回答这样的问题 And that's a question it ought to be able to answer. 264 00:15:23,880 --> 00:15:27,360 这同样也是我们的Lisp程序所回答的问题 That's exactly the same question that our Lisp procedure answered. 265 00:15:28,180 --> 00:15:30,144 但这同样的规则 But the exact same rules 266 00:15:30,896 --> 00:15:34,800 也能够回答像这样的问题: should also be able to answer a question like this: 267 00:15:36,192 --> 00:15:43,248 (1 3 7)和什么能够通过MERGE-TO-FORM形成(1 2 3 4 7 8) 1, 3, 7 and what merged to form 1, 2, 3, 4, 7, 8? 268 00:15:45,560 --> 00:15:47,808 同样的逻辑规则也能够回答这个 The same rules of logic can answer this, 269 00:15:47,840 --> 00:15:49,904 但我们编写的过程却无法回答这个问题 although the procedure we wrote can't answer that question. 270 00:15:50,800 --> 00:15:52,336 又或者 我们可以问 Or we might be able to say what 271 00:15:53,710 --> 00:16:01,120 什么和什么能通过MERGE-TO-FORM what and what else merge to form-- 272 00:16:04,288 --> 00:16:12,688 哪两个东西可以通过MERGE-TO-FORM形成(1 2 3 4 7 8)? what and what else merge to form 1, 2, 3, 4, 7, 8? 273 00:16:13,780 --> 00:16:15,344 机器能够进行遍历 And the thing should be able to go through, 274 00:16:15,840 --> 00:16:17,312 如果它能应用这些逻辑规则的话 if it really can apply that logic, 275 00:16:17,792 --> 00:16:22,540 就能够推断出这个问题所有的2^6种答案 and deduce all, whatever is, 2 to the sixth answers to that question. 276 00:16:25,600 --> 00:16:27,690 因为可以分别是 (1)和其余的 Cause it could be 1 and the rester, or it could be 1, 2 and the rest. 277 00:16:27,696 --> 00:16:28,752 也可以是 (1 2)和其余的 or it could be 1, 2 and the rester. 278 00:16:28,790 --> 00:16:31,536 也可以是(1 3 7)和其余的 Or it could be 1 and 3 and 7 and the rest. 279 00:16:32,016 --> 00:16:33,264 有一大堆的答案 There's a whole bunch of answers. 280 00:16:33,410 --> 00:16:37,760 但原理上来说 逻辑能推断出所有的答案 And in principle, the logic should be enough to deduce that. 281 00:16:38,550 --> 00:16:42,032 因此这里面就有两个巨大的不同 So there are going to be two big differences 282 00:16:44,048 --> 00:16:46,000 在我们所编写的程序中 in the kind of program we're going to look at 283 00:16:46,540 --> 00:16:48,192 不只是Lisp程序 and not only Lisp, 284 00:16:48,208 --> 00:16:50,560 基本上是你们目前编写过的所有程序 but essentially all the programming you've probably done so far 285 00:16:52,032 --> 00:16:53,600 用你能叫出名字的程序语言所编写的程序 in pretty much any language you can think of. 286 00:16:54,150 --> 00:16:57,792 首先 我们并不准备计算一个函数 The first is, we're not going to be computing functions. 287 00:17:00,620 --> 00:17:02,016 我们将要讨论的东西 We're not going to be talking about 288 00:17:02,624 --> 00:17:04,410 并不具有输入和输出 about things that take input and output. 289 00:17:04,410 --> 00:17:05,824 我们讨论的是关系 We're going to be talking about relations. 290 00:17:06,890 --> 00:17:10,000 也就是说 原理上 关系是没有方向性的 And that means in principle, these relations don't have directionality. 291 00:17:11,080 --> 00:17:15,056 所以你指明用来回答这个问题的知识 So the knowledge that you specify to answer this question, 292 00:17:16,460 --> 00:17:18,416 也同样应该能够反过来 should be same, that same knowledge 293 00:17:18,432 --> 00:17:21,800 让你回答其它的这些问题 also allow you to answer these other questions and conversely. 294 00:17:26,608 --> 00:17:29,408 其次则是 And the second issue is that 295 00:17:29,616 --> 00:17:31,232 因为我们讨论的是关系 since we're talking about relations, 296 00:17:32,320 --> 00:17:34,448 关系的答案并不唯一 these relations don't necessarily have one answer. 297 00:17:35,610 --> 00:17:37,008 所以在第三个问题中 So that third question down there 298 00:17:37,020 --> 00:17:38,360 并没有特定的答案 doesn't have a particular answer, 299 00:17:38,400 --> 00:17:39,584 它有很多的答案 it has a whole bunch of answers. 300 00:17:42,270 --> 00:17:44,640 这就是我们的目标 Well, that's where we're going. 301 00:17:44,640 --> 00:17:45,904 顺便说一下 This style of programming, 302 00:17:46,720 --> 00:17:49,216 这种程序设计风格被称作逻辑式程序设计 by the way, is called logic programming, 303 00:17:50,224 --> 00:17:51,584 原因是显而易见的 for kind of obvious reasons. 304 00:17:56,160 --> 00:18:00,384 用逻辑式进行程序设计的那群人之间 And people who do logic programming say that -- 305 00:18:00,400 --> 00:18:03,150 流传着几句箴言 they have this little phrase-- 306 00:18:03,168 --> 00:18:04,672 他们把逻辑式程序设计的要点归纳为 they say the point of logic programming 307 00:18:04,768 --> 00:18:09,008 用逻辑来表达 什么算是“真的” is that you use logic to express what is true, 308 00:18:10,096 --> 00:18:13,888 用逻辑来检测 是否是“真的” you use logic to check whether something is true, 309 00:18:14,672 --> 00:18:17,248 用逻辑来找出这些“真的” and you use logic to find out what is true. 310 00:18:19,200 --> 00:18:22,096 最为大家所熟知的逻辑式程序设计语言 The best known logic programming language, 311 00:18:22,976 --> 00:18:24,784 你们可能也听过 -- 叫做Prolog as you probably know, is called Prolog. 312 00:18:25,780 --> 00:18:28,880 今天早上我们将要实现的这门语言 The language that we're going to implement this morning 313 00:18:29,824 --> 00:18:32,320 是一种查询语言 is something we call the query language, 314 00:18:32,480 --> 00:18:34,416 它基本上就是Prolog的本质了 and it essentially has the essence of prolog. 315 00:18:35,320 --> 00:18:36,736 它可以完成相同的工作 It can do about the same stuff, 316 00:18:37,290 --> 00:18:38,736 虽然它比Prolog慢得多 although it's a lot slower 317 00:18:38,736 --> 00:18:40,010 这是因为我们是通过Lisp来解释的 because we're going to implement it in LISP 318 00:18:41,904 --> 00:18:44,368 而非构造一个专门的编译器 rather than building a particular compiler. 319 00:18:44,464 --> 00:18:46,624 对它的解释 将运行在Lisp解释器之上 We're going to interpret it on top of the LISP interpreter. 320 00:18:47,510 --> 00:18:49,840 除此之外 它可以完成与Prolog相同的事儿 But other than that, it can do about the same stuff as prolog. 321 00:18:49,888 --> 00:18:52,784 不但同样的能力 也有同样的局限 It has about the same power and about the same limitations. 322 00:18:55,088 --> 00:18:56,176 好吧 先解答一下疑惑 All right, let's break for question. 323 00:19:00,430 --> 00:19:02,848 学生:您能再重复一下 AUDIENCE: Yes, could you please repeat what the three 324 00:19:03,488 --> 00:19:06,090 用逻辑去寻找的三件事么? things you use logic programming to find? 325 00:19:06,720 --> 00:19:09,840 就是那些 找出什么为真 知道什么是真 等等 In other words, to find what is true, learn what is true-- what is the? 326 00:19:09,840 --> 00:19:10,520 教授:好的 PROFESSOR: Right. 327 00:19:10,560 --> 00:19:15,744 这算是程序员的某种“教义问答” Sort of a logic programmer's little catechism. 328 00:19:15,850 --> 00:19:19,160 我们用逻辑来表达怎么算是“真的” You use logic to express what is true, 329 00:19:20,800 --> 00:19:21,792 就像这些规则一样 like these rules. 330 00:19:22,610 --> 00:19:25,568 我们用逻辑来检测某事是否是“真的” You use logic to check whether something is true, 331 00:19:25,600 --> 00:19:27,760 但在这里我没有回答这个问题 and that's the kind of question I didn't answer here. 332 00:19:28,550 --> 00:19:29,296 我可以问 I might say-- 333 00:19:29,680 --> 00:19:32,144 在这里我可以这样来问 another question I could put down here is to say, 334 00:19:33,264 --> 00:19:36,560 (1 3 7)和(2 4 8)是否能够 is it true that 1, 3, 7 and 2, 4, 8 335 00:19:36,910 --> 00:19:40,380 通过MERGE-TO-FORM形成(1 2 6 19) merge to form 1, 2, 6, 10 336 00:19:41,120 --> 00:19:44,688 同样的逻辑规则会告诉我们不行 And that same logic should be enough to say no. 337 00:19:45,690 --> 00:19:47,936 这里 我使用逻辑来检测是否为真 So I use logic to check what is true, 338 00:19:48,288 --> 00:19:50,480 然后 我们也可以使用逻辑来找出为真的东西 and then you also use logic to find out what's true. 339 00:20:04,464 --> 00:20:05,168 休息一下吧 Let's break. 340 00:20:06,130 --> 00:20:17,024 [音乐] [JESU, JOY OF MAN'S DESIRING] 341 00:20:17,050 --> 00:20:20,688 《计算机程序的构造和解释》 342 00:20:47,590 --> 00:20:51,024 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 343 00:20:51,070 --> 00:20:55,600 《计算机程序的构造和解释》 344 00:20:55,630 --> 00:21:00,688 逻辑式程序设计 345 00:21:03,248 --> 00:21:04,976 教授:让我们继续来看一看 PROFESSOR: OK, let's go ahead and 346 00:21:05,840 --> 00:21:08,448 这个查询语言及其操作 take a look at this query language and operation. 347 00:21:10,520 --> 00:21:11,840 首先需要注意到 The first thing you might notice, 348 00:21:12,240 --> 00:21:14,144 当我建立好那个小型的圣经数据库后 when I put up that little biblical database, 349 00:21:14,160 --> 00:21:17,240 我们就能够针对一系列的事实 is that it's nice to be able to ask this language questions 350 00:21:17,488 --> 00:21:19,920 以关系的方式来向这个语言提问 in relation to some collection of facts. 351 00:21:21,330 --> 00:21:25,152 因此 我们先来陈述一些事实 So let's start off and make a little collection of facts. 352 00:21:26,060 --> 00:21:29,680 这是波士顿一家高科技公司的 This is a tiny fragment of personnel records 353 00:21:30,080 --> 00:21:32,624 一小部分人事档案 for a Boston high tech company, 354 00:21:33,056 --> 00:21:36,800 这部分档案是Ben Bitdiddle的 and here's a piece of the personnel records of Ben Bitdiddle. 355 00:21:37,500 --> 00:21:41,952 Bitdiddle是这家公司的计算机向导 And Ben Bitdiddle is the computer wizard in this company, 356 00:21:42,848 --> 00:21:45,808 他是这家公司的低薪向导 he's the underpaid computer wizard in this company. 357 00:21:46,420 --> 00:21:48,784 他的上司是Oliver Warbucks His supervisor is all Oliver Warbucks, 358 00:21:49,280 --> 00:21:50,704 这里是他的住址 and here's his address. 359 00:21:52,150 --> 00:21:56,544 我们按照这样的格式给出信息:职务、薪水、上司、住址 So the format is we're giving this information: job, salary, supervisor, address. 360 00:21:57,568 --> 00:21:59,250 还有一些其它的约定 And there are some other conventions. 361 00:21:59,250 --> 00:22:02,224 这里的COMPUTER表示BEN在计算机分部工作 Computer here means that Ben works in the computer division, and 362 00:22:02,768 --> 00:22:04,944 而他在这个分部的工作是向导 his position in the computer division is wizard. 363 00:22:05,660 --> 00:22:07,152 这里是其他人的 Here's somebody else. 364 00:22:07,168 --> 00:22:12,280 ALyssa P.Hacker是一名计算机程序员 Alyssa, Alyssa P. Hacker is a computer programmer, 365 00:22:13,360 --> 00:22:14,608 她的上司是Ben and she works for Ben, 366 00:22:15,216 --> 00:22:16,544 而她住在Cambridge and she lives in Cambridge. 367 00:22:17,550 --> 00:22:19,424 Ben手下的另外一个程序员 And there's another programmer who works for Ben 368 00:22:20,032 --> 00:22:21,440 叫做Lem E. Tweakit who's Lem E. Tweakit. 369 00:22:22,820 --> 00:22:26,736 实习程序员 Louis Reasoner And there's a programmer trainee, who is Louis Reasoner, 370 00:22:27,424 --> 00:22:28,624 在Alyssa手下工作 and he works for Alyssa. 371 00:22:30,100 --> 00:22:35,456 公司里的“大老板”不为任何人工作 And the big wheel of the company doesn't work for anybody. 372 00:22:36,816 --> 00:22:38,110 这就是Oliver Warbucks的档案了 Right, That's Oliver Warbucks. 373 00:22:38,110 --> 00:22:39,312 我们将要做的就是 Anyway, what we're going to do is 374 00:22:40,944 --> 00:22:43,664 对这个小型的世界提问 is ask questions about that little world. 375 00:22:44,970 --> 00:22:48,400 这将是我们进行逻辑运算的样本世界 And that'll be a sample world that we're going to do logic in. 376 00:22:51,420 --> 00:22:54,960 我再最后一次强调一下 Let me just write up here, for probably the last time, 377 00:22:55,600 --> 00:22:58,208 你们应该从这门课中学到的最重要的知识 what I said is the very most important thing you should get out of this course, 378 00:22:58,800 --> 00:23:01,664 也就是 当别人向你介绍语言时 and that is, when somebody tells you about a language, 379 00:23:02,256 --> 00:23:04,432 你要问:“它的基本元素是什么?” you say, fine-- what are the primitives, 380 00:23:06,120 --> 00:23:07,790 组合的手段有哪些? what are the means of combination, 381 00:23:14,704 --> 00:23:16,400 如何把基本元素组织在一起 how do you put the primitives together, 382 00:23:16,672 --> 00:23:19,376 然后把它们抽象出来? and then how do you abstract them, 383 00:23:19,968 --> 00:23:21,936 如何抽象这些复合元素 how do you abstract the compound pieces 384 00:23:24,688 --> 00:23:27,584 以便于你能够复用它们构造更复杂的东西? so you can use them as pieces to make something more complicated? 385 00:23:29,024 --> 00:23:30,816 我已经强调过很多次了 And we've said this a whole bunch of times already, 386 00:23:31,168 --> 00:23:32,480 但还是值得重申一遍 but it's worth saying again. 387 00:23:35,008 --> 00:23:36,670 记住了么?我们开始了 OKay? Let's start. 388 00:23:36,670 --> 00:23:37,344 首先是基本元素 The primitives. 389 00:23:37,776 --> 00:23:39,440 这其中 只有唯一的基本元素 Well, there's really only one primitive, 390 00:23:40,960 --> 00:23:43,200 这门语言中的基本元素就是“查询” and the primitive in this language is called a query. 391 00:23:44,144 --> 00:23:45,744 一条基本查询 A primitive query. 392 00:23:46,810 --> 00:23:48,256 我们先来看几条基本查询 Let's look at some primitive queries. 393 00:23:51,824 --> 00:23:53,024 首先 这条查询问的是 Alright. Job x. 394 00:23:53,100 --> 00:23:54,816 “谁是计算机程序员?” Who is a computer programmer? 395 00:23:55,550 --> 00:23:59,888 或者可以解释为:找出数据库中 Or find every fact in the database 396 00:24:01,552 --> 00:24:06,144 所有JOB栏为COMPUTER PROGRAMMER的事实 that matches job of the x is computer programmer. 397 00:24:06,640 --> 00:24:08,016 这里有一些小语法 And you see a little syntax here. 398 00:24:08,470 --> 00:24:10,592 不带问号的都是字面量 Things without question marks are meant to be literal, 399 00:24:11,280 --> 00:24:13,152 ?X表示X是变量 question mark x means that's a variable, 400 00:24:13,312 --> 00:24:15,568 而这条查询会匹配 比如说 -- and this thing will match, for example, 401 00:24:16,032 --> 00:24:19,008 Alyssa P. Hacker 是程序员 the fact that Alyssa P. Hacker is a computer programmer, 402 00:24:19,280 --> 00:24:21,930 其中X为Alyssa P. Hacker这条事实 or x is Alyssa P. Hacker. 403 00:24:26,820 --> 00:24:29,984 或者更一般地 我可以在一条查询中引入两个变量 Or more generally, I could have something with two variables in it. 404 00:24:30,750 --> 00:24:31,456 我可以问 I could say, 405 00:24:31,600 --> 00:24:35,888 ?X的JOB必须是COMPUTER ?TYPE the job of x is computer something, 406 00:24:39,344 --> 00:24:41,392 也就是会匹配COMPUTER WIZARD and that'll match computer wizard. 407 00:24:42,140 --> 00:24:44,288 所以这里?TYPE可能会匹配WIZARD So there's something here: type will match wizard, 408 00:24:44,928 --> 00:24:46,464 也可能会匹配PROGRAMMER or type will match programmer, 409 00:24:47,488 --> 00:24:50,370 而?X会匹配不同的东西 or x might match various certain things. 410 00:24:50,370 --> 00:24:52,240 但在我们的这个小例子中 So there are, in our little example, 411 00:24:52,256 --> 00:24:55,150 数据库中只有三条事实符合那条查询 only three facts in that database that match that query. 412 00:24:59,120 --> 00:25:02,080 把语法说得再清楚一点 同样的查询 Let's see, just to show you some syntax, the same query, 413 00:25:05,296 --> 00:25:08,096 同样的这条指定了?X的JOB的查询 this query doesn't match the job of x, 414 00:25:09,856 --> 00:25:11,792 并不能够与Lewis Reasoner匹配 doesn't match Lewis Reasoner, 415 00:25:11,840 --> 00:25:13,648 这是因为我这里所写的 the reason for that is when I write something here, 416 00:25:14,224 --> 00:25:17,744 表示要匹配的是由两个符号构成的表 what I mean is that this is going to be a list of two symbols, 417 00:25:19,968 --> 00:25:21,968 其中首元素必须为单词“COMPUTER” of which the first is the word computer, 418 00:25:22,320 --> 00:25:23,808 而第二个可以匹配任意的东西 and the second can be anything. 419 00:25:25,080 --> 00:25:27,320 而Lewis这里的工作描述有三个符号 And Lewis's job description here has three symbols, 420 00:25:27,808 --> 00:25:28,832 因此不匹配 so it doesn't match. 421 00:25:30,340 --> 00:25:32,192 你们还需要知道的一种语法是 And just to show you a little bit of syntax, 422 00:25:35,040 --> 00:25:38,320 更具一般性的点记号 the more general thing I might want to type is a thing with a dot here, 423 00:25:40,176 --> 00:25:42,928 这个标准的表记号表示的是 and this is just standard list notation for saying, 424 00:25:43,040 --> 00:25:43,824 首先这是一个表 this is a list, 425 00:25:44,128 --> 00:25:47,320 它的首元素为单词“COMPUTER” of which the first element is the word computers, 426 00:25:47,584 --> 00:25:50,224 而其余的部分 我们把它们称作?TYPE and THE REST, is something that I'll call type. 427 00:25:53,730 --> 00:25:55,504 因此这条查询就会匹配上 So this one would match. 428 00:25:56,930 --> 00:25:59,312 Lewis的工作是COMPUTER PROGRAMMER TRAINEE Lewis's job is computer programmer trainee, 429 00:25:59,440 --> 00:26:03,296 而?TYPE的值将会是这个表的CDR部分 and type here would be the cdr of this list. 430 00:26:03,328 --> 00:26:05,648 也就是表(PROGRAMMER TRAINEE) It would be the list programmer trainee. 431 00:26:06,960 --> 00:26:10,460 Lisp源码读取器会自动完成对点记号的处理 And that kind of dot processing is done automatically by the LISP reader. 432 00:26:15,900 --> 00:26:17,760 让我们来实际操作一下 Well, let's actually try this. 433 00:26:17,760 --> 00:26:20,512 我将向语言系统输入这些查询 The idea is I'm going to type in queries in this language, 434 00:26:20,768 --> 00:26:21,824 然后得到结果 and answers will come out. 435 00:26:22,544 --> 00:26:24,480 让我们在计算机中试试 Let's look at this. 436 00:26:25,180 --> 00:26:26,512 我可以问 I can go up and say, 437 00:26:27,344 --> 00:26:28,880 谁在计算机分部工作? who works in the computer division? 438 00:26:30,000 --> 00:26:38,224 (JOB ?X (COMPUTER . ?Y) Job of x is computer dot y. 439 00:26:39,730 --> 00:26:41,488 哑变量的名字并不重要 Doesn't matter what I call the dummy variables. 440 00:26:42,768 --> 00:26:44,144 查询的结果是 It says the answers to that, 441 00:26:44,416 --> 00:26:45,680 有四条记录 and it's found four answers. 442 00:26:48,650 --> 00:26:50,096 我也可以问 Or I can go off and say, 443 00:26:50,560 --> 00:26:52,384 大家的上司都是谁? tell me about everybody's supervisor. 444 00:26:52,816 --> 00:26:54,880 我输入一条基本查询 So I'll put in the query, the primitive query, 445 00:26:56,528 --> 00:26:59,390 (SUPERVISOR ?X ?Y) the supervisor of x is y. 446 00:27:02,560 --> 00:27:05,424 这些都是我所知道的上下级关系 There are all the supervisor relationships I know. 447 00:27:05,540 --> 00:27:08,830 或者我也可以问:“谁住在Cambridge?” Or I could go type in, who lives in Cambridge? 448 00:27:08,830 --> 00:27:09,472 我就这么输入: So I can say, 449 00:27:10,240 --> 00:27:20,928 (ADDRESS ?X (CAMBRIDGE . ?T)) the address of x is Cambridge dot anything. 450 00:27:25,090 --> 00:27:26,896 只有一个人住在Cambridge And only one person lives in Cambridge. 451 00:27:30,820 --> 00:27:32,170 这些就是基本查询 OK, so those are primitive queries. 452 00:27:32,170 --> 00:27:34,960 你们看到的这些 就是与系统的基础交互 And you see what happens to basic interaction with the system 453 00:27:35,296 --> 00:27:39,248 你输入一条查询 他输出所有可能的查询 is you type in a query, and it types out all possible answers. 454 00:27:39,620 --> 00:27:40,656 换句话说 也就是 Or another way to say that: 455 00:27:40,670 --> 00:27:44,160 它找出这些变量所有可能的值 it finds out all the possible values of those variables 456 00:27:44,192 --> 00:27:45,872 不管它是叫X、Y还是T x and y or t or whatever I've called them, 457 00:27:46,096 --> 00:27:52,080 然后它输出的是用所有可行值实例化该条查询的结果 and it types out all ways of taking that query and instantiating it-- 458 00:27:52,920 --> 00:27:55,168 也就是规则系统那一课讲的“实例化” remember that from the rule system lecture-- 459 00:27:55,168 --> 00:27:58,830 用变量所有可能的值来实例化查询 instantiates the query with all possible values for those variables 460 00:27:59,008 --> 00:28:00,352 然后输出所有的结果 and then types out all of them. 461 00:28:01,000 --> 00:28:03,350 当然 还有不同的呈现结果的方式 And there are a lot of ways you can arrange a logic language. 462 00:28:03,350 --> 00:28:06,010 比如说 Prolog就有些不一样 Prolog, for instance, does something slightly different. 463 00:28:06,010 --> 00:28:07,440 它并不向你返回查询 Rather than typing back your query, 464 00:28:07,760 --> 00:28:10,784 Prolog会输出X=这个 Y=那个 prolog would type out, x equals this and y equals that, 465 00:28:10,976 --> 00:28:12,944 又或者X=这个 Y=那个 or x equals this and y equals that. 466 00:28:13,660 --> 00:28:15,488 这是使用界面层次的差别 And that's a very surface level thing, 467 00:28:15,712 --> 00:28:17,050 你可以根据你的喜好来决定 you can decide what you like. 468 00:28:18,976 --> 00:28:19,584 我们继续 OK. 469 00:28:21,008 --> 00:28:22,688 也就是说 这个语言中的基本元素 Alright. So the primitives in this language? 470 00:28:23,390 --> 00:28:24,570 只有一个 对吧? Only one, right? 471 00:28:24,570 --> 00:28:27,230 也就是基本查询 Primitive query. 472 00:28:31,312 --> 00:28:32,560 来看看组合的手段 Means of combination. 473 00:28:34,330 --> 00:28:37,680 我们来考察一下这个语言中的复合查询 Let's look at some compound queries in this language. 474 00:28:39,770 --> 00:28:40,464 比如这条 Here's one. 475 00:28:41,790 --> 00:28:42,512 这条查询是说 This one says, 476 00:28:45,056 --> 00:28:48,224 列举出所有在计算机分部工作的人 tell me all the people who work in the computer division. 477 00:28:49,810 --> 00:28:52,000 在计算机分部工作的人 Tell me all the people who work in the computer division 478 00:28:52,544 --> 00:28:53,960 以及他们的上司 together with their supervisors. 479 00:28:56,800 --> 00:28:58,832 我使用AND来编写这条查询 Where I write that is the query is and. 480 00:29:00,220 --> 00:29:04,064 (AND (JOB ?X (COMPUTER . ?Y)) And the job of the x is computer something or other. 481 00:29:04,920 --> 00:29:06,832 (JOB ?X (COMPUTER . ?Y)) And job of x is computer dot y. 482 00:29:07,560 --> 00:29:10,032 并且(SUPERVISOR ?X ?Z) And the supervisor of x is z. 483 00:29:11,440 --> 00:29:14,160 找出所有在计算机分部工作的人 -- 对应这条 Tell me all the people in the computer division-- that's this-- 484 00:29:14,304 --> 00:29:15,888 以及它们的上司 together with their supervisors. 485 00:29:16,460 --> 00:29:17,824 注意这条查询中 And notice in this query 486 00:29:18,672 --> 00:29:22,416 我引入了三个变量 ?X ?Y 以及 ?Z I have three variables-- x, y, and z. 487 00:29:23,584 --> 00:29:28,656 并且 这两个?X应该匹配同样的东西 And this x is supposed to be the same as that x. 488 00:29:29,450 --> 00:29:31,168 ?X被约束在了计算机分部中 So x works in the computer division, 489 00:29:31,312 --> 00:29:33,008 并且?X的上司是?Z and the supervisor of x is z. 490 00:29:34,810 --> 00:29:35,808 我们再来看一条 Let's try another one. 491 00:29:37,250 --> 00:29:39,280 AND算是一种组合手段 So one means of combination is and. 492 00:29:41,440 --> 00:29:43,968 哪些人的薪水超过$30,000? Who are all the people who make more than $30,000? 493 00:29:45,712 --> 00:29:51,712 (AND (SALARY ?P ?A) And the salary of some person p is some amount a. 494 00:29:54,590 --> 00:29:57,456 而关于?A的要求则是 And when I go and look at a, 495 00:29:57,488 --> 00:30:00,128 (LISP-VALUE > ?A 300000) a is greater than $30,000. 496 00:30:00,600 --> 00:30:03,232 这里的LISP-VALUE是一个接口 And LISP value here is a little piece of interface 497 00:30:04,304 --> 00:30:10,048 用来连接查询语言与其底层的Lisp that interfaces the query language to the underlying LISP. 498 00:30:10,600 --> 00:30:12,720 LISP-VALUE让你能够在查询 And what the LISP value allows you to do 499 00:30:12,752 --> 00:30:16,912 中调用任意的Lisp谓词 call any LISP predicate inside a query. 500 00:30:17,180 --> 00:30:20,112 因为我要用Lisp中的谓词> 所以我用LISP-VALUE So here I'm using the LISP predicate greater than, so I say LISP value. 501 00:30:21,020 --> 00:30:21,750 所以这里我用了AND This I say and. 502 00:30:21,750 --> 00:30:24,480 因此这样就查询出了薪水超过$30000的人 So all the people whose salary is greater than $30,000. 503 00:30:28,190 --> 00:30:30,032 或者这条更复杂的查询 Or here's a more complicated one. 504 00:30:31,270 --> 00:30:35,024 告诉我所有那些 在计算机分部中工作 Tell me all the people who work in the computer division 505 00:30:36,256 --> 00:30:39,360 但他的上司不在计算机分部工作的人 who do not have a supervisor who works in the computer division. 506 00:30:42,790 --> 00:30:45,510 (AND (JOB ?X (COMPUTER . ?Y)) and x works in the computer division. 507 00:30:45,510 --> 00:30:47,328 表示?X在计算机分部工作 The job of x is computer dot y. 508 00:30:47,780 --> 00:30:49,248 但是呢 And it's not the case 509 00:30:50,496 --> 00:30:54,256 ?X的上司?Z that both x has a supervisor z 510 00:30:55,376 --> 00:30:57,872 ?Z的JOB不是形如(COMPUTER ...)一类的 and the job of z is computer something or other. 511 00:30:59,620 --> 00:31:00,352 同样的 All right, so again, 512 00:31:00,512 --> 00:31:02,384 这两个?X应该是一致的 this x has got to be that x, 513 00:31:03,200 --> 00:31:05,760 而这两个?Z也应该是一致的 and this z is going to be that z. 514 00:31:09,390 --> 00:31:11,380 你又了解了另一种组合手段 -- NOT And then you see another means a combination, not. 515 00:31:17,712 --> 00:31:18,672 好了 再让我们来试试这些 All right, well, let's look at that. 516 00:31:20,880 --> 00:31:22,080 它同样起效 It works the same way. 517 00:31:22,400 --> 00:31:24,128 我可以问计算机: I can go up to the machine and say 518 00:31:26,896 --> 00:31:35,400 (AND (JOB ?X (COMPUTER . ?Y))) and the job of the x is computer dot y. 519 00:31:38,848 --> 00:31:45,952 另一个条件是(SUPERVISOR ?X ?Z) And the supervisor of x is z. 520 00:31:46,832 --> 00:31:49,536 我把这条查询输入进去 And I typed that in like a query. 521 00:31:51,072 --> 00:31:52,976 计算机返回给我们的 And what it types back, 522 00:31:54,000 --> 00:31:58,736 计算机利用所有可能的答案把我的查询实例化了 what you see are the queries I typed in instantiated by all possible answers. 523 00:31:58,930 --> 00:32:00,080 你会发现有很多的答案 And then you see there are a lot of answers. 524 00:32:01,696 --> 00:32:02,144 好 All right. 525 00:32:02,190 --> 00:32:04,048 之所以把这门语言称作“逻辑语言” So the means of combination in this language-- 526 00:32:05,216 --> 00:32:06,608 是因为这门语言中的组合手段 and this is why it's called a logic language-- 527 00:32:06,640 --> 00:32:09,472 都是逻辑运算 are logical operations. 528 00:32:09,800 --> 00:32:15,680 组合的手段有AND和NOT Means of combinations are things like AND and NOT 529 00:32:15,968 --> 00:32:17,920 以及我还没有告诉你的OR and there's one I didn't show you, which is OR. 530 00:32:18,490 --> 00:32:20,368 我还告诉过你LISP-VALUE And then I showed you LISP value, 531 00:32:20,720 --> 00:32:24,480 当然 虽然它不是一个逻辑运算 which is a, not logic, of course, 532 00:32:24,512 --> 00:32:26,896 但是这个特殊的小技巧把它跟Lisp连接在了一起 but is a little special hack to interface that to LISP 533 00:32:27,344 --> 00:32:28,752 让你获得了更多的力量 so you can get more power. 534 00:32:29,250 --> 00:32:30,672 这些就是组合手段 Those are the means of combination. 535 00:32:32,592 --> 00:32:33,984 好 接着是抽象手段 OK, the means of abstraction. 536 00:32:34,160 --> 00:32:35,216 我们想要的是 What we'd like to do-- 537 00:32:38,272 --> 00:32:41,248 想让我们回过头来看上一张幻灯片 let's go back for second and look at that last slide. 538 00:32:42,260 --> 00:32:44,256 我们想要把一些非常复杂的东西 We might like to take very complicated thing, 539 00:32:44,460 --> 00:32:48,000 比如不与上司在同一部门工作 the idea that someone works in a division 540 00:32:48,016 --> 00:32:50,090 的人的这种概念 but does not have a supervisor in the division. 541 00:32:52,400 --> 00:32:55,104 像以前一样 给它命名 And as before, name that. 542 00:32:56,090 --> 00:32:58,128 如果在某个分部工作的人 Well, if someone works in a division 543 00:32:58,176 --> 00:33:00,250 他的上司却不在那个分部工作 and does not have a supervisor who works in that division, 544 00:33:00,480 --> 00:33:01,936 这就意味着他是个“大腕” that means that person is a big shot. 545 00:33:02,750 --> 00:33:05,136 这样 我们就定义一条规则指明 So let's make a rule that 546 00:33:06,432 --> 00:33:09,168 如果?X是某个部门的BIGSHOT somebody x is a big shot in some department 547 00:33:10,912 --> 00:33:14,688 如果他在该部门工作 if x works in the department 548 00:33:16,048 --> 00:33:20,080 并且他的上司不在该部门工作 and it's not the case that x has a supervisor who works in the department. 549 00:33:21,510 --> 00:33:22,940 因此这就是我们的抽象手段 So this is our means of abstraction. 550 00:33:22,940 --> 00:33:23,904 这是一条规则 This is a rule. 551 00:33:26,220 --> 00:33:27,580 规则由三部分构成 And a rule has three parts. 552 00:33:31,008 --> 00:33:32,480 关键字RULE表明这是一条规则 The thing that says it's a rule. 553 00:33:33,408 --> 00:33:35,488 接着是规则的结论 And then there's the conclusion of the rule. 554 00:33:37,530 --> 00:33:39,072 然后是规则的体 And then there's the body of the rule. 555 00:33:40,000 --> 00:33:41,888 你可以把它解读为这样的一段逻辑: And you can read this as a piece of logic which says, 556 00:33:41,920 --> 00:33:45,150 如果你知道规则的体为真 if you know that the body of the rule is true, 557 00:33:46,400 --> 00:33:48,720 那么你就可以推导出结论为真 then you can conclude that the conclusion is true. 558 00:33:49,456 --> 00:33:53,280 或者说为了推断出?X是某个部门的“大腕” Or in order to deduce that x is a big shot in some department, 559 00:33:53,792 --> 00:33:55,712 这些条件足够验证了 it's enough to verify that. 560 00:33:57,480 --> 00:33:58,820 这就是规则的形式 So that's what rules look like. 561 00:34:03,280 --> 00:34:06,160 让我们回过头来看看 Let's go back and look at that merge example 562 00:34:06,736 --> 00:34:07,920 课间休息前我举的那个例子 that I did before the break. 563 00:34:08,110 --> 00:34:10,688 我们来看看 如果用规则来描述会是什么样的 Let's look at how that would look in terms of rules. 564 00:34:11,440 --> 00:34:12,848 我会抽取出其中的逻辑 I'm going to take the logic I put up 565 00:34:13,088 --> 00:34:15,500 并将它们变为这种格式的规则 and just change it into a bunch of rules in this format. 566 00:34:18,739 --> 00:34:19,350 就有了下面的规则 We have a rule. 567 00:34:19,350 --> 00:34:20,960 这就是MERGE-TO-FORM的规则 Remember, there was this thing merge-to-form. 568 00:34:21,710 --> 00:34:22,976 这个规则是说 There is a rule that says, 569 00:34:26,288 --> 00:34:29,620 '()与?Y可以通过MERGE-TO-FORM形成?Y the empty list and y merge to form y. 570 00:34:29,620 --> 00:34:30,870 这是规则的结论 This is the rule conclusion. 571 00:34:33,210 --> 00:34:35,744 需要注意的是 这个特定的规则没有体 And notice this particular rule has no body. 572 00:34:36,650 --> 00:34:37,664 在这门语言中 And in this language, 573 00:34:38,112 --> 00:34:40,864 没有体的规则总是真的 a rule with no body is something that is always true. 574 00:34:41,239 --> 00:34:42,510 你总是可以假设它们为真 You can always assume that's true. 575 00:34:45,190 --> 00:34:46,496 另一条规则说的是 And there was another piece of logic 576 00:34:46,640 --> 00:34:49,460 任意对象与空表进行MERGE-TO-FORM 得到的任然是原物 that said anything in the empty list merged to form the anything. 577 00:34:49,460 --> 00:34:50,128 就是这条 That's this. 578 00:34:50,900 --> 00:34:53,552 (MERGE-TO-FORM ?Y '() ?Y) A rule y and the empty list merge to form y. 579 00:34:55,510 --> 00:34:58,400 它们对应了我们MERGE过程中的两个终止条件 Those corresponded to the two end cases in our merge procedure, 580 00:34:58,448 --> 00:34:59,776 但我们现在讨论的是逻辑 but now we're talking about logic, 581 00:35:00,416 --> 00:35:01,456 而非过程 not about procedures. 582 00:35:03,490 --> 00:35:04,480 我们还有另外一条规则 Then we had another rule, 583 00:35:04,832 --> 00:35:08,736 描述的是 如果你知道如何MERGE较短的表 which said if you know how shorter things merge, 584 00:35:08,912 --> 00:35:09,830 那么你就可以把它们结合在一起 you can put them together. 585 00:35:09,830 --> 00:35:14,160 这条规则说:如果你有表?X、?Y以及?Z So this says, if you have a list x and y and z, 586 00:35:14,928 --> 00:35:17,616 如果你想推断出(?A . ?X) and if you want to deduce that a dot x-- 587 00:35:17,632 --> 00:35:19,088 这个记法表示(CONS ?A ?X) this means cons a onto x, 588 00:35:19,488 --> 00:35:22,368 或者说首元素是'A、剩余元素是'X的表 or a list whose first thing is a and whose rest is x-- 589 00:35:23,160 --> 00:35:27,400 由此 如果你想推断(MERGE-TO-FROM (?A . ?X) (?B . ?Y) (?B . ?Z)) so if you want to deduce that a dot x and b dot y merge to form b dot z-- 590 00:35:30,360 --> 00:35:33,904 毋宁说如果你想要把表(?A ?X)和表(?B ?Y)合并得到 that would say you merge these two lists a x and b y 591 00:35:33,920 --> 00:35:35,856 一个以?B为首的表 and you're going to get something that starts with b-- 592 00:35:36,768 --> 00:35:40,672 你想要推断出这个结果 就要满足 you can deduce that if you know that it's the case 593 00:35:40,910 --> 00:35:44,480 不但(MERGE-TP-FORM (?A . ?X) ?Y ?Z) both that a dot x and y merge to form z 594 00:35:45,184 --> 00:35:47,248 并且(LISP-VALUE > ?A ?B) and a is larger than b. 595 00:35:48,690 --> 00:35:50,592 因此当我在合并它们时 ?B会首先出现在表中 So when I merge them, b will come first in the list. 596 00:35:51,824 --> 00:35:54,912 这就是简单的把我之前写的伪代码 That's a little translation of the logic rule 597 00:35:55,248 --> 00:35:57,184 翻译成逻辑的语言 that I wrote in pseudo-English before. 598 00:35:57,960 --> 00:36:01,632 为了翻译完整 这还里有种情况 And then just for completeness, here's the other case. 599 00:36:02,880 --> 00:36:05,952 (MERGE-TO-FORM (?A . ?X) (?B . ?Y) (?A . ?Z))成立 a dot x and b dot y merge to form a dot z 600 00:36:06,080 --> 00:36:09,168 就需要(MERGE-TO-FORM ?X (?B . ?Y) ?Z) if x and b dot y merged to form z and b is larger than a. 601 00:36:09,472 --> 00:36:11,008 和(LISP-VALUE > ?B ?A)都成立 and b is larger than a. 602 00:36:12,190 --> 00:36:15,984 我已经把这个用逻辑语言编写的小程序输入计算机了 So that's a little program that I've typed in in this language, 603 00:36:16,016 --> 00:36:17,070 现在让我们来试着运行一下 and now let's look at it run. 604 00:36:21,900 --> 00:36:23,904 由于我已经输入过MERGE-TO-FORM的规则了 So I typed in the merge rules before, 605 00:36:24,624 --> 00:36:25,776 我就可以 and I could say, ahh 606 00:36:27,040 --> 00:36:28,510 我可以像过程一样使用它 I could use this like a procedure. 607 00:36:28,510 --> 00:36:38,240 我可以问(MERGE-TO-FORM (1 3) (2 7) ?X) I could say merge to form 1 and 3 and 2 and 7. 608 00:36:39,424 --> 00:36:41,552 这里 我把它当作一个Lisp过程来使用 So here I'm using it like the LISP procedure. 609 00:36:43,168 --> 00:36:44,976 它先会思考一会儿 Now it's going to think about that for a while 610 00:36:46,432 --> 00:36:47,568 然后应用这些规则 and apply these rules. 611 00:36:50,780 --> 00:36:51,920 它找到了一个答案 So it found an answer. 612 00:36:52,800 --> 00:36:54,544 现在它还要继续寻找其它的答案 Now it's going to see if there are any other answers 613 00:36:55,072 --> 00:36:57,328 因为它事先不知道这里答案只有一个 it doesn't know a priori there's only one answer. 614 00:36:57,810 --> 00:36:59,904 因此它就在这里检查所有的可能性 So it's sitting here checking all possibilities, 615 00:37:00,416 --> 00:37:02,544 确认没有后 输出'DONE' and it says, no more. Done. 616 00:37:03,168 --> 00:37:05,072 这里 我把它们当作过程来使用 So there I've used those rules like a procedure. 617 00:37:05,210 --> 00:37:09,056 不过要注意 我还可以问不同类型的问题 Or remember the whole point is that I can ask different kinds of questions. 618 00:37:10,220 --> 00:37:11,072 我可以问 I could say 619 00:37:18,560 --> 00:37:24,590 (MERGE-TO-FORM (2 ?A) merge to form, let's see, how about 2 and a. 620 00:37:24,590 --> 00:37:27,904 一个我已知是以2为首的二元表 Some list of two elements which I know starts with 2, 621 00:37:29,376 --> 00:37:31,264 而另外一个东西是未知的 and the other thing I don't know, 622 00:37:33,056 --> 00:37:35,040 用?X来表示这个未知的表 and x and some other list 623 00:37:36,480 --> 00:37:39,510 可以通过MERGE-TO-FORM形成(1 2 3 4) merge to form a 1, 2, 3 and 4. 624 00:37:42,760 --> 00:37:44,112 现在它将思考这个问题 So now it's going to think about that. 625 00:37:44,590 --> 00:37:49,408 它会找到 -- 它找到了一种可能 It's got to find-- so it found one possibility. 626 00:37:49,520 --> 00:37:52,464 比如A=3 X=(1 4) It said a could be 3, and x could be the list 1, 4. 627 00:37:53,720 --> 00:37:55,168 现在 它又要继续检查 And now, again, it's got to check 628 00:37:56,560 --> 00:37:57,712 因为它事先并不知道 because it doesn't a priori know 629 00:37:57,744 --> 00:38:00,300 这里并没有其它的可能了 that there aren't any other possibilities going on. 630 00:38:03,680 --> 00:38:06,576 或者 就像我说过的 Or like I said, 631 00:38:07,008 --> 00:38:09,840 我可以问 I could say something like merge to form, 632 00:38:10,544 --> 00:38:17,552 能够通过MERGE-TO-FORM形成(1 2 3 4 5)的?X和?Y分别是什么? like, what and what else merge to form 1, 2, 3, 4, 5? 633 00:38:23,680 --> 00:38:25,536 语言系统又要思考这个问题 Now it's going to think about that. 634 00:38:28,490 --> 00:38:30,310 它可能会得到很多答案 And there are a lot of answers that it might get. 635 00:38:35,180 --> 00:38:38,576 这里我们就体会到了缓慢的代价 And what you see is here you're really paying the price of slowness. 636 00:38:42,210 --> 00:38:43,880 大概是有三种原因造成这样 And kind of for three reasons. 637 00:38:43,880 --> 00:38:46,224 首先 这门语言经过了两次解释 One is that this language is doubly interpreted. 638 00:38:47,630 --> 00:38:49,728 然而在真正的实现中 Whereas in a real implementation, 639 00:38:49,760 --> 00:38:52,048 你应该把这些编译成基本运算 you would go compile this down to primitive operations. 640 00:38:52,190 --> 00:38:53,872 其次就是 The other reason is that 641 00:38:53,888 --> 00:38:58,112 这个MERGE算法 是双重递归的 this particular algorithm for merges is doubly recursive. 642 00:38:58,380 --> 00:39:00,064 因此它需要花费很长的时间 So it's going to take a very long time. 643 00:39:01,020 --> 00:39:04,336 最后呢 它又要遍历所有的情况 And eventually, this is going to go through 644 00:39:04,592 --> 00:39:07,130 找出 -- 找出什么呢? and find-- find what? 645 00:39:07,130 --> 00:39:08,730 所有的2^5种可行解 Two to the fifth possible answers. 646 00:39:12,140 --> 00:39:14,960 我们发现它们以某种相当随意的顺序输出 And you see they come out in some fairly arbitrary order, 647 00:39:15,008 --> 00:39:18,144 这取决于它们用什么样的顺序尝试这些规则 depending on which order it's going to be trying these rules. 648 00:39:20,160 --> 00:39:22,112 事实上 在后期制作本视频时 In fact, what we're going to do when they edit the videotape 649 00:39:22,400 --> 00:39:23,480 我们将加速这段 is speed all this up. 650 00:39:24,080 --> 00:39:26,600 我们就不再这里浪费时间了 Don't you like taking out these waits? 651 00:39:26,600 --> 00:39:28,272 课后你们可以自行尝试 And don't you wish you could do that in your demos? 652 00:39:29,488 --> 00:39:34,240 好吧 它还在运行 Anyway, it's still grinding there. 653 00:39:39,220 --> 00:39:41,120 总之 一共有32种可能 Anyway, there are 32 possibilities-- 654 00:39:41,136 --> 00:39:42,630 我们就不等到输出所有的结果了 we won't wait for it to print out all of them. 655 00:39:47,850 --> 00:39:50,448 因此 这门语言中的抽象手段就是RULE OK, so the needs of abstraction in this language are rules. 656 00:39:53,536 --> 00:39:58,016 我们用逻辑把事物组织在一起 So we take some bunch of things that are put together with logic 657 00:39:59,120 --> 00:40:00,080 并为它们命名 and we name them. 658 00:40:00,350 --> 00:40:03,410 你们可以认为这是为一组特定的逻辑模式命名 And you can think of that as naming a particular pattern of logic. 659 00:40:03,410 --> 00:40:04,544 你们可以把它想做 Or you can think of that as saying, 660 00:40:04,560 --> 00:40:06,750 如果我们想要推断出某个结论 if you want to deduce some conclusion, 661 00:40:07,904 --> 00:40:09,520 就可以应用这些逻辑规则 you can apply those rules of logic. 662 00:40:10,660 --> 00:40:13,200 这些就是这门语言中的三种要素 And those are three elements of this language. 663 00:40:13,420 --> 00:40:14,560 我们先休息一会儿 Let's break now, 664 00:40:14,608 --> 00:40:16,590 然后再来讨论如何实际实现 and then we'll talk about how it's actually implemented. 665 00:40:23,616 --> 00:40:28,848 学生:使用LISP-VALUE之类的基本过程会影响 AUDIENCE: Does using LISP value primitive or whatever interfere with your means 666 00:40:29,152 --> 00:40:30,640 查询的双向性吗? both directions on a query? 667 00:40:31,770 --> 00:40:34,480 教授:这个问题 -- 你问的是 PROFESSOR: OK, that's a-- the question is, 668 00:40:35,088 --> 00:40:36,928 使用LISP-VALUE是否会影响 does using LISP value interfere 669 00:40:37,536 --> 00:40:40,090 双向地推断一条查询 with the ability to go both directions on the query? 670 00:40:40,090 --> 00:40:42,816 虽然我们还没有实际讨论具体实现 We haven't really talked about the implementation yet, 671 00:40:43,680 --> 00:40:45,520 但是它们确实会造成影响 but the answer is, yes, it can. 672 00:40:46,890 --> 00:40:50,208 通常来说 我们最后将会发现 In general, as we'll see at the end-- 673 00:40:50,224 --> 00:40:52,170 虽然我不会讲得太细 although I really won't to go into details-- 674 00:40:53,216 --> 00:40:59,360 当你使用NOT和LISP-VALUE时 会变得相当复杂 it's fairly complicated, especially when you use either not or LISP value-- 675 00:40:59,550 --> 00:41:02,890 或者实际上 只要你用了除AND以外的东西 or actually, if you use anything besides only and, 676 00:41:04,128 --> 00:41:08,192 很难再说清楚这些东西是否会起效了 it becomes very complicated to say when these things will work. 677 00:41:08,208 --> 00:41:10,360 它们并不是在任何情况下都有效 They won't work quite in all situations. 678 00:41:10,360 --> 00:41:13,392 我会在下一堂课的最后讨论这个问题 I'll talk about that at the end of the second half today. 679 00:41:14,300 --> 00:41:15,840 但对于你的问题来说:答案是“会影响” But the answer to your question is, yes, 680 00:41:16,192 --> 00:41:19,216 用LISP-VALUE一方面从Lisp中获得了巨大威力 by dragging in a lot more power from LISP value, 681 00:41:19,408 --> 00:41:23,776 另一方面你失去了逻辑式程序设计的重要威力 you lose some of the principal power of logic programming. 682 00:41:24,170 --> 00:41:25,568 这是你需要做出的取舍 That's a trade-off that you have to make. 683 00:41:28,480 --> 00:41:29,392 好吧 先休息一会儿 OK, let's take a break. 684 00:41:30,176 --> 00:41:37,392 MIT OpenCourseWare http://ocw.mit.edu 685 00:41:37,408 --> 00:41:44,304 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec8b.eng.srt ================================================ 1 00:00:18,910 --> 00:00:22,502 PROFESSOR: All right, well, we've seen how the query language works. 2 00:00:22,502 --> 00:00:26,280 Now, let's talk about how it's implemented. 3 00:00:26,280 --> 00:00:29,470 You already pretty much can guess what's going on there. 4 00:00:29,470 --> 00:00:32,810 At the bottom of it, there's a pattern matcher. 5 00:00:32,810 --> 00:00:38,110 And we looked at a pattern matcher when we did the rule-based control language. 6 00:00:38,110 --> 00:00:41,520 Just to remind you, here are some sample patterns. 7 00:00:41,520 --> 00:00:50,650 This is a pattern that will match any list of three things of which the first is a and the second is c and the middle one can be anything. 8 00:00:50,650 --> 00:00:54,050 So in this little pattern-matching syntax, there's only one distinction you make. 9 00:00:54,050 --> 00:00:59,080 There's either literal things or variables, and variables begin with question mark. 10 00:01:01,370 --> 00:01:06,500 So this matches any list of three things of which the first is a and the second is c. 11 00:01:06,500 --> 00:01:12,530 This one matches any list of three things of which the first is the symbol job. 12 00:01:12,530 --> 00:01:14,210 The second can be anything. 13 00:01:14,210 --> 00:01:20,480 And the third is a list of two things of which the first is the symbol computer and the second can be anything. 14 00:01:20,480 --> 00:01:37,860 And this one, this next one matches any list of three things, and the only difference is, here, the third list, the first is the symbol computer, and then there's some rest of the list. So this means two elements and this means arbitrary number. 15 00:01:37,860 --> 00:01:44,050 And our language implementation isn't even going to have to worry about implementing this dot because that's automatically done by Lisp's reader. 16 00:01:48,340 --> 00:01:50,310 Remember matchers also have some consistency in them. 17 00:01:50,310 --> 00:01:54,430 This match is a list of three things of which the first is a. 18 00:01:54,430 --> 00:01:57,940 And the second and third can be anything, but they have to be the same thing. 19 00:01:57,940 --> 00:01:59,600 They're both called x. 20 00:01:59,600 --> 00:02:05,590 And this matches a list of four things of which the first is the fourth and the second is the same as the third. 21 00:02:05,590 --> 00:02:09,685 And this last one matches any list that begins with a. 22 00:02:09,685 --> 00:02:14,040 The first thing is a, and the rest can be anything. 23 00:02:14,040 --> 00:02:18,780 So that's just a review of pattern matcher syntax that you've already seen. 24 00:02:18,780 --> 00:02:22,740 And remember, that's implemented by some procedure called match. 25 00:02:24,870 --> 00:02:35,695 And match takes a pattern and some data and a dictionary. 26 00:02:43,200 --> 00:02:58,160 And match asks the question is there any way to match this pattern against this data object subject to the bindings that are already in this dictionary? 27 00:02:58,160 --> 00:03:22,010 So, for instance, if we're going to match the pattern x, y, y, x against the data a, b, b, a subject to a dictionary, that says x equals a. 28 00:03:22,010 --> 00:03:25,260 Then the matcher would say, yes, that's consistent. 29 00:03:25,260 --> 00:03:30,320 These match, and it's consistent with what's in the dictionary to say that x equals a. 30 00:03:30,320 --> 00:03:39,490 And the result of the match is the extended dictionary that says x equals a and y equals b. 31 00:03:39,490 --> 00:03:46,840 So a matcher takes in pattern data dictionary, puts out an extended dictionary if it matches, or if it doesn't match, says that it fails. 32 00:03:46,840 --> 00:04:06,665 So, for example, if I use the same pattern here, if I say this x, y, y, x match a, b, b, a with the dictionary y equals a, then the matcher would put out fail. 33 00:04:12,150 --> 00:04:21,190 Well, you've already seen the code for a pattern matcher so I'm not going to go over it, but it's the same thing we've been doing before. 34 00:04:21,190 --> 00:04:23,220 You saw that in the system on rule-based control. 35 00:04:23,220 --> 00:04:24,950 It's essentially the same matcher. 36 00:04:24,950 --> 00:04:31,400 In fact, I think the syntax is a little bit simpler because we're not worrying about arbitrary constants and expressions and things. 37 00:04:31,400 --> 00:04:32,690 There's just variables and constants. 38 00:04:35,790 --> 00:04:39,610 OK, well, given that, what's a primitive query? 39 00:04:42,970 --> 00:04:46,720 Primitive query is going to be a rather complicated thing. 40 00:04:46,720 --> 00:05:03,490 It's going to be-- let's think about the query job of x is d dot y. 41 00:05:06,850 --> 00:05:09,400 That's a query we might type in. 42 00:05:09,400 --> 00:05:11,095 That's going to be implemented in the system. 43 00:05:14,270 --> 00:05:15,700 We'll think of it as this little box. 44 00:05:15,700 --> 00:05:18,880 Here's the primitive query. 45 00:05:18,880 --> 00:05:34,030 What this little box is going to do is take in two streams and put out a stream. 46 00:05:34,030 --> 00:05:41,120 So the shape of a primitive query is that it's a thing where two streams come in and one stream goes out. 47 00:05:41,120 --> 00:05:45,925 What these streams are going to be is down here is the database. 48 00:05:51,600 --> 00:06:00,330 So we imagine all the things in the database sort of sitting there in a stream and this thing sucks on them. 49 00:06:00,330 --> 00:06:02,800 So what are some things that might be in the database? 50 00:06:02,800 --> 00:06:25,770 Oh, job of Alyssa is something and some other job is something. 51 00:06:25,770 --> 00:06:32,040 So imagine all of the facts in the database sitting there in the stream. 52 00:06:32,040 --> 00:06:33,400 That's what comes in here. 53 00:06:33,400 --> 00:06:38,510 What comes in here is a stream of dictionaries. 54 00:06:38,510 --> 00:06:48,855 So one particular dictionary might say y equals programmer. 55 00:06:55,470 --> 00:07:11,390 Now, what the query does when it gets in a dictionary from this stream, it finds all possible ways of matching the query against whatever is coming in from the database. 56 00:07:11,390 --> 00:07:27,550 It looks at the query as a pattern, matches it against any fact from the database or all possible ways of finding and matching the database with respect to this dictionary that's coming in. 57 00:07:27,550 --> 00:07:35,110 So for each fact in the database, it calls the matcher using the pattern, fact, and dictionary. 58 00:07:35,110 --> 00:07:40,420 And every time it gets a good match, it puts out the extended dictionary. 59 00:07:40,420 --> 00:07:52,970 So, for example, if this one comes in and it finds a match, out will come a dictionary that in this case will have y equals programmer and x equals something. 60 00:07:56,740 --> 00:08:01,430 y is programmer, x is something, and d is whatever it found. 61 00:08:01,430 --> 00:08:03,520 And that's all. 62 00:08:03,520 --> 00:08:07,980 And, of course, it's going to try this for every fact in the dictionary. 63 00:08:07,980 --> 00:08:09,250 So it might find lots of them. 64 00:08:09,250 --> 00:08:16,355 It might find another one that says y equals programmer and x equals, and d equals. 65 00:08:20,040 --> 00:08:30,470 So for one frame coming in, it might put out-- for one dictionary coming in, it might put out a lot of dictionaries, or it might put out none. 66 00:08:30,470 --> 00:08:39,320 It might have something that wouldn't match like x equals FOO. 67 00:08:39,320 --> 00:08:47,510 This one might not match anything in which case nothing will go into this stream corresponding to this frame. 68 00:08:47,510 --> 00:09:07,570 Or what you might do is put in an empty frame, and an empty frame says try matching all ways-- find all possible ways of matching the query against something in the database subject to no previous restrictions. 69 00:09:07,570 --> 00:09:13,980 And if you think about what that means, that's just the computation that's done when you type in a query right off. 70 00:09:13,980 --> 00:09:16,650 It tries to find all matches. 71 00:09:16,650 --> 00:09:19,370 So a primitive query sets up this mechanism. 72 00:09:19,370 --> 00:09:44,990 And what the language does, when you type in the query at the top level, it takes this mechanism, feeds in one single empty dictionary, and then for each thing that comes out takes the original query and instantiates the result with all the different dictionaries, producing a new stream of instantiated patterns here. 73 00:09:44,990 --> 00:09:48,170 And that's what gets printed on the terminal. 74 00:09:48,170 --> 00:09:53,510 That's the basic mechanism going on there. 75 00:09:53,510 --> 00:09:56,870 Well, why is that so complicated? 76 00:09:56,870 --> 00:10:04,725 You probably can think of a lot simpler ways to arrange this match for a primitive query rather than having all of these streams floating around. 77 00:10:04,725 --> 00:10:10,860 And the answer is-- you probably guess already. 78 00:10:10,860 --> 00:10:17,790 The answer is this thing extends elegantly to implement the means of combination. 79 00:10:17,790 --> 00:10:22,470 So, for instance, suppose I don't only want to do this. 80 00:10:22,470 --> 00:10:27,230 I don't want to say who to be everybody's job description. 81 00:10:27,230 --> 00:10:48,800 Suppose I want to say AND the job of x is d dot y and the supervisor of x is z. 82 00:10:48,800 --> 00:11:08,700 Now, supervisor of x is z is going to be another primitive query that has the same shape to take in a stream of data objects, a stream of initial dictionaries, which are the restrictions to try and use when you match, and it's going to put out a stream of dictionaries. 83 00:11:08,700 --> 00:11:11,680 So that's what this primitive query looks like. 84 00:11:11,680 --> 00:11:12,910 And how do I implement the AND? 85 00:11:12,910 --> 00:11:13,450 Well, it's simple. 86 00:11:13,450 --> 00:11:14,880 I just hook them together. 87 00:11:14,880 --> 00:11:19,830 I take the output of this one, and I put that to the input of that one. 88 00:11:19,830 --> 00:11:21,545 And I take the dictionary here and I fan it out. 89 00:11:26,570 --> 00:11:37,920 And then you see how that's going to work, because what's going to happen is a frame will now come in here, which has a binding for x, y, and d. 90 00:11:37,920 --> 00:11:56,080 And then when this one gets it, it'll say, oh, gee, subject to these restrictions, which now already have values in the dictionary for y and x and d, it looks in the database and says, gee, can I find any supervisor facts? 91 00:11:56,080 --> 00:12:09,340 And if it finds any, out will come dictionaries which have bindings for y and x and d and z now. 92 00:12:12,070 --> 00:12:26,470 And then notice that because the frames coming in here have these restrictions, that's the thing that assures that when you do the AND, this x will mean the same thing as that x. 93 00:12:26,470 --> 00:12:34,460 Because by the time something comes floating in here, x has a value that you have to match against consistently. 94 00:12:34,460 --> 00:12:40,710 And then you remember from the code from the matcher, there was something in the way the matcher did dictionaries that arrange consistent matches. 95 00:12:40,710 --> 00:12:44,260 So there's AND. 96 00:12:44,260 --> 00:12:48,570 The important point to notice is the general shape. 97 00:12:48,570 --> 00:12:52,600 Look at what happened: the AND of two queries, say, P and Q. 98 00:12:52,600 --> 00:13:01,190 Here's P and Q. The AND of two queries, well, it looks like this. 99 00:13:01,190 --> 00:13:10,230 Each query takes in a stream from the database, a stream of inputs, and puts out a stream of outputs. 100 00:13:10,230 --> 00:13:32,360 And the important point to notice is that if I draw a box around this thing and say this is AND of P and Q, then that box has exactly the same overall shape. 101 00:13:32,360 --> 00:13:34,200 It's something that takes in a stream from the database. 102 00:13:34,200 --> 00:13:38,160 Here it's going to get fanned out inside, but from the outside you don't see that. 103 00:13:38,160 --> 00:13:42,230 It takes an input stream and puts out an output stream. 104 00:13:42,230 --> 00:13:43,570 So this is AND. 105 00:13:43,570 --> 00:13:46,020 And then similarly, OR would look like this. 106 00:13:46,020 --> 00:13:49,840 OR would-- although I didn't show you examples of OR. 107 00:13:49,840 --> 00:13:58,070 OR would say can I find all ways of matching P or Q. So I have P and Q. Each will have their shape. 108 00:14:04,460 --> 00:14:12,500 And the way OR is implemented is I'll take my database stream. 109 00:14:12,500 --> 00:14:13,490 I'll fan it out. 110 00:14:13,490 --> 00:14:21,980 I'll put one into P and one into Q. I'll take my initial query stream coming in and fan it out. 111 00:14:26,750 --> 00:14:41,080 So I'll look at all the answers I might get from P and all the answers I might get from Q, and I'll put them through some sort of thing that appends them or merges the result into one stream, and that's what will come out. 112 00:14:41,080 --> 00:14:48,240 And this whole thing from the outside is OR. 113 00:14:52,350 --> 00:14:56,790 And again, you see it has the same overall shape when looked at from the outside. 114 00:15:01,000 --> 00:15:02,020 What's NOT? 115 00:15:02,020 --> 00:15:04,310 NOT works kind of the same way. 116 00:15:04,310 --> 00:15:14,690 If I have some query P, I take the primitive query for P. 117 00:15:14,690 --> 00:15:20,720 Here, I'm going to implement NOT P. And NOT's just going to act as a filter. 118 00:15:20,720 --> 00:15:39,020 I'll take in the database and my original stream of dictionaries coming in, and what NOT P will do is it will filter these guys. 119 00:15:39,020 --> 00:15:47,460 And the way it will filter it, it will say when I get in a dictionary here, I'll find all the matches, and if I find any, I'll throw it away. 120 00:15:47,460 --> 00:15:55,560 And if I don't find any matches to something coming in here, I'll just pass that through, so NOT is a pure filter. 121 00:15:55,560 --> 00:15:59,980 So AND is-- think of these sort of electoral resistors or something. 122 00:15:59,980 --> 00:16:04,960 AND is series combination and OR is parallel combination. 123 00:16:04,960 --> 00:16:07,460 And then NOT is not going to extend any dictionaries at all. 124 00:16:07,460 --> 00:16:08,750 It's just going to filter it. 125 00:16:08,750 --> 00:16:12,640 It's going to throw away the ones for which it finds a way to match. 126 00:16:12,640 --> 00:16:14,540 And list value is sort of the same way. 127 00:16:14,540 --> 00:16:16,600 The filter's a little more complicated. 128 00:16:16,600 --> 00:16:19,640 It applies to predicate. 129 00:16:19,640 --> 00:16:24,980 The major point to notice here, and it's a major point we've looked at before, is this idea of closure. 130 00:16:28,490 --> 00:16:39,750 The things that we build as a means of combination have the same overall structure as the primitive things that we're combining. 131 00:16:39,750 --> 00:16:44,630 So the AND of two things when looked at from the outside has the same shape. 132 00:16:44,630 --> 00:16:54,950 And what that means is that this box here could be an AND or an OR or a NOT or something because it has the same shape to interface to the larger things. 133 00:16:54,950 --> 00:17:04,170 It's the same thing that allowed us to get complexity in the Escher picture language or allows you to immediately build up these complicated structures just out of pairs. 134 00:17:04,170 --> 00:17:06,280 It's closure. 135 00:17:06,280 --> 00:17:19,260 And that's the thing that allowed me to do what by now you took for granted when I said, gee, there's a query which is AND of job and salary, and I said, oh, there's another one, which is AND of job, a NOT of something. 136 00:17:19,260 --> 00:17:25,230 The fact that I can do that is a direct consequence of this closure principle. 137 00:17:25,230 --> 00:17:29,520 OK, let's break and then we'll go on. 138 00:17:29,520 --> 00:17:30,710 AUDIENCE: Where does the dictionary come from? 139 00:17:30,710 --> 00:17:36,030 PROFESSOR: The dictionary comes initially from what you type in. 140 00:17:36,030 --> 00:17:41,090 So when you start this up, the first thing it does is set up this whole structure. 141 00:17:41,090 --> 00:17:45,000 It puts in one empty dictionary. 142 00:17:45,000 --> 00:17:52,310 And if all you have is one primitive query, then what will come out is a bunch of dictionaries with things filled in. 143 00:17:52,310 --> 00:17:59,710 The general situation that I have here is when this is in the middle of some nest of combined things. 144 00:18:02,380 --> 00:18:03,790 Let's look at the picture over here. 145 00:18:03,790 --> 00:18:06,730 This supervisor query gets in some dictionary. 146 00:18:06,730 --> 00:18:08,730 Where did this one come from? 147 00:18:08,730 --> 00:18:16,260 This dictionary came from the fact that I'm looking at the output of this primitive query. 148 00:18:16,260 --> 00:18:31,770 So maybe to be very specific, if I literally typed in just this query at the top level, this AND, what would actually happen is it would build this structure and start up this whole thing with one empty dictionary. 149 00:18:31,770 --> 00:18:38,640 And now this one would process, and a whole bunch of dictionaries would come out with x, y's and d's in them. 150 00:18:38,640 --> 00:18:40,190 Run it through this one. 151 00:18:40,190 --> 00:18:42,160 So now that's the input to this one. 152 00:18:42,160 --> 00:18:45,040 This one would now put out some other stuff. 153 00:18:45,040 --> 00:18:56,110 And if this itself were buried in some larger thing, like an OR of something, then that would go feed into the next one. 154 00:18:58,560 --> 00:19:07,660 So you initially get only one empty dictionary when you start it, but as you're in the middle of processing these compounds things, that's where these cascades of dictionaries start getting generated. 155 00:19:07,660 --> 00:19:12,280 AUDIENCE: Dictionaries only come about as a result of using the queries? 156 00:19:15,120 --> 00:19:23,220 Or do they become-- do they stay someplace in space like the database does? 157 00:19:23,220 --> 00:19:24,980 Are these temporary items? 158 00:19:24,980 --> 00:19:28,030 PROFESSOR: They're created temporarily in the matcher. 159 00:19:28,030 --> 00:19:29,880 Really, they're someplace in storage. 160 00:19:29,880 --> 00:19:40,950 Initially, someone creates a thing called the empty dictionary that gets initially fed to this match procedure, and then the match procedure builds some dictionaries, and they get passed on and on. 161 00:19:40,950 --> 00:19:43,526 AUDIENCE: OK, so they'll go way after the match? 162 00:19:43,526 --> 00:19:45,930 PROFESSOR: They'll go away when no one needs them again, yeah. 163 00:19:51,900 --> 00:19:56,050 AUDIENCE: It appears that the AND performs some redundant searches of the database. 164 00:19:56,050 --> 00:20:06,700 If the first clause matched, let's say, the third element and not on the first two elements, the second clause is going to look at those first two elements again, discarding them because they don't match. 165 00:20:06,700 --> 00:20:10,000 The match is already in the dictionary. 166 00:20:10,000 --> 00:20:14,450 Would it makes sense to carry the data element from the database along with the dictionary? 167 00:20:17,120 --> 00:20:21,740 PROFESSOR: Well, in general, there are other ways to arrange this search, and there's some analysis that you can do. 168 00:20:21,740 --> 00:20:29,850 I think there's a problem in the book, which talks about a different way that you can cascade AND to eliminate various kinds of redundancies. 169 00:20:29,850 --> 00:20:34,650 This one is meant to be-- was mainly meant to be very simple so you can see how they fit together. 170 00:20:34,650 --> 00:20:35,380 But you're quite right. 171 00:20:35,380 --> 00:20:38,370 There are redundancies here that you can get rid of. 172 00:20:38,370 --> 00:20:41,190 That's another reason why this language is somewhat slow. 173 00:20:41,190 --> 00:20:42,930 There are a lot smarter things you can do. 174 00:20:42,930 --> 00:20:46,840 We're just trying to show you a very simple, in principle, implementation. 175 00:20:51,220 --> 00:20:55,150 AUDIENCE: Did you model this language on Prolog, or did it just come out looking like Prolog? 176 00:21:04,960 --> 00:21:16,120 PROFESSOR: Well, Jerry insulted a whole bunch of people yesterday, so I might as well say that the MIT attitude towards Prolog is something that people did in about 1971 and decided that it wasn't really the right thing and stopped. 177 00:21:16,120 --> 00:21:37,330 So we modeled this on the sort of natural way that this thing was done in about 1971, except at that point, we didn't do it with streams. After we were using it for about six months, we discovered that it had all these problems, some of which I'll talk about later. 178 00:21:37,330 --> 00:21:41,250 And we said, gee, Prolog must have fixed those, and then we found out that it didn't. 179 00:21:41,250 --> 00:21:43,460 So this does about the same thing as Prolog. 180 00:21:43,460 --> 00:21:44,950 AUDIENCE: Does Prolog use streams? 181 00:21:44,950 --> 00:21:46,200 PROFESSOR: No. 182 00:21:48,540 --> 00:21:51,040 In how it behaves, it behaves a lot like Prolog. 183 00:21:51,040 --> 00:21:53,800 Prolog uses a backtracking strategy. 184 00:21:53,800 --> 00:22:20,850 But the other thing that's really good about Prolog that makes it a usable thing is that there's a really very, very well-engineered compiler technology that makes it run fast. So although you saw the merge spitting out these answers very, very slowly, a real Prolog will run very, very fast. Because even though it's sort of doing this, the real work that went into Prolog is a very, very excellent compiler effort. 185 00:22:24,460 --> 00:22:25,710 Let's take a break. 186 00:23:16,650 --> 00:23:26,950 We've looked at the primitive queries and the ways that streams are used to implement the means of combination: AND and OR and NOT. 187 00:23:26,950 --> 00:23:29,580 Now, let go on to the means of abstraction. 188 00:23:29,580 --> 00:23:32,570 Remember, the means of abstraction in this language are rules. 189 00:23:35,150 --> 00:23:48,900 So z is a boss in division d if there's some x who has a job in division d and z is the supervisor of x. 190 00:23:48,900 --> 00:23:52,260 That's what it means for someone to be a boss. 191 00:23:52,260 --> 00:24:33,900 And in effect, if you think about what we're doing with relation to this, there's the query we wrote-- the job of x is in d and the supervisor of x is z-- what we in effect want to do is take this whole mess and draw a box around it and say this whole thing inside the box is boss of z in division d. 192 00:24:33,900 --> 00:24:35,250 That's in effect what we want to do. 193 00:24:38,720 --> 00:25:33,045 So, for instance, if we've done that, and we want to check whether or not it's true that Ben Bitdiddle is a boss in the computer division, so if I want to say boss of Ben Bitdiddle in the computer division, imagine typing that in as query to the system, in effect what we want to do is set up a dictionary here, which has z to Ben Bitdiddle and d to computer. 194 00:25:37,340 --> 00:25:38,720 Where did that dictionary come from? 195 00:25:38,720 --> 00:25:40,710 Let's look at the slide for one second. 196 00:25:40,710 --> 00:25:51,650 That dictionary came from matching the query that said boss of Ben Bitdiddle and computer onto the conclusion of the rule: boss of z and d. 197 00:25:51,650 --> 00:25:54,190 So we match the query to the conclusion of the rule. 198 00:25:54,190 --> 00:26:06,670 That gives us a dictionary, and that's the thing that we would now like to put into this whole big thing and process and see if anything comes out the other side. 199 00:26:06,670 --> 00:26:11,330 If anything comes out, it'll be true. 200 00:26:11,330 --> 00:26:12,370 That's the basic idea. 201 00:26:12,370 --> 00:26:23,580 So in general, the way we implement a rule is we match the conclusion of the rule against something we might want to check it's true. 202 00:26:23,580 --> 00:26:36,470 That match gives us a dictionary, and with respect to that dictionary, we process the body of the rule. 203 00:26:36,470 --> 00:26:43,070 Well, that's really all there is, except for two technical points. 204 00:26:43,070 --> 00:26:47,510 The first technical point is that I might have said something else. 205 00:26:47,510 --> 00:26:52,490 I might have said who's the boss in the computer division? 206 00:26:52,490 --> 00:26:56,270 So I might say boss of who in computer division. 207 00:27:00,329 --> 00:27:18,620 And if I did that, what I would really like to do in effect is start up this dictionary with a match that sort of says, well, d is computer and z is whatever who is. 208 00:27:21,700 --> 00:27:23,220 And our matcher won't quite do that. 209 00:27:23,220 --> 00:27:28,580 That's not quite matching a pattern against data. 210 00:27:28,580 --> 00:27:33,480 It's matching two patterns and saying are they consistent or not or what ways make them consistent. 211 00:27:33,480 --> 00:27:39,740 In other words, what we need is not quite a pattern matcher, but something a little bit more general called a unifier. 212 00:27:44,420 --> 00:27:49,530 And a unifier is a slight generalization of a pattern matcher. 213 00:27:49,530 --> 00:28:05,680 What a unifier does is take two patterns and say what's the most general thing you can substitute for the variables in those two patterns to make them satisfy the pattern simultaneously? 214 00:28:05,680 --> 00:28:08,900 Let me give you an example. 215 00:28:08,900 --> 00:28:43,440 If I have the pattern two-element list, which is x and x, so I have a two-element list where both elements are the same and otherwise I don't care what they are, and I unify that against the pattern that says there's a two-element list, and the first one is a and something in c and the second one is a and b and z, then what the unifier should tell me is, oh yeah, in that dictionary, x has to be a, b, c, and y has to be d and z has to be c. 216 00:28:43,440 --> 00:28:55,420 Those are the restrictions I'd have to put on the values of x, y, and z to make these two unify, or in other words, to make this match x and make this match x. 217 00:28:55,420 --> 00:28:58,540 The unifier should be able to deduce that. 218 00:28:58,540 --> 00:29:01,080 But the unifier may-- there are more complicated things. 219 00:29:01,080 --> 00:29:03,810 I might have said something a little bit more complicated. 220 00:29:03,810 --> 00:29:12,650 I might have said there's a list with two elements, and they're both the same, and they should unify against something of this form. 221 00:29:12,650 --> 00:29:16,890 And the unifier should be able to deduce from that. 222 00:29:16,890 --> 00:29:19,570 Like that y would have to be b. y would have to be b. 223 00:29:19,570 --> 00:29:24,340 Because these two are the same, so y's got to be b. 224 00:29:24,340 --> 00:29:28,940 And v here would have to be a. 225 00:29:28,940 --> 00:29:32,700 And z and w can be anything, but they have to be the same thing. 226 00:29:35,710 --> 00:29:44,680 And x would have to be b, followed by a, followed by whatever w is or whatever z is, which is the same. 227 00:29:44,680 --> 00:29:50,880 So you see, the unifier somehow has to deduce things to unify these patterns. 228 00:29:50,880 --> 00:29:55,850 So you might think there's some kind of magic deduction going on, but there's not. 229 00:29:55,850 --> 00:30:00,150 A unifier is basically a very simple modification of a pattern matcher. 230 00:30:00,150 --> 00:30:08,280 And if you look in the book, you'll see something like three or four lines of code added to the pattern matcher you just saw to handle the symmetric case. 231 00:30:08,280 --> 00:30:14,980 Remember, the pattern matcher has a place where it says is this variable matching a constant. 232 00:30:14,980 --> 00:30:16,420 And if so, it checks in the dictionary. 233 00:30:16,420 --> 00:30:27,030 There's only one other clause in the unifier, which says is this variable matching a variable, in which case you go look in the dictionary and see if that's consistent with what's in the dictionary. 234 00:30:27,030 --> 00:30:45,260 So all the, quote, deduction that's in this language, if you sort of look at it, sort of sits in the rule applications, which, if you look at that, sits in the unifier, which, if you look at that under a microscope, sits essentially in the pattern matcher. 235 00:30:45,260 --> 00:30:47,410 There's no magic at all going on in there. 236 00:30:47,410 --> 00:30:56,030 And the, quote, deduction that you see is just the fact that there's this recursion, which is unwinding the matches bit by bit. 237 00:30:56,030 --> 00:31:02,140 So it looks like this thing is being very clever, but in fact, it's not being very clever at all. 238 00:31:02,140 --> 00:31:04,880 There are cases where a unifier might have to be clever. 239 00:31:04,880 --> 00:31:06,130 Let me show you one more. 240 00:31:11,070 --> 00:31:24,370 Suppose I want to unify a list of two elements, x and x, with a thing that says it's y followed by a dot y. 241 00:31:24,370 --> 00:31:37,330 Now, if you think of what that would have to mean, it would have to mean that x had better be the same as y, but also x had better be the same as a list whose first element is a and whose rest is y. 242 00:31:37,330 --> 00:31:44,710 And if you think about what that would have to mean, it would have to mean that y is the infinite list of a's. 243 00:31:47,500 --> 00:32:01,840 In some sense, in order to do that unification, I have to solve the fixed-point equation cons of a to y is equal to y. 244 00:32:04,570 --> 00:32:07,290 And in general, I wrote a very simple one. 245 00:32:07,290 --> 00:32:15,530 Really doing unification might have to solve an arbitrary fixed-point equation: f of y equals y. 246 00:32:15,530 --> 00:32:20,570 And basically, you can't do that and make the thing finite all the time. 247 00:32:20,570 --> 00:32:25,140 So how does the logic language handle that? 248 00:32:25,140 --> 00:32:26,850 The answer is it doesn't. 249 00:32:26,850 --> 00:32:28,730 It just punts. 250 00:32:28,730 --> 00:32:38,650 And there's a little check in the unifier, which says, oh, is this one of the hard cases which when I go to match things would involve solving a fixed-point equation? 251 00:32:38,650 --> 00:32:42,840 And in this case, I will throw up my hands. 252 00:32:42,840 --> 00:32:47,990 And if that check were not in there, what would happen? 253 00:32:47,990 --> 00:32:53,740 In most cases is that the unifier would just go into an infinite loop. 254 00:32:53,740 --> 00:32:56,800 And other logic programming languages work like that. 255 00:32:56,800 --> 00:32:58,220 So there's really no magic. 256 00:32:58,220 --> 00:33:00,100 The easy case is done in a matcher. 257 00:33:00,100 --> 00:33:02,960 The hard case is not done at all. 258 00:33:02,960 --> 00:33:05,115 And that's about the state of this technology. 259 00:33:12,840 --> 00:33:17,390 Let me just say again formally how rules work now that I talked about unifiers. 260 00:33:17,390 --> 00:33:28,270 So the official definition is that to apply a rule, we-- well, let's start using some words we've used before. 261 00:33:28,270 --> 00:33:43,850 Let's talk about sticking dictionaries into these big boxes of query things as evaluating these large queries relative to an environment or a frame. 262 00:33:43,850 --> 00:33:46,720 So when you think of that dictionary, what's the dictionary after all? 263 00:33:46,720 --> 00:33:48,180 It's a bunch of meanings for symbols. 264 00:33:48,180 --> 00:33:51,800 That's what we've been calling frames or environments. 265 00:33:51,800 --> 00:33:55,970 What does it mean to do some processing relevant to an environment? 266 00:33:55,970 --> 00:33:58,310 That's what we've been calling evaluation. 267 00:33:58,310 --> 00:34:13,230 So we can say the way that you apply a rule is to evaluate the rule body relative to an environment that's formed by unifying the rule conclusion with the given query. 268 00:34:13,230 --> 00:34:21,630 And the thing I want you to notice is the complete formal similarity to the net of circular evaluator or the substitution model. 269 00:34:21,630 --> 00:34:34,560 To apply a procedure, we evaluate the procedure body relative to an environment that's formed by blinding the procedure parameters to the arguments. 270 00:34:34,560 --> 00:34:43,650 There's a complete formal similarity here between the rules, rule application, and procedure application even though these things are very, very different. 271 00:34:43,650 --> 00:34:47,290 And again, you have the EVAL APPLY loop. 272 00:34:47,290 --> 00:34:49,445 EVAL and APPLY. 273 00:34:53,360 --> 00:35:08,660 So in general, I might be processing some combined expression that will turn into a rule application, which will generate some dictionaries or frames or environments-- whatever you want to call them-- from match, which will then be the input to some big compound thing like this. 274 00:35:08,660 --> 00:35:13,580 This has pieces of it and may have other rule applications. 275 00:35:13,580 --> 00:35:19,680 And you have essentially the same cycle even though there's nothing here at all that looks like procedures. 276 00:35:19,680 --> 00:35:25,490 It really has to do with the fact you've built a language whose means of combination and abstraction unwind in certain ways. 277 00:35:28,770 --> 00:35:40,460 And then in general, what happens at the very top level, you might have rules in your database also, so things in this database might be rules. 278 00:35:40,460 --> 00:35:42,920 There are ways to check that things are true. 279 00:35:42,920 --> 00:35:46,750 So it might come in here and have to do a rule check. 280 00:35:46,750 --> 00:35:53,350 And then there's some control structure which says, well, you look at some rules, and you look at some data elements, and you look at some rules and data elements, and these fan out and out and out. 281 00:35:53,350 --> 00:36:00,245 So it becomes essentially impossible to say what order it's looking at these things in, whether it's breadth first or depth first or anything. 282 00:36:00,245 --> 00:36:11,270 And it's even more impossible because the actual order is somehow buried in the delays of the streams. So what's very hard to tell from this is the order in which it's scanned. 283 00:36:11,270 --> 00:36:15,820 But what's true, because you're looking at the stream view, is that all of them eventually get looked at. 284 00:36:24,980 --> 00:36:28,150 Let me just mention one tiny technical problem. 285 00:36:37,530 --> 00:36:45,780 Suppose I tried saying boss of y is computer, then a funny thing would happen. 286 00:36:45,780 --> 00:37:01,580 As I stuck a dictionary with y in here, I might get-- this y is not the same as that y, which was the other piece of somebody's job description. 287 00:37:01,580 --> 00:37:10,930 So if I really only did literally what I said, we'd get some variable conflict problems. So I lied to you a little bit. 288 00:37:10,930 --> 00:37:14,360 Notice that problem is exactly a problem we've run into before. 289 00:37:14,360 --> 00:37:20,505 It is precisely the need for local variables in a language. 290 00:37:20,505 --> 00:37:24,960 When I have the sum of squares, that x had better not be that x. 291 00:37:24,960 --> 00:37:31,800 That's exactly the same as this y had better not be that y. 292 00:37:31,800 --> 00:37:33,100 And we know how to solve that. 293 00:37:33,100 --> 00:37:37,710 That was this whole environment model, and we built chains of frames and all sorts of things like that. 294 00:37:37,710 --> 00:37:39,270 There's a much more brutal way to solve it. 295 00:37:39,270 --> 00:37:41,730 In the query language, we didn't even do that. 296 00:37:41,730 --> 00:37:43,540 We did something completely brutal. 297 00:37:43,540 --> 00:37:55,720 We said every time you apply a rule, rename consistently all the variables in the rule to some new unique names that won't conflict with anything. 298 00:37:55,720 --> 00:37:59,970 That's conceptually simpler, but really brutal and not particularly efficient. 299 00:37:59,970 --> 00:38:09,180 But notice, we could have gotten rid of all of our environment structures if we defined for procedures in Lisp the same thing. 300 00:38:09,180 --> 00:38:19,040 If every time we applied a procedure and did the substitution model we renamed all the variables in the procedure, then we never would have had to worry about local variables because they would never arise. 301 00:38:19,040 --> 00:38:25,610 OK, well, that would be inefficient, and it's inefficient here in the query language, too, but we did it to keep it simple. 302 00:38:25,610 --> 00:38:26,860 Let's break for questions. 303 00:38:30,880 --> 00:38:41,170 AUDIENCE: When you started this section, you emphasized how powerful our APPLY EVAL model was that we could use it for any language. 304 00:38:41,170 --> 00:38:43,950 And then you say we're going to have this language which is so different. 305 00:38:43,950 --> 00:38:47,880 It turns out that this language, as you just pointed out, is very much the same. 306 00:38:47,880 --> 00:38:57,030 I'm wondering if you're arguing that all languages end up coming down to this you can apply a rule or apply a procedure or some kind of apply? 307 00:38:57,030 --> 00:39:14,880 PROFESSOR: I would say that pretty much any language where you really are building up these means of combination and giving them simpler names and you're saying anything of the sort, like here's a general kind of expression, like how to square something, almost anything that you would call a procedure. 308 00:39:14,880 --> 00:39:18,020 If that's got to have parts, you have to unwind those parts. 309 00:39:18,020 --> 00:39:31,720 You have to have some kind of organization which says when I look at the abstract variables or tags or whatever you want to call them that might stand for particular things, you have to keep track of that, and that's going to be something like an environment. 310 00:39:31,720 --> 00:39:37,440 And then if you say this part can have parts which I have to unwind, you've got to have something like this cycle. 311 00:39:39,970 --> 00:39:45,590 And lots and lots of languages have that character when they sort of get put together in this way. 312 00:39:45,590 --> 00:39:50,690 This language again really is different because there's nothing like procedures on the outside. 313 00:39:50,690 --> 00:39:54,870 When you go below the surface and you see the implementation, of course, it starts looking the same. 314 00:39:54,870 --> 00:39:56,950 But from the outside, it's a very different world view. 315 00:39:56,950 --> 00:39:58,650 You're not computing functions of inputs. 316 00:40:03,970 --> 00:40:15,495 AUDIENCE: You mentioned earlier that when you build all of these rules in pattern matcher and with the delayed action of streams, you really have no way to know in what order things are evaluated. 317 00:40:15,495 --> 00:40:15,940 PROFESSOR: Right. 318 00:40:15,940 --> 00:40:23,950 AUDIENCE: And that would indicate then that you should only express declarative knowledge that's true for all-time, no-time sequence built into it. 319 00:40:23,950 --> 00:40:28,490 Otherwise, these things get all-- PROFESSOR: Yes. 320 00:40:28,490 --> 00:40:28,820 Yes. 321 00:40:28,820 --> 00:40:40,830 The question is this really is set up for doing declarative knowledge, and as I presented it-- and I'll show you some of the ugly warts under this after the break. 322 00:40:40,830 --> 00:40:43,070 As I presented it, it's just doing logic. 323 00:40:43,070 --> 00:40:48,840 And in principle, if it were logic, it wouldn't matter what order it's getting done. 324 00:40:48,840 --> 00:41:01,290 And it's quite true when you start doing things where you have side effects like adding things to the database and taking things out, and we'll see some others, you use that kind of control. 325 00:41:01,290 --> 00:41:02,940 So, for example, contrasting with Prolog. 326 00:41:02,940 --> 00:41:09,640 Say Prolog has various features where you really exploit the order of evaluation. 327 00:41:09,640 --> 00:41:11,770 And people write Prolog programs that way. 328 00:41:11,770 --> 00:41:18,590 That turns out to be very complicated in Prolog, although if you're an expert Prolog programmer, you can do it. 329 00:41:18,590 --> 00:41:20,210 However, here I don't think you can do it at all. 330 00:41:20,210 --> 00:41:27,150 It's very complicated because you really are giving up control over any prearranged order of trying things. 331 00:41:27,150 --> 00:41:30,670 AUDIENCE: Now, that would indicate then that you have a functional mapping. 332 00:41:30,670 --> 00:41:38,810 And when you started out this lecture, you said that we express the declarative knowledge which is a relation, and we don't talk about the inputs and the outputs. 333 00:41:41,390 --> 00:41:43,370 PROFESSOR: Well, there's a pun on functional, right? 334 00:41:43,370 --> 00:41:48,700 There's function in the sense of no side effects and not depending on what order is going on. 335 00:41:48,700 --> 00:41:52,220 And then there's functional in the sense of mathematical function, which means input and output. 336 00:41:52,220 --> 00:41:56,510 And it's just that pun that you're making, I think. 337 00:41:56,510 --> 00:42:01,270 AUDIENCE: I'm a little unclear on what you're doing with these two statements, the two boss statements. 338 00:42:01,270 --> 00:42:12,440 Is the first one building up the database and the second one a query or-- PROFESSOR: OK, I'm sorry. 339 00:42:12,440 --> 00:42:19,470 What I meant here, if I type something like this in as a query-- I should have given an example way at the very beginning. 340 00:42:19,470 --> 00:42:34,220 If I type in job, Ben Bitdiddle, computer wizard, what the processing will do is if it finds a match, it'll find a match to that exact thing, and it'll type out a job, Ben Bitdiddle, computer wizard. 341 00:42:34,220 --> 00:42:37,400 If it doesn't find a match, it won't find anything. 342 00:42:37,400 --> 00:42:50,680 So what I should have said is the way you use the query language to check whether something is true, remember, that's one of the things you want to do in logic programming, is you type in your query and either that comes out or it doesn't. 343 00:42:50,680 --> 00:42:57,480 So what I was trying to illustrate here, I wanted to start with a very simple example before talking about unifiers. 344 00:42:57,480 --> 00:43:07,830 So what I should have said, if I just wanted to check whether this is true, I could type that in and see if anything came out AUDIENCE: And then the second one-- PROFESSOR: The second one would be a real query. 345 00:43:07,830 --> 00:43:10,770 AUDIENCE: A real query, yeah. 346 00:43:10,770 --> 00:43:19,560 PROFESSOR: What would come out, see, it would go in here say with FOO, and in would go frame that says z is bound to who and d is bound to computer. 347 00:43:19,560 --> 00:43:23,250 And this will pass through, and then by the time it got out of here, who would pick up a binding. 348 00:43:26,950 --> 00:43:36,460 AUDIENCE: On the unifying thing there, I still am not sure what happens with who and z. 349 00:43:36,460 --> 00:43:46,260 If the unifying-- the rule here says-- OK, so you say that you can't make question mark equal to question mark who. 350 00:43:46,260 --> 00:43:46,410 PROFESSOR: Right. 351 00:43:46,410 --> 00:43:48,360 That's what the matcher can't do. 352 00:43:48,360 --> 00:43:53,800 But what this will mean to a unifier is that there's an environment with three variables. 353 00:43:56,690 --> 00:43:58,520 d here is computer. 354 00:43:58,520 --> 00:44:01,830 z is whatever who is. 355 00:44:01,830 --> 00:44:18,360 So if later on in the matcher routine it said, for example, who has to be 3, then when I looked up in the dictionary, it will say, oh, z is 3 because it's the same as who. 356 00:44:18,360 --> 00:44:22,640 And that's in some sense the only thing you need to do to extend the unifier to a matcher. 357 00:44:22,640 --> 00:44:29,770 AUDIENCE: OK, because it looked like when you were telling how to unify it, it looked like you would put the things together in such a way that you'd actually solve and have a value for both of them. 358 00:44:29,770 --> 00:44:34,860 And what it looks like now is that you're actually pass a dictionary with two variables and the variables are linked. 359 00:44:34,860 --> 00:44:35,130 PROFESSOR: Right. 360 00:44:35,130 --> 00:44:40,540 It only looks like you're solving for both of them because you're sort of looking at the whole solution at once. 361 00:44:40,540 --> 00:44:44,980 If you sort of watch the thing getting built up recursively, it's merely this. 362 00:44:44,980 --> 00:44:48,400 AUDIENCE: OK, so you do pass off that dictionary with two variables? 363 00:44:48,400 --> 00:44:49,110 PROFESSOR: That's right. 364 00:44:49,110 --> 00:44:50,190 AUDIENCE: And link? 365 00:44:50,190 --> 00:44:50,560 PROFESSOR: Right. 366 00:44:50,560 --> 00:44:54,055 It just looks like an ordinary dictionary. 367 00:44:54,055 --> 00:45:04,725 AUDIENCE: When you're talking about the unifier, is it that there are some cases or some points that you are not able to use by them? 368 00:45:04,725 --> 00:45:05,220 PROFESSOR: Right. 369 00:45:05,220 --> 00:45:18,540 AUDIENCE: Can you just by building the rules or writing the forms know in advance if you are going to be able to solve to get the unification or not? 370 00:45:18,540 --> 00:45:30,090 Can you add some properties either to the rules itself or to the formula that you're writing so that you avoid the problem of not finding unification? 371 00:45:30,090 --> 00:45:35,390 PROFESSOR: I mean, you can agree, I think, to write in a fairly restricted way where you won't run into it. 372 00:45:35,390 --> 00:45:55,300 See, because what you're getting-- see, the place where you get into problems is when you-- well, again, you're trying to match things like that against things where these have structure, where a, y, b, y something. 373 00:45:58,980 --> 00:46:03,070 So this is the kind of place where you're going to get into trouble. 374 00:46:03,070 --> 00:46:06,370 AUDIENCE: So you can do that syntactically? 375 00:46:06,370 --> 00:46:11,561 PROFESSOR: So you can kind of watch your rules in the kinds of things that your writing. 376 00:46:11,561 --> 00:46:16,310 AUDIENCE: So that's the problem that the builder of the database has to be concerned? 377 00:46:16,310 --> 00:46:17,560 PROFESSOR: That's a problem. 378 00:46:19,930 --> 00:46:25,800 It's a problem either-- not quite the builder of the database, the person who is expressing the rules, or the builder of the database. 379 00:46:25,800 --> 00:46:34,940 What the unifier actually does is you can check at the next level down when you actually get to the unifier and you'll see in the code where it looks up in the dictionary. 380 00:46:34,940 --> 00:46:37,260 If it sort of says what does y have to be? 381 00:46:37,260 --> 00:46:41,960 Oh, does y have to be something that contains a y as its expression? 382 00:46:41,960 --> 00:46:46,240 At that point, the unifier and say, oh my God, I'm trying to solve a fixed-point equation. 383 00:46:46,240 --> 00:46:49,220 I'll give it up here. 384 00:46:49,220 --> 00:46:51,910 AUDIENCE: You make the distinction between the rules in the database. 385 00:46:51,910 --> 00:46:56,950 Are the rules added to the database? 386 00:46:56,950 --> 00:46:57,870 PROFESSOR: Yes. 387 00:46:57,870 --> 00:46:58,870 Yes, I should have said that. 388 00:46:58,870 --> 00:47:03,890 One way to think about rules is that they're just other things in the database. 389 00:47:03,890 --> 00:47:09,445 So if you want to check the things that have to be checked in the database, they're kind of virtual facts that are in the database. 390 00:47:09,445 --> 00:47:18,230 AUDIENCE: But in that explanation, you made the differentiation between database and the rules itself. 391 00:47:18,230 --> 00:47:20,490 PROFESSOR: Yeah, I probably should not have done that. 392 00:47:20,490 --> 00:47:23,540 The only reason to do that is in terms of the implementation. 393 00:47:23,540 --> 00:47:30,470 When you look at the implementation, there's a part which says check either primitive assertions in the database or check rules. 394 00:47:30,470 --> 00:47:44,600 And then the real reason why you can't tell what order things are going to come out in and is that the rules database and the data database sort of get merged in a kind of delayed evaluation way. 395 00:47:44,600 --> 00:47:46,320 And so that's what makes the order very complicated. 396 00:47:55,440 --> 00:47:56,690 OK, let's break. 397 00:48:33,160 --> 00:48:37,230 We've just seen how the logic language works and how rules work. 398 00:48:37,230 --> 00:48:40,120 Now, let's turn to a more profound question. 399 00:48:40,120 --> 00:48:43,180 What do these things mean? 400 00:48:43,180 --> 00:48:53,570 That brings us to the subtlest, most devious part of this whole query language business, and that is that it's not quite what it seems to be. 401 00:48:53,570 --> 00:49:07,690 AND and OR and NOT and the logical implication of rules are not really the AND and OR and NOT and logical implication of logic. 402 00:49:07,690 --> 00:49:09,910 Let me give you an example of that. 403 00:49:09,910 --> 00:49:30,100 Certainly, if we have two things in logic, it ought to be the case that AND of P and Q is the same as AND of Q and P and that OR of P and Q is the same as OR of Q and P. But let's look here. 404 00:49:30,100 --> 00:49:32,180 Here's an example. 405 00:49:32,180 --> 00:49:40,140 Let's talk about somebody outranking somebody else in our little database organization. 406 00:49:40,140 --> 00:49:55,640 We'll say s is outranked by b or if either the supervisor of this is b or there's some middle manager here, that supervisor of s is m, and m is outranked by b. 407 00:49:59,830 --> 00:50:02,310 So there's one way to define rule outranked by. 408 00:50:02,310 --> 00:50:11,630 Or we can write exactly the same thing, except at the bottom here, we reversed the order of these two clauses. 409 00:50:11,630 --> 00:50:16,690 And certainly if this were logic, those ought to mean the same thing. 410 00:50:16,690 --> 00:50:34,110 However, in our particular implementation, if you say something like who's outranked by Ben Bitdiddle, what you'll find is that this rule will work perfectly well and generate answers, whereas this rule will go into an infinite loop. 411 00:50:34,110 --> 00:50:39,400 And the reason for that is that this will come in and say, oh, who's outranked by Ben Bitdiddle? 412 00:50:41,920 --> 00:50:50,330 Find an s which is outranked by b, where b is Ben Bitdiddle, which is going to happen in it a subproblem. 413 00:50:50,330 --> 00:50:58,560 Oh gee, find an m such as m is outranked by Ben Bitdiddle with no restrictions on m. 414 00:50:58,560 --> 00:51:04,570 So this will say in order to solve this problem, I solve exactly the same problem. 415 00:51:04,570 --> 00:51:08,000 And then after I've solved that, I'll check for a supervisory relationship. 416 00:51:08,000 --> 00:51:15,260 Whereas this one won't get into that, because before it tries to find this outranked by, it'll already have had a restriction on m here. 417 00:51:18,560 --> 00:51:22,860 So these two things which ought to mean the same, in fact, one goes into an infinite loop. 418 00:51:22,860 --> 00:51:26,720 One does not. 419 00:51:26,720 --> 00:51:42,240 That's a very extreme case of a general thing that you'll find in logic programming that if you start changing the order of the things in the ANDs or ORs, you'll find tremendous differences in efficiency. 420 00:51:42,240 --> 00:51:47,110 And we just saw an infinitely big difference in efficiency and an infinite loop. 421 00:51:49,190 --> 00:51:54,070 And there are similar things having to do with the order in which you enter rules. 422 00:51:54,070 --> 00:52:03,840 The order in which it happens to look at rules in the database may vastly change the efficiency with which it gets out answers or, in fact, send it into an infinite loop for some orderings. 423 00:52:03,840 --> 00:52:10,950 And this whole thing has to do with the fact that you're checking these rules in some order. 424 00:52:10,950 --> 00:52:15,180 And some rules may lead to really long paths of implication. 425 00:52:15,180 --> 00:52:16,440 Others might not. 426 00:52:16,440 --> 00:52:19,300 And you don't know a priori which ones are good and which ones are bad. 427 00:52:19,300 --> 00:52:26,970 And there's a whole bunch of research having to do with that, mostly having to do with thinking about making parallel implementations of logic programming languages. 428 00:52:26,970 --> 00:52:32,620 And in some sense, what you'd like to do is check all rules in parallel and whichever ones get answers, you bubble them up. 429 00:52:32,620 --> 00:52:40,550 And if some go down infinite deductive changed, well, you just-- you know, memory is cheap and processors are cheap, and you just let them buzz for as for as long as you want. 430 00:52:43,510 --> 00:52:50,870 There's a deeper problem, though, in comparing this logic language to real logic. 431 00:52:50,870 --> 00:52:58,370 The example I just showed you, it went into an infinite loop maybe, but at least it didn't give the wrong answer. 432 00:52:58,370 --> 00:53:09,490 There's an actual deeper problem when we start comparing, seriously comparing this logic language with real classical logic. 433 00:53:09,490 --> 00:53:14,030 So let's sort of review real classical logic. 434 00:53:14,030 --> 00:53:22,140 All humans are mortal. 435 00:53:22,140 --> 00:53:24,390 That's pretty classical logic. 436 00:53:24,390 --> 00:53:29,120 Then maybe we'll continue in the very best classical tradition. 437 00:53:29,120 --> 00:53:32,740 We'll say all-- let's make it really classical. 438 00:53:32,740 --> 00:53:48,060 All Greeks are human, which has the syllogism that Socrates is a Greek. 439 00:53:48,060 --> 00:53:49,210 And then what do you write here? 440 00:53:49,210 --> 00:53:51,890 I think three dots, classical logic. 441 00:53:51,890 --> 00:54:01,360 Therefore, then the syllogism, Socrates is mortal. 442 00:54:01,360 --> 00:54:05,880 So there's some real honest classical logic. 443 00:54:05,880 --> 00:54:12,570 Let's compare that with our classical logic database. 444 00:54:12,570 --> 00:54:16,270 So here's a classical logic database. 445 00:54:16,270 --> 00:54:18,030 Socrates is a Greek. 446 00:54:18,030 --> 00:54:19,600 Plato is a Greek. 447 00:54:19,600 --> 00:54:24,120 Zeus is a Greek, and Zeus is a god. 448 00:54:24,120 --> 00:54:30,780 And all humans are mortal. 449 00:54:30,780 --> 00:54:34,650 To show that something is mortal, it's enough to show that it's human. 450 00:54:34,650 --> 00:54:35,900 All humans are fallible. 451 00:54:38,900 --> 00:54:40,980 And all Greeks are humans is not quite right. 452 00:54:40,980 --> 00:54:45,920 This says that all Greeks who are not gods are human. 453 00:54:45,920 --> 00:54:49,320 So to show something's human, it's enough to show it's a Greek and not a god. 454 00:54:49,320 --> 00:54:54,470 And the address of any Greek god is Mount Olympus. 455 00:54:54,470 --> 00:54:57,390 So there's a little classical logic database. 456 00:54:57,390 --> 00:54:59,490 And indeed, that would work fairly well. 457 00:54:59,490 --> 00:55:06,910 If we type that in and say is Socrates mortal or Socrates fallible or mortal? 458 00:55:06,910 --> 00:55:07,690 It'll say yes. 459 00:55:07,690 --> 00:55:09,710 Is Plato mortal and fallible. 460 00:55:09,710 --> 00:55:10,680 It'll say yes. 461 00:55:10,680 --> 00:55:12,210 If we say is Zeus mortal? 462 00:55:12,210 --> 00:55:14,900 It won't find anything. 463 00:55:14,900 --> 00:55:16,640 And it'll work perfectly well. 464 00:55:16,640 --> 00:55:20,120 However, suppose we want to extend this. 465 00:55:20,120 --> 00:55:25,070 Let's define what it means for someone to be a perfect being. 466 00:55:25,070 --> 00:55:27,020 Let's say rule: a perfect being. 467 00:55:34,050 --> 00:55:35,480 And I think this is right. 468 00:55:35,480 --> 00:55:44,100 If you're up on your medieval scholastic philosophy, I believe that perfect beings are ones who were neither mortal nor fallible. 469 00:55:44,100 --> 00:55:59,300 AND NOT mortal x, NOT fallible x. 470 00:55:59,300 --> 00:56:05,790 So we'll define this system to teach it what a perfect being is. 471 00:56:05,790 --> 00:56:11,750 And now what we're going to do is he ask for the address of all the perfect beings. 472 00:56:11,750 --> 00:56:23,680 AND the address of x is y and x is perfect. 473 00:56:23,680 --> 00:56:33,830 And so what we're generating here is the world's most exclusive mailing list. For the address of all the perfect things, we might have typed this in. 474 00:56:33,830 --> 00:56:36,240 Or we might type in this. 475 00:56:36,240 --> 00:56:52,140 We'll say AND perfect of x and the address of x is y. 476 00:56:52,140 --> 00:56:55,190 Well, suppose we type all that in and we try this query. 477 00:56:55,190 --> 00:56:57,650 This query is going to give us an answer. 478 00:56:57,650 --> 00:56:59,745 This query will say, yeah, Mount Olympus. 479 00:57:04,230 --> 00:57:06,740 This query, in fact, is going to give us nothing. 480 00:57:06,740 --> 00:57:11,640 It will say no addresses of perfect beings. 481 00:57:11,640 --> 00:57:12,510 Now, why is that? 482 00:57:12,510 --> 00:57:14,230 Why is there a difference? 483 00:57:14,230 --> 00:57:15,690 This is not an infinite loop question. 484 00:57:15,690 --> 00:57:19,145 This is a different answer question. 485 00:57:19,145 --> 00:57:25,880 The reason is that if you remember the implementation of NOT, NOT acted as a filter. 486 00:57:25,880 --> 00:57:36,520 NOT said I'm going to take some possible dictionaries, some possible frames, some possible answers, and filter out the ones that happened to satisfy some condition, and that's how I implement NOT. 487 00:57:36,520 --> 00:57:47,720 If you think about what's going on here, I'll build this query box where the output of an address piece gets fed into a perfect piece. 488 00:57:50,290 --> 00:57:55,290 What will happen is the address piece will set up some things of everyone whose address I know. 489 00:57:55,290 --> 00:57:59,880 Those will get filtered by the NOTs inside perfect here. 490 00:57:59,880 --> 00:58:04,910 So it will throw out the ones which happened to be either mortal or fallible. 491 00:58:04,910 --> 00:58:09,520 In the other order what happens is I set this up, started up with an empty frame. 492 00:58:09,520 --> 00:58:13,920 The perfect in here doesn't find anything for the NOTs to filter, so nothing comes out here at all. 493 00:58:18,830 --> 00:58:21,940 And there's sort of nothing there that gets fed into the address thing. 494 00:58:21,940 --> 00:58:24,260 So here, I don't get an answer. 495 00:58:24,260 --> 00:58:27,440 And again, the reason for that is NOT isn't generating anything. 496 00:58:27,440 --> 00:58:28,800 NOT's only throwing out things. 497 00:58:28,800 --> 00:58:32,020 And if I never started up with anything, there's nothing for it to throw out. 498 00:58:32,020 --> 00:58:33,770 So out of this thing, I get the wrong answer. 499 00:58:37,200 --> 00:58:37,970 How can you fix that? 500 00:58:37,970 --> 00:58:39,070 Well, there are ways to fix that. 501 00:58:39,070 --> 00:58:41,410 So you might say, well, that's sort of stupid. 502 00:58:41,410 --> 00:58:44,900 Why are you just doing all your NOT stuff at the beginning? 503 00:58:44,900 --> 00:58:58,560 The right way to implement NOT is to realize that when you have conditions like NOT, you should generate all your answers first, and then with each of these dictionaries pass along until at the very end I'll do filtering. 504 00:58:58,560 --> 00:59:04,050 And there are implementations of logic languages that work like that that solve this particular problem. 505 00:59:06,660 --> 00:59:12,530 However, there's a more profound problem, which is which one of these is the right answer? 506 00:59:12,530 --> 00:59:15,320 Is it Mount Olympus or is it nothing? 507 00:59:15,320 --> 00:59:24,805 So you might say it's Mount Olympus, because after all, Zeus is in that database, and Zeus was neither mortal nor fallible. 508 00:59:29,550 --> 00:59:44,120 So you might say Zeus wants to satisfy NOT mortal Zeus or NOT fallible Zeus. 509 00:59:44,120 --> 00:59:47,638 But let's actually look at that database. 510 00:59:47,638 --> 00:59:49,320 Let's look at it. 511 00:59:49,320 --> 00:59:54,810 There's no way-- how does it know that Zeus is not fallible? 512 00:59:54,810 --> 00:59:57,930 There's nothing in there about that. 513 00:59:57,930 --> 00:59:59,410 What's in there is that humans are fallible. 514 01:00:02,390 --> 01:00:04,430 How does it know that Zeus is not mortal? 515 01:00:04,430 --> 01:00:07,980 There's nothing in there about that. 516 01:00:07,980 --> 01:00:16,690 It just said I don't have any rule, which-- the only way I can deduce something's mortal is if it's human, and that's all it really knows about mortal. 517 01:00:16,690 --> 01:00:25,300 And in fact, if you remember your classical mythology, you know that the Greek gods were not mortal but fallible. 518 01:00:25,300 --> 01:00:30,850 So the answer is not in the rules there. 519 01:00:30,850 --> 01:00:32,100 See, why does it deduce that? 520 01:00:34,710 --> 01:00:40,080 See, Socrates would certainly not have made this error of logic. 521 01:00:40,080 --> 01:00:43,370 What NOT needs in this language is not NOT. 522 01:00:43,370 --> 01:00:44,930 It's not the NOT of logic. 523 01:00:44,930 --> 01:00:55,140 What NOT needs in this language is not deducible from things in the database as opposed to not true. 524 01:00:55,140 --> 01:00:57,300 That's a very big difference. 525 01:00:57,300 --> 01:00:59,250 Subtle, but big. 526 01:00:59,250 --> 01:01:04,610 So, in fact, this is perfectly happy to say not anything that it doesn't know about. 527 01:01:04,610 --> 01:01:07,830 So if you ask it is it not true that Zeus likes chocolate ice cream? 528 01:01:07,830 --> 01:01:10,251 It will say sure, it's not true. 529 01:01:10,251 --> 01:01:12,850 Or anything else or anything it doesn't know about. 530 01:01:12,850 --> 01:01:18,280 NOT means not deducible from the things you've told me. 531 01:01:18,280 --> 01:01:27,050 In a world where you're identifying not deducible with, in fact, not true, this is called the closed world assumption. 532 01:01:36,870 --> 01:01:38,320 The closed world assumption. 533 01:01:38,320 --> 01:01:46,500 Anything that I cannot deduce from what I know is not true, right? 534 01:01:46,500 --> 01:01:49,290 If I don't know anything about x, the x isn't true. 535 01:01:49,290 --> 01:01:51,420 That's very dangerous. 536 01:01:51,420 --> 01:01:54,480 From a logical point of view, first of all, it doesn't really makes sense. 537 01:01:54,480 --> 01:02:00,240 Because if I don't know anything about x, I'm willing to say not x. 538 01:02:00,240 --> 01:02:03,850 But am I willing to say not not x? 539 01:02:03,850 --> 01:02:06,470 Well, sure, I don't know anything about that either maybe. 540 01:02:06,470 --> 01:02:15,970 So not not x is not necessarily the same as x and so on and so on and so on, so there's some sort of funny bias in there. 541 01:02:15,970 --> 01:02:17,290 So that's sort of funny. 542 01:02:17,290 --> 01:02:27,210 The second thing, if you start building up real reasoning programs based on this, think how dangerous that is. 543 01:02:27,210 --> 01:02:37,780 You're saying I know I'm in a position to deduce everything true that's relevant to this problem. 544 01:02:37,780 --> 01:02:48,860 I'm reasoning, and built into my reasoning mechanism is the assumption that anything that I don't know can't possibly be relevant to this problem, right? 545 01:02:48,860 --> 01:02:54,720 There are a lot of big organizations that work like that, right? 546 01:02:54,720 --> 01:02:56,830 Most corporate marketing divisions work like that. 547 01:02:56,830 --> 01:03:00,560 You know the consequences to that. 548 01:03:00,560 --> 01:03:12,600 So it's very dangerous to start really typing in these big logical implication systems and going on what they say, because they have this really limiting assumption built in. 549 01:03:12,600 --> 01:03:14,905 So you have to be very, very careful about that. 550 01:03:14,905 --> 01:03:16,560 And that's a deep problem. 551 01:03:16,560 --> 01:03:23,840 That's not a problem about we can make a little bit cleverer implementation and do the filters and organize the infinite loops to make them go away. 552 01:03:23,840 --> 01:03:25,920 It's a different kind of problem. 553 01:03:25,920 --> 01:03:27,060 It's a different semantics. 554 01:03:27,060 --> 01:03:50,560 So I think to wrap this up, it's fair to say that logic programming I think is a terrifically exciting idea, the idea that you can bridge this gap from the imperative to the declarative, that you can start talking about relations and really get tremendous power by going above the abstraction of what's my input and what's my output. 555 01:03:50,560 --> 01:03:58,080 And linked to logic, the problem is it's a goal that I think has yet to be realized. 556 01:03:58,080 --> 01:04:09,460 And probably one of the very most interesting research questions going on now in languages is how do you somehow make a real logic language? 557 01:04:09,460 --> 01:04:18,680 And secondly, how do you bridge the gap from this world of logic and relations to the worlds of more traditional languages and somehow combine the power of both. 558 01:04:18,680 --> 01:04:19,930 OK, let's break. 559 01:04:23,750 --> 01:04:27,430 AUDIENCE: Couldn't you solve that last problem by having the extra rules that imply it? 560 01:04:27,430 --> 01:04:32,210 The problem here is you have the definition of something, but you don't have the definition of its opposite. 561 01:04:32,210 --> 01:04:40,370 If you include in the database something that says something implies mortal x, something else implies not mortal x, haven't you basically solved the problem? 562 01:04:43,370 --> 01:04:46,910 PROFESSOR: But the issue is do you put a finite number of those in? 563 01:04:50,740 --> 01:04:57,220 AUDIENCE: If things are specified always in pairs-- PROFESSOR: But the impression is then what do you do about deduction? 564 01:05:00,200 --> 01:05:03,400 You can't specify NOTs. 565 01:05:03,400 --> 01:05:07,960 But the problem is, in a big system, it turns out that might not be a finite number of things. 566 01:05:12,820 --> 01:05:15,290 There are also sort of two issues. 567 01:05:15,290 --> 01:05:16,690 Partly it might not be finite. 568 01:05:16,690 --> 01:05:21,510 Partly it might be that's not what you want. 569 01:05:21,510 --> 01:05:25,120 So a good example would be suppose I want to do connectivity. 570 01:05:25,120 --> 01:05:28,050 I want a reason about connectivity. 571 01:05:28,050 --> 01:05:35,480 And I'm going to tell you there's four things: a and b and c and d. 572 01:05:35,480 --> 01:05:43,200 And I'll tell you a is connected to b and c's connected to d. 573 01:05:43,200 --> 01:05:45,260 And now I'll tell you is a connected to d? 574 01:05:45,260 --> 01:05:46,780 That's the question. 575 01:05:46,780 --> 01:05:50,610 There's an example where I would like something like the closed world assumption. 576 01:05:54,200 --> 01:06:01,340 That's a tiny toy, but a lot of times, I want to be able to say something like anything that I haven't told you, assume is not true. 577 01:06:04,260 --> 01:06:09,470 So it's not as simple as you only want to put in explicit NOTs all over the place. 578 01:06:09,470 --> 01:06:14,150 It's that sometimes it really isn't clear what you even want. 579 01:06:14,150 --> 01:06:20,960 That having to specify both everything and not everything is too precise, and then you get down into problems there. 580 01:06:20,960 --> 01:06:26,510 But there are a lot of approaches that explicitly put in NOTs and reason based on that. 581 01:06:26,510 --> 01:06:28,070 So it's a very good idea. 582 01:06:28,070 --> 01:06:33,490 It's just that then it starts becoming a little cumbersome in the very large problems you'd like to use. 583 01:06:43,460 --> 01:06:53,840 AUDIENCE: I'm not sure how directly related to the argument this is, but one of your points was that one of the dangers of the closed rule is you never really know all the things that are there. 584 01:06:53,840 --> 01:06:55,930 You never really know all the parts to it. 585 01:06:55,930 --> 01:06:58,160 Isn't that a major problem with any programming? 586 01:06:58,160 --> 01:07:07,390 I always write programs where I assume that I've got all the cases, and so I check for them all or whatever, and somewhere down the road, I find out that I didn't check for one of them. 587 01:07:07,390 --> 01:07:08,540 PROFESSOR: Well, sure, it's true. 588 01:07:08,540 --> 01:07:19,600 But the problem here is it's that assumption which is the thing that you're making if you believe you're identifying this with logic. 589 01:07:19,600 --> 01:07:20,510 So you're quite right. 590 01:07:20,510 --> 01:07:22,220 It's a situation you're never in. 591 01:07:22,220 --> 01:07:33,470 The problem is if you're starting to believe that what this is doing is logic and you look at the rules you write down and say what can I deduce from them, you have to be very careful to remember that NOT means something else. 592 01:07:33,470 --> 01:07:39,030 And it means something else based on an assumption which is probably not true. 593 01:07:39,030 --> 01:07:47,990 AUDIENCE: Do I understand you correctly that you cannot fix this problem without killing off all possibilities of inference through altering NOT? 594 01:07:47,990 --> 01:07:49,370 PROFESSOR: No, that's not quite right. 595 01:07:49,370 --> 01:07:56,340 There are other-- there are ways to do logic with real NOTs. 596 01:07:56,340 --> 01:07:58,540 There are actually ways to do that. 597 01:07:58,540 --> 01:08:01,610 But they're very inefficient as far as anybody knows. 598 01:08:01,610 --> 01:08:11,980 And they're much more-- the, quote, inference in here is built into this unifier and this pattern matching unification algorithm. 599 01:08:11,980 --> 01:08:16,590 There are ways to automate real logical reasoning. 600 01:08:16,590 --> 01:08:23,850 But it's not based on that, and logic programming languages don't tend to do that because it's very inefficient as far as anybody knows. 601 01:08:29,390 --> 01:08:30,640 All right, thank you. ================================================ FILE: SrtCN/lec8b.srt ================================================ 1 00:00:00,000 --> 00:00:02,144 Learning-SICP 学习小组 倾情制作 2 00:00:02,400 --> 00:00:05,600 《计算机程序的构造和解释》 3 00:00:18,910 --> 00:00:21,792 我们已经了解了查询语言的使用方式 PROFESSOR: All right, well, we've seen how the query language works. 4 00:00:22,640 --> 00:00:25,072 现在该来讨论如何实现了 Now, let's talk about how it's implemented. 5 00:00:26,280 --> 00:00:27,984 你们也应该能够猜到 You already pretty much can guess 6 00:00:28,592 --> 00:00:29,470 它其中的原理了 what's going on there. 7 00:00:29,470 --> 00:00:31,648 它的最底层是一个模式匹配器 At the bottom of it, there's a pattern matcher. 8 00:00:32,810 --> 00:00:34,256 我们在《基于规则的控制语言》一课中 And we looked at a pattern matcher 9 00:00:34,672 --> 00:00:36,944 已经介绍过模式匹配器了 when we did the rule-based control language. 10 00:00:38,110 --> 00:00:40,592 我举个例子来让你们温习一下 Just to remind you, here are some sample patterns. 11 00:00:41,520 --> 00:00:43,680 这个模式会匹配 This is a pattern that will match 12 00:00:43,808 --> 00:00:44,928 一个含有三个元素的表 any list of three things 13 00:00:44,960 --> 00:00:47,104 其中 首元素为A which the first is a 14 00:00:47,168 --> 00:00:48,336 其次是C the second is c 15 00:00:48,480 --> 00:00:50,192 而中间可以为任意元素 and the middle one can be anything. 16 00:00:50,650 --> 00:00:52,272 所以在这个小型的模式匹配语言中 So in this little pattern-matching syntax, 17 00:00:52,304 --> 00:00:54,050 你只能区分一种类型 there's only one distinction you make. 18 00:00:54,050 --> 00:00:57,200 也就是区分字面量或者变量 There's either literal things or variables, 19 00:00:57,232 --> 00:00:58,864 以问号开头的就是变量 and variables begin with question mark. 20 00:01:01,370 --> 00:01:03,648 因此这个模式会匹配任意的三元表 So this matches any list of three things 21 00:01:04,448 --> 00:01:06,500 只要它的首元素为A 而第三个元素为C of which the first is a and the second is c. 22 00:01:06,500 --> 00:01:09,008 而这个模式匹配的三元表 This one matches any list of three things 23 00:01:10,432 --> 00:01:12,530 它的首元素必须是符号'JOB of which the first is the symbol job. 24 00:01:12,530 --> 00:01:13,904 第二个元素为任意值 The second can be anything. 25 00:01:14,210 --> 00:01:15,904 第三个元素必须是一个二元表 And the third is a list of two things 26 00:01:15,952 --> 00:01:17,728 二元表的首元素为符号'COMPUTER of which the first is the symbol computer 27 00:01:17,888 --> 00:01:19,424 第二个元素可以为任意值 and the second can be anything. 28 00:01:20,480 --> 00:01:25,552 而下一条模式所匹配的三元表 And this one, this next one matches any list of three things, 29 00:01:25,872 --> 00:01:26,992 区别就在于 and the only difference is, 30 00:01:28,400 --> 00:01:31,320 在于第三个元素的首元素必须为符号'COMPUTER here, the third list, the first is the symbol computer, 31 00:01:31,760 --> 00:01:33,296 表剩余部分可以是任意值 and then there's some rest of the list. 32 00:01:35,040 --> 00:01:37,536 也就是说 上面是二元表 而下面没有限定数目 So this means two elements and this means arbitrary number. 33 00:01:37,860 --> 00:01:39,744 然而我们的语言实现 And our language implementation isn't 34 00:01:39,856 --> 00:01:42,064 根本不用操心如何去实现这个点号 isn't even going to have to worry about implementing this dot 35 00:01:42,112 --> 00:01:44,176 因为这个由Lisp读取器自动地完成 because that's automatically done by Lisp's reader. 36 00:01:48,340 --> 00:01:50,310 要注意 匹配器还要保持一致性 Remember matchers also have some consistency in them. 37 00:01:50,310 --> 00:01:52,320 这个模式匹配一个三元表 This match is a list of three things 38 00:01:52,592 --> 00:01:53,984 表的首元素是A of which the first is a. 39 00:01:54,430 --> 00:01:55,792 而第二个元素和第三个元素可以是任意值 And the second and third can be anything, 40 00:01:55,808 --> 00:01:57,088 但它们必须是相同的 but they have to be the same thing. 41 00:01:57,940 --> 00:01:58,848 它们都是?X They're both called x. 42 00:01:59,600 --> 00:02:01,552 而这个模式匹配一个四元表 And this matches a list of four things 43 00:02:01,968 --> 00:02:03,264 其中第一个元素与第四个元素相同 of which the first is the fourth 44 00:02:03,664 --> 00:02:05,152 而第二个元素与第三个元素相同 and the second is the same as the third. 45 00:02:05,590 --> 00:02:08,608 最后一个模式匹配以A开头的任意表 And this last one matches any list that begins with a. 46 00:02:09,680 --> 00:02:11,056 以A开头 The first thing is a, 47 00:02:11,232 --> 00:02:12,560 余下的可以是任意值 and the rest can be anything. 48 00:02:14,040 --> 00:02:16,608 这是对我们已经学习过的模式匹配语言 So that's just a review of pattern matcher syntax 49 00:02:16,624 --> 00:02:17,872 的一个回顾 that you've already seen. 50 00:02:18,780 --> 00:02:19,648 还记得吗 And remember, 51 00:02:19,792 --> 00:02:22,288 这是由一个叫做MATCH的过程实现的 that's implemented by some procedure called match. 52 00:02:24,870 --> 00:02:36,064 MATCH有三个参数:PAT、DATA以及DICTIONARY And match takes a pattern and some data and a dictionary. 53 00:02:43,200 --> 00:02:47,120 MATCH考虑的是 And match asks the question 54 00:02:47,790 --> 00:02:52,640 利用给定DICTIONAY中的绑定 is there any way to match this pattern against this data object 55 00:02:53,552 --> 00:02:56,736 能够找到一种方法把模式与数据对象匹配起来吗? subject to the bindings that are already in this dictionary? 56 00:02:58,160 --> 00:02:59,216 比如说 So, for instance, 57 00:02:59,568 --> 00:03:06,432 如果我们想要把模式(?X ?Y ?Y ?X) if we're going to match the pattern x, y, y, x 58 00:03:07,712 --> 00:03:13,840 与数据对象(A B B A)相匹配 against the data a, b, b, a 59 00:03:15,120 --> 00:03:20,528 又给定了一个字典 X=A subject to a dictionary, that says x equals a. 60 00:03:22,010 --> 00:03:25,232 MATCH就会说:“它们是一致的” Then the matcher would say, yes, that's consistent. 61 00:03:25,260 --> 00:03:27,168 再给定的字典说 X=A 的情况下 These match, and it's consistent 62 00:03:27,808 --> 00:03:30,208 模式与数据相匹配 with what's in the dictionary to say that x equals a. 63 00:03:30,320 --> 00:03:31,600 而匹配的结果则是 And the result of the match 64 00:03:32,256 --> 00:03:34,304 一个扩展了的词典 is the extended dictionary 65 00:03:34,464 --> 00:03:37,600 其中包含 X=A Y=B that says x equals a and y equals b. 66 00:03:39,490 --> 00:03:42,240 MATCH接收模式、数据以及字典 So a matcher takes in pattern data dictionary, 67 00:03:42,384 --> 00:03:44,544 如果成功匹配就输出一个扩展后的词典 puts out an extended dictionary if it matches, 68 00:03:44,976 --> 00:03:46,840 否则就报错 or if it doesn't match, says that it fails. 69 00:03:46,840 --> 00:03:47,712 因此 比如说 So, for example, 70 00:03:47,888 --> 00:03:50,384 如果我在这里使用同样的模式 if I use the same pattern here, 71 00:03:50,976 --> 00:03:55,120 如果我用模式(?X ?Y ?Y ?X) if I say this x, y, y, x 72 00:03:55,660 --> 00:03:58,496 去匹配(A B B A) match a, b, b, a 73 00:03:59,470 --> 00:04:02,840 并给定词典 Y=A with the dictionary y equals a, 74 00:04:05,152 --> 00:04:06,816 那么MATCH就会输出FAIL then the matcher would put out fail. 75 00:04:12,528 --> 00:04:14,656 你们已经见过模式匹配器的代码了 Well, you've already seen the code for a pattern matcher 76 00:04:15,008 --> 00:04:16,176 我就不会再去细讲 so I'm not going to go over it, 77 00:04:16,640 --> 00:04:19,776 这跟我们以前做的类似 but it's the same thing we've been doing before. 78 00:04:21,190 --> 00:04:23,220 我们在《基于规则的系统》中已经见过了 You saw that in the system on rule-based control. 79 00:04:23,220 --> 00:04:24,560 基本上是同样的匹配器 It's essentially the same matcher. 80 00:04:24,950 --> 00:04:27,664 实际上 我认为这里的语法还更简单一点 In fact, I think the syntax is a little bit simpler 81 00:04:28,160 --> 00:04:29,312 因为我们不用去关心 because we're not worrying about 82 00:04:29,408 --> 00:04:31,400 任意变量、任意表达式之类的东西 arbitrary constants and expressions and things. 83 00:04:31,400 --> 00:04:32,880 这里面只区分变量和常量 There's just variables and constants. 84 00:04:35,790 --> 00:04:37,328 那么 有了模式匹配器以后 OK, well, given that, 85 00:04:38,464 --> 00:04:39,610 基本查询又是怎么样的呢? what's a primitive query? 86 00:04:42,970 --> 00:04:45,344 基本查询将会是一个相当复杂的东西 Primitive query is going to be a rather complicated thing. 87 00:04:46,672 --> 00:05:03,580 就拿查询(JOB ?X (?D . ?Y))来说 It's going to be-- let's think about the query job of x is d dot y. 88 00:05:07,040 --> 00:05:08,736 我们可能会输入这样的查询 That's a query we might type in. 89 00:05:09,400 --> 00:05:11,392 这又将如何在系统内实现呢? That's going to be implemented in the system. 90 00:05:14,144 --> 00:05:15,664 我们可以把它想做这个小盒子 We'll think of it as this little box. 91 00:05:15,700 --> 00:05:16,800 这是一条基本查询 Here's the primitive query. 92 00:05:18,880 --> 00:05:20,304 这个小盒子将会 What this little box is going to do 93 00:05:22,240 --> 00:05:27,280 以两条流作为输入 is take in two streams and put out a stream. 94 00:05:31,968 --> 00:05:33,200 并输出一条流 and put out a stream. 95 00:05:34,030 --> 00:05:36,192 因此一条基本查询的形状 So the shape of a primitive query 96 00:05:36,512 --> 00:05:38,464 就将是有两条输入流 is that it's a thing where two streams come in 97 00:05:38,672 --> 00:05:39,968 和一条输出流 and one stream goes out. 98 00:05:41,120 --> 00:05:46,208 而这些流 来自于这里的数据库 What these streams are going to be is down here is the database. 99 00:05:51,952 --> 00:05:53,936 因此我们把数据库中的所有数据 So we imagine all the things in the database 100 00:05:55,930 --> 00:05:57,200 想象成一条流 sort of sitting there in a stream 101 00:05:57,310 --> 00:05:58,400 而这个盒子不断地吸取 and this thing sucks on them. 102 00:06:00,368 --> 00:06:02,432 那么 数据库中有什么呢? So what are some things that might be in the database? 103 00:06:08,432 --> 00:06:20,320 首先是(JOB (ALYSSA ...)) Oh, job of Alyssa is something 104 00:06:21,968 --> 00:06:23,712 以及还有其它的JOB数据 and some other job is something. 105 00:06:25,770 --> 00:06:30,416 想象一下 数据库中的所有事实都在这条流中 So imagine all of the facts in the database sitting there in the stream. 106 00:06:32,040 --> 00:06:33,104 都到了这里 That's what comes in here. 107 00:06:33,360 --> 00:06:34,528 而这条流送来的 What comes in here 108 00:06:34,896 --> 00:06:36,520 是一些字典 is a stream of dictionaries. 109 00:06:38,510 --> 00:06:41,408 其中一个就可能是 So one particular dictionary might say 110 00:06:46,704 --> 00:06:49,312 Y=PROG might say y equals programmer. 111 00:06:55,470 --> 00:06:56,640 现在 查询工作就是要 Now, what the query does 112 00:06:57,072 --> 00:06:59,808 当它从这条流中取得一个字典后 when it gets in a dictionary from this stream, 113 00:07:02,010 --> 00:07:06,672 它会搜寻数据库中的东西 it finds all possible ways of matching the query 114 00:07:07,456 --> 00:07:10,240 来尽可能产生所有匹配结果 against whatever is coming in from the database. 115 00:07:11,390 --> 00:07:12,896 它把查询视作一种模式 It looks at the query as a pattern, 116 00:07:13,152 --> 00:07:16,720 并将它们与数据库中的事实匹配起来 matches it against any fact from the database 117 00:07:16,960 --> 00:07:21,984 结合着相应的字典中的数据 or all possible ways of finding and matching the database 118 00:07:22,944 --> 00:07:25,680 找到数据库中所有匹配的结果 with respect to this dictionary that's coming in. 119 00:07:27,550 --> 00:07:29,696 所以针对数据库中的每条事实 So for each fact in the database, 120 00:07:29,728 --> 00:07:34,350 它都会调用(MATCH PAT FACT DICTIONAY)来检查 it calls the matcher using the pattern, fact, and dictionary. 121 00:07:35,110 --> 00:07:37,680 如果成功匹配 And every time it gets a good match, 122 00:07:38,192 --> 00:07:39,936 它就输出一个扩展了的字典 it puts out the extended dictionary. 123 00:07:40,672 --> 00:07:42,320 比如说 这里进来了一本字典 So, for example, if this one comes in 124 00:07:43,008 --> 00:07:44,096 并且成功匹配 and it finds a match, 125 00:07:44,512 --> 00:07:45,872 那么就会输出一本字典 out will come a dictionary 126 00:07:46,816 --> 00:07:49,792 本例中就是Y=PROG that in this case will have y equals programmer 127 00:07:51,520 --> 00:07:52,970 X=... nd x equals something. 128 00:07:56,544 --> 00:07:58,752 Y=PROG X=... y is programmer, x is something, 129 00:07:58,960 --> 00:08:00,544 D又是一个新的项 and d is whatever it found. 130 00:08:01,728 --> 00:08:02,272 像这样扩展 And that's all. 131 00:08:03,520 --> 00:08:07,824 当然 它会针对数据库中的所有事实做同样的尝试 And, of course, it's going to try this for every fact in the dictionary. 132 00:08:07,980 --> 00:08:09,250 所以就可能有很多的结果 So it might find lots of them. 133 00:08:09,568 --> 00:08:10,592 可能会产生另一本字典 It might find another one 134 00:08:11,280 --> 00:08:17,120 其中 Y=PROG X=... D=... that says y equals programmer and x equals, and d equals. 135 00:08:19,184 --> 00:08:21,550 因此 对于每个输入的框架 So thats, So for one frame coming in, 136 00:08:21,760 --> 00:08:23,696 对于每输入一本字典 it might put out-- for one dictionary coming in, 137 00:08:23,728 --> 00:08:25,240 它可能输出很多本字典 it might put out a lot of dictionaries, 138 00:08:26,544 --> 00:08:28,672 或者什么也不输出 or it might put out none. 139 00:08:30,470 --> 00:08:38,480 可能会有一些不匹配的情况 比如X=FOO It might have something that wouldn't match like x equals FOO. 140 00:08:39,024 --> 00:08:40,896 这个条目不会匹配任何东西 This one might not match anything 141 00:08:41,520 --> 00:08:45,120 就这个框架来说 不会向输出流中输出东西 in which case nothing will go into this stream corresponding to this frame. 142 00:08:47,510 --> 00:08:51,280 或者你也可以输入一个空框架 Or what you might do is put in an empty frame, 143 00:08:52,910 --> 00:08:56,240 空框架是用来 and an empty frame says try matching all ways-- 144 00:08:59,872 --> 00:09:02,336 在没有任何约束的情况下 find all possible ways of matching the query 145 00:09:02,576 --> 00:09:06,144 匹配数据库中所有可能的结果 against something in the database subject to no previous restrictions. 146 00:09:07,570 --> 00:09:09,168 这仅仅代表着 And if you think about what that means, that's just 147 00:09:10,320 --> 00:09:13,872 处理你输入的查询 最初所进行的计算 the computation that's done when you type in a query right off. 148 00:09:14,208 --> 00:09:15,568 它试图找出所有的匹配 It tries to find all matches. 149 00:09:16,650 --> 00:09:18,832 基本查询建立了这种机制 So a primitive query sets up this mechanism. 150 00:09:19,370 --> 00:09:20,576 而语言要做的是 And what the language does, 151 00:09:22,752 --> 00:09:24,672 当你在顶层输入这条查询时 when you type in the query at the top level, 152 00:09:24,848 --> 00:09:26,144 它基于这种机制 it takes this mechanism, 153 00:09:26,160 --> 00:09:28,352 它会输入一本空的字典 feeds in one single empty dictionary, 154 00:09:30,864 --> 00:09:32,560 而对于输出的每个东西 and then for each thing that comes out 155 00:09:33,088 --> 00:09:35,888 然后把最初的查询 takes the original query 156 00:09:36,560 --> 00:09:40,448 用不同的字典来实例化 and instantiates the result with all the different dictionaries, 157 00:09:40,816 --> 00:09:44,368 于是实例化后的模式就形成了一条新的流 producing a new stream of instantiated patterns here. 158 00:09:44,990 --> 00:09:46,512 这就是在终端上打印出来的内容 And that's what gets printed on the terminal. 159 00:09:48,170 --> 00:09:51,248 这也就是其中的基本原理 That's the basic mechanism going on there. 160 00:09:53,510 --> 00:09:55,488 那么 这又为什么复杂呢? Well, why is that so complicated? 161 00:09:57,712 --> 00:10:01,008 除了使用这种基于流的方法 You probably can think of a lot simpler ways to arrange this match for 162 00:10:01,376 --> 00:10:04,256 你们可以想出很多更简单的方法来组织基本查询 a primitive query rather than having all of these streams floating around. 163 00:10:05,184 --> 00:10:06,096 而答案就在于 And the answer is-- 164 00:10:07,152 --> 00:10:08,512 你们可能已经在想了 you probably guess already. 165 00:10:10,860 --> 00:10:14,096 答案就是 这种方法能够优雅地 The answer is this thing extends elegantly 166 00:10:14,560 --> 00:10:16,768 实现组合手段 to implement the means of combination. 167 00:10:17,790 --> 00:10:18,800 比如说 So, for instance, 168 00:10:20,656 --> 00:10:22,470 假设我还想实现其它的效果 suppose I don't only want to do this. 169 00:10:22,470 --> 00:10:26,960 我不只是想查询所有人的工作信息 I don't want to say who to be everybody's job description. 170 00:10:27,230 --> 00:10:28,352 假设我还想查询 Suppose I want to say 171 00:10:29,472 --> 00:10:35,920 (AND (JOB ?X (?D . ?Y)) to say AND the job of x is d dot y 172 00:10:36,800 --> 00:10:47,040 (SUPERVIOSR ?X ?Z)) and the supervisor of x is z. 173 00:10:48,800 --> 00:10:50,672 (SUPERVISOR ?X ?Z)这条查询 Now, supervisor of x is z 174 00:10:51,392 --> 00:10:52,960 是另外的一条基本查询 is going to be another primitive query 175 00:10:53,712 --> 00:10:58,432 它也有类似的形状——接收一条数据对象流 that has the same shape to take in a stream of data objects, 176 00:10:59,184 --> 00:11:01,648 一条初始字典流 a stream of initial dictionaries, 177 00:11:01,680 --> 00:11:05,520 字典是你在进行匹配时 需要遵循的约束 which are the restrictions to try and use when you match, 178 00:11:05,536 --> 00:11:07,440 然后它会输出一条字典流 and it's going to put out a stream of dictionaries. 179 00:11:08,700 --> 00:11:10,800 这就是这条基本查询的形状 So that's what this primitive query looks like. 180 00:11:11,504 --> 00:11:12,910 我又该如何实现AND呢? And how do I implement the AND? 181 00:11:12,910 --> 00:11:13,450 其实很简单 Well, it's simple. 182 00:11:13,450 --> 00:11:14,448 把它们连接起来就好了 I just hook them together. 183 00:11:14,880 --> 00:11:16,288 我把这条查询的输出 I take the output of this one, 184 00:11:16,960 --> 00:11:18,816 连接在这条查询的输入上 and I put that to the input of that one. 185 00:11:19,830 --> 00:11:21,840 然后把这里的字典扇出开来 And I take the dictionary here and I fan it out. 186 00:11:26,570 --> 00:11:27,968 你们就能发现它是如何工作的了 And then you see how that's going to work, 187 00:11:29,050 --> 00:11:32,448 这里会输出一个框架 because what's going to happen is a frame will now come in here, 188 00:11:32,512 --> 00:11:36,848 其中有X、Y和D的绑定 which has a binding for x, y, and d. 189 00:11:37,920 --> 00:11:39,280 当后面的查询接收到结果后 And then when this one gets it, it'll say, 190 00:11:39,296 --> 00:11:41,600 当它了解了这些约束后 oh, gee, subject to these restrictions, 191 00:11:42,176 --> 00:11:49,248 字典中的是Y、X和D的值 which now already have values in the dictionary for y and x and d, 192 00:11:51,808 --> 00:11:53,088 它会搜寻数据库 it looks in the database and says, 193 00:11:53,120 --> 00:11:54,928 试图找到有关SUPERVISOR关系的事实 gee, can I find any supervisor facts? 194 00:11:56,048 --> 00:11:58,510 如果找到了的话 它就会输出一些词典 And if it finds any, out will come dictionaries 195 00:11:59,584 --> 00:12:09,340 其中有Y、X、D以及Z的绑定 which have bindings for y and x and d and z now. 196 00:12:12,070 --> 00:12:14,096 不过要注意 And then notice that the match--- 197 00:12:14,192 --> 00:12:17,248 因为这里输入的框架建立了约束 because the frames coming in here have these restrictions, 198 00:12:17,610 --> 00:12:20,288 它保证了当你执行AND运算时 that's the thing that assures when you do the AND, 199 00:12:20,496 --> 00:12:24,624 这两个X是相同的 this x will mean the same thing as that x. 200 00:12:26,470 --> 00:12:28,960 这是因为通过这条流输出时 Because by the time something comes floating in here, 201 00:12:29,968 --> 00:12:32,656 X已经有值了 你要确保匹配的一致性 x has a value that you have to match against consistently. 202 00:12:34,460 --> 00:12:36,176 然后我们想起在MATCH的代码中 And then you remember from the code from the matcher, 203 00:12:36,190 --> 00:12:38,176 有一种操作字典的特殊组织方法 there was something in the way the matcher did dictionaries 204 00:12:38,208 --> 00:12:39,820 确保了匹配的一致性 that arrange consistent matches. 205 00:12:40,928 --> 00:12:41,776 这就是AND的实现 So there's AND. 206 00:12:44,080 --> 00:12:46,944 关键是要注意它的一般性形状 The important point to notice is the general shape. 207 00:12:48,496 --> 00:12:51,550 我们来看看(AND P Q) Look at what happened: the AND of two queries, say, P and Q. 208 00:12:52,880 --> 00:12:55,616 这里是P和Q Here's P and Q. 209 00:12:57,296 --> 00:12:58,608 两条查询的AND The AND of two queries, 210 00:13:00,272 --> 00:13:01,190 看起来像是这样 well, it looks like this. 211 00:13:01,190 --> 00:13:04,448 每一条查询都通过一条流连接数据库 Each query takes in a stream from the database, 212 00:13:04,544 --> 00:13:05,712 一条输入流 a stream of inputs, 213 00:13:06,336 --> 00:13:08,176 并输出一条输出流 and puts out a stream of outputs. 214 00:13:10,230 --> 00:13:11,728 关键是要注意 And the important point to notice 215 00:13:12,208 --> 00:13:15,024 如果我在它们周围画一个盒子 is that if I draw a box around this thing 216 00:13:19,264 --> 00:13:23,648 这就是(AND P Q) and say this is AND of P and Q, 217 00:13:25,664 --> 00:13:30,384 那么这个盒子也有同样的形状 then that box has exactly the same overall shape. 218 00:13:32,048 --> 00:13:34,200 它也有一条连接数据库的流 It's something that takes in a stream from the database. 219 00:13:34,200 --> 00:13:35,744 但是在内部会扇出开来 Here it's going to get fanned out inside, 220 00:13:36,608 --> 00:13:37,936 但是在外部你看不到 but from the outside you don't see that. 221 00:13:38,160 --> 00:13:40,640 它接收一个流 并输出一个流 It takes an input stream and puts out an output stream. 222 00:13:42,064 --> 00:13:43,168 这就是AND So this is AND. 223 00:13:43,570 --> 00:13:45,728 类似地 OR可能看起像这样 And then similarly, OR would look like this. 224 00:13:46,020 --> 00:13:49,584 虽然我没给你们演示过OR的用法 OR would-- although I didn't show you examples of OR. 225 00:13:49,840 --> 00:13:54,704 OR会尝试找出P或Q所有匹配的事实 OR would say can I find all ways of matching P or Q. 226 00:13:55,808 --> 00:13:58,070 P、Q两条查询都有各自的形状 So I have P and Q. Each will have their shape. 227 00:14:04,460 --> 00:14:06,688 OR的实现则是 And the way OR is implemented is 228 00:14:08,544 --> 00:14:10,912 我把来自于数据库的流 I'll take my database stream. 229 00:14:12,500 --> 00:14:13,490 扇出开来 I'll fan it out. 230 00:14:13,490 --> 00:14:16,048 把它们分别送给P和Q I'll put one into P and one into Q. 231 00:14:17,440 --> 00:14:21,980 我把最初的查询流也给扇出开来 I'll take my initial query stream coming in and fan it out. 232 00:14:26,750 --> 00:14:29,168 这样我不但能够得到P的所有结果 So I'll look at all the answers I might get from P 233 00:14:29,296 --> 00:14:31,088 也能得到Q的所有结果 and all the answers I might get from Q, 234 00:14:31,616 --> 00:14:34,560 把这些输出送入某种“附加器”中 and I'll put them through some sort of thing that appends them 235 00:14:34,624 --> 00:14:37,488 或者把它们“合并”到一条流中 or merges the result into one stream, 236 00:14:39,648 --> 00:14:40,880 然后得到输出 and that's what will come out. 237 00:14:41,080 --> 00:14:48,240 而从外部来看 这整个东西就是OR And this whole thing from the outside is OR. 238 00:14:52,350 --> 00:14:54,896 同样的 当你们从外部观察它时 And again, you see it has the same overall shape 239 00:14:55,072 --> 00:14:56,544 你会发现它具有相同的形状 And again, you see it has the same overall shape 240 00:15:01,000 --> 00:15:01,616 NOT又如何实现呢? What's NOT? 241 00:15:02,020 --> 00:15:03,456 NOT的原理有些类似 NOT works kind of the same way. 242 00:15:04,310 --> 00:15:05,952 如果我有一条查询P If I have some query P, 243 00:15:06,864 --> 00:15:13,504 这是一条基本查询P If I have P, I take the primitive query for P. 244 00:15:14,690 --> 00:15:16,320 现在我要实现(NOT P) Here, I'm going to implement NOT P. 245 00:15:18,688 --> 00:15:20,544 NOT的作用像是一个过滤器 And NOT's just going to act as a filter. 246 00:15:20,720 --> 00:15:21,952 这里连接数据库 I'll take in the database 247 00:15:23,840 --> 00:15:28,288 这里是输入的字典流 and my original stream of dictionaries coming in, 248 00:15:28,780 --> 00:15:31,536 (NOT P)要做的就是 and what NOT P will do is 249 00:15:31,888 --> 00:15:37,400 对这些东西做过滤 it will filter these guys. 250 00:15:39,020 --> 00:15:40,096 过滤的方法则是 And the way it will filter it, 251 00:15:40,192 --> 00:15:42,704 如果我在这里获得了一本字典 it will say when I get in a dictionary here, 252 00:15:43,424 --> 00:15:44,656 那么我就去找所有的匹配 I'll find all the matches, 253 00:15:44,832 --> 00:15:46,480 然后丢弃找到的结果 and if I find any, I'll throw it away. 254 00:15:47,460 --> 00:15:49,936 如果我没有在这里找到匹配 And if I don't find any matches to something coming in here, 255 00:15:50,128 --> 00:15:51,376 我就把它传递过去 I'll just pass that through, 256 00:15:52,400 --> 00:15:53,552 NOT就是一个纯粹的过滤器 so NOT is a pure filter. 257 00:15:55,344 --> 00:15:59,980 因此AND就类似于一个电阻 So AND is-- think of these sort of electoral resistors or something. 258 00:15:59,980 --> 00:16:01,856 AND是串行的组合 AND is series combination 259 00:16:02,496 --> 00:16:04,140 OR是并行组合 and OR is parallel combination. 260 00:16:04,960 --> 00:16:07,460 然而NOT并不会对字典做任何扩展 And then NOT is not going to extend any dictionaries at all. 261 00:16:07,460 --> 00:16:08,400 它只会做过滤 It's just going to filter it. 262 00:16:08,750 --> 00:16:11,792 它会丢弃那些能够匹配的结果 It's going to throw away the ones for which it finds a way to match. 263 00:16:12,640 --> 00:16:14,192 LISP-VALUE的原理类似 And lisp-value is sort of the same way. 264 00:16:14,848 --> 00:16:16,600 它的过滤器会复杂点 The filter's a little more complicated. 265 00:16:16,600 --> 00:16:17,376 因为要应用到谓词上 It applies to predicate. 266 00:16:19,936 --> 00:16:21,648 这里需要注意的关键点是 The major point to notice here, 267 00:16:21,920 --> 00:16:23,552 我们之前也强调过了 and it's a major point we've looked at before, 268 00:16:23,648 --> 00:16:25,296 就是关于“闭包性质”的思想 is this idea of closure. 269 00:16:28,220 --> 00:16:31,808 我们通过组合手段构建的东西 The things that we build as a means of combination 270 00:16:31,952 --> 00:16:34,512 跟所使用的基本物件 have the same overall structure 271 00:16:35,696 --> 00:16:37,584 有同样的结构 as the primitive things that we're combining. 272 00:16:39,750 --> 00:16:41,680 所以从外面看 So the AND of two things 273 00:16:41,712 --> 00:16:43,720 查询的AND与基本查询结构相同 looked at from the outside has the same shape. 274 00:16:44,630 --> 00:16:46,144 这就意味着 And what that means is that 275 00:16:46,940 --> 00:16:50,288 这里的盒子可以是AND、OR、NOT或者其它的 this box here could be an AND or an OR or a NOT or something 276 00:16:50,304 --> 00:16:54,220 因为它具有相同的形状来连接更大的东西 because it has the same shape to interface to the larger things. 277 00:16:54,950 --> 00:16:56,688 这种思想能够让我们获得 It's the same thing that allowed us to get 278 00:16:56,928 --> 00:16:58,960 Escher绘图语言中的那种复杂度 complexity in the Escher picture language 279 00:16:59,550 --> 00:17:01,312 让你能够仅仅使用序对 or allows you to immediately build up these 280 00:17:01,344 --> 00:17:03,260 构建出这些复杂结构 complicated structures just out of pairs. 281 00:17:03,936 --> 00:17:04,784 这就是“闭包性质” It's closure. 282 00:17:06,280 --> 00:17:08,064 这种性质 And that's the thing that 283 00:17:09,648 --> 00:17:11,728 能够让我完成你们现在觉得理所当然的事儿 allowed me to do what by now you took for granted 284 00:17:11,760 --> 00:17:14,912 比如我可以查询(AND JOB SALARY) I said, gee, there's a query which is AND of job and salary, 285 00:17:14,912 --> 00:17:18,800 当然我也可以查询(AND JOB (NOT ...))等等 and I said, oh, there's another one, which is AND of job, a NOT of something. 286 00:17:19,260 --> 00:17:20,928 这种便利是由 The fact that I can do that is 287 00:17:20,944 --> 00:17:22,910 这种“闭包原则”直接带给我们的 a direct consequence of this closure principle. 288 00:17:25,184 --> 00:17:27,080 好吧 提问时间 OK, let's break and then we'll go on. 289 00:17:29,328 --> 00:17:30,896 学生:字典是从哪里来的? AUDIENCE: Where does the dictionary come from? 290 00:17:30,990 --> 00:17:36,032 教授:字典最初来自于你的输入 PROFESSOR: The dictionary comes initially from what you type in. 291 00:17:36,096 --> 00:17:37,328 因此当你最初进行查询时 So when you start this up, 292 00:17:39,168 --> 00:17:41,090 它首先会建立起这整个结构 the first thing it does is set up this whole structure. 293 00:17:41,090 --> 00:17:42,640 它先输入一个空字典 It puts in one empty dictionary. 294 00:17:45,000 --> 00:17:47,248 如果你只有一条基本查询的话 And if all you have is one primitive query, 295 00:17:48,240 --> 00:17:51,104 那么它就会输出一系列具有内容的字典 then what will come out is a bunch of dictionaries with things filled in. 296 00:17:52,310 --> 00:17:54,336 这里演示的一般性情况是 The general situation that I have here 297 00:17:54,512 --> 00:17:59,710 某个嵌套组合查询的中间过程 is when this is in the middle of some nest of combined things. 298 00:18:01,552 --> 00:18:02,304 所以在那时 So by the time. 299 00:18:02,380 --> 00:18:03,790 让我们来看看这里 Let's look at the picture over here. 300 00:18:04,384 --> 00:18:06,730 这条SUPERVISOR查询得到了某本字典 This supervisor query gets in some dictionary. 301 00:18:06,730 --> 00:18:08,032 这本字典来自于哪里呢? Where did this one come from? 302 00:18:08,730 --> 00:18:11,152 它来自于 This dictionary came from the fact that 303 00:18:12,848 --> 00:18:14,896 这条基本查询的输出 I'm looking at the output of this primitive query. 304 00:18:16,260 --> 00:18:17,888 说得更具体一点 So maybe to be very specific, 305 00:18:18,352 --> 00:18:21,728 如果我最初在顶层只输入了这条查询 if I literally typed in just this query at the top level, 306 00:18:22,272 --> 00:18:22,928 这整条AND查询 this AND, 307 00:18:23,072 --> 00:18:25,280 它实际上会构建这种结构 what would actually happen is it would build this structure 308 00:18:25,500 --> 00:18:30,240 并使用一本空字典来启动整个过程 and start up this whole thing with one empty dictionary. 309 00:18:31,770 --> 00:18:34,336 处理过程开始后 会产生一系列的字典 And now this one would process, and a whole bunch of dictionaries 310 00:18:34,368 --> 00:18:37,360 其中就有X、Y以及D would come out with x, y's and d's in them. 311 00:18:38,640 --> 00:18:39,584 向这边传递 Run it through this one. 312 00:18:40,190 --> 00:18:42,160 这就是这条查询的输入 So now that's the input to this one. 313 00:18:42,160 --> 00:18:43,728 这条查询也会生成其它的东西 This one would now put out some other stuff. 314 00:18:45,040 --> 00:18:48,224 如果这整个查询是构建在一个更大的查询中的话 And if this itself were buried in some larger thing, 315 00:18:49,312 --> 00:18:51,008 比如说一条OR查询 like an OR of something, 316 00:18:53,424 --> 00:18:55,712 那么它将输出到下一个查询中 then that would go feed into the next one. 317 00:18:58,560 --> 00:19:01,280 因此最初开始处理时 只有一本空字典 So you initially get only one empty dictionary when you start it, 318 00:19:01,680 --> 00:19:04,080 但是在处理这些复合查询的过程中 but as you're in the middle of processing these compounds things, 319 00:19:04,112 --> 00:19:06,656 会生成各种不同的字典 that's where these cascades of dictionaries start getting generated. 320 00:19:07,660 --> 00:19:12,280 学生:字典都是查询的结果吗? AUDIENCE: Dictionaries only come about as a result of using the queries? 321 00:19:15,120 --> 00:19:17,696 它们会变成 Or do they stays, do they become-- 322 00:19:18,848 --> 00:19:22,816 它们存储在数据库中吗? do they stay someplace in space like the database does? 323 00:19:23,680 --> 00:19:24,980 它们是临时数据吗? Are these temporary items? 324 00:19:24,980 --> 00:19:27,184 教授:它们是在MATCH过程中临时创建的 PROFESSOR: They're created temporarily in the matcher. 325 00:19:28,030 --> 00:19:29,880 但它们实际存放在内存中 Really, they're someplace in storage. 326 00:19:29,880 --> 00:19:33,024 最初 某人创建了一本THE-EMPTY-DICT字典 Initially, someone creates a thing called the empty dictionary 327 00:19:34,224 --> 00:19:36,800 送入这个匹配过程 that gets initially fed to this match procedure, 328 00:19:36,810 --> 00:19:39,056 MATCH过程据此构建新字典 and then the match procedure builds some dictionaries, 329 00:19:39,070 --> 00:19:40,272 并把它们传递下去 and they get passed on and on. 330 00:19:40,768 --> 00:19:42,480 学生:因此匹配完成后它们就被丢弃了? AUDIENCE: OK, so they'll go way after the match? 331 00:19:43,640 --> 00:19:46,256 教授:实际上 当没人需要它们后(就被废料回收了) PROFESSOR: They'll go away when no one needs them again, yeah. 332 00:19:51,900 --> 00:19:53,600 学生:似乎AND查询对数据库 AUDIENCE: It appears that the AND performs 333 00:19:53,632 --> 00:19:55,370 进行了一些冗余操作 some redundant searches of the database. 334 00:19:55,960 --> 00:19:57,488 如果第一条子句扫描过了 If the first clause matched, 335 00:19:57,504 --> 00:19:59,900 比如说前两个元素没有匹配 而第三个元素匹配了 let's say, the third element and not on the first two elements, 336 00:20:00,256 --> 00:20:03,648 然而第二条子句又会检查这两个元素 the second clause is going to look at those first two elements again, 337 00:20:04,320 --> 00:20:06,592 然后又一次丢弃这些不匹配的元素 discarding them because they don't match. 338 00:20:06,640 --> 00:20:08,720 而字典中已经有匹配的项了 The match is already in the dictionary. 339 00:20:10,000 --> 00:20:12,560 如果我们把数据库中的数据 Would it makes sense to carry the data element 340 00:20:12,576 --> 00:20:14,432 跟字典同时传递 这样可行么? from the database along with the dictionary? 341 00:20:15,690 --> 00:20:17,600 教授:实际上 通常来说 PROFESSOR: Yeah, there're... Well, in general, 342 00:20:17,632 --> 00:20:19,480 我们能够以其它方式来安排这些搜索 there are other ways to arrange this search, 343 00:20:20,128 --> 00:20:21,740 你也可以做一些分析 and there's some analysis that you can do. 344 00:20:21,740 --> 00:20:23,168 我记得书里面就有这样的习题 I think there's a problem in the book, 345 00:20:23,872 --> 00:20:26,656 是考察通过安排AND子句的顺序 which talks about a different way that you can cascade AND 346 00:20:27,008 --> 00:20:29,200 来消除不同类型的冗余 to eliminate various kinds of redundancies. 347 00:20:29,850 --> 00:20:30,720 而这里只是为了 This one is meant to be-- 348 00:20:31,328 --> 00:20:34,544 用非常简单的情况来向你们展示它们是如何配合的 was mainly meant to be very simple so you can see how they fit together. 349 00:20:34,704 --> 00:20:35,380 但是你说得非常对 But you're quite right. 350 00:20:35,380 --> 00:20:37,328 这些冗余是可以避免的 There are redundancies here that you can get rid of. 351 00:20:38,370 --> 00:20:40,800 这也是这门语言缓慢的原因之一 That's another reason why this language is somewhat slow. 352 00:20:41,190 --> 00:20:42,704 你们可以让它变得更聪明 There are a lot smarter things you can do. 353 00:20:42,930 --> 00:20:46,224 我只是为了向你们演示非常简单的、原理性的实现 We're just trying to show you a very simple, in principle, implementation. 354 00:20:51,220 --> 00:20:53,232 学生:您是根据Prolog来建模这门语言的 AUDIENCE: Did you model this language on Prolog, 355 00:20:53,248 --> 00:20:55,136 还是说它只是偶然地像Prolog? or did it just come out looking like Prolog? 356 00:21:04,960 --> 00:21:07,088 教授:Gerry教授昨天羞辱了一大堆人 PROFESSOR: Well, Gerry insulted a whole bunch of people yesterday, 357 00:21:07,248 --> 00:21:09,920 我想说真实的情况是 so I might as well say that the MIT attitude towards Prolog is 358 00:21:10,190 --> 00:21:12,608 MIT的研究人员在1971年做了类似的事 is something that people did in about 1971 359 00:21:12,640 --> 00:21:15,600 但是发现这个方向并不正确 并停止了研究 and decided that it wasn't really the right thing and stopped. 360 00:21:16,120 --> 00:21:22,800 因此我们是根据查询处理的基本原理建模的 So we modeled this on the sort of natural way that this thing was done 361 00:21:22,848 --> 00:21:24,730 大概在1971年左右 in about 1971, 362 00:21:25,136 --> 00:21:27,248 只是说 那时候我们还没有用流来实现 except at that point, we didn't do it with streams. 363 00:21:28,272 --> 00:21:33,040 然后我们 -- 但我们使用了它差不多六个月后 And then we... After we were using it for about six months, 364 00:21:33,080 --> 00:21:34,912 发现它存在各种各样的问题 we discovered that it had all these problems, 365 00:21:34,944 --> 00:21:36,300 稍后我会解释 some of which I'll talk about later. 366 00:21:37,330 --> 00:21:38,192 然后我们就想 And we said, 367 00:21:38,448 --> 00:21:39,920 Prolog一定解决了这些问题 gee, Prolog must have fixed those, 368 00:21:39,930 --> 00:21:41,216 但却发现它并没有 and then we found out that it didn't. 369 00:21:41,250 --> 00:21:43,024 从这种意义上来说 它确实跟Prolog一样 So this does about the same thing as Prolog. 370 00:21:43,600 --> 00:21:44,950 学生:Prolog基于流么? AUDIENCE: Does Prolog use streams? 371 00:21:44,950 --> 00:21:46,200 教授:不 Prolog基于的是 PROFESSOR: No. Prolog -- 372 00:21:46,784 --> 00:21:51,040 就行为上来说 我们的语言很像Prolog In how it behaves, it behaves a lot like Prolog. 373 00:21:51,040 --> 00:21:52,960 Prolog使用回溯策略 Prolog uses a backtracking strategy. 374 00:21:53,800 --> 00:21:55,712 但是Prolog有一个优点非常好 But the other thing that's really good about Prolog 375 00:21:55,728 --> 00:21:57,984 也使得它变得实用 that makes it a usable thing 376 00:21:58,280 --> 00:22:01,504 你知道吗 is that there's a really very, very 377 00:22:01,680 --> 00:22:04,090 它们精心设计了Prolog的编译器 there's a really very, very well-engineered compiler technology 378 00:22:04,112 --> 00:22:05,328 使得它能够高速运行 that makes it run fast. 379 00:22:06,656 --> 00:22:10,816 因此 虽然我们这门语言非常缓慢地输出答案 So although you saw the merge spitting out these answers very, very slowly, 380 00:22:11,664 --> 00:22:13,616 真正的Prolog程序却运行得非常快 a real Prolog will run very, very fast. 381 00:22:14,704 --> 00:22:16,480 这是因为 尽管搜索过程十分低效 Because even though it's sort of doing this, 382 00:22:16,670 --> 00:22:20,816 Prolog卓越的编译器也会高效地完成工作 the real work that went into Prolog is a very, very excellent compiler effort. 383 00:22:24,304 --> 00:22:25,216 休息一下吧 Let's take a break. 384 00:22:25,420 --> 00:22:36,176 [音乐] [JESU, JOY OF MAN'S DESIRING] 385 00:22:36,352 --> 00:22:39,872 《计算机程序的构造和解释》 386 00:23:01,488 --> 00:23:05,120 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 387 00:23:05,180 --> 00:23:09,056 《计算机程序的构造和解释》 388 00:23:09,120 --> 00:23:13,664 逻辑式程序设计 II 389 00:23:16,650 --> 00:23:18,832 我们已经考察过了基本查询 We've looked at the primitive queries 390 00:23:19,216 --> 00:23:23,520 以及如何使用流来实现组合手段 and the ways that streams are used to implement the means of combination: 391 00:23:23,792 --> 00:23:25,728 AND、OR以及NOT AND and OR and NOT. 392 00:23:26,950 --> 00:23:28,432 现在 该讨论抽象手段了 Now, let go on to the means of abstraction. 393 00:23:29,580 --> 00:23:32,800 回想一下 我们这门语言的抽象手段是RULE Remember, the means of abstraction in this language are rules. 394 00:23:35,150 --> 00:23:37,792 (BOSS ?Z ?D)描述的是 So z is a boss in division d 395 00:23:39,184 --> 00:23:43,776 如果某人在D部门工作 if there's some x who has a job in division d 396 00:23:45,680 --> 00:23:47,472 并且Z是X的上司 and z is the supervisor of x. 397 00:23:48,900 --> 00:23:50,608 这就是所谓的“BOSS” That's what it means for someone to be a boss. 398 00:23:52,260 --> 00:23:53,152 并且 实际上 So, and in effect, 399 00:23:53,344 --> 00:23:55,616 如果我们考察一下编写的规则与这边的关系 if you think about what we're doing with relation to this, 400 00:23:56,800 --> 00:23:57,904 这是我们编写的查询 there's the query we wrote-- 401 00:23:57,936 --> 00:24:01,900 这个是(JOB ?X ?D) 而这个是(SUPERVISOR ?X ?Z) the job of x is in d and the supervisor of x is z-- 402 00:24:02,192 --> 00:24:04,288 我们实际想要把这一大堆东西 what we in effect want to do is take this whole mess 403 00:24:05,072 --> 00:24:06,576 用一个盒子封装起来 and draw a box around it 404 00:24:19,080 --> 00:24:24,544 然后把这个盒子里的所有东西 and say this whole thing inside the box 405 00:24:25,152 --> 00:24:32,480 认为是(BOSS ?Z ?D) is boss of z in division d. 406 00:24:33,900 --> 00:24:35,250 这是我们想要达到的效果 That's in effect what we want to do. 407 00:24:38,720 --> 00:24:39,728 因此 比如说 So, for instance, 408 00:24:43,184 --> 00:24:44,080 我们这样做了过后 if we've done that, 409 00:24:45,008 --> 00:24:47,840 我们想要检查 and we want to check whether or not it's true 410 00:24:47,952 --> 00:24:50,512 Ben Bitdiddle是否为计算机分部的BOSS that Ben Bitdiddle is a boss in the computer division, 411 00:24:51,104 --> 00:25:02,864 如果我想查询 (BOSS (BITDIDDLE BEN) COMPUTER) so if I want to say boss of Ben Bitdiddle in the computer division, 412 00:25:04,784 --> 00:25:07,088 想象一下把这条查询输入系统 imagine typing that in as query to the system, 413 00:25:07,120 --> 00:25:09,168 实际上发生的是 in effect what we want to do 414 00:25:10,672 --> 00:25:12,928 在这里先构建一本字典 is set up a dictionary here, 415 00:25:15,820 --> 00:25:23,632 其中 ?Z=BITDIDDLE which has z to Ben Bitdiddle 416 00:25:28,880 --> 00:25:33,310 ?D=COMPUTER and d to computer. 417 00:25:37,088 --> 00:25:38,624 这个字典又是来自于哪里呢? Where did that dictionary come from? 418 00:25:38,688 --> 00:25:40,710 我们来看下幻灯片 Let's look at the slide for one second. 419 00:25:40,710 --> 00:25:43,712 这本字典是通过把 That dictionary came from matching the query 420 00:25:44,304 --> 00:25:46,336 查询(BOSS (BITDIDDLE BEN) COMPUTER) that said boss of Ben Bitdiddle and computer 421 00:25:46,512 --> 00:25:49,632 与规则的结论(BOSS ?Z ?D)相匹配得到 onto the conclusion of the rule: boss of z and d. 422 00:25:51,650 --> 00:25:54,112 所以我们把规则的结论和查询匹配了起来 So we match the query to the conclusion of the rule. 423 00:25:54,190 --> 00:25:55,536 这样我们就获得了一本字典 That gives us a dictionary, 424 00:25:58,992 --> 00:26:02,544 现在我们就要把这本字典输入到这整个结构中 and that's the thing that we would now like to put into this whole big thing 425 00:26:02,928 --> 00:26:05,568 进行处理 并观察是否有输出 and process and see if anything comes out the other side. 426 00:26:06,670 --> 00:26:09,888 如果输出了结果 那么查询就为真 If anything comes out, it'll be true. 427 00:26:11,330 --> 00:26:12,370 这是基本的思想 That's the basic idea. 428 00:26:12,370 --> 00:26:13,248 因此 通常来说 So in general, 429 00:26:14,032 --> 00:26:15,408 我们实现规则的方法就是 the way we implement a rule 430 00:26:15,856 --> 00:26:18,896 用规则的结论去匹配 is we match the conclusion of the rule 431 00:26:20,864 --> 00:26:22,960 假设为真的查询 against something we might want to check it's true. 432 00:26:23,580 --> 00:26:25,120 这个过程会产生一本字典 That match gives us a dictionary, 433 00:26:25,296 --> 00:26:28,224 在有了相关字典后 and with respect to that dictionary, 434 00:26:30,352 --> 00:26:34,512 我们来处理规则的体 we process the body of the rule. 435 00:26:36,336 --> 00:26:37,680 基本上就是这样了 Well, that's really all there is, 436 00:26:38,640 --> 00:26:41,440 但还有两个技术点 except for two technical points. 437 00:26:43,040 --> 00:26:44,320 首先就是 The first technical point is that 438 00:26:45,744 --> 00:26:47,264 我也可能有其它的问法 I might have said something else. 439 00:26:47,510 --> 00:26:48,416 比如说 I might have said 440 00:26:50,544 --> 00:26:52,368 查询计算机分部的BOSS who's the boss in the computer division? 441 00:26:52,544 --> 00:26:56,320 就可以查询 (BOSS ?WHO COMPUTER) So I might say boss of who in computer division. 442 00:27:00,784 --> 00:27:01,632 这样做了以后 And if I did that, 443 00:27:02,576 --> 00:27:04,624 我真正想要做的 what I would really like to do in effect is not 444 00:27:05,040 --> 00:27:06,496 就是先建立一本字典 is start up this dictionary 445 00:27:08,352 --> 00:27:09,888 其中有一些约束 with a match that sort of says, 446 00:27:09,936 --> 00:27:11,200 比如 ?D=COMPUTER well, d is computer 447 00:27:14,352 --> 00:27:18,480 而?Z等同于?WHO and z is whatever who is. 448 00:27:21,700 --> 00:27:23,220 我们的匹配器不会那么做 And our matcher won't quite do that. 449 00:27:23,220 --> 00:27:27,008 这不是模式和数据的匹配方式 That's not quite matching a pattern against data. 450 00:27:28,580 --> 00:27:29,728 这是在匹配两个模式 It's matching two patterns 451 00:27:29,744 --> 00:27:31,584 并判断它们是否一致 sort of saying are they consistent or not 452 00:27:31,904 --> 00:27:33,480 又是什么使它们不一致 or what ways make them consistent. 453 00:27:33,480 --> 00:27:36,432 换句话说 我们需要的不是一个模式匹配器 In other words, what we need is not quite a pattern matcher, 454 00:27:36,960 --> 00:27:38,912 而是一种更一般性的东西 but something a little bit more general 455 00:27:39,136 --> 00:27:40,112 就是“合一”算法 called a unifier. 456 00:27:44,420 --> 00:27:48,064 “合一”是更为一般化的模式匹配算法 And a unifier is a slight generalization of a pattern matcher. 457 00:27:49,530 --> 00:27:52,176 合一算法接收两条模式 What a unifier does is take two patterns 458 00:27:53,232 --> 00:27:57,536 它考虑的是:可以找到哪些一般性的元素 and say what's the most general thing you can substitute 459 00:27:58,208 --> 00:28:00,016 用来代换模式中的变量 for the variables in those two patterns 460 00:28:02,688 --> 00:28:05,088 使得它俩能够同时满足 to make them satisfy the pattern simultaneously? 461 00:28:05,680 --> 00:28:06,608 让我来举个例子 Let me give you an example. 462 00:28:08,864 --> 00:28:14,490 我有一个含有两个元素的模式:(?X ?X) If I have the pattern two-element list, which is x and x, 463 00:28:15,760 --> 00:28:17,152 它描述的是一个二元表 so this is I have a two-element list 464 00:28:17,320 --> 00:28:18,640 不管元素具体是什么 where both elements are the same 465 00:28:18,672 --> 00:28:20,040 但两个元素是相同的 and otherwise I don't care what they are, 466 00:28:20,400 --> 00:28:22,832 我把它与另一个模式进行“合一” and I unify that against the pattern 467 00:28:22,920 --> 00:28:24,624 后者描述的是一个二元表 that says there's a two-element list, 468 00:28:24,656 --> 00:28:27,616 首元素一张由A、?Y、C构成的表 and the first one is a and something and c 469 00:28:28,000 --> 00:28:30,144 而第二个元素是由A、B、?Z构成的表 and the second one is a and b and z, 470 00:28:33,070 --> 00:28:34,880 那么 合一算法能够告诉我 then what the unifier should tell me is, 471 00:28:34,896 --> 00:28:36,176 在生成的字典中 oh yeah, in that dictionary, 472 00:28:36,352 --> 00:28:37,968 ?X必须是(A B C) x has to be a, b, c, 473 00:28:39,344 --> 00:28:41,920 ?Y必须为B ?Z必须为C and y has to be d and z has to be c. 474 00:28:43,440 --> 00:28:46,288 这些是我必须对X、Y以及Z施加的约束 Those are the restrictions I'd have to put on the values of x, y, and z 475 00:28:46,336 --> 00:28:47,580 以便让两个模式合一 to make these two unify, 476 00:28:48,120 --> 00:28:50,848 或者换句话来说 让它匹配这个?X or in other words, to make this match x 477 00:28:51,152 --> 00:28:53,370 让它匹配这个?X and make this match x. 478 00:28:55,280 --> 00:28:57,760 合一算法需要能够推断出这些 The unifier should be able to deduce that. 479 00:28:58,540 --> 00:29:01,080 但是合一算法也会遇到复杂的情况 But the unifier may-- there are more complicated things. 480 00:29:01,080 --> 00:29:03,072 我可能会询问一些复杂的查询 I might have said something a little bit more complicated. 481 00:29:03,488 --> 00:29:05,744 比如这是一个二元表 I might have said there's a list with two elements, 482 00:29:07,008 --> 00:29:08,288 其中的元素都是相同的 and they're both the same, 483 00:29:08,864 --> 00:29:11,152 它要与这个模式进行合一 and they should unify against something of this form. 484 00:29:12,650 --> 00:29:15,360 合一算法也要能够从中推断出 And the unifier should be able to deduce from that. 485 00:29:16,890 --> 00:29:19,570 ?Y必须为B Like that y would have to be b. y would have to be b. 486 00:29:19,570 --> 00:29:22,128 因为这两个是一样的 Because these two are the same, 487 00:29:22,224 --> 00:29:23,520 因此?Y就是B so y's got to be b. 488 00:29:24,340 --> 00:29:27,536 这里 ?V应该为A And v here would have to be a. 489 00:29:28,940 --> 00:29:30,992 只要?Z和?W取值相同 And z and w can be anything, 490 00:29:31,008 --> 00:29:32,432 它们就可以是任意值 but they have to be the same thing. 491 00:29:35,710 --> 00:29:41,760 ?X就应该是(B A ?W) 其中?W为任意值 And x would have to be b, followed by a, followed by whatever w 492 00:29:42,832 --> 00:29:44,680 或者是?Z -- 因为?Z和?W是一致的 or whatever z is, which is the same. 493 00:29:44,704 --> 00:29:49,420 发现了么 合一算法需要从这些模式中推断出信息 So you see, the unifier somehow has to deduce things to unify these patterns. 494 00:29:50,880 --> 00:29:53,520 所以你们可能认为 这其中有某种魔法般的推理 So you might think there's some kind of magic deduction going on, 495 00:29:54,272 --> 00:29:55,232 但其实并不是 but there's not. 496 00:29:55,850 --> 00:29:59,888 合一算法基本上只是对模式匹配的小小修改 A unifier is basically a very simple modification of a pattern matcher. 497 00:30:00,150 --> 00:30:01,856 如果你们翻阅教材 就会发现 And if you look in the book, you'll see something like 498 00:30:02,256 --> 00:30:06,160 在模式匹配算法中加入了三到四行代码 like three or four lines of code added to the pattern matcher you just saw 499 00:30:06,496 --> 00:30:08,176 来处理对称的情况 to handle the symmetric case. 500 00:30:08,280 --> 00:30:10,816 还记得吗 模式匹配中有一处代码判断 Remember, the pattern matcher has a place where it says 501 00:30:11,664 --> 00:30:14,288 这个变量匹配一个常量吗? is this variable matching a constant. 502 00:30:14,980 --> 00:30:16,420 如果是的话 就在字典中进行检查 And if so, it checks in the dictionary. 503 00:30:16,420 --> 00:30:18,256 在合一算法中只有另一条子句 There's only one other clause in the unifier, 504 00:30:18,496 --> 00:30:20,752 它判断两个变量是否相匹配 which says is this variable matching a variable, 505 00:30:22,000 --> 00:30:23,424 这种情况下你去查询字典 in which case you go look in the dictionary 506 00:30:23,456 --> 00:30:25,680 看它们在字典的约束下是否一致 and see if that's consistent with what's in the dictionary. 507 00:30:27,030 --> 00:30:31,136 因此 这门语言中的所有“推断” So all the, quote, deduction that's in this language, 508 00:30:31,280 --> 00:30:34,590 你会发现它蕴含在规则应用中 if you sort of look at it, sort of sits in the rule applications, 509 00:30:34,992 --> 00:30:37,888 更进一步地考察 你会发现在合一算法中 which, if you look at that, sits in the unifier, 510 00:30:38,368 --> 00:30:40,320 如果更进一步地用“显微镜”观察 which, if you look at that under a microscope, 511 00:30:40,560 --> 00:30:43,968 基本上就在模式匹配算法中 sits essentially in the pattern matcher. 512 00:30:44,944 --> 00:30:47,072 这其中并没有什么魔法 There's no magic at all going on in there. 513 00:30:47,410 --> 00:30:50,256 而你们所见到的“推断” And the, quote, deduction that you see 514 00:30:50,944 --> 00:30:52,896 只是因为其中的递归 is just the fact that there's this recursion, 515 00:30:52,928 --> 00:30:55,696 它一点一点地回绕MATCH过程 which is unwinding the matches bit by bit. 516 00:30:56,030 --> 00:30:58,032 它让这个过程看起来很聪明 So it looks like this thing is being very clever, 517 00:30:58,448 --> 00:31:00,368 但它实际上并不是那么聪明 but in fact, it's not being very clever at all. 518 00:31:02,140 --> 00:31:04,416 当然 合一算法需要聪明地识别出一些情况 There are cases where a unifier might have to be clever. 519 00:31:04,880 --> 00:31:05,872 我来举个例子吧 Let me show you one more. 520 00:31:11,070 --> 00:31:13,360 假设我想要用一个二元表进行合一 Suppose I want to unify a list of two elements, 521 00:31:13,488 --> 00:31:14,816 (?X ?X) x and x, 522 00:31:17,240 --> 00:31:22,144 另一个模式则是 (?Y (a . ?Y)) with a thing that says it's y followed by a dot y. 523 00:31:24,370 --> 00:31:26,128 现在 如果你想一想它所表达的意思 Now, if you think of what that would have to mean, 524 00:31:26,864 --> 00:31:29,712 它表示了?X应该跟?Y一致 it would have to mean that x had better be the same as y, 525 00:31:30,928 --> 00:31:31,664 同时呢 but also 526 00:31:31,824 --> 00:31:36,160 ?X又应该跟(A . ?Y)相同 x had better be the same as a list whose first element is a and whose rest is y. 527 00:31:37,330 --> 00:31:39,456 如果你仔细思考它成立的条件 And if you think about what that would have to mean, 528 00:31:42,272 --> 00:31:44,710 你会发现 ?Y必须是一个由A构成的无穷表 it would have to mean that y is the infinite list of a's. 529 00:31:47,500 --> 00:31:48,352 从某种角度来说 In some sense, 530 00:31:49,216 --> 00:31:52,400 为了完成这样的合一 in order to do that unification, 531 00:31:52,608 --> 00:31:54,848 我需要求解一个不动点方程 I have to solve the fixed-point equation 532 00:31:55,056 --> 00:32:01,840 (CONS 'A Y)=Y cons of a to y is equal to y. 533 00:32:04,570 --> 00:32:06,960 通常来说 --- 我这个例子很简单 And in general, I wrote a very simple one. 534 00:32:07,290 --> 00:32:08,672 但实际进行合一时 Really doing unification 535 00:32:08,976 --> 00:32:11,984 我们可能要求解一个任意的不动点方程 might have to solve an arbitrary fixed-point equation: 536 00:32:12,016 --> 00:32:13,424 (F Y)=Y f of y equals y. 537 00:32:15,530 --> 00:32:17,088 你基本上不能保证 And basically, you can't do that 538 00:32:17,104 --> 00:32:19,472 在有穷时间内找到解 and make the thing finite all the time. 539 00:32:20,570 --> 00:32:23,600 我们的逻辑语言又该如何处理这类情况呢? So how does the logic language handle that? 540 00:32:24,896 --> 00:32:26,480 答案就是:“不处理” The answer is it doesn't. 541 00:32:27,168 --> 00:32:28,048 它会撒手不干 It just punts. 542 00:32:28,730 --> 00:32:31,072 合一算法中有一处小检查 And there's a little check in the unifier, 543 00:32:31,312 --> 00:32:33,824 用来判断是否为困难的情况 which says, oh, is this one of the hard cases 544 00:32:34,448 --> 00:32:38,000 也就是 匹配这些东西需要求解不动点方程 which when I go to match things would involve solving a fixed-point equation? 545 00:32:38,650 --> 00:32:40,816 遇到这类情况 我就撒手不干 And in this case, I will throw up my hands. 546 00:32:42,840 --> 00:32:44,656 如果不进行这样的检查 And if that check were not in there, 547 00:32:45,008 --> 00:32:45,888 会发生什么情况? what would happen? 548 00:32:47,990 --> 00:32:49,104 大多数情况就是 In most cases is 549 00:32:49,136 --> 00:32:51,312 合一算法会陷入无穷循环 that the unifier would just go into an infinite loop. 550 00:32:53,740 --> 00:32:56,544 其它的逻辑语言有类似的工作原理 And other logic programming languages work like that. 551 00:32:56,800 --> 00:32:58,144 因此这其中没有什么魔法 So there's really no magic. 552 00:32:58,220 --> 00:32:59,936 简单的情况由匹配器完成 The easy case is done in a matcher. 553 00:33:00,100 --> 00:33:01,584 困难的情况根本不去处理 The hard case is not done at all. 554 00:33:02,960 --> 00:33:05,472 这就是这种技术的现状 And that's about the state of this technology. 555 00:33:11,888 --> 00:33:14,240 现在 我来形式化地描述一下 OK, Let me just say again formally 556 00:33:14,272 --> 00:33:16,384 规则系统的运行原理 -- 也就是合一算法 how rules work now that I talked about unifiers. 557 00:33:17,390 --> 00:33:18,752 因此 正式的定义就是 So the official definition 558 00:33:19,200 --> 00:33:20,960 应用一条规则 is that to apply a rule, 559 00:33:24,176 --> 00:33:27,136 我们需要使用一些之前的术语 we-- well, let's start using some words we've used before. 560 00:33:28,270 --> 00:33:32,016 我们把向查询的盒子中 Let's talk about sticking dictionaries into 561 00:33:32,880 --> 00:33:34,784 塞入字典称作是 these big boxes of query things 562 00:33:34,816 --> 00:33:38,544 相对一个环境或者框架 as evaluating these large queries 563 00:33:39,952 --> 00:33:43,850 对这些大型查询求值 relative to an environment or a frame. 564 00:33:43,850 --> 00:33:45,040 因此 当我们谈及“字典”的时候 So when you think of that dictionary, 565 00:33:45,072 --> 00:33:46,280 “字典”究竟是什么? what's the dictionary after all? 566 00:33:46,720 --> 00:33:48,180 它是符号的一系列语义 It's a bunch of meanings for symbols. 567 00:33:48,180 --> 00:33:50,224 我们把它叫做“框架”或者“环境” That's what we've been calling frames or environments. 568 00:33:51,800 --> 00:33:55,970 根据环境进行操作 又是什么? What does it mean to do some processing relevant to an environment? 569 00:33:55,970 --> 00:33:57,424 我们把这个叫做“求值” That's what we've been calling evaluation. 570 00:33:58,336 --> 00:34:01,560 因此我们就说 应用一条规则的方法是 So we can say the way that you apply a rule 571 00:34:01,920 --> 00:34:06,160 先通过将给定的查询与规则的结论合一 得到环境 is to evaluate the rule body relative to an environment 572 00:34:06,672 --> 00:34:11,580 再在该环境中求值相应规则的体 that's formed by unifying the rule conclusion with the given query. 573 00:34:13,230 --> 00:34:14,512 我想要让你们注意的是 And the thing I want you to notice 574 00:34:14,800 --> 00:34:17,088 这非常像是 is the complete formal similarity 575 00:34:18,160 --> 00:34:21,504 元循环求值器以及代换模型 to the net of circular evaluator or the substitution model. 576 00:34:21,630 --> 00:34:22,736 规则的应用就是 To apply a procedure, 577 00:34:22,860 --> 00:34:28,368 在一个环境中求值规则的体 we evaluate the procedure body relative to an environment 578 00:34:28,544 --> 00:34:33,136 环境是通过将实际参数与形式参数绑定起来得到的 that's formed by blinding the procedure parameters to the arguments. 579 00:34:34,560 --> 00:34:36,416 规则、规则的应用、过程的应用 There's a complete formal similarity there 580 00:34:36,440 --> 00:34:40,416 它们在形式上完全相似 between the rules, rule application, and procedure application 581 00:34:40,576 --> 00:34:42,304 尽管它们又非常不同 even though these things are very, very different. 582 00:34:43,650 --> 00:34:45,616 再一次地出现了EVAL-APPLY循环 And again, you have the EVAL APPLY loop. 583 00:34:47,290 --> 00:34:49,520 EVAL-APPLY EVAL and APPLY. 584 00:34:53,392 --> 00:34:57,390 因此通常来说 我们可能会处理一些复合表达式 So in general, I might be processing some combined expression 585 00:34:57,424 --> 00:34:59,136 它们会变成规则的应用 that will turn into a rule application, 586 00:35:00,704 --> 00:35:03,280 进一步又会产生字典、框架或者环境 which will generate some dictionaries or frames or environments-- 587 00:35:03,312 --> 00:35:04,720 不管你要怎么叫它 whatever you want to call them-- from match, 588 00:35:05,024 --> 00:35:08,432 它们随后又会作为某个大的复合对象的输入 which will then be the input to some big compound thing like this. 589 00:35:08,660 --> 00:35:11,776 这有它的一部分 并可能有其它规则的应用 This has pieces of it and may have other rule applications. 590 00:35:13,580 --> 00:35:15,680 这基本上就是相同的循环 And you have essentially the same cycle 591 00:35:15,720 --> 00:35:18,688 尽管这里没有什么东西看起来像过程 even though there's nothing here at all that looks like procedures. 592 00:35:19,680 --> 00:35:21,872 这是因为我们创建的语言 It really has to do with the fact you've built a language 593 00:35:22,080 --> 00:35:25,490 它们的组合手段和抽象手段以某种方式展开 whose means of combination and abstraction unwind in certain ways. 594 00:35:28,770 --> 00:35:29,520 通常来说 And then in general, 595 00:35:29,776 --> 00:35:31,392 最顶层所发生的是 what happens at the very top level, 596 00:35:33,792 --> 00:35:35,968 数据库中也有一些规则 you might have rules in your database also, 597 00:35:36,656 --> 00:35:38,704 数据库中的数据也可能是规则 so things in this database might be rules. 598 00:35:40,460 --> 00:35:42,064 它们用来检查对象是否为真 There are ways to check that things are true. 599 00:35:42,920 --> 00:35:44,896 所以这里可能会有规则检查 So it might come in here and have to do a rule check. 600 00:35:46,750 --> 00:35:48,160 然后就会有一些控制结构 And then there's some control structure 601 00:35:48,192 --> 00:35:50,480 用来判断你访问的是规则 which says, well, you look at some rules, and you look at some data elements, 602 00:35:50,512 --> 00:35:51,808 还是数据元素 and you look at some rules and data elements, 603 00:35:51,840 --> 00:35:53,120 然后不断地把它们扇出来开 and these fan out and out and out. 604 00:35:53,350 --> 00:35:55,488 所以基本上不可能说清楚 So it becomes essentially impossible 605 00:35:55,680 --> 00:35:57,696 是用什么样的顺序来查询这些东西的 to say what order it's looking at these things in, 606 00:35:58,208 --> 00:36:00,272 是广度优先还是深度优先 whether it's breadth first or depth first or anything. 607 00:36:00,280 --> 00:36:01,648 另外一个原因是 And it's even more impossible 608 00:36:01,664 --> 00:36:05,584 我们通过惰性流隐藏了实际执行顺序 because the actual order is somehow buried in the delays of the streams. 609 00:36:07,696 --> 00:36:11,168 因此很难说清楚它的扫描顺序 So what's very hard to tell from this is the order in which it's scanned. 610 00:36:11,270 --> 00:36:12,160 但真实的是 But what's true is, 611 00:36:12,192 --> 00:36:13,648 由于你是在流视图观察它的 because you're looking at the stream view, 612 00:36:13,904 --> 00:36:15,820 而它们最终都要被扫描到 is that all of them eventually get looked at. 613 00:36:24,980 --> 00:36:28,150 这里还有一个小小的技术问题 Let me just mention one tiny technical problem. 614 00:36:30,880 --> 00:36:33,552 假设我在这里输入 Um Suppose I tried over here. 615 00:36:37,530 --> 00:36:41,008 假设我输入(BOSS ?Y COMPUTER) Suppose I tried saying boss of y is computer, 616 00:36:44,224 --> 00:36:45,780 然后就会发生一件有意思的事儿 then a funny thing would happen. 617 00:36:45,780 --> 00:36:50,256 这里的字典就有一项?Y As I stuck a dictionary with y in here, 618 00:36:52,736 --> 00:36:57,376 而这两个?Y是不相同的 I might get-- this y is not the same as that y, 619 00:36:57,424 --> 00:37:00,624 后者是其它人的工作描述 which was the other piece of somebody's job description. 620 00:37:01,580 --> 00:37:03,808 因此 按照输入“照本宣科”地执行的话 So if I really only did literally what I said, 621 00:37:04,224 --> 00:37:06,448 我们就会遇到变量冲突的问题 we'd get some variable conflict problems. 622 00:37:09,280 --> 00:37:10,480 所以我骗了你们一下 So I lied to you a little bit. 623 00:37:10,930 --> 00:37:13,840 注意 我们之前也遇到过同样的问题 Notice that problem is exactly a problem we've run into before. 624 00:37:14,270 --> 00:37:15,568 具体来说就是 It is precisely 625 00:37:15,968 --> 00:37:18,360 一门语言需要局部变量 the need for local variables in a language. 626 00:37:19,240 --> 00:37:21,744 当我计算SQUARE和SUM-SQUARES的时候 When I square, when I have the sum of squares, 627 00:37:21,792 --> 00:37:23,390 这两个X应该是不同的 that x had better not be that x. 628 00:37:24,960 --> 00:37:26,320 同样的道理 That's exactly the same as 629 00:37:27,392 --> 00:37:29,776 这两个?Y应该也不相同 as this y had better not be that y. 630 00:37:31,800 --> 00:37:32,752 我们知道该如何解决 And we know how to solve that. 631 00:37:32,784 --> 00:37:34,490 就是引入环境模型 We built -- That was this whole environment model, 632 00:37:34,512 --> 00:37:37,040 我们构建类似于“框架链”一类的东西 and we built chains of frames and all sorts of things like that. 633 00:37:37,710 --> 00:37:39,104 还有更加“粗暴”的解决方法 There's a much more brutal way to solve it. 634 00:37:39,104 --> 00:37:41,730 在查询语言中 我们根本不这么做 In the query language, we didn't even do that. 635 00:37:41,730 --> 00:37:43,184 我们的解决方法非常粗暴 We did something completely brutal. 636 00:37:43,540 --> 00:37:45,936 我们规定 每次你在应用一条规则的时候 We said every time you apply a rule, 637 00:37:47,264 --> 00:37:49,632 用一个不会引起冲突的唯一名字 rename consistently all the variables in the rule 638 00:37:49,776 --> 00:37:53,504 统一地为规则中的所有变量更名 to some new unique names that won't conflict with anything. 639 00:37:54,040 --> 00:37:57,104 这个从概念上来说更简单 If you looked at the -- That's conceptually simpler, 640 00:37:57,120 --> 00:37:59,240 但既粗暴 又不是很有效 but really brutal and not particularly efficient. 641 00:37:59,970 --> 00:38:01,152 但是请注意 But notice, 642 00:38:01,392 --> 00:38:04,688 如果我们对Lisp中定义的过程也这么处理 we could have gotten rid of all of our environment structures 643 00:38:05,500 --> 00:38:08,720 那么就不需要环境模型了 if we defined for procedures in Lisp the same thing. 644 00:38:08,752 --> 00:38:11,560 如果我们每次在应用一个过程的时候 If every time we applied a procedure and did the substitution model 645 00:38:11,872 --> 00:38:13,904 我们为过程中的所有变量更名 we renamed all the variables in the procedure, 646 00:38:14,192 --> 00:38:16,288 那么我们就不需要担心局部变量了 then we never would have had to worry about local variables 647 00:38:16,336 --> 00:38:17,392 因为它们不会出现 because they would never arise. 648 00:38:19,040 --> 00:38:20,416 但这种做法比较低效 OK, well, that would be inefficient, 649 00:38:20,912 --> 00:38:23,040 在我们的查询语言中同样也比较低效 and it's inefficient here in the query language, too, 650 00:38:23,296 --> 00:38:24,592 但我们还是这样做了 并让它保持简单 but we did it to keep it simple. 651 00:38:25,610 --> 00:38:26,672 有问题吗? Let's break for questions. 652 00:38:30,880 --> 00:38:33,392 学生:您这一小节开始的时候 AUDIENCE: When you started this section, 653 00:38:33,408 --> 00:38:39,600 就强调APPLY-EVAL模型是多么的强大 you emphasized how powerful our APPLY EVAL model was 654 00:38:39,632 --> 00:38:41,170 以至于任何语言都适用 that we could use it for any language. 655 00:38:41,170 --> 00:38:43,392 但你又说这门语言将会非常不同 And then you say we're going to have this language which is so different. 656 00:38:43,950 --> 00:38:45,136 但最后却发现这门语言 It turns out that this language, 657 00:38:45,584 --> 00:38:47,880 就像你指出的那样--也是同样的 as you just pointed out, is very much the same. 658 00:38:47,880 --> 00:38:49,856 我在想 您是否是在论证 I'm wondering if you're arguing that all languages end up 659 00:38:50,480 --> 00:38:54,576 所有的语言都可以转化成 规则或过程的应用 coming down to this you can apply a rule or apply a procedure 660 00:38:55,120 --> 00:38:55,984 或者类似的 or some kind of apply? 661 00:38:57,072 --> 00:38:58,880 教授:可以说 几乎所有语言 PROFESSOR: I would say that pretty much any language 662 00:38:58,928 --> 00:39:00,304 我们通过组合手段构建对象 where you really are building up 663 00:39:00,928 --> 00:39:04,400 用简单的名字给它们命名 these means of combination and giving them simpler names 664 00:39:04,704 --> 00:39:06,864 你可以把任何类似的 比如 and you're saying anything of the sort, like 665 00:39:07,790 --> 00:39:09,900 有一种一般性的表达式 here's a general kind of expression, 666 00:39:09,984 --> 00:39:11,408 比如说如何计算某数的平方 like how to square something, 667 00:39:12,032 --> 00:39:14,208 几乎所有的东西都可以称为“过程” almost anything that you would call a procedure. 668 00:39:14,880 --> 00:39:15,888 如果语言中有这么一部分的话 If that's got to have parts, 669 00:39:15,904 --> 00:39:17,248 那么你就需要能够展开它们 you have to unwind those parts. 670 00:39:18,020 --> 00:39:20,192 你需要有某种组织 使得 You have to have some kind of organization which says 671 00:39:20,570 --> 00:39:24,032 当你查看这些抽象变量 或者说标签的时候 when I look at the abstract variables or tags 672 00:39:24,064 --> 00:39:27,100 它们可能代表着某些特定的东西 or whatever you want to call them that might stand for particular things, 673 00:39:28,336 --> 00:39:29,344 你必须一直跟踪它们 you have to keep track of that, 674 00:39:29,392 --> 00:39:30,912 这就会形成类似于环境的结构 and that's going to be something like an environment. 675 00:39:31,720 --> 00:39:32,544 让后当你要 And then if you say 676 00:39:32,704 --> 00:39:35,264 展开复合对象其中的一个部分的时候 this part can have parts which I have to unwind, 677 00:39:35,808 --> 00:39:37,440 你就需要EVAL-APPLY循环了 you've got to have something like this cycle. 678 00:39:39,970 --> 00:39:43,200 有很多很多的语言有这样的特点 And lots and lots of languages have that character 679 00:39:43,360 --> 00:39:45,408 它们也是按这种方式组织的 as long ... when they sort of get put together in this way. 680 00:39:45,590 --> 00:39:47,200 而这门语言特殊之处在于 This language again really is different 681 00:39:47,216 --> 00:39:49,504 从外界看 并没有“过程” because there's nothing like procedures on the outside. 682 00:39:50,690 --> 00:39:52,688 而当你剖开表层 深入到实现中去 When you go below the surface and you see the implementation, 683 00:39:52,704 --> 00:39:54,240 当然 你会发现本质是一样的 of course, it starts looking the same. 684 00:39:54,870 --> 00:39:56,950 但是从外界来看 这是一种非常不同的世界观 But from the outside, it's a very different world view. 685 00:39:56,950 --> 00:39:58,544 你没有计算输入的函数 You're not computing functions of inputs. 686 00:40:03,970 --> 00:40:05,712 学生:您之前提到过 AUDIENCE: You mentioned earlier that 687 00:40:06,608 --> 00:40:09,552 当用模式匹配来实现这些规则时 when you build all of these rules in pattern matcher 688 00:40:10,010 --> 00:40:11,424 由于使用了流实现延迟求值 and with the delayed action of streams, 689 00:40:11,456 --> 00:40:12,720 所以没有办法知道 you really have no way to know 690 00:40:13,376 --> 00:40:15,360 对象的求值顺序 in what order things are evaluated. 691 00:40:15,584 --> 00:40:15,940 教授:是这样的 PROFESSOR: Right. 692 00:40:15,940 --> 00:40:18,288 学生:但这就表明 AUDIENCE: And that would indicate then that 693 00:40:18,940 --> 00:40:22,288 我们只能表达总是为真的陈述性知识 you should only express declarative knowledge that's true for all-time, 694 00:40:22,304 --> 00:40:23,790 语言并不支持时间序列 no-time sequence built into it. 695 00:40:23,950 --> 00:40:25,472 否则的话 后果就会-- Otherwise, these things get all-- 696 00:40:27,390 --> 00:40:28,768 教授:是的 非常正确 PROFESSOR: Yes. Yes. 697 00:40:28,820 --> 00:40:29,488 问题在于 The question is 698 00:40:30,064 --> 00:40:32,608 这个本来就是用来处理陈述性知识的 this really is set up for doing declarative knowledge, 699 00:40:33,264 --> 00:40:34,816 而就我目前所演示的来说 不支持 and as I presented it-- no 700 00:40:35,712 --> 00:40:39,568 休息之后我会向你们揭露这其中的丑陋之处 and I'll show you some of the ugly warts under this after the break. 701 00:40:40,830 --> 00:40:42,608 就如我目前所展示的 它只是进行逻辑运算 As I presented it, it's just doing logic. 702 00:40:43,070 --> 00:40:44,528 原理上来说 如果我们做的是逻辑运算 And in principle, if it were logic, 703 00:40:44,544 --> 00:40:46,810 用什么顺序完成并不会造成影响 it wouldn't matter what order it's getting done. 704 00:40:48,840 --> 00:40:51,552 但是呢 And it's quite true 705 00:40:51,600 --> 00:40:53,616 当你在进行一些具有副作用的操作的时候 when you start doing things where you have side effects 706 00:40:53,680 --> 00:40:55,200 比如向数据库中添加项 like adding things to the database 707 00:40:55,230 --> 00:40:58,160 从中取出项 等等操作 and taking things out, and we'll see some others, 708 00:40:58,752 --> 00:41:00,832 你就丧失了这类控制 you loose that kind of control. 709 00:41:01,290 --> 00:41:02,940 因此 这就与Prolog完全不同 So, for example, contrasting with Prolog. 710 00:41:02,940 --> 00:41:05,152 Prolog有各种功能 Say Prolog has various features 711 00:41:05,168 --> 00:41:07,792 能够让你利用求值的顺序 where you really exploit the order of evaluation. 712 00:41:09,640 --> 00:41:11,770 人们也这么来写Prolog And people write Prolog programs that way. 713 00:41:11,770 --> 00:41:14,048 结果发现这样变得非常困难 That turns out to be very complicated in Prolog, 714 00:41:14,320 --> 00:41:17,552 但如果你是Prolog程序专家 你就可以这么做 although if you're an expert Prolog programmer, you can do it. 715 00:41:18,590 --> 00:41:20,210 但是我认为你们现在并不可以 However, here I don't think you can do it at all. 716 00:41:20,210 --> 00:41:21,248 它相当复杂 It's very complicated 717 00:41:21,728 --> 00:41:23,648 因为你们放弃了对事先安排的 because you really are giving up control over 718 00:41:23,776 --> 00:41:25,728 求值顺序的控制权 any prearranged order of trying things. 719 00:41:27,150 --> 00:41:30,160 学生:这就表明 当你有一个函数式映射时 AUDIENCE: Now, that would indicate then that you have a functional mapping. 720 00:41:30,670 --> 00:41:32,512 而你最初在讲这门课的时候 And when you started out this lecture, 721 00:41:32,992 --> 00:41:34,080 你说过 you said that 722 00:41:34,672 --> 00:41:36,704 我们在表述作为关系的陈述性知识 we express the declarative knowledge which is a relation, 723 00:41:37,152 --> 00:41:38,810 因为我们讨论的不是输入和输出 and we don't talk about the inputs and the outputs. 724 00:41:41,216 --> 00:41:43,370 教授:这是关于“函数式”的双关语 PROFESSOR: Well, there's a pun on functional, right? 725 00:41:43,370 --> 00:41:45,792 一种是没有副作用 There's functional in the sense of no side effects 726 00:41:46,208 --> 00:41:48,160 因此并不依赖于求值的顺序 and not depending on what order is going on. 727 00:41:48,700 --> 00:41:51,040 还有就是数学意义上的“函数” And then there's functional in the sense of mathematical function, 728 00:41:51,072 --> 00:41:52,220 有关于输入和输出 which means input and output. 729 00:41:52,592 --> 00:41:54,368 我想这就是你想表达的双关 And it's just that pun that you're making, I think. 730 00:41:56,510 --> 00:41:58,512 学生:我对其中两条语句不太明白 AUDIENCE: I'm a little unclear on what you're doing with 731 00:41:58,816 --> 00:42:00,704 也就是那两条有关BOSS的语句 two statements, the two boss statements. 732 00:42:01,270 --> 00:42:05,744 是不是 第一条查询构建了一个数据库 Is the first one building up the database 733 00:42:05,760 --> 00:42:08,080 然后第二条查询-- and the second one a query or-- 734 00:42:09,072 --> 00:42:10,128 教授:抱歉 PROFESSOR: OK, I'm sorry. 735 00:42:12,440 --> 00:42:15,168 这里的意思是 如果我输入这样的查询 What I meant here, if I type something like this in as a query-- 736 00:42:16,128 --> 00:42:18,448 我应该最初就给你们举这个例子 I should have given an example way at the very beginning. 737 00:42:19,470 --> 00:42:23,520 如果我输入(JOB (BITDIDDLE BEN) (COMPUTER WIZARD)) If I type in job, Ben Bitdiddle, computer wizard, 738 00:42:25,040 --> 00:42:27,770 系统会找到一处事实 what the processing will do is if it finds a match, 739 00:42:28,304 --> 00:42:30,288 来完全匹配这条查询 it'll find a match to that exact thing, 740 00:42:30,864 --> 00:42:33,280 然后输出(JOB (BITDIDDLE BEN) (COMPUTER WIZARD)) and it'll type out a job, Ben Bitdiddle, computer wizard. 741 00:42:34,220 --> 00:42:35,600 如果没找到这样的匹配 If it doesn't find a match, 742 00:42:35,696 --> 00:42:36,752 它就什么也不输出 it won't find anything. 743 00:42:37,400 --> 00:42:39,552 我应该这么来表述 So what I should have said is the way 744 00:42:39,568 --> 00:42:42,272 这门语言是用来查询某个表述是否为真 you use the query language to check whether something is true, 745 00:42:43,408 --> 00:42:45,776 这是逻辑式编程的目的之一 that's one of the things you want to do in logic programming, 746 00:42:46,416 --> 00:42:49,344 输入一条查询 要么得到结果 要么没有 is you type in your query and either that comes out or it doesn't. 747 00:42:50,680 --> 00:42:52,384 因此 我这里想要演示的是 So what I was trying to illustrate here, 748 00:42:52,416 --> 00:42:54,800 我想要在介绍合一算法前 I wanted to start with a very simple example 749 00:42:54,832 --> 00:42:56,624 举一个简单的例子 before talking about unifiers. 750 00:42:57,480 --> 00:42:58,112 所以 我应该说 So what I should have said, 751 00:42:58,144 --> 00:43:00,960 如果我想要检查 这个是否为真 if I just wanted to check whether this is true, 752 00:43:01,184 --> 00:43:03,280 我就可以将它输入 并看有没有任何输出 I could type that in and see if anything came out 753 00:43:05,168 --> 00:43:06,272 学生:然后第二条查询 AUDIENCE: And then the second one-- 754 00:43:06,288 --> 00:43:07,840 教授:第二条就是真正意义上的“查询” PROFESSOR: The second one would be a real query. 755 00:43:07,888 --> 00:43:09,120 学生:好的 真正的查询 AUDIENCE: A real query, yeah. 756 00:43:10,770 --> 00:43:13,104 教授:在这里它就会输出与?WHO相关的信息 PROFESSOR: What would come out, see, it would go in here say with WHO, 757 00:43:13,904 --> 00:43:15,744 就会有一个框架 存储着 and in would go frame that says z 758 00:43:16,624 --> 00:43:18,816 ?Z=?WHO ?D=COMPUTER z is bound to who and d is bound to computer. 759 00:43:19,560 --> 00:43:20,496 这个会传递下去 And this will pass through, 760 00:43:20,512 --> 00:43:21,952 传递到这里的时候 and then by the time it got out of here, 761 00:43:22,016 --> 00:43:23,250 ?WHO就会被绑定起来 who would pick up a binding. 762 00:43:26,950 --> 00:43:28,768 学生:在合一那里 AUDIENCE: On the unifying thing there, 763 00:43:29,180 --> 00:43:35,968 我还是不太清楚?WHO和?Z之间发生了什么 I still am not sure what happens with who and z. 764 00:43:36,460 --> 00:43:39,584 要进行合一的话 这里的规则说 OK being unifying-- the rule here says-- 765 00:43:42,032 --> 00:43:46,224 你说过 两个模式变量之间不能互相绑定 OK, so you say that you can't make question mark equal to question mark who. 766 00:43:46,260 --> 00:43:48,080 教授:模式匹配器确实不能这样 PROFESSOR: Right. That's what the matcher can't do. 767 00:43:48,360 --> 00:43:50,832 但对合一算法来说 But unifier, what this will mean to a unifier 768 00:43:51,920 --> 00:43:54,016 就是一个有存储三个变量的环境 is that there's an environment with three variables. 769 00:43:56,690 --> 00:43:57,904 其中?D=COMPUTER d here is computer. 770 00:43:58,520 --> 00:44:00,192 ?Z=?WHO z is whatever who is. 771 00:44:01,830 --> 00:44:05,264 所以在稍后的匹配过程中 So if later on in the matcher routine 772 00:44:07,200 --> 00:44:10,384 如果?WHO=3 it said, for example, who has to be 3, 773 00:44:12,064 --> 00:44:13,664 那么当我再查找字典的时候 then when I looked up in the dictionary, 774 00:44:14,000 --> 00:44:16,400 它会告诉我 因为?Z=?WHO 所以?Z=3 it will say, oh, z is 3 because it's the same as who. 775 00:44:18,360 --> 00:44:20,448 从某种意义上来说 你就只需要修改这一点 And that's in some sense the only thing you need to do 776 00:44:20,464 --> 00:44:21,984 就可以把合一算法变成模式匹配器 to extend the unifier to a matcher. 777 00:44:22,480 --> 00:44:24,800 学生:但是看起来你好像告诉了它 如何进行合一 AUDIENCE: OK, because it looked like when you were telling how to unify, 778 00:44:24,830 --> 00:44:26,960 就像你已经解好了方程 准备好了值 it looked like you would put the things together in such a way 779 00:44:26,992 --> 00:44:29,232 并把它们安排成这样 that you'd actually solve and have a value for both of them. 780 00:44:29,770 --> 00:44:31,248 现在看起来就像是 And what it looks like now 781 00:44:31,280 --> 00:44:32,832 你传递了一本字典 is that you're actually pass a dictionary 782 00:44:32,880 --> 00:44:34,860 其中的两个变量是关联起来的 with two variables and the variables are linked. 783 00:44:34,880 --> 00:44:37,230 教授:实际上 我们在同时求解它们 PROFESSOR: Right. It only looks like you're solving for both of them 784 00:44:37,520 --> 00:44:39,744 这是因为我们想要一下得到整个答案 because you're sort of looking at the whole solution at once. 785 00:44:40,540 --> 00:44:42,816 如果你观察它们是如何被递归地构建的 If you sort of watch the thing getting built up recursively, 786 00:44:42,816 --> 00:44:43,740 基本上就是这样了 it's merely this. 787 00:44:44,980 --> 00:44:48,400 学生:也就是确实要传递含有两个变量的字典? AUDIENCE: OK, so you do pass off that dictionary with two variables? 788 00:44:48,400 --> 00:44:49,110 教授:是的 PROFESSOR: That's right. 789 00:44:49,110 --> 00:44:49,680 学生:然后把它们关联起来? AUDIENCE: And link? 790 00:44:50,384 --> 00:44:52,912 教授:就像通常的字典那样 PROFESSOR: Right. It just looks like an ordinary dictionary. 791 00:44:54,352 --> 00:44:56,064 学生:你在讨论合一算法的时候 AUDIENCE: When you're talking about the unifier, 792 00:44:56,096 --> 00:45:00,192 你说过在某些情况下 is it that there are some cases or some points 793 00:45:00,752 --> 00:45:03,984 合一不能够完成 that you are not able to unify them? 794 00:45:04,032 --> 00:45:04,304 教授:是的 PROFESSOR: Right. 795 00:45:04,970 --> 00:45:08,464 学生:那么 是否可以通过编写规则 AUDIENCE: Can you just by building the rules or 796 00:45:09,160 --> 00:45:15,936 或者 写入那些事先知道可解的形式 writing the forms know in advance if you are going to be able to solve 797 00:45:16,480 --> 00:45:18,540 来使得合一算法能够完成 to get the unification or not? 798 00:45:18,768 --> 00:45:22,944 是否可以在规则中添加一些属性 Can you add some properties either to the rules itself 799 00:45:23,184 --> 00:45:25,456 或者向输入的形式中添加属性 or to the form that you're writing 800 00:45:25,824 --> 00:45:29,040 来避免无法进行合一的窘境 so that you avoid the problem of not finding unification? 801 00:45:29,180 --> 00:45:31,152 PROFESSOR: 我想 你也同意 Well I mean, you can agree, 802 00:45:31,472 --> 00:45:35,264 用非常受限的方式来编写查询 I think, to write in a fairly restricted way where you won't run into it. 803 00:45:35,600 --> 00:45:36,672 看 你遇到的是 See, because what you're getting-- 804 00:45:36,880 --> 00:45:39,120 仔细看 你遇到问题是在 see, the place where you get into problems is when you-- 805 00:45:39,680 --> 00:45:44,256 用像这样的东西去匹配 well, again, you're trying to match things like that 806 00:45:44,592 --> 00:45:47,200 具有这样结构的模式时 against things where these have structure, 807 00:45:47,552 --> 00:45:55,300 比如((A ?Y B) ?Y) where a, y, b, y something. 808 00:45:58,980 --> 00:46:01,488 这是你可能遇到问题的一个地方 So this is the kind of place where you're going to get into trouble. 809 00:46:03,070 --> 00:46:05,808 学生:所以你可以在语法层次上处理它么? AUDIENCE: So you can do that syntactically? 810 00:46:06,140 --> 00:46:08,768 教授:你可以在写查询时 PROFESSOR: So you can kind of watch your rules 811 00:46:08,768 --> 00:46:10,490 注意你的规则 in the kinds of things that your writing. 812 00:46:11,904 --> 00:46:14,080 学生:这个问题应该由 AUDIENCE: So that's the problem that the builder 813 00:46:14,112 --> 00:46:16,272 数据库的构建者考虑么? of the database has to be concerned? 814 00:46:16,576 --> 00:46:17,808 教授:这个问题 PROFESSOR: That's a problem. 815 00:46:19,930 --> 00:46:22,016 不完全是数据库的构建者 It's a problem either-- not quite the builder of the database, 816 00:46:22,048 --> 00:46:23,616 或者是表述规则的人 the person who is expressing the rules, 817 00:46:24,016 --> 00:46:25,312 所需要考虑的 or the builder of the database. 818 00:46:25,800 --> 00:46:29,792 当你们仔细审查合一算法的代码时 What the unifier actually does is you can check at the next level down 819 00:46:29,920 --> 00:46:31,872 你们会发现 when you actually get to the unifier 820 00:46:32,416 --> 00:46:34,768 它实际上在查询一个字典 and you'll see in the code where it looks up in the dictionary. 821 00:46:34,940 --> 00:46:36,832 它会问 ?Y的取值应该是什么? If it sort of says what does y have to be? 822 00:46:37,260 --> 00:46:41,424 ?Y应该是一个含有自包含的表达式么? Oh, does y have to be something that contains a y as its expression? 823 00:46:41,960 --> 00:46:43,264 这时候 合一算法就会说 At that point, the unifier and say, 824 00:46:43,280 --> 00:46:46,240 哦 我正在求解一个不动点方程 oh my God, I'm trying to solve a fixed-point equation. 825 00:46:46,240 --> 00:46:46,992 我还是放弃吧 I'll give it up here. 826 00:46:48,592 --> 00:46:51,910 学生:你区分过数据库中的规则 AUDIENCE: You make the distinction between the rules in the database. 827 00:46:51,910 --> 00:46:56,480 这些规则是加入数据库的么? Are the rules added to the database? 828 00:46:56,950 --> 00:46:57,360 教授:是的 PROFESSOR: Yes. 829 00:46:57,870 --> 00:46:58,870 我应该这么来说 Yes, I should have said that. 830 00:46:58,870 --> 00:47:00,336 你们可以把规则看作 One way to think about rules 831 00:47:00,608 --> 00:47:02,656 数据库中的其它东西 is that they're just other things in the database. 832 00:47:03,712 --> 00:47:06,810 如果你想要检查数据库中需要检查的东西 So if you want to check the things that have to be checked in the database, 833 00:47:06,832 --> 00:47:09,440 它们就是存在于数据库中的虚拟事实 they're kind of virtual facts that are in the database. 834 00:47:09,440 --> 00:47:12,320 学生:但是在这个解释中 AUDIENCE: But in that explanation, you made the differentiation 835 00:47:12,432 --> 00:47:17,264 你就已经区分了数据库和规则本身 between database and the rules itself. 836 00:47:18,230 --> 00:47:19,904 教授:是的 我应该不这么来说 PROFESSOR: Yeah, I probably should not have done that. 837 00:47:20,490 --> 00:47:23,312 这样做的唯一理由就是实现 The only reason to do that is in terms of the implementation. 838 00:47:23,540 --> 00:47:24,672 当你们查看具体实现时 When you look at the implementation, 839 00:47:24,680 --> 00:47:27,504 会发现其中有部分用来检查数据库中的 there's a part which says check either primitive 840 00:47:27,552 --> 00:47:29,850 基本断言或者规则 assertions in the database or check rules. 841 00:47:30,470 --> 00:47:32,720 这其中的真正原因就是 And then the real reason, the real reason why 842 00:47:32,780 --> 00:47:34,560 你不知道查询结果是以什么顺序输出的 you can't tell what order things are going to come out in 843 00:47:34,960 --> 00:47:40,460 而规则数据库和数据数据库 is that the rules database and the data database 844 00:47:40,480 --> 00:47:43,680 是通过某种延迟求值的方式合并的 sort of get merged in a kind of delayed evaluation way. 845 00:47:44,600 --> 00:47:46,800 这就使得顺序变得非常复杂 And so that's what makes the order very complicated. 846 00:47:55,440 --> 00:47:56,096 那好 我们休息一下 OK, let's break. 847 00:47:56,300 --> 00:48:09,904 [音乐] [JESU, JOY OF MAN'S DESIRING] 848 00:48:10,040 --> 00:48:14,416 《计算机程序的构造和解释》 849 00:48:18,680 --> 00:48:22,096 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 850 00:48:22,090 --> 00:48:25,968 《计算机程序的构造和解释》 851 00:48:26,000 --> 00:48:29,872 逻辑式程序设计 II 852 00:48:33,160 --> 00:48:35,376 我们已经学习了逻辑式语言与 We've just seen how the logic language works 853 00:48:35,392 --> 00:48:36,416 规则系统的运行原理 and how rules work. 854 00:48:37,230 --> 00:48:39,376 现在 让我们来探讨一个更加深刻的问题 Now, let's turn to a more profound question. 855 00:48:40,120 --> 00:48:41,280 来看下它们意味着什么 What do these things mean? 856 00:48:43,180 --> 00:48:46,864 这把我们带入到整个查询语言中 That brings us to the subtlest, most devious part 857 00:48:46,992 --> 00:48:48,672 最微妙的部分 of this whole query language business, 858 00:48:49,216 --> 00:48:53,070 也就是它看起来与想象中不同的地方 and that is that it's not quite what it seems to be. 859 00:48:53,570 --> 00:48:56,224 AND、OR以及NOT AND and OR and NOT 860 00:48:57,024 --> 00:48:58,880 以及规则的逻辑蕴含 and the logical implication of rules 861 00:48:59,696 --> 00:49:06,640 并不是逻辑学中的与、或、非以及蕴含 are not really the AND and OR and NOT and logical implication of logic. 862 00:49:07,690 --> 00:49:09,712 让我来举一个实例 Let me give you an example of that. 863 00:49:09,910 --> 00:49:12,224 当然 如果我们有两个逻辑命题 Certainly, if we have two things in logic, 864 00:49:12,400 --> 00:49:19,440 那么(AND P Q)就应该 it ought to be the case that AND of P and Q 865 00:49:20,000 --> 00:49:22,592 等同于(AND Q P) is the same as AND of Q and P 866 00:49:23,100 --> 00:49:24,510 而(OR P Q)就应该 and that OR of P and Q 867 00:49:24,780 --> 00:49:26,510 等同于(OR Q P) is the same as OR of Q and P. 868 00:49:28,672 --> 00:49:30,096 但我们来看看这里 But let's look here. 869 00:49:30,100 --> 00:49:32,016 这里是一个例子 Here's an example. 870 00:49:32,180 --> 00:49:36,160 来看看 在我们的数据库中 Let's talk about somebody outranking somebody else 871 00:49:36,288 --> 00:49:40,140 如何表示某人的级别高于他人 in this our little database organization. 872 00:49:40,140 --> 00:49:42,896 我们定义(OUTRANKED-BY ?S ?B)为 We'll say s is outranked by b 873 00:49:44,640 --> 00:49:48,624 或者S是B的上司 if or if either the supervisor of s is b 874 00:49:49,630 --> 00:49:51,072 或者这其中有某个中间经理M or there's some middle manager here, 875 00:49:51,104 --> 00:49:55,820 其中S是M的上司 M的级别又比B高 that supervisor of s is m, and m is outranked by b. 876 00:49:59,648 --> 00:50:02,310 这是定义OUTRANKED-BY的一种方式 So there's one way to define rule outranked by. 877 00:50:02,310 --> 00:50:04,160 或者我们可以原封不动地写过来 Or we can write exactly the same thing, 878 00:50:05,088 --> 00:50:06,912 除了在最底部的这里 except at the bottom here, 879 00:50:07,216 --> 00:50:09,888 我们颠倒一下这两个子句的顺序 we reversed the order of these two clauses. 880 00:50:11,630 --> 00:50:12,992 当然 如果它们都是逻辑表达式的话 And certainly if this were logic, 881 00:50:13,008 --> 00:50:14,880 它们应该表示的是相同的东西 those ought to mean the same thing. 882 00:50:16,690 --> 00:50:17,312 然而 However, 883 00:50:17,712 --> 00:50:19,616 在我们这个特定的实现中 in our particular implementation, 884 00:50:19,648 --> 00:50:22,880 如果你查询(OUTRANDKED-BY ?WHO (BITDIIDLE BEN)) if you say something like who's outranked by Ben Bitdiddle, 885 00:50:23,488 --> 00:50:25,360 你会发现 这条规则 what you'll find is that this rule 886 00:50:26,768 --> 00:50:28,720 会完美地生成答案 will work perfectly well and generate answers, 887 00:50:30,048 --> 00:50:31,984 然而 这条规则会陷入无穷循环 whereas this rule will go into an infinite loop. 888 00:50:34,110 --> 00:50:36,272 其中的原因就是 And the reason for that is that 889 00:50:36,336 --> 00:50:40,336 这条规则会问谁比BEN BITDIDDLE级别高? this will come in and say, oh, who's outranked by Ben Bitdiddle? 890 00:50:41,920 --> 00:50:43,536 它试图寻找一个S Find an s, find an s 891 00:50:43,888 --> 00:50:46,224 使得S比B的级别更高 其中B是BEN BITDIDDLE which is outranked by b, where b is Ben Bitdiddle, 892 00:50:47,504 --> 00:50:49,632 这会在一个子问题中重复出现 which is going to happen in it a subproblem. 893 00:50:50,330 --> 00:50:51,984 找到一个M Oh gee, find an m 894 00:50:52,240 --> 00:50:54,576 使得M的级别高于BEN BITDIDDLE such as m is outranked by Ben Bitdiddle 895 00:50:55,616 --> 00:50:57,360 而对M没有限制 with no restrictions on m. 896 00:50:58,560 --> 00:51:00,400 这就相当于为了解决这个问题 So this will say in order to solve this problem, 897 00:51:01,424 --> 00:51:03,296 我就还需要求解同样的问题 I solve exactly the same problem. 898 00:51:04,570 --> 00:51:07,232 在把它解出来后 我才检查SUPERVISOR关系 And then after I've solved that, I'll check for a supervisory relationship. 899 00:51:08,000 --> 00:51:09,168 然而这条规则没有这样的问题 Whereas this one won't get into that, 900 00:51:09,184 --> 00:51:12,350 因为在它尝试找出这条OUTRANKED-BY规则之前 because before it tries to find this outranked by, 901 00:51:12,944 --> 00:51:15,260 在这里已经对M施加过约束了 it'll already have had a restriction on m here. 902 00:51:18,384 --> 00:51:20,944 随意 这两条规则理论上是相同的 So these two things which ought to mean the same, 903 00:51:20,992 --> 00:51:22,672 但实际上 其中一条会陷入无穷循环 in fact, one goes into an infinite loop. 904 00:51:22,860 --> 00:51:25,040 而另一条不会 One goes, one does not. 905 00:51:26,720 --> 00:51:29,776 通过这个非常极端的例子 That's a very extreme case 906 00:51:29,790 --> 00:51:32,656 你会发现在逻辑式程序设计中 of a general thing that you'll find in logic programming that 907 00:51:34,288 --> 00:51:38,704 如果你改变了AND或OR所连接子句的顺序 if you start changing the order of the things in the ANDs or ORs, 908 00:51:39,344 --> 00:51:41,584 你会发现效率上的巨大差异 you'll find tremendous differences in efficiency. 909 00:51:42,240 --> 00:51:43,216 我们刚刚就看到了 And we just saw 910 00:51:43,552 --> 00:51:46,544 在无穷循环方面的巨大差异 an infinitely big difference in efficiency and an infinite loop. 911 00:51:49,190 --> 00:51:51,744 同样的 这也跟输入规则 And there are similar things having to do order 912 00:51:52,000 --> 00:51:53,312 的顺序有关 in which you enter rules. 913 00:51:54,070 --> 00:51:56,480 向数据库查询规则的顺序 The order in which it happens to look at rules in the database 914 00:51:56,700 --> 00:51:59,952 会极大程度上影响效率:比如得到答案 may vastly change the efficiency with which it gets out answers or, 915 00:52:00,464 --> 00:52:02,608 或者在某些顺序下陷入无穷循环 in fact, send it into an infinite loop for some orderings. 916 00:52:03,840 --> 00:52:07,296 这些都跟 And this whole thing has to do 917 00:52:07,632 --> 00:52:10,048 你检查这些规则的顺序有关 the fact that you're checking these rules in some order. 918 00:52:10,950 --> 00:52:14,416 有些规则的蕴含路径会相当的长 And some rules may lead to really long paths of implication. 919 00:52:14,448 --> 00:52:16,064 而另外一些不会 Others might, others might not. 920 00:52:16,440 --> 00:52:17,680 但你事先并不知道 And you don't know a priori 921 00:52:17,728 --> 00:52:19,168 哪一个长 哪一个短 which ones are good and which ones are bad. 922 00:52:19,300 --> 00:52:21,488 有很多研究都与此有关 And there's a whole bunch of research having to do with that, 923 00:52:22,160 --> 00:52:23,760 其中大多数都是想通过 mostly having to do with thinking about 924 00:52:23,952 --> 00:52:26,970 用并行的方法来实现逻辑式程序设计语言 making parallel implementations of logic programming languages. 925 00:52:27,320 --> 00:52:29,904 某种意义上来说 就是并行地检查所有规则 And in some sense, what you'd like to do is check all rules in parallel 926 00:52:30,360 --> 00:52:32,800 一旦有一条搜索得到答案 就返回结果 and whichever ones get answers, you bubble them up. And 927 00:52:33,040 --> 00:52:34,992 如果某条路径陷入了无穷的推导 if some go down infinite deductive chain, 928 00:52:35,020 --> 00:52:38,256 那么 你只需知道 内存和处理器都非常廉价 well, you just-- you know, memory is cheap and processors are cheap, 929 00:52:38,288 --> 00:52:40,490 让它们根据你的需要一直搜寻就好了 you just let them buzz for as for as long as you want. 930 00:52:43,472 --> 00:52:44,832 尽管如此 与真正的逻辑相比 There's a deeper problem, though, 931 00:52:45,184 --> 00:52:50,496 这门逻辑式语言还有一个更深刻的问题 in comparing this logic language to real logic. 932 00:52:50,688 --> 00:52:52,528 我给你们演示的例子 The example I just showed you, it 933 00:52:52,976 --> 00:52:54,800 只是会陷入无穷循环 went into an infinite loop maybe, 934 00:52:55,376 --> 00:52:56,992 但至少不会给你错误的答案 but at least it didn't give the wrong answer. 935 00:52:58,370 --> 00:53:03,648 当我们开始严肃地把这门逻辑式语言 There's an actual deeper problem when we start comparing, 936 00:53:03,680 --> 00:53:05,240 与真正的经典逻辑作比较时 you know, seriously comparing 937 00:53:05,712 --> 00:53:08,464 就会发现其中最深层次的问题 this logic language with real classical logic. 938 00:53:09,490 --> 00:53:12,432 让我们来看看真正的经典逻辑 So let's sort of review real classical logic. 939 00:53:13,712 --> 00:53:21,040 所有的人类都是凡人 All humans are mortal. 940 00:53:22,352 --> 00:53:23,456 相当经典的逻辑命题 That's pretty classical logic. 941 00:53:24,390 --> 00:53:28,672 然后我们就依照最经典的传统 Then maybe we'll continue in the very best classical tradition. 942 00:53:29,248 --> 00:53:32,464 我们按照最传统的方式来做 We'll say all-- let's make it really classical. 943 00:53:32,670 --> 00:53:37,168 所有的希腊人都是人类 All Greeks are human, 944 00:53:40,496 --> 00:53:46,064 苏格拉底是希腊人 which has the syllogism that Socrates is a Greek. 945 00:53:48,176 --> 00:53:49,210 然后我们又该写什么呢? And then what do you write here? 946 00:53:49,210 --> 00:53:51,890 经典逻辑中有一个三点符号 I think three dots, classical logic. 947 00:53:51,890 --> 00:53:54,336 因此 我们得到了一个三段论 Therefore, then the syllogism, 948 00:53:54,640 --> 00:53:59,552 苏格拉底是凡人 Socrates is mortal. 949 00:54:01,360 --> 00:54:04,912 这些都是真正的经典逻辑 So there's some real honest classical logic. 950 00:54:05,880 --> 00:54:11,056 把它跟我们经典逻辑数据库比较一下 Let's compare that with our classical logic database. 951 00:54:12,400 --> 00:54:14,464 这是一个经典逻辑数据库 So here's a classical logic database. 952 00:54:16,270 --> 00:54:17,488 (GREEK SOCRATES) Socrates is a Greek. 953 00:54:18,030 --> 00:54:18,848 (GREEK PLATO) Plato is a Greek. 954 00:54:19,600 --> 00:54:20,400 (GREEK ZEUS) Zeus is a Greek, 955 00:54:20,848 --> 00:54:21,984 (GOD ZEUS) and Zeus is a god. 956 00:54:24,120 --> 00:54:29,968 所有的人类都是凡人 And all humans are mortal. 957 00:54:30,540 --> 00:54:32,128 为了证明某人是平凡的 To show that something is mortal, 958 00:54:32,160 --> 00:54:33,600 只需要证明他是人类 it's enough to show that it's human. 959 00:54:34,650 --> 00:54:35,900 所有的人类都是不可靠的 All humans are fallible. 960 00:54:38,900 --> 00:54:40,980 并且说所有的希腊人都是人类 并不正确 And all Greeks are humans is not quite right. 961 00:54:40,980 --> 00:54:44,416 这条规则说 所有不是神的希腊人都是人类 This says that all Greeks who are not gods are human. 962 00:54:45,710 --> 00:54:47,040 因此为了证明某人是人类 So to show something's human, 963 00:54:47,072 --> 00:54:48,896 只需要说明他是一个希腊人 并且不是神 it's enough to show it's a Greek and not a god. 964 00:54:49,320 --> 00:54:52,880 任何一个希腊神的住址是奥林匹斯山 And the address of any Greek god is Mount Olympus. 965 00:54:54,320 --> 00:54:57,168 这就是一个小型经典逻辑数据库 So there's a little classical logic database. 966 00:54:57,390 --> 00:54:59,328 确实 它运行得相当好 And indeed, that would work fairly well. 967 00:54:59,490 --> 00:55:02,096 如果我们向其询问 If we type that in and say 968 00:55:03,472 --> 00:55:06,576 苏格拉底是凡人么 不可靠么? is Socrates mortal or Socrates fallible or mortal? 969 00:55:06,910 --> 00:55:07,690 它会输出:是 It'll say yes. 970 00:55:07,776 --> 00:55:09,710 柏拉图是凡人并且不可靠么? Is Plato mortal and fallible. 971 00:55:09,710 --> 00:55:10,240 它会回答:是 It'll say yes. 972 00:55:10,680 --> 00:55:12,210 如果我们问宙斯是凡人么 If we say is Zeus mortal? 973 00:55:12,210 --> 00:55:13,232 它什么都不会找到 It won't find anything. 974 00:55:14,900 --> 00:55:15,968 运行得非常完美 And it'll work perfectly well. 975 00:55:16,544 --> 00:55:20,120 然而 如果我们想要把它扩展一下 However, suppose we want to extend this. 976 00:55:20,120 --> 00:55:23,056 让我们来定义一下什么是“完美生命体” Let's define what it means for someone to be a perfect being. 977 00:55:23,824 --> 00:55:27,216 我们把规则PERFECT定义为 Let's say rule: a perfect being. 978 00:55:34,050 --> 00:55:35,480 我想这样来定义是正确的 And I think this is right. 979 00:55:35,480 --> 00:55:38,144 如果你熟悉中世纪经院哲学 If you're up on your medieval scholastic philosophy, 980 00:55:38,448 --> 00:55:40,176 我想所谓“完美生命体”一定 I believe that perfect beings are ones 981 00:55:40,688 --> 00:55:42,656 既不是凡人 又不会不可靠 who were neither mortal nor fallible. 982 00:55:44,100 --> 00:55:56,848 (AND (NOT (MORTAL ?X)) (NOT (FALLIBLE ?X))) AND NOT mortal x, NOT fallible x. 983 00:55:59,300 --> 00:56:00,896 这样 我们就定义了一个规则 So we'll define this system 984 00:56:02,672 --> 00:56:04,368 来告诉系统 什么是“完美生命体” to teach it what a perfect being is. 985 00:56:05,790 --> 00:56:07,696 现在 我们就要 And now what we're going to do is 986 00:56:08,064 --> 00:56:10,176 询问所有“完美生命体”的地址 ask for the address of all the perfect beings. 987 00:56:11,488 --> 00:56:22,304 (AND (ADDRESS ?X ?Y) (PERFECT ?X)) AND the address of x is y and x is perfect. 988 00:56:23,488 --> 00:56:24,976 在这里 我们生成了 And so what we're generating here is 989 00:56:24,992 --> 00:56:27,808 世界上最独有的邮件列表 the world's most exclusive mailing list. 990 00:56:30,160 --> 00:56:32,200 为了查询所有完美生命体的地址 For the address of all the perfect beings, 991 00:56:32,240 --> 00:56:33,472 我们会输入像这样的查询 we might have typed this in. 992 00:56:33,830 --> 00:56:35,440 或者像这样输入 Or we might type in this. 993 00:56:36,240 --> 00:56:50,576 (AND (PERFECT ?X) (ADDRESS ?X ?Y)) We'll say AND perfect of x and the address of x is y. 994 00:56:52,064 --> 00:56:54,960 假设我们把它输入进去 并尝试查询 Well, suppose we type all that in and we try this query. 995 00:56:55,190 --> 00:56:56,768 这条查询会给我们答案 This query is going to give us an answer. 996 00:56:57,650 --> 00:57:00,000 这条查询会输出:奥林匹斯山 This query will say, yeah, Mount Olympus. 997 00:57:04,230 --> 00:57:06,576 而这条查询 什么也不会输出 This query, in fact, is going to give us nothing. 998 00:57:06,740 --> 00:57:09,584 它找不到完美生命体的地址 It will say no addresses of perfect beings. 999 00:57:11,640 --> 00:57:12,510 为什么会这样? Now, why is that? 1000 00:57:12,510 --> 00:57:13,440 这又为什么不同? Why is there a difference? 1001 00:57:14,230 --> 00:57:15,690 这个问题跟无穷循环没什么关系 This is not an infinite loop question. 1002 00:57:15,690 --> 00:57:17,088 这个的问题是答案不相同 This is a different answer question. 1003 00:57:19,488 --> 00:57:20,096 原因就是 The reason is 1004 00:57:20,380 --> 00:57:22,320 如果你们还记得NOT的实现的话 that if you remember the implementation of NOT, 1005 00:57:23,504 --> 00:57:24,848 NOT是作为一个过滤器 NOT acted as a filter. 1006 00:57:25,880 --> 00:57:29,008 NOT会接收一本字典 NOT said I'm going to take some possible dictionaries, 1007 00:57:29,050 --> 00:57:31,568 里面有可行解构成的框架 some possible frames, some possible answers, 1008 00:57:31,792 --> 00:57:33,168 然后过滤出那些 and filter out the ones 1009 00:57:33,290 --> 00:57:34,940 满足某个条件的解 that happened to satisfy some condition, 1010 00:57:34,976 --> 00:57:36,112 这就是我如何实现NOT的 and that's how I implement NOT. 1011 00:57:36,928 --> 00:57:38,432 如果你们仔细想想其中的原理 If you think about what's going on here, 1012 00:57:40,112 --> 00:57:42,656 我创建了一个查询盒子 I'll build this query box where the address piece 1013 00:57:43,320 --> 00:57:47,392 ADDRESS盒子的输出作为了PERFECT的输入 the output of an address piece gets fed into a perfect piece. 1014 00:57:50,290 --> 00:57:51,008 这就使得 What will happen is 1015 00:57:51,328 --> 00:57:53,264 ADDRESS盒子会创建出 the address piece will set up some things of 1016 00:57:53,328 --> 00:57:54,832 我知道地址的人 everyone whose address I know. 1017 00:57:55,290 --> 00:57:57,648 这些都会被PERFECT中的NOT给过滤掉 Those will get filtered by the NOTs inside perfect here. 1018 00:57:59,880 --> 00:58:04,192 所以它会丢弃掉那些满足平凡的或者不可靠的数据 So it will throw out the ones which happened to be either mortal or fallible. 1019 00:58:04,910 --> 00:58:06,384 而对于另外一种顺序来说 In the other order what happens 1020 00:58:06,736 --> 00:58:09,120 我以一个空框架开始的 is I set this up, started up with an empty frame. 1021 00:58:09,520 --> 00:58:12,352 但是这里PERFECT没有可以给NOT过滤的东西 The perfect in here doesn't find anything for the NOTs to filter, 1022 00:58:12,384 --> 00:58:13,984 所以这里不会有什么输出 so nothing comes out here at all. 1023 00:58:18,830 --> 00:58:21,504 这也就导致没有东西输入到ADDRESS中 And there's sort of nothing there that gets fed into the address thing. 1024 00:58:21,940 --> 00:58:23,152 因此 我得不到答案 So here, I don't get an answer. 1025 00:58:23,936 --> 00:58:27,040 在强调一下 这是因为NOT不会生成任何东西 And again, the reason for that is NOT isn't generating anything. 1026 00:58:27,440 --> 00:58:28,800 NOT只会丢弃数据 NOT's only throwing out things. 1027 00:58:29,080 --> 00:58:30,512 如果我不向NOT传递东西的话 And if I never started up with anything, 1028 00:58:30,528 --> 00:58:31,744 它也就不会输出 there's nothing for it to throw out. 1029 00:58:32,020 --> 00:58:33,770 这样我就得到了错误的答案 So out of this thing, I get the wrong answer. 1030 00:58:37,200 --> 00:58:37,970 我们又该如何修复它呢? How can you fix that? 1031 00:58:37,970 --> 00:58:39,070 当然 有很多办法 Well, there are ways to fix that. 1032 00:58:39,360 --> 00:58:40,912 你可能认为 现在这样有点愚蠢 So you might say, well, that's sort of stupid. 1033 00:58:41,410 --> 00:58:44,900 为什么要一开始就执行NOT呢? Why are you just doing all your NOT stuff at the beginning? 1034 00:58:44,960 --> 00:58:47,488 想要正确地实现NOT The right way to implement NOT is to realize 1035 00:58:47,840 --> 00:58:50,080 就是要认识到当你遇到NOT时 that when you have conditions like NOT, 1036 00:58:50,336 --> 00:58:52,096 你应该首先生成好答案 you should generate all your answers first, 1037 00:58:52,800 --> 00:58:54,976 然后通过字典把它们传递过来 and then with each of these dictionaries pass along 1038 00:58:55,520 --> 00:58:57,856 然后再最后再做过滤 Gee, at the very end I'll do filtering. 1039 00:58:58,560 --> 00:59:02,016 有些按照这种方式实现的逻辑式语言 And there are implementations of logic languages that work like that 1040 00:59:02,416 --> 00:59:04,050 能够解决这个问题 that solve this particular problem. 1041 00:59:06,800 --> 00:59:08,976 然而 还有一个更深刻的问题 However, there's a more profound problem, 1042 00:59:09,600 --> 00:59:11,536 也就是 哪个才是正确答案呢? which is which one of these is the right answer? 1043 00:59:12,530 --> 00:59:14,240 是奥林匹斯山 还是没有呢? Is it Mount Olympus or is it nothing? 1044 00:59:15,376 --> 00:59:18,730 你可能会认为是奥林匹斯山 So you might say it's Mount Olympus, 1045 00:59:18,760 --> 00:59:20,730 毕竟 宙斯在数据库中 because after all, Zeus is in that database, 1046 00:59:22,528 --> 00:59:25,104 宙斯不是平凡的 也不是不可靠的 and Zeus was neither mortal nor fallible. 1047 00:59:29,550 --> 00:59:32,448 因此你可能会认为宙斯满足 So you might say Zeus wants to satisfy 1048 00:59:34,304 --> 00:59:44,032 (NOT (MORTAL ZEUS))或者(NOT (FALLIBLE ZEUS)) NOT mortal Zeus or NOT fallible Zeus. 1049 00:59:44,120 --> 00:59:45,856 但我们实际来看一看数据库 But let's actually look at that database. 1050 00:59:47,920 --> 00:59:48,464 来看一下 Let's look at it. 1051 00:59:49,360 --> 00:59:53,240 它要如何知道宙斯不是不可靠的? There's no way-- how does it know that Zeus is not fallible? 1052 00:59:54,810 --> 00:59:56,112 这里面没有关于它的知识 There's nothing in there about that. 1053 00:59:57,930 --> 00:59:59,664 里面只能得到人类是不可靠的 What's in there is that humans are fallible. 1054 01:00:02,160 --> 01:00:04,128 它又如何知道宙斯不是不可靠的呢? How does it know that Zeus is not mortal? 1055 01:00:04,480 --> 01:00:05,936 这其中没有相关的规则 There's nothing in there about that. 1056 01:00:07,980 --> 01:00:11,008 它只是说 我没有这样的规则 It just said I don't have any rule, which-- 1057 01:00:11,680 --> 01:00:14,064 我只能通过某人是人类来推断出他是平凡的 see the only way I can deduce something's mortal is if it's human 1058 01:00:14,080 --> 01:00:15,680 这也是它所知道关于“平凡”的所有东西 and that's all it really knows about mortal. 1059 01:00:16,690 --> 01:00:19,856 然而 如果你还记得古典神话的话 And in fact, if you remember your classical mythology, 1060 01:00:19,872 --> 01:00:23,488 你就知道 古希腊众神是不平凡的 但都不可靠 you know that the Greek gods were not mortal but fallible. 1061 01:00:25,056 --> 01:00:28,656 所以 不能通过这些规则得到答案 So the answer is not in the rules there. 1062 01:00:30,850 --> 01:00:32,100 但它又为什么推导出这些呢? See, why does it deduce that? 1063 01:00:34,496 --> 01:00:38,320 显然 苏格拉底不会犯这类逻辑错误 See, Socrates would certainly not have made this error of logic. 1064 01:00:40,080 --> 01:00:42,672 在这门语言中 NOT并不是NOT What NOT means in this language is not NOT. 1065 01:00:43,370 --> 01:00:44,320 不是逻辑非运算 It's not the NOT of logic. 1066 01:00:44,930 --> 01:00:46,400 这门语言中 NOT表示的是 What NOT needs in this language is 1067 01:00:47,160 --> 01:00:49,960 不可以从数据库中推断出结果 not deducible from things in the database 1068 01:00:50,752 --> 01:00:53,344 而不是“非真” as opposed to not true. 1069 01:00:55,024 --> 01:00:56,304 完全是天壤之别 That's a very big difference. 1070 01:00:57,300 --> 01:00:58,640 很细微 但也很巨大 Subtle, but big. 1071 01:00:59,250 --> 01:01:00,272 因此 实际上 So, in fact, 1072 01:01:00,768 --> 01:01:03,920 如果什么都不知道 最好就说NOT this is perfectly happy to say not anything that it doesn't know about. 1073 01:01:04,680 --> 01:01:06,144 如果你问它 So if you ask it is it not true 1074 01:01:06,160 --> 01:01:07,830 宙斯是否喜欢巧克力冰激凌 that Zeus likes chocolate ice cream? 1075 01:01:07,856 --> 01:01:09,120 它会说 这个查询当然非真 It will say sure, it's not true. 1076 01:01:10,640 --> 01:01:12,512 这些事情它都不知道 Or anything else or anything it doesn't know about. 1077 01:01:12,592 --> 01:01:17,344 NOT表示:不能从你告知它的事实中推断出来 NOT means not deducible from the things you've told me. 1078 01:01:18,280 --> 01:01:22,448 换句话说 你要把“无法推断出” In a world where you're identifying not deducible 1079 01:01:22,656 --> 01:01:24,000 与“命题非真”区别开来 with, in fact, not true, 1080 01:01:24,416 --> 01:01:26,304 这被称作是“封闭世界假说” this is called the closed world assumption. 1081 01:01:37,376 --> 01:01:38,176 封闭世界假说 closed world assumption. 1082 01:01:38,200 --> 01:01:42,384 只要结论不能通过我所知道的知识推断出来 Anything that I cannot deduce from what I know 1083 01:01:43,500 --> 01:01:44,368 那么就不是真的 is not true, 1084 01:01:46,240 --> 01:01:48,010 对吧 如果我对X一无所知 Right? If I don't know anything about x, 1085 01:01:48,224 --> 01:01:49,216 那么X就非真 the x isn't true. 1086 01:01:49,290 --> 01:01:50,336 这相当危险 That's very dangerous. 1087 01:01:51,296 --> 01:01:52,448 首先 从逻辑学的角度来说 From a logical point of view, 1088 01:01:52,464 --> 01:01:53,760 它一点也说不通 first of all, it doesn't really makes sense. 1089 01:01:54,480 --> 01:01:56,336 因为如果我对X一无所知的话 Because if I don't know anything about x, 1090 01:01:58,384 --> 01:01:59,696 就说X非真 I'm willing to say not x. 1091 01:02:00,240 --> 01:02:03,328 但为什么不说“X非真”非真 But am I willing to say not not x? 1092 01:02:03,850 --> 01:02:05,664 当然 我也许对后面那个命题也一无所知 Well, sure, I don't know anything about that either maybe. 1093 01:02:06,470 --> 01:02:08,656 因此(NOT (NOT X))就没有必要与X一致 So not not x is not necessarily the same as x 1094 01:02:09,248 --> 01:02:10,944 等等等等 and so on and so on and so on, so 1095 01:02:11,712 --> 01:02:13,936 因此 这里面一定有某种“偏见” there's some sort of funny bias in there. 1096 01:02:15,970 --> 01:02:17,290 这相当有趣 So that's sort of funny. 1097 01:02:17,290 --> 01:02:18,096 第二点就是 The second thing, 1098 01:02:20,144 --> 01:02:24,128 如果你基于此 构建一个真正的推理程序 if you start building up real reasoning programs based on this, 1099 01:02:24,704 --> 01:02:26,112 想一想是多么地危险 think how dangerous that is. 1100 01:02:27,070 --> 01:02:32,000 你说我知道我可以推断出 You're saying I know I'm in a position 1101 01:02:32,224 --> 01:02:36,220 与这个问题有关的所有事情 to deduce everything true that's relevant to this problem. 1102 01:02:37,440 --> 01:02:40,784 因为在我推理机制的内部 I'm reasoning, and built into my reasoning mechanism 1103 01:02:41,232 --> 01:02:44,200 会认为所有与问题有关的知识 is the assumption that anything that I don't know 1104 01:02:44,240 --> 01:02:46,272 我都已经知道了 can't possibly be relevant to this problem. 1105 01:02:48,448 --> 01:02:53,040 有相当多的大型组织都像这样运作 对吧? Right? There are a lot of big organizations that work like that, right? 1106 01:02:53,168 --> 01:02:56,830 大多数公司的市场部门都是这样工作的。 Most corporate marketing divisions work like that. 1107 01:02:56,830 --> 01:02:59,120 你们也知道这样做的后果 You know the consequences to that. 1108 01:03:00,330 --> 01:03:03,456 因此 向这个大型逻辑推理系统 So it's very dangerous to start really 1109 01:03:03,840 --> 01:03:06,250 输入各种查询 根据输出继续工作 typing in these big logical implication systems 1110 01:03:07,056 --> 01:03:09,008 的做法相当危险 and going on what they say, 1111 01:03:09,024 --> 01:03:11,280 因为它们内建的假说非常地有限 because they have this really limiting assumption built in. 1112 01:03:12,600 --> 01:03:14,368 因此你对此需要非常非常地小心 So you have to be very, very careful about that. 1113 01:03:15,296 --> 01:03:16,288 就是这么一个深层次问题 And that's a deep problem. 1114 01:03:16,560 --> 01:03:17,824 这个问题并不是 That's not a problem about 1115 01:03:18,224 --> 01:03:20,144 通过构建更加聪明的实现 we can make a little bit cleverer implementation 1116 01:03:20,160 --> 01:03:21,856 或者通过组织无穷循环 and do the filters and organize the 1117 01:03:22,160 --> 01:03:23,840 以及过滤器就可以消除的 the infinite loops to make them go away. 1118 01:03:23,840 --> 01:03:25,088 这是完全不同的一类问题 It's a different kind of problem. 1119 01:03:25,920 --> 01:03:26,896 完全不同的语义 It's a different semantics. 1120 01:03:27,060 --> 01:03:30,512 我想该总结一下了 平心而论 So I think to wrap this up, it's fair to say 1121 01:03:31,344 --> 01:03:34,432 逻辑式程序设计是一个振奋人心的想法 that logic programming I think is a terrifically exciting idea, 1122 01:03:34,600 --> 01:03:37,008 这个想法使你能够弥合 the idea that you can bridge this 1123 01:03:37,040 --> 01:03:38,780 命令式与声明式语言的鸿沟 gap from the imperative to the declarative, 1124 01:03:39,900 --> 01:03:42,944 使得你可以谈论关系 that you can start talking about relations 1125 01:03:43,584 --> 01:03:45,088 从而获得惊人的力量 and really get tremendous power 1126 01:03:46,096 --> 01:03:49,488 让你超越输入和输出的抽象 by going above the abstraction of what's my input and what's my output. 1127 01:03:50,560 --> 01:03:51,536 而关于逻辑 And linked to logic, 1128 01:03:52,464 --> 01:03:56,464 我认为这个问题还尚未解决 the problem is it's a goal that I think has yet to be realized. 1129 01:03:58,032 --> 01:04:01,808 也许现在语言中最令人感兴趣的 And probably one of the very most interesting 1130 01:04:02,272 --> 01:04:04,416 研究问题之一就是 research questions going on now in languages 1131 01:04:04,672 --> 01:04:08,288 你该如何创建一门真正的逻辑语言? is how do you somehow make a real logic language? 1132 01:04:09,460 --> 01:04:11,056 其次 你如何从 And secondly, how do you bridge the gap 1133 01:04:11,312 --> 01:04:13,152 这个逻辑和关系的世界 this world of logic and relations 1134 01:04:13,520 --> 01:04:16,432 到更传统语言的世界之间 to the worlds of more traditional languages 1135 01:04:16,464 --> 01:04:17,984 架起桥梁并结合两者的力量 and somehow combine the power of both. 1136 01:04:18,880 --> 01:04:19,680 有什么问题吗? OK, let's break. 1137 01:04:23,290 --> 01:04:25,296 学生:你能够通过添加额外的规则 AUDIENCE: Couldn't you solve that last problem 1138 01:04:25,296 --> 01:04:27,740 来解决最后一个问题么? by having the extra rules that imply it? 1139 01:04:27,968 --> 01:04:29,856 这里的困境是:你有某物的定义 The problem here is you have the definition of something, 1140 01:04:29,888 --> 01:04:31,824 但没有它对立面的定义 but you don't have the definition of its opposite. 1141 01:04:32,080 --> 01:04:33,920 如果你在数据库中有 If you include in the database something that says 1142 01:04:34,144 --> 01:04:36,890 某些规则推导出(MORTAL X) uh... something implies mortal x, 1143 01:04:36,992 --> 01:04:38,704 另外一些规则推导出(NOT (MORTAL X)) something else implies not mortal x, 1144 01:04:38,752 --> 01:04:40,370 这不就基本上解决这个问题么? haven't you basically solved the problem? 1145 01:04:43,370 --> 01:04:44,144 教授:但问题就是 PROFESSOR: But the issue is 1146 01:04:44,752 --> 01:04:46,384 添加的这些规则是有穷个么? do you put a finite number of those in? 1147 01:04:48,656 --> 01:04:53,130 学生:如果你同时定义正、反两面 -- AUDIENCE: If things are specified always in pairs-- 1148 01:04:53,616 --> 01:04:57,072 教授:但问题就是 你该如何去做推断? PROFESSOR: But the question is then what do you do about deduction? 1149 01:05:00,200 --> 01:05:02,112 要知道 你不能直接定义命题的非 See, you can't specify NOTs. 1150 01:05:03,400 --> 01:05:04,768 而问题就在于 在大型系统中 But the problem is, in a big system, 1151 01:05:04,784 --> 01:05:07,960 可能含有无穷个数的东西 it turns out that might not be a finite number of things. 1152 01:05:12,820 --> 01:05:15,290 这其中有两个问题 There are also sort of two issues. 1153 01:05:15,290 --> 01:05:16,560 其一是可能有无穷项 Partly it might not be finite. 1154 01:05:16,690 --> 01:05:19,392 另外是因为可能不向你想的那样 Partly it might be that's not what you want. 1155 01:05:21,510 --> 01:05:24,528 一个极好的例子 就是连通性 So a good example would be suppose I want to do connectivity. 1156 01:05:25,120 --> 01:05:26,544 我想对连通性做推理 I want a reason about connectivity. 1157 01:05:28,050 --> 01:05:30,384 我会告诉你这有四个对象 And I'm going to tell you there's four things: 1158 01:05:30,400 --> 01:05:33,744 A、B、C和D a and b and c and d. 1159 01:05:35,480 --> 01:05:38,190 我会告诉你A和B相连 And I'll tell you a is connected to b 1160 01:05:38,640 --> 01:05:41,424 C和D相连 and c's connected to d. 1161 01:05:43,200 --> 01:05:44,800 然后我再告诉你A和D相连 And now I'll tell you is a connected to d? 1162 01:05:45,056 --> 01:05:46,032 就是这种情况 That's the question. 1163 01:05:46,780 --> 01:05:48,528 在这个例子中 There's an example where I would like 1164 01:05:48,704 --> 01:05:50,352 我就希望有“封闭世界假说”这样的东西 something like the closed world assumption. 1165 01:05:54,432 --> 01:05:55,664 这是个小玩具 That's a tiny toy, 1166 01:05:56,240 --> 01:05:58,304 但是很多时候 我都想说 but a lot of times, I want to be able to say something like 1167 01:05:58,480 --> 01:06:01,340 我没告诉你的事 都假设非真 anything that I haven't told you, assume is not true. 1168 01:06:04,260 --> 01:06:06,272 所以这并不是你显式地 So it's not as simple as you only want to put in 1169 01:06:06,272 --> 01:06:08,090 为所有命题定义否命题就可以解决的 explicit NOTs all over the place. 1170 01:06:09,470 --> 01:06:12,704 而是有些时候 你不清楚自己真正想要什么 It's that sometimes it really isn't clear what you even want. 1171 01:06:14,150 --> 01:06:17,920 同时定义原命题与否命题又太过于精细 That having to specify both everything and not everything is too precise, 1172 01:06:17,936 --> 01:06:20,000 这会使你陷入困境 and then you get down into problems there. 1173 01:06:20,960 --> 01:06:22,688 但还是有很多方法 But there are a lot of approaches that 1174 01:06:23,328 --> 01:06:25,936 显式地定义否命题 并基于此进行推理 you know, that explicitly put in NOTs and reason based on that. 1175 01:06:26,510 --> 01:06:27,664 这个想法非常好 So it's a very good idea. 1176 01:06:28,070 --> 01:06:31,456 只是在一些复杂的大型问题中 It's just that then it starts becoming a little cumbersome 1177 01:06:31,488 --> 01:06:33,490 这么做就变得有些笨重了 in the very large problems you'd like to use. 1178 01:06:43,460 --> 01:06:45,968 学生:有个论点 我不知道它和本节课的直接关系 AUDIENCE: I'm not sure how directly related to the argument this is, 1179 01:06:46,000 --> 01:06:47,984 但你想要表达的是 but one of your points was that 1180 01:06:48,496 --> 01:06:50,160 封闭世界假说的危害之一就是 one of the dangers of the closed world rule is 1181 01:06:50,192 --> 01:06:52,064 你永远不会真正了解那里的所有事物 you never really know all the things that are there. 1182 01:06:53,440 --> 01:06:55,328 你永远不会知道它们的每个部分 You never really know all the parts to it. 1183 01:06:55,872 --> 01:06:58,160 这难道不是任何一门程序设计语言的主要问题吗? Isn't that a major problem with any programming? 1184 01:06:58,160 --> 01:06:59,648 写程序时 我总是 I always write programs where I 1185 01:06:59,904 --> 01:07:01,568 假设我考虑了所有的情况 I assume that I've got all the cases, 1186 01:07:01,584 --> 01:07:03,408 然后我检查了每一种情况 and so I check for them all or whatever, and i 1187 01:07:04,060 --> 01:07:04,992 然而在某处 and somewhere down the road, I 1188 01:07:05,024 --> 01:07:06,520 我发现了我遗漏了其中的一个 I find out that I didn't check for one of them. 1189 01:07:07,390 --> 01:07:08,540 教授:你说得很对 PROFESSOR: Well, sure, it's true. 1190 01:07:08,540 --> 01:07:09,760 但这里的问题在于 But the problem here is 1191 01:07:11,968 --> 01:07:15,472 对于你所做的事情 it's that assumption which is the thing that you're making 1192 01:07:15,488 --> 01:07:17,344 你是否认为它是逻辑问题 if you believe you're identifying this with logic. 1193 01:07:19,600 --> 01:07:20,510 你说得非常正确 So you're quite right. 1194 01:07:20,510 --> 01:07:22,220 这是你永远不会遇到的情况 It's a situation you're never in. 1195 01:07:22,220 --> 01:07:24,140 问题在于 如果你认为 The problem is if you're starting to believe that 1196 01:07:24,176 --> 01:07:25,440 你在进行逻辑式程序设计 what this is doing is logic 1197 01:07:26,170 --> 01:07:27,328 然后审视你所编写的规则 and you look at the rules you write down 1198 01:07:27,344 --> 01:07:28,890 并思考能从中推断出什么 and say what can I deduce from them, 1199 01:07:29,536 --> 01:07:32,800 你就需要清醒地认识到NOT具有另外的意义 you have to be very careful to remember that NOT means something else. 1200 01:07:33,470 --> 01:07:35,216 它的意义基于某种假设 And it means something else based on an assumption 1201 01:07:35,248 --> 01:07:36,704 并且可能并不正确 which is probably not true. 1202 01:07:39,030 --> 01:07:40,192 学生:我不知道这样理解是否正确 AUDIENCE: Do I understand you correctly that 1203 01:07:40,256 --> 01:07:41,840 也就是我们无法通过改变NOT you cannot fix this problem 1204 01:07:42,256 --> 01:07:46,080 来消灭推断的所有可能性 从而解决这个问题? without killing off all possibilities of inference through altering NOT? 1205 01:07:46,544 --> 01:07:49,808 教授:不 并不是这样 PROFESSOR: No, that's not quite right. 1206 01:07:52,960 --> 01:07:55,088 有很多种方法可以实现真正的逻辑非 There are ways to do logic with real NOTs. 1207 01:07:56,340 --> 01:07:58,032 实际上有很多种方法 There are actually ways to do that. 1208 01:07:58,540 --> 01:08:00,848 但目前没有一个广为人知的高效算法 But they're very inefficient as far as anybody knows. 1209 01:08:01,610 --> 01:08:02,560 而且他们还-- And they're much more-- 1210 01:08:04,096 --> 01:08:06,896 这里所谓的“推论” they don't-- the, quote, inference in here 1211 01:08:07,390 --> 01:08:08,830 是建立在这个合一算法 is built into this unifier 1212 01:08:08,912 --> 01:08:11,296 以及模式匹配算法之中的 and this pattern matching unification algorithm. 1213 01:08:11,980 --> 01:08:16,192 有多种方法可以实现真正的逻辑推理 There are ways to automate real logical reasoning. 1214 01:08:16,590 --> 01:08:18,192 但它们并不基于此 But it's not based on that, 1215 01:08:18,510 --> 01:08:20,736 而逻辑式程序设计语言也不倾向于这么做 and logic programming languages don't tend to do that 1216 01:08:20,752 --> 01:08:23,850 因为大家都知道 那样做非常低效 because it's very inefficient as far as anybody knows. 1217 01:08:29,390 --> 01:08:30,032 好吧 下课 All right, thank you. 1218 01:08:30,030 --> 01:08:37,120 MIT OpenCourseWare http://ocw.mit.edu 1219 01:08:37,152 --> 01:08:42,688 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec9a.srt ================================================ 1 00:00:00,032 --> 00:00:02,048 Learning-SICP学习小组 倾情制作 2 00:00:02,040 --> 00:00:06,160 翻译&&时间轴:邓雄飞 压制&&特效:邓雄飞(Dysprosium) 校对:邓雄飞(Dysprosium) 3 00:00:06,160 --> 00:00:08,160 特别感谢:裘宗燕教授 4 00:00:08,160 --> 00:00:12,032 计算机程序的构造和解释 5 00:00:12,032 --> 00:00:14,030 寄存机器 Register Machines 6 00:00:17,260 --> 00:00:19,072 教授:我认为 到目前为止 PROFESSOR: Well, up 'til now, I suppose, 7 00:00:19,328 --> 00:00:23,936 我们已经学习了很多关于 we've been learning about a lot of techniques for 8 00:00:24,096 --> 00:00:28,830 组织程序以及操纵符号的技术 organizing big programs, symbolic manipulation a bit, 9 00:00:30,848 --> 00:00:35,600 以及用来构建语言的技术 some of the technology that you use for establishing languages, 10 00:00:35,630 --> 00:00:36,784 用一门语言去创建另一门语言 one in terms of another, 11 00:00:37,104 --> 00:00:39,920 这在组织大型程序时非常有用 which is used for organizing very large programs. 12 00:00:39,968 --> 00:00:42,304 实际上 我所知的最好的程序 In fact, the nicest programs I know 13 00:00:42,448 --> 00:00:44,432 看起来更像是一堆语言 look more like a pile of languages 14 00:00:44,912 --> 00:00:47,968 而不是将问题分解成若干部分 than like a decomposition of a problem into parts. 15 00:00:49,900 --> 00:00:51,456 我想 此时此刻 Well, I suppose at this point, 16 00:00:52,080 --> 00:00:53,584 关于这类东西的工作方式 there are still, however, a few mysteries 17 00:00:53,616 --> 00:00:55,328 仍然存在一些谜团 about how this sort of stuff works. 18 00:00:56,260 --> 00:00:59,680 因此 我现在需要 And so what we'd like to do now is 19 00:01:00,030 --> 00:01:02,608 偏离原先的计划 diverge from the plan of 20 00:01:02,960 --> 00:01:05,420 不再继续讲解如何组织大型程序 telling you how to organize big programs, 21 00:01:05,450 --> 00:01:08,192 而是告诉你一些关于 and rather tell you something about the mechanisms 22 00:01:08,528 --> 00:01:11,710 使这些事情可以起作用的机制 by which these things can be made to work. 23 00:01:12,190 --> 00:01:14,832 这样做的主要是为了 The main reason for this is 24 00:01:15,808 --> 00:01:17,870 揭秘 demystification, if you will, 25 00:01:18,656 --> 00:01:20,540 剩下的很多谜团 that we have a lot of mysteries left, 26 00:01:21,080 --> 00:01:25,488 比如说 如何控制程序的运行 like exactly how it is the case that a program is controlled, 27 00:01:26,080 --> 00:01:30,384 计算机如何知晓下一步的动作 how a computer knows what the next thing to do is, 28 00:01:30,528 --> 00:01:31,744 等等等等 or something like that. 29 00:01:32,430 --> 00:01:35,568 我现在就要让你们清楚地知道 And what I'd like to do now is make that clear to you 30 00:01:35,856 --> 00:01:39,104 就算你之前没有使用过计算机 that even if you've never played with a physical computer before, 31 00:01:39,568 --> 00:01:43,504 但这种机制非常简单 the mechanism is really very simple, 32 00:01:44,336 --> 00:01:46,352 你可以毫无问题地理解它 and that you can understand it completely with no trouble. 33 00:01:47,650 --> 00:01:51,248 好吧 我们先来想象一个 -- So I'd like to start by imagining that we-- 34 00:01:51,328 --> 00:01:52,912 先说明一下 我们采用的方法是 well, the way we're going to do this, by the way, 35 00:01:52,960 --> 00:01:55,808 把一些非常简单的Lisp程序 is we're going to take some very simple Lisp programs, 36 00:01:56,544 --> 00:01:58,128 真的非常简单 very simple Lisp programs, 37 00:01:59,040 --> 00:02:00,624 把它们转换成硬件 and transform them into hardware. 38 00:02:02,160 --> 00:02:04,160 我不会考虑一些中间步骤 I'm not going to worry about some intermediate step 39 00:02:04,700 --> 00:02:07,456 比如转换成某种现有的机器语言 of going through some existing computer machine language 40 00:02:07,472 --> 00:02:09,050 然后来解释计算机是如何工作的 and then showing you how that computer works, 41 00:02:09,824 --> 00:02:12,000 因为那不太明显 because that's not as illuminating. 42 00:02:12,750 --> 00:02:14,176 所以我真正要向你展示的是 So what I'm really going to show you 43 00:02:14,512 --> 00:02:17,488 如何构建一台机器来完成 is how a piece of machinery can be built 44 00:02:18,032 --> 00:02:22,040 一项由你写的程序所描述的工作 to do a job that you have written down as a program. 45 00:02:22,040 --> 00:02:24,032 而程序呢 实际上就是一个机器的描述 That program is, in fact, a description of a machine. 46 00:02:25,760 --> 00:02:27,696 我们从一个非常简单的程序开始 We're going to start with a very simple program, 47 00:02:28,096 --> 00:02:30,816 然后演示一些简单的机制 proceed to show you some simple mechanisms, 48 00:02:31,392 --> 00:02:33,680 进而用更复杂的程序 proceed to a few more complicated programs, 49 00:02:34,304 --> 00:02:37,420 然后又演示一个不那么复杂的程序 and then later show you a not very complicated program, 50 00:02:37,440 --> 00:02:41,230 来演示求值器是如何变成硬件的 how the evaluator transforms into a piece of hardware. 51 00:02:41,230 --> 00:02:42,064 当然 到那个时候 And of course at that point, 52 00:02:42,080 --> 00:02:44,080 你就有了通用的转换算法 you have made the universal transition 53 00:02:44,224 --> 00:02:46,880 并且可以用一个定义明确的硬件 and can execute any program imaginable 54 00:02:47,168 --> 00:02:48,800 来执行任何可以想象的程序 with a piece of well-defined hardware. 55 00:02:51,728 --> 00:02:52,912 那么 现在让我们开始 Well, let's start up now, 56 00:02:53,056 --> 00:02:55,312 给你们关于这些东西的具体感觉 give you a real concrete feeling for this sort of thing. 57 00:02:55,440 --> 00:02:57,664 我们先从一个非常简单的程序开始 Let's start with a very simple program. 58 00:02:59,600 --> 00:03:00,850 这是欧几里得算法 Here's Euclid's algorithm. 59 00:03:03,880 --> 00:03:07,008 它实际上比欧几里德算法更现代一些 It's actually a little bit more modern than Euclid's algorithm. 60 00:03:07,020 --> 00:03:10,096 我想 用来计算两数最大公约数的欧几里得算法 Euclid's algorithm for computing the greatest common divisor of two numbers 61 00:03:10,416 --> 00:03:13,600 是在公元前350年发明的 was invented 350 BC, I think. 62 00:03:14,300 --> 00:03:15,696 它是已知最古老的算法 It's the oldest known algorithm. 63 00:03:19,320 --> 00:03:23,344 我们先定义(GCD A B) But here we're going to talk about GCD of A and B, 64 00:03:23,360 --> 00:03:25,616 也就是用来计算A、B两数的最大公约数 the Greatest Common Divisor or two numbers, A and B. 65 00:03:26,208 --> 00:03:28,912 这个算法相当简单 And the algorithm is extremely simple. 66 00:03:29,500 --> 00:03:31,088 如果B等于0 If B is 0, 67 00:03:34,160 --> 00:03:36,832 那么结果就是A then the result is going to be A. 68 00:03:37,520 --> 00:03:43,616 否则结果就是 (GCD B Otherwise, the result is the GCD of B 69 00:03:44,496 --> 00:03:53,392 (REMAINDER A B)) and the remainder when A is divided by B. 70 00:03:58,530 --> 00:04:01,904 这里 我们定义了一个简单的迭代过程 So this we have here is a very simple iterative process. 71 00:04:02,030 --> 00:04:04,080 这是一个简单的递归过程 This a simple recursive procedure, 72 00:04:04,380 --> 00:04:07,536 也可以说这个过程是递归地定义的 recursively defined procedure, recursive definition, 73 00:04:07,712 --> 00:04:09,264 但它产生的计算过程是迭代的 which yields an iterative process. 74 00:04:09,952 --> 00:04:12,460 它的原理是 在每一步 And the way it works is that every step, 75 00:04:12,800 --> 00:04:15,104 判断B是否为0 it determines whether B was zero. 76 00:04:16,240 --> 00:04:18,800 如果B为0 那么A的值就是我们的答案 And if B is 0, we got the answer in A. 77 00:04:19,632 --> 00:04:22,464 否则就进入下一个步骤 Otherwise, we make another step 78 00:04:22,496 --> 00:04:23,872 其中A就变成旧的B where A is the old B, 79 00:04:23,888 --> 00:04:27,040 而B的值 是A旧值除B旧值的余数 and B is the remainder of the old A divided by the old B. 80 00:04:28,768 --> 00:04:29,552 非常简单 Very simple. 81 00:04:31,110 --> 00:04:32,720 现在 我已经通过这种方式 Now this, I've already told you 82 00:04:32,992 --> 00:04:34,860 告诉了你一些机制 some of the mechanism by just saying it that way. 83 00:04:34,860 --> 00:04:35,904 我是按时序告诉你们的 I said it in time. 84 00:04:36,360 --> 00:04:37,728 我说 其中有特定的步骤 I said there are certain steps, 85 00:04:38,144 --> 00:04:39,328 并且实际上 and that, in fact, 86 00:04:39,520 --> 00:04:40,864 你可以在这里知道 one of the things you can see here 87 00:04:41,184 --> 00:04:43,696 为什么这个过程是迭代的 is that one of the reasons why this is iterative 88 00:04:43,950 --> 00:04:47,680 是因为最后一步无需额外信息来得到答案 is nothing is needed of the last step to get the answer. 89 00:04:49,440 --> 00:04:55,290 所有运行此算法所需的信息都在A和B中 All of the information that's needed to run this algorithm is in A and B. 90 00:04:55,744 --> 00:04:57,808 它有两个定义明确的状态变量 It has two well-defined state variables. 91 00:05:00,470 --> 00:05:02,336 现在 我就要给你们定义一台机器 So I'm going to define a machine for you 92 00:05:03,984 --> 00:05:05,552 用来计算GCD can compute you GCDs. 93 00:05:06,560 --> 00:05:07,120 我们来看看 Now let's see. 94 00:05:07,120 --> 00:05:11,280 每台制造的计算机都是单进程计算机 Every computer that's ever been made that's a single-process computer, 95 00:05:11,800 --> 00:05:14,080 而不是某种多处理器 as opposed to a multiprocessor of some sort, 96 00:05:15,040 --> 00:05:16,592 都是按照相同的方案制定的 is made according to the same plan. 97 00:05:17,840 --> 00:05:19,536 这种方案就是:计算机由两部分组成 The plan is the computer has two parts, 98 00:05:20,576 --> 00:05:22,352 一部分叫数据通路 a part called the datapaths, 99 00:05:23,104 --> 00:05:24,368 而另一部分叫控制器 and a part called the controller. 100 00:05:25,910 --> 00:05:29,280 数据通路相当于你可能有的计算器 The datapaths correspond to a calculator that you might have. 101 00:05:29,712 --> 00:05:31,872 它有一些寄存器 能够存储数据 It contains certain registers that remember things, 102 00:05:31,904 --> 00:05:33,136 你们都用过计算器 and you've all used calculators. 103 00:05:33,560 --> 00:05:35,344 它上面有一些按钮和指示灯 It has some buttons on it and some lights. 104 00:05:37,030 --> 00:05:38,496 通过按下不同的按钮 And so by pushing the various buttons, 105 00:05:38,528 --> 00:05:41,344 你可以使操作在寄存器内发生 you can cause operations to happen inside there among the registers, 106 00:05:41,872 --> 00:05:43,488 并显示计算结果 and some of the results to be displayed. 107 00:05:45,160 --> 00:05:46,250 它是完全机械式的 That's completely mechanical. 108 00:05:46,250 --> 00:05:49,552 你可以认为那个盒子没有任何智能 You could imagine that box has no intelligence in it. 109 00:05:50,900 --> 00:05:53,280 它能计算一个数的正弦也许令人吃惊 Now it might be very impressive that it can produce the sine of a number, 110 00:05:53,536 --> 00:05:58,970 但它显然是机械式的 but that at least is apparently possibly mechanical. 111 00:05:58,970 --> 00:06:01,712 至少 我可以像打开GCD机器一样打开它 At least, I could open that up in the same way I'm about to open GCD. 112 00:06:02,690 --> 00:06:04,368 也就是说 它其中可能有一整台计算机 So this may have a whole computer inside of it, 113 00:06:04,688 --> 00:06:05,696 但这并不有趣 but that's not interesting. 114 00:06:05,940 --> 00:06:07,104 加法相当简单 Addition is certainly simple. 115 00:06:08,200 --> 00:06:09,840 不借助额外机制就可以完成 That can be done without any further mechanism. 116 00:06:10,890 --> 00:06:15,648 现在 如果我们来看另外的一部分:控制器 Now also, if we were to look at the other half, the controller, 117 00:06:15,936 --> 00:06:17,392 这一部分也非常简单 that's a part that's dumb, too. 118 00:06:18,190 --> 00:06:19,168 它负责按下按钮 It pushes the buttons. 119 00:06:20,350 --> 00:06:21,520 它根据指令序列来按按钮 It pushes them according to the sequence, 120 00:06:21,552 --> 00:06:22,848 指令是写在纸上的 which is written down on a piece of paper, 121 00:06:24,272 --> 00:06:25,648 控制器还会观察指示灯 and observes the lights. 122 00:06:26,290 --> 00:06:29,440 而且每隔一段 它就会来到指令序列中的一处 And every so often, it comes to a place in a sequence that says, 123 00:06:29,472 --> 00:06:32,370 如果指示灯A亮 则执行某段指令 if light A is on, do this sequence. 124 00:06:32,370 --> 00:06:33,856 否则执行另外的指令 Otherwise, do that sequence. 125 00:06:34,620 --> 00:06:37,456 因此 这其中也没有什么复杂的 And thereby, there's no complexity there either. 126 00:06:38,350 --> 00:06:39,328 那么 让我们来画一下 Well, let's just draw that 127 00:06:39,344 --> 00:06:40,570 然后来感受一下它 and see what we feel about that. 128 00:06:42,510 --> 00:06:44,848 为了计算GCD So for computing GCDs, 129 00:06:45,888 --> 00:06:49,520 你们要知道:这其中有一些寄存器 what I want you to think about is that there are these registers. 130 00:06:50,560 --> 00:06:53,024 这里 寄存器就是一个存储数值的地方 A register is a place where I store a number, in this case. 131 00:06:53,520 --> 00:06:54,656 这个寄存器存储的是A And this one's called a. 132 00:06:56,810 --> 00:06:58,700 而另外的这个存储的是B And then there's another one for storing b. 133 00:07:03,170 --> 00:07:05,456 现在我们来看看 有了这些寄存器后能做什么 Now we have to see what things we can do with these registers, 134 00:07:05,980 --> 00:07:08,736 至于你能利用它做什么 并不是很明显 and they're not entirely obvious what you can do with them. 135 00:07:09,840 --> 00:07:11,728 那么 我们必须看看需要用它们做什么 Well, we have to see what things we need to do with them. 136 00:07:11,824 --> 00:07:13,872 我们来看看尝试求解的问题 We're looking at the problem we're trying to solve. 137 00:07:14,030 --> 00:07:16,096 计算机设计的一个要点就是 One of the important things for designing a computer, 138 00:07:17,104 --> 00:07:19,584 我想大多数设计师都不会照做 which I think most designers don't do, 139 00:07:20,208 --> 00:07:21,888 也就是专注于待解的问题 is you stay the problem you want to solve 140 00:07:22,624 --> 00:07:25,180 然后使用你研究问题所学到的东西 and then use what you learn from studying the problem you want to solve 141 00:07:25,440 --> 00:07:27,280 把那些求解问题所需要的机制 to put in the mechanisms needed to solve it 142 00:07:27,530 --> 00:07:28,700 融入正在构建的计算机中 in the computer you're building, 143 00:07:28,816 --> 00:07:30,080 不多也不少 no more no less. 144 00:07:32,140 --> 00:07:33,968 现在 可能你所要解决的问题 Now it may be that the problem you're trying to solve 145 00:07:34,240 --> 00:07:35,408 是大家共有的问题 is everybody's problem, 146 00:07:36,060 --> 00:07:37,584 这种情况下你需要构建 in which case you have to build in a universal 147 00:07:37,600 --> 00:07:39,290 某种语言的通用解释器 interpreter of some language. 148 00:07:40,190 --> 00:07:42,320 但是你添加的机制不能比 But you shouldn't put any more in than required 149 00:07:42,352 --> 00:07:44,256 想构建的语言解释器的需求多 to build the universal interpreter of some language. 150 00:07:44,448 --> 00:07:45,856 这一点 我们稍后来讨论 We'll worry about that in a second. 151 00:07:47,232 --> 00:07:49,930 好了 让我们回到这里 OK, going back to here, let's see. 152 00:07:49,930 --> 00:07:51,248 我们必须能够做什么? What do we have to be able to do? 153 00:07:51,792 --> 00:07:54,144 首先 我们能把B的值赋给A Well, somehow, we have to be able to get B into A. 154 00:07:56,080 --> 00:07:59,600 我们要能够把B的旧值赋给A We have to be able to get the old value of B into the value of A. 155 00:08:00,380 --> 00:08:03,328 因此 我们需要某种能够让数据流通的“路径” So we have to have some path by which stuff can flow 156 00:08:03,344 --> 00:08:04,760 而不管数据具体是什么 whatever this information is, 157 00:08:05,376 --> 00:08:06,576 从B到A的通路 OK? from b to a. 158 00:08:07,390 --> 00:08:09,264 我箭头来指示 I'm going to draw that with by an arrow 159 00:08:09,520 --> 00:08:12,624 我们能够把B的值赋给A saying that it is possible to move the contents of b into a, 160 00:08:12,960 --> 00:08:14,576 从而替换A的旧值 replacing the value of a. 161 00:08:15,120 --> 00:08:16,736 当你按下这里的按钮后 And there's a little button here which you push 162 00:08:17,488 --> 00:08:18,560 就能够实现这个效果 which allows that to happen. 163 00:08:19,710 --> 00:08:20,784 这个按钮就在这里 That's what the little x is here. 164 00:08:23,070 --> 00:08:23,936 同样的 Now it's also the case 165 00:08:23,952 --> 00:08:26,288 我还需要能够计算A除B的余数 that I have to be able to compute the remainder of a and b. 166 00:08:27,000 --> 00:08:28,496 这可能混乱而又复杂 Now that may be a complicated mess. 167 00:08:28,860 --> 00:08:30,864 但另一方面 我会把它放到一个小盒子中 On the other hand, I'm going to make it a small box. 168 00:08:31,960 --> 00:08:33,920 如果有必要的话 我们可以打开那个盒子 If we have to, we may open up that box 169 00:08:34,128 --> 00:08:35,632 看看其中有些什么 and look inside and see what it is. 170 00:08:37,770 --> 00:08:39,168 这就是那个小盒子 So here, I'm going to have a little box, 171 00:08:39,200 --> 00:08:40,380 我这么来画它 which I'm going to draw this way, 172 00:08:43,168 --> 00:08:44,384 我把它叫做REM which we'll call the remainder. 173 00:08:46,440 --> 00:08:48,608 它接受A And it's going to take in a. 174 00:08:50,910 --> 00:08:52,160 同时也要接受B That's going to take in b. 175 00:08:54,370 --> 00:08:56,512 它有一个输出 And it's going to put out something, 176 00:08:58,896 --> 00:09:00,464 也就是A除以B的余数 the remainder of a divided by b. 177 00:09:02,290 --> 00:09:03,616 在这里 我们同样需要能够 Another thing we have to see here is 178 00:09:03,648 --> 00:09:06,060 判断B是否等于0 that we have to be able to test whether b is equal to 0. 179 00:09:08,000 --> 00:09:09,664 也就是说 总得有个东西 Well, that means somebody's got to be looking at-- 180 00:09:10,000 --> 00:09:12,304 去查询B的值 a thing that's looking at the value of b. 181 00:09:13,390 --> 00:09:14,400 这是一个指示灯 I have a light bulb here 182 00:09:15,856 --> 00:09:17,390 当B等于0时 它就会点亮 which lights up if b equals 0. 183 00:09:21,110 --> 00:09:22,016 它就是干这个的 That's its job. 184 00:09:24,030 --> 00:09:26,784 最后 因为我们希望 And finally, I suppose, because of the fact 185 00:09:26,960 --> 00:09:30,432 A的新值是B的旧值 that we want the new value of a to be the old value of b, 186 00:09:30,464 --> 00:09:34,416 同时B的新值是有关于A的 and simultaneously the new value of b to be something I've done with a, 187 00:09:35,280 --> 00:09:37,600 如果我打算让机器 and if I plan to make my machine 188 00:09:37,808 --> 00:09:39,744 一次只发生一件事 such that everything happens one at a time, 189 00:09:40,208 --> 00:09:41,408 一次执行一个动作 one motion at a time, 190 00:09:41,616 --> 00:09:43,424 并且我不能在一个寄存器中放两个数字 and I can't put two numbers in a register, 191 00:09:44,032 --> 00:09:46,300 那么进行互换时 必须有另外的地方放置一个数字 then I have to have another place to put one while I'm interchanging. 192 00:09:49,296 --> 00:09:49,600 对吧? OK? 193 00:09:50,000 --> 00:09:51,856 我不能同时交换两手的东西 I can't interchange the two things in my hands, 194 00:09:52,110 --> 00:09:53,728 除非我一手拿两个 unless I either put two in one hand 195 00:09:53,728 --> 00:09:55,130 然后从中取另外一个 and then pull it back the other way, 196 00:09:55,504 --> 00:09:56,912 或者我先放下一个 or unless I put one down, 197 00:09:57,024 --> 00:09:58,688 取得另一个后再像这样捡起来 pick it up, and put the other one, like that 198 00:09:59,648 --> 00:10:00,944 除非我是耍杂技的 unless I'm a juggler, 199 00:10:01,660 --> 00:10:03,500 当然正如大家所见 我并不是 which I'm not, as you can see, 200 00:10:04,656 --> 00:10:07,360 这种情况下 我就会遇到时序错误 in which case I have a possibility of timing errors. 201 00:10:08,850 --> 00:10:11,040 事实上 人们所做的许多类型的计算机设计 In fact, much of the type of computer design 202 00:10:11,072 --> 00:10:12,688 都遇到了时序错误 people do involves timing errors, 203 00:10:13,120 --> 00:10:15,008 或者潜在的时序错误 of some potential timing errors, 204 00:10:15,248 --> 00:10:16,432 我不太喜欢这种错误 which I don't much like. 205 00:10:17,340 --> 00:10:18,640 因此 出于这个原因 But. So for that reason, 206 00:10:18,688 --> 00:10:21,216 我需要有一个地方来放置 I have to have a place to put the third thing down 207 00:10:22,060 --> 00:10:23,296 其中的一个元素 the second one of them down. 208 00:10:23,410 --> 00:10:24,720 因此 这里有一个寄存器 So I have a place called t, 209 00:10:24,752 --> 00:10:26,840 用来存放临时值T which is a register just for temporary, t, 210 00:10:28,592 --> 00:10:29,632 上面有一个按钮 with a button on it. 211 00:10:30,470 --> 00:10:31,888 我会使用它的结果 And then I'll take the result of that, 212 00:10:31,904 --> 00:10:34,144 因为我需要把这个结果送入B since I have to take that and put into b, over here, 213 00:10:34,688 --> 00:10:36,736 我们会把结果像这样给送过来 we'll take the result of that and go like this, 214 00:10:38,416 --> 00:10:39,300 这里同样有一个按钮 and a button here. 215 00:10:42,430 --> 00:10:45,840 这就是GCD机器的数据通路 So that's the datapaths of a GCD machine. 216 00:10:47,600 --> 00:10:48,576 那么 控制器又是怎样的呢? Now what's the controller? 217 00:10:49,740 --> 00:10:51,280 控制器同样很简单 Controller's a very simple thing, too. 218 00:10:52,280 --> 00:10:53,264 机器具有状态 The machine has a state. 219 00:10:54,384 --> 00:10:57,728 我喜欢形象地把它们比作迷宫 The way I like to visualize that is that I've got a maze. 220 00:10:59,010 --> 00:11:03,200 这个迷宫的各处是通过直接的箭头连接的 And the maze has a bunch of places connected by directed arrows. 221 00:11:04,430 --> 00:11:05,600 而我有一颗弹珠 And what I have is a marble, 222 00:11:06,464 --> 00:11:09,072 它代表了控制器的状态 which represents the state of the controller. 223 00:11:10,740 --> 00:11:12,272 弹珠在迷宫中四处滚动 The marble rolls around in the maze. 224 00:11:13,744 --> 00:11:17,150 当然 这种类比因能量的原因而不成立 Of course, this analogy breaks down for energy reasons. 225 00:11:17,150 --> 00:11:19,088 有时我不得不将弹珠泵到顶部 I sometimes have to pump the marble up to the top, 226 00:11:19,120 --> 00:11:21,856 不然它就会成为一台永动机 because it's going to otherwise be a perpetual motion machine. 227 00:11:22,000 --> 00:11:23,328 但不用担心那么多 But not worrying about that, 228 00:11:23,904 --> 00:11:25,904 这并不是一个物理比喻 this is not a physical analogy. 229 00:11:26,080 --> 00:11:27,424 弹珠到处滚动 This marble rolls around. 230 00:11:27,680 --> 00:11:29,568 就像弹球机一样 And every time it rolls around certain bumpers, 231 00:11:29,680 --> 00:11:30,976 每次当它滚动到一些缓冲器时 like in a pinball machine, 232 00:11:31,264 --> 00:11:32,608 它就会按下这些按钮 it pushes one of these buttons. 233 00:11:34,830 --> 00:11:37,504 它也会经常来到一个分支区域 And every so often, it comes to a place, which is a division, 234 00:11:38,624 --> 00:11:39,680 它要在这里做选择 where it has to make a choice. 235 00:11:40,250 --> 00:11:42,360 然后有一个由这个组件控制的挡板 And there's a flap, which is controlled by this. 236 00:11:46,000 --> 00:11:48,820 所以这是一个非常机械化的思考方式 So that's a really mechanical way of thinking about it. 237 00:11:48,820 --> 00:11:51,056 当然 真实计算机中的控制器 Of course, controllers not these days, are not built that way 238 00:11:51,088 --> 00:11:51,840 并不是这样的 in real computers. 239 00:11:51,840 --> 00:11:56,016 而是由一些ROM和状态寄存器构成 They're built with a little bit of ROM and a state register. 240 00:11:56,610 --> 00:11:58,736 但曾几何时 像DEC、PDP-6这些个机器 But there was a time, like the DEC PDP-6, 241 00:11:59,296 --> 00:12:01,024 它们的控制器就是我们说的那样 where that's how you built the controller of a machine. 242 00:12:01,808 --> 00:12:03,616 延迟线上有一些比特信息 There was a bit that ran around the delay line, 243 00:12:05,696 --> 00:12:08,144 它随着时间的推移而触发事件 and it triggered things as it went by. 244 00:12:08,580 --> 00:12:10,704 然后回到开始并再次轮回 And it would come back to the beginning and get fed round again. 245 00:12:11,990 --> 00:12:13,728 当然 还有各种各样的错误 And of course, there were all sorts of great bugs you could have 246 00:12:13,744 --> 00:12:17,670 比如两个比特的信息 -- 对应两个弹珠 like two bits going around, two marbles. 247 00:12:17,670 --> 00:12:19,260 机器也会丢失弹珠 And then the machine has lost its marbles. 248 00:12:19,456 --> 00:12:20,208 这也会发生 That happens, too. 249 00:12:20,980 --> 00:12:21,584 好吧 Oh, well. 250 00:12:22,272 --> 00:12:24,224 无论如何 对于这台机器 So anyway, for this machine, 251 00:12:24,272 --> 00:12:25,488 我想要这么来做 what I have to do is the following. 252 00:12:25,808 --> 00:12:27,744 迷宫从这里开始 I'm going to start my maze here. 253 00:12:30,520 --> 00:12:32,736 我首先要做的是 And the first thing I've got to do, 254 00:12:33,760 --> 00:12:36,752 用一个你们非常熟悉的流程图记号 is in a notation which many of you are familiar with, 255 00:12:37,072 --> 00:12:39,856 这是一个判断:B是否为0 is b equal to zero, a test. 256 00:12:41,504 --> 00:12:43,790 如果判断为是的话 And there's a possibility, either yes, 257 00:12:43,936 --> 00:12:45,584 那我就做完了 in which case I'm done. 258 00:12:49,790 --> 00:12:51,264 否则的话 Otherwise, if no, 259 00:12:52,704 --> 00:12:54,320 我就不得不滚动一些缓冲器 then I'm going have to roll over some bumpers. 260 00:12:55,008 --> 00:12:56,464 按照下列顺序执行 I'm going to do it in the following order. 261 00:12:57,420 --> 00:13:03,408 我想向这样来做一个互换游戏 I want to, I want to do this interchange game. 262 00:13:04,050 --> 00:13:05,808 首先 因为我需要A和B Now first, since I need both a and b, 263 00:13:06,320 --> 00:13:08,576 但首先 -- 虽然并不是必要的 but then the first-- and this is not necessary-- 264 00:13:08,656 --> 00:13:09,728 我需要先把它们收集起来 I want to collect this. 265 00:13:11,070 --> 00:13:12,624 这里的值要送入到B中 This is the thing that's going to go into b. 266 00:13:13,240 --> 00:13:14,032 因此 我会说 So I'm going to say, 267 00:13:14,288 --> 00:13:16,272 用A和B的值来计算这个 take this, which depends upon both a and b, 268 00:13:16,368 --> 00:13:18,672 并把算得的余数放到这里 and put the remainder into here. 269 00:13:19,150 --> 00:13:20,336 因此 我首先要按下这个按钮 So I'm going to push this button first. 270 00:13:21,536 --> 00:13:24,432 然后我要把B的值送入A Then, I'm going to transfer b to a, 271 00:13:24,448 --> 00:13:25,600 通过按这个钮来实现 push that button, 272 00:13:25,824 --> 00:13:27,632 然后我再把临时值送入B and then I transfer the temporary into b, 273 00:13:28,768 --> 00:13:29,424 通过这个按钮实现 push that button. 274 00:13:32,030 --> 00:13:34,970 这是一个相当时序化的机器 So a very sequential machine, 275 00:13:35,392 --> 00:13:36,528 它非常的低效 it's very inefficient. 276 00:13:37,750 --> 00:13:39,056 但目前来说还好 But that's fine right now. 277 00:13:39,810 --> 00:13:40,970 我们来为按钮命名 We're going to name the buttons, 278 00:13:41,472 --> 00:13:42,720 T←R t gets remainder. 279 00:13:46,750 --> 00:13:48,736 A←B a gets b. 280 00:13:50,030 --> 00:13:54,816 B←T And b gets t. 281 00:13:55,470 --> 00:13:57,632 然后我要来到这里 And then I'm going to go around here 282 00:13:58,784 --> 00:13:59,888 也就是回到开始的地方 and it's to go back to start. 283 00:14:01,620 --> 00:14:03,870 在这里 我们看到了什么? And if you look, what are we seeing here? 284 00:14:03,870 --> 00:14:04,912 我们看到各种各样的 -- We're seeing the various-- 285 00:14:05,056 --> 00:14:07,168 我们真正拥有的是某种机械连接 what I really have is some sort of mechanical connection, 286 00:14:07,424 --> 00:14:13,632 其中T←R控制了这个东西 where t gets r controls this thing. 287 00:14:16,830 --> 00:14:21,488 A←B控制了这个东西 And I have here that a gets b controls this fellow over here, 288 00:14:26,960 --> 00:14:28,120 而这里的这个东西 and this fellow over here. 289 00:14:28,120 --> 00:14:31,088 同学们 这简直太恶劣了 Boy, that's absolutely pessimal, 290 00:14:31,488 --> 00:14:32,480 一点也没有优化 the inverse of optimal. 291 00:14:32,630 --> 00:14:34,590 我画的所有线条都相互交叉 Every line heads across every other line the way I drew it. 292 00:14:38,540 --> 00:14:41,150 我想B←T控制的是这个 I suppose this goes here, b gets t. 293 00:14:45,690 --> 00:14:47,952 现在 我就要运行这台机器了 Now I'd like to run this machine. 294 00:14:48,040 --> 00:14:49,344 但是在我运行它之前 But before I run the machine, 295 00:14:49,376 --> 00:14:51,408 我想写下它的控制器的描述 I want to write down a description of this controller, 296 00:14:51,630 --> 00:14:52,816 以便使你们相信 just so you can see that these things, 297 00:14:52,848 --> 00:14:55,632 这些东西可以组织成某种良好的语言 of course, as usual, can be written down in some nice language, 298 00:14:56,080 --> 00:14:58,080 这样我们就不必总是像这样画图 so that we don't have to always draw these diagrams. 299 00:14:58,368 --> 00:15:00,688 图示的缺陷之一 就是占用了太多空间 One of the problems with diagrams is that they take up a lot of space. 300 00:15:00,896 --> 00:15:01,980 对于这样的一个小型机器来说 And for a machine this small, 301 00:15:02,000 --> 00:15:03,056 它占用了两块黑板 it takes two blackboards. 302 00:15:03,220 --> 00:15:05,248 而一台求值器机器 For a machine that's the evaluator machine, 303 00:15:05,408 --> 00:15:07,104 我就很难将它画在这间屋子里了 I have trouble putting it into this room, 304 00:15:07,952 --> 00:15:09,168 尽管它还不是非常大 even though it isn't very big. 305 00:15:09,900 --> 00:15:11,280 因此我要为它构造一门小型语言 So I'm going to make a little language for this 306 00:15:11,296 --> 00:15:12,512 用来描述这个机器 that's just a description of that, 307 00:15:13,104 --> 00:15:23,296 (DEFIME-MACHINE GCD saying define a machine we'll call GCD. 308 00:15:24,420 --> 00:15:25,664 当然 一旦我们有了像这样的描述 Of course, once we have something like this, 309 00:15:25,680 --> 00:15:26,832 我们就能够模拟该机器 we have a simulator for it. 310 00:15:27,220 --> 00:15:29,424 我之所以想构建这种形式的语言 And the reason why we want to build a language in this form, 311 00:15:29,568 --> 00:15:32,944 是因为我们能够立即操纵这些表达式 is because all of a sudden we can manipulate these expressions that I'm writing down. 312 00:15:33,210 --> 00:15:34,912 因此 我也就能够 And then of course I can write things I can 313 00:15:35,290 --> 00:15:38,160 代数地操作 或者模拟这些东西 algebraically manipulate these things, simulate them 314 00:15:38,208 --> 00:15:39,968 以及各种各样我想进行的操作 all that sort of things that I might want to do, 315 00:15:40,128 --> 00:15:42,592 或者还可以把它们转换成布局图 谁知道呢? perhaps transform them as a layout, who knows. 316 00:15:43,630 --> 00:15:48,384 一旦我有了寄存器的良好表示 Once I have a nice representation of registers, 317 00:15:48,510 --> 00:15:49,616 它有一些寄存器 it has certain registers, 318 00:15:53,008 --> 00:15:55,640 记作(REGISTERS A B T) which we can call A, B, and T. 319 00:15:56,752 --> 00:15:57,808 它还有控制器 And there's a controller. 320 00:16:02,190 --> 00:16:04,464 实际上 更好的做法是让它更显式一些 Actually, a better language, which would be more explicit, 321 00:16:04,496 --> 00:16:06,976 也就是说 为每一个按钮命名 would be one which named every button 322 00:16:08,144 --> 00:16:10,176 并指明它们的操作 also and said what it did. 323 00:16:10,420 --> 00:16:11,376 比如说这个按钮 Like, this button 324 00:16:11,552 --> 00:16:14,190 会让T的值送入到B中 causes the contents of T to go to the contents of B. 325 00:16:15,100 --> 00:16:16,096 但我却不想这么做 Well I don't want to do that, 326 00:16:16,112 --> 00:16:17,952 因为这样会让代码难以阅读 because it's actually harder to read to do that, 327 00:16:18,208 --> 00:16:19,344 也会占用更多空间 and it takes up more space. 328 00:16:19,510 --> 00:16:22,368 所以我会把相关的指令写在控制器中 So I'm going to have that in the instructions written in the controller. 329 00:16:23,290 --> 00:16:25,248 这样就隐式地指明了具体的操作 It's going to be implicit what the operations are. 330 00:16:26,320 --> 00:16:28,576 可以通过阅读代码推断出来 They can be deduced by reading these 331 00:16:29,168 --> 00:16:31,392 并收集所有可以完成的不同事情 and collecting together all the different things that can be done. 332 00:16:31,696 --> 00:16:33,500 我们来看一看 We look and see, see... 333 00:16:33,500 --> 00:16:34,704 我们来看下这些东西是什么吧 Well, let's just look at what these things are. 334 00:16:35,712 --> 00:16:37,296 首先是一个循环 There's a little loop that we go around 335 00:16:38,240 --> 00:16:40,208 先是一条分支指令 which says branch, 336 00:16:42,640 --> 00:16:46,464 这个就对应了机器中的小挡板 this is the representation of the little flap 337 00:16:46,896 --> 00:16:48,496 它决定了你在此处的走向 that decides which way you go here, 338 00:16:49,104 --> 00:16:58,000 判断 -- 取B的值 并判断是否为0 if 0, OK, fetch of B, the contents of B, 339 00:16:58,650 --> 00:17:00,064 如果B的值是0 and if the contents of B is 0, 340 00:17:00,320 --> 00:17:01,720 那么就跳转到一个叫DONE的地方 then go to a place called done. 341 00:17:03,640 --> 00:17:05,296 现在 你们在这里看到的是 Now, one thing you're seeing here, 342 00:17:05,296 --> 00:17:07,400 这个看起来非常像传统计算机语言 this looks very much like a traditional computer language. 343 00:17:08,170 --> 00:17:09,552 但你们所见的是 And what you're seeing here 344 00:17:10,032 --> 00:17:12,000 一些个标签 is things like labels 345 00:17:12,992 --> 00:17:16,864 它们代表着存放了一系列指令的地方 that represent places in a sequence written down as a sequence. 346 00:17:17,600 --> 00:17:18,944 之所以需要它们 The reason why they're needed 347 00:17:19,488 --> 00:17:21,152 是因为在这里 is because over here, 348 00:17:21,456 --> 00:17:22,816 我表达了“循环”的概念 I've written something with loops. 349 00:17:23,320 --> 00:17:26,112 但是如果我是在写英文之类的文本 But if I'm writing English text, or something like that, 350 00:17:26,448 --> 00:17:28,096 就很难去引用一个位置 it's hard to refer to a place. 351 00:17:28,580 --> 00:17:29,536 我没有箭头 I don't have arrows. 352 00:17:30,800 --> 00:17:33,024 箭头是通过 Arrows are represented by giving names 353 00:17:33,056 --> 00:17:34,440 给箭头所指的地方命名来表示的 to the places where the arrows terminate, 354 00:17:34,576 --> 00:17:36,288 并通过名字来引用 and then referring to them by those names. 355 00:17:37,408 --> 00:17:38,592 这只是一种编码 Now this is just an encoding. 356 00:17:39,860 --> 00:17:41,888 而不是某种魔法 There's nothing magical about things like that. 357 00:17:43,150 --> 00:17:44,960 接下来我们要做的是 Next thing we're going to do is we're going to say, 358 00:17:45,024 --> 00:17:46,840 我们如何来实现T←R how do we do T gets R? 359 00:17:47,450 --> 00:17:49,760 非常简单 用ASSIGN Oh, that's easy enough, assign. 360 00:17:52,192 --> 00:17:55,552 我们把余数赋值给T We assign to T the remainder. 361 00:17:56,320 --> 00:17:59,248 ASSIGN就是按钮的名字 Assign is the name of the button. 362 00:18:01,470 --> 00:18:02,640 就是按按钮的家伙 That's the button-pusher. 363 00:18:03,140 --> 00:18:04,976 把余数赋给T Assign to T the remainder, 364 00:18:04,992 --> 00:18:06,768 这个操作是这样表示的 and here's the representation of the operation, 365 00:18:11,744 --> 00:18:17,536 取A、B的值 相除得到余数 when we divide the fetch of A by the fetch of B. 366 00:18:23,856 --> 00:18:30,992 同时 我们也要取B的值 赋给A And we're also going to assign to A the fetch of B, 367 00:18:34,990 --> 00:18:47,888 再取T的值赋给B assign to B the result of getting the contents of T. 368 00:18:49,616 --> 00:18:51,856 现在 我需要引用这个开头 And now I have to refer to the beginning here. 369 00:18:53,184 --> 00:18:55,920 呃 我为什么不把这里叫做LOOP呢? I see, why don't I call that loop like I have here? 370 00:19:04,096 --> 00:19:07,040 这就是如何引用这个箭头 OK? So that's that reference to that arrow. 371 00:19:07,610 --> 00:19:08,950 当执行到DONE时 就完成了所有操作 And when we're done, we're done. 372 00:19:09,024 --> 00:19:13,072 我们来到了这里 所有指令的结尾 We go to here, which is the end of the thing. 373 00:19:15,260 --> 00:19:17,040 这段文字化描述的就是 So here's just a written representation 374 00:19:17,696 --> 00:19:20,860 我们在这里画的一小部分机器 of this fragment of machinery that we've drawn here. 375 00:19:21,660 --> 00:19:24,848 下面 我就要运行它 Now the next thing I'd like to do is run this. 376 00:19:25,490 --> 00:19:26,656 我想让你们感受一下它的运行 I want us to feel it running. 377 00:19:27,620 --> 00:19:29,808 从来没有做过这个 你必须做一次 Never done this before, you got to do it once. 378 00:19:31,010 --> 00:19:32,624 让我们以一个具体的问题来演示 So let's take a particular problem. 379 00:19:33,100 --> 00:19:34,704 假设我们想要计算 Suppose we want to compute the GCD 380 00:19:35,040 --> 00:19:40,680 30和42的最大公约数 of a equals 30 and b equals 42. 381 00:19:42,210 --> 00:19:44,928 我现在不知道结果是多少 I have no idea what that is right now. 382 00:19:45,860 --> 00:19:47,600 但我知道A=30而B=42 But a 30 and b is 42. 383 00:19:50,960 --> 00:19:52,096 我就这么着开始 So that's how I start this thing up. 384 00:19:52,608 --> 00:19:53,904 那么 我首先要做些什么呢? Well, what's the first thing I do? 385 00:19:54,240 --> 00:19:56,864 我先判断B是否为0:否 I say is B equal to 0, no. 386 00:19:57,590 --> 00:20:02,112 然后计算A除B的余数 并赋给T Then assign to T the remainder of the fetch of A and the fetch of B. 387 00:20:02,800 --> 00:20:07,600 当然 30除以42的余数就是30自己 Well the remainder of 30 when divided by 42 is itself 30. 388 00:20:11,130 --> 00:20:12,032 按下那个按钮 Push that button. 389 00:20:12,920 --> 00:20:15,104 现在弹珠就滚动到了这里 Now the marble has rolled to here. 390 00:20:17,100 --> 00:20:18,064 A←B A gets B. 391 00:20:19,024 --> 00:20:20,768 又按下了这个按钮 That pushes this button. 392 00:20:21,220 --> 00:20:22,544 因此42来到了这里 So 42 moves into here. 393 00:20:26,592 --> 00:20:27,600 B←T B gets T. 394 00:20:28,368 --> 00:20:29,344 按下了这个按钮 Push that button. 395 00:20:29,870 --> 00:20:30,960 30来到了这里 The 30 goes here. 396 00:20:32,576 --> 00:20:33,696 这样我就交换了它们 Let met just interchange them. 397 00:20:34,660 --> 00:20:38,272 我们再来看看 回到开始 Now let's see, go back to the beginning. 398 00:20:38,640 --> 00:20:39,728 B为0么?不 B 0, no. 399 00:20:40,192 --> 00:20:41,504 将余数赋给T T gets the remainder. 400 00:20:43,230 --> 00:20:46,304 我想 42除以30的余数是12 I suppose the remainder when dividing 42 by 30 is 12. 401 00:20:47,240 --> 00:20:48,304 按下这个钮 I push that one. 402 00:20:48,530 --> 00:20:51,408 下面 我想让30来到这里 Next thing I do is allow the 30 to go to here, 403 00:20:53,904 --> 00:20:55,950 按下这个钮 让12来到这里 push this one, allow the 12 to go to here. 404 00:20:58,416 --> 00:21:00,380 然后继续 OK? Go around this thing. 405 00:21:00,380 --> 00:21:01,312 程序执行完了么? Is that done? 406 00:21:01,530 --> 00:21:02,128 并没有 No. 407 00:21:02,360 --> 00:21:08,224 现在 我需要求解30除以12的余数 How about-- so now I have to find out the remainder of 30 divided by 12. 408 00:21:08,850 --> 00:21:10,672 我想答案是6 And I believe that's 6. 409 00:21:12,420 --> 00:21:15,136 按下这个钮 6就到了这里 So 6 goes here on this button push. 410 00:21:16,208 --> 00:21:18,256 然后我又按下这个钮 Then the next thing I push is this one, 411 00:21:18,304 --> 00:21:19,616 这就让12来到了这里 which the 12 goes into here. 412 00:21:23,730 --> 00:21:25,090 然后我又按下这个按钮 Then I push this button. 413 00:21:25,090 --> 00:21:26,000 6就来到了这里 The 6 gets into here. 414 00:21:29,850 --> 00:21:31,680 6等于0么? Is 6 equal to 0? 415 00:21:31,888 --> 00:21:32,496 不等于 No. 416 00:21:33,420 --> 00:21:33,984 好的 OK. 417 00:21:34,380 --> 00:21:36,800 因此这时 So then at that point, 418 00:21:36,890 --> 00:21:38,128 接下来又要计算余数 the next thing to do is divide it. 419 00:21:38,144 --> 00:21:39,808 哦 这个的余数是0 Ooh, this has got a remainder of 0. 420 00:21:40,660 --> 00:21:41,744 看起来我们就快完成了 Looks like we're almost done. 421 00:21:42,360 --> 00:21:44,360 将6从这里挪到这里 Move the 6 over here next. 422 00:21:47,008 --> 00:21:48,272 0移动到这里 0 over here. 423 00:21:49,090 --> 00:21:50,200 0等于0么? Is the answer 0? 424 00:21:50,200 --> 00:21:50,736 是的 Yes. 425 00:21:51,340 --> 00:21:53,360 B的值等于0 因此答案就是A的值 B is 0, therefore the answer is in A. 426 00:21:54,288 --> 00:21:55,760 因此答案就是6 The answer is 6. 427 00:21:56,610 --> 00:21:57,616 这确实是正确的答案 And indeed that's right, 428 00:21:57,632 --> 00:21:59,472 因为如果我们回过头审视最初的问题 because if we look at the original problem, 429 00:22:00,080 --> 00:22:06,640 我们知道30=2×3×5 what we have is 30 is 2 times 3 times 5, 430 00:22:07,008 --> 00:22:11,120 42=2×3×7 and 42 is 2 times 3 times 7. 431 00:22:11,670 --> 00:22:14,112 因此最大公约数就是2×3 So the greatest common divisor is 2 times 3, 432 00:22:14,208 --> 00:22:15,088 也就是6 which is 6. 433 00:22:18,380 --> 00:22:20,560 我们通常在这里画另外一条线 Now normally, we write one other little line here, 434 00:22:20,592 --> 00:22:22,528 为了使它更清晰一点 just to make it a little bit clearer, 435 00:22:22,896 --> 00:22:27,712 在这两者之间建立了联系 which is that we leave in a connection saying 436 00:22:27,856 --> 00:22:31,010 小挡板需要根据这个指示灯来工作 that this light is the guy that that flap looks at. 437 00:22:34,000 --> 00:22:37,328 当然 跟我给你们展示的东西相比 Of course, any real machine has a lot more 438 00:22:37,856 --> 00:22:40,000 真实计算机的组件更加复杂 complicated things in it than what I've just shown you. 439 00:22:41,350 --> 00:22:47,168 让我们来看看第一张幻灯片 Let's look for a second at the first still store. 440 00:22:47,980 --> 00:22:48,816 哇 Wow. 441 00:22:50,190 --> 00:22:52,432 我们看到 我们想要做的就是 Well you see, for example, one thing we might want to do 442 00:22:52,656 --> 00:22:55,856 IO形式的操作 is worry about the operations that are of IO form. 443 00:22:56,840 --> 00:23:01,424 我们需要从外部搜集一些东西 And we may have to collect something from the outside. 444 00:23:01,980 --> 00:23:03,936 因此 对我们的状态机器来说 So a state machine that we might have, 445 00:23:04,300 --> 00:23:07,024 它们的控制器 the controller may have to, 446 00:23:07,264 --> 00:23:10,560 可能会从某处取得某值 may have to, for example, get a value from something 447 00:23:10,784 --> 00:23:12,416 将它们放入寄存器并从中读取 and put register a to load it up. 448 00:23:13,490 --> 00:23:15,920 我还可以把另外的值加载到寄存器B中 I have to master load up register b with another value. 449 00:23:17,070 --> 00:23:18,608 稍后 当执行完毕后 And then later, when I'm done, 450 00:23:18,992 --> 00:23:20,528 我想要输出结果 I might want to print the answer out. 451 00:23:21,200 --> 00:23:25,232 当然 答案或简单或复杂 And of course, that might be either simple or complicated. 452 00:23:26,090 --> 00:23:28,032 我写代码的时候 总假设PRINT很简单 I'm writing, assuming print is very simple, 453 00:23:28,096 --> 00:23:29,296 READ也很简单 and read is very simple. 454 00:23:29,880 --> 00:23:31,088 但实际上 在真实世界中 But in fact, in the real world, 455 00:23:31,120 --> 00:23:32,896 这些都是非常复杂的操作 those are very complicated operations, 456 00:23:33,080 --> 00:23:35,520 跟你尝试求解的问题相比 fairly, usually much, much larger and more complicated 457 00:23:35,552 --> 00:23:38,330 它们通常更加庞大而复杂 than the thing you're doing as your problem you're trying to solve. 458 00:23:41,670 --> 00:23:43,904 另一方面 我犹记得 On the other hand, I can remember a time when, 459 00:23:44,896 --> 00:23:48,784 使用IBM 7090一类的计算机的时候 I remember using IBM 7090 computer of sorts, 460 00:23:49,056 --> 00:23:53,040 它的READ和WRITE只能操作单个对象 where things like read and write of a single object, 461 00:23:53,088 --> 00:23:54,624 也就是一个数字 a single number, a number, 462 00:23:55,840 --> 00:23:58,544 这就是一个基本的IO操作 is a primitive operation of the IO controller. 463 00:23:59,632 --> 00:24:02,048 我们这里有同样的操作 OK? And so we have that kind of thing in there. 464 00:24:02,330 --> 00:24:04,672 在这样的一台机器中 And in such a machine, 465 00:24:05,440 --> 00:24:06,896 我们实际上在做什么? well, what are we really doing? 466 00:24:07,120 --> 00:24:11,600 我们看到 这个叫做“READ”的组件是数据源头 We're just saying that there's a source over here called "read" 467 00:24:12,208 --> 00:24:14,464 这个操作总是返回一个值 which is an operation which always has a value. 468 00:24:14,660 --> 00:24:17,136 我们可以把它看做 总是返回一个值 We have to think about this as always having a value 469 00:24:17,216 --> 00:24:19,840 它可以赋给寄存器A或B which can be gated into either register a or b. 470 00:24:21,660 --> 00:24:23,232 而PRINT这个过程呢 And print is some sort of thing 471 00:24:23,376 --> 00:24:25,024 当你正确连接它的时候 which when you gate it appropriately, 472 00:24:25,248 --> 00:24:26,432 当你按下上面的按钮 when you push the button on it, 473 00:24:26,656 --> 00:24:29,616 就会打印出当前寄存器A中的值 will cause a print of the value that's currently in register a. 474 00:24:31,660 --> 00:24:32,736 这非常普通 Nothing very exciting. 475 00:24:33,328 --> 00:24:35,200 这是我们想要的一种功能 So that's one sort of thing you might want to have. 476 00:24:35,888 --> 00:24:38,320 但这里还有些其它事情需要我们担忧 But these are also other things that are a little bit worrisome. 477 00:24:38,320 --> 00:24:40,672 比如说 这里我使用了一些复杂的机制 Like I've used here some complicated mechanisms. 478 00:24:41,050 --> 00:24:42,480 我们这里有REMAINDER组件 What you see here is remainder. 479 00:24:43,850 --> 00:24:44,448 这是个什么东西呢? What is that? 480 00:24:44,690 --> 00:24:46,416 求取余数的计算过程并不是那么“显然” That may not be so obvious how to compute. 481 00:24:46,920 --> 00:24:48,928 如果我们把这个组件给拆开 It may be something which when you open it up, 482 00:24:49,488 --> 00:24:50,624 就会得到一整台机器 you get a whole machine. 483 00:24:51,840 --> 00:24:53,664 事实就是这样的 OK? In fact, that's true. 484 00:24:54,540 --> 00:24:59,152 举例来说 如果要编程实现REMAINDER For example, if I write down the program for remainder, 485 00:24:59,440 --> 00:25:02,440 最简单的算法就是 不断地做减法 the simplest program for it is by repeated subtraction. 486 00:25:04,780 --> 00:25:05,952 这是因为 除法可以通过 Because of course, division can be done 487 00:25:05,968 --> 00:25:08,990 对整数不断做减法来实现 by repeated subtraction of numbers, of integers. 488 00:25:09,800 --> 00:25:23,584 N除以D的余数不外乎就是 So the remainder of N divided by D 489 00:25:24,992 --> 00:25:31,440 如果N小于D的话 is nothing more than if N is less than D, 490 00:25:32,240 --> 00:25:33,664 答案就是N then the result is N. 491 00:25:34,304 --> 00:25:35,904 否则的话就是 Otherwise, it's the remainder 492 00:25:41,150 --> 00:25:47,600 N先减去D when we subtract D from N with respect to D, 493 00:25:48,272 --> 00:25:49,328 再除以D的余数 when divided by D. 494 00:25:51,280 --> 00:25:55,056 天啊 这个看起来就像是GCD程序 Gee, this looks just like the GCD program. 495 00:25:56,890 --> 00:25:59,488 当然 这个不是求余数的最优算法 Of course, it's not a very nice way to do remainders. 496 00:25:59,750 --> 00:26:00,912 在实际中 你应该使用那些 You'd really want to use something like 497 00:26:00,920 --> 00:26:05,424 二进制运算、移位运算等操作 binary notation and shift and things like that in a practical computer. 498 00:26:05,550 --> 00:26:06,976 但关键点就是 But the point of that is 499 00:26:07,136 --> 00:26:08,480 如果我把这些组件打开 that if I open this thing up, 500 00:26:08,928 --> 00:26:10,640 我可能会发现其中有一台计算机 I might find inside of it a computer. 501 00:26:11,880 --> 00:26:12,992 现在我们就知道它的原理了 Oh, we know how to do that. 502 00:26:13,510 --> 00:26:14,336 因为我们就造过一台 We just made one. 503 00:26:15,640 --> 00:26:17,104 这些个机器都大同小异 And it could be another thing just like this. 504 00:26:17,400 --> 00:26:18,064 另外一方面 On the other hand, 505 00:26:18,080 --> 00:26:20,000 我们可能想要构建一台更高效 we might want to make a more efficient 506 00:26:20,016 --> 00:26:21,680 组织更精良的机器 or better-structured machine, 507 00:26:21,850 --> 00:26:23,968 比如说 多次利用其中的寄存器 or maybe make use of some of the registers more than once, 508 00:26:24,000 --> 00:26:27,050 或者是硬件设计者能想到的其它可怕混乱 or some horrible mess like that that hardware designers like to do, 509 00:26:27,312 --> 00:26:28,608 等等原因 and for very good reasons. 510 00:26:29,250 --> 00:26:31,568 比如说 你们所见的这台机器 So for example, here's a machine that you see, 511 00:26:32,528 --> 00:26:34,912 不是让你们去细读它的结构的 which you're not supposed to be able to read. 512 00:26:35,050 --> 00:26:37,520 它有些复杂 对吧? It's a little bit complicated. OK? 513 00:26:37,520 --> 00:26:39,872 但它实际上是 But what it is is the integration of 514 00:26:40,096 --> 00:26:43,824 整合了REMAINDER的GCD机器 remainder into the GCD machine. 515 00:26:44,464 --> 00:26:46,020 并且实际上 它没有多余的寄存器 And it takes, in fact, no more registers. 516 00:26:46,020 --> 00:26:48,624 数据通路上有三个寄存器 There are three registers in the datapaths. OK? 517 00:26:49,050 --> 00:26:50,640 但现在 这里有个减法器 But now there's a subtractor. 518 00:26:51,550 --> 00:26:52,992 又有两个东西被测试 There are two things that are tested. 519 00:26:53,020 --> 00:26:55,072 B等于0么? Is b equal to 0, 520 00:26:55,232 --> 00:26:56,560 T小于B么? or is t less than b? 521 00:26:57,250 --> 00:26:59,456 而至于这一块的控制器 And then the controller, which you see over here, 522 00:27:00,224 --> 00:27:01,760 并不会更加复杂 is not much more complicated. 523 00:27:01,850 --> 00:27:03,872 它有两个循环 But it has two loops in it, 524 00:27:04,528 --> 00:27:08,336 最主要的循环是计算GCD的 one of which is the main one for doing the GCD, 525 00:27:08,400 --> 00:27:10,144 而另一条是减法循环 and one of which is the subtraction loop 526 00:27:10,432 --> 00:27:12,800 是用来计算余数的子操作 for doing the remainder sub-operation. 527 00:27:14,030 --> 00:27:15,808 当然 还有一种思考方式 And there are ways, of course, of, 528 00:27:15,968 --> 00:27:18,688 就是把求余数程序 if you think about it, taking the remainder program. 529 00:27:19,920 --> 00:27:21,712 如果我把那边的REMAINDER机器 If I take remainder, as you see over there 530 00:27:21,728 --> 00:27:22,830 当作LAMBDA表达式 as a lambda expression, 531 00:27:23,568 --> 00:27:27,024 代换到GCD程序的REMAINDER中 substitute it in for remainder over here in the GCD program, 532 00:27:28,208 --> 00:27:30,128 然后再做一些化简 OK, then do some simplification 533 00:27:30,320 --> 00:27:33,664 代换其中的A和B by substituting a and b for remainder in there, 534 00:27:34,464 --> 00:27:35,952 那么 我就可以展开这个循环 then I can unwind this loop. 535 00:27:36,630 --> 00:27:39,424 那么我就可以通过 And I can get this piece of machinery 536 00:27:40,736 --> 00:27:42,944 LAMBDA表达式的基本代数化简 by basically, a little bit of simplification 537 00:27:43,360 --> 00:27:45,216 来得到这台机器 algebraic simplification on the lambda expressions. 538 00:27:48,550 --> 00:27:51,200 我想 你们已经见识了一个非常简单的机器了 So I suppose you've seen your first very simple machines now. 539 00:27:51,952 --> 00:27:53,280 有什么疑问么? Are there any questions? 540 00:28:02,700 --> 00:28:03,104 很好 Good. 541 00:28:05,360 --> 00:28:06,544 看起来很容易 难道不是吗? This looks easy, doesn't it? 542 00:28:10,144 --> 00:28:11,328 好吧 休息一下 谢谢大家 Thank you. I suppose, take a break. 543 00:28:12,540 --> 00:28:24,944 [音乐] [JESU, JOY OF MAN'S DESIRING] 544 00:28:25,136 --> 00:28:28,080 《计算机程序的构造和解释》 545 00:28:31,370 --> 00:28:34,700 《计算机程序的构造和解释》 546 00:28:34,768 --> 00:28:38,000 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 547 00:28:38,000 --> 00:28:43,296 寄存机器 548 00:28:47,936 --> 00:28:48,704 教授:好吧 PROFESSOR: Well, let's see. 549 00:28:49,376 --> 00:28:52,464 现在 你们已经知道如何去把迭代过程 Now you know how to make an iterative procedure, 550 00:28:52,544 --> 00:28:54,544 或者是产生迭代计算的过程 or a procedure that yields an iterative process, 551 00:28:55,184 --> 00:28:56,528 变成一台机器 turn into a machine. 552 00:28:57,770 --> 00:29:00,048 我想 接下来我们就应该考虑 I suppose the next thing we want to do is worry about things 553 00:29:00,544 --> 00:29:02,304 如何来处理递归过程了 that reveal recursive processes. 554 00:29:02,816 --> 00:29:05,056 我们先从一个简单的阶乘过程开始 So let's play with a simple factorial procedure. 555 00:29:11,200 --> 00:29:16,944 (DEFINE (FACT N) We define factorial of N to be 556 00:29:19,632 --> 00:29:24,256 如果N=1 那么结果就是1 if n is 1, the result is 1, 557 00:29:24,624 --> 00:29:27,696 为了减少模拟它的工作量 我就使用1 using 1 right now to decrease the amount of work I have to do to simulate it, 558 00:29:28,128 --> 00:29:33,940 否则结果就是(* N (FACT (- N 1))) else it's times N factorial N minus 1. 559 00:29:42,520 --> 00:29:46,048 正如你们所知 这个程序的不同之处在于 And what's different with this program, as you know, 560 00:29:46,656 --> 00:29:50,368 这里 我在计算(FACT (- N 1))之后 is that after I've computed factorial of N minus 1 here, 561 00:29:50,672 --> 00:29:52,260 我要对结果做一些运算 I have to do something to the result. 562 00:29:52,260 --> 00:29:53,680 我要将它与N相乘 I have to multiply it by N. 563 00:29:56,000 --> 00:30:00,672 将这台机器可视化的唯一途径就是 So the only way I can visualize what this machine is doing, 564 00:30:01,088 --> 00:30:02,016 首先 由于-- because of the fact-- 565 00:30:02,352 --> 00:30:03,184 请你们这么来想 think of it this way, 566 00:30:03,360 --> 00:30:04,944 这里 我有一台机器 that I have a machine out here 567 00:30:05,088 --> 00:30:08,112 而这台机器又需要某个阶乘机器来计算结果 which somehow needs a factorial machine in order to compute its answer. 568 00:30:09,320 --> 00:30:11,168 但外面的这台机器 But this machine, the outer machine, 569 00:30:11,200 --> 00:30:13,024 又需要在调用内部阶乘机器 has to exist before and after 570 00:30:13,920 --> 00:30:15,720 的前后都要存在 the factorial machine, which is inside. 571 00:30:16,800 --> 00:30:17,904 然而在迭代情况中 Whereas in the iterative case, 572 00:30:18,752 --> 00:30:20,528 外面的机器不需要 the outer machine doesn't need to exist 573 00:30:20,912 --> 00:30:24,016 在内部机器运行后保持存在 after the inner machine is running, 574 00:30:24,830 --> 00:30:26,160 这是因为你不需要回到 because you never need to go back 575 00:30:26,192 --> 00:30:27,530 外部机器来进行其它操作 to the outer machine to do anything. 576 00:30:28,640 --> 00:30:30,064 因此 我们这里的问题是 So here we have a problem 577 00:30:30,270 --> 00:30:30,976 我们的机器内部 where we have a machine 578 00:30:31,008 --> 00:30:32,730 有一个同样的机器 which has the same machine inside of it, 579 00:30:33,872 --> 00:30:35,520 一台无穷大的机器 an infinitely large machine. 580 00:30:40,390 --> 00:30:43,120 这里面也有其它的东西 比如乘法器 And it's got other things inside of it, like a multiplier, 581 00:30:44,768 --> 00:30:46,032 它接收输入 which takes some inputs, 582 00:30:46,272 --> 00:30:47,776 这是-1操作 and there's a minus 1 box, 583 00:30:48,128 --> 00:30:49,312 等等 and things like that. 584 00:30:50,690 --> 00:30:53,728 你们可以想象 -- 它就是这个样子的 You know, You can imagine that's what it looks like. 585 00:30:54,370 --> 00:30:56,768 但重要之处就在于 But the important thing is that here I have 586 00:30:57,020 --> 00:30:58,704 内部机器执行之前与执行之后 something that happens before and after, 587 00:30:58,784 --> 00:31:01,600 外部机器中都进行了一些运算 in the outer machine, the execution of the inner machine. 588 00:31:02,540 --> 00:31:04,080 因此这台机器必须有“生命” So this machine has to have a life. 589 00:31:05,472 --> 00:31:11,440 外部机器需要在内部机器的两个时间点保持存在 It has to exist on both times sides of this machine. 590 00:31:13,490 --> 00:31:15,808 因此 我就需要有一个地方来保存 So somehow, I have to have a place to store 591 00:31:16,192 --> 00:31:18,192 维持外部机器运转的数据 the things that this thing needs to run. 592 00:31:20,030 --> 00:31:22,096 现实世界中不存在无穷的对象 Infinite objects don't exist in the real world. 593 00:31:24,140 --> 00:31:25,584 我们要做的就是营造一种假象 What we have to do is arrange an illusion 594 00:31:26,128 --> 00:31:27,488 一种无穷对象的假象 that we have an infinite object, 595 00:31:27,984 --> 00:31:29,776 我们在某处有无穷的硬件资源 we have an infinite amount of hardware somewhere. 596 00:31:31,830 --> 00:31:35,344 现在 这个假象非常重要 Now of course, illusion's all that really matters. 597 00:31:36,280 --> 00:31:37,376 如果我们能保证 If we can arrange 598 00:31:38,000 --> 00:31:39,840 每次当你查看某个无穷对象时 that every time you look at some infinite object, 599 00:31:39,880 --> 00:31:42,960 你所要观察的那部分存在 the part of it that you look at is there, 600 00:31:44,496 --> 00:31:46,040 那么就不需要实际上的“无穷” then it's as infinite as you need it to be. 601 00:31:47,390 --> 00:31:49,440 当然 这里面我们想做的就是 And of course, one of the things we might want to do, 602 00:31:49,824 --> 00:31:52,496 来看下这里的东西 just look at this thing over here, 603 00:31:53,008 --> 00:31:54,976 这是我们目前为止的结构 is the organization that we've had so far 604 00:31:56,048 --> 00:31:57,648 这些结构呢 organization that we've had so far 605 00:31:57,920 --> 00:32:01,376 是机器的几大部分 involves having a part of the machine, 606 00:32:01,408 --> 00:32:02,336 比如控制器 which is the controller, 607 00:32:03,184 --> 00:32:04,464 它在这里 which sits right over here, 608 00:32:04,784 --> 00:32:07,616 它相当简单 并且是有穷的 which is perfectly finite and very simple. 609 00:32:09,170 --> 00:32:10,448 我们还有数据通路 We have some datapaths, 610 00:32:10,464 --> 00:32:12,752 它由寄存器和运算器组成 which consist of registers and operators. 611 00:32:13,080 --> 00:32:15,200 现在我提议 And what I propose to do here is decompose 612 00:32:15,488 --> 00:32:16,960 把机器分成两部分 the machine into two parts, 613 00:32:17,360 --> 00:32:19,792 这样 其中一部分全部是有穷的 such that there is a part which is fundamentally finite, 614 00:32:20,784 --> 00:32:23,536 而另一部分 可以保存无穷数据中的一部分 and some part where a certain amount of infinite stuff can be kept. 615 00:32:24,230 --> 00:32:25,904 换句话说 这部分也非常简单 On the other hand this is very simple 616 00:32:26,416 --> 00:32:28,720 但并非无穷 只是非常大而已 and really isn't infinite, but it's just very large. 617 00:32:29,430 --> 00:32:30,400 但它非常简单 But it's so simple 618 00:32:30,528 --> 00:32:32,928 以至于能够廉价地大量生产 that it could be cheaply reproduced in such large amounts, 619 00:32:34,096 --> 00:32:34,928 它就是内存 we call it memory, 620 00:32:35,952 --> 00:32:39,072 我们可以利用它来构造栈结构 OK? that we can make a structure called a stack out of it 621 00:32:39,408 --> 00:32:41,232 事实上 这就使得我们 which will allow us to, in fact, 622 00:32:41,450 --> 00:32:43,632 能够模拟无穷机器的存在 simulate the existence of an infinite machine 623 00:32:43,648 --> 00:32:46,960 也就是那些递归嵌套的机器 which is made out of a recursive nest of many machines. 624 00:32:48,340 --> 00:32:50,432 而它的原理则是 And the way it's going to work is that 625 00:32:50,560 --> 00:32:52,976 我们要在栈上存放必要的信息 we're going to store in this place called the stack 626 00:32:54,304 --> 00:32:57,584 用于内部机器执行完毕后 the information required after the inner machine runs 627 00:32:59,184 --> 00:33:01,072 继续外部机器的操作 to resume the operation of the outer machine. 628 00:33:03,840 --> 00:33:05,488 因此它会记住 So it will remember 629 00:33:05,632 --> 00:33:07,952 关于外部机器生命期的重要数据 the important things about the life of the outer machine 630 00:33:08,048 --> 00:33:10,304 这些是进行计算所必需的 that will be needed for this computation. 631 00:33:11,390 --> 00:33:12,480 当然 Since, of course, 632 00:33:12,752 --> 00:33:16,336 由于这些机器是通过递归的方式嵌套的 these machines are nested in a recursive manner, 633 00:33:18,330 --> 00:33:23,392 因此 栈的存取方式也会是 then in fact the stack will only be accessed in a manner 634 00:33:23,456 --> 00:33:26,440 也会是后进先出的 which is the last thing that goes in is the first thing that comes out. 635 00:33:29,330 --> 00:33:30,640 因此我们只需要存取 So we'll only need to access 636 00:33:30,800 --> 00:33:32,528 这个栈内存的一小部分 some little part of this stack memory. 637 00:33:34,930 --> 00:33:35,920 好吧 让我们来试一试 OK, well, let's do it. 638 00:33:36,810 --> 00:33:38,416 我已经给你们画好了数据通路 I'm going to build you a datapath now, 639 00:33:38,448 --> 00:33:39,680 现在该布置控制器了 and I'm going to write the controller. 640 00:33:40,370 --> 00:33:42,864 然后我们来运行一下 观察实际工作原理 And then we're going to execute this to see how you do it. 641 00:33:43,510 --> 00:33:46,880 还好阶乘机器不是特别的复杂 So the factorial machine isn't so bad. 642 00:33:47,900 --> 00:33:50,160 它有一个VAL寄存器 It's going to have a register called the value, 643 00:33:52,224 --> 00:33:53,888 这是用来存储答案的 where the answer is going to be stored, 644 00:33:54,896 --> 00:33:56,672 还有一个寄存器N and a registered called N, 645 00:33:59,856 --> 00:34:04,160 它里面存储的是要计算阶乘的数 which is where the number I'm taking factorial will be stored, factorial of. 646 00:34:04,510 --> 00:34:06,576 为了满足某些情况 And it will be necessary in some instances 647 00:34:07,488 --> 00:34:10,520 我们要连接VAL和N to connect VAL to N. 648 00:34:11,744 --> 00:34:15,630 事实上 如果我在这里返回N In fact, one nice case of this is if I just said over here, 649 00:34:16,380 --> 00:34:19,536 也是正确的 因为这时N就等于1 N, because that would be right for N equal 1N. 650 00:34:20,090 --> 00:34:23,264 这样的话 我就可以把结果移动过去 And I could just move the answer over there if that's important. 651 00:34:23,900 --> 00:34:25,552 但我现在不考虑这个问题 I'm not worried about that right now. 652 00:34:26,980 --> 00:34:28,608 我还需要做一些事情 And there are things I have to be able to do. 653 00:34:29,060 --> 00:34:31,024 就像我们在这里看到的 我们还需要 Like I have to be able to, as we see here, 654 00:34:31,216 --> 00:34:34,672 用VAL的值乘以N multiply N by something in VAL, 655 00:34:34,912 --> 00:34:37,456 因为VAL是计算阶乘的结果 because VAL is the result of computing factorial. 656 00:34:38,688 --> 00:34:40,448 我需要把算得的结果送回VAL And I have to put the result back into VAL. 657 00:34:41,488 --> 00:34:42,656 所以这里我们看到 So here we can see 658 00:34:42,832 --> 00:34:46,432 N的阶乘就是 that the result of computing a factorial 659 00:34:46,576 --> 00:34:49,200 N乘以某个阶乘 is N times the result of computing a factorial. 660 00:34:50,690 --> 00:34:53,776 而VAL就代表了内部阶乘的结果 VAL will be the representation of the answer of the inner factorial. 661 00:34:55,190 --> 00:35:00,256 因此 在这里我需要有一个乘法器 And so I'm going to have to have a multiplier here, 662 00:35:02,360 --> 00:35:07,184 它的参数有:N以及VAL which is going to sample the value of N and the value of VAL 663 00:35:08,640 --> 00:35:15,600 并且 像这样把计算结果送回VAL OK? and put the result back into VAL like that. 664 00:35:17,170 --> 00:35:19,392 我也需要知道N是否为1 I'm also going to have to be able to see if N is 1. 665 00:35:21,328 --> 00:35:22,384 因此我需要一个指示灯 So I need a light bulb. 666 00:35:28,200 --> 00:35:30,400 另外 我想我还需要 And I suppose the other thing I'm going to need to have 667 00:35:31,024 --> 00:35:32,848 一个组件来减小N is a way of decrementing N. 668 00:35:34,848 --> 00:35:36,096 所以这里有一个递减器 So I'm going to have a decrementer, 669 00:35:38,192 --> 00:35:41,390 它接收参数N 将结果送回N which takes N and is going to put back the result into N. 670 00:35:46,620 --> 00:35:48,400 这基本上就是我的机器所需要的东西了 That's pretty much what I need in my machine. 671 00:35:49,550 --> 00:35:51,648 然而 我还需要一些个东西 Now, there's a little bit else I need. 672 00:35:52,304 --> 00:35:53,584 一个稍微复杂一点的东西 It's a little bit more complicated, 673 00:35:55,168 --> 00:35:56,880 因为我需要有一种方式能够存储 because I'm also going to need a way to store, 674 00:35:57,168 --> 00:35:59,696 必要的一些信息 to save away, the things that are going to be needed 675 00:36:01,020 --> 00:36:03,072 以便计算完子阶乘后 for resuming the computation of a factorial 676 00:36:03,104 --> 00:36:04,896 恢复原始阶乘的计算 after I've done a sub-factorial. 677 00:36:06,250 --> 00:36:06,864 需要哪些信息呢? What's that? 678 00:36:07,230 --> 00:36:08,736 首先就是N One thing I need is N. 679 00:36:09,850 --> 00:36:12,048 因此 我要在这里构造一个栈 So I'm going to build here a thing called a stack. 680 00:36:14,700 --> 00:36:15,776 所谓的栈就是 The stack is 681 00:36:17,984 --> 00:36:24,976 一大堆连续的空间 a bunch of stuff that I'm going to write in sequentially. 682 00:36:27,152 --> 00:36:28,592 我不知道它到底有多深 I don't know how long it is. 683 00:36:29,152 --> 00:36:31,488 栈越深 无穷的假象营造得就越好 The longer it is, the better my illusion of infinity. 684 00:36:33,230 --> 00:36:35,568 我还需要有一种方法 能够把 And I'm going to have to have a way of getting stuff 685 00:36:35,600 --> 00:36:37,020 N中的值放入栈中 out of N and into the stack 686 00:36:38,128 --> 00:36:39,088 反过来也是 and vice versa. 687 00:36:39,936 --> 00:36:41,744 因此我需要一条像这样的连接 So I'm going to need a connection like this, 688 00:36:44,416 --> 00:36:45,488 它是双向的 which is two-way, 689 00:36:50,448 --> 00:36:52,224 通过它 我就可以在某个时间 whereby I can save the value of N 690 00:36:52,240 --> 00:36:55,504 把N的值存储起来 and then restore it some other time through that connection. 691 00:36:56,048 --> 00:36:56,848 这就是栈 This is the stack. 692 00:36:58,100 --> 00:37:01,712 我还需要一种方法来记住 I also need a way of remembering 693 00:37:01,840 --> 00:37:07,728 我现在计算到外部程序的哪个地方了 where I was in the computation of factorial in the outer program. 694 00:37:08,530 --> 00:37:10,064 现在 对于这台机器来说 Now in the case of this machine, 695 00:37:10,768 --> 00:37:13,344 这并不是什么问题 it isn't very much a problem. 696 00:37:14,176 --> 00:37:16,240 FACT总是返回在 Factorial always returns, 697 00:37:16,864 --> 00:37:19,072 一个跟N相乘的地方 has to go back to the place where we multiply by N, 698 00:37:19,344 --> 00:37:20,720 除了最后的一次 except for the last time, 699 00:37:21,150 --> 00:37:23,024 它返回到需要FACT最终答案的地方 when it has to return to whatever needs the factorial 700 00:37:23,040 --> 00:37:24,040 或者是'DONE、'STOP之类的 or go to done or stop. 701 00:37:25,660 --> 00:37:26,672 然而 通常来说 However, in general, 702 00:37:27,168 --> 00:37:28,736 我需要记住我去过哪些地方 I'm going to have to remember where I have been, 703 00:37:29,136 --> 00:37:31,248 因为 我可能从其它地方调用FACT because I might have computed factorial from somewhere else. 704 00:37:32,080 --> 00:37:34,896 我需要返回到那个地方 并从那里继续 I have to go back to that place and continue there. 705 00:37:36,070 --> 00:37:38,000 因此 我需要有一种方法能够 So I'm going to have to have some way of taking the place 706 00:37:38,016 --> 00:37:40,864 记住有穷状态控制器中弹珠的位置 where the marble is in the finite state controller, 707 00:37:41,328 --> 00:37:42,640 也就是控制器的状态 the state of the controller, 708 00:37:44,224 --> 00:37:46,352 并将它存储在栈中 and storing that in the stack as well. 709 00:37:47,400 --> 00:37:49,104 我也需要有一种方法 And I'm going to have to have ways of restoring that 710 00:37:49,456 --> 00:37:51,120 能够恢复弹珠的状态 back to the state of the-- the marble. 711 00:37:52,144 --> 00:37:54,288 因此 我需要有一种将弹珠归位的能力 So I have to have something that moves the marble to the right place. 712 00:37:54,704 --> 00:37:56,528 现在 我们有一个地方用于存储弹珠 Well, we're going to have a place which is the marble now. 713 00:37:57,872 --> 00:37:59,344 它被称作“继续”寄存器 And it's called the continue register, 714 00:38:03,616 --> 00:38:04,528 记作CONTINUE called continue, 715 00:38:09,160 --> 00:38:10,688 下一次调用(GOTO CONTINUE)时 which is the place to put the marble 716 00:38:11,008 --> 00:38:13,050 弹珠就会去向这个地方 next time I go to continue. 717 00:38:14,912 --> 00:38:15,920 它就是用来干这个的 That's what that's for. 718 00:38:16,140 --> 00:38:18,480 因此 它和控制器之间应该有一条通路 And so there's got to be some path from that into the controller. 719 00:38:22,910 --> 00:38:27,120 我也能够将它存储在栈上 I also have to have some way of saving that on the stack. 720 00:38:29,450 --> 00:38:33,104 我也能够把它设置成各种常量 And I have to have some way of setting that up to have various constants, 721 00:38:34,016 --> 00:38:35,696 某一些常量 a certain fixed number of constants. 722 00:38:36,860 --> 00:38:38,208 这非常容易实现 And that's very easy to arrange. 723 00:38:38,840 --> 00:38:40,144 我们现在这里设一些常量 So let's have some constants here. 724 00:38:40,180 --> 00:38:41,504 我们把这个记作AFTER-FACT We'll call this one after-fact. 725 00:38:47,328 --> 00:38:48,752 这个常量 And that's a constant 726 00:38:48,848 --> 00:38:51,504 会送入CONTINUE寄存器 which will get into the continue register, 727 00:38:52,592 --> 00:38:54,432 另外一个寄存器是FACT-DONE and also another one called fact-done. 728 00:39:05,210 --> 00:39:07,824 这就是我想要构建的机器 So this is the machine I want to build. 729 00:39:08,130 --> 00:39:09,488 至少是数据通路部分 That's its datapaths, at least. 730 00:39:09,920 --> 00:39:11,696 这里还混合了一些控制器 And it mixes a little with the controller here, 731 00:39:11,856 --> 00:39:14,592 这是因为我需要记住我当前的位置 because of the fact that I have to remember where I was 732 00:39:14,704 --> 00:39:16,352 并将我恢复到该位置 and restore myself to that place. 733 00:39:17,300 --> 00:39:19,936 现在 让我们来编写控制器对应的程序 But let's write the program now which represents the controller. 734 00:39:20,390 --> 00:39:23,472 我就把DEFINE-MACHINE和寄存器列表给省略了 I'm not going to write the define machine thing and the register list, 735 00:39:23,488 --> 00:39:24,890 因为它们无关紧要 because that's not very interesting. 736 00:39:25,130 --> 00:39:27,792 我就直接写那些跟控制器有关的 I'm just going to write down the sequence of instructions 737 00:39:27,824 --> 00:39:29,020 指令序列 that constitute the controller. 738 00:39:31,488 --> 00:39:41,856 首先是(ASSIGN CONTINUE DONE) So we have assign, to set up, continue to done. 739 00:39:45,150 --> 00:39:45,824 然后是一个循环 We have a loop 740 00:39:47,344 --> 00:39:56,080 先判断 如果1=N 那么就跳转 which says branch if equal 1 fetch N, 741 00:40:00,944 --> 00:40:04,112 那么就进入归纳的基本步骤 if N is 1, then go to the base step of the induction, 742 00:40:06,064 --> 00:40:07,200 也就是最简单的情况 the simple case. 743 00:40:08,050 --> 00:40:08,768 否则的话 Otherwise, 744 00:40:08,880 --> 00:40:10,848 我就要记住那些 I have to remember the things that are necessary 745 00:40:10,880 --> 00:40:13,840 计算子阶乘所必须的信息 to perform a sub-factorial. 746 00:40:14,672 --> 00:40:16,752 我需要来带这里 以便计算子阶乘 I'm going to go over here, and I have to perform a sub-factorial. 747 00:40:17,570 --> 00:40:19,296 所以我需要记住 完成它需要些什么 So I have to remember what's needed to do that 748 00:40:19,712 --> 00:40:22,528 需要记住我计算完之后需要哪些东西 remember what's needed after I will be done with that. 749 00:40:24,000 --> 00:40:25,510 看到了吗 我要做些糟糕的事儿 See, I'm about to do something terrible. 750 00:40:25,728 --> 00:40:27,392 我要去修改N的值 I'm about to change the value of N. 751 00:40:28,576 --> 00:40:30,400 但是它又需要记住N的旧值 But this guy has to know the old value of N. 752 00:40:32,140 --> 00:40:33,648 但是为了计算子阶乘 But in order to make the sub-factorial work, 753 00:40:33,664 --> 00:40:34,920 我又需要修改N的值 I have to change the value of N. 754 00:40:35,600 --> 00:40:37,104 因此 我就得记住N的旧值 So I have to remember the old value. 755 00:40:38,000 --> 00:40:39,600 我也需要记住我的位置 And I also have to remember where I've been. 756 00:40:40,850 --> 00:40:42,320 因此 我保存CONTINUE的值 So I save up continue. 757 00:40:47,700 --> 00:40:51,296 这条指令 就是用来将数据入栈的 And this is an instruction that says, put something in the stack. 758 00:40:53,120 --> 00:40:55,536 将CONTINUE寄存器的值保存起来 Save the contents of the continuation register, 759 00:40:56,512 --> 00:40:58,000 在本例中也就是DONE which in this case is done, 760 00:40:58,880 --> 00:41:00,256 因为稍后我也会修改它 because later I'm going to change that, too, 761 00:41:00,272 --> 00:41:02,780 因为我也需要回到AFTER-FACT because I need to go back to after-fact, as well. 762 00:41:03,550 --> 00:41:04,192 我们来看看 We'll see that. 763 00:41:05,040 --> 00:41:09,712 我们需要存储N 因为稍后会用到 We save N, because I'm going to need that for later. 764 00:41:10,380 --> 00:41:20,544 (ASSIGN N (-1+ (FETCH N))) Assign to N the decrement of fetch N. 765 00:41:23,264 --> 00:41:28,976 (ASSIGN CONTINUE ... Assign continue, 766 00:41:32,128 --> 00:41:33,424 我看一下 -- we're going to look at this now, 767 00:41:34,064 --> 00:41:35,616 AFT) to after, we'll call it. 768 00:41:37,690 --> 00:41:38,704 这个名字很好 That's a good name for this, 769 00:41:38,736 --> 00:41:40,656 因为它短小精炼 很适合用在这里 a little bit easier and shorter, and fits in here. 770 00:41:53,360 --> 00:41:54,640 现在 来看看我怎么做 Now look what I'm doing here. 771 00:41:55,330 --> 00:41:57,020 我说 如果ANSWER是1的话 I'm saying, if the answer is 1, 772 00:41:58,720 --> 00:41:59,664 那程序就结束了 OK, I'm done. 773 00:42:00,464 --> 00:42:01,664 我只需要取得这个答案 I'm going to have to just get the answer. 774 00:42:02,150 --> 00:42:04,880 否则我就要保存当前的继续以及N的值 Otherwise, I'm going to save the continuation, save N, 775 00:42:05,776 --> 00:42:07,328 然后让N减1 make N one less than N, 776 00:42:07,600 --> 00:42:09,632 注意 我先要跳转到某处 remember I'm going to come back to someplace else, 777 00:42:09,648 --> 00:42:11,488 然后来到这里 计算另外的阶乘 and go back and start doing another factorial. 778 00:42:13,504 --> 00:42:15,744 然而 这之中又有了另外的机器 OK? However, I've got a different machine in me now. 779 00:42:16,050 --> 00:42:18,380 其中N=1 CONTINUE是其它值 N is 1, and continue is something else. 780 00:42:22,112 --> 00:42:23,216 N=N-1 N is N minus 1. 781 00:42:23,770 --> 00:42:25,280 再我完成这个之后 Now after I'm done with that, 782 00:42:26,944 --> 00:42:27,760 我会来到这里 I can go there. 783 00:42:28,660 --> 00:42:30,464 我会恢复N的旧值 I will restore the old value of N, 784 00:42:32,688 --> 00:42:36,560 也就是这里SAVE的逆运算 which is the opposite of this save over here. 785 00:42:38,360 --> 00:42:39,888 然后恢复CONTINUE I will restore the continuation. 786 00:42:49,660 --> 00:42:52,576 然后我又会来到这里 I will then go to here. 787 00:42:54,320 --> 00:43:00,864 (ASSIGN VAL I will assign to the VAL register 788 00:43:01,168 --> 00:43:08,130 (* (FETCH N) (FETCH VAL))) the product of N and fetch VAL. 789 00:43:13,440 --> 00:43:18,304 (闭合括号中) VAL fetch product assign. 790 00:43:19,790 --> 00:43:21,440 这样操作就完成了 And then I will be done. 791 00:43:21,440 --> 00:43:25,680 子阶乘的结果就存储在了VAL中 I will have my answer to the sub-factorial in VAL. 792 00:43:26,570 --> 00:43:27,376 这个时候 At that point, 793 00:43:27,660 --> 00:43:28,752 我就要返回到 I'm going to return 794 00:43:29,280 --> 00:43:31,610 CONTINUE所指向的地方 by going to the place where the continuation is pointing. 795 00:43:33,640 --> 00:43:35,776 也就是(GOTO (FETCH CONTINUE)) That says, go to fetch continue. 796 00:43:45,870 --> 00:43:47,408 最后就是基本情况的那步 And then I have finally a base step, 797 00:43:49,312 --> 00:43:50,512 也就是一个立即值 which is the immediate answer. 798 00:43:50,680 --> 00:43:56,880 (ASSIGN VAL (FETCH N)) Assign to VAL fetch N, 799 00:44:01,360 --> 00:44:02,752 (GOTO (FETCH CONTINUE)) and go to fetch continue. 800 00:44:12,670 --> 00:44:13,552 这样我就完成了 And then I'm done. 801 00:44:18,640 --> 00:44:21,216 现在 我们用一个非常简单的例子来运行一下 Now let's see how this executes on a very simple case, 802 00:44:22,512 --> 00:44:23,536 因为这样我们就将看到 because then we'll see 803 00:44:23,664 --> 00:44:26,528 栈是如何帮助我们完成计算的 the use of this stack to do the job we need. 804 00:44:26,890 --> 00:44:28,224 这是计算的静态描述 This is statically what it's doing, 805 00:44:28,224 --> 00:44:29,800 我们需要动态地观察它 but we have look dynamically at this. 806 00:44:31,340 --> 00:44:32,096 因此 让我们来看看 So let's see. 807 00:44:32,300 --> 00:44:34,560 首先我们要把CONTINUE设置为DONE First thing we do is continue gets done. 808 00:44:36,730 --> 00:44:38,096 这是我通过按下这个钮来实现的 The way that happened is I pushed this. 809 00:44:38,300 --> 00:44:39,600 我们还是把它记作DONE吧 Let's call that done the way I have it. 810 00:44:46,224 --> 00:44:47,030 我按下这个按钮 I push that button. 811 00:44:47,030 --> 00:44:48,112 DONE就进到了这里 Done goes into there. 812 00:44:48,950 --> 00:44:53,712 现在 我还要为这些东西设置初始值 Now I also have to set this thing up to have an initial value. 813 00:44:53,850 --> 00:44:58,080 让我们考虑3的阶乘 Let's consider a factorial of three, 814 00:44:58,384 --> 00:44:59,248 这个例子非常简单 a simple case. 815 00:45:00,544 --> 00:45:04,048 我们的栈从这里开始增长 And we're going to start out with our stack growing over here. 816 00:45:05,900 --> 00:45:07,760 栈有它们自己的内部状态 Stacks have their own little internal state 817 00:45:07,792 --> 00:45:09,056 用来标识栈顶位置 saying where they are, 818 00:45:09,808 --> 00:45:11,648 也就是下一个可写位置 where the next place I'm going to write is. 819 00:45:12,770 --> 00:45:14,590 现在我们问 N=1么? So now we say, is N 1? 820 00:45:14,768 --> 00:45:15,712 当然不等于 The answer is no. 821 00:45:16,110 --> 00:45:18,560 因此现在我要保存CONTINUE So now I'm going to save continue, bang. 822 00:45:19,152 --> 00:45:20,656 现在 DONE就来到了这里 Now that done goes in here. 823 00:45:22,080 --> 00:45:23,552 然后 这个指针移动到了这里 And this moves to here, 824 00:45:24,880 --> 00:45:26,144 下次我要把数据写到这里 the next place I'm going to write. 825 00:45:26,660 --> 00:45:28,784 保存N的值--也就是3 Save N 3. 826 00:45:29,950 --> 00:45:30,320 对吧? OK? 827 00:45:30,672 --> 00:45:33,616 N←N-1 Assign to N the decrement of N. 828 00:45:33,968 --> 00:45:35,376 也就是说 我得按下这个钮 That means I've pushed this button. 829 00:45:35,940 --> 00:45:37,320 这就变成了2 This becomes 2. 830 00:45:38,736 --> 00:45:42,288 COUNTINUE←AFT OK? Assign to continue aft. 831 00:45:42,580 --> 00:45:43,610 因此我要按下这个钮 So I've pushed that button. 832 00:45:43,610 --> 00:45:44,544 AFT就进入了这里 Aft goes in here. 833 00:45:49,140 --> 00:45:53,936 然后 跳转到LOOP 我们就来到了这里 OK, now go to loop, bang, so up to here. 834 00:45:54,830 --> 00:45:57,088 N=1么?当然不 Is N 1? No 835 00:45:57,780 --> 00:45:59,232 因此我又要保存CONTINUE So I have to save continue. 836 00:45:59,490 --> 00:46:00,272 CONTINUE的值是什么呢? What's continue? 837 00:46:00,600 --> 00:46:01,530 目前是AFT Continue is aft. 838 00:46:01,530 --> 00:46:02,320 按下这个按钮 Push this button. 839 00:46:02,780 --> 00:46:03,952 这个指针移动到了这里 So this moves to here. 840 00:46:08,490 --> 00:46:09,744 我还要保存N I have to save N. 841 00:46:10,510 --> 00:46:12,128 N在那里 它的值是2 N is over here. I got to 2. 842 00:46:12,280 --> 00:46:13,376 按下这个按钮 Push that button. 843 00:46:13,856 --> 00:46:15,248 2就进入了这里 So a 2 gets written there. 844 00:46:16,050 --> 00:46:17,648 然后这个指针移动到了这里 And then this thing moves down here. 845 00:46:20,060 --> 00:46:22,608 保存N之后 又赋N←N-1 OK, save N. Assign N to the decrement of N. 846 00:46:24,608 --> 00:46:25,460 它就变成了1 This becomes a 1. 847 00:46:29,240 --> 00:46:30,544 CONTINUE←AFT Assign continue to aft. 848 00:46:31,370 --> 00:46:34,480 AFT又进入了这里 A-F-T gets written there again. 849 00:46:34,960 --> 00:46:35,648 然后又跳转到LOOP Go to loop. 850 00:46:36,520 --> 00:46:37,744 N等于1么? Is N equal to 1? 851 00:46:37,930 --> 00:46:39,520 是的 那么答案就是1 Oh, yes, the answer is 1. 852 00:46:41,040 --> 00:46:43,264 跳转到BASE那一步 OK, go to base step. 853 00:46:44,160 --> 00:46:45,776 (ASSIGN VAL (FETCH N)) Assign to VAL fetch of N. 854 00:46:46,560 --> 00:46:50,720 按下这个 1就进入到了这里 Bang, 1 gets put in there. OK? 855 00:46:51,100 --> 00:46:52,200 (GOTO (FETCH CONTINUE)) Go to fetch continue. 856 00:46:52,200 --> 00:46:53,536 来看下CONTINUE寄存器 So we look in continue. 857 00:46:53,680 --> 00:46:56,064 基本上来说 我按下这里的按钮 进入到控制器 Basically, I'm pushing a button over here that goes to the controller. 858 00:46:56,670 --> 00:46:58,288 CONTINUE寄存器就变成了AFT The continue becomes aft, 859 00:46:58,320 --> 00:47:00,256 这样一下子 程序就运行到了这里 and all of a sudden, the program's running here. 860 00:47:02,640 --> 00:47:05,632 现在 我就需要恢复外部的阶乘了 I now have to restore the outer version of factorial. 861 00:47:06,650 --> 00:47:07,550 因此我们来到这里 So we go here. 862 00:47:07,550 --> 00:47:09,488 我们先要恢复N We say, restore N. 863 00:47:10,320 --> 00:47:13,040 这就意味着 我们要使用这里的内容 So restore N means take the contents that's here. 864 00:47:13,940 --> 00:47:18,176 按下这个按钮 2就会来到这里 Push this button, and it goes into here, 2, 865 00:47:18,560 --> 00:47:20,048 然后指针会向上移动 and the pointer moves up. 866 00:47:21,984 --> 00:47:24,490 恢复CONTINUE寄存器也非常简单 Restore continue, pretty easy. 867 00:47:24,810 --> 00:47:26,496 来按下这个按钮 Go push this button. 868 00:47:27,020 --> 00:47:28,928 然后 AFT又一次进入到这里 And then aft gets written in here again. 869 00:47:31,280 --> 00:47:32,640 同时 这个指针也要上移 That means this thing moves up. 870 00:47:32,640 --> 00:47:35,190 这样就避开了栈上的其它东西 I've gotten rid of something else on my stack. 871 00:47:42,240 --> 00:47:43,472 然后我来到这里 Right, then I go to here, 872 00:47:43,872 --> 00:47:47,152 也就是(ASSIGN VAL (* N VAL)) which says, assign to VAL the product of N and VAL. 873 00:47:47,850 --> 00:47:50,576 然后我按下这个按钮 So I push this button over here, bang. 874 00:47:50,970 --> 00:47:52,912 2乘以1等于2 2 times 1 gives me a 2, 875 00:47:54,016 --> 00:47:54,752 我写到这里 get written there. 876 00:47:55,760 --> 00:47:57,200 然后是(GOTO (FETCH CONTINUE)) OK? Go to fetch continue. 877 00:47:57,540 --> 00:47:59,856 CONTINUE现在是AFT 我跳转到AFT Continue is aft. I go to aft. 878 00:48:01,150 --> 00:48:03,888 AFT首先要恢复N OK? Aft says restore N. 879 00:48:04,368 --> 00:48:05,728 恢复N指的是 Do your restore N, 880 00:48:05,872 --> 00:48:08,448 我把这里的值 也就是3 means I take the value over here, which is 3, 881 00:48:09,248 --> 00:48:10,336 按下这里的按钮 push this up to here, 882 00:48:10,600 --> 00:48:15,504 然后把它放到这里 N and move it into here, N. 883 00:48:16,256 --> 00:48:17,344 然后 我们按下这个钮 Now it's pushing that button. 884 00:48:18,016 --> 00:48:19,904 接下来我就要恢复CONTINUE The next thing I do is restore continue. 885 00:48:20,200 --> 00:48:22,208 CONTINUE寄存器现在成为了DONE Continue is now going to become done. 886 00:48:22,830 --> 00:48:26,784 当我按下这个钮后 指针就移动到了这里 So this moves up here when I push this button. 887 00:48:27,130 --> 00:48:29,728 DONE可能从此之后不在这里了 Done may or may be there anymore, 888 00:48:29,728 --> 00:48:31,550 对此我并不感兴趣 但它现在一定在这里 I'm not interested, but it certainly is here. 889 00:48:35,800 --> 00:48:38,120 下一步 我将要把VAL赋值为 Next thing I do is assign to VAL 890 00:48:38,432 --> 00:48:40,768 N乘以VAL的值 the product of the fetch of N and the fetch of VAL. 891 00:48:41,440 --> 00:48:44,300 按下这里的按钮就可以实现 That's pushing this button over here, bang. 892 00:48:44,300 --> 00:48:45,776 2乘以3等于6 2 times 3 is 6. 893 00:48:46,520 --> 00:48:47,870 所以这里我就得到了6 So I get a 6 over here. 894 00:48:50,976 --> 00:48:53,408 下一步是(GOTO (FETCH CONTINUE)) OK? And go to fetch continue, 895 00:48:53,488 --> 00:48:54,832 哦 跳转到DONE 这样我就完成了 whoops, I go to done, and I'm done. 896 00:48:55,020 --> 00:48:56,096 最后的答案是6 And my answer is 6, 897 00:48:56,608 --> 00:48:57,824 你们可以在VAL寄存器中看到 as you can see in the VAL register. 898 00:48:58,950 --> 00:48:59,824 事实上 And in fact, 899 00:49:00,912 --> 00:49:03,344 栈又回到了它初始的状态 the stack is in the state it originally was in. 900 00:49:08,208 --> 00:49:10,704 在使用像栈这样的东西中 有一些原则 Now there's a bit of discipline in using these things like stacks 901 00:49:11,200 --> 00:49:12,272 我们需要注意 that we have to be careful of. 902 00:49:13,620 --> 00:49:15,520 我们会在下一小节中介绍 And we'll see that in the next segment. 903 00:49:16,260 --> 00:49:18,464 但首先 对于这一小节所讲的内容 But first I want to ask if there are any questions for this. 904 00:49:28,560 --> 00:49:29,648 有什么问题么? Are there any questions? 905 00:49:30,170 --> 00:49:30,630 Ron 请讲 Yes, Ron. 906 00:49:30,630 --> 00:49:33,376 学生:当你越过了栈的顶端会怎样-- AUDIENCE: What happens when you roll off the end of the stack with-- 907 00:49:33,392 --> 00:49:34,624 教授:你所谓的“越过”是指什么? PROFESSOR: What do you mean, roll off of? 908 00:49:35,030 --> 00:49:37,504 学生:如果我们的N是一个很大的数 AUDIENCE: Well, the largest number-- a larger starting point of N 909 00:49:37,520 --> 00:49:38,720 就需要更多的内存 对吧? requires more memory, correct? 910 00:49:38,860 --> 00:49:39,440 教授:是的 PROFESSOR: Oh, yes. 911 00:49:39,440 --> 00:49:41,120 这样 我就需要一个足够大的栈 Well, I need to have a long enough stack. 912 00:49:41,530 --> 00:49:43,200 你想问 如果破坏了无穷存储的假象会发生什么? You say, what if I violate my illusion? 913 00:49:43,840 --> 00:49:44,128 学生:是的 AUDIENCE: Yes. 914 00:49:44,550 --> 00:49:46,736 教授:那么 这些魔法就不再起效了 PROFESSOR: Well, then the magic doesn't work. OK? 915 00:49:47,968 --> 00:49:51,008 真相就是 任何机器都是有穷的 The truth of the matter is that every machine is finite. 916 00:49:51,640 --> 00:49:53,728 而对于像这样的过程 And for a procedure like this, 917 00:49:54,176 --> 00:49:58,864 我只能进行有限数量的子阶乘计算 there's a limit to the number of sub-factorials I could have. 918 00:49:59,950 --> 00:50:02,480 想一想 我们之前讲解的Y组合子 Remember when we were doing the y-operator a while ago, 919 00:50:02,800 --> 00:50:06,224 我们指出 存在一系列的指数过程 we pointed out that there was a sequence of exponentiation procedures, 920 00:50:06,256 --> 00:50:08,096 其中每一个都要比前一个更精准 each of which was a little better than the previous one. 921 00:50:08,720 --> 00:50:11,600 现在 我们看到了如何实现这个数学理念 Well, we're now seeing how we implement that mathematical idea. 922 00:50:13,090 --> 00:50:14,192 这个取极限的过程 The limiting process 923 00:50:14,352 --> 00:50:16,336 只有当你取到极限时才足够精准 is only so good as as far as you take the limit. 924 00:50:17,990 --> 00:50:19,420 如果你仔细想想 我这里用了什么 If you think about it, what am I using here? 925 00:50:19,420 --> 00:50:22,656 对于这个过程的每一次递归 I'm using about two chunks, pieces of memory 926 00:50:23,040 --> 00:50:27,072 我用了大概两块内存 for iteration for every recursion of this process. 927 00:50:29,100 --> 00:50:31,712 如果我们尝试计算10000的阶乘 If we try to compute factorial of 10,000, 928 00:50:31,728 --> 00:50:32,816 这并不会花掉很多内存 that's not a lot of memory. 929 00:50:33,180 --> 00:50:34,688 虽然这是一个很大的数 On the other hand, it's an awful big number. 930 00:50:35,952 --> 00:50:38,416 因此 实际的问题就是值不值得 So the question is, is that a valuable thing in this case. 931 00:50:39,180 --> 00:50:42,192 但这并不是这种实现的局限 But it really turns out not to be a terrible limit, 932 00:50:42,224 --> 00:50:43,536 因为内存非常低廉 because memory is el cheapo, 933 00:50:44,160 --> 00:50:45,344 但人力资源却相当昂贵 and people are pretty expensive. 934 00:50:48,130 --> 00:50:50,224 好吧 我们先休息一下 谢谢大家 OK, thank you, let's take a break. 935 00:50:50,780 --> 00:51:07,600 [音乐] [JESU, JOY OF MAN'S DESIRING] 936 00:51:07,600 --> 00:51:12,192 《计算机程序的构造和解释》 937 00:51:39,930 --> 00:51:43,696 讲师:哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 938 00:51:43,710 --> 00:51:47,936 《计算机程序的构造和解释》 939 00:51:47,930 --> 00:51:53,088 寄存机器 940 00:51:56,112 --> 00:51:57,040 教授:我们讲解了 PROFESSOR: Well, let's see. 941 00:51:58,704 --> 00:52:03,376 如果进行简单的迭代计算 What I've shown you now is how to do a simple iterative process 942 00:52:03,696 --> 00:52:05,312 以及简单的递归计算 and a simple recursive process. 943 00:52:05,640 --> 00:52:08,688 我只想通过向你们展示一些针对特定应用的 I just want to summarize the design of simple machines 944 00:52:09,632 --> 00:52:11,120 更加复杂的设计 for specific applications 945 00:52:11,216 --> 00:52:13,584 来总结简单机器的设计 by showing you a little bit more complicated design, 946 00:52:13,968 --> 00:52:17,136 也就是同时递归地调用两个斐波那契函数 that of a thing that does doubly recursive Fibonacci, 947 00:52:17,232 --> 00:52:19,888 因为它会向我们表明 并且我们会理解 because it will indicate to us, and we'll understand, 948 00:52:20,048 --> 00:52:22,688 一些关于栈正常工作 a bit about the conventions required 949 00:52:22,768 --> 00:52:25,040 所需要遵守的约定 for making stacks operate correctly. 950 00:52:26,400 --> 00:52:27,110 现在 让我们来看看 So let's see. 951 00:52:27,110 --> 00:52:28,272 先让我在黑板上写下 I'm just going to write down, first of all, 952 00:52:28,304 --> 00:52:29,712 将要翻译的程序 the program I'm going to translate. 953 00:52:34,150 --> 00:52:36,528 这是一个斐波那契过程 I need a Fibonacci procedure, 954 00:52:39,232 --> 00:52:41,584 它非常的简单 it's very simple, which says, if 955 00:52:44,608 --> 00:52:48,560 如果N小于2 那么结果就是N N is less than 2, the result is N, 956 00:52:49,264 --> 00:52:55,344 否则就是(FIB (- N 1))加上 otherwise it's the sum of Fib of N minus 1 957 00:52:58,448 --> 00:52:59,856 (FIB (- N 2)) and Fib of N minus 2. 958 00:53:07,056 --> 00:53:09,290 这就是我的计划 That's the plan I have here. 959 00:53:09,290 --> 00:53:12,560 现在 我们要来写下这台机器的控制器 And we're just going to write down the controller for such a machine. 960 00:53:13,070 --> 00:53:15,536 首先 我们假设有一个寄存器N We're going to assume that there are registers, N, 961 00:53:15,568 --> 00:53:19,150 里面存放的是斐波那契函数的自变量 which holds the number we're taking Fibonacci of, 962 00:53:19,824 --> 00:53:21,808 而计算结果会存放在VAL寄存器中 VAL, which is where the answer is going to get put, 963 00:53:22,176 --> 00:53:24,976 CONTINUE寄存器会和控制器相连 and continue, which is the thing that's linked to the controller, 964 00:53:26,112 --> 00:53:26,810 就跟之前一样 like before. 965 00:53:26,960 --> 00:53:29,216 但我不会再去画数据通路了 But I'm not going to draw another physical datapath, 966 00:53:31,536 --> 00:53:34,000 因为它和之前的那个差不多 because it's pretty much the same as the last one you've seen. 967 00:53:34,360 --> 00:53:37,840 当然 关于计算的最神奇的事情之一 And of course, one of the most amazing things about computation 968 00:53:38,752 --> 00:53:39,888 就是一段时间后 is that after a while, 969 00:53:40,080 --> 00:53:41,936 你构建了一个又一个的小功能 you build up a little more features and a few more features, 970 00:53:41,952 --> 00:53:43,328 你就一下子拥有了需要的一切 and all of the sudden, you've got everything you need. 971 00:53:44,752 --> 00:53:47,600 这种效率是非常了不起的 So it's remarkable that it just gets there so fast. 972 00:53:48,176 --> 00:53:50,848 构造制作一台通用计算机不需要太多的东西 I don't need much more to make a universal computer. 973 00:53:51,810 --> 00:53:54,688 总之 我们来看看斐波那契机器的控制器 But in any case, let's look at the controller for the Fibonacci thing. 974 00:53:55,060 --> 00:53:57,072 我首先要做的是 First thing I want to do is 975 00:53:57,328 --> 00:54:02,528 通过为CONTINUE寄存器赋值 start the thing up by assign to continue 976 00:54:07,136 --> 00:54:10,288 赋FIB-DONE来启动计算 a place called done, called Fib-done here. 977 00:54:14,144 --> 00:54:15,536 这就意味着在这里 So that means that somewhere over here, 978 00:54:15,552 --> 00:54:18,480 我需要有一个标签 FIB-DONE I'm going to have a label, Fib-done, 979 00:54:19,712 --> 00:54:21,104 当我来到这个地方后 which is the place where I go 980 00:54:21,232 --> 00:54:22,448 机器就停止了 when I want the machine to stop. 981 00:54:24,000 --> 00:54:24,864 这就是这个标签的作用 That's what that is. 982 00:54:25,920 --> 00:54:26,896 然后我要创建一个循环 And I'm going to make up a loop. 983 00:54:31,110 --> 00:54:34,256 我要来到这里来启动FIB的计算 It's a place I'm going to go to in order to start up computing a Fib. 984 00:54:35,470 --> 00:54:36,864 无论这时 N等于多少 Whatever is in N at this point, 985 00:54:37,392 --> 00:54:38,992 斐波那契函数都会被计算 Fibonacci will be computed of, 986 00:54:39,136 --> 00:54:42,016 然后会返回到由CONTINUE寄存器指向的地方 and we will return to the place specified by continue. 987 00:54:44,800 --> 00:54:48,400 因此你们将在这里看到 So what you're going to see here at this place, 988 00:54:48,448 --> 00:54:50,480 我想要在做一个约定 what I want here is the contract 989 00:54:50,970 --> 00:54:54,256 我用注释的形式来说明这个约定 that says, I'm going to write this with a comment syntax, 990 00:54:54,576 --> 00:55:00,992 也就是N中存储的是参数 the contract is N contains arg, the argument. 991 00:55:02,100 --> 00:55:09,824 而CONTINUE存储的是接收者 Continue is the recipient. 992 00:55:13,360 --> 00:55:14,290 这个约定就是这样的 And that's where it is. 993 00:55:15,710 --> 00:55:18,960 因此每当我来到这里 At this point, if I ever go to this place, 994 00:55:19,248 --> 00:55:21,040 我希望这个约定是成立的 I'm expecting this to be true, 995 00:55:21,520 --> 00:55:23,328 这些计算斐波那契函数所需要的参数 the argument for computing the Fibonacci. 996 00:55:24,820 --> 00:55:26,832 接下来我想做的是分支 Now the next thing I want to do is to branch. 997 00:55:30,220 --> 00:55:32,224 如果N小于2 And if N is less than 2-- 998 00:55:35,072 --> 00:55:37,440 随便说一下 我使用的语法看起来像Lisp by the way, I'm using what looks like Lisp syntax. 999 00:55:38,730 --> 00:55:39,632 但它并不是Lisp This is not Lisp. 1000 00:55:41,310 --> 00:55:42,384 它们运行不起来 This does not run. 1001 00:55:42,750 --> 00:55:45,472 我在这里写的并不是一个简单的Lisp程序 What I'm writing here does not run as a simple Lisp program. 1002 00:55:46,120 --> 00:55:49,312 这是另一门语言的表示形式 This is a representation of another language. 1003 00:55:49,710 --> 00:55:52,256 我之所以使用这种满是括号的语法 The reason I'm using the syntax of parentheses and so on 1004 00:55:52,400 --> 00:55:54,704 是因为我刚好使用Lisp系统 is because I tend to use a Lisp system 1005 00:55:55,328 --> 00:55:57,344 来为这门语言编写解释器 to write an interpreter for this 1006 00:55:57,824 --> 00:55:59,184 这就使得我们能够模拟 which allows me to simulate 1007 00:55:59,296 --> 00:56:00,912 我想要构建的机器 the machine I'm trying to build. 1008 00:56:03,380 --> 00:56:06,240 我不想让你们感到困惑 认为这是Lisp代码 I don't want to confuse this to think that this is Lisp code. 1009 00:56:06,940 --> 00:56:08,608 只是我用了很多Lisp组件 It's just I'm using a lot of the pieces of Lisp. 1010 00:56:09,510 --> 00:56:10,848 我在Lisp中嵌入了一门语言 I'm embedding a language in Lisp, 1011 00:56:11,024 --> 00:56:12,448 把Lisp当作组件 using Lisp as pieces 1012 00:56:12,720 --> 00:56:15,120 这样就能让我的模拟工作变得简单 to make my process of making my simulator easy. 1013 00:56:16,620 --> 00:56:18,560 我从Lisp中继承了这些属性 So I'm inheriting from Lisp all of its properties. 1014 00:56:19,100 --> 00:56:21,530 (FETCH N) 2) Fetch of N 2, 1015 00:56:21,776 --> 00:56:23,728 成立的话 我想要跳转到IMMEDIATE-ANSWER这个地方 I want to go to a place called immediate answer. 1016 00:56:26,208 --> 00:56:27,296 这是基本步骤 It's the base step. 1017 00:56:33,150 --> 00:56:34,352 它对应在这里 Now, that's somewhere over here, 1018 00:56:35,920 --> 00:56:36,896 也就是在FIB-DONE的上方 just above done. 1019 00:56:37,750 --> 00:56:38,640 我们稍后就会看到 And we'll see it later. 1020 00:56:39,424 --> 00:56:40,704 现在 对于一般情况来说 Now, in the general case, 1021 00:56:40,720 --> 00:56:42,448 也就是我现在要写的 which is the part I'm going to write down now, 1022 00:56:43,136 --> 00:56:44,192 是这样的 let's just do it. 1023 00:56:44,912 --> 00:56:48,200 首先呢 我需要调用斐波那契函数两次 Well, first of all, I'm going to have to call Fibonacci twice. 1024 00:56:49,420 --> 00:56:52,544 在每一次中 -- 至少在其中一次 In each case-- well, in one case at least, 1025 00:56:52,780 --> 00:56:53,952 我得需要知道该怎么做 I'm going to have to know what to do 1026 00:56:53,968 --> 00:56:55,360 才能回过头来进行另外一个计算 to come back and do the next one. 1027 00:56:56,310 --> 00:56:58,368 我需要记住 I have to remember, 1028 00:56:59,200 --> 00:57:01,232 我计算完第一个FIB了么? have I done the first Fib, 1029 00:57:01,264 --> 00:57:02,544 或者第二个也计算完了? or have I done the second one? 1030 00:57:04,500 --> 00:57:07,040 我是该返回到计算第二个FIB的地方 Do I have to come back to the place where I do the second Fib, 1031 00:57:07,072 --> 00:57:09,088 还是回到执行ADD的地方 or do I have to come back to the place where I do the add? 1032 00:57:10,128 --> 00:57:12,112 无论哪种情况 我都需要-- In both cases I going to need, I don't 1033 00:57:12,140 --> 00:57:14,464 在第一个计算第一个FIB时 In the first case, over the first Fibonacci, 1034 00:57:14,512 --> 00:57:16,980 我需要保存N的值 来计算第二个FIB I'm going to need the value of N for computing for the second one. 1035 00:57:19,840 --> 00:57:21,584 因此我要把这些东西保存起来 So I have to store some of these things up. 1036 00:57:23,360 --> 00:57:24,896 首先要保存CONTINUE So first I'm going to save continue. 1037 00:57:26,192 --> 00:57:27,328 也就是答案的接收者 That's who needs the answer. 1038 00:57:31,320 --> 00:57:32,464 我之所以要这么做 And the reason I'm doing that 1039 00:57:32,480 --> 00:57:34,208 是因为我现在要把CONTINUE赋值为 is because I'm about to assign continue 1040 00:57:40,112 --> 00:57:44,320 我待会儿想要返回的地方 to the place which is the place I want to go to after. 1041 00:57:46,832 --> 00:57:50,272 我们把它叫做AFTER-FIB-N-1 Let's call it Fib-N-minus-1, 1042 00:57:51,040 --> 00:57:53,760 这个长名字 非常具有Lisp的命名特点 big long name, classic Lisp name. 1043 00:57:57,360 --> 00:58:00,224 这是因为我先要计算第一个(FIB (- N 1)) Because I'm going to compute the first Fib of N minus 1, 1044 00:58:00,840 --> 00:58:01,728 计算完成之后 and then after that, 1045 00:58:01,728 --> 00:58:03,290 我想要回过头来做些其它事 I want to come back and do something else. 1046 00:58:03,960 --> 00:58:06,528 而AFTER-FIB-N-1这个地方 That's the place I want to go to after I've done 1047 00:58:07,552 --> 00:58:09,488 就是我计算完第一个FIB后应该返回的地方 the first Fibonacci calculation. 1048 00:58:11,520 --> 00:58:13,136 接下来我要保存N And I want to do a save of N, 1049 00:58:14,416 --> 00:58:17,264 因为我稍后需要用到它 because I'm going to need it later, after that. 1050 00:58:19,130 --> 00:58:20,544 在这里 我就已经 Now I'm going to, at this point, 1051 00:58:20,672 --> 00:58:22,848 准备好计算(FIB (- N 1))了 get ready to do the Fibonacci of N minus 1. 1052 00:58:23,024 --> 00:58:33,950 (ASSIGN N (- (FETCH N) 1)) So assign to N the difference of the fetch of N and 1. 1053 00:58:38,110 --> 00:58:40,270 现在 该跳转到FIB-LOOP了 Now I'm ready to go back to doing the Fib loop. 1054 00:58:47,184 --> 00:58:49,872 我满足我立下的约定么? Do I have... Have I satisfied my contract? 1055 00:58:50,400 --> 00:58:51,504 答案是是的 And the answer is yes. 1056 00:58:51,770 --> 00:58:55,120 N现在存储的是N-1 这是我需要的 N contains N minus 1, which is what I need. 1057 00:58:56,432 --> 00:59:00,096 而CONTINUE包含的是计算完成后 返回的目的地 OK? Continue contains a place I want to go to when I'm done 1058 00:59:01,280 --> 00:59:03,072 也就是计算(FIB (- N 1))完成之后 with calculating FIB N minus 1. 1059 00:59:04,100 --> 00:59:05,440 因此我满足了这些约定 So I've satisfied the contract. 1060 00:59:05,440 --> 00:59:09,024 因此 我就可以在这里写下一个标签 And therefore, I can write down here a tag, after, a label, 1061 00:59:11,472 --> 00:59:17,568 AFTER-FIB-N-1 after-Fib-N-minus-1. 1062 00:59:20,490 --> 00:59:21,632 在这里 我又该做些什么呢? Now what am I going to do here? 1063 00:59:22,690 --> 00:59:23,616 在这里 Here's a place 1064 00:59:23,952 --> 00:59:26,750 我已经准备好去计算(FIB (- N 2))了 where I now have to get ready to do Fib of N minus 2. 1065 00:59:29,270 --> 00:59:30,720 但是为了计算(FIB (- N 2)) But in order to do a Fib of N minus 2, 1066 00:59:30,752 --> 00:59:31,630 首先 我不知道 look, I don't know. 1067 00:59:31,780 --> 00:59:33,408 这里 我已经改变了N I've clobbered my N over here. 1068 00:59:33,810 --> 00:59:35,472 或者在这个时候 我的N总是不断地 And presumably my N is counted down 1069 00:59:37,856 --> 00:59:38,800 向1或者0递减 all the way to 1 or 0 or something at this point. 1070 00:59:39,780 --> 00:59:42,512 所以我不知道N寄存器中存储的到底是什么 So I don't know what the value of N in the N register is. 1071 00:59:43,030 --> 00:59:44,752 我想要保存在栈中的N的值 I want the value of N that was on the stack 1072 00:59:44,800 --> 00:59:46,000 也就是我在这里保存的值 that I saved over here 1073 00:59:46,176 --> 00:59:47,888 这样我就可以在这里恢复它 so that could restore it over here. 1074 00:59:49,520 --> 00:59:51,024 我在这里存储的N I saved up the value of N, 1075 00:59:51,150 --> 00:59:54,496 是这个时间点N的值 which is this value of N at this point, 1076 00:59:54,896 --> 00:59:57,376 因此计算完(FIB (- N 1))之后我可以恢复它 so that I could restore it after computing Fib of N minus 1, 1077 00:59:57,530 --> 00:59:59,360 这样的话 我就可以计算(- N 2) so that I could count that down to N minus 2 1078 00:59:59,392 --> 01:00:00,860 然后就可以计算(FIB (- N 2))的值 and then compute Fib of N minus 2. 1079 01:00:01,810 --> 01:00:02,752 现在让我们来恢复它 So let's restore that. 1080 01:00:08,830 --> 01:00:09,776 (RESTORE N) Restore of N. 1081 01:00:11,130 --> 01:00:15,984 现在我要做一件很教条的事 Now I'm about to do something which is superstitious, 1082 01:00:16,000 --> 01:00:17,408 我们会尽快将其删除 and we will remove it shortly. 1083 01:00:18,520 --> 01:00:20,480 如果你们愿意的话 I am about to finish the sequence 1084 01:00:20,592 --> 01:00:23,440 我将要结束子过程调用 of doing the subroutine call, if you will. 1085 01:00:24,800 --> 01:00:25,952 接下来我会说 I'm going to say, well, 1086 01:00:26,064 --> 01:00:27,904 因为我保存了CONTINUE I also saved up the continuation, 1087 01:00:28,480 --> 01:00:30,432 现在就要去恢复它 since I'm going to restore it now. 1088 01:00:31,600 --> 01:00:32,608 但实际上 我并不需要这么做 But actually, I don't have to, 1089 01:00:32,640 --> 01:00:33,550 因为我并不需要用到它 because I'm not going to need it. 1090 01:00:34,610 --> 01:00:35,728 我们稍后会修正它 We'll fix that in a second. 1091 01:00:36,260 --> 01:00:37,952 现在我们来恢复CONTINUE So we'll do a restore of continue, 1092 01:00:46,048 --> 01:00:48,020 通常来说 我都会这么做 which is what I would in general need to do. 1093 01:00:48,020 --> 01:00:49,232 我们将要看到 And we're just going to see whats called 1094 01:00:49,312 --> 01:00:52,144 编译器领域中的“窥孔优化” what you would call in the compiler world a peephole optimization, 1095 01:00:52,272 --> 01:00:53,728 来帮我们消除这个不必要的步骤 which says, whoops, you didn't have to do that. 1096 01:00:55,420 --> 01:00:57,104 因此 我即将要做的就是 OK, so the next thing I see here 1097 01:00:58,464 --> 01:01:02,288 准备好计算(FIB (- N 2)) is that I have to get ready now to do Fibonacci of N minus 2. 1098 01:01:02,770 --> 01:01:04,496 但是我不再需要保存N了 But I don't have to save N anymore. 1099 01:01:05,050 --> 01:01:06,720 原因就是 The reason why I don't have to save N anymore 1100 01:01:06,800 --> 01:01:09,344 计算完(FIB (- N 2))之后 我就不需要N了 is because I don't need N after I've done Fib of N minus 2, 1101 01:01:09,360 --> 01:01:10,720 因为 我接下来要做的就是ADD because the next thing I do is add. 1102 01:01:13,540 --> 01:01:15,856 因此 我会这么来设置N So I'm just going to set up my N that way. 1103 01:01:16,608 --> 01:01:28,990 (ASSIGN N (- (FETCH N) 2)) Assign N minus difference of fetch N and 2. 1104 01:01:31,850 --> 01:01:34,016 现在我需要结束 Now I have to finish the setup 1105 01:01:34,272 --> 01:01:36,730 调用(FIB (- N 2))的设置过程了 for calling Fibonacci of N minus 2. 1106 01:01:36,950 --> 01:01:38,336 我需要保存CONTINUE Well, I have to save up continue 1107 01:01:44,224 --> 01:01:49,024 然后把CONTINUE赋值为 and assign continue, continue, 1108 01:01:52,304 --> 01:01:59,952 AFTER-FIB-N-2 to the place which is after Fib N 2, 1109 01:02:02,576 --> 01:02:04,032 对应了那边代码的某处 that place over here somewhere. 1110 01:02:05,320 --> 01:02:07,232 然而 我需要非常小心 However, I've got to be very careful. 1111 01:02:08,650 --> 01:02:11,424 而(FIB (- N 1))的值 The old value, the value of Fib of N minus 1, 1112 01:02:12,064 --> 01:02:13,120 我稍后会用到 I'm going to need later. 1113 01:02:15,300 --> 01:02:17,376 (FIB (- N 1))的值 The value of Fibonacci of N minus 1, 1114 01:02:17,616 --> 01:02:18,480 我需要它的值 I'm going to need. 1115 01:02:18,784 --> 01:02:19,808 我不能去改变它 And I can't clobber it, 1116 01:02:21,072 --> 01:02:23,600 因为我需要用它来加上(FIB (- N 2)) because I'm going to have to add it to the value of Fib of N minus 2. 1117 01:02:24,150 --> 01:02:25,888 它是存放在寄存器中的 因此我需要保存它 That's in the value register, so I'm going to save it. 1118 01:02:27,792 --> 01:02:32,608 所以现在我要用(SAVE VAL)来保存它 So I have to save this right now, save up VAL. 1119 01:02:33,780 --> 01:02:35,440 现在我就可以调用子过程了 And now I can go off to my subroutine, 1120 01:02:36,672 --> 01:02:39,540 (GOTO FIB-LOOP) go to Fib loop. 1121 01:02:44,220 --> 01:02:46,576 现在 在进行更进一步计算之前 Now before I go any further 1122 01:02:46,800 --> 01:02:49,360 在结束这个程序之前 and finish this program, 1123 01:02:49,392 --> 01:02:51,050 我想审视一下目前的代码片段 I just want to look at this segment so far 1124 01:02:51,232 --> 01:02:56,000 这里有一系列的指令 and see, oh yes, there's a sequence of instructions here, if you will 1125 01:02:57,840 --> 01:02:59,088 我可以对它们进行某些操作 that I can do something about. 1126 01:03:01,580 --> 01:03:03,200 这里 我有一个操作用来恢复CONTINUE Here I have a restore of continue, 1127 01:03:04,256 --> 01:03:05,488 一个操作用来保存CONTINUE a save of continue, 1128 01:03:06,016 --> 01:03:07,408 然后给CONTINUE赋值 and then an assign of continue, 1129 01:03:08,704 --> 01:03:10,640 但这之中没有CONTINUE的其它引用 with no other references to continue in between. 1130 01:03:13,840 --> 01:03:15,488 恢复之后又保存 The restore followed by the save 1131 01:03:15,504 --> 01:03:16,670 使得栈没有被修改 leaves the stack unchanged. 1132 01:03:19,090 --> 01:03:21,728 唯一的区别就是 我给CONTINUE寄存器赋了值 The only difference is that I set the continue register to a value, 1133 01:03:21,968 --> 01:03:23,280 一个存放在栈上的值 which is the value that was on the stack. 1134 01:03:24,330 --> 01:03:25,792 由于我现在改变了这个值 Since I now clobber that value, 1135 01:03:26,448 --> 01:03:27,936 但这之间并没有引用这个值 as in it was never referenced, 1136 01:03:28,592 --> 01:03:30,096 这些指令就是不必要的 these instructions are unnecessary. 1137 01:03:31,760 --> 01:03:35,390 因此我们会移除它们 So we will remove these. 1138 01:03:38,880 --> 01:03:40,784 但我只有先把它们写出来 才会发现这个情况 But I couldn't have seen that unless I had written them down. 1139 01:03:43,780 --> 01:03:44,720 真是这样吗? Was that really true? 1140 01:03:45,776 --> 01:03:46,608 我并不知道 Well, I don't know. 1141 01:03:48,610 --> 01:03:52,912 现在 我们要开始计算(FIB (- N 2))了 OK, so we've now gone off to compute Fibonacci of N minus 2. 1142 01:03:53,660 --> 01:03:54,592 计算完毕后 So after that, 1143 01:04:02,960 --> 01:04:03,856 我们又要做什么呢? what are we going to do? 1144 01:04:05,070 --> 01:04:06,768 我想 我们首先要做的就是 Well, I suppose the first thing we have to do-- 1145 01:04:06,992 --> 01:04:07,888 我们有两件事要做 we've got two things. 1146 01:04:07,960 --> 01:04:10,496 目前VAL寄存器中的值 是有意义的 We've got a thing in the value register which is now valuable. 1147 01:04:10,920 --> 01:04:11,984 然而 栈上也有一个数据 We also have a thing on the stack 1148 01:04:12,048 --> 01:04:13,632 需要恢复到VAL寄存器中 can be restored into the value register. 1149 01:04:14,810 --> 01:04:16,576 现在我需要非常小心的是 And what I have to be careful with now 1150 01:04:16,880 --> 01:04:18,992 正确地给它们排序 以便计算乘法 is I want to shuffle this right so I can do the multiply. 1151 01:04:19,470 --> 01:04:21,248 现在 我可能会使用不同的约定 Now there are various conventions I might use, 1152 01:04:21,472 --> 01:04:23,520 但我现在会采用非常挑剔的一种 but I'm going to be very picky and say, 1153 01:04:23,552 --> 01:04:25,888 栈上数据来自于哪个寄存器 就恢复到那个寄存器中 I'm only going to restore into a register I've saved from. 1154 01:04:26,740 --> 01:04:28,288 如果是这样的话 在这里我就要进行洗牌 If that's the case, I have to do a shuffle here. 1155 01:04:29,248 --> 01:04:31,840 这跟我有多少只手是同样的问题 It's the same problem with how many hands I have. 1156 01:04:32,688 --> 01:04:37,136 现在我要给N赋值 So I'm going to assign to N, 1157 01:04:37,168 --> 01:04:39,376 因为我现在不再需要N了 N是无用的 because I'm not going to need N anymore, N is useless, 1158 01:04:39,920 --> 01:04:41,216 获取当前VAL寄存器的值 the current value of VAL, 1159 01:04:45,216 --> 01:04:47,340 也就是(FIB (- N 2))的值 which was the value of Fib of N minus 2. 1160 01:04:52,950 --> 01:04:56,352 现在 我就要恢复VAL寄存器了 And I'm going to restore the value register now. 1161 01:05:01,850 --> 01:05:03,920 这个RESTORE匹配这里的SAVE This restore matches this save. 1162 01:05:05,584 --> 01:05:08,832 如果你非常仔细地研究发生了什么 And if you're very careful and examine very carefully what goes on, 1163 01:05:09,216 --> 01:05:11,968 会发现 RESTORE和SAVE总是成对的 OK? restores and saves are always matched. 1164 01:05:13,840 --> 01:05:15,152 现在 这里有个额外的SAVE Now there's an outstanding save, 1165 01:05:15,184 --> 01:05:16,384 当然 我们很快就会消灭它 of course, that we have to get rid of soon. 1166 01:05:19,000 --> 01:05:20,590 恢复完VAL寄存器后 And so I restored the value register. 1167 01:05:20,944 --> 01:05:22,576 我就要恢复CONTINUE寄存器了 Now I restore the continue one, 1168 01:05:31,152 --> 01:05:32,400 它匹配了这个 which matches this one, 1169 01:05:34,800 --> 01:05:37,856 从这里到这里 dot, dot, dot, dot, dot, dot, dot, down to here, 1170 01:05:40,592 --> 01:05:42,464 这样就恢复了继续 Now restoring that continuation. 1171 01:05:42,860 --> 01:05:45,712 这个表达式继续是由(FIB N)产生的 That continuation is a continuation of Fib of N, 1172 01:05:46,460 --> 01:05:47,840 也就是我正尝试求解的 which is the problem I was trying to solve, 1173 01:05:47,856 --> 01:05:49,320 最主要的问题 a major problem I'm trying to solve. 1174 01:05:49,984 --> 01:05:52,352 我需要把(FIB N)的答案返回给这个继续 So that's the guy I have to go back to who wants Fib of N. 1175 01:05:52,544 --> 01:05:54,032 在我意识到N并不小于2之前 I saved them all the way up here 1176 01:05:54,160 --> 01:05:56,608 我一直保存着它们 when I realized N was not less than 2. 1177 01:05:57,360 --> 01:05:59,072 因此 我需要进行一个复杂的运算 And so I had to do a complicated operation. 1178 01:06:00,840 --> 01:06:02,576 现在万事俱备 Now I've got everything I need to do it. 1179 01:06:03,240 --> 01:06:04,368 因此我要恢复它们 So I'm going to restore that, 1180 01:06:05,420 --> 01:06:21,088 (ASSIGN VAL (+ (FETCH VAL) (FETCH N))) assign to VAL the sum of fetch VAL and fetch of N 1181 01:06:27,440 --> 01:06:28,608 然后跳转到CONTINUE and go to continue. 1182 01:06:38,260 --> 01:06:44,784 然后我就从(FIB N)中返回了出来 So now I've returned from computing Fibonacci of N, 1183 01:06:45,392 --> 01:06:46,576 也就是FIB的一般情况 the general case. 1184 01:06:47,110 --> 01:06:50,608 现在还有一些细节 需要我们填充 Now what's left is we have to fix up a few details, 1185 01:06:50,992 --> 01:06:55,536 比如归纳的基本情况:可以立即得到答案 like there's the base case of this induction, immediate answer, 1186 01:07:02,540 --> 01:07:06,592 这不过就是 as, which is nothing more than 1187 01:07:06,608 --> 01:07:11,850 (ASSIGN VAL (FETCH N) assign to VAL fetch of N, 1188 01:07:13,640 --> 01:07:15,472 因为N小于2 because N was less than 2, 1189 01:07:15,504 --> 01:07:16,890 因此答案就是N and therefore, the answer is N 1190 01:07:16,990 --> 01:07:18,192 跟源程序是一致的 in our original program, 1191 01:07:19,230 --> 01:07:26,480 (GOTO (FETCH CONTINUE)) and return continue-- 1192 01:07:31,248 --> 01:07:36,130 最后就结束了 bobble, bobble almost-- and finally Fib done. 1193 01:07:43,460 --> 01:07:45,640 这是个相当复杂的程序 So that's a fairly complicated program. 1194 01:07:45,640 --> 01:07:47,344 我之所以给你们演示这个程序 And the reason I wanted you see to that 1195 01:07:47,500 --> 01:07:49,216 是因为我想让你们见识 is because I want you to see the particular 1196 01:07:49,456 --> 01:07:52,672 我所遵守的栈使用准则 flavors of stack discipline that I was obeying. 1197 01:07:53,328 --> 01:07:55,216 第一点就是 我不想保存那些 It was first of all, I don't want to save anything 1198 01:07:56,928 --> 01:07:58,128 稍后不需要的值 that I'm not going to need later. 1199 01:08:00,576 --> 01:08:01,850 我非常地小心 I was being very careful. 1200 01:08:01,850 --> 01:08:02,912 这非常重要 And it's very important. 1201 01:08:03,940 --> 01:08:06,528 当然 人们还制定了其它的准则 And there are all sorts of other disciplines people make 1202 01:08:07,376 --> 01:08:09,616 来操作栈帧之类的东西 with frames and things like that of some sort, 1203 01:08:10,190 --> 01:08:11,392 这些准则中 那些不再需要的东西 where you save all sorts of junk 1204 01:08:11,408 --> 01:08:12,640 也需要保存并恢复 you're not going to need later and restore it 1205 01:08:12,672 --> 01:08:15,260 因为从某种意义上来说 这样做更容易些 because, in some sense, it's easier to do that. 1206 01:08:15,830 --> 01:08:17,408 但这会带来各种灾难 That's going to lead to various disasters, 1207 01:08:18,592 --> 01:08:20,256 我们稍后就会见识一些 which we'll see a little later. 1208 01:08:21,440 --> 01:08:24,240 只保存那些你稍后需要的值 这很关键 It's crucial to save exactly what you're going to need later. 1209 01:08:26,890 --> 01:08:28,016 这是非常重要的理念 It's an important idea. 1210 01:08:29,872 --> 01:08:33,360 无论谁保存了一个值 都应该由他来恢复 And the responsibility of that is whoever saves something 1211 01:08:33,760 --> 01:08:35,328 因为他需要这个值 is the guy who restores it, because he needs it. 1212 01:08:36,930 --> 01:08:38,544 在这样的准则中 And in such discipline, 1213 01:08:38,864 --> 01:08:40,768 你可以发现哪些数据是不必要的 you can see what things are unnecessary, 1214 01:08:43,456 --> 01:08:44,736 哪些操作又是不重要的 operations that are unimportant. 1215 01:08:47,150 --> 01:08:50,400 我还想告诉你们 Now, one other thing I want to tell you about is very simple 1216 01:08:51,664 --> 01:08:54,672 当然 你们看到的并不是全部的图景 is that, of course, the picture you see is not the whole picture. 1217 01:08:55,350 --> 01:08:56,688 假设我的系统中 Supposing I had systems 1218 01:08:56,800 --> 01:09:01,520 具有像CAR、CDR、CONS这样的运算 had things like other operations, CAR, CDR, CONS, 1219 01:09:03,536 --> 01:09:05,600 或者创建一个向量 building a vector 1220 01:09:05,888 --> 01:09:07,328 并引用它的第N个元素 and referencing the nth element of it, 1221 01:09:08,304 --> 01:09:09,216 等等运算 or things like that. 1222 01:09:10,400 --> 01:09:13,600 然而 就在这个层次的细节来说 Well, at this level of detail, whatever it is, 1223 01:09:13,872 --> 01:09:17,856 我们可以在数据通路中把它们视为基本运算 we can conceptualize those as primitive operations in the datapath. 1224 01:09:18,752 --> 01:09:21,952 换句话说 我们可以认为 有一台机器 In other words, we could say that some machine that, for example, has 1225 01:09:22,320 --> 01:09:24,112 包含了APPEND机器 has the append machine, 1226 01:09:24,208 --> 01:09:26,464 它通过(CONS (CAR X) which has to do cons of the CAR of x 1227 01:09:26,640 --> 01:09:29,808 (APPEND (CDR X) Y)来实现 with the append of the CDR of x and y, 1228 01:09:29,888 --> 01:09:33,184 哦 天啊 这就跟阶乘机器有相同的结构 well, gee, that's exactly the same as the factorial structure. 1229 01:09:33,630 --> 01:09:35,296 当然 它有相同的结构 Well, it's got about the same structure. 1230 01:09:36,544 --> 01:09:37,270 我们有什么呢? And what do we have? 1231 01:09:37,270 --> 01:09:39,392 我们有某种东西 其中有 We have some sort of things in it 1232 01:09:39,760 --> 01:09:42,480 诸如X、Y之类的寄存器 which may be registers, x and y, 1233 01:09:42,510 --> 01:09:45,120 有时X会移动到Y中 and then x has to somehow move to y sometimes, 1234 01:09:45,280 --> 01:09:46,750 或者X会取得Y的值 x has to get the value of y. 1235 01:09:46,930 --> 01:09:50,112 我们或许要需要能够进行CONS运算 And then we may have to be able to do something which is a cons. 1236 01:09:51,700 --> 01:09:57,744 我记不清这个系统中是否需要这样的东西 I don't remember if I need to like this is in this system, 1237 01:09:57,760 --> 01:10:01,100 但CONS有点类似于减法器或加法器之类的东西 but cons is sort of like subtract or add or something. 1238 01:10:01,420 --> 01:10:02,704 它把两个东西结合起来 It combines two things, 1239 01:10:02,736 --> 01:10:04,272 然后产生一个序对 producing a thing which is the cons, 1240 01:10:04,512 --> 01:10:06,496 然后会把输出结果送入到这里 which we may then think goes into there. 1241 01:10:07,600 --> 01:10:09,728 可能还有一个叫做CAR的组件 And then maybe a thing called the CAR, 1242 01:10:12,880 --> 01:10:16,224 它的结果是 -- 某个东西的CAR部分 which will produce-- I can get the CAR or something. 1243 01:10:16,920 --> 01:10:19,552 我还可以取得某物的CDR部分 等等 And maybe I can get the CDR of something, and so on. 1244 01:10:20,150 --> 01:10:22,304 但我们不应该害怕这么说 But we shouldn't be too afraid of saying things this way, 1245 01:10:22,928 --> 01:10:24,240 因为最坏的情况不过 because the worst that could happen 1246 01:10:24,944 --> 01:10:26,416 当我们打开CONS后 is if we open up cons, 1247 01:10:27,312 --> 01:10:29,824 会发现其中存在某台机器 what we're going to find is some machine. 1248 01:10:31,888 --> 01:10:34,448 CONS可能会与CAR和CDR有所重叠 And cons may in fact overlap with CAR and CDR, and it always does, 1249 01:10:35,504 --> 01:10:38,128 就像加法和减法有所重叠一样 in the same way that plus and minus overlap, 1250 01:10:38,576 --> 01:10:39,856 它们本质上都是一样的 and really the same business. 1251 01:10:41,210 --> 01:10:42,608 CONS、CAR和CDR将会有所重叠 CONS, CAR, and CDR are going to overlap, 1252 01:10:42,624 --> 01:10:44,528 我们会发现其中有小型控制器 and we're going to find a little controller, 1253 01:10:45,504 --> 01:10:46,544 小型的数据通路 a little datapath, 1254 01:10:48,032 --> 01:10:49,648 其中还有一些寄存器 which may have some registers in it, 1255 01:10:50,000 --> 01:10:52,864 一些其它的像这样的东西 some stuff like that. 1256 01:10:53,300 --> 01:10:54,416 并且 也许在这之中 And maybe inside it, 1257 01:10:54,432 --> 01:10:56,160 可能也有无穷的部分 there may also be an infinite part, 1258 01:10:56,464 --> 01:10:58,704 又或者是半无穷的 之类的 a part that's semi-infinite or something, 1259 01:10:58,816 --> 01:11:00,656 这些都是统一的东西 which is a lot of very uniform stuff, 1260 01:11:00,960 --> 01:11:02,030 也就是我们所谓的“内存” which we'll call memory. 1261 01:11:06,570 --> 01:11:08,832 有限的内存也能无穷地存储 对此我一点也不吃惊 And I wouldn't be so horrified if that were the way it works. 1262 01:11:09,330 --> 01:11:11,072 实际上它就是这样的 我们之后就会了解 In fact, it does, and we'll talk about that later. 1263 01:11:13,320 --> 01:11:14,570 那么 有什么疑问么? So are there any questions? 1264 01:11:24,340 --> 01:11:25,808 天啊!你们都一言不发 Gee, what an unquestioning audience. 1265 01:11:28,670 --> 01:11:30,330 假设我说得都是谎言吧! Suppose I tell you a horrible pile of lies. 1266 01:11:39,690 --> 01:11:40,384 好吧 OK. 1267 01:11:41,990 --> 01:11:42,520 谢谢大家 Well, thank you. 1268 01:11:42,520 --> 01:11:43,280 我们下课吧! Let's take our break. 1269 01:11:44,230 --> 01:11:48,780 MIT OpenCourseWare http://ocw.mit.edu 1270 01:11:48,780 --> 01:11:55,152 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtCN/lec9b.eng.srt ================================================ 1 00:00:15,840 --> 00:00:29,730 PROFESSOR: Well, I hope you appreciate that we have inducted you into some real magic, the magic of building languages, really building new languages. 2 00:00:29,730 --> 00:00:30,430 What have we looked at? 3 00:00:30,430 --> 00:00:42,360 We've looked at an Escher picture language: this language invented by Peter Henderson. 4 00:00:42,360 --> 00:00:46,260 We looked at digital logic language. 5 00:00:53,260 --> 00:00:53,570 Let's see. 6 00:00:53,570 --> 00:00:55,360 We've looked at the query language. 7 00:00:59,700 --> 00:01:08,250 And the thing you should realize is, even though these were toy examples, they really are the kernels of really useful things. 8 00:01:08,250 --> 00:01:23,300 So, for instance, the Escher picture language was taken by Henry Wu, who's a student at MIT, and developed into a real language for laying out PC boards based just on extending those structures. 9 00:01:23,300 --> 00:01:33,460 And the digital logic language, Jerry mentioned when he showed it to you, was really extended to be used as the basis for a simulator that was used to design a real computer. 10 00:01:33,460 --> 00:01:37,510 And the query language, of course, is kind of the germ of prologue. 11 00:01:37,510 --> 00:01:41,080 So we built all of these languages, they're all based on LISP. 12 00:01:43,630 --> 00:01:48,820 A lot of people ask what particular problems is LISP good for solving for? 13 00:01:48,820 --> 00:02:01,470 The answer is LISP is not good for solving any particular problems. What LISP is good for is constructing within it the right language to solve the problems you want to solve, and that's how you should think about it. 14 00:02:01,470 --> 00:02:04,326 So all of these languages were based on LISP. 15 00:02:04,326 --> 00:02:07,270 Now, what's LISP based on? 16 00:02:07,270 --> 00:02:07,920 Where's that come from? 17 00:02:07,920 --> 00:02:09,400 Well, we looked at that too. 18 00:02:12,740 --> 00:02:25,810 We looked at the meta-circular evaluator and said well, LISP is based on LISP. 19 00:02:25,810 --> 00:02:29,950 And when we start looking at that, we've got to do some real magic, right? 20 00:02:29,950 --> 00:02:31,660 So what does that mean, right? 21 00:02:31,660 --> 00:02:47,470 Why operators, and fixed points, and the idea that what this means is that LISP is somehow the fixed-point equation for this funny set of things which are defined in terms of themselves. 22 00:02:47,470 --> 00:02:49,070 Now, it's real magic. 23 00:02:49,070 --> 00:02:54,250 Well, today, for a final piece of magic, we're going to make all the magic go away. 24 00:03:06,430 --> 00:03:09,770 We already know how to do that. 25 00:03:09,770 --> 00:03:15,500 The idea is, we're going to take the register machine architecture and show how to implement LISP on terms of that. 26 00:03:15,500 --> 00:03:24,800 And, remember, the idea of the register machine is that there's a fixed and finite part of the machine. 27 00:03:24,800 --> 00:03:30,510 There's a finite-state controller, which does some particular thing with a particular amount of hardware. 28 00:03:30,510 --> 00:03:33,550 There are particular data paths: the operation the machine does. 29 00:03:33,550 --> 00:03:42,060 And then, in order to implement recursion and sustain the illusion of infinity, there's some large amount of memory, which is the stack. 30 00:03:42,060 --> 00:03:49,850 So, if we implement LISP in terms of a register machine, then everything ought to become, at this point, completely concrete. 31 00:03:49,850 --> 00:03:51,650 All the magic should go away. 32 00:03:51,650 --> 00:04:04,720 And, by the end of this talk, I want you get the feeling that, as opposed to this very mysterious meta-circular evaluator, that a LISP evaluator really is something that's concrete enough that you can hold in the palm of your hand. 33 00:04:04,720 --> 00:04:09,546 You should be able to imagine holding a LISP interpreter there. 34 00:04:09,546 --> 00:04:10,950 All right, how are we going to do this? 35 00:04:10,950 --> 00:04:13,960 We already have all the ingredients. 36 00:04:13,960 --> 00:04:28,210 See, what you learned last time from Jerry is how to take any particular couple of LISP procedures and hand-translate them into something that runs on a register machine. 37 00:04:28,210 --> 00:04:39,120 So, to implement all of LISP on a register machine, all we have to do is take the particular procedures that are the meta-circular evaluator and hand-translate them for a register machine. 38 00:04:39,120 --> 00:04:42,320 And that does all of LISP, right? 39 00:04:42,320 --> 00:04:45,380 So, in principle, we already know how to do this. 40 00:04:45,380 --> 00:04:54,670 And, indeed, it's going to be no different, in kind, from translating, say, recursive factorial or recursive Fibonacci. 41 00:04:54,670 --> 00:04:56,840 It's just bigger and there's more of it. 42 00:04:56,840 --> 00:05:01,730 So it'd just be more details, but nothing really conceptually new. 43 00:05:01,730 --> 00:05:14,810 All right, also, when we've done that, and the thing is completely explicit, and we see how to implement LISP in terms of the actual sequential register operations, that's going to be our final most explicit model of LISP in this course. 44 00:05:14,810 --> 00:05:16,950 And, remember, that's a progression through this course. 45 00:05:16,950 --> 00:05:20,370 We started out with substitution, which is sort of like algebra. 46 00:05:20,370 --> 00:05:26,390 And then we went to the environment model, which talked about the actual frames and how they got linked together. 47 00:05:26,390 --> 00:05:31,080 And then we made that more concrete in the meta-circular evaluator. 48 00:05:31,080 --> 00:05:34,360 There are things the meta-circular evaluator doesn't tell us. 49 00:05:34,360 --> 00:05:36,090 You should realize that. 50 00:05:36,090 --> 00:05:47,210 For instance, it left unanswered the question of how a procedure, like recursive factorial here , somehow takes space that grows. 51 00:05:47,210 --> 00:05:56,760 On the other hand, a procedure which also looks syntactically recursive, called fact-iter, somehow doesn't take space. 52 00:05:56,760 --> 00:06:01,960 We justify that it doesn't need to take space by showing the substitution model. 53 00:06:01,960 --> 00:06:12,520 But we didn't really say how it happens that the machine manages to do that, that that has to do with the details of how arguments are passed to procedures. 54 00:06:12,520 --> 00:06:23,510 And that's the thing we didn't see in the meta-circular evaluator precisely because the way arguments got passed to procedures in this LISP depended on the way arguments got passed to procedures in this LISP. 55 00:06:26,070 --> 00:06:30,740 But, now, that's going to become extremely explicit. 56 00:06:30,740 --> 00:06:31,230 OK. 57 00:06:31,230 --> 00:06:43,250 Well, before going on to the evaluator, let me just give you a sense of what a whole LISP system looks like so you can see the parts we're going to talk about and the parts we're not going to talk about. 58 00:06:43,250 --> 00:06:52,525 Let's see, over here is a happy LISP user, and the LISP user is talking to something called the reader. 59 00:07:00,360 --> 00:07:19,210 The reader's job in life is to take characters from the user and turn them into data structures in something called a list structure memory. 60 00:07:29,783 --> 00:07:42,340 All right, so the reader is going to take symbols, parentheses, and A's and B's, and ones and threes that you type in, and turn these into actual list structure: pairs, and pointers, and things. 61 00:07:42,340 --> 00:07:45,850 And so, by the time evaluator is going, there are no characters in the world. 62 00:07:45,850 --> 00:07:56,280 And, of course, in more modern list systems, there's sort of a big morass here that might sit between the user and the reader: Windows systems, and top levels, and mice, and all kinds of things. 63 00:07:56,280 --> 00:07:59,590 But conceptually, characters are coming in. 64 00:07:59,590 --> 00:08:17,090 All right, the reader transforms these into pointers to stuff in this memory, and that's what the evaluator sees, OK? 65 00:08:17,090 --> 00:08:19,780 The evaluator has a bunch of helpers. 66 00:08:19,780 --> 00:08:23,080 It has all possible primitive operators you might want. 67 00:08:23,080 --> 00:08:35,960 So there's a completely separate box, a floating point unit, or all sorts of things, which do the primitive operators. 68 00:08:35,960 --> 00:08:42,080 And, if you want more special primitives, you build more primitive operators, but they're separate from the evaluator. 69 00:08:42,080 --> 00:08:47,400 The evaluator finally gets an answer and communicates that to the printer. 70 00:08:50,780 --> 00:09:05,540 And now, the printer's job in life is to take this list structure coming from the evaluator, and turn it back into characters, and communicate them to the user through whatever interface there is. 71 00:09:08,050 --> 00:09:08,810 OK. 72 00:09:08,810 --> 00:09:12,670 Well, today, what we're going to talk about is this evaluator. 73 00:09:12,670 --> 00:09:19,440 The primitive operators have nothing particular to do with LISP, they're however you like to implement primitive operations. 74 00:09:19,440 --> 00:09:24,420 The reader and printer are actually complicated, but we're not going to talk about them. 75 00:09:24,420 --> 00:09:29,900 They sort of have to do with details of how you might build up list structure from characters. 76 00:09:29,900 --> 00:09:32,490 So that is a long story, but we're not going to talk about it. 77 00:09:32,490 --> 00:09:36,930 The list structure memory, we'll talk about next time. 78 00:09:36,930 --> 00:09:46,295 So, pretty much, except for the details of reading and printing, the only mystery that's going to be left after you see the evaluator is how you build list structure on conventional memories. 79 00:09:46,295 --> 00:09:50,580 But we'll worry about that next time too. 80 00:09:50,580 --> 00:09:51,830 OK. 81 00:09:53,350 --> 00:09:56,110 Well, let's start talking about the evaluator. 82 00:09:56,110 --> 00:10:01,120 The one that we're going to show you, of course, is not, I think, nothing special about it. 83 00:10:01,120 --> 00:10:04,810 It's just a particular register machine that runs LISP. 84 00:10:04,810 --> 00:10:09,890 And it has seven registers, and here are the seven registers. 85 00:10:09,890 --> 00:10:18,370 There's a register, called EXP, and its job is to hold the expression to be evaluated. 86 00:10:18,370 --> 00:10:26,550 And by that, I mean it's going to hold a pointer to someplace in list structure memory that holds the expression to be evaluated. 87 00:10:26,550 --> 00:10:34,070 There's a register, called ENV, which holds the environment in which this expression is to be evaluated. 88 00:10:34,070 --> 00:10:34,940 And, again, I made a pointer. 89 00:10:34,940 --> 00:10:38,240 The environment is some data structure. 90 00:10:38,240 --> 00:10:44,630 There's a register, called FUN, which will hold the procedure to be applied when you go to apply a procedure. 91 00:10:44,630 --> 00:10:50,630 A register, called ARGL, which wants the list of evaluated arguments. 92 00:10:50,630 --> 00:10:53,140 What you can start seeing here is the basic structure of the evaluator. 93 00:10:53,140 --> 00:10:54,490 Remember how evaluators work. 94 00:10:54,490 --> 00:11:03,480 There's a piece that takes expressions and environments, and there's a piece that takes functions, or procedures and arguments. 95 00:11:03,480 --> 00:11:07,740 And going back and forth around here is the eval/apply loop. 96 00:11:07,740 --> 00:11:10,270 So those are the basic pieces of the eval and apply. 97 00:11:10,270 --> 00:11:11,610 Then there's some other things, there's continue. 98 00:11:11,610 --> 00:11:19,000 You just saw before how the continue register is used to implement recursion and stack discipline. 99 00:11:19,000 --> 00:11:24,190 There's a register that's going to hold the result of some evaluation. 100 00:11:24,190 --> 00:11:37,150 And then, besides that, there's one temporary register, called UNEV, which typically, in the evaluator, is going to be used to hold temporary pieces of the expression you're working on, which you haven't gotten around to evaluate yet, right? 101 00:11:37,150 --> 00:11:40,646 So there's my machine: a seven-register machine. 102 00:11:40,646 --> 00:11:48,480 And, of course, you might want to make a machine with a lot more registers to get better performance, but this is just a tiny, minimal one. 103 00:11:48,480 --> 00:11:49,780 Well, how about the data paths? 104 00:11:49,780 --> 00:11:55,100 This machine has a lot of special operations for LISP. 105 00:11:55,100 --> 00:12:00,120 So, here are some typical data paths. 106 00:12:00,120 --> 00:12:06,710 A typical one might be, oh, assign to the VAL register the contents of the EXP register. 107 00:12:06,710 --> 00:12:11,900 In terms of those diagrams you saw, that's a little button on some arrow. 108 00:12:11,900 --> 00:12:14,040 Here's a more complicated one. 109 00:12:14,040 --> 00:12:23,850 It says branch, if the thing in the expression register is a conditional to some label here, called the ev-conditional. 110 00:12:23,850 --> 00:12:26,230 And you can imagine this implemented in a lot of different ways. 111 00:12:26,230 --> 00:12:36,610 You might imagine this conditional test as a special purpose sub-routine, and conditional might be represented as some data abstraction that you don't care about at this level of detail. 112 00:12:36,610 --> 00:12:37,980 So that might be done as a sub-routine. 113 00:12:37,980 --> 00:12:45,350 This might be a machine with hardware-types, and conditional might be testing some bits for a particular code. 114 00:12:45,350 --> 00:12:50,190 There are all sorts of ways that's beneath the level of abstraction we're looking at. 115 00:12:50,190 --> 00:12:56,840 Another kind of operation, and there are a lot of different operations assigned to EXP, the first clause of what's in EXP. 116 00:12:56,840 --> 00:12:59,260 This might be part of processing a conditional. 117 00:12:59,260 --> 00:13:04,470 And, again, first clause is some selector whose details we don't care about. 118 00:13:04,470 --> 00:13:12,170 And you can, again, imagine that as a sub-routine which'll do some list operations, or you can imagine that as something that's built directly into hardware. 119 00:13:12,170 --> 00:13:19,740 The reason I keep saying you can imagine it built directly into hardware is even though there are a lot of operations, there are still a fixed number of them. 120 00:13:19,740 --> 00:13:22,370 I forget how many, maybe 150. 121 00:13:22,370 --> 00:13:26,400 So, it's plausible to think of building these directly into hardware. 122 00:13:26,400 --> 00:13:28,500 Here's a more complicated one. 123 00:13:28,500 --> 00:13:31,710 You can see this has to do with looking up the values of variables. 124 00:13:31,710 --> 00:13:42,850 It says assign to the VAL register the result of looking up the variable value of some particular expression, which, in this case, is supposed to be a variable in some environment. 125 00:13:42,850 --> 00:13:52,240 And this'll be some operation that searches through the environment structure, however it is represented, and goes and looks up that variable. 126 00:13:52,240 --> 00:13:55,790 And, again, that's below the level of detail that we're thinking about. 127 00:13:55,790 --> 00:14:00,380 This has to do with the details of the data structures for representing environments. 128 00:14:00,380 --> 00:14:05,940 But, anyway, there is this fixed and finite number of operations in the register machine. 129 00:14:08,500 --> 00:14:11,720 Well, what's its overall structure? 130 00:14:11,720 --> 00:14:14,930 Those are some typical operations. 131 00:14:14,930 --> 00:14:22,890 Remember what we have to do, we have to take the meta-circular evaluator-- and here's a piece of the meta-circular evaluator. 132 00:14:22,890 --> 00:14:28,310 This is the one using abstract syntax that's in the book. 133 00:14:28,310 --> 00:14:33,500 It's a little bit different from the one that Jerry shows you. 134 00:14:33,500 --> 00:14:48,560 And the main thing to remember about the evaluator is that it's doing some sort of case analysis on the kinds of expressions: so if it's either self-evaluated, or quoted, or whatever else. 135 00:14:48,560 --> 00:14:55,750 And then, in the general case where the expression it's looking at is an application, there's some tricky recursions going on. 136 00:14:55,750 --> 00:15:05,880 First of all, eval has to call itself both to evaluate the operator and to evaluate all the operands. 137 00:15:05,880 --> 00:15:12,270 So there's this sort of red recursion of values walking down the tree that's really the easy recursion. 138 00:15:12,270 --> 00:15:14,750 That's just a val walking down this tree of expressions. 139 00:15:14,750 --> 00:15:16,600 Then, in the evaluator, there's a hard recursion. 140 00:15:16,600 --> 00:15:18,200 There's the red to green. 141 00:15:18,200 --> 00:15:19,450 Eval calls apply. 142 00:15:22,470 --> 00:15:30,370 That's the case where evaluating a procedure or argument reduces to applying the procedure to the list of arguments. 143 00:15:30,370 --> 00:15:31,700 And then, apply comes over here. 144 00:15:34,770 --> 00:15:44,560 Apply takes a procedure and arguments and, in the general case where there's a compound procedure, apply goes around and green calls red. 145 00:15:44,560 --> 00:15:48,170 Apply comes around and calls eval again. 146 00:15:48,170 --> 00:15:56,605 Eval's the body of the procedure in the result of extending the environment with the parameters of the procedure by binding the arguments. 147 00:15:59,620 --> 00:16:05,980 Except in the primitive case, where it just calls something else primitive-apply, which is not really the business of the evaluator. 148 00:16:05,980 --> 00:16:17,186 So this sort of red to green, to red to green, that's the eval/apply loop, and that's the thing that we're going to want to see in the evaluator. 149 00:16:19,840 --> 00:16:19,970 All right. 150 00:16:19,970 --> 00:16:27,470 Well, it won't surprise you at all that the two big pieces of this evaluator correspond to eval and apply. 151 00:16:27,470 --> 00:16:32,110 There's a piece called eval-dispatch, and a piece called apply-dispatch. 152 00:16:32,110 --> 00:16:41,870 And, before we get into the details of the code, the way to understand this is to think, again, in terms of these pieces of the evaluator having contracts with the rest of the world. 153 00:16:41,870 --> 00:16:45,780 What do they do from the outside before getting into the grungy details? 154 00:16:45,780 --> 00:16:51,300 Well, the contract for eval-dispatch-- remember, it corresponds to eval. 155 00:16:51,300 --> 00:16:54,100 It's got to evaluate an expression in an environment. 156 00:16:54,100 --> 00:17:03,640 So, in particular, what this one is going to do, eval-dispatch will assume that, when you call it, that the expression you want to evaluate is in the EXP register. 157 00:17:03,640 --> 00:17:09,569 The environment in which you want the evaluation to take place is in the ENV register. 158 00:17:09,569 --> 00:17:13,880 And continue tells you the place where the machine should go next when the evaluation is done. 159 00:17:17,440 --> 00:17:26,619 Eval-dispatch's contract is that it'll actually perform that evaluation, and, at the end of which, it'll end up at the place specified by continue. 160 00:17:26,619 --> 00:17:29,950 The result of the evaluation will be in the VAL register. 161 00:17:29,950 --> 00:17:35,230 And it just warns you, it makes no promises about what happens to the registers. 162 00:17:35,230 --> 00:17:37,490 All other registers might be destroyed. 163 00:17:37,490 --> 00:17:41,790 So, there's one piece, OK? 164 00:17:41,790 --> 00:17:54,540 Together, the pieces, apply-dispatch that corresponds to apply, it's got to apply a procedure to some arguments, so it assumes that this register, ARGL, contains a list of the evaluated arguments. 165 00:17:54,540 --> 00:17:57,220 FUN contains the procedure. 166 00:17:57,220 --> 00:18:01,055 Those correspond to the arguments to the apply procedure in the meta-circular evaluator. 167 00:18:03,970 --> 00:18:21,840 And apply, in this particular evaluator, we're going to use a discipline which says the place the machine should go to next when apply is done is, at the moment apply-dispatch is called at the top of the stack, that's just discipline for the way this particular machine's organized. 168 00:18:21,840 --> 00:18:23,950 And now apply's contract is given all that. 169 00:18:23,950 --> 00:18:25,540 It'll perform the application. 170 00:18:25,540 --> 00:18:28,890 The result of that application will end up in VAL. 171 00:18:28,890 --> 00:18:31,120 The stack will be popped. 172 00:18:31,120 --> 00:18:35,110 And, again, the contents of all the other registers may be destroyed, all right? 173 00:18:35,110 --> 00:18:39,760 So that's the basic organization of this machine. 174 00:18:39,760 --> 00:18:42,700 Let's break for a little bit and see if there are any questions, and then we'll do a real example. 175 00:19:47,850 --> 00:20:03,400 Well, let's take the register machine now, and actually step through, and really, in real detail, so you see completely concrete how some expressions are evaluated, all right? 176 00:20:03,400 --> 00:20:06,435 So, let's start with a very simple expression. 177 00:20:09,620 --> 00:20:13,320 Let's evaluate the expression 1. 178 00:20:18,880 --> 00:20:23,085 And we need an environment, so let's imagine that somewhere there's an environment, we'll call it E,0. 179 00:20:30,260 --> 00:20:38,360 And just, since we'll use these later, we obviously don't really need anything to evaluate 1. 180 00:20:38,360 --> 00:20:49,140 But, just for reference later, let's assume that E,0 has in it an X that's bound to 3 and a Y that's bound to 4, OK? 181 00:20:49,140 --> 00:21:03,560 And now what we're going to do is we're going to evaluate 1 in this environment, and so the ENV register has a pointer to this environment, E,0, all right? 182 00:21:03,560 --> 00:21:05,650 So let's watch that thing go. 183 00:21:05,650 --> 00:21:08,260 What I'm going to do is step through the code. 184 00:21:08,260 --> 00:21:10,080 And, let's see, I'll be the controller. 185 00:21:10,080 --> 00:21:16,830 And now what I need, since this gets rather complicated, is a very little execution unit. 186 00:21:16,830 --> 00:21:22,624 So here's the execution unit, OK? 187 00:21:22,624 --> 00:21:23,874 OK. 188 00:21:27,088 --> 00:21:28,590 OK. 189 00:21:28,590 --> 00:21:30,690 All right, now we're going to start. 190 00:21:30,690 --> 00:21:33,660 We're going to start the machine at eval-dispatch, right? 191 00:21:33,660 --> 00:21:36,120 That's the beginning of this. 192 00:21:36,120 --> 00:21:42,010 Eval-dispatch is going to look at the expression in dispatch, just like eval where we look at the very first thing. 193 00:21:42,010 --> 00:21:47,950 We branch on whether or not this expression is self-evaluating. 194 00:21:47,950 --> 00:21:57,040 Self-evaluating is some abstraction we put into the machine-- it's going to be true for numbers-- to a place called ev-self-eval, right? 195 00:21:57,040 --> 00:22:02,780 So me, being the controller, looks at ev-self-eval, so we'll go over to there. 196 00:22:02,780 --> 00:22:15,220 Ev-self-eval says fine, assign to val whatever is in the expression unit, OK? 197 00:22:15,220 --> 00:22:32,050 And I have a bug because what I didn't do when I initialized this machine is also say what's supposed to happen when it's done, so I should have started out the machine with done being in the continue register, OK? 198 00:22:32,050 --> 00:22:33,640 So we assign to VAL. 199 00:22:33,640 --> 00:22:40,000 And now go to fetch of continue, and now change-- OK. 200 00:22:40,000 --> 00:22:42,160 OK, let's try something harder. 201 00:22:42,160 --> 00:22:56,710 Let's reset the machine here, and we'll put in the expression register, X, OK? 202 00:22:56,710 --> 00:22:59,610 Start again at eval-dispatch. 203 00:22:59,610 --> 00:23:01,690 Check, is it self-evaluating? 204 00:23:01,690 --> 00:23:02,650 No. 205 00:23:02,650 --> 00:23:04,630 Is it a variable? 206 00:23:04,630 --> 00:23:05,560 Yes. 207 00:23:05,560 --> 00:23:08,380 We go off to ev-variable. 208 00:23:08,380 --> 00:23:21,620 It says assign to VAL, look up the variable value in the expression register, OK? 209 00:23:21,620 --> 00:23:23,625 Go to fetch of continue. 210 00:23:23,625 --> 00:23:24,875 PROFESSOR: Done. 211 00:23:27,252 --> 00:23:28,950 PROFESSOR: OK. 212 00:23:28,950 --> 00:23:29,430 All right. 213 00:23:29,430 --> 00:23:31,330 Well, that's the basic idea. 214 00:23:31,330 --> 00:23:32,920 That's a simple operation of the machine. 215 00:23:32,920 --> 00:23:36,070 Now, let's actually do something a little bit more interesting. 216 00:23:36,070 --> 00:23:49,678 Let's look at the expression the sum of x and y. 217 00:23:49,678 --> 00:23:50,130 OK. 218 00:23:50,130 --> 00:23:57,100 And now we'll see how you start unrolling these expression trees, OK? 219 00:23:57,100 --> 00:24:00,645 Well, start again at eval-dispatch, all right? 220 00:24:04,610 --> 00:24:06,060 Self-evaluating? 221 00:24:06,060 --> 00:24:06,810 No. 222 00:24:06,810 --> 00:24:07,280 Variable? 223 00:24:07,280 --> 00:24:07,850 No. 224 00:24:07,850 --> 00:24:13,260 All the other special forms which I didn't write down, like quote, and lambda, and set, and whatever, it's none of those. 225 00:24:13,260 --> 00:24:19,970 It turns out to be an application, so we go off to ev-application, OK? 226 00:24:19,970 --> 00:24:25,580 Ev-application, remember what it's going to do overall. 227 00:24:25,580 --> 00:24:28,310 It is going to evaluate the operator. 228 00:24:28,310 --> 00:24:35,060 It's going to evaluate the arguments, and then it's going to go apply them. 229 00:24:35,060 --> 00:24:55,340 So, before we start, since we're being very literal, we'd better remember that, somewhere in this environment, it's linked to another environment in which plus is bound to the primitive procedure plus before we get an unknown variable in our machine. 230 00:24:55,340 --> 00:24:56,590 OK, so we're at ev-application. 231 00:24:59,850 --> 00:25:07,920 OK, assign to UNEV the operands of what's in the expression register, OK? 232 00:25:07,920 --> 00:25:09,230 Those are the operands. 233 00:25:09,230 --> 00:25:12,916 UNEV's a temporary register where we're going to save them. 234 00:25:12,916 --> 00:25:13,860 PROFESSOR: I'm assigning. 235 00:25:13,860 --> 00:25:18,070 PROFESSOR: Assign to x the operator. 236 00:25:18,070 --> 00:25:25,820 Now, notice we've destroyed that expression in x, but the piece that we need is now in UNEV. OK. 237 00:25:25,820 --> 00:25:28,750 Now, we're going to get set up to recursively evaluate the operator. 238 00:25:28,750 --> 00:25:31,565 Save the continue register on the stack. 239 00:25:34,870 --> 00:25:36,120 Save the environment. 240 00:25:40,520 --> 00:25:54,460 Save UNEV. OK, assign to continue a label called eval-args. 241 00:26:01,400 --> 00:26:01,980 Now, what have we done? 242 00:26:01,980 --> 00:26:04,380 We've set up for a recursive call. 243 00:26:04,380 --> 00:26:06,280 We're about to go to eval-dispatch. 244 00:26:06,280 --> 00:26:10,230 We've set up for a recursive call to eval-dispatch. 245 00:26:10,230 --> 00:26:11,020 What did we do? 246 00:26:11,020 --> 00:26:27,120 We took the things we're going to need later, those operands that were in UNEV; the environment in which we're going to eventually have to, maybe, evaluate those operands; the place we eventually want to go to, which, in this case, was done; we've saved them on the stack. 247 00:26:27,120 --> 00:26:33,550 The reason we saved them on the stack is because eval-dispatch makes no promises about what registers it may destroy. 248 00:26:33,550 --> 00:26:35,020 So all that stuff is saved on the stack. 249 00:26:35,020 --> 00:26:37,380 Now, we've set up eval-dispatch's contract. 250 00:26:37,380 --> 00:26:47,600 There's a new expression, which is the operator plus; a new environment, although, in this case, it's the same one; and a new place to go to when you're done, which is eval-args. 251 00:26:47,600 --> 00:26:48,130 So that's set up. 252 00:26:48,130 --> 00:26:50,890 Now, we're going to go off to eval-dispatch. 253 00:26:50,890 --> 00:26:53,090 Here we are back at eval-dispatch. 254 00:26:53,090 --> 00:26:54,490 It's not self-evaluating. 255 00:26:54,490 --> 00:27:00,260 Oh, it's a variable, so we'd better go off to ev-variable, right? 256 00:27:00,260 --> 00:27:02,880 Ev-variable is assigned to VAL. 257 00:27:02,880 --> 00:27:08,770 Look up the variable value of the expression, OK? 258 00:27:08,770 --> 00:27:13,000 So VAL is the primitive procedure plus, OK? 259 00:27:13,000 --> 00:27:15,020 And go to fetch of continue. 260 00:27:15,020 --> 00:27:15,660 PROFESSOR: Eval-args. 261 00:27:15,660 --> 00:27:19,340 PROFESSOR: Right, which is now eval-args not done. 262 00:27:19,340 --> 00:27:23,210 So we come back here at eval-args, and what do we do? 263 00:27:23,210 --> 00:27:32,900 We're going to restore the stuff that we saved, so we restore UNEV. And notice, there, it wasn't necessary, although, in general, it would be. 264 00:27:32,900 --> 00:27:35,430 It might be some arbitrary evaluation that happened. 265 00:27:35,430 --> 00:27:51,900 We restore ENV. OK, we assign to FUN fetch of VAL. 266 00:27:58,620 --> 00:28:04,340 OK, now, we're going to go off and start evaluating some arguments. 267 00:28:04,340 --> 00:28:10,165 Well, first thing we'd better do is save FUN because some arbitrary stuff might happen in that evaluation. 268 00:28:15,330 --> 00:28:25,460 We initialize the argument list. Assign to argl an empty argument list, and go to eval-arg-loop, OK? 269 00:28:25,460 --> 00:28:38,090 At eval-arg-loop, the idea of this is we're going to evaluate the pieces of the expressions that are in UNEV, one by one, and move them from unevaluated in UNEV to evaluated in the arg list, OK? 270 00:28:38,090 --> 00:28:39,340 So we save argl. 271 00:28:43,950 --> 00:28:53,960 We assign to x the first operand of the stuff in UNEV. 272 00:28:53,960 --> 00:28:55,890 Now, we check and see if that was the last operand. 273 00:28:55,890 --> 00:28:59,190 In this case, it is not, all right? 274 00:28:59,190 --> 00:29:01,235 So we save the environment. 275 00:29:09,170 --> 00:29:13,500 We save UNEV because those are all things we might need later. 276 00:29:13,500 --> 00:29:15,800 We're going to need the environment to do some more evaluations. 277 00:29:15,800 --> 00:29:20,340 We're going to need UNEV to look at what the rest of those arguments were. 278 00:29:20,340 --> 00:29:24,040 We're going to assign continue a place called accumulate-args, or accumulate-arg. 279 00:29:30,898 --> 00:29:36,810 OK, now, we've set up for another call to eval-dispatch, OK? 280 00:29:36,810 --> 00:29:41,090 All right, now, let me short-circuit this so we don't go through the details of eval-dispatch. 281 00:29:41,090 --> 00:29:51,320 Eval-dispatch's contract says I'm going to end up, the world will end up, with the value of evaluating this expression in this environment in the VAL register, and I'll end up there. 282 00:29:51,320 --> 00:29:58,010 So we short-circuit all of this, and a 3 ends up in VAL. 283 00:29:58,010 --> 00:30:02,110 And, when we return from eval-dispatch, we're going to return to accumulate-arg. 284 00:30:02,110 --> 00:30:03,555 PROFESSOR: Accumulate-arg. 285 00:30:03,555 --> 00:30:08,720 PROFESSOR: With 3 in the VAL register, OK? 286 00:30:08,720 --> 00:30:10,650 So that short-circuited that evaluation. 287 00:30:10,650 --> 00:30:11,320 Now, what do we do? 288 00:30:11,320 --> 00:30:28,650 We're going to go back and look at the rest of the arguments, so we restore UNEV. We restore ENV. We restore argl. 289 00:30:28,650 --> 00:30:29,170 One thing. 290 00:30:29,170 --> 00:30:31,290 PROFESSOR: Oops! Parity error. 291 00:30:31,290 --> 00:30:33,465 [LAUGHTER] 292 00:30:33,465 --> 00:30:34,905 PROFESSOR: Restore argl. 293 00:30:41,650 --> 00:30:42,900 PROFESSOR: OK. 294 00:30:45,570 --> 00:30:53,130 OK, we assign to argl consing on fetch of the value register to what's in argl. 295 00:30:58,985 --> 00:31:11,516 OK, we assign to UNEV the rest of the operands in fetch of UNEV, and we go back to eval-arg-loop. 296 00:31:11,516 --> 00:31:12,280 PROFESSOR: Eval-arg-loop. 297 00:31:12,280 --> 00:31:13,530 PROFESSOR: OK. 298 00:31:15,880 --> 00:31:19,340 Now, we're about to do the next argument, so the first thing we do is save argl. 299 00:31:25,400 --> 00:31:37,140 OK, we assign to x the first operand of fetch of UNEV. OK, we test and see if that's the last operand. 300 00:31:37,140 --> 00:31:47,446 In this case, it is, so we're going to go to a special place that says evaluate the last argument because, notice, after evaluating the argument, we don't need the environment any more. 301 00:31:47,446 --> 00:31:50,250 That's going to be the difference. 302 00:31:50,250 --> 00:32:06,900 So here, at eval-last-arg, which is assigned to accumulate-last-arg, now, we're set up again for eval-dispatch. 303 00:32:06,900 --> 00:32:08,620 We've got a place to go to when we're done. 304 00:32:08,620 --> 00:32:09,840 We've got an expression. 305 00:32:09,840 --> 00:32:11,330 We've got an environment. 306 00:32:11,330 --> 00:32:14,370 OK, so we'll short-circuit the call to eval-dispatch. 307 00:32:14,370 --> 00:32:21,060 And what'll happen is there's a y there, it's 4 in that environment, so VAL will end up with 4 in it. 308 00:32:21,060 --> 00:32:25,450 And, then, we're going to end up at accumulate-last-arg, OK? 309 00:32:25,450 --> 00:32:30,150 So, at accumulate-last-arg, we restore argl. 310 00:32:41,490 --> 00:32:49,850 We assign to argl cons of fetch of the new value onto it, so we cons a 4 onto that. 311 00:32:49,850 --> 00:32:53,446 We restore what was saved in the function register. 312 00:32:53,446 --> 00:32:59,420 And notice, in this case, it had not been destroyed, but, in general, it will be. 313 00:32:59,420 --> 00:33:02,850 And now, we're ready to go off to apply-dispatch, all right? 314 00:33:02,850 --> 00:33:04,510 So we've just gone through the eval. 315 00:33:04,510 --> 00:33:09,580 We evaluated the argument, the operator, and the arguments, and now, we're about to apply them. 316 00:33:09,580 --> 00:33:17,481 So we come off to apply-dispatch here, OK? 317 00:33:17,481 --> 00:33:23,450 We come off to apply-dispatch, and we're going to check whether it's a primitive or a compound procedure. 318 00:33:23,450 --> 00:33:24,116 PROFESSOR: Yes. 319 00:33:24,116 --> 00:33:24,830 PROFESSOR: All right. 320 00:33:24,830 --> 00:33:29,790 So, in this case, it's a primitive procedure, and we go off to primitive-apply. 321 00:33:29,790 --> 00:33:40,940 So we go off to primitive-apply, and it says assign to VAL the result of applying primitive procedure of the function to the argument list. 322 00:33:40,940 --> 00:33:42,540 PROFESSOR: I don't know how to add. 323 00:33:42,540 --> 00:33:43,995 I'm just an execution unit. 324 00:33:43,995 --> 00:33:45,350 PROFESSOR: Well, I don't know how to add either. 325 00:33:45,350 --> 00:33:48,360 I'm just the evaluator, so we need a primitive operator. 326 00:33:48,360 --> 00:33:52,605 Let's see, so the primitive operator, what's the sum of 3 and 4? 327 00:33:52,605 --> 00:33:53,205 AUDIENCE: 7. 328 00:33:53,205 --> 00:33:54,580 PROFESSOR: OK, 7. 329 00:33:54,580 --> 00:33:55,999 PROFESSOR: Thank you. 330 00:33:58,837 --> 00:34:12,900 PROFESSOR: Now, we restore continue, and we go to fetch of continue. 331 00:34:12,900 --> 00:34:13,880 PROFESSOR: Done. 332 00:34:13,880 --> 00:34:14,929 PROFESSOR: OK. 333 00:34:14,929 --> 00:34:18,659 Well, that was in as much detail as you will ever see. 334 00:34:18,659 --> 00:34:21,590 We'll never do it in as much detail again. 335 00:34:21,590 --> 00:34:29,780 One very important thing to notice is that we just executed a recursive procedure, right? 336 00:34:29,780 --> 00:34:33,070 This whole thing, we used a stack and the evaluator was recursive. 337 00:34:33,070 --> 00:34:42,150 A lot of people think the reason that you need a stack and recursion in an evaluator is because you might be evaluating recursive procedures like factorial or Fibonacci. 338 00:34:42,150 --> 00:34:43,670 It's not true. 339 00:34:43,670 --> 00:34:48,010 So you notice we did recursion here, and all we evaluated was plus X, Y, all right? 340 00:34:48,010 --> 00:34:54,780 The reason that you need recursion in the evaluator is because the evaluation process, itself, is recursive, all right? 341 00:34:54,780 --> 00:34:59,270 It's not because the procedure that you might be evaluating in LISP is a recursive procedure. 342 00:34:59,270 --> 00:35:03,010 So that's an important thing that people get confused about a lot. 343 00:35:03,010 --> 00:35:07,120 The other thing to notice is that, when we're done here, we're really done. 344 00:35:07,120 --> 00:35:13,810 Not only are we at done, but there's no accumulated stuff on the stack, right? 345 00:35:13,810 --> 00:35:17,170 The machine is back to its initial state, all right? 346 00:35:17,170 --> 00:35:19,830 So that's part of what it means to be done. 347 00:35:19,830 --> 00:35:33,460 Another way to say that is the evaluation process has reduced the expression, plus X, Y, to the value here, 7. 348 00:35:33,460 --> 00:35:36,010 And by reduced, I mean a very particular thing. 349 00:35:36,010 --> 00:35:38,180 It means that there's nothing left on the stack. 350 00:35:38,180 --> 00:35:42,760 The machine is now in the same state, except there's something in the value register. 351 00:35:42,760 --> 00:35:44,520 It's not part of a sub-problem of anything. 352 00:35:44,520 --> 00:35:46,210 There's nothing to go back to. 353 00:35:46,210 --> 00:35:46,440 OK. 354 00:35:46,440 --> 00:35:47,690 Let's break. 355 00:35:49,712 --> 00:35:50,159 Question? 356 00:35:50,159 --> 00:35:55,820 AUDIENCE: The question here, in the stack, is because the data may be recursive. 357 00:35:55,820 --> 00:35:59,312 You may have embedded expressions, for instance. 358 00:35:59,312 --> 00:36:02,080 PROFESSOR: Yes, because you might have embedded expressions. 359 00:36:02,080 --> 00:36:12,930 But, again, don't confuse that with what people sometimes mean by the data may be recursive, which is to say you have these list-structured, recursive data list operations. 360 00:36:12,930 --> 00:36:13,980 That has nothing to do with it. 361 00:36:13,980 --> 00:36:17,363 It's simply that the expressions contain sub-expressions. 362 00:36:17,363 --> 00:36:19,618 Yeah? 363 00:36:19,618 --> 00:36:23,225 AUDIENCE: Why is it that the order of the arguments in the arg list got reversed? 364 00:36:23,225 --> 00:36:27,260 PROFESSOR: Ah! Yes, I should've mentioned that. 365 00:36:27,260 --> 00:36:36,050 Here, the reason the order is reversed-- it's a question of what you mean by reversed. 366 00:36:36,050 --> 00:36:40,624 I believe it was Newton. 367 00:36:40,624 --> 00:36:46,840 In the very early part of optics, people realized that, when you look through the lens of your eye, the image was up-side down. 368 00:36:46,840 --> 00:36:51,280 And there was a lot of argument about why that didn't mean you saw things up-side down. 369 00:36:51,280 --> 00:36:52,860 So it's sort of the same issue. 370 00:36:52,860 --> 00:36:54,810 Reversed from what? 371 00:36:54,810 --> 00:36:57,940 So we just need some convention. 372 00:36:57,940 --> 00:37:04,520 The reason that they're coming at 4, 3 is because we're taking UNEV and consing the result onto argl. 373 00:37:04,520 --> 00:37:06,900 So you have to realize you've made that convention. 374 00:37:06,900 --> 00:37:11,230 The place that you have to realize that-- well, there's actually two places. 375 00:37:11,230 --> 00:37:19,490 One is in apply-primitive-operator, which has to realize that the arguments to primitives go in, in the opposite order from the way you're writing them down. 376 00:37:19,490 --> 00:37:28,870 And the other one is, we'll see later when you actually go to bind a function's parameters, you should realize the arguments are going to come in from the opposite order of the variables to which you're binding them. 377 00:37:28,870 --> 00:37:31,830 So, if you just keep track of that, there's no problem. 378 00:37:31,830 --> 00:37:40,730 Also, this is completely arbitrary because, if we'd done, say, an iteration through a vector assigning them, they might come out in the other order, OK? 379 00:37:40,730 --> 00:37:45,085 So it's just a convention of the way this particular evaluator works. 380 00:37:45,085 --> 00:37:46,335 All right, let's take a break. 381 00:38:41,840 --> 00:38:46,950 We just saw evaluating an expression and, of course, that was very simple one. 382 00:38:46,950 --> 00:38:55,130 But, in essence, it would be no different if it was some big nested expression, so there would just be deeper recursion on the stack. 383 00:38:55,130 --> 00:38:56,920 But what I want to do now is show you the last piece. 384 00:38:56,920 --> 00:39:01,300 I want to walk you around this eval and apply loop, right? 385 00:39:01,300 --> 00:39:03,000 That's the thing we haven't seen, really. 386 00:39:03,000 --> 00:39:15,810 We haven't seen any compound procedures where applying a procedure reduces to evaluating the body of the procedure, so let's just suppose we had this. 387 00:39:15,810 --> 00:39:47,280 Suppose we were looking at the procedure define F of A and B to be the sum of A and B. So, as we typed in that procedure previously, and now we're going to evaluate F of X and Y, again, in this environment, E,0, where X is bound to 3 and Y is bound to 4. 388 00:39:50,830 --> 00:39:55,950 When the defined is executed, remember, there's a lambda here, and lambdas create procedures. 389 00:39:55,950 --> 00:40:18,180 And, basically, what will happen is, in E,0, we'll end up with a binding for F, which will say F is a procedure, and its args are A and B, and its body is plus a,b. 390 00:40:18,180 --> 00:40:24,400 So that's what the environment would have looked like had we made that definition. 391 00:40:24,400 --> 00:40:31,810 Then, when we go to evaluate F of X and Y, we'll go through exactly the same process that we did before. 392 00:40:31,810 --> 00:40:33,360 It's even the same expression. 393 00:40:33,360 --> 00:40:41,040 The only difference is that F, instead of having primitive plus in it, will have this thing. 394 00:40:41,040 --> 00:41:08,040 And so we'll go through exactly the same process, except this time, when we end up at apply-dispatch, the function register, instead of having primitive plus, will have a thing that will represent it saying procedure, where the args are A and B, and the body is plus A, B. 395 00:41:08,040 --> 00:41:13,280 And, again, what I mean, by its ENV, I mean there's a pointer to it, so don't worry that I'm writing a lot of stuff there. 396 00:41:13,280 --> 00:41:17,170 There's a pointer to this procedure data structure. 397 00:41:17,170 --> 00:41:20,960 OK, so, we're in exactly the same situation. 398 00:41:20,960 --> 00:41:26,480 We get to apply-dispatch, so, here, we come to apply-dispatch. 399 00:41:26,480 --> 00:41:30,010 Last time, we branched off to a primitive procedure. 400 00:41:30,010 --> 00:41:36,150 Here, it says oh, we now have a compound procedure, so we're going to go off to compound-apply. 401 00:41:38,660 --> 00:41:39,910 Now, what's compound-apply? 402 00:41:42,100 --> 00:41:45,090 Well, remember what the meta-circular evaluator did? 403 00:41:45,090 --> 00:41:54,120 Compound-apply said we're going to evaluate the body of the procedure in some new environment. 404 00:41:54,120 --> 00:41:56,730 Where does that new environment come from? 405 00:41:56,730 --> 00:42:14,990 We take the environment that was packaged with the procedure, we bind the parameters of the procedure to the arguments that we're passing in, and use that as a new frame to extend the procedure environment. 406 00:42:14,990 --> 00:42:21,630 And that's the environment in which we evaluate the procedure body, right? 407 00:42:21,630 --> 00:42:24,470 That's going around the apply/eval loop. 408 00:42:24,470 --> 00:42:27,988 That's apply coming back to call eval, all right? 409 00:42:30,910 --> 00:42:32,860 OK. 410 00:42:32,860 --> 00:42:36,950 So, now, that's all we have to do in compound-apply. 411 00:42:36,950 --> 00:42:37,720 What are we going to do? 412 00:42:37,720 --> 00:42:40,730 We're going to manufacture a new environment. 413 00:42:43,720 --> 00:42:48,310 And we're going to manufacture a new environment, let's see, that we'll call E,1. 414 00:42:53,100 --> 00:43:09,270 E,1 is going to be some environment where the parameters of the procedure, where A is bound to 3 and B is bound to 4, and it's linked to E,0 because that's where f is defined. 415 00:43:09,270 --> 00:43:12,050 And, in this environment, we're going to evaluate the body of the procedure. 416 00:43:12,050 --> 00:43:13,870 So let's look at that, all right? 417 00:43:16,730 --> 00:43:28,300 All right, here we are at compound-apply, which says assign to the expression register the body of the procedure that's in the function register. 418 00:43:28,300 --> 00:43:42,710 So I assign to the expression register the procedure body, OK? 419 00:43:42,710 --> 00:43:57,800 That's going to be evaluated in an environment which is formed by making some bindings using information determined by the procedure-- that's what's in FUN-- and the argument list. 420 00:43:57,800 --> 00:44:01,930 And let's not worry about exactly what that does, but you can see the information's there. 421 00:44:01,930 --> 00:44:08,200 So make bindings will say oh, the procedure, itself, had an environment attached to it. 422 00:44:08,200 --> 00:44:09,320 I didn't write that quite here. 423 00:44:09,320 --> 00:44:13,660 I should've said in environment because every procedure gets built with an environment. 424 00:44:13,660 --> 00:44:19,290 So, from that environment, it knows what the procedure's definition environment is. 425 00:44:19,290 --> 00:44:21,830 It knows what the arguments are. 426 00:44:21,830 --> 00:44:24,280 It looks at argl, and then you see a reversal convention here. 427 00:44:24,280 --> 00:44:29,990 It just has to know that argl is reversed, and it builds this frame, E,1. 428 00:44:29,990 --> 00:44:35,780 All right, so, let's assume that that's what make bindings returns, so it assigns to ENV this thing, E,1. 429 00:44:41,490 --> 00:44:46,890 All right, the next thing it says is restore continue. 430 00:44:46,890 --> 00:44:48,760 Remember what continue was here? 431 00:44:48,760 --> 00:44:52,240 It got put up in the last segment. 432 00:44:52,240 --> 00:44:54,020 Continue got stored. 433 00:44:54,020 --> 00:44:59,920 That was the original done, which said what are you going to do after you're done with this particular application? 434 00:44:59,920 --> 00:45:03,920 It was one of the very first things that happened when we evaluated the application. 435 00:45:03,920 --> 00:45:06,860 And now, finally, we're going to restore continue. 436 00:45:06,860 --> 00:45:09,290 Remember apply-dispatch's contract. 437 00:45:09,290 --> 00:45:13,590 It assumes that where it should go to next was on the stack, and there it was on the stack. 438 00:45:13,590 --> 00:45:19,940 Continue has done, and now we're going to go back to eval-dispatch. 439 00:45:19,940 --> 00:45:20,970 We're set up again. 440 00:45:20,970 --> 00:45:25,511 We have an expression, an environment, and a place to go to. 441 00:45:25,511 --> 00:45:29,940 We're not going to go through that because it's sort of the same expression. 442 00:45:35,167 --> 00:45:44,830 OK, but the thing, again, to notice is, at this point, we have reduced the original expression, F,X,Y, right? 443 00:45:44,830 --> 00:45:52,670 We've reduced evaluating F,X,Y in environment E,0 to evaluate plus A, B in E,1. 444 00:45:52,670 --> 00:45:55,720 And notice, nothing's on the stack, right? 445 00:45:55,720 --> 00:45:56,830 It's a reduction. 446 00:45:56,830 --> 00:46:08,090 At this point, the machine does not contain, as part of its state, the fact that it's in the middle of evaluating some procedure called f, that's gone, right? 447 00:46:08,090 --> 00:46:13,072 There's no accumulated state, OK? 448 00:46:13,072 --> 00:46:14,370 Again, that's a very important idea. 449 00:46:14,370 --> 00:46:21,350 That's the meaning of, when we used to write in the substitution model, this expression reduces to that expression. 450 00:46:21,350 --> 00:46:22,660 And you don't have to remember anything. 451 00:46:22,660 --> 00:46:24,500 And here, you see the meaning of reduction. 452 00:46:24,500 --> 00:46:26,160 At this point, there is nothing on the stack. 453 00:46:31,590 --> 00:46:35,240 See, that has very important consequences. 454 00:46:35,240 --> 00:46:40,590 Let's go back and look at iterative factorial, all right? 455 00:46:40,590 --> 00:46:45,130 Remember, this was some sort of loop and doing iter. 456 00:46:45,130 --> 00:46:49,430 And we kept saying that's an iterative procedure, right? 457 00:46:52,570 --> 00:47:12,360 And what we wrote, remember, are things like, we said, fact-iter of 5. 458 00:47:12,360 --> 00:47:27,210 We wrote things like reduces to iter of 1, and 1, and 5, which reduces to iter of 1, and 2, and 5, and so on, and so on, and so on. 459 00:47:27,210 --> 00:47:31,720 And we kept saying well, look, you don't have to build up any storage to do that. 460 00:47:31,720 --> 00:47:35,040 And we waved our hands, and said in principle, there's no storage needed. 461 00:47:35,040 --> 00:47:36,170 Now, you see no storage needed. 462 00:47:36,170 --> 00:47:39,090 Each of these is a real reduction, right? 463 00:47:49,280 --> 00:48:01,650 As you walk through these expressions, what you'll see are these expressions on the stack in some particular environment, and then these expressions in the EXP register in some particular environment. 464 00:48:01,650 --> 00:48:09,135 And, at each point, there'll be no accumulated stuff on the stack because each one's a real reduction, OK? 465 00:48:09,135 --> 00:48:48,120 All right, so, for example, just to go through it in a little bit more care, if I start out with an expression that says something like, oh, say, fact-iter of 5 in some environment that will, at some point, create an environment in which n is down to 5. 466 00:48:51,340 --> 00:49:17,160 Let's call that-- And, at some point, the machine will reduce this whole thing to a thing that says that's really iter of 1, and 1, and n, evaluated in this environment, E,1 with nothing on the stack. 467 00:49:17,160 --> 00:49:29,366 See, at this moment, the machine is not remembering that evaluating this expression, iter-- which is the loop-- is part of this thing called iterative factorial. 468 00:49:29,366 --> 00:49:30,590 It's not remembering that. 469 00:49:30,590 --> 00:49:33,170 It's just reducing the expression to that, right? 470 00:49:33,170 --> 00:49:42,810 If we look again at the body of iterative factorial, this expression has reduced to that expression. 471 00:49:42,810 --> 00:49:44,060 Oh, I shouldn't have the n there. 472 00:49:46,590 --> 00:49:53,340 It's a slightly different convention from the slide to the program, OK? 473 00:49:53,340 --> 00:49:56,310 And, then, what's the body of iter? 474 00:49:56,310 --> 00:50:00,060 Well, iter's going to be an it, and I won't go through the details of if. 475 00:50:00,060 --> 00:50:02,540 It'll evaluate the predicate. 476 00:50:02,540 --> 00:50:03,810 In this case, it'll be false. 477 00:50:03,810 --> 00:50:43,200 And this iter will now reduce to the expression iter of whatever it says, star, counter product, and-- what does it say-- plus counter 1 in some other environment, by this time, E,2, where E,2 will be set up having bindings for product and counter, right? 478 00:50:43,200 --> 00:50:45,140 And it'll reduce to that, right? 479 00:50:45,140 --> 00:50:49,340 It won't be remembering that it's part of something that it has to return to. 480 00:50:49,340 --> 00:50:59,160 And when iter calls iter again, it'll reduce to another thing that looks like this in some environment, E,3, which has new bindings for product and counter. 481 00:50:59,160 --> 00:51:21,230 So, if you're wondering, see, if you've always been queasy about how it is we've been saying those procedures, that look syntactically recursive, are, in fact, iterative, run in constant space, well, I don't know if this makes you less queasy, but at least it shows you what's happening. 482 00:51:21,230 --> 00:51:22,830 There really isn't any buildup there. 483 00:51:25,910 --> 00:51:31,710 Now, you might ask well, is there buildup in principle in these environment frames? 484 00:51:31,710 --> 00:51:36,440 And the answer is yeah, you have to make these new environment frames, but you don't have to hang onto them when you're done. 485 00:51:36,440 --> 00:51:40,720 They can be garbage collected, or the space can be reused automatically. 486 00:51:40,720 --> 00:51:50,132 But you see the control structure of the evaluator is really using this idea that you actually have a reduction, so these procedures really are iterative procedures. 487 00:51:50,132 --> 00:51:51,382 All right, let's stop for questions. 488 00:52:02,288 --> 00:52:03,538 All right, let's break. 489 00:52:48,770 --> 00:52:58,030 Let me contrast the iterative procedure just so you'll see where space does build up with a recursive procedure, so you can see the difference. 490 00:52:58,030 --> 00:53:02,880 Let's look at the evaluation of recursive factorial, all right? 491 00:53:02,880 --> 00:53:07,220 So, here's fact-recursive, or standard factorial definition. 492 00:53:07,220 --> 00:53:13,750 We said this one is still a recursive procedure, but this is actually a recursive process. 493 00:53:13,750 --> 00:54:15,240 And then, just to link it back to the way we started, we said oh, you can see that it's going to be recursive process by the substitution model because, if I say recursive factorial of 5, that turns into 5 times-- what is it, fact-rec, or record fact-- 5 times recursive factorial of 4, which turns into 5 times 4 times fact-rec of 3, which returns into 5 times 4 times 3 times, and so on, right? 494 00:54:15,240 --> 00:54:21,520 The idea is there was this chain of stuff building up, which justified, in the substitution model, the fact that it's recursive. 495 00:54:21,520 --> 00:54:27,465 And now, let's actually see that chain of stuff build up and where it is in the machine, OK? 496 00:54:27,465 --> 00:54:30,230 All right, well, let's imagine we're going to start out again. 497 00:54:30,230 --> 00:54:49,580 We'll tell it to evaluate recursive factorial of 5 in some environment, again, E,0 where recursive factorial is defined, OK? 498 00:54:49,580 --> 00:54:52,490 Well, now we know what's eventually going to happen. 499 00:54:52,490 --> 00:55:14,610 This is going to come along, it'll evaluate those things, figure out it's a procedure, build somewhere over here an environment, E,1, which has n bound to 5, which hangs off of E,0, which would be, presumably, the definition environment of recursive factorial, OK? 500 00:55:14,610 --> 00:55:19,670 And, in this environment, it's going to go off and evaluate the body. 501 00:55:19,670 --> 00:55:30,240 So, again, the evaluation here will reduce to evaluating the body in E,1. 502 00:55:30,240 --> 00:55:33,530 That's going to look at an if, and I won't go through the details of if. 503 00:55:33,530 --> 00:55:34,880 It'll look at the predicate. 504 00:55:34,880 --> 00:55:37,840 It'll decide it eventually has to evaluate the alternative. 505 00:55:37,840 --> 00:56:08,720 So this whole thing, again, will reduce to the alternative of recursive factorial, the alternative clause, which says that this whole thing reduces to times n of recursive factorial of n minus 1 in the environment E,1, OK? 506 00:56:08,720 --> 00:56:14,130 So the original expression, now, is going to reduce to evaluating that expression, all right? 507 00:56:14,130 --> 00:56:16,280 Now we have an application. 508 00:56:16,280 --> 00:56:18,500 We did an application before. 509 00:56:18,500 --> 00:56:20,390 Remember what happens in an application? 510 00:56:20,390 --> 00:56:25,350 The first thing you do is you go off and you save the value of the continue register on the stack. 511 00:56:25,350 --> 00:56:27,365 So the stack here is going to have done in it. 512 00:56:29,980 --> 00:56:35,130 And then you're going to set up to evaluate the sub-parts, OK? 513 00:56:35,130 --> 00:56:36,710 So here we go off to evaluate the sub-parts. 514 00:56:39,520 --> 00:56:41,045 First thing we're going to do is evaluate the operator. 515 00:56:44,490 --> 00:56:47,250 What happens when we evaluate an operator? 516 00:56:47,250 --> 00:56:51,480 Well, we arrange things so that the operator ends up in the expression register. 517 00:56:51,480 --> 00:56:56,590 The environments in the ENV register continue someplace where we're going to go evaluate the arguments. 518 00:56:56,590 --> 00:57:01,720 And, on the stack, we've saved the original continue, which is where we wanted to be when we're all done. 519 00:57:01,720 --> 00:57:15,620 And then the things we needed when we're going to get done evaluating the operator, the things we'll need to evaluate the arguments, namely, the environment and those arguments, those unevaluated arguments, so there they are sitting on the stack. 520 00:57:15,620 --> 00:57:18,370 And we're about to go off to evaluate the operator. 521 00:57:23,130 --> 00:57:43,080 Well, when we return from this particular call-- so we're about to call eval-dispatch here-- when we return from this call, the value of that operator, which, in this case, is going to be the primitive multiplier procedure, will end up in the FUN register, all right? 522 00:57:43,080 --> 00:57:44,530 We're going to evaluate some arguments. 523 00:57:44,530 --> 00:57:47,730 They will evaluate in here. 524 00:57:47,730 --> 00:57:50,250 That'll give us 5, in this case. 525 00:57:50,250 --> 00:57:57,460 We're going to put that in the argl register, and then we'll go off to evaluate the second operand. 526 00:57:57,460 --> 00:58:09,460 So, at the point where we go off to evaluate the second operand-- and I'll skip details like computing, and minus 1, and all of that-- but, when we go off to evaluate the second operand, that will eventually reduce to another call to fact-recursive. 527 00:58:12,060 --> 00:58:23,790 And, what we've got on the stack here is the operator from that combination that we're going to use it in and the other argument, OK? 528 00:58:23,790 --> 00:58:30,200 So, now, we're set up for another call to recursive factorial. 529 00:58:30,200 --> 00:58:33,935 And, when we're done with this one, we're going to go to accumulate the last arg. 530 00:58:33,935 --> 00:58:35,200 And remember what that'll do? 531 00:58:35,200 --> 00:58:41,690 That'll say oh, whatever the result of this has to get combined with that, and we're going to multiply them. 532 00:58:41,690 --> 00:58:45,720 But, notice now, we're at another recursive factorial. 533 00:58:45,720 --> 00:58:53,700 We're about to call eval-dispatch again, except we haven't really reduced it because there's stuff on the stack now. 534 00:58:53,700 --> 00:58:58,430 The stuff on the stack says oh, when you get back, you'd better multiply it by the 5 you had hanging there. 535 00:58:58,430 --> 00:59:09,300 So, when we go off to make another call, we evaluate the n minus 1. 536 00:59:09,300 --> 00:59:14,600 That gives us another environment in which the new n's going to be down to 4. 537 00:59:14,600 --> 00:59:18,930 And we're about to call eval-dispatch again, right? 538 00:59:18,930 --> 00:59:21,350 We get another call. 539 00:59:21,350 --> 00:59:26,040 That 4 is going to end up in the same situation. 540 00:59:26,040 --> 00:59:30,020 We'll end up with another call to fact-recursive n. 541 00:59:30,020 --> 00:59:35,360 And sitting on the stack will be the stuff from the original one and, now, the subsidiary one we're doing. 542 00:59:35,360 --> 00:59:36,910 And both of them are waiting for the same thing. 543 00:59:36,910 --> 00:59:40,600 They're going to go to accumulate a last argument. 544 00:59:40,600 --> 00:59:45,640 And then, of course, when we go to the fourth call, the same thing happens, right? 545 00:59:45,640 --> 00:59:47,300 And this goes on, and on, and on. 546 00:59:47,300 --> 00:59:54,960 And what you see here on the stack, exactly what's sitting here on the stack, the thing that says times and 5. 547 00:59:54,960 --> 01:00:00,470 And what you're going to do with that is accumulate that into a last argument. 548 01:00:00,470 --> 01:00:02,760 That's exactly this, right? 549 01:00:02,760 --> 01:00:05,650 This is exactly where that stuff is hanging. 550 01:00:05,650 --> 01:00:19,620 Effectively, the operator you're going to apply, the other argument that it's got to be multiplied by when you get back and the parentheses, which says yeah, what you wanted to do was accumulate them. 551 01:00:19,620 --> 01:00:22,560 So, you see, the substitution model is not such a lie. 552 01:00:22,560 --> 01:00:27,198 That really is, in some sense, what's sitting right on the stack. 553 01:00:27,198 --> 01:00:29,046 OK. 554 01:00:29,046 --> 01:00:49,430 All right, so that, in some sense, should explain for you, or at least convince you, that, somehow, this evaluator is managing to take these procedures and execute some of them iteratively and some of them recursively, even though, as syntactically, they look like recursive procedures. 555 01:00:49,430 --> 01:00:50,660 How's it managing to do that? 556 01:00:50,660 --> 01:01:01,090 Well, the basic reason it's managing to do that is the evaluator is set up to save only what it needs later. 557 01:01:01,090 --> 01:01:20,160 So, for example, at the point where you've reduced evaluating an expression and an environment to applying a procedure to some arguments, it doesn't need that original environment anymore because any environment stuff will be packaged inside the procedures where the application's going to happen. 558 01:01:20,160 --> 01:01:31,500 All right, similarly, when you're going along evaluating an argument list, when you've finished evaluating the list, when you're finished evaluating the last argument, you don't need that argument list any more, right? 559 01:01:31,500 --> 01:01:36,690 And you don't need the environment where those arguments would be evaluated, OK? 560 01:01:36,690 --> 01:01:43,050 So the basic reason that this interpreter is being so smart is that it's not being smart at all, it's being stupid. 561 01:01:43,050 --> 01:01:46,010 It's just saying I'm only going to save what I really need. 562 01:01:48,700 --> 01:01:51,000 Well, let me show you here. 563 01:01:54,880 --> 01:01:58,310 Here's the actual thing that's making a tail recursive. 564 01:01:58,310 --> 01:02:00,135 Remember, it's the restore of continue. 565 01:02:00,135 --> 01:02:15,170 It's saying when I go off to evaluate the procedure body, I should tell eval to come back to the place where that original evaluation was supposed to come back to. 566 01:02:15,170 --> 01:02:18,770 So, in some sense, you want to say what's the actual line that makes a tail recursive? 567 01:02:18,770 --> 01:02:19,920 It's that one. 568 01:02:19,920 --> 01:02:39,920 If I wanted to build a non-tail recursive evaluator, for some strange reason, all I would need to do is, instead of restoring continue at this point, I'd set up a label down here called, "Where to come back after you've finished applying the procedure." Instead, I'd set continue to that. 569 01:02:39,920 --> 01:02:43,790 I'd go to eval-dispatch, and then eval-dispatch would come back here. 570 01:02:43,790 --> 01:02:47,920 At that point, I would restore continue and go to the original one. 571 01:02:47,920 --> 01:02:52,840 So here, the only consequence of that would be to make it non-tail recursive. 572 01:02:52,840 --> 01:02:59,500 It would give you exactly the same answers, except, if you did that iterative factorial and all those iterative procedures, it would execute recursively. 573 01:03:03,080 --> 01:03:13,890 Well, I lied to you a little bit, but just a little bit, because I showed you a slightly over-simplified evaluator where it assumes that each procedure body has only one expression. 574 01:03:13,890 --> 01:03:17,870 Remember, in general, a procedure has a sequence of expressions in it. 575 01:03:17,870 --> 01:03:20,490 So there's nothing really conceptually new. 576 01:03:20,490 --> 01:03:24,730 Let me just show you the actual evaluator that handles sequences of expressions. 577 01:03:28,470 --> 01:03:42,670 This is compound-apply now, and the only difference from the old one is that, instead of going off to eval directly, it takes the whole body of the procedure, which, in this case, is a sequence of expressions, and goes off to eval-sequence. 578 01:03:42,670 --> 01:03:49,980 And eval-sequence is a little loop that, basically, does these evaluations one at a time. 579 01:03:52,630 --> 01:03:53,900 So it does an evaluation. 580 01:03:53,900 --> 01:03:58,440 Says oh, when I come back, I'd better come back here to do the next one. 581 01:03:58,440 --> 01:04:06,410 And, when I'm all done, when I want to get the last expression, I just restore my continue and go off to eval-dispatch. 582 01:04:06,410 --> 01:04:14,900 And, again, if you wanted for some reason to break tail recursion in this evaluator, all you need to do is not handle the last expression, especially. 583 01:04:14,900 --> 01:04:21,900 Just say, after you've done the last expression, come back to some other place after which you restore continue. 584 01:04:21,900 --> 01:04:26,550 And, for some reason, a lot of LISP evaluators tended to work that way. 585 01:04:26,550 --> 01:04:31,614 And the only consequence of that is that iterative procedures built up stack. 586 01:04:31,614 --> 01:04:35,670 And it's not clear why that happened. 587 01:04:35,670 --> 01:04:36,210 All right. 588 01:04:36,210 --> 01:04:41,120 Well, let me just sort of summarize, since this is a lot of details in a big program. 589 01:04:41,120 --> 01:04:47,060 But the main point is that it's no different, conceptually, from translating any other program. 590 01:04:47,060 --> 01:04:51,870 And the main idea is that we have this universal evaluator program, the meta-circular evaluator. 591 01:04:51,870 --> 01:04:54,560 If we translate that into LISP, then we have all of LISP. 592 01:04:54,560 --> 01:04:57,980 And that's all we did, OK? 593 01:04:57,980 --> 01:04:59,680 The second point is that the magic's gone away. 594 01:04:59,680 --> 01:05:01,970 There should be no more magic in this whole system, right? 595 01:05:04,820 --> 01:05:12,640 In principle, it should all be very clear except, maybe, for how list structured memory works, and we'll see that later. 596 01:05:12,640 --> 01:05:15,450 But that's not very hard. 597 01:05:15,450 --> 01:05:25,870 The third point is that all this tail recursion came from the discipline of eval being very careful to save only what it needs next time. 598 01:05:25,870 --> 01:05:33,940 It's not some arbitrary thing where we're saying well, whenever we call a sub-routine, we'll save all the registers in the world and come back, right? 599 01:05:33,940 --> 01:05:37,150 See, sometimes it pays to really worry about efficiency. 600 01:05:37,150 --> 01:05:45,230 And, when you're down in the guts of your evaluator machine, it really pays to think about things like that because it makes big consequences. 601 01:05:45,230 --> 01:05:52,560 Well, I hope what this has done is really made the evaluator seem concrete, right? 602 01:05:52,560 --> 01:05:59,390 I hope you really believe that somebody could hold a LISP evaluator in the palm of their hand. 603 01:05:59,390 --> 01:06:06,160 Maybe to help you believe that, here's a LISP evaluator that I'm holding the palm of my hand, right? 604 01:06:06,160 --> 01:06:13,700 And this is a chip which is actually quite a bit more complicated than the evaluator I showed you. 605 01:06:17,815 --> 01:06:19,200 Maybe, here's a better picture of it. 606 01:06:22,070 --> 01:06:24,730 What there is, is you can see the same overall structure. 607 01:06:24,730 --> 01:06:26,940 This is a register array. 608 01:06:26,940 --> 01:06:27,910 These are the data paths. 609 01:06:27,910 --> 01:06:29,800 Here's a finite state controller. 610 01:06:29,800 --> 01:06:32,810 And again, finite state, that's all there is. 611 01:06:32,810 --> 01:06:35,750 And somewhere there's external memory that'll worry about things. 612 01:06:35,750 --> 01:06:57,120 And this particular one is very complicated because it's trying to run LISP fast. And it has some very, very fast parallel operations in there like, if you want to index into an array, simultaneously check that the index is an integer, check that it doesn't exceed the array bands, and go off and do the memory access, and do all those things simultaneously. 613 01:06:57,120 --> 01:07:00,420 And then, later, if they're all OK, actually get the value there. 614 01:07:00,420 --> 01:07:06,550 So there are a lot of complicated operations in these data paths for making LISP run in parallel. 615 01:07:06,550 --> 01:07:10,640 It's a completely non-risk philosophy of evaluating LISP. 616 01:07:10,640 --> 01:07:13,740 And then, this microcode is pretty complicated. 617 01:07:13,740 --> 01:07:17,740 Let's see, there's what? 618 01:07:17,740 --> 01:07:27,940 There's about 389 instructions of 220-bit microcode sitting here because these are very complicated data paths. 619 01:07:27,940 --> 01:07:33,580 And the whole thing has about 89,000 transistors, OK? 620 01:07:33,580 --> 01:07:33,840 OK. 621 01:07:33,840 --> 01:07:37,970 Well, I hope that that takes away a lot of the mystery. 622 01:07:37,970 --> 01:07:39,240 Maybe somebody wants to look at this. 623 01:07:42,048 --> 01:07:43,298 Yeah. 624 01:07:46,260 --> 01:07:46,480 OK. 625 01:07:46,480 --> 01:07:47,730 Let's stop. 626 01:07:55,890 --> 01:07:57,815 Questions? 627 01:07:57,815 --> 01:08:15,165 AUDIENCE: OK, now, it sounds like what you're saying is that, with the restore continue put in the proper place, that procedures that would invoke a recursive process now invoke an integer process just by the way that the eval signature is? 628 01:08:15,165 --> 01:08:28,029 PROFESSOR: I think the way I'd prefer to put it is that, with restore continue put in the wrong place, you can cause any syntactically-looking recursive procedure, in fact, to build up stack as it runs. 629 01:08:28,029 --> 01:08:35,660 But there's no reason for that, so you might want to play around with it. 630 01:08:35,660 --> 01:08:45,060 You can just switch around two or three instructions in the way compound-apply comes back, and you'll get something which isn't tail recursive. 631 01:08:45,060 --> 01:08:47,670 But the thing I wanted to emphasize is there's no magic. 632 01:08:47,670 --> 01:09:01,060 It's not as if there's some very clever pre-processing program that's looking at this procedure, factorial iter, and say oh, gee, I really notice that I don't have to push stack in order to do this. 633 01:09:01,060 --> 01:09:03,760 Some people think that that's what's going on. 634 01:09:03,760 --> 01:09:08,880 It's something much, much more dumb than that, it's this one place you're putting the restore instruction. 635 01:09:08,880 --> 01:09:10,353 It's just automatic. 636 01:09:10,353 --> 01:09:11,603 AUDIENCE: OK. 637 01:09:14,217 --> 01:09:17,850 AUDIENCE: But that's not affecting the time complexity is it? 638 01:09:17,850 --> 01:09:18,275 PROFESSOR: No. 639 01:09:18,275 --> 01:09:23,020 AUDIENCE: It's just that it's handling it recursively instead of iteratively. 640 01:09:23,020 --> 01:09:29,220 But, in terms of the order of time it takes to finish the operation, it's the same one way or the other, right? 641 01:09:29,220 --> 01:09:29,920 PROFESSOR: Yes. 642 01:09:29,920 --> 01:09:36,029 Tail recursion is not going to change the time complexity of anything because, in some sense, it's the same algorithm that's going on. 643 01:09:36,029 --> 01:09:41,210 What it's doing is really making this thing run as an iteration, right? 644 01:09:41,210 --> 01:09:47,683 Not going to run out of memory counting up to a giant number simply because the stack would get pushed. 645 01:09:47,683 --> 01:09:57,990 See, the thing you really have to believe is that, when we write-- see, we've been writing all these things called iterations, infinite loops, define loop to be called loop. 646 01:10:01,660 --> 01:10:07,630 That's is as much an iteration as if we wrote do forever loop, right? 647 01:10:07,630 --> 01:10:09,280 It's just syntactic sugar as the difference. 648 01:10:09,280 --> 01:10:14,730 These things are real, honest to god, iterations, right? 649 01:10:14,730 --> 01:10:18,535 They don't change the time complexity, but they turn them into real iterations. 650 01:10:21,686 --> 01:10:23,800 All right, thank you. ================================================ FILE: SrtCN/lec9b.srt ================================================ 1 00:00:16,300 --> 00:00:18,080 教授:我想大家已经意识到 PROFESSOR: Well, I hope you appreciate that we have 2 00:00:20,010 --> 00:00:22,730 我们介绍了一些真正的魔法 we have inducted you into some real magic, 3 00:00:24,200 --> 00:00:27,240 创造新语言的魔法 the magic of building languages 4 00:00:27,420 --> 00:00:28,720 用来创造全新的语言 really building new languages. 5 00:00:29,690 --> 00:00:30,400 我们学了些什么? What have we looked at? 6 00:00:30,430 --> 00:00:32,780 我们学习了一门用来操作图片的Escher的语言 We've looked at an Escher picture language. 7 00:00:38,920 --> 00:00:41,150 这门语言由Peter Henderson发明 OK? this language invented by Peter Henderson. 8 00:00:42,010 --> 00:00:46,490 我们还学习了数字逻辑语言 We looked at digital logic language. 9 00:00:53,160 --> 00:00:55,550 以及 我们还学习了查询语言 Let's see.We've looked at the query language. 10 00:00:59,700 --> 00:01:00,780 然而你需要明白的是 And the thing you should realize is, 11 00:01:00,810 --> 00:01:03,100 尽管它们都是“玩具级”的语言示例 even though these were toy examples, 12 00:01:04,700 --> 00:01:07,610 但也确实是实用工具的核心 they really are the kernels of really useful things. 13 00:01:08,250 --> 00:01:09,480 比如说 So, for instance, 14 00:01:10,120 --> 00:01:11,184 Escher图片语言 the Escher picture language 15 00:01:11,200 --> 00:01:14,336 就被MIT的学生Henry Wu拿去 was taken byHenry Wu, who's a student at MIT, 16 00:01:14,880 --> 00:01:16,432 开发成了一门用于 and developed into a real 17 00:01:16,976 --> 00:01:19,450 为电路板布局的语言 language for laying out PC boards, 18 00:01:20,350 --> 00:01:22,560 它就是在这些结构上扩展而来 based just on extending those structures. 19 00:01:23,240 --> 00:01:24,650 至于数字逻辑语言 And the digital logic language, 20 00:01:24,680 --> 00:01:26,080 Gerry教授在上课的时候也提到过 Gerry mentioned when he showed it to you, 21 00:01:26,430 --> 00:01:29,920 它被扩展为了一个仿真器的基础 was really extended to be used as the basis for a simulator 22 00:01:30,850 --> 00:01:32,960 用来设计真实的计算机 that was used to design a real computer. 23 00:01:33,460 --> 00:01:34,320 至于查询语言 And the query language, 24 00:01:34,350 --> 00:01:36,440 当然就是Prolog语言的一种核心 of course, is kind of the germ of prolog. 25 00:01:37,510 --> 00:01:39,070 我们构造的这些语言 So we built all of these languages, 26 00:01:39,550 --> 00:01:40,650 全都是用Lisp编写 they're all based on LISP. 27 00:01:43,630 --> 00:01:44,590 很多人问 A lot of people ask 28 00:01:45,270 --> 00:01:48,730 Lisp适合用来解决哪一类问题? what particular problems is LISP good for solving for? 29 00:01:48,750 --> 00:01:49,930 答案就是 The answer is LISP is not... 30 00:01:50,330 --> 00:01:52,650 Lisp不适合解决任何一类问题 LISP is not good for solving any particular problems. 31 00:01:53,530 --> 00:01:54,600 Lisp擅长的是 What LISP is good for 32 00:01:54,730 --> 00:01:57,150 用它来构造一门合适的语言 is constructing within it the right language 33 00:01:57,180 --> 00:01:58,570 来解决你的问题 to solve the problems you want to solve, 34 00:01:59,170 --> 00:02:00,440 你应该像这样看待Lisp and that's how you should think about it. 35 00:02:01,470 --> 00:02:03,390 那么既然这些语言都基于Lisp So all of these languages were based on LISP. 36 00:02:04,570 --> 00:02:05,720 那Lisp又基于什么? Now, what's LISP based on? 37 00:02:06,970 --> 00:02:07,880 它又从何而来? Where's that come from? 38 00:02:07,900 --> 00:02:09,400 这个我们也学过 Well, we looked at that too. 39 00:02:09,580 --> 00:02:16,090 我们学过元循环求值器 We looked at the meta-circular evaluator 40 00:02:21,530 --> 00:02:23,400 学习了元循环求值器后 我们说 the meta-circular evaluator and sort of said 41 00:02:23,420 --> 00:02:25,760 Lisp就是基于Lisp的 well, LISP is based on LISP. 42 00:02:25,800 --> 00:02:27,480 而当我们研究它的时候 And when we start looking at that, 43 00:02:28,270 --> 00:02:29,950 我们必须得施展一些真正的魔法 对吧? we've got to do some real magic, right? 44 00:02:29,950 --> 00:02:31,740 这又是什么意思呢? So what does that mean, right? 45 00:02:31,740 --> 00:02:34,960 Y算子、不动点 Y operators, and fixed points, 46 00:02:35,760 --> 00:02:38,330 以及这样的一个观念-- and the idea that what this means is 47 00:02:38,360 --> 00:02:41,440 Lisp实际上是一个方程的不动点 that LISP is somehow the fixed-point equation for the 48 00:02:42,200 --> 00:02:45,420 一个通过自身来定义的有趣方程 for this funny set of things which are defined in terms of themselves. 49 00:02:47,400 --> 00:02:48,560 这确实是神奇的魔法 Now, it's real magic. 50 00:02:49,070 --> 00:02:52,350 那么今天 作为魔法的最后一步 Well, today, for a final piece of magic, 51 00:02:52,620 --> 00:02:54,030 我们要把它们通通消除掉 we're going to make all the magic go away. 52 00:03:06,800 --> 00:03:07,980 我们已经知道怎么做了 We already know how to do that. 53 00:03:09,770 --> 00:03:10,768 核心要思想是 The idea is, we're going to take 54 00:03:11,136 --> 00:03:12,730 将Lisp语言 the register machine architecture 55 00:03:13,360 --> 00:03:15,500 实现在使用寄存器架构的机器上 and show how to implement LISP on terms of that. 56 00:03:15,500 --> 00:03:17,936 回想一下 寄存器机器的关键之处在于 And, remember, the idea of the register machine 57 00:03:19,600 --> 00:03:24,680 机器的一部分是确定且有穷的 is that there's a fixed and finite part of the machine. 58 00:03:24,720 --> 00:03:26,120 它有一个有穷状态控制器 There's a finite-state controller, 59 00:03:26,120 --> 00:03:27,872 它用特定的硬件 which dose particular thing 60 00:03:27,888 --> 00:03:29,310 去完成特定的事情 with a particular amount of hardware. 61 00:03:30,510 --> 00:03:31,740 其中还有一些运算所需的 There are particular data paths, 62 00:03:31,760 --> 00:03:33,240 特殊数据通路 the operation the machine does 63 00:03:33,550 --> 00:03:35,290 然后 为了实现递归 And then, in order to implement recursion 64 00:03:35,530 --> 00:03:37,600 并且维持无穷的假象 and sustain the illusion of infinity, 65 00:03:37,820 --> 00:03:39,770 还使用了一种称作“栈”的大内存 there's some large amount of memory, which is the stack. 66 00:03:42,060 --> 00:03:43,728 所以如果我们在 So, if we implement LISP 67 00:03:43,920 --> 00:03:45,500 寄存器机器上实现了Lisp in terms of a register machine, 68 00:03:47,020 --> 00:03:48,350 那么这个时候 then everything ought to become, 69 00:03:48,400 --> 00:03:49,850 所有的东西都会完全具体化 at this point,completely concrete. 70 00:03:49,850 --> 00:03:51,230 所有的魔法都会消除 All the magic should go away. 71 00:03:51,650 --> 00:03:53,520 这堂课结束时 And, by the end of this talk, 72 00:03:53,530 --> 00:03:54,780 我想让你感觉到 I want you get the feeling 73 00:03:55,140 --> 00:03:59,050 相对于神秘的元循环求值器 that, as opposed to this very mysterious meta-circular evaluator 74 00:03:59,670 --> 00:04:02,600 Lisp求值器是非常具体的东西 that a LISP evaluator really is something that's concrete enough 75 00:04:02,850 --> 00:04:04,570 你甚至可以把它放在手心中 that you can hold in the palm of your hand. 76 00:04:04,760 --> 00:04:06,240 你可以想象一下 You should be able to imagine holding 77 00:04:06,570 --> 00:04:07,900 手里拿着一个Lisp解释器的情景 holding a LISP interpreter there. 78 00:04:09,630 --> 00:04:10,940 好 那我们怎么做呢? All right, how are we going to do this? 79 00:04:10,950 --> 00:04:12,760 所有的原料都已经齐全 We already have all the ingredients. 80 00:04:13,960 --> 00:04:17,450 上节课Gerry教了你们 See, what you learned last time from Gerry 81 00:04:17,600 --> 00:04:21,470 对一个任意的Lisp过程 is how to take any particular couple of LISP procedures. 82 00:04:22,600 --> 00:04:24,280 如何手动地把它们 and hand-translate them 83 00:04:24,750 --> 00:04:26,670 翻译成在寄存器机器上运行的代码 into something that runs on a register machine. 84 00:04:28,200 --> 00:04:30,520 那么 要在寄存器机器上实现Lisp本身 So, to implement all of LISP on a register machine, 85 00:04:30,570 --> 00:04:31,440 我们只需要 all we have to do 86 00:04:31,690 --> 00:04:33,450 把最关键的过程 is take the particular procedures 87 00:04:33,680 --> 00:04:35,420 也就是元循环求值器 that are the meta-circular evaluator 88 00:04:36,170 --> 00:04:38,110 手工翻译成寄存器机器的代码 and hand-translate them for a register machine. 89 00:04:39,040 --> 00:04:40,250 这就实现了整个Lisp And that does all of LISP 90 00:04:42,140 --> 00:04:43,008 因此 我们已经知道了 Right? So, in principle, 91 00:04:43,024 --> 00:04:44,430 实现的原理 we already know how to do this. 92 00:04:45,380 --> 00:04:46,544 而且实际上 And, indeed, it's going to be no 93 00:04:46,688 --> 00:04:48,864 这跟翻译 no different, in kind, 94 00:04:50,000 --> 00:04:53,400 递归版的阶乘或斐波那契数列 from in say recursive factorial 95 00:04:53,420 --> 00:04:54,670 没什么区别 or recursive Fibonacci. 96 00:04:54,670 --> 00:04:56,000 只是它规模更大 代码更多 It's just bigger and there's more of it. 97 00:04:56,840 --> 00:04:58,030 只是包含了更多细节 So it'd just be more details, 98 00:04:58,040 --> 00:04:59,660 但是没有任何新的概念 but nothing really conceptually new. 99 00:05:01,480 --> 00:05:03,020 当我们完成这个以后 And also, when we've done that, 100 00:05:03,080 --> 00:05:04,760 所有的东西都变得明确了 and the thing is completely explicit, 101 00:05:04,870 --> 00:05:06,910 当我们看到如何用一系列的 and we see how to implement LISP 102 00:05:06,940 --> 00:05:10,080 寄存器操作来实现Lisp之后 in terms of the actual sequential register operations, 103 00:05:10,160 --> 00:05:11,630 它就成为了我们整个课程中 that's going to be our final 104 00:05:11,950 --> 00:05:14,160 最明确的Lisp模型 most explicit model of LISP in this course. 105 00:05:14,810 --> 00:05:16,950 回忆一下 这个过程贯穿了整个课程 And, remember, that's a progression through this course. 106 00:05:16,950 --> 00:05:18,250 我们先从代换模型开始 We started out with substitution, 107 00:05:18,280 --> 00:05:19,580 它和代数有点相似 which is sort of like algebra. 108 00:05:20,240 --> 00:05:21,870 然后学习了环境模型 And then we went to the environment model, 109 00:05:21,880 --> 00:05:24,000 它引入了“框架”的概念 which talked about the actual frames 110 00:05:24,030 --> 00:05:25,310 以及框架之间的关联 and how they got linked together. 111 00:05:26,320 --> 00:05:27,880 然后我们在元循环求值器中 And then we made that more concrete 112 00:05:27,900 --> 00:05:29,360 把它变得更具体了 in the meta-circular evaluator. 113 00:05:31,050 --> 00:05:31,640 但是有的事情 There are things 114 00:05:31,870 --> 00:05:33,980 元循环求值器没有告诉我们 the meta-circular evaluator doesn't tell us. 115 00:05:34,360 --> 00:05:35,340 你应该认识到这点 You should realize that. 116 00:05:36,090 --> 00:05:38,640 比如说 我们还不知道 For instance, it left unanswered the question 117 00:05:38,730 --> 00:05:42,670 像这里的递归阶乘过程 of how a procedure, like recursive factorial here, 118 00:05:45,170 --> 00:05:47,130 为何不断地申请新的空间 somehow takes space that grows. 119 00:05:47,210 --> 00:05:47,980 另一方面 On the other hand, 120 00:05:48,160 --> 00:05:51,940 一个语法上看起来像是递归的过程 a procedure which also looks syntactically recursive, 121 00:05:52,110 --> 00:05:55,070 比如FACT-ITER 并不占用栈空间 called fact-iter, somehow doesn't take space. 122 00:05:55,100 --> 00:05:59,160 我们通过代换模型来证明 We justify that it doesn't need to take space 123 00:06:00,500 --> 00:06:01,960 它不占用空间 by showing the substitution model. 124 00:06:01,960 --> 00:06:02,940 但我们并没有说清楚 But we didn't really say 125 00:06:03,420 --> 00:06:06,760 机器是如何做到这一点的 how it happens that the machine manages to do that, 126 00:06:07,310 --> 00:06:08,910 这涉及到一些细节 that that has to do with the details 127 00:06:09,020 --> 00:06:11,120 比如参数是如何传递给过程的 of how arguments are passed to procedures 128 00:06:12,480 --> 00:06:13,690 这是我们在元循环求值器中 And that's the thing we didn't see 129 00:06:13,710 --> 00:06:15,340 没有看到的 in the meta-circular evaluator 130 00:06:15,360 --> 00:06:17,400 完全是因为在所实现的Lisp中 precisely because the way arguments 131 00:06:17,420 --> 00:06:19,200 把参数传递给过程的方式 got passed to procedures in this LISP 132 00:06:19,700 --> 00:06:20,590 取决于 depended on 133 00:06:21,020 --> 00:06:23,500 外部Lisp的传参方式 the way arguments got passed to procedures in this LISP. 134 00:06:25,870 --> 00:06:29,020 但现在 这一点将变得非常明确 But, now, that's going to become extremely explicit. 135 00:06:30,740 --> 00:06:31,120 好 OK. 136 00:06:31,230 --> 00:06:34,300 在开始研究求值器之前 Well, before going on to the evaluator, 137 00:06:34,360 --> 00:06:35,530 我先让你们感受一下 let me just give you a sense of 138 00:06:35,550 --> 00:06:37,000 一个完整Lisp系统是怎么样的 what a whole LISP system looks like 139 00:06:37,600 --> 00:06:39,360 这样你就可以知道 我们要讨论哪部分 so you can see the parts we're going to talk about 140 00:06:39,400 --> 00:06:40,810 不讨论哪些部分 and the parts we're not going to talk about. 141 00:06:43,180 --> 00:06:47,420 首先 这里有一个快乐的Lisp用户 Let's see, over here is a happy LISP user, 142 00:06:48,670 --> 00:06:52,650 他正在和一个叫做读取器的东西交流 and the LISP user is talking to something called the reader. 143 00:07:00,360 --> 00:07:01,530 读取器的工作是 The reader's job in life 144 00:07:01,950 --> 00:07:13,230 读取用户输入的字符串 is to take characters from the user 145 00:07:14,170 --> 00:07:16,620 把它们转化成一种称作 and turn them into data structures 146 00:07:17,200 --> 00:07:19,370 表结构内存的数据结构 in something called a list structure memory. 147 00:07:30,000 --> 00:07:31,720 读取器会读取-- All right, so the reader is going to take 148 00:07:32,650 --> 00:07:33,950 你敲出来的符号、括号 symbols, parentheses, 149 00:07:34,480 --> 00:07:37,120 A和B、1和3这些东西 and A's and B's, and 1s and 3s that you type in, 150 00:07:37,180 --> 00:07:39,040 并把它们变成表结构 and turn these into actual list structure: 151 00:07:39,150 --> 00:07:40,540 变成序对、指针等等 pairs, and pointers, and things. 152 00:07:42,350 --> 00:07:43,920 所以当求值器运行的时候 And so, by the time evaluator is going, 153 00:07:43,930 --> 00:07:45,100 环境里已经不存在原始字符了 there are no characters in the world. 154 00:07:45,850 --> 00:07:48,160 当然 在更现代的Lisp系统中 And, of course, in more modern Lisp systems, there's 155 00:07:49,000 --> 00:07:50,440 可能还有一大团东西 there's sort a big morass here 156 00:07:50,440 --> 00:07:52,170 存在于在读取器和用户之间 that might sit between the user and the reader: 157 00:07:52,410 --> 00:07:54,520 最顶层首先是视窗系统 you know, Windows systems, in top levels, 158 00:07:54,770 --> 00:07:56,030 以及鼠标之类的东西 and mice, and all kinds of things. 159 00:07:56,280 --> 00:07:58,200 但从概念上来说 都是在输入字符 But conceptually, characters are coming in. 160 00:07:59,930 --> 00:08:04,320 总之 读取器把它们都变成指针 All right, the reader transforms these into pointers 161 00:08:05,560 --> 00:08:07,280 指向内存中的对象 pointers to stuff in this memory, 162 00:08:08,270 --> 00:08:10,940 这是求值器的所能看到的东西 and that's what the evaluator sees 163 00:08:15,550 --> 00:08:16,040 明白吗? OK? 164 00:08:17,020 --> 00:08:18,880 求值器有一些辅助函数 The evaluator has a bunch of helpers. 165 00:08:19,780 --> 00:08:23,160 包括你需要的所有基本运算 It has all possible primitive operators you might want. 166 00:08:23,160 --> 00:08:24,910 也就是说这里另有一盒子东西 So there's a completely separate box, 167 00:08:28,400 --> 00:08:30,250 比如浮点单元 a floating point unit, 168 00:08:32,220 --> 00:08:34,400 或者其它类似的东西来执行这些运算 or all sorts of things, which do the primitive operators. 169 00:08:35,390 --> 00:08:37,680 如果你需要支持更多的基本运算 there's and, if you want more special primitives, 170 00:08:37,710 --> 00:08:39,020 你就实现更多的运算符执行器 you build more primitive operators, 171 00:08:39,050 --> 00:08:40,480 但它们和求值器都是分离的 but they're separate from the evaluator. 172 00:08:42,080 --> 00:08:43,770 求值器最终算出结果 The evaluator finally gets an answer 173 00:08:45,168 --> 00:08:46,768 并且把它们告诉打印程序 and communicates that to the printer. 174 00:08:50,624 --> 00:08:52,016 现在 打印程序的任务就是 And now, the printer's job in life 175 00:08:52,016 --> 00:08:54,544 从求值器取得这个表结构 is this list structure coming from the evaluator, 176 00:08:55,392 --> 00:08:56,992 再把它们变回字符 and turn it back into characters, 177 00:09:01,856 --> 00:09:04,070 然后通过某种界面 and communicate them to the user through 178 00:09:04,288 --> 00:09:05,664 展示给用户 whatever interface there is. 179 00:09:08,050 --> 00:09:11,232 那么 今天我们要讨论的是这个求值器 OK. Well, today, what we're going to talk about is this evaluator. 180 00:09:12,670 --> 00:09:15,200 基本运算和Lisp没有什么特别的关系 The primitive operators have nothing particular to do with LISP, 181 00:09:15,200 --> 00:09:18,144 它们只取决于你怎么实现基本运算 they're however you like to implement primitive operations. 182 00:09:19,360 --> 00:09:22,180 读取器和打印程序实际上很复杂 The reader and printer are actually complicated, 183 00:09:22,180 --> 00:09:23,552 但是我们不去讨论它们 but we're not going to talk about them. 184 00:09:24,688 --> 00:09:27,100 从字符构建表的过程中 They sort of have to do with details of how you might build 185 00:09:27,100 --> 00:09:28,928 它们需要处理很多细节 build up list structure from characters. 186 00:09:29,900 --> 00:09:31,184 说来话长 So that is a long story, 187 00:09:31,184 --> 00:09:32,320 我们就不讨论它了 but we're not going to talk about it, 188 00:09:32,490 --> 00:09:33,696 关于表结构内存 the list structure memory, 189 00:09:34,368 --> 00:09:35,632 我们下次再来讨论 we'll talk about next time. 190 00:09:36,930 --> 00:09:39,728 那么去除了读取和打印的细节 So, pretty much, except for the details of reading and printing, 191 00:09:40,120 --> 00:09:41,712 关于这个求值器 the only mystery that's going to be left 192 00:09:41,728 --> 00:09:43,056 所剩下的唯一谜团 after you see the evaluator 193 00:09:43,250 --> 00:09:45,856 几乎就只有怎么在传统内存上构建表结构了 is how you build list structure on conventional memories. 194 00:09:46,656 --> 00:09:48,208 不过我们把那也放到下次来讨论 But we'll worry about that next time too. 195 00:09:50,580 --> 00:09:51,040 好 OK. 196 00:09:53,344 --> 00:09:56,110 那么 我们先来看看这个求值器 Well, let's start talking about the evaluator. 197 00:09:56,200 --> 00:09:58,320 我将要展示的这个求值器 The one that we're going to show you, 198 00:09:58,496 --> 00:10:01,120 我想 它并没有什么特别的 of course, is not, I think, nothing special about it. 199 00:10:01,152 --> 00:10:04,560 它只是一台专门运行Lisp的寄存器机器 It's just a particular register machine that runs LISP. 200 00:10:04,810 --> 00:10:06,096 它有七个寄存器 And it has seven registers, 201 00:10:07,888 --> 00:10:09,264 这是它的七个寄存器 and here are the seven registers. 202 00:10:09,890 --> 00:10:12,384 这个寄存器叫EXP There's a register, called EXP 203 00:10:14,120 --> 00:10:15,536 它的任务是存放 and its job is to hold 204 00:10:16,368 --> 00:10:18,032 将要被求值的表达式 the expression to be evaluated. 205 00:10:18,370 --> 00:10:19,808 具体来说 And by that, I mean 206 00:10:20,384 --> 00:10:21,648 它存放的是一个指针 it's going to hold a pointer 207 00:10:22,032 --> 00:10:23,552 指针指向存放着求值的表达式 to someplace in list structure memory 208 00:10:23,568 --> 00:10:25,328 的一处表结构内存 the expression to be evaluated. 209 00:10:26,550 --> 00:10:27,824 还有一个叫做ENV的寄存器 There's a register, called ENV, 210 00:10:28,880 --> 00:10:30,288 它存放着环境 which holds the environment 211 00:10:31,000 --> 00:10:33,056 也就是表达式的求值环境 in which this expression is to be evaluated. 212 00:10:34,070 --> 00:10:35,024 同样的 这也是一个指针 And, again, I made a pointer. 213 00:10:35,024 --> 00:10:36,752 环境是一种数据结构 The environment is some data structure. 214 00:10:38,240 --> 00:10:40,144 这个叫做FUN的寄存器-- There's a register, called FUN, which will 215 00:10:40,752 --> 00:10:42,544 当你在应用一个过程时 which will hold the procedure to be applied 216 00:10:42,576 --> 00:10:43,968 它会存放这个过程 when you go to apply a procedure. 217 00:10:44,560 --> 00:10:46,240 还有寄存器ARGL A register, called ARGL, 218 00:10:47,360 --> 00:10:49,344 它存放的是已求值的参数 which holds the list of evaluated arguments. 219 00:10:50,540 --> 00:10:51,600 从这里开始你能看到 What you can start seeing here is 220 00:10:51,632 --> 00:10:53,140 求值器的基本构造 the basic structure of the evaluator. 221 00:10:53,140 --> 00:10:54,490 回忆一下它是怎么工作的 Remember how evaluators work. 222 00:10:54,490 --> 00:10:56,624 对这一块输入表达式和环境 There's a piece that takes expressions and environments, 223 00:10:57,670 --> 00:10:59,712 而这一块接收函数 and there's a piece that takes functions 224 00:10:59,744 --> 00:11:02,144 或者说 过程以及参数 or procedures and arguments. 225 00:11:03,480 --> 00:11:06,304 EVAL-APPLY循环使用这些寄存器工作 And going back and forth around here is the eval/apply loop. 226 00:11:07,408 --> 00:11:09,696 所以这些是EVAL-APPLY的基本组成部分 So those are the basic pieces of the eval and apply. 227 00:11:10,200 --> 00:11:10,992 还有一些别的东西 Then there's some other things, 228 00:11:11,008 --> 00:11:11,610 比如CONTINUE寄存器 there's continue. 229 00:11:11,610 --> 00:11:15,340 你之前已经见过CONTINUE寄存器 You just saw before how the continue register is used to 230 00:11:15,340 --> 00:11:18,048 是如何实现递归以及栈操作的 implement recursion and stack discipline. 231 00:11:18,940 --> 00:11:20,688 还有个寄存器用来存放 There's a register that's going to hold the 232 00:11:20,944 --> 00:11:22,520 某个求值的结果 result of some evaluation. 233 00:11:24,140 --> 00:11:24,896 然后 除了这些以外 And then, besides that, 234 00:11:24,896 --> 00:11:26,432 还有一个临时寄存器 there's one temporary register, 235 00:11:26,700 --> 00:11:27,296 它就是UNEV called UNEV, 236 00:11:27,296 --> 00:11:29,040 一般来讲 在求值器中 which typically, in the evaluator, 237 00:11:29,280 --> 00:11:32,720 它是用来存放正在求值的表达式 is going to be used to hold temporary pieces of the 238 00:11:32,896 --> 00:11:33,950 的临时部分 expression you're working on, 239 00:11:33,950 --> 00:11:35,728 就是那些尚未求值的部分 which you haven't gotten around to evaluate yet 240 00:11:36,976 --> 00:11:39,824 那么 这就是我的七寄存器机器 Right? So there's my machine: a seven-register machine. 241 00:11:40,960 --> 00:11:42,980 当然 你可能想造一台 And, of course, you might want to make a machine with 242 00:11:42,980 --> 00:11:44,960 有更多寄存器的机器 来取得更好性能 a lot more registers to get better performance, 243 00:11:44,976 --> 00:11:47,056 但我们这个只是一台小型机器 but this is just a tiny, minimal one. 244 00:11:48,480 --> 00:11:49,584 那么数据通路呢? Well, how about the data paths? 245 00:11:49,780 --> 00:11:53,664 这台机器有很多专为Lisp设计的运算 This machine has a lot of special operations for LISP. 246 00:11:55,100 --> 00:11:58,080 这里有几条典型的数据通路 So, here are some typical data paths. 247 00:12:00,120 --> 00:12:01,040 其中一条可能是 A typical one might be, 248 00:12:01,370 --> 00:12:03,408 将EXP寄存器的值 oh, assign to the VAL register 249 00:12:03,408 --> 00:12:04,800 赋给VAL寄存器 the contents of the EXP register. 250 00:12:05,710 --> 00:12:08,016 用我们之前的数据通路图来说 That's in terms of those diagrams you saw, 251 00:12:08,032 --> 00:12:10,816 就是一条箭头上的小按钮 that's a little button on some arrow. 252 00:12:11,900 --> 00:12:13,136 这还有一个更复杂的 Here's a more complicated one. 253 00:12:13,690 --> 00:12:14,800 它判断 It says branch, 254 00:12:15,230 --> 00:12:19,584 如果EXP寄存器的内容是COND语句 if the thing in the expression register is a conditional 255 00:12:20,496 --> 00:12:22,720 那么这里就会跳转到EV-COND标号处 to some label here, called the ev-conditional. 256 00:12:23,808 --> 00:12:26,230 你可以想象出很多种实现它的方法 And you can imagine this implemented in a lot of different ways. 257 00:12:26,230 --> 00:12:28,368 你可以把这个判断看作是 You might imagine this conditional test 258 00:12:28,368 --> 00:12:29,984 一个特殊意图的子过程 as a special purpose sub-routine, 259 00:12:30,600 --> 00:12:33,952 而条件被表示成某种数据抽象 and conditional might be represented as some data abstraction 260 00:12:33,968 --> 00:12:36,000 你在这个层面上不用考虑它 that you don't care about at this level of detail. 261 00:12:36,610 --> 00:12:37,980 那么它可以用子过程实现 So that might be done as a sub-routine. 262 00:12:37,980 --> 00:12:40,672 如果机器通过硬件来判断表达式类型 This might be a machine with hardware-types, 263 00:12:40,900 --> 00:12:44,048 那么某些特定比特就代表了COND语句 and conditional might be testing some bits for a particular code. 264 00:12:45,350 --> 00:12:46,410 有很多种实现办法 There are all sorts of ways that's 265 00:12:46,410 --> 00:12:48,480 它们都低于我们关注的这一层抽象 beneath the level of abstraction we're looking at. 266 00:12:50,190 --> 00:12:51,712 然后还有另一种操作 Another kind of operation, 267 00:12:51,712 --> 00:12:53,240 以及其它很多操作 and there are a lot of different operations 268 00:12:53,240 --> 00:12:56,656 把EXP的第一个子句赋值给EXP assigned to EXP, the first clause of what's in EXP. 269 00:12:56,840 --> 00:12:58,896 这可能是处理COND语句的一部分 This might be part of processing a conditional. 270 00:12:59,260 --> 00:13:01,808 同样 FIRST-SELECTOR这个选择子 And, again, first clause is some selector 271 00:13:03,072 --> 00:13:04,480 我们也不需要关心它的细节 whose details we don't care about. 272 00:13:04,496 --> 00:13:06,464 同样可以把那也看成一个子过程 And you can, again, imagine that as a sub-routine 273 00:13:06,460 --> 00:13:07,904 用来进行一些表操作 which'll do some list operations, 274 00:13:08,224 --> 00:13:09,180 或者你也可以想象成 or you can imagine that as 275 00:13:09,180 --> 00:13:10,736 一个直接构建在硬件中的东西 something that's built directly into hardware. 276 00:13:12,170 --> 00:13:13,712 我之所以强调 The reason I keep saying you can imagine it 277 00:13:14,032 --> 00:13:15,220 你可以把它想象成硬件直接实现 built directly into hardware 278 00:13:15,220 --> 00:13:17,808 是因为尽管有很多的运算 is even though there are a lot of operations, 279 00:13:18,360 --> 00:13:19,740 但也它们的数量也是固定的 there are still a fixed number of them. 280 00:13:20,128 --> 00:13:21,808 我记不清有多少 大概有150个 I forget how many, maybe 150. 281 00:13:22,370 --> 00:13:25,392 所以假设用硬件实现它们是合理的 So, it's plausible to think of building these directly into hardware. 282 00:13:26,416 --> 00:13:27,680 而这一条更加复杂 Here's a more complicated one. 283 00:13:28,270 --> 00:13:29,472 你会发现 这条涉及到 You can see this has to do with 284 00:13:29,472 --> 00:13:31,104 查找变量的值 looking up the values of variables. 285 00:13:31,500 --> 00:13:33,280 它会查找某条表达式中 It says assign to the VAL register 286 00:13:33,456 --> 00:13:36,912 某个变量的值 the result of looking up the variable value 287 00:13:36,992 --> 00:13:38,528 并赋值给VAL寄存器 of some particular expression, 288 00:13:39,180 --> 00:13:40,304 在本例中 也就是 which, in this case, is supposed to be 289 00:13:40,336 --> 00:13:42,000 在某个环境中查找变量 a variable in some environment. 290 00:13:42,800 --> 00:13:44,688 然后这个操作 And this'll be some operation 291 00:13:45,210 --> 00:13:47,504 会搜索整个环境结构 that search through the environment structure, 292 00:13:47,520 --> 00:13:48,976 无论环境是如何表示的 however it is represented, 293 00:13:49,376 --> 00:13:50,912 并查找该变量 and goes and looks up that variable. 294 00:13:52,176 --> 00:13:53,952 同样 它也不在我们思考的 And, again, that's below the level of detail 295 00:13:53,960 --> 00:13:54,864 的抽象层面上 that we're thinking about. 296 00:13:54,896 --> 00:13:57,300 它需要处理的细节是 This is... this has to do with the details of 297 00:13:57,552 --> 00:13:59,440 用来表示环境的数据结构 the data structures for representing environments. 298 00:14:00,070 --> 00:14:01,216 但是不管怎么说 But, anyway, there is this 299 00:14:01,312 --> 00:14:03,470 这就是这台寄存器机器的 there is this fixed and finite number 300 00:14:04,112 --> 00:14:06,080 有穷数量的固定操作 of operations in the register machine. 301 00:14:08,500 --> 00:14:11,600 那么 它的整体结构是什么样子的? Well, what's its overall structure? 302 00:14:11,720 --> 00:14:13,232 这有几个典型的运算 Those are some typical operations. 303 00:14:14,768 --> 00:14:16,336 想一想 我们要做什么 Remember what we have to do, 304 00:14:16,440 --> 00:14:18,400 我们需要把元循环求值器 we have to take the meta-circular evaluator-- 305 00:14:20,432 --> 00:14:22,760 这就是元循环求值器的一部分 and here's a piece of the meta-circular evaluator. 306 00:14:22,760 --> 00:14:26,896 这是书中使用抽象代码的版本 This is the one using abstract syntax that's in the book. 307 00:14:28,224 --> 00:14:31,536 它和Gerry教授给你们展示的有些不同 It's a little bit different from the one that Gerry shows you. 308 00:14:33,500 --> 00:14:35,104 关于求值器 And the main thing 309 00:14:35,136 --> 00:14:37,870 主要需要记住的是 to remember about the evaluator is that 310 00:14:37,870 --> 00:14:40,960 它是某种针对表达式类型的分情况分析 it's doing some sort of case analysis on the kinds of expressions: 311 00:14:43,760 --> 00:14:45,904 看它是否为自求值的 或被引用的 so if it's either self-evaluated, or quoted, 312 00:14:45,920 --> 00:14:46,864 或是别的什么 or whatever else. 313 00:14:48,560 --> 00:14:50,576 而在大部分情况下 And then, in the general case where 314 00:14:50,860 --> 00:14:52,960 它处理的是一个过程应用 the expression it's looking at is an application, 315 00:14:53,550 --> 00:14:55,360 那么里面有一些技巧性的递归过程 there's some tricky recursions going on. 316 00:14:55,750 --> 00:14:59,360 首先 EVAL要调用它自己 First of all, eval has to call itself 317 00:14:59,790 --> 00:15:01,456 来求值运算符以及 both to evaluate the operator 318 00:15:02,144 --> 00:15:04,048 所有的运算对象 and to evaluate all the operands. 319 00:15:05,880 --> 00:15:07,408 因此这些标红线的地方 So there's this sort of red recursion 320 00:15:07,632 --> 00:15:09,280 就是某种在语法树上的递归 of values walking down the tree 321 00:15:10,944 --> 00:15:12,270 这是很简单的递归 that's sort of the easy recursion. 322 00:15:12,270 --> 00:15:14,448 只是EVAL在递归地遍历语法树 That's just eval walking down this tree of expressions. 323 00:15:14,750 --> 00:15:15,536 然后在求值器中 Then, in the evaluator, 324 00:15:15,536 --> 00:15:16,460 有一个复杂的递归 there's a hard recursion. 325 00:15:16,490 --> 00:15:17,920 由绿线到红线的递归 There's the red to green. 326 00:15:18,000 --> 00:15:19,660 由EVAL调用APPLY Eval calls apply. 327 00:15:22,470 --> 00:15:26,450 也就是把过程调用 That's the case where evaluating a procedure argument 328 00:15:26,450 --> 00:15:28,720 归约为了 将过程应用在 reduces to applying the procedure 329 00:15:28,944 --> 00:15:29,936 实参表上 to the list of arguments. 330 00:15:30,370 --> 00:15:31,760 然后请看APPLY And then, apply comes over here. 331 00:15:34,770 --> 00:15:36,672 APPLY需要过程PROC和参数ARGS Apply takes a procedure and arguments 332 00:15:37,650 --> 00:15:39,456 一般情况下 and, in the general case 333 00:15:39,488 --> 00:15:40,816 PROC都是一个复合过程 where there's a compound procedure, 334 00:15:41,050 --> 00:15:42,192 随着APPLY不断被调用 apply goes around and 335 00:15:42,256 --> 00:15:43,152 绿线处会调用红线处 green calls red. 336 00:15:43,344 --> 00:15:46,448 APPLY被调用并再次调用EVAL Eval-- Apply comes around and calls eval again. 337 00:15:48,170 --> 00:15:49,792 EVAL会求值过程体 Eval's the body of the procedure 338 00:15:50,240 --> 00:15:52,592 基于一个扩展了的环境 in the result of extending the environment 339 00:15:53,696 --> 00:15:55,280 这个环境通过将过程的形式参数 with the parameters of the procedure 340 00:15:55,480 --> 00:15:56,928 与实际参数绑定起来而得 by binding the arguments. 341 00:15:59,620 --> 00:16:00,624 而对于最基本的情况 Except in the primitive case, 342 00:16:00,640 --> 00:16:02,528 它会调用PRIMITIVE-APPLY过程 where it just calls something else primitive-apply 343 00:16:02,736 --> 00:16:04,704 而那又不是求值器的工作了 which is not really the business of the evaluator. 344 00:16:05,980 --> 00:16:07,472 那么像这样从红到绿 So this sort of red to green, 345 00:16:07,470 --> 00:16:08,400 又到红又到绿 to red to green, 346 00:16:09,792 --> 00:16:12,720 这就是EVAL-APPLY循环 Right? That's the that's the eval/apply loop, 347 00:16:14,064 --> 00:16:15,744 这就是我们在求值器中 and that's the thing that we're going to want to see 348 00:16:16,192 --> 00:16:17,728 想要看到的东西 in the evaluator. 349 00:16:19,696 --> 00:16:21,070 这样 你不会惊异于 Well, it won't surprise you at all that 350 00:16:21,070 --> 00:16:23,520 这个求值器的两大部分 the two big pieces of this evaluator 351 00:16:25,344 --> 00:16:27,040 对应于EVAL-APPLY are correspond to eval and apply. 352 00:16:27,470 --> 00:16:29,440 一个部分叫EVAL-DISPATCH There's a piece called eval-dispatch, 353 00:16:29,600 --> 00:16:31,200 另一部分叫做APPLY-DISPATCH and a piece called apply-dispatch. 354 00:16:32,000 --> 00:16:34,090 在我们关注代码细节之前 And, before we get into the details of the code, 355 00:16:34,208 --> 00:16:35,760 理解它们的方法就是 the way to understand this is to think, 356 00:16:36,090 --> 00:16:39,024 假设这些求值器的各个部分 again, in terms of these pieces of evaluator 357 00:16:39,024 --> 00:16:40,976 和这个世界中其它的部分有一些约定 having contracts with the rest of the world. 358 00:16:41,870 --> 00:16:43,184 在进入这些肮脏的细节前 What do they do from the outside 359 00:16:43,200 --> 00:16:45,504 它们在外部做了什么? before getting into the grungy details? 360 00:16:45,780 --> 00:16:49,328 针对EVAL-DISPATCH的约定 Well, the contract for eval-dispatch-- 361 00:16:50,016 --> 00:16:51,408 还记得吗 它对应的是EVAL remember, it corresponds to eval. 362 00:16:51,552 --> 00:16:54,100 它要在环境中求值一个表达式 It's got to evaluate an expression in an environment. 363 00:16:54,100 --> 00:16:55,888 那么 这部分要做的就是 So, in particular, what this one is going to do, 364 00:16:56,520 --> 00:16:58,688 EVAL-DISPATCH会假设当你调用它的时候 eval-dispatch will assume that, when you call it, 365 00:16:59,680 --> 00:17:01,488 你想要求值的表达式 that the expression you want to evaluate 366 00:17:01,488 --> 00:17:02,528 就存放在EXP寄存器中 is in the EXP register. 367 00:17:03,640 --> 00:17:07,392 而求值所基于的环境 The environment in which you want the evaluation 368 00:17:07,456 --> 00:17:09,056 则存放在ENV环境中 to take place is in the ENV register. 369 00:17:09,560 --> 00:17:10,672 而CONTINUE寄存器用来指示 And continue tells you 370 00:17:10,848 --> 00:17:12,464 当求值完成后 the place where the machine should go next 371 00:17:12,528 --> 00:17:13,920 机器需要去向何方 when the evaluation is done. 372 00:17:17,280 --> 00:17:19,184 EVAL-DISPATCH的约定实际上就是 Eval-dispatch's contract is that 373 00:17:19,280 --> 00:17:21,264 它会执行实际的求值 it'll actually perform that evaluation, 374 00:17:21,400 --> 00:17:22,464 并且在求值结束后 and, at the end of which, 375 00:17:23,280 --> 00:17:25,632 它会转到由CONTINUE寄存器指定的位置 it'll end up at the place specified by continue. 376 00:17:26,610 --> 00:17:29,168 求值的结果会存放在VAL寄存器中 The result of the evaluation will be in the VAL register. 377 00:17:29,820 --> 00:17:30,960 需要提醒的是 And it just warns you, 378 00:17:30,992 --> 00:17:32,912 它对其余的寄存器 it makes no promises about 379 00:17:32,960 --> 00:17:34,608 不做任何承诺 what happens to rest the registers. 380 00:17:35,230 --> 00:17:36,816 其它所有的寄存器都可能被修改 All other registers might be destroyed. 381 00:17:37,490 --> 00:17:40,144 那么这是一部分 So, there's one piece, OK? 382 00:17:41,552 --> 00:17:43,488 这些部分一块构成了APPLY-DISPATCH Together, the pieces, apply-dispatch 383 00:17:43,520 --> 00:17:44,928 它们对应了APPLY that corresponds to apply, 384 00:17:46,096 --> 00:17:48,432 用来把一个过程应用在一些参数上 it's got to apply a procedure to some arguments, 385 00:17:48,730 --> 00:17:51,430 因此它假设ARGL寄存器 so it assumes that this register, ARGL, 386 00:17:51,680 --> 00:17:53,776 存放着求值后的参数列表 contains a list of the evaluated arguments. 387 00:17:54,540 --> 00:17:55,968 FUN寄存器存放着那个过程 FUN contains the procedure. 388 00:17:57,220 --> 00:17:58,832 它们对应于元循环求值器中的 Those correspond to the arguments to 389 00:17:58,944 --> 00:18:01,360 参数应用部分 the apply procedure in the meta-circular evaluator. 390 00:18:03,970 --> 00:18:06,048 在我们的这个求值器中 And apply, in this particular evaluator, 391 00:18:06,064 --> 00:18:07,584 我们APPLY时采用的约定是 we're going to use a discipline which says 392 00:18:07,720 --> 00:18:08,976 当APPLY完成后-- the place that apply 393 00:18:09,470 --> 00:18:11,200 机器应该跳转到 the place the machine should go to next 394 00:18:11,792 --> 00:18:13,456 的下一个地方应该是 when apply is done, is at the moment 395 00:18:13,552 --> 00:18:15,920 APPLY-DISPATCH被调用时的栈顶元素 apply-dispatch is called at the top of the stack 396 00:18:17,070 --> 00:18:21,248 这只是针对这台机器的约定 that's just discipline for the way this particular machine's organized. 397 00:18:21,840 --> 00:18:23,700 现在已经给出了APPLY的所有约定 And now apply's contract is given all that. 398 00:18:23,936 --> 00:18:25,376 它会去执行应用 It'll perform the application. 399 00:18:25,540 --> 00:18:27,856 这个应用的结果将会保存在VAL寄存器中 The result of that application will end up in VAL. 400 00:18:28,890 --> 00:18:29,952 栈会被弹出 The stack will be popped. 401 00:18:31,120 --> 00:18:31,664 同样的 And, again, 402 00:18:31,712 --> 00:18:34,030 其它所有寄存器的内容都可能被修改 the contents of all the other registers may be destroyed. 403 00:18:34,840 --> 00:18:37,824 那么 这就是这台机器的基本结构 All right? So that's the basic organization of this machine. 404 00:18:38,992 --> 00:18:41,504 我们先课间休息一下 Let's break for a little bit and see if there are any questions 405 00:18:41,520 --> 00:18:42,700 然后再来研究一个真实的例子 and then we'll do a real example. 406 00:18:43,530 --> 00:19:08,112 [音乐] [JESU, JOY OF MAN'S DESIRING] 407 00:19:08,144 --> 00:19:13,472 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 408 00:19:33,100 --> 00:19:35,872 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Sussman Jay Sussman 409 00:19:35,870 --> 00:19:40,384 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 410 00:19:40,380 --> 00:19:45,296 显式控制求值器 Explicit-control Evaluator 411 00:19:47,850 --> 00:19:49,952 现在 我们来研究一下这台寄存器机器 Well, let's take the register machine now, 412 00:19:50,416 --> 00:19:51,776 我们一步一步地跟进 and actually step through, 413 00:19:52,270 --> 00:19:56,944 具体到每一处细节 and really, in real detail, 414 00:19:57,072 --> 00:19:58,520 这样你就能完全具体地看到 so you see completely concrete 415 00:19:58,864 --> 00:20:01,248 表达式是如何求值的 how some expressions are evaluated, 416 00:20:03,150 --> 00:20:06,864 那么我们从一个非常简单的表达式开始 Alright? So, let's start with a very simple expression. 417 00:20:07,456 --> 00:20:13,520 我们要求值的表达式只有一个1 Let's evaluate the expression 1. 418 00:20:18,770 --> 00:20:20,400 我们需要一个环境 And we need an environment, 419 00:20:20,432 --> 00:20:22,352 因此我们假设某处有一个环境 so let's imagine that somewhere there's an environment 420 00:20:22,384 --> 00:20:23,392 我们把它记作E0 we'll call it E0. 421 00:20:30,064 --> 00:20:34,560 由于我们之后也要用到它 And just, since we'll use these later, 422 00:20:35,620 --> 00:20:37,040 而且显然不需要任何东西 we obviously don't really need anything 423 00:20:37,072 --> 00:20:37,930 就可以求值1 to evaluate 1. 424 00:20:38,360 --> 00:20:39,456 但是为了方便以后引用 But, just for reference later, 425 00:20:39,456 --> 00:20:40,944 我们假设环境E0中有 let's assume that E0 has in it 426 00:20:41,440 --> 00:20:43,152 X=3 an X that's bound to 3 427 00:20:43,720 --> 00:20:45,370 Y=4 and a Y that's bound to 4, 428 00:20:48,272 --> 00:20:48,784 好吗? OK? 429 00:20:49,140 --> 00:20:50,128 现在 我们要做的就是 And now what we're going to do 430 00:20:50,510 --> 00:20:54,592 在这个环境中求值表达式1 is we're going to evaluate 1 in this environment 431 00:20:55,744 --> 00:20:58,544 这样 ENV寄存器就存放了一个指针 and so the ENV register has a pointer 432 00:20:59,650 --> 00:21:01,040 指向这个环境E0 to this environment, E0, all right? 433 00:21:03,312 --> 00:21:05,650 那么我们来看它是怎么进行的 Right? So let's watch that thing go. 434 00:21:05,650 --> 00:21:07,264 我要步步跟进代码 What I'm going to do is step through the code. 435 00:21:08,260 --> 00:21:10,000 这样的话 我会充当控制器 And, let's see, I'll be the controller. 436 00:21:10,040 --> 00:21:10,800 现在我需要的是-- And now what I need, 437 00:21:11,024 --> 00:21:12,490 由于这台机器已经变得相当复杂 since this gets rather complicated, 438 00:21:12,980 --> 00:21:16,830 我需要一个小小的执行单元 is a very little execution unit. 439 00:21:16,830 --> 00:21:18,160 那么请上我们的执行单元 So here's the execution unit, OK? 440 00:21:22,620 --> 00:21:23,120 好的 OK. 441 00:21:28,590 --> 00:21:29,968 好 现在我们要开始了 All right, now we're going to start. 442 00:21:30,530 --> 00:21:32,480 我们要从EVAL-DISPATCH启动机器 We're going to start the machine at eval-dispatch。 443 00:21:33,264 --> 00:21:34,624 这是整个过程的开始 Right? That's the beginning of this. 444 00:21:35,870 --> 00:21:38,752 EVAL-DISPATCH会查看表达式并进行分派 Eval-dispatch is going to look at the expression and dispatch, 445 00:21:39,320 --> 00:21:40,064 就像EVAL just like eval 446 00:21:40,870 --> 00:21:42,000 先从第一句看起 where we look at the very first thing. 447 00:21:42,048 --> 00:21:47,950 先判断表达式是不是自求值的 We branch on whether or not this expression is self-evaluating. 448 00:21:47,950 --> 00:21:49,968 SELF-EVALUATING?是我们放入机器的 Self-evaluating is some abstraction 449 00:21:49,968 --> 00:21:51,100 一个抽象过程 we put into the machine-- 450 00:21:52,224 --> 00:21:53,510 它对于数字1来说为真 it's going to be true for numbers-- 451 00:21:53,648 --> 00:21:55,520 因此跳转的目的是EV-SELF-EVAL to a place called ev-self-eval, 452 00:21:56,770 --> 00:21:58,208 那么我作为控制器 So me, being the controller, 453 00:21:58,224 --> 00:21:59,552 会去查看EV-SELF-EVAL looks at ev-self-eval, 454 00:22:00,064 --> 00:22:01,072 所以我们要跳到那里 so we'll go over to there. 455 00:22:02,600 --> 00:22:04,768 EV-SELF-EAVL的代码是-- Ev-self-eval says fine, 456 00:22:06,544 --> 00:22:09,904 把EXP寄存器的值赋值给VAL寄存器 assign to val whatever is in the expression unit. 457 00:22:15,248 --> 00:22:16,512 我遇到一个BUG And I have a bug 458 00:22:17,936 --> 00:22:20,592 因为我初始化机器的时候没有做一件事情 because what I didn't do when I initialized this machine 459 00:22:21,620 --> 00:22:22,896 也就是指定当它执行完毕后 is also say what's supposed 460 00:22:22,912 --> 00:22:24,192 应该做什么 to happen when it's done, 461 00:22:24,650 --> 00:22:26,832 所以在启动机器的时候 so I should have started out the machine 462 00:22:27,376 --> 00:22:29,856 应该将CONTINUE寄存器设置为DONE with done being in the continue register, 463 00:22:31,184 --> 00:22:33,264 所以我们给VAL赋值 OK? So we assign to VAL. 464 00:22:33,370 --> 00:22:35,568 然后执行(GOTO (FETCH CONTINUE)) And now go to fetch of continue, 465 00:22:35,632 --> 00:22:36,560 并且修改-- and now change-- 466 00:22:38,096 --> 00:22:38,608 好 OK. 467 00:22:40,000 --> 00:22:41,168 好 我们来看一个更复杂的 OK, let's try something harder. 468 00:22:42,160 --> 00:22:43,456 我们先重置机器 Let's reset the machine here, 469 00:22:44,864 --> 00:22:50,880 然后把X放入EXP寄存器中 and we'll put in the expression register, X, OK? 470 00:22:56,710 --> 00:22:58,208 重新从EVAL-DISPATCH开始 Start again at eval-dispatch. 471 00:22:59,610 --> 00:23:01,690 先检查它是自求值的么? Check, is it self-evaluating? 472 00:23:01,690 --> 00:23:02,032 不是 No. 473 00:23:02,650 --> 00:23:03,616 它是变量吗 Is it a variable? 474 00:23:04,630 --> 00:23:05,024 是的 Yes. 475 00:23:05,560 --> 00:23:07,072 我们跳转到EV-VARIABLE We go off to ev-variable. 476 00:23:08,380 --> 00:23:10,976 它说:查找EXP寄存器中变量的值 It says assign to VAL, 477 00:23:12,130 --> 00:23:15,696 并把它赋值给VAL寄存器 look up the variable value in the expression register 478 00:23:21,232 --> 00:23:22,912 (GOTO (FETCH CONTINUE)) Go to fetch of continue. 479 00:23:23,968 --> 00:23:24,480 Sussman教授:DONE PROFESSOR: Done. 480 00:23:27,616 --> 00:23:28,096 Abelson教授:好 PROFESSOR: OK. 481 00:23:29,312 --> 00:23:30,768 这些都是最基本的理念 Alright, Well, that's the basic idea. Those're 482 00:23:31,330 --> 00:23:32,656 这是这台机器上的简单运算 That's a simple operation of the machine. 483 00:23:32,680 --> 00:23:35,072 现在 我们来做些有意义的事情 Now, let's actually do something a little bit more interesting. 484 00:23:36,070 --> 00:23:38,640 我们看这条表达式 Let's look at the expression 485 00:23:43,584 --> 00:23:47,936 (+ X Y) the sum of x and y. 486 00:23:49,696 --> 00:23:51,280 现在我们会看到 OK. And now we'll see how you start 487 00:23:52,416 --> 00:23:54,016 如何展开这些表达式树 unrolling these expression trees. 488 00:23:57,136 --> 00:23:58,688 我们再次从EVAL-DISPATCH开始 Well, start again at eval-dispatch. 489 00:24:04,610 --> 00:24:05,808 是自求值的吗? Self-evaluating? 490 00:24:05,952 --> 00:24:06,528 不是 No. 491 00:24:06,704 --> 00:24:07,712 是变量吗?不是 Variable? No. 492 00:24:07,820 --> 00:24:08,992 它也不是我在这里 All the other special forms 493 00:24:08,992 --> 00:24:10,120 没有列出的特殊形式 which I didn't write down, 494 00:24:10,270 --> 00:24:12,480 比如引用、LAMBDA、SET! 等等 like quote, and lambda, and set, and whatever, 495 00:24:12,480 --> 00:24:13,088 它都不是 it's none of those. 496 00:24:13,260 --> 00:24:14,736 它是一个过程应用 It turns out to be an application, 497 00:24:15,880 --> 00:24:17,424 所以我们要跳转到EV-APPLICATION so we go off to ev-application. 498 00:24:19,970 --> 00:24:24,944 回忆一下EV-APPLICATION要做什么 Ev-application, remember what it's going to do overall. 499 00:24:25,580 --> 00:24:28,192 它先要求值运算符 It is going to evaluate the operator. 500 00:24:28,272 --> 00:24:31,408 然后求值运算对象 It's going to evaluate the arguments, 501 00:24:32,368 --> 00:24:34,304 然后再进行应用 and then it's going to go apply them. 502 00:24:35,060 --> 00:24:36,096 所以在我们开始之前 So, before we start, 503 00:24:36,944 --> 00:24:37,880 由于我们是严格按照代码来执行的 since we're being very literal, 504 00:24:37,880 --> 00:24:38,880 我们最好记住 we'd better remember that, 505 00:24:39,070 --> 00:24:40,544 在这个环境中的某处 somewhere in this environment, 506 00:24:40,576 --> 00:24:42,368 连接到了另一个环境 it's linked to another environment 507 00:24:43,980 --> 00:24:44,944 其中符号'+ in which plus 508 00:24:45,728 --> 00:24:49,160 跟基本的加法过程绑定在了一起 is bound to the primitive procedure plus 509 00:24:51,632 --> 00:24:54,032 这样 求值+时就不会导致“变量未定义” before we get an unknown variable in our machine. 510 00:24:55,340 --> 00:24:56,848 现在我们来到了EV-APPLICATION OK, so we're at ev-application. 511 00:24:59,856 --> 00:25:04,320 把EXP寄存器对应的运算对象 OK, assign to UNEV the operands 512 00:25:04,928 --> 00:25:06,896 赋值给UNEV寄存器 of what's in the expression register. 513 00:25:07,616 --> 00:25:08,832 这些是运算对象 OK. Those are the operands. 514 00:25:09,230 --> 00:25:11,664 UNEV这个临时寄存器 UNEV's a temporary register 515 00:25:11,680 --> 00:25:12,590 就是用来暂存它们的 where we're going to save them. 516 00:25:13,220 --> 00:25:13,860 Sussman教授:我正在赋值 PROFESSOR: I'm assigning. 517 00:25:14,288 --> 00:25:16,624 Abelson教授:把运算符赋值给EXP寄存器 PROFESSOR: Assign to EXP the operator. 518 00:25:18,070 --> 00:25:20,096 注意 现在我们已经修改了EXP中的表达式 Now, notice we've destroyed that expression in EXP, 519 00:25:21,840 --> 00:25:23,616 但是我们需要的部分在UNEV中 but the piece that we need is now in UNEV. 520 00:25:25,820 --> 00:25:26,816 现在 我们要准备好 Now, we're going to get set up to 521 00:25:26,816 --> 00:25:28,592 去递归地求值运算符 to recursively evaluate the operator. 522 00:25:28,750 --> 00:25:31,696 把CONTINUE寄存器保存在栈上 Save the continue register on the stack. 523 00:25:34,864 --> 00:25:36,096 保存ENV Save the environment. 524 00:25:40,480 --> 00:25:41,696 保存UNEV Save UNEV. 525 00:25:49,536 --> 00:25:54,640 把标号EVAL-ARGS赋值给CONTINUE寄存器 OK, assign to continue a label called eval-args. 526 00:26:01,400 --> 00:26:01,950 我们做了什么 Now, what have we done? 527 00:26:01,950 --> 00:26:04,380 我们为递归调用做了必要的准备 We've set up for a recursive call. 528 00:26:04,380 --> 00:26:05,888 我们要开始执行EVAL-DISPATCH We're about to go to eval-dispatch. 529 00:26:06,280 --> 00:26:08,832 我们为递归调用EVAL-DISPATCH做好了准备 We've set up for a recursive call to eval-dispatch. 530 00:26:10,230 --> 00:26:10,864 我们做了哪些事情 What did we do? 531 00:26:11,020 --> 00:26:13,648 我们把之后要用到的东西 We took the things we're going to need later, 532 00:26:14,480 --> 00:26:15,984 也就是UNEV中的运算对象 those operands that were in UNEV; 533 00:26:16,360 --> 00:26:18,992 以及我们最终求值运算对象时 the environment in which we're going to eventually have to, 534 00:26:19,168 --> 00:26:20,720 会用到的环境 maybe, evaluate those operands; 535 00:26:22,288 --> 00:26:23,936 以及我们最终想要去的位置 the place we eventually want to go to, 536 00:26:23,952 --> 00:26:25,072 本例中 也就是DONE which, in this case, was done; 537 00:26:25,344 --> 00:26:26,704 我们把它们保存在栈上 we've saved them on the stack. 538 00:26:27,104 --> 00:26:28,416 我们之所以把它们保存在栈上 The reason we saved them on the stack 539 00:26:28,430 --> 00:26:30,672 是因为EVAL-DISPATCH并不会保证 is because eval-dispatch makes no promises 540 00:26:30,944 --> 00:26:32,544 不会去修改这些寄存器 about what registers it may destroy. 541 00:26:33,550 --> 00:26:35,020 那么所有这些东西都存在了栈上 So all that stuff is saved on the stack. 542 00:26:35,020 --> 00:26:36,912 现在我们满足了EVAL-DISPATCH的约定 Now, we've set up eval-dispatch's contract. 543 00:26:37,380 --> 00:26:38,752 这是一条新的表达式 There's a new expression, 544 00:26:38,784 --> 00:26:40,048 也就是+运算符 which is the operator plus; 545 00:26:41,072 --> 00:26:41,952 以及一个新的环境 a new environment, 546 00:26:41,984 --> 00:26:43,600 尽管在本例中是同一个环境 although, in this case, it's the same one; 547 00:26:44,250 --> 00:26:45,872 以及在完成后要返回的位置 and a new place to go to when you're done, 548 00:26:45,872 --> 00:26:46,910 也就是EVAL-ARGS which is eval-args. 549 00:26:47,600 --> 00:26:48,130 这样就满足了 So that's set up. 550 00:26:48,130 --> 00:26:49,680 现在我们来执行EVAL-DISPATCH Now, we're going to go off to eval-dispatch. 551 00:26:50,890 --> 00:26:52,368 我们回到了EVAL-DISPATCH Here we are back at eval-dispatch. 552 00:26:53,056 --> 00:26:54,400 它不是自求值的 It's not self-evaluating. 553 00:26:54,440 --> 00:26:55,472 但它是一个变量 Oh, it's a variable, 554 00:26:56,320 --> 00:26:58,064 因此我们最好跳转到EV-VARIABLE so we'd better go off to ev-variable, 555 00:26:59,792 --> 00:27:02,656 EV-VARIABLE首先要给VAL赋值 Right? Ev-variable is assigned to VAL. 556 00:27:02,704 --> 00:27:06,336 查找表达式中变量的值 Look up the variable value of the expression, 557 00:27:08,496 --> 00:27:10,752 那么VAL寄存器中应该是基本的加法运算 OK? So VAL is the primitive procedure plus. 558 00:27:13,376 --> 00:27:15,168 然后(GOTO (FETCH CONTINUE)) And go to fetch of continue. 559 00:27:15,232 --> 00:27:16,112 Sussman教授:它是EVAL-ARGS PROFESSOR: Eval-args. 560 00:27:16,208 --> 00:27:18,736 Abelson教授:现在它是EVAL-ARGS而不是DONE了 PROFESSOR: Right, which is now eval-args not done. 561 00:27:19,424 --> 00:27:21,264 然后我们来到EVAL-ARGS So we come back here at eval-args, 562 00:27:22,160 --> 00:27:23,024 看看它要做什么 and what do we do? 563 00:27:23,072 --> 00:27:24,848 我们要恢复之前保存的东西 We're going to restore the stuff that we saved, 564 00:27:25,200 --> 00:27:26,576 因此调用(RESTORE UNEV) so we restore UNEV. 565 00:27:29,216 --> 00:27:31,696 注意 这里并不是必要的 And notice, there, it wasn't necessary, 566 00:27:31,744 --> 00:27:32,900 但通常来说都会有这么一步 although, in general, it would be. 567 00:27:32,900 --> 00:27:35,168 它可以是任意的求值过程 It might be some arbitrary evaluation that happened. 568 00:27:35,430 --> 00:27:36,704 恢复ENV寄存器 We restore ENV. 569 00:27:47,872 --> 00:27:52,048 然后把(FETCH VAL)赋值给FUN OK, we assign to FUN fetch of VAL. 570 00:27:59,952 --> 00:28:02,816 现在我们要开始求值参数了 OK, now, we're going to go off and start evaluating some arguments. 571 00:28:04,340 --> 00:28:06,480 首先 我们最好把FUN寄存器保存起来 Well, first thing we'd better do is save FUN 572 00:28:07,424 --> 00:28:10,624 因为求值过程中可能发生任何事情 because some arbitrary stuff might happen in that evaluation. 573 00:28:15,330 --> 00:28:16,880 我们初始化参数列表 We initialize the argument list. 574 00:28:16,912 --> 00:28:19,296 给ARGL赋值一个空的参数列表 Assign to argl an empty argument list, 575 00:28:20,880 --> 00:28:22,176 然后跳转到EVAL-ARG-LOOP and go to eval-arg-loop, 576 00:28:24,860 --> 00:28:26,272 在EVAL-ARG-LOOP中 At eval-arg-loop, 577 00:28:27,770 --> 00:28:31,536 我们想要去一条一条的求值 the idea of this is we're going to evaluate the pieces of the 578 00:28:31,616 --> 00:28:33,370 UNEV中的表达式 expressions that are in UNEV, one by one, 579 00:28:33,540 --> 00:28:35,680 然后把它们从UNEV中的待求值表 and move them from unevaluated in UNEV 580 00:28:35,900 --> 00:28:37,264 移动到ARGL中的已求值表中 to evaluated in the arg list. 581 00:28:37,840 --> 00:28:39,184 然后我们保存ARGL OK. So we save argl. 582 00:28:43,950 --> 00:28:47,264 然后我们把UNEV中的第一个运算对象 We assign to EXP the first operand 583 00:28:47,376 --> 00:28:48,380 赋值给EXP of the stuff in UNEV. 584 00:28:53,770 --> 00:28:55,890 然后我们检查它是否为最后一个运算对象 Now, we check and see if that was the last operand. 585 00:28:55,890 --> 00:28:56,912 在这里 它还不是 In this case, it is not. 586 00:28:58,992 --> 00:29:01,552 然后我们保存环境 So we save the environment. 587 00:29:08,000 --> 00:29:10,064 我们之所以保存UNEV We save UNEV 588 00:29:11,616 --> 00:29:13,500 是因为稍后我们可能会需要它们 because those are all things we might need later. 589 00:29:13,500 --> 00:29:14,400 我们需要环境 We're going to need the environment 590 00:29:14,448 --> 00:29:15,648 来进行一些求值 to do some more evaluations. 591 00:29:15,800 --> 00:29:16,608 我们需要UNEV寄存器来指示 We're going to need UNEV 592 00:29:16,624 --> 00:29:19,200 其余的待求值参数 to look at what the rest of those arguments were. 593 00:29:20,340 --> 00:29:21,552 我们要把CONTINUE寄存器赋值为 We're going to assign continue 594 00:29:21,560 --> 00:29:24,448 ACCUMULATE-ARG这个标号 a place called accumulate-args, or accumulate-arg. 595 00:29:31,136 --> 00:29:34,016 现在 我们已经准备好再次调用EVAL-DISPATCH了 OK, now, we've set up for another call to eval-dispatch, 596 00:29:37,072 --> 00:29:38,544 现在让我把这个短路掉 All right, now, let me short-circuit this 597 00:29:39,120 --> 00:29:41,090 这里我们不跟进EVAL-DISPATCH的细节 so we don't go through the details of eval-dispatch. 598 00:29:41,090 --> 00:29:42,640 EVAL-DISPATCH的约定说: Eval-dispatch's contract says 599 00:29:42,970 --> 00:29:45,008 我的调用完成后 i'm going to end up, 600 00:29:45,136 --> 00:29:45,960 整个机器的状态会变为 the world will end up, 601 00:29:46,032 --> 00:29:48,208 也就是在ENV环境中求值EXP表达式 with the value of evaluating this expression 602 00:29:48,240 --> 00:29:50,270 求值结果会保存在VAL寄存器中 in this environment in the VAL register, 603 00:29:50,270 --> 00:29:51,072 结束状态就是这样 and I'll end up there. 604 00:29:51,320 --> 00:29:52,624 那么我们把这些全都省略掉 So we short-circuit all of this, 605 00:29:54,432 --> 00:29:56,368 最后VAL的内容是3 and a 3 ends up in VAL. 606 00:29:58,010 --> 00:29:59,760 并且当我们从EVAL-DISPATCH返回的时候 And, when we return from eval-dispatch, 607 00:29:59,760 --> 00:30:01,760 我们会返回到ACCUMULAT-ARG这里 we're going to return to accumulate-arg. 608 00:30:02,304 --> 00:30:03,232 Sussman教授:跳转到ACCUMULATE-ARG PROFESSOR: Accumulate-arg. 609 00:30:06,224 --> 00:30:08,208 Abelson教授:VAL寄存器里是3 对吧? PROFESSOR: With 3 in the VAL register, OK? 610 00:30:08,720 --> 00:30:10,592 我们跳过了求值的细节 So that short-circuited that evaluation. 611 00:30:10,650 --> 00:30:11,320 现在我们要做什么? Now, what do we do? 612 00:30:11,320 --> 00:30:13,680 我们返回继续看剩下的参数 We're going to go back and look at the rest of the arguments, 613 00:30:13,680 --> 00:30:14,832 我们恢复UNEV so we restore UNEV. 614 00:30:17,510 --> 00:30:19,008 恢复ENV We restore ENV. 615 00:30:25,792 --> 00:30:27,056 然后恢复ARGL We restore argl. 616 00:30:28,650 --> 00:30:29,170 这件事 One thing. 617 00:30:30,064 --> 00:30:31,456 Sussman教授:糟糕 奇偶错误 PROFESSOR: Oops! Parity error. 618 00:30:33,760 --> 00:30:34,832 Abelson教授:恢复ARGL PROFESSOR: Restore argl. 619 00:30:45,570 --> 00:30:49,760 然后 我们把VAL寄存器和ARGL给CONS起来 OK, we assign to argl consing on 620 00:30:50,656 --> 00:30:52,640 然后赋值给ARGL寄存器 fetch of the value register to what's in argl. 621 00:30:59,360 --> 00:31:02,960 我们把UNEV中剩余的运算对象 OK, we assign to UNEV the rest of the operands 622 00:31:03,344 --> 00:31:04,528 赋值给UNEV in fetch of UNEV, 623 00:31:08,912 --> 00:31:10,768 然后我们返回到EVAL-ARG-LOOP and we go back to eval-arg-loop. 624 00:31:11,510 --> 00:31:12,280 Sussman教授:EVAL-ARG-LOOP PROFESSOR: Eval-arg-loop. 625 00:31:12,280 --> 00:31:12,864 Abelson教授:好 PROFESSOR: OK. 626 00:31:15,880 --> 00:31:17,088 现在我们处理下一个参数 Now, we're about to do the next argument, 627 00:31:17,584 --> 00:31:19,312 所以首先我们要保存ARGL so the first thing we do is save argl. 628 00:31:25,400 --> 00:31:28,272 然后我们把UNEV中的第一个运算对象 OK, we assign to EXP the first operand 629 00:31:29,152 --> 00:31:30,816 赋给EXP of fetch of UNEV. 630 00:31:34,720 --> 00:31:37,024 然后我们检查它是否为最后一个运算对象 OK, we test and see if that's the last operand. 631 00:31:37,024 --> 00:31:38,000 这里它是最后一个 In this case, it is 632 00:31:39,088 --> 00:31:40,272 所以我们跳到一个特殊的地方 so we're going to go to a special place 633 00:31:40,288 --> 00:31:42,064 来求值最后一个参数 that says evaluate the last argument 634 00:31:43,376 --> 00:31:45,072 因为请注意 在求值这个参数之后 because, notice,after evaluating the argument, 635 00:31:45,104 --> 00:31:46,624 我们就不再需要这个环境了 we don't need the environment any more. 636 00:31:47,648 --> 00:31:48,784 这就是区别 That's going to be the difference. 637 00:31:50,250 --> 00:31:51,856 在这里 在EVAL-LAST-ARG这里 So here, at eval-last-arg, 638 00:31:52,240 --> 00:31:54,928 CONTINUE被赋值为了ACCUMULATE-LAST-ARG which is assigned to continue accumulate-last-arg, 639 00:32:04,270 --> 00:32:06,900 现在我们再次为EVAL-DISPATCH做准备 now, we're set up again for eval-dispatch. 640 00:32:06,900 --> 00:32:08,512 我们有一个完成时要跳转的目的地 We've got a place to go to when we're done. 641 00:32:08,620 --> 00:32:09,840 我们有一条表达式 We've got an expression. 642 00:32:09,840 --> 00:32:10,800 还有一个环境 We've got an environment. 643 00:32:11,330 --> 00:32:13,648 好 那么我们略过对EVAL-DISPATCH的调用 OK, so we'll short-circuit the call to eval-dispatch. 644 00:32:14,370 --> 00:32:16,416 现在情况是这里有一个Y And what'll happen is there's a y there, 645 00:32:16,700 --> 00:32:18,560 在这个环境中 它的值是4 it's 4 in that environment, 646 00:32:18,608 --> 00:32:20,096 所以最终VAL寄存器将会是4 so VAL will end up with 4 in it. 647 00:32:21,060 --> 00:32:22,864 然后我们就要以ACCUMULATE-LAST-ARG结束了 And, then, we're going to end up at accumulate-last-arg, OK? 648 00:32:25,450 --> 00:32:26,912 因此 在ACCUMULATE-LAST-ARG中 So, at accumulate-last-arg, 649 00:32:29,280 --> 00:32:30,520 我们恢复ARGL寄存器 we restore argl. 650 00:32:37,696 --> 00:32:42,768 我们把ARGL赋值为 We assign to argl, we assign to argl cons, 651 00:32:43,600 --> 00:32:45,830 将一个新值CONS在它上面的结果 of fetch of the new value onto it, 652 00:32:45,936 --> 00:32:47,392 所以我们在它的旧值前CONS一个4 so we cons a 4 onto that. 653 00:32:49,850 --> 00:32:52,528 我们恢复FUN寄存器中的内容 We restore what was saved in the function register. 654 00:32:53,770 --> 00:32:54,992 需要注意的是 在则个例子中 And notice, in this case, 655 00:32:55,008 --> 00:32:56,270 FUN寄存器还没有被修改过 it had not been destroyed, 656 00:32:56,384 --> 00:32:57,728 但是通常来说 它会的 but in general, it will be. 657 00:32:59,130 --> 00:33:01,504 现在 我们将要调用APPLY-DISPATCH And now, we're ready to go off to apply-dispatch, 658 00:33:02,650 --> 00:33:04,400 所以我们刚刚步步跟进了EVAL过程 Alright? So we've just gone through the eval. 659 00:33:04,510 --> 00:33:05,856 我们求值了运算符 We evaluated the argument, 660 00:33:06,464 --> 00:33:07,980 以及实际参数 the operator, and the arguments, 661 00:33:07,980 --> 00:33:09,248 现在我们要应用它们了 and now, we're about to apply them. 662 00:33:09,580 --> 00:33:11,376 因此 我们来到APPLY-DISPATCH这里 So we come off to apply-dispatch here 663 00:33:18,032 --> 00:33:19,296 这是APPLY-DISPATCH的代码 We come off to apply-dispatch, 664 00:33:21,056 --> 00:33:22,416 我们要检查它是一个基本过程 and we're going to check whether it's a primitive 665 00:33:22,416 --> 00:33:23,450 还是一个复合过程 or a compound procedure. 666 00:33:23,648 --> 00:33:24,208 Sussman教授:基本过程 PROFESSOR: Yes. 667 00:33:24,544 --> 00:33:24,830 Abelson教授:好的 PROFESSOR: All right. 668 00:33:24,896 --> 00:33:26,528 这里 它是一个基本过程 So, in this case, it's a primitive procedure, 669 00:33:27,456 --> 00:33:28,912 因此 我们跳转到PRIMITIVE-APPLY and we go off to primitive-apply. 670 00:33:29,790 --> 00:33:31,360 我们来到PRIMITIVE-APPLY So we go off to primitive-apply, 671 00:33:33,710 --> 00:33:35,376 它说:把VAL赋值为 that says assign to VAL 672 00:33:35,696 --> 00:33:38,256 把基本过程 result of applying primitive procedure 673 00:33:38,360 --> 00:33:40,304 应用在参数表的结果 of the function to the argument list. 674 00:33:41,312 --> 00:33:42,432 Sussman教授:我不知道怎么做加法 PROFESSOR: I don't know how to add. 675 00:33:42,540 --> 00:33:43,808 我只是一个执行单元 I'm just an execution unit. 676 00:33:44,144 --> 00:33:45,350 Abelson教授:我也不知道 PROFESSOR: Well, I don't know how to add either. 677 00:33:45,350 --> 00:33:46,512 我只是一个求值器 I'm just the evaluator, 678 00:33:47,088 --> 00:33:48,360 因此 我们需要一个基本运算执行器 so we need a primitive operator. 679 00:33:48,360 --> 00:33:49,728 那么 请问基本运算执行器 Let's see, so the primitive operator, 680 00:33:49,760 --> 00:33:52,368 3+4等于多少? What's the... what's the sum of 3 and 4? 681 00:33:52,864 --> 00:33:53,328 学生:7 AUDIENCE: 7. 682 00:33:53,712 --> 00:33:54,656 Abelson教授:好 是7 PROFESSOR: OK, 7. 683 00:33:55,328 --> 00:33:55,990 Sussman教授:谢谢 PROFESSOR: Thank you. 684 00:33:59,200 --> 00:34:00,608 Abelson教授:现在 我们恢复CONTINUE PROFESSOR: Now, we restore continue, 685 00:34:11,584 --> 00:34:12,900 执行(GOTO (FETCH CONTINUE)) and we go to fetch of continue. 686 00:34:13,072 --> 00:34:13,472 Sussman教授:'DONE PROFESSOR: Done. 687 00:34:14,208 --> 00:34:14,672 Abelson教授:好 PROFESSOR: OK. 688 00:34:14,920 --> 00:34:18,410 这些是你能看到的最细致的过程了 Well, that was in as much detail as you will ever see. 689 00:34:18,410 --> 00:34:20,192 我们再也不会讲得这么细了 We'll never do it in as much detail again. 690 00:34:21,590 --> 00:34:23,920 有一件重要的事需要注意 One very important thing to notice 691 00:34:24,912 --> 00:34:27,552 我们刚刚执行了一个递归过程 is that we just executed a recursive procedure, 692 00:34:29,568 --> 00:34:31,170 我们在整个过程中使用了栈 Right? This whole thing, we used a stack 693 00:34:31,170 --> 00:34:32,752 而且求值器是递归的 and the evaluator was recursive. 694 00:34:33,070 --> 00:34:35,888 有很多人以为在求值器中 A lot of people think the reason that you need a stack 695 00:34:36,480 --> 00:34:37,856 会用到栈和递归 and recursion in an evaluator 696 00:34:37,872 --> 00:34:38,976 或许是因为 is because you might be 697 00:34:39,090 --> 00:34:42,150 回去求值像阶乘或者FIB那样的递归过程 evaluating recursive procedures like factorial or Fibonacci. 698 00:34:42,150 --> 00:34:42,928 这并不正确 It's not true. 699 00:34:43,670 --> 00:34:44,992 注意 我们在这里进行了递归 So you notice we did recursion here, 700 00:34:45,008 --> 00:34:46,864 而仅仅是去求值(+ X Y) and all we evaluated was (+ x y) 701 00:34:47,776 --> 00:34:50,656 在求值器中需要递归 实际上是因为 Right? The reason that you need recursion in the evaluator 702 00:34:50,960 --> 00:34:52,976 是因为求值过程本身 is because the evaluation process, 703 00:34:52,992 --> 00:34:54,060 就是递归的 itself, is recursive. 704 00:34:54,450 --> 00:34:56,176 并不是因为你在Lisp中 Right? It's not because the procedure 705 00:34:56,320 --> 00:34:58,096 要求值的那个过程 that you might be evaluating in LISP 706 00:34:58,128 --> 00:34:59,270 是一个递归过程 is a recursive procedure. 707 00:34:59,270 --> 00:35:00,528 这一点很重要 So that's an important thing 708 00:35:00,528 --> 00:35:02,144 人们经常在这里被弄糊涂 that people get confused about a lot. 709 00:35:03,010 --> 00:35:04,272 另一点要注意的是 The other thing to notice is that, 710 00:35:04,272 --> 00:35:05,648 我们在这里完成之后 when we're done here, 711 00:35:06,280 --> 00:35:07,120 真正完成以后 we're really done. 712 00:35:07,120 --> 00:35:08,496 不仅仅是指我们在'DONE这个标号 Not only are we at done, 713 00:35:09,456 --> 00:35:13,232 栈上也没有累积的东西了 but there's no accumulated stuff on the stack, 714 00:35:13,600 --> 00:35:15,712 对吧?机器又回到了它的初始状态 Right? The machine is back to its initial state. 715 00:35:17,008 --> 00:35:18,752 那就是“完成”的其中一部分意义 So that's part of what it means to be done. 716 00:35:19,710 --> 00:35:21,040 换句话说就是 Another way to say that is 717 00:35:22,720 --> 00:35:26,048 整个求值过程是把 the evaluation process has reduced 718 00:35:26,410 --> 00:35:28,320 (+ X Y)这条表达式 the expression, plus X, Y, 719 00:35:30,544 --> 00:35:32,784 归约为这里的7 to the value here, 7. 720 00:35:33,240 --> 00:35:35,456 我所指的“归约”有特殊的意义 And by reduced, I mean a very particular thing. 721 00:35:36,010 --> 00:35:38,180 也就是栈上没剩下任何东西了 It means that there's nothing left on the stack. 722 00:35:38,180 --> 00:35:40,368 机器现在与初始状态相同 The machine is now in the same state, 723 00:35:40,928 --> 00:35:42,656 只是VAL寄存器里有一些东西 except there's something in the value register. 724 00:35:42,720 --> 00:35:44,520 它不是任何问题的子问题 It's not part of a sub-problem of anything. 725 00:35:44,520 --> 00:35:45,632 不需要返回到其它地方 There's nothing to go back to. 726 00:35:46,128 --> 00:35:46,960 好 这节课就讲到这里 OK. Let's break. 727 00:35:50,160 --> 00:35:50,768 有问题吗 Question? 728 00:35:51,088 --> 00:35:54,020 学生:关于栈有一个问题 AUDIENCE: The question here, in the stack, 729 00:35:54,020 --> 00:35:55,820 由于数据有可能是递归的 is because the data may be recursive. 730 00:35:56,208 --> 00:35:58,752 例如 嵌套的表达式 You may have embedded expressions, for instance. 731 00:35:59,310 --> 00:36:02,080 教授:是的 因为你可能遇到嵌套的表达式 PROFESSOR: Yes, because you might have embedded expressions. 732 00:36:02,080 --> 00:36:04,770 但是再说一遍 不要搞混 But, again, don't confuse that 733 00:36:04,770 --> 00:36:07,984 有时候人们说数据是递归的 with what people sometimes mean by the data may be recursive, 734 00:36:08,000 --> 00:36:10,352 他们说的是对于这些表结构的 which is to say you have these list-structured, 735 00:36:11,040 --> 00:36:12,930 一些递归运算 recursive data list operations. 736 00:36:12,930 --> 00:36:13,968 那和这没有关系 That has nothing to do with it. 737 00:36:13,984 --> 00:36:16,160 这只是包含子表达式的表达式而已 It's simply that the expressions contain sub-expressions. 738 00:36:20,048 --> 00:36:23,520 学生:为什么ARGL中参数的顺序是反过来的 AUDIENCE: Why is it that the order of the arguments in the arg list got reversed? 739 00:36:23,552 --> 00:36:25,296 教授:对 我应该提一嘴这个 PROFESSOR: Ah! Yes, I should've mentioned that. 740 00:36:27,260 --> 00:36:29,070 之所以在这里把顺序反过来 Here, the reason the order is reversed-- 741 00:36:32,784 --> 00:36:35,376 你首先定义怎么算“逆序” it's a question of what you mean by reversed. 742 00:36:36,050 --> 00:36:39,904 我记得应该是牛顿 I believe it was Newton. 743 00:36:40,910 --> 00:36:42,416 在光学发展的很早期 In the very early part of optics, 744 00:36:42,432 --> 00:36:43,260 人们意识到 people realized 745 00:36:43,616 --> 00:36:45,360 当你用眼睛通过透镜看东西的时候 that when you look through the lens of your eye, 746 00:36:45,500 --> 00:36:46,730 图像是上下颠倒的 the image was up-side down. 747 00:36:46,730 --> 00:36:48,040 当时有很多的争论说 And there was a lot of argument about 748 00:36:48,040 --> 00:36:50,480 为什么不能是你眼睛平时看见的都是上下颠倒的 why that didn't mean you saw things up-side down. 749 00:36:51,280 --> 00:36:52,656 这实际上是一样的道理 So it's sort of the same issue. 750 00:36:52,860 --> 00:36:53,904 和什么相比反过来了 Reversed from what? 751 00:36:54,810 --> 00:36:56,240 我们只是需要一个约定 So we just need some convention. 752 00:36:56,590 --> 00:37:00,352 它们作为(4 3)出现的原因是 So all we.. The reason that they're coming at 4, 3 753 00:37:00,800 --> 00:37:02,496 是因为我们从UNEV中取出东西 is because taking UNEV 754 00:37:02,528 --> 00:37:04,030 并且把它CONS到了ARGL上面 and consing the result onto argl. 755 00:37:04,520 --> 00:37:06,688 那么你要意识到你已经做了这个约定 So you have to realize you've made that convention. 756 00:37:06,864 --> 00:37:09,376 你需要意识到这点的地方有 The place that you have to realize that-- 757 00:37:09,980 --> 00:37:11,230 实际上有两个地方 well, there's actually two places. 758 00:37:11,230 --> 00:37:12,910 首先是在APPLY-PRIMITIVE-OPERATOR One is in apply-primitive-operator, 759 00:37:12,910 --> 00:37:14,064 你要意识到 which has to realize that 760 00:37:15,120 --> 00:37:16,752 参数传入基本运算的顺序 the arguments to primitives go in, 761 00:37:16,784 --> 00:37:18,720 是和你的书写顺序相反的 the opposite order from the way you're writing them down. 762 00:37:19,490 --> 00:37:21,000 我们之后会在另外一处看到 And the other one is, we'll see later 763 00:37:21,072 --> 00:37:23,808 当你实际绑定绑定函数的形式参数时 when you actually go to bind a function's parameters, 764 00:37:24,010 --> 00:37:25,740 你要意识到参数进入的顺序 you should realize the arguments are going to come in 765 00:37:25,740 --> 00:37:28,544 和你要绑定这些变量时的顺序相反 from the opposite order of the variables to which you're binding them. 766 00:37:28,870 --> 00:37:30,176 所以如果你注意这些 So, if you just keep track of that, 767 00:37:31,088 --> 00:37:31,830 就没有问题了 there's no problem. 768 00:37:31,830 --> 00:37:33,696 同样 这完全是随意的 Also, this is completely arbitrary 769 00:37:33,900 --> 00:37:34,960 因为如果我们做了一个 because, if we'd done, 770 00:37:35,104 --> 00:37:37,152 比如 给向量的各个维度赋值的迭代 say, an iteration through a vector assigning them, 771 00:37:37,420 --> 00:37:38,736 它们可能会以其它顺序输出 they might come out in the other order. 772 00:37:40,410 --> 00:37:42,048 那么这只是这个求值器 OK. So it's just a convention of the way 773 00:37:42,064 --> 00:37:43,536 工作时的一个约定 this particular evaluator works. 774 00:37:45,392 --> 00:37:46,240 好 我们休息一下 All right, let's take a break. 775 00:37:46,330 --> 00:38:02,448 [音乐] [JESU, JOY OF MAN'S DESIRING] 776 00:38:02,440 --> 00:38:07,648 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 777 00:38:28,620 --> 00:38:32,512 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Sussman Jay Sussman 778 00:38:32,510 --> 00:38:35,680 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 779 00:38:35,680 --> 00:38:39,616 显式控制求值器 Explicit-control Evaluator 780 00:38:41,840 --> 00:38:45,310 教授:我们已经学习了表达式的求值 Professor: We just saw evaluating an expression 781 00:38:45,600 --> 00:38:47,080 虽然这只是一个非常简单的例子 and, of course, that was very simple one. But 782 00:38:48,810 --> 00:38:50,240 但从本质上来说 in essence, it would be no different 783 00:38:50,240 --> 00:38:52,030 它跟那些大型嵌套表达式没什么不同 if it was some big nested expression, 784 00:38:52,030 --> 00:38:54,570 后者只是在栈上递归得更深而已 so there would just be deeper recursion on the stack. 785 00:38:55,130 --> 00:38:56,032 我现在要为你们 But what I want to do now 786 00:38:56,048 --> 00:38:56,910 讲解最后一部分 is show you the last piece. 787 00:38:56,920 --> 00:38:59,820 我要带着你们观察EVAL-APPLY循环 I want to walk you around this eval and apply loop, 788 00:39:01,010 --> 00:39:02,810 我们还没有仔细研究过它 That's the thing we haven't seen, really. 789 00:39:03,000 --> 00:39:04,750 我们还没有见过一个复合程序 We haven't seen any compound procedures 790 00:39:05,200 --> 00:39:07,790 对它的求值会归约为 where evalutation of procedure reduces to 791 00:39:07,920 --> 00:39:10,110 对一个过程的应用 where applying of procedure reduces to 792 00:39:10,120 --> 00:39:11,640 进而是对过程体的求值 evaluating the body of the procedure, 793 00:39:12,440 --> 00:39:15,880 因此 假设我们有这个 so let's just suppose we had this. 794 00:39:15,930 --> 00:39:17,440 假设我们正在考察 Suppose we were looking at the procedure 795 00:39:18,070 --> 00:39:31,600 (DEFINE (F A B) (+ A B) define F of A and B to be the sum of A and B. 796 00:39:33,990 --> 00:39:37,320 假设我们预先定义好了这个过程 So, as we typed in that procedure previously, 797 00:39:37,690 --> 00:39:41,640 现在 我们将要求值(F X Y) and now we're going to evaluate F of X and Y 798 00:39:42,270 --> 00:39:44,200 基于的环境是E0 again, in this environment, E,0, 799 00:39:44,350 --> 00:39:47,020 其中X=3 Y=4 where X is bound to 3 and Y is bound to 4. 800 00:39:50,780 --> 00:39:52,110 当执行DEFINE的时候 When the defined is executed, 801 00:39:52,120 --> 00:39:53,690 还记得么 这里是一个LAMBDA remember, there's a lambda here, 802 00:39:53,820 --> 00:39:55,530 LAMBDA会创建一个过程 and lambdas create procedures. 803 00:39:55,950 --> 00:39:58,490 基本上 会发生的事情是 And, basically, what will happen is, 804 00:39:59,632 --> 00:40:00,688 在环境E0中 in E0, 805 00:40:01,008 --> 00:40:02,650 我们会得到F的绑定 we'll end up with a binding for F, 806 00:40:03,560 --> 00:40:05,610 它指出F是一个过程 which will say F is a procedure, 807 00:40:07,150 --> 00:40:11,280 这个过程的参数是A和B and its args are A and B, 808 00:40:12,570 --> 00:40:16,190 而过程体是(+ A B) and its body is plus a,b. 809 00:40:18,110 --> 00:40:20,990 这就是环境大概的样子 So that's what the environment would have looked like 810 00:40:21,210 --> 00:40:22,520 我们之前就定义过了 had we made that definition. 811 00:40:24,220 --> 00:40:27,280 然后 我们去求值(F X Y) Then, when we go to evaluate F of X and Y, 812 00:40:28,800 --> 00:40:30,896 我们会仔细地解释每一步 we'll go through exactly the same process 813 00:40:31,024 --> 00:40:31,850 就像之前那样 that we did before. 814 00:40:31,880 --> 00:40:33,090 不会跳过重复的表达式 It's even the same expression. 815 00:40:33,280 --> 00:40:34,380 唯一的不同是 The only difference is that 816 00:40:34,400 --> 00:40:36,640 它的内部不再是基本的“+”过程 F, instead of having primitive "plus" in it 817 00:40:37,240 --> 00:40:38,990 它还有这个东西 will have this thing. 818 00:40:41,040 --> 00:40:43,600 因此我们要进行相同的过程 And so we'll go through exactly the same process, 819 00:40:43,600 --> 00:40:44,928 只不过这次 except this time, when we end up 820 00:40:45,264 --> 00:40:47,420 当我们停在APPLY-DISPATCH时 at apply-dispatch, 821 00:40:47,860 --> 00:40:50,280 FUN寄存器中不再是基本的“+”过程 the function register, instead of having primitive plus, 822 00:40:50,440 --> 00:40:53,580 而是一个代表过程的东西 will have a thing that will represent it saying procedure, 823 00:40:54,300 --> 00:40:59,000 其中参数为A和B where the args are A and B, 824 00:41:00,640 --> 00:41:06,270 过程体是(+ A B) and the body is plus A, B. 825 00:41:07,870 --> 00:41:09,920 再强调一下 我所谓的ENV And, again, what I mean, by its ENV, 826 00:41:09,960 --> 00:41:11,120 是一个指向环境的指针 I mean there's a pointer to it, 827 00:41:11,240 --> 00:41:13,070 所以不用担心我在这里写了很多东西 so don't worry that I'm writing a lot of stuff there. 828 00:41:13,280 --> 00:41:15,630 这是一个指向代表过程的数据结构的指针 There's a pointer to this procedure data structure. 829 00:41:17,170 --> 00:41:19,770 因此 我们现在面临着相同的情况 OK, so, we're in exactly the same situation. 830 00:41:20,270 --> 00:41:22,430 我们来到了APPLY-DISPATCH We get to apply-dispatch, 831 00:41:23,980 --> 00:41:26,480 这是APPLY-DISPATCH的代码 so, here, we come to apply-dispatch. 832 00:41:26,480 --> 00:41:28,730 上一次 我们分支跳转到了一个基本过程 Last time, we branched off to a primitive procedure. 833 00:41:30,010 --> 00:41:30,700 然而这一次 Here, it says oh, 834 00:41:30,840 --> 00:41:32,800 我们遇到的是一个复合过程 we now have a compound procedure, 835 00:41:34,550 --> 00:41:36,600 因此我们要跳转到COMPOUND-APPLY so we're going to go off to compound-apply. 836 00:41:38,470 --> 00:41:39,920 COMPOUND-APPLY又是怎样定义的呢? Now, what's compound-apply? 837 00:41:41,920 --> 00:41:44,540 还记得元循环求值器是怎么做的么? Well, remember what the meta-circular evaluator did? 838 00:41:45,090 --> 00:41:47,400 COMPOUND-APPLY的执行步骤则是 Compound-apply said we're going to evaluate 839 00:41:49,900 --> 00:41:51,600 在一个新的环境中 the body of the procedure 840 00:41:52,940 --> 00:41:54,120 求值一个过程的体 in some new environment. 841 00:41:54,120 --> 00:41:55,870 这个新的环境来自于哪里呢? Where does that new environment come from? 842 00:41:56,730 --> 00:42:01,360 我们把跟过程一同打包的环境 We take the environment that was packaged with the procedure, 843 00:42:03,020 --> 00:42:05,790 我们把过程的形式参数 we bind the parameters of the procedure 844 00:42:06,000 --> 00:42:07,630 同传递进来的实际参数给绑定起来 to the arguments that we're passing in, 845 00:42:09,750 --> 00:42:11,950 把这个作为新的框架 and use that as a new frame to extend 846 00:42:12,590 --> 00:42:13,790 来扩展过程附带的环境 the procedure environment. 847 00:42:14,990 --> 00:42:16,080 我们就是在这个环境中 And that's the environment 848 00:42:16,300 --> 00:42:18,880 求值过程的体 in which we evaluate the procedure body, 849 00:42:20,120 --> 00:42:24,470 对吧?这就是APPLY-EVAL循环做的事 Right? That's going around the apply/eval loop. 850 00:42:24,470 --> 00:42:26,250 这就是APPLY回过头来调用EVAL That's apply coming back to call eval, 851 00:42:32,860 --> 00:42:34,920 因此 这就是我们要在COMPOUND-APPLY中要做的所有事 So, now, that's all we have to do in compound-apply. 852 00:42:36,780 --> 00:42:37,720 要怎么来实现呢? What are we going to do? 853 00:42:37,720 --> 00:42:40,970 我们要构造一个新的环境 We're going to manufacture a new environment. 854 00:42:43,550 --> 00:42:45,640 而我们构造的这个新环境呢 And we're going to manufacture a new environment that, 855 00:42:46,760 --> 00:42:48,110 我们把它记作E1 let's see, that we'll call E1. 856 00:42:52,900 --> 00:42:55,630 E1这个环境呢 E1 is going to be some environment where the 857 00:42:57,310 --> 00:42:59,150 存储了过程的参数绑定 where the parameters of the procedure, 858 00:42:59,210 --> 00:43:03,260 其中A=3 B=4 Nwhere A is bound to 3, and B is bound to 4, 859 00:43:04,270 --> 00:43:05,760 并且它跟E0相连 and it's linked to E0 860 00:43:05,760 --> 00:43:08,080 这是因为 F就是在E0中定义的 because that's where f is defined. 861 00:43:09,270 --> 00:43:10,270 因此 在这个环境中 And, in this environment, 862 00:43:10,270 --> 00:43:11,960 我们要来求值过程的体 we're going to evaluate the body of the procedure. 863 00:43:12,050 --> 00:43:14,480 让我们来看一看 So let's look at that, we're going 864 00:43:16,520 --> 00:43:18,320 我们来看COMPOUND-APPLY的代码 Here we are at compound-apply, 865 00:43:20,300 --> 00:43:23,470 首先是给EXP寄存器赋值 which says assign to the expression register 866 00:43:24,500 --> 00:43:25,984 所赋的值是FUN寄存器 the body of the procedure 867 00:43:25,984 --> 00:43:27,260 所指向过程的体 that's in the function register. 868 00:43:28,380 --> 00:43:30,640 这样 我就将过程的体 So I assign to the expression register 869 00:43:31,296 --> 00:43:32,330 赋值给了EXP寄存器 the procedure body, 870 00:43:40,750 --> 00:43:41,100 对吧? OK? 871 00:43:42,640 --> 00:43:44,970 而这将在某个环境中求值 That's going to be evaluated in an environment 872 00:43:45,820 --> 00:43:48,320 这个环境是通过将FUN寄存器 which is formed by making some bindings 873 00:43:51,300 --> 00:43:53,670 所指向的过程中的形式参数 using information determined by the procedure-- 874 00:43:53,670 --> 00:43:56,250 与实际参数绑定起来 得到的 that's what's in FUN-- and the argument list. 875 00:43:57,800 --> 00:44:00,000 我们先不要关系它的具体细节 And let's not worry about exactly what that does, 876 00:44:00,080 --> 00:44:01,630 你可以知道它的最后结果 but you can see the information's there. 877 00:44:01,930 --> 00:44:03,320 因此MAKE-BINDINGS会说 So make bindings will say oh, 878 00:44:04,040 --> 00:44:07,900 过程本身就附带有一个环境 the procedure, itself, had an environment attached to it. 879 00:44:07,960 --> 00:44:09,320 在这里 我没有写出来 I didn't write that quite here. 880 00:44:09,360 --> 00:44:10,560 但我应该说过它有一个环境 I should've said in environment 881 00:44:11,300 --> 00:44:12,736 因为每个过程在构造时 because every procedure gets built 882 00:44:12,768 --> 00:44:13,440 都有一个环境 with an environment. 883 00:44:13,660 --> 00:44:14,832 因此 通过这个环境 So, from that environment, 884 00:44:15,680 --> 00:44:16,350 它能够知道 it knows 885 00:44:16,600 --> 00:44:18,650 定义该过程时的环境是怎样的 what the procedure's definition environment is. 886 00:44:19,290 --> 00:44:20,750 它知道实际参数是什么 It knows what the arguments are. 887 00:44:21,830 --> 00:44:22,490 它查看ARGL It looks at argl, 888 00:44:22,490 --> 00:44:24,280 然后你会在这里看到逆序的约定 and then you see a reversal convention here. 889 00:44:24,280 --> 00:44:26,620 它需要知道ARGL是逆序的 It just has to know that argl is reversed, 890 00:44:27,060 --> 00:44:28,810 然后它构造了这个框架 E1 and it builds this frame, E,1. 891 00:44:29,990 --> 00:44:31,088 因此我们假设 All right, so, let's assume that 892 00:44:31,104 --> 00:44:32,920 MAKE-BINDINGS返回的就是这些东西 that's what make bindings returns, 893 00:44:33,360 --> 00:44:36,220 然后 它把E1赋值给ENV so it assigns to ENV this thing, E,1. 894 00:44:41,340 --> 00:44:42,544 下一步就是 The next thing it says 895 00:44:43,952 --> 00:44:45,840 恢复CONTINUE is restore continue. 896 00:44:46,890 --> 00:44:48,190 还记得CONTINUE之前是什么吗? Remember what continue was here? 897 00:44:48,760 --> 00:44:50,430 在最后一段中 It got put up in the last segment. 898 00:44:52,240 --> 00:44:54,020 CONTINUE被保存了 Continue got stored. 899 00:44:54,020 --> 00:44:55,180 它的值是最初的'DONE That was the original done, 900 00:44:55,320 --> 00:44:56,560 这代表了 which said what are you going to do 901 00:44:56,730 --> 00:44:59,440 在完成这项特定应用后要做的事 after you're done with this particular application? 902 00:45:00,140 --> 00:45:01,720 这是在求值整个应用时 It was one of the very first things that happened 903 00:45:01,760 --> 00:45:03,180 最先发生的事儿 when we evaluated the application. 904 00:45:03,880 --> 00:45:05,870 现在 我们要恢复CONTINUE了 And now, finally, we're going to restore continue. 905 00:45:06,860 --> 00:45:09,550 还记得APPLY-DISPATCH的约定么? Remember apply-dispatch's contract. 906 00:45:09,580 --> 00:45:11,200 它假设下一步的跳转目标 It assumes that where it should go to next 907 00:45:11,230 --> 00:45:11,980 已经存放在栈上了 was on the stack, 908 00:45:12,030 --> 00:45:13,120 并且 这里确实存放在栈上了 and there it was on the stack. 909 00:45:13,590 --> 00:45:14,760 CONTINUE被赋值成了DONE Continue has done, 910 00:45:17,820 --> 00:45:19,900 现在我们要回到EVAL-DISPATCH了 and now we're going to go back to eval-dispatch. 911 00:45:19,940 --> 00:45:20,840 我们要再次进行寄存器设置 We're set up again. 912 00:45:20,970 --> 00:45:24,410 我们有表达式、环境、下一步 We have an expression, an environment, and a place to go to. 913 00:45:25,800 --> 00:45:26,890 我不会再细讲了 We're not going to go through that 914 00:45:27,880 --> 00:45:29,550 因为它基本上就是相同的表达式 because it's sort of the same expression. 915 00:45:35,400 --> 00:45:37,792 但是需要注意的是 OK, but the thing, again, to notice 916 00:45:37,824 --> 00:45:38,736 在这个时候 is, at this point, 917 00:45:39,340 --> 00:45:43,720 我们已经归约了原始表达式(F X Y) we have reduced the original expression, F,X,Y, 918 00:45:44,640 --> 00:45:47,920 通过在E0中求值(F X Y) We've reduced evaluating F,X,Y in environment E,0 919 00:45:48,890 --> 00:45:52,670 将其归约为在E1中求值(+ A B) to evaluate plus A, B in E,1. 920 00:45:52,780 --> 00:45:55,920 要注意 栈上并没有什么东西 对吧? And notice, nothing's on the stack, right? 921 00:45:56,110 --> 00:45:56,830 这是一个归约 It's a reduction. 922 00:45:56,840 --> 00:45:59,800 这个时候 机器的状态中 At this point, the machine does not contain, 923 00:45:59,840 --> 00:46:01,200 并没有包含 as part of its state, 924 00:46:01,760 --> 00:46:03,712 它是求值过程F的 the fact that it's in the middle of evaluating 925 00:46:03,728 --> 00:46:04,880 中间状态的事实 some procedure called f, 926 00:46:05,490 --> 00:46:06,280 它消失了 that's gone, 927 00:46:07,660 --> 00:46:09,550 这里面没有积累的状态 Right? There's no accumulated state? 928 00:46:13,070 --> 00:46:14,370 注意 这个思想非常重要 Again, that's a very important idea. 929 00:46:14,370 --> 00:46:16,330 这意味着 That's the meaning of, 930 00:46:16,760 --> 00:46:18,390 当我们使用代换模型时 when we used to write in the substitution model, 931 00:46:18,390 --> 00:46:20,860 一条表达式会归约到另一条表达式 this expression reduces to that expression. 932 00:46:21,350 --> 00:46:22,660 而你不需要记住任何东西 And you don't have to remember anything. 933 00:46:22,660 --> 00:46:24,500 这里 你就见到了归约的真谛 And here, you see the meaning of reduction. 934 00:46:24,560 --> 00:46:26,160 这个时候 栈上没有任何东西 At this point, there is nothing on the stack. 935 00:46:31,590 --> 00:46:33,630 这样就有一个非常重要的结果 See, that has very important consequences. 936 00:46:35,240 --> 00:46:37,900 让我们回过头来看看迭代式阶乘 Let's go back and look at iterative factorial, 937 00:46:40,420 --> 00:46:42,768 还记得吗?这是某种循环 all right? Remember, this was some sort of loop 938 00:46:44,016 --> 00:46:44,880 用来进行迭代 and doing iter. 939 00:46:45,130 --> 00:46:47,360 我们不断强调 它是一个迭代过程 And we kept saying that's an iterative procedure, 940 00:46:49,260 --> 00:46:53,840 还记得吗 And what we wrote, remember, 941 00:46:58,440 --> 00:47:03,130 我们使用它的时候 are things like, we said, 942 00:47:04,350 --> 00:47:11,070 是像(FACT-ITER 5)这样调用它的 fact-iter of 5. 943 00:47:12,360 --> 00:47:18,670 然后我们把它归约成(ITER 1 1 5) We wrote things like reduces to iter of 1, and 1, and 5, 944 00:47:19,030 --> 00:47:25,150 然后它归约成(ITER 1 2 5) which reduces to iter of 1, and 2, and 5, 945 00:47:25,320 --> 00:47:27,070 等等等等 and so on, and so on, and so on. 946 00:47:27,070 --> 00:47:28,170 然后我们又说 看 And we kept saying well, look, 947 00:47:28,170 --> 00:47:30,350 为了实现这个效果 不需要存储任何东西 you don't have to build up any storage to do that. 948 00:47:31,720 --> 00:47:32,730 我们摆了摆手 说 And we waved our hands, 949 00:47:32,750 --> 00:47:34,590 “原则上 这不需要任何存储” and said in principle, there's no storage needed. 950 00:47:35,040 --> 00:47:36,170 现在你们发现 确实不需要 Now, you see no storage needed. 951 00:47:36,170 --> 00:47:39,090 这里的每一步都是真正的归约 对吧? Each of these is a real reduction, right? 952 00:47:39,090 --> 00:47:42,600 随着你求值这些表达式 As you walk through these expressions, 953 00:47:47,300 --> 00:47:50,512 在求值这些表达式的过程中 As you walk through these expressions, 954 00:47:50,832 --> 00:47:51,370 你会发现 what you'll see 955 00:47:51,370 --> 00:47:52,810 栈上的这些表达式 are these expressions on the stack 956 00:47:53,750 --> 00:47:55,640 都在一个特定的环境中 in some particular environment, 957 00:47:56,420 --> 00:48:00,020 抱歉 是EXP寄存器中的表达式 and then these expressions, sorry, in the EXP register 958 00:48:00,020 --> 00:48:01,500 是在某个特定的环境中 in some particular environment. 959 00:48:01,570 --> 00:48:02,190 并且 在每一步 And, at each point, 960 00:48:02,190 --> 00:48:04,000 栈上不会积累任何东西 there'll be no accumulated stuff on the stack 961 00:48:04,360 --> 00:48:05,680 因为每一步都是真正的归约 because each one's a real reduction. 962 00:48:09,280 --> 00:48:10,510 因此 举例来说 All right, so, for example, 963 00:48:10,580 --> 00:48:12,510 说得更仔细一点 just to go through it in a little bit more care, 964 00:48:13,460 --> 00:48:16,880 如果我从这样的一条表达式开始 if I start out with an expression that says something like, 965 00:48:22,440 --> 00:48:34,250 比如说 在某个环境中计算(FACT-ITER 5) oh, say, fact-iter of 5 in some environment 966 00:48:42,110 --> 00:48:46,300 它将在某个时刻创建一个环境 that will, at some point, create an environment 967 00:48:46,810 --> 00:48:48,380 其中N=5 in which n is down to 5. 968 00:48:51,470 --> 00:48:52,010 我们把它写下来 Let's call that-- 969 00:48:55,680 --> 00:48:56,590 然后 在某个时候 And, at some point, 970 00:48:56,890 --> 00:49:02,560 机器会归约这整个东西 the machine will reduce this whole thing 971 00:49:02,910 --> 00:49:04,350 将它归约为 to a thing that says that's really 972 00:49:04,760 --> 00:49:09,850 (ITER 1 1 N) iter of 1, and 1, and n, 973 00:49:10,680 --> 00:49:13,720 然后在环境E1中求值这条表达式 evaluated in this environment, E,1 974 00:49:15,870 --> 00:49:17,160 而不在栈上存放任何东西 with nothing on the stack. 975 00:49:17,160 --> 00:49:19,550 看到了么 这时机器并不会记住 See, at this moment, the machine is not remembering 976 00:49:20,710 --> 00:49:22,500 求值这条ITER表达式-- that evaluating this expression, iter-- 977 00:49:25,000 --> 00:49:25,630 也就是某种循环-- which is the loop-- 978 00:49:25,790 --> 00:49:28,570 并不是FACT-ITER的一部分 is part of this thing called iterative factorial. 979 00:49:29,680 --> 00:49:30,590 它不会记住这个事实 It's not remembering that. 980 00:49:30,590 --> 00:49:33,170 它只是归约了该表达式 It's just reducing the expression to that, right? 981 00:49:33,170 --> 00:49:36,560 如果我们再来看迭代式阶乘的体 If we look again at the body of iterative factorial, 982 00:49:38,050 --> 00:49:41,080 这条表达式归约为了这条表达式 this expression has reduced to that expression. 983 00:49:42,810 --> 00:49:43,870 哦 这里漏了一个N Oh, I shouldn't have the n there. 984 00:49:46,590 --> 00:49:47,744 幻灯片中的约定 It's a slightly different convention 985 00:49:47,744 --> 00:49:49,130 和实际程序中稍有不同 from the slide to the program. 986 00:49:53,340 --> 00:49:56,250 那么 ITER的体又是什么? And, then, what's the body of iter? 987 00:49:56,280 --> 00:49:57,400 ITER的体首先是一个IF-- Well, iter's going to be an if, 988 00:49:58,750 --> 00:50:00,190 我不会再深入IF语句的细节了 and I won't go through the details of if. 989 00:50:00,240 --> 00:50:01,630 它会对谓词求值 It'll evaluate the predicate. 990 00:50:02,400 --> 00:50:03,710 本例中 会返回FALSE In this case, it'll be false. 991 00:50:03,810 --> 00:50:08,640 然后这里的ITER会归约为表达式-- And this iter will now reduce to the expression 992 00:50:09,850 --> 00:50:20,200 (ITER (* COUNTER PRODUCT) iter of whatever it says, star, counter product, and-- 993 00:50:21,620 --> 00:50:22,240 按照它代码写的-- what does it say-- 994 00:50:22,680 --> 00:50:24,560 (+ COUNTER 1)) plus counter 1 995 00:50:28,720 --> 00:50:31,420 在另外的一个环境E2中求值 in some other environment, by this time, E,2, 996 00:50:32,970 --> 00:50:35,980 其中 E2会记录着 where E,2 will be set up having bindings 997 00:50:36,490 --> 00:50:39,390 PRODUCT和COUNTER的值 for product and counter. 998 00:50:42,920 --> 00:50:44,330 它会被归约为这条语句 And it'll reduce to that. 999 00:50:44,940 --> 00:50:46,040 它不会记得 Right? It won't be remembering 1000 00:50:46,060 --> 00:50:48,750 它是一个需要返回到某处的一部分 that it's part of something that it has to return to. 1001 00:50:49,340 --> 00:50:50,430 当ITER再次调用ITER时 And when iter calls iter again, 1002 00:50:50,440 --> 00:50:52,560 它会归约为另一个像这样的东西 it'll reduce to another thing that looks like this 1003 00:50:53,050 --> 00:50:54,680 只是会在新环境E3中 in some environment, E,3, 1004 00:50:54,830 --> 00:50:56,670 里面有关于PRODUCT和COUNTER新的绑定 which has new bindings for product and counter. 1005 00:50:58,800 --> 00:51:05,290 因此 如果你想知道 OK? So, if you're wondering, 1006 00:51:06,090 --> 00:51:07,530 如果你一直感到不安 if you've always been queasy about 1007 00:51:08,250 --> 00:51:10,670 不知道为什么我们说这些过程 about how it is we've been saying those procedures 1008 00:51:10,670 --> 00:51:12,450 虽然从语法上看起来是递归的 that look syntactically recursive, 1009 00:51:13,200 --> 00:51:15,690 但实际上是迭代的 are, in fact, iterative, 1010 00:51:15,870 --> 00:51:17,240 可以在常量空间中运行 run in constant space, 1011 00:51:18,400 --> 00:51:19,750 我不知道这么说是否打消了你们的疑虑 well, I don't know if this makes you less queasy, 1012 00:51:19,750 --> 00:51:21,230 但至少让你们知道发生了什么 but at least it shows you what's happening. 1013 00:51:21,230 --> 00:51:22,810 这其中没有任何构造 There really isn't any buildup there. 1014 00:51:25,910 --> 00:51:27,580 但你也会说 这里面还是有一些构造 Now, you might ask well, is there buildup 1015 00:51:27,980 --> 00:51:30,080 从原则上来说 我们也构造了环境框架 in principle in these environment frames? 1016 00:51:31,710 --> 00:51:32,370 答案则是 And the answer is yeah, 1017 00:51:32,400 --> 00:51:33,840 你确实需要构建这些环境框架 you have to make these new environment frames, 1018 00:51:33,840 --> 00:51:35,264 但是 等你求值完毕后 but you don't have to hang onto them 1019 00:51:35,424 --> 00:51:36,192 不必保留它们 when you're done. 1020 00:51:36,440 --> 00:51:37,610 它们可以被废料收集 They can be garbage collected, 1021 00:51:37,920 --> 00:51:39,470 这些空间也可以被自动地重用 or the space can be reused automatically. 1022 00:51:40,720 --> 00:51:42,990 但你们可以看到求值器控制流 But you see the control structure of the evaluator 1023 00:51:43,250 --> 00:51:46,120 的中心思想就是进行归约 is really using this idea that you actually have a reduction, 1024 00:51:47,020 --> 00:51:49,290 因此这些过程实际上是迭代过程 so these procedures really are iterative procedures. 1025 00:51:50,130 --> 00:51:51,380 好吧 有什么问题么? All right, let's stop for questions. 1026 00:52:02,680 --> 00:52:03,230 好吧 课件休息吧 All right, let's break. 1027 00:52:04,120 --> 00:52:24,560 [音乐] [JESU, JOY OF MAN'S DESIRING] 1028 00:52:24,600 --> 00:52:29,696 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 1029 00:52:35,200 --> 00:52:38,368 讲师: 哈罗德·艾伯森教授 及 格兰德·杰·萨斯曼教授 By: Prof. Harold Abelson && Sussman Jay Sussman 1030 00:52:38,360 --> 00:52:42,144 《计算机程序的构造和解释》 The Structure And Interpretation of Computer Programs 1031 00:52:42,140 --> 00:52:46,448 显示控制求值器 Explicit-control Evaluator 1032 00:52:48,770 --> 00:52:51,550 教授:跟迭代过程形成对比的是 PROFESSOR: Let me contrast the iterative procedure 1033 00:52:52,770 --> 00:52:54,896 确实会占用空间的 just so you'll see where space does build up 1034 00:52:55,120 --> 00:52:56,140 递归过程 with a recursive procedure, 1035 00:52:56,170 --> 00:52:57,290 你们可以看到其中的区别 so you can see the difference. 1036 00:52:58,030 --> 00:53:01,200 让我们来看看递归式阶乘的求值 Let's look at the evaluation of recursive factorial. 1037 00:53:02,650 --> 00:53:05,536 这里的FACT-REC So, here's fact-recursive, 1038 00:53:05,552 --> 00:53:07,220 就是阶乘的标准定义 or standard factorial definition. 1039 00:53:07,220 --> 00:53:10,010 这个当然是一个递归过程 We said this one is still a recursive procedure, 1040 00:53:10,010 --> 00:53:12,570 它的计算过程也是递归的 but this is actually a recursive process. 1041 00:53:13,750 --> 00:53:16,560 然后 只要把它和我们开始的方式联系起来 And then, just to link it back to the way we started, 1042 00:53:16,830 --> 00:53:20,530 我们会通过代换模型发现 we said oh, you can see that it's going to be recursive process 1043 00:53:20,530 --> 00:53:21,820 这是一个递归过程 by the substitution model 1044 00:53:22,360 --> 00:53:28,000 因为 如果我调用(REC-FACT 5) because, if I say recursive factorial of 5, 1045 00:53:30,450 --> 00:53:34,940 会变成(* 5 that turns into 5 times-- 1046 00:53:36,280 --> 00:53:37,820 哦 这里是FACT-REC what is it, fact-rec, or record fact-- 1047 00:53:42,620 --> 00:53:47,930 (* 5 (FACT-REC 4)) 5 times recursive factorial of 4, 1048 00:53:49,660 --> 00:53:58,220 又会变成(* 5 (* 4 (FACT-REC 3))) which turns into 5 times 4 times fact-rec of 3, 1049 00:54:00,220 --> 00:54:08,600 又会变成(* 5 (* 4 (* 3 (* ... which returns into 5 times 4 times 3 times 1050 00:54:13,450 --> 00:54:15,310 以此类推 and so on, right? 1051 00:54:15,390 --> 00:54:17,390 关键点就是 有一条链条被不断构造出来 The idea is there was this chain of stuff building up, 1052 00:54:18,100 --> 00:54:20,060 这就在代换模型中证明了 which justified, in the substitution model, 1053 00:54:20,080 --> 00:54:21,280 FACT-REC是递归的 the fact that it's recursive. 1054 00:54:21,520 --> 00:54:24,180 现在 让我们来看看这条构造起来的链条 And now, let's actually see that chain of stuff build up 1055 00:54:24,180 --> 00:54:25,290 它又是在机器中的什么地方? and where it is in the machine, OK? 1056 00:54:27,680 --> 00:54:29,950 好吧 让我们想象一下要从哪里开始 All right, well, let's imagine we're going to start out again. 1057 00:54:30,440 --> 00:54:40,010 我们告诉机器 求值(FACT-REC 5) We'll tell it to evaluate recursive factorial of 5 1058 00:54:41,450 --> 00:54:43,390 基于的环境是E0 in some environment, again, E0, where 1059 00:54:45,080 --> 00:54:48,970 也就是定义FACT-REC时的环境 where recursive factorial is defined, OK? 1060 00:54:49,550 --> 00:54:51,230 现在 我们知道最终要发生什么 Well, now we know what's eventually going to happen. 1061 00:54:52,250 --> 00:54:53,640 首先 This is going to come along, 1062 00:54:53,920 --> 00:54:55,640 它会对这些东西求值 it'll evaluate those things, 1063 00:54:55,680 --> 00:54:56,990 发现它是一个过程 figure out it's a procedure, 1064 00:54:57,180 --> 00:55:00,160 在这里创建一个新环境E1 build somewhere over here an environment, E1, 1065 00:55:00,880 --> 00:55:03,690 其中N=5 which has n bound to 5, 1066 00:55:04,330 --> 00:55:06,540 并且与E0相连 which hangs off of E0, 1067 00:55:07,800 --> 00:55:08,970 这个E0也就是 which would be, presumably, 1068 00:55:08,990 --> 00:55:12,300 定义FACT-REC的那个环境 the definition environment of recursive factorial. 1069 00:55:14,110 --> 00:55:15,740 然后 在E1这个环境中 OK? And, in this environment, 1070 00:55:15,760 --> 00:55:17,480 求值过程的体 it's going to go off and evaluate the body. 1071 00:55:19,670 --> 00:55:25,920 因此 在这里求值会归约为 So, again, the evaluation here will reduce to 1072 00:55:27,000 --> 00:55:28,920 在E1中求值过程的体 evaluating the body in E1. 1073 00:55:30,160 --> 00:55:31,340 这就需要求值IF语句 That's going to look at an if, 1074 00:55:32,170 --> 00:55:33,530 而我不会讲解IF语句的细节 and I won't go through the details of if. 1075 00:55:33,530 --> 00:55:34,880 IF语句会求值谓词 It'll look at the predicate. 1076 00:55:34,880 --> 00:55:37,530 最后发现需要求值ELSE子句 It'll decide it eventually has to evaluate the alternative. 1077 00:55:37,840 --> 00:55:40,410 因此 这里的整个部分 会归约为 So this whole thing, again, will reduce to 1078 00:55:41,300 --> 00:55:45,530 FACT-REC的ELSE子句 the alternative of recursive factorial, 1079 00:55:45,820 --> 00:55:46,970 也就是谓词为假的部分 the alternative clause, 1080 00:55:47,230 --> 00:55:51,160 整个表达式就归约为了(* N which says that this whole thing reduces to times n 1081 00:55:53,070 --> 00:55:59,960 (FACT-REC (- N 1)) of recursive factorial of n minus 1 1082 00:56:03,480 --> 00:56:05,550 求值的环境是E1 in the environment E1 1083 00:56:08,380 --> 00:56:10,910 因此 最初的表达式现在就会归约为 OK? So the original expression, now, is going to reduce 1084 00:56:11,040 --> 00:56:12,520 求值这样的一个表达式 to evaluating that expression, all right? 1085 00:56:13,750 --> 00:56:16,280 而现在 我们面对的是一个应用 OK? Now we have an application. 1086 00:56:16,280 --> 00:56:17,630 我们之前求值过应用 We did an application before. 1087 00:56:18,220 --> 00:56:20,250 还记得要怎么求值应用么? Remember what happens in an application? 1088 00:56:20,360 --> 00:56:21,690 正式求值一个应用之前 The first thing you do is you go off and you 1089 00:56:21,740 --> 00:56:24,810 你需要把CONTINUE寄存器的值保存在栈上 you save the value of the continue register on the stack. 1090 00:56:25,350 --> 00:56:27,180 此时 栈上会有一个值'DONE So the stack here is going to have done in it. 1091 00:56:29,980 --> 00:56:32,880 接下来 你要为求值子部分做准备 And then you're going to set up to evaluate the sub-parts. 1092 00:56:35,000 --> 00:56:37,200 因此 我们在这里开始求值子部分 OK? So here we go off to evaluate the sub-parts. 1093 00:56:39,470 --> 00:56:41,450 首先要做的是求值运算符 First thing we're going to do is evaluate the operator. 1094 00:56:44,600 --> 00:56:46,320 运算符是怎样求值的呢? What happens when we evaluate an operator? 1095 00:56:47,250 --> 00:56:48,990 我们通过一些手段 Well, we arrange things so that 1096 00:56:49,000 --> 00:56:51,040 将EXP寄存器指向运算符对应的过程 the operator ends up in the expression register. 1097 00:56:51,480 --> 00:56:53,150 并且让ENV寄存器指向求值的环境 The environments in the ENV register 1098 00:56:53,660 --> 00:56:54,608 而把CONTINUE寄存器赋值为 continue someplace 1099 00:56:54,624 --> 00:56:56,220 用于求值参数的EVAL-ARGS where we're going to go evaluate the arguments. 1100 00:56:56,590 --> 00:56:57,370 并且 我们把 And, on the stack, 1101 00:56:57,400 --> 00:56:59,290 CONTINUE的原始值保存在栈上 we've saved the original continue, 1102 00:56:59,520 --> 00:57:01,020 我们完成所有工作后 就会跳转到这个地方 which is where we wanted to be when we're all done. 1103 00:57:01,720 --> 00:57:02,860 在我们求值完运算符后 And then the things we needed 1104 00:57:03,580 --> 00:57:05,800 需要做的则是 when we're going to get done evaluating the operator, 1105 00:57:05,900 --> 00:57:07,660 求值对实际参数进行求值 the things we'll need to evaluate the arguments, 1106 00:57:07,690 --> 00:57:12,010 也就是这个环境和这些参数 namely the environment and those arguments, 1107 00:57:12,140 --> 00:57:13,440 这些尚未求值的实际参数 those unevaluated arguments, 1108 00:57:14,200 --> 00:57:15,620 它们现在都还在栈上 so there they are sitting on the stack. 1109 00:57:15,620 --> 00:57:18,590 我们现在就要先来求值运算符 And we're about to go off to evaluate the operator. 1110 00:57:23,260 --> 00:57:26,730 当我们从这个调用返回时 Well, when we return from this particular call-- 1111 00:57:26,920 --> 00:57:28,640 在这里 我们将要去调用EVAL-DISPATCH so we're about to call eval-dispatch here-- 1112 00:57:29,380 --> 00:57:30,830 当我们从这个调用返回时 when we return from this call, 1113 00:57:31,450 --> 00:57:32,700 这个运算符所对应的值 the value of that operator, 1114 00:57:32,730 --> 00:57:33,520 在本例中 which, in this case, 1115 00:57:33,552 --> 00:57:35,440 也就是基本的乘法过程 is going to be the primitive multiplier procedure, 1116 00:57:36,440 --> 00:57:37,930 会存放在FUN寄存器中 will end up in the FUN register. 1117 00:57:43,020 --> 00:57:44,530 我们要去求值实际参数 We're going to evaluate some arguments. 1118 00:57:44,530 --> 00:57:45,850 现在这里求值N They will evaluate n here. 1119 00:57:47,730 --> 00:57:49,870 本例中 会返回5 That'll give us 5, in this case. 1120 00:57:50,250 --> 00:57:52,040 然后我们会把它放入ARGL寄存器 We're going to put that in the argl register, 1121 00:57:53,000 --> 00:57:55,880 然后我们会去求值第二个运算对象 and then we'll go off to evaluate the second operand. 1122 00:57:57,460 --> 00:58:00,480 就在我们准备求值第二个运算对象之时 So, at the point where we go off to evaluate the second operand-- 1123 00:58:00,520 --> 00:58:02,192 我会省略计算 and I'll skip details like computing, 1124 00:58:02,208 --> 00:58:03,580 (- N 1)之类的细节 N minus 1, and all of that-- 1125 00:58:03,710 --> 00:58:05,880 但是 当我们去求值第二个运算对象时 but, when we go off to evaluate the second operand, 1126 00:58:06,620 --> 00:58:10,440 会最终归约为对FACT-REC的另一个调用 that will eventually reduce to another call to fact-recursive. 1127 00:58:12,000 --> 00:58:14,200 现在 我们在栈上有 And, what we've got on the stack here is 1128 00:58:16,520 --> 00:58:19,940 来自于这个组合式的运算符 the operator from that combination that we're going to use it in 1129 00:58:20,120 --> 00:58:21,070 以及其它的参数 and the other argument. 1130 00:58:23,400 --> 00:58:27,610 现在 我们已经准备好 OK? So, now, we're set up for another call 1131 00:58:28,490 --> 00:58:29,690 去调用另外的FACT-REC了 to recursive factorial. 1132 00:58:30,200 --> 00:58:31,430 而让我们完成了这个调用以后 And, when we're done with this one, 1133 00:58:31,560 --> 00:58:33,640 我们就要跳转到ACCUMULATE-LAST-ARG we're going to go to accumulate the last arg. 1134 00:58:34,120 --> 00:58:35,200 还记得这是做什么的么? and remember what that'll do? 1135 00:58:35,200 --> 00:58:35,930 它会说 That'll say oh, 1136 00:58:36,450 --> 00:58:39,280 我们会把这个调用的结果 whatever the result of this has to get combined with that, 1137 00:58:39,280 --> 00:58:40,400 和这个5相乘 and we're going to multiply them. 1138 00:58:41,690 --> 00:58:42,380 但是请注意 But, notice now, 1139 00:58:42,730 --> 00:58:44,810 我们现在处于另一个递归阶乘中 we're at another recursive factorial. 1140 00:58:45,720 --> 00:58:48,920 我们又要再次调用EVAL-DISPATCH We're about to call eval-dispatch again, 1141 00:58:49,320 --> 00:58:50,600 然而我们并没有真正地“归约”它 except we haven't really reduced it 1142 00:58:50,640 --> 00:58:52,080 因为现在栈上还有东西 because there's stuff on the stack now. 1143 00:58:53,700 --> 00:58:55,390 栈上的这些东西说:“当你返回时” The stuff on the stack says oh, when you get back, 1144 00:58:55,400 --> 00:58:57,520 你最好把结果和放在这里的5相乘 you'd better multiply it by the 5 you had hanging there. 1145 00:58:58,430 --> 00:59:05,770 所以当我们进行另外的调用 So, when we go off to make another call, 1146 00:59:07,120 --> 00:59:08,840 求值(- N 1) we evaluate the n minus 1. 1147 00:59:09,300 --> 00:59:11,050 这会返回给我们另一个环境 That gives us another environment which 1148 00:59:11,250 --> 00:59:13,840 其中N的新值为4 in which the new n's going to be down to 4. 1149 00:59:14,600 --> 00:59:16,220 然后又将调用EVAL-DISPATCH And we're about to call eval-dispatch again. 1150 00:59:19,200 --> 00:59:20,220 我们又创建了另一个调用 We get another call. 1151 00:59:21,350 --> 00:59:24,440 这个4又会遇到相同的情况 That 4 is going to end up in the same situation. 1152 00:59:26,040 --> 00:59:28,620 我们最后会遇到对(FACT-REC N)的又一次调用 We'll end up with another call to fact-recursive n. 1153 00:59:30,020 --> 00:59:32,680 而这时候 栈上会有从最初的调用 And sitting on the stack will be the stuff from the original one 1154 00:59:32,880 --> 00:59:34,510 到最近一次调用的东西 and, now, the subsidiary one we're doing. 1155 00:59:35,360 --> 00:59:36,910 它们都在等待同一个东西 And both of them are waiting for the same thing. 1156 00:59:36,910 --> 00:59:39,160 它们都要跳转到ACCUMULATE-LAST-ARG They're going to go to accumulate a last argument. 1157 00:59:40,510 --> 00:59:42,940 当然 当我们进行第四次调用时 And then, of course, when we go to the fourth call, 1158 00:59:43,250 --> 00:59:44,380 会发生同样的事 the same thing happens. 1159 00:59:45,640 --> 00:59:47,070 如此往复 And this goes on, and on, and on. 1160 00:59:47,300 --> 00:59:48,600 在这里 你在栈上看到的 And what you see here on the stack, 1161 00:59:50,300 --> 00:59:52,220 栈上面实际存放的是 exactly what's sitting here on the stack, 1162 00:59:52,220 --> 00:59:54,590 基本过程*以及5 the thing that says times and 5. 1163 00:59:54,960 --> 00:59:56,400 而你要把它用来 And what you're going to do with that 1164 00:59:56,590 --> 00:59:58,540 调用ACCUMULATE-LAST-ARG accumulate that into a last argument. 1165 01:00:00,470 --> 01:00:02,016 就是这样 对吧? That's exactly this, right? 1166 01:00:02,010 --> 01:00:04,750 这跟它们在表达式中的顺序是一致的 This is exactly where that stuff is hanging. 1167 01:00:05,650 --> 01:00:10,650 实际上 你将要应用的运算符 Effectively, the operator you're going to apply, 1168 01:00:11,720 --> 01:00:14,304 以及当你返回时 the other argument that it's got 1169 01:00:14,320 --> 01:00:15,790 需要去求积的参数 to be multiplied by when you get back 1170 01:00:15,808 --> 01:00:16,910 以及这里的括号 and sort of the parentheses, 1171 01:00:16,940 --> 01:00:18,960 都在告诉你 在对它们进行积累 which says yeah, what you wanted to do was accumulate them. 1172 01:00:19,620 --> 01:00:21,880 因此 你可以看到代换模型并不是这样的谎言 So, you see, the substitution model is not such a lie. 1173 01:00:22,560 --> 01:00:23,630 从某种意义上来说 它实际上是 That really is, in some sense, 1174 01:00:23,640 --> 01:00:25,310 存在于栈上的那些东西 what's sitting right on the stack. 1175 01:00:29,370 --> 01:00:30,400 好吧 从某种意义上来说 All right, so that, 1176 01:00:30,810 --> 01:00:32,480 应该给你们解释了 in some sense, should explain for you, 1177 01:00:33,260 --> 01:00:34,520 或者 至少让你们相信 or at least convince you, 1178 01:00:35,930 --> 01:00:38,720 求值器会通过某些方式 that somehow, this evaluator is managing 1179 01:00:40,060 --> 01:00:42,860 迭代地去求值某些过程 to take these procedures and execute some of them iteratively 1180 01:00:42,950 --> 01:00:44,250 而递归地去求值另外的过程 and some of them recursively, 1181 01:00:45,260 --> 01:00:47,450 尽管从语法上看 even though, as syntactically, 1182 01:00:47,450 --> 01:00:49,050 它们都是递归过程 they look like recursive procedures. 1183 01:00:49,400 --> 01:00:50,640 它又是如何做到的呢? How's it managing to do that? 1184 01:00:50,660 --> 01:00:53,720 其中的基本原因就是 Well, the basic reason it's managing to do that 1185 01:00:53,800 --> 01:00:55,680 求值器被设置为 is the evaluator is set up 1186 01:00:56,040 --> 01:00:59,260 只保存那些稍后会用到的东西 to save only what it needs later. 1187 01:01:01,090 --> 01:01:04,250 比如说 当你在把 So, for example, at the point where you've reduced 1188 01:01:04,670 --> 01:01:07,390 在一个环境中求值表达式归约为 evaluating an expression and an environment 1189 01:01:07,870 --> 01:01:09,870 将某个过程应用在参数上时 to applying a procedure to some arguments, 1190 01:01:10,520 --> 01:01:12,490 它就不再需要最初的环境了 it doesn't need that original environment anymore 1191 01:01:13,370 --> 01:01:16,650 因为所需要的环境信息都被打包到 because any environment stuff will be packaged inside the procedures 1192 01:01:17,880 --> 01:01:19,360 需要应用的那个过程中了 where the application's going to happen. 1193 01:01:20,750 --> 01:01:21,610 同样 类似地 All right, similarly, 1194 01:01:21,630 --> 01:01:23,650 当你求值一个参数表时 when you're going along evaluating an argument list, 1195 01:01:23,650 --> 01:01:25,200 当你完成对表的求值时 when you've finished evaluating the list, 1196 01:01:25,910 --> 01:01:28,030 当你求值完最后一个参数时 when you're finished evaluating the last argument, 1197 01:01:28,200 --> 01:01:31,610 你就不再需要这个参数表了 对吧? you don't need that argument list any more, right? 1198 01:01:31,630 --> 01:01:32,940 你也就不再需要 And you don't need the environment where 1199 01:01:33,040 --> 01:01:34,640 求值这些参数所需的环境了 those arguments would be evaluated. 1200 01:01:36,690 --> 01:01:40,890 所以这个解释器如此“智能”的根本原因 So the basic reason that this interpreter is being so smart 1201 01:01:40,890 --> 01:01:42,880 根本不是因为它“智能” 只是因为它老实 is that it's not being smart at all, it's being stupid. 1202 01:01:43,050 --> 01:01:45,740 它的原则就是:“只保存那些需要的” It's just saying I'm only going to save what I really need. 1203 01:01:48,700 --> 01:01:51,000 这里 让我来给你们展示 Well, let me show you here. 1204 01:01:53,070 --> 01:01:57,200 这是致使尾递归的根本原因 Here's the actual thing that's making a tail recursive. 1205 01:01:58,310 --> 01:02:00,200 要记住 (RESOTRE CONTINUE)这条代码 Remember, it's the restore of continue. 1206 01:02:00,220 --> 01:02:06,940 它指的是 当我去求值过程体的时候 It's saying when I go off to evaluate the procedure body, 1207 01:02:08,960 --> 01:02:11,000 我应该告诉EVAL返回到 I should tell eval to come back to 1208 01:02:11,250 --> 01:02:12,540 最初的求值 the place where that original 1209 01:02:12,540 --> 01:02:14,250 应该返回的地方 evaluation was supposed to come back to. 1210 01:02:15,170 --> 01:02:15,950 因此 从某种角度来说 So, in some sense, 1211 01:02:16,170 --> 01:02:18,840 你想知道是哪一行代码致使了尾递归 you want to say what's the actual line that makes tail recursive 1212 01:02:18,890 --> 01:02:19,440 那么就是这一行 It's that one. 1213 01:02:19,920 --> 01:02:21,530 出于某些奇怪的原因 If I wanted to build a non- 1214 01:02:21,770 --> 01:02:24,800 如果我想构建一个没有尾递归的求值器 tail recursive evaluator, for some strange reason, 1215 01:02:25,690 --> 01:02:26,860 我需要做的就是 all I would need to do 1216 01:02:27,120 --> 01:02:29,290 在这里先不要去恢复CONTINUE is, instead of restoring continue at this point, 1217 01:02:30,060 --> 01:02:31,660 而是在这里建立一个标号 I'd set up a label down here 1218 01:02:32,750 --> 01:02:36,250 用来标识完成过程应用后的返回位置 called, "Where to come back after you've finished applying the procedure." 1219 01:02:37,640 --> 01:02:39,710 而我会把CONTINUE设置为这个标号 Instead, I'd set continue to that. 1220 01:02:39,920 --> 01:02:41,210 然后跳转到EVAL-DISPATCH I'd go to eval-dispatch, 1221 01:02:41,400 --> 01:02:43,210 然后EVAL-DISPATCH会回到这里 and then eval-dispatch would come back here. 1222 01:02:43,790 --> 01:02:44,300 而这时 At that point, 1223 01:02:44,320 --> 01:02:45,280 我会恢复CONTINUE I would restore continue 1224 01:02:45,290 --> 01:02:46,520 并回到最初的返回位置 and go to the original one. 1225 01:02:47,920 --> 01:02:51,000 因此 这里唯一的后果就是 So here, the only consequence of that 1226 01:02:51,150 --> 01:02:52,680 解释器不再是尾递归的了 would be to make it non-tail recursive. 1227 01:02:52,840 --> 01:02:54,620 它会给你完全相同的答案 It would give you exactly the same answers, 1228 01:02:54,720 --> 01:02:57,020 只是当你执行迭代式阶乘 except if you did that iterative factorial 1229 01:02:57,050 --> 01:02:58,360 或者其它迭代过程时 and all those iterative procedures, 1230 01:02:58,600 --> 01:02:59,800 它都会递归地去执行 it would execute recursively. 1231 01:03:03,040 --> 01:03:05,400 然而 我对你们撒了一个小谎 Well, I lied to you a little bit, but just a little bit, 1232 01:03:05,760 --> 01:03:06,990 因为我演示的 because I showed you a slightly 1233 01:03:07,020 --> 01:03:08,330 一个有些过于简化的解释器 over-simplified evaluator 1234 01:03:08,720 --> 01:03:10,380 这个解释器假设每个过程 where it assumes that each procedure -- 1235 01:03:11,360 --> 01:03:13,660 只含有一条表达式 each procedure body has only one expression. 1236 01:03:13,890 --> 01:03:14,540 还记得吗 通常来说 Remember, in general, 1237 01:03:14,560 --> 01:03:16,570 过程的体是多条表达式组成的序列 a procedure has a sequence of expressions in it. 1238 01:03:17,870 --> 01:03:20,490 所以没有什么新概念 So there's nothing really conceptually new. 1239 01:03:20,490 --> 01:03:22,280 让我来展示一下实际的求值器 Let me just show you the actual evaluator 1240 01:03:22,890 --> 01:03:24,730 是怎么来处理表达式序列的 that handles sequences of expressions. 1241 01:03:28,470 --> 01:03:29,740 这是现在的COMPOUND-APPLY This is compound-apply now, 1242 01:03:29,740 --> 01:03:31,310 和之前的唯一不同是 and the only difference from the old one 1243 01:03:32,070 --> 01:03:34,330 它不再直接地跳转到EVAL is that, instead of going off to eval directly, 1244 01:03:35,980 --> 01:03:38,030 它先获取整个过程的体 it takes the whole body of the procedure, 1245 01:03:38,030 --> 01:03:40,150 在本例中 也就是表达式序列 which, in this case, is a sequence of expressions, 1246 01:03:40,280 --> 01:03:41,710 然后跳转到EVAL-SEQUENCE and goes off to eval-sequence. 1247 01:03:42,600 --> 01:03:45,320 EVAL-SEQUENCE是一个小型的循环 And eval-sequence is a little loop 1248 01:03:46,830 --> 01:03:49,980 然后每次求值一条表达式 that, basically, does these evaluations one at a time. 1249 01:03:52,630 --> 01:03:53,850 就是这样来求值的-- So it does an evaluation. 1250 01:03:53,900 --> 01:03:54,940 当它求值完一条表达式后 Says oh, when I come back, 1251 01:03:54,970 --> 01:03:56,860 会跳转到这里 去求值下一条 I'd better come back here to do the next one. 1252 01:03:58,440 --> 01:03:59,290 当我完成了所有的求值后 And, when I'm all done, 1253 01:03:59,290 --> 01:04:01,020 我想要跳转到LAST-EXP when I want to get the last expression, 1254 01:04:01,310 --> 01:04:03,280 我就只需要恢复CONTINUE寄存器 I just restore my continue 1255 01:04:03,920 --> 01:04:05,280 然后跳转到EVAL-DISPATCH and go off to eval-dispatch. 1256 01:04:06,410 --> 01:04:08,200 同样的 如果你想要在这种求值器中 And, again, if you wanted for some reason 1257 01:04:08,200 --> 01:04:10,350 破坏尾递归机制 to break tail recursion in this evaluator, 1258 01:04:10,640 --> 01:04:13,710 你只需要在LAST-EXP中不做特殊处理即可 all you need to do is not handle the last expression, especially. 1259 01:04:14,900 --> 01:04:17,340 也就是说 当你处理完最后一条表达式 Just say, after you've done the last expression, 1260 01:04:17,360 --> 01:04:18,650 你跳转到另外一个地方 come back to some other place 1261 01:04:19,150 --> 01:04:20,680 在那个地方去恢复CONTINUE after which you restore continue. 1262 01:04:21,900 --> 01:04:23,260 出于某些原因 And, for some reason, 1263 01:04:23,260 --> 01:04:25,740 很多Lisp求值器倾向于这么做 a lot of LISP evaluators tended to work that way. 1264 01:04:26,550 --> 01:04:28,440 这样做的后果就是 And the only consequence of that is that 1265 01:04:28,860 --> 01:04:30,720 迭代式过程也会使栈增长 iterative procedures built up stack. 1266 01:04:31,880 --> 01:04:33,610 还不清楚为什么会这样 And it's not clear why that happened. 1267 01:04:35,920 --> 01:04:37,980 好吧 我稍微来总结一下 All right. Well, let me just sort of summarize, 1268 01:04:38,090 --> 01:04:39,600 毕竟这是一个大程序 since this is a lot of details 1269 01:04:39,980 --> 01:04:41,040 又有很多细节 in a big program. 1270 01:04:41,120 --> 01:04:42,250 但关键点就是 But the main point is that 1271 01:04:43,040 --> 01:04:43,872 从概念上来说 it's no different, 1272 01:04:44,048 --> 01:04:46,080 这跟翻译其它程序没什么不同 conceptually, from translating any other program. 1273 01:04:47,060 --> 01:04:48,060 核心思想就是 And the main idea is that 1274 01:04:48,060 --> 01:04:50,280 我们已经有了通用求值器程序 we have this universal evaluator program, 1275 01:04:50,330 --> 01:04:51,710 一个元循环求值器 the meta-circular evaluator. 1276 01:04:51,870 --> 01:04:53,070 如果我们把它翻译为了Lisp If we translate that into LISP, 1277 01:04:53,100 --> 01:04:53,950 那么我们就有了Lisp的所有东西 then we have all of LISP. 1278 01:04:54,330 --> 01:04:55,150 我们就是这么来做的 And that's all we did. 1279 01:04:57,980 --> 01:04:59,680 第二点则是 魔法消失了 The second point is that the magic's gone away. 1280 01:04:59,680 --> 01:05:01,970 这整个系统不再神秘了 对吧? There should be no more magic in this whole system, right? 1281 01:05:01,970 --> 01:05:07,790 原则上来说 这应该相当清楚了 In principle, it should all be very clear 1282 01:05:07,820 --> 01:05:10,080 只是还不太了解表结构的内存管理 except, maybe, for how list structured memory works, 1283 01:05:10,800 --> 01:05:11,800 我们后面会讲 and we'll see that later. 1284 01:05:12,640 --> 01:05:14,200 这也并不困难 But that's not very hard. 1285 01:05:15,450 --> 01:05:16,350 第三点就是 The third point is that 1286 01:05:16,350 --> 01:05:17,520 所有的这些尾递归 all this tail recursion 1287 01:05:18,240 --> 01:05:21,960 来自于严格的求值纪律 came from the discipline of eval being very careful 1288 01:05:22,550 --> 01:05:24,510 也就是只保存那些后面会用到的东西 to save only what it needs next time. 1289 01:05:25,870 --> 01:05:27,720 而不是一些比较随意的原则 It's not some arbitrary thing 1290 01:05:27,760 --> 01:05:29,860 比如 无论什么时候我们调用一个子过程 where we're saying well, whenever we call a sub-routine, 1291 01:05:29,860 --> 01:05:32,160 我们会保存所有的寄存器并且返回 we'll save all the registers in the world and come back? 1292 01:05:33,940 --> 01:05:36,490 有些时候为了提效 这样做很值得 See, sometimes it pays to really worry about efficiency. 1293 01:05:37,150 --> 01:05:39,960 当你研究求值机器的内部原理时 And, when you're down in the guts of your evaluator machine, 1294 01:05:40,450 --> 01:05:42,560 这类东西就很值得去研究 it really pays to think about things like that 1295 01:05:42,560 --> 01:05:43,960 因为它会带来显著的不同 because it makes big consequences. 1296 01:05:45,230 --> 01:05:47,690 我想现在基本上已经 Well, I hope what this has done 1297 01:05:47,900 --> 01:05:52,300 把这个求值器讲得很清楚了 is really made the evaluator seem concrete. 1298 01:05:52,560 --> 01:05:53,900 我希望你们能相信 I hope you really believe 1299 01:05:54,320 --> 01:05:56,270 真的有人能够 that somebody could hold a LISP 1300 01:05:56,840 --> 01:05:58,560 将一个Lisp求值器放在掌心之中 LISP evaluator in the palm of their hand. 1301 01:05:59,070 --> 01:06:00,490 为了让你们死心塌地 Maybe to help you believe that, here's a 1302 01:06:00,800 --> 01:06:01,960 我给你们看一个Lisp求值器 here's a LISP evaluator 1303 01:06:02,540 --> 01:06:04,060 它就在我的手掌中 that I'm holding the palm of my hand. 1304 01:06:06,160 --> 01:06:10,560 这块求值器芯片实际上 And this is a chip which is actually 1305 01:06:10,890 --> 01:06:13,700 比我给你们展示的求值器还要复杂 quite a bit more complicated than the evaluator I showed you. 1306 01:06:16,864 --> 01:06:19,200 这张图片效果更好 Uh.. maybe, here's a better picture of it. 1307 01:06:22,070 --> 01:06:22,570 在这上面 What there is, 1308 01:06:22,600 --> 01:06:24,380 你可以看到相同的宏观结构 is you can see the same overall structure. 1309 01:06:24,730 --> 01:06:25,930 这是寄存器阵列 This is a register array. 1310 01:06:26,800 --> 01:06:27,710 这些是数据通路 These are the data paths. 1311 01:06:27,720 --> 01:06:29,070 这里有是有穷状态控制器 Here's a finite state controller. 1312 01:06:29,800 --> 01:06:31,040 再强调一下 是有穷状态 And again, finite state, 1313 01:06:31,960 --> 01:06:32,800 全都在这里了 that's all there is. 1314 01:06:32,810 --> 01:06:34,160 在另外的地方还有外部存储 And somewhere there's external memory 1315 01:06:34,160 --> 01:06:35,230 用来存储数据 that'll worry about things. 1316 01:06:35,750 --> 01:06:37,630 而这块芯片非常复杂 And this particular one is very complicated 1317 01:06:37,640 --> 01:06:39,160 是因为它尝试更快地运行Lisp because it's trying to run LISP fast. 1318 01:06:39,660 --> 01:06:42,970 它具有非常非常之快的并行运算 And it has some very, very fast parallel operations in there 1319 01:06:43,070 --> 01:06:46,320 比如说 如果你想要索引一个数组 like, if you want to index into an array, 1320 01:06:46,700 --> 01:06:50,400 同时又要检查该索引是否为一个整数 simultaneously check that the index is an integer, 1321 01:06:50,430 --> 01:06:52,860 以及该索引没有越界 check that it doesn't exceed the array bands, 1322 01:06:53,040 --> 01:06:55,020 同时还要进行内存存取 and go off and do the memory access, 1323 01:06:55,050 --> 01:06:56,700 它会同时进行这些事 and do all those things simultaneously. 1324 01:06:57,120 --> 01:06:58,400 如果这些操作都没有问题的话 And then, later, if they're all OK, 1325 01:06:58,440 --> 01:06:59,960 最终就会在这里得到结果 actually get the value there. 1326 01:07:00,420 --> 01:07:02,460 因此 数据通路中大量的 So there are a lot of complicated operations 1327 01:07:02,480 --> 01:07:04,650 复杂运算使得Lisp能够并行运行 in these data paths for making LISP run in parallel. 1328 01:07:05,260 --> 01:07:08,416 这完全是求值Lisp的 It's a completely non-risk 1329 01:07:08,768 --> 01:07:10,360 一种无冒险的哲学 philosophy of evaluating LISP. 1330 01:07:10,640 --> 01:07:13,200 并且 这个的微指令也相当复杂 And then, this microcode is pretty complicated. 1331 01:07:13,450 --> 01:07:17,560 让我先看一看 Let's see, there's what? 1332 01:07:17,600 --> 01:07:21,100 这其中有大概389条 There's about 389 instructions of 1333 01:07:21,680 --> 01:07:23,850 220比特的微指令 of 220-bit microcode sitting here 1334 01:07:24,070 --> 01:07:27,940 只因为这些数据通路非常复杂 because these are very complicated data paths. 1335 01:07:27,940 --> 01:07:32,250 整个芯片大概有89,000支晶体管 And the whole thing has about 89,000 transistors, OK? 1336 01:07:33,560 --> 01:07:36,860 好吧 我希望通过这节课解答了大部分疑惑 OK. Well, I hope that that takes away a lot of the mystery. 1337 01:07:37,970 --> 01:07:39,240 也许你们想看一看这块芯片 Maybe somebody wants to look at this. 1338 01:07:46,140 --> 01:07:46,890 好吧 先讲到这里 OK. Let's stop. 1339 01:07:56,460 --> 01:07:56,750 有问题吗? Questions? 1340 01:07:59,000 --> 01:08:00,420 学生:您所讲的 听起来像是 AUDIENCE: OK, now, it sounds like what you're saying is that, 1341 01:08:00,420 --> 01:08:03,480 如果把(RESTORE CONTINUE)放在合适的地方 with the restore continue put in the proper place, 1342 01:08:03,580 --> 01:08:09,420 这样之前递归求值的过程 that procedures that would invoke a recursive process 1343 01:08:09,420 --> 01:08:11,950 现在就会变成迭代求值的 now invoke an iterative process 1344 01:08:12,670 --> 01:08:15,360 (意义不明) just by the way that the eval-sequence source? 1345 01:08:15,600 --> 01:08:17,540 教授:我想我应该这么来说 PROFESSOR: I think the way I'd prefer to put it is that, 1346 01:08:17,540 --> 01:08:19,820 如果把(RESTORE CONTINUE)放在了错误的位置 with restore continue put in the wrong place, 1347 01:08:20,550 --> 01:08:25,480 你就会让那些语法上看起来像递归的过程 you can cause any syntactically-looking recursive procedure, 1348 01:08:25,520 --> 01:08:27,280 在运行的时候不断地扩张栈 in fact, to build up stack as it runs. 1349 01:08:28,640 --> 01:08:30,520 但这样是没有原因的 But there's no reason for that, 1350 01:08:33,150 --> 01:08:35,120 你可以自己去试一试 so you might want to play around with it. 1351 01:08:35,150 --> 01:08:38,090 你可以在COMPOND-APPLY返回后 You can just switch around two or three instructions 1352 01:08:38,180 --> 01:08:40,780 交换两、三条语句的顺序 in the way compound-apply comes back, 1353 01:08:41,310 --> 01:08:43,260 那么你得到的就不再是尾递归了 and you'll get something which isn't tail recursive. 1354 01:08:45,060 --> 01:08:46,140 我只是想强调 But the thing I wanted to emphasize 1355 01:08:46,160 --> 01:08:47,400 这其中没有什么魔法 is there's no magic. there's no 1356 01:08:47,670 --> 01:08:48,570 这并不是 It's not as if 1357 01:08:49,310 --> 01:08:52,170 有什么智能的预处理程序 there's some very clever pre-processing program 1358 01:08:52,650 --> 01:08:55,450 它会分析FACT-ITER这个程序 that's looking at this procedure, factorial iter, 1359 01:08:55,470 --> 01:08:56,730 然后说 and say oh, gee, um 1360 01:08:57,420 --> 01:08:58,860 我注意到 I really notice that 1361 01:08:58,880 --> 01:09:01,130 完成这个调用 不需要我进行压栈 I don't have to push stack in order to do this. 1362 01:09:01,130 --> 01:09:02,880 但是有些人是这么认为的 Some people think that that's what's going on. 1363 01:09:03,760 --> 01:09:05,380 而是一种比这个还要蠢的机制 It's something much, much more dumb than that, 1364 01:09:05,380 --> 01:09:07,500 就是在合适的地方插入RESTORE指令 it's this one place you're putting the restore instruction. 1365 01:09:08,560 --> 01:09:09,790 就可以自动地实现 It's just automatic. 1366 01:09:14,720 --> 01:09:17,550 学生:但这不会影响到时间复杂度 对吧? AUDIENCE: But that's not affecting the time complexity is it? 1367 01:09:17,580 --> 01:09:17,870 教授:不会 PROFESSOR: No. 1368 01:09:18,600 --> 01:09:21,770 学生:它不会迭代地处理 AUDIENCE: It's just that it's handling it recursively 1369 01:09:21,800 --> 01:09:23,020 而是会递归地处理 instead of iteratively. 1370 01:09:23,020 --> 01:09:27,340 但就从完成这两个运算的时间来说 But, in terms of the order of time it takes to finish the operation, 1371 01:09:27,370 --> 01:09:29,220 它们都是相同的 对吧? it's the same one way or the other, right? 1372 01:09:29,470 --> 01:09:29,760 教授 :是的 PROFESSOR: Yes. 1373 01:09:29,790 --> 01:09:32,680 尾递归不会改变任何东西的时间复杂度 Tail recursion is not going to change the time complexity of anything 1374 01:09:32,720 --> 01:09:33,290 因为 从某种意义上来说 because, in some sense, 1375 01:09:33,340 --> 01:09:35,150 两者都是相同的算法 it's the same algorithm that's going on. 1376 01:09:36,020 --> 01:09:39,370 它只是让这个过程迭代地运行 What it's doing is really making this thing run as an iteration. 1377 01:09:41,000 --> 01:09:42,640 这样 当参数很大时 Right? Not going to run out of memory 1378 01:09:42,680 --> 01:09:44,220 它不会耗尽所有的内存 you know counting up to a giant number 1379 01:09:44,750 --> 01:09:46,400 因为这其中没有压栈 simply because the stack would get pushed. 1380 01:09:48,350 --> 01:09:50,240 事实上 你们需要相信 See, the thing you really have to believe is that, 1381 01:09:50,560 --> 01:09:51,130 当我们编写-- when we write-- 1382 01:09:51,640 --> 01:09:53,780 我们一直把这些代码称作“迭代” see, we've been writing all these things called iterations, 1383 01:09:53,930 --> 01:09:57,990 把(DEFINE (LOOP) (LOOP))称作无穷循环 infinite loops, define loop to be called loop. 1384 01:10:00,320 --> 01:10:03,360 这就是一个迭代 That's is as much an iteration 1385 01:10:03,650 --> 01:10:05,660 跟我们用DO语句来写无穷循环是一样的 you know as if we wrote do forever loop. 1386 01:10:07,630 --> 01:10:09,280 它们只是语法上不同而已 It's just syntactic sugar as the difference. 1387 01:10:09,280 --> 01:10:11,320 它们实际上都是迭代 These things are real, honest to god, iterations? 1388 01:10:14,730 --> 01:10:16,080 它们并不改变时间复杂度 They don't change the time complexity, 1389 01:10:16,110 --> 01:10:18,530 但是它会把它们变成真正的迭代 but they turn them into real iterations. 1390 01:10:21,680 --> 01:10:23,800 好吧 下课 All right, thank you. 1391 01:10:23,800 --> 01:10:25,800 MIT OpenCourseWare http://ocw.mit.edu 1392 01:10:25,800 --> 01:10:27,800 本项目主页 https://github.com/DeathKing/Learning-SICP ================================================ FILE: SrtEN/lec10a_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:05,580 1 00:00:05,580 --> 00:00:20,180 [MUSIC PLAYING] 2 00:00:20,180 --> 00:00:23,920 PROFESSOR: Last time, we took a look at an explicit control 3 00:00:23,920 --> 00:00:27,280 evaluator for Lisp, and that bridged the gap between all 4 00:00:27,280 --> 00:00:30,460 these high-level languages like Lisp and the query 5 00:00:30,460 --> 00:00:33,330 language and all of that stuff, bridged the gap between 6 00:00:33,330 --> 00:00:36,640 that and a conventional register machine. 7 00:00:36,640 --> 00:00:40,140 And in fact, you can think of the explicit control evaluator 8 00:00:40,140 --> 00:00:44,650 either as, say, the code for a Lisp interpreter if you wanted 9 00:00:44,650 --> 00:00:47,680 to implement it in the assembly language of some 10 00:00:47,680 --> 00:00:50,120 conventional register transfer machine, or, if you like, you 11 00:00:50,120 --> 00:00:52,770 can think of it as the microcode of some machine 12 00:00:52,770 --> 00:00:55,340 that's going to be specially designed to run Lisp. 13 00:00:55,340 --> 00:00:58,160 In either case, what we're doing is we're taking a 14 00:00:58,160 --> 00:01:01,790 machine that speaks some low-level language, and we're 15 00:01:01,790 --> 00:01:05,250 raising the machine to a high-level language like Lisp 16 00:01:05,250 --> 00:01:08,230 by writing an interpreter. 17 00:01:08,230 --> 00:01:21,160 So for instance, here, conceptually, is a special 18 00:01:21,160 --> 00:01:23,910 purpose machine for computing factorials. 19 00:01:23,910 --> 00:01:29,000 It takes in five and puts out 120. 20 00:01:29,000 --> 00:01:32,060 And what this special purpose machine is is actually a Lisp 21 00:01:32,060 --> 00:01:38,410 interpreter that's configured itself to run factorials, 22 00:01:38,410 --> 00:01:39,880 because you fit into it a description of 23 00:01:39,880 --> 00:01:42,410 the factorial machine. 24 00:01:42,410 --> 00:01:43,610 So that's what an interpreter is. 25 00:01:43,610 --> 00:01:47,320 It configures itself to emulate a machine whose 26 00:01:47,320 --> 00:01:50,120 description you read in. 27 00:01:50,120 --> 00:01:52,110 Now, inside the Lisp interpreter, what's that? 28 00:01:52,110 --> 00:01:54,860 Well, that might be your general register language 29 00:01:54,860 --> 00:01:59,500 interpreter that configures itself to behave like a Lisp 30 00:01:59,500 --> 00:02:01,360 interpreter, because you put in a whole bunch of 31 00:02:01,360 --> 00:02:03,410 instructions in register language. 32 00:02:03,410 --> 00:02:07,070 This is the explicit control evaluator. 33 00:02:07,070 --> 00:02:09,300 And then it also has some sort of library, a library of 34 00:02:09,300 --> 00:02:11,620 primitive operators and Lisp operations and all sorts of 35 00:02:11,620 --> 00:02:12,780 things like that. 36 00:02:12,780 --> 00:02:17,350 That's the general strategy of interpretation. 37 00:02:17,350 --> 00:02:19,420 And the point is, what we're doing is we're writing an 38 00:02:19,420 --> 00:02:24,060 interpreter to raise the machine to the level of the 39 00:02:24,060 --> 00:02:25,430 programs that we want to write. 40 00:02:25,430 --> 00:02:27,850 Well, there's another strategy, a different one, 41 00:02:27,850 --> 00:02:29,030 which is compilation. 42 00:02:29,030 --> 00:02:31,090 Compilation's a little bit different. 43 00:02:31,090 --> 00:02:37,720 Here--here we might have produced a special purpose 44 00:02:37,720 --> 00:02:44,430 machine for, for computing factorials, starting with some 45 00:02:44,430 --> 00:02:46,450 sort of machine that speaks register language, except 46 00:02:46,450 --> 00:02:47,870 we're going to do a different strategy. 47 00:02:47,870 --> 00:02:51,680 We take our factorial program. 48 00:02:51,680 --> 00:02:53,780 We use that as the source code into a compiler. 49 00:02:53,780 --> 00:02:57,090 What the compiler will do is translate that factorial 50 00:02:57,090 --> 00:02:59,926 program into some register machine language. 51 00:02:59,926 --> 00:03:03,110 And this will now be not the explicit control evaluator for 52 00:03:03,110 --> 00:03:04,990 Lisp, this will be some register language for 53 00:03:04,990 --> 00:03:06,760 computing factorials. 54 00:03:06,760 --> 00:03:10,460 So this is the translation of that. 55 00:03:10,460 --> 00:03:14,690 That will go into some sort of loader which will combine this 56 00:03:14,690 --> 00:03:17,520 code with code selected from the library to do things like 57 00:03:17,520 --> 00:03:19,970 primitive multiplication. 58 00:03:19,970 --> 00:03:23,190 And then we'll produce a load module which configures the 59 00:03:23,190 --> 00:03:25,760 register language machine to be a special 60 00:03:25,760 --> 00:03:28,320 purpose factorial machine. 61 00:03:28,320 --> 00:03:29,905 So that's a, that's a different strategy. 62 00:03:29,905 --> 00:03:33,740 In interpretation, we're raising the machine to the 63 00:03:33,740 --> 00:03:35,360 level of our language, like Lisp. 64 00:03:35,360 --> 00:03:38,580 In compilation, we're taking our program and lowering it to 65 00:03:38,580 --> 00:03:42,040 the language that's spoken by the machine. 66 00:03:42,040 --> 00:03:44,280 Well, how do these two strategies compare? 67 00:03:44,280 --> 00:03:48,890 The compiler can produce code that will execute more 68 00:03:48,890 --> 00:03:50,140 efficiently. 69 00:03:50,140 --> 00:03:52,490 70 00:03:52,490 --> 00:03:56,820 The essential reason for that is that if you think about the 71 00:03:56,820 --> 00:04:02,870 register operations that are running, the interpreter has 72 00:04:02,870 --> 00:04:05,880 to produce register operations which, in principle, are going 73 00:04:05,880 --> 00:04:10,260 to be general enough to execute any Lisp procedure. 74 00:04:10,260 --> 00:04:12,680 Whereas the compiler only has to worry about producing a 75 00:04:12,680 --> 00:04:16,029 special bunch of register operations for, for doing the 76 00:04:16,029 --> 00:04:20,209 particular Lisp procedure that you've compiled. 77 00:04:20,209 --> 00:04:23,340 Or another way to say that is that the interpreter is a 78 00:04:23,340 --> 00:04:26,940 general purpose simulator, that when you read in a Lisp 79 00:04:26,940 --> 00:04:29,820 procedure, then those can simulate the program described 80 00:04:29,820 --> 00:04:31,160 by that, by that procedure. 81 00:04:31,160 --> 00:04:33,290 So the interpreter is worrying about making a general purpose 82 00:04:33,290 --> 00:04:36,170 simulator, whereas the compiler, in effect, is 83 00:04:36,170 --> 00:04:37,930 configuring the thing to be the machine that the 84 00:04:37,930 --> 00:04:40,000 interpreter would have been simulating. 85 00:04:40,000 --> 00:04:41,340 So the compiler can be faster. 86 00:04:41,340 --> 00:04:52,830 87 00:04:52,830 --> 00:04:57,100 On the other hand, the interpreter is a nicer 88 00:04:57,100 --> 00:04:59,340 environment for debugging. 89 00:04:59,340 --> 00:05:02,200 And the reason for that is that we've got the source code 90 00:05:02,200 --> 00:05:02,960 actually there. 91 00:05:02,960 --> 00:05:03,740 We're interpreting it. 92 00:05:03,740 --> 00:05:06,010 That's what we're working with. 93 00:05:06,010 --> 00:05:07,880 And we also have the library around. 94 00:05:07,880 --> 00:05:10,150 See, the interpreter--the library sitting there is part 95 00:05:10,150 --> 00:05:11,140 of the interpreter. 96 00:05:11,140 --> 00:05:13,660 The compiler only pulls out from the library what it needs 97 00:05:13,660 --> 00:05:14,830 to run the program. 98 00:05:14,830 --> 00:05:18,710 So if you're in the middle of debugging, and you might like 99 00:05:18,710 --> 00:05:21,730 to write a little extra program to examine some run 100 00:05:21,730 --> 00:05:24,450 time data structure or to produce some computation that 101 00:05:24,450 --> 00:05:25,990 you didn't think of when you wrote the program, the 102 00:05:25,990 --> 00:05:28,390 interpreter can do that perfectly well, whereas the 103 00:05:28,390 --> 00:05:29,670 compiler can't. 104 00:05:29,670 --> 00:05:31,850 So there are sort of dual, dual advantages. 105 00:05:31,850 --> 00:05:34,720 The compiler will produce code that executes faster. 106 00:05:34,720 --> 00:05:39,030 The interpreter is a better environment for debugging. 107 00:05:39,030 --> 00:05:43,520 And most Lisp systems end up having both, end up being 108 00:05:43,520 --> 00:05:45,860 configured so you have an interpreter that you use when 109 00:05:45,860 --> 00:05:46,930 you're developing your code. 110 00:05:46,930 --> 00:05:49,060 Then you can speed it up by compiling. 111 00:05:49,060 --> 00:05:51,720 And very often, you can arrange that compiled code and 112 00:05:51,720 --> 00:05:54,810 interpreted code can call each other. 113 00:05:54,810 --> 00:05:55,700 We'll see how to do that. 114 00:05:55,700 --> 00:05:56,950 That's not hard. 115 00:05:56,950 --> 00:06:01,040 116 00:06:01,040 --> 00:06:02,290 In fact, the way we'll-- 117 00:06:02,290 --> 00:06:04,390 118 00:06:04,390 --> 00:06:06,580 in the compiler we're going to make, the way we'll arrange 119 00:06:06,580 --> 00:06:08,952 for compiled coding and interpreted code to call, to 120 00:06:08,952 --> 00:06:12,220 call each other, is that we'll have the compiler use exactly 121 00:06:12,220 --> 00:06:14,320 the same register conventions as the interpreter. 122 00:06:14,320 --> 00:06:18,680 123 00:06:18,680 --> 00:06:23,900 Well, the idea of a compiler is very much like the idea of 124 00:06:23,900 --> 00:06:25,490 an interpreter or evaluator. 125 00:06:25,490 --> 00:06:27,070 It's the same thing. 126 00:06:27,070 --> 00:06:31,460 See, the evaluator walks over the code and performs some 127 00:06:31,460 --> 00:06:33,840 register operations. 128 00:06:33,840 --> 00:06:37,040 That's what we did yesterday. 129 00:06:37,040 --> 00:06:39,700 Well, the compiler essentially would like to walk over the 130 00:06:39,700 --> 00:06:44,000 code and produce the register operations that the evaluator 131 00:06:44,000 --> 00:06:48,890 would have done were it evaluating the thing. 132 00:06:48,890 --> 00:06:52,000 And that gives us a model for how to implement a 133 00:06:52,000 --> 00:06:57,150 zeroth-order compiler, a very bad compiler but 134 00:06:57,150 --> 00:06:58,330 essentially a compiler. 135 00:06:58,330 --> 00:07:00,900 A model for doing that is you just take the evaluator, you 136 00:07:00,900 --> 00:07:04,970 run it over the code, but instead of executing the 137 00:07:04,970 --> 00:07:07,550 actual operations, you just save them away. 138 00:07:07,550 --> 00:07:08,820 And that's your compiled code. 139 00:07:08,820 --> 00:07:10,140 So let me give you an example of that. 140 00:07:10,140 --> 00:07:15,130 141 00:07:15,130 --> 00:07:15,770 Suppose we're going to compile--suppose we want to 142 00:07:15,770 --> 00:07:18,010 compile the expression f of x. 143 00:07:18,010 --> 00:07:25,100 144 00:07:25,100 --> 00:07:28,175 So let's assume that we've got f of x in the x register and 145 00:07:28,175 --> 00:07:30,170 something in the environment register. 146 00:07:30,170 --> 00:07:31,745 And now imagine starting up the evaluator. 147 00:07:31,745 --> 00:07:34,560 148 00:07:34,560 --> 00:07:36,370 Well, it looks at the expression and it sees that 149 00:07:36,370 --> 00:07:38,000 it's an application. 150 00:07:38,000 --> 00:07:43,730 And it branches to a place in the evaluator code we saw 151 00:07:43,730 --> 00:07:44,980 called ev-application. 152 00:07:44,980 --> 00:07:47,230 153 00:07:47,230 --> 00:07:48,190 And then it begins. 154 00:07:48,190 --> 00:07:50,560 It stores away the operands and unev, and then it's going 155 00:07:50,560 --> 00:07:53,030 to put the operator in exp, and it's going to go 156 00:07:53,030 --> 00:07:54,410 recursively evaluate it. 157 00:07:54,410 --> 00:07:56,385 That's the process that we walk through. 158 00:07:56,385 --> 00:07:58,360 And if you start looking at the code, you start seeing 159 00:07:58,360 --> 00:08:00,200 some register operations. 160 00:08:00,200 --> 00:08:03,370 You see assign to unev the operands, assign to exp the 161 00:08:03,370 --> 00:08:05,520 operator, save the environment, generate 162 00:08:05,520 --> 00:08:06,770 that, and so on. 163 00:08:06,770 --> 00:08:10,310 164 00:08:10,310 --> 00:08:16,220 Well, if we look on the overhead here, we can see, we 165 00:08:16,220 --> 00:08:20,860 can see those operations starting to be produced. 166 00:08:20,860 --> 00:08:24,130 Here's sort of the first real operation that the evaluator 167 00:08:24,130 --> 00:08:24,910 would have done. 168 00:08:24,910 --> 00:08:27,980 It pulls the operands out of the exp register and assigns 169 00:08:27,980 --> 00:08:31,340 it to unev. And then it assigns something to the 170 00:08:31,340 --> 00:08:34,240 expression register, and it saves continue, and it saves 171 00:08:34,240 --> 00:08:34,740 env. 172 00:08:34,740 --> 00:08:38,049 And all I'm doing here is writing down the register 173 00:08:38,049 --> 00:08:41,130 assignments that the evaluator would have done in 174 00:08:41,130 --> 00:08:42,010 executing that code. 175 00:08:42,010 --> 00:08:44,280 And can zoom out a little bit. 176 00:08:44,280 --> 00:08:49,430 Altogether, there are about 19 operations there. 177 00:08:49,430 --> 00:08:52,650 And this is the--this will be the piece of code up until the 178 00:08:52,650 --> 00:08:56,230 point where the evaluator branches off to 179 00:08:56,230 --> 00:08:57,940 apply-dispatch. 180 00:08:57,940 --> 00:09:00,110 And in fact, in this compiler, we're not going to worry about 181 00:09:00,110 --> 00:09:01,450 apply-dispatch at all. 182 00:09:01,450 --> 00:09:02,672 We're going to have everything--we're going to 183 00:09:02,672 --> 00:09:06,160 have both interpreted code and compiled code. 184 00:09:06,160 --> 00:09:08,670 Always evaluate procedures, always apply procedures by 185 00:09:08,670 --> 00:09:10,240 going to apply-dispatch. 186 00:09:10,240 --> 00:09:12,720 That will easily allow interpreted code and compiled 187 00:09:12,720 --> 00:09:13,970 code to call each other. 188 00:09:13,970 --> 00:09:18,330 189 00:09:18,330 --> 00:09:21,220 Well, in principle, that's all we need to do. 190 00:09:21,220 --> 00:09:22,620 You just run the evaluator. 191 00:09:22,620 --> 00:09:24,320 So the compiler's a lot like the evaluator. 192 00:09:24,320 --> 00:09:26,890 You run it, except it stashes away these operations instead 193 00:09:26,890 --> 00:09:29,480 of actually executing them. 194 00:09:29,480 --> 00:09:32,680 Well, that's not, that's not quite true. 195 00:09:32,680 --> 00:09:36,370 There's only one little lie in that. 196 00:09:36,370 --> 00:09:40,480 What you have to worry about is if you have a, a predicate. 197 00:09:40,480 --> 00:09:44,200 If you have some kind of test you want to do, obviously, at 198 00:09:44,200 --> 00:09:47,000 the point when you're compiling it, you don't know 199 00:09:47,000 --> 00:09:49,490 which branch of these--of a conditional like this you're 200 00:09:49,490 --> 00:09:51,400 going to do. 201 00:09:51,400 --> 00:09:55,010 So you can't say which one the evaluator would have done. 202 00:09:55,010 --> 00:09:57,190 So all you do there is very simple. 203 00:09:57,190 --> 00:09:58,985 You compile both branches. 204 00:09:58,985 --> 00:10:02,050 So you compile a structure that looks like this. 205 00:10:02,050 --> 00:10:08,430 That'll compile into something that says, the code, the code 206 00:10:08,430 --> 00:10:18,140 for P. And it puts its results in, say, the val register. 207 00:10:18,140 --> 00:10:21,680 So you walk the interpreter over the predicate and make 208 00:10:21,680 --> 00:10:24,770 sure that the result would go into the val register. 209 00:10:24,770 --> 00:10:30,790 And then you compile an instruction that says, branch 210 00:10:30,790 --> 00:10:38,670 if, if val is true, to a place we'll call label one. 211 00:10:38,670 --> 00:10:44,950 212 00:10:44,950 --> 00:10:49,792 Then we, we will put the code for B to walk the 213 00:10:49,792 --> 00:10:54,040 interpreter--walk the interpreter over B. And then 214 00:10:54,040 --> 00:10:58,070 go to put in an instruction that says, go to the next 215 00:10:58,070 --> 00:11:03,820 thing, whatever, whatever was supposed to happen after this 216 00:11:03,820 --> 00:11:04,920 thing was done. 217 00:11:04,920 --> 00:11:06,900 You put in that instruction. 218 00:11:06,900 --> 00:11:08,280 And here you put label one. 219 00:11:08,280 --> 00:11:11,521 220 00:11:11,521 --> 00:11:19,860 And here you put the code for A. And you 221 00:11:19,860 --> 00:11:25,870 put go to next thing. 222 00:11:25,870 --> 00:11:31,420 223 00:11:31,420 --> 00:11:33,090 So that's how you treat a conditional. 224 00:11:33,090 --> 00:11:35,890 You generate a little block like that. 225 00:11:35,890 --> 00:11:40,550 And other than that, this zeroth-order compiler is the 226 00:11:40,550 --> 00:11:42,310 same as the evaluator. 227 00:11:42,310 --> 00:11:44,380 It's just stashing away the instructions instead of 228 00:11:44,380 --> 00:11:46,380 executing them. 229 00:11:46,380 --> 00:11:48,140 That seems pretty simple, but we've gained 230 00:11:48,140 --> 00:11:50,120 something by that. 231 00:11:50,120 --> 00:11:51,360 See, already that's going to be more 232 00:11:51,360 --> 00:11:53,630 efficient than the evaluator. 233 00:11:53,630 --> 00:11:58,030 Because, if you watch the evaluator run, it's not only 234 00:11:58,030 --> 00:12:01,410 generating the register operations we wrote down, it's 235 00:12:01,410 --> 00:12:04,740 also doing things to decide which ones to generate. 236 00:12:04,740 --> 00:12:08,480 So the very first thing it does, say, here for instance, 237 00:12:08,480 --> 00:12:13,470 is go do some tests and decide that this is an application, 238 00:12:13,470 --> 00:12:15,930 and then branch off to the place that, that handles 239 00:12:15,930 --> 00:12:16,780 applications. 240 00:12:16,780 --> 00:12:18,870 In other words, what the evaluator's doing is 241 00:12:18,870 --> 00:12:23,720 simultaneously analyzing the code to see what to do, and 242 00:12:23,720 --> 00:12:25,580 running these operations. 243 00:12:25,580 --> 00:12:25,960 And when you-- 244 00:12:25,960 --> 00:12:28,960 if you run the evaluator a million times, that analysis 245 00:12:28,960 --> 00:12:31,870 phase happens a million times, whereas in the compiler, it's 246 00:12:31,870 --> 00:12:33,650 happened once, and then you just have the register 247 00:12:33,650 --> 00:12:34,900 operations themselves. 248 00:12:34,900 --> 00:12:39,730 249 00:12:39,730 --> 00:12:42,310 Ok, that's a, a zeroth-order compiler, but it is a 250 00:12:42,310 --> 00:12:44,550 wretched, wretched compiler. 251 00:12:44,550 --> 00:12:47,200 It's really dumb. 252 00:12:47,200 --> 00:12:52,040 Let's--let's go back and, and look at this overhead. 253 00:12:52,040 --> 00:12:54,170 So look at look at some of the operations 254 00:12:54,170 --> 00:12:56,020 this thing is doing. 255 00:12:56,020 --> 00:13:01,030 We're supposedly looking at the operations and 256 00:13:01,030 --> 00:13:03,710 interpreting f of x. 257 00:13:03,710 --> 00:13:05,220 Now, look here what it's doing. 258 00:13:05,220 --> 00:13:10,360 For example, here it assigns to exp the 259 00:13:10,360 --> 00:13:13,850 operator in fetch of exp. 260 00:13:13,850 --> 00:13:16,290 But see, there's no reason to do that, because this is-- 261 00:13:16,290 --> 00:13:21,290 the compiler knows that the operator, fetch of exp, is f 262 00:13:21,290 --> 00:13:23,310 right here. 263 00:13:23,310 --> 00:13:25,850 So there's no reason why this instruction should say that. 264 00:13:25,850 --> 00:13:29,580 It should say, we'll assign to exp, f. 265 00:13:29,580 --> 00:13:32,000 Or in fact, you don't need exp at all. 266 00:13:32,000 --> 00:13:33,670 There's no reason it should have exp at all. 267 00:13:33,670 --> 00:13:35,170 What, what did exp get used for? 268 00:13:35,170 --> 00:13:43,190 Well, if we come down here, we're going to assign to val, 269 00:13:43,190 --> 00:13:48,620 look up the stuff in exp in the environment. 270 00:13:48,620 --> 00:13:50,800 So what we really should do is get rid of the exp register 271 00:13:50,800 --> 00:13:53,290 altogether, and just change this instruction to say, 272 00:13:53,290 --> 00:13:57,600 assign to val, look up the variable value of the symbol f 273 00:13:57,600 --> 00:13:58,850 in the environment. 274 00:13:58,850 --> 00:14:01,100 275 00:14:01,100 --> 00:14:04,800 Similarly, back up here, we don't need unev at all, 276 00:14:04,800 --> 00:14:08,260 because we know what the operands of fetch of exp are 277 00:14:08,260 --> 00:14:09,150 for this piece of code. 278 00:14:09,150 --> 00:14:10,630 It's the, it's the list x. 279 00:14:10,630 --> 00:14:13,270 280 00:14:13,270 --> 00:14:19,660 So in some sense, you don't want unev and exp at all. 281 00:14:19,660 --> 00:14:22,690 See, what they really are in some sense, those aren't 282 00:14:22,690 --> 00:14:24,330 registers of the actual machine 283 00:14:24,330 --> 00:14:25,230 that's supposed to run. 284 00:14:25,230 --> 00:14:28,180 Those are registers that have to do with arranging the thing 285 00:14:28,180 --> 00:14:30,760 that can simulate that machine. 286 00:14:30,760 --> 00:14:34,890 So they're always going to hold expressions which, from 287 00:14:34,890 --> 00:14:37,330 the compiler's point of view, are just constants, so can be 288 00:14:37,330 --> 00:14:39,510 put right into the code. 289 00:14:39,510 --> 00:14:41,850 So you can forget about all the operations worrying about 290 00:14:41,850 --> 00:14:44,000 exp and unev and just use those constants. 291 00:14:44,000 --> 00:14:48,200 Similarly, again, if we go, go back and look here, there are 292 00:14:48,200 --> 00:14:50,510 things like assign to continue eval-args. 293 00:14:50,510 --> 00:14:53,890 294 00:14:53,890 --> 00:14:55,440 Now, that has nothing to do with anything. 295 00:14:55,440 --> 00:14:59,280 That was just the evaluator keeping track of where it 296 00:14:59,280 --> 00:15:05,150 should go next, to evaluate the arguments in some, in some 297 00:15:05,150 --> 00:15:06,920 application. 298 00:15:06,920 --> 00:15:08,690 But of course, that's irrelevant to the compiler, 299 00:15:08,690 --> 00:15:09,940 because you-- 300 00:15:09,940 --> 00:15:11,470 301 00:15:11,470 --> 00:15:15,220 the analysis phase will have already done that. 302 00:15:15,220 --> 00:15:17,680 So this is completely irrelevant. 303 00:15:17,680 --> 00:15:20,170 So a lot of these, these assignments to continue have 304 00:15:20,170 --> 00:15:24,070 not to do where the running machine is supposed to 305 00:15:24,070 --> 00:15:26,120 continue in keeping track of its state. 306 00:15:26,120 --> 00:15:28,380 It has to, to do with where the evaluator analysis should 307 00:15:28,380 --> 00:15:30,080 continue, and those are completely irrelevant. 308 00:15:30,080 --> 00:15:31,330 So we can get rid of them. 309 00:15:31,330 --> 00:15:44,330 310 00:15:44,330 --> 00:15:46,990 Ok, well, if we, if we simply do that, make those kinds of 311 00:15:46,990 --> 00:15:51,380 optimizations, get rid, get rid of worrying about exp and 312 00:15:51,380 --> 00:15:55,030 unev, and get rid of these irrelevant register 313 00:15:55,030 --> 00:16:01,400 assignments to continue, then we can take this literal code, 314 00:16:01,400 --> 00:16:05,370 these sort of 19 instructions that the, that the evaluator 315 00:16:05,370 --> 00:16:08,540 would have done, and then replace them. 316 00:16:08,540 --> 00:16:09,865 Let's look at the, at the slide. 317 00:16:09,865 --> 00:16:13,490 318 00:16:13,490 --> 00:16:15,180 Replace them by--we get rid of about half of them. 319 00:16:15,180 --> 00:16:18,370 320 00:16:18,370 --> 00:16:21,470 And again, this is just sort of filtering what the 321 00:16:21,470 --> 00:16:23,410 evaluator would have done by getting rid of 322 00:16:23,410 --> 00:16:25,200 the irrelevant stuff. 323 00:16:25,200 --> 00:16:29,450 And you see, for instance, here the--where the evaluator 324 00:16:29,450 --> 00:16:32,570 said, assign val, look up variable value, fetch of exp, 325 00:16:32,570 --> 00:16:35,470 here we have put in the constant f. 326 00:16:35,470 --> 00:16:37,020 Here we've put in the constant x. 327 00:16:37,020 --> 00:16:39,770 328 00:16:39,770 --> 00:16:43,860 So there's a, there's a little better compiler. 329 00:16:43,860 --> 00:16:47,930 It's still pretty dumb. 330 00:16:47,930 --> 00:16:50,560 It's still doing a lot of dumb things. 331 00:16:50,560 --> 00:16:53,290 Again, if we go look at the slide again, look at the very 332 00:16:53,290 --> 00:17:00,150 beginning here, we see a save the environment, assign 333 00:17:00,150 --> 00:17:03,430 something to the val register, and restore the environment. 334 00:17:03,430 --> 00:17:05,030 Where'd that come from? 335 00:17:05,030 --> 00:17:08,200 That came from the evaluator back here saying, oh, I'm in 336 00:17:08,200 --> 00:17:11,160 the middle of evaluating an application. 337 00:17:11,160 --> 00:17:15,940 So I'm going to recursively call eval dispatch. 338 00:17:15,940 --> 00:17:18,170 So I'd better save the thing I'm going to need later, which 339 00:17:18,170 --> 00:17:19,849 is the environment. 340 00:17:19,849 --> 00:17:21,609 This was the result of recursively 341 00:17:21,609 --> 00:17:23,520 calling eval dispatch. 342 00:17:23,520 --> 00:17:26,540 It was evaluating the symbol f in that case. 343 00:17:26,540 --> 00:17:28,900 Then it came back from eval dispatch, restored the 344 00:17:28,900 --> 00:17:31,380 environment. 345 00:17:31,380 --> 00:17:35,290 But in fact, the actual thing it ended up doing in the 346 00:17:35,290 --> 00:17:38,740 evaluation is not going to hurt the environment at all. 347 00:17:38,740 --> 00:17:40,890 So there's no reason to be saving the environment and 348 00:17:40,890 --> 00:17:42,170 restoring the environment here. 349 00:17:42,170 --> 00:17:46,020 350 00:17:46,020 --> 00:17:53,690 Similarly, here I'm saving the argument list. That's a piece 351 00:17:53,690 --> 00:17:56,560 of the argument evaluation loop, saving the argument 352 00:17:56,560 --> 00:17:58,090 list, and here you restore it. 353 00:17:58,090 --> 00:18:01,510 But the actual thing that you ended up doing didn't trash 354 00:18:01,510 --> 00:18:04,090 the argument list. So there was no reason to save it. 355 00:18:04,090 --> 00:18:08,690 356 00:18:08,690 --> 00:18:14,415 So another way to say, another way to say that is that the, 357 00:18:14,415 --> 00:18:19,923 the evaluator has to be maximally pessimistic, because 358 00:18:19,923 --> 00:18:22,050 as far from its point of view it's just going off to 359 00:18:22,050 --> 00:18:23,180 evaluate something. 360 00:18:23,180 --> 00:18:26,200 So it better save what it's going to need later. 361 00:18:26,200 --> 00:18:28,700 But once you've done the analysis, the compiler is in a 362 00:18:28,700 --> 00:18:32,140 position to say, well, what actually did I need to save? 363 00:18:32,140 --> 00:18:35,410 And doesn't need to do any-- it doesn't need to be as 364 00:18:35,410 --> 00:18:38,060 careful as the evaluator, because it knows what it 365 00:18:38,060 --> 00:18:39,950 actually needs. 366 00:18:39,950 --> 00:18:44,240 Well, in any case, if we do that and eliminate all those 367 00:18:44,240 --> 00:18:48,110 redundant saves and restores, then we can 368 00:18:48,110 --> 00:18:49,400 get it down to this. 369 00:18:49,400 --> 00:18:52,810 And you see there are actually only three instructions that 370 00:18:52,810 --> 00:18:56,230 we actually need, down from the initial 11 or so, or the 371 00:18:56,230 --> 00:19:00,070 initial 20 or so in the original one. 372 00:19:00,070 --> 00:19:03,260 And that's just saying, of those register operations, 373 00:19:03,260 --> 00:19:04,870 which ones did we actually need? 374 00:19:04,870 --> 00:19:09,490 375 00:19:09,490 --> 00:19:11,950 Let me just sort of summarize that in another way, just to 376 00:19:11,950 --> 00:19:13,450 show you in a little better picture. 377 00:19:13,450 --> 00:19:16,010 378 00:19:16,010 --> 00:19:18,690 Here's a picture of starting-- 379 00:19:18,690 --> 00:19:20,530 This is looking at all the saves and restores. 380 00:19:20,530 --> 00:19:23,770 381 00:19:23,770 --> 00:19:26,300 So here's the expression, f of x, and then this traces 382 00:19:26,300 --> 00:19:30,940 through, on the bottom here, the various places in the 383 00:19:30,940 --> 00:19:38,160 evaluator that were passed when the evaluation happened. 384 00:19:38,160 --> 00:19:40,250 And then here, here you see arrows. 385 00:19:40,250 --> 00:19:42,320 Arrow down means register saved. 386 00:19:42,320 --> 00:19:43,690 So the first thing that happened is the 387 00:19:43,690 --> 00:19:46,860 environment got saved. 388 00:19:46,860 --> 00:19:48,305 And over here, the environment got restored. 389 00:19:48,305 --> 00:19:52,380 390 00:19:52,380 --> 00:19:56,220 And these-- so there are all the pairs of stack operations. 391 00:19:56,220 --> 00:19:59,462 Now, if you go ahead and say, well, let's remember that we 392 00:19:59,462 --> 00:20:02,070 don't--that unev, for instance, is a completely 393 00:20:02,070 --> 00:20:03,320 useless register. 394 00:20:03,320 --> 00:20:07,550 395 00:20:07,550 --> 00:20:09,820 And if we use the constant structure of the code, well, 396 00:20:09,820 --> 00:20:11,770 we don't need, we don't need to save unev. We don't need 397 00:20:11,770 --> 00:20:13,020 unev at all. 398 00:20:13,020 --> 00:20:16,220 399 00:20:16,220 --> 00:20:18,790 And then, depending on how we set up the discipline of 400 00:20:18,790 --> 00:20:22,610 the--of calling other things that apply, we may or may not 401 00:20:22,610 --> 00:20:23,860 need to save continue. 402 00:20:23,860 --> 00:20:27,360 403 00:20:27,360 --> 00:20:28,800 That's the first step I did. 404 00:20:28,800 --> 00:20:30,116 And then we can look and see what's actually, what's 405 00:20:30,116 --> 00:20:32,960 actually needed. 406 00:20:32,960 --> 00:20:36,300 See, we don't-- didn't really need to save env or 407 00:20:36,300 --> 00:20:38,536 cross-evaluating f, because it wouldn't, it 408 00:20:38,536 --> 00:20:40,040 wouldn't trash it. 409 00:20:40,040 --> 00:20:46,720 So if we take advantage of that, and see the evaluation 410 00:20:46,720 --> 00:20:52,280 of f here, doesn't really need to worry about, about hurting 411 00:20:52,280 --> 00:20:57,560 env. And similarly, the evaluation of x here, when the 412 00:20:57,560 --> 00:21:00,140 evaluator did that it said, oh, I'd better preserve the 413 00:21:00,140 --> 00:21:03,320 function register around that, because I might need it later. 414 00:21:03,320 --> 00:21:07,140 And I better preserve the argument list. 415 00:21:07,140 --> 00:21:09,280 Whereas the compiler is now in a position to know, well, we 416 00:21:09,280 --> 00:21:10,690 didn't really need to save-- to do 417 00:21:10,690 --> 00:21:12,730 those saves and restores. 418 00:21:12,730 --> 00:21:15,520 So in fact, all of the stack operations done by the 419 00:21:15,520 --> 00:21:18,900 evaluator turned out to be unnecessary or overly 420 00:21:18,900 --> 00:21:19,670 pessimistic. 421 00:21:19,670 --> 00:21:21,390 And the compiler is in a position to know that. 422 00:21:21,390 --> 00:21:27,470 423 00:21:27,470 --> 00:21:29,980 Well that's the basic idea. 424 00:21:29,980 --> 00:21:32,600 We take the evaluator, we eliminate the things that you 425 00:21:32,600 --> 00:21:34,450 don't need, that in some sense have nothing to do with the 426 00:21:34,450 --> 00:21:38,480 compiler at all, just the evaluator, and then you see 427 00:21:38,480 --> 00:21:40,460 which stack operations are unnecessary. 428 00:21:40,460 --> 00:21:44,490 That's the basic structure of the compiler that's described 429 00:21:44,490 --> 00:21:45,130 in the book. 430 00:21:45,130 --> 00:21:48,620 Let me just show you how that examples a 431 00:21:48,620 --> 00:21:51,280 little bit too simple. 432 00:21:51,280 --> 00:21:53,500 To see how you, how you actually save a lot, let's 433 00:21:53,500 --> 00:21:55,765 look at a little bit more complicated expression. 434 00:21:55,765 --> 00:21:58,330 435 00:21:58,330 --> 00:22:03,542 F of G of X and 1. 436 00:22:03,542 --> 00:22:06,410 And I'm not going to go through all the code. 437 00:22:06,410 --> 00:22:09,830 There's a, there's a fair pile of it. 438 00:22:09,830 --> 00:22:13,410 I think there are, there are something like 16 pairs of 439 00:22:13,410 --> 00:22:15,440 register saves and restores as the evaluator 440 00:22:15,440 --> 00:22:17,270 walks through that. 441 00:22:17,270 --> 00:22:20,680 Here's a diagram of them. 442 00:22:20,680 --> 00:22:21,060 Let's see. 443 00:22:21,060 --> 00:22:24,210 You see what's going on. 444 00:22:24,210 --> 00:22:25,530 You start out by--the evaluator says, oh, I'm about 445 00:22:25,530 --> 00:22:26,480 to do an application. 446 00:22:26,480 --> 00:22:28,010 I'll preserve the environment. 447 00:22:28,010 --> 00:22:30,261 I'll restore it here. 448 00:22:30,261 --> 00:22:33,900 Then I'm about to do the first operand. 449 00:22:33,900 --> 00:22:36,790 450 00:22:36,790 --> 00:22:38,970 Here it recursively goes to the evaluator. 451 00:22:38,970 --> 00:22:41,370 The evaluator says, oh, this is an application, I'll save 452 00:22:41,370 --> 00:22:44,090 the environment, do the operator of that combination, 453 00:22:44,090 --> 00:22:46,740 restore it here. 454 00:22:46,740 --> 00:22:51,720 This save--this restore matches that save. And so on. 455 00:22:51,720 --> 00:22:53,740 There's unev here, which turns out to be completely 456 00:22:53,740 --> 00:22:57,240 unnecessary, continues getting bumped around here. 457 00:22:57,240 --> 00:23:01,040 The function register is getting, getting saved across 458 00:23:01,040 --> 00:23:05,330 the first operands, across the operands. 459 00:23:05,330 --> 00:23:06,680 All sorts of things are going on. 460 00:23:06,680 --> 00:23:09,090 But if you say, well, what of those really were the business 461 00:23:09,090 --> 00:23:12,770 of the compiler as opposed to the evaluator, you get rid of 462 00:23:12,770 --> 00:23:14,320 a whole bunch. 463 00:23:14,320 --> 00:23:19,500 And then on top of that, if you say things like, the 464 00:23:19,500 --> 00:23:24,520 evaluation of F doesn't hurt the environment register, or 465 00:23:24,520 --> 00:23:30,500 simply looking up the symbol X, you don't have to protect 466 00:23:30,500 --> 00:23:34,570 the function register against that. 467 00:23:34,570 --> 00:23:36,044 So you come down to just a couple of, a 468 00:23:36,044 --> 00:23:37,530 couple of pairs here. 469 00:23:37,530 --> 00:23:40,280 470 00:23:40,280 --> 00:23:42,160 And still, you can do a little better. 471 00:23:42,160 --> 00:23:44,962 Look what's going on here with the environment register. 472 00:23:44,962 --> 00:23:51,350 The environment register comes along and says, oh, here's a 473 00:23:51,350 --> 00:23:52,600 combination. 474 00:23:52,600 --> 00:23:54,280 475 00:23:54,280 --> 00:23:58,580 This evaluator, by the way, doesn't know anything about G. 476 00:23:58,580 --> 00:24:02,330 So here it says, so it says, I'd better save the 477 00:24:02,330 --> 00:24:05,610 environment register, because evaluating G might be some 478 00:24:05,610 --> 00:24:07,960 arbitrary piece of code that would trash it, and I'm going 479 00:24:07,960 --> 00:24:12,360 to need it later, after this argument, for 480 00:24:12,360 --> 00:24:15,540 doing the second argument. 481 00:24:15,540 --> 00:24:20,580 So that's why this one didn't go away, because the compiler 482 00:24:20,580 --> 00:24:22,550 made no assumptions about what G would do. 483 00:24:22,550 --> 00:24:26,170 On the other hand, if you look at what the second argument 484 00:24:26,170 --> 00:24:27,710 is, that's just looking up one. 485 00:24:27,710 --> 00:24:30,810 That doesn't need this environment register. 486 00:24:30,810 --> 00:24:32,070 So there's no reason to save it. 487 00:24:32,070 --> 00:24:35,020 So in fact, you can get rid of that one, too. 488 00:24:35,020 --> 00:24:38,290 And from this whole pile of, of register operations, if you 489 00:24:38,290 --> 00:24:40,840 simply do a little bit of reasoning like that, you get 490 00:24:40,840 --> 00:24:45,170 down to, I think, just two pairs of saves and restores. 491 00:24:45,170 --> 00:24:47,870 And those, in fact, could go away further if you, if you 492 00:24:47,870 --> 00:24:56,650 knew something about G. 493 00:24:56,650 --> 00:24:59,250 So again, the general idea is that the reason the compiler 494 00:24:59,250 --> 00:25:01,430 can be better is that the interpreter doesn't know what 495 00:25:01,430 --> 00:25:03,310 it's about to encounter. 496 00:25:03,310 --> 00:25:05,740 It has to be maximally pessimistic in saving things 497 00:25:05,740 --> 00:25:07,750 to protect itself. 498 00:25:07,750 --> 00:25:10,820 The compiler only has to deal with what 499 00:25:10,820 --> 00:25:13,410 actually had to be saved. 500 00:25:13,410 --> 00:25:15,620 And there are two reasons that something might 501 00:25:15,620 --> 00:25:17,920 not have to be saved. 502 00:25:17,920 --> 00:25:20,100 One is that what you're protecting it against, in 503 00:25:20,100 --> 00:25:22,700 fact, didn't trash the register, like it was just a 504 00:25:22,700 --> 00:25:24,210 variable look-up. 505 00:25:24,210 --> 00:25:26,730 And the other one is, that the thing that you were saving it 506 00:25:26,730 --> 00:25:30,800 for might turn out not to actually need it. 507 00:25:30,800 --> 00:25:34,370 So those are the two basic pieces of knowledge that the 508 00:25:34,370 --> 00:25:37,010 compiler can take advantage of in making 509 00:25:37,010 --> 00:25:38,260 the code more efficient. 510 00:25:38,260 --> 00:25:44,570 511 00:25:44,570 --> 00:25:45,820 Let's break for questions. 512 00:25:45,820 --> 00:25:51,280 513 00:25:51,280 --> 00:25:54,410 AUDIENCE: You kept saying that the uneval register, unev 514 00:25:54,410 --> 00:25:56,350 register didn't need to be used at all. 515 00:25:56,350 --> 00:25:57,660 Does that mean that you could just map a 516 00:25:57,660 --> 00:25:58,590 six-register machine? 517 00:25:58,590 --> 00:26:00,220 Or is that, in this particular example, it 518 00:26:00,220 --> 00:26:01,860 didn't need to be used? 519 00:26:01,860 --> 00:26:05,480 PROFESSOR: For the compiler, you could generate code for 520 00:26:05,480 --> 00:26:07,580 the six-register, five, right? 521 00:26:07,580 --> 00:26:08,930 Because that exp goes away also. 522 00:26:08,930 --> 00:26:11,750 523 00:26:11,750 --> 00:26:14,700 Assuming--yeah, you can get rid of both exp and unev, 524 00:26:14,700 --> 00:26:17,380 because, see, those are data structures of the evaluator. 525 00:26:17,380 --> 00:26:19,600 Those are all things that would be constants from the 526 00:26:19,600 --> 00:26:21,410 point of view of the compiler. 527 00:26:21,410 --> 00:26:24,730 The only thing is this particular compiler is set up 528 00:26:24,730 --> 00:26:29,330 so that interpreted code and compiled code can coexist. 529 00:26:29,330 --> 00:26:34,330 So the way to think about it is, is maybe you build a chip 530 00:26:34,330 --> 00:26:37,420 which is the evaluator, and what the compiler might do is 531 00:26:37,420 --> 00:26:39,920 generate code for that chip. 532 00:26:39,920 --> 00:26:41,550 It just wouldn't use two of the registers. 533 00:26:41,550 --> 00:26:51,158 534 00:26:51,158 --> 00:26:53,326 All right, let's take a break. 535 00:26:53,326 --> 00:27:28,576 [MUSIC PLAYING] 536 00:27:28,576 --> 00:27:32,900 We just looked at what the compiler is supposed to do. 537 00:27:32,900 --> 00:27:36,700 Now let's very briefly look at how, how this gets 538 00:27:36,700 --> 00:27:38,120 accomplished. 539 00:27:38,120 --> 00:27:39,600 And I'm going to give no details. 540 00:27:39,600 --> 00:27:42,580 There's, there's a giant pile of code in the book that gives 541 00:27:42,580 --> 00:27:43,440 all the details. 542 00:27:43,440 --> 00:27:46,150 But what I want to do is just show you the, the 543 00:27:46,150 --> 00:27:49,590 essential idea here. 544 00:27:49,590 --> 00:27:51,450 Worry about the details some other time. 545 00:27:51,450 --> 00:27:55,420 Let's imagine that we're compiling an expression that 546 00:27:55,420 --> 00:27:57,650 looks like there's some operator, and 547 00:27:57,650 --> 00:27:58,900 there are two arguments. 548 00:27:58,900 --> 00:28:03,660 549 00:28:03,660 --> 00:28:06,310 Now, the-- 550 00:28:06,310 --> 00:28:08,940 what's the code that the compiler should generate? 551 00:28:08,940 --> 00:28:12,630 Well, first of all, it should recursively go off and compile 552 00:28:12,630 --> 00:28:14,192 the operator. 553 00:28:14,192 --> 00:28:18,650 So it says, I'll compile the operator. 554 00:28:18,650 --> 00:28:21,250 555 00:28:21,250 --> 00:28:26,600 And where I'm going to need that is to be in the function 556 00:28:26,600 --> 00:28:28,400 register, eventually. 557 00:28:28,400 --> 00:28:30,830 So I'll compile some instructions that will compile 558 00:28:30,830 --> 00:28:37,640 the operator and end up with the result in 559 00:28:37,640 --> 00:28:38,890 the function register. 560 00:28:38,890 --> 00:28:45,420 561 00:28:45,420 --> 00:28:49,770 The next thing it's going to do, another piece is to say, 562 00:28:49,770 --> 00:28:55,140 well, I have to compile the first argument. 563 00:28:55,140 --> 00:28:58,100 So it calls itself recursively. 564 00:28:58,100 --> 00:29:03,010 And let's say the result will go into val. 565 00:29:03,010 --> 00:29:09,150 566 00:29:09,150 --> 00:29:11,460 And then what it's going to need to do is start setting up 567 00:29:11,460 --> 00:29:25,060 the argument list. So it'll say, assign to argl cons of 568 00:29:25,060 --> 00:29:27,160 fetch-- so it generates this literal instruction-- 569 00:29:27,160 --> 00:29:35,430 fetch of val onto empty list. 570 00:29:35,430 --> 00:29:36,680 However, it might have to work-- 571 00:29:36,680 --> 00:29:39,590 572 00:29:39,590 --> 00:29:43,950 when it gets here, it's going to need the environment. 573 00:29:43,950 --> 00:29:45,650 It's going to need whatever environment was here in order 574 00:29:45,650 --> 00:29:49,030 to do this evaluation of the first argument. 575 00:29:49,030 --> 00:29:54,990 So it has to ensure that the compilation of this operand, 576 00:29:54,990 --> 00:29:58,610 or it has to protect the function register against 577 00:29:58,610 --> 00:30:01,220 whatever might happen in the compilation of this operand. 578 00:30:01,220 --> 00:30:04,820 So it puts a note here and says, oh, this piece should be 579 00:30:04,820 --> 00:30:12,650 done preserving the environment register. 580 00:30:12,650 --> 00:30:17,350 581 00:30:17,350 --> 00:30:22,630 Similarly, here, after it gets done compiling the first 582 00:30:22,630 --> 00:30:25,110 operand, it's going to say, I better compile-- 583 00:30:25,110 --> 00:30:26,740 I'm going to need to know the environment 584 00:30:26,740 --> 00:30:27,930 for the second operand. 585 00:30:27,930 --> 00:30:30,870 So it puts a little note here, saying, yeah, this is also 586 00:30:30,870 --> 00:30:41,510 done preserving env. Now it goes on and says, well, the 587 00:30:41,510 --> 00:30:48,880 next chunk of code is the one that's going to compile the 588 00:30:48,880 --> 00:30:50,760 second argument. 589 00:30:50,760 --> 00:30:57,840 And let's say it'll compile it with a targeted to 590 00:30:57,840 --> 00:30:59,360 val, as they say. 591 00:30:59,360 --> 00:31:03,940 592 00:31:03,940 --> 00:31:08,360 And then it'll generate the literal instruction, building 593 00:31:08,360 --> 00:31:20,860 up the argument list. So it'll say, assign to argl cons of 594 00:31:20,860 --> 00:31:34,060 the new value it just got onto the old argument list. 595 00:31:34,060 --> 00:31:37,610 However, in order to have the old argument list, it better 596 00:31:37,610 --> 00:31:40,440 have arranged that the argument list didn't get 597 00:31:40,440 --> 00:31:43,510 trashed by whatever happened in here. 598 00:31:43,510 --> 00:31:46,200 So it puts a little note here and says, oh, this has to be 599 00:31:46,200 --> 00:31:51,400 done preserving argl. 600 00:31:51,400 --> 00:31:54,380 601 00:31:54,380 --> 00:31:58,090 Now it's got the argument list set up. 602 00:31:58,090 --> 00:32:02,520 And it's all ready to go to apply dispatch. 603 00:32:02,520 --> 00:32:06,450 604 00:32:06,450 --> 00:32:10,440 It generates this literal instruction. 605 00:32:10,440 --> 00:32:14,990 606 00:32:14,990 --> 00:32:19,310 Because now it's got the arguments in argl and the 607 00:32:19,310 --> 00:32:22,360 operator in fun, but wait, it's only got the operator in 608 00:32:22,360 --> 00:32:27,520 fun if it had ensured that this block of code didn't 609 00:32:27,520 --> 00:32:29,600 trash what was in the function register. 610 00:32:29,600 --> 00:32:32,090 So it puts a little note here and says, oh, yes, all this 611 00:32:32,090 --> 00:32:39,460 stuff here had better be done preserving 612 00:32:39,460 --> 00:32:40,710 the function register. 613 00:32:40,710 --> 00:32:46,110 614 00:32:46,110 --> 00:32:46,210 So that's the little--so when it starts ticking--so 615 00:32:46,210 --> 00:32:51,510 basically, what the compiler does is append a whole bunch 616 00:32:51,510 --> 00:32:53,432 of code sequences. 617 00:32:53,432 --> 00:32:58,580 See, what it's got in it is little primitive pieces of 618 00:32:58,580 --> 00:33:01,940 things, like how to look up a symbol, how to do a 619 00:33:01,940 --> 00:33:02,560 conditional. 620 00:33:02,560 --> 00:33:05,530 Those are all little pieces of things. 621 00:33:05,530 --> 00:33:07,340 And then it appends them together in this sort of 622 00:33:07,340 --> 00:33:08,810 discipline. 623 00:33:08,810 --> 00:33:11,890 So the basic means of combining things is to append 624 00:33:11,890 --> 00:33:13,140 two code sequences. 625 00:33:13,140 --> 00:33:21,610 626 00:33:21,610 --> 00:33:22,860 That's what's going on here. 627 00:33:22,860 --> 00:33:25,690 628 00:33:25,690 --> 00:33:27,590 And it's a little bit tricky. 629 00:33:27,590 --> 00:33:32,020 The idea is that it appends two code sequences, taking 630 00:33:32,020 --> 00:33:35,670 care to preserve a register. 631 00:33:35,670 --> 00:33:39,250 So the actual append operation looks like this. 632 00:33:39,250 --> 00:33:41,230 What it wants to do is say, if-- 633 00:33:41,230 --> 00:33:44,450 here's what it means to append two code sequences. 634 00:33:44,450 --> 00:33:53,685 So if sequence one needs register-- 635 00:33:53,685 --> 00:33:54,720 I should change this. 636 00:33:54,720 --> 00:33:57,200 Append sequence one to sequence two, 637 00:33:57,200 --> 00:34:03,815 preserving some register. 638 00:34:03,815 --> 00:34:08,370 639 00:34:08,370 --> 00:34:11,080 Let me say, and. 640 00:34:11,080 --> 00:34:13,719 So it's clear that sequence one comes first. 641 00:34:13,719 --> 00:34:26,449 So if sequence two needs the register and sequence one 642 00:34:26,449 --> 00:34:35,230 modifies the register, then the instructions that the 643 00:34:35,230 --> 00:34:43,380 compiler spits out are, save the register. 644 00:34:43,380 --> 00:34:44,440 Here's the code. 645 00:34:44,440 --> 00:34:45,280 You generate this code. 646 00:34:45,280 --> 00:34:50,860 Save the register, and then you put out the recursively 647 00:34:50,860 --> 00:34:53,389 compiled stuff for sequence one. 648 00:34:53,389 --> 00:34:54,639 And then you restore the register. 649 00:34:54,639 --> 00:35:00,440 650 00:35:00,440 --> 00:35:04,610 And then you put out the recursively compiled stuff for 651 00:35:04,610 --> 00:35:07,330 sequence two. 652 00:35:07,330 --> 00:35:09,610 That's in the case where you need to do it. 653 00:35:09,610 --> 00:35:12,700 Sequence two actually needs the register, and sequence one 654 00:35:12,700 --> 00:35:15,430 actually clobbers it. 655 00:35:15,430 --> 00:35:16,320 So that's sort of if. 656 00:35:16,320 --> 00:35:25,820 Otherwise, all you spit out is sequence one followed by 657 00:35:25,820 --> 00:35:28,240 sequence two. 658 00:35:28,240 --> 00:35:31,720 So that's the basic operation for sticking together these 659 00:35:31,720 --> 00:35:34,490 bits of code fragments, these bits of 660 00:35:34,490 --> 00:35:36,960 instructions into a sequence. 661 00:35:36,960 --> 00:35:42,840 And you see, from this point of view, the difference 662 00:35:42,840 --> 00:35:46,840 between the interpreter and the compiler, in some sense, 663 00:35:46,840 --> 00:35:50,220 is that where the compiler has these preserving notes, and 664 00:35:50,220 --> 00:35:52,910 says, maybe I'll actually generate the saves and 665 00:35:52,910 --> 00:35:56,220 restores and maybe I won't, the interpreter being 666 00:35:56,220 --> 00:35:59,550 maximally pessimistic always has a save and restore here. 667 00:35:59,550 --> 00:36:04,140 That's the essential difference. 668 00:36:04,140 --> 00:36:07,620 Well, in order to do this, of course, the compiler needs 669 00:36:07,620 --> 00:36:10,775 some theory of what code sequences need 670 00:36:10,775 --> 00:36:12,025 and modifier registers. 671 00:36:12,025 --> 00:36:14,330 672 00:36:14,330 --> 00:36:17,670 So the tiny little fragments that you put in, like the 673 00:36:17,670 --> 00:36:23,340 basic primitive code fragments, say, what are the 674 00:36:23,340 --> 00:36:27,120 operations that you do when you look up a variable? 675 00:36:27,120 --> 00:36:29,630 What are the sequence of things that you do when you 676 00:36:29,630 --> 00:36:32,900 compile a constant or apply a function? 677 00:36:32,900 --> 00:36:35,600 Those have little notations in there about what they need and 678 00:36:35,600 --> 00:36:36,850 what they modify. 679 00:36:36,850 --> 00:36:38,760 680 00:36:38,760 --> 00:36:42,750 So the bottom-level data structures-- 681 00:36:42,750 --> 00:36:44,330 Well, I'll say this. 682 00:36:44,330 --> 00:36:48,070 A code sequence to the compiler looks like this. 683 00:36:48,070 --> 00:36:50,945 It has the actual sequence of instructions. 684 00:36:50,945 --> 00:36:55,780 685 00:36:55,780 --> 00:37:00,370 And then, along with it, there's the set 686 00:37:00,370 --> 00:37:02,195 of registers modified. 687 00:37:02,195 --> 00:37:10,630 688 00:37:10,630 --> 00:37:12,335 And then there's the set of registers needed. 689 00:37:12,335 --> 00:37:19,910 690 00:37:19,910 --> 00:37:24,310 So that's the information the compiler has that it draws on 691 00:37:24,310 --> 00:37:25,965 in order to be able to do this operation. 692 00:37:25,965 --> 00:37:29,420 693 00:37:29,420 --> 00:37:30,650 And where do those come from? 694 00:37:30,650 --> 00:37:34,920 Well, those come from, you might expect, for the very 695 00:37:34,920 --> 00:37:37,230 primitive ones, we're going to put them in by hand. 696 00:37:37,230 --> 00:37:39,890 And then, when we combine two sequences, we'll figure out 697 00:37:39,890 --> 00:37:42,080 what these things should be. 698 00:37:42,080 --> 00:37:48,460 So for example, a very primitive one, let's see. 699 00:37:48,460 --> 00:37:51,790 How about doing a register assignment. 700 00:37:51,790 --> 00:37:56,040 So a primitive sequence might say, oh, it's code fragment. 701 00:37:56,040 --> 00:38:03,050 Its code instruction is assigned to R1, fetch of R2. 702 00:38:03,050 --> 00:38:05,000 So this is an example. 703 00:38:05,000 --> 00:38:08,510 That might be an example of a sequence of instructions. 704 00:38:08,510 --> 00:38:13,110 And along with that, it'll say, oh, what I need to 705 00:38:13,110 --> 00:38:20,670 remember is that that modifies R1, and then it needs R2. 706 00:38:20,670 --> 00:38:24,630 707 00:38:24,630 --> 00:38:27,640 So when you're first building this compiler, you put in 708 00:38:27,640 --> 00:38:31,030 little fragments of stuff like that. 709 00:38:31,030 --> 00:38:37,320 And now, when it combines two sequences, if I'm going to 710 00:38:37,320 --> 00:38:45,990 combine, let's say, sequence one, that modifies a bunch of 711 00:38:45,990 --> 00:38:50,950 registers M1, and needs a bunch of registers N1. 712 00:38:50,950 --> 00:38:54,940 713 00:38:54,940 --> 00:39:00,800 And I'm going to combine that with sequence two. 714 00:39:00,800 --> 00:39:07,780 That modifies a bunch of registers M2, and needs a 715 00:39:07,780 --> 00:39:09,570 bunch of registers N2. 716 00:39:09,570 --> 00:39:12,590 717 00:39:12,590 --> 00:39:15,035 Then, well, we can reason it out. 718 00:39:15,035 --> 00:39:20,230 The new code fragment, sequence one, and-- 719 00:39:20,230 --> 00:39:25,270 followed by sequence two, well, 720 00:39:25,270 --> 00:39:27,760 what's it going to modify? 721 00:39:27,760 --> 00:39:29,380 The things that it will modify are the things that are 722 00:39:29,380 --> 00:39:33,990 modified either by sequence one or sequence two. 723 00:39:33,990 --> 00:39:38,380 So the union of these two sets are what 724 00:39:38,380 --> 00:39:40,530 the new thing modifies. 725 00:39:40,530 --> 00:39:45,620 And then you say, well, what is this--what registers is it 726 00:39:45,620 --> 00:39:47,870 going to need? 727 00:39:47,870 --> 00:39:50,770 It's going to need the things that are, first of all, needed 728 00:39:50,770 --> 00:39:52,790 by sequence one. 729 00:39:52,790 --> 00:39:55,250 So what it needs is sequence one. 730 00:39:55,250 --> 00:39:58,820 And then, well, not quite all of the ones that are needed by 731 00:39:58,820 --> 00:39:59,760 sequence one. 732 00:39:59,760 --> 00:40:02,910 What it needs are the ones that are needed by sequence 733 00:40:02,910 --> 00:40:08,070 two that have not been set up by sequence one. 734 00:40:08,070 --> 00:40:12,880 So it's sort of the union of the things that sequence two 735 00:40:12,880 --> 00:40:19,370 needs minus the ones that sequence one modifies. 736 00:40:19,370 --> 00:40:20,910 Because it worries about setting them up. 737 00:40:20,910 --> 00:40:24,230 738 00:40:24,230 --> 00:40:26,740 So there's the basic structure of the compiler. 739 00:40:26,740 --> 00:40:30,520 The way you do register optimizations is you have some 740 00:40:30,520 --> 00:40:34,010 strategies for what needs to be preserved. 741 00:40:34,010 --> 00:40:35,450 That depends on a data structure. 742 00:40:35,450 --> 00:40:37,600 Well, it depends on the operation of what it means to 743 00:40:37,600 --> 00:40:39,080 put things together. 744 00:40:39,080 --> 00:40:44,710 Preserving something, that depends on knowing what 745 00:40:44,710 --> 00:40:46,200 registers are needed and modified 746 00:40:46,200 --> 00:40:48,900 by these code fragments. 747 00:40:48,900 --> 00:40:52,820 That depends on having little data structures, which say, a 748 00:40:52,820 --> 00:40:56,450 code sequence is the actual instructions, what they modify 749 00:40:56,450 --> 00:40:57,350 and what they need. 750 00:40:57,350 --> 00:40:58,750 That comes from, at the primitive 751 00:40:58,750 --> 00:41:00,240 level, building it in. 752 00:41:00,240 --> 00:41:02,800 At the primitive level, it's going to be completely obvious 753 00:41:02,800 --> 00:41:04,850 what something needs and modifies. 754 00:41:04,850 --> 00:41:08,160 Plus, this particular way that says, when I build up bigger 755 00:41:08,160 --> 00:41:11,130 ones, here's how I generate the new set of registers 756 00:41:11,130 --> 00:41:15,010 modified and the new set of registers needed. 757 00:41:15,010 --> 00:41:16,120 And that's the whole-- 758 00:41:16,120 --> 00:41:17,810 well, I shouldn't say that's the whole thing. 759 00:41:17,810 --> 00:41:21,320 That's the whole thing except for about 30 pages of details 760 00:41:21,320 --> 00:41:21,860 in the book. 761 00:41:21,860 --> 00:41:28,880 But it is a perfectly usable rudimentary compiler. 762 00:41:28,880 --> 00:41:31,390 Let me kind of show you what it does. 763 00:41:31,390 --> 00:41:36,330 Suppose we start out with recursive factorial. 764 00:41:36,330 --> 00:41:38,590 And these slides are going to be much too small to read. 765 00:41:38,590 --> 00:41:40,370 I just want to flash through the code and show you about 766 00:41:40,370 --> 00:41:41,620 how much it is. 767 00:41:41,620 --> 00:41:44,460 768 00:41:44,460 --> 00:41:46,220 That starts out with--here's a first block of it, where it 769 00:41:46,220 --> 00:41:48,740 compiles a procedure entry and does a bunch of assignments. 770 00:41:48,740 --> 00:41:53,000 And this thing is basically up through the part where it sets 771 00:41:53,000 --> 00:41:55,500 up to do the predicate and test whether 772 00:41:55,500 --> 00:41:56,830 the predicate's true. 773 00:41:56,830 --> 00:41:59,530 The second part is what results from-- 774 00:41:59,530 --> 00:42:04,210 in the recursive call to fact of n minus one. 775 00:42:04,210 --> 00:42:08,750 And this last part is coming back from that and then taking 776 00:42:08,750 --> 00:42:09,890 care of the constant case. 777 00:42:09,890 --> 00:42:12,010 So that's about how much code it 778 00:42:12,010 --> 00:42:13,760 would produce for factorial. 779 00:42:13,760 --> 00:42:18,380 We could make this compiler much, much better, of course. 780 00:42:18,380 --> 00:42:21,870 The main way we could make it better is to allow the 781 00:42:21,870 --> 00:42:24,720 compiler to make any assumptions at all about what 782 00:42:24,720 --> 00:42:26,990 happens when you call a procedure. 783 00:42:26,990 --> 00:42:30,810 So this compiler, for instance, doesn't even know, 784 00:42:30,810 --> 00:42:35,030 say, that multiplication is something that 785 00:42:35,030 --> 00:42:36,030 could be coded in line. 786 00:42:36,030 --> 00:42:37,670 Instead, it sets up this whole mechanism. 787 00:42:37,670 --> 00:42:38,920 It goes to apply-dispatch. 788 00:42:38,920 --> 00:42:41,430 789 00:42:41,430 --> 00:42:43,900 That's a tremendous waste, because what you do every time 790 00:42:43,900 --> 00:42:46,060 you go to apply-dispatch is you have to concept this 791 00:42:46,060 --> 00:42:48,640 argument list, because it's a very general thing 792 00:42:48,640 --> 00:42:49,170 you're going to. 793 00:42:49,170 --> 00:42:51,510 In any real compiler, of course, you're going to have 794 00:42:51,510 --> 00:42:53,830 registers for holding arguments. 795 00:42:53,830 --> 00:42:57,060 And you're going to start preserving and saving the way 796 00:42:57,060 --> 00:43:00,510 you use those registers similar to the 797 00:43:00,510 --> 00:43:02,442 same strategy here. 798 00:43:02,442 --> 00:43:06,700 So that's probably the very main way that this particular 799 00:43:06,700 --> 00:43:08,940 compiler in the book could be fixed. 800 00:43:08,940 --> 00:43:12,010 There are other things like looking up variable values and 801 00:43:12,010 --> 00:43:14,010 making more efficient primitive operations and all 802 00:43:14,010 --> 00:43:14,490 sorts of things. 803 00:43:14,490 --> 00:43:17,260 Essentially, a good Lisp compiler can absorb an 804 00:43:17,260 --> 00:43:19,780 arbitrary amount of effort. 805 00:43:19,780 --> 00:43:23,820 And probably one of the reasons that Lisp is slow with 806 00:43:23,820 --> 00:43:27,470 compared to languages like FORTRAN is that, if you look 807 00:43:27,470 --> 00:43:29,860 over history at the amount of effort that's gone into 808 00:43:29,860 --> 00:43:32,110 building Lisp compilers, it's nowhere near the amount of 809 00:43:32,110 --> 00:43:34,520 effort that's gone into FORTRAN compilers. 810 00:43:34,520 --> 00:43:36,910 And maybe that's something that will change over the next 811 00:43:36,910 --> 00:43:38,250 couple of years. 812 00:43:38,250 --> 00:43:39,500 OK, let's break. 813 00:43:39,500 --> 00:43:43,950 814 00:43:43,950 --> 00:43:45,200 Questions? 815 00:43:45,200 --> 00:43:48,370 816 00:43:48,370 --> 00:43:49,590 AUDIENCE: One of the very first classes-- 817 00:43:49,590 --> 00:43:52,180 I don't know if it was during class or after class- you 818 00:43:52,180 --> 00:43:57,040 showed me the, say, addition has a primitive that we don't 819 00:43:57,040 --> 00:44:00,720 see, and-percent add or something like that. 820 00:44:00,720 --> 00:44:03,070 Is that because, if you're doing inline code you'd want 821 00:44:03,070 --> 00:44:08,540 to just do it for two operators, operands? 822 00:44:08,540 --> 00:44:10,552 But if you had more operands, you'd want to 823 00:44:10,552 --> 00:44:12,800 do something special? 824 00:44:12,800 --> 00:44:15,290 PROFESSOR: Yeah, you're looking in the actual scheme 825 00:44:15,290 --> 00:44:15,980 implementation. 826 00:44:15,980 --> 00:44:17,880 There's a plus, and a plus is some operator. 827 00:44:17,880 --> 00:44:20,630 And then if you go look inside the code for plus, you see 828 00:44:20,630 --> 00:44:21,440 something called-- 829 00:44:21,440 --> 00:44:24,640 I forget-- and-percent plus or something like that. 830 00:44:24,640 --> 00:44:27,190 And what's going on there is that particular kind of 831 00:44:27,190 --> 00:44:28,540 optimization. 832 00:44:28,540 --> 00:44:30,520 Because, see, general plus takes an 833 00:44:30,520 --> 00:44:31,770 arbitrary number of arguments. 834 00:44:31,770 --> 00:44:34,750 835 00:44:34,750 --> 00:44:38,020 So the most general plus says, oh, if I have an argument 836 00:44:38,020 --> 00:44:42,400 list, I'd better cons it up in some list and then figure out 837 00:44:42,400 --> 00:44:44,880 how many there were or something like that. 838 00:44:44,880 --> 00:44:47,820 That's terribly inefficient, especially since most of the 839 00:44:47,820 --> 00:44:49,200 time you're probably adding two numbers. 840 00:44:49,200 --> 00:44:52,200 You don't want to really have to cons this argument list. So 841 00:44:52,200 --> 00:44:57,050 what you'd like to do is build the code for plus with a bunch 842 00:44:57,050 --> 00:44:58,170 of entries. 843 00:44:58,170 --> 00:45:00,170 So most of what it's doing is the same. 844 00:45:00,170 --> 00:45:02,630 However, there might be a special entry that you'd go to 845 00:45:02,630 --> 00:45:04,640 if you knew there were only two arguments. 846 00:45:04,640 --> 00:45:05,910 And those you'll put in registers. 847 00:45:05,910 --> 00:45:07,590 They won't be in an argument list and you won't have to 848 00:45:07,590 --> 00:45:09,080 [UNINTELLIGIBLE]. 849 00:45:09,080 --> 00:45:12,570 That's how a lot of these things work. 850 00:45:12,570 --> 00:45:13,948 OK, let's take a break. 851 00:45:13,948 --> 00:45:15,696 [MUSIC PLAYING] 852 00:45:15,696 --> 00:45:42,911 ================================================ FILE: SrtEN/lec10b_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:04,970 1 00:00:04,970 --> 00:00:05,285 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY 2 00:00:05,285 --> 00:00:06,535 JOHANN SEBASTIAN BACH] 3 00:00:06,535 --> 00:00:18,910 4 00:00:18,910 --> 00:00:22,140 PROFESSOR: Well, there's one bit of mystery left, which I'd 5 00:00:22,140 --> 00:00:24,440 like to get rid of right now. 6 00:00:24,440 --> 00:00:28,210 And that's that we've been blithely doing things like 7 00:00:28,210 --> 00:00:33,660 cons assuming there's always another one. 8 00:00:33,660 --> 00:00:37,060 That we've been doing these things like car-ing and 9 00:00:37,060 --> 00:00:38,750 cdr-ing and assuming that we had some idea 10 00:00:38,750 --> 00:00:40,020 how this can be done. 11 00:00:40,020 --> 00:00:43,800 Now indeed we said that that's equivalent to having 12 00:00:43,800 --> 00:00:45,780 procedures. 13 00:00:45,780 --> 00:00:48,360 But that doesn't really solve the problem, because the 14 00:00:48,360 --> 00:00:50,470 procedure need all sorts of complicated mechanisms like 15 00:00:50,470 --> 00:00:53,010 environment structures and things like that to work. 16 00:00:53,010 --> 00:00:55,770 And those were ultimately made out of conses in the model 17 00:00:55,770 --> 00:00:59,380 that we had, so that really doesn't solve the problem. 18 00:00:59,380 --> 00:01:02,860 Now the problem here is the glue the data 19 00:01:02,860 --> 00:01:04,760 structure's made out of. 20 00:01:04,760 --> 00:01:07,370 What kind of possible thing could it be? 21 00:01:07,370 --> 00:01:11,060 We've been showing you things like a machine, a computer 22 00:01:11,060 --> 00:01:14,700 that has a controller, and some 23 00:01:14,700 --> 00:01:16,980 registers, and maybe a stack. 24 00:01:16,980 --> 00:01:18,270 And we haven't said anything about, for 25 00:01:18,270 --> 00:01:20,570 example, larger memory. 26 00:01:20,570 --> 00:01:23,740 And I think that's what we have to worry about right now. 27 00:01:23,740 --> 00:01:27,160 But just to make it perfectly clear that this is an 28 00:01:27,160 --> 00:01:31,320 inessential, purely implementational thing, I'd 29 00:01:31,320 --> 00:01:33,500 like to show you, for example, how you can do it 30 00:01:33,500 --> 00:01:34,800 all with the numbers. 31 00:01:34,800 --> 00:01:37,590 That's an easy one. 32 00:01:37,590 --> 00:01:45,020 Famous fellow by the name of Godel, a logician at the end 33 00:01:45,020 --> 00:01:51,050 of the 1930s, invented a very clever way of encoding the 34 00:01:51,050 --> 00:01:54,320 complicated expressions as numbers. 35 00:01:54,320 --> 00:01:55,540 For example-- 36 00:01:55,540 --> 00:01:58,250 I'm not saying exactly what Godel's scheme is, because he 37 00:01:58,250 --> 00:01:59,660 didn't use words like cons. 38 00:01:59,660 --> 00:02:03,090 He had other kinds of ways of combining to make expressions. 39 00:02:03,090 --> 00:02:05,860 But he said, I'm going to assign a number to every 40 00:02:05,860 --> 00:02:07,920 algebraic expression. 41 00:02:07,920 --> 00:02:09,970 And the way I'm going to manufacture these numbers is 42 00:02:09,970 --> 00:02:12,470 by combining the numbers of the parts. 43 00:02:12,470 --> 00:02:15,880 So for example, what we were doing our world, we could say 44 00:02:15,880 --> 00:02:34,130 that if objects are represented by numbers, then 45 00:02:34,130 --> 00:02:42,660 cons of x and y could be represented by 2 to the x 46 00:02:42,660 --> 00:02:46,130 times 2 to the y. 47 00:02:46,130 --> 00:02:49,560 Because then we could extract the parts. 48 00:02:49,560 --> 00:02:57,500 We could say, for example, that then car of, say, x is 49 00:02:57,500 --> 00:03:06,690 the number of factors of 2 in x. 50 00:03:06,690 --> 00:03:10,690 And of course cdr is the same thing. 51 00:03:10,690 --> 00:03:16,510 It's the number of factors of 3 in x. 52 00:03:16,510 --> 00:03:19,660 Now this is a perfectly reasonable scheme, except for 53 00:03:19,660 --> 00:03:22,870 the fact that the numbers rapidly get to be much larger 54 00:03:22,870 --> 00:03:25,500 in number of digits than the number of 55 00:03:25,500 --> 00:03:27,950 protons in the universe. 56 00:03:27,950 --> 00:03:30,420 So there's no easy way to use this scheme other than the 57 00:03:30,420 --> 00:03:33,430 theoretical one. 58 00:03:33,430 --> 00:03:37,010 On the other hand, there are other ways of representing 59 00:03:37,010 --> 00:03:38,450 these things. 60 00:03:38,450 --> 00:03:44,010 We have been thinking in terms of little boxes. 61 00:03:44,010 --> 00:03:47,000 We've been thinking about our cons structures as looking 62 00:03:47,000 --> 00:03:50,280 sort of like this. 63 00:03:50,280 --> 00:03:53,610 They're little pigeon holes with things in them. 64 00:03:53,610 --> 00:03:57,210 And of course we arrange them in little trees. 65 00:03:57,210 --> 00:04:00,680 I wish that the semiconductor manufacturers would supply me 66 00:04:00,680 --> 00:04:04,280 with something appropriate for this, but actually what they 67 00:04:04,280 --> 00:04:09,380 do supply me with is a linear memory. 68 00:04:09,380 --> 00:04:15,170 Memory is sort of a big pile of pigeonholes, 69 00:04:15,170 --> 00:04:17,720 pigeonholes like this. 70 00:04:17,720 --> 00:04:21,470 Each of which can hold a certain sized object, a fixed 71 00:04:21,470 --> 00:04:23,390 size object. 72 00:04:23,390 --> 00:04:25,890 So, for example, a complicated list with 25 elements won't 73 00:04:25,890 --> 00:04:28,550 fit in one of these. 74 00:04:28,550 --> 00:04:30,600 However, each of these is indexed by an address. 75 00:04:30,600 --> 00:04:33,970 76 00:04:33,970 --> 00:04:36,750 So the address might be zero here, one here, two here, 77 00:04:36,750 --> 00:04:38,060 three here, and so on. 78 00:04:38,060 --> 00:04:40,400 That we write these down as numbers is unimportant. 79 00:04:40,400 --> 00:04:42,710 What matters is that they're distinct as a way to get to 80 00:04:42,710 --> 00:04:44,970 the next one. 81 00:04:44,970 --> 00:04:48,300 And inside of each of these, we can stuff something into 82 00:04:48,300 --> 00:04:49,530 these pigeonholes. 83 00:04:49,530 --> 00:04:52,300 That's what memory is like, for those of you who haven't 84 00:04:52,300 --> 00:04:53,550 built a computer. 85 00:04:53,550 --> 00:04:56,690 86 00:04:56,690 --> 00:04:59,280 Now the problem is how are we going to impose on this type 87 00:04:59,280 --> 00:05:03,290 of structure, this nice tree structure. 88 00:05:03,290 --> 00:05:05,480 Well it's not very hard, and there have been numerous 89 00:05:05,480 --> 00:05:06,630 schemes involved in this. 90 00:05:06,630 --> 00:05:09,930 The most important one is to say, well assuming that the 91 00:05:09,930 --> 00:05:13,920 semiconductor manufacturer allows me to arrange my memory 92 00:05:13,920 --> 00:05:16,390 so that one of these pigeonholes is big enough to 93 00:05:16,390 --> 00:05:21,706 hold the address of another I haven't made. 94 00:05:21,706 --> 00:05:23,730 Now it actually has to be a little bit bigger because I 95 00:05:23,730 --> 00:05:28,215 have to also install or store some information as to a tag 96 00:05:28,215 --> 00:05:30,390 which describes the kind of thing that's there. 97 00:05:30,390 --> 00:05:32,350 And we'll see that in a second. 98 00:05:32,350 --> 00:05:34,560 And of course if the semiconductor manufacturer 99 00:05:34,560 --> 00:05:37,470 doesn't arrange it so I can do that, then of course I can, 100 00:05:37,470 --> 00:05:40,910 with some cleverness, arrange combinations of these to fit 101 00:05:40,910 --> 00:05:43,770 together in that way. 102 00:05:43,770 --> 00:05:48,510 So we're going to have to imagine imposing this 103 00:05:48,510 --> 00:05:51,740 complicated tree structure on our nice linear memory. 104 00:05:51,740 --> 00:05:57,540 If we look at the first still store, we see a classic scheme 105 00:05:57,540 --> 00:05:59,490 for doing that. 106 00:05:59,490 --> 00:06:03,910 It's a standard way of representing Lisp structures 107 00:06:03,910 --> 00:06:05,980 in a linear memory. 108 00:06:05,980 --> 00:06:12,030 What we do is we divide this memory into two parts. 109 00:06:12,030 --> 00:06:17,580 An array called the cars, and an array called the cdrs. 110 00:06:17,580 --> 00:06:20,470 Now whether those happen to be sequential addresses or 111 00:06:20,470 --> 00:06:22,560 whatever, it's not important. 112 00:06:22,560 --> 00:06:25,800 That's somebody's implementation details. 113 00:06:25,800 --> 00:06:28,960 But there are two arrays here. 114 00:06:28,960 --> 00:06:34,840 Linear arrays indexed by sequential indices like this. 115 00:06:34,840 --> 00:06:36,150 What is stored in each of these 116 00:06:36,150 --> 00:06:41,430 pigeonholes is a typed object. 117 00:06:41,430 --> 00:06:44,840 And what we have here are types which begin with letters 118 00:06:44,840 --> 00:06:47,790 like p, standing for a pair. 119 00:06:47,790 --> 00:06:50,040 Or n, standing for a number. 120 00:06:50,040 --> 00:06:57,290 Or e, standing for an empty list. The end of the list. And 121 00:06:57,290 --> 00:07:00,420 so if we wish to represent an object like this, the list 122 00:07:00,420 --> 00:07:04,310 beginning with 1, 2 and then having a 3 and a 4 as its 123 00:07:04,310 --> 00:07:06,430 second and third elements. 124 00:07:06,430 --> 00:07:10,220 A list containing a list as its first part and then two 125 00:07:10,220 --> 00:07:12,610 numbers as a second and third parts. 126 00:07:12,610 --> 00:07:15,250 Then of course we draw it sort of like this these days, in 127 00:07:15,250 --> 00:07:17,320 box-and-pointer notation. 128 00:07:17,320 --> 00:07:21,190 And you see, these are the three cells that have as their 129 00:07:21,190 --> 00:07:28,390 car pointer the object which is either 1, 2 or 3 or 4. 130 00:07:28,390 --> 00:07:30,860 And then of course the 1, 2, the car of this entire 131 00:07:30,860 --> 00:07:33,870 structure, is itself a substructure which contains a 132 00:07:33,870 --> 00:07:35,940 sublist like that. 133 00:07:35,940 --> 00:07:39,970 What I'm about to do is put down places which are-- 134 00:07:39,970 --> 00:07:41,880 I'm going to assign indices. 135 00:07:41,880 --> 00:07:45,530 Like this 1, over here, represents the 136 00:07:45,530 --> 00:07:46,850 index of this cell. 137 00:07:46,850 --> 00:07:49,850 138 00:07:49,850 --> 00:07:55,540 But that pointer that we see here is a reference to the 139 00:07:55,540 --> 00:07:57,640 pair of pigeonholes in the cars and the cdrs that are 140 00:07:57,640 --> 00:08:02,000 labeled by 1 in my linear memory down here. 141 00:08:02,000 --> 00:08:05,920 So if I wish to impose this structure on my linear memory, 142 00:08:05,920 --> 00:08:08,780 what I do is I say, oh yes, why don't we drop 143 00:08:08,780 --> 00:08:12,220 this into cell 1? 144 00:08:12,220 --> 00:08:12,660 I pick one. 145 00:08:12,660 --> 00:08:14,270 There's 1. 146 00:08:14,270 --> 00:08:16,640 And that says that its car, I'm going to 147 00:08:16,640 --> 00:08:17,950 assign it to be a pair. 148 00:08:17,950 --> 00:08:22,590 It's a pair, which is in index 5. 149 00:08:22,590 --> 00:08:26,360 And the cdr, which is this one over here, is a pair which I'm 150 00:08:26,360 --> 00:08:28,340 going to stick into place 2. 151 00:08:28,340 --> 00:08:30,890 p2. 152 00:08:30,890 --> 00:08:32,950 And take a look at p2. 153 00:08:32,950 --> 00:08:37,550 Oh yes, well p2 is a thing whose car is the number 3, so 154 00:08:37,550 --> 00:08:39,520 as you see, an n3. 155 00:08:39,520 --> 00:08:46,640 And whose cdr, over here, is a pair, which lives in place 4. 156 00:08:46,640 --> 00:08:48,650 So that's what this p4 is. 157 00:08:48,650 --> 00:08:56,200 p4 is a number whose value is 4 in its car and whose cdr is 158 00:08:56,200 --> 00:08:59,170 an empty list right there. 159 00:08:59,170 --> 00:09:00,690 And that ends it. 160 00:09:00,690 --> 00:09:05,750 So this is the traditional way of representing this kind of 161 00:09:05,750 --> 00:09:11,620 binary tree in a linear memory. 162 00:09:11,620 --> 00:09:15,770 Now the next question, of course, that we might want to 163 00:09:15,770 --> 00:09:18,440 worry about is just a little bit of implementation. 164 00:09:18,440 --> 00:09:22,690 That means that when I write procedures of the form 165 00:09:22,690 --> 00:09:24,600 assigned a, [UNINTELLIGIBLE] procedures-- 166 00:09:24,600 --> 00:09:29,000 lines of register machine code of the form assigned a, the 167 00:09:29,000 --> 00:09:30,140 car of [UNINTELLIGIBLE] 168 00:09:30,140 --> 00:09:38,740 b, what I really mean is addressing these elements. 169 00:09:38,740 --> 00:09:44,470 And so we're going to think of that as a abbreviation for it. 170 00:09:44,470 --> 00:09:46,720 Now of course in order to write that down I'm going to 171 00:09:46,720 --> 00:09:49,140 introduce some sort of a structure called a vector. 172 00:09:49,140 --> 00:09:52,120 173 00:09:52,120 --> 00:09:53,990 And we're going to have something which will reference 174 00:09:53,990 --> 00:09:58,710 a vector, just so we can write it down. 175 00:09:58,710 --> 00:10:02,240 Which takes the name of the vector, or the-- 176 00:10:02,240 --> 00:10:03,970 I don't think that name is the right word. 177 00:10:03,970 --> 00:10:12,010 Which takes the vector and the index, and I have to have a 178 00:10:12,010 --> 00:10:13,950 way of setting one of those with something called a vector 179 00:10:13,950 --> 00:10:16,280 set, I don't really care. 180 00:10:16,280 --> 00:10:19,520 But let's look, for example, at then that kind of 181 00:10:19,520 --> 00:10:26,470 implementation of car and cdr. 182 00:10:26,470 --> 00:10:31,470 So for example if I happen to have a register b, which 183 00:10:31,470 --> 00:10:37,580 contains the type index of a pair, and therefore it is the 184 00:10:37,580 --> 00:10:41,930 pointer to a pair, then I could take the car of that and 185 00:10:41,930 --> 00:10:42,760 if I-- write this down-- 186 00:10:42,760 --> 00:10:44,490 I might put that in register a. 187 00:10:44,490 --> 00:10:49,400 What that really is is a representation of the assign 188 00:10:49,400 --> 00:10:52,890 to a, the value of vector reffing-- 189 00:10:52,890 --> 00:10:54,700 or array indexing, if you will-- or 190 00:10:54,700 --> 00:10:58,490 something, the cars object-- 191 00:10:58,490 --> 00:10:59,990 whatever that is-- 192 00:10:59,990 --> 00:11:02,650 with the index, b. 193 00:11:02,650 --> 00:11:06,330 And similarly for cdr. And we can do the same thing for 194 00:11:06,330 --> 00:11:10,370 assignment to data structures, if we need to do that sort of 195 00:11:10,370 --> 00:11:11,840 thing at all. 196 00:11:11,840 --> 00:11:14,580 It's not too hard to build that. 197 00:11:14,580 --> 00:11:16,170 Well now the next question is how are we going to do 198 00:11:16,170 --> 00:11:18,010 allocation. 199 00:11:18,010 --> 00:11:21,550 And every so often I say I want a cons. 200 00:11:21,550 --> 00:11:23,790 Now conses don't grow on trees. 201 00:11:23,790 --> 00:11:25,340 Or maybe they should. 202 00:11:25,340 --> 00:11:29,980 But I have to have some way of getting the next one. 203 00:11:29,980 --> 00:11:33,920 I have to have some idea of if their memory is unused that I 204 00:11:33,920 --> 00:11:35,630 might want to allocate from. 205 00:11:35,630 --> 00:11:37,380 And there are many schemes for doing this. 206 00:11:37,380 --> 00:11:38,660 And the particular thing I'm showing you 207 00:11:38,660 --> 00:11:42,100 right now is not essential. 208 00:11:42,100 --> 00:11:44,960 However it's convenient and has been done many times. 209 00:11:44,960 --> 00:11:47,660 One scheme's was called the free list allocation scheme. 210 00:11:47,660 --> 00:11:50,570 What that means is that all of the free memory that there is 211 00:11:50,570 --> 00:11:54,700 in the world is linked together in a linked list, 212 00:11:54,700 --> 00:11:56,960 just like all the other stuff. 213 00:11:56,960 --> 00:12:01,230 And whenever you need a free cell to make a new cons, you 214 00:12:01,230 --> 00:12:04,440 grab the first, one make the free list be the cdr of it, 215 00:12:04,440 --> 00:12:06,030 and then allocate that. 216 00:12:06,030 --> 00:12:09,530 And so what that looks like is something like this. 217 00:12:09,530 --> 00:12:18,510 Here we have the free list starting in 6. 218 00:12:18,510 --> 00:12:24,860 And what that is is a pointer-off to say 8. 219 00:12:24,860 --> 00:12:27,020 So what it says is, this one is free and the 220 00:12:27,020 --> 00:12:28,870 next one is an 8. 221 00:12:28,870 --> 00:12:32,880 This one is free and the next one is in 3, the next one 222 00:12:32,880 --> 00:12:33,930 that's free. 223 00:12:33,930 --> 00:12:37,680 That one's free and the next one is in 0. 224 00:12:37,680 --> 00:12:40,940 That one's free and the next one's in 15. 225 00:12:40,940 --> 00:12:42,780 Something like that. 226 00:12:42,780 --> 00:12:46,400 We can imagine having such a structure. 227 00:12:46,400 --> 00:12:50,480 Given that we have something like that, then it's possible 228 00:12:50,480 --> 00:12:53,940 to just get one when you need it. 229 00:12:53,940 --> 00:12:57,960 And so a program for doing cons, this is what 230 00:12:57,960 --> 00:12:59,320 cons might turn into. 231 00:12:59,320 --> 00:13:05,410 To assign to a register A the result of cons-ing, a B onto 232 00:13:05,410 --> 00:13:08,250 C, the value in this containing B and the value 233 00:13:08,250 --> 00:13:11,240 containing C, what we have to do is get the current 234 00:13:11,240 --> 00:13:13,400 [? type ?] ahead of the freelist, make the free list 235 00:13:13,400 --> 00:13:19,840 be its cdr. Then we have to change the cars to be the 236 00:13:19,840 --> 00:13:25,680 thing we're making up to be in A to be the B, the thing in B. 237 00:13:25,680 --> 00:13:30,880 And we have to make change the cdrs of the thing that's in A 238 00:13:30,880 --> 00:13:36,020 to be C. And then what we have in A is the right new frob, 239 00:13:36,020 --> 00:13:36,650 whatever it is. 240 00:13:36,650 --> 00:13:40,470 The object that we want. 241 00:13:40,470 --> 00:13:43,490 Now there's a little bit of a cheat here that I haven't told 242 00:13:43,490 --> 00:13:47,155 you about, which is somewhere around here I haven't set that 243 00:13:47,155 --> 00:13:51,540 I've the type of the thing that I'm cons-ing up to be a 244 00:13:51,540 --> 00:13:53,510 pair, and I ought to. 245 00:13:53,510 --> 00:13:56,570 So there should be some sort of bits here are being set, 246 00:13:56,570 --> 00:13:59,810 and I just haven't written that down. 247 00:13:59,810 --> 00:14:01,480 We could have arranged it, of course, for the free lift to 248 00:14:01,480 --> 00:14:03,100 be made out of pairs. 249 00:14:03,100 --> 00:14:06,430 And so then there's no problem with that. 250 00:14:06,430 --> 00:14:10,160 But that sort of-- again, an inessential detail in a way 251 00:14:10,160 --> 00:14:13,500 some particular programmer or architect or whatever might 252 00:14:13,500 --> 00:14:17,540 manufacture his machine or Lisp system. 253 00:14:17,540 --> 00:14:23,930 So for example, just looking at this, to allocate given 254 00:14:23,930 --> 00:14:27,200 that I had already the structure that you saw before, 255 00:14:27,200 --> 00:14:31,900 supposing I wanted to allocate a new cell, which is going to 256 00:14:31,900 --> 00:14:38,680 be representation of list one, one, two, where already one 257 00:14:38,680 --> 00:14:43,430 two was the car of the list we were playing with before. 258 00:14:43,430 --> 00:14:44,780 Well that's not so hard. 259 00:14:44,780 --> 00:14:47,670 I stored that one and one, so p1 one is the 260 00:14:47,670 --> 00:14:49,530 representation of this. 261 00:14:49,530 --> 00:14:51,690 This is p5. 262 00:14:51,690 --> 00:14:54,070 That's going to be the cdr of this. 263 00:14:54,070 --> 00:14:55,610 Now we're going to pull something off the free list, 264 00:14:55,610 --> 00:14:57,780 but remember the free list started at six. 265 00:14:57,780 --> 00:15:01,540 The new free list after this allocation is eight, a free 266 00:15:01,540 --> 00:15:02,890 list beginning at eight. 267 00:15:02,890 --> 00:15:06,360 And of course in six now we have a number one, which is 268 00:15:06,360 --> 00:15:10,540 what we wanted, with its cdr being the pair starting in 269 00:15:10,540 --> 00:15:13,330 location five. 270 00:15:13,330 --> 00:15:16,810 And that's no big deal. 271 00:15:16,810 --> 00:15:21,480 So the only problem really remaining here is, well, I 272 00:15:21,480 --> 00:15:25,080 don't have an infinitely large memory. 273 00:15:25,080 --> 00:15:28,070 If I do this for a little while, say, for example, 274 00:15:28,070 --> 00:15:30,745 supposing it takes me a microsecond to do a cons, and 275 00:15:30,745 --> 00:15:34,570 I have a million cons memory then I'm only going to run out 276 00:15:34,570 --> 00:15:38,000 in a second, and that's pretty bad. 277 00:15:38,000 --> 00:15:41,470 So what we do to prevent that disaster, that ecological 278 00:15:41,470 --> 00:15:44,300 disaster, talk about right after questions. 279 00:15:44,300 --> 00:15:45,550 Are there any questions? 280 00:15:45,550 --> 00:15:51,500 281 00:15:51,500 --> 00:15:52,030 Yes. 282 00:15:52,030 --> 00:15:54,830 AUDIENCE: In the environment diagrams that we were drawing 283 00:15:54,830 --> 00:15:58,630 we would use the body of procedures, and you would 284 00:15:58,630 --> 00:16:02,620 eventually wind up with things that were no longer useful in 285 00:16:02,620 --> 00:16:04,930 that structure. 286 00:16:04,930 --> 00:16:06,890 How is that represented? 287 00:16:06,890 --> 00:16:09,180 PROFESSOR: There's two problems here. 288 00:16:09,180 --> 00:16:13,870 One you were asking is that material becomes useless. 289 00:16:13,870 --> 00:16:14,920 We'll talk about that in a second. 290 00:16:14,920 --> 00:16:18,100 That has to do with how to prevent ecological disasters. 291 00:16:18,100 --> 00:16:20,190 If I make a lot of garbage I have to somehow be able to 292 00:16:20,190 --> 00:16:21,820 clean up after myself. 293 00:16:21,820 --> 00:16:23,430 And we'll talk about that in a second. 294 00:16:23,430 --> 00:16:25,370 The other question you're asking is how you represent 295 00:16:25,370 --> 00:16:27,210 the environments, I think. 296 00:16:27,210 --> 00:16:27,600 AUDIENCE: Yes. 297 00:16:27,600 --> 00:16:28,190 PROFESSOR: OK. 298 00:16:28,190 --> 00:16:29,780 And the environment structures can be represented in 299 00:16:29,780 --> 00:16:30,860 arbitrary ways. 300 00:16:30,860 --> 00:16:31,780 There are lots of them. 301 00:16:31,780 --> 00:16:33,630 I mean, here I'm just telling you about list cells. 302 00:16:33,630 --> 00:16:36,400 Of course every real system has vectors of arbitrary 303 00:16:36,400 --> 00:16:39,500 length as well as the vectors of length, too, which 304 00:16:39,500 --> 00:16:41,080 represent list cells. 305 00:16:41,080 --> 00:16:45,460 And the environment structures that one uses in a 306 00:16:45,460 --> 00:16:49,890 professionally written Lisp system tend to be vectors 307 00:16:49,890 --> 00:16:52,350 which contain a number of elements approximately equal 308 00:16:52,350 --> 00:16:56,090 to the number of arguments-- a little bit more because you 309 00:16:56,090 --> 00:16:58,290 need certain glue. 310 00:16:58,290 --> 00:17:00,360 So remember, the environment [UNINTELLIGIBLE] 311 00:17:00,360 --> 00:17:00,740 frames. 312 00:17:00,740 --> 00:17:03,980 The frames are constructed by applying a procedure. 313 00:17:03,980 --> 00:17:08,849 In doing so, an allocation is made of a place which is the 314 00:17:08,849 --> 00:17:11,270 number of arguments long plus [? unglue ?] 315 00:17:11,270 --> 00:17:13,859 that gets linked into a chain. 316 00:17:13,859 --> 00:17:15,660 It's just like algol at that level. 317 00:17:15,660 --> 00:17:19,810 318 00:17:19,810 --> 00:17:21,060 There any other questions? 319 00:17:21,060 --> 00:17:23,700 320 00:17:23,700 --> 00:17:23,920 OK. 321 00:17:23,920 --> 00:17:26,106 Thank you, and let's take a short break. 322 00:17:26,106 --> 00:17:26,449 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY 323 00:17:26,449 --> 00:17:27,699 JOHANN SEBASTIAN BACH] 324 00:17:27,699 --> 00:18:12,270 325 00:18:12,270 --> 00:18:15,840 PROFESSOR: Well, as I just said, computer memories 326 00:18:15,840 --> 00:18:19,420 supplied by the semiconductor manufacturers are finite. 327 00:18:19,420 --> 00:18:21,620 And that's quite a pity. 328 00:18:21,620 --> 00:18:24,030 It might not always be that way. 329 00:18:24,030 --> 00:18:27,990 Just for a quick calculation, you can see that it's possible 330 00:18:27,990 --> 00:18:28,860 that if [? memory ?] 331 00:18:28,860 --> 00:18:32,130 prices keep going at the rate they're going that if you 332 00:18:32,130 --> 00:18:34,950 still took a microsecond second to do a cons, then-- 333 00:18:34,950 --> 00:18:37,120 first of all, everybody should know that there's about pi 334 00:18:37,120 --> 00:18:39,450 times ten to the seventh seconds in a year. 335 00:18:39,450 --> 00:18:42,640 And so that would be ten to the seventh plus ten to the 336 00:18:42,640 --> 00:18:43,940 sixth is ten to the thirteenth. 337 00:18:43,940 --> 00:18:45,870 So there's maybe ten to the fourteenth conses in the life 338 00:18:45,870 --> 00:18:47,520 of a machine. 339 00:18:47,520 --> 00:18:49,900 If there was ten to the fourteenth words of memory on 340 00:18:49,900 --> 00:18:54,020 your machine, you'd never run out. 341 00:18:54,020 --> 00:18:56,310 And that's not completely unreasonable. 342 00:18:56,310 --> 00:18:58,460 Ten to the fourteenth is not a very large number. 343 00:18:58,460 --> 00:19:03,860 344 00:19:03,860 --> 00:19:05,180 I don't think it is. 345 00:19:05,180 --> 00:19:08,700 But then again I like to play with astronomy. 346 00:19:08,700 --> 00:19:11,380 It's at least ten to the eighteenth centimeters between 347 00:19:11,380 --> 00:19:12,930 us and the nearest star. 348 00:19:12,930 --> 00:19:19,620 But the thing I'm about to worry about is, at least in 349 00:19:19,620 --> 00:19:22,130 the current economic state of affairs, ten to the fourteenth 350 00:19:22,130 --> 00:19:24,200 pieces of memory is expensive. 351 00:19:24,200 --> 00:19:27,280 And so I suppose what we have to do is make 352 00:19:27,280 --> 00:19:28,120 do with much smaller. 353 00:19:28,120 --> 00:19:30,170 Memories 354 00:19:30,170 --> 00:19:35,800 Now in general we want to have an illusion of infinity. 355 00:19:35,800 --> 00:19:38,850 All we need to do is arrange it so that whenever you look, 356 00:19:38,850 --> 00:19:40,100 the thing is there. 357 00:19:40,100 --> 00:19:42,670 358 00:19:42,670 --> 00:19:45,105 That's really an important idea. 359 00:19:45,105 --> 00:19:49,540 360 00:19:49,540 --> 00:19:52,470 A person or a computer lives only a finite amount of time 361 00:19:52,470 --> 00:19:55,280 and can only take a finite number of looks at something. 362 00:19:55,280 --> 00:19:58,190 And so you really only need a finite amount of stuff. 363 00:19:58,190 --> 00:20:01,730 But you have to arrange it so no matter how much there is, 364 00:20:01,730 --> 00:20:04,000 how much you really claim there is, there's always 365 00:20:04,000 --> 00:20:06,900 enough stuff so that when you take a look, it's there. 366 00:20:06,900 --> 00:20:08,750 And so you only need a finite amount. 367 00:20:08,750 --> 00:20:11,630 But let's see. 368 00:20:11,630 --> 00:20:14,980 One problem is, as was brought up, that there are possible 369 00:20:14,980 --> 00:20:18,660 ways that there is lots of stuff that we make that we 370 00:20:18,660 --> 00:20:19,410 don't need. 371 00:20:19,410 --> 00:20:20,895 And we could recycle the material out 372 00:20:20,895 --> 00:20:22,760 of which its made. 373 00:20:22,760 --> 00:20:27,820 An example is the fact that we're building environment 374 00:20:27,820 --> 00:20:30,470 structures, and we do so every time we call a procedure. 375 00:20:30,470 --> 00:20:32,810 We have built in it a environment frame. 376 00:20:32,810 --> 00:20:34,840 That environment frame doesn't necessarily 377 00:20:34,840 --> 00:20:36,730 have a very long lifetime. 378 00:20:36,730 --> 00:20:40,330 Its lifetime, meaning its usefulness, may exist only 379 00:20:40,330 --> 00:20:42,850 over the invocation of the procedure. 380 00:20:42,850 --> 00:20:45,860 Or if the procedure exports another procedure by returning 381 00:20:45,860 --> 00:20:48,260 it as a value and that procedure is defined inside of 382 00:20:48,260 --> 00:20:52,210 it, well then the lifetime of the frame of the outer 383 00:20:52,210 --> 00:20:57,070 procedure still is only the lifetime of the procedure 384 00:20:57,070 --> 00:20:58,530 which was exported. 385 00:20:58,530 --> 00:21:01,960 And so ultimately, a lot of that is garbage. 386 00:21:01,960 --> 00:21:05,370 There are other ways of producing garbage as well. 387 00:21:05,370 --> 00:21:07,240 Users produce garbage. 388 00:21:07,240 --> 00:21:10,930 An example of user garbage is something like this. 389 00:21:10,930 --> 00:21:15,220 If we write a program to, for example, append two lists 390 00:21:15,220 --> 00:21:19,890 together, well one way to do it is to reverse the first 391 00:21:19,890 --> 00:21:23,440 list onto the empty list and reverse that onto the second 392 00:21:23,440 --> 00:21:28,160 list. Now that's not terribly bad way of doing it. 393 00:21:28,160 --> 00:21:31,070 And however, the intermediate result, which is the reversal 394 00:21:31,070 --> 00:21:37,300 of the first list as done by this program, is never going 395 00:21:37,300 --> 00:21:39,920 to be accessed ever again after it's copied back on to 396 00:21:39,920 --> 00:21:41,010 the second. 397 00:21:41,010 --> 00:21:43,580 It's an intermediate result. 398 00:21:43,580 --> 00:21:47,230 It's going to be hard to ever see how anybody would ever be 399 00:21:47,230 --> 00:21:48,600 able to access it. 400 00:21:48,600 --> 00:21:51,050 In fact, it will go away. 401 00:21:51,050 --> 00:21:53,190 Now if we make a lot of garbage like that, and we 402 00:21:53,190 --> 00:21:56,210 should be allowed to, then there's got to be some way to 403 00:21:56,210 --> 00:21:58,800 reclaim that garbage. 404 00:21:58,800 --> 00:22:03,050 Well, what I'd like to tell you about now is a very clever 405 00:22:03,050 --> 00:22:09,820 technique whereby a Lisp system can prove a small 406 00:22:09,820 --> 00:22:12,750 theorem every so often on the [? forum, ?] the following 407 00:22:12,750 --> 00:22:17,410 piece of junk will never be accessed again. 408 00:22:17,410 --> 00:22:21,400 It can have no affect on the future of the computation. 409 00:22:21,400 --> 00:22:24,920 It's actually based on a very simple idea. 410 00:22:24,920 --> 00:22:28,570 We've designed our computers to look sort of like this. 411 00:22:28,570 --> 00:22:35,280 There's some data path, which contains the registers. 412 00:22:35,280 --> 00:22:42,610 There are things like x, and env, and val, and so on. 413 00:22:42,610 --> 00:22:47,490 And there's one here called stack, some sort which points 414 00:22:47,490 --> 00:22:50,240 off to a structure somewhere, which is the stack. 415 00:22:50,240 --> 00:22:51,740 And we'll worry about that in a second. 416 00:22:51,740 --> 00:22:55,390 There's some finite controller, finite state 417 00:22:55,390 --> 00:22:56,730 machine controller. 418 00:22:56,730 --> 00:22:59,850 And there's some control signals that go this way and 419 00:22:59,850 --> 00:23:02,270 predicate results that come this way, not 420 00:23:02,270 --> 00:23:04,260 the interesting part. 421 00:23:04,260 --> 00:23:07,140 There's some sort of structured memory, which I 422 00:23:07,140 --> 00:23:10,460 just told you how to make, which may contain a stack. 423 00:23:10,460 --> 00:23:12,690 I didn't tell you how to make things of arbitrary shape, 424 00:23:12,690 --> 00:23:13,450 only pairs. 425 00:23:13,450 --> 00:23:16,280 But in fact with what I've told you can simulate a stack 426 00:23:16,280 --> 00:23:19,140 by a big list. I don't plan to do that, it's not a 427 00:23:19,140 --> 00:23:20,360 nice way to do it. 428 00:23:20,360 --> 00:23:22,990 But we could have something like that. 429 00:23:22,990 --> 00:23:25,990 We have all sorts of little data structures in here that 430 00:23:25,990 --> 00:23:27,470 are hooked together in funny ways. 431 00:23:27,470 --> 00:23:30,115 432 00:23:30,115 --> 00:23:32,560 They connect to other things. 433 00:23:32,560 --> 00:23:33,250 And so on. 434 00:23:33,250 --> 00:23:37,190 And ultimately things up there are pointers to these. 435 00:23:37,190 --> 00:23:40,730 The things that are in the registers are pointers off to 436 00:23:40,730 --> 00:23:44,910 the data structures that live in this Lisp structure memory. 437 00:23:44,910 --> 00:23:52,660 Now the truth of the matter is that the entire consciousness 438 00:23:52,660 --> 00:23:55,550 of this machine is in these registers. 439 00:23:55,550 --> 00:23:59,380 There is no possible way that the machine, if done 440 00:23:59,380 --> 00:24:02,410 correctly, if built correctly, can access anything in this 441 00:24:02,410 --> 00:24:05,580 Lisp structure memory unless the thing in that Lisp 442 00:24:05,580 --> 00:24:10,310 structure memory is connected by a sequence of data 443 00:24:10,310 --> 00:24:15,070 structures to the registers. 444 00:24:15,070 --> 00:24:17,550 If it's accessible by legitimate data structure 445 00:24:17,550 --> 00:24:20,100 selectors from the pointers that are 446 00:24:20,100 --> 00:24:22,280 stored in these registers. 447 00:24:22,280 --> 00:24:24,940 Things like array references, perhaps. 448 00:24:24,940 --> 00:24:28,790 Or cons cell references, cars and cdrs. 449 00:24:28,790 --> 00:24:30,970 But I can't just talk about a random place in this memory, 450 00:24:30,970 --> 00:24:32,740 because I can't get to it. 451 00:24:32,740 --> 00:24:34,665 These are being arbitrary names I'm not allowed to 452 00:24:34,665 --> 00:24:38,985 count, at least as I'm evaluating expressions. 453 00:24:38,985 --> 00:24:41,620 454 00:24:41,620 --> 00:24:44,600 If that's the case then there's a very simple theorem 455 00:24:44,600 --> 00:24:47,160 to be proved. 456 00:24:47,160 --> 00:24:49,730 Which is, if I start with all lead pointers that are in all 457 00:24:49,730 --> 00:24:53,570 these registers and recursively chase out, marking 458 00:24:53,570 --> 00:24:57,980 all the places I can get to by selectors, then eventually I 459 00:24:57,980 --> 00:25:00,750 mark everything they can be gotten to. 460 00:25:00,750 --> 00:25:02,140 Anything which is not so marked is 461 00:25:02,140 --> 00:25:05,560 garbage and can be recycled. 462 00:25:05,560 --> 00:25:07,200 Very simple. 463 00:25:07,200 --> 00:25:11,180 Cannot affect the future of the computation. 464 00:25:11,180 --> 00:25:16,616 So let me show you that in a particular example. 465 00:25:16,616 --> 00:25:19,800 Now that means I'm going to have to append to my 466 00:25:19,800 --> 00:25:23,640 description of the list structure a mark. 467 00:25:23,640 --> 00:25:29,080 And so here, for example, is a Lisp structured memory. 468 00:25:29,080 --> 00:25:31,360 And in this Lisp structured memory is a Lisp structure 469 00:25:31,360 --> 00:25:33,030 beginning in a place I'm going to call-- 470 00:25:33,030 --> 00:25:35,640 471 00:25:35,640 --> 00:25:38,590 this is the root. 472 00:25:38,590 --> 00:25:40,120 Now it doesn't really have to have a root. 473 00:25:40,120 --> 00:25:42,670 It could be a bunch of them, like all the registers. 474 00:25:42,670 --> 00:25:45,270 But I could cleverly arrange it so all the registers, all 475 00:25:45,270 --> 00:25:47,080 the things that are in old registers are also at the 476 00:25:47,080 --> 00:25:50,770 right moment put into this root structure, and then we've 477 00:25:50,770 --> 00:25:51,850 got one pointer to it. 478 00:25:51,850 --> 00:25:54,570 I don't really care. 479 00:25:54,570 --> 00:25:57,290 So the idea is we're going to cons up stuff until our free 480 00:25:57,290 --> 00:25:58,720 list is empty. 481 00:25:58,720 --> 00:26:00,950 We've run out of things. 482 00:26:00,950 --> 00:26:04,560 Now we're going to do this process of proving the theorem 483 00:26:04,560 --> 00:26:07,850 that a certain percentage of the memory has got crap in it. 484 00:26:07,850 --> 00:26:10,320 And then we're going to recycle that to grow new 485 00:26:10,320 --> 00:26:14,570 trees, a standard use of such garbage. 486 00:26:14,570 --> 00:26:17,090 487 00:26:17,090 --> 00:26:18,840 So in any case, what do we have here? 488 00:26:18,840 --> 00:26:21,700 Well we have some data structure which starts out 489 00:26:21,700 --> 00:26:27,502 over here one. 490 00:26:27,502 --> 00:26:33,980 And in fact it has a car in five, and its cdr is in two. 491 00:26:33,980 --> 00:26:36,700 And all the marks start out at zero. 492 00:26:36,700 --> 00:26:39,920 Well let's start marking, just to play this game. 493 00:26:39,920 --> 00:26:42,540 OK. 494 00:26:42,540 --> 00:26:47,090 So for example, since I can access one from the root I 495 00:26:47,090 --> 00:26:48,390 will mark that. 496 00:26:48,390 --> 00:26:50,960 Let me mark it. 497 00:26:50,960 --> 00:26:52,430 Bang. 498 00:26:52,430 --> 00:26:54,560 That's marked. 499 00:26:54,560 --> 00:27:00,020 Now since I have a five here I can go to five and see, well 500 00:27:00,020 --> 00:27:01,450 I'll mark that. 501 00:27:01,450 --> 00:27:01,760 Bang. 502 00:27:01,760 --> 00:27:02,900 That's useful stuff. 503 00:27:02,900 --> 00:27:05,410 But five references as a number in its car, I'm not 504 00:27:05,410 --> 00:27:08,700 interested in marking numbers but its cdr is seven. 505 00:27:08,700 --> 00:27:10,450 So I can mark that. 506 00:27:10,450 --> 00:27:12,260 Bang. 507 00:27:12,260 --> 00:27:16,000 Seven is the empty list, the only thing that references, 508 00:27:16,000 --> 00:27:17,120 and it's got a number in its car. 509 00:27:17,120 --> 00:27:19,490 Not interesting. 510 00:27:19,490 --> 00:27:20,500 Well now let's go back here. 511 00:27:20,500 --> 00:27:21,650 I forgot about something. 512 00:27:21,650 --> 00:27:22,840 Two. 513 00:27:22,840 --> 00:27:25,960 See in other words, if I'm looking at cell one, cell one 514 00:27:25,960 --> 00:27:30,370 contains a two right over here. 515 00:27:30,370 --> 00:27:31,730 A reference to two. 516 00:27:31,730 --> 00:27:35,700 That means I should go mark two. 517 00:27:35,700 --> 00:27:37,140 Bang. 518 00:27:37,140 --> 00:27:38,960 Two contains a reference to four. 519 00:27:38,960 --> 00:27:41,593 It's got a number in its car, I'm not interested in that, so 520 00:27:41,593 --> 00:27:43,780 I'm going to go mark that. 521 00:27:43,780 --> 00:27:47,840 Four refers to seven through its car, and is empty in its 522 00:27:47,840 --> 00:27:49,990 cdr, but I've already marked that one so I don't have to 523 00:27:49,990 --> 00:27:51,400 mark it again. 524 00:27:51,400 --> 00:27:55,000 This is all the accessible structure from that place. 525 00:27:55,000 --> 00:27:58,710 Simple recursive mark algorithm. 526 00:27:58,710 --> 00:28:01,160 Now there are some unhappinesses about that 527 00:28:01,160 --> 00:28:04,920 algorithm, and we can worry about that a second. 528 00:28:04,920 --> 00:28:07,280 But basically you'll see that all the things that have not 529 00:28:07,280 --> 00:28:14,220 been marked are places that are free, and I could recycle. 530 00:28:14,220 --> 00:28:16,210 So the next stage after that is going to be to scan through 531 00:28:16,210 --> 00:28:21,180 all of my memory, looking for things that are not marked. 532 00:28:21,180 --> 00:28:23,370 Every time I come across a marked thing I unmark it, and 533 00:28:23,370 --> 00:28:26,390 every time I come across an unmarked thing I'm going to 534 00:28:26,390 --> 00:28:28,770 link it together in my free list. 535 00:28:28,770 --> 00:28:32,120 Classic, very simple algorithm. 536 00:28:32,120 --> 00:28:33,840 So let's see. 537 00:28:33,840 --> 00:28:34,770 Is that very simple? 538 00:28:34,770 --> 00:28:35,570 Yes it is. 539 00:28:35,570 --> 00:28:38,340 I'm not going to go through the code in any detail, but I 540 00:28:38,340 --> 00:28:40,090 just want to show you about how long it is. 541 00:28:40,090 --> 00:28:42,490 Let's look at the mark phase. 542 00:28:42,490 --> 00:28:45,060 Here's the first part of the mark phase. 543 00:28:45,060 --> 00:28:48,280 We pick up the root. 544 00:28:48,280 --> 00:28:52,380 We're going to use that as a recursive procedure call. 545 00:28:52,380 --> 00:28:55,800 We're going to sweep from there, after when we're done 546 00:28:55,800 --> 00:28:57,380 with marking. 547 00:28:57,380 --> 00:28:59,840 And then we're going to do a little couple of instructions 548 00:28:59,840 --> 00:29:01,920 that do this checking out on the marks and changing the 549 00:29:01,920 --> 00:29:04,000 marks and things like that, according to the algorithm 550 00:29:04,000 --> 00:29:05,500 I've just shown you. 551 00:29:05,500 --> 00:29:06,470 It comes out here. 552 00:29:06,470 --> 00:29:08,800 You have to mark the cars of things and you also have to be 553 00:29:08,800 --> 00:29:10,660 able to mark the cdrs of things. 554 00:29:10,660 --> 00:29:14,370 That's the entire mark phase. 555 00:29:14,370 --> 00:29:16,590 I'll just tell you a little story about this. 556 00:29:16,590 --> 00:29:22,950 The old DEC PDP-6 computer, this was the way that the 557 00:29:22,950 --> 00:29:26,740 mark-sweep garbage collection, as it was, was written. 558 00:29:26,740 --> 00:29:31,940 The program was so small that with the data that it needed, 559 00:29:31,940 --> 00:29:34,310 with the registers that it needed to manipulate the 560 00:29:34,310 --> 00:29:38,070 memory, it fit into the fast registers of the machine, 561 00:29:38,070 --> 00:29:39,280 which were 16. 562 00:29:39,280 --> 00:29:39,800 The whole program. 563 00:29:39,800 --> 00:29:40,700 And you could execute 564 00:29:40,700 --> 00:29:43,170 instructions in the fast registers. 565 00:29:43,170 --> 00:29:46,560 So it's an extremely small program, and it could run very 566 00:29:46,560 --> 00:29:48,870 fast. 567 00:29:48,870 --> 00:29:53,130 Now unfortunately, of course, this program, because the fact 568 00:29:53,130 --> 00:29:57,630 that it's recursive in the way that you do something first 569 00:29:57,630 --> 00:29:59,690 and then you do something after that, you have to work 570 00:29:59,690 --> 00:30:03,410 on the cars and then the cdrs, it requires auxiliary memory. 571 00:30:03,410 --> 00:30:05,680 So Lisp systems-- 572 00:30:05,680 --> 00:30:08,260 those requires a stack for marking. 573 00:30:08,260 --> 00:30:12,440 Lisp systems that are built this way have a limit to the 574 00:30:12,440 --> 00:30:16,060 depth of recursion you can have in data structures in 575 00:30:16,060 --> 00:30:19,930 either the car or the cdr, and that doesn't work very nicely. 576 00:30:19,930 --> 00:30:23,180 On the other hand, you never notice it if it's big enough. 577 00:30:23,180 --> 00:30:27,650 And that's certainly been the case for most Maclisp, for 578 00:30:27,650 --> 00:30:30,760 example, which ran Macsyma where you could deal with 579 00:30:30,760 --> 00:30:33,560 expressions of thousands of elements long. 580 00:30:33,560 --> 00:30:35,490 These are algebraic expressions with thousand of 581 00:30:35,490 --> 00:30:39,490 terms. And there's no problem with that. 582 00:30:39,490 --> 00:30:42,190 Such, the garbage collector does work. 583 00:30:42,190 --> 00:30:44,750 On the other hand, there's a very clever modification to 584 00:30:44,750 --> 00:30:49,020 this algorithm, which I will not describe, by Peter Deutsch 585 00:30:49,020 --> 00:30:50,720 and Schorr and Waite-- 586 00:30:50,720 --> 00:30:55,380 Herb Schorr from IBM and Waite, who I don't know. 587 00:30:55,380 --> 00:30:58,470 That algorithm allows you to build-- you do can do this 588 00:30:58,470 --> 00:31:01,990 without auxiliary memory, by remembering as you walk the 589 00:31:01,990 --> 00:31:04,760 data structures where you came from by reversing the pointers 590 00:31:04,760 --> 00:31:06,650 as you go down and crawling up the reverse 591 00:31:06,650 --> 00:31:07,520 pointers as you go up. 592 00:31:07,520 --> 00:31:09,130 It's a rather tricky algorithm. 593 00:31:09,130 --> 00:31:11,230 The first time you write it-- or in fact, the first three 594 00:31:11,230 --> 00:31:14,350 times you write it it has a terrible bug in it. 595 00:31:14,350 --> 00:31:18,110 And it's also rather slow, because it's complicated. 596 00:31:18,110 --> 00:31:21,150 It takes about six times as many memory references to do 597 00:31:21,150 --> 00:31:24,580 the sorts of things that we're talking about. 598 00:31:24,580 --> 00:31:28,140 Well now once I've done this marking phase, and I get into 599 00:31:28,140 --> 00:31:30,920 a position where things look like this, let's look-- 600 00:31:30,920 --> 00:31:31,510 yes. 601 00:31:31,510 --> 00:31:35,590 Here we have the mark done, just as I did it. 602 00:31:35,590 --> 00:31:37,330 Now we have to perform the sweep phase. 603 00:31:37,330 --> 00:31:39,820 And I described to you what this sweep is like. 604 00:31:39,820 --> 00:31:42,130 I'm going to walk down from one end of memory or the 605 00:31:42,130 --> 00:31:45,690 other, I don't care where, scanning every cell that's in 606 00:31:45,690 --> 00:31:46,836 the memory. 607 00:31:46,836 --> 00:31:51,000 And as I scan these cells, I'm going to link them together, 608 00:31:51,000 --> 00:31:53,890 if they are free, into the free list. And if they're not 609 00:31:53,890 --> 00:31:57,500 free, I'm going to unmark them so the marks become zero. 610 00:31:57,500 --> 00:32:00,050 And in fact what I get-- well the program is not very 611 00:32:00,050 --> 00:32:00,460 complicated. 612 00:32:00,460 --> 00:32:02,780 It looks sort of like this-- it's a little longer. 613 00:32:02,780 --> 00:32:04,820 Here's the first piece of it. 614 00:32:04,820 --> 00:32:06,710 This one's coming down from the top of memory. 615 00:32:06,710 --> 00:32:09,580 I don't want you to try to understand this at this point. 616 00:32:09,580 --> 00:32:11,030 It's rather simple. 617 00:32:11,030 --> 00:32:14,260 It's a very simple algorithm, but there's pieces of it that 618 00:32:14,260 --> 00:32:15,970 just sort of look like this. 619 00:32:15,970 --> 00:32:18,600 They're all sort of obvious. 620 00:32:18,600 --> 00:32:21,060 And after we've done the sweep, we get an answer that 621 00:32:21,060 --> 00:32:22,310 looks like that. 622 00:32:22,310 --> 00:32:25,330 623 00:32:25,330 --> 00:32:27,150 Now there are some disadvantages with mark-sweep 624 00:32:27,150 --> 00:32:29,590 algorithms of this sort. 625 00:32:29,590 --> 00:32:31,940 Serious ones. 626 00:32:31,940 --> 00:32:34,250 One important disadvantage is that your memories get larger 627 00:32:34,250 --> 00:32:36,498 and larger. 628 00:32:36,498 --> 00:32:39,100 As you say, address spaces get larger and larger, you're 629 00:32:39,100 --> 00:32:43,080 willing to represent more and more stuff, then it gets very 630 00:32:43,080 --> 00:32:46,360 costly to scan all of memory. 631 00:32:46,360 --> 00:32:50,490 What you'd really like to do is only scan useful stuff. 632 00:32:50,490 --> 00:32:56,120 It would even be better if you realized that some stuff was 633 00:32:56,120 --> 00:32:59,320 known to be good and useful, and you don't have to look at 634 00:32:59,320 --> 00:33:00,370 it more than once or twice. 635 00:33:00,370 --> 00:33:01,550 Or very rarely. 636 00:33:01,550 --> 00:33:05,120 Whereas other stuff that you're not so sure about, you 637 00:33:05,120 --> 00:33:10,110 can look at more detail every time you want to do this, want 638 00:33:10,110 --> 00:33:11,910 to garbage collect. 639 00:33:11,910 --> 00:33:15,660 Well there are algorithms that are organized in this way. 640 00:33:15,660 --> 00:33:18,850 Let me tell you about a famous old algorithm which allows you 641 00:33:18,850 --> 00:33:20,370 only look at the part of memory which 642 00:33:20,370 --> 00:33:22,800 is known to be useful. 643 00:33:22,800 --> 00:33:24,690 And which happens to be the fastest known garbage 644 00:33:24,690 --> 00:33:26,310 collector algorithm. 645 00:33:26,310 --> 00:33:28,170 This is the Minsky-Feinchel-Yochelson 646 00:33:28,170 --> 00:33:30,150 garbage collector algorithm. 647 00:33:30,150 --> 00:33:36,660 It was invented by Minsky in 1961 or '60 or something, for 648 00:33:36,660 --> 00:33:45,870 the RLE PDP-1 Lisp, which had 4,096 words of list memory, 649 00:33:45,870 --> 00:33:48,480 and a drum. 650 00:33:48,480 --> 00:33:50,890 And the whole idea was to garbage collect 651 00:33:50,890 --> 00:33:53,380 this terrible memory. 652 00:33:53,380 --> 00:33:56,510 What Minsky realized was the easiest way to do this is to 653 00:33:56,510 --> 00:33:59,950 scan the memory in the same sense, walking the good 654 00:33:59,950 --> 00:34:06,350 structure, copying it out into the drum, compacted. 655 00:34:06,350 --> 00:34:09,429 And then when we were done copying it all out, then you 656 00:34:09,429 --> 00:34:12,300 swap that back into your memory. 657 00:34:12,300 --> 00:34:14,260 Now whether or you not use a drum, or another piece of 658 00:34:14,260 --> 00:34:17,030 memory, or something like that isn't important. 659 00:34:17,030 --> 00:34:18,260 In fact, I don't think people use 660 00:34:18,260 --> 00:34:20,350 drums anymore for anything. 661 00:34:20,350 --> 00:34:25,920 But this algorithm basically depends upon having about 662 00:34:25,920 --> 00:34:30,270 twice as much address space as you're actually using. 663 00:34:30,270 --> 00:34:35,370 And so what you have is some, initially, some mixture of 664 00:34:35,370 --> 00:34:37,110 useful data and garbage. 665 00:34:37,110 --> 00:34:38,560 So this is called fromspace. 666 00:34:38,560 --> 00:34:45,179 667 00:34:45,179 --> 00:34:47,800 And this is a mixture of crud. 668 00:34:47,800 --> 00:34:52,000 Some of it's important and some of it isn't. 669 00:34:52,000 --> 00:34:55,770 Now there's another place which is hopefully big enough, 670 00:34:55,770 --> 00:34:58,240 if we recall, tospace, which is where we're copying to. 671 00:34:58,240 --> 00:35:01,590 672 00:35:01,590 --> 00:35:03,260 And what happens is-- and I'm not going to go 673 00:35:03,260 --> 00:35:04,970 through this detail. 674 00:35:04,970 --> 00:35:07,590 It's in our book quite explicitly. 675 00:35:07,590 --> 00:35:11,030 There's a root point where you start from. 676 00:35:11,030 --> 00:35:14,600 And the idea is that you start with the root. 677 00:35:14,600 --> 00:35:18,610 You copy the first thing you see, the first thing that the 678 00:35:18,610 --> 00:35:22,810 root points at, to the beginning of tospace. 679 00:35:22,810 --> 00:35:24,790 The first thing is a pair or something 680 00:35:24,790 --> 00:35:27,560 like, a data structure. 681 00:35:27,560 --> 00:35:32,330 You then also leave behind a broken heart saying, I moved 682 00:35:32,330 --> 00:35:36,330 this object from here to here, giving the place 683 00:35:36,330 --> 00:35:37,800 where it moved to. 684 00:35:37,800 --> 00:35:40,270 This is called a broken heart because a friend of mine who 685 00:35:40,270 --> 00:35:44,760 implemented one of these in 1966 was a very romantic 686 00:35:44,760 --> 00:35:46,760 character and called it a broken heart. 687 00:35:46,760 --> 00:35:49,580 688 00:35:49,580 --> 00:35:53,570 But in any case, the next thing you do is now you have a 689 00:35:53,570 --> 00:35:57,840 new free pointer which is here, and you start scanning. 690 00:35:57,840 --> 00:36:00,235 You scan this data structure you just copied. 691 00:36:00,235 --> 00:36:02,710 And every time you encounter a pointer in it, you treat it as 692 00:36:02,710 --> 00:36:04,000 if it was the root pointer here. 693 00:36:04,000 --> 00:36:05,170 Oh, I'm sorry. 694 00:36:05,170 --> 00:36:06,330 The other thing you do is you now move the 695 00:36:06,330 --> 00:36:09,220 root pointer to there. 696 00:36:09,220 --> 00:36:11,310 So now you scan this, and everything you see you treat 697 00:36:11,310 --> 00:36:14,110 as it were the root pointer. 698 00:36:14,110 --> 00:36:16,360 So if you see something, well it points 699 00:36:16,360 --> 00:36:18,510 up into there somewhere. 700 00:36:18,510 --> 00:36:21,780 Is it pointing at a thing which you've not copied yet? 701 00:36:21,780 --> 00:36:23,880 Is there a broken heart there? 702 00:36:23,880 --> 00:36:25,370 If there's a broken heart there and it's something you 703 00:36:25,370 --> 00:36:27,640 have copied, you've just replaced this pointer with the 704 00:36:27,640 --> 00:36:30,620 thing a broken heart points at. 705 00:36:30,620 --> 00:36:33,030 If this thing has not been copied, you copy it to the 706 00:36:33,030 --> 00:36:34,430 next place over here. 707 00:36:34,430 --> 00:36:39,860 Move your free pointer over here, and then leave a broken 708 00:36:39,860 --> 00:36:43,670 heart behind and scan. 709 00:36:43,670 --> 00:36:46,840 And eventually when the scant pointer hits the free pointer, 710 00:36:46,840 --> 00:36:50,140 everything in memory has been copied. 711 00:36:50,140 --> 00:36:52,170 And then there's a whole bunch of empty space up here, which 712 00:36:52,170 --> 00:36:53,820 you could either make into a free list, if that's what you 713 00:36:53,820 --> 00:36:54,470 want to do. 714 00:36:54,470 --> 00:36:56,270 But generally you don't in this kind of system. 715 00:36:56,270 --> 00:36:57,470 In this system you sequentially 716 00:36:57,470 --> 00:37:00,910 allocate your memory. 717 00:37:00,910 --> 00:37:03,820 That is a very, very nice algorithm, and sort of the one 718 00:37:03,820 --> 00:37:06,790 we use in the scheme that you've been using. 719 00:37:06,790 --> 00:37:09,490 And it's expected-- 720 00:37:09,490 --> 00:37:12,400 I believe no one has found a faster algorithm than that. 721 00:37:12,400 --> 00:37:14,150 There are very simple modifications to this 722 00:37:14,150 --> 00:37:19,060 algorithm invented by Henry Baker which allow one to run 723 00:37:19,060 --> 00:37:21,210 this algorithm in real time, meaning you don't have to stop 724 00:37:21,210 --> 00:37:22,010 to garbage collect. 725 00:37:22,010 --> 00:37:25,410 But you could interleave the consing that the machine does 726 00:37:25,410 --> 00:37:27,870 when its running with steps of the garbage collection 727 00:37:27,870 --> 00:37:31,370 process, so that the garbage collector's distributed, and 728 00:37:31,370 --> 00:37:32,980 the machine doesn't have to stop, and garbage 729 00:37:32,980 --> 00:37:34,640 collecting can start. 730 00:37:34,640 --> 00:37:37,520 Of course in the case of machines with virtual memory 731 00:37:37,520 --> 00:37:41,760 where a lot of it is in inaccessible places, this 732 00:37:41,760 --> 00:37:44,460 becomes a very expensive process. 733 00:37:44,460 --> 00:37:47,690 And there have been numerous attempts to 734 00:37:47,690 --> 00:37:49,190 make this much better. 735 00:37:49,190 --> 00:37:52,080 There is a nice paper, for those of you who are 736 00:37:52,080 --> 00:37:56,210 interested, by Moon and other people which describes a 737 00:37:56,210 --> 00:37:57,940 modification to the incremental 738 00:37:57,940 --> 00:38:00,290 Minsky-Feinchel-Yochelson algorithm, and modification 739 00:38:00,290 --> 00:38:05,980 the Baker algorithm which is more efficient for virtual 740 00:38:05,980 --> 00:38:08,340 memory systems. 741 00:38:08,340 --> 00:38:12,840 Well I think now the mystery to this is sort of gone. 742 00:38:12,840 --> 00:38:14,090 And I'd like to see if there are any questions. 743 00:38:14,090 --> 00:38:19,780 744 00:38:19,780 --> 00:38:20,810 Yes. 745 00:38:20,810 --> 00:38:24,100 AUDIENCE: I saw one of you run the garbage collector on the 746 00:38:24,100 --> 00:38:27,640 systems upstairs, and it seemed to me to run extremely 747 00:38:27,640 --> 00:38:30,190 fast. Did the whole thing take-- 748 00:38:30,190 --> 00:38:31,880 does it sweep through all of memory? 749 00:38:31,880 --> 00:38:32,510 PROFESSOR: No. 750 00:38:32,510 --> 00:38:34,480 It swept through exactly what was needed to 751 00:38:34,480 --> 00:38:37,320 copy the useful structure. 752 00:38:37,320 --> 00:38:40,030 It's a copying collector. 753 00:38:40,030 --> 00:38:45,090 And it is very fast. On the whole, I suppose to copy-- 754 00:38:45,090 --> 00:38:47,000 in a Bobcat-- 755 00:38:47,000 --> 00:38:52,450 to copy, I think, a three megabyte thing or something is 756 00:38:52,450 --> 00:38:56,800 less than a second, real time. 757 00:38:56,800 --> 00:38:59,200 Really, these are very small programs. One thing you should 758 00:38:59,200 --> 00:39:05,400 realise is that garbage collectors have to be small. 759 00:39:05,400 --> 00:39:08,770 Not because they have to be fast, but because no one can 760 00:39:08,770 --> 00:39:11,340 debug a complicated garbage collector. 761 00:39:11,340 --> 00:39:15,000 A garbage collector, if it doesn't work, will trash your 762 00:39:15,000 --> 00:39:16,940 memory in such a way that you cannot figure out what the 763 00:39:16,940 --> 00:39:18,350 hell happened. 764 00:39:18,350 --> 00:39:20,660 You need an audit trail. 765 00:39:20,660 --> 00:39:22,460 Because it rearranges everything, and how do you 766 00:39:22,460 --> 00:39:23,740 know what happened there? 767 00:39:23,740 --> 00:39:27,480 So this is the only kind of program that it really, 768 00:39:27,480 --> 00:39:30,100 seriously matters if you stare at it long enough so you 769 00:39:30,100 --> 00:39:31,970 believe that it works. 770 00:39:31,970 --> 00:39:35,100 And sort of prove it to yourself. 771 00:39:35,100 --> 00:39:36,940 So there's no way to debug it. 772 00:39:36,940 --> 00:39:39,230 And that takes it being small enough so you can 773 00:39:39,230 --> 00:39:41,690 hold it in your head. 774 00:39:41,690 --> 00:39:45,020 Garbage collectors are special in this way. 775 00:39:45,020 --> 00:39:47,130 So every reasonable garbage collector has gotten small, 776 00:39:47,130 --> 00:39:52,430 and generally small programs are fast. Yes. 777 00:39:52,430 --> 00:39:53,650 AUDIENCE: Can you repeat the name of this 778 00:39:53,650 --> 00:39:54,510 technique once again? 779 00:39:54,510 --> 00:39:56,220 PROFESSOR: That's the Minsky-Feinchel-Yochelson 780 00:39:56,220 --> 00:39:58,420 garbage collector. 781 00:39:58,420 --> 00:39:59,340 AUDIENCE: You got that? 782 00:39:59,340 --> 00:40:02,210 PROFESSOR: Minsky invented it in '61 for the RLE PDP-1. 783 00:40:02,210 --> 00:40:07,410 A version of it was developed and elaborated to be used in 784 00:40:07,410 --> 00:40:12,410 Multics Maclisp by Feinchel and Yochelson in somewhere 785 00:40:12,410 --> 00:40:19,570 around 1968 or '69. 786 00:40:19,570 --> 00:40:20,650 OK. 787 00:40:20,650 --> 00:40:22,640 Let's take a break. 788 00:40:22,640 --> 00:40:22,934 [MUSIC: "JESU, JOY OF MAN'S DESIRING" BY 789 00:40:22,934 --> 00:40:24,184 JOHANN SEBASTIAN BACH] 790 00:40:24,184 --> 00:41:17,310 791 00:41:17,310 --> 00:41:21,600 PROFESSOR: Well we've come to the end of this subject, and 792 00:41:21,600 --> 00:41:24,860 we've already shown you a universal machine which is 793 00:41:24,860 --> 00:41:26,740 down to evaluator. 794 00:41:26,740 --> 00:41:28,980 It's down to the level of detail you could imagine you 795 00:41:28,980 --> 00:41:30,420 could make one. 796 00:41:30,420 --> 00:41:34,390 This is a particular implementation of Lisp, built 797 00:41:34,390 --> 00:41:37,530 on one of those scheme chips that was talked about 798 00:41:37,530 --> 00:41:39,180 yesterday, sitting over here. 799 00:41:39,180 --> 00:41:42,990 This is mostly interface to somebody's memory with a 800 00:41:42,990 --> 00:41:45,010 little bit of timing and other such stuff. 801 00:41:45,010 --> 00:41:48,760 But this fellow actually ran Lisp at a fairly reasonable 802 00:41:48,760 --> 00:41:50,610 rate, as interpretive. 803 00:41:50,610 --> 00:41:56,500 It ran Lisp as fast as a DEC PDP-10 back in 1979. 804 00:41:56,500 --> 00:41:59,870 And so it's gotten pretty hardware. 805 00:41:59,870 --> 00:42:02,470 Pretty concrete. 806 00:42:02,470 --> 00:42:05,000 We've also downed you a bit with the 807 00:42:05,000 --> 00:42:07,370 things you can compute. 808 00:42:07,370 --> 00:42:11,850 But is it the case that there are things we can't compute? 809 00:42:11,850 --> 00:42:14,690 And so I'd like to end this with showing you some things 810 00:42:14,690 --> 00:42:18,190 that you'd like be able to compute that you can't. 811 00:42:18,190 --> 00:42:22,720 The answer is yes, there are things you can't compute. 812 00:42:22,720 --> 00:42:28,200 For example, something you'd really like is-- 813 00:42:28,200 --> 00:42:30,210 if you're writing [UNINTELLIGIBLE], you'd like a 814 00:42:30,210 --> 00:42:32,800 program that would check that the thing you're 815 00:42:32,800 --> 00:42:34,630 going to do will work. 816 00:42:34,630 --> 00:42:36,080 Wouldn't that be nice? 817 00:42:36,080 --> 00:42:37,960 You'd like something that would catch infinite loops, 818 00:42:37,960 --> 00:42:43,190 for example, in programs that were written by users. 819 00:42:43,190 --> 00:42:45,890 But in general you can't write such a program that will read 820 00:42:45,890 --> 00:42:48,760 any program and determine whether or not it's an 821 00:42:48,760 --> 00:42:50,990 infinite loop. 822 00:42:50,990 --> 00:42:51,685 Let me show you that. 823 00:42:51,685 --> 00:42:53,340 It's a little bit of a minor mathematics. 824 00:42:53,340 --> 00:42:58,780 825 00:42:58,780 --> 00:43:01,360 Let's imagine that we just had a mathematical 826 00:43:01,360 --> 00:43:02,620 function before we start. 827 00:43:02,620 --> 00:43:12,980 And there is one, called s, which takes a procedure and 828 00:43:12,980 --> 00:43:14,230 its argument, a. 829 00:43:14,230 --> 00:43:19,320 830 00:43:19,320 --> 00:43:24,250 And what s does is it determines whether or not it's 831 00:43:24,250 --> 00:43:26,632 safe to run p on a. 832 00:43:26,632 --> 00:43:34,500 And what I mean by that is this: it's true if p applied 833 00:43:34,500 --> 00:43:45,330 to a will converge to a value without an error. 834 00:43:45,330 --> 00:43:52,365 835 00:43:52,365 --> 00:44:06,890 And it's false if p of a loops forever or makes an error. 836 00:44:06,890 --> 00:44:15,000 837 00:44:15,000 --> 00:44:18,780 Now that's surely a function. 838 00:44:18,780 --> 00:44:21,830 There is some for every procedure and for every 839 00:44:21,830 --> 00:44:25,900 argument you could give it that is either true or false 840 00:44:25,900 --> 00:44:28,440 that it converges without making an error. 841 00:44:28,440 --> 00:44:31,770 And you could make a giant table of them. 842 00:44:31,770 --> 00:44:34,710 But the question is, can you write a procedure that compute 843 00:44:34,710 --> 00:44:37,430 the values of this function? 844 00:44:37,430 --> 00:44:39,720 Well let's assume that we can. 845 00:44:39,720 --> 00:44:58,740 Suppose that we have a procedure called "safe" that 846 00:44:58,740 --> 00:44:59,990 computes the value of s. 847 00:44:59,990 --> 00:45:12,170 848 00:45:12,170 --> 00:45:17,620 Now I'm going to show you by several methods that 849 00:45:17,620 --> 00:45:19,760 you can't do this. 850 00:45:19,760 --> 00:45:22,300 The easiest one, or the first one, let's define a procedure 851 00:45:22,300 --> 00:45:23,810 called diag1. 852 00:45:23,810 --> 00:45:38,250 Given that we have safe, we can define diag1 to be the 853 00:45:38,250 --> 00:45:43,430 procedure of one argument, p, which has the following 854 00:45:43,430 --> 00:45:44,780 properties. 855 00:45:44,780 --> 00:45:54,620 If if it's safe to apply p to itself, then I wish to have an 856 00:45:54,620 --> 00:45:55,870 infinite loop. 857 00:45:55,870 --> 00:45:59,330 858 00:45:59,330 --> 00:46:00,715 Otherwise I'm going to return 3. 859 00:46:00,715 --> 00:46:03,680 860 00:46:03,680 --> 00:46:04,470 Remember it was 42. 861 00:46:04,470 --> 00:46:07,060 What's the answer to the big question? 862 00:46:07,060 --> 00:46:08,525 Where of course we know what an infinite loop is. 863 00:46:08,525 --> 00:46:12,050 864 00:46:12,050 --> 00:46:16,130 Infinite loop, to be a procedure of no arguments, 865 00:46:16,130 --> 00:46:18,430 which is that nice lambda calculus loop. 866 00:46:18,430 --> 00:46:24,680 Lambda of x, x of x, applied to lambda of x, x of x. 867 00:46:24,680 --> 00:46:26,550 So there's nothing left to the imagination here. 868 00:46:26,550 --> 00:46:29,830 869 00:46:29,830 --> 00:46:32,500 Well let's see what the story is. 870 00:46:32,500 --> 00:46:38,100 I'm supposing it's the case that we worry about the 871 00:46:38,100 --> 00:46:43,180 procedure called diag1 applied to diag1. 872 00:46:43,180 --> 00:46:45,860 873 00:46:45,860 --> 00:46:49,970 Well what could it possibly be? 874 00:46:49,970 --> 00:46:51,390 Well I don't know. 875 00:46:51,390 --> 00:46:57,310 We're going to substitute diag1 for p in the body here. 876 00:46:57,310 --> 00:47:00,220 Well is it safe to compute diag1 of diag1? 877 00:47:00,220 --> 00:47:00,780 I don't know. 878 00:47:00,780 --> 00:47:03,400 There are two possibilities. 879 00:47:03,400 --> 00:47:06,260 If it's safe to compute diag1 of diag1 that means it 880 00:47:06,260 --> 00:47:08,490 shouldn't loop. 881 00:47:08,490 --> 00:47:09,540 That means I go to here, but then I 882 00:47:09,540 --> 00:47:10,560 produce an infinite loop. 883 00:47:10,560 --> 00:47:12,210 So it can't be safe. 884 00:47:12,210 --> 00:47:15,055 But if it's not safe to compute diag1 of diag1 then 885 00:47:15,055 --> 00:47:16,020 the answer to this is 3. 886 00:47:16,020 --> 00:47:20,530 But that's diag1 of diag1, so it had to be safe. 887 00:47:20,530 --> 00:47:27,470 So therefore by contradiction you cannot produce safe. 888 00:47:27,470 --> 00:47:30,565 For those of you who were boggled by that one I'm going 889 00:47:30,565 --> 00:47:32,820 to say it again, in a different way. 890 00:47:32,820 --> 00:47:35,530 Listen to one more alternative. 891 00:47:35,530 --> 00:47:36,780 Let's define diag2. 892 00:47:36,780 --> 00:47:39,840 893 00:47:39,840 --> 00:47:45,260 These are named diag because of Cantor's diagonal argument. 894 00:47:45,260 --> 00:47:48,180 These are instances of a famous argument which was 895 00:47:48,180 --> 00:47:52,070 originally used by Cantor in the late part of the last 896 00:47:52,070 --> 00:47:56,420 century to prove that the real numbers were not countable, 897 00:47:56,420 --> 00:47:58,160 that there are too many real numbers to 898 00:47:58,160 --> 00:48:00,190 be counted by integers. 899 00:48:00,190 --> 00:48:02,710 That there are more points on a line, for example, than 900 00:48:02,710 --> 00:48:05,260 there are counting numbers. 901 00:48:05,260 --> 00:48:07,190 It may or may not be obvious, and I don't want to 902 00:48:07,190 --> 00:48:08,440 get into that now. 903 00:48:08,440 --> 00:48:10,900 904 00:48:10,900 --> 00:48:15,820 But diag2 is again a procedure of one argument p. 905 00:48:15,820 --> 00:48:19,220 It's almost the same as the previous one, which is, if 906 00:48:19,220 --> 00:48:26,445 it's safe to compute p on p, then I'm going to produce-- 907 00:48:26,445 --> 00:48:29,310 908 00:48:29,310 --> 00:48:34,010 then I want to compute some other things 909 00:48:34,010 --> 00:48:38,960 other than p of p. 910 00:48:38,960 --> 00:48:40,210 Otherwise I'm going to put out false. 911 00:48:40,210 --> 00:48:43,600 912 00:48:43,600 --> 00:48:46,510 Where other then it says, whatever p of p, I'm going to 913 00:48:46,510 --> 00:48:48,880 put out something else. 914 00:48:48,880 --> 00:48:51,860 I can give you an example of a definition of other than which 915 00:48:51,860 --> 00:48:53,890 I think works. 916 00:48:53,890 --> 00:48:55,640 Let's see. 917 00:48:55,640 --> 00:48:56,330 Yes. 918 00:48:56,330 --> 00:49:06,580 Where other than be a procedure of one argument x 919 00:49:06,580 --> 00:49:14,090 which says, if its eq x to, say, quote a, then the answer 920 00:49:14,090 --> 00:49:15,720 is quote b. 921 00:49:15,720 --> 00:49:16,970 Otherwise it's quote a. 922 00:49:16,970 --> 00:49:20,090 923 00:49:20,090 --> 00:49:22,770 That always produces something which is not what 924 00:49:22,770 --> 00:49:25,350 its argument is. 925 00:49:25,350 --> 00:49:26,540 That's all it is. 926 00:49:26,540 --> 00:49:28,250 That's all I wanted. 927 00:49:28,250 --> 00:49:30,640 Well now let's consider this one, diag2 of diag2. 928 00:49:30,640 --> 00:49:38,220 929 00:49:38,220 --> 00:49:39,560 Well look. 930 00:49:39,560 --> 00:49:42,950 This only does something dangerous, like calling p of 931 00:49:42,950 --> 00:49:47,470 p, if it's safe to do so. 932 00:49:47,470 --> 00:49:51,590 So if safe defined at all, if you can define such a 933 00:49:51,590 --> 00:49:55,680 procedure, safe, then this procedure is always defined 934 00:49:55,680 --> 00:49:57,225 and therefore safe on any inputs. 935 00:49:57,225 --> 00:50:01,540 936 00:50:01,540 --> 00:50:11,770 So diag2 of diag2 must reduce to other than diag2 of diag2. 937 00:50:11,770 --> 00:50:15,496 938 00:50:15,496 --> 00:50:20,020 And that doesn't make sense, so we have a contradiction, 939 00:50:20,020 --> 00:50:22,950 and therefore we can't define safe. 940 00:50:22,950 --> 00:50:27,210 I just waned to do that twice, slightly differently, so you 941 00:50:27,210 --> 00:50:32,260 wouldn't feel that the first one was a trick. 942 00:50:32,260 --> 00:50:34,275 They may be both tricks, but they're at 943 00:50:34,275 --> 00:50:37,300 least slightly different. 944 00:50:37,300 --> 00:50:40,080 So I suppose that pretty much wraps it up. 945 00:50:40,080 --> 00:50:43,540 I've just proved what we call the halting theorem, and I 946 00:50:43,540 --> 00:50:46,720 suppose with that we're going to halt. 947 00:50:46,720 --> 00:50:47,970 I hope you have a good time. 948 00:50:47,970 --> 00:50:50,900 949 00:50:50,900 --> 00:50:53,300 Are there any questions? 950 00:50:53,300 --> 00:50:53,810 Yes. 951 00:50:53,810 --> 00:50:56,940 AUDIENCE: What is the value of s of diag1? 952 00:50:56,940 --> 00:50:57,430 PROFESSOR: Of what? 953 00:50:57,430 --> 00:51:00,120 AUDIENCE: S of diag1. 954 00:51:00,120 --> 00:51:02,340 If you said s is a function and we can 955 00:51:02,340 --> 00:51:02,620 [INTERPOSING VOICES] 956 00:51:02,620 --> 00:51:03,870 PROFESSOR: Oh, I don't know. 957 00:51:03,870 --> 00:51:04,350 I don't know. 958 00:51:04,350 --> 00:51:06,850 It's a function, but I don't know how to compute it. 959 00:51:06,850 --> 00:51:08,610 I can't do it. 960 00:51:08,610 --> 00:51:11,530 I'm just a machine, too. 961 00:51:11,530 --> 00:51:12,210 Right? 962 00:51:12,210 --> 00:51:14,670 There's no machine that in principle-- 963 00:51:14,670 --> 00:51:16,690 it might be that in that particular case you just 964 00:51:16,690 --> 00:51:18,580 asked, with some thinking I could figure it out. 965 00:51:18,580 --> 00:51:21,670 But in general I can't compute the value of s any better than 966 00:51:21,670 --> 00:51:23,780 any other machine can. 967 00:51:23,780 --> 00:51:27,210 There is such a function, it's just that no machine can be 968 00:51:27,210 --> 00:51:29,580 built to compute it. 969 00:51:29,580 --> 00:51:32,980 Now there's a way of saying that that should not be 970 00:51:32,980 --> 00:51:35,350 surprising. 971 00:51:35,350 --> 00:51:36,390 Going through this-- 972 00:51:36,390 --> 00:51:41,020 I mean, I don't have time to do this here, but the number 973 00:51:41,020 --> 00:51:44,600 of functions is very large. 974 00:51:44,600 --> 00:51:48,210 If there's a certain number of answers possible and a certain 975 00:51:48,210 --> 00:51:50,520 number of inputs possible, then it's the number of 976 00:51:50,520 --> 00:51:52,290 answers raised to the number inputs is the number of 977 00:51:52,290 --> 00:51:54,720 possible functions. 978 00:51:54,720 --> 00:51:55,970 On one variable. 979 00:51:55,970 --> 00:51:58,150 980 00:51:58,150 --> 00:52:03,690 Now that's always bigger than the thing you're raising to, 981 00:52:03,690 --> 00:52:05,480 the exponent. 982 00:52:05,480 --> 00:52:12,150 The number of functions is larger than the number of 983 00:52:12,150 --> 00:52:15,340 programs that one can write, by an 984 00:52:15,340 --> 00:52:17,840 infinity counting argument. 985 00:52:17,840 --> 00:52:19,475 And it's much larger. 986 00:52:19,475 --> 00:52:22,540 So there must be a lot of functions that can't be 987 00:52:22,540 --> 00:52:26,280 computed by programs. 988 00:52:26,280 --> 00:52:27,300 AUDIENCE: A few moments ago you were talking about 989 00:52:27,300 --> 00:52:30,640 specifications and automatic generation of solutions. 990 00:52:30,640 --> 00:52:33,360 Do you see any steps between specifications and solutions? 991 00:52:33,360 --> 00:52:37,250 992 00:52:37,250 --> 00:52:38,720 PROFESSOR: Steps between. 993 00:52:38,720 --> 00:52:42,720 You mean, you're saying, how you go about constructing 994 00:52:42,720 --> 00:52:45,205 devices given that have specifications for the device? 995 00:52:45,205 --> 00:52:45,500 Sure. 996 00:52:45,500 --> 00:52:48,540 AUDIENCE: There's a lot of software engineering that goes 997 00:52:48,540 --> 00:52:51,703 through specifications through many layers of design and then 998 00:52:51,703 --> 00:52:52,430 implementation. 999 00:52:52,430 --> 00:52:52,850 PROFESSOR: Yes? 1000 00:52:52,850 --> 00:52:55,600 AUDIENCE: I was curious if you think that's realistic. 1001 00:52:55,600 --> 00:52:57,210 PROFESSOR: Well I think that some of it's realistic and 1002 00:52:57,210 --> 00:52:58,100 some of it isn't. 1003 00:52:58,100 --> 00:53:01,680 I mean, surely if I want to build an electrical filter and 1004 00:53:01,680 --> 00:53:07,160 I have a rather interesting possibility. 1005 00:53:07,160 --> 00:53:12,180 Supposing I want to build a thing that matches some power 1006 00:53:12,180 --> 00:53:19,906 output to the radio transmitter, to some antenna. 1007 00:53:19,906 --> 00:53:21,970 And I'm really out of this power-- 1008 00:53:21,970 --> 00:53:23,230 it's output tube out here. 1009 00:53:23,230 --> 00:53:25,920 And the problem is that they have different impedances. 1010 00:53:25,920 --> 00:53:27,550 I want them to match the impedances. 1011 00:53:27,550 --> 00:53:29,920 I also want to make a filter in there which is going to get 1012 00:53:29,920 --> 00:53:32,780 rid of some harmonic radiation. 1013 00:53:32,780 --> 00:53:36,270 Well one old-fashioned technique for doing this is 1014 00:53:36,270 --> 00:53:38,860 called image impedances, or something like that. 1015 00:53:38,860 --> 00:53:40,240 And what you do is you say you have a basic 1016 00:53:40,240 --> 00:53:43,300 module called an L-section. 1017 00:53:43,300 --> 00:53:44,550 Looks like this. 1018 00:53:44,550 --> 00:53:47,080 1019 00:53:47,080 --> 00:53:50,470 If I happen to connect this to some resistance, r, and if I 1020 00:53:50,470 --> 00:53:55,150 make this impedance x, xl, and if it happens to be q times r, 1021 00:53:55,150 --> 00:53:59,710 then this produces a low pass filter with a q square plus 1022 00:53:59,710 --> 00:54:02,110 one impedance match. 1023 00:54:02,110 --> 00:54:03,120 Just what I need. 1024 00:54:03,120 --> 00:54:04,610 Because now I can take two of these, hook them 1025 00:54:04,610 --> 00:54:06,510 together like this. 1026 00:54:06,510 --> 00:54:11,660 1027 00:54:11,660 --> 00:54:16,570 OK, and I take another one and I'll hook them 1028 00:54:16,570 --> 00:54:18,290 together like that. 1029 00:54:18,290 --> 00:54:20,320 And I have two L-sections hooked together. 1030 00:54:20,320 --> 00:54:22,460 And this will step the impedance down to one that I 1031 00:54:22,460 --> 00:54:25,530 know, and this will step it up to one I know. 1032 00:54:25,530 --> 00:54:26,710 Each of these is a low pass filter 1033 00:54:26,710 --> 00:54:28,090 getting rid of some harmonics. 1034 00:54:28,090 --> 00:54:30,270 It's good filter, it's called a pie-section filter. 1035 00:54:30,270 --> 00:54:31,700 Great. 1036 00:54:31,700 --> 00:54:34,300 Except for the fact that in doing what I just did, I've 1037 00:54:34,300 --> 00:54:38,620 made a terrible inefficiency in this system. 1038 00:54:38,620 --> 00:54:41,620 I've made two coils where I should have made one. 1039 00:54:41,620 --> 00:54:45,200 And the problem with most software engineering art is 1040 00:54:45,200 --> 00:54:47,440 that there's no mechanism, other than peephole 1041 00:54:47,440 --> 00:54:50,280 optimization and compilers, for getting rid of the 1042 00:54:50,280 --> 00:54:52,810 redundant parts that are constructed when doing top 1043 00:54:52,810 --> 00:54:55,350 down design. 1044 00:54:55,350 --> 00:54:57,160 It's even worse, there are lots of very important 1045 00:54:57,160 --> 00:55:01,110 structures that you can't construct at all this way. 1046 00:55:01,110 --> 00:55:03,940 So I think that the standard top down design is a rather 1047 00:55:03,940 --> 00:55:05,710 shallow business. 1048 00:55:05,710 --> 00:55:08,315 Doesn't really capture what people want to do in design. 1049 00:55:08,315 --> 00:55:10,100 I'll give you another electrical example. 1050 00:55:10,100 --> 00:55:12,140 Electrical examples are so much clearer than 1051 00:55:12,140 --> 00:55:14,440 computational examples, because computation examples 1052 00:55:14,440 --> 00:55:17,220 require a certain degree of complexity to explain them. 1053 00:55:17,220 --> 00:55:19,650 But one of my favorite examples in the electrical 1054 00:55:19,650 --> 00:55:23,330 world is how would I ever come up with the output stage of 1055 00:55:23,330 --> 00:55:27,530 this inter-stage connection in an IF amplifier. 1056 00:55:27,530 --> 00:55:32,410 It's a little transistor here, and let's see. 1057 00:55:32,410 --> 00:55:37,560 Well I'm going to have a tank, and I'm going to hook this up 1058 00:55:37,560 --> 00:55:43,040 to, say, I'm going to link-couple that to the input 1059 00:55:43,040 --> 00:55:44,850 of the next stage. 1060 00:55:44,850 --> 00:55:48,580 Here's a perfectly plausible plan-- 1061 00:55:48,580 --> 00:55:51,070 well except for the fact that since I put that going up I 1062 00:55:51,070 --> 00:55:53,170 should make that going that way. 1063 00:55:53,170 --> 00:55:56,050 Here's a perfectly plausible plan for a-- 1064 00:55:56,050 --> 00:55:57,270 no I shouldn't. 1065 00:55:57,270 --> 00:55:57,940 I'm dumb. 1066 00:55:57,940 --> 00:55:59,690 Excuse me. 1067 00:55:59,690 --> 00:56:00,730 Doesn't matter. 1068 00:56:00,730 --> 00:56:01,540 The point is [UNINTELLIGIBLE] 1069 00:56:01,540 --> 00:56:02,560 plan for a couple [UNINTELLIGIBLE] 1070 00:56:02,560 --> 00:56:04,590 stages together. 1071 00:56:04,590 --> 00:56:07,620 Now what the problem is is what's this hierarchically? 1072 00:56:07,620 --> 00:56:09,480 It's not one thing. 1073 00:56:09,480 --> 00:56:11,990 Hierarchically it doesn't make any sense at all. 1074 00:56:11,990 --> 00:56:17,230 It's the inductance of a tuned circuit, it's the primary of a 1075 00:56:17,230 --> 00:56:22,350 transformer, and it's also the DC path by which bias 1076 00:56:22,350 --> 00:56:26,460 conditions get to the collector of that transistor. 1077 00:56:26,460 --> 00:56:29,170 And there's no simple top-down design that's going to produce 1078 00:56:29,170 --> 00:56:33,400 a structure like that with so many overlapping uses for a 1079 00:56:33,400 --> 00:56:34,530 particular thing. 1080 00:56:34,530 --> 00:56:39,015 Playing Scrabble, where you have to do triple word scores, 1081 00:56:39,015 --> 00:56:44,950 or whatever, is not so easy in top-down design strategy. 1082 00:56:44,950 --> 00:56:48,100 Yet most of real engineering is based on getting the most 1083 00:56:48,100 --> 00:56:52,140 oomph for effort. 1084 00:56:52,140 --> 00:56:54,860 And that's what you're seeing here. 1085 00:56:54,860 --> 00:56:55,550 Yeah? 1086 00:56:55,550 --> 00:56:56,810 AUDIENCE: Is this the last question? 1087 00:56:56,810 --> 00:57:00,282 1088 00:57:00,282 --> 00:57:18,640 [LAUGHTER] 1089 00:57:18,640 --> 00:57:19,890 PROFESSOR: Apparently so. 1090 00:57:19,890 --> 00:57:23,240 1091 00:57:23,240 --> 00:57:26,092 Thank you. 1092 00:57:26,092 --> 00:57:39,040 [APPLAUSE] 1093 00:57:39,040 --> 00:57:39,383 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY 1094 00:57:39,383 --> 00:57:40,633 JOHANN SEBASTIAN BACH] 1095 00:57:40,633 --> 00:58:53,546 ================================================ FILE: SrtEN/lec1a_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:03,880 1 00:00:03,880 --> 00:00:14,550 [MUSIC PLAYING] 2 00:00:14,550 --> 00:00:15,790 PROFESSOR: I'd like to welcome you to this 3 00:00:15,790 --> 00:00:17,270 course on computer science. 4 00:00:17,270 --> 00:00:28,370 5 00:00:28,370 --> 00:00:29,990 Actually, that's a terrible way to start. 6 00:00:29,990 --> 00:00:32,740 Computer science is a terrible name for this business. 7 00:00:32,740 --> 00:00:35,572 First of all, it's not a science. 8 00:00:35,572 --> 00:00:40,300 It might be engineering or it might be art, but we'll 9 00:00:40,300 --> 00:00:43,470 actually see that computer so-called science actually has 10 00:00:43,470 --> 00:00:45,350 a lot in common with magic, and we'll see 11 00:00:45,350 --> 00:00:47,210 that in this course. 12 00:00:47,210 --> 00:00:48,040 So it's not a science. 13 00:00:48,040 --> 00:00:53,340 It's also not really very much about computers. 14 00:00:53,340 --> 00:00:57,140 And it's not about computers in the same sense that physics 15 00:00:57,140 --> 00:01:02,920 is not really about particle accelerators, and biology is 16 00:01:02,920 --> 00:01:06,350 not really about microscopes and petri dishes. 17 00:01:06,350 --> 00:01:10,400 And it's not about computers in the same sense that 18 00:01:10,400 --> 00:01:16,480 geometry is not really about using surveying instruments. 19 00:01:16,480 --> 00:01:20,320 In fact, there's a lot of commonality between computer 20 00:01:20,320 --> 00:01:21,240 science and geometry. 21 00:01:21,240 --> 00:01:23,830 Geometry, first of all, is another subject 22 00:01:23,830 --> 00:01:25,680 with a lousy name. 23 00:01:25,680 --> 00:01:28,130 The name comes from Gaia, meaning the Earth, and metron, 24 00:01:28,130 --> 00:01:29,770 meaning to measure. 25 00:01:29,770 --> 00:01:31,350 Geometry originally meant measuring 26 00:01:31,350 --> 00:01:34,260 the Earth or surveying. 27 00:01:34,260 --> 00:01:37,260 And the reason for that was that, thousands of years ago, 28 00:01:37,260 --> 00:01:40,930 the Egyptian priesthood developed the rudiments of 29 00:01:40,930 --> 00:01:45,320 geometry in order to figure out how to restore the 30 00:01:45,320 --> 00:01:47,430 boundaries of fields that were destroyed in the annual 31 00:01:47,430 --> 00:01:49,390 flooding of the Nile. 32 00:01:49,390 --> 00:01:52,360 And to the Egyptians who did that, geometry really was the 33 00:01:52,360 --> 00:01:55,600 use of surveying instruments. 34 00:01:55,600 --> 00:01:57,850 Now, the reason that we think computer science is about 35 00:01:57,850 --> 00:02:01,770 computers is pretty much the same reason that the Egyptians 36 00:02:01,770 --> 00:02:04,520 thought geometry was about surveying instruments. 37 00:02:04,520 --> 00:02:07,340 And that is, when some field is just getting started and 38 00:02:07,340 --> 00:02:11,790 you don't really understand it very well, it's very easy to 39 00:02:11,790 --> 00:02:15,280 confuse the essence of what you're doing with the tools 40 00:02:15,280 --> 00:02:17,590 that you use. 41 00:02:17,590 --> 00:02:20,960 And indeed, on some absolute scale of things, we probably 42 00:02:20,960 --> 00:02:25,100 know less about the essence of computer science than the 43 00:02:25,100 --> 00:02:26,955 ancient Egyptians really knew about geometry. 44 00:02:26,955 --> 00:02:29,970 45 00:02:29,970 --> 00:02:32,570 Well, what do I mean by the essence of computer science? 46 00:02:32,570 --> 00:02:34,300 What do I mean by the essence of geometry? 47 00:02:34,300 --> 00:02:36,380 See, it's certainly true that these Egyptians went off and 48 00:02:36,380 --> 00:02:40,190 used surveying instruments, but when we look back on them 49 00:02:40,190 --> 00:02:42,240 after a couple of thousand years, we say, gee, what they 50 00:02:42,240 --> 00:02:45,910 were doing, the important stuff they were doing, was to 51 00:02:45,910 --> 00:02:52,510 begin to formalize notions about space and time, to start 52 00:02:52,510 --> 00:02:57,490 a way of talking about mathematical truths formally. 53 00:02:57,490 --> 00:02:59,420 That led to the axiomatic method. 54 00:02:59,420 --> 00:03:04,420 That led to sort of all of modern mathematics, figuring 55 00:03:04,420 --> 00:03:08,350 out a way to talk precisely about so-called declarative 56 00:03:08,350 --> 00:03:10,000 knowledge, what is true. 57 00:03:10,000 --> 00:03:12,550 58 00:03:12,550 --> 00:03:15,680 Well, similarly, I think in the future people will look 59 00:03:15,680 --> 00:03:18,520 back and say, yes, those primitives in the 20th century 60 00:03:18,520 --> 00:03:20,190 were fiddling around with these gadgets called 61 00:03:20,190 --> 00:03:25,790 computers, but really what they were doing is starting to 62 00:03:25,790 --> 00:03:32,730 learn how to formalize intuitions about process, how 63 00:03:32,730 --> 00:03:47,100 to do things, starting to develop a way to talk 64 00:03:47,100 --> 00:03:52,190 precisely about how-to knowledge, as opposed to 65 00:03:52,190 --> 00:03:56,470 geometry that talks about what is true. 66 00:03:56,470 --> 00:03:57,810 Let me give you an example of that. 67 00:03:57,810 --> 00:04:01,650 68 00:04:01,650 --> 00:04:02,550 Let's take a look. 69 00:04:02,550 --> 00:04:08,250 Here is a piece of mathematics that says what 70 00:04:08,250 --> 00:04:10,250 a square root is. 71 00:04:10,250 --> 00:04:17,019 The square root of X is the number Y, such that Y squared 72 00:04:17,019 --> 00:04:20,290 is equal to X and Y is greater than 0. 73 00:04:20,290 --> 00:04:23,510 Now, that's a fine piece of mathematics, but just telling 74 00:04:23,510 --> 00:04:26,900 you what a square root is doesn't really say anything 75 00:04:26,900 --> 00:04:31,420 about how you might go out and find one. 76 00:04:31,420 --> 00:04:37,410 So let's contrast that with a piece of imperative knowledge, 77 00:04:37,410 --> 00:04:39,840 how you might go out and find a square root. 78 00:04:39,840 --> 00:04:44,660 This, in fact, also comes from Egypt, not 79 00:04:44,660 --> 00:04:45,640 ancient, ancient Egypt. 80 00:04:45,640 --> 00:04:50,050 This is an algorithm due to Heron of Alexandria, called 81 00:04:50,050 --> 00:04:52,910 how to find a square root by successive averaging. 82 00:04:52,910 --> 00:05:03,370 And what it says is that, in order to find a square root, 83 00:05:03,370 --> 00:05:07,560 you make a guess, you improve that guess-- 84 00:05:07,560 --> 00:05:10,070 85 00:05:10,070 --> 00:05:12,670 and the way you improve the guess is to average the guess 86 00:05:12,670 --> 00:05:15,170 and X over the guess, and we'll talk a little bit later 87 00:05:15,170 --> 00:05:17,080 about why that's a reasonable thing-- 88 00:05:17,080 --> 00:05:19,740 and you keep improving the guess until it's good enough. 89 00:05:19,740 --> 00:05:20,800 That's a method. 90 00:05:20,800 --> 00:05:25,070 That's how to do something as opposed to declarative 91 00:05:25,070 --> 00:05:28,270 knowledge that says what you're looking for. 92 00:05:28,270 --> 00:05:29,520 That's a process. 93 00:05:29,520 --> 00:05:34,130 94 00:05:34,130 --> 00:05:38,850 Well, what's a process in general? 95 00:05:38,850 --> 00:05:40,000 It's kind of hard to say. 96 00:05:40,000 --> 00:05:45,350 You can think of it as like a magical spirit that sort of 97 00:05:45,350 --> 00:05:47,870 lives in the computer and does something. 98 00:05:47,870 --> 00:05:56,250 And the thing that directs a process is a pattern of rules 99 00:05:56,250 --> 00:05:57,500 called a procedure. 100 00:05:57,500 --> 00:06:01,690 101 00:06:01,690 --> 00:06:05,940 So procedures are the spells, if you like, that control 102 00:06:05,940 --> 00:06:10,700 these magical spirits that are the processes. 103 00:06:10,700 --> 00:06:12,650 I guess you know everyone needs a magical language, and 104 00:06:12,650 --> 00:06:17,310 sorcerers, real sorcerers, use ancient Arcadian or Sumerian 105 00:06:17,310 --> 00:06:18,670 or Babylonian or whatever. 106 00:06:18,670 --> 00:06:21,540 We're going to conjure our spirits in a magical language 107 00:06:21,540 --> 00:06:26,750 called Lisp, which is a language designed for talking 108 00:06:26,750 --> 00:06:31,120 about, for casting the spells that are procedures to direct 109 00:06:31,120 --> 00:06:32,040 the processes. 110 00:06:32,040 --> 00:06:33,780 Now, it's very easy to learn Lisp. 111 00:06:33,780 --> 00:06:35,810 In fact, in a few minutes, I'm going to teach you, 112 00:06:35,810 --> 00:06:36,960 essentially, all of Lisp. 113 00:06:36,960 --> 00:06:40,660 I'm going to teach you, essentially, all of the rules. 114 00:06:40,660 --> 00:06:43,440 And you shouldn't find that particularly surprising. 115 00:06:43,440 --> 00:06:46,150 That's sort of like saying it's very easy to learn the 116 00:06:46,150 --> 00:06:46,940 rules of chess. 117 00:06:46,940 --> 00:06:48,860 And indeed, in a few minutes, you can tell somebody the 118 00:06:48,860 --> 00:06:50,710 rules of chess. 119 00:06:50,710 --> 00:06:53,490 But of course, that's very different from saying you 120 00:06:53,490 --> 00:06:55,740 understand the implications of those rules and how to use 121 00:06:55,740 --> 00:06:58,420 those rules to become a masterful chess player. 122 00:06:58,420 --> 00:07:00,380 Well, Lisp is the same way. 123 00:07:00,380 --> 00:07:02,610 We're going to state the rules in a few minutes, and it'll be 124 00:07:02,610 --> 00:07:03,360 very easy to see. 125 00:07:03,360 --> 00:07:06,210 But what's really hard is going to be the implications 126 00:07:06,210 --> 00:07:09,310 of those rules, how you exploit those rules to be a 127 00:07:09,310 --> 00:07:12,080 master programmer. 128 00:07:12,080 --> 00:07:15,260 And the implications of those rules are going to take us 129 00:07:15,260 --> 00:07:17,770 the, well, the whole rest of the subject and, of course, 130 00:07:17,770 --> 00:07:19,020 way beyond. 131 00:07:19,020 --> 00:07:21,420 132 00:07:21,420 --> 00:07:26,070 OK, so in computer science, we're in the business of 133 00:07:26,070 --> 00:07:30,910 formalizing this sort of how-to imperative knowledge, 134 00:07:30,910 --> 00:07:33,330 how to do stuff. 135 00:07:33,330 --> 00:07:35,120 And the real issues of computer science are, of 136 00:07:35,120 --> 00:07:38,620 course, not telling people how to do square roots. 137 00:07:38,620 --> 00:07:40,050 Because if that was all it was, there 138 00:07:40,050 --> 00:07:41,760 wouldn't be no big deal. 139 00:07:41,760 --> 00:07:45,550 The real problems come when we try to build very, very large 140 00:07:45,550 --> 00:07:49,270 systems, computer programs that are thousands of pages 141 00:07:49,270 --> 00:07:52,640 long, so long that nobody can really hold them in their 142 00:07:52,640 --> 00:07:54,640 heads all at once. 143 00:07:54,640 --> 00:07:58,770 And the only reason that that's possible is because 144 00:07:58,770 --> 00:08:17,830 there are techniques for controlling the complexity of 145 00:08:17,830 --> 00:08:21,590 these large systems. And these techniques that are 146 00:08:21,590 --> 00:08:22,950 controlling complexity are what this 147 00:08:22,950 --> 00:08:24,700 course is really about. 148 00:08:24,700 --> 00:08:26,030 And in some sense, that's really what 149 00:08:26,030 --> 00:08:29,650 computer science is about. 150 00:08:29,650 --> 00:08:31,740 Now, that may seem like a very strange thing to say. 151 00:08:31,740 --> 00:08:34,960 Because after all, a lot of people besides computer 152 00:08:34,960 --> 00:08:37,970 scientists deal with controlling complexity. 153 00:08:37,970 --> 00:08:41,860 A large airliner is an extremely complex system, and 154 00:08:41,860 --> 00:08:44,760 the aeronautical engineers who design that are dealing with 155 00:08:44,760 --> 00:08:47,030 immense complexity. 156 00:08:47,030 --> 00:08:49,380 But there's a difference between that kind of 157 00:08:49,380 --> 00:08:52,205 complexity and what we deal with in computer science. 158 00:08:52,205 --> 00:08:55,090 159 00:08:55,090 --> 00:08:57,750 And that is that computer science, in some 160 00:08:57,750 --> 00:08:59,700 sense, isn't real. 161 00:08:59,700 --> 00:09:02,670 162 00:09:02,670 --> 00:09:07,070 You see, when an engineer is designing a physical system, 163 00:09:07,070 --> 00:09:09,520 that's made out of real parts. 164 00:09:09,520 --> 00:09:12,820 The engineers who worry about that have to address problems 165 00:09:12,820 --> 00:09:16,540 of tolerance and approximation and noise in the system. 166 00:09:16,540 --> 00:09:19,280 So for example, as an electrical engineer, I can go 167 00:09:19,280 --> 00:09:21,885 off and easily build a one-stage amplifier or a 168 00:09:21,885 --> 00:09:25,090 two-stage amplifier, and I can imagine cascading a lot of 169 00:09:25,090 --> 00:09:26,760 them to build a million-stage amplifier. 170 00:09:26,760 --> 00:09:30,900 But it's ridiculous to build such a thing, because long 171 00:09:30,900 --> 00:09:33,160 before the millionth stage, the thermal noise in those 172 00:09:33,160 --> 00:09:34,740 components way at the beginning is going to get 173 00:09:34,740 --> 00:09:36,200 amplified and make the whole thing meaningless. 174 00:09:36,200 --> 00:09:38,880 175 00:09:38,880 --> 00:09:44,070 Computer science deals with idealized components. 176 00:09:44,070 --> 00:09:47,430 We know as much as we want about these little program and 177 00:09:47,430 --> 00:09:51,820 data pieces that we're fitting things together. 178 00:09:51,820 --> 00:09:53,090 We don't have to worry about tolerance. 179 00:09:53,090 --> 00:09:57,960 And that means that, in building a large program, 180 00:09:57,960 --> 00:10:01,720 there's not all that much difference between what I can 181 00:10:01,720 --> 00:10:06,520 build and what I can imagine, because the parts are these 182 00:10:06,520 --> 00:10:10,250 abstract entities that I know as much as I want. 183 00:10:10,250 --> 00:10:13,430 I know about them as precisely as I'd like. 184 00:10:13,430 --> 00:10:15,920 So as opposed to other kinds of engineering, where the 185 00:10:15,920 --> 00:10:17,830 constraints on what you can build are the constraints of 186 00:10:17,830 --> 00:10:19,810 physical systems, the constraints of physics and 187 00:10:19,810 --> 00:10:24,160 noise and approximation, the constraints imposed in 188 00:10:24,160 --> 00:10:26,640 building large software systems are the limitations of 189 00:10:26,640 --> 00:10:28,930 our own minds. 190 00:10:28,930 --> 00:10:32,460 So in that sense, computer science is like an abstract 191 00:10:32,460 --> 00:10:33,530 form of engineering. 192 00:10:33,530 --> 00:10:35,680 It's the kind of engineering where you ignore the 193 00:10:35,680 --> 00:10:37,645 constraints that are imposed by reality. 194 00:10:37,645 --> 00:10:42,050 195 00:10:42,050 --> 00:10:46,400 Well, what are some of these techniques? 196 00:10:46,400 --> 00:10:47,830 They're not special to computer science. 197 00:10:47,830 --> 00:10:50,360 198 00:10:50,360 --> 00:10:54,140 First technique, which is used in all of engineering, is a 199 00:10:54,140 --> 00:10:57,785 kind of abstraction called black-box abstraction. 200 00:10:57,785 --> 00:11:07,670 201 00:11:07,670 --> 00:11:14,340 Take something and build a box about it. 202 00:11:14,340 --> 00:11:19,220 Let's see, for example, if we looked at that square root 203 00:11:19,220 --> 00:11:29,678 method, I might want to take that and build a box. 204 00:11:29,678 --> 00:11:38,980 That sort of says, to find the square root of X. And that 205 00:11:38,980 --> 00:11:42,560 might be a whole complicated set of rules. 206 00:11:42,560 --> 00:11:46,280 And that might end up being a kind of thing where I can put 207 00:11:46,280 --> 00:11:50,270 in, say, 36 and say, what's the square root of 36? 208 00:11:50,270 --> 00:11:51,520 And out comes 6. 209 00:11:51,520 --> 00:11:53,880 210 00:11:53,880 --> 00:11:59,630 And the important thing is that I'd like to design that 211 00:11:59,630 --> 00:12:05,080 so that if George comes along and would like to compute, 212 00:12:05,080 --> 00:12:11,580 say, the square root of A plus the square root of B, he can 213 00:12:11,580 --> 00:12:14,930 take this thing and use it as a module without having to 214 00:12:14,930 --> 00:12:16,760 look inside and build something that looks like 215 00:12:16,760 --> 00:12:24,960 this, like an A and a B and a square root box and another 216 00:12:24,960 --> 00:12:32,660 square root box and then something that adds that would 217 00:12:32,660 --> 00:12:33,870 put out the answer. 218 00:12:33,870 --> 00:12:38,830 And you can see, just from the fact that I want to do that, 219 00:12:38,830 --> 00:12:41,560 is from George's point of view, the internals of what's 220 00:12:41,560 --> 00:12:44,170 in here should not be important. 221 00:12:44,170 --> 00:12:46,940 So for instance, it shouldn't matter that, when I wrote 222 00:12:46,940 --> 00:12:50,750 this, I said I want to find the square root of X. I could 223 00:12:50,750 --> 00:12:54,840 have said the square root of Y, or the square root of A, or 224 00:12:54,840 --> 00:12:56,890 anything at all. 225 00:12:56,890 --> 00:13:03,480 That's the fundamental notion of putting something in a box 226 00:13:03,480 --> 00:13:07,520 using black-box abstraction to suppress detail. 227 00:13:07,520 --> 00:13:10,070 And the reason for that is you want to go off and build 228 00:13:10,070 --> 00:13:11,990 bigger boxes. 229 00:13:11,990 --> 00:13:13,880 Now, there's another reason for doing black-box 230 00:13:13,880 --> 00:13:17,340 abstraction other than you want to suppress detail for 231 00:13:17,340 --> 00:13:18,310 building bigger boxes. 232 00:13:18,310 --> 00:13:24,880 Sometimes you want to say that your way of doing something, 233 00:13:24,880 --> 00:13:30,210 your how-to method, is an instance of a more general 234 00:13:30,210 --> 00:13:33,430 thing, and you'd like your language to be able to express 235 00:13:33,430 --> 00:13:35,560 that generality. 236 00:13:35,560 --> 00:13:37,800 Let me show you another example 237 00:13:37,800 --> 00:13:38,740 sticking with square roots. 238 00:13:38,740 --> 00:13:42,260 Let's go back and take another look at that slide with the 239 00:13:42,260 --> 00:13:44,380 square root algorithm on it. 240 00:13:44,380 --> 00:13:45,460 Remember what that says. 241 00:13:45,460 --> 00:13:50,700 That says, in order to do something, I make a guess, and 242 00:13:50,700 --> 00:13:53,800 I improve that guess, and I sort of keep 243 00:13:53,800 --> 00:13:56,970 improving that guess. 244 00:13:56,970 --> 00:13:59,560 So there's the general strategy of, I'm looking for 245 00:13:59,560 --> 00:14:02,440 something, and the way I find it is that I 246 00:14:02,440 --> 00:14:04,280 keep improving it. 247 00:14:04,280 --> 00:14:10,930 Now, that's a particular case of another kind of strategy 248 00:14:10,930 --> 00:14:14,176 for finding a fixed point of something. 249 00:14:14,176 --> 00:14:17,660 So you have a fixed point of a function. 250 00:14:17,660 --> 00:14:26,090 A fixed point of a function is something, is a value. 251 00:14:26,090 --> 00:14:30,710 A fixed point of a function F is a value Y, such that F of Y 252 00:14:30,710 --> 00:14:41,592 equals Y. And the way I might do that is start with a guess. 253 00:14:41,592 --> 00:14:44,630 And then if I want something that doesn't change when I 254 00:14:44,630 --> 00:14:47,800 keep applying F, is I'll keep applying F over and over until 255 00:14:47,800 --> 00:14:50,150 that result doesn't change very much. 256 00:14:50,150 --> 00:14:52,290 So there's a general strategy. 257 00:14:52,290 --> 00:14:56,250 And then, for example, to compute the square root of X, 258 00:14:56,250 --> 00:15:00,780 I can try and find a fixed point of the function which 259 00:15:00,780 --> 00:15:05,020 takes Y to the average of X/Y. And the idea that is that if I 260 00:15:05,020 --> 00:15:09,300 really had Y equal to the square root of X, then Y and 261 00:15:09,300 --> 00:15:12,080 X/Y would be the same value. 262 00:15:12,080 --> 00:15:16,370 They'd both be the square root of X, because X over the 263 00:15:16,370 --> 00:15:19,080 square root of X is the square root of X. 264 00:15:19,080 --> 00:15:23,860 And so the average if Y were equal to the square of X, then 265 00:15:23,860 --> 00:15:26,230 the average wouldn't change. 266 00:15:26,230 --> 00:15:27,530 So the square root of X is a fixed point of 267 00:15:27,530 --> 00:15:30,250 that particular function. 268 00:15:30,250 --> 00:15:34,010 Now, what I'd like to have, I'd like to express the 269 00:15:34,010 --> 00:15:36,430 general strategy for finding fixed points. 270 00:15:36,430 --> 00:15:37,210 So what I might imagine doing, is to find, is to be able to 271 00:15:37,210 --> 00:15:37,309 use my language to define a box that says "fixed point," 272 00:15:37,309 --> 00:15:37,417 just like I could make a box that says "square root." And 273 00:15:37,417 --> 00:15:38,667 I'd like to be able to express this in my language. 274 00:15:38,667 --> 00:15:56,350 275 00:15:56,350 --> 00:16:00,870 So I'd like to express not only the imperative how-to 276 00:16:00,870 --> 00:16:03,620 knowledge of a particular thing like square root, but 277 00:16:03,620 --> 00:16:05,600 I'd like to be able to express the imperative knowledge of 278 00:16:05,600 --> 00:16:09,930 how to do a general thing like how to find fixed point. 279 00:16:09,930 --> 00:16:12,090 And in fact, let's go back and look at that slide again. 280 00:16:12,090 --> 00:16:15,010 281 00:16:15,010 --> 00:16:23,380 See, not only is this a piece of imperative knowledge, how 282 00:16:23,380 --> 00:16:27,190 to find a fixed point, but over here on the bottom, 283 00:16:27,190 --> 00:16:29,890 there's another piece of imperative knowledge which 284 00:16:29,890 --> 00:16:34,350 says, one way to compute square root is to apply this 285 00:16:34,350 --> 00:16:36,140 general fixed point method. 286 00:16:36,140 --> 00:16:37,710 So I'd like to also be able to express 287 00:16:37,710 --> 00:16:39,700 that imperative knowledge. 288 00:16:39,700 --> 00:16:40,650 What would that look like? 289 00:16:40,650 --> 00:16:46,010 That would say, this fixed point box is such that if I 290 00:16:46,010 --> 00:16:56,980 input to it the function that takes Y to the average of Y 291 00:16:56,980 --> 00:17:04,300 and X/Y, then what should come out of that fixed point box is 292 00:17:04,300 --> 00:17:06,200 a method for finding square roots. 293 00:17:06,200 --> 00:17:08,800 294 00:17:08,800 --> 00:17:10,829 So in these boxes we're building, we're not only 295 00:17:10,829 --> 00:17:16,369 building boxes that you input numbers and output numbers, 296 00:17:16,369 --> 00:17:19,410 we're going to be building in boxes that, in effect, compute 297 00:17:19,410 --> 00:17:22,250 methods like finding square root. 298 00:17:22,250 --> 00:17:27,480 And my take is their inputs functions, like Y goes to the 299 00:17:27,480 --> 00:17:32,360 average of Y and X/Y. The reason we want to do that, the 300 00:17:32,360 --> 00:17:35,425 reason this is a procedure, will end up being a procedure, 301 00:17:35,425 --> 00:17:39,640 as we'll see, whose value is another procedure, the reason 302 00:17:39,640 --> 00:17:42,630 we want to do that is because procedures are going to be our 303 00:17:42,630 --> 00:17:47,960 ways of talking about imperative knowledge. 304 00:17:47,960 --> 00:17:50,560 And the way to make that very powerful is to be able to talk 305 00:17:50,560 --> 00:17:53,260 about other kinds of knowledge. 306 00:17:53,260 --> 00:17:55,930 So here is a procedure that, in effect, talks about another 307 00:17:55,930 --> 00:17:59,450 procedure, a general strategy that itself talks about 308 00:17:59,450 --> 00:18:00,700 general strategies. 309 00:18:00,700 --> 00:18:04,290 310 00:18:04,290 --> 00:18:08,370 Well, our first topic in this course-- there'll be three 311 00:18:08,370 --> 00:18:11,070 major topics-- will be black-box abstraction. 312 00:18:11,070 --> 00:18:15,150 Let's look at that in a little bit more detail. 313 00:18:15,150 --> 00:18:23,910 What we're going to do is we will start out talking about 314 00:18:23,910 --> 00:18:27,480 how Lisp is built up out of primitive objects. 315 00:18:27,480 --> 00:18:29,580 What does the language supply with us? 316 00:18:29,580 --> 00:18:32,690 And we'll see that there are primitive procedures and 317 00:18:32,690 --> 00:18:35,620 primitive data. 318 00:18:35,620 --> 00:18:38,510 Then we're going to see, how do you take those primitives 319 00:18:38,510 --> 00:18:41,940 and combine them to make more complicated things, means of 320 00:18:41,940 --> 00:18:42,860 combination? 321 00:18:42,860 --> 00:18:44,824 And what we'll see is that there are ways of putting 322 00:18:44,824 --> 00:18:47,850 things together, putting primitive procedures together 323 00:18:47,850 --> 00:18:50,960 to make more complicated procedures. 324 00:18:50,960 --> 00:18:53,250 And we'll see how to put primitive data together to 325 00:18:53,250 --> 00:18:55,830 make compound data. 326 00:18:55,830 --> 00:18:59,700 Then we'll say, well, having made those compounds things, 327 00:18:59,700 --> 00:19:02,830 how do you abstract them? 328 00:19:02,830 --> 00:19:05,290 How do you put those black boxes around them so you can 329 00:19:05,290 --> 00:19:08,090 use them as components in more complex things? 330 00:19:08,090 --> 00:19:11,640 And we'll see that's done by defining procedures and a 331 00:19:11,640 --> 00:19:13,740 technique for dealing with compound data called data 332 00:19:13,740 --> 00:19:15,540 abstraction. 333 00:19:15,540 --> 00:19:19,150 And then, what's maybe the most important thing, is going 334 00:19:19,150 --> 00:19:21,650 from just the rules to how does an expert work? 335 00:19:21,650 --> 00:19:25,800 How do you express common patterns of doing things, like 336 00:19:25,800 --> 00:19:28,580 saying, well, there's a general method of fixed point 337 00:19:28,580 --> 00:19:32,822 and square root is a particular case of that? 338 00:19:32,822 --> 00:19:34,290 And we're going to use-- 339 00:19:34,290 --> 00:19:36,640 I've already hinted at it-- something called higher-order 340 00:19:36,640 --> 00:19:40,770 procedures, namely procedures whose inputs and outputs are 341 00:19:40,770 --> 00:19:43,230 themselves procedures. 342 00:19:43,230 --> 00:19:44,900 And then we'll also see something very interesting. 343 00:19:44,900 --> 00:19:47,730 We'll see, as we go further and further on and become more 344 00:19:47,730 --> 00:19:50,310 abstract, there'll be very-- 345 00:19:50,310 --> 00:19:53,700 well, the line between what we consider to be data and what 346 00:19:53,700 --> 00:19:56,920 we consider to be procedures is going to blur at an 347 00:19:56,920 --> 00:19:58,170 incredible rate. 348 00:19:58,170 --> 00:20:03,270 349 00:20:03,270 --> 00:20:06,300 Well, that's our first subject, black-box 350 00:20:06,300 --> 00:20:07,020 abstraction. 351 00:20:07,020 --> 00:20:08,270 Let's look at the second topic. 352 00:20:08,270 --> 00:20:10,640 353 00:20:10,640 --> 00:20:13,510 I can introduce it like this. 354 00:20:13,510 --> 00:20:19,590 See, suppose I want to express the idea-- 355 00:20:19,590 --> 00:20:22,790 remember, we're talking about ideas-- 356 00:20:22,790 --> 00:20:30,950 suppose I want to express the idea that I can take something 357 00:20:30,950 --> 00:20:36,070 and multiply it by the sum of two other things. 358 00:20:36,070 --> 00:20:40,180 So for example, I might say, if I had 1 and 3 and multiply 359 00:20:40,180 --> 00:20:41,920 that by 2, I get 8. 360 00:20:41,920 --> 00:20:43,930 But I'm talking about the general idea of what's called 361 00:20:43,930 --> 00:20:46,470 linear combination, that you can add two things and 362 00:20:46,470 --> 00:20:49,170 multiply them by something else. 363 00:20:49,170 --> 00:20:51,040 It's very easy when I think about it for numbers, but 364 00:20:51,040 --> 00:20:56,060 suppose I also want to use that same idea to think about, 365 00:20:56,060 --> 00:21:00,920 I could add two vectors, a1 and a2, and then scale them by 366 00:21:00,920 --> 00:21:03,060 some factor x and get another vector. 367 00:21:03,060 --> 00:21:08,570 Or I might say, I want to think about a1 and a2 as being 368 00:21:08,570 --> 00:21:13,720 polynomials, and I might want to add those two polynomials 369 00:21:13,720 --> 00:21:16,680 and then multiply them by 2 to get a more complicated one. 370 00:21:16,680 --> 00:21:20,020 371 00:21:20,020 --> 00:21:24,650 Or a1 and a2 might be electrical signals, and I 372 00:21:24,650 --> 00:21:26,870 might want to think about summing those two electrical 373 00:21:26,870 --> 00:21:29,350 signals and then putting the whole thing through an 374 00:21:29,350 --> 00:21:33,890 amplifier, multiplying it by some factor of 2 or something. 375 00:21:33,890 --> 00:21:34,850 The idea is I want to think about the 376 00:21:34,850 --> 00:21:38,530 general notion of that. 377 00:21:38,530 --> 00:21:42,880 Now, if our language is going to be good language for 378 00:21:42,880 --> 00:21:47,960 expressing those kind of general ideas, if I really, 379 00:21:47,960 --> 00:21:55,190 really can do that, I'd like to be able to say I'm going to 380 00:21:55,190 --> 00:22:03,660 multiply by x the sum of a1 and a2, and I'd like that to 381 00:22:03,660 --> 00:22:07,470 express the general idea of all different kinds of things 382 00:22:07,470 --> 00:22:09,980 that a1 and a2 could be. 383 00:22:09,980 --> 00:22:11,690 Now, if you think about that, there's a problem, because 384 00:22:11,690 --> 00:22:16,370 after all, the actual primitive operations that go 385 00:22:16,370 --> 00:22:17,870 on in the machine are obviously going to be 386 00:22:17,870 --> 00:22:22,070 different if I'm adding two numbers than if I'm adding two 387 00:22:22,070 --> 00:22:25,790 polynomials, or if I'm adding the representation of two 388 00:22:25,790 --> 00:22:27,940 electrical signals or wave forms. 389 00:22:27,940 --> 00:22:30,950 Somewhere, there has to be the knowledge of the kinds of 390 00:22:30,950 --> 00:22:33,140 various things that you can add and the 391 00:22:33,140 --> 00:22:34,390 ways of adding them. 392 00:22:34,390 --> 00:22:37,110 393 00:22:37,110 --> 00:22:39,430 Now, to construct such a system, the question is, where 394 00:22:39,430 --> 00:22:41,090 do I put that knowledge? 395 00:22:41,090 --> 00:22:43,280 How do I think about the different kinds 396 00:22:43,280 --> 00:22:44,480 of choices I have? 397 00:22:44,480 --> 00:22:48,310 And if tomorrow George comes up with a new kind of object 398 00:22:48,310 --> 00:22:51,770 that might be added and multiplied, how do I add 399 00:22:51,770 --> 00:22:54,280 George's new object to the system without screwing up 400 00:22:54,280 --> 00:22:57,690 everything that was already there? 401 00:22:57,690 --> 00:23:00,790 Well, that's going to be the second big topic, the way of 402 00:23:00,790 --> 00:23:03,720 controlling that kind of complexity. 403 00:23:03,720 --> 00:23:07,480 And the way you do that is by establishing conventional 404 00:23:07,480 --> 00:23:20,230 interfaces, agreed upon ways of plugging things together. 405 00:23:20,230 --> 00:23:23,530 Just like in electrical engineering, people have 406 00:23:23,530 --> 00:23:26,520 standard impedances for connectors, and then you know 407 00:23:26,520 --> 00:23:28,080 if you build something with one of those standard 408 00:23:28,080 --> 00:23:30,160 impedances, you can plug it together with something else. 409 00:23:30,160 --> 00:23:32,720 410 00:23:32,720 --> 00:23:34,300 So that's going to be our second large topic, 411 00:23:34,300 --> 00:23:35,690 conventional interfaces. 412 00:23:35,690 --> 00:23:39,000 What we're going to see is, first, we're going to talk 413 00:23:39,000 --> 00:23:41,400 about the problem of generic operations, which is the one I 414 00:23:41,400 --> 00:23:46,100 alluded to, things like "plus" that have to work with all 415 00:23:46,100 --> 00:23:47,350 different kinds of data. 416 00:23:47,350 --> 00:23:52,149 417 00:23:52,149 --> 00:23:54,660 So we talk about generic operations. 418 00:23:54,660 --> 00:23:58,270 Then we're going to talk about really large-scale structures. 419 00:23:58,270 --> 00:24:01,820 How do you put together very large programs that model the 420 00:24:01,820 --> 00:24:03,880 kinds of complex systems in the real world that 421 00:24:03,880 --> 00:24:05,480 you'd like to model? 422 00:24:05,480 --> 00:24:08,990 And what we're going to see is that there are two very 423 00:24:08,990 --> 00:24:11,770 important metaphors for putting together such systems. 424 00:24:11,770 --> 00:24:14,730 One is called object-oriented programming, where you sort of 425 00:24:14,730 --> 00:24:19,840 think of your system as a kind of society full of little 426 00:24:19,840 --> 00:24:21,150 things that interact by sending 427 00:24:21,150 --> 00:24:23,300 information between them. 428 00:24:23,300 --> 00:24:26,540 And then the second one is operations on aggregates, 429 00:24:26,540 --> 00:24:29,820 called streams, where you think of a large system put 430 00:24:29,820 --> 00:24:33,530 together kind of like a signal processing engineer puts 431 00:24:33,530 --> 00:24:35,020 together a large electrical system. 432 00:24:35,020 --> 00:24:38,610 433 00:24:38,610 --> 00:24:40,240 That's going to be our second topic. 434 00:24:40,240 --> 00:24:43,370 435 00:24:43,370 --> 00:24:47,000 Now, the third thing we're going to come to, the third 436 00:24:47,000 --> 00:24:49,640 basic technique for controlling complexity, is 437 00:24:49,640 --> 00:24:51,680 making new languages. 438 00:24:51,680 --> 00:24:54,370 Because sometimes, when you're sort of overwhelmed by the 439 00:24:54,370 --> 00:24:56,640 complexity of a design, the way that you control that 440 00:24:56,640 --> 00:25:01,330 complexity is to pick a new design language. 441 00:25:01,330 --> 00:25:03,330 And the purpose of the new design language will be to 442 00:25:03,330 --> 00:25:05,730 highlight different aspects of the system. 443 00:25:05,730 --> 00:25:08,360 It will suppress some kinds of details and emphasize other 444 00:25:08,360 --> 00:25:09,610 kinds of details. 445 00:25:09,610 --> 00:25:12,910 446 00:25:12,910 --> 00:25:15,910 This is going to be the most magical part of the course. 447 00:25:15,910 --> 00:25:18,350 We're going to start out by actually looking at the 448 00:25:18,350 --> 00:25:21,730 technology for building new computer languages. 449 00:25:21,730 --> 00:25:25,770 The first thing we're going to do is actually build in Lisp. 450 00:25:25,770 --> 00:25:29,210 451 00:25:29,210 --> 00:25:32,940 We're going to express in Lisp the process of interpreting 452 00:25:32,940 --> 00:25:33,800 Lisp itself. 453 00:25:33,800 --> 00:25:36,840 And that's going to be a very sort of self-circular thing. 454 00:25:36,840 --> 00:25:38,870 There's a little mystical symbol that 455 00:25:38,870 --> 00:25:40,750 has to do with that. 456 00:25:40,750 --> 00:25:45,500 The process of interpreting Lisp is sort of a giant wheel 457 00:25:45,500 --> 00:25:49,150 of two processes, apply and eval, which sort of constantly 458 00:25:49,150 --> 00:25:52,031 reduce expressions to each other. 459 00:25:52,031 --> 00:25:54,150 Then we're going to see all sorts of other magical things. 460 00:25:54,150 --> 00:25:56,690 Here's another magical symbol. 461 00:25:56,690 --> 00:25:59,870 462 00:25:59,870 --> 00:26:02,260 This is sort of the Y operator, which is, in some 463 00:26:02,260 --> 00:26:04,800 sense, the expression of infinity inside 464 00:26:04,800 --> 00:26:06,390 our procedural language. 465 00:26:06,390 --> 00:26:08,610 We'll take a look at that. 466 00:26:08,610 --> 00:26:11,880 In any case, this section of the course is called 467 00:26:11,880 --> 00:26:24,270 Metalinguistic Abstraction, abstracting by talking about 468 00:26:24,270 --> 00:26:25,535 how you construct new languages. 469 00:26:25,535 --> 00:26:30,270 470 00:26:30,270 --> 00:26:34,140 As I said, we're going to start out by looking at the 471 00:26:34,140 --> 00:26:35,530 process of interpretation. 472 00:26:35,530 --> 00:26:38,270 We're going to look at this apply-eval 473 00:26:38,270 --> 00:26:41,980 loop, and build Lisp. 474 00:26:41,980 --> 00:26:44,450 Then, just to show you that this is very general, we're 475 00:26:44,450 --> 00:26:47,100 going to use exactly the same technology to build a very 476 00:26:47,100 --> 00:26:49,780 different kind of language, a so-called logic programming 477 00:26:49,780 --> 00:26:52,880 language, where you don't really talk about procedures 478 00:26:52,880 --> 00:26:54,560 at all that have inputs and outputs. 479 00:26:54,560 --> 00:26:57,290 What you do is talk about relations between things. 480 00:26:57,290 --> 00:27:01,220 And then finally, we're going to talk about how you 481 00:27:01,220 --> 00:27:04,140 implement these things very concretely on the very 482 00:27:04,140 --> 00:27:06,830 simplest kind of machines. 483 00:27:06,830 --> 00:27:09,860 We'll see something like this. 484 00:27:09,860 --> 00:27:14,880 This is a picture of a chip, which is the Lisp interpreter 485 00:27:14,880 --> 00:27:17,330 that we will be talking about then in hardware. 486 00:27:17,330 --> 00:27:21,010 487 00:27:21,010 --> 00:27:24,840 Well, there's an outline of the course, three big topics. 488 00:27:24,840 --> 00:27:28,120 Black-box abstraction, conventional interfaces, 489 00:27:28,120 --> 00:27:31,590 metalinguistic abstraction. 490 00:27:31,590 --> 00:27:33,480 Now, let's take a break now and then we'll get started. 491 00:27:33,480 --> 00:28:04,770 [MUSIC PLAYING] 492 00:28:04,770 --> 00:28:08,020 Let's actually start in learning Lisp now. 493 00:28:08,020 --> 00:28:10,250 Actually, we'll start out by learning something much more 494 00:28:10,250 --> 00:28:12,320 important, maybe the very most important thing in this 495 00:28:12,320 --> 00:28:16,220 course, which is not Lisp, in particular, of course, but 496 00:28:16,220 --> 00:28:20,320 rather a general framework for thinking about languages that 497 00:28:20,320 --> 00:28:21,970 I already alluded to. 498 00:28:21,970 --> 00:28:24,420 When somebody tells you they're going to show you a 499 00:28:24,420 --> 00:28:27,150 language, what you should say is, what I'd like you to tell 500 00:28:27,150 --> 00:28:32,510 me is what are the primitive elements? 501 00:28:32,510 --> 00:28:37,490 502 00:28:37,490 --> 00:28:38,930 What does the language come with? 503 00:28:38,930 --> 00:28:43,650 Then, what are the ways you put those together? 504 00:28:43,650 --> 00:28:46,720 What are the means of combination? 505 00:28:46,720 --> 00:28:50,190 506 00:28:50,190 --> 00:28:53,400 What are the things that allow you to take these primitive 507 00:28:53,400 --> 00:28:57,920 elements and build bigger things out of them? 508 00:28:57,920 --> 00:29:01,280 What are the ways of putting things together? 509 00:29:01,280 --> 00:29:04,890 And then, what are the means of abstraction? 510 00:29:04,890 --> 00:29:08,110 511 00:29:08,110 --> 00:29:15,830 How do we take those complicated things and draw 512 00:29:15,830 --> 00:29:16,750 those boxes around them? 513 00:29:16,750 --> 00:29:20,180 How do we name them so that we can now use them as if they 514 00:29:20,180 --> 00:29:22,810 were primitive elements in making still 515 00:29:22,810 --> 00:29:23,790 more complex things? 516 00:29:23,790 --> 00:29:26,850 And so on, and so on, and so on. 517 00:29:26,850 --> 00:29:28,580 So when someone says to you, gee, I have a great new 518 00:29:28,580 --> 00:29:32,900 computer language, you don't say, how many characters does 519 00:29:32,900 --> 00:29:35,810 it take to invert a matrix? 520 00:29:35,810 --> 00:29:37,460 It's irrelevant. 521 00:29:37,460 --> 00:29:41,220 What you say is, if the language did not come with 522 00:29:41,220 --> 00:29:43,470 matrices built in or with something else built in, how 523 00:29:43,470 --> 00:29:45,910 could I then build that thing? 524 00:29:45,910 --> 00:29:47,590 What are the means of combination which would allow 525 00:29:47,590 --> 00:29:48,610 me to do that? 526 00:29:48,610 --> 00:29:52,450 And then, what are the means of abstraction which allow me 527 00:29:52,450 --> 00:29:55,750 then to use those as elements in making more complicated 528 00:29:55,750 --> 00:29:57,000 things yet? 529 00:29:57,000 --> 00:29:58,960 530 00:29:58,960 --> 00:30:02,330 Well, we're going to see that Lisp has some primitive data 531 00:30:02,330 --> 00:30:05,280 and some primitive procedures. 532 00:30:05,280 --> 00:30:08,410 In fact, let's really start. 533 00:30:08,410 --> 00:30:09,950 And here's a piece of primitive data in 534 00:30:09,950 --> 00:30:16,710 Lisp, number 3. 535 00:30:16,710 --> 00:30:18,800 Actually, if I'm being very pedantic, that's 536 00:30:18,800 --> 00:30:19,790 not the number 3. 537 00:30:19,790 --> 00:30:24,620 That's some symbol that represents Plato's concept of 538 00:30:24,620 --> 00:30:27,060 the number 3. 539 00:30:27,060 --> 00:30:30,500 And here's another. 540 00:30:30,500 --> 00:30:35,370 Here's some more primitive data in Lisp, 17.4. 541 00:30:35,370 --> 00:30:40,940 Or actually, some representation of 17.4. 542 00:30:40,940 --> 00:30:43,795 And here's another one, 5. 543 00:30:43,795 --> 00:30:46,750 544 00:30:46,750 --> 00:30:48,490 Here's another primitive object that's 545 00:30:48,490 --> 00:30:52,130 built in Lisp, addition. 546 00:30:52,130 --> 00:30:56,830 Actually, to use the same kind of pedantic-- this is a name 547 00:30:56,830 --> 00:31:00,140 for the primitive method of adding things. 548 00:31:00,140 --> 00:31:02,920 Just like this is a name for Plato's number 3, this is a 549 00:31:02,920 --> 00:31:10,370 name for Plato's concept of how you add things. 550 00:31:10,370 --> 00:31:12,370 So those are some primitive elements. 551 00:31:12,370 --> 00:31:14,090 I can put them together. 552 00:31:14,090 --> 00:31:18,140 I can say, gee, what's the sum of 3 and 17.4 and 5? 553 00:31:18,140 --> 00:31:25,580 And the way I do that is to say, let's apply the sum 554 00:31:25,580 --> 00:31:27,600 operator to these three numbers. 555 00:31:27,600 --> 00:31:28,310 And I should get, what? 556 00:31:28,310 --> 00:31:29,690 8, 17. 557 00:31:29,690 --> 00:31:34,390 25.4. 558 00:31:34,390 --> 00:31:37,590 So I should be able to ask Lisp what the value of this 559 00:31:37,590 --> 00:31:43,050 is, and it will return 25.4. 560 00:31:43,050 --> 00:31:44,610 Let's introduce some names. 561 00:31:44,610 --> 00:31:50,950 This thing that I typed is called a combination. 562 00:31:50,950 --> 00:31:56,830 563 00:31:56,830 --> 00:31:59,040 And a combination consists, in general, 564 00:31:59,040 --> 00:32:02,790 of applying an operator-- 565 00:32:02,790 --> 00:32:04,220 so this is an operator-- 566 00:32:04,220 --> 00:32:09,500 567 00:32:09,500 --> 00:32:13,190 to some operands. 568 00:32:13,190 --> 00:32:14,440 These are the operands. 569 00:32:14,440 --> 00:32:21,760 570 00:32:21,760 --> 00:32:23,640 And of course, I can make more complex things. 571 00:32:23,640 --> 00:32:25,950 The reason I can get complexity out of this is 572 00:32:25,950 --> 00:32:30,290 because the operands themselves, in general, can be 573 00:32:30,290 --> 00:32:31,200 combinations. 574 00:32:31,200 --> 00:32:37,770 So for instance, I could say, what is the sum of 3 and the 575 00:32:37,770 --> 00:32:45,660 product of 5 and 6 and 8 and 2? 576 00:32:45,660 --> 00:32:47,520 And I should get-- let's see-- 577 00:32:47,520 --> 00:32:52,355 30, 40, 43. 578 00:32:52,355 --> 00:32:56,520 So Lisp should tell me that that's 43. 579 00:32:56,520 --> 00:33:01,610 Forming combinations is the basic needs of combination 580 00:33:01,610 --> 00:33:04,690 that we'll be looking at. 581 00:33:04,690 --> 00:33:10,520 And then, well, you see some syntax here. 582 00:33:10,520 --> 00:33:16,940 Lisp uses what's called prefix notation, which means that the 583 00:33:16,940 --> 00:33:25,400 operator is written to the left of the operands. 584 00:33:25,400 --> 00:33:27,810 It's just a convention. 585 00:33:27,810 --> 00:33:29,960 And notice, it's fully parenthesized. 586 00:33:29,960 --> 00:33:32,170 And the parentheses make it completely unambiguous. 587 00:33:32,170 --> 00:33:36,840 So by looking at this, I can see that there's the operator, 588 00:33:36,840 --> 00:33:42,760 and there are 1, 2, 3, 4 operands. 589 00:33:42,760 --> 00:33:46,980 And I can see that the second operand here is itself some 590 00:33:46,980 --> 00:33:52,500 combination that has one operator and two operands. 591 00:33:52,500 --> 00:33:55,740 Parentheses in Lisp are a little bit, or are very unlike 592 00:33:55,740 --> 00:33:57,630 parentheses in conventional mathematics. 593 00:33:57,630 --> 00:34:01,400 In mathematics, we sort of use them to mean grouping, and it 594 00:34:01,400 --> 00:34:03,140 sort of doesn't hurt if sometimes you leave out 595 00:34:03,140 --> 00:34:04,610 parentheses if people understand 596 00:34:04,610 --> 00:34:05,790 that that's a group. 597 00:34:05,790 --> 00:34:07,660 And in general, it doesn't hurt if you put in extra 598 00:34:07,660 --> 00:34:09,760 parentheses, because that maybe makes the 599 00:34:09,760 --> 00:34:10,570 grouping more distinct. 600 00:34:10,570 --> 00:34:13,010 Lisp is not like that. 601 00:34:13,010 --> 00:34:17,020 In Lisp, you cannot leave out parentheses, and you cannot 602 00:34:17,020 --> 00:34:20,530 put in extra parentheses, because putting in parentheses 603 00:34:20,530 --> 00:34:23,980 always means, exactly and precisely, this is a 604 00:34:23,980 --> 00:34:27,260 combination which has meaning, applying 605 00:34:27,260 --> 00:34:29,050 operators to operands. 606 00:34:29,050 --> 00:34:32,290 And if I left this out, if I left those parentheses out, it 607 00:34:32,290 --> 00:34:35,469 would mean something else. 608 00:34:35,469 --> 00:34:38,100 In fact, the way to think about this, is really what I'm 609 00:34:38,100 --> 00:34:42,280 doing when I write something like this is writing a tree. 610 00:34:42,280 --> 00:34:48,909 So this combination is a tree that has a plus and then a 3 611 00:34:48,909 --> 00:34:54,500 and then a something else and an 8 and a 2. 612 00:34:54,500 --> 00:34:57,670 And then this something else here is itself a little 613 00:34:57,670 --> 00:35:03,770 subtree that has a star and a 5 and a 6. 614 00:35:03,770 --> 00:35:07,400 And the way to think of that is, really, what's going on 615 00:35:07,400 --> 00:35:13,260 are we're writing these trees, and parentheses are just a way 616 00:35:13,260 --> 00:35:16,390 to write this two-dimensional structure as a linear 617 00:35:16,390 --> 00:35:19,130 character string. 618 00:35:19,130 --> 00:35:22,110 Because at least when Lisp first started and people had 619 00:35:22,110 --> 00:35:24,630 teletypes or punch cards or whatever, this was more 620 00:35:24,630 --> 00:35:25,890 convenient. 621 00:35:25,890 --> 00:35:29,590 Maybe if Lisp started today, the syntax of Lisp 622 00:35:29,590 --> 00:35:31,900 would look like that. 623 00:35:31,900 --> 00:35:33,720 Well, let's look at what that actually 624 00:35:33,720 --> 00:35:36,450 looks like on the computer. 625 00:35:36,450 --> 00:35:39,320 Here I have a Lisp interaction set up. 626 00:35:39,320 --> 00:35:41,060 There's a editor. 627 00:35:41,060 --> 00:35:43,980 And on the top, I'm going to type some values and ask Lisp 628 00:35:43,980 --> 00:35:45,050 what they are. 629 00:35:45,050 --> 00:35:46,750 So for instance, I can say to Lisp, what's the 630 00:35:46,750 --> 00:35:49,370 value of that symbol? 631 00:35:49,370 --> 00:35:50,050 That's 3. 632 00:35:50,050 --> 00:35:51,850 And I ask Lisp to evaluate it. 633 00:35:51,850 --> 00:35:55,530 And there you see Lisp has returned on the bottom, and 634 00:35:55,530 --> 00:35:57,690 said, oh yeah, that's 3. 635 00:35:57,690 --> 00:36:06,490 Or I can say, what's the sum of 3 and 4 and 8? 636 00:36:06,490 --> 00:36:08,950 What's that combination? 637 00:36:08,950 --> 00:36:10,660 And ask Lisp to evaluate it. 638 00:36:10,660 --> 00:36:14,660 639 00:36:14,660 --> 00:36:16,246 That's 15. 640 00:36:16,246 --> 00:36:19,210 Or I can type in something more complicated. 641 00:36:19,210 --> 00:36:29,510 I can say, what's the sum of the product of 3 and the sum 642 00:36:29,510 --> 00:36:35,210 of 7 and 19.5? 643 00:36:35,210 --> 00:36:37,820 And you'll notice here that Lisp has something built in 644 00:36:37,820 --> 00:36:39,660 that helps me keep track of all these parentheses. 645 00:36:39,660 --> 00:36:42,260 Watch as I type the next closed parentheses, which is 646 00:36:42,260 --> 00:36:45,620 going to close the combination starting with the star. 647 00:36:45,620 --> 00:36:48,220 The opening one will flash. 648 00:36:48,220 --> 00:36:50,200 Here, I'll rub those out and do it again. 649 00:36:50,200 --> 00:36:53,590 Type close, and you see that closes the plus. 650 00:36:53,590 --> 00:36:57,910 Close again, that closes the star. 651 00:36:57,910 --> 00:36:59,570 Now I'm back to the sum, and maybe I'm going to 652 00:36:59,570 --> 00:37:01,480 add that all to 4. 653 00:37:01,480 --> 00:37:02,630 That closes the plus. 654 00:37:02,630 --> 00:37:05,750 Now I have a complete combination, and I can ask 655 00:37:05,750 --> 00:37:07,170 Lisp for the value of that. 656 00:37:07,170 --> 00:37:11,310 That kind of paren balancing is something that's built into 657 00:37:11,310 --> 00:37:13,630 a lot of Lisp systems to help you keep track, because it is 658 00:37:13,630 --> 00:37:16,760 kind of hard just by hand doing all these parentheses. 659 00:37:16,760 --> 00:37:20,520 There's another kind of convention for keeping track 660 00:37:20,520 --> 00:37:21,100 of parentheses. 661 00:37:21,100 --> 00:37:24,800 Let me write another complicated combination. 662 00:37:24,800 --> 00:37:33,170 Let's take the sum of the product of 3 and 5 and add 663 00:37:33,170 --> 00:37:34,090 that to something. 664 00:37:34,090 --> 00:37:37,510 And now what I'm going to do is I'm going to indent so that 665 00:37:37,510 --> 00:37:39,830 the operands are written vertically. 666 00:37:39,830 --> 00:37:47,250 Which the sum of that and the product of 47 and-- 667 00:37:47,250 --> 00:37:50,340 let's say the product of 47 with a 668 00:37:50,340 --> 00:37:54,520 difference of 20 and 6.8. 669 00:37:54,520 --> 00:37:58,236 That means subtract 6.8 from 20. 670 00:37:58,236 --> 00:38:00,050 And then you see the parentheses close. 671 00:38:00,050 --> 00:38:01,890 Close the minus. 672 00:38:01,890 --> 00:38:03,572 Close the star. 673 00:38:03,572 --> 00:38:05,150 And now let's get another operator. 674 00:38:05,150 --> 00:38:08,230 You see the Lisp editor here is indenting to the right 675 00:38:08,230 --> 00:38:12,660 position automatically to help me keep track. 676 00:38:12,660 --> 00:38:13,920 I'll do that again. 677 00:38:13,920 --> 00:38:16,220 I'll close that last parentheses again. 678 00:38:16,220 --> 00:38:17,470 You see it balances the plus. 679 00:38:17,470 --> 00:38:20,340 680 00:38:20,340 --> 00:38:24,100 Now I can say, what's the value of that? 681 00:38:24,100 --> 00:38:29,620 So those two things, indenting to the right level, which is 682 00:38:29,620 --> 00:38:34,230 called pretty printing, and flashing parentheses, are two 683 00:38:34,230 --> 00:38:37,120 things that a lot of Lisp systems have built in to help 684 00:38:37,120 --> 00:38:37,660 you keep track. 685 00:38:37,660 --> 00:38:38,910 And you should learn how to use them. 686 00:38:38,910 --> 00:38:42,020 687 00:38:42,020 --> 00:38:44,640 Well, those are the primitives. 688 00:38:44,640 --> 00:38:46,190 There's a means of combination. 689 00:38:46,190 --> 00:38:49,360 Now let's go up to the means of abstraction. 690 00:38:49,360 --> 00:38:52,400 I'd like to be able to take the idea that I do some 691 00:38:52,400 --> 00:38:54,820 combination like this, and abstract it and give it a 692 00:38:54,820 --> 00:38:57,300 simple name, so I can use that as an element. 693 00:38:57,300 --> 00:39:01,770 And I do that in Lisp with "define." So I can say, for 694 00:39:01,770 --> 00:39:14,515 example, define A to be the product of 5 and 5. 695 00:39:14,515 --> 00:39:17,936 696 00:39:17,936 --> 00:39:23,240 And now I could say, for example, to Lisp, what is the 697 00:39:23,240 --> 00:39:26,742 product of A and A? 698 00:39:26,742 --> 00:39:31,980 And this should be 25, and this should be 625. 699 00:39:31,980 --> 00:39:36,200 And then, crucial thing, I can now use A-- 700 00:39:36,200 --> 00:39:38,360 here I've used it in a combination-- 701 00:39:38,360 --> 00:39:41,770 but I could use that in other more complicated things that I 702 00:39:41,770 --> 00:39:43,440 name in turn. 703 00:39:43,440 --> 00:39:53,970 So I could say, define B to be the sum of, we'll say, A and 704 00:39:53,970 --> 00:40:00,260 the product of 5 and A. And then close the plus. 705 00:40:00,260 --> 00:40:03,470 706 00:40:03,470 --> 00:40:04,920 Let's take a look at that on the computer and 707 00:40:04,920 --> 00:40:07,850 see how that looks. 708 00:40:07,850 --> 00:40:10,515 So I'll just type what I wrote on the board. 709 00:40:10,515 --> 00:40:21,165 I could say, define A to be the product of 5 and 5. 710 00:40:21,165 --> 00:40:23,675 711 00:40:23,675 --> 00:40:25,640 And I'll tell that to Lisp. 712 00:40:25,640 --> 00:40:27,320 And notice what Lisp responded there with 713 00:40:27,320 --> 00:40:29,120 was an A in the bottom. 714 00:40:29,120 --> 00:40:31,680 In general, when you type in a definition in Lisp, it 715 00:40:31,680 --> 00:40:35,180 responds with the symbol being defined. 716 00:40:35,180 --> 00:40:39,200 Now I could say to Lisp, what is the product of A and A? 717 00:40:39,200 --> 00:40:42,266 718 00:40:42,266 --> 00:40:46,140 And it says that's 625. 719 00:40:46,140 --> 00:40:59,790 I can define B to be the sum of A and the product of 5 and 720 00:40:59,790 --> 00:41:03,110 A. Close a paren closes the star. 721 00:41:03,110 --> 00:41:04,600 Close the plus. 722 00:41:04,600 --> 00:41:11,030 Close the "define." Lisp says, OK, B, there on the bottom. 723 00:41:11,030 --> 00:41:13,110 And now I can say to Lisp, what's the value of B? 724 00:41:13,110 --> 00:41:17,100 725 00:41:17,100 --> 00:41:19,310 And I can say something more complicated, like what's the 726 00:41:19,310 --> 00:41:26,600 sum of A and the quotient of B and 5? 727 00:41:26,600 --> 00:41:30,430 That slash is divide, another primitive operator. 728 00:41:30,430 --> 00:41:33,830 I've divided B by 5, added it to A. Lisp 729 00:41:33,830 --> 00:41:36,830 says, OK, that's 55. 730 00:41:36,830 --> 00:41:39,810 So there's what it looks like. 731 00:41:39,810 --> 00:41:43,670 There's the basic means of defining something. 732 00:41:43,670 --> 00:41:47,870 It's the simplest kind of naming, but it's not really 733 00:41:47,870 --> 00:41:49,970 very powerful. 734 00:41:49,970 --> 00:41:51,760 See, what I'd really like to name-- 735 00:41:51,760 --> 00:41:53,510 remember, we're talking about general methods-- 736 00:41:53,510 --> 00:41:56,810 I'd like to name, oh, the general idea that, for 737 00:41:56,810 --> 00:42:11,440 example, I could multiply 5 by 5, or 6 by 6, or 1,001 by 738 00:42:11,440 --> 00:42:18,240 1,001, 1,001.7 by 1,001.7. 739 00:42:18,240 --> 00:42:22,350 I'd like to be able to name the general idea of 740 00:42:22,350 --> 00:42:23,970 multiplying something by itself. 741 00:42:23,970 --> 00:42:28,400 742 00:42:28,400 --> 00:42:28,960 Well, you know what that is. 743 00:42:28,960 --> 00:42:31,146 That's called squaring. 744 00:42:31,146 --> 00:42:43,640 And the way I can do that in Lisp is I can say, define to 745 00:42:43,640 --> 00:42:57,850 square something x, multiply x by itself. 746 00:42:57,850 --> 00:43:01,260 And then having done that, I could say to Lisp, for 747 00:43:01,260 --> 00:43:06,240 example, what's the square of 10? 748 00:43:06,240 --> 00:43:10,240 And Lisp will say 100. 749 00:43:10,240 --> 00:43:14,796 So now let's actually look at that a little more closely. 750 00:43:14,796 --> 00:43:17,040 Right, there's the definition of square. 751 00:43:17,040 --> 00:43:23,730 To square something, multiply it by itself. 752 00:43:23,730 --> 00:43:26,210 You see this x here. 753 00:43:26,210 --> 00:43:28,550 That x is kind of a pronoun, which is the something that 754 00:43:28,550 --> 00:43:31,380 I'm going to square. 755 00:43:31,380 --> 00:43:35,220 And what I do with it is I multiply x, I 756 00:43:35,220 --> 00:43:36,930 multiply it by itself. 757 00:43:36,930 --> 00:43:44,670 758 00:43:44,670 --> 00:43:44,775 OK. 759 00:43:44,775 --> 00:43:48,280 So there's the notation for defining a procedure. 760 00:43:48,280 --> 00:43:52,500 Actually, this is a little bit confusing, because this is 761 00:43:52,500 --> 00:43:53,830 sort of how I might use square. 762 00:43:53,830 --> 00:43:57,790 And I say square root of x or square root of 10, but it's 763 00:43:57,790 --> 00:44:00,300 not making it very clear that I'm actually naming something. 764 00:44:00,300 --> 00:44:02,970 765 00:44:02,970 --> 00:44:05,790 So let me write this definition in another way that 766 00:44:05,790 --> 00:44:06,770 makes it a little bit more clear 767 00:44:06,770 --> 00:44:08,420 that I'm naming something. 768 00:44:08,420 --> 00:44:28,250 I'll say, "define" square to be lambda of x times xx. 769 00:44:28,250 --> 00:44:36,550 770 00:44:36,550 --> 00:44:40,480 Here, I'm naming something square, just like over here, 771 00:44:40,480 --> 00:44:44,390 I'm naming something A. The thing that I'm naming square-- 772 00:44:44,390 --> 00:44:49,290 here, the thing I named A was the value of this combination. 773 00:44:49,290 --> 00:44:52,270 Here, the thing that I'm naming square is this thing 774 00:44:52,270 --> 00:44:55,610 that begins with lambda, and lambda is Lisp's way of saying 775 00:44:55,610 --> 00:44:56,860 make a procedure. 776 00:44:56,860 --> 00:45:00,150 777 00:45:00,150 --> 00:45:04,170 Let's look at that more closely on the slide. 778 00:45:04,170 --> 00:45:07,410 The way I read that definition is to say, I define square to 779 00:45:07,410 --> 00:45:09,910 be make a procedure-- 780 00:45:09,910 --> 00:45:12,730 781 00:45:12,730 --> 00:45:14,010 that's what the lambda is-- 782 00:45:14,010 --> 00:45:19,220 make a procedure with an argument named x. 783 00:45:19,220 --> 00:45:22,030 And what it does is return the results of 784 00:45:22,030 --> 00:45:24,920 multiplying x by itself. 785 00:45:24,920 --> 00:45:32,380 Now, in general, we're going to be using this top form of 786 00:45:32,380 --> 00:45:35,050 defining, just because it's a little bit more convenient. 787 00:45:35,050 --> 00:45:38,750 But don't lose sight of the fact that it's really this. 788 00:45:38,750 --> 00:45:41,530 In fact, as far as the Lisp interpreter's concerned, 789 00:45:41,530 --> 00:45:44,830 there's no difference between typing this to it and typing 790 00:45:44,830 --> 00:45:46,460 this to it. 791 00:45:46,460 --> 00:45:54,380 And there's a word for that, sort of syntactic sugar. 792 00:45:54,380 --> 00:45:58,400 What syntactic sugar means, it's having somewhat more 793 00:45:58,400 --> 00:46:01,060 convenient surface forms for typing something. 794 00:46:01,060 --> 00:46:04,470 So this is just really syntactic sugar for this 795 00:46:04,470 --> 00:46:07,310 underlying Greek thing with the lambda. 796 00:46:07,310 --> 00:46:09,710 And the reason you should remember that is don't forget 797 00:46:09,710 --> 00:46:12,430 that, when I write something like this, I'm 798 00:46:12,430 --> 00:46:14,380 really naming something. 799 00:46:14,380 --> 00:46:17,040 I'm naming something square, and the something that I'm 800 00:46:17,040 --> 00:46:21,620 naming square is a procedure that's getting constructed. 801 00:46:21,620 --> 00:46:24,820 Well, let's look at that on the computer, too. 802 00:46:24,820 --> 00:46:30,660 So I'll come and I'll say, define square of 803 00:46:30,660 --> 00:46:34,670 x to be times xx. 804 00:46:34,670 --> 00:46:49,570 805 00:46:49,570 --> 00:46:53,042 Now I'll tell Lisp that. 806 00:46:53,042 --> 00:46:56,580 It says "square." See, I've named something "square." Now, 807 00:46:56,580 --> 00:47:00,760 having done that, I can ask Lisp for, what's 808 00:47:00,760 --> 00:47:05,230 the square of 1,001? 809 00:47:05,230 --> 00:47:14,920 Or in general, I could say, what's the square of the sum 810 00:47:14,920 --> 00:47:17,340 of 5 and 7? 811 00:47:17,340 --> 00:47:22,532 812 00:47:22,532 --> 00:47:25,190 The square of 12's 144. 813 00:47:25,190 --> 00:47:28,080 Or I can use square itself as an element in some 814 00:47:28,080 --> 00:47:28,680 combination. 815 00:47:28,680 --> 00:47:36,240 I can say, what's the sum of the square of 3 and 816 00:47:36,240 --> 00:47:37,490 the square of 4? 817 00:47:37,490 --> 00:47:42,480 818 00:47:42,480 --> 00:47:44,950 9 and 16 is 25. 819 00:47:44,950 --> 00:47:49,580 Or I can use square as an element in some much more 820 00:47:49,580 --> 00:47:50,390 complicated thing. 821 00:47:50,390 --> 00:47:53,032 I can say, what's the square of, the sqare of, 822 00:47:53,032 --> 00:48:07,016 the square of 1,001? 823 00:48:07,016 --> 00:48:11,160 And there's the square of the square of the square of 1,001. 824 00:48:11,160 --> 00:48:15,620 Or I can say to Lisp, what is square itself? 825 00:48:15,620 --> 00:48:17,040 What's the value of that? 826 00:48:17,040 --> 00:48:21,040 And Lisp returns some conventional way of telling me 827 00:48:21,040 --> 00:48:22,200 that that's a procedure. 828 00:48:22,200 --> 00:48:24,990 It says, "compound procedure square." Remember, the value 829 00:48:24,990 --> 00:48:30,050 of square is this procedure, and the thing with the stars 830 00:48:30,050 --> 00:48:33,810 and the brackets are just Lisp's conventional way of 831 00:48:33,810 --> 00:48:37,010 describing that. 832 00:48:37,010 --> 00:48:40,830 Let's look at two more examples of defining. 833 00:48:40,830 --> 00:48:45,020 834 00:48:45,020 --> 00:48:47,210 Here are two more procedures. 835 00:48:47,210 --> 00:48:51,860 I can define the average of x and y to be the sum of x and y 836 00:48:51,860 --> 00:48:54,460 divided by 2. 837 00:48:54,460 --> 00:49:00,830 Or having had average and mean square, having had average and 838 00:49:00,830 --> 00:49:03,970 square, I can use that to talk about the mean square of 839 00:49:03,970 --> 00:49:08,325 something, which is the average of the square of x and 840 00:49:08,325 --> 00:49:10,790 the square of y. 841 00:49:10,790 --> 00:49:13,870 So for example, having done that, I could say, what's the 842 00:49:13,870 --> 00:49:24,915 mean square of 2 and 3? 843 00:49:24,915 --> 00:49:29,530 And I should get the average of 4 and 9, which is 6.5. 844 00:49:29,530 --> 00:49:32,970 845 00:49:32,970 --> 00:49:37,000 The key thing here is that, having defined square, I can 846 00:49:37,000 --> 00:49:38,560 use it as if it were primitive. 847 00:49:38,560 --> 00:49:41,410 848 00:49:41,410 --> 00:49:45,200 So if we look here on the slide, if I look at mean 849 00:49:45,200 --> 00:49:50,910 square, the person defining mean square doesn't have to 850 00:49:50,910 --> 00:49:54,660 know, at this point, whether square was something built 851 00:49:54,660 --> 00:49:57,540 into the language or whether it was a 852 00:49:57,540 --> 00:49:59,600 procedure that was defined. 853 00:49:59,600 --> 00:50:04,040 And that's a key thing in Lisp, that you do not make 854 00:50:04,040 --> 00:50:08,230 arbitrary distinctions between things that happen to be 855 00:50:08,230 --> 00:50:10,400 primitive in the language and things that 856 00:50:10,400 --> 00:50:12,740 happen to be built in. 857 00:50:12,740 --> 00:50:14,750 A person using that shouldn't even have to know. 858 00:50:14,750 --> 00:50:17,800 So the things you construct get used with all the power 859 00:50:17,800 --> 00:50:19,700 and flexibility as if they were primitives. 860 00:50:19,700 --> 00:50:21,470 In fact, you can drive that home by looking on the 861 00:50:21,470 --> 00:50:24,750 computer one more time. 862 00:50:24,750 --> 00:50:26,680 We talked about plus. 863 00:50:26,680 --> 00:50:29,920 And in fact, if I come here on the computer screen and say, 864 00:50:29,920 --> 00:50:31,745 what is the value of plus? 865 00:50:31,745 --> 00:50:34,380 866 00:50:34,380 --> 00:50:36,120 Notice what Lisp types out. 867 00:50:36,120 --> 00:50:38,230 On the bottom there, it typed out, "compound procedure 868 00:50:38,230 --> 00:50:43,070 plus." Because, in this system, it turns out that the 869 00:50:43,070 --> 00:50:45,770 addition operator is itself a compound procedure. 870 00:50:45,770 --> 00:50:48,140 And if I didn't just type that in, you'd never know that, and 871 00:50:48,140 --> 00:50:49,710 it wouldn't make any difference anyway. 872 00:50:49,710 --> 00:50:50,240 We don't care. 873 00:50:50,240 --> 00:50:52,500 It's below the level of the abstraction that 874 00:50:52,500 --> 00:50:54,120 we're dealing with. 875 00:50:54,120 --> 00:50:57,230 So the key thing is you cannot tell, should not be able to 876 00:50:57,230 --> 00:51:00,910 tell, in general, the difference between things that 877 00:51:00,910 --> 00:51:03,590 are built in and things that are compound. 878 00:51:03,590 --> 00:51:04,160 Why is that? 879 00:51:04,160 --> 00:51:06,630 Because the things that are compound have an abstraction 880 00:51:06,630 --> 00:51:09,420 wrapper wrapped around them. 881 00:51:09,420 --> 00:51:12,510 We've seen almost all the elements of Lisp now. 882 00:51:12,510 --> 00:51:15,090 There's only one more we have to look at, and that is how to 883 00:51:15,090 --> 00:51:16,510 make a case analysis. 884 00:51:16,510 --> 00:51:18,760 Let me show you what I mean. 885 00:51:18,760 --> 00:51:22,550 We might want to think about the mathematical definition of 886 00:51:22,550 --> 00:51:23,740 the absolute value functions. 887 00:51:23,740 --> 00:51:30,520 I might say the absolute value of x is the function which has 888 00:51:30,520 --> 00:51:35,670 the property that it's negative of x. 889 00:51:35,670 --> 00:51:42,580 For x less than 0, it's 0 for x equal to 0. 890 00:51:42,580 --> 00:51:46,360 And it's x for x greater than 0. 891 00:51:46,360 --> 00:51:49,190 892 00:51:49,190 --> 00:51:51,490 And Lisp has a way of making case analyses. 893 00:51:51,490 --> 00:51:55,210 Let me define for you absolute value. 894 00:51:55,210 --> 00:52:03,080 Say define the absolute value of x is conditional. 895 00:52:03,080 --> 00:52:05,075 This means case analysis, COND. 896 00:52:05,075 --> 00:52:08,773 897 00:52:08,773 --> 00:52:18,760 If x is less than 0, the answer is negate x. 898 00:52:18,760 --> 00:52:22,990 899 00:52:22,990 --> 00:52:24,290 What I've written here is a clause. 900 00:52:24,290 --> 00:52:29,490 901 00:52:29,490 --> 00:52:33,818 This whole thing is a conditional clause, 902 00:52:33,818 --> 00:52:36,380 and it has two parts. 903 00:52:36,380 --> 00:52:44,760 This part here is a predicate or a condition. 904 00:52:44,760 --> 00:52:45,640 That's a condition. 905 00:52:45,640 --> 00:52:47,680 And the condition is expressed by something called a 906 00:52:47,680 --> 00:52:51,170 predicate, and a predicate in Lisp is some sort of thing 907 00:52:51,170 --> 00:52:53,440 that returns either true or false. 908 00:52:53,440 --> 00:52:55,490 And you see Lisp has a primitive procedure, 909 00:52:55,490 --> 00:53:00,510 less-than, that tests whether something is true or false. 910 00:53:00,510 --> 00:53:06,940 And the other part of a clause is an action or a thing to do, 911 00:53:06,940 --> 00:53:07,930 in the case where that's true. 912 00:53:07,930 --> 00:53:12,130 And here, what I'm doing is negating x. 913 00:53:12,130 --> 00:53:13,300 The negation operator, the minus sign in Lisp is 914 00:53:13,300 --> 00:53:14,550 a little bit funny. 915 00:53:14,550 --> 00:53:17,880 916 00:53:17,880 --> 00:53:19,186 If there's two or more arguments, if there's two 917 00:53:19,186 --> 00:53:21,740 arguments it subtracts the second one from the first, and 918 00:53:21,740 --> 00:53:22,380 we saw that. 919 00:53:22,380 --> 00:53:25,280 And if there's one argument, it negates it. 920 00:53:25,280 --> 00:53:27,700 So this corresponds to that. 921 00:53:27,700 --> 00:53:28,960 And then there's another COND clause. 922 00:53:28,960 --> 00:53:34,630 It says, in the case where x is equal to 0, 923 00:53:34,630 --> 00:53:37,482 the answer is 0. 924 00:53:37,482 --> 00:53:43,480 And in the case where x is greater than 0, 925 00:53:43,480 --> 00:53:45,430 the answer is x. 926 00:53:45,430 --> 00:53:46,790 Close that clause. 927 00:53:46,790 --> 00:53:48,250 Close the COND. 928 00:53:48,250 --> 00:53:48,920 Close the definition. 929 00:53:48,920 --> 00:53:51,110 And there's the definition of absolute value. 930 00:53:51,110 --> 00:53:53,560 And you see it's the case analysis that looks very much 931 00:53:53,560 --> 00:53:55,265 like the case analysis you use in mathematics. 932 00:53:55,265 --> 00:53:58,500 933 00:53:58,500 --> 00:54:02,300 There's a somewhat different way of writing a restricted 934 00:54:02,300 --> 00:54:03,090 case analysis. 935 00:54:03,090 --> 00:54:05,520 Often, you have a case analysis where you only have 936 00:54:05,520 --> 00:54:08,810 one case, where you test something, and then depending 937 00:54:08,810 --> 00:54:11,000 on whether it's true or false, you do something. 938 00:54:11,000 --> 00:54:16,150 And here's another definition of absolute value which looks 939 00:54:16,150 --> 00:54:21,010 almost the same, which says, if x is less than 0, the 940 00:54:21,010 --> 00:54:24,380 result is negate x. 941 00:54:24,380 --> 00:54:25,960 Otherwise, the answer is x. 942 00:54:25,960 --> 00:54:27,120 And we'll be using "if" a lot. 943 00:54:27,120 --> 00:54:30,650 But again, the thing to remember is that this form of 944 00:54:30,650 --> 00:54:35,130 absolute value that you're looking at here, and then this 945 00:54:35,130 --> 00:54:37,650 one over here that I wrote on the board, are 946 00:54:37,650 --> 00:54:39,040 essentially the same. 947 00:54:39,040 --> 00:54:40,700 And "if" and COND are-- 948 00:54:40,700 --> 00:54:42,020 well, whichever way you like it. 949 00:54:42,020 --> 00:54:45,100 You can think of COND as syntactic sugar for "if," or 950 00:54:45,100 --> 00:54:47,375 you can think of "if" as syntactic sugar for COND, and 951 00:54:47,375 --> 00:54:48,810 it doesn't make any difference. 952 00:54:48,810 --> 00:54:51,400 The person implementing a Lisp system will pick one and 953 00:54:51,400 --> 00:54:52,840 implement the other in terms of that. 954 00:54:52,840 --> 00:54:54,570 And it doesn't matter which one you pick. 955 00:54:54,570 --> 00:55:02,660 956 00:55:02,660 --> 00:55:05,640 Why don't we break now, and then take some questions. 957 00:55:05,640 --> 00:55:11,760 How come sometimes when I write define, I put an open 958 00:55:11,760 --> 00:55:16,790 paren here and say, define open paren something or other, 959 00:55:16,790 --> 00:55:19,480 and sometimes when I write this, I 960 00:55:19,480 --> 00:55:22,330 don't put an open paren? 961 00:55:22,330 --> 00:55:27,550 The answer is, this particular form of "define," where you 962 00:55:27,550 --> 00:55:30,850 say define some expression, is this very special thing for 963 00:55:30,850 --> 00:55:33,630 defining procedures. 964 00:55:33,630 --> 00:55:37,900 But again, what it really means is I'm defining this 965 00:55:37,900 --> 00:55:41,350 symbol, square, to be that. 966 00:55:41,350 --> 00:55:44,810 So the way you should think about it is what "define" does 967 00:55:44,810 --> 00:55:48,330 is you write "define," and the second thing you write is the 968 00:55:48,330 --> 00:55:49,830 symbol here-- no open paren-- 969 00:55:49,830 --> 00:55:54,610 the symbol you're defining and what you're defining it to be. 970 00:55:54,610 --> 00:55:57,300 That's like here and like here. 971 00:55:57,300 --> 00:56:01,480 That's sort of the basic way you use "define." And then, 972 00:56:01,480 --> 00:56:05,040 there's this special syntactic trick which allows you to 973 00:56:05,040 --> 00:56:08,140 define procedures that look like this. 974 00:56:08,140 --> 00:56:10,690 So the difference is, it's whether or not you're defining 975 00:56:10,690 --> 00:56:11,755 a procedure. 976 00:56:11,755 --> 00:56:38,110 [MUSIC PLAYING] 977 00:56:38,110 --> 00:56:42,600 Well, believe it or not, you actually now know enough Lisp 978 00:56:42,600 --> 00:56:46,610 to write essentially any numerical procedure that you'd 979 00:56:46,610 --> 00:56:49,470 write in a language like FORTRAN or Basic or whatever, 980 00:56:49,470 --> 00:56:51,656 or, essentially, any other language. 981 00:56:51,656 --> 00:56:55,190 And you're probably saying, that's not believable, because 982 00:56:55,190 --> 00:56:56,890 you know that these languages have things like "for 983 00:56:56,890 --> 00:57:00,910 statements," and "do until while" or something. 984 00:57:00,910 --> 00:57:04,745 But we don't really need any of that. 985 00:57:04,745 --> 00:57:06,220 In fact, we're not going to use any of 986 00:57:06,220 --> 00:57:08,180 that in this course. 987 00:57:08,180 --> 00:57:10,410 Let me show you. 988 00:57:10,410 --> 00:57:14,400 Again, looking back at square root, let's go back to this 989 00:57:14,400 --> 00:57:18,505 square root algorithm of Heron of Alexandria. 990 00:57:18,505 --> 00:57:20,000 Remember what that said. 991 00:57:20,000 --> 00:57:23,060 It said, to find an approximation to the square 992 00:57:23,060 --> 00:57:28,730 root of X, you make a guess, you improve that guess by 993 00:57:28,730 --> 00:57:32,900 averaging the guess and X over the guess. 994 00:57:32,900 --> 00:57:36,382 You keep improving that until the guess is good enough. 995 00:57:36,382 --> 00:57:38,460 I already alluded to the idea. 996 00:57:38,460 --> 00:57:44,650 The idea is that, if the initial guess that you took 997 00:57:44,650 --> 00:57:48,430 was actually equal to the square root of X, then G here 998 00:57:48,430 --> 00:57:52,760 would be equal to X/G. 999 00:57:52,760 --> 00:57:54,400 So if you hit the square root, averaging them 1000 00:57:54,400 --> 00:57:55,630 wouldn't change it. 1001 00:57:55,630 --> 00:57:59,160 If the G that you picked was larger than the square root of 1002 00:57:59,160 --> 00:58:03,280 X, then X/G will be smaller than the square root of X, so 1003 00:58:03,280 --> 00:58:05,890 that when you average G and X/G, you get 1004 00:58:05,890 --> 00:58:09,130 something in between. 1005 00:58:09,130 --> 00:58:11,790 So if you pick a G that's too small, your 1006 00:58:11,790 --> 00:58:13,040 answer will be too large. 1007 00:58:13,040 --> 00:58:17,190 If you pick a G that's too large, if your G is larger 1008 00:58:17,190 --> 00:58:19,420 than the square root of X and X/G will be smaller than the 1009 00:58:19,420 --> 00:58:21,110 square root of X. 1010 00:58:21,110 --> 00:58:24,460 So averaging always gives you something in between. 1011 00:58:24,460 --> 00:58:27,450 And then, it's not quite trivial, but it's possible to 1012 00:58:27,450 --> 00:58:31,050 show that, in fact, if G misses the square root of X by 1013 00:58:31,050 --> 00:58:34,220 a little bit, the average of G and X/G will actually keep 1014 00:58:34,220 --> 00:58:37,800 getting closer to the square root of X. So if you keep 1015 00:58:37,800 --> 00:58:40,140 doing this enough, you'll eventually get as 1016 00:58:40,140 --> 00:58:41,680 close as you want. 1017 00:58:41,680 --> 00:58:44,170 And then there's another fact, that you can always start out 1018 00:58:44,170 --> 00:58:49,210 this process by using 1 as an initial guess. 1019 00:58:49,210 --> 00:58:52,440 And it'll always converge to the square root of X. So 1020 00:58:52,440 --> 00:58:55,610 that's this method of successive averaging due to 1021 00:58:55,610 --> 00:58:56,660 Heron of Alexandria. 1022 00:58:56,660 --> 00:59:00,250 Let's write it in Lisp. 1023 00:59:00,250 --> 00:59:05,770 Well, the central idea is, what does it mean to try a 1024 00:59:05,770 --> 00:59:07,940 guess for the square root of X? 1025 00:59:07,940 --> 00:59:09,780 Let's write that. 1026 00:59:09,780 --> 00:59:24,310 So we'll say, define to try a guess for the square root of 1027 00:59:24,310 --> 00:59:27,750 X, what do we do? 1028 00:59:27,750 --> 00:59:44,130 We'll say, if the guess is good enough to be a guess for 1029 00:59:44,130 --> 00:59:48,330 the square root of X, then, as an answer, 1030 00:59:48,330 --> 00:59:51,550 we'll take the guess. 1031 00:59:51,550 --> 00:59:58,620 Otherwise, we will try the improved guess. 1032 00:59:58,620 --> 01:00:05,400 We'll improve that guess for the square root of X, and 1033 01:00:05,400 --> 01:00:09,690 we'll try that as a guess for the square root of X. Close 1034 01:00:09,690 --> 01:00:13,510 the "try." Close the "if." Close the "define." So that's 1035 01:00:13,510 --> 01:00:15,820 how we try a guess. 1036 01:00:15,820 --> 01:00:18,050 And then, the next part of the process said, in order to 1037 01:00:18,050 --> 01:00:28,370 compute square roots, we'll say, define to compute the 1038 01:00:28,370 --> 01:00:35,290 square root of X, we will try 1 as a guess for the square 1039 01:00:35,290 --> 01:00:40,280 root of X. Well, we have to define a couple more things. 1040 01:00:40,280 --> 01:00:43,770 We have to say, how is a guess good enough? 1041 01:00:43,770 --> 01:00:45,545 And how do we improve a guess? 1042 01:00:45,545 --> 01:00:47,380 So let's look at that. 1043 01:00:47,380 --> 01:00:53,650 The algorithm to improve a guess for the square root of 1044 01:00:53,650 --> 01:00:55,640 X, we average-- 1045 01:00:55,640 --> 01:00:57,000 that was the algorithm-- 1046 01:00:57,000 --> 01:01:00,680 we average the guess with the quotient of 1047 01:01:00,680 --> 01:01:03,030 dividing X by the guess. 1048 01:01:03,030 --> 01:01:05,810 That's how we improve a guess. 1049 01:01:05,810 --> 01:01:07,720 And to tell whether a guess is good enough, well, we have to 1050 01:01:07,720 --> 01:01:09,530 decide something. 1051 01:01:09,530 --> 01:01:11,510 This is supposed to be a guess for the square root of X, so 1052 01:01:11,510 --> 01:01:14,700 one possible thing you can do is say, when you take that 1053 01:01:14,700 --> 01:01:19,110 guess and square it, do you get something very close to X? 1054 01:01:19,110 --> 01:01:22,870 So one way to say that is to say, I square the guess, 1055 01:01:22,870 --> 01:01:26,900 subtract X from that, and see if the absolute value of that 1056 01:01:26,900 --> 01:01:31,200 whole thing is less than some small number, which depends on 1057 01:01:31,200 --> 01:01:32,450 my purposes. 1058 01:01:32,450 --> 01:01:35,080 1059 01:01:35,080 --> 01:01:40,410 So there's a complete procedure for how to compute 1060 01:01:40,410 --> 01:01:42,830 the square root of X. Let's look at the structure of that 1061 01:01:42,830 --> 01:01:44,080 a little bit. 1062 01:01:44,080 --> 01:01:47,970 1063 01:01:47,970 --> 01:01:49,100 I have the whole thing. 1064 01:01:49,100 --> 01:01:55,370 I have the notion of how to compute a square root. 1065 01:01:55,370 --> 01:01:56,960 That's some kind of module. 1066 01:01:56,960 --> 01:01:58,580 That's some kind of black box. 1067 01:01:58,580 --> 01:02:07,340 It's defined in terms of how to try a guess for the square 1068 01:02:07,340 --> 01:02:09,090 root of X. 1069 01:02:09,090 --> 01:02:15,110 "Try" is defined in terms of, well, telling whether 1070 01:02:15,110 --> 01:02:16,640 something is good enough and telling 1071 01:02:16,640 --> 01:02:18,680 how to improve something. 1072 01:02:18,680 --> 01:02:19,800 So good enough. 1073 01:02:19,800 --> 01:02:30,790 "Try" is defined in terms of "good enough" and "improve." 1074 01:02:30,790 --> 01:02:32,170 And let's see what else I fill in. 1075 01:02:32,170 --> 01:02:34,640 Well, I'll go down this tree. 1076 01:02:34,640 --> 01:02:36,040 "Good enough" was defined in terms of 1077 01:02:36,040 --> 01:02:37,930 absolute value, and square. 1078 01:02:37,930 --> 01:02:40,910 1079 01:02:40,910 --> 01:02:43,290 And improve was defined in terms of something called 1080 01:02:43,290 --> 01:02:47,340 averaging and then some other primitive operator. 1081 01:02:47,340 --> 01:02:49,530 Square root's defined in terms of "try." "Try" is defined in 1082 01:02:49,530 --> 01:02:53,860 terms of "good enough" and "improve," 1083 01:02:53,860 --> 01:02:55,410 but also "try" itself. 1084 01:02:55,410 --> 01:03:02,750 So "try" is also defined in terms of how to try itself. 1085 01:03:02,750 --> 01:03:06,240 Well, that may give you some problems. Your high school 1086 01:03:06,240 --> 01:03:10,680 geometry teacher probably told you that it's naughty to try 1087 01:03:10,680 --> 01:03:13,360 and define things in terms of themselves, because it doesn't 1088 01:03:13,360 --> 01:03:13,810 make sense. 1089 01:03:13,810 --> 01:03:16,440 But that's false. 1090 01:03:16,440 --> 01:03:18,730 Sometimes it makes perfect sense to define things in 1091 01:03:18,730 --> 01:03:20,210 terms of themselves. 1092 01:03:20,210 --> 01:03:22,918 And this is the case. 1093 01:03:22,918 --> 01:03:24,150 And we can look at that. 1094 01:03:24,150 --> 01:03:28,140 We could write down what this means, and say, suppose I 1095 01:03:28,140 --> 01:03:30,100 asked Lisp what the square root of 2 is. 1096 01:03:30,100 --> 01:03:32,690 1097 01:03:32,690 --> 01:03:35,710 What's the square root of 2 mean? 1098 01:03:35,710 --> 01:03:42,700 Well, that means I try 1 as a guess for the 1099 01:03:42,700 --> 01:03:43,950 square root of 2. 1100 01:03:43,950 --> 01:03:47,100 1101 01:03:47,100 --> 01:03:47,760 Now I look. 1102 01:03:47,760 --> 01:03:50,000 I say, gee, is 1 a good enough guess for the 1103 01:03:50,000 --> 01:03:51,140 square root of 2? 1104 01:03:51,140 --> 01:03:54,140 And that depends on the test that "good enough" does. 1105 01:03:54,140 --> 01:03:57,240 And in this case, "good enough" will say, no, 1 is not 1106 01:03:57,240 --> 01:03:59,740 a good enough guess for the square root of 2. 1107 01:03:59,740 --> 01:04:10,350 So that will reduce to saying, I have to try an improved-- 1108 01:04:10,350 --> 01:04:15,910 improve 1 as a guess for the square root of 2, and try that 1109 01:04:15,910 --> 01:04:19,110 as a guess for the square root of 2. 1110 01:04:19,110 --> 01:04:22,350 Improving 1 as a guess for the square root of 2 means I 1111 01:04:22,350 --> 01:04:27,270 average 1 and 2 divided by 1. 1112 01:04:27,270 --> 01:04:29,550 So this is going to be average. 1113 01:04:29,550 --> 01:04:37,830 This piece here will be the average of 1 and the 1114 01:04:37,830 --> 01:04:40,930 quotient of 2 by 1. 1115 01:04:40,930 --> 01:04:44,910 That's this piece here. 1116 01:04:44,910 --> 01:04:46,160 And this is 1.5. 1117 01:04:46,160 --> 01:04:49,060 1118 01:04:49,060 --> 01:04:53,670 So this square root of 2 reduces to trying 1 for the 1119 01:04:53,670 --> 01:05:03,370 square root of 2, which reduces to trying 1.5 as a 1120 01:05:03,370 --> 01:05:06,220 guess for the square root of 2. 1121 01:05:06,220 --> 01:05:07,880 So that makes sense. 1122 01:05:07,880 --> 01:05:09,650 Let's look at the rest of the process. 1123 01:05:09,650 --> 01:05:14,890 If I try 1.5, that reduces. 1124 01:05:14,890 --> 01:05:18,210 1.5 turns out to be not good enough as a guess for the 1125 01:05:18,210 --> 01:05:20,130 square root of 2. 1126 01:05:20,130 --> 01:05:23,340 So that reduces to trying the average of 1.5 and 2 divided 1127 01:05:23,340 --> 01:05:28,200 by 1.5 as a guess for the square root of 2. 1128 01:05:28,200 --> 01:05:31,110 That average turns out to be 1.333. 1129 01:05:31,110 --> 01:05:34,215 So this whole thing reduces to trying 1.333 as a guess for 1130 01:05:34,215 --> 01:05:35,130 the square root of 2. 1131 01:05:35,130 --> 01:05:37,910 And then so on. 1132 01:05:37,910 --> 01:05:40,750 That reduces to another called a "good enough," 1.4 1133 01:05:40,750 --> 01:05:41,630 something or other. 1134 01:05:41,630 --> 01:05:45,160 And then it keeps going until the process finally stops with 1135 01:05:45,160 --> 01:05:47,780 something that "good enough" thinks is good enough, which, 1136 01:05:47,780 --> 01:05:52,500 in this case, is 1.4142 something or other. 1137 01:05:52,500 --> 01:05:55,890 So the process makes perfect sense. 1138 01:05:55,890 --> 01:05:59,710 1139 01:05:59,710 --> 01:06:02,620 This, by the way, is called a recursive definition. 1140 01:06:02,620 --> 01:06:14,410 1141 01:06:14,410 --> 01:06:19,470 And the ability to make recursive definitions is a 1142 01:06:19,470 --> 01:06:20,710 source of incredible power. 1143 01:06:20,710 --> 01:06:24,040 And as you can already see I've hinted at, it's the thing 1144 01:06:24,040 --> 01:06:27,160 that effectively allows you to do these infinite computations 1145 01:06:27,160 --> 01:06:30,730 that go on until something is true, without having any other 1146 01:06:30,730 --> 01:06:33,235 constricts other than the ability to call a procedure. 1147 01:06:33,235 --> 01:06:35,890 1148 01:06:35,890 --> 01:06:37,970 Well, let's see, there's one more thing. 1149 01:06:37,970 --> 01:06:43,210 Let me show you a variant of this definition of square root 1150 01:06:43,210 --> 01:06:46,300 here on the slide. 1151 01:06:46,300 --> 01:06:48,320 Here's sort of the same thing. 1152 01:06:48,320 --> 01:06:51,430 What I've done here is packaged the definitions of 1153 01:06:51,430 --> 01:06:55,340 "improve" and "good enough" and "try" inside "square 1154 01:06:55,340 --> 01:06:59,760 root." So, in effect, what I've done is I've built a 1155 01:06:59,760 --> 01:07:01,860 square root box. 1156 01:07:01,860 --> 01:07:07,320 So I've built a box that's the square root procedure that 1157 01:07:07,320 --> 01:07:08,150 someone can use. 1158 01:07:08,150 --> 01:07:11,910 They might put in 36 and get out 6. 1159 01:07:11,910 --> 01:07:15,080 And then, packaged inside this box are the definitions of 1160 01:07:15,080 --> 01:07:26,530 "try" and "good enough" and "improve." 1161 01:07:26,530 --> 01:07:28,260 So they're hidden inside this box. 1162 01:07:28,260 --> 01:07:32,010 And the reason for doing that is that, if someone's using 1163 01:07:32,010 --> 01:07:34,920 this square root, if George is using this square root, George 1164 01:07:34,920 --> 01:07:39,180 probably doesn't care very much that, when I implemented 1165 01:07:39,180 --> 01:07:42,600 square root, I had things inside there called "try" and 1166 01:07:42,600 --> 01:07:48,150 "good enough" and "improve." And in fact, Harry might have 1167 01:07:48,150 --> 01:07:50,300 a cube root procedure that has "try" and "good enough" and 1168 01:07:50,300 --> 01:07:53,260 "improve." And in order to not get the whole system confused, 1169 01:07:53,260 --> 01:07:55,430 it'd be good for Harry to package his internal 1170 01:07:55,430 --> 01:07:58,320 procedures inside his cube root procedure. 1171 01:07:58,320 --> 01:08:00,970 Well, this is called block structure, this particular way 1172 01:08:00,970 --> 01:08:09,940 of packaging internals inside of a definition. 1173 01:08:09,940 --> 01:08:13,040 And let's go back and look at the slide again. 1174 01:08:13,040 --> 01:08:17,720 The way to read this kind of procedure is to say, to define 1175 01:08:17,720 --> 01:08:23,010 "square root," well, inside that definition, I'll have the 1176 01:08:23,010 --> 01:08:26,479 definition of an "improve" and the definition of "good 1177 01:08:26,479 --> 01:08:31,149 enough" and the definition of "try." And then, subject to 1178 01:08:31,149 --> 01:08:36,010 those definitions, the way I do square root is to try 1. 1179 01:08:36,010 --> 01:08:38,310 And notice here, I don't have to say 1 as a guess for the 1180 01:08:38,310 --> 01:08:41,290 square root of X, because since it's all inside the 1181 01:08:41,290 --> 01:08:44,270 square root, it sort of has this X known. 1182 01:08:44,270 --> 01:08:54,770 1183 01:08:54,770 --> 01:08:56,510 Let me summarize. 1184 01:08:56,510 --> 01:08:59,890 We started out with the idea that what we're going to be 1185 01:08:59,890 --> 01:09:04,960 doing is expressing imperative knowledge. 1186 01:09:04,960 --> 01:09:08,960 And in fact, here's a slide that summarizes the way we 1187 01:09:08,960 --> 01:09:09,680 looked at Lisp. 1188 01:09:09,680 --> 01:09:13,609 We started out by looking at some primitive elements in 1189 01:09:13,609 --> 01:09:17,609 addition and multiplication, some predicates for testing 1190 01:09:17,609 --> 01:09:19,630 whether something is less-than or something's equal. 1191 01:09:19,630 --> 01:09:22,330 And in fact, we saw really sneakily in the system we're 1192 01:09:22,330 --> 01:09:25,160 actually using, these aren't actually primitives, but it 1193 01:09:25,160 --> 01:09:26,550 doesn't matter. 1194 01:09:26,550 --> 01:09:28,120 What matters is we're going to use them as if they're 1195 01:09:28,120 --> 01:09:28,510 primitives. 1196 01:09:28,510 --> 01:09:30,220 We're not going to look inside. 1197 01:09:30,220 --> 01:09:34,540 We also have some primitive data and some numbers. 1198 01:09:34,540 --> 01:09:36,830 We saw some means of composition, means of 1199 01:09:36,830 --> 01:09:41,300 combination, the basic one being composing functions and 1200 01:09:41,300 --> 01:09:44,840 building combinations with operators and operands. 1201 01:09:44,840 --> 01:09:47,600 And there were some other things, like COND and "if" and 1202 01:09:47,600 --> 01:09:53,790 "define." But the main thing about "define," in particular, 1203 01:09:53,790 --> 01:09:55,710 was that it was the means of abstraction. 1204 01:09:55,710 --> 01:09:57,670 It was the way that we name things. 1205 01:09:57,670 --> 01:09:59,770 You can also see from this slide not only where we've 1206 01:09:59,770 --> 01:10:01,450 been, but holes we have to fill in. 1207 01:10:01,450 --> 01:10:03,930 At some point, we'll have to talk about how you combine 1208 01:10:03,930 --> 01:10:07,720 primitive data to get compound data, and how you abstract 1209 01:10:07,720 --> 01:10:11,950 data so you can use large globs of data as 1210 01:10:11,950 --> 01:10:13,900 if they were primitive. 1211 01:10:13,900 --> 01:10:16,370 So that's where we're going. 1212 01:10:16,370 --> 01:10:20,790 But before we do that, for the next couple of lectures we're 1213 01:10:20,790 --> 01:10:25,720 going to be talking about, first of all, how it is that 1214 01:10:25,720 --> 01:10:28,900 you make a link between these procedures we write and the 1215 01:10:28,900 --> 01:10:32,040 processes that happen in the machine. 1216 01:10:32,040 --> 01:10:36,210 And then, how it is that you start using the power of Lisp 1217 01:10:36,210 --> 01:10:38,710 to talk not only about these individual little 1218 01:10:38,710 --> 01:10:43,080 computations, but about general conventional methods 1219 01:10:43,080 --> 01:10:45,200 of doing things. 1220 01:10:45,200 --> 01:10:46,730 OK, are there any questions? 1221 01:10:46,730 --> 01:10:47,640 AUDIENCE: Yes. 1222 01:10:47,640 --> 01:10:51,880 If we defined A using parentheses instead of as we 1223 01:10:51,880 --> 01:10:53,400 did, what would be the difference? 1224 01:10:53,400 --> 01:10:58,130 PROFESSOR: If I wrote this, if I wrote that, what I would be 1225 01:10:58,130 --> 01:11:03,740 doing is defining a procedure named A. In this case, a 1226 01:11:03,740 --> 01:11:07,950 procedure of no arguments, which, when I ran it, would 1227 01:11:07,950 --> 01:11:10,274 give me back 5 times 5. 1228 01:11:10,274 --> 01:11:10,716 AUDIENCE: Right. 1229 01:11:10,716 --> 01:11:12,610 I mean, you come up with the same thing, except for you 1230 01:11:12,610 --> 01:11:13,940 really got a different-- 1231 01:11:13,940 --> 01:11:14,120 PROFESSOR: Right. 1232 01:11:14,120 --> 01:11:16,330 And the difference would be, in the old one-- 1233 01:11:16,330 --> 01:11:19,180 Let me be a little bit clearer here. 1234 01:11:19,180 --> 01:11:24,070 Let's call this A, like here. 1235 01:11:24,070 --> 01:11:35,060 And pretend here, just for contrast, I wrote, define D to 1236 01:11:35,060 --> 01:11:37,300 be the product of 5 and 5. 1237 01:11:37,300 --> 01:11:40,200 1238 01:11:40,200 --> 01:11:42,450 And the difference between those, let's think about 1239 01:11:42,450 --> 01:11:45,770 interactions with the Lisp interpreter. 1240 01:11:45,770 --> 01:11:52,860 I could type in A and Lisp would return 25. 1241 01:11:52,860 --> 01:12:01,240 I could type in D, if I just typed in D, Lisp would return 1242 01:12:01,240 --> 01:12:08,000 compound procedure D, because that's what it is. 1243 01:12:08,000 --> 01:12:09,670 It's a procedure. 1244 01:12:09,670 --> 01:12:12,500 I could run D. I could say, what's the value of running D? 1245 01:12:12,500 --> 01:12:16,520 Here is a combination with no operands. 1246 01:12:16,520 --> 01:12:17,570 I see there are no operands. 1247 01:12:17,570 --> 01:12:22,940 I didn't put any after D. And it would say, oh, that's 25. 1248 01:12:22,940 --> 01:12:28,070 Or I could say, just for completeness, if I typed in, 1249 01:12:28,070 --> 01:12:29,310 what's the value of running A? 1250 01:12:29,310 --> 01:12:31,690 I get an error. 1251 01:12:31,690 --> 01:12:35,150 The error would be the same one as over there. 1252 01:12:35,150 --> 01:12:40,010 It'd be the error would say, sorry, 25, which is the value 1253 01:12:40,010 --> 01:12:43,720 of A, is not an operator that I can apply to something. 1254 01:12:43,720 --> 01:12:53,076 ================================================ FILE: SrtEN/lec1b_512kb.mp4.srt ================================================ 1 00:00:00,000 --> 00:00:14,550 [MUSIC PLAYING BY J.S. BACH] 2 00:00:14,550 --> 00:00:16,320 PROFESSOR: Hi. 3 00:00:16,320 --> 00:00:20,050 You've seen that the job of a programmer is to design 4 00:00:20,050 --> 00:00:24,070 processes that accomplish particular goals, such as 5 00:00:24,070 --> 00:00:27,050 finding the square roots of numbers or other sorts of 6 00:00:27,050 --> 00:00:28,830 things you might want to do. 7 00:00:28,830 --> 00:00:32,080 We haven't introduced anything else yet. 8 00:00:32,080 --> 00:00:34,370 Of course, the way in which a programmer does this is by 9 00:00:34,370 --> 00:00:39,440 constructing spells, which are constructed out of procedures 10 00:00:39,440 --> 00:00:41,050 and expressions. 11 00:00:41,050 --> 00:00:46,000 And that these spells are somehow direct a process to 12 00:00:46,000 --> 00:00:49,190 accomplish the goal that was intended by the programmer. 13 00:00:49,190 --> 00:00:51,670 In order for the programmer to do this effectively, he has to 14 00:00:51,670 --> 00:00:54,330 understand the relationship between the particular things 15 00:00:54,330 --> 00:00:56,830 that he writes, these particular spells, and the 16 00:00:56,830 --> 00:01:01,630 behavior of the process that he's attempting to control. 17 00:01:01,630 --> 00:01:03,560 So what we're doing this lecture is attempt to 18 00:01:03,560 --> 00:01:07,630 establish that connection in as clear a way as possible. 19 00:01:07,630 --> 00:01:10,450 What we will particularly do is understand how particular 20 00:01:10,450 --> 00:01:15,300 patterns of procedures and expressions cause particular 21 00:01:15,300 --> 00:01:17,230 patterns of execution, particular 22 00:01:17,230 --> 00:01:19,050 behaviors from the processes. 23 00:01:19,050 --> 00:01:22,420 24 00:01:22,420 --> 00:01:24,190 Let's get down to that. 25 00:01:24,190 --> 00:01:28,240 I'm going to start with a very simple program. 26 00:01:28,240 --> 00:01:29,680 This is a program to compute the sum of the 27 00:01:29,680 --> 00:01:33,630 squares of two numbers. 28 00:01:33,630 --> 00:01:45,970 And we'll define the sum of the squares of x and y to be 29 00:01:45,970 --> 00:01:49,835 the sum of the square of x-- 30 00:01:49,835 --> 00:01:51,460 I'm going to write it that way-- 31 00:01:51,460 --> 00:02:08,690 and the square of y where the square of x is the 32 00:02:08,690 --> 00:02:10,830 product of x and x. 33 00:02:10,830 --> 00:02:14,220 34 00:02:14,220 --> 00:02:17,670 Now, supposing I were to say something to this, like, to 35 00:02:17,670 --> 00:02:20,845 the system after having defined these things, of the 36 00:02:20,845 --> 00:02:26,420 form, the sum of the squares of 3 and 4, I am hoping that I 37 00:02:26,420 --> 00:02:29,310 will get out a 25. 38 00:02:29,310 --> 00:02:33,090 Because the square of 3 is 9, and the square of 4 is 16, and 39 00:02:33,090 --> 00:02:34,900 25 is the sum of those. 40 00:02:34,900 --> 00:02:36,720 But how does that happen? 41 00:02:36,720 --> 00:02:39,730 If we're going to understand processes and how we control 42 00:02:39,730 --> 00:02:43,910 them, then we have to have a mapping from the mechanisms of 43 00:02:43,910 --> 00:02:49,540 this procedure into the way in which these processes behave. 44 00:02:49,540 --> 00:02:52,380 What we're going to have is a formal, or semi-formal, 45 00:02:52,380 --> 00:02:56,180 mechanical model whereby you understand how a machine 46 00:02:56,180 --> 00:02:57,920 could, in fact, in principle, do this. 47 00:02:57,920 --> 00:03:00,660 Whether or not the actual machine really does what I'm 48 00:03:00,660 --> 00:03:01,860 about to tell you is completely 49 00:03:01,860 --> 00:03:03,840 irrelevant at this moment. 50 00:03:03,840 --> 00:03:06,290 In fact, this is an engineering model in the same 51 00:03:06,290 --> 00:03:09,600 way that, electrical resistor, we write down a model v equals 52 00:03:09,600 --> 00:03:12,330 i r, it's approximately true. 53 00:03:12,330 --> 00:03:13,880 It's not really true. 54 00:03:13,880 --> 00:03:16,860 If I put up current through the resistor it goes boom. 55 00:03:16,860 --> 00:03:20,410 So the voltage is not always proportional to the current, 56 00:03:20,410 --> 00:03:24,200 but for some purposes the model is appropriate. 57 00:03:24,200 --> 00:03:26,640 In particular, the model we're going to describe right now, 58 00:03:26,640 --> 00:03:29,770 which I call the substitution model, is the simplest model 59 00:03:29,770 --> 00:03:32,700 that we have for understanding how procedures work and how 60 00:03:32,700 --> 00:03:34,310 processes work. 61 00:03:34,310 --> 00:03:36,350 How procedures yield processes. 62 00:03:36,350 --> 00:03:39,150 And that substitution model will be accurate for most of 63 00:03:39,150 --> 00:03:41,790 the things we'll be dealing with in the next few days. 64 00:03:41,790 --> 00:03:45,240 But eventually, it will become impossible to sustain the 65 00:03:45,240 --> 00:03:47,060 illusion that that's the way the machine works, and we'll 66 00:03:47,060 --> 00:03:50,490 go to other more specific and particular models that will 67 00:03:50,490 --> 00:03:53,590 show more detail. 68 00:03:53,590 --> 00:03:58,200 OK, well, the first thing, of course, is we say, what are 69 00:03:58,200 --> 00:03:59,170 the things we have here? 70 00:03:59,170 --> 00:04:00,550 We have some cryptic symbols. 71 00:04:00,550 --> 00:04:04,350 And these cryptic symbols are made out of pieces. 72 00:04:04,350 --> 00:04:05,990 There are kinds of expressions. 73 00:04:05,990 --> 00:04:07,410 So let's write down here the kinds of 74 00:04:07,410 --> 00:04:08,660 expressions there are. 75 00:04:08,660 --> 00:04:17,890 76 00:04:17,890 --> 00:04:20,295 And we have-- and so far I see things like numbers. 77 00:04:20,295 --> 00:04:25,370 78 00:04:25,370 --> 00:04:28,030 I see things like symbols like that. 79 00:04:28,030 --> 00:04:32,160 80 00:04:32,160 --> 00:04:35,430 We have seen things before like lambda expressions, but 81 00:04:35,430 --> 00:04:36,190 they're not here. 82 00:04:36,190 --> 00:04:37,180 I'm going to leave them out. 83 00:04:37,180 --> 00:04:39,650 Lambda expressions, we'll worry about them later. 84 00:04:39,650 --> 00:04:44,630 85 00:04:44,630 --> 00:04:45,880 Things like definitions. 86 00:04:45,880 --> 00:04:51,900 87 00:04:51,900 --> 00:04:53,150 Things like conditionals. 88 00:04:53,150 --> 00:04:58,410 89 00:04:58,410 --> 00:05:00,155 And finally, things like combinations. 90 00:05:00,155 --> 00:05:07,040 91 00:05:07,040 --> 00:05:10,470 These kinds of expressions are-- 92 00:05:10,470 --> 00:05:12,880 I'll worry about later-- 93 00:05:12,880 --> 00:05:16,030 these are special forms. There are particular 94 00:05:16,030 --> 00:05:17,670 rules for each of these. 95 00:05:17,670 --> 00:05:19,950 I'm going to tell you, however, the rules for doing a 96 00:05:19,950 --> 00:05:21,120 general case. 97 00:05:21,120 --> 00:05:23,510 How does one evaluate a combination? 98 00:05:23,510 --> 00:05:25,820 Because, in fact, over here, all I really have are 99 00:05:25,820 --> 00:05:29,180 combinations and some symbols and numbers. 100 00:05:29,180 --> 00:05:31,290 And the simple things like a number, well, it 101 00:05:31,290 --> 00:05:33,370 will evaluate to itself. 102 00:05:33,370 --> 00:05:35,180 In the model I will have for you, the 103 00:05:35,180 --> 00:05:37,170 symbols will disappear. 104 00:05:37,170 --> 00:05:40,220 They won't be there at the time when you need them, when 105 00:05:40,220 --> 00:05:41,680 you need to get at them. 106 00:05:41,680 --> 00:05:44,000 So the only thing I really have to explain to you is, how 107 00:05:44,000 --> 00:05:45,250 do we evaluate combinations? 108 00:05:45,250 --> 00:05:48,350 109 00:05:48,350 --> 00:05:50,340 OK, let's see. 110 00:05:50,340 --> 00:05:54,430 So first I want to get the first slide. 111 00:05:54,430 --> 00:05:58,450 Here is the rule for evaluating an application. 112 00:05:58,450 --> 00:06:01,430 113 00:06:01,430 --> 00:06:07,030 What we have is a rule that says, to evaluate a 114 00:06:07,030 --> 00:06:08,530 combination, there are two parts, three 115 00:06:08,530 --> 00:06:09,740 parts to the rule. 116 00:06:09,740 --> 00:06:12,390 The combination has several parts. 117 00:06:12,390 --> 00:06:16,630 It has operators and it has operands. 118 00:06:16,630 --> 00:06:20,180 The operator returns into a procedure. 119 00:06:20,180 --> 00:06:22,480 If we evaluate the operator, we will get a procedure. 120 00:06:22,480 --> 00:06:25,330 And you saw, for example, how I'll type at the machine and 121 00:06:25,330 --> 00:06:28,880 out came compound procedure something or other. 122 00:06:28,880 --> 00:06:31,940 And the operands produce arguments. 123 00:06:31,940 --> 00:06:35,690 Once we've gotten the operator evaluated to get a procedure, 124 00:06:35,690 --> 00:06:38,050 and the argument is evaluated to get argument-- 125 00:06:38,050 --> 00:06:39,550 the operand's value to get arguments-- 126 00:06:39,550 --> 00:06:43,320 we apply the procedure to these arguments by copying the 127 00:06:43,320 --> 00:06:46,000 body of the procedure, which is the expression that the 128 00:06:46,000 --> 00:06:47,800 procedure is defined in terms of. 129 00:06:47,800 --> 00:06:49,500 What is it supposed to do? 130 00:06:49,500 --> 00:06:53,060 Substituting the argument supplied for the formal 131 00:06:53,060 --> 00:06:56,120 parameters of the procedure, the formal parameters being 132 00:06:56,120 --> 00:06:59,100 the names defined by the declaration of the procedure. 133 00:06:59,100 --> 00:07:02,700 Then we evaluate the resulting new body, the body resulting 134 00:07:02,700 --> 00:07:07,350 from copying the old body with the substitutions made. 135 00:07:07,350 --> 00:07:10,900 It's a very simple rule, and we're going to do it very 136 00:07:10,900 --> 00:07:12,300 formally for a little while. 137 00:07:12,300 --> 00:07:15,620 Because for the next few lectures, what I want you to 138 00:07:15,620 --> 00:07:18,330 do is to say, if I don't understand something, if I 139 00:07:18,330 --> 00:07:21,260 don't understand something, be very mechanical and do this. 140 00:07:21,260 --> 00:07:23,890 141 00:07:23,890 --> 00:07:26,360 So let's see. 142 00:07:26,360 --> 00:07:28,590 Let's consider a particular evaluation, the one we were 143 00:07:28,590 --> 00:07:29,550 talking about before. 144 00:07:29,550 --> 00:07:33,330 The sum of the squares of 3 and 4. 145 00:07:33,330 --> 00:07:35,900 146 00:07:35,900 --> 00:07:37,010 What does that mean? 147 00:07:37,010 --> 00:07:38,600 It says, take-- 148 00:07:38,600 --> 00:07:41,470 well, I could find out what's on the square-- it's some 149 00:07:41,470 --> 00:07:43,500 procedure, and I'm not going to worry about the 150 00:07:43,500 --> 00:07:44,870 representation, and I'm not going to write it on the 151 00:07:44,870 --> 00:07:46,800 blackboard for you. 152 00:07:46,800 --> 00:07:50,650 And I have that 3 represents some number, but if I have to 153 00:07:50,650 --> 00:07:52,690 repeat that number, I can't tell you the number. 154 00:07:52,690 --> 00:07:54,580 The number itself is some abstract thing. 155 00:07:54,580 --> 00:07:56,670 There's a numeral which represents it, which I'll call 156 00:07:56,670 --> 00:07:59,680 3, and I'll use that in my substitution. 157 00:07:59,680 --> 00:08:01,880 And 4 is also a number. 158 00:08:01,880 --> 00:08:07,420 I'm going to substitute 3 for x and 4 for y in the body of 159 00:08:07,420 --> 00:08:09,540 this procedure that you see over here. 160 00:08:09,540 --> 00:08:11,560 Here's the body of the procedure. 161 00:08:11,560 --> 00:08:13,300 It corresponds to this 162 00:08:13,300 --> 00:08:14,860 combination, which is an addition. 163 00:08:14,860 --> 00:08:17,500 164 00:08:17,500 --> 00:08:21,210 So what that reduces to, as a reduction step, we call it, is 165 00:08:21,210 --> 00:08:30,450 the sum of the square of 3 and the square of 4. 166 00:08:30,450 --> 00:08:34,200 Now, what's the next step I have to do here? 167 00:08:34,200 --> 00:08:36,100 I say, well, I have to evaluate this. 168 00:08:36,100 --> 00:08:40,299 According to my rule, which you just saw on that overhead 169 00:08:40,299 --> 00:08:44,430 or slide, what we had was that we have to 170 00:08:44,430 --> 00:08:46,260 evaluate the operands-- 171 00:08:46,260 --> 00:08:48,220 and here are the operands, here's one and 172 00:08:48,220 --> 00:08:49,120 here's the next operand-- 173 00:08:49,120 --> 00:08:51,060 and how we have to evaluate procedure. 174 00:08:51,060 --> 00:08:52,830 The order doesn't matter. 175 00:08:52,830 --> 00:08:56,810 And then we're going to apply the procedure, which is plus, 176 00:08:56,810 --> 00:08:59,830 and magically somehow that's going to produce the answer. 177 00:08:59,830 --> 00:09:02,500 I'm not to open up plus and look inside of it. 178 00:09:02,500 --> 00:09:05,380 However, in order to evaluate the operand, let's pick some 179 00:09:05,380 --> 00:09:06,780 arbitrary order and do them. 180 00:09:06,780 --> 00:09:08,540 I'm going to go from right to left. 181 00:09:08,540 --> 00:09:10,530 Well, in order to evaluate this operand, I have to 182 00:09:10,530 --> 00:09:14,350 evaluate the parts of it by the same rule. 183 00:09:14,350 --> 00:09:16,260 And the parts are I have to find out what square is-- it's 184 00:09:16,260 --> 00:09:19,580 some procedure, which has a formal parameter x. 185 00:09:19,580 --> 00:09:25,510 And also, I have an operand which is 4, which I have to 186 00:09:25,510 --> 00:09:28,710 substitute for x in the body of square. 187 00:09:28,710 --> 00:09:32,170 So the next step is basically to say that this is the sum of 188 00:09:32,170 --> 00:09:40,990 the square of 3 and the product of 4 and 4. 189 00:09:40,990 --> 00:09:44,460 Of course, I could open up asterisk if I liked-- 190 00:09:44,460 --> 00:09:46,920 the multiplication operation-- 191 00:09:46,920 --> 00:09:47,900 but I'm not going to do that. 192 00:09:47,900 --> 00:09:50,610 I'm going to consider that primitive. 193 00:09:50,610 --> 00:09:53,320 And, of course, at any level of detail, if you look inside 194 00:09:53,320 --> 00:09:55,540 this machine, you're going to find that there's multiple 195 00:09:55,540 --> 00:09:58,250 levels below that that you don't know about. 196 00:09:58,250 --> 00:09:59,620 But one of the things we have to learn how to 197 00:09:59,620 --> 00:10:02,520 do is ignore details. 198 00:10:02,520 --> 00:10:04,960 The key to understanding complicated things is to know 199 00:10:04,960 --> 00:10:07,710 what not to look at and what not compute 200 00:10:07,710 --> 00:10:09,500 and what not to think. 201 00:10:09,500 --> 00:10:12,380 So we're going to stop this one here and say, oh, yes, 202 00:10:12,380 --> 00:10:14,510 this is the product of two things. 203 00:10:14,510 --> 00:10:15,930 We're going to do it now. 204 00:10:15,930 --> 00:10:19,220 So this is nothing more than the sum of the 205 00:10:19,220 --> 00:10:23,340 square of 3 and 16. 206 00:10:23,340 --> 00:10:27,910 And now I have another thing I have to evaluate, but that 207 00:10:27,910 --> 00:10:29,430 square of 3, well, it's the same thing. 208 00:10:29,430 --> 00:10:36,910 That's the sum of the product of 3 and 3 and 16, which is 209 00:10:36,910 --> 00:10:44,830 the sum of 9 and 16, which is 25. 210 00:10:44,830 --> 00:10:49,366 So now you see the basic method of doing substitutions. 211 00:10:49,366 --> 00:10:54,980 And I warn you that this is not a perfect description of 212 00:10:54,980 --> 00:10:57,200 what the computer does. 213 00:10:57,200 --> 00:11:00,800 But it's a good enough description for the problems 214 00:11:00,800 --> 00:11:03,090 that we're going to have in the next few lectures that you 215 00:11:03,090 --> 00:11:05,220 should think about this religiously. 216 00:11:05,220 --> 00:11:07,880 And this is how the machine works for now. 217 00:11:07,880 --> 00:11:09,130 Later we'll get more detailed. 218 00:11:09,130 --> 00:11:12,090 219 00:11:12,090 --> 00:11:14,500 Now, of course, I made a specific choice of the order 220 00:11:14,500 --> 00:11:15,780 of evaluation here. 221 00:11:15,780 --> 00:11:17,180 There are other possibilities. 222 00:11:17,180 --> 00:11:21,360 If we go back to the telestrator here and look at 223 00:11:21,360 --> 00:11:25,130 the substitution rule, we see that I evaluated the operator 224 00:11:25,130 --> 00:11:27,910 to get the procedures, and I evaluated the operands to get 225 00:11:27,910 --> 00:11:31,110 the arguments first, before I do the application. 226 00:11:31,110 --> 00:11:33,320 It's entirely possible, and there are alternate rules 227 00:11:33,320 --> 00:11:36,570 called normal order evaluation whereby you can do the 228 00:11:36,570 --> 00:11:41,150 substitution of the expressions which are the 229 00:11:41,150 --> 00:11:44,580 operands for the formal parameters inside the body 230 00:11:44,580 --> 00:11:48,880 first. And you'll get also the same answer. 231 00:11:48,880 --> 00:11:50,970 But right now, for concreteness, and because this 232 00:11:50,970 --> 00:11:53,780 is the way our machine really does it, I'm going to give you 233 00:11:53,780 --> 00:11:56,510 this rule, which has a particular order. 234 00:11:56,510 --> 00:11:58,440 But that order is to some extent arbitrary, too. 235 00:11:58,440 --> 00:12:01,110 236 00:12:01,110 --> 00:12:03,110 In the long run, there are some reasons why you might 237 00:12:03,110 --> 00:12:04,920 pick one order or another, and we'll get to that 238 00:12:04,920 --> 00:12:06,170 later in the subject. 239 00:12:06,170 --> 00:12:12,320 240 00:12:12,320 --> 00:12:15,500 OK, well now the only other thing I have to tell you about 241 00:12:15,500 --> 00:12:17,530 just to understand what's going on is let's look at the 242 00:12:17,530 --> 00:12:19,840 rule for conditionals. 243 00:12:19,840 --> 00:12:27,200 Conditionals are very simple, and I'd like to examine this. 244 00:12:27,200 --> 00:12:32,490 A conditional is something that is if-- there's also 245 00:12:32,490 --> 00:12:33,720 cond, of course-- 246 00:12:33,720 --> 00:12:35,980 but I'm going to give names to the parts of the expression. 247 00:12:35,980 --> 00:12:39,340 There's a predicate, which is a thing that is 248 00:12:39,340 --> 00:12:40,900 either true or false. 249 00:12:40,900 --> 00:12:46,920 And there's a consequent, which is the thing you do if 250 00:12:46,920 --> 00:12:48,370 the predicate is true. 251 00:12:48,370 --> 00:12:53,970 And there's an alternative, which is the thing you do if 252 00:12:53,970 --> 00:12:55,470 the predicate is false. 253 00:12:55,470 --> 00:13:00,202 It's important, by the way, to get names for, to get names 254 00:13:00,202 --> 00:13:03,810 for, the parts of things, or the parts of expressions. 255 00:13:03,810 --> 00:13:06,410 One of the things that every sorcerer will tell you is if 256 00:13:06,410 --> 00:13:10,350 you have the name of a spirit, you have power over it. 257 00:13:10,350 --> 00:13:12,320 So you have to learn these names so that we can discuss 258 00:13:12,320 --> 00:13:13,790 these things. 259 00:13:13,790 --> 00:13:16,570 So here we have a predicate, a consequent, and an 260 00:13:16,570 --> 00:13:17,860 alternative. 261 00:13:17,860 --> 00:13:21,830 And, using such words, we see that an if expression, the 262 00:13:21,830 --> 00:13:25,160 problems you evaluate to the predicate expression, if that 263 00:13:25,160 --> 00:13:29,630 yields true, then you then go on to evaluate the consequent. 264 00:13:29,630 --> 00:13:31,975 Otherwise, you evaluate the alternative expression. 265 00:13:31,975 --> 00:13:34,880 266 00:13:34,880 --> 00:13:39,290 So I'd like to illustrate that now in the context of a 267 00:13:39,290 --> 00:13:43,600 particular little program. 268 00:13:43,600 --> 00:13:44,620 Going to write down a program which we're 269 00:13:44,620 --> 00:13:45,870 going to see many times. 270 00:13:45,870 --> 00:13:51,770 271 00:13:51,770 --> 00:13:58,380 This is the sum of x and y done by what's called Peano 272 00:13:58,380 --> 00:14:00,140 arithmetic, which is all we're doing is incrementing and 273 00:14:00,140 --> 00:14:01,510 decrementing. 274 00:14:01,510 --> 00:14:03,070 And we're going to see this for a little bit. 275 00:14:03,070 --> 00:14:06,240 It's a very important program. 276 00:14:06,240 --> 00:14:12,190 If x equals o, then the result is y. 277 00:14:12,190 --> 00:14:17,980 Otherwise, this is the sum of the decrement of x and the 278 00:14:17,980 --> 00:14:20,590 increment of y. 279 00:14:20,590 --> 00:14:23,720 280 00:14:23,720 --> 00:14:28,000 We're going to look at this a lot more in the future. 281 00:14:28,000 --> 00:14:29,360 Let's look at the overhead. 282 00:14:29,360 --> 00:14:31,830 So here we have this procedure, and we're going to 283 00:14:31,830 --> 00:14:33,930 look at how we do the substitutions, the sequence of 284 00:14:33,930 --> 00:14:36,110 substitutions. 285 00:14:36,110 --> 00:14:38,370 Well, I'm going to try and add together 3 and 4. 286 00:14:38,370 --> 00:14:40,950 Well, using the first rule that I showed you, we 287 00:14:40,950 --> 00:14:44,840 substitute 3 for x and 4 four y in the 288 00:14:44,840 --> 00:14:45,980 body of this procedure. 289 00:14:45,980 --> 00:14:49,000 The body of the procedure is the thing that begins with if 290 00:14:49,000 --> 00:14:51,410 and finishes over here. 291 00:14:51,410 --> 00:14:54,025 So what we get is, of course, if 3 is 0, then 292 00:14:54,025 --> 00:14:56,010 the result is 4. 293 00:14:56,010 --> 00:14:58,960 Otherwise, it's the sum of the decrement of 3 and the 294 00:14:58,960 --> 00:15:01,360 increment of 4. 295 00:15:01,360 --> 00:15:03,320 But I'm not going to worry about these yet 296 00:15:03,320 --> 00:15:05,610 because 3 is not 0. 297 00:15:05,610 --> 00:15:08,310 So the answer is not 4. 298 00:15:08,310 --> 00:15:12,250 Therefore, this if reduces to an evaluation of the 299 00:15:12,250 --> 00:15:14,550 expression, the sum to the decrement of 3 and the 300 00:15:14,550 --> 00:15:16,860 increment of 4. 301 00:15:16,860 --> 00:15:19,540 Continuing with my evaluation, the increment I presume to be 302 00:15:19,540 --> 00:15:23,010 primitive, and so I get a 5 there. 303 00:15:23,010 --> 00:15:26,090 OK, and then the decrement is also primitive, and I get a 2. 304 00:15:26,090 --> 00:15:28,560 And so I change the problem into a simpler problem. 305 00:15:28,560 --> 00:15:33,480 Instead of adding 3 to 4, I'm adding 2 to 5. 306 00:15:33,480 --> 00:15:35,380 The reason why this is a simpler problem is because I'm 307 00:15:35,380 --> 00:15:40,540 counting down on x, and eventually, then, x will be 0. 308 00:15:40,540 --> 00:15:43,480 309 00:15:43,480 --> 00:15:46,090 So, so much for the substitution rule. 310 00:15:46,090 --> 00:15:49,240 In general, I'm not going to write down intermediate steps 311 00:15:49,240 --> 00:15:52,160 when using substitutions having to do with ifs, because 312 00:15:52,160 --> 00:15:55,520 they just expand things to become complicated. 313 00:15:55,520 --> 00:15:58,160 What we will be doing is saying, oh, yes, the sum of 3 314 00:15:58,160 --> 00:16:02,463 and 4 results in the sum of 2 and 5 and reduces to the sum 315 00:16:02,463 --> 00:16:07,100 of 2 and 5, which, in fact, reduces to the sum of 1 and 6, 316 00:16:07,100 --> 00:16:11,410 which reduces to the sum of 0 and 7 over here, which 317 00:16:11,410 --> 00:16:14,130 reduces to a 7. 318 00:16:14,130 --> 00:16:16,550 That's what we're going to be seeing. 319 00:16:16,550 --> 00:16:20,600 Are there any questions for the first segment yet? 320 00:16:20,600 --> 00:16:21,942 Yes? 321 00:16:21,942 --> 00:16:24,858 STUDENT: You're using 1 plus and minus 1 plus. 322 00:16:24,858 --> 00:16:25,830 Are those primitive operations? 323 00:16:25,830 --> 00:16:26,810 PROFESSOR: Yes. 324 00:16:26,810 --> 00:16:29,370 One of the things you're going to be seeing in this subject 325 00:16:29,370 --> 00:16:33,360 is I'm going to, without thinking about it, introduce 326 00:16:33,360 --> 00:16:36,180 more and more primitive operations. 327 00:16:36,180 --> 00:16:38,400 There's presumably some large library of primitive 328 00:16:38,400 --> 00:16:39,830 operations somewhere. 329 00:16:39,830 --> 00:16:41,620 But it doesn't matter that they're primitive-- 330 00:16:41,620 --> 00:16:43,860 there may be some manual that lists them all. 331 00:16:43,860 --> 00:16:45,900 If I tell you what they do, you say, oh, yes, I 332 00:16:45,900 --> 00:16:46,960 know what they do. 333 00:16:46,960 --> 00:16:49,070 So one of them is the decrementor-- 334 00:16:49,070 --> 00:16:50,960 minus 1 plus-- and the other operation is 335 00:16:50,960 --> 00:16:53,310 increment, which is 1 plus. 336 00:16:53,310 --> 00:16:53,840 Thank you. 337 00:16:53,840 --> 00:16:55,662 That's the end of the first segment. 338 00:16:55,662 --> 00:17:19,230 [MUSIC PLAYING BY J.S. BACH] 339 00:17:19,230 --> 00:17:22,079 PROFESSOR: Now that we have a reasonably mechanical way of 340 00:17:22,079 --> 00:17:28,349 understanding how a program made out of procedures and 341 00:17:28,349 --> 00:17:32,390 expressions evolves a process, I'd like to develop some 342 00:17:32,390 --> 00:17:36,920 intuition about how particular programs evolve particular 343 00:17:36,920 --> 00:17:39,930 processes, what the shapes of programs have to be in order 344 00:17:39,930 --> 00:17:42,940 to get particular shaped processes. 345 00:17:42,940 --> 00:17:47,110 This is a question about, really, pre-visualizing. 346 00:17:47,110 --> 00:17:49,230 That's a word from photography. 347 00:17:49,230 --> 00:17:53,140 I used to be interested in photography a lot, and one of 348 00:17:53,140 --> 00:17:55,140 the things you discover when you start trying to learn 349 00:17:55,140 --> 00:17:57,330 about photography is that you say, gee, I'd like to be a 350 00:17:57,330 --> 00:17:58,910 creative photographer. 351 00:17:58,910 --> 00:18:01,820 Now, I know the rules, I push buttons, and I adjust the 352 00:18:01,820 --> 00:18:03,430 aperture and things like that. 353 00:18:03,430 --> 00:18:06,710 But the key to being a creative person, partly, is to 354 00:18:06,710 --> 00:18:09,595 be able to do analysis at some level. 355 00:18:09,595 --> 00:18:13,880 To say, how do I know what it is that I'm going to get on 356 00:18:13,880 --> 00:18:17,170 the film before I push the button. 357 00:18:17,170 --> 00:18:23,060 Can I imagine in my mind the resulting image very precisely 358 00:18:23,060 --> 00:18:28,300 and clearly as a consequence of the particular framing, of 359 00:18:28,300 --> 00:18:32,620 the aperture I choose, of the focus, and things like that? 360 00:18:32,620 --> 00:18:35,755 That's part of the art of doing this sort of thing. 361 00:18:35,755 --> 00:18:39,230 And learning a lot of that involves 362 00:18:39,230 --> 00:18:40,970 things like test strips. 363 00:18:40,970 --> 00:18:44,950 You take very simple images that have varying degrees of 364 00:18:44,950 --> 00:18:47,870 density in them, for example, and examine what those look 365 00:18:47,870 --> 00:18:51,630 like on a piece of paper when you print them out. 366 00:18:51,630 --> 00:18:54,270 You find out what is the range of contrasts that you can 367 00:18:54,270 --> 00:18:55,850 actually see. 368 00:18:55,850 --> 00:18:58,650 And what, in a real scene, would correspond to the 369 00:18:58,650 --> 00:19:02,790 various levels and zones that you have of 370 00:19:02,790 --> 00:19:05,440 density in an image. 371 00:19:05,440 --> 00:19:08,410 Well, today I want to look at some very particular test 372 00:19:08,410 --> 00:19:12,000 strips, and I suppose one of them I see here is up on the 373 00:19:12,000 --> 00:19:14,880 telestrator, so we should switch to that. 374 00:19:14,880 --> 00:19:19,350 There's a very important, very important pair of programs for 375 00:19:19,350 --> 00:19:24,500 understanding what's going on in the evolution of a process 376 00:19:24,500 --> 00:19:27,320 by the execution of a program. 377 00:19:27,320 --> 00:19:29,090 What we have here are two procedures 378 00:19:29,090 --> 00:19:30,340 that are almost identical. 379 00:19:30,340 --> 00:19:32,820 380 00:19:32,820 --> 00:19:35,440 Almost no difference between them at all. 381 00:19:35,440 --> 00:19:38,860 It's a few characters that distinguish them. 382 00:19:38,860 --> 00:19:42,140 These are two ways of adding numbers together. 383 00:19:42,140 --> 00:19:48,660 The first one, which you see here, the first one is the sum 384 00:19:48,660 --> 00:19:50,880 of two numbers-- just what we did before-- 385 00:19:50,880 --> 00:19:52,580 is, if the first one is 0, it's the answer 386 00:19:52,580 --> 00:19:53,600 of the second one. 387 00:19:53,600 --> 00:19:56,480 Otherwise, it's the sum of the decrement of the first and the 388 00:19:56,480 --> 00:19:57,960 increment of the second. 389 00:19:57,960 --> 00:20:04,480 And you may think of that as having two piles. 390 00:20:04,480 --> 00:20:06,280 And the way I'm adding these numbers together to make a 391 00:20:06,280 --> 00:20:10,560 third pile is by moving marbles from one to the other. 392 00:20:10,560 --> 00:20:11,640 Nothing more than that. 393 00:20:11,640 --> 00:20:13,520 And eventually, when I run out of one, then the 394 00:20:13,520 --> 00:20:15,650 other is the sum. 395 00:20:15,650 --> 00:20:20,690 However, the second procedure here doesn't do it that way. 396 00:20:20,690 --> 00:20:22,960 It says if the first number is 0, then the 397 00:20:22,960 --> 00:20:24,330 answer is the second. 398 00:20:24,330 --> 00:20:28,550 Otherwise, it's the increment of the sum of the decrement of 399 00:20:28,550 --> 00:20:31,360 the first number and the second. 400 00:20:31,360 --> 00:20:35,930 So what this says is add together the decrement of the 401 00:20:35,930 --> 00:20:38,870 first number and the second-- a simpler problem, no doubt-- 402 00:20:38,870 --> 00:20:43,190 and then change that result to increment it. 403 00:20:43,190 --> 00:20:45,900 And so this means that if you think about this in terms of 404 00:20:45,900 --> 00:20:49,320 piles, it means I'm holding in my hand the 405 00:20:49,320 --> 00:20:52,120 things to be added later. 406 00:20:52,120 --> 00:20:53,990 And then I'm going to add them in. 407 00:20:53,990 --> 00:20:57,710 As I slowly decrease one pile to 0, I've got what's left 408 00:20:57,710 --> 00:21:00,330 here, and then I'm going to add them back. 409 00:21:00,330 --> 00:21:02,360 Two different ways of adding. 410 00:21:02,360 --> 00:21:05,270 The nice thing about these two programs is that they're 411 00:21:05,270 --> 00:21:06,580 almost identical. 412 00:21:06,580 --> 00:21:09,530 The only thing is where I put the increment. 413 00:21:09,530 --> 00:21:11,860 A couple of characters moved around. 414 00:21:11,860 --> 00:21:15,370 Now I want to understand the kind of behavior we're going 415 00:21:15,370 --> 00:21:18,200 to get from each of these programs. Just to get them 416 00:21:18,200 --> 00:21:19,670 firmly in your mind-- 417 00:21:19,670 --> 00:21:22,120 I usually don't want to be this careful-- 418 00:21:22,120 --> 00:21:24,490 but just to get them firmly in your mind, I'm going to write 419 00:21:24,490 --> 00:21:26,155 the programs again on the blackboard, and then I'm going 420 00:21:26,155 --> 00:21:28,150 to evolve a process. 421 00:21:28,150 --> 00:21:29,350 And you're going to see what happens. 422 00:21:29,350 --> 00:21:31,910 We're going to look at the shape of the process as a 423 00:21:31,910 --> 00:21:34,390 consequence of the program. 424 00:21:34,390 --> 00:21:44,170 So the program we started with is this: the sum of x and y 425 00:21:44,170 --> 00:21:51,160 says if x is 0, then the result is y. 426 00:21:51,160 --> 00:21:56,090 Otherwise, it's the sum of the decrement of x and the 427 00:21:56,090 --> 00:21:58,630 increment of y. 428 00:21:58,630 --> 00:22:01,740 429 00:22:01,740 --> 00:22:07,080 Now, supposing we wish to do this addition of 3 and 4, the 430 00:22:07,080 --> 00:22:10,900 sum of 3 and 4, well, what is that? 431 00:22:10,900 --> 00:22:14,580 It says that I have to substitute the arguments for 432 00:22:14,580 --> 00:22:17,750 the formal parameters in the body. 433 00:22:17,750 --> 00:22:19,940 I'm doing that in my mind. 434 00:22:19,940 --> 00:22:22,830 And I say, oh, yes, 3 is substituted for x, but 3 is 435 00:22:22,830 --> 00:22:28,650 not 0, so I'm going to go directly to this part and 436 00:22:28,650 --> 00:22:30,710 write down the simplified consequent here. 437 00:22:30,710 --> 00:22:33,420 Because I'm really interested in the behavior of addition. 438 00:22:33,420 --> 00:22:34,400 Well, what is that? 439 00:22:34,400 --> 00:22:38,460 That therefore turns into the sum of 2 and 5. 440 00:22:38,460 --> 00:22:41,750 In other words, I've reduced this problem to this problem. 441 00:22:41,750 --> 00:22:48,450 Then I reduce this problem to the sum of 1 and 6, and then, 442 00:22:48,450 --> 00:22:53,390 going around again once, I get the sum of 0 and 7. 443 00:22:53,390 --> 00:22:57,110 And that's one where x equals 0 so the result is y, and so I 444 00:22:57,110 --> 00:23:00,260 write down here a 7. 445 00:23:00,260 --> 00:23:03,790 So this is the behavior of the process evolved by trying to 446 00:23:03,790 --> 00:23:07,410 add together 3 and 4 with this program. 447 00:23:07,410 --> 00:23:20,060 For the other program, which is over here, I will define 448 00:23:20,060 --> 00:23:23,376 the sum of x and y. 449 00:23:23,376 --> 00:23:24,626 And what is it? 450 00:23:24,626 --> 00:23:27,260 451 00:23:27,260 --> 00:23:32,100 If x is 0, then the result is y-- almost the same-- 452 00:23:32,100 --> 00:23:36,200 otherwise the increment of the sum of the 453 00:23:36,200 --> 00:23:40,550 decrement of x and y. 454 00:23:40,550 --> 00:23:47,770 455 00:23:47,770 --> 00:23:49,020 No. 456 00:23:49,020 --> 00:23:53,330 457 00:23:53,330 --> 00:23:56,490 I don't have my balancer in front of me. 458 00:23:56,490 --> 00:23:59,060 OK, well, let's do it now. 459 00:23:59,060 --> 00:24:01,560 The sum of 3 and 4. 460 00:24:01,560 --> 00:24:03,660 Well, this is actually a little more interesting. 461 00:24:03,660 --> 00:24:07,930 Of course, 3 is not 0 as before, so that results in the 462 00:24:07,930 --> 00:24:14,240 increment of the sum of the decrement of x, which is 2 and 463 00:24:14,240 --> 00:24:23,240 4, which is the increment of the sum of 1 and-- 464 00:24:23,240 --> 00:24:26,000 whoops: the increment of the increment. 465 00:24:26,000 --> 00:24:30,040 What I have to do now is compute what this means. 466 00:24:30,040 --> 00:24:31,310 I have to evaluate this. 467 00:24:31,310 --> 00:24:33,530 Or what that is, the result of substituting 2 and 468 00:24:33,530 --> 00:24:35,690 4 for x and y here. 469 00:24:35,690 --> 00:24:44,810 But that is the increment of the sum of 1 and 4, which is-- 470 00:24:44,810 --> 00:24:47,820 well, now I have to expand this. 471 00:24:47,820 --> 00:24:52,520 Ah, but that's the increment of the increment of the 472 00:24:52,520 --> 00:24:56,520 increment of the sum of 0 and 4. 473 00:24:56,520 --> 00:25:00,050 474 00:25:00,050 --> 00:25:03,190 Ah, but now I'm beginning to find things I can do. 475 00:25:03,190 --> 00:25:07,430 The increment of the increment of the increment of-- well, 476 00:25:07,430 --> 00:25:08,850 the sum of 0 and 4 is 4. 477 00:25:08,850 --> 00:25:12,430 478 00:25:12,430 --> 00:25:14,235 The increment of 4 is 5. 479 00:25:14,235 --> 00:25:20,880 So this is the increment of the increment of 5, which is 480 00:25:20,880 --> 00:25:26,112 the increment of 6, which is 7. 481 00:25:26,112 --> 00:25:29,960 Two different ways of computing sums. 482 00:25:29,960 --> 00:25:31,430 Now, let's see. 483 00:25:31,430 --> 00:25:34,250 These processes have very different shapes. 484 00:25:34,250 --> 00:25:36,760 I want you to feel these shapes. 485 00:25:36,760 --> 00:25:40,740 It's the feeling for the shapes that matters. 486 00:25:40,740 --> 00:25:43,000 What's some things we can see about this? 487 00:25:43,000 --> 00:25:45,650 Well, somehow this is sort of straight. 488 00:25:45,650 --> 00:25:47,750 It goes this way-- straight. 489 00:25:47,750 --> 00:25:54,130 This right edge doesn't vary particularly in size. 490 00:25:54,130 --> 00:25:57,610 Whereas this one, I see that this thing gets bigger and 491 00:25:57,610 --> 00:25:58,860 then it gets smaller. 492 00:25:58,860 --> 00:26:01,240 493 00:26:01,240 --> 00:26:03,110 So I don't know what that means yet, 494 00:26:03,110 --> 00:26:04,080 but what are we seeing? 495 00:26:04,080 --> 00:26:09,170 We're seeing here that somehow these increments are expanding 496 00:26:09,170 --> 00:26:13,070 out and then contracting back. 497 00:26:13,070 --> 00:26:16,470 I'm building up a bunch of them to do later. 498 00:26:16,470 --> 00:26:18,960 I can't do them now. 499 00:26:18,960 --> 00:26:21,770 There's things to be deferred. 500 00:26:21,770 --> 00:26:23,000 Well, let's see. 501 00:26:23,000 --> 00:26:24,830 I can imagine an abstract machine. 502 00:26:24,830 --> 00:26:26,680 There's some physical machine, perhaps, that could be built 503 00:26:26,680 --> 00:26:29,260 to do it, which, in fact, executes these programs 504 00:26:29,260 --> 00:26:31,730 exactly as I tell you, substituting character strings 505 00:26:31,730 --> 00:26:34,540 in like this. 506 00:26:34,540 --> 00:26:37,910 Such a machine, the number of such steps is an approximation 507 00:26:37,910 --> 00:26:40,040 of the amount of time it takes. 508 00:26:40,040 --> 00:26:41,290 So this way is time. 509 00:26:41,290 --> 00:26:45,510 510 00:26:45,510 --> 00:26:48,890 And the width of the thing is how much I have to remember in 511 00:26:48,890 --> 00:26:50,150 order to continue the process. 512 00:26:50,150 --> 00:26:51,400 And this much is space. 513 00:26:51,400 --> 00:26:53,920 514 00:26:53,920 --> 00:26:58,800 And what we see here is a process that takes a time 515 00:26:58,800 --> 00:27:02,710 which is proportional to the argument x. 516 00:27:02,710 --> 00:27:05,820 Because if I made x larger by 1, then I'd had an extra line. 517 00:27:05,820 --> 00:27:08,810 518 00:27:08,810 --> 00:27:12,080 So this is a process which is space-- sorry-- 519 00:27:12,080 --> 00:27:14,640 time. 520 00:27:14,640 --> 00:27:20,630 The time of this process is what we say order of x. 521 00:27:20,630 --> 00:27:24,390 That means it is proportional to x by some constant of 522 00:27:24,390 --> 00:27:26,430 proportionality, and I'm not particularly interested in 523 00:27:26,430 --> 00:27:28,580 what the constant is. 524 00:27:28,580 --> 00:27:31,360 The other thing we see here is that the amount of space this 525 00:27:31,360 --> 00:27:35,150 takes up is constant, it's proportional to 1. 526 00:27:35,150 --> 00:27:42,070 So the space complexity of this is order of 1. 527 00:27:42,070 --> 00:27:44,180 We have a name for such a process. 528 00:27:44,180 --> 00:27:45,950 Such a process is called an iteration. 529 00:27:45,950 --> 00:27:51,000 530 00:27:51,000 --> 00:27:55,390 And what matters here is not that some particular machine I 531 00:27:55,390 --> 00:27:58,590 designed here and talked to you about and called a 532 00:27:58,590 --> 00:28:00,240 substitution machine or whatever-- 533 00:28:00,240 --> 00:28:01,480 substitution model-- 534 00:28:01,480 --> 00:28:04,550 managed to do this in constant space. 535 00:28:04,550 --> 00:28:07,140 What really matters is this tells us a bound. 536 00:28:07,140 --> 00:28:09,680 Any machine could do this in constant space. 537 00:28:09,680 --> 00:28:13,275 This algorithm represented by this procedure is executable 538 00:28:13,275 --> 00:28:15,250 in constant space. 539 00:28:15,250 --> 00:28:18,330 Now, of course, the model is ignoring some things, standard 540 00:28:18,330 --> 00:28:19,120 sorts of things. 541 00:28:19,120 --> 00:28:22,390 Like numbers that are bigger take up more space and so on. 542 00:28:22,390 --> 00:28:23,990 But that's a level of abstraction at which I'm 543 00:28:23,990 --> 00:28:24,360 cutting off. 544 00:28:24,360 --> 00:28:25,290 How do you represent numbers? 545 00:28:25,290 --> 00:28:28,090 I'm considering every number to be the same size. 546 00:28:28,090 --> 00:28:30,540 And numbers grow slowly for the amount of space they take 547 00:28:30,540 --> 00:28:34,240 up and their size. 548 00:28:34,240 --> 00:28:38,000 Now, this algorithm is different in its complexity. 549 00:28:38,000 --> 00:28:42,850 As we can see here, this algorithm has a time 550 00:28:42,850 --> 00:28:48,220 complexity which is also proportional to the input 551 00:28:48,220 --> 00:28:49,460 argument x. 552 00:28:49,460 --> 00:28:53,040 That's because if I were to add 1 to 3, if I made a larger 553 00:28:53,040 --> 00:28:56,170 problem, which is larger by 1 here, then I'd add a line at 554 00:28:56,170 --> 00:28:57,670 the top and I'd add a line at the bottom. 555 00:28:57,670 --> 00:29:00,650 556 00:29:00,650 --> 00:29:03,300 And the fact that it's a constant amount, like this is 557 00:29:03,300 --> 00:29:05,420 twice as many lines as that, is not interesting at the 558 00:29:05,420 --> 00:29:08,030 level of detail I'm talking about right now. 559 00:29:08,030 --> 00:29:13,020 So this is a time complexity order of the input argument x. 560 00:29:13,020 --> 00:29:18,500 And space complexity, well, this is more interesting. 561 00:29:18,500 --> 00:29:21,130 I happen to have some overhead, which you see over 562 00:29:21,130 --> 00:29:23,670 here, which is constant approximately. 563 00:29:23,670 --> 00:29:24,620 Constant overhead. 564 00:29:24,620 --> 00:29:27,240 But then I have something which increases and decreases 565 00:29:27,240 --> 00:29:29,950 and is proportional to the input argument x. 566 00:29:29,950 --> 00:29:31,350 The input argument x is 3. 567 00:29:31,350 --> 00:29:34,590 That's why there are three deferred increments sitting 568 00:29:34,590 --> 00:29:36,700 around here. 569 00:29:36,700 --> 00:29:37,720 See? 570 00:29:37,720 --> 00:29:42,060 So the space complexity here is also order x. 571 00:29:42,060 --> 00:29:44,835 And this kind of process, named for the kind of process, 572 00:29:44,835 --> 00:29:46,085 this is a recursion. 573 00:29:46,085 --> 00:29:50,770 574 00:29:50,770 --> 00:29:56,020 A linear recursion, I will call it, because of the fact 575 00:29:56,020 --> 00:29:57,920 that it's proportional to the input argument in 576 00:29:57,920 --> 00:29:59,170 both time and space. 577 00:29:59,170 --> 00:30:01,560 578 00:30:01,560 --> 00:30:03,225 This could have been a linear iteration. 579 00:30:03,225 --> 00:30:13,960 580 00:30:13,960 --> 00:30:16,740 So then what's the essence of this matter? 581 00:30:16,740 --> 00:30:19,100 This matter isn't so obvious. 582 00:30:19,100 --> 00:30:21,320 Maybe there are other models by which we can describe the 583 00:30:21,320 --> 00:30:23,780 differences between iterative and recursive processes. 584 00:30:23,780 --> 00:30:25,520 Because this is hard now. 585 00:30:25,520 --> 00:30:27,975 Remember, we have-- those are both recursive definitions. 586 00:30:27,975 --> 00:30:32,020 What we're seeing there are both recursive definitions, 587 00:30:32,020 --> 00:30:34,170 definitions that refer to the thing being defined in the 588 00:30:34,170 --> 00:30:35,330 definition. 589 00:30:35,330 --> 00:30:37,770 But they lead to different shape processes. 590 00:30:37,770 --> 00:30:42,220 There's nothing special about the fact that the definition 591 00:30:42,220 --> 00:30:46,140 is recursive that leads to a recursive process. 592 00:30:46,140 --> 00:30:48,770 OK. 593 00:30:48,770 --> 00:30:50,210 Let's think of another model. 594 00:30:50,210 --> 00:30:52,940 I'm going to talk to you about bureaucracy. 595 00:30:52,940 --> 00:30:54,730 Bureaucracy is sort of interesting. 596 00:30:54,730 --> 00:31:00,076 Here we see on a slide an iteration. 597 00:31:00,076 --> 00:31:04,220 An iteration is sort of a fun kind of process. 598 00:31:04,220 --> 00:31:06,150 Imagine that there's a fellow called GJS-- 599 00:31:06,150 --> 00:31:08,140 that stands for me-- 600 00:31:08,140 --> 00:31:13,240 and he's got a problem: he wants to add together 3 and 4. 601 00:31:13,240 --> 00:31:16,176 This fella here wants to add together 3 and 4. 602 00:31:16,176 --> 00:31:18,850 Well, the way he's going to do it-- he's lazy-- is he's going 603 00:31:18,850 --> 00:31:21,420 to find somebody else to help him do it. 604 00:31:21,420 --> 00:31:22,340 They way he finds someone else to-- 605 00:31:22,340 --> 00:31:25,300 he finds someone else to help him do it and says, well, give 606 00:31:25,300 --> 00:31:28,040 me the answer to 3 and 4 and return the result to me. 607 00:31:28,040 --> 00:31:32,040 He makes a little piece of paper and says, here, here's a 608 00:31:32,040 --> 00:31:33,140 piece of paper-- you go ahead and solve this problem and 609 00:31:33,140 --> 00:31:35,310 give the result back to me. 610 00:31:35,310 --> 00:31:38,370 And this guy, of course, is lazy, too. 611 00:31:38,370 --> 00:31:41,310 He doesn't want to see this piece of paper again. 612 00:31:41,310 --> 00:31:46,550 He says, oh, yes, produce a new problem, which is the sum 613 00:31:46,550 --> 00:31:50,420 of 2 ad 5, and return the result back to GJS. 614 00:31:50,420 --> 00:31:52,290 I don't want to see it again. 615 00:31:52,290 --> 00:31:56,130 This guy does not want to see this piece of paper. 616 00:31:56,130 --> 00:32:01,070 And then this fellow makes a new problem, which is the 617 00:32:01,070 --> 00:32:04,120 addition of the sum of 1 and 6, and he give it to this 618 00:32:04,120 --> 00:32:08,440 fella and says, produce that answer and returned it to GJS. 619 00:32:08,440 --> 00:32:11,270 And that produces a problem, which is to add together 0 and 620 00:32:11,270 --> 00:32:14,190 7, and give the result to GJS. 621 00:32:14,190 --> 00:32:16,650 This fella finally just says, oh, yeah, the answer is 7, and 622 00:32:16,650 --> 00:32:18,480 sends it back to GJS. 623 00:32:18,480 --> 00:32:20,160 That's what an iteration is. 624 00:32:20,160 --> 00:32:22,680 By contrast, a recursion is a slightly 625 00:32:22,680 --> 00:32:23,930 different kind of process. 626 00:32:23,930 --> 00:32:26,390 627 00:32:26,390 --> 00:32:28,520 This one involves more bureaucracy. 628 00:32:28,520 --> 00:32:30,150 It keeps more people busy. 629 00:32:30,150 --> 00:32:32,680 It keeps more people employed. 630 00:32:32,680 --> 00:32:35,850 Perhaps it's better for that reason. 631 00:32:35,850 --> 00:32:38,860 But here it is: I want the answer to the problem 3 and 4. 632 00:32:38,860 --> 00:32:40,780 So I make a piece of paper that says, give the result 633 00:32:40,780 --> 00:32:43,260 back to me. 634 00:32:43,260 --> 00:32:44,670 Give it to this fella. 635 00:32:44,670 --> 00:32:48,050 This fellow says, oh, yes, I will remember that I have to 636 00:32:48,050 --> 00:32:51,550 add later, and I want to get the answer the problem 2 plus 637 00:32:51,550 --> 00:32:55,980 4, give that one to Harry, and have the results 638 00:32:55,980 --> 00:32:56,710 sent back to me-- 639 00:32:56,710 --> 00:32:58,830 I'm Joe. 640 00:32:58,830 --> 00:33:01,800 When the answer comes back from Harry, which is a 6, I 641 00:33:01,800 --> 00:33:07,600 will then do the increment and give that 7 back to GJS. 642 00:33:07,600 --> 00:33:10,240 So there are more pieces of paper outstanding in the 643 00:33:10,240 --> 00:33:12,600 recursive process than the iteration. 644 00:33:12,600 --> 00:33:16,890 645 00:33:16,890 --> 00:33:19,850 There's another way to think about what an iteration is and 646 00:33:19,850 --> 00:33:21,780 the difference between an iteration and a recursion. 647 00:33:21,780 --> 00:33:27,090 You see, the question is, how much stuff is under the table? 648 00:33:27,090 --> 00:33:28,650 If I were to stop-- 649 00:33:28,650 --> 00:33:32,250 supposing I were to kill this computer right now, OK? 650 00:33:32,250 --> 00:33:37,040 And at this point I lose the state of affairs, well, I 651 00:33:37,040 --> 00:33:40,340 could continue the computation from this point but everything 652 00:33:40,340 --> 00:33:43,860 I need to continue the computation is in the 653 00:33:43,860 --> 00:33:48,050 valuables that were defined in the procedure that the 654 00:33:48,050 --> 00:33:49,300 programmer wrote for me. 655 00:33:49,300 --> 00:33:53,080 An iteration is a system that has all of its state in 656 00:33:53,080 --> 00:33:54,330 explicit variables. 657 00:33:54,330 --> 00:33:56,990 658 00:33:56,990 --> 00:34:01,290 Whereas the recursion is not quite the same. 659 00:34:01,290 --> 00:34:05,820 If I were to lose this pile of junk over here, and all I was 660 00:34:05,820 --> 00:34:08,070 left with was the sum of 1 and 4, that's not enough 661 00:34:08,070 --> 00:34:11,290 information to continue the process of computing out the 7 662 00:34:11,290 --> 00:34:14,870 from the original problem of adding together 3 of 4. 663 00:34:14,870 --> 00:34:20,570 Besides the information that's in the variables of the formal 664 00:34:20,570 --> 00:34:24,190 parameters of the program, there is also information 665 00:34:24,190 --> 00:34:27,360 under the table belonging to the computer, which is what 666 00:34:27,360 --> 00:34:30,440 things have been deferred for later. 667 00:34:30,440 --> 00:34:33,500 And, of course, there's a physical analogy to this, 668 00:34:33,500 --> 00:34:38,300 which is in differential equations, for example, when 669 00:34:38,300 --> 00:34:42,300 we talk about something like drawing a circle. 670 00:34:42,300 --> 00:34:45,920 Try to draw a circle, you make that out of a differential 671 00:34:45,920 --> 00:34:51,940 equation which says the change in my state as a function of 672 00:34:51,940 --> 00:34:53,190 my current state. 673 00:34:53,190 --> 00:34:55,830 So if my current state corresponds to particular 674 00:34:55,830 --> 00:35:00,020 values of y and x, then I can compute from them a derivative 675 00:35:00,020 --> 00:35:03,480 which says how the state must change. 676 00:35:03,480 --> 00:35:09,470 And, in fact, you can see this was a circle because if I 677 00:35:09,470 --> 00:35:15,510 happen to be, say, at this place over here, at 1, 0, for 678 00:35:15,510 --> 00:35:21,240 example, on this graph, then it means that the derivative 679 00:35:21,240 --> 00:35:23,620 of y is x, which we see over here. 680 00:35:23,620 --> 00:35:26,140 That's 1, so I'm going up. 681 00:35:26,140 --> 00:35:29,075 And the derivative of x is minus y, which 682 00:35:29,075 --> 00:35:31,510 means I'm going backwards. 683 00:35:31,510 --> 00:35:33,580 I'm actually doing nothing at this point, then I start going 684 00:35:33,580 --> 00:35:37,920 backwards as y increases. 685 00:35:37,920 --> 00:35:40,090 So that's how you make a circle. 686 00:35:40,090 --> 00:35:43,960 And the interesting thing to see is a little program that 687 00:35:43,960 --> 00:35:45,400 will draw a circle by this method. 688 00:35:45,400 --> 00:35:47,675 Actually, this won't draw a circle because it's a forward 689 00:35:47,675 --> 00:35:49,230 oil or integrator and will eventually 690 00:35:49,230 --> 00:35:51,090 spiral out and all that. 691 00:35:51,090 --> 00:35:52,200 But it'll draw a circle for a while 692 00:35:52,200 --> 00:35:54,240 before it starts spiraling. 693 00:35:54,240 --> 00:35:58,050 However, what we see here is two state variables, x and y. 694 00:35:58,050 --> 00:36:01,120 And there's an iteration that says, in order to circle, 695 00:36:01,120 --> 00:36:03,920 given an x and y, what I want is to circle with the next 696 00:36:03,920 --> 00:36:08,260 values of x and y being the old value of x decrement by y 697 00:36:08,260 --> 00:36:14,140 times dt where dt is the time step and the old value of y 698 00:36:14,140 --> 00:36:17,560 being implemented by x times dt, giving me the new values 699 00:36:17,560 --> 00:36:18,810 of x and y. 700 00:36:18,810 --> 00:36:21,390 701 00:36:21,390 --> 00:36:25,360 So now you have a feeling for at least two different kinds 702 00:36:25,360 --> 00:36:28,900 of processes that can be evolved by 703 00:36:28,900 --> 00:36:30,150 almost the same program. 704 00:36:30,150 --> 00:36:32,600 705 00:36:32,600 --> 00:36:34,630 And with a little bit of perturbation analysis like 706 00:36:34,630 --> 00:36:37,320 this, how you change a program a little bit and see how the 707 00:36:37,320 --> 00:36:41,940 process changes, that's how we get some intuition. 708 00:36:41,940 --> 00:36:44,320 Pretty soon we're going to use that intuition to build big, 709 00:36:44,320 --> 00:36:45,060 hairy, complicated 710 00:36:45,060 --> 00:36:47,627 systems. Thank you. 711 00:36:47,627 --> 00:37:06,513 [MUSIC PLAYING BY J.S. BACH] 712 00:37:06,513 --> 00:37:09,100 PROFESSOR: Well, you've just seen a simple perturbational 713 00:37:09,100 --> 00:37:13,690 analysis of some programs. I took a program that was very 714 00:37:13,690 --> 00:37:16,580 similar to another program and looked at them both and saw 715 00:37:16,580 --> 00:37:18,540 how they evolved processes. 716 00:37:18,540 --> 00:37:20,580 I want to show you some variety by showing you some 717 00:37:20,580 --> 00:37:25,033 other processes and shapes they may have. Again, we're 718 00:37:25,033 --> 00:37:27,140 going to take very simple things, programs that you 719 00:37:27,140 --> 00:37:29,070 wouldn't want to ever write. 720 00:37:29,070 --> 00:37:32,565 They would be probably the worst way of computing some of 721 00:37:32,565 --> 00:37:34,080 the things we're going to compute. 722 00:37:34,080 --> 00:37:36,040 But I'm just going to show you these things for the purpose 723 00:37:36,040 --> 00:37:42,750 of feeling out how to program represents itself as the rule 724 00:37:42,750 --> 00:37:46,486 for the evolution of a process. 725 00:37:46,486 --> 00:37:50,770 So let's consider a fun thing, the Fibonacci numbers. 726 00:37:50,770 --> 00:37:53,340 You probably know about the Fibonacci numbers. 727 00:37:53,340 --> 00:37:57,740 Somebody, I can't remember who, was interested in the 728 00:37:57,740 --> 00:38:00,035 growth of piles of rabbits. 729 00:38:00,035 --> 00:38:03,670 And for some reason or other, the piles of rabbits tend to 730 00:38:03,670 --> 00:38:05,870 grow exponentially, as we know. 731 00:38:05,870 --> 00:38:09,700 And we have a nice model for this process, is that we start 732 00:38:09,700 --> 00:38:13,750 with two numbers, 0 and 1. 733 00:38:13,750 --> 00:38:16,000 And then every number after this is the 734 00:38:16,000 --> 00:38:18,040 sum of the two previous. 735 00:38:18,040 --> 00:38:20,240 So we have here a 1. 736 00:38:20,240 --> 00:38:22,760 Then the sum of these two is 2. 737 00:38:22,760 --> 00:38:24,570 The sum of those two is 3. 738 00:38:24,570 --> 00:38:26,465 The sum of those two is 5. 739 00:38:26,465 --> 00:38:28,640 The sum of those two is 8. 740 00:38:28,640 --> 00:38:31,650 The sum of those two is 13. 741 00:38:31,650 --> 00:38:34,800 This is 21. 742 00:38:34,800 --> 00:38:36,940 34. 743 00:38:36,940 --> 00:38:38,160 55. 744 00:38:38,160 --> 00:38:40,640 Et cetera. 745 00:38:40,640 --> 00:38:43,170 If we start numbering these numbers, say this is the 746 00:38:43,170 --> 00:38:46,280 zeroth one, the first one, the second one, the third one, the 747 00:38:46,280 --> 00:38:47,780 fourth one, et cetera. 748 00:38:47,780 --> 00:38:51,850 This is the 10th one, the 10th Fibonacci number. 749 00:38:51,850 --> 00:38:56,010 These numbers grow very fast. Just like rabbits. 750 00:38:56,010 --> 00:38:59,750 Why rabbits grow this way I'm not going to hazard a guess. 751 00:38:59,750 --> 00:39:02,550 Now, I'm going to try to write for you the very simplest 752 00:39:02,550 --> 00:39:05,740 program that computes Fibonacci numbers. 753 00:39:05,740 --> 00:39:08,300 754 00:39:08,300 --> 00:39:13,375 What I want is a program that, given an n, will produce for 755 00:39:13,375 --> 00:39:14,625 me Fibonacci event. 756 00:39:14,625 --> 00:39:18,220 757 00:39:18,220 --> 00:39:19,470 OK? 758 00:39:19,470 --> 00:39:21,830 759 00:39:21,830 --> 00:39:23,080 I'll write it right here. 760 00:39:23,080 --> 00:39:28,240 761 00:39:28,240 --> 00:39:33,275 I want the Fibonacci of n, which means the-- this is the 762 00:39:33,275 --> 00:39:36,066 n, and this is Fibonacci of n. 763 00:39:36,066 --> 00:39:38,160 And here's the story. 764 00:39:38,160 --> 00:39:45,330 If n is less than 2, then the result is n. 765 00:39:45,330 --> 00:39:47,260 Because that's what these are. 766 00:39:47,260 --> 00:39:49,090 That's how you start it up. 767 00:39:49,090 --> 00:39:58,870 Otherwise, the result is the sum of Fib of n minus 1 and 768 00:39:58,870 --> 00:40:01,344 the Fibonacci number, n minus 2. 769 00:40:01,344 --> 00:40:10,540 770 00:40:10,540 --> 00:40:13,620 So this is a very simple, direct specification of the 771 00:40:13,620 --> 00:40:16,765 description of Fibonacci numbers that I gave you when I 772 00:40:16,765 --> 00:40:18,460 introduced those numbers. 773 00:40:18,460 --> 00:40:21,670 It represents the recurrence relation in the simplest 774 00:40:21,670 --> 00:40:23,650 possible way. 775 00:40:23,650 --> 00:40:24,920 Now, how do we use such a thing? 776 00:40:24,920 --> 00:40:27,230 Let's draw this process. 777 00:40:27,230 --> 00:40:29,610 Let's figure out what this does. 778 00:40:29,610 --> 00:40:31,620 Let's consider something very simple by computing 779 00:40:31,620 --> 00:40:32,870 Fibonacci of 4. 780 00:40:32,870 --> 00:40:35,679 781 00:40:35,679 --> 00:40:39,070 To compute Fibonacci of 4, what do I do? 782 00:40:39,070 --> 00:40:41,080 Well, it says I have-- 783 00:40:41,080 --> 00:40:43,070 it's not less than 2. 784 00:40:43,070 --> 00:40:45,500 Therefore it's the sum of two things. 785 00:40:45,500 --> 00:40:47,430 Well, in order to compute that I have to compute, then, 786 00:40:47,430 --> 00:40:52,860 Fibonacci of 3 and Fibonacci of 2. 787 00:40:52,860 --> 00:40:57,200 788 00:40:57,200 --> 00:41:00,940 In order to compute Fibonacci of 3, I have to compute 789 00:41:00,940 --> 00:41:04,340 Fibonacci of 2 and Fibonacci of 1. 790 00:41:04,340 --> 00:41:08,000 791 00:41:08,000 --> 00:41:10,730 In order to compute Fibonacci of 2, I have to compute 792 00:41:10,730 --> 00:41:12,090 Fibonacci of 1 and Fibonacci of 0. 793 00:41:12,090 --> 00:41:16,890 794 00:41:16,890 --> 00:41:20,010 In order to compute Fibonacci of 1, well, the answer is 1. 795 00:41:20,010 --> 00:41:26,070 That's from the base case of this recursion. 796 00:41:26,070 --> 00:41:28,923 And in order to compute Fibonacci of 0, well, that 797 00:41:28,923 --> 00:41:30,480 answer is 0, from the same base. 798 00:41:30,480 --> 00:41:33,200 And here is a 1. 799 00:41:33,200 --> 00:41:38,238 And Fibonacci of 2 is really the sum of Fibonacci of 1. 800 00:41:38,238 --> 00:41:43,023 And Fib of 0, in order to compute that, I get a 1, and 801 00:41:43,023 --> 00:41:44,273 here I've got a 0. 802 00:41:44,273 --> 00:41:47,010 803 00:41:47,010 --> 00:41:50,310 I've built a tree. 804 00:41:50,310 --> 00:41:53,700 Now, we can observe some things about this tree. 805 00:41:53,700 --> 00:41:56,340 We can see why this is an extremely bad way to compute 806 00:41:56,340 --> 00:41:58,420 Fibonacci numbers. 807 00:41:58,420 --> 00:41:59,960 Because in order to compute Fibonacci of 4, I had to 808 00:41:59,960 --> 00:42:03,045 compute Fibonacci of 2's sub-tree twice. 809 00:42:03,045 --> 00:42:07,670 810 00:42:07,670 --> 00:42:10,326 In fact, in order way to add one more, supposing I want to 811 00:42:10,326 --> 00:42:13,940 do Fibonacci of 5, what I really have to do then is 812 00:42:13,940 --> 00:42:18,100 compute Fibonacci of 4 plus Fibonacci of 3. 813 00:42:18,100 --> 00:42:21,045 But Fibonacci of 3's sub-tree has already been built. 814 00:42:21,045 --> 00:42:24,870 815 00:42:24,870 --> 00:42:27,700 This is a prescription for a process that's 816 00:42:27,700 --> 00:42:30,570 exponential in time. 817 00:42:30,570 --> 00:42:33,740 To add 1, I have to multiply by something because I take a 818 00:42:33,740 --> 00:42:38,350 proportion of the existing thing and add it to itself to 819 00:42:38,350 --> 00:42:39,880 add one more step. 820 00:42:39,880 --> 00:42:48,270 So this is a thing whose time complexity is order of-- 821 00:42:48,270 --> 00:42:50,520 actually, it turns out to be Fibonacci-- 822 00:42:50,520 --> 00:42:51,770 of n. 823 00:42:51,770 --> 00:42:56,230 824 00:42:56,230 --> 00:43:01,130 There's a thing that grows exactly at Fibonacci numbers. 825 00:43:01,130 --> 00:43:02,620 It's a horrible thing. 826 00:43:02,620 --> 00:43:03,640 You wouldn't want to do it. 827 00:43:03,640 --> 00:43:06,170 The reason why the time has to grow that way is because we're 828 00:43:06,170 --> 00:43:07,110 presuming in the model-- 829 00:43:07,110 --> 00:43:09,220 the substitution model that I gave you, which I'm not doing 830 00:43:09,220 --> 00:43:14,130 formally here, I sort of now spit it out in a simple way-- 831 00:43:14,130 --> 00:43:17,880 but presuming that everything is done sequentially. 832 00:43:17,880 --> 00:43:19,810 That every one of these nodes in this 833 00:43:19,810 --> 00:43:21,350 tree has to be examined. 834 00:43:21,350 --> 00:43:24,740 835 00:43:24,740 --> 00:43:27,350 And so since the number of nodes in this tree grows 836 00:43:27,350 --> 00:43:29,960 exponentially, because I add a proportion of the existing 837 00:43:29,960 --> 00:43:35,820 nodes to the nodes I already have to add 1, then I know 838 00:43:35,820 --> 00:43:38,860 I've got an exponential explosion here. 839 00:43:38,860 --> 00:43:40,610 Now, let's see if we can think of how much 840 00:43:40,610 --> 00:43:41,860 space this takes up. 841 00:43:41,860 --> 00:43:44,520 842 00:43:44,520 --> 00:43:46,140 Well, it's not so bad. 843 00:43:46,140 --> 00:43:48,020 It depends on how much we have to remember in order to 844 00:43:48,020 --> 00:43:50,220 continue this thing running. 845 00:43:50,220 --> 00:43:51,650 Well, that's not so hard. 846 00:43:51,650 --> 00:43:54,815 It says, gee, in order to know where I am in this tree, I 847 00:43:54,815 --> 00:43:56,760 have to have a path back to the root. 848 00:43:56,760 --> 00:43:59,210 In other words, in order to-- let's consider the path I 849 00:43:59,210 --> 00:44:00,795 would have to execute this. 850 00:44:00,795 --> 00:44:03,190 I'd say, oh, yes, I'm going to go down here. 851 00:44:03,190 --> 00:44:04,950 I don't care which direction I go. 852 00:44:04,950 --> 00:44:06,265 I have to do this. 853 00:44:06,265 --> 00:44:06,935 I have to then do this. 854 00:44:06,935 --> 00:44:09,300 I have to traverse this tree in a sort of funny way. 855 00:44:09,300 --> 00:44:12,040 856 00:44:12,040 --> 00:44:13,290 I'm going to walk this nice little path. 857 00:44:13,290 --> 00:44:15,740 I come back to here. 858 00:44:15,740 --> 00:44:18,050 Well, I've got to remember where I'm going to be next. 859 00:44:18,050 --> 00:44:20,110 I've got to keep that in mind. 860 00:44:20,110 --> 00:44:21,240 So I have to know what I've done. 861 00:44:21,240 --> 00:44:22,740 I have to know what's left. 862 00:44:22,740 --> 00:44:26,793 In order to compute Fibonacci of 4, at some point I'm going 863 00:44:26,793 --> 00:44:28,580 to have to be down here. 864 00:44:28,580 --> 00:44:32,170 And I have to remember that I have to go back and then go 865 00:44:32,170 --> 00:44:33,750 back to here to do an addition. 866 00:44:33,750 --> 00:44:35,200 And then go back to here to do an addition to something I 867 00:44:35,200 --> 00:44:38,060 haven't touched yet. 868 00:44:38,060 --> 00:44:40,390 The amount of space that takes up is the 869 00:44:40,390 --> 00:44:42,800 path, the longest path. 870 00:44:42,800 --> 00:44:45,920 How long it is. 871 00:44:45,920 --> 00:44:48,360 And that grows as n. 872 00:44:48,360 --> 00:44:50,550 So the space-- 873 00:44:50,550 --> 00:44:53,040 because that's the length of the deepest 874 00:44:53,040 --> 00:44:54,660 line through the tree-- 875 00:44:54,660 --> 00:44:59,210 the space is order of n. 876 00:44:59,210 --> 00:45:00,460 It's a pretty bad process. 877 00:45:00,460 --> 00:45:09,010 878 00:45:09,010 --> 00:45:13,930 Now, one thing I want to see from this is a feeling of 879 00:45:13,930 --> 00:45:15,660 what's going on here. 880 00:45:15,660 --> 00:45:17,460 Why are there-- 881 00:45:17,460 --> 00:45:20,712 how is this program related to this process? 882 00:45:20,712 --> 00:45:22,150 Well, what are we seeing here? 883 00:45:22,150 --> 00:45:25,110 There really are only two sorts of things 884 00:45:25,110 --> 00:45:27,460 this program does. 885 00:45:27,460 --> 00:45:29,950 This program consists of two rules, if you will. 886 00:45:29,950 --> 00:45:36,100 One rule that says Fibonacci of n is this sum that you see 887 00:45:36,100 --> 00:45:42,120 over here, which is a node that's shaped like this. 888 00:45:42,120 --> 00:45:45,165 It says that I break up something into two parts. 889 00:45:45,165 --> 00:45:48,340 890 00:45:48,340 --> 00:45:52,890 Under some condition over here that n is greater than 2, then 891 00:45:52,890 --> 00:45:56,880 the node breaks up into two parts. 892 00:45:56,880 --> 00:45:57,920 Less than 2. 893 00:45:57,920 --> 00:45:58,390 No. 894 00:45:58,390 --> 00:46:00,704 Greater than 2. 895 00:46:00,704 --> 00:46:01,830 Yes. 896 00:46:01,830 --> 00:46:04,700 The other possibility is that I have a reduction 897 00:46:04,700 --> 00:46:05,950 that looks like this. 898 00:46:05,950 --> 00:46:08,780 899 00:46:08,780 --> 00:46:10,950 And that's this case. 900 00:46:10,950 --> 00:46:14,470 If it's less than 2, the answer is n itself. 901 00:46:14,470 --> 00:46:16,990 So what we're seeing here is that the process that got 902 00:46:16,990 --> 00:46:22,210 built locally at every place is an instance of this rule. 903 00:46:22,210 --> 00:46:24,130 Here's one instance of the rule. 904 00:46:24,130 --> 00:46:26,350 Here is another instance of the rule. 905 00:46:26,350 --> 00:46:28,460 And the reason why people think of programming as being 906 00:46:28,460 --> 00:46:32,230 hard, of course, is because you're writing down a general 907 00:46:32,230 --> 00:46:37,310 rule, which is going to be used for lots of instances, 908 00:46:37,310 --> 00:46:39,710 that a particular instance-- 909 00:46:39,710 --> 00:46:43,900 it's going to control each particular instance for you. 910 00:46:43,900 --> 00:46:46,820 You've got to write down something that's a general in 911 00:46:46,820 --> 00:46:48,400 terms of variables, and you have to think of all the 912 00:46:48,400 --> 00:46:50,640 things that could possibly fit in those variables, and all 913 00:46:50,640 --> 00:46:53,600 those have to lead to the process you want to work. 914 00:46:53,600 --> 00:46:57,770 Locally, you have to break up your process into things that 915 00:46:57,770 --> 00:46:59,490 can be represented in terms of these very 916 00:46:59,490 --> 00:47:00,740 specific local rules. 917 00:47:00,740 --> 00:47:03,540 918 00:47:03,540 --> 00:47:05,030 Well, let's see. 919 00:47:05,030 --> 00:47:08,190 Fibonaccis are, of course, not much fun. 920 00:47:08,190 --> 00:47:09,180 Yes, they are. 921 00:47:09,180 --> 00:47:12,820 You get something called the golden ratio, and we may even 922 00:47:12,820 --> 00:47:15,420 see a lot of that some time. 923 00:47:15,420 --> 00:47:16,840 Well, let's talk about another thing. 924 00:47:16,840 --> 00:47:20,310 There's a famous game called the Towers of Hanoi, because I 925 00:47:20,310 --> 00:47:24,170 want to teach you how to think about these recursively. 926 00:47:24,170 --> 00:47:29,700 The problem is this one: I have a bunch of disks, I have 927 00:47:29,700 --> 00:47:34,130 a bunch of spikes, and it's rumored that somewhere in the 928 00:47:34,130 --> 00:47:38,420 Orient there is a 64-high tower, and the job of various 929 00:47:38,420 --> 00:47:41,320 monks or something is to move these spikes in some 930 00:47:41,320 --> 00:47:43,860 complicated pattern so eventually-- 931 00:47:43,860 --> 00:47:45,220 these disks-- 932 00:47:45,220 --> 00:47:49,450 so eventually I moved all of the disks from one 933 00:47:49,450 --> 00:47:50,555 spike to the other. 934 00:47:50,555 --> 00:47:54,000 And if it's 64 high, and it's going to take 2 to the 64th 935 00:47:54,000 --> 00:47:57,746 moves, then it's a long time. 936 00:47:57,746 --> 00:48:03,820 They claim that the universe ends when this is done. 937 00:48:03,820 --> 00:48:05,630 Well, let's see. 938 00:48:05,630 --> 00:48:08,830 The way in which you would construct a recursive process 939 00:48:08,830 --> 00:48:11,990 is by wishful thinking. 940 00:48:11,990 --> 00:48:14,600 You have to believe. 941 00:48:14,600 --> 00:48:15,610 So, the idea. 942 00:48:15,610 --> 00:48:20,360 Supposing I want to move this pile from here to here, from 943 00:48:20,360 --> 00:48:25,400 spike one to spike two, well, that's not so hard. 944 00:48:25,400 --> 00:48:28,470 See, supposing somehow, by some magic-- because I've got 945 00:48:28,470 --> 00:48:29,310 a simpler problem-- 946 00:48:29,310 --> 00:48:31,240 I move a three-high pile to here-- 947 00:48:31,240 --> 00:48:32,070 I can only move one disk at a time, so 948 00:48:32,070 --> 00:48:33,900 identifying how I did it. 949 00:48:33,900 --> 00:48:37,910 But supposing I could do that, well, then I could just pick 950 00:48:37,910 --> 00:48:41,500 up this disk and move it here. 951 00:48:41,500 --> 00:48:42,980 And now I have a simple problem. 952 00:48:42,980 --> 00:48:44,110 I have to move a three-high tower to 953 00:48:44,110 --> 00:48:46,220 here, which is no problem. 954 00:48:46,220 --> 00:48:48,860 So by two moves of a three high tower plus one move of a 955 00:48:48,860 --> 00:48:53,140 single object, I can move the tower from here to here. 956 00:48:53,140 --> 00:48:55,680 957 00:48:55,680 --> 00:48:57,530 Now, whether or not-- 958 00:48:57,530 --> 00:49:02,730 this is not obvious in any deep way that this works. 959 00:49:02,730 --> 00:49:04,300 And why? 960 00:49:04,300 --> 00:49:07,320 Now, why is it the case that I can presume, maybe, that I can 961 00:49:07,320 --> 00:49:08,570 move the three-high tower? 962 00:49:08,570 --> 00:49:11,430 963 00:49:11,430 --> 00:49:14,550 Well, the answer is because I'm always counting down, and 964 00:49:14,550 --> 00:49:16,840 eventually I get down to zero-high tower, and a 965 00:49:16,840 --> 00:49:20,070 zero-high tower requires no moves. 966 00:49:20,070 --> 00:49:24,060 So let's write the algorithm for that. 967 00:49:24,060 --> 00:49:26,670 Very easy. 968 00:49:26,670 --> 00:49:29,260 I'm going to label these towers with numbers, but it 969 00:49:29,260 --> 00:49:31,120 doesn't matter what they're labelled with. 970 00:49:31,120 --> 00:49:35,020 And the problem is to move an n-high tower from a spike 971 00:49:35,020 --> 00:49:37,785 called From to a spike called To with a particular spike 972 00:49:37,785 --> 00:49:39,968 called Spare. 973 00:49:39,968 --> 00:49:41,414 That's what we're going to do. 974 00:49:41,414 --> 00:49:50,240 975 00:49:50,240 --> 00:49:53,070 Using the algorithm I informally described to you, 976 00:49:53,070 --> 00:50:02,532 move of a n-high tower from From to To with a Spare. 977 00:50:02,532 --> 00:50:06,300 978 00:50:06,300 --> 00:50:11,540 Well, I've got two cases, and this is a case analysis, just 979 00:50:11,540 --> 00:50:14,840 like it is in all the other things we've done. 980 00:50:14,840 --> 00:50:20,285 981 00:50:20,285 --> 00:50:23,160 If n is 0, then-- 982 00:50:23,160 --> 00:50:24,600 I'm going to put out some answers-- 983 00:50:24,600 --> 00:50:26,870 Done, we'll say. 984 00:50:26,870 --> 00:50:29,530 I don't know what that means. 985 00:50:29,530 --> 00:50:32,200 Because we'll never use that answer for anything. 986 00:50:32,200 --> 00:50:34,350 We're going to do these moves. 987 00:50:34,350 --> 00:50:36,640 Else. 988 00:50:36,640 --> 00:50:37,890 I'm going to do a move. 989 00:50:37,890 --> 00:50:40,250 990 00:50:40,250 --> 00:50:44,495 Move a tower of height less than n, the 991 00:50:44,495 --> 00:50:48,140 decrement of n height. 992 00:50:48,140 --> 00:50:51,030 Now, I'm going to move it to the Spare tower. 993 00:50:51,030 --> 00:50:55,220 The whole idea now is to move this from here to here, to the 994 00:50:55,220 --> 00:50:57,550 Spare tower-- so from From to Spare-- 995 00:50:57,550 --> 00:51:03,050 996 00:51:03,050 --> 00:51:04,700 using To as a spare tower. 997 00:51:04,700 --> 00:51:08,960 998 00:51:08,960 --> 00:51:14,680 Later, somewhere later, I'm going to move that same n-high 999 00:51:14,680 --> 00:51:17,340 tower, after I've done this. 1000 00:51:17,340 --> 00:51:21,650 Going to move that same n minus one-high tower from the 1001 00:51:21,650 --> 00:51:24,750 Spare tower to the To tower using the 1002 00:51:24,750 --> 00:51:26,380 From tower as my spare. 1003 00:51:26,380 --> 00:51:29,390 1004 00:51:29,390 --> 00:51:40,410 So the Spare tower to the To tower using 1005 00:51:40,410 --> 00:51:44,225 the From as the spare. 1006 00:51:44,225 --> 00:51:48,780 1007 00:51:48,780 --> 00:51:51,670 All I have to do now is when I've gotten it in this 1008 00:51:51,670 --> 00:51:56,600 condition, between these two moves of a whole tower-- 1009 00:51:56,600 --> 00:51:57,950 I've got it into that condition-- 1010 00:51:57,950 --> 00:52:03,100 now I just have to move one disk. 1011 00:52:03,100 --> 00:52:04,543 So I'm going to say that some things are printing a move and 1012 00:52:04,543 --> 00:52:05,793 I don't care how it works. 1013 00:52:05,793 --> 00:52:11,680 1014 00:52:11,680 --> 00:52:13,660 From the To. 1015 00:52:13,660 --> 00:52:17,890 1016 00:52:17,890 --> 00:52:20,410 Now, you see the reason why I'm bringing this up at this 1017 00:52:20,410 --> 00:52:24,800 moment is this is an almost identical program to this one 1018 00:52:24,800 --> 00:52:26,980 in some sense. 1019 00:52:26,980 --> 00:52:29,810 It's not computing the same mathematical quantity, it's 1020 00:52:29,810 --> 00:52:34,620 not exactly the same tree, but it's going to produce a tree. 1021 00:52:34,620 --> 00:52:38,760 The general way of making these moves is going to lead 1022 00:52:38,760 --> 00:52:41,760 to an exponential tree. 1023 00:52:41,760 --> 00:52:43,060 Well, let's do this four-high. 1024 00:52:43,060 --> 00:52:45,720 1025 00:52:45,720 --> 00:52:50,660 I have my little crib sheet here otherwise I get confused. 1026 00:52:50,660 --> 00:52:54,720 1027 00:52:54,720 --> 00:52:57,320 Well, what I'm going to put in is the question of move a 1028 00:52:57,320 --> 00:53:10,080 tower of height four from one to spike two using spike three 1029 00:53:10,080 --> 00:53:11,980 as a spare. 1030 00:53:11,980 --> 00:53:14,190 That's all I'm really going to do. 1031 00:53:14,190 --> 00:53:15,550 You know, let's just do it. 1032 00:53:15,550 --> 00:53:17,140 I'm not going to worry about writing out 1033 00:53:17,140 --> 00:53:17,950 the traits of this. 1034 00:53:17,950 --> 00:53:21,950 You can do that yourself because it's very simple. 1035 00:53:21,950 --> 00:53:26,680 I'm going to move disk one to disk three. 1036 00:53:26,680 --> 00:53:28,760 And how do I get to move disk one to disk three? 1037 00:53:28,760 --> 00:53:29,530 How do I know that? 1038 00:53:29,530 --> 00:53:32,790 Well, I suppose I have to look at the trace a little bit. 1039 00:53:32,790 --> 00:53:33,810 What am I doing here? 1040 00:53:33,810 --> 00:53:36,560 Well, and this is not-- n is not zero. 1041 00:53:36,560 --> 00:53:38,650 So I'm going to look down here. 1042 00:53:38,650 --> 00:53:41,000 This is going to require doing two moves. 1043 00:53:41,000 --> 00:53:42,320 I'm only going to look at the first one. 1044 00:53:42,320 --> 00:53:43,570 It's going to require moving-- 1045 00:53:43,570 --> 00:53:47,860 1046 00:53:47,860 --> 00:53:49,010 why do I have move tower? 1047 00:53:49,010 --> 00:53:52,910 It makes it harder for me to move. 1048 00:53:52,910 --> 00:53:59,950 I'm going to move a three-high tower from the from place, 1049 00:53:59,950 --> 00:54:04,750 which is four, to the spare, which is two, 1050 00:54:04,750 --> 00:54:07,940 using three as my-- 1051 00:54:07,940 --> 00:54:15,220 no, using from-- 1052 00:54:15,220 --> 00:54:15,988 STUDENT: [INAUDIBLE PHRASE]. 1053 00:54:15,988 --> 00:54:16,944 PROFESSOR: Yes. 1054 00:54:16,944 --> 00:54:18,370 I'm sorry. 1055 00:54:18,370 --> 00:54:19,710 From two-- 1056 00:54:19,710 --> 00:54:26,230 from one to three using two as my spare. 1057 00:54:26,230 --> 00:54:27,520 That's right. 1058 00:54:27,520 --> 00:54:32,940 And then there's another move over here afterwards. 1059 00:54:32,940 --> 00:54:37,790 So now I say, oh, yes, that requires me moving a two-high 1060 00:54:37,790 --> 00:54:42,950 tower from one to two using three as a spare. 1061 00:54:42,950 --> 00:54:45,760 And so, are the same, and that's going to require me 1062 00:54:45,760 --> 00:54:52,470 moving and one-high tower from one to three 1063 00:54:52,470 --> 00:54:53,720 using two as a spare. 1064 00:54:53,720 --> 00:54:57,740 1065 00:54:57,740 --> 00:54:59,720 Well, and then there's lots of other things to be done. 1066 00:54:59,720 --> 00:55:03,510 1067 00:55:03,510 --> 00:55:09,265 So I move my one-high tower from one to three using two as 1068 00:55:09,265 --> 00:55:11,490 a spare, which I didn't do anything with. 1069 00:55:11,490 --> 00:55:15,570 Well, this thing just proceeds very simply. 1070 00:55:15,570 --> 00:55:17,652 I move this from one to two. 1071 00:55:17,652 --> 00:55:21,500 And I move this disk from three to two. 1072 00:55:21,500 --> 00:55:23,060 And I don't really want to do it, but I 1073 00:55:23,060 --> 00:55:24,310 move from one to three. 1074 00:55:24,310 --> 00:55:29,390 Then I move two to one. 1075 00:55:29,390 --> 00:55:32,150 Then I move two to three. 1076 00:55:32,150 --> 00:55:36,310 Then one to three. 1077 00:55:36,310 --> 00:55:39,620 One to two. 1078 00:55:39,620 --> 00:55:41,390 Three to two. 1079 00:55:41,390 --> 00:55:44,055 Three to one. 1080 00:55:44,055 --> 00:55:46,380 This all got worked out beforehand, of course. 1081 00:55:46,380 --> 00:55:48,090 Two to one. 1082 00:55:48,090 --> 00:55:50,810 Three to two. 1083 00:55:50,810 --> 00:55:52,950 One to three. 1084 00:55:52,950 --> 00:55:54,176 STUDENT: [INAUDIBLE PHRASE]. 1085 00:55:54,176 --> 00:55:55,650 PROFESSOR: Oh, one to three. 1086 00:55:55,650 --> 00:55:55,823 Excuse me. 1087 00:55:55,823 --> 00:55:56,460 Thank you. 1088 00:55:56,460 --> 00:55:59,020 One to two. 1089 00:55:59,020 --> 00:56:00,850 And then three to two. 1090 00:56:00,850 --> 00:56:02,100 Whew. 1091 00:56:02,100 --> 00:56:04,250 1092 00:56:04,250 --> 00:56:07,920 Now what I'd like you to think about, you just saw a 1093 00:56:07,920 --> 00:56:09,920 recursive algorithm for doing this, and it takes exponential 1094 00:56:09,920 --> 00:56:11,040 time, of course. 1095 00:56:11,040 --> 00:56:12,530 Now, I don't know if there's any algorithm that doesn't 1096 00:56:12,530 --> 00:56:14,820 take exponential time-- it has to. 1097 00:56:14,820 --> 00:56:16,320 As I'm doing one operation-- 1098 00:56:16,320 --> 00:56:17,890 I can only move one thing at a time-- 1099 00:56:17,890 --> 00:56:18,590 there's no algorithm that's not going to 1100 00:56:18,590 --> 00:56:20,570 take exponential time. 1101 00:56:20,570 --> 00:56:24,420 But can you write an iterative algorithm rather than a 1102 00:56:24,420 --> 00:56:25,670 recursive algorithm for doing this? 1103 00:56:25,670 --> 00:56:28,740 1104 00:56:28,740 --> 00:56:30,700 One of the sort of little things I like to think about. 1105 00:56:30,700 --> 00:56:33,590 1106 00:56:33,590 --> 00:56:38,970 Can you write one that, in fact, doesn't break this 1107 00:56:38,970 --> 00:56:41,510 problem into two sub-problems the way I described, but 1108 00:56:41,510 --> 00:56:45,250 rather proceeds a step at a time using a more local rule? 1109 00:56:45,250 --> 00:56:48,160 1110 00:56:48,160 --> 00:56:50,660 That might be fun. 1111 00:56:50,660 --> 00:56:52,025 Thank you so much for the third segment. 1112 00:56:52,025 --> 00:56:56,310 1113 00:56:56,310 --> 00:56:57,910 Are there questions? 1114 00:56:57,910 --> 00:57:01,670 STUDENT: [INAUDIBLE] a way to reduce a tree or recursion 1115 00:57:01,670 --> 00:57:06,970 problem, how do you save the immediate work you have done 1116 00:57:06,970 --> 00:57:08,985 in computing the Fibonacci number? 1117 00:57:08,985 --> 00:57:12,760 PROFESSOR: Oh, well, in fact, one of the ways to do is what 1118 00:57:12,760 --> 00:57:13,890 you just said. 1119 00:57:13,890 --> 00:57:16,480 You said, I save the intermediate work. 1120 00:57:16,480 --> 00:57:16,960 OK? 1121 00:57:16,960 --> 00:57:19,310 Well, let me tell you-- 1122 00:57:19,310 --> 00:57:21,010 this, again, we'll see later-- 1123 00:57:21,010 --> 00:57:24,710 but suppose it's the case that anytime I compute anything, 1124 00:57:24,710 --> 00:57:28,240 any one of these Fibonacci numbers, I remember the table 1125 00:57:28,240 --> 00:57:32,790 that takes only linear time to look up the answer. 1126 00:57:32,790 --> 00:57:35,180 Then if I ever see it again, instead of doing the 1127 00:57:35,180 --> 00:57:37,050 expansional tree, I look it up. 1128 00:57:37,050 --> 00:57:39,820 I've just transformed my problem into a problem that's 1129 00:57:39,820 --> 00:57:41,380 much simpler. 1130 00:57:41,380 --> 00:57:44,380 Now, of course, there are the way to do this, as well. 1131 00:57:44,380 --> 00:57:47,240 That one's called memoization, and you'll see it sometime 1132 00:57:47,240 --> 00:57:48,280 later in this term. 1133 00:57:48,280 --> 00:57:53,890 But I suppose there's a very simple linear time, and, in 1134 00:57:53,890 --> 00:57:57,110 fact, iterative model for computing Fibonaccis, and 1135 00:57:57,110 --> 00:58:00,320 that's another thing you should sit down and work out. 1136 00:58:00,320 --> 00:58:01,340 That's important. 1137 00:58:01,340 --> 00:58:05,560 It's important to see how to do this. 1138 00:58:05,560 --> 00:58:07,310 I want you to practice. 1139 00:58:07,310 --> 00:58:19,540 ================================================ FILE: SrtEN/lec2a_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:25,680 1 00:00:25,680 --> 00:00:27,960 PROFESSOR: Well, yesterday was easy. 2 00:00:27,960 --> 00:00:33,020 You learned all of the rules of programming and lived. 3 00:00:33,020 --> 00:00:34,980 Almost all of them. 4 00:00:34,980 --> 00:00:38,372 And so at this point, you're now certified programmers-- 5 00:00:38,372 --> 00:00:40,200 it says. 6 00:00:40,200 --> 00:00:48,890 However, I suppose what we did is we, aah, sort of got you a 7 00:00:48,890 --> 00:00:51,700 little bit of into an easy state. 8 00:00:51,700 --> 00:00:54,770 Here, you still believe it's possible that this might be 9 00:00:54,770 --> 00:00:59,250 programming in BASIC or Pascal with just a funny syntax. 10 00:00:59,250 --> 00:01:01,770 Today, that illusion-- 11 00:01:01,770 --> 00:01:04,919 or you can no longer support that belief. 12 00:01:04,919 --> 00:01:06,450 What we're going to do today is going to 13 00:01:06,450 --> 00:01:08,340 completely smash that. 14 00:01:08,340 --> 00:01:13,590 So let's start out by writing a few programs on the 15 00:01:13,590 --> 00:01:15,895 blackboard that have a lot in common with each other. 16 00:01:15,895 --> 00:01:19,540 What we're going to do is try to make them abstractions that 17 00:01:19,540 --> 00:01:23,880 are not ones that are easy to make in most languages. 18 00:01:23,880 --> 00:01:26,040 Let's start with some very simple ones that you can make 19 00:01:26,040 --> 00:01:28,070 in most languages. 20 00:01:28,070 --> 00:01:32,130 Supposing I want to write the mathematical expression which 21 00:01:32,130 --> 00:01:34,100 adds up a bunch of integers. 22 00:01:34,100 --> 00:01:38,850 So if I wanted to write down and say the sum from i 23 00:01:38,850 --> 00:01:41,410 equal a to b on i. 24 00:01:41,410 --> 00:01:44,190 Now, you know that that's an easy thing to compute in a 25 00:01:44,190 --> 00:01:46,180 closed form for it, and I'm not interested in that. 26 00:01:46,180 --> 00:01:47,140 But I'm going to write a program that 27 00:01:47,140 --> 00:01:49,045 adds up those integers. 28 00:01:49,045 --> 00:01:57,890 Well, that's rather easy to do to say I want to define the 29 00:01:57,890 --> 00:02:08,710 sum of the integers from a to b to be-- 30 00:02:08,710 --> 00:02:11,380 well, it's the following two possibilities. 31 00:02:11,380 --> 00:02:17,430 If a is greater than b, well, then there's nothing to be 32 00:02:17,430 --> 00:02:19,582 done and the answer is zero. 33 00:02:19,582 --> 00:02:22,530 This is how you're going to have to think recursively. 34 00:02:22,530 --> 00:02:24,880 You're going to say if I have an easy case that I know the 35 00:02:24,880 --> 00:02:26,610 answer to, just write it down. 36 00:02:26,610 --> 00:02:29,890 Otherwise, I'm going to try to reduce this problem to a 37 00:02:29,890 --> 00:02:31,060 simpler problem. 38 00:02:31,060 --> 00:02:33,000 And maybe in this case, I'm going to make a subproblem of 39 00:02:33,000 --> 00:02:35,340 the simpler problem and then do something to the result. 40 00:02:35,340 --> 00:02:41,290 So the easiest way to do this is say that I'm going to add 41 00:02:41,290 --> 00:02:46,530 the index, which in this case is a, to the result of adding 42 00:02:46,530 --> 00:02:57,960 up the integers from a plus 1 to b. 43 00:02:57,960 --> 00:03:02,343 44 00:03:02,343 --> 00:03:04,460 Now, at this point, you should have no trouble looking at 45 00:03:04,460 --> 00:03:06,190 such a definition. 46 00:03:06,190 --> 00:03:09,740 Indeed, coming up with such a thing might be a little hard 47 00:03:09,740 --> 00:03:12,230 in synthesis, but being able to read it at this point 48 00:03:12,230 --> 00:03:13,840 should be easy. 49 00:03:13,840 --> 00:03:18,220 And what it says to you is, well, here is the subproblem 50 00:03:18,220 --> 00:03:19,520 I'm going to solve. 51 00:03:19,520 --> 00:03:24,240 I'm going to try to add up the integers, one fewer integer 52 00:03:24,240 --> 00:03:26,970 than I added up for the the whole problem. 53 00:03:26,970 --> 00:03:31,270 I'm adding up the one fewer one, and that subproblem, once 54 00:03:31,270 --> 00:03:35,150 I've solved it, I'm going to add a to that, and that will 55 00:03:35,150 --> 00:03:38,550 be the answer to this problem. 56 00:03:38,550 --> 00:03:41,626 And the simplest case, I don't have to do any work. 57 00:03:41,626 --> 00:03:44,990 Now, I'm also going to write down another simple one just 58 00:03:44,990 --> 00:03:49,617 like this, which is the mathematical expression, the 59 00:03:49,617 --> 00:03:55,840 sum of the square from i equal a to b. 60 00:03:55,840 --> 00:03:58,055 And again, it's a very simple program. 61 00:03:58,055 --> 00:04:11,220 62 00:04:11,220 --> 00:04:13,510 And indeed, it starts the same way. 63 00:04:13,510 --> 00:04:16,029 64 00:04:16,029 --> 00:04:21,240 If a is greater than b, then the answer is zero. 65 00:04:21,240 --> 00:04:24,160 And, of course, we're beginning to see that there's 66 00:04:24,160 --> 00:04:27,980 something wrong with me writing this down again. 67 00:04:27,980 --> 00:04:29,820 It's the same program. 68 00:04:29,820 --> 00:04:42,180 It's the sum of the square of a and the sum of the square of 69 00:04:42,180 --> 00:04:46,134 the increment and b. 70 00:04:46,134 --> 00:04:50,880 71 00:04:50,880 --> 00:04:54,070 Now, if you look at these things, these programs are 72 00:04:54,070 --> 00:04:56,380 almost identical. 73 00:04:56,380 --> 00:04:59,860 There's not much to distinguish them. 74 00:04:59,860 --> 00:05:03,140 They have the same first clause of the conditional and 75 00:05:03,140 --> 00:05:06,250 the same predicate and the same consequence, and the 76 00:05:06,250 --> 00:05:08,910 alternatives are very similar, too. 77 00:05:08,910 --> 00:05:15,510 They only differ by the fact that where here I have a, 78 00:05:15,510 --> 00:05:17,336 here, I have the square of a. 79 00:05:17,336 --> 00:05:22,020 The only other difference, but this one's sort of unessential 80 00:05:22,020 --> 00:05:25,240 is in the name of this procedure is sum int, whereas 81 00:05:25,240 --> 00:05:27,560 the name of the procedure is sum square. 82 00:05:27,560 --> 00:05:29,820 So the things that vary between these 83 00:05:29,820 --> 00:05:33,250 two are very small. 84 00:05:33,250 --> 00:05:36,080 Now, wherever you see yourself writing the same thing down 85 00:05:36,080 --> 00:05:38,340 more than once, there's something wrong, and you 86 00:05:38,340 --> 00:05:40,280 shouldn't be doing it. 87 00:05:40,280 --> 00:05:43,420 And the reason is not because it's a waste of time to write 88 00:05:43,420 --> 00:05:45,540 something down more than once. 89 00:05:45,540 --> 00:05:50,720 It's because there's some idea here, a very simple idea, 90 00:05:50,720 --> 00:05:54,620 which has to do with the sigma notation-- 91 00:05:54,620 --> 00:05:57,330 this much-- 92 00:05:57,330 --> 00:06:01,255 not depending upon what it is I'm adding up. 93 00:06:01,255 --> 00:06:03,070 And I would like to be able to-- 94 00:06:03,070 --> 00:06:05,610 always, whenever trying to make complicated systems and 95 00:06:05,610 --> 00:06:08,575 understand them, it's crucial to divide the things up into 96 00:06:08,575 --> 00:06:11,030 as many pieces as I can, each of which I understand 97 00:06:11,030 --> 00:06:13,050 separately. 98 00:06:13,050 --> 00:06:15,030 I would like to understand the way of adding things up 99 00:06:15,030 --> 00:06:19,540 independently of what it is I'm adding up so I can do that 100 00:06:19,540 --> 00:06:24,260 having debugged it once and understood it once and having 101 00:06:24,260 --> 00:06:29,400 been able to share that among many different uses of it. 102 00:06:29,400 --> 00:06:32,360 Here, we have another example. 103 00:06:32,360 --> 00:06:40,400 This is Leibnitz's formula for finding pi over 8. 104 00:06:40,400 --> 00:06:43,460 It's a funny, ugly mess. 105 00:06:43,460 --> 00:06:43,930 What is it? 106 00:06:43,930 --> 00:06:50,670 It's something like 1 over 1 times 3 plus 1 over 5 times 7 107 00:06:50,670 --> 00:06:54,340 plus 1 over 9 times 11 plus-- 108 00:06:54,340 --> 00:06:59,750 and for some reason, things like this tend to have 109 00:06:59,750 --> 00:07:02,160 interesting values like pi over 8. 110 00:07:02,160 --> 00:07:04,460 But what do we see here? 111 00:07:04,460 --> 00:07:07,850 It's the same program or almost the same program. 112 00:07:07,850 --> 00:07:09,290 It's a sum. 113 00:07:09,290 --> 00:07:12,660 So we're seeing the figure notation, although over here, 114 00:07:12,660 --> 00:07:17,320 we're dealing with incrementing by 4, so it's a 115 00:07:17,320 --> 00:07:20,550 slightly different problem, which means that over here, I 116 00:07:20,550 --> 00:07:25,560 have to change a by 4, as you see right over here. 117 00:07:25,560 --> 00:07:28,390 It's not by 1. 118 00:07:28,390 --> 00:07:31,150 The other thing, of course, is that the thing that's 119 00:07:31,150 --> 00:07:34,805 represented by square in the previous sum of squares, or a 120 00:07:34,805 --> 00:07:36,400 when adding up the integers. 121 00:07:36,400 --> 00:07:38,060 Well, here, I have a different thing I'm adding up, a 122 00:07:38,060 --> 00:07:44,290 different term, which is 1 over a times a plus 2. 123 00:07:44,290 --> 00:07:45,875 But the rest of this program is identical. 124 00:07:45,875 --> 00:07:48,530 125 00:07:48,530 --> 00:07:50,640 Well, any time we have a bunch of things like this that are 126 00:07:50,640 --> 00:07:53,200 identical, we're going to have to come up with some sort of 127 00:07:53,200 --> 00:07:55,582 abstraction to cover them. 128 00:07:55,582 --> 00:07:59,920 If you think about this, what you've learned so far is the 129 00:07:59,920 --> 00:08:03,370 rules of some language, some primitive, some means of 130 00:08:03,370 --> 00:08:06,310 combination, almost all of them, the means of 131 00:08:06,310 --> 00:08:09,730 abstraction, almost all of them. 132 00:08:09,730 --> 00:08:13,290 But what you haven't learned is common patterns of usage. 133 00:08:13,290 --> 00:08:15,150 Now, most of the time, you learn idioms when learning a 134 00:08:15,150 --> 00:08:18,380 language, which is a common pattern that mean things that 135 00:08:18,380 --> 00:08:20,760 are useful to know in a flash. 136 00:08:20,760 --> 00:08:22,760 And if you build a great number of them, if you're a 137 00:08:22,760 --> 00:08:26,180 FORTRAN programmer, of course, everybody knows how to-- 138 00:08:26,180 --> 00:08:29,640 what do you do, for example, to get an integer which is the 139 00:08:29,640 --> 00:08:31,250 biggest integer in something. 140 00:08:31,250 --> 00:08:32,600 It's a classic thing. 141 00:08:32,600 --> 00:08:34,350 Every FORTRAN programmer knows how to do that. 142 00:08:34,350 --> 00:08:36,059 And if you don't know that, you're in real hot water 143 00:08:36,059 --> 00:08:38,150 because it takes a long time to think it out. 144 00:08:38,150 --> 00:08:41,620 However, one of the things you can do in this language that 145 00:08:41,620 --> 00:08:43,900 we're showing you is not only do you know something like 146 00:08:43,900 --> 00:08:48,380 that, but you give the knowledge of that a name. 147 00:08:48,380 --> 00:08:50,500 And so that's what we're going to be going after right now. 148 00:08:50,500 --> 00:08:53,530 149 00:08:53,530 --> 00:08:55,860 OK, well, let's see what these things have in common. 150 00:08:55,860 --> 00:08:58,680 151 00:08:58,680 --> 00:09:02,560 Right over here we have what appears to be a general 152 00:09:02,560 --> 00:09:06,470 pattern, a general pattern which covers all of the cases 153 00:09:06,470 --> 00:09:09,700 we've seen so far. 154 00:09:09,700 --> 00:09:15,200 There is a sum procedure, which is being defined. 155 00:09:15,200 --> 00:09:17,680 It has two arguments, which are a lower bound 156 00:09:17,680 --> 00:09:19,630 and an upper bound. 157 00:09:19,630 --> 00:09:23,150 The lower bound is tested to be greater than the upper 158 00:09:23,150 --> 00:09:27,590 bound, and if it is greater, then the result is zero. 159 00:09:27,590 --> 00:09:31,640 Otherwise, we're going to do something to the lower bound, 160 00:09:31,640 --> 00:09:35,540 which is the index of the conversation, and add that 161 00:09:35,540 --> 00:09:40,150 result to the result of following the procedure 162 00:09:40,150 --> 00:09:45,050 recursively on our lower bound incremented by some next 163 00:09:45,050 --> 00:09:49,605 operation with the same upper bound as I had before. 164 00:09:49,605 --> 00:09:53,710 165 00:09:53,710 --> 00:09:59,230 So this is a general pattern, and what I'd like to do is be 166 00:09:59,230 --> 00:10:03,610 able to name this general pattern a bit. 167 00:10:03,610 --> 00:10:06,550 Well, that's sort of easy, because one of the things I'm 168 00:10:06,550 --> 00:10:09,610 going to do right now is-- there's nothing very special 169 00:10:09,610 --> 00:10:11,790 about numbers. 170 00:10:11,790 --> 00:10:14,790 Numbers are just one kind of data. 171 00:10:14,790 --> 00:10:17,570 It seems to me perfectly reasonable to give all sorts 172 00:10:17,570 --> 00:10:23,260 of names to all kinds of data, for example, procedures. 173 00:10:23,260 --> 00:10:26,370 And now many languages allow you have procedural arguments, 174 00:10:26,370 --> 00:10:27,830 and right now, we're going to talk 175 00:10:27,830 --> 00:10:29,120 about procedural arguments. 176 00:10:29,120 --> 00:10:31,280 They're very easy to deal with. 177 00:10:31,280 --> 00:10:33,300 And shortly, we'll do some remarkable things that are not 178 00:10:33,300 --> 00:10:35,730 like procedural arguments. 179 00:10:35,730 --> 00:10:43,190 So here, we'll define our sigma notation. 180 00:10:43,190 --> 00:10:55,450 This is called sum and it takes a term, an A, a next 181 00:10:55,450 --> 00:11:00,190 term, and B as arguments. 182 00:11:00,190 --> 00:11:03,420 So it takes four arguments, and there was nothing 183 00:11:03,420 --> 00:11:06,580 particularly special about me writing this in lowercase. 184 00:11:06,580 --> 00:11:08,700 I hope that it doesn't confuse you, so I'll write it in 185 00:11:08,700 --> 00:11:09,930 uppercase right now. 186 00:11:09,930 --> 00:11:11,180 The machine doesn't care. 187 00:11:11,180 --> 00:11:14,350 188 00:11:14,350 --> 00:11:17,180 But these two arguments are different. 189 00:11:17,180 --> 00:11:19,360 These are not numbers. 190 00:11:19,360 --> 00:11:21,600 These are going to be procedures for computing 191 00:11:21,600 --> 00:11:23,690 something given a number. 192 00:11:23,690 --> 00:11:26,590 Term will be a procedure which, when given an index, 193 00:11:26,590 --> 00:11:29,920 will produce the value of the term for that index. 194 00:11:29,920 --> 00:11:31,660 Next will be given an index, which will 195 00:11:31,660 --> 00:11:34,050 produce the next index. 196 00:11:34,050 --> 00:11:36,000 This will be for counting. 197 00:11:36,000 --> 00:11:37,250 And it's very simple. 198 00:11:37,250 --> 00:11:40,590 199 00:11:40,590 --> 00:11:43,400 It's exactly what you see. 200 00:11:43,400 --> 00:11:52,220 If A is greater than B, then the result is 0. 201 00:11:52,220 --> 00:12:04,970 Otherwise, it's the sum of term applied to A and the sum 202 00:12:04,970 --> 00:12:10,410 of term, next index. 203 00:12:10,410 --> 00:12:14,990 204 00:12:14,990 --> 00:12:16,480 Let me write it this way. 205 00:12:16,480 --> 00:12:29,370 206 00:12:29,370 --> 00:12:32,160 Now, I'd like you to see something, first of all. 207 00:12:32,160 --> 00:12:35,210 I was writing here, and I ran out of space. 208 00:12:35,210 --> 00:12:38,110 What I did is I start indenting according to the 209 00:12:38,110 --> 00:12:41,080 Pretty-printing rule, which says that I align all of the 210 00:12:41,080 --> 00:12:44,340 arguments of the procedure so I can see 211 00:12:44,340 --> 00:12:47,060 which ones go together. 212 00:12:47,060 --> 00:12:49,840 And this is just something I do automatically, and I want 213 00:12:49,840 --> 00:12:51,530 you to learn how to do that, too, so your programs can be 214 00:12:51,530 --> 00:12:52,780 read and understood. 215 00:12:52,780 --> 00:12:54,750 216 00:12:54,750 --> 00:12:57,610 However, what do we have here? 217 00:12:57,610 --> 00:13:01,730 We have four arguments: the procedure, the lower index-- 218 00:13:01,730 --> 00:13:03,670 lower bound index-- 219 00:13:03,670 --> 00:13:09,010 the way to get the next index, and the upper bound. 220 00:13:09,010 --> 00:13:13,890 What's passed along on the recursive call is indeed the 221 00:13:13,890 --> 00:13:18,110 same procedure because I'm going to need it again, the 222 00:13:18,110 --> 00:13:21,260 next index, which is using the next procedure to compute it, 223 00:13:21,260 --> 00:13:23,332 the procedure for computing next, which I also have to 224 00:13:23,332 --> 00:13:25,250 have separately, and that's different. 225 00:13:25,250 --> 00:13:27,940 The procedure for computing next is different from the 226 00:13:27,940 --> 00:13:30,680 next index, which is the result of using next on the 227 00:13:30,680 --> 00:13:32,510 last index. 228 00:13:32,510 --> 00:13:34,210 And I also have to pass along the upper bound. 229 00:13:34,210 --> 00:13:37,090 230 00:13:37,090 --> 00:13:44,850 So this captures both of these and the other nice program 231 00:13:44,850 --> 00:13:47,810 that we are playing with. 232 00:13:47,810 --> 00:13:52,740 So using this, we can write down the original program as 233 00:13:52,740 --> 00:13:56,260 instances of sum very simply. 234 00:13:56,260 --> 00:14:08,880 235 00:14:08,880 --> 00:14:17,620 A and B. Well, I'm going to need an identity procedure 236 00:14:17,620 --> 00:14:29,440 here because ,ahh, the sum of the integers requires me to in 237 00:14:29,440 --> 00:14:33,020 this case compute a term for every integer, but the term 238 00:14:33,020 --> 00:14:35,560 procedure doesn't want to do anything to that integer. 239 00:14:35,560 --> 00:14:41,460 So the identity procedure on A is A or X or whatever, and I 240 00:14:41,460 --> 00:14:52,420 want to say the sum of using identity of the term procedure 241 00:14:52,420 --> 00:14:58,400 and using A as the initial index and the incrementer 242 00:14:58,400 --> 00:15:05,552 being the way to get the next index and B being the high 243 00:15:05,552 --> 00:15:07,870 bound, the upper bound. 244 00:15:07,870 --> 00:15:12,010 This procedure does exactly the same as the sum of the 245 00:15:12,010 --> 00:15:14,140 integers over here, computes the same answer. 246 00:15:14,140 --> 00:15:17,690 247 00:15:17,690 --> 00:15:21,520 Now, one thing you should see, of course, is that there's 248 00:15:21,520 --> 00:15:25,220 nothing very special over here about what I used as the 249 00:15:25,220 --> 00:15:25,990 formal parameter. 250 00:15:25,990 --> 00:15:27,230 I could have, for example, written this 251 00:15:27,230 --> 00:15:29,690 X. It doesn't matter. 252 00:15:29,690 --> 00:15:33,760 I just wanted you to see that this name does not conflict 253 00:15:33,760 --> 00:15:35,140 with this one at all. 254 00:15:35,140 --> 00:15:37,850 It's an internal name. 255 00:15:37,850 --> 00:15:40,500 For the second procedure here, the sum of the squares, it's 256 00:15:40,500 --> 00:15:41,750 even a little bit easier. 257 00:15:41,750 --> 00:15:53,760 258 00:15:53,760 --> 00:15:54,850 And what do we have to do? 259 00:15:54,850 --> 00:16:02,560 Nothing more than add up the squares, this is the procedure 260 00:16:02,560 --> 00:16:05,620 that each index will be given, will be given each-- 261 00:16:05,620 --> 00:16:06,780 yes. 262 00:16:06,780 --> 00:16:10,410 Each index will have this done to it to get the term. 263 00:16:10,410 --> 00:16:13,570 That's the thing that maps against term over here. 264 00:16:13,570 --> 00:16:18,810 Then I have A as the lower bound, the incrementer as the 265 00:16:18,810 --> 00:16:21,520 next term method, and B as the upper bound. 266 00:16:21,520 --> 00:16:26,780 267 00:16:26,780 --> 00:16:29,030 And finally, just for the thing that we did about pi 268 00:16:29,030 --> 00:16:33,270 sums, pi sums are sort of-- 269 00:16:33,270 --> 00:16:35,840 well, it's even easier to think about them this way 270 00:16:35,840 --> 00:16:36,610 because I don't have to think. 271 00:16:36,610 --> 00:16:41,110 What I'm doing is separating the thing I'm adding up from 272 00:16:41,110 --> 00:16:43,340 the method of doing the addition. 273 00:16:43,340 --> 00:16:57,200 And so we have here, for example, pi sum A B 274 00:16:57,200 --> 00:16:59,890 of the sum of things. 275 00:16:59,890 --> 00:17:03,350 I'm going to write the terms procedure here explicitly 276 00:17:03,350 --> 00:17:05,670 without giving it a name. 277 00:17:05,670 --> 00:17:07,119 This is done anonymously. 278 00:17:07,119 --> 00:17:10,960 I don't necessarily have to give a name to something if I 279 00:17:10,960 --> 00:17:12,310 just want to use it once. 280 00:17:12,310 --> 00:17:18,050 And, of course, I can write sort of a expression that 281 00:17:18,050 --> 00:17:19,579 produces a procedure. 282 00:17:19,579 --> 00:17:22,740 I'm going to write the Greek lambda letter here instead of 283 00:17:22,740 --> 00:17:26,220 L-A-M-B-D-A in general to avoid taking up a lot of space 284 00:17:26,220 --> 00:17:27,240 on blackboards. 285 00:17:27,240 --> 00:17:28,270 But unfortunately, we don't have 286 00:17:28,270 --> 00:17:29,960 lambda keys on our keyboards. 287 00:17:29,960 --> 00:17:32,170 Maybe we can convince our friends in the computer 288 00:17:32,170 --> 00:17:34,040 industry that this is an important. 289 00:17:34,040 --> 00:17:43,480 Lambda of i is the quotient of 1 and the product of i and the 290 00:17:43,480 --> 00:17:58,020 sum of i 2, starting at a with the way of incrementing being 291 00:17:58,020 --> 00:18:08,666 that procedure of an index i, which adds i to 4, and b being 292 00:18:08,666 --> 00:18:09,916 the upper bound. 293 00:18:09,916 --> 00:18:12,270 294 00:18:12,270 --> 00:18:17,490 So you can see that this notation, the invention of the 295 00:18:17,490 --> 00:18:21,370 procedure that takes a procedural argument, allows us 296 00:18:21,370 --> 00:18:26,066 to compress a lot of these procedures into one thing. 297 00:18:26,066 --> 00:18:32,780 This procedure, sums, covers a whole bunch of ideas. 298 00:18:32,780 --> 00:18:34,740 Now, just why is this important? 299 00:18:34,740 --> 00:18:37,370 I tried to say before that it helps us divide a problem into 300 00:18:37,370 --> 00:18:42,760 two pieces, and indeed, it does, for example, if someone 301 00:18:42,760 --> 00:18:46,570 came up with a different way of implementing this, which, 302 00:18:46,570 --> 00:18:50,010 of course, one might. 303 00:18:50,010 --> 00:18:51,230 Here, for example, an iterative 304 00:18:51,230 --> 00:18:52,480 implementation of sum. 305 00:18:52,480 --> 00:18:55,900 306 00:18:55,900 --> 00:18:59,470 Iterative implementation for some reason might be better 307 00:18:59,470 --> 00:19:00,840 than the recursive implementation. 308 00:19:00,840 --> 00:19:03,670 309 00:19:03,670 --> 00:19:06,460 But the important thing is that it's different. 310 00:19:06,460 --> 00:19:09,460 Now, supposing I had written my program this way that you 311 00:19:09,460 --> 00:19:14,310 see on the blackboard on the left. 312 00:19:14,310 --> 00:19:17,810 That's correct, the left. 313 00:19:17,810 --> 00:19:22,280 Well, then if I want to change the method of addition, then 314 00:19:22,280 --> 00:19:25,200 I'd have to change each of these. 315 00:19:25,200 --> 00:19:30,210 Whereas if I write them like this that you see here, then 316 00:19:30,210 --> 00:19:32,430 the method by which I did the addition is encapsulated in 317 00:19:32,430 --> 00:19:34,850 the procedure sum. 318 00:19:34,850 --> 00:19:37,780 That decomposition allows me to independently change one 319 00:19:37,780 --> 00:19:43,210 part of the program and prove it perhaps without changing 320 00:19:43,210 --> 00:19:45,052 the other part that was written for some 321 00:19:45,052 --> 00:19:46,630 of the other cases. 322 00:19:46,630 --> 00:19:50,366 323 00:19:50,366 --> 00:19:51,010 Thank you. 324 00:19:51,010 --> 00:19:52,420 Are there any questions? 325 00:19:52,420 --> 00:19:53,190 Yes, sir. 326 00:19:53,190 --> 00:19:55,150 AUDIENCE: Would you go over next A and next again on-- 327 00:19:55,150 --> 00:19:55,640 PROFESSOR: Yes. 328 00:19:55,640 --> 00:19:56,680 It's the same problem. 329 00:19:56,680 --> 00:19:57,900 I'm sure you're going to-- 330 00:19:57,900 --> 00:19:59,160 you're going to have to work on this. 331 00:19:59,160 --> 00:20:01,280 This is hard the first time you've ever seen 332 00:20:01,280 --> 00:20:02,460 something like this. 333 00:20:02,460 --> 00:20:06,300 What I have here is a-- procedures 334 00:20:06,300 --> 00:20:07,550 can be named by variables. 335 00:20:07,550 --> 00:20:10,020 336 00:20:10,020 --> 00:20:12,710 Procedures are not special. 337 00:20:12,710 --> 00:20:15,230 Actually, sum square is a variable, which has gotten a 338 00:20:15,230 --> 00:20:18,640 value, which is a procedure. 339 00:20:18,640 --> 00:20:20,030 This is define sum square to be 340 00:20:20,030 --> 00:20:23,310 lambda of A and B something. 341 00:20:23,310 --> 00:20:24,700 So the procedure can be named. 342 00:20:24,700 --> 00:20:27,900 Therefore, they can be passed from one to another, one 343 00:20:27,900 --> 00:20:31,430 procedure to another, as arguments. 344 00:20:31,430 --> 00:20:33,630 Well, what we're doing here is we're passing the procedure 345 00:20:33,630 --> 00:20:38,190 term as an argument to sum just when we get it around in 346 00:20:38,190 --> 00:20:41,060 the next recursive. 347 00:20:41,060 --> 00:20:45,350 Here, we're passing the procedure next 348 00:20:45,350 --> 00:20:47,630 as an argument also. 349 00:20:47,630 --> 00:20:50,120 However, here we're using the procedure next. 350 00:20:50,120 --> 00:20:51,690 That's what the parentheses mean. 351 00:20:51,690 --> 00:20:56,750 We're applying next to A to get the next value of A. If 352 00:20:56,750 --> 00:20:59,390 you look at what next is mapped against, remember that 353 00:20:59,390 --> 00:21:02,390 the way you think about this is that you substitute the 354 00:21:02,390 --> 00:21:06,800 arguments for the formal parameters in the body. 355 00:21:06,800 --> 00:21:10,590 If you're ever confused, think of the thing that way. 356 00:21:10,590 --> 00:21:14,730 Well, over here, with sum of the integers. 357 00:21:14,730 --> 00:21:21,150 I substitute identity for a term and 1 plus the 358 00:21:21,150 --> 00:21:26,070 incrementer for next in the body. 359 00:21:26,070 --> 00:21:30,600 Well, the identity procedure on A is what I get here. 360 00:21:30,600 --> 00:21:35,170 Identity is being passed along, and here, I have 361 00:21:35,170 --> 00:21:41,040 increment 1 plus being applied to A and 1 plus is being 362 00:21:41,040 --> 00:21:42,980 passed along. 363 00:21:42,980 --> 00:21:46,340 Does that clarify the situation? 364 00:21:46,340 --> 00:21:49,355 AUDIENCE: We could also define explicitly those two 365 00:21:49,355 --> 00:21:51,300 functions, then pass them. 366 00:21:51,300 --> 00:21:52,360 PROFESSOR: Sure. 367 00:21:52,360 --> 00:21:54,950 What we can do is we could have given names to them, just 368 00:21:54,950 --> 00:21:55,770 like I did here. 369 00:21:55,770 --> 00:21:57,530 In fact, I gave you various ways so you 370 00:21:57,530 --> 00:21:59,390 could see it, a variety. 371 00:21:59,390 --> 00:22:05,130 Here, I define the thing which I passed the name of. 372 00:22:05,130 --> 00:22:07,850 I referenced it by its name. 373 00:22:07,850 --> 00:22:10,400 But the thing is, in fact, that procedure, one argument 374 00:22:10,400 --> 00:22:14,300 X, which is X. And the identity procedure is just 375 00:22:14,300 --> 00:22:20,870 lambda of X X. And that's what you're seeing here. 376 00:22:20,870 --> 00:22:26,190 Here, I happened to just write its canonical name there for 377 00:22:26,190 --> 00:22:27,440 you to see. 378 00:22:27,440 --> 00:22:31,730 379 00:22:31,730 --> 00:22:33,020 Is it OK if we take our five-minute break? 380 00:22:33,020 --> 00:23:15,850 381 00:23:15,850 --> 00:23:19,780 As I said, computers to make people happy, not people to 382 00:23:19,780 --> 00:23:21,070 make computers happy. 383 00:23:21,070 --> 00:23:23,080 And for the most part, the reason why we introduce all 384 00:23:23,080 --> 00:23:26,440 this abstraction stuff is to make it so that programs can 385 00:23:26,440 --> 00:23:29,940 be more easily written and more easily read. 386 00:23:29,940 --> 00:23:32,930 Let's try to understand what's the most complicated program 387 00:23:32,930 --> 00:23:36,280 we've seen so far using a little bit of 388 00:23:36,280 --> 00:23:38,120 this abstraction stuff. 389 00:23:38,120 --> 00:23:44,560 If you look at the slide, this is the Heron of Alexandria's 390 00:23:44,560 --> 00:23:51,590 method of computing square roots that we saw yesterday. 391 00:23:51,590 --> 00:23:56,460 And let's see. 392 00:23:56,460 --> 00:24:00,780 Well, in any case, this program is a little 393 00:24:00,780 --> 00:24:01,805 complicated. 394 00:24:01,805 --> 00:24:04,800 And at the current state of your thinking, you just can't 395 00:24:04,800 --> 00:24:07,320 look at that and say, oh, this obviously means 396 00:24:07,320 --> 00:24:10,380 something very clear. 397 00:24:10,380 --> 00:24:12,930 It's not obvious from looking at the 398 00:24:12,930 --> 00:24:17,060 program what it's computing. 399 00:24:17,060 --> 00:24:21,890 There's some loop here inside try, and a loop does something 400 00:24:21,890 --> 00:24:26,030 about trying the improvement of y. 401 00:24:26,030 --> 00:24:30,170 There's something called improve, which does some 402 00:24:30,170 --> 00:24:33,270 averaging and quotienting and things like that. 403 00:24:33,270 --> 00:24:34,840 But what's the real idea? 404 00:24:34,840 --> 00:24:38,930 Can we make it clear what the idea is? 405 00:24:38,930 --> 00:24:41,610 Well, I think we can. 406 00:24:41,610 --> 00:24:45,070 I think we can use abstraction that we have learned about so 407 00:24:45,070 --> 00:24:48,990 far to clarify what's going on. 408 00:24:48,990 --> 00:24:54,720 Now, what we have mathematically is a procedure 409 00:24:54,720 --> 00:24:58,411 for improving a guess for square roots. 410 00:24:58,411 --> 00:25:02,610 And if y is a guess for a square root, then what we want 411 00:25:02,610 --> 00:25:04,570 to get we'll call a function f. 412 00:25:04,570 --> 00:25:07,660 This is the means of improvement. 413 00:25:07,660 --> 00:25:17,510 I want to get y plus x/y over 2, so the average of y and x 414 00:25:17,510 --> 00:25:24,080 divided by y as the improved value for the square root of x 415 00:25:24,080 --> 00:25:27,920 such that-- one thing you can notice about this function f 416 00:25:27,920 --> 00:25:36,310 is that f of the square root of f is in fact the 417 00:25:36,310 --> 00:25:38,460 square root of x. 418 00:25:38,460 --> 00:25:41,670 In other words, if I take the square root of x and 419 00:25:41,670 --> 00:25:44,930 substitute it for y here, I see the square root of x plus 420 00:25:44,930 --> 00:25:47,560 x divided by the square of x, which is the square root of x. 421 00:25:47,560 --> 00:25:49,890 That's 2 times the square root of x divided by 2, is the 422 00:25:49,890 --> 00:25:51,640 square root of x. 423 00:25:51,640 --> 00:25:55,630 So, in fact, what we're really looking for is we're looking 424 00:25:55,630 --> 00:26:12,850 for a fixed point, a fixed point of the function f. 425 00:26:12,850 --> 00:26:17,570 426 00:26:17,570 --> 00:26:22,650 A fixed point is a place which has the property that if you 427 00:26:22,650 --> 00:26:24,850 put it into the function, you get the same value out. 428 00:26:24,850 --> 00:26:27,620 429 00:26:27,620 --> 00:26:29,700 Now, I suppose if I were giving some nice, boring 430 00:26:29,700 --> 00:26:34,480 lecture, and you happened to have in front of you an HP-35 431 00:26:34,480 --> 00:26:36,380 desk calculator like I used to have when I 432 00:26:36,380 --> 00:26:38,170 went to boring lectures. 433 00:26:38,170 --> 00:26:41,120 And if you think it was really boring, you put it into 434 00:26:41,120 --> 00:26:44,720 radians mode, and you hit cosine, and you hit cosine, 435 00:26:44,720 --> 00:26:45,780 and you hit cosine. 436 00:26:45,780 --> 00:26:48,770 And eventually, you end up with 0.734 or 437 00:26:48,770 --> 00:26:50,090 something like that. 438 00:26:50,090 --> 00:26:53,250 0.743, I don't remember what exactly, and it gets closer 439 00:26:53,250 --> 00:26:54,810 and closer to that. 440 00:26:54,810 --> 00:26:57,980 Some functions have the property that you can find 441 00:26:57,980 --> 00:27:03,420 their fixed point by iterating the function, and that's 442 00:27:03,420 --> 00:27:07,170 essentially what's happening in the square root program by 443 00:27:07,170 --> 00:27:08,420 Heron's method. 444 00:27:08,420 --> 00:27:11,550 445 00:27:11,550 --> 00:27:14,732 So let's see if we can write that down, that idea. 446 00:27:14,732 --> 00:27:17,670 Now, I'm not going to say how I compute fixed points yet. 447 00:27:17,670 --> 00:27:19,240 There might be more than one way. 448 00:27:19,240 --> 00:27:22,750 But the first thing to do is I'm going to 449 00:27:22,750 --> 00:27:24,310 say what I just said. 450 00:27:24,310 --> 00:27:27,460 I'm going to say it specifically, the square root. 451 00:27:27,460 --> 00:27:32,440 452 00:27:32,440 --> 00:27:48,210 The square root of x is the fixed point of that procedure 453 00:27:48,210 --> 00:27:59,180 which takes an argument y and averages of x 454 00:27:59,180 --> 00:28:02,330 divided by y with y. 455 00:28:02,330 --> 00:28:05,620 456 00:28:05,620 --> 00:28:08,120 And we're going to start up with the initial guess for the 457 00:28:08,120 --> 00:28:09,630 fixed point of 1. 458 00:28:09,630 --> 00:28:11,860 It doesn't matter where it starts. 459 00:28:11,860 --> 00:28:13,940 A theorem having to do with square roots. 460 00:28:13,940 --> 00:28:18,610 461 00:28:18,610 --> 00:28:21,410 So what you're seeing here is I'm just trying to write out 462 00:28:21,410 --> 00:28:22,560 by wishful thinking. 463 00:28:22,560 --> 00:28:24,380 I don't know how I'm going to make fixed point happen. 464 00:28:24,380 --> 00:28:26,290 We'll worry about that later. 465 00:28:26,290 --> 00:28:29,570 But if somehow I had a way of finding the fixed point of the 466 00:28:29,570 --> 00:28:33,590 function computed by this procedure, then I would have-- 467 00:28:33,590 --> 00:28:36,120 that would be the square root that I'm looking for. 468 00:28:36,120 --> 00:28:39,770 469 00:28:39,770 --> 00:28:41,500 OK, well, now let's see how we're going to write-- 470 00:28:41,500 --> 00:28:43,470 how we're going to come up with fixed points. 471 00:28:43,470 --> 00:28:44,890 Well, it's very simple, actually. 472 00:28:44,890 --> 00:28:47,180 I'm going to write an abbreviated version here just 473 00:28:47,180 --> 00:28:48,430 so we understand it. 474 00:28:48,430 --> 00:29:00,450 475 00:29:00,450 --> 00:29:03,310 I'm going to find the fixed point of a function f-- 476 00:29:03,310 --> 00:29:06,140 actually, the fixed point of the function computed by the 477 00:29:06,140 --> 00:29:09,990 procedure whose name will be f in this procedure. 478 00:29:09,990 --> 00:29:11,025 How's that? 479 00:29:11,025 --> 00:29:13,230 A long sentence-- 480 00:29:13,230 --> 00:29:14,820 starting with a particular starting value. 481 00:29:14,820 --> 00:29:19,920 482 00:29:19,920 --> 00:29:22,660 Well, I'm going to have a little loop inside here, which 483 00:29:22,660 --> 00:29:25,800 is going to push the button on the calculator repeatedly, 484 00:29:25,800 --> 00:29:28,940 hoping that it will eventually converge. 485 00:29:28,940 --> 00:29:35,290 And we will say here internal loops are written by defining 486 00:29:35,290 --> 00:29:36,540 internal procedures. 487 00:29:36,540 --> 00:29:39,340 488 00:29:39,340 --> 00:29:41,860 Well, one thing I'm going to have to do is I'm going to 489 00:29:41,860 --> 00:29:43,690 have to say whether I'm done. 490 00:29:43,690 --> 00:29:45,410 And the way I'm going to decide when I'm done is when 491 00:29:45,410 --> 00:29:47,760 the old value and the new value are close enough so I 492 00:29:47,760 --> 00:29:50,820 can't distinguish them anymore. 493 00:29:50,820 --> 00:29:53,510 That's the standard thing you do on the calculator unless 494 00:29:53,510 --> 00:29:54,970 you look at more precision, and eventually, 495 00:29:54,970 --> 00:29:57,820 you run out of precision. 496 00:29:57,820 --> 00:30:06,530 So the old value and new value, and I'm going to stay 497 00:30:06,530 --> 00:30:14,758 here if I can't distinguish them if they're close enough, 498 00:30:14,758 --> 00:30:16,830 and we'll have to worry about what that is soon. 499 00:30:16,830 --> 00:30:20,780 500 00:30:20,780 --> 00:30:22,580 The old value and the new value are close enough to each 501 00:30:22,580 --> 00:30:25,880 other and let's pick the new value as the answer. 502 00:30:25,880 --> 00:30:33,520 Otherwise, I'm going to iterate around again with the 503 00:30:33,520 --> 00:30:39,020 next value of old being the current value of new and the 504 00:30:39,020 --> 00:30:43,160 next value of new being the result of calling f on new. 505 00:30:43,160 --> 00:30:54,810 506 00:30:54,810 --> 00:30:57,680 And so this is my iteration loop that pushes the button on 507 00:30:57,680 --> 00:30:58,600 the calculator. 508 00:30:58,600 --> 00:31:00,760 I basically think of it as having two registers on the 509 00:31:00,760 --> 00:31:02,495 calculator: old and new. 510 00:31:02,495 --> 00:31:09,070 And in each step, new becomes old, and new gets F of new. 511 00:31:09,070 --> 00:31:13,080 So this is the thing where I'm getting the next value. 512 00:31:13,080 --> 00:31:20,970 And now, I'm going to start this thing up 513 00:31:20,970 --> 00:31:22,220 by giving two values. 514 00:31:22,220 --> 00:31:28,470 515 00:31:28,470 --> 00:31:30,570 I wrote down on the blackboard to be slow 516 00:31:30,570 --> 00:31:31,640 so you can see this. 517 00:31:31,640 --> 00:31:34,650 This is the first time you've seen something quite this 518 00:31:34,650 --> 00:31:37,700 complicated, I think. 519 00:31:37,700 --> 00:31:44,710 However, we might want to see the whole thing over here in 520 00:31:44,710 --> 00:31:50,720 this transparency or slide or whatever. 521 00:31:50,720 --> 00:31:57,200 What we have is all of the details that are required to 522 00:31:57,200 --> 00:31:58,500 make this thing work. 523 00:31:58,500 --> 00:32:01,660 I have a way of getting a tolerance for a close enough 524 00:32:01,660 --> 00:32:03,080 procedure, which we see here. 525 00:32:03,080 --> 00:32:06,030 The close enough procedure, it tests whether u and v are 526 00:32:06,030 --> 00:32:09,170 close enough by seeing if the absolute value of the 527 00:32:09,170 --> 00:32:12,460 difference in u and v is less than the given tolerance, OK? 528 00:32:12,460 --> 00:32:14,440 And here is the iteration loop that I just wrote on the 529 00:32:14,440 --> 00:32:17,930 blackboard and the initialization for it, which 530 00:32:17,930 --> 00:32:19,180 is right there. 531 00:32:19,180 --> 00:32:21,680 532 00:32:21,680 --> 00:32:22,930 It's very simple. 533 00:32:22,930 --> 00:32:34,210 534 00:32:34,210 --> 00:32:34,880 But let's see. 535 00:32:34,880 --> 00:32:36,630 I haven't told you enough. 536 00:32:36,630 --> 00:32:39,500 It's actually easier than this. 537 00:32:39,500 --> 00:32:42,120 There is more structure to this problem than I've 538 00:32:42,120 --> 00:32:43,310 already told you. 539 00:32:43,310 --> 00:32:45,700 Like why should this work? 540 00:32:45,700 --> 00:32:48,070 Why should it converge? 541 00:32:48,070 --> 00:32:50,930 There's a hairy theorem in mathematics tied up in what 542 00:32:50,930 --> 00:32:52,760 I've written here. 543 00:32:52,760 --> 00:32:55,890 Why is it that I should assume that by iterating averaging 544 00:32:55,890 --> 00:32:57,780 the quotient of x and y and y that I should 545 00:32:57,780 --> 00:33:00,110 get the right answer? 546 00:33:00,110 --> 00:33:01,360 It isn't so obvious. 547 00:33:01,360 --> 00:33:03,710 548 00:33:03,710 --> 00:33:07,280 Surely there are other things, other procedures, which 549 00:33:07,280 --> 00:33:09,870 compute functions whose fixed points would also be the 550 00:33:09,870 --> 00:33:12,040 square root. 551 00:33:12,040 --> 00:33:20,480 For example, the obvious one will be a new function g, 552 00:33:20,480 --> 00:33:25,330 which maps y to x/y. 553 00:33:25,330 --> 00:33:27,950 554 00:33:27,950 --> 00:33:30,870 That's even simpler. 555 00:33:30,870 --> 00:33:34,540 The fixed point of g is surely the square root also, and it's 556 00:33:34,540 --> 00:33:37,400 a simpler procedure. 557 00:33:37,400 --> 00:33:39,020 Why am I not using it? 558 00:33:39,020 --> 00:33:40,470 Well, I suppose you know. 559 00:33:40,470 --> 00:33:44,970 Supposing x is 2 and I start out with 1, and if I divide 1 560 00:33:44,970 --> 00:33:47,700 into 2, I get 2. 561 00:33:47,700 --> 00:33:49,610 And then if I divide 2 into 2, I get 1. 562 00:33:49,610 --> 00:33:52,740 If I divide 1 into 2, I get 2, and 2 into 2, I get 1, and I 563 00:33:52,740 --> 00:33:55,480 never get any closer to the square root. 564 00:33:55,480 --> 00:33:56,730 It just oscillates. 565 00:33:56,730 --> 00:33:59,080 566 00:33:59,080 --> 00:34:03,110 So what we have is a signal processing system, an 567 00:34:03,110 --> 00:34:06,230 electrical circuit which is oscillating, and I want to 568 00:34:06,230 --> 00:34:07,480 damp out these oscillations. 569 00:34:07,480 --> 00:34:10,530 570 00:34:10,530 --> 00:34:11,840 Well, I can do that. 571 00:34:11,840 --> 00:34:14,190 See, what I'm really doing here when I'm taking my 572 00:34:14,190 --> 00:34:17,290 average, the average is averaging the last two values 573 00:34:17,290 --> 00:34:21,350 of something which oscillates, getting something in between. 574 00:34:21,350 --> 00:34:24,480 The classic way is damping out oscillations in a signal 575 00:34:24,480 --> 00:34:25,730 processing system. 576 00:34:25,730 --> 00:34:28,460 577 00:34:28,460 --> 00:34:31,719 So why don't we write down the strategy that I just said in a 578 00:34:31,719 --> 00:34:33,872 more clear way? 579 00:34:33,872 --> 00:34:35,520 Well, that's easy enough. 580 00:34:35,520 --> 00:34:38,639 581 00:34:38,639 --> 00:34:53,790 I'm going to define the square root of x to be a fixed point 582 00:34:53,790 --> 00:34:58,510 of the procedure resulting from average damping. 583 00:34:58,510 --> 00:35:10,780 So I have a procedure resulting from average damp of 584 00:35:10,780 --> 00:35:24,820 the procedure, that procedure of y, which divides x by y 585 00:35:24,820 --> 00:35:26,070 starting out at 1. 586 00:35:26,070 --> 00:35:29,840 587 00:35:29,840 --> 00:35:33,520 Ah, but average damp is a special procedure that's going 588 00:35:33,520 --> 00:35:35,720 to take a procedure as its argument and return a 589 00:35:35,720 --> 00:35:38,080 procedure as its value. 590 00:35:38,080 --> 00:35:42,090 It's a generalization that says given a procedure, it's 591 00:35:42,090 --> 00:35:45,090 the thing which produces a procedure which averages the 592 00:35:45,090 --> 00:35:47,980 last value and the value before and 593 00:35:47,980 --> 00:35:51,320 after running the procedure. 594 00:35:51,320 --> 00:35:53,260 You can use it for anything if you want to damp out 595 00:35:53,260 --> 00:35:54,880 oscillations. 596 00:35:54,880 --> 00:35:56,495 So let's write that down. 597 00:35:56,495 --> 00:35:57,745 It's very easy. 598 00:35:57,745 --> 00:36:00,624 599 00:36:00,624 --> 00:36:04,590 And stylistically here, I'm going to use lambda notation 600 00:36:04,590 --> 00:36:06,950 because it's much easier to think when you're dealing with 601 00:36:06,950 --> 00:36:08,845 procedure, the mid-line procedures, to understand that 602 00:36:08,845 --> 00:36:11,552 the procedures are the objects I'm dealing with, so I'm going 603 00:36:11,552 --> 00:36:13,830 to use lambda notation here. 604 00:36:13,830 --> 00:36:14,490 Not always. 605 00:36:14,490 --> 00:36:18,110 I don't always use it, but very specifically here to 606 00:36:18,110 --> 00:36:22,040 expand on that idea, to elucidate it. 607 00:36:22,040 --> 00:36:28,590 608 00:36:28,590 --> 00:36:33,810 Well, average damp is a procedure, which takes a 609 00:36:33,810 --> 00:36:37,560 procedure as its argument, which we will call f. 610 00:36:37,560 --> 00:36:38,710 And what does it produce? 611 00:36:38,710 --> 00:36:40,340 It produces as its value-- 612 00:36:40,340 --> 00:36:43,890 the body of this procedure is a thing which produces a 613 00:36:43,890 --> 00:36:47,260 procedure, the construct of the procedures right here, of 614 00:36:47,260 --> 00:37:00,440 one argument x, which averages f of x with x. 615 00:37:00,440 --> 00:37:10,420 616 00:37:10,420 --> 00:37:14,070 This is a very special thing. 617 00:37:14,070 --> 00:37:17,730 I think for the first time you're seeing a procedure 618 00:37:17,730 --> 00:37:21,730 which produces a procedure as its value. 619 00:37:21,730 --> 00:37:25,690 This procedure takes the procedure f and does something 620 00:37:25,690 --> 00:37:29,360 to it to produce a new procedure of one argument x, 621 00:37:29,360 --> 00:37:31,050 which averages f-- 622 00:37:31,050 --> 00:37:31,950 this f-- 623 00:37:31,950 --> 00:37:36,040 applied to x and x itself. 624 00:37:36,040 --> 00:37:40,280 Using the context here, I apply average damping to the 625 00:37:40,280 --> 00:37:44,670 procedure, which just divides x by y. 626 00:37:44,670 --> 00:37:45,920 It's a division. 627 00:37:45,920 --> 00:37:48,122 628 00:37:48,122 --> 00:37:51,980 And I'm finding to fixed point of that, and that's a clearer 629 00:37:51,980 --> 00:37:54,460 way of writing down what I wrote down over 630 00:37:54,460 --> 00:37:57,796 here, wherever it was. 631 00:37:57,796 --> 00:38:01,110 Here, because it tells why I am writing this down. 632 00:38:01,110 --> 00:38:07,910 633 00:38:07,910 --> 00:38:11,110 I suppose this to some extent really clarifies what Heron of 634 00:38:11,110 --> 00:38:14,260 Alexandria was up to. 635 00:38:14,260 --> 00:38:15,130 I suppose I'll stop now. 636 00:38:15,130 --> 00:38:16,380 Are there any questions? 637 00:38:16,380 --> 00:38:18,190 638 00:38:18,190 --> 00:38:21,282 AUDIENCE: So when you define average damp, don't you need 639 00:38:21,282 --> 00:38:25,210 to have a variable on f? 640 00:38:25,210 --> 00:38:28,150 PROFESSOR: Ah, the question was, and here we're having-- 641 00:38:28,150 --> 00:38:29,900 again, you've got to learn about the syntax. 642 00:38:29,900 --> 00:38:33,840 The question was when defining average damp, don't you have 643 00:38:33,840 --> 00:38:38,070 to have a variable defined with f? 644 00:38:38,070 --> 00:38:40,310 What you are asking about is the formal parameter of f? 645 00:38:40,310 --> 00:38:41,290 AUDIENCE: Yeah. 646 00:38:41,290 --> 00:38:42,810 PROFESSOR: OK. 647 00:38:42,810 --> 00:38:45,580 The formal parameter of f is here. 648 00:38:45,580 --> 00:38:47,318 The formal parameter of f-- 649 00:38:47,318 --> 00:38:50,190 AUDIENCE: The formal parameter of average damp. 650 00:38:50,190 --> 00:38:51,890 PROFESSOR: F is being used to apply it to 651 00:38:51,890 --> 00:38:54,400 an argument, right? 652 00:38:54,400 --> 00:38:57,780 It's indeed true that f must have a formal parameter. 653 00:38:57,780 --> 00:39:00,380 Let's find out what f's formal parameter is. 654 00:39:00,380 --> 00:39:02,440 AUDIENCE: The formal parameter of average damp. 655 00:39:02,440 --> 00:39:04,700 PROFESSOR: Oh, f is the formal parameter of average damp. 656 00:39:04,700 --> 00:39:05,500 I'm sorry. 657 00:39:05,500 --> 00:39:07,910 You're just confusing a syntactic thing. 658 00:39:07,910 --> 00:39:10,470 I could have written this the other way. 659 00:39:10,470 --> 00:39:12,520 Actually, I didn't understand your question. 660 00:39:12,520 --> 00:39:13,910 Of course, I could have written it this other way. 661 00:39:13,910 --> 00:39:19,340 662 00:39:19,340 --> 00:39:21,540 Those are identical notations. 663 00:39:21,540 --> 00:39:25,607 This is a different way of writing this. 664 00:39:25,607 --> 00:39:31,710 665 00:39:31,710 --> 00:39:33,280 You're going to have to get used to lambda notation 666 00:39:33,280 --> 00:39:35,520 because I'm going to use it. 667 00:39:35,520 --> 00:39:40,460 What it says here, I'm defining the name average damp 668 00:39:40,460 --> 00:39:44,600 to name the procedure whose of one argument f. 669 00:39:44,600 --> 00:39:49,250 That's the formal parameter of the procedure average damp. 670 00:39:49,250 --> 00:39:56,550 What define does is it says give this name a value. 671 00:39:56,550 --> 00:39:57,860 Here is the value of for it. 672 00:39:57,860 --> 00:40:01,310 673 00:40:01,310 --> 00:40:05,100 That there happens to be a funny syntax to make that 674 00:40:05,100 --> 00:40:08,085 easier in some cases is purely convenience. 675 00:40:08,085 --> 00:40:10,900 676 00:40:10,900 --> 00:40:14,540 But the reason why I wrote it this way here is to emphasize 677 00:40:14,540 --> 00:40:16,530 that I'm dealing with a procedure that takes a 678 00:40:16,530 --> 00:40:18,100 procedure as its argument and produces a 679 00:40:18,100 --> 00:40:19,350 procedure as its value. 680 00:40:19,350 --> 00:40:23,640 681 00:40:23,640 --> 00:40:25,800 AUDIENCE: I don't understand why you use lambda twice. 682 00:40:25,800 --> 00:40:27,760 Can you just use one lambda and take two 683 00:40:27,760 --> 00:40:29,230 arguments f and x? 684 00:40:29,230 --> 00:40:29,520 PROFESSOR: No. 685 00:40:29,520 --> 00:40:30,330 AUDIENCE: You can't? 686 00:40:30,330 --> 00:40:32,500 PROFESSOR: No, that would be a different thing. 687 00:40:32,500 --> 00:40:36,190 If I were to write the procedure lambda of f and x, 688 00:40:36,190 --> 00:40:40,090 the average of f of x and x, that would not be something 689 00:40:40,090 --> 00:40:42,810 which would be allowed to take a procedure as an argument and 690 00:40:42,810 --> 00:40:44,580 produce a procedure as its value. 691 00:40:44,580 --> 00:40:46,330 That would be a thing that takes a procedure as its 692 00:40:46,330 --> 00:40:48,700 argument and numbers its argument and 693 00:40:48,700 --> 00:40:50,620 produces a new number. 694 00:40:50,620 --> 00:40:53,650 But what I'm producing here is a procedure to fit in the 695 00:40:53,650 --> 00:40:56,090 procedure slot over here, which is going to 696 00:40:56,090 --> 00:40:58,860 be used over here. 697 00:40:58,860 --> 00:41:01,450 So the number has to come from here. 698 00:41:01,450 --> 00:41:04,440 This is the thing that's going to eventually end up in the x. 699 00:41:04,440 --> 00:41:07,810 And if you're confused, you should do some substitution 700 00:41:07,810 --> 00:41:09,060 and see for yourself. 701 00:41:09,060 --> 00:41:12,010 702 00:41:12,010 --> 00:41:12,746 Yes? 703 00:41:12,746 --> 00:41:15,870 AUDIENCE: Will you please show the definition for average 704 00:41:15,870 --> 00:41:19,320 damp without using lambda notation in both cases. 705 00:41:19,320 --> 00:41:21,490 PROFESSOR: I can't make a very simple one like that. 706 00:41:21,490 --> 00:41:22,990 Let me do it for you, though. 707 00:41:22,990 --> 00:41:26,530 I can get rid of this lambda easily. 708 00:41:26,530 --> 00:41:27,780 I don't want to be-- 709 00:41:27,780 --> 00:41:32,760 710 00:41:32,760 --> 00:41:33,810 actually, I'm lying to you. 711 00:41:33,810 --> 00:41:37,170 I don't want to do what you want because I think it's more 712 00:41:37,170 --> 00:41:39,310 confusing than you think. 713 00:41:39,310 --> 00:41:40,560 I'm not going to write what you want. 714 00:41:40,560 --> 00:41:55,450 715 00:41:55,450 --> 00:41:56,500 So we'll have to get a name. 716 00:41:56,500 --> 00:42:13,370 FOO of x to be of F of x and x and return as a value FOO. 717 00:42:13,370 --> 00:42:17,140 718 00:42:17,140 --> 00:42:20,406 This is equivalent, but I've had to make an 719 00:42:20,406 --> 00:42:21,700 arbitrary name up. 720 00:42:21,700 --> 00:42:26,290 This is equivalent to this without any lambdas. 721 00:42:26,290 --> 00:42:31,240 Lambda is very convenient for naming anonymous procedures. 722 00:42:31,240 --> 00:42:34,080 It's the anonymous name of something. 723 00:42:34,080 --> 00:42:39,780 Now, if you really want to know a cute way of doing this, 724 00:42:39,780 --> 00:42:41,820 we'll talk about it later. 725 00:42:41,820 --> 00:42:44,680 We're going to have to define the anonymous procedure. 726 00:42:44,680 --> 00:42:45,930 Any other questions? 727 00:42:45,930 --> 00:42:49,116 728 00:42:49,116 --> 00:42:50,880 And so we go for our break again. 729 00:42:50,880 --> 00:43:31,740 730 00:43:31,740 --> 00:43:35,380 So now we've seen how to use high-order 731 00:43:35,380 --> 00:43:36,490 procedures, they're called. 732 00:43:36,490 --> 00:43:38,570 That's procedures that take procedural arguments and 733 00:43:38,570 --> 00:43:43,310 produce procedural values to help us clarify and abstract 734 00:43:43,310 --> 00:43:46,470 some otherwise complicated processes. 735 00:43:46,470 --> 00:43:48,500 I suppose what I'd like to do now is have a bit of fun with 736 00:43:48,500 --> 00:43:54,080 that and sort of a little practice as well. 737 00:43:54,080 --> 00:43:56,290 So let's play with this square root thing even more. 738 00:43:56,290 --> 00:43:59,800 Let's elaborate it and understand what's going on and 739 00:43:59,800 --> 00:44:04,270 make use of this kind of programming style. 740 00:44:04,270 --> 00:44:08,680 One thing that you might know is that there is a general 741 00:44:08,680 --> 00:44:12,990 method called Newton's method the purpose of which is to 742 00:44:12,990 --> 00:44:15,180 find the roots-- 743 00:44:15,180 --> 00:44:17,280 that's the zeroes-- 744 00:44:17,280 --> 00:44:19,130 of functions. 745 00:44:19,130 --> 00:44:38,420 So, for example, to find a y such that f of y equals 0, we 746 00:44:38,420 --> 00:44:40,280 start with some guess. 747 00:44:40,280 --> 00:44:41,530 This is Newton's method. 748 00:44:41,530 --> 00:44:51,260 749 00:44:51,260 --> 00:44:55,860 And the guess we start with we'll call y0, and then we 750 00:44:55,860 --> 00:45:01,100 will iterate the following expression. 751 00:45:01,100 --> 00:45:04,880 y n plus 1-- this is a difference equation-- 752 00:45:04,880 --> 00:45:17,366 is yn minus f of yn over the derivative with respect to y 753 00:45:17,366 --> 00:45:23,270 of f evaluated at y equal yn. 754 00:45:23,270 --> 00:45:26,430 Very strange notation. 755 00:45:26,430 --> 00:45:31,700 I must say ugh. 756 00:45:31,700 --> 00:45:35,990 The derivative of f with respect to y is a function. 757 00:45:35,990 --> 00:45:38,420 I'm having a little bit of unhappiness with that, but 758 00:45:38,420 --> 00:45:39,120 that's all right. 759 00:45:39,120 --> 00:45:41,050 It turns out in the programming language world, 760 00:45:41,050 --> 00:45:43,930 the notation is much clearer. 761 00:45:43,930 --> 00:45:45,950 Now, what is this? 762 00:45:45,950 --> 00:45:47,330 People call it Newton's method. 763 00:45:47,330 --> 00:45:54,250 It's a method for finding the roots of the function f. 764 00:45:54,250 --> 00:45:56,410 And it, of course, sometimes converges, and when it does, 765 00:45:56,410 --> 00:45:59,310 it does so very fast. And sometimes, it doesn't 766 00:45:59,310 --> 00:46:03,230 converge, and, oh well, we have to do something else. 767 00:46:03,230 --> 00:46:07,190 But let's talk about square root by Newton's method. 768 00:46:07,190 --> 00:46:08,680 Well, that's rather interesting. 769 00:46:08,680 --> 00:46:11,340 Let's do exactly the same thing we did last time: a bit 770 00:46:11,340 --> 00:46:13,490 of wishful thinking. 771 00:46:13,490 --> 00:46:18,210 We will apply Newton's method, assuming we knew how to do it. 772 00:46:18,210 --> 00:46:20,620 You don't know how to do it yet. 773 00:46:20,620 --> 00:46:21,870 Well, let's go. 774 00:46:21,870 --> 00:46:25,090 775 00:46:25,090 --> 00:46:26,070 What do I have here? 776 00:46:26,070 --> 00:46:27,320 The square root of x. 777 00:46:27,320 --> 00:46:31,410 778 00:46:31,410 --> 00:46:37,480 It's Newton's method applied to a procedure which will 779 00:46:37,480 --> 00:46:39,990 represent that function of y, which computes 780 00:46:39,990 --> 00:46:42,480 that function of y. 781 00:46:42,480 --> 00:46:48,820 Well, that procedure is that procedure of y, which is the 782 00:46:48,820 --> 00:46:51,810 difference between x and the square of y. 783 00:46:51,810 --> 00:47:00,080 784 00:47:00,080 --> 00:47:07,570 Indeed, if I had a value of y for which this was zero, then 785 00:47:07,570 --> 00:47:10,020 y would be the square root of x. 786 00:47:10,020 --> 00:47:13,730 787 00:47:13,730 --> 00:47:15,550 See that? 788 00:47:15,550 --> 00:47:19,250 OK, I'm going to start this out searching at 1. 789 00:47:19,250 --> 00:47:23,570 Again, completely arbitrary property of square roots that 790 00:47:23,570 --> 00:47:24,820 I can do that. 791 00:47:24,820 --> 00:47:27,950 792 00:47:27,950 --> 00:47:31,480 Now, how am I going to compute Newton's method? 793 00:47:31,480 --> 00:47:32,170 Well, this is the method. 794 00:47:32,170 --> 00:47:34,310 I have it right here. 795 00:47:34,310 --> 00:47:37,740 In fact, what I'm doing is looking for a fixed point of 796 00:47:37,740 --> 00:47:41,240 some procedure. 797 00:47:41,240 --> 00:47:45,190 This procedure involves some complicated expressions in 798 00:47:45,190 --> 00:47:47,150 terms of other complicated things. 799 00:47:47,150 --> 00:47:48,800 Well, I'm trying to find the fixed point of this. 800 00:47:48,800 --> 00:47:54,620 I want to find the values of y, which if I put y in here, I 801 00:47:54,620 --> 00:48:00,130 get the same value out here up to some degree of accuracy. 802 00:48:00,130 --> 00:48:02,710 Well, I already have a fixed point process 803 00:48:02,710 --> 00:48:05,040 around to do that. 804 00:48:05,040 --> 00:48:07,350 And so, let's just define Newton's method over here. 805 00:48:07,350 --> 00:48:19,430 806 00:48:19,430 --> 00:48:21,680 A procedure which computes a function and a 807 00:48:21,680 --> 00:48:26,640 guess, initial guess. 808 00:48:26,640 --> 00:48:28,920 Now, I'm going to have to do something here. 809 00:48:28,920 --> 00:48:33,280 I'm going to need the derivative of the function. 810 00:48:33,280 --> 00:48:36,550 I'm going to need a procedure which computes the derivative 811 00:48:36,550 --> 00:48:39,490 of the function computed by the given a procedure f. 812 00:48:39,490 --> 00:48:42,140 813 00:48:42,140 --> 00:48:44,440 I'm trying to be very careful about what I'm saying. 814 00:48:44,440 --> 00:48:46,270 I don't want to mix up the word procedure and function. 815 00:48:46,270 --> 00:48:47,875 Function is a mathematical word. 816 00:48:47,875 --> 00:48:52,950 It says I'm mapping from values to other values, a set 817 00:48:52,950 --> 00:48:55,430 of ordered pairs. 818 00:48:55,430 --> 00:49:00,380 But sometimes, I'll accidentally mix those up. 819 00:49:00,380 --> 00:49:01,655 Procedures compute functions. 820 00:49:01,655 --> 00:49:07,400 821 00:49:07,400 --> 00:49:12,100 So I'm going to define the derivative of f to be by 822 00:49:12,100 --> 00:49:12,930 wishful thinking again. 823 00:49:12,930 --> 00:49:14,720 I don't know how I'm going to do it. 824 00:49:14,720 --> 00:49:15,970 Let's worry about that later-- 825 00:49:15,970 --> 00:49:18,612 826 00:49:18,612 --> 00:49:25,340 of F. So if F is a procedure, which happens to be this one 827 00:49:25,340 --> 00:49:31,800 over here for a square root, then DF will be the derivative 828 00:49:31,800 --> 00:49:34,890 of it, which is also the derivative of the function 829 00:49:34,890 --> 00:49:36,080 computed by that procedure. 830 00:49:36,080 --> 00:49:38,760 DF will be a procedure that computes the derivative of the 831 00:49:38,760 --> 00:49:42,920 function computed by the procedure F. And then given 832 00:49:42,920 --> 00:49:44,850 that, I will just go looking for a fixed point. 833 00:49:44,850 --> 00:49:51,910 834 00:49:51,910 --> 00:49:53,710 What is the fixed point I'm looking for? 835 00:49:53,710 --> 00:49:57,580 It's the one for that procedure of one argument x, 836 00:49:57,580 --> 00:50:00,500 which I compute by subtracting x. 837 00:50:00,500 --> 00:50:04,870 That's the old-- that's the yn here. 838 00:50:04,870 --> 00:50:21,110 The quotient of f of x and df of x, starting out with the 839 00:50:21,110 --> 00:50:22,360 original guess. 840 00:50:22,360 --> 00:50:29,450 841 00:50:29,450 --> 00:50:32,640 That's all very simple. 842 00:50:32,640 --> 00:50:35,130 Now, I have one part left that I haven't written, and I want 843 00:50:35,130 --> 00:50:37,720 you to see the process by which I write these things, 844 00:50:37,720 --> 00:50:40,150 because this is really true. 845 00:50:40,150 --> 00:50:43,810 I start out with some mathematical idea, perhaps. 846 00:50:43,810 --> 00:50:48,440 By wishful thinking, I assume that by some magic I can do 847 00:50:48,440 --> 00:50:50,980 something that I have a name for. 848 00:50:50,980 --> 00:50:54,850 I'm not going to worry about how I do it yet. 849 00:50:54,850 --> 00:50:57,970 Then I go walking down here and say, well, by some magic, 850 00:50:57,970 --> 00:51:01,142 I'm somehow going to figure how to do that, but I'm going 851 00:51:01,142 --> 00:51:04,330 to write my program anyway. 852 00:51:04,330 --> 00:51:07,990 Wishful thinking, essential to good engineering, and 853 00:51:07,990 --> 00:51:10,060 certainly essential to a good computer science. 854 00:51:10,060 --> 00:51:12,770 855 00:51:12,770 --> 00:51:15,900 So anyway, how many of you wished that your 856 00:51:15,900 --> 00:51:17,150 computer ran faster? 857 00:51:17,150 --> 00:51:21,120 858 00:51:21,120 --> 00:51:23,390 Well, the derivative isn't so bad either. 859 00:51:23,390 --> 00:51:24,640 Sort of like average damping. 860 00:51:24,640 --> 00:51:28,922 861 00:51:28,922 --> 00:51:34,010 The derivative is a procedure that takes a procedure that 862 00:51:34,010 --> 00:51:38,560 computes a function as its argument, and it produces a 863 00:51:38,560 --> 00:51:42,230 procedure that computes a function, which needs one 864 00:51:42,230 --> 00:51:43,930 argument x. 865 00:51:43,930 --> 00:51:46,270 Well, you all know this definition. 866 00:51:46,270 --> 00:51:49,040 It's f of x plus delta x minus f of x over delta x, right? 867 00:51:49,040 --> 00:51:50,800 For some small delta x. 868 00:51:50,800 --> 00:51:59,850 So that's the quotient of the difference of f of the sum of 869 00:51:59,850 --> 00:52:10,345 x and dx minus f point x divided by dx. 870 00:52:10,345 --> 00:52:18,530 871 00:52:18,530 --> 00:52:21,360 I think the thing was lining up correctly when I balanced 872 00:52:21,360 --> 00:52:22,610 the parentheses. 873 00:52:22,610 --> 00:52:25,120 874 00:52:25,120 --> 00:52:27,070 Now, I want you to look at this. 875 00:52:27,070 --> 00:52:28,320 Just look. 876 00:52:28,320 --> 00:52:31,330 877 00:52:31,330 --> 00:52:33,220 I suppose I haven't told you what dx is. 878 00:52:33,220 --> 00:52:44,880 Somewhere in the world I'm going to have to write down 879 00:52:44,880 --> 00:52:45,770 something like that. 880 00:52:45,770 --> 00:52:48,150 I'm not interested. 881 00:52:48,150 --> 00:52:52,970 This is a procedure which takes a procedure and produces 882 00:52:52,970 --> 00:52:55,950 an approximation, a procedure that computes an approximation 883 00:52:55,950 --> 00:52:58,010 of the derivative of the function computed by the 884 00:52:58,010 --> 00:53:02,740 procedure given by the standard methods that you all 885 00:53:02,740 --> 00:53:04,800 know and love. 886 00:53:04,800 --> 00:53:08,920 Now, it may not be the case that doing this operation is 887 00:53:08,920 --> 00:53:11,390 such a good way of approximating a derivative. 888 00:53:11,390 --> 00:53:14,800 Numerical analysts here should jump on me and 889 00:53:14,800 --> 00:53:16,690 say don't do that. 890 00:53:16,690 --> 00:53:20,150 Computing derivatives produces noisy answers, which is true. 891 00:53:20,150 --> 00:53:24,850 However, this again is for the sake of understanding. 892 00:53:24,850 --> 00:53:26,620 Look what we've got. 893 00:53:26,620 --> 00:53:29,040 We started out with what is apparently a mathematically 894 00:53:29,040 --> 00:53:31,210 complex thing. 895 00:53:31,210 --> 00:53:31,610 and. 896 00:53:31,610 --> 00:53:35,370 In a few blackboards full, we managed to decompose the 897 00:53:35,370 --> 00:53:37,900 problem of computing square roots by the way you were 898 00:53:37,900 --> 00:53:41,770 taught in your college calculus class-- 899 00:53:41,770 --> 00:53:43,720 Newton's method-- 900 00:53:43,720 --> 00:53:45,830 so that it can be understood. 901 00:53:45,830 --> 00:53:47,840 It's clear. 902 00:53:47,840 --> 00:53:51,231 Let's look at the structure of what it is we've got. 903 00:53:51,231 --> 00:53:54,660 Let's look at this slide. 904 00:53:54,660 --> 00:54:03,110 This is a diagram of the machine described by the 905 00:54:03,110 --> 00:54:05,520 program on the blackboard. 906 00:54:05,520 --> 00:54:08,940 There's a machine described here. 907 00:54:08,940 --> 00:54:10,700 And what have I got? 908 00:54:10,700 --> 00:54:17,690 Over here is the Newton's method function f that we have 909 00:54:17,690 --> 00:54:21,040 on the left-most blackboard. 910 00:54:21,040 --> 00:54:24,990 It's the thing that takes an argument called y and puts out 911 00:54:24,990 --> 00:54:32,500 the difference between x and the square of y, where x is 912 00:54:32,500 --> 00:54:35,400 some sort of free variable that comes in from the outside 913 00:54:35,400 --> 00:54:38,050 by some magic. 914 00:54:38,050 --> 00:54:43,430 So the square root routine picks up an x, and builds this 915 00:54:43,430 --> 00:54:47,750 procedure, which I have the x rolled up in it by 916 00:54:47,750 --> 00:54:50,170 substitution. 917 00:54:50,170 --> 00:54:58,930 Now, this procedure in the cloud is fed in as the f into 918 00:54:58,930 --> 00:55:01,630 the Newton's method which is here, this box. 919 00:55:01,630 --> 00:55:04,650 920 00:55:04,650 --> 00:55:08,790 The f is fanned out. 921 00:55:08,790 --> 00:55:12,130 Part of it goes into something else, and the other part of it 922 00:55:12,130 --> 00:55:15,670 goes through a derivative process into something else to 923 00:55:15,670 --> 00:55:20,570 produce a procedure, which computes the function which is 924 00:55:20,570 --> 00:55:24,090 the iteration function of Newton's method when we use 925 00:55:24,090 --> 00:55:27,450 the fixed point method. 926 00:55:27,450 --> 00:55:33,030 So this procedure, which contains it by substitution-- 927 00:55:33,030 --> 00:55:37,730 remember, Newton's method over here, Newton's method builds 928 00:55:37,730 --> 00:55:43,010 this procedure, and Newton's method has in it defined f and 929 00:55:43,010 --> 00:55:48,900 df, so those are captured over here: f and df. 930 00:55:48,900 --> 00:55:51,930 Starting with this procedure, I can now feed this to the 931 00:55:51,930 --> 00:55:55,260 fixed point process within an initial guess coming out from 932 00:55:55,260 --> 00:55:59,135 the outside from square root to produce the 933 00:55:59,135 --> 00:56:00,385 square root of x. 934 00:56:00,385 --> 00:56:03,680 935 00:56:03,680 --> 00:56:07,680 So what we've built is a very powerful engine, which allows 936 00:56:07,680 --> 00:56:11,256 us to make nice things like this. 937 00:56:11,256 --> 00:56:19,000 Now, I want to end this with basically an idea of Chris 938 00:56:19,000 --> 00:56:21,520 Strachey, one of the 939 00:56:21,520 --> 00:56:23,230 grandfathers of computer science. 940 00:56:23,230 --> 00:56:27,440 He's a logician who lived in the-- 941 00:56:27,440 --> 00:56:30,320 I suppose about 10 years ago or 15 years ago, he died. 942 00:56:30,320 --> 00:56:31,840 I don't remember exactly when. 943 00:56:31,840 --> 00:56:33,250 He's one of the inventors of something called 944 00:56:33,250 --> 00:56:34,820 denotational semantics. 945 00:56:34,820 --> 00:56:40,560 He was a great advocate of making procedures or functions 946 00:56:40,560 --> 00:56:43,950 first-class citizens in a programming language. 947 00:56:43,950 --> 00:56:46,910 So here's the rights and privileges of first-class 948 00:56:46,910 --> 00:56:50,690 citizens in a programming language. 949 00:56:50,690 --> 00:56:53,070 It allows you to make any abstraction you like if you 950 00:56:53,070 --> 00:56:57,710 have functions as first-class citizens. 951 00:56:57,710 --> 00:56:59,030 The first-class citizens must be able 952 00:56:59,030 --> 00:57:02,270 to be named by variables. 953 00:57:02,270 --> 00:57:04,600 And you're seeing me doing that all the time. 954 00:57:04,600 --> 00:57:07,700 Here's a nice variable which names a procedure which 955 00:57:07,700 --> 00:57:08,950 computes something. 956 00:57:08,950 --> 00:57:13,270 957 00:57:13,270 --> 00:57:15,370 They have to be passed as arguments to procedures. 958 00:57:15,370 --> 00:57:18,540 We've certainly seen that. 959 00:57:18,540 --> 00:57:20,640 We have to be able to return them as values from 960 00:57:20,640 --> 00:57:23,340 procedures. 961 00:57:23,340 --> 00:57:25,300 And I suppose we've seen that. 962 00:57:25,300 --> 00:57:27,970 We haven't yet seen anything about data structures. 963 00:57:27,970 --> 00:57:31,490 We will soon, but it's also the case that in order to have 964 00:57:31,490 --> 00:57:33,940 a first-class citizen in a programming language, the 965 00:57:33,940 --> 00:57:37,200 object has to be allowed to be part of a data structure. 966 00:57:37,200 --> 00:57:39,110 We're going to see that soon. 967 00:57:39,110 --> 00:57:43,530 So I just want to close with this and say having things 968 00:57:43,530 --> 00:57:46,180 like procedures as first-class data structures, first-class 969 00:57:46,180 --> 00:57:50,780 data, allows one to make powerful abstractions, which 970 00:57:50,780 --> 00:57:53,110 encode general methods like Newton's method 971 00:57:53,110 --> 00:57:54,780 in very clear way. 972 00:57:54,780 --> 00:57:57,430 Are there any questions? 973 00:57:57,430 --> 00:57:57,780 Yes. 974 00:57:57,780 --> 00:58:00,040 AUDIENCE: Could you put derivative instead of df 975 00:58:00,040 --> 00:58:02,570 directly in the fixed point? 976 00:58:02,570 --> 00:58:03,810 PROFESSOR: Oh, sure. 977 00:58:03,810 --> 00:58:09,220 Yes, I could have put deriv of f right here, no question. 978 00:58:09,220 --> 00:58:11,810 979 00:58:11,810 --> 00:58:16,190 Any time you see something defined, you can put the thing 980 00:58:16,190 --> 00:58:18,950 that the definition is there because you 981 00:58:18,950 --> 00:58:21,060 get the same result. 982 00:58:21,060 --> 00:58:22,800 In fact, what that would look like, it's interesting. 983 00:58:22,800 --> 00:58:23,750 AUDIENCE: Lambda. 984 00:58:23,750 --> 00:58:24,085 PROFESSOR: Huh? 985 00:58:24,085 --> 00:58:25,970 AUDIENCE: You could put the lambda expression in there. 986 00:58:25,970 --> 00:58:29,990 PROFESSOR: I could also put derivative of f here. 987 00:58:29,990 --> 00:58:32,640 It would look interesting because of the open paren, 988 00:58:32,640 --> 00:58:38,610 open paren, deriv of f, closed paren on an x. 989 00:58:38,610 --> 00:58:40,900 Now, that would have the bad property of computing the 990 00:58:40,900 --> 00:58:43,980 derivative many times, because every time I would run this 991 00:58:43,980 --> 00:58:45,490 procedure, I would compute the derivative again. 992 00:58:45,490 --> 00:58:48,030 993 00:58:48,030 --> 00:58:52,510 However, the two open parens here both would be meaningful. 994 00:58:52,510 --> 00:58:54,600 I want you to understand syntactically that that's a 995 00:58:54,600 --> 00:58:55,350 sensible thing. 996 00:58:55,350 --> 00:58:58,190 Because if was to rewrite this program-- and I should do it 997 00:58:58,190 --> 00:59:00,210 right here just so you see because 998 00:59:00,210 --> 00:59:01,460 that's a good question-- 999 00:59:01,460 --> 00:59:11,490 1000 00:59:11,490 --> 00:59:25,430 of F and guess to be fixed point of that procedure of one 1001 00:59:25,430 --> 00:59:34,920 argument x, which subtracts from x the quotient of F 1002 00:59:34,920 --> 00:59:45,045 applied to x and the deriv of F applied to x. 1003 00:59:45,045 --> 00:59:53,459 1004 00:59:53,459 --> 00:59:54,709 This is guess. 1005 00:59:54,709 --> 00:59:59,960 1006 00:59:59,960 --> 01:00:02,680 This is a perfectly legitimate program, 1007 01:00:02,680 --> 01:00:04,250 because what I have here-- 1008 01:00:04,250 --> 01:00:05,910 remember the evaluation rule. 1009 01:00:05,910 --> 01:00:08,760 The evaluation rule is evaluate all of the parts of 1010 01:00:08,760 --> 01:00:12,070 the combination: the operator and the operands. 1011 01:00:12,070 --> 01:00:14,575 This is the operator of this combination. 1012 01:00:14,575 --> 01:00:17,080 1013 01:00:17,080 --> 01:00:21,080 Evaluating this operator will, of course, produce the 1014 01:00:21,080 --> 01:00:28,250 derivative of F. 1015 01:00:28,250 --> 01:00:30,300 AUDIENCE: To get it one step further, you could put the 1016 01:00:30,300 --> 01:00:31,200 lambda expression there, too. 1017 01:00:31,200 --> 01:00:33,180 PROFESSOR: Oh, of course. 1018 01:00:33,180 --> 01:00:37,620 Any time I take something which is define, I can put the 1019 01:00:37,620 --> 01:00:40,420 thing it's defined to be in the place where the thing 1020 01:00:40,420 --> 01:00:42,420 defined is. 1021 01:00:42,420 --> 01:00:44,430 I can't remember which is definiens and which is 1022 01:00:44,430 --> 01:00:45,680 definiendum. 1023 01:00:45,680 --> 01:00:47,490 1024 01:00:47,490 --> 01:00:50,230 When I'm trying to figure out how to do a lecture about this 1025 01:00:50,230 --> 01:00:54,160 in a freshman class, I use such words and tell everybody 1026 01:00:54,160 --> 01:00:55,440 it's fun to tell their friends. 1027 01:00:55,440 --> 01:00:59,470 1028 01:00:59,470 --> 01:01:01,460 OK, I think that's it. 1029 01:01:01,460 --> 01:01:18,506 ================================================ FILE: SrtEN/lec2b_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:05,892 1 00:00:05,892 --> 00:00:22,120 [MUSIC PLAYING] 2 00:00:22,120 --> 00:00:24,170 PROFESSOR: Well, so far in this course we've been talking 3 00:00:24,170 --> 00:00:27,680 about procedures, and then just to remind you of this 4 00:00:27,680 --> 00:00:31,090 framework that we introduced for talking about languages, 5 00:00:31,090 --> 00:00:33,980 we talked about the primitive things that are 6 00:00:33,980 --> 00:00:36,040 built into the system. 7 00:00:36,040 --> 00:00:39,710 We mentioned some means of combination by which you take 8 00:00:39,710 --> 00:00:42,530 the primitive things and you make more complicated things. 9 00:00:42,530 --> 00:00:44,610 And then we talked about the means of abstraction, how you 10 00:00:44,610 --> 00:00:47,190 can take those complicated things and name them so you 11 00:00:47,190 --> 00:00:49,770 can use them as simple building blocks. 12 00:00:49,770 --> 00:00:51,750 And then last time you saw we went even beyond that. 13 00:00:51,750 --> 00:00:55,830 We saw that by using higher order procedures, you can 14 00:00:55,830 --> 00:00:58,400 actually express general methods for computing things. 15 00:00:58,400 --> 00:01:01,540 Like the method of doing something by fixed points, or 16 00:01:01,540 --> 00:01:05,280 Newton's method, and so the incredible expressive power 17 00:01:05,280 --> 00:01:08,730 you can get just by combining these means of abstraction. 18 00:01:08,730 --> 00:01:13,260 And the crucial idea in all of this is the one that we build 19 00:01:13,260 --> 00:01:15,210 a layered system. 20 00:01:15,210 --> 00:01:17,570 So for instance, if we're writing the square root 21 00:01:17,570 --> 00:01:24,950 procedure, somewhere the square root procedure uses a 22 00:01:24,950 --> 00:01:33,130 procedure called good-enough, and between those there is 23 00:01:33,130 --> 00:01:35,220 some sort of abstraction boundary. 24 00:01:35,220 --> 00:01:38,060 25 00:01:38,060 --> 00:01:41,620 It's almost as if we go out and in writing square root, we 26 00:01:41,620 --> 00:01:45,940 go and make a contract with George, and tell George that 27 00:01:45,940 --> 00:01:49,600 his job is to write good-enough, and so long as 28 00:01:49,600 --> 00:01:52,630 good-enough works, we don't care what it does. 29 00:01:52,630 --> 00:01:54,380 We don't care exactly how it's implemented. 30 00:01:54,380 --> 00:01:58,360 There are levels of detail here that are George's concern 31 00:01:58,360 --> 00:02:00,450 and not ours. 32 00:02:00,450 --> 00:02:03,680 So for instance, George might use an absolute value 33 00:02:03,680 --> 00:02:07,370 procedure that's written by Harry, and we don't much care 34 00:02:07,370 --> 00:02:10,065 about that or even know that, maybe, Harry exists. 35 00:02:10,065 --> 00:02:13,830 36 00:02:13,830 --> 00:02:16,910 So the crucial idea is that when we're building things, we 37 00:02:16,910 --> 00:02:22,600 divorce the task of building things from the task of 38 00:02:22,600 --> 00:02:23,850 implementing the parts. 39 00:02:23,850 --> 00:02:27,690 40 00:02:27,690 --> 00:02:30,110 And in a large system, of course, we have abstraction 41 00:02:30,110 --> 00:02:34,180 barriers like this at lots, and lots, and lots of levels. 42 00:02:34,180 --> 00:02:36,700 And that's the idea that we've been using so far over and 43 00:02:36,700 --> 00:02:38,290 over in implementing procedures. 44 00:02:38,290 --> 00:02:41,220 Well, now what we're going to do is look at the 45 00:02:41,220 --> 00:02:44,170 same issues for data. 46 00:02:44,170 --> 00:02:46,350 We're going to see that the system has primitive data. 47 00:02:46,350 --> 00:02:47,470 In fact, we've already seen that. 48 00:02:47,470 --> 00:02:50,270 We've talked about numbers as primitive data. 49 00:02:50,270 --> 00:02:51,300 And then we're going to see their means of 50 00:02:51,300 --> 00:02:52,390 combination for data. 51 00:02:52,390 --> 00:02:55,940 There's glue that allows you to put primitive data together 52 00:02:55,940 --> 00:02:59,500 to make more complicated, kind of compound data. 53 00:02:59,500 --> 00:03:04,840 And then we're going to see a methodology for abstraction 54 00:03:04,840 --> 00:03:07,330 that's a very good thing to use when you start building up 55 00:03:07,330 --> 00:03:09,090 data in terms of simpler data. 56 00:03:09,090 --> 00:03:11,790 And again, the key idea is that you're going to build the 57 00:03:11,790 --> 00:03:15,700 system in layers and set up abstraction barriers that 58 00:03:15,700 --> 00:03:20,250 isolate the details at the lower layers from the thing 59 00:03:20,250 --> 00:03:21,630 that's going on at the upper layers. 60 00:03:21,630 --> 00:03:23,270 The details at the lower layers, the 61 00:03:23,270 --> 00:03:25,260 ideas, they won't matter. 62 00:03:25,260 --> 00:03:27,680 They're going to be George's concern because he signed this 63 00:03:27,680 --> 00:03:30,430 contract with us for how the stuff that he implements 64 00:03:30,430 --> 00:03:36,250 behaves, and how he implements the thing is his problem. 65 00:03:36,250 --> 00:03:37,890 All right, well let's look at an example. 66 00:03:37,890 --> 00:03:40,990 And the example I'm going to talk about is a system that 67 00:03:40,990 --> 00:03:43,010 does arithmetic on rational numbers. 68 00:03:43,010 --> 00:03:46,160 And what I have in mind is that we should have something 69 00:03:46,160 --> 00:03:52,220 in the computer that allows us to ask it, like, what's the 70 00:03:52,220 --> 00:04:00,590 sum of 1/2 and 1/4, and somehow the system should say, 71 00:04:00,590 --> 00:04:02,890 yeah, that's 3/4. 72 00:04:02,890 --> 00:04:11,370 Or we should be able to say what's 3/4 times 2/3, and the 73 00:04:11,370 --> 00:04:13,650 system should be able to say, yeah, that's 1/2. 74 00:04:13,650 --> 00:04:16,500 75 00:04:16,500 --> 00:04:16,730 Right? 76 00:04:16,730 --> 00:04:17,990 And you know what I have in mind. 77 00:04:17,990 --> 00:04:20,700 And you also know how to do this from, I don't know, fifth 78 00:04:20,700 --> 00:04:22,410 grade or sixth grade. 79 00:04:22,410 --> 00:04:26,510 There are these formulas that say if I have some fraction 80 00:04:26,510 --> 00:04:29,350 which is a numerator over a denominator, and I want to add 81 00:04:29,350 --> 00:04:33,600 that to some other fraction which is another numerator 82 00:04:33,600 --> 00:04:38,200 over another denominator, then the answer is the numerator of 83 00:04:38,200 --> 00:04:41,920 the first times the denominator of the second, 84 00:04:41,920 --> 00:04:45,885 plus the numerator of the second times the denominator 85 00:04:45,885 --> 00:04:49,930 of the first. That's the numerator of the answer, and 86 00:04:49,930 --> 00:04:53,260 the denominator is the product of the two denominators. 87 00:04:53,260 --> 00:04:53,400 Right? 88 00:04:53,400 --> 00:04:56,850 So there's something from fifth or sixth grade fraction 89 00:04:56,850 --> 00:04:57,570 arithmetic. 90 00:04:57,570 --> 00:05:00,320 And then similarly, if I want to multiply two things, n1 91 00:05:00,320 --> 00:05:06,710 over d1 multiplied by n2 over d2 is the product of the 92 00:05:06,710 --> 00:05:10,510 numerators over the product of the denominators. 93 00:05:10,510 --> 00:05:14,330 94 00:05:14,330 --> 00:05:18,880 So it's no problem at all, but it's absolutely no problem to 95 00:05:18,880 --> 00:05:21,460 think about what computation you want to make in adding and 96 00:05:21,460 --> 00:05:23,760 multiplying these fractions. 97 00:05:23,760 --> 00:05:26,010 But as soon as we go to implement it, we 98 00:05:26,010 --> 00:05:27,920 run up across something. 99 00:05:27,920 --> 00:05:33,320 We don't have what a rational number is. 100 00:05:33,320 --> 00:05:36,840 So we said that the system gives us individual numbers, 101 00:05:36,840 --> 00:05:43,700 so we can have 5 and 3, but somehow we don't have a way of 102 00:05:43,700 --> 00:05:47,970 saying there's a thing that has both a 3 and a 4 in it, or 103 00:05:47,970 --> 00:05:49,850 both a 2 and a 3. 104 00:05:49,850 --> 00:05:55,110 It's almost as if we'd like to imagine that somehow there are 105 00:05:55,110 --> 00:06:00,820 these clouds, and a cloud somehow has both a numerator 106 00:06:00,820 --> 00:06:03,590 and a denominator in it, and that's what we'd like to work 107 00:06:03,590 --> 00:06:04,840 in terms of. 108 00:06:04,840 --> 00:06:06,820 109 00:06:06,820 --> 00:06:08,320 Well, how are we going to solve that problem? 110 00:06:08,320 --> 00:06:11,360 We're going to solve that problem by using this 111 00:06:11,360 --> 00:06:14,450 incredibly powerful design strategy that you've already 112 00:06:14,450 --> 00:06:16,580 seen us use over and over. 113 00:06:16,580 --> 00:06:18,330 And that's the strategy of wishful thinking. 114 00:06:18,330 --> 00:06:25,700 115 00:06:25,700 --> 00:06:27,870 Just like before when we didn't have a procedure, we 116 00:06:27,870 --> 00:06:31,420 said, well, let's imagine that that procedure already exists. 117 00:06:31,420 --> 00:06:36,100 We'll say, well, let's imagine that we have these clouds. 118 00:06:36,100 --> 00:06:42,400 Now more precisely what I mean is let's imagine that we have 119 00:06:42,400 --> 00:06:45,120 three procedures, one called make-RAT. 120 00:06:45,120 --> 00:06:47,740 121 00:06:47,740 --> 00:06:54,696 make-RAT is going to take as arguments two numbers, so I'll 122 00:06:54,696 --> 00:06:58,800 call them numerator and denominator, and it'll return 123 00:06:58,800 --> 00:07:02,860 for us a cloud-- 124 00:07:02,860 --> 00:07:05,300 one of these clouds. 125 00:07:05,300 --> 00:07:07,030 I don't really know what a cloud is. 126 00:07:07,030 --> 00:07:11,500 It's whatever make-RAT returns, that's its business. 127 00:07:11,500 --> 00:07:13,400 And then we're going to say, suppose we've got one of these 128 00:07:13,400 --> 00:07:17,800 clouds, we have a procedure called numer, which takes in a 129 00:07:17,800 --> 00:07:21,462 cloud that has an n and a d in it, whatever a cloud is, and I 130 00:07:21,462 --> 00:07:23,990 don't know what it is, and returns for us 131 00:07:23,990 --> 00:07:26,980 the numerator part. 132 00:07:26,980 --> 00:07:31,750 And then we'll assume we have a procedure denom, which again 133 00:07:31,750 --> 00:07:36,610 takes in a cloud, whatever a cloud is, and returns for us 134 00:07:36,610 --> 00:07:37,850 the denominator [? required. ?] 135 00:07:37,850 --> 00:07:42,530 This is just like before, when if we're building a square 136 00:07:42,530 --> 00:07:45,440 root, we assume that we have good enough. 137 00:07:45,440 --> 00:07:45,600 Right? 138 00:07:45,600 --> 00:07:48,310 And what we'll say is, we'll go find George, and we'll say 139 00:07:48,310 --> 00:07:50,480 to George, well, it's your business to make us these 140 00:07:50,480 --> 00:07:52,280 procedures. 141 00:07:52,280 --> 00:07:54,170 And how you choose to implement these clouds, that's 142 00:07:54,170 --> 00:07:55,060 your problem. 143 00:07:55,060 --> 00:07:56,310 We don't want to know. 144 00:07:56,310 --> 00:07:58,670 145 00:07:58,670 --> 00:08:03,740 Well, having pushed this task off onto George, then it's 146 00:08:03,740 --> 00:08:05,520 pretty easy to do the other part. 147 00:08:05,520 --> 00:08:08,360 Once we've got the clouds, it's pretty easy to write the 148 00:08:08,360 --> 00:08:11,820 thing that does say addition of rational numbers. 149 00:08:11,820 --> 00:08:17,820 You can just say define, well, let's say +RAT. 150 00:08:17,820 --> 00:08:21,980 151 00:08:21,980 --> 00:08:25,450 Define +RAT, which will take in two rational 152 00:08:25,450 --> 00:08:28,110 numbers, x and y. 153 00:08:28,110 --> 00:08:31,880 x and y are each these clouds. 154 00:08:31,880 --> 00:08:32,539 And what does it do? 155 00:08:32,539 --> 00:08:35,840 Well, it's going to return for us a rational number. 156 00:08:35,840 --> 00:08:40,299 157 00:08:40,299 --> 00:08:41,460 What rational number is it? 158 00:08:41,460 --> 00:08:43,659 Well, we've got the formulas there. 159 00:08:43,659 --> 00:08:49,620 The numerator of it is the sum of the product of the 160 00:08:49,620 --> 00:08:56,550 numerator of x and the denominator of y. 161 00:08:56,550 --> 00:09:02,580 162 00:09:02,580 --> 00:09:03,950 It's one thing in the sum. 163 00:09:03,950 --> 00:09:07,310 And the other thing in the numerator is the product of 164 00:09:07,310 --> 00:09:19,060 the numerator of y and the denominator of x. 165 00:09:19,060 --> 00:09:20,910 The star, close the plus. 166 00:09:20,910 --> 00:09:23,830 Right, that's the first argument to make-RAT, which is 167 00:09:23,830 --> 00:09:26,080 the numerator of the thing I'm constructing. 168 00:09:26,080 --> 00:09:28,860 And then the rest of the thing goes into make-RAT is the 169 00:09:28,860 --> 00:09:32,950 denominator of the answer, which is the product of the 170 00:09:32,950 --> 00:09:42,230 denominator of x and the denominator of y. 171 00:09:42,230 --> 00:09:43,480 Like that. 172 00:09:43,480 --> 00:09:46,050 173 00:09:46,050 --> 00:09:46,500 OK? 174 00:09:46,500 --> 00:09:50,480 So there is the analog of doing 175 00:09:50,480 --> 00:09:51,710 rational number addition. 176 00:09:51,710 --> 00:09:54,030 And it's no problem at all, assuming that 177 00:09:54,030 --> 00:09:55,280 we have these clouds. 178 00:09:55,280 --> 00:09:59,020 179 00:09:59,020 --> 00:10:00,810 And of course, we can do 180 00:10:00,810 --> 00:10:02,250 multiplication in the same way. 181 00:10:02,250 --> 00:10:05,570 182 00:10:05,570 --> 00:10:10,030 Define how to get the product of two rational 183 00:10:10,030 --> 00:10:13,080 numbers, call it *RAT. 184 00:10:13,080 --> 00:10:20,950 Takes in two of these clouds, x and y, it returns a rational 185 00:10:20,950 --> 00:10:27,100 number, make-RAT, whose numerator is the product of 186 00:10:27,100 --> 00:10:28,350 the numerators-- 187 00:10:28,350 --> 00:10:30,270 188 00:10:30,270 --> 00:10:38,170 numerator of x times the numerator of y. 189 00:10:38,170 --> 00:10:41,780 And the denominator of the thing it's going to return is 190 00:10:41,780 --> 00:10:43,030 the product of the denominators. 191 00:10:43,030 --> 00:10:57,930 192 00:10:57,930 --> 00:11:01,550 Well, except that I haven't told you what these clouds 193 00:11:01,550 --> 00:11:04,510 are, that's all there is to it. 194 00:11:04,510 --> 00:11:05,280 See, what did I do? 195 00:11:05,280 --> 00:11:08,510 I assumed by wishful thinking that I had a new 196 00:11:08,510 --> 00:11:10,490 kind of data object. 197 00:11:10,490 --> 00:11:14,780 And in particular, I assumed I had ways of creating these 198 00:11:14,780 --> 00:11:16,360 data objects. 199 00:11:16,360 --> 00:11:18,140 Make-RAT creates one of these things. 200 00:11:18,140 --> 00:11:19,390 This is called a constructor. 201 00:11:19,390 --> 00:11:25,720 202 00:11:25,720 --> 00:11:29,750 All right, I have a thing that constructs such data objects. 203 00:11:29,750 --> 00:11:34,370 And then I assume I have things that, having made these 204 00:11:34,370 --> 00:11:35,940 things, I have ways of getting the parts out. 205 00:11:35,940 --> 00:11:37,550 Those are called selectors. 206 00:11:37,550 --> 00:11:42,850 207 00:11:42,850 --> 00:11:45,750 And so formally, what I said is I assumed I had procedures 208 00:11:45,750 --> 00:11:48,450 that are constructors and selectors for these data 209 00:11:48,450 --> 00:11:52,090 objects, and then I went off and used them. 210 00:11:52,090 --> 00:11:55,010 That's no different in kind from saying I assume I have a 211 00:11:55,010 --> 00:11:57,240 procedure good-enough, and I go use it to 212 00:11:57,240 --> 00:11:58,490 implement square root. 213 00:11:58,490 --> 00:12:00,850 214 00:12:00,850 --> 00:12:06,940 OK, well before we go on, let's ask the question of why 215 00:12:06,940 --> 00:12:08,660 do we want to do this in the first place? 216 00:12:08,660 --> 00:12:14,170 See, why do we want a procedure like +RAT that takes 217 00:12:14,170 --> 00:12:20,340 in two rational numbers and returns a rational number? 218 00:12:20,340 --> 00:12:22,140 See, another way to think about this is, well, here's 219 00:12:22,140 --> 00:12:23,390 this formula. 220 00:12:23,390 --> 00:12:25,160 221 00:12:25,160 --> 00:12:28,060 And I've also got to implement something that 222 00:12:28,060 --> 00:12:29,890 adds rational numbers. 223 00:12:29,890 --> 00:12:32,240 One other way to think about is, well, there's this thing, 224 00:12:32,240 --> 00:12:34,850 and I type in four numbers, an n1, and a d1, and 225 00:12:34,850 --> 00:12:36,600 an n2, and a d2. 226 00:12:36,600 --> 00:12:41,610 And it sets some registers in the machine to this numerator 227 00:12:41,610 --> 00:12:42,440 and this denominator. 228 00:12:42,440 --> 00:12:44,380 So I might say, well, why don't I just add rational 229 00:12:44,380 --> 00:12:46,640 numbers by I type in four numbers, numerators and 230 00:12:46,640 --> 00:12:48,950 denominators, and get out two numbers, which is a numerator 231 00:12:48,950 --> 00:12:51,000 and a denominator. 232 00:12:51,000 --> 00:12:54,020 Why are we worrying about building 233 00:12:54,020 --> 00:12:55,270 things like this anyway? 234 00:12:55,270 --> 00:12:58,620 235 00:12:58,620 --> 00:13:02,390 Well, the answer is, suppose you want to think about 236 00:13:02,390 --> 00:13:06,620 expressing something like this, suppose I'd like to 237 00:13:06,620 --> 00:13:14,840 express the idea of taking two rational numbers, x plus y, 238 00:13:14,840 --> 00:13:20,720 say, and multiplying that by the sum of two 239 00:13:20,720 --> 00:13:23,670 other rational numbers. 240 00:13:23,670 --> 00:13:28,650 Well, the way I do it, having things like +RAT and *RAT, is 241 00:13:28,650 --> 00:13:33,930 I'd say, oh yeah, what that is is just the product. 242 00:13:33,930 --> 00:13:51,570 That's *RAT of the sum of x and y and the sum of s and t. 243 00:13:51,570 --> 00:13:57,710 So except for syntax, I get an expression that looks like the 244 00:13:57,710 --> 00:13:59,490 way I want to think about it mathematically. 245 00:13:59,490 --> 00:14:02,080 I want to say there are two numbers. 246 00:14:02,080 --> 00:14:06,060 There's a thing which is the sum of them, and there's a 247 00:14:06,060 --> 00:14:07,490 thing which is the sum of these two. 248 00:14:07,490 --> 00:14:10,780 That's this and this. 249 00:14:10,780 --> 00:14:12,530 And then I multiply them. 250 00:14:12,530 --> 00:14:14,640 So I get an expression that matches this expression. 251 00:14:14,640 --> 00:14:17,720 If I did the other thing, if I said, well, the way I want to 252 00:14:17,720 --> 00:14:20,770 think about this is I type into my machine four numbers, 253 00:14:20,770 --> 00:14:24,140 which are the numerators and the denominators of x and y, 254 00:14:24,140 --> 00:14:26,540 and then four more numbers, which are the numerators and 255 00:14:26,540 --> 00:14:29,140 denominators of s and t. 256 00:14:29,140 --> 00:14:30,460 And then what I'd be sitting with is, well, 257 00:14:30,460 --> 00:14:31,340 what would I do? 258 00:14:31,340 --> 00:14:34,380 I'd add these, and somehow I'd have to have two temporary 259 00:14:34,380 --> 00:14:37,090 variables, which are the numerators and denominators of 260 00:14:37,090 --> 00:14:39,710 this sum, and I'd go off and store them someplace. 261 00:14:39,710 --> 00:14:42,500 262 00:14:42,500 --> 00:14:44,670 And then I'd go over here, I'd type in four more numbers, I'd 263 00:14:44,670 --> 00:14:47,140 get two more temporary variables, which are the 264 00:14:47,140 --> 00:14:50,180 numerators and denominators of s and t. 265 00:14:50,180 --> 00:14:55,000 And then finally, I put those together by multiplying them. 266 00:14:55,000 --> 00:14:56,890 You see, what's starting to happen, there are all these 267 00:14:56,890 --> 00:15:01,450 temporary variables, which are sort of the guts of the 268 00:15:01,450 --> 00:15:04,320 internals of these rational numbers that start hanging out 269 00:15:04,320 --> 00:15:06,190 all over the system. 270 00:15:06,190 --> 00:15:08,050 And of course, if I had more and more complicated 271 00:15:08,050 --> 00:15:10,380 expressions, there'd be more and more guts hanging out that 272 00:15:10,380 --> 00:15:13,010 confuse my programming. 273 00:15:13,010 --> 00:15:15,920 And those of you who sort of programmed things like that, 274 00:15:15,920 --> 00:15:18,440 where you're just adding numbers in assembly language, 275 00:15:18,440 --> 00:15:20,280 you sort of see you have to suddenly be concerned with 276 00:15:20,280 --> 00:15:23,040 these temporary variables. 277 00:15:23,040 --> 00:15:28,350 But more importantly than confusing my programming, 278 00:15:28,350 --> 00:15:29,760 they're going to confuse my mind. 279 00:15:29,760 --> 00:15:34,700 Because the whole name of this game is that we'd like the 280 00:15:34,700 --> 00:15:38,750 programming language to express the concepts that we 281 00:15:38,750 --> 00:15:41,350 have in our heads, like rational numbers are things 282 00:15:41,350 --> 00:15:44,770 that you can add and then take that result and multiply them. 283 00:15:44,770 --> 00:15:48,760 284 00:15:48,760 --> 00:15:50,010 Let's break for questions. 285 00:15:50,010 --> 00:15:59,570 286 00:15:59,570 --> 00:16:00,080 Yeah? 287 00:16:00,080 --> 00:16:03,240 AUDIENCE: I don't quite see the need- when we had make-RAT 288 00:16:03,240 --> 00:16:05,150 with the numerator and denominator, we had to have 289 00:16:05,150 --> 00:16:07,590 the numerator and denominator to pass as parameters to 290 00:16:07,590 --> 00:16:10,420 create the cloud, and then we extracted to get back what we 291 00:16:10,420 --> 00:16:11,720 had to have originally. 292 00:16:11,720 --> 00:16:13,740 PROFESSOR: That's right. 293 00:16:13,740 --> 00:16:16,310 So the question is, I sort of have the numerator and the 294 00:16:16,310 --> 00:16:20,690 denominator, why am I worrying about having the cloud given 295 00:16:20,690 --> 00:16:23,500 that I have to get the pieces out? 296 00:16:23,500 --> 00:16:26,310 That's sort of what I tried to say at the end, but let me try 297 00:16:26,310 --> 00:16:27,250 and say it again, because that's 298 00:16:27,250 --> 00:16:29,390 really the crucial question. 299 00:16:29,390 --> 00:16:32,540 The point is, I want to carry this numerator and denominator 300 00:16:32,540 --> 00:16:36,816 around together all the time. 301 00:16:36,816 --> 00:16:39,570 And it's almost as if I want to know, yeah, there's a 302 00:16:39,570 --> 00:16:42,350 numerator and denominator in there, but also, I would like 303 00:16:42,350 --> 00:16:50,180 to say, fine, but from another point of view, that's x. 304 00:16:50,180 --> 00:16:53,040 And I carry x around, and I name it as x, and I hold it. 305 00:16:53,040 --> 00:16:56,520 And I can say things like, the sum of x and y, rather than 306 00:16:56,520 --> 00:16:59,180 just have-- see, it's not so bad when I only think about x, 307 00:16:59,180 --> 00:17:02,360 but if I have a system with 10 rational numbers, suddenly I 308 00:17:02,360 --> 00:17:04,770 have 20 numerators and denominators, which are not 309 00:17:04,770 --> 00:17:05,930 necessarily-- 310 00:17:05,930 --> 00:17:08,609 if I don't link them, then it's just 20 arbitrary numbers 311 00:17:08,609 --> 00:17:10,560 that are not linked in any particular way. 312 00:17:10,560 --> 00:17:14,400 It's a lot like saying, well, I have these instructions that 313 00:17:14,400 --> 00:17:16,099 are the body of the procedures, why do I want to 314 00:17:16,099 --> 00:17:17,970 package them and say it's the procedure? 315 00:17:17,970 --> 00:17:19,220 It's exactly the same idea. 316 00:17:19,220 --> 00:17:31,875 317 00:17:31,875 --> 00:17:33,840 No? 318 00:17:33,840 --> 00:17:35,120 OK. 319 00:17:35,120 --> 00:17:36,870 Let's break, let's just stretch and get somebody-- 320 00:17:36,870 --> 00:17:38,349 [INAUDIBLE] 321 00:17:38,349 --> 00:18:27,080 [MUSIC PLAYING] 322 00:18:27,080 --> 00:18:29,790 OK, well, we've been working on this rational number 323 00:18:29,790 --> 00:18:34,590 arithmetic system, and then what we did, the important 324 00:18:34,590 --> 00:18:37,430 thing about what we did, is we thought about the problem by 325 00:18:37,430 --> 00:18:40,160 breaking it into two pieces. 326 00:18:40,160 --> 00:18:43,580 We said, assume there is this contract with George, and 327 00:18:43,580 --> 00:18:46,200 George has figured out the way to how to construct these 328 00:18:46,200 --> 00:18:50,900 clouds, provided us procedures make-RAT, which was a 329 00:18:50,900 --> 00:18:54,340 constructor, and selectors, which are numerator and 330 00:18:54,340 --> 00:18:55,040 denominator. 331 00:18:55,040 --> 00:18:57,580 And then in terms of that, we went off and implemented 332 00:18:57,580 --> 00:19:00,630 addition and multiplication of rational numbers. 333 00:19:00,630 --> 00:19:03,640 Well, now let's go look at George's problem. 334 00:19:03,640 --> 00:19:06,910 How can we go and package together a numerator and a 335 00:19:06,910 --> 00:19:09,360 denominator and actually make one of these clouds? 336 00:19:09,360 --> 00:19:15,760 See, what we need is a kind of glue, a glue for data objects 337 00:19:15,760 --> 00:19:18,040 that allows us to put things together. 338 00:19:18,040 --> 00:19:23,170 And Lisp provides such a glue, and that glue 339 00:19:23,170 --> 00:19:24,420 is called list structure. 340 00:19:24,420 --> 00:19:30,410 341 00:19:30,410 --> 00:19:35,700 List structure is a way of gluing things together, and 342 00:19:35,700 --> 00:19:40,750 more precisely, Lisp provides a way of constructing things 343 00:19:40,750 --> 00:19:42,000 called pairs. 344 00:19:42,000 --> 00:19:44,750 345 00:19:44,750 --> 00:19:52,222 There's a primitive operator in Lisp called cons. 346 00:19:52,222 --> 00:19:54,920 We can take a look at it. 347 00:19:54,920 --> 00:19:57,170 There's a thing called cons. 348 00:19:57,170 --> 00:20:00,620 349 00:20:00,620 --> 00:20:03,880 Cons is an operator which takes in two arguments called 350 00:20:03,880 --> 00:20:08,800 x and y, and it returns for us a thing called a pair. 351 00:20:08,800 --> 00:20:11,510 352 00:20:11,510 --> 00:20:17,520 All right, so a thing called a pair that has a first part a 353 00:20:17,520 --> 00:20:18,770 second part. 354 00:20:18,770 --> 00:20:22,250 355 00:20:22,250 --> 00:20:25,450 So cons takes two objects. 356 00:20:25,450 --> 00:20:26,780 There's a thing called a pair. 357 00:20:26,780 --> 00:20:30,700 The first part of the cons is x, and the second part 358 00:20:30,700 --> 00:20:31,600 of the cons is y. 359 00:20:31,600 --> 00:20:34,090 And that's what it builds. 360 00:20:34,090 --> 00:20:35,740 And then we also assume we have ways of 361 00:20:35,740 --> 00:20:36,880 getting things out. 362 00:20:36,880 --> 00:20:41,820 If you're given a pair, there's a thing called car, 363 00:20:41,820 --> 00:20:44,760 and car of a pair, p, gives you out the first part 364 00:20:44,760 --> 00:20:46,640 of the pair, p. 365 00:20:46,640 --> 00:20:49,650 And there's a thing called cdr, and cdr of the pair, p, 366 00:20:49,650 --> 00:20:54,310 gives you the second part of the pair, p. 367 00:20:54,310 --> 00:20:56,710 OK, so that's how we construct things. 368 00:20:56,710 --> 00:21:01,720 There's also a conventional way of drawing pictures of 369 00:21:01,720 --> 00:21:02,800 these things. 370 00:21:02,800 --> 00:21:09,070 Just like we write down that as the conventional way of 371 00:21:09,070 --> 00:21:17,480 writing Plato's idea of two, the way we could draw a 372 00:21:17,480 --> 00:21:21,510 diagram to represent cons of two and three is like this. 373 00:21:21,510 --> 00:21:23,912 We draw a little box. 374 00:21:23,912 --> 00:21:27,140 And so here's the box we're talking about, and this box 375 00:21:27,140 --> 00:21:30,070 has two arrows coming out of it. 376 00:21:30,070 --> 00:21:35,890 And say the first part of this pair is 2, and the second part 377 00:21:35,890 --> 00:21:38,250 of this pair is 3. 378 00:21:38,250 --> 00:21:41,180 And this notation has a name, it's called 379 00:21:41,180 --> 00:21:44,855 box and pointer notation. 380 00:21:44,855 --> 00:21:56,050 381 00:21:56,050 --> 00:21:58,340 By the way, let me say right now that a lot of people get 382 00:21:58,340 --> 00:22:01,650 confused that there's some significance to the geometric 383 00:22:01,650 --> 00:22:03,640 way I drew these pointers, the directions. 384 00:22:03,640 --> 00:22:06,090 Like some people think it'd be different if I took this 385 00:22:06,090 --> 00:22:08,660 pointer and turned it up here, and put the 3 out here. 386 00:22:08,660 --> 00:22:10,760 That has no significance. 387 00:22:10,760 --> 00:22:10,940 All right? 388 00:22:10,940 --> 00:22:13,240 It's merely you have a bunch of arrows, these 389 00:22:13,240 --> 00:22:15,090 pointers, and the boxes. 390 00:22:15,090 --> 00:22:18,860 The only issue is how they're connected, not the geometric 391 00:22:18,860 --> 00:22:20,400 arrangement of whether I write the pointer 392 00:22:20,400 --> 00:22:23,160 across, or up, or down. 393 00:22:23,160 --> 00:22:26,700 Now it's completely un-obvious, probably, why 394 00:22:26,700 --> 00:22:28,870 that's called list structure. 395 00:22:28,870 --> 00:22:30,420 We're not actually going to talk about that today. 396 00:22:30,420 --> 00:22:31,850 We'll see that next time. 397 00:22:31,850 --> 00:22:37,870 398 00:22:37,870 --> 00:22:41,740 So those are pairs, there's cons that constructs them. 399 00:22:41,740 --> 00:22:45,640 And what I'm going to know about cons, and car, and cdr, 400 00:22:45,640 --> 00:22:51,420 is precisely that if I have any x and y, all right, if I 401 00:22:51,420 --> 00:22:59,420 have any things x and y, and I use cons to construct a pair, 402 00:22:59,420 --> 00:23:03,090 then the car of that pair is going to be x, the thing I put 403 00:23:03,090 --> 00:23:07,790 in, and the cdr of that pair is going to be y. 404 00:23:07,790 --> 00:23:12,360 That's the behavior of these operators, cons, car, and cdr. 405 00:23:12,360 --> 00:23:14,870 Given them, it's pretty clear how George can go off and 406 00:23:14,870 --> 00:23:17,520 construct his rational numbers. 407 00:23:17,520 --> 00:23:19,390 After all, all he has to do-- 408 00:23:19,390 --> 00:23:21,710 remember George's problem was to implement make-RAT, 409 00:23:21,710 --> 00:23:23,320 numerator, and denom. 410 00:23:23,320 --> 00:23:34,980 So all George has to do is say define make-RAT of 411 00:23:34,980 --> 00:23:37,110 some n and a d-- 412 00:23:37,110 --> 00:23:40,710 so all I have to do is cons them. 413 00:23:40,710 --> 00:23:42,790 That's cons of n and d. 414 00:23:42,790 --> 00:23:45,570 415 00:23:45,570 --> 00:23:48,300 And then if I want to get the numerator out, I would say 416 00:23:48,300 --> 00:24:00,260 define the numerator, numer, of some rational number, x. 417 00:24:00,260 --> 00:24:03,010 If the rational number's implemented as a pair, then 418 00:24:03,010 --> 00:24:06,190 all I have to do is get out the car of x. 419 00:24:06,190 --> 00:24:19,350 And then similarly, define the denom is going to be the cdr, 420 00:24:19,350 --> 00:24:21,430 the other thing I put into the pair. 421 00:24:21,430 --> 00:24:27,080 422 00:24:27,080 --> 00:24:28,960 Well, now we're in business. 423 00:24:28,960 --> 00:24:31,530 That's a complete 424 00:24:31,530 --> 00:24:33,810 implementation of rational numbers. 425 00:24:33,810 --> 00:24:34,410 Let's use it. 426 00:24:34,410 --> 00:24:37,270 Suppose I want to say, so I want to think about how to add 427 00:24:37,270 --> 00:24:43,470 1/2 plus 1/4 and watch the system work. 428 00:24:43,470 --> 00:24:50,780 Well, the way I'd use that is I'd say, well, maybe define a. 429 00:24:50,780 --> 00:24:53,080 I have to make a 1/2. 430 00:24:53,080 --> 00:24:55,980 Well, that's a rational number with numerator 1 and 431 00:24:55,980 --> 00:25:01,090 denominator 2, so a will be make-RAT of 1 and 2. 432 00:25:01,090 --> 00:25:05,490 433 00:25:05,490 --> 00:25:07,770 And then I'll construct the 1/4. 434 00:25:07,770 --> 00:25:20,560 I'll say define d to be make-RAT of 1 and 4. 435 00:25:20,560 --> 00:25:23,362 436 00:25:23,362 --> 00:25:25,440 And if I'd like to look at the answer-- 437 00:25:25,440 --> 00:25:27,710 well, assuming I don't have a special thing that prints 438 00:25:27,710 --> 00:25:30,100 rational numbers, or I could make one-- 439 00:25:30,100 --> 00:25:41,622 I could say, for instance, define the answer to be +RAT 440 00:25:41,622 --> 00:25:47,790 of a and b, and now I can say, what's the answer? 441 00:25:47,790 --> 00:25:50,900 What are the numerators and denominators of the answer? 442 00:25:50,900 --> 00:25:55,520 So if I'm adding 1/2 and 1/4, I'll say, what is the 443 00:25:55,520 --> 00:26:00,440 numerator of the answer? 444 00:26:00,440 --> 00:26:04,230 445 00:26:04,230 --> 00:26:10,880 And the system is going to type out, well, 6. 446 00:26:10,880 --> 00:26:13,250 Bad news. 447 00:26:13,250 --> 00:26:22,790 And if I say what's the denominator of the answer, the 448 00:26:22,790 --> 00:26:26,430 system's going to type out 8. 449 00:26:26,430 --> 00:26:30,400 So instead of what I would really like, which is for it 450 00:26:30,400 --> 00:26:36,550 to say that 1/2 and 1/4 is 3/4, this foolish machine is 451 00:26:36,550 --> 00:26:40,450 going to say, no, it's 6/8. 452 00:26:40,450 --> 00:26:43,400 Well, that's sort of bad news. 453 00:26:43,400 --> 00:26:44,650 Where's the bug? 454 00:26:44,650 --> 00:26:47,280 455 00:26:47,280 --> 00:26:48,780 Why does it do that, after all? 456 00:26:48,780 --> 00:26:51,400 Well, it's the way that we just had +RAT. 457 00:26:51,400 --> 00:26:53,220 +RAT just took the-- 458 00:26:53,220 --> 00:26:58,510 it said you add the numerator times the denominator, you add 459 00:26:58,510 --> 00:27:01,230 that to the numerator times the denominator, and put that 460 00:27:01,230 --> 00:27:03,140 over the product of the two denominators, and that's why 461 00:27:03,140 --> 00:27:05,890 you get 6/8. 462 00:27:05,890 --> 00:27:10,640 So what was wrong with our implementation of +RAT? 463 00:27:10,640 --> 00:27:12,110 What's wrong with that rational number arithmetic 464 00:27:12,110 --> 00:27:15,880 stuff that we did before the break? 465 00:27:15,880 --> 00:27:17,730 Well, the answer is one way to look at it is absolutely 466 00:27:17,730 --> 00:27:19,730 nothing's wrong. 467 00:27:19,730 --> 00:27:21,070 That's perfectly good implementation. 468 00:27:21,070 --> 00:27:26,285 It follows the sixth grade, fifth grade mathematic for 469 00:27:26,285 --> 00:27:27,535 adding fractions. 470 00:27:27,535 --> 00:27:30,000 471 00:27:30,000 --> 00:27:33,310 One thing we can say is, well, that's George's problem. 472 00:27:33,310 --> 00:27:37,030 Like, boy, wasn't George dumb to say that he can make a 473 00:27:37,030 --> 00:27:39,960 rational number simply by sticking together the 474 00:27:39,960 --> 00:27:42,900 numerator and the denominator? 475 00:27:42,900 --> 00:27:45,910 Wouldn't it be better for George, when he made a 476 00:27:45,910 --> 00:27:50,970 rational number, to reduce the stuff to lowest terms? 477 00:27:50,970 --> 00:27:55,750 And what I mean is, wouldn't it be better for George, 478 00:27:55,750 --> 00:28:01,300 instead of using this version of make-RAT, to use this one 479 00:28:01,300 --> 00:28:03,580 on the slide? 480 00:28:03,580 --> 00:28:09,190 Or instead of just saying cons together n and d, what you do 481 00:28:09,190 --> 00:28:13,650 is compute the greatest common divisor of n and d, and gcd is 482 00:28:13,650 --> 00:28:16,540 the procedure which, well, for all we care is a primitive, 483 00:28:16,540 --> 00:28:20,628 which computes the greatest common divisor of two numbers. 484 00:28:20,628 --> 00:28:24,890 So the way I can construct a rational number is get the 485 00:28:24,890 --> 00:28:27,140 greatest common divisor of the two numbers, and I'm going to 486 00:28:27,140 --> 00:28:33,000 call that g, and then instead of consing together n and d, 487 00:28:33,000 --> 00:28:34,000 I'll divide them through. 488 00:28:34,000 --> 00:28:37,630 I'll cons together the quotient of n by the the gcd 489 00:28:37,630 --> 00:28:40,510 and the quotient of d by the gcd. 490 00:28:40,510 --> 00:28:42,540 And that will reduce the rational number to lowest 491 00:28:42,540 --> 00:28:49,200 terms. So when I do this addition, 492 00:28:49,200 --> 00:28:54,330 when +RAT calls make-RAT-- 493 00:28:54,330 --> 00:28:57,810 and for the definition of +RAT it had a make-RAT in there-- 494 00:28:57,810 --> 00:28:59,880 just by the fact that it's constructing that, the thing 495 00:28:59,880 --> 00:29:01,425 will get reduced to lowest terms automatically. 496 00:29:01,425 --> 00:29:09,612 497 00:29:09,612 --> 00:29:15,180 OK, that is a complete system. 498 00:29:15,180 --> 00:29:16,780 For rational number arithmetic, let's look at what 499 00:29:16,780 --> 00:29:19,590 we've done. 500 00:29:19,590 --> 00:29:22,440 All right, we said we want to build rational number 501 00:29:22,440 --> 00:29:27,230 arithmetic, and we had a thing called +RAT. 502 00:29:27,230 --> 00:29:29,940 We implemented that. 503 00:29:29,940 --> 00:29:34,660 And I showed you multiplying rational numbers, and although 504 00:29:34,660 --> 00:29:36,570 I didn't put them up there, presumably we'd like to have 505 00:29:36,570 --> 00:29:39,860 something that subtracts rational numbers, and I don't 506 00:29:39,860 --> 00:29:40,770 know, all sorts of things. 507 00:29:40,770 --> 00:29:43,120 Things that test equality in division, and maybe things 508 00:29:43,120 --> 00:29:46,190 that print rational numbers in some particular way. 509 00:29:46,190 --> 00:29:52,330 And we implemented those in terms of pairs. 510 00:29:52,330 --> 00:29:55,800 These pairs, cons, car, and cdr that are built into Lisp. 511 00:29:55,800 --> 00:30:05,100 But the important thing is that between these and these, 512 00:30:05,100 --> 00:30:07,622 we set up an abstraction barrier. 513 00:30:07,622 --> 00:30:09,260 We set up a layer of abstraction. 514 00:30:09,260 --> 00:30:17,310 515 00:30:17,310 --> 00:30:19,190 And what was that layer of abstraction? 516 00:30:19,190 --> 00:30:22,140 That layer of abstraction was precisely the constructor and 517 00:30:22,140 --> 00:30:23,390 the selectors. 518 00:30:23,390 --> 00:30:25,630 519 00:30:25,630 --> 00:30:34,730 This layer was make-RAT, and numer, and denom. 520 00:30:34,730 --> 00:30:38,970 521 00:30:38,970 --> 00:30:43,670 This methodology, another way to say what it's doing, is 522 00:30:43,670 --> 00:30:53,960 that we are separating the way something is used, separating 523 00:30:53,960 --> 00:30:57,760 the use of data objects, from the 524 00:30:57,760 --> 00:30:59,350 representation of data objects. 525 00:30:59,350 --> 00:31:07,650 526 00:31:07,650 --> 00:31:10,010 So up here, we have the way that rational numbers are 527 00:31:10,010 --> 00:31:12,620 used, do arithmetic on them. 528 00:31:12,620 --> 00:31:15,280 Down here, we have the way that they're represented, and 529 00:31:15,280 --> 00:31:17,950 they're separated by this boundary. 530 00:31:17,950 --> 00:31:19,605 The boundary is the constructors and selectors. 531 00:31:19,605 --> 00:31:23,760 532 00:31:23,760 --> 00:31:25,920 And this methodology has a name. 533 00:31:25,920 --> 00:31:27,170 This is called data abstraction. 534 00:31:27,170 --> 00:31:35,820 535 00:31:35,820 --> 00:31:39,030 Data abstraction is sort of the programming methodology of 536 00:31:39,030 --> 00:31:42,060 setting up data objects by postulating constructors and 537 00:31:42,060 --> 00:31:44,085 selectors to isolate use from representation. 538 00:31:44,085 --> 00:31:47,550 539 00:31:47,550 --> 00:31:49,060 Well, so why? 540 00:31:49,060 --> 00:31:51,750 I mean, after all, we didn't have to do it this way. 541 00:31:51,750 --> 00:31:55,450 It's perfectly possible to do rational number addition 542 00:31:55,450 --> 00:31:57,550 without having any compound data objects, and here on the 543 00:31:57,550 --> 00:32:00,060 slide is one example. 544 00:32:00,060 --> 00:32:04,640 We certainly could have defined +RAT, which takes in 545 00:32:04,640 --> 00:32:07,830 things x and y, and we'll say, well what are these rational 546 00:32:07,830 --> 00:32:10,030 numbers really? 547 00:32:10,030 --> 00:32:13,060 So really, they're just pairs, and the numerator's the car 548 00:32:13,060 --> 00:32:16,180 and the denominator's the cdr. So what we'll do is we'll take 549 00:32:16,180 --> 00:32:23,310 the car of x times the cdr of y, multiply them. 550 00:32:23,310 --> 00:32:26,470 Take the car of y times the cdr of x, multiply them. 551 00:32:26,470 --> 00:32:28,650 Add them. 552 00:32:28,650 --> 00:32:31,960 Take the cdr of x and the cdr of y, multiply them, and then 553 00:32:31,960 --> 00:32:33,210 constitute together. 554 00:32:33,210 --> 00:32:35,450 555 00:32:35,450 --> 00:32:36,890 Well, that sort of does the same thing. 556 00:32:36,890 --> 00:32:41,560 557 00:32:41,560 --> 00:32:43,930 But this ignores the problem of reducing things to lowest 558 00:32:43,930 --> 00:32:47,680 terms, but let's not worry about that for a minute. 559 00:32:47,680 --> 00:32:48,200 But so what? 560 00:32:48,200 --> 00:32:50,790 Why don't we do it that way? 561 00:32:50,790 --> 00:32:50,960 Right? 562 00:32:50,960 --> 00:32:53,220 After all, there are sort of fewer procedures to define, 563 00:32:53,220 --> 00:32:54,470 and it's a lot more straightforward. 564 00:32:54,470 --> 00:32:57,210 565 00:32:57,210 --> 00:32:59,610 It saves all this self-righteous BS about 566 00:32:59,610 --> 00:33:00,850 talking about data abstraction. 567 00:33:00,850 --> 00:33:02,270 We just sort of do it. 568 00:33:02,270 --> 00:33:04,870 I mean, who knows, maybe it's even marginally more efficient 569 00:33:04,870 --> 00:33:07,930 depending on whatever compiler were using for this. 570 00:33:07,930 --> 00:33:11,500 What's the point of isolating the use from the 571 00:33:11,500 --> 00:33:13,910 representation? 572 00:33:13,910 --> 00:33:17,130 Well, it goes back to this notion of naming. 573 00:33:17,130 --> 00:33:21,020 Remember, one of the most important principles in 574 00:33:21,020 --> 00:33:23,770 programming is the same as one of the most important 575 00:33:23,770 --> 00:33:25,660 principles in sorcery, all right? 576 00:33:25,660 --> 00:33:28,210 That's if you have the name of the spirit, you get 577 00:33:28,210 --> 00:33:30,330 control over it. 578 00:33:30,330 --> 00:33:34,420 And if you go back and look at the slide, you see what's in 579 00:33:34,420 --> 00:33:38,580 there is we have this thing +RAT, but nowhere in the 580 00:33:38,580 --> 00:33:41,710 system, if I have a +RAT and a -RAT and a *RAT, and things 581 00:33:41,710 --> 00:33:44,870 that look like that, nowhere in the system do I have a 582 00:33:44,870 --> 00:33:50,770 thing that I can point at which is a rational number. 583 00:33:50,770 --> 00:33:53,550 584 00:33:53,550 --> 00:33:58,480 I don't have, in a system like that, the idea of rational 585 00:33:58,480 --> 00:34:01,340 number as a conceptual entity. 586 00:34:01,340 --> 00:34:04,270 Well, what's the advantage of that? 587 00:34:04,270 --> 00:34:07,200 What's the advantage of isolating the idea of rational 588 00:34:07,200 --> 00:34:09,400 numbers as a conceptual entity, and really naming it 589 00:34:09,400 --> 00:34:12,900 with make-RAT, numerator, and denominator. 590 00:34:12,900 --> 00:34:18,659 Well, one advantage is you might want to have alternative 591 00:34:18,659 --> 00:34:20,679 representations. 592 00:34:20,679 --> 00:34:24,889 See, before I showed you that one way George can solve this 593 00:34:24,889 --> 00:34:27,280 things not reduced to lowest terms problem, is when you 594 00:34:27,280 --> 00:34:30,260 build a rational number, you divide up by the greatest 595 00:34:30,260 --> 00:34:31,190 common denominator. 596 00:34:31,190 --> 00:34:36,650 Another way to do that is shown over here. 597 00:34:36,650 --> 00:34:38,810 I can have an alternative representation for rational 598 00:34:38,810 --> 00:34:40,980 numbers where when you make a rational number, 599 00:34:40,980 --> 00:34:43,409 you just cons them. 600 00:34:43,409 --> 00:34:46,610 However, when you go to select out the numerator, at that 601 00:34:46,610 --> 00:34:50,929 point you compute the gcd of the stuff that's sitting in 602 00:34:50,929 --> 00:34:53,440 that pair, and divide out by the gcd. 603 00:34:53,440 --> 00:34:57,970 604 00:34:57,970 --> 00:35:02,300 And similarly, when I get the denominator, at that point 605 00:35:02,300 --> 00:35:03,990 when I go to get the denominator, I'll divide out 606 00:35:03,990 --> 00:35:05,420 by the gcd. 607 00:35:05,420 --> 00:35:09,090 So the difference would be in the old representation, when 608 00:35:09,090 --> 00:35:13,680 ans was constructed here, say what's 6 and 8, in the first 609 00:35:13,680 --> 00:35:16,260 way, the 6 and 8 would have got reduced when they got 610 00:35:16,260 --> 00:35:20,380 stuck into that pair, numerator would select out 3. 611 00:35:20,380 --> 00:35:23,850 And in the way I just showed you, well, ans would get 6 and 612 00:35:23,850 --> 00:35:27,650 8 put in, and then at the point where I said numerator, 613 00:35:27,650 --> 00:35:29,770 some computation would get done to put out 614 00:35:29,770 --> 00:35:32,590 3 instead of 6. 615 00:35:32,590 --> 00:35:34,520 So those are two different ways I might do it. 616 00:35:34,520 --> 00:35:37,530 Which one's better? 617 00:35:37,530 --> 00:35:38,460 Well, it depends, right? 618 00:35:38,460 --> 00:35:41,230 If I'm making a system where I am mostly constructing 619 00:35:41,230 --> 00:35:43,240 rational numbers and hardly ever looking at them, then 620 00:35:43,240 --> 00:35:46,520 it's probably better not to do that gcd computation when I 621 00:35:46,520 --> 00:35:47,776 construct them. 622 00:35:47,776 --> 00:35:51,070 If I'm doing a system where I look at things a lot more than 623 00:35:51,070 --> 00:35:54,470 I construct them, then it's probably better to do the work 624 00:35:54,470 --> 00:35:57,240 when I construct them. 625 00:35:57,240 --> 00:35:58,170 So there's a choice there. 626 00:35:58,170 --> 00:36:04,840 But the real issue is that you might not be able to decide at 627 00:36:04,840 --> 00:36:07,640 the moment you're worrying about these rational numbers. 628 00:36:07,640 --> 00:36:14,470 See, in general, as systems designers, you're forced with 629 00:36:14,470 --> 00:36:16,350 the necessity to make decisions about how you're 630 00:36:16,350 --> 00:36:19,640 going to do things, and in general, the way you'd like to 631 00:36:19,640 --> 00:36:22,720 retain flexibility is to never make up your mind about 632 00:36:22,720 --> 00:36:26,890 anything until you're forced to do it. 633 00:36:26,890 --> 00:36:31,730 The problem is, there's a very, very narrow line between 634 00:36:31,730 --> 00:36:34,765 deferring decisions and outright procrastination. 635 00:36:34,765 --> 00:36:38,760 636 00:36:38,760 --> 00:36:43,860 So you'd like to make progress, but also at the same 637 00:36:43,860 --> 00:36:45,020 time, never be bound by the 638 00:36:45,020 --> 00:36:48,620 consequences of your decisions. 639 00:36:48,620 --> 00:36:50,550 Data abstraction's one way of doing this. 640 00:36:50,550 --> 00:36:54,540 What we did is we used wishful thinking. 641 00:36:54,540 --> 00:36:57,190 See, we gave a name to the decision. 642 00:36:57,190 --> 00:37:01,340 We said, make-RAT, numerator, and denominator will stand for 643 00:37:01,340 --> 00:37:03,040 however it's going to be done, and however it's going to be 644 00:37:03,040 --> 00:37:04,080 done is George's problem. 645 00:37:04,080 --> 00:37:07,100 But really, what that was doing is giving a name to the 646 00:37:07,100 --> 00:37:12,030 decision of how we're going to do it, and then continuing as 647 00:37:12,030 --> 00:37:14,400 if we made the decision. 648 00:37:14,400 --> 00:37:17,110 And then eventually, when we really wanted it to work, 649 00:37:17,110 --> 00:37:20,330 coming back and facing what we really had to do. 650 00:37:20,330 --> 00:37:23,080 And in fact, we'll see a couple times from now that you 651 00:37:23,080 --> 00:37:25,440 may never have to choose any particular representation, 652 00:37:25,440 --> 00:37:27,800 ever, ever. 653 00:37:27,800 --> 00:37:30,230 Anyway, that's a very powerful design technique. 654 00:37:30,230 --> 00:37:32,295 It's the key to the reason people use data abstraction. 655 00:37:32,295 --> 00:37:34,830 656 00:37:34,830 --> 00:37:37,854 And we're going to see that idea again and again. 657 00:37:37,854 --> 00:37:40,510 Let's stop for questions. 658 00:37:40,510 --> 00:37:43,810 AUDIENCE: What does this decision making through 659 00:37:43,810 --> 00:37:47,500 abstraction layers do to the axiom of do all your design 660 00:37:47,500 --> 00:37:49,800 before any of your code? 661 00:37:49,800 --> 00:37:52,700 PROFESSOR: Well, that's someone's axiom, and I bet 662 00:37:52,700 --> 00:37:54,990 that's the axiom of someone who hasn't implemented very 663 00:37:54,990 --> 00:37:56,600 large computer systems very much. 664 00:37:56,600 --> 00:38:01,220 665 00:38:01,220 --> 00:38:04,116 I said that computer science is a lot like magic, and it's 666 00:38:04,116 --> 00:38:05,270 sort of good that it's like magic. 667 00:38:05,270 --> 00:38:06,690 There's a bad part of computer science 668 00:38:06,690 --> 00:38:08,746 that's a lot like religion. 669 00:38:08,746 --> 00:38:13,570 And in general, I think people who really believe that you 670 00:38:13,570 --> 00:38:16,800 design everything before you implement it basically are 671 00:38:16,800 --> 00:38:18,440 people who haven't designed very many things. 672 00:38:18,440 --> 00:38:21,230 673 00:38:21,230 --> 00:38:24,660 The real power is that you can pretend that you've made the 674 00:38:24,660 --> 00:38:28,640 decision and then later on figure out which one is right, 675 00:38:28,640 --> 00:38:30,550 which decision you ought to have made. 676 00:38:30,550 --> 00:38:32,870 And when you can do that, you have the best of both worlds. 677 00:38:32,870 --> 00:38:35,834 678 00:38:35,834 --> 00:38:37,330 AUDIENCE: Can you explain the difference 679 00:38:37,330 --> 00:38:40,180 between let and define? 680 00:38:40,180 --> 00:38:43,520 PROFESSOR: Oh, OK. 681 00:38:43,520 --> 00:38:49,040 Let is a way to establish local names. 682 00:38:49,040 --> 00:38:55,150 683 00:38:55,150 --> 00:38:57,430 Let me give you sort of the half answer. 684 00:38:57,430 --> 00:39:00,970 And I'll say, later on we can talk about the whole very 685 00:39:00,970 --> 00:39:02,960 complicated thing. 686 00:39:02,960 --> 00:39:06,000 But the big difference for now is that, see, when you're 687 00:39:06,000 --> 00:39:10,020 typing at Lisp, you're typing in this environment where 688 00:39:10,020 --> 00:39:12,020 you're making definitions. 689 00:39:12,020 --> 00:39:18,990 And when you say define a to be 5, if I say define a to be 690 00:39:18,990 --> 00:39:25,640 5, then from then on the thing will remember that a is 5. 691 00:39:25,640 --> 00:39:29,460 Let is a way to set up a local context where there's a 692 00:39:29,460 --> 00:39:31,090 definition. 693 00:39:31,090 --> 00:39:37,695 So if I type something like, saying let a-- no, I 694 00:39:37,695 --> 00:39:40,642 shouldn't say a-- 695 00:39:40,642 --> 00:39:50,480 if I said let z be 10, and within that context, tell me 696 00:39:50,480 --> 00:39:54,280 what the sum of z and z is. 697 00:39:54,280 --> 00:39:59,780 So if I typed in this expression to Lisp, and then 698 00:39:59,780 --> 00:40:02,210 this would put out 20. 699 00:40:02,210 --> 00:40:07,340 However, then if I said what's z, the computer would say 700 00:40:07,340 --> 00:40:10,910 that's an unbound variable. 701 00:40:10,910 --> 00:40:13,710 So let is a way of setting up a context where you can make 702 00:40:13,710 --> 00:40:16,320 definitions. 703 00:40:16,320 --> 00:40:19,320 But those definitions are local to this context. 704 00:40:19,320 --> 00:40:27,990 And of course, if I'd said a in here, I'd still get 20. 705 00:40:27,990 --> 00:40:33,960 But this a would not interfere at all with this one. 706 00:40:33,960 --> 00:40:36,210 So if I type this, and then type this, and then say what's 707 00:40:36,210 --> 00:40:39,160 a? a will still be 5. 708 00:40:39,160 --> 00:40:42,220 So there's some other subtle differences between let and 709 00:40:42,220 --> 00:40:44,543 define, but that's the most important one. 710 00:40:44,543 --> 00:41:20,090 711 00:41:20,090 --> 00:41:22,980 All right, well, we've looked at implementing this little 712 00:41:22,980 --> 00:41:27,470 system for doing arithmetic on rational numbers as an example 713 00:41:27,470 --> 00:41:31,096 of this methodology of data abstraction. 714 00:41:31,096 --> 00:41:34,430 And that's a way of controlling complexity in 715 00:41:34,430 --> 00:41:39,530 large systems. But, see, like procedure definition, and like 716 00:41:39,530 --> 00:41:41,420 all the ways we're going to talk about for controlling 717 00:41:41,420 --> 00:41:45,660 complexity, the real power of these things show up not when 718 00:41:45,660 --> 00:41:49,370 you sort of do these things in themselves, like it's not such 719 00:41:49,370 --> 00:41:52,430 a great thing that we've done rational number arithmetic, 720 00:41:52,430 --> 00:41:57,150 it's that you can use these as building blocks for making 721 00:41:57,150 --> 00:42:00,620 more complicated things. 722 00:42:00,620 --> 00:42:03,460 So it's no wonderful idea that you can just put two numbers 723 00:42:03,460 --> 00:42:04,265 together to form a pair. 724 00:42:04,265 --> 00:42:06,890 If that's all you ever wanted to do, there are tons of ways 725 00:42:06,890 --> 00:42:08,450 that you can do that. 726 00:42:08,450 --> 00:42:11,910 The real issue is can you do that in such a way so that the 727 00:42:11,910 --> 00:42:14,420 things that you build become building blocks for doing 728 00:42:14,420 --> 00:42:16,945 something even more complex? 729 00:42:16,945 --> 00:42:19,120 So whenever someone shows you a method for controlling 730 00:42:19,120 --> 00:42:21,080 complexity, you should say, yeah, that's great, but what 731 00:42:21,080 --> 00:42:22,330 can I build with it? 732 00:42:22,330 --> 00:42:25,290 733 00:42:25,290 --> 00:42:30,490 So for example, let me just run through another thing 734 00:42:30,490 --> 00:42:32,090 that's a lot like the rational number one. 735 00:42:32,090 --> 00:42:35,760 Suppose we would like to represent points in the plane. 736 00:42:35,760 --> 00:42:38,130 You sort of say, well, there's a point, and we're going to 737 00:42:38,130 --> 00:42:40,810 call that point p. 738 00:42:40,810 --> 00:42:48,810 And that point might have coordinates, like this might 739 00:42:48,810 --> 00:42:50,330 be the point 1 comma 2. 740 00:42:50,330 --> 00:42:52,500 The x-coordinate might be 1, and it's 741 00:42:52,500 --> 00:42:54,370 y-coordinate might be 2. 742 00:42:54,370 --> 00:42:57,310 And we'll make a little system for manipulating 743 00:42:57,310 --> 00:43:00,450 points in the plane. 744 00:43:00,450 --> 00:43:03,040 And again, we can do that-- here's a 745 00:43:03,040 --> 00:43:04,290 little example of that. 746 00:43:04,290 --> 00:43:07,070 747 00:43:07,070 --> 00:43:10,080 It can represent vectors, the same as points in the plane, 748 00:43:10,080 --> 00:43:17,550 and we'll say, yep, there's a constructor called 749 00:43:17,550 --> 00:43:21,100 make-vector, make-vector's going to take two coordinates, 750 00:43:21,100 --> 00:43:24,280 and here we can implement them if we like as pairs, but the 751 00:43:24,280 --> 00:43:27,120 important thing is that there's a constructor. 752 00:43:27,120 --> 00:43:31,890 And then given some vector, p, we can find its x-coordinate, 753 00:43:31,890 --> 00:43:33,540 or we can get its y-coordinate. 754 00:43:33,540 --> 00:43:36,270 So there's a constructor and selectors for 755 00:43:36,270 --> 00:43:39,010 points in the plane. 756 00:43:39,010 --> 00:43:41,310 Well, given points in the plane, we might want to use 757 00:43:41,310 --> 00:43:42,420 them to build something. 758 00:43:42,420 --> 00:43:45,730 So for instance, we might want to talk about, we might have a 759 00:43:45,730 --> 00:43:51,220 point, p, and a point, q, and p might be the point 1, 2, and 760 00:43:51,220 --> 00:43:54,790 q might be the point 2, 3. 761 00:43:54,790 --> 00:43:58,970 And we might want to talk about the line segment that 762 00:43:58,970 --> 00:44:01,570 starts at p and ends at q. 763 00:44:01,570 --> 00:44:05,180 And that might be the segment s. 764 00:44:05,180 --> 00:44:12,300 So we might want to build points for vectors in terms of 765 00:44:12,300 --> 00:44:16,410 numbers, and segments in terms of vectors. 766 00:44:16,410 --> 00:44:18,240 So we can represent line segments in 767 00:44:18,240 --> 00:44:19,920 exactly the same way. 768 00:44:19,920 --> 00:44:22,300 All right, so the line segment from p to q, we'll say there's 769 00:44:22,300 --> 00:44:23,640 a constructor, make-segment. 770 00:44:23,640 --> 00:44:27,010 771 00:44:27,010 --> 00:44:30,270 And make up names for the selectors, the starting point 772 00:44:30,270 --> 00:44:32,560 of the segment and the ending point of the segment. 773 00:44:32,560 --> 00:44:35,290 And again, we can implement a segment using cons as a pair 774 00:44:35,290 --> 00:44:39,610 of points, and car and cdr get out the two points that we put 775 00:44:39,610 --> 00:44:40,860 together to get the segment. 776 00:44:40,860 --> 00:44:44,820 777 00:44:44,820 --> 00:44:48,520 Well, now having done that, we can have some 778 00:44:48,520 --> 00:44:51,920 operations on them. 779 00:44:51,920 --> 00:44:57,610 Like we could say, what's the midpoint of a line segment? 780 00:44:57,610 --> 00:45:00,540 So here's the midpoint of a line segment, that's going to 781 00:45:00,540 --> 00:45:05,880 be the points whose coordinates are the averages 782 00:45:05,880 --> 00:45:07,310 of the coordinates of the endpoints. 783 00:45:07,310 --> 00:45:10,170 OK, there's the midpoint. 784 00:45:10,170 --> 00:45:14,290 So to get the midpoint of a line segment, s, we'll just 785 00:45:14,290 --> 00:45:18,240 say grab the starting point to the segment, grab the ending 786 00:45:18,240 --> 00:45:21,640 point of the segment, and now make a vector-- 787 00:45:21,640 --> 00:45:26,480 make a point whose coordinates are the average of the 788 00:45:26,480 --> 00:45:28,510 x-coordinate of the first point and the x-coordinate of 789 00:45:28,510 --> 00:45:31,930 the second point, and whose y-coordinate is the average of 790 00:45:31,930 --> 00:45:33,530 the y-coordinates. 791 00:45:33,530 --> 00:45:37,810 So there's an implementation of midpoint. 792 00:45:37,810 --> 00:45:42,400 And then similarly, we can build something like the 793 00:45:42,400 --> 00:45:44,450 length of the segment. 794 00:45:44,450 --> 00:45:47,070 The length of the segment is a thing whose-- 795 00:45:47,070 --> 00:45:50,410 796 00:45:50,410 --> 00:45:53,000 use Pythagoras's rule, the length of the segment is the 797 00:45:53,000 --> 00:45:57,100 square root of the d x squared plus d y squared. 798 00:45:57,100 --> 00:46:02,200 We'll say to get the length of a line segment, we'll let dx 799 00:46:02,200 --> 00:46:09,030 be the difference of the x-coordinate of one endpoint 800 00:46:09,030 --> 00:46:12,180 and the x-coordinate of the other endpoint, and we'll let 801 00:46:12,180 --> 00:46:16,260 dy be the difference of the y-coordinates. 802 00:46:16,260 --> 00:46:19,290 And then we'll take the square root of the sum of the squares 803 00:46:19,290 --> 00:46:22,251 of dx and dy, that's what this says. 804 00:46:22,251 --> 00:46:26,190 All right, so there's an implementation of length. 805 00:46:26,190 --> 00:46:35,760 And again, what we built is a layered system. 806 00:46:35,760 --> 00:46:39,730 We built a system which has, well, say up 807 00:46:39,730 --> 00:46:40,980 here there's segments. 808 00:46:40,980 --> 00:46:47,430 809 00:46:47,430 --> 00:46:50,530 And then there's an abstraction barrier. 810 00:46:50,530 --> 00:46:56,880 The abstraction barrier separates the implementation 811 00:46:56,880 --> 00:46:59,000 of segments from the implementation of vectors and 812 00:46:59,000 --> 00:47:02,950 points, and what that abstraction barrier is are the 813 00:47:02,950 --> 00:47:04,260 constructors and selectors. 814 00:47:04,260 --> 00:47:14,340 It's make-segment, and segment-start, and 815 00:47:14,340 --> 00:47:15,590 segment-end. 816 00:47:15,590 --> 00:47:18,030 817 00:47:18,030 --> 00:47:20,120 And then there are vectors. 818 00:47:20,120 --> 00:47:25,600 And vectors in turn are built on top of pairs and numbers. 819 00:47:25,600 --> 00:47:29,670 So I'll say pairs and numbers. 820 00:47:29,670 --> 00:47:33,250 And that has its own abstraction barrier, which is 821 00:47:33,250 --> 00:47:42,350 make-vector, and x-coordinate, and y-coordinate. 822 00:47:42,350 --> 00:47:46,920 823 00:47:46,920 --> 00:47:48,930 So we have, again, a layered system. 824 00:47:48,930 --> 00:47:52,080 You're starting to see that there are layers here. 825 00:47:52,080 --> 00:47:58,080 I ought to mention, there is a very important thing that I 826 00:47:58,080 --> 00:47:59,330 kind of took for granted. 827 00:47:59,330 --> 00:48:02,016 828 00:48:02,016 --> 00:48:06,700 And it's sort of so natural, but on the other hand it's a 829 00:48:06,700 --> 00:48:07,580 very important thing. 830 00:48:07,580 --> 00:48:12,070 Notice that in order to represent this segment s, I 831 00:48:12,070 --> 00:48:16,600 said this segment is a pair of points. 832 00:48:16,600 --> 00:48:19,120 And a point is a pair of numbers. 833 00:48:19,120 --> 00:48:22,180 And if I were going to draw the box and pointers structure 834 00:48:22,180 --> 00:48:27,180 for that, I would say, oh, the segment is, given those 835 00:48:27,180 --> 00:48:29,900 particular representations that I showed you, I'd say 836 00:48:29,900 --> 00:48:38,070 this segment s is a pair, and the first thing in the pair is 837 00:48:38,070 --> 00:48:45,430 a vector, and the vector is a pair of numbers. 838 00:48:45,430 --> 00:48:47,000 And that's this, that's p. 839 00:48:47,000 --> 00:48:50,190 840 00:48:50,190 --> 00:48:55,330 And the other thing in the segment is q, which is itself 841 00:48:55,330 --> 00:49:00,100 a pair of numbers. 842 00:49:00,100 --> 00:49:04,070 So I almost took it for granted when I said that cons 843 00:49:04,070 --> 00:49:08,960 allows you to put things together. 844 00:49:08,960 --> 00:49:13,110 But it's very easy to not appreciate that, because 845 00:49:13,110 --> 00:49:17,650 notice, some of the things I can put together can 846 00:49:17,650 --> 00:49:20,720 themselves be pairs. 847 00:49:20,720 --> 00:49:23,510 And let me introduce a word that I'll talk about more next 848 00:49:23,510 --> 00:49:26,915 time, it's one of my favorite words, called closure. 849 00:49:26,915 --> 00:49:30,640 850 00:49:30,640 --> 00:49:35,180 And by closure I mean that the means of combination in your 851 00:49:35,180 --> 00:49:39,390 system are such that when you put things together using 852 00:49:39,390 --> 00:49:43,430 them, like we make a pair, you can then put those together 853 00:49:43,430 --> 00:49:45,080 with the same means of combination. 854 00:49:45,080 --> 00:49:48,120 So I can have not only a pair of numbers, but I can have a 855 00:49:48,120 --> 00:49:49,370 pair of pairs. 856 00:49:49,370 --> 00:49:51,710 857 00:49:51,710 --> 00:49:58,070 So for instance, making arrays in a language like Fortran is 858 00:49:58,070 --> 00:50:00,120 not a closed means of combination, because I can 859 00:50:00,120 --> 00:50:02,200 make an array of numbers, but I can't 860 00:50:02,200 --> 00:50:03,450 make an array of arrays. 861 00:50:03,450 --> 00:50:05,790 862 00:50:05,790 --> 00:50:09,060 And one of the things that you should ask, one of your tests 863 00:50:09,060 --> 00:50:12,430 of quality for a means of combination that someone shows 864 00:50:12,430 --> 00:50:16,500 you, is gee, are the things you make closed under that 865 00:50:16,500 --> 00:50:18,340 means of combination? 866 00:50:18,340 --> 00:50:21,290 So pairs would not be nearly so interesting if all I could 867 00:50:21,290 --> 00:50:23,160 do was make a pair of numbers. 868 00:50:23,160 --> 00:50:26,820 I couldn't build very much structure at all. 869 00:50:26,820 --> 00:50:28,170 OK, well, we'll come back to that. 870 00:50:28,170 --> 00:50:29,300 I just wanted to mention it now. 871 00:50:29,300 --> 00:50:32,170 You'll hear a lot about closure later on. 872 00:50:32,170 --> 00:50:38,520 You can also see the potential for losing control of 873 00:50:38,520 --> 00:50:41,310 complexity as you have a layered system if you don't 874 00:50:41,310 --> 00:50:44,030 use data abstraction. 875 00:50:44,030 --> 00:50:48,130 Let's go back and look at this slide for length. 876 00:50:48,130 --> 00:50:53,190 Length works and is a simple thing because I can say, when 877 00:50:53,190 --> 00:50:56,450 I want to get this value, I can say, oh, that is the 878 00:50:56,450 --> 00:51:00,430 x-coordinate of the first endpoint of the segment. 879 00:51:00,430 --> 00:51:02,990 880 00:51:02,990 --> 00:51:04,850 And each of these things, each of these selectors, 881 00:51:04,850 --> 00:51:09,190 x-coordinate and endpoint, stand for a decision choice 882 00:51:09,190 --> 00:51:12,260 whose details I don't have to look at. 883 00:51:12,260 --> 00:51:15,070 So I could perfectly well, again, just like rational 884 00:51:15,070 --> 00:51:17,910 numbers I did before, I could say, oh well, gee, a segment 885 00:51:17,910 --> 00:51:21,180 really is a pair of pairs. 886 00:51:21,180 --> 00:51:24,810 And the x-coordinate of the first endpoint or the segment 887 00:51:24,810 --> 00:51:26,770 really is the-- 888 00:51:26,770 --> 00:51:27,330 well, what is it? 889 00:51:27,330 --> 00:51:33,890 It's the car of the car of the segment. 890 00:51:33,890 --> 00:51:37,500 So I could perfectly well go and redefine length. 891 00:51:37,500 --> 00:51:48,614 I could say, define the length of some segment s. 892 00:51:48,614 --> 00:51:51,050 And I could start off writing something like, well, we'll 893 00:51:51,050 --> 00:51:56,260 let dx be-- well, what's it have to be? 894 00:51:56,260 --> 00:51:58,380 It's got to be the difference of the two coordinates, so 895 00:51:58,380 --> 00:52:04,310 that's the difference of, the first one is the car of the 896 00:52:04,310 --> 00:52:13,070 car of s, subtracted from the first one, the car of the 897 00:52:13,070 --> 00:52:16,140 other half of it, the cdr of s. 898 00:52:16,140 --> 00:52:21,530 899 00:52:21,530 --> 00:52:24,430 All right, and then dy would be-- 900 00:52:24,430 --> 00:52:27,780 well, let's see, I'd get the y-coordinate, so it'd be the 901 00:52:27,780 --> 00:52:36,890 difference of the cdr of the car of s, and the cdr of the 902 00:52:36,890 --> 00:52:41,385 cdr of s, sort of go on. 903 00:52:41,385 --> 00:52:44,210 904 00:52:44,210 --> 00:52:46,980 You can see that's much harder to read than the 905 00:52:46,980 --> 00:52:48,270 program I had before. 906 00:52:48,270 --> 00:52:52,075 But worse than that, suppose you'd gone 907 00:52:52,075 --> 00:52:53,325 and implemented length? 908 00:52:53,325 --> 00:52:56,930 909 00:52:56,930 --> 00:52:59,150 And then the next day, George comes to you and says, I'm 910 00:52:59,150 --> 00:53:01,030 sorry, I changed my mind. 911 00:53:01,030 --> 00:53:05,390 I want to write points with the x-coordinate first. So you 912 00:53:05,390 --> 00:53:06,940 come back you stare at this code and say, oh 913 00:53:06,940 --> 00:53:07,750 gee, what was that? 914 00:53:07,750 --> 00:53:15,510 That was the car, so I have to change this to cdr, and this 915 00:53:15,510 --> 00:53:20,770 is cdr, and this now has to be car. 916 00:53:20,770 --> 00:53:23,900 And this has to be car. 917 00:53:23,900 --> 00:53:26,050 And you sort of do that, and then the next day George comes 918 00:53:26,050 --> 00:53:31,600 back and says, sorry, the guys designing the display would 919 00:53:31,600 --> 00:53:35,740 like lines to be painted in the opposite direction, so I 920 00:53:35,740 --> 00:53:37,630 have to write the endpoint first in the order. 921 00:53:37,630 --> 00:53:39,386 And then you come back and you stare at this code, and say, 922 00:53:39,386 --> 00:53:42,400 gee, what was it talking about? 923 00:53:42,400 --> 00:53:45,520 Oh yeah, well I've got to change this one to cdr, and 924 00:53:45,520 --> 00:53:50,500 this one becomes car, this one comes car, and this becomes 925 00:53:50,500 --> 00:53:50,620 cdr. 926 00:53:50,620 --> 00:53:53,340 And you go up and do that, and then the next day, George 927 00:53:53,340 --> 00:53:55,270 comes back and says, I'm sorry, what I really meant is 928 00:53:55,270 --> 00:53:58,150 that the segments always have to be painted from left to 929 00:53:58,150 --> 00:53:59,660 right on the screen. 930 00:53:59,660 --> 00:54:01,800 And then you sort of, it's clear, you just go and punch 931 00:54:01,800 --> 00:54:03,610 George in the mouth at that point. 932 00:54:03,610 --> 00:54:09,410 But you see, as soon as we have a 10 layer system, you 933 00:54:09,410 --> 00:54:12,050 see how that complexity immediately builds up to the 934 00:54:12,050 --> 00:54:16,250 point where even something like this gets out of control. 935 00:54:16,250 --> 00:54:20,470 So again, the way we've gotten out of that is we've named 936 00:54:20,470 --> 00:54:21,150 that spirit. 937 00:54:21,150 --> 00:54:26,560 We built a system where there is a thing, which is the 938 00:54:26,560 --> 00:54:29,510 representation choice for how you're going 939 00:54:29,510 --> 00:54:31,570 to talk about vectors. 940 00:54:31,570 --> 00:54:34,430 And choices about that representation are localized 941 00:54:34,430 --> 00:54:35,670 right there. 942 00:54:35,670 --> 00:54:37,840 They don't have their guts spilling over into things like 943 00:54:37,840 --> 00:54:40,926 how you compute the length and how you compute the midpoint. 944 00:54:40,926 --> 00:54:45,660 And that's the real power of this system. 945 00:54:45,660 --> 00:54:48,890 OK, we're explicit about them, so that we have 946 00:54:48,890 --> 00:54:50,916 control over them. 947 00:54:50,916 --> 00:54:52,190 All right, questions? 948 00:54:52,190 --> 00:54:54,685 AUDIENCE: What happens in the case where you don't want to 949 00:54:54,685 --> 00:54:56,660 be treating objects in terms of pairs? 950 00:54:56,660 --> 00:55:00,590 For instance, in three-dimensional space, you'd 951 00:55:00,590 --> 00:55:01,680 have three coordinates. 952 00:55:01,680 --> 00:55:02,740 Or even in the case where you have 953 00:55:02,740 --> 00:55:04,180 n-dimensional space, what happens? 954 00:55:04,180 --> 00:55:05,140 PROFESSOR: Right, OK. 955 00:55:05,140 --> 00:55:08,374 Well, this is a preview of what I'll say tomorrow. 956 00:55:08,374 --> 00:55:15,020 But the point is, once you have two things, you have as 957 00:55:15,020 --> 00:55:16,972 many things as you want. 958 00:55:16,972 --> 00:55:17,370 All right? 959 00:55:17,370 --> 00:55:19,970 Because if I want to make three things, I could start 960 00:55:19,970 --> 00:55:26,970 making things like a pair whose first thing is 1, and 961 00:55:26,970 --> 00:55:31,780 whose second thing is another pair that, say, 962 00:55:31,780 --> 00:55:34,582 has 2 and 3 in it. 963 00:55:34,582 --> 00:55:35,760 And so on, a hundred things. 964 00:55:35,760 --> 00:55:37,550 I can nest them out of pairs. 965 00:55:37,550 --> 00:55:40,370 I made a pretty arbitrary decision about how to do it, 966 00:55:40,370 --> 00:55:41,770 and you can immediately see there are lots 967 00:55:41,770 --> 00:55:42,730 of ways to do that. 968 00:55:42,730 --> 00:55:45,210 What we'll start talking about next time are conventions for 969 00:55:45,210 --> 00:55:47,660 how to do things like that. 970 00:55:47,660 --> 00:55:49,730 But notice that what this really depends on is I can 971 00:55:49,730 --> 00:55:51,950 make pairs of pairs. 972 00:55:51,950 --> 00:55:53,380 If all I could do was make pairs of 973 00:55:53,380 --> 00:55:54,630 numbers, I'd be stuck. 974 00:55:54,630 --> 00:56:07,140 975 00:56:07,140 --> 00:56:09,236 OK. 976 00:56:09,236 --> 00:56:11,960 Let's break. 977 00:56:11,960 --> 00:56:55,580 [MUSIC PLAYING] 978 00:56:55,580 --> 00:57:00,210 All right, well, we've just gone off and done a couple of 979 00:57:00,210 --> 00:57:03,575 simple examples of data abstraction. 980 00:57:03,575 --> 00:57:05,695 Now I want to do something more complicated. 981 00:57:05,695 --> 00:57:08,310 We're going to talk about what it means. 982 00:57:08,310 --> 00:57:11,590 And this will be harder, because it's always much 983 00:57:11,590 --> 00:57:14,450 harder in computer programming to talk about what something 984 00:57:14,450 --> 00:57:16,450 means than to go off and do it. 985 00:57:16,450 --> 00:57:22,070 But let's go back to almost the very beginning. 986 00:57:22,070 --> 00:57:27,050 Let's go back to the point where I said, we just assumed 987 00:57:27,050 --> 00:57:32,370 that there were procedures, make-RAT, 988 00:57:32,370 --> 00:57:38,480 and numer, and denom. 989 00:57:38,480 --> 00:57:41,570 Let's go back to where we had this, at the very beginning, 990 00:57:41,570 --> 00:57:46,210 constructors and selectors, and when often defined the 991 00:57:46,210 --> 00:57:47,210 rational number arithmetic. 992 00:57:47,210 --> 00:57:49,700 And remember, I said at that point we were sort of done, 993 00:57:49,700 --> 00:57:51,990 except for George. 994 00:57:51,990 --> 00:57:55,920 Well, what is it that we'd actually done at that point? 995 00:57:55,920 --> 00:57:59,420 What was it that was done? 996 00:57:59,420 --> 00:58:03,540 Well, what I want to say is, what was done after we'd 997 00:58:03,540 --> 00:58:06,540 implemented the operations and terms of these, was that we 998 00:58:06,540 --> 00:58:11,100 had defined a rational number representation in terms of 999 00:58:11,100 --> 00:58:12,390 abstract data. 1000 00:58:12,390 --> 00:58:17,946 1001 00:58:17,946 --> 00:58:21,090 What do I mean by abstract data? 1002 00:58:21,090 --> 00:58:26,630 Well, the idea is that at that point, when we had our +RAT 1003 00:58:26,630 --> 00:58:32,115 and our *RAT, that any implementation of make-RAT, 1004 00:58:32,115 --> 00:58:38,000 and numerator, and denominator that George supplied us with, 1005 00:58:38,000 --> 00:58:39,520 could be the basis for a rational number 1006 00:58:39,520 --> 00:58:40,990 representation. 1007 00:58:40,990 --> 00:58:44,550 Like, it wasn't our concern where you divided through to 1008 00:58:44,550 --> 00:58:48,980 get the greatest common denominator, or any of that. 1009 00:58:48,980 --> 00:58:53,830 So the idea is that what we built is a rational arithmetic 1010 00:58:53,830 --> 00:58:57,140 system that would sit on top of any representation. 1011 00:58:57,140 --> 00:58:59,930 What do I mean by any representation? 1012 00:58:59,930 --> 00:59:02,950 I mean, certainly it can't be the case that all I mean is 1013 00:59:02,950 --> 00:59:05,130 George can reach in a bag and pull out three arbitrary 1014 00:59:05,130 --> 00:59:10,380 procedures and say, well, fine, now that's the 1015 00:59:10,380 --> 00:59:11,960 implementation. 1016 00:59:11,960 --> 00:59:14,080 That can't be what I mean. 1017 00:59:14,080 --> 00:59:18,990 What I've got to mean is that there's some way of saying 1018 00:59:18,990 --> 00:59:23,950 whether three procedures are going to be suitable as a 1019 00:59:23,950 --> 00:59:26,690 basis for rational number representation. 1020 00:59:26,690 --> 00:59:30,750 If we think about it, what suitable might mean is if I 1021 00:59:30,750 --> 00:59:36,220 have to assume something like this, I have to say that if x 1022 00:59:36,220 --> 00:59:54,130 is the result of say, doing make-RAT of n and d, then the 1023 00:59:54,130 --> 01:00:06,400 numerator of x divided by the denominator of x is 1024 01:00:06,400 --> 01:00:09,680 equal to n over d. 1025 01:00:09,680 --> 01:00:13,770 See, what that is is that's George's contract. 1026 01:00:13,770 --> 01:00:16,520 What we mean by writing a contract for rational numbers, 1027 01:00:16,520 --> 01:00:18,790 if you think about it, this is the right thing. 1028 01:00:18,790 --> 01:00:21,510 And the two ones we showed do the right thing. 1029 01:00:21,510 --> 01:00:25,720 See, if I'm taking out greatest common divisors, it 1030 01:00:25,720 --> 01:00:28,350 doesn't matter whether I take them out or not, or the place 1031 01:00:28,350 --> 01:00:29,830 where I take them, because the idea is I'm 1032 01:00:29,830 --> 01:00:32,380 going to divide through. 1033 01:00:32,380 --> 01:00:33,930 But see, this is George's contract. 1034 01:00:33,930 --> 01:00:37,160 So what we really say to George is your business is to 1035 01:00:37,160 --> 01:00:41,703 go off and find us three procedures, make-RAT, and 1036 01:00:41,703 --> 01:00:45,810 numerator, and denominator, that fulfill this contract for 1037 01:00:45,810 --> 01:00:46,870 any choice of n and d. 1038 01:00:46,870 --> 01:00:51,080 And that's what we mean by we can use that as the basis for 1039 01:00:51,080 --> 01:00:54,540 a rational number representation. 1040 01:00:54,540 --> 01:00:57,130 And other than that, it fulfills this contract. 1041 01:00:57,130 --> 01:00:59,292 We don't care how he does it. 1042 01:00:59,292 --> 01:01:00,410 It's not our business. 1043 01:01:00,410 --> 01:01:02,330 It's below the layer of abstraction. 1044 01:01:02,330 --> 01:01:07,010 1045 01:01:07,010 --> 01:01:09,980 In fact, if we want to say, what is a 1046 01:01:09,980 --> 01:01:13,860 rational number really? 1047 01:01:13,860 --> 01:01:16,240 See, what's it really, without having to talk about going 1048 01:01:16,240 --> 01:01:18,240 below the layer of abstraction, what we're forced 1049 01:01:18,240 --> 01:01:24,820 into saying is a rational number really is sort of this 1050 01:01:24,820 --> 01:01:28,830 axiom, is three procedures, make-RAT, numerator, and 1051 01:01:28,830 --> 01:01:32,370 denominator, that satisfy this axiom. 1052 01:01:32,370 --> 01:01:34,790 In some sense, abstractly, that's what a 1053 01:01:34,790 --> 01:01:37,080 rational number is really. 1054 01:01:37,080 --> 01:01:41,490 1055 01:01:41,490 --> 01:01:44,860 That's sort of easy words to listen to, because what you 1056 01:01:44,860 --> 01:01:47,190 have in your head, of course, is well, for all this thing 1057 01:01:47,190 --> 01:01:50,850 about saying that's what a rational number is really, you 1058 01:01:50,850 --> 01:01:52,950 actually just saw that we built rational numbers. 1059 01:01:52,950 --> 01:01:58,830 1060 01:01:58,830 --> 01:02:00,230 See, what we really did is we built rational 1061 01:02:00,230 --> 01:02:04,230 numbers on top of pairs. 1062 01:02:04,230 --> 01:02:08,680 1063 01:02:08,680 --> 01:02:11,170 So for all I'm saying abstractly, we can say a 1064 01:02:11,170 --> 01:02:15,450 rational number really is just this axiom. 1065 01:02:15,450 --> 01:02:17,370 You can listen to that comfortably, because you're 1066 01:02:17,370 --> 01:02:20,510 saying, well, yeah, but really it's actually pairs, and I'm 1067 01:02:20,510 --> 01:02:24,820 just annoying you by trying to be abstract. 1068 01:02:24,820 --> 01:02:29,960 Well, let me, as an antidote for that, let me do something 1069 01:02:29,960 --> 01:02:32,636 that I think is really going to terrify you. 1070 01:02:32,636 --> 01:02:36,920 I mean, it's really going to bring you face to face with 1071 01:02:36,920 --> 01:02:40,090 the sort of existential reality of this abstraction 1072 01:02:40,090 --> 01:02:41,490 that we're talking about. 1073 01:02:41,490 --> 01:02:43,250 And what I'm going to talk about is, 1074 01:02:43,250 --> 01:02:45,960 what are pairs really? 1075 01:02:45,960 --> 01:02:48,710 See, what did I tell you about pairs? 1076 01:02:48,710 --> 01:02:49,420 I tricked you, right? 1077 01:02:49,420 --> 01:02:52,115 I said that Lisp has this primitive called cons that 1078 01:02:52,115 --> 01:02:53,520 builds pairs. 1079 01:02:53,520 --> 01:02:56,470 But what did I really tell you about? 1080 01:02:56,470 --> 01:03:00,060 If you go back and said, let's look on this slide, all I 1081 01:03:00,060 --> 01:03:04,090 really told you about pairs is that there happens to be this 1082 01:03:04,090 --> 01:03:07,220 property, these properties of cons, car, and cdr. And all I 1083 01:03:07,220 --> 01:03:09,840 really said about pairs is that there's a thing called 1084 01:03:09,840 --> 01:03:14,870 cons, and a thing called car, and a thing called cdr. 1085 01:03:14,870 --> 01:03:18,080 And it is the case that if I build cons of x, y and take 1086 01:03:18,080 --> 01:03:20,710 car of it, I get x. 1087 01:03:20,710 --> 01:03:25,810 And if I build cons of x, y and get cdr of it, I get y. 1088 01:03:25,810 --> 01:03:31,670 And even though I lulled you into thinking that there's 1089 01:03:31,670 --> 01:03:33,890 something in Lisp that does that, so you pretended you 1090 01:03:33,890 --> 01:03:36,590 knew what it was, in fact, I didn't tell you any more about 1091 01:03:36,590 --> 01:03:39,750 pairs than this tells you about rational numbers. 1092 01:03:39,750 --> 01:03:41,050 It's just some axiom for pairs. 1093 01:03:41,050 --> 01:03:44,720 1094 01:03:44,720 --> 01:03:51,880 Well, to drive that home, let me really scare you, and show 1095 01:03:51,880 --> 01:03:56,120 you what we might build pairs in terms of. 1096 01:03:56,120 --> 01:04:00,470 And what you're going to see is that we can build rational 1097 01:04:00,470 --> 01:04:02,960 numbers, and line segments, and vectors, and all of this 1098 01:04:02,960 --> 01:04:06,160 stuff in terms of pairs, and we're going to see below here 1099 01:04:06,160 --> 01:04:10,680 that pairs can be built out of nothing at all. 1100 01:04:10,680 --> 01:04:12,680 Pure abstraction. 1101 01:04:12,680 --> 01:04:17,800 So let me show you on this slide an implementation of 1102 01:04:17,800 --> 01:04:23,080 cons, car, and cdr. And we'll look at it again in a second, 1103 01:04:23,080 --> 01:04:26,480 but notice that their procedure definitions of cons, 1104 01:04:26,480 --> 01:04:29,850 car, and cdr, you don't see any data in there, what you 1105 01:04:29,850 --> 01:04:34,720 see is a lambda. 1106 01:04:34,720 --> 01:04:39,630 So cons here is going to return-- is a procedure that 1107 01:04:39,630 --> 01:04:44,630 returns a procedure, just like average [UNINTELLIGIBLE]. 1108 01:04:44,630 --> 01:04:49,050 Cons of a and b returns a procedure of an argument 1109 01:04:49,050 --> 01:04:55,265 called pick, and it says, if pick is equal to 1, I'm going 1110 01:04:55,265 --> 01:04:59,220 to return a, and if pick is equal to 2, I'm going to 1111 01:04:59,220 --> 01:05:02,000 return b, and that's what cons is going to be. 1112 01:05:02,000 --> 01:05:04,810 1113 01:05:04,810 --> 01:05:11,600 Car of a thing x, car of a pair x, is going to be x 1114 01:05:11,600 --> 01:05:12,320 applied to 1. 1115 01:05:12,320 --> 01:05:13,470 And notice that makes sense. 1116 01:05:13,470 --> 01:05:16,690 You might not understand why or how I'm doing such a thing, 1117 01:05:16,690 --> 01:05:19,820 but at least it makes sense, because the thing constructed 1118 01:05:19,820 --> 01:05:24,630 by cons is a procedure, and car applies that to 1. 1119 01:05:24,630 --> 01:05:29,370 And similarly, cdr applies that thing to 2. 1120 01:05:29,370 --> 01:05:33,290 OK, now I claimed that this is a representation of cons, car, 1121 01:05:33,290 --> 01:05:35,780 and cdr, and notice there's no data in it. 1122 01:05:35,780 --> 01:05:37,190 All right, it's built out of air. 1123 01:05:37,190 --> 01:05:39,600 It's just procedures. 1124 01:05:39,600 --> 01:05:43,660 There's no data objects at all in that representation. 1125 01:05:43,660 --> 01:05:45,140 Well, what could that possibly mean? 1126 01:05:45,140 --> 01:05:49,690 1127 01:05:49,690 --> 01:05:54,990 Well, if you really believe this stuff, then you have to 1128 01:05:54,990 --> 01:05:58,650 believe that in order to show that that's a representation 1129 01:05:58,650 --> 01:06:01,390 for cons, car, and cdr, all I have to do is show that it 1130 01:06:01,390 --> 01:06:03,550 satisfies the axiom. 1131 01:06:03,550 --> 01:06:06,070 See, all I should have to convince you of is, for 1132 01:06:06,070 --> 01:06:23,760 example, that gee, that car of cons of 37 and 49 is 37 for 1133 01:06:23,760 --> 01:06:28,060 arbitrary values of 37 and 49. 1134 01:06:28,060 --> 01:06:29,310 And cdr the same way. 1135 01:06:29,310 --> 01:06:32,070 1136 01:06:32,070 --> 01:06:35,050 See, if I really can demonstrate to you that that 1137 01:06:35,050 --> 01:06:38,900 weird procedure definition, in terms of [? air ?], has the 1138 01:06:38,900 --> 01:06:42,860 property that it satisfies this, then you just have to 1139 01:06:42,860 --> 01:06:46,520 grant me that that is a possible implementation of 1140 01:06:46,520 --> 01:06:50,030 cons, car, and cdr, on which I can build everything else. 1141 01:06:50,030 --> 01:06:50,980 Well, let's look at that. 1142 01:06:50,980 --> 01:06:53,820 And this will be practice in the substitution model. 1143 01:06:53,820 --> 01:06:59,320 1144 01:06:59,320 --> 01:07:00,690 How could we check this? 1145 01:07:00,690 --> 01:07:01,840 We sort of know how to do that. 1146 01:07:01,840 --> 01:07:05,920 It's just the same substitution model. 1147 01:07:05,920 --> 01:07:06,310 Let's look. 1148 01:07:06,310 --> 01:07:07,910 We start out, and we say, what's car of 1149 01:07:07,910 --> 01:07:11,120 cons of 37 and 49? 1150 01:07:11,120 --> 01:07:11,720 What do we do? 1151 01:07:11,720 --> 01:07:13,085 Cons is some procedure. 1152 01:07:13,085 --> 01:07:15,950 1153 01:07:15,950 --> 01:07:19,530 Its value is cons was a procedure of a and b. 1154 01:07:19,530 --> 01:07:25,450 The thing returned by cons is its procedure body with 37 and 1155 01:07:25,450 --> 01:07:27,370 49 substituted for the parameters. 1156 01:07:27,370 --> 01:07:32,770 It'll be 37 substituted for a and 49 substituted for b. 1157 01:07:32,770 --> 01:07:36,710 So this expression has the same meaning as this 1158 01:07:36,710 --> 01:07:37,170 expression. 1159 01:07:37,170 --> 01:07:40,410 Its car of, and the body of cons was this thing that 1160 01:07:40,410 --> 01:07:43,190 started with lambda. 1161 01:07:43,190 --> 01:07:46,730 And it says, so if pick is equal to 1, where pick is this 1162 01:07:46,730 --> 01:07:50,070 other argument, if pick is equal to 1, it's 37, that's 1163 01:07:50,070 --> 01:07:55,240 where a was, and if pick is equal to 2, it's 49. 1164 01:07:55,240 --> 01:07:56,410 So that's the first step. 1165 01:07:56,410 --> 01:07:59,460 I'm just going through mechanical substitution. 1166 01:07:59,460 --> 01:08:01,630 And remember, at this point in the course, if you're confused 1167 01:08:01,630 --> 01:08:04,190 about what things mean, go mechanically through the 1168 01:08:04,190 --> 01:08:05,480 substitution model. 1169 01:08:05,480 --> 01:08:07,920 Well, what is this reduced to? 1170 01:08:07,920 --> 01:08:15,050 Car said, take your argument, which in this case is this, 1171 01:08:15,050 --> 01:08:16,060 and apply it to 1. 1172 01:08:16,060 --> 01:08:17,979 That was the definition of car. 1173 01:08:17,979 --> 01:08:22,600 So if I look at car, if I do that, the answer is, well, 1174 01:08:22,600 --> 01:08:24,470 it's that argument, this was the argument to 1175 01:08:24,470 --> 01:08:26,319 car, applied to 1. 1176 01:08:26,319 --> 01:08:29,580 1177 01:08:29,580 --> 01:08:31,140 Well, what does that mean? 1178 01:08:31,140 --> 01:08:34,800 I take 1, and I substitute it in the body here for this 1179 01:08:34,800 --> 01:08:36,630 value of pick, which is the name of the 1180 01:08:36,630 --> 01:08:39,779 argument, what do I get? 1181 01:08:39,779 --> 01:08:43,390 Well, I get the thing that says if 1 equals 1 it's 37, 1182 01:08:43,390 --> 01:08:46,700 and if 1 equals 2 it's 49, so the answer's 37. 1183 01:08:46,700 --> 01:08:49,880 And similarly, if I'd taken cdr, that would apply it to 2, 1184 01:08:49,880 --> 01:08:51,729 and I'd get 49. 1185 01:08:51,729 --> 01:08:55,020 So you see, what I've demonstrated is that that 1186 01:08:55,020 --> 01:08:57,560 completely weird implementation of cons, car, 1187 01:08:57,560 --> 01:09:02,000 and cdr, satisfies the axioms. So it's a perfectly valid way 1188 01:09:02,000 --> 01:09:04,100 of building, in fact, all of the data objects we're going 1189 01:09:04,100 --> 01:09:05,620 to see in Lisp. 1190 01:09:05,620 --> 01:09:07,930 So they all, if you like, can be built on sort of 1191 01:09:07,930 --> 01:09:09,670 existential nothing. 1192 01:09:09,670 --> 01:09:14,229 And as far as you know, that's how it works. 1193 01:09:14,229 --> 01:09:15,149 You couldn't tell. 1194 01:09:15,149 --> 01:09:18,580 If all you're ever going to do with pairs is construct them 1195 01:09:18,580 --> 01:09:20,890 with cons and look at them with car and cdr, you couldn't 1196 01:09:20,890 --> 01:09:24,270 possibly tell how this thing works. 1197 01:09:24,270 --> 01:09:26,370 Now, it might give you a sort of warm feeling inside if I 1198 01:09:26,370 --> 01:09:29,470 say, well, yeah, in fact, for various reasons there happens 1199 01:09:29,470 --> 01:09:32,930 to be a primitive called cons, car, and cdr, and if it's too 1200 01:09:32,930 --> 01:09:35,330 scary, if this kind of stuff is too scary, you don't have 1201 01:09:35,330 --> 01:09:36,770 to look inside of it. 1202 01:09:36,770 --> 01:09:40,060 So that might make you feel better, but the point is, it 1203 01:09:40,060 --> 01:09:42,910 really could work this way, and it wouldn't make any 1204 01:09:42,910 --> 01:09:46,590 difference to the system at all. 1205 01:09:46,590 --> 01:09:48,979 So in some sense, we don't need data at all to build 1206 01:09:48,979 --> 01:09:51,760 these data abstractions. 1207 01:09:51,760 --> 01:09:54,860 We can do everything in terms of procedures. 1208 01:09:54,860 --> 01:09:57,500 OK, well, why did I terrify you in this way? 1209 01:09:57,500 --> 01:09:59,660 First, I really want to reinforce this idea of 1210 01:09:59,660 --> 01:10:03,670 abstraction, that you really can do these things 1211 01:10:03,670 --> 01:10:06,220 abstractly. 1212 01:10:06,220 --> 01:10:10,640 Secondly, I want to introduce an idea we're going to see 1213 01:10:10,640 --> 01:10:15,190 more and more of in this course, which is we're going 1214 01:10:15,190 --> 01:10:17,440 to blur the line between what's data 1215 01:10:17,440 --> 01:10:19,715 and what's a procedure. 1216 01:10:19,715 --> 01:10:22,350 See, in this funny implementation it turned out 1217 01:10:22,350 --> 01:10:26,340 that cons of something happened to be represented in 1218 01:10:26,340 --> 01:10:29,080 terms of a procedure, even though we think of it as data. 1219 01:10:29,080 --> 01:10:31,940 1220 01:10:31,940 --> 01:10:35,360 While here that's sort of a mathematical trick, but one of 1221 01:10:35,360 --> 01:10:38,050 the things we'll see is that a lot of the very important 1222 01:10:38,050 --> 01:10:42,150 programming techniques that we're going to get to sort of 1223 01:10:42,150 --> 01:10:45,840 depend very crucially on blurring this traditional line 1224 01:10:45,840 --> 01:10:47,940 between what you consider a procedure and what you 1225 01:10:47,940 --> 01:10:48,950 consider data. 1226 01:10:48,950 --> 01:10:50,060 We're going to see more and more of that, 1227 01:10:50,060 --> 01:10:52,495 especially next time. 1228 01:10:52,495 --> 01:10:55,190 OK, questions? 1229 01:10:55,190 --> 01:10:57,290 AUDIENCE: If you asked the system to print 1230 01:10:57,290 --> 01:11:00,720 a, what would happen? 1231 01:11:00,720 --> 01:11:04,570 PROFESSOR: The question is, what would happen if I asked 1232 01:11:04,570 --> 01:11:05,600 the system to print a. 1233 01:11:05,600 --> 01:11:10,200 Given this representation, you already know the answer. 1234 01:11:10,200 --> 01:11:16,360 The answer is compound procedure a, 1235 01:11:16,360 --> 01:11:18,485 just like last time. 1236 01:11:18,485 --> 01:11:21,170 1237 01:11:21,170 --> 01:11:22,590 It'd say compound procedure. 1238 01:11:22,590 --> 01:11:25,150 1239 01:11:25,150 --> 01:11:26,420 It might say a little bit more. 1240 01:11:26,420 --> 01:11:28,250 It might say compound procedure lambda or something 1241 01:11:28,250 --> 01:11:31,730 or other, depending on details of how I named it. 1242 01:11:31,730 --> 01:11:33,070 But it's a procedure. 1243 01:11:33,070 --> 01:11:35,790 And the only reason for that is I haven't told the system 1244 01:11:35,790 --> 01:11:40,220 anything special about how to print such things. 1245 01:11:40,220 --> 01:11:43,500 Now, it's in fact true that with the actual implementation 1246 01:11:43,500 --> 01:11:45,630 of cons that to be built in the system, it would print 1247 01:11:45,630 --> 01:11:46,840 something else. 1248 01:11:46,840 --> 01:11:48,890 It would print, say, this is a pair. 1249 01:11:48,890 --> 01:11:53,500 1250 01:11:53,500 --> 01:11:58,870 AUDIENCE: When you define cons, and then you pass it 1251 01:11:58,870 --> 01:12:03,840 into values, how does it know where to look for the cons, 1252 01:12:03,840 --> 01:12:07,220 because you can use cons over and over again? 1253 01:12:07,220 --> 01:12:11,442 How does it know where to look to know which a and b it's 1254 01:12:11,442 --> 01:12:13,500 supposed to pull back out? 1255 01:12:13,500 --> 01:12:17,140 I don't know if I'm expressing that quite right. 1256 01:12:17,140 --> 01:12:19,120 Where is it stored? 1257 01:12:19,120 --> 01:12:24,760 PROFESSOR: OK, the question is, I sort of have a cons with 1258 01:12:24,760 --> 01:12:27,880 a 37 and a 49, and I might make another cons with a 1 and 1259 01:12:27,880 --> 01:12:30,200 a 2, and I might have one called a, and I might 1260 01:12:30,200 --> 01:12:31,920 have one called b. 1261 01:12:31,920 --> 01:12:33,400 And the question is, how does it know? 1262 01:12:33,400 --> 01:12:35,275 And why don't they get confused? 1263 01:12:35,275 --> 01:12:37,510 And that's a very good question. 1264 01:12:37,510 --> 01:12:40,820 1265 01:12:40,820 --> 01:12:43,280 See, you have to really believe that the procedures 1266 01:12:43,280 --> 01:12:45,550 are objects. 1267 01:12:45,550 --> 01:12:46,725 It's sort of like saying-- let's try 1268 01:12:46,725 --> 01:12:49,340 another simpler example. 1269 01:12:49,340 --> 01:12:51,190 Suppose I ask for the square root of 3. 1270 01:12:51,190 --> 01:12:55,760 1271 01:12:55,760 --> 01:12:59,220 So I asked for the square root of 5, and then I ask for the 1272 01:12:59,220 --> 01:13:06,470 square of 20. 1273 01:13:06,470 --> 01:13:09,050 You're probably not the least bit bothered that I can take 1274 01:13:09,050 --> 01:13:11,470 square root and apply it to 5, and then I can take square 1275 01:13:11,470 --> 01:13:14,880 root and apply it to 20. 1276 01:13:14,880 --> 01:13:16,980 And there's sort of no issue, gee, doesn't it get confused 1277 01:13:16,980 --> 01:13:19,630 about whether it's working on 5 or 20? 1278 01:13:19,630 --> 01:13:23,120 There's no issue about that because you're thinking of a 1279 01:13:23,120 --> 01:13:26,600 procedure which goes off and does something. 1280 01:13:26,600 --> 01:13:30,410 Now, in some sense you're asking me the same question. 1281 01:13:30,410 --> 01:13:32,940 But it's really bothering you, and it's bothering you for a 1282 01:13:32,940 --> 01:13:34,140 really good reason. 1283 01:13:34,140 --> 01:13:37,150 Because when I write that, you're saying gee, this is, I 1284 01:13:37,150 --> 01:13:38,300 know, sort of a procedure. 1285 01:13:38,300 --> 01:13:40,250 But it's not a procedure that's just running. 1286 01:13:40,250 --> 01:13:42,600 It's just sort of a procedure sitting there. 1287 01:13:42,600 --> 01:13:45,570 And how can it be that sometimes this procedure has 1288 01:13:45,570 --> 01:13:49,540 37 and 49, and there might be another one which has 5 and 6 1289 01:13:49,540 --> 01:13:52,630 in there, and why don't they get confused? 1290 01:13:52,630 --> 01:13:55,910 So there's something very, very important that's 1291 01:13:55,910 --> 01:13:58,990 bothering you. 1292 01:13:58,990 --> 01:14:01,380 And it's really crucial to what's going on. 1293 01:14:01,380 --> 01:14:05,870 We're suddenly saying that procedures are not just the 1294 01:14:05,870 --> 01:14:08,290 act of doing something. 1295 01:14:08,290 --> 01:14:12,310 Procedures are conceptual entities, objects, and if I 1296 01:14:12,310 --> 01:14:16,080 built cons of 37 and 49, that's a particular procedure 1297 01:14:16,080 --> 01:14:18,070 that sits there. 1298 01:14:18,070 --> 01:14:21,490 And it's different from cons of 3 and 4. 1299 01:14:21,490 --> 01:14:23,020 That's another procedure that sits there. 1300 01:14:23,020 --> 01:14:24,060 AUDIENCE: Both of them exist independently. 1301 01:14:24,060 --> 01:14:25,610 PROFESSOR: And exists independently. 1302 01:14:25,610 --> 01:14:28,370 AUDIENCE: And they both can be referenced by car and cdr. 1303 01:14:28,370 --> 01:14:30,350 PROFESSOR: And they both would be referenced by car and cdr. 1304 01:14:30,350 --> 01:14:35,500 Just like I could increment this, and I 1305 01:14:35,500 --> 01:14:38,270 could increment that. 1306 01:14:38,270 --> 01:14:39,960 They're objects. 1307 01:14:39,960 --> 01:14:41,730 And that's sort of where we're going. 1308 01:14:41,730 --> 01:14:43,660 See, the fact that you're asking the question shows that 1309 01:14:43,660 --> 01:14:46,330 you're really starting to think about the implications 1310 01:14:46,330 --> 01:14:47,790 of what's going on. 1311 01:14:47,790 --> 01:14:50,820 It's the difference between saying a procedure is just the 1312 01:14:50,820 --> 01:14:53,070 act of doing something. 1313 01:14:53,070 --> 01:14:56,270 And a procedure is a real object that has existence. 1314 01:14:56,270 --> 01:14:58,550 AUDIENCE: So when the procedure gets built, the 1315 01:14:58,550 --> 01:15:01,930 actual values are now substituted for a and b-- 1316 01:15:01,930 --> 01:15:02,050 PROFESSOR: That's right. 1317 01:15:02,050 --> 01:15:04,870 AUDIENCE: And then that procedure exists as lambda, 1318 01:15:04,870 --> 01:15:07,720 and pick is what's actually passed in. 1319 01:15:07,720 --> 01:15:11,850 PROFESSOR: Yes, when cons gets called, and the result of cons 1320 01:15:11,850 --> 01:15:14,260 is a new procedure that's constructed, that new 1321 01:15:14,260 --> 01:15:17,440 procedure has an argument that's called pick. 1322 01:15:17,440 --> 01:15:18,830 AUDIENCE: But it no longer has an a and b. 1323 01:15:18,830 --> 01:15:20,416 The a and b are the actual values 1324 01:15:20,416 --> 01:15:20,820 that are passed through. 1325 01:15:20,820 --> 01:15:23,280 PROFESSOR: And it has-- right, according to the substitution 1326 01:15:23,280 --> 01:15:26,340 model, what it now has is not those arbitrary names a and b, 1327 01:15:26,340 --> 01:15:31,560 it somehow has that 37 and 49 in there. 1328 01:15:31,560 --> 01:15:33,520 But you're right, that's a hard thing to think about it, 1329 01:15:33,520 --> 01:15:35,150 and it's different from the way you've been thinking about 1330 01:15:35,150 --> 01:15:36,500 procedures. 1331 01:15:36,500 --> 01:15:39,285 AUDIENCE: And if I have again cons of 37 and 49, it's a 1332 01:15:39,285 --> 01:15:41,300 different [UNINTELLIGIBLE]? 1333 01:15:41,300 --> 01:15:51,790 PROFESSOR: And if you make another cons of 37 and 49, 1334 01:15:51,790 --> 01:15:54,390 you're into a wonderful philosophical problem, which 1335 01:15:54,390 --> 01:15:57,870 is going to be what the lecture about halfway through 1336 01:15:57,870 --> 01:16:00,080 this course is about. 1337 01:16:00,080 --> 01:16:03,810 Which is, if I cons 37 and 49, and I do it again, is that the 1338 01:16:03,810 --> 01:16:06,490 same thing, or is it a different thing? 1339 01:16:06,490 --> 01:16:07,680 And how could you tell? 1340 01:16:07,680 --> 01:16:10,240 And when could it possibly matter? 1341 01:16:10,240 --> 01:16:18,110 And that's sort of like saying, is that the 1342 01:16:18,110 --> 01:16:21,140 same thing as this? 1343 01:16:21,140 --> 01:16:23,850 Or is this the same thing as that? 1344 01:16:23,850 --> 01:16:25,150 It's the same kind of question. 1345 01:16:25,150 --> 01:16:27,930 And that's a very, very deep question. 1346 01:16:27,930 --> 01:16:30,180 And I can't answer in less than an hour. 1347 01:16:30,180 --> 01:16:31,770 But we will. 1348 01:16:31,770 --> 01:16:45,972 ================================================ FILE: SrtEN/lec3a_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:04,470 1 00:00:04,470 --> 00:00:21,130 [MUSIC PLAYING] 2 00:00:21,130 --> 00:00:24,770 PROFESSOR: Well, last time we talked about compound data, 3 00:00:24,770 --> 00:00:29,800 and there were two main points to that business. 4 00:00:29,800 --> 00:00:31,640 First of all, there was a methodology of data 5 00:00:31,640 --> 00:00:35,010 abstraction, and the point of that was that you could 6 00:00:35,010 --> 00:00:40,500 isolate the way that data objects are used from the way 7 00:00:40,500 --> 00:00:43,170 that they're represented: this idea that there's this guy, 8 00:00:43,170 --> 00:00:45,600 George, and you go out make a contract with him; and it's 9 00:00:45,600 --> 00:00:47,800 his business to represent the data objects; and at the 10 00:00:47,800 --> 00:00:49,880 moment you are using them, you don't think 11 00:00:49,880 --> 00:00:52,220 about George's problem. 12 00:00:52,220 --> 00:00:55,460 And then secondly, there was this particular way that Lisp 13 00:00:55,460 --> 00:01:00,770 has of gluing together things to form objects called pairs, 14 00:01:00,770 --> 00:01:03,870 and that's done with cons, car and cdr. And the way that 15 00:01:03,870 --> 00:01:06,480 cons, car and cdr are implemented is basically 16 00:01:06,480 --> 00:01:07,790 irrelevant. 17 00:01:07,790 --> 00:01:09,230 That's sort of George's problem of how 18 00:01:09,230 --> 00:01:10,030 to build those things. 19 00:01:10,030 --> 00:01:11,160 It could be done as primitives. 20 00:01:11,160 --> 00:01:13,780 It could be done using procedures in some weird way, 21 00:01:13,780 --> 00:01:16,210 but we're not going to worry about that. 22 00:01:16,210 --> 00:01:20,230 And as an example, we looked at rational number arithmetic. 23 00:01:20,230 --> 00:01:21,800 We looked at vectors, and here's 24 00:01:21,800 --> 00:01:24,160 just a review of vectors. 25 00:01:24,160 --> 00:01:28,355 Here's an operation that takes the sum of of two vectors, so 26 00:01:28,355 --> 00:01:32,390 we want to add this vector, v1, and this vector, v2, and 27 00:01:32,390 --> 00:01:34,680 we get the sum. 28 00:01:34,680 --> 00:01:39,120 And the sum is the vector whose coordinates are the sum 29 00:01:39,120 --> 00:01:41,380 of the coordinates of the pieces you're adding. 30 00:01:41,380 --> 00:01:45,440 So I can say, to define make-vect, right, to add two 31 00:01:45,440 --> 00:01:50,710 vectors I make a vector, whose x coordinate is the sum of the 32 00:01:50,710 --> 00:01:53,810 two x coordinates, and whose y coordinate is the sum of the 33 00:01:53,810 --> 00:01:56,760 two y coordinates. 34 00:01:56,760 --> 00:02:03,520 And then similarly, we could have an operation that scales 35 00:02:03,520 --> 00:02:09,449 vectors, so here's a procedure scale that multiplies a 36 00:02:09,449 --> 00:02:13,160 vector, v, by some number, s. 37 00:02:13,160 --> 00:02:17,270 So here's v, v goes from there to there and I scale v, and I 38 00:02:17,270 --> 00:02:21,520 get a vector in the same direction that's longer. 39 00:02:21,520 --> 00:02:23,850 And again, to scale a vector, I multiply the successive 40 00:02:23,850 --> 00:02:24,320 coordinates. 41 00:02:24,320 --> 00:02:29,090 So I make a vector, whose x coordinate is the scale factor 42 00:02:29,090 --> 00:02:31,900 times the x coordinate and whose y coordinate is the 43 00:02:31,900 --> 00:02:34,340 scale factor times the y coordinate. 44 00:02:34,340 --> 00:02:38,970 So those are two operations that are implemented using the 45 00:02:38,970 --> 00:02:40,570 representation of vectors. 46 00:02:40,570 --> 00:02:42,900 And the representation of vectors, for instance, is 47 00:02:42,900 --> 00:02:45,640 something that we can build in terms of pairs. 48 00:02:45,640 --> 00:02:48,760 So George has gone out and implemented for us make-vector 49 00:02:48,760 --> 00:02:53,960 and x coordinate and y coordinate, and this could be 50 00:02:53,960 --> 00:03:04,380 done, for instance, using cons, car and cdr; and notice 51 00:03:04,380 --> 00:03:08,320 here, I wrote this in a slightly different way. 52 00:03:08,320 --> 00:03:10,660 The procedures we've seen before, I've said something 53 00:03:10,660 --> 00:03:16,170 like say, make-vector of x and y: cons of x and y. 54 00:03:16,170 --> 00:03:18,870 And here I just wrote make-vector cons. 55 00:03:18,870 --> 00:03:20,920 And that means something slightly different. 56 00:03:20,920 --> 00:03:23,990 Previously we'd say, define make-vector to be a procedure 57 00:03:23,990 --> 00:03:26,870 that takes two arguments, x and y, and does 58 00:03:26,870 --> 00:03:28,150 cons of x and y. 59 00:03:28,150 --> 00:03:32,870 And here I am saying define make-vector to be the thing 60 00:03:32,870 --> 00:03:38,630 that cons is, and that's almost the same as the other 61 00:03:38,630 --> 00:03:39,670 way we've been writing things. 62 00:03:39,670 --> 00:03:43,510 And I just want you to get used to the idea that 63 00:03:43,510 --> 00:03:46,360 procedures can be objects, and that you can name them. 64 00:03:46,360 --> 00:03:48,960 65 00:03:48,960 --> 00:03:52,640 OK, well there's vector representation, and again, if 66 00:03:52,640 --> 00:03:54,650 that was all there was to it, this would 67 00:03:54,650 --> 00:03:56,666 all be pretty boring. 68 00:03:56,666 --> 00:04:00,290 And the point is, remember, that you can use cons to glue 69 00:04:00,290 --> 00:04:02,790 together not just numbers to form pairs, but to glue 70 00:04:02,790 --> 00:04:04,270 together arbitrary things. 71 00:04:04,270 --> 00:04:11,500 So for instance, if we'd like to represent a line segment, 72 00:04:11,500 --> 00:04:16,959 say the line segment that goes from a certain vector: say, 73 00:04:16,959 --> 00:04:27,160 the segment from the vector 2,3 to the point represented 74 00:04:27,160 --> 00:04:28,270 by the vector 5,1. 75 00:04:28,270 --> 00:04:33,770 If we want to represent that line segment, then we can 76 00:04:33,770 --> 00:04:35,785 build that as a pair of pairs. 77 00:04:35,785 --> 00:04:41,130 78 00:04:41,130 --> 00:04:42,990 So again, we can represent line segments. 79 00:04:42,990 --> 00:04:48,150 We can make a constructor that makes a segment using cons, 80 00:04:48,150 --> 00:04:50,760 selects out the start of a segment, selects out the end 81 00:04:50,760 --> 00:04:57,310 point of the segment; and then if we actually look at that, 82 00:04:57,310 --> 00:05:00,040 if we peel away the abstraction layers, and say 83 00:05:00,040 --> 00:05:05,160 what's that really is a pair of pairs, we'd say 84 00:05:05,160 --> 00:05:06,290 well that's a pair. 85 00:05:06,290 --> 00:05:07,540 Here's the segment. 86 00:05:07,540 --> 00:05:10,320 87 00:05:10,320 --> 00:05:15,030 It's car, right, it's car pointer is a pair, and it's 88 00:05:15,030 --> 00:05:21,130 cdr is also a pair, and then what the car is-- here's the 89 00:05:21,130 --> 00:05:26,110 car, that itself is a pair of 2 and 3. 90 00:05:26,110 --> 00:05:28,090 And similarly the cdr is a pair of 2 and 3. 91 00:05:28,090 --> 00:05:30,800 And let me remind you again, that a lot of people have some 92 00:05:30,800 --> 00:05:35,110 idea that if I'd taken this arrow and somehow written it 93 00:05:35,110 --> 00:05:36,870 to point down, that would mean something else. 94 00:05:36,870 --> 00:05:38,980 That's irrelevant. 95 00:05:38,980 --> 00:05:40,900 It's only how these are connected and not whether this 96 00:05:40,900 --> 00:05:43,280 arrow happens to go vertically or horizontally. 97 00:05:43,280 --> 00:05:47,770 98 00:05:47,770 --> 00:05:49,930 And again just to remind you, there was 99 00:05:49,930 --> 00:05:52,860 this notion of closure. 100 00:05:52,860 --> 00:06:02,900 See, closure was the thing that allowed us to start 101 00:06:02,900 --> 00:06:06,910 building up complexity, that didn't trap us in pairs. 102 00:06:06,910 --> 00:06:12,610 Particularly what I mean is the things that we make, 103 00:06:12,610 --> 00:06:16,970 having combined things using cons to get a pair, those 104 00:06:16,970 --> 00:06:21,330 things themselves can be combined using cons to make 105 00:06:21,330 --> 00:06:23,800 more complicated things. 106 00:06:23,800 --> 00:06:27,360 Or as a mathematician might say, the set of data objects 107 00:06:27,360 --> 00:06:34,130 in List is closed under the operation of forming pairs. 108 00:06:34,130 --> 00:06:36,360 That's the thing that allows us to build complexity. 109 00:06:36,360 --> 00:06:40,000 And that seems obvious, but remember, a lot of the things 110 00:06:40,000 --> 00:06:42,480 in the computer languages that people use are not closed. 111 00:06:42,480 --> 00:06:47,120 So for example, forming arrays in basic and Fortran is not a 112 00:06:47,120 --> 00:06:50,390 closed operation, because you can make an array of numbers 113 00:06:50,390 --> 00:06:52,690 or character strings or something, but you can't make 114 00:06:52,690 --> 00:06:54,800 an array of arrays. 115 00:06:54,800 --> 00:06:59,260 And when you look at means of combination, you should be 116 00:06:59,260 --> 00:07:01,260 should be asking yourself whether things are closed 117 00:07:01,260 --> 00:07:02,510 under that means of combination. 118 00:07:02,510 --> 00:07:05,280 119 00:07:05,280 --> 00:07:09,100 Well in any case, because we can form pairs of pairs, we 120 00:07:09,100 --> 00:07:11,980 can start using pairs to glue things together in all sorts 121 00:07:11,980 --> 00:07:14,230 of different ways. 122 00:07:14,230 --> 00:07:17,300 So for instance if I'd like to glue together the four things, 123 00:07:17,300 --> 00:07:20,880 1, 2, 3 and 4, there are a lot of ways I can do it. 124 00:07:20,880 --> 00:07:25,050 I could, for example, like we did with that line segment, I 125 00:07:25,050 --> 00:07:32,990 could make a pair that had a 1 and a 2 and 126 00:07:32,990 --> 00:07:36,900 a 3 and a 4, right? 127 00:07:36,900 --> 00:07:40,090 Or if I liked, I could do something like this. 128 00:07:40,090 --> 00:07:46,580 I could make a pair, whose first thing is a pair, whose 129 00:07:46,580 --> 00:07:53,010 car is 1, and his cdr is itself a pair that has the 2 130 00:07:53,010 --> 00:07:56,660 and the 3, and then I could put the 4 up here. 131 00:07:56,660 --> 00:07:59,420 So you see, there are a lot of different ways that I can 132 00:07:59,420 --> 00:08:02,560 start using pairs to glue things together, and so it'll 133 00:08:02,560 --> 00:08:07,540 be a good idea to establish some kind of conventions, 134 00:08:07,540 --> 00:08:10,830 right, that allow us to deal with this thing in some 135 00:08:10,830 --> 00:08:12,590 conventional way, so we're not constantly 136 00:08:12,590 --> 00:08:16,070 making an ad hoc choice. 137 00:08:16,070 --> 00:08:21,650 And List has a particular convention for representing a 138 00:08:21,650 --> 00:08:26,730 sequence of things as, essentially, a chain of pairs, 139 00:08:26,730 --> 00:08:34,581 and that's called a List. 140 00:08:34,581 --> 00:08:39,169 And what a List is is essentially just a convention 141 00:08:39,169 --> 00:08:40,929 for representing a sequence. 142 00:08:40,929 --> 00:08:45,790 I would represent the sequence 1, 2, 3 and 4 by 143 00:08:45,790 --> 00:08:48,420 a sequence of pairs. 144 00:08:48,420 --> 00:08:53,920 I'd put 1 here and then the cdr of this would point to 145 00:08:53,920 --> 00:09:01,490 another pair whose car was the next thing in the sequence, 146 00:09:01,490 --> 00:09:06,260 and the cdr would point to another pair whose car was the 147 00:09:06,260 --> 00:09:08,400 next thing in the sequence-- so there's 3-- 148 00:09:08,400 --> 00:09:09,550 and then another one. 149 00:09:09,550 --> 00:09:15,450 So for each item in the sequence, I'll get a pair. 150 00:09:15,450 --> 00:09:21,130 And now there are no more, so I put a special marker that 151 00:09:21,130 --> 00:09:28,760 means there's nothing more in the List. OK, so that's a 152 00:09:28,760 --> 00:09:31,750 conventional way to glue things together if you want to 153 00:09:31,750 --> 00:09:34,450 represent a sequence, right. 154 00:09:34,450 --> 00:09:42,570 And what it is is a bunch of pairs, the successive cars of 155 00:09:42,570 --> 00:09:46,470 each pair are the items that you want to glue together, and 156 00:09:46,470 --> 00:09:50,330 the cdr pointer points to the next pair. 157 00:09:50,330 --> 00:09:52,710 Now if I actually wanted to construct that, what I would 158 00:09:52,710 --> 00:09:57,630 type into List is this: I'd actually construct that as 159 00:09:57,630 --> 00:10:07,640 saying, well this thing is the cons of 1 onto the cons of 2 160 00:10:07,640 --> 00:10:14,390 onto the cons of 3 onto the cons of 4 onto, 161 00:10:14,390 --> 00:10:15,150 well, this thing nil. 162 00:10:15,150 --> 00:10:21,050 And what nil is is a name for the end of List marker. 163 00:10:21,050 --> 00:10:22,960 It's a special name, which means this is the end of the 164 00:10:22,960 --> 00:10:29,980 List. OK, so that's how I would actually construct that. 165 00:10:29,980 --> 00:10:37,195 166 00:10:37,195 --> 00:10:40,670 Of course, it's a terrible drag to constantly have to 167 00:10:40,670 --> 00:10:43,000 write something like the cons of 1 onto the cons of 2 onto 168 00:10:43,000 --> 00:10:45,310 the cons of 3, whenever you want to make this thing. 169 00:10:45,310 --> 00:10:54,270 So List has an operation that's called List, and List 170 00:10:54,270 --> 00:10:59,160 is just an abbreviation for this nest of conses. 171 00:10:59,160 --> 00:11:02,310 So I could say, I could construct that by saying that 172 00:11:02,310 --> 00:11:08,010 is the List of 1, 2, 3 and 4. 173 00:11:08,010 --> 00:11:11,310 And all this is is another way, a piece of syntactic 174 00:11:11,310 --> 00:11:13,550 sugar, a more convenient way for writing 175 00:11:13,550 --> 00:11:15,390 that chain of conses-- 176 00:11:15,390 --> 00:11:18,410 cons of cons of cons of cons of cons of cons onto nil. 177 00:11:18,410 --> 00:11:21,810 So for example, I could build this thing and say, I'll 178 00:11:21,810 --> 00:11:39,150 define 1-TO-4 to be the List of 1, 2, 3 and 4. 179 00:11:39,150 --> 00:11:48,070 180 00:11:48,070 --> 00:11:51,890 OK, well notice some of the consequences of using this 181 00:11:51,890 --> 00:11:54,190 convention. 182 00:11:54,190 --> 00:11:57,520 First of all if I have this List, this 1, 2, 3 and 4, the 183 00:11:57,520 --> 00:11:59,290 car of the whole thing is the first element 184 00:11:59,290 --> 00:12:04,100 in the List, right. 185 00:12:04,100 --> 00:12:05,400 How do I get 2? 186 00:12:05,400 --> 00:12:21,850 Well, 2 would be the car of the cdr of this thing 1-TO-4, 187 00:12:21,850 --> 00:12:25,160 it would be 2, right. 188 00:12:25,160 --> 00:12:30,050 I take this thing, I take the cdr of it, which is this much, 189 00:12:30,050 --> 00:12:38,760 and the car of that is 2, and then similarly, the car of the 190 00:12:38,760 --> 00:12:48,060 cdr of the cdr of 1-TO-4, cdr, cdr, car-- 191 00:12:48,060 --> 00:12:52,898 would give me 3, and so on. 192 00:12:52,898 --> 00:12:54,650 Let's take a look at that on the computer 193 00:12:54,650 --> 00:12:55,900 screen for a second. 194 00:12:55,900 --> 00:12:57,880 195 00:12:57,880 --> 00:13:07,050 I could come up to List, and I could type define 1-TO-4 to be 196 00:13:07,050 --> 00:13:14,190 the List of 1, 2, 3 and 4, right. 197 00:13:14,190 --> 00:13:19,690 And I'll tell that to List, and it says, fine, that's the 198 00:13:19,690 --> 00:13:22,540 definition of 1-TO-4. 199 00:13:22,540 --> 00:13:28,950 And I could say, for instance, what's the car of the cdr of 200 00:13:28,950 --> 00:13:38,096 the cdr of 1-TO-4, close paren, close paren. 201 00:13:38,096 --> 00:13:43,916 Right, so the car of the cdr of the cdr would be 3. 202 00:13:43,916 --> 00:13:51,660 Right, or I could say, what's 1-TO-4 itself. 203 00:13:51,660 --> 00:13:56,160 And you see what List typed out is 1, 2, 3, 4, enclosed in 204 00:13:56,160 --> 00:13:59,630 parentheses, and this notation, typing the elements 205 00:13:59,630 --> 00:14:02,930 of the List enclosed in parentheses is List's 206 00:14:02,930 --> 00:14:07,660 conventional way for printing back this chain of pairs that 207 00:14:07,660 --> 00:14:09,190 represents a sequence. 208 00:14:09,190 --> 00:14:19,520 So for example, if I said, what's the cdr of 1-TO-4, 209 00:14:19,520 --> 00:14:22,080 that's going to be the rest of the List. That's the thing 210 00:14:22,080 --> 00:14:25,410 pointed to by the first pair, which is, again, a sequence 211 00:14:25,410 --> 00:14:28,880 that starts off with 2. 212 00:14:28,880 --> 00:14:36,740 Or for example, I go off and say, what's the cdr of the cdr 213 00:14:36,740 --> 00:14:44,990 of 1-TO-4; then that's 3,4. 214 00:14:44,990 --> 00:14:58,205 Or if I say, what's the cdr of the cdr of the cdr of the cdr 215 00:14:58,205 --> 00:15:07,090 of 1-TO-4, and I'm down there looking at the end of List 216 00:15:07,090 --> 00:15:09,340 pointer itself, and List prints that as just open 217 00:15:09,340 --> 00:15:10,780 paren, close paren. 218 00:15:10,780 --> 00:15:13,805 You can think of that as a List with nothing in there. 219 00:15:13,805 --> 00:15:16,190 All right, see at the end what I did there was I looked at 220 00:15:16,190 --> 00:15:22,150 the cdr of the cdr of the cdr of 1-TO-4, and I'm just left 221 00:15:22,150 --> 00:15:24,880 with the end of List pointer itself. 222 00:15:24,880 --> 00:15:26,450 And that gets printed as open close. 223 00:15:26,450 --> 00:15:34,350 224 00:15:34,350 --> 00:15:37,660 All right, well that's a conventional way you can see 225 00:15:37,660 --> 00:15:42,080 for working down a List by taking 226 00:15:42,080 --> 00:15:43,340 successive cdrs of things. 227 00:15:43,340 --> 00:15:47,470 It's called cdring down a List. And of course it's 228 00:15:47,470 --> 00:15:49,840 pretty much of a drag to type all those cdrs by hand. 229 00:15:49,840 --> 00:15:50,570 You don't do that. 230 00:15:50,570 --> 00:15:53,220 You write procedures that do that. 231 00:15:53,220 --> 00:15:56,300 And in fact one very, very common thing to do in List is 232 00:15:56,300 --> 00:16:02,290 to write procedures that, sort of, take a List of things and 233 00:16:02,290 --> 00:16:05,630 do something to every element in List, and return you a List 234 00:16:05,630 --> 00:16:07,400 of the results. 235 00:16:07,400 --> 00:16:10,550 So what I mean for example, is I might write a procedure 236 00:16:10,550 --> 00:16:18,440 called Scale-List, and Scale-List I might say I want 237 00:16:18,440 --> 00:16:27,640 to scale by 10 the entire List 1-TO-4, and that would return 238 00:16:27,640 --> 00:16:36,513 for me the List 10, 20, 30, 40. 239 00:16:36,513 --> 00:16:38,480 [UNINTELLIGIBLE PHRASE] 240 00:16:38,480 --> 00:16:46,360 Right, it returns List, and well you can see that there's 241 00:16:46,360 --> 00:16:48,320 going to be some kind of recursive 242 00:16:48,320 --> 00:16:49,320 strategy for doing it. 243 00:16:49,320 --> 00:16:52,800 How would I actually write that procedure? 244 00:16:52,800 --> 00:16:56,760 The idea would be, well if you'd like to build up a List 245 00:16:56,760 --> 00:17:01,140 where you've multiplied every element by 10, what you'd say 246 00:17:01,140 --> 00:17:06,010 is well you imagine that you'd taken the rest of the List-- 247 00:17:06,010 --> 00:17:08,560 right, the thing represented by the cdr of the List, and 248 00:17:08,560 --> 00:17:12,869 suppose I'd already built a List where each of these was 249 00:17:12,869 --> 00:17:16,470 multiplied by 10-- 250 00:17:16,470 --> 00:17:20,784 that would be Scale-List of the cdr of the List. And then 251 00:17:20,784 --> 00:17:25,099 all I have to do is multiply the car of the List by 10, and 252 00:17:25,099 --> 00:17:28,666 then cons that onto the rest, and I'll get a List. 253 00:17:28,666 --> 00:17:31,610 Right and then similarly, to have scaled the cdr of the 254 00:17:31,610 --> 00:17:35,020 List, I'll scale the cdr of that and cons onto that 2 255 00:17:35,020 --> 00:17:36,830 multiplied by 10. 256 00:17:36,830 --> 00:17:38,690 And finally when I get all the way down to the end, and I 257 00:17:38,690 --> 00:17:41,672 only have this end of List pointer. 258 00:17:41,672 --> 00:17:43,640 All right, this thing whose name is nil-- well I just 259 00:17:43,640 --> 00:17:45,455 returned an end of List pointer. 260 00:17:45,455 --> 00:17:47,700 So there's a recursive strategy for doing that. 261 00:17:47,700 --> 00:17:51,180 Here's the actual procedure that does that. 262 00:17:51,180 --> 00:17:53,810 Right, this is an example of the general strategy of 263 00:17:53,810 --> 00:17:56,800 cdr-ing down a List and so called cons-ing 264 00:17:56,800 --> 00:17:58,310 up the result, right. 265 00:17:58,310 --> 00:18:06,090 So to Scale a List l by some scale factor s, what do I do? 266 00:18:06,090 --> 00:18:10,560 Well there's a test, and List has the predicate called null. 267 00:18:10,560 --> 00:18:14,060 Null means is this thing the end of List pointer, or 268 00:18:14,060 --> 00:18:16,700 another way to think of that is are there any elements in 269 00:18:16,700 --> 00:18:17,810 this List, right. 270 00:18:17,810 --> 00:18:20,820 But in any case if I'm looking at the end of List pointer, 271 00:18:20,820 --> 00:18:23,640 then I just return the end of List pointer. 272 00:18:23,640 --> 00:18:32,290 I just return nil, otherwise I cons together the result of 273 00:18:32,290 --> 00:18:35,850 doing what I'm going to do to the first element in the List, 274 00:18:35,850 --> 00:18:40,920 namely taking the car of l and multiplying it by s, and I 275 00:18:40,920 --> 00:18:50,240 cons that onto recursively scaling the rest of the List. 276 00:18:50,240 --> 00:18:53,730 OK, so again, the general idea is that you recursively do 277 00:18:53,730 --> 00:18:56,740 something to the rest of the List, to the cdr of the List, 278 00:18:56,740 --> 00:18:59,560 and then you cons that onto actually doing something to 279 00:18:59,560 --> 00:19:02,230 the first element of the List. When you get down to the end 280 00:19:02,230 --> 00:19:07,810 here, you return the end of List pointer, and that's a 281 00:19:07,810 --> 00:19:16,400 general pattern for doing something to a List. Well of 282 00:19:16,400 --> 00:19:19,540 course you should know by now that the very fact that 283 00:19:19,540 --> 00:19:21,190 there's a general pattern there means I shouldn't be 284 00:19:21,190 --> 00:19:23,140 writing this procedure at all. 285 00:19:23,140 --> 00:19:25,500 What I should do is write a procedure that's the general 286 00:19:25,500 --> 00:19:28,350 pattern itself that says, do something to everything in the 287 00:19:28,350 --> 00:19:30,870 List and define this thing in terms of that. 288 00:19:30,870 --> 00:19:33,050 Right, make some higher order procedure, and here's the 289 00:19:33,050 --> 00:19:34,390 higher order procedure that does that. 290 00:19:34,390 --> 00:19:40,100 It's called MAP, and what MAP does is it takes a List, takes 291 00:19:40,100 --> 00:19:45,700 a List l, and it takes a procedure p, and it returns 292 00:19:45,700 --> 00:19:49,840 the List of the elements gotten by applying p to each 293 00:19:49,840 --> 00:19:53,445 successive element in the List. All right, so p to v1, p 294 00:19:53,445 --> 00:19:56,480 to v2, p of en. 295 00:19:56,480 --> 00:19:59,670 Right, so I think of taking this List and transforming it 296 00:19:59,670 --> 00:20:02,720 by applying p to each element. 297 00:20:02,720 --> 00:20:06,200 And you see all this procedure is is exactly the general 298 00:20:06,200 --> 00:20:07,030 strategy I said. 299 00:20:07,030 --> 00:20:09,370 Instead of multiply by 10, it's do the procedure. 300 00:20:09,370 --> 00:20:13,150 If the List is empty, return nil. 301 00:20:13,150 --> 00:20:17,240 Otherwise, apply p to the first element of the List. 302 00:20:17,240 --> 00:20:21,990 Right, apply p to car of l, and cons that onto the result 303 00:20:21,990 --> 00:20:26,450 of applying p to everything in the cdr of the List, so that's 304 00:20:26,450 --> 00:20:30,110 a general procedure called MAP. 305 00:20:30,110 --> 00:20:39,590 And I could define Scale-List in terms of MAP. 306 00:20:39,590 --> 00:20:43,265 Let me show you that first. 307 00:20:43,265 --> 00:20:46,650 But I could say Scale-List is another way to define it is 308 00:20:46,650 --> 00:20:53,950 just MAP along the List by the procedure, which takes an item 309 00:20:53,950 --> 00:20:55,430 and multiplies it by s. 310 00:20:55,430 --> 00:20:58,208 311 00:20:58,208 --> 00:21:01,260 Right, so this is really the way I should think about 312 00:21:01,260 --> 00:21:04,640 scaling the List, build that actual recursion into the 313 00:21:04,640 --> 00:21:07,570 general strategy, not to every particular procedure I write. 314 00:21:07,570 --> 00:21:09,900 And of course, one of the values of doing this is that 315 00:21:09,900 --> 00:21:11,962 you start to see commonality. 316 00:21:11,962 --> 00:21:16,420 Right, again you're capturing general patterns of usage. 317 00:21:16,420 --> 00:21:22,610 For instance, if I said MAP, the square procedure, down 318 00:21:22,610 --> 00:21:32,690 this List 1-TO-4, then I'd end up with 1, 4, 9 and 16. 319 00:21:32,690 --> 00:21:42,710 Right, or if I said MAP down this List, lambda of x plus 320 00:21:42,710 --> 00:21:51,020 x10, if I MAP that down 1-TO-4, then I'd get the List 321 00:21:51,020 --> 00:21:55,020 where everything had 10 added to it: right, so I'd get 11, 322 00:21:55,020 --> 00:22:00,400 12, 13, 14. 323 00:22:00,400 --> 00:22:03,480 And you can see that's going to be a very, very common 324 00:22:03,480 --> 00:22:08,760 idea: doing something to every element in the List. 325 00:22:08,760 --> 00:22:11,240 One thing you might think about is writing MAP in an 326 00:22:11,240 --> 00:22:12,350 iterative style. 327 00:22:12,350 --> 00:22:15,460 The one I wrote happens to evolve a recursive process, 328 00:22:15,460 --> 00:22:18,050 but we could just as easily have made one that evolves an 329 00:22:18,050 --> 00:22:19,390 iterative process. 330 00:22:19,390 --> 00:22:21,610 But see the interesting thing about it is that once you 331 00:22:21,610 --> 00:22:24,270 start thinking in terms of MAP-- 332 00:22:24,270 --> 00:22:27,170 see, once you say scale is just MAP, you stop thinking 333 00:22:27,170 --> 00:22:29,200 about whether it's iterative or recursive, and you just 334 00:22:29,200 --> 00:22:32,380 say, well there's this aggregate, there's this List, 335 00:22:32,380 --> 00:22:34,490 and what I do is transform every item in the List, and I 336 00:22:34,490 --> 00:22:37,360 stop thinking about the particular control 337 00:22:37,360 --> 00:22:39,050 structure in order. 338 00:22:39,050 --> 00:22:45,190 That's a very, very important idea, and it, I guess it 339 00:22:45,190 --> 00:22:46,530 really comes out of APL. 340 00:22:46,530 --> 00:22:49,370 It's, sort of, the really important idea in APL that you 341 00:22:49,370 --> 00:22:52,020 stop thinking about control structures, and you start 342 00:22:52,020 --> 00:22:55,580 thinking about operations on aggregates, and then about 343 00:22:55,580 --> 00:22:58,330 halfway through this course, we'll see when we talk about 344 00:22:58,330 --> 00:23:00,940 something called stream processing, how that view of 345 00:23:00,940 --> 00:23:02,670 the world really comes into its glory. 346 00:23:02,670 --> 00:23:05,400 This is just us a, sort of, cute idea. 347 00:23:05,400 --> 00:23:09,520 But we'll see much more applications of that later on. 348 00:23:09,520 --> 00:23:13,560 Well let me mention that there's something that's very 349 00:23:13,560 --> 00:23:17,680 similar to MAP that's also a useful idea, and that's-- 350 00:23:17,680 --> 00:23:23,130 see, MAP says I take a List, I apply something to each item, 351 00:23:23,130 --> 00:23:26,220 and I return a List of the successive values. 352 00:23:26,220 --> 00:23:28,200 There's another thing I might do, which is very, very 353 00:23:28,200 --> 00:23:32,850 similar, which is take a List and some action you want to do 354 00:23:32,850 --> 00:23:36,470 and then do it to each item in the List in sequence. 355 00:23:36,470 --> 00:23:38,240 Don't make a List of the values, just do this 356 00:23:38,240 --> 00:23:40,810 particular action, and that's something that's 357 00:23:40,810 --> 00:23:45,040 very much like MAP. 358 00:23:45,040 --> 00:23:49,130 It's called for-each, and for-each takes a procedure and 359 00:23:49,130 --> 00:23:52,970 a List, and what it's going to do is do something to every 360 00:23:52,970 --> 00:23:56,830 item in the List. So basically what it does: it says if the 361 00:23:56,830 --> 00:24:02,250 List is not empty, right, if the List is not null, then 362 00:24:02,250 --> 00:24:05,830 what I do is, I apply my procedure to the first item in 363 00:24:05,830 --> 00:24:12,130 the List, and then I do this thing to the rest of the List. 364 00:24:12,130 --> 00:24:15,610 I apply for-each to the cdr of the List. 365 00:24:15,610 --> 00:24:17,660 All right, so I do it to the first of the List, do it to 366 00:24:17,660 --> 00:24:20,930 the rest of the List, and of course, when I call it 367 00:24:20,930 --> 00:24:22,920 recursively, that's going to do it to the rest of the rest 368 00:24:22,920 --> 00:24:24,050 of the List and so on. 369 00:24:24,050 --> 00:24:27,540 And finally, when I get done, I have to just do something to 370 00:24:27,540 --> 00:24:30,930 say I'm done, so we'll return the message "done." So that's 371 00:24:30,930 --> 00:24:32,980 very, very similar to MAP. 372 00:24:32,980 --> 00:24:35,680 It's mostly different in what it returns. 373 00:24:35,680 --> 00:24:38,920 And so for example, if I had some procedure that printed 374 00:24:38,920 --> 00:24:42,030 things on the screen, if I wanted to print everything in 375 00:24:42,030 --> 00:24:47,160 the List, I could say for-each, print this List. Or 376 00:24:47,160 --> 00:24:50,660 if I had a List of figures, and I wanted to draw them on 377 00:24:50,660 --> 00:24:53,900 the display, I could say for-each, display on the 378 00:24:53,900 --> 00:24:55,150 screen this figure. 379 00:24:55,150 --> 00:24:57,750 380 00:24:57,750 --> 00:25:00,970 Let's take questions. 381 00:25:00,970 --> 00:25:03,810 AUDIENCE: Does it create a new copy with something done to 382 00:25:03,810 --> 00:25:06,744 it, unless you explicitly tell it to do that? 383 00:25:06,744 --> 00:25:08,010 Is that correct? 384 00:25:08,010 --> 00:25:10,030 PROFESSOR: Right. 385 00:25:10,030 --> 00:25:10,980 Yeah, that's right. 386 00:25:10,980 --> 00:25:14,020 For-each does not create a List. It just 387 00:25:14,020 --> 00:25:15,350 sort of does something. 388 00:25:15,350 --> 00:25:18,180 So if you have a bunch of things you want to do and 389 00:25:18,180 --> 00:25:19,720 you're not worried about values like printing 390 00:25:19,720 --> 00:25:22,030 something, or drawing something on the screen, or 391 00:25:22,030 --> 00:25:24,610 ringing the bell on the terminal, or for something, 392 00:25:24,610 --> 00:25:26,760 you can say for-each, you know, do this for-each of 393 00:25:26,760 --> 00:25:29,770 those things in the List, whereas MAP actually builds 394 00:25:29,770 --> 00:25:31,780 you this new collection of values that you 395 00:25:31,780 --> 00:25:32,570 might want to use. 396 00:25:32,570 --> 00:25:34,380 It's just a subtle difference between them. 397 00:25:34,380 --> 00:25:37,590 AUDIENCE: Could you write MAP using for-each, so that you 398 00:25:37,590 --> 00:25:39,640 did some sort of cons or something to build 399 00:25:39,640 --> 00:25:41,520 the List back up? 400 00:25:41,520 --> 00:25:42,510 PROFESSOR: Well, sort of. 401 00:25:42,510 --> 00:25:44,570 I mean, I probably could. 402 00:25:44,570 --> 00:25:48,810 I can't think of how to do it right offhand, but yeah, I 403 00:25:48,810 --> 00:25:51,380 could arrange something. 404 00:25:51,380 --> 00:25:52,830 AUDIENCE: The vital difference between MAP and for-each is 405 00:25:52,830 --> 00:25:57,320 one is recursive and the other is not in the sense you 406 00:25:57,320 --> 00:26:01,570 defined early yesterday, I believe. 407 00:26:01,570 --> 00:26:03,660 PROFESSOR: Yeah, about MAP and for-each and recursion. 408 00:26:03,660 --> 00:26:05,390 Yeah, that's a good point. 409 00:26:05,390 --> 00:26:09,420 410 00:26:09,420 --> 00:26:11,615 For the MAP procedure I wrote, that happens to 411 00:26:11,615 --> 00:26:13,880 be a recursive process. 412 00:26:13,880 --> 00:26:16,130 And the reason for that is that when you've done this 413 00:26:16,130 --> 00:26:19,000 thing to the rest of the List, you're waiting for that value 414 00:26:19,000 --> 00:26:21,830 so that you can stick it on to the beginning of the List, 415 00:26:21,830 --> 00:26:23,340 whereas for-each doesn't really have any 416 00:26:23,340 --> 00:26:24,740 values to wait for. 417 00:26:24,740 --> 00:26:26,680 So that turns out to be an iterative process. 418 00:26:26,680 --> 00:26:27,590 That's not fundamental. 419 00:26:27,590 --> 00:26:30,920 I could have defined MAP so that it's evolved by an 420 00:26:30,920 --> 00:26:31,770 iterative process. 421 00:26:31,770 --> 00:26:33,670 I just didn't happen to. 422 00:26:33,670 --> 00:26:37,780 AUDIENCE: If you were to cons for each with a List that had 423 00:26:37,780 --> 00:26:43,210 embedded Lists, I imagine it would work, right? 424 00:26:43,210 --> 00:26:47,300 It would give you the internal elements of each of those 425 00:26:47,300 --> 00:26:48,940 internal Lists? 426 00:26:48,940 --> 00:26:50,430 PROFESSOR: OK, the question is if I [UNINTELLIGIBLE] 427 00:26:50,430 --> 00:26:54,420 for each or MAP, for that matter, with a List that had 428 00:26:54,420 --> 00:26:56,406 Lists in it-- 429 00:26:56,406 --> 00:26:59,430 although we haven't really looked at that yet-- 430 00:26:59,430 --> 00:27:01,310 would that work. 431 00:27:01,310 --> 00:27:04,610 The answer is yes in the sense I mean work and no in the 432 00:27:04,610 --> 00:27:09,140 sense that you mean work, because all that-- 433 00:27:09,140 --> 00:27:16,190 see if I give you a List, where hanging off here is, you 434 00:27:16,190 --> 00:27:19,700 know, is something that's not a number, maybe another List 435 00:27:19,700 --> 00:27:22,670 or you know, another cons or something, for-each just says 436 00:27:22,670 --> 00:27:25,240 do something to each item in this List. It goes down 437 00:27:25,240 --> 00:27:26,965 successively looking at the cdrs. 438 00:27:26,965 --> 00:27:27,220 AUDIENCE: OK. 439 00:27:27,220 --> 00:27:29,140 PROFESSOR: And as far as it's concerned, the first item in 440 00:27:29,140 --> 00:27:30,830 this List is whatever is hanging off here. 441 00:27:30,830 --> 00:27:31,830 AUDIENCE: Mhm. 442 00:27:31,830 --> 00:27:33,780 PROFESSOR: That might or might not be the right thing. 443 00:27:33,780 --> 00:27:35,670 AUDIENCE: So it wouldn't go down into the-- 444 00:27:35,670 --> 00:27:37,030 PROFESSOR: Absolutely not. 445 00:27:37,030 --> 00:27:38,380 I could certainly write something else. 446 00:27:38,380 --> 00:27:40,930 There's another, what you're looking for is a common 447 00:27:40,930 --> 00:27:43,600 pattern of usage called tree recursion, where you take a 448 00:27:43,600 --> 00:27:46,523 List, and you actually go all the way down to the what's 449 00:27:46,523 --> 00:27:48,140 called the leaves of the tree. 450 00:27:48,140 --> 00:27:50,140 And you could write such a thing, but that's not for-each 451 00:27:50,140 --> 00:27:52,420 and it's not MAP. 452 00:27:52,420 --> 00:27:53,590 Remember, these things are really 453 00:27:53,590 --> 00:27:55,492 being very simple minded. 454 00:27:55,492 --> 00:27:57,390 OK, no more questions? 455 00:27:57,390 --> 00:27:58,998 All right, let's break. 456 00:27:58,998 --> 00:28:42,480 [MUSIC PLAYING] 457 00:28:42,480 --> 00:28:46,220 PROFESSOR: What I'd like to do now is spend the rest of this 458 00:28:46,220 --> 00:28:50,960 time talking about one example, and this example, I 459 00:28:50,960 --> 00:28:53,510 think, pretty much summarizes everything that we've done up 460 00:28:53,510 --> 00:28:58,050 until now: all right, and that's List structure and 461 00:28:58,050 --> 00:29:02,360 issues of abstraction, and representation and capturing 462 00:29:02,360 --> 00:29:05,620 commonality with higher order procedures, and also is going 463 00:29:05,620 --> 00:29:09,290 to introduce something we haven't really talked about a 464 00:29:09,290 --> 00:29:13,160 lot yet-- what I said is the major third theme in this 465 00:29:13,160 --> 00:29:17,190 course: meta-linguistic abstraction, which is the idea 466 00:29:17,190 --> 00:29:20,930 that one of the ways of tackling complexity in 467 00:29:20,930 --> 00:29:27,750 engineering design is to build a suitable powerful language. 468 00:29:27,750 --> 00:29:31,370 You might recall what I said was pretty much the very most 469 00:29:31,370 --> 00:29:33,620 important thing that we're going to tell you in this 470 00:29:33,620 --> 00:29:39,010 course is that when you think about a language, you think 471 00:29:39,010 --> 00:29:43,470 about it in terms of what are the primitives; what are the 472 00:29:43,470 --> 00:29:46,225 means of combination-- 473 00:29:46,225 --> 00:29:49,560 474 00:29:49,560 --> 00:29:52,310 right, what are the things that allow you to build bigger 475 00:29:52,310 --> 00:29:54,945 things; and then what are the means of abstraction. 476 00:29:54,945 --> 00:30:01,170 477 00:30:01,170 --> 00:30:05,800 How do you take those bigger things that you've built and 478 00:30:05,800 --> 00:30:09,620 put black boxes around them and use them as elements in 479 00:30:09,620 --> 00:30:12,846 making something even more complicated? 480 00:30:12,846 --> 00:30:18,170 Now the particular language I'm going to talk about is an 481 00:30:18,170 --> 00:30:21,675 example that was made up by a friend of ours 482 00:30:21,675 --> 00:30:22,925 called Peter Henderson. 483 00:30:22,925 --> 00:30:28,130 484 00:30:28,130 --> 00:30:29,800 Peter Henderson is at the University 485 00:30:29,800 --> 00:30:32,870 of Stirling in Scotland. 486 00:30:32,870 --> 00:30:39,170 And what this language is about is making figures that 487 00:30:39,170 --> 00:30:42,090 sort of look like this. 488 00:30:42,090 --> 00:30:49,470 This is this is a woodcut by Escher called "Square Limit." 489 00:30:49,470 --> 00:30:52,860 You, sort of, see it has this complicated, kind of, 490 00:30:52,860 --> 00:30:59,170 recursive, sort of, recursive kind of figure, where there's 491 00:30:59,170 --> 00:31:02,060 this fish pattern in the middle and things sort of 492 00:31:02,060 --> 00:31:04,570 bleed out smaller and smaller in self similar ways. 493 00:31:04,570 --> 00:31:08,610 494 00:31:08,610 --> 00:31:11,450 Anyway, Peter Henderson's language was for describing 495 00:31:11,450 --> 00:31:15,990 figures that look like that and designing new ones that 496 00:31:15,990 --> 00:31:20,240 look like that and drawing them on a display screen. 497 00:31:20,240 --> 00:31:26,930 There's another theme that we'll see illustrated by this 498 00:31:26,930 --> 00:31:31,030 example, and that's the issue of what Gerry and I have 499 00:31:31,030 --> 00:31:34,300 already mentioned a lot: that there's no real difference, in 500 00:31:34,300 --> 00:31:37,340 some sense, between procedures and data. 501 00:31:37,340 --> 00:31:41,820 And anyway I hope by the end of this morning, if you're not 502 00:31:41,820 --> 00:31:45,470 already, you will be completely confused about what 503 00:31:45,470 --> 00:31:47,715 the difference between procedures and data are, if 504 00:31:47,715 --> 00:31:51,190 you're not confused about that already. 505 00:31:51,190 --> 00:31:55,370 Well in any case, let's start describing Peter's language. 506 00:31:55,370 --> 00:31:58,410 I should start by telling you what the primitives are. 507 00:31:58,410 --> 00:31:59,690 This language is very simple because 508 00:31:59,690 --> 00:32:00,940 there's only one primitive. 509 00:32:00,940 --> 00:32:03,380 510 00:32:03,380 --> 00:32:07,480 A primitive is not quite what you think it is. 511 00:32:07,480 --> 00:32:09,970 There's only one primitive called a picture, and a 512 00:32:09,970 --> 00:32:12,200 picture is not quite what you think it is. 513 00:32:12,200 --> 00:32:13,950 Here's an example. 514 00:32:13,950 --> 00:32:15,220 This is a picture of George. 515 00:32:15,220 --> 00:32:18,980 516 00:32:18,980 --> 00:32:23,990 The idea is that a picture in this language is going to be 517 00:32:23,990 --> 00:32:30,640 something that draws a figure scaled to fit a rectangle that 518 00:32:30,640 --> 00:32:33,030 you specify. 519 00:32:33,030 --> 00:32:34,200 So here you see in [? Saint ?] 520 00:32:34,200 --> 00:32:34,570 [? Lawrence's ?] 521 00:32:34,570 --> 00:32:37,070 outline of a rectangle, that's not really part of the 522 00:32:37,070 --> 00:32:43,210 picture, but the picture-- 523 00:32:43,210 --> 00:32:45,270 you'll give it a rectangle, and it will draw this figure 524 00:32:45,270 --> 00:32:47,100 scaled to fit the rectangle. 525 00:32:47,100 --> 00:32:50,930 So for example, there's George, and here, 526 00:32:50,930 --> 00:32:52,840 this is also George. 527 00:32:52,840 --> 00:32:55,480 It's the same picture, right, just scaled to 528 00:32:55,480 --> 00:32:57,920 fit a different rectangle. 529 00:32:57,920 --> 00:32:59,290 Here's George as a fat kid. 530 00:32:59,290 --> 00:33:02,400 531 00:33:02,400 --> 00:33:03,920 That's the same George. 532 00:33:03,920 --> 00:33:05,260 It's all the same figure. 533 00:33:05,260 --> 00:33:07,810 All of these three things are the same 534 00:33:07,810 --> 00:33:09,670 picture in this language. 535 00:33:09,670 --> 00:33:12,900 I'm just giving it different rectangles to scale itself in. 536 00:33:12,900 --> 00:33:16,300 537 00:33:16,300 --> 00:33:19,150 OK, those are the primitives. 538 00:33:19,150 --> 00:33:21,420 That is the primitive. 539 00:33:21,420 --> 00:33:24,440 Now let's start talking about the means of combination and 540 00:33:24,440 --> 00:33:25,960 the operations. 541 00:33:25,960 --> 00:33:31,080 There is, for example, an operation called Rotate. 542 00:33:31,080 --> 00:33:35,900 And what Rotate does is, if I have a picture, say a picture 543 00:33:35,900 --> 00:33:42,080 that draws an "A" in some rectangle that I give it, the 544 00:33:42,080 --> 00:33:43,080 Rotate of that-- 545 00:33:43,080 --> 00:33:47,490 say the Rotate by 90 degrees would, if I give it a 546 00:33:47,490 --> 00:33:52,850 rectangle, draw the same image, but again, scaled to 547 00:33:52,850 --> 00:33:54,100 fit that rectangle. 548 00:33:54,100 --> 00:33:56,160 549 00:33:56,160 --> 00:33:58,400 So that's Rotate by 90 degrees. 550 00:33:58,400 --> 00:34:00,700 There's another operation called Flip that can flip 551 00:34:00,700 --> 00:34:04,351 something, either horizontally or vertically. 552 00:34:04,351 --> 00:34:06,450 All right, so those are, sort of, operations, or you can 553 00:34:06,450 --> 00:34:11,010 think of those as means of combination of one element. 554 00:34:11,010 --> 00:34:12,880 I can put things together. 555 00:34:12,880 --> 00:34:17,350 There's a means of combination called Beside, and what Beside 556 00:34:17,350 --> 00:34:24,525 does: it'll take two pictures, let's say A and B-- 557 00:34:24,525 --> 00:34:29,489 558 00:34:29,489 --> 00:34:31,230 and by picture I mean something that's going to draw 559 00:34:31,230 --> 00:34:34,159 an image in a specified rectangle-- 560 00:34:34,159 --> 00:34:38,159 and what Beside will do-- 561 00:34:38,159 --> 00:34:42,719 I have to say, Beside of A and B, the side of two pictures 562 00:34:42,719 --> 00:34:45,590 and some number, s. 563 00:34:45,590 --> 00:34:47,639 And s will be a number between zero and one. 564 00:34:47,639 --> 00:34:50,960 565 00:34:50,960 --> 00:34:52,620 And Beside will draw a picture that looks like this. 566 00:34:52,620 --> 00:34:55,100 It will take the rectangle you give it and 567 00:34:55,100 --> 00:34:56,480 scale its base by s. 568 00:34:56,480 --> 00:34:57,730 Say s is 0.5. 569 00:34:57,730 --> 00:35:00,240 570 00:35:00,240 --> 00:35:04,980 And then over here it will draw-- 571 00:35:04,980 --> 00:35:12,070 it'll put the first picture, and over here it'll put the 572 00:35:12,070 --> 00:35:14,100 second picture. 573 00:35:14,100 --> 00:35:17,250 Or for instance if I gave it a different value of s, if I 574 00:35:17,250 --> 00:35:27,390 said Beside with a 0.25, it would do the same thing, 575 00:35:27,390 --> 00:35:28,640 except the A would be much skinnier. 576 00:35:28,640 --> 00:35:32,230 577 00:35:32,230 --> 00:35:38,230 So it would draw something like that. 578 00:35:38,230 --> 00:35:41,110 So there's a means of combination Beside, and 579 00:35:41,110 --> 00:35:43,410 similarly there's an Above, which does the same thing 580 00:35:43,410 --> 00:35:45,230 except it puts them vertically instead of horizontally. 581 00:35:45,230 --> 00:35:47,990 582 00:35:47,990 --> 00:35:50,470 Well let's look at that. 583 00:35:50,470 --> 00:35:58,830 All right, there's George and his kid brother, which is, 584 00:35:58,830 --> 00:36:10,630 right, constructed by taking George and putting him Beside 585 00:36:10,630 --> 00:36:11,760 the Above-- 586 00:36:11,760 --> 00:36:13,440 taking the empty picture, and there's a thing called the 587 00:36:13,440 --> 00:36:16,650 empty picture, which does the obvious thing-- 588 00:36:16,650 --> 00:36:19,515 putting the empty picture above a copy of George, and 589 00:36:19,515 --> 00:36:21,100 then putting that whole thing Beside George. 590 00:36:21,100 --> 00:36:28,900 591 00:36:28,900 --> 00:36:38,230 Here's something called P which is, again, George Beside 592 00:36:38,230 --> 00:36:42,550 Flipping George, I think, horizontally in this case, and 593 00:36:42,550 --> 00:36:46,400 then Rotating the whole result 180 degrees and putting them 594 00:36:46,400 --> 00:36:50,510 Beside one another with the basic rectangle divided at 595 00:36:50,510 --> 00:36:59,320 0.5, right, and I can call that P. And then I can take P, 596 00:36:59,320 --> 00:37:04,100 and put it above the Flipped copy of itself, and I can call 597 00:37:04,100 --> 00:37:09,650 that Q. 598 00:37:09,650 --> 00:37:15,570 Notice how rapidly that we've built up complexity, just in, 599 00:37:15,570 --> 00:37:18,640 you know, 15 seconds, you've gotten from George to that 600 00:37:18,640 --> 00:37:22,260 thing Q. Why is that? 601 00:37:22,260 --> 00:37:26,100 How are how we able to do that so fast? 602 00:37:26,100 --> 00:37:28,670 The answer is the closure property. 603 00:37:28,670 --> 00:37:31,810 See, it's the fact that when I take a picture and put it 604 00:37:31,810 --> 00:37:35,560 Beside another picture, that's then, again, a picture that I 605 00:37:35,560 --> 00:37:39,090 can go and Rotate and Flip or put Above something else. 606 00:37:39,090 --> 00:37:41,645 Right, and when I take that element P, which is the Beside 607 00:37:41,645 --> 00:37:43,450 or the Flip or the Rotate of something, 608 00:37:43,450 --> 00:37:45,560 that's, again, a picture. 609 00:37:45,560 --> 00:37:49,420 Right, the world of pictures is closed under those means of 610 00:37:49,420 --> 00:37:50,830 combination. 611 00:37:50,830 --> 00:37:53,570 So whenever I have something, I can turn right around and 612 00:37:53,570 --> 00:37:56,480 use that as an element in something else. 613 00:37:56,480 --> 00:37:59,010 So maybe better than List and segments, that just gives you 614 00:37:59,010 --> 00:38:02,020 an image for how fast you can build up complexity, because 615 00:38:02,020 --> 00:38:03,270 operations are closed. 616 00:38:03,270 --> 00:38:07,500 617 00:38:07,500 --> 00:38:12,440 OK, well before we go on with building more things, let's 618 00:38:12,440 --> 00:38:14,345 talk about how this language is actually implemented. 619 00:38:14,345 --> 00:38:17,200 620 00:38:17,200 --> 00:38:23,270 The basic element that sits under the table here is a 621 00:38:23,270 --> 00:38:27,610 thing called a rectangle, and what a rectangle is going to 622 00:38:27,610 --> 00:38:36,900 be, it's a thing that specified by an origin that's 623 00:38:36,900 --> 00:38:38,910 going to be some vector that says where 624 00:38:38,910 --> 00:38:40,390 the rectangle starts. 625 00:38:40,390 --> 00:38:44,020 And then there's going to be some other vector that I'm 626 00:38:44,020 --> 00:38:49,020 going to call the horizontal part of the rectangle, and 627 00:38:49,020 --> 00:38:57,650 another picture called the 628 00:38:57,650 --> 00:39:00,640 vertical part of the rectangle. 629 00:39:00,640 --> 00:39:03,790 And those three pieces are the elements: where the lower 630 00:39:03,790 --> 00:39:08,200 vertex is, how you get to the next vertex over here, and how 631 00:39:08,200 --> 00:39:09,630 you get to the vertex over there. 632 00:39:09,630 --> 00:39:11,590 The three vectors specify a rectangle. 633 00:39:11,590 --> 00:39:16,080 634 00:39:16,080 --> 00:39:18,380 Now to actually build rectangles, what I'll assume 635 00:39:18,380 --> 00:39:23,380 is that we have a constructor called "make rectangle," or 636 00:39:23,380 --> 00:39:37,910 "make-rect," and selectors for horiz and vert and origin that 637 00:39:37,910 --> 00:39:39,720 get out the pieces of that rectangle. 638 00:39:39,720 --> 00:39:42,500 And well, you know a lot of ways you can do this now. 639 00:39:42,500 --> 00:39:47,190 You can do it by using pairs in some way or other standard 640 00:39:47,190 --> 00:39:47,670 List or not. 641 00:39:47,670 --> 00:39:50,130 But in any case, the implementation of these 642 00:39:50,130 --> 00:39:51,320 things, that's George's problem. 643 00:39:51,320 --> 00:39:53,300 It's just a data representation problem. 644 00:39:53,300 --> 00:39:55,500 So let's assume we have these rectangles to work with. 645 00:39:55,500 --> 00:39:58,902 646 00:39:58,902 --> 00:40:00,152 OK. 647 00:40:00,152 --> 00:40:02,310 648 00:40:02,310 --> 00:40:05,090 Now the idea of this, remember what's got to happen. 649 00:40:05,090 --> 00:40:10,250 Somehow we have to worry about taking the figure and scaling 650 00:40:10,250 --> 00:40:15,260 it to fit some rectangle that you give it, that's the basic 651 00:40:15,260 --> 00:40:18,340 thing you have to arrange, that these pictures can do. 652 00:40:18,340 --> 00:40:22,440 653 00:40:22,440 --> 00:40:23,460 How do we think about that? 654 00:40:23,460 --> 00:40:26,010 Well, one way to think about that is that any time I give 655 00:40:26,010 --> 00:40:40,050 you a rectangle, that defines, in some sense, a 656 00:40:40,050 --> 00:40:43,340 transformation from the standard 657 00:40:43,340 --> 00:40:45,685 square into that rectangle. 658 00:40:45,685 --> 00:40:46,960 Let me say what I mean. 659 00:40:46,960 --> 00:40:49,540 By the standard square, I'll mean something, which is a 660 00:40:49,540 --> 00:40:58,420 square whose coordinates are 0,0, and 1,0, and 0,1 and 1,1. 661 00:40:58,420 --> 00:41:01,830 662 00:41:01,830 --> 00:41:04,590 And there's some sort of the obvious scaling 663 00:41:04,590 --> 00:41:10,180 transformation, which maps this to that and this to that, 664 00:41:10,180 --> 00:41:11,920 and sort of, stretches everything uniformly. 665 00:41:11,920 --> 00:41:22,755 So we take a line segment like this and end up mapping it to 666 00:41:22,755 --> 00:41:31,390 a line segment like that, so some point xy goes to some 667 00:41:31,390 --> 00:41:33,000 other point up there. 668 00:41:33,000 --> 00:41:36,870 And although it's not important, with a little 669 00:41:36,870 --> 00:41:39,190 vector algebra, you could write that formula. 670 00:41:39,190 --> 00:41:43,670 The thing that xy goes to, the point that xy goes to is 671 00:41:43,670 --> 00:41:48,950 gotten by taking the origin of the rectangle and then adding 672 00:41:48,950 --> 00:41:51,280 that as a vector to-- 673 00:41:51,280 --> 00:41:54,300 well, take x, the x coordinate, which is something 674 00:41:54,300 --> 00:42:01,030 between zero and one, multiply that by the horizontal vector 675 00:42:01,030 --> 00:42:09,670 of the rectangle; and take the y coordinate, which is also 676 00:42:09,670 --> 00:42:14,460 something between zero and one and multiply that by the 677 00:42:14,460 --> 00:42:16,690 vertical vector of the rectangle. 678 00:42:16,690 --> 00:42:19,280 That's just a little linear algebra. 679 00:42:19,280 --> 00:42:22,600 Anyway, that's the formula, which is the right obvious 680 00:42:22,600 --> 00:42:26,100 transformation that takes things into the unit square, 681 00:42:26,100 --> 00:42:27,760 into the interior of that rectangle. 682 00:42:27,760 --> 00:42:31,790 683 00:42:31,790 --> 00:42:35,200 OK well, let's actually look at that as a procedure. 684 00:42:35,200 --> 00:42:39,830 So what we want is the thing which tells us that particular 685 00:42:39,830 --> 00:42:44,070 transformation that a rectangle defines. 686 00:42:44,070 --> 00:42:45,860 So here's the procedure. 687 00:42:45,860 --> 00:42:48,010 I'll call it coordinate-map. 688 00:42:48,010 --> 00:42:51,180 Coordinate-map is the thing that takes as its argument a 689 00:42:51,180 --> 00:42:57,605 rectangle and returns for you a procedure on points. 690 00:42:57,605 --> 00:43:00,690 691 00:43:00,690 --> 00:43:03,600 Right, so for each rectangle you get a way of transforming 692 00:43:03,600 --> 00:43:07,310 a point xy into that rectangle. 693 00:43:07,310 --> 00:43:08,020 And how do you get it? 694 00:43:08,020 --> 00:43:08,750 Well I just-- 695 00:43:08,750 --> 00:43:10,890 writing in List what I wrote there on the blackboard-- 696 00:43:10,890 --> 00:43:18,300 I add to the origin of the rectangle 697 00:43:18,300 --> 00:43:20,540 the result of adding-- 698 00:43:20,540 --> 00:43:26,080 I take the horizontal part of the rectangle; I scale that by 699 00:43:26,080 --> 00:43:29,880 the x coordinate of the point. 700 00:43:29,880 --> 00:43:33,750 I take the vertical vector of the rectangle. 701 00:43:33,750 --> 00:43:37,720 I scale that by the y coordinate of the point, and 702 00:43:37,720 --> 00:43:40,380 then add all those three things up. 703 00:43:40,380 --> 00:43:41,320 That's the procedure. 704 00:43:41,320 --> 00:43:44,045 That is the procedure that I'm going to apply to a point. 705 00:43:44,045 --> 00:43:46,890 706 00:43:46,890 --> 00:43:53,170 And this whole thing is generated for each rectangle. 707 00:43:53,170 --> 00:43:55,900 So any rectangle defines a coordinate MAP, which is a 708 00:43:55,900 --> 00:43:59,370 procedure on points. 709 00:43:59,370 --> 00:44:00,620 OK. 710 00:44:00,620 --> 00:44:06,720 711 00:44:06,720 --> 00:44:12,020 All right, so for example, George here, my original 712 00:44:12,020 --> 00:44:14,900 George, might have been something that I specified by 713 00:44:14,900 --> 00:44:20,970 segments in the unit square, and then for each rectangle I 714 00:44:20,970 --> 00:44:27,600 give this thing, I'm going to draw those segments inside 715 00:44:27,600 --> 00:44:28,180 that rectangle. 716 00:44:28,180 --> 00:44:30,630 How actually do I do that? 717 00:44:30,630 --> 00:44:35,820 Well I take each segment in my original reference George that 718 00:44:35,820 --> 00:44:40,080 was specified, and to each of the end points of those 719 00:44:40,080 --> 00:44:42,490 segments, I applied the coordinate MAP of the 720 00:44:42,490 --> 00:44:44,440 particular rectangle I want to draw it in. 721 00:44:44,440 --> 00:44:47,530 So for example, this lower rectangle, this George as a 722 00:44:47,530 --> 00:44:51,370 fat kid rectangle, has its coordinate MAP. 723 00:44:51,370 --> 00:44:56,310 And if I want to draw this image, what I do is for each 724 00:44:56,310 --> 00:45:01,500 segment here, say for this segment, I transformed that 725 00:45:01,500 --> 00:45:04,600 point by the coordinate MAP, transform that point by the 726 00:45:04,600 --> 00:45:04,990 coordinate MAP. 727 00:45:04,990 --> 00:45:07,890 That will give me this point and that point and draw the 728 00:45:07,890 --> 00:45:10,150 segment between them. 729 00:45:10,150 --> 00:45:12,970 Right, that's the idea. 730 00:45:12,970 --> 00:45:14,570 Right, and if I give it a different rectangle like this 731 00:45:14,570 --> 00:45:16,200 one, that's a different coordinate MAP, so I get a 732 00:45:16,200 --> 00:45:19,281 different image of those line segments. 733 00:45:19,281 --> 00:45:22,500 Well how do we actually get a picture to start with? 734 00:45:22,500 --> 00:45:25,250 I can build a picture to start with out of a List of line 735 00:45:25,250 --> 00:45:27,750 segments initially. 736 00:45:27,750 --> 00:45:31,680 Here's a procedure that builds what I'll call a primitive 737 00:45:31,680 --> 00:45:35,570 picture, meaning one I, sort of, got that didn't come out 738 00:45:35,570 --> 00:45:37,680 of Beside or Rotate or something. 739 00:45:37,680 --> 00:45:43,270 It starts with a List of line segments, and now 740 00:45:43,270 --> 00:45:44,090 it does what I said. 741 00:45:44,090 --> 00:45:45,600 What's a picture have to be? 742 00:45:45,600 --> 00:45:48,790 First of all it's a procedure that's defined on rectangles. 743 00:45:48,790 --> 00:45:52,060 744 00:45:52,060 --> 00:45:53,190 What does it do? 745 00:45:53,190 --> 00:45:54,880 It says for each-- 746 00:45:54,880 --> 00:45:57,480 this is going to be a List of line segments-- 747 00:45:57,480 --> 00:46:02,510 for each segment, for each s, which is a segment in this 748 00:46:02,510 --> 00:46:07,410 List of segments, well it draws a line. 749 00:46:07,410 --> 00:46:10,690 What line does it draw? 750 00:46:10,690 --> 00:46:16,230 It gets the start point of that segment, transforms that 751 00:46:16,230 --> 00:46:19,920 by the coordinate MAP of the rectangle. 752 00:46:19,920 --> 00:46:21,830 That's the first new point it wants to do. 753 00:46:21,830 --> 00:46:24,160 Then it takes the endpoint of the segment, transforms that 754 00:46:24,160 --> 00:46:27,310 by the coordinate MAP of the rectangle, and then draws a 755 00:46:27,310 --> 00:46:27,990 line between. 756 00:46:27,990 --> 00:46:30,180 Let's assume drawline is some primitive that's built into 757 00:46:30,180 --> 00:46:34,250 the system that actually draws a line on the display. 758 00:46:34,250 --> 00:46:35,980 All right, so it transforms the endpoints by the 759 00:46:35,980 --> 00:46:37,670 coordinate MAP of the rectangle, draws a line 760 00:46:37,670 --> 00:46:43,110 between them, does that for each s in 761 00:46:43,110 --> 00:46:46,220 this List of segments. 762 00:46:46,220 --> 00:46:49,000 And now remember again, a picture is a procedure that 763 00:46:49,000 --> 00:46:51,550 takes a rectangle as argument. 764 00:46:51,550 --> 00:46:53,610 So when you hand it a rectangle, this is what it 765 00:46:53,610 --> 00:46:57,140 does: draws those lines. 766 00:46:57,140 --> 00:46:59,690 All right, so there's-- 767 00:46:59,690 --> 00:47:01,260 how would I actually use this thing? 768 00:47:01,260 --> 00:47:03,325 Let's make it a little bit more concrete. 769 00:47:03,325 --> 00:47:05,890 770 00:47:05,890 --> 00:47:21,070 Right, I would say for instance, define R to be 771 00:47:21,070 --> 00:47:26,520 make-rectangle of some stuff, and I'd have to specify some 772 00:47:26,520 --> 00:47:30,080 vectors here using make-vector. 773 00:47:30,080 --> 00:47:45,010 And then I could say, define say, G to be make-picture, and 774 00:47:45,010 --> 00:47:47,100 then some stuff. 775 00:47:47,100 --> 00:47:51,540 And what I'd have to specify here is a List of line 776 00:47:51,540 --> 00:47:55,250 segments, right, using make segment. 777 00:47:55,250 --> 00:47:57,480 Make-segment might be made out of vectors, and vectors might 778 00:47:57,480 --> 00:47:59,610 be made out of points. 779 00:47:59,610 --> 00:48:03,970 And then if I actually wanted to see the image of G inside a 780 00:48:03,970 --> 00:48:10,280 rectangle, well a picture is a procedure that takes a 781 00:48:10,280 --> 00:48:11,940 rectangle as argument. 782 00:48:11,940 --> 00:48:18,720 So if I then called G with an input of R, that would cause 783 00:48:18,720 --> 00:48:22,520 whatever image G is worrying about to be drawn inside the 784 00:48:22,520 --> 00:48:26,722 rectangle R. Right, so that's how you'd use that. 785 00:48:26,722 --> 00:49:08,072 [MUSIC PLAYING] 786 00:49:08,072 --> 00:49:12,530 PROFESSOR: Well why is it that I say this example is nice? 787 00:49:12,530 --> 00:49:13,680 You probably don't think it's nice. 788 00:49:13,680 --> 00:49:15,540 You probably think it's more weird than nice. 789 00:49:15,540 --> 00:49:18,740 Right, representing these pictures as procedures, which 790 00:49:18,740 --> 00:49:21,430 do complicated things with rectangles. 791 00:49:21,430 --> 00:49:22,680 So why is it nice? 792 00:49:22,680 --> 00:49:25,460 793 00:49:25,460 --> 00:49:29,070 The reason it's nice is that once you've implemented the 794 00:49:29,070 --> 00:49:32,670 primitives in this way, the means of combination just fall 795 00:49:32,670 --> 00:49:36,390 out by implementing procedures. 796 00:49:36,390 --> 00:49:37,400 Let me show you what I mean. 797 00:49:37,400 --> 00:49:38,650 Suppose we want to implement Beside. 798 00:49:38,650 --> 00:49:41,980 799 00:49:41,980 --> 00:49:44,040 So I'd like to-- 800 00:49:44,040 --> 00:49:46,310 suppose I've got a picture. 801 00:49:46,310 --> 00:49:47,620 Let's call it P1. 802 00:49:47,620 --> 00:49:49,500 P1 is going to be-- and now remember what a 803 00:49:49,500 --> 00:49:50,780 picture really is. 804 00:49:50,780 --> 00:49:56,800 It's a thing that if you can hand it some rectangle, it 805 00:49:56,800 --> 00:50:00,920 will cause an image to be drawn in whatever rectangle 806 00:50:00,920 --> 00:50:03,520 you hand it. 807 00:50:03,520 --> 00:50:08,210 And suppose P2 two is some other picture, and you hand 808 00:50:08,210 --> 00:50:09,570 that a rectangle. 809 00:50:09,570 --> 00:50:11,220 And whatever rectangle you hand it, 810 00:50:11,220 --> 00:50:12,470 it draws some picture. 811 00:50:12,470 --> 00:50:14,920 812 00:50:14,920 --> 00:50:25,230 And now if I'd like to implement Beside of P1 and P2 813 00:50:25,230 --> 00:50:28,380 with a scale factor A, well what does that have to be? 814 00:50:28,380 --> 00:50:29,950 That's got to be picture. 815 00:50:29,950 --> 00:50:32,440 It's got to be a thing that you hand it a rectangle, and 816 00:50:32,440 --> 00:50:34,800 it draws something in that rectangle. 817 00:50:34,800 --> 00:50:38,350 So if hand Beside this rectangle-- 818 00:50:38,350 --> 00:50:41,206 let's hand it a rectangle. 819 00:50:41,206 --> 00:50:42,860 Well what's it going to do? 820 00:50:42,860 --> 00:50:45,900 it's going to take this rectangle and split it into 821 00:50:45,900 --> 00:50:53,470 two at a ratio of A and one minus A. And it will say, oh 822 00:50:53,470 --> 00:50:54,895 sure, now I've got two rectangles. 823 00:50:54,895 --> 00:51:02,370 824 00:51:02,370 --> 00:51:05,560 And now it goes off to P1 and says P1, well draw yourself in 825 00:51:05,560 --> 00:51:10,220 this rectangle, and goes off to P2, and says, P2, fine, 826 00:51:10,220 --> 00:51:13,490 draw yourself in this rectangle. 827 00:51:13,490 --> 00:51:15,690 The only computation it has to do is figure out what these 828 00:51:15,690 --> 00:51:17,550 rectangles are. 829 00:51:17,550 --> 00:51:21,660 Remember a rectangle is specified by an origin and a 830 00:51:21,660 --> 00:51:24,480 horizontal vector and a vertical vector, so it's got 831 00:51:24,480 --> 00:51:27,400 to figure out what these things are. 832 00:51:27,400 --> 00:51:30,740 So for this first rectangle, the origin turns out to be the 833 00:51:30,740 --> 00:51:34,370 origin of the original rectangle, and the vertical 834 00:51:34,370 --> 00:51:36,810 vector is the same as the vertical vector of the 835 00:51:36,810 --> 00:51:38,930 original rectangle. 836 00:51:38,930 --> 00:51:43,510 The horizontal vector is the horizontal vector of the 837 00:51:43,510 --> 00:51:47,740 original rectangle scaled by A. And 838 00:51:47,740 --> 00:51:49,680 that's the first rectangle. 839 00:51:49,680 --> 00:51:55,390 The second rectangle, the origin is the original origin 840 00:51:55,390 --> 00:52:01,910 plus that horizontal vector scaled by A. The horizontal 841 00:52:01,910 --> 00:52:05,060 vector of the second rectangle is the rest of the horizontal 842 00:52:05,060 --> 00:52:10,780 vector of the first one, which is 1 minus A times the 843 00:52:10,780 --> 00:52:15,660 original H, and the vertical vector is still v. But 844 00:52:15,660 --> 00:52:17,570 basically it goes and constructs these two 845 00:52:17,570 --> 00:52:19,890 rectangles, and the important point is having constructed 846 00:52:19,890 --> 00:52:22,940 the rectangles, it says OK, p1, you draw yourself in 847 00:52:22,940 --> 00:52:25,080 there, and p2, you draw yourself in there, and that's 848 00:52:25,080 --> 00:52:27,480 all Beside has to do. 849 00:52:27,480 --> 00:52:29,115 All right, let's look at that piece of code. 850 00:52:29,115 --> 00:52:34,500 851 00:52:34,500 --> 00:52:45,420 Beside of a picture and another picture with some 852 00:52:45,420 --> 00:52:51,030 scaling ratio is first of all, since it's a picture, a 853 00:52:51,030 --> 00:52:55,590 procedure that's going to take a rectangle as argument. 854 00:52:55,590 --> 00:52:57,050 What's it going to do? 855 00:52:57,050 --> 00:53:00,650 It says, p1 draw yourself in some rectangle and p2 draw 856 00:53:00,650 --> 00:53:03,190 yourself in some other rectangle. 857 00:53:03,190 --> 00:53:04,530 And now what are those rectangles? 858 00:53:04,530 --> 00:53:05,550 Well here's the computation. 859 00:53:05,550 --> 00:53:08,680 It makes a rectangle, and this is the algebra I just did on 860 00:53:08,680 --> 00:53:11,140 the board: the origin, something; the horizontal 861 00:53:11,140 --> 00:53:13,030 vector, something; and the vertical vector, something. 862 00:53:13,030 --> 00:53:17,790 And for p2, the rectangle it wants has some other origin 863 00:53:17,790 --> 00:53:19,820 and horizontal vector and vertical vector. 864 00:53:19,820 --> 00:53:23,330 But the important point is that all it's saying is, p1, 865 00:53:23,330 --> 00:53:25,990 go do your thing in one rectangle, and p2, go do your 866 00:53:25,990 --> 00:53:27,890 thing in another rectangle. 867 00:53:27,890 --> 00:53:30,920 That's all the Beside has to do. 868 00:53:30,920 --> 00:53:37,060 OK, similarly Rotate-- 869 00:53:37,060 --> 00:53:44,180 see if I have this picture A, and I want to look at say 870 00:53:44,180 --> 00:53:51,050 rotating A by 90 degrees, what that should mean is, well take 871 00:53:51,050 --> 00:53:57,010 this rectangle, which is origin and horizontal vector 872 00:53:57,010 --> 00:54:01,570 and vertical vector, and now pretend that it's really the 873 00:54:01,570 --> 00:54:05,710 rectangle that looks like this, which has an origin and 874 00:54:05,710 --> 00:54:09,690 a horizontal vector up here, and a vertical vector there, 875 00:54:09,690 --> 00:54:13,620 and now draw yourself with respect to that rectangle. 876 00:54:13,620 --> 00:54:17,120 Let me show you that as a procedure. 877 00:54:17,120 --> 00:54:21,570 All right, so we'll Rotate 90 of the picture, because again, 878 00:54:21,570 --> 00:54:24,870 a procedure for rectangle, which says, OK picture, draw 879 00:54:24,870 --> 00:54:29,190 yourself in some rectangle; and then this algebra is the 880 00:54:29,190 --> 00:54:30,580 transformation on the rectangle. 881 00:54:30,580 --> 00:54:33,370 It's the one which makes it look like the rectangle is 882 00:54:33,370 --> 00:54:35,220 sideways, the origin is someplace else and the 883 00:54:35,220 --> 00:54:37,670 vertical vector is someplace else, and the horizontal 884 00:54:37,670 --> 00:54:38,965 vector is someplace else, and vertical vector 885 00:54:38,965 --> 00:54:41,704 is someplace else. 886 00:54:41,704 --> 00:54:43,117 OK? 887 00:54:43,117 --> 00:54:44,367 OK. 888 00:54:44,367 --> 00:54:46,890 889 00:54:46,890 --> 00:54:50,810 OK, again notice, the crucial thing that's going on here is 890 00:54:50,810 --> 00:54:57,080 you're using the representation of pictures as 891 00:54:57,080 --> 00:55:01,910 procedures to automatically get the closure property, 892 00:55:01,910 --> 00:55:05,320 because what happens is, Beside just has this thing p1. 893 00:55:05,320 --> 00:55:08,430 Beside doesn't care if that's a primitive picture or it's 894 00:55:08,430 --> 00:55:11,760 line segments or if p1 is, itself, the result of doing 895 00:55:11,760 --> 00:55:12,950 Aboves or Besides or Rotates. 896 00:55:12,950 --> 00:55:17,380 All Beside has to know about, say, p1 is that if you hand p1 897 00:55:17,380 --> 00:55:21,070 a rectangle, it will cause something to be drawn. 898 00:55:21,070 --> 00:55:23,550 And above that level, Beside just doesn't-- 899 00:55:23,550 --> 00:55:27,321 it's none of its business how p1 accomplishes that drawing. 900 00:55:27,321 --> 00:55:31,140 All right, so you're using the procedural representation to 901 00:55:31,140 --> 00:55:32,390 ensure this closure. 902 00:55:32,390 --> 00:55:34,440 903 00:55:34,440 --> 00:55:35,830 OK. 904 00:55:35,830 --> 00:55:40,010 So implementing pictures as procedures makes these means 905 00:55:40,010 --> 00:55:43,090 of combination, you know, both pretty simple and also, I 906 00:55:43,090 --> 00:55:46,040 think, elegant. 907 00:55:46,040 --> 00:55:49,370 But that's not the real punchline. 908 00:55:49,370 --> 00:55:52,030 The real punchline comes when you look at the means of 909 00:55:52,030 --> 00:55:54,870 abstraction in this language. 910 00:55:54,870 --> 00:55:56,300 Because what have we done? 911 00:55:56,300 --> 00:56:02,760 We've implemented the means of combination themselves as 912 00:56:02,760 --> 00:56:04,010 procedures. 913 00:56:04,010 --> 00:56:05,950 914 00:56:05,950 --> 00:56:08,870 And what that means is that when we go to abstract in this 915 00:56:08,870 --> 00:56:14,890 language, everything that List supplies us for manipulating 916 00:56:14,890 --> 00:56:20,600 procedures is automatically available to do things in this 917 00:56:20,600 --> 00:56:22,010 picture language. 918 00:56:22,010 --> 00:56:25,520 The technical term I want to say is not only is this 919 00:56:25,520 --> 00:56:29,900 language implemented in List, obviously it is, but the 920 00:56:29,900 --> 00:56:39,890 language is nicely embedded in List. What I mean is by 921 00:56:39,890 --> 00:56:44,800 embedding the language in this way, all the power of List is 922 00:56:44,800 --> 00:56:47,680 automatically available as an extension to 923 00:56:47,680 --> 00:56:49,880 whatever you want to do. 924 00:56:49,880 --> 00:56:52,030 And what do I mean by that? 925 00:56:52,030 --> 00:56:57,410 Example: say, suppose I want to make a thing that takes 926 00:56:57,410 --> 00:57:06,090 four pictures A, B, C and D, and makes a configuration that 927 00:57:06,090 --> 00:57:07,340 looks like this. 928 00:57:07,340 --> 00:57:12,870 929 00:57:12,870 --> 00:57:14,670 Well you might call that, you know, four pictures or 930 00:57:14,670 --> 00:57:17,110 something, four-pict configuration. 931 00:57:17,110 --> 00:57:17,740 How do I do that? 932 00:57:17,740 --> 00:57:18,700 Well I can obviously do that. 933 00:57:18,700 --> 00:57:26,140 I just write a procedure that takes B above D and A above C 934 00:57:26,140 --> 00:57:28,350 and puts those things beside each other. 935 00:57:28,350 --> 00:57:31,150 So I automatically have List's ability to do procedure 936 00:57:31,150 --> 00:57:33,090 composition. 937 00:57:33,090 --> 00:57:34,960 And I didn't have to make that specifically 938 00:57:34,960 --> 00:57:35,790 in the picture language. 939 00:57:35,790 --> 00:57:38,710 It's automatic from the fact that the means of combination 940 00:57:38,710 --> 00:57:41,100 are themselves procedures. 941 00:57:41,100 --> 00:57:43,570 Or suppose I wanted to do something a little bit more 942 00:57:43,570 --> 00:57:44,200 complicated. 943 00:57:44,200 --> 00:57:46,670 I wanted to put in a parameter so that for each of these, I 944 00:57:46,670 --> 00:57:50,530 could independently specify a rotation by 90 degrees. 945 00:57:50,530 --> 00:57:53,200 That's just putting a parameter in the procedure. 946 00:57:53,200 --> 00:57:55,430 It's automatically there. 947 00:57:55,430 --> 00:57:58,470 Right, it automatically comes from the embedding. 948 00:57:58,470 --> 00:58:04,850 Or even more, suppose I wanted to, you know, use recursion. 949 00:58:04,850 --> 00:58:09,560 Let's look at a recursive means of 950 00:58:09,560 --> 00:58:10,740 combination on pictures. 951 00:58:10,740 --> 00:58:12,620 I could say define-- 952 00:58:12,620 --> 00:58:14,890 let's see if you can figure out what this one is-- suppose 953 00:58:14,890 --> 00:58:22,990 I say define what it means to right-push a picture, 954 00:58:22,990 --> 00:58:28,770 right-push a picture and some integer N and some scale 955 00:58:28,770 --> 00:58:40,000 factor A. I'll define this to say if N equals 0, then the 956 00:58:40,000 --> 00:58:42,340 answer is the picture. 957 00:58:42,340 --> 00:58:49,724 Otherwise I'm going to put-- 958 00:58:49,724 --> 00:58:59,080 oops, name change: P. Otherwise, I'm going to take P 959 00:58:59,080 --> 00:59:09,460 and put it beside the results of recursively right-pushing P 960 00:59:09,460 --> 00:59:25,660 with N minus 1 and A and use a scale factor of A. OK, so if 961 00:59:25,660 --> 00:59:31,080 N0 , it's P. Otherwise I put P with a scale factor of A-- 962 00:59:31,080 --> 00:59:33,610 I'm sorry I didn't align this right-- 963 00:59:33,610 --> 00:59:37,070 recursively beside the result of right-pushing P, N minus 1 964 00:59:37,070 --> 00:59:38,550 times with a scale factor of A. 965 00:59:38,550 --> 00:59:43,860 There's a recursive means of combination. 966 00:59:43,860 --> 00:59:44,790 What's that look like? 967 00:59:44,790 --> 00:59:46,060 Well, here's what it looks like. 968 00:59:46,060 --> 00:59:54,250 There's George right-pushed against himself twice with a 969 00:59:54,250 --> 00:59:59,520 scale factor of 0.75. 970 00:59:59,520 --> 01:00:00,020 OK. 971 01:00:00,020 --> 01:00:00,850 Where'd that come from? 972 01:00:00,850 --> 01:00:02,260 How did I get all this fancy recursion? 973 01:00:02,260 --> 01:00:02,960 And the answer is just 974 01:00:02,960 --> 01:00:05,240 automatic, absolutely automatic. 975 01:00:05,240 --> 01:00:08,370 Since these are procedures, the embedding says, well sure, 976 01:00:08,370 --> 01:00:10,440 I can define recursive procedures. 977 01:00:10,440 --> 01:00:13,830 I didn't have to arrange that. 978 01:00:13,830 --> 01:00:15,320 And of course, we can do more complicated 979 01:00:15,320 --> 01:00:16,440 things of the same sort. 980 01:00:16,440 --> 01:00:18,240 I could make something that does an up-push. 981 01:00:18,240 --> 01:00:21,740 Right, that sort of goes like this, by recursively putting 982 01:00:21,740 --> 01:00:22,670 something above. 983 01:00:22,670 --> 01:00:25,730 Or I could make something that, sort 984 01:00:25,730 --> 01:00:26,590 of, was this scheme. 985 01:00:26,590 --> 01:00:33,430 I might start out with a picture and then, sort of, 986 01:00:33,430 --> 01:00:38,250 recursively both push it aside and above, and that might put 987 01:00:38,250 --> 01:00:39,420 something there. 988 01:00:39,420 --> 01:00:42,590 And then up here I put the same recursive thing, and I 989 01:00:42,590 --> 01:00:45,220 might end up with something like this. 990 01:00:45,220 --> 01:00:49,650 Right, so there's a procedure that's a little bit more 991 01:00:49,650 --> 01:00:53,800 complicated than right-push but not much. 992 01:00:53,800 --> 01:00:56,670 I just do an Above and a Beside, 993 01:00:56,670 --> 01:00:57,920 rather than just a Beside. 994 01:00:57,920 --> 01:01:01,380 995 01:01:01,380 --> 01:01:05,780 Now if I take that and apply that with the idea of putting 996 01:01:05,780 --> 01:01:09,500 four pictures together, which I can surely do; and I go and 997 01:01:09,500 --> 01:01:16,460 I apply that to Q, which we defined before, right, what I 998 01:01:16,460 --> 01:01:22,310 end up with this is this thing, which is, sort of, the 999 01:01:22,310 --> 01:01:25,045 square limit of Q, done twice. 1000 01:01:25,045 --> 01:01:27,970 1001 01:01:27,970 --> 01:01:31,960 Right, and then we can compare that with Escher's "Square 1002 01:01:31,960 --> 01:01:35,110 Limit." And you see, it's sort of the same idea. 1003 01:01:35,110 --> 01:01:37,040 Escher's is, of course, much, much prettier. 1004 01:01:37,040 --> 01:01:43,250 If we go back and look at George, right, if we go look 1005 01:01:43,250 --> 01:01:44,340 at George here-- 1006 01:01:44,340 --> 01:01:47,970 see, I started with a fairly arbitrary design, this picture 1007 01:01:47,970 --> 01:01:51,170 of George and did things with it. 1008 01:01:51,170 --> 01:01:54,420 Right, whereas if we go look at the Escher picture, right, 1009 01:01:54,420 --> 01:01:56,200 the Escher picture is not an arbitrary design. 1010 01:01:56,200 --> 01:01:59,130 It's this very, very clever thing, so that when you take 1011 01:01:59,130 --> 01:02:03,590 this fish body and Rotate it and shrink it down, it bleeds 1012 01:02:03,590 --> 01:02:04,990 into the next one really nicely. 1013 01:02:04,990 --> 01:02:07,620 1014 01:02:07,620 --> 01:02:10,320 And of course with George, I didn't really do 1015 01:02:10,320 --> 01:02:12,140 anything like that. 1016 01:02:12,140 --> 01:02:16,300 So if we look at George, right, there's a little bit of 1017 01:02:16,300 --> 01:02:18,670 match up, but not very nice, and it's pretty arbitrary. 1018 01:02:18,670 --> 01:02:23,710 One very nice project, by the way, would be to write a 1019 01:02:23,710 --> 01:02:27,120 procedure that could take some basic figure like this George 1020 01:02:27,120 --> 01:02:30,050 thing and start moving the ends of the lines around, so 1021 01:02:30,050 --> 01:02:33,170 you got a really nice one when you went and did that "Square 1022 01:02:33,170 --> 01:02:34,720 Limit" process. 1023 01:02:34,720 --> 01:02:38,360 That'd be a really nice thing to think about. 1024 01:02:38,360 --> 01:02:39,710 Well so, we can combine things. 1025 01:02:39,710 --> 01:02:40,980 We can recursive procedures. 1026 01:02:40,980 --> 01:02:44,680 We can do all kinds of things, and that's all automatic. 1027 01:02:44,680 --> 01:02:47,050 Right, the important point, the difference between merely 1028 01:02:47,050 --> 01:02:49,370 implementing something in a language and embedding 1029 01:02:49,370 --> 01:02:51,570 something in the language, so that you don't lose the 1030 01:02:51,570 --> 01:02:53,280 original power of the language, and what List is 1031 01:02:53,280 --> 01:02:56,680 great at, see List is a lousy language for doing any 1032 01:02:56,680 --> 01:02:57,600 particular problem. 1033 01:02:57,600 --> 01:03:00,260 What it's good for is figuring out the right language that 1034 01:03:00,260 --> 01:03:04,000 you want and embedding that in List. That's the real power of 1035 01:03:04,000 --> 01:03:05,980 this approach to design. 1036 01:03:05,980 --> 01:03:06,880 Of course, we can go further. 1037 01:03:06,880 --> 01:03:10,970 See, you saw the other thing that we can do in List is 1038 01:03:10,970 --> 01:03:16,800 capture general methods of doing things as higher order 1039 01:03:16,800 --> 01:03:19,090 procedures. 1040 01:03:19,090 --> 01:03:21,800 And you probably just from me drawing it got the idea that 1041 01:03:21,800 --> 01:03:25,600 right-push and the analogous thing where you push something 1042 01:03:25,600 --> 01:03:31,570 up and up and up and up and this corner push thing are all 1043 01:03:31,570 --> 01:03:34,690 generalizations of a common kind of idea. 1044 01:03:34,690 --> 01:03:38,210 So just to illustrate and give you practice in looking at a 1045 01:03:38,210 --> 01:03:41,340 fairly convoluted use of higher order procedures, let 1046 01:03:41,340 --> 01:03:45,280 me show you the general idea of pushing some means of 1047 01:03:45,280 --> 01:03:48,510 combination to recursively repeat it. 1048 01:03:48,510 --> 01:03:51,240 So here's a good one to puzzle out. 1049 01:03:51,240 --> 01:03:59,550 We'll define it what it means to push using a means of 1050 01:03:59,550 --> 01:04:01,800 combination. 1051 01:04:01,800 --> 01:04:05,582 Comb is going to be something like the Beside or Above. 1052 01:04:05,582 --> 01:04:07,240 Well what's that going to be. 1053 01:04:07,240 --> 01:04:10,540 That's going to be a procedure, remember what 1054 01:04:10,540 --> 01:04:13,480 Beside actually was, right. 1055 01:04:13,480 --> 01:04:18,700 It took a picture, took two pictures and a scale factor. 1056 01:04:18,700 --> 01:04:21,740 Using that I produced something that took a level 1057 01:04:21,740 --> 01:04:24,800 number and a picture and a scale factor, that I called 1058 01:04:24,800 --> 01:04:26,310 right-push. 1059 01:04:26,310 --> 01:04:27,700 So this is going to be something that takes a 1060 01:04:27,700 --> 01:04:32,700 picture, a level number and a scale factor, and 1061 01:04:32,700 --> 01:04:33,950 it's going to say-- 1062 01:04:33,950 --> 01:04:36,320 1063 01:04:36,320 --> 01:04:39,520 I'm going to do some repeated operation. 1064 01:04:39,520 --> 01:04:46,100 I'm going to repeatedly apply the procedure which takes a 1065 01:04:46,100 --> 01:04:53,540 picture and applies the means of combination to the picture 1066 01:04:53,540 --> 01:04:58,160 and the original picture and the one I took in here and the 1067 01:04:58,160 --> 01:05:06,100 scale factor, and I do the thing which repeats this 1068 01:05:06,100 --> 01:05:15,370 procedure N times, and I apply that whole thing to my 1069 01:05:15,370 --> 01:05:16,620 original picture. 1070 01:05:16,620 --> 01:05:19,600 1071 01:05:19,600 --> 01:05:23,390 Repeated here, in case you haven't seen it, is another 1072 01:05:23,390 --> 01:05:29,660 higher order procedure that takes a procedure and a number 1073 01:05:29,660 --> 01:05:32,510 and returns for you another procedure that applies this 1074 01:05:32,510 --> 01:05:36,150 procedure N times. 1075 01:05:36,150 --> 01:05:38,690 And I think some of you have already written repeated as an 1076 01:05:38,690 --> 01:05:41,520 exercise, but if you haven't, it's a very good exercise in 1077 01:05:41,520 --> 01:05:43,910 thinking about higher order procedures. 1078 01:05:43,910 --> 01:05:46,320 But in any case, the result of this repeated is what I apply 1079 01:05:46,320 --> 01:05:47,570 to picture. 1080 01:05:47,570 --> 01:05:49,510 1081 01:05:49,510 --> 01:05:52,880 And having done that, that's going to capture-- 1082 01:05:52,880 --> 01:05:56,700 that is the thing, the way I got from the idea of Beside to 1083 01:05:56,700 --> 01:06:00,760 the idea of right-push So having done that, I could say 1084 01:06:00,760 --> 01:06:12,790 define right-push to be push of Beside. 1085 01:06:12,790 --> 01:06:17,640 1086 01:06:17,640 --> 01:06:20,770 Or if I say, define up-push to be push of Beside, I'd get the 1087 01:06:20,770 --> 01:06:23,480 analogous thing or define corner-push to be push of some 1088 01:06:23,480 --> 01:06:25,745 appropriate thing that did both the Beside and Above, or 1089 01:06:25,745 --> 01:06:28,340 I could push anything. 1090 01:06:28,340 --> 01:06:31,660 Anyway this is, if you're having trouble with lambdas, 1091 01:06:31,660 --> 01:06:33,840 this is an excellent exercise in figuring 1092 01:06:33,840 --> 01:06:36,100 out what this means. 1093 01:06:36,100 --> 01:06:42,190 OK, well there's a lot to learn from this example. 1094 01:06:42,190 --> 01:06:46,040 The main point I've been dwelling on is the notion of 1095 01:06:46,040 --> 01:06:50,760 nicely embedding a language inside another language. 1096 01:06:50,760 --> 01:06:54,700 Right, so that all the power of this language like List of 1097 01:06:54,700 --> 01:06:57,270 the surrounding language is still accessible to you and 1098 01:06:57,270 --> 01:06:59,270 appears as a natural extension of the 1099 01:06:59,270 --> 01:07:01,000 language that you built. 1100 01:07:01,000 --> 01:07:06,140 That's one thing that this example shows very well. 1101 01:07:06,140 --> 01:07:07,990 OK. 1102 01:07:07,990 --> 01:07:10,960 Another thing is, if you go back and think about that, 1103 01:07:10,960 --> 01:07:12,180 what's procedures and what's data. 1104 01:07:12,180 --> 01:07:15,320 You know, by the time we get up to here, my God, 1105 01:07:15,320 --> 01:07:16,190 what's going on. 1106 01:07:16,190 --> 01:07:18,620 I mean, this is some procedure, and it takes a 1107 01:07:18,620 --> 01:07:20,380 picture and an argument, and what's a picture. 1108 01:07:20,380 --> 01:07:22,700 Well, a picture itself, as you remember, was a procedure, and 1109 01:07:22,700 --> 01:07:23,630 that took a rectangle. 1110 01:07:23,630 --> 01:07:26,090 And a rectangle is some abstraction. 1111 01:07:26,090 --> 01:07:31,300 And I hope now that by now you're completely lost as to 1112 01:07:31,300 --> 01:07:32,580 the question of what in the system is 1113 01:07:32,580 --> 01:07:33,590 procedure and what's data. 1114 01:07:33,590 --> 01:07:35,500 You see, there isn't any difference. 1115 01:07:35,500 --> 01:07:38,020 There really isn't. 1116 01:07:38,020 --> 01:07:39,850 And you might think of a picture sometimes as a 1117 01:07:39,850 --> 01:07:42,790 procedure and sometimes as data, but that's just, sort 1118 01:07:42,790 --> 01:07:44,860 of, you know, making you feel comfortable. 1119 01:07:44,860 --> 01:07:48,640 It's really both in some sense or neither in some sense. 1120 01:07:48,640 --> 01:07:56,370 OK, there's a more general point about the structure of 1121 01:07:56,370 --> 01:08:03,510 the system as creating a language, viewing the 1122 01:08:03,510 --> 01:08:08,030 engineering design process as one of creating language or 1123 01:08:08,030 --> 01:08:12,730 rather one of creating a sort of sequence 1124 01:08:12,730 --> 01:08:14,830 of layers of language. 1125 01:08:14,830 --> 01:08:18,010 You see, there's this methodology, or maybe I should 1126 01:08:18,010 --> 01:08:22,460 say mythology, that's, sort of, charitably called 1127 01:08:22,460 --> 01:08:24,989 software, quote, engineering. 1128 01:08:24,989 --> 01:08:27,090 All right, and what does it say, it's says well, you go 1129 01:08:27,090 --> 01:08:29,140 and you figure out your task, and you figure out exactly 1130 01:08:29,140 --> 01:08:30,520 what you want to do. 1131 01:08:30,520 --> 01:08:32,080 And once you figure out exactly what you want to do, 1132 01:08:32,080 --> 01:08:34,490 you find out that it breaks out into three sub-tasks, and 1133 01:08:34,490 --> 01:08:36,710 you go and you start working on-- and you work on this 1134 01:08:36,710 --> 01:08:38,770 sub-task, and you figure out exactly what that is. 1135 01:08:38,770 --> 01:08:40,649 And you find out that that breaks down into three 1136 01:08:40,649 --> 01:08:43,380 sub-tasks, and you specify them completely, and you go 1137 01:08:43,380 --> 01:08:45,920 and you work on those two, and you work on this sub-one, and 1138 01:08:45,920 --> 01:08:47,229 you specify that exactly. 1139 01:08:47,229 --> 01:08:48,990 And then finally when you're done, you come back way up 1140 01:08:48,990 --> 01:08:51,779 here, and you work on your second sub-task, and specify 1141 01:08:51,779 --> 01:08:53,370 that out and work it out. 1142 01:08:53,370 --> 01:08:55,490 And then you end up with-- 1143 01:08:55,490 --> 01:08:57,680 you end up at the end with this beautiful edifice. 1144 01:08:57,680 --> 01:09:03,120 Right, you end up with a marvelous tree, where you've 1145 01:09:03,120 --> 01:09:05,590 broken your task into sub-tasks and broken each of 1146 01:09:05,590 --> 01:09:07,260 these into sub-tasks and broken those 1147 01:09:07,260 --> 01:09:10,370 into sub-tasks, right. 1148 01:09:10,370 --> 01:09:15,200 And each of these nodes is exactly and precisely defined 1149 01:09:15,200 --> 01:09:17,779 to do the wonderful, beautiful task to make it fit into the 1150 01:09:17,779 --> 01:09:19,180 whole edifice, right. 1151 01:09:19,180 --> 01:09:21,080 That's this mythology. 1152 01:09:21,080 --> 01:09:23,970 See only a computer scientist could possibly believe that 1153 01:09:23,970 --> 01:09:28,220 you build a complex system like that, right. 1154 01:09:28,220 --> 01:09:32,700 Contrast that with this Henderson example. 1155 01:09:32,700 --> 01:09:35,319 It didn't work like that. 1156 01:09:35,319 --> 01:09:37,359 What happened was that there was a sequence 1157 01:09:37,359 --> 01:09:41,319 of layers of language. 1158 01:09:41,319 --> 01:09:41,990 What happened? 1159 01:09:41,990 --> 01:09:47,770 There was a layer of a thing that allowed us to build 1160 01:09:47,770 --> 01:09:49,020 primitive pictures. 1161 01:09:49,020 --> 01:09:51,569 1162 01:09:51,569 --> 01:09:56,440 There's primitive pictures and that was a language. 1163 01:09:56,440 --> 01:09:57,530 I didn't say much about it. 1164 01:09:57,530 --> 01:09:59,900 We talked about how to construct George, but that was 1165 01:09:59,900 --> 01:10:01,950 a language where you talked about vectors and line 1166 01:10:01,950 --> 01:10:06,520 segments and points and where they sat in the unit square. 1167 01:10:06,520 --> 01:10:12,000 And then on top of that, right, on top of that-- 1168 01:10:12,000 --> 01:10:13,850 so this is the language of primitive pictures. 1169 01:10:13,850 --> 01:10:17,100 1170 01:10:17,100 --> 01:10:19,240 Right, talking about line segments in particular 1171 01:10:19,240 --> 01:10:21,620 pictures in the unit square. 1172 01:10:21,620 --> 01:10:24,110 On top of that was a whole language. 1173 01:10:24,110 --> 01:10:33,110 There was a language of geometric combinators, a 1174 01:10:33,110 --> 01:10:41,340 language of geometric positions, which talks about 1175 01:10:41,340 --> 01:10:48,240 things like Above and Beside and right-push and Rotate. 1176 01:10:48,240 --> 01:10:53,600 And those things, sort of, happened with reference to the 1177 01:10:53,600 --> 01:10:55,470 things that are talked about in this language. 1178 01:10:55,470 --> 01:10:58,640 1179 01:10:58,640 --> 01:11:03,070 And then if we like, we saw that above that there was sort 1180 01:11:03,070 --> 01:11:14,810 of a language of schemes of combination. 1181 01:11:14,810 --> 01:11:21,410 1182 01:11:21,410 --> 01:11:25,930 For example, push, which talked about repeatedly doing 1183 01:11:25,930 --> 01:11:28,540 something over with a scale factor. 1184 01:11:28,540 --> 01:11:31,130 And the things that were being discussed in that language 1185 01:11:31,130 --> 01:11:36,280 were, sort of, the things that happened down here. 1186 01:11:36,280 --> 01:11:41,310 So what you have is, at each level, the objects that are 1187 01:11:41,310 --> 01:11:46,090 being talked about are the things that were erected at 1188 01:11:46,090 --> 01:11:48,270 the previous level. 1189 01:11:48,270 --> 01:11:53,270 What's the difference between this thing and this thing? 1190 01:11:53,270 --> 01:11:59,890 The answer is that over here in the tree, each node, and in 1191 01:11:59,890 --> 01:12:03,610 fact, each decomposition down here, is being designed to do 1192 01:12:03,610 --> 01:12:09,640 a specific task, whereas in the other scheme, what you 1193 01:12:09,640 --> 01:12:13,900 have is a full range of linguistic 1194 01:12:13,900 --> 01:12:15,940 power at each level. 1195 01:12:15,940 --> 01:12:21,340 See what's happening there, at any level, it's not being set 1196 01:12:21,340 --> 01:12:23,310 up to do a particular task. 1197 01:12:23,310 --> 01:12:27,710 It's being set up to talk about a whole range of things. 1198 01:12:27,710 --> 01:12:31,810 The consequence of that for design is that something 1199 01:12:31,810 --> 01:12:36,620 that's designed in that method is likely to be more robust, 1200 01:12:36,620 --> 01:12:40,470 where by robust, I mean that if you go and make some change 1201 01:12:40,470 --> 01:12:46,820 in your description, it's more likely to be captured by a 1202 01:12:46,820 --> 01:12:51,070 corresponding change, in the way that the language is 1203 01:12:51,070 --> 01:12:55,460 implemented at the next level up, right, because you've made 1204 01:12:55,460 --> 01:12:56,660 these levels full. 1205 01:12:56,660 --> 01:12:59,980 So you're not talking about a particular thing like Beside. 1206 01:12:59,980 --> 01:13:02,880 You've given yourself a whole vocabulary to express things 1207 01:13:02,880 --> 01:13:06,540 of that sort, so if you go and change your specifications a 1208 01:13:06,540 --> 01:13:09,580 little bit, it's more likely that your methodology will 1209 01:13:09,580 --> 01:13:13,680 able to adapt to capture that change, whereas a design like 1210 01:13:13,680 --> 01:13:15,770 this is not going to be robust, because if I go and 1211 01:13:15,770 --> 01:13:18,310 change something that's in here, that might affect the 1212 01:13:18,310 --> 01:13:20,840 entire way that I decomposed everything down, 1213 01:13:20,840 --> 01:13:23,240 further down the tree. 1214 01:13:23,240 --> 01:13:26,350 Right, so very big difference in outlook in decomposition, 1215 01:13:26,350 --> 01:13:28,590 levels of language rather than, sort 1216 01:13:28,590 --> 01:13:30,580 of, a strict hierarchy. 1217 01:13:30,580 --> 01:13:33,750 Not only that, but when you have levels of language you've 1218 01:13:33,750 --> 01:13:37,390 given yourself a different vocabularies for talking about 1219 01:13:37,390 --> 01:13:38,780 the design at different levels. 1220 01:13:38,780 --> 01:13:42,260 So if we go back and look at George one last time, if I 1221 01:13:42,260 --> 01:13:46,610 wanted to change this picture George, see suddenly I have a 1222 01:13:46,610 --> 01:13:48,800 whole different ways of describing the change. 1223 01:13:48,800 --> 01:13:52,320 Like for example, I may want to go to the basic primitive 1224 01:13:52,320 --> 01:13:57,640 design and move the endpoint of some vector. 1225 01:13:57,640 --> 01:14:01,140 That's a change that I would discuss at the lowest level. 1226 01:14:01,140 --> 01:14:03,420 I would say the endpoint is somewhere else. 1227 01:14:03,420 --> 01:14:05,440 Or I might come up and say, well the next thing I wanted 1228 01:14:05,440 --> 01:14:10,320 to do, this little replicated element, I might want to do by 1229 01:14:10,320 --> 01:14:10,990 something else. 1230 01:14:10,990 --> 01:14:13,740 I might want to put a scale factor in that Beside. 1231 01:14:13,740 --> 01:14:17,850 That's a change that I would discuss at the next level of 1232 01:14:17,850 --> 01:14:19,350 design, the level of combinators. 1233 01:14:19,350 --> 01:14:22,580 Or I might want to say, I might want to change the basic 1234 01:14:22,580 --> 01:14:27,510 way that I took this pattern and made some recursive 1235 01:14:27,510 --> 01:14:29,400 decomposition, maybe not bleeding out toward the 1236 01:14:29,400 --> 01:14:30,960 corners or something else. 1237 01:14:30,960 --> 01:14:33,150 That would be a change that I would discuss 1238 01:14:33,150 --> 01:14:34,260 at the highest level. 1239 01:14:34,260 --> 01:14:36,700 And because I've structured the system to be this way, I 1240 01:14:36,700 --> 01:14:39,120 have all these vocabularies for talking about change in 1241 01:14:39,120 --> 01:14:41,580 different ways and a lot of flexibility to decide which 1242 01:14:41,580 --> 01:14:42,830 one's appropriate. 1243 01:14:42,830 --> 01:14:44,810 1244 01:14:44,810 --> 01:14:48,370 OK, well that's sort of a big point about the difference in 1245 01:14:48,370 --> 01:14:51,470 software methodology that comes out from List, and it 1246 01:14:51,470 --> 01:14:54,840 all comes, again, out of the notion that really, the design 1247 01:14:54,840 --> 01:14:58,430 process is not so much implementing programs as 1248 01:14:58,430 --> 01:14:59,370 implementing languages. 1249 01:14:59,370 --> 01:15:02,870 And that's really the powerful of List. OK, thank you. 1250 01:15:02,870 --> 01:15:04,480 Let's take a break. 1251 01:15:04,480 --> 01:15:34,591 ================================================ FILE: SrtEN/lec3b_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:02,928 1 00:00:02,928 --> 00:00:19,520 [MUSIC PLAYING] 2 00:00:19,520 --> 00:00:22,720 PROFESSOR: Well, Hal just told us how you build robust 3 00:00:22,720 --> 00:00:26,960 systems. The key idea was-- 4 00:00:26,960 --> 00:00:30,000 I'm sure that many of you don't really assimilate that 5 00:00:30,000 --> 00:00:32,980 yet-- but the key idea is that in order to make a system 6 00:00:32,980 --> 00:00:36,850 that's robust, it has to be insensitive to small changes, 7 00:00:36,850 --> 00:00:39,680 that is, a small change in the problem should lead to only a 8 00:00:39,680 --> 00:00:41,340 small change in the solution. 9 00:00:41,340 --> 00:00:42,670 There ought to be a continuity. 10 00:00:42,670 --> 00:00:45,275 The space of solutions ought to be continuous in this space 11 00:00:45,275 --> 00:00:46,120 of problems. 12 00:00:46,120 --> 00:00:50,270 The way he was explaining how to do that was instead of 13 00:00:50,270 --> 00:00:52,240 solving a particular problem at every level of 14 00:00:52,240 --> 00:00:55,520 decomposition of the problem at the subproblems, where you 15 00:00:55,520 --> 00:00:58,570 solve the class of problems, which are a neighborhood of 16 00:00:58,570 --> 00:01:01,440 the particular problem that you're trying to solve. 17 00:01:01,440 --> 00:01:03,980 The way you do that is by producing a language at that 18 00:01:03,980 --> 00:01:07,500 level of detail in which the solutions to that class of 19 00:01:07,500 --> 00:01:11,170 problems is representable in that language. 20 00:01:11,170 --> 00:01:14,370 Therefore when you makes more changes to the problem you're 21 00:01:14,370 --> 00:01:17,140 trying to solve, you generally have to make only small local 22 00:01:17,140 --> 00:01:20,640 changes to the solution you've constructed, because at the 23 00:01:20,640 --> 00:01:23,190 level of detail you're working, there's a language 24 00:01:23,190 --> 00:01:26,940 where you can express the various solutions to alternate 25 00:01:26,940 --> 00:01:30,170 problems of the same type. 26 00:01:30,170 --> 00:01:35,090 Well that's the beginning of a very important idea, the most 27 00:01:35,090 --> 00:01:37,950 important perhaps idea that makes computer science more 28 00:01:37,950 --> 00:01:40,320 powerful than most of the other kinds of engineering 29 00:01:40,320 --> 00:01:43,500 disciplines we know about. 30 00:01:43,500 --> 00:01:47,350 What we've seen so far is sort of how to use 31 00:01:47,350 --> 00:01:49,500 embedding of languages. 32 00:01:49,500 --> 00:01:52,570 And, of course, the power of embedding languages partly 33 00:01:52,570 --> 00:01:55,480 comes from procedures like this one that 34 00:01:55,480 --> 00:01:57,500 I showed you yesterday. 35 00:01:57,500 --> 00:02:01,210 What you see here is the derivative program that we 36 00:02:01,210 --> 00:02:02,280 described yesterday. 37 00:02:02,280 --> 00:02:06,270 It's a procedure that takes a procedure as an argument and 38 00:02:06,270 --> 00:02:09,880 returns a procedure as a value. 39 00:02:09,880 --> 00:02:12,680 And using such things is very nice. 40 00:02:12,680 --> 00:02:15,480 You can make things like push combinators and all that sort 41 00:02:15,480 --> 00:02:18,020 of wonderful thing that you saw last time. 42 00:02:18,020 --> 00:02:21,730 However, now I'm going to really muddy the waters. 43 00:02:21,730 --> 00:02:25,430 See this confuses the issue of what's the procedure and what 44 00:02:25,430 --> 00:02:28,310 is data, but not very badly. 45 00:02:28,310 --> 00:02:31,260 What we really want to do is confuse it very badly. 46 00:02:31,260 --> 00:02:33,400 And the best way to do that is to get involved with the 47 00:02:33,400 --> 00:02:35,980 manipulation of the algebraic expressions that the 48 00:02:35,980 --> 00:02:39,750 procedures themselves are expressed in. 49 00:02:39,750 --> 00:02:43,660 So at this point, I want to talk about instead of things 50 00:02:43,660 --> 00:02:48,300 like on this slide, the derivative procedure being a 51 00:02:48,300 --> 00:02:49,880 thing that manipulates a procedure-- 52 00:02:49,880 --> 00:02:51,870 this is a numerical method you see here. 53 00:02:51,870 --> 00:02:56,440 And what you're seeing is a representation of the 54 00:02:56,440 --> 00:02:59,275 numerical approximation to the derivative. 55 00:02:59,275 --> 00:03:00,980 That's what's here. 56 00:03:00,980 --> 00:03:04,180 In fact what I'd like to talk about is instead things that 57 00:03:04,180 --> 00:03:06,170 look like this. 58 00:03:06,170 --> 00:03:12,080 And what we have here are rules from a calculus book. 59 00:03:12,080 --> 00:03:15,010 These are rules for finding the derivatives of the 60 00:03:15,010 --> 00:03:18,190 expressions that one might write in 61 00:03:18,190 --> 00:03:21,520 some algebraic language. 62 00:03:21,520 --> 00:03:24,990 It says things like a derivative of a constant is 0. 63 00:03:24,990 --> 00:03:27,700 The derivative of the valuable with respect to which you are 64 00:03:27,700 --> 00:03:29,250 taking the derivative is 1. 65 00:03:29,250 --> 00:03:32,490 The derivative of a constant times the function is the 66 00:03:32,490 --> 00:03:34,980 constant times the derivative of the function, 67 00:03:34,980 --> 00:03:38,300 and things like that. 68 00:03:38,300 --> 00:03:39,690 These are exact expressions. 69 00:03:39,690 --> 00:03:43,090 These are not numerical approximations. 70 00:03:43,090 --> 00:03:44,560 Can we make programs? 71 00:03:44,560 --> 00:03:51,000 And, in fact, it's very easy to make programs that 72 00:03:51,000 --> 00:03:52,250 manipulate these expressions. 73 00:03:52,250 --> 00:03:56,130 74 00:03:56,130 --> 00:03:57,480 Well let's see. 75 00:03:57,480 --> 00:04:01,350 Let's look at these rules in some detail. 76 00:04:01,350 --> 00:04:03,850 You all have seen these rules in your elementary calculus 77 00:04:03,850 --> 00:04:06,140 class at one time or another. 78 00:04:06,140 --> 00:04:10,570 And you know from calculus that it's easy to produce 79 00:04:10,570 --> 00:04:12,840 derivatives of arbitrary expressions. 80 00:04:12,840 --> 00:04:14,900 You also know from your elementary calculus that it's 81 00:04:14,900 --> 00:04:17,140 hard to produce integrals. 82 00:04:17,140 --> 00:04:19,690 Yet integrals and derivatives are opposites of each other. 83 00:04:19,690 --> 00:04:21,800 They're inverse operations. 84 00:04:21,800 --> 00:04:24,360 And they have the same rules. 85 00:04:24,360 --> 00:04:29,110 What is special about these rules that makes it possible 86 00:04:29,110 --> 00:04:32,310 for one to produce derivatives easily and 87 00:04:32,310 --> 00:04:35,100 integrals why it's so hard? 88 00:04:35,100 --> 00:04:37,510 Let's think about that very simply. 89 00:04:37,510 --> 00:04:39,390 Look at these rules. 90 00:04:39,390 --> 00:04:42,190 Every one of these rules, when used in the direction for 91 00:04:42,190 --> 00:04:44,260 taking derivatives, which is in the direction of this 92 00:04:44,260 --> 00:04:48,830 arrow, the left side is matched against your 93 00:04:48,830 --> 00:04:51,710 expression, and the right side is the thing which is the 94 00:04:51,710 --> 00:04:53,810 derivative of that expression. 95 00:04:53,810 --> 00:04:55,570 The arrow is going that way. 96 00:04:55,570 --> 00:04:58,630 97 00:04:58,630 --> 00:05:02,830 In each of these rules, the expressions on the right-hand 98 00:05:02,830 --> 00:05:05,600 side of the rule that are contained within derivatives 99 00:05:05,600 --> 00:05:08,630 are subexpressions, are proper subexpressions, of the 100 00:05:08,630 --> 00:05:10,670 expression on the left-hand side. 101 00:05:10,670 --> 00:05:14,510 So here we see the derivative of the sum, with is the 102 00:05:14,510 --> 00:05:17,260 expression on the left-hand side is the sum of the 103 00:05:17,260 --> 00:05:20,030 derivatives of the pieces. 104 00:05:20,030 --> 00:05:25,070 So the rule of moving to the right are reduction rules. 105 00:05:25,070 --> 00:05:28,110 The problem becomes easier. 106 00:05:28,110 --> 00:05:30,810 I turn a big complicated problem it's lots of smaller 107 00:05:30,810 --> 00:05:35,000 problems and then combine the results, a perfect place for 108 00:05:35,000 --> 00:05:36,730 recursion to work. 109 00:05:36,730 --> 00:05:42,310 If I'm going in the other direction like this, if I'm 110 00:05:42,310 --> 00:05:44,160 trying to produce integrals, well there are several 111 00:05:44,160 --> 00:05:45,340 problems you see here. 112 00:05:45,340 --> 00:05:48,460 First of all, if I try to integrate an expression like a 113 00:05:48,460 --> 00:05:50,930 sum, more than one rule matches. 114 00:05:50,930 --> 00:05:52,610 Here's one that matches. 115 00:05:52,610 --> 00:05:54,850 Here's one that matches. 116 00:05:54,850 --> 00:05:56,210 I don't know which one to take. 117 00:05:56,210 --> 00:05:57,870 And they may be different. 118 00:05:57,870 --> 00:06:00,250 I may get to explore different things. 119 00:06:00,250 --> 00:06:04,660 Also, the expressions become larger in that direction. 120 00:06:04,660 --> 00:06:06,910 And when the expressions become larger, then there's no 121 00:06:06,910 --> 00:06:10,940 guarantee that any particular path I choose will terminate, 122 00:06:10,940 --> 00:06:14,380 because we will only terminate by accidental cancellation. 123 00:06:14,380 --> 00:06:16,840 So that's why integrals are complicated 124 00:06:16,840 --> 00:06:19,170 searches and hard to do. 125 00:06:19,170 --> 00:06:21,640 Right now I don't want to do anything as hard as that. 126 00:06:21,640 --> 00:06:24,260 Let's work on derivatives for a while. 127 00:06:24,260 --> 00:06:26,860 Well, these roles are ones you know for 128 00:06:26,860 --> 00:06:28,860 the most part hopefully. 129 00:06:28,860 --> 00:06:32,410 So let's see if we can write a program which is these rules. 130 00:06:32,410 --> 00:06:34,790 And that should be very easy. 131 00:06:34,790 --> 00:06:36,830 Just write the program. 132 00:06:36,830 --> 00:06:39,010 See, because while I showed you is that it's a reduction 133 00:06:39,010 --> 00:06:43,180 rule, it's something appropriate for a recursion. 134 00:06:43,180 --> 00:06:45,230 And, of course, what we have for each of these rules is we 135 00:06:45,230 --> 00:06:48,375 have a case in some case analysis. 136 00:06:48,375 --> 00:06:50,350 So I'm just going to write this program down. 137 00:06:50,350 --> 00:06:53,130 138 00:06:53,130 --> 00:06:56,780 Now, of course, I'm going to be saying something you have 139 00:06:56,780 --> 00:06:57,450 to believe. 140 00:06:57,450 --> 00:06:57,890 Right? 141 00:06:57,890 --> 00:06:59,870 What you have to believe is I can represent these algebraic 142 00:06:59,870 --> 00:07:03,210 expressions, that I can grab their parts, that I can put 143 00:07:03,210 --> 00:07:04,330 them together. 144 00:07:04,330 --> 00:07:07,620 We've invented list structures so that you can do that. 145 00:07:07,620 --> 00:07:09,810 But you don't want to worry about that now. 146 00:07:09,810 --> 00:07:11,680 Right now I'm going to write the program that encapsulates 147 00:07:11,680 --> 00:07:14,920 these rules independent of the representation of the 148 00:07:14,920 --> 00:07:16,170 algebraic expressions. 149 00:07:16,170 --> 00:07:20,580 150 00:07:20,580 --> 00:07:27,610 You have a derivative of an expression with 151 00:07:27,610 --> 00:07:30,280 respect to a variable. 152 00:07:30,280 --> 00:07:32,020 This is a different thing than the 153 00:07:32,020 --> 00:07:35,040 derivative of the function. 154 00:07:35,040 --> 00:07:39,130 That's what we saw last time, that numerical approximation. 155 00:07:39,130 --> 00:07:40,860 It's something you can't open up a function. 156 00:07:40,860 --> 00:07:42,990 It's just the answers. 157 00:07:42,990 --> 00:07:44,450 The derivative of an expression is 158 00:07:44,450 --> 00:07:45,990 the way it's written. 159 00:07:45,990 --> 00:07:48,410 And therefore it's a syntactic phenomenon. 160 00:07:48,410 --> 00:07:50,540 And so a lot of what we're going to be doing today is 161 00:07:50,540 --> 00:07:53,400 worrying about syntax, syntax of expressions 162 00:07:53,400 --> 00:07:54,830 and things like that. 163 00:07:54,830 --> 00:07:57,700 Well, there's a case analysis. 164 00:07:57,700 --> 00:08:00,420 Anytime we do anything complicated thereby a 165 00:08:00,420 --> 00:08:03,690 recursion, we presumably need a case analysis. 166 00:08:03,690 --> 00:08:05,340 It's the essential way to begin. 167 00:08:05,340 --> 00:08:06,590 And that's usually a conditional 168 00:08:06,590 --> 00:08:08,170 of some large kind. 169 00:08:08,170 --> 00:08:10,000 Well, what are their possibilities? 170 00:08:10,000 --> 00:08:12,290 the first rule that you saw is this something a constant? 171 00:08:12,290 --> 00:08:16,610 172 00:08:16,610 --> 00:08:20,510 And what I'm asking is, is the expression a constant with 173 00:08:20,510 --> 00:08:21,920 respect to the variable given? 174 00:08:21,920 --> 00:08:24,990 175 00:08:24,990 --> 00:08:28,460 If so, the result is 0, because the derivative 176 00:08:28,460 --> 00:08:31,880 represents the rate of change of something. 177 00:08:31,880 --> 00:08:38,169 If, however, the expression that I'm taking the derivative 178 00:08:38,169 --> 00:08:42,770 of is the variable I'm varying, then this is the same 179 00:08:42,770 --> 00:08:52,560 variable, the expression var, then the rate of change of the 180 00:08:52,560 --> 00:08:55,560 expression with respect to the variable is 1. 181 00:08:55,560 --> 00:08:56,810 It's the same 1. 182 00:08:56,810 --> 00:08:58,970 183 00:08:58,970 --> 00:09:01,490 Well now there are a couple of other possibilities. 184 00:09:01,490 --> 00:09:04,010 It could, for example, be a sum. 185 00:09:04,010 --> 00:09:06,140 Well, I don't know how I'm going to express sums yet. 186 00:09:06,140 --> 00:09:07,180 Actually I do. 187 00:09:07,180 --> 00:09:10,370 But I haven't told you yet. 188 00:09:10,370 --> 00:09:12,630 But is it a sum? 189 00:09:12,630 --> 00:09:15,520 I'm imagining that there's some way of telling. 190 00:09:15,520 --> 00:09:20,860 I'm doing a dispatch on the type of the expression here, 191 00:09:20,860 --> 00:09:24,960 absolutely essential in building languages. 192 00:09:24,960 --> 00:09:26,520 Languages are made out of different expressions. 193 00:09:26,520 --> 00:09:28,930 And soon we're going to see that in our more powerful 194 00:09:28,930 --> 00:09:32,760 methods of building languages on languages. 195 00:09:32,760 --> 00:09:35,530 Is an expression a sum? 196 00:09:35,530 --> 00:09:38,360 If it's a sum, well, we know the rule for derivative of the 197 00:09:38,360 --> 00:09:42,160 sum is the sum of the derivatives of the parts. 198 00:09:42,160 --> 00:09:43,370 One of them is called the addend and the 199 00:09:43,370 --> 00:09:44,050 other is the augend. 200 00:09:44,050 --> 00:09:45,710 But I don't have enough space on the blackboard 201 00:09:45,710 --> 00:09:46,810 to such long names. 202 00:09:46,810 --> 00:09:48,660 So I'll call them A1 and A2. 203 00:09:48,660 --> 00:09:50,250 I want to make a sum. 204 00:09:50,250 --> 00:09:53,100 205 00:09:53,100 --> 00:09:57,300 Do you remember which is the sum for end or the menu end? 206 00:09:57,300 --> 00:10:00,310 Or was it the dividend and the divisor or 207 00:10:00,310 --> 00:10:01,700 something like that? 208 00:10:01,700 --> 00:10:08,720 Make sum of the derivative of the A1, I'll call it. 209 00:10:08,720 --> 00:10:12,640 It's the addend of the expression with respect to the 210 00:10:12,640 --> 00:10:23,506 variable, and the derivative of the A2 of the expression, 211 00:10:23,506 --> 00:10:27,020 because the two arguments, the addition with 212 00:10:27,020 --> 00:10:28,270 respect to the variable. 213 00:10:28,270 --> 00:10:32,450 214 00:10:32,450 --> 00:10:36,350 And another rule that we know is product rule, which is, if 215 00:10:36,350 --> 00:10:37,600 the expression is a product. 216 00:10:37,600 --> 00:10:43,090 217 00:10:43,090 --> 00:10:47,070 By the way, it's a good idea when you're defining things, 218 00:10:47,070 --> 00:10:49,440 when you're defining predicates, to give them a 219 00:10:49,440 --> 00:10:51,290 name that ends in a question mark. 220 00:10:51,290 --> 00:10:53,140 This question mark doesn't mean anything. 221 00:10:53,140 --> 00:10:54,730 It's for us as an agreement. 222 00:10:54,730 --> 00:10:57,710 It's a conventional interface between humans so you can read 223 00:10:57,710 --> 00:10:59,980 my programs more easily. 224 00:10:59,980 --> 00:11:02,510 So I want you to, when you write programs, if you define 225 00:11:02,510 --> 00:11:05,330 a predicate procedure, that's something that rings true of 226 00:11:05,330 --> 00:11:07,720 false, it should have a name which ends in question mark. 227 00:11:07,720 --> 00:11:09,740 The list doesn't care. 228 00:11:09,740 --> 00:11:11,740 I care. 229 00:11:11,740 --> 00:11:13,400 I want to make a sum. 230 00:11:13,400 --> 00:11:18,280 Because the derivative of a product is the sum of the 231 00:11:18,280 --> 00:11:19,920 first times the derivative of the second plus the second 232 00:11:19,920 --> 00:11:26,620 times the derivative of the first. Make a sum of two 233 00:11:26,620 --> 00:11:37,710 things, a product of, well, I'm going to say the M1 of the 234 00:11:37,710 --> 00:11:47,560 expression, and the derivative of the M2 of the expression 235 00:11:47,560 --> 00:12:01,680 with respect to the variable, and the product of the 236 00:12:01,680 --> 00:12:10,720 derivative of M1, the multiplier of the expression, 237 00:12:10,720 --> 00:12:13,450 with respect to the variable. 238 00:12:13,450 --> 00:12:17,340 It's the product of that and the multiplicand, M2, of the 239 00:12:17,340 --> 00:12:18,590 expression. 240 00:12:18,590 --> 00:12:21,660 241 00:12:21,660 --> 00:12:22,630 Make that product. 242 00:12:22,630 --> 00:12:23,850 Make the sum. 243 00:12:23,850 --> 00:12:25,080 Close that case. 244 00:12:25,080 --> 00:12:28,590 And, of course, I could add as many cases as I like here for 245 00:12:28,590 --> 00:12:30,960 a complete set of rules you might find in a calculus book. 246 00:12:30,960 --> 00:12:34,880 247 00:12:34,880 --> 00:12:41,184 So this is what it takes to encapsulate those rules. 248 00:12:41,184 --> 00:12:43,080 And you see, you have to realize there's a lot of 249 00:12:43,080 --> 00:12:44,690 wishful thinking here. 250 00:12:44,690 --> 00:12:46,620 I haven't told you anything about how I'm going to make 251 00:12:46,620 --> 00:12:48,570 these representations. 252 00:12:48,570 --> 00:12:52,830 Now, once I've decided that this is my set of rules, I 253 00:12:52,830 --> 00:12:55,820 think it's time to play with the representation. 254 00:12:55,820 --> 00:12:58,030 Let's attack that/ 255 00:12:58,030 --> 00:13:01,120 Well, first of all, I'm going to play a pun. 256 00:13:01,120 --> 00:13:02,870 It's an important pun. 257 00:13:02,870 --> 00:13:06,590 It's a key to a sort of powerful idea. 258 00:13:06,590 --> 00:13:09,750 259 00:13:09,750 --> 00:13:12,790 If I want to represent sums, and products, and differences, 260 00:13:12,790 --> 00:13:16,450 and quotients, and things like that, why not use the same 261 00:13:16,450 --> 00:13:20,660 language as I'm writing my program in? 262 00:13:20,660 --> 00:13:23,130 I write my program in algebraic expressions that 263 00:13:23,130 --> 00:13:29,280 look like the sum of the product on a and the product 264 00:13:29,280 --> 00:13:34,330 of x and x, and things like that. 265 00:13:34,330 --> 00:13:39,390 And the product of b and x and c, whatever, make that a sum 266 00:13:39,390 --> 00:13:40,960 of the product. 267 00:13:40,960 --> 00:13:43,230 Right now I don't want to have procedures with unknown 268 00:13:43,230 --> 00:13:48,300 numbers of arguments, a product of b and x and c. 269 00:13:48,300 --> 00:13:51,050 270 00:13:51,050 --> 00:13:54,280 This is list structure. 271 00:13:54,280 --> 00:13:56,950 And the reason why this is nice, is because any one of 272 00:13:56,950 --> 00:14:00,380 these objects has a property. 273 00:14:00,380 --> 00:14:01,970 I know where the car is. 274 00:14:01,970 --> 00:14:04,100 The car is the operator. 275 00:14:04,100 --> 00:14:08,190 And the operands are the successive cdrs the successive 276 00:14:08,190 --> 00:14:12,276 cars of the cdrs of the list that this is. 277 00:14:12,276 --> 00:14:14,470 It makes it very convenient. 278 00:14:14,470 --> 00:14:15,560 I have to parse it. 279 00:14:15,560 --> 00:14:17,590 It's been done for me. 280 00:14:17,590 --> 00:14:19,685 I'm using the embedding and Lisp to advantage. 281 00:14:19,685 --> 00:14:22,860 282 00:14:22,860 --> 00:14:29,340 So, for example, let's start using list structure to write 283 00:14:29,340 --> 00:14:35,390 down the representation that I'm implicitly assuming here. 284 00:14:35,390 --> 00:14:37,590 Well I have to define various things that are implied in 285 00:14:37,590 --> 00:14:38,640 this representation. 286 00:14:38,640 --> 00:14:41,210 Like I have to find out how to do a constant, 287 00:14:41,210 --> 00:14:42,520 how you do same variable. 288 00:14:42,520 --> 00:14:45,890 Let's do those first. That's pretty easy enough. 289 00:14:45,890 --> 00:14:47,410 Now I'm going to be introducing lots of primitives 290 00:14:47,410 --> 00:14:49,680 here, because these are the primitives that 291 00:14:49,680 --> 00:14:51,745 come with list structure. 292 00:14:51,745 --> 00:14:53,015 OK, you define a constant. 293 00:14:53,015 --> 00:15:02,800 294 00:15:02,800 --> 00:15:06,350 And what I mean by a constant, an expression that's constant 295 00:15:06,350 --> 00:15:10,860 with respect to a veritable, is that the expression is 296 00:15:10,860 --> 00:15:11,530 something simple. 297 00:15:11,530 --> 00:15:13,550 I can't take it into pieces, and yet 298 00:15:13,550 --> 00:15:16,550 it isn't that variable. 299 00:15:16,550 --> 00:15:18,940 I can't break it up, and yet it isn't that variable. 300 00:15:18,940 --> 00:15:22,840 That does not mean that there may be other expressions that 301 00:15:22,840 --> 00:15:25,230 are more complicated that are constants. 302 00:15:25,230 --> 00:15:26,700 It's just that I'm going to look at the primitive 303 00:15:26,700 --> 00:15:30,510 constants in this way. 304 00:15:30,510 --> 00:15:34,080 So what this is, is it says that's it's the and. 305 00:15:34,080 --> 00:15:37,030 I can combine predicate expressions which return true 306 00:15:37,030 --> 00:15:38,610 or false with and. 307 00:15:38,610 --> 00:15:45,600 Something atomic, The expression is atomic, meaning 308 00:15:45,600 --> 00:15:47,050 it cannot be broken into parts. 309 00:15:47,050 --> 00:15:51,150 It doesn't have a car and a cdr. It's not a list. It adds 310 00:15:51,150 --> 00:15:54,250 a special test built into the system. 311 00:15:54,250 --> 00:16:06,950 And it's not identically equal to that variable. 312 00:16:06,950 --> 00:16:11,810 I'm representing my variable by things that are symbols 313 00:16:11,810 --> 00:16:16,550 which cannot be broken into pieces, things like x, and y, 314 00:16:16,550 --> 00:16:17,800 things like this. 315 00:16:17,800 --> 00:16:19,850 316 00:16:19,850 --> 00:16:21,890 Whereas, of course, something like this can be broken up 317 00:16:21,890 --> 00:16:23,140 into pieces. 318 00:16:23,140 --> 00:16:24,860 319 00:16:24,860 --> 00:16:40,560 And the same variable of an expression with respect to a 320 00:16:40,560 --> 00:16:48,840 variable is, in fact, an atomic expression. 321 00:16:48,840 --> 00:16:50,040 I want to have an atomic 322 00:16:50,040 --> 00:16:59,330 expression, which is identical. 323 00:16:59,330 --> 00:17:08,030 324 00:17:08,030 --> 00:17:13,329 I don't want to look inside this stuff anymore. 325 00:17:13,329 --> 00:17:16,040 These are primitive maybe. 326 00:17:16,040 --> 00:17:18,180 But it doesn't matter. 327 00:17:18,180 --> 00:17:22,569 I'm using things that are given to me with a language. 328 00:17:22,569 --> 00:17:24,300 I'm not terribly interest in them 329 00:17:24,300 --> 00:17:26,900 Now how do we deal with sums? 330 00:17:26,900 --> 00:17:29,100 Ah, something very interesting will happen. 331 00:17:29,100 --> 00:17:32,380 A sum is something which is not atomic and begins with the 332 00:17:32,380 --> 00:17:35,230 plus symbol. 333 00:17:35,230 --> 00:17:36,680 That's what it means. 334 00:17:36,680 --> 00:17:39,125 So here, I will define. 335 00:17:39,125 --> 00:17:45,630 336 00:17:45,630 --> 00:18:08,380 An question is a sum if and it's not atomic and it's head, 337 00:18:08,380 --> 00:18:15,140 it's beginning, its car of the expression is the symbol plus. 338 00:18:15,140 --> 00:18:19,950 339 00:18:19,950 --> 00:18:21,730 Now you're about to see something you haven't seen 340 00:18:21,730 --> 00:18:23,690 before, this quotation. 341 00:18:23,690 --> 00:18:26,240 342 00:18:26,240 --> 00:18:29,440 Why do I have that quotation there? 343 00:18:29,440 --> 00:18:30,970 Say your name, 344 00:18:30,970 --> 00:18:31,410 AUDIENCE: Susanna. 345 00:18:31,410 --> 00:18:32,270 PROFESSOR: Louder. 346 00:18:32,270 --> 00:18:33,190 AUDIENCE: Susanna 347 00:18:33,190 --> 00:18:34,250 PROFESSOR: Say your name. 348 00:18:34,250 --> 00:18:35,160 AUDIENCE: Your name. 349 00:18:35,160 --> 00:18:35,910 PROFESSOR: Louder. 350 00:18:35,910 --> 00:18:36,960 AUDIENCE: Your name. 351 00:18:36,960 --> 00:18:39,100 PROFESSOR: OK. 352 00:18:39,100 --> 00:18:42,040 What I'm showing you here is that the words 353 00:18:42,040 --> 00:18:45,520 of English are ambiguous. 354 00:18:45,520 --> 00:18:52,220 I was saying, say your name. 355 00:18:52,220 --> 00:18:57,070 I was also possibly saying say, your name. 356 00:18:57,070 --> 00:19:00,710 357 00:19:00,710 --> 00:19:04,100 But that cannot be distinguished in speech. 358 00:19:04,100 --> 00:19:09,600 However, we do have a notation in writing, which is quotation 359 00:19:09,600 --> 00:19:14,180 for distinguishing these two possible meanings. 360 00:19:14,180 --> 00:19:19,490 In particular, over here, in Lisp we have a notation for 361 00:19:19,490 --> 00:19:21,510 distinguishing these meetings. 362 00:19:21,510 --> 00:19:24,992 If I were to just write a plus here, a plus symbol, I would 363 00:19:24,992 --> 00:19:29,400 be asking, is the first element of the expression, is 364 00:19:29,400 --> 00:19:32,220 the operator position of the expression, 365 00:19:32,220 --> 00:19:34,760 the addition operator? 366 00:19:34,760 --> 00:19:36,330 I don't know. 367 00:19:36,330 --> 00:19:39,550 I would have to have written the addition operator there, 368 00:19:39,550 --> 00:19:41,330 which I can't write. 369 00:19:41,330 --> 00:19:45,470 However, this way I'm asking, is this the symbolic object 370 00:19:45,470 --> 00:19:49,790 plus, which normally stands for the addition operator? 371 00:19:49,790 --> 00:19:50,420 That's what I want. 372 00:19:50,420 --> 00:19:53,110 That's the question I want to ask. 373 00:19:53,110 --> 00:19:55,430 Now before I go any further, I want to point out the 374 00:19:55,430 --> 00:19:59,780 quotation is a very complex concept, and adding it to a 375 00:19:59,780 --> 00:20:03,510 language causes a great deal of troubles. 376 00:20:03,510 --> 00:20:06,370 Consider the next slide. 377 00:20:06,370 --> 00:20:11,830 Here's a deduction which we should all agree with. 378 00:20:11,830 --> 00:20:17,530 We have, Alyssa is smart and Alyssa is George's mother. 379 00:20:17,530 --> 00:20:22,350 This is an equality, is. 380 00:20:22,350 --> 00:20:27,470 From those two, we can deduce that George's mother is smart. 381 00:20:27,470 --> 00:20:32,320 Because we can always substitute equals for equals 382 00:20:32,320 --> 00:20:34,250 in expressions. 383 00:20:34,250 --> 00:20:36,420 Or can we? 384 00:20:36,420 --> 00:20:41,400 Here's a case where we have "Chicago" has seven letters. 385 00:20:41,400 --> 00:20:45,100 The quotation means that I'm discussing the word Chicago, 386 00:20:45,100 --> 00:20:46,365 not what the word represents. 387 00:20:46,365 --> 00:20:49,940 388 00:20:49,940 --> 00:20:54,830 Here I have that Chicago is the biggest city in Illinois. 389 00:20:54,830 --> 00:20:57,160 As a consequence of this, I would like to deduce that the 390 00:20:57,160 --> 00:20:59,250 biggest city in Illinois has seven letters. 391 00:20:59,250 --> 00:21:00,785 But that's manifestly false. 392 00:21:00,785 --> 00:21:05,480 393 00:21:05,480 --> 00:21:09,420 Wow, it works. 394 00:21:09,420 --> 00:21:13,420 OK, so once we have things like that, our language gets 395 00:21:13,420 --> 00:21:14,540 much more complicated. 396 00:21:14,540 --> 00:21:17,440 Because it's no longer true that things we tend to like to 397 00:21:17,440 --> 00:21:19,750 do with languages, like substituting equals for equals 398 00:21:19,750 --> 00:21:22,840 and getting right answers, are going to work without being 399 00:21:22,840 --> 00:21:24,550 very careful. 400 00:21:24,550 --> 00:21:26,470 We can't substitute into what's called referentially 401 00:21:26,470 --> 00:21:30,410 opaque contexts, of which a quotation is the prototypical 402 00:21:30,410 --> 00:21:33,380 type of referentially opaque context. 403 00:21:33,380 --> 00:21:35,560 If you know what that means, you can consult a philosopher. 404 00:21:35,560 --> 00:21:38,790 Presumably there is one in the room. 405 00:21:38,790 --> 00:21:42,280 In any case, let's continue now, now that we at least have 406 00:21:42,280 --> 00:21:45,660 an operational understanding of a 2000-year-old issue that 407 00:21:45,660 --> 00:21:47,350 has to do with name, and mention, and all sorts of 408 00:21:47,350 --> 00:21:48,600 things like that. 409 00:21:48,600 --> 00:21:52,440 410 00:21:52,440 --> 00:21:59,790 I have to define what I mean, how to make a sum of two 411 00:21:59,790 --> 00:22:02,250 things, an a1 and a2. 412 00:22:02,250 --> 00:22:03,590 And I'm going to do this very simply. 413 00:22:03,590 --> 00:22:13,600 It's a list of the symbol plus, and a1, and a2. 414 00:22:13,600 --> 00:22:17,075 And I can determine the first element. 415 00:22:17,075 --> 00:22:21,600 416 00:22:21,600 --> 00:22:34,510 Define a1 to be cadr. I've just 417 00:22:34,510 --> 00:22:36,370 introduced another primitive. 418 00:22:36,370 --> 00:22:39,990 This is the car of the cdr of something. 419 00:22:39,990 --> 00:22:43,950 You might want to know why car and cdr are names of these 420 00:22:43,950 --> 00:22:46,720 primitives, and why they've survived, even though they're 421 00:22:46,720 --> 00:22:48,970 much better ideas like left and right. 422 00:22:48,970 --> 00:22:51,380 We could have called them things like that. 423 00:22:51,380 --> 00:22:54,340 Well, first of all, the names come from the fact that in the 424 00:22:54,340 --> 00:22:57,470 great past, when Lisp was invented, I suppose in '58 or 425 00:22:57,470 --> 00:23:00,730 something, it was on a 704 or something like 426 00:23:00,730 --> 00:23:01,870 that, which had a machine. 427 00:23:01,870 --> 00:23:04,440 It was a machine that had an address register and a 428 00:23:04,440 --> 00:23:05,340 decrement register. 429 00:23:05,340 --> 00:23:07,610 And these were the contents of the address register and the 430 00:23:07,610 --> 00:23:08,270 decrement register. 431 00:23:08,270 --> 00:23:09,880 So it's an historical accident. 432 00:23:09,880 --> 00:23:11,880 Now why have these names survived? 433 00:23:11,880 --> 00:23:14,110 It's because Lisp programmers like to talk to each other 434 00:23:14,110 --> 00:23:15,900 over the phone. 435 00:23:15,900 --> 00:23:18,460 And if you want to have a long sequence of cars and cdrs you 436 00:23:18,460 --> 00:23:22,530 might say, cdaddedr, which can be understood. 437 00:23:22,530 --> 00:23:26,330 But left of right or right of left is not so clear if you 438 00:23:26,330 --> 00:23:26,970 get good at it. 439 00:23:26,970 --> 00:23:30,570 So that's why we have these words. 440 00:23:30,570 --> 00:23:33,566 All of them up to four deep are defined typically in a 441 00:23:33,566 --> 00:23:34,816 Lisp system. 442 00:23:34,816 --> 00:23:38,270 443 00:23:38,270 --> 00:23:40,540 A2 to be-- 444 00:23:40,540 --> 00:23:43,540 445 00:23:43,540 --> 00:23:46,170 and, of course, you can see that if I looked at one of 446 00:23:46,170 --> 00:23:54,630 these expressions like the sum of 3 and 5, what that is is a 447 00:23:54,630 --> 00:24:06,100 list containing the symbol plus, and a number 3, 448 00:24:06,100 --> 00:24:11,470 and a number 5. 449 00:24:11,470 --> 00:24:16,100 Then the car is the symbol plus. 450 00:24:16,100 --> 00:24:19,210 The car of the cdr. Well I take the cdr and 451 00:24:19,210 --> 00:24:20,070 then I take the car. 452 00:24:20,070 --> 00:24:21,200 And that's how I get to the 3. 453 00:24:21,200 --> 00:24:22,630 That's the first argument. 454 00:24:22,630 --> 00:24:24,370 And the car of the cdr of the cdr gets me to 455 00:24:24,370 --> 00:24:25,640 this one, the 5. 456 00:24:25,640 --> 00:24:28,860 457 00:24:28,860 --> 00:24:32,970 And similarly, of course, I can define what's going on 458 00:24:32,970 --> 00:24:35,300 with products. 459 00:24:35,300 --> 00:24:36,550 Let's do that very quickly. 460 00:24:36,550 --> 00:24:48,760 461 00:24:48,760 --> 00:24:51,130 Is the expression a product? 462 00:24:51,130 --> 00:25:01,910 Yes if and if it's true, that's it's not atomic and 463 00:25:01,910 --> 00:25:13,260 it's EQ quote, the asterisk symbol, which is the operator 464 00:25:13,260 --> 00:25:15,800 for multiplication. 465 00:25:15,800 --> 00:25:35,090 Make product of an M1 and an M2 to be list, quote, the 466 00:25:35,090 --> 00:25:40,930 asterisk operation and M1 and M2. 467 00:25:40,930 --> 00:26:00,596 and I define M1 to be cadr and M2 to be caddr. You get to be 468 00:26:00,596 --> 00:26:02,690 a good Lisp programmer because you start talking that way. 469 00:26:02,690 --> 00:26:06,430 I cdr down lists and console them up and so on. 470 00:26:06,430 --> 00:26:09,480 Now, now that we have essentially a complete program 471 00:26:09,480 --> 00:26:10,880 for finding derivatives, you can add more 472 00:26:10,880 --> 00:26:12,360 rules if you like. 473 00:26:12,360 --> 00:26:14,800 What kind of behavior do we get out of it? 474 00:26:14,800 --> 00:26:17,930 I'll have to clear that x. 475 00:26:17,930 --> 00:26:28,060 Well, supposing I define foo here to be the sum of the 476 00:26:28,060 --> 00:26:30,450 product of ax square and bx plus c. 477 00:26:30,450 --> 00:26:34,020 That's the same thing we see here as the algebraic 478 00:26:34,020 --> 00:26:35,260 expression written in the more conventional 479 00:26:35,260 --> 00:26:37,860 notation over there. 480 00:26:37,860 --> 00:26:40,620 Well, the derivative of foo with respect to x, which we 481 00:26:40,620 --> 00:26:46,250 can see over here, is this horrible, horrendous mess. 482 00:26:46,250 --> 00:26:50,760 I would like it to be 2ax plus b. 483 00:26:50,760 --> 00:26:52,240 But it's not. 484 00:26:52,240 --> 00:26:54,620 It's equivalent to it. 485 00:26:54,620 --> 00:26:56,090 What is it? 486 00:26:56,090 --> 00:27:00,510 I have here, what do I have? 487 00:27:00,510 --> 00:27:04,550 I have the derivative of the product of x and x. 488 00:27:04,550 --> 00:27:09,410 Over here is, of course, the sum of x times 489 00:27:09,410 --> 00:27:12,830 1 and 1 times x. 490 00:27:12,830 --> 00:27:14,100 Now, well, it's the first times the derivative of the 491 00:27:14,100 --> 00:27:15,330 second plus the second times the derivative of the first. 492 00:27:15,330 --> 00:27:17,780 It's right. 493 00:27:17,780 --> 00:27:20,220 That's 2x of course. 494 00:27:20,220 --> 00:27:26,600 a times 2x is 2ax plus 0X square doesn't count plus B 495 00:27:26,600 --> 00:27:29,100 over here plus a bunch of 0's. 496 00:27:29,100 --> 00:27:30,130 Well the answer is right. 497 00:27:30,130 --> 00:27:34,390 But I give people take off points on an exam for that, 498 00:27:34,390 --> 00:27:35,690 sadly enough. 499 00:27:35,690 --> 00:27:37,830 Let's worry about that in the next segment. 500 00:27:37,830 --> 00:27:39,080 Are there any questions? 501 00:27:39,080 --> 00:27:42,970 502 00:27:42,970 --> 00:27:44,070 Yes? 503 00:27:44,070 --> 00:27:46,790 AUDIENCE: If you had left the quote when you put the plus, 504 00:27:46,790 --> 00:27:51,120 then would that be referring to the procedure plus and 505 00:27:51,120 --> 00:27:53,560 could you do a comparison between that procedure and 506 00:27:53,560 --> 00:27:55,460 some other procedure if you wanted to? 507 00:27:55,460 --> 00:27:56,320 PROFESSOR: Yes. 508 00:27:56,320 --> 00:27:58,960 Good question. 509 00:27:58,960 --> 00:28:05,650 If I had left this quotation off at this point, if I had 510 00:28:05,650 --> 00:28:08,720 left that quotation off at that point, then I would be 511 00:28:08,720 --> 00:28:12,790 referring here to the procedure which is the thing 512 00:28:12,790 --> 00:28:15,510 that plus is defined to be. 513 00:28:15,510 --> 00:28:22,810 And indeed, I could compare some procedures with each 514 00:28:22,810 --> 00:28:25,070 other for identity. 515 00:28:25,070 --> 00:28:28,080 Now what that means is not clear right now. 516 00:28:28,080 --> 00:28:30,100 I don't like to think about it. 517 00:28:30,100 --> 00:28:31,840 Because I don't know exactly what it would need to compare 518 00:28:31,840 --> 00:28:32,450 procedures. 519 00:28:32,450 --> 00:28:35,610 There are reasons why that may make no sense at all. 520 00:28:35,610 --> 00:28:38,890 However, the symbols, we understand. 521 00:28:38,890 --> 00:28:41,240 And so that's why I put that quote in. 522 00:28:41,240 --> 00:28:42,510 I want to talk about the symbol that's 523 00:28:42,510 --> 00:28:43,760 apparent on the page. 524 00:28:43,760 --> 00:28:46,250 525 00:28:46,250 --> 00:28:48,700 Any other questions? 526 00:28:48,700 --> 00:28:50,720 OK. 527 00:28:50,720 --> 00:28:51,060 Thank you. 528 00:28:51,060 --> 00:28:54,210 Let's take a break. 529 00:28:54,210 --> 00:29:30,010 [MUSIC PLAYING] 530 00:29:30,010 --> 00:29:31,580 PROFESSOR: Well, let's see. 531 00:29:31,580 --> 00:29:35,560 We've just developed a fairly plausible program for 532 00:29:35,560 --> 00:29:38,390 computing the derivatives of algebraic expressions. 533 00:29:38,390 --> 00:29:40,400 It's an incomplete program, if you would 534 00:29:40,400 --> 00:29:42,330 like to add more rules. 535 00:29:42,330 --> 00:29:46,020 And perhaps you might extend it to deal with uses of 536 00:29:46,020 --> 00:29:48,390 addition with any number of arguments and multiplication 537 00:29:48,390 --> 00:29:49,950 with any of the number of arguments. 538 00:29:49,950 --> 00:29:52,470 And that's all rather easy. 539 00:29:52,470 --> 00:29:57,620 However, there was a little fly in that ointment. 540 00:29:57,620 --> 00:30:02,980 We go back to this slide. 541 00:30:02,980 --> 00:30:09,000 We see that the expressions that we get are rather bad. 542 00:30:09,000 --> 00:30:11,620 This is a rather bad expression. 543 00:30:11,620 --> 00:30:14,000 How do we get such an expression? 544 00:30:14,000 --> 00:30:16,940 Why do we have that expression? 545 00:30:16,940 --> 00:30:19,060 Let's look at this expression in some detail. 546 00:30:19,060 --> 00:30:21,850 Let's find out where all the pieces come from. 547 00:30:21,850 --> 00:30:24,590 As we see here, we have a sum-- 548 00:30:24,590 --> 00:30:27,012 just what I showed you at the end of the last time-- 549 00:30:27,012 --> 00:30:30,110 of X times 1 plus 1 time X. That is a 550 00:30:30,110 --> 00:30:32,590 derivative of this product. 551 00:30:32,590 --> 00:30:36,270 The produce of a times that, where a does not depend upon 552 00:30:36,270 --> 00:30:40,430 x, and therefore is constant with respect to x, is this 553 00:30:40,430 --> 00:30:43,910 sum, which goes from here all the way through here and 554 00:30:43,910 --> 00:30:44,840 through here. 555 00:30:44,840 --> 00:30:48,470 Because it is the first thing times the derivative of the 556 00:30:48,470 --> 00:30:54,900 second plus the derivative of the first times the second as 557 00:30:54,900 --> 00:30:57,970 the program we wrote on the blackboard 558 00:30:57,970 --> 00:31:00,740 indicated we should do. 559 00:31:00,740 --> 00:31:06,690 And, of course, the product of bx over here manifests itself 560 00:31:06,690 --> 00:31:15,220 as B times 1 plus 0 times X because we see that B does not 561 00:31:15,220 --> 00:31:19,085 depend upon X. And so the derivative of B is this 0, and 562 00:31:19,085 --> 00:31:23,100 the derivative of X with respect itself is the 1. 563 00:31:23,100 --> 00:31:26,510 And, of course, the derivative of the sums over here turn 564 00:31:26,510 --> 00:31:29,360 into these two sums of the derivatives of the parts. 565 00:31:29,360 --> 00:31:32,620 So what we're seeing here is exactly the thing I was trying 566 00:31:32,620 --> 00:31:37,760 to tell you about with Fibonacci numbers a while ago, 567 00:31:37,760 --> 00:31:44,430 that the form of the process is expanded from the local 568 00:31:44,430 --> 00:31:48,850 rules that you see in the procedure, that the procedure 569 00:31:48,850 --> 00:31:51,720 represents a set of local rules for the expansion of 570 00:31:51,720 --> 00:31:53,520 this process. 571 00:31:53,520 --> 00:31:59,440 And here, the process left behind some stuff, which is 572 00:31:59,440 --> 00:32:00,370 the answer. 573 00:32:00,370 --> 00:32:03,850 And it was constructed by the walk it takes of the tree 574 00:32:03,850 --> 00:32:05,775 structure, which is the expression. 575 00:32:05,775 --> 00:32:08,390 576 00:32:08,390 --> 00:32:11,540 So every part in the answer we see here derives from some 577 00:32:11,540 --> 00:32:14,670 part of the problem. 578 00:32:14,670 --> 00:32:17,360 Now, we can look at, for example, the derivative of 579 00:32:17,360 --> 00:32:20,500 foo, which is ax square plus bx plus c, with respect to 580 00:32:20,500 --> 00:32:25,320 other things, like here, for example, we can see that the 581 00:32:25,320 --> 00:32:27,860 derivative of foo with respect to a. 582 00:32:27,860 --> 00:32:29,390 And it's very similar. 583 00:32:29,390 --> 00:32:32,840 It's, in fact, the identical algebraic expression, except 584 00:32:32,840 --> 00:32:34,320 for the fact that theses 0's and 1's are 585 00:32:34,320 --> 00:32:35,900 in different places. 586 00:32:35,900 --> 00:32:38,260 Because the only degree of freedom we have in this tree 587 00:32:38,260 --> 00:32:42,285 walk is what's constant with respect to the variable we're 588 00:32:42,285 --> 00:32:44,550 taking the derivative with respect to and 589 00:32:44,550 --> 00:32:45,800 was the same variable. 590 00:32:45,800 --> 00:32:48,310 591 00:32:48,310 --> 00:32:51,660 In other words, if we go back to this blackboard and we 592 00:32:51,660 --> 00:32:55,302 look, we have no choice what to do when we take the 593 00:32:55,302 --> 00:32:58,150 derivative of the sum or a product. 594 00:32:58,150 --> 00:33:03,840 The only interesting place here is, is the expression the 595 00:33:03,840 --> 00:33:07,590 variable, or is the expression a constant with respect to 596 00:33:07,590 --> 00:33:10,130 that variable for very, very small expressions? 597 00:33:10,130 --> 00:33:13,220 In which case we get various 1's and 0's, which if we go 598 00:33:13,220 --> 00:33:17,290 back to this slide, we can see that the 0's that appear here, 599 00:33:17,290 --> 00:33:21,740 for example, this 1 over here in derivative of foo with 600 00:33:21,740 --> 00:33:25,980 respect to A, which gets us an X square, because that 1 gets 601 00:33:25,980 --> 00:33:32,770 the multiply of X and X into the answer, that 1 is 0. 602 00:33:32,770 --> 00:33:34,173 Over here, we're not taking the derivative of foo with 603 00:33:34,173 --> 00:33:36,690 respect to c. 604 00:33:36,690 --> 00:33:40,301 But the shapes of these expressions are the same. 605 00:33:40,301 --> 00:33:42,561 See all those shapes. 606 00:33:42,561 --> 00:33:43,811 They're the same. 607 00:33:43,811 --> 00:33:50,480 608 00:33:50,480 --> 00:33:53,750 Well is there anything wrong with our rules? 609 00:33:53,750 --> 00:33:54,030 No. 610 00:33:54,030 --> 00:33:56,250 They're the right rules. 611 00:33:56,250 --> 00:33:58,160 We've been through this one before. 612 00:33:58,160 --> 00:34:02,020 One of the things you're going to begin to discover is that 613 00:34:02,020 --> 00:34:03,270 there aren't too many good ideas. 614 00:34:03,270 --> 00:34:06,510 615 00:34:06,510 --> 00:34:12,139 When we were looking at rational numbers yesterday, 616 00:34:12,139 --> 00:34:14,909 the problem was that we got 6/8 rather then 3/4. 617 00:34:14,909 --> 00:34:17,949 The answer was unsimplified. 618 00:34:17,949 --> 00:34:21,150 The problem, of course, is very similar. 619 00:34:21,150 --> 00:34:24,350 There are things I'd like to be identical by simplification 620 00:34:24,350 --> 00:34:27,350 that don't become identical. 621 00:34:27,350 --> 00:34:30,690 And yet the rules for doing addition a multiplication of 622 00:34:30,690 --> 00:34:34,000 rational numbers were correct. 623 00:34:34,000 --> 00:34:36,350 So the way we might solve this problem is do the thing we did 624 00:34:36,350 --> 00:34:37,940 last time, which always works. 625 00:34:37,940 --> 00:34:40,690 If something worked last time it ought to work again. 626 00:34:40,690 --> 00:34:43,120 It's changed representation. 627 00:34:43,120 --> 00:34:45,350 Perhaps in the representation we could put in a 628 00:34:45,350 --> 00:34:48,940 simplification step that produces a simplified 629 00:34:48,940 --> 00:34:50,199 representation. 630 00:34:50,199 --> 00:34:52,580 This may not always work, of course. 631 00:34:52,580 --> 00:34:55,210 I'm not trying to say that it always works. 632 00:34:55,210 --> 00:34:59,540 But it's one of the pieces of artillery we have in our war 633 00:34:59,540 --> 00:35:01,560 against complexity. 634 00:35:01,560 --> 00:35:04,360 You see, because we solved our problem very carefully. 635 00:35:04,360 --> 00:35:06,170 What we've done, is we've divided the 636 00:35:06,170 --> 00:35:07,630 world in several parts. 637 00:35:07,630 --> 00:35:12,980 There are derivatives rules and general rules for algebra 638 00:35:12,980 --> 00:35:16,420 of some sort at this level of detail. 639 00:35:16,420 --> 00:35:17,925 and i have an abstraction barrier. 640 00:35:17,925 --> 00:35:21,874 641 00:35:21,874 --> 00:35:32,710 And i have the representation of the algebraic expressions, 642 00:35:32,710 --> 00:35:33,960 list structure. 643 00:35:33,960 --> 00:35:37,420 644 00:35:37,420 --> 00:35:43,050 And in this barrier, I have the interface procedures. 645 00:35:43,050 --> 00:35:49,410 I have constant, and things like same-var. 646 00:35:49,410 --> 00:35:54,680 647 00:35:54,680 --> 00:35:58,095 I have things like sum, make-sum. 648 00:35:58,095 --> 00:36:02,310 649 00:36:02,310 --> 00:36:06,770 I have A1, A2. 650 00:36:06,770 --> 00:36:09,370 I have products and things like that, all the other 651 00:36:09,370 --> 00:36:11,490 things I might need for various kinds of algebraic 652 00:36:11,490 --> 00:36:13,000 expressions. 653 00:36:13,000 --> 00:36:18,080 Making this barrier allows me to arbitrarily change the 654 00:36:18,080 --> 00:36:21,710 representation without changing the rules that are 655 00:36:21,710 --> 00:36:25,060 written in terms of that representation. 656 00:36:25,060 --> 00:36:28,220 So if I can make the problem go away by changing 657 00:36:28,220 --> 00:36:32,320 representation, the composition of the problem 658 00:36:32,320 --> 00:36:35,660 into these two parts has helped me a great deal. 659 00:36:35,660 --> 00:36:38,860 So let's take a very simple case of this. 660 00:36:38,860 --> 00:36:40,330 What was one of the problems? 661 00:36:40,330 --> 00:36:44,115 Let's go back to this transparency again. 662 00:36:44,115 --> 00:36:48,280 And we see here, oh yes, there's horrible things like 663 00:36:48,280 --> 00:36:53,190 here is the sum of an expression and 0. 664 00:36:53,190 --> 00:36:55,590 Well that's no reason to think of it as anything other than 665 00:36:55,590 --> 00:36:57,300 the expression itself. 666 00:36:57,300 --> 00:36:59,970 Why should the summation operation have 667 00:36:59,970 --> 00:37:03,450 made up this edition? 668 00:37:03,450 --> 00:37:05,550 It can be smarter than that. 669 00:37:05,550 --> 00:37:09,080 Or here, for example, is a multiplication of 670 00:37:09,080 --> 00:37:10,816 something by 1. 671 00:37:10,816 --> 00:37:12,990 It's another thing like that. 672 00:37:12,990 --> 00:37:14,960 Or here is a product of something with 0, which is 673 00:37:14,960 --> 00:37:17,800 certainly 0. 674 00:37:17,800 --> 00:37:21,430 So we won't have to make this construction. 675 00:37:21,430 --> 00:37:23,800 So why don't we just do that? 676 00:37:23,800 --> 00:37:25,340 We need to change the way the representation 677 00:37:25,340 --> 00:37:27,990 works, almost here. 678 00:37:27,990 --> 00:37:37,500 679 00:37:37,500 --> 00:37:42,060 Make-sum to be. 680 00:37:42,060 --> 00:37:44,020 Well, now it's not something so simple. 681 00:37:44,020 --> 00:37:48,500 I'm not going to make a list containing the symbol plus and 682 00:37:48,500 --> 00:37:51,322 things unless I need to. 683 00:37:51,322 --> 00:37:52,630 Well, what are the possibilities? 684 00:37:52,630 --> 00:37:57,220 685 00:37:57,220 --> 00:37:59,420 I have some sort of cases here. 686 00:37:59,420 --> 00:38:09,160 If I have numbers, if anyone is a number-- 687 00:38:09,160 --> 00:38:10,930 and here's another primitive I've just introduced, it's 688 00:38:10,930 --> 00:38:15,230 possible to tell whether something's number-- 689 00:38:15,230 --> 00:38:23,090 and if number A2, meaning they're not symbolic 690 00:38:23,090 --> 00:38:26,280 expressions, then why not do the addition now? 691 00:38:26,280 --> 00:38:29,540 The result is just a plus of A1 and A2. 692 00:38:29,540 --> 00:38:32,270 693 00:38:32,270 --> 00:38:34,000 I'm not asking if these represent numbers. 694 00:38:34,000 --> 00:38:37,100 Of course all of these symbols represent numbers. 695 00:38:37,100 --> 00:38:39,100 I'm talking about whether the one I've got is the 696 00:38:39,100 --> 00:38:43,420 number 3 right now. 697 00:38:43,420 --> 00:38:59,070 And, for example, supposing A1 is a number, and it's equal to 698 00:38:59,070 --> 00:39:06,900 0, well then the answer is just A2. 699 00:39:06,900 --> 00:39:10,698 There is no reason to make anything up. 700 00:39:10,698 --> 00:39:27,630 And if A2 is a number, and equal A20, then 701 00:39:27,630 --> 00:39:30,210 the result is A1. 702 00:39:30,210 --> 00:39:32,770 And only if I can't figure out something better to do with 703 00:39:32,770 --> 00:39:41,160 this situation, well, I can start a list. Otherwise I want 704 00:39:41,160 --> 00:39:45,790 the representation to be the list containing the quoted 705 00:39:45,790 --> 00:39:51,850 symbol plus, and A1, and A2. 706 00:39:51,850 --> 00:39:58,720 707 00:39:58,720 --> 00:40:00,660 And, of course, a very similar thing 708 00:40:00,660 --> 00:40:03,020 can be done for products. 709 00:40:03,020 --> 00:40:05,650 And I think I'll avoid boring you with them. 710 00:40:05,650 --> 00:40:07,740 I was going to write it on the blackboard. 711 00:40:07,740 --> 00:40:09,080 I don't think it's necessary. 712 00:40:09,080 --> 00:40:10,830 You know what to do. 713 00:40:10,830 --> 00:40:12,880 It's very simple. 714 00:40:12,880 --> 00:40:17,890 But now, let's just see the kind of results we get out of 715 00:40:17,890 --> 00:40:21,870 changing our program in this way. 716 00:40:21,870 --> 00:40:25,920 Well, here's the derivatives after having just changed the 717 00:40:25,920 --> 00:40:28,810 constructors for expressions. 718 00:40:28,810 --> 00:40:35,810 The same foo, aX square plus bX plus c, and what I get is 719 00:40:35,810 --> 00:40:40,265 nothing more than the derivative of that is 2aX plus 720 00:40:40,265 --> 00:40:40,660 B. 721 00:40:40,660 --> 00:40:42,670 Well, it's not completely simplified. 722 00:40:42,670 --> 00:40:45,170 I would like to collect common terms and sums. 723 00:40:45,170 --> 00:40:47,180 Well, that's more work. 724 00:40:47,180 --> 00:40:51,130 And, of course, programs to do this sort of thing are huge 725 00:40:51,130 --> 00:40:52,440 and complicated. 726 00:40:52,440 --> 00:40:56,510 Algebraic simplification, it's a very complicated mess. 727 00:40:56,510 --> 00:40:58,240 There's a very famous program you may have heard of called 728 00:40:58,240 --> 00:41:02,750 Maxima developed at MIT in the past, which is 5,000 pages of 729 00:41:02,750 --> 00:41:05,830 Lisp code, mostly the algebraic simplification 730 00:41:05,830 --> 00:41:07,080 operations. 731 00:41:07,080 --> 00:41:10,080 732 00:41:10,080 --> 00:41:12,210 There we see the derivative of foo. 733 00:41:12,210 --> 00:41:14,390 In fact, X is at something I wouldn't take off more than 1 734 00:41:14,390 --> 00:41:18,390 point for on an elementary calculus class. 735 00:41:18,390 --> 00:41:20,960 And the derivative of foo with respect to a, well it's gone 736 00:41:20,960 --> 00:41:24,730 down to X times X, which isn't so bad. 737 00:41:24,730 --> 00:41:28,200 And the derivative of foo with respect to b is just X itself. 738 00:41:28,200 --> 00:41:30,730 And the derivative of foo with respect to c comes out 1. 739 00:41:30,730 --> 00:41:34,260 So I'm pretty pleased with this. 740 00:41:34,260 --> 00:41:36,830 What you've seen is, of course, a little bit 741 00:41:36,830 --> 00:41:41,020 contrived, carefully organized example to show you how we can 742 00:41:41,020 --> 00:41:43,610 manipulate algebraic expressions, how we do that 743 00:41:43,610 --> 00:41:46,890 abstractly in terms of abstract syntax rather than 744 00:41:46,890 --> 00:41:53,910 concrete syntax and how we can use the abstraction to control 745 00:41:53,910 --> 00:41:57,850 what goes on in building these expressions. 746 00:41:57,850 --> 00:42:00,910 But the real story isn't just such a simple thing as that. 747 00:42:00,910 --> 00:42:03,890 The real story is, in fact, that I'm manipulating these 748 00:42:03,890 --> 00:42:04,450 expressions. 749 00:42:04,450 --> 00:42:06,860 And the expressions are the same expressions-- 750 00:42:06,860 --> 00:42:08,150 going back to the slide-- 751 00:42:08,150 --> 00:42:12,110 as the ones that are Lisp expressions. 752 00:42:12,110 --> 00:42:13,890 There's a pun here. 753 00:42:13,890 --> 00:42:17,020 I've chosen my representation to be the same as the 754 00:42:17,020 --> 00:42:22,830 representation in my language of similar things. 755 00:42:22,830 --> 00:42:26,990 By doing so, I've invoked a necessity. 756 00:42:26,990 --> 00:42:30,890 I created the necessity to have things like quotation 757 00:42:30,890 --> 00:42:35,690 because of the fact that my language is capable of writing 758 00:42:35,690 --> 00:42:39,820 expressions that talk about expressions of the language. 759 00:42:39,820 --> 00:42:42,420 I need to have something that says, this is an expression 760 00:42:42,420 --> 00:42:45,320 I'm talking about rather than this expression is talking 761 00:42:45,320 --> 00:42:48,400 about something, and I want to talk about that. 762 00:42:48,400 --> 00:42:51,290 763 00:42:51,290 --> 00:42:54,420 So quotation stops and says, I'm talking about this 764 00:42:54,420 --> 00:42:55,670 expression itself. 765 00:42:55,670 --> 00:42:58,140 766 00:42:58,140 --> 00:43:03,030 Now, given that power, if I can manipulate expressions of 767 00:43:03,030 --> 00:43:07,370 the language, I can begin to build even much more powerful 768 00:43:07,370 --> 00:43:09,860 layers upon layers of languages. 769 00:43:09,860 --> 00:43:12,370 Because I can write languages that not only are embedded in 770 00:43:12,370 --> 00:43:16,730 Lisp or whatever language you start with, but languages that 771 00:43:16,730 --> 00:43:20,400 are completely different, that are just, if we say, 772 00:43:20,400 --> 00:43:23,280 interpreted in Lisp or something like that. 773 00:43:23,280 --> 00:43:26,232 We'll get to understand those words more in the future. 774 00:43:26,232 --> 00:43:30,150 But right now I just want to leave you with the fact that 775 00:43:30,150 --> 00:43:36,160 we've hit a line which gives us tremendous power. 776 00:43:36,160 --> 00:43:37,900 And this point we've bought a sledgehammer. 777 00:43:37,900 --> 00:43:42,250 We have to be careful to what flies when we apply it. 778 00:43:42,250 --> 00:43:42,570 Thank you. 779 00:43:42,570 --> 00:43:43,820 [MUSIC PLAYING] 780 00:43:43,820 --> 00:44:03,796 ================================================ FILE: SrtEN/lec4a_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:24,460 1 00:00:24,460 --> 00:00:28,270 PROFESSOR: Well, yesterday we learned a bit about symbolic 2 00:00:28,270 --> 00:00:35,140 manipulation, and we wrote a rather stylized program to 3 00:00:35,140 --> 00:00:40,620 implement a pile of calculus rule from the calculus book. 4 00:00:40,620 --> 00:00:47,790 Here on the transparencies, we see a bunch of calculus rules 5 00:00:47,790 --> 00:00:49,470 from such a book. 6 00:00:49,470 --> 00:00:53,030 And, of course, what we did is sort of translate these rules 7 00:00:53,030 --> 00:00:56,040 into the language of the computer. 8 00:00:56,040 --> 00:00:59,340 But, of course, that's a sort of funny strategy. 9 00:00:59,340 --> 00:01:03,570 Why should we have to translate these rules into the 10 00:01:03,570 --> 00:01:04,989 language of the computer? 11 00:01:04,989 --> 00:01:07,320 And what do I really mean by that? 12 00:01:07,320 --> 00:01:08,170 These are--the program we wrote 13 00:01:08,170 --> 00:01:11,240 yesterday was very stylized. 14 00:01:11,240 --> 00:01:15,210 It was a conditional, a dispatch on the type of the 15 00:01:15,210 --> 00:01:19,660 expression as observed by the rules. 16 00:01:19,660 --> 00:01:23,450 What we see here are rules that say if the object being 17 00:01:23,450 --> 00:01:26,850 the derivative is being taken of, if that expression is a 18 00:01:26,850 --> 00:01:29,350 constant, then do one thing. 19 00:01:29,350 --> 00:01:31,590 If it's a variable, do another thing. 20 00:01:31,590 --> 00:01:34,040 If it's a product of a constant times a variable, do 21 00:01:34,040 --> 00:01:36,220 something and so on. 22 00:01:36,220 --> 00:01:38,630 There's sort of a dispatch there on a type. 23 00:01:38,630 --> 00:01:41,750 24 00:01:41,750 --> 00:01:44,260 Well, since it has such a stylized behavior and 25 00:01:44,260 --> 00:01:48,110 structure, is there some other way of writing this program 26 00:01:48,110 --> 00:01:50,401 that's more clear? 27 00:01:50,401 --> 00:01:52,280 Well, what's a rule, first of all? 28 00:01:52,280 --> 00:01:53,530 What are these rules? 29 00:01:53,530 --> 00:01:55,960 30 00:01:55,960 --> 00:01:57,130 Let's think about that. 31 00:01:57,130 --> 00:01:58,910 Rules have parts. 32 00:01:58,910 --> 00:02:04,400 If you look at these rules in detail, what you see, for 33 00:02:04,400 --> 00:02:08,750 example, is the rule has a left-hand side and a 34 00:02:08,750 --> 00:02:10,940 right-hand side. 35 00:02:10,940 --> 00:02:13,220 Each of these rules has a left-hand side and the 36 00:02:13,220 --> 00:02:14,960 right-hand side. 37 00:02:14,960 --> 00:02:18,640 The left-hand side is somehow compared with the expression 38 00:02:18,640 --> 00:02:21,250 you're trying to take the derivative of. 39 00:02:21,250 --> 00:02:24,440 The right-hand side is the replacement for that 40 00:02:24,440 --> 00:02:25,690 expression. 41 00:02:25,690 --> 00:02:28,410 42 00:02:28,410 --> 00:02:33,070 So all rules on this page are something like this. 43 00:02:33,070 --> 00:02:35,900 44 00:02:35,900 --> 00:02:45,990 I have patterns, and somehow, I have to produce, given a 45 00:02:45,990 --> 00:02:47,845 pattern, a skeleton. 46 00:02:47,845 --> 00:02:51,700 47 00:02:51,700 --> 00:02:52,950 This is a rule. 48 00:02:52,950 --> 00:02:55,420 49 00:02:55,420 --> 00:02:58,650 A pattern is something that matches, and a skeleton is 50 00:02:58,650 --> 00:03:02,470 something you substitute into in order to get a new 51 00:03:02,470 --> 00:03:03,720 expression. 52 00:03:03,720 --> 00:03:06,410 53 00:03:06,410 --> 00:03:12,960 So what that means is that the pattern is matched against the 54 00:03:12,960 --> 00:03:15,910 expression, which is the source expression. 55 00:03:15,910 --> 00:03:23,730 56 00:03:23,730 --> 00:03:26,620 And the result of the application of the rule is to 57 00:03:26,620 --> 00:03:38,070 produce a new expression, which I'll call a target, by 58 00:03:38,070 --> 00:03:41,620 instantiation of a skeleton. 59 00:03:41,620 --> 00:03:42,870 That's called instantiation. 60 00:03:42,870 --> 00:03:50,580 61 00:03:50,580 --> 00:03:52,530 So that is the process by which 62 00:03:52,530 --> 00:03:55,780 these rules are described. 63 00:03:55,780 --> 00:04:02,680 What I'd like to do today is build a language and a means 64 00:04:02,680 --> 00:04:04,950 of interpreting that language, a means of executing that 65 00:04:04,950 --> 00:04:07,770 language, where that language allows us to directly express 66 00:04:07,770 --> 00:04:10,550 these rules. 67 00:04:10,550 --> 00:04:14,150 And what we're going to do is instead of bringing the rules 68 00:04:14,150 --> 00:04:16,920 to the level of the computer by writing a program that is 69 00:04:16,920 --> 00:04:20,279 those rules in the computer's language-- 70 00:04:20,279 --> 00:04:22,170 at the moment, in a Lisp-- 71 00:04:22,170 --> 00:04:25,740 we're going to bring the computer to the level of us by 72 00:04:25,740 --> 00:04:28,400 writing a way by which the computer can understand rules 73 00:04:28,400 --> 00:04:30,670 of this sort. 74 00:04:30,670 --> 00:04:35,210 This is slightly emphasizing the idea that we had last time 75 00:04:35,210 --> 00:04:37,560 that we're trying to make a solution to a class of 76 00:04:37,560 --> 00:04:39,630 problems rather than a particular one. 77 00:04:39,630 --> 00:04:45,740 The problem is if I want to write rules for a different 78 00:04:45,740 --> 00:04:49,990 piece of mathematics, say, to simple algebraic 79 00:04:49,990 --> 00:04:54,050 simplification or something like that, or manipulation of 80 00:04:54,050 --> 00:04:57,160 trigonometric functions, I would have to write a 81 00:04:57,160 --> 00:05:01,130 different program in using yesterday's method. 82 00:05:01,130 --> 00:05:03,550 Whereas I would like to encapsulate all of the things 83 00:05:03,550 --> 00:05:06,770 that are common to both of those programs, meaning the 84 00:05:06,770 --> 00:05:09,870 idea of matching, instantiation, the control 85 00:05:09,870 --> 00:05:12,090 structure, which turns out to be very complicated for such a 86 00:05:12,090 --> 00:05:17,420 thing, I'd like to encapsulate that separately from the rules 87 00:05:17,420 --> 00:05:20,010 themselves. 88 00:05:20,010 --> 00:05:22,730 So let's look at, first of all, a representation. 89 00:05:22,730 --> 00:05:24,670 I'd like to use the overhead here. 90 00:05:24,670 --> 00:05:25,975 I'd like-- there it is. 91 00:05:25,975 --> 00:05:29,440 I'd like to look at a representation of the rules of 92 00:05:29,440 --> 00:05:36,010 calculus for derivatives in a sort of simple language that 93 00:05:36,010 --> 00:05:38,140 I'm writing right here. 94 00:05:38,140 --> 00:05:41,420 Now, I'm going to avoid--I'm going to avoid 95 00:05:41,420 --> 00:05:44,250 worrying about syntax. 96 00:05:44,250 --> 00:05:48,340 We can easily pretty this, and I'm not interested in making-- 97 00:05:48,340 --> 00:05:49,230 this is indeed ugly. 98 00:05:49,230 --> 00:05:54,810 This doesn't look like the beautiful text set dx by dt or 99 00:05:54,810 --> 00:05:56,730 something that I'd like to write, 100 00:05:56,730 --> 00:05:58,710 but that's not essential. 101 00:05:58,710 --> 00:06:00,480 That's sort of an accidental phenomenon. 102 00:06:00,480 --> 00:06:03,220 Here, we're just worrying about the fact that the 103 00:06:03,220 --> 00:06:07,060 structure of the rules is that there is a left-hand side 104 00:06:07,060 --> 00:06:10,510 here, represents the thing I want to match against the 105 00:06:10,510 --> 00:06:11,720 derivative expression. 106 00:06:11,720 --> 00:06:14,140 This is the representation I'm going to say for the 107 00:06:14,140 --> 00:06:18,980 derivative of a constant, which we will call c with 108 00:06:18,980 --> 00:06:23,730 respect to the variable we will call v. And what we will 109 00:06:23,730 --> 00:06:26,010 get on the right-hand side is 0. 110 00:06:26,010 --> 00:06:29,620 So this represents a rule. 111 00:06:29,620 --> 00:06:32,980 The next rule will be the derivative of a variable, 112 00:06:32,980 --> 00:06:36,010 which we will call v with respect to the same variable 113 00:06:36,010 --> 00:06:38,560 v, and we get a 1. 114 00:06:38,560 --> 00:06:41,360 However, if we have the derivative of a variable 115 00:06:41,360 --> 00:06:44,490 called u with respect to a different variables 116 00:06:44,490 --> 00:06:47,790 v, we will get 0. 117 00:06:47,790 --> 00:06:50,880 I just want you look at these rules a little bit and see how 118 00:06:50,880 --> 00:06:52,750 they fit together. 119 00:06:52,750 --> 00:06:56,310 For example, over here, we're going to have the derivative 120 00:06:56,310 --> 00:07:00,360 of the sum of an expression called x1 and an 121 00:07:00,360 --> 00:07:01,790 expression called x2. 122 00:07:01,790 --> 00:07:04,960 These things that begin with question marks are called 123 00:07:04,960 --> 00:07:08,910 pattern variables in the language that we're inventing, 124 00:07:08,910 --> 00:07:12,820 and you see we're just making it up, so pattern variables 125 00:07:12,820 --> 00:07:14,960 for matching. 126 00:07:14,960 --> 00:07:16,050 And so in this-- 127 00:07:16,050 --> 00:07:19,140 here we have the derivative of the sum of the expression 128 00:07:19,140 --> 00:07:20,380 which we will call x1. 129 00:07:20,380 --> 00:07:23,150 And the expression we will call x2 with respect to the 130 00:07:23,150 --> 00:07:26,500 variable we call v will be-- here is the right-hand side: 131 00:07:26,500 --> 00:07:29,700 the sum of the derivative of that expression x1 with 132 00:07:29,700 --> 00:07:33,910 respect to v-- the right-hand side is the skeleton-- 133 00:07:33,910 --> 00:07:38,950 and the derivative of x2 with respect to v. Colons here will 134 00:07:38,950 --> 00:07:42,170 stand for substitution objects. 135 00:07:42,170 --> 00:07:44,690 136 00:07:44,690 --> 00:07:48,480 They're--we'll call them skeleton evaluations. 137 00:07:48,480 --> 00:07:52,420 So let me put up here on the blackboard for a second some 138 00:07:52,420 --> 00:07:54,380 syntax so we'll know what's going on 139 00:07:54,380 --> 00:07:56,620 for this rule language. 140 00:07:56,620 --> 00:07:58,730 First of all, we're going to have to worry about the 141 00:07:58,730 --> 00:07:59,980 pattern matching. 142 00:07:59,980 --> 00:08:05,790 143 00:08:05,790 --> 00:08:11,950 We're going to have things like a symbol like foo matches 144 00:08:11,950 --> 00:08:13,200 exactly itself. 145 00:08:13,200 --> 00:08:23,170 146 00:08:23,170 --> 00:08:35,919 The expression f of a and b will be used to match any list 147 00:08:35,919 --> 00:08:51,130 whose first element is f, whose second element is a, and 148 00:08:51,130 --> 00:08:58,550 whose third element is b. 149 00:08:58,550 --> 00:09:03,200 Also, another thing we might have in a pattern is that-- 150 00:09:03,200 --> 00:09:08,150 a question mark with some variable like x. 151 00:09:08,150 --> 00:09:17,965 And what that means, it says matches anything, which we 152 00:09:17,965 --> 00:09:19,215 will call x. 153 00:09:19,215 --> 00:09:25,610 154 00:09:25,610 --> 00:09:30,922 Question mark c x will match only constants. 155 00:09:30,922 --> 00:09:41,140 So this is something which matches a constant colon x. 156 00:09:41,140 --> 00:09:44,620 157 00:09:44,620 --> 00:09:55,920 And question mark v x will match a variable, 158 00:09:55,920 --> 00:09:57,170 which we call x. 159 00:09:57,170 --> 00:10:01,690 160 00:10:01,690 --> 00:10:04,140 This is sort of the language we're making up now. 161 00:10:04,140 --> 00:10:07,240 If I match two things against each other, then they are 162 00:10:07,240 --> 00:10:10,200 compared element by element. 163 00:10:10,200 --> 00:10:13,630 But elements in the pattern may contain these syntactic 164 00:10:13,630 --> 00:10:19,310 variables, pattern variables, which will be used to match 165 00:10:19,310 --> 00:10:22,160 arbitrary objects. 166 00:10:22,160 --> 00:10:28,480 And we'll get that object as the value in the name x here, 167 00:10:28,480 --> 00:10:31,030 for example. 168 00:10:31,030 --> 00:10:39,290 Now, when we make skeletons for instantiation. 169 00:10:39,290 --> 00:10:42,320 Well, then we have things like this. 170 00:10:42,320 --> 00:10:46,160 foo, a symbol, instantiates to itself. 171 00:10:46,160 --> 00:10:55,020 172 00:10:55,020 --> 00:10:59,630 Something which is a list like f of a and b, 173 00:10:59,630 --> 00:11:06,350 instantiates to-- 174 00:11:06,350 --> 00:11:14,270 well, f instantiates to a 3-list, a list of three 175 00:11:14,270 --> 00:11:27,420 elements, okay, which are the results of instantiating each 176 00:11:27,420 --> 00:11:33,320 of f, a, and b. 177 00:11:33,320 --> 00:11:36,310 178 00:11:36,310 --> 00:11:53,470 And x well--we instantiate to the value of x as in the 179 00:11:53,470 --> 00:11:54,720 matched pattern. 180 00:11:54,720 --> 00:12:02,960 181 00:12:02,960 --> 00:12:08,630 So going back to the overhead here, we see--we see that all 182 00:12:08,630 --> 00:12:14,040 of those kinds of objects, we see here a pattern variable 183 00:12:14,040 --> 00:12:18,180 which matches a constant, a pattern variable which matches 184 00:12:18,180 --> 00:12:22,660 a variable, a pattern variable which will match anything. 185 00:12:22,660 --> 00:12:25,810 And if we have two instances of the same name, like this is 186 00:12:25,810 --> 00:12:29,840 the derivative of the expression which is a variable 187 00:12:29,840 --> 00:12:34,510 only whose name will be v with respect to some arbitrary 188 00:12:34,510 --> 00:12:38,560 expression which we will call v, since this v appears twice, 189 00:12:38,560 --> 00:12:42,770 we're going to want that to mean they have to be the same. 190 00:12:42,770 --> 00:12:45,630 The only consistent match is that those are the same. 191 00:12:45,630 --> 00:12:48,170 So here, we're making up a language. 192 00:12:48,170 --> 00:12:50,440 And in fact, that's a very nice thing to be doing. 193 00:12:50,440 --> 00:12:52,555 It's so much fun to make up a language. 194 00:12:52,555 --> 00:12:54,320 And you do this all the time. 195 00:12:54,320 --> 00:12:57,390 And the really most powerful design things you ever do are 196 00:12:57,390 --> 00:13:02,050 sort of making up a language to solve problems like this. 197 00:13:02,050 --> 00:13:05,780 Now, here we go back here and look at some of these rules. 198 00:13:05,780 --> 00:13:07,070 Well, there's a whole set of them. 199 00:13:07,070 --> 00:13:10,540 I mean, there's one for addition and one for 200 00:13:10,540 --> 00:13:12,390 multiplication, just like we had before. 201 00:13:12,390 --> 00:13:16,900 The derivative of the product of x1 and x2 with respect to v 202 00:13:16,900 --> 00:13:22,660 is the sum of the product of x1 and the derivative x2 with 203 00:13:22,660 --> 00:13:24,750 respect to v and the product of the 204 00:13:24,750 --> 00:13:27,200 derivative of x1 and x2. 205 00:13:27,200 --> 00:13:29,180 And here we have exponentiation. 206 00:13:29,180 --> 00:13:30,880 And, of course, we run off the end down here. 207 00:13:30,880 --> 00:13:32,540 We get as many as we like. 208 00:13:32,540 --> 00:13:36,270 But the whole thing over here, I'm giving this--this list of 209 00:13:36,270 --> 00:13:40,910 rules the name "derivative rules." 210 00:13:40,910 --> 00:13:45,240 What would we do with such a thing once we have it? 211 00:13:45,240 --> 00:13:49,080 Well, one of the nicest ideas, first of all, is I'm going to 212 00:13:49,080 --> 00:13:52,230 write for you, and we're going to play with it all day. 213 00:13:52,230 --> 00:13:56,680 What I'm going to write for you is a program called 214 00:13:56,680 --> 00:14:00,150 simplifier, the general-purpose simplifier. 215 00:14:00,150 --> 00:14:09,150 And we're going to say something like define dsimp to 216 00:14:09,150 --> 00:14:17,260 be a simplifier of the derivative rules. 217 00:14:17,260 --> 00:14:23,740 218 00:14:23,740 --> 00:14:26,390 And what simplifier is going to do is, given a set of 219 00:14:26,390 --> 00:14:29,670 rules, it will produce for me a procedure which will 220 00:14:29,670 --> 00:14:33,200 simplify expressions containing the things that are 221 00:14:33,200 --> 00:14:34,680 referred to by these rules. 222 00:14:34,680 --> 00:14:37,360 223 00:14:37,360 --> 00:14:42,110 So here will be a procedure constructed for your purposes 224 00:14:42,110 --> 00:14:45,150 to simplify things with derivatives in them such that, 225 00:14:45,150 --> 00:14:49,050 after that, if we're typing at some list system, and we get a 226 00:14:49,050 --> 00:14:58,030 prompt, and we say dsimp, for example, of the derivative of 227 00:14:58,030 --> 00:15:03,885 the sum of x and y with respect to x-- 228 00:15:03,885 --> 00:15:06,990 229 00:15:06,990 --> 00:15:08,740 note the quote here because I'm talking about the 230 00:15:08,740 --> 00:15:10,660 expression which is the derivative-- 231 00:15:10,660 --> 00:15:13,310 232 00:15:13,310 --> 00:15:19,970 then I will get back as a result plus 1 0. 233 00:15:19,970 --> 00:15:23,760 Because the derivative of x plus y is the derivative of x 234 00:15:23,760 --> 00:15:24,490 plus derivative y. 235 00:15:24,490 --> 00:15:26,300 The derivative of x with respect to x is 1. 236 00:15:26,300 --> 00:15:29,260 The derivative of y with respect to x is 0. 237 00:15:29,260 --> 00:15:31,170 It's not what we're going to get. 238 00:15:31,170 --> 00:15:33,280 I haven't put any simplification at that level-- 239 00:15:33,280 --> 00:15:34,440 algebraic simplification-- 240 00:15:34,440 --> 00:15:36,010 yet. 241 00:15:36,010 --> 00:15:39,702 Of course, once we have such a thing, then we can--then we 242 00:15:39,702 --> 00:15:42,340 can look at other rules. 243 00:15:42,340 --> 00:15:49,310 So, for example, we can, if we go to the slide, OK? 244 00:15:49,310 --> 00:15:52,480 Here, for example, are other rules that we might have, 245 00:15:52,480 --> 00:15:56,780 algebraic manipulation rules, ones that would be used for 246 00:15:56,780 --> 00:15:58,960 simplifying algebraic expressions. 247 00:15:58,960 --> 00:16:04,470 For example, just looking at some of these, the left-hand 248 00:16:04,470 --> 00:16:08,220 side says any operator applied to a constant e1 and a 249 00:16:08,220 --> 00:16:12,310 constant e2 is the result of evaluating that operator on 250 00:16:12,310 --> 00:16:15,850 the constants e1 and e2. 251 00:16:15,850 --> 00:16:20,660 Or an operator, applied to e1, any expression e1 and a 252 00:16:20,660 --> 00:16:24,520 constant e2, is going to move the constant forward. 253 00:16:24,520 --> 00:16:25,980 So that'll turn into the operator with 254 00:16:25,980 --> 00:16:28,770 e2 followed by e1. 255 00:16:28,770 --> 00:16:30,200 Why I did that, I don't know. 256 00:16:30,200 --> 00:16:33,560 It wouldn't work if I had division, for example. 257 00:16:33,560 --> 00:16:36,610 So there's a bug in the rules, if you like. 258 00:16:36,610 --> 00:16:42,120 So the sum of 0 and e is e. 259 00:16:42,120 --> 00:16:46,110 The product of 1 and any expression e is e. 260 00:16:46,110 --> 00:16:49,520 The product of 0 and any expression e is 0. 261 00:16:49,520 --> 00:16:51,130 Just looking at some more of these rules, we could have 262 00:16:51,130 --> 00:16:53,670 arbitrarily complicated ones. 263 00:16:53,670 --> 00:16:59,050 We could have things like the product of the constant e1 and 264 00:16:59,050 --> 00:17:04,230 any constant e2 with e3 is the result of multiplying the 265 00:17:04,230 --> 00:17:10,310 result of--multiplying now the constants e1 and e2 together 266 00:17:10,310 --> 00:17:13,319 and putting e3 there. 267 00:17:13,319 --> 00:17:16,760 So it says combine the constants that I had, which 268 00:17:16,760 --> 00:17:20,480 was if I had a product of e1 and e2 and e3 just multiply--I 269 00:17:20,480 --> 00:17:23,800 mean and e1 and e2 are both constants, multiply them. 270 00:17:23,800 --> 00:17:25,690 And you can make up the rules as you like. 271 00:17:25,690 --> 00:17:27,619 There are lots of them here. 272 00:17:27,619 --> 00:17:31,300 There are things as complicated, for example, as-- 273 00:17:31,300 --> 00:17:33,910 oh, I suppose down here some distributive law, you see. 274 00:17:33,910 --> 00:17:39,150 The product of any object c and the sum of d and e gives 275 00:17:39,150 --> 00:17:42,340 the result as the same as the sum of the product of c and d 276 00:17:42,340 --> 00:17:45,320 and the product of c and e. 277 00:17:45,320 --> 00:17:47,770 Now, what exactly these rules are doesn't very 278 00:17:47,770 --> 00:17:49,220 much interest me. 279 00:17:49,220 --> 00:17:51,970 We're going to be writing the language that will allow us to 280 00:17:51,970 --> 00:17:56,480 interpret these rules so that we can, in fact, make up 281 00:17:56,480 --> 00:17:59,430 whatever rules we like, another whole language of 282 00:17:59,430 --> 00:18:00,680 programming. 283 00:18:00,680 --> 00:18:03,350 284 00:18:03,350 --> 00:18:05,130 Well, let's see. 285 00:18:05,130 --> 00:18:07,520 I haven't told you how we're going to do this. 286 00:18:07,520 --> 00:18:10,760 And, of course, for a while, we're going to work on that. 287 00:18:10,760 --> 00:18:13,980 But there's a real question of what is--what am I going to do 288 00:18:13,980 --> 00:18:16,940 at all at a large scale? 289 00:18:16,940 --> 00:18:18,930 How do these rules work? 290 00:18:18,930 --> 00:18:21,830 How is the simplifier program going to manipulate these 291 00:18:21,830 --> 00:18:26,190 rules with your expression to produce a reasonable answer? 292 00:18:26,190 --> 00:18:28,410 Well, first, I'd like to think about these rules as being 293 00:18:28,410 --> 00:18:32,100 some sort of deck of them. 294 00:18:32,100 --> 00:18:42,030 So here I have a whole bunch of rules, right? 295 00:18:42,030 --> 00:18:43,660 Each rule-- 296 00:18:43,660 --> 00:18:46,930 here's a rule-- 297 00:18:46,930 --> 00:18:49,720 has a pattern and a skeleton. 298 00:18:49,720 --> 00:18:53,410 I'm trying to make up a control structure for this. 299 00:18:53,410 --> 00:19:02,720 Now, what I have is a matcher, and I have something which is 300 00:19:02,720 --> 00:19:03,970 an instantiater. 301 00:19:03,970 --> 00:19:09,120 302 00:19:09,120 --> 00:19:13,950 And I'm going to pass from the matcher to the instantiater 303 00:19:13,950 --> 00:19:18,200 some set of meaning for the pattern variables, a 304 00:19:18,200 --> 00:19:20,560 dictionary, I'll call it. 305 00:19:20,560 --> 00:19:26,740 A dictionary, which will say x was matched against the 306 00:19:26,740 --> 00:19:30,410 following subexpression and y was matched against another 307 00:19:30,410 --> 00:19:32,170 following subexpression. 308 00:19:32,170 --> 00:19:35,040 And from the instantiater, I will be making expressions, 309 00:19:35,040 --> 00:19:37,130 and they will go into the matcher. 310 00:19:37,130 --> 00:19:38,380 They will be expressions. 311 00:19:38,380 --> 00:19:44,960 312 00:19:44,960 --> 00:19:49,190 And the patterns of the rules will be fed into the matcher, 313 00:19:49,190 --> 00:19:53,600 and the skeletons from the same rule will be fed into the 314 00:19:53,600 --> 00:19:55,190 instantiater. 315 00:19:55,190 --> 00:19:57,920 Now, this is a little complicated because when you 316 00:19:57,920 --> 00:20:00,965 have something like an algebraic expression, where 317 00:20:00,965 --> 00:20:02,290 someth--the rules are intended to be able to allow you to 318 00:20:02,290 --> 00:20:04,290 substitute equal for equal. 319 00:20:04,290 --> 00:20:06,860 These are equal transformation rules. 320 00:20:06,860 --> 00:20:08,710 So all subexpressions of the expression 321 00:20:08,710 --> 00:20:11,090 should be looked at. 322 00:20:11,090 --> 00:20:14,440 You give it an expression, this thing, and the rules 323 00:20:14,440 --> 00:20:16,010 should be cycled around. 324 00:20:16,010 --> 00:20:18,540 First of all, for every subexpression of the 325 00:20:18,540 --> 00:20:21,340 expression you feed in, all of the rules must be 326 00:20:21,340 --> 00:20:24,390 tried and looked at. 327 00:20:24,390 --> 00:20:27,200 And if any rule matches, then this process occurs. 328 00:20:27,200 --> 00:20:30,620 The dictionary--the dictionary is to have some values in it. 329 00:20:30,620 --> 00:20:34,800 The instantiater makes a new expression, which is basically 330 00:20:34,800 --> 00:20:38,000 replaces that part of the expression that was matched in 331 00:20:38,000 --> 00:20:40,800 your original expression. 332 00:20:40,800 --> 00:20:44,700 And then, then, of course, we're going to recheck that, 333 00:20:44,700 --> 00:20:47,170 going to go around these rules again, seeing if that could be 334 00:20:47,170 --> 00:20:49,520 simplified further. 335 00:20:49,520 --> 00:20:50,960 And then, then we're going to do that for every 336 00:20:50,960 --> 00:20:54,940 subexpression until the thing no longer changes. 337 00:20:54,940 --> 00:20:57,890 You can think of this as sort of an organic process. 338 00:20:57,890 --> 00:21:00,190 You've got some sort of stew, right? 339 00:21:00,190 --> 00:21:03,076 You've got bacteria or something, or enzymes in some, 340 00:21:03,076 --> 00:21:05,590 in some gooey mess. 341 00:21:05,590 --> 00:21:10,470 And there's these--and these enzymes change things. 342 00:21:10,470 --> 00:21:13,320 They attach to your expression, change it, and 343 00:21:13,320 --> 00:21:15,300 then they go away. 344 00:21:15,300 --> 00:21:16,080 And they have to match. 345 00:21:16,080 --> 00:21:17,740 The key-in-lock phenomenon. 346 00:21:17,740 --> 00:21:19,660 They match, they change it, they go away. 347 00:21:19,660 --> 00:21:22,310 You can imagine it as a parallel process of some sort. 348 00:21:22,310 --> 00:21:26,250 So you stick an expression into this mess, and after a 349 00:21:26,250 --> 00:21:29,440 while, you take it out, and it's been simplified. 350 00:21:29,440 --> 00:21:31,660 And it just keeps changing until it no 351 00:21:31,660 --> 00:21:33,170 longer can be changed. 352 00:21:33,170 --> 00:21:37,840 But these enzymes can attach to any part of the, of the 353 00:21:37,840 --> 00:21:39,230 expression. 354 00:21:39,230 --> 00:21:44,990 OK, at this point, I'd like to stop and ask for questions. 355 00:21:44,990 --> 00:21:45,950 Yes. 356 00:21:45,950 --> 00:21:48,550 AUDIENCE: This implies that the matching program and the 357 00:21:48,550 --> 00:21:50,460 instantiation program are separate 358 00:21:50,460 --> 00:21:51,650 programs; is that right? 359 00:21:51,650 --> 00:21:52,690 Or is that-- they are. 360 00:21:52,690 --> 00:21:54,090 PROFESSOR: They're separate little pieces. 361 00:21:54,090 --> 00:21:57,170 They fit together in a larger structure. 362 00:21:57,170 --> 00:22:00,480 AUDIENCE: So I'm going through and matching and passing the 363 00:22:00,480 --> 00:22:03,520 information about what I matched to an instantiater, 364 00:22:03,520 --> 00:22:04,620 which makes the changes. 365 00:22:04,620 --> 00:22:06,480 And then I pass that back to the matcher? 366 00:22:06,480 --> 00:22:07,060 PROFESSOR: It won't make a change. 367 00:22:07,060 --> 00:22:11,540 It will make a new expression, which has, which has 368 00:22:11,540 --> 00:22:14,980 substituted the values of the pattern variable that were 369 00:22:14,980 --> 00:22:17,860 matched on the left-hand side for the variables that are 370 00:22:17,860 --> 00:22:20,570 mentioned, the skeleton variables or evaluation 371 00:22:20,570 --> 00:22:25,170 variables or whatever I called them, on the right-hand side. 372 00:22:25,170 --> 00:22:27,660 AUDIENCE: And then that's passed back into the matcher? 373 00:22:27,660 --> 00:22:29,490 PROFESSOR: Then this is going to go around again. 374 00:22:29,490 --> 00:22:31,330 This is going to go through this mess until 375 00:22:31,330 --> 00:22:33,240 it no longer changes. 376 00:22:33,240 --> 00:22:35,440 AUDIENCE: And it seems that there would be a danger of 377 00:22:35,440 --> 00:22:37,170 getting into a recursive loop. 378 00:22:37,170 --> 00:22:38,160 PROFESSOR: Yes. 379 00:22:38,160 --> 00:22:41,240 Yes, if you do not write your rules nicely, you are-- 380 00:22:41,240 --> 00:22:43,870 indeed, in any programming language you invent, if it's 381 00:22:43,870 --> 00:22:46,190 sufficiently powerful to do anything, you can write 382 00:22:46,190 --> 00:22:49,280 programs that will go into infinite loops. 383 00:22:49,280 --> 00:22:52,600 And indeed, writing a program for doing algebraic 384 00:22:52,600 --> 00:22:55,010 manipulation for long will produce infinite loops. 385 00:22:55,010 --> 00:23:00,722 386 00:23:00,722 --> 00:23:01,680 Go ahead. 387 00:23:01,680 --> 00:23:04,580 AUDIENCE: Some language designers feel that this 388 00:23:04,580 --> 00:23:07,850 feature is so important that it should become part of the 389 00:23:07,850 --> 00:23:12,670 basic language, for example, scheme in this case. 390 00:23:12,670 --> 00:23:13,960 What are your thoughts on-- 391 00:23:13,960 --> 00:23:15,722 PROFESSOR: Which language feature? 392 00:23:15,722 --> 00:23:17,290 AUDIENCE: The pairs matching. 393 00:23:17,290 --> 00:23:21,840 It's all application of such rules should be-- 394 00:23:21,840 --> 00:23:23,650 PROFESSOR: Oh, you mean like Prolog? 395 00:23:23,650 --> 00:23:26,595 AUDIENCE: Like Prolog, but it becomes a more general-- 396 00:23:26,595 --> 00:23:28,470 PROFESSOR: It's possible. 397 00:23:28,470 --> 00:23:33,740 OK, I think my feeling about that is that I would like to 398 00:23:33,740 --> 00:23:35,840 teach you how to do it so you don't depend upon some 399 00:23:35,840 --> 00:23:38,490 language designer. 400 00:23:38,490 --> 00:23:40,870 AUDIENCE: OK. 401 00:23:40,870 --> 00:23:41,850 PROFESSOR: You make it yourself. 402 00:23:41,850 --> 00:23:44,640 You can roll your own. 403 00:23:44,640 --> 00:23:45,890 Thank you. 404 00:23:45,890 --> 00:24:14,120 405 00:24:14,120 --> 00:24:15,800 Well, let's see. 406 00:24:15,800 --> 00:24:17,100 Now we have to tell you how it works. 407 00:24:17,100 --> 00:24:21,586 408 00:24:21,586 --> 00:24:24,445 It conveniently breaks up into various pieces. 409 00:24:24,445 --> 00:24:28,680 I'd like to look now at the matcher. 410 00:24:28,680 --> 00:24:32,730 The matcher has the following basic structure. 411 00:24:32,730 --> 00:24:44,500 It's a box that takes as its input an expression and a 412 00:24:44,500 --> 00:24:53,570 pattern, and it turns out a dictionary. 413 00:24:53,570 --> 00:25:01,530 414 00:25:01,530 --> 00:25:06,440 A dictionary, remember, is a mapping of pattern variables 415 00:25:06,440 --> 00:25:09,990 to the values that were found by matching, and it puts out 416 00:25:09,990 --> 00:25:20,370 another dictionary, which is the result of augmenting this 417 00:25:20,370 --> 00:25:24,350 dictionary by what was found in matching this expression 418 00:25:24,350 --> 00:25:25,600 against this pattern. 419 00:25:25,600 --> 00:25:27,930 420 00:25:27,930 --> 00:25:29,180 So that's the matcher. 421 00:25:29,180 --> 00:25:33,900 422 00:25:33,900 --> 00:25:37,600 Now, this is a rather complicated program, and we 423 00:25:37,600 --> 00:25:42,530 can look at it on the overhead over here and see, ha, ha, 424 00:25:42,530 --> 00:25:44,430 it's very complicated. 425 00:25:44,430 --> 00:25:46,740 I just want you to look at the shape of it. 426 00:25:46,740 --> 00:25:51,670 It's too complicated to look at except in pieces. 427 00:25:51,670 --> 00:25:56,720 However, it's a fairly large, complicated program with a lot 428 00:25:56,720 --> 00:26:00,140 of sort of indented structure. 429 00:26:00,140 --> 00:26:02,090 At the largest scale-- 430 00:26:02,090 --> 00:26:04,740 you don't try to read those characters, but at the largest 431 00:26:04,740 --> 00:26:09,130 scale, you see that there is a case analysis, which is all 432 00:26:09,130 --> 00:26:12,100 these cases lined up. 433 00:26:12,100 --> 00:26:15,400 What we're now going to do is look at this in a bit more 434 00:26:15,400 --> 00:26:19,970 detail, attempting to understand how it works. 435 00:26:19,970 --> 00:26:24,810 Let's go now to the first slide, showing some of the 436 00:26:24,810 --> 00:26:28,710 structure of the matcher at a large scale. 437 00:26:28,710 --> 00:26:33,440 And we see that the matcher, the matcher takes as its input 438 00:26:33,440 --> 00:26:36,050 a pattern, an expression, and a dictionary. 439 00:26:36,050 --> 00:26:38,580 440 00:26:38,580 --> 00:26:42,370 And there is a case analysis here, which is made out of 441 00:26:42,370 --> 00:26:46,630 several cases, some of which have been left out over here, 442 00:26:46,630 --> 00:26:50,560 and the general case, which I'd like you to see. 443 00:26:50,560 --> 00:26:51,920 Let's consider this general case. 444 00:26:51,920 --> 00:26:53,230 It's a very important pattern. 445 00:26:53,230 --> 00:26:55,920 446 00:26:55,920 --> 00:27:00,650 The problem is that we have to examine two trees 447 00:27:00,650 --> 00:27:03,000 simultaneously. 448 00:27:03,000 --> 00:27:06,230 One of the trees is the tree of the expression, and the 449 00:27:06,230 --> 00:27:08,660 other is the tree of the pattern. 450 00:27:08,660 --> 00:27:12,540 We have to compare them with each other so that the 451 00:27:12,540 --> 00:27:15,230 subexpressions of the expression are matched against 452 00:27:15,230 --> 00:27:18,380 subexpressions of the pattern. 453 00:27:18,380 --> 00:27:21,170 Looking at that in a bit more detail, suppose I had a 454 00:27:21,170 --> 00:27:29,820 pattern, a pattern, which was the sum of the product of a 455 00:27:29,820 --> 00:27:38,130 thing which we will call x and a thing which we will call y, 456 00:27:38,130 --> 00:27:42,000 and the sum of that, and the same thing we call y. 457 00:27:42,000 --> 00:27:45,070 458 00:27:45,070 --> 00:27:49,902 So we're looking for a sum of a product whose second--whose 459 00:27:49,902 --> 00:27:53,790 second argument is the same as the second 460 00:27:53,790 --> 00:27:56,960 argument of the sum. 461 00:27:56,960 --> 00:27:59,650 That's a thing you might be looking for. 462 00:27:59,650 --> 00:28:02,770 Well, that, as a pattern, looks like this. 463 00:28:02,770 --> 00:28:09,660 There is a tree, which consists of a sum, and a 464 00:28:09,660 --> 00:28:16,640 product with a pattern variable question mark x and 465 00:28:16,640 --> 00:28:21,960 question mark y, the other pattern variable, and question 466 00:28:21,960 --> 00:28:25,785 mark y, just looking at the same, just writing down the 467 00:28:25,785 --> 00:28:28,760 list structure in a different way. 468 00:28:28,760 --> 00:28:31,040 Now, suppose we were matching that against an expression 469 00:28:31,040 --> 00:28:38,990 which matches it, the sum of, say, the product of 3 and x 470 00:28:38,990 --> 00:28:42,420 and, say, x. 471 00:28:42,420 --> 00:28:44,380 That's another tree. 472 00:28:44,380 --> 00:28:56,250 It's the sum of the product of 3 and x and of x. 473 00:28:56,250 --> 00:28:59,320 474 00:28:59,320 --> 00:29:02,030 So what I want to do is traverse these two trees 475 00:29:02,030 --> 00:29:04,410 simultaneously. 476 00:29:04,410 --> 00:29:08,670 And what I'd like to do is walk them like this. 477 00:29:08,670 --> 00:29:12,880 I'm going to say are these the same? 478 00:29:12,880 --> 00:29:15,200 This is a complicated object. 479 00:29:15,200 --> 00:29:17,240 Let's look at the left branches. 480 00:29:17,240 --> 00:29:18,460 Well, that could be the car. 481 00:29:18,460 --> 00:29:19,250 How does that look? 482 00:29:19,250 --> 00:29:21,880 Oh yes, the plus looks just fine. 483 00:29:21,880 --> 00:29:24,080 But the next thing here is a complicated thing. 484 00:29:24,080 --> 00:29:25,170 Let's look at that. 485 00:29:25,170 --> 00:29:26,780 Oh yes, that's pretty fine, too. 486 00:29:26,780 --> 00:29:28,560 They're both asterisks. 487 00:29:28,560 --> 00:29:30,410 Now, whoops! 488 00:29:30,410 --> 00:29:34,300 My pattern variable, it matches against the 3. 489 00:29:34,300 --> 00:29:36,400 Remember, x equals 3 now. 490 00:29:36,400 --> 00:29:38,290 That's in my dictionary, and the dictionary's going to 491 00:29:38,290 --> 00:29:41,490 follow along with me: x equals three. 492 00:29:41,490 --> 00:29:46,800 Ah yes, x equals 3 and y equals x, different x. 493 00:29:46,800 --> 00:29:51,060 The pattern x is the expression x, the pattern y. 494 00:29:51,060 --> 00:29:53,630 495 00:29:53,630 --> 00:29:56,570 Oh yes, the pattern variable y, I've already 496 00:29:56,570 --> 00:29:57,270 got a value for it. 497 00:29:57,270 --> 00:29:58,410 It's x. 498 00:29:58,410 --> 00:29:59,050 Is this an x? 499 00:29:59,050 --> 00:30:00,070 Oh yeah, sure it is. 500 00:30:00,070 --> 00:30:02,040 That's fine. 501 00:30:02,040 --> 00:30:03,380 Yep, done. 502 00:30:03,380 --> 00:30:07,070 I now have a dictionary, which I've accumulated 503 00:30:07,070 --> 00:30:08,320 by making this walk. 504 00:30:08,320 --> 00:30:11,370 505 00:30:11,370 --> 00:30:14,080 Well, now let's look at this general case here and see how 506 00:30:14,080 --> 00:30:15,830 that works. 507 00:30:15,830 --> 00:30:17,150 Here we have it. 508 00:30:17,150 --> 00:30:20,520 I take in a pattern variable--a pattern, an 509 00:30:20,520 --> 00:30:22,310 expression, and a dictionary. 510 00:30:22,310 --> 00:30:26,650 And now I'm going to do a complicated thing here, which 511 00:30:26,650 --> 00:30:29,610 is the general case. 512 00:30:29,610 --> 00:30:33,480 The expression is made out of two parts: a left and a right 513 00:30:33,480 --> 00:30:35,470 half, in general. 514 00:30:35,470 --> 00:30:38,080 Anything that's complicated is made out of two pieces in a 515 00:30:38,080 --> 00:30:39,950 Lisp system. 516 00:30:39,950 --> 00:30:41,870 Well, now what do we have here? 517 00:30:41,870 --> 00:30:45,840 I'm going to match the car's of the two expressions against 518 00:30:45,840 --> 00:30:50,190 each other with respect to the dictionary I already have, 519 00:30:50,190 --> 00:30:55,620 producing a dictionary as its value, which I will then use 520 00:30:55,620 --> 00:30:58,130 for matching the cdr's against each other. 521 00:30:58,130 --> 00:31:00,580 So that's how the dictionary travels, 522 00:31:00,580 --> 00:31:03,580 threads the entire structure. 523 00:31:03,580 --> 00:31:06,310 And then the result of that is the dictionary for the match 524 00:31:06,310 --> 00:31:11,230 of the car and the cdr, and that's what's going to be 525 00:31:11,230 --> 00:31:13,640 returned as a value. 526 00:31:13,640 --> 00:31:16,670 Now, at any point, a match might fail. 527 00:31:16,670 --> 00:31:19,670 It may be the case, for example, if we go back and 528 00:31:19,670 --> 00:31:24,010 look at an expression that doesn't quite match, like 529 00:31:24,010 --> 00:31:29,040 supposing this was a 4. 530 00:31:29,040 --> 00:31:33,520 Well, now these two don't match any more, because the x 531 00:31:33,520 --> 00:31:38,190 that had to be-- sorry, the y that had to be x here and this 532 00:31:38,190 --> 00:31:40,410 y has to be 4. 533 00:31:40,410 --> 00:31:44,510 But x and 4 were not the same object syntactically. 534 00:31:44,510 --> 00:31:47,130 So this wouldn't match, and that would be rejected 535 00:31:47,130 --> 00:31:50,220 sometimes, so matches may fail. 536 00:31:50,220 --> 00:31:54,140 Now, of course, because this matcher takes the dictionary 537 00:31:54,140 --> 00:31:57,110 from the previous match as input, it must be able to 538 00:31:57,110 --> 00:31:58,520 propagate the failures. 539 00:31:58,520 --> 00:32:00,090 And so that's what the first clause of 540 00:32:00,090 --> 00:32:03,420 this conditional does. 541 00:32:03,420 --> 00:32:07,330 It's also true that if it turned out that the pattern 542 00:32:07,330 --> 00:32:08,540 was not atomic-- 543 00:32:08,540 --> 00:32:10,280 see, if the pattern was atomic, I'd go into this 544 00:32:10,280 --> 00:32:12,060 stuff, which we haven't looked at yet. 545 00:32:12,060 --> 00:32:16,250 But if the pattern is not atomic and the 546 00:32:16,250 --> 00:32:17,825 expression is atomic-- 547 00:32:17,825 --> 00:32:20,010 it's not made out of pieces-- 548 00:32:20,010 --> 00:32:23,560 then that must be a failure, and so we go over here. 549 00:32:23,560 --> 00:32:26,660 If the pattern is not atomic and the pattern is not a 550 00:32:26,660 --> 00:32:27,420 pattern variable-- 551 00:32:27,420 --> 00:32:29,716 I have to remind myself of that-- 552 00:32:29,716 --> 00:32:30,850 then we go over here. 553 00:32:30,850 --> 00:32:32,570 So that way, failures may occur. 554 00:32:32,570 --> 00:32:35,280 555 00:32:35,280 --> 00:32:39,612 OK, so now let's look at the insides of this thing. 556 00:32:39,612 --> 00:32:42,080 Well, the first place to look is what happens if I have an 557 00:32:42,080 --> 00:32:42,870 atomic pattern? 558 00:32:42,870 --> 00:32:43,870 That's very simple. 559 00:32:43,870 --> 00:32:46,945 A pattern that's not made out of any pieces: foo. 560 00:32:46,945 --> 00:32:49,200 That's a nice atomic pattern. 561 00:32:49,200 --> 00:32:52,060 Well, here's what we see. 562 00:32:52,060 --> 00:32:56,750 If the pattern is atomic, then if the expression is atomic, 563 00:32:56,750 --> 00:33:00,200 then if they are the same thing, then the dictionary I 564 00:33:00,200 --> 00:33:03,120 get is the same one as I had before. 565 00:33:03,120 --> 00:33:04,730 Nothing's changed. 566 00:33:04,730 --> 00:33:09,160 It's just that I matched plus against plus, asterisk against 567 00:33:09,160 --> 00:33:11,440 asterisk, x against x. 568 00:33:11,440 --> 00:33:12,920 That's all fine. 569 00:33:12,920 --> 00:33:16,110 However, if the pattern is not the one which is the 570 00:33:16,110 --> 00:33:19,405 expression, if I have two separate atomic objects, then 571 00:33:19,405 --> 00:33:25,810 it was matching plus against asterisk, which case I fail. 572 00:33:25,810 --> 00:33:29,300 Or if it turns out that the pattern is atomic but the 573 00:33:29,300 --> 00:33:33,310 expression is complicated, it's not atomic, 574 00:33:33,310 --> 00:33:34,560 then I get a failure. 575 00:33:34,560 --> 00:33:37,100 576 00:33:37,100 --> 00:33:38,800 That's very simple. 577 00:33:38,800 --> 00:33:44,040 Now, what about the various kinds of pattern variables? 578 00:33:44,040 --> 00:33:45,610 We had three kinds. 579 00:33:45,610 --> 00:33:47,340 I give them the names. 580 00:33:47,340 --> 00:33:50,990 They're arbitrary constants, arbitrary variables, and 581 00:33:50,990 --> 00:33:53,770 arbitrary expressions. 582 00:33:53,770 --> 00:34:01,210 A question mark x is an arbitrary expression. 583 00:34:01,210 --> 00:34:04,830 A question mark cx is an arbitrary constant, and a 584 00:34:04,830 --> 00:34:08,537 question mark vx is an arbitrary variable. 585 00:34:08,537 --> 00:34:10,540 Well, what do we do here? 586 00:34:10,540 --> 00:34:14,139 Looking at this, we see that if I have an arbitrary 587 00:34:14,139 --> 00:34:18,080 constant, if the pattern is an arbitrary constant, then it 588 00:34:18,080 --> 00:34:19,560 had better be the case that the expression 589 00:34:19,560 --> 00:34:21,480 had better be a constant. 590 00:34:21,480 --> 00:34:22,620 If the expression is not a constant, 591 00:34:22,620 --> 00:34:23,920 then that match fails. 592 00:34:23,920 --> 00:34:26,780 If it is a constant, however, then I wish to extend the 593 00:34:26,780 --> 00:34:27,620 dictionary. 594 00:34:27,620 --> 00:34:32,380 I wish to extend the dictionary with that pattern 595 00:34:32,380 --> 00:34:36,650 being remembered to be that expression using the old 596 00:34:36,650 --> 00:34:37,900 dictionary as a starting point. 597 00:34:37,900 --> 00:34:41,050 598 00:34:41,050 --> 00:34:44,179 So really, for arbitrary variables, I have to check 599 00:34:44,179 --> 00:34:47,440 first if the expression is a variable by matching against. 600 00:34:47,440 --> 00:34:50,750 If so, it's worth extending the dictionary so that the 601 00:34:50,750 --> 00:34:52,639 pattern is remembered to be matched against that 602 00:34:52,639 --> 00:34:55,900 expression, given the original dictionary, and this makes a 603 00:34:55,900 --> 00:34:58,880 new dictionary. 604 00:34:58,880 --> 00:35:00,310 Now, it has to check. 605 00:35:00,310 --> 00:35:03,860 There's a sorts of failure inside extend dictionary, 606 00:35:03,860 --> 00:35:04,990 which is that-- 607 00:35:04,990 --> 00:35:09,200 if one of these pattern variables already has a value 608 00:35:09,200 --> 00:35:12,810 and I'm trying to match the thing against something else 609 00:35:12,810 --> 00:35:15,310 which is not equivalent to the one that I've already matched 610 00:35:15,310 --> 00:35:17,760 it against once, then a failure will come flying out 611 00:35:17,760 --> 00:35:20,220 of here, too. 612 00:35:20,220 --> 00:35:22,890 And I will see that some time. 613 00:35:22,890 --> 00:35:25,850 And finally, an arbitrary expression does not have to 614 00:35:25,850 --> 00:35:29,010 check anything syntactic about the expression that's being 615 00:35:29,010 --> 00:35:31,670 matched, so all it does is it's an extension of the 616 00:35:31,670 --> 00:35:34,355 dictionary. 617 00:35:34,355 --> 00:35:39,300 So you've just seen a complete, very simple matcher. 618 00:35:39,300 --> 00:35:41,640 Now, one of the things that's rather remarkable about this 619 00:35:41,640 --> 00:35:44,670 is people pay an awful lot of money these days for someone 620 00:35:44,670 --> 00:35:49,290 to make a, quote, AI expert system that has nothing more 621 00:35:49,290 --> 00:35:53,470 in it than a matcher and maybe an instantiater like this. 622 00:35:53,470 --> 00:35:55,780 But it's very easy to do, and now, of course, you can start 623 00:35:55,780 --> 00:35:59,070 up a little start-up company and make a couple of megabucks 624 00:35:59,070 --> 00:36:01,835 in the next week taking some people for a ride. 625 00:36:01,835 --> 00:36:04,690 626 00:36:04,690 --> 00:36:07,510 20 years ago, this was remarkable, 627 00:36:07,510 --> 00:36:09,610 this kind of program. 628 00:36:09,610 --> 00:36:11,870 But now, this is sort of easy. 629 00:36:11,870 --> 00:36:13,660 You can teach it to freshmen. 630 00:36:13,660 --> 00:36:15,380 Well, now there's an instantiater as well. 631 00:36:15,380 --> 00:36:19,980 632 00:36:19,980 --> 00:36:21,710 The problem is they're all going off and making more 633 00:36:21,710 --> 00:36:24,190 money than I do. 634 00:36:24,190 --> 00:36:26,660 But that's always been true of universities. 635 00:36:26,660 --> 00:36:33,140 As expression, the purpose of the instantiater is to make 636 00:36:33,140 --> 00:36:39,245 expressions given a dictionary and a skeleton. 637 00:36:39,245 --> 00:36:44,290 638 00:36:44,290 --> 00:36:46,770 And that's not very hard at all. 639 00:36:46,770 --> 00:36:53,590 We'll see that very simply in the next, the next slide here. 640 00:36:53,590 --> 00:36:57,570 To instantiate a skeleton, given a particular 641 00:36:57,570 --> 00:36:58,230 dictionary-- 642 00:36:58,230 --> 00:36:59,650 oh, this is easy. 643 00:36:59,650 --> 00:37:04,050 We're going to do a recursive tree walk over the skeleton. 644 00:37:04,050 --> 00:37:06,540 And for everything which is a skeleton variable-- 645 00:37:06,540 --> 00:37:08,390 I don't know, call it a skeleton evaluation. 646 00:37:08,390 --> 00:37:10,612 That's the name and the abstract syntax that I give it 647 00:37:10,612 --> 00:37:13,610 in this program: a skeleton evaluation, a thing beginning 648 00:37:13,610 --> 00:37:18,180 with a colon in the rules. 649 00:37:18,180 --> 00:37:21,850 For anything of that case, I'm going to look up the answer in 650 00:37:21,850 --> 00:37:24,470 the dictionary, and we'll worry about that in a second. 651 00:37:24,470 --> 00:37:27,700 Let's look at this as a whole. 652 00:37:27,700 --> 00:37:28,530 Here, I have-- 653 00:37:28,530 --> 00:37:32,740 I'm going to instantiate a skeleton, given a dictionary. 654 00:37:32,740 --> 00:37:38,300 Well, I'm going to define some internal loop right there, and 655 00:37:38,300 --> 00:37:40,190 it's going to do something very simple. 656 00:37:40,190 --> 00:37:44,600 Even if a skeleton--even if a skeleton is simple and atomic, 657 00:37:44,600 --> 00:37:46,450 in which case it's nothing more than giving the skeleton 658 00:37:46,450 --> 00:37:51,140 back as an answer, or in the general case, it's 659 00:37:51,140 --> 00:37:56,150 complicated, in which case I'm going to make up the 660 00:37:56,150 --> 00:37:59,360 expression which is the result of instantiating-- 661 00:37:59,360 --> 00:38:01,000 calling this loop recursively-- 662 00:38:01,000 --> 00:38:04,870 instantiating the car of the skeleton and the cdr. 663 00:38:04,870 --> 00:38:08,090 So here is a recursive tree walk. 664 00:38:08,090 --> 00:38:12,410 However, if it turns out to be a skeleton evaluation, a colon 665 00:38:12,410 --> 00:38:18,020 expression in the skeleton, then what I'm going to do is 666 00:38:18,020 --> 00:38:21,520 find the expression that's in the colon-- 667 00:38:21,520 --> 00:38:22,820 the CADR in this case. 668 00:38:22,820 --> 00:38:25,110 It's a piece of abstract syntax here, so I can change 669 00:38:25,110 --> 00:38:27,480 my representation of rules. 670 00:38:27,480 --> 00:38:31,330 I'm going to evaluate that relative to this dictionary, 671 00:38:31,330 --> 00:38:32,940 whatever evaluation means. 672 00:38:32,940 --> 00:38:36,100 We'll find out a lot about that sometime. 673 00:38:36,100 --> 00:38:39,650 And the result of that is my answer. 674 00:38:39,650 --> 00:38:39,830 so. 675 00:38:39,830 --> 00:38:42,240 I start up this loop-- here's my initialization-- 676 00:38:42,240 --> 00:38:44,900 by calling it with the whole skeleton, and this will just 677 00:38:44,900 --> 00:38:47,100 do a recursive decomposition into pieces. 678 00:38:47,100 --> 00:38:49,690 679 00:38:49,690 --> 00:38:55,090 Now, one more little bit of detail is what 680 00:38:55,090 --> 00:38:57,130 happens inside evaluate? 681 00:38:57,130 --> 00:39:00,030 I can't tell you that in great detail. 682 00:39:00,030 --> 00:39:01,650 I'll tell you a little bit of it. 683 00:39:01,650 --> 00:39:03,130 Later, we're going to see--look into this in much 684 00:39:03,130 --> 00:39:04,970 more detail. 685 00:39:04,970 --> 00:39:10,120 To evaluate some form, some expression with respect to a 686 00:39:10,120 --> 00:39:15,355 dictionary, if the expression is an atomic object, well, I'm 687 00:39:15,355 --> 00:39:18,620 going to go look it up. 688 00:39:18,620 --> 00:39:20,610 Nothing very exciting there. 689 00:39:20,610 --> 00:39:23,900 Otherwise, I'm going to do something complicated here, 690 00:39:23,900 --> 00:39:26,790 which is I'm going to apply a procedure which is the result 691 00:39:26,790 --> 00:39:30,220 of looking up the operator part in something that we're 692 00:39:30,220 --> 00:39:32,150 going to find out about someday. 693 00:39:32,150 --> 00:39:34,630 I want you realize you're seeing magic now. 694 00:39:34,630 --> 00:39:40,000 This magic will become clear very soon, but not today. 695 00:39:40,000 --> 00:39:43,540 Then I'm looking at--looking up all the pieces, all the 696 00:39:43,540 --> 00:39:48,460 arguments to that in the dictionary. 697 00:39:48,460 --> 00:39:51,390 So I don't want you to look at this in detail. 698 00:39:51,390 --> 00:39:54,330 I want you to say that there's more going on here, and we're 699 00:39:54,330 --> 00:39:59,000 going to see more about this. 700 00:39:59,000 --> 00:39:59,490 But it's-- 701 00:39:59,490 --> 00:40:02,490 the magic is going to stop. 702 00:40:02,490 --> 00:40:07,140 This part has to do with Lisp, and it's the end of that. 703 00:40:07,140 --> 00:40:10,260 704 00:40:10,260 --> 00:40:15,040 OK, so now we know about matching and instantiation. 705 00:40:15,040 --> 00:40:16,505 Are there any questions for this segment? 706 00:40:16,505 --> 00:40:27,936 707 00:40:27,936 --> 00:40:29,870 AUDIENCE: I have a question. 708 00:40:29,870 --> 00:40:30,880 PROFESSOR: Yes. 709 00:40:30,880 --> 00:40:33,600 AUDIENCE: Is it possible to bring up a previous slide? 710 00:40:33,600 --> 00:40:36,160 It's about this define match pattern. 711 00:40:36,160 --> 00:40:37,300 PROFESSOR: Yes. 712 00:40:37,300 --> 00:40:40,590 You'd like to see the overall slide define match pattern. 713 00:40:40,590 --> 00:40:41,890 Can somebody put up the-- 714 00:40:41,890 --> 00:40:42,940 no, the overhead. 715 00:40:42,940 --> 00:40:45,300 That's the biggest scale one. 716 00:40:45,300 --> 00:40:47,640 What part would you like to see? 717 00:40:47,640 --> 00:40:49,930 AUDIENCE: Well, the top would be fine. 718 00:40:49,930 --> 00:40:54,540 Any of the parts where you're passing failed. 719 00:40:54,540 --> 00:40:56,300 PROFESSOR: Yes. 720 00:40:56,300 --> 00:40:58,625 AUDIENCE: The idea is to pass failed back to the dictionary; 721 00:40:58,625 --> 00:40:59,000 is that right? 722 00:40:59,000 --> 00:41:05,180 PROFESSOR: The dictionary is the answer to a match, right? 723 00:41:05,180 --> 00:41:13,150 And it is either some mapping or there's no match. 724 00:41:13,150 --> 00:41:14,560 It doesn't match. 725 00:41:14,560 --> 00:41:15,150 AUDIENCE: Right. 726 00:41:15,150 --> 00:41:18,110 PROFESSOR: So what you're seeing over here is, in fact, 727 00:41:18,110 --> 00:41:21,620 because the fact that a match may have another match pass in 728 00:41:21,620 --> 00:41:24,950 the dictionary, as you see in the general case down here. 729 00:41:24,950 --> 00:41:27,325 Here's the general case where a match passes another match 730 00:41:27,325 --> 00:41:28,090 to the dictionary. 731 00:41:28,090 --> 00:41:31,860 When I match the cdr's, I match them in the dictionary 732 00:41:31,860 --> 00:41:36,070 that is resulting from matching the car's. 733 00:41:36,070 --> 00:41:37,180 OK, that's what I have here. 734 00:41:37,180 --> 00:41:41,430 So because of that, if the match of the car's fails, then 735 00:41:41,430 --> 00:41:44,770 it may be necessary that the match of the cdr's propagates 736 00:41:44,770 --> 00:41:48,570 that failure, and that's what the first line is. 737 00:41:48,570 --> 00:41:51,400 AUDIENCE: OK, well, I'm still unclear what matches-- 738 00:41:51,400 --> 00:41:54,800 what comes out of one instance of the match? 739 00:41:54,800 --> 00:41:56,320 PROFESSOR: One of two possibilities. 740 00:41:56,320 --> 00:41:59,350 Either the symbol failed, which means there is no match. 741 00:41:59,350 --> 00:41:59,840 AUDIENCE: Right. 742 00:41:59,840 --> 00:42:03,360 PROFESSOR: Or some mapping, which is an abstract thing 743 00:42:03,360 --> 00:42:06,480 right now, and you should know about the structure of it, 744 00:42:06,480 --> 00:42:13,170 which relates the pattern variables to their values as 745 00:42:13,170 --> 00:42:14,490 picked up in the match. 746 00:42:14,490 --> 00:42:16,930 AUDIENCE: OK, so it is-- 747 00:42:16,930 --> 00:42:18,810 PROFESSOR: That's constructed by extend dictionary. 748 00:42:18,810 --> 00:42:22,450 AUDIENCE: So the recursive nature brings about the fact 749 00:42:22,450 --> 00:42:28,290 that if ever a failed gets passed out of any calling of 750 00:42:28,290 --> 00:42:30,430 match, then the first condition will pick it up-- 751 00:42:30,430 --> 00:42:32,820 PROFESSOR: And just propagate it along without any further 752 00:42:32,820 --> 00:42:33,530 ado, right. 753 00:42:33,530 --> 00:42:34,370 AUDIENCE: Oh, right. 754 00:42:34,370 --> 00:42:35,460 OK. 755 00:42:35,460 --> 00:42:36,650 PROFESSOR: That's just the fastest way to get that 756 00:42:36,650 --> 00:42:37,900 failure out of there. 757 00:42:37,900 --> 00:42:43,260 758 00:42:43,260 --> 00:42:43,850 Yes. 759 00:42:43,850 --> 00:42:46,530 AUDIENCE: If I don't fail, that means that I've matched a 760 00:42:46,530 --> 00:42:51,230 pattern, and I run the procedure extend dict and then 761 00:42:51,230 --> 00:42:52,655 pass in the pattern in the expression. 762 00:42:52,655 --> 00:42:55,270 763 00:42:55,270 --> 00:42:57,290 But the substitution will not be made at that 764 00:42:57,290 --> 00:42:58,400 point; is that right? 765 00:42:58,400 --> 00:42:59,110 I'm just-- 766 00:42:59,110 --> 00:42:59,420 PROFESSOR: No, no. 767 00:42:59,420 --> 00:43:00,960 There's no substitution being there because there's no 768 00:43:00,960 --> 00:43:02,520 skeleton to be substituted in. 769 00:43:02,520 --> 00:43:02,950 AUDIENCE: Right. 770 00:43:02,950 --> 00:43:03,070 So what-- 771 00:43:03,070 --> 00:43:04,760 PROFESSOR: All you've got there is we're making up the 772 00:43:04,760 --> 00:43:08,270 dictionary for later substitution. 773 00:43:08,270 --> 00:43:10,680 AUDIENCE: And what would the dictionary look like? 774 00:43:10,680 --> 00:43:13,540 Is it ordered pairs? 775 00:43:13,540 --> 00:43:15,940 PROFESSOR: That's--that's not told to you. 776 00:43:15,940 --> 00:43:16,700 We're being abstract. 777 00:43:16,700 --> 00:43:17,650 AUDIENCE: OK. 778 00:43:17,650 --> 00:43:18,850 PROFESSOR: Why do you want to know? 779 00:43:18,850 --> 00:43:20,075 What it is, it's a function. 780 00:43:20,075 --> 00:43:21,330 It's a function. 781 00:43:21,330 --> 00:43:22,090 AUDIENCE: Well, the reason I want to know is-- 782 00:43:22,090 --> 00:43:23,300 PROFESSOR: A function abstractly is a 783 00:43:23,300 --> 00:43:25,130 set of ordered pairs. 784 00:43:25,130 --> 00:43:29,040 It could be implemented as a set of list pairs. 785 00:43:29,040 --> 00:43:32,590 It could be implemented as some fancy table mechanism. 786 00:43:32,590 --> 00:43:35,780 It could be implemented as a function. 787 00:43:35,780 --> 00:43:38,500 And somehow, I'm building up a function. 788 00:43:38,500 --> 00:43:40,560 But I'm not telling you. 789 00:43:40,560 --> 00:43:43,090 That's up to George, who's going to build that later. 790 00:43:43,090 --> 00:43:49,430 791 00:43:49,430 --> 00:43:52,470 I know you really badly want to write concrete things. 792 00:43:52,470 --> 00:43:54,280 I'm not going to let you do that. 793 00:43:54,280 --> 00:43:56,020 AUDIENCE: Well, let me at least ask, what is the 794 00:43:56,020 --> 00:43:57,530 important information there that's being 795 00:43:57,530 --> 00:43:59,750 passed to extend dict? 796 00:43:59,750 --> 00:44:01,720 I want to pass the pattern I found-- 797 00:44:01,720 --> 00:44:02,630 PROFESSOR: Yes. 798 00:44:02,630 --> 00:44:04,870 The pattern that's matched against the expression. 799 00:44:04,870 --> 00:44:07,680 You want to have the pattern, which happens to be in those 800 00:44:07,680 --> 00:44:09,970 cases pattern variables, right? 801 00:44:09,970 --> 00:44:11,420 All of those three cases for extend 802 00:44:11,420 --> 00:44:13,220 dict are pattern variables. 803 00:44:13,220 --> 00:44:14,090 AUDIENCE: Right. 804 00:44:14,090 --> 00:44:16,370 PROFESSOR: So you have a pattern variable that is to be 805 00:44:16,370 --> 00:44:18,965 given a value in a dictionary. 806 00:44:18,965 --> 00:44:19,250 AUDIENCE: Mm-hmm. 807 00:44:19,250 --> 00:44:21,760 PROFESSOR: The value is the expression that it matched 808 00:44:21,760 --> 00:44:27,260 against. The dictionary is the set of things I've already 809 00:44:27,260 --> 00:44:30,195 figured out that I have memorized or learned. 810 00:44:30,195 --> 00:44:33,250 And I am going to make a new dictionary, which is extended 811 00:44:33,250 --> 00:44:36,870 from the original one by having that pattern variable 812 00:44:36,870 --> 00:44:39,880 have a value with the new dictionary. 813 00:44:39,880 --> 00:44:41,580 AUDIENCE: I guess what I don't understand is why can't the 814 00:44:41,580 --> 00:44:43,450 substitution be made right as soon as you find-- 815 00:44:43,450 --> 00:44:44,760 PROFESSOR: How do I know what I'm going to substitute? 816 00:44:44,760 --> 00:44:47,590 I don't know anything about this skeleton. 817 00:44:47,590 --> 00:44:49,550 This pattern, this matcher is an independent unit. 818 00:44:49,550 --> 00:44:50,320 AUDIENCE: Oh, I see. 819 00:44:50,320 --> 00:44:51,090 OK. 820 00:44:51,090 --> 00:44:51,350 PROFESSOR: Right? 821 00:44:51,350 --> 00:44:52,330 AUDIENCE: Yeah. 822 00:44:52,330 --> 00:44:53,200 PROFESSOR: I take the matcher. 823 00:44:53,200 --> 00:44:54,170 I apply the matcher. 824 00:44:54,170 --> 00:44:57,532 If it matches, then it was worth doing instantiation. 825 00:44:57,532 --> 00:44:58,516 AUDIENCE: OK, good. 826 00:44:58,516 --> 00:44:59,008 Yeah. 827 00:44:59,008 --> 00:45:00,484 PROFESSOR: OK? 828 00:45:00,484 --> 00:45:02,880 AUDIENCE: Can you just do that answer again using that 829 00:45:02,880 --> 00:45:04,940 example on the board? 830 00:45:04,940 --> 00:45:06,390 You know, what you just passed back to the matcher. 831 00:45:06,390 --> 00:45:06,900 PROFESSOR: Oh yes. 832 00:45:06,900 --> 00:45:08,480 OK, yes. 833 00:45:08,480 --> 00:45:10,660 You're looking at this example. 834 00:45:10,660 --> 00:45:14,470 At this point when I'm traversing this structure, I 835 00:45:14,470 --> 00:45:16,630 get to here: x. 836 00:45:16,630 --> 00:45:18,760 I have some dictionary, presumably an empty dictionary 837 00:45:18,760 --> 00:45:22,020 at this point if this is the whole expression. 838 00:45:22,020 --> 00:45:26,550 So I have an empty dictionary, and I've matched x against 3. 839 00:45:26,550 --> 00:45:28,850 So now, after this point, the dictionary 840 00:45:28,850 --> 00:45:33,550 contains x is 3, OK? 841 00:45:33,550 --> 00:45:35,290 Now, I continue walking along here. 842 00:45:35,290 --> 00:45:37,040 I see y. 843 00:45:37,040 --> 00:45:39,780 Now, this is a particular x, a pattern x. 844 00:45:39,780 --> 00:45:41,690 I see y, a pattern y. 845 00:45:41,690 --> 00:45:48,940 The dictionary says, oh yes, the pattern y is the symbol x 846 00:45:48,940 --> 00:45:52,360 because I've got a match there. 847 00:45:52,360 --> 00:45:55,380 So the dictionary now contains at this point two entries. 848 00:45:55,380 --> 00:46:02,180 The pattern x is 3, and the pattern y is the expression x. 849 00:46:02,180 --> 00:46:04,230 Now, I get that, I can walk along further. 850 00:46:04,230 --> 00:46:08,100 I say, oh, pattern y also wants to be 4. 851 00:46:08,100 --> 00:46:10,680 But that isn't possible, producing a failure. 852 00:46:10,680 --> 00:46:14,340 853 00:46:14,340 --> 00:46:14,830 Thank you. 854 00:46:14,830 --> 00:46:16,080 Let's take a break. 855 00:46:16,080 --> 00:47:02,380 856 00:47:02,380 --> 00:47:07,020 OK, you're seeing your first very big and hairy program. 857 00:47:07,020 --> 00:47:10,380 Now, of course, one of the goals of this subsegment is to 858 00:47:10,380 --> 00:47:12,440 get you to be able to read something like this and not be 859 00:47:12,440 --> 00:47:13,760 afraid of it. 860 00:47:13,760 --> 00:47:16,715 This one's only about four pages of code. 861 00:47:16,715 --> 00:47:20,460 By the end of the subject, I hope a 50-page program will 862 00:47:20,460 --> 00:47:22,510 not look particularly frightening. 863 00:47:22,510 --> 00:47:25,310 But I don't expect-- and I don't want you to think that I 864 00:47:25,310 --> 00:47:29,200 expect you to be getting it as it's coming out. 865 00:47:29,200 --> 00:47:31,760 You're supposed to feel the flavor of this, OK? 866 00:47:31,760 --> 00:47:33,800 And then you're supposed to think about it because it is a 867 00:47:33,800 --> 00:47:35,220 big program. 868 00:47:35,220 --> 00:47:40,812 There's a lot of stuff inside this program. 869 00:47:40,812 --> 00:47:44,400 Now, I've told you about the language we're implementing, 870 00:47:44,400 --> 00:47:46,770 the pattern match substitution language. 871 00:47:46,770 --> 00:47:48,320 I showed you some rules. 872 00:47:48,320 --> 00:47:51,490 And I've told you about matching and instantiation, 873 00:47:51,490 --> 00:47:54,240 which are the two halves of how a rule works. 874 00:47:54,240 --> 00:47:57,350 Now we have to understand the control structure by which the 875 00:47:57,350 --> 00:48:03,220 rules are applied to the expressions so as to do 876 00:48:03,220 --> 00:48:04,470 algebraic simplification. 877 00:48:04,470 --> 00:48:06,960 878 00:48:06,960 --> 00:48:12,060 Now, that's also a big complicated mess. 879 00:48:12,060 --> 00:48:16,450 The problem is that there is a variety of interlocking, 880 00:48:16,450 --> 00:48:20,140 interwoven loops, if you will, involved in this. 881 00:48:20,140 --> 00:48:22,540 For one thing, I have to apply-- 882 00:48:22,540 --> 00:48:25,910 I have to examine every subexpression of my expression 883 00:48:25,910 --> 00:48:29,070 that I'm trying to simplify. 884 00:48:29,070 --> 00:48:29,960 That we know how to do. 885 00:48:29,960 --> 00:48:34,090 It's a car cdr recursion of some sort, or something like 886 00:48:34,090 --> 00:48:37,480 that, and some sort of tree walk. 887 00:48:37,480 --> 00:48:38,850 And that's going to be happening. 888 00:48:38,850 --> 00:48:43,660 Now, for every such place, every node that I get to in 889 00:48:43,660 --> 00:48:48,270 doing my traversal of the expression I'm trying to 890 00:48:48,270 --> 00:48:53,390 simplify, I want to apply all of the rules. 891 00:48:53,390 --> 00:48:56,380 Every rule is going to look at every node. 892 00:48:56,380 --> 00:48:57,750 I'm going to rotate the rules around. 893 00:48:57,750 --> 00:49:01,660 894 00:49:01,660 --> 00:49:07,530 Now, either a rule will or will not match. 895 00:49:07,530 --> 00:49:10,140 If the rule does not match, then it's not very 896 00:49:10,140 --> 00:49:12,270 interesting. 897 00:49:12,270 --> 00:49:16,090 If the rule does match, then I'm going to replace that node 898 00:49:16,090 --> 00:49:20,110 in the expression by an alternate expression. 899 00:49:20,110 --> 00:49:21,360 I'm actually going to make a new 900 00:49:21,360 --> 00:49:23,530 expression, which contains-- 901 00:49:23,530 --> 00:49:26,560 everything contains that new value, the result of 902 00:49:26,560 --> 00:49:29,950 substituting into the skeleton, instantiating the 903 00:49:29,950 --> 00:49:32,480 skeleton for that rule at this level. 904 00:49:32,480 --> 00:49:35,670 But no one knows whether that thing that I instantiated 905 00:49:35,670 --> 00:49:38,180 there is in simplified form. 906 00:49:38,180 --> 00:49:41,690 So we're going to have to simplify that, somehow to call 907 00:49:41,690 --> 00:49:43,370 the simplifier on the thing that I just constructed. 908 00:49:43,370 --> 00:49:45,990 909 00:49:45,990 --> 00:49:48,710 And then when that's done, then I sort of can build that 910 00:49:48,710 --> 00:49:51,820 into the expression I want as my answer. 911 00:49:51,820 --> 00:49:55,490 Now, there is a basic idea here, which I will call a 912 00:49:55,490 --> 00:49:57,110 garbage- in, garbage-out simplifier. 913 00:49:57,110 --> 00:50:01,280 914 00:50:01,280 --> 00:50:03,570 It's a kind of recursive simplifier. 915 00:50:03,570 --> 00:50:06,750 And what happens is the way you simplify something is that 916 00:50:06,750 --> 00:50:10,660 simple objects like variables are simple. 917 00:50:10,660 --> 00:50:14,110 Compound objects, well, I don't know. 918 00:50:14,110 --> 00:50:16,260 What I'm going to do is I'm going to build up from simple 919 00:50:16,260 --> 00:50:19,940 objects, trying to make simple things by assuming that the 920 00:50:19,940 --> 00:50:21,220 pieces they're made out of are simple. 921 00:50:21,220 --> 00:50:24,540 922 00:50:24,540 --> 00:50:27,830 That's what's happening here. 923 00:50:27,830 --> 00:50:30,400 Well, now, if we look at the first slide-- 924 00:50:30,400 --> 00:50:31,965 no, overhead, overhead. 925 00:50:31,965 --> 00:50:35,780 If we look at the overhead, we see a very complicated program 926 00:50:35,780 --> 00:50:38,810 like we saw before for the matcher, so complicated that 927 00:50:38,810 --> 00:50:41,260 you can't read it like that. 928 00:50:41,260 --> 00:50:44,590 I just want you to get the feel of the shape of it, and 929 00:50:44,590 --> 00:50:48,880 the shape of it is that this program has various 930 00:50:48,880 --> 00:50:50,210 subprograms in it. 931 00:50:50,210 --> 00:50:53,550 932 00:50:53,550 --> 00:50:57,080 One of them--this part is the part for traversing the 933 00:50:57,080 --> 00:51:02,560 expression, and this part is the part for trying rules. 934 00:51:02,560 --> 00:51:06,490 Now, of course, we can look at that in some more detail. 935 00:51:06,490 --> 00:51:13,370 Let's look at--let's look at the first transparency, right? 936 00:51:13,370 --> 00:51:17,990 The simplifier is made out of several parts. 937 00:51:17,990 --> 00:51:20,500 Now, remember at the very beginning, the simplifier is 938 00:51:20,500 --> 00:51:24,100 the thing which takes a rules--a set of rules and 939 00:51:24,100 --> 00:51:27,190 produces a program which will simplify it relative to them. 940 00:51:27,190 --> 00:51:29,850 941 00:51:29,850 --> 00:51:32,390 So here we have our simplifier. 942 00:51:32,390 --> 00:51:36,150 It takes a rule set. 943 00:51:36,150 --> 00:51:39,440 And in the context where that rule set is defined, there are 944 00:51:39,440 --> 00:51:42,260 various other definitions that are done here. 945 00:51:42,260 --> 00:51:46,660 And then the result of this simplifier procedure is, in 946 00:51:46,660 --> 00:51:50,110 fact, one of the procedures that was defined. 947 00:51:50,110 --> 00:51:52,400 Simplify x. 948 00:51:52,400 --> 00:51:56,480 What I'm returning as the value of calling the 949 00:51:56,480 --> 00:52:01,340 simplifier on a set of rules is a procedure, the simplify x 950 00:52:01,340 --> 00:52:05,680 procedure, which is defined in that context, which is a 951 00:52:05,680 --> 00:52:08,200 simplification procedure appropriate for using those 952 00:52:08,200 --> 00:52:09,450 set of rules. 953 00:52:09,450 --> 00:52:14,930 954 00:52:14,930 --> 00:52:17,460 That's what I have there. 955 00:52:17,460 --> 00:52:21,440 Now, the first two of these procedures, this one and this 956 00:52:21,440 --> 00:52:25,070 one, are together going to be the recursive traversal of an 957 00:52:25,070 --> 00:52:26,950 expression. 958 00:52:26,950 --> 00:52:29,680 This one is the general simplification for any 959 00:52:29,680 --> 00:52:32,620 expression, and this is the thing which simplifies a list 960 00:52:32,620 --> 00:52:35,540 of parts of an expression. 961 00:52:35,540 --> 00:52:36,940 Nothing more. 962 00:52:36,940 --> 00:52:38,770 For each of those, we're going to do something complicated, 963 00:52:38,770 --> 00:52:40,340 which involves trying the rules. 964 00:52:40,340 --> 00:52:41,700 Now, we should look at the various parts. 965 00:52:41,700 --> 00:52:45,290 966 00:52:45,290 --> 00:52:47,710 Well let's look first at the recursive traversal of an 967 00:52:47,710 --> 00:52:48,530 expression. 968 00:52:48,530 --> 00:52:54,210 And this is done in a sort of simple way. 969 00:52:54,210 --> 00:52:59,310 This is a little nest of recursive procedures. 970 00:52:59,310 --> 00:53:02,580 And what we have here are two procedures-- 971 00:53:02,580 --> 00:53:06,600 one for simplifying an expression, and one for 972 00:53:06,600 --> 00:53:08,982 simplifying parts of an expression. 973 00:53:08,982 --> 00:53:12,130 And the way this works is very simple. 974 00:53:12,130 --> 00:53:16,270 If the expression I'm trying to simplify is a compound 975 00:53:16,270 --> 00:53:19,920 expression, I'm going to simplify all the parts of it. 976 00:53:19,920 --> 00:53:22,480 And that's calling--that procedure, simplify parts, is 977 00:53:22,480 --> 00:53:25,020 going to make up a new expression with all the parts 978 00:53:25,020 --> 00:53:26,920 simplified, which I'm then going to try the 979 00:53:26,920 --> 00:53:30,840 rules on over here. 980 00:53:30,840 --> 00:53:33,560 If it turns out that the expression is not compound, if 981 00:53:33,560 --> 00:53:37,990 it's simple, like just a symbol or something like pi, 982 00:53:37,990 --> 00:53:40,300 then in any case, I'm going to try the rules on it because it 983 00:53:40,300 --> 00:53:42,900 might be that I want in my set of rules to expand pi to 984 00:53:42,900 --> 00:53:48,290 3.14159265358979, dot, dot, dot. 985 00:53:48,290 --> 00:53:49,570 But I may not. 986 00:53:49,570 --> 00:53:52,750 But there is no reason not to do it. 987 00:53:52,750 --> 00:53:59,010 Now, if I want to simplify the parts, well, that's easy too. 988 00:53:59,010 --> 00:54:02,480 Either the expression is an empty one, there's no more 989 00:54:02,480 --> 00:54:05,730 parts, in which case I have the empty expression. 990 00:54:05,730 --> 00:54:11,460 Otherwise, I'm going to make a new expression by cons, which 991 00:54:11,460 --> 00:54:13,360 is the result of simplifying the first part of the 992 00:54:13,360 --> 00:54:16,370 expression, the car, and simplifying the rest of the 993 00:54:16,370 --> 00:54:21,060 expression, which is the cdr. 994 00:54:21,060 --> 00:54:23,250 Now, the reason why I'm showing you this sort of stuff 995 00:54:23,250 --> 00:54:26,740 this way is because I want you get the feeling for the 996 00:54:26,740 --> 00:54:29,800 various patterns that are very important when writing 997 00:54:29,800 --> 00:54:33,970 programs. And this could be written a different way. 998 00:54:33,970 --> 00:54:35,850 There's another way to write simplified expressions so 999 00:54:35,850 --> 00:54:37,355 there would be only one of them. 1000 00:54:37,355 --> 00:54:39,530 There would only be one little procedure here. 1001 00:54:39,530 --> 00:54:41,540 Let me just write that on the blackboard to give you a 1002 00:54:41,540 --> 00:54:42,790 feeling for that. 1003 00:54:42,790 --> 00:54:49,520 1004 00:54:49,520 --> 00:54:52,170 This in another idiom, if you will. 1005 00:54:52,170 --> 00:54:58,449 1006 00:54:58,449 --> 00:55:02,696 To simplify an expression called x, what 1007 00:55:02,696 --> 00:55:03,400 am I going to do? 1008 00:55:03,400 --> 00:55:11,100 I'm going to try the rules on the following situation. 1009 00:55:11,100 --> 00:55:12,170 If-- 1010 00:55:12,170 --> 00:55:14,090 on the following expression-- 1011 00:55:14,090 --> 00:55:15,690 compound, just like we had before. 1012 00:55:15,690 --> 00:55:21,060 1013 00:55:21,060 --> 00:55:24,270 If the expression is compound, well, what am I going to do? 1014 00:55:24,270 --> 00:55:25,970 I'm going to simplify all the parts. 1015 00:55:25,970 --> 00:55:30,950 But I already have a cdr recursion, a common pattern of 1016 00:55:30,950 --> 00:55:33,590 usage, which has been captured as a high-order procedure. 1017 00:55:33,590 --> 00:55:36,040 It's called map. 1018 00:55:36,040 --> 00:55:37,180 So I'll just write that here. 1019 00:55:37,180 --> 00:55:47,290 Map simplify the expression, all the parts of the 1020 00:55:47,290 --> 00:55:49,060 expression. 1021 00:55:49,060 --> 00:55:52,580 This says apply the simplification operation, 1022 00:55:52,580 --> 00:55:55,780 which is this one, every part of the expression, and then 1023 00:55:55,780 --> 00:56:02,440 that cuts those up into a list. It's every element of 1024 00:56:02,440 --> 00:56:06,254 the list which the expression is assumed to be made out of, 1025 00:56:06,254 --> 00:56:08,910 and otherwise, I have the expression. 1026 00:56:08,910 --> 00:56:12,650 So I don't need the helper procedure, simplify parts, 1027 00:56:12,650 --> 00:56:15,370 because that's really this. 1028 00:56:15,370 --> 00:56:17,690 So sometimes, you just write it this way. 1029 00:56:17,690 --> 00:56:20,830 It doesn't matter very much. 1030 00:56:20,830 --> 00:56:24,410 Well, now let's take a look at-- 1031 00:56:24,410 --> 00:56:27,660 let's just look at how you try rules. 1032 00:56:27,660 --> 00:56:30,540 If you look at this slide, we see this is a 1033 00:56:30,540 --> 00:56:33,680 complicated mess also. 1034 00:56:33,680 --> 00:56:36,140 I'm trying rules on an expression. 1035 00:56:36,140 --> 00:56:38,030 It turns out the expression I'm trying it on is some 1036 00:56:38,030 --> 00:56:40,490 subexpression now of the expression I started with. 1037 00:56:40,490 --> 00:56:43,040 Because the thing I just arranged allowed us to try 1038 00:56:43,040 --> 00:56:44,290 every subexpression. 1039 00:56:44,290 --> 00:56:46,050 1040 00:56:46,050 --> 00:56:50,140 So now here we're taking in a subexpression of the 1041 00:56:50,140 --> 00:56:51,080 expression we started with. 1042 00:56:51,080 --> 00:56:52,225 That's what this is. 1043 00:56:52,225 --> 00:56:55,670 And what we're going to define here is a procedure called 1044 00:56:55,670 --> 00:56:58,640 scan, which is going to try every rule. 1045 00:56:58,640 --> 00:57:01,920 And we're going to start it up on the whole set of rules. 1046 00:57:01,920 --> 00:57:06,670 This is going to go cdr-ing down the rules, if you will, 1047 00:57:06,670 --> 00:57:09,370 looking for a rule to apply. 1048 00:57:09,370 --> 00:57:14,140 And when it finds one, it'll do the job. 1049 00:57:14,140 --> 00:57:17,630 Well, let's take a look at how try rules works. 1050 00:57:17,630 --> 00:57:19,720 It's very simple: the scan rules. 1051 00:57:19,720 --> 00:57:22,066 Scan rules, the way of scanning. 1052 00:57:22,066 --> 00:57:23,270 Well, is it so simple? 1053 00:57:23,270 --> 00:57:25,510 It's a big program, of course. 1054 00:57:25,510 --> 00:57:28,060 We take a bunch of rules, which is a sublist 1055 00:57:28,060 --> 00:57:30,700 of the list of rules. 1056 00:57:30,700 --> 00:57:33,080 We've tried some of them already, and they've not been 1057 00:57:33,080 --> 00:57:35,360 appropriate, so we get to some here. 1058 00:57:35,360 --> 00:57:36,490 We get to move to the next one. 1059 00:57:36,490 --> 00:57:38,600 If there are no more rules, well then, there's nothing I 1060 00:57:38,600 --> 00:57:42,200 can do with this expression, and it's simplified. 1061 00:57:42,200 --> 00:57:46,790 However, if it turns out that there are still rules to be 1062 00:57:46,790 --> 00:57:52,180 done, then let's match the pattern of the first rule 1063 00:57:52,180 --> 00:57:55,280 against the expression using the empty dictionary to start 1064 00:57:55,280 --> 00:58:00,270 with and use that as the dictionary. 1065 00:58:00,270 --> 00:58:02,830 If that happens to be a failure, try 1066 00:58:02,830 --> 00:58:04,080 the rest of the rules. 1067 00:58:04,080 --> 00:58:06,540 1068 00:58:06,540 --> 00:58:08,790 That's all it says here. 1069 00:58:08,790 --> 00:58:11,080 It says discard that rule. 1070 00:58:11,080 --> 00:58:14,640 Otherwise, well, I'm going to get the skeleton of the first 1071 00:58:14,640 --> 00:58:17,890 rule, instantiate that relative to the dictionary, 1072 00:58:17,890 --> 00:58:20,940 and simplify the result, and that's the expression I want. 1073 00:58:20,940 --> 00:58:24,070 1074 00:58:24,070 --> 00:58:26,380 So although that was a complicated program, every 1075 00:58:26,380 --> 00:58:29,940 complicated program is made out of a lot of simple pieces. 1076 00:58:29,940 --> 00:58:34,760 Now, the pattern of recursions here is very complicated. 1077 00:58:34,760 --> 00:58:35,950 And one of the most important things is not 1078 00:58:35,950 --> 00:58:38,126 to think about that. 1079 00:58:38,126 --> 00:58:41,130 If you try to think about the actual pattern by which this 1080 00:58:41,130 --> 00:58:45,250 does something, you're going to get very confused. 1081 00:58:45,250 --> 00:58:47,420 I would. 1082 00:58:47,420 --> 00:58:51,470 This is not a matter of you can do this with practice. 1083 00:58:51,470 --> 00:58:53,761 These patterns are hard. 1084 00:58:53,761 --> 00:58:55,840 But you don't have to think about it. 1085 00:58:55,840 --> 00:58:57,010 The key to this-- 1086 00:58:57,010 --> 00:59:00,120 it's very good programming and very good design-- is to know 1087 00:59:00,120 --> 00:59:02,990 what not to think about. 1088 00:59:02,990 --> 00:59:07,540 The fact is, going back to this slide, I don't have to 1089 00:59:07,540 --> 00:59:11,640 think about it because I have specifications in my mind for 1090 00:59:11,640 --> 00:59:14,000 what simplify x does. 1091 00:59:14,000 --> 00:59:16,735 I don't have to know how it does it. 1092 00:59:16,735 --> 00:59:20,720 And it may, in fact, call scan somehow through try rules, 1093 00:59:20,720 --> 00:59:22,190 which it does. 1094 00:59:22,190 --> 00:59:24,230 And somehow, I've got another recursion going on here. 1095 00:59:24,230 --> 00:59:28,470 But since I know that simplify x is assumed by wishful 1096 00:59:28,470 --> 00:59:31,446 thinking to produce the simplified result, then I 1097 00:59:31,446 --> 00:59:33,900 don't have to think about it anymore. 1098 00:59:33,900 --> 00:59:35,030 I've used it. 1099 00:59:35,030 --> 00:59:36,480 I've used it in a reasonable way. 1100 00:59:36,480 --> 00:59:39,468 I will get a reasonable answer. 1101 00:59:39,468 --> 00:59:41,760 And you have to learn how to program that way-- 1102 00:59:41,760 --> 00:59:43,010 with abandon. 1103 00:59:43,010 --> 00:59:47,480 1104 00:59:47,480 --> 00:59:50,390 Well, there's very little left of this thing. 1105 00:59:50,390 --> 00:59:53,610 All there is left is a few details associated with what a 1106 00:59:53,610 --> 00:59:55,060 dictionary is. 1107 00:59:55,060 --> 00:59:57,520 And those of you who've been itching to know what a 1108 00:59:57,520 --> 01:00:01,130 dictionary is, well, I will flip it up and not tell you 1109 01:00:01,130 --> 01:00:04,110 anything about it. 1110 01:00:04,110 --> 01:00:06,020 Dictionaries are easy. 1111 01:00:06,020 --> 01:00:09,570 It's represented in terms of something else called an A 1112 01:00:09,570 --> 01:00:14,730 list, which is a particular pattern of usage for making 1113 01:00:14,730 --> 01:00:16,730 tables in lists. 1114 01:00:16,730 --> 01:00:17,220 They're easy. 1115 01:00:17,220 --> 01:00:21,670 They're made out of pairs, as was asked a bit ago. 1116 01:00:21,670 --> 01:00:23,270 And there are special procedures for dealing with 1117 01:00:23,270 --> 01:00:27,020 such things called assq, and you can find them in manuals. 1118 01:00:27,020 --> 01:00:28,730 I'm not terribly excited about it. 1119 01:00:28,730 --> 01:00:31,710 The only interesting thing here in extend dictionary is I 1120 01:00:31,710 --> 01:00:36,480 have to extend the dictionary with a pattern, a datum, and a 1121 01:00:36,480 --> 01:00:37,910 dictionary. 1122 01:00:37,910 --> 01:00:42,896 This pattern is, in fact, at this point a pattern variable. 1123 01:00:42,896 --> 01:00:44,880 And what do I want to do? 1124 01:00:44,880 --> 01:00:48,220 I want to pull out the name of that pattern variable, the 1125 01:00:48,220 --> 01:00:52,100 pattern variable name, and I'm going to look up in the 1126 01:00:52,100 --> 01:00:53,750 dictionary and see if it already has a value. 1127 01:00:53,750 --> 01:00:57,030 If not, I'm going to add a new one in. 1128 01:00:57,030 --> 01:01:00,730 If it does have one, if it has a value, then it had better be 1129 01:01:00,730 --> 01:01:03,920 equal to the one that was already stored away. 1130 01:01:03,920 --> 01:01:05,690 And if that's the case, the dictionary is what I 1131 01:01:05,690 --> 01:01:06,940 expected it to be. 1132 01:01:06,940 --> 01:01:11,605 Otherwise, I fail. 1133 01:01:11,605 --> 01:01:13,430 So that's easy, too. 1134 01:01:13,430 --> 01:01:15,940 If you open up any program, you're going to find inside of 1135 01:01:15,940 --> 01:01:20,000 it lots of little pieces, all of which are easy. 1136 01:01:20,000 --> 01:01:23,340 So at this point, I suppose, I've just told you some 1137 01:01:23,340 --> 01:01:27,995 million-dollar valuable information. 1138 01:01:27,995 --> 01:01:30,320 And I suppose at this point we're pretty much done with 1139 01:01:30,320 --> 01:01:31,930 this program. 1140 01:01:31,930 --> 01:01:34,330 I'd like to ask about questions. 1141 01:01:34,330 --> 01:01:35,940 AUDIENCE: Yes, can you give me the words that describe the 1142 01:01:35,940 --> 01:01:38,650 specification for a simplified expression? 1143 01:01:38,650 --> 01:01:39,475 PROFESSOR: Sure. 1144 01:01:39,475 --> 01:01:43,330 A simplified expression takes an expression and produces a 1145 01:01:43,330 --> 01:01:44,838 simplified expression. 1146 01:01:44,838 --> 01:01:48,120 That's it, OK? 1147 01:01:48,120 --> 01:01:51,212 How it does it is very easy. 1148 01:01:51,212 --> 01:01:53,710 In compound expressions, all the pieces are simplified, and 1149 01:01:53,710 --> 01:01:56,910 then the rules are tried on the result. 1150 01:01:56,910 --> 01:01:59,216 And for simple expressions, you just try all the rules. 1151 01:01:59,216 --> 01:02:01,280 AUDIENCE: So an expression is simplified by 1152 01:02:01,280 --> 01:02:02,535 virtue of the rules? 1153 01:02:02,535 --> 01:02:03,660 PROFESSOR: That's, of course, true. 1154 01:02:03,660 --> 01:02:04,140 AUDIENCE: Right. 1155 01:02:04,140 --> 01:02:06,060 PROFESSOR: And the way this works is that simplifi 1156 01:02:06,060 --> 01:02:10,000 expression, as you see here, what it does is it breaks the 1157 01:02:10,000 --> 01:02:13,190 expression down into the smallest pieces, simplifies 1158 01:02:13,190 --> 01:02:16,690 building up from the bottom using the rules to be the 1159 01:02:16,690 --> 01:02:21,100 simplifier, to do the manipulations, and constructs 1160 01:02:21,100 --> 01:02:24,400 a new expression as the result. 1161 01:02:24,400 --> 01:02:28,290 Eventually, one of things you see is that the rules 1162 01:02:28,290 --> 01:02:30,880 themselves, the try rules, call a simplified expression 1163 01:02:30,880 --> 01:02:34,280 on the results when it changes something, the 1164 01:02:34,280 --> 01:02:35,830 results of a match. 1165 01:02:35,830 --> 01:02:39,420 I'm sorry, the results of instantiation of a skeleton 1166 01:02:39,420 --> 01:02:41,900 for a rule that has matched. 1167 01:02:41,900 --> 01:02:44,570 So the spec of a simplified expression is that any 1168 01:02:44,570 --> 01:02:46,860 expression you put into it comes out simplified according 1169 01:02:46,860 --> 01:02:49,590 to those rules. 1170 01:02:49,590 --> 01:02:50,190 Thank you. 1171 01:02:50,190 --> 01:02:51,860 Let's take a break. 1172 01:02:51,860 --> 01:03:07,924 ================================================ FILE: SrtEN/lec4b_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:03,936 1 00:00:03,936 --> 00:00:04,279 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY 2 00:00:04,279 --> 00:00:05,529 JOHANN SEBASTIAN BACH] 3 00:00:05,529 --> 00:00:20,180 4 00:00:20,180 --> 00:00:21,840 PROFESSOR: So far in this course we've been talking a 5 00:00:21,840 --> 00:00:23,780 lot about data abstraction. 6 00:00:23,780 --> 00:00:28,230 And remember the idea is that we build systems that have 7 00:00:28,230 --> 00:00:31,980 these horizontal barriers in them, these abstraction 8 00:00:31,980 --> 00:00:38,490 barriers that separate use, the way you might use some 9 00:00:38,490 --> 00:00:41,180 data object, from the way you might represent it. 10 00:00:41,180 --> 00:00:48,985 11 00:00:48,985 --> 00:00:51,760 Or another way to think of that is up here you have the 12 00:00:51,760 --> 00:00:57,110 boss who's going to be using some sort of data object. 13 00:00:57,110 --> 00:01:02,310 And down here is George who's implemented it. 14 00:01:02,310 --> 00:01:05,760 Now this notion of separating use from representation so you 15 00:01:05,760 --> 00:01:10,930 can think about these two problems separately is a very, 16 00:01:10,930 --> 00:01:15,930 very powerful programming methodology, data abstraction. 17 00:01:15,930 --> 00:01:21,040 On the other hand, it's not really sufficient for really 18 00:01:21,040 --> 00:01:28,640 complex systems. And the problem with this is George. 19 00:01:28,640 --> 00:01:32,110 Or actually, the problem is that there 20 00:01:32,110 --> 00:01:34,630 are a lot of Georges. 21 00:01:34,630 --> 00:01:35,390 Let's be concrete. 22 00:01:35,390 --> 00:01:41,192 Let's suppose there is George, and there's also Martha. 23 00:01:41,192 --> 00:01:46,040 OK, now George and Martha are both working on this system, 24 00:01:46,040 --> 00:01:49,250 both designing representations, and 25 00:01:49,250 --> 00:01:51,750 absolutely are incompatible. 26 00:01:51,750 --> 00:01:54,620 They wouldn't cooperate on a representation under any 27 00:01:54,620 --> 00:01:57,250 circumstances. 28 00:01:57,250 --> 00:02:00,060 And the problem is you would like to have some system where 29 00:02:00,060 --> 00:02:05,380 both George and Martha are designing representations, and 30 00:02:05,380 --> 00:02:09,756 yet, if you're above this abstraction barrier you don't 31 00:02:09,756 --> 00:02:12,360 want to have to worry about that, whether something is 32 00:02:12,360 --> 00:02:14,180 done by George or by Martha. 33 00:02:14,180 --> 00:02:15,430 And you don't want George and Martha to 34 00:02:15,430 --> 00:02:16,630 interfere with each other. 35 00:02:16,630 --> 00:02:20,310 Somehow in designing a system, you not only want these 36 00:02:20,310 --> 00:02:26,300 horizontal barriers, but you also want some kind of 37 00:02:26,300 --> 00:02:32,980 vertical barrier to keep George and Martha separate. 38 00:02:32,980 --> 00:02:36,560 Let me be a little bit more concrete. 39 00:02:36,560 --> 00:02:42,650 Imagine that you're thinking about personnel records for a 40 00:02:42,650 --> 00:02:48,180 large company with a lot of loosely linked divisions that 41 00:02:48,180 --> 00:02:50,430 don't cooperate very well either. 42 00:02:50,430 --> 00:02:57,040 And imagine even that this company is formed by merging a 43 00:02:57,040 --> 00:02:59,450 whole bunch of companies that already have their personnel 44 00:02:59,450 --> 00:03:00,700 record system set up. 45 00:03:00,700 --> 00:03:03,250 46 00:03:03,250 --> 00:03:06,570 And imagine that once these divisions are all linked in 47 00:03:06,570 --> 00:03:08,530 some kind of very sophisticated satellite 48 00:03:08,530 --> 00:03:12,240 network, and all these databases are put together. 49 00:03:12,240 --> 00:03:17,260 And what you'd like to do is, from any place in the company, 50 00:03:17,260 --> 00:03:23,130 to be able to say things like, oh, what's the name in a 51 00:03:23,130 --> 00:03:26,400 personnel record? 52 00:03:26,400 --> 00:03:30,540 Or, what's the job description in a personnel record? 53 00:03:30,540 --> 00:03:34,840 And not have to worry about the fact that each division 54 00:03:34,840 --> 00:03:36,760 obviously is going to have completely separate 55 00:03:36,760 --> 00:03:41,580 conventions for how you might implement these records. 56 00:03:41,580 --> 00:03:44,960 From this point you don't want to know about that. 57 00:03:44,960 --> 00:03:48,430 Well how could you possibly do that? 58 00:03:48,430 --> 00:03:52,640 One way, of course, is to send down an edict from somewhere 59 00:03:52,640 --> 00:03:56,290 that everybody has to change their format to some fixed 60 00:03:56,290 --> 00:03:58,070 compatible thing. 61 00:03:58,070 --> 00:04:01,820 That's what people often try, and of course it never works. 62 00:04:01,820 --> 00:04:07,340 Another thing that you might want to do is somehow arrange 63 00:04:07,340 --> 00:04:11,250 it so you can have these vertical barriers. 64 00:04:11,250 --> 00:04:14,430 So that when you ask for the name of a personnel record, 65 00:04:14,430 --> 00:04:17,970 somehow, whatever format it happens to be, name will 66 00:04:17,970 --> 00:04:19,470 figure out how to do the right thing. 67 00:04:19,470 --> 00:04:22,730 68 00:04:22,730 --> 00:04:26,260 We want name to be, so-called, a generic operator. 69 00:04:26,260 --> 00:04:30,060 Generic operator means what it sort of precisely does depends 70 00:04:30,060 --> 00:04:33,650 on the kind of data that it's looking at. 71 00:04:33,650 --> 00:04:37,100 More than that, you'd like to design the system so that the 72 00:04:37,100 --> 00:04:43,250 next time a new division comes into the company they don't 73 00:04:43,250 --> 00:04:45,640 have to make any big changes in what they're already doing 74 00:04:45,640 --> 00:04:50,110 to link into this system, and the rest of the company 75 00:04:50,110 --> 00:04:53,500 doesn't have to make any big changes to admit their stuff 76 00:04:53,500 --> 00:04:55,520 to the system. 77 00:04:55,520 --> 00:04:58,700 So that's the problem you should be thinking about. 78 00:04:58,700 --> 00:05:00,770 Like it's sort of just your work. 79 00:05:00,770 --> 00:05:02,390 You want to be able to include new things by 80 00:05:02,390 --> 00:05:03,640 making minimal changes. 81 00:05:03,640 --> 00:05:05,980 82 00:05:05,980 --> 00:05:07,340 OK, well that's the problem that we'll be 83 00:05:07,340 --> 00:05:09,440 talking about today. 84 00:05:09,440 --> 00:05:13,140 And you should have this sort of distributed personnel 85 00:05:13,140 --> 00:05:14,240 record system in your mind. 86 00:05:14,240 --> 00:05:16,620 But actually the one I'll be talking about is a problem 87 00:05:16,620 --> 00:05:18,900 that's a little bit more self-contained than that. 88 00:05:18,900 --> 00:05:21,870 that'll bring up the issues, I think, more clearly. 89 00:05:21,870 --> 00:05:25,300 That's the problem of doing a system that does arithmetic on 90 00:05:25,300 --> 00:05:27,770 complex numbers. 91 00:05:27,770 --> 00:05:30,690 So let's take a look here. 92 00:05:30,690 --> 00:05:32,460 Just as a little review, there are things 93 00:05:32,460 --> 00:05:35,250 called complex numbers. 94 00:05:35,250 --> 00:05:36,960 Complex number you can think of as a point in 95 00:05:36,960 --> 00:05:39,370 the plane, or z. 96 00:05:39,370 --> 00:05:46,230 And you can represent a point either by its real-part and 97 00:05:46,230 --> 00:05:47,190 its imaginary-part. 98 00:05:47,190 --> 00:05:51,690 So if this is z and its real-part is this much, and 99 00:05:51,690 --> 00:05:54,880 its imaginary-part is that much, and you write z 100 00:05:54,880 --> 00:05:56,130 equals x plus iy. 101 00:05:56,130 --> 00:05:59,110 102 00:05:59,110 --> 00:06:03,210 Or another way to represent a complex number is by saying, 103 00:06:03,210 --> 00:06:10,900 what's the distance from the origin, and what's the angle? 104 00:06:10,900 --> 00:06:13,540 So that represents a complex number as its 105 00:06:13,540 --> 00:06:16,670 radius times an angle. 106 00:06:16,670 --> 00:06:19,520 107 00:06:19,520 --> 00:06:20,820 This one's called-- the original one's called 108 00:06:20,820 --> 00:06:24,690 rectangular form, rectangular representation, real- and 109 00:06:24,690 --> 00:06:28,640 imaginary-part, or polar representation. 110 00:06:28,640 --> 00:06:30,040 Magnitude and angle-- 111 00:06:30,040 --> 00:06:32,260 and if you know the real- and imaginary-part, you can figure 112 00:06:32,260 --> 00:06:33,720 out the magnitude and angle. 113 00:06:33,720 --> 00:06:37,190 If you know x and y, you can get r by this formula. 114 00:06:37,190 --> 00:06:39,480 Square root of sum of the squares, and you can get the 115 00:06:39,480 --> 00:06:41,420 angle as an arctangent. 116 00:06:41,420 --> 00:06:44,420 Or conversely, if you knew r and A you could 117 00:06:44,420 --> 00:06:45,800 figure out x and y. 118 00:06:45,800 --> 00:06:49,435 x is r times the cosine of A, and y is r times the sine of 119 00:06:49,435 --> 00:06:52,490 A. All right, so there's these two. 120 00:06:52,490 --> 00:06:54,130 They're complex numbers. 121 00:06:54,130 --> 00:06:55,810 You can think of them either in polar form 122 00:06:55,810 --> 00:06:57,150 or rectangular form. 123 00:06:57,150 --> 00:06:59,830 What we would like to do is make a system that does 124 00:06:59,830 --> 00:07:03,850 arithmetic on complex numbers. 125 00:07:03,850 --> 00:07:05,580 In other words, what we'd like-- 126 00:07:05,580 --> 00:07:07,380 just like the rational number example-- 127 00:07:07,380 --> 00:07:11,120 is to have some operations plus c, which is going to take 128 00:07:11,120 --> 00:07:14,640 two complex numbers and add them, subtract them, and 129 00:07:14,640 --> 00:07:16,910 multiply them, and divide them. 130 00:07:16,910 --> 00:07:20,730 131 00:07:20,730 --> 00:07:25,280 OK, well there's little bit of mathematics behind it. 132 00:07:25,280 --> 00:07:29,800 What are the actual formulas for manipulating such things? 133 00:07:29,800 --> 00:07:34,270 And it's sort of not important where they come from, but just 134 00:07:34,270 --> 00:07:36,120 as an implementer let's see-- 135 00:07:36,120 --> 00:07:40,030 if you want to add two complex numbers it's pretty easy to 136 00:07:40,030 --> 00:07:42,660 get its real-part and its imaginary-part. 137 00:07:42,660 --> 00:07:47,810 The real-part of the sum of two complex numbers, the 138 00:07:47,810 --> 00:07:53,720 real-part of the z1 plus z2 is the real-part of z1 plus the 139 00:07:53,720 --> 00:07:54,970 real-part of z2. 140 00:07:54,970 --> 00:07:57,820 141 00:07:57,820 --> 00:08:02,770 And the imaginary-part of z1 plus z2 is the imaginary part 142 00:08:02,770 --> 00:08:07,410 of z1 plus the imaginary part of z2. 143 00:08:07,410 --> 00:08:09,480 So it's pretty easy to add complex numbers. 144 00:08:09,480 --> 00:08:12,320 You just add the corresponding parts and make a new complex 145 00:08:12,320 --> 00:08:13,400 number with those parts. 146 00:08:13,400 --> 00:08:17,180 If you want to multiply them, it's kind of nice to do it in 147 00:08:17,180 --> 00:08:17,840 polar form. 148 00:08:17,840 --> 00:08:21,810 Because if you have two complex numbers, the magnitude 149 00:08:21,810 --> 00:08:26,285 of their product is here, the product of the magnitudes. 150 00:08:26,285 --> 00:08:28,850 151 00:08:28,850 --> 00:08:35,809 And the angle of the product is the sum of the angles. 152 00:08:35,809 --> 00:08:39,179 So that's sort of mathematics that allows you to do 153 00:08:39,179 --> 00:08:40,549 arithmetic on complex numbers. 154 00:08:40,549 --> 00:08:43,720 Let's actually think about the implementation. 155 00:08:43,720 --> 00:08:49,330 Well we do it just like rational numbers. 156 00:08:49,330 --> 00:08:52,200 We come down, we assume we have some 157 00:08:52,200 --> 00:08:53,840 constructors and selectors. 158 00:08:53,840 --> 00:08:55,330 What would we like? 159 00:08:55,330 --> 00:08:58,890 Well let's assume that we make a data object cloud, which is 160 00:08:58,890 --> 00:09:02,510 a complex number that has some stuff in it, and that we can 161 00:09:02,510 --> 00:09:05,870 get out from a complex number the real-part, or the 162 00:09:05,870 --> 00:09:12,150 imaginary-part, or the magnitude, or the angle. 163 00:09:12,150 --> 00:09:14,320 We want some ways of making complex numbers-- not only 164 00:09:14,320 --> 00:09:16,800 selectors, but constructors. 165 00:09:16,800 --> 00:09:20,160 So we'll assume we have a thing called make-rectangular. 166 00:09:20,160 --> 00:09:24,510 What make-rectangular is going to do is take a real-part and 167 00:09:24,510 --> 00:09:28,610 an imaginary-part and construct a complex number 168 00:09:28,610 --> 00:09:31,920 with those parts. 169 00:09:31,920 --> 00:09:35,010 Similarly, we can have make-polar which will take a 170 00:09:35,010 --> 00:09:42,550 magnitude and an angle, and construct a complex number 171 00:09:42,550 --> 00:09:44,680 which has that magnitude and angle. 172 00:09:44,680 --> 00:09:45,460 So here's a system. 173 00:09:45,460 --> 00:09:48,910 We'll have two constructors and four selectors. 174 00:09:48,910 --> 00:09:55,150 And now, just like before, in terms of that abstract data 175 00:09:55,150 --> 00:09:59,220 we'll go ahead and implement our complex number operations. 176 00:09:59,220 --> 00:10:03,280 And here you can see translated into Lisp code just 177 00:10:03,280 --> 00:10:08,330 the arithmetic formulas I put down before. 178 00:10:08,330 --> 00:10:13,450 If I want to add two complex numbers I will make a complex 179 00:10:13,450 --> 00:10:16,630 number out of its real- and imaginary-parts. 180 00:10:16,630 --> 00:10:19,680 The real part of the complex number I'm going to make is 181 00:10:19,680 --> 00:10:23,310 the sum of the real-parts. 182 00:10:23,310 --> 00:10:25,250 The imaginary part of the complex number I'm going to 183 00:10:25,250 --> 00:10:27,005 make is the sum of the imaginary-parts. 184 00:10:27,005 --> 00:10:30,310 185 00:10:30,310 --> 00:10:31,990 I put those together, make a complex number. 186 00:10:31,990 --> 00:10:35,780 That's how I implement complex number addition. 187 00:10:35,780 --> 00:10:39,650 Subtraction is essentially the same. 188 00:10:39,650 --> 00:10:45,140 All I do is subtract the parts rather than add them. 189 00:10:45,140 --> 00:10:47,980 To multiply two complex numbers, I 190 00:10:47,980 --> 00:10:49,270 use the other formula. 191 00:10:49,270 --> 00:10:55,350 I'll make a complex number out of a magnitude and angle. 192 00:10:55,350 --> 00:10:58,740 The magnitude is going to be the product of the magnitudes 193 00:10:58,740 --> 00:11:00,465 of the two complex numbers I'm multiplying. 194 00:11:00,465 --> 00:11:03,710 195 00:11:03,710 --> 00:11:06,980 And the angle is going to be the sum of the angles of the 196 00:11:06,980 --> 00:11:09,620 two complex numbers I'm multiplying. 197 00:11:09,620 --> 00:11:11,230 So there's multiplication. 198 00:11:11,230 --> 00:11:17,370 And then division, division is almost the same. 199 00:11:17,370 --> 00:11:19,660 Here I divide the magnitudes and subtract the angles. 200 00:11:19,660 --> 00:11:28,640 201 00:11:28,640 --> 00:11:31,870 Now I've implemented the operations. 202 00:11:31,870 --> 00:11:33,640 And what do we do? 203 00:11:33,640 --> 00:11:36,060 We call on George. 204 00:11:36,060 --> 00:11:38,070 We've done the use, let's worry about the 205 00:11:38,070 --> 00:11:38,800 representation. 206 00:11:38,800 --> 00:11:42,200 We'll call on George and say to George, go ahead and build 207 00:11:42,200 --> 00:11:45,250 us a complex number representation. 208 00:11:45,250 --> 00:11:47,770 Well that's fine. 209 00:11:47,770 --> 00:11:52,660 George can say, we'll implement a complex number 210 00:11:52,660 --> 00:11:56,400 simply as a pair that has the real-part and the 211 00:11:56,400 --> 00:11:57,200 imaginary-part. 212 00:11:57,200 --> 00:12:01,020 So if I want to make a complex number with a certain 213 00:12:01,020 --> 00:12:03,860 real-part and an imaginary-part, I'll just use 214 00:12:03,860 --> 00:12:06,640 cons to form a pair, and that will-- that's George's 215 00:12:06,640 --> 00:12:09,780 representation of a complex number. 216 00:12:09,780 --> 00:12:12,420 So if I want to get out the real-part of something, I just 217 00:12:12,420 --> 00:12:14,350 extract the car, the first part. 218 00:12:14,350 --> 00:12:16,300 If I want to get the imaginary-part, I extract the 219 00:12:16,300 --> 00:12:22,220 cdr. How do I deal with the magnitude and angle? 220 00:12:22,220 --> 00:12:25,550 Well if I want to extract the magnitude of one of these 221 00:12:25,550 --> 00:12:28,895 things, I get the square root of the sum of the square of 222 00:12:28,895 --> 00:12:34,310 the car plus the square of the cdr. If I want to get the 223 00:12:34,310 --> 00:12:37,660 angle, I compute the arctangent of 224 00:12:37,660 --> 00:12:39,530 the cdr in the car. 225 00:12:39,530 --> 00:12:42,300 This is a list procedure for computing arctangent. 226 00:12:42,300 --> 00:12:44,970 227 00:12:44,970 --> 00:12:49,150 And if somebody hands me a magnitude and an angle and 228 00:12:49,150 --> 00:12:51,670 says, make me a complex number, well I compute the 229 00:12:51,670 --> 00:12:54,280 real-part and the imaginary-part, or our cosine 230 00:12:54,280 --> 00:12:58,120 of a and our sine of a, and stick them 231 00:12:58,120 --> 00:13:01,460 together into a pair. 232 00:13:01,460 --> 00:13:02,260 OK so we're done. 233 00:13:02,260 --> 00:13:07,830 In fact, what I just did, conceptually, is absolutely no 234 00:13:07,830 --> 00:13:11,710 different from the rational number representation that we 235 00:13:11,710 --> 00:13:12,510 looked at last time. 236 00:13:12,510 --> 00:13:13,910 It's the same sort of idea. 237 00:13:13,910 --> 00:13:18,070 You implement the operators, you pick a representation. 238 00:13:18,070 --> 00:13:20,070 Nothing different. 239 00:13:20,070 --> 00:13:23,210 Now let's worry about Martha. 240 00:13:23,210 --> 00:13:26,670 See, Martha has a different idea. 241 00:13:26,670 --> 00:13:29,490 She doesn't want to represent a complex number as a pair of 242 00:13:29,490 --> 00:13:30,900 a real-part and an imaginary-part. 243 00:13:30,900 --> 00:13:34,170 What she would like to do is represent a complex number as 244 00:13:34,170 --> 00:13:39,550 a pair of a magnitude and an angle. 245 00:13:39,550 --> 00:13:42,130 So if instead of calling up George we ask Martha to design 246 00:13:42,130 --> 00:13:44,570 our representation, we get something like this. 247 00:13:44,570 --> 00:13:47,160 We get make-polar. 248 00:13:47,160 --> 00:13:50,220 Sure, if I give you a magnitude and an angle we're 249 00:13:50,220 --> 00:13:55,430 just going to form a pair that has magnitude and angle. 250 00:13:55,430 --> 00:13:57,680 If you want to extract the magnitude, that's easy. 251 00:13:57,680 --> 00:13:59,780 You just pull out the car or the pair. 252 00:13:59,780 --> 00:14:02,670 If you want to extract the angle, sure, that's easy. 253 00:14:02,670 --> 00:14:05,480 You just pull out the cdr. If you want to look for 254 00:14:05,480 --> 00:14:07,660 real-parts and imaginary-parts, well then you 255 00:14:07,660 --> 00:14:08,590 have to do some work. 256 00:14:08,590 --> 00:14:14,580 If you want the real-part, you have to get r cosine a. 257 00:14:14,580 --> 00:14:19,990 In other words, r, the car of the pair, times the cosine of 258 00:14:19,990 --> 00:14:20,910 the cdr of the pair. 259 00:14:20,910 --> 00:14:26,230 So this is r times the cosine of a, 260 00:14:26,230 --> 00:14:28,330 and that's the real-part. 261 00:14:28,330 --> 00:14:30,810 If you want to get the imaginary-part, it's r times 262 00:14:30,810 --> 00:14:32,660 the sine of a. 263 00:14:32,660 --> 00:14:37,930 And if I hand you a real-part and an imaginary-part and say, 264 00:14:37,930 --> 00:14:42,030 make me a complex number with that real-part and 265 00:14:42,030 --> 00:14:44,170 imaginary-part, well I figure out what the magnitude and 266 00:14:44,170 --> 00:14:45,540 angle should be. 267 00:14:45,540 --> 00:14:48,090 The magnitude's the square root of the sum of the squares 268 00:14:48,090 --> 00:14:49,230 and the angle's the arctangent. 269 00:14:49,230 --> 00:14:52,090 I put those together to make a pair. 270 00:14:52,090 --> 00:14:54,170 So there's Martha's idea. 271 00:14:54,170 --> 00:14:56,690 272 00:14:56,690 --> 00:14:59,680 Well which is better? 273 00:14:59,680 --> 00:15:02,850 Well if you're doing a lot of additions, probably George's 274 00:15:02,850 --> 00:15:04,810 is better, because you're doing a lot of real-parts and 275 00:15:04,810 --> 00:15:05,850 imaginary-parts. 276 00:15:05,850 --> 00:15:07,920 If mostly you're going to be doing multiplications and 277 00:15:07,920 --> 00:15:11,140 divisions, then maybe Martha's idea is better. 278 00:15:11,140 --> 00:15:16,590 Or maybe, and this is the real point, you can't decide. 279 00:15:16,590 --> 00:15:21,170 Or maybe you just have to let them both hang around, for 280 00:15:21,170 --> 00:15:23,480 personality reasons. 281 00:15:23,480 --> 00:15:25,870 Maybe you just really can't ever decide 282 00:15:25,870 --> 00:15:28,560 what you would like. 283 00:15:28,560 --> 00:15:31,520 And again, what we would really like is a system that 284 00:15:31,520 --> 00:15:32,320 looks like this. 285 00:15:32,320 --> 00:15:37,090 That somehow there's George over here, who has built 286 00:15:37,090 --> 00:15:41,470 rectangular complex numbers. 287 00:15:41,470 --> 00:15:46,120 And Martha, who has polar complex numbers. 288 00:15:46,120 --> 00:15:54,200 And somehow we have operations that can add, and subtract, 289 00:15:54,200 --> 00:15:59,710 and multiply, and divide, and it shouldn't matter that there 290 00:15:59,710 --> 00:16:02,790 are two incompatible representations of complex 291 00:16:02,790 --> 00:16:04,410 numbers floating around this system. 292 00:16:04,410 --> 00:16:09,640 In other words, not only like an abstraction barrier here 293 00:16:09,640 --> 00:16:15,770 that has things in it like a real-part, and an 294 00:16:15,770 --> 00:16:23,830 imaginary-part, and magnitude, and angle. 295 00:16:23,830 --> 00:16:26,850 So not only is there an abstraction barrier that hides 296 00:16:26,850 --> 00:16:30,310 the actual representation from us, but also there's some kind 297 00:16:30,310 --> 00:16:33,620 of vertical barrier here that allows both of these 298 00:16:33,620 --> 00:16:36,270 representations to exist without 299 00:16:36,270 --> 00:16:38,570 interfering with each other. 300 00:16:38,570 --> 00:16:41,900 The idea is that the things in here-- 301 00:16:41,900 --> 00:16:44,120 real-part, imaginary-part, magnitude, and angle-- 302 00:16:44,120 --> 00:16:47,310 will be generic operators. 303 00:16:47,310 --> 00:16:50,190 If you ask for the real-part, it will worry about what 304 00:16:50,190 --> 00:16:53,880 representation it's looking at. 305 00:16:53,880 --> 00:16:56,840 OK, well how can we do that? 306 00:16:56,840 --> 00:17:00,290 There's actually a really obvious idea, if you're used 307 00:17:00,290 --> 00:17:02,770 to thinking about complex numbers. 308 00:17:02,770 --> 00:17:06,390 If you're used to thinking about compound data. 309 00:17:06,390 --> 00:17:10,690 See, suppose you could just tell by looking at a complex 310 00:17:10,690 --> 00:17:13,190 number whether it was constructed 311 00:17:13,190 --> 00:17:15,790 by George or Martha. 312 00:17:15,790 --> 00:17:18,900 In other words, so it's not that what's floating around 313 00:17:18,900 --> 00:17:20,910 here are ordinary, just complex numbers, right? 314 00:17:20,910 --> 00:17:24,390 They're fancy, designer complex numbers. 315 00:17:24,390 --> 00:17:27,260 So you look at a complex numbers as it's not just a 316 00:17:27,260 --> 00:17:29,190 complex number, it's got a label on it that says, this 317 00:17:29,190 --> 00:17:31,450 one is by Martha. 318 00:17:31,450 --> 00:17:34,480 Or this is a complex number by George. 319 00:17:34,480 --> 00:17:34,700 Right? 320 00:17:34,700 --> 00:17:36,860 They're signed. 321 00:17:36,860 --> 00:17:40,155 See, and then whenever we looked at a complex number we 322 00:17:40,155 --> 00:17:45,800 could just read the label, and then we'd know how you expect 323 00:17:45,800 --> 00:17:48,030 to operate on that. 324 00:17:48,030 --> 00:17:49,850 In other words, what we want is not just 325 00:17:49,850 --> 00:17:51,190 ordinary data objects. 326 00:17:51,190 --> 00:17:53,120 We want to introduce the notion of what's 327 00:17:53,120 --> 00:17:54,370 called typed data. 328 00:17:54,370 --> 00:17:59,760 329 00:17:59,760 --> 00:18:03,940 Typed data means, again, there's some sort of cloud. 330 00:18:03,940 --> 00:18:08,930 And what it's got in it is an ordinary data object like 331 00:18:08,930 --> 00:18:10,180 we've been thinking about. 332 00:18:10,180 --> 00:18:13,180 333 00:18:13,180 --> 00:18:16,540 Pulled out the contents, sort of the actual data. 334 00:18:16,540 --> 00:18:19,320 335 00:18:19,320 --> 00:18:24,220 But also a thing called a type, but it's signed by 336 00:18:24,220 --> 00:18:25,850 either George or Martha. 337 00:18:25,850 --> 00:18:28,340 So we're going to go from regular data to type data. 338 00:18:28,340 --> 00:18:31,950 339 00:18:31,950 --> 00:18:32,710 How do we build that? 340 00:18:32,710 --> 00:18:33,990 Well that's easy. 341 00:18:33,990 --> 00:18:34,980 We know how to build clouds. 342 00:18:34,980 --> 00:18:37,920 We build them out of pairs. 343 00:18:37,920 --> 00:18:41,050 So here's a little representation that supports 344 00:18:41,050 --> 00:18:43,510 typed data. 345 00:18:43,510 --> 00:18:49,020 There's a thing called take a type and attach it to a piece 346 00:18:49,020 --> 00:18:51,530 of contents, and we just use cons. 347 00:18:51,530 --> 00:18:53,770 And if we have a piece of typed data, we can look at the 348 00:18:53,770 --> 00:18:56,290 type, which is the car. 349 00:18:56,290 --> 00:19:00,460 We can look at the contents, which is the cdr. Now along 350 00:19:00,460 --> 00:19:05,420 with that, the way we use our type data will test, when 351 00:19:05,420 --> 00:19:07,520 we're given a piece of data, what type it is. 352 00:19:07,520 --> 00:19:10,510 So we have some type predicates with us. 353 00:19:10,510 --> 00:19:13,730 For example, to see whether a complex number is one of 354 00:19:13,730 --> 00:19:16,860 George's, whether it's rectangular, we just check to 355 00:19:16,860 --> 00:19:23,850 see if the type of that is the symbol rectangular, right? 356 00:19:23,850 --> 00:19:25,100 The symbol rectangular. 357 00:19:25,100 --> 00:19:27,200 358 00:19:27,200 --> 00:19:30,650 And to check whether a complex number is one of Martha's, we 359 00:19:30,650 --> 00:19:33,430 check to see whether the type is the symbol polar. 360 00:19:33,430 --> 00:19:36,460 361 00:19:36,460 --> 00:19:38,710 So that's a way to test what kind of number 362 00:19:38,710 --> 00:19:40,350 we're looking at. 363 00:19:40,350 --> 00:19:42,070 Now let's think about how we can use that 364 00:19:42,070 --> 00:19:43,870 to build the system. 365 00:19:43,870 --> 00:19:46,170 So let's suppose that George and Martha were off working 366 00:19:46,170 --> 00:19:50,710 separately, and each of them had designed their complex 367 00:19:50,710 --> 00:19:52,640 number representation packages. 368 00:19:52,640 --> 00:19:58,980 What do they have to do to become part of the system, to 369 00:19:58,980 --> 00:20:00,140 exist compatibly? 370 00:20:00,140 --> 00:20:02,860 Well it's really pretty easy. 371 00:20:02,860 --> 00:20:05,970 Remember, George had this package. 372 00:20:05,970 --> 00:20:08,980 Here's George's original package, or half of it. 373 00:20:08,980 --> 00:20:12,090 And underlined in red are the changes he has to make. 374 00:20:12,090 --> 00:20:16,010 So before, when George made a complex number out of an x and 375 00:20:16,010 --> 00:20:20,930 y, he just put them together to make a pair. 376 00:20:20,930 --> 00:20:24,090 And the only difference is that now he signs them. 377 00:20:24,090 --> 00:20:26,920 He attaches the type, which is the symbol 378 00:20:26,920 --> 00:20:30,600 rectangular to that pair. 379 00:20:30,600 --> 00:20:33,920 Everything else George does is the same, except that-- 380 00:20:33,920 --> 00:20:35,970 see, George and Martha both have procedures named 381 00:20:35,970 --> 00:20:38,700 real-part and imaginary-part. 382 00:20:38,700 --> 00:20:44,220 So to allow them both to exist in the same Lisp environment, 383 00:20:44,220 --> 00:20:45,920 George had changed the names of his procedures. 384 00:20:45,920 --> 00:20:49,045 So we'll say, this is George's real-part procedure. 385 00:20:49,045 --> 00:20:52,710 It's the real-part rectangular procedure, the imaginary-part 386 00:20:52,710 --> 00:20:55,170 rectangular procedure. 387 00:20:55,170 --> 00:20:59,130 And then here's the rest of George's package. 388 00:20:59,130 --> 00:21:02,060 He'd had magnitude and angle, just renames them magnitude 389 00:21:02,060 --> 00:21:05,702 rectangular and angle rectangular. 390 00:21:05,702 --> 00:21:09,860 And Martha has to do basically the same thing. 391 00:21:09,860 --> 00:21:15,200 Martha previously, when she made a complex number out of a 392 00:21:15,200 --> 00:21:19,270 magnitude and angle, she just cons them. 393 00:21:19,270 --> 00:21:25,330 Now she attaches the type polar, and she changes the 394 00:21:25,330 --> 00:21:28,100 name so her real-part procedure won't conflict in 395 00:21:28,100 --> 00:21:30,710 name with George's. 396 00:21:30,710 --> 00:21:34,540 It's a real-part-polar, imaginary-part-polar, 397 00:21:34,540 --> 00:21:38,060 magnitude polar, and angle polar. 398 00:21:38,060 --> 00:21:45,000 399 00:21:45,000 --> 00:21:46,130 Now we have the system. 400 00:21:46,130 --> 00:21:49,160 Right there's George and Martha. 401 00:21:49,160 --> 00:21:51,050 And now we've got to get some kind of manager to look at 402 00:21:51,050 --> 00:21:52,300 these types. 403 00:21:52,300 --> 00:21:55,050 404 00:21:55,050 --> 00:21:57,530 How are these things actually going to work now that George 405 00:21:57,530 --> 00:22:00,530 and Martha have supplied us with typed data? 406 00:22:00,530 --> 00:22:05,260 Well what we have are a bunch of generic selectors. 407 00:22:05,260 --> 00:22:07,800 Generic selectors for complex numbers real-part, 408 00:22:07,800 --> 00:22:10,630 imaginary-part, magnitude, and angle. 409 00:22:10,630 --> 00:22:14,140 410 00:22:14,140 --> 00:22:15,410 Let's look at them more closely. 411 00:22:15,410 --> 00:22:17,930 412 00:22:17,930 --> 00:22:19,310 What does a real-part do? 413 00:22:19,310 --> 00:22:24,070 If I ask for the real part of a complex number, 414 00:22:24,070 --> 00:22:25,800 well I look at it. 415 00:22:25,800 --> 00:22:26,690 I look at its type. 416 00:22:26,690 --> 00:22:27,940 I say, is it rectangular? 417 00:22:27,940 --> 00:22:31,020 418 00:22:31,020 --> 00:22:36,970 If so, I apply George's real part procedure to the contents 419 00:22:36,970 --> 00:22:38,220 of that complex number. 420 00:22:38,220 --> 00:22:41,230 421 00:22:41,230 --> 00:22:43,720 This is a number that has a type on it. 422 00:22:43,720 --> 00:22:46,340 I strip off the type using contents and 423 00:22:46,340 --> 00:22:47,590 apply George's procedure. 424 00:22:47,590 --> 00:22:50,700 425 00:22:50,700 --> 00:22:53,950 Or is this a polar complex number? 426 00:22:53,950 --> 00:22:56,890 If I want the real part, I apply Martha's real part 427 00:22:56,890 --> 00:22:59,850 procedure to the contents of that number. 428 00:22:59,850 --> 00:23:02,260 So that's how real part works. 429 00:23:02,260 --> 00:23:04,670 And then similarly there's imaginary-part, which is 430 00:23:04,670 --> 00:23:06,770 almost the same. 431 00:23:06,770 --> 00:23:09,600 It looks at the number and if it's rectangular, uses 432 00:23:09,600 --> 00:23:11,130 George's imaginary-part procedure. 433 00:23:11,130 --> 00:23:13,380 If it's polar, uses Martha's. 434 00:23:13,380 --> 00:23:17,240 And then there's a magnitude and an angle. 435 00:23:17,240 --> 00:23:19,880 436 00:23:19,880 --> 00:23:21,130 So there's a system. 437 00:23:21,130 --> 00:23:23,460 438 00:23:23,460 --> 00:23:24,260 Has three parts. 439 00:23:24,260 --> 00:23:26,760 There's sort of George, and Martha, and the manager. 440 00:23:26,760 --> 00:23:28,970 And that's how you get generic operators implemented. 441 00:23:28,970 --> 00:23:33,500 Let's look at just a simple example, just to pin it down. 442 00:23:33,500 --> 00:23:40,240 But exactly how this is going to work, suppose you're going 443 00:23:40,240 --> 00:23:44,460 to be looking at the complex number who's real-part is one, 444 00:23:44,460 --> 00:23:46,090 and who's imaginary-part is two. 445 00:23:46,090 --> 00:23:50,310 So that would be one plus 2i. 446 00:23:50,310 --> 00:23:56,350 What would happen is up here, up here above where the 447 00:23:56,350 --> 00:23:58,530 operations have to happen, that number would be 448 00:23:58,530 --> 00:24:10,320 represented as a pair of 1 and 2 together with typed data. 449 00:24:10,320 --> 00:24:11,870 That would be the contents. 450 00:24:11,870 --> 00:24:16,300 And the whole data would be that thing with the symbol 451 00:24:16,300 --> 00:24:17,960 rectangular added onto that. 452 00:24:17,960 --> 00:24:20,980 And that's the way that complex number would exist in 453 00:24:20,980 --> 00:24:22,330 the system. 454 00:24:22,330 --> 00:24:26,560 When you went to take the real-part, the manager would 455 00:24:26,560 --> 00:24:30,270 look at this and say, oh it's one of George's. 456 00:24:30,270 --> 00:24:34,440 He'll strip off the type and hand down to 457 00:24:34,440 --> 00:24:37,532 George the pair 1, 2. 458 00:24:37,532 --> 00:24:41,420 And that's the kind of data that George developed his 459 00:24:41,420 --> 00:24:42,670 system to use. 460 00:24:42,670 --> 00:24:44,950 461 00:24:44,950 --> 00:24:46,680 So it gets stripped down. 462 00:24:46,680 --> 00:24:51,240 Later on, if you ask George to construct a complex number, 463 00:24:51,240 --> 00:24:55,370 George would construct some complex number as a pair, and 464 00:24:55,370 --> 00:24:59,630 before he passes it back up through the manager would 465 00:24:59,630 --> 00:25:00,880 attach the type rectangular. 466 00:25:00,880 --> 00:25:03,920 467 00:25:03,920 --> 00:25:04,650 So you see what happens. 468 00:25:04,650 --> 00:25:05,850 There's no confusion in this system. 469 00:25:05,850 --> 00:25:13,780 It doesn't matter in the least that the pair 1, 2 means 470 00:25:13,780 --> 00:25:15,750 something completely different in Martha's world. 471 00:25:15,750 --> 00:25:18,440 In Martha's world this pair means the complex number whose 472 00:25:18,440 --> 00:25:21,190 magnitude is 1 and whose angle is 2. 473 00:25:21,190 --> 00:25:23,930 And there's no confusion, because by the time any pair 474 00:25:23,930 --> 00:25:27,250 like this gets handed back through the manager to the 475 00:25:27,250 --> 00:25:31,210 main system it's going to have the type polar attached. 476 00:25:31,210 --> 00:25:33,670 Whereas this one would have the type rectangular attached. 477 00:25:33,670 --> 00:25:36,930 478 00:25:36,930 --> 00:25:38,180 OK, let's take a break. 479 00:25:38,180 --> 00:25:40,770 480 00:25:40,770 --> 00:25:41,057 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY 481 00:25:41,057 --> 00:25:42,307 JOHANN SEBASTIAN BACH] 482 00:25:42,307 --> 00:26:20,210 483 00:26:20,210 --> 00:26:22,080 We just looked at a strategy for 484 00:26:22,080 --> 00:26:24,150 implementing generic operators. 485 00:26:24,150 --> 00:26:31,400 That strategy has a name: it's called dispatch type. 486 00:26:31,400 --> 00:26:34,310 487 00:26:34,310 --> 00:26:38,480 And the idea is that you break your system 488 00:26:38,480 --> 00:26:39,360 into a bunch of pieces. 489 00:26:39,360 --> 00:26:43,250 There's George and Martha, who are making representations, 490 00:26:43,250 --> 00:26:46,320 and then there's the manager. 491 00:26:46,320 --> 00:26:49,880 Looks at the types on the data and then dispatches them to 492 00:26:49,880 --> 00:26:51,990 the right person. 493 00:26:51,990 --> 00:26:55,320 Well what criticisms can we make of that as a system 494 00:26:55,320 --> 00:26:56,570 organization? 495 00:26:56,570 --> 00:26:58,150 496 00:26:58,150 --> 00:27:00,400 Well first of all there was this little, annoying problem 497 00:27:00,400 --> 00:27:02,350 that George and Martha had to change the names of their 498 00:27:02,350 --> 00:27:04,220 procedures. 499 00:27:04,220 --> 00:27:06,160 George originally had a real-part procedure, and he 500 00:27:06,160 --> 00:27:09,110 had to go name it real-part rectangular so it wouldn't 501 00:27:09,110 --> 00:27:11,170 interfere with Martha's real-part procedure, which is 502 00:27:11,170 --> 00:27:14,410 now named real-part-polar, so it wouldn't interfere with the 503 00:27:14,410 --> 00:27:17,310 manager's real-part procedure, who's now named real-part. 504 00:27:17,310 --> 00:27:19,460 That's kind of an annoying problem. 505 00:27:19,460 --> 00:27:21,270 But I'm not going to talk about that one now. 506 00:27:21,270 --> 00:27:24,450 We'll see later on when we think about the structure of 507 00:27:24,450 --> 00:27:27,480 Lisp names and environments that there really are ways to 508 00:27:27,480 --> 00:27:30,390 package all those so-called name spaces separately so they 509 00:27:30,390 --> 00:27:32,500 don't interfere with each other. 510 00:27:32,500 --> 00:27:35,720 Not going to think about that problem now. 511 00:27:35,720 --> 00:27:38,740 The problem that I actually want to focus on is what 512 00:27:38,740 --> 00:27:44,510 happens when you bring somebody new into the system. 513 00:27:44,510 --> 00:27:45,320 What has to happen? 514 00:27:45,320 --> 00:27:47,690 Well George and Martha don't care. 515 00:27:47,690 --> 00:27:52,830 George is sitting there in his rectangular world, has his 516 00:27:52,830 --> 00:27:54,090 procedures and his types. 517 00:27:54,090 --> 00:27:56,260 Martha sits in her polar world. 518 00:27:56,260 --> 00:27:59,380 She doesn't care. 519 00:27:59,380 --> 00:28:01,540 But let's look at the manager. 520 00:28:01,540 --> 00:28:03,180 What's the manager have to do? 521 00:28:03,180 --> 00:28:07,360 The manager comes through and had these operations. 522 00:28:07,360 --> 00:28:09,040 There was a test for rectangular 523 00:28:09,040 --> 00:28:10,140 and a test for polar. 524 00:28:10,140 --> 00:28:17,210 If Harry comes in with some new kind of complex number, 525 00:28:17,210 --> 00:28:20,430 and Harry has a new type, Harry type complex number, the 526 00:28:20,430 --> 00:28:25,240 manager has to go in and change all those procedures. 527 00:28:25,240 --> 00:28:28,940 So the inflexibility in the system, the place where work 528 00:28:28,940 --> 00:28:34,890 has to happen to accommodate change, is in the manager. 529 00:28:34,890 --> 00:28:35,990 That's pretty annoying. 530 00:28:35,990 --> 00:28:40,300 It's even more annoying when you realize the manager's not 531 00:28:40,300 --> 00:28:42,590 doing anything. 532 00:28:42,590 --> 00:28:46,690 The manager is just being a paper pusher. 533 00:28:46,690 --> 00:28:51,760 Let's look again at these programs. What are they doing? 534 00:28:51,760 --> 00:28:52,880 What does real-part do? 535 00:28:52,880 --> 00:28:56,170 Real-part says, oh, is it the kind of complex number that 536 00:28:56,170 --> 00:28:57,000 George can handle? 537 00:28:57,000 --> 00:28:59,410 If so, send it off to George. 538 00:28:59,410 --> 00:29:01,910 Is it the kind of complex number that Martha can handle? 539 00:29:01,910 --> 00:29:05,040 If so, send it off to Martha. 540 00:29:05,040 --> 00:29:08,720 So it's really annoying that the bottleneck in this system, 541 00:29:08,720 --> 00:29:13,040 the thing that's preventing flexibility and change, is 542 00:29:13,040 --> 00:29:15,000 completely in the bureaucracy. 543 00:29:15,000 --> 00:29:19,700 It's not in anybody who's doing any of the work. 544 00:29:19,700 --> 00:29:23,300 Not an uncommon situation, unfortunately. 545 00:29:23,300 --> 00:29:24,570 See, what's really going on-- 546 00:29:24,570 --> 00:29:28,100 abstractly in the system, there's a table. 547 00:29:28,100 --> 00:29:30,150 So what's really happening is somewhere there's a table. 548 00:29:30,150 --> 00:29:32,780 549 00:29:32,780 --> 00:29:34,400 There're types. 550 00:29:34,400 --> 00:29:38,565 There's polar and rectangular. 551 00:29:38,565 --> 00:29:41,550 552 00:29:41,550 --> 00:29:44,380 And Harry's may be over here. 553 00:29:44,380 --> 00:29:48,050 And there are operators. 554 00:29:48,050 --> 00:29:50,340 There's an operator like real-part. 555 00:29:50,340 --> 00:29:55,600 556 00:29:55,600 --> 00:30:00,010 Or imaginary-part. 557 00:30:00,010 --> 00:30:05,830 Or a magnitude and angle. 558 00:30:05,830 --> 00:30:19,280 And sitting in this table are the right procedures. 559 00:30:19,280 --> 00:30:21,990 So sitting here for the type polar and real-part is 560 00:30:21,990 --> 00:30:24,730 Martha's procedure real-part-polar. 561 00:30:24,730 --> 00:30:30,570 562 00:30:30,570 --> 00:30:33,740 And over here in the table is George's procedure 563 00:30:33,740 --> 00:30:34,990 real-part-rectangular. 564 00:30:34,990 --> 00:30:37,740 565 00:30:37,740 --> 00:30:40,680 And over here would be, say, Martha's procedure 566 00:30:40,680 --> 00:30:46,780 magnitude-polar, and George's procedure 567 00:30:46,780 --> 00:30:49,760 magnitude-rectangular, right, and so on. 568 00:30:49,760 --> 00:30:52,390 The rest of this table's filled in. 569 00:30:52,390 --> 00:30:54,260 And that's really what's going on. 570 00:30:54,260 --> 00:30:57,630 571 00:30:57,630 --> 00:31:03,380 So in some sense, all the manager is doing is acting as 572 00:31:03,380 --> 00:31:04,630 this table. 573 00:31:04,630 --> 00:31:06,860 574 00:31:06,860 --> 00:31:08,610 Well how do we fix our system? 575 00:31:08,610 --> 00:31:12,110 576 00:31:12,110 --> 00:31:13,770 How do you fix bureaucracies a lot of the time? 577 00:31:13,770 --> 00:31:16,240 What you do is you get rid of the manager. 578 00:31:16,240 --> 00:31:20,170 We just take the manager and replace him by a computer. 579 00:31:20,170 --> 00:31:23,320 We're going to automate him out of existence. 580 00:31:23,320 --> 00:31:25,970 Namely, instead of having the manager who basically consults 581 00:31:25,970 --> 00:31:31,020 this table, we'll have our system use the table directly. 582 00:31:31,020 --> 00:31:32,110 What do I mean by that? 583 00:31:32,110 --> 00:31:38,730 Let's assume, again using data abstraction, that we have some 584 00:31:38,730 --> 00:31:40,880 kind of data structure that's a table. 585 00:31:40,880 --> 00:31:43,080 And we have ways of sticking things in and ways of getting 586 00:31:43,080 --> 00:31:44,356 things out. 587 00:31:44,356 --> 00:31:47,000 And to be explicit, let me assume that there's an 588 00:31:47,000 --> 00:31:52,710 operation called "put." And put is going to take, in this 589 00:31:52,710 --> 00:32:00,130 case two things I'll call "keys." Key1 and key2. 590 00:32:00,130 --> 00:32:01,380 And a value. 591 00:32:01,380 --> 00:32:06,200 592 00:32:06,200 --> 00:32:11,490 And that stores the value in the table under key1 and key2. 593 00:32:11,490 --> 00:32:15,530 And then we'll assume there's a thing called "get," such 594 00:32:15,530 --> 00:32:19,680 that if later on I say, get me what's in the table stored 595 00:32:19,680 --> 00:32:25,010 under key1 and key2, it'll retrieve whatever value was 596 00:32:25,010 --> 00:32:26,730 stored there. 597 00:32:26,730 --> 00:32:30,000 And let's not worry about how tables are implemented. 598 00:32:30,000 --> 00:32:33,060 That's yet another data abstraction, George's problem. 599 00:32:33,060 --> 00:32:34,700 And maybe we'll see later-- 600 00:32:34,700 --> 00:32:36,970 talk about how you might actually build tables in Lisp. 601 00:32:36,970 --> 00:32:40,710 602 00:32:40,710 --> 00:32:44,850 Well given this organization, what did George and Martha 603 00:32:44,850 --> 00:32:47,380 have to do? 604 00:32:47,380 --> 00:32:50,010 Well when they build their system, they each have the 605 00:32:50,010 --> 00:32:52,750 responsibility to set up their appropriate 606 00:32:52,750 --> 00:32:55,210 column in the table. 607 00:32:55,210 --> 00:33:00,620 So what George does, for example, when he defines his 608 00:33:00,620 --> 00:33:04,020 procedures, all he has to do is go off and put into the 609 00:33:04,020 --> 00:33:06,990 table under the type-rectangular. 610 00:33:06,990 --> 00:33:09,820 611 00:33:09,820 --> 00:33:14,100 And the name of the operation is real-part, his procedure 612 00:33:14,100 --> 00:33:16,250 real-part-rectangular. 613 00:33:16,250 --> 00:33:17,780 So notice what's going into this table. 614 00:33:17,780 --> 00:33:22,100 The two keys here are symbols, rectangular and real-part. 615 00:33:22,100 --> 00:33:24,400 That's the quote. 616 00:33:24,400 --> 00:33:27,410 And what's going into the table is the actual procedure 617 00:33:27,410 --> 00:33:28,870 that he wrote, real-part rectangular. 618 00:33:28,870 --> 00:33:32,040 619 00:33:32,040 --> 00:33:35,000 And then puts an imaginary part into the table, filed 620 00:33:35,000 --> 00:33:39,370 under the keys rectangular- and imaginary-part, and 621 00:33:39,370 --> 00:33:44,020 magnitude under the keys rectangular magnitude, angle 622 00:33:44,020 --> 00:33:45,270 under rectangular-angle. 623 00:33:45,270 --> 00:33:47,350 624 00:33:47,350 --> 00:33:50,840 So that's what George has to do to be part of this system. 625 00:33:50,840 --> 00:33:54,420 626 00:33:54,420 --> 00:33:57,740 Martha similarly sets up the column and 627 00:33:57,740 --> 00:33:59,430 the table under polar. 628 00:33:59,430 --> 00:34:02,160 Polar and real-part. 629 00:34:02,160 --> 00:34:04,340 Is the procedure real-part-polar? 630 00:34:04,340 --> 00:34:09,030 And imaginary-part, and magnitude, and angle. 631 00:34:09,030 --> 00:34:11,409 So this is what Martha has to do to be part of the system. 632 00:34:11,409 --> 00:34:13,550 Everyone who makes a representation has the 633 00:34:13,550 --> 00:34:17,840 responsibility for setting up a column in the table. 634 00:34:17,840 --> 00:34:19,900 And what does Harry do when Harry comes in with his 635 00:34:19,900 --> 00:34:21,800 brilliant idea for implementing complex numbers? 636 00:34:21,800 --> 00:34:25,170 Well he makes whatever procedure he wants and builds 637 00:34:25,170 --> 00:34:28,550 a new column in this table. 638 00:34:28,550 --> 00:34:31,330 OK, well what happened to the manager? 639 00:34:31,330 --> 00:34:34,610 The manager has been automated out of existence and is 640 00:34:34,610 --> 00:34:37,110 replaced by a procedure called operate. 641 00:34:37,110 --> 00:34:40,380 And this is the key procedure in the whole system. 642 00:34:40,380 --> 00:34:45,920 Let's say define operate. 643 00:34:45,920 --> 00:34:51,060 644 00:34:51,060 --> 00:34:57,750 Operate is going to take an operation that you want to do, 645 00:34:57,750 --> 00:35:01,840 the name of an operation, and an object that you would like 646 00:35:01,840 --> 00:35:04,210 to apply that operation to. 647 00:35:04,210 --> 00:35:07,400 So for example, the real-part of some particular complex 648 00:35:07,400 --> 00:35:09,890 number, what does it do? 649 00:35:09,890 --> 00:35:12,650 Well the first thing it does, it looks in the table. 650 00:35:12,650 --> 00:35:20,710 Goes into the table and tries to find a procedure that's 651 00:35:20,710 --> 00:35:23,320 stored in the table. 652 00:35:23,320 --> 00:35:29,830 So it gets from the table, using as keys the type of the 653 00:35:29,830 --> 00:35:40,450 object and the operator, but looks on the table and sees 654 00:35:40,450 --> 00:35:42,300 what's stored under the type of the object and the 655 00:35:42,300 --> 00:35:44,440 operator, sees if anything's stored. 656 00:35:44,440 --> 00:35:45,930 Let's assume that get is implemented. 657 00:35:45,930 --> 00:35:52,560 So if nothing is stored there, it'll return the empty list. 658 00:35:52,560 --> 00:35:55,130 So it says, if there's actually something stored 659 00:35:55,130 --> 00:36:04,920 there, if the procedure here is not no, then it'll take the 660 00:36:04,920 --> 00:36:11,240 procedure that it found in the table and apply it to the 661 00:36:11,240 --> 00:36:15,120 contents of the object. 662 00:36:15,120 --> 00:36:18,042 663 00:36:18,042 --> 00:36:21,445 And otherwise if there was nothing stored there, it'll-- 664 00:36:21,445 --> 00:36:22,435 well we can decide. 665 00:36:22,435 --> 00:36:25,920 In this case let's have it put out an error message saying, 666 00:36:25,920 --> 00:36:28,650 undefined operator. 667 00:36:28,650 --> 00:36:30,230 No operator for this type. 668 00:36:30,230 --> 00:36:32,770 669 00:36:32,770 --> 00:36:34,285 Or some appropriate error message. 670 00:36:34,285 --> 00:36:39,150 671 00:36:39,150 --> 00:36:39,300 OK? 672 00:36:39,300 --> 00:36:41,890 And that replaces the manager. 673 00:36:41,890 --> 00:36:43,960 How do we really use it? 674 00:36:43,960 --> 00:36:48,580 Well what we say is we'll go off and define our generic 675 00:36:48,580 --> 00:36:50,040 selectors using operate. 676 00:36:50,040 --> 00:36:57,140 We'll say that the real-part of an object is found by 677 00:36:57,140 --> 00:37:05,010 operating on the object with the name of the operation 678 00:37:05,010 --> 00:37:06,260 being real-part. 679 00:37:06,260 --> 00:37:08,070 680 00:37:08,070 --> 00:37:10,870 And then similarly, imaginary-part is operate 681 00:37:10,870 --> 00:37:16,080 using the name imaginary-part and magnitude and angle. 682 00:37:16,080 --> 00:37:17,430 That's our implementation. 683 00:37:17,430 --> 00:37:21,330 That plus the tape plus the operate procedure. 684 00:37:21,330 --> 00:37:23,100 And the table effectively replaces what the 685 00:37:23,100 --> 00:37:24,150 manager used to do. 686 00:37:24,150 --> 00:37:27,040 Let's just go through that slowly to show you 687 00:37:27,040 --> 00:37:27,900 what's going on. 688 00:37:27,900 --> 00:37:33,000 Suppose I have one of Martha's complex numbers. 689 00:37:33,000 --> 00:37:35,520 690 00:37:35,520 --> 00:37:39,100 It's got magnitude 1 and angle 2. 691 00:37:39,100 --> 00:37:40,220 And it's one of Martha's. 692 00:37:40,220 --> 00:37:47,120 So it's labeled here, polar. 693 00:37:47,120 --> 00:37:48,000 Let's call that z. 694 00:37:48,000 --> 00:37:49,250 Suppose that's z. 695 00:37:49,250 --> 00:37:51,770 696 00:37:51,770 --> 00:37:54,320 And suppose with this implementation someone comes 697 00:37:54,320 --> 00:37:57,110 up and asks for the real-part of z. 698 00:37:57,110 --> 00:38:04,870 699 00:38:04,870 --> 00:38:08,920 Well real-part now is defined in terms of operate. 700 00:38:08,920 --> 00:38:18,470 So that's equivalent to saying operate with the name of the 701 00:38:18,470 --> 00:38:27,060 operator being real-part, the symbol real-part on z. 702 00:38:27,060 --> 00:38:28,090 And now operate comes. 703 00:38:28,090 --> 00:38:31,720 It's going to look in the table, and it's going to try 704 00:38:31,720 --> 00:38:34,005 and find something stored under-- 705 00:38:34,005 --> 00:38:38,830 706 00:38:38,830 --> 00:38:42,160 the operation is going to apply by looking in the table 707 00:38:42,160 --> 00:38:46,225 under the type of the object. 708 00:38:46,225 --> 00:38:48,790 And the type of z is polar. 709 00:38:48,790 --> 00:38:52,990 So it's going to look and say, can I get using polar? 710 00:38:52,990 --> 00:38:58,250 And the operation name, which was real-part. 711 00:38:58,250 --> 00:39:05,960 712 00:39:05,960 --> 00:39:09,490 It's going to look in there and apply that to 713 00:39:09,490 --> 00:39:14,930 the contents of z. 714 00:39:14,930 --> 00:39:15,650 And that? 715 00:39:15,650 --> 00:39:20,350 If everything was set up correctly, this thing is the 716 00:39:20,350 --> 00:39:21,700 procedure that Martha put there. 717 00:39:21,700 --> 00:39:22,950 This is real-part-polar. 718 00:39:22,950 --> 00:39:30,790 719 00:39:30,790 --> 00:39:35,130 And this is z without its type. 720 00:39:35,130 --> 00:39:37,860 The thing that Martha originally designed those 721 00:39:37,860 --> 00:39:40,340 procedures to work on, which is 1, 2. 722 00:39:40,340 --> 00:39:43,790 723 00:39:43,790 --> 00:39:47,210 And so operate sort of does uniformly what the manager 724 00:39:47,210 --> 00:39:49,450 used to do sort of all over the system. 725 00:39:49,450 --> 00:39:52,170 It finds the right thing, looks in the table, strips off 726 00:39:52,170 --> 00:39:56,600 the type, and passes it down into the 727 00:39:56,600 --> 00:39:59,160 person who handles it. 728 00:39:59,160 --> 00:40:04,980 This is another, and, you can see, more flexible for most 729 00:40:04,980 --> 00:40:07,990 purposes, way of implementing generic operators. 730 00:40:07,990 --> 00:40:15,505 And it's called data-directed programming. 731 00:40:15,505 --> 00:40:20,350 732 00:40:20,350 --> 00:40:24,920 And the idea of that is in some sense the data objects 733 00:40:24,920 --> 00:40:27,260 themselves, those little complex numbers that are 734 00:40:27,260 --> 00:40:30,340 floating around the system, are carrying with them the 735 00:40:30,340 --> 00:40:35,390 information about how you should operate on them. 736 00:40:35,390 --> 00:40:36,640 Let's break for questions. 737 00:40:36,640 --> 00:40:41,000 738 00:40:41,000 --> 00:40:41,240 Yes. 739 00:40:41,240 --> 00:40:43,390 AUDIENCE: What do you have stored in that data object? 740 00:40:43,390 --> 00:40:47,850 You have the data itself, you have its type, and you have 741 00:40:47,850 --> 00:40:49,690 the operations for that type? 742 00:40:49,690 --> 00:40:53,600 Or where are the operations that you found? 743 00:40:53,600 --> 00:40:54,980 PROFESSOR: OK, let me-- 744 00:40:54,980 --> 00:40:56,500 yeah, that's a good question. 745 00:40:56,500 --> 00:40:59,700 Because it raises other possibilities of how 746 00:40:59,700 --> 00:41:00,750 you might do it. 747 00:41:00,750 --> 00:41:04,200 And of course there are a lot of possibilities. 748 00:41:04,200 --> 00:41:06,820 In this particular implementation, what's sitting 749 00:41:06,820 --> 00:41:11,630 in this data object, for example, is the data itself-- 750 00:41:11,630 --> 00:41:14,980 which in this case is a pair of 1 and 2-- 751 00:41:14,980 --> 00:41:16,550 and also a symbol. 752 00:41:16,550 --> 00:41:21,140 This is the symbol, the word P-O-L-A-R, and that's what's 753 00:41:21,140 --> 00:41:22,390 sitting in this data object. 754 00:41:22,390 --> 00:41:24,870 755 00:41:24,870 --> 00:41:26,690 Where are the operations themselves? 756 00:41:26,690 --> 00:41:29,850 The operations are sitting in the table. 757 00:41:29,850 --> 00:41:35,450 So in this table, the rows and columns of the table are 758 00:41:35,450 --> 00:41:38,230 labeled by symbols. 759 00:41:38,230 --> 00:41:40,810 So when I store something in this table, the key might be 760 00:41:40,810 --> 00:41:48,240 the symbol polar and the symbol magnitude. 761 00:41:48,240 --> 00:41:51,310 And I think by writing it this way I've been very confusing. 762 00:41:51,310 --> 00:41:53,160 Because what's really sitting here isn't-- 763 00:41:53,160 --> 00:41:58,360 when I wrote magnitude polar, what I mean is the procedure 764 00:41:58,360 --> 00:41:59,850 magnitude polar. 765 00:41:59,850 --> 00:42:02,580 And probably what I really should have written-- 766 00:42:02,580 --> 00:42:04,200 except it's too small for me to write 767 00:42:04,200 --> 00:42:05,580 in this little space-- 768 00:42:05,580 --> 00:42:11,250 is something like lambda of z, the thing that 769 00:42:11,250 --> 00:42:14,710 Martha wrote to implement. 770 00:42:14,710 --> 00:42:16,620 And then you can see from that, there's another way that 771 00:42:16,620 --> 00:42:20,250 I alluded to of solving this name conflict problem, which 772 00:42:20,250 --> 00:42:22,380 is that George and Martha never have to name their 773 00:42:22,380 --> 00:42:23,150 procedures at all. 774 00:42:23,150 --> 00:42:26,710 They can just stick the anonymous things generated by 775 00:42:26,710 --> 00:42:28,660 lambda directly into the table. 776 00:42:28,660 --> 00:42:32,540 There's also another thing that your question raises, is 777 00:42:32,540 --> 00:42:36,045 the possibility that maybe what I would like somehow is 778 00:42:36,045 --> 00:42:40,120 to store in this data object not the symbol P-O-L-A-R but 779 00:42:40,120 --> 00:42:43,520 maybe actually all the operations themselves. 780 00:42:43,520 --> 00:42:45,860 And that's another way to organize the system, called 781 00:42:45,860 --> 00:42:48,650 message passing. 782 00:42:48,650 --> 00:42:49,970 So there are a lot of ways you can do it. 783 00:42:49,970 --> 00:42:54,640 784 00:42:54,640 --> 00:42:58,040 AUDIENCE: Therefore if Martha and George had used the same 785 00:42:58,040 --> 00:43:01,230 procedure names, it would be OK because it wouldn't look 786 00:43:01,230 --> 00:43:02,560 [UNINTELLIGIBLE]. 787 00:43:02,560 --> 00:43:03,010 PROFESSOR: That's right. 788 00:43:03,010 --> 00:43:04,890 That's right. 789 00:43:04,890 --> 00:43:07,060 See, they wouldn't even have to name their 790 00:43:07,060 --> 00:43:09,470 procedures at all. 791 00:43:09,470 --> 00:43:12,440 What George could have written instead of saying put in the 792 00:43:12,440 --> 00:43:16,890 table under rectangular- and real-part, the procedure 793 00:43:16,890 --> 00:43:19,660 real-part rectangular, George could have written put under 794 00:43:19,660 --> 00:43:23,080 rectangular real-part, lambda of z, such and such, 795 00:43:23,080 --> 00:43:24,540 and such and such. 796 00:43:24,540 --> 00:43:27,330 And the system would work completely the same. 797 00:43:27,330 --> 00:43:31,750 AUDIENCE: My question is, Martha could have put key1 798 00:43:31,750 --> 00:43:37,120 key2 real-part, and George could have put key1 key2 799 00:43:37,120 --> 00:43:40,060 real-part, and as long as they defined them differently they 800 00:43:40,060 --> 00:43:41,290 wouldn't have had any conflicts, right? 801 00:43:41,290 --> 00:43:45,130 PROFESSOR: Yes, that would all be OK except for the fact that 802 00:43:45,130 --> 00:43:47,130 if you imagine George and Martha typing at the same 803 00:43:47,130 --> 00:43:50,090 console with the same meanings for all their names, and it 804 00:43:50,090 --> 00:43:51,720 would get confused by real-part, but there are ways 805 00:43:51,720 --> 00:43:52,800 to arrange that, too. 806 00:43:52,800 --> 00:43:54,980 And in principle you're absolutely right. 807 00:43:54,980 --> 00:43:56,290 If their names didn't conflict-- 808 00:43:56,290 --> 00:43:58,190 it's the objects that go in the table, not the names. 809 00:43:58,190 --> 00:44:08,200 810 00:44:08,200 --> 00:44:09,450 OK, let's take a break. 811 00:44:09,450 --> 00:44:12,493 812 00:44:12,493 --> 00:44:12,836 [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY 813 00:44:12,836 --> 00:44:14,086 JOHANN SEBASTIAN BACH] 814 00:44:14,086 --> 00:45:12,880 815 00:45:12,880 --> 00:45:17,680 All right, well we just looked at data-directed programming 816 00:45:17,680 --> 00:45:21,590 as a way of implementing a system that does arithmetic on 817 00:45:21,590 --> 00:45:22,840 complex numbers. 818 00:45:22,840 --> 00:45:27,420 819 00:45:27,420 --> 00:45:32,880 So I had these operations in it called plus C and minus C, 820 00:45:32,880 --> 00:45:38,230 and multiply, and divide, and maybe some others. 821 00:45:38,230 --> 00:45:46,030 And that sat on top of-- and this is the key point-- sat on 822 00:45:46,030 --> 00:45:50,340 top of two different representations. 823 00:45:50,340 --> 00:45:55,110 A rectangular package here, and a polar package. 824 00:45:55,110 --> 00:45:58,240 825 00:45:58,240 --> 00:45:59,150 And maybe some more. 826 00:45:59,150 --> 00:46:01,640 And we saw that the whole idea is that maybe some more are 827 00:46:01,640 --> 00:46:04,670 now very easy to add. 828 00:46:04,670 --> 00:46:08,900 But that doesn't really show the power of this methodology. 829 00:46:08,900 --> 00:46:10,150 Shows you what's going on. 830 00:46:10,150 --> 00:46:13,260 The power of the methodology only becomes apparent when you 831 00:46:13,260 --> 00:46:17,080 start embedding this in some more complex system. 832 00:46:17,080 --> 00:46:19,180 What I'm going to do now is embed this in some more 833 00:46:19,180 --> 00:46:20,250 complex system. 834 00:46:20,250 --> 00:46:23,960 Let's assume that what we really have is a general kind 835 00:46:23,960 --> 00:46:25,280 of arithmetic system. 836 00:46:25,280 --> 00:46:27,240 So called generic arithmetic system. 837 00:46:27,240 --> 00:46:32,060 And at the top level here, somebody can say add two 838 00:46:32,060 --> 00:46:38,450 things, or subtract two things, or multiply two 839 00:46:38,450 --> 00:46:41,180 things, or divide two things. 840 00:46:41,180 --> 00:46:44,140 841 00:46:44,140 --> 00:46:47,930 And underneath that there's an abstraction barrier. 842 00:46:47,930 --> 00:46:50,510 And underneath this barrier, is, say, a 843 00:46:50,510 --> 00:46:52,850 complex arithmetic package. 844 00:46:52,850 --> 00:46:55,110 And you can say, add two complex numbers. 845 00:46:55,110 --> 00:46:57,540 Or you might also have-- remember we did a rational 846 00:46:57,540 --> 00:47:00,190 number package-- you might have that sitting there. 847 00:47:00,190 --> 00:47:03,950 And there might be a rational thing. 848 00:47:03,950 --> 00:47:07,760 And the rational number package, well, has the things 849 00:47:07,760 --> 00:47:08,320 we implemented. 850 00:47:08,320 --> 00:47:15,490 Plus rat, and times rat, and so on. 851 00:47:15,490 --> 00:47:17,010 Or you might have ordinary Lisp numbers. 852 00:47:17,010 --> 00:47:19,310 You might say add three and four. 853 00:47:19,310 --> 00:47:29,030 So we might have ordinary numbers, in which case we have 854 00:47:29,030 --> 00:47:36,670 the Lisp supplied plus, and minus, and times, and slash. 855 00:47:36,670 --> 00:47:39,840 OK, so we might imagine this complex number system sitting 856 00:47:39,840 --> 00:47:43,660 in a more complicated generic operator structure at 857 00:47:43,660 --> 00:47:44,910 the next level up. 858 00:47:44,910 --> 00:47:47,730 859 00:47:47,730 --> 00:47:49,050 Well how can we make that? 860 00:47:49,050 --> 00:47:50,240 We already have the idea, we're just 861 00:47:50,240 --> 00:47:52,780 going to do it again. 862 00:47:52,780 --> 00:47:54,720 We've implemented a rational number package. 863 00:47:54,720 --> 00:47:56,650 Let's look at how it has to be changed. 864 00:47:56,650 --> 00:48:01,590 865 00:48:01,590 --> 00:48:02,660 In fact, at this level it doesn't have to 866 00:48:02,660 --> 00:48:03,730 be changed at all. 867 00:48:03,730 --> 00:48:07,180 This is exactly the code that we wrote last time. 868 00:48:07,180 --> 00:48:10,140 To add two rational numbers, remember 869 00:48:10,140 --> 00:48:11,140 there was this formula. 870 00:48:11,140 --> 00:48:14,980 You make a rational number whose numerator-- 871 00:48:14,980 --> 00:48:17,330 the numerator of the first times the denominator of the 872 00:48:17,330 --> 00:48:20,486 second, plus the denominator of the first times the 873 00:48:20,486 --> 00:48:21,520 numerator of the second. 874 00:48:21,520 --> 00:48:25,760 And who's denominator is the product of the denominators. 875 00:48:25,760 --> 00:48:30,580 And minus rat, and star rat, and slash rat. 876 00:48:30,580 --> 00:48:34,420 And this is exactly the rational number package that 877 00:48:34,420 --> 00:48:36,310 we made before. 878 00:48:36,310 --> 00:48:38,390 We're ignoring the GCD problem, but let's not worry 879 00:48:38,390 --> 00:48:40,240 about that. 880 00:48:40,240 --> 00:48:42,980 As implementers of this rational number package, how 881 00:48:42,980 --> 00:48:45,570 do we install it in the generic arithmetic system? 882 00:48:45,570 --> 00:48:46,820 Well that's easy. 883 00:48:46,820 --> 00:48:48,980 884 00:48:48,980 --> 00:48:51,840 There's only one thing we have to do differently. 885 00:48:51,840 --> 00:48:56,270 Whereas previously we said that to make a rational number 886 00:48:56,270 --> 00:49:00,960 you built a pair of the numerator and denominator, 887 00:49:00,960 --> 00:49:03,300 here we'll not only build the pair, but we'll sign it. 888 00:49:03,300 --> 00:49:06,120 We'll attach the type rational. 889 00:49:06,120 --> 00:49:08,940 That's the only thing we have to do different, make it a 890 00:49:08,940 --> 00:49:12,380 typed data object. 891 00:49:12,380 --> 00:49:14,500 And now we'll stick our operations in the table. 892 00:49:14,500 --> 00:49:18,920 We'll put under the symbol rational and the operation add 893 00:49:18,920 --> 00:49:21,820 our procedure, plus rat. 894 00:49:21,820 --> 00:49:23,580 And, again, note this is a symbol. 895 00:49:23,580 --> 00:49:23,930 Right? 896 00:49:23,930 --> 00:49:26,830 Quote, unquote, but the actual thing we're putting in the 897 00:49:26,830 --> 00:49:30,060 table is the procedure. 898 00:49:30,060 --> 00:49:33,700 And for how to subtract, well you subtract 899 00:49:33,700 --> 00:49:38,270 rationals with minus rat. 900 00:49:38,270 --> 00:49:41,090 And multiply, and divide. 901 00:49:41,090 --> 00:49:43,640 And that is exactly and precisely what we have to do 902 00:49:43,640 --> 00:49:48,510 to fit inside this generic arithmetic system. 903 00:49:48,510 --> 00:49:51,560 Well how does the whole thing work? 904 00:49:51,560 --> 00:50:00,170 See, what we want to do is have some generic operators. 905 00:50:00,170 --> 00:50:01,720 Have add and sub and [UNINTELLIGIBLE] 906 00:50:01,720 --> 00:50:03,990 be generic operators. 907 00:50:03,990 --> 00:50:18,930 So we're going to define add and say, to add x and y, that 908 00:50:18,930 --> 00:50:21,840 will be operate-- 909 00:50:21,840 --> 00:50:26,080 910 00:50:26,080 --> 00:50:27,490 we were going to call it operate-2. 911 00:50:27,490 --> 00:50:30,350 This is our operator procedure, but set up for two 912 00:50:30,350 --> 00:50:37,261 arguments using add on x and y. 913 00:50:37,261 --> 00:50:40,420 And so this is the analog to operate. 914 00:50:40,420 --> 00:50:41,680 Let's look at the code for second. 915 00:50:41,680 --> 00:50:42,930 It's almost like operate. 916 00:50:42,930 --> 00:50:46,040 917 00:50:46,040 --> 00:50:51,550 To operate with some operator on an argument 1 and an 918 00:50:51,550 --> 00:50:56,370 argument 2, well the first thing we're going to do is 919 00:50:56,370 --> 00:51:01,900 check and see if the two arguments have the same type. 920 00:51:01,900 --> 00:51:06,610 So we'll say, is the type of the first argument the same as 921 00:51:06,610 --> 00:51:07,860 the type of the second argument? 922 00:51:07,860 --> 00:51:10,350 923 00:51:10,350 --> 00:51:15,070 And if they're not, we'll go off and complain, and say, 924 00:51:15,070 --> 00:51:15,670 that's an error. 925 00:51:15,670 --> 00:51:19,140 We don't know how to do that. 926 00:51:19,140 --> 00:51:20,920 If they do have the same type, we'll do 927 00:51:20,920 --> 00:51:22,080 exactly what we did before. 928 00:51:22,080 --> 00:51:26,460 We'll go look and filed under the type of the argument-- 929 00:51:26,460 --> 00:51:30,420 arg 1 and arg 2 have the same type, so it doesn't matter. 930 00:51:30,420 --> 00:51:33,640 So we'll look in the table, find the procedure. 931 00:51:33,640 --> 00:51:38,870 If there is a procedure there, then we'll apply it to the 932 00:51:38,870 --> 00:51:43,030 contents of the argument 1 and the contents of arg 2. 933 00:51:43,030 --> 00:51:44,760 And otherwise we'll say, error. 934 00:51:44,760 --> 00:51:46,890 Undefined operator. 935 00:51:46,890 --> 00:51:48,140 And so there's operate-2. 936 00:51:48,140 --> 00:51:51,326 937 00:51:51,326 --> 00:51:55,160 And that's all we have to do. 938 00:51:55,160 --> 00:51:57,640 We just built the complex number package before. 939 00:51:57,640 --> 00:52:00,140 How do we embed that complex number package in 940 00:52:00,140 --> 00:52:02,140 this generic system? 941 00:52:02,140 --> 00:52:03,390 Almost the same. 942 00:52:03,390 --> 00:52:06,410 943 00:52:06,410 --> 00:52:11,060 We make a procedure called make-complex that takes 944 00:52:11,060 --> 00:52:14,100 whatever George and Martha hand to us and add the 945 00:52:14,100 --> 00:52:15,350 type-complex. 946 00:52:15,350 --> 00:52:18,170 947 00:52:18,170 --> 00:52:25,840 And then we say, to add complex numbers, plus complex, 948 00:52:25,840 --> 00:52:32,240 we use our internal procedure, plus c, and attach a type, 949 00:52:32,240 --> 00:52:33,490 make that a complex number. 950 00:52:33,490 --> 00:52:37,560 951 00:52:37,560 --> 00:52:42,840 So our original package had names plus c and minus c that 952 00:52:42,840 --> 00:52:45,250 we're using to communicate with George and Martha. 953 00:52:45,250 --> 00:52:47,730 And then to communicate with the outside world, we have a 954 00:52:47,730 --> 00:52:52,380 thing called plus-complex and minus-complex. 955 00:52:52,380 --> 00:52:55,920 956 00:52:55,920 --> 00:52:56,530 And so on. 957 00:52:56,530 --> 00:52:59,000 And the only difference is that these return 958 00:52:59,000 --> 00:53:01,120 values that are tight. 959 00:53:01,120 --> 00:53:02,850 So they can be looked at up here. 960 00:53:02,850 --> 00:53:04,690 And these are internal operations. 961 00:53:04,690 --> 00:53:09,250 962 00:53:09,250 --> 00:53:10,680 Let's go look at that slide again. 963 00:53:10,680 --> 00:53:13,740 There's one more thing we do. 964 00:53:13,740 --> 00:53:19,280 After defining plus-complex, we put under the type complex 965 00:53:19,280 --> 00:53:23,200 and the symbol add, that procedure plus complex. 966 00:53:23,200 --> 00:53:27,130 And then similarly for subtracting complex numbers, 967 00:53:27,130 --> 00:53:29,130 and multiplying them, and dividing them. 968 00:53:29,130 --> 00:53:31,700 969 00:53:31,700 --> 00:53:35,250 OK, how do we install ordinary numbers? 970 00:53:35,250 --> 00:53:38,160 Exactly the same way. 971 00:53:38,160 --> 00:53:40,500 Come off and say, well we'll make a thing called 972 00:53:40,500 --> 00:53:41,750 make-number. 973 00:53:41,750 --> 00:53:44,340 974 00:53:44,340 --> 00:53:48,500 Make-number takes a number and attaches a type, which is the 975 00:53:48,500 --> 00:53:50,260 symbol number. 976 00:53:50,260 --> 00:53:55,300 We build a procedure called plus-number, which is simply, 977 00:53:55,300 --> 00:53:59,220 add the two things using the ordinary addition, because in 978 00:53:59,220 --> 00:54:01,850 this case we're talking about ordinary numbers, and attach a 979 00:54:01,850 --> 00:54:04,510 type to it and make that a number. 980 00:54:04,510 --> 00:54:08,700 And then we put into the table under the symbol number and 981 00:54:08,700 --> 00:54:12,550 the operation add, this procedure plus-number, and 982 00:54:12,550 --> 00:54:15,360 then the same thing for subtracting, and multiplying, 983 00:54:15,360 --> 00:54:16,610 and dividing. 984 00:54:16,610 --> 00:54:22,750 985 00:54:22,750 --> 00:54:26,060 Let's look at an example, just to make it clear. 986 00:54:26,060 --> 00:54:32,600 Suppose, for instance, I'm going 987 00:54:32,600 --> 00:54:34,150 to perform the operation. 988 00:54:34,150 --> 00:54:38,220 So I sit up here and I'm going to perform the operation, 989 00:54:38,220 --> 00:54:40,930 which looks like multiplying two complex numbers. 990 00:54:40,930 --> 00:54:49,786 So I would multiply, say, 3 plus 4i and 2 plus 6i. 991 00:54:49,786 --> 00:54:51,740 And that's something that I might want to take 992 00:54:51,740 --> 00:54:52,840 hand that to mul. 993 00:54:52,840 --> 00:54:57,170 I'll write mul as my generic operator here. 994 00:54:57,170 --> 00:54:58,280 How's that going to work? 995 00:54:58,280 --> 00:55:05,020 Well 3 plus 4i, say, sits in the system at this level as 996 00:55:05,020 --> 00:55:06,250 something that looks like this. 997 00:55:06,250 --> 00:55:08,280 Let's say it was one of George's. 998 00:55:08,280 --> 00:55:14,695 So it would have a 3 and a 4. 999 00:55:14,695 --> 00:55:18,490 1000 00:55:18,490 --> 00:55:25,330 And attached to that would be George's type, which would say 1001 00:55:25,330 --> 00:55:29,510 rectangular, it came from George. 1002 00:55:29,510 --> 00:55:31,230 And attached to that-- 1003 00:55:31,230 --> 00:55:35,630 and this itself would be the data view from the next level 1004 00:55:35,630 --> 00:55:37,700 up, which it is-- 1005 00:55:37,700 --> 00:55:41,030 so that itself would be a type-data object which would 1006 00:55:41,030 --> 00:55:42,280 say complex. 1007 00:55:42,280 --> 00:55:44,820 1008 00:55:44,820 --> 00:55:49,240 So that's what this object would look like up here at the 1009 00:55:49,240 --> 00:55:52,300 very highest level, where the really super-generic 1010 00:55:52,300 --> 00:55:55,560 operations are looking at it. 1011 00:55:55,560 --> 00:55:58,220 Now what happens, mul eventually's going to come 1012 00:55:58,220 --> 00:56:00,400 along and say, oh, what's it's type? 1013 00:56:00,400 --> 00:56:01,650 It's type is complex. 1014 00:56:01,650 --> 00:56:04,270 1015 00:56:04,270 --> 00:56:08,460 Go through to operate-2 and say, oh, what I want to do is 1016 00:56:08,460 --> 00:56:10,440 apply what's in the table, which is going to be the 1017 00:56:10,440 --> 00:56:17,150 procedure star complex, on this thing with the type 1018 00:56:17,150 --> 00:56:17,950 stripped off. 1019 00:56:17,950 --> 00:56:22,400 So it's going to strip off the type, take that much, and send 1020 00:56:22,400 --> 00:56:26,288 that down into the complex world. 1021 00:56:26,288 --> 00:56:28,950 The complex world looks at its operations and says, oh, I 1022 00:56:28,950 --> 00:56:31,280 have to apply star c. 1023 00:56:31,280 --> 00:56:34,490 Star c might say, oh, at some point I want to look at the 1024 00:56:34,490 --> 00:56:39,420 magnitude of this object that it's in, that it's got. 1025 00:56:39,420 --> 00:56:40,160 And they'll say, oh, it's 1026 00:56:40,160 --> 00:56:41,870 rectangular, it's one of George's. 1027 00:56:41,870 --> 00:56:47,340 So it'll then strip off the next version of type, and hand 1028 00:56:47,340 --> 00:56:52,160 that down to George to take the magnitude of. 1029 00:56:52,160 --> 00:56:55,290 So you see what's going on is that there are 1030 00:56:55,290 --> 00:56:59,320 these chains of types. 1031 00:56:59,320 --> 00:57:01,530 And the length of the chain is sort of the number of levels 1032 00:57:01,530 --> 00:57:05,090 that you're going to be going up in this table. 1033 00:57:05,090 --> 00:57:09,590 And what a type tells you, every time you have a vertical 1034 00:57:09,590 --> 00:57:12,350 barrier in this table, where there's some ambiguity about 1035 00:57:12,350 --> 00:57:15,010 where you should go down to the next level, the type is 1036 00:57:15,010 --> 00:57:17,440 telling you where to go. 1037 00:57:17,440 --> 00:57:19,950 And then everybody at the bottom, as they construct data 1038 00:57:19,950 --> 00:57:22,810 and filter it up, they stick their type back on. 1039 00:57:22,810 --> 00:57:25,350 1040 00:57:25,350 --> 00:57:30,750 So that's the general structure of the system. 1041 00:57:30,750 --> 00:57:33,410 1042 00:57:33,410 --> 00:57:34,820 OK. 1043 00:57:34,820 --> 00:57:38,660 Now that we've got this, let's go and make this thing even 1044 00:57:38,660 --> 00:57:39,910 more complex. 1045 00:57:39,910 --> 00:57:41,890 1046 00:57:41,890 --> 00:57:46,150 Let's talk about adding to the system not only these kinds of 1047 00:57:46,150 --> 00:57:49,680 numbers, but it's also meaningful to start talking 1048 00:57:49,680 --> 00:57:51,510 about adding polynomials. 1049 00:57:51,510 --> 00:57:53,360 Might do arithmetic on polynomials. 1050 00:57:53,360 --> 00:57:57,570 Like we could have x to the fifteenth plus 2x to the 1051 00:57:57,570 --> 00:58:04,480 seventh plus 5. 1052 00:58:04,480 --> 00:58:06,380 That might be some polynomial. 1053 00:58:06,380 --> 00:58:08,720 And if we have two such gadgets we can add them or 1054 00:58:08,720 --> 00:58:10,530 multiply them. 1055 00:58:10,530 --> 00:58:12,140 Let's not worry about dividing them. 1056 00:58:12,140 --> 00:58:15,870 Just add them, multiply them, then we'll subtract them. 1057 00:58:15,870 --> 00:58:16,660 What do we have to do? 1058 00:58:16,660 --> 00:58:21,830 Well let's think about how we might represent a polynomial. 1059 00:58:21,830 --> 00:58:24,950 It's going to be some typed data object. 1060 00:58:24,950 --> 00:58:29,690 So let's say a polynomial to this system might look like a 1061 00:58:29,690 --> 00:58:32,000 thing that starts with the type polynomial. 1062 00:58:32,000 --> 00:58:33,710 And then maybe it says the next thing is what 1063 00:58:33,710 --> 00:58:34,550 variable its in. 1064 00:58:34,550 --> 00:58:38,960 So I might say I'm a polynomial in the variable x. 1065 00:58:38,960 --> 00:58:40,500 And then it'll have some information about 1066 00:58:40,500 --> 00:58:42,250 what the terms are. 1067 00:58:42,250 --> 00:58:45,620 And there're just tons of ways to do this, but one way is to 1068 00:58:45,620 --> 00:58:51,520 say we're going to have a thing called a term-list. And 1069 00:58:51,520 --> 00:58:53,700 a term-list-- 1070 00:58:53,700 --> 00:58:54,830 well, in our case we'll use something 1071 00:58:54,830 --> 00:58:56,360 that looks like this. 1072 00:58:56,360 --> 00:58:59,010 We'll make it a bunch of pairs which have an order in a 1073 00:58:59,010 --> 00:58:59,690 coefficient. 1074 00:58:59,690 --> 00:59:09,070 So this polynomial would be represented by this term-list. 1075 00:59:09,070 --> 00:59:12,910 And what that means is that this polynomial starts off 1076 00:59:12,910 --> 00:59:19,710 with a term of order 15 and coefficient 1. 1077 00:59:19,710 --> 00:59:23,820 1078 00:59:23,820 --> 00:59:26,780 And the next thing in it is a term of order 7 and 1079 00:59:26,780 --> 00:59:29,680 coefficient 2, a term of order 0, which is constant in 1080 00:59:29,680 --> 00:59:31,450 coefficient 5. 1081 00:59:31,450 --> 00:59:35,600 And there are lots and lots of ways, and lots and lots of 1082 00:59:35,600 --> 00:59:37,890 trade-offs when you really think about making algebraic 1083 00:59:37,890 --> 00:59:40,570 manipulation packages about exactly how you should 1084 00:59:40,570 --> 00:59:41,730 represent these things. 1085 00:59:41,730 --> 00:59:44,180 But this is a fairly standard one. 1086 00:59:44,180 --> 00:59:47,770 It's useful in a lot of contexts. 1087 00:59:47,770 --> 00:59:50,815 OK, well how do we implement our polynomial arithmetic? 1088 00:59:50,815 --> 00:59:54,270 1089 00:59:54,270 --> 00:59:55,520 Let's start out. 1090 00:59:55,520 --> 00:59:57,950 1091 00:59:57,950 --> 01:00:00,760 What we'll do to make a polynomial-- 1092 01:00:00,760 --> 01:00:05,690 we'll first have a way to make polynomials. 1093 01:00:05,690 --> 01:00:08,560 We're going to make a polynomial out of variable 1094 01:00:08,560 --> 01:00:13,180 like x and term-list. And all that does is we'll package 1095 01:00:13,180 --> 01:00:14,290 them together someway. 1096 01:00:14,290 --> 01:00:18,740 We'll put the variable together with the term list 1097 01:00:18,740 --> 01:00:21,380 using cons, and then attached to that the type polynomial. 1098 01:00:21,380 --> 01:00:26,270 1099 01:00:26,270 --> 01:00:29,280 OK, how do we add two polynomials? 1100 01:00:29,280 --> 01:00:33,330 To add a polynomial, p1 and p2, and then just for 1101 01:00:33,330 --> 01:00:36,060 simplicity let's say we will only add 1102 01:00:36,060 --> 01:00:37,380 things in the same variable. 1103 01:00:37,380 --> 01:00:40,740 So if they have the same variable, and same variable 1104 01:00:40,740 --> 01:00:43,160 here is going to be some selector we write, whose 1105 01:00:43,160 --> 01:00:45,150 details we don't care about. 1106 01:00:45,150 --> 01:00:48,280 If the two polynomials have the same variable, then we'll 1107 01:00:48,280 --> 01:00:48,810 do something. 1108 01:00:48,810 --> 01:00:52,350 If they don't have the same variable, we'll give an error, 1109 01:00:52,350 --> 01:00:55,480 polynomials not in the same variable. 1110 01:00:55,480 --> 01:00:58,120 And if they do have the same variable, what we'll do is 1111 01:00:58,120 --> 01:01:01,130 we'll make a polynomial whose variable is whatever that 1112 01:01:01,130 --> 01:01:05,570 variable is, and whose term-list is something we'll 1113 01:01:05,570 --> 01:01:10,170 call sum-terms. Plus terms will add the two term lists. 1114 01:01:10,170 --> 01:01:13,500 So we'll add the two term lists to the polynomial. 1115 01:01:13,500 --> 01:01:16,755 That'll give us a term-list. We'll add on, we'll say it's a 1116 01:01:16,755 --> 01:01:19,500 polynomial in the variable with that 1117 01:01:19,500 --> 01:01:22,550 term-list. That's plus poly. 1118 01:01:22,550 --> 01:01:26,360 And then we're going to put in our table under the type 1119 01:01:26,360 --> 01:01:30,520 polynomial, add them using plus poly. 1120 01:01:30,520 --> 01:01:31,750 And of course we really haven't done much. 1121 01:01:31,750 --> 01:01:34,360 What we've really done is pushed all the work onto this 1122 01:01:34,360 --> 01:01:38,480 thing, plus-terms, which is supposed to add term-lists. 1123 01:01:38,480 --> 01:01:40,920 Let's look at that. 1124 01:01:40,920 --> 01:01:48,900 Here's an overview of how we might add two term-lists. 1125 01:01:48,900 --> 01:01:51,860 So L1 and L2 were going to be two term-lists. 1126 01:01:51,860 --> 01:01:55,700 And a term-list is a bunch of pairs, coefficient in order. 1127 01:01:55,700 --> 01:01:56,950 And it's a big case analysis. 1128 01:01:56,950 --> 01:01:59,860 1129 01:01:59,860 --> 01:02:03,470 And the first thing we'll check for and see if there are 1130 01:02:03,470 --> 01:02:07,020 any terms. We're going to recursively work down these 1131 01:02:07,020 --> 01:02:09,980 term-lists, so eventually we'll get to a place where 1132 01:02:09,980 --> 01:02:12,270 either L1 or L2 might be empty. 1133 01:02:12,270 --> 01:02:15,160 And if either one is empty, our answer will 1134 01:02:15,160 --> 01:02:15,850 be the other one. 1135 01:02:15,850 --> 01:02:20,720 So if L1 is empty we'll return L2, and if L2 is empty 1136 01:02:20,720 --> 01:02:23,470 we'll return L1. 1137 01:02:23,470 --> 01:02:27,220 Otherwise there are sort of three interesting cases. 1138 01:02:27,220 --> 01:02:30,560 What we're going to do is grab the first term in each of 1139 01:02:30,560 --> 01:02:37,660 those lists, called t1 and t2. 1140 01:02:37,660 --> 01:02:43,090 And we're going to look at three cases, depending on 1141 01:02:43,090 --> 01:02:47,230 whether the order of t1 is greater than the order of t2, 1142 01:02:47,230 --> 01:02:50,470 or less than t2, or the same. 1143 01:02:50,470 --> 01:02:53,290 1144 01:02:53,290 --> 01:02:54,910 Those are the three cases we're going to look at. 1145 01:02:54,910 --> 01:02:56,160 Let's look at this case. 1146 01:02:56,160 --> 01:02:58,640 1147 01:02:58,640 --> 01:03:03,550 If the order of t1 is greater than the order of t2, then 1148 01:03:03,550 --> 01:03:08,280 what that means is that our answer is going to start with 1149 01:03:08,280 --> 01:03:11,480 this term of the order of t1. 1150 01:03:11,480 --> 01:03:14,455 Because it won't combine with any lower order terms. So what 1151 01:03:14,455 --> 01:03:19,720 we do is add the lower order terms. We recursively add 1152 01:03:19,720 --> 01:03:21,900 together all the terms in the rest of the 1153 01:03:21,900 --> 01:03:26,880 term-list in L1 and L2. 1154 01:03:26,880 --> 01:03:30,120 That's going to be the lower order terms of the answer. 1155 01:03:30,120 --> 01:03:31,490 And then we're going to adjoin to that the 1156 01:03:31,490 --> 01:03:33,180 highest order term. 1157 01:03:33,180 --> 01:03:35,120 And I'm using here a whole bunch of procedures I haven't 1158 01:03:35,120 --> 01:03:39,360 defined, like a adjoin-term, and rest-terms, and selectors 1159 01:03:39,360 --> 01:03:41,410 that get order. 1160 01:03:41,410 --> 01:03:44,730 But you can imagine what those are. 1161 01:03:44,730 --> 01:03:48,550 So if the first term-list has a higher order than the 1162 01:03:48,550 --> 01:03:51,830 second, we recursively add all the lower terms and then stick 1163 01:03:51,830 --> 01:03:55,540 on that last term. 1164 01:03:55,540 --> 01:03:56,890 The other case, the same way. 1165 01:03:56,890 --> 01:04:05,400 If the first term has a smaller order, well then we 1166 01:04:05,400 --> 01:04:07,740 add the first term-list and the rest of the terms in the 1167 01:04:07,740 --> 01:04:11,430 second one, and adjoin on this highest order term. 1168 01:04:11,430 --> 01:04:14,570 1169 01:04:14,570 --> 01:04:16,660 So so far nothing's much happened, we've just sort of 1170 01:04:16,660 --> 01:04:19,700 pushed this thing off into adding lower order terms. The 1171 01:04:19,700 --> 01:04:22,870 last case where you actually get to a coefficients that you 1172 01:04:22,870 --> 01:04:24,240 have to add, this will be the case where 1173 01:04:24,240 --> 01:04:27,240 the orders are equal. 1174 01:04:27,240 --> 01:04:30,340 What we do is, well again recursively add the lower 1175 01:04:30,340 --> 01:04:33,460 order terms. But now we have to really combine something. 1176 01:04:33,460 --> 01:04:38,960 What we do is we make a term whose order is the order of 1177 01:04:38,960 --> 01:04:40,820 the term we're looking at. 1178 01:04:40,820 --> 01:04:44,320 By now t1 and t2 have the same order. 1179 01:04:44,320 --> 01:04:45,090 That's its order. 1180 01:04:45,090 --> 01:04:50,400 And its coefficient is gotten by adding the coefficient of 1181 01:04:50,400 --> 01:04:52,230 t1 and the coefficient of t2. 1182 01:04:52,230 --> 01:04:56,360 1183 01:04:56,360 --> 01:04:59,800 This is a big recursive working down of terms, but 1184 01:04:59,800 --> 01:05:03,070 really there's only one interesting symbol in this 1185 01:05:03,070 --> 01:05:05,900 procedure, only one interesting idea. 1186 01:05:05,900 --> 01:05:08,500 The interesting idea is this add. 1187 01:05:08,500 --> 01:05:12,390 1188 01:05:12,390 --> 01:05:15,330 And the reason that's interesting is because 1189 01:05:15,330 --> 01:05:18,220 something completely wonderful just happened. 1190 01:05:18,220 --> 01:05:25,440 We reduced adding polynomials, not to sort of plus, but to 1191 01:05:25,440 --> 01:05:28,820 the generic add. 1192 01:05:28,820 --> 01:05:33,270 In other words, by implementing it that way, not 1193 01:05:33,270 --> 01:05:37,530 only do we have our system where we can have rational 1194 01:05:37,530 --> 01:05:42,090 numbers, or complex numbers, or ordinary numbers, we've 1195 01:05:42,090 --> 01:05:43,340 just added on polynomials. 1196 01:05:43,340 --> 01:05:48,520 1197 01:05:48,520 --> 01:05:51,820 But the coefficients of the polynomials can be anything 1198 01:05:51,820 --> 01:05:53,590 that the system can add. 1199 01:05:53,590 --> 01:05:57,450 So these could be polynomials whose coefficients are 1200 01:05:57,450 --> 01:06:04,110 rational numbers or complex numbers, which in turn could 1201 01:06:04,110 --> 01:06:11,250 be either rectangular, or polar, or ordinary numbers. 1202 01:06:11,250 --> 01:06:19,860 1203 01:06:19,860 --> 01:06:23,460 So what I mean precisely is our system right now 1204 01:06:23,460 --> 01:06:30,200 automatically can handle things like adding together 1205 01:06:30,200 --> 01:06:35,830 polynomials that have this one: 2/3 of x squared plus 1206 01:06:35,830 --> 01:06:40,940 5/17 x plus 11/4. 1207 01:06:40,940 --> 01:06:44,210 Or automatically handle polynomials that look like 3 1208 01:06:44,210 --> 01:06:54,160 plus 2i times x to the fifth plus 4 plus 7i, or something. 1209 01:06:54,160 --> 01:06:56,210 You can automatically handle those things. 1210 01:06:56,210 --> 01:06:57,820 Why is that? 1211 01:06:57,820 --> 01:07:03,280 That's merely because, or profoundly because we reduced 1212 01:07:03,280 --> 01:07:06,790 adding polynomials to adding their coefficients. 1213 01:07:06,790 --> 01:07:09,670 And adding coefficients was done by the generic add 1214 01:07:09,670 --> 01:07:12,970 operator, which said, I don't care what your types are as 1215 01:07:12,970 --> 01:07:15,170 long as I know how to add you. 1216 01:07:15,170 --> 01:07:17,800 So automatically for free we get the 1217 01:07:17,800 --> 01:07:20,880 ability to handle that. 1218 01:07:20,880 --> 01:07:24,920 What's even better than that, because remember one of the 1219 01:07:24,920 --> 01:07:29,870 things we did is we put into the table that the way you add 1220 01:07:29,870 --> 01:07:34,660 polynomials is using plus poly. 1221 01:07:34,660 --> 01:07:37,480 That means that polynomials themselves are 1222 01:07:37,480 --> 01:07:39,370 things that can be added. 1223 01:07:39,370 --> 01:07:42,110 So for instance let me write one here. 1224 01:07:42,110 --> 01:07:45,260 1225 01:07:45,260 --> 01:07:46,510 Here's a polynomial. 1226 01:07:46,510 --> 01:07:50,560 1227 01:07:50,560 --> 01:07:55,080 So this gadget here I'm writing up, this is a 1228 01:07:55,080 --> 01:08:02,710 polynomial in y whose coefficients are 1229 01:08:02,710 --> 01:08:04,690 polynomials in x. 1230 01:08:04,690 --> 01:08:08,610 1231 01:08:08,610 --> 01:08:13,110 So you see, simply by saying, polynomials are themselves 1232 01:08:13,110 --> 01:08:15,590 things that can be added, we can go off and say, well not 1233 01:08:15,590 --> 01:08:19,560 only can we deal with rationals, or complex, or 1234 01:08:19,560 --> 01:08:22,330 ordinary numbers, but we can deal with polynomials whose 1235 01:08:22,330 --> 01:08:25,420 coefficients are rationals, or complex, or ordinary numbers, 1236 01:08:25,420 --> 01:08:31,979 or polynomials whose coefficients are rationals, or 1237 01:08:31,979 --> 01:08:37,569 complex, rectangular, polar, or ordinary numbers, or 1238 01:08:37,569 --> 01:08:42,609 polynomials whose coefficients are rationals, complex, or 1239 01:08:42,609 --> 01:08:43,670 ordinary numbers. 1240 01:08:43,670 --> 01:08:45,950 And so on, and so on, and so on. 1241 01:08:45,950 --> 01:08:50,830 So this is sort of an infinite or maybe a recursive tower of 1242 01:08:50,830 --> 01:08:53,880 types that we've built up. 1243 01:08:53,880 --> 01:08:56,420 And it's all exactly from that one little symbol. 1244 01:08:56,420 --> 01:08:59,615 A-D-D. Writing "add" instead of "plus" in 1245 01:08:59,615 --> 01:09:02,270 the polynomial thing. 1246 01:09:02,270 --> 01:09:04,620 Slightly different way to think about it is that 1247 01:09:04,620 --> 01:09:08,740 polynomials are a constructor for types. 1248 01:09:08,740 --> 01:09:12,149 Namely you give it a type, like integer, and it returns 1249 01:09:12,149 --> 01:09:16,279 for you polynomials in x whose coefficients are integers. 1250 01:09:16,279 --> 01:09:20,010 And the important thing about that is that the operations on 1251 01:09:20,010 --> 01:09:22,729 polynomials reduce to the operations on the 1252 01:09:22,729 --> 01:09:23,500 coefficients. 1253 01:09:23,500 --> 01:09:25,840 And there are a lot of things like that. 1254 01:09:25,840 --> 01:09:28,870 So for example, let's go back and rational numbers. 1255 01:09:28,870 --> 01:09:32,410 We thought about rational numbers as an integer over an 1256 01:09:32,410 --> 01:09:34,229 integer, but there's the general notion 1257 01:09:34,229 --> 01:09:36,240 of a rational object. 1258 01:09:36,240 --> 01:09:43,010 Like we might think about 3x plus 7 over x squared plus 1. 1259 01:09:43,010 --> 01:09:47,430 That's general rational object whose numerator and 1260 01:09:47,430 --> 01:09:50,310 denominator are polynomials. 1261 01:09:50,310 --> 01:09:52,990 And to add two of them we use the same formula, numerator 1262 01:09:52,990 --> 01:09:55,720 times denominator plus denominator times numerator 1263 01:09:55,720 --> 01:09:57,290 over product of denominators. 1264 01:09:57,290 --> 01:09:59,430 How could we install that in our system? 1265 01:09:59,430 --> 01:10:01,820 Well here's our original rational 1266 01:10:01,820 --> 01:10:04,250 number arithmetic package. 1267 01:10:04,250 --> 01:10:08,660 And all we have to do in order to make the entire system 1268 01:10:08,660 --> 01:10:12,530 continue working with general rational objects, is replace 1269 01:10:12,530 --> 01:10:16,480 these particular pluses and stars by the generic operator. 1270 01:10:16,480 --> 01:10:19,870 So if we simply change that procedure to this one, here 1271 01:10:19,870 --> 01:10:23,100 we've changed plus and star to add a mul, those are 1272 01:10:23,100 --> 01:10:28,170 absolutely the only change, then suddenly our entire 1273 01:10:28,170 --> 01:10:34,000 system can start talking about objects that look like this. 1274 01:10:34,000 --> 01:10:40,350 So for example, here is a rational object whose 1275 01:10:40,350 --> 01:10:44,030 numerator is a polynomial in x whose coefficients are 1276 01:10:44,030 --> 01:10:47,350 rational numbers. 1277 01:10:47,350 --> 01:10:53,740 Or here is a rational object whose numerator is polynomials 1278 01:10:53,740 --> 01:11:00,480 in x whose coefficients are rational objects constructed 1279 01:11:00,480 --> 01:11:03,390 out of complex numbers. 1280 01:11:03,390 --> 01:11:04,850 And then there are a lot of other things like that. 1281 01:11:04,850 --> 01:11:07,500 See, whenever you have a thing where the operations reduce to 1282 01:11:07,500 --> 01:11:10,450 operations on the pieces, another example would be two 1283 01:11:10,450 --> 01:11:12,310 by two matrices. 1284 01:11:12,310 --> 01:11:17,030 I have the idea, there might be a matrix here of general 1285 01:11:17,030 --> 01:11:18,650 things that I don't care about. 1286 01:11:18,650 --> 01:11:25,180 But if I add two of them, the answer over here is gotten by 1287 01:11:25,180 --> 01:11:29,030 adding this one and that one, however they like to add. 1288 01:11:29,030 --> 01:11:31,110 So I can implement that the same way. 1289 01:11:31,110 --> 01:11:33,520 And if I do that, then again suddenly my system can start 1290 01:11:33,520 --> 01:11:35,480 handling things like this. 1291 01:11:35,480 --> 01:11:39,460 So here's a matrix whose elements happen to be-- 1292 01:11:39,460 --> 01:11:43,330 we'll say this element here is a rational object whose 1293 01:11:43,330 --> 01:11:47,230 numerator and denominators are polynomials. 1294 01:11:47,230 --> 01:11:49,510 And all that comes for free. 1295 01:11:49,510 --> 01:11:52,580 1296 01:11:52,580 --> 01:11:53,920 What's really going on here? 1297 01:11:53,920 --> 01:11:58,910 What's really going on is getting rid of this manager 1298 01:11:58,910 --> 01:12:02,060 who's sitting there poking his nose into who everybody's 1299 01:12:02,060 --> 01:12:03,120 business is. 1300 01:12:03,120 --> 01:12:05,900 We built a system that has decentralized control. 1301 01:12:05,900 --> 01:12:14,350 1302 01:12:14,350 --> 01:12:18,340 So when you come into and no one's poking around saying, 1303 01:12:18,340 --> 01:12:21,080 gee, are you in the official list of 1304 01:12:21,080 --> 01:12:22,440 people who can be added? 1305 01:12:22,440 --> 01:12:24,850 Rather you say, well go off and add yourself how your 1306 01:12:24,850 --> 01:12:27,810 parts like to be added. 1307 01:12:27,810 --> 01:12:31,030 And the result of that is you can get this very, very, very 1308 01:12:31,030 --> 01:12:33,870 complex hierarchy where a lot of things just get done and 1309 01:12:33,870 --> 01:12:36,482 rooted to the right place automatically. 1310 01:12:36,482 --> 01:12:37,732 Let's stop for questions. 1311 01:12:37,732 --> 01:12:40,380 1312 01:12:40,380 --> 01:12:43,020 AUDIENCE: You say you get this for free. 1313 01:12:43,020 --> 01:12:46,920 One thing that strikes me is that now you've lost kind of 1314 01:12:46,920 --> 01:12:50,150 the cleanness of the break between what's on top and 1315 01:12:50,150 --> 01:12:50,910 what's underneath. 1316 01:12:50,910 --> 01:12:52,770 In other words, now you're defining some of the 1317 01:12:52,770 --> 01:12:54,850 lower-level procedures in terms of things 1318 01:12:54,850 --> 01:12:56,610 above their own line. 1319 01:12:56,610 --> 01:13:00,350 Isn't that dangerous? 1320 01:13:00,350 --> 01:13:05,440 Or, if nothing more, a little less structured? 1321 01:13:05,440 --> 01:13:06,125 PROFESSOR: No, I-- 1322 01:13:06,125 --> 01:13:07,770 the question is whether that's less structured. 1323 01:13:07,770 --> 01:13:08,690 Depends on what you mean by structure. 1324 01:13:08,690 --> 01:13:11,050 All this is doing is recursion. 1325 01:13:11,050 --> 01:13:15,780 See, it's saying that the way you add these 1326 01:13:15,780 --> 01:13:18,640 guys is to use that. 1327 01:13:18,640 --> 01:13:20,520 And that's not less structured, it's just a 1328 01:13:20,520 --> 01:13:22,610 recursive structure. 1329 01:13:22,610 --> 01:13:24,730 So I don't think it's particularly any less clean. 1330 01:13:24,730 --> 01:13:27,250 AUDIENCE: Now when you want to change the multiplier or the 1331 01:13:27,250 --> 01:13:31,380 add operator, suddenly you've got tremendous consequences 1332 01:13:31,380 --> 01:13:34,480 underneath that you're not even sure the extent of. 1333 01:13:34,480 --> 01:13:37,080 PROFESSOR: That's right, but it depends what you mean. 1334 01:13:37,080 --> 01:13:38,470 See, this goes both ways. 1335 01:13:38,470 --> 01:13:41,790 1336 01:13:41,790 --> 01:13:44,690 What would be a good example? 1337 01:13:44,690 --> 01:13:47,500 I ignored greatest common divisor, for instance. 1338 01:13:47,500 --> 01:13:50,280 I ignored that problem just to keep the example simple. 1339 01:13:50,280 --> 01:13:59,820 But if I suddenly decided that plus rat here should do a GCD 1340 01:13:59,820 --> 01:14:04,750 computation and install that, then that immediately becomes 1341 01:14:04,750 --> 01:14:08,280 available to all of these, to that guy, and that guy, and 1342 01:14:08,280 --> 01:14:11,560 that guy, and all the way down. 1343 01:14:11,560 --> 01:14:13,890 So it depends what you mean by the coherence of your system. 1344 01:14:13,890 --> 01:14:17,030 It's certainly true that you might want to have a special 1345 01:14:17,030 --> 01:14:18,950 different one that didn't filter down through the 1346 01:14:18,950 --> 01:14:21,400 coefficients, but the nice thing about this particular 1347 01:14:21,400 --> 01:14:25,440 example is that mostly you do. 1348 01:14:25,440 --> 01:14:27,630 AUDIENCE: Isn't that the problem, I think, that you're 1349 01:14:27,630 --> 01:14:32,950 getting to tied in with the fact that the structuring, the 1350 01:14:32,950 --> 01:14:36,330 recursiveness of that structuring there is actually 1351 01:14:36,330 --> 01:14:40,340 in execution as opposed to just definition of the actual 1352 01:14:40,340 --> 01:14:41,590 types themselves? 1353 01:14:41,590 --> 01:14:44,680 1354 01:14:44,680 --> 01:14:46,120 PROFESSOR: I think I understand the question. 1355 01:14:46,120 --> 01:14:48,650 The point is that these types evolve and get more and more 1356 01:14:48,650 --> 01:14:50,400 complex as the thing's actually running. 1357 01:14:50,400 --> 01:14:50,730 Is that what-- 1358 01:14:50,730 --> 01:14:50,990 AUDIENCE: Yes. 1359 01:14:50,990 --> 01:14:51,790 As it's running. 1360 01:14:51,790 --> 01:14:51,956 PROFESSOR: --what you're saying? 1361 01:14:51,956 --> 01:14:52,090 Yes, the point is-- 1362 01:14:52,090 --> 01:14:54,180 AUDIENCE: As opposed to the basic definitions. 1363 01:14:54,180 --> 01:14:54,830 PROFESSOR: Right. 1364 01:14:54,830 --> 01:14:57,210 The type structure is sort of recursive. 1365 01:14:57,210 --> 01:15:02,770 It's not that you can make this finite list of the actual 1366 01:15:02,770 --> 01:15:04,850 things they might look like before the system runs. 1367 01:15:04,850 --> 01:15:06,780 It's something that evolves. 1368 01:15:06,780 --> 01:15:09,610 So if you want to specify that system, you have to do in some 1369 01:15:09,610 --> 01:15:12,275 other way than by this finite list. You have to do it by a 1370 01:15:12,275 --> 01:15:13,670 recursive structure. 1371 01:15:13,670 --> 01:15:16,960 AUDIENCE: Because the basic structure of the types is 1372 01:15:16,960 --> 01:15:17,900 pretty clean and simple. 1373 01:15:17,900 --> 01:15:20,125 PROFESSOR: Right. 1374 01:15:20,125 --> 01:15:21,460 Yes? 1375 01:15:21,460 --> 01:15:22,870 AUDIENCE: I have a question. 1376 01:15:22,870 --> 01:15:25,980 I understand once you have your data structure set up, 1377 01:15:25,980 --> 01:15:29,230 how it pulls off complex and passes that down, and then 1378 01:15:29,230 --> 01:15:30,640 pulls off rect, passes that down. 1379 01:15:30,640 --> 01:15:32,790 But if you're just a user and you don't know anything about 1380 01:15:32,790 --> 01:15:35,610 rect or polar or whatever, how do you initially set up that 1381 01:15:35,610 --> 01:15:37,330 data structure so that everything goes 1382 01:15:37,330 --> 01:15:38,390 to the right spot? 1383 01:15:38,390 --> 01:15:41,210 If I just have the equation over there on the left and I 1384 01:15:41,210 --> 01:15:42,500 just want to add, multiply complex numbers-- 1385 01:15:42,500 --> 01:15:43,640 PROFESSOR: Well that's the wonderful thing. 1386 01:15:43,640 --> 01:15:47,730 If you're just a user you say "mul." 1387 01:15:47,730 --> 01:15:50,280 AUDIENCE: And it figures out that I mean complex numbers? 1388 01:15:50,280 --> 01:15:51,420 Or how do I tell it that I want-- 1389 01:15:51,420 --> 01:15:51,950 PROFESSOR: Well you're going to have in your 1390 01:15:51,950 --> 01:15:53,050 hands complex numbers. 1391 01:15:53,050 --> 01:15:56,490 See what you would have at some level, as a real user, is 1392 01:15:56,490 --> 01:15:58,370 a constructor for complex numbers. 1393 01:15:58,370 --> 01:15:59,470 AUDIENCE: So then I have to make complex numbers? 1394 01:15:59,470 --> 01:16:00,350 PROFESSOR: So you have to make them. 1395 01:16:00,350 --> 01:16:03,180 What you would probably have as a user is some little thing 1396 01:16:03,180 --> 01:16:07,390 in the reader loop, which would give you some plausible 1397 01:16:07,390 --> 01:16:09,850 way to type in a complex number, in 1398 01:16:09,850 --> 01:16:11,590 whatever format you like. 1399 01:16:11,590 --> 01:16:14,360 Or it might be that you're never typing them in. 1400 01:16:14,360 --> 01:16:16,170 Someone's just handing you a complex number. 1401 01:16:16,170 --> 01:16:19,500 AUDIENCE: OK, so if I had a complex number that had a 1402 01:16:19,500 --> 01:16:21,505 polynomial in it, I'd have to make my polynomial and then 1403 01:16:21,505 --> 01:16:21,960 make my complex number. 1404 01:16:21,960 --> 01:16:24,220 PROFESSOR: Right if you wanted it constructed from scratch. 1405 01:16:24,220 --> 01:16:25,710 At some point you construct them from scratch. 1406 01:16:25,710 --> 01:16:27,880 But what you don't have to know of that is when you have 1407 01:16:27,880 --> 01:16:32,345 the object you can just say "mul." And it'll multiply. 1408 01:16:32,345 --> 01:16:33,279 Yeah? 1409 01:16:33,279 --> 01:16:36,450 AUDIENCE: I think the question that was being posed here is, 1410 01:16:36,450 --> 01:16:40,220 say if I want to change my presentation of complexes, or 1411 01:16:40,220 --> 01:16:46,330 some operation of complex, how much real code I will have to 1412 01:16:46,330 --> 01:16:49,860 gets around with, or change to change it in 1413 01:16:49,860 --> 01:16:52,270 one specific operation? 1414 01:16:52,270 --> 01:16:53,490 PROFESSOR: [UNINTELLIGIBLE] what you have to change. 1415 01:16:53,490 --> 01:16:54,690 And the point is that you only have to 1416 01:16:54,690 --> 01:16:56,070 change what you're changing. 1417 01:16:56,070 --> 01:17:00,320 See if Martha decides that she would rather-- 1418 01:17:00,320 --> 01:17:01,440 let's see something silly-- 1419 01:17:01,440 --> 01:17:04,040 like change the order in the pair. 1420 01:17:04,040 --> 01:17:09,700 Like angle and magnitude in the other order, she just 1421 01:17:09,700 --> 01:17:10,970 makes that change locally. 1422 01:17:10,970 --> 01:17:12,750 And the whole thing will propagate through the system 1423 01:17:12,750 --> 01:17:14,790 in the right way. 1424 01:17:14,790 --> 01:17:18,040 Or if suddenly you said, gee, I have another representation 1425 01:17:18,040 --> 01:17:19,700 for rationals. 1426 01:17:19,700 --> 01:17:22,740 And I'm going to stick it here, by filing those 1427 01:17:22,740 --> 01:17:24,820 operations in the table. 1428 01:17:24,820 --> 01:17:27,220 Then suddenly all of these polynomials whose coefficients 1429 01:17:27,220 --> 01:17:29,240 are coefficients of coefficients, or whatever, 1430 01:17:29,240 --> 01:17:32,970 also can automatically have available that representation. 1431 01:17:32,970 --> 01:17:35,952 That's the power of this particular one. 1432 01:17:35,952 --> 01:17:37,625 AUDIENCE: I'm not sure if I can even pose an intelligent 1433 01:17:37,625 --> 01:17:38,700 sounding question. 1434 01:17:38,700 --> 01:17:42,920 But somehow this whole thing went really nicely to this 1435 01:17:42,920 --> 01:17:44,910 beautiful finish where all the things seemed 1436 01:17:44,910 --> 01:17:47,280 to fall into place. 1437 01:17:47,280 --> 01:17:48,530 Sort of seemed a little contrived. 1438 01:17:48,530 --> 01:17:50,930 1439 01:17:50,930 --> 01:17:52,670 That's all for the sake, I'm sure, of teaching. 1440 01:17:52,670 --> 01:17:55,100 I doubt that the guys who first did this-- 1441 01:17:55,100 --> 01:17:56,510 and I could be wrong-- 1442 01:17:56,510 --> 01:17:59,200 figured it all out so that when they just all put it all 1443 01:17:59,200 --> 01:18:02,410 together, you could all of the sudden, blam, do any kind of 1444 01:18:02,410 --> 01:18:04,860 arithmetic on any kind of object. 1445 01:18:04,860 --> 01:18:07,930 It seems like maybe they had to play with it for a while 1446 01:18:07,930 --> 01:18:11,800 and had to bash it and rework it. 1447 01:18:11,800 --> 01:18:14,120 And it seems like that's the kind of problem we're really 1448 01:18:14,120 --> 01:18:16,540 faced with we start trying to design a really complex 1449 01:18:16,540 --> 01:18:19,390 system, is having lots of different kinds of parts and 1450 01:18:19,390 --> 01:18:22,730 not even knowing what kinds of operations we're going to want 1451 01:18:22,730 --> 01:18:24,620 to do on those parts. 1452 01:18:24,620 --> 01:18:27,580 How to organize the operations in this nice way so that no 1453 01:18:27,580 --> 01:18:29,630 matter what you do, when you start putting them together 1454 01:18:29,630 --> 01:18:31,700 everything starts falling out for free. 1455 01:18:31,700 --> 01:18:33,090 PROFESSOR: OK, well that's certainly a 1456 01:18:33,090 --> 01:18:34,340 very intelligent question. 1457 01:18:34,340 --> 01:18:37,020 1458 01:18:37,020 --> 01:18:40,560 One part is this is a very good methodology that people 1459 01:18:40,560 --> 01:18:44,590 have discovered a lot coming from symbolic algebra. 1460 01:18:44,590 --> 01:18:47,590 Because there are a lot of complications. 1461 01:18:47,590 --> 01:18:50,710 To allow you to implement these things before you decide 1462 01:18:50,710 --> 01:18:52,130 what you want all the operations to 1463 01:18:52,130 --> 01:18:53,310 be, and all of that. 1464 01:18:53,310 --> 01:18:55,580 So in some sense it's an answer that people have 1465 01:18:55,580 --> 01:18:58,560 discovered by wading through this stuff. 1466 01:18:58,560 --> 01:19:02,160 In another sense, it is a very contrived example. 1467 01:19:02,160 --> 01:19:06,240 AUDIENCE: It seems like to be able to do this you do have to 1468 01:19:06,240 --> 01:19:08,320 wade through it for a certain amount of time before you can 1469 01:19:08,320 --> 01:19:09,010 become good at it. 1470 01:19:09,010 --> 01:19:12,220 PROFESSOR: Let me show you how terribly contrived this is. 1471 01:19:12,220 --> 01:19:14,130 So you can write all these wonderful things. 1472 01:19:14,130 --> 01:19:17,600 But the system that I wrote here, and if we had another 1473 01:19:17,600 --> 01:19:19,820 half an hour to give this lecture I would have given 1474 01:19:19,820 --> 01:19:23,470 this part of it, which says, notice that it breaks down if 1475 01:19:23,470 --> 01:19:30,880 I tell it to do something as foolish as add 3 plus 7/2. 1476 01:19:30,880 --> 01:19:33,980 Because what will happen is you'll get to operate-2, and 1477 01:19:33,980 --> 01:19:36,180 operate-2 will say, oh this is type number, 1478 01:19:36,180 --> 01:19:37,560 and that's type rational. 1479 01:19:37,560 --> 01:19:38,810 I don't know how to add them. 1480 01:19:38,810 --> 01:19:41,530 1481 01:19:41,530 --> 01:19:43,600 So you'd like the system at least to be able to say 1482 01:19:43,600 --> 01:19:48,660 something like, gee, before you do that 1483 01:19:48,660 --> 01:19:50,480 change that to 3/1. 1484 01:19:50,480 --> 01:19:52,250 Turn it into a rational number, hand that to the 1485 01:19:52,250 --> 01:19:53,500 rational package. 1486 01:19:53,500 --> 01:19:55,510 1487 01:19:55,510 --> 01:19:58,860 That's the thing I didn't talk about in this lecture. 1488 01:19:58,860 --> 01:20:00,880 It's a little bit in the book, which talks about the problem 1489 01:20:00,880 --> 01:20:03,390 of what's called coercion. 1490 01:20:03,390 --> 01:20:05,310 Where you wanted-- 1491 01:20:05,310 --> 01:20:08,280 see, having so carefully set up all of these types as 1492 01:20:08,280 --> 01:20:11,720 distinct objects, a lot of times you want to also put in 1493 01:20:11,720 --> 01:20:16,650 knowledge about how to view an ordinary number 1494 01:20:16,650 --> 01:20:19,110 as a kind of rational. 1495 01:20:19,110 --> 01:20:21,620 Or view an ordinary number as a kind of complex. 1496 01:20:21,620 --> 01:20:24,580 That's where the complexity in the system really starts 1497 01:20:24,580 --> 01:20:27,110 happening, where you talk about, see where 1498 01:20:27,110 --> 01:20:28,420 do I put that knowledge? 1499 01:20:28,420 --> 01:20:30,810 Is it rational to know that ordinary numbers might be 1500 01:20:30,810 --> 01:20:33,130 pieces of [UNINTELLIGIBLE] of them? 1501 01:20:33,130 --> 01:20:38,790 Or they're terrible, terrible examples, like if I might want 1502 01:20:38,790 --> 01:20:47,510 to add a complex number to a rational number. 1503 01:20:47,510 --> 01:20:50,080 1504 01:20:50,080 --> 01:20:50,760 Bad example. 1505 01:20:50,760 --> 01:20:52,010 5/7. 1506 01:20:52,010 --> 01:20:53,860 1507 01:20:53,860 --> 01:20:57,300 Then somebody's got to know that I have to convert these 1508 01:20:57,300 --> 01:20:59,790 to another type, which is complex numbers whose parts 1509 01:20:59,790 --> 01:21:01,540 might be rationals. 1510 01:21:01,540 --> 01:21:02,680 And who worries about that? 1511 01:21:02,680 --> 01:21:03,950 Does complex worry about that? 1512 01:21:03,950 --> 01:21:05,030 Does rational worry about that? 1513 01:21:05,030 --> 01:21:06,900 Does plus worry about that? 1514 01:21:06,900 --> 01:21:08,520 That's where the real complexity comes in. 1515 01:21:08,520 --> 01:21:11,380 And that's where it's pretty well sorted out. 1516 01:21:11,380 --> 01:21:14,810 And a lot of, in fact, all of this message passing stuff was 1517 01:21:14,810 --> 01:21:18,460 motivated by problems like this. 1518 01:21:18,460 --> 01:21:21,630 And when you really push it, people are-- somehow the 1519 01:21:21,630 --> 01:21:25,330 algebraic manipulation problem seems to be so complex that 1520 01:21:25,330 --> 01:21:27,410 the people who are always at the edge of it are exactly in 1521 01:21:27,410 --> 01:21:28,050 the state you said. 1522 01:21:28,050 --> 01:21:29,940 They're wading through this thing, mucking around, seeing 1523 01:21:29,940 --> 01:21:33,470 what they use, trying to distill stuff. 1524 01:21:33,470 --> 01:21:36,030 AUDIENCE: I just want to come back to this issue of 1525 01:21:36,030 --> 01:21:39,250 complexity once more. 1526 01:21:39,250 --> 01:21:44,550 It certainly seems to be true that you have a great deal of 1527 01:21:44,550 --> 01:21:49,580 flexibility in altering the lower level kinds of things. 1528 01:21:49,580 --> 01:21:54,320 But it is true that you are, in a sense, freezing higher 1529 01:21:54,320 --> 01:21:55,450 level operations. 1530 01:21:55,450 --> 01:21:58,510 Or at least if you change them you don't know where all of 1531 01:21:58,510 --> 01:22:02,060 the changes are going to show up, or how they are. 1532 01:22:02,060 --> 01:22:04,840 PROFESSOR: OK, that's an extremely good question. 1533 01:22:04,840 --> 01:22:10,130 What I have to do is, if I decide there's a new general 1534 01:22:10,130 --> 01:22:16,300 operation called equality test, then all of these people 1535 01:22:16,300 --> 01:22:19,835 have to decide whether or not they would like to have an 1536 01:22:19,835 --> 01:22:24,650 equality test by looking in the table. 1537 01:22:24,650 --> 01:22:27,870 There're ways to decentralize it even more. 1538 01:22:27,870 --> 01:22:31,430 That's what I sort of hinted at last time, where I said you 1539 01:22:31,430 --> 01:22:34,240 could not only have this type as a symbol, but you actually 1540 01:22:34,240 --> 01:22:37,850 might store in each object the operations 1541 01:22:37,850 --> 01:22:40,450 that it knows of that. 1542 01:22:40,450 --> 01:22:44,670 So you might have things like greatest common divisor, which 1543 01:22:44,670 --> 01:22:47,540 is a thing here which is defined only for integers, and 1544 01:22:47,540 --> 01:22:51,030 not in general for rational numbers. 1545 01:22:51,030 --> 01:22:53,110 So it might be a very, very fragmented system. 1546 01:22:53,110 --> 01:22:56,570 And then depending on where you want your flexibility, 1547 01:22:56,570 --> 01:22:58,190 there's a whole spectrum of places that you 1548 01:22:58,190 --> 01:22:59,960 can build that in. 1549 01:22:59,960 --> 01:23:02,320 But you're pointing at the place where this starts being 1550 01:23:02,320 --> 01:23:04,540 weak, that there has to be some agreement on top here 1551 01:23:04,540 --> 01:23:06,370 about these general operations. 1552 01:23:06,370 --> 01:23:08,390 Or at least people have to think about them. 1553 01:23:08,390 --> 01:23:10,340 Or you might decide, you might have a table that's very 1554 01:23:10,340 --> 01:23:14,010 sparse, that only has a few things in it. 1555 01:23:14,010 --> 01:23:15,490 But there are lot of ways to play that game. 1556 01:23:15,490 --> 01:23:19,780 1557 01:23:19,780 --> 01:23:21,030 OK, thank you. 1558 01:23:21,030 --> 01:23:23,534 1559 01:23:23,534 --> 01:23:23,849 [MUSIC: "JESU, JOY OF MAN'S DESIRING" BY 1560 01:23:23,849 --> 01:23:25,099 JOHANN SEBASTIAN BACH] 1561 01:23:25,099 --> 01:23:36,682 ================================================ FILE: SrtEN/lec5a_512kb.mp4.srt ================================================ 1 00:00:00,000 --> 00:00:16,830 [MUSIC PLAYING] 2 00:00:16,830 --> 00:00:22,480 PROFESSOR: Well, so far we've invented enough programming to 3 00:00:22,480 --> 00:00:24,850 do some very complicated things. 4 00:00:24,850 --> 00:00:28,710 And you surely learned a lot about 5 00:00:28,710 --> 00:00:29,760 programming at this point. 6 00:00:29,760 --> 00:00:32,189 You've learned almost all the most important tricks that 7 00:00:32,189 --> 00:00:34,870 usually don't get taught to people until they have had a 8 00:00:34,870 --> 00:00:36,610 lot of experience. 9 00:00:36,610 --> 00:00:40,800 For example, data directed programming is a major trick, 10 00:00:40,800 --> 00:00:42,755 and yesterday you also saw an interpreted language. 11 00:00:42,755 --> 00:00:45,300 12 00:00:45,300 --> 00:00:50,320 We did this all in a computer language, at this point, where 13 00:00:50,320 --> 00:00:54,020 there was no assignment statement. 14 00:00:54,020 --> 00:00:56,790 And presumably, for those of you who've seen your Basic or 15 00:00:56,790 --> 00:01:00,170 Pascal or whatever, that's usually considered the most 16 00:01:00,170 --> 00:01:02,040 important thing. 17 00:01:02,040 --> 00:01:03,580 Well today, we're going to do some thing horrible. 18 00:01:03,580 --> 00:01:07,370 We're going to add an assignment statement. 19 00:01:07,370 --> 00:01:09,220 And since we can do all these wonderful things without it, 20 00:01:09,220 --> 00:01:11,110 why should we add it? 21 00:01:11,110 --> 00:01:13,040 An important thing to understand is that today we're 22 00:01:13,040 --> 00:01:17,270 going to, first of all, have a rule, which is going to always 23 00:01:17,270 --> 00:01:19,520 be obeyed, which is the only reason we ever add a feature 24 00:01:19,520 --> 00:01:23,636 to our language is because there is a good reason. 25 00:01:23,636 --> 00:01:27,470 And the good reason is going to boil down to the ability, 26 00:01:27,470 --> 00:01:30,500 you now get an ability to break a problem into pieces 27 00:01:30,500 --> 00:01:32,010 that are different sets of pieces then you could have 28 00:01:32,010 --> 00:01:35,380 broken it down without that, give you another means of 29 00:01:35,380 --> 00:01:36,630 decomposition. 30 00:01:36,630 --> 00:01:38,350 31 00:01:38,350 --> 00:01:39,490 However, let's just start. 32 00:01:39,490 --> 00:01:43,270 Let me quick begin by reviewing the kind of language 33 00:01:43,270 --> 00:01:48,240 that we have now. 34 00:01:48,240 --> 00:01:51,310 We've been writing what's called functional programs. 35 00:01:51,310 --> 00:01:56,770 And functional programs are a kind of encoding of 36 00:01:56,770 --> 00:01:58,890 mathematical truths. 37 00:01:58,890 --> 00:02:02,420 For example, when we look at the factorial procedure that 38 00:02:02,420 --> 00:02:07,090 you see on the slide here, it's basically two clauses. 39 00:02:07,090 --> 00:02:09,530 If n is one, the result is one, otherwise n times 40 00:02:09,530 --> 00:02:11,230 factorial n minus one. 41 00:02:11,230 --> 00:02:12,990 That's factorial of n. 42 00:02:12,990 --> 00:02:14,960 Well, that is factorial of n. 43 00:02:14,960 --> 00:02:17,120 And written down in some other obscure notation that you 44 00:02:17,120 --> 00:02:22,310 might have learned in calculus classes, mathematical logic, 45 00:02:22,310 --> 00:02:28,090 what you see there is if n equals one, for the result of 46 00:02:28,090 --> 00:02:31,060 n factorial is one, otherwise, greater than one, n factorial 47 00:02:31,060 --> 00:02:32,680 is n times n minus one factorial. 48 00:02:32,680 --> 00:02:35,560 True statements, that's the kind of 49 00:02:35,560 --> 00:02:37,000 language we've been using. 50 00:02:37,000 --> 00:02:39,610 And whenever we have true statements of that sort, there 51 00:02:39,610 --> 00:02:47,490 is a kind of, a way of understanding how they work 52 00:02:47,490 --> 00:02:50,170 which is that such processes can be involved by 53 00:02:50,170 --> 00:02:51,390 substitution. 54 00:02:51,390 --> 00:02:56,230 And so we see on the second slide here, that the way we 55 00:02:56,230 --> 00:03:02,010 understand the execution implied by those statements in 56 00:03:02,010 --> 00:03:05,640 arranged in that order, is that you do successive 57 00:03:05,640 --> 00:03:09,370 substitutions of arguments for formal parameters in the body 58 00:03:09,370 --> 00:03:12,430 of a procedure. 59 00:03:12,430 --> 00:03:14,710 This is basically a sequence of equalities. 60 00:03:14,710 --> 00:03:17,390 Factorial four is four times factorial three. 61 00:03:17,390 --> 00:03:21,290 That is four times three times factorial of two and so on. 62 00:03:21,290 --> 00:03:23,325 We're always preserving truth. 63 00:03:23,325 --> 00:03:26,580 64 00:03:26,580 --> 00:03:29,190 Even though we're talking about true statements, there 65 00:03:29,190 --> 00:03:31,390 might be more than one organization of these true 66 00:03:31,390 --> 00:03:34,630 statements to describe the computation of a particular 67 00:03:34,630 --> 00:03:37,490 function, the computation of the value of 68 00:03:37,490 --> 00:03:38,640 a particular function. 69 00:03:38,640 --> 00:03:42,460 So, for example, looking at the next one here. 70 00:03:42,460 --> 00:03:49,780 Here is a way of looking at the sum of n and m. 71 00:03:49,780 --> 00:03:52,930 And we did this one by a recursive process. 72 00:03:52,930 --> 00:04:00,130 It's the increment of the sum of the decrement of n and m. 73 00:04:00,130 --> 00:04:03,780 And, of course, there is some piece of mathematical logic 74 00:04:03,780 --> 00:04:06,240 here that describes that. 75 00:04:06,240 --> 00:04:11,450 It's the increment of the sum of the decrement of n and m, 76 00:04:11,450 --> 00:04:13,120 just like that. 77 00:04:13,120 --> 00:04:16,440 So there's nothing particularly magic about that. 78 00:04:16,440 --> 00:04:19,059 And, of course, if we can also look at an iterative process 79 00:04:19,059 --> 00:04:22,920 for the same, a program that evolves an iterative process, 80 00:04:22,920 --> 00:04:25,310 for the same function. 81 00:04:25,310 --> 00:04:29,930 These are two things that compute the same answer. 82 00:04:29,930 --> 00:04:34,220 And we have equivalent mathematical truths that are 83 00:04:34,220 --> 00:04:36,720 arranged there. 84 00:04:36,720 --> 00:04:38,920 And just the way you arrange those truths determine the 85 00:04:38,920 --> 00:04:40,430 particular process. 86 00:04:40,430 --> 00:04:42,810 In the way choose and arrange them determines the process 87 00:04:42,810 --> 00:04:44,400 that's evolved. 88 00:04:44,400 --> 00:04:47,370 So we have the flexibility of talking about both the 89 00:04:47,370 --> 00:04:49,260 function to be computed, and the method 90 00:04:49,260 --> 00:04:50,410 by which it's computed. 91 00:04:50,410 --> 00:04:53,580 So it's not clear we need more. 92 00:04:53,580 --> 00:04:55,440 However, today I'm going to this awful thing. 93 00:04:55,440 --> 00:04:59,070 I'm going to introduce this assignment operation. 94 00:04:59,070 --> 00:05:02,890 Now, what is this? 95 00:05:02,890 --> 00:05:07,830 Well, first of all, there is going to be another kind of 96 00:05:07,830 --> 00:05:09,960 kind of statement, if you will, in a programming 97 00:05:09,960 --> 00:05:11,210 language called Set! 98 00:05:11,210 --> 00:05:13,800 99 00:05:13,800 --> 00:05:16,550 Things that do things like assignment, I'm going to put 100 00:05:16,550 --> 00:05:18,570 exclamation points after. 101 00:05:18,570 --> 00:05:20,990 We'll talk about what that means in a second. 102 00:05:20,990 --> 00:05:23,370 The exclamation point, again like question mark, is an 103 00:05:23,370 --> 00:05:25,960 arbitrary thing we attach to the symbol which is the name, 104 00:05:25,960 --> 00:05:28,090 has no significance to the system. 105 00:05:28,090 --> 00:05:31,520 The only significance is to me and you to alert you that this 106 00:05:31,520 --> 00:05:35,910 is an assignment of some sort. 107 00:05:35,910 --> 00:05:39,960 But we're going to set a variable to a value. 108 00:05:39,960 --> 00:05:43,800 109 00:05:43,800 --> 00:05:47,120 And what that's going to mean is that there is a time at 110 00:05:47,120 --> 00:05:48,600 which something happens. 111 00:05:48,600 --> 00:05:50,100 Here's a time. 112 00:05:50,100 --> 00:05:55,030 If I have time going this way, it's a time access. 113 00:05:55,030 --> 00:05:58,650 Time progresses by walking down the page. 114 00:05:58,650 --> 00:06:01,250 Then an assignment is the first thing we have that 115 00:06:01,250 --> 00:06:06,670 produces the difference between a before and an after. 116 00:06:06,670 --> 00:06:09,660 All the other programs that we've written, that have no 117 00:06:09,660 --> 00:06:12,400 assignments in them, the order in which they were evaluated 118 00:06:12,400 --> 00:06:14,590 didn't matter. 119 00:06:14,590 --> 00:06:17,990 But assignment is special, it produces a moment in time. 120 00:06:17,990 --> 00:06:27,980 So there is a moment before the set occurs and after, such 121 00:06:27,980 --> 00:06:39,500 that after this moment in time, the variable has the 122 00:06:39,500 --> 00:06:43,320 value, value. 123 00:06:43,320 --> 00:06:49,310 124 00:06:49,310 --> 00:06:53,340 Independent of what value it had before, set! 125 00:06:53,340 --> 00:06:57,660 changes the value of the variable. 126 00:06:57,660 --> 00:07:03,150 Until this moment, we had nothing that changed. 127 00:07:03,150 --> 00:07:06,910 So, for example, one of the things we can think of is that 128 00:07:06,910 --> 00:07:09,890 the procedures we write for something like factorial are 129 00:07:09,890 --> 00:07:13,740 in fact pretty much identical to the function factorial. 130 00:07:13,740 --> 00:07:18,120 Factorial of four, if I write fact4, independent of what 131 00:07:18,120 --> 00:07:20,920 context it's in, and independent of how many times 132 00:07:20,920 --> 00:07:23,040 I write it, I always get the same answer. 133 00:07:23,040 --> 00:07:25,430 It's always 24. 134 00:07:25,430 --> 00:07:30,360 It's a unique map from the argument to the answer. 135 00:07:30,360 --> 00:07:33,580 And all the programs we've written so far are like that. 136 00:07:33,580 --> 00:07:37,020 However, once I have assignment, that isn't true. 137 00:07:37,020 --> 00:07:50,070 So, for example, if I were to define count to be one. 138 00:07:50,070 --> 00:07:55,550 And then I'm going to define also a procedure, a simple 139 00:07:55,550 --> 00:08:02,960 procedure called demo, which takes argument x and does the 140 00:08:02,960 --> 00:08:03,870 following operations. 141 00:08:03,870 --> 00:08:09,650 It first sets x to x plus one. 142 00:08:09,650 --> 00:08:13,160 My gosh, this looks just like FORTRAN, right-- 143 00:08:13,160 --> 00:08:14,410 in a funny syntax. 144 00:08:14,410 --> 00:08:16,910 145 00:08:16,910 --> 00:08:24,330 And then add to x count, Oh, I just made a mistake. 146 00:08:24,330 --> 00:08:27,010 I want to say, set! count to one plus count. 147 00:08:27,010 --> 00:08:30,310 148 00:08:30,310 --> 00:08:31,730 It's this thing defined here. 149 00:08:31,730 --> 00:08:34,350 150 00:08:34,350 --> 00:08:36,369 And then plus x count. 151 00:08:36,369 --> 00:08:40,409 152 00:08:40,409 --> 00:08:42,559 Then I can try this procedure. 153 00:08:42,559 --> 00:08:43,880 Let's run it. 154 00:08:43,880 --> 00:08:48,125 So, suppose I get a prompt and I say, demo three. 155 00:08:48,125 --> 00:08:52,210 156 00:08:52,210 --> 00:08:53,540 Well, what happens here? 157 00:08:53,540 --> 00:08:57,020 The first thing that happens is count is currently one. 158 00:08:57,020 --> 00:08:59,130 Currently, there is a time. 159 00:08:59,130 --> 00:09:00,710 We're talking about time. 160 00:09:00,710 --> 00:09:02,960 x gets three. 161 00:09:02,960 --> 00:09:06,090 At this moment, I say, oh yes, count is 162 00:09:06,090 --> 00:09:08,690 incremented, so count is two. 163 00:09:08,690 --> 00:09:10,710 two plus three is five. 164 00:09:10,710 --> 00:09:14,460 So the answer I get out is five. 165 00:09:14,460 --> 00:09:23,640 Then I say, demo of say, three again. 166 00:09:23,640 --> 00:09:24,830 What do I get? 167 00:09:24,830 --> 00:09:29,310 Well, now count is two, it's not one anymore, because I 168 00:09:29,310 --> 00:09:30,760 have incremented it. 169 00:09:30,760 --> 00:09:35,050 But now I go through this process, three goes into x, 170 00:09:35,050 --> 00:09:38,160 count becomes one plus count, so that's three now. 171 00:09:38,160 --> 00:09:42,130 The sum of those two is six, so the answer is six. 172 00:09:42,130 --> 00:09:45,760 And what we see is the same expression leads to two 173 00:09:45,760 --> 00:09:52,170 different answers, depending upon time. 174 00:09:52,170 --> 00:09:55,040 So demo is not a function, does not compute a 175 00:09:55,040 --> 00:09:56,290 mathematical function. 176 00:09:56,290 --> 00:10:00,020 177 00:10:00,020 --> 00:10:03,180 In fact, you could also see why now, of course, this is 178 00:10:03,180 --> 00:10:05,650 the first place where the substitution model 179 00:10:05,650 --> 00:10:07,780 isn't going to work. 180 00:10:07,780 --> 00:10:11,410 This kills the substitution model dead. 181 00:10:11,410 --> 00:10:14,060 You know, with quotation there were some little problems that 182 00:10:14,060 --> 00:10:17,380 a philosopher might notice with the substitutions, 183 00:10:17,380 --> 00:10:19,560 because you have to worry about what deductions you can 184 00:10:19,560 --> 00:10:23,070 make when you substitute into quotes, if you're allowed to 185 00:10:23,070 --> 00:10:25,150 do that at all. 186 00:10:25,150 --> 00:10:28,590 But here the substitution model is dead, can't do 187 00:10:28,590 --> 00:10:29,810 anything at all. 188 00:10:29,810 --> 00:10:34,490 Because, supposing I wanted to use a substitution model to 189 00:10:34,490 --> 00:10:37,560 consider substituting for count? 190 00:10:37,560 --> 00:10:42,150 Well, my gosh, if I substitute for here and here, they're 191 00:10:42,150 --> 00:10:44,540 different ones. 192 00:10:44,540 --> 00:10:46,570 It's not the same count any more. 193 00:10:46,570 --> 00:10:47,880 I get the wrong answer. 194 00:10:47,880 --> 00:10:51,410 The substitution model is a static phenomenon that 195 00:10:51,410 --> 00:10:55,560 describes things that are true and not things that change. 196 00:10:55,560 --> 00:10:56,810 Here, we have truths that change. 197 00:10:56,810 --> 00:11:01,860 198 00:11:01,860 --> 00:11:06,770 OK, Well, before I give you any understanding of this, 199 00:11:06,770 --> 00:11:07,870 this is very bad. 200 00:11:07,870 --> 00:11:11,520 Now, we've lost our model of computation. 201 00:11:11,520 --> 00:11:13,420 Pretty soon, I'm going to have to build you a new model of 202 00:11:13,420 --> 00:11:15,030 computation. 203 00:11:15,030 --> 00:11:18,710 But ours plays with this, just now, in an informal sense. 204 00:11:18,710 --> 00:11:21,490 Of course, what you already see is that when I have 205 00:11:21,490 --> 00:11:24,600 something like assignment, the model that we're going to need 206 00:11:24,600 --> 00:11:27,760 is different from the model that we had before in that the 207 00:11:27,760 --> 00:11:31,840 variables, those symbols like count, or x are no longer 208 00:11:31,840 --> 00:11:35,010 going to refer to the values they have, but rather to some 209 00:11:35,010 --> 00:11:37,810 sort of place where the value restored. 210 00:11:37,810 --> 00:11:40,330 We're going to have to think that way for a while. 211 00:11:40,330 --> 00:11:42,290 And it's going to be a very bad thing and 212 00:11:42,290 --> 00:11:44,590 cause a lot of trouble. 213 00:11:44,590 --> 00:11:47,350 And so, as I said, the very fact that we're inventing this 214 00:11:47,350 --> 00:11:49,750 bad thing, means that there had better be a good reason 215 00:11:49,750 --> 00:11:52,040 for it, otherwise, just a waste of time 216 00:11:52,040 --> 00:11:53,510 and a lot of effort. 217 00:11:53,510 --> 00:11:56,090 Let's just look at some of it just to play. 218 00:11:56,090 --> 00:11:59,130 Supposing we write down the functional version, functional 219 00:11:59,130 --> 00:12:02,770 meaning in the old style, of factorial by 220 00:12:02,770 --> 00:12:04,430 an iterative process. 221 00:12:04,430 --> 00:12:09,780 222 00:12:09,780 --> 00:12:26,810 Factorial of n, we're going to iterate of m and i, which says 223 00:12:26,810 --> 00:12:40,030 if i is greater than n, then the result is m, otherwise, 224 00:12:40,030 --> 00:12:46,930 the result of iterating the product of i and m. 225 00:12:46,930 --> 00:12:51,690 So m is going to be the product that I'm accumulating. 226 00:12:51,690 --> 00:12:52,940 m is the product. 227 00:12:52,940 --> 00:12:58,170 228 00:12:58,170 --> 00:12:59,990 And the count I'm going to increase by one. 229 00:12:59,990 --> 00:13:04,810 230 00:13:04,810 --> 00:13:12,060 Plus, ITER, ELSE, COND, define. 231 00:13:12,060 --> 00:13:13,310 I'm going to start this up. 232 00:13:13,310 --> 00:13:17,000 233 00:13:17,000 --> 00:13:18,980 And these days, you should have no trouble reading 234 00:13:18,980 --> 00:13:21,020 something like this. 235 00:13:21,020 --> 00:13:23,750 What I have here is a product there being 236 00:13:23,750 --> 00:13:26,750 accumulated and a counter. 237 00:13:26,750 --> 00:13:29,050 I start them up both at one. 238 00:13:29,050 --> 00:13:32,380 I'm going to buzz the counter up, i goes to i plus one every 239 00:13:32,380 --> 00:13:34,800 time around. 240 00:13:34,800 --> 00:13:38,910 But that's only our putting a time on the process, each of 241 00:13:38,910 --> 00:13:42,840 this is just a set of truths, true rules. 242 00:13:42,840 --> 00:13:47,010 And m is going to get a new values of i and m, i times m 243 00:13:47,010 --> 00:13:49,860 each time around, and eventually i is going to be 244 00:13:49,860 --> 00:13:52,750 bigger than n, in which case, the answer's going to be m. 245 00:13:52,750 --> 00:13:55,760 Now, I'm speaking to you, use time in this. 246 00:13:55,760 --> 00:13:58,210 That's just because I know how the computer works. 247 00:13:58,210 --> 00:13:59,090 But I didn't have to. 248 00:13:59,090 --> 00:14:01,810 This could be a purely mathematical description at 249 00:14:01,810 --> 00:14:03,040 this point, because substitution 250 00:14:03,040 --> 00:14:05,280 will work for this. 251 00:14:05,280 --> 00:14:08,870 But let's set right down a similar sort of program, using 252 00:14:08,870 --> 00:14:11,975 the same algorithm, but with assignments. 253 00:14:11,975 --> 00:14:15,296 254 00:14:15,296 --> 00:14:16,940 So this is called the functional version. 255 00:14:16,940 --> 00:14:23,840 256 00:14:23,840 --> 00:14:25,255 I want to write down an imperative version. 257 00:14:25,255 --> 00:14:34,150 258 00:14:34,150 --> 00:14:36,010 Factorial of n. 259 00:14:36,010 --> 00:14:37,510 I'm going to create my two variables. 260 00:14:37,510 --> 00:14:40,120 261 00:14:40,120 --> 00:14:48,230 Let i initialize itself to one, and m be initialized to 262 00:14:48,230 --> 00:14:50,930 one, similar. 263 00:14:50,930 --> 00:15:05,840 We'll create a loop which has COND greater than i, and if i 264 00:15:05,840 --> 00:15:07,360 is greater than n, we're done. 265 00:15:07,360 --> 00:15:10,910 And the result is m, the product I'm accumulating. 266 00:15:10,910 --> 00:15:19,320 Otherwise, I'm going to write down three things to do. 267 00:15:19,320 --> 00:15:22,300 I'm going to set! 268 00:15:22,300 --> 00:15:34,610 m to the product of i and m, set! i to the sum of i and 269 00:15:34,610 --> 00:15:40,610 one, and go around the loop again. 270 00:15:40,610 --> 00:15:44,890 Looks very familiar to you FORTRAN programmers. 271 00:15:44,890 --> 00:15:47,760 ELSE, COND, define, funny syntax though. 272 00:15:47,760 --> 00:15:51,270 273 00:15:51,270 --> 00:15:59,320 Start the loop up, and that's the program. 274 00:15:59,320 --> 00:16:02,790 Now, this program, how do we think about it? 275 00:16:02,790 --> 00:16:04,690 Well, let's just say what we're seeing here. 276 00:16:04,690 --> 00:16:07,820 There are two local variables, i and m, that have been 277 00:16:07,820 --> 00:16:10,810 initialized to one. 278 00:16:10,810 --> 00:16:13,120 Every time around the loop, I test to see if i is greater 279 00:16:13,120 --> 00:16:16,040 than n, which is the input argument, and if so, the 280 00:16:16,040 --> 00:16:19,240 result is the product being accumulated in m. 281 00:16:19,240 --> 00:16:23,640 However, if it's not the end of the loop, if I'm not done, 282 00:16:23,640 --> 00:16:26,260 then what I'm going to do is change the product to be the 283 00:16:26,260 --> 00:16:29,130 result of multiplying i times the current product. 284 00:16:29,130 --> 00:16:31,530 Which is sort of what we were doing here. 285 00:16:31,530 --> 00:16:33,386 Except here I wasn't changing. 286 00:16:33,386 --> 00:16:38,220 I was making another copy, because the substitution model 287 00:16:38,220 --> 00:16:44,410 says, you copy the body of the procedure with the arguments 288 00:16:44,410 --> 00:16:46,710 substituted for the formal parameters. 289 00:16:46,710 --> 00:16:49,690 Here I'm not worried about copying, here I've changed the 290 00:16:49,690 --> 00:16:51,990 value of m. 291 00:16:51,990 --> 00:16:56,090 I also then change the value of i to i plus one, and go 292 00:16:56,090 --> 00:16:58,300 buzzing around. 293 00:16:58,300 --> 00:17:01,360 Seems like essentially the same program, but there are 294 00:17:01,360 --> 00:17:03,110 some ways of making errors here that 295 00:17:03,110 --> 00:17:06,160 didn't exist until today. 296 00:17:06,160 --> 00:17:10,660 For example, if I were to do the horrible thing of not 297 00:17:10,660 --> 00:17:15,329 being careful in writing my program and interchange those 298 00:17:15,329 --> 00:17:17,890 two assignments, the program wouldn't 299 00:17:17,890 --> 00:17:20,339 compute the same function. 300 00:17:20,339 --> 00:17:24,859 I get a timing error because there's a dependency that m 301 00:17:24,859 --> 00:17:27,460 depends upon having the last value of i. 302 00:17:27,460 --> 00:17:32,760 If I try to i first, then I've got the wrong value of i when 303 00:17:32,760 --> 00:17:36,060 I multiply by m. 304 00:17:36,060 --> 00:17:38,600 It's a bug that wasn't available until this moment, 305 00:17:38,600 --> 00:17:40,660 until we introduced something that had time in it. 306 00:17:40,660 --> 00:17:43,470 307 00:17:43,470 --> 00:17:47,650 So, as I said, first we need a new model of computation, and 308 00:17:47,650 --> 00:17:49,790 second, we have to be damn good reason for doing this 309 00:17:49,790 --> 00:17:52,800 kind of ugly thing. 310 00:17:52,800 --> 00:17:54,050 Are there any questions? 311 00:17:54,050 --> 00:17:58,800 312 00:17:58,800 --> 00:18:00,505 Speak loudly, David. 313 00:18:00,505 --> 00:18:04,220 AUDIENCE: I'm confused about, we've introduced set now, but 314 00:18:04,220 --> 00:18:07,630 we had let before and define before. 315 00:18:07,630 --> 00:18:09,980 I'm confused about the difference between the three. 316 00:18:09,980 --> 00:18:14,100 Wouldn't define work in the same situation as set if you 317 00:18:14,100 --> 00:18:15,280 introduced it a bit? 318 00:18:15,280 --> 00:18:18,230 PROFESSOR: No, define is intended for setting something 319 00:18:18,230 --> 00:18:20,230 once the first time, for making it. 320 00:18:20,230 --> 00:18:22,790 321 00:18:22,790 --> 00:18:26,440 You've never seen me write on a blackboard two defines in a 322 00:18:26,440 --> 00:18:30,940 row whose intention was to change the old value of some 323 00:18:30,940 --> 00:18:31,970 variable to a new one. 324 00:18:31,970 --> 00:18:34,380 AUDIENCE: Is that by convention or-- 325 00:18:34,380 --> 00:18:38,120 PROFESSOR: No, it's intention. 326 00:18:38,120 --> 00:18:41,680 The answer is that, for example, internal to a 327 00:18:41,680 --> 00:18:47,250 procedure, two defines in a row are illegal, two defines 328 00:18:47,250 --> 00:18:49,850 in a row of the same variable. 329 00:18:49,850 --> 00:18:51,890 x can't be defined twice. 330 00:18:51,890 --> 00:18:54,300 Whether or not a system catches that error is a 331 00:18:54,300 --> 00:18:58,840 different question, but I legislate to you that define 332 00:18:58,840 --> 00:19:00,840 happens once on anything. 333 00:19:00,840 --> 00:19:04,770 Now, indeed, in interactive debugging, we intend that you 334 00:19:04,770 --> 00:19:08,460 interacting with your computer will redefine things, and so 335 00:19:08,460 --> 00:19:10,050 there's a special exception made 336 00:19:10,050 --> 00:19:11,610 for interactive debugging. 337 00:19:11,610 --> 00:19:18,480 But define is intended to mean to set up something which will 338 00:19:18,480 --> 00:19:22,460 be forever that value after that point. 339 00:19:22,460 --> 00:19:26,490 It's as if all the defines were done at the beginning. 340 00:19:26,490 --> 00:19:29,870 In fact, the only legal place to put a define in Scheme, 341 00:19:29,870 --> 00:19:32,570 internal to a procedure, is just at the beginning of a 342 00:19:32,570 --> 00:19:36,605 lambda expression, the beginning of 343 00:19:36,605 --> 00:19:37,855 the body of a procedure. 344 00:19:37,855 --> 00:19:41,750 345 00:19:41,750 --> 00:19:46,670 Now, let of course does nothing like either of that. 346 00:19:46,670 --> 00:19:50,520 I mean, if you look at what's happening with a let, this 347 00:19:50,520 --> 00:19:52,220 happens again exactly once. 348 00:19:52,220 --> 00:19:56,820 It sets up a context where i and m are values one and one. 349 00:19:56,820 --> 00:20:01,630 That context exists throughout this scope, this 350 00:20:01,630 --> 00:20:02,880 region of the program. 351 00:20:02,880 --> 00:20:05,080 352 00:20:05,080 --> 00:20:11,110 However, you don't think of that let as setting i again. 353 00:20:11,110 --> 00:20:12,350 It doesn't change it. 354 00:20:12,350 --> 00:20:15,390 i never changes because of the let. 355 00:20:15,390 --> 00:20:18,690 i gets created because of let. 356 00:20:18,690 --> 00:20:22,300 In fact, the let is a very simple idea. 357 00:20:22,300 --> 00:20:30,930 Let does nothing more, Let a variable one to have value 358 00:20:30,930 --> 00:20:37,660 one; I'll write this down a little bit more neatly; Let's 359 00:20:37,660 --> 00:20:43,890 write, var one have value, the value of expression e1, and 360 00:20:43,890 --> 00:20:48,470 variable two, have this value of the expression e2, in an 361 00:20:48,470 --> 00:21:00,420 expression e3, is the same thing as a procedure of var 362 00:21:00,420 --> 00:21:08,460 one and var two, the formal parameters, and e3 being the 363 00:21:08,460 --> 00:21:15,010 body, where var one is bound to the value of e1, and var 364 00:21:15,010 --> 00:21:16,820 two gets the value of e2. 365 00:21:16,820 --> 00:21:19,590 366 00:21:19,590 --> 00:21:22,050 So this is, in fact, a perfectly understandable thing 367 00:21:22,050 --> 00:21:24,930 from a substitution point of view. 368 00:21:24,930 --> 00:21:27,300 This is really the same expression written in two 369 00:21:27,300 --> 00:21:28,550 different ways. 370 00:21:28,550 --> 00:21:31,820 371 00:21:31,820 --> 00:21:34,220 In fact, the way the actual system works is this gets 372 00:21:34,220 --> 00:21:37,311 translated into this before anything happens. 373 00:21:37,311 --> 00:21:39,690 AUDIENCE: OK, I'm still unclear as then what makes the 374 00:21:39,690 --> 00:21:41,360 difference between a let and a define. 375 00:21:41,360 --> 00:21:42,125 They could-- 376 00:21:42,125 --> 00:21:45,570 PROFESSOR: A define is a syntactic sugar, whereby, 377 00:21:45,570 --> 00:21:48,270 essentially a bunch of variables get created by lets 378 00:21:48,270 --> 00:21:49,520 and then set up once. 379 00:21:49,520 --> 00:21:57,170 380 00:21:57,170 --> 00:21:58,790 OK, time for the first break, I think. 381 00:21:58,790 --> 00:22:00,040 Thank you. 382 00:22:00,040 --> 00:22:03,480 383 00:22:03,480 --> 00:23:04,430 [MUSIC PLAYING] 384 00:23:04,430 --> 00:23:06,530 Well let's see. 385 00:23:06,530 --> 00:23:10,520 I now have to rebuild the model of computation, so you 386 00:23:10,520 --> 00:23:13,690 understand how some such mechanical mechanism could 387 00:23:13,690 --> 00:23:17,600 work that can do what we've just talked about. 388 00:23:17,600 --> 00:23:22,730 I just recently destroyed your substitution model. 389 00:23:22,730 --> 00:23:25,070 Unfortunately, this model is significantly more complicated 390 00:23:25,070 --> 00:23:26,380 than the substitution model. 391 00:23:26,380 --> 00:23:29,010 It's called the environment model. 392 00:23:29,010 --> 00:23:32,130 And I'm going to have to introduce some terminology, 393 00:23:32,130 --> 00:23:34,660 which is very good terminology for you to know anyway. 394 00:23:34,660 --> 00:23:36,640 It's about names. 395 00:23:36,640 --> 00:23:39,360 And we're going to give names to the kinds of names things 396 00:23:39,360 --> 00:23:42,720 have and the way those names are used. 397 00:23:42,720 --> 00:23:48,290 So this is a meta-description, if you will. 398 00:23:48,290 --> 00:23:50,840 Anyway, there is a pile of an unfortunate terminology here, 399 00:23:50,840 --> 00:23:52,730 but we're going to need this to understand what's called 400 00:23:52,730 --> 00:23:54,770 the environment model. 401 00:23:54,770 --> 00:23:58,250 We're about to do a little bit of boring, dog-work here. 402 00:23:58,250 --> 00:24:02,280 Let's look at the first transparency. 403 00:24:02,280 --> 00:24:08,880 And we see a description of a word called bound. 404 00:24:08,880 --> 00:24:11,980 And we're going to say that a variable, v, is bound in an 405 00:24:11,980 --> 00:24:16,890 expression, e, if the meaning of e is unchanged by the 406 00:24:16,890 --> 00:24:22,520 uniform replacement of a variable w, not occurring in 407 00:24:22,520 --> 00:24:25,440 e, for every occurrence of v in e. 408 00:24:25,440 --> 00:24:28,390 Now that's a long sentence, so, I think, I'm going to have 409 00:24:28,390 --> 00:24:31,690 to say a little bit about that before we even fool 410 00:24:31,690 --> 00:24:33,490 around at all here. 411 00:24:33,490 --> 00:24:35,260 Bound variables we're talking about here. 412 00:24:35,260 --> 00:24:44,030 413 00:24:44,030 --> 00:24:46,710 And you've seen lots of them. 414 00:24:46,710 --> 00:24:48,170 You may not know that you've seen lots of them. 415 00:24:48,170 --> 00:24:51,880 Well, I suppose in your logic you saw a logical variables 416 00:24:51,880 --> 00:24:58,210 like, for every x there exists a y such that p is true of x 417 00:24:58,210 --> 00:24:59,860 and y from your calculus class. 418 00:24:59,860 --> 00:25:02,960 419 00:25:02,960 --> 00:25:06,780 This variable, x, and this variable, y, are bound, 420 00:25:06,780 --> 00:25:10,920 because the meaning of this expression does not depend 421 00:25:10,920 --> 00:25:16,640 upon the particular letters I used to describe x and y. 422 00:25:16,640 --> 00:25:21,740 If I were to change the w for x, then said for every w there 423 00:25:21,740 --> 00:25:26,420 exists a y such that p is true of w and y, it would be the 424 00:25:26,420 --> 00:25:29,540 same sentence. 425 00:25:29,540 --> 00:25:30,390 That's what it means. 426 00:25:30,390 --> 00:25:35,690 Or another case of this that you've seen is integral say, 427 00:25:35,690 --> 00:25:42,415 from 0 to one of dx over one plus x square. 428 00:25:42,415 --> 00:25:46,080 429 00:25:46,080 --> 00:25:47,440 Well that's something you see all the time. 430 00:25:47,440 --> 00:25:52,270 And this x is a bound variable. 431 00:25:52,270 --> 00:25:55,190 If I change that to a t, the expression is 432 00:25:55,190 --> 00:25:58,170 still the same thing. 433 00:25:58,170 --> 00:26:04,850 This is a 1/4 of the arctan of one or something like that. 434 00:26:04,850 --> 00:26:06,620 Yes, that's the arctan of one. 435 00:26:06,620 --> 00:26:09,380 So bound variables are actually fairly common, for 436 00:26:09,380 --> 00:26:13,690 those of you who have played a bit with mathematics. 437 00:26:13,690 --> 00:26:19,100 Well, let's go into the programming world. 438 00:26:19,100 --> 00:26:22,220 Instead of the quantifier being something like, for 439 00:26:22,220 --> 00:26:25,000 every, or there exists, or integral, a quantifier is a 440 00:26:25,000 --> 00:26:27,570 symbol that binds a variable. 441 00:26:27,570 --> 00:26:30,280 And we are going to use the quantifier lambda as being the 442 00:26:30,280 --> 00:26:33,970 essential thing that binds variables. 443 00:26:33,970 --> 00:26:37,730 And so we have some nice examples here like that 444 00:26:37,730 --> 00:26:43,160 procedure of one argument y which does 445 00:26:43,160 --> 00:26:44,370 the following thing. 446 00:26:44,370 --> 00:26:50,300 It calls the procedure of one argument x, which multiplies x 447 00:26:50,300 --> 00:26:54,145 by y, and applies that to three. 448 00:26:54,145 --> 00:26:58,810 449 00:26:58,810 --> 00:27:00,860 That procedure has the property there of two bound 450 00:27:00,860 --> 00:27:04,790 variables in it, x and y. 451 00:27:04,790 --> 00:27:08,500 This quantifier, lambda here, binds this y, and this 452 00:27:08,500 --> 00:27:12,120 quantifier, lambda, binds that x. 453 00:27:12,120 --> 00:27:15,000 Because, if I were to take an arbitrary symbol does not 454 00:27:15,000 --> 00:27:20,130 occur in this expression like w and replace all y's with w's 455 00:27:20,130 --> 00:27:23,610 in this expression, the expression is still the same, 456 00:27:23,610 --> 00:27:26,240 the same procedure. 457 00:27:26,240 --> 00:27:27,430 And this is an important idea. 458 00:27:27,430 --> 00:27:30,700 The reason why we had such things like that is a kind of 459 00:27:30,700 --> 00:27:31,500 modularity. 460 00:27:31,500 --> 00:27:34,800 If two people are writing programs, and they work 461 00:27:34,800 --> 00:27:38,150 together, it shouldn't matter what names they use internal 462 00:27:38,150 --> 00:27:42,490 to their own little machines that they're building. 463 00:27:42,490 --> 00:27:45,960 And so, what I'm really telling you there, is that, 464 00:27:45,960 --> 00:27:49,490 for example, this is equivalent to that procedure 465 00:27:49,490 --> 00:27:54,260 of one argument y which uses that procedure of one argument 466 00:27:54,260 --> 00:28:01,200 d which multiplies z by y. 467 00:28:01,200 --> 00:28:03,570 Because nobody cares what I used in here. 468 00:28:03,570 --> 00:28:06,270 469 00:28:06,270 --> 00:28:08,880 It's a nice example. 470 00:28:08,880 --> 00:28:15,320 On the other hand, I have some variables that are not bound. 471 00:28:15,320 --> 00:28:22,450 For example, that procedure of one argument x which 472 00:28:22,450 --> 00:28:27,390 multiplies x by y. 473 00:28:27,390 --> 00:28:32,370 In this case, y is not bound. 474 00:28:32,370 --> 00:28:36,440 Supposing y had the value three, and z had the value 475 00:28:36,440 --> 00:28:41,420 four, then this procedure would be the thing that 476 00:28:41,420 --> 00:28:44,910 multiplies its argument by three. 477 00:28:44,910 --> 00:28:47,793 If I were to replace every instance of y with z, I would 478 00:28:47,793 --> 00:28:50,190 have a different procedure which multiplies every 479 00:28:50,190 --> 00:28:53,491 argument that's given by four. 480 00:28:53,491 --> 00:28:57,810 And, in fact, we have a name for such a variable. 481 00:28:57,810 --> 00:29:03,680 Here, we say that a variable, v, is free in the expression, 482 00:29:03,680 --> 00:29:06,200 e, if the meaning of the expression, e, is changed by 483 00:29:06,200 --> 00:29:09,355 the uniform replacement of a variable, w, not occurring in 484 00:29:09,355 --> 00:29:13,120 e for every occurrence of v and e. 485 00:29:13,120 --> 00:29:20,680 So that's why this variable over here, 486 00:29:20,680 --> 00:29:22,525 y, is a free variable. 487 00:29:22,525 --> 00:29:29,010 488 00:29:29,010 --> 00:29:33,610 And so free variables in this expression-- 489 00:29:33,610 --> 00:29:38,690 And other examples of that is that procedure of one argument 490 00:29:38,690 --> 00:29:43,160 y, which is just what we had before, which uses that 491 00:29:43,160 --> 00:29:48,130 procedure of one argument x that multiplies x by y-- 492 00:29:48,130 --> 00:29:51,540 493 00:29:51,540 --> 00:29:52,790 use that on three. 494 00:29:52,790 --> 00:29:56,940 495 00:29:56,940 --> 00:30:00,060 This procedure has a free variable 496 00:30:00,060 --> 00:30:01,795 in it which is asterisk. 497 00:30:01,795 --> 00:30:05,010 498 00:30:05,010 --> 00:30:07,170 See, because, if that has a normal meaning of 499 00:30:07,170 --> 00:30:11,360 multiplication, then if I were to replace uniformly all 500 00:30:11,360 --> 00:30:15,770 asterisks with pluses, then the meaning of this expression 501 00:30:15,770 --> 00:30:17,020 would change. 502 00:30:17,020 --> 00:30:19,360 503 00:30:19,360 --> 00:30:22,850 That's what you mean by a free variable. 504 00:30:22,850 --> 00:30:26,350 So, so far you've learned some logician words which describe 505 00:30:26,350 --> 00:30:29,020 the way names are used. 506 00:30:29,020 --> 00:30:32,490 Now, we have to do a little bit more playing around here, 507 00:30:32,490 --> 00:30:35,200 a little bit more. 508 00:30:35,200 --> 00:30:38,600 I want to tell you about the regions are over which 509 00:30:38,600 --> 00:30:39,850 variables are defined. 510 00:30:39,850 --> 00:30:42,270 511 00:30:42,270 --> 00:30:45,260 You see, we've been very informal about this up till 512 00:30:45,260 --> 00:30:48,870 now, and, of course, many of you have probably understood 513 00:30:48,870 --> 00:30:51,960 very clearly or most of you, that the x that's being 514 00:30:51,960 --> 00:30:55,170 declared here is defined only in here. 515 00:30:55,170 --> 00:30:58,250 516 00:30:58,250 --> 00:31:03,580 This x is the defined only in here, and this y is defined 517 00:31:03,580 --> 00:31:04,830 only in here. 518 00:31:04,830 --> 00:31:07,080 519 00:31:07,080 --> 00:31:08,400 We have a name for such an idea. 520 00:31:08,400 --> 00:31:11,660 It's called a scope. 521 00:31:11,660 --> 00:31:14,710 And let me give you another piece of terminology. 522 00:31:14,710 --> 00:31:16,050 It's a long story. 523 00:31:16,050 --> 00:31:18,850 If x is a bound variable in e, then there is a lambda 524 00:31:18,850 --> 00:31:20,560 expression where it is bound. 525 00:31:20,560 --> 00:31:23,956 So the only way you can get a bound variable ultimately is 526 00:31:23,956 --> 00:31:24,970 by lambda expression. 527 00:31:24,970 --> 00:31:28,250 Then you may worry, does define quite an 528 00:31:28,250 --> 00:31:29,670 exception to this? 529 00:31:29,670 --> 00:31:31,840 And it turns out, we could always arrange things so you 530 00:31:31,840 --> 00:31:33,100 don't need any defines. 531 00:31:33,100 --> 00:31:34,070 And we'll see that in a while. 532 00:31:34,070 --> 00:31:36,900 It's a very magical thing. 533 00:31:36,900 --> 00:31:39,000 So define really can go away. 534 00:31:39,000 --> 00:31:42,650 The really, only thing that makes names is lambda . 535 00:31:42,650 --> 00:31:44,350 That's its job. 536 00:31:44,350 --> 00:31:46,865 And what's so amazing about a lot of things is you can 537 00:31:46,865 --> 00:31:48,740 compute with only lambda. 538 00:31:48,740 --> 00:31:53,910 But, in any case, a lambda expression has a place where 539 00:31:53,910 --> 00:31:55,880 it declares a variable. 540 00:31:55,880 --> 00:31:59,970 We call it the formal parameter list or the bound 541 00:31:59,970 --> 00:32:03,290 variable list. We say that the lambda expression binds-- 542 00:32:03,290 --> 00:32:04,970 so it's a verb-- 543 00:32:04,970 --> 00:32:08,730 binds the variables declared in it's found variable list. 544 00:32:08,730 --> 00:32:10,580 In addition, those parts of the expression where the 545 00:32:10,580 --> 00:32:15,680 variable is defined, which was declared by some declaration, 546 00:32:15,680 --> 00:32:20,400 is called the scope of that variable. 547 00:32:20,400 --> 00:32:22,270 So these are scopes. 548 00:32:22,270 --> 00:32:23,630 This is the scope of y. 549 00:32:23,630 --> 00:32:27,140 550 00:32:27,140 --> 00:32:28,690 And this is the scope of x-- 551 00:32:28,690 --> 00:32:33,030 552 00:32:33,030 --> 00:32:34,280 that sort of thing. 553 00:32:34,280 --> 00:32:41,460 554 00:32:41,460 --> 00:32:47,120 OK, well, now we have enough terminology to begin to 555 00:32:47,120 --> 00:32:52,360 understand how to make a new model for computation, because 556 00:32:52,360 --> 00:32:56,060 the key thing going on here is that we destroyed the 557 00:32:56,060 --> 00:32:58,820 substitution model, and we now have to have a model that 558 00:32:58,820 --> 00:33:03,950 represents the names as referring to places. 559 00:33:03,950 --> 00:33:06,460 Because if we are going to change something, then we have 560 00:33:06,460 --> 00:33:09,660 a place where it's stored. 561 00:33:09,660 --> 00:33:14,860 You see, if a name only refers to a value, and if I tried to 562 00:33:14,860 --> 00:33:19,280 change the name's meaning, well, that's not clear. 563 00:33:19,280 --> 00:33:23,570 There's nothing that is the place that that 564 00:33:23,570 --> 00:33:25,030 name referred to. 565 00:33:25,030 --> 00:33:25,960 How am I really saying it? 566 00:33:25,960 --> 00:33:28,220 There is nothing shared among all of the 567 00:33:28,220 --> 00:33:29,840 instances of that name. 568 00:33:29,840 --> 00:33:32,080 And what we really mean, by a name, is that we 569 00:33:32,080 --> 00:33:34,440 fan something out. 570 00:33:34,440 --> 00:33:37,350 We've given something a name, and you have it, and you have 571 00:33:37,350 --> 00:33:39,470 it, because I'm given you a reference to it, and I've 572 00:33:39,470 --> 00:33:41,130 given you a reference to it. 573 00:33:41,130 --> 00:33:43,580 And we'll see a lot about that. 574 00:33:43,580 --> 00:33:45,986 So let me tell you about environments. 575 00:33:45,986 --> 00:33:52,140 I need the overhead projection machine, thank you. 576 00:33:52,140 --> 00:34:01,590 And so here is a bunch of environment structures. 577 00:34:01,590 --> 00:34:06,490 An environment is a way of doing substitutions virtually. 578 00:34:06,490 --> 00:34:09,639 It represents a place where something is stored which is 579 00:34:09,639 --> 00:34:11,409 the substitutions that you haven't done. 580 00:34:11,409 --> 00:34:14,540 581 00:34:14,540 --> 00:34:17,639 It's a place where everything accumulates, where the names 582 00:34:17,639 --> 00:34:20,600 of the variables are associated with the values 583 00:34:20,600 --> 00:34:26,020 they have such that when you say, what dose this name mean, 584 00:34:26,020 --> 00:34:28,090 you look it up in an environment. 585 00:34:28,090 --> 00:34:32,420 So an environment is a function, or a table, or 586 00:34:32,420 --> 00:34:33,290 something like that. 587 00:34:33,290 --> 00:34:35,790 But it's a structured sort of table. 588 00:34:35,790 --> 00:34:37,125 It's made out of things called frames. 589 00:34:37,125 --> 00:34:41,050 590 00:34:41,050 --> 00:34:45,210 Frames are pieces of environment, and they are 591 00:34:45,210 --> 00:34:50,270 chained together, in some nice ways, by what's called parent 592 00:34:50,270 --> 00:34:53,940 links or something like that. 593 00:34:53,940 --> 00:34:57,740 So here, we have an environment structure 594 00:34:57,740 --> 00:35:00,100 consisting of three environments, 595 00:35:00,100 --> 00:35:05,250 basically, a, b, and c. 596 00:35:05,250 --> 00:35:11,480 d is also an environment, but it's the same one, they share. 597 00:35:11,480 --> 00:35:14,550 And that's the essence of assignment. 598 00:35:14,550 --> 00:35:18,120 If I change a variable, a value of a valuable that lives 599 00:35:18,120 --> 00:35:21,950 here, like that one, it should be visible from all places 600 00:35:21,950 --> 00:35:23,750 that you're looking at it from. 601 00:35:23,750 --> 00:35:24,990 Take this one, x. 602 00:35:24,990 --> 00:35:28,560 If I change the x to four, it's 603 00:35:28,560 --> 00:35:30,340 visible from other places. 604 00:35:30,340 --> 00:35:32,270 But I'm not going to worry about that right now. 605 00:35:32,270 --> 00:35:34,590 We're going to talk a lot about that in a little while. 606 00:35:34,590 --> 00:35:36,830 What do we have here? 607 00:35:36,830 --> 00:35:37,990 Well, these are called frames. 608 00:35:37,990 --> 00:35:43,270 Here is a frame, here's a frame, and here's a frame. 609 00:35:43,270 --> 00:35:47,040 a is an environment which consists of the table which is 610 00:35:47,040 --> 00:35:52,570 frame two, followed by the table labeled frame one. 611 00:35:52,570 --> 00:35:59,280 And, in this environment, in say this environment, frame 612 00:35:59,280 --> 00:36:04,150 two, x and y are bound. 613 00:36:04,150 --> 00:36:05,920 They have values. 614 00:36:05,920 --> 00:36:07,290 Sorry, in frame one-- 615 00:36:07,290 --> 00:36:15,340 In frame two, z is bound, and x is bound, and y is bound, 616 00:36:15,340 --> 00:36:18,560 but the value of x that we see, looking from this point 617 00:36:18,560 --> 00:36:20,940 of view, is this x. 618 00:36:20,940 --> 00:36:24,940 It's x is seven, rather than this one which is three. 619 00:36:24,940 --> 00:36:27,660 We say that this x shadows this x. 620 00:36:27,660 --> 00:36:31,070 621 00:36:31,070 --> 00:36:33,320 From environment three-- 622 00:36:33,320 --> 00:36:36,460 from frame three, from environment b, which refers to 623 00:36:36,460 --> 00:36:42,155 frame three, we have variables n and y bound and also x. 624 00:36:42,155 --> 00:36:44,740 625 00:36:44,740 --> 00:36:48,630 This y shadow this one. 626 00:36:48,630 --> 00:36:50,580 So the value, looking from this point of 627 00:36:50,580 --> 00:36:53,410 view, of y is two. 628 00:36:53,410 --> 00:36:54,900 The value for looking from this point of 629 00:36:54,900 --> 00:36:56,500 view and m is one. 630 00:36:56,500 --> 00:36:57,620 And the value, looking from this point of 631 00:36:57,620 --> 00:36:58,870 view, of x is three. 632 00:36:58,870 --> 00:37:02,310 633 00:37:02,310 --> 00:37:04,300 So there we have a very simple environment 634 00:37:04,300 --> 00:37:06,340 structure made out of frames. 635 00:37:06,340 --> 00:37:10,990 These correspond to the applications of procedures. 636 00:37:10,990 --> 00:37:14,390 And we'll see that in a second. 637 00:37:14,390 --> 00:37:16,860 So now I have to make you some other nice little structure 638 00:37:16,860 --> 00:37:18,110 that we build. 639 00:37:18,110 --> 00:37:20,870 640 00:37:20,870 --> 00:37:25,820 Next slide, we see an object, which I'm going to draw 641 00:37:25,820 --> 00:37:27,850 procedures. 642 00:37:27,850 --> 00:37:30,190 This is a procedure. 643 00:37:30,190 --> 00:37:33,150 A procedure is made out of two parts. 644 00:37:33,150 --> 00:37:34,515 It's sort of like a cons. 645 00:37:34,515 --> 00:37:37,210 646 00:37:37,210 --> 00:37:38,460 However, it's the two parts. 647 00:37:38,460 --> 00:37:40,820 648 00:37:40,820 --> 00:37:46,410 The first part refers to some code, something that can be 649 00:37:46,410 --> 00:37:48,940 executed, a set of instructions, if you will. 650 00:37:48,940 --> 00:37:50,750 You can think of it that way. 651 00:37:50,750 --> 00:37:53,830 And the second part is the environment. 652 00:37:53,830 --> 00:37:57,250 The procedure is the whole thing. 653 00:37:57,250 --> 00:38:01,420 And we're going to have to use this to capture the values of 654 00:38:01,420 --> 00:38:06,250 the free variables that occur in the procedure. 655 00:38:06,250 --> 00:38:08,760 If a variable occurs in the procedure it's either bound in 656 00:38:08,760 --> 00:38:11,170 that procedure or free. 657 00:38:11,170 --> 00:38:16,930 If it's bound, then the value will somehow be easy to find. 658 00:38:16,930 --> 00:38:19,070 It will be in some easy environment to get at. 659 00:38:19,070 --> 00:38:21,800 If it's free, we're going to have to have something that 660 00:38:21,800 --> 00:38:24,010 goes with the procedure that says where we'll go 661 00:38:24,010 --> 00:38:27,100 look for its value. 662 00:38:27,100 --> 00:38:32,290 And the reasons why are not obvious yet, but will be soon. 663 00:38:32,290 --> 00:38:33,760 So here's a procedure object. 664 00:38:33,760 --> 00:38:40,200 It's a composite object consisting of a piece of code 665 00:38:40,200 --> 00:38:42,750 and a environment structure. 666 00:38:42,750 --> 00:38:46,400 Now I will tell you the new rules, the complete new rules, 667 00:38:46,400 --> 00:38:47,650 for evaluation. 668 00:38:47,650 --> 00:38:50,690 669 00:38:50,690 --> 00:38:53,250 The first rule is-- there's only two of them. 670 00:38:53,250 --> 00:38:57,250 These correspond to the substitution model rules. 671 00:38:57,250 --> 00:39:00,830 And the first one has to do with how do you apply a 672 00:39:00,830 --> 00:39:02,570 procedure to its arguments? 673 00:39:02,570 --> 00:39:05,610 674 00:39:05,610 --> 00:39:08,890 And a procedural object is applied to a set of arguments 675 00:39:08,890 --> 00:39:11,270 by constructing a new frame. 676 00:39:11,270 --> 00:39:13,860 That frame will contain the mapping of the former 677 00:39:13,860 --> 00:39:16,540 parameters to the actual parameters of the arguments 678 00:39:16,540 --> 00:39:21,490 that were supplied in the call. 679 00:39:21,490 --> 00:39:25,320 As you know, when we make up a call to a procedure like 680 00:39:25,320 --> 00:39:28,670 lambda x times x y, and we call that with the argument 681 00:39:28,670 --> 00:39:31,280 three, then we're going to need some 682 00:39:31,280 --> 00:39:34,290 mapping of x to three. 683 00:39:34,290 --> 00:39:38,490 It's the same thing as later substituting, if you will, the 684 00:39:38,490 --> 00:39:41,990 three for the x in the old model. 685 00:39:41,990 --> 00:39:45,160 So I'm going to build a frame which contains x equals three 686 00:39:45,160 --> 00:39:46,550 as the information in that frame. 687 00:39:46,550 --> 00:39:49,230 688 00:39:49,230 --> 00:39:52,640 Now, the body of the procedure will then have to be evaluated 689 00:39:52,640 --> 00:39:54,170 which is this. 690 00:39:54,170 --> 00:40:04,710 I will be evaluated in an environment which is 691 00:40:04,710 --> 00:40:08,780 constructed by adjoining the new frame that we just made to 692 00:40:08,780 --> 00:40:10,450 the environment which was part of the 693 00:40:10,450 --> 00:40:13,100 procedure that we applied. 694 00:40:13,100 --> 00:40:15,670 So I'm going to make a little example of that here. 695 00:40:15,670 --> 00:40:19,220 696 00:40:19,220 --> 00:40:25,110 Supposing I have some environment. 697 00:40:25,110 --> 00:40:27,980 Here's a frame which represents it. 698 00:40:27,980 --> 00:40:30,190 And some procedure-- which I'm going to draw with circles 699 00:40:30,190 --> 00:40:33,370 here because it's easier than little triangles-- 700 00:40:33,370 --> 00:40:38,940 Sorry, those are rhombuses, rhomboidal little pieces of 701 00:40:38,940 --> 00:40:42,710 fruit jelly or something. 702 00:40:42,710 --> 00:40:45,960 So here's a procedure which takes this environment. 703 00:40:45,960 --> 00:40:48,920 And the procedure has a piece of code, which is a lambda 704 00:40:48,920 --> 00:40:55,600 expression, which binds x and y and then executes an 705 00:40:55,600 --> 00:40:58,010 expression, e. 706 00:40:58,010 --> 00:40:59,345 And this is the procedure. 707 00:40:59,345 --> 00:41:01,470 We'll call it p. 708 00:41:01,470 --> 00:41:06,490 I wish to apply that procedure to three and four. 709 00:41:06,490 --> 00:41:09,790 So I want to do p of three and four. 710 00:41:09,790 --> 00:41:13,210 What I'm going to do, of course, is make a new frame. 711 00:41:13,210 --> 00:41:18,630 I build a frame which contains x equals three, 712 00:41:18,630 --> 00:41:21,740 and y equals four. 713 00:41:21,740 --> 00:41:27,680 I'm going to connect that frame to this frame over here. 714 00:41:27,680 --> 00:41:31,940 And then this environment, with I will call b, is the 715 00:41:31,940 --> 00:41:34,880 environment in which I will evaluate the body of e. 716 00:41:34,880 --> 00:41:39,940 717 00:41:39,940 --> 00:41:46,890 Now, e may contain references to x and y and other things. 718 00:41:46,890 --> 00:41:50,790 x and y will have values right here. 719 00:41:50,790 --> 00:41:55,040 Other things will have their values here. 720 00:41:55,040 --> 00:41:56,920 How do we get this frame? 721 00:41:56,920 --> 00:42:00,110 That we do by the construction of procedures which is the 722 00:42:00,110 --> 00:42:01,980 other rule. 723 00:42:01,980 --> 00:42:05,500 And I think that's the next slide. 724 00:42:05,500 --> 00:42:10,000 Rule two, when a lambda expression is evaluated, 725 00:42:10,000 --> 00:42:11,510 relative to a particular environment-- 726 00:42:11,510 --> 00:42:14,150 727 00:42:14,150 --> 00:42:17,470 See, the way I get a procedure is by evaluating the lambda 728 00:42:17,470 --> 00:42:18,300 expression. 729 00:42:18,300 --> 00:42:20,110 Here's a lambda expression. 730 00:42:20,110 --> 00:42:22,880 By evaluating it, I get a procedure which I 731 00:42:22,880 --> 00:42:25,170 can apply to three. 732 00:42:25,170 --> 00:42:28,710 Now this lambda expression is evaluated in an environment 733 00:42:28,710 --> 00:42:31,820 where y is defined. 734 00:42:31,820 --> 00:42:33,760 And I want the body of this which contains a 735 00:42:33,760 --> 00:42:36,680 free version of y. 736 00:42:36,680 --> 00:42:41,790 y is free in here, it's bound over the whole thing, but it's 737 00:42:41,790 --> 00:42:43,350 free over here. 738 00:42:43,350 --> 00:42:47,440 I want that y to be this one. 739 00:42:47,440 --> 00:42:53,150 I evaluate this body of this procedure in the environment 740 00:42:53,150 --> 00:42:55,470 where y was created. 741 00:42:55,470 --> 00:42:57,800 That's this kind of thing, because that was done by 742 00:42:57,800 --> 00:42:59,140 application. 743 00:42:59,140 --> 00:43:03,490 Now, if I ever want to look up the value of y, I have to know 744 00:43:03,490 --> 00:43:04,370 where it is. 745 00:43:04,370 --> 00:43:07,440 Therefore, this procedural was created, the creation of the 746 00:43:07,440 --> 00:43:09,530 procedure which is the result of evaluating that lambda 747 00:43:09,530 --> 00:43:14,480 expression had better capture a pointer or remember the 748 00:43:14,480 --> 00:43:18,110 frame in which y was bound. 749 00:43:18,110 --> 00:43:22,100 So that's what this rule is telling us. 750 00:43:22,100 --> 00:43:28,610 So, for example, if I happen to be evaluating a lambda 751 00:43:28,610 --> 00:43:37,370 expression, lambda expression in e, lambda of say, x and y, 752 00:43:37,370 --> 00:43:43,020 let's call it g in e, evaluating that. 753 00:43:43,020 --> 00:43:47,190 Well, all that means is I now construct a procedure object. 754 00:43:47,190 --> 00:43:48,990 e is some environment. 755 00:43:48,990 --> 00:43:51,920 e is something which has a pointer to it. 756 00:43:51,920 --> 00:43:56,120 I construct a procedure object that points up to that 757 00:43:56,120 --> 00:44:01,830 environment, where the code of that is a lambda expression or 758 00:44:01,830 --> 00:44:03,180 whatever that translates into. 759 00:44:03,180 --> 00:44:06,330 760 00:44:06,330 --> 00:44:07,580 And this is the procedure. 761 00:44:07,580 --> 00:44:12,380 762 00:44:12,380 --> 00:44:17,640 So this produces for me-- this object here, this environment 763 00:44:17,640 --> 00:44:21,140 pointer, captures the place where this lambda expression 764 00:44:21,140 --> 00:44:25,820 was evaluated, where the definition was used, where the 765 00:44:25,820 --> 00:44:26,900 definition was used to make a 766 00:44:26,900 --> 00:44:32,950 procedure, to make the procedure. 767 00:44:32,950 --> 00:44:35,190 So it picks up the environment from the place where that 768 00:44:35,190 --> 00:44:39,680 procedure was defined, stores it in the procedure itself, 769 00:44:39,680 --> 00:44:42,210 and then when the procedure is used, the environment where it 770 00:44:42,210 --> 00:44:44,990 was defined is extended with the new frame. 771 00:44:44,990 --> 00:44:48,740 772 00:44:48,740 --> 00:44:51,170 So this gives us a locus for putting where a 773 00:44:51,170 --> 00:44:53,090 variable has a value. 774 00:44:53,090 --> 00:44:55,700 And, for example, if there are lots of guys pointing in at 775 00:44:55,700 --> 00:45:01,430 that environment, then they share that place. 776 00:45:01,430 --> 00:45:03,810 And we'll see more of that shortly. 777 00:45:03,810 --> 00:45:08,940 Well, now you have a new model for understanding the 778 00:45:08,940 --> 00:45:12,420 execution of programs. I suppose I'll take questions 779 00:45:12,420 --> 00:45:14,970 now, and then we'll go on and use that for something. 780 00:45:14,970 --> 00:45:17,802 781 00:45:17,802 --> 00:45:21,870 AUDIENCE: Is it right to say then, the environment is that 782 00:45:21,870 --> 00:45:23,695 linked chain of frames-- 783 00:45:23,695 --> 00:45:24,580 PROFESSOR: That's right. 784 00:45:24,580 --> 00:45:25,650 AUDIENCE: starting with-- 785 00:45:25,650 --> 00:45:27,076 working all the way back? 786 00:45:27,076 --> 00:45:29,400 PROFESSOR: Yes, the environment is a sequence of 787 00:45:29,400 --> 00:45:32,470 frames linked together. 788 00:45:32,470 --> 00:45:34,700 And the way I like to think about it, it's the pointer to 789 00:45:34,700 --> 00:45:38,150 the first one, because once you've got that 790 00:45:38,150 --> 00:45:39,400 you've got them all. 791 00:45:39,400 --> 00:45:44,080 792 00:45:44,080 --> 00:45:44,995 Anybody else? 793 00:45:44,995 --> 00:45:47,800 AUDIENCE: Is it possible to evaluate a procedure or to 794 00:45:47,800 --> 00:45:49,300 define a procedure in two different environments such 795 00:45:49,300 --> 00:45:51,580 that it will behave differently, and 796 00:45:51,580 --> 00:45:52,140 have pointers to both-- 797 00:45:52,140 --> 00:45:53,600 PROFESSOR: Oh, yes. 798 00:45:53,600 --> 00:45:55,260 The same procedure is not going to have two different 799 00:45:55,260 --> 00:45:57,290 environments. 800 00:45:57,290 --> 00:46:01,895 The same code, the same lambda expression can be evaluated in 801 00:46:01,895 --> 00:46:03,430 two environments producing two different procedures. 802 00:46:03,430 --> 00:46:06,220 803 00:46:06,220 --> 00:46:07,140 Each procedure-- 804 00:46:07,140 --> 00:46:08,690 AUDIENCE: Their definition has the same name. 805 00:46:08,690 --> 00:46:09,170 Their operation-- 806 00:46:09,170 --> 00:46:11,070 PROFESSOR: The definition is written the same, with the 807 00:46:11,070 --> 00:46:12,570 same characters. 808 00:46:12,570 --> 00:46:16,700 I can evaluate that set of characters, whatever, that 809 00:46:16,700 --> 00:46:19,530 list structure that defines, that is the textual 810 00:46:19,530 --> 00:46:21,340 representation. 811 00:46:21,340 --> 00:46:23,650 I can evaluate that in two different environments 812 00:46:23,650 --> 00:46:25,650 producing two different procedures. 813 00:46:25,650 --> 00:46:31,700 Each of those procedures has its own local sets of 814 00:46:31,700 --> 00:46:33,490 variables, and we'll see that right now. 815 00:46:33,490 --> 00:46:36,770 816 00:46:36,770 --> 00:46:38,020 Anybody else? 817 00:46:38,020 --> 00:46:42,670 818 00:46:42,670 --> 00:46:43,280 OK, thank you. 819 00:46:43,280 --> 00:46:44,530 Let's take a break. 820 00:46:44,530 --> 00:46:48,750 821 00:46:48,750 --> 00:47:22,870 [MUSIC PLAYING] 822 00:47:22,870 --> 00:47:26,670 Well, now I've done this terrible thing to you. 823 00:47:26,670 --> 00:47:34,600 I've introduced a very complicated thing, assignment, 824 00:47:34,600 --> 00:47:36,680 which destroys most of the interesting mathematical 825 00:47:36,680 --> 00:47:43,270 properties of our programs. Why should I have done this? 826 00:47:43,270 --> 00:47:46,590 What possible good could this do? 827 00:47:46,590 --> 00:47:52,490 Clearly not a nice thing, so I better have a good excuse. 828 00:47:52,490 --> 00:47:56,150 Well, let's do a little bit of playing, first of all, with 829 00:47:56,150 --> 00:47:58,870 some very interesting programs that have assignment. 830 00:47:58,870 --> 00:48:02,000 Understand something special about them that makes them 831 00:48:02,000 --> 00:48:04,820 somewhat valuable. 832 00:48:04,820 --> 00:48:08,110 Start with a very simple program which I'm going to 833 00:48:08,110 --> 00:48:10,670 call make-counter. 834 00:48:10,670 --> 00:48:26,480 I'm going to define make-counter to be a procedure 835 00:48:26,480 --> 00:48:31,280 of one argument n which returns as its value a 836 00:48:31,280 --> 00:48:34,390 procedure of no arguments-- 837 00:48:34,390 --> 00:48:36,840 a procedure that produces a procedure-- 838 00:48:36,840 --> 00:48:48,600 which sets n to the increment of n and returns 839 00:48:48,600 --> 00:48:50,120 that value of n. 840 00:48:50,120 --> 00:48:55,520 841 00:48:55,520 --> 00:48:57,560 Now we're going to investigate the behavior of this. 842 00:48:57,560 --> 00:48:59,840 It's a sort of interesting thing. 843 00:48:59,840 --> 00:49:02,150 In order to investigate the behavior, I have to make an 844 00:49:02,150 --> 00:49:05,130 environment model, because we can't understand 845 00:49:05,130 --> 00:49:06,380 this any other way. 846 00:49:06,380 --> 00:49:08,630 847 00:49:08,630 --> 00:49:10,040 So let's just do that. 848 00:49:10,040 --> 00:49:13,005 We start out with some sort of-- 849 00:49:13,005 --> 00:49:15,270 let's say there is a global environment that the machine 850 00:49:15,270 --> 00:49:16,240 is born with. 851 00:49:16,240 --> 00:49:19,720 Global we'll call it. 852 00:49:19,720 --> 00:49:24,530 And it's going to have in it a bunch of initial things. 853 00:49:24,530 --> 00:49:25,820 We all know what it's got. 854 00:49:25,820 --> 00:49:32,930 It's got things in it like say, plus, and times, and 855 00:49:32,930 --> 00:49:39,330 quotient, and difference, and CAR, and et 856 00:49:39,330 --> 00:49:42,960 cetera, lots of things. 857 00:49:42,960 --> 00:49:46,160 I don't know what they are, some various squiggles that 858 00:49:46,160 --> 00:49:51,290 are the things the machine is born with. 859 00:49:51,290 --> 00:49:56,350 And by doing the definition here, what I plan to do-- 860 00:49:56,350 --> 00:49:57,390 Well, what am I doing? 861 00:49:57,390 --> 00:49:59,780 I'm doing this relative to the global environment. 862 00:49:59,780 --> 00:50:03,580 So here's my environment pointer. 863 00:50:03,580 --> 00:50:05,980 In order to do that I have to evaluate this lambda 864 00:50:05,980 --> 00:50:08,270 expression. 865 00:50:08,270 --> 00:50:11,490 That means I make a procedure object. 866 00:50:11,490 --> 00:50:13,190 So I'm going to make a procedure object here. 867 00:50:13,190 --> 00:50:17,400 868 00:50:17,400 --> 00:50:21,430 And the procedure object has, as the place it's defined, the 869 00:50:21,430 --> 00:50:23,820 global environment. 870 00:50:23,820 --> 00:50:29,880 The procedure object contains some code that represents a 871 00:50:29,880 --> 00:50:33,470 procedure of one argument n which returns a procedure of 872 00:50:33,470 --> 00:50:35,340 no arguments which does something. 873 00:50:35,340 --> 00:50:38,320 874 00:50:38,320 --> 00:50:44,580 And the define is a way of changing this environment, so 875 00:50:44,580 --> 00:50:53,230 that I now add to it a make-counter, a special rule 876 00:50:53,230 --> 00:50:55,470 for the special thing defined. 877 00:50:55,470 --> 00:50:59,810 But what that is, is it gives me that 878 00:50:59,810 --> 00:51:03,840 pointer to that procedure. 879 00:51:03,840 --> 00:51:06,370 So now the global environment contains make-counter as well. 880 00:51:06,370 --> 00:51:09,330 881 00:51:09,330 --> 00:51:11,800 Now, we're going to do some operations. 882 00:51:11,800 --> 00:51:14,596 I'm going to use this to make some counters. 883 00:51:14,596 --> 00:51:17,140 We'll see what a counter is. 884 00:51:17,140 --> 00:51:26,700 So let's define c1 to be a counter beginning at 0. 885 00:51:26,700 --> 00:51:35,440 886 00:51:35,440 --> 00:51:39,660 Well, we know how to do this now, according to the model. 887 00:51:39,660 --> 00:51:43,340 I have to evaluate the expression make-counter in the 888 00:51:43,340 --> 00:51:47,900 global environment, make-counter of 0. 889 00:51:47,900 --> 00:51:50,785 Well, I look up make-counter and see that it's a procedure. 890 00:51:50,785 --> 00:51:53,630 891 00:51:53,630 --> 00:51:56,010 I'm going to have to apply that procedure. 892 00:51:56,010 --> 00:51:59,820 The way I apply the procedure is by constructing a frame. 893 00:51:59,820 --> 00:52:02,400 894 00:52:02,400 --> 00:52:12,030 So I construct a frame which has a value for n in it which 895 00:52:12,030 --> 00:52:16,850 is 0, and the parent environment is the one which 896 00:52:16,850 --> 00:52:18,810 is the environment of definition of make-counter. 897 00:52:18,810 --> 00:52:23,890 898 00:52:23,890 --> 00:52:28,400 So I've made an environment by applying make-counter to 0. 899 00:52:28,400 --> 00:52:31,580 900 00:52:31,580 --> 00:52:34,700 Now, I have to evaluate the body of make-counter, which is 901 00:52:34,700 --> 00:52:37,455 this lambda expression, in that environment. 902 00:52:37,455 --> 00:52:40,730 903 00:52:40,730 --> 00:52:43,770 Well evaluating this body, this body is a lambda 904 00:52:43,770 --> 00:52:46,360 expression. 905 00:52:46,360 --> 00:52:49,570 Evaluate a lambda expression means make a procedure object. 906 00:52:49,570 --> 00:52:50,820 So I'm going to make a procedure object. 907 00:52:50,820 --> 00:52:56,840 908 00:52:56,840 --> 00:52:59,620 And that procedure object has the environment it was defined 909 00:52:59,620 --> 00:53:07,656 in being that, where n was defined to be 0. 910 00:53:07,656 --> 00:53:11,370 And it has some code, which is the procedure of no arguments 911 00:53:11,370 --> 00:53:17,622 which does something, that sets something, and returns n. 912 00:53:17,622 --> 00:53:22,680 And this thing is going to be the object, which in the 913 00:53:22,680 --> 00:53:26,020 global environment, will have the name c1. 914 00:53:26,020 --> 00:53:32,625 So we construct a name here, c1, and say that equals that. 915 00:53:32,625 --> 00:53:35,560 916 00:53:35,560 --> 00:53:50,790 Now, but also make another counter, c2 to be make-counter 917 00:53:50,790 --> 00:53:53,868 say, starting with 10. 918 00:53:53,868 --> 00:53:57,270 Then I do essentially the same thing. 919 00:53:57,270 --> 00:53:59,910 I apply the make-counter procedure, which I got from 920 00:53:59,910 --> 00:54:05,690 here, to make another frame with n being 10. 921 00:54:05,690 --> 00:54:10,050 That frame has the global environment as its parent. 922 00:54:10,050 --> 00:54:16,750 I then construct a procedure which has that as it's frame 923 00:54:16,750 --> 00:54:18,000 of definition. 924 00:54:18,000 --> 00:54:20,440 925 00:54:20,440 --> 00:54:23,240 The code of it is the procedure of no arguments 926 00:54:23,240 --> 00:54:25,390 which does something. 927 00:54:25,390 --> 00:54:28,700 And it does a set, and so on. 928 00:54:28,700 --> 00:54:31,510 And n comes out. 929 00:54:31,510 --> 00:54:36,950 And c2 is this. 930 00:54:36,950 --> 00:54:38,780 Well, you're already beginning to see something fairly 931 00:54:38,780 --> 00:54:40,200 interesting. 932 00:54:40,200 --> 00:54:42,880 There are two n's here. 933 00:54:42,880 --> 00:54:46,330 They are not one n. 934 00:54:46,330 --> 00:54:49,310 Each time I called make-counter, I made another 935 00:54:49,310 --> 00:54:52,520 instance of n. 936 00:54:52,520 --> 00:54:54,370 These are distinct and separate from each other. 937 00:54:54,370 --> 00:54:57,880 938 00:54:57,880 --> 00:55:00,783 Now, let's do some execution, use those counters. 939 00:55:00,783 --> 00:55:02,735 I'm going to use those counters. 940 00:55:02,735 --> 00:55:05,990 941 00:55:05,990 --> 00:55:15,900 Well, what happens if I say, c1 at this point? 942 00:55:15,900 --> 00:55:18,420 Well, I go over here, and I say, oh 943 00:55:18,420 --> 00:55:20,840 yes, c1 is a procedure. 944 00:55:20,840 --> 00:55:23,490 I'm going to call this procedure on no arguments, but 945 00:55:23,490 --> 00:55:25,060 it has no parameters. 946 00:55:25,060 --> 00:55:27,020 That's right. 947 00:55:27,020 --> 00:55:28,080 What's its body? 948 00:55:28,080 --> 00:55:29,776 Well, I have to look over here, because I 949 00:55:29,776 --> 00:55:30,130 didn't write it down. 950 00:55:30,130 --> 00:55:39,050 It said, set n to one plus n and return n, increment n. 951 00:55:39,050 --> 00:55:42,970 Well, the n it sees is this one. 952 00:55:42,970 --> 00:55:45,490 So I increment that n. 953 00:55:45,490 --> 00:55:50,040 That becomes one, and I return the value one. 954 00:55:50,040 --> 00:55:53,050 955 00:55:53,050 --> 00:55:58,220 Supposing I then called c2. 956 00:55:58,220 --> 00:55:59,820 Well, what do I do? 957 00:55:59,820 --> 00:56:03,600 I say c2 is this procedure which does the same thing, but 958 00:56:03,600 --> 00:56:05,450 here's the n. 959 00:56:05,450 --> 00:56:11,140 It becomes 11. 960 00:56:11,140 --> 00:56:15,980 And so I have an 11 which is the value. 961 00:56:15,980 --> 00:56:18,130 I then can say, let's try c1 again. 962 00:56:18,130 --> 00:56:21,580 963 00:56:21,580 --> 00:56:29,660 c1 is this, that's two, so the answer is two. 964 00:56:29,660 --> 00:56:36,560 And c2 gives me a 12 by the same method, by walking down 965 00:56:36,560 --> 00:56:38,730 here looking at that and saying, here's the n, I'm 966 00:56:38,730 --> 00:56:39,980 incrementing. 967 00:56:39,980 --> 00:56:41,630 968 00:56:41,630 --> 00:56:44,920 So what I have are computational objects. 969 00:56:44,920 --> 00:56:49,780 There are two counters, each with its own 970 00:56:49,780 --> 00:56:51,060 independent local state. 971 00:56:51,060 --> 00:56:55,540 972 00:56:55,540 --> 00:56:56,650 Let's talk about this a little. 973 00:56:56,650 --> 00:56:58,510 This is a strange thing. 974 00:56:58,510 --> 00:57:01,270 975 00:57:01,270 --> 00:57:04,140 What's an object? 976 00:57:04,140 --> 00:57:07,560 It's not at all obvious what an object is. 977 00:57:07,560 --> 00:57:11,720 We like to think about objects, because it's 978 00:57:11,720 --> 00:57:14,800 economical to think that way. 979 00:57:14,800 --> 00:57:18,670 It's an intellectual economy. 980 00:57:18,670 --> 00:57:21,120 I am an object. 981 00:57:21,120 --> 00:57:23,610 You are an object. 982 00:57:23,610 --> 00:57:25,030 We are not the same object. 983 00:57:25,030 --> 00:57:27,600 984 00:57:27,600 --> 00:57:32,315 I can divide the world into two parts, me and you, and 985 00:57:32,315 --> 00:57:36,600 there's other things as well, such that most of the things I 986 00:57:36,600 --> 00:57:41,410 might want to discuss about my workings do not involve you, 987 00:57:41,410 --> 00:57:43,790 and most of the things I want to discuss about your workings 988 00:57:43,790 --> 00:57:45,750 don't involve me. 989 00:57:45,750 --> 00:57:50,990 I have a blood pressure, a temperature, a respiration 990 00:57:50,990 --> 00:57:56,900 rate, a certain amount of sugar in my blood, and 991 00:57:56,900 --> 00:57:59,400 numerous, thousands, of state variables-- millions actually, 992 00:57:59,400 --> 00:58:01,030 or I don't know how many-- 993 00:58:01,030 --> 00:58:03,040 huge numbers of state variables in the physical 994 00:58:03,040 --> 00:58:09,240 sense which represent the state of me as a particle, and 995 00:58:09,240 --> 00:58:12,770 you have gazillions of them as well. 996 00:58:12,770 --> 00:58:17,290 And most of mine are uncoupled to most of yours. 997 00:58:17,290 --> 00:58:21,000 So we can compute the properties of me without 998 00:58:21,000 --> 00:58:23,940 worrying too much about the properties of you. 999 00:58:23,940 --> 00:58:26,310 If we had to work about both of us together, than the 1000 00:58:26,310 --> 00:58:28,460 number of states that we have to consider is the product of 1001 00:58:28,460 --> 00:58:29,840 the number of states you have and the number of states I 1002 00:58:29,840 --> 00:58:32,760 have. But this way it's almost a sum. 1003 00:58:32,760 --> 00:58:36,110 Now, indeed there are forces that couple us. 1004 00:58:36,110 --> 00:58:38,420 I'm talking to you and your state changes. 1005 00:58:38,420 --> 00:58:41,680 I'm looking at you and my state changes. 1006 00:58:41,680 --> 00:58:45,010 Some of my state variables, a very few of them, therefore, 1007 00:58:45,010 --> 00:58:46,190 are coupled to yours. 1008 00:58:46,190 --> 00:58:48,470 If you were to suddenly yell very loud, my blood pressure 1009 00:58:48,470 --> 00:58:49,720 would go up. 1010 00:58:49,720 --> 00:58:54,320 1011 00:58:54,320 --> 00:58:57,590 However, and it may not be always appropriate to think 1012 00:58:57,590 --> 00:59:00,360 about the world as being made out of independent states and 1013 00:59:00,360 --> 00:59:02,260 independent particles. 1014 00:59:02,260 --> 00:59:05,350 Lots of the bugs that occur in things like quantum mechanics, 1015 00:59:05,350 --> 00:59:07,660 or the bugs in our minds that occur when we think about 1016 00:59:07,660 --> 00:59:09,840 things like quantum mechanics, are due the fact that we are 1017 00:59:09,840 --> 00:59:11,910 trying to think about things being broken up into 1018 00:59:11,910 --> 00:59:15,880 independent pieces, when in fact there's more coupling 1019 00:59:15,880 --> 00:59:19,750 than we see on the surface, or that we want to believe in, 1020 00:59:19,750 --> 00:59:22,300 because we want to compute efficiently and effectively. 1021 00:59:22,300 --> 00:59:23,780 We've been trained to think that way. 1022 00:59:23,780 --> 00:59:29,336 1023 00:59:29,336 --> 00:59:31,440 Well, let's see. 1024 00:59:31,440 --> 00:59:35,140 How would we know if we had objects at all? 1025 00:59:35,140 --> 00:59:37,690 How can we tell if we have objects? 1026 00:59:37,690 --> 00:59:41,770 Consider some possible optical illusions. 1027 00:59:41,770 --> 00:59:44,805 This could be done. 1028 00:59:44,805 --> 00:59:47,970 These pieces of chalk are not appropriately identical, but 1029 00:59:47,970 --> 00:59:49,520 supposing you couldn't tell the difference of them by 1030 00:59:49,520 --> 00:59:52,130 looking at them. 1031 00:59:52,130 --> 00:59:54,290 Well, there's a possibility that this all a game I'm 1032 00:59:54,290 --> 00:59:55,725 playing with mirrors. 1033 00:59:55,725 --> 00:59:59,690 It's really the same piece of chalk, but you're 1034 00:59:59,690 --> 01:00:01,660 seeing two of them. 1035 01:00:01,660 --> 01:00:05,160 How would you know if you're seeing one or two? 1036 01:00:05,160 --> 01:00:07,430 Well, there's only one way I know. 1037 01:00:07,430 --> 01:00:10,110 You grab one of them and change it and see if the other 1038 01:00:10,110 --> 01:00:11,360 one changed. 1039 01:00:11,360 --> 01:00:13,580 1040 01:00:13,580 --> 01:00:16,180 And it didn't, so there's two of them. 1041 01:00:16,180 --> 01:00:19,070 1042 01:00:19,070 --> 01:00:20,890 And, on the other hand, there is some other screwy 1043 01:00:20,890 --> 01:00:22,580 properties of things like that. 1044 01:00:22,580 --> 01:00:25,040 Like, how do we know if something changed? 1045 01:00:25,040 --> 01:00:28,760 We have to look at it before and after the change. 1046 01:00:28,760 --> 01:00:32,200 The change is an assignment, it's a moment in time. 1047 01:00:32,200 --> 01:00:34,120 But that means we have to know it was the same one that we're 1048 01:00:34,120 --> 01:00:36,540 looking at. 1049 01:00:36,540 --> 01:00:39,270 So some very strange, and unusual, and obscure, and-- 1050 01:00:39,270 --> 01:00:42,950 I don't understand the problems associated with 1051 01:00:42,950 --> 01:00:47,380 assignment, and change, and objects. 1052 01:00:47,380 --> 01:00:51,420 These could get very, very bad. 1053 01:00:51,420 --> 01:00:56,250 For example, here I am, I am a particular person, a 1054 01:00:56,250 --> 01:00:57,650 particular object. 1055 01:00:57,650 --> 01:01:02,430 Now, I can take out my knife, and cut my fingernail. 1056 01:01:02,430 --> 01:01:06,030 A piece of my fingernail has fallen off onto the table. 1057 01:01:06,030 --> 01:01:11,200 I believe I am the same person I was a second ago, but I'm 1058 01:01:11,200 --> 01:01:14,490 not physically the same in the slightest. 1059 01:01:14,490 --> 01:01:15,620 I have changed. 1060 01:01:15,620 --> 01:01:18,180 Why am I the same? 1061 01:01:18,180 --> 01:01:21,070 What is the identity of me? 1062 01:01:21,070 --> 01:01:22,320 I don't know. 1063 01:01:22,320 --> 01:01:25,170 1064 01:01:25,170 --> 01:01:29,770 Except for the fact that I have some sort of identity. 1065 01:01:29,770 --> 01:01:34,770 And so, I think by introducing assignment and objects, we 1066 01:01:34,770 --> 01:01:37,670 have opened ourselves up to all the horrible questions of 1067 01:01:37,670 --> 01:01:40,490 philosophy that have been plaguing philosophers for some 1068 01:01:40,490 --> 01:01:43,510 thousands of years about this sort of thing. 1069 01:01:43,510 --> 01:01:45,880 It's why mathematics is a lot cleaner. 1070 01:01:45,880 --> 01:01:49,590 Let's look at the best things I know to say about actions 1071 01:01:49,590 --> 01:01:50,840 and identity. 1072 01:01:50,840 --> 01:01:52,500 1073 01:01:52,500 --> 01:01:56,050 We say that an action, a, had an effect on an object, x, or 1074 01:01:56,050 --> 01:01:59,340 equivalently, that x was changed by a, if some 1075 01:01:59,340 --> 01:02:02,410 property, p, which was true of x before a, became 1076 01:02:02,410 --> 01:02:05,100 false of x after a. 1077 01:02:05,100 --> 01:02:07,750 Let's test. It still means I have to have the 1078 01:02:07,750 --> 01:02:10,950 x before and after. 1079 01:02:10,950 --> 01:02:13,810 Or, the other way of saying this is, we say that two 1080 01:02:13,810 --> 01:02:15,460 objects x and y are the same for any action which has an 1081 01:02:15,460 --> 01:02:19,580 effect on x has the same effect on y. 1082 01:02:19,580 --> 01:02:22,230 However, objects are very useful, as I said, for 1083 01:02:22,230 --> 01:02:24,650 intellectual economy. 1084 01:02:24,650 --> 01:02:28,350 One of the things that's incredibly useful about them, 1085 01:02:28,350 --> 01:02:32,980 is that the world is, we like to think about, made out of 1086 01:02:32,980 --> 01:02:35,050 independent objects with independent local state. 1087 01:02:35,050 --> 01:02:36,430 We like to think that way, although it 1088 01:02:36,430 --> 01:02:39,730 isn't completely true. 1089 01:02:39,730 --> 01:02:42,470 When we want to make very complicated programs that deal 1090 01:02:42,470 --> 01:02:45,400 with such a world, if we want those programs to be 1091 01:02:45,400 --> 01:02:49,070 understandable by us and also to be changeable, so that if 1092 01:02:49,070 --> 01:02:51,390 we change the world we change the program only a little bit, 1093 01:02:51,390 --> 01:02:53,810 then we want there to be connections, isomorphism, 1094 01:02:53,810 --> 01:02:56,130 between the objects in the world and the objects in our 1095 01:02:56,130 --> 01:02:58,720 mental model. 1096 01:02:58,720 --> 01:03:00,960 The modularity of the world can give us the modularity in 1097 01:03:00,960 --> 01:03:02,400 our programming. 1098 01:03:02,400 --> 01:03:04,590 So we invent things called object-oriented programming 1099 01:03:04,590 --> 01:03:09,950 and things like that to provide us with that power. 1100 01:03:09,950 --> 01:03:10,990 But it's even easier. 1101 01:03:10,990 --> 01:03:12,310 Let's play a little game. 1102 01:03:12,310 --> 01:03:15,110 I want to play a little game, show you an even easier 1103 01:03:15,110 --> 01:03:19,610 example of where modularity can be enhanced by using an 1104 01:03:19,610 --> 01:03:22,960 assignment statement, judiciously. 1105 01:03:22,960 --> 01:03:26,280 One thing I want to enforce and impress on you, is don't 1106 01:03:26,280 --> 01:03:28,280 use assignment statements the way you use it in FORTRAN or 1107 01:03:28,280 --> 01:03:30,930 Basic or something or Pascal, to do the things you don't 1108 01:03:30,930 --> 01:03:32,180 have to do with it. 1109 01:03:32,180 --> 01:03:34,200 1110 01:03:34,200 --> 01:03:37,010 It's not the right way to think for most things. 1111 01:03:37,010 --> 01:03:39,810 Sometimes it's essential, or maybe it's essential. 1112 01:03:39,810 --> 01:03:42,320 We'll see more about that too. 1113 01:03:42,320 --> 01:03:44,330 OK, let me show you a fun game here. 1114 01:03:44,330 --> 01:03:47,270 1115 01:03:47,270 --> 01:03:51,750 There was mathematician by the name of Cesaro-- 1116 01:03:51,750 --> 01:03:54,760 or Cesaro, Cesaro I suppose it is-- 1117 01:03:54,760 --> 01:03:58,450 who figured out a clever way of computing pi. 1118 01:03:58,450 --> 01:04:06,320 It turns out that if I take to random numbers, two integers 1119 01:04:06,320 --> 01:04:11,110 at random, and compute the greatest common divisor, their 1120 01:04:11,110 --> 01:04:13,920 greatest common divisor is either one or it's not one. 1121 01:04:13,920 --> 01:04:15,445 If it's one, then they have no common divisors. 1122 01:04:15,445 --> 01:04:18,240 1123 01:04:18,240 --> 01:04:21,060 If their greatest common divisor is one-- 1124 01:04:21,060 --> 01:04:23,590 the probability that two random numbers, two numbers 1125 01:04:23,590 --> 01:04:26,910 chosen at random, has as greatest common divisor one is 1126 01:04:26,910 --> 01:04:29,580 related to pi. 1127 01:04:29,580 --> 01:04:31,310 In fact-- 1128 01:04:31,310 --> 01:04:33,070 yes, it's very strange-- 1129 01:04:33,070 --> 01:04:34,980 of course there are other ways of computing pi, like dropping 1130 01:04:34,980 --> 01:04:38,100 pins on flags, and things like that, and sort of the same 1131 01:04:38,100 --> 01:04:40,110 kind of thing. 1132 01:04:40,110 --> 01:04:48,510 So the probability of that the GCD of number one and number 1133 01:04:48,510 --> 01:04:55,660 two, two random numbers chosen, is 6 over pi squared. 1134 01:04:55,660 --> 01:04:57,240 I'm not going to try to prove that. 1135 01:04:57,240 --> 01:05:01,120 It's actually not too hard and sort of fun. 1136 01:05:01,120 --> 01:05:03,590 How would we estimate such probability? 1137 01:05:03,590 --> 01:05:07,340 Well, the way we do that, the way we estimate probabilities, 1138 01:05:07,340 --> 01:05:09,620 is by doing lots of experiments, and then 1139 01:05:09,620 --> 01:05:12,260 computing the ratios of the ones that come out one way to 1140 01:05:12,260 --> 01:05:13,570 the total number of experiments we do. 1141 01:05:13,570 --> 01:05:16,320 1142 01:05:16,320 --> 01:05:19,680 It's called Monte Carlo, and it's useful in other contexts 1143 01:05:19,680 --> 01:05:21,280 for doing things like integrals where you have lots 1144 01:05:21,280 --> 01:05:22,960 and lots of variables-- 1145 01:05:22,960 --> 01:05:24,780 the space which is limiting the dimensions you are doing 1146 01:05:24,780 --> 01:05:26,360 you integral in. 1147 01:05:26,360 --> 01:05:34,680 But going back to here, Let's look at this slide, We can use 1148 01:05:34,680 --> 01:05:40,520 Cesaro's method for estimating pi with n trials by taking the 1149 01:05:40,520 --> 01:05:45,850 square root of six over a Monte Carlo, a Monte Carlo 1150 01:05:45,850 --> 01:05:51,410 experiment with n trials, using Cesaro's experiment, 1151 01:05:51,410 --> 01:05:56,550 where Cesaro's experiment is the test of whether the GCD of 1152 01:05:56,550 --> 01:05:59,070 two random numbers-- 1153 01:05:59,070 --> 01:06:01,200 And you can see that I've already got some assignments 1154 01:06:01,200 --> 01:06:03,990 in here, just by what I wrote. 1155 01:06:03,990 --> 01:06:07,930 The fact that this word rand, in parentheses, therefore, 1156 01:06:07,930 --> 01:06:11,530 that procedure call, yields a different value than this one, 1157 01:06:11,530 --> 01:06:13,330 at least that's what I'm assuming by writing this this 1158 01:06:13,330 --> 01:06:18,590 way, indicates that this is not a function, that there's 1159 01:06:18,590 --> 01:06:20,400 internal state in it which is changing. 1160 01:06:20,400 --> 01:06:25,110 1161 01:06:25,110 --> 01:06:28,530 If the GCD of those two random numbers is equal to one, 1162 01:06:28,530 --> 01:06:31,530 that's the experiment. 1163 01:06:31,530 --> 01:06:34,330 So here I have an experimental method for estimating the 1164 01:06:34,330 --> 01:06:36,560 value of pi. 1165 01:06:36,560 --> 01:06:40,160 Where, I can easily divide this problem into two parts. 1166 01:06:40,160 --> 01:06:43,610 One is the specific Monte Carlo experiment of Cesaro, 1167 01:06:43,610 --> 01:06:46,700 which you just saw, and the other is the general technique 1168 01:06:46,700 --> 01:06:49,320 of doing Monte Carlo experiments. 1169 01:06:49,320 --> 01:06:51,190 And that's what this is. 1170 01:06:51,190 --> 01:06:55,930 If I want to do Monte Carlo experiments with n trials, a 1171 01:06:55,930 --> 01:06:59,590 certain number of trials, and a particular experiment, the 1172 01:06:59,590 --> 01:07:03,460 way I do that is I make a little iterative procedure 1173 01:07:03,460 --> 01:07:05,960 which has variable the number of trials remaining and the 1174 01:07:05,960 --> 01:07:10,230 number trials that have been passed, that I've gotten true. 1175 01:07:10,230 --> 01:07:13,010 And if the number remaining is 0, then the answer is the 1176 01:07:13,010 --> 01:07:16,260 number past divided by this whole number of trials, was 1177 01:07:16,260 --> 01:07:19,150 the estimate of the probability. 1178 01:07:19,150 --> 01:07:22,140 And if it's not, if I have more trials to do, 1179 01:07:22,140 --> 01:07:22,870 then let's do one. 1180 01:07:22,870 --> 01:07:23,860 We do an experiment. 1181 01:07:23,860 --> 01:07:27,350 We call the procedure which is experiment on no arguments. 1182 01:07:27,350 --> 01:07:30,870 We do the experiment and then, if that turned out to be true, 1183 01:07:30,870 --> 01:07:33,830 we go around the loop decrementing the number of 1184 01:07:33,830 --> 01:07:36,560 experiments we have to do by one and incrementing the 1185 01:07:36,560 --> 01:07:38,650 number that were passed. 1186 01:07:38,650 --> 01:07:41,880 And if the experiment was false, we just go around the 1187 01:07:41,880 --> 01:07:44,700 loop decrementing the number of experiments remaining and 1188 01:07:44,700 --> 01:07:48,910 keeping the number passed the same. 1189 01:07:48,910 --> 01:07:51,320 We start this up iterating over the total number of 1190 01:07:51,320 --> 01:07:55,840 trials with 0 experiments past. A very 1191 01:07:55,840 --> 01:07:57,730 elegant little program. 1192 01:07:57,730 --> 01:08:00,530 And I don't have to just do this with Cesaro's experiment, 1193 01:08:00,530 --> 01:08:03,390 it could be lots of Monte Carlo experiments I might do. 1194 01:08:03,390 --> 01:08:05,860 Of course, this depends upon the existence of some sort of 1195 01:08:05,860 --> 01:08:07,440 random number generator. 1196 01:08:07,440 --> 01:08:09,960 And random number generators generally look 1197 01:08:09,960 --> 01:08:11,210 something like this. 1198 01:08:11,210 --> 01:08:13,570 1199 01:08:13,570 --> 01:08:17,550 There is a random number generator-- 1200 01:08:17,550 --> 01:08:24,490 is in fact a procedure which is going to do something just 1201 01:08:24,490 --> 01:08:25,710 like the counter. 1202 01:08:25,710 --> 01:08:30,870 It's going to update an x to the result of applying some 1203 01:08:30,870 --> 01:08:34,600 function to x, where this function is some screwy kind 1204 01:08:34,600 --> 01:08:38,800 of function that you might find out in Knuth's books on 1205 01:08:38,800 --> 01:08:41,689 the details of programming. 1206 01:08:41,689 --> 01:08:45,020 He does these wonderful books that are full of the details 1207 01:08:45,020 --> 01:08:47,500 of programming, because I can't remember how to make a 1208 01:08:47,500 --> 01:08:50,156 random number generator, but I can look it up there, and I 1209 01:08:50,156 --> 01:08:51,720 can find out. 1210 01:08:51,720 --> 01:08:54,850 And then, eventually, I return the value of x which is the 1211 01:08:54,850 --> 01:08:58,319 state variable internal to the random number generator. 1212 01:08:58,319 --> 01:09:00,140 That state variable is initialized 1213 01:09:00,140 --> 01:09:03,479 somehow, and has a value. 1214 01:09:03,479 --> 01:09:06,490 And this procedure is defined in the context where that 1215 01:09:06,490 --> 01:09:10,450 variable is bound. 1216 01:09:10,450 --> 01:09:15,930 So this is a hidden piece of local state that you see here. 1217 01:09:15,930 --> 01:09:21,720 And this procedure is defined in that context. 1218 01:09:21,720 --> 01:09:24,103 Now, that's a very simple thing to do. 1219 01:09:24,103 --> 01:09:26,020 And it's very nice. 1220 01:09:26,020 --> 01:09:29,080 Supposing, I didn't want to use assignments. 1221 01:09:29,080 --> 01:09:30,819 Supposing, I wanted to write this program without 1222 01:09:30,819 --> 01:09:32,840 assignments. 1223 01:09:32,840 --> 01:09:35,580 What problems would I have? 1224 01:09:35,580 --> 01:09:37,890 Well, let's see. 1225 01:09:37,890 --> 01:09:44,540 I'd like to use the overhead machine here, thank you. 1226 01:09:44,540 --> 01:09:45,870 First of all, let's look at the whole thing. 1227 01:09:45,870 --> 01:09:48,140 It's a big story. 1228 01:09:48,140 --> 01:09:51,720 Unfortunately, which tells you there is something wrong. 1229 01:09:51,720 --> 01:09:54,255 It's at least that big, and it's monolithic. 1230 01:09:54,255 --> 01:09:57,020 1231 01:09:57,020 --> 01:09:59,580 You don't have to understand or look at the text there 1232 01:09:59,580 --> 01:10:02,120 right now to see that it's monolithic. 1233 01:10:02,120 --> 01:10:05,090 It isn't a thing which is Cesaro's experiment. 1234 01:10:05,090 --> 01:10:10,050 It's not pulled out from the Monte Carlo process. 1235 01:10:10,050 --> 01:10:10,890 It's not separated. 1236 01:10:10,890 --> 01:10:12,140 Let's look why. 1237 01:10:12,140 --> 01:10:14,350 1238 01:10:14,350 --> 01:10:19,330 Remember, the constraint here is that every procedure return 1239 01:10:19,330 --> 01:10:23,070 the same value for the same arguments. 1240 01:10:23,070 --> 01:10:26,800 Every procedure represents a function. 1241 01:10:26,800 --> 01:10:28,275 That's a different kind of constraint. 1242 01:10:28,275 --> 01:10:30,250 Because when I have assignments, I can change some 1243 01:10:30,250 --> 01:10:31,840 internal state variable. 1244 01:10:31,840 --> 01:10:35,060 So let's see how that causes things to go wrong. 1245 01:10:35,060 --> 01:10:38,510 Well, start at the beginning. 1246 01:10:38,510 --> 01:10:42,950 The estimate of pi looks sort of the same. 1247 01:10:42,950 --> 01:10:47,560 What I'm doing is I take the square root of six over the 1248 01:10:47,560 --> 01:10:52,990 random GCD test applied to n, whereas that's what this is. 1249 01:10:52,990 --> 01:10:55,390 But here, we are beginning to see something funny. 1250 01:10:55,390 --> 01:10:58,770 The random GCD test of a certain number of trials is 1251 01:10:58,770 --> 01:11:03,400 just like we had before, an iteration on the number of 1252 01:11:03,400 --> 01:11:06,210 trials remaining, the number of trials that have been 1253 01:11:06,210 --> 01:11:10,870 passed, and another variable x. 1254 01:11:10,870 --> 01:11:12,370 What's that x? 1255 01:11:12,370 --> 01:11:14,950 That x is the state of the random number generator. 1256 01:11:14,950 --> 01:11:18,950 1257 01:11:18,950 --> 01:11:21,150 And it is now going to be used here. 1258 01:11:21,150 --> 01:11:23,890 The same random update function that I have over here 1259 01:11:23,890 --> 01:11:25,890 is the one I would have used in a random number generator 1260 01:11:25,890 --> 01:11:28,510 if I were building it the other way, the one I get out 1261 01:11:28,510 --> 01:11:31,710 of Knuth's books. 1262 01:11:31,710 --> 01:11:33,380 x is going to get transformed into x1, I 1263 01:11:33,380 --> 01:11:34,950 need two random numbers. 1264 01:11:34,950 --> 01:11:37,630 And x1 is going to get transformed into x2, I have 1265 01:11:37,630 --> 01:11:39,550 two random numbers. 1266 01:11:39,550 --> 01:11:42,620 I then have to do exactly what I did before. 1267 01:11:42,620 --> 01:11:43,870 I take the GCD of x1 x2. 1268 01:11:43,870 --> 01:11:48,260 If that's one, then I go around the loop with x2 being 1269 01:11:48,260 --> 01:11:49,520 the next value of x. 1270 01:11:49,520 --> 01:11:54,850 1271 01:11:54,850 --> 01:11:57,740 You see what's happened here is that the state of the 1272 01:11:57,740 --> 01:12:00,480 random number generator is no longer confined to the insides 1273 01:12:00,480 --> 01:12:01,495 of the random number generator. 1274 01:12:01,495 --> 01:12:03,450 It has leaked out. 1275 01:12:03,450 --> 01:12:09,240 It has leaked out into my procedure that does the Monte 1276 01:12:09,240 --> 01:12:10,720 Carlo experiment. 1277 01:12:10,720 --> 01:12:13,480 But what's worse than that, is it's also, because it was 1278 01:12:13,480 --> 01:12:17,470 contained inside my experiment itself, Cesaro, it leaked out 1279 01:12:17,470 --> 01:12:18,090 of that too. 1280 01:12:18,090 --> 01:12:21,920 Because Cesaro called twice, has to have a different value 1281 01:12:21,920 --> 01:12:24,780 each time, if I going to have a legitimate experimental 1282 01:12:24,780 --> 01:12:31,910 test. So Cesaro can't be a function either, unless I pass 1283 01:12:31,910 --> 01:12:34,730 it the seed of the random number generator that is going 1284 01:12:34,730 --> 01:12:36,490 to go wandering around. 1285 01:12:36,490 --> 01:12:39,740 So unfortunately, the seed of random number generator has 1286 01:12:39,740 --> 01:12:42,850 leaked out into Cesaro, from the random number generator, 1287 01:12:42,850 --> 01:12:45,465 that's leaked into the Monte Carlo experiment. 1288 01:12:45,465 --> 01:12:48,485 And, unfortunately, my Monte Carlo experiment here is no 1289 01:12:48,485 --> 01:12:50,310 longer general. 1290 01:12:50,310 --> 01:12:52,990 The Monte Carlo experiment here knows how many random 1291 01:12:52,990 --> 01:12:54,405 numbers I need to do the experiment. 1292 01:12:54,405 --> 01:12:58,530 1293 01:12:58,530 --> 01:13:00,230 That's sort of horrible. 1294 01:13:00,230 --> 01:13:04,090 I lost an ability to decompose a problem into pieces, because 1295 01:13:04,090 --> 01:13:10,720 I wasn't willing to accept the little loop of information, 1296 01:13:10,720 --> 01:13:14,720 the feedback process, that happens inside the random 1297 01:13:14,720 --> 01:13:18,000 number generator before that was made by having an 1298 01:13:18,000 --> 01:13:20,400 assignment to a state variable that was confined to the 1299 01:13:20,400 --> 01:13:22,770 random number generator. 1300 01:13:22,770 --> 01:13:26,070 So the fact that the random number generator is an object, 1301 01:13:26,070 --> 01:13:29,040 with an internal state variable, it's affected by 1302 01:13:29,040 --> 01:13:30,595 nothing, but it'll give you something, and it will apply 1303 01:13:30,595 --> 01:13:34,290 it's force to you, that was what we're missing now. 1304 01:13:34,290 --> 01:13:38,140 1305 01:13:38,140 --> 01:13:42,870 OK, well I think we've seen enough reason for doing this, 1306 01:13:42,870 --> 01:13:45,510 and it all sort of looks very wonderful. 1307 01:13:45,510 --> 01:13:51,840 Wouldn't it be nice if assignment was a good thing 1308 01:13:51,840 --> 01:13:55,440 and maybe it's worth it, but I'm not sure. 1309 01:13:55,440 --> 01:13:57,860 As Mr. Gilbert and Sullivan said, things are seldom what 1310 01:13:57,860 --> 01:14:01,940 they seem, skim milk masquerades as cream. 1311 01:14:01,940 --> 01:14:03,655 Are there any questions? 1312 01:14:03,655 --> 01:14:17,010 1313 01:14:17,010 --> 01:14:20,120 Are there any philosophers here? 1314 01:14:20,120 --> 01:14:21,930 Anybody want to argue about objects? 1315 01:14:21,930 --> 01:14:24,590 1316 01:14:24,590 --> 01:14:25,840 You're just floored, right? 1317 01:14:25,840 --> 01:14:29,840 1318 01:14:29,840 --> 01:14:30,805 And you haven't done your homework yet. 1319 01:14:30,805 --> 01:14:32,055 You haven't come up with a good question. 1320 01:14:32,055 --> 01:14:36,790 1321 01:14:36,790 --> 01:14:38,040 Oh, well. 1322 01:14:38,040 --> 01:14:40,110 1323 01:14:40,110 --> 01:14:41,120 Sure, thank you. 1324 01:14:41,120 --> 01:14:42,370 Let's take the long break now. 1325 01:14:42,370 --> 01:15:17,567 ================================================ FILE: SrtEN/lec5b_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:21,170 1 00:00:21,170 --> 00:00:24,550 PROFESSOR: Well, now that we've given you some power to 2 00:00:24,550 --> 00:00:28,340 make independent local state and to model objects, I 3 00:00:28,340 --> 00:00:31,610 thought we'd do a bit of programming of a very 4 00:00:31,610 --> 00:00:35,380 complicated kind, just to illustrate what you can do 5 00:00:35,380 --> 00:00:36,630 with this sort of thing. 6 00:00:36,630 --> 00:00:40,430 7 00:00:40,430 --> 00:00:44,080 I suppose, as I said, we were motivated by physical systems 8 00:00:44,080 --> 00:00:47,200 and the ways we like to think about physical systems, which 9 00:00:47,200 --> 00:00:52,060 is that there are these things that the world is made out of. 10 00:00:52,060 --> 00:00:55,570 And each of these things has particular independent local 11 00:00:55,570 --> 00:00:58,830 state, and therefore it is a thing. 12 00:00:58,830 --> 00:01:01,280 That's what makes it a thing. 13 00:01:01,280 --> 00:01:04,410 And then we're going to say that in the model in the 14 00:01:04,410 --> 00:01:07,900 world--we have a world and a model in our minds and in the 15 00:01:07,900 --> 00:01:10,940 computer of that world. 16 00:01:10,940 --> 00:01:13,230 And what I want to make is a correspondence between the 17 00:01:13,230 --> 00:01:15,980 objects in the world and the objects in the computer, the 18 00:01:15,980 --> 00:01:18,140 relationships between the objects in the world and the 19 00:01:18,140 --> 00:01:21,200 relationships between those same obj...--the model objects 20 00:01:21,200 --> 00:01:24,890 in the computer, and the functions that relate things 21 00:01:24,890 --> 00:01:27,320 in the world to the functions that relate 22 00:01:27,320 --> 00:01:28,570 things in the computer. 23 00:01:28,570 --> 00:01:30,840 24 00:01:30,840 --> 00:01:34,740 This buys us modularity. 25 00:01:34,740 --> 00:01:37,786 If we really believe the world is like that, that it's made 26 00:01:37,786 --> 00:01:40,120 out of these little pieces, and of course we could arrange 27 00:01:40,120 --> 00:01:43,085 our world to be like that, we could only model those things 28 00:01:43,085 --> 00:01:47,030 that are like that, then we can inherit the modularity in 29 00:01:47,030 --> 00:01:50,450 the world into our programming. 30 00:01:50,450 --> 00:01:53,150 That's why we would invent some of this object-oriented 31 00:01:53,150 --> 00:01:55,420 programming. 32 00:01:55,420 --> 00:01:58,890 Well, let's take the best kind of objects I know. 33 00:01:58,890 --> 00:02:03,160 They're completely--they're completely wonderful: 34 00:02:03,160 --> 00:02:10,270 electrical systems. Electrical systems really are the 35 00:02:10,270 --> 00:02:14,220 physicist's best, best objects. 36 00:02:14,220 --> 00:02:16,760 You see over here I have some piece of machinery. 37 00:02:16,760 --> 00:02:20,040 Right here's a piece of machinery. 38 00:02:20,040 --> 00:02:24,270 And it's got an electrical wire connecting one part of 39 00:02:24,270 --> 00:02:27,190 the machinery with another part of the machinery. 40 00:02:27,190 --> 00:02:30,450 And one of the wonderful properties of the electrical 41 00:02:30,450 --> 00:02:34,610 world is that I can say this is an object, and this is an 42 00:02:34,610 --> 00:02:36,040 object, and they're-- 43 00:02:36,040 --> 00:02:38,310 the connection between them is clear. 44 00:02:38,310 --> 00:02:41,190 In principle, there is no connection that I didn't 45 00:02:41,190 --> 00:02:44,740 describe with these wires. 46 00:02:44,740 --> 00:02:48,000 Let's say if I have light bulbs, a light bulb and a 47 00:02:48,000 --> 00:02:51,370 power supply that's plugged into the outlet. 48 00:02:51,370 --> 00:02:53,620 Then the connection is perfectly clear. 49 00:02:53,620 --> 00:02:56,220 There's no other connections that we know of. 50 00:02:56,220 --> 00:02:59,250 If I were to tie a knot in the wire that connects the light 51 00:02:59,250 --> 00:03:04,040 bulb to the power supply, the light remains lit up. 52 00:03:04,040 --> 00:03:05,290 It doesn't care. 53 00:03:05,290 --> 00:03:08,300 54 00:03:08,300 --> 00:03:11,120 That the way the physics is arranged is such that the 55 00:03:11,120 --> 00:03:13,790 connection can be made abstract, at least for low 56 00:03:13,790 --> 00:03:15,270 frequencies and things like that. 57 00:03:15,270 --> 00:03:17,840 58 00:03:17,840 --> 00:03:20,360 So in fact, we have captured all of the connections there 59 00:03:20,360 --> 00:03:22,350 really are. 60 00:03:22,350 --> 00:03:24,310 Well, as you can go one step further and talk about the 61 00:03:24,310 --> 00:03:27,830 most abstract types of electrical systems we have, 62 00:03:27,830 --> 00:03:30,951 digital to dual circuits. 63 00:03:30,951 --> 00:03:34,610 And here there are certain kinds of objects. 64 00:03:34,610 --> 00:03:38,240 For example, in digital circuits we 65 00:03:38,240 --> 00:03:41,092 have things like inverters. 66 00:03:41,092 --> 00:03:43,990 We have things like and-gates. 67 00:03:43,990 --> 00:03:47,210 We have things like or-gates. 68 00:03:47,210 --> 00:03:53,980 We connect them together by sort-of wires which represent 69 00:03:53,980 --> 00:03:55,610 abstract signals. 70 00:03:55,610 --> 00:03:57,390 We don't really care as physical variables whether 71 00:03:57,390 --> 00:04:00,190 these are voltages or currents or some combination or 72 00:04:00,190 --> 00:04:05,160 anything like that, or water, water pressure. 73 00:04:05,160 --> 00:04:09,420 These abstract variables represent certain signals. 74 00:04:09,420 --> 00:04:11,950 And we build systems by wiring these things 75 00:04:11,950 --> 00:04:14,070 together with wires. 76 00:04:14,070 --> 00:04:17,730 So today what I'm going to show you, right now, we're 77 00:04:17,730 --> 00:04:22,650 going to build up an invented language in Lisp, embedded in 78 00:04:22,650 --> 00:04:24,590 the same sense that Henderson's picture language 79 00:04:24,590 --> 00:04:29,780 was embedded, which is not the same sense as the language of 80 00:04:29,780 --> 00:04:32,700 pattern match and substitution was done yesterday. 81 00:04:32,700 --> 00:04:35,725 The pattern match/substitution language was interpreted by a 82 00:04:35,725 --> 00:04:38,160 Lisp program. 83 00:04:38,160 --> 00:04:40,920 But the embedding of Henderson's program is that we 84 00:04:40,920 --> 00:04:43,370 just build up more and more procedures that encapsulate 85 00:04:43,370 --> 00:04:45,480 the structure we want. 86 00:04:45,480 --> 00:04:49,280 So for example here, I'm going to have some various primitive 87 00:04:49,280 --> 00:04:53,026 kinds of objects, as you see, that one and that one. 88 00:04:53,026 --> 00:04:55,810 I'm going to use wires to combine them. 89 00:04:55,810 --> 00:04:58,420 The way I represent attaching-- 90 00:04:58,420 --> 00:04:59,870 I can make wires. 91 00:04:59,870 --> 00:05:01,740 So let's say A is a wire. 92 00:05:01,740 --> 00:05:02,690 And B is a wire. 93 00:05:02,690 --> 00:05:03,460 And C is a wire. 94 00:05:03,460 --> 00:05:04,230 And D is a wire. 95 00:05:04,230 --> 00:05:04,830 And E is wire. 96 00:05:04,830 --> 00:05:06,880 And S is a wire. 97 00:05:06,880 --> 00:05:12,380 Well, an or-gate that has both inputs, the inputs being A and 98 00:05:12,380 --> 00:05:17,940 B, and the output being Y or D, you notate like this. 99 00:05:17,940 --> 00:05:22,390 An and-gate, which has inputs A and B and output C, we 100 00:05:22,390 --> 00:05:24,820 notate like that. 101 00:05:24,820 --> 00:05:29,690 By making such a sequence of declarations, like this, I can 102 00:05:29,690 --> 00:05:32,750 wire together an arbitrary circuit. 103 00:05:32,750 --> 00:05:35,940 So I've just told you a set of primitives and means of 104 00:05:35,940 --> 00:05:40,930 combination for building digital circuits, when I need 105 00:05:40,930 --> 00:05:43,690 more in a real language than abstraction. 106 00:05:43,690 --> 00:05:46,766 And so for example, here I have--here 107 00:05:46,766 --> 00:05:52,240 I have a half adder. 108 00:05:52,240 --> 00:05:54,270 It's something you all know if you've 109 00:05:54,270 --> 00:05:56,930 done any digital design. 110 00:05:56,930 --> 00:06:00,830 It's used for adding numbers together on A and B and 111 00:06:00,830 --> 00:06:03,956 putting out a sum and a carry. 112 00:06:03,956 --> 00:06:05,710 And in fact, the wiring diagram is 113 00:06:05,710 --> 00:06:07,450 exactly what I told you. 114 00:06:07,450 --> 00:06:11,410 A half adder with things that come out of the box-- you see 115 00:06:11,410 --> 00:06:14,790 the box, the boundary, the abstraction is always a box. 116 00:06:14,790 --> 00:06:19,700 And there are things that come out of it, A, B, S, and C. 117 00:06:19,700 --> 00:06:24,950 Those are the declared variables--declared variables 118 00:06:24,950 --> 00:06:27,020 of a lambda expression, which is the one that 119 00:06:27,020 --> 00:06:28,270 defines half adder. 120 00:06:28,270 --> 00:06:31,400 121 00:06:31,400 --> 00:06:36,080 And internal to that, I make up some more wires, D and E, 122 00:06:36,080 --> 00:06:37,760 which I'm going to use for the interconnect-- 123 00:06:37,760 --> 00:06:41,860 here E is this one and D is this wire, the interconnect 124 00:06:41,860 --> 00:06:45,100 that doesn't come through the walls of the box-- 125 00:06:45,100 --> 00:06:48,790 and wire things together as you just saw. 126 00:06:48,790 --> 00:06:51,180 And the nice thing about this that I've just shown you is 127 00:06:51,180 --> 00:06:53,890 this language is hierarchical in the right way. 128 00:06:53,890 --> 00:06:55,950 If a language isn't hierarchical in the right way, 129 00:06:55,950 --> 00:06:58,850 if it turns out that a compound object doesn't look 130 00:06:58,850 --> 00:07:00,820 like a primitive, there's something 131 00:07:00,820 --> 00:07:02,180 wrong with the language-- 132 00:07:02,180 --> 00:07:06,300 at least the way I feel about that. 133 00:07:06,300 --> 00:07:09,220 So here we have--here, instead of starting with mathematical 134 00:07:09,220 --> 00:07:10,900 functions, or things that compute mathematical 135 00:07:10,900 --> 00:07:13,870 functions, which is what we've been doing up until now, 136 00:07:13,870 --> 00:07:15,770 instead of starting with things that look like 137 00:07:15,770 --> 00:07:18,080 mathematical functions, or compute such things, we are 138 00:07:18,080 --> 00:07:21,330 starting with things that are electrical objects and we 139 00:07:21,330 --> 00:07:23,350 build up more electrical objects. 140 00:07:23,350 --> 00:07:26,590 And the glue we're using is basically the 141 00:07:26,590 --> 00:07:30,500 Lisp structure: lambdas. 142 00:07:30,500 --> 00:07:32,930 Lambda is the ultimate glue, if you will. 143 00:07:32,930 --> 00:07:39,000 And of course, half adder itself can be used in a more 144 00:07:39,000 --> 00:07:42,250 complicated abstraction called a full adder, which in fact 145 00:07:42,250 --> 00:07:46,670 involves two half adders, as you see here, hooked together 146 00:07:46,670 --> 00:07:50,600 with some extra wires, that you see here, S, C1, and C2, 147 00:07:50,600 --> 00:07:57,340 and an or-gate, to manufacture a full adder, which takes a 148 00:07:57,340 --> 00:08:01,570 input number, another input number, a carry in, and 149 00:08:01,570 --> 00:08:05,900 produces output, a sum and a carry out. 150 00:08:05,900 --> 00:08:09,820 And out of full adders, you can make real adder chains and 151 00:08:09,820 --> 00:08:12,990 big adders. 152 00:08:12,990 --> 00:08:18,870 So we have here a language so far that has primitives, means 153 00:08:18,870 --> 00:08:22,270 of combination, and means of abstraction to real language. 154 00:08:22,270 --> 00:08:25,000 Now, how are we going to implement this? 155 00:08:25,000 --> 00:08:27,070 Well, let's do it easily. 156 00:08:27,070 --> 00:08:28,610 Let's look at the primitives. 157 00:08:28,610 --> 00:08:31,160 The only problem is we have to implement the primitives. 158 00:08:31,160 --> 00:08:34,270 Nothing else has to be implemented, because we're 159 00:08:34,270 --> 00:08:37,640 picking up the means of combination and abstraction 160 00:08:37,640 --> 00:08:43,417 from Lisp, inheriting them in the embedding. 161 00:08:43,417 --> 00:08:45,860 OK, so let's look at a particular primitive. 162 00:08:45,860 --> 00:08:47,400 An inverter is a nice one. 163 00:08:47,400 --> 00:08:51,540 164 00:08:51,540 --> 00:08:54,900 Now, inverter has two wires coming in, an in and an out. 165 00:08:54,900 --> 00:08:57,440 166 00:08:57,440 --> 00:09:01,570 And somehow, it's going to have to know what to do when a 167 00:09:01,570 --> 00:09:04,300 signal comes in. 168 00:09:04,300 --> 00:09:07,710 So somehow it's going to have to tell its input wire-- 169 00:09:07,710 --> 00:09:10,756 and now we're going to talk about objects and we're going 170 00:09:10,756 --> 00:09:13,260 to see this in a little more detail soon-- 171 00:09:13,260 --> 00:09:16,660 but it's going to have to tell its input wire that when you 172 00:09:16,660 --> 00:09:20,120 change, tell me. 173 00:09:20,120 --> 00:09:22,720 So this object, the object which is the inverter has to 174 00:09:22,720 --> 00:09:25,070 tell the object which is the input wire, 175 00:09:25,070 --> 00:09:26,870 hi, my name is George. 176 00:09:26,870 --> 00:09:30,480 And my, my job is to do something with results when 177 00:09:30,480 --> 00:09:31,720 you change. 178 00:09:31,720 --> 00:09:34,730 So when you change, you get a change, tell me about it. 179 00:09:34,730 --> 00:09:37,010 Because I've got to do something with that. 180 00:09:37,010 --> 00:09:42,200 Well, that's done down here by adding an action on the input 181 00:09:42,200 --> 00:09:47,020 wire called invert-in, where invert-in is defined over here 182 00:09:47,020 --> 00:09:51,660 to be a procedure of no arguments, which gets the 183 00:09:51,660 --> 00:09:56,130 logical not of the signal on the input wire. 184 00:09:56,130 --> 00:09:59,720 And after some delay, which is the inverter delay, all these 185 00:09:59,720 --> 00:10:04,110 electrical objects have delays, we'll do the following 186 00:10:04,110 --> 00:10:07,140 thing-- set the signal on the output wire to the new value. 187 00:10:07,140 --> 00:10:10,160 188 00:10:10,160 --> 00:10:12,400 A very simple program. 189 00:10:12,400 --> 00:10:14,820 Now, you have to imagine that the output wire has to be 190 00:10:14,820 --> 00:10:19,650 sensitive and know that when its signal changes, it may 191 00:10:19,650 --> 00:10:23,840 have to tell other guys, hey, wake up. 192 00:10:23,840 --> 00:10:26,050 My value has changed. 193 00:10:26,050 --> 00:10:29,350 So when you hook together inverter with an and-gate or 194 00:10:29,350 --> 00:10:31,680 something like that, there has to be a lot of communication 195 00:10:31,680 --> 00:10:34,040 going on in order to make sure that the 196 00:10:34,040 --> 00:10:36,810 signal propagates right. 197 00:10:36,810 --> 00:10:38,620 And down here is nothing very exciting. 198 00:10:38,620 --> 00:10:41,100 This is just the definition of logical not for some 199 00:10:41,100 --> 00:10:44,170 particular representations of the logical values-- 200 00:10:44,170 --> 00:10:46,240 1, 0 in this case. 201 00:10:46,240 --> 00:10:49,780 And we can look at things more complicated like and-gates. 202 00:10:49,780 --> 00:10:55,000 And-gates take two inputs, A1 and A2, we'll call them, and 203 00:10:55,000 --> 00:10:56,950 produce an output. 204 00:10:56,950 --> 00:10:59,840 But the structure of the and-gate is identical to the 205 00:10:59,840 --> 00:11:00,860 one we just saw. 206 00:11:00,860 --> 00:11:03,000 There's one called an and-action procedure that's 207 00:11:03,000 --> 00:11:08,570 defined, which is the thing that gets called when an input 208 00:11:08,570 --> 00:11:10,910 is changed. 209 00:11:10,910 --> 00:11:13,230 And what it does, of course, is nothing more than compute 210 00:11:13,230 --> 00:11:15,900 the logical and of the signals on the inputs. 211 00:11:15,900 --> 00:11:20,890 And after some delay, called the and-gate delay, calls this 212 00:11:20,890 --> 00:11:25,470 procedure, which sets a signal on the output to a new value. 213 00:11:25,470 --> 00:11:27,320 Now, how I implement these things 214 00:11:27,320 --> 00:11:28,350 is all wishful thinking. 215 00:11:28,350 --> 00:11:32,020 As you see here, I have an assignment operation. 216 00:11:32,020 --> 00:11:34,570 It's not set. 217 00:11:34,570 --> 00:11:36,820 It's a derived assignment operation in the same way we 218 00:11:36,820 --> 00:11:41,140 had functions that were derived from CAR and CDR. So 219 00:11:41,140 --> 00:11:46,340 I, by convention, label that with an exclamation point. 220 00:11:46,340 --> 00:11:50,730 And over here, you see there's an action, which is to inform 221 00:11:50,730 --> 00:11:57,190 the wire, called A1 locally in this and-gate, to call the 222 00:11:57,190 --> 00:12:00,960 and-action procedure when it gets changed, and the wire A2 223 00:12:00,960 --> 00:12:02,100 to call the and-action procedure 224 00:12:02,100 --> 00:12:03,350 when it gets changed. 225 00:12:03,350 --> 00:12:06,310 226 00:12:06,310 --> 00:12:09,510 All very simple. 227 00:12:09,510 --> 00:12:12,870 Well, let's talk a little bit about this communication that 228 00:12:12,870 --> 00:12:18,310 must occur between these various parts. 229 00:12:18,310 --> 00:12:24,560 Suppose, for example, I have a very simple circuit which 230 00:12:24,560 --> 00:12:34,230 contains an and with wires A and B. And that connects 231 00:12:34,230 --> 00:12:40,580 through a wire called C to an inverter which has a wire 232 00:12:40,580 --> 00:12:46,310 output called D. What are the comput...--here's 233 00:12:46,310 --> 00:12:47,360 the physical world. 234 00:12:47,360 --> 00:12:49,860 It's an abstraction of the physical world. 235 00:12:49,860 --> 00:12:52,010 Now I can buy these out of little pieces that you get at 236 00:12:52,010 --> 00:12:54,880 Radio Shack for a few cents. 237 00:12:54,880 --> 00:12:57,680 And there are boxes that act like this, which have little 238 00:12:57,680 --> 00:13:01,530 numbers on them like LS04 or something. 239 00:13:01,530 --> 00:13:06,980 Now supposing I were to try to say what's the 240 00:13:06,980 --> 00:13:09,010 computational model. 241 00:13:09,010 --> 00:13:11,610 What is the thing that corresponds to that, that part 242 00:13:11,610 --> 00:13:15,850 of reality in the mind of us and in the computer? 243 00:13:15,850 --> 00:13:18,200 Well, I have to assign for every object in the world an 244 00:13:18,200 --> 00:13:22,160 object in the computer, and for every relationship in the 245 00:13:22,160 --> 00:13:25,750 world between them a relationship in the computer. 246 00:13:25,750 --> 00:13:28,560 That's my goal. 247 00:13:28,560 --> 00:13:30,900 So let's do that. 248 00:13:30,900 --> 00:13:35,401 Well, I have some sort of thing called the signal, A. 249 00:13:35,401 --> 00:13:37,940 This is A. It's a signal. 250 00:13:37,940 --> 00:13:39,900 It's a cloudy thing like that. 251 00:13:39,900 --> 00:13:42,390 And I have another one down here which I'm going to call 252 00:13:42,390 --> 00:13:49,140 B. It's another signal. 253 00:13:49,140 --> 00:13:52,070 Now this signal--these two signals are somehow going to 254 00:13:52,070 --> 00:13:56,180 have to hook together into a box, let's call it this, which 255 00:13:56,180 --> 00:14:00,320 is the and-gate, action procedure. 256 00:14:00,320 --> 00:14:02,040 That's the and-gate's action procedure. 257 00:14:02,040 --> 00:14:07,660 258 00:14:07,660 --> 00:14:09,750 And it's going to produce--well, it's going to 259 00:14:09,750 --> 00:14:18,360 interact with a signal object, which we call C--a wire 260 00:14:18,360 --> 00:14:21,330 object, excuse me, we call C. And then the-- 261 00:14:21,330 --> 00:14:25,630 this is going to put out again, or connect to, another 262 00:14:25,630 --> 00:14:28,240 action procedure which is one associated with the inverter 263 00:14:28,240 --> 00:14:30,195 in the world, not. 264 00:14:30,195 --> 00:14:32,860 265 00:14:32,860 --> 00:14:39,980 And I'm going to have another--another wire, which 266 00:14:39,980 --> 00:14:42,970 we'll call D. 267 00:14:42,970 --> 00:14:45,770 So here's my layout of stuff. 268 00:14:45,770 --> 00:14:47,650 Now we have to say what's inside them and what they have 269 00:14:47,650 --> 00:14:51,500 to know to compute. 270 00:14:51,500 --> 00:14:53,900 Well, every--every one of these wires has to know what 271 00:14:53,900 --> 00:14:57,340 the value of the signal that's on that wire is. 272 00:14:57,340 --> 00:14:59,430 So there's going to be some variable inside here, we'll 273 00:14:59,430 --> 00:15:00,680 call it signal. 274 00:15:00,680 --> 00:15:02,670 275 00:15:02,670 --> 00:15:05,840 And he owns a value. 276 00:15:05,840 --> 00:15:06,870 So there must be some environment 277 00:15:06,870 --> 00:15:08,656 associated with this. 278 00:15:08,656 --> 00:15:10,550 And for each one of these, there must be an environment 279 00:15:10,550 --> 00:15:11,800 that binds signal. 280 00:15:11,800 --> 00:15:15,400 281 00:15:15,400 --> 00:15:16,880 And there must be a signal here, therefore. 282 00:15:16,880 --> 00:15:19,400 283 00:15:19,400 --> 00:15:22,920 And presumably, signal's a value that's either 1 or 0, 284 00:15:22,920 --> 00:15:24,170 and signal. 285 00:15:24,170 --> 00:15:28,000 286 00:15:28,000 --> 00:15:33,140 Now, we also have to have some list of people to inform if 287 00:15:33,140 --> 00:15:34,390 the signal here changes. 288 00:15:34,390 --> 00:15:36,660 289 00:15:36,660 --> 00:15:39,300 We're going to have to inform this. 290 00:15:39,300 --> 00:15:41,470 So I've got that list. We'll call it the 291 00:15:41,470 --> 00:15:44,500 Action Procedures, AP. 292 00:15:44,500 --> 00:15:47,590 And it's presumably a list. But the first thing on the 293 00:15:47,590 --> 00:15:50,500 list, in this case, is this guy. 294 00:15:50,500 --> 00:15:53,730 And the action procedures of this one happens to have some 295 00:15:53,730 --> 00:15:54,810 list of stuff. 296 00:15:54,810 --> 00:15:57,510 There might be other people who are sharing A, who are 297 00:15:57,510 --> 00:15:59,020 looking at it. 298 00:15:59,020 --> 00:16:02,060 So there might be other guys on this list, like somebody 299 00:16:02,060 --> 00:16:03,630 over there that we don't know about. 300 00:16:03,630 --> 00:16:07,200 It's the other guy attached to A. 301 00:16:07,200 --> 00:16:11,230 And the action procedure here also has to point to that, the 302 00:16:11,230 --> 00:16:13,070 list of action procedures. 303 00:16:13,070 --> 00:16:17,060 And of course, that means this one, its action procedures has 304 00:16:17,060 --> 00:16:18,530 to point up to here. 305 00:16:18,530 --> 00:16:18,770 This is the things-- 306 00:16:18,770 --> 00:16:21,770 the people it has to inform. 307 00:16:21,770 --> 00:16:24,280 And this guy has some too. 308 00:16:24,280 --> 00:16:25,660 But I don't know what they are because I didn't 309 00:16:25,660 --> 00:16:27,190 draw it in my diagram. 310 00:16:27,190 --> 00:16:30,320 It's the things connected to D. 311 00:16:30,320 --> 00:16:36,240 Now, it's also the case that when the and-action procedure 312 00:16:36,240 --> 00:16:41,951 is awakened, saying one of the people who know that you've 313 00:16:41,951 --> 00:16:44,010 told--one of the people you've told to wake you up if their 314 00:16:44,010 --> 00:16:48,430 signal changes, you have to go look and ask them what's their 315 00:16:48,430 --> 00:16:51,540 signal so you can do the and, and produce a 316 00:16:51,540 --> 00:16:52,790 signal for this one. 317 00:16:52,790 --> 00:16:57,090 318 00:16:57,090 --> 00:16:59,760 So there has to be, for example, information here 319 00:16:59,760 --> 00:17:06,400 saying A1, my A1 is this guy, and my A2 is this guy. 320 00:17:06,400 --> 00:17:08,930 321 00:17:08,930 --> 00:17:14,170 And not only that, when I do my and, I'm going to have to 322 00:17:14,170 --> 00:17:16,170 tell this guy something. 323 00:17:16,170 --> 00:17:17,420 So I need an output-- 324 00:17:17,420 --> 00:17:19,904 325 00:17:19,904 --> 00:17:21,160 being this guy. 326 00:17:21,160 --> 00:17:25,800 327 00:17:25,800 --> 00:17:29,550 And similarly, this guy's going to have a thing called 328 00:17:29,550 --> 00:17:37,540 the input that he interrogates to find out what the value of 329 00:17:37,540 --> 00:17:39,430 the signal on the input is, when the signal wakes up and 330 00:17:39,430 --> 00:17:42,980 says, I've changed, and sends a message this way saying, 331 00:17:42,980 --> 00:17:43,520 I've changed. 332 00:17:43,520 --> 00:17:46,900 This guy says, OK, what's your value now? 333 00:17:46,900 --> 00:17:50,840 When he gets that value, then he's going to have to say, OK, 334 00:17:50,840 --> 00:17:55,860 output changes this guy, changes this guy. 335 00:17:55,860 --> 00:18:00,600 336 00:18:00,600 --> 00:18:02,481 And so on. 337 00:18:02,481 --> 00:18:06,240 And so I have to have at least that much connected-ness. 338 00:18:06,240 --> 00:18:10,260 Now, let's go back and look, for example, at the and-gate. 339 00:18:10,260 --> 00:18:13,670 Here we are back on this slide. 340 00:18:13,670 --> 00:18:16,040 And we can see some of these parts. 341 00:18:16,040 --> 00:18:18,470 For any particular and-gate, there is an A1, there is an 342 00:18:18,470 --> 00:18:21,030 A2, and the output. 343 00:18:21,030 --> 00:18:21,483 And those are, those are an environment that was created 344 00:18:21,483 --> 00:18:30,720 at the--those produce a frame at the time and-gate was 345 00:18:30,720 --> 00:18:37,200 called, a frame where A1, A2, and output are--have as their 346 00:18:37,200 --> 00:18:41,940 values, they're bound to the wires which, they are--which 347 00:18:41,940 --> 00:18:46,240 were passed in. 348 00:18:46,240 --> 00:18:50,890 In that environment, I constructed a procedure-- 349 00:18:50,890 --> 00:18:54,590 this one right there. 350 00:18:54,590 --> 00:18:56,810 And-action procedure was constructed in that 351 00:18:56,810 --> 00:18:57,780 environment. 352 00:18:57,780 --> 00:19:00,190 That was the result of evaluating a lambda 353 00:19:00,190 --> 00:19:01,620 expression. 354 00:19:01,620 --> 00:19:07,620 So it hangs onto the frame where these were defined. 355 00:19:07,620 --> 00:19:11,700 Local--part of its local state is that. 356 00:19:11,700 --> 00:19:15,000 The and-action procedure, therefore, has access to A1, 357 00:19:15,000 --> 00:19:17,310 A2, and output as we see here. 358 00:19:17,310 --> 00:19:19,645 A1, A2, and output. 359 00:19:19,645 --> 00:19:22,360 360 00:19:22,360 --> 00:19:26,030 Now, we haven't looked inside of a wire yet. 361 00:19:26,030 --> 00:19:29,030 That's all that remains. 362 00:19:29,030 --> 00:19:30,280 Let's look at a wire. 363 00:19:30,280 --> 00:19:33,520 364 00:19:33,520 --> 00:19:36,160 Like the overhead, very good. 365 00:19:36,160 --> 00:19:39,500 366 00:19:39,500 --> 00:19:40,940 Well, the wire, again, is a, is a 367 00:19:40,940 --> 00:19:43,090 somewhat complicated mess. 368 00:19:43,090 --> 00:19:46,840 Ooh, wrong one. 369 00:19:46,840 --> 00:19:49,780 It's a big complicated mess, like that. 370 00:19:49,780 --> 00:19:54,720 But let's look at it in detail and see what's going on. 371 00:19:54,720 --> 00:19:57,760 Well, the wire is one of these. 372 00:19:57,760 --> 00:20:02,320 And it has to have two things that are part of 373 00:20:02,320 --> 00:20:05,010 it, that it's state. 374 00:20:05,010 --> 00:20:07,390 One of them is the signal we see here. 375 00:20:07,390 --> 00:20:10,670 In other words, when we call make-wire to make a wire, then 376 00:20:10,670 --> 00:20:15,300 the first thing we do is we create some variables which 377 00:20:15,300 --> 00:20:19,270 are the signal and the action procedures for this wire. 378 00:20:19,270 --> 00:20:22,042 379 00:20:22,042 --> 00:20:26,540 And in that context, we define various functions--or 380 00:20:26,540 --> 00:20:27,840 procedures, excuse me, procedures. 381 00:20:27,840 --> 00:20:32,850 One of them is called set-my-signal to a new value. 382 00:20:32,850 --> 00:20:37,930 And what that does is takes a new value in. 383 00:20:37,930 --> 00:20:40,360 If that's equal to my current value of my signal, I'm done. 384 00:20:40,360 --> 00:20:43,460 Otherwise, I set the signal to the new value and call each of 385 00:20:43,460 --> 00:20:47,081 the action procedures that I've been, that I've 386 00:20:47,081 --> 00:20:48,331 been--what's the right word?-- 387 00:20:48,331 --> 00:20:51,700 388 00:20:51,700 --> 00:20:54,630 introduced to. 389 00:20:54,630 --> 00:21:01,530 I get introduced when the and-gate was applied to me. 390 00:21:01,530 --> 00:21:04,130 391 00:21:04,130 --> 00:21:07,410 I add action procedure at the bottom. 392 00:21:07,410 --> 00:21:10,440 Also, I have to define a way of accepting an action 393 00:21:10,440 --> 00:21:12,780 procedure-- which is what you see here--- 394 00:21:12,780 --> 00:21:18,530 which increments my action procedures using set to the 395 00:21:18,530 --> 00:21:22,060 result of CONSing up a new process--a procedure, which is 396 00:21:22,060 --> 00:21:25,760 passed to me, on to my actions procedures list. And for 397 00:21:25,760 --> 00:21:27,780 technical reasons, I have to call that procedure one. 398 00:21:27,780 --> 00:21:29,660 So I'm not going to tell you anything about that, that has 399 00:21:29,660 --> 00:21:32,610 to do with event-driven simulations and getting them 400 00:21:32,610 --> 00:21:36,950 started, which takes a little bit of thinking. 401 00:21:36,950 --> 00:21:38,690 And finally, I'm going to define a thing called the 402 00:21:38,690 --> 00:21:45,390 dispatcher, which is a way of passing a message to a wire, 403 00:21:45,390 --> 00:21:48,030 which is going to be used to extract from it various 404 00:21:48,030 --> 00:21:53,820 information, like what is the current signal value? 405 00:21:53,820 --> 00:21:57,180 What is the method of setting your signal? 406 00:21:57,180 --> 00:22:00,100 I want to get that out of it. 407 00:22:00,100 --> 00:22:02,600 How do I--how do I add another action procedure? 408 00:22:02,600 --> 00:22:05,510 409 00:22:05,510 --> 00:22:08,280 And I'm going to return that dispatch, that 410 00:22:08,280 --> 00:22:09,940 procedure as a value. 411 00:22:09,940 --> 00:22:12,610 So the wire that I've constructed is a message 412 00:22:12,610 --> 00:22:16,710 accepting object which accepts a message like, like what's 413 00:22:16,710 --> 00:22:19,790 your method of adding action procedures? 414 00:22:19,790 --> 00:22:22,270 In fact, it'll give me a procedure, which is the add 415 00:22:22,270 --> 00:22:26,020 action procedure, which I can then apply to an action 416 00:22:26,020 --> 00:22:29,010 procedure to create another action procedure in the wire. 417 00:22:29,010 --> 00:22:31,620 418 00:22:31,620 --> 00:22:32,820 So that's a permission. 419 00:22:32,820 --> 00:22:37,450 So it's given me permission to change your action procedures. 420 00:22:37,450 --> 00:22:41,710 And in fact, you can see that over here. 421 00:22:41,710 --> 00:22:43,278 Next slide. 422 00:22:43,278 --> 00:22:44,528 Ah. 423 00:22:44,528 --> 00:22:47,760 424 00:22:47,760 --> 00:22:49,120 This is nothing very interesting. 425 00:22:49,120 --> 00:22:52,040 The call each of the action procedures is just a CDRing 426 00:22:52,040 --> 00:22:53,500 down a list. And I'm not going to even 427 00:22:53,500 --> 00:22:54,990 talk about that anymore. 428 00:22:54,990 --> 00:22:57,560 We're too advanced for that. 429 00:22:57,560 --> 00:23:00,280 However, if I want to get a signal from a 430 00:23:00,280 --> 00:23:02,250 wire, I ask the wire-- 431 00:23:02,250 --> 00:23:03,090 which is, what is the wire? 432 00:23:03,090 --> 00:23:05,860 The wire is the dispatch returned by creating the wire. 433 00:23:05,860 --> 00:23:06,830 It's a procedure. 434 00:23:06,830 --> 00:23:12,590 I call that dispatch on the message get-signal. 435 00:23:12,590 --> 00:23:14,770 And what I should expect to get is a method 436 00:23:14,770 --> 00:23:16,900 of getting a signal. 437 00:23:16,900 --> 00:23:19,220 Or actually, I get the signal. 438 00:23:19,220 --> 00:23:25,800 If I want to set a signal, I want to change a signal, then 439 00:23:25,800 --> 00:23:28,810 what I'm going to do is take a wire as an argument and a new 440 00:23:28,810 --> 00:23:31,120 value for the signal, I'm going to ask the wire for 441 00:23:31,120 --> 00:23:35,660 permission to set its signal and use that permission, which 442 00:23:35,660 --> 00:23:38,700 is a procedure, on the new value. 443 00:23:38,700 --> 00:23:44,156 And if we go back to the overhead here, thank you, if 444 00:23:44,156 --> 00:23:46,880 we go back to the overhead here, we see that the method-- 445 00:23:46,880 --> 00:23:49,720 if I ask for the method of setting the signal, that's 446 00:23:49,720 --> 00:23:54,620 over here, it's set-my-signal, a procedure that's defined 447 00:23:54,620 --> 00:23:59,270 inside the wire, which if we look over here is the thing 448 00:23:59,270 --> 00:24:02,930 that says set my internal value called the signal, my 449 00:24:02,930 --> 00:24:08,640 internal variable, which is the signal, to the new value, 450 00:24:08,640 --> 00:24:11,630 which is passed to me as an argument, and then call each 451 00:24:11,630 --> 00:24:13,010 of the action procedures waking them up. 452 00:24:13,010 --> 00:24:16,340 453 00:24:16,340 --> 00:24:19,400 Very simple. 454 00:24:19,400 --> 00:24:24,310 Going back to that slide, we also have the one last thing-- 455 00:24:24,310 --> 00:24:27,810 which I suppose now you can easily work out for yourself-- 456 00:24:27,810 --> 00:24:30,100 is the way you add an action. 457 00:24:30,100 --> 00:24:36,470 You take a wire--a wire and an action procedure. 458 00:24:36,470 --> 00:24:40,050 And I ask the wire for permission to add an action. 459 00:24:40,050 --> 00:24:43,210 Getting that permission, I use that permission to give it an 460 00:24:43,210 --> 00:24:45,020 action procedure. 461 00:24:45,020 --> 00:24:48,570 So that's a real object. 462 00:24:48,570 --> 00:24:52,460 There's a few more details about this. 463 00:24:52,460 --> 00:24:58,390 For example, how am I going to control this thing? 464 00:24:58,390 --> 00:25:01,290 How do I do these delays? 465 00:25:01,290 --> 00:25:02,540 Let's look at that for a second. 466 00:25:02,540 --> 00:25:05,275 467 00:25:05,275 --> 00:25:08,360 The next one here. 468 00:25:08,360 --> 00:25:09,570 Let's see. 469 00:25:09,570 --> 00:25:15,450 We know when we looked at the and-gate or the not-gate that 470 00:25:15,450 --> 00:25:18,770 when a signal changed on the input, there was a delay. 471 00:25:18,770 --> 00:25:22,060 And then it was going to call the procedure, which was going 472 00:25:22,060 --> 00:25:23,310 to change the output. 473 00:25:23,310 --> 00:25:26,040 474 00:25:26,040 --> 00:25:28,120 Well, how are we going to do this? 475 00:25:28,120 --> 00:25:30,600 We're going to make up some mechanism, a fairly 476 00:25:30,600 --> 00:25:32,840 complicated mechanism at that, which we're going to have to 477 00:25:32,840 --> 00:25:34,720 be very careful about. 478 00:25:34,720 --> 00:25:37,390 But after a delay, we're going to do an action. 479 00:25:37,390 --> 00:25:40,590 A delay is a number, and an action is a procedure. 480 00:25:40,590 --> 00:25:41,970 What that's going to be is they're going to have a 481 00:25:41,970 --> 00:25:47,120 special structure called an agenda, which is a thing that 482 00:25:47,120 --> 00:25:49,510 organizes time and actions. 483 00:25:49,510 --> 00:25:50,880 And we're going to see that in a while. 484 00:25:50,880 --> 00:25:53,070 I don't want to get into that right now. 485 00:25:53,070 --> 00:25:55,745 But the agenda has a moment at which--at 486 00:25:55,745 --> 00:25:59,130 which something happens. 487 00:25:59,130 --> 00:26:03,120 We're setting up for later at some moment, which is the sum 488 00:26:03,120 --> 00:26:05,400 of the time, which is the delay time plus the current 489 00:26:05,400 --> 00:26:08,460 time, which the agenda thinks is now. 490 00:26:08,460 --> 00:26:11,840 We're going to set up to do this action, and add that to 491 00:26:11,840 --> 00:26:13,090 the agenda. 492 00:26:13,090 --> 00:26:15,280 493 00:26:15,280 --> 00:26:18,660 And the way this machine will now run is very simple. 494 00:26:18,660 --> 00:26:20,800 We have a thing called propagate, which is the way 495 00:26:20,800 --> 00:26:22,710 things run. 496 00:26:22,710 --> 00:26:25,290 If the agenda is empty, we're done--if there's nothing more 497 00:26:25,290 --> 00:26:27,440 to be done. 498 00:26:27,440 --> 00:26:31,690 Otherwise, we're going to take the first item off the agenda, 499 00:26:31,690 --> 00:26:34,200 and that's a procedure of no arguments. 500 00:26:34,200 --> 00:26:36,030 So that we're going to see extra parentheses here. 501 00:26:36,030 --> 00:26:39,190 We call that on no arguments. 502 00:26:39,190 --> 00:26:42,200 That takes the action. 503 00:26:42,200 --> 00:26:45,050 Then we remove that first item from the agenda, and we go 504 00:26:45,050 --> 00:26:48,395 around the propagation loop. 505 00:26:48,395 --> 00:26:50,750 So that's the overall structure of this thing. 506 00:26:50,750 --> 00:26:53,380 507 00:26:53,380 --> 00:26:57,430 Now, there's a, a few other things we can look at. 508 00:26:57,430 --> 00:26:59,160 And then we're going to look into the agenda a 509 00:26:59,160 --> 00:27:00,410 little while from now. 510 00:27:00,410 --> 00:27:02,800 Now the overhead again. 511 00:27:02,800 --> 00:27:04,980 Well, in order to set this thing going, I just want to 512 00:27:04,980 --> 00:27:07,410 show you some behavior out of this simulator. 513 00:27:07,410 --> 00:27:10,610 By the way, you may think this simulator is very simple, and 514 00:27:10,610 --> 00:27:12,370 probably too simple to be useful. 515 00:27:12,370 --> 00:27:15,730 The fact of the matter is that this simulator has been used 516 00:27:15,730 --> 00:27:18,680 to manufacture a fairly large computer. 517 00:27:18,680 --> 00:27:22,360 So this is a real live example. 518 00:27:22,360 --> 00:27:24,790 Actually, not exactly this simulator, because I'll tell 519 00:27:24,790 --> 00:27:25,560 you the difference. 520 00:27:25,560 --> 00:27:28,180 The difference is that there were many more different kinds 521 00:27:28,180 --> 00:27:29,820 of primitives. 522 00:27:29,820 --> 00:27:33,200 There's not just the word inverter or and-gate. 523 00:27:33,200 --> 00:27:37,590 There were things like edge-triggered, flip-flops, 524 00:27:37,590 --> 00:27:43,780 and latches, transparent latches, and adders, and 525 00:27:43,780 --> 00:27:45,170 things like that. 526 00:27:45,170 --> 00:27:48,510 And the difficulty with that is that there's pages and 527 00:27:48,510 --> 00:27:51,410 pages of the definitions of all these primitives with 528 00:27:51,410 --> 00:27:54,690 numbers like LS04. 529 00:27:54,690 --> 00:27:56,740 And then there's many more parameters for them. 530 00:27:56,740 --> 00:27:58,480 It's not just one delay. 531 00:27:58,480 --> 00:28:00,020 There's things like set up times and hold 532 00:28:00,020 --> 00:28:01,220 times and all that. 533 00:28:01,220 --> 00:28:03,990 But with the exception of that part of the complexity, the 534 00:28:03,990 --> 00:28:07,580 structure of the simulator that we use for building a 535 00:28:07,580 --> 00:28:12,290 real computer, that works is exactly what 536 00:28:12,290 --> 00:28:15,110 you're seeing here. 537 00:28:15,110 --> 00:28:19,270 Well in any case, what we have here is a few simple things. 538 00:28:19,270 --> 00:28:21,580 Like, there's inverter delays being set up and 539 00:28:21,580 --> 00:28:23,030 making a new agenda. 540 00:28:23,030 --> 00:28:26,470 And then we can make some inputs. 541 00:28:26,470 --> 00:28:28,220 There's input-1, input-2, a sum and a 542 00:28:28,220 --> 00:28:29,460 carry, which are wires. 543 00:28:29,460 --> 00:28:32,560 I'm going to put a special kind of object called a probe 544 00:28:32,560 --> 00:28:37,810 onto, onto some of the wires, onto sum and onto carry. 545 00:28:37,810 --> 00:28:41,590 A probe is a, can object that has the property that when you 546 00:28:41,590 --> 00:28:46,120 change a wire it's attached to, it types out a message. 547 00:28:46,120 --> 00:28:47,970 It's an easy thing to do. 548 00:28:47,970 --> 00:28:50,790 And then once we have that, of course, the way you put the 549 00:28:50,790 --> 00:28:53,040 probe on, the first thing it does, it says, the current 550 00:28:53,040 --> 00:28:59,400 value of the sum at time 0 is 0 because I just noticed it. 551 00:28:59,400 --> 00:29:02,640 And the value of the carry at time 0, this is 552 00:29:02,640 --> 00:29:05,556 the time, is 0. 553 00:29:05,556 --> 00:29:09,620 And then we go off and we build some structure. 554 00:29:09,620 --> 00:29:14,440 Like, we can build a structure here that says you have a 555 00:29:14,440 --> 00:29:18,420 half-adder on input-1, input-2, sum, and carry. 556 00:29:18,420 --> 00:29:20,420 And we're going to set the signal on input-1 to 1. 557 00:29:20,420 --> 00:29:21,880 We do some propagation. 558 00:29:21,880 --> 00:29:25,380 At time 8, which you could see going through this thing if 559 00:29:25,380 --> 00:29:29,520 you wanted to, the new value of sum became 1. 560 00:29:29,520 --> 00:29:31,150 And the thing says I'm done. 561 00:29:31,150 --> 00:29:32,630 That wasn't very interesting. 562 00:29:32,630 --> 00:29:34,150 But we can send it some more signals. 563 00:29:34,150 --> 00:29:36,590 Like, we set-signal on input-2 to be one. 564 00:29:36,590 --> 00:29:39,430 And at that time if we propagate, then it carried at 565 00:29:39,430 --> 00:29:43,280 11, the carry becomes 1, and at 16, the sum's new 566 00:29:43,280 --> 00:29:45,040 value becomes 0. 567 00:29:45,040 --> 00:29:48,060 And you might want to work out that, if you like, about the 568 00:29:48,060 --> 00:29:48,990 digital circuitry. 569 00:29:48,990 --> 00:29:50,620 It's true, and it works. 570 00:29:50,620 --> 00:29:51,535 And it's not very interesting. 571 00:29:51,535 --> 00:29:53,330 But that's the kind of behavior we 572 00:29:53,330 --> 00:29:54,580 get out of this thing. 573 00:29:54,580 --> 00:30:01,830 574 00:30:01,830 --> 00:30:06,550 So what I've shown you right now is a large-scale picture, 575 00:30:06,550 --> 00:30:10,360 how you, at a bigger, big scale, you implement an 576 00:30:10,360 --> 00:30:12,952 event-driven simulation of some sort. 577 00:30:12,952 --> 00:30:16,010 And how you might organize it to have nice hierarchical 578 00:30:16,010 --> 00:30:20,220 structure allowing you to build abstract boxes that you 579 00:30:20,220 --> 00:30:21,225 can instantiate. 580 00:30:21,225 --> 00:30:23,630 But I haven't told you any of the details about how this 581 00:30:23,630 --> 00:30:25,780 agenda and things like that work. 582 00:30:25,780 --> 00:30:28,630 That we'll do next. 583 00:30:28,630 --> 00:30:32,040 And that's going to involve change and mutation of data 584 00:30:32,040 --> 00:30:34,310 and things like that. 585 00:30:34,310 --> 00:30:35,860 Are there any questions now, before I go on? 586 00:30:35,860 --> 00:30:47,160 587 00:30:47,160 --> 00:30:47,550 Thank you. 588 00:30:47,550 --> 00:30:48,800 Let's take a break. 589 00:30:48,800 --> 00:31:28,940 590 00:31:28,940 --> 00:31:35,060 Well, we've been making a simulation. 591 00:31:35,060 --> 00:31:39,360 And the simulation is an event-driven simulation where 592 00:31:39,360 --> 00:31:43,920 the objects in the world are the objects in the computer. 593 00:31:43,920 --> 00:31:46,700 And the changes of state that are happening in the world in 594 00:31:46,700 --> 00:31:53,520 time are organized to be time in the computer, so that if 595 00:31:53,520 --> 00:31:56,430 something happens after something else in the world, 596 00:31:56,430 --> 00:32:00,910 then we have it happen after, after the corresponding events 597 00:32:00,910 --> 00:32:04,420 happen in the same order in the computer. 598 00:32:04,420 --> 00:32:06,070 That's where we have assignments, when 599 00:32:06,070 --> 00:32:08,220 we make that alignment. 600 00:32:08,220 --> 00:32:11,860 Right now I want to show you a way of organizing time, which 601 00:32:11,860 --> 00:32:16,040 is an agenda or priority queue, it's sometimes called. 602 00:32:16,040 --> 00:32:17,990 We'll do some--we'll do a little bit of just 603 00:32:17,990 --> 00:32:19,980 understanding what are the things we need to be able to 604 00:32:19,980 --> 00:32:21,230 do to make agendas. 605 00:32:21,230 --> 00:32:28,330 606 00:32:28,330 --> 00:32:30,310 And so we're going to have--and so right now over 607 00:32:30,310 --> 00:32:31,750 here, I'm going to write down a bunch of primitive 608 00:32:31,750 --> 00:32:35,960 operations for manipulating agendas. 609 00:32:35,960 --> 00:32:38,650 I'm not going to show you the code for them because they're 610 00:32:38,650 --> 00:32:41,300 all very simple, and you've got 611 00:32:41,300 --> 00:32:43,680 listings of all that anyway. 612 00:32:43,680 --> 00:32:44,380 So what do we have? 613 00:32:44,380 --> 00:32:52,880 We have things like make-agenda which produces a 614 00:32:52,880 --> 00:32:54,130 new agenda. 615 00:32:54,130 --> 00:32:59,860 616 00:32:59,860 --> 00:33:10,950 We can ask--we get the current-time of an agenda, 617 00:33:10,950 --> 00:33:12,625 which gives me a number, a time. 618 00:33:12,625 --> 00:33:16,990 619 00:33:16,990 --> 00:33:20,650 We can get--we can ask whether an agenda is empty, 620 00:33:20,650 --> 00:33:21,900 empty-agenda. 621 00:33:21,900 --> 00:33:30,200 622 00:33:30,200 --> 00:33:32,570 And that produces either a true or a false. 623 00:33:32,570 --> 00:33:42,590 624 00:33:42,590 --> 00:33:44,720 We can add an object to an agenda. 625 00:33:44,720 --> 00:33:52,710 626 00:33:52,710 --> 00:33:55,230 Actually, what we add to an agenda is an operation--an 627 00:33:55,230 --> 00:33:56,910 action to be done. 628 00:33:56,910 --> 00:34:03,560 And that takes a time, the action itself, and the agenda 629 00:34:03,560 --> 00:34:04,810 I want to add it to. 630 00:34:04,810 --> 00:34:07,850 631 00:34:07,850 --> 00:34:09,280 That inserts it in the appropriate 632 00:34:09,280 --> 00:34:10,719 place in the agenda. 633 00:34:10,719 --> 00:34:14,850 I can get the first item off an agenda, the first thing I 634 00:34:14,850 --> 00:34:23,259 have to do, which is going to give me an action. 635 00:34:23,259 --> 00:34:26,085 636 00:34:26,085 --> 00:34:29,540 And I can remove the first item from an agenda. 637 00:34:29,540 --> 00:34:31,409 That's what I have to be able to do with agendas. 638 00:34:31,409 --> 00:34:33,020 That is a big complicated mess. 639 00:34:33,020 --> 00:34:42,530 640 00:34:42,530 --> 00:34:43,780 From an agenda. 641 00:34:43,780 --> 00:34:45,530 642 00:34:45,530 --> 00:34:48,040 Well, let's see how we can organize this thing as a data 643 00:34:48,040 --> 00:34:52,528 structure a bit. 644 00:34:52,528 --> 00:34:58,720 Well, an agenda is going to be some kind of list. And it's 645 00:34:58,720 --> 00:35:00,190 going to be a list that I'm going to have 646 00:35:00,190 --> 00:35:01,570 to be able to modify. 647 00:35:01,570 --> 00:35:05,820 So we have to talk about modifying of lists, because 648 00:35:05,820 --> 00:35:09,590 I'm going to add things to it, and delete things from it, and 649 00:35:09,590 --> 00:35:11,070 things like that. 650 00:35:11,070 --> 00:35:13,820 It's organized by time. 651 00:35:13,820 --> 00:35:15,570 It's probably good to keep it in sorted order. 652 00:35:15,570 --> 00:35:18,330 653 00:35:18,330 --> 00:35:22,170 But sometimes there are lots of things that happen at the 654 00:35:22,170 --> 00:35:23,420 same time--approximate same time. 655 00:35:23,420 --> 00:35:26,440 What I have to do is say, group things by the time at 656 00:35:26,440 --> 00:35:29,040 which they're supposed to happen. 657 00:35:29,040 --> 00:35:32,780 So I'm going to make an agenda as a list of segments. 658 00:35:32,780 --> 00:35:36,780 And so I'm going to draw you a data structure for an agenda, 659 00:35:36,780 --> 00:35:39,620 a perfectly reasonable one. 660 00:35:39,620 --> 00:35:41,110 Here's an agenda. 661 00:35:41,110 --> 00:35:42,870 It's a thing that begins with a name. 662 00:35:42,870 --> 00:35:47,630 663 00:35:47,630 --> 00:35:49,940 I'm going to do it right now out of list structure. 664 00:35:49,940 --> 00:35:52,620 665 00:35:52,620 --> 00:35:53,980 It's got a header. 666 00:35:53,980 --> 00:35:55,840 There's a reason for the header. 667 00:35:55,840 --> 00:35:57,630 We're going to see the reason soon. 668 00:35:57,630 --> 00:36:00,680 669 00:36:00,680 --> 00:36:03,750 And it will have a segment. 670 00:36:03,750 --> 00:36:05,620 It will have--it will be a list of segments. 671 00:36:05,620 --> 00:36:08,310 672 00:36:08,310 --> 00:36:13,580 Supposing this agenda has two segments, they're the car's-- 673 00:36:13,580 --> 00:36:18,260 successive car's of this list. Each segment is 674 00:36:18,260 --> 00:36:20,250 going to have a time-- 675 00:36:20,250 --> 00:36:24,160 676 00:36:24,160 --> 00:36:26,900 say for example, 10-- 677 00:36:26,900 --> 00:36:29,060 that says that the things that happen in this 678 00:36:29,060 --> 00:36:33,320 segment are at time 10. 679 00:36:33,320 --> 00:36:36,670 And what I'm going to have in here is another data structure 680 00:36:36,670 --> 00:36:39,490 which I'm not going to describe, which is a queue of 681 00:36:39,490 --> 00:36:42,240 things to do at time 10. 682 00:36:42,240 --> 00:36:43,330 It's a queue. 683 00:36:43,330 --> 00:36:45,130 And we'll talk about that in a second. 684 00:36:45,130 --> 00:36:49,530 But abstractly, the queue is just a list of things to do at 685 00:36:49,530 --> 00:36:50,200 a particular time. 686 00:36:50,200 --> 00:36:53,100 And I can add things to a queue. 687 00:36:53,100 --> 00:36:56,140 This is a queue. 688 00:36:56,140 --> 00:36:59,115 There's a time, there's a segment. 689 00:36:59,115 --> 00:37:02,889 690 00:37:02,889 --> 00:37:06,035 Now, I may have another segment in this agenda. 691 00:37:06,035 --> 00:37:08,940 692 00:37:08,940 --> 00:37:13,410 Supposing this is stuff that happens at time 30. 693 00:37:13,410 --> 00:37:18,020 It has, of course, another queue of things that are 694 00:37:18,020 --> 00:37:23,210 queued up to be done at time 30. 695 00:37:23,210 --> 00:37:24,705 Well, there are various things I have to be 696 00:37:24,705 --> 00:37:27,090 able to do to an agenda. 697 00:37:27,090 --> 00:37:30,410 Supposing I want to add to an agenda another thing to be 698 00:37:30,410 --> 00:37:33,030 done at time 10. 699 00:37:33,030 --> 00:37:34,700 Well, that's not very hard. 700 00:37:34,700 --> 00:37:37,480 I'm going to walk down here, looking for the 701 00:37:37,480 --> 00:37:39,730 segment of time 10. 702 00:37:39,730 --> 00:37:42,930 It is possible that there is no segment of time 10. 703 00:37:42,930 --> 00:37:45,420 We'll cover that case in a second. 704 00:37:45,420 --> 00:37:48,590 But if I find a segment of time 10, then if I want to add 705 00:37:48,590 --> 00:37:51,070 another thing to be done at time 10, I just 706 00:37:51,070 --> 00:37:53,860 increase that queue-- 707 00:37:53,860 --> 00:37:56,290 "just increase" isn't such an obvious idea. 708 00:37:56,290 --> 00:38:01,430 But I increase the things to be done at that time. 709 00:38:01,430 --> 00:38:02,900 Now, supposing I want to add something to be 710 00:38:02,900 --> 00:38:05,140 done at time 20. 711 00:38:05,140 --> 00:38:08,680 There is no segment for time 20. 712 00:38:08,680 --> 00:38:11,340 I'm going to have to create a new segment. 713 00:38:11,340 --> 00:38:13,960 I want my time 20 segment to exist between 714 00:38:13,960 --> 00:38:17,610 time 10 and time 30. 715 00:38:17,610 --> 00:38:20,170 Well, that takes a little work. 716 00:38:20,170 --> 00:38:21,525 I'm going to have to do a CONS. 717 00:38:21,525 --> 00:38:24,260 718 00:38:24,260 --> 00:38:28,690 I'm going to have to make a new element of the agenda 719 00:38:28,690 --> 00:38:29,940 list--list of segments. 720 00:38:29,940 --> 00:38:33,600 721 00:38:33,600 --> 00:38:35,400 I'm going to have to change. 722 00:38:35,400 --> 00:38:37,540 Here's change. 723 00:38:37,540 --> 00:38:42,290 I'm going to have to change the CDR of the CDR of the 724 00:38:42,290 --> 00:38:50,620 agenda to point that a new CONS of the new segment and 725 00:38:50,620 --> 00:38:56,657 the CDR of the CDR of the CDR of the agenda, the CD-D-D-DR. 726 00:38:56,657 --> 00:39:02,470 And this is going to have a new segment now of time 20 727 00:39:02,470 --> 00:39:06,290 with its own queue, which now has one element in it. 728 00:39:06,290 --> 00:39:10,730 729 00:39:10,730 --> 00:39:13,080 If I wanted to add something at the end, I'm going to have 730 00:39:13,080 --> 00:39:20,770 to replace the CDR of this, of this list with something. 731 00:39:20,770 --> 00:39:24,040 We're going to have to change that piece of data structure. 732 00:39:24,040 --> 00:39:27,210 So I'm going to need new primitives for doing this. 733 00:39:27,210 --> 00:39:29,550 But I'm just showing you why I need them. 734 00:39:29,550 --> 00:39:33,390 And finally, if I wanted to add a thing to be done at time 735 00:39:33,390 --> 00:39:41,240 5, I'm going to have to change this one, because I'm going to 736 00:39:41,240 --> 00:39:44,770 have to add it in over here, which is why I planned ahead 737 00:39:44,770 --> 00:39:49,400 and had a header cell, which has a place. 738 00:39:49,400 --> 00:39:50,580 If I'm going to change things, I have to have 739 00:39:50,580 --> 00:39:53,420 places for the change. 740 00:39:53,420 --> 00:39:58,600 I have to have a place to make the change. 741 00:39:58,600 --> 00:40:02,540 If I remove things from the agenda, that's not so hard. 742 00:40:02,540 --> 00:40:04,990 Removing them from the beginning is pretty easy, 743 00:40:04,990 --> 00:40:07,740 which is the only case I have. I can go looking for the 744 00:40:07,740 --> 00:40:11,220 first, the first segment. 745 00:40:11,220 --> 00:40:14,510 I see if it has a non-empty queue. 746 00:40:14,510 --> 00:40:17,610 If it has a non-empty queue, well, I'm going to delete one 747 00:40:17,610 --> 00:40:20,100 element from the queue, like that. 748 00:40:20,100 --> 00:40:23,460 If the queue ever becomes empty, then I have to delete 749 00:40:23,460 --> 00:40:24,220 the whole segment. 750 00:40:24,220 --> 00:40:28,220 And then this, this changes to point to here. 751 00:40:28,220 --> 00:40:30,540 So it's quite a complicated data structure manipulation 752 00:40:30,540 --> 00:40:36,440 going on, the details of which are not really very exciting. 753 00:40:36,440 --> 00:40:38,920 Now, let's talk about queues. 754 00:40:38,920 --> 00:40:41,160 They're similar. 755 00:40:41,160 --> 00:40:44,340 Because each of these agendas has a queue in it. 756 00:40:44,340 --> 00:40:45,590 What's a queue? 757 00:40:45,590 --> 00:40:49,079 758 00:40:49,079 --> 00:40:51,110 A queue is going to have the following primitive 759 00:40:51,110 --> 00:40:52,350 operations. 760 00:40:52,350 --> 00:41:02,170 To make a queue, this gives me a new queue. 761 00:41:02,170 --> 00:41:07,274 762 00:41:07,274 --> 00:41:12,610 I'm going to have to be able to insert into 763 00:41:12,610 --> 00:41:16,850 a queue a new item. 764 00:41:16,850 --> 00:41:24,510 765 00:41:24,510 --> 00:41:27,490 I'm going to have to be able to delete from a queue the 766 00:41:27,490 --> 00:41:28,740 first item in the queue. 767 00:41:28,740 --> 00:41:39,988 768 00:41:39,988 --> 00:41:51,320 And I want to be able to get the first thing in the queue 769 00:41:51,320 --> 00:41:52,890 from some queue. 770 00:41:52,890 --> 00:41:55,140 I also have to be able to test whether a queue is empty. 771 00:41:55,140 --> 00:42:07,110 772 00:42:07,110 --> 00:42:09,710 And when you invent things like this, I want you to be 773 00:42:09,710 --> 00:42:13,220 very careful to use the kinds of conventions I use for 774 00:42:13,220 --> 00:42:15,120 naming things. 775 00:42:15,120 --> 00:42:18,450 Notice that I'm careful to say these change something and 776 00:42:18,450 --> 00:42:19,870 that tests it. 777 00:42:19,870 --> 00:42:24,335 And presumably, I did the same thing over here. 778 00:42:24,335 --> 00:42:29,240 OK, and there should be an empty test over here. 779 00:42:29,240 --> 00:42:31,720 OK, well, how would I make a queue? 780 00:42:31,720 --> 00:42:35,210 A queue wants to be something I can add to at the end of, 781 00:42:35,210 --> 00:42:37,840 and pick up the thing at the beginning of. 782 00:42:37,840 --> 00:42:39,290 I should be able to delete from the beginning 783 00:42:39,290 --> 00:42:41,230 and add to the end. 784 00:42:41,230 --> 00:42:42,400 Well, I'm going to show you a very simple 785 00:42:42,400 --> 00:42:43,740 structure for that. 786 00:42:43,740 --> 00:42:47,080 We can make this out of CONSes as well. 787 00:42:47,080 --> 00:42:49,910 Here's a queue. 788 00:42:49,910 --> 00:42:55,310 It has--it has a queue header, which contains two parts-- 789 00:42:55,310 --> 00:42:59,610 a front pointer and a rear pointer. 790 00:42:59,610 --> 00:43:02,930 791 00:43:02,930 --> 00:43:09,000 And here I have a queue with two items in it. 792 00:43:09,000 --> 00:43:12,095 The first item, I don't know, it's perhaps a 1. 793 00:43:12,095 --> 00:43:16,530 And the second item, I don't know, let's give it a 2. 794 00:43:16,530 --> 00:43:21,160 795 00:43:21,160 --> 00:43:24,550 The reason why I want two pointers in here, a front 796 00:43:24,550 --> 00:43:27,570 pointer and a rear pointer, is so I can add to the end 797 00:43:27,570 --> 00:43:31,850 without having to chase down from the beginning. 798 00:43:31,850 --> 00:43:34,380 So for example, if I wanted to add one more item to this 799 00:43:34,380 --> 00:43:40,380 queue, if I want to add on another item to be worried 800 00:43:40,380 --> 00:43:44,060 about later, all I have to do is make a CONS, which contains 801 00:43:44,060 --> 00:43:47,530 that item, say a 3. 802 00:43:47,530 --> 00:43:51,340 That's for inserting 3 into the queue. 803 00:43:51,340 --> 00:44:00,100 Then I have to change this pointer here to here. 804 00:44:00,100 --> 00:44:04,320 And I have to change this one to point to the new rear. 805 00:44:04,320 --> 00:44:09,120 806 00:44:09,120 --> 00:44:11,990 If I wish to take the first element of the queue, the 807 00:44:11,990 --> 00:44:15,130 first item, I just go chasing down the front pointer until I 808 00:44:15,130 --> 00:44:18,890 find the first one and pick it up. 809 00:44:18,890 --> 00:44:22,560 If I wish to delete the first item from the queue, 810 00:44:22,560 --> 00:44:25,240 delete-queue, all I do is move the front 811 00:44:25,240 --> 00:44:27,450 pointer along this way. 812 00:44:27,450 --> 00:44:31,700 The new front of the queue is now this. 813 00:44:31,700 --> 00:44:34,390 So queues are very simple too. 814 00:44:34,390 --> 00:44:39,690 So what you see now is that I need a certain number of new 815 00:44:39,690 --> 00:44:41,350 primitive operations. 816 00:44:41,350 --> 00:44:42,560 And I'm going to give them some names. 817 00:44:42,560 --> 00:44:45,310 And then we're going to look into how they work, and how 818 00:44:45,310 --> 00:44:47,350 they're used. 819 00:44:47,350 --> 00:44:56,970 We have set the CAR of some pair, or a thing produced by 820 00:44:56,970 --> 00:44:58,940 CONSing, to a new value. 821 00:44:58,940 --> 00:45:02,370 822 00:45:02,370 --> 00:45:09,920 And set the CDR of a pair to a new value. 823 00:45:09,920 --> 00:45:12,680 824 00:45:12,680 --> 00:45:16,030 And then we're going to look into how they work. 825 00:45:16,030 --> 00:45:19,720 I needed setting CAR over here to delete the first 826 00:45:19,720 --> 00:45:20,960 element of the queue. 827 00:45:20,960 --> 00:45:23,470 This is the CAR, and I had to set it. 828 00:45:23,470 --> 00:45:26,300 I had to be able to set the CDR to be able to move the 829 00:45:26,300 --> 00:45:30,160 rear pointer, or to be able to increment the queue here. 830 00:45:30,160 --> 00:45:33,170 All of the operations I did were made out of those that I 831 00:45:33,170 --> 00:45:35,515 just showed you on the, on the last blackboard. 832 00:45:35,515 --> 00:45:38,230 833 00:45:38,230 --> 00:45:38,430 Good. 834 00:45:38,430 --> 00:45:40,357 Let's pause the time, and take a little break then. 835 00:45:40,357 --> 00:46:38,346 836 00:46:38,346 --> 00:46:42,910 When we originally introduced pairs made out of CONS, made 837 00:46:42,910 --> 00:46:48,640 by CONS, we only said a few axioms about them, which were 838 00:46:48,640 --> 00:46:50,040 of the form-- 839 00:46:50,040 --> 00:46:52,010 what were they-- 840 00:46:52,010 --> 00:47:06,040 for all X and Y, the CAR of the CONS of X and Y is X and 841 00:47:06,040 --> 00:47:15,650 the CDR of the CONS of X and Y is Y. Now, these say nothing 842 00:47:15,650 --> 00:47:21,850 about whether a CONS has an identity like a person. 843 00:47:21,850 --> 00:47:25,730 In fact, all they say is something sort of abstract, 844 00:47:25,730 --> 00:47:29,740 that a CONS is the parts it's made out of. 845 00:47:29,740 --> 00:47:32,320 And of course, two things are made out of the same parts, 846 00:47:32,320 --> 00:47:34,990 they're the same, at least from the point of view of 847 00:47:34,990 --> 00:47:37,390 these axioms. 848 00:47:37,390 --> 00:47:39,920 But by introducing assignment-- 849 00:47:39,920 --> 00:47:43,360 in fact, mutable data is a kind of assignment, we have a 850 00:47:43,360 --> 00:47:45,590 set CAR and a set CDR-- 851 00:47:45,590 --> 00:47:48,300 by introducing those, these axioms no longer tell the 852 00:47:48,300 --> 00:47:49,830 whole story. 853 00:47:49,830 --> 00:47:53,250 And they're still true if written exactly like this. 854 00:47:53,250 --> 00:47:56,070 But they don't tell the whole story. 855 00:47:56,070 --> 00:48:01,150 Because if I'm going to set a particular CAR in a particular 856 00:48:01,150 --> 00:48:05,810 CONS, the questions are, well, is that setting all CARs and 857 00:48:05,810 --> 00:48:10,090 all CONSes of the same two things or not? 858 00:48:10,090 --> 00:48:12,610 If I--if we use CONSes to make up things like rational 859 00:48:12,610 --> 00:48:19,540 numbers, or things like 3 over 4, supposing I had two 860 00:48:19,540 --> 00:48:21,570 three-fourths. 861 00:48:21,570 --> 00:48:24,110 Are they the same one-- 862 00:48:24,110 --> 00:48:25,340 or are they different? 863 00:48:25,340 --> 00:48:27,860 Well, in the case of numbers, it doesn't matter. 864 00:48:27,860 --> 00:48:29,410 Because there's no meaning to changing the 865 00:48:29,410 --> 00:48:33,020 denominator of a number. 866 00:48:33,020 --> 00:48:34,670 What you could do is make a number which has a different 867 00:48:34,670 --> 00:48:36,840 denominator. 868 00:48:36,840 --> 00:48:38,980 But the concept of changing a number which has to have a 869 00:48:38,980 --> 00:48:41,570 different denominator is sort of a very weird, and sort of 870 00:48:41,570 --> 00:48:44,770 not supported by what you think of as mathematics. 871 00:48:44,770 --> 00:48:46,570 However, when these CONSes represent things in the 872 00:48:46,570 --> 00:48:50,940 physical world, then changing something like the CAR is like 873 00:48:50,940 --> 00:48:53,690 removing a piece of the fingernail. 874 00:48:53,690 --> 00:48:57,770 And so CONSes have an identity. 875 00:48:57,770 --> 00:49:01,280 Let me show you what I mean about identity, first of all. 876 00:49:01,280 --> 00:49:04,320 Let's do some little example here. 877 00:49:04,320 --> 00:49:15,200 Supposing I define A to the CONS of 1 and 2. 878 00:49:15,200 --> 00:49:18,040 879 00:49:18,040 --> 00:49:22,510 Well, what that means, first of all, is that somewhere in 880 00:49:22,510 --> 00:49:27,590 some environment I've made a symbol A to have a value which 881 00:49:27,590 --> 00:49:33,300 is a pair consisting of pointers to a 1 and a pointer 882 00:49:33,300 --> 00:49:38,120 to a 2, just like that. 883 00:49:38,120 --> 00:49:47,220 Now, supposing I also say define B to be the CONS-- 884 00:49:47,220 --> 00:49:53,320 885 00:49:53,320 --> 00:49:58,240 it doesn't matter, but I like it better, it's prettier-- 886 00:49:58,240 --> 00:50:03,970 of A and A. 887 00:50:03,970 --> 00:50:07,840 Well, first of all, I'm using the name A twice. 888 00:50:07,840 --> 00:50:09,100 At this moment, I'm going to think of 889 00:50:09,100 --> 00:50:11,300 CONSes as having identity. 890 00:50:11,300 --> 00:50:13,690 This is the same one. 891 00:50:13,690 --> 00:50:19,200 And so what that means is I make another pair, which I'm 892 00:50:19,200 --> 00:50:29,120 going to call B. And it contains two pointers to A. At 893 00:50:29,120 --> 00:50:33,260 this point, I have three names for this object. 894 00:50:33,260 --> 00:50:34,790 A is its name. 895 00:50:34,790 --> 00:50:37,230 The CAR of B is its name. 896 00:50:37,230 --> 00:50:39,360 And the CDR of B is its name. 897 00:50:39,360 --> 00:50:41,150 It has several aliases, they're called. 898 00:50:41,150 --> 00:50:44,230 899 00:50:44,230 --> 00:51:01,860 Now, supposing I do something like set-the-CAR, the CAR of 900 00:51:01,860 --> 00:51:07,880 the CAR of B to 3. 901 00:51:07,880 --> 00:51:12,750 902 00:51:12,750 --> 00:51:17,830 What that means is I find the CAR of B, that's this. 903 00:51:17,830 --> 00:51:20,935 I set the CAR of that to be 3, changing this. 904 00:51:20,935 --> 00:51:24,760 905 00:51:24,760 --> 00:51:29,940 I've changed A. If I were to ask what's the 906 00:51:29,940 --> 00:51:35,340 CAR of A--of A now? 907 00:51:35,340 --> 00:51:42,250 I would get out 3, even though here we see that A was the 908 00:51:42,250 --> 00:51:45,290 CONS of 1 and 2. 909 00:51:45,290 --> 00:51:48,400 I caused A to change by changing B. 910 00:51:48,400 --> 00:51:52,010 There is sharing here. 911 00:51:52,010 --> 00:51:54,240 That's sometimes what we want. 912 00:51:54,240 --> 00:51:56,400 Surely in the queues and things like that, that's 913 00:51:56,400 --> 00:51:59,560 exactly what we defined our--organized our data 914 00:51:59,560 --> 00:52:01,790 structures to facilitate-- 915 00:52:01,790 --> 00:52:04,350 sharing. 916 00:52:04,350 --> 00:52:08,950 But inadvertent sharing, unanticipated interactions 917 00:52:08,950 --> 00:52:12,925 between objects, is the source of most of the bugs that occur 918 00:52:12,925 --> 00:52:17,820 in complicated programs. So by introducing this possibility 919 00:52:17,820 --> 00:52:22,570 of things having identity and sharing and having multiple 920 00:52:22,570 --> 00:52:25,190 names for the same thing, we get a lot of power. 921 00:52:25,190 --> 00:52:27,390 But we're going to pay for it with lots of 922 00:52:27,390 --> 00:52:28,640 complexity and bugs. 923 00:52:28,640 --> 00:52:32,190 924 00:52:32,190 --> 00:52:35,430 So also, for example, if I just looked at this just to 925 00:52:35,430 --> 00:52:43,370 drive that home, the CADR of B, which has nothing to do 926 00:52:43,370 --> 00:52:46,560 with even the CAR of B, apparently. 927 00:52:46,560 --> 00:52:49,350 The CADR of B, what's that? 928 00:52:49,350 --> 00:52:53,560 Take that CDR of B and now take the CAR of that. 929 00:52:53,560 --> 00:52:56,480 Oh, that's 3 also. 930 00:52:56,480 --> 00:53:01,120 So I can have non-local interactions by sharing. 931 00:53:01,120 --> 00:53:02,480 And I have to be very careful of that. 932 00:53:02,480 --> 00:53:06,640 933 00:53:06,640 --> 00:53:10,530 Well, so far, of course, it seems I've introduced several 934 00:53:10,530 --> 00:53:13,030 different assignment operators-- 935 00:53:13,030 --> 00:53:19,480 set, set CAR, set CDR. Well, maybe I should just get rid of 936 00:53:19,480 --> 00:53:22,820 set CAR and set CDR. Maybe they're not worthwhile. 937 00:53:22,820 --> 00:53:25,680 Well, the answer is that once you let the camel's nose into 938 00:53:25,680 --> 00:53:27,170 the tent, the rest of him follows. 939 00:53:27,170 --> 00:53:30,160 940 00:53:30,160 --> 00:53:34,600 All I have to have is set, and I can make all of the--all of 941 00:53:34,600 --> 00:53:35,850 the bad things that can happen. 942 00:53:35,850 --> 00:53:38,550 943 00:53:38,550 --> 00:53:40,690 Let's play with that a little bit. 944 00:53:40,690 --> 00:53:45,330 A couple of days ago, when we introduced compound data, you 945 00:53:45,330 --> 00:53:49,980 saw Hal show you a definition of CONS in terms 946 00:53:49,980 --> 00:53:52,480 of a message acceptor. 947 00:53:52,480 --> 00:53:57,280 I'm going to show you even a more horrible thing, a 948 00:53:57,280 --> 00:54:04,440 definition of CONS in terms of nothing but air, hot air. 949 00:54:04,440 --> 00:54:07,640 What is the definition of CONS, of the old functional 950 00:54:07,640 --> 00:54:13,330 kind, in terms of purely lambdic expressions, 951 00:54:13,330 --> 00:54:14,580 procedures? 952 00:54:14,580 --> 00:54:17,190 953 00:54:17,190 --> 00:54:20,630 Because I'm going to then modify this definition to get 954 00:54:20,630 --> 00:54:25,020 assignment to be only one kind of assignment, to get rid of 955 00:54:25,020 --> 00:54:28,580 the set CAR and set CDR in terms of set. 956 00:54:28,580 --> 00:54:41,020 So what if I define CONS of X and Y to be a procedure of one 957 00:54:41,020 --> 00:54:44,310 argument called a message M, which calls that 958 00:54:44,310 --> 00:54:46,320 message on X and Y? 959 00:54:46,320 --> 00:54:51,120 960 00:54:51,120 --> 00:54:54,080 This [? idea ?] was invented by Alonzo Church, who was the 961 00:54:54,080 --> 00:54:56,180 greatest programmer of the 20th century, although he 962 00:54:56,180 --> 00:54:57,870 never saw a computer. 963 00:54:57,870 --> 00:54:59,130 It was done in the 1930s. 964 00:54:59,130 --> 00:55:02,220 He was a logician, I suppose at Princeton at the time. 965 00:55:02,220 --> 00:55:08,660 966 00:55:08,660 --> 00:55:15,690 Define CAR of X to be the result of applying X to that 967 00:55:15,690 --> 00:55:24,000 procedure of two arguments, A and D, which selects A. I will 968 00:55:24,000 --> 00:55:36,410 define CDR of X to be that procedure, to be the result of 969 00:55:36,410 --> 00:55:46,670 applying X to that procedure of A and D, which selects D. 970 00:55:46,670 --> 00:55:50,510 Now, you may not recognize this as CAR, CDR, and CONS. 971 00:55:50,510 --> 00:55:52,690 But I'm going to demonstrate to you that it satisfies the 972 00:55:52,690 --> 00:55:55,210 original axioms, just once. 973 00:55:55,210 --> 00:55:58,290 And then we're going to do some playing of games. 974 00:55:58,290 --> 00:56:09,695 Consider the problem CAR of CONS of, say, 35 and 47. 975 00:56:09,695 --> 00:56:11,120 Well, what is that? 976 00:56:11,120 --> 00:56:14,080 It is the result of taking car of the result of substituting 977 00:56:14,080 --> 00:56:19,710 35 and 47 for X and Y in the body of this. 978 00:56:19,710 --> 00:56:20,690 Well, that's easy enough. 979 00:56:20,690 --> 00:56:27,780 That's CAR of the result of substituting into lambda of M, 980 00:56:27,780 --> 00:56:35,750 M of 35 and 47. 981 00:56:35,750 --> 00:56:38,680 Well, what this is, is the result of substituting this 982 00:56:38,680 --> 00:56:42,830 object for X in the body of that. 983 00:56:42,830 --> 00:56:48,930 So that's just lambda of M-- 984 00:56:48,930 --> 00:56:51,090 that's substituted, because this object is being 985 00:56:51,090 --> 00:56:54,980 substituted for X, which is the beginning of a list, 986 00:56:54,980 --> 00:56:57,260 lambda of M-- 987 00:56:57,260 --> 00:57:07,570 M of 35 and 47, applied to that procedure of A and D, 988 00:57:07,570 --> 00:57:12,280 which gives me A. Well, that's the result of substituting 989 00:57:12,280 --> 00:57:15,840 this for M here. 990 00:57:15,840 --> 00:57:22,320 So that's the same thing as lambda of A, D, A, 991 00:57:22,320 --> 00:57:26,026 applied to 35 and 47. 992 00:57:26,026 --> 00:57:27,560 Oh, well that's 35. 993 00:57:27,560 --> 00:57:36,000 That's substituting 35 for A and for 47 for D in A. So I 994 00:57:36,000 --> 00:57:40,720 don't need any data at all, not even numbers. 995 00:57:40,720 --> 00:57:42,640 This is Alonso Church's hack. 996 00:57:42,640 --> 00:57:52,420 997 00:57:52,420 --> 00:57:56,760 Well, now we're going to do something nasty to him. 998 00:57:56,760 --> 00:57:58,860 Being a logician, he wouldn't like this. 999 00:57:58,860 --> 00:58:03,260 But as programmers, let's look at the overhead. 1000 00:58:03,260 --> 00:58:05,390 And here we go. 1001 00:58:05,390 --> 00:58:09,570 I'm going to change the definition of CONS. 1002 00:58:09,570 --> 00:58:14,520 It's almost the same as Alonzo Church's, but not quite. 1003 00:58:14,520 --> 00:58:16,070 What do we have here? 1004 00:58:16,070 --> 00:58:20,880 The CONS of two arguments, X and Y, is going to be that 1005 00:58:20,880 --> 00:58:25,020 procedure of one argument M, which supplies M to X and Y as 1006 00:58:25,020 --> 00:58:30,900 before, but also to two permissions, the permission to 1007 00:58:30,900 --> 00:58:35,030 set X to N and the permission to set Y to N, given that I 1008 00:58:35,030 --> 00:58:40,940 have an N. 1009 00:58:40,940 --> 00:58:44,040 So besides the things that I had here in Church's 1010 00:58:44,040 --> 00:58:50,990 definition, what I have is that the thing that CONS 1011 00:58:50,990 --> 00:58:55,900 returns will apply its argument to not just the 1012 00:58:55,900 --> 00:59:00,210 values of the X and Y that the CONS is made of, but also 1013 00:59:00,210 --> 00:59:03,365 permissions to set X and Y to new values. 1014 00:59:03,365 --> 00:59:06,540 1015 00:59:06,540 --> 00:59:09,220 Now, of course, just as before, CAR 1016 00:59:09,220 --> 00:59:11,690 is exactly the same. 1017 00:59:11,690 --> 00:59:14,980 The CAR of X is nothing more than applying X, as in 1018 00:59:14,980 --> 00:59:18,110 Church's definition, to a procedure, in this case, of 1019 00:59:18,110 --> 00:59:22,550 four arguments, which selects out the first one. 1020 00:59:22,550 --> 00:59:28,750 And just as we did before, that will be the value of X 1021 00:59:28,750 --> 00:59:33,470 that was contained in the procedure which is the result 1022 00:59:33,470 --> 00:59:36,260 of evaluating this lambda expression in the environment 1023 00:59:36,260 --> 00:59:37,920 where X and Y are defined over here. 1024 00:59:37,920 --> 00:59:41,940 1025 00:59:41,940 --> 00:59:45,640 That's the value of CONS. 1026 00:59:45,640 --> 00:59:47,730 Now, however, the exciting part. 1027 00:59:47,730 --> 00:59:48,960 CDR, of course, is the same. 1028 00:59:48,960 --> 00:59:54,270 The exciting part, set CAR and set CDR. Well, they're nothing 1029 00:59:54,270 --> 00:59:55,800 very complicated anymore. 1030 00:59:55,800 --> 01:00:02,700 Set CAR of a CONS X to a new value Y is nothing more than 1031 01:00:02,700 --> 01:00:06,097 applying that CONS, which is the procedure of four--the 1032 01:00:06,097 --> 01:00:09,160 procedure of one argument which applies its argument to 1033 01:00:09,160 --> 01:00:15,950 four things, to a procedure which is of four arguments-- 1034 01:00:15,950 --> 01:00:19,450 the value of X, the value of Y, permission to set X, the 1035 01:00:19,450 --> 01:00:21,390 permission to set Y-- 1036 01:00:21,390 --> 01:00:23,610 and using it--using that permission to set 1037 01:00:23,610 --> 01:00:26,150 X to the new value. 1038 01:00:26,150 --> 01:00:31,650 1039 01:00:31,650 --> 01:00:33,540 And similarly, set-cdr is the same thing. 1040 01:00:33,540 --> 01:00:36,120 1041 01:00:36,120 --> 01:00:38,470 So what you've just seen is that I didn't introduce any 1042 01:00:38,470 --> 01:00:40,470 new primitives at all. 1043 01:00:40,470 --> 01:00:43,340 Whether or not I want to implement it this way is a 1044 01:00:43,340 --> 01:00:45,340 matter of engineering. 1045 01:00:45,340 --> 01:00:48,080 And the answer is of course I don't implement it this way 1046 01:00:48,080 --> 01:00:51,680 for reasons that have to do with engineering. 1047 01:00:51,680 --> 01:00:55,170 However in principle, logically, once I introduced 1048 01:00:55,170 --> 01:00:57,515 one assignment operator, I've assigned--I've 1049 01:00:57,515 --> 01:00:58,765 introduced them all. 1050 01:00:58,765 --> 01:01:05,420 1051 01:01:05,420 --> 01:01:06,670 Are there any questions? 1052 01:01:06,670 --> 01:01:09,200 1053 01:01:09,200 --> 01:01:12,040 Yes, David. 1054 01:01:12,040 --> 01:01:14,860 AUDIENCE: I can follow you up until you get--I can follow 1055 01:01:14,860 --> 01:01:15,740 all of that. 1056 01:01:15,740 --> 01:01:19,760 But when we bring in the permissions, defining CONS in 1057 01:01:19,760 --> 01:01:24,210 terms of the lambda N, I don't follow where N gets passed. 1058 01:01:24,210 --> 01:01:25,100 PROFESSOR: Oh, I'm sorry. 1059 01:01:25,100 --> 01:01:26,340 I'll show you. 1060 01:01:26,340 --> 01:01:27,360 Let's follow it. 1061 01:01:27,360 --> 01:01:29,180 Of course, we could do it on the blackboard. 1062 01:01:29,180 --> 01:01:30,170 It's not so hard. 1063 01:01:30,170 --> 01:01:32,450 But it's also easy here. 1064 01:01:32,450 --> 01:01:38,520 Supposing I wish to set-cdr of X to Y. See that right there. 1065 01:01:38,520 --> 01:01:43,680 set-cdr of X to Y. X is presumably a CONS, a thing 1066 01:01:43,680 --> 01:01:46,890 resulting from evaluating CONS. 1067 01:01:46,890 --> 01:01:54,030 Therefore X comes from a place over here, that that X is of 1068 01:01:54,030 --> 01:01:58,110 the result of evaluating this lambda expression. 1069 01:01:58,110 --> 01:01:59,380 Right? 1070 01:01:59,380 --> 01:02:04,475 That when I evaluated that lambda expression, I evaluated 1071 01:02:04,475 --> 01:02:07,700 it in an environment where the arguments 1072 01:02:07,700 --> 01:02:08,950 to CONS were defined. 1073 01:02:08,950 --> 01:02:11,750 1074 01:02:11,750 --> 01:02:14,530 That means that as free variables in this lambda 1075 01:02:14,530 --> 01:02:18,670 expression, there is the--there are in the frame, 1076 01:02:18,670 --> 01:02:23,860 which is the parent frame of this lambda expression, the 1077 01:02:23,860 --> 01:02:27,470 procedure resulting from this lambda expression, X and Y 1078 01:02:27,470 --> 01:02:29,250 have places. 1079 01:02:29,250 --> 01:02:31,910 And it's possible to set them. 1080 01:02:31,910 --> 01:02:35,380 I set them to an N, which is the argument of the 1081 01:02:35,380 --> 01:02:37,010 permission. 1082 01:02:37,010 --> 01:02:43,650 The permission is a procedure which is passed to M, which is 1083 01:02:43,650 --> 01:02:47,940 the argument that the CONS object gets passed. 1084 01:02:47,940 --> 01:02:54,020 Now, let's go back here in the set-cdr The CONS object, which 1085 01:02:54,020 --> 01:02:56,230 is the first argument of set-cdr 1086 01:02:56,230 --> 01:02:57,480 gets passed an argument. 1087 01:02:57,480 --> 01:03:00,260 1088 01:03:00,260 --> 01:03:02,910 That--there's a procedure of four things, indeed, because 1089 01:03:02,910 --> 01:03:05,780 that's the same thing as this M over here, which is applied 1090 01:03:05,780 --> 01:03:07,920 to four objects. 1091 01:03:07,920 --> 01:03:12,970 The object over here, SD, is, in fact, this permission. 1092 01:03:12,970 --> 01:03:15,470 1093 01:03:15,470 --> 01:03:19,930 When I use SD, I apply it to Y, right there. 1094 01:03:19,930 --> 01:03:22,910 1095 01:03:22,910 --> 01:03:25,740 So that comes from this. 1096 01:03:25,740 --> 01:03:27,410 AUDIENCE: So what do you-- 1097 01:03:27,410 --> 01:03:31,420 PROFESSOR: So to finish that, the N that was here is the Y 1098 01:03:31,420 --> 01:03:34,160 which is here. 1099 01:03:34,160 --> 01:03:34,810 How's that? 1100 01:03:34,810 --> 01:03:35,750 AUDIENCE: Right, OK. 1101 01:03:35,750 --> 01:03:40,240 Now, when you do a set-cdr, X is the value the 1102 01:03:40,240 --> 01:03:41,970 CDR is going to become. 1103 01:03:41,970 --> 01:03:44,742 PROFESSOR: The X over here. 1104 01:03:44,742 --> 01:03:46,200 I'm sorry, that's not true. 1105 01:03:46,200 --> 01:03:48,720 The X is--set-cdr has two arguments-- 1106 01:03:48,720 --> 01:03:56,150 The CONS I'm changing and the value I'm changing it to. 1107 01:03:56,150 --> 01:03:58,320 So you have them backwards, that's all. 1108 01:03:58,320 --> 01:04:01,750 1109 01:04:01,750 --> 01:04:03,000 Are there any other questions? 1110 01:04:03,000 --> 01:04:07,880 1111 01:04:07,880 --> 01:04:08,640 Well, thank you. 1112 01:04:08,640 --> 01:04:09,890 It's time for lunch. 1113 01:04:09,890 --> 01:04:28,970 ================================================ FILE: SrtEN/lec6a_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:18,550 1 00:00:18,550 --> 00:00:21,230 PROFESSOR: Well, last time Gerry really let the cat out 2 00:00:21,230 --> 00:00:22,230 of the bag. 3 00:00:22,230 --> 00:00:26,350 He introduced the idea of assignment. 4 00:00:26,350 --> 00:00:33,405 Assignment and state. 5 00:00:33,405 --> 00:00:37,620 6 00:00:37,620 --> 00:00:41,500 And as we started to see, the implications of introducing 7 00:00:41,500 --> 00:00:43,860 assignment and state into the language are absolutely 8 00:00:43,860 --> 00:00:45,350 frightening. 9 00:00:45,350 --> 00:00:47,240 First of all, the substitution model of 10 00:00:47,240 --> 00:00:48,865 evaluation breaks down. 11 00:00:48,865 --> 00:00:52,210 And we have to use this much more complicated environment 12 00:00:52,210 --> 00:00:53,780 model and this very mechanistic thing with 13 00:00:53,780 --> 00:00:56,530 diagrams, even to say what statements in the programming 14 00:00:56,530 --> 00:00:58,130 language mean. 15 00:00:58,130 --> 00:01:00,260 And that's not a mere technical point. 16 00:01:00,260 --> 00:01:03,090 See, it's not that we had this particular substitution model 17 00:01:03,090 --> 00:01:05,200 and, well, it doesn't quite work, so we have to do 18 00:01:05,200 --> 00:01:05,870 something else. 19 00:01:05,870 --> 00:01:10,730 It's that nothing like the substitution model can work. 20 00:01:10,730 --> 00:01:15,950 Because suddenly, a variable is not just something that 21 00:01:15,950 --> 00:01:18,080 stands for a value. 22 00:01:18,080 --> 00:01:22,390 A variable now has to somehow specify a place 23 00:01:22,390 --> 00:01:23,630 that holds a value. 24 00:01:23,630 --> 00:01:25,885 And the value that's in that place can change. 25 00:01:25,885 --> 00:01:30,280 26 00:01:30,280 --> 00:01:39,110 Or for instance, an expression like f of x might have a side 27 00:01:39,110 --> 00:01:40,410 effect in it. 28 00:01:40,410 --> 00:01:44,160 So if we say f of x and it has some value, and then later we 29 00:01:44,160 --> 00:01:48,890 say f of x again, we might get a different value 30 00:01:48,890 --> 00:01:49,730 depending on the order. 31 00:01:49,730 --> 00:01:52,780 So suddenly, we have to think not only about values but 32 00:01:52,780 --> 00:01:54,030 about time. 33 00:01:54,030 --> 00:01:57,970 34 00:01:57,970 --> 00:02:02,070 And then things like pairs are no longer just their CARs and 35 00:02:02,070 --> 00:02:02,520 their CDRs. 36 00:02:02,520 --> 00:02:06,310 A pair now is not quite its CAR and its CDR. It's rather 37 00:02:06,310 --> 00:02:08,449 its identity. 38 00:02:08,449 --> 00:02:11,650 So a pair has identity. 39 00:02:11,650 --> 00:02:12,900 It's an object. 40 00:02:12,900 --> 00:02:21,330 41 00:02:21,330 --> 00:02:26,280 And two pairs that have the same CAR and CDR might be the 42 00:02:26,280 --> 00:02:29,650 same or different, because suddenly we have to worry 43 00:02:29,650 --> 00:02:30,900 about sharing. 44 00:02:30,900 --> 00:02:34,960 45 00:02:34,960 --> 00:02:38,910 So all of these things enter as soon as we introduce 46 00:02:38,910 --> 00:02:40,480 assignment. 47 00:02:40,480 --> 00:02:43,340 See, this is a really far cry from where we started with 48 00:02:43,340 --> 00:02:45,400 substitution. 49 00:02:45,400 --> 00:02:50,420 It's a technically harder way of looking at things because 50 00:02:50,420 --> 00:02:52,710 we have to think more mechanistically about our 51 00:02:52,710 --> 00:02:53,540 programming language. 52 00:02:53,540 --> 00:02:55,960 We can't just think about it as mathematics. 53 00:02:55,960 --> 00:02:59,860 It's philosophically harder, because suddenly there are all 54 00:02:59,860 --> 00:03:02,020 these funny issues about what does it mean that something 55 00:03:02,020 --> 00:03:04,050 changes or that two things are the same. 56 00:03:04,050 --> 00:03:07,910 And also, it's programming harder, because as Gerry 57 00:03:07,910 --> 00:03:10,070 showed last time, there are all these bugs having to do 58 00:03:10,070 --> 00:03:14,420 with bad sequencing and aliasing that just don't exist 59 00:03:14,420 --> 00:03:18,210 in a language where we don't worry about objects. 60 00:03:18,210 --> 00:03:23,635 Well, how'd we get into this mess? 61 00:03:23,635 --> 00:03:27,500 Remember what we did, the reason we got into this is 62 00:03:27,500 --> 00:03:35,750 because we were looking to build modular systems. We 63 00:03:35,750 --> 00:03:40,250 wanted to build systems that fall apart into chunks that 64 00:03:40,250 --> 00:03:42,760 seem natural. 65 00:03:42,760 --> 00:03:46,260 So for instance, we want to take a random number generator 66 00:03:46,260 --> 00:03:48,660 and package up the state of that random number generator 67 00:03:48,660 --> 00:03:52,840 inside of it so that we can separate the idea of picking 68 00:03:52,840 --> 00:03:56,640 random numbers from the general Monte Carlo strategy 69 00:03:56,640 --> 00:03:59,740 of estimating something and separate that from the 70 00:03:59,740 --> 00:04:03,060 particular way that you work with random numbers in that 71 00:04:03,060 --> 00:04:06,980 formula developed by Cesaro for pi. 72 00:04:06,980 --> 00:04:11,400 And similarly, when we go off and construct some models of 73 00:04:11,400 --> 00:04:15,440 things, if we go off and model a system that we see in the 74 00:04:15,440 --> 00:04:19,050 real world, we'd like our program to break into natural 75 00:04:19,050 --> 00:04:22,310 pieces, pieces that mirror the parts of the system that we 76 00:04:22,310 --> 00:04:24,900 see in the real world. 77 00:04:24,900 --> 00:04:28,780 So for example, if we look at a digital circuit, we say, 78 00:04:28,780 --> 00:04:33,910 gee, there's a circuit and it has a piece and 79 00:04:33,910 --> 00:04:35,160 it has another piece. 80 00:04:35,160 --> 00:04:40,100 81 00:04:40,100 --> 00:04:43,580 And these different pieces sort of have identity. 82 00:04:43,580 --> 00:04:45,550 They have state. 83 00:04:45,550 --> 00:04:48,580 And the state sits on these wires. 84 00:04:48,580 --> 00:04:51,020 And we think of this piece as an object that's different 85 00:04:51,020 --> 00:04:52,610 from that as an object. 86 00:04:52,610 --> 00:04:54,400 And when we watch the system change, we think about a 87 00:04:54,400 --> 00:04:57,500 signal coming in here and changing a state that might be 88 00:04:57,500 --> 00:04:59,860 here and going here and interacting with a state that 89 00:04:59,860 --> 00:05:02,170 might be stored there, and so on and so on. 90 00:05:02,170 --> 00:05:06,860 91 00:05:06,860 --> 00:05:12,760 So what we'd like is we'd like to build in the computer 92 00:05:12,760 --> 00:05:17,340 systems that fall into pieces that mirror our view of 93 00:05:17,340 --> 00:05:19,870 reality, of the way that the actual systems we're modeling 94 00:05:19,870 --> 00:05:23,365 seem to fall into pieces. 95 00:05:23,365 --> 00:05:28,970 Well, maybe the reason that building systems like this 96 00:05:28,970 --> 00:05:31,600 seems to introduce such technical complications has 97 00:05:31,600 --> 00:05:33,610 nothing to do with computers. 98 00:05:33,610 --> 00:05:37,960 See, maybe the real reason that we pay such a price to 99 00:05:37,960 --> 00:05:41,910 write programs that mirror our view of reality is that we 100 00:05:41,910 --> 00:05:44,550 have the wrong view of reality. 101 00:05:44,550 --> 00:05:47,460 See, maybe time is just an illusion, and 102 00:05:47,460 --> 00:05:50,150 nothing ever changes. 103 00:05:50,150 --> 00:05:52,910 See, for example, if I take this chalk, and we say, gee, 104 00:05:52,910 --> 00:05:55,820 this is an object and it has a state. 105 00:05:55,820 --> 00:05:59,710 At each moment it has a position and a velocity. 106 00:05:59,710 --> 00:06:01,240 And if we do something, that state can change. 107 00:06:01,240 --> 00:06:04,340 108 00:06:04,340 --> 00:06:07,900 But if you studied any relativity, for instance, you 109 00:06:07,900 --> 00:06:09,760 know that you don't think of the path of that chalk as 110 00:06:09,760 --> 00:06:11,340 something that goes on instant by instant. 111 00:06:11,340 --> 00:06:13,870 It's more insightful to think of that whole chalk's 112 00:06:13,870 --> 00:06:16,020 existence as a path in space-time. 113 00:06:16,020 --> 00:06:18,040 that's all splayed out. 114 00:06:18,040 --> 00:06:19,840 There aren't individual positions and velocities. 115 00:06:19,840 --> 00:06:24,640 There's just its unchanging existence in space-time. 116 00:06:24,640 --> 00:06:28,080 Similarly, if we look at this electrical system, if we 117 00:06:28,080 --> 00:06:32,450 imagine this electrical system is implementing some sort of 118 00:06:32,450 --> 00:06:35,730 signal processing system, the signal processing engineer who 119 00:06:35,730 --> 00:06:39,010 put that thing together doesn't think of it as, well, 120 00:06:39,010 --> 00:06:41,490 at each instance there's a voltage coming in. 121 00:06:41,490 --> 00:06:43,340 And that translates into something. 122 00:06:43,340 --> 00:06:46,400 And that affects the state over here, which changes the 123 00:06:46,400 --> 00:06:46,810 state over here. 124 00:06:46,810 --> 00:06:49,060 Nobody putting together a signal processing system 125 00:06:49,060 --> 00:06:50,420 thinks about it like that. 126 00:06:50,420 --> 00:06:56,830 Instead, you say there's this signal that's 127 00:06:56,830 --> 00:06:58,060 splayed out over time. 128 00:06:58,060 --> 00:07:01,100 And if this is acting as a filter, this whole thing 129 00:07:01,100 --> 00:07:09,570 transforms this whole thing for some sort of other output. 130 00:07:09,570 --> 00:07:11,790 You don't think of it as what's happening instant by 131 00:07:11,790 --> 00:07:14,160 instant as the state of these things. 132 00:07:14,160 --> 00:07:17,990 And somehow you think of this box as a whole thing, not as 133 00:07:17,990 --> 00:07:20,980 little pieces sending messages of state to each other at 134 00:07:20,980 --> 00:07:22,230 particular instants. 135 00:07:22,230 --> 00:07:28,250 136 00:07:28,250 --> 00:07:30,130 Well, today we're going to look at another way to 137 00:07:30,130 --> 00:07:34,260 decompose systems that's more like the signal processing 138 00:07:34,260 --> 00:07:37,050 engineer's view of the world than it is like thinking about 139 00:07:37,050 --> 00:07:41,130 objects that communicate sending messages. 140 00:07:41,130 --> 00:07:43,310 That's called stream processing. 141 00:07:43,310 --> 00:07:54,570 142 00:07:54,570 --> 00:08:01,790 And we're going to start by showing how we can make our 143 00:08:01,790 --> 00:08:08,550 programs more uniform and see a lot more commonality if we 144 00:08:08,550 --> 00:08:12,490 throw out of these programs what you might say is an 145 00:08:12,490 --> 00:08:17,210 inordinate concern with worrying about time. 146 00:08:17,210 --> 00:08:19,910 Let me start by comparing two procedures. 147 00:08:19,910 --> 00:08:23,260 148 00:08:23,260 --> 00:08:25,690 The first one does this. 149 00:08:25,690 --> 00:08:27,770 We imagine that there's a tree. 150 00:08:27,770 --> 00:08:30,400 151 00:08:30,400 --> 00:08:33,179 Say there's a tree of integers. 152 00:08:33,179 --> 00:08:34,429 It's a binary tree. 153 00:08:34,429 --> 00:08:39,100 154 00:08:39,100 --> 00:08:40,230 So it looks like this. 155 00:08:40,230 --> 00:08:44,990 And there's integers in each of the nodes. 156 00:08:44,990 --> 00:08:51,000 And what we would like to compute is for each odd number 157 00:08:51,000 --> 00:08:54,210 sitting here, we'd like to find the square and then sum 158 00:08:54,210 --> 00:08:57,210 up all those squares. 159 00:08:57,210 --> 00:08:59,480 Well, that should be a familiar kind of thing. 160 00:08:59,480 --> 00:09:02,930 There's a recursive strategy for doing it. 161 00:09:02,930 --> 00:09:04,880 We look at each leaf, and either it's going to 162 00:09:04,880 --> 00:09:06,690 contribute the square of the number if it's odd 163 00:09:06,690 --> 00:09:08,680 or 0 if it's even. 164 00:09:08,680 --> 00:09:13,280 And then recursively, we can say at each tree, the sum of 165 00:09:13,280 --> 00:09:15,330 all of them is the sum coming from the right branch and the 166 00:09:15,330 --> 00:09:17,640 left branch, and recursively down through the nodes. 167 00:09:17,640 --> 00:09:20,360 And that's a familiar way of thinking about programming. 168 00:09:20,360 --> 00:09:23,960 Let's actually look at that on the slide. 169 00:09:23,960 --> 00:09:27,960 We say to sum the odd squares in a tree, well, there's a 170 00:09:27,960 --> 00:09:30,520 test. Either it's a leaf node, and we're going to check to 171 00:09:30,520 --> 00:09:34,710 see if it's an integer, and then either it's odd, in which 172 00:09:34,710 --> 00:09:37,160 we take the square, or else it's 0. 173 00:09:37,160 --> 00:09:40,260 And then the sum of the whole thing is the sum coming from 174 00:09:40,260 --> 00:09:42,120 the left branch and the right branch. 175 00:09:42,120 --> 00:09:46,340 176 00:09:46,340 --> 00:09:51,560 OK, well, let me contrast that with a second problem. 177 00:09:51,560 --> 00:09:55,810 Suppose I give you an integer n, and then some function to 178 00:09:55,810 --> 00:09:59,270 compute of the first of each integer in 1 through n. 179 00:09:59,270 --> 00:10:01,810 And then I want to collect together in a list all those 180 00:10:01,810 --> 00:10:05,600 function values that satisfy some property. 181 00:10:05,600 --> 00:10:06,880 That's a general kind of thing. 182 00:10:06,880 --> 00:10:09,750 Let's say to be specific, let's imagine that for each 183 00:10:09,750 --> 00:10:11,270 integer, k, we're going to compute 184 00:10:11,270 --> 00:10:14,210 the k Fibonacci number. 185 00:10:14,210 --> 00:10:17,550 And then we'll see which of those are odd and assemble 186 00:10:17,550 --> 00:10:19,050 those into a list. 187 00:10:19,050 --> 00:10:20,710 So here's a procedure that does that. 188 00:10:20,710 --> 00:10:23,730 189 00:10:23,730 --> 00:10:26,240 Find the odd Fibonacci numbers among the first n. 190 00:10:26,240 --> 00:10:28,910 And here is a standard loop the way we've been writing it. 191 00:10:28,910 --> 00:10:30,800 This is a recursion. 192 00:10:30,800 --> 00:10:33,740 It's a loop on k, and says if k is bigger than n, it's the 193 00:10:33,740 --> 00:10:36,990 empty list. Otherwise we compute the k-th Fibonacci 194 00:10:36,990 --> 00:10:40,370 number, call that f. 195 00:10:40,370 --> 00:10:45,180 If it's odd, we CONS it on to the list starting 196 00:10:45,180 --> 00:10:47,690 with the next one. 197 00:10:47,690 --> 00:10:50,390 And otherwise, we just take the next one. 198 00:10:50,390 --> 00:10:52,000 And this is the standard way we've been 199 00:10:52,000 --> 00:10:53,000 writing iterative loops. 200 00:10:53,000 --> 00:10:57,600 And we start off calling that loop with 1. 201 00:10:57,600 --> 00:11:01,600 OK, so there are two procedures. 202 00:11:01,600 --> 00:11:02,900 Those procedures look very different. 203 00:11:02,900 --> 00:11:04,390 They have very different structures. 204 00:11:04,390 --> 00:11:07,740 Yet from a certain point of view, those procedures are 205 00:11:07,740 --> 00:11:11,330 really doing very much the same thing. 206 00:11:11,330 --> 00:11:14,930 So if I was talking like a signal processing engineer, 207 00:11:14,930 --> 00:11:25,730 what I might say is that the first procedure enumerates the 208 00:11:25,730 --> 00:11:26,980 leaves of a tree. 209 00:11:26,980 --> 00:11:31,160 210 00:11:31,160 --> 00:11:33,510 And then we can think of a signal coming out of that, 211 00:11:33,510 --> 00:11:35,330 which is all the leaves. 212 00:11:35,330 --> 00:11:43,970 We'll filter them to see which ones are odd, put them through 213 00:11:43,970 --> 00:11:45,190 some kind of filter. 214 00:11:45,190 --> 00:11:49,000 We'll then put them through a kind of transducer. 215 00:11:49,000 --> 00:11:51,420 And for each one of those things, we'll take the square. 216 00:11:51,420 --> 00:11:54,200 217 00:11:54,200 --> 00:11:58,290 And then we'll accumulate all of those. 218 00:11:58,290 --> 00:12:00,570 We'll accumulate them by sticking them together with 219 00:12:00,570 --> 00:12:03,340 addition starting from 0. 220 00:12:03,340 --> 00:12:07,140 221 00:12:07,140 --> 00:12:08,210 That's the first program. 222 00:12:08,210 --> 00:12:10,620 The second program, I can describe in a very, very 223 00:12:10,620 --> 00:12:11,780 similar way. 224 00:12:11,780 --> 00:12:17,450 I'll say, we'll enumerate the numbers on this interval, for 225 00:12:17,450 --> 00:12:19,080 the interval 1 through n. 226 00:12:19,080 --> 00:12:22,500 227 00:12:22,500 --> 00:12:28,080 We'll, for each one, compute the Fibonacci number, put them 228 00:12:28,080 --> 00:12:29,270 through a transducer. 229 00:12:29,270 --> 00:12:31,780 We'll then take the result of that, and we'll 230 00:12:31,780 --> 00:12:35,976 filter it for oddness. 231 00:12:35,976 --> 00:12:39,350 And then we'll take those and put them into an accumulator. 232 00:12:39,350 --> 00:12:41,730 This time we'll build up a list, so we'll accumulate with 233 00:12:41,730 --> 00:12:47,110 CONS starting from the empty list. 234 00:12:47,110 --> 00:12:50,940 So this way of looking at the program makes the two seem 235 00:12:50,940 --> 00:12:51,900 very, very similar. 236 00:12:51,900 --> 00:12:55,880 The problem is that that commonality is completely 237 00:12:55,880 --> 00:12:58,050 obscured when we look at the procedures we wrote. 238 00:12:58,050 --> 00:13:02,670 Let's go back and look at some odd squares again, and say 239 00:13:02,670 --> 00:13:06,300 things like, where's the enumerator? 240 00:13:06,300 --> 00:13:08,140 Where's the enumerator in this program? 241 00:13:08,140 --> 00:13:11,230 Well, it's not in one place. 242 00:13:11,230 --> 00:13:15,990 It's a little bit in this leaf-node test, 243 00:13:15,990 --> 00:13:17,160 which is going to stop. 244 00:13:17,160 --> 00:13:19,380 It's a little bit in the recursive structure of the 245 00:13:19,380 --> 00:13:20,630 thing itself. 246 00:13:20,630 --> 00:13:23,150 247 00:13:23,150 --> 00:13:24,120 Where's the accumulator? 248 00:13:24,120 --> 00:13:25,680 The accumulator isn't in one place either. 249 00:13:25,680 --> 00:13:32,180 It's partly in this 0 and partly in this plus. 250 00:13:32,180 --> 00:13:34,510 It's not there as a thing that we can look at. 251 00:13:34,510 --> 00:13:40,550 Similarly, if we look at odd Fibs, that's also, in some 252 00:13:40,550 --> 00:13:42,940 sense, an enumerator and an accumulator, but 253 00:13:42,940 --> 00:13:44,470 it looks very different. 254 00:13:44,470 --> 00:13:49,260 Because partly, the enumerator is here in this greater than 255 00:13:49,260 --> 00:13:52,100 sign in the test. And partly it's in this whole recursive 256 00:13:52,100 --> 00:13:55,680 structure in the loop, and the way that we call it. 257 00:13:55,680 --> 00:13:58,100 And then similarly, that's also mixed up in there with 258 00:13:58,100 --> 00:14:01,010 the accumulator, which is partly over there and partly 259 00:14:01,010 --> 00:14:03,600 over there. 260 00:14:03,600 --> 00:14:09,790 So these very, very natural pieces, these very natural 261 00:14:09,790 --> 00:14:13,770 boxes here don't appear in our programs. Because they're kind 262 00:14:13,770 --> 00:14:14,360 of mixed up. 263 00:14:14,360 --> 00:14:16,290 The programs don't chop things up in the right way. 264 00:14:16,290 --> 00:14:19,450 265 00:14:19,450 --> 00:14:22,240 Going back to this fundamental principle of computer science 266 00:14:22,240 --> 00:14:24,620 that in order to control something, you need the name 267 00:14:24,620 --> 00:14:27,820 of it, we don't really have control over thinking about 268 00:14:27,820 --> 00:14:30,500 things this way because we don't have our hands in them 269 00:14:30,500 --> 00:14:31,060 explicitly. 270 00:14:31,060 --> 00:14:35,510 We don't have a good language for talking about them. 271 00:14:35,510 --> 00:14:42,850 Well, let's invent an appropriate language in which 272 00:14:42,850 --> 00:14:44,515 we can build these pieces. 273 00:14:44,515 --> 00:14:48,650 The key to the language is these guys, is what is these 274 00:14:48,650 --> 00:14:50,480 things I called signals? 275 00:14:50,480 --> 00:14:52,070 What are these things that are flying on the 276 00:14:52,070 --> 00:14:53,320 arrows between the boxes? 277 00:14:53,320 --> 00:14:56,880 278 00:14:56,880 --> 00:15:02,840 Well, those things are going to be data structures called 279 00:15:02,840 --> 00:15:04,770 streams. That's going to be the key to 280 00:15:04,770 --> 00:15:07,980 inventing this language. 281 00:15:07,980 --> 00:15:08,600 What's a stream? 282 00:15:08,600 --> 00:15:10,820 Well, a stream is, like anything else, a data 283 00:15:10,820 --> 00:15:12,220 abstraction. 284 00:15:12,220 --> 00:15:15,000 So I should tell you what its selectors and 285 00:15:15,000 --> 00:15:16,870 constructors are. 286 00:15:16,870 --> 00:15:20,185 For a stream, we're going to have one constructor that's 287 00:15:20,185 --> 00:15:21,435 called CONS-stream. 288 00:15:21,435 --> 00:15:25,690 289 00:15:25,690 --> 00:15:29,060 CONS-stream is going to put two things together to form a 290 00:15:29,060 --> 00:15:32,040 thing called a stream. 291 00:15:32,040 --> 00:15:34,250 And then to extract things from the stream, we're going 292 00:15:34,250 --> 00:15:38,010 to have a selector called the head of the stream. 293 00:15:38,010 --> 00:15:41,340 So if I have a stream, I can take its head or I 294 00:15:41,340 --> 00:15:44,720 can take its tail. 295 00:15:44,720 --> 00:15:48,290 And remember, I have to tell you George's contract here to 296 00:15:48,290 --> 00:15:53,160 tell you what the axioms are that relate these. 297 00:15:53,160 --> 00:16:04,080 And it's going to be for any x and y, if I form the 298 00:16:04,080 --> 00:16:11,420 CONS-stream and take the head, the head of CONS-stream of x 299 00:16:11,420 --> 00:16:26,590 and y is going to be x and the tail of CONS-stream of x and y 300 00:16:26,590 --> 00:16:28,440 is going to be y. 301 00:16:28,440 --> 00:16:31,180 So those are the constructor, two selectors for 302 00:16:31,180 --> 00:16:34,750 streams, and an axiom. 303 00:16:34,750 --> 00:16:36,980 There's something fishy here. 304 00:16:36,980 --> 00:16:41,060 So you might notice that these are exactly the axioms for 305 00:16:41,060 --> 00:16:46,100 CONS, CAR, and CDR. If instead of writing CONS-stream I wrote 306 00:16:46,100 --> 00:16:50,810 CONS and I said head was the CAR and tail was the CDR, 307 00:16:50,810 --> 00:16:52,810 those are exactly the axioms for pairs. 308 00:16:52,810 --> 00:16:55,130 And in fact, there's another thing here. 309 00:16:55,130 --> 00:17:02,930 We're going to have a thing called the-empty-stream, which 310 00:17:02,930 --> 00:17:08,319 is like the-empty-list. 311 00:17:08,319 --> 00:17:10,030 So why am I introducing this terminology? 312 00:17:10,030 --> 00:17:12,780 Why don't I just keep talking about pairs and lists? 313 00:17:12,780 --> 00:17:15,510 Well, we'll see. 314 00:17:15,510 --> 00:17:18,440 For now, if you like, why don't you just pretend that 315 00:17:18,440 --> 00:17:21,560 streams really are just a terminology for lists. 316 00:17:21,560 --> 00:17:24,890 And we'll see in a little while why we want to keep this 317 00:17:24,890 --> 00:17:28,150 extra abstraction layer and not just call them lists. 318 00:17:28,150 --> 00:17:32,300 319 00:17:32,300 --> 00:17:34,860 OK, now that we have streams, we can start constructing the 320 00:17:34,860 --> 00:17:38,990 pieces of the language to operate on streams. And there 321 00:17:38,990 --> 00:17:41,330 are a whole bunch of very useful things that we could 322 00:17:41,330 --> 00:17:42,120 start making. 323 00:17:42,120 --> 00:17:54,850 For instance, we'll make our map box to take a stream, s, 324 00:17:54,850 --> 00:18:00,400 and a procedure, and to generate a new stream which 325 00:18:00,400 --> 00:18:03,640 has as its elements the procedure applied to all the 326 00:18:03,640 --> 00:18:05,666 successive elements of s. 327 00:18:05,666 --> 00:18:07,400 In fact, we've seen this before. 328 00:18:07,400 --> 00:18:10,950 This is the procedure map that we did with lists. 329 00:18:10,950 --> 00:18:14,000 And you see it's exactly map, except we're testing for 330 00:18:14,000 --> 00:18:14,650 empty-stream. 331 00:18:14,650 --> 00:18:15,560 Oh, I forgot to mention that. 332 00:18:15,560 --> 00:18:19,420 Empty-stream is like the null test. So if it's empty, we 333 00:18:19,420 --> 00:18:20,510 generate the empty stream. 334 00:18:20,510 --> 00:18:24,700 Otherwise, we form a new stream whose first element is 335 00:18:24,700 --> 00:18:28,950 the procedure applied to the head of the stream, and whose 336 00:18:28,950 --> 00:18:31,570 rest is gotten by mapping along with the procedure down 337 00:18:31,570 --> 00:18:33,140 the tail of the stream. 338 00:18:33,140 --> 00:18:34,920 So that looks exactly like the map procedure 339 00:18:34,920 --> 00:18:37,030 we looked at before. 340 00:18:37,030 --> 00:18:38,350 Here's another useful thing. 341 00:18:38,350 --> 00:18:40,460 Filter, this is our filter box. 342 00:18:40,460 --> 00:18:43,890 We're going to have a predicate and a stream. 343 00:18:43,890 --> 00:18:46,720 We're going to make a new stream that consists of all 344 00:18:46,720 --> 00:18:48,310 the elements of the original one 345 00:18:48,310 --> 00:18:50,160 that satisfy the predicate. 346 00:18:50,160 --> 00:18:51,270 That's case analysis. 347 00:18:51,270 --> 00:18:53,140 When there's nothing in the stream, we 348 00:18:53,140 --> 00:18:56,280 return the empty stream. 349 00:18:56,280 --> 00:19:00,060 We test the predicate on the head of the stream. 350 00:19:00,060 --> 00:19:03,520 And if it's true, we add the head of the stream onto the 351 00:19:03,520 --> 00:19:08,220 result of filtering the tail of the stream. 352 00:19:08,220 --> 00:19:10,870 And otherwise, if that predicate was false, we just 353 00:19:10,870 --> 00:19:13,500 filter the tail of the stream. 354 00:19:13,500 --> 00:19:16,595 Right, so there's filter. 355 00:19:16,595 --> 00:19:18,560 Let me run through a couple more rather quickly. 356 00:19:18,560 --> 00:19:20,880 They're all in the book and you can look at them. 357 00:19:20,880 --> 00:19:22,110 Let me just flash through. 358 00:19:22,110 --> 00:19:23,260 Here's accumulate. 359 00:19:23,260 --> 00:19:27,690 Accumulate takes a way of combining things and an 360 00:19:27,690 --> 00:19:31,560 initial value in a stream and sticks them all together. 361 00:19:31,560 --> 00:19:33,970 If the stream's empty, it's just the initial value. 362 00:19:33,970 --> 00:19:36,930 Otherwise, we combine the head of the stream with the result 363 00:19:36,930 --> 00:19:39,550 of accumulating the tail of the stream starting from the 364 00:19:39,550 --> 00:19:40,900 initial value. 365 00:19:40,900 --> 00:19:42,830 So that's what I'd use to add up everything in the stream. 366 00:19:42,830 --> 00:19:45,830 I'd accumulate with plus. 367 00:19:45,830 --> 00:19:48,060 How would I enumerate the leaves of a tree? 368 00:19:48,060 --> 00:19:54,530 Well, if the tree is just a leaf itself, I make something 369 00:19:54,530 --> 00:19:56,640 which only has that node in it. 370 00:19:56,640 --> 00:20:01,100 Otherwise, I append together the stuff of enumerating the 371 00:20:01,100 --> 00:20:04,340 left branch and the right branch. 372 00:20:04,340 --> 00:20:08,130 And then append here is like the ordinary append on lists. 373 00:20:08,130 --> 00:20:13,190 374 00:20:13,190 --> 00:20:13,850 You can look at that. 375 00:20:13,850 --> 00:20:16,410 That's analogous to the ordinary procedure for 376 00:20:16,410 --> 00:20:19,150 appending two lists. 377 00:20:19,150 --> 00:20:21,810 How would I enumerate an interval? 378 00:20:21,810 --> 00:20:24,500 This will take two integers, low and high, and generate a 379 00:20:24,500 --> 00:20:28,106 stream of the integers going from low to high. 380 00:20:28,106 --> 00:20:31,890 And we can make a whole bunch of pieces. 381 00:20:31,890 --> 00:20:34,860 So that's a little language of talking about streams. Once we 382 00:20:34,860 --> 00:20:37,670 have streams, we can build things for manipulating them. 383 00:20:37,670 --> 00:20:40,200 Again, we're making a language. 384 00:20:40,200 --> 00:20:41,270 And now we can start expressing 385 00:20:41,270 --> 00:20:43,060 things in this language. 386 00:20:43,060 --> 00:20:46,590 Here's our original procedure for summing the odd 387 00:20:46,590 --> 00:20:47,310 squares in a tree. 388 00:20:47,310 --> 00:20:52,210 And you'll notice it looks exactly now like the block 389 00:20:52,210 --> 00:20:54,590 diagram, like the signal processing block diagram. 390 00:20:54,590 --> 00:21:00,230 So to sum the odd squares in a tree, we enumerate the leaves 391 00:21:00,230 --> 00:21:01,320 of the tree. 392 00:21:01,320 --> 00:21:04,830 We filter that for oddness. 393 00:21:04,830 --> 00:21:06,220 We map that for squareness. 394 00:21:06,220 --> 00:21:09,320 395 00:21:09,320 --> 00:21:12,460 And we accumulate the result of that using addition, 396 00:21:12,460 --> 00:21:14,760 starting from 0. 397 00:21:14,760 --> 00:21:17,290 So we can see the pieces that we wanted. 398 00:21:17,290 --> 00:21:22,050 Similarly, the Fibonacci one, how do we get the odd Fibs? 399 00:21:22,050 --> 00:21:27,900 Well, we enumerate the interval from 1 to n, we map 400 00:21:27,900 --> 00:21:30,920 along that, computing the Fibonacci of each one. 401 00:21:30,920 --> 00:21:34,810 We filter the result of those for oddness. 402 00:21:34,810 --> 00:21:38,460 And we accumulate all of that stuff using CONS starting from 403 00:21:38,460 --> 00:21:43,650 the empty-list. 404 00:21:43,650 --> 00:21:47,680 OK, what's the advantage of this? 405 00:21:47,680 --> 00:21:50,260 Well, for one thing, we now have pieces that we can start 406 00:21:50,260 --> 00:21:51,880 mixing and matching. 407 00:21:51,880 --> 00:21:58,230 So for instance, if I wanted to change this, if I wanted to 408 00:21:58,230 --> 00:22:00,400 compute the squares of the integers and then filter them, 409 00:22:00,400 --> 00:22:03,810 all I need to do is pick up a standard piece like this in 410 00:22:03,810 --> 00:22:06,210 that square and put it in. 411 00:22:06,210 --> 00:22:10,150 Or if we wanted to do this whole Fibonacci computation on 412 00:22:10,150 --> 00:22:12,980 the leaves of a tree rather than a sequence, all I need to 413 00:22:12,980 --> 00:22:18,030 do is replace this enumerator with that one. 414 00:22:18,030 --> 00:22:20,650 See, the advantage of this stream processing is that 415 00:22:20,650 --> 00:22:21,995 we're establishing-- 416 00:22:21,995 --> 00:22:25,330 this is one of the big themes of the course-- 417 00:22:25,330 --> 00:22:35,570 we're establishing conventional interfaces that 418 00:22:35,570 --> 00:22:38,130 allow us to glue things together. 419 00:22:38,130 --> 00:22:41,730 Things like map and filter are a standard set of components 420 00:22:41,730 --> 00:22:43,900 that we can start using for pasting together programs in 421 00:22:43,900 --> 00:22:45,750 all sorts of ways. 422 00:22:45,750 --> 00:22:50,090 It allows us to see the commonality of programs. 423 00:22:50,090 --> 00:22:52,390 I just ought to mention, I've only showed you two 424 00:22:52,390 --> 00:22:53,860 procedures. 425 00:22:53,860 --> 00:22:57,800 But let me emphasize that this way of putting things together 426 00:22:57,800 --> 00:22:59,780 with maps, filters, and accumulators 427 00:22:59,780 --> 00:23:01,410 is very, very general. 428 00:23:01,410 --> 00:23:08,010 It's the generate and test paradigm for programs. And as 429 00:23:08,010 --> 00:23:11,970 an example of that, Richard Waters, who was at MIT when he 430 00:23:11,970 --> 00:23:14,060 was a graduate student, as part of his thesis research 431 00:23:14,060 --> 00:23:17,700 went and analyzed a large chunk of the IBM scientific 432 00:23:17,700 --> 00:23:22,340 subroutine library, and discovered that about 60% of 433 00:23:22,340 --> 00:23:26,830 the programs in it could be expressed exactly in terms 434 00:23:26,830 --> 00:23:28,940 using no more than what we've put here-- 435 00:23:28,940 --> 00:23:30,710 map, filter, and accumulate. 436 00:23:30,710 --> 00:23:31,960 All right, let's take a break. 437 00:23:31,960 --> 00:23:36,620 438 00:23:36,620 --> 00:23:37,870 Questions? 439 00:23:37,870 --> 00:23:40,470 440 00:23:40,470 --> 00:23:43,033 AUDIENCE: It seems like the essence of this whole thing is 441 00:23:43,033 --> 00:23:45,980 just that you have a very uniform, simple data structure 442 00:23:45,980 --> 00:23:48,380 to work with, the stream. 443 00:23:48,380 --> 00:23:48,920 PROFESSOR: Right. 444 00:23:48,920 --> 00:23:51,670 The essence is that you, again, it's this sense of 445 00:23:51,670 --> 00:23:53,710 conventional interfaces. 446 00:23:53,710 --> 00:23:55,610 So you can start putting a lot of things together. 447 00:23:55,610 --> 00:23:59,830 And the stream is as you say, the uniform data structure 448 00:23:59,830 --> 00:24:00,890 that supports that. 449 00:24:00,890 --> 00:24:03,600 This is very much like APL, by the way. 450 00:24:03,600 --> 00:24:06,330 APL is very much the same idea, except in APL, instead 451 00:24:06,330 --> 00:24:09,560 of this stream, you have arrays and vectors. 452 00:24:09,560 --> 00:24:13,565 And a lot of the power of APL is exactly the same reason of 453 00:24:13,565 --> 00:24:14,815 the power of this. 454 00:24:14,815 --> 00:24:19,910 455 00:24:19,910 --> 00:24:20,910 OK, thank you. 456 00:24:20,910 --> 00:24:22,160 Let's take a break. 457 00:24:22,160 --> 00:24:57,470 458 00:24:57,470 --> 00:24:57,610 All right. 459 00:24:57,610 --> 00:25:02,830 We've been looking at ways of organizing computations using 460 00:25:02,830 --> 00:25:07,560 streams. What I want to do now is just show you two somewhat 461 00:25:07,560 --> 00:25:10,810 more complicated examples of that. 462 00:25:10,810 --> 00:25:15,000 Let's start by thinking about the following kind of utility 463 00:25:15,000 --> 00:25:16,810 procedure that will come in useful. 464 00:25:16,810 --> 00:25:19,960 Suppose I've got a stream. 465 00:25:19,960 --> 00:25:23,730 And the elements of this stream are themselves streams. 466 00:25:23,730 --> 00:25:26,530 So the first thing might be 1, 2, 3. 467 00:25:26,530 --> 00:25:32,600 468 00:25:32,600 --> 00:25:33,880 So I've got a stream. 469 00:25:33,880 --> 00:25:40,100 And each element of the stream is itself a stream. 470 00:25:40,100 --> 00:25:45,580 And what I'd like to do is build a stream that collects 471 00:25:45,580 --> 00:25:47,870 together all of the elements, pulls all of the elements out 472 00:25:47,870 --> 00:25:50,840 of these sub-streams and strings them all 473 00:25:50,840 --> 00:25:52,080 together in one thing. 474 00:25:52,080 --> 00:25:56,220 So just to show you the use of this language, how easy it is, 475 00:25:56,220 --> 00:25:56,960 call that flatten. 476 00:25:56,960 --> 00:26:13,020 And I can define to flatten this stream of streams. Well, 477 00:26:13,020 --> 00:26:13,960 what is that? 478 00:26:13,960 --> 00:26:16,240 That's just an accumulation. 479 00:26:16,240 --> 00:26:25,240 I want to accumulate using append, by 480 00:26:25,240 --> 00:26:26,450 successively appending. 481 00:26:26,450 --> 00:26:36,590 So I accumulate using append streams, starting with 482 00:26:36,590 --> 00:26:54,370 the-empty-stream down that stream of streams. 483 00:26:54,370 --> 00:26:58,290 OK, so there's an example of how you can start using these 484 00:26:58,290 --> 00:27:00,830 higher order things to do some interesting operations. 485 00:27:00,830 --> 00:27:04,230 In fact, there's another useful thing 486 00:27:04,230 --> 00:27:05,100 that I want to do. 487 00:27:05,100 --> 00:27:18,700 I want to define a procedure called flat-map, flat map of 488 00:27:18,700 --> 00:27:21,840 some function and a stream. 489 00:27:21,840 --> 00:27:23,920 And what this is going to do is f will 490 00:27:23,920 --> 00:27:25,720 be a stream of elements. 491 00:27:25,720 --> 00:27:28,930 f is going to be a function that for each element in the 492 00:27:28,930 --> 00:27:31,950 stream produces another stream. 493 00:27:31,950 --> 00:27:33,950 And what I want to do is take all of the elements and all of 494 00:27:33,950 --> 00:27:36,000 those streams and combine them together. 495 00:27:36,000 --> 00:27:51,350 So that's just going to be the flatten of map f down s. 496 00:27:51,350 --> 00:27:54,290 Each time I apply f to an element of s, I get a stream. 497 00:27:54,290 --> 00:27:56,690 If I map it all the way down, I get a stream of streams, and 498 00:27:56,690 --> 00:27:58,385 I'll flatten that. 499 00:27:58,385 --> 00:28:04,670 Well, I want to use that to show you a new way to do a 500 00:28:04,670 --> 00:28:06,360 familiar kind of problem. 501 00:28:06,360 --> 00:28:12,310 The problem's going to be like a lot of problems you've seen, 502 00:28:12,310 --> 00:28:14,190 although maybe not this particular one. 503 00:28:14,190 --> 00:28:15,490 I'm going to give you an integer, n. 504 00:28:15,490 --> 00:28:18,480 505 00:28:18,480 --> 00:28:31,020 And the problem is going to be find all pairs and integers i 506 00:28:31,020 --> 00:28:42,740 and j, between 0 and i, with j less than i, up to n, such 507 00:28:42,740 --> 00:28:51,910 that i plus j is prime. 508 00:28:51,910 --> 00:28:55,740 509 00:28:55,740 --> 00:29:00,520 So for example, if n equals 6, let's make a little table 510 00:29:00,520 --> 00:29:06,640 here, i and j and i plus j. 511 00:29:06,640 --> 00:29:09,700 512 00:29:09,700 --> 00:29:15,520 So for, say, i equals 2 and j equals 1, I'd get 3. 513 00:29:15,520 --> 00:29:18,940 And for i equals 3, I could have j equals 2, and that 514 00:29:18,940 --> 00:29:21,210 would be 5. 515 00:29:21,210 --> 00:29:28,400 And 4 and 1 would be 5 and so on, up until i goes to 6. 516 00:29:28,400 --> 00:29:33,640 And what I'd like to return is to produce a stream of all the 517 00:29:33,640 --> 00:29:37,350 triples like this, let's say i, j, and i plus j. 518 00:29:37,350 --> 00:29:41,530 So for each n, I want to generate this stream. 519 00:29:41,530 --> 00:29:43,680 OK, well, that's easy. 520 00:29:43,680 --> 00:29:47,230 Let's build it up. 521 00:29:47,230 --> 00:29:50,150 We start like this. 522 00:29:50,150 --> 00:29:55,510 We're going to say for each i, we're going 523 00:29:55,510 --> 00:29:56,440 to generate a stream. 524 00:29:56,440 --> 00:29:58,830 For each i in the interval 1 through n, we're going to 525 00:29:58,830 --> 00:30:00,660 generate a stream. 526 00:30:00,660 --> 00:30:02,230 What's that stream going to be? 527 00:30:02,230 --> 00:30:04,180 We're going to start by generating all the pairs. 528 00:30:04,180 --> 00:30:11,840 So for each i, we're going to generate, for each j in the 529 00:30:11,840 --> 00:30:19,450 interval 1 to i minus 1, we'll generate the pair, or the list 530 00:30:19,450 --> 00:30:20,710 with two elements i and j. 531 00:30:20,710 --> 00:30:23,780 532 00:30:23,780 --> 00:30:30,712 So we map along the interval, generating the pairs. 533 00:30:30,712 --> 00:30:33,170 And for each i, that generates a stream of pairs. 534 00:30:33,170 --> 00:30:34,590 And we flatmap it. 535 00:30:34,590 --> 00:30:37,390 Now we have all the pairs i and j, such that i 536 00:30:37,390 --> 00:30:38,730 is less than j. 537 00:30:38,730 --> 00:30:39,850 So that builds that. 538 00:30:39,850 --> 00:30:42,990 Now we're got to test them. 539 00:30:42,990 --> 00:30:47,160 Well, we take that thing we just built, the flatmap, and 540 00:30:47,160 --> 00:30:50,090 we filter it to see whether the i-- 541 00:30:50,090 --> 00:30:51,660 see, we had an i and a j. 542 00:30:51,660 --> 00:30:55,180 i was the first thing in the list, j was the second thing 543 00:30:55,180 --> 00:30:59,030 in the list. So we have a predicate which says in that 544 00:30:59,030 --> 00:31:00,870 list of two elements is the sum of the 545 00:31:00,870 --> 00:31:02,070 CAR and the CDR prime. 546 00:31:02,070 --> 00:31:06,540 And we filter that collection of pairs we just built. 547 00:31:06,540 --> 00:31:09,420 So those are the pairs we want. 548 00:31:09,420 --> 00:31:13,340 Now we go ahead and we take the result of that filter and 549 00:31:13,340 --> 00:31:19,610 we map along it, generating the list i and j and i plus j. 550 00:31:19,610 --> 00:31:22,910 And that's our procedure prime-sum-pairs. 551 00:31:22,910 --> 00:31:24,480 And then just to flash it up, here's the whole procedure. 552 00:31:24,480 --> 00:31:27,945 553 00:31:27,945 --> 00:31:30,750 A map, a filter, a flatmap. 554 00:31:30,750 --> 00:31:34,850 555 00:31:34,850 --> 00:31:36,350 There's the whole thing, even though this isn't 556 00:31:36,350 --> 00:31:37,120 particularly readable. 557 00:31:37,120 --> 00:31:40,000 It's just expanding that flatmap. 558 00:31:40,000 --> 00:31:45,090 So there's an example which illustrates the general point 559 00:31:45,090 --> 00:31:49,350 that nested loops in this procedure start looking like 560 00:31:49,350 --> 00:31:52,370 compositions of flatmaps of flatmaps of flatmaps of maps 561 00:31:52,370 --> 00:31:54,200 and things. 562 00:31:54,200 --> 00:31:57,900 So not only can we enumerate individual things, but by 563 00:31:57,900 --> 00:32:00,890 using flatmaps, we can do what would correspond to nested 564 00:32:00,890 --> 00:32:03,230 loops in most other languages. 565 00:32:03,230 --> 00:32:06,870 Of course, it's pretty awful to keep writing these flatmaps 566 00:32:06,870 --> 00:32:08,410 of flatmaps of flatmaps. 567 00:32:08,410 --> 00:32:13,830 Prime-sum-pairs you saw looked fairly complicated, even 568 00:32:13,830 --> 00:32:15,480 though the individual pieces were easy. 569 00:32:15,480 --> 00:32:17,800 So what you can do, if you like, is introduced some 570 00:32:17,800 --> 00:32:21,040 syntactic sugar that's called collect. 571 00:32:21,040 --> 00:32:23,570 And collect is just an abbreviation for that nest of 572 00:32:23,570 --> 00:32:26,160 flatmaps and filters arranged in that particular way. 573 00:32:26,160 --> 00:32:29,620 Here's prime-sum-pairs again, written using collect. 574 00:32:29,620 --> 00:32:32,670 It says to find all those pairs, I'm going to collect 575 00:32:32,670 --> 00:32:40,910 together a result, which is the list i, j, and i plus j, 576 00:32:40,910 --> 00:32:44,510 that's going to be generated as i runs through the interval 577 00:32:44,510 --> 00:32:51,440 from 1 to n and as j runs through the interval from 1 to 578 00:32:51,440 --> 00:32:58,040 i minus 1, such that i plus j is prime. 579 00:32:58,040 --> 00:33:00,690 So I'm not going to say what collect does in general. 580 00:33:00,690 --> 00:33:03,420 You can look at that by looking at it in the book. 581 00:33:03,420 --> 00:33:06,010 But pretty much, you can see that the pieces of this are 582 00:33:06,010 --> 00:33:08,820 the pieces of that original procedure I wrote. 583 00:33:08,820 --> 00:33:11,550 And this collect is just some syntactic sugar for 584 00:33:11,550 --> 00:33:16,310 automatically generating that nest of flatmaps and flatmaps. 585 00:33:16,310 --> 00:33:21,120 OK, well, let me do one more example that shows you the 586 00:33:21,120 --> 00:33:22,120 same kind of thing. 587 00:33:22,120 --> 00:33:25,740 Here's a very famous problem that's used to illustrate a 588 00:33:25,740 --> 00:33:28,980 lot of so-called backtracking computer algorithms. This is 589 00:33:28,980 --> 00:33:30,200 the eight queens problem. 590 00:33:30,200 --> 00:33:32,370 This is a chess board. 591 00:33:32,370 --> 00:33:34,570 And the eight queens problem says, find a way to put down 592 00:33:34,570 --> 00:33:37,660 eight queens on a chess board so that no two are attacking 593 00:33:37,660 --> 00:33:38,000 each other. 594 00:33:38,000 --> 00:33:39,685 And here's a particular solution to the 595 00:33:39,685 --> 00:33:41,430 eight queens problem. 596 00:33:41,430 --> 00:33:44,450 So I have to make sure to put down queens so that no two are 597 00:33:44,450 --> 00:33:48,570 in the same row or the same column or sit 598 00:33:48,570 --> 00:33:51,410 along the same diagonal. 599 00:33:51,410 --> 00:33:56,400 Now, there's sort of a standard way of doing that. 600 00:33:56,400 --> 00:33:59,740 601 00:33:59,740 --> 00:34:03,200 Well, first we need to do is below the 602 00:34:03,200 --> 00:34:04,940 surface, at George's level. 603 00:34:04,940 --> 00:34:07,340 We have to find some way to represent a board, and 604 00:34:07,340 --> 00:34:08,095 represent positions. 605 00:34:08,095 --> 00:34:09,800 And we'll not worry about that. 606 00:34:09,800 --> 00:34:12,540 But let's assume that there's a predicate called safe. 607 00:34:12,540 --> 00:34:16,040 608 00:34:16,040 --> 00:34:19,090 And what safe is going to do is going to say given that I 609 00:34:19,090 --> 00:34:22,520 have a bunch of queens down on the chess board, is it OK to 610 00:34:22,520 --> 00:34:25,400 put a queen in this particular spot? 611 00:34:25,400 --> 00:34:32,889 So safe is going to take a row and a column. 612 00:34:32,889 --> 00:34:34,510 That's going to be a place where I'm going to try and put 613 00:34:34,510 --> 00:34:42,370 down the next queen, and the rest of positions. 614 00:34:42,370 --> 00:34:45,420 615 00:34:45,420 --> 00:34:48,679 And what safe will say is given that I already have 616 00:34:48,679 --> 00:34:53,920 queens down in these positions, is it safe to put 617 00:34:53,920 --> 00:34:58,300 another queen down in that row and that column? 618 00:34:58,300 --> 00:34:59,360 And let's not worry about that. 619 00:34:59,360 --> 00:35:01,380 That's George's problem. and it's not hard to write. 620 00:35:01,380 --> 00:35:06,350 You just have to check whether this thing contains any things 621 00:35:06,350 --> 00:35:10,530 on that row or that column or in that diagonal. 622 00:35:10,530 --> 00:35:13,590 Now, how would you organize the program given that? 623 00:35:13,590 --> 00:35:18,010 And there's sort of a traditional way to organize it 624 00:35:18,010 --> 00:35:20,116 called backtracking. 625 00:35:20,116 --> 00:35:27,570 And it says, well, let's think about all the ways of putting 626 00:35:27,570 --> 00:35:31,290 the first queen down in the first column. 627 00:35:31,290 --> 00:35:32,580 There are eight ways. 628 00:35:32,580 --> 00:35:35,880 Well, let's say try the first column. 629 00:35:35,880 --> 00:35:37,300 Try column 1, row 1. 630 00:35:37,300 --> 00:35:41,300 These branches are going to represent the possibilities at 631 00:35:41,300 --> 00:35:43,360 each level. 632 00:35:43,360 --> 00:35:45,875 So I'll try and put a queen down in the first column. 633 00:35:45,875 --> 00:35:48,360 And now given that it's in the first column, I'll try and put 634 00:35:48,360 --> 00:35:49,980 the next queen down in the first column. 635 00:35:49,980 --> 00:35:53,035 636 00:35:53,035 --> 00:35:55,470 I'll try and put the first queen, the one in the first 637 00:35:55,470 --> 00:35:56,920 column, down in the first row. 638 00:35:56,920 --> 00:35:59,050 I'm sorry. 639 00:35:59,050 --> 00:36:00,780 And then given that, we'll put the next queen down 640 00:36:00,780 --> 00:36:01,390 in the first row. 641 00:36:01,390 --> 00:36:02,090 And that's no good. 642 00:36:02,090 --> 00:36:04,200 So I'll back up to here. 643 00:36:04,200 --> 00:36:06,280 And I'll say, oh, can I put the first queen down in the 644 00:36:06,280 --> 00:36:07,510 second row? 645 00:36:07,510 --> 00:36:08,550 Well, that's no good. 646 00:36:08,550 --> 00:36:09,760 Oh, can I put it down in the third row? 647 00:36:09,760 --> 00:36:12,790 Well, that's good. 648 00:36:12,790 --> 00:36:14,290 Well, now can I put the next queen down 649 00:36:14,290 --> 00:36:15,380 in the first column? 650 00:36:15,380 --> 00:36:18,030 Well, I can't visualize this chess board anymore, but I 651 00:36:18,030 --> 00:36:19,195 think that's right. 652 00:36:19,195 --> 00:36:20,450 And I try the next one. 653 00:36:20,450 --> 00:36:24,170 And at each place, I go as far down this tree as I can. 654 00:36:24,170 --> 00:36:25,640 And I back up. 655 00:36:25,640 --> 00:36:28,970 If I get down to here and find no possibilities below there, 656 00:36:28,970 --> 00:36:31,740 I back all the way up to here, and now start again generating 657 00:36:31,740 --> 00:36:33,260 this sub-tree. 658 00:36:33,260 --> 00:36:35,050 And I sort of walk around. 659 00:36:35,050 --> 00:36:37,870 And finally, if I ever manage to get all the way down, I've 660 00:36:37,870 --> 00:36:40,090 found a solution. 661 00:36:40,090 --> 00:36:45,020 So that's a typical sort of paradigm that's used a lot in 662 00:36:45,020 --> 00:36:45,930 AI programming. 663 00:36:45,930 --> 00:36:47,300 It's called backtracking search. 664 00:36:47,300 --> 00:36:57,470 665 00:36:57,470 --> 00:37:03,860 And it's really unnecessary. 666 00:37:03,860 --> 00:37:06,550 You saw me get confused when I was visualizing this thing. 667 00:37:06,550 --> 00:37:08,550 And you see the complication. 668 00:37:08,550 --> 00:37:10,760 This is a complicated thing to say. 669 00:37:10,760 --> 00:37:12,390 Why is it complicated? 670 00:37:12,390 --> 00:37:16,190 Its because somehow this program is too inordinately 671 00:37:16,190 --> 00:37:18,580 concerned with time. 672 00:37:18,580 --> 00:37:19,200 It's too much-- 673 00:37:19,200 --> 00:37:21,670 I try this one, and I try this one, and I go back to the last 674 00:37:21,670 --> 00:37:22,320 possibility. 675 00:37:22,320 --> 00:37:24,340 And that's a complicated thing. 676 00:37:24,340 --> 00:37:28,590 If I stop worrying about time so much, then there's a much 677 00:37:28,590 --> 00:37:31,200 simpler way to describe this. 678 00:37:31,200 --> 00:37:40,320 It says, let's imagine that I have in my hands the tree down 679 00:37:40,320 --> 00:37:43,400 to k minus 1 levels. 680 00:37:43,400 --> 00:37:50,670 See, suppose I had in my hands all possible ways to put down 681 00:37:50,670 --> 00:37:53,560 queens in the first k columns. 682 00:37:53,560 --> 00:37:54,610 Suppose I just had that. 683 00:37:54,610 --> 00:37:57,070 Let's not worry about how we get it. 684 00:37:57,070 --> 00:37:59,200 Well, then, how do I extend that? 685 00:37:59,200 --> 00:38:01,420 How do I find all possible ways to put down queens in the 686 00:38:01,420 --> 00:38:02,480 next column? 687 00:38:02,480 --> 00:38:03,620 It's really easy. 688 00:38:03,620 --> 00:38:12,210 For each of these positions I have, I think about putting 689 00:38:12,210 --> 00:38:16,160 down a queen in each row to make the next thing. 690 00:38:16,160 --> 00:38:18,930 And then for each one I put down, I filter those by the 691 00:38:18,930 --> 00:38:22,080 ones that are safe. 692 00:38:22,080 --> 00:38:24,190 So instead of thinking about this tree as generated step by 693 00:38:24,190 --> 00:38:26,860 step, suppose I had it all there. 694 00:38:26,860 --> 00:38:29,680 695 00:38:29,680 --> 00:38:32,990 And to extend it from level k minus 1 to level k, I just 696 00:38:32,990 --> 00:38:36,840 need to extend each thing in all possible ways and only 697 00:38:36,840 --> 00:38:37,800 keep the ones that are safe. 698 00:38:37,800 --> 00:38:39,300 And that will give me the tree to level k. 699 00:38:39,300 --> 00:38:41,675 And that's a recursive strategy for solving the eight 700 00:38:41,675 --> 00:38:44,530 queens problem. 701 00:38:44,530 --> 00:38:45,780 All right, well, let's look at it. 702 00:38:45,780 --> 00:38:50,280 703 00:38:50,280 --> 00:38:54,360 To solve the eight queens problem on a board of some 704 00:38:54,360 --> 00:39:00,390 specified size, we write a sub-procedure called 705 00:39:00,390 --> 00:39:01,030 fill-columns. 706 00:39:01,030 --> 00:39:04,050 Fill-columns is going to put down queens up 707 00:39:04,050 --> 00:39:06,086 through column k. 708 00:39:06,086 --> 00:39:07,700 And here's the pattern of the recursion. 709 00:39:07,700 --> 00:39:12,990 I'm going to call fill-columns with the size eventually. 710 00:39:12,990 --> 00:39:15,630 So fill-columns says how to put down queens safely in the 711 00:39:15,630 --> 00:39:19,255 first k columns of this chess board with a size number of 712 00:39:19,255 --> 00:39:20,360 rows in it. 713 00:39:20,360 --> 00:39:22,946 If k is equal to 0, well, then I don't have to 714 00:39:22,946 --> 00:39:23,940 put anything down. 715 00:39:23,940 --> 00:39:26,710 So my solution is just an empty chess board. 716 00:39:26,710 --> 00:39:28,070 Otherwise, I'm going to do some stuff. 717 00:39:28,070 --> 00:39:30,522 And I'm going to use collect. 718 00:39:30,522 --> 00:39:31,772 And here's the collect. 719 00:39:31,772 --> 00:39:34,530 720 00:39:34,530 --> 00:39:40,590 I find all ways to put down queens in the 721 00:39:40,590 --> 00:39:41,910 first k minus 1 columns. 722 00:39:41,910 --> 00:39:43,320 And this was just what I set for. 723 00:39:43,320 --> 00:39:48,880 Imagine I have this tree down to k minus 1 levels. 724 00:39:48,880 --> 00:39:53,230 And then I find all ways of trying a row, that's just each 725 00:39:53,230 --> 00:39:54,130 of the possible rows. 726 00:39:54,130 --> 00:39:58,040 They're size rows, so that's enumerate interval. 727 00:39:58,040 --> 00:40:03,950 And now what I do is I collect together the new row I'm going 728 00:40:03,950 --> 00:40:08,950 to try and column k with the rest of the queens. 729 00:40:08,950 --> 00:40:10,200 I adjoin a position. 730 00:40:10,200 --> 00:40:11,290 This is George's problem. 731 00:40:11,290 --> 00:40:13,640 An adjoined position is like safe. 732 00:40:13,640 --> 00:40:16,530 It's a thing that takes a row and a column and the rest of 733 00:40:16,530 --> 00:40:19,660 the positions and makes a new position collection. 734 00:40:19,660 --> 00:40:26,230 So I adjoin a position of a new row and a new column to 735 00:40:26,230 --> 00:40:30,310 the rest of the queens, where the rest of the queens runs 736 00:40:30,310 --> 00:40:32,870 through all possible ways of solving the problem 737 00:40:32,870 --> 00:40:34,620 in k minus 1 columns. 738 00:40:34,620 --> 00:40:39,730 And the new row runs through all possible rows such that it 739 00:40:39,730 --> 00:40:43,240 was safe to put one there. 740 00:40:43,240 --> 00:40:46,500 And that's the whole program. 741 00:40:46,500 --> 00:40:49,840 There's the whole procedure. 742 00:40:49,840 --> 00:40:51,990 Not only that, that doesn't just solve the eight queens 743 00:40:51,990 --> 00:40:56,010 problem, it gives you all solutions to the 744 00:40:56,010 --> 00:40:56,680 eight queens problem. 745 00:40:56,680 --> 00:40:58,480 When you're done, you have a stream. 746 00:40:58,480 --> 00:41:00,650 And the elements of that stream are all possible ways 747 00:41:00,650 --> 00:41:01,900 of solving that problem. 748 00:41:01,900 --> 00:41:05,310 749 00:41:05,310 --> 00:41:06,260 Why is that simpler? 750 00:41:06,260 --> 00:41:10,170 Well, we threw away the whole idea that this is some process 751 00:41:10,170 --> 00:41:12,720 that happens in time with state. 752 00:41:12,720 --> 00:41:14,420 And we just said it's a whole collection of stuff. 753 00:41:14,420 --> 00:41:18,260 And that's why it's simpler. 754 00:41:18,260 --> 00:41:20,110 We've changed our view. 755 00:41:20,110 --> 00:41:22,820 Remember, that's where we started today. 756 00:41:22,820 --> 00:41:26,230 We've changed our view of what it is we're trying to model. 757 00:41:26,230 --> 00:41:30,570 we stop modeling things that evolve in time and have steps 758 00:41:30,570 --> 00:41:31,750 and have state. 759 00:41:31,750 --> 00:41:33,990 And instead, we're trying to model this global thing like 760 00:41:33,990 --> 00:41:37,950 the whole flight of the chalk, rather than its 761 00:41:37,950 --> 00:41:40,750 state at each instant. 762 00:41:40,750 --> 00:41:42,000 Any questions? 763 00:41:42,000 --> 00:41:43,810 764 00:41:43,810 --> 00:41:46,190 AUDIENCE: It looks to me like backtracking would be 765 00:41:46,190 --> 00:41:49,970 searching for the first solution it can find, whereas 766 00:41:49,970 --> 00:41:54,030 this recursive search would be looking for all solutions. 767 00:41:54,030 --> 00:41:58,090 And it seems that if you have a large enough area to search, 768 00:41:58,090 --> 00:42:01,360 that the second is going to become impossible. 769 00:42:01,360 --> 00:42:07,610 PROFESSOR: OK, the answer to that question is the whole 770 00:42:07,610 --> 00:42:08,570 rest of this lecture. 771 00:42:08,570 --> 00:42:10,540 It's exactly the right question. 772 00:42:10,540 --> 00:42:13,522 773 00:42:13,522 --> 00:42:15,540 And without trying to anticipate the lecture too 774 00:42:15,540 --> 00:42:19,910 much, you should start being suspicious at this point, and 775 00:42:19,910 --> 00:42:22,220 exactly those kinds of suspicions. 776 00:42:22,220 --> 00:42:24,830 It's wonderful, but isn't it so terribly inefficient? 777 00:42:24,830 --> 00:42:28,100 That's where we're going. 778 00:42:28,100 --> 00:42:30,020 So I won't answer now, but I'll answer later. 779 00:42:30,020 --> 00:42:33,350 780 00:42:33,350 --> 00:42:34,600 OK, let's take a break. 781 00:42:34,600 --> 00:43:29,650 782 00:43:29,650 --> 00:43:35,600 Well, by now you should be starting to get suspicious. 783 00:43:35,600 --> 00:43:41,450 See, I've showed your this simple, elegant way of putting 784 00:43:41,450 --> 00:43:46,440 programs together, very unlike these other traditional 785 00:43:46,440 --> 00:43:50,490 programs that sum the odd squares or compute the odd 786 00:43:50,490 --> 00:43:53,740 Fibonacci numbers. 787 00:43:53,740 --> 00:43:57,080 Very unlike these programs that mix up the enumerator and 788 00:43:57,080 --> 00:44:00,440 the filter and the accumulator. 789 00:44:00,440 --> 00:44:04,770 And by mixing it up, we don't have all of these wonderful 790 00:44:04,770 --> 00:44:07,990 conceptual advantages of these streams pieces, these 791 00:44:07,990 --> 00:44:09,840 wonderful mix and match components for putting 792 00:44:09,840 --> 00:44:13,800 together lots and lots of programs. 793 00:44:13,800 --> 00:44:15,810 On the other hand, most of the programs you've seen look like 794 00:44:15,810 --> 00:44:18,340 these ugly ones. 795 00:44:18,340 --> 00:44:19,460 Why's that? 796 00:44:19,460 --> 00:44:23,705 Can it possibly be that computer scientists are so 797 00:44:23,705 --> 00:44:28,370 obtuse that they don't notice that if you'd merely did this 798 00:44:28,370 --> 00:44:33,620 thing, then you can get this great programming elegance? 799 00:44:33,620 --> 00:44:36,760 There's got to be a catch. 800 00:44:36,760 --> 00:44:39,510 And it's actually pretty easy to see what the catch is. 801 00:44:39,510 --> 00:44:42,030 Let's think about the following problem. 802 00:44:42,030 --> 00:44:47,510 Suppose I tell you to find the second prime between 10,000 803 00:44:47,510 --> 00:44:51,020 and 1 million, or if your computer's larger, say between 804 00:44:51,020 --> 00:44:54,105 10,000 and 100 billion, or something. 805 00:44:54,105 --> 00:44:55,550 And you say, oh, that's easy. 806 00:44:55,550 --> 00:44:57,080 I can do that with a stream. 807 00:44:57,080 --> 00:45:01,530 All I do is I enumerate the interval 808 00:45:01,530 --> 00:45:04,160 from 10,000 to 1 million. 809 00:45:04,160 --> 00:45:06,800 So I get all those integers from 10,000 to 1 million. 810 00:45:06,800 --> 00:45:10,520 I filter them for prime-ness, so test all of them and see if 811 00:45:10,520 --> 00:45:11,762 they're prime. 812 00:45:11,762 --> 00:45:13,170 And I take the second element. 813 00:45:13,170 --> 00:45:16,130 That's the head of the tail. 814 00:45:16,130 --> 00:45:17,380 Well, that's clearly pretty ridiculous. 815 00:45:17,380 --> 00:45:21,660 816 00:45:21,660 --> 00:45:24,620 We'd not even have room in the machine to store the integers 817 00:45:24,620 --> 00:45:27,040 in the first place, much less to test them. 818 00:45:27,040 --> 00:45:29,810 And then I only want the second one. 819 00:45:29,810 --> 00:45:36,500 See, the power of this traditional programming style 820 00:45:36,500 --> 00:45:39,860 is exactly its weakness, that we're mixing up the 821 00:45:39,860 --> 00:45:45,090 enumerating and the testing and the accumulating. 822 00:45:45,090 --> 00:45:46,670 So we don't do it all. 823 00:45:46,670 --> 00:45:52,580 So the very thing that makes it conceptually ugly is the 824 00:45:52,580 --> 00:45:55,210 very thing that makes it efficient. 825 00:45:55,210 --> 00:45:57,800 It's this mixing up. 826 00:45:57,800 --> 00:45:59,840 So it seems that all I've done this morning so far is just 827 00:45:59,840 --> 00:46:00,420 confuse you. 828 00:46:00,420 --> 00:46:02,930 I showed you this wonderful way that programming might 829 00:46:02,930 --> 00:46:05,840 work, except that it doesn't. 830 00:46:05,840 --> 00:46:09,040 Well, here's where the wonderful thing happens. 831 00:46:09,040 --> 00:46:13,210 It turns out in this game that we really can have our cake 832 00:46:13,210 --> 00:46:14,870 and eat it too. 833 00:46:14,870 --> 00:46:20,280 And what I mean by that is that we really can write 834 00:46:20,280 --> 00:46:24,210 stream programs exactly like the ones I wrote and arrange 835 00:46:24,210 --> 00:46:28,830 things so that when the machine actually runs, it's as 836 00:46:28,830 --> 00:46:31,690 efficient as running this traditional programming style 837 00:46:31,690 --> 00:46:36,310 that mixes up the generation and the test. 838 00:46:36,310 --> 00:46:40,770 Well, that sounds pretty magic. 839 00:46:40,770 --> 00:46:43,690 The key to this is that streams are not lists. 840 00:46:43,690 --> 00:46:48,090 841 00:46:48,090 --> 00:46:50,070 We'll see this carefully in a second, but for now, let's 842 00:46:50,070 --> 00:46:52,115 take a look at that slide again. 843 00:46:52,115 --> 00:46:55,060 The image you should have here of this signal processing 844 00:46:55,060 --> 00:47:00,940 system is that what's going to happen is there's this box 845 00:47:00,940 --> 00:47:05,360 that has the integers sitting in it. 846 00:47:05,360 --> 00:47:08,680 And there's this filter that's connected to it and it's 847 00:47:08,680 --> 00:47:10,940 tugging on them. 848 00:47:10,940 --> 00:47:13,680 And then there's someone who's tugging on this stuff saying 849 00:47:13,680 --> 00:47:16,790 what comes out of the filter. 850 00:47:16,790 --> 00:47:19,630 And the image you should have is that someone says, well, 851 00:47:19,630 --> 00:47:24,590 what's the first prime, and tugs on this filter. 852 00:47:24,590 --> 00:47:28,020 And the filter tugs on the integers. 853 00:47:28,020 --> 00:47:29,830 And you look only at that much, and then say, oh, I 854 00:47:29,830 --> 00:47:30,930 really wanted the second one. 855 00:47:30,930 --> 00:47:33,710 What's the second prime? 856 00:47:33,710 --> 00:47:37,730 And that no computation gets done except when you tug on 857 00:47:37,730 --> 00:47:40,500 these things. 858 00:47:40,500 --> 00:47:41,410 Let me try that again. 859 00:47:41,410 --> 00:47:43,815 This is a little device. 860 00:47:43,815 --> 00:47:46,400 This is a little stream machine invented by Eric 861 00:47:46,400 --> 00:47:49,830 Grimson who's been teaching this course at MIT. 862 00:47:49,830 --> 00:47:52,940 And the image is here's a stream of stuff, like a whole 863 00:47:52,940 --> 00:47:54,780 bunch of the integers. 864 00:47:54,780 --> 00:47:58,700 And here's some processing elements. 865 00:47:58,700 --> 00:48:02,600 And if, say, it's filter of filter of map, or something. 866 00:48:02,600 --> 00:48:05,570 867 00:48:05,570 --> 00:48:08,760 And if I really tried to implement that with streams as 868 00:48:08,760 --> 00:48:11,520 lists, what I'd say is, well, I've got this list of things, 869 00:48:11,520 --> 00:48:12,670 and now I do the first filter. 870 00:48:12,670 --> 00:48:14,070 So do all this processing. 871 00:48:14,070 --> 00:48:18,570 And I take this and I process and I process and I process 872 00:48:18,570 --> 00:48:19,610 and I process. 873 00:48:19,610 --> 00:48:21,910 And now I'm got this new stream. 874 00:48:21,910 --> 00:48:24,070 Now I take that result in my hand someplace. 875 00:48:24,070 --> 00:48:25,260 And I put that through the second one. 876 00:48:25,260 --> 00:48:28,110 And I process the whole thing. 877 00:48:28,110 --> 00:48:29,510 And there's this new stream. 878 00:48:29,510 --> 00:48:32,130 879 00:48:32,130 --> 00:48:35,230 And then I take the result and I put it all the way through 880 00:48:35,230 --> 00:48:36,360 this one the same way. 881 00:48:36,360 --> 00:48:41,760 That's what would happen to these stream programs if 882 00:48:41,760 --> 00:48:43,860 streams were just lists. 883 00:48:43,860 --> 00:48:46,065 But in fact, streams aren't lists, they're streams. And 884 00:48:46,065 --> 00:48:47,240 the image you should have is something a little 885 00:48:47,240 --> 00:48:50,230 bit more like this. 886 00:48:50,230 --> 00:48:55,880 I've got these gadgets connected up by this data 887 00:48:55,880 --> 00:48:57,130 that's flowing out of them. 888 00:48:57,130 --> 00:48:59,960 889 00:48:59,960 --> 00:49:04,190 And here's my original source of the streams. It might be 890 00:49:04,190 --> 00:49:05,980 starting to generate the integers. 891 00:49:05,980 --> 00:49:07,580 And now, what happens if I want a result? 892 00:49:07,580 --> 00:49:10,200 I tug on the end here. 893 00:49:10,200 --> 00:49:13,090 And this element says, gee, I need some more data. 894 00:49:13,090 --> 00:49:15,830 So this one comes here and tugs on that one. 895 00:49:15,830 --> 00:49:17,890 And it says, gee, I need some more data. 896 00:49:17,890 --> 00:49:19,960 And this one tugs on this thing, which might be a 897 00:49:19,960 --> 00:49:21,640 filter, and says, gee, I need some more data. 898 00:49:21,640 --> 00:49:24,755 And only as much of this thing at the end here gets generated 899 00:49:24,755 --> 00:49:25,780 as I tugged. 900 00:49:25,780 --> 00:49:28,030 And only as much of this stuff goes through the processing 901 00:49:28,030 --> 00:49:30,760 units as I'm pulling on the end I need. 902 00:49:30,760 --> 00:49:33,720 That's the image you should have of the difference between 903 00:49:33,720 --> 00:49:36,580 implementing what we're actually going to do and if 904 00:49:36,580 --> 00:49:37,830 streams were lists. 905 00:49:37,830 --> 00:49:40,600 906 00:49:40,600 --> 00:49:42,430 Well, how do we make this thing? 907 00:49:42,430 --> 00:49:43,400 I hope you have the image. 908 00:49:43,400 --> 00:49:44,947 The trick is how to make it. 909 00:49:44,947 --> 00:49:47,930 910 00:49:47,930 --> 00:49:52,080 We want to arrange for a stream to be a data structure 911 00:49:52,080 --> 00:49:55,670 that computes itself incrementally, an on-demand 912 00:49:55,670 --> 00:49:56,920 data structure. 913 00:49:56,920 --> 00:49:59,220 914 00:49:59,220 --> 00:50:02,700 And the basic idea is, again, one of the very basic ideas 915 00:50:02,700 --> 00:50:04,490 that we're seeing throughout the whole course. 916 00:50:04,490 --> 00:50:07,440 And that is that there's not a firm distinction between 917 00:50:07,440 --> 00:50:09,240 programs and data. 918 00:50:09,240 --> 00:50:12,260 So what a stream is going to be is simultaneously this data 919 00:50:12,260 --> 00:50:15,270 structure that you think of, like the stream of the leaves 920 00:50:15,270 --> 00:50:16,810 of this tree. 921 00:50:16,810 --> 00:50:18,880 But at the same time, it's going to be a very clever 922 00:50:18,880 --> 00:50:23,550 procedure that has the method of computing in it. 923 00:50:23,550 --> 00:50:25,930 Well, let me try this. 924 00:50:25,930 --> 00:50:28,460 It's going to turn out that we don't need any more mechanism. 925 00:50:28,460 --> 00:50:31,150 We already have everything we need simply from the fact that 926 00:50:31,150 --> 00:50:32,770 we know how to handle procedures 927 00:50:32,770 --> 00:50:35,460 as first-class objects. 928 00:50:35,460 --> 00:50:36,880 Well, let's go back to the key. 929 00:50:36,880 --> 00:50:39,030 The key is, remember, we had these operations. 930 00:50:39,030 --> 00:50:48,080 CONS-stream and head and tail. 931 00:50:48,080 --> 00:50:51,580 When I started, I said you can think about this as CONS and 932 00:50:51,580 --> 00:50:53,340 think about this as CAR and think about that as 933 00:50:53,340 --> 00:50:55,080 CDR, but it's not. 934 00:50:55,080 --> 00:50:57,550 Now, let's look at what they really are. 935 00:50:57,550 --> 00:51:09,360 Well, CONS-stream of x and y is going to be an abbreviation 936 00:51:09,360 --> 00:51:19,540 for the following thing. 937 00:51:19,540 --> 00:51:24,470 CONS form a pair, ordinary CONS, of x to a thing called 938 00:51:24,470 --> 00:51:28,000 delay of y. 939 00:51:28,000 --> 00:51:31,188 940 00:51:31,188 --> 00:51:34,670 And before I explain that, let me go and write the rest. The 941 00:51:34,670 --> 00:51:39,790 head of a stream is going to be just the CAR. 942 00:51:39,790 --> 00:51:42,380 943 00:51:42,380 --> 00:51:47,610 And the tail of a stream is going to be a thing called 944 00:51:47,610 --> 00:51:56,120 force the CDR of the stream. 945 00:51:56,120 --> 00:51:58,060 Now let me explain this. 946 00:51:58,060 --> 00:52:01,420 Delay is going to be a special magic thing. 947 00:52:01,420 --> 00:52:06,240 What delay does is take an expression and produce a 948 00:52:06,240 --> 00:52:08,380 promise to compute that expression 949 00:52:08,380 --> 00:52:10,600 when you ask for it. 950 00:52:10,600 --> 00:52:11,980 It doesn't do any computation here. 951 00:52:11,980 --> 00:52:14,820 It just gives you a rain check. 952 00:52:14,820 --> 00:52:17,110 It produces a promise. 953 00:52:17,110 --> 00:52:23,280 And CONS-stream says I'm going to put together in a pair x 954 00:52:23,280 --> 00:52:25,360 and a promise to compute y. 955 00:52:25,360 --> 00:52:28,230 956 00:52:28,230 --> 00:52:30,200 Now, if I want the head, that's just the CAR that I put 957 00:52:30,200 --> 00:52:31,840 in the pair. 958 00:52:31,840 --> 00:52:34,350 And the key is that the tail is going to be-- 959 00:52:34,350 --> 00:52:39,110 force calls in that promise. 960 00:52:39,110 --> 00:52:43,690 Tail says, well, take that promise and now 961 00:52:43,690 --> 00:52:44,610 call in that promise. 962 00:52:44,610 --> 00:52:47,430 And then we compute that thing. 963 00:52:47,430 --> 00:52:48,740 That's how this is going to work. 964 00:52:48,740 --> 00:52:51,550 That's what CONS-stream, head, and tail really are. 965 00:52:51,550 --> 00:52:54,196 966 00:52:54,196 --> 00:52:55,570 Now, let's see how this works. 967 00:52:55,570 --> 00:52:58,410 And we'll go through this fairly carefully. 968 00:52:58,410 --> 00:53:01,990 We're going to see how this works in this example of 969 00:53:01,990 --> 00:53:08,650 computing the second prime between 10,000 and a million. 970 00:53:08,650 --> 00:53:11,610 OK, so we start off and we have this expression. 971 00:53:11,610 --> 00:53:15,820 972 00:53:15,820 --> 00:53:20,380 The second prime-- the head of the tail of the result of 973 00:53:20,380 --> 00:53:24,060 filtering for primality the integers between 974 00:53:24,060 --> 00:53:26,710 10,000 and 1 million. 975 00:53:26,710 --> 00:53:28,400 Now, what is that? 976 00:53:28,400 --> 00:53:35,790 What that is, that interval between 10,000 and 1 million, 977 00:53:35,790 --> 00:53:37,480 well, if you trace through enumerate interval, there 978 00:53:37,480 --> 00:53:40,250 builds a CONS-stream. 979 00:53:40,250 --> 00:53:45,880 And the CONS-stream is the CONS of 10,000 to a promise to 980 00:53:45,880 --> 00:53:54,480 compute the integers between 10,001 and 1 million. 981 00:53:54,480 --> 00:53:55,750 So that's what this expression is. 982 00:53:55,750 --> 00:53:57,640 Here I'm using the substitution model. 983 00:53:57,640 --> 00:53:59,690 And we can use the substitution model because we 984 00:53:59,690 --> 00:54:01,010 don't have side effects and state. 985 00:54:01,010 --> 00:54:04,270 986 00:54:04,270 --> 00:54:07,860 So I have CONS of 10,000 to a promise to compute the rest of 987 00:54:07,860 --> 00:54:08,380 the integers. 988 00:54:08,380 --> 00:54:09,850 So only one integer, so far, got enumerated. 989 00:54:09,850 --> 00:54:14,380 990 00:54:14,380 --> 00:54:16,580 Well, I'm going to filter that thing for primality. 991 00:54:16,580 --> 00:54:19,900 992 00:54:19,900 --> 00:54:22,360 Again, you go back and look at the filter code. 993 00:54:22,360 --> 00:54:25,460 What the filter will first do is test the head. 994 00:54:25,460 --> 00:54:31,580 So in this case, the filter will test 10,000 and say, oh, 995 00:54:31,580 --> 00:54:33,500 10,000's not prime. 996 00:54:33,500 --> 00:54:36,260 Therefore, what I have to do recursively 997 00:54:36,260 --> 00:54:39,220 is filter the tail. 998 00:54:39,220 --> 00:54:42,550 And what's the tail of it, well, that's the tail of this 999 00:54:42,550 --> 00:54:46,340 pair with a promise in it. 1000 00:54:46,340 --> 00:54:49,680 Tail now comes in and says, well, I'm going to force that. 1001 00:54:49,680 --> 00:54:53,790 I'm going to force that promise, which means now I'm 1002 00:54:53,790 --> 00:55:00,880 going to compute the integers between 10,001 and 1 million. 1003 00:55:00,880 --> 00:55:02,970 OK, so this filter now is looking at that. 1004 00:55:02,970 --> 00:55:07,810 1005 00:55:07,810 --> 00:55:10,100 That enumerate itself, well, now we're back in the original 1006 00:55:10,100 --> 00:55:11,960 enumerate situation. 1007 00:55:11,960 --> 00:55:16,920 The enumerate is the CONS of the first thing, 10,001, onto 1008 00:55:16,920 --> 00:55:19,740 a promise to compute the rest. 1009 00:55:19,740 --> 00:55:23,060 So now the primality filter is going to go look at 10,001. 1010 00:55:23,060 --> 00:55:25,120 It's going to decide if it likes that or not. 1011 00:55:25,120 --> 00:55:27,550 It turns out 10,001 isn't prime. 1012 00:55:27,550 --> 00:55:29,610 So it'll force it again and again and again. 1013 00:55:29,610 --> 00:55:32,920 1014 00:55:32,920 --> 00:55:37,100 And finally, I think the first prime it hits is 10,009. 1015 00:55:37,100 --> 00:55:40,465 And at that point, it'll stop. 1016 00:55:40,465 --> 00:55:42,500 And that will be the first prime, and then eventually, 1017 00:55:42,500 --> 00:55:45,240 it'll need the second prime. 1018 00:55:45,240 --> 00:55:47,030 So at that point, it will go again. 1019 00:55:47,030 --> 00:55:51,880 So you see what happens is that no more gets generated 1020 00:55:51,880 --> 00:55:53,130 than you actually need. 1021 00:55:53,130 --> 00:55:56,690 1022 00:55:56,690 --> 00:56:00,060 That enumerator is not going to generate any more integers 1023 00:56:00,060 --> 00:56:02,410 than the filter asks it for as it's pulling in things to 1024 00:56:02,410 --> 00:56:04,930 check for primality. 1025 00:56:04,930 --> 00:56:07,290 And the filter is not going to generate any more stuff than 1026 00:56:07,290 --> 00:56:11,255 you ask it for, which is the head of the tail. 1027 00:56:11,255 --> 00:56:17,180 You see, what's happened is we've put that mixing of 1028 00:56:17,180 --> 00:56:20,130 generation and test into what actually happens in the 1029 00:56:20,130 --> 00:56:24,250 computer, even though that's not apparently what's 1030 00:56:24,250 --> 00:56:28,160 happening from looking at our programs. 1031 00:56:28,160 --> 00:56:30,230 OK, well, that seemed easy. 1032 00:56:30,230 --> 00:56:33,326 All of this mechanism got put into this magic delay. 1033 00:56:33,326 --> 00:56:36,900 So you're saying, gee, that must be where the magic is. 1034 00:56:36,900 --> 00:56:39,070 But see there's no magic there either. 1035 00:56:39,070 --> 00:56:40,610 You know what delay is. 1036 00:56:40,610 --> 00:56:50,040 Delay on some expression is just an abbreviation for-- 1037 00:56:50,040 --> 00:56:53,400 1038 00:56:53,400 --> 00:56:56,490 well, what's a promise to compute an expression? 1039 00:56:56,490 --> 00:57:00,700 Lambda of nil, procedure of no arguments, which is that 1040 00:57:00,700 --> 00:57:03,000 expression. 1041 00:57:03,000 --> 00:57:03,930 That's what a procedure is. 1042 00:57:03,930 --> 00:57:06,050 It says I'm going to compute an expression. 1043 00:57:06,050 --> 00:57:07,460 What's force? 1044 00:57:07,460 --> 00:57:10,800 How do I take up a promise? 1045 00:57:10,800 --> 00:57:15,890 Well, force of some procedure, a promise, is just run it. 1046 00:57:15,890 --> 00:57:18,710 1047 00:57:18,710 --> 00:57:20,120 Done. 1048 00:57:20,120 --> 00:57:23,580 So there's no magic there at all. 1049 00:57:23,580 --> 00:57:26,440 Well, what have we done? 1050 00:57:26,440 --> 00:57:29,510 We said the old style, traditional style of 1051 00:57:29,510 --> 00:57:30,960 programming is more efficient. 1052 00:57:30,960 --> 00:57:35,260 And the stream thing is more perspicuous. 1053 00:57:35,260 --> 00:57:40,070 And we managed to make the stream procedures run like the 1054 00:57:40,070 --> 00:57:43,350 other procedures by using delay. 1055 00:57:43,350 --> 00:57:46,880 And the thing that delay did for us was to de-couple the 1056 00:57:46,880 --> 00:57:52,150 apparent order of events in our programs from the actual 1057 00:57:52,150 --> 00:57:54,440 order of events that happened in the machine. 1058 00:57:54,440 --> 00:57:56,540 That's really what delay is doing. 1059 00:57:56,540 --> 00:57:58,290 That's exactly the whole point. 1060 00:57:58,290 --> 00:58:04,720 We've given up the idea that our procedures, as they run, 1061 00:58:04,720 --> 00:58:09,182 or as we look at them, mirror some clear notion of time. 1062 00:58:09,182 --> 00:58:12,960 And by giving that up, we give delay the freedom to arrange 1063 00:58:12,960 --> 00:58:16,690 the order of events in the computation the way it likes. 1064 00:58:16,690 --> 00:58:17,610 That's the whole idea. 1065 00:58:17,610 --> 00:58:20,640 We de-couple the apparent order of events in our 1066 00:58:20,640 --> 00:58:24,200 programs from the actual order of events in the computer. 1067 00:58:24,200 --> 00:58:25,770 OK, well there's one more detail. 1068 00:58:25,770 --> 00:58:27,750 It's just a technical detail, but it's actually 1069 00:58:27,750 --> 00:58:29,730 an important one. 1070 00:58:29,730 --> 00:58:32,190 As you run through these recursive programs unwinding, 1071 00:58:32,190 --> 00:58:35,360 you'll see a lot of things that look like tail of the 1072 00:58:35,360 --> 00:58:39,320 tail of the tail. 1073 00:58:39,320 --> 00:58:41,840 That's the kind of thing that would happen as I go CONSing 1074 00:58:41,840 --> 00:58:43,860 down a stream all the way. 1075 00:58:43,860 --> 00:58:47,170 And if each time I'm doing that, each time to compute a 1076 00:58:47,170 --> 00:58:51,830 tail, I evaluate a procedure which then has to go 1077 00:58:51,830 --> 00:58:54,270 re-compute its tail, and re-compute its tail and 1078 00:58:54,270 --> 00:58:56,380 recompute its tail each time, you can see that's very 1079 00:58:56,380 --> 00:58:59,610 inefficient compared to just having a list where the 1080 00:58:59,610 --> 00:59:02,510 elements are all there, and I don't have to re-compute each 1081 00:59:02,510 --> 00:59:05,290 tail every time I get the next tail. 1082 00:59:05,290 --> 00:59:15,030 So there's one little hack to slightly change what delay is, 1083 00:59:15,030 --> 00:59:17,380 and make it a thing which is-- 1084 00:59:17,380 --> 00:59:20,390 I'll write it this way. 1085 00:59:20,390 --> 00:59:27,360 The actual implementation, delay is an abbreviation for 1086 00:59:27,360 --> 00:59:31,000 this thing, memo-proc of a procedure. 1087 00:59:31,000 --> 00:59:35,150 Memo-proc is a special thing that transforms a procedure. 1088 00:59:35,150 --> 00:59:39,250 What it does is it takes a procedure of no arguments and 1089 00:59:39,250 --> 00:59:42,190 it transforms it into a procedure that'll only have to 1090 00:59:42,190 --> 00:59:44,806 do its computation once. 1091 00:59:44,806 --> 00:59:48,700 And what I mean by that is, you give it a procedure. 1092 00:59:48,700 --> 00:59:51,950 The result of memo-proc will be a new procedure, which the 1093 00:59:51,950 --> 00:59:55,370 first time you call it, will run the original procedure, 1094 00:59:55,370 --> 01:00:00,040 remember what result it got, and then from ever on after, 1095 01:00:00,040 --> 01:00:01,610 when you call it, it just won't have to do the 1096 01:00:01,610 --> 01:00:02,360 computation. 1097 01:00:02,360 --> 01:00:05,200 It will have cached that result someplace. 1098 01:00:05,200 --> 01:00:06,550 And here's an implementation of memo-proc. 1099 01:00:06,550 --> 01:00:11,210 1100 01:00:11,210 --> 01:00:12,710 Once you have the idea, it's easy to implement. 1101 01:00:12,710 --> 01:00:15,830 Memo-proc is this little thing that has two 1102 01:00:15,830 --> 01:00:17,390 little flags in there. 1103 01:00:17,390 --> 01:00:20,320 It says, have I already been run? 1104 01:00:20,320 --> 01:00:23,620 And initially it says, no, I haven't already been run. 1105 01:00:23,620 --> 01:00:29,070 And what was the result I got the last time I was run? 1106 01:00:29,070 --> 01:00:32,200 So memo-proc takes a procedure called proc, and it returns a 1107 01:00:32,200 --> 01:00:34,360 new procedure of no arguments. 1108 01:00:34,360 --> 01:00:38,610 Proc is supposed to be a procedure of no arguments. 1109 01:00:38,610 --> 01:00:42,970 And it says, oh, if I'm not already run, then I'm going to 1110 01:00:42,970 --> 01:00:44,430 do a sequence of things. 1111 01:00:44,430 --> 01:00:48,450 I'm going to compute proc, I'm going to save that. 1112 01:00:48,450 --> 01:00:51,140 I'm going to stash that in the variable result. 1113 01:00:51,140 --> 01:00:53,510 I'm going to make a note to myself that I've already been 1114 01:00:53,510 --> 01:00:56,610 run, and then I'll return the result. 1115 01:00:56,610 --> 01:00:59,010 So that's if you compute it if it's not already run. 1116 01:00:59,010 --> 01:01:01,040 If you call it and it's already been run, it just 1117 01:01:01,040 --> 01:01:03,420 returns the result. 1118 01:01:03,420 --> 01:01:08,400 So that's a little clever hack called memoization. 1119 01:01:08,400 --> 01:01:12,100 And in this case, it short circuits having to re-compute 1120 01:01:12,100 --> 01:01:15,270 the tail of the tail of the tail of the tail of the tail. 1121 01:01:15,270 --> 01:01:17,810 So there isn't even that kind of inefficiency. 1122 01:01:17,810 --> 01:01:20,590 And in fact, the streams will run with pretty much the same 1123 01:01:20,590 --> 01:01:24,210 efficiency as the other programs precisely. 1124 01:01:24,210 --> 01:01:28,110 And remember, again, the whole idea of this is that we've 1125 01:01:28,110 --> 01:01:32,390 used the fact that there's no really good dividing line 1126 01:01:32,390 --> 01:01:33,610 between procedures and data. 1127 01:01:33,610 --> 01:01:36,510 We've written data structures that, in fact, are sort of 1128 01:01:36,510 --> 01:01:38,760 like procedures. 1129 01:01:38,760 --> 01:01:45,280 And what that's allowed us to do is take an example of a 1130 01:01:45,280 --> 01:01:49,620 common control structure, in this place iteration. 1131 01:01:49,620 --> 01:01:52,460 And we've built a data structure which, since itself 1132 01:01:52,460 --> 01:01:54,530 is a procedure, kind of has this iteration control 1133 01:01:54,530 --> 01:01:55,496 structure in it. 1134 01:01:55,496 --> 01:01:58,650 And that's really what streams are. 1135 01:01:58,650 --> 01:01:59,900 OK, questions? 1136 01:01:59,900 --> 01:02:03,950 1137 01:02:03,950 --> 01:02:06,110 AUDIENCE: Your description of tail-tail-tail, if I 1138 01:02:06,110 --> 01:02:10,050 understand it correctly, force is actually execution of a 1139 01:02:10,050 --> 01:02:13,052 procedure, if it's done without this memo-proc thing. 1140 01:02:13,052 --> 01:02:16,380 And you implied that memo-proc gets around that problem. 1141 01:02:16,380 --> 01:02:20,580 Doesn't it only get around it if tail-tail-tail is always 1142 01:02:20,580 --> 01:02:22,550 executing exactly the same-- 1143 01:02:22,550 --> 01:02:23,500 PROFESSOR: Oh, that's-- 1144 01:02:23,500 --> 01:02:23,910 sure. 1145 01:02:23,910 --> 01:02:26,050 AUDIENCE: I guess I missed that point. 1146 01:02:26,050 --> 01:02:26,540 PROFESSOR: Oh, sure. 1147 01:02:26,540 --> 01:02:27,790 I mean the point is-- 1148 01:02:27,790 --> 01:02:31,160 1149 01:02:31,160 --> 01:02:31,290 yeah. 1150 01:02:31,290 --> 01:02:34,160 I mean I have to do a computation to get the answer. 1151 01:02:34,160 --> 01:02:37,590 But the point is, once I've found the tail of the stream, 1152 01:02:37,590 --> 01:02:39,530 to get the tail of the tail, I shouldn't have had to 1153 01:02:39,530 --> 01:02:42,980 re-compute the first tail. 1154 01:02:42,980 --> 01:02:45,370 See, and if I didn't use memo-proc, that re-computation 1155 01:02:45,370 --> 01:02:46,460 would have been done. 1156 01:02:46,460 --> 01:02:47,710 AUDIENCE: I understand now. 1157 01:02:47,710 --> 01:02:50,830 1158 01:02:50,830 --> 01:02:52,550 AUDIENCE: In one of your examples, you mentioned that 1159 01:02:52,550 --> 01:02:55,010 we were able to use the substitution model because 1160 01:02:55,010 --> 01:02:56,830 there are no side effects. 1161 01:02:56,830 --> 01:03:01,040 What if we had a single processing unit-- 1162 01:03:01,040 --> 01:03:03,620 if we had a side effect, if we had a state? 1163 01:03:03,620 --> 01:03:09,120 Could we still practically build the stream model? 1164 01:03:09,120 --> 01:03:09,530 PROFESSOR: Maybe. 1165 01:03:09,530 --> 01:03:10,540 That's a hard question. 1166 01:03:10,540 --> 01:03:15,540 I'm going to talk a little bit later about the places where 1167 01:03:15,540 --> 01:03:18,960 substitution and side effects don't really mix very well. 1168 01:03:18,960 --> 01:03:21,170 But in general, I think the answer is unless you're very 1169 01:03:21,170 --> 01:03:23,920 careful, any amount of side effect is going to mess up 1170 01:03:23,920 --> 01:03:25,170 everything. 1171 01:03:25,170 --> 01:03:35,490 1172 01:03:35,490 --> 01:03:36,150 AUDIENCE: Sorry, I didn't quite understand 1173 01:03:36,150 --> 01:03:39,410 the memo-proc operation. 1174 01:03:39,410 --> 01:03:41,990 When do you execute the lambda? 1175 01:03:41,990 --> 01:03:46,270 In other words, when memo-proc is executed, just this lambda 1176 01:03:46,270 --> 01:03:47,600 expression is being generated. 1177 01:03:47,600 --> 01:03:50,390 But it's not clear to me when it's executed. 1178 01:03:50,390 --> 01:03:51,350 PROFESSOR: Right. 1179 01:03:51,350 --> 01:03:53,890 What memo-proc does-- remember, the thing that's 1180 01:03:53,890 --> 01:03:57,290 going into memo-proc, the thing proc, is a procedure of 1181 01:03:57,290 --> 01:03:57,930 no arguments. 1182 01:03:57,930 --> 01:04:00,390 And someday, you're going to call it. 1183 01:04:00,390 --> 01:04:03,350 Memo-proc translates that procedure into another 1184 01:04:03,350 --> 01:04:05,110 procedure of no arguments, which someday 1185 01:04:05,110 --> 01:04:06,620 you're going to call. 1186 01:04:06,620 --> 01:04:09,890 That's that lambda. 1187 01:04:09,890 --> 01:04:17,370 So here, where I initially built as my tail of the 1188 01:04:17,370 --> 01:04:20,680 stream, say, this procedure of no arguments, which 1189 01:04:20,680 --> 01:04:24,100 someday I'll call. 1190 01:04:24,100 --> 01:04:27,130 Instead, I'm going to have the tail of the stream be 1191 01:04:27,130 --> 01:04:30,650 memo-proc of it, which someday I'll call. 1192 01:04:30,650 --> 01:04:35,340 So that lambda of nil, that gets called when you call the 1193 01:04:35,340 --> 01:04:40,990 memo-proc, when you call the result of that memo-proc, 1194 01:04:40,990 --> 01:04:44,400 which would be ordinarily when you would have called the 1195 01:04:44,400 --> 01:04:47,642 original thing that you set it. 1196 01:04:47,642 --> 01:04:49,690 AUDIENCE: OK, the reason I ask is I had a feeling that when 1197 01:04:49,690 --> 01:04:52,610 you call memo-proc, you just return this lambda. 1198 01:04:52,610 --> 01:04:53,770 PROFESSOR: That's right. 1199 01:04:53,770 --> 01:04:58,100 When you call memo-proc, you return the lambda. 1200 01:04:58,100 --> 01:05:00,090 You never evaluate the expression at all, until the 1201 01:05:00,090 --> 01:05:02,270 first time that you would have evaluated it. 1202 01:05:02,270 --> 01:05:07,590 1203 01:05:07,590 --> 01:05:10,000 AUDIENCE: Do I understand it right that you actually have 1204 01:05:10,000 --> 01:05:12,980 to build the list up, but the elements of the 1205 01:05:12,980 --> 01:05:14,240 list don't get evaluated? 1206 01:05:14,240 --> 01:05:15,630 The expressions don't get evaluated? 1207 01:05:15,630 --> 01:05:18,540 But at each stage, you actually are building a list. 1208 01:05:18,540 --> 01:05:19,750 PROFESSOR: That's-- 1209 01:05:19,750 --> 01:05:20,700 I really should have said this. 1210 01:05:20,700 --> 01:05:22,270 That's a really good point. 1211 01:05:22,270 --> 01:05:23,660 No, it's not quite right. 1212 01:05:23,660 --> 01:05:25,080 Because what happens is this. 1213 01:05:25,080 --> 01:05:26,890 Let me draw this as pairs. 1214 01:05:26,890 --> 01:05:29,710 Suppose I'm going to make a big stream, like enumerate 1215 01:05:29,710 --> 01:05:32,740 interval, 1 through 1 billion. 1216 01:05:32,740 --> 01:05:43,045 What that is, is a pair with a 1 and a promise. 1217 01:05:43,045 --> 01:05:46,520 1218 01:05:46,520 --> 01:05:47,890 That's exactly what it is. 1219 01:05:47,890 --> 01:05:49,140 Nothing got built up. 1220 01:05:49,140 --> 01:05:51,600 1221 01:05:51,600 --> 01:05:56,370 When I go and force this, and say, what happens? 1222 01:05:56,370 --> 01:06:00,530 Well, this thing is now also recursively a CONS. 1223 01:06:00,530 --> 01:06:07,770 So that this promise now is the next thing, which is a 2 1224 01:06:07,770 --> 01:06:11,350 and a promise to do more. 1225 01:06:11,350 --> 01:06:14,470 And so on and so on and so on. 1226 01:06:14,470 --> 01:06:18,200 So nothing gets built up until you walk down the stream. 1227 01:06:18,200 --> 01:06:20,790 Because what's sitting here is not the list, but a promise to 1228 01:06:20,790 --> 01:06:24,250 generate the list. And by promise, 1229 01:06:24,250 --> 01:06:25,500 technically I mean procedure. 1230 01:06:25,500 --> 01:06:28,050 1231 01:06:28,050 --> 01:06:30,485 So it doesn't get built up. 1232 01:06:30,485 --> 01:06:34,280 Yeah, I should have said that before this point. 1233 01:06:34,280 --> 01:06:34,490 OK. 1234 01:06:34,490 --> 01:06:34,790 Thank you. 1235 01:06:34,790 --> 01:06:36,340 Let's take a break. 1236 01:06:36,340 --> 01:06:55,828 ================================================ FILE: SrtEN/lec6b_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:20,970 1 00:00:20,970 --> 00:00:24,580 PROFESSOR: OK, well, we've been looking at streams, this 2 00:00:24,580 --> 00:00:28,870 signal processing way of putting systems together. 3 00:00:28,870 --> 00:00:35,200 And remember, the key idea is that we decouple the apparent 4 00:00:35,200 --> 00:00:38,480 order of events in our programs from the actual order 5 00:00:38,480 --> 00:00:40,635 of events in the computer. 6 00:00:40,635 --> 00:00:43,630 And that means that we can start dealing with very long 7 00:00:43,630 --> 00:00:46,340 streams and only having to generate 8 00:00:46,340 --> 00:00:47,500 the elements on demand. 9 00:00:47,500 --> 00:00:50,310 That sort of on-demand computation is built into the 10 00:00:50,310 --> 00:00:51,560 stream's data structure. 11 00:00:51,560 --> 00:00:54,450 12 00:00:54,450 --> 00:00:55,990 So if we have a very long stream, we only 13 00:00:55,990 --> 00:00:58,040 compute what we need. 14 00:00:58,040 --> 00:01:00,750 The things only get computed when we actually ask for them. 15 00:01:00,750 --> 00:01:02,110 Well, what are examples? 16 00:01:02,110 --> 00:01:04,800 Are they actually asking for them? 17 00:01:04,800 --> 00:01:11,050 For instance, we might ask for the n-th element of a stream. 18 00:01:11,050 --> 00:01:16,360 19 00:01:16,360 --> 00:01:18,130 Here's a procedure that computes the n-th 20 00:01:18,130 --> 00:01:20,400 element of a stream. 21 00:01:20,400 --> 00:01:23,810 An integer n, the n-th element of some stream s, and we just 22 00:01:23,810 --> 00:01:25,570 recursively walk down the stream. 23 00:01:25,570 --> 00:01:27,960 And the end of 0, we compute the head. 24 00:01:27,960 --> 00:01:32,350 Otherwise, it's the n-th the minus 1 element of the tail of 25 00:01:32,350 --> 00:01:34,310 the stream. 26 00:01:34,310 --> 00:01:36,570 Those two are just like for Lisp, but the difference is 27 00:01:36,570 --> 00:01:39,580 those elements aren't going to get computed until we walk 28 00:01:39,580 --> 00:01:41,700 down, taking successive n-ths. 29 00:01:41,700 --> 00:01:43,630 So that's one way that the stream 30 00:01:43,630 --> 00:01:45,910 elements might get forced. 31 00:01:45,910 --> 00:01:47,980 And another way, here's a little procedure 32 00:01:47,980 --> 00:01:49,300 that prints a stream. 33 00:01:49,300 --> 00:01:54,150 We say print a stream, so to print a stream s. 34 00:01:54,150 --> 00:01:55,315 Well, what do we do? 35 00:01:55,315 --> 00:01:58,270 We print the head of the stream, and that will cause 36 00:01:58,270 --> 00:01:59,720 the head to be computed. 37 00:01:59,720 --> 00:02:04,990 And then we recursively print stream the tail of the stream. 38 00:02:04,990 --> 00:02:07,190 And if we're already done, maybe we have to return 39 00:02:07,190 --> 00:02:09,660 something about the message done. 40 00:02:09,660 --> 00:02:12,250 OK, and then so if you make a stream, you could say here's 41 00:02:12,250 --> 00:02:14,310 the stream, this very long stream. 42 00:02:14,310 --> 00:02:16,990 And then you say print the stream, and the elements of 43 00:02:16,990 --> 00:02:20,550 the stream will get computed successively as that print 44 00:02:20,550 --> 00:02:21,320 calls them. 45 00:02:21,320 --> 00:02:24,680 They won't get all computed initially. 46 00:02:24,680 --> 00:02:30,190 So in this way, we can deal with some very long streams. 47 00:02:30,190 --> 00:02:33,600 Well, how long can a stream be? 48 00:02:33,600 --> 00:02:36,360 Well, it can be infinitely long. 49 00:02:36,360 --> 00:02:38,920 Let's look at an example here on the computer. 50 00:02:38,920 --> 00:02:43,400 I could walk up to this computer, and I could say-- 51 00:02:43,400 --> 00:02:52,270 how about we'll define the stream of integers starting 52 00:02:52,270 --> 00:02:56,170 with some number N, the stream of positive integers starting 53 00:02:56,170 --> 00:02:57,420 with some number n. 54 00:02:57,420 --> 00:02:59,760 55 00:02:59,760 --> 00:03:12,990 And that's cons-stream of n onto the 56 00:03:12,990 --> 00:03:19,010 integers from one more. 57 00:03:19,010 --> 00:03:24,680 58 00:03:24,680 --> 00:03:25,930 So there are the integers. 59 00:03:25,930 --> 00:03:28,800 60 00:03:28,800 --> 00:03:31,500 Then I could say let's get all the integers. 61 00:03:31,500 --> 00:03:34,410 62 00:03:34,410 --> 00:03:43,330 define the stream of integers to be the integers 63 00:03:43,330 --> 00:03:44,580 starting with 1. 64 00:03:44,580 --> 00:03:48,840 65 00:03:48,840 --> 00:03:54,950 And now if I say something like what's the what's the 66 00:03:54,950 --> 00:04:02,995 20th integer. 67 00:04:02,995 --> 00:04:07,270 So it's 21 because we start counting at 0. 68 00:04:07,270 --> 00:04:09,450 Or I can do more complicated things. 69 00:04:09,450 --> 00:04:10,840 Let me to define a little predicate here. 70 00:04:10,840 --> 00:04:13,740 71 00:04:13,740 --> 00:04:19,160 How about define no-seven. 72 00:04:19,160 --> 00:04:22,126 It's going to test an integer, and it's 73 00:04:22,126 --> 00:04:23,376 going to say it's not. 74 00:04:23,376 --> 00:04:28,820 75 00:04:28,820 --> 00:04:38,175 I take the remainder of x by 7, I don't get 0. 76 00:04:38,175 --> 00:04:41,890 77 00:04:41,890 --> 00:04:50,360 And then I could say define the integers with no sevens to 78 00:04:50,360 --> 00:04:58,885 be, take all the integers and filter them to have no sevens. 79 00:04:58,885 --> 00:05:11,570 80 00:05:11,570 --> 00:05:14,060 So now I've got the stream of all the integers that are not 81 00:05:14,060 --> 00:05:16,360 divisible by seven. 82 00:05:16,360 --> 00:05:25,420 So if I say what's the 100th integer and the list not 83 00:05:25,420 --> 00:05:28,320 divisible by seven, I get 117. 84 00:05:28,320 --> 00:05:35,270 Or if I'd like to say well, gee, what are all of them? 85 00:05:35,270 --> 00:05:39,810 So I could say print stream all these integers with no 86 00:05:39,810 --> 00:05:41,700 seven, it goes off printing. 87 00:05:41,700 --> 00:05:45,100 88 00:05:45,100 --> 00:05:47,070 You may have to wait a very long time to see them all. 89 00:05:47,070 --> 00:05:52,670 90 00:05:52,670 --> 00:05:56,040 Well, you can start asking, gee, is it really true that 91 00:05:56,040 --> 00:05:59,080 this data structure with the integers is 92 00:05:59,080 --> 00:06:01,100 really all the integers? 93 00:06:01,100 --> 00:06:04,053 And let me draw a picture of that program I just wrote. 94 00:06:04,053 --> 00:06:08,170 95 00:06:08,170 --> 00:06:09,980 Here's the definition of the integers again that I just 96 00:06:09,980 --> 00:06:14,850 typed in, Right it's a cons of the first integer under the 97 00:06:14,850 --> 00:06:18,120 integer starting with the rest. Now, we can make a 98 00:06:18,120 --> 00:06:19,775 picture of that and see what it looks like. 99 00:06:19,775 --> 00:06:22,720 100 00:06:22,720 --> 00:06:26,270 Conceptually, what I have is a box that's the integer 101 00:06:26,270 --> 00:06:27,420 starting with n. 102 00:06:27,420 --> 00:06:31,900 It takes in some number n, and it's going to 103 00:06:31,900 --> 00:06:35,050 return a stream of-- 104 00:06:35,050 --> 00:06:37,705 this infinite stream of all integers starting with n. 105 00:06:37,705 --> 00:06:38,690 And what do I do? 106 00:06:38,690 --> 00:06:42,470 Well, this is an integers from box. 107 00:06:42,470 --> 00:06:45,070 108 00:06:45,070 --> 00:06:45,800 What's it got in it? 109 00:06:45,800 --> 00:06:54,110 Well, it takes in this n, and it increments it. 110 00:06:54,110 --> 00:06:58,030 111 00:06:58,030 --> 00:07:01,920 And then it puts the result into recursively another 112 00:07:01,920 --> 00:07:03,170 integer's from box. 113 00:07:03,170 --> 00:07:06,870 114 00:07:06,870 --> 00:07:10,630 It takes the result of that and the original n and puts 115 00:07:10,630 --> 00:07:14,270 those together with a cons and forms a stream. 116 00:07:14,270 --> 00:07:18,530 So that's a picture of that program I wrote. 117 00:07:18,530 --> 00:07:18,780 Let's see. 118 00:07:18,780 --> 00:07:21,380 These kind of diagrams we first saw drawn by Peter 119 00:07:21,380 --> 00:07:23,320 Henderson, the same guy who did the Escher language. 120 00:07:23,320 --> 00:07:26,170 We call them Henderson diagrams. And the convention 121 00:07:26,170 --> 00:07:28,530 here is that you put these things together. 122 00:07:28,530 --> 00:07:33,260 And the solid lines are things coming out are streams, and 123 00:07:33,260 --> 00:07:37,270 dotted lines are initial values going in. 124 00:07:37,270 --> 00:07:39,440 So this one has the shape of-- 125 00:07:39,440 --> 00:07:41,820 it takes in some integer, some initial value, 126 00:07:41,820 --> 00:07:43,070 and outputs a stream. 127 00:07:43,070 --> 00:07:46,410 128 00:07:46,410 --> 00:07:48,380 Again, you can ask. 129 00:07:48,380 --> 00:07:49,710 Is that data structure integers 130 00:07:49,710 --> 00:07:52,340 really all the integers? 131 00:07:52,340 --> 00:07:55,190 Or is it is something that's cleverly arranged so that 132 00:07:55,190 --> 00:07:58,190 whenever you look for an integer you find it there? 133 00:07:58,190 --> 00:07:59,780 That's sort of a philosophical question, right? 134 00:07:59,780 --> 00:08:03,090 If something is there whenever you look, is it 135 00:08:03,090 --> 00:08:04,450 really there or not? 136 00:08:04,450 --> 00:08:07,970 It's sort of the same sense in which the money in your 137 00:08:07,970 --> 00:08:09,420 savings account is in the bank. 138 00:08:09,420 --> 00:08:12,380 139 00:08:12,380 --> 00:08:19,830 Well, let me do another example. 140 00:08:19,830 --> 00:08:22,040 Gee, we started the course with an algorithm from 141 00:08:22,040 --> 00:08:25,910 Alexandria, which was Heron of Alexandria's algorithm for 142 00:08:25,910 --> 00:08:28,470 computing the square root. 143 00:08:28,470 --> 00:08:32,030 Let's take a look at another Alexandrian algorithm. 144 00:08:32,030 --> 00:08:37,860 This one is Eratosthenes method for computing all of 145 00:08:37,860 --> 00:08:39,110 the primes. 146 00:08:39,110 --> 00:08:41,169 147 00:08:41,169 --> 00:08:42,830 It is called the Sieve of Eratosthenes. 148 00:08:42,830 --> 00:08:51,830 And what you do is you start out, and you list all the 149 00:08:51,830 --> 00:08:53,880 integers, say, starting with 2. 150 00:08:53,880 --> 00:08:55,890 And then you take the first integer, and you say, oh, 151 00:08:55,890 --> 00:08:57,310 that's prime. 152 00:08:57,310 --> 00:08:59,600 And then you go look at the rest, and you cross out all 153 00:08:59,600 --> 00:09:01,230 the things divisible by 2. 154 00:09:01,230 --> 00:09:05,250 So I cross out this and this and this. 155 00:09:05,250 --> 00:09:07,260 This takes a long time because I have to do it 156 00:09:07,260 --> 00:09:11,160 for all of the integers. 157 00:09:11,160 --> 00:09:19,680 So I go through the entire list of integers, crossing the 158 00:09:19,680 --> 00:09:22,010 ones divisible by 2. 159 00:09:22,010 --> 00:09:25,400 And now when I finish with all of the integers, I go back and 160 00:09:25,400 --> 00:09:27,040 look and say what am I left with? 161 00:09:27,040 --> 00:09:29,330 Well, the first thing that starts there is 3. 162 00:09:29,330 --> 00:09:30,770 So 3 is a prime. 163 00:09:30,770 --> 00:09:33,950 And now I go back through what I'm left with, and I cross out 164 00:09:33,950 --> 00:09:35,120 all the things divisible by 3. 165 00:09:35,120 --> 00:09:44,050 So let's see, 9 and 15 and 21 and 27 and 33 and so on. 166 00:09:44,050 --> 00:09:45,350 I won't finish. 167 00:09:45,350 --> 00:09:47,250 Then I see what I'm left with. 168 00:09:47,250 --> 00:09:50,860 And the next one I have is 5. 169 00:09:50,860 --> 00:09:53,470 Now I can through the rest, and I find the first one 170 00:09:53,470 --> 00:09:54,540 that's divisible by 5. 171 00:09:54,540 --> 00:09:56,590 I cross out from the remainder all the ones that are 172 00:09:56,590 --> 00:09:58,030 divisible by 5. 173 00:09:58,030 --> 00:10:01,890 And I do that, and then I go through and find 7. 174 00:10:01,890 --> 00:10:04,170 Go through all the rest, cross out things divisible 7, and I 175 00:10:04,170 --> 00:10:06,810 keep doing that forever. 176 00:10:06,810 --> 00:10:08,100 And when I'm done, what I'm left with is a 177 00:10:08,100 --> 00:10:10,120 list of all the primes. 178 00:10:10,120 --> 00:10:15,430 So that's the Sieve of Eratosthenes. 179 00:10:15,430 --> 00:10:17,930 Let's look at it as a computer program. 180 00:10:17,930 --> 00:10:19,550 It's a procedure called sieve. 181 00:10:19,550 --> 00:10:27,910 182 00:10:27,910 --> 00:10:30,480 Now, I just write what I did. 183 00:10:30,480 --> 00:10:34,510 I'll say to sieve some stream s. 184 00:10:34,510 --> 00:10:38,770 185 00:10:38,770 --> 00:10:41,280 I'm going to build a stream whose first element is the 186 00:10:41,280 --> 00:10:41,870 head of this. 187 00:10:41,870 --> 00:10:44,930 Remember, I always found the first thing I was left with, 188 00:10:44,930 --> 00:10:48,480 and the rest of it is the result of taking the tail of 189 00:10:48,480 --> 00:10:54,030 this, filtering it to throw away all the things that are 190 00:10:54,030 --> 00:10:59,020 divisible by the head of this, and now sieving the result. 191 00:10:59,020 --> 00:11:01,980 That's just what I did. 192 00:11:01,980 --> 00:11:05,560 And now to get the infinite stream of times, we just sieve 193 00:11:05,560 --> 00:11:06,900 all the integers starting from 2. 194 00:11:06,900 --> 00:11:14,920 195 00:11:14,920 --> 00:11:16,300 Let's try that. 196 00:11:16,300 --> 00:11:19,760 We can actually do it. 197 00:11:19,760 --> 00:11:23,170 I typed in the definition of sieve before, I hope, so I can 198 00:11:23,170 --> 00:11:35,340 say something like define the primes to be the result of 199 00:11:35,340 --> 00:11:41,350 sieving the integers starting with 2. 200 00:11:41,350 --> 00:11:46,760 201 00:11:46,760 --> 00:11:48,100 So now I've got this list of primes. 202 00:11:48,100 --> 00:11:50,990 That's all of the primes, right? 203 00:11:50,990 --> 00:12:01,010 So, if for example, what's the 20th prime in that list? 204 00:12:01,010 --> 00:12:02,540 73. 205 00:12:02,540 --> 00:12:05,080 See, and that little pause, it was only at the point when I 206 00:12:05,080 --> 00:12:06,500 started asking for the 20th prime is 207 00:12:06,500 --> 00:12:07,750 that it started computing. 208 00:12:07,750 --> 00:12:10,370 209 00:12:10,370 --> 00:12:14,960 Or I can say here let's look at all of the primes. 210 00:12:14,960 --> 00:12:22,780 211 00:12:22,780 --> 00:12:25,350 And there it goes computing all of the primes. 212 00:12:25,350 --> 00:12:26,970 Of course, it will take a while again if I want to look 213 00:12:26,970 --> 00:12:28,570 at all of them, so let's stop it. 214 00:12:28,570 --> 00:12:32,030 215 00:12:32,030 --> 00:12:33,130 Let me draw you a picture of that. 216 00:12:33,130 --> 00:12:34,890 Well, I've got a picture of that. 217 00:12:34,890 --> 00:12:37,900 What's that program really look like? 218 00:12:37,900 --> 00:12:39,550 Again, some practice with these diagrams, I 219 00:12:39,550 --> 00:12:42,610 have a sieve box. 220 00:12:42,610 --> 00:12:43,560 How does sieve work? 221 00:12:43,560 --> 00:12:44,810 It takes in a stream. 222 00:12:44,810 --> 00:12:48,850 223 00:12:48,850 --> 00:12:50,870 It splits off the head from the tail. 224 00:12:50,870 --> 00:12:53,500 And the first thing that's going to come out of the sieve 225 00:12:53,500 --> 00:12:54,970 is the head of the original stream. 226 00:12:54,970 --> 00:12:57,796 227 00:12:57,796 --> 00:13:02,550 Then it also takes the head and uses that. 228 00:13:02,550 --> 00:13:03,850 It takes the stream. 229 00:13:03,850 --> 00:13:07,290 It filters the tail and uses the head to filter for 230 00:13:07,290 --> 00:13:09,152 nondivisibility. 231 00:13:09,152 --> 00:13:11,710 It takes the result of nondivisibility and puts it 232 00:13:11,710 --> 00:13:15,130 through another sieve box and puts the result together. 233 00:13:15,130 --> 00:13:17,890 So you can think of this sieve a filter, but notice that it's 234 00:13:17,890 --> 00:13:19,650 an infinitely recursive filter. 235 00:13:19,650 --> 00:13:23,560 Because inside the sieve box is another sieve box, and 236 00:13:23,560 --> 00:13:27,130 inside that is another sieve box and another sieve box. 237 00:13:27,130 --> 00:13:28,960 So you see we start getting some very powerful things. 238 00:13:28,960 --> 00:13:32,390 We're starting to mix this signal processing view of the 239 00:13:32,390 --> 00:13:35,760 world with things like recursion that come from 240 00:13:35,760 --> 00:13:36,690 computation. 241 00:13:36,690 --> 00:13:39,210 And there are all sorts of interesting things you can do 242 00:13:39,210 --> 00:13:40,970 that are like this. 243 00:13:40,970 --> 00:13:42,220 All right, any questions? 244 00:13:42,220 --> 00:13:48,190 245 00:13:48,190 --> 00:13:49,440 OK, let's take a break. 246 00:13:49,440 --> 00:14:28,820 247 00:14:28,820 --> 00:14:31,440 Well, we've been looking at a couple of examples of stream 248 00:14:31,440 --> 00:14:32,690 programming. 249 00:14:32,690 --> 00:14:34,790 250 00:14:34,790 --> 00:14:39,920 All the stream procedures that we've looked at so far have 251 00:14:39,920 --> 00:14:41,490 the same kind of character. 252 00:14:41,490 --> 00:14:44,470 We've been writing these recursive procedures that kind 253 00:14:44,470 --> 00:14:46,820 of generate these stream elements one at a time and put 254 00:14:46,820 --> 00:14:50,030 them together in cons-streams. So we've been thinking a lot 255 00:14:50,030 --> 00:14:51,000 about generators. 256 00:14:51,000 --> 00:14:53,970 There's another way to think about stream processing, and 257 00:14:53,970 --> 00:14:57,840 that's to focus not on programs that sort of process 258 00:14:57,840 --> 00:15:00,840 these elements as you walk down the stream, but on things 259 00:15:00,840 --> 00:15:07,350 that kind of process the streams all at once. 260 00:15:07,350 --> 00:15:09,950 To show you what I mean, let me start by defining two 261 00:15:09,950 --> 00:15:12,410 procedures that will come in handy. 262 00:15:12,410 --> 00:15:17,580 The first one's called add streams. Add streams takes two 263 00:15:17,580 --> 00:15:22,330 streams: s1 and s2. 264 00:15:22,330 --> 00:15:22,460 and. 265 00:15:22,460 --> 00:15:27,240 It's going to produce a stream whose elements are the are the 266 00:15:27,240 --> 00:15:32,970 corresponding sums. We just sort of add them element-wise. 267 00:15:32,970 --> 00:15:36,810 If either stream is empty, we just return the other one. 268 00:15:36,810 --> 00:15:42,000 Otherwise, we're going to make a new stream whose head is the 269 00:15:42,000 --> 00:15:46,890 sum of the two heads and whose tail is the result of 270 00:15:46,890 --> 00:15:50,090 recursively adding the tails. 271 00:15:50,090 --> 00:15:52,100 So that will produce the element-wise sum of two 272 00:15:52,100 --> 00:15:53,150 streams. 273 00:15:53,150 --> 00:15:55,830 And then another useful thing to have 274 00:15:55,830 --> 00:15:57,500 around is scale stream. 275 00:15:57,500 --> 00:16:04,150 Scale stream takes some constant number in a stream s 276 00:16:04,150 --> 00:16:08,140 and is going to produce the stream of elements of s 277 00:16:08,140 --> 00:16:09,710 multiplied by this constant. 278 00:16:09,710 --> 00:16:14,320 And that's easy, that's just a map of the function of an 279 00:16:14,320 --> 00:16:17,040 element that multiplies it by the constant, and we map that 280 00:16:17,040 --> 00:16:18,290 down the stream. 281 00:16:18,290 --> 00:16:20,520 282 00:16:20,520 --> 00:16:23,630 So given those two, let me show you what I mean by 283 00:16:23,630 --> 00:16:27,910 programs that operate on streams all at once. 284 00:16:27,910 --> 00:16:30,200 Let's look at this. 285 00:16:30,200 --> 00:16:31,680 Suppose I write this. 286 00:16:31,680 --> 00:16:32,930 I say define-- 287 00:16:32,930 --> 00:16:36,618 288 00:16:36,618 --> 00:16:39,590 I'll call it ones-- 289 00:16:39,590 --> 00:16:52,190 to be cons-stream of 1 onto ones. 290 00:16:52,190 --> 00:16:54,860 291 00:16:54,860 --> 00:16:56,950 What's that? 292 00:16:56,950 --> 00:17:00,530 That's going to be an infinite stream of ones because the 293 00:17:00,530 --> 00:17:03,330 first thing is 1. 294 00:17:03,330 --> 00:17:07,819 And the tail of it is a thing whose first thing is 1 and 295 00:17:07,819 --> 00:17:11,220 whose tail is a thing whose first thing is 1 and so on and 296 00:17:11,220 --> 00:17:11,780 so on and so on. 297 00:17:11,780 --> 00:17:15,130 So that's an infinite stream of ones. 298 00:17:15,130 --> 00:17:17,380 And now using that, let me give you another definition of 299 00:17:17,380 --> 00:17:18,599 the integers. 300 00:17:18,599 --> 00:17:28,270 We can define the integers to be-- 301 00:17:28,270 --> 00:17:32,820 well, the first integer we'll take to be 1, this cons-stream 302 00:17:32,820 --> 00:17:42,790 of 1 onto the element-wise sum onto add streams of the 303 00:17:42,790 --> 00:17:48,270 integers to ones. 304 00:17:48,270 --> 00:17:54,950 305 00:17:54,950 --> 00:18:01,240 The integers are a thing whose first element is 1, and the 306 00:18:01,240 --> 00:18:04,940 rest of them you get by taking those integers and 307 00:18:04,940 --> 00:18:06,640 incrementing each one by one. 308 00:18:06,640 --> 00:18:10,400 So the second element of the integers is the first element 309 00:18:10,400 --> 00:18:13,940 of the integers incremented by one. 310 00:18:13,940 --> 00:18:15,830 And the rest of that is the next one, and the third 311 00:18:15,830 --> 00:18:19,690 element of that is the same as the first element of the tail 312 00:18:19,690 --> 00:18:25,050 of the integers incremented by one, which is the same as the 313 00:18:25,050 --> 00:18:28,930 first element of the original integers incremented by one 314 00:18:28,930 --> 00:18:31,250 and incremented by one again and so on. 315 00:18:31,250 --> 00:18:35,240 316 00:18:35,240 --> 00:18:36,310 That looks pretty suspicious. 317 00:18:36,310 --> 00:18:40,150 See, notice that it works because of delay. 318 00:18:40,150 --> 00:18:42,480 See, this looks like-- 319 00:18:42,480 --> 00:18:43,870 let's take a look at ones. 320 00:18:43,870 --> 00:18:46,810 This looks like it couldn't even be processed because it's 321 00:18:46,810 --> 00:18:49,410 suddenly saying in order to know what ones is, I say it's 322 00:18:49,410 --> 00:18:51,130 cons-stream of something onto ones. 323 00:18:51,130 --> 00:18:53,220 The reason that works is because of that very sneaky 324 00:18:53,220 --> 00:18:55,250 hidden delay in there. 325 00:18:55,250 --> 00:18:58,870 Because what this really is, remember, cons-stream is just 326 00:18:58,870 --> 00:19:00,290 an abbreviation. 327 00:19:00,290 --> 00:19:08,785 This really is cons of 1 onto delay of ones. 328 00:19:08,785 --> 00:19:12,140 329 00:19:12,140 --> 00:19:15,500 So how does that work? 330 00:19:15,500 --> 00:19:18,020 You say I'm going to define ones. 331 00:19:18,020 --> 00:19:20,700 First I see what ones is supposed to be defined as. 332 00:19:20,700 --> 00:19:27,320 Well, ones is supposed to be defined as a cons whose first 333 00:19:27,320 --> 00:19:30,070 part is 1 and whose second part is, well, it's a promise 334 00:19:30,070 --> 00:19:32,710 to compute something that I don't worry about yet. 335 00:19:32,710 --> 00:19:34,680 So it doesn't bother me that at the point I do this 336 00:19:34,680 --> 00:19:37,270 definition, ones isn't defined. 337 00:19:37,270 --> 00:19:40,670 Having run the definition now, ones is defined. 338 00:19:40,670 --> 00:19:44,920 So that when I go and look at the tail of it, it's defined. 339 00:19:44,920 --> 00:19:46,590 It's very sneaky. 340 00:19:46,590 --> 00:19:48,470 And an integer is the same way. 341 00:19:48,470 --> 00:19:52,060 I can refer to integers here because hidden way down-- 342 00:19:52,060 --> 00:19:53,210 because of this cons-stream. 343 00:19:53,210 --> 00:19:56,200 It's the cons-stream of 1 onto something that I 344 00:19:56,200 --> 00:19:57,050 don't worry that yet. 345 00:19:57,050 --> 00:19:58,970 So I don't look at it, and I don't notice that integers 346 00:19:58,970 --> 00:20:01,320 isn't defined at the point where I try and run the 347 00:20:01,320 --> 00:20:02,570 definition. 348 00:20:02,570 --> 00:20:06,320 349 00:20:06,320 --> 00:20:08,700 OK, let me draw a picture of that integers thing because it 350 00:20:08,700 --> 00:20:12,430 still maybe seems a little bit shaky. 351 00:20:12,430 --> 00:20:15,020 What do I do? 352 00:20:15,020 --> 00:20:23,490 I've got the stream of ones, and that sort of comes in and 353 00:20:23,490 --> 00:20:25,340 goes into an adder that's going to be 354 00:20:25,340 --> 00:20:26,590 this add streams thing. 355 00:20:26,590 --> 00:20:29,310 356 00:20:29,310 --> 00:20:33,260 And that goes in-- 357 00:20:33,260 --> 00:20:35,760 that's going to put out the integers. 358 00:20:35,760 --> 00:20:40,760 359 00:20:40,760 --> 00:20:45,280 And the other thing that goes into the adder here is the 360 00:20:45,280 --> 00:20:48,060 integer, so there's a little feedback loop. 361 00:20:48,060 --> 00:20:51,930 And all I need to start it off is someplace I've got a stick 362 00:20:51,930 --> 00:20:53,180 that initial 1. 363 00:20:53,180 --> 00:20:57,100 364 00:20:57,100 --> 00:21:00,000 In a real signal processing thing, this might be a delay 365 00:21:00,000 --> 00:21:02,910 element with that was initialized to 1. 366 00:21:02,910 --> 00:21:07,860 But there's a picture of that ones program. 367 00:21:07,860 --> 00:21:09,860 And in fact, that looks a lot like-- 368 00:21:09,860 --> 00:21:13,910 if you've seen real signal block diagram things, that 369 00:21:13,910 --> 00:21:17,360 looks a lot like accumulators, finite state accumulators. 370 00:21:17,360 --> 00:21:21,640 And in fact, we can modify this a little bit to change 371 00:21:21,640 --> 00:21:25,700 this into something that integrates a stream or a 372 00:21:25,700 --> 00:21:27,440 finite state accumulator, however you like 373 00:21:27,440 --> 00:21:28,440 to think about it. 374 00:21:28,440 --> 00:21:30,370 So instead of the ones coming in and getting out the 375 00:21:30,370 --> 00:21:35,460 integers, what we'll do is say there's a stream s coming in, 376 00:21:35,460 --> 00:21:43,210 and we're going to get out the integral of this, successive 377 00:21:43,210 --> 00:21:45,700 values of that, and it looks almost the same. 378 00:21:45,700 --> 00:21:49,220 The only thing we're going to do is when s comes in here, 379 00:21:49,220 --> 00:21:53,010 before we just add it in we're going to multiply it 380 00:21:53,010 --> 00:21:54,260 by some number dt. 381 00:21:54,260 --> 00:21:57,680 382 00:21:57,680 --> 00:21:58,790 And now what we have here, this is 383 00:21:58,790 --> 00:22:00,000 exactly the same thing. 384 00:22:00,000 --> 00:22:04,020 We have a box, which is an integrator. 385 00:22:04,020 --> 00:22:09,790 386 00:22:09,790 --> 00:22:15,250 And it takes in a stream s, and instead of 1 here, we can 387 00:22:15,250 --> 00:22:19,980 put the additional value for the integral. 388 00:22:19,980 --> 00:22:23,940 And that one looks very much like a signal processing block 389 00:22:23,940 --> 00:22:25,270 diagram program. 390 00:22:25,270 --> 00:22:27,980 In fact, here's the procedure that looks exactly like that. 391 00:22:27,980 --> 00:22:31,490 392 00:22:31,490 --> 00:22:34,010 Find the integral of a stream. 393 00:22:34,010 --> 00:22:36,350 So an integral's going to take a stream and produce a new 394 00:22:36,350 --> 00:22:39,560 stream, and it takes in an initial value 395 00:22:39,560 --> 00:22:42,230 and some time constant. 396 00:22:42,230 --> 00:22:43,040 And what do we do? 397 00:22:43,040 --> 00:22:45,560 Well, we internally define this thing int, and we make 398 00:22:45,560 --> 00:22:47,850 this internal name so we can feed it back, 399 00:22:47,850 --> 00:22:49,400 loop it around itself. 400 00:22:49,400 --> 00:22:52,380 And int is defined to be something that starts out at 401 00:22:52,380 --> 00:22:58,500 the initial value, and the rest of it is 402 00:22:58,500 --> 00:23:01,280 gotten by adding together. 403 00:23:01,280 --> 00:23:03,980 We take our input stream, scale it by dt, 404 00:23:03,980 --> 00:23:06,880 and add that to int. 405 00:23:06,880 --> 00:23:09,130 And now we'll return from all that the value of integral is 406 00:23:09,130 --> 00:23:10,690 this thing int. 407 00:23:10,690 --> 00:23:13,240 And we use this internal definition syntax so we could 408 00:23:13,240 --> 00:23:14,670 write a little internal definition 409 00:23:14,670 --> 00:23:15,920 that refers to itself. 410 00:23:15,920 --> 00:23:21,880 411 00:23:21,880 --> 00:23:23,710 Well, there are all sorts of things we can do. 412 00:23:23,710 --> 00:23:25,500 Let's try this one. 413 00:23:25,500 --> 00:23:26,895 how about the Fibonacci numbers. 414 00:23:26,895 --> 00:23:32,625 You can say define fibs. 415 00:23:32,625 --> 00:23:36,350 416 00:23:36,350 --> 00:23:37,985 Well, what are the Fibonacci numbers? 417 00:23:37,985 --> 00:23:48,840 They're something that starts out with 0, and 418 00:23:48,840 --> 00:23:50,090 the next one is 1. 419 00:23:50,090 --> 00:23:56,260 420 00:23:56,260 --> 00:24:06,470 And the rest of the Fibonacci numbers are gotten by adding 421 00:24:06,470 --> 00:24:11,000 the Fibonacci numbers to their own tail. 422 00:24:11,000 --> 00:24:17,570 423 00:24:17,570 --> 00:24:20,580 There's a definition of the Fibonacci numbers. 424 00:24:20,580 --> 00:24:21,430 How does that work? 425 00:24:21,430 --> 00:24:25,520 Well, we start off, and someone says compute for us 426 00:24:25,520 --> 00:24:30,490 the Fibonacci numbers, and we're going to tell you it 427 00:24:30,490 --> 00:24:31,870 starts out with 0 and 1. 428 00:24:31,870 --> 00:24:35,790 429 00:24:35,790 --> 00:24:40,320 And everything after the 0 and 1 is gotten by summing two 430 00:24:40,320 --> 00:24:44,580 streams. One is the fibs themselves, and the other one 431 00:24:44,580 --> 00:24:45,830 is the tail of the fibs. 432 00:24:45,830 --> 00:24:48,870 433 00:24:48,870 --> 00:24:52,430 So if I know that these start out with 0 and 1, I know that 434 00:24:52,430 --> 00:24:56,435 the fibs now start out with 0 and 1, and the tail of the 435 00:24:56,435 --> 00:24:58,360 fibs start out with 1. 436 00:24:58,360 --> 00:25:00,850 So as soon as I know that, I know that the next one here is 437 00:25:00,850 --> 00:25:04,600 0 plus 1 is 1, and that tells me that the next one here is 1 438 00:25:04,600 --> 00:25:06,300 and the next one here is 1. 439 00:25:06,300 --> 00:25:09,390 And as soon as I know that, I know that the next one is 2. 440 00:25:09,390 --> 00:25:11,700 So the next one here is 2 and the next one here is 2. 441 00:25:11,700 --> 00:25:12,950 And this is 3. 442 00:25:12,950 --> 00:25:14,720 443 00:25:14,720 --> 00:25:18,530 This one goes to 3, and this is 5. 444 00:25:18,530 --> 00:25:21,500 So it's a perfectly sensible definition. 445 00:25:21,500 --> 00:25:22,830 It's a one-line definition. 446 00:25:22,830 --> 00:25:25,590 And again, I could walk over to the computer and type that 447 00:25:25,590 --> 00:25:28,650 in, exactly that, and then say print stream the Fibonacci 448 00:25:28,650 --> 00:25:30,150 numbers, and they all come flying out. 449 00:25:30,150 --> 00:25:32,790 450 00:25:32,790 --> 00:25:34,120 See, this is a lot like learning 451 00:25:34,120 --> 00:25:36,810 about recursion again. 452 00:25:36,810 --> 00:25:41,350 Instead of thinking that recursive procedures, we have 453 00:25:41,350 --> 00:25:45,160 recursively defined data objects. 454 00:25:45,160 --> 00:25:48,150 But that shouldn't surprise you at all, because by now, 455 00:25:48,150 --> 00:25:50,020 you should be coming to really believe that there's no 456 00:25:50,020 --> 00:25:53,090 difference really between procedures and data. 457 00:25:53,090 --> 00:25:55,550 In fact, in some sense, the underlying streams are 458 00:25:55,550 --> 00:25:57,240 procedures sitting there, although we don't think of 459 00:25:57,240 --> 00:25:58,210 them that way. 460 00:25:58,210 --> 00:26:00,910 So the fact that we have recursive procedures, well, 461 00:26:00,910 --> 00:26:03,630 then it should be natural that we have recursive data, too. 462 00:26:03,630 --> 00:26:07,840 463 00:26:07,840 --> 00:26:09,720 OK, well, this is all pretty neat. 464 00:26:09,720 --> 00:26:13,120 Unfortunately, there are problems that streams aren't 465 00:26:13,120 --> 00:26:14,990 going to solve. 466 00:26:14,990 --> 00:26:17,580 Let me show you one of them. 467 00:26:17,580 --> 00:26:21,190 See, in the same way, let's imagine that we're building an 468 00:26:21,190 --> 00:26:26,810 analog computer to solve some differential equation like, 469 00:26:26,810 --> 00:26:33,720 say, we want to solve the equation y prime dy dt is y 470 00:26:33,720 --> 00:26:36,390 squared, and I'm going to give you some initial value. 471 00:26:36,390 --> 00:26:38,030 I'll tell you y of 0 equals 1. 472 00:26:38,030 --> 00:26:41,060 473 00:26:41,060 --> 00:26:43,690 Let's say dt is equal to something. 474 00:26:43,690 --> 00:26:46,770 475 00:26:46,770 --> 00:26:49,530 Now, in the old days, people built analog computers to 476 00:26:49,530 --> 00:26:51,040 solve these kinds of things. 477 00:26:51,040 --> 00:26:53,020 And the way you do that is really simple. 478 00:26:53,020 --> 00:27:01,030 You get yourself an integrator, like that one, an 479 00:27:01,030 --> 00:27:03,055 integrator box. 480 00:27:03,055 --> 00:27:08,530 And we put in the initial value y of 0 is 1. 481 00:27:08,530 --> 00:27:10,900 And now if we feed something in and get something out, 482 00:27:10,900 --> 00:27:13,890 we'll say, gee, what we're getting out is the answer. 483 00:27:13,890 --> 00:27:18,420 And what we're going to feed in is the derivative, and the 484 00:27:18,420 --> 00:27:21,490 derivative is supposed to be the square of the answer. 485 00:27:21,490 --> 00:27:31,070 So if we take these values and map using square, and if I 486 00:27:31,070 --> 00:27:38,750 feed this around, that's how I build a block diagram for an 487 00:27:38,750 --> 00:27:42,910 analog computer that solves this differential equation. 488 00:27:42,910 --> 00:27:45,630 Now, what we'd like to do is write a stream program that 489 00:27:45,630 --> 00:27:47,230 looks exactly like that. 490 00:27:47,230 --> 00:27:49,390 And what do I mean exactly like that? 491 00:27:49,390 --> 00:28:08,100 Well, I'd say define y to be the integral of dy starting at 492 00:28:08,100 --> 00:28:13,790 1 with 0.001 as a time step. 493 00:28:13,790 --> 00:28:16,805 And I'd like to say that says this. 494 00:28:16,805 --> 00:28:19,635 And then I'd like to say, well, dy is gotten by mapping 495 00:28:19,635 --> 00:28:20,850 the square along y. 496 00:28:20,850 --> 00:28:33,510 So define dy to be map square along y. 497 00:28:33,510 --> 00:28:36,270 So there's a stream description of this analog 498 00:28:36,270 --> 00:28:41,410 computer, and unfortunately, it doesn't work. 499 00:28:41,410 --> 00:28:43,715 And you can see why it doesn't work because when I come in 500 00:28:43,715 --> 00:28:49,550 and say define y to be the integral of dy, it says, oh, 501 00:28:49,550 --> 00:28:51,190 the integral of y-- huh? 502 00:28:51,190 --> 00:28:53,710 Oh, that's undefined. 503 00:28:53,710 --> 00:28:56,860 So I can't write this definition before I've 504 00:28:56,860 --> 00:28:58,770 written this one. 505 00:28:58,770 --> 00:29:00,600 On the other hand, if I try and write this one first, it 506 00:29:00,600 --> 00:29:03,580 says, oh, I define y to be the map of square along y? 507 00:29:03,580 --> 00:29:05,770 Oh, that's not defined yet. 508 00:29:05,770 --> 00:29:07,730 So I can't write this one first, and I can't write that 509 00:29:07,730 --> 00:29:11,580 one first. So I can't quite play this game. 510 00:29:11,580 --> 00:29:17,560 511 00:29:17,560 --> 00:29:20,460 Well, is there a way out? 512 00:29:20,460 --> 00:29:22,200 See, we can do that with ones. 513 00:29:22,200 --> 00:29:27,820 See, over here, we did this thing ones, and we were able 514 00:29:27,820 --> 00:29:30,990 to define ones in terms of ones because of this delay 515 00:29:30,990 --> 00:29:34,770 that was built inside because cons-stream had a delay. 516 00:29:34,770 --> 00:29:36,070 Now, why's it sensible? 517 00:29:36,070 --> 00:29:37,970 Why's it sensible for cons-stream to be built with 518 00:29:37,970 --> 00:29:40,730 this delay? 519 00:29:40,730 --> 00:29:43,940 The reason is that cons-stream can do a useful thing without 520 00:29:43,940 --> 00:29:45,950 looking at its tail. 521 00:29:45,950 --> 00:29:49,050 See, if I say this is cons-stream of 1 onto 522 00:29:49,050 --> 00:29:52,340 something without knowing anything about something, I 523 00:29:52,340 --> 00:29:54,870 know that the stream starts off with 1. 524 00:29:54,870 --> 00:29:56,660 That's why it was sensible to build something like 525 00:29:56,660 --> 00:29:57,910 cons-stream. 526 00:29:57,910 --> 00:29:59,960 527 00:29:59,960 --> 00:30:02,610 So we put a delay in there, and that allows us to have 528 00:30:02,610 --> 00:30:06,320 this sort of self-referential definition. 529 00:30:06,320 --> 00:30:08,190 Well, integral is a little bit the same way. 530 00:30:08,190 --> 00:30:14,620 See, notice for an integral, I can-- 531 00:30:14,620 --> 00:30:17,580 let's go back and look at integral for a second. 532 00:30:17,580 --> 00:30:24,010 See, notice integral, it makes sense to say what's the first 533 00:30:24,010 --> 00:30:27,390 thing in the integral without knowing the stream that you're 534 00:30:27,390 --> 00:30:28,970 integrating. 535 00:30:28,970 --> 00:30:30,770 Because the first thing in the integral is always going to be 536 00:30:30,770 --> 00:30:33,140 the initial value that you're handed. 537 00:30:33,140 --> 00:30:37,090 So integral could be a procedure like cons-stream. 538 00:30:37,090 --> 00:30:39,830 You could define it, and then even before it knows what it's 539 00:30:39,830 --> 00:30:44,360 supposed to be integrating, it knows enough to say what its 540 00:30:44,360 --> 00:30:46,710 initial value is. 541 00:30:46,710 --> 00:30:49,150 So we can make a smarter integral, which is aha, you're 542 00:30:49,150 --> 00:30:51,390 going to give me a stream to integrate and an initial 543 00:30:51,390 --> 00:30:54,140 value, but I really don't have to look at that stream that 544 00:30:54,140 --> 00:30:56,430 I'm supposed to integrate until you ask me to work down 545 00:30:56,430 --> 00:30:58,430 the stream. 546 00:30:58,430 --> 00:31:00,870 In other words, integral can be like cons-stream, and you 547 00:31:00,870 --> 00:31:02,690 can expect that there's going to be a 548 00:31:02,690 --> 00:31:03,710 delay around its integrand. 549 00:31:03,710 --> 00:31:05,610 And we can write that. 550 00:31:05,610 --> 00:31:07,650 Here's a procedure that does that. 551 00:31:07,650 --> 00:31:09,810 Another version of integral, and this is almost like the 552 00:31:09,810 --> 00:31:13,960 previous one, except the stream it's going to get in is 553 00:31:13,960 --> 00:31:17,110 going to expect to be a delayed object. 554 00:31:17,110 --> 00:31:18,850 And how does this integral work? 555 00:31:18,850 --> 00:31:21,340 Well, the little thing it's going to define inside of 556 00:31:21,340 --> 00:31:25,350 itself says on the cons-stream, the initial value 557 00:31:25,350 --> 00:31:29,750 is the initial value, but only inside of that cons-stream, 558 00:31:29,750 --> 00:31:32,300 and remember, there's going to be a hidden delay inside here. 559 00:31:32,300 --> 00:31:34,950 560 00:31:34,950 --> 00:31:38,260 Only inside of that cons-stream will I start 561 00:31:38,260 --> 00:31:43,180 looking at what the actual delayed object is. 562 00:31:43,180 --> 00:31:45,970 So my answer is the first thing's the initial value. 563 00:31:45,970 --> 00:31:50,280 If anybody now asks me for my tail, at that point, I'm going 564 00:31:50,280 --> 00:31:52,680 to force that delayed object-- 565 00:31:52,680 --> 00:31:54,500 and I'll call that s-- 566 00:31:54,500 --> 00:31:58,300 and I do the add streams. So this is an integral which is 567 00:31:58,300 --> 00:31:59,260 sort of like cons-stream. 568 00:31:59,260 --> 00:32:04,120 It's not going to actually try and see what you handed it as 569 00:32:04,120 --> 00:32:06,080 the thing to integrate until you look 570 00:32:06,080 --> 00:32:07,330 past the first element. 571 00:32:07,330 --> 00:32:10,120 572 00:32:10,120 --> 00:32:13,900 And if we do that and we can make this work, all we have to 573 00:32:13,900 --> 00:32:24,120 do here is say define y to the integral of delay of y, of 574 00:32:24,120 --> 00:32:27,090 delay of dy. 575 00:32:27,090 --> 00:32:33,380 So y is going to be the integral of delay of dy 576 00:32:33,380 --> 00:32:35,280 starting at 1, and now this will work. 577 00:32:35,280 --> 00:32:38,190 Because I type in the definition of y, and that 578 00:32:38,190 --> 00:32:40,840 says, oh, I'm supposed to use the integral of something I 579 00:32:40,840 --> 00:32:44,600 don't care about right now because it's a delay. 580 00:32:44,600 --> 00:32:46,320 And these things, now you define dy. 581 00:32:46,320 --> 00:32:47,550 Now, y is defined. 582 00:32:47,550 --> 00:32:51,700 So when I define dy, it can see that definition for y. 583 00:32:51,700 --> 00:32:52,840 Everything is now started up. 584 00:32:52,840 --> 00:32:54,920 Both streams have their first element. 585 00:32:54,920 --> 00:32:57,030 And then when I start mapping down, looking at successive 586 00:32:57,030 --> 00:33:00,590 elements, both y and dy are defined. 587 00:33:00,590 --> 00:33:02,820 So there's a little game you can play that goes a little 588 00:33:02,820 --> 00:33:06,700 bit beyond just using the delay that's hidden inside 589 00:33:06,700 --> 00:33:08,660 streams. Questions? 590 00:33:08,660 --> 00:33:13,178 591 00:33:13,178 --> 00:33:14,428 OK, let's take a break. 592 00:33:14,428 --> 00:34:07,300 593 00:34:07,300 --> 00:34:11,739 Well, just before the break, I'm not sure if you noticed 594 00:34:11,739 --> 00:34:14,320 it, but something nasty started to happen. 595 00:34:14,320 --> 00:34:21,040 We've been going along with the streams and divorcing time 596 00:34:21,040 --> 00:34:24,580 in the programs from time in the computers, and all that 597 00:34:24,580 --> 00:34:27,840 divorcing got hidden inside the streams. And then at the 598 00:34:27,840 --> 00:34:30,429 very end, we saw that sometimes in order to really 599 00:34:30,429 --> 00:34:32,580 take advantage of this method, you have to 600 00:34:32,580 --> 00:34:34,389 pull out other delays. 601 00:34:34,389 --> 00:34:36,480 You have to write some explicit delays that are not 602 00:34:36,480 --> 00:34:39,030 hidden inside that cons-stream. 603 00:34:39,030 --> 00:34:41,400 And I did a very simple example with differential 604 00:34:41,400 --> 00:34:44,150 equations, but if you have some very complicated system 605 00:34:44,150 --> 00:34:47,310 with all kinds of self-loops, it becomes very, very 606 00:34:47,310 --> 00:34:49,929 difficult to see where you need those delays. 607 00:34:49,929 --> 00:34:52,389 And if you leave them out by mistake, it becomes very, very 608 00:34:52,389 --> 00:34:55,550 difficult to see why the thing maybe isn't working. 609 00:34:55,550 --> 00:35:00,330 So that's kind of mess, that by getting this power and 610 00:35:00,330 --> 00:35:03,030 allowing us to use delay, we end up with some very 611 00:35:03,030 --> 00:35:05,080 complicated programming sometimes, because it can't 612 00:35:05,080 --> 00:35:08,690 all be hidden inside the streams. 613 00:35:08,690 --> 00:35:11,036 Well, is there a way out of that? 614 00:35:11,036 --> 00:35:13,480 Yeah, there is a way out of that. 615 00:35:13,480 --> 00:35:17,230 We could change the language so that all procedures acted 616 00:35:17,230 --> 00:35:22,320 like cons-stream, so that every procedure automatically 617 00:35:22,320 --> 00:35:25,450 has an implicit delay around its arguments. 618 00:35:25,450 --> 00:35:27,520 And what would that mean? 619 00:35:27,520 --> 00:35:30,760 That would mean when you call a procedure, the arguments 620 00:35:30,760 --> 00:35:32,210 wouldn't get evaluated. 621 00:35:32,210 --> 00:35:34,820 Instead, they'd only be evaluated when you need them, 622 00:35:34,820 --> 00:35:36,830 so they might be passed off to some other procedure, which 623 00:35:36,830 --> 00:35:39,260 wouldn't evaluate them either. 624 00:35:39,260 --> 00:35:42,150 So all these procedures would be passing promises around. 625 00:35:42,150 --> 00:35:44,970 And then finally maybe when you finally got down to having 626 00:35:44,970 --> 00:35:48,040 to look at the value of something that was handed to a 627 00:35:48,040 --> 00:35:50,720 primitive operator would you actually start calling in all 628 00:35:50,720 --> 00:35:52,380 those promises. 629 00:35:52,380 --> 00:35:54,400 If we did that, since everything would have a 630 00:35:54,400 --> 00:35:58,220 uniform delay, then you wouldn't have to write any 631 00:35:58,220 --> 00:36:00,370 explicit delays, because it would be automatically built 632 00:36:00,370 --> 00:36:02,920 into the way the language works. 633 00:36:02,920 --> 00:36:05,870 Or another way to say that, technically what I'm 634 00:36:05,870 --> 00:36:09,130 describing is what's called-- 635 00:36:09,130 --> 00:36:12,720 if we did that, our language would be so-called 636 00:36:12,720 --> 00:36:22,270 normal-order evaluation language versus what we've 637 00:36:22,270 --> 00:36:24,260 actually been working with, which is 638 00:36:24,260 --> 00:36:25,510 called applicative order-- 639 00:36:25,510 --> 00:36:31,240 640 00:36:31,240 --> 00:36:34,560 versus applicative-order evaluation. 641 00:36:34,560 --> 00:36:36,835 And remember the substitution model for applicative order. 642 00:36:36,835 --> 00:36:40,690 It says when you go and evaluate a combination, you 643 00:36:40,690 --> 00:36:43,590 find the values of all the pieces. 644 00:36:43,590 --> 00:36:46,430 You evaluate the arguments and then you substitute them in 645 00:36:46,430 --> 00:36:47,600 the body of the procedure. 646 00:36:47,600 --> 00:36:49,890 Normal order says no, don't do that. 647 00:36:49,890 --> 00:36:53,980 What you do is effectively substitute in the body of the 648 00:36:53,980 --> 00:36:56,640 procedure, but instead of evaluating the arguments, you 649 00:36:56,640 --> 00:36:58,640 just put a promise to compute them there. 650 00:36:58,640 --> 00:37:01,030 Or another way to say that is you take the expressions for 651 00:37:01,030 --> 00:37:03,370 the arguments, if you like, and substitute them in the 652 00:37:03,370 --> 00:37:06,320 body of the procedure and go on, and never really simplify 653 00:37:06,320 --> 00:37:09,340 anything until you get down to a primitive operator. 654 00:37:09,340 --> 00:37:11,840 So that would be a normal-order language. 655 00:37:11,840 --> 00:37:13,490 Well, why don't we do that? 656 00:37:13,490 --> 00:37:16,550 Because if we did, we'd get all the advantages of delayed 657 00:37:16,550 --> 00:37:18,940 evaluation with none of the mess. 658 00:37:18,940 --> 00:37:22,250 In fact, if we did that and cons was just a delayed 659 00:37:22,250 --> 00:37:24,710 procedure, that would make cons the same as cons-stream. 660 00:37:24,710 --> 00:37:27,240 We wouldn't need streams of all because lists would 661 00:37:27,240 --> 00:37:30,675 automatically be streams. That's how lists would behave, 662 00:37:30,675 --> 00:37:32,350 and data structures would behave that way. 663 00:37:32,350 --> 00:37:35,270 Everything would behave that way, right? 664 00:37:35,270 --> 00:37:38,510 You'd never really do any computation until you actually 665 00:37:38,510 --> 00:37:41,020 needed the answer. 666 00:37:41,020 --> 00:37:42,780 You wouldn't have to worry about all these explicit 667 00:37:42,780 --> 00:37:44,790 annoying delays. 668 00:37:44,790 --> 00:37:47,160 Well, why don't we do that? 669 00:37:47,160 --> 00:37:49,230 First of all, I should say people do do that. 670 00:37:49,230 --> 00:37:51,850 There's some very beautiful languages. 671 00:37:51,850 --> 00:37:56,170 One of the very nicest is a language called Miranda, which 672 00:37:56,170 --> 00:38:00,710 is developed by David Turner at the University of Kent. 673 00:38:00,710 --> 00:38:01,930 And that's how this language works. 674 00:38:01,930 --> 00:38:06,430 It's a normal-order language and its data structures, which 675 00:38:06,430 --> 00:38:09,250 look like lists, are actually streams. And you write 676 00:38:09,250 --> 00:38:11,710 ordinary procedures in Miranda, and they do these 677 00:38:11,710 --> 00:38:13,950 prime things and eight queens things, just 678 00:38:13,950 --> 00:38:14,970 without anything special. 679 00:38:14,970 --> 00:38:17,790 It's all built in there. 680 00:38:17,790 --> 00:38:19,040 But there's a price. 681 00:38:19,040 --> 00:38:21,190 682 00:38:21,190 --> 00:38:23,170 Remember how we got here. 683 00:38:23,170 --> 00:38:26,380 We're decoupling time in the programs 684 00:38:26,380 --> 00:38:27,480 from time in the machines. 685 00:38:27,480 --> 00:38:30,400 And if we put delay, that sort of decouples it everywhere, 686 00:38:30,400 --> 00:38:33,140 not just in streams. Remember what we're trying to do. 687 00:38:33,140 --> 00:38:36,900 We're trying to think about programming as a way to 688 00:38:36,900 --> 00:38:39,300 specify processes. 689 00:38:39,300 --> 00:38:41,690 And if we give up too much time, our language becomes 690 00:38:41,690 --> 00:38:47,030 more elegant, but it becomes a little bit less expressive. 691 00:38:47,030 --> 00:38:51,480 There are certain distinctions that we can't draw. 692 00:38:51,480 --> 00:38:53,980 One of them, for instance, is iteration. 693 00:38:53,980 --> 00:38:58,630 Remember this old procedure, iterative factorial, that we 694 00:38:58,630 --> 00:39:01,230 looked at quite a long time ago. 695 00:39:01,230 --> 00:39:03,410 Iterative factorial had a thing, and it said there was 696 00:39:03,410 --> 00:39:06,290 an internal procedure, and there was a state which was a 697 00:39:06,290 --> 00:39:09,970 product and a counter, and we iterate that 698 00:39:09,970 --> 00:39:12,120 going around the loop. 699 00:39:12,120 --> 00:39:13,880 And we said that was an iterative procedure because it 700 00:39:13,880 --> 00:39:15,730 didn't build up state. 701 00:39:15,730 --> 00:39:19,630 And the reason it didn't build up state is because this iter 702 00:39:19,630 --> 00:39:23,900 that's called is just passing these things around to itself. 703 00:39:23,900 --> 00:39:26,130 Or in the substitution model, you could see in the 704 00:39:26,130 --> 00:39:29,480 substitution model that Jerry did, that in an iterative 705 00:39:29,480 --> 00:39:31,660 procedure, that state doesn't have to grow. 706 00:39:31,660 --> 00:39:33,030 And in fact, we said it doesn't, 707 00:39:33,030 --> 00:39:34,840 so this is an iteration. 708 00:39:34,840 --> 00:39:37,890 But now think about this exact same text if we had a 709 00:39:37,890 --> 00:39:41,150 normal-order language. 710 00:39:41,150 --> 00:39:44,230 What would happen is this would no longer be an 711 00:39:44,230 --> 00:39:45,650 iterative procedure? 712 00:39:45,650 --> 00:39:47,790 And if you really think about the details of the 713 00:39:47,790 --> 00:39:51,460 substitution model, which I'm not going to do here, this 714 00:39:51,460 --> 00:39:52,330 expression would grow. 715 00:39:52,330 --> 00:39:53,280 Why would it grow? 716 00:39:53,280 --> 00:39:56,740 It's because when iter calls itself, it calls itself with 717 00:39:56,740 --> 00:39:58,080 this product. 718 00:39:58,080 --> 00:40:00,210 If it's a normal-order language, that multiplication 719 00:40:00,210 --> 00:40:02,510 is not going to get done. 720 00:40:02,510 --> 00:40:04,790 That's going to say I'm to call myself with a promise to 721 00:40:04,790 --> 00:40:06,670 compute this product. 722 00:40:06,670 --> 00:40:09,760 And now iter goes around again. 723 00:40:09,760 --> 00:40:13,680 And I'm going to call myself with a promise to compute this 724 00:40:13,680 --> 00:40:18,400 product where now one of the one factors is a promise. 725 00:40:18,400 --> 00:40:19,430 And I call myself again. 726 00:40:19,430 --> 00:40:22,580 And if you write out the substitution model for that 727 00:40:22,580 --> 00:40:26,430 iterative process, you'll see exactly the same growth in 728 00:40:26,430 --> 00:40:29,080 state, all those promises that are getting remembered that 729 00:40:29,080 --> 00:40:31,790 have to get called in at the very end. 730 00:40:31,790 --> 00:40:35,690 So one of the disadvantages is that you can't 731 00:40:35,690 --> 00:40:36,980 really express iteration. 732 00:40:36,980 --> 00:40:39,610 Maybe that's a little theoretical reason why not, 733 00:40:39,610 --> 00:40:43,510 but in fact, people who are trying to write real operating 734 00:40:43,510 --> 00:40:46,750 systems in these languages are running into exactly these 735 00:40:46,750 --> 00:40:51,650 types of problems. Like it's perfectly possible to 736 00:40:51,650 --> 00:40:54,610 implement a text editor in languages like these. 737 00:40:54,610 --> 00:40:58,830 But after you work a while, you suddenly have 3 megabytes 738 00:40:58,830 --> 00:41:01,240 of stuff, which is-- 739 00:41:01,240 --> 00:41:04,470 I guess they call them the dragging tail problem of 740 00:41:04,470 --> 00:41:07,320 people who are looking at these, of promises that sort 741 00:41:07,320 --> 00:41:09,260 of haven't been called in because you couldn't quite 742 00:41:09,260 --> 00:41:10,230 express an iteration. 743 00:41:10,230 --> 00:41:14,330 And one of the research questions in these kinds of 744 00:41:14,330 --> 00:41:17,930 languages are figuring out the right compiler technology to 745 00:41:17,930 --> 00:41:20,110 get rid of the so-called dragging tails. 746 00:41:20,110 --> 00:41:23,940 It's not simple. 747 00:41:23,940 --> 00:41:28,520 But there's another kind of more striking issue about why 748 00:41:28,520 --> 00:41:30,100 you just don't go ahead and make your 749 00:41:30,100 --> 00:41:32,056 language normal order. 750 00:41:32,056 --> 00:41:37,440 And the reason is that normal-order evaluation and 751 00:41:37,440 --> 00:41:42,000 side effects just don't mix. 752 00:41:42,000 --> 00:41:45,350 They just don't go together very well. 753 00:41:45,350 --> 00:41:48,360 Somehow, you can't-- 754 00:41:48,360 --> 00:41:51,500 it's sort of you can't simultaneously go around 755 00:41:51,500 --> 00:41:55,990 trying to model objects with local state and change and at 756 00:41:55,990 --> 00:41:58,520 the same time do these normal-order tricks of 757 00:41:58,520 --> 00:42:00,400 de-coupling time. 758 00:42:00,400 --> 00:42:02,010 Let me just show you a really simple 759 00:42:02,010 --> 00:42:03,790 example, very, very simple. 760 00:42:03,790 --> 00:42:07,520 Suppose we had a normal-order language. 761 00:42:07,520 --> 00:42:09,550 And I'm going to start out in this language. 762 00:42:09,550 --> 00:42:10,520 This is now normal order. 763 00:42:10,520 --> 00:42:13,570 I'm going to define x to be 0. 764 00:42:13,570 --> 00:42:15,750 It's just some variable I'll initialize. 765 00:42:15,750 --> 00:42:18,610 And now I'm going to define this little funny function, 766 00:42:18,610 --> 00:42:22,640 which is an identity function. 767 00:42:22,640 --> 00:42:25,520 And what it does, it keeps track of the last time you 768 00:42:25,520 --> 00:42:26,770 called it using x. 769 00:42:26,770 --> 00:42:31,620 770 00:42:31,620 --> 00:42:34,390 So the identity of n just returns n, but it 771 00:42:34,390 --> 00:42:36,760 sets x to be n. 772 00:42:36,760 --> 00:42:40,050 And now I'll define a little increment function, which is a 773 00:42:40,050 --> 00:42:42,580 very little, simple scenario. 774 00:42:42,580 --> 00:42:44,780 Now, imagine I'm interacting with this in the normal-order 775 00:42:44,780 --> 00:42:47,230 language, and I type the following. 776 00:42:47,230 --> 00:42:52,940 I say define y to be increment the identity function of 3, so 777 00:42:52,940 --> 00:42:54,190 y is going to be 4. 778 00:42:54,190 --> 00:42:57,410 779 00:42:57,410 --> 00:42:59,520 Now, I say what's x? 780 00:42:59,520 --> 00:43:02,720 Well, x should have been the value that was remembered last 781 00:43:02,720 --> 00:43:04,710 when I called the identity function. 782 00:43:04,710 --> 00:43:06,500 So you'd expect to say, well, x is 3 at this 783 00:43:06,500 --> 00:43:08,530 point, but it's not. 784 00:43:08,530 --> 00:43:13,460 Because when I defined y here, what I really defined y to be 785 00:43:13,460 --> 00:43:17,000 increment of a promise to do this thing. 786 00:43:17,000 --> 00:43:19,050 So I didn't look at y, so that identity 787 00:43:19,050 --> 00:43:21,560 function didn't get run. 788 00:43:21,560 --> 00:43:24,070 So if I type in this definition and look at x, I'm 789 00:43:24,070 --> 00:43:25,320 going to get 0. 790 00:43:25,320 --> 00:43:28,360 791 00:43:28,360 --> 00:43:33,120 Now, if I go look at y and say what's y, say y is 4, looking 792 00:43:33,120 --> 00:43:36,180 at y, that very active looking at y caused the identity 793 00:43:36,180 --> 00:43:38,342 function to be run. 794 00:43:38,342 --> 00:43:40,740 And now x will get remembered as 3. 795 00:43:40,740 --> 00:43:42,020 So here x will be 0. 796 00:43:42,020 --> 00:43:43,280 Here, x will be 3. 797 00:43:43,280 --> 00:43:47,890 That's a tiny, little, simple scenario, but you can see what 798 00:43:47,890 --> 00:43:52,640 kind of a mess that's going to make for debugging interactive 799 00:43:52,640 --> 00:43:57,100 programs when you have normal-order evaluation. 800 00:43:57,100 --> 00:43:59,690 It's very confusing. 801 00:43:59,690 --> 00:44:03,200 But it's very confusing for a very deep reason, which is 802 00:44:03,200 --> 00:44:07,250 that the whole idea of putting in delays is that 803 00:44:07,250 --> 00:44:09,780 you throw away time. 804 00:44:09,780 --> 00:44:11,750 That's why we can have these infinite processes. 805 00:44:11,750 --> 00:44:13,870 Since we've thrown away time, we don't have to wait for them 806 00:44:13,870 --> 00:44:17,790 to run, right? 807 00:44:17,790 --> 00:44:21,000 We decouple the order of events in the computer from 808 00:44:21,000 --> 00:44:23,730 what we write in our programs. But when we talk about state 809 00:44:23,730 --> 00:44:26,910 and set and change, that's exactly what we do want 810 00:44:26,910 --> 00:44:28,760 control of. 811 00:44:28,760 --> 00:44:32,960 So it's almost as if there's this fundamental contradiction 812 00:44:32,960 --> 00:44:34,570 in what you want. 813 00:44:34,570 --> 00:44:38,710 And that brings us back to these sort of philosophical 814 00:44:38,710 --> 00:44:40,720 mutterings about what is it that you're trying to model 815 00:44:40,720 --> 00:44:42,410 and how do you look at the world. 816 00:44:42,410 --> 00:44:45,890 Or sometimes this is called the debate over functional 817 00:44:45,890 --> 00:44:47,140 programming. 818 00:44:47,140 --> 00:44:53,570 819 00:44:53,570 --> 00:44:57,730 A so-called purely functional language is one that just 820 00:44:57,730 --> 00:45:00,440 doesn't have any side effects. 821 00:45:00,440 --> 00:45:02,450 Since you have no side effects, there's no assignment 822 00:45:02,450 --> 00:45:06,360 operator, so there are no terrible consequences of it. 823 00:45:06,360 --> 00:45:07,930 You can use a substitution-like thing. 824 00:45:07,930 --> 00:45:11,120 Programs really are like mathematics and not like 825 00:45:11,120 --> 00:45:12,640 models in the real world, not like 826 00:45:12,640 --> 00:45:15,050 objects in the real world. 827 00:45:15,050 --> 00:45:16,100 There are a lot of wonderful things 828 00:45:16,100 --> 00:45:17,170 about functional languages. 829 00:45:17,170 --> 00:45:19,240 Since there's no time, you never have any synchronization 830 00:45:19,240 --> 00:45:23,140 problems. And if you want to put something into a parallel 831 00:45:23,140 --> 00:45:26,820 algorithm, you can run the pieces of that parallel 832 00:45:26,820 --> 00:45:29,260 processing any way you want. 833 00:45:29,260 --> 00:45:31,235 There's just never any synchronization to worry that, 834 00:45:31,235 --> 00:45:33,640 and it's a very congenial environment for doing this. 835 00:45:33,640 --> 00:45:35,450 The price is you give up assignment. 836 00:45:35,450 --> 00:45:39,060 837 00:45:39,060 --> 00:45:41,460 So an advocate of a functional language would say, gee, 838 00:45:41,460 --> 00:45:44,520 that's just a tiny price to pay. 839 00:45:44,520 --> 00:45:45,690 You probably shouldn't use assignment 840 00:45:45,690 --> 00:45:46,510 most of the time anyway. 841 00:45:46,510 --> 00:45:49,360 And if you just give up assignment, you can be in this 842 00:45:49,360 --> 00:45:54,190 much, much nicer world than this place with objects. 843 00:45:54,190 --> 00:45:56,300 Well, what's the rejoinder to that? 844 00:45:56,300 --> 00:46:00,300 Remember how we got into this mess. 845 00:46:00,300 --> 00:46:04,440 We started trying to model things that had local state. 846 00:46:04,440 --> 00:46:06,840 So remember Jerry's random number generator. 847 00:46:06,840 --> 00:46:10,000 There was this random number generator that had some little 848 00:46:10,000 --> 00:46:12,290 state in it to compute the next random number and the 849 00:46:12,290 --> 00:46:14,080 next random number and the next random number. 850 00:46:14,080 --> 00:46:17,830 And we wanted to hide that state away from the Cesaro 851 00:46:17,830 --> 00:46:21,050 compute part process, and that's why we needed set. 852 00:46:21,050 --> 00:46:24,070 We wanted to package that stated modularly. 853 00:46:24,070 --> 00:46:26,920 Well, a functional programming person would say, well, you're 854 00:46:26,920 --> 00:46:27,560 just all wet. 855 00:46:27,560 --> 00:46:28,810 I mean, you can write a perfectly 856 00:46:28,810 --> 00:46:29,840 good modular program. 857 00:46:29,840 --> 00:46:33,250 It's just you're thinking about modularity wrong. 858 00:46:33,250 --> 00:46:35,420 You're hung up in this next random number and the next 859 00:46:35,420 --> 00:46:36,880 random number and the next random number. 860 00:46:36,880 --> 00:46:39,880 Why don't you just say let's write a program. 861 00:46:39,880 --> 00:46:42,990 Let's write an enumerator which just generates an 862 00:46:42,990 --> 00:46:44,445 infinite stream of random numbers. 863 00:46:44,445 --> 00:46:49,010 864 00:46:49,010 --> 00:46:52,970 We can sort of have that stream all at once, and that's 865 00:46:52,970 --> 00:46:54,540 going to be our source of random numbers. 866 00:46:54,540 --> 00:46:56,770 And then if you like, you can put that through some sort of 867 00:46:56,770 --> 00:46:58,530 processor, which is-- 868 00:46:58,530 --> 00:46:59,530 I don't know-- 869 00:46:59,530 --> 00:47:06,880 a Cesaro test, and that can do what it wants. 870 00:47:06,880 --> 00:47:16,320 And what would come out of there would be a stream of 871 00:47:16,320 --> 00:47:28,140 successive approximations to pi. 872 00:47:28,140 --> 00:47:31,600 So as we looked further down this stream, we'd tug on this 873 00:47:31,600 --> 00:47:34,420 Cesaro thing, and it would pull out more 874 00:47:34,420 --> 00:47:35,540 and more random numbers. 875 00:47:35,540 --> 00:47:37,200 And the further and further we look down the stream, the 876 00:47:37,200 --> 00:47:39,720 better an approximation we'd get to pi. 877 00:47:39,720 --> 00:47:41,850 And it would do exactly the same as the other computation, 878 00:47:41,850 --> 00:47:43,890 except we're thinking about the modularity different. 879 00:47:43,890 --> 00:47:46,360 We're saying imagine we had all those infinite streams of 880 00:47:46,360 --> 00:47:49,400 random numbers all at once. 881 00:47:49,400 --> 00:47:53,860 You can see the details of this procedure in the book. 882 00:47:53,860 --> 00:47:56,940 Similarly, there are other things that we tend to get 883 00:47:56,940 --> 00:48:00,730 locked into on this one and that one and the next one and 884 00:48:00,730 --> 00:48:03,280 the next one, which don't have to be that way. 885 00:48:03,280 --> 00:48:07,930 Like you might think about like a banking system, which 886 00:48:07,930 --> 00:48:08,900 is a very simple idea. 887 00:48:08,900 --> 00:48:10,960 Imagine we have a program that sort of 888 00:48:10,960 --> 00:48:12,210 represents a bank account. 889 00:48:12,210 --> 00:48:18,810 890 00:48:18,810 --> 00:48:22,860 The bank account might have in it-- 891 00:48:22,860 --> 00:48:26,020 if we looked at this in a sort of message-passing view of the 892 00:48:26,020 --> 00:48:29,070 world, we'd say a bank account is an object that has some 893 00:48:29,070 --> 00:48:31,510 local state in there, which is the balance, say. 894 00:48:31,510 --> 00:48:34,110 895 00:48:34,110 --> 00:48:37,640 And a user using this system comes and sends a transaction 896 00:48:37,640 --> 00:48:41,230 request. So the user sends a transaction request, like 897 00:48:41,230 --> 00:48:43,970 deposit some money, and the bank account maybe-- 898 00:48:43,970 --> 00:48:45,850 let's say the bank account always responds with what the 899 00:48:45,850 --> 00:48:48,560 current balance is. 900 00:48:48,560 --> 00:48:50,360 The user says let's deposits some money, and the bank 901 00:48:50,360 --> 00:48:54,350 account sends back a message which is the balance. 902 00:48:54,350 --> 00:48:57,970 And the user says deposit some more, and the bank account 903 00:48:57,970 --> 00:48:59,150 sends back a message. 904 00:48:59,150 --> 00:49:00,900 And just like the random number generator, you'd say, 905 00:49:00,900 --> 00:49:03,200 gee, we would like to use set. 906 00:49:03,200 --> 00:49:06,150 We'd like to have balance be a piece of local state inside 907 00:49:06,150 --> 00:49:08,110 this bank account because we want to separate the state of 908 00:49:08,110 --> 00:49:09,570 the user from the state of the bank account. 909 00:49:09,570 --> 00:49:13,280 910 00:49:13,280 --> 00:49:16,420 Well, that's the message-processing view. 911 00:49:16,420 --> 00:49:20,030 There's a stream view with that thing, which does the 912 00:49:20,030 --> 00:49:22,740 same thing without any set or side effects. 913 00:49:22,740 --> 00:49:29,380 And the idea is again we don't think about anything having 914 00:49:29,380 --> 00:49:31,180 local state. 915 00:49:31,180 --> 00:49:33,640 We think about the bank account as something that's 916 00:49:33,640 --> 00:49:38,640 going to process a stream of transaction requests. 917 00:49:38,640 --> 00:49:40,670 So think about this bank account not as something that 918 00:49:40,670 --> 00:49:44,510 goes message by message, but something that takes in a 919 00:49:44,510 --> 00:49:46,610 stream of transaction requests like maybe 920 00:49:46,610 --> 00:49:49,490 successive deposit announced. 921 00:49:49,490 --> 00:49:55,940 1, 2, 2, 4, those might be successive amounts to deposit. 922 00:49:55,940 --> 00:49:58,570 And then coming out of it is the successive 923 00:49:58,570 --> 00:50:03,770 balances 1, 3, 5, 9. 924 00:50:03,770 --> 00:50:05,550 So we think of the bank account not as something that 925 00:50:05,550 --> 00:50:09,970 has state, but something that acts sort of on the infinite 926 00:50:09,970 --> 00:50:10,820 stream of requests. 927 00:50:10,820 --> 00:50:12,370 But remember, we've thrown away time. 928 00:50:12,370 --> 00:50:17,950 So what we can do is if the user's here, we can have this 929 00:50:17,950 --> 00:50:21,530 infinite stream of requests being generated one at a time 930 00:50:21,530 --> 00:50:27,000 coming from the user and this transaction stream coming back 931 00:50:27,000 --> 00:50:30,010 on a printer being printed one at a time. 932 00:50:30,010 --> 00:50:33,850 And if we drew a little line here, right there to the user, 933 00:50:33,850 --> 00:50:36,910 the user couldn't tell that this system 934 00:50:36,910 --> 00:50:39,560 doesn't have state. 935 00:50:39,560 --> 00:50:41,410 It looks just like the other one, but 936 00:50:41,410 --> 00:50:42,660 there's no state in there. 937 00:50:42,660 --> 00:50:45,120 938 00:50:45,120 --> 00:50:48,510 And by the way, just to show you, here's an actual 939 00:50:48,510 --> 00:50:52,240 implementation of this-- we'll call it make deposit account 940 00:50:52,240 --> 00:50:53,835 because you can only deposit. 941 00:50:53,835 --> 00:50:57,430 It takes an initial balance and then a stream of deposits 942 00:50:57,430 --> 00:51:00,020 you might make. 943 00:51:00,020 --> 00:51:00,820 And what is it? 944 00:51:00,820 --> 00:51:04,580 Well, it's just cons-stream of the balance onto make a new 945 00:51:04,580 --> 00:51:08,490 account stream whose initial balance is the old balance 946 00:51:08,490 --> 00:51:14,020 plus the first thing in the deposit stream and make 947 00:51:14,020 --> 00:51:16,470 deposit account works on the rest of which is the tail of 948 00:51:16,470 --> 00:51:18,300 the deposit stream. 949 00:51:18,300 --> 00:51:24,650 So there's sort of a very typical message-passing, 950 00:51:24,650 --> 00:51:26,700 object-oriented thing that's done without 951 00:51:26,700 --> 00:51:28,790 side effects at all. 952 00:51:28,790 --> 00:51:32,250 There are very many things you can do this way. 953 00:51:32,250 --> 00:51:36,400 Well, can you do everything without assignment? 954 00:51:36,400 --> 00:51:40,050 Can everybody go over to purely functional languages? 955 00:51:40,050 --> 00:51:44,450 Well, we don't know, but there seem to be places where purely 956 00:51:44,450 --> 00:51:48,100 functional programming breaks down. 957 00:51:48,100 --> 00:51:50,030 Where it starts hurting is when you have things like 958 00:51:50,030 --> 00:51:53,520 this, but you also mix it up with the other things that we 959 00:51:53,520 --> 00:51:56,300 had to worry that, which are objects and sharing and two 960 00:51:56,300 --> 00:51:58,850 independent agents being the same. 961 00:51:58,850 --> 00:52:00,850 So under a typical one, suppose you want to extend 962 00:52:00,850 --> 00:52:02,960 this bank account. 963 00:52:02,960 --> 00:52:04,210 So here's a bank account. 964 00:52:04,210 --> 00:52:12,220 965 00:52:12,220 --> 00:52:15,410 Bank accounts take in a stream of transaction requests and 966 00:52:15,410 --> 00:52:18,780 put out streams of, say, balances or responses to that. 967 00:52:18,780 --> 00:52:21,020 But suppose you want to model the fact that this is a joint 968 00:52:21,020 --> 00:52:26,090 bank account between two independent people. 969 00:52:26,090 --> 00:52:31,890 So suppose there are two people, say, Bill and Dave, 970 00:52:31,890 --> 00:52:33,140 who have a joint bank account. 971 00:52:33,140 --> 00:52:35,960 972 00:52:35,960 --> 00:52:36,850 How would you model this? 973 00:52:36,850 --> 00:52:40,460 Well, Bill puts out a stream of transaction requests, and 974 00:52:40,460 --> 00:52:42,390 Dave puts out a stream of transaction requests, and 975 00:52:42,390 --> 00:52:45,880 somehow, they have to merge into this bank account. 976 00:52:45,880 --> 00:52:48,370 So what you might do is write a little stream processing 977 00:52:48,370 --> 00:52:58,660 thing called merge, which sort of takes these, merges them 978 00:52:58,660 --> 00:53:01,190 together, produces a single stream for the bank account. 979 00:53:01,190 --> 00:53:03,610 Now they're both talking to the same bank account. 980 00:53:03,610 --> 00:53:06,600 That's all great, but how do you write merge? 981 00:53:06,600 --> 00:53:09,730 What's this procedure merge? 982 00:53:09,730 --> 00:53:12,760 You want to do something that's reasonable. 983 00:53:12,760 --> 00:53:14,380 Your first guess might be to say, well, we'll take 984 00:53:14,380 --> 00:53:20,050 alternate requests from Bill and Dave. But what happens if 985 00:53:20,050 --> 00:53:21,950 suddenly in the middle of this thing, Dave goes away on 986 00:53:21,950 --> 00:53:24,150 vacation for two years? 987 00:53:24,150 --> 00:53:27,690 Then Bill's sort of stuck. 988 00:53:27,690 --> 00:53:29,750 So what you want to do is-- well, it's hard to describe. 989 00:53:29,750 --> 00:53:33,380 What you want to do is what people call fair merge. 990 00:53:33,380 --> 00:53:38,410 991 00:53:38,410 --> 00:53:41,850 The idea of fair merge is it sort of should do them 992 00:53:41,850 --> 00:53:43,930 alternately, but if there's nothing waiting here, it 993 00:53:43,930 --> 00:53:46,010 should take one twice. 994 00:53:46,010 --> 00:53:48,450 Notice I can't even say that without talking about time. 995 00:53:48,450 --> 00:53:51,300 996 00:53:51,300 --> 00:53:55,970 So one of the other active researcher areas in functional 997 00:53:55,970 --> 00:54:00,480 languages is inventing little things like fair merge and 998 00:54:00,480 --> 00:54:04,650 maybe some others, which will take the places where I used 999 00:54:04,650 --> 00:54:08,050 to need side effects and objects and sort of hide them 1000 00:54:08,050 --> 00:54:11,160 away in some very well-defined modules of the system so that 1001 00:54:11,160 --> 00:54:14,430 all the problems of assignment don't sort of leak out all 1002 00:54:14,430 --> 00:54:16,760 over the system but are captured in some fairly 1003 00:54:16,760 --> 00:54:18,010 well-understood things. 1004 00:54:18,010 --> 00:54:20,780 1005 00:54:20,780 --> 00:54:23,410 More generally, I think what you're seeing is that we're 1006 00:54:23,410 --> 00:54:25,960 running across what I think is a very basic problem in 1007 00:54:25,960 --> 00:54:29,450 computer science, which is how to define languages that 1008 00:54:29,450 --> 00:54:36,240 somehow can talk about delayed evaluation, but also be able 1009 00:54:36,240 --> 00:54:37,280 to reflect this view that there are 1010 00:54:37,280 --> 00:54:38,360 objects in the world. 1011 00:54:38,360 --> 00:54:41,230 How do we somehow get both? 1012 00:54:41,230 --> 00:54:43,040 And I think that's a very hard problem. 1013 00:54:43,040 --> 00:54:46,750 And it may be that it's a very hard problem that has almost 1014 00:54:46,750 --> 00:54:49,260 nothing to do with computer science, that it really is a 1015 00:54:49,260 --> 00:54:51,950 problem having to do with two very incompatible ways of 1016 00:54:51,950 --> 00:54:53,840 looking at the world. 1017 00:54:53,840 --> 00:54:55,090 OK, questions? 1018 00:54:55,090 --> 00:55:17,556 1019 00:55:17,556 --> 00:55:20,610 AUDIENCE: You mentioned earlier that once you 1020 00:55:20,610 --> 00:55:23,930 introduce assignment, the general rule for using the 1021 00:55:23,930 --> 00:55:25,890 substitution model is you can't. 1022 00:55:25,890 --> 00:55:27,570 Unless you're very careful, you can't. 1023 00:55:27,570 --> 00:55:28,260 PROFESSOR: Right. 1024 00:55:28,260 --> 00:55:32,550 AUDIENCE: Is there a set of techniques or a set of 1025 00:55:32,550 --> 00:55:37,030 guidelines for localizing the effects of assignment so that 1026 00:55:37,030 --> 00:55:40,300 the very careful becomes defined? 1027 00:55:40,300 --> 00:55:42,890 PROFESSOR: I don't know. 1028 00:55:42,890 --> 00:55:45,430 Let me think. 1029 00:55:45,430 --> 00:55:50,150 Well, certainly, there was an assignment inside memo proc, 1030 00:55:50,150 --> 00:55:51,480 but that was sort of hidden away. 1031 00:55:51,480 --> 00:55:53,480 It ended up not making any difference. 1032 00:55:53,480 --> 00:55:57,385 Part of the reason for that is once this thing triggered that 1033 00:55:57,385 --> 00:55:58,990 it had run and gotten an answer, that 1034 00:55:58,990 --> 00:56:00,390 answer will never change. 1035 00:56:00,390 --> 00:56:02,080 So that was sort of a one-time assignment. 1036 00:56:02,080 --> 00:56:05,020 So one very general thing you can do is if you only do 1037 00:56:05,020 --> 00:56:08,750 what's called a one-time assignment and never change 1038 00:56:08,750 --> 00:56:11,250 anything, then you can do better. 1039 00:56:11,250 --> 00:56:17,156 One of the problems in this merge thing, people have-- 1040 00:56:17,156 --> 00:56:18,490 let me see if this is right. 1041 00:56:18,490 --> 00:56:22,910 I think it's true that with fair merge, with just fair 1042 00:56:22,910 --> 00:56:27,060 merge, you can begin effectively simulating 1043 00:56:27,060 --> 00:56:30,820 assignment in the rest of the language. 1044 00:56:30,820 --> 00:56:33,630 It seems like anything you do to go outside-- 1045 00:56:33,630 --> 00:56:36,440 I'm not quite sure that's true for fair merge, but it's true 1046 00:56:36,440 --> 00:56:38,500 of a little bit more general things that 1047 00:56:38,500 --> 00:56:39,520 people have been doing. 1048 00:56:39,520 --> 00:56:42,630 So it might be that any little bit you put in, suddenly if 1049 00:56:42,630 --> 00:56:44,610 they allow you to build arbitrary stuff, it's almost 1050 00:56:44,610 --> 00:56:47,970 as bad as having assignment altogether. 1051 00:56:47,970 --> 00:56:51,590 But that's an area that people are thinking about now. 1052 00:56:51,590 --> 00:56:57,010 AUDIENCE: I guess I don't see the problem here with merge if 1053 00:56:57,010 --> 00:57:00,930 I call Bill, if Bill is a procedure, then Bill is going 1054 00:57:00,930 --> 00:57:03,690 to increment the bank account or build the list that 's 1055 00:57:03,690 --> 00:57:04,730 going to put in the next element. 1056 00:57:04,730 --> 00:57:07,170 If I call Dave twice in a row, that will do that. 1057 00:57:07,170 --> 00:57:09,350 I'm not sure where fair merge has to be involved. 1058 00:57:09,350 --> 00:57:10,150 PROFESSOR: The problem is imagine 1059 00:57:10,150 --> 00:57:11,200 these really as people. 1060 00:57:11,200 --> 00:57:13,490 See, here I have the user who's interacting with this 1061 00:57:13,490 --> 00:57:14,850 bank account. 1062 00:57:14,850 --> 00:57:15,960 Put in a request, get an answer. 1063 00:57:15,960 --> 00:57:17,070 Put in a request, get an answer. 1064 00:57:17,070 --> 00:57:18,200 AUDIENCE: Right. 1065 00:57:18,200 --> 00:57:20,860 PROFESSOR: But if the only way I can process request is to 1066 00:57:20,860 --> 00:57:22,290 alternate them from two people-- 1067 00:57:22,290 --> 00:57:24,220 AUDIENCE: Well, why would you alternate them? 1068 00:57:24,220 --> 00:57:25,070 PROFESSOR: Why don't I? 1069 00:57:25,070 --> 00:57:26,140 AUDIENCE: Yes. 1070 00:57:26,140 --> 00:57:26,580 Why do you? 1071 00:57:26,580 --> 00:57:27,640 PROFESSOR: Think of them as real people, right? 1072 00:57:27,640 --> 00:57:29,280 This guy might go away for a year. 1073 00:57:29,280 --> 00:57:32,700 And you're sitting here at the bank account window, and you 1074 00:57:32,700 --> 00:57:34,040 can't put in two requests because it's 1075 00:57:34,040 --> 00:57:35,480 waiting for this guy. 1076 00:57:35,480 --> 00:57:37,380 AUDIENCE: Why does it have to be waiting for one? 1077 00:57:37,380 --> 00:57:39,110 PROFESSOR: Because it's trying to compute a function. 1078 00:57:39,110 --> 00:57:41,720 I have to define a function. 1079 00:57:41,720 --> 00:57:44,210 Another way to say that is the answer to what comes out of 1080 00:57:44,210 --> 00:57:51,690 this merge box is not a function of what goes in. 1081 00:57:51,690 --> 00:57:53,490 Because, see, what would the function be? 1082 00:57:53,490 --> 00:58:03,470 Suppose he puts in 1, 1, 1, 1, and he puts in 2, 2, 2, 2. 1083 00:58:03,470 --> 00:58:05,910 What's the answer supposed to be? 1084 00:58:05,910 --> 00:58:08,740 It's not good enough to say it's 1, 2, 1, 2, 1, 2. 1085 00:58:08,740 --> 00:58:09,390 AUDIENCE: I understand. 1086 00:58:09,390 --> 00:58:11,560 But when Bill puts in 1, 1 goes in. 1087 00:58:11,560 --> 00:58:13,950 When Dave puts in 2 twice, 2 goes in twice. 1088 00:58:13,950 --> 00:58:15,090 When Bill puts in-- 1089 00:58:15,090 --> 00:58:15,450 PROFESSOR: Right. 1090 00:58:15,450 --> 00:58:17,140 AUDIENCE: Why can't it be hooked to 1091 00:58:17,140 --> 00:58:18,680 the time of the input-- 1092 00:58:18,680 --> 00:58:20,100 the actual procedural-- 1093 00:58:20,100 --> 00:58:23,980 PROFESSOR: Because I don't have time. 1094 00:58:23,980 --> 00:58:26,900 See, all I can say is I'm going to define a function. 1095 00:58:26,900 --> 00:58:28,150 I don't have time. 1096 00:58:28,150 --> 00:58:32,070 1097 00:58:32,070 --> 00:58:34,690 There's no concept if it's going to alternate, except if 1098 00:58:34,690 --> 00:58:38,420 nobody's there, it's going to wait a while for him. 1099 00:58:38,420 --> 00:58:41,910 It's just going to say I have the stream of requests, the 1100 00:58:41,910 --> 00:58:44,580 timeless infinite streams of all the requests that Dave 1101 00:58:44,580 --> 00:58:47,810 would have made, right? 1102 00:58:47,810 --> 00:58:49,710 And the timeless infinite stream of all the requests 1103 00:58:49,710 --> 00:58:51,690 Bill would have made, and I want to operate on them. 1104 00:58:51,690 --> 00:58:53,510 See, that's how this bank account is working. 1105 00:58:53,510 --> 00:58:56,710 1106 00:58:56,710 --> 00:58:59,120 And the problem is that these poor people who are sitting at 1107 00:58:59,120 --> 00:59:02,180 the bank account windows have the 1108 00:59:02,180 --> 00:59:05,340 misfortune to exist in time. 1109 00:59:05,340 --> 00:59:08,490 They don't see their infinite stream of all the requests 1110 00:59:08,490 --> 00:59:10,070 they would have ever made. 1111 00:59:10,070 --> 00:59:11,550 They're waiting now, and they want an answer. 1112 00:59:11,550 --> 00:59:14,290 1113 00:59:14,290 --> 00:59:16,340 So if you're sitting there-- 1114 00:59:16,340 --> 00:59:20,360 if this is the screen operation on some time-sharing 1115 00:59:20,360 --> 00:59:22,940 system and it's working functionally, you want an 1116 00:59:22,940 --> 00:59:25,290 answer then when you talk the character. 1117 00:59:25,290 --> 00:59:26,940 You don't want it to have to wait for everybody in the 1118 00:59:26,940 --> 00:59:28,990 whole system to have typed one character before it can get 1119 00:59:28,990 --> 00:59:30,910 around to service you. 1120 00:59:30,910 --> 00:59:33,890 So that's the problem. 1121 00:59:33,890 --> 00:59:36,850 I mean, the fact that people live in time, apparently. 1122 00:59:36,850 --> 00:59:38,620 If they didn't, it wouldn't be a problem. 1123 00:59:38,620 --> 00:59:49,100 1124 00:59:49,100 --> 00:59:52,240 AUDIENCE: I'm afraid I miss the point of having no time in 1125 00:59:52,240 --> 00:59:54,740 this banking transaction. 1126 00:59:54,740 --> 00:59:56,880 Isn't time very important? 1127 00:59:56,880 --> 01:00:00,790 For instance, the sequence of events. 1128 01:00:00,790 --> 01:00:07,150 If Dave take out $100, then the timing 1129 01:00:07,150 --> 01:00:08,400 sequence should be important. 1130 01:00:08,400 --> 01:00:11,260 How do you treat transactions as streams? 1131 01:00:11,260 --> 01:00:14,260 PROFESSOR: Well, that's the thing I'm saying. 1132 01:00:14,260 --> 01:00:17,510 This is an example where you can't. 1133 01:00:17,510 --> 01:00:18,610 You can't. 1134 01:00:18,610 --> 01:00:21,410 The point is what comes out of here is simply not a function 1135 01:00:21,410 --> 01:00:24,170 of the stream going in here and the stream going in here. 1136 01:00:24,170 --> 01:00:26,660 It's a function of the stream going in here and the stream 1137 01:00:26,660 --> 01:00:29,670 going in here and some kind of information about time, which 1138 01:00:29,670 --> 01:00:31,610 is precisely what a normal-order language won't 1139 01:00:31,610 --> 01:00:32,860 let you say. 1140 01:00:32,860 --> 01:00:34,810 1141 01:00:34,810 --> 01:00:36,950 AUDIENCE: In order to brings this back into a more 1142 01:00:36,950 --> 01:00:40,476 functional perspective, could we just explicitly time stamp 1143 01:00:40,476 --> 01:00:44,390 all the inputs from Bill and Dave and define fair merge to 1144 01:00:44,390 --> 01:00:46,400 just be the sort on those time stamps? 1145 01:00:46,400 --> 01:00:49,150 1146 01:00:49,150 --> 01:00:49,550 PROFESSOR: Yeah, you can do that. 1147 01:00:49,550 --> 01:00:50,600 You can do that sort of thing. 1148 01:00:50,600 --> 01:00:53,830 Another thing you could say is imagine that really what this 1149 01:00:53,830 --> 01:00:59,070 function is, is that it does a read every microsecond, and 1150 01:00:59,070 --> 01:01:00,110 then if there's none there, that's 1151 01:01:00,110 --> 01:01:00,970 considered an empty one. 1152 01:01:00,970 --> 01:01:03,610 That's about equivalent to what you said. 1153 01:01:03,610 --> 01:01:07,110 And yes, you can do that, but that's a clg. 1154 01:01:07,110 --> 01:01:09,480 So it's not quite only implementation 1155 01:01:09,480 --> 01:01:10,170 we're worried about. 1156 01:01:10,170 --> 01:01:12,830 We're worried about expressive power in the language, and 1157 01:01:12,830 --> 01:01:15,630 what we're running across is a real mismatch between what we 1158 01:01:15,630 --> 01:01:18,824 can say easily and what we'd like to say. 1159 01:01:18,824 --> 01:01:20,790 AUDIENCE: It sounds like where we're getting hung up with 1160 01:01:20,790 --> 01:01:23,480 that is the fact it expects one input from both Bill and 1161 01:01:23,480 --> 01:01:26,080 Dave at the same time. 1162 01:01:26,080 --> 01:01:28,530 PROFESSOR: It's not quite one, but it's anything you define. 1163 01:01:28,530 --> 01:01:31,000 So you can say Dave can go twice as often, but if 1164 01:01:31,000 --> 01:01:36,110 anything you predefine, it's not the right thing. 1165 01:01:36,110 --> 01:01:39,880 You can't decide at some particular function of their 1166 01:01:39,880 --> 01:01:41,930 input requests. 1167 01:01:41,930 --> 01:01:44,870 Worse yet, I mean, worse yet, there are things that even 1168 01:01:44,870 --> 01:01:47,290 merge can't do. 1169 01:01:47,290 --> 01:01:49,170 One thing you might want to do that's even more general is 1170 01:01:49,170 --> 01:01:52,470 suddenly you add somebody else to this bank account system. 1171 01:01:52,470 --> 01:01:56,030 You go and you add John to this bank account system. 1172 01:01:56,030 --> 01:01:58,250 And now there's yet another stream that's going to come 1173 01:01:58,250 --> 01:02:02,040 into the picture at some time which we haven't prespecified. 1174 01:02:02,040 --> 01:02:04,050 So that's something even fair merge can't do, and they're 1175 01:02:04,050 --> 01:02:05,662 things called-- 1176 01:02:05,662 --> 01:02:07,220 I forget-- 1177 01:02:07,220 --> 01:02:08,860 natagers or something. 1178 01:02:08,860 --> 01:02:11,790 That's a generalization of fair merge to allow that. 1179 01:02:11,790 --> 01:02:14,140 There's a whole sort of research discipline saying how 1180 01:02:14,140 --> 01:02:16,790 far can you push this functional perspective by 1181 01:02:16,790 --> 01:02:19,580 adding more and more mechanism? 1182 01:02:19,580 --> 01:02:21,470 And how far does that go before the whole thing breaks 1183 01:02:21,470 --> 01:02:25,610 down and you might as well been using set anyway. 1184 01:02:25,610 --> 01:02:28,960 AUDIENCE: You need to set him up on automatic deposit. 1185 01:02:28,960 --> 01:02:39,630 [LAUGHTER] 1186 01:02:39,630 --> 01:02:40,880 PROFESSOR: OK, thank you. 1187 01:02:40,880 --> 01:03:00,115 ================================================ FILE: SrtEN/lec7a_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:15,314 1 00:00:15,314 --> 00:00:17,580 PROFESSOR: Well today we're going to learn about something 2 00:00:17,580 --> 00:00:18,410 quite amazing. 3 00:00:18,410 --> 00:00:22,950 We're going to understand what we mean by a program a little 4 00:00:22,950 --> 00:00:26,800 bit more profoundly than we have up till now. 5 00:00:26,800 --> 00:00:30,650 Up till now, we've been thinking of programs as 6 00:00:30,650 --> 00:00:32,729 describing machines. 7 00:00:32,729 --> 00:00:38,800 So for example, looking at this still store, we see here 8 00:00:38,800 --> 00:00:42,800 is a program for factorial. 9 00:00:42,800 --> 00:00:46,970 And what it is, is a character string description, if you 10 00:00:46,970 --> 00:00:49,520 will, of the wiring diagram of a 11 00:00:49,520 --> 00:00:52,230 potentially infinite machine. 12 00:00:52,230 --> 00:00:53,870 And we can look at that a little bit and 13 00:00:53,870 --> 00:00:55,130 just see the idea. 14 00:00:55,130 --> 00:00:58,950 That this is a sort of compact notation which says, if n is 15 00:00:58,950 --> 00:01:00,170 0, the result is one. 16 00:01:00,170 --> 00:01:03,800 Well here comes n coming into this machine, and if it's 0, 17 00:01:03,800 --> 00:01:06,720 then I control this switch in such a way that the switch 18 00:01:06,720 --> 00:01:09,340 allows the output to be one. 19 00:01:09,340 --> 00:01:12,970 Otherwise, it's n times factorial of n minus one. 20 00:01:12,970 --> 00:01:15,920 Well, I'm computing factorial of n minus one and multiplying 21 00:01:15,920 --> 00:01:19,350 that by n, and, in the case that it's not 0, this switch 22 00:01:19,350 --> 00:01:21,900 makes the output come from there. 23 00:01:21,900 --> 00:01:24,460 Of course, this is a machine with a potentially infinite 24 00:01:24,460 --> 00:01:27,300 number of parts, because factorial occurs within 25 00:01:27,300 --> 00:01:31,070 factorial, so we don't know how deep it has to be. 26 00:01:31,070 --> 00:01:36,480 But that's basically what our notation for programs really 27 00:01:36,480 --> 00:01:38,310 means to us at this point. 28 00:01:38,310 --> 00:01:41,810 It's a character string description, if you will, of a 29 00:01:41,810 --> 00:01:44,900 wiring diagram that could also be drawn some other way. 30 00:01:44,900 --> 00:01:47,520 And, in fact, many people have proposed to me, programming 31 00:01:47,520 --> 00:01:49,490 languages look graphical like this. 32 00:01:49,490 --> 00:01:51,500 I'm not sure I believe there are many advantages. 33 00:01:51,500 --> 00:01:54,470 The major disadvantage, of course, is that it takes up 34 00:01:54,470 --> 00:01:57,360 more space on a page, and, therefore, it's harder to pack 35 00:01:57,360 --> 00:02:01,090 into a listing or to edit very well. 36 00:02:01,090 --> 00:02:05,300 But in any case, there's something very remarkable that 37 00:02:05,300 --> 00:02:08,810 can happen in the competition world which is that you can 38 00:02:08,810 --> 00:02:10,450 have something called a universal machine. 39 00:02:10,450 --> 00:02:18,340 If we look at the second slide, what we see is a 40 00:02:18,340 --> 00:02:21,260 special machine called eval. 41 00:02:21,260 --> 00:02:23,670 There is a machine called eval, and I'm going to show it 42 00:02:23,670 --> 00:02:25,720 to you today. 43 00:02:25,720 --> 00:02:27,780 It's very simple. 44 00:02:27,780 --> 00:02:30,490 What is remarkable is that it will fit on the blackboard. 45 00:02:30,490 --> 00:02:33,350 46 00:02:33,350 --> 00:02:38,310 However, eval is a machine which takes as input a 47 00:02:38,310 --> 00:02:40,450 description of another machine. 48 00:02:40,450 --> 00:02:42,620 It could take the wiring diagram of a 49 00:02:42,620 --> 00:02:46,490 factorial machine as input. 50 00:02:46,490 --> 00:02:52,020 Having done so, it becomes a simulator for the factorial 51 00:02:52,020 --> 00:02:58,910 machine such that, if you put a six in, out comes a 720. 52 00:02:58,910 --> 00:03:02,130 That's a very remarkable sort of machine. 53 00:03:02,130 --> 00:03:04,560 And the most amazing part of it is that it fits on a 54 00:03:04,560 --> 00:03:05,590 blackboard. 55 00:03:05,590 --> 00:03:10,070 By contrast, one could imagine in the analog electronics 56 00:03:10,070 --> 00:03:17,180 world a very different machine, a machine which also 57 00:03:17,180 --> 00:03:20,440 was, in some sense, universal, where you gave a circuit 58 00:03:20,440 --> 00:03:24,830 diagram as one of the inputs, for example, of this little 59 00:03:24,830 --> 00:03:28,050 low-pass filter, one-pole low-pass filter. 60 00:03:28,050 --> 00:03:30,230 And you can imagine that you could, for 61 00:03:30,230 --> 00:03:32,030 example, scan this out-- 62 00:03:32,030 --> 00:03:37,950 the scan lines are the signal that's describing what this 63 00:03:37,950 --> 00:03:40,770 machine is to simulate-- 64 00:03:40,770 --> 00:03:43,040 then the analog of that which is made out of electrical 65 00:03:43,040 --> 00:03:45,540 circuits, should configure itself into a filter that has 66 00:03:45,540 --> 00:03:47,010 the frequency response specified 67 00:03:47,010 --> 00:03:49,890 by the circuit diagram. 68 00:03:49,890 --> 00:03:52,520 That's a very hard machine to make, and, surely, there's no 69 00:03:52,520 --> 00:03:55,670 chance that I could put it on a blackboard. 70 00:03:55,670 --> 00:03:58,430 So we're going to see an amazing thing today. 71 00:03:58,430 --> 00:04:01,240 We're going to see, on the blackboard, 72 00:04:01,240 --> 00:04:02,790 the universal machine. 73 00:04:02,790 --> 00:04:06,780 And we'll see that among other things, it's extremely simple. 74 00:04:06,780 --> 00:04:10,070 Now, we're getting very close to the real spirit in the 75 00:04:10,070 --> 00:04:11,280 computer at this point. 76 00:04:11,280 --> 00:04:14,110 So I have to show a certain amount of reverence and 77 00:04:14,110 --> 00:04:16,970 respect, so I'm going to wear a suit jacket for the only 78 00:04:16,970 --> 00:04:20,470 time that you'll ever see me wear a suit jacket here. 79 00:04:20,470 --> 00:04:25,730 And I think I'm also going to put on an appropriate hat for 80 00:04:25,730 --> 00:04:26,980 the occasion. 81 00:04:26,980 --> 00:04:28,780 82 00:04:28,780 --> 00:04:31,390 Now, this is a lecturer which I have to warn you-- 83 00:04:31,390 --> 00:04:34,140 84 00:04:34,140 --> 00:04:37,690 let's see, normally, people under 40 and who don't have 85 00:04:37,690 --> 00:04:40,370 several children are advised to be careful. 86 00:04:40,370 --> 00:04:44,170 If they're really worried, they should leave. Because 87 00:04:44,170 --> 00:04:46,890 there's a certain amount of mysticism that will appear 88 00:04:46,890 --> 00:04:50,140 here which may be disturbing and cause 89 00:04:50,140 --> 00:04:51,820 trouble in your minds. 90 00:04:51,820 --> 00:04:57,300 Well in any case, let's see, I wish to write for you the 91 00:04:57,300 --> 00:05:02,510 evaluator for Lisp. 92 00:05:02,510 --> 00:05:05,020 Now the evaluator isn't very complicated. 93 00:05:05,020 --> 00:05:08,240 It's very much like all the programs we've seen already. 94 00:05:08,240 --> 00:05:10,860 That's the amazing part of it. 95 00:05:10,860 --> 00:05:15,370 It's going to be-- and I'm going to write it right here-- 96 00:05:15,370 --> 00:05:16,620 it's a program called eval. 97 00:05:16,620 --> 00:05:22,900 98 00:05:22,900 --> 00:05:28,780 And it's a procedure of two arguments in expression of an 99 00:05:28,780 --> 00:05:30,030 environment. 100 00:05:30,030 --> 00:05:31,860 101 00:05:31,860 --> 00:05:33,130 And like every interesting 102 00:05:33,130 --> 00:05:34,940 procedure, it's a case analysis. 103 00:05:34,940 --> 00:05:40,460 104 00:05:40,460 --> 00:05:44,210 But before I start on this, I want to tell you some things. 105 00:05:44,210 --> 00:05:46,880 The program we're going to write on the blackboard is 106 00:05:46,880 --> 00:05:52,450 ugly, dirty, disgusting, not the way I would write this is 107 00:05:52,450 --> 00:05:54,210 a professional. 108 00:05:54,210 --> 00:05:57,940 It is written with concrete syntax, meaning you've got 109 00:05:57,940 --> 00:05:59,630 really to use lots of CARs and CDRs which is exactly what I 110 00:05:59,630 --> 00:06:02,550 told you not to do. 111 00:06:02,550 --> 00:06:07,180 That's on purpose in this case, because I want it to be 112 00:06:07,180 --> 00:06:11,010 small, compact, fit on the blackboard so you can get the 113 00:06:11,010 --> 00:06:12,420 whole thing. 114 00:06:12,420 --> 00:06:15,800 So I don't want to use long names like I normally use. 115 00:06:15,800 --> 00:06:19,580 I want to use CAR-CDR because it's short. 116 00:06:19,580 --> 00:06:20,950 Now, that's a trade-off. 117 00:06:20,950 --> 00:06:23,570 I don't want you writing programs like this. 118 00:06:23,570 --> 00:06:26,090 This is purely for an effect. 119 00:06:26,090 --> 00:06:27,530 Now, you're going to have to work a little harder to read 120 00:06:27,530 --> 00:06:29,270 it, but I'm going to try to make it clear 121 00:06:29,270 --> 00:06:31,270 as I'm writing it. 122 00:06:31,270 --> 00:06:32,395 I'm also-- 123 00:06:32,395 --> 00:06:34,960 this is a pretty much complete interpreter, but there's going 124 00:06:34,960 --> 00:06:36,290 to be room for putting in more things-- 125 00:06:36,290 --> 00:06:39,160 I'm going to leave out definition and assignment, 126 00:06:39,160 --> 00:06:45,310 just because they are not essential, for a mathematical 127 00:06:45,310 --> 00:06:51,670 reason I'll show you later and also they take up more space. 128 00:06:51,670 --> 00:06:54,170 But, in any case, what do we have to do? 129 00:06:54,170 --> 00:06:57,160 We have to do a dispatch which breaks the types of 130 00:06:57,160 --> 00:07:02,030 expressions up into particular classes. 131 00:07:02,030 --> 00:07:03,525 So that's what we're going to have here. 132 00:07:03,525 --> 00:07:05,150 Well, what expressions are there? 133 00:07:05,150 --> 00:07:06,810 Let's look at the kinds of expressions. 134 00:07:06,810 --> 00:07:10,420 We can have things like the numeral three. 135 00:07:10,420 --> 00:07:12,720 What do I want that to do? 136 00:07:12,720 --> 00:07:15,640 I can make choices, but I think right now, I want it to 137 00:07:15,640 --> 00:07:17,050 be a three. 138 00:07:17,050 --> 00:07:18,860 That's what I want. 139 00:07:18,860 --> 00:07:19,800 So that's easy enough. 140 00:07:19,800 --> 00:07:27,520 That means I want, if the thing is a number, the 141 00:07:27,520 --> 00:07:30,720 expression, that I want the expression 142 00:07:30,720 --> 00:07:31,970 itself as the answer. 143 00:07:31,970 --> 00:07:35,420 144 00:07:35,420 --> 00:07:37,700 Now the next possibility is things that we 145 00:07:37,700 --> 00:07:39,390 represent as symbols. 146 00:07:39,390 --> 00:07:47,614 Examples of symbols are things like x, n, eval, number, x. 147 00:07:47,614 --> 00:07:49,630 What do I mean them to be? 148 00:07:49,630 --> 00:07:51,690 Those are things that stand for other things. 149 00:07:51,690 --> 00:07:54,770 Those are the variables of our language. 150 00:07:54,770 --> 00:07:58,540 And so I want to be able to say, for example, that x, for 151 00:07:58,540 --> 00:08:02,930 example, transforms to it's value which might be three. 152 00:08:02,930 --> 00:08:07,920 Or I might ask something like car. 153 00:08:07,920 --> 00:08:09,710 I want to have as its value-- 154 00:08:09,710 --> 00:08:17,380 be something like some procedure, which I don't know 155 00:08:17,380 --> 00:08:20,440 what is inside there, perhaps a machine language code or 156 00:08:20,440 --> 00:08:23,100 something like that. 157 00:08:23,100 --> 00:08:24,430 So, well, that's easy enough. 158 00:08:24,430 --> 00:08:27,890 I'm going to push that off on someone else. 159 00:08:27,890 --> 00:08:33,370 If something is a symbol, if the expression is a symbol, 160 00:08:33,370 --> 00:08:38,140 then I want the answer to be the result, looking up the 161 00:08:38,140 --> 00:08:40,159 expression in the environment. 162 00:08:40,159 --> 00:08:46,480 163 00:08:46,480 --> 00:08:52,410 Now the environment is a dictionary which maps the 164 00:08:52,410 --> 00:08:54,060 symbol names to their values. 165 00:08:54,060 --> 00:08:56,280 And that's all it is. 166 00:08:56,280 --> 00:08:57,530 How it's done? 167 00:08:57,530 --> 00:08:59,760 Well, we'll see that later. 168 00:08:59,760 --> 00:09:01,670 It's very easy. 169 00:09:01,670 --> 00:09:03,630 It's easy to make data structures that are tables of 170 00:09:03,630 --> 00:09:04,670 various sorts. 171 00:09:04,670 --> 00:09:07,080 But it's only a table, and this is the access routine for 172 00:09:07,080 --> 00:09:10,040 some table. 173 00:09:10,040 --> 00:09:12,720 Well, the next thing, another kind of expression-- 174 00:09:12,720 --> 00:09:14,870 you have things that are described constants that are 175 00:09:14,870 --> 00:09:17,430 not numbers, like 'foo. 176 00:09:17,430 --> 00:09:20,170 177 00:09:20,170 --> 00:09:22,450 Well, for my convenience, I want to syntactically 178 00:09:22,450 --> 00:09:31,520 transform that into a list structure which is, quote foo. 179 00:09:31,520 --> 00:09:35,140 180 00:09:35,140 --> 00:09:39,950 A quoted object, whatever it is, is going to be actually an 181 00:09:39,950 --> 00:09:43,550 abbreviation, which is not part of the evaluator but 182 00:09:43,550 --> 00:09:46,960 happens somewhere else, an abbreviation for an expression 183 00:09:46,960 --> 00:09:48,780 that looks like this. 184 00:09:48,780 --> 00:09:52,120 This way, I can test for the type of the expression as 185 00:09:52,120 --> 00:09:55,615 being a quotation by examining the car of the expression. 186 00:09:55,615 --> 00:09:58,460 187 00:09:58,460 --> 00:10:01,650 So I'm not going to worry about that in the evaluator. 188 00:10:01,650 --> 00:10:02,780 It's happening somewhere earlier in 189 00:10:02,780 --> 00:10:05,540 the reader or something. 190 00:10:05,540 --> 00:10:18,620 If the expression of the expression is quote, then what 191 00:10:18,620 --> 00:10:25,140 I want, I want quote foo to itself evaluate to foo. 192 00:10:25,140 --> 00:10:27,530 It's a constant. 193 00:10:27,530 --> 00:10:30,645 This is just a way of saying that this evaluates to itself. 194 00:10:30,645 --> 00:10:33,150 195 00:10:33,150 --> 00:10:33,660 What is that? 196 00:10:33,660 --> 00:10:37,330 That's the second of the list. It's the second element of the 197 00:10:37,330 --> 00:10:41,604 list. The second element of the list is it's CADR. So I'm 198 00:10:41,604 --> 00:10:51,290 just going to write here, CADR. 199 00:10:51,290 --> 00:10:52,510 What else do we have here? 200 00:10:52,510 --> 00:10:56,040 We have lambda expressions, for example, 201 00:10:56,040 --> 00:11:04,160 lambda of x plus x y. 202 00:11:04,160 --> 00:11:05,910 Well, I going have to have some representation for the 203 00:11:05,910 --> 00:11:08,610 procedure which is the value of an expression, of a lambda 204 00:11:08,610 --> 00:11:09,600 expression. 205 00:11:09,600 --> 00:11:13,030 The procedure here is not the expression lambda x. 206 00:11:13,030 --> 00:11:16,170 That's the description of it, the textual description. 207 00:11:16,170 --> 00:11:18,800 However, what what I going to expect to see here is 208 00:11:18,800 --> 00:11:20,930 something which contains an environment as one of its 209 00:11:20,930 --> 00:11:27,360 parts if I'm implementing a lexical language. 210 00:11:27,360 --> 00:11:30,790 And so what I'd like to see is some type flags. 211 00:11:30,790 --> 00:11:33,440 I'm going to have to be able to distinguish procedures 212 00:11:33,440 --> 00:11:37,190 later, procedures which were produced by lambdas, from ones 213 00:11:37,190 --> 00:11:39,060 that may be primitive. 214 00:11:39,060 --> 00:11:42,440 And so I'm going to have some flag, which I'll just 215 00:11:42,440 --> 00:11:44,935 arbitrarily call closure, just for historical reasons. 216 00:11:44,935 --> 00:11:47,760 217 00:11:47,760 --> 00:11:49,920 Now, to say what parts of this are important. 218 00:11:49,920 --> 00:11:51,970 I'm going to need to know the bound variable 219 00:11:51,970 --> 00:11:54,220 list and the body. 220 00:11:54,220 --> 00:12:00,870 Well, that's the CDR of this, so it's going to be x and plus 221 00:12:00,870 --> 00:12:03,795 x y and some environment. 222 00:12:03,795 --> 00:12:08,170 223 00:12:08,170 --> 00:12:13,980 Now this is not something that users should ever see, this is 224 00:12:13,980 --> 00:12:16,680 purely a representation, internally, 225 00:12:16,680 --> 00:12:18,520 for a procedure object. 226 00:12:18,520 --> 00:12:22,010 It contains a bound variable list, a body, and an 227 00:12:22,010 --> 00:12:26,340 environment, and some type tag saying, I am a procedure. 228 00:12:26,340 --> 00:12:28,080 I'm going to make one now. 229 00:12:28,080 --> 00:12:43,720 So if the CAR of the expression is quote lambda, 230 00:12:43,720 --> 00:12:45,970 then what I'm going to put here is-- 231 00:12:45,970 --> 00:12:58,860 I'm going to make a list of closure, the CDR of the 232 00:12:58,860 --> 00:13:07,520 procedure description was everything except the lambda, 233 00:13:07,520 --> 00:13:10,250 and the current environment. 234 00:13:10,250 --> 00:13:14,470 This implements the rule for environments in the 235 00:13:14,470 --> 00:13:15,190 environment model. 236 00:13:15,190 --> 00:13:17,980 It has to do with construction of procedures from lambda 237 00:13:17,980 --> 00:13:19,210 expressions. 238 00:13:19,210 --> 00:13:22,180 The environment that was around at the time the 239 00:13:22,180 --> 00:13:25,940 evaluator encountered the lambda expression is the 240 00:13:25,940 --> 00:13:30,990 environment where the procedure resulting interprets 241 00:13:30,990 --> 00:13:32,240 it's free variables. 242 00:13:32,240 --> 00:13:34,720 243 00:13:34,720 --> 00:13:35,920 So that's part of that. 244 00:13:35,920 --> 00:13:38,120 And so we have to capture that environment as part of the 245 00:13:38,120 --> 00:13:39,210 procedure object. 246 00:13:39,210 --> 00:13:41,750 And we'll see how that gets used later. 247 00:13:41,750 --> 00:13:45,140 There are also conditional expressions of things like 248 00:13:45,140 --> 00:13:54,520 COND of say, p one, e one, p two, e two. 249 00:13:54,520 --> 00:13:57,670 Where this is a predicate, a predicate is a thing that is 250 00:13:57,670 --> 00:14:00,930 either true or false, and the expression to be evaluated if 251 00:14:00,930 --> 00:14:03,480 the predicate is true. 252 00:14:03,480 --> 00:14:05,516 A set of clauses, if you will, that's the 253 00:14:05,516 --> 00:14:06,790 name for such a thing. 254 00:14:06,790 --> 00:14:09,360 So I'm going put that somewhere else. 255 00:14:09,360 --> 00:14:12,420 We're going to worry about that in another piece of code. 256 00:14:12,420 --> 00:14:13,670 So EQ-- 257 00:14:13,670 --> 00:14:15,900 258 00:14:15,900 --> 00:14:24,710 if the CAR of the expression is COND, then I'm going to do 259 00:14:24,710 --> 00:14:30,800 nothing more than evaluate the COND, the CDR of the 260 00:14:30,800 --> 00:14:32,050 expression. 261 00:14:32,050 --> 00:14:34,080 262 00:14:34,080 --> 00:14:38,380 That's all the clauses in the environment that I'm given. 263 00:14:38,380 --> 00:14:41,430 264 00:14:41,430 --> 00:14:46,480 Well, there's one more case, arbitrary thing like the sum 265 00:14:46,480 --> 00:14:53,380 of x and three, where this is an operator applied to 266 00:14:53,380 --> 00:14:56,590 operands, and there's nothing special about it. 267 00:14:56,590 --> 00:14:59,850 It's not one of the special cases, the special forms. 268 00:14:59,850 --> 00:15:09,650 These are the special forms. 269 00:15:09,650 --> 00:15:12,480 And if I were writing here a professional program, again, I 270 00:15:12,480 --> 00:15:14,370 would somehow make this data directed. 271 00:15:14,370 --> 00:15:16,690 So there wouldn't be a sequence of conditionals here, 272 00:15:16,690 --> 00:15:20,290 there'd be a dispatch on some bits if I were trying to do 273 00:15:20,290 --> 00:15:22,360 this in a more professional way. 274 00:15:22,360 --> 00:15:25,750 So that, in fact, I can add to the thing without changing my 275 00:15:25,750 --> 00:15:26,710 program much. 276 00:15:26,710 --> 00:15:29,850 So, for example, they would run fast, but I'm not worried 277 00:15:29,850 --> 00:15:31,280 about that. 278 00:15:31,280 --> 00:15:34,890 Here we're trying to look at this in its entirety. 279 00:15:34,890 --> 00:15:37,360 So it's else. 280 00:15:37,360 --> 00:15:38,560 Well, what do we do? 281 00:15:38,560 --> 00:15:40,965 In this case, I have to somehow do an addition. 282 00:15:40,965 --> 00:15:44,350 283 00:15:44,350 --> 00:15:46,565 Well, I could find out what the plus is. 284 00:15:46,565 --> 00:15:50,550 I have to find out what the x and the three are. 285 00:15:50,550 --> 00:15:53,330 And then I have to apply the result of finding what the 286 00:15:53,330 --> 00:15:56,360 plus is to the result of finding out what the x 287 00:15:56,360 --> 00:15:58,020 and the three are. 288 00:15:58,020 --> 00:15:59,830 We'll have a name for that. 289 00:15:59,830 --> 00:16:11,280 So I'm going to apply the result of evaluating the CAR 290 00:16:11,280 --> 00:16:13,270 of the expression-- 291 00:16:13,270 --> 00:16:17,210 the car of the expression is the operator-- 292 00:16:17,210 --> 00:16:20,480 in the environment given. 293 00:16:20,480 --> 00:16:24,050 So evaluating the operator gets me the procedure. 294 00:16:24,050 --> 00:16:27,290 Now I have to evaluate all the operands to get the arguments. 295 00:16:27,290 --> 00:16:34,710 I'll call that EVLIST, the CDR of the operands, of the 296 00:16:34,710 --> 00:16:38,835 expression, with respect to the environment. 297 00:16:38,835 --> 00:16:41,940 298 00:16:41,940 --> 00:16:43,290 EVLIST will come up later-- 299 00:16:43,290 --> 00:16:48,070 EVLIST, apply, COND pair, COND, lambda, define. 300 00:16:48,070 --> 00:16:50,900 301 00:16:50,900 --> 00:16:53,630 So that what you are seeing here now is pretty much all 302 00:16:53,630 --> 00:16:56,590 there is in the evaluator itself. 303 00:16:56,590 --> 00:17:01,370 It's the case dispatch on the type of the expression with 304 00:17:01,370 --> 00:17:07,470 the default being a general application or a combination. 305 00:17:07,470 --> 00:17:17,520 306 00:17:17,520 --> 00:17:20,089 Now there is lots of things we haven't defined yet. 307 00:17:20,089 --> 00:17:21,780 Let's just look at them and see what they are. 308 00:17:21,780 --> 00:17:25,480 We're going to have to do this later, evcond. 309 00:17:25,480 --> 00:17:27,579 We have to write apply. 310 00:17:27,579 --> 00:17:29,120 We're going to have to write EVLIST. We're 311 00:17:29,120 --> 00:17:31,790 going to write LOOKUP. 312 00:17:31,790 --> 00:17:33,430 I think that's everything, isn't there? 313 00:17:33,430 --> 00:17:35,860 Everything else is something which is simple, or primitive, 314 00:17:35,860 --> 00:17:38,570 or something like that. 315 00:17:38,570 --> 00:17:42,360 And, of course, we could many more special forms here, but 316 00:17:42,360 --> 00:17:44,450 that would be a bad idea in general in a language. 317 00:17:44,450 --> 00:17:46,730 You make a language very complicated by putting a lot 318 00:17:46,730 --> 00:17:47,690 of things in there. 319 00:17:47,690 --> 00:17:49,830 The number of reserve words that should exist in a 320 00:17:49,830 --> 00:17:52,540 language should be no more than a person could remember 321 00:17:52,540 --> 00:17:54,010 on his fingers and toes. 322 00:17:54,010 --> 00:17:56,820 And I get very upset with languages which have hundreds 323 00:17:56,820 --> 00:17:59,410 of reserve words. 324 00:17:59,410 --> 00:18:00,710 But that's where the reserve words go. 325 00:18:00,710 --> 00:18:04,750 326 00:18:04,750 --> 00:18:06,430 Well, now let's get to the next part of 327 00:18:06,430 --> 00:18:09,640 this, the kernel, apply. 328 00:18:09,640 --> 00:18:11,590 What else is this doing? 329 00:18:11,590 --> 00:18:17,020 Well, apply's job is to take a procedure and apply it to its 330 00:18:17,020 --> 00:18:19,500 arguments after both have been evaluated to come up with a 331 00:18:19,500 --> 00:18:22,560 procedure and the arguments rather the operator symbols 332 00:18:22,560 --> 00:18:25,360 and the operand symbols, whatever they are-- 333 00:18:25,360 --> 00:18:26,610 symbolic expressions. 334 00:18:26,610 --> 00:18:33,270 335 00:18:33,270 --> 00:18:40,810 So we will define apply to be a procedure of two arguments, 336 00:18:40,810 --> 00:18:43,280 a procedure and arguments. 337 00:18:43,280 --> 00:18:47,110 338 00:18:47,110 --> 00:18:48,080 And what does it do? 339 00:18:48,080 --> 00:18:49,720 It does nothing very complicated. 340 00:18:49,720 --> 00:18:50,970 It's got two cases. 341 00:18:50,970 --> 00:18:53,580 342 00:18:53,580 --> 00:18:55,095 Either the procedure is primitive-- 343 00:18:55,095 --> 00:19:02,970 344 00:19:02,970 --> 00:19:06,930 And I don't know exactly how that is done. 345 00:19:06,930 --> 00:19:10,930 It's possible there's some type information just like we 346 00:19:10,930 --> 00:19:14,110 made closure for, here, being the description of the type of 347 00:19:14,110 --> 00:19:16,810 a compound thing-- 348 00:19:16,810 --> 00:19:18,550 probably so. 349 00:19:18,550 --> 00:19:21,360 But it is not essential how that works, and, in fact, it 350 00:19:21,360 --> 00:19:24,140 turns out, as you probably know or have deduced, that you 351 00:19:24,140 --> 00:19:27,350 don't need any primitives anyway. 352 00:19:27,350 --> 00:19:30,732 You can compute anything without them because some of 353 00:19:30,732 --> 00:19:33,190 the lambda that I've been playing with. 354 00:19:33,190 --> 00:19:34,750 But it's nice to have them. 355 00:19:34,750 --> 00:19:36,630 So here we're going to do some magic which I'm 356 00:19:36,630 --> 00:19:38,060 not going to explain. 357 00:19:38,060 --> 00:19:42,860 Go to machine language, apply primop. 358 00:19:42,860 --> 00:19:44,850 Here's how it adds. 359 00:19:44,850 --> 00:19:46,100 Execute an add instruction. 360 00:19:46,100 --> 00:19:50,360 361 00:19:50,360 --> 00:19:52,840 However, the interesting part of a language is the glue by 362 00:19:52,840 --> 00:19:54,940 which the predicates are glued together. 363 00:19:54,940 --> 00:19:56,910 So let's look at that. 364 00:19:56,910 --> 00:20:01,210 Well, the other possibility is that this is a compound made 365 00:20:01,210 --> 00:20:05,140 up by executing a lambda expression, this 366 00:20:05,140 --> 00:20:07,620 is a compound procedure. 367 00:20:07,620 --> 00:20:10,110 Well, we'll check its type. 368 00:20:10,110 --> 00:20:23,010 If it is closure, if it's one of those, then I have to do an 369 00:20:23,010 --> 00:20:24,500 eval of the body. 370 00:20:24,500 --> 00:20:28,960 The way I do this, the way I deal with this at all, is the 371 00:20:28,960 --> 00:20:31,210 way I evaluate the application of a procedure to its 372 00:20:31,210 --> 00:20:34,400 arguments, is by evaluating the body of the procedure in 373 00:20:34,400 --> 00:20:37,050 the environment resulting from extending the environment of 374 00:20:37,050 --> 00:20:39,670 the procedure with the bindings of the formal 375 00:20:39,670 --> 00:20:43,010 parameters of the procedure to the arguments that 376 00:20:43,010 --> 00:20:44,260 were passed to it. 377 00:20:44,260 --> 00:20:47,030 378 00:20:47,030 --> 00:20:48,280 That was a long sentence. 379 00:20:48,280 --> 00:20:51,130 380 00:20:51,130 --> 00:20:52,822 Well that's easy enough. 381 00:20:52,822 --> 00:20:56,214 Now here's going to be a lot of CAR-CDRing. 382 00:20:56,214 --> 00:20:59,400 I have to get the body of the procedure. 383 00:20:59,400 --> 00:21:02,960 Where's the body of the procedure in here? 384 00:21:02,960 --> 00:21:05,490 Well here's the CAR, here's the CDR is the 385 00:21:05,490 --> 00:21:06,130 whole rest of this. 386 00:21:06,130 --> 00:21:09,130 So here's the CADR. And so I see, what I have here is the 387 00:21:09,130 --> 00:21:11,430 body is the second element of the second 388 00:21:11,430 --> 00:21:13,200 element of the procedure. 389 00:21:13,200 --> 00:21:19,170 So it's the CADR of the CADR or the CADADR. 390 00:21:19,170 --> 00:21:27,495 It's the C-A-D-A-D-R, CADADR of the procedure. 391 00:21:27,495 --> 00:21:30,260 392 00:21:30,260 --> 00:21:35,170 To evaluate the body in the result of binding that's 393 00:21:35,170 --> 00:21:39,080 making up more environment, well I need the formal 394 00:21:39,080 --> 00:21:43,500 parameters of the of the procedure, what is that? 395 00:21:43,500 --> 00:21:48,780 That's the CAR of the CDR. It's horrible isn't it? 396 00:21:48,780 --> 00:21:52,440 397 00:21:52,440 --> 00:21:55,440 --of the procedure. 398 00:21:55,440 --> 00:22:00,370 Bind that to the arguments that were passed in the 399 00:22:00,370 --> 00:22:04,540 environment, which is passed also as part of the procedure. 400 00:22:04,540 --> 00:22:09,670 Well, that's the CAR of the CDR of the CDR of this, 401 00:22:09,670 --> 00:22:16,315 CADDR, of the procedure. 402 00:22:16,315 --> 00:22:20,290 403 00:22:20,290 --> 00:22:26,490 Bind, eval, pair, COND, lamda, define-- 404 00:22:26,490 --> 00:22:29,370 Now, of course, if I were being really a neat character, 405 00:22:29,370 --> 00:22:33,490 and I was being very careful, I would actually put an extra 406 00:22:33,490 --> 00:22:36,540 case here for checking for certain errors like, did you 407 00:22:36,540 --> 00:22:39,000 try to apply one to an argument? 408 00:22:39,000 --> 00:22:42,570 You get a undefined procedure type. 409 00:22:42,570 --> 00:22:45,500 So I may as well do that anyway. 410 00:22:45,500 --> 00:22:57,610 --else, some sort of error, like that. 411 00:22:57,610 --> 00:23:02,620 Now, of course, again, in some sort of more real system, 412 00:23:02,620 --> 00:23:06,770 written for professional reasons, this would be written 413 00:23:06,770 --> 00:23:10,750 with a case analysis done by some sort of dispatch. 414 00:23:10,750 --> 00:23:13,250 Over here, I would probably have other cases like, is this 415 00:23:13,250 --> 00:23:16,220 compiled code? 416 00:23:16,220 --> 00:23:17,020 It's very important. 417 00:23:17,020 --> 00:23:19,530 I might have distinguished the kind of code that's produced 418 00:23:19,530 --> 00:23:23,150 by a directly evaluating a lambda in interpretation from 419 00:23:23,150 --> 00:23:25,190 code that was produced by somebody's compiler or 420 00:23:25,190 --> 00:23:25,880 something like that. 421 00:23:25,880 --> 00:23:27,230 And we'll talk about that later. 422 00:23:27,230 --> 00:23:28,710 Or is this a piece Fortran program I have 423 00:23:28,710 --> 00:23:30,510 to go off and execute. 424 00:23:30,510 --> 00:23:31,820 It's a perfectly possible thing, at this 425 00:23:31,820 --> 00:23:32,920 point, to do that. 426 00:23:32,920 --> 00:23:36,070 In fact, in this concrete syntax evaluator I'm writing 427 00:23:36,070 --> 00:23:42,600 here, there's an assumption built in that this is Lisp, 428 00:23:42,600 --> 00:23:44,360 because I'm using CARs and CDRs. 429 00:23:44,360 --> 00:23:46,750 CAR means the operator, and CDR means the operand. 430 00:23:46,750 --> 00:23:50,500 In the text, there is an abstract syntax evaluator for 431 00:23:50,500 --> 00:23:52,160 which these could be-- 432 00:23:52,160 --> 00:23:54,310 these are given abstract names like operator, and operand, 433 00:23:54,310 --> 00:23:56,160 and all these other things are like that. 434 00:23:56,160 --> 00:24:00,320 And, in that case, you could reprogram it to be ALGOL with 435 00:24:00,320 --> 00:24:01,570 no problem. 436 00:24:01,570 --> 00:24:03,760 437 00:24:03,760 --> 00:24:07,410 Well, here we have added another couple of things that 438 00:24:07,410 --> 00:24:08,660 we haven't defined. 439 00:24:08,660 --> 00:24:10,810 440 00:24:10,810 --> 00:24:13,800 I don't think I'll worry about these at all, however, this 441 00:24:13,800 --> 00:24:15,050 one will be interesting later. 442 00:24:15,050 --> 00:24:17,930 443 00:24:17,930 --> 00:24:20,550 Let's just proceed through this and get it done. 444 00:24:20,550 --> 00:24:21,810 There's only two more blackboards so it 445 00:24:21,810 --> 00:24:23,060 can't be very long. 446 00:24:23,060 --> 00:24:27,056 447 00:24:27,056 --> 00:24:30,070 It's carefully tailored to exactly fit. 448 00:24:30,070 --> 00:24:30,980 Well, what do we have left? 449 00:24:30,980 --> 00:24:33,730 We have to define EVLIST, which is over here. 450 00:24:33,730 --> 00:24:40,620 And EVLIST is nothing more than a map down a bunch of 451 00:24:40,620 --> 00:24:44,240 operands producing arguments. 452 00:24:44,240 --> 00:24:45,820 But I'm going to write it out. 453 00:24:45,820 --> 00:24:47,445 And one of the reasons I'm going to write this out is for 454 00:24:47,445 --> 00:24:51,820 a mystical reason, which is I want to make this evaluator so 455 00:24:51,820 --> 00:24:53,610 simple that it can understand itself. 456 00:24:53,610 --> 00:24:56,450 457 00:24:56,450 --> 00:25:00,230 I'm going to really worry about that a little bit. 458 00:25:00,230 --> 00:25:02,850 So let's write it out completely. 459 00:25:02,850 --> 00:25:04,890 See, I don't want to worry about whether or not the thing 460 00:25:04,890 --> 00:25:06,080 can pass functional arguments. 461 00:25:06,080 --> 00:25:08,980 The value evaluator is not going to use them. 462 00:25:08,980 --> 00:25:10,880 The evaluator is not going to produce functional values. 463 00:25:10,880 --> 00:25:12,310 So even if there were a different, alternative 464 00:25:12,310 --> 00:25:16,510 language that were very close to this, this evaluates a 465 00:25:16,510 --> 00:25:19,830 complex language like Scheme which does allow procedural 466 00:25:19,830 --> 00:25:24,070 arguments, procedural values, and procedural data. 467 00:25:24,070 --> 00:25:28,100 But even if I were evaluating ALGOL, which doesn't allow 468 00:25:28,100 --> 00:25:31,580 procedural values, I could use this evaluator. 469 00:25:31,580 --> 00:25:32,870 And this evaluator is not making any 470 00:25:32,870 --> 00:25:34,050 assumptions about that. 471 00:25:34,050 --> 00:25:36,580 And, in fact, if this value were to be restricted to not 472 00:25:36,580 --> 00:25:37,700 being able to that, it wouldn't matter, because it 473 00:25:37,700 --> 00:25:40,640 doesn't use any of those clever things. 474 00:25:40,640 --> 00:25:44,070 So that's why I'm arranging this to be super simple. 475 00:25:44,070 --> 00:25:45,970 This is sort of the kernel of all possible language 476 00:25:45,970 --> 00:25:47,810 evaluators. 477 00:25:47,810 --> 00:25:49,420 How about that? 478 00:25:49,420 --> 00:25:50,670 Evlist-- 479 00:25:50,670 --> 00:25:52,525 480 00:25:52,525 --> 00:25:53,820 well, what is it? 481 00:25:53,820 --> 00:25:56,300 It's the procedure of two arguments, l and an 482 00:25:56,300 --> 00:26:06,260 environment, where l is a list such that if the list of 483 00:26:06,260 --> 00:26:12,380 arguments is the empty list, then the result is the empty 484 00:26:12,380 --> 00:26:21,480 list. Otherwise, I want to cons up the result of 485 00:26:21,480 --> 00:26:31,880 evaluating the CAR of the list of operands in the 486 00:26:31,880 --> 00:26:33,260 environment. 487 00:26:33,260 --> 00:26:36,360 So I want the first operand evaluated, and I'm going to 488 00:26:36,360 --> 00:26:40,735 make a list of the results by CONSing that onto the result 489 00:26:40,735 --> 00:26:48,880 of this EVLISTing as a CDR recursion, the CDR of the list 490 00:26:48,880 --> 00:26:50,130 relative to the same environment. 491 00:26:50,130 --> 00:26:53,350 492 00:26:53,350 --> 00:26:57,960 Evlist, cons, else, COND, lambda, define-- 493 00:26:57,960 --> 00:27:00,950 494 00:27:00,950 --> 00:27:03,620 And I have one more that I want to put on the blackboard. 495 00:27:03,620 --> 00:27:05,470 It's the essence of this whole thing. 496 00:27:05,470 --> 00:27:08,130 And there's some sort of next layer down. 497 00:27:08,130 --> 00:27:14,540 498 00:27:14,540 --> 00:27:15,770 Conditionals-- 499 00:27:15,770 --> 00:27:17,500 conditionals are the only thing left that are sort of 500 00:27:17,500 --> 00:27:18,880 substantial. 501 00:27:18,880 --> 00:27:22,320 Then below that, we have to worry about things like lookup 502 00:27:22,320 --> 00:27:25,530 and bind, and we'll look at that in a second. 503 00:27:25,530 --> 00:27:29,030 But of the substantial stuff at this level of detail, next 504 00:27:29,030 --> 00:27:31,600 important thing is how you deal with conditionals. 505 00:27:31,600 --> 00:27:33,330 Well, how do we have a conditional thing? 506 00:27:33,330 --> 00:27:37,670 507 00:27:37,670 --> 00:27:44,720 It's a procedure of a set of clauses and an environment. 508 00:27:44,720 --> 00:27:47,340 509 00:27:47,340 --> 00:27:49,820 And what does it do? 510 00:27:49,820 --> 00:28:03,310 It says, if I've no more clauses, well, I have to give 511 00:28:03,310 --> 00:28:04,520 this a value. 512 00:28:04,520 --> 00:28:06,540 It could be that it was an error. 513 00:28:06,540 --> 00:28:08,030 Supposing it run off the end of a 514 00:28:08,030 --> 00:28:10,060 conditional, it's pretty arbitrary. 515 00:28:10,060 --> 00:28:13,650 It's up to me as programmer to choose what I want to happen. 516 00:28:13,650 --> 00:28:15,940 It's convenient for me, right now, to write down that this 517 00:28:15,940 --> 00:28:20,100 has a value which is the empty list, doesn't matter. 518 00:28:20,100 --> 00:28:21,530 For error checking, some people might 519 00:28:21,530 --> 00:28:23,110 prefer something else. 520 00:28:23,110 --> 00:28:25,570 But the interesting things are the following ones. 521 00:28:25,570 --> 00:28:27,450 If I've got an else clause-- 522 00:28:27,450 --> 00:28:31,420 523 00:28:31,420 --> 00:28:34,120 You see, if I have a list of clauses, then each clause is a 524 00:28:34,120 --> 00:28:37,480 list. And so the predicate part is 525 00:28:37,480 --> 00:28:40,265 the CAAR of the clauses. 526 00:28:40,265 --> 00:28:43,560 527 00:28:43,560 --> 00:28:48,070 It's the CAR, which is the first part of the first clause 528 00:28:48,070 --> 00:28:51,090 in the list of clauses. 529 00:28:51,090 --> 00:28:55,900 If it's an else, then it means I want my result of the 530 00:28:55,900 --> 00:28:58,400 conditional to be the result of evaluating the matching 531 00:28:58,400 --> 00:28:59,800 expression. 532 00:28:59,800 --> 00:29:10,610 So I eval the CADR. So this is the first clause, the second 533 00:29:10,610 --> 00:29:12,830 element of it, CADAR-- 534 00:29:12,830 --> 00:29:16,360 CADAR of a CAR-- 535 00:29:16,360 --> 00:29:22,195 of the clauses, with respect to the environment. 536 00:29:22,195 --> 00:29:26,620 537 00:29:26,620 --> 00:29:29,630 Now the next possibility is more interesting. 538 00:29:29,630 --> 00:29:34,860 If it's false, if the first predicate in the predicate 539 00:29:34,860 --> 00:29:38,840 list is not an else, and it's not false, if it's not the 540 00:29:38,840 --> 00:29:42,050 word else, and if it's not a false thing-- 541 00:29:42,050 --> 00:29:44,360 Let's write down what it is if it's a false thing. 542 00:29:44,360 --> 00:29:49,590 If the result of evaluating the first 543 00:29:49,590 --> 00:29:52,900 predicate, the clauses-- 544 00:29:52,900 --> 00:29:55,490 545 00:29:55,490 --> 00:30:01,630 respect the environment, if that evaluation yields false, 546 00:30:01,630 --> 00:30:04,180 then it means, I want to look at the next clause. 547 00:30:04,180 --> 00:30:05,990 So I want to discard the first one. 548 00:30:05,990 --> 00:30:15,450 So we just go around loop, evcond, the CDR of the clauses 549 00:30:15,450 --> 00:30:16,700 relative to that environment. 550 00:30:16,700 --> 00:30:21,240 551 00:30:21,240 --> 00:30:27,740 And otherwise, I had a true clause, in which case, what I 552 00:30:27,740 --> 00:30:40,710 want is to evaluate the CADAR of the clauses relative to 553 00:30:40,710 --> 00:30:41,960 that environment. 554 00:30:41,960 --> 00:30:48,200 555 00:30:48,200 --> 00:30:51,210 Boy, it's almost done. 556 00:30:51,210 --> 00:30:53,730 It's quite close to done. 557 00:30:53,730 --> 00:30:56,210 I think we're going to finish this part off. 558 00:30:56,210 --> 00:30:59,530 So just buzzing through this evaluator, but so far you're 559 00:30:59,530 --> 00:31:01,220 seeing almost everything. 560 00:31:01,220 --> 00:31:04,040 Let's look at the next transparency here. 561 00:31:04,040 --> 00:31:08,980 562 00:31:08,980 --> 00:31:11,980 Here is bind. 563 00:31:11,980 --> 00:31:15,460 Bind is for making more table. 564 00:31:15,460 --> 00:31:19,260 And what we are going to do here is make a-- 565 00:31:19,260 --> 00:31:22,800 we're going to make a no-frame for an environment structure. 566 00:31:22,800 --> 00:31:26,230 The environment structure is going to be represented as a 567 00:31:26,230 --> 00:31:28,080 list of frames. 568 00:31:28,080 --> 00:31:30,520 So given an existing environment structure, I'm 569 00:31:30,520 --> 00:31:32,500 going to make a new environment structure by 570 00:31:32,500 --> 00:31:35,270 consing a new frame onto the existing environment 571 00:31:35,270 --> 00:31:38,700 structure, where the new frame consists of the result of 572 00:31:38,700 --> 00:31:41,940 pairing up the variables, which are the bound variables 573 00:31:41,940 --> 00:31:45,610 of the procedure I'm applying, to the values which are the 574 00:31:45,610 --> 00:31:49,690 arguments that were passed that procedure. 575 00:31:49,690 --> 00:31:53,260 This is just making a list, adding a new element to our 576 00:31:53,260 --> 00:31:56,070 list of frames, which is an environment structure, to make 577 00:31:56,070 --> 00:31:58,391 a new environment. 578 00:31:58,391 --> 00:32:01,540 Where pair-up is very simple. 579 00:32:01,540 --> 00:32:04,610 Pair-up is nothing more than if I have a list of variables 580 00:32:04,610 --> 00:32:07,830 and a list of values, well, if I run out of variables and if 581 00:32:07,830 --> 00:32:09,720 I run out of values, everything's OK. 582 00:32:09,720 --> 00:32:12,990 Otherwise, I've given too many arguments. 583 00:32:12,990 --> 00:32:15,390 If I've not run out of variables, but I've run out of 584 00:32:15,390 --> 00:32:18,560 values, that I have too few arguments. 585 00:32:18,560 --> 00:32:20,695 And in the general case, where I don't have any errors, and 586 00:32:20,695 --> 00:32:26,860 I'm not done, then I really am just adding a new pair of the 587 00:32:26,860 --> 00:32:32,810 first variable with the first argument, the first value, 588 00:32:32,810 --> 00:32:37,780 onto a list resulting from pairing-up the rest of the 589 00:32:37,780 --> 00:32:42,950 variables with the rest of the values. 590 00:32:42,950 --> 00:32:46,620 Lookup is of course equally simple. 591 00:32:46,620 --> 00:32:50,230 If I have to look up a symbol in an environment, well, if 592 00:32:50,230 --> 00:32:54,650 the environment is empty, then I've got an unbound variable. 593 00:32:54,650 --> 00:32:59,770 Otherwise, what I'm going to do is use a special pair list 594 00:32:59,770 --> 00:33:02,540 lookup procedure, which we'll have very shortly, of the 595 00:33:02,540 --> 00:33:05,930 symbol in the first frame of the environment. 596 00:33:05,930 --> 00:33:07,670 Since I know the environment is not empty, it must have a 597 00:33:07,670 --> 00:33:09,200 first frame. 598 00:33:09,200 --> 00:33:11,140 So I lookup the symbol in the first frame. 599 00:33:11,140 --> 00:33:15,150 That becomes the value cell here. 600 00:33:15,150 --> 00:33:19,860 And then, if the value cell is empty, if there is no such 601 00:33:19,860 --> 00:33:22,150 value cell, then I have to continue and look at the rest 602 00:33:22,150 --> 00:33:23,720 of the frames. 603 00:33:23,720 --> 00:33:25,990 It means there was nothing found there. 604 00:33:25,990 --> 00:33:29,740 So that's a property of ASSQ is it returns emptiness if it 605 00:33:29,740 --> 00:33:32,010 doesn't find something. 606 00:33:32,010 --> 00:33:35,175 but if it did find something, then I'm going to use the CDR 607 00:33:35,175 --> 00:33:38,080 of the value cell here, which is the thing that was the pair 608 00:33:38,080 --> 00:33:41,050 consisting of the variable and the value. 609 00:33:41,050 --> 00:33:45,000 So the CDR of it is the value part. 610 00:33:45,000 --> 00:33:47,970 Finally, ASSQ is something you've probably seen already. 611 00:33:47,970 --> 00:33:52,400 ASSQ takes a symbol and a list of pairs, and if the list is 612 00:33:52,400 --> 00:33:53,760 empty, it's empty. 613 00:33:53,760 --> 00:33:57,850 If the symbol is the first thing in the list-- 614 00:33:57,850 --> 00:33:59,820 That's an error. 615 00:33:59,820 --> 00:34:04,160 That should be CAAR, C-A-A-R. Everybody note that. 616 00:34:04,160 --> 00:34:07,730 617 00:34:07,730 --> 00:34:08,980 Right there, OK? 618 00:34:08,980 --> 00:34:13,121 619 00:34:13,121 --> 00:34:17,150 And in any case, if the symbol is the CAAR of the A list, 620 00:34:17,150 --> 00:34:22,340 then I want the first, the first pair, in the A list. So, 621 00:34:22,340 --> 00:34:26,300 in other words, if this is the key matching the right entry, 622 00:34:26,300 --> 00:34:30,429 otherwise, I want to look up that symbol in the rest. Sorry 623 00:34:30,429 --> 00:34:35,190 for producing a bug, bugs appear. 624 00:34:35,190 --> 00:34:38,389 Well, in any case, you're pretty much seeing 625 00:34:38,389 --> 00:34:39,639 the whole thing now. 626 00:34:39,639 --> 00:34:41,880 627 00:34:41,880 --> 00:34:45,150 It's a very beautiful thing, even though it's written in an 628 00:34:45,150 --> 00:34:49,600 ugly style, being the kernel of every language. 629 00:34:49,600 --> 00:34:50,210 I suggest that we just-- 630 00:34:50,210 --> 00:34:51,460 let's look at it for a while. 631 00:34:51,460 --> 00:34:56,749 632 00:34:56,749 --> 00:35:49,750 [MUSIC PLAYING] 633 00:35:49,750 --> 00:35:51,000 Are there any questions? 634 00:35:51,000 --> 00:36:01,180 635 00:36:01,180 --> 00:36:04,044 Alright, I suppose it's time to take a small break then. 636 00:36:04,044 --> 00:36:56,780 [MUSIC PLAYING] 637 00:36:56,780 --> 00:36:59,390 OK, now we're just going to do a little bit of practice 638 00:36:59,390 --> 00:37:03,470 understanding what it is we've just shown you. 639 00:37:03,470 --> 00:37:05,700 What we're going to do is go through, in detail, an 640 00:37:05,700 --> 00:37:09,720 evaluation by informally substituting through the 641 00:37:09,720 --> 00:37:11,500 interpreter. 642 00:37:11,500 --> 00:37:14,160 And since we have no assignments or definitions in 643 00:37:14,160 --> 00:37:18,470 this interpreter, we have no possible side effects, and so 644 00:37:18,470 --> 00:37:23,200 the we can do substitution with impunity and not worry 645 00:37:23,200 --> 00:37:25,330 about results. 646 00:37:25,330 --> 00:37:28,800 So the particular problem I'd like to look at is it an 647 00:37:28,800 --> 00:37:30,690 interesting one. 648 00:37:30,690 --> 00:37:41,910 It's the evaluation of quote, open, open, open, lambda of x, 649 00:37:41,910 --> 00:37:55,100 lambda of y plus x y, lambda, lambda, applied to three, 650 00:37:55,100 --> 00:37:58,640 applied to four, in some global environment 651 00:37:58,640 --> 00:37:59,890 which I'll call e0. 652 00:37:59,890 --> 00:38:04,930 653 00:38:04,930 --> 00:38:07,900 So what we have here is a procedure of one argument x, 654 00:38:07,900 --> 00:38:10,980 which produces as its value a procedure of one argument y, 655 00:38:10,980 --> 00:38:14,300 which adds x to y. 656 00:38:14,300 --> 00:38:17,960 We are applying the procedure of one argument x to three. 657 00:38:17,960 --> 00:38:21,400 So x should become three. 658 00:38:21,400 --> 00:38:23,590 And the result of that should be procedure of one argument 659 00:38:23,590 --> 00:38:26,167 y, which will then apply to 4. 660 00:38:26,167 --> 00:38:28,910 661 00:38:28,910 --> 00:38:31,480 And there is a very simple case, they will 662 00:38:31,480 --> 00:38:34,790 then add those results. 663 00:38:34,790 --> 00:38:36,860 And now in order to do that, I want to make a very simple 664 00:38:36,860 --> 00:38:37,660 environment model. 665 00:38:37,660 --> 00:38:41,200 And at this point, you should already have in your mind the 666 00:38:41,200 --> 00:38:44,460 environments that this produces. 667 00:38:44,460 --> 00:38:48,810 But we're going to start out with a global environment, 668 00:38:48,810 --> 00:38:56,740 which I'll call e0, which is that. 669 00:38:56,740 --> 00:39:00,550 And it's going to have in it things, definitions for plus, 670 00:39:00,550 --> 00:39:07,390 and times, and-- 671 00:39:07,390 --> 00:39:08,560 using Greek letters, isn't that 672 00:39:08,560 --> 00:39:11,290 interesting, for the objects-- 673 00:39:11,290 --> 00:39:27,330 and minus, and quotient, and CAR, and CDR, and CONS, and 674 00:39:27,330 --> 00:39:30,480 EQ, and everything else you might imagine in a global 675 00:39:30,480 --> 00:39:31,270 environment. 676 00:39:31,270 --> 00:39:34,590 It's got something there for each of those things, 677 00:39:34,590 --> 00:39:39,220 something the machine is born with, that's e0. 678 00:39:39,220 --> 00:39:42,940 Now what does it mean to do this evaluation? 679 00:39:42,940 --> 00:39:46,120 Well, we go through the set of special forms. First of all, 680 00:39:46,120 --> 00:39:48,670 this is not a number. 681 00:39:48,670 --> 00:39:50,380 This is not a symbol. 682 00:39:50,380 --> 00:39:53,210 683 00:39:53,210 --> 00:39:56,520 Gee, it's not a quoted expression. 684 00:39:56,520 --> 00:40:00,080 This is a quoted expression, but that's not what I 685 00:40:00,080 --> 00:40:00,600 interested in. 686 00:40:00,600 --> 00:40:02,700 The question is, whether or not the thing which is quoted 687 00:40:02,700 --> 00:40:05,890 is quoted expression? 688 00:40:05,890 --> 00:40:07,960 I'm evaluating an expression. 689 00:40:07,960 --> 00:40:11,410 This just says it's this particular expression. 690 00:40:11,410 --> 00:40:12,660 This is not a quoted expression. 691 00:40:12,660 --> 00:40:15,230 692 00:40:15,230 --> 00:40:19,120 It's not a thing that begins with lambda. 693 00:40:19,120 --> 00:40:22,030 It's not a thing that begins with COND. 694 00:40:22,030 --> 00:40:24,630 Therefore, it's an application of its 695 00:40:24,630 --> 00:40:26,310 of an operated operands. 696 00:40:26,310 --> 00:40:28,570 It's a combination. 697 00:40:28,570 --> 00:40:35,230 The combination thus has this as the operator and this is 698 00:40:35,230 --> 00:40:36,480 the operands. 699 00:40:36,480 --> 00:40:40,130 700 00:40:40,130 --> 00:40:43,540 Well, that means that what I'm going to do is transform this 701 00:40:43,540 --> 00:40:54,010 into apply of eval, of quote, open, open lambda of 702 00:40:54,010 --> 00:40:58,180 x, lambda of y-- 703 00:40:58,180 --> 00:40:59,980 I'm evaluating the operator-- 704 00:40:59,980 --> 00:41:13,610 plus x y, in the environment, also e0, with the operands 705 00:41:13,610 --> 00:41:16,330 that I'm going to apply this to, the arguments being the 706 00:41:16,330 --> 00:41:24,450 result of EVLIST, the list containing four, fin e0. 707 00:41:24,450 --> 00:41:29,010 708 00:41:29,010 --> 00:41:33,010 I'm using this funny notation here for e0 because this 709 00:41:33,010 --> 00:41:36,840 should be that environment. 710 00:41:36,840 --> 00:41:38,640 I haven't a name for it, because I have no environment 711 00:41:38,640 --> 00:41:39,890 to name it in. 712 00:41:39,890 --> 00:41:41,960 713 00:41:41,960 --> 00:41:44,630 So this is just a representation of what would 714 00:41:44,630 --> 00:41:47,730 be a quoted expression, if you will. 715 00:41:47,730 --> 00:41:53,040 The data structure, which is the environment, goes there. 716 00:41:53,040 --> 00:41:55,850 Well, that's what we're seeing here. 717 00:41:55,850 --> 00:41:57,370 Well in order to do this, I have to do this, and 718 00:41:57,370 --> 00:41:59,610 I have to do that. 719 00:41:59,610 --> 00:42:03,770 Well this one's easy, so why don't we do that one first. 720 00:42:03,770 --> 00:42:07,780 This turns into apply of eval-- just 721 00:42:07,780 --> 00:42:09,520 copying something now. 722 00:42:09,520 --> 00:42:11,000 Most of the substitution rule is copying. 723 00:42:11,000 --> 00:42:18,530 724 00:42:18,530 --> 00:42:22,100 So I'm going to not say the words when I copy, because 725 00:42:22,100 --> 00:42:23,350 it's faster. 726 00:42:23,350 --> 00:42:26,100 727 00:42:26,100 --> 00:42:34,130 And then the EVLIST is going to turn into a cons, of eval, 728 00:42:34,130 --> 00:42:36,160 of four, in e0-- 729 00:42:36,160 --> 00:42:38,780 730 00:42:38,780 --> 00:42:42,260 because it was not an empty list-- 731 00:42:42,260 --> 00:42:48,910 onto the result of EVLISTing, on the empty list, in e0. 732 00:42:48,910 --> 00:42:52,580 733 00:42:52,580 --> 00:42:54,550 And I'm going to start leaving out steps soon, because it's 734 00:42:54,550 --> 00:42:55,800 going to get boring. 735 00:42:55,800 --> 00:42:59,870 736 00:42:59,870 --> 00:43:05,025 But this is basically the same thing as apply, of eval-- 737 00:43:05,025 --> 00:43:07,640 738 00:43:07,640 --> 00:43:10,230 I'm going to keep doing this-- 739 00:43:10,230 --> 00:43:20,240 the lambda of x, the lambda of y, plus xy, 3, close, e0. 740 00:43:20,240 --> 00:43:21,490 I'm a pretty good machine. 741 00:43:21,490 --> 00:43:24,690 742 00:43:24,690 --> 00:43:27,410 Well, eval of four, that's meets the 743 00:43:27,410 --> 00:43:28,790 question, is it a number. 744 00:43:28,790 --> 00:43:35,280 So that's cons, cons of 4. 745 00:43:35,280 --> 00:43:37,110 And EVLIST of the empty list is the empty 746 00:43:37,110 --> 00:43:39,240 list, so that's this. 747 00:43:39,240 --> 00:43:43,270 748 00:43:43,270 --> 00:43:46,170 And that's very simple to understand, because that means 749 00:43:46,170 --> 00:43:48,710 the list containing four itself. 750 00:43:48,710 --> 00:43:56,340 So this is nothing more than apply of eval, quote, open, 751 00:43:56,340 --> 00:44:06,590 open, lambda of x, lambda of y, plus x y, three applied to, 752 00:44:06,590 --> 00:44:11,678 e0, applied to the list four-- 753 00:44:11,678 --> 00:44:13,940 bang. 754 00:44:13,940 --> 00:44:15,190 So that's that step. 755 00:44:15,190 --> 00:44:18,100 756 00:44:18,100 --> 00:44:20,360 Now let's look at the next, more interesting thing. 757 00:44:20,360 --> 00:44:23,070 What do I do to evaluate that? 758 00:44:23,070 --> 00:44:27,780 Evaluating this means I have to evaluate-- 759 00:44:27,780 --> 00:44:29,460 Well, it's not. 760 00:44:29,460 --> 00:44:31,680 It's nothing but an application. 761 00:44:31,680 --> 00:44:33,570 It's not one of the special things. 762 00:44:33,570 --> 00:44:37,660 If the application of this operator, which we see here-- 763 00:44:37,660 --> 00:44:40,270 here's the operator-- 764 00:44:40,270 --> 00:44:46,570 applied to this operands, that combination. 765 00:44:46,570 --> 00:44:51,390 But we know how to do that, because that's the last case 766 00:44:51,390 --> 00:44:52,370 of the conditional. 767 00:44:52,370 --> 00:44:56,480 So substituting in for this evaluation, it's apply of eval 768 00:44:56,480 --> 00:45:01,160 of the operator in the EVLIST of the operands. 769 00:45:01,160 --> 00:45:12,100 Well, it's apply, of apply, of eval, of quote, open, lambda 770 00:45:12,100 --> 00:45:23,780 of x, lambda of y, plus x y, lambda, lambda, 771 00:45:23,780 --> 00:45:25,350 in environment e0. 772 00:45:25,350 --> 00:45:30,520 773 00:45:30,520 --> 00:45:32,730 I'm going to short circuit the evaluation of the operands , 774 00:45:32,730 --> 00:45:35,230 because they're the same as they were before. 775 00:45:35,230 --> 00:45:38,080 I got a list containing three, apply that, and 776 00:45:38,080 --> 00:45:39,330 apply that to four. 777 00:45:39,330 --> 00:45:42,780 778 00:45:42,780 --> 00:45:44,410 Well let's see. 779 00:45:44,410 --> 00:45:49,450 Eval of a lambda expression produces a procedure object. 780 00:45:49,450 --> 00:45:52,030 781 00:45:52,030 --> 00:46:04,530 So this is apply, of apply, of the procedure object closure, 782 00:46:04,530 --> 00:46:09,420 which contains the body of the procedure, x, which is 783 00:46:09,420 --> 00:46:12,130 lambda-- which binds x [UNINTELLIGIBLE] 784 00:46:12,130 --> 00:46:17,230 the internals of the body, it returns the procedure of one 785 00:46:17,230 --> 00:46:20,630 argument y, which adds x to y. 786 00:46:20,630 --> 00:46:23,210 787 00:46:23,210 --> 00:46:27,930 Environment e0 is now captured in it, because this was 788 00:46:27,930 --> 00:46:30,340 evaluated with respect to e0. 789 00:46:30,340 --> 00:46:33,040 e0 is part now of the closure object. 790 00:46:33,040 --> 00:46:40,050 Apply that to open, three, close, apply, to open, 4, 791 00:46:40,050 --> 00:46:41,300 close, apply. 792 00:46:41,300 --> 00:46:47,390 793 00:46:47,390 --> 00:46:50,220 So going from this step to this step meant that I made up 794 00:46:50,220 --> 00:46:55,060 a procedure object which captured in it e0 as part of 795 00:46:55,060 --> 00:46:57,150 the procedure object. 796 00:46:57,150 --> 00:46:58,620 Now, we're going to pass those to apply. 797 00:46:58,620 --> 00:47:00,480 We have to apply this procedure 798 00:47:00,480 --> 00:47:02,710 to that set of arguments. 799 00:47:02,710 --> 00:47:07,380 Well, but that procedure is not primitive. 800 00:47:07,380 --> 00:47:10,500 It's, in fact, a thing which has got the tag closure, and, 801 00:47:10,500 --> 00:47:13,710 therefore, what we have to do is do a bind. 802 00:47:13,710 --> 00:47:15,830 We have to bind. 803 00:47:15,830 --> 00:47:21,850 A new environment is made at this point, which has as its 804 00:47:21,850 --> 00:47:26,980 parent environment the one over here, e0, that 805 00:47:26,980 --> 00:47:28,230 environment. 806 00:47:28,230 --> 00:47:30,320 807 00:47:30,320 --> 00:47:31,570 And we'll call this one, e1. 808 00:47:31,570 --> 00:47:34,620 809 00:47:34,620 --> 00:47:36,040 Now what's bound in there? 810 00:47:36,040 --> 00:47:38,620 x is bound to three. 811 00:47:38,620 --> 00:47:41,480 So I have x equal three. 812 00:47:41,480 --> 00:47:42,730 That's what's in there. 813 00:47:42,730 --> 00:47:44,940 814 00:47:44,940 --> 00:47:46,240 And we'll call that e1. 815 00:47:46,240 --> 00:47:51,940 So what this transforms into is an eval of the body of 816 00:47:51,940 --> 00:47:56,740 this, which is this, the body of that procedure, in the 817 00:47:56,740 --> 00:48:00,290 environment that you just saw. 818 00:48:00,290 --> 00:48:11,480 So that's an apply, of eval, quote, open, lambda of y, plus 819 00:48:11,480 --> 00:48:12,750 x y-- the body-- 820 00:48:12,750 --> 00:48:15,270 821 00:48:15,270 --> 00:48:16,520 in e1. 822 00:48:16,520 --> 00:48:20,660 823 00:48:20,660 --> 00:48:26,040 And apply the result of that to four, open, close, 4-- 824 00:48:26,040 --> 00:48:28,680 list of arguments. 825 00:48:28,680 --> 00:48:31,600 Well, that's sensible enough because evaluating a lambda, I 826 00:48:31,600 --> 00:48:33,110 know what to do. 827 00:48:33,110 --> 00:48:43,680 That means I apply, the procedure which is closure, 828 00:48:43,680 --> 00:48:52,150 binds one argument y, adds x to y, with e1 captured in it. 829 00:48:52,150 --> 00:48:55,790 830 00:48:55,790 --> 00:48:57,800 And you should really see this. 831 00:48:57,800 --> 00:49:00,140 I somehow manufactured a closure. 832 00:49:00,140 --> 00:49:01,790 I should've put this here. 833 00:49:01,790 --> 00:49:03,040 There was one over here too. 834 00:49:03,040 --> 00:49:06,230 835 00:49:06,230 --> 00:49:08,080 Well, there's one here now. 836 00:49:08,080 --> 00:49:13,710 I've captured e1, and this is the procedure of one argument 837 00:49:13,710 --> 00:49:17,880 y, whatever this is. 838 00:49:17,880 --> 00:49:20,435 That's what that is there, that closure. 839 00:49:20,435 --> 00:49:23,040 840 00:49:23,040 --> 00:49:26,230 I'm going to apply that to four. 841 00:49:26,230 --> 00:49:30,690 842 00:49:30,690 --> 00:49:31,940 Well, that's easy enough. 843 00:49:31,940 --> 00:49:36,830 844 00:49:36,830 --> 00:49:39,720 That means I have to make a new environment by copying 845 00:49:39,720 --> 00:49:45,030 this pointer, which was the pointer of the procedure, 846 00:49:45,030 --> 00:49:49,540 which binds y equal 4 with that environment. 847 00:49:49,540 --> 00:49:52,460 And here's my new environment, which I'll call e2. 848 00:49:52,460 --> 00:49:55,870 849 00:49:55,870 --> 00:49:58,990 And, of course, this application then is evaluate 850 00:49:58,990 --> 00:50:01,910 the body in e2. 851 00:50:01,910 --> 00:50:10,830 So this is eval, the body, which is plus x y, in the 852 00:50:10,830 --> 00:50:13,710 environment e2. 853 00:50:13,710 --> 00:50:22,220 But this is an application, so this is the apply, of eval, 854 00:50:22,220 --> 00:50:37,340 plus in e2, an EVLIST, quote, open, x y, in e2. 855 00:50:37,340 --> 00:50:44,880 856 00:50:44,880 --> 00:50:45,590 Well, but let's see. 857 00:50:45,590 --> 00:50:52,480 That is apply, the object which is a 858 00:50:52,480 --> 00:50:54,190 result of that and plus. 859 00:50:54,190 --> 00:50:57,920 So here we are in e2, plus is not here, it's not here, oh, 860 00:50:57,920 --> 00:51:01,780 yes, but's here as some primitive operator. 861 00:51:01,780 --> 00:51:04,745 So it's the primitive operator for addition. 862 00:51:04,745 --> 00:51:08,490 863 00:51:08,490 --> 00:51:14,370 Apply that to the result of evaluating x and y in e2. 864 00:51:14,370 --> 00:51:18,340 But we can see that x is three and y is four. 865 00:51:18,340 --> 00:51:23,936 So that's a three and four, here. 866 00:51:23,936 --> 00:51:26,280 And that magically produces for me a seven. 867 00:51:26,280 --> 00:51:30,520 868 00:51:30,520 --> 00:51:33,460 I wanted to go through this so you would see, essentially, 869 00:51:33,460 --> 00:51:36,960 one important ingredient, which is what's being passed 870 00:51:36,960 --> 00:51:40,470 around, and who owns what, and what his job is. 871 00:51:40,470 --> 00:51:41,700 So what do we have here? 872 00:51:41,700 --> 00:51:46,520 We have eval, and we have apply, the two main players. 873 00:51:46,520 --> 00:51:49,370 874 00:51:49,370 --> 00:51:52,320 And there is a big loop the goes around like this. 875 00:51:52,320 --> 00:52:00,780 Which is eval produces a procedure and 876 00:52:00,780 --> 00:52:06,270 arguments for apply. 877 00:52:06,270 --> 00:52:09,710 Now some things eval could do by itself. 878 00:52:09,710 --> 00:52:10,860 Those are little self things here. 879 00:52:10,860 --> 00:52:12,700 They're not interesting. 880 00:52:12,700 --> 00:52:16,240 Also eval evaluates all of the arguments, one after another. 881 00:52:16,240 --> 00:52:17,650 That's not very interesting. 882 00:52:17,650 --> 00:52:21,540 Apply can apply some procedures like plus, not very 883 00:52:21,540 --> 00:52:22,300 interesting. 884 00:52:22,300 --> 00:52:25,520 However, if apply can't apply a procedure like plus, it 885 00:52:25,520 --> 00:52:32,880 produces an expression and environment for eval. 886 00:52:32,880 --> 00:52:35,470 887 00:52:35,470 --> 00:52:39,770 The procedural arguments wrap up essentially the state of a 888 00:52:39,770 --> 00:52:43,740 computation and, certainly, the expression of environment. 889 00:52:43,740 --> 00:52:45,600 And so what we're actually going to do next is not the 890 00:52:45,600 --> 00:52:47,570 complete state, because it doesn't say 891 00:52:47,570 --> 00:52:48,820 who wants the answers. 892 00:52:48,820 --> 00:52:51,280 893 00:52:51,280 --> 00:52:53,500 But what we're going to do-- it's always got something like 894 00:52:53,500 --> 00:52:56,580 an expression of environment or procedure and arguments as 895 00:52:56,580 --> 00:52:58,970 the main loop that we're going around. 896 00:52:58,970 --> 00:53:01,500 There are minor little sub loops like eval through 897 00:53:01,500 --> 00:53:11,030 EVLIST, or eval through evcond, or apply through a 898 00:53:11,030 --> 00:53:12,280 primitive apply. 899 00:53:12,280 --> 00:53:16,140 900 00:53:16,140 --> 00:53:18,500 But they're not the essential things. 901 00:53:18,500 --> 00:53:21,860 So that's what I wanted you to see. 902 00:53:21,860 --> 00:53:23,110 Are there any questions? 903 00:53:23,110 --> 00:53:25,930 904 00:53:25,930 --> 00:53:28,690 Yes. 905 00:53:28,690 --> 00:53:32,670 AUDIENCE: I'm trying to understand how x got down to 906 00:53:32,670 --> 00:53:37,070 three instead of four. 907 00:53:37,070 --> 00:53:38,540 At the early part of the-- 908 00:53:38,540 --> 00:53:41,310 PROFESSOR: Here. 909 00:53:41,310 --> 00:53:43,310 You want to know how x got down to three? 910 00:53:43,310 --> 00:53:49,770 AUDIENCE: Because x is the outer procedure, and x and y 911 00:53:49,770 --> 00:53:51,040 are the inner procedure. 912 00:53:51,040 --> 00:53:52,570 PROFESSOR: Fine. 913 00:53:52,570 --> 00:53:55,280 Well, I was very careful and mechanical. 914 00:53:55,280 --> 00:53:57,350 First of all, I should write those procedures again for 915 00:53:57,350 --> 00:54:00,610 you, pretty printed. 916 00:54:00,610 --> 00:54:02,260 First order of business, because you're probably not 917 00:54:02,260 --> 00:54:03,830 reading them well. 918 00:54:03,830 --> 00:54:08,500 So I have here that procedure of-- 919 00:54:08,500 --> 00:54:11,280 was it x over there-- 920 00:54:11,280 --> 00:54:12,690 which is-- 921 00:54:12,690 --> 00:54:20,710 value of that procedure of y, which adds x to y, lambda, 922 00:54:20,710 --> 00:54:25,380 lambda, applied that to three, takes the result of that, and 923 00:54:25,380 --> 00:54:26,140 applied that to four. 924 00:54:26,140 --> 00:54:28,810 Is that not what I wrote? 925 00:54:28,810 --> 00:54:34,170 Now, you should immediately see that here is an 926 00:54:34,170 --> 00:54:35,150 application-- 927 00:54:35,150 --> 00:54:37,400 let me get a white piece of chalk-- 928 00:54:37,400 --> 00:54:40,735 here is an application, a combination. 929 00:54:40,735 --> 00:54:44,300 930 00:54:44,300 --> 00:54:48,270 That combination has this as the operator 931 00:54:48,270 --> 00:54:51,040 and this as the operand. 932 00:54:51,040 --> 00:54:54,900 The three is going in for the x here. 933 00:54:54,900 --> 00:54:58,720 The result of this is a procedure of one argument y, 934 00:54:58,720 --> 00:55:01,530 which gets applied to four. 935 00:55:01,530 --> 00:55:04,190 So you just weren't reading the expression right. 936 00:55:04,190 --> 00:55:11,580 The way you see that over here is that here I have the actual 937 00:55:11,580 --> 00:55:13,340 procedure object, x. 938 00:55:13,340 --> 00:55:18,980 It's getting applied to three, the list containing three. 939 00:55:18,980 --> 00:55:20,350 What I'm left over with is something which 940 00:55:20,350 --> 00:55:24,080 gets applied to four. 941 00:55:24,080 --> 00:55:25,330 Are there any other questions? 942 00:55:25,330 --> 00:55:28,600 943 00:55:28,600 --> 00:55:30,900 Time for our next small break then. 944 00:55:30,900 --> 00:55:33,735 Thank you. 945 00:55:33,735 --> 00:56:08,410 [MUSIC PLAYING] 946 00:56:08,410 --> 00:56:14,730 Let's see, at this point, you should be getting the feeling, 947 00:56:14,730 --> 00:56:16,630 what's this nonsense this Sussman 948 00:56:16,630 --> 00:56:17,960 character is feeding me? 949 00:56:17,960 --> 00:56:20,740 950 00:56:20,740 --> 00:56:24,800 There's an awful lot of strange nonsense here. 951 00:56:24,800 --> 00:56:28,300 After all, he purported to explain to me Lisp, and he 952 00:56:28,300 --> 00:56:30,892 wrote me a Lisp program on the blackboard. 953 00:56:30,892 --> 00:56:33,560 The Lisp program was intended to be interpreted for Lisp, 954 00:56:33,560 --> 00:56:35,280 but you need a Lisp interpreter in order to 955 00:56:35,280 --> 00:56:38,370 understand that program. 956 00:56:38,370 --> 00:56:41,160 How could that program have told me anything there is to 957 00:56:41,160 --> 00:56:44,150 be known about Lisp? 958 00:56:44,150 --> 00:56:45,795 How is that not completely vacuous? 959 00:56:45,795 --> 00:56:48,490 960 00:56:48,490 --> 00:56:50,990 It's a very strange thing. 961 00:56:50,990 --> 00:56:52,430 Does it tell me anything at all? 962 00:56:52,430 --> 00:56:56,070 963 00:56:56,070 --> 00:56:59,230 Well, you see, the whole thing is sort of like these Escher's 964 00:56:59,230 --> 00:57:03,105 hands that we see on this slide. 965 00:57:03,105 --> 00:57:06,180 966 00:57:06,180 --> 00:57:11,750 Yes, eval and apply each sort of draw each other and 967 00:57:11,750 --> 00:57:15,690 construct the real thing, which can sit 968 00:57:15,690 --> 00:57:17,110 out and draw itself. 969 00:57:17,110 --> 00:57:19,300 Escher was a very brilliant man, he just didn't know the 970 00:57:19,300 --> 00:57:20,550 names of these spirits. 971 00:57:20,550 --> 00:57:23,910 972 00:57:23,910 --> 00:57:27,700 Well, I'm going to do now, is I'm going to try to convince 973 00:57:27,700 --> 00:57:33,060 you that both this mean something, and, as a aside, 974 00:57:33,060 --> 00:57:36,090 I'm going to show you why you don't need definitions. 975 00:57:36,090 --> 00:57:38,760 Just turns out that that sort of falls out, why definitions 976 00:57:38,760 --> 00:57:42,990 are not essential in a mathematical sense for doing 977 00:57:42,990 --> 00:57:44,890 all the things we need to do for computing. 978 00:57:44,890 --> 00:57:49,070 979 00:57:49,070 --> 00:57:50,690 Well, let's see here. 980 00:57:50,690 --> 00:57:54,870 Consider the following small program, what does it mean? 981 00:57:54,870 --> 00:57:57,035 This is a program for computing exponentials. 982 00:57:57,035 --> 00:58:07,270 983 00:58:07,270 --> 00:58:13,350 The exponential of x to the nth power is if-- 984 00:58:13,350 --> 00:58:16,910 985 00:58:16,910 --> 00:58:22,070 and is zero, then the result is one. 986 00:58:22,070 --> 00:58:29,520 Otherwise, I want the product of x and the result of 987 00:58:29,520 --> 00:58:33,930 exponentiating x to the n minus one power. 988 00:58:33,930 --> 00:58:42,858 989 00:58:42,858 --> 00:58:46,630 I think I got it right. 990 00:58:46,630 --> 00:58:49,470 Now this is a recursive definition. 991 00:58:49,470 --> 00:58:53,930 It's a definition of the exponentiation procedure in 992 00:58:53,930 --> 00:58:56,410 terms of itself. 993 00:58:56,410 --> 00:59:00,710 And, as it has been mentioned before, your high school 994 00:59:00,710 --> 00:59:03,010 geometry teacher probably gave you a hard time 995 00:59:03,010 --> 00:59:05,650 about things like that. 996 00:59:05,650 --> 00:59:07,910 Was that justified? 997 00:59:07,910 --> 00:59:13,430 Why does this self referential definition make any sense? 998 00:59:13,430 --> 00:59:15,060 Well, first of all, I'm going to convince you that your high 999 00:59:15,060 --> 00:59:17,600 school geometry teacher was I telling you nonsense. 1000 00:59:17,600 --> 00:59:20,370 1001 00:59:20,370 --> 00:59:24,490 Consider the following set of definitions here. 1002 00:59:24,490 --> 00:59:33,070 x plus y equals three, and x minus y equal one. 1003 00:59:33,070 --> 00:59:36,170 Well, gee, this tells you x in terms of y, and this one tells 1004 00:59:36,170 --> 00:59:37,490 you y in terms of x, presumably. 1005 00:59:37,490 --> 00:59:40,150 1006 00:59:40,150 --> 00:59:42,950 And yet this happens to have a unique solution in x and y. 1007 00:59:42,950 --> 00:59:55,910 1008 00:59:55,910 --> 01:00:06,600 However, I could also write two x plus two y is six. 1009 01:00:06,600 --> 01:00:09,610 These two equations have an infinite number solutions. 1010 01:00:09,610 --> 01:00:15,730 1011 01:00:15,730 --> 01:00:21,520 And I could write you, for example, x minus y equal 2, 1012 01:00:21,520 --> 01:00:24,070 and these two equations have no solutions. 1013 01:00:24,070 --> 01:00:29,820 1014 01:00:29,820 --> 01:00:32,350 Well, I have here three sets of simultaneous linear 1015 01:00:32,350 --> 01:00:39,510 equations, this set, this set, and this set. 1016 01:00:39,510 --> 01:00:42,900 But they have different numbers of solutions. 1017 01:00:42,900 --> 01:00:45,760 The number of solutions is not in the form of the equations. 1018 01:00:45,760 --> 01:00:48,350 They all three sets have the same form. 1019 01:00:48,350 --> 01:00:50,205 The number of solutions is in the content. 1020 01:00:50,205 --> 01:00:53,000 1021 01:00:53,000 --> 01:00:55,510 I can't tell by looking at the form of a definition whether 1022 01:00:55,510 --> 01:00:59,660 it makes sense, only by its detailed content. 1023 01:00:59,660 --> 01:01:02,170 What are the coefficients, for example, in the 1024 01:01:02,170 --> 01:01:05,100 case of linear equations? 1025 01:01:05,100 --> 01:01:07,440 So I shouldn't expect to be able to tell looking at 1026 01:01:07,440 --> 01:01:11,500 something like this, from some simple things like, oh yes, 1027 01:01:11,500 --> 01:01:16,030 EXPT is the solution of this recursion equation. 1028 01:01:16,030 --> 01:01:22,110 Expt is the procedure which if substituted in here, 1029 01:01:22,110 --> 01:01:26,040 gives me EXPT back. 1030 01:01:26,040 --> 01:01:30,750 I can't tell, looking at this form, whether or not there's a 1031 01:01:30,750 --> 01:01:33,970 single, unique solution for EXPT, an infinite number of 1032 01:01:33,970 --> 01:01:37,200 solutions, or no solutions. 1033 01:01:37,200 --> 01:01:38,930 It's got to be how it counts and things 1034 01:01:38,930 --> 01:01:40,490 like that, the details. 1035 01:01:40,490 --> 01:01:42,900 And it's harder in programming than linear algebra. 1036 01:01:42,900 --> 01:01:45,210 There aren't too many theorems about it in programming. 1037 01:01:45,210 --> 01:01:48,450 1038 01:01:48,450 --> 01:01:50,990 Well, I want to rewrite these equations a little 1039 01:01:50,990 --> 01:01:53,970 bit, these over here. 1040 01:01:53,970 --> 01:01:55,560 Because what we're investigating is 1041 01:01:55,560 --> 01:01:56,770 equations like this. 1042 01:01:56,770 --> 01:01:58,820 But I want to play a little with equations like this that 1043 01:01:58,820 --> 01:02:02,050 we understand, just so we get some insight into 1044 01:02:02,050 --> 01:02:04,730 this kind of question. 1045 01:02:04,730 --> 01:02:07,870 We could rewrite our equations here, say these two, the ones 1046 01:02:07,870 --> 01:02:17,070 that are interesting, as x equals three minus y, and y 1047 01:02:17,070 --> 01:02:19,380 equals x minus one. 1048 01:02:19,380 --> 01:02:22,010 1049 01:02:22,010 --> 01:02:24,050 What do we call this transformation? 1050 01:02:24,050 --> 01:02:26,095 This is a linear transformation, t. 1051 01:02:26,095 --> 01:02:29,430 1052 01:02:29,430 --> 01:02:35,390 Then what we're getting here is an equation x y 1053 01:02:35,390 --> 01:02:37,370 equals t of x y. 1054 01:02:37,370 --> 01:02:42,990 1055 01:02:42,990 --> 01:02:44,560 What am I looking for? 1056 01:02:44,560 --> 01:02:47,040 I'm looking for a fixed point of t. 1057 01:02:47,040 --> 01:02:59,350 The solution is a fixed point of t. 1058 01:02:59,350 --> 01:03:01,910 1059 01:03:01,910 --> 01:03:04,830 So the methods we should have for looking for solutions to 1060 01:03:04,830 --> 01:03:09,230 equations, if I can do it by fixed points, might be 1061 01:03:09,230 --> 01:03:10,880 applicable. 1062 01:03:10,880 --> 01:03:13,710 If I have a means of finding a solution to an equations by 1063 01:03:13,710 --> 01:03:15,690 fixed points-- 1064 01:03:15,690 --> 01:03:18,620 just, might not work-- 1065 01:03:18,620 --> 01:03:21,160 but it might be applicable to investigating solutions of 1066 01:03:21,160 --> 01:03:22,410 equations like this. 1067 01:03:22,410 --> 01:03:27,240 1068 01:03:27,240 --> 01:03:30,260 But what I want you to feel is that this is an equation. 1069 01:03:30,260 --> 01:03:32,930 It's an expression with several instances of various 1070 01:03:32,930 --> 01:03:39,020 names which puts a constraint on the name, saying what that 1071 01:03:39,020 --> 01:03:42,770 name could have as its value, rather than some sort of 1072 01:03:42,770 --> 01:03:45,010 mechanical process of substitution right now. 1073 01:03:45,010 --> 01:03:47,740 1074 01:03:47,740 --> 01:03:51,220 This is an equation which I'm going to try to solve. 1075 01:03:51,220 --> 01:03:53,960 Well, let's play around and solve it. 1076 01:03:53,960 --> 01:03:57,800 First of all, I want to write down the function which 1077 01:03:57,800 --> 01:04:00,320 corresponds to t. 1078 01:04:00,320 --> 01:04:02,670 First I want to write down the function which corresponds to 1079 01:04:02,670 --> 01:04:06,960 t whose fixed point is the answer to this question. 1080 01:04:06,960 --> 01:04:11,950 1081 01:04:11,950 --> 01:04:14,240 Well, let's consider the following procedure f. 1082 01:04:14,240 --> 01:04:16,870 1083 01:04:16,870 --> 01:04:19,340 I claim it computes that function. 1084 01:04:19,340 --> 01:04:26,860 f is that procedure of one argument g, which is that 1085 01:04:26,860 --> 01:04:33,430 procedure of two arguments x and n. 1086 01:04:33,430 --> 01:04:42,410 Which have the property that if n is zero, then the result 1087 01:04:42,410 --> 01:04:56,050 is one, otherwise, the result is the product of x and g, 1088 01:04:56,050 --> 01:05:00,690 applied to x, and minus n1. 1089 01:05:00,690 --> 01:05:03,370 1090 01:05:03,370 --> 01:05:07,900 g, times, else, COND, lambda, lambda-- 1091 01:05:07,900 --> 01:05:11,900 1092 01:05:11,900 --> 01:05:17,230 Here f is a procedure, which if I had a solution to that 1093 01:05:17,230 --> 01:05:23,640 equation, if I had a good exponentiation procedure, and 1094 01:05:23,640 --> 01:05:29,500 I applied f to that procedure, then the result would be a 1095 01:05:29,500 --> 01:05:30,930 good exponentiation procedure. 1096 01:05:30,930 --> 01:05:37,460 1097 01:05:37,460 --> 01:05:39,420 Because, what does it do? 1098 01:05:39,420 --> 01:05:44,200 Well, all it is is exposing g were a good exponentiation 1099 01:05:44,200 --> 01:05:48,010 procedure, well then this would produce, as its value, a 1100 01:05:48,010 --> 01:05:51,650 procedure to arguments x and n, such that if n were 0, the 1101 01:05:51,650 --> 01:05:53,360 result would be one, which is certainly true of 1102 01:05:53,360 --> 01:05:54,670 exponentiation. 1103 01:05:54,670 --> 01:05:57,730 Otherwise, it will be the result of multiplying x by the 1104 01:05:57,730 --> 01:06:01,750 exponentiation procedure given to me with x and n minus one 1105 01:06:01,750 --> 01:06:03,470 as arguments. 1106 01:06:03,470 --> 01:06:05,680 So if this computed the correct exponentiation for n 1107 01:06:05,680 --> 01:06:10,500 minus one, then this would be the correct exponentiation for 1108 01:06:10,500 --> 01:06:13,370 exponent n, so this would have been the right 1109 01:06:13,370 --> 01:06:14,620 exponentiation procedure. 1110 01:06:14,620 --> 01:06:17,500 1111 01:06:17,500 --> 01:06:26,560 So what I really want to say here is E-X-P-T is a fixed 1112 01:06:26,560 --> 01:06:32,320 point of f. 1113 01:06:32,320 --> 01:06:37,550 1114 01:06:37,550 --> 01:06:40,060 Now our problem is there might be more than one fixed point. 1115 01:06:40,060 --> 01:06:43,270 There might be no fixed points. 1116 01:06:43,270 --> 01:06:44,810 I have to go hunting for the fixed points. 1117 01:06:44,810 --> 01:06:48,290 1118 01:06:48,290 --> 01:06:49,540 Got to solve this equation. 1119 01:06:49,540 --> 01:06:52,160 1120 01:06:52,160 --> 01:06:55,580 Well there are various ways to hunt for fixed points. 1121 01:06:55,580 --> 01:06:58,080 Of course, the one we played with at the beginning of this 1122 01:06:58,080 --> 01:07:00,815 term worked for cosine. 1123 01:07:00,815 --> 01:07:06,080 1124 01:07:06,080 --> 01:07:09,235 Go into radians mode on your calculator and push cosine, 1125 01:07:09,235 --> 01:07:12,990 and just keep doing it, and you get to some number which 1126 01:07:12,990 --> 01:07:16,090 is about 0.73 or 0.74. 1127 01:07:16,090 --> 01:07:17,340 I can't remember which. 1128 01:07:17,340 --> 01:07:22,900 1129 01:07:22,900 --> 01:07:27,170 By iterating a function, whose fixed point I'm searching for, 1130 01:07:27,170 --> 01:07:32,090 it is sometimes the case that that function will converge in 1131 01:07:32,090 --> 01:07:33,770 producing the fixed point. 1132 01:07:33,770 --> 01:07:39,910 I think we luck out in this case, so let's look for it. 1133 01:07:39,910 --> 01:07:48,030 Let's look at this slide. 1134 01:07:48,030 --> 01:07:51,390 Consider the following sequence of procedures. 1135 01:07:51,390 --> 01:07:56,400 1136 01:07:56,400 --> 01:08:02,940 e0 over here is the procedure which does nothing at all. 1137 01:08:02,940 --> 01:08:05,390 It's the procedure which produces an error for any 1138 01:08:05,390 --> 01:08:07,780 arguments you give it. 1139 01:08:07,780 --> 01:08:09,030 It's basically useless. 1140 01:08:09,030 --> 01:08:14,480 1141 01:08:14,480 --> 01:08:20,080 Well, however, I can make an approximation. 1142 01:08:20,080 --> 01:08:22,930 Let's consider it the worst possible approximation to 1143 01:08:22,930 --> 01:08:26,990 exponentiation, because it does nothing. 1144 01:08:26,990 --> 01:08:34,170 Well, supposing I substituted e0 for g by calling f, as you 1145 01:08:34,170 --> 01:08:37,380 see over here on e0. 1146 01:08:37,380 --> 01:08:40,729 So you see over here, have e0 there. 1147 01:08:40,729 --> 01:08:43,859 Then gee, what's e1? 1148 01:08:43,859 --> 01:08:47,189 e1 is a procedure which exponentiate things to the 0th 1149 01:08:47,189 --> 01:08:49,325 power, with no trouble. 1150 01:08:49,325 --> 01:08:52,420 It gets the right answer, anything to the zero is one, 1151 01:08:52,420 --> 01:08:54,250 and it makes an error on anything else. 1152 01:08:54,250 --> 01:08:57,390 1153 01:08:57,390 --> 01:09:06,040 Well, now what if I take e1 and I substitute if for g by 1154 01:09:06,040 --> 01:09:07,310 calling f on e1? 1155 01:09:07,310 --> 01:09:10,500 1156 01:09:10,500 --> 01:09:15,670 Oh gosh, I have here a procedure of two arguments. 1157 01:09:15,670 --> 01:09:18,250 Now remember e1 was appropriate for taking 1158 01:09:18,250 --> 01:09:24,200 exponentiations of 0, for raising to the 0 exponent. 1159 01:09:24,200 --> 01:09:27,910 So here, is n is 0, the result is one, so this guy is good 1160 01:09:27,910 --> 01:09:29,520 for that too. 1161 01:09:29,520 --> 01:09:32,479 However, I can use something for raising to the 0th power 1162 01:09:32,479 --> 01:09:35,979 to multiply it by x to raise something to the first power. 1163 01:09:35,979 --> 01:09:39,670 So e2 is good for both power 0 and one. 1164 01:09:39,670 --> 01:09:43,800 1165 01:09:43,800 --> 01:09:47,899 And e3 is constructed from e2 in the same way. 1166 01:09:47,899 --> 01:09:52,240 And e3, of course, by the same argument is good for powers 0, 1167 01:09:52,240 --> 01:09:55,120 one, and two. 1168 01:09:55,120 --> 01:10:00,140 And so I will assert for you, without proof, because the 1169 01:10:00,140 --> 01:10:02,520 proof is horribly difficult. 1170 01:10:02,520 --> 01:10:04,050 And that's the sort of thing that people called 1171 01:10:04,050 --> 01:10:07,710 denotational semanticists do. 1172 01:10:07,710 --> 01:10:10,265 This great idea was invented by Scott and Strachey. 1173 01:10:10,265 --> 01:10:14,240 1174 01:10:14,240 --> 01:10:17,110 They're very famous mathematician types who 1175 01:10:17,110 --> 01:10:21,030 invented the interpretation for these programs that we 1176 01:10:21,030 --> 01:10:24,240 have that I'm talking to you about right now. 1177 01:10:24,240 --> 01:10:28,950 And they proved, by topology that there is such a fixed 1178 01:10:28,950 --> 01:10:32,220 point in the cases that we want. 1179 01:10:32,220 --> 01:10:41,180 But the assertion is E-X-P-T is limit as n goes 1180 01:10:41,180 --> 01:10:43,680 to infinity of em. 1181 01:10:43,680 --> 01:10:47,900 and And that we've constructed this by the following way. 1182 01:10:47,900 --> 01:10:50,520 1183 01:10:50,520 --> 01:10:57,530 --is Well, it's f of, f of, f of, f of, f of-- 1184 01:10:57,530 --> 01:11:01,120 f applied to anything at all. 1185 01:11:01,120 --> 01:11:04,070 It didn't matter what that was, because, in fact, this 1186 01:11:04,070 --> 01:11:05,320 always produces an error. 1187 01:11:05,320 --> 01:11:07,540 1188 01:11:07,540 --> 01:11:08,790 Applied to this-- 1189 01:11:08,790 --> 01:11:12,840 1190 01:11:12,840 --> 01:11:16,380 That's by infinite nesting of f's. 1191 01:11:16,380 --> 01:11:19,760 So now my problem is to make some infinite things. 1192 01:11:19,760 --> 01:11:22,590 1193 01:11:22,590 --> 01:11:24,920 We need some infinite things. 1194 01:11:24,920 --> 01:11:28,980 How am I going to nest up an f an infinite number of times? 1195 01:11:28,980 --> 01:11:32,380 I'd better construct this. 1196 01:11:32,380 --> 01:11:32,930 Well, I don't know. 1197 01:11:32,930 --> 01:11:34,810 How would I make an infinite loop at all? 1198 01:11:34,810 --> 01:11:37,090 Let's take a very simple infinite loop, the simplest 1199 01:11:37,090 --> 01:11:38,340 infinite loop imaginable. 1200 01:11:38,340 --> 01:11:43,550 1201 01:11:43,550 --> 01:11:48,070 If I were to take that procedure of one argument x 1202 01:11:48,070 --> 01:11:57,580 which applies x to x and apply that to the procedure of one 1203 01:11:57,580 --> 01:12:05,320 argument x which applies x to x, then this 1204 01:12:05,320 --> 01:12:07,440 is an infinite loop. 1205 01:12:07,440 --> 01:12:09,980 The reason why this is an infinite loop is as follows. 1206 01:12:09,980 --> 01:12:14,390 The way I understand this is I substitute the argument for 1207 01:12:14,390 --> 01:12:18,850 the formal parameter in the body. 1208 01:12:18,850 --> 01:12:22,590 But if I do that, I take for each of these x's, I 1209 01:12:22,590 --> 01:12:25,740 substitute one of these, making a copy of the original 1210 01:12:25,740 --> 01:12:28,410 expression I just started with, the 1211 01:12:28,410 --> 01:12:29,660 simplest infinite loop. 1212 01:12:29,660 --> 01:12:35,440 1213 01:12:35,440 --> 01:12:40,750 Now I want to tell you about a particular operator which is 1214 01:12:40,750 --> 01:12:43,090 constructed by a perturbation from this infinite loop. 1215 01:12:43,090 --> 01:12:47,040 1216 01:12:47,040 --> 01:12:48,290 I'll call it y. 1217 01:12:48,290 --> 01:12:52,290 1218 01:12:52,290 --> 01:12:56,680 This is called Curry's Paradoxical Combinator of y 1219 01:12:56,680 --> 01:13:00,510 after a fellow by the name of Curry, who was a logician of 1220 01:13:00,510 --> 01:13:04,480 the 1930s also. 1221 01:13:04,480 --> 01:13:08,670 And if I have a procedure of one argument f, what's it 1222 01:13:08,670 --> 01:13:09,330 going to have in it? 1223 01:13:09,330 --> 01:13:13,420 It's going to have a kind of infinite loop in it, which is 1224 01:13:13,420 --> 01:13:21,670 that procedure of one argument x which applies f to x of x, 1225 01:13:21,670 --> 01:13:25,820 applied to that procedure of one argument x, which applies 1226 01:13:25,820 --> 01:13:27,899 f to f of x. 1227 01:13:27,899 --> 01:13:32,300 1228 01:13:32,300 --> 01:13:34,590 Now what's this do? 1229 01:13:34,590 --> 01:13:42,950 Suppose we apply y to F. Well, that's easy enough. 1230 01:13:42,950 --> 01:13:46,910 That's this capital F over here. 1231 01:13:46,910 --> 01:13:48,670 Well, the easiest thing to say there is, I 1232 01:13:48,670 --> 01:13:49,920 substitute F for here. 1233 01:13:49,920 --> 01:13:55,320 1234 01:13:55,320 --> 01:13:58,460 So that's going to give me, basically-- 1235 01:13:58,460 --> 01:14:02,800 because then I'm going to substitute this for x in here. 1236 01:14:02,800 --> 01:14:08,970 1237 01:14:08,970 --> 01:14:10,810 Let me actually do it in steps, so you can see it 1238 01:14:10,810 --> 01:14:11,730 completely. 1239 01:14:11,730 --> 01:14:15,020 I'm going to be very careful. 1240 01:14:15,020 --> 01:14:27,510 This is open, open, lambda of x , capital F, x, x, applied 1241 01:14:27,510 --> 01:14:37,910 to itself, F of x of x. 1242 01:14:37,910 --> 01:14:45,600 Substituting this for this in here, this is F applied to-- 1243 01:14:45,600 --> 01:14:47,040 what is it-- 1244 01:14:47,040 --> 01:14:53,850 substituting this in here, open, open, lambda of x, F, of 1245 01:14:53,850 --> 01:15:08,910 x and x, applied to lambda of x, F of x of x, F, lambda, 1246 01:15:08,910 --> 01:15:11,510 pair, F. 1247 01:15:11,510 --> 01:15:13,420 Oh, but what is this? 1248 01:15:13,420 --> 01:15:17,490 This thing over here that I just computed, is 1249 01:15:17,490 --> 01:15:20,030 this thing over here. 1250 01:15:20,030 --> 01:15:23,370 But I just wrapped another F around it. 1251 01:15:23,370 --> 01:15:27,850 So by applying y to F, I make an infinite series of F's. 1252 01:15:27,850 --> 01:15:30,520 If I just let this run forever, I'll just keep making 1253 01:15:30,520 --> 01:15:33,170 more and more F's outside. 1254 01:15:33,170 --> 01:15:35,600 I ran an infinite loop which is useless, but it doesn't 1255 01:15:35,600 --> 01:15:36,855 matter that the inside is useless. 1256 01:15:36,855 --> 01:15:40,220 1257 01:15:40,220 --> 01:15:53,900 So y of F is F applied to y of F. So y is a magical thing 1258 01:15:53,900 --> 01:15:58,840 which, when applied to some function, produces the object 1259 01:15:58,840 --> 01:16:03,200 which is the fixed point of that function, if it exists, 1260 01:16:03,200 --> 01:16:04,450 and if this all works. 1261 01:16:04,450 --> 01:16:07,910 1262 01:16:07,910 --> 01:16:10,380 Because, indeed, if I take y of F and put it into F, I get 1263 01:16:10,380 --> 01:16:11,630 y of F out. 1264 01:16:11,630 --> 01:16:16,240 1265 01:16:16,240 --> 01:16:20,750 Now I want you to think this in terms of the eval-apply 1266 01:16:20,750 --> 01:16:23,860 interpreter for a bit. 1267 01:16:23,860 --> 01:16:28,540 I wrote down a whole bunch of recursion equations out there. 1268 01:16:28,540 --> 01:16:30,210 They're simultaneous in the same way these are 1269 01:16:30,210 --> 01:16:31,470 simultaneous equations. 1270 01:16:31,470 --> 01:16:33,310 Exponentiation was not a simultaneous equation. 1271 01:16:33,310 --> 01:16:38,150 It was only one variable I was looking for a meaning for. 1272 01:16:38,150 --> 01:16:41,210 But what Lisp is is the fixed point of the process which 1273 01:16:41,210 --> 01:16:44,740 says, if I knew what Lisp was and substituted it in for 1274 01:16:44,740 --> 01:16:47,780 eval, and apply, and so on, on the right hand sides of all 1275 01:16:47,780 --> 01:16:51,930 those recursion equations, then if it was a real good 1276 01:16:51,930 --> 01:16:55,340 Lisp, is a real one, then the left hand side 1277 01:16:55,340 --> 01:16:58,220 would also be Lisp. 1278 01:16:58,220 --> 01:16:59,565 So I made sense of that definition. 1279 01:16:59,565 --> 01:17:02,420 1280 01:17:02,420 --> 01:17:05,410 Now whether or not there's an answer isn't so obvious. 1281 01:17:05,410 --> 01:17:07,740 I can't attack that. 1282 01:17:07,740 --> 01:17:09,160 Now these arguments that I'm giving you 1283 01:17:09,160 --> 01:17:10,660 now are quite dangerous. 1284 01:17:10,660 --> 01:17:13,570 Let's look over here. 1285 01:17:13,570 --> 01:17:14,610 These are limit arguments. 1286 01:17:14,610 --> 01:17:17,020 We're talking about limits, and it's really calculus, or 1287 01:17:17,020 --> 01:17:21,255 topology, or something like that, a kind of analysis. 1288 01:17:21,255 --> 01:17:23,380 Now here's an argument that you all believe. 1289 01:17:23,380 --> 01:17:27,010 And I want to make sure you realize that I could be 1290 01:17:27,010 --> 01:17:29,660 bullshitting you. 1291 01:17:29,660 --> 01:17:30,910 What is this? 1292 01:17:30,910 --> 01:17:34,250 1293 01:17:34,250 --> 01:17:40,300 u is the sum of 1/2, 1/4, and 1/8, and so on, the sum of a 1294 01:17:40,300 --> 01:17:42,820 geometric series. 1295 01:17:42,820 --> 01:17:44,820 And, of course, I could play a game here. 1296 01:17:44,820 --> 01:17:47,570 u minus one is 1/2, plus 1/4, plus 1/8, and so on. 1297 01:17:47,570 --> 01:17:53,590 1298 01:17:53,590 --> 01:17:56,190 What I could do here-- 1299 01:17:56,190 --> 01:17:56,680 oops. 1300 01:17:56,680 --> 01:17:58,920 There is a parentheses error here. 1301 01:17:58,920 --> 01:18:02,740 But I can put here two times u minus one is one plus 1/2, 1302 01:18:02,740 --> 01:18:03,990 plus 1/4, plus 1/8. 1303 01:18:03,990 --> 01:18:07,570 1304 01:18:07,570 --> 01:18:08,820 Can I fix that? 1305 01:18:08,820 --> 01:18:14,010 1306 01:18:14,010 --> 01:18:16,125 Yes, well. 1307 01:18:16,125 --> 01:18:19,520 1308 01:18:19,520 --> 01:18:27,850 But that gives me back two times u minus one is u, 1309 01:18:27,850 --> 01:18:30,300 therefore, we conclude that u is two. 1310 01:18:30,300 --> 01:18:31,830 And this actually is true. 1311 01:18:31,830 --> 01:18:33,910 There's no problem like that. 1312 01:18:33,910 --> 01:18:38,540 But supposing I did something different. 1313 01:18:38,540 --> 01:18:39,740 Supposing I start up with something which 1314 01:18:39,740 --> 01:18:41,470 manifestly has no sum. 1315 01:18:41,470 --> 01:18:47,390 v is one, plus two, plus four, plus 8, plus dot, dot, dot. 1316 01:18:47,390 --> 01:18:49,560 Well, v minus one is surely two, plus four, plus eight, 1317 01:18:49,560 --> 01:18:52,010 plus dot, dot, dot. 1318 01:18:52,010 --> 01:18:57,410 v minus one over two, gee, that looks like v again. 1319 01:18:57,410 --> 01:19:01,070 From that I should be able to conclude that-- 1320 01:19:01,070 --> 01:19:03,070 that's also wrong, apparently. 1321 01:19:03,070 --> 01:19:04,510 v equals minus one. 1322 01:19:04,510 --> 01:19:12,455 1323 01:19:12,455 --> 01:19:15,280 That should be a minus one. 1324 01:19:15,280 --> 01:19:16,735 And that's certainly a false conclusion. 1325 01:19:16,735 --> 01:19:22,000 1326 01:19:22,000 --> 01:19:27,300 So when you play with limits, arguments that may work in one 1327 01:19:27,300 --> 01:19:30,750 case they may not work in some other case. 1328 01:19:30,750 --> 01:19:32,240 You have to be very careful. 1329 01:19:32,240 --> 01:19:35,752 The arguments have to be well formed. 1330 01:19:35,752 --> 01:19:40,790 And I don't know, in general, what the story is about 1331 01:19:40,790 --> 01:19:43,270 arguments like this. 1332 01:19:43,270 --> 01:19:46,060 We can read a pile of topology and find out. 1333 01:19:46,060 --> 01:19:49,750 But, surely, at least you understand now, why it might 1334 01:19:49,750 --> 01:19:52,230 be some meaning to the things we've been writing on the 1335 01:19:52,230 --> 01:19:53,260 blackboard. 1336 01:19:53,260 --> 01:19:56,480 And you understand what that might mean. 1337 01:19:56,480 --> 01:20:02,900 So, I suppose, it's almost about time for you to merit 1338 01:20:02,900 --> 01:20:05,720 being made a member of the grand recursive order of 1339 01:20:05,720 --> 01:20:09,320 lambda calculus hackers. 1340 01:20:09,320 --> 01:20:10,820 This is the badge. 1341 01:20:10,820 --> 01:20:14,540 Because you now understand, for example, what it says at 1342 01:20:14,540 --> 01:20:21,890 the very top, y F equals F y F. Thank you. 1343 01:20:21,890 --> 01:20:24,710 Are there any questions? 1344 01:20:24,710 --> 01:20:25,150 Yes, Lev. 1345 01:20:25,150 --> 01:20:28,250 AUDIENCE: With this, it seems that then there's no need to 1346 01:20:28,250 --> 01:20:31,330 define, as you imply, to just remember a 1347 01:20:31,330 --> 01:20:34,090 value, to apply it later. 1348 01:20:34,090 --> 01:20:35,850 Defines were kind of a side-effect it 1349 01:20:35,850 --> 01:20:36,490 seemed in the language. 1350 01:20:36,490 --> 01:20:37,075 [INTERPOSING] 1351 01:20:37,075 --> 01:20:39,300 are order dependent. 1352 01:20:39,300 --> 01:20:42,820 Does this eliminate the side-effect from the 1353 01:20:42,820 --> 01:20:43,150 [INTERPOSING] 1354 01:20:43,150 --> 01:20:46,010 PROFESSOR: The answer is, this is not the way these things 1355 01:20:46,010 --> 01:20:49,180 were implemented. 1356 01:20:49,180 --> 01:20:53,830 Define, indeed is implemented as an operation that actually 1357 01:20:53,830 --> 01:20:59,000 modifies an environment structure, changes the frame 1358 01:20:59,000 --> 01:21:03,690 that the define is executed in. 1359 01:21:03,690 --> 01:21:08,440 And there are many reasons for that, but a lot of this has to 1360 01:21:08,440 --> 01:21:11,340 do with making an interactive system. 1361 01:21:11,340 --> 01:21:14,750 What this is saying is that if you've made a system, and you 1362 01:21:14,750 --> 01:21:17,210 know you're not going to do any debugging or anything like 1363 01:21:17,210 --> 01:21:20,930 that, and you know everything there is all at once, and you 1364 01:21:20,930 --> 01:21:21,930 want to say, what is the meaning of a 1365 01:21:21,930 --> 01:21:24,090 final set of equations? 1366 01:21:24,090 --> 01:21:25,790 This gives you a meaning for it. 1367 01:21:25,790 --> 01:21:27,740 But in order to make an interactive system, where you 1368 01:21:27,740 --> 01:21:29,430 can change the meaning of one thing without changing 1369 01:21:29,430 --> 01:21:33,580 everything else, incrementally, you can't do 1370 01:21:33,580 --> 01:21:35,000 that by implementing it this way. 1371 01:21:35,000 --> 01:21:40,990 1372 01:21:40,990 --> 01:21:41,860 Yes. 1373 01:21:41,860 --> 01:21:44,650 AUDIENCE: Another question on your danger slide. 1374 01:21:44,650 --> 01:21:47,350 It seemed that the two examples that you gave had to 1375 01:21:47,350 --> 01:21:50,300 do with convergence and non-convergence? 1376 01:21:50,300 --> 01:21:53,380 And that may or may not have something to do with function 1377 01:21:53,380 --> 01:21:55,600 theory in a way which would lead you to think of it in 1378 01:21:55,600 --> 01:21:59,710 terms of linear systems, or non-linear systems. How does 1379 01:21:59,710 --> 01:22:03,140 this convergence relate to being able to see a priori 1380 01:22:03,140 --> 01:22:05,430 what properties of that might be violated? 1381 01:22:05,430 --> 01:22:07,680 PROFESSOR: I don't know. 1382 01:22:07,680 --> 01:22:10,610 The answer is, I don't know under what circumstances. 1383 01:22:10,610 --> 01:22:13,660 I don't know how to translate that into less than an 1384 01:22:13,660 --> 01:22:16,910 hour of talk more. 1385 01:22:16,910 --> 01:22:19,850 What are the conditions under which, for which we know that 1386 01:22:19,850 --> 01:22:22,720 these things converge? 1387 01:22:22,720 --> 01:22:25,230 And v, all that was telling you that arguments that are 1388 01:22:25,230 --> 01:22:30,420 based on convergence are flaky if you don't know the 1389 01:22:30,420 --> 01:22:32,810 convergence beforehand. 1390 01:22:32,810 --> 01:22:34,440 You can make wrong arguments. 1391 01:22:34,440 --> 01:22:37,810 You can make deductions, as if you know the answer, and not 1392 01:22:37,810 --> 01:22:40,690 be stopped somewhere by some obvious contradiction. 1393 01:22:40,690 --> 01:22:43,635 AUDIENCE: So can we say then that if F is a convergent 1394 01:22:43,635 --> 01:22:46,230 mathematical expression, then the recursion 1395 01:22:46,230 --> 01:22:47,690 property can be-- 1396 01:22:47,690 --> 01:22:52,740 PROFESSOR: Well, I think there's a technical kind of F, 1397 01:22:52,740 --> 01:22:55,150 there is a technical description of those F's that 1398 01:22:55,150 --> 01:23:00,790 have the property that when you iteratively apply them 1399 01:23:00,790 --> 01:23:03,020 like this, you converge. 1400 01:23:03,020 --> 01:23:08,470 Things that are monotonic, and continuous, and 1401 01:23:08,470 --> 01:23:09,370 I forgot what else. 1402 01:23:09,370 --> 01:23:12,010 There is a whole bunch of little conditions like that 1403 01:23:12,010 --> 01:23:13,430 which have this property. 1404 01:23:13,430 --> 01:23:15,820 Now the real problem is deducing from looking at the 1405 01:23:15,820 --> 01:23:19,020 F, its definition here, whether not it has those 1406 01:23:19,020 --> 01:23:22,010 properties, and that's very hard. 1407 01:23:22,010 --> 01:23:23,280 The properties are easy. 1408 01:23:23,280 --> 01:23:24,580 You can write them down. 1409 01:23:24,580 --> 01:23:26,930 You can look in a book by Joe Stoy. 1410 01:23:26,930 --> 01:23:28,660 It's a great book-- 1411 01:23:28,660 --> 01:23:29,910 Stoy. 1412 01:23:29,910 --> 01:23:31,780 1413 01:23:31,780 --> 01:23:37,360 It's called, The Scott-Strachey Method of 1414 01:23:37,360 --> 01:23:41,800 Denotational Semantics, and it's by Joe Stoy, MIT Press. 1415 01:23:41,800 --> 01:23:47,960 1416 01:23:47,960 --> 01:23:50,630 And he works out all this in great detail, enough to 1417 01:23:50,630 --> 01:23:51,880 horrify you. 1418 01:23:51,880 --> 01:23:55,080 1419 01:23:55,080 --> 01:23:56,330 But it really is readable. 1420 01:23:56,330 --> 01:24:09,150 1421 01:24:09,150 --> 01:24:11,490 OK, well, thank you. 1422 01:24:11,490 --> 01:24:13,780 Time for the bigger break, I suppose. 1423 01:24:13,780 --> 01:24:36,991 ================================================ FILE: SrtEN/lec7b_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:00,994 1 00:00:00,994 --> 00:00:16,401 [MUSIC PLAYING] 2 00:00:16,401 --> 00:00:19,520 PROFESSOR: Well, let's see. 3 00:00:19,520 --> 00:00:21,800 What we did so far was a lot of fun, was 4 00:00:21,800 --> 00:00:23,050 it useful for anything? 5 00:00:23,050 --> 00:00:26,330 6 00:00:26,330 --> 00:00:29,380 I suppose the answer is going to be yes. 7 00:00:29,380 --> 00:00:33,930 If these metacircular interpreters are a valuable 8 00:00:33,930 --> 00:00:35,180 thing to play with. 9 00:00:35,180 --> 00:00:38,050 10 00:00:38,050 --> 00:00:41,300 Well, there have been times I spend 50% of my time, over a 11 00:00:41,300 --> 00:00:46,590 year, trying various design alternatives by experimenting 12 00:00:46,590 --> 00:00:49,600 with them with metacircular interpreters-- 13 00:00:49,600 --> 00:00:52,570 metacircular interpreters like the sort you just saw. 14 00:00:52,570 --> 00:00:55,910 Metacircular is because they are defined in terms of 15 00:00:55,910 --> 00:00:58,830 themselves in such a way that the language they interpret 16 00:00:58,830 --> 00:01:01,270 contains itself. 17 00:01:01,270 --> 00:01:04,080 Such interpreters are a convenient medium for 18 00:01:04,080 --> 00:01:06,800 exploring language issues. 19 00:01:06,800 --> 00:01:11,010 If you want to try adding a new feature, it's sort of a 20 00:01:11,010 --> 00:01:15,490 snap, it's easy, you just do it and see what happens. 21 00:01:15,490 --> 00:01:17,710 You play with that language for a while you say, gee, I'm 22 00:01:17,710 --> 00:01:21,090 didn't like that, you throw it away. 23 00:01:21,090 --> 00:01:24,640 Or you might want to see what the difference is if you'd 24 00:01:24,640 --> 00:01:30,080 make a slight difference in the binding strategy, or some 25 00:01:30,080 --> 00:01:33,720 more complicated things that might occur. 26 00:01:33,720 --> 00:01:36,810 In fact, these metacircular interpreters are an excellent 27 00:01:36,810 --> 00:01:44,030 medium for people exchanging ideas about language design, 28 00:01:44,030 --> 00:01:46,960 because they're pretty easy to understand, and they're short, 29 00:01:46,960 --> 00:01:49,690 and compact, and simple. 30 00:01:49,690 --> 00:01:54,360 If I have some idea that I want somebody to criticize 31 00:01:54,360 --> 00:02:00,770 like say, Dan Friedman at Indiana, I'd write a little 32 00:02:00,770 --> 00:02:04,260 metacircular interpreter and send him some network mail 33 00:02:04,260 --> 00:02:05,450 with this interpreter in it. 34 00:02:05,450 --> 00:02:07,900 He could whip it up on his machine and play with it and 35 00:02:07,900 --> 00:02:11,940 say, that's no good. 36 00:02:11,940 --> 00:02:13,706 And then send it back to me and say, well, why don't you 37 00:02:13,706 --> 00:02:16,880 try this one, it's a little better. 38 00:02:16,880 --> 00:02:20,160 So I want to show you some of that technology. 39 00:02:20,160 --> 00:02:24,750 See, because, really, it's the essential, simple technology 40 00:02:24,750 --> 00:02:27,760 for getting started in designing your own languages 41 00:02:27,760 --> 00:02:30,790 for particular purposes. 42 00:02:30,790 --> 00:02:34,210 Let's start by adding a very simple feature to a Lisp. 43 00:02:34,210 --> 00:02:40,640 44 00:02:40,640 --> 00:02:42,800 Now, one thing I want to tell you about is 45 00:02:42,800 --> 00:02:44,370 features, before I start. 46 00:02:44,370 --> 00:02:49,560 47 00:02:49,560 --> 00:02:53,100 There are many languages that have made a mess of themselves 48 00:02:53,100 --> 00:02:56,620 by adding huge numbers of features. 49 00:02:56,620 --> 00:03:00,620 Computer scientists have a joke about bugs that transform 50 00:03:00,620 --> 00:03:02,520 it to features all the time. 51 00:03:02,520 --> 00:03:05,030 52 00:03:05,030 --> 00:03:10,120 But I like to think of it is that many systems suffer from 53 00:03:10,120 --> 00:03:12,820 what's called creeping featurism. 54 00:03:12,820 --> 00:03:17,740 Which is that George has a pet feature he'd like in the 55 00:03:17,740 --> 00:03:20,170 system, so he adds it. 56 00:03:20,170 --> 00:03:23,480 And then Harry says, gee, this system is no longer what 57 00:03:23,480 --> 00:03:26,640 exactly I like, so I'm going to add my favorite feature. 58 00:03:26,640 --> 00:03:30,710 And then Jim adds his favorite feature. 59 00:03:30,710 --> 00:03:35,280 And, after a while, the thing has a manual 500 pages long 60 00:03:35,280 --> 00:03:37,790 that no one can understand. 61 00:03:37,790 --> 00:03:40,780 And sometimes it's the same person who writes all of these 62 00:03:40,780 --> 00:03:44,830 features and produces this terribly complicated thing. 63 00:03:44,830 --> 00:03:48,250 In some cases, like editors, it's sort of reasonable to 64 00:03:48,250 --> 00:03:51,940 have lots of features, because there are a lot of things you 65 00:03:51,940 --> 00:03:55,730 want to be able to do and many of them arbitrary. 66 00:03:55,730 --> 00:04:00,440 But in computer languages, I think it's a disaster to have 67 00:04:00,440 --> 00:04:01,690 too much stuff in them. 68 00:04:01,690 --> 00:04:04,110 69 00:04:04,110 --> 00:04:06,860 The other alternative you get into is something called 70 00:04:06,860 --> 00:04:12,300 feeping creaturism, which is where you have a box which has 71 00:04:12,300 --> 00:04:17,370 a display, a fancy display, and a mouse, and there is all 72 00:04:17,370 --> 00:04:21,010 sorts of complexity associated with all this fancy IO. 73 00:04:21,010 --> 00:04:24,430 And your computer language becomes a dismal, little, tiny 74 00:04:24,430 --> 00:04:26,430 thing that barely works because of all the swapping, 75 00:04:26,430 --> 00:04:30,080 and disk twitching, and so on, caused by your Windows system. 76 00:04:30,080 --> 00:04:32,650 And every time you go near the computer, the mouse process 77 00:04:32,650 --> 00:04:35,910 wakes up and says, gee do you have something for me to do, 78 00:04:35,910 --> 00:04:37,440 and then it goes back to sleep. 79 00:04:37,440 --> 00:04:40,210 And if you accidentally push mouse with you elbow, a big 80 00:04:40,210 --> 00:04:41,600 puff of smoke comes out of your computer 81 00:04:41,600 --> 00:04:42,940 and things like that. 82 00:04:42,940 --> 00:04:46,030 So two ways to disastrously destroy a 83 00:04:46,030 --> 00:04:47,500 system by adding features. 84 00:04:47,500 --> 00:04:49,730 But try right now to add a little, simple feature. 85 00:04:49,730 --> 00:04:52,300 86 00:04:52,300 --> 00:04:54,350 This actually is a good one, and in fact, 87 00:04:54,350 --> 00:04:57,250 real Lisps have it. 88 00:04:57,250 --> 00:05:03,420 As you've seen, there are procedures like plus and times 89 00:05:03,420 --> 00:05:05,430 that take any number of arguments. 90 00:05:05,430 --> 00:05:09,440 So we can write things like the sum of the product of a 91 00:05:09,440 --> 00:05:17,540 and x and x, and the product of b and x and c. 92 00:05:17,540 --> 00:05:21,210 As you can see here, addition takes three arguments or two 93 00:05:21,210 --> 00:05:24,230 arguments, multiplication takes two arguments or three 94 00:05:24,230 --> 00:05:27,290 arguments, taking numbers of arguments all of which are to 95 00:05:27,290 --> 00:05:30,000 be treated in the same way. 96 00:05:30,000 --> 00:05:32,300 This is a valuable thing, 97 00:05:32,300 --> 00:05:34,960 indefinite numbers of arguments. 98 00:05:34,960 --> 00:05:40,460 Yet the particular Lisp system that I showed you is one where 99 00:05:40,460 --> 00:05:43,600 the numbers of arguments is fixed, because I had to match 100 00:05:43,600 --> 00:05:45,910 the arguments against the formal parameters in the 101 00:05:45,910 --> 00:05:47,850 binder, where there's a pairup. 102 00:05:47,850 --> 00:05:50,810 103 00:05:50,810 --> 00:05:53,460 Well, I'd like to be able to define new procedures like 104 00:05:53,460 --> 00:05:58,590 this that can have any number of arguments. 105 00:05:58,590 --> 00:06:01,150 Well there's several parts to this problem. 106 00:06:01,150 --> 00:06:03,870 The first part is coming up with the syntactic 107 00:06:03,870 --> 00:06:10,620 specification, some way of notating the additional 108 00:06:10,620 --> 00:06:15,480 arguments, of which you don't know how many there are. 109 00:06:15,480 --> 00:06:17,980 And then there's the other thing, which is once we've 110 00:06:17,980 --> 00:06:21,940 notated it, how are we going to interpret that notation so 111 00:06:21,940 --> 00:06:26,980 as to do the right thing, whatever the right thing is? 112 00:06:26,980 --> 00:06:29,230 So let's consider an example of a sort of thing we might 113 00:06:29,230 --> 00:06:30,480 want to be able to do. 114 00:06:30,480 --> 00:06:33,070 115 00:06:33,070 --> 00:06:36,380 So an example might be, that I might want to be able to 116 00:06:36,380 --> 00:06:40,490 define a procedure which is a procedure of one required 117 00:06:40,490 --> 00:06:45,820 argument x and a bunch of arguments, I don't know how 118 00:06:45,820 --> 00:06:49,090 many there are, called y. 119 00:06:49,090 --> 00:07:00,725 So x is required, and there are many y's, many argument-- 120 00:07:00,725 --> 00:07:04,710 121 00:07:04,710 --> 00:07:05,990 y will be the list of them. 122 00:07:05,990 --> 00:07:14,480 123 00:07:14,480 --> 00:07:17,370 Now, with such a thing, we might be able to say something 124 00:07:17,370 --> 00:07:20,720 like, map-- 125 00:07:20,720 --> 00:07:22,590 I'm going to do something to every one-- 126 00:07:22,590 --> 00:07:30,055 of that procedure of one argument u, which multiplies x 127 00:07:30,055 --> 00:07:36,890 by u, and we'll apply that to y. 128 00:07:36,890 --> 00:07:41,020 I've used a dot here to indicate that the thing after 129 00:07:41,020 --> 00:07:46,300 this is a list of all the rest of the arguments. 130 00:07:46,300 --> 00:07:47,745 I'm making a syntactic specification. 131 00:07:47,745 --> 00:07:53,320 132 00:07:53,320 --> 00:07:56,870 Now, what this depends upon, the reason why this is sort of 133 00:07:56,870 --> 00:08:01,440 a reasonable thing to do, is because this happens to be a 134 00:08:01,440 --> 00:08:04,640 syntax that's used in the Lisp reader for 135 00:08:04,640 --> 00:08:08,631 representing conses. 136 00:08:08,631 --> 00:08:11,080 We've never introduced that before. 137 00:08:11,080 --> 00:08:13,680 You may have seen when playing with the system that if you 138 00:08:13,680 --> 00:08:16,740 cons two things together, you get the first, space, dot, the 139 00:08:16,740 --> 00:08:19,800 second, space-- 140 00:08:19,800 --> 00:08:23,880 the first, space, dot, space, the second with parentheses 141 00:08:23,880 --> 00:08:26,980 around the whole thing. 142 00:08:26,980 --> 00:08:36,350 So that, for example, this x dot y corresponds to a pair, 143 00:08:36,350 --> 00:08:41,870 which has got an x in it and a y in it. 144 00:08:41,870 --> 00:08:45,520 The other notations that you've seen so far are things 145 00:08:45,520 --> 00:08:55,720 like a procedure of arguments x and y and z which do things, 146 00:08:55,720 --> 00:08:57,590 and that looks like-- 147 00:08:57,590 --> 00:09:02,000 148 00:09:02,000 --> 00:09:04,910 Just looking at the bound variable list, it looks like 149 00:09:04,910 --> 00:09:18,280 this, x, y, z, and the empty thing. 150 00:09:18,280 --> 00:09:22,590 If I have a list of arguments I wish to match this against, 151 00:09:22,590 --> 00:09:26,110 supposing, I have a list of arguments one, two, three, I 152 00:09:26,110 --> 00:09:36,300 want to match these against. So I might have here a list of 153 00:09:36,300 --> 00:09:46,380 three things, one, two, three. 154 00:09:46,380 --> 00:09:48,990 155 00:09:48,990 --> 00:09:54,220 And I want to match x, y, z against one, two, three. 156 00:09:54,220 --> 00:09:56,830 Well, it's clear that the one matches the x, because I can 157 00:09:56,830 --> 00:10:00,130 just sort of follow the structure, and the two matches 158 00:10:00,130 --> 00:10:05,480 the y, and the three matches the z. 159 00:10:05,480 --> 00:10:09,560 But now, supposing I were to compare this x dot y-- 160 00:10:09,560 --> 00:10:12,460 this is x dot y-- 161 00:10:12,460 --> 00:10:16,010 supposing I compare that with a list of three arguments, 162 00:10:16,010 --> 00:10:18,510 one, two, three. 163 00:10:18,510 --> 00:10:20,000 Let's look at that again. 164 00:10:20,000 --> 00:10:28,000 165 00:10:28,000 --> 00:10:30,930 One, two, three-- 166 00:10:30,930 --> 00:10:34,970 Well, I can walk along here and say, oh yes, x matches the 167 00:10:34,970 --> 00:10:43,740 one, the y matches the list, which is two and three. 168 00:10:43,740 --> 00:10:47,150 So the notation I'm choosing here is one that's very 169 00:10:47,150 --> 00:10:50,160 natural for Lisp system. 170 00:10:50,160 --> 00:10:52,660 171 00:10:52,660 --> 00:10:54,790 But I'm going to choose this as a notation for representing 172 00:10:54,790 --> 00:10:56,040 a bunch of arguments. 173 00:10:56,040 --> 00:10:58,290 174 00:10:58,290 --> 00:11:00,770 Now, there's an alternative possibility. 175 00:11:00,770 --> 00:11:03,560 If I don't want to take one special out, or two special 176 00:11:03,560 --> 00:11:07,300 ones out or something like that, if I don't want to do 177 00:11:07,300 --> 00:11:11,420 that, if I want to talk about just the list of all the 178 00:11:11,420 --> 00:11:16,950 arguments like in addition, well then the argument list 179 00:11:16,950 --> 00:11:20,370 I'm going to choose to be that procedure of all the arguments 180 00:11:20,370 --> 00:11:25,140 x which does something with x. 181 00:11:25,140 --> 00:11:29,190 And which, for example, if I take the procedure, which 182 00:11:29,190 --> 00:11:35,040 takes all the arguments x and returned the list of them, 183 00:11:35,040 --> 00:11:45,850 that's list. That's the procedure list. 184 00:11:45,850 --> 00:11:46,840 How does this work? 185 00:11:46,840 --> 00:11:49,610 Well, indeed what I had as the bound variable list in this 186 00:11:49,610 --> 00:11:52,450 case, whatever it is, is being matched 187 00:11:52,450 --> 00:11:55,140 against a list of arguments. 188 00:11:55,140 --> 00:11:57,145 This symbol now is all of the arguments. 189 00:11:57,145 --> 00:12:01,490 190 00:12:01,490 --> 00:12:03,830 And so this is the choice I'm making for a particular 191 00:12:03,830 --> 00:12:08,060 syntactic specification, for the description of procedures 192 00:12:08,060 --> 00:12:10,285 which take indefinite numbers of arguments. 193 00:12:10,285 --> 00:12:13,190 194 00:12:13,190 --> 00:12:18,420 There are two cases of it, this one and this one. 195 00:12:18,420 --> 00:12:21,330 When you make syntactic specifications, it's important 196 00:12:21,330 --> 00:12:26,410 that it's unambiguous, that neither of these can be 197 00:12:26,410 --> 00:12:31,100 confused with a representation we already have, this one. 198 00:12:31,100 --> 00:12:33,610 199 00:12:33,610 --> 00:12:38,350 I can always tell whether I have a fixed number of 200 00:12:38,350 --> 00:12:41,180 explicitly named arguments made by these formal 201 00:12:41,180 --> 00:12:45,470 parameters, or a fixed number of named formal parameters 202 00:12:45,470 --> 00:12:49,240 followed by a thing which picks up all the rest of them, 203 00:12:49,240 --> 00:12:54,620 or a list of all the arguments which will be matched against 204 00:12:54,620 --> 00:12:57,170 this particular formal parameter called x, because 205 00:12:57,170 --> 00:12:58,465 these are syntactically distinguishable. 206 00:12:58,465 --> 00:13:02,250 207 00:13:02,250 --> 00:13:05,960 Many languages make terrible errors in that form where 208 00:13:05,960 --> 00:13:08,340 whole segments of interpretation are cut off, 209 00:13:08,340 --> 00:13:14,560 because there are syntactic ambiguities in the language. 210 00:13:14,560 --> 00:13:16,330 They are the traditional problems with ALGOL like 211 00:13:16,330 --> 00:13:22,810 languages having to do with the nesting of ifs in the 212 00:13:22,810 --> 00:13:25,060 predicate part. 213 00:13:25,060 --> 00:13:30,510 In any case, now, so I've told you about the syntax, now, 214 00:13:30,510 --> 00:13:35,250 what are we going to do about the semantics of this? 215 00:13:35,250 --> 00:13:36,590 How do we interpret it? 216 00:13:36,590 --> 00:13:38,440 Well this is just super easy. 217 00:13:38,440 --> 00:13:39,900 I'm going to modify the metacircular 218 00:13:39,900 --> 00:13:43,396 interpreter to do it. 219 00:13:43,396 --> 00:13:46,020 And that's a one liner. 220 00:13:46,020 --> 00:13:47,590 There it is. 221 00:13:47,590 --> 00:13:49,560 I'm changing the way you pair things up. 222 00:13:49,560 --> 00:13:56,390 223 00:13:56,390 --> 00:14:06,070 Here's the procedure that pairs the variables, the 224 00:14:06,070 --> 00:14:12,090 formal parameters, with the arguments that were passed 225 00:14:12,090 --> 00:14:16,080 from the last description of the metacircular interpreter. 226 00:14:16,080 --> 00:14:18,960 227 00:14:18,960 --> 00:14:20,840 And here's some things that are the same 228 00:14:20,840 --> 00:14:22,670 as they were before. 229 00:14:22,670 --> 00:14:25,880 In other words, if the list of variables is empty, then if 230 00:14:25,880 --> 00:14:31,050 the list of values is empty, then I have an empty list. 231 00:14:31,050 --> 00:14:36,890 Otherwise, I have too many arguments, that is, if I have 232 00:14:36,890 --> 00:14:41,580 empty variables but not empty values. 233 00:14:41,580 --> 00:14:47,713 If I have empty values, but the variables are not empty, I 234 00:14:47,713 --> 00:14:50,090 have too few arguments. 235 00:14:50,090 --> 00:14:51,340 The variables are a symbol-- 236 00:14:51,340 --> 00:14:55,620 237 00:14:55,620 --> 00:14:58,130 interesting case-- 238 00:14:58,130 --> 00:15:04,040 then, what I should do is say, oh yes, this is the special 239 00:15:04,040 --> 00:15:06,255 case that I have a symbolic tail. 240 00:15:06,255 --> 00:15:09,010 241 00:15:09,010 --> 00:15:14,900 I have here a thing just like we looked over here. 242 00:15:14,900 --> 00:15:18,630 This is a tail which is a symbol, y. 243 00:15:18,630 --> 00:15:20,730 It's not a nil. 244 00:15:20,730 --> 00:15:24,290 It's not the empty list. Here's a symbolic tail that is 245 00:15:24,290 --> 00:15:25,600 just the very beginning of the tail. 246 00:15:25,600 --> 00:15:27,790 There is nothing else. 247 00:15:27,790 --> 00:15:36,540 In that case, I wish to match that variable with all the 248 00:15:36,540 --> 00:15:44,500 values and add that to the pairing that I'm making. 249 00:15:44,500 --> 00:15:47,660 Otherwise, I go through the normal arrangement of making 250 00:15:47,660 --> 00:15:48,910 up the whole pairing. 251 00:15:48,910 --> 00:15:52,020 252 00:15:52,020 --> 00:15:54,510 I suppose that's very simple. 253 00:15:54,510 --> 00:15:57,080 And that's all there is to it. 254 00:15:57,080 --> 00:15:58,330 And now I'll answer some questions. 255 00:15:58,330 --> 00:16:02,620 256 00:16:02,620 --> 00:16:04,220 The first one-- 257 00:16:04,220 --> 00:16:06,600 Are there any questions? 258 00:16:06,600 --> 00:16:06,950 Yes? 259 00:16:06,950 --> 00:16:10,450 AUDIENCE: Could you explain that third form? 260 00:16:10,450 --> 00:16:12,590 PROFESSOR: This one? 261 00:16:12,590 --> 00:16:15,280 Well, maybe we should look at the thing as a 262 00:16:15,280 --> 00:16:18,570 piece of list structure. 263 00:16:18,570 --> 00:16:22,400 This is a procedure which contains a lambda. 264 00:16:22,400 --> 00:16:25,970 265 00:16:25,970 --> 00:16:27,110 I'm just looking at the list structure 266 00:16:27,110 --> 00:16:31,090 which represents this. 267 00:16:31,090 --> 00:16:32,730 Here's x. 268 00:16:32,730 --> 00:16:33,980 These are our symbols. 269 00:16:33,980 --> 00:16:37,410 270 00:16:37,410 --> 00:16:39,580 And then the body is nothing but x. 271 00:16:39,580 --> 00:16:44,840 272 00:16:44,840 --> 00:16:48,040 If I were looking for the bound variable list part of 273 00:16:48,040 --> 00:16:52,400 this procedure, I would go looking at the CADR, and I'd 274 00:16:52,400 --> 00:16:54,010 find a symbol. 275 00:16:54,010 --> 00:16:56,750 So the, naturally, which is this pairup thing I just 276 00:16:56,750 --> 00:17:01,570 showed you, is going to be matching a symbolic object 277 00:17:01,570 --> 00:17:05,760 against a list of arguments that were passed. 278 00:17:05,760 --> 00:17:09,559 And it will bind that symbol to the list of arguments. 279 00:17:09,559 --> 00:17:13,910 280 00:17:13,910 --> 00:17:18,560 In this case, if I'm looking for it, the match will be 281 00:17:18,560 --> 00:17:20,920 against this in the bound variable list position. 282 00:17:20,920 --> 00:17:24,140 283 00:17:24,140 --> 00:17:27,020 Now, if what this does is it gets a list of arguments and 284 00:17:27,020 --> 00:17:31,450 returns it, that's list. That's what the procedure is. 285 00:17:31,450 --> 00:17:34,510 286 00:17:34,510 --> 00:17:36,140 Oh well, thank you. 287 00:17:36,140 --> 00:17:37,830 Let's take a break. 288 00:17:37,830 --> 00:18:20,358 [MUSIC PLAYING] 289 00:18:20,358 --> 00:18:23,260 PROFESSOR: Well let's see. 290 00:18:23,260 --> 00:18:24,760 Now, I'm going to tell you about a rather more 291 00:18:24,760 --> 00:18:32,440 substantial variation, one that's a famous variation that 292 00:18:32,440 --> 00:18:38,250 many early Lisps had. 293 00:18:38,250 --> 00:18:41,770 It's called dynamic binding of variables. 294 00:18:41,770 --> 00:18:44,680 And we'll investigate a little bit about that right now. 295 00:18:44,680 --> 00:18:47,620 296 00:18:47,620 --> 00:18:49,710 I'm going to first introduce this by showing you the sort 297 00:18:49,710 --> 00:18:53,740 of thing that would make someone want this idea. 298 00:18:53,740 --> 00:18:56,680 I'm not going to tell what it is yet, I'm going to show you 299 00:18:56,680 --> 00:18:58,640 why you might want it. 300 00:18:58,640 --> 00:19:02,100 Suppose, for example, we looked at the sum procedure 301 00:19:02,100 --> 00:19:08,140 again for summing up a bunch of things. 302 00:19:08,140 --> 00:19:15,860 To be that procedure, of a term, lower bound, method of 303 00:19:15,860 --> 00:19:25,560 computing the next index, and upper bound, such that, if a 304 00:19:25,560 --> 00:19:34,020 is greater than b then the result is 0, otherwise, it's 305 00:19:34,020 --> 00:19:40,680 the sum, of the term, procedure, applied to a and 306 00:19:40,680 --> 00:19:51,925 the result of adding up, terms, with the next a being 307 00:19:51,925 --> 00:20:06,970 the a, the next procedure passed along, and the upper 308 00:20:06,970 --> 00:20:08,220 bound being passed along. 309 00:20:08,220 --> 00:20:14,510 310 00:20:14,510 --> 00:20:15,760 Blink, blink, blink-- 311 00:20:15,760 --> 00:20:18,900 312 00:20:18,900 --> 00:20:23,350 Now, when I use this sum procedure, I can use it, for 313 00:20:23,350 --> 00:20:25,450 example, like this. 314 00:20:25,450 --> 00:20:38,680 We can define the sum of the powers to be, for example, sum 315 00:20:38,680 --> 00:20:43,240 of a bunch of powers x to the n, to be that procedure 316 00:20:43,240 --> 00:20:45,970 of a, b, and n-- 317 00:20:45,970 --> 00:20:48,150 lower bound, the upper bound, and n-- 318 00:20:48,150 --> 00:20:54,530 which is sum, of lambda of x, the procedure of one argument 319 00:20:54,530 --> 00:21:05,720 x, which exponentiates x to the n, with the a, the 320 00:21:05,720 --> 00:21:11,440 incrementer, and b, being passed along. 321 00:21:11,440 --> 00:21:16,340 So we're adding up x to n, given an x. 322 00:21:16,340 --> 00:21:19,740 x takes on values from a to b, incrementing by one. 323 00:21:19,740 --> 00:21:22,940 324 00:21:22,940 --> 00:21:24,300 I can also write the-- 325 00:21:24,300 --> 00:21:27,670 326 00:21:27,670 --> 00:21:29,780 That's right. 327 00:21:29,780 --> 00:21:31,910 Product, excuse me. 328 00:21:31,910 --> 00:21:33,220 The product of a bunch of powers. 329 00:21:33,220 --> 00:21:38,080 330 00:21:38,080 --> 00:21:40,020 It's a strange name. 331 00:21:40,020 --> 00:21:41,960 I'm going to leave it there. 332 00:21:41,960 --> 00:21:43,210 Weird-- 333 00:21:43,210 --> 00:21:45,760 334 00:21:45,760 --> 00:21:50,890 I write up what I have. I'm sure that's right. 335 00:21:50,890 --> 00:21:53,720 And if I want the product of a bunch of powers-- 336 00:21:53,720 --> 00:21:58,630 337 00:21:58,630 --> 00:22:03,400 That was 12 brain cells, that double-take. 338 00:22:03,400 --> 00:22:06,890 I can for example use the procedure which is like sum, 339 00:22:06,890 --> 00:22:10,080 which is for making products, but it's similar to that, that 340 00:22:10,080 --> 00:22:11,450 you've seen before. 341 00:22:11,450 --> 00:22:16,725 There's a procedure of three arguments again. 342 00:22:16,725 --> 00:22:24,080 Which is the product of terms that are constructed, or 343 00:22:24,080 --> 00:22:26,480 factors in this case, constructed from 344 00:22:26,480 --> 00:22:35,970 exponentiating x to the n, where I start with a, I 345 00:22:35,970 --> 00:22:37,850 increment, and I go to b. 346 00:22:37,850 --> 00:22:41,530 347 00:22:41,530 --> 00:22:48,690 Now, there's some sort of thing here that should disturb 348 00:22:48,690 --> 00:22:50,750 you immediately. 349 00:22:50,750 --> 00:22:53,180 These look the same. 350 00:22:53,180 --> 00:22:56,590 Why am I writing this code so many times? 351 00:22:56,590 --> 00:23:01,270 Here I am, in the same boat I've been in before. 352 00:23:01,270 --> 00:23:03,810 Wouldn't it be nice to make an abstraction here? 353 00:23:03,810 --> 00:23:05,980 What's an example of a good abstraction to make? 354 00:23:05,980 --> 00:23:08,470 Well, I see some codes that's identical. 355 00:23:08,470 --> 00:23:11,080 Here's one, and here's another. 356 00:23:11,080 --> 00:23:14,450 357 00:23:14,450 --> 00:23:17,090 And so maybe I should be able to pull that out. 358 00:23:17,090 --> 00:23:21,580 I should be able to say, oh yes, the sum of the powers 359 00:23:21,580 --> 00:23:23,350 could be written in terms of something called 360 00:23:23,350 --> 00:23:25,710 the nth power procedure. 361 00:23:25,710 --> 00:23:28,690 Imagine somebody wanted to write a slightly different 362 00:23:28,690 --> 00:23:30,030 procedure that looks like this. 363 00:23:30,030 --> 00:23:37,630 364 00:23:37,630 --> 00:23:49,300 The sum powers to be a procedure of a, b, and n, as 365 00:23:49,300 --> 00:23:53,556 the result of summing up the nth power. 366 00:23:53,556 --> 00:23:59,720 We're going to give a name to that idea, for starting at a, 367 00:23:59,720 --> 00:24:02,170 going by one, and ending at b. 368 00:24:02,170 --> 00:24:06,000 369 00:24:06,000 --> 00:24:12,480 And similarly, I might want to write the product powers this 370 00:24:12,480 --> 00:24:16,270 way, abstracting out this idea. 371 00:24:16,270 --> 00:24:17,520 I might want this. 372 00:24:17,520 --> 00:24:22,100 373 00:24:22,100 --> 00:24:35,350 Product powers, to be a procedure of a, b, and n, 374 00:24:35,350 --> 00:24:47,540 which is the product of the nth power operation on a with 375 00:24:47,540 --> 00:24:56,380 the incrementation and b being my arguments for the 376 00:24:56,380 --> 00:24:58,380 analogous-thing product. 377 00:24:58,380 --> 00:25:02,840 And I'd like to be able to define, I'd like to be able to 378 00:25:02,840 --> 00:25:04,680 define nth power-- 379 00:25:04,680 --> 00:25:05,930 I'll put it over here. 380 00:25:05,930 --> 00:25:11,215 381 00:25:11,215 --> 00:25:12,990 I'll put it at the top. 382 00:25:12,990 --> 00:25:25,410 383 00:25:25,410 --> 00:25:30,630 --to be, in fact, my procedure of one argument x which is the 384 00:25:30,630 --> 00:25:35,390 result of exponentiating x to the n. 385 00:25:35,390 --> 00:25:38,640 But I have a problem. 386 00:25:38,640 --> 00:25:44,160 My environment model, that is my means of interpretation for 387 00:25:44,160 --> 00:25:47,010 the language that we've defined so far, does not give 388 00:25:47,010 --> 00:25:48,810 me a meaning for this n. 389 00:25:48,810 --> 00:25:52,520 390 00:25:52,520 --> 00:26:06,410 Because, as you know, this n is free in this procedure. 391 00:26:06,410 --> 00:26:09,600 The environment model tells us that the meaning of a free 392 00:26:09,600 --> 00:26:13,760 variable is determined in the environment in which this 393 00:26:13,760 --> 00:26:16,640 procedure is defined. 394 00:26:16,640 --> 00:26:18,120 In a way I have written it, assuming these things are 395 00:26:18,120 --> 00:26:22,830 defined on the blackboard as is, this is defined in the 396 00:26:22,830 --> 00:26:25,850 global environment, where there is no end. 397 00:26:25,850 --> 00:26:28,720 Therefore, n is unbound variable. 398 00:26:28,720 --> 00:26:33,390 But it's perfectly clear, to most of us, that we would like 399 00:26:33,390 --> 00:26:36,220 it to be this n and this n. 400 00:26:36,220 --> 00:26:38,990 401 00:26:38,990 --> 00:26:42,840 On the other hand, it would be nice. 402 00:26:42,840 --> 00:26:45,290 Certainly we've got to be careful here of keeping this 403 00:26:45,290 --> 00:26:51,005 to be this, and this one over here, wherever it 404 00:26:51,005 --> 00:26:52,900 is to be this one. 405 00:26:52,900 --> 00:26:57,390 406 00:26:57,390 --> 00:27:01,360 Well, the desire to make this work has led to 407 00:27:01,360 --> 00:27:04,040 a very famous bug. 408 00:27:04,040 --> 00:27:07,310 I'll tell you about the famous bug. 409 00:27:07,310 --> 00:27:10,660 Look at this slide. 410 00:27:10,660 --> 00:27:13,990 This is an idea called dynamic binding. 411 00:27:13,990 --> 00:27:17,980 Where, instead of the free variable being interpreted in 412 00:27:17,980 --> 00:27:22,820 the environment of definition of a procedure, the free 413 00:27:22,820 --> 00:27:25,770 variable is interpreted as having its value in the 414 00:27:25,770 --> 00:27:29,125 environment of the caller of the procedure. 415 00:27:29,125 --> 00:27:31,850 416 00:27:31,850 --> 00:27:36,680 So what you have is a system where you search up the chain 417 00:27:36,680 --> 00:27:41,990 of callers of a particular procedure, and, of course, in 418 00:27:41,990 --> 00:27:45,240 this case, since nth power is called from inside product 419 00:27:45,240 --> 00:27:46,010 whatever it is-- 420 00:27:46,010 --> 00:27:48,140 I had to write our own sum which is the analogous 421 00:27:48,140 --> 00:27:50,530 procedure-- 422 00:27:50,530 --> 00:27:55,300 and product is presumably called from product powers, as 423 00:27:55,300 --> 00:27:58,490 you see over here, then since product powers bind with 424 00:27:58,490 --> 00:28:03,220 variable n , then nth powers n would be derived 425 00:28:03,220 --> 00:28:04,470 through that chain. 426 00:28:04,470 --> 00:28:08,140 427 00:28:08,140 --> 00:28:12,600 Similarly, this n, the nth power in n in this case, would 428 00:28:12,600 --> 00:28:15,800 come through nth power here being called from inside sum. 429 00:28:15,800 --> 00:28:19,730 You can see it being called from inside sum here. 430 00:28:19,730 --> 00:28:22,900 It's called term here. 431 00:28:22,900 --> 00:28:28,930 But sum was called from inside of sum powers, which bound n. 432 00:28:28,930 --> 00:28:35,245 Therefore, there would be an n available for that n to get 433 00:28:35,245 --> 00:28:36,495 it's value from. 434 00:28:36,495 --> 00:28:39,430 435 00:28:39,430 --> 00:28:43,630 What we have below this white line plus over here, is what's 436 00:28:43,630 --> 00:28:46,540 called a dynamic binding view of the world. 437 00:28:46,540 --> 00:28:50,850 If that works, that's a dynamic binding view. 438 00:28:50,850 --> 00:28:55,310 Now, let's take a look, for example, at just what it takes 439 00:28:55,310 --> 00:28:55,990 to implement that. 440 00:28:55,990 --> 00:28:57,480 That's real easy. 441 00:28:57,480 --> 00:29:01,400 In fact, the very first Lisps that had any interpretations 442 00:29:01,400 --> 00:29:04,440 of the free variables at all, had dynamic binding 443 00:29:04,440 --> 00:29:06,490 interpretations for the free variables. 444 00:29:06,490 --> 00:29:09,570 APL has dynamic binding interpretation for the free 445 00:29:09,570 --> 00:29:15,220 variables, not lexical or static binding. 446 00:29:15,220 --> 00:29:18,790 So, of course, the change is in eval. 447 00:29:18,790 --> 00:29:22,780 And it's really in two places. 448 00:29:22,780 --> 00:29:27,760 First of all, one thing we see, is that things become a 449 00:29:27,760 --> 00:29:29,010 little simpler. 450 00:29:29,010 --> 00:29:32,460 451 00:29:32,460 --> 00:29:34,930 If I don't have to have the environment be the environment 452 00:29:34,930 --> 00:29:38,490 of definition for procedure, the procedure need not capture 453 00:29:38,490 --> 00:29:42,030 the environment at the time it's defined. 454 00:29:42,030 --> 00:29:47,900 And so if we look here at this slide, we see that the clause 455 00:29:47,900 --> 00:29:51,890 for a lambda expression, which is the way a procedure is 456 00:29:51,890 --> 00:29:57,820 defined, does not make up a thing which has a type closure 457 00:29:57,820 --> 00:30:01,290 and a attached environment structure. 458 00:30:01,290 --> 00:30:02,540 It's just the expression itself. 459 00:30:02,540 --> 00:30:06,440 And we'll decompose that some other way somewhere else. 460 00:30:06,440 --> 00:30:12,210 The other thing we see is the applicator must be able to get 461 00:30:12,210 --> 00:30:14,290 the environment of the caller. 462 00:30:14,290 --> 00:30:19,560 The caller of a procedure is right here. 463 00:30:19,560 --> 00:30:22,810 If the expression we're evaluating is anpplication or 464 00:30:22,810 --> 00:30:25,680 a combination, then we're going to call a procedure 465 00:30:25,680 --> 00:30:26,980 which is the value of the operator. 466 00:30:26,980 --> 00:30:29,840 467 00:30:29,840 --> 00:30:33,100 The environment of the caller is the environment we have 468 00:30:33,100 --> 00:30:35,890 right here, available now. 469 00:30:35,890 --> 00:30:38,570 So all I have to do is pass that environment to the 470 00:30:38,570 --> 00:30:41,490 applicator, to apply. 471 00:30:41,490 --> 00:30:44,680 And if we look at that here, the only change we have to 472 00:30:44,680 --> 00:30:49,720 make is that fellow takes that environment and uses that 473 00:30:49,720 --> 00:30:57,240 environment for the purpose of extending that environment 474 00:30:57,240 --> 00:31:00,100 when abiding the formal parameters of the procedure to 475 00:31:00,100 --> 00:31:04,560 the arguments that were passed, not an environment 476 00:31:04,560 --> 00:31:06,810 that was captured in the procedure. 477 00:31:06,810 --> 00:31:09,780 The reason why the first Lisps were implemented this way, is 478 00:31:09,780 --> 00:31:14,130 the sort of the obvious, accidental implementation. 479 00:31:14,130 --> 00:31:15,990 And, of course, as usual, people got used to 480 00:31:15,990 --> 00:31:17,250 it and liked it. 481 00:31:17,250 --> 00:31:18,730 And there were some people said, this is 482 00:31:18,730 --> 00:31:21,590 the way to do it. 483 00:31:21,590 --> 00:31:25,870 Unfortunately that causes some serious problems. The most 484 00:31:25,870 --> 00:31:31,240 important, serious problem in using dynamic binding is 485 00:31:31,240 --> 00:31:35,460 there's a modularity crisis that's involved it. 486 00:31:35,460 --> 00:31:38,370 If two people are working together on some big system, 487 00:31:38,370 --> 00:31:41,580 then an important thing to want is that the names used by 488 00:31:41,580 --> 00:31:44,580 each one don't interfere with the names of the other. 489 00:31:44,580 --> 00:31:47,930 490 00:31:47,930 --> 00:31:51,060 It's important that when I invent some segment of code 491 00:31:51,060 --> 00:31:54,985 that no one can make my code stop working by using my names 492 00:31:54,985 --> 00:31:59,850 that I use internal to my code, internal to his code. 493 00:31:59,850 --> 00:32:03,140 However, dynamic binding violates that particular 494 00:32:03,140 --> 00:32:06,670 modularity constraint in a clear way. 495 00:32:06,670 --> 00:32:12,540 Consider, for example, what happens over here. 496 00:32:12,540 --> 00:32:17,590 Suppose it was the case that I decided to 497 00:32:17,590 --> 00:32:19,810 change the word next. 498 00:32:19,810 --> 00:32:25,870 Supposing somebody is writing sum, and somebody else is 499 00:32:25,870 --> 00:32:28,970 going to use sum. 500 00:32:28,970 --> 00:32:33,790 The writer of sum has a choice of what names he may use. 501 00:32:33,790 --> 00:32:36,760 Let's say, I'm that writer. 502 00:32:36,760 --> 00:32:39,300 Well, by gosh, just happens I didn't want to call this next. 503 00:32:39,300 --> 00:32:41,500 I called it n. 504 00:32:41,500 --> 00:32:48,140 So all places where you see next, I called it n. 505 00:32:48,140 --> 00:32:49,940 Whoops. 506 00:32:49,940 --> 00:32:51,700 I changed nothing about the specifications of this 507 00:32:51,700 --> 00:32:56,110 program, but this program stops working. 508 00:32:56,110 --> 00:32:59,730 Not only that, unfortunately, this one does too. 509 00:32:59,730 --> 00:33:02,260 Why do these programs stop working? 510 00:33:02,260 --> 00:33:04,480 Well, it's sort of clear. 511 00:33:04,480 --> 00:33:09,890 Instead of chasing out the value of the n that occurs in 512 00:33:09,890 --> 00:33:16,450 nth power over here or over here, through the environment 513 00:33:16,450 --> 00:33:19,940 of definition, where this one is always linked to this one, 514 00:33:19,940 --> 00:33:21,660 if it was through the environment of definition, 515 00:33:21,660 --> 00:33:24,370 because here is the definition. 516 00:33:24,370 --> 00:33:27,320 This lambda expression was executed in the environment 517 00:33:27,320 --> 00:33:30,700 where that n was defined. 518 00:33:30,700 --> 00:33:33,150 If instead of doing that, I have to chase through the call 519 00:33:33,150 --> 00:33:37,320 chain, then look what horrible thing happens. 520 00:33:37,320 --> 00:33:44,780 Well, this was called from inside sum as term, term a. 521 00:33:44,780 --> 00:33:47,350 I'm looking for a value of n. 522 00:33:47,350 --> 00:33:50,700 Instead of getting this one, I get that one. 523 00:33:50,700 --> 00:33:53,430 So by changing the insides of this program, this program 524 00:33:53,430 --> 00:33:54,680 stops working. 525 00:33:54,680 --> 00:33:56,770 526 00:33:56,770 --> 00:33:58,770 So I no longer have a quantifier, 527 00:33:58,770 --> 00:34:00,020 as I described before. 528 00:34:00,020 --> 00:34:02,700 529 00:34:02,700 --> 00:34:05,430 The lambda symbol is supposed to be a quantifier. 530 00:34:05,430 --> 00:34:09,650 A thing which has the property that the names that are bound 531 00:34:09,650 --> 00:34:14,739 by it are unimportant, that I can uniformly substitute any 532 00:34:14,739 --> 00:34:18,230 names for these throughout this thing, so long as they 533 00:34:18,230 --> 00:34:21,699 don't occur in here, the new names, and the meaning of this 534 00:34:21,699 --> 00:34:24,040 expression should remain unchanged. 535 00:34:24,040 --> 00:34:26,050 I've just changed the meaning of the expression by changing 536 00:34:26,050 --> 00:34:28,690 the one of the names. 537 00:34:28,690 --> 00:34:32,170 So lambda is no longer a well defined idea. 538 00:34:32,170 --> 00:34:34,550 It's a very serious problem. 539 00:34:34,550 --> 00:34:40,850 So for that reason, I and my buddies have given up this 540 00:34:40,850 --> 00:34:43,650 particular kind of abstraction, which I would 541 00:34:43,650 --> 00:34:48,090 like to have, in favor of a modularity principle. 542 00:34:48,090 --> 00:34:52,310 But this is the kind of experiment you can do if you 543 00:34:52,310 --> 00:34:54,530 want to play with these interpreters. 544 00:34:54,530 --> 00:34:58,270 You can try them out this way, that way, and the other way. 545 00:34:58,270 --> 00:35:00,070 You see what makes a nicer language. 546 00:35:00,070 --> 00:35:02,680 547 00:35:02,680 --> 00:35:04,990 So that's a very important thing to be able to do. 548 00:35:04,990 --> 00:35:07,260 Now, I would like to give you a feeling for I think the 549 00:35:07,260 --> 00:35:10,880 right thing to do is here. 550 00:35:10,880 --> 00:35:14,190 How are you going to I get this kind of power in a 551 00:35:14,190 --> 00:35:16,280 lexical system? 552 00:35:16,280 --> 00:35:18,610 And the answer is, of course, what I really want is a 553 00:35:18,610 --> 00:35:21,790 something that makes up for me an exponentiator for a 554 00:35:21,790 --> 00:35:23,690 particular n. 555 00:35:23,690 --> 00:35:26,280 Given an n, it will make me an exponentiator. 556 00:35:26,280 --> 00:35:28,170 Oh, but that's easy too. 557 00:35:28,170 --> 00:35:30,570 In other words, I can write my program this way. 558 00:35:30,570 --> 00:35:35,450 559 00:35:35,450 --> 00:35:40,720 I'm going to define a thing called PGEN, which is a 560 00:35:40,720 --> 00:35:45,240 procedure of n which produces for me an exponentiator. 561 00:35:45,240 --> 00:35:50,240 562 00:35:50,240 --> 00:35:51,490 --x to the n. 563 00:35:51,490 --> 00:35:56,900 564 00:35:56,900 --> 00:36:00,310 Given that I have that, then I can capture the abstraction I 565 00:36:00,310 --> 00:36:04,090 wanted even better, because now it's encapsulated in a way 566 00:36:04,090 --> 00:36:07,890 where I can't be destroyed by a change of names. 567 00:36:07,890 --> 00:36:20,200 I can define some powers to be a procedure again of a, b, and 568 00:36:20,200 --> 00:36:28,070 n which is the sum of the term function generated by using 569 00:36:28,070 --> 00:36:37,590 this generator, PGEN, n, with a, incrementer, and b. 570 00:36:37,590 --> 00:36:42,490 571 00:36:42,490 --> 00:36:57,100 And I can define the product of powers to be a procedure of 572 00:36:57,100 --> 00:37:09,010 a, b, and n which is the product PGEN, n, with a, 573 00:37:09,010 --> 00:37:11,150 increment, and b. 574 00:37:11,150 --> 00:37:14,340 Now, of course, this is a very simple example where this 575 00:37:14,340 --> 00:37:17,280 object that I'm trying to abstract over is small. 576 00:37:17,280 --> 00:37:20,100 But it could be a 100 lines of code. 577 00:37:20,100 --> 00:37:22,350 And so, the purpose of this is, of 578 00:37:22,350 --> 00:37:23,670 course, to make it simple. 579 00:37:23,670 --> 00:37:25,630 I'd give a name to it, it's just that here it's a 580 00:37:25,630 --> 00:37:28,200 parameterized name. 581 00:37:28,200 --> 00:37:31,460 It's a name that depends upon, explicitly, the lexically 582 00:37:31,460 --> 00:37:34,050 apparent value of n. 583 00:37:34,050 --> 00:37:37,130 584 00:37:37,130 --> 00:37:40,210 So you can think of this as a long name. 585 00:37:40,210 --> 00:37:45,150 And here, I've solved my problem by naming the term 586 00:37:45,150 --> 00:37:49,220 generation procedures within an n in them. 587 00:37:49,220 --> 00:37:55,080 588 00:37:55,080 --> 00:37:57,140 Are there any questions? 589 00:37:57,140 --> 00:37:58,380 Oh, yes, David. 590 00:37:58,380 --> 00:38:04,820 AUDIENCE: Is the only solution to the problem you raise to 591 00:38:04,820 --> 00:38:06,470 create another procedure? 592 00:38:06,470 --> 00:38:09,020 In other words, can this only work in languages that are 593 00:38:09,020 --> 00:38:12,402 capable of defining objects as procedures? 594 00:38:12,402 --> 00:38:13,765 PROFESSOR: Oh, I see. 595 00:38:13,765 --> 00:38:16,530 596 00:38:16,530 --> 00:38:20,530 My solution to making this abstraction, when I didn't 597 00:38:20,530 --> 00:38:23,950 want include the procedure inside the body, depends upon 598 00:38:23,950 --> 00:38:28,190 my ability to return a procedure or export one. 599 00:38:28,190 --> 00:38:30,410 And that's right. 600 00:38:30,410 --> 00:38:33,550 If I don't have that, then I just don't have this ability 601 00:38:33,550 --> 00:38:39,490 to make an abstraction in a way where I don't have 602 00:38:39,490 --> 00:38:40,930 possibilities of symbol conflicts that were 603 00:38:40,930 --> 00:38:43,000 unanticipated. 604 00:38:43,000 --> 00:38:45,610 That's right. 605 00:38:45,610 --> 00:38:52,690 I consider being able to return the procedural value 606 00:38:52,690 --> 00:38:57,780 and, therefore, to sort of have first class procedures, 607 00:38:57,780 --> 00:39:01,840 in general, as being essential to doing very good modular 608 00:39:01,840 --> 00:39:03,700 programming. 609 00:39:03,700 --> 00:39:07,440 Now, indeed there are many other ways to skin this cat. 610 00:39:07,440 --> 00:39:10,500 What you can do is take for each of the bad things that 611 00:39:10,500 --> 00:39:13,420 you have to worry about, you can make a special feature 612 00:39:13,420 --> 00:39:15,840 that covers that thing. 613 00:39:15,840 --> 00:39:17,930 You can make a package system. 614 00:39:17,930 --> 00:39:22,240 You can make a module system as in Ada, et cetera. 615 00:39:22,240 --> 00:39:26,440 And all of those work, or they cover little regions of it. 616 00:39:26,440 --> 00:39:28,820 The thing is that returning procedures as values cover all 617 00:39:28,820 --> 00:39:35,820 of those problems. And so it's the simplest mechanism that 618 00:39:35,820 --> 00:39:40,110 gives you the best modularity, gives you all of the known 619 00:39:40,110 --> 00:39:45,590 modularity mechanisms. 620 00:39:45,590 --> 00:39:48,248 Well, I suppose it's time for the next break, thank you. 621 00:39:48,248 --> 00:40:41,871 [MUSIC PLAYING] 622 00:40:41,871 --> 00:40:43,690 PROFESSOR: Well, yesterday when you learned about 623 00:40:43,690 --> 00:40:52,110 streams, Hal worried to you about the order of evaluation 624 00:40:52,110 --> 00:40:55,420 and delayed arguments to procedures. 625 00:40:55,420 --> 00:41:00,620 The way we played with streams yesterday, it was the 626 00:41:00,620 --> 00:41:07,170 responsibility of the caller and the callee to both agree 627 00:41:07,170 --> 00:41:12,180 that an argument was delayed, and the callee must force the 628 00:41:12,180 --> 00:41:15,250 argument if it needs the answer. 629 00:41:15,250 --> 00:41:18,400 So there had to be a lot of hand shaking between the 630 00:41:18,400 --> 00:41:26,100 designer of a procedure and user of it over delayedness. 631 00:41:26,100 --> 00:41:29,670 That turns out, of course, to be a fairly bad thing, it 632 00:41:29,670 --> 00:41:33,120 works all right with streams. But as a general thing, what 633 00:41:33,120 --> 00:41:37,520 you want is an idea to have a locus, a decision, a design 634 00:41:37,520 --> 00:41:40,580 decision in general, to have a place where it's made, 635 00:41:40,580 --> 00:41:45,900 explicitly, and notated in a clear way. 636 00:41:45,900 --> 00:41:48,780 And so it's not a very good idea to have to have an 637 00:41:48,780 --> 00:41:52,670 agreement, between the person who writes a procedure and the 638 00:41:52,670 --> 00:41:56,730 person who calls it, about such details as, maybe, the 639 00:41:56,730 --> 00:41:59,500 arguments of evaluation, the order of evaluation. 640 00:41:59,500 --> 00:42:00,750 Although, that's not so bad. 641 00:42:00,750 --> 00:42:02,920 I mean, we have other such agreements like, 642 00:42:02,920 --> 00:42:04,540 the input's a number. 643 00:42:04,540 --> 00:42:07,650 But it would be nice if only one of these guys could take 644 00:42:07,650 --> 00:42:11,020 responsibility, completely. 645 00:42:11,020 --> 00:42:15,510 Now this is not a new idea. 646 00:42:15,510 --> 00:42:22,020 ALGOL 60 had two different ways of calling a procedure. 647 00:42:22,020 --> 00:42:25,590 The arguments could be passed by name or by value. 648 00:42:25,590 --> 00:42:31,110 And what that meant was that a name argument was delayed. 649 00:42:31,110 --> 00:42:34,020 That when you passed an argument by name, that its 650 00:42:34,020 --> 00:42:39,620 value would only be obtained if you accessed that argument. 651 00:42:39,620 --> 00:42:42,290 652 00:42:42,290 --> 00:42:45,870 So what I'd like to do now is show you, first of all, a 653 00:42:45,870 --> 00:42:48,040 little bit about, again, we're going to make a modification 654 00:42:48,040 --> 00:42:50,320 to a language. 655 00:42:50,320 --> 00:42:53,370 In this case, we're going to add a feature. 656 00:42:53,370 --> 00:42:56,900 We're going to add the feature of, by name parameters, if you 657 00:42:56,900 --> 00:43:00,430 will, or delayed parameters. 658 00:43:00,430 --> 00:43:05,580 Because, in fact, the default in our Lisp system is by the 659 00:43:05,580 --> 00:43:08,220 value of a pointer. 660 00:43:08,220 --> 00:43:10,530 A pointer is copied, but the data structure it 661 00:43:10,530 --> 00:43:13,410 points at is not. 662 00:43:13,410 --> 00:43:17,580 But I'd like to, in fact, show you is how you add name 663 00:43:17,580 --> 00:43:19,990 arguments as well. 664 00:43:19,990 --> 00:43:23,100 Now again, why would we need such a thing? 665 00:43:23,100 --> 00:43:26,930 Well supposing we wanted to invent certain kinds of what 666 00:43:26,930 --> 00:43:29,720 otherwise would be special forms, reserve words? 667 00:43:29,720 --> 00:43:32,180 But I'd rather not take up reserve words. 668 00:43:32,180 --> 00:43:36,360 I want procedures that can do things like if. 669 00:43:36,360 --> 00:43:39,420 If is special, or cond, or whatever it is. 670 00:43:39,420 --> 00:43:40,600 It's the same thing. 671 00:43:40,600 --> 00:43:43,080 It's special in that it determines whether or not to 672 00:43:43,080 --> 00:43:48,360 evaluate the consequent or the alternative based on the value 673 00:43:48,360 --> 00:43:50,840 of the predicate part of an expression. 674 00:43:50,840 --> 00:43:54,230 So taking the value of one thing determines whether or 675 00:43:54,230 --> 00:43:57,270 not to do something else. 676 00:43:57,270 --> 00:44:00,240 Whereas all the procedures like plus, the ones that we 677 00:44:00,240 --> 00:44:05,900 can define right now, evaluate all of their arguments before 678 00:44:05,900 --> 00:44:08,670 application. 679 00:44:08,670 --> 00:44:11,750 So, for example, supposing I wish to be able to define 680 00:44:11,750 --> 00:44:19,452 something like the reverse of if in terms of if. 681 00:44:19,452 --> 00:44:20,702 Call it unless. 682 00:44:20,702 --> 00:44:24,890 683 00:44:24,890 --> 00:44:26,760 We've a predicate, a consequent, and an 684 00:44:26,760 --> 00:44:28,190 alternative. 685 00:44:28,190 --> 00:44:30,995 Now what I would like to sort of be able to do is say-- oh, 686 00:44:30,995 --> 00:44:32,440 I'll do it in terms of cond. 687 00:44:32,440 --> 00:44:41,660 Cond, if not the predicate, then take the consequent, 688 00:44:41,660 --> 00:44:45,350 otherwise, take the alternative. 689 00:44:45,350 --> 00:44:51,290 690 00:44:51,290 --> 00:44:54,320 Now, what I'd like this to mean, is supposing I do 691 00:44:54,320 --> 00:44:56,920 something like this. 692 00:44:56,920 --> 00:45:05,860 I'd like this unless say if equals one, 0, then the answer 693 00:45:05,860 --> 00:45:11,350 is two, otherwise, the quotient of one and 0. 694 00:45:11,350 --> 00:45:15,980 695 00:45:15,980 --> 00:45:20,170 What I'd like that to mean is the result of substituting 696 00:45:20,170 --> 00:45:23,450 equal one, 0, and two, and the quotient of one, 0 697 00:45:23,450 --> 00:45:25,580 for p, c, and a. 698 00:45:25,580 --> 00:45:28,750 I'd like that to mean, and this is funny, I'd like it to 699 00:45:28,750 --> 00:45:40,940 transform into or mean cond not equal one, 0, then the 700 00:45:40,940 --> 00:45:48,910 result is two, otherwise I want it to be the 701 00:45:48,910 --> 00:45:51,160 quotient one and 0. 702 00:45:51,160 --> 00:45:54,480 703 00:45:54,480 --> 00:45:56,210 Now, you know that if I were to type this into 704 00:45:56,210 --> 00:45:59,970 Lisp, I'd get a two. 705 00:45:59,970 --> 00:46:02,910 There's no problem with that. 706 00:46:02,910 --> 00:46:05,940 However, if I were to type this into Lisp, because all 707 00:46:05,940 --> 00:46:09,590 the arguments are evaluated before I start, then I'm going 708 00:46:09,590 --> 00:46:10,840 to get an error out of this. 709 00:46:10,840 --> 00:46:13,380 710 00:46:13,380 --> 00:46:16,130 So that if the substitutions work at all, of course, I 711 00:46:16,130 --> 00:46:16,880 would get the right answer. 712 00:46:16,880 --> 00:46:20,160 But here's a case where the substitutions don't work. 713 00:46:20,160 --> 00:46:22,920 714 00:46:22,920 --> 00:46:23,860 I don't get the wrong answer. 715 00:46:23,860 --> 00:46:24,670 I get no answer. 716 00:46:24,670 --> 00:46:25,920 I get an error. 717 00:46:25,920 --> 00:46:28,420 718 00:46:28,420 --> 00:46:31,860 Now, however, I'd like to be able to make my definition so 719 00:46:31,860 --> 00:46:34,270 that this kind of thing works. 720 00:46:34,270 --> 00:46:36,010 What I want to do is say something 721 00:46:36,010 --> 00:46:39,930 special about c and a. 722 00:46:39,930 --> 00:46:42,715 I want them to be delayed automatically. 723 00:46:42,715 --> 00:46:46,300 724 00:46:46,300 --> 00:46:51,520 I don't want them to be evaluated at the time I call. 725 00:46:51,520 --> 00:46:52,980 So I'm going to make a declaration, and then I'm 726 00:46:52,980 --> 00:46:55,600 going to see how to implement such a declaration. 727 00:46:55,600 --> 00:46:58,870 But again, I want you to say to yourself, oh, this is an 728 00:46:58,870 --> 00:47:02,140 interesting kluge he's adding in here. 729 00:47:02,140 --> 00:47:05,750 The piles of kluges make a big complicated mess. 730 00:47:05,750 --> 00:47:08,240 And is this going to foul up something 731 00:47:08,240 --> 00:47:10,120 else that might occur. 732 00:47:10,120 --> 00:47:13,860 First of all, is it syntactically unambiguous? 733 00:47:13,860 --> 00:47:16,120 Well, it will be syntactically unambiguous with what we've 734 00:47:16,120 --> 00:47:17,840 seen so far. 735 00:47:17,840 --> 00:47:21,670 But what I'm going to do may, in fact, cause trouble. 736 00:47:21,670 --> 00:47:25,450 It may be that the thing I had will conflict with type 737 00:47:25,450 --> 00:47:28,700 declarations I might want to add in the future for giving 738 00:47:28,700 --> 00:47:31,730 some system, some compiler or something, the ability to 739 00:47:31,730 --> 00:47:34,300 optimize given the types are known. 740 00:47:34,300 --> 00:47:37,130 Or it might conflict with other types of declarations I 741 00:47:37,130 --> 00:47:40,570 might want to make about the formal parameters. 742 00:47:40,570 --> 00:47:44,520 So I'm not making a general mechanism here where I can add 743 00:47:44,520 --> 00:47:44,925 declarations. 744 00:47:44,925 --> 00:47:46,750 And I would like to be able to do that. 745 00:47:46,750 --> 00:47:51,010 But I don't want to talk about that right now. 746 00:47:51,010 --> 00:47:53,680 So here I'm going to do, I'm going to build a kluge. 747 00:47:53,680 --> 00:47:57,050 748 00:47:57,050 --> 00:48:08,770 So we're going to define unless of a predicate-- 749 00:48:08,770 --> 00:48:10,180 and I'm going to call these by name-- 750 00:48:10,180 --> 00:48:12,810 751 00:48:12,810 --> 00:48:14,930 the consequent, and name the alternative. 752 00:48:14,930 --> 00:48:19,850 753 00:48:19,850 --> 00:48:22,670 Huh, huh-- 754 00:48:22,670 --> 00:48:25,280 I got caught in the corner. 755 00:48:25,280 --> 00:48:31,240 756 00:48:31,240 --> 00:48:37,165 If not p then the result is c, else-- 757 00:48:37,165 --> 00:48:40,110 758 00:48:40,110 --> 00:48:41,360 that's what I'd like. 759 00:48:41,360 --> 00:48:44,670 760 00:48:44,670 --> 00:48:49,500 Where I can explicitly declare certain of the parameters to 761 00:48:49,500 --> 00:48:51,650 be delayed, to be computed later. 762 00:48:51,650 --> 00:48:55,008 763 00:48:55,008 --> 00:48:57,910 Now, this is actually a very complicated modification to an 764 00:48:57,910 --> 00:49:00,450 interpreter rather than a simple one. 765 00:49:00,450 --> 00:49:05,270 The ones you saw before, dynamic binding or adding 766 00:49:05,270 --> 00:49:07,630 indefinite argument procedures, 767 00:49:07,630 --> 00:49:09,280 is relatively simple. 768 00:49:09,280 --> 00:49:12,120 But this one changes a basic strategy. 769 00:49:12,120 --> 00:49:18,070 The problem here is that our interpreter, as written, 770 00:49:18,070 --> 00:49:24,420 evaluates a combination by evaluating the procedure, the 771 00:49:24,420 --> 00:49:26,910 operator producing the procedure, and evaluating the 772 00:49:26,910 --> 00:49:31,410 operands producing the arguments, and then doing 773 00:49:31,410 --> 00:49:36,110 apply of the procedure to the arguments. 774 00:49:36,110 --> 00:49:40,540 However, here, I don't want to evaluate the operands to 775 00:49:40,540 --> 00:49:44,640 produce the arguments until after I examined the procedure 776 00:49:44,640 --> 00:49:46,810 to see what the procedure's declarations look like. 777 00:49:46,810 --> 00:49:49,590 778 00:49:49,590 --> 00:49:52,680 So let's look at that. 779 00:49:52,680 --> 00:49:57,480 Here we have a changed evaluator. 780 00:49:57,480 --> 00:50:02,110 I'm starting with the simple lexical evaluator, not 781 00:50:02,110 --> 00:50:06,730 dynamic, but we're going to have to do something sort of 782 00:50:06,730 --> 00:50:09,750 similar in some ways. 783 00:50:09,750 --> 00:50:13,710 Because of the fact that, if I delay a procedure-- 784 00:50:13,710 --> 00:50:15,790 I'm sorry-- delay an argument to a procedure, I'm going to 785 00:50:15,790 --> 00:50:19,360 have to attach and environment to it. 786 00:50:19,360 --> 00:50:23,380 Remember how Hal implemented delay. 787 00:50:23,380 --> 00:50:28,650 Hal implemented delay as being a procedure of no arguments 788 00:50:28,650 --> 00:50:31,180 which does some expression. 789 00:50:31,180 --> 00:50:32,670 That's what delay of the expression is. 790 00:50:32,670 --> 00:50:35,370 791 00:50:35,370 --> 00:50:36,620 --of that expression. 792 00:50:36,620 --> 00:50:39,180 793 00:50:39,180 --> 00:50:40,950 This turned into something like this. 794 00:50:40,950 --> 00:50:44,520 795 00:50:44,520 --> 00:50:47,760 Now, however, if I evaluate a lambda expression, I have to 796 00:50:47,760 --> 00:50:49,010 capture the environment. 797 00:50:49,010 --> 00:50:51,410 798 00:50:51,410 --> 00:50:56,920 The reason why is because there are variables in there 799 00:50:56,920 --> 00:51:00,280 who's meaning I wish to derive from the context where this 800 00:51:00,280 --> 00:51:01,530 was written. 801 00:51:01,530 --> 00:51:04,010 802 00:51:04,010 --> 00:51:06,095 So that's why a lambda does the job. 803 00:51:06,095 --> 00:51:08,070 It's the right thing. 804 00:51:08,070 --> 00:51:17,070 And such that the forcing of a delayed expression was same 805 00:51:17,070 --> 00:51:21,090 thing as calling that with no arguments. 806 00:51:21,090 --> 00:51:24,100 It's just the opposite of this. 807 00:51:24,100 --> 00:51:28,120 Producing an environment of the call which is, in fact, 808 00:51:28,120 --> 00:51:31,713 the environment where this was defined with an extra frame in 809 00:51:31,713 --> 00:51:33,132 it that's empty. 810 00:51:33,132 --> 00:51:36,240 I don't care about that. 811 00:51:36,240 --> 00:51:42,460 Well, if we go back to this slide, since it's the case, if 812 00:51:42,460 --> 00:51:45,290 we look at this for a second, everything is the same as it 813 00:51:45,290 --> 00:51:51,980 was before except the case of applications or combinations. 814 00:51:51,980 --> 00:51:54,680 And combinations are going to do two things. 815 00:51:54,680 --> 00:51:58,010 One, is I have to evaluate the procedure-- 816 00:51:58,010 --> 00:52:00,425 forget the procedure-- by evaluating the operator. 817 00:52:00,425 --> 00:52:02,380 That's what you see right here. 818 00:52:02,380 --> 00:52:04,990 I have to make sure that that's current, that is not a 819 00:52:04,990 --> 00:52:08,530 delayed object, and evaluate that to the point where it's 820 00:52:08,530 --> 00:52:10,730 forced now. 821 00:52:10,730 --> 00:52:18,460 And then I have to somehow apply that to the operands. 822 00:52:18,460 --> 00:52:20,040 But I have to keep the environment, pass that 823 00:52:20,040 --> 00:52:21,530 environmental along. 824 00:52:21,530 --> 00:52:23,710 So some of those operands I may have to delay. 825 00:52:23,710 --> 00:52:29,302 I may have to attach that environment to those operands. 826 00:52:29,302 --> 00:52:32,990 This is a rather complicated thing happening here. 827 00:52:32,990 --> 00:52:34,240 Looking at that in apply. 828 00:52:34,240 --> 00:52:36,400 829 00:52:36,400 --> 00:52:39,370 Apply, well it has a primitive procedure 830 00:52:39,370 --> 00:52:42,610 thing just like before. 831 00:52:42,610 --> 00:52:44,390 But the compound one is a little more interesting. 832 00:52:44,390 --> 00:52:47,250 833 00:52:47,250 --> 00:52:50,920 I have to evaluate the body, just as before, in an 834 00:52:50,920 --> 00:52:56,010 environment which is the result of binding some formal 835 00:52:56,010 --> 00:53:00,290 parameters to arguments in the environment. 836 00:53:00,290 --> 00:53:01,530 That's true. 837 00:53:01,530 --> 00:53:03,070 The environment is the one that comes from 838 00:53:03,070 --> 00:53:03,820 the procedure now. 839 00:53:03,820 --> 00:53:08,040 It's a lexical language, statically bound. 840 00:53:08,040 --> 00:53:11,230 However, one thing I have to do is strip off the 841 00:53:11,230 --> 00:53:12,960 declarations to get the names of the variables. 842 00:53:12,960 --> 00:53:15,450 That's what this guy does, vnames. 843 00:53:15,450 --> 00:53:17,940 And the other thing I have to do is process these 844 00:53:17,940 --> 00:53:21,770 declarations, deciding which of these operands-- 845 00:53:21,770 --> 00:53:24,150 that's the operands now, as opposed to the arguments-- 846 00:53:24,150 --> 00:53:28,010 which of these operands to evaluate, and which of them 847 00:53:28,010 --> 00:53:33,770 are to be encapsulated in delays of some sort. 848 00:53:33,770 --> 00:53:37,280 849 00:53:37,280 --> 00:53:40,720 The other thing you see here is that we got a primitive, a 850 00:53:40,720 --> 00:53:43,170 primitive like plus, had better 851 00:53:43,170 --> 00:53:45,820 get at the real operands. 852 00:53:45,820 --> 00:53:47,690 So here is a place where we're going to have to force them. 853 00:53:47,690 --> 00:53:49,306 And we're going to look at what evlist is going to have 854 00:53:49,306 --> 00:53:51,340 to do a bunch of forces. 855 00:53:51,340 --> 00:53:52,780 So we have two different kinds of evlist now. 856 00:53:52,780 --> 00:53:55,980 We have evlist and gevlist. Gevlist is going to wrap 857 00:53:55,980 --> 00:53:59,870 delays around some things and force others, evaluate others. 858 00:53:59,870 --> 00:54:07,900 And this guy's going to do some forcing of things. 859 00:54:07,900 --> 00:54:10,770 Just looking at this a little bit, this is a game you must 860 00:54:10,770 --> 00:54:12,250 play for yourself, you know. 861 00:54:12,250 --> 00:54:14,870 It's not something that you're going to see all possible 862 00:54:14,870 --> 00:54:19,730 variations on an evaluator talking to me. 863 00:54:19,730 --> 00:54:21,410 What you have to do is do this for yourself. 864 00:54:21,410 --> 00:54:24,610 And after you feel this, you play this a bit, you get to 865 00:54:24,610 --> 00:54:26,580 see all the possible design decisions and what they might 866 00:54:26,580 --> 00:54:29,930 mean, and how they interact with each other. 867 00:54:29,930 --> 00:54:33,160 So what languages might have in them. 868 00:54:33,160 --> 00:54:35,340 And what are some of the consistent sets that make a 869 00:54:35,340 --> 00:54:37,200 legitimate language. 870 00:54:37,200 --> 00:54:39,135 Whereas what things are complicated kluges that are 871 00:54:39,135 --> 00:54:41,850 just piles of junk. 872 00:54:41,850 --> 00:54:45,050 So evlist of course, over here, just as I said, is a 873 00:54:45,050 --> 00:54:49,450 list of operands which are going to be undelayed after 874 00:54:49,450 --> 00:54:50,750 evaluation. 875 00:54:50,750 --> 00:54:53,600 So these are going to be forced, whatever 876 00:54:53,600 --> 00:54:56,050 that's going to mean. 877 00:54:56,050 --> 00:54:58,490 And gevlist, which is the next thing-- 878 00:54:58,490 --> 00:55:01,320 879 00:55:01,320 --> 00:55:04,040 Thank you. 880 00:55:04,040 --> 00:55:09,810 What we see here, well there's a couple of possibilities. 881 00:55:09,810 --> 00:55:13,750 Either it's a normal, ordinary thing, a symbol sitting there 882 00:55:13,750 --> 00:55:18,020 like the predicate in the unless, and that's 883 00:55:18,020 --> 00:55:19,390 what we have here. 884 00:55:19,390 --> 00:55:21,710 In which case, this is intended to be evaluated in 885 00:55:21,710 --> 00:55:23,340 applicative order. 886 00:55:23,340 --> 00:55:25,630 And it's, essentially, just what we had before. 887 00:55:25,630 --> 00:55:30,400 It's mapping eval down the list. In other words, I 888 00:55:30,400 --> 00:55:35,690 evaluate the first expression and continue gevlisting the 889 00:55:35,690 --> 00:55:37,900 CDR of the expression in the environment. 890 00:55:37,900 --> 00:55:43,600 However, it's possible that this is a name parameter. 891 00:55:43,600 --> 00:55:47,320 If it's a name parameter, I want to put a delay in which 892 00:55:47,320 --> 00:55:53,480 combines that expression, which I'm calling by name, 893 00:55:53,480 --> 00:55:59,250 with the environment that's available at this time and 894 00:55:59,250 --> 00:56:02,790 passing that as the parameter. 895 00:56:02,790 --> 00:56:04,350 And this is part of the mapping process 896 00:56:04,350 --> 00:56:05,600 that you see here. 897 00:56:05,600 --> 00:56:09,070 898 00:56:09,070 --> 00:56:12,040 The only other interesting place in this 899 00:56:12,040 --> 00:56:14,700 interpreter is cond. 900 00:56:14,700 --> 00:56:16,440 People tend to write this thing, and then they leave 901 00:56:16,440 --> 00:56:18,550 this one out. 902 00:56:18,550 --> 00:56:20,510 There's a place where you have to force. 903 00:56:20,510 --> 00:56:25,260 Conditionals have to know whether or not the answer is 904 00:56:25,260 --> 00:56:25,990 true or false. 905 00:56:25,990 --> 00:56:28,550 It's like a primitive. 906 00:56:28,550 --> 00:56:31,890 When you do a conditional, you have to force. 907 00:56:31,890 --> 00:56:32,880 Now, I'm not going to look at any more 908 00:56:32,880 --> 00:56:34,350 of this in any detail. 909 00:56:34,350 --> 00:56:36,750 It isn't very exciting. 910 00:56:36,750 --> 00:56:38,990 And what's left is how you make delays. 911 00:56:38,990 --> 00:56:42,680 Well, delays are data structures which contain an 912 00:56:42,680 --> 00:56:44,840 expression, an environment, and a type on them. 913 00:56:44,840 --> 00:56:46,680 And it says they're a thunk. 914 00:56:46,680 --> 00:56:50,100 That comes from ALGOL language, and it's claimed to 915 00:56:50,100 --> 00:56:52,970 be the sound of something being pushed on a stack. 916 00:56:52,970 --> 00:56:53,410 I don't know. 917 00:56:53,410 --> 00:56:57,830 I was not an ALGOLician or an ALGOLite or whatever, so I 918 00:56:57,830 --> 00:56:58,740 don't know. 919 00:56:58,740 --> 00:57:00,270 But that's what was claimed. 920 00:57:00,270 --> 00:57:03,400 And undelay is something which will recursively undelay 921 00:57:03,400 --> 00:57:07,860 thunks until the thunk becomes something which isn't a thunk. 922 00:57:07,860 --> 00:57:09,930 This is the way you implement a call by name 923 00:57:09,930 --> 00:57:12,050 like thing in ALGOL. 924 00:57:12,050 --> 00:57:15,210 And that's about all there is. 925 00:57:15,210 --> 00:57:16,460 Are there any questions? 926 00:57:16,460 --> 00:57:26,840 927 00:57:26,840 --> 00:57:27,560 AUDIENCE: Gerry? 928 00:57:27,560 --> 00:57:29,626 PROFESSOR: Yes, Vesko? 929 00:57:29,626 --> 00:57:33,900 AUDIENCE: I noticed you avoided calling by name in the 930 00:57:33,900 --> 00:57:38,480 primitive procedures, I was wondering what 931 00:57:38,480 --> 00:57:39,350 cause you have on that? 932 00:57:39,350 --> 00:57:40,070 You never need that? 933 00:57:40,070 --> 00:57:44,720 PROFESSOR: Vesko is asking if it's ever reasonable to call a 934 00:57:44,720 --> 00:57:47,140 primitive procedure by name? 935 00:57:47,140 --> 00:57:49,270 The answer is, yes. 936 00:57:49,270 --> 00:57:51,680 There's one particular case where it's reasonable, 937 00:57:51,680 --> 00:57:52,930 actually two. 938 00:57:52,930 --> 00:57:56,050 939 00:57:56,050 --> 00:57:59,250 Construction of a data structure like cons where 940 00:57:59,250 --> 00:58:01,100 making an array if you have arrays with 941 00:58:01,100 --> 00:58:03,690 any number of elements. 942 00:58:03,690 --> 00:58:07,440 It's unnecessary to evaluate those arguments. 943 00:58:07,440 --> 00:58:10,180 All you need is promises to evaluate those arguments if 944 00:58:10,180 --> 00:58:11,160 you look at them. 945 00:58:11,160 --> 00:58:17,310 If I cons together two things, then I could cons together the 946 00:58:17,310 --> 00:58:21,830 promises just as easily as I can cons together the things. 947 00:58:21,830 --> 00:58:23,720 And it's not even when I CAR CDR them that I 948 00:58:23,720 --> 00:58:24,840 have to look at them. 949 00:58:24,840 --> 00:58:26,150 That just gets out the promises and 950 00:58:26,150 --> 00:58:28,260 passes them to somebody. 951 00:58:28,260 --> 00:58:31,320 That's why the lambda calculus definition, the Alonzo Church 952 00:58:31,320 --> 00:58:34,420 definition of CAR, CDR, and cons makes sense. 953 00:58:34,420 --> 00:58:36,630 It's because no work is done in CAR, CDR, and cons, it's 954 00:58:36,630 --> 00:58:40,760 just shuffling data, it's just routing, if you will. 955 00:58:40,760 --> 00:58:42,960 However, the things that do have to look at data are 956 00:58:42,960 --> 00:58:45,280 things like plus. 957 00:58:45,280 --> 00:58:47,910 Because they have a look at the bits that the numbers are 958 00:58:47,910 --> 00:58:50,220 made out of, unless they're lambda calculus 959 00:58:50,220 --> 00:58:52,460 numbers which are funny. 960 00:58:52,460 --> 00:58:54,630 They have to look at the bits to be able to crunch them 961 00:58:54,630 --> 00:58:55,880 together to do the add. 962 00:58:55,880 --> 00:58:59,210 963 00:58:59,210 --> 00:59:03,280 So, in fact, data constructors, data selectors, 964 00:59:03,280 --> 00:59:08,500 and, in fact, things that side-effect data objects don't 965 00:59:08,500 --> 00:59:13,300 need to do any forcing in the laziest possible interpreters. 966 00:59:13,300 --> 00:59:16,460 967 00:59:16,460 --> 00:59:18,700 On the other hand predicates on data structures have to. 968 00:59:18,700 --> 00:59:21,710 969 00:59:21,710 --> 00:59:23,560 Is this a pair? 970 00:59:23,560 --> 00:59:24,640 Or is it a symbol? 971 00:59:24,640 --> 00:59:25,690 Well, you better find out. 972 00:59:25,690 --> 00:59:26,940 You got to look at it then. 973 00:59:26,940 --> 00:59:30,300 974 00:59:30,300 --> 00:59:31,550 Any other questions? 975 00:59:31,550 --> 00:59:40,050 976 00:59:40,050 --> 00:59:41,610 Oh, well, I suppose it's time for a break. 977 00:59:41,610 --> 00:59:42,106 Thank you. 978 00:59:42,106 --> 01:00:02,950 [MUSIC PLAYING] 979 01:00:02,950 --> 01:00:04,200 and 980 01:00:04,200 --> 01:00:05,972 ================================================ FILE: SrtEN/lec8a_512kb.mp4.srt ================================================ 1 00:00:00,000 --> 00:00:17,814 [MUSIC PLAYING BY J.S. BACH] 2 00:00:17,814 --> 00:00:20,040 PROFESSOR: The last time we began having a look at how 3 00:00:20,040 --> 00:00:22,132 languages are constructed. 4 00:00:22,132 --> 00:00:26,050 Remember the main point that an evaluator for, LISP, say, 5 00:00:26,050 --> 00:00:27,580 has two main elements. 6 00:00:27,580 --> 00:00:36,350 There is EVAL, and EVAL's job is to take in an expression 7 00:00:36,350 --> 00:00:43,820 and an environment and turn that into a procedure and some 8 00:00:43,820 --> 00:00:46,635 arguments and pass that off to APPLY. 9 00:00:46,635 --> 00:00:49,410 10 00:00:49,410 --> 00:00:52,250 And APPLY takes the procedure in the arguments, turns that 11 00:00:52,250 --> 00:00:55,680 back into, in a general case, another expression to be 12 00:00:55,680 --> 00:00:58,280 evaluated in another environment and passes that 13 00:00:58,280 --> 00:01:00,770 off to EVAL, which passes it to APPLY, and there's this 14 00:01:00,770 --> 00:01:02,750 whole big circle where things go around and around and 15 00:01:02,750 --> 00:01:05,519 around until you get either to some very primitive data or to 16 00:01:05,519 --> 00:01:07,740 a primitive procedure. 17 00:01:07,740 --> 00:01:12,080 See, what this cycle has to do with is unwinding the means of 18 00:01:12,080 --> 00:01:15,020 combination and the means of abstraction in the language. 19 00:01:15,020 --> 00:01:17,870 So for instance, you have a procedure in LISP-- a 20 00:01:17,870 --> 00:01:21,320 procedure is a general way of saying, I want to be able to 21 00:01:21,320 --> 00:01:25,392 evaluate this expression for any value of the arguments, 22 00:01:25,392 --> 00:01:27,670 and that's sort of what's going on here. 23 00:01:27,670 --> 00:01:28,510 That's what APPLY does. 24 00:01:28,510 --> 00:01:30,770 It says the general thing coming in with the arguments 25 00:01:30,770 --> 00:01:33,380 reduces to the expression that's the body, and then if 26 00:01:33,380 --> 00:01:35,790 that's a compound expression or another procedure 27 00:01:35,790 --> 00:01:40,440 application, the thing will go around and around the circle. 28 00:01:40,440 --> 00:01:43,040 Anyway, that's sort of the basic structure of gee, pretty 29 00:01:43,040 --> 00:01:45,120 much any interpreter. 30 00:01:45,120 --> 00:01:46,720 The other thing that you saw is once you have the 31 00:01:46,720 --> 00:01:49,080 interpreter in your hands, you have all this power to start 32 00:01:49,080 --> 00:01:49,870 playing with the language. 33 00:01:49,870 --> 00:01:53,390 So you can make it dynamically scoped, or you can put in 34 00:01:53,390 --> 00:01:55,960 normal order evaluation, or you can add new forms to the 35 00:01:55,960 --> 00:01:57,680 language, whatever you like. 36 00:01:57,680 --> 00:02:00,570 Or more generally, there's this notion of metalinguistic 37 00:02:00,570 --> 00:02:07,930 abstraction, which says that part of your perspective as an 38 00:02:07,930 --> 00:02:09,970 engineer, as a software engineer, but as an engineer 39 00:02:09,970 --> 00:02:15,270 in general is that you can gain control of complexity by 40 00:02:15,270 --> 00:02:18,010 inventing new languages sometimes. 41 00:02:18,010 --> 00:02:22,830 See, one way to think about computer programming is that 42 00:02:22,830 --> 00:02:25,170 it only incidentally has to do with getting a 43 00:02:25,170 --> 00:02:26,440 computer to do something. 44 00:02:26,440 --> 00:02:29,220 Primarily what a computer program has to do with, it's a 45 00:02:29,220 --> 00:02:33,270 way of expressing ideas with communicating ideas. 46 00:02:33,270 --> 00:02:36,300 And sometimes when you want to communicate new kinds of 47 00:02:36,300 --> 00:02:39,770 ideas, you'd like to invent new modes of expressing that. 48 00:02:39,770 --> 00:02:44,300 Well, today we're going to apply this framework to build 49 00:02:44,300 --> 00:02:45,730 a new language. 50 00:02:45,730 --> 00:02:48,140 See, once we have the basic idea of the interpreter, you 51 00:02:48,140 --> 00:02:50,830 can pretty much go build any language that you like. 52 00:02:50,830 --> 00:02:54,370 So for example, we can go off and build Pascal. 53 00:02:54,370 --> 00:02:58,820 And gee, we would worry about syntax and parsing and various 54 00:02:58,820 --> 00:03:01,450 kinds of compiler optimizations, and there are 55 00:03:01,450 --> 00:03:05,580 people who make honest livings doing that, but at the level 56 00:03:05,580 --> 00:03:09,100 of abstraction that we're talking, a Pascal interpreter 57 00:03:09,100 --> 00:03:13,020 would not look very different at all from what you saw Gerry 58 00:03:13,020 --> 00:03:15,350 do last time. 59 00:03:15,350 --> 00:03:18,190 Instead of that, we'll spend today building a really 60 00:03:18,190 --> 00:03:23,400 different language, a language that encourages you to think 61 00:03:23,400 --> 00:03:26,980 about programming not in terms of procedures, but in a really 62 00:03:26,980 --> 00:03:29,090 different way. 63 00:03:29,090 --> 00:03:33,650 And the lecture today is going to be at two levels 64 00:03:33,650 --> 00:03:34,810 simultaneously. 65 00:03:34,810 --> 00:03:37,210 On the one hand, I'm going to show you what this language 66 00:03:37,210 --> 00:03:40,410 looks like, and on the other hand, I'll show you how it's 67 00:03:40,410 --> 00:03:41,010 implemented. 68 00:03:41,010 --> 00:03:43,250 And we'll build an implementation in LISP and see 69 00:03:43,250 --> 00:03:44,220 how that works. 70 00:03:44,220 --> 00:03:48,730 And you should be drawing lessons on two levels. 71 00:03:48,730 --> 00:03:52,190 The first is to realize just how different a 72 00:03:52,190 --> 00:03:53,790 language can be. 73 00:03:53,790 --> 00:03:57,830 So if you think that the jump from Fortran to LISP is a big 74 00:03:57,830 --> 00:04:01,560 deal, you haven't seen anything yet. 75 00:04:01,560 --> 00:04:05,660 And secondly, you'll see that even with such a very 76 00:04:05,660 --> 00:04:08,590 different language, which will turn out to not have 77 00:04:08,590 --> 00:04:12,260 procedures at all and not talk about functions at all, there 78 00:04:12,260 --> 00:04:16,570 will still be this basic cycle of eval and apply that's 79 00:04:16,570 --> 00:04:19,170 unwinds the means of combination and the means an 80 00:04:19,170 --> 00:04:20,950 abstraction. 81 00:04:20,950 --> 00:04:24,430 And then thirdly, as kind of a minor but elegant technical 82 00:04:24,430 --> 00:04:27,720 point, you'll see a nice use of streams to avoid 83 00:04:27,720 --> 00:04:28,970 backtracking. 84 00:04:28,970 --> 00:04:32,330 85 00:04:32,330 --> 00:04:35,860 OK, well, I said that this language is very different. 86 00:04:35,860 --> 00:04:41,620 To explain that, let's go back to the very first idea that we 87 00:04:41,620 --> 00:04:44,710 talked about in this course, and that was the idea of the 88 00:04:44,710 --> 00:04:48,780 distinction between the declarative knowledge of 89 00:04:48,780 --> 00:04:50,240 mathematics-- 90 00:04:50,240 --> 00:04:55,470 the definition of a square root as a mathematical truth-- 91 00:04:55,470 --> 00:04:59,080 and the idea that computer science talks about the how to 92 00:04:59,080 --> 00:04:59,810 knowledge-- 93 00:04:59,810 --> 00:05:03,700 contrast that definition of square root with a program to 94 00:05:03,700 --> 00:05:05,970 compute a square root. 95 00:05:05,970 --> 00:05:08,042 That's where we started off. 96 00:05:08,042 --> 00:05:11,830 Well, wouldn't it be great if you could somehow bridge this 97 00:05:11,830 --> 00:05:16,030 gap and make a programming language which sort of did 98 00:05:16,030 --> 00:05:20,510 things, but you talked about it in terms of truth, in 99 00:05:20,510 --> 00:05:22,380 declarative terms? 100 00:05:22,380 --> 00:05:24,110 So that would be a programming language in 101 00:05:24,110 --> 00:05:27,690 which you specify facts. 102 00:05:27,690 --> 00:05:28,880 You tell it what is. 103 00:05:28,880 --> 00:05:30,950 You say what is true. 104 00:05:30,950 --> 00:05:34,220 And then when you want an answer, somehow the language 105 00:05:34,220 --> 00:05:38,560 has built into it automatically general kinds of 106 00:05:38,560 --> 00:05:41,200 how to knowledge so it can just take your facts and it 107 00:05:41,200 --> 00:05:44,180 can evolve these methods on its on using the facts you 108 00:05:44,180 --> 00:05:46,200 gave it and maybe some general rules of logic. 109 00:05:46,200 --> 00:05:49,330 110 00:05:49,330 --> 00:05:53,920 So for instance, I might go up to this program and start 111 00:05:53,920 --> 00:05:55,645 telling it some things. 112 00:05:55,645 --> 00:06:08,920 So I might tell it that the son of Adam is Abel. 113 00:06:08,920 --> 00:06:17,660 And I might tell it that the son of Adam is Cain. 114 00:06:17,660 --> 00:06:24,670 And I might tell it that the son of Cain is Enoch. 115 00:06:24,670 --> 00:06:27,502 116 00:06:27,502 --> 00:06:37,550 And I might tell it that the son of Enoch is Irad, and all 117 00:06:37,550 --> 00:06:41,190 through the rest of our chapter whatever of Genesis, 118 00:06:41,190 --> 00:06:45,010 which ends up ending in Adah, by the way, and this shows the 119 00:06:45,010 --> 00:06:48,760 genealogy of Adah from Cain. 120 00:06:48,760 --> 00:06:52,520 Anyway, once you tell it these facts, you 121 00:06:52,520 --> 00:06:53,510 might ask it things. 122 00:06:53,510 --> 00:06:58,560 You might go up to your language and say, who's the 123 00:06:58,560 --> 00:07:00,420 son of Adam? 124 00:07:00,420 --> 00:07:03,480 And you can very easily imagine having a little 125 00:07:03,480 --> 00:07:06,460 general purpose search program which would be able to go 126 00:07:06,460 --> 00:07:08,800 through and in response to that say, oh yeah, there are 127 00:07:08,800 --> 00:07:10,930 two answers: the son of Adam is Abel and the 128 00:07:10,930 --> 00:07:14,140 son of Adam is Cain. 129 00:07:14,140 --> 00:07:19,350 Or you might say, based on the very same facts, who is Cain 130 00:07:19,350 --> 00:07:21,950 the son of? 131 00:07:21,950 --> 00:07:25,520 And then you can imagine generating another slightly 132 00:07:25,520 --> 00:07:29,510 different search program which would be able to go through 133 00:07:29,510 --> 00:07:33,760 and checked for who is Cain, and son of, and 134 00:07:33,760 --> 00:07:35,890 come up with Adam. 135 00:07:35,890 --> 00:07:40,300 Or you might say, what's the relationship 136 00:07:40,300 --> 00:07:42,070 between Cain and Enoch? 137 00:07:42,070 --> 00:07:46,340 And again, a minor variant on that search program. 138 00:07:46,340 --> 00:07:48,160 You could figure out that it said son of. 139 00:07:48,160 --> 00:07:52,880 140 00:07:52,880 --> 00:07:56,960 But even here in this very simple example, what you see 141 00:07:56,960 --> 00:08:00,460 is that a single fact, see, a single fact like the son of 142 00:08:00,460 --> 00:08:04,230 Adam is Cain can be used to answer 143 00:08:04,230 --> 00:08:06,520 different kinds of questions. 144 00:08:06,520 --> 00:08:10,540 You can say, who's the son of, or you can say who's the son 145 00:08:10,540 --> 00:08:12,220 of Adam, or you can say what's the relation 146 00:08:12,220 --> 00:08:12,970 between Adam and Cain? 147 00:08:12,970 --> 00:08:17,370 Those are different questions being run by different 148 00:08:17,370 --> 00:08:22,474 traditional procedures all based on the same fact. 149 00:08:22,474 --> 00:08:24,960 And that's going to be the essence of the power of this 150 00:08:24,960 --> 00:08:30,050 programming style, that one piece of declarative knowledge 151 00:08:30,050 --> 00:08:33,150 can be used as the basis for a lot of different kinds of 152 00:08:33,150 --> 00:08:36,440 how-to knowledge, as opposed to the kinds of procedures 153 00:08:36,440 --> 00:08:39,010 we're writing where you sort of tell it what input you're 154 00:08:39,010 --> 00:08:41,490 giving it and what answer you want. 155 00:08:41,490 --> 00:08:43,710 So for instance, our square root program can perfectly 156 00:08:43,710 --> 00:08:48,900 well answer the question, what's the square root of 144? 157 00:08:48,900 --> 00:08:51,290 But in principle, the mathematical definition of 158 00:08:51,290 --> 00:08:52,830 square root tells you other things. 159 00:08:52,830 --> 00:08:57,590 Like it could say, what is 17 the square root of? 160 00:08:57,590 --> 00:08:58,590 And that would be have to be answered 161 00:08:58,590 --> 00:09:01,920 by a different program. 162 00:09:01,920 --> 00:09:05,700 So the mathematical definition, or in general, the 163 00:09:05,700 --> 00:09:09,540 facts that you give it are somehow unbiased as to what 164 00:09:09,540 --> 00:09:10,900 the question is. 165 00:09:10,900 --> 00:09:13,240 Whereas the programs we tend to write specifically because 166 00:09:13,240 --> 00:09:15,230 they are how-to knowledge tend to be looking 167 00:09:15,230 --> 00:09:17,700 for a specific answer. 168 00:09:17,700 --> 00:09:19,530 So that's going to be one characteristic of what we're 169 00:09:19,530 --> 00:09:21,810 talking about. 170 00:09:21,810 --> 00:09:23,480 We can go on. 171 00:09:23,480 --> 00:09:26,420 We can imagine that we've given our language 172 00:09:26,420 --> 00:09:27,710 some sort of facts. 173 00:09:27,710 --> 00:09:30,020 Now let's give it some rules of inference. 174 00:09:30,020 --> 00:09:35,100 We can say, for instance, if the-- 175 00:09:35,100 --> 00:09:36,510 make up some syntax here-- 176 00:09:36,510 --> 00:09:41,580 if the son of x is y-- 177 00:09:41,580 --> 00:09:45,650 I'll put question marks to indicate variables here-- 178 00:09:45,650 --> 00:10:01,800 if the son of x is y and the son of y is z, then the 179 00:10:01,800 --> 00:10:09,320 grandson of x is z. 180 00:10:09,320 --> 00:10:15,370 So I can imagine telling my machine that rule and then 181 00:10:15,370 --> 00:10:17,680 being able to say, for instance, who's 182 00:10:17,680 --> 00:10:20,610 the grandson of Adam? 183 00:10:20,610 --> 00:10:24,790 Or who is Irad the grandson of? 184 00:10:24,790 --> 00:10:28,080 Or deduce all grandson relationships you possibly can 185 00:10:28,080 --> 00:10:29,330 from this information. 186 00:10:29,330 --> 00:10:31,220 187 00:10:31,220 --> 00:10:34,580 We can imagine somehow the language knowing how to do 188 00:10:34,580 --> 00:10:35,830 that automatically. 189 00:10:35,830 --> 00:10:42,640 190 00:10:42,640 --> 00:10:45,200 Let me give you maybe a little bit more concrete example. 191 00:10:45,200 --> 00:10:49,610 192 00:10:49,610 --> 00:10:53,700 Here's a procedure that merges two sorted lists. 193 00:10:53,700 --> 00:11:01,370 So x and y are two, say, lists of numbers, lists of distinct 194 00:11:01,370 --> 00:11:04,780 numbers, if you like, that are in increasing order. 195 00:11:04,780 --> 00:11:08,560 And what merge does is take two such lists and combine 196 00:11:08,560 --> 00:11:10,040 them into a list where everything's in increasing 197 00:11:10,040 --> 00:11:15,330 order, and this is a pretty easy programs that you ought 198 00:11:15,330 --> 00:11:16,390 to be able to write. 199 00:11:16,390 --> 00:11:18,860 It says, if x is empty, the answer is y. 200 00:11:18,860 --> 00:11:21,180 If y is empty, the answer is x. 201 00:11:21,180 --> 00:11:22,990 Otherwise, you compare the first two elements. 202 00:11:22,990 --> 00:11:25,540 So you pick out the first thing in x and the first thing 203 00:11:25,540 --> 00:11:31,060 in y, and then depending on which of those first elements 204 00:11:31,060 --> 00:11:35,500 is less, you stick the lower one on to the result a 205 00:11:35,500 --> 00:11:40,150 recursively merging, either chopping the first one off x 206 00:11:40,150 --> 00:11:42,400 or chopping the first one off y. 207 00:11:42,400 --> 00:11:43,960 That's a standard kind of program. 208 00:11:43,960 --> 00:11:46,470 209 00:11:46,470 --> 00:11:48,620 Let's look at the logic. 210 00:11:48,620 --> 00:11:51,660 Let's forget about the program and look at the logic on which 211 00:11:51,660 --> 00:11:53,820 that procedure is based. 212 00:11:53,820 --> 00:11:56,860 See, there's some logic which says, gee, if the first one is 213 00:11:56,860 --> 00:12:00,240 less, then we get the answer by sticking something onto the 214 00:12:00,240 --> 00:12:03,350 result of recursively merging the rest. So let's try and be 215 00:12:03,350 --> 00:12:05,420 explicit about what that logic is that's 216 00:12:05,420 --> 00:12:08,430 making the program work. 217 00:12:08,430 --> 00:12:10,130 So here's one piece. 218 00:12:10,130 --> 00:12:13,820 Here's the piece of the program which recursively 219 00:12:13,820 --> 00:12:19,980 chops down x if the first thing in x is smaller. 220 00:12:19,980 --> 00:12:22,030 And if you want to be very explicit about what the logic 221 00:12:22,030 --> 00:12:27,120 is there, what's really going on is a deduction, which says, 222 00:12:27,120 --> 00:12:31,790 if you know that some list, that we'll call cdr of x, and 223 00:12:31,790 --> 00:12:40,480 y merged to form z, and you know that a is less than the 224 00:12:40,480 --> 00:12:47,570 first thing in y, then you know that if you put a onto 225 00:12:47,570 --> 00:12:55,820 the cdr of x, then that result and y merge to form a onto z. 226 00:12:55,820 --> 00:12:58,720 And what that is, that's the underlying piece of logic-- 227 00:12:58,720 --> 00:13:01,620 I haven't written it as a program, I wrote it a sort of 228 00:13:01,620 --> 00:13:05,480 deduction that's underneath this particular clause that 229 00:13:05,480 --> 00:13:09,410 says we can use the recursion there. 230 00:13:09,410 --> 00:13:11,910 And then similar, here's the other clause 231 00:13:11,910 --> 00:13:14,000 just to complete it. 232 00:13:14,000 --> 00:13:16,880 The other clause is based on this piece of logic, which is 233 00:13:16,880 --> 00:13:19,460 almost the same and I won't go through it, and then there's 234 00:13:19,460 --> 00:13:22,730 the n cases where we tested for null, and that's based on 235 00:13:22,730 --> 00:13:26,920 the idea that for any x, x and the empty list merge to form 236 00:13:26,920 --> 00:13:30,740 an x, or for any y, the empty list and y merge to form y. 237 00:13:30,740 --> 00:13:33,360 238 00:13:33,360 --> 00:13:39,340 OK, so there's a piece of procedure and the logic on 239 00:13:39,340 --> 00:13:41,740 which it's based. 240 00:13:41,740 --> 00:13:44,750 And notice a big difference. 241 00:13:44,750 --> 00:13:51,050 The procedure looked like this: it 242 00:13:51,050 --> 00:13:52,900 said there was a box-- 243 00:13:52,900 --> 00:13:55,410 and all the things we've been doing have the characteristic 244 00:13:55,410 --> 00:13:57,890 we have boxes and things going in and things going out-- 245 00:13:57,890 --> 00:14:04,480 there was this box called merge, and in came an x and y, 246 00:14:04,480 --> 00:14:07,550 and out came an answer. 247 00:14:07,550 --> 00:14:09,340 That's the character of the procedure that we wrote. 248 00:14:09,340 --> 00:14:13,160 249 00:14:13,160 --> 00:14:14,660 These rules don't look like that. 250 00:14:14,660 --> 00:14:17,620 These rules talk about a relation. 251 00:14:17,620 --> 00:14:23,030 There's some sort of relation that in those slides I called 252 00:14:23,030 --> 00:14:25,370 mrege-to-form. 253 00:14:25,370 --> 00:14:29,200 So I said x and y merge to form z, and 254 00:14:29,200 --> 00:14:32,610 somehow this is a function. 255 00:14:32,610 --> 00:14:32,850 Right? 256 00:14:32,850 --> 00:14:36,070 The answer is a function of x and y, and here what I have is 257 00:14:36,070 --> 00:14:39,720 a relation between three things. 258 00:14:39,720 --> 00:14:43,120 And I'm not going to specify which is the input and which 259 00:14:43,120 --> 00:14:44,200 is the output. 260 00:14:44,200 --> 00:14:48,690 And the reason I want to say that is because in principle, 261 00:14:48,690 --> 00:14:51,300 we could use exactly those same logic rules to answer a 262 00:14:51,300 --> 00:14:54,570 lot of different questions. 263 00:14:54,570 --> 00:14:56,750 So we can say, for instance-- 264 00:14:56,750 --> 00:14:59,050 imagine giving our machine those rules of logic. 265 00:14:59,050 --> 00:15:01,400 Not the program, the underlying rules of logic. 266 00:15:01,400 --> 00:15:04,750 Then it ought to be able to say-- 267 00:15:04,750 --> 00:15:06,770 we could ask it-- 268 00:15:06,770 --> 00:15:20,910 1, 3, 7 and 2, 4, 8 merge to form what? 269 00:15:20,910 --> 00:15:23,880 And that's a question it ought to be able to answer. 270 00:15:23,880 --> 00:15:26,480 That's exactly the same question that our list 271 00:15:26,480 --> 00:15:28,180 procedure answered. 272 00:15:28,180 --> 00:15:33,750 But the exact same rules should also be able to answer 273 00:15:33,750 --> 00:15:41,760 a question like this: 1, 3, 7 and what merged to form 1, 2, 274 00:15:41,760 --> 00:15:45,560 3, 4, 7, 8? 275 00:15:45,560 --> 00:15:48,120 The same rules of logic can answer this, although the 276 00:15:48,120 --> 00:15:50,880 procedure we wrote can't answer that question. 277 00:15:50,880 --> 00:15:56,070 Or we might be able to say what and what 278 00:15:56,070 --> 00:16:07,900 else merge to form-- 279 00:16:07,900 --> 00:16:13,780 what and what else merge to form 1, 2, 3, 4, 7, 8? 280 00:16:13,780 --> 00:16:16,320 And the thing should be able to go through, if it really 281 00:16:16,320 --> 00:16:20,470 can apply that logic, and deduce all, whatever is, 2 to 282 00:16:20,470 --> 00:16:22,540 the sixth answers to that question. 283 00:16:22,540 --> 00:16:25,600 284 00:16:25,600 --> 00:16:28,790 It could be 1 and the rest, or it could be 1, 2 and the rest. 285 00:16:28,790 --> 00:16:32,490 Or it could be 1 and 3 and 7 and the rest. There's a whole 286 00:16:32,490 --> 00:16:33,410 bunch of answers. 287 00:16:33,410 --> 00:16:36,830 And in principle, the logic should be 288 00:16:36,830 --> 00:16:38,550 enough to deduce that. 289 00:16:38,550 --> 00:16:44,540 So there are going to be two big differences in the kind of 290 00:16:44,540 --> 00:16:48,370 program we're going to look at and not only list, but 291 00:16:48,370 --> 00:16:49,850 essentially all the programming you've probably 292 00:16:49,850 --> 00:16:54,150 done so far in pretty much any language you can think of. 293 00:16:54,150 --> 00:16:57,620 The first is, we're not going to be computing functions. 294 00:16:57,620 --> 00:17:00,800 295 00:17:00,800 --> 00:17:03,770 We're not going to be talking about things that take input 296 00:17:03,770 --> 00:17:04,410 and output. 297 00:17:04,410 --> 00:17:06,890 We're going to be talking about relations. 298 00:17:06,890 --> 00:17:09,180 And that means in principle, these relations don't have 299 00:17:09,180 --> 00:17:11,089 directionality. 300 00:17:11,089 --> 00:17:14,569 So the knowledge that you specify to answer this 301 00:17:14,569 --> 00:17:19,220 question, that same knowledge should also allow you to 302 00:17:19,220 --> 00:17:21,345 answer these other questions and conversely. 303 00:17:21,345 --> 00:17:26,310 304 00:17:26,310 --> 00:17:30,590 And the second issue is that since we're talking about 305 00:17:30,590 --> 00:17:33,150 relations, these relations don't 306 00:17:33,150 --> 00:17:35,610 necessarily have one answer. 307 00:17:35,610 --> 00:17:37,480 So that third question down there doesn't have a 308 00:17:37,480 --> 00:17:39,415 particular answer, it has a whole bunch of answers. 309 00:17:39,415 --> 00:17:42,270 310 00:17:42,270 --> 00:17:44,640 Well, that's where we're going. 311 00:17:44,640 --> 00:17:48,620 This style of programming, by the way, is called logic 312 00:17:48,620 --> 00:17:51,310 programming, for kind of obvious reasons. 313 00:17:51,310 --> 00:17:56,160 314 00:17:56,160 --> 00:18:02,440 And people who do logic programming say that-- they 315 00:18:02,440 --> 00:18:04,150 have this little phrase-- they say the point of logic 316 00:18:04,150 --> 00:18:10,190 programming is that you use logic to express what is true, 317 00:18:10,190 --> 00:18:15,190 you use logic to check whether something is true, and you use 318 00:18:15,190 --> 00:18:19,200 logic to find out what is true. 319 00:18:19,200 --> 00:18:23,300 The best known logic programming language, as you 320 00:18:23,300 --> 00:18:25,780 probably know, is called Prolog. 321 00:18:25,780 --> 00:18:31,010 The language that we're going to implement this morning is 322 00:18:31,010 --> 00:18:33,110 something we call the query language, and it essentially 323 00:18:33,110 --> 00:18:35,320 has the essence of prologue. 324 00:18:35,320 --> 00:18:38,340 It can do about the same stuff, although it's a lot 325 00:18:38,340 --> 00:18:42,390 slower because we're going to implement it in LISP rather 326 00:18:42,390 --> 00:18:44,210 than building a particular compiler. 327 00:18:44,210 --> 00:18:47,510 We're going to interpret it on top of the LISP interpreter. 328 00:18:47,510 --> 00:18:48,950 But other than that, it can do about the 329 00:18:48,950 --> 00:18:49,750 same stuff as prolog. 330 00:18:49,750 --> 00:18:52,160 It has about the same power and about the same 331 00:18:52,160 --> 00:18:54,696 limitations. 332 00:18:54,696 --> 00:18:56,120 All right, let's break for question. 333 00:18:56,120 --> 00:19:00,040 334 00:19:00,040 --> 00:19:04,010 STUDENT: Yes, could you please repeat what the three things 335 00:19:04,010 --> 00:19:06,720 you use logic programming to find? 336 00:19:06,720 --> 00:19:09,120 In other words, to find what is true, learn what is true-- 337 00:19:09,120 --> 00:19:09,840 what is the? 338 00:19:09,840 --> 00:19:10,520 PROFESSOR: Right. 339 00:19:10,520 --> 00:19:15,850 Sort of a logic programmer's little catechism. 340 00:19:15,850 --> 00:19:22,610 You use logic to express what is true, like these rules. 341 00:19:22,610 --> 00:19:26,120 You use logic to check whether something is true, and that's 342 00:19:26,120 --> 00:19:28,550 the kind of question I didn't answer here. 343 00:19:28,550 --> 00:19:29,720 I might say-- 344 00:19:29,720 --> 00:19:33,620 another question I could put down here is to say, is it 345 00:19:33,620 --> 00:19:41,400 true that 1, 3, 7 and 2, 4, 8 merge to form 1, 2, 6, 10 And 346 00:19:41,400 --> 00:19:45,690 that same logic should be enough to say no. 347 00:19:45,690 --> 00:19:49,190 So I use logic to check what is true, and then you also use 348 00:19:49,190 --> 00:19:50,480 logic to find out what's true. 349 00:19:50,480 --> 00:20:04,060 350 00:20:04,060 --> 00:20:04,570 All right. 351 00:20:04,570 --> 00:20:06,138 Let's break. 352 00:20:06,138 --> 00:20:22,106 [MUSIC PLAYING BY J.S. BACH] 353 00:20:22,106 --> 00:20:47,590 [MUSIC ENDS] 354 00:20:47,590 --> 00:21:02,901 [MUSIC PLAYING BY J.S. BACH] 355 00:21:02,901 --> 00:21:06,810 PROFESSOR: OK, let's go ahead and take a look at this query 356 00:21:06,810 --> 00:21:10,520 language and operation. 357 00:21:10,520 --> 00:21:12,890 The first thing you might notice, when I put up that 358 00:21:12,890 --> 00:21:15,390 little biblical database, is that it's nice to be able to 359 00:21:15,390 --> 00:21:18,900 ask this language questions in relation to some 360 00:21:18,900 --> 00:21:21,330 collection of facts. 361 00:21:21,330 --> 00:21:26,060 So let's start off and make a little collection of facts. 362 00:21:26,060 --> 00:21:31,700 This is a tiny fragment of personnel records for a Boston 363 00:21:31,700 --> 00:21:34,440 high tech company, and here's a piece of the personnel 364 00:21:34,440 --> 00:21:37,500 records of Ben Bitdiddle. 365 00:21:37,500 --> 00:21:41,470 And Ben Bitdiddle is the computer wizard in this 366 00:21:41,470 --> 00:21:44,660 company, he's the underpaid computer 367 00:21:44,660 --> 00:21:46,420 wizard in this company. 368 00:21:46,420 --> 00:21:49,330 His supervisor is all Oliver Warbucks, 369 00:21:49,330 --> 00:21:52,150 and here's his address. 370 00:21:52,150 --> 00:21:55,220 So the format is we're giving this information: job, salary, 371 00:21:55,220 --> 00:21:57,300 supervisor, address. 372 00:21:57,300 --> 00:21:59,250 And there are some other conventions. 373 00:21:59,250 --> 00:22:01,570 Computer here means that Ben works in the computer 374 00:22:01,570 --> 00:22:03,590 division, and his position in the 375 00:22:03,590 --> 00:22:06,440 computer division is wizard. 376 00:22:06,440 --> 00:22:07,580 Here's somebody else. 377 00:22:07,580 --> 00:22:13,860 Alyssa, Alyssa P. Hacker is a computer programmer, and she 378 00:22:13,860 --> 00:22:17,550 works for Ben, and she lives in Cambridge. 379 00:22:17,550 --> 00:22:19,990 And there's another programmer who works for Ben 380 00:22:19,990 --> 00:22:22,820 who's Lem E. Tweakit. 381 00:22:22,820 --> 00:22:26,330 And there's a programmer trainee, who is Louis 382 00:22:26,330 --> 00:22:30,100 Reasoner, and he works for Alyssa. 383 00:22:30,100 --> 00:22:34,830 And the big wheel of the company doesn't work for 384 00:22:34,830 --> 00:22:37,010 anybody, right? 385 00:22:37,010 --> 00:22:38,110 That's Oliver Warbucks. 386 00:22:38,110 --> 00:22:43,080 Anyway, what we're going to do is ask questions about that 387 00:22:43,080 --> 00:22:44,971 little world. 388 00:22:44,971 --> 00:22:47,410 And that'll be a sample world that we're 389 00:22:47,410 --> 00:22:48,660 going to do logic in. 390 00:22:48,660 --> 00:22:51,420 391 00:22:51,420 --> 00:22:55,810 Let me just write up here, for probably the last time, what I 392 00:22:55,810 --> 00:22:57,600 said is the very most important thing you should get 393 00:22:57,600 --> 00:23:00,760 out of this course, and that is, when somebody tells you 394 00:23:00,760 --> 00:23:03,440 about a language, you say, fine-- 395 00:23:03,440 --> 00:23:15,050 what are the primitives, what are the means of combination, 396 00:23:15,050 --> 00:23:18,480 how do you put the primitives together, and then how do you 397 00:23:18,480 --> 00:23:24,690 abstract them, how do you abstract the compound pieces 398 00:23:24,690 --> 00:23:26,740 so you can use them as pieces to make something more 399 00:23:26,740 --> 00:23:28,500 complicated? 400 00:23:28,500 --> 00:23:31,440 And we've said this a whole bunch of times already, but 401 00:23:31,440 --> 00:23:32,690 it's worth saying again. 402 00:23:32,690 --> 00:23:36,210 403 00:23:36,210 --> 00:23:36,670 Let's start. 404 00:23:36,670 --> 00:23:38,040 The primitives. 405 00:23:38,040 --> 00:23:41,660 Well, there's really only one primitive, and the primitive 406 00:23:41,660 --> 00:23:44,400 in this language is called a query. 407 00:23:44,400 --> 00:23:46,810 A primitive query. 408 00:23:46,810 --> 00:23:48,060 Let's look at some primitive queries. 409 00:23:48,060 --> 00:23:52,160 410 00:23:52,160 --> 00:23:53,100 Job x. 411 00:23:53,100 --> 00:23:55,550 Who is a computer programmer? 412 00:23:55,550 --> 00:24:04,700 Or find every fact in the database that matches job of 413 00:24:04,700 --> 00:24:06,640 the x is computer programmer. 414 00:24:06,640 --> 00:24:08,470 And you see a little syntax here. 415 00:24:08,470 --> 00:24:11,330 Things without question marks are meant to be literal, 416 00:24:11,330 --> 00:24:13,940 question mark x means that's a variable, and this thing will 417 00:24:13,940 --> 00:24:18,110 match, for example, the fact that Alyssa P. Hacker is a 418 00:24:18,110 --> 00:24:21,930 computer programmer, or x is Alyssa P. Hacker. 419 00:24:21,930 --> 00:24:26,820 420 00:24:26,820 --> 00:24:29,170 Or more generally, I could have something with two 421 00:24:29,170 --> 00:24:30,750 variables in it. 422 00:24:30,750 --> 00:24:39,530 I could say, the job of x is computer something, and 423 00:24:39,530 --> 00:24:42,140 that'll match computer wizard. 424 00:24:42,140 --> 00:24:44,865 So there's something here: type will match wizard, or 425 00:24:44,865 --> 00:24:49,390 type will match programmer, or x might match 426 00:24:49,390 --> 00:24:50,370 various certain things. 427 00:24:50,370 --> 00:24:53,270 So there are, in our little example, only three facts in 428 00:24:53,270 --> 00:24:55,150 that database that match that query. 429 00:24:55,150 --> 00:24:59,210 430 00:24:59,210 --> 00:25:04,910 Let's see, just to show you some syntax, the same query, 431 00:25:04,910 --> 00:25:11,490 this query doesn't match the job of x, doesn't match Lewis 432 00:25:11,490 --> 00:25:13,200 Reasoner, the reason for that is when I write something 433 00:25:13,200 --> 00:25:17,160 here, what I mean is that this is going to be a list of two 434 00:25:17,160 --> 00:25:22,730 symbols, of which the first is the word computer, and the 435 00:25:22,730 --> 00:25:24,810 second can be anything. 436 00:25:24,810 --> 00:25:28,130 And Lewis's job description here has three symbols, so it 437 00:25:28,130 --> 00:25:30,340 doesn't match. 438 00:25:30,340 --> 00:25:35,360 And just to show you a little bit of syntax, the more 439 00:25:35,360 --> 00:25:37,920 general thing I might want to type is a thing with a dot 440 00:25:37,920 --> 00:25:42,550 here, and this is just standard this notation for 441 00:25:42,550 --> 00:25:46,560 saying, this is a list, of which the first element is the 442 00:25:46,560 --> 00:25:49,350 word computers, and THE REST, is something 443 00:25:49,350 --> 00:25:50,600 that I'll call type. 444 00:25:50,600 --> 00:25:53,730 445 00:25:53,730 --> 00:25:56,930 So this one would match. 446 00:25:56,930 --> 00:26:00,000 Lewis's job is computer programmer trainee, and type 447 00:26:00,000 --> 00:26:04,690 here would be the cdr of this list. It would be the list 448 00:26:04,690 --> 00:26:06,960 programmer trainee. 449 00:26:06,960 --> 00:26:08,410 And that kind of dot processing is done 450 00:26:08,410 --> 00:26:10,460 automatically by the LISP reader. 451 00:26:10,460 --> 00:26:15,900 452 00:26:15,900 --> 00:26:17,760 Well, let's actually try this. 453 00:26:17,760 --> 00:26:20,810 The idea is I'm going to type in queries in this language, 454 00:26:20,810 --> 00:26:23,630 and answers will come out. 455 00:26:23,630 --> 00:26:25,180 Let's look at this. 456 00:26:25,180 --> 00:26:30,000 I can go up and say, who works in the computer division? 457 00:26:30,000 --> 00:26:39,730 Job of x is computer dot y. 458 00:26:39,730 --> 00:26:42,562 Doesn't matter what I call the dummy variables. 459 00:26:42,562 --> 00:26:45,690 It says the answers to that, and it's found four answers. 460 00:26:45,690 --> 00:26:48,650 461 00:26:48,650 --> 00:26:51,380 Or I can go off and say, tell me about everybody's 462 00:26:51,380 --> 00:26:52,505 supervisor. 463 00:26:52,505 --> 00:26:56,610 So I'll put in the query, the primitive query, the 464 00:26:56,610 --> 00:26:59,390 supervisor of x is y. 465 00:26:59,390 --> 00:27:02,860 466 00:27:02,860 --> 00:27:05,540 There are all the supervisor relationships I know. 467 00:27:05,540 --> 00:27:08,830 Or I could go type in, who lives in Cambridge? 468 00:27:08,830 --> 00:27:20,670 So I can say, the address of x is Cambridge dot anything. 469 00:27:20,670 --> 00:27:25,090 470 00:27:25,090 --> 00:27:26,585 And only one person lives in Cambridge. 471 00:27:26,585 --> 00:27:30,820 472 00:27:30,820 --> 00:27:32,170 OK, so those are primitive queries. 473 00:27:32,170 --> 00:27:34,460 And you see what happens to basic interaction with the 474 00:27:34,460 --> 00:27:38,140 system is you type in a query, and it types out 475 00:27:38,140 --> 00:27:39,620 all possible answers. 476 00:27:39,620 --> 00:27:43,100 Or another way to say that: it finds out all the possible 477 00:27:43,100 --> 00:27:45,330 values of those variables x and y or t or whatever I've 478 00:27:45,330 --> 00:27:50,380 called them, and it types out all ways of taking that query 479 00:27:50,380 --> 00:27:53,080 and instantiating it-- 480 00:27:53,080 --> 00:27:56,250 remember that from the rule system lecture-- instantiates 481 00:27:56,250 --> 00:27:59,150 the query with all possible values for those variables and 482 00:27:59,150 --> 00:28:01,000 then types out all of them. 483 00:28:01,000 --> 00:28:02,370 And there are a lot of ways you can 484 00:28:02,370 --> 00:28:03,350 arrange a logic language. 485 00:28:03,350 --> 00:28:06,010 Prolog, for instance, does something slightly different. 486 00:28:06,010 --> 00:28:08,980 Rather than typing back your query, prolog would type out, 487 00:28:08,980 --> 00:28:12,230 x equals this and y equals that, or x sequels this and y 488 00:28:12,230 --> 00:28:12,650 equals that. 489 00:28:12,650 --> 00:28:16,430 And that's a very surface level thing, you can decide 490 00:28:16,430 --> 00:28:19,070 what you like. 491 00:28:19,070 --> 00:28:20,760 OK. 492 00:28:20,760 --> 00:28:21,340 All right. 493 00:28:21,340 --> 00:28:23,390 So the primitives in this language? 494 00:28:23,390 --> 00:28:24,570 Only one, right? 495 00:28:24,570 --> 00:28:27,230 Primitive query. 496 00:28:27,230 --> 00:28:31,360 497 00:28:31,360 --> 00:28:31,650 OK. 498 00:28:31,650 --> 00:28:34,330 Means of combination. 499 00:28:34,330 --> 00:28:39,770 Let's look at some compound queries in this language. 500 00:28:39,770 --> 00:28:41,790 Here's one. 501 00:28:41,790 --> 00:28:47,250 This one says, tell me all the people who work in the 502 00:28:47,250 --> 00:28:49,810 computer division. 503 00:28:49,810 --> 00:28:52,610 Tell me all the people who work in the computer division 504 00:28:52,610 --> 00:28:53,860 together with their supervisors. 505 00:28:53,860 --> 00:28:56,800 506 00:28:56,800 --> 00:29:00,220 The way I write that is the query is and. 507 00:29:00,220 --> 00:29:04,920 And the job of the x is computer something or other. 508 00:29:04,920 --> 00:29:07,560 And job of x is computer dot y. 509 00:29:07,560 --> 00:29:11,650 And the supervisor of x is z. 510 00:29:11,650 --> 00:29:13,570 Tell me all the people in the computer division-- 511 00:29:13,570 --> 00:29:16,460 that's this-- together with their supervisors. 512 00:29:16,460 --> 00:29:20,290 And notice in this query I have three variables-- 513 00:29:20,290 --> 00:29:23,660 x, y, and z. 514 00:29:23,660 --> 00:29:29,450 And this x is supposed to be the same as that x. 515 00:29:29,450 --> 00:29:31,560 So x works in the computer division, and the 516 00:29:31,560 --> 00:29:34,810 supervisor of x is z. 517 00:29:34,810 --> 00:29:37,250 Let's try another one. 518 00:29:37,250 --> 00:29:39,005 So one means of combination is and. 519 00:29:39,005 --> 00:29:41,540 520 00:29:41,540 --> 00:29:45,790 Who are all the people who make more than $30,000? 521 00:29:45,790 --> 00:29:51,640 And the salary of some person p is some amount a. 522 00:29:51,640 --> 00:29:54,590 523 00:29:54,590 --> 00:30:00,600 And when I go and look at a, a is greater than $30,000. 524 00:30:00,600 --> 00:30:06,300 And LISP value here is a little piece of interface that 525 00:30:06,300 --> 00:30:10,600 interfaces the query language to the underlying LISP. 526 00:30:10,600 --> 00:30:13,540 And what the LISP value allows you to do is call any LISP 527 00:30:13,540 --> 00:30:17,180 predicate inside a query. 528 00:30:17,180 --> 00:30:19,110 So here I'm using the LISP predicate greater than, so I 529 00:30:19,110 --> 00:30:21,020 say LISP value. 530 00:30:21,020 --> 00:30:21,750 This I say and. 531 00:30:21,750 --> 00:30:28,190 So all the people whose salary is greater than $30,000. 532 00:30:28,190 --> 00:30:31,270 Or here's a more complicated one. 533 00:30:31,270 --> 00:30:36,150 Tell me all the people who work in the computer division 534 00:30:36,150 --> 00:30:38,560 who do not have a supervisor who works in 535 00:30:38,560 --> 00:30:39,810 the computer division. 536 00:30:39,810 --> 00:30:42,790 537 00:30:42,790 --> 00:30:45,510 and x works in the computer division. 538 00:30:45,510 --> 00:30:47,780 The job of x is computer dot y. 539 00:30:47,780 --> 00:30:55,570 And it's not the case that both x has a supervisor z and 540 00:30:55,570 --> 00:30:59,620 the job of z is computer something or other. 541 00:30:59,620 --> 00:31:04,050 All right, so again, this x has got to be that x, and this 542 00:31:04,050 --> 00:31:05,710 z is going to be that z. 543 00:31:05,710 --> 00:31:09,390 544 00:31:09,390 --> 00:31:11,380 And then you see another means a combination, not. 545 00:31:11,380 --> 00:31:17,272 546 00:31:17,272 --> 00:31:20,880 All right, well, let's look at that. 547 00:31:20,880 --> 00:31:22,400 It works the same way. 548 00:31:22,400 --> 00:31:33,110 I can go up to the machine and say and the job of the x is 549 00:31:33,110 --> 00:31:35,400 computer dot y. 550 00:31:35,400 --> 00:31:38,480 551 00:31:38,480 --> 00:31:46,600 And the supervisor of x is z. 552 00:31:46,600 --> 00:31:50,794 And I typed that in like a query. 553 00:31:50,794 --> 00:31:55,680 And what it types back, what you see are the queries I 554 00:31:55,680 --> 00:31:58,930 typed in instantiated by all possible answers. 555 00:31:58,930 --> 00:32:02,000 And then you see there are a lot of answers. 556 00:32:02,000 --> 00:32:02,190 All right. 557 00:32:02,190 --> 00:32:05,230 So the means of combination in this language-- 558 00:32:05,230 --> 00:32:07,550 and this is why it's called a logic language-- 559 00:32:07,550 --> 00:32:09,800 are logical operations. 560 00:32:09,800 --> 00:32:16,120 Means of combinations are things like AND and NOT and 561 00:32:16,120 --> 00:32:18,490 there's one I didn't show you, which is OR. 562 00:32:18,490 --> 00:32:24,310 And then I showed you LISP value, which is not logic, of 563 00:32:24,310 --> 00:32:26,365 course, but is a little special hack to interface that 564 00:32:26,365 --> 00:32:29,250 to LISP so you can get more power. 565 00:32:29,250 --> 00:32:32,690 Those are the means of combination. 566 00:32:32,690 --> 00:32:34,160 OK, the means of abstraction. 567 00:32:34,160 --> 00:32:35,410 What we'd like to do-- 568 00:32:35,410 --> 00:32:38,330 569 00:32:38,330 --> 00:32:42,260 let's go back for second and look at that last slide. 570 00:32:42,260 --> 00:32:45,010 We might like to take very complicated thing, the idea 571 00:32:45,010 --> 00:32:48,800 that someone works in a division but does not have a 572 00:32:48,800 --> 00:32:52,400 supervisor in the division. 573 00:32:52,400 --> 00:32:56,090 And as before, name that. 574 00:32:56,090 --> 00:32:58,800 Well, if someone works in a division and does not have a 575 00:32:58,800 --> 00:33:00,950 supervisor who works in that division, that means that 576 00:33:00,950 --> 00:33:02,750 person is a big shot. 577 00:33:02,750 --> 00:33:08,370 So let's make a rule that somebody x is a big shot in 578 00:33:08,370 --> 00:33:16,760 some department if x works in the department and it's not 579 00:33:16,760 --> 00:33:19,610 the case that x has a supervisor who works in the 580 00:33:19,610 --> 00:33:21,510 department. 581 00:33:21,510 --> 00:33:22,940 So this is our means of abstraction. 582 00:33:22,940 --> 00:33:24,190 This is a rule. 583 00:33:24,190 --> 00:33:26,220 584 00:33:26,220 --> 00:33:27,580 And a rule has three parts. 585 00:33:27,580 --> 00:33:30,970 586 00:33:30,970 --> 00:33:33,450 The thing that says it's a rule. 587 00:33:33,450 --> 00:33:37,530 And then there's the conclusion of the rule. 588 00:33:37,530 --> 00:33:40,000 And then there's the body of the rule. 589 00:33:40,000 --> 00:33:42,150 And you can read this as a piece of logic which says, if 590 00:33:42,150 --> 00:33:46,940 you know that the body of the rule is true, then you can 591 00:33:46,940 --> 00:33:49,470 conclude that the conclusion is true. 592 00:33:49,470 --> 00:33:52,640 Or in order to deduce that x is a big shot in some 593 00:33:52,640 --> 00:33:57,480 department, it's enough to verify that. 594 00:33:57,480 --> 00:33:58,820 So that's what rules look like. 595 00:33:58,820 --> 00:34:03,280 596 00:34:03,280 --> 00:34:07,180 Let's go back and look at that merge example that I did 597 00:34:07,180 --> 00:34:08,110 before the break. 598 00:34:08,110 --> 00:34:11,610 Let's look at how that would look in terms of rules. 599 00:34:11,610 --> 00:34:14,030 I'm going to take the logic I put up and just change it into 600 00:34:14,030 --> 00:34:15,500 a bunch of rules in this format. 601 00:34:15,500 --> 00:34:18,739 602 00:34:18,739 --> 00:34:19,350 We have a rule. 603 00:34:19,350 --> 00:34:21,710 Remember, there was this thing merge-to-form. 604 00:34:21,710 --> 00:34:28,489 There is a rule that says, the empty list and y 605 00:34:28,489 --> 00:34:29,620 merge to form y. 606 00:34:29,620 --> 00:34:30,870 This is the rule conclusion. 607 00:34:30,870 --> 00:34:33,210 608 00:34:33,210 --> 00:34:36,650 And notice this particular rule has no body. 609 00:34:36,650 --> 00:34:40,010 And in this language, a rule with no body is something that 610 00:34:40,010 --> 00:34:41,239 is always true. 611 00:34:41,239 --> 00:34:42,510 You can always assume that's true. 612 00:34:42,510 --> 00:34:45,190 613 00:34:45,190 --> 00:34:47,530 And there was another piece of logic that said anything in 614 00:34:47,530 --> 00:34:49,460 the empty list merged to form the anything. 615 00:34:49,460 --> 00:34:50,900 That's this. 616 00:34:50,900 --> 00:34:55,510 A rule y and the empty list merge to form y. 617 00:34:55,510 --> 00:34:58,060 Those corresponded to the two end cases in our merge 618 00:34:58,060 --> 00:35:00,890 procedure, but now we're talking about logic, not about 619 00:35:00,890 --> 00:35:03,490 procedures. 620 00:35:03,490 --> 00:35:07,560 Then we had another rule, which said if you know how 621 00:35:07,560 --> 00:35:09,830 shorter things merge, you can put them together. 622 00:35:09,830 --> 00:35:15,340 So this says, if you have a list x and y and z, and if you 623 00:35:15,340 --> 00:35:19,530 want to deduce that a dot x-- this means constant a onto x, 624 00:35:19,530 --> 00:35:23,160 or a list whose first thing is a and whose rest is x-- 625 00:35:23,160 --> 00:35:26,230 so if you want to deduce that a dot x and b dot y merge to 626 00:35:26,230 --> 00:35:27,480 form b dot c-- 627 00:35:27,480 --> 00:35:30,570 628 00:35:30,570 --> 00:35:34,070 that would say you merge these two lists a x and b y and 629 00:35:34,070 --> 00:35:37,680 you're going to get something that starts with b-- 630 00:35:37,680 --> 00:35:41,880 you can deduce that if you know that it's the case both 631 00:35:41,880 --> 00:35:48,690 that a dot x and y merge to form z and a is larger than b. 632 00:35:48,690 --> 00:35:52,610 So when I merge them, b will come first in the list. That's 633 00:35:52,610 --> 00:35:56,050 a little translation of the logic rule that I wrote in 634 00:35:56,050 --> 00:35:57,960 pseudo-English before. 635 00:35:57,960 --> 00:35:59,870 And then just for completeness, 636 00:35:59,870 --> 00:36:03,130 here's the other case. 637 00:36:03,130 --> 00:36:08,170 a dot x and b dot y merge to form a dot z if x and b dot y 638 00:36:08,170 --> 00:36:12,190 merged to form z and b is larger than a. 639 00:36:12,190 --> 00:36:15,610 So that's a little program that I've typed in in this 640 00:36:15,610 --> 00:36:17,416 language, and now let's look at it run. 641 00:36:17,416 --> 00:36:21,900 642 00:36:21,900 --> 00:36:27,740 So I typed in the merge rules before, and I could use this 643 00:36:27,740 --> 00:36:28,510 like a procedure. 644 00:36:28,510 --> 00:36:39,590 I could say merge to form 1 and 3 and 2 and 7. 645 00:36:39,590 --> 00:36:43,330 So here I'm using it like the LISP procedure. 646 00:36:43,330 --> 00:36:46,940 Now it's going to think about that for a while and apply 647 00:36:46,940 --> 00:36:48,190 these rules. 648 00:36:48,190 --> 00:36:50,780 649 00:36:50,780 --> 00:36:52,800 So it found an answer. 650 00:36:52,800 --> 00:36:55,370 Now it's going to see if there are any other answers but it 651 00:36:55,370 --> 00:36:57,810 doesn't know a priori there's only one answer. 652 00:36:57,810 --> 00:37:00,790 So it's sitting here checking all possibilities, and it 653 00:37:00,790 --> 00:37:01,970 says, no more. 654 00:37:01,970 --> 00:37:02,775 Done. 655 00:37:02,775 --> 00:37:05,210 So there I've used those rules like a procedure. 656 00:37:05,210 --> 00:37:08,340 Or remember the whole point is that I can ask different kinds 657 00:37:08,340 --> 00:37:10,220 of questions. 658 00:37:10,220 --> 00:37:24,590 I could say merge to form, let's see, how about 2 and a. 659 00:37:24,590 --> 00:37:29,440 Some list of two elements which I know starts with 2, 660 00:37:29,440 --> 00:37:34,600 and the other thing I don't know, and x and some other 661 00:37:34,600 --> 00:37:39,510 list merge to form a 1, 2, 3 and 4. 662 00:37:39,510 --> 00:37:42,760 663 00:37:42,760 --> 00:37:44,590 So now it's going to think about that. 664 00:37:44,590 --> 00:37:45,840 It's got to find-- 665 00:37:45,840 --> 00:37:48,070 666 00:37:48,070 --> 00:37:49,095 so it found one possibility. 667 00:37:49,095 --> 00:37:53,830 It said a could be 3, and x could be the list 1, 4. 668 00:37:53,830 --> 00:37:57,220 And now, again, it's got to check because it doesn't a 669 00:37:57,220 --> 00:37:59,050 priori know that there aren't any other 670 00:37:59,050 --> 00:38:00,300 possibilities going on. 671 00:38:00,300 --> 00:38:03,680 672 00:38:03,680 --> 00:38:10,660 Or like I said, I could say something like merge to form, 673 00:38:10,660 --> 00:38:17,275 like, what and what else merge to form 1, 2, 3, 4, 5? 674 00:38:17,275 --> 00:38:24,340 675 00:38:24,340 --> 00:38:25,590 Now it's going to think about that. 676 00:38:25,590 --> 00:38:28,490 677 00:38:28,490 --> 00:38:30,310 And there are a lot of answers that it might get. 678 00:38:30,310 --> 00:38:35,180 679 00:38:35,180 --> 00:38:37,920 And what you see is here you're really paying the price 680 00:38:37,920 --> 00:38:39,170 of slowness. 681 00:38:39,170 --> 00:38:42,210 682 00:38:42,210 --> 00:38:43,880 And kind of for three reasons. 683 00:38:43,880 --> 00:38:47,630 One is that this language is doubly interpreted. 684 00:38:47,630 --> 00:38:50,100 Whereas in a real implementation, you would go 685 00:38:50,100 --> 00:38:52,190 compile this down to primitive operations. 686 00:38:52,190 --> 00:38:56,410 The other reason is that this particular algorithm for 687 00:38:56,410 --> 00:38:58,380 merges is doubly recursive. 688 00:38:58,380 --> 00:39:01,020 So it's going to take a very long time. 689 00:39:01,020 --> 00:39:06,710 And eventually, this is going to go through and find-- 690 00:39:06,710 --> 00:39:07,130 find what? 691 00:39:07,130 --> 00:39:08,730 Two to the fifth possible answers. 692 00:39:08,730 --> 00:39:12,140 693 00:39:12,140 --> 00:39:14,830 And you see they come out in some fairly arbitrary order, 694 00:39:14,830 --> 00:39:17,100 depending on which order it's going to be 695 00:39:17,100 --> 00:39:20,160 trying these rules. 696 00:39:20,160 --> 00:39:21,530 In fact, what we're going to do when they edit the 697 00:39:21,530 --> 00:39:24,310 videotape is speed all this up. 698 00:39:24,310 --> 00:39:26,600 Don't you like taking out these weights? 699 00:39:26,600 --> 00:39:28,250 And don't you wish you could do that in your demos? 700 00:39:28,250 --> 00:39:32,840 701 00:39:32,840 --> 00:39:34,260 Anyway, it's still grinding there. 702 00:39:34,260 --> 00:39:39,220 703 00:39:39,220 --> 00:39:41,170 Anyway, there are 32 possibilities-- 704 00:39:41,170 --> 00:39:42,630 we won't wait for it to print out all of them. 705 00:39:42,630 --> 00:39:47,850 706 00:39:47,850 --> 00:39:49,410 OK, so the needs of abstraction in this 707 00:39:49,410 --> 00:39:50,660 language are rules. 708 00:39:50,660 --> 00:39:53,630 709 00:39:53,630 --> 00:39:57,410 So we take some bunch of things that are put together 710 00:39:57,410 --> 00:40:00,350 with logic and we name them. 711 00:40:00,350 --> 00:40:02,080 And you can think of that as naming a 712 00:40:02,080 --> 00:40:03,410 particular pattern of logic. 713 00:40:03,410 --> 00:40:05,810 Or you can think of that as saying, if you want to deduce 714 00:40:05,810 --> 00:40:10,660 some conclusion, you can apply those rules of logic. 715 00:40:10,660 --> 00:40:13,420 And those are three elements of this language. 716 00:40:13,420 --> 00:40:15,670 Let's break now, and then we'll talk about how it's 717 00:40:15,670 --> 00:40:16,920 actually implemented. 718 00:40:16,920 --> 00:40:22,747 719 00:40:22,747 --> 00:40:27,380 STUDENT: Does using LISP value primitive or whatever 720 00:40:27,380 --> 00:40:31,770 interfere with your means to go both directions on a query? 721 00:40:31,770 --> 00:40:33,530 PROFESSOR: OK, that's a-- 722 00:40:33,530 --> 00:40:37,840 the question is, does using LISP value interfere with the 723 00:40:37,840 --> 00:40:40,090 ability to go both directions on the query? 724 00:40:40,090 --> 00:40:43,850 We haven't really talked about the implementation yet, but 725 00:40:43,850 --> 00:40:46,890 the answer is, yes, it can. 726 00:40:46,890 --> 00:40:50,510 In general, as we'll see at the end-- 727 00:40:50,510 --> 00:40:53,330 although I really won't to go into details-- 728 00:40:53,330 --> 00:40:58,140 it's fairly complicated, especially when you use either 729 00:40:58,140 --> 00:40:59,780 not or LISP value-- 730 00:40:59,780 --> 00:41:04,310 or actually, if you use anything besides only and, it 731 00:41:04,310 --> 00:41:07,350 becomes very complicated to say when 732 00:41:07,350 --> 00:41:08,700 these things will work. 733 00:41:08,700 --> 00:41:10,360 They won't work quite in all situations. 734 00:41:10,360 --> 00:41:14,300 I'll talk about that at the end of the second half today. 735 00:41:14,300 --> 00:41:17,180 But the answer to your question is, yes, by dragging 736 00:41:17,180 --> 00:41:22,000 in a lot more power from LISP value, you lose some of the 737 00:41:22,000 --> 00:41:24,170 principal power of logic programming. 738 00:41:24,170 --> 00:41:28,090 That's a trade-off that you have to make. 739 00:41:28,090 --> 00:41:30,390 OK, let's take a break. 740 00:41:30,390 --> 00:41:49,844 ================================================ FILE: SrtEN/lec8b_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:18,910 1 00:00:18,910 --> 00:00:20,900 PROFESSOR: All right, well, we've seen how the query 2 00:00:20,900 --> 00:00:22,502 language works. 3 00:00:22,502 --> 00:00:26,280 Now, let's talk about how it's implemented. 4 00:00:26,280 --> 00:00:29,470 You already pretty much can guess what's going on there. 5 00:00:29,470 --> 00:00:32,810 At the bottom of it, there's a pattern matcher. 6 00:00:32,810 --> 00:00:35,180 And we looked at a pattern matcher when we did the 7 00:00:35,180 --> 00:00:38,110 rule-based control language. 8 00:00:38,110 --> 00:00:41,520 Just to remind you, here are some sample patterns. 9 00:00:41,520 --> 00:00:45,010 This is a pattern that will match any list of three things 10 00:00:45,010 --> 00:00:48,930 of which the first is a and the second is c and the middle 11 00:00:48,930 --> 00:00:50,650 one can be anything. 12 00:00:50,650 --> 00:00:52,310 So in this little pattern-matching syntax, 13 00:00:52,310 --> 00:00:54,050 there's only one distinction you make. 14 00:00:54,050 --> 00:00:57,830 There's either literal things or variables, and variables 15 00:00:57,830 --> 00:00:59,080 begin with question mark. 16 00:00:59,080 --> 00:01:01,370 17 00:01:01,370 --> 00:01:04,900 So this matches any list of three things of which the 18 00:01:04,900 --> 00:01:06,500 first is a and the second is c. 19 00:01:06,500 --> 00:01:11,010 This one matches any list of three things of which the 20 00:01:11,010 --> 00:01:12,530 first is the symbol job. 21 00:01:12,530 --> 00:01:14,210 The second can be anything. 22 00:01:14,210 --> 00:01:16,750 And the third is a list of two things of which the first is 23 00:01:16,750 --> 00:01:20,480 the symbol computer and the second can be anything. 24 00:01:20,480 --> 00:01:25,100 And this one, this next one matches any list of three 25 00:01:25,100 --> 00:01:29,120 things, and the only difference is, here, the third 26 00:01:29,120 --> 00:01:32,280 list, the first is the symbol computer, and then there's 27 00:01:32,280 --> 00:01:36,430 some rest of the list. So this means two elements and this 28 00:01:36,430 --> 00:01:37,860 means arbitrary number. 29 00:01:37,860 --> 00:01:39,996 And our language implementation isn't even 30 00:01:39,996 --> 00:01:42,310 going to have to worry about implementing this dot because 31 00:01:42,310 --> 00:01:44,050 that's automatically done by Lisp's reader. 32 00:01:44,050 --> 00:01:48,340 33 00:01:48,340 --> 00:01:50,310 Remember matchers also have some consistency in them. 34 00:01:50,310 --> 00:01:53,010 This match is a list of three things of which 35 00:01:53,010 --> 00:01:54,430 the first is a. 36 00:01:54,430 --> 00:01:56,280 And the second and third can be anything, but they have to 37 00:01:56,280 --> 00:01:57,940 be the same thing. 38 00:01:57,940 --> 00:01:59,600 They're both called x. 39 00:01:59,600 --> 00:02:02,730 And this matches a list of four things of which the first 40 00:02:02,730 --> 00:02:05,590 is the fourth and the second is the same as the third. 41 00:02:05,590 --> 00:02:09,685 And this last one matches any list that begins with a. 42 00:02:09,685 --> 00:02:14,040 The first thing is a, and the rest can be anything. 43 00:02:14,040 --> 00:02:16,750 So that's just a review of pattern matcher syntax that 44 00:02:16,750 --> 00:02:18,780 you've already seen. 45 00:02:18,780 --> 00:02:21,490 And remember, that's implemented by some procedure 46 00:02:21,490 --> 00:02:22,740 called match. 47 00:02:22,740 --> 00:02:24,870 48 00:02:24,870 --> 00:02:35,695 And match takes a pattern and some data and a dictionary. 49 00:02:35,695 --> 00:02:43,200 50 00:02:43,200 --> 00:02:50,470 And match asks the question is there any way to match this 51 00:02:50,470 --> 00:02:55,170 pattern against this data object subject to the bindings 52 00:02:55,170 --> 00:02:58,160 that are already in this dictionary? 53 00:02:58,160 --> 00:03:03,200 So, for instance, if we're going to match the pattern x, 54 00:03:03,200 --> 00:03:18,080 y, y, x against the data a, b, b, a subject to a dictionary, 55 00:03:18,080 --> 00:03:22,010 that says x equals a. 56 00:03:22,010 --> 00:03:25,260 Then the matcher would say, yes, that's consistent. 57 00:03:25,260 --> 00:03:28,410 These match, and it's consistent with what's in the 58 00:03:28,410 --> 00:03:30,320 dictionary to say that x equals a. 59 00:03:30,320 --> 00:03:34,810 And the result of the match is the extended dictionary that 60 00:03:34,810 --> 00:03:39,490 says x equals a and y equals b. 61 00:03:39,490 --> 00:03:42,860 So a matcher takes in pattern data dictionary, puts out an 62 00:03:42,860 --> 00:03:45,590 extended dictionary if it matches, or if it doesn't 63 00:03:45,590 --> 00:03:46,840 match, says that it fails. 64 00:03:46,840 --> 00:03:51,620 So, for example, if I use the same pattern here, if I say 65 00:03:51,620 --> 00:04:02,450 this x, y, y, x match a, b, b, a with the dictionary y equals 66 00:04:02,450 --> 00:04:06,665 a, then the matcher would put out fail. 67 00:04:06,665 --> 00:04:12,150 68 00:04:12,150 --> 00:04:15,100 Well, you've already seen the code for a pattern matcher so 69 00:04:15,100 --> 00:04:19,040 I'm not going to go over it, but it's the same thing we've 70 00:04:19,040 --> 00:04:21,190 been doing before. 71 00:04:21,190 --> 00:04:23,220 You saw that in the system on rule-based control. 72 00:04:23,220 --> 00:04:24,950 It's essentially the same matcher. 73 00:04:24,950 --> 00:04:28,415 In fact, I think the syntax is a little bit simpler because 74 00:04:28,415 --> 00:04:30,490 we're not worrying about arbitrary constants and 75 00:04:30,490 --> 00:04:31,400 expressions and things. 76 00:04:31,400 --> 00:04:32,690 There's just variables and constants. 77 00:04:32,690 --> 00:04:35,790 78 00:04:35,790 --> 00:04:39,610 OK, well, given that, what's a primitive query? 79 00:04:39,610 --> 00:04:42,970 80 00:04:42,970 --> 00:04:46,720 Primitive query is going to be a rather complicated thing. 81 00:04:46,720 --> 00:04:48,100 It's going to be-- 82 00:04:48,100 --> 00:05:03,490 let's think about the query job of x is d dot y. 83 00:05:03,490 --> 00:05:06,850 84 00:05:06,850 --> 00:05:09,400 That's a query we might type in. 85 00:05:09,400 --> 00:05:11,095 That's going to be implemented in the system. 86 00:05:11,095 --> 00:05:14,270 87 00:05:14,270 --> 00:05:15,700 We'll think of it as this little box. 88 00:05:15,700 --> 00:05:18,880 Here's the primitive query. 89 00:05:18,880 --> 00:05:32,070 What this little box is going to do is take in two streams 90 00:05:32,070 --> 00:05:34,030 and put out a stream. 91 00:05:34,030 --> 00:05:37,310 So the shape of a primitive query is that it's a thing 92 00:05:37,310 --> 00:05:41,120 where two streams come in and one stream goes out. 93 00:05:41,120 --> 00:05:43,240 What these streams are going to be is 94 00:05:43,240 --> 00:05:45,925 down here is the database. 95 00:05:45,925 --> 00:05:51,600 96 00:05:51,600 --> 00:05:56,180 So we imagine all the things in the database sort of 97 00:05:56,180 --> 00:06:00,330 sitting there in a stream and this thing sucks on them. 98 00:06:00,330 --> 00:06:02,800 So what are some things that might be in the database? 99 00:06:02,800 --> 00:06:22,440 Oh, job of Alyssa is something and some 100 00:06:22,440 --> 00:06:25,770 other job is something. 101 00:06:25,770 --> 00:06:29,800 So imagine all of the facts in the database sitting there in 102 00:06:29,800 --> 00:06:32,040 the stream. 103 00:06:32,040 --> 00:06:33,400 That's what comes in here. 104 00:06:33,400 --> 00:06:38,510 What comes in here is a stream of dictionaries. 105 00:06:38,510 --> 00:06:48,855 So one particular dictionary might say y equals programmer. 106 00:06:48,855 --> 00:06:55,470 107 00:06:55,470 --> 00:06:59,170 Now, what the query does when it gets in a dictionary from 108 00:06:59,170 --> 00:07:06,090 this stream, it finds all possible ways of matching the 109 00:07:06,090 --> 00:07:11,390 query against whatever is coming in from the database. 110 00:07:11,390 --> 00:07:15,420 It looks at the query as a pattern, matches it against 111 00:07:15,420 --> 00:07:20,870 any fact from the database or all possible ways of finding 112 00:07:20,870 --> 00:07:24,830 and matching the database with respect to this dictionary 113 00:07:24,830 --> 00:07:27,550 that's coming in. 114 00:07:27,550 --> 00:07:30,940 So for each fact in the database, it calls the matcher 115 00:07:30,940 --> 00:07:35,110 using the pattern, fact, and dictionary. 116 00:07:35,110 --> 00:07:38,950 And every time it gets a good match, it puts out the 117 00:07:38,950 --> 00:07:40,420 extended dictionary. 118 00:07:40,420 --> 00:07:44,610 So, for example, if this one comes in and it finds a match, 119 00:07:44,610 --> 00:07:48,710 out will come a dictionary that in this case will have y 120 00:07:48,710 --> 00:07:52,970 equals programmer and x equals something. 121 00:07:52,970 --> 00:07:56,740 122 00:07:56,740 --> 00:07:59,410 y is programmer, x is something, and d 123 00:07:59,410 --> 00:08:01,430 is whatever it found. 124 00:08:01,430 --> 00:08:03,520 And that's all. 125 00:08:03,520 --> 00:08:07,240 And, of course, it's going to try this for every fact in the 126 00:08:07,240 --> 00:08:07,980 dictionary. 127 00:08:07,980 --> 00:08:09,250 So it might find lots of them. 128 00:08:09,250 --> 00:08:14,110 It might find another one that says y equals programmer and x 129 00:08:14,110 --> 00:08:16,355 equals, and d equals. 130 00:08:16,355 --> 00:08:20,040 131 00:08:20,040 --> 00:08:22,750 So for one frame coming in, it might put out-- 132 00:08:22,750 --> 00:08:24,600 for one dictionary coming in, it might put out a lot of 133 00:08:24,600 --> 00:08:30,470 dictionaries, or it might put out none. 134 00:08:30,470 --> 00:08:34,620 It might have something that wouldn't match 135 00:08:34,620 --> 00:08:39,320 like x equals FOO. 136 00:08:39,320 --> 00:08:42,730 This one might not match anything in which case nothing 137 00:08:42,730 --> 00:08:47,510 will go into this stream corresponding to this frame. 138 00:08:47,510 --> 00:08:53,560 Or what you might do is put in an empty frame, and an empty 139 00:08:53,560 --> 00:08:55,905 frame says try matching all ways-- 140 00:08:55,905 --> 00:08:59,930 141 00:08:59,930 --> 00:09:02,880 find all possible ways of matching the query against 142 00:09:02,880 --> 00:09:05,470 something in the database subject to no previous 143 00:09:05,470 --> 00:09:07,570 restrictions. 144 00:09:07,570 --> 00:09:10,620 And if you think about what that means, that's just the 145 00:09:10,620 --> 00:09:13,980 computation that's done when you type in a query right off. 146 00:09:13,980 --> 00:09:16,650 It tries to find all matches. 147 00:09:16,650 --> 00:09:19,370 So a primitive query sets up this mechanism. 148 00:09:19,370 --> 00:09:23,920 And what the language does, when you type in the query at 149 00:09:23,920 --> 00:09:27,440 the top level, it takes this mechanism, feeds in one single 150 00:09:27,440 --> 00:09:33,130 empty dictionary, and then for each thing that comes out 151 00:09:33,130 --> 00:09:39,330 takes the original query and instantiates the result with 152 00:09:39,330 --> 00:09:41,810 all the different dictionaries, producing a new 153 00:09:41,810 --> 00:09:44,990 stream of instantiated patterns here. 154 00:09:44,990 --> 00:09:48,170 And that's what gets printed on the terminal. 155 00:09:48,170 --> 00:09:53,510 That's the basic mechanism going on there. 156 00:09:53,510 --> 00:09:56,870 Well, why is that so complicated? 157 00:09:56,870 --> 00:10:00,310 You probably can think of a lot simpler ways to arrange 158 00:10:00,310 --> 00:10:03,010 this match for a primitive query rather than having all 159 00:10:03,010 --> 00:10:04,725 of these streams floating around. 160 00:10:04,725 --> 00:10:07,290 And the answer is-- 161 00:10:07,290 --> 00:10:10,860 you probably guess already. 162 00:10:10,860 --> 00:10:15,660 The answer is this thing extends elegantly to implement 163 00:10:15,660 --> 00:10:17,790 the means of combination. 164 00:10:17,790 --> 00:10:22,470 So, for instance, suppose I don't only want to do this. 165 00:10:22,470 --> 00:10:27,230 I don't want to say who to be everybody's job description. 166 00:10:27,230 --> 00:10:39,140 Suppose I want to say AND the job of x is d dot y and the 167 00:10:39,140 --> 00:10:48,800 supervisor of x is z. 168 00:10:48,800 --> 00:10:52,550 Now, supervisor of x is z is going to be another primitive 169 00:10:52,550 --> 00:10:57,830 query that has the same shape to take in a stream of data 170 00:10:57,830 --> 00:11:02,570 objects, a stream of initial dictionaries, which are the 171 00:11:02,570 --> 00:11:05,930 restrictions to try and use when you match, and it's going 172 00:11:05,930 --> 00:11:08,700 to put out a stream of dictionaries. 173 00:11:08,700 --> 00:11:11,680 So that's what this primitive query looks like. 174 00:11:11,680 --> 00:11:12,910 And how do I implement the AND? 175 00:11:12,910 --> 00:11:13,450 Well, it's simple. 176 00:11:13,450 --> 00:11:14,880 I just hook them together. 177 00:11:14,880 --> 00:11:17,790 I take the output of this one, and I put that to the 178 00:11:17,790 --> 00:11:19,830 input of that one. 179 00:11:19,830 --> 00:11:21,545 And I take the dictionary here and I fan it out. 180 00:11:21,545 --> 00:11:26,570 181 00:11:26,570 --> 00:11:29,610 And then you see how that's going to work, because what's 182 00:11:29,610 --> 00:11:32,820 going to happen is a frame will now come in here, which 183 00:11:32,820 --> 00:11:37,920 has a binding for x, y, and d. 184 00:11:37,920 --> 00:11:40,030 And then when this one gets it, it'll say, oh, gee, 185 00:11:40,030 --> 00:11:45,530 subject to these restrictions, which now already have values 186 00:11:45,530 --> 00:11:52,340 in the dictionary for y and x and d, it looks in the 187 00:11:52,340 --> 00:11:56,080 database and says, gee, can I find any supervisor facts? 188 00:11:56,080 --> 00:12:00,120 And if it finds any, out will come dictionaries which have 189 00:12:00,120 --> 00:12:09,340 bindings for y and x and d and z now. 190 00:12:09,340 --> 00:12:12,070 191 00:12:12,070 --> 00:12:16,430 And then notice that because the frames coming in here have 192 00:12:16,430 --> 00:12:19,440 these restrictions, that's the thing that assures that when 193 00:12:19,440 --> 00:12:26,470 you do the AND, this x will mean the same thing as that x. 194 00:12:26,470 --> 00:12:30,520 Because by the time something comes floating in here, x has 195 00:12:30,520 --> 00:12:34,460 a value that you have to match against consistently. 196 00:12:34,460 --> 00:12:36,250 And then you remember from the code from the matcher, there 197 00:12:36,250 --> 00:12:38,570 was something in the way the matcher did dictionaries that 198 00:12:38,570 --> 00:12:40,710 arrange consistent matches. 199 00:12:40,710 --> 00:12:44,260 So there's AND. 200 00:12:44,260 --> 00:12:48,570 The important point to notice is the general shape. 201 00:12:48,570 --> 00:12:52,600 Look at what happened: the AND of two queries, say, P and Q. 202 00:12:52,600 --> 00:13:00,465 Here's P and Q. The AND of two queries, well, 203 00:13:00,465 --> 00:13:01,190 it looks like this. 204 00:13:01,190 --> 00:13:05,120 Each query takes in a stream from the database, a stream of 205 00:13:05,120 --> 00:13:10,230 inputs, and puts out a stream of outputs. 206 00:13:10,230 --> 00:13:14,320 And the important point to notice is that if I draw a box 207 00:13:14,320 --> 00:13:26,500 around this thing and say this is AND of P and Q, then that 208 00:13:26,500 --> 00:13:32,360 box has exactly the same overall shape. 209 00:13:32,360 --> 00:13:34,200 It's something that takes in a stream from the database. 210 00:13:34,200 --> 00:13:37,020 Here it's going to get fanned out inside, but from the 211 00:13:37,020 --> 00:13:38,160 outside you don't see that. 212 00:13:38,160 --> 00:13:42,230 It takes an input stream and puts out an output stream. 213 00:13:42,230 --> 00:13:43,570 So this is AND. 214 00:13:43,570 --> 00:13:46,020 And then similarly, OR would look like this. 215 00:13:46,020 --> 00:13:48,030 OR would-- 216 00:13:48,030 --> 00:13:49,840 although I didn't show you examples of OR. 217 00:13:49,840 --> 00:13:55,970 OR would say can I find all ways of matching P or Q. So I 218 00:13:55,970 --> 00:13:58,070 have P and Q. Each will have their shape. 219 00:13:58,070 --> 00:14:04,460 220 00:14:04,460 --> 00:14:08,720 And the way OR is implemented is I'll 221 00:14:08,720 --> 00:14:12,500 take my database stream. 222 00:14:12,500 --> 00:14:13,490 I'll fan it out. 223 00:14:13,490 --> 00:14:19,870 I'll put one into P and one into Q. I'll take my initial 224 00:14:19,870 --> 00:14:21,980 query stream coming in and fan it out. 225 00:14:21,980 --> 00:14:26,750 226 00:14:26,750 --> 00:14:29,460 So I'll look at all the answers I might get from P and 227 00:14:29,460 --> 00:14:32,950 all the answers I might get from Q, and I'll put them 228 00:14:32,950 --> 00:14:35,280 through some sort of thing that appends them or merges 229 00:14:35,280 --> 00:14:41,080 the result into one stream, and that's what will come out. 230 00:14:41,080 --> 00:14:48,240 And this whole thing from the outside is OR. 231 00:14:48,240 --> 00:14:52,350 232 00:14:52,350 --> 00:14:55,540 And again, you see it has the same overall shape when looked 233 00:14:55,540 --> 00:14:56,790 at from the outside. 234 00:14:56,790 --> 00:15:01,000 235 00:15:01,000 --> 00:15:02,020 What's NOT? 236 00:15:02,020 --> 00:15:04,310 NOT works kind of the same way. 237 00:15:04,310 --> 00:15:14,690 If I have some query P, I take the primitive query for P. 238 00:15:14,690 --> 00:15:19,600 Here, I'm going to implement NOT P. And NOT's just going to 239 00:15:19,600 --> 00:15:20,720 act as a filter. 240 00:15:20,720 --> 00:15:27,050 I'll take in the database and my original stream of 241 00:15:27,050 --> 00:15:32,210 dictionaries coming in, and what NOT P will do is it will 242 00:15:32,210 --> 00:15:39,020 filter these guys. 243 00:15:39,020 --> 00:15:41,850 And the way it will filter it, it will say when I get in a 244 00:15:41,850 --> 00:15:45,540 dictionary here, I'll find all the matches, and if I find 245 00:15:45,540 --> 00:15:47,460 any, I'll throw it away. 246 00:15:47,460 --> 00:15:49,670 And if I don't find any matches to something coming in 247 00:15:49,670 --> 00:15:52,500 here, I'll just pass that through, so 248 00:15:52,500 --> 00:15:55,560 NOT is a pure filter. 249 00:15:55,560 --> 00:15:56,890 So AND is-- 250 00:15:56,890 --> 00:15:59,090 think of these sort of electoral 251 00:15:59,090 --> 00:15:59,980 resistors or something. 252 00:15:59,980 --> 00:16:04,960 AND is series combination and OR is parallel combination. 253 00:16:04,960 --> 00:16:06,780 And then NOT is not going to extend any 254 00:16:06,780 --> 00:16:07,460 dictionaries at all. 255 00:16:07,460 --> 00:16:08,750 It's just going to filter it. 256 00:16:08,750 --> 00:16:10,220 It's going to throw away the ones for which it 257 00:16:10,220 --> 00:16:12,640 finds a way to match. 258 00:16:12,640 --> 00:16:14,540 And list value is sort of the same way. 259 00:16:14,540 --> 00:16:16,600 The filter's a little more complicated. 260 00:16:16,600 --> 00:16:19,640 It applies to predicate. 261 00:16:19,640 --> 00:16:22,610 The major point to notice here, and it's a major point 262 00:16:22,610 --> 00:16:24,980 we've looked at before, is this idea of closure. 263 00:16:24,980 --> 00:16:28,490 264 00:16:28,490 --> 00:16:32,280 The things that we build as a means of combination have the 265 00:16:32,280 --> 00:16:36,470 same overall structure as the primitive 266 00:16:36,470 --> 00:16:39,750 things that we're combining. 267 00:16:39,750 --> 00:16:42,950 So the AND of two things when looked at from the outside has 268 00:16:42,950 --> 00:16:44,630 the same shape. 269 00:16:44,630 --> 00:16:48,790 And what that means is that this box here could be an AND 270 00:16:48,790 --> 00:16:51,560 or an OR or a NOT or something because it has the same shape 271 00:16:51,560 --> 00:16:54,950 to interface to the larger things. 272 00:16:54,950 --> 00:16:57,370 It's the same thing that allowed us to get complexity 273 00:16:57,370 --> 00:17:00,980 in the Escher picture language or allows you to immediately 274 00:17:00,980 --> 00:17:04,170 build up these complicated structures just out of pairs. 275 00:17:04,170 --> 00:17:06,280 It's closure. 276 00:17:06,280 --> 00:17:10,920 And that's the thing that allowed me to do what by now 277 00:17:10,920 --> 00:17:12,829 you took for granted when I said, gee, there's a query 278 00:17:12,829 --> 00:17:15,369 which is AND of job and salary, and I said, oh, 279 00:17:15,369 --> 00:17:17,190 there's another one, which is AND of 280 00:17:17,190 --> 00:17:19,260 job, a NOT of something. 281 00:17:19,260 --> 00:17:22,185 The fact that I can do that is a direct consequence of this 282 00:17:22,185 --> 00:17:25,230 closure principle. 283 00:17:25,230 --> 00:17:29,520 OK, let's break and then we'll go on. 284 00:17:29,520 --> 00:17:30,710 AUDIENCE: Where does the dictionary come from? 285 00:17:30,710 --> 00:17:35,140 PROFESSOR: The dictionary comes initially from 286 00:17:35,140 --> 00:17:36,030 what you type in. 287 00:17:36,030 --> 00:17:40,390 So when you start this up, the first thing it does is set up 288 00:17:40,390 --> 00:17:41,090 this whole structure. 289 00:17:41,090 --> 00:17:45,000 It puts in one empty dictionary. 290 00:17:45,000 --> 00:17:48,560 And if all you have is one primitive query, then what 291 00:17:48,560 --> 00:17:50,330 will come out is a bunch of dictionaries with 292 00:17:50,330 --> 00:17:52,310 things filled in. 293 00:17:52,310 --> 00:17:55,330 The general situation that I have here is when this is in 294 00:17:55,330 --> 00:17:59,710 the middle of some nest of combined things. 295 00:17:59,710 --> 00:18:02,380 296 00:18:02,380 --> 00:18:03,790 Let's look at the picture over here. 297 00:18:03,790 --> 00:18:06,730 This supervisor query gets in some dictionary. 298 00:18:06,730 --> 00:18:08,730 Where did this one come from? 299 00:18:08,730 --> 00:18:13,480 This dictionary came from the fact that I'm looking at the 300 00:18:13,480 --> 00:18:16,260 output of this primitive query. 301 00:18:16,260 --> 00:18:20,370 So maybe to be very specific, if I literally typed in just 302 00:18:20,370 --> 00:18:23,820 this query at the top level, this AND, what would actually 303 00:18:23,820 --> 00:18:26,400 happen is it would build this structure and start up this 304 00:18:26,400 --> 00:18:31,770 whole thing with one empty dictionary. 305 00:18:31,770 --> 00:18:33,850 And now this one would process, and a whole bunch of 306 00:18:33,850 --> 00:18:38,640 dictionaries would come out with x, y's and d's in them. 307 00:18:38,640 --> 00:18:40,190 Run it through this one. 308 00:18:40,190 --> 00:18:42,160 So now that's the input to this one. 309 00:18:42,160 --> 00:18:45,040 This one would now put out some other stuff. 310 00:18:45,040 --> 00:18:50,110 And if this itself were buried in some larger thing, like an 311 00:18:50,110 --> 00:18:54,860 OR of something, then that would go feed 312 00:18:54,860 --> 00:18:56,110 into the next one. 313 00:18:56,110 --> 00:18:58,560 314 00:18:58,560 --> 00:19:00,780 So you initially get only one empty dictionary when you 315 00:19:00,780 --> 00:19:03,380 start it, but as you're in the middle of processing these 316 00:19:03,380 --> 00:19:05,640 compounds things, that's where these cascades of dictionaries 317 00:19:05,640 --> 00:19:07,660 start getting generated. 318 00:19:07,660 --> 00:19:11,030 AUDIENCE: Dictionaries only come about as a result of 319 00:19:11,030 --> 00:19:12,280 using the queries? 320 00:19:12,280 --> 00:19:15,120 321 00:19:15,120 --> 00:19:18,280 Or do they become-- 322 00:19:18,280 --> 00:19:23,220 do they stay someplace in space like the database does? 323 00:19:23,220 --> 00:19:24,980 Are these temporary items? 324 00:19:24,980 --> 00:19:28,030 PROFESSOR: They're created temporarily in the matcher. 325 00:19:28,030 --> 00:19:29,880 Really, they're someplace in storage. 326 00:19:29,880 --> 00:19:32,430 Initially, someone creates a thing called the empty 327 00:19:32,430 --> 00:19:36,740 dictionary that gets initially fed to this match procedure, 328 00:19:36,740 --> 00:19:39,150 and then the match procedure builds some dictionaries, and 329 00:19:39,150 --> 00:19:40,950 they get passed on and on. 330 00:19:40,950 --> 00:19:43,526 AUDIENCE: OK, so they'll go way after the match? 331 00:19:43,526 --> 00:19:44,680 PROFESSOR: They'll go away when no one 332 00:19:44,680 --> 00:19:45,930 needs them again, yeah. 333 00:19:45,930 --> 00:19:51,900 334 00:19:51,900 --> 00:19:54,230 AUDIENCE: It appears that the AND performs some redundant 335 00:19:54,230 --> 00:19:56,050 searches of the database. 336 00:19:56,050 --> 00:19:58,660 If the first clause matched, let's say, the third element 337 00:19:58,660 --> 00:20:01,820 and not on the first two elements, the second clause is 338 00:20:01,820 --> 00:20:04,890 going to look at those first two elements again, discarding 339 00:20:04,890 --> 00:20:06,700 them because they don't match. 340 00:20:06,700 --> 00:20:10,000 The match is already in the dictionary. 341 00:20:10,000 --> 00:20:12,920 Would it makes sense to carry the data element from the 342 00:20:12,920 --> 00:20:14,450 database along with the dictionary? 343 00:20:14,450 --> 00:20:17,120 344 00:20:17,120 --> 00:20:18,550 PROFESSOR: Well, in general, there are other ways to 345 00:20:18,550 --> 00:20:21,220 arrange this search, and there's some analysis 346 00:20:21,220 --> 00:20:21,740 that you can do. 347 00:20:21,740 --> 00:20:24,600 I think there's a problem in the book, which talks about a 348 00:20:24,600 --> 00:20:27,680 different way that you can cascade AND to eliminate 349 00:20:27,680 --> 00:20:29,850 various kinds of redundancies. 350 00:20:29,850 --> 00:20:31,380 This one is meant to be-- 351 00:20:31,380 --> 00:20:33,910 was mainly meant to be very simple so you can see how they 352 00:20:33,910 --> 00:20:34,650 fit together. 353 00:20:34,650 --> 00:20:35,380 But you're quite right. 354 00:20:35,380 --> 00:20:38,370 There are redundancies here that you can get rid of. 355 00:20:38,370 --> 00:20:41,190 That's another reason why this language is somewhat slow. 356 00:20:41,190 --> 00:20:42,930 There are a lot smarter things you can do. 357 00:20:42,930 --> 00:20:45,590 We're just trying to show you a very simple, in principle, 358 00:20:45,590 --> 00:20:46,840 implementation. 359 00:20:46,840 --> 00:20:51,220 360 00:20:51,220 --> 00:20:53,716 AUDIENCE: Did you model this language on Prolog, or did it 361 00:20:53,716 --> 00:20:55,150 just come out looking like Prolog? 362 00:20:55,150 --> 00:21:04,960 363 00:21:04,960 --> 00:21:06,380 PROFESSOR: Well, Jerry insulted a whole bunch of 364 00:21:06,380 --> 00:21:08,750 people yesterday, so I might as well say that the MIT 365 00:21:08,750 --> 00:21:11,460 attitude towards Prolog is something that people did in 366 00:21:11,460 --> 00:21:15,030 about 1971 and decided that it wasn't really the right thing 367 00:21:15,030 --> 00:21:16,120 and stopped. 368 00:21:16,120 --> 00:21:22,640 So we modeled this on the sort of natural way that this thing 369 00:21:22,640 --> 00:21:26,655 was done in about 1971, except at that point, we didn't do it 370 00:21:26,655 --> 00:21:33,020 with streams. After we were using it for about six months, 371 00:21:33,020 --> 00:21:35,360 we discovered that it had all these problems, some of which 372 00:21:35,360 --> 00:21:37,330 I'll talk about later. 373 00:21:37,330 --> 00:21:40,310 And we said, gee, Prolog must have fixed those, and then we 374 00:21:40,310 --> 00:21:41,250 found out that it didn't. 375 00:21:41,250 --> 00:21:43,460 So this does about the same thing as Prolog. 376 00:21:43,460 --> 00:21:44,950 AUDIENCE: Does Prolog use streams? 377 00:21:44,950 --> 00:21:46,200 PROFESSOR: No. 378 00:21:46,200 --> 00:21:48,540 379 00:21:48,540 --> 00:21:51,040 In how it behaves, it behaves a lot like Prolog. 380 00:21:51,040 --> 00:21:53,800 Prolog uses a backtracking strategy. 381 00:21:53,800 --> 00:21:55,910 But the other thing that's really good about Prolog that 382 00:21:55,910 --> 00:21:59,950 makes it a usable thing is that there's a really very, 383 00:21:59,950 --> 00:22:04,830 very well-engineered compiler technology that makes it run 384 00:22:04,830 --> 00:22:09,260 fast. So although you saw the merge spitting out these 385 00:22:09,260 --> 00:22:13,080 answers very, very slowly, a real Prolog will run very, 386 00:22:13,080 --> 00:22:16,800 very fast. Because even though it's sort of doing this, the 387 00:22:16,800 --> 00:22:19,600 real work that went into Prolog is a very, very 388 00:22:19,600 --> 00:22:20,850 excellent compiler effort. 389 00:22:20,850 --> 00:22:24,460 390 00:22:24,460 --> 00:22:25,710 Let's take a break. 391 00:22:25,710 --> 00:23:16,650 392 00:23:16,650 --> 00:23:20,410 We've looked at the primitive queries and the ways that 393 00:23:20,410 --> 00:23:24,300 streams are used to implement the means of combination: AND 394 00:23:24,300 --> 00:23:26,950 and OR and NOT. 395 00:23:26,950 --> 00:23:29,580 Now, let go on to the means of abstraction. 396 00:23:29,580 --> 00:23:31,280 Remember, the means of abstraction in this 397 00:23:31,280 --> 00:23:32,570 language are rules. 398 00:23:32,570 --> 00:23:35,150 399 00:23:35,150 --> 00:23:42,580 So z is a boss in division d if there's some x who has a 400 00:23:42,580 --> 00:23:48,900 job in division d and z is the supervisor of x. 401 00:23:48,900 --> 00:23:52,260 That's what it means for someone to be a boss. 402 00:23:52,260 --> 00:23:54,780 And in effect, if you think about what we're doing with 403 00:23:54,780 --> 00:23:58,660 relation to this, there's the query we wrote-- the job of x 404 00:23:58,660 --> 00:24:02,150 is in d and the supervisor of x is z-- 405 00:24:02,150 --> 00:24:05,330 what we in effect want to do is take this whole mess and 406 00:24:05,330 --> 00:24:24,070 draw a box around it and say this whole thing inside the 407 00:24:24,070 --> 00:24:33,900 box is boss of z in division d. 408 00:24:33,900 --> 00:24:35,250 That's in effect what we want to do. 409 00:24:35,250 --> 00:24:38,720 410 00:24:38,720 --> 00:24:45,690 So, for instance, if we've done that, and we want to 411 00:24:45,690 --> 00:24:49,410 check whether or not it's true that Ben Bitdiddle is a boss 412 00:24:49,410 --> 00:25:00,730 in the computer division, so if I want to say boss of Ben 413 00:25:00,730 --> 00:25:05,850 Bitdiddle in the computer division, imagine typing that 414 00:25:05,850 --> 00:25:10,860 in as query to the system, in effect what we want to do is 415 00:25:10,860 --> 00:25:28,920 set up a dictionary here, which has z to Ben Bitdiddle 416 00:25:28,920 --> 00:25:33,045 and d to computer. 417 00:25:33,045 --> 00:25:37,340 418 00:25:37,340 --> 00:25:38,720 Where did that dictionary come from? 419 00:25:38,720 --> 00:25:40,710 Let's look at the slide for one second. 420 00:25:40,710 --> 00:25:44,750 That dictionary came from matching the query that said 421 00:25:44,750 --> 00:25:47,720 boss of Ben Bitdiddle and computer onto the conclusion 422 00:25:47,720 --> 00:25:51,650 of the rule: boss of z and d. 423 00:25:51,650 --> 00:25:54,190 So we match the query to the conclusion of the rule. 424 00:25:54,190 --> 00:26:00,330 That gives us a dictionary, and that's the thing that we 425 00:26:00,330 --> 00:26:03,180 would now like to put into this whole big thing and 426 00:26:03,180 --> 00:26:06,670 process and see if anything comes out the other side. 427 00:26:06,670 --> 00:26:11,330 If anything comes out, it'll be true. 428 00:26:11,330 --> 00:26:12,370 That's the basic idea. 429 00:26:12,370 --> 00:26:17,020 So in general, the way we implement a rule is we match 430 00:26:17,020 --> 00:26:21,860 the conclusion of the rule against something we might 431 00:26:21,860 --> 00:26:23,580 want to check it's true. 432 00:26:23,580 --> 00:26:26,790 That match gives us a dictionary, and with respect 433 00:26:26,790 --> 00:26:36,470 to that dictionary, we process the body of the rule. 434 00:26:36,470 --> 00:26:40,110 Well, that's really all there is, except for 435 00:26:40,110 --> 00:26:43,070 two technical points. 436 00:26:43,070 --> 00:26:46,580 The first technical point is that I might have said 437 00:26:46,580 --> 00:26:47,510 something else. 438 00:26:47,510 --> 00:26:52,490 I might have said who's the boss in the computer division? 439 00:26:52,490 --> 00:26:56,270 So I might say boss of who in computer division. 440 00:26:56,270 --> 00:27:00,329 441 00:27:00,329 --> 00:27:03,920 And if I did that, what I would really like to do in 442 00:27:03,920 --> 00:27:09,280 effect is start up this dictionary with a match that 443 00:27:09,280 --> 00:27:17,370 sort of says, well, d is computer and z is 444 00:27:17,370 --> 00:27:18,620 whatever who is. 445 00:27:18,620 --> 00:27:21,700 446 00:27:21,700 --> 00:27:23,220 And our matcher won't quite do that. 447 00:27:23,220 --> 00:27:28,580 That's not quite matching a pattern against data. 448 00:27:28,580 --> 00:27:31,310 It's matching two patterns and saying are they consistent or 449 00:27:31,310 --> 00:27:33,480 not or what ways make them consistent. 450 00:27:33,480 --> 00:27:35,940 In other words, what we need is not quite a pattern 451 00:27:35,940 --> 00:27:38,450 matcher, but something a little bit more 452 00:27:38,450 --> 00:27:39,740 general called a unifier. 453 00:27:39,740 --> 00:27:44,420 454 00:27:44,420 --> 00:27:47,190 And a unifier is a slight generalization 455 00:27:47,190 --> 00:27:49,530 of a pattern matcher. 456 00:27:49,530 --> 00:27:55,390 What a unifier does is take two patterns and say what's 457 00:27:55,390 --> 00:27:59,020 the most general thing you can substitute for the variables 458 00:27:59,020 --> 00:28:04,060 in those two patterns to make them satisfy the pattern 459 00:28:04,060 --> 00:28:05,680 simultaneously? 460 00:28:05,680 --> 00:28:08,900 Let me give you an example. 461 00:28:08,900 --> 00:28:13,940 If I have the pattern two-element list, which is x 462 00:28:13,940 --> 00:28:18,220 and x, so I have a two-element list where both elements are 463 00:28:18,220 --> 00:28:20,670 the same and otherwise I don't care what they are, and I 464 00:28:20,670 --> 00:28:23,790 unify that against the pattern that says there's a 465 00:28:23,790 --> 00:28:27,010 two-element list, and the first one is a and something 466 00:28:27,010 --> 00:28:33,830 in c and the second one is a and b and z, then what the 467 00:28:33,830 --> 00:28:36,960 unifier should tell me is, oh yeah, in that dictionary, x 468 00:28:36,960 --> 00:28:43,440 has to be a, b, c, and y has to be d and z has to be c. 469 00:28:43,440 --> 00:28:45,660 Those are the restrictions I'd have to put on the values of 470 00:28:45,660 --> 00:28:48,880 x, y, and z to make these two unify, or in other words, to 471 00:28:48,880 --> 00:28:55,420 make this match x and make this match x. 472 00:28:55,420 --> 00:28:58,540 The unifier should be able to deduce that. 473 00:28:58,540 --> 00:28:59,730 But the unifier may-- 474 00:28:59,730 --> 00:29:01,080 there are more complicated things. 475 00:29:01,080 --> 00:29:03,810 I might have said something a little bit more complicated. 476 00:29:03,810 --> 00:29:07,170 I might have said there's a list with two elements, and 477 00:29:07,170 --> 00:29:10,080 they're both the same, and they should unify against 478 00:29:10,080 --> 00:29:12,650 something of this form. 479 00:29:12,650 --> 00:29:16,890 And the unifier should be able to deduce from that. 480 00:29:16,890 --> 00:29:19,570 Like that y would have to be b. y would have to be b. 481 00:29:19,570 --> 00:29:24,340 Because these two are the same, so y's got to be b. 482 00:29:24,340 --> 00:29:28,940 And v here would have to be a. 483 00:29:28,940 --> 00:29:31,450 And z and w can be anything, but they have 484 00:29:31,450 --> 00:29:32,700 to be the same thing. 485 00:29:32,700 --> 00:29:35,710 486 00:29:35,710 --> 00:29:40,680 And x would have to be b, followed by a, followed by 487 00:29:40,680 --> 00:29:44,680 whatever w is or whatever z is, which is the same. 488 00:29:44,680 --> 00:29:48,260 So you see, the unifier somehow has to deduce things 489 00:29:48,260 --> 00:29:50,880 to unify these patterns. 490 00:29:50,880 --> 00:29:52,880 So you might think there's some kind of magic deduction 491 00:29:52,880 --> 00:29:55,850 going on, but there's not. 492 00:29:55,850 --> 00:29:59,100 A unifier is basically a very simple modification of a 493 00:29:59,100 --> 00:30:00,150 pattern matcher. 494 00:30:00,150 --> 00:30:02,530 And if you look in the book, you'll see something like 495 00:30:02,530 --> 00:30:05,350 three or four lines of code added to the pattern matcher 496 00:30:05,350 --> 00:30:08,280 you just saw to handle the symmetric case. 497 00:30:08,280 --> 00:30:11,920 Remember, the pattern matcher has a place where it says is 498 00:30:11,920 --> 00:30:14,980 this variable matching a constant. 499 00:30:14,980 --> 00:30:16,420 And if so, it checks in the dictionary. 500 00:30:16,420 --> 00:30:18,970 There's only one other clause in the unifier, which says is 501 00:30:18,970 --> 00:30:22,760 this variable matching a variable, in which case you go 502 00:30:22,760 --> 00:30:24,740 look in the dictionary and see if that's consistent with 503 00:30:24,740 --> 00:30:27,030 what's in the dictionary. 504 00:30:27,030 --> 00:30:31,450 So all the, quote, deduction that's in this language, if 505 00:30:31,450 --> 00:30:33,780 you sort of look at it, sort of sits in the rule 506 00:30:33,780 --> 00:30:37,220 applications, which, if you look at that, sits in the 507 00:30:37,220 --> 00:30:42,500 unifier, which, if you look at that under a microscope, sits 508 00:30:42,500 --> 00:30:45,260 essentially in the pattern matcher. 509 00:30:45,260 --> 00:30:47,410 There's no magic at all going on in there. 510 00:30:47,410 --> 00:30:51,930 And the, quote, deduction that you see is just the fact that 511 00:30:51,930 --> 00:30:54,610 there's this recursion, which is unwinding the 512 00:30:54,610 --> 00:30:56,030 matches bit by bit. 513 00:30:56,030 --> 00:30:58,670 So it looks like this thing is being very clever, but in 514 00:30:58,670 --> 00:31:02,140 fact, it's not being very clever at all. 515 00:31:02,140 --> 00:31:03,420 There are cases where a unifier 516 00:31:03,420 --> 00:31:04,880 might have to be clever. 517 00:31:04,880 --> 00:31:06,130 Let me show you one more. 518 00:31:06,130 --> 00:31:11,070 519 00:31:11,070 --> 00:31:17,530 Suppose I want to unify a list of two elements, x and x, with 520 00:31:17,530 --> 00:31:24,370 a thing that says it's y followed by a dot y. 521 00:31:24,370 --> 00:31:27,120 Now, if you think of what that would have to mean, it would 522 00:31:27,120 --> 00:31:32,230 have to mean that x had better be the same as y, but also x 523 00:31:32,230 --> 00:31:35,160 had better be the same as a list whose first element is a 524 00:31:35,160 --> 00:31:37,330 and whose rest is y. 525 00:31:37,330 --> 00:31:42,460 And if you think about what that would have to mean, it 526 00:31:42,460 --> 00:31:44,710 would have to mean that y is the infinite list of a's. 527 00:31:44,710 --> 00:31:47,500 528 00:31:47,500 --> 00:31:53,100 In some sense, in order to do that unification, I have to 529 00:31:53,100 --> 00:32:01,840 solve the fixed-point equation cons of a to y is equal to y. 530 00:32:01,840 --> 00:32:04,570 531 00:32:04,570 --> 00:32:07,290 And in general, I wrote a very simple one. 532 00:32:07,290 --> 00:32:11,260 Really doing unification might have to solve an arbitrary 533 00:32:11,260 --> 00:32:15,530 fixed-point equation: f of y equals y. 534 00:32:15,530 --> 00:32:18,750 And basically, you can't do that and make the thing finite 535 00:32:18,750 --> 00:32:20,570 all the time. 536 00:32:20,570 --> 00:32:25,140 So how does the logic language handle that? 537 00:32:25,140 --> 00:32:26,850 The answer is it doesn't. 538 00:32:26,850 --> 00:32:28,730 It just punts. 539 00:32:28,730 --> 00:32:32,280 And there's a little check in the unifier, which says, oh, 540 00:32:32,280 --> 00:32:35,520 is this one of the hard cases which when I go to match 541 00:32:35,520 --> 00:32:38,650 things would involve solving a fixed-point equation? 542 00:32:38,650 --> 00:32:42,840 And in this case, I will throw up my hands. 543 00:32:42,840 --> 00:32:47,990 And if that check were not in there, what would happen? 544 00:32:47,990 --> 00:32:50,590 In most cases is that the unifier would just go into an 545 00:32:50,590 --> 00:32:53,740 infinite loop. 546 00:32:53,740 --> 00:32:56,800 And other logic programming languages work like that. 547 00:32:56,800 --> 00:32:58,220 So there's really no magic. 548 00:32:58,220 --> 00:33:00,100 The easy case is done in a matcher. 549 00:33:00,100 --> 00:33:02,960 The hard case is not done at all. 550 00:33:02,960 --> 00:33:05,115 And that's about the state of this technology. 551 00:33:05,115 --> 00:33:12,840 552 00:33:12,840 --> 00:33:15,250 Let me just say again formally how rules work now that I 553 00:33:15,250 --> 00:33:17,390 talked about unifiers. 554 00:33:17,390 --> 00:33:25,260 So the official definition is that to apply a rule, we-- 555 00:33:25,260 --> 00:33:28,270 well, let's start using some words we've used before. 556 00:33:28,270 --> 00:33:33,280 Let's talk about sticking dictionaries into these big 557 00:33:33,280 --> 00:33:40,090 boxes of query things as evaluating these large queries 558 00:33:40,090 --> 00:33:43,850 relative to an environment or a frame. 559 00:33:43,850 --> 00:33:45,350 So when you think of that dictionary, what's the 560 00:33:45,350 --> 00:33:46,720 dictionary after all? 561 00:33:46,720 --> 00:33:48,180 It's a bunch of meanings for symbols. 562 00:33:48,180 --> 00:33:51,800 That's what we've been calling frames or environments. 563 00:33:51,800 --> 00:33:55,430 What does it mean to do some processing relevant to an 564 00:33:55,430 --> 00:33:55,970 environment? 565 00:33:55,970 --> 00:33:58,310 That's what we've been calling evaluation. 566 00:33:58,310 --> 00:34:03,030 So we can say the way that you apply a rule is to evaluate 567 00:34:03,030 --> 00:34:07,730 the rule body relative to an environment that's formed by 568 00:34:07,730 --> 00:34:13,230 unifying the rule conclusion with the given query. 569 00:34:13,230 --> 00:34:16,340 And the thing I want you to notice is the complete formal 570 00:34:16,340 --> 00:34:20,760 similarity to the net of circular evaluator or the 571 00:34:20,760 --> 00:34:21,630 substitution model. 572 00:34:21,630 --> 00:34:27,100 To apply a procedure, we evaluate the procedure body 573 00:34:27,100 --> 00:34:31,040 relative to an environment that's formed by blinding the 574 00:34:31,040 --> 00:34:34,560 procedure parameters to the arguments. 575 00:34:34,560 --> 00:34:36,760 There's a complete formal similarity here between the 576 00:34:36,760 --> 00:34:40,870 rules, rule application, and procedure application even 577 00:34:40,870 --> 00:34:43,650 though these things are very, very different. 578 00:34:43,650 --> 00:34:47,290 And again, you have the EVAL APPLY loop. 579 00:34:47,290 --> 00:34:49,445 EVAL and APPLY. 580 00:34:49,445 --> 00:34:53,360 581 00:34:53,360 --> 00:34:57,050 So in general, I might be processing some combined 582 00:34:57,050 --> 00:35:01,050 expression that will turn into a rule application, which will 583 00:35:01,050 --> 00:35:03,090 generate some dictionaries or frames or environments-- 584 00:35:03,090 --> 00:35:05,360 whatever you want to call them-- from match, which will 585 00:35:05,360 --> 00:35:08,660 then be the input to some big compound thing like this. 586 00:35:08,660 --> 00:35:13,580 This has pieces of it and may have other rule applications. 587 00:35:13,580 --> 00:35:16,220 And you have essentially the same cycle even though there's 588 00:35:16,220 --> 00:35:19,680 nothing here at all that looks like procedures. 589 00:35:19,680 --> 00:35:22,120 It really has to do with the fact you've built a language 590 00:35:22,120 --> 00:35:24,150 whose means of combination and abstraction 591 00:35:24,150 --> 00:35:25,490 unwind in certain ways. 592 00:35:25,490 --> 00:35:28,770 593 00:35:28,770 --> 00:35:33,840 And then in general, what happens at the very top level, 594 00:35:33,840 --> 00:35:37,280 you might have rules in your database also, so things in 595 00:35:37,280 --> 00:35:40,460 this database might be rules. 596 00:35:40,460 --> 00:35:42,920 There are ways to check that things are true. 597 00:35:42,920 --> 00:35:46,750 So it might come in here and have to do a rule check. 598 00:35:46,750 --> 00:35:48,580 And then there's some control structure which says, well, 599 00:35:48,580 --> 00:35:50,130 you look at some rules, and you look at some data 600 00:35:50,130 --> 00:35:51,965 elements, and you look at some rules and data elements, and 601 00:35:51,965 --> 00:35:53,350 these fan out and out and out. 602 00:35:53,350 --> 00:35:56,520 So it becomes essentially impossible to say what order 603 00:35:56,520 --> 00:35:59,300 it's looking at these things in, whether it's breadth first 604 00:35:59,300 --> 00:36:00,245 or depth first or anything. 605 00:36:00,245 --> 00:36:03,650 And it's even more impossible because the actual order is 606 00:36:03,650 --> 00:36:08,900 somehow buried in the delays of the streams. So what's very 607 00:36:08,900 --> 00:36:11,270 hard to tell from this is the order in which it's scanned. 608 00:36:11,270 --> 00:36:13,330 But what's true, because you're looking at the stream 609 00:36:13,330 --> 00:36:15,820 view, is that all of them eventually get looked at. 610 00:36:15,820 --> 00:36:24,980 611 00:36:24,980 --> 00:36:28,150 Let me just mention one tiny technical problem. 612 00:36:28,150 --> 00:36:37,530 613 00:36:37,530 --> 00:36:44,960 Suppose I tried saying boss of y is computer, then a funny 614 00:36:44,960 --> 00:36:45,780 thing would happen. 615 00:36:45,780 --> 00:36:53,680 As I stuck a dictionary with y in here, I might get-- 616 00:36:53,680 --> 00:36:59,350 this y is not the same as that y, which was the other piece 617 00:36:59,350 --> 00:37:01,580 of somebody's job description. 618 00:37:01,580 --> 00:37:04,380 So if I really only did literally what I said, we'd 619 00:37:04,380 --> 00:37:09,990 get some variable conflict problems. So I lied to you a 620 00:37:09,990 --> 00:37:10,930 little bit. 621 00:37:10,930 --> 00:37:12,900 Notice that problem is exactly a problem 622 00:37:12,900 --> 00:37:14,360 we've run into before. 623 00:37:14,360 --> 00:37:20,505 It is precisely the need for local variables in a language. 624 00:37:20,505 --> 00:37:22,490 When I have the sum of squares, that x had 625 00:37:22,490 --> 00:37:24,960 better not be that x. 626 00:37:24,960 --> 00:37:28,620 That's exactly the same as this y had 627 00:37:28,620 --> 00:37:31,800 better not be that y. 628 00:37:31,800 --> 00:37:33,100 And we know how to solve that. 629 00:37:33,100 --> 00:37:34,730 That was this whole environment model, and we 630 00:37:34,730 --> 00:37:37,710 built chains of frames and all sorts of things like that. 631 00:37:37,710 --> 00:37:39,270 There's a much more brutal way to solve it. 632 00:37:39,270 --> 00:37:41,730 In the query language, we didn't even do that. 633 00:37:41,730 --> 00:37:43,540 We did something completely brutal. 634 00:37:43,540 --> 00:37:48,520 We said every time you apply a rule, rename consistently all 635 00:37:48,520 --> 00:37:51,100 the variables in the rule to some new unique names that 636 00:37:51,100 --> 00:37:55,720 won't conflict with anything. 637 00:37:55,720 --> 00:37:58,150 That's conceptually simpler, but really brutal and not 638 00:37:58,150 --> 00:37:59,970 particularly efficient. 639 00:37:59,970 --> 00:38:03,700 But notice, we could have gotten rid of all of our 640 00:38:03,700 --> 00:38:08,030 environment structures if we defined for procedures in Lisp 641 00:38:08,030 --> 00:38:09,180 the same thing. 642 00:38:09,180 --> 00:38:10,580 If every time we applied a procedure and did the 643 00:38:10,580 --> 00:38:13,410 substitution model we renamed all the variables in the 644 00:38:13,410 --> 00:38:15,830 procedure, then we never would have had to worry about local 645 00:38:15,830 --> 00:38:19,040 variables because they would never arise. 646 00:38:19,040 --> 00:38:21,240 OK, well, that would be inefficient, and it's 647 00:38:21,240 --> 00:38:23,870 inefficient here in the query language, too, but we did it 648 00:38:23,870 --> 00:38:25,610 to keep it simple. 649 00:38:25,610 --> 00:38:26,860 Let's break for questions. 650 00:38:26,860 --> 00:38:30,880 651 00:38:30,880 --> 00:38:34,870 AUDIENCE: When you started this section, you emphasized 652 00:38:34,870 --> 00:38:40,390 how powerful our APPLY EVAL model was that we could use it 653 00:38:40,390 --> 00:38:41,170 for any language. 654 00:38:41,170 --> 00:38:42,790 And then you say we're going to have this language which is 655 00:38:42,790 --> 00:38:43,950 so different. 656 00:38:43,950 --> 00:38:46,440 It turns out that this language, as you just pointed 657 00:38:46,440 --> 00:38:47,880 out, is very much the same. 658 00:38:47,880 --> 00:38:49,710 I'm wondering if you're arguing that all languages end 659 00:38:49,710 --> 00:38:53,810 up coming down to this you can apply a rule or apply a 660 00:38:53,810 --> 00:38:57,030 procedure or some kind of apply? 661 00:38:57,030 --> 00:38:59,150 PROFESSOR: I would say that pretty much any language where 662 00:38:59,150 --> 00:39:03,210 you really are building up these means of combination and 663 00:39:03,210 --> 00:39:06,120 giving them simpler names and you're saying anything of the 664 00:39:06,120 --> 00:39:10,430 sort, like here's a general kind of expression, like how 665 00:39:10,430 --> 00:39:13,180 to square something, almost anything that you 666 00:39:13,180 --> 00:39:14,880 would call a procedure. 667 00:39:14,880 --> 00:39:16,360 If that's got to have parts, you have to 668 00:39:16,360 --> 00:39:18,020 unwind those parts. 669 00:39:18,020 --> 00:39:20,830 You have to have some kind of organization which says when I 670 00:39:20,830 --> 00:39:24,892 look at the abstract variables or tags or whatever you want 671 00:39:24,892 --> 00:39:28,490 to call them that might stand for particular things, you 672 00:39:28,490 --> 00:39:29,720 have to keep track of that, and that's going to be 673 00:39:29,720 --> 00:39:31,720 something like an environment. 674 00:39:31,720 --> 00:39:34,670 And then if you say this part can have parts which I have to 675 00:39:34,670 --> 00:39:37,440 unwind, you've got to have something like this cycle. 676 00:39:37,440 --> 00:39:39,970 677 00:39:39,970 --> 00:39:44,000 And lots and lots of languages have that character when they 678 00:39:44,000 --> 00:39:45,590 sort of get put together in this way. 679 00:39:45,590 --> 00:39:47,610 This language again really is different because there's 680 00:39:47,610 --> 00:39:50,690 nothing like procedures on the outside. 681 00:39:50,690 --> 00:39:52,080 When you go below the surface and you see the 682 00:39:52,080 --> 00:39:54,870 implementation, of course, it starts looking the same. 683 00:39:54,870 --> 00:39:56,950 But from the outside, it's a very different world view. 684 00:39:56,950 --> 00:39:58,650 You're not computing functions of inputs. 685 00:39:58,650 --> 00:40:03,970 686 00:40:03,970 --> 00:40:07,920 AUDIENCE: You mentioned earlier that when you build 687 00:40:07,920 --> 00:40:10,660 all of these rules in pattern matcher and with the delayed 688 00:40:10,660 --> 00:40:13,900 action of streams, you really have no way to know in what 689 00:40:13,900 --> 00:40:15,495 order things are evaluated. 690 00:40:15,495 --> 00:40:15,940 PROFESSOR: Right. 691 00:40:15,940 --> 00:40:19,470 AUDIENCE: And that would indicate then that you should 692 00:40:19,470 --> 00:40:21,850 only express declarative knowledge that's true for 693 00:40:21,850 --> 00:40:23,950 all-time, no-time sequence built into it. 694 00:40:23,950 --> 00:40:27,440 Otherwise, these things get all-- 695 00:40:27,440 --> 00:40:28,490 PROFESSOR: Yes. 696 00:40:28,490 --> 00:40:28,820 Yes. 697 00:40:28,820 --> 00:40:32,100 The question is this really is set up for doing declarative 698 00:40:32,100 --> 00:40:37,190 knowledge, and as I presented it-- and I'll show you some of 699 00:40:37,190 --> 00:40:40,830 the ugly warts under this after the break. 700 00:40:40,830 --> 00:40:43,070 As I presented it, it's just doing logic. 701 00:40:43,070 --> 00:40:45,720 And in principle, if it were logic, it wouldn't matter what 702 00:40:45,720 --> 00:40:48,840 order it's getting done. 703 00:40:48,840 --> 00:40:52,840 And it's quite true when you start doing things where you 704 00:40:52,840 --> 00:40:55,380 have side effects like adding things to the database and 705 00:40:55,380 --> 00:40:59,990 taking things out, and we'll see some others, you use that 706 00:40:59,990 --> 00:41:01,290 kind of control. 707 00:41:01,290 --> 00:41:02,940 So, for example, contrasting with Prolog. 708 00:41:02,940 --> 00:41:05,720 Say Prolog has various features where you really 709 00:41:05,720 --> 00:41:09,640 exploit the order of evaluation. 710 00:41:09,640 --> 00:41:11,770 And people write Prolog programs that way. 711 00:41:11,770 --> 00:41:14,420 That turns out to be very complicated in Prolog, 712 00:41:14,420 --> 00:41:15,940 although if you're an expert Prolog 713 00:41:15,940 --> 00:41:18,590 programmer, you can do it. 714 00:41:18,590 --> 00:41:20,210 However, here I don't think you can do it at all. 715 00:41:20,210 --> 00:41:22,890 It's very complicated because you really are giving up 716 00:41:22,890 --> 00:41:27,150 control over any prearranged order of trying things. 717 00:41:27,150 --> 00:41:29,210 AUDIENCE: Now, that would indicate then that you have a 718 00:41:29,210 --> 00:41:30,670 functional mapping. 719 00:41:30,670 --> 00:41:34,870 And when you started out this lecture, you said that we 720 00:41:34,870 --> 00:41:36,635 express the declarative knowledge which is a relation, 721 00:41:36,635 --> 00:41:38,810 and we don't talk about the inputs and the outputs. 722 00:41:38,810 --> 00:41:41,390 723 00:41:41,390 --> 00:41:43,370 PROFESSOR: Well, there's a pun on functional, right? 724 00:41:43,370 --> 00:41:46,560 There's function in the sense of no side effects and not 725 00:41:46,560 --> 00:41:48,700 depending on what order is going on. 726 00:41:48,700 --> 00:41:50,720 And then there's functional in the sense of mathematical 727 00:41:50,720 --> 00:41:52,220 function, which means input and output. 728 00:41:52,220 --> 00:41:56,510 And it's just that pun that you're making, I think. 729 00:41:56,510 --> 00:41:58,520 AUDIENCE: I'm a little unclear on what you're doing with 730 00:41:58,520 --> 00:42:01,270 these two statements, the two boss statements. 731 00:42:01,270 --> 00:42:06,416 Is the first one building up the database and the second 732 00:42:06,416 --> 00:42:09,150 one a query or-- 733 00:42:09,150 --> 00:42:12,440 PROFESSOR: OK, I'm sorry. 734 00:42:12,440 --> 00:42:14,130 What I meant here, if I type something like 735 00:42:14,130 --> 00:42:16,200 this in as a query-- 736 00:42:16,200 --> 00:42:19,470 I should have given an example way at the very beginning. 737 00:42:19,470 --> 00:42:25,100 If I type in job, Ben Bitdiddle, computer wizard, 738 00:42:25,100 --> 00:42:28,570 what the processing will do is if it finds a match, it'll 739 00:42:28,570 --> 00:42:31,600 find a match to that exact thing, and it'll type out a 740 00:42:31,600 --> 00:42:34,220 job, Ben Bitdiddle, computer wizard. 741 00:42:34,220 --> 00:42:37,400 If it doesn't find a match, it won't find anything. 742 00:42:37,400 --> 00:42:40,100 So what I should have said is the way you use the query 743 00:42:40,100 --> 00:42:43,610 language to check whether something is true, remember, 744 00:42:43,610 --> 00:42:45,130 that's one of the things you want to do in logic 745 00:42:45,130 --> 00:42:47,990 programming, is you type in your query and either that 746 00:42:47,990 --> 00:42:50,680 comes out or it doesn't. 747 00:42:50,680 --> 00:42:52,940 So what I was trying to illustrate here, I wanted to 748 00:42:52,940 --> 00:42:55,220 start with a very simple example before 749 00:42:55,220 --> 00:42:57,480 talking about unifiers. 750 00:42:57,480 --> 00:43:00,260 So what I should have said, if I just wanted to check whether 751 00:43:00,260 --> 00:43:02,820 this is true, I could type that in and see if anything 752 00:43:02,820 --> 00:43:04,854 came out 753 00:43:04,854 --> 00:43:06,290 AUDIENCE: And then the second one-- 754 00:43:06,290 --> 00:43:07,830 PROFESSOR: The second one would be a real query. 755 00:43:07,830 --> 00:43:10,770 AUDIENCE: A real query, yeah. 756 00:43:10,770 --> 00:43:12,380 PROFESSOR: What would come out, see, it would go in here 757 00:43:12,380 --> 00:43:17,480 say with FOO, and in would go frame that says z is bound to 758 00:43:17,480 --> 00:43:19,560 who and d is bound to computer. 759 00:43:19,560 --> 00:43:21,400 And this will pass through, and then by the time it got 760 00:43:21,400 --> 00:43:23,250 out of here, who would pick up a binding. 761 00:43:23,250 --> 00:43:26,950 762 00:43:26,950 --> 00:43:31,950 AUDIENCE: On the unifying thing there, I still am not 763 00:43:31,950 --> 00:43:36,460 sure what happens with who and z. 764 00:43:36,460 --> 00:43:37,850 If the unifying-- 765 00:43:37,850 --> 00:43:39,490 the rule here says-- 766 00:43:39,490 --> 00:43:42,070 767 00:43:42,070 --> 00:43:44,920 OK, so you say that you can't make question mark equal to 768 00:43:44,920 --> 00:43:46,260 question mark who. 769 00:43:46,260 --> 00:43:46,410 PROFESSOR: Right. 770 00:43:46,410 --> 00:43:48,360 That's what the matcher can't do. 771 00:43:48,360 --> 00:43:52,550 But what this will mean to a unifier is that there's an 772 00:43:52,550 --> 00:43:53,800 environment with three variables. 773 00:43:53,800 --> 00:43:56,690 774 00:43:56,690 --> 00:43:58,520 d here is computer. 775 00:43:58,520 --> 00:44:01,830 z is whatever who is. 776 00:44:01,830 --> 00:44:09,180 So if later on in the matcher routine it said, for example, 777 00:44:09,180 --> 00:44:14,110 who has to be 3, then when I looked up in the dictionary, 778 00:44:14,110 --> 00:44:18,360 it will say, oh, z is 3 because it's the same as who. 779 00:44:18,360 --> 00:44:20,500 And that's in some sense the only thing you need to do to 780 00:44:20,500 --> 00:44:22,640 extend the unifier to a matcher. 781 00:44:22,640 --> 00:44:23,830 AUDIENCE: OK, because it looked like when you were 782 00:44:23,830 --> 00:44:26,000 telling how to unify it, it looked like you would put the 783 00:44:26,000 --> 00:44:27,955 things together in such a way that you'd actually solve and 784 00:44:27,955 --> 00:44:29,770 have a value for both of them. 785 00:44:29,770 --> 00:44:32,230 And what it looks like now is that you're actually pass a 786 00:44:32,230 --> 00:44:34,860 dictionary with two variables and the variables are linked. 787 00:44:34,860 --> 00:44:35,130 PROFESSOR: Right. 788 00:44:35,130 --> 00:44:37,580 It only looks like you're solving for both of them 789 00:44:37,580 --> 00:44:40,540 because you're sort of looking at the whole solution at once. 790 00:44:40,540 --> 00:44:42,790 If you sort of watch the thing getting built up recursively, 791 00:44:42,790 --> 00:44:44,980 it's merely this. 792 00:44:44,980 --> 00:44:46,620 AUDIENCE: OK, so you do pass off that 793 00:44:46,620 --> 00:44:48,400 dictionary with two variables? 794 00:44:48,400 --> 00:44:49,110 PROFESSOR: That's right. 795 00:44:49,110 --> 00:44:50,190 AUDIENCE: And link? 796 00:44:50,190 --> 00:44:50,560 PROFESSOR: Right. 797 00:44:50,560 --> 00:44:54,055 It just looks like an ordinary dictionary. 798 00:44:54,055 --> 00:44:57,450 AUDIENCE: When you're talking about the unifier, is it that 799 00:44:57,450 --> 00:45:02,785 there are some cases or some points that you are not able 800 00:45:02,785 --> 00:45:04,725 to use by them? 801 00:45:04,725 --> 00:45:05,220 PROFESSOR: Right. 802 00:45:05,220 --> 00:45:10,100 AUDIENCE: Can you just by building the rules or writing 803 00:45:10,100 --> 00:45:15,582 the forms know in advance if you are going to be able to 804 00:45:15,582 --> 00:45:18,540 solve to get the unification or not? 805 00:45:18,540 --> 00:45:23,560 Can you add some properties either to the rules itself or 806 00:45:23,560 --> 00:45:26,730 to the formula that you're writing so that you avoid the 807 00:45:26,730 --> 00:45:30,090 problem of not finding unification? 808 00:45:30,090 --> 00:45:32,870 PROFESSOR: I mean, you can agree, I think, to write in a 809 00:45:32,870 --> 00:45:35,390 fairly restricted way where you won't run into it. 810 00:45:35,390 --> 00:45:36,870 See, because what you're getting-- 811 00:45:36,870 --> 00:45:39,760 see, the place where you get into problems is when you-- 812 00:45:39,760 --> 00:45:45,020 well, again, you're trying to match things like that against 813 00:45:45,020 --> 00:45:47,600 things where these have structure, 814 00:45:47,600 --> 00:45:55,300 where a, y, b, y something. 815 00:45:55,300 --> 00:45:58,980 816 00:45:58,980 --> 00:46:00,570 So this is the kind of place where you're 817 00:46:00,570 --> 00:46:03,070 going to get into trouble. 818 00:46:03,070 --> 00:46:06,370 AUDIENCE: So you can do that syntactically? 819 00:46:06,370 --> 00:46:09,320 PROFESSOR: So you can kind of watch your rules in the kinds 820 00:46:09,320 --> 00:46:11,561 of things that your writing. 821 00:46:11,561 --> 00:46:14,460 AUDIENCE: So that's the problem that the builder of 822 00:46:14,460 --> 00:46:16,310 the database has to be concerned? 823 00:46:16,310 --> 00:46:17,560 PROFESSOR: That's a problem. 824 00:46:17,560 --> 00:46:19,930 825 00:46:19,930 --> 00:46:21,580 It's a problem either-- not quite the builder of the 826 00:46:21,580 --> 00:46:24,270 database, the person who is expressing the rules, or the 827 00:46:24,270 --> 00:46:25,800 builder of the database. 828 00:46:25,800 --> 00:46:29,230 What the unifier actually does is you can check at the next 829 00:46:29,230 --> 00:46:32,710 level down when you actually get to the unifier and you'll 830 00:46:32,710 --> 00:46:34,940 see in the code where it looks up in the dictionary. 831 00:46:34,940 --> 00:46:37,260 If it sort of says what does y have to be? 832 00:46:37,260 --> 00:46:40,690 Oh, does y have to be something that contains a y as 833 00:46:40,690 --> 00:46:41,960 its expression? 834 00:46:41,960 --> 00:46:45,120 At that point, the unifier and say, oh my God, I'm trying to 835 00:46:45,120 --> 00:46:46,240 solve a fixed-point equation. 836 00:46:46,240 --> 00:46:49,220 I'll give it up here. 837 00:46:49,220 --> 00:46:50,940 AUDIENCE: You make the distinction between the rules 838 00:46:50,940 --> 00:46:51,910 in the database. 839 00:46:51,910 --> 00:46:56,950 Are the rules added to the database? 840 00:46:56,950 --> 00:46:57,870 PROFESSOR: Yes. 841 00:46:57,870 --> 00:46:58,870 Yes, I should have said that. 842 00:46:58,870 --> 00:47:01,540 One way to think about rules is that they're just other 843 00:47:01,540 --> 00:47:03,890 things in the database. 844 00:47:03,890 --> 00:47:06,050 So if you want to check the things that have to be checked 845 00:47:06,050 --> 00:47:08,935 in the database, they're kind of virtual facts that are in 846 00:47:08,935 --> 00:47:09,445 the database. 847 00:47:09,445 --> 00:47:12,510 AUDIENCE: But in that explanation, you made the 848 00:47:12,510 --> 00:47:18,230 differentiation between database and the rules itself. 849 00:47:18,230 --> 00:47:20,490 PROFESSOR: Yeah, I probably should not have done that. 850 00:47:20,490 --> 00:47:22,440 The only reason to do that is in terms of the 851 00:47:22,440 --> 00:47:23,540 implementation. 852 00:47:23,540 --> 00:47:25,220 When you look at the implementation, there's a part 853 00:47:25,220 --> 00:47:28,120 which says check either primitive assertions in the 854 00:47:28,120 --> 00:47:30,470 database or check rules. 855 00:47:30,470 --> 00:47:33,510 And then the real reason why you can't tell what order 856 00:47:33,510 --> 00:47:38,010 things are going to come out in and is that the rules 857 00:47:38,010 --> 00:47:42,240 database and the data database sort of get merged in a kind 858 00:47:42,240 --> 00:47:44,600 of delayed evaluation way. 859 00:47:44,600 --> 00:47:46,320 And so that's what makes the order very complicated. 860 00:47:46,320 --> 00:47:55,440 861 00:47:55,440 --> 00:47:56,690 OK, let's break. 862 00:47:56,690 --> 00:48:33,160 863 00:48:33,160 --> 00:48:35,520 We've just seen how the logic language works 864 00:48:35,520 --> 00:48:37,230 and how rules work. 865 00:48:37,230 --> 00:48:40,120 Now, let's turn to a more profound question. 866 00:48:40,120 --> 00:48:43,180 What do these things mean? 867 00:48:43,180 --> 00:48:47,240 That brings us to the subtlest, most devious part of 868 00:48:47,240 --> 00:48:51,420 this whole query language business, and that is that 869 00:48:51,420 --> 00:48:53,570 it's not quite what it seems to be. 870 00:48:53,570 --> 00:48:59,750 AND and OR and NOT and the logical implication of rules 871 00:48:59,750 --> 00:49:05,400 are not really the AND and OR and NOT and logical 872 00:49:05,400 --> 00:49:07,690 implication of logic. 873 00:49:07,690 --> 00:49:09,910 Let me give you an example of that. 874 00:49:09,910 --> 00:49:12,960 Certainly, if we have two things in logic, it ought to 875 00:49:12,960 --> 00:49:22,225 be the case that AND of P and Q is the same as AND of Q and 876 00:49:22,225 --> 00:49:28,920 P and that OR of P and Q is the same as OR of Q and P. But 877 00:49:28,920 --> 00:49:30,100 let's look here. 878 00:49:30,100 --> 00:49:32,180 Here's an example. 879 00:49:32,180 --> 00:49:38,200 Let's talk about somebody outranking somebody else in 880 00:49:38,200 --> 00:49:40,140 our little database organization. 881 00:49:40,140 --> 00:49:47,890 We'll say s is outranked by b or if either the supervisor of 882 00:49:47,890 --> 00:49:51,100 this is b or there's some middle manager here, that 883 00:49:51,100 --> 00:49:55,640 supervisor of s is m, and m is outranked by b. 884 00:49:55,640 --> 00:49:59,830 885 00:49:59,830 --> 00:50:02,310 So there's one way to define rule outranked by. 886 00:50:02,310 --> 00:50:06,300 Or we can write exactly the same thing, except at the 887 00:50:06,300 --> 00:50:11,630 bottom here, we reversed the order of these two clauses. 888 00:50:11,630 --> 00:50:14,180 And certainly if this were logic, those ought to mean the 889 00:50:14,180 --> 00:50:16,690 same thing. 890 00:50:16,690 --> 00:50:20,060 However, in our particular implementation, if you say 891 00:50:20,060 --> 00:50:23,800 something like who's outranked by Ben Bitdiddle, what you'll 892 00:50:23,800 --> 00:50:27,870 find is that this rule will work perfectly well and 893 00:50:27,870 --> 00:50:31,030 generate answers, whereas this rule will go 894 00:50:31,030 --> 00:50:34,110 into an infinite loop. 895 00:50:34,110 --> 00:50:37,230 And the reason for that is that this will come in and 896 00:50:37,230 --> 00:50:39,400 say, oh, who's outranked by Ben Bitdiddle? 897 00:50:39,400 --> 00:50:41,920 898 00:50:41,920 --> 00:50:45,790 Find an s which is outranked by b, where b is Ben 899 00:50:45,790 --> 00:50:50,330 Bitdiddle, which is going to happen in it a subproblem. 900 00:50:50,330 --> 00:50:55,710 Oh gee, find an m such as m is outranked by Ben Bitdiddle 901 00:50:55,710 --> 00:50:58,560 with no restrictions on m. 902 00:50:58,560 --> 00:51:01,910 So this will say in order to solve this problem, I solve 903 00:51:01,910 --> 00:51:04,570 exactly the same problem. 904 00:51:04,570 --> 00:51:06,010 And then after I've solved that, I'll check for a 905 00:51:06,010 --> 00:51:08,000 supervisory relationship. 906 00:51:08,000 --> 00:51:10,290 Whereas this one won't get into that, because before it 907 00:51:10,290 --> 00:51:14,010 tries to find this outranked by, it'll already have had a 908 00:51:14,010 --> 00:51:15,260 restriction on m here. 909 00:51:15,260 --> 00:51:18,560 910 00:51:18,560 --> 00:51:21,190 So these two things which ought to mean the same, in 911 00:51:21,190 --> 00:51:22,860 fact, one goes into an infinite loop. 912 00:51:22,860 --> 00:51:26,720 One does not. 913 00:51:26,720 --> 00:51:30,630 That's a very extreme case of a general thing that you'll 914 00:51:30,630 --> 00:51:35,970 find in logic programming that if you start changing the 915 00:51:35,970 --> 00:51:39,910 order of the things in the ANDs or ORs, you'll find 916 00:51:39,910 --> 00:51:42,240 tremendous differences in efficiency. 917 00:51:42,240 --> 00:51:45,860 And we just saw an infinitely big difference in efficiency 918 00:51:45,860 --> 00:51:47,110 and an infinite loop. 919 00:51:47,110 --> 00:51:49,190 920 00:51:49,190 --> 00:51:52,220 And there are similar things having to do with the order in 921 00:51:52,220 --> 00:51:54,070 which you enter rules. 922 00:51:54,070 --> 00:51:55,980 The order in which it happens to look at rules in the 923 00:51:55,980 --> 00:51:59,140 database may vastly change the efficiency with which it gets 924 00:51:59,140 --> 00:52:01,860 out answers or, in fact, send it into an infinite loop for 925 00:52:01,860 --> 00:52:03,840 some orderings. 926 00:52:03,840 --> 00:52:08,370 And this whole thing has to do with the fact that you're 927 00:52:08,370 --> 00:52:10,950 checking these rules in some order. 928 00:52:10,950 --> 00:52:13,690 And some rules may lead to really long paths of 929 00:52:13,690 --> 00:52:15,180 implication. 930 00:52:15,180 --> 00:52:16,440 Others might not. 931 00:52:16,440 --> 00:52:18,480 And you don't know a priori which ones are good and which 932 00:52:18,480 --> 00:52:19,300 ones are bad. 933 00:52:19,300 --> 00:52:21,270 And there's a whole bunch of research having to do with 934 00:52:21,270 --> 00:52:24,840 that, mostly having to do with thinking about making parallel 935 00:52:24,840 --> 00:52:26,970 implementations of logic programming languages. 936 00:52:26,970 --> 00:52:29,330 And in some sense, what you'd like to do is check all rules 937 00:52:29,330 --> 00:52:31,870 in parallel and whichever ones get answers, 938 00:52:31,870 --> 00:52:32,620 you bubble them up. 939 00:52:32,620 --> 00:52:34,600 And if some go down infinite deductive 940 00:52:34,600 --> 00:52:36,290 changed, well, you just-- 941 00:52:36,290 --> 00:52:38,440 you know, memory is cheap and processors are cheap, and you 942 00:52:38,440 --> 00:52:40,550 just let them buzz for as for as long as you want. 943 00:52:40,550 --> 00:52:43,510 944 00:52:43,510 --> 00:52:47,660 There's a deeper problem, though, in comparing this 945 00:52:47,660 --> 00:52:50,870 logic language to real logic. 946 00:52:50,870 --> 00:52:54,260 The example I just showed you, it went into an infinite loop 947 00:52:54,260 --> 00:52:58,370 maybe, but at least it didn't give the wrong answer. 948 00:52:58,370 --> 00:53:02,980 There's an actual deeper problem when we start 949 00:53:02,980 --> 00:53:07,460 comparing, seriously comparing this logic language with real 950 00:53:07,460 --> 00:53:09,490 classical logic. 951 00:53:09,490 --> 00:53:14,030 So let's sort of review real classical logic. 952 00:53:14,030 --> 00:53:22,140 All humans are mortal. 953 00:53:22,140 --> 00:53:24,390 That's pretty classical logic. 954 00:53:24,390 --> 00:53:26,410 Then maybe we'll continue in the very 955 00:53:26,410 --> 00:53:29,120 best classical tradition. 956 00:53:29,120 --> 00:53:31,010 We'll say all-- 957 00:53:31,010 --> 00:53:32,740 let's make it really classical. 958 00:53:32,740 --> 00:53:41,690 All Greeks are human, which has the syllogism that 959 00:53:41,690 --> 00:53:48,060 Socrates is a Greek. 960 00:53:48,060 --> 00:53:49,210 And then what do you write here? 961 00:53:49,210 --> 00:53:51,890 I think three dots, classical logic. 962 00:53:51,890 --> 00:54:01,360 Therefore, then the syllogism, Socrates is mortal. 963 00:54:01,360 --> 00:54:05,880 So there's some real honest classical logic. 964 00:54:05,880 --> 00:54:12,570 Let's compare that with our classical logic database. 965 00:54:12,570 --> 00:54:16,270 So here's a classical logic database. 966 00:54:16,270 --> 00:54:18,030 Socrates is a Greek. 967 00:54:18,030 --> 00:54:19,600 Plato is a Greek. 968 00:54:19,600 --> 00:54:24,120 Zeus is a Greek, and Zeus is a god. 969 00:54:24,120 --> 00:54:30,780 And all humans are mortal. 970 00:54:30,780 --> 00:54:32,880 To show that something is mortal, it's enough to show 971 00:54:32,880 --> 00:54:34,650 that it's human. 972 00:54:34,650 --> 00:54:35,900 All humans are fallible. 973 00:54:35,900 --> 00:54:38,900 974 00:54:38,900 --> 00:54:40,980 And all Greeks are humans is not quite right. 975 00:54:40,980 --> 00:54:45,920 This says that all Greeks who are not gods are human. 976 00:54:45,920 --> 00:54:47,820 So to show something's human, it's enough to show it's a 977 00:54:47,820 --> 00:54:49,320 Greek and not a god. 978 00:54:49,320 --> 00:54:54,470 And the address of any Greek god is Mount Olympus. 979 00:54:54,470 --> 00:54:57,390 So there's a little classical logic database. 980 00:54:57,390 --> 00:54:59,490 And indeed, that would work fairly well. 981 00:54:59,490 --> 00:55:05,420 If we type that in and say is Socrates mortal or Socrates 982 00:55:05,420 --> 00:55:06,910 fallible or mortal? 983 00:55:06,910 --> 00:55:07,690 It'll say yes. 984 00:55:07,690 --> 00:55:09,710 Is Plato mortal and fallible. 985 00:55:09,710 --> 00:55:10,680 It'll say yes. 986 00:55:10,680 --> 00:55:12,210 If we say is Zeus mortal? 987 00:55:12,210 --> 00:55:14,900 It won't find anything. 988 00:55:14,900 --> 00:55:16,640 And it'll work perfectly well. 989 00:55:16,640 --> 00:55:20,120 However, suppose we want to extend this. 990 00:55:20,120 --> 00:55:25,070 Let's define what it means for someone to be a perfect being. 991 00:55:25,070 --> 00:55:27,020 Let's say rule: a perfect being. 992 00:55:27,020 --> 00:55:34,050 993 00:55:34,050 --> 00:55:35,480 And I think this is right. 994 00:55:35,480 --> 00:55:38,570 If you're up on your medieval scholastic philosophy, I 995 00:55:38,570 --> 00:55:41,350 believe that perfect beings are ones who were neither 996 00:55:41,350 --> 00:55:44,100 mortal nor fallible. 997 00:55:44,100 --> 00:55:59,300 AND NOT mortal x, NOT fallible x. 998 00:55:59,300 --> 00:56:03,340 So we'll define this system to teach it what a 999 00:56:03,340 --> 00:56:05,790 perfect being is. 1000 00:56:05,790 --> 00:56:09,110 And now what we're going to do is he ask for the address of 1001 00:56:09,110 --> 00:56:11,750 all the perfect beings. 1002 00:56:11,750 --> 00:56:23,680 AND the address of x is y and x is perfect. 1003 00:56:23,680 --> 00:56:26,590 And so what we're generating here is the world's most 1004 00:56:26,590 --> 00:56:32,050 exclusive mailing list. For the address of all the perfect 1005 00:56:32,050 --> 00:56:33,830 things, we might have typed this in. 1006 00:56:33,830 --> 00:56:36,240 Or we might type in this. 1007 00:56:36,240 --> 00:56:52,140 We'll say AND perfect of x and the address of x is y. 1008 00:56:52,140 --> 00:56:55,190 Well, suppose we type all that in and we try this query. 1009 00:56:55,190 --> 00:56:57,650 This query is going to give us an answer. 1010 00:56:57,650 --> 00:56:59,745 This query will say, yeah, Mount Olympus. 1011 00:56:59,745 --> 00:57:04,230 1012 00:57:04,230 --> 00:57:06,740 This query, in fact, is going to give us nothing. 1013 00:57:06,740 --> 00:57:11,640 It will say no addresses of perfect beings. 1014 00:57:11,640 --> 00:57:12,510 Now, why is that? 1015 00:57:12,510 --> 00:57:14,230 Why is there a difference? 1016 00:57:14,230 --> 00:57:15,690 This is not an infinite loop question. 1017 00:57:15,690 --> 00:57:19,145 This is a different answer question. 1018 00:57:19,145 --> 00:57:21,790 The reason is that if you remember the implementation of 1019 00:57:21,790 --> 00:57:25,880 NOT, NOT acted as a filter. 1020 00:57:25,880 --> 00:57:29,040 NOT said I'm going to take some possible dictionaries, 1021 00:57:29,040 --> 00:57:32,480 some possible frames, some possible answers, and filter 1022 00:57:32,480 --> 00:57:35,070 out the ones that happened to satisfy some condition, and 1023 00:57:35,070 --> 00:57:36,520 that's how I implement NOT. 1024 00:57:36,520 --> 00:57:40,730 If you think about what's going on here, I'll build this 1025 00:57:40,730 --> 00:57:46,470 query box where the output of an address piece gets fed into 1026 00:57:46,470 --> 00:57:47,720 a perfect piece. 1027 00:57:47,720 --> 00:57:50,290 1028 00:57:50,290 --> 00:57:52,880 What will happen is the address piece will set up some 1029 00:57:52,880 --> 00:57:55,290 things of everyone whose address I know. 1030 00:57:55,290 --> 00:57:59,880 Those will get filtered by the NOTs inside perfect here. 1031 00:57:59,880 --> 00:58:03,230 So it will throw out the ones which happened to be either 1032 00:58:03,230 --> 00:58:04,910 mortal or fallible. 1033 00:58:04,910 --> 00:58:07,700 In the other order what happens is I set this up, 1034 00:58:07,700 --> 00:58:09,520 started up with an empty frame. 1035 00:58:09,520 --> 00:58:12,000 The perfect in here doesn't find anything for the NOTs to 1036 00:58:12,000 --> 00:58:13,920 filter, so nothing comes out here at all. 1037 00:58:13,920 --> 00:58:18,830 1038 00:58:18,830 --> 00:58:20,940 And there's sort of nothing there that gets fed into the 1039 00:58:20,940 --> 00:58:21,940 address thing. 1040 00:58:21,940 --> 00:58:24,260 So here, I don't get an answer. 1041 00:58:24,260 --> 00:58:25,620 And again, the reason for that is NOT 1042 00:58:25,620 --> 00:58:27,440 isn't generating anything. 1043 00:58:27,440 --> 00:58:28,800 NOT's only throwing out things. 1044 00:58:28,800 --> 00:58:31,160 And if I never started up with anything, there's nothing for 1045 00:58:31,160 --> 00:58:32,020 it to throw out. 1046 00:58:32,020 --> 00:58:33,770 So out of this thing, I get the wrong answer. 1047 00:58:33,770 --> 00:58:37,200 1048 00:58:37,200 --> 00:58:37,970 How can you fix that? 1049 00:58:37,970 --> 00:58:39,070 Well, there are ways to fix that. 1050 00:58:39,070 --> 00:58:41,410 So you might say, well, that's sort of stupid. 1051 00:58:41,410 --> 00:58:43,700 Why are you just doing all your NOT 1052 00:58:43,700 --> 00:58:44,900 stuff at the beginning? 1053 00:58:44,900 --> 00:58:48,220 The right way to implement NOT is to realize that when you 1054 00:58:48,220 --> 00:58:51,360 have conditions like NOT, you should generate all your 1055 00:58:51,360 --> 00:58:54,140 answers first, and then with each of these dictionaries 1056 00:58:54,140 --> 00:58:58,560 pass along until at the very end I'll do filtering. 1057 00:58:58,560 --> 00:59:01,560 And there are implementations of logic languages that work 1058 00:59:01,560 --> 00:59:04,050 like that that solve this particular problem. 1059 00:59:04,050 --> 00:59:06,660 1060 00:59:06,660 --> 00:59:10,030 However, there's a more profound problem, which is 1061 00:59:10,030 --> 00:59:12,530 which one of these is the right answer? 1062 00:59:12,530 --> 00:59:15,320 Is it Mount Olympus or is it nothing? 1063 00:59:15,320 --> 00:59:19,420 So you might say it's Mount Olympus, because after all, 1064 00:59:19,420 --> 00:59:23,220 Zeus is in that database, and Zeus was 1065 00:59:23,220 --> 00:59:24,805 neither mortal nor fallible. 1066 00:59:24,805 --> 00:59:29,550 1067 00:59:29,550 --> 00:59:43,310 So you might say Zeus wants to satisfy NOT mortal Zeus or NOT 1068 00:59:43,310 --> 00:59:44,120 fallible Zeus. 1069 00:59:44,120 --> 00:59:47,638 But let's actually look at that database. 1070 00:59:47,638 --> 00:59:49,320 Let's look at it. 1071 00:59:49,320 --> 00:59:51,275 There's no way-- 1072 00:59:51,275 --> 00:59:54,810 how does it know that Zeus is not fallible? 1073 00:59:54,810 --> 00:59:57,930 There's nothing in there about that. 1074 00:59:57,930 --> 00:59:59,410 What's in there is that humans are fallible. 1075 00:59:59,410 --> 01:00:02,390 1076 01:00:02,390 --> 01:00:04,430 How does it know that Zeus is not mortal? 1077 01:00:04,430 --> 01:00:07,980 There's nothing in there about that. 1078 01:00:07,980 --> 01:00:12,000 It just said I don't have any rule, which-- 1079 01:00:12,000 --> 01:00:13,820 the only way I can deduce something's mortal is if it's 1080 01:00:13,820 --> 01:00:16,690 human, and that's all it really knows about mortal. 1081 01:00:16,690 --> 01:00:20,060 And in fact, if you remember your classical mythology, you 1082 01:00:20,060 --> 01:00:25,300 know that the Greek gods were not mortal but fallible. 1083 01:00:25,300 --> 01:00:30,850 So the answer is not in the rules there. 1084 01:00:30,850 --> 01:00:32,100 See, why does it deduce that? 1085 01:00:32,100 --> 01:00:34,710 1086 01:00:34,710 --> 01:00:37,330 See, Socrates would certainly not have made 1087 01:00:37,330 --> 01:00:40,080 this error of logic. 1088 01:00:40,080 --> 01:00:43,370 What NOT needs in this language is not NOT. 1089 01:00:43,370 --> 01:00:44,930 It's not the NOT of logic. 1090 01:00:44,930 --> 01:00:48,950 What NOT needs in this language is not deducible from 1091 01:00:48,950 --> 01:00:55,140 things in the database as opposed to not true. 1092 01:00:55,140 --> 01:00:57,300 That's a very big difference. 1093 01:00:57,300 --> 01:00:59,250 Subtle, but big. 1094 01:00:59,250 --> 01:01:03,080 So, in fact, this is perfectly happy to say not anything that 1095 01:01:03,080 --> 01:01:04,610 it doesn't know about. 1096 01:01:04,610 --> 01:01:06,900 So if you ask it is it not true that Zeus likes 1097 01:01:06,900 --> 01:01:07,830 chocolate ice cream? 1098 01:01:07,830 --> 01:01:10,251 It will say sure, it's not true. 1099 01:01:10,251 --> 01:01:12,850 Or anything else or anything it doesn't know about. 1100 01:01:12,850 --> 01:01:18,280 NOT means not deducible from the things you've told me. 1101 01:01:18,280 --> 01:01:22,760 In a world where you're identifying not deducible 1102 01:01:22,760 --> 01:01:25,800 with, in fact, not true, this is called the closed world 1103 01:01:25,800 --> 01:01:27,050 assumption. 1104 01:01:27,050 --> 01:01:36,870 1105 01:01:36,870 --> 01:01:38,320 The closed world assumption. 1106 01:01:38,320 --> 01:01:43,550 Anything that I cannot deduce from what I know 1107 01:01:43,550 --> 01:01:46,500 is not true, right? 1108 01:01:46,500 --> 01:01:49,290 If I don't know anything about x, the x isn't true. 1109 01:01:49,290 --> 01:01:51,420 That's very dangerous. 1110 01:01:51,420 --> 01:01:52,860 From a logical point of view, first of all, it doesn't 1111 01:01:52,860 --> 01:01:54,480 really makes sense. 1112 01:01:54,480 --> 01:01:58,860 Because if I don't know anything about x, I'm willing 1113 01:01:58,860 --> 01:02:00,240 to say not x. 1114 01:02:00,240 --> 01:02:03,850 But am I willing to say not not x? 1115 01:02:03,850 --> 01:02:04,500 Well, sure, I don't know anything 1116 01:02:04,500 --> 01:02:06,470 about that either maybe. 1117 01:02:06,470 --> 01:02:09,450 So not not x is not necessarily the same as x and 1118 01:02:09,450 --> 01:02:13,120 so on and so on and so on, so there's some sort of funny 1119 01:02:13,120 --> 01:02:15,970 bias in there. 1120 01:02:15,970 --> 01:02:17,290 So that's sort of funny. 1121 01:02:17,290 --> 01:02:22,840 The second thing, if you start building up real reasoning 1122 01:02:22,840 --> 01:02:27,210 programs based on this, think how dangerous that is. 1123 01:02:27,210 --> 01:02:33,420 You're saying I know I'm in a position to deduce everything 1124 01:02:33,420 --> 01:02:37,780 true that's relevant to this problem. 1125 01:02:37,780 --> 01:02:41,590 I'm reasoning, and built into my reasoning mechanism is the 1126 01:02:41,590 --> 01:02:45,160 assumption that anything that I don't know can't possibly be 1127 01:02:45,160 --> 01:02:48,860 relevant to this problem, right? 1128 01:02:48,860 --> 01:02:52,350 There are a lot of big organizations that work like 1129 01:02:52,350 --> 01:02:54,720 that, right? 1130 01:02:54,720 --> 01:02:56,830 Most corporate marketing divisions work like that. 1131 01:02:56,830 --> 01:03:00,560 You know the consequences to that. 1132 01:03:00,560 --> 01:03:04,490 So it's very dangerous to start really typing in these 1133 01:03:04,490 --> 01:03:08,750 big logical implication systems and going on what they 1134 01:03:08,750 --> 01:03:10,500 say, because they have this really limiting 1135 01:03:10,500 --> 01:03:12,600 assumption built in. 1136 01:03:12,600 --> 01:03:14,905 So you have to be very, very careful about that. 1137 01:03:14,905 --> 01:03:16,560 And that's a deep problem. 1138 01:03:16,560 --> 01:03:19,570 That's not a problem about we can make a little bit cleverer 1139 01:03:19,570 --> 01:03:22,360 implementation and do the filters and organize the 1140 01:03:22,360 --> 01:03:23,840 infinite loops to make them go away. 1141 01:03:23,840 --> 01:03:25,920 It's a different kind of problem. 1142 01:03:25,920 --> 01:03:27,060 It's a different semantics. 1143 01:03:27,060 --> 01:03:31,910 So I think to wrap this up, it's fair to say that logic 1144 01:03:31,910 --> 01:03:34,650 programming I think is a terrifically exciting idea, 1145 01:03:34,650 --> 01:03:38,010 the idea that you can bridge this gap from the imperative 1146 01:03:38,010 --> 01:03:42,300 to the declarative, that you can start talking about 1147 01:03:42,300 --> 01:03:46,900 relations and really get tremendous power by going 1148 01:03:46,900 --> 01:03:48,570 above the abstraction of what's my input 1149 01:03:48,570 --> 01:03:50,560 and what's my output. 1150 01:03:50,560 --> 01:03:55,160 And linked to logic, the problem is it's a goal that I 1151 01:03:55,160 --> 01:03:58,080 think has yet to be realized. 1152 01:03:58,080 --> 01:04:02,740 And probably one of the very most interesting research 1153 01:04:02,740 --> 01:04:06,530 questions going on now in languages is how do you 1154 01:04:06,530 --> 01:04:09,460 somehow make a real logic language? 1155 01:04:09,460 --> 01:04:11,940 And secondly, how do you bridge the gap from this world 1156 01:04:11,940 --> 01:04:16,020 of logic and relations to the worlds of more traditional 1157 01:04:16,020 --> 01:04:18,680 languages and somehow combine the power of both. 1158 01:04:18,680 --> 01:04:19,930 OK, let's break. 1159 01:04:19,930 --> 01:04:23,750 1160 01:04:23,750 --> 01:04:25,675 AUDIENCE: Couldn't you solve that last problem by having 1161 01:04:25,675 --> 01:04:27,430 the extra rules that imply it? 1162 01:04:27,430 --> 01:04:30,060 The problem here is you have the definition of something, 1163 01:04:30,060 --> 01:04:32,210 but you don't have the definition of its opposite. 1164 01:04:32,210 --> 01:04:35,890 If you include in the database something that says something 1165 01:04:35,890 --> 01:04:38,780 implies mortal x, something else implies not mortal x, 1166 01:04:38,780 --> 01:04:40,370 haven't you basically solved the problem? 1167 01:04:40,370 --> 01:04:43,370 1168 01:04:43,370 --> 01:04:45,660 PROFESSOR: But the issue is do you put a finite 1169 01:04:45,660 --> 01:04:46,910 number of those in? 1170 01:04:46,910 --> 01:04:50,740 1171 01:04:50,740 --> 01:04:54,980 AUDIENCE: If things are specified always in pairs-- 1172 01:04:54,980 --> 01:04:55,970 PROFESSOR: But the impression is then what do 1173 01:04:55,970 --> 01:04:57,220 you do about deduction? 1174 01:04:57,220 --> 01:05:00,200 1175 01:05:00,200 --> 01:05:03,400 You can't specify NOTs. 1176 01:05:03,400 --> 01:05:05,930 But the problem is, in a big system, it turns out that 1177 01:05:05,930 --> 01:05:07,960 might not be a finite number of things. 1178 01:05:07,960 --> 01:05:12,820 1179 01:05:12,820 --> 01:05:15,290 There are also sort of two issues. 1180 01:05:15,290 --> 01:05:16,690 Partly it might not be finite. 1181 01:05:16,690 --> 01:05:21,510 Partly it might be that's not what you want. 1182 01:05:21,510 --> 01:05:23,790 So a good example would be suppose I want to do 1183 01:05:23,790 --> 01:05:25,120 connectivity. 1184 01:05:25,120 --> 01:05:28,050 I want a reason about connectivity. 1185 01:05:28,050 --> 01:05:32,100 And I'm going to tell you there's four things: a and b 1186 01:05:32,100 --> 01:05:35,480 and c and d. 1187 01:05:35,480 --> 01:05:39,740 And I'll tell you a is connected to b and c's 1188 01:05:39,740 --> 01:05:43,200 connected to d. 1189 01:05:43,200 --> 01:05:45,260 And now I'll tell you is a connected to d? 1190 01:05:45,260 --> 01:05:46,780 That's the question. 1191 01:05:46,780 --> 01:05:49,360 There's an example where I would like something like the 1192 01:05:49,360 --> 01:05:50,610 closed world assumption. 1193 01:05:50,610 --> 01:05:54,200 1194 01:05:54,200 --> 01:05:57,630 That's a tiny toy, but a lot of times, I want to be able to 1195 01:05:57,630 --> 01:05:59,800 say something like anything that I haven't told you, 1196 01:05:59,800 --> 01:06:01,340 assume is not true. 1197 01:06:01,340 --> 01:06:04,260 1198 01:06:04,260 --> 01:06:06,990 So it's not as simple as you only want to put in explicit 1199 01:06:06,990 --> 01:06:09,470 NOTs all over the place. 1200 01:06:09,470 --> 01:06:11,200 It's that sometimes it really isn't clear 1201 01:06:11,200 --> 01:06:14,150 what you even want. 1202 01:06:14,150 --> 01:06:17,160 That having to specify both everything and not everything 1203 01:06:17,160 --> 01:06:20,960 is too precise, and then you get down into problems there. 1204 01:06:20,960 --> 01:06:24,420 But there are a lot of approaches that explicitly put 1205 01:06:24,420 --> 01:06:26,510 in NOTs and reason based on that. 1206 01:06:26,510 --> 01:06:28,070 So it's a very good idea. 1207 01:06:28,070 --> 01:06:31,620 It's just that then it starts becoming a little cumbersome 1208 01:06:31,620 --> 01:06:33,490 in the very large problems you'd like to use. 1209 01:06:33,490 --> 01:06:43,460 1210 01:06:43,460 --> 01:06:45,410 AUDIENCE: I'm not sure how directly related to the 1211 01:06:45,410 --> 01:06:48,840 argument this is, but one of your points was that one of 1212 01:06:48,840 --> 01:06:51,100 the dangers of the closed rule is you never really know all 1213 01:06:51,100 --> 01:06:53,840 the things that are there. 1214 01:06:53,840 --> 01:06:55,930 You never really know all the parts to it. 1215 01:06:55,930 --> 01:06:58,160 Isn't that a major problem with any programming? 1216 01:06:58,160 --> 01:07:01,110 I always write programs where I assume that I've got all the 1217 01:07:01,110 --> 01:07:04,430 cases, and so I check for them all or whatever, and somewhere 1218 01:07:04,430 --> 01:07:05,750 down the road, I find out that I didn't 1219 01:07:05,750 --> 01:07:07,390 check for one of them. 1220 01:07:07,390 --> 01:07:08,540 PROFESSOR: Well, sure, it's true. 1221 01:07:08,540 --> 01:07:14,630 But the problem here is it's that assumption which is the 1222 01:07:14,630 --> 01:07:16,610 thing that you're making if you believe you're identifying 1223 01:07:16,610 --> 01:07:19,600 this with logic. 1224 01:07:19,600 --> 01:07:20,510 So you're quite right. 1225 01:07:20,510 --> 01:07:22,220 It's a situation you're never in. 1226 01:07:22,220 --> 01:07:24,420 The problem is if you're starting to believe that what 1227 01:07:24,420 --> 01:07:27,305 this is doing is logic and you look at the rules you write 1228 01:07:27,305 --> 01:07:30,200 down and say what can I deduce from them, you have to be very 1229 01:07:30,200 --> 01:07:33,470 careful to remember that NOT means something else. 1230 01:07:33,470 --> 01:07:35,510 And it means something else based on an assumption which 1231 01:07:35,510 --> 01:07:39,030 is probably not true. 1232 01:07:39,030 --> 01:07:41,170 AUDIENCE: Do I understand you correctly that you cannot fix 1233 01:07:41,170 --> 01:07:44,510 this problem without killing off all possibilities of 1234 01:07:44,510 --> 01:07:47,990 inference through altering NOT? 1235 01:07:47,990 --> 01:07:49,370 PROFESSOR: No, that's not quite right. 1236 01:07:49,370 --> 01:07:50,620 There are other-- 1237 01:07:50,620 --> 01:07:52,710 1238 01:07:52,710 --> 01:07:56,340 there are ways to do logic with real NOTs. 1239 01:07:56,340 --> 01:07:58,540 There are actually ways to do that. 1240 01:07:58,540 --> 01:08:01,610 But they're very inefficient as far as anybody knows. 1241 01:08:01,610 --> 01:08:02,860 And they're much more-- 1242 01:08:02,860 --> 01:08:05,390 1243 01:08:05,390 --> 01:08:09,240 the, quote, inference in here is built into this unifier and 1244 01:08:09,240 --> 01:08:11,980 this pattern matching unification algorithm. 1245 01:08:11,980 --> 01:08:16,590 There are ways to automate real logical reasoning. 1246 01:08:16,590 --> 01:08:19,460 But it's not based on that, and logic programming 1247 01:08:19,460 --> 01:08:21,420 languages don't tend to do that because it's very 1248 01:08:21,420 --> 01:08:23,850 inefficient as far as anybody knows. 1249 01:08:23,850 --> 01:08:29,390 1250 01:08:29,390 --> 01:08:30,640 All right, thank you. 1251 01:08:30,640 --> 01:08:43,903 ================================================ FILE: SrtEN/lec9a_512kb.mp4.srt ================================================ 0 00:00:00,000 --> 00:00:02,190 1 00:00:02,190 --> 00:00:02,550 [MUSIC PLAYING - "JESU, JOY OF MAN'S DESIRING" BY JOHANN 2 00:00:02,550 --> 00:00:03,800 SEBASTIAN BACH] 3 00:00:03,800 --> 00:00:17,260 4 00:00:17,260 --> 00:00:20,520 PROFESSOR: Well, up 'til now, I suppose, we've been learning 5 00:00:20,520 --> 00:00:26,690 about a lot of techniques for organizing big programs, 6 00:00:26,690 --> 00:00:33,180 symbolic manipulation a bit, some of the technology that 7 00:00:33,180 --> 00:00:36,250 you use for establishing languages, one in terms of 8 00:00:36,250 --> 00:00:39,340 another, which is used for organizing very large 9 00:00:39,340 --> 00:00:43,160 programs. In fact, the nicest programs I know look more like 10 00:00:43,160 --> 00:00:47,310 a pile of languages than like a decomposition of a problem 11 00:00:47,310 --> 00:00:49,900 into parts. 12 00:00:49,900 --> 00:00:52,880 Well, I suppose at this point, there are still, however, a 13 00:00:52,880 --> 00:00:56,260 few mysteries about how this sort of stuff works. 14 00:00:56,260 --> 00:01:02,410 And so what we'd like to do now is diverge from the plan 15 00:01:02,410 --> 00:01:06,060 of telling you how to organize big programs, and rather tell 16 00:01:06,060 --> 00:01:09,870 you something about the mechanisms by which these 17 00:01:09,870 --> 00:01:12,196 things can be made to work. 18 00:01:12,196 --> 00:01:18,652 The main reason for this is demystification, if you will, 19 00:01:18,652 --> 00:01:21,930 that we have a lot of mysteries left, like exactly 20 00:01:21,930 --> 00:01:27,260 how it is the case that a program is controlled, how a 21 00:01:27,260 --> 00:01:30,760 computer knows what the next thing to do is, or 22 00:01:30,760 --> 00:01:32,430 something like that. 23 00:01:32,430 --> 00:01:36,410 And what I'd like to do now is make that clear to you, that 24 00:01:36,410 --> 00:01:38,580 even if you've never played with a physical computer 25 00:01:38,580 --> 00:01:44,660 before, the mechanism is really very simple, and that 26 00:01:44,660 --> 00:01:47,650 you can understand it completely with no trouble. 27 00:01:47,650 --> 00:01:51,390 So I'd like to start by imagining that we-- 28 00:01:51,390 --> 00:01:53,190 well, the way we're going to do this, by the way, is we're 29 00:01:53,190 --> 00:01:57,320 going to take some very simple Lisp programs, very simple 30 00:01:57,320 --> 00:02:02,160 Lisp programs, and transform them into hardware. 31 00:02:02,160 --> 00:02:05,260 I'm not going to worry about some intermediate step of 32 00:02:05,260 --> 00:02:07,560 going through some existing computer machine language and 33 00:02:07,560 --> 00:02:10,960 then showing you how that computer works, because that's 34 00:02:10,960 --> 00:02:12,750 not as illuminating. 35 00:02:12,750 --> 00:02:16,310 So what I'm really going to show you is how a piece of 36 00:02:16,310 --> 00:02:21,130 machinery can be built to do a job that you have written down 37 00:02:21,130 --> 00:02:22,040 as a program. 38 00:02:22,040 --> 00:02:25,760 That program is, in fact, a description of a machine. 39 00:02:25,760 --> 00:02:28,600 We're going to start with a very simple program, proceed 40 00:02:28,600 --> 00:02:32,250 to show you some simple mechanisms, proceed to a few 41 00:02:32,250 --> 00:02:36,660 more complicated programs, and then later show you a not very 42 00:02:36,660 --> 00:02:40,360 complicated program, how the evaluator transforms into a 43 00:02:40,360 --> 00:02:41,230 piece of hardware. 44 00:02:41,230 --> 00:02:43,390 And of course at that point, you have made the universal 45 00:02:43,390 --> 00:02:47,510 transition and can execute any program imaginable with a 46 00:02:47,510 --> 00:02:48,800 piece of well-defined hardware. 47 00:02:48,800 --> 00:02:51,392 48 00:02:51,392 --> 00:02:54,320 Well, let's start up now, give you a real concrete feeling 49 00:02:54,320 --> 00:02:55,440 for this sort of thing. 50 00:02:55,440 --> 00:02:59,600 Let's start with a very simple program. 51 00:02:59,600 --> 00:03:00,850 Here's Euclid's algorithm. 52 00:03:00,850 --> 00:03:03,880 53 00:03:03,880 --> 00:03:06,140 It's actually a little bit more modern 54 00:03:06,140 --> 00:03:06,770 than Euclid's algorithm. 55 00:03:06,770 --> 00:03:09,010 Euclid's algorithm for computing the greatest common 56 00:03:09,010 --> 00:03:14,300 divisor of two numbers was invented 350 BC, I think. 57 00:03:14,300 --> 00:03:15,550 It's the oldest known algorithm. 58 00:03:15,550 --> 00:03:19,320 59 00:03:19,320 --> 00:03:23,440 But here we're going to talk about GCD of A and B, the 60 00:03:23,440 --> 00:03:27,380 Greatest Common Divisor or two numbers, A and B. And the 61 00:03:27,380 --> 00:03:29,500 algorithm is extremely simple. 62 00:03:29,500 --> 00:03:38,170 If B is 0, then the result is going to be A. Otherwise, the 63 00:03:38,170 --> 00:03:52,990 result is the GCD of B and the remainder when A is divided by 64 00:03:52,990 --> 00:03:58,530 B. 65 00:03:58,530 --> 00:04:02,030 So this we have here is a very simple iterative process. 66 00:04:02,030 --> 00:04:05,550 This a simple recursive procedure, recursively defined 67 00:04:05,550 --> 00:04:08,340 procedure, recursive definition, which yields an 68 00:04:08,340 --> 00:04:09,990 iterative process. 69 00:04:09,990 --> 00:04:13,840 And the way it works is that every step, it determines 70 00:04:13,840 --> 00:04:15,996 whether B was zero. 71 00:04:15,996 --> 00:04:21,660 And if B is 0, we got the answer in A. Otherwise, we 72 00:04:21,660 --> 00:04:25,060 make another step where A is the old B, and B is the 73 00:04:25,060 --> 00:04:31,110 remainder of the old A divided by the old B. Very simple. 74 00:04:31,110 --> 00:04:33,900 Now this, I've already told you some of the mechanism by 75 00:04:33,900 --> 00:04:34,860 just saying it that way. 76 00:04:34,860 --> 00:04:36,360 I set it in time. 77 00:04:36,360 --> 00:04:39,710 I said there are certain steps, and that, in fact, one 78 00:04:39,710 --> 00:04:42,510 of the things you can see here is that one of the reasons why 79 00:04:42,510 --> 00:04:46,960 this is iterative is nothing is needed of the last step to 80 00:04:46,960 --> 00:04:49,490 get the answer. 81 00:04:49,490 --> 00:04:54,230 All of the information that's needed to run this algorithm 82 00:04:54,230 --> 00:04:57,540 is in A and B. It has two well-defined state variables. 83 00:04:57,540 --> 00:05:00,470 84 00:05:00,470 --> 00:05:04,370 So I'm going to define a machine for you that can 85 00:05:04,370 --> 00:05:06,560 compute you GCDs. 86 00:05:06,560 --> 00:05:07,120 Now let's see. 87 00:05:07,120 --> 00:05:10,010 Every computer that's ever been made that's a 88 00:05:10,010 --> 00:05:13,490 single-process computer, as opposed to a multiprocessor of 89 00:05:13,490 --> 00:05:17,840 some sort, is made according to the same plan. 90 00:05:17,840 --> 00:05:21,630 The plan is the computer has two parts, a part called the 91 00:05:21,630 --> 00:05:25,910 datapaths, and a part called the controller. 92 00:05:25,910 --> 00:05:28,960 The datapaths correspond to a calculator that you might 93 00:05:28,960 --> 00:05:31,580 have. It contains certain registers that remember 94 00:05:31,580 --> 00:05:33,560 things, and you've all used calculators. 95 00:05:33,560 --> 00:05:37,030 It has some buttons on it and some lights. 96 00:05:37,030 --> 00:05:39,010 And so by pushing the various buttons, you can cause 97 00:05:39,010 --> 00:05:42,080 operations to happen inside there among the registers, and 98 00:05:42,080 --> 00:05:45,160 some of the results to be displayed. 99 00:05:45,160 --> 00:05:46,250 That's completely mechanical. 100 00:05:46,250 --> 00:05:50,900 You could imagine that box has no intelligence in it. 101 00:05:50,900 --> 00:05:52,400 Now it might be very impressive that it can produce 102 00:05:52,400 --> 00:05:57,670 the sine of a number, but that at least is apparently 103 00:05:57,670 --> 00:05:58,970 possibly mechanical. 104 00:05:58,970 --> 00:06:00,685 At least, I could open that up in the same way I'm 105 00:06:00,685 --> 00:06:02,690 about to open GCD. 106 00:06:02,690 --> 00:06:04,830 So this may have a whole computer inside of it, but 107 00:06:04,830 --> 00:06:05,940 that's not interesting. 108 00:06:05,940 --> 00:06:08,200 Addition is certainly simple. 109 00:06:08,200 --> 00:06:10,890 That can be done without any further mechanism. 110 00:06:10,890 --> 00:06:15,080 Now also, if we were to look at the other half, the 111 00:06:15,080 --> 00:06:18,190 controller, that's a part that's dumb, too. 112 00:06:18,190 --> 00:06:20,350 It pushes the buttons. 113 00:06:20,350 --> 00:06:21,920 It pushes them according to the sequence, which is written 114 00:06:21,920 --> 00:06:26,290 down on a piece of paper, and observes the lights. 115 00:06:26,290 --> 00:06:29,210 And every so often, it comes to a place in a sequence that 116 00:06:29,210 --> 00:06:32,370 says, if light A is on, do this sequence. 117 00:06:32,370 --> 00:06:34,620 Otherwise, do that sequence. 118 00:06:34,620 --> 00:06:37,950 And thereby, there's no complexity there either. 119 00:06:37,950 --> 00:06:42,510 Well, let's just draw that and see what we feel about that. 120 00:06:42,510 --> 00:06:48,270 So for computing GCDs, what I want you to think about is 121 00:06:48,270 --> 00:06:50,310 that there are these registers. 122 00:06:50,310 --> 00:06:53,240 A register is a place where I store a number, in this case. 123 00:06:53,240 --> 00:06:56,810 And this one's called a. 124 00:06:56,810 --> 00:06:58,700 And then there's another one for storing b. 125 00:06:58,700 --> 00:07:03,170 126 00:07:03,170 --> 00:07:04,820 Now we have to see what things we can do with these 127 00:07:04,820 --> 00:07:08,150 registers, and they're not entirely obvious what you can 128 00:07:08,150 --> 00:07:09,840 do with them. 129 00:07:09,840 --> 00:07:10,940 Well, we have to see what things we 130 00:07:10,940 --> 00:07:11,890 need to do with them. 131 00:07:11,890 --> 00:07:14,030 We're looking at the problem we're trying to solve. 132 00:07:14,030 --> 00:07:17,100 One of the important things for designing a computer, 133 00:07:17,100 --> 00:07:20,810 which I think most designers don't do, is you study the 134 00:07:20,810 --> 00:07:23,910 problem you want to solve and then use what you learn from 135 00:07:23,910 --> 00:07:25,970 studying the problem you want to solve to put in the 136 00:07:25,970 --> 00:07:28,260 mechanisms needed to solve it in the computer you're 137 00:07:28,260 --> 00:07:32,140 building, no more no less. 138 00:07:32,140 --> 00:07:34,440 Now it may be that the problem you're trying to solve is 139 00:07:34,440 --> 00:07:37,200 everybody's problem, in which case you have to build in a 140 00:07:37,200 --> 00:07:40,190 universal interpreter of some language. 141 00:07:40,190 --> 00:07:42,580 But you shouldn't put any more in than required to build the 142 00:07:42,580 --> 00:07:44,540 universal interpreter of some language. 143 00:07:44,540 --> 00:07:47,025 We'll worry about that in a second. 144 00:07:47,025 --> 00:07:49,930 OK, going back to here, let's see. 145 00:07:49,930 --> 00:07:51,640 What do we have to be able to do? 146 00:07:51,640 --> 00:07:56,580 Well, somehow, we have to be able to get B into A. We have 147 00:07:56,580 --> 00:07:59,260 to be able to get the old value of B into the value of 148 00:07:59,260 --> 00:08:03,340 A. So we have to have some path by which stuff can flow, 149 00:08:03,340 --> 00:08:07,390 whatever this information is, from b to a. 150 00:08:07,390 --> 00:08:10,520 I'm going to draw that with by an arrow saying that it is 151 00:08:10,520 --> 00:08:13,640 possible to move the contents of b into a, replacing the 152 00:08:13,640 --> 00:08:15,120 value of a. 153 00:08:15,120 --> 00:08:17,660 And there's a little button here which you push which 154 00:08:17,660 --> 00:08:19,710 allows that to happen. 155 00:08:19,710 --> 00:08:23,070 That's what the little x is here. 156 00:08:23,070 --> 00:08:25,110 Now it's also the case that I have to be able to compute the 157 00:08:25,110 --> 00:08:27,000 remainder of a and b. 158 00:08:27,000 --> 00:08:28,860 Now that may be a complicated mess. 159 00:08:28,860 --> 00:08:31,960 On the other hand, I'm going to make it a small box. 160 00:08:31,960 --> 00:08:34,890 If we have to, we may open up that box and look inside and 161 00:08:34,890 --> 00:08:37,740 see what it is. 162 00:08:37,740 --> 00:08:39,580 So here, I'm going to have a little box, which I'm going to 163 00:08:39,580 --> 00:08:46,440 draw this way, which we'll call the remainder. 164 00:08:46,440 --> 00:08:48,265 And it's going to take in a. 165 00:08:48,265 --> 00:08:50,910 166 00:08:50,910 --> 00:08:54,370 That's going to take in b. 167 00:08:54,370 --> 00:08:59,660 And it's going to put out something, the remainder of a 168 00:08:59,660 --> 00:09:02,290 divided by b. 169 00:09:02,290 --> 00:09:04,050 Another thing we have to see here is that we have to be 170 00:09:04,050 --> 00:09:08,000 able to test whether b is equal to 0. 171 00:09:08,000 --> 00:09:10,020 Well, that means somebody's got to be looking at-- 172 00:09:10,020 --> 00:09:13,390 a thing that's looking at the value of b. 173 00:09:13,390 --> 00:09:17,390 I have a light bulb here which lights up if b equals 0. 174 00:09:17,390 --> 00:09:21,110 175 00:09:21,110 --> 00:09:24,030 That's its job. 176 00:09:24,030 --> 00:09:27,250 And finally, I suppose, because of the fact that we 177 00:09:27,250 --> 00:09:30,640 want the new value of a to be the old value of b, and 178 00:09:30,640 --> 00:09:33,820 simultaneously the new value of b to be something I've done 179 00:09:33,820 --> 00:09:38,160 with a, and if I plan to make my machine such that 180 00:09:38,160 --> 00:09:41,620 everything happens one at a time, one motion at a time, 181 00:09:41,620 --> 00:09:44,526 and I can't put two numbers in a register, then I have to 182 00:09:44,526 --> 00:09:46,300 have another place to put one while I'm interchanging. 183 00:09:46,300 --> 00:09:49,534 184 00:09:49,534 --> 00:09:50,000 OK? 185 00:09:50,000 --> 00:09:52,490 I can't interchange the two things in my hands, unless I 186 00:09:52,490 --> 00:09:54,730 either put two in one hand and then pull it back the other 187 00:09:54,730 --> 00:09:57,960 way, or unless I put one down, pick it up, and put the other 188 00:09:57,960 --> 00:10:02,930 one, like that, unless I'm a juggler, which I'm not, as you 189 00:10:02,930 --> 00:10:06,200 can see, in which case I have a 190 00:10:06,200 --> 00:10:08,850 possibility of timing errors. 191 00:10:08,850 --> 00:10:11,500 In fact, much of the type of computer design people do 192 00:10:11,500 --> 00:10:15,260 involves timing errors, of some potential timing errors, 193 00:10:15,260 --> 00:10:17,840 which I don't much like. 194 00:10:17,840 --> 00:10:22,500 So for that reason, I have to have a place to put the second 195 00:10:22,500 --> 00:10:23,410 one of them down. 196 00:10:23,410 --> 00:10:25,820 So I have a place called t, which is a register just for 197 00:10:25,820 --> 00:10:30,470 temporary, t, with a button on it. 198 00:10:30,470 --> 00:10:32,450 And then I'll take the result of that, since I have to take 199 00:10:32,450 --> 00:10:35,640 that and put into b, over here, we'll take the result of 200 00:10:35,640 --> 00:10:39,300 that and go like this, and a button here. 201 00:10:39,300 --> 00:10:42,430 202 00:10:42,430 --> 00:10:47,600 So that's the datapaths of a GCD machine. 203 00:10:47,600 --> 00:10:49,740 Now what's the controller? 204 00:10:49,740 --> 00:10:52,280 Controller's a very simple thing, too. 205 00:10:52,280 --> 00:10:53,710 The machine has a state. 206 00:10:53,710 --> 00:10:59,010 The way I like to visualize that is that I've got a maze. 207 00:10:59,010 --> 00:11:01,680 And the maze has a bunch of places 208 00:11:01,680 --> 00:11:04,430 connected by directed arrows. 209 00:11:04,430 --> 00:11:08,430 And what I have is a marble, which represents the state of 210 00:11:08,430 --> 00:11:10,740 the controller. 211 00:11:10,740 --> 00:11:13,256 The marble rolls around in the maze. 212 00:11:13,256 --> 00:11:17,150 Of course, this analogy breaks down for energy reasons. 213 00:11:17,150 --> 00:11:19,310 I sometimes have to pump the marble up to the top, because 214 00:11:19,310 --> 00:11:22,000 it's going to otherwise be a perpetual motion machine. 215 00:11:22,000 --> 00:11:24,270 But not worrying about that, this is 216 00:11:24,270 --> 00:11:26,080 not a physical analogy. 217 00:11:26,080 --> 00:11:27,680 This marble rolls around. 218 00:11:27,680 --> 00:11:30,180 And every time it rolls around certain bumpers, like in a 219 00:11:30,180 --> 00:11:34,830 pinball machine, it pushes one of these buttons. 220 00:11:34,830 --> 00:11:36,810 And every so often, it comes to a place, which is a 221 00:11:36,810 --> 00:11:40,250 division, where it has to make a choice. 222 00:11:40,250 --> 00:11:42,360 And there's a flap, which is controlled by this. 223 00:11:42,360 --> 00:11:46,000 224 00:11:46,000 --> 00:11:48,820 So that's a really mechanical way of thinking about it. 225 00:11:48,820 --> 00:11:50,980 Of course, controllers these days, are not built that way 226 00:11:50,980 --> 00:11:51,840 in real computers. 227 00:11:51,840 --> 00:11:54,090 They're built with a little bit of 228 00:11:54,090 --> 00:11:56,610 ROM and a state register. 229 00:11:56,610 --> 00:11:59,726 But there was a time, like the DEC PDP-6, where that's how 230 00:11:59,726 --> 00:12:01,400 you built the controller of a machine. 231 00:12:01,400 --> 00:12:06,800 There was a bit that ran around the delay line, and it 232 00:12:06,800 --> 00:12:08,580 triggered things as it went by. 233 00:12:08,580 --> 00:12:09,860 And it would come back to the beginning and 234 00:12:09,860 --> 00:12:11,990 get fed round again. 235 00:12:11,990 --> 00:12:13,630 And of course, there were all sorts of great bugs you could 236 00:12:13,630 --> 00:12:17,670 have like two bits going around, two marbles. 237 00:12:17,670 --> 00:12:19,260 And then the machine has lost its marbles. 238 00:12:19,260 --> 00:12:20,980 That happens, too. 239 00:12:20,980 --> 00:12:21,935 Oh, well. 240 00:12:21,935 --> 00:12:24,570 So anyway, for this machine, what I have 241 00:12:24,570 --> 00:12:25,940 to do is the following. 242 00:12:25,940 --> 00:12:27,690 I'm going to start my maze here. 243 00:12:27,690 --> 00:12:30,520 244 00:12:30,520 --> 00:12:35,460 And the first thing I've got to do, in a notation which 245 00:12:35,460 --> 00:12:41,540 many of you are familiar with, is b equal to zero, a test. 246 00:12:41,540 --> 00:12:44,540 And there's a possibility, either yes, in 247 00:12:44,540 --> 00:12:45,790 which case I'm done. 248 00:12:45,790 --> 00:12:49,790 249 00:12:49,790 --> 00:12:53,220 Otherwise, if no, then I'm going have to 250 00:12:53,220 --> 00:12:54,725 roll over some bumpers. 251 00:12:54,725 --> 00:12:57,420 I'm going to do it in the following order. 252 00:12:57,420 --> 00:13:04,050 I want to do this interchange game. 253 00:13:04,050 --> 00:13:07,360 Now first, since I need both a and b, but then the first-- 254 00:13:07,360 --> 00:13:08,670 and this is not necessary-- 255 00:13:08,670 --> 00:13:11,070 I want to collect this. 256 00:13:11,070 --> 00:13:13,240 This is the thing that's going to go into b. 257 00:13:13,240 --> 00:13:15,680 So I'm going to say, take this, which depends upon both 258 00:13:15,680 --> 00:13:19,150 a and b, and put the remainder into here. 259 00:13:19,150 --> 00:13:22,940 So I'm going to push this button first. Then, I'm going 260 00:13:22,940 --> 00:13:26,460 to transfer b to a, push that button, and then I transfer 261 00:13:26,460 --> 00:13:32,030 the temporary into b, push that button. 262 00:13:32,030 --> 00:13:37,750 So a very sequential machine, it's very inefficient. 263 00:13:37,750 --> 00:13:39,810 But that's fine right now. 264 00:13:39,810 --> 00:13:42,305 We're going to name the buttons, t gets remainder. 265 00:13:42,305 --> 00:13:46,750 266 00:13:46,750 --> 00:13:50,036 a gets b. 267 00:13:50,036 --> 00:13:55,470 And b gets t. 268 00:13:55,470 --> 00:13:59,150 And then I'm going to go around here and it's to go 269 00:13:59,150 --> 00:14:01,620 back to start. 270 00:14:01,620 --> 00:14:03,870 And if you look, what are we seeing here? 271 00:14:03,870 --> 00:14:05,080 We're seeing the various-- 272 00:14:05,080 --> 00:14:07,400 what I really have is some sort of mechanical connection, 273 00:14:07,400 --> 00:14:13,620 where t gets r controls this thing. 274 00:14:13,620 --> 00:14:16,830 275 00:14:16,830 --> 00:14:20,910 And I have here that a gets b controls this fellow over 276 00:14:20,910 --> 00:14:28,120 here, and this fellow over here. 277 00:14:28,120 --> 00:14:31,090 Boy, that's absolutely pessimal, 278 00:14:31,090 --> 00:14:32,630 the inverse of optimal. 279 00:14:32,630 --> 00:14:34,590 Every line heads across every other line the way I drew it. 280 00:14:34,590 --> 00:14:38,540 281 00:14:38,540 --> 00:14:41,150 I suppose this goes here, b gets t. 282 00:14:41,150 --> 00:14:45,690 283 00:14:45,690 --> 00:14:48,040 Now I'd like to run this machine. 284 00:14:48,040 --> 00:14:50,260 But before I run the machine, I want to write down a 285 00:14:50,260 --> 00:14:52,243 description of this controller, just so you can 286 00:14:52,243 --> 00:14:54,160 see that these things, of course, as usual, can be 287 00:14:54,160 --> 00:14:56,560 written down in some nice language, so that we don't 288 00:14:56,560 --> 00:14:59,010 have to always draw these diagrams. One of the problems 289 00:14:59,010 --> 00:15:00,710 with diagrams is that they take up a lot of space. 290 00:15:00,710 --> 00:15:03,220 And for a machine this small, it takes two blackboards. 291 00:15:03,220 --> 00:15:05,690 For a machine that's the evaluator machine, I have 292 00:15:05,690 --> 00:15:08,320 trouble putting it into this room, even though 293 00:15:08,320 --> 00:15:09,900 it isn't very big. 294 00:15:09,900 --> 00:15:11,550 So I'm going to make a little language for this that's just 295 00:15:11,550 --> 00:15:17,530 a description of that, saying define a 296 00:15:17,530 --> 00:15:24,420 machine we'll call GCD. 297 00:15:24,420 --> 00:15:25,970 Of course, once we have something like this, we have a 298 00:15:25,970 --> 00:15:27,220 simulator for it. 299 00:15:27,220 --> 00:15:29,630 And the reason why we want to build a language in this form, 300 00:15:29,630 --> 00:15:31,500 is because all of a sudden we can manipulate these 301 00:15:31,500 --> 00:15:33,210 expressions that I'm writing down. 302 00:15:33,210 --> 00:15:35,970 And then of course I can write things that can algebraically 303 00:15:35,970 --> 00:15:38,730 manipulate these things, simulate them, all that sort 304 00:15:38,730 --> 00:15:41,255 of things that I might want to do, perhaps transform them as 305 00:15:41,255 --> 00:15:43,630 a layout, who knows. 306 00:15:43,630 --> 00:15:48,185 Once I have a nice representation of registers, 307 00:15:48,185 --> 00:15:56,326 it has certain registers, which we can call A, B, and T. 308 00:15:56,326 --> 00:15:57,576 And there's a controller. 309 00:15:57,576 --> 00:16:02,190 310 00:16:02,190 --> 00:16:04,910 Actually, a better language, which would be more explicit, 311 00:16:04,910 --> 00:16:09,440 would be one which named every button also and 312 00:16:09,440 --> 00:16:10,420 said what it did. 313 00:16:10,420 --> 00:16:13,390 Like, this button causes the contents of T to go to the 314 00:16:13,390 --> 00:16:16,310 contents of B. Well I don't want to do that, because it's 315 00:16:16,310 --> 00:16:18,410 actually harder to read to do that, and it 316 00:16:18,410 --> 00:16:19,510 takes up more space. 317 00:16:19,510 --> 00:16:21,710 So I'm going to have that in the instructions written in 318 00:16:21,710 --> 00:16:23,290 the controller. 319 00:16:23,290 --> 00:16:26,460 It's going to be implicit what the operations are. 320 00:16:26,460 --> 00:16:29,990 They can be deduced by reading these and collecting together 321 00:16:29,990 --> 00:16:33,500 all the different things that can be done. 322 00:16:33,500 --> 00:16:35,482 Well, let's just look at what these things are. 323 00:16:35,482 --> 00:16:42,550 There's a little loop that we go around which says branch, 324 00:16:42,550 --> 00:16:47,430 this is the representation of the little flap that decides 325 00:16:47,430 --> 00:16:58,010 which way you go here, if 0 fetch of B, the contents of B, 326 00:16:58,010 --> 00:17:00,790 and if the contents of B is 0, then go to a 327 00:17:00,790 --> 00:17:03,640 place called done. 328 00:17:03,640 --> 00:17:06,030 Now, one thing you're seeing here, this looks very much 329 00:17:06,030 --> 00:17:08,170 like a traditional computer language. 330 00:17:08,170 --> 00:17:13,099 And what you're seeing here is things like labels that 331 00:17:13,099 --> 00:17:17,609 represent places in a sequence written down as a sequence. 332 00:17:17,609 --> 00:17:21,700 The reason why they're needed is because over here, I've 333 00:17:21,700 --> 00:17:23,329 written something with loops. 334 00:17:23,329 --> 00:17:26,569 But if I'm writing English text, or something like that, 335 00:17:26,569 --> 00:17:28,580 it's hard to refer to a place. 336 00:17:28,580 --> 00:17:31,440 I don't have arrows. 337 00:17:31,440 --> 00:17:33,450 Arrows are represented by giving names to the places 338 00:17:33,450 --> 00:17:35,680 where the arrows terminate, and then referring to them by 339 00:17:35,680 --> 00:17:37,620 those names. 340 00:17:37,620 --> 00:17:39,860 Now this is just an encoding. 341 00:17:39,860 --> 00:17:43,150 There's nothing magical about things like that. 342 00:17:43,150 --> 00:17:45,310 Next thing we're going to do is we're going to say, how do 343 00:17:45,310 --> 00:17:46,840 we do T gets R? 344 00:17:46,840 --> 00:17:49,030 Oh, that's easy enough, assign. 345 00:17:49,030 --> 00:17:51,930 346 00:17:51,930 --> 00:17:56,400 We assign to T the remainder. 347 00:17:56,400 --> 00:18:01,470 Assign is the name of the button. 348 00:18:01,470 --> 00:18:03,140 That's the button-pusher. 349 00:18:03,140 --> 00:18:05,910 Assign to T the remainder, and here's the representation of 350 00:18:05,910 --> 00:18:17,550 the operation, when we divide the fetch of A by the fetch of 351 00:18:17,550 --> 00:18:23,478 B. 352 00:18:23,478 --> 00:18:35,560 And we're also going to assign to A the fetch of B, assign to 353 00:18:35,560 --> 00:18:50,140 B the result of getting the contents of T. And now I have 354 00:18:50,140 --> 00:18:53,280 to refer to the beginning here. 355 00:18:53,280 --> 00:18:55,760 I see, why don't I call that loop like I have here? 356 00:18:55,760 --> 00:19:05,390 357 00:19:05,390 --> 00:19:07,610 So that's that reference to that arrow. 358 00:19:07,610 --> 00:19:08,950 And when we're done, we're done. 359 00:19:08,950 --> 00:19:14,340 We go to here, which is the end of the thing. 360 00:19:14,340 --> 00:19:18,090 So here's just a written representation of this 361 00:19:18,090 --> 00:19:21,660 fragment of machinery that we've drawn here. 362 00:19:21,660 --> 00:19:25,490 Now the next thing I'd like to do is run this. 363 00:19:25,490 --> 00:19:27,620 I want us to feel it running. 364 00:19:27,620 --> 00:19:31,010 Never done this before, you got to do it once. 365 00:19:31,010 --> 00:19:33,100 So let's take a particular problem. 366 00:19:33,100 --> 00:19:38,580 Suppose we want to compute the GCD of a equals 30 367 00:19:38,580 --> 00:19:42,210 and b equals 42. 368 00:19:42,210 --> 00:19:45,860 I have no idea what that is right now. 369 00:19:45,860 --> 00:19:50,530 But a 30 and b is 42. 370 00:19:50,530 --> 00:19:52,410 So that's how I start this thing up. 371 00:19:52,410 --> 00:19:54,240 Well, what's the first thing I do? 372 00:19:54,240 --> 00:19:57,590 I say is B equal to 0, no. 373 00:19:57,590 --> 00:20:01,500 Then assign to T the remainder of the fetch of A and the 374 00:20:01,500 --> 00:20:05,640 fetch of B. Well the remainder of 30 when divided by 375 00:20:05,640 --> 00:20:11,130 42 is itself 30. 376 00:20:11,130 --> 00:20:12,920 Push that button. 377 00:20:12,920 --> 00:20:17,100 Now the marble has rolled to here. 378 00:20:17,100 --> 00:20:21,220 A gets B. That pushes this button. 379 00:20:21,220 --> 00:20:26,360 So 42 moves into here. 380 00:20:26,360 --> 00:20:29,870 B gets C. Push that button. 381 00:20:29,870 --> 00:20:32,225 The 30 goes here. 382 00:20:32,225 --> 00:20:34,660 Let met just interchange them. 383 00:20:34,660 --> 00:20:38,280 Now let's see, go back to the beginning. 384 00:20:38,280 --> 00:20:40,200 B 0, no. 385 00:20:40,200 --> 00:20:43,230 T gets the remainder. 386 00:20:43,230 --> 00:20:47,240 I suppose the remainder when dividing 42 by 30 is 12. 387 00:20:47,240 --> 00:20:48,530 I push that one. 388 00:20:48,530 --> 00:20:54,360 Next thing I do is allow the 30 to go to here, push this 389 00:20:54,360 --> 00:20:55,950 one, allow the 12 to go to here. 390 00:20:55,950 --> 00:20:59,550 391 00:20:59,550 --> 00:21:00,380 Go around this thing. 392 00:21:00,380 --> 00:21:01,530 Is that done? 393 00:21:01,530 --> 00:21:02,360 No. 394 00:21:02,360 --> 00:21:05,080 How about-- 395 00:21:05,080 --> 00:21:08,850 so now I have to find out the remainder of 30 divided by 12. 396 00:21:08,850 --> 00:21:12,420 And I believe that's 6. 397 00:21:12,420 --> 00:21:15,916 So 6 goes here on this button push. 398 00:21:15,916 --> 00:21:18,550 Then the next thing I push is this one, which the 399 00:21:18,550 --> 00:21:23,730 12 goes into here. 400 00:21:23,730 --> 00:21:25,090 Then I push this button. 401 00:21:25,090 --> 00:21:26,340 The 6 gets into here. 402 00:21:26,340 --> 00:21:29,850 403 00:21:29,850 --> 00:21:32,100 Is 6 equal to 0? 404 00:21:32,100 --> 00:21:33,420 No. 405 00:21:33,420 --> 00:21:34,380 OK. 406 00:21:34,380 --> 00:21:38,380 So then at that point, the next thing to do is divide it. 407 00:21:38,380 --> 00:21:40,660 Ooh, this has got a remainder of 0. 408 00:21:40,660 --> 00:21:42,360 Looks like we're almost done. 409 00:21:42,360 --> 00:21:44,360 Move the 6 over here next. 410 00:21:44,360 --> 00:21:47,230 411 00:21:47,230 --> 00:21:49,090 0 over here. 412 00:21:49,090 --> 00:21:50,200 Is the answer 0? 413 00:21:50,200 --> 00:21:51,340 Yes. 414 00:21:51,340 --> 00:21:54,470 B is 0, therefore the answer is in A. 415 00:21:54,470 --> 00:21:56,610 The answer is 6. 416 00:21:56,610 --> 00:21:58,400 And indeed that's right, because if we look at the 417 00:21:58,400 --> 00:22:07,060 original problem, what we have is 30 is 2 times 3 times 5, 418 00:22:07,060 --> 00:22:11,670 and 42 is 2 times 3 times 7. 419 00:22:11,670 --> 00:22:15,090 So the greatest common divisor is 2 times 3, which is 6. 420 00:22:15,090 --> 00:22:18,380 421 00:22:18,380 --> 00:22:20,780 Now normally, we write one other little line here, just 422 00:22:20,780 --> 00:22:23,770 to make it a little bit clearer, which is that we 423 00:22:23,770 --> 00:22:29,760 leave in a connection saying that this light is the guy 424 00:22:29,760 --> 00:22:31,010 that that flap looks at. 425 00:22:31,010 --> 00:22:34,050 426 00:22:34,050 --> 00:22:38,440 Of course, any real machine has a lot more complicated 427 00:22:38,440 --> 00:22:41,350 things in it than what I've just shown you. 428 00:22:41,350 --> 00:22:47,980 Let's look for a second at the first still store. 429 00:22:47,980 --> 00:22:50,190 Wow. 430 00:22:50,190 --> 00:22:52,850 Well you see, for example, one thing we might want to do is 431 00:22:52,850 --> 00:22:56,840 worry about the operations that are of IO form. 432 00:22:56,840 --> 00:23:01,980 And we may have to collect something from the outside. 433 00:23:01,980 --> 00:23:06,310 So a state machine that we might have, the controller may 434 00:23:06,310 --> 00:23:11,190 have to, for example, get a value from something and put 435 00:23:11,190 --> 00:23:13,490 register a to load it up. 436 00:23:13,490 --> 00:23:17,070 I have to master load up register b with another value. 437 00:23:17,070 --> 00:23:19,900 And then later, when I'm done, I might want to print the 438 00:23:19,900 --> 00:23:20,970 answer out. 439 00:23:20,970 --> 00:23:26,250 And of course, that might be either simple or complicated. 440 00:23:26,250 --> 00:23:28,320 I'm writing, assuming print is very simple, and 441 00:23:28,320 --> 00:23:29,880 read is very simple. 442 00:23:29,880 --> 00:23:31,700 But in fact, in the real world, those are very 443 00:23:31,700 --> 00:23:34,930 complicated operations, usually much, much larger and 444 00:23:34,930 --> 00:23:37,080 more complicated than the thing you're doing as your 445 00:23:37,080 --> 00:23:38,330 problem you're trying to solve. 446 00:23:38,330 --> 00:23:41,670 447 00:23:41,670 --> 00:23:45,060 On the other hand, I can remember a time when, I 448 00:23:45,060 --> 00:23:49,320 remember using IBM 7090 computer of sorts, where 449 00:23:49,320 --> 00:23:53,600 things like read and write of a single object, a single 450 00:23:53,600 --> 00:23:58,040 number, a number, is a primitive operation of the IO 451 00:23:58,040 --> 00:23:59,065 controller. 452 00:23:59,065 --> 00:24:00,400 OK? 453 00:24:00,400 --> 00:24:02,330 And so we have that kind of thing in there. 454 00:24:02,330 --> 00:24:08,360 And in such a machine, well, what are we really doing? 455 00:24:08,360 --> 00:24:11,110 We're just saying that there's a source over here called 456 00:24:11,110 --> 00:24:14,660 "read," which is an operation which always has a value. 457 00:24:14,660 --> 00:24:17,480 We have to think about this as always having a value which 458 00:24:17,480 --> 00:24:21,660 can be gated into either register a or b. 459 00:24:21,660 --> 00:24:24,290 And print is some sort of thing which when you gate it 460 00:24:24,290 --> 00:24:27,410 appropriately, when you push the button on it, will cause a 461 00:24:27,410 --> 00:24:31,660 print of the value that's currently in register a. 462 00:24:31,660 --> 00:24:33,050 Nothing very exciting. 463 00:24:33,050 --> 00:24:36,110 So that's one sort of thing you might want to have. But 464 00:24:36,110 --> 00:24:37,260 these are also other things that are 465 00:24:37,260 --> 00:24:38,320 a little bit worrisome. 466 00:24:38,320 --> 00:24:41,050 Like I've used here some complicated mechanisms. 467 00:24:41,050 --> 00:24:43,850 What you see here is remainder. 468 00:24:43,850 --> 00:24:44,690 What is that? 469 00:24:44,690 --> 00:24:46,920 That may not be so obvious how to compute. 470 00:24:46,920 --> 00:24:49,860 It may be something which when you open it up, you get a 471 00:24:49,860 --> 00:24:51,880 whole machine. 472 00:24:51,880 --> 00:24:52,720 OK? 473 00:24:52,720 --> 00:24:54,540 In fact, that's true. 474 00:24:54,540 --> 00:24:59,570 For example, if I write down the program for remainder, the 475 00:24:59,570 --> 00:25:04,480 simplest program for it is by repeated subtraction. 476 00:25:04,480 --> 00:25:06,380 Because of course, division can be done by repeated 477 00:25:06,380 --> 00:25:09,800 subtraction of numbers, of integers. 478 00:25:09,800 --> 00:25:30,270 So the remainder of N divided by D is nothing more than if N 479 00:25:30,270 --> 00:25:34,920 is less than D, then the result is N. Otherwise, it's 480 00:25:34,920 --> 00:25:48,350 the remainder when we subtract D from N with respect to D, 481 00:25:48,350 --> 00:25:52,160 when divided by D. Gee, this looks just 482 00:25:52,160 --> 00:25:56,890 like the GCD program. 483 00:25:56,890 --> 00:25:59,750 Of course, it's not a very nice way to do remainders. 484 00:25:59,750 --> 00:26:01,525 You'd really want to use something like binary notation 485 00:26:01,525 --> 00:26:05,550 and shift and things like that in a practical computer. 486 00:26:05,550 --> 00:26:09,060 But the point of that is that if I open this thing up, I 487 00:26:09,060 --> 00:26:11,880 might find inside of it a computer. 488 00:26:11,880 --> 00:26:13,510 Oh, we know how to do that. 489 00:26:13,510 --> 00:26:15,640 We just made one. 490 00:26:15,640 --> 00:26:17,400 And it could be another thing just like this. 491 00:26:17,400 --> 00:26:20,030 On the other hand, we might want to make a more efficient 492 00:26:20,030 --> 00:26:22,810 or better-structured machine, or maybe make use of some of 493 00:26:22,810 --> 00:26:25,340 the registers more than once, or some horrible mess like 494 00:26:25,340 --> 00:26:27,550 that that hardware designers like to do, and 495 00:26:27,550 --> 00:26:29,250 for very good reasons. 496 00:26:29,250 --> 00:26:32,990 So for example, here's a machine that you see, which 497 00:26:32,990 --> 00:26:35,050 you're not supposed to be able to read. 498 00:26:35,050 --> 00:26:37,520 It's a little bit complicated. 499 00:26:37,520 --> 00:26:41,830 But what it is is the integration of the remainder 500 00:26:41,830 --> 00:26:44,210 into the GCD machine. 501 00:26:44,210 --> 00:26:46,020 And it takes, in fact, no more registers. 502 00:26:46,020 --> 00:26:48,360 There are three registers in the datapaths. 503 00:26:48,360 --> 00:26:49,050 OK? 504 00:26:49,050 --> 00:26:51,550 But now there's a subtractor. 505 00:26:51,550 --> 00:26:53,020 There are two things that are tested. 506 00:26:53,020 --> 00:26:57,250 Is b equal to 0, or is t less than b? 507 00:26:57,250 --> 00:27:00,800 And then the controller, which you see over here, is not much 508 00:27:00,800 --> 00:27:01,850 more complicated. 509 00:27:01,850 --> 00:27:07,040 But it has two loops in it, one of which is the main one 510 00:27:07,040 --> 00:27:10,370 for doing the GCD, and one of which is the subtraction loop 511 00:27:10,370 --> 00:27:14,030 for doing the remainder sub-operation. 512 00:27:14,030 --> 00:27:17,190 And there are ways, of course, of, if you think about it, 513 00:27:17,190 --> 00:27:19,920 taking the remainder program. 514 00:27:19,920 --> 00:27:22,270 If I take remainder, as you see over there, as a lambda 515 00:27:22,270 --> 00:27:25,920 expression, substitute it in for remainder over here in the 516 00:27:25,920 --> 00:27:30,910 GCD program, then do some simplification by substituting 517 00:27:30,910 --> 00:27:34,670 a and b for remainder in there, then I 518 00:27:34,670 --> 00:27:36,630 can unwind this loop. 519 00:27:36,630 --> 00:27:41,660 And I can get this piece of machinery by basically, a 520 00:27:41,660 --> 00:27:44,700 little bit of algebraic simplification on the lambda 521 00:27:44,700 --> 00:27:45,950 expressions. 522 00:27:45,950 --> 00:27:48,550 523 00:27:48,550 --> 00:27:50,140 So I suppose you've seen your first very 524 00:27:50,140 --> 00:27:52,280 simple machines now. 525 00:27:52,280 --> 00:27:53,530 Are there any questions? 526 00:27:53,530 --> 00:28:02,700 527 00:28:02,700 --> 00:28:05,360 Good. 528 00:28:05,360 --> 00:28:06,610 This looks easy, doesn't it? 529 00:28:06,610 --> 00:28:10,200 530 00:28:10,200 --> 00:28:10,550 Thank you. 531 00:28:10,550 --> 00:28:11,350 I suppose, take a break. 532 00:28:11,350 --> 00:28:11,760 [MUSIC PLAYING - "JESU, JOY OF MAN'S DESIRING" BY JOHANN 533 00:28:11,760 --> 00:28:13,010 SEBASTIAN BACH] 534 00:28:13,010 --> 00:28:47,310 535 00:28:47,310 --> 00:28:49,480 PROFESSOR: Well, let's see. 536 00:28:49,480 --> 00:28:52,750 Now you know how to make an iterative procedure, or a 537 00:28:52,750 --> 00:28:53,930 procedure that yields an iterative 538 00:28:53,930 --> 00:28:57,770 process, turn into a machine. 539 00:28:57,770 --> 00:28:59,750 I suppose the next thing we want to do is worry about 540 00:28:59,750 --> 00:29:02,690 things that reveal recursive processes. 541 00:29:02,690 --> 00:29:04,695 So let's play with a simple factorial procedure. 542 00:29:04,695 --> 00:29:10,894 543 00:29:10,894 --> 00:29:24,690 We define factorial of N to be if n is 1, the result is 1, 544 00:29:24,690 --> 00:29:26,830 using 1 right now to decrease the amount of work I have to 545 00:29:26,830 --> 00:29:33,940 do to simulate it, else it's times N factorial N minus 1. 546 00:29:33,940 --> 00:29:42,520 547 00:29:42,520 --> 00:29:47,440 And what's different with this program, as you know, is that 548 00:29:47,440 --> 00:29:51,050 after I've computed factorial of N minus 1 here, I have to 549 00:29:51,050 --> 00:29:52,260 do something to the result. 550 00:29:52,260 --> 00:29:56,000 I have to multiply it by N. 551 00:29:56,000 --> 00:30:00,160 So the only way I can visualize what this machine is 552 00:30:00,160 --> 00:30:02,360 doing, because of the fact-- 553 00:30:02,360 --> 00:30:05,320 think of it this way, that I have a machine out here which 554 00:30:05,320 --> 00:30:07,530 somehow needs a factorial machine in order to compute 555 00:30:07,530 --> 00:30:09,320 its answer. 556 00:30:09,320 --> 00:30:12,550 But this machine, the outer machine, has to exist before 557 00:30:12,550 --> 00:30:16,800 and after the factorial machine, which is inside. 558 00:30:16,800 --> 00:30:20,080 Whereas in the iterative case, the outer machine doesn't need 559 00:30:20,080 --> 00:30:25,170 to exist after the inner machine is running, because 560 00:30:25,170 --> 00:30:26,580 you never need to go back to the outer 561 00:30:26,580 --> 00:30:28,640 machine to do anything. 562 00:30:28,640 --> 00:30:31,200 So here we have a problem where we have a machine which 563 00:30:31,200 --> 00:30:34,090 has the same machine inside of it, an 564 00:30:34,090 --> 00:30:35,340 infinitely large machine. 565 00:30:35,340 --> 00:30:40,390 566 00:30:40,390 --> 00:30:42,310 And it's got other things inside of it, like a 567 00:30:42,310 --> 00:30:47,240 multiplier, which takes some inputs, and there's a minus 1 568 00:30:47,240 --> 00:30:50,690 box, and things like that. 569 00:30:50,690 --> 00:30:54,370 You can imagine that's what it looks like. 570 00:30:54,370 --> 00:30:57,340 But the important thing is that here I have something 571 00:30:57,340 --> 00:31:00,360 that happens before and after, in the outer machine, the 572 00:31:00,360 --> 00:31:02,540 execution of the inner machine. 573 00:31:02,540 --> 00:31:05,570 So this machine has to have a life. 574 00:31:05,570 --> 00:31:13,490 It has to exist on both times sides of this machine. 575 00:31:13,490 --> 00:31:16,770 So somehow, I have to have a place to store the things that 576 00:31:16,770 --> 00:31:20,030 this thing needs to run. 577 00:31:20,030 --> 00:31:24,140 Infinite objects don't exist in the real world. 578 00:31:24,140 --> 00:31:27,020 What we have to do is arrange an illusion that we have an 579 00:31:27,020 --> 00:31:28,540 infinite object, we have an infinite 580 00:31:28,540 --> 00:31:31,830 amount of hardware somewhere. 581 00:31:31,830 --> 00:31:36,280 Now of course, illusion's all that really matters. 582 00:31:36,280 --> 00:31:39,370 If we can arrange that every time you look at some infinite 583 00:31:39,370 --> 00:31:44,800 object, the part of it that you look at is there, then 584 00:31:44,800 --> 00:31:47,390 it's as infinite as you need it to be. 585 00:31:47,390 --> 00:31:49,830 And of course, one of the things we might want to do, 586 00:31:49,830 --> 00:31:53,890 just look at this thing over here, is the organization that 587 00:31:53,890 --> 00:32:01,390 we've had so far involves having a part of the machine, 588 00:32:01,390 --> 00:32:05,140 which is the controller, which sits right over here, which is 589 00:32:05,140 --> 00:32:09,170 perfectly finite and very simple. 590 00:32:09,170 --> 00:32:11,070 We have some datapaths, which consist of 591 00:32:11,070 --> 00:32:13,080 registers and operators. 592 00:32:13,080 --> 00:32:16,190 And what I propose to do here is decompose the machine into 593 00:32:16,190 --> 00:32:19,260 two parts, such that there is a part which is fundamentally 594 00:32:19,260 --> 00:32:22,770 finite, and some part where a certain amount of infinite 595 00:32:22,770 --> 00:32:24,230 stuff can be kept. 596 00:32:24,230 --> 00:32:27,050 On the other hand this is very simple and really isn't 597 00:32:27,050 --> 00:32:29,430 infinite, but it's just very large. 598 00:32:29,430 --> 00:32:31,840 But it's so simple that it could be cheaply reproduced in 599 00:32:31,840 --> 00:32:37,550 such large amounts, we call it memory, that we can make a 600 00:32:37,550 --> 00:32:40,710 structure called a stack out of it which will allow us to, 601 00:32:40,710 --> 00:32:43,280 in fact, simulate the existence of an infinite 602 00:32:43,280 --> 00:32:44,650 machine which is made out of a recursive 603 00:32:44,650 --> 00:32:48,340 nest of many machines. 604 00:32:48,340 --> 00:32:51,760 And the way it's going to work is that we're going to store 605 00:32:51,760 --> 00:32:56,290 in this place called the stack the information required after 606 00:32:56,290 --> 00:33:00,400 the inner machine runs to resume the operation of the 607 00:33:00,400 --> 00:33:01,650 outer machine. 608 00:33:01,650 --> 00:33:03,840 609 00:33:03,840 --> 00:33:06,760 So it will remember the important things about the 610 00:33:06,760 --> 00:33:09,510 life of the outer machine that will be needed for this 611 00:33:09,510 --> 00:33:11,390 computation. 612 00:33:11,390 --> 00:33:15,380 Since, of course, these machines are nested in a 613 00:33:15,380 --> 00:33:20,320 recursive manner, then in fact the stack will only be 614 00:33:20,320 --> 00:33:25,330 accessed in a manner which is the last thing that goes in is 615 00:33:25,330 --> 00:33:26,580 the first thing that comes out. 616 00:33:26,580 --> 00:33:29,330 617 00:33:29,330 --> 00:33:31,510 So we'll only need to access some little part 618 00:33:31,510 --> 00:33:34,930 of this stack memory. 619 00:33:34,930 --> 00:33:36,810 OK, well, let's do it. 620 00:33:36,810 --> 00:33:38,750 I'm going to build you a datapath now, and I'm going to 621 00:33:38,750 --> 00:33:40,370 write the controller. 622 00:33:40,370 --> 00:33:42,090 And then we're going to execute this to 623 00:33:42,090 --> 00:33:43,510 see how you do it. 624 00:33:43,510 --> 00:33:47,900 So the factorial machine isn't so bad. 625 00:33:47,900 --> 00:33:52,660 It's going to have a register called the value, where the 626 00:33:52,660 --> 00:33:59,890 answer is going to be stored, and a registered called N, 627 00:33:59,890 --> 00:34:02,330 which is where the number I'm taking factorial will be 628 00:34:02,330 --> 00:34:04,165 stored, factorial of. 629 00:34:04,165 --> 00:34:09,780 And it will be necessary in some instances to connect VAL 630 00:34:09,780 --> 00:34:11,760 to N. 631 00:34:11,760 --> 00:34:16,389 In fact, one nice case of this is if I just said over here, 632 00:34:16,389 --> 00:34:19,139 N, because that would be right for N equal 1N. 633 00:34:19,139 --> 00:34:21,389 And I could just move the answer over 634 00:34:21,389 --> 00:34:23,909 there if that's important. 635 00:34:23,909 --> 00:34:26,980 I'm not worried about that right now. 636 00:34:26,980 --> 00:34:29,060 And there are things I have to be able to do. 637 00:34:29,060 --> 00:34:32,650 Like I have to be able to, as we see here, multiply N by 638 00:34:32,650 --> 00:34:36,350 something in VAL, because VAL is the result 639 00:34:36,350 --> 00:34:38,290 of computing factorial. 640 00:34:38,290 --> 00:34:41,429 And I have to put the result back into VAL. 641 00:34:41,429 --> 00:34:45,639 So here we can see that the result of computing a 642 00:34:45,639 --> 00:34:48,070 factorial is N times the result 643 00:34:48,070 --> 00:34:50,690 of computing a factorial. 644 00:34:50,690 --> 00:34:52,770 VAL will be the representation of the answer 645 00:34:52,770 --> 00:34:55,199 of the inner factorial. 646 00:34:55,199 --> 00:35:02,525 And so I'm going to have to have a multiplier here, which 647 00:35:02,525 --> 00:35:09,350 is going to sample the value of N and the value of VAL and 648 00:35:09,350 --> 00:35:17,170 put the result back into VAL like that. 649 00:35:17,170 --> 00:35:20,618 I'm also going to have to be able to see if N is 1. 650 00:35:20,618 --> 00:35:22,230 So I need a light bulb. 651 00:35:22,230 --> 00:35:28,200 652 00:35:28,200 --> 00:35:31,270 And I suppose the other thing I'm going to need to have is a 653 00:35:31,270 --> 00:35:38,260 way of decrementing N. So I'm going to have a decrementer, 654 00:35:38,260 --> 00:35:46,620 which takes N and is going to put back the result into N. 655 00:35:46,620 --> 00:35:49,550 That's pretty much what I need in my machine. 656 00:35:49,550 --> 00:35:51,985 Now, there's a little bit else I need. 657 00:35:51,985 --> 00:35:55,620 It's a little bit more complicated, because I'm also 658 00:35:55,620 --> 00:35:58,925 going to need a way to store, to save away, the things that 659 00:35:58,925 --> 00:36:02,600 are going to be needed for resuming the computation of a 660 00:36:02,600 --> 00:36:06,250 factorial after I've done a sub-factorial. 661 00:36:06,250 --> 00:36:07,230 What's that? 662 00:36:07,230 --> 00:36:09,850 One thing I need is N. 663 00:36:09,850 --> 00:36:11,870 So I'm going to build here a thing called a stack. 664 00:36:11,870 --> 00:36:14,700 665 00:36:14,700 --> 00:36:24,130 The stack is a bunch of stuff that I'm going to write in 666 00:36:24,130 --> 00:36:25,380 sequentially. 667 00:36:25,380 --> 00:36:27,410 668 00:36:27,410 --> 00:36:28,916 I don't how long it is. 669 00:36:28,916 --> 00:36:32,890 The longer it is, the better my illusion of infinity. 670 00:36:32,890 --> 00:36:36,036 And I'm going to have to have a way of getting stuff out of 671 00:36:36,036 --> 00:36:39,515 N and into the stack and vice versa. 672 00:36:39,515 --> 00:36:44,740 So I'm going to need a connection like this, which is 673 00:36:44,740 --> 00:36:52,500 two-way, whereby I can save the value of N and then 674 00:36:52,500 --> 00:36:55,820 restore it some other time through that connection. 675 00:36:55,820 --> 00:36:58,100 This is the stack. 676 00:36:58,100 --> 00:37:02,790 I also need a way of remembering where I was in the 677 00:37:02,790 --> 00:37:08,530 computation of factorial in the outer program. 678 00:37:08,530 --> 00:37:11,090 Now in the case of this machine, it 679 00:37:11,090 --> 00:37:14,090 isn't very much a problem. 680 00:37:14,090 --> 00:37:18,020 Factorial always returns, has to go back to the place where 681 00:37:18,020 --> 00:37:21,650 we multiply by N, except for the last time, when it has to 682 00:37:21,650 --> 00:37:23,110 return to whatever needs the factorial or 683 00:37:23,110 --> 00:37:25,660 go to done or stop. 684 00:37:25,660 --> 00:37:28,245 However, in general, I'm going to have to remember where I 685 00:37:28,245 --> 00:37:30,570 have been, because I might have computed factorial from 686 00:37:30,570 --> 00:37:31,770 somewhere else. 687 00:37:31,770 --> 00:37:36,070 I have to go back to that place and continue there. 688 00:37:36,070 --> 00:37:37,990 So I'm going to have to have some way of taking the place 689 00:37:37,990 --> 00:37:41,500 where the marble is in the finite state controller, the 690 00:37:41,500 --> 00:37:45,390 state of the controller, and storing that in 691 00:37:45,390 --> 00:37:47,400 the stack as well. 692 00:37:47,400 --> 00:37:49,840 And I'm going to have to have ways of restoring that back to 693 00:37:49,840 --> 00:37:51,870 the state of the-- the marble. 694 00:37:51,870 --> 00:37:53,570 So I have to have something that moves the marble to the 695 00:37:53,570 --> 00:37:54,310 right place. 696 00:37:54,310 --> 00:37:57,462 Well, we're going to have a place which is the marble now. 697 00:37:57,462 --> 00:38:09,220 And it's called the continue register, called continue, 698 00:38:09,220 --> 00:38:11,480 which is the place to put the marble next 699 00:38:11,480 --> 00:38:14,260 time I go to continue. 700 00:38:14,260 --> 00:38:16,140 That's what that's for. 701 00:38:16,140 --> 00:38:17,990 And so there's got to be some path from that into the 702 00:38:17,990 --> 00:38:19,240 controller. 703 00:38:19,240 --> 00:38:22,910 704 00:38:22,910 --> 00:38:29,074 I also have to have some way of saving that on the stack. 705 00:38:29,074 --> 00:38:32,120 And I have to have some way of setting that up to have 706 00:38:32,120 --> 00:38:36,860 various constants, a certain fixed number of constants. 707 00:38:36,860 --> 00:38:38,840 And that's very easy to arrange. 708 00:38:38,840 --> 00:38:40,180 So let's have some constants here. 709 00:38:40,180 --> 00:38:41,430 We'll call this one after-fact. 710 00:38:41,430 --> 00:38:47,430 711 00:38:47,430 --> 00:38:50,890 And that's a constant which we'll get into the continue 712 00:38:50,890 --> 00:38:54,010 register, and also another one called fact-done. 713 00:38:54,010 --> 00:39:05,210 714 00:39:05,210 --> 00:39:08,130 So this is the machine I want to build. 715 00:39:08,130 --> 00:39:10,810 That's its datapaths, at least. And it mixes a little 716 00:39:10,810 --> 00:39:12,790 with the controller here, because of the fact that I 717 00:39:12,790 --> 00:39:15,220 have to remember where I was and restore 718 00:39:15,220 --> 00:39:17,300 myself to that place. 719 00:39:17,300 --> 00:39:19,310 But let's write the program now which represents the 720 00:39:19,310 --> 00:39:20,390 controller. 721 00:39:20,390 --> 00:39:22,760 I'm not going to write the define machine thing and the 722 00:39:22,760 --> 00:39:24,890 register list, because that's not very interesting. 723 00:39:24,890 --> 00:39:28,020 I'm just going to write down the sequence of instructions 724 00:39:28,020 --> 00:39:30,920 that constitute the controller. 725 00:39:30,920 --> 00:39:41,510 So we have assign, to set up, continue to done. 726 00:39:41,510 --> 00:39:44,476 727 00:39:44,476 --> 00:40:01,150 We have a loop which says branch if equal 1 fetch N, if 728 00:40:01,150 --> 00:40:06,300 N is 1, then go to the base step of the induction, the 729 00:40:06,300 --> 00:40:08,050 simple case. 730 00:40:08,050 --> 00:40:10,740 Otherwise, I have to remember the things that are necessary 731 00:40:10,740 --> 00:40:14,265 to perform a sub-factorial. 732 00:40:14,265 --> 00:40:16,280 I'm going to go over here, and I have to perform a 733 00:40:16,280 --> 00:40:17,570 sub-factorial. 734 00:40:17,570 --> 00:40:21,750 So I have to remember what's needed after I will 735 00:40:21,750 --> 00:40:24,000 be done with that. 736 00:40:24,000 --> 00:40:25,510 See, I'm about to do something terrible. 737 00:40:25,510 --> 00:40:29,430 I'm about to change the value of N. But this guy has to know 738 00:40:29,430 --> 00:40:32,780 the old value of N. But in order to make the 739 00:40:32,780 --> 00:40:35,790 sub-factorial work, I have to change the value of N. So I 740 00:40:35,790 --> 00:40:38,000 have to remember the old value. 741 00:40:38,000 --> 00:40:40,850 And I also have to remember where I've been. 742 00:40:40,850 --> 00:40:42,100 So I save up continue. 743 00:40:42,100 --> 00:40:47,705 744 00:40:47,705 --> 00:40:50,260 And this is an instruction that says, put 745 00:40:50,260 --> 00:40:53,580 something in the stack. 746 00:40:53,580 --> 00:40:56,760 Save the contents of the continuation register, which 747 00:40:56,760 --> 00:40:59,830 in this case is done, because later I'm going to change 748 00:40:59,830 --> 00:41:00,970 that, too, because I need to go back to 749 00:41:00,970 --> 00:41:03,550 after-fact, as well. 750 00:41:03,550 --> 00:41:05,040 We'll see that. 751 00:41:05,040 --> 00:41:10,380 We save N, because I'm going to need that for later. 752 00:41:10,380 --> 00:41:31,422 Assign to N the decrement of fetch N. Assign continue, 753 00:41:31,422 --> 00:41:37,690 we're going to look at this now, to after, we'll call it. 754 00:41:37,690 --> 00:41:39,890 That's a good name for this, a little bit easier and shorter, 755 00:41:39,890 --> 00:41:41,140 and fits in here. 756 00:41:41,140 --> 00:41:52,772 757 00:41:52,772 --> 00:41:55,330 Now look what I'm doing here. 758 00:41:55,330 --> 00:42:00,065 I'm saying, if the answer is 1, I'm done. 759 00:42:00,065 --> 00:42:02,150 I'm going to have to just get the answer. 760 00:42:02,150 --> 00:42:06,160 Otherwise, I'm going to save the continuation, save N, make 761 00:42:06,160 --> 00:42:08,940 N one less than N, remember I'm going to come back to 762 00:42:08,940 --> 00:42:10,530 someplace else, and go back and start 763 00:42:10,530 --> 00:42:11,780 doing another factorial. 764 00:42:11,780 --> 00:42:13,980 765 00:42:13,980 --> 00:42:16,050 However, I've got a different machine [? in me ?] now. 766 00:42:16,050 --> 00:42:18,380 N is 1, and continue is something else. 767 00:42:18,380 --> 00:42:22,160 768 00:42:22,160 --> 00:42:23,590 N is N minus 1. 769 00:42:23,590 --> 00:42:28,660 Now after I'm done with that, I can go there. 770 00:42:28,660 --> 00:42:34,130 I will restore the old value of N, which is the opposite of 771 00:42:34,130 --> 00:42:38,360 this save over here. 772 00:42:38,360 --> 00:42:39,610 I will restore the continuation. 773 00:42:39,610 --> 00:42:49,660 774 00:42:49,660 --> 00:42:54,320 I will then go to here. 775 00:42:54,320 --> 00:43:03,310 I will assign to the VAL register the product 776 00:43:03,310 --> 00:43:08,130 of N and fetch VAL. 777 00:43:08,130 --> 00:43:13,520 778 00:43:13,520 --> 00:43:19,790 VAL fetch product assign. 779 00:43:19,790 --> 00:43:21,440 And then I will be done. 780 00:43:21,440 --> 00:43:26,570 I will have my answer to the sub-factorial in VAL. 781 00:43:26,570 --> 00:43:30,140 At that point, I'm going to return by going to the place 782 00:43:30,140 --> 00:43:33,640 where the continuation is pointing. 783 00:43:33,640 --> 00:43:35,300 That says, go to fetch continue. 784 00:43:35,300 --> 00:43:45,870 785 00:43:45,870 --> 00:43:49,470 And then I have finally a base step, which is 786 00:43:49,470 --> 00:43:50,730 the immediate answer. 787 00:43:50,730 --> 00:44:02,570 Assign to VAL fetch N, and go to fetch continue. 788 00:44:02,570 --> 00:44:12,670 789 00:44:12,670 --> 00:44:13,920 And then I'm done. 790 00:44:13,920 --> 00:44:18,640 791 00:44:18,640 --> 00:44:20,820 Now let's see how this executes on a very simple 792 00:44:20,820 --> 00:44:25,570 case, because then we'll see the use of this stack to do 793 00:44:25,570 --> 00:44:26,890 the job we need. 794 00:44:26,890 --> 00:44:28,820 This is statically what it's doing, but we have look 795 00:44:28,820 --> 00:44:31,340 dynamically at this. 796 00:44:31,340 --> 00:44:32,300 So let's see. 797 00:44:32,300 --> 00:44:36,730 First thing we do is continue gets done. 798 00:44:36,730 --> 00:44:38,300 The way that happened is I pushed this. 799 00:44:38,300 --> 00:44:40,122 Let's call that done the way I have it. 800 00:44:40,122 --> 00:44:46,390 801 00:44:46,390 --> 00:44:47,030 I push that button. 802 00:44:47,030 --> 00:44:48,950 Done goes into there. 803 00:44:48,950 --> 00:44:52,550 Now I also have to set this thing up to 804 00:44:52,550 --> 00:44:53,850 have an initial value. 805 00:44:53,850 --> 00:45:00,192 Let's consider a factorial of three, a simple case. 806 00:45:00,192 --> 00:45:03,010 And we're going to start out with our stack 807 00:45:03,010 --> 00:45:05,900 growing over here. 808 00:45:05,900 --> 00:45:08,520 Stacks have their own little internal state saying where 809 00:45:08,520 --> 00:45:12,770 they are, where the next place I'm going to write is. 810 00:45:12,770 --> 00:45:14,590 So now we say, is N 1? 811 00:45:14,590 --> 00:45:16,110 The answer is no. 812 00:45:16,110 --> 00:45:19,066 So now I'm going to save continue, bang. 813 00:45:19,066 --> 00:45:22,080 Now that done goes in here. 814 00:45:22,080 --> 00:45:26,660 And this moves to here, the next place I'm going to write. 815 00:45:26,660 --> 00:45:29,950 Save N 3. 816 00:45:29,950 --> 00:45:30,750 OK? 817 00:45:30,750 --> 00:45:34,240 Assign to N the decrement of N. That means 818 00:45:34,240 --> 00:45:35,940 I've pushed this button. 819 00:45:35,940 --> 00:45:37,320 This becomes 2. 820 00:45:37,320 --> 00:45:40,400 821 00:45:40,400 --> 00:45:42,580 Assign to continue aft. 822 00:45:42,580 --> 00:45:43,610 So I've pushed that button. 823 00:45:43,610 --> 00:45:44,860 Aft goes in here. 824 00:45:44,860 --> 00:45:49,140 825 00:45:49,140 --> 00:45:54,830 OK, now go to loop, bang, so up to here. 826 00:45:54,830 --> 00:45:56,570 Is N 1? 827 00:45:56,570 --> 00:45:57,780 No. 828 00:45:57,780 --> 00:45:59,490 So I have to save continue. 829 00:45:59,490 --> 00:46:00,600 What's continue? 830 00:46:00,600 --> 00:46:01,530 Continue is aft. 831 00:46:01,530 --> 00:46:02,780 Push this button. 832 00:46:02,780 --> 00:46:04,030 So this moves to here. 833 00:46:04,030 --> 00:46:08,490 834 00:46:08,490 --> 00:46:11,460 I have to save N. N is over here. 835 00:46:11,460 --> 00:46:12,280 I got to 2. 836 00:46:12,280 --> 00:46:13,655 Push that button. 837 00:46:13,655 --> 00:46:16,050 So a 2 gets written there. 838 00:46:16,050 --> 00:46:20,060 And then this thing moves down here. 839 00:46:20,060 --> 00:46:24,214 OK, save N. Assign N to the decrement of N. 840 00:46:24,214 --> 00:46:25,464 This becomes a 1. 841 00:46:25,464 --> 00:46:29,240 842 00:46:29,240 --> 00:46:31,370 Assign continue to aft. 843 00:46:31,370 --> 00:46:34,960 A-F-T gets written there again. 844 00:46:34,960 --> 00:46:36,520 Go to loop. 845 00:46:36,520 --> 00:46:37,930 Is N equal to 1? 846 00:46:37,930 --> 00:46:41,160 Oh, yes, the answer is 1. 847 00:46:41,160 --> 00:46:44,160 OK, go to base step. 848 00:46:44,160 --> 00:46:51,100 Assign to VAL fetch of N. Bang, 1 gets put in there. 849 00:46:51,100 --> 00:46:52,200 Go to fetch continue. 850 00:46:52,200 --> 00:46:53,680 So we look in continue. 851 00:46:53,680 --> 00:46:55,350 Basically, I'm pushing a button over here that goes to 852 00:46:55,350 --> 00:46:57,130 the controller. 853 00:46:57,130 --> 00:46:59,580 The continue becomes aft, and all of a sudden, the program's 854 00:46:59,580 --> 00:47:02,640 running here. 855 00:47:02,640 --> 00:47:06,650 I now have to restore the outer version of factorial. 856 00:47:06,650 --> 00:47:07,550 So we go here. 857 00:47:07,550 --> 00:47:12,410 We say, restore N. So restore N means take the contents 858 00:47:12,410 --> 00:47:13,940 that's here. 859 00:47:13,940 --> 00:47:19,190 Push this button, and it goes into here, 2, and the 860 00:47:19,190 --> 00:47:22,230 pointer moves up. 861 00:47:22,230 --> 00:47:24,810 Restore continue, pretty easy. 862 00:47:24,810 --> 00:47:27,020 Go push this button. 863 00:47:27,020 --> 00:47:31,280 And then aft gets written in here again. 864 00:47:31,280 --> 00:47:32,640 That means this thing moves up. 865 00:47:32,640 --> 00:47:35,190 I've gotten rid of something else on my stack. 866 00:47:35,190 --> 00:47:42,240 867 00:47:42,240 --> 00:47:45,930 Right, then I go to here, which says, assign to VAL the 868 00:47:45,930 --> 00:47:47,850 product of N an VAL. 869 00:47:47,850 --> 00:47:50,970 So I push this button over here, bang. 870 00:47:50,970 --> 00:47:55,920 2 times 1 gives me a 2, get written there. 871 00:47:55,920 --> 00:47:57,540 Go to fetch continue. 872 00:47:57,540 --> 00:47:59,190 Continue is aft. 873 00:47:59,190 --> 00:48:01,290 I go to aft. 874 00:48:01,290 --> 00:48:06,640 Aft says restore N. Do your restore N, means I take the 875 00:48:06,640 --> 00:48:11,030 value over here, which is 3, push this up to here, and move 876 00:48:11,030 --> 00:48:17,715 it into here, N. Now it's pushing that button. 877 00:48:17,715 --> 00:48:20,200 The next thing I do is restore continue. 878 00:48:20,200 --> 00:48:22,830 Continue is now going to become done. 879 00:48:22,830 --> 00:48:27,260 So this moves up here when I push this button. 880 00:48:27,260 --> 00:48:30,470 Done may or may be there anymore, I'm not interested, 881 00:48:30,470 --> 00:48:31,720 but it certainly is here. 882 00:48:31,720 --> 00:48:35,800 883 00:48:35,800 --> 00:48:39,590 Next thing I do is assign to VAL the product of the fetch 884 00:48:39,590 --> 00:48:41,440 of N and the fetch of VAL. 885 00:48:41,440 --> 00:48:44,300 That's pushing this button over here, bang. 886 00:48:44,300 --> 00:48:46,520 2 times 3 is 6. 887 00:48:46,520 --> 00:48:47,870 So I get a 6 over here. 888 00:48:47,870 --> 00:48:52,020 889 00:48:52,020 --> 00:48:54,140 And go to fetch continue, whoops, I go to 890 00:48:54,140 --> 00:48:55,020 done, and I'm done. 891 00:48:55,020 --> 00:48:58,950 And my answer is 6, as you can see in the VAL register. 892 00:48:58,950 --> 00:49:02,380 And in fact, the stack is in the state it 893 00:49:02,380 --> 00:49:03,630 originally was in. 894 00:49:03,630 --> 00:49:07,735 895 00:49:07,735 --> 00:49:09,850 Now there's a bit of discipline in using these 896 00:49:09,850 --> 00:49:13,620 things like stacks that we have to be careful of. 897 00:49:13,620 --> 00:49:16,260 And we'll see that in the next segment. 898 00:49:16,260 --> 00:49:17,340 But first I want to ask if there are any 899 00:49:17,340 --> 00:49:18,590 questions for this. 900 00:49:18,590 --> 00:49:28,560 901 00:49:28,560 --> 00:49:30,170 Are there any questions? 902 00:49:30,170 --> 00:49:30,630 Yes, Ron. 903 00:49:30,630 --> 00:49:32,780 AUDIENCE: What happens when you roll off the end of the 904 00:49:32,780 --> 00:49:33,640 stack with-- 905 00:49:33,640 --> 00:49:35,030 PROFESSOR: What do you mean, roll off of? 906 00:49:35,030 --> 00:49:36,090 AUDIENCE: Well, the largest number-- 907 00:49:36,090 --> 00:49:38,860 a larger starting point of N requires more memory, correct? 908 00:49:38,860 --> 00:49:39,440 PROFESSOR: Oh, yes. 909 00:49:39,440 --> 00:49:41,530 Well, I need to have a long enough stack. 910 00:49:41,530 --> 00:49:43,843 You say, what if I violate my illusion? 911 00:49:43,843 --> 00:49:44,550 AUDIENCE: Yes. 912 00:49:44,550 --> 00:49:48,210 PROFESSOR: Well, then the magic doesn't work. 913 00:49:48,210 --> 00:49:51,640 The truth of the matter is that every machine is finite. 914 00:49:51,640 --> 00:49:56,480 And for a procedure like this, there's a limit to the number 915 00:49:56,480 --> 00:49:59,950 of sub-factorials I could have. 916 00:49:59,950 --> 00:50:02,970 Remember when we were doing the y-operator a while ago, we 917 00:50:02,970 --> 00:50:05,750 pointed out that there was a sequence of exponentiation 918 00:50:05,750 --> 00:50:07,390 procedures, each of which was a little better than the 919 00:50:07,390 --> 00:50:08,350 previous one. 920 00:50:08,350 --> 00:50:10,530 Well, we're now seeing how we implement that 921 00:50:10,530 --> 00:50:13,090 mathematical idea. 922 00:50:13,090 --> 00:50:15,620 The limiting process is only so good as as far as 923 00:50:15,620 --> 00:50:17,990 you take the limit. 924 00:50:17,990 --> 00:50:19,420 If you think about it, what am I using here? 925 00:50:19,420 --> 00:50:26,340 I'm using about two pieces of memory for every recursion of 926 00:50:26,340 --> 00:50:29,100 this process. 927 00:50:29,100 --> 00:50:31,920 If we try to compute factorial of 10,000, that's 928 00:50:31,920 --> 00:50:33,180 not a lot of memory. 929 00:50:33,180 --> 00:50:36,080 On the other hand, it's an awful big number. 930 00:50:36,080 --> 00:50:39,180 So the question is, is that a valuable thing in this case. 931 00:50:39,180 --> 00:50:42,480 But it really turns out not to be a terrible limit, because 932 00:50:42,480 --> 00:50:45,085 memory is el cheapo, and people are pretty expensive. 933 00:50:45,085 --> 00:50:48,130 934 00:50:48,130 --> 00:50:51,050 OK, thank you, let's take a break. 935 00:50:51,050 --> 00:50:51,410 [MUSIC PLAYING - "JESU, JOY OF MAN'S DESIRING" BY JOHANN 936 00:50:51,410 --> 00:50:52,660 SEBASTIAN BACH] 937 00:50:52,660 --> 00:51:55,176 938 00:51:55,176 --> 00:51:58,351 PROFESSOR: Well, let's see. 939 00:51:58,351 --> 00:52:02,770 What I've shown you now is how to do a simple iterative 940 00:52:02,770 --> 00:52:05,640 process and a simple recursive process. 941 00:52:05,640 --> 00:52:09,760 I just want to summarize the design of simple machines for 942 00:52:09,760 --> 00:52:12,470 specific applications by showing you a little bit more 943 00:52:12,470 --> 00:52:15,870 complicated design, that of a thing that does doubly 944 00:52:15,870 --> 00:52:19,015 recursive Fibonacci, because it will indicate to us, and 945 00:52:19,015 --> 00:52:22,870 we'll understand, a bit about the conventions required for 946 00:52:22,870 --> 00:52:26,400 making stacks operate correctly. 947 00:52:26,400 --> 00:52:27,110 So let's see. 948 00:52:27,110 --> 00:52:28,830 I'm just going to write down, first of all, the program I'm 949 00:52:28,830 --> 00:52:30,080 going to translate. 950 00:52:30,080 --> 00:52:34,150 951 00:52:34,150 --> 00:52:41,190 I need a Fibonacci procedure, it's very simple, which says, 952 00:52:41,190 --> 00:52:50,390 if N is less than 2, the result is N, otherwise it's 953 00:52:50,390 --> 00:52:59,965 the sum of Fib of N minus 1 and Fib of N minus 2. 954 00:52:59,965 --> 00:53:07,240 955 00:53:07,240 --> 00:53:09,290 That's the plan I have here. 956 00:53:09,290 --> 00:53:11,180 And we're just going to write down the 957 00:53:11,180 --> 00:53:13,070 controller for such a machine. 958 00:53:13,070 --> 00:53:16,240 We're going to assume that there are registers, N, which 959 00:53:16,240 --> 00:53:20,510 holds the number we're taking Fibonacci of, VAL, which is 960 00:53:20,510 --> 00:53:23,630 where the answer is going to get put, and continue, which 961 00:53:23,630 --> 00:53:26,810 is the thing that's linked to the controller, like before. 962 00:53:26,810 --> 00:53:31,740 But I'm not going to draw another physical datapath, 963 00:53:31,740 --> 00:53:32,995 because it's pretty much the same as the 964 00:53:32,995 --> 00:53:34,360 last one you've seen. 965 00:53:34,360 --> 00:53:37,070 And of course, one of the most amazing things about 966 00:53:37,070 --> 00:53:40,700 computation is that after a while, you build up a little 967 00:53:40,700 --> 00:53:42,126 more features and a few more features, and all of the 968 00:53:42,126 --> 00:53:44,860 sudden, you've got everything you need. 969 00:53:44,860 --> 00:53:48,290 So it's remarkable that it just gets there so fast. I 970 00:53:48,290 --> 00:53:51,810 don't need much more to make a universal computer. 971 00:53:51,810 --> 00:53:53,630 But in any case, let's look at the controller for the 972 00:53:53,630 --> 00:53:55,060 Fibonacci thing. 973 00:53:55,060 --> 00:54:01,680 First thing I want to do is start the thing up by assign 974 00:54:01,680 --> 00:54:10,230 to continue a place called done, called Fib-done here. 975 00:54:10,230 --> 00:54:13,709 976 00:54:13,709 --> 00:54:16,630 So that means that somewhere over here, I'm going to have a 977 00:54:16,630 --> 00:54:21,610 label, Fib-done, which is the place where I go when I want 978 00:54:21,610 --> 00:54:24,120 the machine to stop. 979 00:54:24,120 --> 00:54:25,395 That's what that is. 980 00:54:25,395 --> 00:54:26,795 And I'm going to make up a loop. 981 00:54:26,795 --> 00:54:31,110 982 00:54:31,110 --> 00:54:33,490 It's a place I'm going to go to in order to start up 983 00:54:33,490 --> 00:54:35,470 computing a Fib. 984 00:54:35,470 --> 00:54:38,210 Whatever is in N at this point, Fibonacci will be 985 00:54:38,210 --> 00:54:41,320 computed of, and we will return to the place specified 986 00:54:41,320 --> 00:54:42,570 by continue. 987 00:54:42,570 --> 00:54:46,070 988 00:54:46,070 --> 00:54:48,640 So what you're going to see here at this place, what I 989 00:54:48,640 --> 00:54:52,650 want here is the contract that says, I'm going to write this 990 00:54:52,650 --> 00:55:00,230 with a comment syntax, the contract is N contains arg, 991 00:55:00,230 --> 00:55:02,100 the argument. 992 00:55:02,100 --> 00:55:09,325 Continue is the recipient. 993 00:55:09,325 --> 00:55:12,812 994 00:55:12,812 --> 00:55:14,290 And that's where it is. 995 00:55:14,290 --> 00:55:17,370 996 00:55:17,370 --> 00:55:20,430 At this point, if I ever go to this place, I'm expecting this 997 00:55:20,430 --> 00:55:24,820 to be true, the argument for computing the Fibonacci. 998 00:55:24,820 --> 00:55:26,450 Now the next thing I want to do is to branch. 999 00:55:26,450 --> 00:55:30,220 1000 00:55:30,220 --> 00:55:32,070 And if N is less than 2-- 1001 00:55:32,070 --> 00:55:34,930 1002 00:55:34,930 --> 00:55:38,730 by the way, I'm using what looks like Lisp syntax. 1003 00:55:38,730 --> 00:55:41,310 This is not Lisp. 1004 00:55:41,310 --> 00:55:42,750 This does not run. 1005 00:55:42,750 --> 00:55:46,120 What I'm writing here does not run as a simple Lisp program. 1006 00:55:46,120 --> 00:55:49,710 This is a representation of another language. 1007 00:55:49,710 --> 00:55:52,030 The reason I'm using the syntax of parentheses and so 1008 00:55:52,030 --> 00:55:56,100 on is because I tend to use a Lisp system to write an 1009 00:55:56,100 --> 00:55:59,380 interpreter for this which allows me to simulate the 1010 00:55:59,380 --> 00:56:03,380 machine I'm trying to build. 1011 00:56:03,380 --> 00:56:05,170 I don't want to confuse this to think that 1012 00:56:05,170 --> 00:56:06,940 this is Lisp code. 1013 00:56:06,940 --> 00:56:09,510 It's just I'm using a lot of the pieces of Lisp. 1014 00:56:09,510 --> 00:56:12,880 I'm embedding a language in Lisp, using Lisp as pieces to 1015 00:56:12,880 --> 00:56:16,620 make my process of making my simulator easy. 1016 00:56:16,620 --> 00:56:18,900 So I'm inheriting from Lisp all of its properties. 1017 00:56:18,900 --> 00:56:22,700 Fetch of N 2, I want to go to a place 1018 00:56:22,700 --> 00:56:25,985 called immediate answer. 1019 00:56:25,985 --> 00:56:27,235 It's the base step. 1020 00:56:27,235 --> 00:56:33,150 1021 00:56:33,150 --> 00:56:37,750 Now, that's somewhere over here, just above done. 1022 00:56:37,750 --> 00:56:39,330 And we'll see it later. 1023 00:56:39,330 --> 00:56:41,480 Now, in the general case, which is the part I'm going to 1024 00:56:41,480 --> 00:56:44,860 write down now, let's just do it. 1025 00:56:44,860 --> 00:56:46,370 Well, first of all, I'm going to have to 1026 00:56:46,370 --> 00:56:49,420 call Fibonacci twice. 1027 00:56:49,420 --> 00:56:51,300 In each case-- 1028 00:56:51,300 --> 00:56:53,640 well, in one case at least, I'm going to have to know what 1029 00:56:53,640 --> 00:56:56,310 to do to come back and do the next one. 1030 00:56:56,310 --> 00:57:01,600 I have to remember, have I done the first Fib, or have I 1031 00:57:01,600 --> 00:57:04,500 done the second one? 1032 00:57:04,500 --> 00:57:06,630 Do I have to come back to the place where I do the second 1033 00:57:06,630 --> 00:57:08,240 Fib, or do I have to come back to the place 1034 00:57:08,240 --> 00:57:09,490 where I do the add? 1035 00:57:09,490 --> 00:57:12,140 1036 00:57:12,140 --> 00:57:14,810 In the first case, over the first Fibonacci, I'm going to 1037 00:57:14,810 --> 00:57:16,980 need the value of N for computing for the second one. 1038 00:57:16,980 --> 00:57:20,010 1039 00:57:20,010 --> 00:57:22,996 So I have to store some of these things up. 1040 00:57:22,996 --> 00:57:25,820 So first I'm going to save continue. 1041 00:57:25,820 --> 00:57:27,265 That's who needs the answer. 1042 00:57:27,265 --> 00:57:31,320 1043 00:57:31,320 --> 00:57:33,560 And the reason I'm doing that is because I'm about to assign 1044 00:57:33,560 --> 00:57:42,870 continue to the place which is the place I 1045 00:57:42,870 --> 00:57:44,130 want to go to after. 1046 00:57:44,130 --> 00:57:46,870 1047 00:57:46,870 --> 00:57:52,510 Let's call it Fib-N-minus-1, big long name, 1048 00:57:52,510 --> 00:57:53,760 classic Lisp name. 1049 00:57:53,760 --> 00:57:57,700 1050 00:57:57,700 --> 00:58:00,900 Because I'm going to compute the first Fib of N minus 1, 1051 00:58:00,900 --> 00:58:02,440 and then after that, I want to come back and 1052 00:58:02,440 --> 00:58:03,960 do something else. 1053 00:58:03,960 --> 00:58:08,050 That's the place I want to go to after I've done the first 1054 00:58:08,050 --> 00:58:11,106 Fibonacci calculation. 1055 00:58:11,106 --> 00:58:15,030 And I want to do a save of N, because I'm going to need it 1056 00:58:15,030 --> 00:58:19,130 later, after that. 1057 00:58:19,130 --> 00:58:21,480 Now I'm going to, at this point, get ready to do the 1058 00:58:21,480 --> 00:58:23,230 Fibonacci of N minus 1. 1059 00:58:23,230 --> 00:58:33,950 So assign to N the difference of the fetch of N and 1. 1060 00:58:33,950 --> 00:58:38,110 1061 00:58:38,110 --> 00:58:40,270 Now I'm ready to go back to doing the Fib loop. 1062 00:58:40,270 --> 00:58:47,630 1063 00:58:47,630 --> 00:58:50,195 Have I satisfied my contract? 1064 00:58:50,195 --> 00:58:51,770 And the answer is yes. 1065 00:58:51,770 --> 00:58:57,210 N contains N minus 1, which is what I need. 1066 00:58:57,210 --> 00:59:01,370 Continue contains a place I want to go to when I'm done 1067 00:59:01,370 --> 00:59:04,100 with calculating N minus 1. 1068 00:59:04,100 --> 00:59:05,440 So I've satisfied the contract. 1069 00:59:05,440 --> 00:59:11,580 And therefore, I can write down here a label, 1070 00:59:11,580 --> 00:59:12,830 after-Fib-N-minus-1. 1071 00:59:12,830 --> 00:59:20,490 1072 00:59:20,490 --> 00:59:22,690 Now what am I going to do here? 1073 00:59:22,690 --> 00:59:25,660 Here's a place where I now have to get ready to do 1074 00:59:25,660 --> 00:59:26,910 Fib of N minus 2. 1075 00:59:26,910 --> 00:59:29,270 1076 00:59:29,270 --> 00:59:31,780 But in order to do a Fib of N minus 2, look, I don't know. 1077 00:59:31,780 --> 00:59:33,810 I've clobbered my N over here. 1078 00:59:33,810 --> 00:59:36,610 And presumably my N is counted down all the way to 1 or 0 or 1079 00:59:36,610 --> 00:59:39,780 something at this point. 1080 00:59:39,780 --> 00:59:43,030 So I don't know what the value of N in the N register is. 1081 00:59:43,030 --> 00:59:45,640 I want the value of N that was on the stack that I saved over 1082 00:59:45,640 --> 00:59:49,520 here so that could restore it over here. 1083 00:59:49,520 --> 00:59:53,880 I saved up the value of N, which is this value of N at 1084 00:59:53,880 --> 00:59:56,340 this point, so that I could restore it after computing Fib 1085 00:59:56,340 --> 00:59:59,360 of N minus 1, so that I could count that down to N minus 2 1086 00:59:59,360 --> 01:00:01,810 and then compute Fib of N minus 2. 1087 01:00:01,810 --> 01:00:03,060 So let's restore that. 1088 01:00:03,060 --> 01:00:08,830 1089 01:00:08,830 --> 01:00:11,130 Restore of N. 1090 01:00:11,130 --> 01:00:16,200 Now I'm about to do something which is superstitious, and we 1091 01:00:16,200 --> 01:00:18,520 will remove it shortly. 1092 01:00:18,520 --> 01:00:22,390 I am about to finish the sequence of doing the 1093 01:00:22,390 --> 01:00:24,800 subroutine call, if you will. 1094 01:00:24,800 --> 01:00:28,510 I'm going to say, well, I also saved up the continuation, 1095 01:00:28,510 --> 01:00:31,600 since I'm going to restore it now. 1096 01:00:31,600 --> 01:00:32,970 But actually, I don't have to, because I'm not 1097 01:00:32,970 --> 01:00:34,610 going to need it. 1098 01:00:34,610 --> 01:00:36,260 We'll fix that in a second. 1099 01:00:36,260 --> 01:00:46,590 So we'll do a restore of continue, which is what I 1100 01:00:46,590 --> 01:00:48,020 would in general need to do. 1101 01:00:48,020 --> 01:00:50,240 And we're just going to see what you would call in the 1102 01:00:50,240 --> 01:00:52,540 compiler world a peephole optimization, which says, 1103 01:00:52,540 --> 01:00:55,420 whoops, you didn't have to do that. 1104 01:00:55,420 --> 01:00:59,720 OK, so the next thing I see here is that I have to get 1105 01:00:59,720 --> 01:01:02,770 ready now to do Fibonacci of N minus 2. 1106 01:01:02,770 --> 01:01:05,050 But I don't have to save N anymore. 1107 01:01:05,050 --> 01:01:07,140 The reason why I don't have to save N anymore is because I 1108 01:01:07,140 --> 01:01:09,690 don't need N after I've done Fib of N minus 2, because the 1109 01:01:09,690 --> 01:01:13,540 next thing I do is add. 1110 01:01:13,540 --> 01:01:16,500 So I'm just going to set up my N that way. 1111 01:01:16,500 --> 01:01:28,990 Assign N minus difference of fetch N and 2. 1112 01:01:28,990 --> 01:01:31,850 1113 01:01:31,850 --> 01:01:35,440 Now I have to finish the setup for calling 1114 01:01:35,440 --> 01:01:36,950 Fibonacci of N minus 2. 1115 01:01:36,950 --> 01:01:48,330 Well, I have to save up continue and assign continue, 1116 01:01:48,330 --> 01:02:03,050 continue, to the place which is after Fib N 2, that place 1117 01:02:03,050 --> 01:02:05,320 over here somewhere. 1118 01:02:05,320 --> 01:02:08,650 However, I've got to be very careful. 1119 01:02:08,650 --> 01:02:12,470 The old value, the value of Fib of N minus 1, I'm going to 1120 01:02:12,470 --> 01:02:15,300 need later. 1121 01:02:15,300 --> 01:02:18,480 The value of Fibonacci of N minus 1, I'm going to need. 1122 01:02:18,480 --> 01:02:21,880 And I can't clobber it, because I'm going to have to 1123 01:02:21,880 --> 01:02:24,150 add it to the value of Fib of N minus 2. 1124 01:02:24,150 --> 01:02:27,720 That's in the value register, so I'm going to save it. 1125 01:02:27,720 --> 01:02:33,780 So I have to save this right now, save up VAL. 1126 01:02:33,780 --> 01:02:39,547 And now I can go off to my subroutine, go to Fib loop. 1127 01:02:39,547 --> 01:02:44,220 1128 01:02:44,220 --> 01:02:49,460 Now before I go any further and finish this program, I 1129 01:02:49,460 --> 01:02:52,340 just want to look at this segment so far and see, oh 1130 01:02:52,340 --> 01:02:55,520 yes, there's a sequence of instructions here, if you 1131 01:02:55,520 --> 01:03:01,580 will, that I can do something about. 1132 01:03:01,580 --> 01:03:06,010 Here I have a restore of continue, a save of continue, 1133 01:03:06,010 --> 01:03:09,200 and then an assign of continue, with no other 1134 01:03:09,200 --> 01:03:10,640 references to continue in between. 1135 01:03:10,640 --> 01:03:13,840 1136 01:03:13,840 --> 01:03:15,520 The restore followed by the save 1137 01:03:15,520 --> 01:03:16,770 leaves the stack unchanged. 1138 01:03:16,770 --> 01:03:19,090 1139 01:03:19,090 --> 01:03:21,250 The only difference is that I set the continue register to a 1140 01:03:21,250 --> 01:03:24,330 value, which is the value that was on the stack. 1141 01:03:24,330 --> 01:03:27,360 Since I now clobber that value, as in it was never 1142 01:03:27,360 --> 01:03:31,710 referenced, these instructions are unnecessary. 1143 01:03:31,710 --> 01:03:35,390 So we will remove these. 1144 01:03:35,390 --> 01:03:38,550 1145 01:03:38,550 --> 01:03:40,210 But I couldn't have seen that unless I had 1146 01:03:40,210 --> 01:03:41,460 written them down. 1147 01:03:41,460 --> 01:03:43,780 1148 01:03:43,780 --> 01:03:45,590 Was that really true? 1149 01:03:45,590 --> 01:03:48,610 Well, I don't know. 1150 01:03:48,610 --> 01:03:51,560 OK, so we've now gone off to compute 1151 01:03:51,560 --> 01:03:53,660 Fibonacci of N minus 2. 1152 01:03:53,660 --> 01:04:05,070 So after that, what are we going to do? 1153 01:04:05,070 --> 01:04:07,010 Well, I suppose the first thing we have to do-- 1154 01:04:07,010 --> 01:04:07,960 we've got two things. 1155 01:04:07,960 --> 01:04:09,460 We've got a thing in the value register 1156 01:04:09,460 --> 01:04:10,920 which is now valuable. 1157 01:04:10,920 --> 01:04:12,610 We also have a thing on the stack that can be restored 1158 01:04:12,610 --> 01:04:14,815 into the value register. 1159 01:04:14,815 --> 01:04:17,630 And what I have to be careful with now is I want to shuffle 1160 01:04:17,630 --> 01:04:19,470 this right so I can do the multiply. 1161 01:04:19,470 --> 01:04:21,600 Now there are various conventions I might use, but 1162 01:04:21,600 --> 01:04:24,510 I'm going to be very picky and say, I'm only going to restore 1163 01:04:24,510 --> 01:04:26,740 into a register I've saved from. 1164 01:04:26,740 --> 01:04:30,020 If that's the case, I have to do a shuffle here. 1165 01:04:30,020 --> 01:04:32,950 It's the same problem with how many hands I have. So I'm 1166 01:04:32,950 --> 01:04:37,800 going to assign to N, because I'm not going to need N 1167 01:04:37,800 --> 01:04:45,440 anymore, N is useless, the current value of VAL, which 1168 01:04:45,440 --> 01:04:47,340 was the value of Fib of N minus 2. 1169 01:04:47,340 --> 01:04:52,950 1170 01:04:52,950 --> 01:04:56,180 And I'm going to restore the value register now. 1171 01:04:56,180 --> 01:05:01,850 1172 01:05:01,850 --> 01:05:06,290 This restore matches this save. And if you're very 1173 01:05:06,290 --> 01:05:09,820 careful and examine very carefully what goes on, 1174 01:05:09,820 --> 01:05:13,840 restores and saves are always matched. 1175 01:05:13,840 --> 01:05:15,660 Now there's an outstanding save, of course, that we have 1176 01:05:15,660 --> 01:05:19,000 to get rid of soon. 1177 01:05:19,000 --> 01:05:20,590 And so I restored the value register. 1178 01:05:20,590 --> 01:05:34,850 Now I restore the continue one, which matches this one, 1179 01:05:34,850 --> 01:05:41,300 dot, dot, dot, dot, dot, dot, dot, down to here, restoring 1180 01:05:41,300 --> 01:05:42,860 that continuation. 1181 01:05:42,860 --> 01:05:46,600 That continuation is a continuation of Fib of N, 1182 01:05:46,600 --> 01:05:48,330 which is the problem I was trying to solve, a major 1183 01:05:48,330 --> 01:05:49,665 problem I'm trying to solve. 1184 01:05:49,665 --> 01:05:52,670 So that's the guy I have to go back to who wants Fib of N. I 1185 01:05:52,670 --> 01:05:55,470 saved them all the way up here when I realized N was 1186 01:05:55,470 --> 01:05:57,360 not less than 2. 1187 01:05:57,360 --> 01:06:00,840 And so I had to do a complicated operation. 1188 01:06:00,840 --> 01:06:03,240 Now I've got everything I need to do it. 1189 01:06:03,240 --> 01:06:17,470 So I'm going to restore that, assign to VAL the sum of fetch 1190 01:06:17,470 --> 01:06:28,335 VAL and fetch of N, and go to continue. 1191 01:06:28,335 --> 01:06:38,260 1192 01:06:38,260 --> 01:06:45,750 So now I've returned from computing Fibonacci of N, the 1193 01:06:45,750 --> 01:06:47,110 general case. 1194 01:06:47,110 --> 01:06:51,230 Now what's left is we have to fix up a few details, like 1195 01:06:51,230 --> 01:07:03,750 there's the base case of this induction, immediate answer, 1196 01:07:03,750 --> 01:07:13,710 which is nothing more than assign to VAL fetch of N, 1197 01:07:13,710 --> 01:07:17,120 because N was less than 2, and therefore, the answer is N in 1198 01:07:17,120 --> 01:07:26,095 our original program, and return continue-- 1199 01:07:26,095 --> 01:07:31,460 1200 01:07:31,460 --> 01:07:34,800 bobble, bobble almost-- 1201 01:07:34,800 --> 01:07:36,130 and finally Fib done. 1202 01:07:36,130 --> 01:07:43,460 1203 01:07:43,460 --> 01:07:45,640 So that's a fairly complicated program. 1204 01:07:45,640 --> 01:07:47,950 And the reason I wanted you see to that is because I want 1205 01:07:47,950 --> 01:07:51,740 you to see the particular flavors of stack discipline 1206 01:07:51,740 --> 01:07:52,965 that I was obeying. 1207 01:07:52,965 --> 01:07:57,240 It was first of all, I don't want to take anything that I'm 1208 01:07:57,240 --> 01:08:00,395 not going to need later. 1209 01:08:00,395 --> 01:08:01,850 I was being very careful. 1210 01:08:01,850 --> 01:08:03,940 And it's very important. 1211 01:08:03,940 --> 01:08:07,095 And there are all sorts of other disciplines people make 1212 01:08:07,095 --> 01:08:10,520 with frames and things like that of some sort, where you 1213 01:08:10,520 --> 01:08:12,280 save all sorts of junk you're not going to need later and 1214 01:08:12,280 --> 01:08:15,830 restore it because, in some sense, it's easier to do that. 1215 01:08:15,830 --> 01:08:19,109 That's going to lead to various disasters, which we'll 1216 01:08:19,109 --> 01:08:21,740 see a little later. 1217 01:08:21,740 --> 01:08:23,560 It's crucial to say exactly what you're 1218 01:08:23,560 --> 01:08:24,810 going to need later. 1219 01:08:24,810 --> 01:08:26,899 1220 01:08:26,899 --> 01:08:29,859 It's an important idea. 1221 01:08:29,859 --> 01:08:34,020 And the responsibility of that is whoever saves something is 1222 01:08:34,020 --> 01:08:36,930 the guy who restores it, because he needs it. 1223 01:08:36,930 --> 01:08:40,130 And in such discipline, you can see what things are 1224 01:08:40,130 --> 01:08:46,940 unnecessary, operations that are unimportant. 1225 01:08:46,940 --> 01:08:49,950 Now, one other thing I want to tell you about that's very 1226 01:08:49,950 --> 01:08:54,120 simple is that, of course, the picture you see is not the 1227 01:08:54,120 --> 01:08:55,350 whole picture. 1228 01:08:55,350 --> 01:08:58,430 Supposing I had systems that had things like other 1229 01:08:58,430 --> 01:09:06,080 operations, CAR, CDR, cons, building a vector and 1230 01:09:06,080 --> 01:09:10,000 referencing the nth element of it, or things like that. 1231 01:09:10,000 --> 01:09:14,229 Well, at this level of detail, whatever it is, we can 1232 01:09:14,229 --> 01:09:15,520 conceptualize those as primitive 1233 01:09:15,520 --> 01:09:18,299 operations in the datapath. 1234 01:09:18,299 --> 01:09:21,020 In other words, we could say that some machine that, for 1235 01:09:21,020 --> 01:09:25,460 example, has the append machine, which has to do cons 1236 01:09:25,460 --> 01:09:29,870 of the CAR of x with the append of the CDR of x and y, 1237 01:09:29,870 --> 01:09:31,149 well, gee, that's exactly the same as 1238 01:09:31,149 --> 01:09:33,630 the factorial structure. 1239 01:09:33,630 --> 01:09:36,133 Well, it's got about the same structure. 1240 01:09:36,133 --> 01:09:37,270 And what do we have? 1241 01:09:37,270 --> 01:09:41,590 We have some sort of things in it which may be registers, x 1242 01:09:41,590 --> 01:09:45,490 and y, and then x has to somehow move to y sometimes, x 1243 01:09:45,490 --> 01:09:46,939 has to get the value of y. 1244 01:09:46,939 --> 01:09:48,000 And then we may have to be able to do 1245 01:09:48,000 --> 01:09:51,700 something which is a cons. 1246 01:09:51,700 --> 01:09:57,760 I don't remember if I need to like this is in this system, 1247 01:09:57,760 --> 01:10:01,420 but cons is sort of like subtract or add or something. 1248 01:10:01,420 --> 01:10:03,800 It combines two things, producing a thing which is the 1249 01:10:03,800 --> 01:10:07,600 cons, which we may then think goes into there. 1250 01:10:07,600 --> 01:10:14,920 And then maybe a thing called the CAR, which will produce-- 1251 01:10:14,920 --> 01:10:16,920 I can get the CAR or something. 1252 01:10:16,920 --> 01:10:20,150 And maybe I can get the CDR of something, and so on. 1253 01:10:20,150 --> 01:10:22,730 But we shouldn't be too afraid of saying things this way, 1254 01:10:22,730 --> 01:10:27,330 because the worst that could happen is if we open up cons, 1255 01:10:27,330 --> 01:10:31,770 what we're going to find is some machine. 1256 01:10:31,770 --> 01:10:33,750 And cons may in fact overlap with CAR and CDR, and it 1257 01:10:33,750 --> 01:10:38,660 always does, in the same way that plus and minus overlap, 1258 01:10:38,660 --> 01:10:41,210 and really the same business. 1259 01:10:41,210 --> 01:10:42,950 Cons, CAR, and CDR are going to overlap, and we're going to 1260 01:10:42,950 --> 01:10:48,630 find a little controller, a little datapath, which may 1261 01:10:48,630 --> 01:10:53,300 have some registers in it, some stuff like that. 1262 01:10:53,300 --> 01:10:56,650 And maybe inside it, there may also be an infinite part, a 1263 01:10:56,650 --> 01:10:59,440 part that's semi-infinite or something, which is a lot of 1264 01:10:59,440 --> 01:11:02,030 very uniform stuff, which we'll call memory. 1265 01:11:02,030 --> 01:11:06,570 1266 01:11:06,570 --> 01:11:09,330 And I wouldn't be so horrified if that were the way it works. 1267 01:11:09,330 --> 01:11:13,320 In fact, it does, and we'll talk about that later. 1268 01:11:13,320 --> 01:11:14,570 So are there any questions? 1269 01:11:14,570 --> 01:11:24,340 1270 01:11:24,340 --> 01:11:25,665 Gee, what an unquestioning audience. 1271 01:11:25,665 --> 01:11:28,670 1272 01:11:28,670 --> 01:11:30,330 Suppose I tell you a horrible pile of lies. 1273 01:11:30,330 --> 01:11:39,690 1274 01:11:39,690 --> 01:11:41,990 OK. 1275 01:11:41,990 --> 01:11:42,520 Well, thank you. 1276 01:11:42,520 --> 01:11:44,230 Let's take our break. 1277 01:11:44,230 --> 01:11:47,230 [MUSIC PLAYING - "JESU, JOY OF MAN'S DESIRING" BY JOHANN 1278 01:11:47,230 --> 01:11:48,780 SEBASTIAN BACH] 1279 01:11:48,780 --> 01:11:56,124 ================================================ FILE: SrtEN/lec9b_512kb.mp4.srt ================================================ 1 00:00:15,840 --> 00:00:20,260 PROFESSOR: Well, I hope you appreciate that we have 2 00:00:20,260 --> 00:00:24,562 inducted you into some real magic, 3 00:00:24,562 --> 00:00:29,500 the magic of building languages, really building new languages. 4 00:00:29,500 --> 00:00:31,275 What have we looked at? We've looked at 5 00:00:31,275 --> 00:00:38,925 an Escher picture language: 6 00:00:38,925 --> 00:00:42,141 this language invented by Peter Henderson. 7 00:00:42,141 --> 00:00:47,600 We looked at digital logic language. 8 00:00:53,000 --> 00:00:56,944 Let's see.We've looked at the query language. 9 00:00:59,700 --> 00:01:04,700 And the thing you should realize is, even though these were toy examples, 10 00:01:04,700 --> 00:01:08,250 they really are the kernels of really useful things. 11 00:01:08,250 --> 00:01:12,375 So, for instance, the Escher picture language was taken by 12 00:01:12,375 --> 00:01:14,450 Henry Wu, who's a student at MIT, 13 00:01:14,450 --> 00:01:20,350 and developed into a real language for laying out PC boards, 14 00:01:20,350 --> 00:01:23,244 based just on extending those structures. 15 00:01:23,244 --> 00:01:26,350 And the digital logic language, Jerry mentioned when he showed it to you, 16 00:01:26,350 --> 00:01:30,850 was really extended to be used as the basis for a simulator 17 00:01:30,850 --> 00:01:33,460 that was used to design a real computer. 18 00:01:33,460 --> 00:01:37,510 And the query language, of course, is kind of the germ of prologue. 19 00:01:37,510 --> 00:01:39,425 So we built all of these languages, 20 00:01:39,425 --> 00:01:42,300 they're all based on LISP. 21 00:01:43,630 --> 00:01:45,275 A lot of people ask 22 00:01:45,275 --> 00:01:48,606 what particular problems is LISP good for solving for? 23 00:01:48,606 --> 00:01:53,450 The answer is LISP is not good for solving any particular problems. 24 00:01:53,450 --> 00:01:56,213 What LISP is good for is constructing within it 25 00:01:56,213 --> 00:01:59,175 the right language to solve the problems you want to solve, 26 00:01:59,175 --> 00:02:01,470 and that's how you should think about it. 27 00:02:01,470 --> 00:02:04,326 So all of these languages were based on LISP. 28 00:02:04,326 --> 00:02:06,925 Now, what's LISP based on? 29 00:02:06,925 --> 00:02:09,400 Where's that come from? Well, we looked at that too. 30 00:02:09,400 --> 00:02:22,935 We looked at the meta-circular evaluator 31 00:02:22,935 --> 00:02:25,810 and said well, LISP is based on LISP. 32 00:02:25,810 --> 00:02:28,275 And when we start looking at that, 33 00:02:28,275 --> 00:02:29,950 we've got to do some real magic, right? 34 00:02:29,950 --> 00:02:31,660 So what does that mean, right? 35 00:02:31,660 --> 00:02:37,350 Why operators, and fixed points, and the idea that 36 00:02:37,350 --> 00:02:41,000 what this means is that LISP is somehow the fixed-point equation 37 00:02:41,000 --> 00:02:47,400 for this funny set of things which are defined in terms of themselves. 38 00:02:47,400 --> 00:02:49,070 Now, it's real magic. 39 00:02:49,070 --> 00:02:52,625 Well, today, for a final piece of magic, 40 00:02:52,625 --> 00:03:01,852 we're going to make all the magic go away. 41 00:03:06,430 --> 00:03:09,770 We already know how to do that. 42 00:03:09,770 --> 00:03:13,135 The idea is, we're going to take the register machine architecture 43 00:03:13,135 --> 00:03:15,500 and show how to implement LISP on terms of that. 44 00:03:15,500 --> 00:03:21,325 And, remember, the idea of the register machine is that 45 00:03:21,325 --> 00:03:24,800 there's a fixed and finite part of the machine. 46 00:03:24,800 --> 00:03:27,050 There's a finite-state controller, which does some 47 00:03:27,050 --> 00:03:30,510 particular thing with a particular amount of hardware. 48 00:03:30,510 --> 00:03:33,550 There are particular data paths, the operation the machine does 49 00:03:33,550 --> 00:03:37,725 And then, in order to implement recursion and sustain the illusion of infinity, 50 00:03:37,725 --> 00:03:42,060 there's some large amount of memory, which is the stack. 51 00:03:42,060 --> 00:03:47,025 So, if we implement LISP in terms of a register machine, 52 00:03:47,025 --> 00:03:49,850 then everything ought to become, at this point,completely concrete. 53 00:03:49,850 --> 00:03:51,650 All the magic should go away. 54 00:03:51,650 --> 00:03:55,140 And, by the end of this talk, I want you get the feeling 55 00:03:55,140 --> 00:03:59,675 that, as opposed to this very mysterious meta-circular evaluator 56 00:03:59,675 --> 00:04:02,850 that a LISP evaluator really is something that's concrete enough 57 00:04:02,850 --> 00:04:04,720 that you can hold in the palm of your hand. 58 00:04:04,720 --> 00:04:06,450 You should be able to imagine holding 59 00:04:06,450 --> 00:04:09,546 holding a LISP interpreter there. 60 00:04:09,546 --> 00:04:10,950 All right, how are we going to do this? 61 00:04:10,950 --> 00:04:13,960 We already have all the ingredients. 62 00:04:13,960 --> 00:04:17,450 See, what you learned last time from Jerry 63 00:04:17,450 --> 00:04:22,600 is how to take any particular couple of LISP procedures 64 00:04:22,600 --> 00:04:28,210 and hand-translate them into something that runs on a register machine. 65 00:04:28,210 --> 00:04:30,525 So, to implement all of LISP on a register machine, 66 00:04:30,525 --> 00:04:33,600 all we have to do is take the particular procedures 67 00:04:33,600 --> 00:04:36,050 that are the meta-circular evaluator 68 00:04:36,050 --> 00:04:38,825 and hand-translate them for a register machine. 69 00:04:38,825 --> 00:04:42,320 And that does all of LISP, right? 70 00:04:42,320 --> 00:04:45,380 So, in principle, we already know how to do this. 71 00:04:45,380 --> 00:04:51,275 And, indeed, it's going to be no different, in kind, from 72 00:04:51,275 --> 00:04:54,670 from translating, say, recursive factorial or recursive Fibonacci. 73 00:04:54,670 --> 00:04:56,840 It's just bigger and there's more of it. 74 00:04:56,840 --> 00:05:01,375 So it'd just be more details, but nothing really conceptually new. 75 00:05:01,375 --> 00:05:04,876 And also, when we've done that, and the thing is completely explicit, 76 00:05:04,876 --> 00:05:06,990 and we see how to implement LISP in terms of 77 00:05:06,990 --> 00:05:10,085 the actual sequential register operations, 78 00:05:10,085 --> 00:05:14,810 that's going to be our final most explicit model of LISP in this course. 79 00:05:14,810 --> 00:05:16,950 And, remember, that's a progression through this course. 80 00:05:16,950 --> 00:05:20,100 We started out with substitution, which is sort of like algebra. 81 00:05:20,100 --> 00:05:21,838 And then we went to the environment model, 82 00:05:21,838 --> 00:05:26,125 which talked about the actual frames and how they got linked together. 83 00:05:26,125 --> 00:05:31,080 And then we made that more concrete in the meta-circular evaluator. 84 00:05:31,080 --> 00:05:34,360 There are things the meta-circular evaluator doesn't tell us. 85 00:05:34,360 --> 00:05:36,090 You should realize that. 86 00:05:36,090 --> 00:05:40,420 For instance, it left unanswered the question of how 87 00:05:40,420 --> 00:05:45,175 a procedure, like recursive factorial here, 88 00:05:45,175 --> 00:05:47,210 somehow takes space that grows. 89 00:05:47,210 --> 00:05:51,948 On the other hand, a procedure which also looks syntactically recursive, 90 00:05:51,948 --> 00:05:56,760 called fact-iter, somehow doesn't take space.We justify , 91 00:05:56,760 --> 00:06:00,500 We justify that it doesn't need to take space 92 00:06:00,500 --> 00:06:01,960 by showing the substitution model. 93 00:06:01,960 --> 00:06:07,275 But we didn't really say how it happens that the machine manages to do that, 94 00:06:07,275 --> 00:06:09,161 that that has to do with the details 95 00:06:09,161 --> 00:06:12,250 of how arguments are passed to procedures. 96 00:06:12,250 --> 00:06:15,846 And that's the thing we didn't see in the meta-circular evaluator precisely 97 00:06:15,846 --> 00:06:19,700 because the way arguments got passed to procedures in this LISP 98 00:06:19,700 --> 00:06:25,050 depended on the way arguments got passed to procedures in this LISP. 99 00:06:26,070 --> 00:06:30,740 But, now, that's going to become extremely explicit. 100 00:06:30,740 --> 00:06:31,230 OK. 101 00:06:31,230 --> 00:06:34,426 Well, before going on to the evaluator, 102 00:06:34,426 --> 00:06:37,600 let me just give you a sense of what a whole LISP system looks like 103 00:06:37,600 --> 00:06:39,086 so you can see the parts we're going to talk about 104 00:06:39,086 --> 00:06:43,250 and the parts we're not going to talk about. 105 00:06:43,250 --> 00:06:48,675 Let's see, over here is a happy LISP user, 106 00:06:48,675 --> 00:06:53,245 and the LISP user is talking to something called the reader. 107 00:07:00,360 --> 00:07:14,170 The reader's job in life is to take characters from the user 108 00:07:14,170 --> 00:07:17,960 and turn them into data structures in something called 109 00:07:17,960 --> 00:07:21,405 a list structure memory. 110 00:07:29,783 --> 00:07:32,653 All right, so the reader is going to take 111 00:07:32,653 --> 00:07:36,953 symbols, parentheses, and A's and B's, and 1s and 3s that you type in, 112 00:07:36,953 --> 00:07:39,150 and turn these into actual list structure: 113 00:07:39,150 --> 00:07:39,156 pairs, and pointers, and things. 114 00:07:39,156 --> 00:07:42,340 pairs, and pointers, and things. 115 00:07:42,340 --> 00:07:45,850 And so, by the time evaluator is going, there are no characters in the world. 116 00:07:45,850 --> 00:07:49,480 And, of course, in more modern list systems, there's sort of 117 00:07:49,480 --> 00:07:52,325 a big morass here that might sit between the user and the reader: 118 00:07:52,325 --> 00:07:54,775 Windows systems, and top levels, 119 00:07:54,775 --> 00:07:56,280 and mice, and all kinds of things. 120 00:07:56,280 --> 00:07:59,590 But conceptually, characters are coming in. 121 00:07:59,590 --> 00:08:05,525 All right, the reader transforms these into pointers 122 00:08:05,525 --> 00:08:08,275 pointers to stuff in this memory, 123 00:08:08,275 --> 00:08:12,445 and that's what the evaluator sees 124 00:08:15,300 --> 00:08:17,090 OK? 125 00:08:17,090 --> 00:08:17,300 The evaluator has a bunch of helpers. 126 00:08:17,300 --> 00:08:19,780 The evaluator has a bunch of helpers. 127 00:08:19,780 --> 00:08:23,080 It has all possible primitive operators you might want. 128 00:08:23,080 --> 00:08:28,400 So there's a completely separate box, 129 00:08:28,400 --> 00:08:32,225 a floating point unit, 130 00:08:32,225 --> 00:08:35,960 or all sorts of things, which do the primitive operators. 131 00:08:35,960 --> 00:08:37,548 And, if you want more special primitives, 132 00:08:37,548 --> 00:08:42,080 you build more primitive operators, but they're separate from the evaluator. 133 00:08:42,080 --> 00:08:45,025 The evaluator finally gets an answer 134 00:08:45,025 --> 00:08:50,450 and communicates that to the printer. 135 00:08:50,780 --> 00:08:52,265 And now, the printer's job in life is to take 136 00:08:52,265 --> 00:08:55,318 this list structure coming from the evaluator, 137 00:08:55,318 --> 00:08:57,614 and turn it back into characters, 138 00:09:01,700 --> 00:09:04,075 and communicate them to the user through 139 00:09:04,075 --> 00:09:05,750 whatever interface there is. 140 00:09:08,050 --> 00:09:12,670 OK. Well, today, what we're going to talk about is this evaluator. 141 00:09:12,670 --> 00:09:15,200 The primitive operators have nothing particular to do with LISP, 142 00:09:15,200 --> 00:09:19,175 they're however you like to implement primitive operations. 143 00:09:19,175 --> 00:09:22,187 The reader and printer are actually complicated, 144 00:09:22,187 --> 00:09:24,420 but we're not going to talk about them. 145 00:09:24,420 --> 00:09:27,100 They sort of have to do with details of how you might build 146 00:09:27,100 --> 00:09:29,900 build up list structure from characters. 147 00:09:29,900 --> 00:09:32,490 So that is a long story, but we're not going to talk about it, 148 00:09:32,490 --> 00:09:36,930 the list structure memory, we'll talk about next time. 149 00:09:36,930 --> 00:09:40,125 So, pretty much, except for the details of reading and printing, 150 00:09:40,125 --> 00:09:43,250 the only mystery that's going to be left after you see the evaluator 151 00:09:43,250 --> 00:09:46,295 is how you build list structure on conventional memories. 152 00:09:46,295 --> 00:09:50,580 But we'll worry about that next time too. 153 00:09:50,580 --> 00:09:51,830 OK. 154 00:09:53,350 --> 00:09:56,110 Well, let's start talking about the evaluator. 155 00:09:56,110 --> 00:09:59,775 The one that we're going to show you, of course, is not, 156 00:09:59,775 --> 00:10:01,120 I think, nothing special about it. 157 00:10:01,120 --> 00:10:04,810 It's just a particular register machine that runs LISP. 158 00:10:04,810 --> 00:10:09,890 And it has seven registers, and here are the seven registers. 159 00:10:09,890 --> 00:10:14,925 There's a register, called EXP, and its job is to 160 00:10:14,925 --> 00:10:18,370 hold the expression to be evaluated. 161 00:10:18,370 --> 00:10:21,750 And by that, I mean it's going to hold a pointer 162 00:10:21,750 --> 00:10:23,764 to someplace in list structure memory that holds 163 00:10:23,764 --> 00:10:26,550 the expression to be evaluated. 164 00:10:26,550 --> 00:10:31,000 There's a register, called ENV, which holds the environment 165 00:10:31,000 --> 00:10:34,070 in which this expression is to be evaluated. 166 00:10:34,070 --> 00:10:38,240 And, again, I made a pointer. The environment is some data structure. 167 00:10:38,240 --> 00:10:40,425 There's a register, called FUN, which will 168 00:10:40,425 --> 00:10:44,350 which will hold the procedure to be applied when you go to apply a procedure. 169 00:10:44,350 --> 00:10:47,325 A register, called ARGL, 170 00:10:47,325 --> 00:10:50,200 which wants the list of evaluated arguments. 171 00:10:50,200 --> 00:10:53,140 What you can start seeing here is the basic structure of the evaluator. 172 00:10:53,140 --> 00:10:54,490 Remember how evaluators work. 173 00:10:54,490 --> 00:10:57,670 There's a piece that takes expressions and environments, 174 00:10:57,670 --> 00:10:59,100 and there's a piece that takes 175 00:10:59,100 --> 00:11:03,480 functions, or procedures and arguments. 176 00:11:03,480 --> 00:11:07,294 And going back and forth around here is the eval/apply loop. 177 00:11:07,294 --> 00:11:10,000 So those are the basic pieces of the eval and apply. 178 00:11:10,000 --> 00:11:11,610 Then there's some other things, there's continue. 179 00:11:11,610 --> 00:11:15,340 You just saw before how the continue register is used to 180 00:11:15,340 --> 00:11:18,750 implement recursion and stack discipline. 181 00:11:18,750 --> 00:11:23,925 There's a register that's going to hold the result of some evaluation. 182 00:11:23,925 --> 00:11:26,555 And then, besides that, there's one temporary register, 183 00:11:26,555 --> 00:11:29,280 called UNEV, which typically, in the evaluator, 184 00:11:29,280 --> 00:11:30,625 is going to be used to hold 185 00:11:30,625 --> 00:11:33,950 temporary pieces of the expression you're working on, 186 00:11:33,950 --> 00:11:37,150 which you haven't gotten around to evaluate yet, right? 187 00:11:37,150 --> 00:11:40,646 So there's my machine: a seven-register machine. 188 00:11:40,646 --> 00:11:42,981 And, of course, you might want to make a machine with 189 00:11:42,981 --> 00:11:44,846 a lot more registers to get better performance, 190 00:11:44,846 --> 00:11:48,480 but this is just a tiny, minimal one. 191 00:11:48,480 --> 00:11:49,780 Well, how about the data paths? 192 00:11:49,780 --> 00:11:55,100 This machine has a lot of special operations for LISP. 193 00:11:55,100 --> 00:12:00,120 So, here are some typical data paths. 194 00:12:00,120 --> 00:12:03,320 A typical one might be, oh, assign to the VAL register 195 00:12:03,320 --> 00:12:06,710 the contents of the EXP register. 196 00:12:06,710 --> 00:12:11,900 In terms of those diagrams you saw, that's a little button on some arrow. 197 00:12:11,900 --> 00:12:13,699 Here's a more complicated one. 198 00:12:13,699 --> 00:12:18,810 It says branch, if the thing in the expression register is 199 00:12:18,810 --> 00:12:23,550 a conditional to some label here, called the ev-conditional. 200 00:12:23,550 --> 00:12:26,230 And you can imagine this implemented in a lot of different ways. 201 00:12:26,230 --> 00:12:30,600 You might imagine this conditional test as a special purpose sub-routine, 202 00:12:30,600 --> 00:12:33,845 and conditional might be represented as some data abstraction 203 00:12:33,845 --> 00:12:36,610 that you don't care about at this level of detail. 204 00:12:36,610 --> 00:12:37,980 So that might be done as a sub-routine. 205 00:12:37,980 --> 00:12:40,900 This might be a machine with hardware-types, 206 00:12:40,900 --> 00:12:45,350 and conditional might be testing some bits for a particular code. 207 00:12:45,350 --> 00:12:46,417 There are all sorts of ways that's 208 00:12:46,417 --> 00:12:50,190 beneath the level of abstraction we're looking at. 209 00:12:50,190 --> 00:12:53,247 Another kind of operation, and there are a lot of different operations 210 00:12:53,247 --> 00:12:56,840 assigned to EXP, the first clause of what's in EXP. 211 00:12:56,840 --> 00:12:59,260 This might be part of processing a conditional. 212 00:12:59,260 --> 00:13:04,258 And, again, first clause is some selector whose details we don't care about. 213 00:13:04,258 --> 00:13:06,300 And you can, again, imagine that as a sub-routine 214 00:13:06,300 --> 00:13:09,180 which'll do some list operations, or you can imagine that as 215 00:13:09,180 --> 00:13:12,170 something that's built directly into hardware. 216 00:13:12,170 --> 00:13:15,222 The reason I keep saying you can imagine it built directly into hardware 217 00:13:15,222 --> 00:13:18,360 is even though there are a lot of operations, 218 00:13:18,360 --> 00:13:19,740 there are still a fixed number of them. 219 00:13:19,740 --> 00:13:22,370 I forget how many, maybe 150. 220 00:13:22,370 --> 00:13:26,167 So, it's plausible to think of building these directly into hardware. 221 00:13:26,167 --> 00:13:28,275 Here's a more complicated one. 222 00:13:28,275 --> 00:13:31,500 You can see this has to do with looking up the values of variables. 223 00:13:31,500 --> 00:13:35,550 It says assign to the VAL register the result of looking up 224 00:13:35,550 --> 00:13:39,025 the variable value of some particular expression, 225 00:13:39,025 --> 00:13:42,600 which,in this case, is supposed to be a variable in some environment. 226 00:13:42,600 --> 00:13:46,280 And this'll be some operation that searches through 227 00:13:46,280 --> 00:13:49,325 the environment structure, however it is represented, 228 00:13:49,325 --> 00:13:52,019 and goes and looks up that variable. 229 00:13:52,019 --> 00:13:55,790 And, again, that's below the level of detail that we're thinking about. 230 00:13:55,790 --> 00:13:57,300 This has to do with the details of 231 00:13:57,300 --> 00:14:00,075 the data structures for representing environments. 232 00:14:00,075 --> 00:14:03,679 But, anyway, there is this fixed and finite number 233 00:14:03,679 --> 00:14:06,325 of operations in the register machine. 234 00:14:08,500 --> 00:14:11,720 Well, what's its overall structure? 235 00:14:11,720 --> 00:14:14,675 Those are some typical operations. 236 00:14:14,675 --> 00:14:16,442 Remember what we have to do, 237 00:14:16,442 --> 00:14:20,172 we have to take the meta-circular evaluator-- 238 00:14:20,172 --> 00:14:22,767 and here's a piece of the meta-circular evaluator. 239 00:14:22,767 --> 00:14:28,050 This is the one using abstract syntax that's in the book. 240 00:14:28,050 --> 00:14:33,500 It's a little bit different from the one that Jerry shows you. 241 00:14:33,500 --> 00:14:37,874 And the main thing to remember about the evaluator is that 242 00:14:37,874 --> 00:14:43,425 it's doing some sort of case analysis on the kinds of expressions: 243 00:14:43,425 --> 00:14:48,560 so if it's either self-evaluated, or quoted, or whatever else. 244 00:14:48,560 --> 00:14:50,864 And then, in the general case where 245 00:14:50,864 --> 00:14:53,550 the expression it's looking at is an application, 246 00:14:53,550 --> 00:14:55,750 there's some tricky recursions going on. 247 00:14:55,750 --> 00:15:00,730 First of all, eval has to call itself both to evaluate the 248 00:15:00,730 --> 00:15:05,880 operator and to evaluate all the operands. 249 00:15:05,880 --> 00:15:10,850 So there's this sort of red recursion of values walking down the tree 250 00:15:10,850 --> 00:15:12,270 that's really the easy recursion. 251 00:15:12,270 --> 00:15:14,750 That's just a val walking down this tree of expressions. 252 00:15:14,750 --> 00:15:16,305 Then, in the evaluator, there's a hard recursion. 253 00:15:16,305 --> 00:15:21,650 There's the red to green. Eval calls apply. 254 00:15:22,470 --> 00:15:26,450 That's the case where evaluating a procedure or argument 255 00:15:26,450 --> 00:15:30,370 reduces to applying the procedure to the list of arguments. 256 00:15:30,370 --> 00:15:33,875 And then, apply comes over here. 257 00:15:34,770 --> 00:15:37,650 Apply takes a procedure and arguments 258 00:15:37,650 --> 00:15:41,051 and, in the general case where there's a compound procedure, 259 00:15:41,051 --> 00:15:44,560 apply goes around and green calls red. Eval -- 260 00:15:44,560 --> 00:15:48,170 Apply comes around and calls eval again. 261 00:15:48,170 --> 00:15:51,330 Eval's the body of the procedure in the result of 262 00:15:51,330 --> 00:15:55,485 extending the environment with the parameters of the procedure 263 00:15:55,485 --> 00:15:57,379 by binding the arguments. 264 00:15:59,620 --> 00:16:01,626 Except in the primitive case, where it just calls something else 265 00:16:01,626 --> 00:16:05,980 primitive-apply, which is not really the business of the evaluator. 266 00:16:05,980 --> 00:16:11,249 So this sort of red to green, to red to green, that's the 267 00:16:11,249 --> 00:16:13,975 that's the eval/apply loop, 268 00:16:13,975 --> 00:16:19,475 and that's the thing that we're going to want to see in the evaluator. 269 00:16:19,475 --> 00:16:21,079 Well, it won't surprise you at all that 270 00:16:21,079 --> 00:16:27,470 the two big pieces of this evaluator correspond to eval and apply. 271 00:16:27,470 --> 00:16:29,548 There's a piece called eval-dispatch, 272 00:16:29,548 --> 00:16:31,913 and a piece called apply-dispatch. 273 00:16:31,913 --> 00:16:34,095 And, before we get into the details of the code, 274 00:16:34,095 --> 00:16:37,760 the way to understand this is to think, again, in terms of 275 00:16:37,760 --> 00:16:41,870 these pieces of the evaluator having contracts with the rest of the world. 276 00:16:41,870 --> 00:16:45,780 What do they do from the outside before getting into the grungy details? 277 00:16:45,780 --> 00:16:51,300 Well, the contract for eval-dispatch-- remember, it corresponds to eval. 278 00:16:51,300 --> 00:16:54,100 It's got to evaluate an expression in an environment. 279 00:16:54,100 --> 00:16:56,525 So, in particular, what this one is going to do, 280 00:16:56,525 --> 00:16:59,920 eval-dispatch will assume that, when you call it, that 281 00:16:59,920 --> 00:17:03,640 the expression you want to evaluate is in the EXP register. 282 00:17:03,640 --> 00:17:07,750 The environment in which you want the evaluation to take place 283 00:17:07,750 --> 00:17:09,569 is in the ENV register. 284 00:17:09,569 --> 00:17:11,899 And continue tells you the place where the machine should 285 00:17:11,899 --> 00:17:14,575 go next when the evaluation is done. 286 00:17:17,440 --> 00:17:21,070 Eval-dispatch's contract is that it'll actually perform that evaluation, 287 00:17:21,070 --> 00:17:26,619 and, at the end of which, it'll end up at the place specified by continue. 288 00:17:26,619 --> 00:17:29,825 The result of the evaluation will be in the VAL register. 289 00:17:29,825 --> 00:17:32,964 And it just warns you, it makes no promises about 290 00:17:32,964 --> 00:17:35,230 what happens to the registers. 291 00:17:35,230 --> 00:17:37,490 All other registers might be destroyed. 292 00:17:37,490 --> 00:17:41,412 So, there's one piece, OK? 293 00:17:41,412 --> 00:17:45,925 Together, the pieces, apply-dispatch that corresponds to apply, 294 00:17:45,925 --> 00:17:48,731 it's got to apply a procedure to some arguments, 295 00:17:48,731 --> 00:17:51,434 so it assumes that this register, ARGL, 296 00:17:51,434 --> 00:17:54,540 contains a list of the evaluated arguments. 297 00:17:54,540 --> 00:17:57,220 FUN contains the procedure. 298 00:17:57,220 --> 00:17:59,500 Those correspond to the arguments to the apply 299 00:17:59,500 --> 00:18:02,300 procedure in the meta-circular evaluator. 300 00:18:03,970 --> 00:18:07,676 And apply, in this particular evaluator, we're going to use a discipline which says 301 00:18:07,676 --> 00:18:12,556 the place the machine should go to next when apply is done 302 00:18:12,556 --> 00:18:17,070 is, at the moment apply-dispatch is called at the top of the stack 303 00:18:17,070 --> 00:18:21,840 that's just discipline for the way this particular machine's organized. 304 00:18:21,840 --> 00:18:23,700 And now apply's contract is given all that. 305 00:18:23,700 --> 00:18:25,540 It'll perform the application. 306 00:18:25,540 --> 00:18:28,890 The result of that application will end up in VAL. 307 00:18:28,890 --> 00:18:31,120 The stack will be popped. 308 00:18:31,120 --> 00:18:34,841 And, again, the contents of all the other registers may be destroyed. 309 00:18:34,841 --> 00:18:39,760 All right? So that's the basic organization of this machine. 310 00:18:39,760 --> 00:18:41,110 Let's break for a little bit and see if there are any 311 00:18:41,110 --> 00:18:42,700 questions, and then we'll do a real example. 312 00:19:47,850 --> 00:19:50,175 Well, let's take the register machine now, 313 00:19:50,175 --> 00:19:52,175 and actually step through, 314 00:19:52,200 --> 00:19:58,708 and really, in real detail, so you see completely concrete 315 00:19:58,708 --> 00:20:03,400 how some expressions are evaluated, all right? 316 00:20:03,400 --> 00:20:09,300 So, let's start with a very simple expression. 317 00:20:09,620 --> 00:20:14,150 Let's evaluate the expression 1. 318 00:20:18,775 --> 00:20:21,279 And we need an environment, so let's imagine that 319 00:20:21,279 --> 00:20:24,025 somewhere there's an environment, we'll call it E,0. 320 00:20:30,260 --> 00:20:35,620 And just, since we'll use these later, 321 00:20:35,620 --> 00:20:38,360 we obviously don't really need anything to evaluate 1. 322 00:20:38,360 --> 00:20:41,202 But, just for reference later, let's assume that E,0 has in it 323 00:20:41,202 --> 00:20:49,140 an X that's bound to 3 and a Y that's bound to 4, OK? 324 00:20:49,140 --> 00:20:53,700 And now what we're going to do is we're going to evaluate 1 325 00:20:53,700 --> 00:20:59,650 in this environment, and so the ENV register has a pointer 326 00:20:59,650 --> 00:21:03,560 to this environment, E,0, all right? 327 00:21:03,560 --> 00:21:05,650 So let's watch that thing go. 328 00:21:05,650 --> 00:21:08,260 What I'm going to do is step through the code. 329 00:21:08,260 --> 00:21:09,782 And, let's see, I'll be the controller. 330 00:21:09,782 --> 00:21:12,980 And now what I need, since this gets rather complicated, 331 00:21:12,980 --> 00:21:16,830 is a very little execution unit. 332 00:21:16,830 --> 00:21:21,310 So here's the execution unit, OK? 333 00:21:22,624 --> 00:21:23,874 OK. 334 00:21:27,088 --> 00:21:28,590 OK. 335 00:21:28,590 --> 00:21:30,533 All right, now we're going to start. 336 00:21:30,533 --> 00:21:33,700 We're going to start the machine at eval-dispatch, right? 337 00:21:33,700 --> 00:21:35,875 That's the beginning of this. 338 00:21:35,875 --> 00:21:39,320 Eval-dispatch is going to look at the expression in dispatch, 339 00:21:39,320 --> 00:21:40,875 just like eval 340 00:21:40,875 --> 00:21:41,760 where we look at the very first thing. 341 00:21:41,760 --> 00:21:47,950 We branch on whether or not this expression is self-evaluating. 342 00:21:47,950 --> 00:21:52,171 Self-evaluating is some abstraction we put into the machine-- 343 00:21:52,171 --> 00:21:53,515 it's going to be true for numbers-- 344 00:21:53,515 --> 00:21:56,775 to a place called ev-self-eval, right? 345 00:21:56,775 --> 00:22:00,010 So me, being the controller, looks at ev-self-eval, 346 00:22:00,010 --> 00:22:02,607 so we'll go over to there. 347 00:22:02,607 --> 00:22:08,128 Ev-self-eval says fine, assign to val 348 00:22:08,128 --> 00:22:15,220 whatever is in the expression unit, OK? 349 00:22:15,220 --> 00:22:17,600 And I have a bug 350 00:22:17,600 --> 00:22:17,650 because what I didn't do when I initialized this machine 351 00:22:17,650 --> 00:22:21,625 because what I didn't do when I initialized this machine 352 00:22:21,625 --> 00:22:24,650 is also say what's supposed to happen when it's done, 353 00:22:24,650 --> 00:22:27,640 so I should have started out the machine with 354 00:22:27,640 --> 00:22:32,050 done being in the continue register, OK? 355 00:22:32,050 --> 00:22:33,079 So we assign to VAL. 356 00:22:33,079 --> 00:22:38,000 And now go to fetch of continue, and now change-- 357 00:22:38,000 --> 00:22:40,000 OK. 358 00:22:40,000 --> 00:22:42,160 OK, let's try something harder. 359 00:22:42,160 --> 00:22:44,787 Let's reset the machine here, 360 00:22:44,787 --> 00:22:51,562 and we'll put in the expression register, X, OK? 361 00:22:56,710 --> 00:22:59,610 Start again at eval-dispatch. 362 00:22:59,610 --> 00:23:01,690 Check, is it self-evaluating? 363 00:23:01,690 --> 00:23:02,650 No. 364 00:23:02,650 --> 00:23:04,630 Is it a variable? 365 00:23:04,630 --> 00:23:05,560 Yes. 366 00:23:05,560 --> 00:23:08,380 We go off to ev-variable. 367 00:23:08,380 --> 00:23:12,131 It says assign to VAL, 368 00:23:12,131 --> 00:23:16,150 look up the variable value in the expression register, OK? 369 00:23:21,075 --> 00:23:23,625 Go to fetch of continue. 370 00:23:23,625 --> 00:23:24,875 PROFESSOR: Done. 371 00:23:27,252 --> 00:23:28,950 PROFESSOR: OK. 372 00:23:28,950 --> 00:23:29,430 All right. 373 00:23:29,430 --> 00:23:31,330 Well, that's the basic idea. 374 00:23:31,330 --> 00:23:32,688 That's a simple operation of the machine. 375 00:23:32,688 --> 00:23:36,070 Now, let's actually do something a little bit more interesting. 376 00:23:36,070 --> 00:23:49,678 Let's look at the expression the sum of x and y. 377 00:23:49,678 --> 00:23:50,130 OK. 378 00:23:50,130 --> 00:23:54,350 And now we'll see how you start unrolling these expression trees. 379 00:23:56,625 --> 00:23:59,434 Well, start again at eval-dispatch. 380 00:24:04,610 --> 00:24:05,935 Self-evaluating? 381 00:24:05,935 --> 00:24:06,850 No. 382 00:24:06,850 --> 00:24:07,850 Variable? No. 383 00:24:07,850 --> 00:24:10,270 All the other special forms which I didn't write down, 384 00:24:10,270 --> 00:24:12,480 like quote, and lambda, and set, and whatever, 385 00:24:12,480 --> 00:24:13,260 it's none of those. 386 00:24:13,260 --> 00:24:15,889 It turns out to be an application, 387 00:24:15,889 --> 00:24:19,970 so we go off to ev-application, OK? 388 00:24:19,970 --> 00:24:25,580 Ev-application, remember what it's going to do overall. 389 00:24:25,580 --> 00:24:28,310 It is going to evaluate the operator. 390 00:24:28,310 --> 00:24:32,225 It's going to evaluate the arguments, 391 00:24:32,225 --> 00:24:35,060 and then it's going to go apply them. 392 00:24:35,060 --> 00:24:37,887 So, before we start, since we're being very literal, 393 00:24:37,887 --> 00:24:40,435 we'd better remember that, somewhere in this environment, 394 00:24:40,435 --> 00:24:44,475 it's linked to another environment in which 395 00:24:44,475 --> 00:24:51,475 plus is bound to the primitive procedure plus 396 00:24:51,475 --> 00:24:55,340 before we get an unknown variable in our machine. 397 00:24:55,340 --> 00:24:58,625 OK, so we're at ev-application. 398 00:24:59,700 --> 00:25:04,405 OK, assign to UNEV the operands 399 00:25:04,405 --> 00:25:07,920 of what's in the expression register, OK? 400 00:25:07,920 --> 00:25:09,230 Those are the operands. 401 00:25:09,230 --> 00:25:13,225 UNEV's a temporary register where we're going to save them. 402 00:25:13,225 --> 00:25:13,860 PROFESSOR: I'm assigning. 403 00:25:13,860 --> 00:25:18,070 PROFESSOR: Assign to x the operator. 404 00:25:18,070 --> 00:25:21,849 Now, notice we've destroyed that expression in x, 405 00:25:21,849 --> 00:25:25,820 but the piece that we need is now in UNEV. OK. 406 00:25:25,820 --> 00:25:28,750 Now, we're going to get set up to recursively evaluate the operator. 407 00:25:28,750 --> 00:25:32,825 Save the continue register on the stack. 408 00:25:34,870 --> 00:25:37,600 Save the environment. 409 00:25:40,520 --> 00:25:43,594 Save UNEV. 410 00:25:49,409 --> 00:25:56,234 OK, assign to continue a label called eval-args. 411 00:26:01,400 --> 00:26:01,950 Now, what have we done? 412 00:26:01,950 --> 00:26:04,380 We've set up for a recursive call. 413 00:26:04,380 --> 00:26:06,280 We're about to go to eval-dispatch. 414 00:26:06,280 --> 00:26:10,230 We've set up for a recursive call to eval-dispatch. 415 00:26:10,230 --> 00:26:11,020 What did we do? 416 00:26:11,020 --> 00:26:14,425 We took the things we're going to need later, 417 00:26:14,425 --> 00:26:16,363 those operands that were in UNEV; 418 00:26:16,363 --> 00:26:19,073 the environment in which we're going to eventually have to, 419 00:26:19,073 --> 00:26:22,129 maybe, evaluate those operands; 420 00:26:22,129 --> 00:26:25,265 the place we eventually want to go to, which, in this case, was done; 421 00:26:25,265 --> 00:26:27,275 we've saved them on the stack. 422 00:26:27,275 --> 00:26:28,724 The reason we saved them on the stack is because 423 00:26:28,724 --> 00:26:33,550 eval-dispatch makes no promises about what registers it may destroy. 424 00:26:33,550 --> 00:26:35,020 So all that stuff is saved on the stack. 425 00:26:35,020 --> 00:26:37,380 Now, we've set up eval-dispatch's contract. 426 00:26:37,380 --> 00:26:40,964 There's a new expression, which is the operator plus; 427 00:26:40,964 --> 00:26:44,250 a new environment, although, in this case, it's the same one; 428 00:26:44,250 --> 00:26:47,600 and a new place to go to when you're done, which is eval-args. 429 00:26:47,600 --> 00:26:48,130 So that's set up. 430 00:26:48,130 --> 00:26:50,890 Now, we're going to go off to eval-dispatch. 431 00:26:50,890 --> 00:26:53,090 Here we are back at eval-dispatch. 432 00:26:53,090 --> 00:26:54,490 It's not self-evaluating. 433 00:26:54,490 --> 00:27:00,147 Oh, it's a variable, so we'd better go off to ev-variable, right? 434 00:27:00,147 --> 00:27:02,880 Ev-variable is assigned to VAL. 435 00:27:02,880 --> 00:27:08,770 Look up the variable value of the expression, OK? 436 00:27:08,770 --> 00:27:13,000 So VAL is the primitive procedure plus, OK? 437 00:27:13,000 --> 00:27:15,020 And go to fetch of continue. 438 00:27:15,020 --> 00:27:16,050 PROFESSOR: Eval-args. 439 00:27:16,050 --> 00:27:19,340 PROFESSOR: Right, which is now eval-args not done. 440 00:27:19,340 --> 00:27:23,071 So we come back here at eval-args, and what do we do? 441 00:27:23,071 --> 00:27:29,050 We're going to restore the stuff that we saved, so we restore UNEV. 442 00:27:29,050 --> 00:27:32,900 And notice, there, it wasn't necessary, although, in general, it would be. 443 00:27:32,900 --> 00:27:35,430 It might be some arbitrary evaluation that happened. 444 00:27:35,430 --> 00:27:54,900 We restore ENV. OK, we assign to FUN fetch of VAL. 445 00:27:58,620 --> 00:28:04,340 OK, now, we're going to go off and start evaluating some arguments. 446 00:28:04,340 --> 00:28:08,330 Well, first thing we'd better do is save FUN because some 447 00:28:08,330 --> 00:28:13,675 arbitrary stuff might happen in that evaluation. 448 00:28:15,330 --> 00:28:20,750 We initialize the argument list. Assign to argl an empty argument list, 449 00:28:20,750 --> 00:28:25,460 and go to eval-arg-loop, OK? 450 00:28:25,460 --> 00:28:29,580 At eval-arg-loop, the idea of this is we're going to 451 00:28:29,580 --> 00:28:33,540 evaluate the pieces of the expressions that are in UNEV, one by one, 452 00:28:33,540 --> 00:28:35,688 and move them from unevaluated in UNEV 453 00:28:35,688 --> 00:28:38,090 to evaluated in the arg list, OK? 454 00:28:38,090 --> 00:28:42,400 So we save argl. 455 00:28:43,950 --> 00:28:49,145 We assign to x the first operand of the stuff in UNEV. 456 00:28:53,772 --> 00:28:55,890 Now, we check and see if that was the last operand. 457 00:28:55,890 --> 00:28:59,190 In this case, it is not, all right? 458 00:28:59,190 --> 00:29:02,975 So we save the environment. 459 00:29:07,850 --> 00:29:13,500 We save UNEV because those are all things we might need later. 460 00:29:13,500 --> 00:29:15,800 We're going to need the environment to do some more evaluations. 461 00:29:15,800 --> 00:29:20,340 We're going to need UNEV to look at what the rest of those arguments were. 462 00:29:20,340 --> 00:29:26,053 We're going to assign continue a place called accumulate-args, or accumulate-arg. 463 00:29:30,898 --> 00:29:36,810 OK, now, we've set up for another call to eval-dispatch, OK? 464 00:29:36,810 --> 00:29:39,125 All right, now, let me short-circuit this 465 00:29:39,125 --> 00:29:41,090 so we don't go through the details of eval-dispatch. 466 00:29:41,090 --> 00:29:45,103 Eval-dispatch's contract says I'm going to end up, 467 00:29:45,103 --> 00:29:48,240 the world will end up, with the value of evaluating this expression 468 00:29:48,240 --> 00:29:50,270 in this environment in the VAL register, 469 00:29:50,270 --> 00:29:51,320 and I'll end up there. 470 00:29:51,320 --> 00:29:58,010 So we short-circuit all of this, and a 3 ends up in VAL. 471 00:29:58,010 --> 00:29:59,768 And, when we return from eval-dispatch, 472 00:29:59,768 --> 00:30:02,110 we're going to return to accumulate-arg. 473 00:30:02,110 --> 00:30:03,555 PROFESSOR: Accumulate-arg. 474 00:30:06,185 --> 00:30:08,720 PROFESSOR: With 3 in the VAL register, OK? 475 00:30:08,720 --> 00:30:10,650 So that short-circuited that evaluation. 476 00:30:10,650 --> 00:30:11,320 Now, what do we do? 477 00:30:11,320 --> 00:30:13,689 We're going to go back and look at the rest of the arguments, 478 00:30:13,689 --> 00:30:15,609 so we restore UNEV. 479 00:30:17,513 --> 00:30:28,650 We restore ENV. We restore argl. 480 00:30:28,650 --> 00:30:29,170 One thing. 481 00:30:29,170 --> 00:30:30,536 PROFESSOR: Oops! 482 00:30:30,536 --> 00:30:31,290 Parity error. 483 00:30:31,290 --> 00:30:33,465 [LAUGHTER] 484 00:30:33,465 --> 00:30:34,905 PROFESSOR: Restore argl. 485 00:30:41,650 --> 00:30:42,900 PROFESSOR: OK. 486 00:30:45,570 --> 00:30:50,400 OK, we assign to argl consing on 487 00:30:50,400 --> 00:30:53,130 fetch of the value register to what's in argl. 488 00:30:58,985 --> 00:31:05,025 OK, we assign to UNEV the rest of the operands in fetch of UNEV, 489 00:31:08,700 --> 00:31:11,516 and we go back to eval-arg-loop. 490 00:31:11,516 --> 00:31:12,280 PROFESSOR: Eval-arg-loop. 491 00:31:12,280 --> 00:31:13,530 PROFESSOR: OK. 492 00:31:15,880 --> 00:31:17,375 Now, we're about to do the next argument, 493 00:31:17,375 --> 00:31:19,800 so the first thing we do is save argl. 494 00:31:25,400 --> 00:31:31,803 OK, we assign to x the first operand of fetch of UNEV. 495 00:31:34,650 --> 00:31:38,925 OK,we test and see if that's the last operand.In this case, it is 496 00:31:38,925 --> 00:31:43,173 so we're going to go to a special place that says evaluate the last argument 497 00:31:43,173 --> 00:31:44,965 because, notice,after evaluating the argument, 498 00:31:44,965 --> 00:31:47,446 we don't need the environment any more. 499 00:31:47,446 --> 00:31:50,250 That's going to be the difference. 500 00:31:50,250 --> 00:31:52,054 So here, at eval-last-arg, 501 00:31:52,054 --> 00:31:55,382 which is assigned to continue accumulate-last-arg, 502 00:32:04,275 --> 00:32:06,900 now, we're set up again for eval-dispatch. 503 00:32:06,900 --> 00:32:08,620 We've got a place to go to when we're done. 504 00:32:08,620 --> 00:32:09,840 We've got an expression. 505 00:32:09,840 --> 00:32:11,330 We've got an environment. 506 00:32:11,330 --> 00:32:14,370 OK, so we'll short-circuit the call to eval-dispatch. 507 00:32:14,370 --> 00:32:16,700 And what'll happen is there's a y there, 508 00:32:16,700 --> 00:32:21,060 it's 4 in that environment, so VAL will end up with 4 in it. 509 00:32:21,060 --> 00:32:25,450 And, then, we're going to end up at accumulate-last-arg, OK? 510 00:32:25,450 --> 00:32:30,525 So, at accumulate-last-arg, we restore argl. 511 00:32:41,490 --> 00:32:45,835 We assign to argl cons of fetch of the new value onto it, 512 00:32:45,835 --> 00:32:49,850 so we cons a 4 onto that. 513 00:32:49,850 --> 00:32:53,446 We restore what was saved in the function register. 514 00:32:53,446 --> 00:32:56,277 And notice, in this case, it had not been destroyed, 515 00:32:56,277 --> 00:32:59,132 but in general, it will be. 516 00:32:59,132 --> 00:33:02,850 And now, we're ready to go off to apply-dispatch, all right? 517 00:33:02,850 --> 00:33:04,510 So we've just gone through the eval. 518 00:33:04,510 --> 00:33:07,980 We evaluated the argument, the operator, and the arguments, 519 00:33:07,980 --> 00:33:09,580 and now, we're about to apply them. 520 00:33:09,580 --> 00:33:17,481 So we come off to apply-dispatch here, OK? 521 00:33:17,481 --> 00:33:20,575 We come off to apply-dispatch, 522 00:33:20,575 --> 00:33:23,450 and we're going to check whether it's a primitive or a compound procedure. 523 00:33:23,450 --> 00:33:24,116 PROFESSOR: Yes. 524 00:33:24,116 --> 00:33:24,830 PROFESSOR: All right. 525 00:33:24,830 --> 00:33:27,375 So, in this case, it's a primitive procedure, 526 00:33:27,375 --> 00:33:29,790 and we go off to primitive-apply. 527 00:33:29,790 --> 00:33:34,130 So we go off to primitive-apply, and it says 528 00:33:34,130 --> 00:33:38,360 assign to VAL the result of applying primitive procedure 529 00:33:38,360 --> 00:33:40,940 of the function to the argument list. 530 00:33:40,940 --> 00:33:42,540 PROFESSOR: I don't know how to add. 531 00:33:42,540 --> 00:33:43,995 I'm just an execution unit. 532 00:33:43,995 --> 00:33:45,350 PROFESSOR: Well, I don't know how to add either. 533 00:33:45,350 --> 00:33:48,360 I'm just the evaluator, so we need a primitive operator. 534 00:33:48,360 --> 00:33:50,925 Let's see, so the primitive operator, what's the 535 00:33:50,925 --> 00:33:52,605 What's the sum of 3 and 4? 536 00:33:52,605 --> 00:33:53,205 AUDIENCE: 7. 537 00:33:53,205 --> 00:33:55,050 PROFESSOR: OK, 7. 538 00:33:55,050 --> 00:33:55,999 PROFESSOR: Thank you. 539 00:33:58,837 --> 00:34:00,850 PROFESSOR: Now, we restore continue, 540 00:34:11,275 --> 00:34:12,900 and we go to fetch of continue. 541 00:34:12,900 --> 00:34:13,880 PROFESSOR: Done. 542 00:34:13,880 --> 00:34:14,929 PROFESSOR: OK. 543 00:34:14,929 --> 00:34:18,413 Well, that was in as much detail as you will ever see. 544 00:34:18,413 --> 00:34:21,590 We'll never do it in as much detail again. 545 00:34:21,590 --> 00:34:25,233 One very important thing to notice is that 546 00:34:25,233 --> 00:34:29,780 we just executed a recursive procedure, right? 547 00:34:29,780 --> 00:34:31,172 This whole thing, we used a stack 548 00:34:31,172 --> 00:34:33,070 and the evaluator was recursive. 549 00:34:33,070 --> 00:34:36,480 A lot of people think the reason that you need a stack 550 00:34:36,480 --> 00:34:39,090 and recursion in an evaluator is because you might be 551 00:34:39,090 --> 00:34:42,150 evaluating recursive procedures like factorial or Fibonacci. 552 00:34:42,150 --> 00:34:43,670 It's not true. 553 00:34:43,670 --> 00:34:46,110 So you notice we did recursion here, and all we evaluated was 554 00:34:46,110 --> 00:34:48,010 plus X, Y, all right? 555 00:34:48,010 --> 00:34:51,219 The reason that you need recursion in the evaluator is 556 00:34:51,219 --> 00:34:54,450 because the evaluation process, itself, is recursive, all right? 557 00:34:54,450 --> 00:34:57,760 It's not because the procedure that you might be evaluating in LISP 558 00:34:57,760 --> 00:34:59,270 is a recursive procedure. 559 00:34:59,270 --> 00:35:00,411 So that's an important thing 560 00:35:00,411 --> 00:35:03,010 that people get confused about a lot. 561 00:35:03,010 --> 00:35:06,280 The other thing to notice is that, when we're done here, 562 00:35:06,280 --> 00:35:07,120 we're really done. 563 00:35:07,120 --> 00:35:10,878 Not only are we at done, but 564 00:35:10,878 --> 00:35:13,810 there's no accumulated stuff on the stack, right? 565 00:35:13,810 --> 00:35:17,170 The machine is back to its initial state, all right? 566 00:35:17,170 --> 00:35:19,715 So that's part of what it means to be done. 567 00:35:19,715 --> 00:35:26,410 Another way to say that is the evaluation process has reduced 568 00:35:26,410 --> 00:35:33,245 the expression, plus X, Y, to the value here, 7. 569 00:35:33,245 --> 00:35:36,010 And by reduced, I mean a very particular thing. 570 00:35:36,010 --> 00:35:38,180 It means that there's nothing left on the stack. 571 00:35:38,180 --> 00:35:40,743 The machine is now in the same state, 572 00:35:40,743 --> 00:35:42,723 except there's something in the value register. 573 00:35:42,723 --> 00:35:44,520 It's not part of a sub-problem of anything. 574 00:35:44,520 --> 00:35:46,210 There's nothing to go back to. 575 00:35:46,210 --> 00:35:46,440 OK. 576 00:35:46,440 --> 00:35:47,690 Let's break. 577 00:35:49,712 --> 00:35:50,159 Question? 578 00:35:50,159 --> 00:35:54,027 AUDIENCE: The question here, in the stack, 579 00:35:54,027 --> 00:35:55,820 is because the data may be recursive. 580 00:35:55,820 --> 00:35:59,312 You may have embedded expressions, for instance. 581 00:35:59,312 --> 00:36:02,080 PROFESSOR: Yes, because you might have embedded expressions. 582 00:36:02,080 --> 00:36:04,774 But, again, don't confuse that 583 00:36:04,774 --> 00:36:07,718 with what people sometimes mean by the data may be recursive, 584 00:36:07,718 --> 00:36:12,930 which is to say you have these list-structured, recursive data list operations. 585 00:36:12,930 --> 00:36:13,804 That has nothing to do with it. 586 00:36:13,804 --> 00:36:17,363 It's simply that the expressions contain sub-expressions. 587 00:36:17,363 --> 00:36:19,618 Yeah? 588 00:36:19,618 --> 00:36:23,457 AUDIENCE: Why is it that the order of the arguments in the arg list got reversed? 589 00:36:23,457 --> 00:36:27,260 PROFESSOR: Ah! Yes, I should've mentioned that. 590 00:36:27,260 --> 00:36:29,075 Here, the reason the order is reversed-- 591 00:36:32,507 --> 00:36:36,050 it's a question of what you mean by reversed. 592 00:36:36,050 --> 00:36:40,624 I believe it was Newton. 593 00:36:40,624 --> 00:36:43,800 In the very early part of optics, people realized that, 594 00:36:43,800 --> 00:36:45,500 when you look through the lens of your eye, 595 00:36:45,500 --> 00:36:46,730 the image was up-side down. 596 00:36:46,730 --> 00:36:48,044 And there was a lot of argument about 597 00:36:48,044 --> 00:36:51,280 why that didn't mean you saw things up-side down. 598 00:36:51,280 --> 00:36:52,860 So it's sort of the same issue. 599 00:36:52,860 --> 00:36:54,810 Reversed from what? 600 00:36:54,810 --> 00:36:57,940 So we just need some convention. 601 00:36:57,940 --> 00:37:01,730 The reason that they're coming at 4, 3 is because we're 602 00:37:01,730 --> 00:37:04,520 taking UNEV and consing the result onto argl. 603 00:37:04,520 --> 00:37:06,771 So you have to realize you've made that convention. 604 00:37:06,771 --> 00:37:09,987 The place that you have to realize that-- 605 00:37:09,987 --> 00:37:11,230 well, there's actually two places. 606 00:37:11,230 --> 00:37:12,910 One is in apply-primitive-operator, 607 00:37:12,910 --> 00:37:16,610 which has to realize that the arguments to primitives go in, 608 00:37:16,610 --> 00:37:19,490 in the opposite order from the way you're writing them down. 609 00:37:19,490 --> 00:37:21,008 And the other one is, we'll see later 610 00:37:21,008 --> 00:37:24,016 when you actually go to bind a function's parameters, 611 00:37:24,016 --> 00:37:25,745 you should realize the arguments are going to come in 612 00:37:25,745 --> 00:37:28,870 from the opposite order of the variables to which you're binding them. 613 00:37:28,870 --> 00:37:31,830 So, if you just keep track of that, there's no problem. 614 00:37:31,830 --> 00:37:33,900 Also, this is completely arbitrary 615 00:37:33,900 --> 00:37:37,420 because, if we'd done, say, an iteration through a vector assigning them, 616 00:37:37,420 --> 00:37:40,730 they might come out in the other order, OK? 617 00:37:40,730 --> 00:37:45,085 So it's just a convention of the way this particular evaluator works. 618 00:37:45,085 --> 00:37:46,335 All right, let's take a break. 619 00:38:41,840 --> 00:38:45,609 We just saw evaluating an expression and, 620 00:38:45,609 --> 00:38:46,950 of course, that was very simple one. 621 00:38:46,950 --> 00:38:50,247 But, in essence, it would be no different 622 00:38:50,247 --> 00:38:52,039 if it was some big nested expression, 623 00:38:52,039 --> 00:38:55,130 so there would just be deeper recursion on the stack. 624 00:38:55,130 --> 00:38:56,470 But what I want to do now is show you the last piece. 625 00:38:56,470 --> 00:39:01,013 I want to walk you around this eval and apply loop, right? 626 00:39:01,013 --> 00:39:03,000 That's the thing we haven't seen, really. 627 00:39:03,000 --> 00:39:05,200 We haven't seen any compound procedures 628 00:39:05,200 --> 00:39:07,925 where evalutation of procedure reduces to 629 00:39:07,925 --> 00:39:12,250 where applying of procedure reduces to evaluating the body of the procedure, 630 00:39:12,250 --> 00:39:15,810 so let's just suppose we had this. 631 00:39:15,810 --> 00:39:18,075 Suppose we were looking at the procedure 632 00:39:18,075 --> 00:39:33,995 define F of A and B to be the sum of A and B. 633 00:39:33,995 --> 00:39:37,325 So, as we typed in that procedure previously, 634 00:39:37,325 --> 00:39:42,275 and now we're going to evaluate F of X and Y 635 00:39:42,275 --> 00:39:44,209 again, in this environment, E,0, 636 00:39:44,209 --> 00:39:47,280 where X is bound to 3 and Y is bound to 4. 637 00:39:50,650 --> 00:39:53,825 When the defined is executed, remember, there's a lambda here, 638 00:39:53,825 --> 00:39:55,950 and lambdas create procedures. 639 00:39:55,950 --> 00:40:00,815 And, basically, what will happen is, in E,0, 640 00:40:00,815 --> 00:40:03,563 we'll end up with a binding for F, 641 00:40:03,563 --> 00:40:07,151 which will say F is a procedure, 642 00:40:07,151 --> 00:40:16,495 and its args are A and B, and its body is plus a,b. 643 00:40:17,843 --> 00:40:21,053 So that's what the environment would have looked like 644 00:40:21,053 --> 00:40:22,675 had we made that definition. 645 00:40:24,225 --> 00:40:28,600 Then, when we go to evaluate F of X and Y, 646 00:40:28,600 --> 00:40:31,615 we'll go through exactly the same process that we did before. 647 00:40:31,615 --> 00:40:33,096 It's even the same expression. 648 00:40:33,096 --> 00:40:36,030 The only difference is that F, instead of having primitive 649 00:40:36,030 --> 00:40:39,250 "plus" in it, will have this thing. 650 00:40:41,040 --> 00:40:43,600 And so we'll go through exactly the same process, 651 00:40:43,600 --> 00:40:47,864 except this time, when we end up at apply-dispatch, 652 00:40:47,864 --> 00:40:50,285 the function register, instead of having primitive plus, 653 00:40:50,285 --> 00:40:54,300 will have a thing that will represent it saying procedure, 654 00:40:54,300 --> 00:41:06,275 where the args are A and B, and the body is plus A, B. 655 00:41:07,875 --> 00:41:11,092 And, again, what I mean, by its ENV, I mean there's a pointer to it, 656 00:41:11,092 --> 00:41:13,280 so don't worry that I'm writing a lot of stuff there. 657 00:41:13,280 --> 00:41:15,636 There's a pointer to this procedure data structure. 658 00:41:17,170 --> 00:41:20,960 OK, so, we're in exactly the same situation. 659 00:41:20,960 --> 00:41:26,480 We get to apply-dispatch, so, here, we come to apply-dispatch. 660 00:41:26,480 --> 00:41:30,010 Last time, we branched off to a primitive procedure. 661 00:41:30,010 --> 00:41:34,550 Here, it says oh, we now have a compound procedure, 662 00:41:34,550 --> 00:41:36,911 so we're going to go off to compound-apply. 663 00:41:38,475 --> 00:41:40,075 Now, what's compound-apply? 664 00:41:41,925 --> 00:41:45,090 Well, remember what the meta-circular evaluator did? 665 00:41:45,090 --> 00:41:49,903 Compound-apply said we're going to evaluate 666 00:41:49,903 --> 00:41:54,120 the body of the procedure in some new environment. 667 00:41:54,120 --> 00:41:56,730 Where does that new environment come from? 668 00:41:56,730 --> 00:42:01,362 We take the environment that was packaged with the procedure, 669 00:42:03,029 --> 00:42:05,791 we bind the parameters of the procedure 670 00:42:05,791 --> 00:42:09,759 to the arguments that we're passing in, 671 00:42:09,759 --> 00:42:14,990 and use that as a new frame to extend the procedure environment. 672 00:42:14,990 --> 00:42:21,630 And that's the environment in which we evaluate the procedure body, right? 673 00:42:21,630 --> 00:42:24,470 That's going around the apply/eval loop. 674 00:42:24,470 --> 00:42:27,988 That's apply coming back to call eval, all right? 675 00:42:30,910 --> 00:42:32,860 OK. 676 00:42:32,860 --> 00:42:36,787 So, now, that's all we have to do in compound-apply. 677 00:42:36,787 --> 00:42:37,720 What are we going to do? 678 00:42:37,720 --> 00:42:40,975 We're going to manufacture a new environment. 679 00:42:43,550 --> 00:42:46,768 And we're going to manufacture a new environment that, 680 00:42:46,768 --> 00:42:48,310 let's see, that we'll call E,1. 681 00:42:52,900 --> 00:42:57,310 E,1 is going to be some environment where the 682 00:42:57,310 --> 00:43:01,765 where the parameters of the procedure, where A is bound to 3 683 00:43:01,765 --> 00:43:05,768 and B is bound to 4, and it's linked to E,0 684 00:43:05,768 --> 00:43:09,270 because that's where f is defined. 685 00:43:09,270 --> 00:43:12,050 And, in this environment, we're going to evaluate the body of the procedure. 686 00:43:12,050 --> 00:43:13,870 So let's look at that, all right? 687 00:43:16,525 --> 00:43:20,690 All right, here we are at compound-apply, which says 688 00:43:20,690 --> 00:43:24,500 assign to the expression register 689 00:43:24,500 --> 00:43:28,163 the body of the procedure that's in the function register. 690 00:43:28,163 --> 00:43:42,450 So I assign to the expression register the procedure body, OK? 691 00:43:42,450 --> 00:43:45,825 That's going to be evaluated in an environment 692 00:43:45,825 --> 00:43:51,300 which is formed by making some bindings 693 00:43:51,300 --> 00:43:53,673 using information determined by the procedure-- 694 00:43:53,673 --> 00:43:55,320 that's what's in FUN-- 695 00:43:55,320 --> 00:43:57,800 and the argument list. 696 00:43:57,800 --> 00:44:00,230 And let's not worry about exactly what that does, 697 00:44:00,230 --> 00:44:01,930 but you can see the information's there. 698 00:44:01,930 --> 00:44:05,948 So make bindings will say oh, the procedure, itself, 699 00:44:05,948 --> 00:44:07,950 had an environment attached to it. 700 00:44:07,950 --> 00:44:09,320 I didn't write that quite here. 701 00:44:09,320 --> 00:44:11,300 I should've said in environment 702 00:44:11,300 --> 00:44:13,660 because every procedure gets built with an environment. 703 00:44:13,660 --> 00:44:16,600 So, from that environment, it knows 704 00:44:16,600 --> 00:44:19,290 what the procedure's definition environment is. 705 00:44:19,290 --> 00:44:21,830 It knows what the arguments are. 706 00:44:21,830 --> 00:44:24,280 It looks at argl, and then you see a reversal convention here. 707 00:44:24,280 --> 00:44:27,062 It just has to know that argl is reversed, 708 00:44:27,062 --> 00:44:29,990 and it builds this frame, E,1. 709 00:44:29,990 --> 00:44:33,364 All right, so, let's assume that that's what make bindings returns, 710 00:44:33,364 --> 00:44:36,225 so it assigns to ENV this thing, E,1. 711 00:44:41,490 --> 00:44:46,890 All right, the next thing it says is restore continue. 712 00:44:46,890 --> 00:44:48,760 Remember what continue was here? 713 00:44:48,760 --> 00:44:52,240 It got put up in the last segment. 714 00:44:52,240 --> 00:44:54,020 Continue got stored. 715 00:44:54,020 --> 00:44:56,565 That was the original done, which said what are you going to do 716 00:44:56,565 --> 00:44:59,920 after you're done with this particular application? 717 00:44:59,920 --> 00:45:01,560 It was one of the very first things that happened 718 00:45:01,560 --> 00:45:03,920 when we evaluated the application. 719 00:45:03,920 --> 00:45:06,860 And now, finally, we're going to restore continue. 720 00:45:06,860 --> 00:45:09,290 Remember apply-dispatch's contract. 721 00:45:09,290 --> 00:45:12,035 It assumes that where it should go to next was on the stack, 722 00:45:12,035 --> 00:45:13,590 and there it was on the stack. 723 00:45:13,590 --> 00:45:19,940 Continue has done, and now we're going to go back to eval-dispatch. 724 00:45:19,940 --> 00:45:20,970 We're set up again. 725 00:45:20,970 --> 00:45:25,511 We have an expression, an environment, and a place to go to. 726 00:45:25,511 --> 00:45:29,940 We're not going to go through that because it's sort of the same expression. 727 00:45:35,167 --> 00:45:39,342 OK, but the thing, again, to notice is, at this point, 728 00:45:39,342 --> 00:45:44,830 we have reduced the original expression, F,X,Y, right? 729 00:45:44,830 --> 00:45:48,755 We've reduced evaluating F,X,Y in environment E,0 730 00:45:48,755 --> 00:45:52,670 to evaluate plus A, B in E,1. 731 00:45:52,670 --> 00:45:55,720 And notice, nothing's on the stack, right? 732 00:45:55,720 --> 00:45:56,830 It's a reduction. 733 00:45:56,830 --> 00:46:01,769 At this point, the machine does not contain, as part of its state, 734 00:46:01,769 --> 00:46:05,493 the fact that it's in the middle of evaluating some procedure called f, 735 00:46:05,493 --> 00:46:07,669 that's gone, right? 736 00:46:07,669 --> 00:46:13,072 There's no accumulated state, OK? 737 00:46:13,072 --> 00:46:14,370 Again, that's a very important idea. 738 00:46:14,370 --> 00:46:18,396 That's the meaning of, when we used to write in the substitution model, 739 00:46:18,396 --> 00:46:21,350 this expression reduces to that expression. 740 00:46:21,350 --> 00:46:22,660 And you don't have to remember anything. 741 00:46:22,660 --> 00:46:24,500 And here, you see the meaning of reduction. 742 00:46:24,500 --> 00:46:26,160 At this point, there is nothing on the stack. 743 00:46:31,590 --> 00:46:35,240 See, that has very important consequences. 744 00:46:35,240 --> 00:46:38,325 Let's go back and look at iterative factorial, 745 00:46:40,425 --> 00:46:45,130 all right? Remember, this was some sort of loop and doing iter. 746 00:46:45,130 --> 00:46:49,430 And we kept saying that's an iterative procedure, right? 747 00:46:49,430 --> 00:47:04,660 And what we wrote, remember, are things like, we said, 748 00:47:04,660 --> 00:47:12,360 fact-iter of 5. 749 00:47:12,360 --> 00:47:19,030 We wrote things like reduces to iter of 1, and 1, and 5, 750 00:47:19,030 --> 00:47:25,324 which reduces to iter of 1, and 2, and 5, 751 00:47:25,324 --> 00:47:27,079 and so on, and so on, and so on. 752 00:47:27,079 --> 00:47:28,175 And we kept saying well, look, 753 00:47:28,175 --> 00:47:31,720 you don't have to build up any storage to do that. 754 00:47:31,720 --> 00:47:35,040 And we waved our hands, and said in principle, there's no storage needed. 755 00:47:35,040 --> 00:47:36,170 Now, you see no storage needed. 756 00:47:36,170 --> 00:47:39,090 Each of these is a real reduction, right? 757 00:47:39,090 --> 00:47:42,825 As you walk through these expressions, 758 00:47:47,300 --> 00:47:51,370 As you walk through these expressions, what you'll see 759 00:47:51,370 --> 00:47:53,751 are these expressions on the stack 760 00:47:53,751 --> 00:47:56,425 in some particular environment, 761 00:47:56,425 --> 00:48:00,023 and then these expressions in the EXP register 762 00:48:00,023 --> 00:48:01,575 in some particular environment. 763 00:48:01,575 --> 00:48:04,365 And, at each point, there'll be no accumulated stuff on the stack 764 00:48:04,365 --> 00:48:06,100 because each one's a real reduction, OK? 765 00:48:09,135 --> 00:48:10,581 All right, so, for example, 766 00:48:10,581 --> 00:48:13,460 just to go through it in a little bit more care, 767 00:48:13,460 --> 00:48:17,108 if I start out with an expression that says something like, 768 00:48:17,825 --> 00:48:34,400 oh, say, fact-iter of 5 in some environment 769 00:48:41,900 --> 00:48:46,810 that will, at some point, create an environment 770 00:48:46,810 --> 00:48:48,549 in which n is down to 5. 771 00:48:51,340 --> 00:48:52,590 Let's call that-- 772 00:48:55,750 --> 00:49:02,757 And, at some point, the machine will reduce this whole thing 773 00:49:02,757 --> 00:49:07,673 to a thing that says that's really iter 774 00:49:07,673 --> 00:49:15,875 of 1, and 1, and n, evaluated in this environment, E,1 775 00:49:15,875 --> 00:49:17,160 with nothing on the stack. 776 00:49:17,160 --> 00:49:20,710 See, at this moment, the machine is not remembering 777 00:49:20,710 --> 00:49:22,500 that evaluating this expression, iter-- 778 00:49:25,000 --> 00:49:29,366 which is the loop-- is part of this thing called iterative factorial. 779 00:49:29,366 --> 00:49:30,590 It's not remembering that. 780 00:49:30,590 --> 00:49:33,170 It's just reducing the expression to that, right? 781 00:49:33,170 --> 00:49:38,050 If we look again at the body of iterative factorial, 782 00:49:38,050 --> 00:49:42,810 this expression has reduced to that expression. 783 00:49:42,810 --> 00:49:44,060 Oh, I shouldn't have the n there. 784 00:49:46,590 --> 00:49:53,340 It's a slightly different convention from the slide to the program, OK? 785 00:49:53,340 --> 00:49:56,124 And, then, what's the body of iter? 786 00:49:56,124 --> 00:49:58,625 Well, iter's going to be an if, 787 00:49:58,625 --> 00:50:00,060 and I won't go through the details of if. 788 00:50:00,060 --> 00:50:02,225 It'll evaluate the predicate. 789 00:50:02,225 --> 00:50:03,810 In this case, it'll be false. 790 00:50:03,810 --> 00:50:09,850 And this iter will now reduce to the expression 791 00:50:09,850 --> 00:50:21,620 iter of whatever it says, star, counter product, and-- 792 00:50:21,620 --> 00:50:22,650 what does it say-- 793 00:50:22,650 --> 00:50:32,975 plus counter 1 in some other environment, by this time, E,2, 794 00:50:32,975 --> 00:50:43,200 where E,2 will be set up having bindings for product and counter, right? 795 00:50:43,200 --> 00:50:45,140 And it'll reduce to that, right? 796 00:50:45,140 --> 00:50:47,156 It won't be remembering that it's part of 797 00:50:47,156 --> 00:50:49,340 something that it has to return to. 798 00:50:49,340 --> 00:50:53,053 And when iter calls iter again, it'll reduce to another thing that looks like this 799 00:50:53,053 --> 00:50:59,160 in some environment, E,3, which has new bindings for product and counter. 800 00:50:59,160 --> 00:51:08,450 So, if you're wondering, see, if you've always been queasy 801 00:51:08,450 --> 00:51:10,678 about how it is we've been saying those procedures 802 00:51:10,678 --> 00:51:12,458 that look syntactically recursive, 803 00:51:12,458 --> 00:51:18,100 are, in fact, iterative, run in constant space, 804 00:51:18,100 --> 00:51:19,750 well, I don't know if this makes you less queasy, 805 00:51:19,750 --> 00:51:21,230 but at least it shows you what's happening. 806 00:51:21,230 --> 00:51:22,830 There really isn't any buildup there. 807 00:51:25,910 --> 00:51:27,984 Now, you might ask well, is there buildup 808 00:51:27,984 --> 00:51:31,710 in principle in these environment frames? 809 00:51:31,710 --> 00:51:32,375 And the answer is yeah, 810 00:51:32,375 --> 00:51:32,443 you have to make these new environment frames, 811 00:51:32,443 --> 00:51:33,848 you have to make these new environment frames, 812 00:51:33,848 --> 00:51:36,440 but you don't have to hang onto them when you're done. 813 00:51:36,440 --> 00:51:40,720 They can be garbage collected, or the space can be reused automatically. 814 00:51:40,720 --> 00:51:43,250 But you see the control structure of the evaluator 815 00:51:43,250 --> 00:51:47,020 is really using this idea that you actually have a reduction, 816 00:51:47,020 --> 00:51:50,132 so these procedures really are iterative procedures. 817 00:51:50,132 --> 00:51:51,382 All right, let's stop for questions. 818 00:52:02,288 --> 00:52:03,538 All right, let's break. 819 00:52:48,770 --> 00:52:52,775 Let me contrast the iterative procedure 820 00:52:52,775 --> 00:52:56,000 just so you'll see where space does build up with a recursive procedure, 821 00:52:56,000 --> 00:52:58,030 so you can see the difference. 822 00:52:58,030 --> 00:53:02,880 Let's look at the evaluation of recursive factorial, all right? 823 00:53:02,880 --> 00:53:07,220 So, here's fact-recursive, or standard factorial definition. 824 00:53:07,220 --> 00:53:09,910 We said this one is still a recursive procedure, 825 00:53:09,910 --> 00:53:13,750 but this is actually a recursive process. 826 00:53:13,750 --> 00:53:16,566 And then, just to link it back to the way we started, 827 00:53:16,566 --> 00:53:20,530 we said oh, you can see that it's going to be recursive process 828 00:53:20,530 --> 00:53:22,122 by the substitution model 829 00:53:22,122 --> 00:53:30,450 because, if I say recursive factorial of 5, 830 00:53:30,450 --> 00:53:36,000 that turns into 5 times-- 831 00:53:36,000 --> 00:53:37,989 what is it, fact-rec, or record fact-- 832 00:53:42,620 --> 00:53:54,230 5 times recursive factorial of 4, which turns into 5 times 4 833 00:53:54,230 --> 00:54:08,090 times fact-rec of 3, which returns into 5 times 4 times 3 834 00:54:08,090 --> 00:54:15,240 times, and so on, right? 835 00:54:15,240 --> 00:54:18,100 The idea is there was this chain of stuff building up, 836 00:54:18,100 --> 00:54:21,520 which justified, in the substitution model, the fact that it's recursive. 837 00:54:21,520 --> 00:54:24,180 And now, let's actually see that chain of stuff build up 838 00:54:24,180 --> 00:54:27,465 and where it is in the machine, OK? 839 00:54:27,465 --> 00:54:30,230 All right, well, let's imagine we're going to start out again. 840 00:54:30,230 --> 00:54:41,451 We'll tell it to evaluate recursive factorial of 5 841 00:54:41,451 --> 00:54:45,000 in some environment, again, E,0 842 00:54:45,000 --> 00:54:49,275 where recursive factorial is defined, OK? 843 00:54:49,275 --> 00:54:52,490 Well, now we know what's eventually going to happen. 844 00:54:52,490 --> 00:54:53,925 This is going to come along, 845 00:54:53,925 --> 00:54:57,071 it'll evaluate those things, figure out it's a procedure, 846 00:54:57,071 --> 00:55:00,255 build somewhere over here an environment, E,1, 847 00:55:00,255 --> 00:55:06,725 which has n bound to 5, which hangs off of E,0, 848 00:55:07,800 --> 00:55:10,847 which would be, presumably, the definition environment 849 00:55:10,847 --> 00:55:12,847 of recursive factorial, OK? 850 00:55:14,610 --> 00:55:19,670 And, in this environment, it's going to go off and evaluate the body. 851 00:55:19,670 --> 00:55:27,000 So, again, the evaluation here will reduce to 852 00:55:27,000 --> 00:55:29,950 evaluating the body in E,1. 853 00:55:29,950 --> 00:55:33,530 That's going to look at an if, and I won't go through the details of if. 854 00:55:33,530 --> 00:55:34,880 It'll look at the predicate. 855 00:55:34,880 --> 00:55:37,840 It'll decide it eventually has to evaluate the alternative. 856 00:55:37,840 --> 00:55:41,300 So this whole thing, again, will reduce to 857 00:55:41,300 --> 00:55:47,139 the alternative of recursive factorial, the alternative clause, 858 00:55:47,139 --> 00:55:53,075 which says that this whole thing reduces to times n 859 00:55:53,075 --> 00:56:08,720 of recursive factorial of n minus 1 in the environment E,1, OK? 860 00:56:08,720 --> 00:56:11,200 So the original expression, now, is going to reduce to 861 00:56:11,200 --> 00:56:13,754 evaluating that expression, all right? 862 00:56:13,754 --> 00:56:16,280 Now we have an application. 863 00:56:16,280 --> 00:56:18,225 We did an application before. 864 00:56:18,225 --> 00:56:20,390 Remember what happens in an application? 865 00:56:20,390 --> 00:56:21,975 The first thing you do is you go off and you 866 00:56:21,975 --> 00:56:25,350 save the value of the continue register on the stack. 867 00:56:25,350 --> 00:56:27,365 So the stack here is going to have done in it. 868 00:56:29,980 --> 00:56:35,130 And then you're going to set up to evaluate the sub-parts, OK? 869 00:56:35,130 --> 00:56:37,200 So here we go off to evaluate the sub-parts. 870 00:56:39,375 --> 00:56:41,450 First thing we're going to do is evaluate the operator. 871 00:56:44,490 --> 00:56:47,250 What happens when we evaluate an operator? 872 00:56:47,250 --> 00:56:51,480 Well, we arrange things so that the operator ends up in the expression register. 873 00:56:51,480 --> 00:56:54,630 The environments in the ENV register continue someplace 874 00:56:54,630 --> 00:56:56,590 where we're going to go evaluate the arguments. 875 00:56:56,590 --> 00:56:59,520 And, on the stack, we've saved the original continue, 876 00:56:59,520 --> 00:57:01,720 which is where we wanted to be when we're all done. 877 00:57:01,720 --> 00:57:03,400 And then the things we needed 878 00:57:03,400 --> 00:57:05,807 when we're going to get done evaluating the operator, 879 00:57:05,807 --> 00:57:08,333 the things we'll need to evaluate the arguments, namely, 880 00:57:08,333 --> 00:57:14,000 the environment and those arguments, those unevaluated arguments, 881 00:57:14,000 --> 00:57:15,620 so there they are sitting on the stack. 882 00:57:15,620 --> 00:57:18,370 And we're about to go off to evaluate the operator. 883 00:57:23,130 --> 00:57:26,920 Well, when we return from this particular call-- 884 00:57:26,920 --> 00:57:29,380 so we're about to call eval-dispatch here-- 885 00:57:29,380 --> 00:57:32,730 when we return from this call, the value of that operator, 886 00:57:32,730 --> 00:57:36,275 which, in this case, is going to be the primitive multiplier procedure, 887 00:57:36,275 --> 00:57:42,800 will end up in the FUN register, all right? 888 00:57:42,800 --> 00:57:44,530 We're going to evaluate some arguments. 889 00:57:44,530 --> 00:57:47,730 They will evaluate n here. 890 00:57:47,730 --> 00:57:50,250 That'll give us 5, in this case. 891 00:57:50,250 --> 00:57:52,900 We're going to put that in the argl register, 892 00:57:52,900 --> 00:57:57,460 and then we'll go off to evaluate the second operand. 893 00:57:57,460 --> 00:58:00,365 So, at the point where we go off to evaluate the second operand-- 894 00:58:00,365 --> 00:58:03,633 and I'll skip details like computing, and minus 1, and all of that-- 895 00:58:03,633 --> 00:58:06,385 but, when we go off to evaluate the second operand, 896 00:58:06,385 --> 00:58:10,737 that will eventually reduce to another call to fact-recursive. 897 00:58:12,000 --> 00:58:16,525 And, what we've got on the stack here is 898 00:58:16,525 --> 00:58:19,942 the operator from that combination that we're going to use it in 899 00:58:19,942 --> 00:58:23,790 and the other argument, OK? 900 00:58:23,790 --> 00:58:30,200 So, now, we're set up for another call to recursive factorial. 901 00:58:30,200 --> 00:58:31,438 And, when we're done with this one, 902 00:58:31,438 --> 00:58:33,935 we're going to go to accumulate the last arg. 903 00:58:33,935 --> 00:58:35,200 And remember what that'll do? 904 00:58:35,200 --> 00:58:36,425 That'll say oh, 905 00:58:36,425 --> 00:58:36,450 whatever the result of this has to get combined with that, 906 00:58:36,450 --> 00:58:39,281 whatever the result of this has to get combined with that, 907 00:58:39,281 --> 00:58:41,690 and we're going to multiply them. 908 00:58:41,690 --> 00:58:45,720 But, notice now, we're at another recursive factorial. 909 00:58:45,720 --> 00:58:49,325 We're about to call eval-dispatch again, 910 00:58:49,325 --> 00:58:53,700 except we haven't really reduced it because there's stuff on the stack now. 911 00:58:53,700 --> 00:58:55,244 The stuff on the stack says oh, when you get back, 912 00:58:55,244 --> 00:58:58,430 you'd better multiply it by the 5 you had hanging there. 913 00:58:58,430 --> 00:59:07,125 So, when we go off to make another call, 914 00:59:07,125 --> 00:59:09,300 we evaluate the n minus 1. 915 00:59:09,300 --> 00:59:11,256 That gives us another environment 916 00:59:11,256 --> 00:59:14,600 in which the new n's going to be down to 4. 917 00:59:14,600 --> 00:59:18,930 And we're about to call eval-dispatch again, right? 918 00:59:18,930 --> 00:59:21,350 We get another call. 919 00:59:21,350 --> 00:59:26,040 That 4 is going to end up in the same situation. 920 00:59:26,040 --> 00:59:30,020 We'll end up with another call to fact-recursive n. 921 00:59:30,020 --> 00:59:32,684 And sitting on the stack will be the stuff from the original one 922 00:59:32,684 --> 00:59:35,360 and, now, the subsidiary one we're doing. 923 00:59:35,360 --> 00:59:36,910 And both of them are waiting for the same thing. 924 00:59:36,910 --> 00:59:40,600 They're going to go to accumulate a last argument. 925 00:59:40,600 --> 00:59:43,258 And then, of course, when we go to the fourth call, 926 00:59:43,258 --> 00:59:45,640 the same thing happens, right? 927 00:59:45,640 --> 00:59:47,300 And this goes on, and on, and on. 928 00:59:47,300 --> 00:59:50,075 And what you see here on the stack, 929 00:59:50,107 --> 00:59:52,225 exactly what's sitting here on the stack, 930 00:59:52,225 --> 00:59:54,960 the thing that says times and 5. 931 00:59:54,960 --> 01:00:00,470 And what you're going to do with that is accumulate that into a last argument. 932 01:00:00,470 --> 01:00:02,760 That's exactly this, right? 933 01:00:02,760 --> 01:00:05,650 This is exactly where that stuff is hanging. 934 01:00:05,650 --> 01:00:11,659 Effectively, the operator you're going to apply, 935 01:00:11,659 --> 01:00:13,625 the other argument 936 01:00:13,672 --> 01:00:15,300 that it's got to be multiplied by when you get back 937 01:00:15,300 --> 01:00:16,879 and the parentheses, 938 01:00:16,879 --> 01:00:19,620 which says yeah, what you wanted to do was accumulate them. 939 01:00:19,620 --> 01:00:22,560 So, you see, the substitution model is not such a lie. 940 01:00:22,560 --> 01:00:27,198 That really is, in some sense, what's sitting right on the stack. 941 01:00:27,198 --> 01:00:29,046 OK. 942 01:00:29,046 --> 01:00:33,260 All right, so that, in some sense, should explain for you, 943 01:00:33,260 --> 01:00:36,596 or at least convince you, that, 944 01:00:36,596 --> 01:00:39,870 somehow, this evaluator is managing 945 01:00:39,870 --> 01:00:42,959 to take these procedures and execute some of them iteratively 946 01:00:42,959 --> 01:00:46,410 and some of them recursively, even though, 947 01:00:46,410 --> 01:00:49,215 as syntactically, they look like recursive procedures. 948 01:00:49,215 --> 01:00:50,660 How's it managing to do that? 949 01:00:50,660 --> 01:00:53,725 Well, the basic reason it's managing to do that 950 01:00:53,725 --> 01:01:01,090 is the evaluator is set up to save only what it needs later. 951 01:01:01,090 --> 01:01:04,670 So, for example, at the point where you've reduced 952 01:01:04,670 --> 01:01:07,683 evaluating an expression and an environment 953 01:01:07,683 --> 01:01:10,525 to applying a procedure to some arguments, 954 01:01:10,525 --> 01:01:13,375 it doesn't need that original environment anymore 955 01:01:13,375 --> 01:01:17,675 because any environment stuff will be packaged inside the procedures 956 01:01:17,675 --> 01:01:20,160 where the application's going to happen. 957 01:01:20,160 --> 01:01:23,656 All right, similarly, when you're going along evaluating an argument list, 958 01:01:23,656 --> 01:01:25,910 when you've finished evaluating the list, 959 01:01:25,910 --> 01:01:28,200 when you're finished evaluating the last argument, 960 01:01:28,200 --> 01:01:31,500 you don't need that argument list any more, right? 961 01:01:31,500 --> 01:01:32,941 And you don't need the environment where 962 01:01:32,941 --> 01:01:36,690 those arguments would be evaluated, OK? 963 01:01:36,690 --> 01:01:40,890 So the basic reason that this interpreter is being so smart 964 01:01:40,890 --> 01:01:43,050 is that it's not being smart at all, it's being stupid. 965 01:01:43,050 --> 01:01:46,010 It's just saying I'm only going to save what I really need. 966 01:01:48,700 --> 01:01:51,000 Well, let me show you here. 967 01:01:54,880 --> 01:01:58,310 Here's the actual thing that's making a tail recursive. 968 01:01:58,310 --> 01:02:00,135 Remember, it's the restore of continue. 969 01:02:00,135 --> 01:02:08,800 It's saying when I go off to evaluate the procedure body, 970 01:02:08,800 --> 01:02:11,252 I should tell eval to come back to 971 01:02:11,252 --> 01:02:15,170 the place where that original evaluation was supposed to come back to. 972 01:02:15,170 --> 01:02:17,700 So, in some sense, you want to say what's the actual line 973 01:02:17,700 --> 01:02:18,770 that makes a tail recursive? 974 01:02:18,770 --> 01:02:19,920 It's that one. 975 01:02:19,920 --> 01:02:23,680 If I wanted to build a non-tail recursive evaluator, 976 01:02:23,680 --> 01:02:27,124 for some strange reason, all I would need to do is, 977 01:02:27,124 --> 01:02:32,750 instead of restoring continue at this point, I'd set up a label down here 978 01:02:32,750 --> 01:02:37,455 called, "Where to come back after you've finished applying the procedure." 979 01:02:37,455 --> 01:02:39,920 Instead, I'd set continue to that. 980 01:02:39,920 --> 01:02:41,299 I'd go to eval-dispatch, 981 01:02:41,299 --> 01:02:43,790 and then eval-dispatch would come back here. 982 01:02:43,790 --> 01:02:47,920 At that point, I would restore continue and go to the original one. 983 01:02:47,920 --> 01:02:51,075 So here, the only consequence of that 984 01:02:51,075 --> 01:02:52,840 would be to make it non-tail recursive. 985 01:02:52,840 --> 01:02:54,629 It would give you exactly the same answers, 986 01:02:54,629 --> 01:02:56,656 except if you did that iterative factorial 987 01:02:56,656 --> 01:02:59,875 and all those iterative procedures, it would execute recursively. 988 01:03:02,900 --> 01:03:05,760 Well, I lied to you a little bit, but just a little bit, 989 01:03:05,760 --> 01:03:08,550 because I showed you a slightly over-simplified evaluator 990 01:03:08,550 --> 01:03:11,225 where it assumes that each procedure -- 991 01:03:11,225 --> 01:03:13,890 each procedure body has only one expression. 992 01:03:13,890 --> 01:03:17,870 Remember, in general, a procedure has a sequence of expressions in it. 993 01:03:17,870 --> 01:03:20,490 So there's nothing really conceptually new. 994 01:03:20,490 --> 01:03:22,725 Let me just show you the actual evaluator 995 01:03:22,725 --> 01:03:24,730 that handles sequences of expressions. 996 01:03:28,470 --> 01:03:32,075 This is compound-apply now, and the only difference from the old one 997 01:03:32,075 --> 01:03:35,980 is that, instead of going off to eval directly, 998 01:03:35,980 --> 01:03:38,039 it takes the whole body of the procedure, 999 01:03:38,039 --> 01:03:40,151 which, in this case, is a sequence of expressions, 1000 01:03:40,151 --> 01:03:42,325 and goes off to eval-sequence. 1001 01:03:42,325 --> 01:03:47,907 And eval-sequence is a little loop that, basically, 1002 01:03:47,907 --> 01:03:49,980 does these evaluations one at a time. 1003 01:03:52,630 --> 01:03:53,900 So it does an evaluation. 1004 01:03:53,900 --> 01:03:58,440 Says oh, when I come back, I'd better come back here to do the next one. 1005 01:03:58,440 --> 01:04:01,038 And, when I'm all done, when I want to get the last expression, 1006 01:04:01,038 --> 01:04:06,410 I just restore my continue and go off to eval-dispatch. 1007 01:04:06,410 --> 01:04:08,200 And, again, if you wanted for some reason to 1008 01:04:08,200 --> 01:04:10,492 break tail recursion in this evaluator, 1009 01:04:10,492 --> 01:04:14,900 all you need to do is not handle the last expression, especially. 1010 01:04:14,900 --> 01:04:17,247 Just say, after you've done the last expression, 1011 01:04:17,247 --> 01:04:21,900 come back to some other place after which you restore continue. 1012 01:04:21,900 --> 01:04:26,550 And, for some reason, a lot of LISP evaluators tended to work that way. 1013 01:04:26,550 --> 01:04:28,545 And the only consequence of that is that 1014 01:04:28,545 --> 01:04:31,614 iterative procedures built up stack. 1015 01:04:31,614 --> 01:04:35,670 And it's not clear why that happened. 1016 01:04:35,670 --> 01:04:36,210 All right. 1017 01:04:36,210 --> 01:04:38,095 Well, let me just sort of summarize, 1018 01:04:38,095 --> 01:04:41,120 since this is a lot of details in a big program. 1019 01:04:41,120 --> 01:04:44,040 But the main point is that it's no different, 1020 01:04:44,040 --> 01:04:47,060 conceptually, from translating any other program. 1021 01:04:47,060 --> 01:04:50,156 And the main idea is that we have this universal evaluator program, 1022 01:04:50,156 --> 01:04:51,870 the meta-circular evaluator. 1023 01:04:51,870 --> 01:04:54,560 If we translate that into LISP, then we have all of LISP. 1024 01:04:54,560 --> 01:04:57,980 And that's all we did, OK? 1025 01:04:57,980 --> 01:04:59,680 The second point is that the magic's gone away. 1026 01:04:59,680 --> 01:05:01,970 There should be no more magic in this whole system, right? 1027 01:05:01,970 --> 01:05:08,720 In principle, it should all be very clear except, maybe, for 1028 01:05:08,720 --> 01:05:10,940 how list structured memory works, and 1029 01:05:10,940 --> 01:05:12,640 we'll see that later. 1030 01:05:12,640 --> 01:05:15,450 But that's not very hard. 1031 01:05:15,450 --> 01:05:18,720 The third point is that all this tail recursion came from 1032 01:05:18,720 --> 01:05:22,550 the discipline of eval being very careful 1033 01:05:22,550 --> 01:05:25,870 to save only what it needs next time. 1034 01:05:25,870 --> 01:05:28,180 It's not some arbitrary thing where we're saying well, 1035 01:05:28,180 --> 01:05:29,864 whenever we call a sub-routine, 1036 01:05:29,864 --> 01:05:33,940 we'll save all the registers in the world and come back, right? 1037 01:05:33,940 --> 01:05:37,150 See, sometimes it pays to really worry about efficiency. 1038 01:05:37,150 --> 01:05:40,459 And, when you're down in the guts of your evaluator machine, 1039 01:05:40,459 --> 01:05:42,560 it really pays to think about things like that 1040 01:05:42,560 --> 01:05:45,230 because it makes big consequences. 1041 01:05:45,230 --> 01:05:47,842 Well, I hope what this has done 1042 01:05:47,842 --> 01:05:52,560 is really made the evaluator seem concrete, right? 1043 01:05:52,560 --> 01:05:56,631 I hope you really believe that somebody could hold a LISP 1044 01:05:56,631 --> 01:05:59,075 LISP evaluator in the palm of their hand. 1045 01:05:59,075 --> 01:06:02,540 Maybe to help you believe that, here's a LISP evaluator 1046 01:06:02,540 --> 01:06:06,160 that I'm holding the palm of my hand, right? 1047 01:06:06,160 --> 01:06:10,738 And this is a chip which is actually 1048 01:06:10,738 --> 01:06:13,700 quite a bit more complicated than the evaluator I showed you. 1049 01:06:17,815 --> 01:06:19,200 Maybe, here's a better picture of it. 1050 01:06:22,070 --> 01:06:24,730 What there is, is you can see the same overall structure. 1051 01:06:24,730 --> 01:06:26,940 This is a register array. 1052 01:06:26,940 --> 01:06:27,910 These are the data paths. 1053 01:06:27,910 --> 01:06:29,800 Here's a finite state controller. 1054 01:06:29,800 --> 01:06:32,810 And again, finite state, that's all there is. 1055 01:06:32,810 --> 01:06:34,160 And somewhere there's external memory 1056 01:06:34,160 --> 01:06:35,750 that'll worry about things. 1057 01:06:35,750 --> 01:06:37,552 And this particular one is very complicated 1058 01:06:37,552 --> 01:06:39,664 because it's trying to run LISP fast. 1059 01:06:39,664 --> 01:06:42,976 And it has some very, very fast parallel operations in there 1060 01:06:42,976 --> 01:06:46,650 like, if you want to index into an array, 1061 01:06:46,650 --> 01:06:50,362 simultaneously check that the index is an integer, 1062 01:06:50,362 --> 01:06:52,863 check that it doesn't exceed the array bands, 1063 01:06:52,863 --> 01:06:57,120 and go off and do the memory access, and do all those things simultaneously. 1064 01:06:57,120 --> 01:06:58,970 And then, later, if they're all OK, actually 1065 01:06:58,970 --> 01:07:00,420 get the value there. 1066 01:07:00,420 --> 01:07:02,327 So there are a lot of complicated operations 1067 01:07:02,327 --> 01:07:06,550 in these data paths for making LISP run in parallel. 1068 01:07:06,550 --> 01:07:10,640 It's a completely non-risk philosophy of evaluating LISP. 1069 01:07:10,640 --> 01:07:13,740 And then, this microcode is pretty complicated. 1070 01:07:13,740 --> 01:07:17,740 Let's see, there's what? 1071 01:07:17,740 --> 01:07:24,079 There's about 389 instructions of 220-bit microcode sitting here 1072 01:07:24,079 --> 01:07:27,940 because these are very complicated data paths. 1073 01:07:27,940 --> 01:07:33,580 And the whole thing has about 89,000 transistors, OK? 1074 01:07:33,580 --> 01:07:33,840 OK. 1075 01:07:33,840 --> 01:07:37,970 Well, I hope that that takes away a lot of the mystery. 1076 01:07:37,970 --> 01:07:39,240 Maybe somebody wants to look at this. 1077 01:07:42,048 --> 01:07:43,298 Yeah. 1078 01:07:46,260 --> 01:07:46,480 OK. 1079 01:07:46,480 --> 01:07:47,730 Let's stop. 1080 01:07:55,890 --> 01:07:57,815 Questions? 1081 01:07:57,815 --> 01:08:00,420 AUDIENCE: OK, now, it sounds like what you're saying is that, 1082 01:08:00,420 --> 01:08:04,600 with the restore continue put in the proper place, that 1083 01:08:04,600 --> 01:08:09,422 procedures that would invoke a recursive process 1084 01:08:09,422 --> 01:08:12,675 now invoke an integer process 1085 01:08:12,675 --> 01:08:15,165 just by the way that the eval signature is? 1086 01:08:15,165 --> 01:08:17,549 PROFESSOR: I think the way I'd prefer to put it is that, 1087 01:08:17,549 --> 01:08:20,557 with restore continue put in the wrong place, 1088 01:08:20,557 --> 01:08:25,880 you can cause any syntactically-looking recursive procedure, in fact, 1089 01:08:25,880 --> 01:08:28,029 to build up stack as it runs. 1090 01:08:28,029 --> 01:08:33,150 But there's no reason for that, 1091 01:08:33,150 --> 01:08:35,660 so you might want to play around with it. 1092 01:08:35,660 --> 01:08:38,185 You can just switch around two or three instructions 1093 01:08:38,185 --> 01:08:41,129 in the way compound-apply comes back, 1094 01:08:41,129 --> 01:08:45,060 and you'll get something which isn't tail recursive. 1095 01:08:45,060 --> 01:08:47,670 But the thing I wanted to emphasize is there's no magic. 1096 01:08:47,670 --> 01:08:52,455 It's not as if there's some very clever pre-processing program 1097 01:08:52,455 --> 01:08:57,425 that's looking at this procedure, factorial iter, and say oh, gee, 1098 01:08:57,425 --> 01:09:01,060 I really notice that I don't have to push stack in order to do this. 1099 01:09:01,060 --> 01:09:03,760 Some people think that that's what's going on. 1100 01:09:03,760 --> 01:09:05,383 It's something much, much more dumb than that, 1101 01:09:05,383 --> 01:09:08,880 it's this one place you're putting the restore instruction. 1102 01:09:08,880 --> 01:09:10,353 It's just automatic. 1103 01:09:10,353 --> 01:09:11,603 AUDIENCE: OK. 1104 01:09:14,217 --> 01:09:17,850 AUDIENCE: But that's not affecting the time complexity is it? 1105 01:09:17,850 --> 01:09:18,275 PROFESSOR: No. 1106 01:09:18,275 --> 01:09:21,810 AUDIENCE: It's just that it's handling it recursively 1107 01:09:21,810 --> 01:09:23,020 instead of iteratively. 1108 01:09:23,020 --> 01:09:27,179 But, in terms of the order of time it takes to finish the operation, 1109 01:09:27,179 --> 01:09:29,220 it's the same one way or the other, right? 1110 01:09:29,220 --> 01:09:29,920 PROFESSOR: Yes. 1111 01:09:29,920 --> 01:09:32,609 Tail recursion is not going to change the time complexity of anything 1112 01:09:32,609 --> 01:09:36,029 because, in some sense, it's the same algorithm that's going on. 1113 01:09:36,029 --> 01:09:41,210 What it's doing is really making this thing run as an iteration, right? 1114 01:09:41,210 --> 01:09:44,750 Not going to run out of memory counting up to a giant number 1115 01:09:44,750 --> 01:09:47,683 simply because the stack would get pushed. 1116 01:09:47,683 --> 01:09:51,640 See, the thing you really have to believe is that, when we write-- 1117 01:09:51,640 --> 01:09:53,781 see, we've been writing all these things called iterations, 1118 01:09:53,781 --> 01:09:57,990 infinite loops, define loop to be called loop. 1119 01:10:00,325 --> 01:10:03,650 That's is as much an iteration 1120 01:10:03,650 --> 01:10:07,630 as if we wrote do forever loop, right? 1121 01:10:07,630 --> 01:10:09,280 It's just syntactic sugar as the difference. 1122 01:10:09,280 --> 01:10:14,730 These things are real, honest to god, iterations, right? 1123 01:10:14,730 --> 01:10:16,681 They don't change the time complexity, but they 1124 01:10:16,681 --> 01:10:18,535 turn them into real iterations. 1125 01:10:21,686 --> 01:10:23,800 All right, thank you. ================================================ FILE: Sub/lec10a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 10A: Compilation [MUSIC PLAYING] PROFESSOR: Last time, we took a look at an explicit control evaluator for Lisp, and that bridged the gap between all these high-level languages like Lisp and the query language and all of that stuff, bridged the gap between that and a conve ntional register machine. And in fact, you can think of the explicit control evaluator either as, say, the code for a Lisp interpreter if you wanted to implement it in the assembly language of some conventional register transfer machine, or, if you like, you can think of it as the microcode of some machine that's going to be specially designed to run Lisp. In either case, what we're doing is we're taking a machine that speaks some low-level language, and we're raising the machine to a high- level language like Lisp by writing an interpreter. So for instance, here, conceptually, is a special purpose machine for computing factorials. It takes in five and puts out 120. And what this special purpose machine is is actually a Lisp interpreter that's configured itself to run factorials, because you fit into it a description of the factorial machine. So that's what an interpreter is. It configures itself to emulate a machine whose description you read in. Now, inside the Lisp interpreter, what's that? Well, that might be your general register language interpreter that configures itself to behave like a Lisp interpreter, because you put in a whole bunch of instructions in register language. This is the explicit control evaluator. And then it also has some sort of library, a library of primitive operators and Lisp operations and all sorts of things like that. That's the general strategy of interpretation. And the point is, what we're doing is we're writing an interpreter to raise the machine to the level of the programs that we want to write. Well, there's another strategy, a different one, which is compilation. Compilation's a little bit different. Here --here we might have produced a special purpose machine for, for computing factorials, starting with some sort of m achine that speaks register language, except we're going to do a different strategy. We take our factorial program. We use that as the source code into a compiler. What the compiler will do is translate that factorial program into some register machine language. And this will now be not the explicit control evaluator for Lisp, this will be some register language for computing factorials. So this is the translation of that. That will go into some sort of loader which will combine this code with code selected from the library to do things like primitive multiplication. And then we'll produce a load module which configures the register language machine to be a special purpose factorial machine. So that's a, that's a different strategy. In interpretation, we're raising the machine to the level of our language, like Lisp. In compilation, we're taking our program and lowering it to the language that's spoken by the machine. Well, how do these two strategies compare? The compiler can produce code that will execute more efficiently. The essential reason for that is that if you think about the register operations that are running, the interpreter has to produce register operations which, in principle, are going to be general enough to execute any Lisp procedure.Whereas the compiler only has to worry about producing a special bunch of register operations for, for doing the particular Lisp procedure that you've compiled. Or another way to say that is that the interpreter is a general purpose simulator, that when you read in a Lisp procedure, then those can simulate the program described by that, by that procedure. So the interpreter is worrying about making a general purpose simulator, whereas the compiler, in effect, is configuring the thing to be the machine tha t the interpreter would have been simulating. So the compiler can be faster. On the other hand, the interpreter is a nicer environment for debugging. And the reason for that is that we've got the source code actually there. We're interpreting it. That's what we're working with. And we also have the library around. See, the interpreter--the library sitting there is part of the interpreter. The compiler only pulls out from the library what it needs to run the program. So if you're in the middle of debugging, and you might like to write a little extra program to examine some run time data structure or to produce some computation that you didn't think of when you wrote the program, the interpreter can do that perfectly well, whereas the compiler can't. So there are sort of dual, dual advantages. The compiler will produce code that executes faster. The interpreter is a better environment for debugging. And most Lisp systems end up having both, end up being configured so you have an interpreter that you use when you're developing your code. Then you can speed it up by compiling. And very often, you can arrange that compiled code and interpreted code can call each other. We'll see how to do that. That's not hard. In fact, the way we'll-- in the compiler we're going to make, the way we'll arrange for compiled coding and interpreted code to call, to call each other, is that we'll have the compiler use exactly the same register conventions as the interpreter. Well, the idea of a compiler is very much like the idea of an interpreter or evaluator. It's the same thing. See, the evaluator walks over the code and performs some register operations. That's what we did yesterday. Well, the compiler essentially would like to walk over the code and produce the register operations that the evaluator would have done were it evaluating the thing. And that gives us a model for how to implement a zeroth-order compiler, a very bad compiler but essentially a compiler. A model for doing that is you just take the evaluator, you run it over the code, but instead of executing the actual operations, you just save them away. And that's your compiled code. So let me give you an example of that. Suppose we're going to compile--suppose we want to compile the expression f of x. So let's assume that we've got f of x in the x register and something in the environment register. And now imagine starting up the evaluator. Well, it looks at the expression and it sees that it's an application. And it branches to a place in the evaluator code we saw called ev-application. And then it begins. It stores away the operands and unev, and then it's going to put the operator in exp, and it's going to go recursively evaluate it. That's the process that we walk through. And if you start looking at the code, you start seeing some register operations. You see assign to unev the operands, assign to exp the operator, save the environment, generate that, and so on. Well, if we look on the overhead here, we can see, we can see those operations starting to be produced. Here's sort of the first real operation that the evaluator would have done. It pulls the operands out of the exp register and assigns it to unev. And then it assigns something to the expression register, and it saves continue, and it saves env. And all I'm doing here is writing down the register assignments that the evaluator would have done in executing that code. And can zoom out a little bit. Altogether, there are about 19 operations there. And this is the--this will be the piece of code up until the point where the evaluator branches off to apply-dispatch. And in fact, in this compiler, we're not going to worry about apply-dispatch at all. We're going to have everything--we're going to have both interpreted code and compiled code. Always evaluate procedures, always apply procedures by going to apply-dispatch. That will easily allow interpreted code and compiled code to call each other. Well, in principle, that's all we need to do. You just run the evaluator. So the compiler's a lot like the evaluator. You run it, except it stashes away these operations instead of actually executing them. Well, that's not, that's not quite true. There's only one little lie in that. What you have to worry about is if you have a, a predicate. If you have some kind of test you want to do, obviously, at the point when you're compiling it, you don't know which branch of these--of a conditional like this you're going to do. So you can't say which one the evaluator would have done. So all you do there is very simple. You compile both branches. So you compile a structure that looks like this. That'll compile into something that says, the code, the code for P. And it puts its results in, say, the val register. So you walk the interpreter over the predicate and make sure that the result would go into the val register. And then you compile an instruction that says, branch if, if val is true, to a place we'll call label one. Then we, we will put the code for B to walk the interpreter--walk the interpreter over B. And then go to put in an instruction that says, go to the next thing, whatever, whatever was supposed to happen after this thing was done. You put in that instruction. And here you put label one. And here you put the code for A. And you put go to next thing. So that's how you treat a conditional. You generate a little block like that. And other than that, this zeroth-order compiler is the same as the evaluator. It's just stashing away the instructions instead of executing them. That seems pretty simple, but we've gained something by that. See, already that's going to be more efficient than the evaluator. Because, if you watch the evaluator run, it's not only generating the register operations we wrote down, it's also doing things to decide which ones to generate. So the very first thing it does, say, here for instance, is go do some tests and decide that this is an application, and then branch off to the place that, that handles applications. In other words, what the evaluator's doing is simultaneously analyzing the code to see what to do, and running these operations. And when you-- if you run the evaluator a million times, that analysis phase happens a million times, whereas in the compiler, it's happened once, and then you just have the register operations themselves. Ok, that's a, a zeroth-order compiler, but it is a wretched, wretched compiler. It's really dumb. Let's--let's go back and, and look at this overhead. So look at look at some of the operations this thing is doing. We're supposedly looking at the operations and interpreting f of x. Now, look here what it's doing. For example, here it assigns to exp the operator in fetch of exp. But see, there's no reason to do that, because this is-- the compiler knows that the operator, fetch of exp, is f right here. So there's no reason why this instruction should say that. It should say, we'll assign to exp, f. Or in fact, you don't need exp at all. There's no reason it should have exp at all. What, what did exp get used for? Well, if we come down here, we're going to assign to val, look up the stuff in exp in the environment. So what we really should do is get rid of the exp register altogether, and just change this instruction to say, assign to val, look up the variable value of the symbol f in the environment. Similarly, back up here, we don't need unev at all, because we know what the operands of fetch of exp are for this piece of code. It's the, it's the list x. So in some sense, you don't want unev and exp at all. See, what they really are in some sense, those aren't registers of the actual machine that's supposed to run. Those are registers that have to do with arranging the thing that can simulate that machine. So they're always going to hold expressions which, from the compiler's point of view, are just constants, so can be put right into the code. So you can forget about all the operations worrying about exp and unev and just use those constants. Similarly, again, if we go, go back and look here, there are things like assign to continue eval-args. Now, that has nothing to do with anything. That was just the evaluator keeping track of where it should go next, to evaluate the arguments in some, in some application. But of course, that's irrelevant to the compiler, because you-- the analysis phase will have already done that. So this is completely irrelevant. So a lot of these, these assignments to continue have not to do where the running machine is supposed to continue in keeping track of its state. It has to, to do with where the evaluator analysis should continue, and those are completely irrelevant. So we can get rid of them. Ok, well, if we, if we simply do that, make those kinds of optimizations, get rid, get rid of worrying about exp and unev, and get rid of these irrelevant register assignments to continue, then we can take this literal code, these sort of 19 instructions that the, that the evaluator would have done, and then replace them. Let's look at the, at theslide. Replace them by--we get rid of about half of them. And again, this is just sort of filtering what the evaluator would have done by getting rid of the irrelevant stuff. And you see, for instance, here the--where the evaluator said, assign val, look up variable value, fetch of exp, here we have put in the constant f. Here we've put in the constant x. So there's a, there's a little better compiler. It's still pretty dumb. It's still doing a lot of dumb things. Again, if we go look at the slide again, look at the very beginning here, we see a save the environment, assign something to the val register, and restore the environment. Where'd that come from? That came from the evaluator back here saying, oh, I'm in the middle of evaluating an application. So I'm going to recursively call eval dispatch. So I'd better save the thing I'm going to need later, which is the environment. This was the result of recursively calling eval dispatch. It was evaluating the symbol f in that case. Then it came back from eval dispatch, restored the environment. But in fact, the actual thing it ended up doing in the evaluation is not going to hurt the environment at all. So there's no reason to be saving the environment and restoring the environment here. Similarly, here I'm saving the argument list. That's a piece of the argument evaluation loop, saving the argument list, and here you restore it. But the actual thing that you ended up doing didn't trash the argument list. So there was no reason to save it. So another way to say, another way to say that is that the, the evaluator has to be maximally pessimistic, because as far from its point of view it's just going off to evaluate something. So it better save what it's going to need later. But once you've done the analysis, the compiler is in a position to say, well, what actually did I need to save? And doesn't need to do any-- it doesn't need to be as careful as the evaluator, because it knows what it actually needs. Well, in any case, if we do that and eliminate all those redundant saves and restores, then we can get it down to this. And you see there are actually only three instructions that we actually need, down from the initial 11 or so, or the initial 20 or so in the original one. And that's just saying, of those register operations, which ones did we actually need? Let me just sort of summarize that in another way, just to show you in a little better picture. Here's a picture of starting-- This is looking at all the saves and restores. So here's the expression, f of x, and then this traces through, on the bottom here, the various places in the evaluator that were passed when the evaluation happened. And then here, here you see arrows. Arrow down means register saved. So the first thing that happened is the environment got saved. And over here, the environment got restored. And these-- so there are all the pairs of stack operations. Now, if you go ahead and say, well, let's remember that we don't--that unev, for instance, is a completely useless register. And if we use the constant structure of the code, well, we don't need, we don't need to save unev. We don't need unev at all. And then, depending on how we set up the discipline of the--of calling other things that apply, we may or may not need to save continue. That's the first step I did. And then we can look and see what's actually, what's actually needed. See, we don't-- didn't really need to save env or cross-evaluating f, because it wouldn't, it wouldn't trash it. So if we take advantage of that, and see the evaluation of f here, doesn't really need to worry about, about hurting env. And similarly, the evaluation of x here, when the evaluator did that it said, oh, I'd better preserve the function register around that, because I might need it later. And I better preserve the argument list. Whereas the compiler is now in a position to know, well, we didn't really need to save-- to do those saves and restores. So in fact, all of the stack operations done by the evaluator turned out to be unnecessary or overly pessimistic. And the compiler is in a position to know that. Well that's the basic idea. We take the evaluator, we eliminate the things that you don't need, that in some sense have nothing to do with the compiler at all, just the evaluator, and then you see which stack operations are unnecessary. That's the basic structure of the compiler that's described in the book. Let me just show you how that examples a little bit too simple. To see how you, how you actually save a lot, let's look at a little bit mor e complicated expression. F of G of X and 1. And I'm not going to go through all the code. There's a, there's a fair pile of it. I think there are, there are something like 16 pairs of register saves and restores as the evaluator walks through that. Here's a diagram of them. Let's see. You see what's going on. You start out by--the evaluator says, oh, I'm about to do an application. I'll preserve the environment. I'll restore it here. Then I'm about to do the first operand. Here it recursively goes to the evaluator. The evaluator says, oh, this is an application, I'll save the environment, do the operator of that combination, restore it here. This save--this restore matches that save. And so on. There's unev here, which turns out to be completely unnecessary, continues getting bumped around here. The function register is getting, getting saved across the first operands, across the operands. All sorts of things are going on. But if you say, well, what of those really were the business of the compiler as opposed to the evaluator, you get rid of a whole bunch. And then on top of that, if you say things like, the evaluation of F doesn't hurt the environment register, or simply looking up the symbol X, you don't have to protect the function register against that. So you come down to just a couple of, a couple of pairs here. And still, you can do a little better. Look what's going on here with the environment register. The environment register comes along and says, oh, here's a combination. This evaluator, by the way, doesn't know anything about G. So here it says, so it says, I'd better save the environment register, because evaluating G might be some arbitrary piece of code that would trash it, and I'm going to need it later, after this argument, for doing the second argument. So that's why this one didn't go away, because the compiler made no assumptions about what G would do. On the other hand, if you look at what the second argument is, that's just looking up one. That doesn't need this environment register. So there's no reason to save it. So in fact, you can get rid of that one, too. And from this whole pile of, of register operations, if you simply do a little bit of reasoning like that, you get down to, I think, just two pairs of saves and restores. And those, in fact, could go away further if you, if you knew something about G. So again, the general idea is that the reason the compiler can be better is that the interpreter doesn't know what it's about to encounter. It has to be maximally pessimistic in saving things to protect itself. The compiler only has to deal with what actually had to be saved. And there are two reasons that something might not have to be saved. One is that what you're protecting it against, in fact, didn't trash the register, like it was just a variable look-up. And the other one is, that the thing that you were saving it for might turn out not to actually need it. So those are the two basic pieces of knowledge that the compiler can take advantage of in making the code more efficient. Let's break for questions. AUDIENCE: You kept saying that the uneval register, unev register didn't need to be used at all. Does that mean that you could just map a six-register machine? Or is that, in this particular example, it didn't need to be used? PROFESSOR: For the compiler, you could generate code for the six-register, five, right? Because that exp goes away also. Assuming--yeah, you can get rid of both exp and unev, because, see, those are data structures of the evaluator. Those are all things that would be constants from the point of view of the compiler. The only thing is this particular compiler is set up so that interpreted code and compiled code can coexist. So the way to think about it is, is maybe you build a chip which is the evaluator, and what the compiler might do is generate code for that chip. It just wouldn't use two of the registers. All right, let's take a break. [MUSIC PLAYING] We just looked at what the compiler is supposed to do. Now let's very briefly look at how, how this gets accomplished. And I'm going to give no details. There's, there's a giant pile of code in the book that gives all the details. But what I want to do is just show you the, the essential idea here. Worry about the details some other time. Let's imagine that we're compiling an expression that looks like there's some operator, and there are two arguments. Now, the-- what's the code that the compiler should generate? Well, first of all, it should r ecursively go off and compile the operator. So it says, I'll compile the operator. And where I'm going to need that is to be in the function register, eventually. So I'll compile some instructions that will compile the operator and end up with the result i n the function register. The next thing it's going to do, another piece is to say, well, I have to compile the first argument. So it calls itself recursively. And let's say the result will go into val. And then what it's going to need to do is start setting up the argument list. So it'll say, assign to argl cons of fetch-- so it generates this literal instruction-- fetch of val onto empty list. However, it might have to work-- when it gets here, it's going to need the environment. It's going to need whatever environment was here in order to do this evaluation of the first argument. So it has to ensure that the compilation of this operand, or it has to protect the function register against whatever might happen in the compilation of this operand. So it puts a note here and says, oh, this piece should be done preserving the environment register. Similarly, here, after it gets done compiling the first operand, it's going to say, I better compile-- I'm going to need to know the environment for the second operand. So it puts a little note here, saying, yeah, this is also done preserving env. Now it goes on and says, well, the next chunk of code is the one that's going to compile the second argument. And let's say it'll compile it with a targeted to val, as they say. And then it'll generate the literal instruction, building up the argument list. So it'll say, assign to argl cons of the new value it just got onto the old argument list. However, in order to have the old argument list, it better have arranged that the argument list didn't get trashed by whatever happened in here. So it puts a little note here and says, oh, this has to be done preserving argl. Now it's got the argument list set up. And it's all ready to go to apply dispatch. It generates thi s literal instruction. Because now it's got the arguments in argl and the operator in fun, but wait, it's only got the operator in fun if it had ensured that this block of code didn't trash what was in the function register. So it puts a little note here and says, oh, yes, all this stuff here had better be done preserving the function register. So that's the little--so when it starts ticking--so basically, what the compiler does is append a whole bunch of code sequences. See, what it's got in it is little primitive pieces of things, like how to look up a symbol, how to do a conditional. Those are all little pieces of things. And then it appends them together in this sort of discipline. So the basic means of combining things is to append two code sequences. That's what's going on here. And it's a little bit tricky. The idea is that it appends two code sequences, taking care to preserve a register. So the actual append operation looks like this. What it wants to do is say, if -- here's what it means to append two code sequences. So if sequence one needs register-- I should change this. Append sequence one to sequence two, preserving some register. Let me say, and. So it's clear that sequence one comes first. So if sequence two needs the register and sequence one modifies the register, then the instructions that the compiler spits out are, save the register. Here's the code. You generate this code. Save the register, and then you put out the recursively compiled stuff for sequence one. And then you restore the register. And then you put out the recursively compiled stuff for sequence two. That's in the case where you need to do it. Sequence two actually needs the register, and sequence one actually clobbers it. So that's sort of if. Otherwise, all you spit out is sequence one followed by sequence two. So that's the basic operation for sticking together these bits of code fragments, these bits of instructions into a sequence. And you see, from this point of view, the difference between the interpreter and the compiler, in some sense, is that where the compiler has these preserving notes, and says, maybe I'll actually generate the saves and restores and maybe I won't, the interpreter being maximally pessimistic always has a save and restore here. That's the essential difference. Well, in order to do this, of course, the compiler needs some theory of what code sequences need and modifier registers. So the tiny little fragments that you put in, like the basic primitive code fragments, say, what are the operations that you do when you look up a variable? What are the sequence of things that you do when you compile a constant or apply a function? Those have little notations in there about what they need and what they modify. So the bottom-level data structures-- Well, I'll say this. A code sequence to the compiler looks like this. It has the actual sequence of instructions. And then, along with it, there's the set of registers modified. And then there's the set of registers needed. So that's the information the compiler has that it draws on in order to be able to do this operation. And where do those come from? Well, those come from, you might expect, for the very primitive ones, we're going to put them in by hand. And then, when we combine two sequences, we'll figure out what these things should be. So for example, a very primitive one, let's see. How about doing a register assignment. So a primitive sequence might say, oh, it's code fragment. Its code instruction is assigned to R1, fetch of R2. So this is an example. That might be an example of a sequence of instructions. And along with that, it'll say, oh, what I need to remember is that that modifies R1, and then it needs R2. So when you're first building this compiler, you put in little fragments of stuff like that. And now, when it combines two sequences, if I'm going to combine, let's say, sequence one, that modifies a bunch of registers M1, and needs a bunch of registers N1. And I'm going to combine that with sequence two. That modifies a bunch of registers M2, and needs a bunch of registers N2. Then, well, we can reason it out. The new code fragment, sequence one, and-- followed by sequence two, well, what's it going to modify? The things that it will modify are the things that are modified either by sequence one or sequence two. So the union of these two sets are what the new thing modifies. And then you say, well, what is this--what registers is it going to need? It's going to need the things that are, first of all, needed by sequence one. Sowhat it needs is sequence one. And then, well, not quite all of the ones that are needed by sequence one. What it needs are the ones that are needed by sequence two that have not been set up by sequence one. So it's sort of the union of the things that se quence two needs minus the ones that sequence one modifies. Because it worries about setting them up. So there's the basic structure of the compiler. The way you do register optimizations is you have some strategies for what needs to be preserved. That depends on a data structure. Well, it depends on the operation of what it means to put things together. Preserving something, that depends on knowing what registers are needed and modified by these code fragments. That depends on having little data structures, which say, a code sequence is the actual instructions, what they modify and what they need. That comes from, at the primitive level, building it in. At the primitive level, it's going to be completely obvious what something needs and modifies. Plus, this particular way that says, when I build up bigger ones, here's how I generate the new set of registers modified and the new set of registers needed. And that's the whole-- well, I shouldn't say that's the whole thing. That's the whole thing except for about 30 pages of details in the book. But it is a perfectly usable rudimentary compiler. Let me kind of show you what it does. Suppose we start out with recursive factorial. And these slides are going to be much too small to read. I just want to flash through the code and show you about how much it is. That starts out with--here's a first block of it, where it compiles a procedure entry and does a bunch of assignments. And this thing is basically up through the part where it sets up to do the predicate and test whether the predicate's true. The second part is what results from-- in the recursive call to fact of n minus one. And this last part is coming back from that and then taking care of the constant case. So that's about how much code it would produce for factorial. We could make this compiler much, much better, of course. The main way we could make it better is to allow the compiler to make any assumptions at all about what happens when you call a procedure. So this compiler, for instance, doesn't even know, say, that multiplication is something that could be coded in line. Instead, it sets up this whole mechanism. It goes to apply-dispatch. That's a tremendous waste, because what you do every time you go to apply-dispatch is you have to concept this argument list, because it's a very general thing you're going to. In any real compiler, of course, you're going to have registers for holding arguments. And you're going to start preserving and saving the way you use those registers similar to the same strategy here. So that's probably the very main way that this particular compiler in the book could be fixed. There are other things like looking up variable values and making more efficient primitive operations and all sorts of things. Essentially,a good Lisp compiler can absorb an arbitrary amount of effort. And probably one of the reasons that Lisp is slow with compared to languages like FORTRAN is that, if you look over history at the amount of effort that's gone into building Lisp compilers, it's nowhere near the amount of effort that's gone into FORTRAN compilers. And maybe that's something that will change over the next couple of years. OK, let's break. Questions? AUDIENCE: One of the very first classes-- I don't know if it was during class or after class- you showed me the, say, addition has a primitive that we don't see, and-percent add or something like that. Is that because, if you're doing inline code you'd want to just do it for two operators, operands? But if you had more operands, you'd want to do something special? PROFESSOR: Yeah, you're looking in the actual scheme implementation. There's a plus, and a plus is some operator. And then if you go look inside the code for plus, you see something called-- I forget-- and-percent plus or something like that. And what's going on there is that particular kind of optimization. Because, see, general plus takes an arbitrary number of arguments. So the most general plus says, oh, if I have an argument list, I'd better cons it up in some list and then figure out how many there were or something like that. That's terribly inefficient, especially since most of the time you're probably adding two numbers. You don't want to really have to cons this argument list. So what you'd like to do is build the code for plus with a bunch of entries. So most of what it's doing is the same. However, there might be a special entry that you'd go to if you knew there were only two arguments. And those you'll put in registers. They won't be in an argument list and you won't have to [UNINTELLIGIBLE]. That's how a lot of these things work. OK, let's take a break. [MUSIC PLAYING] MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec10b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 10B: Storage Allocation and Garbage Collection [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] PROFESSOR: Well, there's one bit of mystery left, which I'd like to get rid of right now. And that's that we've been blithely doing things like cons assuming there's always another one. That we've been doing these things like car-ing and cdr-ing and assuming that we had some idea how this can be done. Now indeed we said that that's equivalent to having procedures. But that doesn't really solve the problem, because the procedure need all sortsof complicated mechanisms like environment structures and things like that to work. And those were ultimately made out of conses in the model that we had, so that really doesn't solve the problem. Now the problem here is the glue the data structure's made out of. What kind of possible thing could it be? We've been showing you things like a machine, a computer that has a controller, and some registers, and maybe a stack. And we haven't said anything about, for example, larger memory. And I think that's what we have to worry about right now. But just to make it perfectly clear that this is an inessential, purely implementational thing, I'd like to show you, for example, how you can do it all with the numbers. That's an easy one. Famous fellow by the name of Godel, a logician at the end of the 1930s, invented a very clever way of encoding the complicated expressions as numbers. For example-- I'm not saying exactly what Godel's scheme is, because he didn't use words like cons. He had other kinds of ways of combining to make expressions. But he said, I'm going to assign a number to every algebraic expression. And the way I'm going to manufacture these numbers is by combining the numbers of the parts. So for example, what we were doing our world, we could saythat if objects are represented by numbers, then cons of x and y could be represented by 2 to the x times 2 to the y. Because then we could extract the parts. We could say, for example, that then car of, say, x is the number of factors of 2 in x. And of course cdr is the same thing. It's the number of factors of 3 in x. Now this is a perfectly reasonable scheme, except for the fact that the numbers rapidly get to be much larger in number of digits than the number of protons in the universe. So there's no easy way to use this scheme other than the theoretical one. On the other hand, there are other ways of representing these things. We have been thinking in terms of little boxes. We've been thinking about our cons structures as looking sort of like this. They're little pigeon holes with things in them. And of course we arrange them in little trees. I wish that the semiconductor manufacturers would supply me with something appropriate for this, but actually what they do supply me with is a linear memory. Memory is sort of a big pile of pigeonholes, pigeonholes like this. Each of which can hold a certain sized object, a fixed size object. So, for example, a complicated list with 25 elements won't fit in one of these. However, each of these is indexed by an address. So the address might be zero here, one here, two here, three here, and so on. That we write these down as numbers is unimportant. What matters is that they're distinct as a way to get to the next one. And inside of each of these, we can stuff something into these pigeonholes. That's what memory is like, for those of you who haven't built a computer. Now the problem is how are we going to impose on this type of structure, this nice tree structure. Well it's not very hard, and there have been numerous schemes involved in this. The most important one is to say, well assuming that the semiconductor manufacturer allows me to arrange my memory so that one of these pigeonholes is big enough to hold the address of another I haven't made. Now it actually has to be a little bit bigger because I have to also install or store some information as to a tag which describes the kind of thing that's there. And we'll see that in a second. And of course if the semiconductor manufacturer doesn't arrange it so I can do that, then of course I can, with some cleverness, arrange combinations of these to fit together in that way. So we're going to have to imagine imposing this complicated tree structure on our nice linear memory. If we look at the first still store, we seea classic scheme for doing that. It's a standard way of representing Lisp structures in a linear memory. What we do is we divide this memory into two parts. An array called the cars, and an array called the cdrs. Now whether those happen to be sequential addresses or whatever, it's not important. That's somebody's implementation details. But there are two arrays here. Linear arrays indexed by sequential indices like this. What is stored in each of these pigeonholes is a typed object. And what we have here are types which begin with letters like p, standing for a pair. Or n, standing for a number. Or e, standing for an empty list. The end of the list. And so if we wish to represent an object like this, the list beginning with 1, 2 and then having a 3 and a 4 as its second and third elements. A list containing a list as its first part and then two numbers as a second and third parts. Then of course we draw it sort of like this these days, in box-and-pointer notation. And you see, these are the three cells that have as their car pointer the object which is either 1, 2 or 3 or 4. And then of course the 1, 2, the car of this entire structure, is itself a substructure which contains a sublist like that. What I'm about to do is put down places which are-- I'm going to assign indices. Like this 1, over here, represents the index of this cell. But that pointer that we see here is a reference to the pair of pigeonholes in the cars and the cdrs that are labeled by 1 in my linear memory down here. So if I wish to impose this structure on my linear memory, what I do is I say, oh yes, why don't we drop this into cell 1? I pick one. There's 1. And that says that its car, I'm going to assign it to be a pair. It's a pair, which is in index 5. And the cdr, which is this one over here, is a pair which I'm going to stick into place 2. p2. And take a look at p2. Oh yes, well p2 is a thing whose car is the number 3, so as you see, an n3. And whose cdr, over here, is a pair, which lives in place 4. So that's what this p4 is. p4 is a number whose value is 4 in its car and whose cdr is an empty list right there. And that ends it. So this is the traditional way of representing this kind of binary tree in a linear memory. Now the next question, of course, that we might want to worry about is just a little bit of implementation. That means that when I write procedures of the form assigned a, [UNINTELLIGIBLE] procedures-- lines of register machine code of the form assigned a, the car of [UNINTELLIGIBLE] b, what I really mean is addressing these elements. And so we're going to think of that as a abbreviation for it. Now of course in order to write that down I'm going to introduce some sort of a structure called a vector. And we're going to have something which will reference a vector, just so we can write it down. Which takes the name of the vector, or the-- I don't think that name is the right word. Which takes the vector and the index, and I have to have a way of setting one of those with something called a vector set, I don't really care. But let's look, for example, at then that kind of implementation of car and cdr. So for example if I happen to have a register b, which contains the type index of a pair, and therefore it is the pointer to a pair, then I could take the car of that and if I-- write this down-- I might put that in register a. What that really is is a representation of the assign to a, the value of vector reffing-- or array indexing, if you will-- or something, the cars object- - whatever that is-- with the index, b. And similarly for cdr. And we can do the same thing for assignment to data structures, if we need to do that sort of thing at all. It's not too hard to build that. Well now the next question is how are we going to do allocation. And every so often I say I want a cons. Now conses don't grow on trees. Or maybe they should. But I have to have some way of getting the next one. I have to have some idea of if their memory is unused that I might want to allocate from. And there are many schemes for doing this. And the particular thing I'm showing you right now is not essential. However it's convenient and has been done many times. One scheme's was called the free list allocation scheme. What that means is that all of the free memory that there is in the world is linked together in a linked list, just like all the other stuff. And whenever you need a free cell to make a new cons, you grab the first, one make the free list be the cdr of it, and then allocate that. And so what that looks like is something like this. Here we have the free list starting in 6. And what that is is a pointer-off to say 8. So what it says is, this one is free and the next one is an 8. This one is free and the next one is in 3, the next one that's free. That one's free and the next one is in 0. That one's free and the next one's in 15. Something like that. We can imagine having such a structure. Given that we have something like that, then it's possible to just get one when you need it. And so a program for doing cons, this is what cons might turn into. To assign to a register A the result of cons-ing, a B onto C, the value in this containing B and the value containing C, what we have to do is get the current [? type ?] ahead of the freelist, make the free list be its cdr. Then we have to change the cars to be the thing we're making up to be in A to be the B, the thing in B. And we have to make change the cdrs of the thing that's in A to be C. And then what we have in A is the right new frob, whatever it is. The object that we want. Now there's a little bit of a cheat here that I haven't told you about, which is somewhere around here I haven't set that I've the type of the thing that I'm cons -ing up to be a pair, and I ought to. So there should be some sort of bits here are being set, and I just haven't written that down. We could have arranged it, of course, for the free lift to be made outof pairs. And so then there's no problem with that. But that sort of-- again, an inessential detail in a way some particular programmer or architect or whatever might manufacture his machine or Lisp system. So for example, just looking at this, to allocate given that I had already the structure that you saw before, supposing I wanted to allocate a new cell, which is going to be representation of list one, one, two, where already one two was the car of the list we were playing with before. Well that's not so hard. I stored that one and one, so p1 one is the representation of this. This is p5. That's going to be the cdr of this. Now we're going to pull something off the free list, but remember the free list started at six. The new free list after this allocation is eight, a free list beginning at eight. And of course in six now we have a number one, which is what we wanted, with its cdr being the pair starting in location five. And that's no big deal. So the only problem really remaining here is, well, I don't have an infinitely large memory. If I do this for a little while, say, for example, supposing it takes me a microsecond to do a cons, and I have a million cons memory then I'm only going to run out in a second, and that's pretty bad. So what we do to prevent that disaster, that ecological disaster, talk about right after questions. Are there any questions? Yes. AUDIENCE: In the environment diagrams that we were drawing we would use the body of procedures, and you would eventually wind up with things that were no longer useful in that structure. How is that represented? PROFESSOR: There's two problems here. One you were asking is that material becomes useless. We'll talk about that in a second. That has to do with how to prevent ecological disasters. If I make a lot of garbage I have to somehow be able to clean up after myself. And we'll talk about that in a second. The other question you're asking is how you represent the environments, I think. AUDIENCE: Yes. PROFESSOR: OK. And the environment structures can be represented in arbitrary ways. There are lots of them. I mean, here I'm just telling you about list cells. Of course every real system has vectors of arbitrary length as well as the vectors of length, too, which represent list cells. And the environment structures that one uses in a professionally written Lisp system tend to be vectors which contain a number of elements approximately equal to the number of arguments-- a little bit more because you need certain glue. So remember, the environment [UNINTELLIGIBLE] frames. The frames are constructed by applying a procedure. In doing so, an allocation is made of a place which is the number of arguments long plus [? unglue ?] that gets linked into a chain. It's just like algol at that level. There any other questions? OK. Thank you, and let's take a short break. [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] PROFESSOR: Well, as I just said, computer memories supplied by the semiconductor manufacturers are finite. And that's quite a pity. It might not always be that way. Just for a quick calculation, you can see that it's possible that if [? memory ?] prices keep going at the rate they're going that if you still took a microsecond second to do a cons, then -- first of all, everybody should know that there's about pi times ten to the seventh seconds in a year. And so that would be ten to the seventh plus ten to the sixth is ten to the thirteenth. So there's maybe ten to the fourteenth conses in the life of a machine. If there was ten to the fourteenth words of memory on your machine, you'd never run out. And that's not completely unreasonable. Ten to the fourteenth is not a very large number. I don't think it is. But then again I like to play with astronomy. It's at least ten to the eighteenth centimeters between us and the nearest star. But the thing I'm about to worry about is, at least in the current economic state of affairs, ten to the fourteenth pieces of memory is expensive. And so I suppose what we have to do is make do with much smaller. Memories Now in general we want to have an illusion of infinity. All we need to do is arrange it so that whenever you look, the thing is there. That's really an important idea. A person or a computer lives only a finite amount of time and can only take a finite number of looks at something. And so you really only need a finite amount of stuff. But you have to arrange it so no matter how much there is, how much you really claim there is, there's always enough stuff so that when you take a look, it's there. And so you only need a finite amount. But let's see. One problem is, as was brought up, that there are possible ways that there is lots of stuff that we make that we don't need. And we could recycle the material out of which its made. An example is the fact that we're building environment structures, and we do so every time we call a procedure. We have built in it a environment frame. That environment frame doesn't necessarily have a very long lifetime. Its lifetime, meaning its usefulness, may exist only over the invocation of the procedure. Or if the procedure exports another procedure by returning it as a value and that procedure is defined inside of it, well then the lifetime of the frame of the outer procedure still is only the lifetime of the procedure which was exported. And so ultimately, a lot of that is garbage. There are other ways of producing garbage as well. Users produce garbage. An example of user garbage is something like this. If we write a program to, for example, append two lists together, well one way to do it is to reverse the first list onto the empty list and reverse that onto the second list. Now that's not terribly bad way of doing it. And however, the intermediate result, which is the reversal of the first list as done by this program, is never going to be accessed ever again after it's copied back on to the second. It's an intermediate result. It's going to be hard to ever see how anybody would ever be able to access it. In fact, it will go away. Now if we make a lot of garbage like that, and we should be allowed to, then there's got to be some way to reclaim that garbage. Well, what I'd like to tell you about now is a very clever technique whereby a Lisp system can prove a small theorem every so often on the [? forum, ?] the following piece of junk will never be accessed again. It can have no affect on the future of the computation. It's actually based on a very simple idea. We've designed our computers to look sort of like this. There's some data path, which contains the registers. There are things like x, and env, and val, and so on. And there's one here called stack, some sort which points off to a structure somewhere, which is the stack. And we'll worry about that in a second. There's some finite controller, finite state machine controller. And there's some control signals that go this way and predicate results that come this way, not the interesting part. There's some sort of structured memory, which I just told you how to make, which may contain a stack. I didn't tell you how to make things of arbitrary shape, only pairs. But in fact with what I've told you can simulate a stack by a big list. I don't plan to do that, it's not a nice way to do it. But we could have something like that. We have all sorts of little data structures in here that are hooked together in funny ways. They connect to other things. And so on. And ultimately things up there are pointers to these. The things that are in the registers are pointers off to the data structures that live in this Lisp structure memory. Now the truth of the matter is that the entire consciousness of this machine is in these registers. There is no possible way that the machine, if done correctly, if built correctly, can access anything in this Lisp structure memory unless the thing in that Lisp structure memory is connected by a sequence of data structures to the registers. If it's accessibleby legitimate data structure selectors from the pointers that are stored in these registers. Things like array references, perhaps. Or cons cell references, cars and cdrs. But I can't just talk about a random place in this memory, because I can't get to it. These are being arbitrary names I'm not allowed to count, at least as I'm evaluating expressions. If that's the case then there's a very simple theorem to be proved. Which is, if I start with all lead pointers that are in all these registers and recursively chase out, marking all the places I can get to by selectors, then eventually I mark everything they can be gotten to. Anything which is not so marked is garbage and can be recycled. Very simple. Cannot affect the future of the computation. So let me show you that in a particular example. Now that means I'm going to have to append to my description of the list structure a mark. And so here, for example, is a Lisp structured memory. And in this Lisp structured memory is a Lisp structure beginning ina place I'm going to call-- this is the root. Now it doesn't really have to have a root. It could be a bunch of them, like all the registers. But I could cleverly arrange it so all the registers, all the things that are in old registers are also at the right moment put into this root structure, and then we've got one pointer to it. I don't really care. So the idea is we're going to cons up stuff until our free list is empty. We've run out of things. Now we're going to do this process of proving the theorem that a certain percentage of the memory has got crap in it. And then we're going to recycle that to grow new trees, a standard use of such garbage. So in any case, what do we have here? Well we have some data structure which starts out over here one. And in fact it has a car in five, and its cdr is in two. And all the marks start out at zero. Well let's start marking, just to play this game. OK. So for example, since I can access one from the root I will mark that. Let me mark it. Bang. That's marked. Now since I have a five here I can go to five and see, well I'll mark that. Bang. That's useful stuff. But five references as a number in its car, I'm not interested in marking numbers but its cdr is seven. So I can mark that. Bang. Seven is the empty list, the only thing that references, and it's got a number in its car. Not interesting. Well now let's go back here. I forgot about something. Two. See in other words, if I'm looking at cell one, cell one contains a two right over here. A reference to two. That means I should go mark two. Bang. Two contains a reference to four. It's got a number in its car, I'm not interested in that, so I'm going to go mark that. Four refers to seven through its car, and is empty in its cdr, but I've already marked that one so I don't have to mark it again. This is all the accessible structure from that place. Simple recursive mark algorithm. Now there are some unhappinesses about that algorithm, and we can worry about that a second. But basically you'll see that all the things that have not been marked are places that are free, and I could recycle. So the next stage after that is going to be to scan through all of my memory, looking for things that are not marked. Every time I come across a marked thing I unmark it, and every time I come across an unmarked thing I'm going to link it together in my free list. Classic, very simple algorithm. So let's see. Is that very simple? Yes it is. I'm not going to go through the code in any detail, but I just want to show you about how long it is. Let's look at the mark phase. Here's the first part of the mark phase. We pick up the root. We're going to use that as a recursive procedure call. We're going to sweep from there, after when we're done with marking. And then we're going to do a little couple of instructions that do this checking out on the marks and changing the marks and things like that, according to the algorithm I've just shown you. It comes out here. You have to mark the cars of things and you also have to be able to mark the cdrs of things. That's the entire mark phase. I'll just tell you a little story about this. The old DEC PDP-6 computer, this was the way that the mark-sweep garbage collection, as it was, was written. The program was so small that with the data that it needed, with the registers that it needed to manipulate the memory, it fit into the fast registers of the machine, which were 16. The whole program. And you could execute instructions in the fast registers. So it's an extremely small program, and it could run very fast. Now unfortunately, of course, this program, because the fact that it's recursive in the way that you do something first and then you do something after that, you have to work on the cars and then the cdrs, it requires auxiliary memory. So Lisp systems-- those requires a stack for marking. Lisp systems that are built this way have a limit to the depth of rec ursion you can have in data structures in either the car or the cdr, and that doesn't work very nicely. On the other hand, you never notice it if it's big enough. And that's certainly been the case for most Maclisp, for example, which ran Macsyma where you could deal with expressions of thousands of elements long. These are algebraic expressions with thousand of terms. And there's no problem with that. Such, the garbage collector does work. On the other hand, there's a very clever modification to this algorithm, which I will not describe, by Peter Deutsch and Schorr and Waite-- Herb Schorr from IBM and Waite, who I don't know. That algorithm allows you to build-- you do can do this without auxiliary memory, by remembering as you walk the data structureswhere you came from by reversing the pointers as you go down and crawling up the reverse pointers as you go up. It's a rather tricky algorithm. The first time you write it-- or in fact, the first three times you write it it has a terrible bug in it. And it's also rather slow, because it's complicated. It takes about six times as many memory references to do the sorts of things that we're talking about. Well now once I've done this marking phase, and I get into a position where things look like this, let's look-- yes. Here we have the mark done, just as I did it. Now we have to perform the sweep phase. And I described to you what this sweep is like. I'm going to walk down from one end of memory or the other, I don't care where, scanning every cell that's inthe memory. And as I scan these cells, I'm going to link them together, if they are free, into the free list. And if they're not free, I'm going to unmark them so the marks become zero. And in fact what I get-- well the program is not very complicated. It looks sort of like this -- it's a little longer. Here's the first piece of it. This one's coming down from the top of memory. I don't want you to try to understand this at this point. It's rather simple. It's a very simple algorithm, but there's pieces of it that just sort of look like this. They're all sort of obvious. And after we've done the sweep, we get an answer that looks like that. Now there are some disadvantages with mark-sweep algorithms of this sort. Serious ones. One important disadvantage is that your memories get larger and larger. As you say, address spaces get larger and larger, you're willing to represent more and more stuff, then it gets very costly to scan all of memory. What you'd really like to do is only scan useful stuff. It would even be better if you realized that some stuff was known to be good and useful, and you don't have to look at it more than once or twice. Or very rarely. Whereas other stuff that you're not so sure about, you can look at more detail every time you want to do this, want to garbage collect. Well there are algorithms that are organized in this way. Let me tell you about a famous old algorithm which allows you only look at the part of memory which is known to be useful. And which happens to be the fastest known garbage collector algorithm. This is the Minsky- Feinchel-Yochelson garbage collector algorithm. It was invented by Minsky in 1961 or '60 or something, for the RLE PDP-1 Lisp, which had 4,096 words of list memory, and a drum. And the whole idea was to garbage collect this terrible memory. What Minsky realized was the easiest way to do this is to scan the memory in the same sense, walking the good structure, copying it out into the drum, compacted. And then when we were done copying it all out, then you swap that back into your memory. Now whether or you not use a drum, or another piece of memory, or something like that isn't important. In fact, I don't think people use drums anymore for anything. But this algorithm basically depends upon having about twice as much address space as you're actually using. And so what you have is some, initially, some mixture of useful data and garbage. So this is called fromspace. And this is a mixture of crud. Some of it's important and some of it isn't. Now there's another place which is hopefully big enough, if we recall, tospace, which is where we're copying to. And what happens is-- and I'm not going to go through this detail. It's in our book quite explicitly. There's a root point where you start from. And the ide a is that you start with the root. You copy the first thing you see, the first thing that the root points at, to the beginning of tospace. The first thing is a pair or something like, a data structure. You then also leave behind a broken heart saying, I moved this object from here to here, giving the place where it moved to. This is called a broken heart because a friend of mine who implemented one of these in 1966 was a very romantic character and called it a broken heart. But in any case, the next thing you do is now you have a new free pointer which is here, and you start scanning. You scan this data structure you just copied. And every time you encounter a pointer in it, you treat it as if it was the root pointer here. Oh, I'm sorry. The other thing you do is you now move the root pointer to there. So now you scan this, and everything you see you treat as it were the root pointer. So if you see something, well it points up into there somewhere. Is it pointing at a thing which you've not copied yet? Is there a broken heart there? If there's a broken heart there and it's something you have copied, you've just replaced this pointer with the thing a broken heart points at. If this thing has not been copied, you copy it to the next place over here. Move your free pointer over here, and then leave a broken heart behind and scan. And eventually when the scant pointer hits the free pointer, everything in memory has been copied. And then there's a whole bunch of empty space up here, which you could either make into a free list, if that's what you want to do. But generally you don't in this kind of system. In this system you sequentially allocate your memory. That is a very, very nice algorithm, and sort of the one we use in the scheme that you've been using. And it's expected-- I believe no one has found a faster algorithm than that. There are very simple modifications to this algorithm invented by Henry Baker which allow one to run this algorithm in real time, meaning you don't have to stop to garbage collect. But you could interleave the consing that the machine does when its running with steps of the garbage collection process, so that the garbage collector's distributed, and the machine doesn't have to stop, and garbage collecting can start. Of course in the case of machines with virtual memory where a lot of it is in inaccessible places, this becomes a very expensive process. And there have been numerous attempts to make this much better. There is a nice paper, for those ofyou who are interested, by Moon and other people which describes a modification to the incremental Minsky -Feinchel- Yochelson algorithm, and modification the Baker algorithm which is more efficient for virtual memory systems. Well I think now the mystery to this is sort of gone. And I'd like to see if there are any questions. Yes. AUDIENCE: I saw one of you run the garbage collector on the systems upstairs, and it seemed to me to run extremely fast. Did the whole thing take-- does it sweep through all of memory? PROFESSOR: No. It swept through exactly what was needed to copy the useful structure. It's a copying collector. And it is very fast. On the whole, I suppose to copy -- in a Bobcat-- to copy, I think, a three megabyte thing or something is less than a second, real time. Really, these are very small programs. One thing you should realise is that garbage collectors have to be small. Not because they have to be fast, but because no one can debug a complicated garbage collector. A garbage collector, if it doesn't work, will trash your memory in such a way that you cannot figure out what the hell happened. You need an audit trail. Because it rearranges everything, and how do you know what happened there? So this is the only kind of program that it really, seriously matters if you stare at it long enough so you believe that it works. And sort of prove it to yourself. So there's no way to debug it. And that takes it being small enough so you can hold it in your head. Garbage collectors are special in this way. So every reasonable garbage collector has gotten small, and generally small programs are fast. Yes. AUDIENCE: Can you repeat the name of this technique once again? PROFESSOR: That's the Minsky-Feinchel-Yochelson garbage collector. AUDIENCE: You got that? PROFESSOR: Minsky invented it in '61 for the RLE PDP-1. A version of it was developed and elaborated to be used in Multics Maclisp by Feinchel and Yochelson in somewhere around 1968 or '69. OK. Let's take a break. [MUSIC: "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] PROFESSOR: Well we've come to the end of this subject, and we've already shown you a universal machine which is down to evaluator. It's down to the level of detail you could imagine you could make one. This is a particular implementation of Lisp, built on one of those scheme chips that was talked about yesterday, sitting over here. This is mostly interface to somebody's memory with a little bit of timing and other such stuff. But this fellow actually ran Lisp at a fairly reasonable rate, as interpretive. It ran Lisp as fast as a DEC PDP-10 back in 1979. And so it's gotten pretty hardware. Pretty concrete. We've also downed you a bit with the things you can compute. But is it the case that th ere are things we can't compute? And so I'd like to end this with showing you some things that you'd like be able to compute that you can't. The answer is yes, there are things you can't compute. For example, something you'd really like is-- if you're writing [UNINTELLIGIBLE], you'd like a program that would check that the thing you're going to do will work. Wouldn't that be nice? You'd like something that would catch infinite loops, for example, in programs that were written by users. But in general you can't write such a program that will read any program and determine whether or not it's an infinite loop. Let me show you that. It's a little bit of a minor mathematics. Let's imagine that we just had a mathematical function before we start. And there isone, called s, which takes a procedure and its argument, a. And what s does is it determines whether or not it's safe to run p on a. And what I mean by that is this: it's true if p applied to a will converge to a value without an error. And it's false if p of a loops forever or makes an error. Now that's surely a function. There is some for every procedure and for every argument you could give it that is either true or false that it converges without making an error. And you could make a giant table of them. But the question is, can you write a procedure that compute the values of this function? Well let's assume that we can. Suppose that we have a procedure called "safe" that computes the value of s. Now I'm going to show you by several methods that you can't do this. The easiest one, or the first one, let's define a procedure called diag1. Given that we have safe, we can define diag1 to be the procedure of one argument, p, which has the following properties. If if it's safe to apply p to itself, then I wish to have an infinite loop. Otherwise I'm going to return 3. Remember it was 42. What's the answer to the big question? Where of course we know what an infinite loop is. Infinite loop, to be a procedure of no arguments, which is that nice lambda calculus loop. Lambda of x, x of x, applied to lambda of x, x of x. So there's nothing left to the imagination here. Well let's see what the story is. I'm supposing it's the case that we worry about the procedure called diag1 applied to diag1. Well what could it possibly be? Well I don't know. We're going to substitute diag1 for p in the body here. Well is it safe to compute diag1 of diag1? I don't know. There are two possibilities. If it's safe to compute diag1 of diag1 that means it shouldn't loop. That means I go to here, but then I produce an infinite loop. So it can't be safe. But if it's not safe to compute diag1 of diag1 then the answer to this is 3. But that's diag1 of diag1, so it had to be safe. So therefore by contradiction you cannot produce safe. For those of you who were boggled by that one I'm going to say it again, in a different way. Listen to one more alternative. Let's define diag2. These are named diag because of Cantor's diagonal argument. These are instances of a famous argument which was originally used by Cantor in the late part of the last century to prove that the real numbers were not countable, that there are too many real numbers to be counted by integers. That there are more points on a line, for example, than there are counting numbers. It may or may not be obvious, and I don't want to get into that now. But diag2 is again a procedure of one argument p. It's almost the same as the previous one, which is, if it's safe to compute p on p, then I'm going to produce-- then I want to compute some other things other than p of p. Otherwise I'm going to put out false. Where other then it says, whatever p of p, I'm going to put out something else. I can give you an example of a definition of other than which I think works. Let's see. Yes. Where other than be a procedure of one argument x which says, if its eq x to, say, quote a, then the answer is quote b. Otherwise it's quote a. That always produces something which is not what its argument is. That's all it is. That's all I wanted. Well now let's consider this one, diag2 of diag2. Well look. This only does something dangerous, like calling p of p, if it's safe to do so. So if safe defined at all, if you can define such a procedure, safe, then this procedure is always defined and thereforesafe on any inputs. So diag2 of diag2 must reduce to other than diag2 of diag2. And that doesn't make sense, so we have a contradiction, and therefore we can't define safe. I just waned to do that twice, slightly differently, so you wouldn't feel that the first one was a trick. They may be both tricks, but they're at least slightly different. So I suppose that pretty much wraps it up. I've just proved what we call the halting theorem, and I suppose with that we're going to halt. I hope you have a good time. Are there any questions? Yes. AUDIENCE: What is the value of s of diag1? PROFESSOR: Of what? AUDIENCE: S of diag1. If you said s is a function and we can [INTERPOSING VOICES] PROFESSOR: Oh, I don't know. I don't know. It's a function, but I don't know how to compute it. I can't do it. I'm just a machine, too. Right? There's no machine that in principle-- it might be that in that particular case you just asked, with some thinkin g I could figure it out. But in general I can't compute the value of s any better than any other machine can. There is such a function, it's just that no machine can be built to compute it. Now there's a way of saying that that should not be surprising. Going through this-- I mean, I don't have time to do this here, but the number of functions is very large. If there's a certain number of answers possible and a certain number of inputs possible, then it's the number of answers raised to the number inputs is the number of possible functions. On one variable. Now that's always bigger than the thing you're raising to, the exponent. The number of functions is larger than the number of programs that one can write, by an infinity counting argument. And it's much larger. So there must be a lot of functions that can't be computed by programs. AUDIENCE: A few moments ago you were talking about specifications and automatic generation of solutions. Do you see any steps between specifications and solutions? PROFESSOR: Steps between. You mean, you're saying, how you go about constructing devices given that have specifications for the device? Sure. AUDIENCE: There's a lot of software engineering that goes through specifications through many layers of design and then implementation. PROFESSOR: Yes? AUDIENCE: I was curious if you think that's realistic. PROFESSOR: Well I think that some of it's realistic and some of it isn't. I mean, surely if I want to build an electrical filter and I have a rather interesting possibility. Supposing I want to build a thing that matches some power output to the radio transmitter, to some antenna. And I'm really out of this power-- it's output tube out here. And the problem is that they have different impedances. I want them to match the impedances. I also want to make a filter in there which is going to get rid of some harmonic radiation. Well one old-fashioned technique for doing this is called image impedances, or something like that. And what you do is you say you have a basic module called an L-section. Looks like this. If I happen to connect this to some resistance, r, and if I make this impedance x, xl, and if it happens to be q times r, then this produces a low pass filter with a q square plus one impedance match. Just what I need. Because now I can take two of these, hook them together like this. OK, and I take another one and I'll hook them together like that. And I have two L-sections hooked together. And this will step the impedance down to one that I know, and this will step it up to one I know. Each of these is a low pass filter getting rid of some harmonics. It's good filter, it's called a pie -section filter. Great. Except for the fact that in doing what I just did, I've made a terrible inefficiency in this system. I've made two coils where I should have made one. And the problem with most software engineering art is that there's no mechanism, other than peephole optimization and compilers, for getting rid of the redundant parts that are constructed when doing top down design. It's even worse, there are lots of very important structures that you can't construct at all this way. So I think that the standard top down design is a rather shallow business. Doesn't really capture what people want to do in design. I'll give you another electrical example. Electrical examples are so much clearer than computational examples, because computation examples require a certain degree of complexity to explain them. But one of my favorite examples in the electrical world is how would I ever come up with the output stage of this inter-stage connection in an IF amplifier. It's a little transistor here, and let's see. Well I'm going to have a tank, and I'm going to hook this up to, say, I'm going to link-couple that to the input of the next stage. Here's a perfectly plausible plan-- well except for the fact that since I put that going up I should make that going that way. Here's a perfectly plausible plan for a -- no I shouldn't. I'm dumb. Excuse me. Doesn't matter. The point is [UNINTELLIGIBLE] plan for a couple [UNINTELLIGIBLE] stages together. Now what the problem is is what's this hierarchically? It's not one thing. Hierarchically it doesn't make any sense at all. It's the inductance of a tuned circuit, it's the primary of a transformer, and it'salso the DC path by which bias conditions get to the collector of that transistor. And there's no simple top -down design that's going to produce a structure like that with so many overlapping uses for a particular thing. Playing Scrabble, where you have to do triple word scores, or whatever, is not so easy in top-down design strategy. Yet most of real engineering is based on getting the most oomph for effort. And that's what you're seeing here. Yeah? AUDIENCE: Is this the last question? [LAUGHTER] PROFESSOR: Apparently so. Thank you. [APPLAUSE] [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec1a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 1A: Overview and Introduction to Lisp [MUSIC PLAYING] PROFESSOR: I'd like to welcome you to this course on computer science. Actually, that's a terrible way to start. Computer science is a terrible name for this business. First of all, it's not a science. It might be engineering or it might be art, but we'll actually see that computer so-called science actually has a lot in common with magic, and we'll see that in this course. So it's not a science. It's also not really very much about computers. And it's not about computers in the same sense that physics is not really about particle accelerators, and biology is not really about microscopes and petri dishes. And it's not about computers in the same sense that geometry is not really about using surveying instruments. In fact, there's a lot of commonality between computer science and geometry. Geometry, first of all, is another subject with a lousy name. The name comes from Gaia, meaning the Earth, and metron, meaning to measure. Geometry originally meant measuring the Earth or surveying. And the reason for that was that, thousands of years ago, the Egyptian priesthood developed the rudiments of geometry in order to figure out how to restore the boundaries of fields that were destroyed in the annual flooding of the Nile. And to the Egyptians who did that, geometry really was the use of surveying instruments. Now, the reason that we think computer science is about computers is pretty much the same reason that the Egyptians thought geometry was about surveying instruments. And that is, when some field is just getting started and you don't really understand it very well, it's very easy to confuse the essence of what you're doing with the tools that you use. And indeed, on some absolute scale of things, we probably know less about the essence of computer science than the ancient Egyptians really knew about geometry. Well, what do I mean by the essence of computer science? What do I mean by the essence of geometry? See, it's certainly true that these Egyptians went off and used surveying instruments, but when we look back on them after a couple of thousand years, we say, gee, what they were doing, the important stuff they were doing, was to begin to formalize notions about space and time, to start a way of talking about mathematical truths formally. That led to the axiomatic method. That led to sort of all of modern mathematics, figuring out a way to talk precisely about so-called declarative knowledge, what is true. Well, similarly, I think in the future people will look back and say, yes, those primitives in the 20th century were fiddling around with these gadgets called computers, but really what they were doing is starting to learn how to formalize intuitions about process, how to do things, starting to develop a way to talk precisely about how-to knowledge, as opposed to geometry that talks about what is true. Let me give you an example of that. Let's take a look. Here is a piece of mathematics that says what a square root is. The square root of X is the number Y, such that Y squared is equal to X and Y is greater than 0. Now, that's a fine piece of mathematics, but just telling you what a square root is doesn't really say anything about how you might go out and find one. So let's contrast that with a piece of imperative knowledge, how you might go out and find a square root. This, in fact, also comes from Egypt, not ancient, ancient Egypt. This is an algorithm due to Heron of Alexandria, called how to find a square root by successive averaging. And what it says is that, in order to find a square root, you make a guess, y ou improve that guess-- and the way you improve the guess is to average the guess and X over the guess, and we'll talk a little bit later about why that's a reasonable thing -- and you keep improving the guess until it's good enough. That's a method. That's how to do something as opposed to declarative knowledge that says what you're looking for. That's a process. Well, what's a process in general? It's kind of hard to say. You can think of it as like a magical spirit that sort of lives in the computer and does something. And the thing that directs a process is a pattern of rules called a procedure. So procedures are the spells, if you like, that control these magical spirits that are the processes. I guess you know everyone needs a magical language, and sorcerers, real sorcerers, use ancient Arcadian or Sumerian or Babylonian or whatever. We're going to conjure our spirits in a magical language called Lisp, which is a language designed for talking about, for casting the spells that are procedures to direct the processes. Now, it's very easy to learn Lisp. In fact, in a few minutes, I'm going to teach you, essentially, all of Lisp. I'm going to teach you, essentially, all of the rules. And you shouldn't find that particularly surprising. That's sort of like saying it's very easy to learn the rules of chess. And indeed, in a few minutes, you can tell somebody the rules of chess. But of course, that's very different from saying you understand the implications of those rules and how to use those rules to become a masterful chess player. Well, Lisp is the same way. We're going to state the rules in a few minutes, and it'll be very easy to see. But what's really hard is going to be the implications of those rules, how you exploit those rules to be a master programmer. And the implications of those rules are going to take us the, well, the whole rest of the subject and, of course, way beyond. OK, so in computer science, we're in the business of formalizing this sort of how-to imperative knowledge, how to do stuff. And the real issues of computer science are, of course, not telling people how to do square roots. Because if that was all it was, there wouldn't be no big deal. The real problems come when we try to build very, very large systems, computer programs that are thousands of pages long, so long that nobody can really hold them in their heads all at once. And the only reason that that's possible is because there are techniques for controlling the complexity of these large systems. And these techniques that are controlling complexity are what this course is really about. And in some sense, that's really what computer science is about. Now, that may seem like a very strange thing to say. Because after all, a lot of people besides computer scientists deal with controlling complexity. A large airliner is an extremely complex system, and the aeronautical engineers who design that are dealing with immense complexity. But there's a difference between that kind of complexity and what we deal with in computer science. And that is that computer science, in some sense, isn't real. You see, when an engineer is designing a physical system, that's made out of real parts. The engineers who worry about that have to address problems of tolerance and approximation and noise in the system. So for example, as an electrical engineer, I can go off and easily build a one-stage amplifier or a two-stage amplifier, and I can imagine cascading a lot of them to build a million -stage amplifier. But it's ridiculous to build such a thing, because long before the millionth stage, the thermal noise in those components way at the beginning is going to get amplified and make the whole thing meaningless. Computer science deals with idealized components. We know as much as we want about these little program and data pieces that we're fitting things together. We don't have to worry about tolerance. And that means that, in building a large program, there's not all that much difference between what I can build and what I can imagine, because the parts are these abstract entities that I know as much as I want. I know about them as precisely as I'd like. So as opposed to other kinds of engineering, where the constraints on what you can build are the constraints of physical systems, th e constraints of physics and noise and approximation, the constraints imposed in building large software systems are the limitations of our own minds. So in that sense, computer science is like an abstract form of engineering. It's the kind of engineering where you ignore the constraints that are imposed by reality. Well, what are some of these techniques? They're not special to computer science. First technique, which is used in all of engineering, is a kind of abstraction called black- box abstraction. Take something and build a box about it. Let's see, for example, if we looked at that square root method, I might want to take that and build a box. That sort of says, to find the square root of X. And that might be a whole complicated set of rules. And that might end up being a kind of thing where I can put in, say, 36 and say, what's the square root of 36? And out comes 6. And the important thing is that I'd like to design that so that if George comes along and would like to compute, say, the square root of A plus the square root of B, he can take this thing and use it as a module without having to look inside and build something that looks like this, like an A and a B and a square root box and another square root box and then something that adds that would put out the answer. And you can see, just from the fact that I want to do that, is from George's point of view, the internals of what's in here should not be important. So for instance, it shouldn't matter that, when I wrote this, I said I want to find the square root of X. I could have said the square root of Y, or the square root of A, or anything at all. That's the fundamental notion of putting something in a box using black-box abstraction to suppress detail. And the reason for that is you want to go off and build bigger boxes. Now, there's another reason for doing black-box abstraction other than you want to suppress detail for building bigger boxes. Sometimes you want to say that your way of doing something, your how -to method, is an instance of a more general thing, and you'd like your language to be able to express that generality. Let me show you another example sticking with square roots. Let's go back and take another look at that slide with the square root algorithm on it. Remember what that says. That says, in order to do something, I make a guess, and I improve that guess, and I sort of keep improving that guess. So there's the general strategy of, I'm looking for something, and the way I find it is that I keep improving it. Now, that's a particular case of another kind of strategy for finding a fixed point of something. So you have a fixed point of a function. A fixed point of a function is something, is a value. A fixed point of a function F is a value Y, such that F of Y equals Y. And the way I might do that is start with a guess. And then if I want something that doesn't change when I keep applying F, is I'll keep applying F over and over until that result doesn't change very much. So there's a general strategy. And then, for example, to compute the square root of X, I can try and find a fixed point of the function which takes Y to the average of X/Y. And the idea that is that if I really had Y equal to the square root of X, then Y and X/Y would be the same value. They'd both be the square root of X, because X over the square root of X is the square root of X. And so the average if Y were equal to the square of X, then the average wouldn't change. So the square root of X is a fixed point of that particular function. Now, what I'd like to have, I'd like to express the general strategy for finding fixed points. So what I might imagine doing, is to find, is to be able to use my language to define a box that says "fixed point," just like I could make a box that says "square root." And I'd like to be able to express this in my language. So I'd like to express not only the imperative how-to knowledge of a particular thing like square root, but I'd like to be able to express the imperative knowledge of how to do a general thing like how to find fixed point. And in fact, let's go back and look at that slide again. See, not only is this a piece of imperative knowledge, how to find a fixed point, but over here on the bottom, there's another piece of imperative knowledge which says, one way to compute square root is to apply this general fixed point method. So I'd like to also be able to express that imperative knowledge. What would that look like? That would say, this fixed point box is such that if I input to it the function that ta kes Y to the average of Y and X/Y, then what should come out of that fixed point box is a method for finding square roots. So in these boxes we're building, we're not only building boxes that you input numbers and output numbers, we're going to be building in boxes that, in effect, compute methods like finding square root. And my take is their inputs functions, like Y goes to the average of Y and X/Y. The reason we want to do that, the reason this is a procedure, will end up being a procedure, as we'll see, whose value is another procedure, the reason we want to do that is because procedures are going to be our ways of talking about imperative knowledge. And the way to make that very powerful is to be able to talk about other kinds of knowledge. So here is a procedure that, in effect, talks about another procedure, a general strategy that itself talks about general strategies. Well, our first topic in this course -- there'll be three major topics-- will be black-box abstraction. Let's look at that in a little bit more detail. What we're going to do is we will start out talking about how Lisp is built up out of primitive objects. What does the language supply with us? And we'll see that there are primitive procedures and primitive data. Then we're going to see, how do you take those primitives and combine them to make more complicated things, means of combination? And what we'll see is that there are ways of putting things together, putting primitive procedures together to make more complicated procedures. And we'll see how to put primitive data together to make compound data. Then we'll say, well, having made those compounds things, how do you abstract them? How do you put those black boxes around them so you can use them as components in more complex things? And we'll see that's done by defining procedures and a technique for dealing with compound data called data abstraction. And then, what's maybe the most important thing, is going from just the rules to how does an expert work? How do you express common patterns of doing things, like saying, well, there's a general method of fixed point and square root is a particular case of that? And we're going to use-- I've already hinted at it-- something called higher-order procedures, namely procedures whose inputs and outputs are themselves procedures. And then we'll also see something very interesting. We'll see, as we go further and further on and become more abstract, there'll be very-- well, the line between what we consider to be data and what we consider to be procedures is going to blur at an incredible rate. Well, that's our first subject, black-box abstraction. Let's look at the second topic. I can introduce it like this. See, suppose I want to express the idea-- remember, we're talking about ideas-- suppose I want to express the idea that I can take something and multiply it by the sum of two other things. So for example, I might say, if I had 1 and 3 and multiply that by 2, I get 8. But I'm talking about the general idea of what's called linear combi nation, that you can add two things and multiply them by something else. It's very easy when I think about it for numbers, but suppose I also want to use that same idea to think about, I could add two vectors, a1 and a2, and then scale them by some factor x and get another vector. Or I might say, I want to think about a1 and a2 as being polynomials, and I might want to add those two polynomials and then multiply them by 2 to get a more complicated one. Or a1 and a2 might be electrical signals, and I might want to think about summing those two electrical signals and then putting the whole thing through an amplifier, multiplying it by some factor of 2 or something. The idea is I want to think about the general notion of that. Now, if our language is going to be good language for expressing those kind of general ideas, if I really, really can do that, I'd like to be able to say I'm going to multiply by x the sum of a1 and a2, and I'd like that to express the general idea of all different kinds of things that a1 and a2 could be. Now, if you think about that, there's a problem, because after all, the actual primitive operations that go on in the machine are obviously going to be different if I'm adding two numbers than if I'm adding two polynomials, or if I'm adding the representation of two electrical signals or wave forms. Somewhere, there has to be the knowledge of the kinds of various things that you can add and the ways of adding them. Now, to construct such a system, the question is, where do I put that knowledge? How do I think about the different kinds of choices I have? An d if tomorrow George comes up with a new kind of object that might be added and multiplied, how do I add George's new object to the system without screwing up everything that was already there? Well, that's going to be the second big topic, the way of controlling that kind of complexity. And the way you do that is by establishing conventional interfaces, agreed upon ways of plugging things together. Just like in electrical engineering, people have standard impedances for connectors, and then you know if y ou build something with one of those standard impedances, you can plug it together with something else. So that's going to be our second large topic, conventional interfaces. What we're going to see is, first, we're going to talk about the problem of generic operations, which is the one I alluded to, things like "plus" that have to work with all different kinds of data. So we talk about generic operations. Then we're going to talk about really large-scale structures. How do you put together very large programs that model the kinds of complex systems in the real world that you'd like to model? And what we're going to see is that there are two very important metaphors for putting together such systems. One is called object-oriented programming, where you sort of think of your system as a kind of society full of little things that interact by sending information between them. And then the second one is operations on aggregates, called streams, where you think of a large system put together kind of like a signal processing engineer puts together a large electrical system. That's going to be our second topic. Now, the third thing we're going to come to, the third basic technique for controlling complexity, is making new languages. Because sometimes, when you're sort of overwhelmed by the complexity of a design, the way that you control that complexity is to pick a new design language. And the purpose of the new design language will be to highlight different aspects of the system. It will suppress some kinds of details and emphasize other kinds of details. This is going to be the most magical part of the course. We're going to start out by actually looking at the technology for building new computer languages. The first thing we're going to do is actually build in Lisp. We're going to express in Lisp the process of interpreting Lisp itself. And that's going to be a very sort of self-circular thing. There's a little mystical symbol that has to do with that. The process of interpreting Lisp is sort of a giant whe el of two processes, apply and eval, which sort of constantly reduce expressions to each other. Then we're going to see all sorts of other magical things. Here's another magical symbol. This is sort of the Y operator, which is, in some sense, the expression of infinity inside our procedural language. We'll take a look at that. In any case, this section of the course is called Metalinguistic Abstraction, abstracting by talking about how you construct new languages. As I said, we're going to start out by looking at the process of interpretation. We're going to look at this apply-eval loop, and build Lisp. Then, just to show you that this is very general, we're going to use exactly the same technology to build a very different kind of language, a so-called logic programming language, where you don't really talk about procedures at all that have inputs and outputs. What you do is talk about relations between things. And then finally, we're going to talk about how you implement these things very concretely on the very simplest kind of machines. We'll see something like this. This is a picture of a chip, which is the Lisp interpreter that we will be talking about then in hardware. Well, there's an outline of the course, three big topics. Black-box abstraction, conventional interfaces, metalinguistic abstraction. Now, let's take a break now and then we'll get started. [MUSIC PLAYING] Let's actually start in learning Lisp now. Actually, we'll start out by learning something much more important, maybe the very most important thing in this course, which is not Lisp, in particular, of course, but rather a general framework for thinking about languages that I already alluded to. When somebody tells you they're going to show you a language, what you should say is, what I'd like you to tell me is what are the primitive elements? What does the language come with? Then, what are the ways you put those together? What are the means of combination? What are the things that allow you to take these primitive elements and build bigger things out of them? What are the ways of putting things together? And then, what are the means of abstraction? How do we take those complicated things and draw those boxes around them? How do we name them so that we can now use them as if they were primitive elements in making still more complex things? And so on, and so on, and so on. So when someone says to you, gee, I have a great new computer language, you don't say, how many characters does it take to invert a matrix? It's irrelevant. What you say is, if the language did not come with matrices built in or with something else built in, how could I then build that thing? What are the means of combination which would allow me to do that? And then, what are the means of abstraction which allow me then to use those as elements in making more complicated things yet? Well, we're going to see that Lisp has some primitive data and some primitive procedures. In fact, let's really start. And here's a piece of primitive data in Lisp, number 3. Actually, if I'm being very pedantic, that's not the number 3. That's some symbol that represents Plato's concept of the number 3. And here's another. Here's some more primitive data in Lisp, 17.4. Or actually, some representation of 17.4. And here's another one, 5. Here's another primitive object that's built in Lisp, addition. Actually, to use the same kind of pedantic-- this is a name for the primitive method of adding things. Just like this is a name for Plato's number 3, this is a name for Plato's concept of how you add things. So those are some primitive elements. I can put them together. I can say, gee, what's the sum of 3 and 17.4 and 5? And the way I do that is to say, let's apply the sum operator to these three numbers. And I should get, what? 8, 17. 25.4. So I should be able to ask Lisp what the value of this is, and it will return 25.4. Let's introduce some names. This thing that I typed is called a combination. And a combination consists, in general, of applying an operator -- so this is an operator-- to some operands. These are the operands. And of course, I can make more complex things. The reason I can get complexity out of this is because the operands themselves, in general, can be combinations. So for instance, I could say, what is the sum of 3 and the product of 5 and 6 and 8 and 2? And I should get-- let's see-- 30, 40, 43. So Lisp should tell me that that's 43. Forming combinations is the basic needs of combination that we'll be looking at. And then, well, you see some syntax here. Lisp uses what's called prefix notation, which means that the operator is written to the left of the operands. It's just a convention. And notice, it's fully parenthesized. And the parentheses make it completely unambiguous. So by looking at this, I can see that there's the operator, and there are 1, 2, 3, 4 operands. And I can see that the second operand here is itself some combination that has one operator and two operands. Parentheses in Lisp are a little bit, or are very unlike parentheses in conventional mathematics. In mathematics, we sort of use them to mean grouping, and it sort of doesn't hurt if sometimes you leave out parentheses if people understand that that's a group. And in general, it doesn't hurt if you put in extra parentheses, because that maybe makes the grouping more distinct. Lisp is not like that. In Lisp, you cannot leave out parentheses, and you cannot put in extra parentheses, because putting in parentheses always means, exactly and precisely, this is a combination which has meaning, applying operators to operands. And if I left this out, if I left those parentheses out, it would mean something else. In fact, the way to think about this, is really what I'm doing when I write something like this is writing a tree. So this combination is a tree that has a plus and then a 3 and then a something else and an 8 and a 2. And then this som ething else here is itself a little subtree that has a star and a 5 and a 6. And the way to think of that is, really, what's going on are we're writing these trees, and parentheses are just a way to write this two-dimensional structure as a linear character string. Because at least when Lisp first started and people had teletypes or punch cards or whatever, this was more convenient. Maybe if Lisp started today, the syntax of Lisp would look like that. Well, let's look at what that actually looks like on the computer. Here I have a Lisp interaction set up. There's a editor. And on the top, I'm going to type some values and ask Lisp what they are. So for instance, I can say to Lisp, what's the value of that symbol? That's 3. And I ask Lisp to evaluate it. And there you see Lisp has returned on the bottom, and said, oh yeah, that's 3. Or I can say, what's the sum of 3 and 4 and 8? What's that combination? And ask Lisp to evaluate it. That's 15. Or I can type in something more complicated. I can say, what's the sum of the product of 3 and the sum of 7 and 19.5? And you'll notice here that Lisp has something built in that helps me keep track of all these parentheses. Watch as I type the next closed parentheses, which is going to close the combination starting with the star. The opening one will flash. Here, I'll rub those out and do it again. Type close, and you see that closes the plus. Close again, that closes the star. Now I'm back to the sum, and maybe I'm going to add that all to 4. That closes the plus. Now I have a complete combination, and I can ask Lisp for the value of that. That kind of paren balancing is something that's built into a lot of Lisp systems to help you keep track, because it is kind of hard just by hand doing all these parentheses. There's another kind of convention for keeping track of parentheses. Let me write another complicated combination. Let's take the sum of the product of 3 and 5 and add that to something. And now what I'm going to do is I'm going to indent so that the operands are written vertically. Which the sum of that and the product of 47 and-- let's say the product of 47 with a difference of 20 and 6.8. That means subtract 6.8 from 20. And then you see the parentheses close. Close the minus. Close the star. And now let's get another operator. You see the Lisp editor here is indenting to the right position automatically to help me keep track. I'll do that again. I'll close that last parentheses again. You see it balances the plus. Now I can say, what's the value of that? So those two things, indenting to the right level, which is called pretty printing, and flashing parentheses, are two things that a lot of Lisp systems have built in to help you keep track. And you should learn how to use them. Well, those are the primitives. There's a means of combination. Now let's go up to the means of abstraction. I'd like to be able to take the idea that I do some combination like this, and abstract it and give it a simple name, so I can use that as an element. And I do that in Lisp with "define." So I can say, for example, define A to be the product of 5 and 5. And now I could say, for example, to Lisp, what is the product of A and A? And this should be 25, and this should be 625. And then, crucial thing, I can now use A-- here I've used it in a combination-- but I could use that in other more complicated things that I name in turn. So I could say, define B to be the sum of, we'll say, A and the product of 5 and A. And then close the plus. Let's take a look at that on the computer and see how that looks. So I'll just type what I wrote on the board. I could say, define A to be the product of 5 and 5. And I'll tell that to Lisp. And notice what Lisp responded there with was an A in the bottom. In general, when you type in a definition in Lisp, it responds with the symbol being defined. Now I could say to Lisp, what is the product of A and A? And it says that's 625. I can define B to be the sum of A and the product of 5 and A. Close a paren closes the star. Close the plus. Close the "define." Lisp says, OK, B, there on the bottom. And now I can say to Lisp, what's the value of B? And I can say something more complicated, like what's the sum of A and the quotient of B and 5? That slash is divide, another primitive operator. I've divided B by 5, added it to A. Lisp says, OK, that's 55. So there's what it looks like. There's the basic means of defining something. It's the simplest kind of naming, bu t it's not really very powerful. See, what I'd really like to name-- remember, we're talking about general methods-- I'd like to name, oh, the general idea that, for example, I could multiply 5 by 5, or 6 by 6, or 1,001 by 1,001, 1,001.7 by 1,001.7. I'd like to be able to name the general idea of multiplying something by itself. Well, you know what that is. That's called squaring. And the way I can do that in Lisp is I can say, define to square something x, multiply x by itself. And then having done that, I could say to Lisp, for example, what's the square of 10? And Lisp will say 100. So now let's actually look at that a little more closely. Right, there's the definition of square. To square something, multiply it by itself. You see this x here. That x is kind of a pronoun, which is the something that I'm going to square. And what I do with it is I multiply x, I multiply it by itself. OK. So there's the notation for defining a procedure. Actually, this is a little bit confusing, because this is sort of how I might use square. And I say square root of x or square root of 10, but it's not making it very clear that I'm actually naming something. So let me write this definition in another way that makes it a little bit more clear that I'm naming something. I'll say, "define" square to be lambda of x times xx. Here, I'm naming something square, just like over here, I'm naming something A. The thing that I'm naming square-- here, the thing I named A was the value of this combination. Here, the thing that I'm naming square is this thing that begins with lambda, and lambda is Lisp's way of saying make a procedure. Let's look at that more closely on the slide. The way I read that definition is to say, I define square to be make a procedure-- that's what the lambda is-- make a procedure with an argument named x. And what it does is return the results of multiplying x by itself. Now, in general, we're going to be using this top form of defining, just because it's a little bit more convenient. But don't lose sight of the fact that it's really this. In fact, as far as the Lisp interpreter's concerned, there's no difference between typing this to it and typing this to it. And there's a word for that, sort of syntactic sugar. What syntactic sugar means, it's having somewhat more convenient surface forms for typing something. So this is just really syntactic sugar for this underlying Greek thing with the lambda. And the reason you should remember that is don't forget that, when I write something like this, I'm really naming something. I'm naming something square, and the something that I'm naming square is a procedure that's getting constructed. Well, let's look at that on the computer, too. So I'll come and I'll say, define square of x to be times xx. Now I'll tell Lisp that. It says "square." See, I've named something "square." Now, having done that, I can ask Lisp for, what's the square of 1,001? Or in general, I could say, what's the square of the sum of 5 and 7? The square of 12's 144. Or I can use square itself as an element in some combination. I can say, what's the sum of the square of 3 and the square of 4? 9 and 16 is 25. Or I can use square as an element in some much more complicated thing. I can say, what's the square of, the sqare of, the square of 1,001? And there's the square of the square of the square of 1,001. Or I can say to Lisp, what is square itself? What's the value of that? And Lisp returns some conventional way of telling me that that's a procedure. It says, "compound procedure square." Remember, the value of square is this procedure, and the thing with the stars and the brackets are just Lisp's conventional way of describing that. Let's look at two more examples of defining. Here are two more procedures. I can define the average of x and y to be the sum of x and y divided by 2. Or having had average and mean square, having had average and square, I can use that to talk about the mean square of something, which is the average of the square of x and the square of y. So for example, having done that, I could say, what's the mean square of 2 and 3? And I should get the average of 4 and 9, which is 6.5. The key thing here is that, having defined square, I can use it as if it were primitive. So if we look here on the slide, if I look at mean square, the person defining mean square doesn't have to know, at this point, whether square was something built into the language or whether it was a procedure that was defined. And that's a key thing in Lisp, that you do not make arbitrary distinctions between things that happen to be primitive in the language and things that happen to be built in. A person using that shouldn't even have to know. So the things you construct get used with all the power and flexibility as if they were primitives. In fact, you can drive that home by looking on the computer one more time. We talked about plus. And in fact, if I come here on the computer screen and say, what is the value of plus? Notice what Lisp types out. On the bottom there, it typed out, "compound procedure plus." Because, in this system, it turns out that the addition operator is itself a compound procedure. And if I didn't just type that in, you'd never know that, and it wouldn't make any difference anyway. We don't care. It's below the level of the abstraction that we're dealing with. So the key thing is you cannot tell, should not be able to tell, in general, the difference between things that are built in and things that are compound. Why is that? Because the things that are compound have an abstraction wrapper wrapped around them. We've seen almost all the elements of Lisp now. There's only one more we have to look at, and that is how to make a case analysis. Let me show you what I mean. We might want to think about the mathematical definition of the absolute value functions. I might say the absolute value of x is the function which has the property that it's negative of x. For x less than 0, it's 0 for x equal to 0. And it's x for x greater than 0. And Lisp has a way of making case analyses. Let me define for you absolute value. Say define the absolute value of x is conditional. This means case analysis, COND. If x is less than 0, the answer is negate x. What I've written here is a clause. This whole thing is a conditional clause, and it has two p arts. This part here is a predicate or a condition. That's a condition. And the condition is expressed by something called a predicate, and a predicate in Lisp is some sort of thing that returns either true or false. Andyou see Lisp has a primitive procedure, less-than, that tests whether something is true or false. And the other part of a clause is an action or a thing to do, in the case where that's true. And here, what I'm doing is negating x. The negation operator,the minus sign in Lisp is a little bit funny. If there's two or more arguments, if there's two arguments it subtracts the second one from the first, and we saw that. And if there's one argument, it negates it. So this corresponds to that. And then there's another COND clause. It says, in the case where x is equal to 0, the answer is 0. And in the case where x is greater than 0, the answer is x. Close that clause. Close the COND. Close the definition. And there's the definition of absolute value. And you see it's the case analysis that looks very much like the case analysis you use in mathematics. There's a somewhat different way of writing a restricted case analysis. Often, you have a case analysis where you only have one case, where you test something,and then depending on whether it's true or false, you do something. And here's another definition of absolute value which looks almost the same, which says, if x is less than 0, the result is negate x. Otherwise, the answer is x. And we'll be using "if" alot. But again, the thing to remember is that this form of absolute value that you're looking at here, and then this one over here that I wrote on the board, are essentially the same. And "if" and COND are-- well, whichever way you like it. You can thin k of COND as syntactic sugar for "if," or you can think of "if" as syntactic sugar for COND, and it doesn't make any difference. The person implementing a Lisp system will pick one and implement the other in terms of that. And it doesn't matter which one you pick. Why don't we break now, and then take some questions. How come sometimes when I write define, I put an open paren here and say, define open paren something or other, and sometimes when I write this, I don't put an open paren? The answer is, this particular form of "define," where you say define some expression, is this very special thing for defining procedures. But again, what it really means is I'm defining this symbol, square, to be that. So the way you should think about it is what "define" does is you write "define," and the second thing you write is the symbol here-- no open paren-- the symbol you're defining and what you're defining it to be. That's like here and like here. That's sort of the basic way you use "define." And then, there's this special syntactic trick which allows you to define procedures that look like this. So the difference is, it's whether or not you're defining a procedure. [MUSIC PLAYING] Well, believe it or not, you actually now know enough Lisp to write essentially any numerical procedure that you'd write in a language like FORTRAN or Basic or whatever, or, essentially, any other language. And you're probably saying, that's not believable, because you know that these languages have things like "for statements," and "do until while" or something. But we don't really need any of that. In fact, we're not going to use any of that in this course. Let me show you. Again, looking back at square root, let's go back to this square root algorithm of Heron of Alexandria. Remember what that said. It said, to find an approximation to the square root of X, you make a guess, you improve that guess by averaging the guess and X over the guess. You keep improving that until the guess is good enough. I already alluded to the idea. The idea is that, if the initial guess that you took was actually equal to the square root of X, then G here would be equal to X/G. So if you hit the square root, averaging them wouldn't change it. If the G that you picked was larger than the square root of X, then X/G will be smaller than the square root of X, so that when you average G and X/G, you get something in between. So if you pick a G that's too small, your answer will be too large. If you pick a G that's too large, if your G is larger than the square root of X and X/G will be smaller than the square root of X. So averaging always gives you something in between. And then, it's not quite trivial, but it's possible to show that, in fact, if G misses the square root of X by a little bit, the averag e of G and X/G will actually keep getting closer to the square root of X. So if you keep doing this enough, you'll eventually get as close as you want. And then there's another fact, that you can always start out this process by using 1 as an initial guess. And it'll always converge to the square root of X. So that's this method of successive averaging due to Heron of Alexandria. Let's write it in Lisp. Well, the central idea is, what does it mean to try a guess for the square root of X? Let's write that. So we'll say, define to try a guess for the square root of X, what do we do? We'll say, if the guess is good enough to be a guess for the square root of X, then, as an answer, we'll take the guess. Otherwise, we will try the improved guess. We'll improve that guess for the square root of X, and we'll try that as a guess for the square root of X. Close the "try." Close the "if." Close the "define." So that's how we try a guess. And then, the next part of the process said, in order to compute square roots, we'll say, define to compute the square root of X, we will try 1 as a guess for the square root of X. Well, we have to define a couple more things. We have to say, how is a guess good enough? And how do we improve a guess? So let's look at that. The algorithm to improve a guess for the square root of X, we average-- that was the algorithm-- we average the guess with the quotient of dividing X by the guess. That's how we improve a guess. And to tell whether a guess is good enough, well, we have to decide something. This is supposed to be a guess for the square root of X, so one possible thing you can do is say, when you take that guess and square it, do you get something very close to X? So one way to say that is to say, I square the guess, subtract X from that, and see if the absolute value of that whole thing is less than some small number, which depends on my purposes. So there's a complete procedure for how to compute the square root of X. Let's look at the structure of that a little bit. I have the whole thing. I have the notion of how to compute a square root. That's some kind of module. That's some kind of black box. It's defined in terms of how to try a guess for the square root of X. "Try" is defined in terms of, well, telling whether something is good enough and telling how to improve something. So good enough. "Try" is defined in terms of "good enough" and "improve." And let's see what else I fill in. Well, I'll go down thtree. "Good enough" was defined in terms of absolute value, and square. And improve was defined in terms of something called averaging and then some other primitive operator. Square root's defined in terms of "try." "Try" is defined in terms of "good enough" and "improve," but also "try" itself. So "try" is also defined in terms of how to try itself. Well, that may give you some problems. Your high school geometry teacher probably told you that it's naughty to try and define things in terms of themselves, because it doesn't make sense. But that's false. Sometimes it makes perfect sense to define things in terms of themselves. And this is the case. And we can look at that. We could write down what this means, and say, suppose I asked Lisp what the square root of 2 is. What's the square root of 2 mean? Well, that means I try 1 as a guess for the square root of 2. Now I look. I say, gee, is 1 a good enough guess for the square root of 2? And that depends on the test that "good enough" does. And in this case, "good enough" will say, no, 1 is not a good enough guess for the square root of 2. So that will reduce to saying, I have to try an improved-- improve 1 as a guess for the square root of 2, and try that as a guess for the square root of 2. Improving 1 as a guess for the square root of 2 means I average 1 and 2 divided by 1. So this is going to be average. This piece here will be the average of 1 and the quotient of 2 by 1. That's this piece here. And this is 1.5. So this square root of 2 reduces to trying 1 for the square root of 2, which reduces to trying 1.5 as a guess for the square root of 2. So that makes sense. Let's look at the rest of the process. If I try 1.5, that reduces. 1.5 turns out to be not good enough as a guess for the square root of 2. So that reduces to trying the average of 1.5 and 2 divided by 1.5 as a guess for the square root of 2. That average turns out to be 1.333. So this whole thing reduces to trying 1.333 as a guess for the square root of 2. And then so on. That reduces to a nother called a "good enough," 1.4 something or other. And then it keeps going until the process finally stops with something that "good enough" thinks is good enough, which, in this case, is 1.4142 something or other. So the process makes perfect sense. This, by the way, is called a recursive definition. And the ability to make recursive definitions is a source of incredible power. And as you can already see I've hinted at, it's the thing that effectively allows you to do these infinite computations that go on until something is true, without having any other constricts other than the ability to call a procedure. Well, let's see, there's one more thing. Let me show you a variant of this definition of square root here on the slide. Here's sort of the sam e thing. What I've done here is packaged the definitions of "improve" and "good enough" and "try" inside "square root." So, in effect, what I've done is I've built a square root box. So I've built a box that's the square root procedure that someone can use. They might put in 36 and get out 6. And then, packaged inside this box are the definitions of "try" and "good enough" and "improve." So they're hidden inside this box. And the reason for doing that is that, if someone's using this square root, if George is using this square root, George probably doesn't care very much that, when I implemented square root, I had things inside there called "try" and "good enough" and "improve." And in fact, Harry might have a cube root procedure that has "try" and "good enough" and "improve." And in order to not get the whole system confused, it'd be good for Harry to package his internal procedures inside his cube root procedure. Well, this is called block structure, this particular way of packaging internals inside ofa definition. And let's go back and look at the slide again. The way to read this kind of procedure is to say, to define "square root," well, inside that definition, I'll have the definition of an "improve" and the definition of "good enough" and the defin ition of "try." And then, subject to those definitions, the way I do square root is to try 1. And notice here, I don't have to say 1 as a guess for the square root of X, because since it's all inside the square root, it sort of has this X known. Let me summarize. We started out with the idea that what we're going to be doing is expressing imperative knowledge. And in fact, here's a slide that summarizes the way we looked at Lisp. We started out by looking at some primitive elements in addition and multiplication, some predicates for testing whether something is less-than or something's equal. And in fact, we saw really sneakily in the system we're actually using, these aren't actually primitives, but it doesn't matter. What matters is we're going to use them as if they're primitives. We're not going to look inside. We also have some primitive data and some numbers. We saw some means of composition, means of combination, the basic one being composing functions and building combinations with operato rs and operands. And there were some other things, like COND and "if" and "define." But the main thing about "define," in particular, was that it was the means of abstraction. It was the way that we name things. You can also see from this slide not only where we've been, but holes we have to fill in. At some point, we'll have to talk about how you combine primitive data to get compound data, and how you abstract data so you can use large globs of data as if they were primitive. So that's where we're going. But before we do that, for the next couple of lectures we're going to be talking about, first of all, how it is that you make a link between these procedures we write and the processes that happen in the machine. And then, how it is that you start usin g the power of Lisp to talk not only about these individual little computations, but about general conventional methods of doing things. OK, are there any questions? AUDIENCE: Yes. If we defined A using parentheses instead of as we did, what would be the difference? PROFESSOR: If I wrote this, if I wrote that, what I would be doing is defining a procedure named A. In this case, a procedure of no arguments, which, when I ran it, would give me back 5 times 5. AUDIENCE: Right. I mean, you come up with the same thing, except for you really got a different-- PROFESSOR: Right. And the difference would be, in the old one-- Let me be a little bit clearer here. Let's call this A, like here. And pretend here, just for contrast, I wrote, define D to be the product of 5 and 5. And the difference between those, let's think about interactions with the Lisp interpreter. I could type in A and Lisp would return 25. I could type in D, if I just typed in D, Lisp would return compound procedure D, because that's what it is. It's a procedure. I could run D. I could say, what's the value of running D? Here is a combination with no operands. I see there are no operands. I didn't put any after D. And it would say, oh, that's 25. Or I could say, just for completeness, if I typed in, what's the value of running A? I get an error. The error would be the same one as over there. It'd be the error would say, sorry, 25, which is the value of A, is not an operator that I can apply to something. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec1b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 1B: Procedures and Processes; Substitution Model [MUSIC PLAYING BY J.S. BACH] PROFESSOR: Hi. You've seen that the job of a programmer is to design processes that accomplish particular goals, such as finding the square roots of numbers or other sorts of things you might want to do. We haven't introduced anything else yet. Of course, the way in which a programmer does this is by constructing spells, which are constructed out of procedures and expressions. And that these spells are somehow direct a process to accomplish the goal that was intended by the programmer. In order for the programmer to do this effectively, he has to understand the relationship between the particular things that he writes, these particular spells, and the behavior of the process that he's attempting to control. So what we're doing this lecture is attempt to establish that connecti on in as clear a way as possible. What we will particularly do is understand how particular patterns of procedures and expressions cause particular patterns of execution, particular behaviors from the processes. Let's get down to that. I'm going to start with a very simple program. This is a program to compute the sum of the squares of two numbers. And we'll define the sum of the squares of x and y to be the sum of the square of x-- I'm going to write it that way-- and the square of y where the square of x is the product of x and x. Now, supposing I were to say something to this, like, to the system after having defined these things, of the form, the sum of the squares of 3 and 4, I am hoping that I will get out a 25. Because the square of 3 is 9, and the square of 4 is 16, and 25 is the sum of those. But how does that happen? If we're going to understand processes and how we control them, then we have to have a mapping from the mechanisms of this procedure into the way in which these processes behave. What we're going to have is a formal, or semi-formal, mechanical model whereby you understand how a machine could, in fact, in principle, do this. Whether or not the actual machine really does what I'm about to tell you is completely irrelevant at this moment. In fact, this is an engineering model in the same way that, electrical resistor, we write down a model v equals i r, it's approximately true. It's not really true. If I put up current through the resistor it goes boom. So the voltage is not always proportional to the current, but for some purposes the model is appropriate. In particular, the model we're going to describe right now, which I call the substitution model, is the simplest model that we have for understanding how procedures work and how processes work. How procedures yield processes. And that substitution model will be accurate for most of the things we'll be dealing with in the next few days. But eventually, it will become impossible to sustain the illusion that that's the way the machine works, and we'll go to other more specific and particular models that will show more detail. OK, well, the first thing, of course, is we say, what are the things we have here? We have some cryptic symbols. And these cryptic symbols are made out of pieces. There are kinds of expressions. So let's write down here the kinds of expressions there are. And we have-- and so far I see things like numbers. I see things like symbols like that. We have seen things before like lambda expressions, but they're not here. I'm going to leave them out. Lambda expressions, we'll worry about them later. Things like definitions. Things like conditionals. And finally, things like combinations. These kinds of expressions are-- I'll worry about later-- these are special forms. There are particular rules for each of these. I'm going to tell you, however, the rules for doing a general case. How does one evaluate a combination? Because, in fact, over here, all I really have are combinations and some symbols and numbers. And the sim ple things like a number, well, it will evaluate to itself. In the model I will have for you, the symbols will disappear. They won't be there at the time when you need them, when you need to get at them. So the only thing I really have to explain to you is, how do we evaluate combinations? OK, let's see. So first I want to get the first slide. Here is the rule for evaluating an application. What we have is a rule that says, to evaluate a combination, there are two parts, three parts to the rule. The combination has several parts. It has operators and it has operands. The operator returns into a procedure. If we evaluate the operator, we will get a procedure. And you saw, for example, how I'll type at the machine and out came compound procedure something or other. And the operands produce arguments. Once we've gotten the operator evaluated to get a procedure, and the argument is evaluated to get argument-- the operand's value to get arguments-- we apply the procedure to these arguments by copying the body of the procedure, which is the expression that the procedure is defined in terms of. What is it supposed to do? Substituting the argument supplied for the formal parameters of the procedure, the formal parameters being the names defined by the declaration of the procedure. Then we evaluate the resulting new body, the body resulting from copying the old body with the substitutions made. It's a very simple rule, and we're going to do it very formally for a little while. Because for the next few lectures, what I want you to do is to say, if I don't understand something, if I don't understand something, be very mechanical and do this. So let's see. Let's consider a particular evaluation, the one we were talking about before. The sum of the squares of 3 and 4. What does that mean? It says, take-- well, I could find out what's on the square-- it's some procedure, and I'm not going to worry about the representation, and I'm not going to write it on the blackboard for you. And I have that 3 represents some number, but if I have to repeat that number, I can't tell you the number. The number itself is some abstract thing. There's a numeral which represents it, which I'll call 3, and I'll use that in my substitution. And 4 is also a number. I'm going to substitute 3 for x and 4 for y in the body of this procedure that you see over here. Here's the body of the procedure. It corresponds to this combination, which is an addition. So what that reduces to, as a reduction step, we call it, is the sum of the square of 3 and the square of 4. Now, what's the next step I have to do here? I say, well, I have to evaluate this. According to my rule, which you just saw on that overhead or slide, what we had was that we have to evaluate the operands-- and here are the operands, here's one and here's the next operand-- and how we have to evaluate procedure. The order doesn't matter. And then we're going to apply the procedure, which is plus, and magically somehow that's going to produce the answer. I'm not to open up plus and look inside of it. However, in order to evaluate the operand, let's pick some arbitrary order and do them. I'm going to go from right to left. Well, in order to evaluate this operand, I have to evaluate the parts of it by the same rule. And the parts are I have to find out what square is-- it's some procedure, which has a formal parameter x. And also, I have an operand which is 4, which I have to substitute for x in the body of square. So the next step is basically to say that this is the sum of the square of 3 and the product of 4 and 4. Of course, I could open up asterisk if I liked-- the multiplication operation -- but I'm not going to do that. I'm going to consider that primitive. And, of course, at any level of detail, if you look inside this machine, you're going to find that there's multiple levels below that that you don't know about. But one of the things we have to learn how to do is ignore details. The key to understanding complicated things is to know what not to look at and what not compute and what not to think. So we're going to stop this one here and say, oh, yes, this is the product of two things. We're going to do it now. So this is nothing more than the sum of the square of 3 and 16. And now I have another thing I have to evaluate, but that square of 3, well, it's the same thing. That's the sum of the product of 3 and 3 and 16, which is the sum of 9 and 16, which is 25. So now you see the basic method of doing substitutions. And I warn you that this is not a perfect description of what the computer does. But it's a good enough description for the problems that we're going to have in the next few lectures that you should think about this religiously. And this is how the machine works for now. Later we'll get more detailed. Now, of course, I made a specific choice of the order of evaluation here. There are other possibilities. If we go back to the telestrator here and look atthe substitution rule, we see that I evaluated the operator to get the procedures, and I evaluated the operands to get the arguments first, before I do the application. It's entirely possible, and there are alternate rules called normal order evaluation whereby you can do the substitution of the expressions which are the operands for the formal parameters inside the body first. And you'll get also the same answer. But right now, for concreteness, and because this is the way our machine really does it, Im ' going to give you this rule, which has a particular order. But that order is to some extent arbitrary, too. In the long run, there are some reasons why you might pick one order or another, and we'll get to that later in the subject. OK, well now the only other thing I have to tell you about just to understand what's going on is let's look at the rule for conditionals. Conditionals are very simple, and I'd like to examine this. A conditional is something that is if -- there's also cond, of course-- but I'm going to give names to the parts of the expression. There's a predicate, which is a thing that is either true or false. And there's a consequent, which is the thing you do if the predicate is true. And there's an alternative, which is the thing you do if the predicate is false. It's important, by the way, to get names for, to get names for, the parts of things, or the parts of expressions. One of the things that every sorcerer will tell you is if you have the name of a spirit, you have power over it. So you have to learn these names so that we can discuss these things. So here we have a predicate, a consequent, and an alternative. And, using such words, we see that an if expression, the problems you evaluate to the predicate expression, if that yields true, then you then go on to evaluate the consequent. Otherwise, you evaluate the alternative expression. So I'd like to illustrate that now in the context of a particular little program. Going to write down a program which we're going to see many times. This is the sum of x and y done by what's called Peano arithmetic, which is all we're doing is incrementing and decrementing. And we're going to see this for a little bit. It's a very important program. If x equals o, then the result is y. Otherwise, this is the sum of the decrement of x and the increment of y. We're going to look at this a lot more in the future. Let's look at the overhead. So here we have this procedure, and we're going to look at how we do the substitutions, the sequence of substitutions. Well, I'm going to try and add together 3 and 4. Well, using the first rule that I showed you, we substitute 3 for x and 4 four y in the body of this procedure. The body of the procedure is the thing that begins with if and finishes over here. So what we get is, of course, if 3 is 0, then the result is 4. Otherwise, it's the sum of the decrement of 3 and the increment of 4. But I'm not going to worry about these yet because 3 is not 0. So the answer is not 4. Therefore, this if reduces to an evaluation of the expression, the sum to the decrement of 3 and the increment of 4. Continuing with my evaluation, the increment I presume to be primitive, and so I get a 5 there. OK, and then the decrement is also primitive, and Iget a 2. And so I change the problem into a simpler problem. Instead of adding 3 to 4, I'm adding 2 to 5. The reason why this is a simpler problem is because I'm counting down on x, and eventually, then, x will be 0. So, so much for the substitution rule. In general, I'm not going to write down intermediate steps when using substitutions having to do with ifs, because they just expand things to become complicated. What we will be doing is saying, oh, yes, the sum of 3 and 4 results in the sum of 2 and 5 and reduces to the sum of 2 and 5, which, in fact, reduces to the sum of 1 and 6, which reduces to the sum of 0 and 7 over here, which reduces to a 7. That's what we're going to be seeing. Are there any questions for the first segment yet? Yes? STUDENT: You're using 1 plus and minus 1 plus. Are those primitive operations? PROFESSOR: Yes. One of the things you're going to be seeing in this subject is I'm going to, without thinking about it, introduce more and more primitive operations. There's presumably some large library of primitive operations somewhere. But it doesn't matter that they're primitive-- there may be some manual that lists them all. If I tell you what they do, you say, oh, yes, I know what they do. So one of them is the decrementor -- minus 1 plus-- and the other operation is increment, which is 1 plus. Thank you. That's the end of the first segment. [MUSIC PLAYING BY J.S. BACH] PROFESSOR: Now that we have a reasonably mechanical way of understanding how a program made out of procedures and expressions evolves a process, I'd like to develop some intuition about how particular programs evolve particular processes, what the shapes of programs have to be in order to get particular shaped processes. This is a question about, really, pre-visualizing. That's a word from photography. I used to be interested in photography a lot, and one of the things you discover when you start trying to learn about photography is that you say, gee, I'd like to be a creative photographer. Now, I know the rules, I push buttons, and I adjust the aperture and things like that. But the key to being a creative person, partly, is to be able to do analysis at some level. To say, how do I know what it is that I'm going to get on the film before I push the button. Can I imagine in my mind the resulting image very precisely and clearly as a consequence of the particular framing, of the aperture I choose, of the focus, and things like that? That's part of the art of doing this sort of thing. And learning a lot of that involves things like test strips. You take very simple images that have varying degrees of density in them, for example, and examine what those look like on a piece of paper when you print them out. You find out what is the range of contrasts that you can actually see. And what, in a real scene, would correspond to the various levels and zones that you have of density in an image. Well, today I want to look at some very particular test strips, and I suppose one of them I see here is up on the telestrator, so we should switch to that. There's a very important, very important pair of programs for understanding what's going on in the evolution of a process by the execution of a program. What we have here are two procedures that are almost identical. Almost n o difference between them at all. It's a few characters that distinguish them. These are two ways of adding numbers together. The first one, which you see here, the first one is the sum of two numbers -- just what we did before-- is, if the first one is 0 , it's the answer of the second one. Otherwise, it's the sum of the decrement of the first and the increment of the second. And you may think of that as having two piles. And the way I'm adding these numbers together to make a third pile is by moving marbles from one to the other. Nothing more than that. And eventually, when I run out of one, then the other is the sum. However, the second procedure here doesn't do it that way. It says if the first number is 0, then the answer is the second. Otherwise, it's the increment of the sum of the decrement of the first number and the second. So what this says is add together the decrement of the first number and the second-- a simpler problem, no doubt-- and then change that result to increment it. And so this means that if you think about this in terms of piles, it means I'm holding in my hand the things to be added later. And then I'm going to add them in. As I slowly decrease one pile to 0, I've got what's left here, and then I'm going to add them back. Two dif ferent ways of adding. The nice thing about these two programs is that they're almost identical. The only thing is where I put the increment. A couple of characters moved around. Now I want to understand the kind of behavior we're going to get from each of these programs. Just to get them firmly in your mind-- I usually don't want to be this careful-- but just to get them firmly in your mind, I'm going to write the programs again on the blackboard, and then I'm going to evolve a process. And you're going to see what happens. We're going to look at the shape of the process as a consequence of the program. So the program we started with is this: the sum of x and y says if x is 0, then the result is y. Otherwise, it's the sum of the decrement of x and the increment of y. Now, supposing we wish to do this addition of 3 and 4, the sum of 3 and 4, well, what is that? It says that I have to substitute the arguments for the formal parameters in the body. I'm doing that in my mind. And I say, oh, yes, 3 is substituted for x, but 3 is not 0, so I'm going to go directly to this part and write down the simplified consequent here. Because I'm really interested in the behavior of addition. Well, what is that? That therefore turns into the sum of 2 and 5. In other wo rds, I've reduced this problem to this problem. Then I reduce this problem to the sum of 1 and 6, and then, going around again once, I get the sum of 0 and 7. And that's one where x equals 0 so the result is y, and so I write down here a 7. So this is the behavior of the process evolved by trying to add together 3 and 4 with this program. For the other program, which is over here, I will define the sum of x and y. And what is it? If x is 0, then the result is y-- almost the same-- otherwise the increment of the sum of the decrement of x and y. No. I don't have my balancer in front of me. OK, well, let's do it now. The sum of 3 and 4. Well, this is actually a little more interesting. Of course, 3 is not 0 as before, so that results in the increment of thesum of the decrement of x, which is 2 and 4, which is the increment of the sum of 1 and -- whoops: the increment of the increment. What I have to do now is compute what this means. I have to evaluate this. Or what that is, the result of substituting 2 and 4 for x and y here. But that is the increment of the sum of 1 and 4, which is-- well, now I have to expand this. Ah, but that's the increment of the increment of the increment of the sum of 0 and 4. Ah, but now I'm beginning to find things I can do. The increment of the increment of the increment of-- well, the sum of 0 and 4 is 4. The increment of 4 is 5. So this is the increment of the increment of 5, which is the increment of 6, which is 7. Two different ways of computing sums. Now, let's see. These processes have very different shapes. I want you to feel these shapes. It's the feeling for the shapes that matters. What's some things we can see about this? Well, somehow this is sort of straight. It goes this way-- straight. This right edge doesn't vary particularly in size. Whereas this one, I see that this thing gets bigger and then it gets smaller. So I don't know what that means yet, but what are we seeing? We're seeing here that somehow these increments are expanding out and then contracting back. I'm building up a bunch of them to do later. I can't do them now. There's things to be deferred. Well, let's see. I can imagine an abstract machine. There's some physical machine, perhaps, that could be built to do it, which, in fact, executes these programs exactly as I tell you, substituting character strings in like this. Such a machine, the number of such steps is an approximation of the amount of time it takes. So this way is time. And the width of the thing is how much I have to remember in order to continue the process. And this much is space. And what we see here is a process that takes a time which is proportional to the argument x. Because if I made x larger by 1, then I'd had an extra line. So this is a process which is space-- sorry-- time. The time of this process is what we say order of x. That means it is proportional to x by some constant of proportionality, and I'm not particularly interested in what the constant is. The other thing we se e here is that the amount of space this takes up is constant, it's proportional to 1. So the space complexity of this is order of 1. We have a name for such a process. Such a process is called an iteration. And what matters here is not that some particular machine I designed here and talked to you about and called a substitution machine or whatever-- substitution model-- managed to do this in constant space. What really matters is this tells us a bound. Any machine could do this in constant space. This algorithm represented by this procedure is executable in constant space. Now, of course, the model is ignoring some things, standard sorts of things. Like numbers that are bigger take up more space and so on. But that's a level of abstraction at which I'm cutting off. How do you represent numbers? I'm considering every number to be the same size. And numbers grow slowly for the amount of space they take up and their size. Now, this algorithm is different in its complexity. As we can see here, this algorit hm has a time complexity which is also proportional to the input argument x. That's because if I were to add 1 to 3, if I made a larger problem, which is larger by 1 here, then I'd add a line at the top and I'd add a line at the bottom. And the fact that it's a constant amount, like this is twice as many lines as that, is not interesting at the level of detail I'm talking about right now. So this is a time complexity order of the input argument x. And space complexity, well, this is more interesting. I happen to have some overhead, which you see over here, which is constant approximately. Constant overhead. But then I have something which increases and decreases and is proportional to the input argument x. The input argument x is 3. That's why there are three deferred increments sitting around here. See? So the space complexity here is also order x. And this kind of process, named for the kind of process, this is a recursion. A linear recursion, I will call it, because of the fact that it's proportional to the input argument in both time and space. This could have been a linear iteration. So then what's the essence of this matter? This matter isn't so obvious. Maybe there are other models by which we can describe the differences between iterative and recursive processes. Because this is hard now. Remember, we have-- those are both recursive definitions. What we're seeing there are both recursive definitions, definitions that refer to the thing being defined in the definition. But they lead to different sh ape processes. There's nothing special about the fact that the definition is recursive that leads to a recursive process. OK. Let's think of another model. I'm going to talk to you about bureaucracy. Bureaucracy is sort of interesting. Here we see on a slide an iteration. An iteration is sort of a fun kind of process. Imagine that there's a fellow called GJS-- that stands for me-- and he's got a problem: he wants to add together 3 and 4. This fella here wants to add together 3 and 4. Well, the way he's going to do it-- he's lazy-- is he's going to find somebody else to help him do it. They way he finds someone else to-- he finds someone else to help him do it and says, well, give me the answer to 3 and 4 and return the result to me. He makes a little piece of paper and says, here, here's a piece of paper-- you go ahead and solve this problem and give the result back to me. And this guy, of course, is lazy, too. He doesn't want to see this piece of paper again. He says, oh, yes, produce a new problem, which is the sum of 2 ad 5, and return the result back to GJS. I don't want to see it again. This guy does not want to see this piece of paper. And then this fellow makes a new problem, which is the addition of the sum of 1 and 6, and he give it to this fella and says, produce that answer and returned it to GJS. And that produces a problem, which is to add together 0 and 7, and give the result to GJS. This fella finally just says, oh, yeah, the answer is 7, and sends it back to GJS. That's what an iteration is. By contrast, a recursion is a slightly different kind of process. This one involves more bureaucracy. It keeps more people busy. It keeps more people employed. Perhaps it's better for that reason. But here it is: I want the answer to the problem 3 and 4. So I make a piece of paper that says, give the result back to me. Give it to this fella. This fellow says, oh, yes, I will remember that I have to add later, and I want to get the answer the problem 2 plus 4, give that one to Harry, and have the results sent back to me-- I'm Joe. When the answer comes back from Harry, which is a 6, I will then do the increment and give that 7 back to GJS. So there are more pieces of paper outstanding in the recursive process than the iteration. There's another way to think about what an iteration is and the difference between an iteration and a recursion. You see, the question is, how much stuff is under the table? If I were to stop-- supposing I were to kill this computer right now, OK? And at this point I lose the state of affairs, well, I could continue the computation from this point but everything I need to continue the computation is in the valuables that were defined in the procedure that the programmer wrote for me. An iteration is a system that has all of itsstate in explicit variables. Whereas the recursion is not quite the same. If I were to lose this pile of junk over here, and all I was left with was the sum of 1 and 4, that's not enough information to continue the process of computing out the 7 from the original problem of adding together 3 of 4. Besides the information that's in the variables of the formal parameters of the program, there is also information under the table belonging to the computer, which is what things have been deferred for later. And, of course, there's a physical analogy to this, which is in differential equations, for example, when we talk about something like drawing a circle. Try to draw a circle, you make that out of a differential equation which says the change in my state as a function of my current state. So if my current state corresponds to particular values of y and x, then I can compute from them a derivative which says how the state must change. And, in fact, you can see this was a circle because if I happen to be, say, at this place over here, at 1, 0, for example, on this graph, then it means that the derivative of y is x, which we see over here. That's 1, so I'm going up. And the derivative of x is minus y, which means I'm going backwards. I'm actually doing nothing at this point, then I start going backwards as y increases. So that's how you make a circle. And the interesting thing to see is a little program that will draw a circle by this method. Actually, this won't draw a circle because it's a forward oil or integrator and will eventually spiral out and all that. But it'll draw a circle for a while before it starts spiraling. However, what we see here is two state variables, x and y. And there's an iteration that says, in order to circle, given an x and y, what I want is to circle with the next values of x and y being the old value of x decrement by y times dt where dt is the time step and the old value of y being implemented by x times dt, giving me the new values of x and y. So now you have a feeling for at least two different kinds of processes that can be evolved by almost the same program. And with a little bit of perturbation analysis like this, how you change a program a little bit and see how the process changes, that's how we get some intuition. Pretty soon we're going to use that intuition to build big, hairy, complicated systems. Thank you. [MUSIC PLAYING BY J.S. BACH] PROFESSOR: Well, you've just seen a simple perturbational analysis of some programs. I took a program that was very similar to another program and looked at them both and saw how they evolved processes. I want to show you some variety by showing you some other processes and shapes they may have. Again, we're going to take very simple things, programs that you wouldn't want to ever write. They would be probably the worst way of computing some of the things we're going to compute. But I'm just going to show you these things for the purpose of feeling out how to program represents itself as the rule for the evolution of a process. So let's consider a fun thing, the Fibonacci numbers. You probably know about the Fibonacci numbers. Somebody, I can't remember who, was interested in the growth of piles of rabbits. And for some reason or other, the piles of rabbits tend to grow exponenti ally, as we know. And we have a nice model for this process, is that we start with two numbers, 0 and 1. And then every number after this is the sum of the two previous. So we have here a 1. Then the sum of these two is 2. The sum of those two is 3. The sum of those two is 5. The sum of those two is 8. The sum of those two is 13. This is 21. 34. 55. Et cetera. If we start numbering these numbers, say this is the zeroth one, the first one, the second one, the third one, the fourth one, et cetera. This isthe 10th one, the 10th Fibonacci number. These numbers grow very fast. Just like rabbits. Why rabbits grow this way I'm not going to hazard a guess. Now, I'm going to try to write for you the very simplest program that computes Fibonacci numbers. What I want is a program that, given an n, will produce for me Fibonacci event. OK? I'll write it right here. I want the Fibonacci of n, which means the -- this is the n, and this is Fibonacci of n. And here's the story. If n is less than 2, then the result is n. Because that's what these are. That's how you start it up. Otherwise, the result is the sum of Fib of n minus 1 and the Fibonacci number, n minus 2. So this is a very simple, direct specification of the description of Fibonacci numbers that I gave you when I introduced those numbers. It represents the recurrence relation in the simplest possible way. Now, how do we use such a thing? Let's draw this process. Let's figure out what this does. Let's consider something very simple by computing Fibonacci of 4. To compute Fibonacci of 4, what do I do? Well, it says I have-- it's not less than 2. Therefore it's the sum of two things. Well, in order to compute that I have to compute, then, Fibonacci of 3 and Fibonacci of 2. In order to compute Fibonacci of 3, I have to compute Fibonacci of 2 and Fibonacci of 1. In order to compute Fibonacci of 2, I have to compute Fibonacci of 1 and Fibonacci of 0. In order to compute Fibonacci of 1, well, the answer is 1. That's from the base case of this recursion. And in order to compute Fibonacci of 0, well, that answer is 0, from the same base. And here is a 1. And Fibonacci of 2 is really the sum of Fibonacci of 1. And Fib of 0, in order to compute that, I get a 1, and here I've got a 0. I've built a tree. Now, we can observe some things about this tree. We can see why this is an extremely bad way to compute Fibonacci numbers. Because in order to compute Fibonacci of 4, I had to compute Fibonacci of 2's sub-tree twice. In fact, in order way to add one more, supposing I want to do Fibonacci of 5, what I really have to do then is compute Fibonacci of 4 plus Fibonacci of 3. But Fibonacci of 3's sub-tree has already been built. This is a prescription for a process that's exponential in time. To add 1, I have to multiply by something because I take a proportion of the existing thing and add it to itself to add one more step. So this is a thing whose time complexity is order of -- actually, it turns out to be Fibonacci-- of n. There's a thing that grows exactly at Fibonacci numbers. It's a horrible thing. You wouldn't want to do it. The reason why the time has to grow that way is because we're presuming in the model-- the substitution model that I gave you, which I'm not doing formally here, I sort of now spit it out in a simple way-- but presuming that everything is done sequentially. That every one of these nodes in this tree has to be examined. And so since the number of nodes in this tree grows exponentially, because I add a proportion of the existing nodes to the nodes I already have to add 1, then I know I've got an exponential explosion here. Now, let's see if we can think of how much space this takes up. Well, it's not so bad. It depends on how much we have to remember in order to continue this thing running. Well, that's not so hard. It says, gee, in order to know where I am in this tree, I have to have a path back to the root. In other words, in order to-- let's consider the path I would have to execute this. I'd say, oh, yes, I'm going to go down here. I don't care which direction I go. I have to do this. I have to then do this. I have to traverse this tree in a sort of funny way. I'm going to walk this nice little path. I come back to here. Well, I've got to remember where I'm going to be next. I've got to keep that in mind. So I have to know what I've done. I have to know what's left. In order to compute Fibonacci of 4, at some point I'm going to have to be down here. And I have to remember that I have to go back and then go back to here to do an addition. And then go back to here to do an addition to something I haven't touched yet. The amount of space that takes up is the path, the longest path. How long it is. And that grows as n. So the space-- because that's the length of the deepest line through the tree-- the space is order of n. It's a pretty bad process. Now, one thing I want to see from this is a feeling of what's going on here. Why are there -- how is this program related to this process? Well, what are we seeing here? There really are only two sorts of things this program does. This program consists of two rules, if you will. One rule that says Fibonacci of n is this sum that you see over here, which is a node that's shaped like this. It says that I break up something into two parts. Under some condition over here that n is greater than 2, then the node breaks up into two parts. Less than 2. No. Greater than 2. Yes. The other possibility is that I have a reduction that looks like this. And that's this case. If it's less than 2, the answer is n itself. So what we're seeing here is that the process that got built locally at every place is an instance of this rule. Here's one instance of the rule. Here is another instance of the rule. And the reason why people think of programming as being hard, of course, is because you're writing down a general rule, which is going to be used for lots of instances, that a particular instance-- it's going to control each particular instance for you. You've got to write down something that's a general in terms of variables, and you have to think of all the things that could possibly fit in those variables, and all those have to lead to the process you want to work. Locally, you have to break up your process into things that can be represented in terms of these very specific local rules. Well, let's see. Fibonaccis are, of course, not much fun. Yes, they are. You get something called the golden ratio, and we may even see a lot of that some time. Well, let's talk about another thing. There's a famous game called the T owers of Hanoi, because I want to teach you how to think about these recursively. The problem is this one: I have a bunch of disks, I have a bunch of spikes, and it's rumored that somewhere in the Orient there is a 64-high tower, and the job of various monks or something is to move these spikes in some complicated pattern so eventually -- these disks- - so eventually I moved all of the disks from one spike to the other. And if it's 64 high, and it's going to take 2 to the 64th moves, then it's a long time. They claim that the universe ends when this is done. Well, let's see. The way in which you would construct a recursive process is by wishful thinking. You have to believe. So, the idea. Supposing I want to move this pile from here to here, from spike one to spike two, well, that's not so hard. See, supposing somehow, by some magic-- because I've got a simpler problem-- I move a three-high pile to here-- I can only move one disk at a time, so identifying how I did it. But supposing I could do that, well, then I could just pick up this disk and move it here. And now I have a simple problem. I have to move a three-high tower to here, which is no problem. So by two moves of a three high tower plus one move of a single object, I can move the tower from here to here. Now, whether or not-- this is not obvious in any deep way that this works. And why? Now, why is it the case that I can presume, maybe, that I can move the three-high tower? Well, the answer is because I'm always counting down, and eventually I get down to zero -high tower, and a zero-high tower requires no moves. So let's write the algorithm for that. Very easy. I'm going to label these towers with numbers, but it doesn't matter what they're labelled with. And the problem is to move an n - high tower from a spike called From to a spike called To with a particular spike called Spare. That's what we're going to do. Using the algorithm I informally described to you, move of a n-high tower from From to To with a Spare. Well, I've got two cases, and this is a case analysis, just like it is in all the other things we've done. If n is 0, then-- I'm going to put out some answers-- Done, we'll say. I don't know what that means. Because we'll never use that answer for anything. We're going to do these moves. Else. I'm going to do a move. Move a tower of height less than n, the decrement of n height. Now, I'm going to move it to the Spare tower. The whole idea now is to move this from here to here, to the Spare tower-- so from From to Spare-- using To as a spare tower. Later, somewhere later, I'm going to move that same n-high tower, after I've done this. Going to move that same n minus one-high tower from the Spare tower to the To tower using the From tower as my spare. So the Spare tower to the To tower using the From as the spare. All I have to do now is when I've gotten it in this condition, between these two moves of a whole tower-- I've got it into that condition-- now I just have to move one disk. So I'm going to say that some things are printing a move and I don't care how it works. From the To. Now, you see the reason why I'm bringing this up at this moment is this is an almost identical program to this one in some sense. It's not computing the same mathematical quantity, it's not exactly the same tree, but it's going to produce a tree. The general way of making these moves is going to lead to an exponential tree. Well, let's do this four -high. I have my little crib sheet here ot herwise I get confused. Well, what I'm going to put in is the question of move a tower of height four from one to spike two using spike three as a spare. That's all I'm really going to do. You know, let's just do it. I'm not going to worry about writing out the traits of this. You can do that yourself because it's very simple. I'm going to move disk one to disk three. And how do I get to move disk one to disk three? How do I know that? Well, I suppose I have to look at the trace a little bit. What am I do ing here? Well, and this is not -- n is not zero. So I'm going to look down here. This is going to require doing two moves. I'm only going to look at the first one. It's going to require moving-- why do I have move tower? It makes it harder for me to move.I'm going to move a three-high tower from the from place, which is four, to the spare, which is two, using three as my-- no, using from-- STUDENT: [INAUDIBLE PHRASE]. PROFESSOR: Yes. I'm sorry. From two-- from one to three using two as my spare. That's right. And then there's another move over here afterwards. So now I say, oh, yes, that requires me moving a two-high tower from one to two using three as a spare. And so, are the same, and that's going to require me moving and one-high tower from one to three using two as a spare. Well, and then there's lots of other things to be done. So I move my one-high tower from one to three using two as a spare, which I didn't do anything with. Well, this thing just proceeds very simply. I move this from one to two. And I move this disk from three to two. And I don't really want to do it, but I move from one to three. Then I move two to one. Then I move two to three. Then one to three. One to two. Three to two. Three to one. This all got worked out beforehand, of course. Two to one. Three to two. One to three. STUDENT: [INAUDIBLE PHRASE]. PROFESSOR: Oh, one to three. Excuse me. Thank you. One to two. And then three to two. Whew. Now what I'd like you to think about, you just saw a recursive algorithm for doing this, and it takes exponential time, of course. Now, I don't know if there's any algorithm that doesn't take exponential time-- it has to. As I'm doing one operation-- I can only move one thing at a time-- there's no algorithm that's not going to take exponential time. But can you write an iterative algorithm rather than a recursive algorithm for doing this? One of the sort of little things I like to think about. Can you write one that, in fact, doesn't break this problem into two sub-problems the way I described, but rather proceeds a step at a time using a more local rule? That might be fun. Thank you so much for the third segment. Are there questions? STUDENT: [INAUDIBLE] a way to reduce a tree or recursion problem, how do you save the immediate work you have done in computing the Fibonacci number? PROFESSOR: Oh, well, in fact, one of the ways to do is what you just said. You said, I save the intermediate work. OK? Well, let me tell you-- this, again, we'll see later -- but suppose it's the case that anytime I compute anything, any one of these Fibonacci numbers, I remember the table that takes only linear time to look up the answer. Then if I ever see it again, instead of doing the expansional tree, I look it up. I've just transformed my problem into a problem that's much simpler. Now, of course, there are the way to do this, a s well. That one's called memoization, and you'll see it sometime later in this term. But I suppose there's a very simple linear time, and, in fact, iterative model for computing Fibonaccis, and that's another thing you should sit down and work out. That's important. It's important to see how to do this. I want you to practice. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec2a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 2A: Higher-order Procedures PROFESSOR: Well, yesterday was easy. You learned all of the rules of programming and lived. Almost all of them. And so at this point, you're now certified programmers -- it says. However, I suppose what we did is we, aah, sort of got you a little bit of into an easy state. Here, you still believe it's possible that this might be programming in BASIC or Pascal with just a funny syntax. Today, that illusion-- or you can no longer support that belief. What we're going to do today is going to completely smash that. So let's start out by writing a few programs on the blackboard that have a lot in common with each other. What we're going to do is try to make them abstractions that are not ones that are easy to make in most languages. Let's start with some very si mple ones that you can make in most languages. Supposing I want to write the mathematical expression which adds up a bunch of integers. So if I wanted to write down and say the sum from i equal a to b on i. Now, you know that that's an easy thing to compute in a closed form for it, and I'm not interested in that. But I'm going to write a program that adds up those integers. Well, that's rather easy to do to say I want to define the sum of the integers from a to b to be-- well, it's the following two possibilities. If a is greater than b, well, then there's nothing to be done and the answer is zero. This is how you're going to have to think recursively. You're going to say if I have an easy case that I know the answer to, just write it down. Otherwise, I'm going to try to reduce this problem to a simpler problem. And maybe in this case, I'm going to make a subproblem of the simpler problem and then do something to the result. So the easiest way to do this is say that I'm going to add the index, which in this case is a, to the result of adding up the integers from a plus 1 to b. Now, at this point, you should have no trouble looking at such a definition. Indeed, coming up with such a thing might be a little hard in synthesis, but being able to read it at this point should be easy. And what it says to you is, well, here is the subproblem I'm going to solve. I'm going to try to add up the integers, one fewer integer than I added up for the the whole problem. I'm adding up the one fewer one, and that subproblem, once I've solved it, I'm going to add a to that, and that will be the answer to this problem. And the simplest case, I don't have to do any work. Now, I'm also going to write down another simple one just like this, which is the mathematical expression, the sum of the square from i equal a to b. And again, it's a very simple program. And indeed, it starts the same way. If a is greater than b, then the answer is zero. And, of course, we're beginning to see that there's something wrong with me writing this down again. It's the same program. It's the sum of the square of a and the sum of the square of the increment and b. Now, if you look at these things, these programs are almost identical. There's not much to distinguish them. They have the same first clause of the conditional and the same predicate and the same consequence, and the alternatives are very similar, too. They only differ by the fact that where here I have a, here, I have the square of a. The only other difference, but this one's sort of unessential is in the name of this procedure is sum int, whereas the name of the procedure is sum square. So the things that vary between these two are very small. Now, wherever you see yourself writing the same thing down more than once, there's something wrong, and you shouldn't be doing it. And the reason is not because it's a waste of time to write something down more than once. It's because there's some idea here, a very simple idea, which has to do with the sigma notation-- this much-- not depending upon what it is I'm adding up. And I would like to be able to-- always, whenever trying to make complicated systems and understand them, it's crucial to divide the things up into as many pieces as I can, each of which I understand separately. I would like to understand the way of adding things up independently of what it is I'm adding up so I can do that having debugged it once and understood it once and having been able to share that among many different uses of it. Here, we have another example. This is Leibnitz's formula for finding pi over 8. It's a funny, ugly mess. What is it? It's something like 1 over 1 times 3 plus 1 over 5 times 7 plus 1 over 9 times 11 plus-- and for some reason, things like this tend to have interesting values like pi over 8. But what do we see here? It's the same program or almost the same program. It's a sum. So we're seeing the figure notation, although over here, we're dealing with incrementing by 4, so it's a slightly different problem, which means that over here, I have to change a by 4, as you see right over here. It's not by 1. The other thing, of course, is that the thing that's represented by square in the previous sum of squares, or a when adding up the integers. Well, here, I have a different thing I'm adding up, a different term, which is 1 over a times a plus 2. But the rest of this program is identical. Well, any time we have a bunch of things like this that are identical, we're going to have to come up with some sort of abstraction to cover them. If you think about this, what you've learned so far is the rules of some language, some primitive, some means of combination, almost all of them, the means of abstraction, almost all of them. But what you haven't learned is common patterns of usage. Now, most of the time, you learn idioms when learning a language, which is a common pattern that mean things that are useful to know in a flash. And if you build a great number of them, if you're a FORTRAN programmer, of course, everybody knows how to-- what do you do, for example, to get an integer which is the biggest integer in something. It's a classic thing. Every FORTRAN programmer knows how to do that. And if you don't know that, you're in real hot water because it takes a long time to think it out. However, one of the things you can do in this language that we're showing you is not only do you know something like that, but you give the knowledge of that a name. And so that's what we're going to be going after right now. OK, well, let's see what these things have in common. Right over here we have what appears to be a general pattern, a general pattern which covers all of the cases we've seen so far. There is a sum procedure, which is being defined. It has two arguments, which are a lower bound and an upper bound. The lower bound is tested to be greater than the upper bound, and if it is greater, then the result is zero. Otherwise, we're going to do something to the lower bound, which is the index of the conversation, and add that result to the result of following the procedure recursively on our lower bound incremented by some next operation with the same upper bound as I had before. So this is a general pattern, and what I'd like to do is be able to name this general pattern a bit. Well, that's sort of easy, because one of the things I'm going to do right now is-- there's nothing very special about numbers. Numbers are just one kind of data. It seems to me perfectly reasonable to give all sorts of names to all kinds of data, for example, procedures. And now many languages allow you have procedural arguments, and right now, we're going to talk about procedural arguments. They're very easy to deal with. And shortly, we'll do some remarkable things that are not like procedural arguments. So here, we'll define our sigma notation. This is called sum and it takes a term, an A, a next term, and B as arguments. So it takes four arguments, and there was nothing particularly special about me writing this in lowercase. I hope that it doesn't confuse you, so I' ll write it in uppercase right now. The machine doesn't care. But these two arguments are different. These are not numbers. These are going to be procedures for computing something given a number. Term will be a procedure which, when given an index, will produce the value of the term for that index. Next will be given an index, which will produce the next index. This will be for counting. And it's very simple. It's exactly what you see. If A is greater than B, then the result is 0. Otherwise, it's the sum of term applied to A and the sum of term, next index. Let me write it this way. Now, I'd like you to see something, first of all. I was writing here, and I ran out of space. What I did is I start indenting according to the Pretty-printing rule, which says that I align all of the arguments of the procedure so I can see which ones go together. And this is just something I do automatically, and I want you to learn how to do that, too, so your programs can be read and understood. However, what do we have here? We have four arguments: the procedure, the lower index- - lower bound index-- the way to get the next index, and the upper bound. What's passed along on the recursive call is indeed the same procedure because I'm going to need it again, the next index, which is using the next procedure to compute it, the procedure for computing next, which I also have to have separately, and that's different. The procedure for computing next is different from the next index, which is the result of using next on the last index. And I also have to pass along the upper bound. So this captures both of these and the other nice program that we are playing with. So using this, we can write down the original program as instances of sum very simply. A and B. Well, I'm going to need an identity procedure here because ,ahh, the sum of the integers requires me to in this case compute a term for every integer, but the term procedure doesn't want to do anything to that integer. So the identity procedure on A is A or X or whatever, and I want to say the sum of using identity of the term procedure and using A as the initial index and the incrementer being the way to get the next index and B being the high bound, the upper bound. This procedure does exactly the same as the sum of the integers over here, computes the same answer. Now, one thing you should see, of course, is that there's nothing very special over here about what I used as the formal parameter. I could have, for example, written this X. It doesn't matter. I just wanted you to see that this name does not conflict with this one at all. It's an internal name. For the second procedure here, the sum of the squares, it's even a little bit easier. And what do we have to do? Nothing more than add up the squares, this is the procedure that each index will be given, will be given each-- yes. Each index will have this done to it to get the term. That's the thing that maps against term over here. Then I have A as the lower bound, the incrementer as the next term method, and B as the upper bound. And finally, just for the thing that we did about pi sums, pi sums are sort of-- well, it's even easier to think about them this way because I don't have to think. What I'm doing is separating the thing I'm adding up from the method of doing the addition. And so we have here, for example, pi sum A B of the sum of things. I'm going to write the terms procedure here explicitly without giving it a name. This is done anonymously. I don't necessarily have to give a name to something if I just want to use it once. And, of course, I can write sort of a expression that produces a procedure. I'm going to write the Greek lambda letter here instead of L-A-M-B-D-A in general to avoid taking up a lot of space on blackboards. But unfortunately, we don't have lambda keys on our keyboards. Maybe we can convince our friends in the computer industry that this is an important. Lambda of i is the quotient of 1 and the product of i and the sum of i 2, starting at a with the way of incrementing being that procedure of an index i, which adds i to 4, and b being the upper bound. So you can see that this notation, the invention of the procedure that takes a procedural argument, allows us to compress a lot of these procedures into one thing. This procedure, sums, covers a whole bunch of ideas. Now, just why is this important? I tried to say before that it helps us divide a problem into two pieces, and indeed, it does, for example, if someone came up with a different way of implementing this, which, of course, one might . Here, for example, an iterative implementation of sum. Iterative implementation for some reason might be better than the recursive implementation. But the important thing is that it's different. Now, supposing I had written my program this way that you see on the blackboard on the left. That's correct, the left. Well, then if I want to change the method of addition, then I'd have to change each of these. Whereas if I write them like this that you see here, then the method by which I did the addition is encapsulated in the procedure sum. That decomposition allows me to independently change one part of the program and prove it perhaps without changing the other part that was written for some of the other cases. Thank you. Are there any questions? Yes, sir. AUDIENCE: Would you go over next A and next again on-- PROFESSOR: Yes. It's the same problem. I'm sure you're going to-- you're going to have to work on this. This is hard the first time you've ever seen something like this. What I have here is a-- procedures can be named by variables. Procedures are not special. Actually, sum square is a variable, which has gotten a value, which is a procedure. This is define sum square to be lambda of A and B something. So the procedure can be named. Therefore, they can be passed from one to another, one procedure to another, as arguments. Well, what we're doing here is we're passing the procedure term as an argument to sum just when we get it around in the next recursive. Here, we're passing the procedure next as an argument also. However, here we're using the procedure next. That's what the parentheses mean. We're applying next to A to get the next value of A. If you look at what next is mapped against, remember that the way you think about this is that you substitute the arguments for the formal parameters in the body. If you're ever confused, think of the thing that way. Well, over here, with sum of the integers. I substitute identity for a term and 1 plus the incrementer for next in the body. Well, the identity procedure on A is what I get here. Identity is being passed along, and here, I have increment 1 plus being applied to A and 1 plus is being passed along. Does that clarify the situation? AUDIENCE: We could also define explicitly those two functions, then pass them. PROFESSOR: Sure. What we can do is we could have given names to them, just like I did here. In fact, I gave you various ways so you could see it, a variety. Here, I define the thing which I passed the name of. I referenced it by its name. But the thing is, in fact, that procedure, one argument X, which is X. And the identity procedure is just lambda of X X. And that's what you're seeing here. Here, I happened to just write its canonical name there for you to see. Is it OK if we take our five-minute break? As I said, computers to make people happy, not people to make computers happy. And for the most part, the reason why we introduce all this abstraction stuff is to make it so that programs can be more easily written and more easily read. Let's try to understand what's the most complicated program we've seen so far using a little bit of this abstraction stuff. If you look at the slide, this is the Heron of Alexandria's method of computing square roots that we saw yesterday. And let's see. Well, in any case, this program is a little complicated. And at the current state of your thinking, you just can't look at that and say, oh, this obviously means something very clear. It's not obvious from looking at the program what it's computing. There's some loop here inside try, and a loop does something about trying the improvement of y. There's something called improve, which does some averaging and quotienting and things like that. But what's the real idea? Can we make it clear what the idea is? Well, I think we can. I think we can use abstraction that we have learned about so far to clarify what's going on. Now, what we have mathematically is a procedure for improving a guess for square roots. And if y is a guess for a square root, then what we want to get we'll call a function f. This is the means of improvement. I want to get y plus x/y over 2, so the average of y and x divided by y as the improved value for the square root of x such that-- one thing you can notice about this function f is that f of the square root of f is in fact the square root of x. In other words, if I take the square root of x and substitute it for y here, I see the square root of x plus x divided by the square of x, which is the square root of x. That's 2 times the square root of x divided by 2, is the square root of x. So, in fact, what we're really looking for is we're looking for a fixed point, a fixed point of the function f. A fixed point is a place which has the property that if you put it into the function, you get the same value out. Now, I suppose if I were giving some nice, boring lecture, and you happened to have in front of you an HP -35 desk calculator like I used to have when I went to boring lectures. And if you think it was really boring, you put it into radians mode, and you hit cosine, and you hit cosine, and you hit cosine. And eventually, you end up with 0.734 or something like that. 0.743, I don't remember what exactly, and it gets closer and closer to that. Some functions have the property that you can find their fixed point by iterating the function, and that's essentially what's happening in the square root program by Heron's method. So let's see if we can write that down, that idea. Now, I'm not going to say how I compute fixed points yet. There might be more than one way. But the first thing to do is I'm going to say what I just said. I'm going to say it specifically, the square root. The square root of x is the fixed point of that procedure which takes an argument y and averages of x divided by y with y. And we're going to start up with the initial guess for the fixed point of 1. It doesn't matter where it starts. A theorem having to do with square roots. So what you're seeing here is I'm just trying to write out by wishful thinking. I don't know how I'm going to make fixed point happen. We'll worry about that later. But if somehow I had a way of finding the fixed point of the function computed by this procedure, then I would have-- that would be the square root that I'm looking for. OK, well, now let's see how we're going to write-- how we're going to come up with fixed points. Well, it's very simple, actually. I'm going to write an abbreviated version here just so we understand it. I'm going to find the fixed point of a function f-- actually, the fixed point of the function computed by the procedure whose name will be f in this procedure. How's that? A long sentence-- starting with a particular starting value. Well, I'm going to have a little loop inside here, which is going to push the button on the calculator repeatedly, hoping that it will eventually converge. And we will say here internal loops are written by defining internal procedures. Well, one thing I'm going to have to do is I'm going to have to say whether I'm done. And the way I'm going to decide when I'm done is when the old value and the new value are close enough so I can't distinguish them anymore. That's the standard thing you do on the calculator unless you look at more precision, and eventually, you run out of precision. So the old value and new value, and I'm going to stay here if I can't distinguish them if they're close enough, and we'll have to worry about what that is soon. The old value and the new value are close enough to each other and let's pick the new value as the answer. Otherwise, I'm going to iterate around again with the next value of old being the current value of new and the next value of new being the result of calling f on new. And so this is my iteration loop that pushes the button on the calculator. I basically think of it as having two registers on the calculator: old and new. And in each step, new becomes old, and new gets F of new. So this is the thing where I'm getting the next value. And now, I'm going to start this thing up by giving two values. I wrote down on the blackboard to be slow so you can see this. This is the first time you've seen something quite this complicated, I think. However, we might want to see the whole thing over here in this transparency or slide or whatever. What we have is all of the details that are required to make this thing work. I have a way of getting a tolerance for a close enough procedure, which we see here. The close enough procedure, it tests whether u and v are close enough by seeing if the absolute value of the difference in u and v is less than the given tolerance, OK? And here is the iteration loop that I just wrote on the blackboard and the initialization for it, which is right there. It's very simple. But let's see. I haven't told you enough. It's actually easier than this. There is more structure to this problem than I've already told you. Like why should this work? Why should it converge? There's a hairy theorem in mathematics tied up in what I've written here. Why is it that I should assume that by iterating averaging the quotient of x and y and y that I should get the right answer? It isn't so obvious. Surely there are other things, other procedures, which compute functions whose fixed points would also be the square root. For example, the obvious one will be a new function g, which maps y to x/y. That's even simpler. The fixed point of g is surely the square root also, and it's a simpler procedure. Why am I not using it? Well, I suppose you know. Supposing x is 2 and I start out with 1, and if I divide 1 into 2, I get 2. And then if I divide 2 into 2, I get 1. If I divide 1 into 2, I get 2, and 2 into 2, I get 1, and I never get any closer to the square root. It just oscillates. So what we have is a signal processing system, an electrical circuit which is oscillating, and I want to damp out these oscillations. Well, I can do that. See, what I'm really doing here when I'm taking my average, the average is averaging the last two values of something which oscillates, getting something in between. The classic way is damping out oscillations in a signal processing system. So why don't we write down the strategy that I just said in a more clear way? Well, that's easy enough. I'm going to define the square root of x to be a fixed point of the procedure resulting from average damping. So I have a procedure resulting from average damp of the procedure, that procedure of y, which divides x by y starting out at 1. Ah, but average damp is a special procedure that's going to take a procedure as its argument and return a procedure as its value. It's a generalization that says given a procedure, it's the thing which produces a procedure which averages the last value and the value before and after running the procedure. You can use it for anything if you want to damp out oscillations. So let's write that down. It's very easy. And stylistically here, I'm going to use lambda notation because it's much easier to think when you're dealing with procedure, the mid-line procedures, to understand that the procedures are the objects I'm dealing with, so I'm going to use lambda notation here. Not always. I don't always use it, but very specifically here to expand on that idea, to elucidate it. Well, average damp is a procedure, which takes a procedure as its argument, which we will call f. And what does it produce? It produces as its value-- the body of this procedure is a thing which produces a procedure, the construct of the procedures right here, of o ne argument x, which averages f of x with x. This is a very special thing. I think for the first time you're seeing a procedure which produces a procedure as its value. This procedure takes the procedure f and does something to it to produce a new procedure of one argument x, which averages f-- this f-- applied to x and x itself. Using the context here, I apply average damping to the procedure, which just divides x by y. It's a division. And I'm finding to fixed point of that, and that's a clearer way of writing down what I wrote down over here, wherever it was. Here, because it tells why I am writing this down. I suppose this to some extent really clarifies what Heron of Alexandria was up to. I suppose I'll stop now. Are there any questions? AUDIENCE: So when you define average damp, don't you need to have a variable on f? PROFESSOR: Ah, the question was, and here we're having-- again, you've got to learn about the syntax. The question was when defining average damp, don't you have to have a variable defined with f? What you are asking about is the formal parameter of f? AUDIENCE: Yeah. PROFESSOR: OK. The formal parameter of f is here. The formal parameter of f-- AUDIENCE: The formal parameter of average damp. PROFESSOR: F is being used to apply it to an argument, right? It's indeed true that f must have a formal parameter. Let's find out what f's formal parameter is. AUDIENCE: The formal parameter of average damp. PROFESSOR: Oh, f is the formal parameter of average damp. I'm sorry. You're just confusing a syntactic thing. I could have written this the other way. Actually, I didn't understand your question. Of course, I could have written it this other way. Those are identical notations. This is a different w ay of writing this. You're going to have to get used to lambda notation because I'm going to use it. What it says here, I'm defining the name average damp to name the procedure whose of one argument f. That's the formal parameter of the procedure averagedamp. What define does is it says give this name a value. Here is the value of for it. That there happens to be a funny syntax to make that easier in some cases is purely convenience. But the reason why I wrote it this way here is to emphasize that I'm dealing with a procedure that takes a procedure as its argument and produces a procedure as its value. AUDIENCE: I don't understand why you use lambda twice. Can you just use one lambda and take two arguments f and x? PROFESSOR: No. AUDIENCE: You can't? PROFESSOR: No, that would be a different thing. If I were to write the procedure lambda of f and x, the average of f of x and x, that would not be something which would be allowed to take a procedure as an argument and produce a procedure as its value. That would be a thing that takes a procedure as its argument and numbers its argument and produces a new number. But what I'm producing here is a procedure to fit in the procedure slot over here, which is going to be used over here. So the number has to come from here. This is the thing that's going to eventually end up in the x. And if you're confused, you should do some substitution and see for yourself. Yes? AUDIENCE: Will you please show the definition for average damp without using lambda notation in both cases. PROFESSOR: I can't make a very simple one like that. Let me do it for you, though. I can get rid of this lambda easily. I don't want to be-- actually, I'm lying to you. I don't want to do what you want because I think it's more confusing than you think. I'm not going to write what you want. So we'll have to get a name. FOO of x to be of F of x and x and return as a value FOO. This is equivalent, but I've had to make an arbitrary name up. This is equivalent to this without any lambdas. Lambda is very convenient for naming anonymous procedures. It's the anonymous name of something. Now, if you really want to know a cute way of doing this, we'll talk about it later. We're going to have to define the anonymous procedure. Any other questions? And so we go for our break again. So now we've seen how to use high-order procedures, they're called. That's procedures that take procedural arguments and produce procedural values to help us clarify and abstract some otherwise complicated processes. I suppose what I'd like to do now is have a bit of fun with that and sort of a little practice as well. So let's play with this square root thing even more. Let's elaborate it and understand what's going on and make use of this kind of programming style. One thing that you might know is that there is a general method called Newton's method the purpose of which is to find the roots-- that's the zeroes-- of functions. So, for example, to find a y such that f of y equals 0, we start with some guess. This is Newton's method. And the guess we start with we'll call y0, and then we will iterate the following expression. y n plus 1-- this is a difference equation-- is yn minus f of yn over the derivative with respect to y of f evaluated at y equal yn. Very strange notation. I must say ugh. The derivative of f with respect to y is a function. I'm having a little bit of unha ppiness with that, but that's all right. It turns out in the programming language world, the notation is much clearer. Now, what is this? People call it Newton's method. It's a method for finding the roots of the function f. And it, of course, sometimes converges, and when it does, it does so very fast. And sometimes, it doesn't converge, and, oh well, we have to do something else. But let's talk about square root by Newton's method. Well, that's rather interesting. Let's do exactly the same thing we di d last time: a bit of wishful thinking. We will apply Newton's method, assuming we knew how to do it. You don't know how to do it yet. Well, let's go. What do I have here? The square root of x. It's Newton's method applied to a procedure which will represent that function of y, which computes that function of y. Well, that procedure is that procedure of y, which is the difference between x and the square of y. Indeed, if I had a value of y for which this was zero, then y would be the square root of x. See that? OK, I'm going to start this out searching at 1. Again, completely arbitrary property of square roots that I can do that. Now, how am I going to compute Newton's method? Well, this is the method. I have it right here. In fact, what I'm doing is looking for a fixed point of some procedure. This procedure involves some complicated expressions in terms of other complicated things. Well, I'm trying to find the fixed point of this. I want to find the values of y, which if I put y in here, I get the same value out here up to some degree of accuracy. Well, I already have a fixed point process around to do that. And so, let's just define Newton's method over here. A procedure which computes a function and a guess, initial guess. Now, I'm going to have to do something here. I'm going to need the derivative of the function. I'm going to need a procedure which computes the derivative of the function computed by the given a procedure f. I'm trying to be very careful about what I'm saying. I don't want to mix up the word procedure and function. Function is a mathematical word. It says I'm mapping from values to other values, a set of ordered pairs. But sometimes, I'll accidentally mix those up. Procedures compute functions. So I'm going to define the derivative of f to be by wishful thinking again. I don't know how I'm going to do it. Let's worry about that later-- of F. So if F is a procedure, which happens to be this one over here for a square root, then DF will be the derivative of it, which is also the derivative of the function computed by that procedure. DF will be a procedure that computes the derivative of the function computed by the procedure F. And then given that, I will just go looking for a fixed point. What is the fixed point I'm looking for? It's the one for that procedure of one argument x, which I compute by subtracting x. That's the old-- that's the yn here. The quotient of f of x and df of x, starting out with the original guess. That's all very simple. Now, I have one part left that I haven't written, and I want you to see the process by which I write these things, because this is really true. I start out with some mathematical idea, perhaps. By wishful thinking, I assume that by some magic I can do something that I have a name for. I'm not going to worry about how I do it yet. Then I go walking down here and say, well, by some magic, I'm somehow going to figure how to do that, but I'm going to write my program anyway. Wishful thinking, essential to good engineering, and certainly essential to a good computer science. So anyway, how many of you wished that your computer ran faster? Well, the derivative isn't so bad either. Sort of like average damping. The derivative is a procedure that takes a procedure that computes a function as its argument, and it produces a procedure that computes a function, which needs one argument x. Well, you all know this definition. It's f of x plus delta x minus f of x over delta x, right? For some small delta x. So that's the quotient of the difference of f of the sum of x and dx minus f point x divided by dx. I think the thing was lining up correctly when I balanced the parentheses. Now, I want you to look at this. Just look. I suppose I haven't told you what dx is. Somewhere in the world I'm going to have to write down something like that. I'm not interested. This is a procedure which takes a procedure and produces an approximation, a procedure that computes an approximation of the derivative of the function computed by the procedure given by the standard methods that you all know and love. Now, it may not be the case that doing this operation is such a good way of approximating a derivative. Numerical analysts here should jump on me and say don't do that. Computing derivatives produces noisy answers, which is true. However, this again is for the sake of understanding. Look what we've got. We started out with what is apparently a mathematically complex thing. and. In a few blackboards full, we managed to decompose the problem of computing square roots by the way you were taught in your college calculus class-- Newton's method-- so that it can be understood. It's clear. Let's look at the structure of what it is we've got. Let's look at this slide. This is a diagram of the machine described by the program on the blackboard. There's a machine described here. And what have I got? Over here is the Newton's method function f that we have on the left-most blackboard. It's the thing that takes an argument called y and puts out the difference between x and the square of y, where x is some sort of free variable that comes in from the outside by some magic. So the square root routine picks up an x, and builds this procedure, which I have the x rolled up in it by substitution. Now, this procedure in the cloud is fed in as the f into the Newton's method which is here, this box. The f is fanned out. Part of it goes into something else, and the other part of it goes through a derivative process into something else to produce a proc edure, which computes the function which is the iteration function of Newton's method when we use the fixed point method. So this procedure, which contains it by substitution -- remember, Newton's method over here, Newton's method builds this procedure, andNewton's method has in it defined f and df, so those are captured over here: f and df. Starting with this procedure, I can now feed this to the fixed point process within an initial guess coming out from the outside from square root to produce the squareroot of x. So what we've built is a very powerful engine, which allows us to make nice things like this. Now, I want to end this with basically an idea of Chris Strachey, one of the grandfathers of computer science. He's a logician who lived in the -- I suppose about 10 years ago or 15 years ago, he died. I don't remember exactly when. He's one of the inventors of something called denotational semantics. He was a great advocate of making procedures or functions first-class citizens in a programming languag e. So here's the rights and privileges of first-class citizens in a programming language. It allows you to make any abstraction you like if you have functions as first -class citizens. The first-class citizens must be able to be named by variables. And you're seeing me doing that all the time. Here's a nice variable which names a procedure which computes something. They have to be passed as arguments to procedures. We've certainly seen that. We have to be able to return them as values from procedures. And I suppose we've seen that. We haven't yet seen anything about data structures. We will soon, but it's also the case that in order to have a first-class citizen in a programming language, the object has to be allowed to be part of a data structure. We're going to see that soon. So I just want to close with this and say having things like procedures as first-class data structures, first-class data, allows one to make powerful abstractions, which encode general methods like Newton's method in very clear way. Are there any questions? Yes. AUDIENCE: Could you put derivative instead of df directly in the fixed point? PROFESSOR: Oh, sure. Yes, I could have put deriv of f right here, no question. Any time you see something defined, you can put the thing that the definition is there because you get the same result. In fact, what that would look like, it's interesting. AUDIENCE: Lambda. PROFESSOR: Huh? AUDIENCE: You could put the lambda expression in there. PROFESSOR: I could also put derivative of f here. It would look interesting because of the open paren, open paren, deriv of f, closed paren on an x. Now, that would have the bad property of computing the derivative many times, because every time I would run this procedure, I would compute the derivative again. However, the two open parens here both would be meaningful. I want you to understand syntactically that that's a sensible thing. Because if was to rewrite this program-- and I should do it right here just so you see because that's a good question-- of F and guess to be fixed point of that procedure of one argument x, which subtracts from x the quotient of F applied to x and the deriv of F applied to x. This is guess. This is a perfectly legitimate program, because what I have here-- remember the evaluation rule. The evaluation rule is evaluate all of the parts of the combination: the operator and the operands. This is the operator of this combination. Evaluating this operator will, of course, produce the derivative of F. AUDIENCE: To get it one step further, you could put the lambda expression there, too. PROFESSOR: Oh, of course. Any time I take something which is define, I can put the thing it's defined to be in the place where the thing defined is. I can't remember which is definiens and which is definiendum. When I'm trying to figure out how to do a lecture about this in a freshman class, I use such words and tell everybody it's fun to tell their friends. OK, I think that's it. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed thismaterial in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec2b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 2B: Compound Data [MUSIC PLAYING] PROFESSOR: Well, so far in this course we've been talking about procedures, and then just to remind you of this framework that we introduced for talking about languages, we talked about the primitive things that are built into the system. W e mentioned some means of combination by which you take the primitive things and you make more complicated things. And then we talked about the means of abstraction, how you can take those complicated things and name them so you can use them as simple building blocks. And then last time you saw we went even beyond that. We saw that by using higher order procedures, you can actually express general methods for computing things. Like the method of doing something by fixed points, or Newton's method, and so the incredible expressive power you can get just by combining these means of abstraction. And the crucial idea in all of this is the one that we build a layered system. So for instance, if we're writing the square root procedure, somewhere the square root procedure uses a procedure called good-enough, and between those there is some sort of abstraction boundary. It's almost as if we go out and in writing square root, we go and make a contract with George, and tell George that his job is to write good-enough, and so long as good- enough works, we don't care what it does. We don't care exactly how it's implemented. There are levels of detail here that are George's concern and not ours. So for instance, George might use an absolute value procedure that's written by Harry, and we don't much care about that or even know that, maybe, Harry exists. So the crucial idea is that when we're building things, we divorce the task of building things from the task of implementing the parts. And in a large system, of course, we have abstraction barriers like this at lots, and lots, and lots of levels. And that's the idea that we've been using so far over and over in implementing procedures. Well, now what we're going to do is look at the same issues for data. We're going to see that the system has primitive data. In fact, we've already seen that. We've talked about numbers as primitive data. And then we're going to see their means of combination for data. There's glue that allows you to put primitive data together to make more complicated, kind of compound data. And then we're going to see a methodology for abstraction that's a very good thing to use when you start building up data in terms of simpler data. And again, the key idea is that you're going to build the system in layers and set up abstraction barriers that isolate the details at the lower layers from the thing that's going on at the upper layers. The details at the lower layers, the ideas, they won't matter. They're going to be George's concern because he signed this contract with us for how the stuff that he implements behaves, and how he implements the thing is his problem. All right, well let's look at an example. And the example I'm going to talk about is a system that does arithmetic on rational numbers. And what I have in mind is that we should have something in the computer that allows us to ask it, like, what's the sum of 1/2 and 1/4, and somehow the system should say, yeah, that's 3/4. Or we should be able to say what's 3/4 times 2/3, and the system should be able to say, yeah, that's 1/2. Right? And you know what I have in mind. And you also know how to do this from, I don't know, fifth grade or sixth grade. There are these formulas that say if I have some fraction which is a numerator over a denominator, and I want to add that to some other fraction which is another numerator over another denominator, then the answer is the numerator of the first times the denominator of the second, plus the numerator of the second times the denominator of the first. That's the numerator of the answer, and the denominator is the product of the two denominators. Right? So there's something from fifth or sixth grade fraction arithmetic. And then similarly, if I want to multiply two things, n1 over d1 multiplied by n2 over d2 is the product of the numerators over the product of the denominators. So it's no problem at all, but it's absolutely no problem to think about what computation you want to make in adding and multiplying these fractions. But as soon as we go to im plement it, we run up across something. We don't have what a rational number is. So we said that the system gives us individual numbers, so we can have 5 and 3, but somehow we don't have a way of saying there's a thing that has both a 3 and a 4 in it, or both a 2 and a 3. It's almost as if we'd like to imagine that somehow there are these clouds, and a cloud somehow has both a numerator and a denominator in it, and that's what we'd like to work in terms of. Well, how are we going to solve that problem? We're going to solve that problem by using this incredibly powerful design strategy that you've already seen us use over and over. And that's the strategy of wishful thinking. Just like before when we didn't have a procedure, we said, well, let's imagine tha t that procedure already exists. We'll say, well, let's imagine that we have these clouds. Now more precisely what I mean is let's imagine that we have three procedures, one called make-RAT. make-RAT is going to take as arguments two numbers, so I'll call them numerator and denominator, and it'll return for us a cloud -- one of these clouds. I don't really know what a cloud is. It's whatever make-RAT returns, that's its business. And then we're going to say, suppose we've got one of these clouds, we have a procedure called numer, which takes in a cloud that has an n and a d in it, whatever a clo ud is, and I don't know what it is, and returns for us the numerator part. And then we'll assume we have a procedure denom, which again takes in a cloud, whatever a cloud is, and returns for us the denominator [? required. ?] This is just like before, when if we're building a square root, we assume that we have good enough. Right? And what we'll say is, we'll go find George, and we'll say to George, well, it's your business to make us these procedures. And how you choose to implement these clouds, that's your problem. We don't want to know. Well, having pushed this task off onto George, then it's pretty easy to do the other part. Once we've got the clouds, it's pretty easy to write the thing that does say addition of rational numbers. You can just say define, well, let's say +RAT. Define +RAT, which will take in two rational numbers, x and y. x and y are each these clouds. And what does it do? Well, it's going to return for us a rational number. What rational number is it? Well, we've got the formulas there. The numerator of it is the sum of the product of the numerator of x and the denominator of y. It's one thing in the sum. And the other thing in the numerator is the product of the numerator of y and the denominator of x. The star, close the plus. Right, that's the first argument to make-RAT, which is the numerator of the thing I'm constructing. And then the rest of the thing goes into make-RAT is the denominator of the answer, which is the product of the denominator of x and the denominator of y. Like that. OK? So there is the analog of doing rational number addition. And it's no problem at all, assuming that we have these clouds. And of course, we can do multiplication in the same way. Define how to get the product of two rational numbers, call it *RAT. Takes in two of these clouds, x and y, it returns a rational number, make-RAT, whose numerator is the product of the numerators-- numerator of x times the numerator of y. And the denominator of the thing it's going to return is the product of the denominators. Well, except that I haven't told you what these clouds are, that's all there is to it. See, what did I do? I assumed by wishful thinking that I had a new kind of data object. And in particular, I assumed I had ways of creating these data obje cts. Make-RAT creates one of these things. This is called a constructor. All right, I have a thing that constructs such data objects. And then I assume I have things that, having made these things, I have ways of getting the parts out. Those are called selectors. And so formally, what I said is I assumed I had procedures that are constructors and selectors for these data objects, and then I went off and used them. That's no different in kind from saying I assume I have a procedure good-enough, and I go use it to implement square root. OK, well before we go on, let's ask the question of why do we want to do this in the first place? See, why do we want a procedure like +RAT that takes in two rational numbers and returns a rational number? See, another way to think about this is, well, here's this formula. And I've also got to implement something that adds rational numbers. One other way to think about is, well, there's this thing, and I type in four numbers, an n1, and a d1, and an n2, and a d2. And it sets some registers in the machine to this numerator and this denominator. So I might say, well, why don't I just add rational numbers by I type in four numbers, numerators and denominators, and get out two numbers, which is a numerator and a denominator. Why are we worrying about building things like this anyway? Well, the answer is, suppose you want to think about expressing something like this, suppose I'd like to express the idea of taking two rational numbers, x plus y, say, and multiplying that by the sum of two other rational numbers. Well, the way I do it, having things like +RAT and *RAT, is I'd say, oh yeah, what that is is just the product. That's *RAT of the sum of x and y and the sum of s and t. So except for syntax, I get an expression that looks like the way I want to think about it mathematically. I want to say there are two numbers. There's a thing which is the sum of them, and there's a thing which is the sum of these two. That's this and this. And then I multiply them. So I get an expression that matches this expression. If I did the other thing, if I said, well, the way I want to think about this is I type into my machine four numbers, which are the numerators and the denominators of x and y, and then four more numbers, which are the numerators and denominators of s and t. And then what I'd be sitting with is, well, what would I do? I'd add these, and somehow I'd have to have two temporary variables, which are the numerators and denominators of this sum, and I'd go off and store them someplace. And then I'd go over here, I'd type in four more numbers, I'd get two more temporary variables, which are the numerators and denominators of s and t. And then finally, I put those together by multiplying them. You see, what's starting to happen, there are all these temporary variables, which are sort of the guts of the internals of these rational numbers that start hanging out all over the system. And of course, if I had more and more complicated expressions, there'd be more and more guts hanging out that confuse my programming. And those of you who sort of programmed things like that, where you're just adding numbers in assembly language, you sort of see you have to suddenly be concerned with these temporary variables. But more importantly than confusing my programming, they're going to confuse my mind. Because the whole name of this game is that we'd like the programming language to express the concepts that we have in our heads, like rational numbers are things that you can add and then take that result and multiply them. Let's break for questions. Yeah? AUDIENCE: I don't quite see the need- when we had make-RAT with the numerator and denominator, we had to have the numerator and denominator to pass as parameters to create the cloud, and then we extracted to get back what we had to have originally. PROFESSOR: That's right. So the question is, I sort of have the numerator and the denominator, why am I worrying about having the cloud given that I have to get the pieces out? That's sort of what I tried to say at the end, but let me try and say it again, because that's really the crucial question. The point is, I want to carry this numerator and denominator around together all the time. And it's almost as if I want to know, yeah, there's a numerator and denominator in there, but also, I would like to say, fine, but from another point of view, that's x. And I carry x around, and I name it as x, and I hold it. And I can say things like, the sum of x and y, rather than just have-- see, it's not so bad when I only think about x, but if I have a system with 10 rational numbers, suddenly I have 20 numerators and denominators, which are not necessarily-- if I don't link them, then it's just 20 arbitrary numbers that are not linked in any particular way. It's a lot like saying, well, I have these instructions that are the body of the procedures, why do I want to package them and say it's the procedure? It's exactly the same idea. No? OK. Let's break, let's just stretch and get somebody-- [INAUDIBLE] [MUSIC PLAYING] OK, well, we've been working on this rational number arithmetic system, and then what we did, the important thing about what we did, is we thought about the problem by breaking it into two pieces. We said, assume there is this contract with George, and George has figured out the way to how to construct these clouds, provided us procedures make-RAT, which was a constructor, and selectors, which are numerator and denominator. And then in terms of that, we went off and implemented addition and multiplication of rational numbers. Well, now let's go look at George's problem. How can we go and package together a numerator and a denominator and actually make one of these clouds? See, what we need is a kind of glue, a glue for data objects that allows us to put things together. And Lisp provides such a glue, and that glue is called list structure. List structure is a way of gluing things together, and more precisely, Lisp provides a way of constructing things called pairs. There's a primitive operator in Lisp called cons. We can take a look at it. There's a thing called cons. Cons is an operator which takes in two arguments called x and y, and it returns for us a thing called a pair. All right, so a thing called a pair that has a first part a second part. So cons takes two objects. There's a thing called a pair. The first part of the cons is x, and the second part of the cons is y. And that's what it builds. And then we also assume we have ways of getting things out. If you're given a pair, there's a thing called car, and car of a pair, p, gives you out the first part of the pair, p. And there's a thing called cdr, and cdr of the pair, p, gives you the second part of the pair, p. OK, so that's how we construct things. There's also a conventional way of drawing pictures of these things. Just like we write down that as the conventional way of writing Plato's idea of two, the way we could draw a diagram to represent cons of two and three is like this. We draw a little box. And so here's the box we're talking about, and this box has two arrows coming out of it. And say the first part of this pair is 2, and the second part of this pair is 3. And this notation has a name, it's called box and pointer notation. By the way, let me say right now that a lot of people get confused that there's some significance to the geometric way I drew these pointers, the directions. Like some people think it'd be different if I took this pointer and turned it up here, and put the 3 out here. That has no significance. All right? It's merely you have a bunch of arrows, these pointers, and the boxes. The only issue is how they're connected, not the geometric arrangement of whether I write the pointer across, or up, or down. Now it's completely un-obvious, probably, why that's called list structure. We're not actually going to talk about that today. We'll see that next time. So those are pairs, there's cons that constructs them. And what I'm going to know about cons, and car, and cdr, is precisely that if I have any x and y, all right, if I have any things x and y, and I use cons to construct a pair, then the car of that pair is going to be x, the thing I put in, and the cdr of that pair is going to be y. That's the behavior of these operators, cons, car, and cdr. Given them, it's pretty clear how George can go off and construct his rational numbers. After all, all he has to do-- remember George's problem was to implement make-RAT, numerator, and denom. So all George has to do is say define make-RAT of some n and a d-- so all I have to do is cons them. That's cons of n and d. And then if I want to get the numerator out, I would say define the numerator, numer, of some rational number, x. If the rational number's implemented as a pair, then all Ihave to do is get out the car of x. And then similarly, define the denom is going to be the cdr, the other thing I put into the pair. Well, now we're in business. That's a complete implementation of rational numbers. Let's use it. Suppose I want to say, so I want to think about how to add 1/2 plus 1/4 and watch the system work. Well, the way I'd use that is I'd say, well, maybe define a. I have to make a 1/2. Well, that's a rational number with numerator 1 and denominator 2, so a will be make-RAT of 1 and 2. And then I'll construct the 1/4. I'll say define d to be make-RAT of 1 and 4. And if I'd like to look at the answer-- well, assuming I don't have a special thing that prints rational numbers, or I could make one-- I could say, for instance, define the answer to be +RAT of a and b, and now I can say, what's the answer? What are the numerators and denominators of the answer? So if I'm adding 1/2 and 1/4, I'll say, what is the numerator of the answer? And the system is going to type out, well, 6. Bad news. And if I say what's the denominator of the answer, the system's going to type out 8. So instead of what I would really like, which is for it to say that 1/2 and 1/4 is 3/4, this foolish machine is going to say, no, it's 6/8. Well, that's sort of bad news. Where's the bug? Why does it do that, after all? Well, it's the way that we just had +RAT. +RAT just took the-- it said you add the numerator times the denominator, you add that to the numerator times the denominator, and put that over the product of the two denominators, and that's why you get 6/8. So what was wrong with our implementation of +RAT? What's wrong with that rational number arithmetic stuff that we did before the break? Well, the answer is one way to look at it is absolutely nothing's wrong. That's perfectly good implementation. It follows the sixth grade, fifth grade mathematic for adding fractions. One thing we can say is, well, that's George's problem. Like, boy, wasn't George dumb to say that he can make a rational number simply by sticking together the numerator and the denominator? Wouldn't it be better for George, when he made a rational number, to reduce the stuff to lowest terms? And what I mean is, wouldn't it be better for George, instead of using this version of make-RAT, to use this one on the slide? Or instead of just saying cons together n and d, what you do is compute the greatest common divisor of n and d, and gcd is the procedure which, well, for all we care is a primitive, which computes the greatest common divisor of two numbers. So the way I can construct a rational number is get the greatest common divisor of the two numbers, and I'm going to call that g, and then instead of consing together n and d, I'll divide them through. I'll cons together the quotient of n by the the gcd and the quotient of d by the gcd. And that will reduce the rational number to lowest terms. So when I do this addition, when +RAT calls make-RAT-- and for the definition of +RAT it had a make-RAT in there-- just by the fact that it's constructing that, the thing will get reduced to lowest terms automatically. OK, that is a complete system. For rational number arithmetic, let's look at what we've done. All right, we said we want to build rational number arithmetic, and we had a thing called +RAT. We implemented that. And I showed you multiplying rational numbers, and although I didn't put them up there, presumably we'd like to have something that subtracts rational numbers, and I don't know, all sorts of things. Things that test equality in division, and maybe things that print rational numbers in some particular way. And we implemented those in terms of pairs. These pairs, cons, car, and cdr that are built into Lisp. But the important thing is that between these and these, we set up an abstraction barrier. We set up a layer of abstraction. And what was that layer of abstraction? That layer of abstraction was precisely the constructor and the selectors. This layer was make-RAT, and numer, and denom. This methodology, another way to say what it's doing, is that we are separating the way something is used, separating the use of data objects, from the representation of data objects. So up here, we have the way that rational numbers are used, do arithmetic on them. Down here, we have the way that they're represented, and they're separated by this boundary. The boundary is the constructors and selectors. And this methodology has a name. This is called data abstraction. Data abstraction is sort of the programming methodology of setting up data objects by postulating constructors and selectors to isolate use from representation. Well, so why? I mean, after all, we didn't have to do it this way. It's perfectly possible to do rational number addition without having any compound data objects, and here on the slide is one example. We certainly could have defined +RAT, which takes in things x and y, and we'll say, well what are these rational numbers really? So really, they're just pairs, and the numerator's the car and the denominator's the cdr. So what we'll do is we'll take the car of x times the cdr of y, multiply them. Take the car of y times the cdr of x, multiply them. Add them. Take the cdr of x and the cdr of y, multiply them, and then constitute together. Well, that sort of does the same thing. But this ignores the problem of reducing things to lowest terms, but let's not worry about that for a minute. But so what? Why don't we do it that way? Right? After all, there are sort of fewer procedures to define, and it's a lot more straightforward. It saves all this self - righteous BS about talking about data abstraction. We just sort of do it. I mean, who knows, maybe it's even marginally more efficient depending on whatever compiler were using for this. What's the point of isolating the use from the representation? Well, it goes back to this notion of naming. Remember, one of the most important principles in programming is the same as one of the most important principles in sorcery, all right? That's if you have the name of the spirit, you get control over it. And if you go back and look at the slide, you see what's in there is we have this thing +RAT, but nowhere in the system, if I have a +RAT and a -RAT and a *RAT, and things that look like that, nowhere in the system do I have a thing that I can point at which is a rational number. I don't have, in a system like that, the idea of rational number as a conceptual entity. Well, what's the advantage of that? What's the advantage of isolating the idea of rational numbers as a conceptual entity, and really naming it with make-RAT, numerator, and denominator. Well, one advantage is you might want to have alternative representations. See, before I showed you that one way George can solve this things not reduced to lowest terms problem, is when you build a rational number, you divide up by the greatest common denominator. Another way to do that is shown over here. I can have an alternative representation for rational numbers where when you make a rational number, you just cons them. However, when you go to select out the numerator, at that point you compute the gcd of the stuff that's sitting in that pair, and divide out by the gcd. And similarly, when I get the denominator, at that point when I go to get the denominator, I'll divide out by the gcd. So the difference would be in the old representation, when ans was constructed here, say what's 6 and 8, in the first way, the 6 and 8 would have got reduced when they got stuck into that pair, numerator would select out 3. And in the way I just showed you, well, ans would get 6 and 8 put in, and then at the point where I said numera tor, some computation would get done to put out 3 instead of 6. So those are two different ways I might do it. Which one's better? Well, it depends, right? If I'm making a system where I am mostly constructing rational numbers and hardly ever looking at them, then it's probably better not to do that gcd computation when I construct them. If I'm doing a system where I look at things a lot more than I construct them, then it's probably better to do the work when I construct them. So there's a choice there. But the real issue is that you might not be able to decide at the moment you're worrying about these rational numbers. See, in general, as systems designers, you're forced with the necessity to make decisions about how you're going to do things, and in general, the way you'd like to retain flexibility is to never make up your mind about anything until you're forced to do it. The problem is, there's a very, very narrow line between deferring decisions and outright procrastination. So you'd like to make progress, but also at the same time, never be bound by the consequences of your decisions. Data abstraction's one way of doing this. What we did is we used wishful thinking. See, we gave a name to the decision. We said, make-RAT, numerator, and denominator will stand for however it's going to be done, and however it's going to be done is George's problem. But really, what that was doing is giving a name to the decision of how we're going to do it, and then continuing as if we made the decision. And then eventually, when we really wanted it to work, coming back and facing what we really had to do. And in fact, we'll see a couple times from now that you may never have to choose any particular representation, ever, ever. Anyway, that's a very powerful design technique. It's the key to the reason people use data abstraction. And we're going to see that idea again and again. Let's stop for questions. AUDIENCE: What does this decision making through abstraction layers do to the axiom of do all your design before any of your code? PROFESSOR: Well, that's someone's axiom, and I bet that's the axiom of someone who hasn't implemented very large computer systems very much. I said that computer science is a lot like magic, and it's sort of good that it's like magic. There's a bad part of computer science that's a lot like religion. And in general, I think people who really believe that you design everything before you implement it basically are people who haven't designed very many things. The real power is that you can pretend that you've made the decision and then later on figure out which one is right, which decision you ought to have made. And when you can do that, you have the best of both worlds. AUDIENCE: Can you explain the difference between let and define? PROFESSOR: Oh, OK. Let is a way to establish local names. Let me give you sort of the half answer. And I'll say, later on we can talk about the whole very complicated thing. But the big difference for now is that, see, when you're typing at Lisp, you're typing in this environment where you're making definitions. And when you say define a to be 5, if I say define a to be 5, then from then on the thing will remember that a is 5. Let is a way to set up a local context where there's a definition. So if I type something like, saying let a-- no, I shouldn't say a-- if I said let z be 10, and within that context, tell me what the sum of z and z is. So if I typed in this expression to Lisp, and then this would put out 20. However, then if I said what's z, the computer would say that's an unbound variable. So let is a way of setting up a context where you can make definitions. But those definitions are local to this context. And of course, if I'd said a in here, I'd still get 20. But this a would not interfere at all with this one. So if I type this, and then type this, and then say what's a? a will still be 5. So there's some other subtle differencesbetween let and define, but that's the most important one. All right, well, we've looked at implementing this little system for doing arithmetic on rational numbers as an example of this methodology of data abstraction. And that's a way of controlling complexity in large systems. But, see, like procedure definition, and like all the ways we're going to talk about for controlling complexity, the real power of these things show up not when you sort of do these things in themselves, like it's not such a gre at thing that we've done rational number arithmetic, it's that you can use these as building blocks for making more complicated things. So it's no wonderful idea that you can just put two numbers together to form a pair. If that's all you ever wanted to do, there are tons of ways that you can do that. The real issue is can you do that in such a way so that the things that you build become building blocks for doing something even more complex? So whenever someone shows you a method for controlling complexity, you should say, yeah, that's great, but what can I build with it? So for example, let me just run through another thing that's a lot like the rational number one. Suppose we would like to represent points in the plane. You sort of say, well, there'sa point, and we're going to call that point p. And that point might have coordinates, like this might be the point 1 comma 2. The x-coordinate might be 1, and it's y-coordinate might be 2. And we'll make a little system for manipulating points in the plane. And again, we can do that-- here's a little example of that. It can represent vectors, the same as points in the plane, and we'll say, yep, there's a constructor called make-vector, make-vector's going to take two coordinates, and here we can implementthem if we like as pairs, but the important thing is that there's a constructor. And then given some vector, p, we can find its x-coordinate, or we can get its y-coordinate. So there's a constructor and selectors for points in the plane. Well, given points in the plane, we might want to use them to build something. So for instance, we might want to talk about, we might have a point, p, and a point, q, and p might be the point 1, 2, and q might be the point 2, 3. And we might want to talk about the line segment that starts at p and ends at q. And that might be the segment s. So we might want to build points for vectors in terms of numbers, and segments in terms of vectors. So we can represent line segments in exactly the same way. All right, so the line segment from p to q, we'll say there's a constructor, make-segment. And make up names for the selectors, the starting point of the segment and the ending point of the segment. And again, we can implement a segment using cons as a pair of points, and car and cdr get out the two points that we put together to get the segment. Well, now having done that, we can have some operations on them. Like we could say, what's the midpoint of a line segment? So here's the midpoint of a line segment, that's going to be the points whose coordinates are the averages of the coordinates of the endpoints. OK, there's the midpoint. So to get the midpoint of a line segment, s, we'll just say grab the starting point to the segment, grab the ending point of the segment, and now make a vector-- make a point whose coordinates are the average of the x-coordinate of the first point and the x- coordinate of the second point, and whose y-coordinate is the average of the y-coordinates. So there's an implementation of midpoint. And then similarly, we can build something like the length of the segment. The length of the segment is a thing whose-- use Pythagoras's rule, the length of the segment is the square root of the d x squared plus d y squared. We'll say to get the length of a line segment, we'll let dx be the difference of the x-coordinate of one endpoint and the x-coordinate of the other endpoint, and we'll let dy be the difference of the y-coordinates. And then we'll take the square root of the sum of the squares of dx and dy, that's what this says. All right, so there's an implementation of length. And again, what we built is a layered system. We built a system which has, well, say up here there's segments. And then there's an abstraction barrier. The abstraction barrier separates the implementation of segments from the implementation of vectors and points, and what that abstraction barrier is are the constructors and selectors. It's make-segment, and segment-start, and segment-end. And then there are vectors. And vectors in turn are built on top of pairs and numbers. So I'll say pairs and numbers. And that has its own abstraction barrier, which is make-vector, and x-coordinate, and y-coordinate. So we have, again, a layered system. You're starting to see that there are layers here. I ought to mention, there is a very important thing that I kind of took for granted. And it's sort of so natural, but on the other hand it's a very important thing. Notice that in order to represent this segment s, I said this segment is a pair of points. And a point is a pair of numbers. And if I were going to draw the box and pointers structure for that, I would say, oh, the segment is, given those particular representations that I showed you, I'd say this segment s is a pair, and the first thing in the pair is a vector, and the vector is a pair of numbers. And that's this, that's p. And the other thing i n the segment is q, which is itself a pair of numbers. So I almost took it for granted when I said that cons allows you to put things together. But it's very easy to not appreciate that, because notice, some of the things I can put together can themselves be pairs. And let me introduce a word that I'll talk about more next time, it's one of my favorite words, called closure. And by closure I mean that the means of combination in your system are such that when you put things together using them, like we make a pair, you can then put those together with the same means of combination. So I can have not only a pair of numbers, but I can have a pair of pairs. So for instance, making arrays in a language like Fortran is not a closed means of combination, because I can make an array of numbers, but I can't make an array of arrays. And one of the things that you should ask, one of your tests of quality for a means of combination that someone shows you, is gee, are the things you make closed under that means of combination? So pairs would not be nearly so interesting if all I could do was make a pair of numbers. I couldn't build very much structure at all. OK, well, we'll come back to that. I just wanted to mention it now. You'll hear a lot about closure later on. You can also see the potential for losing control of complexity as you have a layered system if you don't use data abstraction. Let's go back and look at this slide for length. Length works and is a simple thing because I can say, when I want to get th is value, I can say, oh, that is the x-coordinate of the first endpoint of the segment. And each of these things, each of these selectors, x-coordinate and endpoint, stand for a decision choice whose details I don't have to look at. So I could perfectly well, again, just like rational numbers I did before, I could say, oh well, gee, a segment really is a pair of pairs. And the x-coordinate of the first endpoint or the segment really is the -- well, what is it? It's the car of the car of the segment. So I could perfectly well go and redefine length. I could say, define the length of some segment s. And I could start off writing something like, well, we'll let dx be-- well, what's it have to be? It's got to be the difference of the two coordinates, so that's the difference of, the first one is the car of the car of s, subtracted from the first one, the car of the other half of it, the cdr of s. All right, and then dy would be-- well, let's see, I'd get the y-coordinate, so it'd be the difference of the cdr of the car of s, and the cdr of the cdr of s, sort of go on. You can see that's much harder to read than the program I had before. But worse than that, suppose you'd gone and implemented length? And then the next day, George comes to you and says, I'm sorry, I changed my mind. I want to write points with the x-coordinate first. So you come back you stare at this code and say, oh gee, what was that? That was the car, so I have to change this to cdr, and this is cdr, and this now has to be car. And this has to be car. And you sort of do that, and then the next day George comes back and says, sorry, the guys designing the display would like lines to be painted in the opposite direction, so I have to write the endpoint first in the order. And then you come back and you stare at this code, and say, gee, what was it talking about? Oh yeah, well I've got to change this one to cdr, and this one becomes car, this one comes car, and this becomes cdr. And you go up and do that, and then the next day, George comes back and says, I'm sorry, what I really meant is that the segments always have to be painted from left to right on the screen. And then you sort of, it's clear, you just go and punch George in the mouth at that point. But you see, as soon as we have a 10 layer system, you see how that complexity immediately builds up to the point where even something like this gets out of control. So again, the way we've gotten out of that is we've named that spirit. We built a system where there is a thing, which is the representation choice for how you're going to talk about vectors. And choices about that representation are localized right there. They don't have their guts spilling over into things like how you compute the length and how you compute the midpoint. And that's the real power of this system. OK, we're explicit about them, so that we have control over them. All right, questions? AUDIENCE: What happens in the case where you don't want to be treating objects in terms of pairs? For instance, in three-dimensional space, you'd have three coordinates. Or even in the case where you have n-dimensional space, what happens? PROFESSOR: Right, OK. Well, this is a preview of what I'll say tomorrow. But the point is, once you have two things, you have as many things as you want. All right? Because if I want to make three things, I could start making things like a pair whose first thing is 1, and whose second thing is another pair that, say, has 2 and 3 in it. And so on, a hundred things. I can nest them out of pairs. I made a pretty arbitrary decision about how to do it, and you can immediately see there are lots of ways to do that. What we'll start talking about next time are conventions for how to do things like that. But notice that what this really depends on is I can make pairs of pairs. If all I could do was make pairs of numbers, I'd be stuck. OK. Let's break. [MUSIC PLAYING] All right, well, we've just gone off and done a couple of simple examples of data abstraction. Now I want to do something more complicated. We're going to talk about what it means. And this will be harder, because it's always much harder in computer programming to talk about what something means than to go off and do it. But let's go back to almost the very beginning. Let's go back to the point where I said, we just assumed that there were procedures, make-RAT, and numer, and denom. Let's go back to where we had this, at the very beginning, constructors and selectors, and wh en often defined the rational number arithmetic. And remember, I said at that point we were sort of done, except for George. Well, what is it that we'd actually done at that point? What was it that was done? Well, what I want to say is, what was done after we'd implemented the operations and terms of these, was that we had defined a rational number representation in terms of abstract data. What do I mean by abstract data? Well, the idea is that at that point, when we had our +RAT and our *RAT, that any implementation of make-RAT, and numerator, and denominator that George supplied us with, could be the basis for a rational number representation. Like, it wasn't our concern where you divided through to get the greatest common denominator, or any of that. So the idea is that what we built is a rational arithmetic system that would sit on top of any representation. What do I mean by any representation? I mean, certainly it can't be the case that all I mean is George can reach in a bag and pull out three arbitrary procedures and say, well, fine, now that's the implementation. That can't be what I mean. What I've got to mean is that there's some way of saying whether three procedures are going to be suitable as a basis for rational number representation. If we think about it, what suitable might mean is if I have to assume something like this, I have to say that if x is the result of say, doing make-RAT of n and d, then the numerator of x divided by the denominator of x is equal to n over d. See, what that is is that's George's contract. What we mean by writing a contract for rational numbers, if you think about it, this is the right thing. And the two ones we showed do the right thing. See, if I'm taking out greatest common divisors, it doesn't matter whether I take them out or not, or the place where I take them, because the idea is I'm going to divide through. But see, this is George's contract. So what we really say to George is your business is to go off and find us three procedures, make-RAT, and numerator, and denominator, that fulfill this contract for any choice of n and d. And that's what we mean by we can use that as the basis for a rational number representation. And other than that, it fulfills this contract. We don't care how he does it. It's not our business. It's below the layer of abstraction. In fact, if we want to say, what is a rational number really? See, what's it really, without having to talk about going below the layer of abstraction, what we're forced into saying is a rational number really is sort of this axiom, is three procedures, make-RAT, numerator, and denominator, that satisfy this axiom. In some sense, abstractly, that's what a rational number is really. That's sort of easy words to listen to, because what you have in your head, of course, is well, for all this thing about saying that's what a rational number is really, you actual ly just saw that we built rational numbers. See, what we really did is we built rational numbers on top of pairs. So for all I'm saying abstractly, we can say a rational number really is just this axiom. You can listen to that comfortably, because you're saying, well, yeah, but really it's actually pairs, and I'm just annoying you by trying to be abstract. Well, let me, as an antidote for that, let me do something that I think is really going to terrify you. I mean, it's really going to bring you face to face with the sort of existential reality of this abstraction that we're talking about. And what I'm going to talk about is, what are pairs really? See, what did I tell you about pairs? I tricked you, right? I said that Lisp has this primitive called cons that builds pairs. But what did I really tell you about? If you go back and said, let's look on this slide, all I really told you about pairs is that there happens to be this property, these properties of cons, car, and cdr. And all I really said about pairs is that there's a thing called cons, and a thing called car, and a thing called cdr. And it is the case that if I build cons of x, y and take car of it, I get x. And if I build cons of x, y and get cdr of it, I get y. And even though I lulled you into thinking that there's something in Lisp that does that, so you pretended you knew what it was, in fact, I didn't tell you any more about pairs than this tells you about rational numbers. It's just some axiom for pairs. Well, to drive that home, let me really scare you, and show you what we might build pairs in terms of. And what you're going to see is that we can build rational numbers, and line segments, and vectors, and all of this stuff in terms of pairs, and we're going to see below here that pairs can be built out of nothing at all. Pure abstraction. So let me show you on this slide an implementation of cons, car, and cdr. And we'll look at it again in a second, but notice that their procedure definitions of cons, car, and cdr, you don't see any data in there, what you see is a lambda. So cons here is going to return -- is a procedure that returns a procedure, just like average [UNINTELLIGIBLE]. Cons of a and b returns a procedure of an argument called pick, and it says, if pick is equal to 1, I'm going to return a, and if pick is equal to 2, I'm going to return b, and that's what cons is going to be. Car of a thing x, car of a pair x, is going to be x applied to 1. And notice that makes sense. You might not understand why or how I'm doing such a thing, but at least it makes sense, because the thing constructed by cons is a procedure, and car applies that to 1. And similarly, cdr applies that thing to 2. OK, now I claimed that this is a representation of cons, car, and cdr, and notice there's no data in it. All right, it's built out of air. It's just procedures. There's no data objects at all in that representation. Well, what could that possibly mean? Well, if you really believe this stuff, then you have to believe that in order to show that that's a representation for cons, car, and cdr, all I have to do is show that it satisfies the axiom. See, all I should have to convince you of is, for example, that gee, that car of cons of 37 and 49 is 37 for arbitrary values of 37 and 49. And cdr the same way. See, if I really can demonstrate to you that that weird procedure definition, in terms of [? air ?], has the property that it satisfies this, then you just have to grant me that that is a possible implementation of cons, car, and cdr, on which I can build everything else. Well, let's look at that. And this will be practice in the substitution model. How could we check this? We sort of know how to do that. It's just the same substitution model. Let's look. We start out, and we say, what's car of cons of 37 and 49? What do we do? Cons is some procedure. Its value is cons was a procedure of a and b. The thing returned by cons is its procedure body with 37 and 49 substituted for the parameters. It'll be 37 substituted for a and 49 substituted for b. So this expression has the same meaning as this expression. Its car of, and the body of cons was this thing that started with lambda. And it says, so if pick is equal to 1, where pick is this other argument, if pick is equal to 1, it's 37, that's where a was, and if pick is equal to 2, it's 49. So that's the first step. I'm just going through mechanical substitution. And remember, at this point in the course, if you're confused about what things mean, go mechanically through the substitution model. Well, what is this reduced to? Car said, take your argument, which in this case is this, and apply it to 1. That was the definition of car. So if I look at car, if I do that, the answer is, well, it's that argument, this was the argument to car, applied to 1. Well, what does that mean? I take 1, and I substitute it in the body here for this value of pick, which is the name of the argument, what do I get? Well, I get the thing that says if 1 equals 1 it's 37, and if 1 equals 2 it's 49, so the answer's 37. And similarly, if I'd taken cdr, that would apply it to 2, and I'd get 49. So you see, what I've demonstrated is that that completely weird implementation of cons, car, and cdr, satisfies the axioms. So it's a perfectly valid way of building, in fact, all of the data objects we're going to see in Lisp. So they all, if you like, can be built on sort of existential nothing. And as far as you know, that's how it works. You couldn't tell. If all you're ever going to do with pairs is construct them with cons and look at them with car and cdr, you couldn't possibly tell how this thing works. Now, it might give you a sort of warm feeling inside if I say, well, yeah, in fact, for various reasons there happens to be a primitive called cons, car, and cdr, and if it's too scary, if this kind of stuff is too scary, you don't have to look inside of it. So that might make you feel better, but the point is, it really could work this way, and it wouldn't make any difference to the system at all. So in some sense, we don't need data at all to build these data abstractions. We can do everything in terms of procedures. OK, well, why did I terrify you in this way? First, I really want to reinforce this idea of abstraction, that you really can do these things abstractly. Secondly, I want to introduce an idea we're going to see more and more of in this course, which is we're going to blur the line between what's data and what's a procedure. See, in this funny implementation it turned out that cons of something happened to be represented in terms of a procedure, even though we think of it as data. While here that's sort of a mathematical trick, but one of the things we'll see is that a lot of the very important programming techniques that we're going to get to sort of depend very crucially on blurring this traditional line between what you consider a procedure and what you consider data. We're going to see more and more of that, especially next time. OK, questions? AUDIENCE: If you asked the system to print a, what would happen? PROFESSOR: The question is, what would happen if I asked the system to print a. Given this representation, you already know the answer. The answer is compound procedure a, just like last time. It'd say compound procedure. It might say a little bit more. It might say compound procedure lambda or something or other, dependingon details of how I named it. But it's a procedure. And the only reason for that is I haven't told the system anything special about how to print such things. Now, it's in fact true that with the actual implementation of cons that to be built in the system, it would print something else. It would print, say, this is a pair. AUDIENCE: When you define cons, and then you pass it into values, how does it know where to look for the cons, because you can use cons over and over again? How does it know where to look to know which a and b it's supposed to pull back out? I don't know if I'm expressing that quite right. Where is it stored? PROFESSOR: OK, the question is, I sort of have a cons with a 37 and a 49, and I might make another cons with a 1 and a 2, and I might have one called a, and I might have one called b. And the question is, how does it know? And why don't they get confused? And that's a very good question. See, you have to really believe that the procedures are objects. It's sort of like saying -- let's try another simpler example. Suppose I ask for the square root of 3. So I asked for the square root of 5, and then I ask for the square of 20. You're probably not the least bit bothered that I can take square root and apply it to 5, and then I can take square root and apply it to 20. And there's sort of no issue, gee, doesn't it get confused about whether it's working on 5 or 20? There's no issue about that because you're thinking of a procedure which goes off and does something. Now, in some sense you're asking me the same question. But it's really bothering you, and it's bothering you for a really good reason. Because when I write that, you're saying gee, this is, I know, sort of a procedure. But it's not a procedure that's just running. It's ju st sort of a procedure sitting there. And how can it be that sometimes this procedure has 37 and 49, and there might be another one which has 5 and 6 in there, and why don't they get confused? So there's something very, very important that's bothering you. And it's really crucial to what's going on. We're suddenly saying that procedures are not just the act of doing something. Procedures are conceptual entities, objects, and if I built cons of 37 and 49, that's a particular procedure that sits there. And it's different from cons of 3 and 4. That's another procedure that sits there. AUDIENCE: Both of them exist independently. PROFESSOR: And exists independently. AUDIENCE: And they both can be referenced by car and cdr. PROFESSOR: And they both would be referenced by car and cdr. Just like I could increment this, and I could increment that. They're objects. And that's sort of where we're going. See, the fact that you're asking the question shows that you're really starting to think about the implications of what's going on. It's the difference between saying a procedure is just the act of doing something. And a procedure is a real object that has existence. AUDIENCE: So when the procedure gets built, the actual values are now substituted for a and b-- PROFESSOR: That's right. AUDIENCE: And then that procedure exists as lambda, and pick is what's actually passed in. PROFESSOR: Yes, when cons gets called, and the result of cons is a new procedure that's constructed, that new procedure has an argument that's called pick. AUDIENCE: But it no longer has an a and b. The a and b are the actual values that are passed through. PROFESSOR: And it has-- right, according to the substitution model, what it now has is not those arbitrary names a and b, it somehow has that 37 and 49 in there. But you're right, that's a hard thing to think about it, and it's different from the way you've been thinking about procedures. AUDIENCE: And if I have again cons of 37 and 49, it's a different [UNINTELLIGIBLE]? PROFESSOR: And if you make another cons of 37 and 49, you're into a wonderful philosophical problem, which is going to be what the lecture about halfway through this course is about. Which is, if I cons 37 and 49, and I do it agai n, is that the same thing, or is it a different thing? And how could you tell? And when could it possibly matter? And that's sort of like saying, is that the same thing as this? Or is this the same thing as that? It's the same kind of question. And that's a very, very deep question. And I can't answer in less than an hour. But we will. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec3a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 3A: Henderson Escher Example [MUSIC PLAYING] PROFESSOR: Well, last time we talked about compound data, and there were two main points to that business. First of all, there was a methodology of data abstraction, and the point of that was that you could isolate the way that data objects are used from the way that they're represented: this idea that there's this guy, George, and you go out make a contract with him; and it's his business to represent the data objects; and at the moment you are using them, you don't think about George's problem. And then secondly, there was this particular way that Lisp has of gluing together things to form objects called pairs, and that's done with cons, car and cdr. And the way that cons, car and cdr are implemented is basically irrelevant. That's sort of George's problem of how to build those things. It could be done as primitives. It could be done using procedures in some weird way, but we're not going to worry about that. And as an example, we looked at rational number arithmetic. We looked at vectors, and here's just a review of vectors. Here's an operation that takes the sum of of two vectors, so we want to add this vector, v1, and this vector, v2, and we get the sum. And the sum is the vector whose coordinates are the sum of the coordinates of the pieces you're adding. So I can say, to define make-vect, right, to add two vectors I make a vector, whose x coordinate is the sum of the two x coordinates, and whose y coordinate is the sum of the two y coordinates. And then similarly, we could have an operation that scales vectors, so here's a procedure scale that multiplies a vector, v, by some number, s. So here's v, v goes from there to there and I scale v, and I get a vector in the same direction that's longer. And again, to scale a vector, I multiply the successive coordinates. So I make a vector, whose x coordinate is the scale factor times the x coordinate and whose y coordinate is the scale factor times the y coordinate. So those are two operations that are implemented using the representation of vectors. And the representation of vectors, for instance, is something that we can build in terms of pairs. So George has gone out and implemented for us make-vector and x coordinate and y coordinate, and this could be done, for instance, using cons, car and cdr; and notice here, I wrote this in a slightly different way. The procedures we've seen before, I've said something like say, make-vector of x and y: cons of x and y. And here I just wrote make-vector cons. And that means something slightly different. Previously we'd say, define make-vector to be a procedure that takes two arguments, x and y, and does cons of x and y. And here I am saying define make-vector to be the thing that cons is, and that's almost the same as the other way we've been writing things. And I just want you to get used to the idea that procedures can be objects, and that you can name them. OK, well there's vector representation, and again, if that was all there was to it, this would all be pretty boring. And the point is, remember, that you can use cons to glue together not just numbers to form pairs, but to glue together arbitrary things. So for instance, if we'd like to represent a line segment, say the line segment that goes from a certain vector: say, the segment from the vector 2,3 to the point represented by the vector 5,1. If we want to represent that line segment, then we can build that as a pair of pairs. So again, we can represent line segments. We can make a constructor that makes a segment using cons, selects out the start of a segment, selects out the end point of the segment; and then if we actually look at that, if we peel away the abstraction layers, and say what's that really is a pair of pairs, we'd say well that's a pair. Here's the segment. It's car, right, it's car pointer is a pair, and it's cdr is also a pair, and then what the car is-- here's the car, that itself is a pair of 2 and 3. And similarly the cdr is a pair of 2 and 3. And let me remind you again, that a lot of people have some idea that if I'd taken this arrow and somehow written it to point down, that would mean something else. That's irrelevant. It's only how these are connected and not whether this arrow happens to go vertically or horizontally. And again just to remind you, there was this notion of closure. See, closure was the thing that allowed us to start building up complexity, that didn't trap us in pairs. Particularly what I mean is the things that we make, having combined things using cons to get a pair, those things themselves can be combined using cons to make more complicated things. Or as a mathematician might say, the set of data objects in List is closed under the operation of forming pairs. That's the thing that allows us to build complexity. And that seems obvious, but remember, a lot of the things in the computer languages that people use are not closed. So for example, forming arrays in basic and Fortran is not a closed operation, because you can make an array of numbers or character strings or something, but you can't make an array of arrays. And when you look at means of combination, you should be should be asking yourself whether things are closed under that means of combination. Well in any case, because we can form pairs of pairs, we can start using pairs to glue things toge ther in all sorts of different ways. So for instance if I'd like to glue together the four things, 1, 2, 3 and 4, there are a lot of ways I can do it. I could, for example, like we did with that line segment, I could make a pair that had a 1 and a 2 and a 3 and a 4, right? Or if I liked, I could do something like this. I could make a pair, whose first thing is a pair, whose car is 1, and his cdr is itself a pair that has the 2 and the 3, and then I could put the 4 up here. So you see, there are a lot of different ways that I can start using pairs to glue things together, and so it'll be a good idea to establish some kind of conventions, right, that allow us to deal with this thing in some conventional way, so we're not constantly making an ad hoc choice. And List has a particular convention for representing a sequence of things as, essentially, a chain of pairs, and that's called a List. And what a List is is essentially just a convention for representing a sequence. I would represent the sequence 1, 2, 3 and 4 by a sequence of pairs. I'd put 1 here and then the cdr of this would point to another pair whose car was the next thing in the sequence, and the cdr would point to another pair whose car was the next thing in the sequence-- so there's 3- - and then another one. So for each item in the sequence, I'll get a pair. And now there are no more, so I put a special marker that means there's nothing more in the List. OK, so that's a conventional way to glue things together if you want to represent a sequence, right. And what it is is a bunch of pairs, the successive cars of each pair are the items that you want to glue together, and the cdr pointer points to the next pair. Now if I actually wanted to construct that, what I would type into List is this: I'd actually construct that as saying, well this thing is the cons of 1 onto the cons of 2 onto the cons of 3 onto the cons of 4 onto, well, this thing nil. And what nil is is a name for the end of List marker. It's a special name, which means this is the end of the List. OK, so that's how I would actually construct that. Of course, it's a terrible drag to constantly have to write something like the cons of 1 onto the cons of 2 onto the cons of 3, whenever you want to make this thing. So List has an operation that's called List, and List is just an abbreviation for this nest of conses. So I could say, I could construct that by saying that is the List of 1, 2, 3 and 4. And all this is is another way, a piece of syntactic sugar, a more convenient way for writing that chain of conses-- cons of cons of cons of cons of cons of cons onto nil. So for example, I could build this thing and say, I'll define 1-TO-4 to be the List of 1, 2, 3 and 4. OK, well notice some of the consequences of using this convention. First of all if I have this List, this 1, 2, 3 and 4, the car of the whole thing is the first element in the List, right. How do I get 2? Well, 2 would be the car of the cdr of this thing 1-TO-4, it would be 2, right. I take this thing, I take the cdr of it, which is this much, and the car of that is 2, and then similarly, the car of the cdr of the cdr of 1-TO-4, cdr, cdr, car-- would give me 3, and so on. Let's take a look at that on the computer screen for a second. I could come up to List, and I could type define 1-TO-4 to be the List of 1, 2, 3 and 4, right. And I'll tell that to List, and it says, fine, that's the definition of 1-TO-4. And I could say, for instance, what's the car of the cdr of the cdr of 1-TO-4, close paren, close paren. Right, so the car of the cdr of the cdr would be 3. Right, or I could say, what's 1-TO-4 itself. And you see what List typed out is 1, 2, 3, 4, enclosed in parentheses, and this notation, typing the elements of the List enclosed in parentheses is List's conventional way for printing back this chain of pairs that represents a sequence. So for example, if I said, what's the cdr of 1-TO-4, that's going to be the rest of the List. That's the thing pointed to by the first pair, which is, again, a sequence that starts off with 2. Or for example, I go off and say, what's the cdr of the cdr of 1-TO-4; then that's 3,4. Or if I say, what's the cdr of the cdr of the cdr of the cdr of 1-TO-4, and I'm down there looking at the end of List pointer itself, and List prints that as just open paren, close paren. You can think of that as a List with nothing in there. All right, see at the end what I did there was I looked at the cdr of the cdr of the cdr of 1-TO-4, and I'm just left with the end of List pointer itself. And that gets printed as open close. All right, well that's a conventional way you can see for working down a List by taking successive cdrs of things. It's called cdring down a List. And of course it's pretty much of a drag to type all those cdrs by hand. You don't do that. You write procedures that do that. And in fact one very, very common thing to do in List is to write procedures that, sort of, take a List of things and do something to every element in List, and return you a List of the results. So what I mean for example, is I might write a procedure called Scale-List, and Scale-List I might say I want to scale by 10 the entire List 1-TO-4, and that would return for me the List 10, 20, 30, 40. [UNINTELLIGIBLE PHRASE] Right, it returns List, and well you can see that there's going to be some kind of recursive strategy for doing it. How would I actually write that procedure? The idea would be, well if you'd like to build up a List where you've multiplied every element by 10, what you'd say is well you imagine that you'd taken the rest of the List-- right, the thing represented by the cdr of the List, and suppose I'd already built a List where each of these was multiplied by 10-- that would be Scale-List of the cdr of the List. And then all I have to do is multiply the car of the List by 10, and then cons that onto the rest, and I'll get a List. Right and then similarly, to have scaled the cdr of the List, I'll scale the cdr of that and cons onto that 2 multiplied by 10. And finally when I get all the way down to the end, and I only have this end of List pointer. All right, this thing whose name is nil -- well I just returned an end of List pointer. So there's a recursive strategy for doing that.Here's the actual procedure that does that. Right, this is an example of the general strategy of cdr -ing down a List and so called cons-ing up the result, right. So to Scale a List l by some scale factor s, what do I do? Well there's a test, and List ha s the predicate called null. Null means is this thing the end of List pointer, or another way to think of that is are there any elements in this List, right. But in any case if I'm looking at the end of List pointer, then I just return the end of List pointer. I just return nil, otherwise I cons together the result of doing what I'm going to do to the first element in the List, namely taking the car of l and multiplying it by s, and I cons that onto recursively scaling the rest of the List. OK, so again, the general idea is that you recursively do something to the rest of the List, to the cdr of the List, and then you cons that onto actually doing something to the first element of the List. When you get down to the end here, you return the end of List pointer, and that's a general pattern for doing something to a List. Well of course you should know by now that the very fact that there's a general pattern there means I shouldn't be writing this procedure at all. What I should do is write a procedure that's the general pattern itself that says, do something to everything in the List and define this thing in terms of that. Right, make some higher order procedure, and here's the higher order procedure that does that. It's called MAP, and what MAP does is it takes a List, takes a List l, and it takes a procedure p, and it returns the List of the elements gotten by applying p to each successive element in the List. All right, so p to v1, p to v2, p of en. Right, so I think of taking this List and transforming it by applying p to each element. And you see all this procedure is is exactly the general strategy I said. Instead of multiply by 10, it's do the procedure. If the List is empty, return nil. Otherwise, apply p to the first element of the List. Right, apply p to car of l, and cons that onto the result of applying p to everything in the cdr of the List, so that's a general procedure called MAP. And I could define Scale-List in terms of MAP. Let me show you that first. But I could say Scale-List is another way to define it is just MAP along the List by the procedure, which takes an item and multiplies it by s. Right, so this is really the way I should think about scaling the List, build that actual recursion into the general strategy, not to every particular procedure I write. And of course, one of the values of doing this is that you start to see commonality. Right, again you're capturing general patterns of usage. For instance, if I said MAP, the square procedure, down this List 1-TO-4, then I'd end up with 1, 4, 9 and 16. Right, or if I said MAP down this List, lambda of x plus x10, if I MAP that down 1-TO-4, then I'd get the List where everything had 10 added to it: right, so I'd get 11, 12, 13, 14. And you can see that's going to be a very, very common idea: doing something to every element in the List. One thing you might think about is writing MAP in an iterative style. The one I wrote happens to evolve a recursive process, but we could just as easily have made one that evolves an iterative process. But see the interesting thing about it is that once you start thinking in terms of MAP -- see, once you say scale is just MAP, you stop thinking about whether it's iterative or recursive, and you just say, well there's this aggregate, there's this List, and what I do is transform every item in the List, and I stop thinking about the particular control structure in order. That's a very, very important idea, and it, I guess it really comes out of APL. It's, sort of, the really important idea in APL that you stop thinking about control structures, and you start thinking about operations on aggregates, and then about halfway through this course, we'll see when we talk about something called stream processing, how that view of the world really comes into its glory. This is just us a, sort of, cute idea. But we'll see much more applications of that later on. Well let me mention that there's something that's very similar to MAP that's also a useful idea, and that's-- see, MAP says I take a List, I apply something to each item, and I return a List of the successive values. There's another thing I might do, which is very, very similar, which is take a List and some action you want to do and then do it to each item in the List in sequence. Don't make a List of the values, just do this particular action, and that's something that's very much like MAP. It's called for-each, and for-each takes a procedure and a List, and what it's going to do is do something to every item in the List. So basically what it does: it says if th e List is not empty, right, if the List is not null, then what I do is, I apply my procedure to the first item in the List, and then I do this thing to the rest of the List. I apply for-each to the cdr of the List. All right, so I do it to the first of the List, do it to the rest of the List, and of course, when I call it recursively, that's going to do it to the rest of the rest of the List and so on. And finally, when I get done, I have to just do something to say I'm done, so we'll return the message "done." So that's very, very similar to MAP. It's mostly different in what it returns. And so for example, if I had some procedure that printed things on the screen, if I wanted to print everything in the List, I could say for-each, print this List. Or if I had a List of figures, and I wanted to draw them on the display, I could say for-each, display on the screen this figure. Let's take questions. AUDIENCE: Does it create a new copy with something done to it, unless you explicitly tell it to do that? Is that correct? PROFESSOR: Right. Yeah, that's right. For-each does not create a List. It just sort of does something. So if you have a bunch of things you want to do and you're not worried about values like printing s omething, or drawing something on the screen, or ringing the bell on the terminal, or for something, you can say for-each, you know, do this for-each of those things in the List, whereas MAP actually builds you this new collection of values that you might want to use. It's just a subtle difference between them. AUDIENCE: Could you write MAP using for-each, so that you did some sort of cons or something to build the List back up? PROFESSOR: Well, sort of. I mean, I probably could. I can't think of how to do it right offhand, but yeah, I could arrange something. AUDIENCE: The vital difference between MAP and for-each is one is recursive and the other is not in the sense you defined early yesterday, I believe. PROFESSOR: Yeah, about MAP and for-each and recursion. Yeah, that's a good point. For the MAP procedure I wrote, that happens to be a recursive process. And the reason for that is that when you've done this thing to the rest of the List, you're waiting for that value so that you can stick it on to the beginning of the List, whereas for-each doesn't really have any values to wait for. So that turns out to be an iterative process. That's not fundamental. I could have defined MAP so that it's evolved by an iterative process. I just didn't happen to. AUDIENCE: If you were to cons for each with a List that had embedded Lists, I imagine it would work, right? It would give you the internal elements of each of those internal Lists? PROFESSOR: OK, the question is if I [UNINTELLIGIBLE] for each or MAP, for that matter, with a List that had Lists in it-- although we haven't really looked at that yet-- would that work. The answer is yes in the sense I mean work and no in the sense that you mean work, because all that-- see if I give you a List, where hanging off here is, you know, is something that's not a number, maybe another List or you know, another cons or something, for -each just says do something to each item in this List. It goes down successively looking at the cdrs. AUDIENCE: OK. PROFESSOR: And as far as it's concerned, the first item in this List is whatever is hanging off here. AUDIENCE: Mhm. PROFESSOR: That might or might not be the right thing. AUDIENCE: So it wouldn't go down into the-- PROFESSOR: Absolutely not. I could certainly write something else. There's another, what you're looking for is a common pattern of usage called tree recursion, where you take a List, and you actually go all the way down to the what's called the leaves of the tree. And you could write such a thing, but that's not for-each and it's not MAP. Remember, these things are really being very simple minded. OK, no more questions? All right, let's break. [MUSIC PLAYING] PROFESSOR: What I'd like to do now is spend the rest of this time talking about one example, and this example, I think, pretty much summarizes everything that we've done up until now: all right, and that's List structure and issues of abstraction, and representation and capturing commonality with higher order procedures, and also is going to introduce something we haven't really talked about a lot yet-- what I said is the major third theme in this course: meta-linguistic abstraction, which is the idea that one of the ways of tackling complexity in engineering design is to build a suitable powerful language. You might recall what I said was pretty much the very most important thing that we're going to tell you in this course is that when you think about a language, you think about it in terms of what are the primitives; what are the means of combination-- right, what are the things that allow you to build bigger things; and then what are the means of abstraction. How do you take those bigger things that you've built and put black boxes around them and use them as elements in making something even more complicated? Now the particular language I'm going to talk about is an example that was made up by a friend of ours called Peter Henderson. Peter Henderson is at the University of Stirling in Scotland. And what this language is about is making figures that sort of look like this. This is this is a woodcut by Escher called "Square Limit." You, sort of, see it has this complicated, kind of, recursive, sort of, recursive kind of figure, where there's this fish pattern in the middle and things sort of bleed out smaller and smaller in self similar ways. Anyway, Peter Henderson's language was for describing figures that look like that and designing new ones that look like that and drawing them on a display screen. There's another theme that we'll see illustrated by this example, and that's the issue of what Gerry and I have already mentioned a lot: that there's no real difference, in some sense, between procedures and data. And anyway I hope by the end of this morning, if you're not a lready, you will be completely confused about what the difference between procedures and data are, if you're not confused about that already. Well in any case, let's start describing Peter's language. I should start by telling you what the primitives are. This language is very simple because there's only one primitive. A primitive is not quite what you think it is. There's only one primitive called a picture, and a picture is not quite what you think it is. Here's an example. This is a picture of George. The idea is that a picture in this language is going to be something that draws a figure scaled to fit a rectangle that you specify. So here you see in [? Saint ?] [? Lawrence's ?] outline of a rectangle, that's not really part of the picture, but the picture-- you'll give it a rectangle, and it will draw this figure scaled to fit the rectangle. So for example, there's George, and here, this is also George. It's the same picture, right, just scaled to fit a different rectangle. Here's George as a fat kid.That's the same George. It's all the same figure. All of these three things are the same picture in this language. I'm just giving it different rectangles to scale itself in. OK, those are the primitives. That is the primitive. Now let's start talking about the means of combination and the operations. There is, for example, an operation called Rotate. And what Rotate does is, if I have a picture, say a picture that draws an "A" in some rectangle that I give it, the Rotate of that-- say the Rotate by 90 degrees would, if I give it a rectangle, draw the same image, but again, scaled to fit that rectangle. So that's Rotate by 90 degrees. There's another operation called Flip that can flip something, either horizontally or vertically. All right, so those are,sort of, operations, or you can think of those as means of combination of one element. I can put things together. There's a means of combination called Beside, and what Beside does: it'll take two pictures, let's say A and B-- and by picture I mean something that's going to draw an image in a specified rectangle-- and what Beside will do-- I have to say, Beside of A and B, the side of two pictures and some number, s. And s will be a number between zero and one. And Beside will draw a picture that looks like this. It will take the rectangle you give it and scale its base by s. Say s is 0.5. And then over here it will draw-- it'll put the first picture, and over here it'll put the second picture. Or for instance if I gave it a different value of s, if I said Beside with a 0.25, it would do the same thing, except the A would be much skinnier. So it would draw something like that. So there's a means of combination Beside, and similarly there's an Above, which does the same thing except it puts them vertically instead of horizontally. Well let's look at that. All right, there's George and his kid brother, which is, right, constructed by taking George and putting him Beside the Above-- taking the empty picture, and there's a thing called the empty picture, which does the obvious thing-- putting the empty picture above a copy of George, and then putting that whole thing Beside George. Here's something called P which is, again, George Beside Flipping George, I think, horizontally in this case, and then Rotating the whole result 180 degrees and putting them Beside one another with the basic rectangle divided at 0.5, right, and I can call that P. And then I can take P, and put it above the Flipped copy of itself, and I can call that Q. Notice how rapidly that we've built up complexity, just in, you know, 15 seconds, you've gotten from George to that thing Q. Why is that? How are how we able to do that so fast? The answer is the closure property. See, it's the fact that when I take a picture and put it Beside another picture, that's then, again, a picture that I can go and Rotate and Flip or put Above something else. Right, and when I take that element P, which is the Beside or the Flip or the Rotate of something, that's, again, a picture. Right, the world of pictur es is closed under those means of combination. So whenever I have something, I can turn right around and use that as an element in something else. So maybe better than List and segments, that just gives you an image for how fast you can build up complexity , because operations are closed. OK, well before we go on with building more things, let's talk about how this language is actually implemented. The basic element that sits under the table here is a thing called a rectangle, and what a rectangle is going to be, it's a thing that specified by an origin that's going to be some vector that says where the rectangle starts. And then there's going to be some other vector that I'm going to call the horizontal part of the rectangle, and another picture called the vertical part of the rectangle. And those three pieces are the elements: where the lower vertex is, how you get to the next vertex over here, and how you get to the vertex over there. The three vectors specify a rectangle. Now to actually build rectangles, what I'll assume is that we have a constructor called "make rectangle," or "make-rect," and selectors for horiz and vert and origin that get out the pieces of that rectangle. And well, you know a lot of ways you can do thi s now. You can do it by using pairs in some way or other standard List or not. But in any case, the implementation of these things, that's George's problem. It's just a data representation problem. So let's assume we have these rectangles to work with. OK. Now the idea of this, remember what's got to happen. Somehow we have to worry about taking the figure and scaling it to fit some rectangle that you give it, that's the basic thing you have to arrange, that these pictures can do. How do we think about that? Well, one way to think about that is that any time I give you a rectangle, that defines, in some sense, a transformation from the standard square into that rectangle. Let me say what I mean. By the standard square, I'll mean something, which is a square whose coordinates are 0,0, and 1,0, and 0,1 and 1,1. And there's some sort of the obvious scaling transformation, which maps this to that and this to that, and sort of, stretches everything uniformly. So we take a line segment like this and end up mapping it to a line segment like that, so some point xy goes to some other point up there. And although it's not important, with a little vector algebra, you could write that formula. The thing that xy goes to, the point that xy goes to is gotten by taking the origin of the rectangle and then adding that as a vector to-- well, take x, the x coordinate, which is something between zero and one, multiply that by the horizontal vector of the rectangle; and take the y coordinate, which is also something between zero and one and multiply that by the vertical vector of the rectangle. That's just a little linear algebra. Anyway, that's the formula, which is the right obvious transformation that takes things into the unit square, into the interior of that rectangle. OK well, let's actually look at that as a procedure. So what we want is the thing which tells us that particular transformation that a rectangle defines. So here's the procedure. I'll call it coordinate-map. Coordinate-map is the thing that takes as its argument a rectangle and returns for you a procedure on points. Right, so for each rectangle you get a way of transforming a point xy into that rectangle. And how do you get it? Well I just-- writing in List what I wrote there on the blackboard-- I add to the origin of the rectangle the result of adding-- I take the horizontal part of the rectangle; I scale that by the x coordinate of the point. I take the vertical vector of the rectangle. I scale that by the y coordinate of the point, and then add all those three things up. That's the procedure. That is the procedure that I'm going to apply to a point. And this whole thing is generated for each rectangle. So any rectangle defines a coordinate MAP, which is a procedure on points. OK. All right, so for example , George here, my original George, might have been something that I specified by segments in the unit square, and then for each rectangle I give this thing, I'm going to draw those segments inside that rectangle. How actually do I do that? Well I take each segment in my original reference George that was specified, and to each of the end points of those segments, I applied the coordinate MAP of the particular rectangle I want to draw it in. So for example, this lower rectangle, this George as a fat kid rectangle, has its coordinate MAP. And if I want to draw this image, what I do is for each segment here, say for this segment, I transformed that point by the coordinate MAP, transform that point by the coordinate MAP. That will give me this point and that point and draw the segment between them. Right, that's the idea. Right, and if I give it a different rectangle like this one, that's a different coordinate MAP, so I get a different image of those line segments. Well how do we actually get a picture to start with? I can build a picture to start with out of a List of line segments initially. Here's a procedure that builds what I'll call a primitive picture, meaning one I, sort of, got that didn't come out of Beside or Rotate or something. It starts with a List of line segments, and now it does what I said. What's a picture have to be? First of all it's a procedure that's defined on rectangles. What does it do? It says for each-- this is going to be a List of line segments-- for each segment, for each s, which is a segment in this List of segments, well it draws a line. What line does it draw? It gets the start point of that segment, transforms that by the coordinate MAP of the rectangle. That's the first new point it wants to do. Then it takes the endpoint of the segment, transforms that by the coordinate MAP of the rectangle, and then draws a line between. Let's assume drawline is some primitive that's built into the system that actually draws a line on the display. All right, so it transforms the endpoints by the coordinate MAP of the rectangle, draws a line between them, does that for each s in this List of segments. And now remember again, a picture is a procedure that takes a rectangle as argument. So when you hand it a rectangle, this is what it does: draws those lines. All right, so there's-- how would I actually use this thing? Let's make it a little bit more concrete. Right, I would say for instance, define R to be make - rectangle of some stuff, and I'd have to specify some vectors here using make-vector. And then I could say, define say, G to be make-picture, and then some stuff. And what I'd have to specify here is a List of line segments, right, using make segment. Make-segment might be made out of vectors, and vectors might be made out of points. And then if I actually wanted to see the image of G inside a rectangle, well a picture is a procedure that takes a rectangle as argument. So if I then called G with an input of R, that would cause whatever image G is worrying about to be drawn inside the rectangle R. Right, so that's how you'd use that. [MUSIC PLAYING] PROFESSOR: Well why is it that I say this example is nice? You probably don't think it's nice. You probably think it's more weird than nice. Right, representing these pictures as procedures, which do complicated things with rectangles. So why is it nice? The reason it's nice is that once you've implemented the primitives in this way, the means of combination just fall out by implementing procedures. Let me show you what I mean. Suppose wewant to implement Beside. So I'd like to -- suppose I've got a picture. Let's call it P1. P1 is going to be-- and now remember what a picture really is. It's a thing that if you can hand it some rectangle, it will cause an image to be drawn in whatever rectangle you hand it. And suppose P2 two is some other picture, and you hand that a rectangle. And whatever rectangle you hand it, it draws some picture. And now if I'd like to implement Beside of P1 and P2 with a scale factor A, well what does that have to be? That's got to be picture. It's got to be a thing that you hand it a rectangle, and it draws something in that rectangle. So if hand Beside this rectangle-- let's hand it a rectangle. Well what's it going to do? it's going to take this rectangle and split it into two at a ratio of A and one minus A. And it will say, oh sure, now I've got two rectangles. And now it goes off to P1 and says P1, well draw yourself in this rectangle, and goes off to P2, and says, P2, fine, draw yourself in this rectangle. The only computation it has to do is figure out what these rectangles are. Remember a rectangle is specified by an origin and a horizontal vector and a vertical vector, so it's got to figure out what these things are. So for this first rectangle, the origin turns out to be the origin of the original rectangle, and the vertical vector is the same as the vertical vector of the original rectangle. The horizontal vector is the horizontal vector of the original rectangle scaled by A. And that's the first rectangle. The second rectangle, the origin is the original origin plus that horizontal vector scaled by A. The horizontal vector of the second rectangle is the rest of the horizontal vector of the first one, which is 1 minus A times the original H, and the ve rtical vector is still v. But basically it goes and constructs these two rectangles, and the important point is having constructed the rectangles, it says OK, p1, you draw yourself in there, and p2, you draw yourself in there, and that's all Beside has to do. All right, let's look at that piece of code. Beside of a picture and another picture with some scaling ratio is first of all, since it's a picture, a procedure that's going to take a rectangle as argument. What's it going to do? It says, p1 draw yourself in some rectangle and p2 draw yourself in some other rectangle. And now what are those rectangles? Well here's the computation. It makes a rectangle, and this is the algebra I just did on the board: the origin, so mething; the horizontal vector, something; and the vertical vector, something. And for p2, the rectangle it wants has some other origin and horizontal vector and vertical vector. But the important point is that all it's saying is, p1, go do your thing in one rectangle, and p2, go do your thing in another rectangle. That's all the Beside has to do. OK, similarly Rotate-- see if I have this picture A, and I want to look at say rotating A by 90 degrees, what that should mean is, well take this rectangle, which is origin and horizontal vector and vertical vector, and now pretend that it's really the rectangle that looks like this, which has an origin and a horizontal vector up here, and a vertical vector there, and now draw yourself with respect to that rectangle. Let me show you that as a procedure. All right, so we'll Rotate 90 of the picture, because again, a procedure for rectangle, which says, OK picture, draw yourself in some rectangle; and then this algebra is the transformation on the rectangle. It's the one which makes it look like the rectangle is sideways, the origin is someplace else and the vertical vector is someplace else, and the horizontal vector is someplace else, and vertical vector is someplace else. OK? OK. OK, again notice, the crucial thing that's going on here is you're using the representation of pictures as procedures to automatically get the closure property, because what happens is, Beside just has this thing p1. Beside doesn't care if that's a primitive picture or it's line segments or if p1 is, itself, the result of doing Aboves or Besides or Rotates. All Beside has to know about, say, p1 is that if you hand p1 a rectangle, it will cause something to be drawn. And above that level, Beside just doesn't-- it's none of its business how p1 accomplishes that drawing. All right, so you're using the procedural representation to ensure this closure. OK. So implementing pictures as procedures makes these means of combination, you know, both pretty simple and also, I think, elegant. But that's not the real punchline. The real punchline comes when you look at the means of abstraction in this language. Because what have we done? We've implemented the means of combination themselves as procedures. And what that means is that when we go to abstract in this language, everything that List supplies us for manipulating procedures is automatically available to do things in this picture language. The technical term I want to say is not only is this language implemented in List, obviously it is, but the language is nicely embedded in List. What I mean is by embedding the language in this way, all the power of List is automatically available as an extension to whatever you want to do. And what do I mean by that? Example: say, suppose I want to make a thing that takes four pictures A, B, C and D, and makes a configuration that looks like this. Well you might call that, you know, four pictures or something, four-pict configuration. How do I do that? Well I can obviously do that. I just write a procedure that takes B above D and A above C and puts those things beside each other. So I automatically have List's ability to do procedure composition. And I didn't have to make that specifically in the picture language. It's automatic from the fact that the means of combination are themselves procedures. Or suppose I wanted to do something a little bit more complicated. I wanted to put in a parameter so that for each of these, I could independently specify a rotation by 90 degrees. That's just putting a parameter in the procedure. It's automatically there. Right, it automatically comes from the embedding. Or even more, suppose I wanted to, you know, use recursion. Let's look at a recursive means of combination on pictures. I could say define -- let's see if you can figure out what this one is-- suppose I say define what it means to right-push a picture, right-push a picture and some integer N and some scale factor A. I'll define this to say if N equals 0, then the answer is the picture. Otherwise I'm going to put -- oops, name change: P. Otherwise, I'm going to take P and put it beside the results of recursively right- pushing P with N minus 1 and A and use a scale factor of A. OK, so if N0 , it's P. Otherwise I put P with a scale factor of A-- I'm sorry I didn't align this right-- recursively beside the result of right-pushing P, N minus 1 times with a scale factor of A. There's a recursive means of combination. What's that look like? Well, here's what it looks like. There's George right-pushed against himself twice with a scale factor of 0.75. OK. Where'd that come from? How did I get all this fancy recursion? And the answer is just automatic, absolutely automatic. Since these are procedures, the embedding says, well sure, I can define recursive procedures. I didn't have to arrange that. And of course, we can do more complicated things of the same sort. I could make something that does an up - push. Right, that sort of goes like this, by recursively putting something above. Or I could make something that, sort of, was this scheme. I might start out with a picture and then, sort of, recursively both push it aside and above, and that might put something there. And then up here I put the same recursive thing, and I might end up with something like this. Right, so there's a procedure that's a little bit more complicated than right- push but not much. I just do an Above and a Beside, rather than just a Beside. Now if I take that and apply that with the idea of putting four pictures together, which I can surely do; and I go and I apply that to Q, which we defined before, right, what I end up with this is this thing, which is, sort of, the square limit of Q, done twice. Right, and then we can compare that with Escher's "Square Limit." And you see, it's sort of the same idea. Escher's is, of course, much, much prettier. If we go back and look at George, right, if we go look at George here-- see, I started with a fairly arbitrary design, this picture of George and did things with it. Right, whereas if we go look at the Escher picture, right, the Escher picture is not an arbitrary design. It's this very, very clever thing, so that when you take this fish body and Rotate it and shrink it down, it bleeds into the next one really nicely. And of course with George, I didn't really do anything like that. So if we look at George, right, there's a little bit of match up, but not very nice, and it's pretty arbitrary. One very nice project, by the way, would be to write a procedure that could take some basic figure like this George thing and start moving the ends of the lines around, so you got a really nice one when you went and did that "Square Limit" process. That'd be a really nice thing to think about. Well so, we can combine things. We can recursive procedures. We can do all kindsof things, and that's all automatic. Right, the important point, the difference between merely implementing something in a language and embedding something in the language, so that you don't lose the original power of the language, and what List is great at, see List is a lousy language for doing any particular problem. What it's good for is figuring out the right language that you want and embedding that in List. That's the real power of this approach to design. Of course, we can go further. See, you saw the other thing that we can do in List is capture general methods of doing things as higher order procedures. And you probably just from me drawing it got the idea that right-push and the analogous thing where you push something up and up and up and up and this corner push thing are all generalizations of a common kind of idea. So just to illustrate and give you practice in looking at a fairly convoluted use of higher order procedures, let me show you the general idea of pushing some means of combination to recursively repeat it. So here's a good one to puzzle out. We'll define it what it means to push using a means of combination. Comb is going to be something like the Beside or Above. Well what's that going to be. That's going to be a procedure, remember what Beside actually was, right. It took a picture, took two pictures and a scale factor. Using that I produced something that took a level number and a picture and a scale factor, that I called right-push. So this is going to be something that takes a picture, a level number and a scale factor, and it's going to say-- I'm going to do some repeated operation. I'm going to repeatedly apply the procedure which takes a picture and applies the means of combination to the pictu re and the original picture and the one I took in here and the scale factor, and I do the thing which repeats this procedure N times, and I apply that whole thing to my original picture. Repeated here, in case you haven't seen it, is another higher orderprocedure that takes a procedure and a number and returns for you another procedure that applies this procedure N times. And I think some of you have already written repeated as an exercise, but if you haven't, it's a very good exercise in thinking about higher order procedures. But in any case, the result of this repeated is what I apply to picture. And having done that, that's going to capture-- that is the thing, the way I got from the idea of Beside to the idea of right-push So having done that, I could say define right-push to be push of Beside. Or if I say, define up-push to be push of Beside, I'd get the analogous thing or define corner-push to be push of some appropriate thing that did both the Beside and Above, or I could push anything. Anyway this is, if you're having trouble with lambdas, this is an excellent exercise in figuring out what this means. OK, well there's a lot to learn from this example. The main point I've been dwelling on is the notion of nicely embedding a language inside another language. Right, so that all the power of this language like List of the surrounding language is still accessible to you and appears as a natural extension of the language that you built. That's one thing that this example shows very well. OK. Another thing is, if you go back and think about that, what's procedures and what's data. You know, by the time we get up to here, my God, what's going on. I mean, this is some procedure, and it takes a picture and an argument, and what's a picture. Well, a picture itself, as you remember, was a procedure, and that took a rectangle. And a rectangle is some abstraction. And I hope now that by now you're completely lost as to the question of what in the system is procedure and what's data. You see, there isn't any difference. There really isn't. And you might think of a picture sometimes as a procedure and sometimes as data, but that's just, sort of, you know, making you feel comfortable. It's really both in some sense or neither in some sense. OK, there's a more general point about the structure of the system as creating a language, viewing the engineering design process as one of creating language or rather one of creating a sort of sequence of layers of language. You see, there's this methodology, or maybe I should say mythology, that's, sort of, charitably called software, quote, engineering. All right, and what does it say, it's says well, you go and you figure out your task, and you figure out exactly what you want to do. And once you figure out exactly what you want to do, you find out that it breaks out into three sub-tasks, and you go and you start working on-- and you work on this sub-task, and you figure out exactly what that is. And you find out that that breaks down into three sub-tasks, and you specify them completely, and you go and you work on those two, and you work on this sub -one, and you specify that exactly. And then finally when you're done, you come back way up here, and you work on your second sub-task, and specify that out and work it out. And then you end up with-- you end up at the end with this beautiful edifice. Right, you end up with a marvelous tree, where you've broken your task into sub-tasks and broken each of these into sub-tasks and broken those into sub-tasks, right. And each of these nodes is exactly and precisely defined to do the wonderful, beautiful task to make it fit into the whole edifice, right. That's this mythology. See only a computer scientist could possibly believe that you build a complex system like that, right. Contrast that with this Henderson example. It didn't work like that. What happened was that there was a sequence of layers of language. What happened? There was a layer of a thing that allowed us to build primitive pictures. There's primitive pictures and that was a language. I didn't say much about it. We talked about how to construct George, but that was a language where you talked about vectors and line segments and points and where they sat in the unit square. And then on top of that, right, on top of that-- so this is the language of primitive pictures. Right, talking about line segments in particular pictures in the unit square. On top of that was a whole language. There was a language of geometric combinators, a language of geometric positions, which talks about things like Above and Beside and right-push and Rotate. And those things, sort of, happened with reference to the things that are talked about in this language. And then if we like, we saw that above that there was sort of a language of schemes of combination. For example, push, which talked about repeatedly doing something over with a scale factor. And the things that were being discussed in that language were, sort of, the things that happened down here. So what you have is, at each level, the objects that are being talked about are the things that were erected at the previous level. What's the difference between this thing and this thing? The answer is that over here in the tree, each node, and in fact, each decomposition down here, is being designed to do a specific task, whereas in the other scheme, what you have is a full range of linguistic power at each level. See what's happening there, at any level, it's not being set up to do a particular task. It's being set up to talk about a whole range of things. The consequence of that for design is that something that's designed in that method is likely to be more robust, where by robust, I mean that if you go and make some change in your description, it's more likely to be captured by a corresponding change, in the way that the language is implemented at the next level up, right, because you've made these levels full. So you're not talking about a particular thing like Beside. You've given yourself a whole vocabulary to express things of that sort, so if you go and change your specifications a little bit, it's more likely that your methodology will able to adapt to capture that change, whereas a design like this is not going to be robust, because if I go and change something that's in here, that migh t affect the entire way that I decomposed everything down, further down the tree. Right, so very big difference in outlook in decomposition, levels of language rather than, sort of, a strict hierarchy. Not only that, but when you have levels of language you've given yourself a different vocabularies for talking about the design at different levels. So if we go back and look at George one last time, if I wanted to change this picture George, see suddenly I have a whole different ways of describing the change. Like for example, I may want to go to the basic primitive design and move the endpoint of some vector. That's a change that I would discuss at the lowest level. I would say the endpoint is somewhere else. Or I might come up and say, well the next thing I wanted to do, this little replicated element, I might want to do by something else. I might want to put a scale factor in that Beside. That's a change that I would discuss at the next level of design, the level of combinators. Or I might want to say, I might want to change the basic way that I took this pattern and made some recursive decomposition, maybe not bleeding out toward the corners or something else. That would be a change that I would discuss at the highest level. And because I've structured the system to be this way, I have all these vocabularies for talking about change in different ways and a lot of flexibility to decide which one's appropriate. OK, well that's sort of a big point about the difference in software methodology that comes out from List, and it all comes, again, out of the notion that really, the design process is not so much implementing programs as implementing languages. And that's really the powerful of List. OK, thank you. Let's take a break. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec3b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 3B: Symbolic Differentiation; Quotation [MUSIC PLAYING] PROFESSOR: Well, Hal just told us how you build robust systems. The key idea was-- I'm sure that many of you don't really assimilate that yet-- but the key idea is that in order to make a system that's robust, it has to be insensitive to sm all changes, that is, a small change in the problem should lead to only a small change in the solution. There ought to be a continuity. The space of solutions ought to be continuous in this space of problems. The way he was explaining how to do that was instead of solving a particular problem at every level of decomposition of the problem at the subproblems, where you solve the class of problems, which are a neighborhood of the particular problem that you're trying to solve. The way you do that is by producing a language at that level of detail in which the solutions to that class of problems is representable in that language. Therefore when you makes more changes to the problem you're trying to solve, you generally have to make only small local changes to the solution you've constructed, because at the level of detail you're working, there's a language where you can express the various solutions to alternate problems of the same type. Well that's the beginning of a very important idea, the most important perhaps idea that makes computer science more powerful than most of the other kinds of engineering disciplines we know about. What we've seen so far is sort of how to use embedding of languages. And, of course, the power of embedding languages partly comes from procedures like this one that I showed you yesterday. What you see here is the derivative program that we described yesterday. It's a procedure that takes a procedure as an argument and returns a procedure as a value. And using such things is very nice. You can make things like push combinators and all that sort of wonderful thing that you saw last time. However, now I'm going to really muddy the waters. See this confuses the issue of what's the procedure and what is data, but not very badly. What we really want to do is confuse it very badly. And the best way to do that is to get involved with the manipulation of the algebraic expressions that the procedures themselves are expressed in. So at this point, I want to talk about instead of things like on this slide, the derivative procedure being a thing that manipulates a procedure-- this is a numerical method you see here. And what you're seeing is a representation of the numerical approximation to the derivative. That's what's here. In fact what I'd like to talk about is instead things that look like this. And what we have here are rules from a calculus book. These are rules for finding the derivatives of the expressions that one might write in some algebraic language. It says things like a derivative of a constant is 0. The derivative of the valuable with respect to which you are taking the derivative is 1. The derivative of a constant times the function is the constant times the derivative of the function, and things like that. These are exact expressions. These are not numerical approximations. Can we make programs? And, in fact, it's very easy to make programs that manipulate these expressions. Well let's see. Let's look at these rules in some detail. You all have seen these rules in your elementary calculus class at one time or another. And you know from calculus that it's easy to produce derivatives of arbitrary expressions. You also know from your elementary calculus that it's hard to produce integrals. Yet integrals and derivatives are opposites of each other. They're inverse operations. And they have the same rules. What is special about these rules that makes it possible for one to produce derivatives easily and integrals why it's so hard? Let's think about that very simply. Look at these rules. Every one of these rules, when used in the direction for taking derivatives, which is in the direction of this arrow, the left side is matched against your expression, and the right side is the thing which is the derivative of that expression. The arrow is going that way. In each of these rules, the expressions on the right -hand side of the rule that are contained within derivatives are subexpressions, are proper subexpressions, of the expression on the left-hand side. So here we see the derivative of the sum, with is the expression on the left-hand side is the sum of the derivatives of the pieces. So the rule of moving to the right are reduction rules. The problem becomes easier. I turn a big complicated problem it's lots of smaller problems and then combine the results, a perfect place for recursion to work. If I'm going in the other direction like this, if I'm trying to produce integrals, well there are several problems you see here. First of all, if I try to integrate an expression like asum, more than one rule matches. Here's one that matches. Here's one that matches. I don't know which one to take. And they may be different. I may get to explore different things. Also, the expressions become larger in that direction. And when the expressions become larger, then there's no guarantee that any particular path I choose will terminate, because we will only terminate by accidental cancellation. So that's why integrals are complicated searches and hard to do. Right now I don't want to do anything as hard as that. Let's work on derivatives for a while. Well, these roles are ones you know for the most part hopefully. So let's see if we can write a program which is these rules. And that should be very easy. Just write the program. See, because while I showed you is that it's a reduction rule, it's something appropriate for a recursion. And, of course, what we have for each of these rules is we have a case in some case analysis. So I'm just going to write this program down. Now, of course, I'm going to be saying something you have to believe. Right? What you have to believe is I can represent these algebraic expressions, that I can grab their parts, that I can put them together. We've invented list structures so that you can do that. But you don't want to worry about that now. Right now I'm going to write the program that encapsulates these rules independent of the representation of the algebraic expressions. You have a derivative of an expression with respect to a variable. This is a different thing than the derivative of the function. That's what we saw last time, that numerical approximation. It's something you can't open up a function. It's just the answers. The derivative of an expression is the way it's written. And therefore it's a syntactic phenomenon. And so a lot of what we're going to be doing today is worrying about syntax, syntax of expressions and things like that. Well, there's a case analysis. Anytime we do anything complicated thereby a recursion, we presumably need a case analysis. It's the essential way to begin. And that's usually a conditional of some large kind. Well, what are their possibilities? the first rule that you saw is this something a constant? And what I'm asking is, is the expression a constant with respect to the variable given? If so, the result is 0, because the derivative represents the rate of change of something. If, however, the expression that I'm taking the derivative of is the variable I'm varying, then this is the same variable, the expression var, then the rate of change of the expression with respect to the variable is 1. It's the same 1. Well now there are a couple of other possibilities. It could, for example, be a sum. Well, I don't know how I'm going to express sums yet. Actually I do. But I haven't told you yet. But is it a sum? I'm imagining that there's some way of telling. I'm doing a dispatch on the type of the expression here, absolutely essential in building languages. Languages are made out of different expressions. And soon we're going to see that in our more powerful methods of building languages on languages. Is an expression a sum? If it's a sum, well, we know the rule for derivative of the sum is the sum of the derivatives of the parts. One of them is calledthe addend and the other is the augend. But I don't have enough space on the blackboard to such long names. So I'll call them A1 and A2. I want to make a sum. Do you remember which is the sum for end or the menu end? Or was it the dividend and the divisor or something like that? Make sum of the derivative of the A1, I'll call it. It's the addend of the expression with respect to the variable, and the derivative of the A2 of the expression, because the two arguments, the addition with respect to the variable. And another rule that we know is product rule, which is, if the expression is a product. By the way, it's a good idea when you're defining things, when you're defining predicates, to give them a name that ends in a question mark. This question mark doesn't mean anything. It's for us as an agreement. It's a conventional interface between humans so you can read my programs more easily. So I want you to, when you write programs, if you define a predicate procedure, that's something that rings true of false, it should have a name which ends in question mark. The list doesn't care. I care. I want to make a sum. Because the derivative of a product is the sum of the first times the derivative of the second plus the second times the derivative of the first.Make a sum of two things, a product of, well, I'm going to say the M1 of the expression, and the derivative of the M2 of the expression with respect to the variable, and the product of the derivative of M1, the multiplier of the expression, with respect to the variable. It's the product of that and the multiplicand, M2, of the expression. Make that product. Make the sum. Close that case. And, of course, I could add as many cases as I like here for a complete set of rules you might find in a calculus book. So this is what it takes to encapsulate those rules. And you see, you have to realize there's a lot of wishful thinking here. I haven't told you anything about how I'm going to make these representations. Now, once I've decided that this is my set of rules, I think it's time to play with the representation. Let's attack that/ Well, first of all, I'm going to play a pun. It's an important pun. It's a key to a sort of powerful idea. If I want to represent sums, and products, and differences, and quotients, and things like that, why not use the same language as I'm writing my program in? I write my program in algebraic expressions that look like the sum of the product on a and the product of x and x, and things like that. And the product of b and x and c, whatever, make that a sum of the product. Right now I don't want to have procedures with unknown numbers of arguments, a product of b and x and c. This is list structure. And the reason why this is nice, is because any one of these objects has a property. I know where the car is. The car is the operator. And the operands are the successive cdrs the successive cars of the cdrs of the list that this is. It makes it very convenient. I have to parse it. It's been done for me. I'm using the embedding and Lisp to advantage. So, for example, let's start using list structure to write down the representation that I'm implicitly assuming here. Well I have to define various things that are implied in this representation. Like I have to find out how to do a constant, how you do same variable. Let's do those first. That's pretty easy enough. Now I'm going to be introducing lots of primitives here, because these are the primitives that come with list structure. OK, you define a constant. And what I mean by a constant, an expression that's constant with respect to a veritable, is that the expression is something simple. I can't take it into pieces, and yet it isn't that variable. I can't break it up, and yet it isn't that variable. That does not mean that there may be other expressions that are more complicated that are constants. It's just that I'm going to look at the primitive constants in this way. So what this is, is it says that's it's the and. I can combine predicate expressions which return true or false with and. Something atomic, The expression is atomic, meaning it cannot be broken into parts. It doesn't have a car and a cdr. It's not a list. It adds a special test built into the system. And it's not identically equal to that variable. I'm representing my variable by things that are symbols which cannot be broken into pieces, things like x, and y, things like this. Whereas, of course, something like this can be broken up into pieces. And the same variable of an expression with respect to a variable is, in fact, an atomic expression. I want to have an atomic expression, which is identical. I don't want to look inside this stuff anymore. These are primitive maybe. But it doesn't matter. I'm using things that are given to me with a language. I'm not terribly interest in them Now how do we deal with sums? Ah, something very interesting will happen. A sum is something which is not atomic and begins with the plus symbol. That's what it means. So here, I will define. An question is a sum if and it's not atomic and it's head, it's beginning, its car of the expression is the symbol plus. Now you're about to see something you haven't seen before, this quotation. Why do I have that quotation there? Say your name, AUDIENCE: Susanna. PROFESSOR: Louder. AUDIENCE: Susanna PROFESSOR: Say your name. AUDIENCE: Your name. PROFESSOR: Louder. AUDIENCE: Your name. PROFESSOR: OK. What I'm showing you here is that the words of English are ambiguous. I was saying, say your name. I was also possibly saying say, your name. But that cannot be distinguished in speech. However, we do have a notation in writing, which is quotation for distinguishing these two possible meanings. In particular, over here, in Lisp we have a notation for distinguish ing these meetings. If I were to just write a plus here, a plus symbol, I would be asking, is the first element of the expression, is the operator position of the expression, the addition operator? I don't know. I would have to have written the addition operator there, which I can't write. However, this way I'm asking, is this the symbolic object plus, which normally stands for the addition operator? That's what I want. That's the question I want to ask. Now before I go any further, I want to point out the quotation is a very complex concept, and adding it to a language causes a great deal of troubles. Consider the next slide. Here's a deduction which we should all agree with. We have, Alyssa is smart and Alyssa is George's mother. This is an equality, is. From those two, we can deduce that George's mother is smart. Because we can always substitute equals for equals in expressions. Or can we? Here's a case where we have "Chicago" has seven letters. The quotation means that I'm discussing the word Chicago, not what the word represents. Here I have that Chicago is the biggest city in Illinois. As a consequence of this, I would like to deduce that the biggest city in Illinois has seven letters. But that's manifestly false. Wow, it works. OK, so once we have things like that, our language gets much more complicated. Because it's no longer true that things we tend to like to do with languages, like substituting equals for equals and getting right answers, are going to work without being very careful. We c an't substitute into what's called referentially opaque contexts, of which a quotation is the prototypical type of referentially opaque context. If you know what that means, you can consult a philosopher. Presumably there is one in the room. In any case, let's continue now, now that we at least have an operational understanding of a 2000-year-old issue that has to do with name, and mention, and all sorts of things like that. I have to define what I mean, how to make a sum of two things, an a1 and a2. And I'm going to do this very simply. It's a list of the symbol plus, and a1, and a2. And I can determine the first element. Define a1 to be cadr. I've just introduced another primitive. This is the car of the cdr of something. You might want to know why car and cdr are names of these primitives, and why they've survived, even though they're much better ideas like left and right. We could have called them things like that. Well, first of all, the names come from the fact that in the great past, when Lisp was invented, I suppose in '58 or something, it was on a 704 or something like that, which had a machine. It was a machine that had an address register and a decrement register. And these were the contents of the address register and the decrement register. So it's an historical accident. Now why have these names survived? It's because Lisp programmers like to talk to each other over the phone. And if you want to have a long sequence of cars and cdrs you might say, cdaddedr, which can be understood. But left of right or right of left is not so clear if you get good at it. So that's why we have these words. All of them up to four deep are defined typically in a Lisp system. A2 to be-- and, of course, you can see that if I looked at one of these expressions like the sum of 3 and 5, what that is is a list containing the symbol plus, and a number 3, and a number 5. Then the car is the symbol plus. The car of the cdr. Well I take the cdr and then I take the car. And that's how I get to the 3. That's the first argument. And the car of the cdr of the cdr gets me to this one, the 5. And similarly, of course, I can define what's going on with products. Let's do that very quickly. Is the expression a product? Yes if and if it's true, that's it's not atomic and it's EQ quote, the asterisk symbol, which is the operator for multiplication. Make product of an M1 and an M2 to be list, quote, the asterisk operation and M1 and M2. and I define M1 to be cadr and M2 to be caddr. You get to be a good Lisp programmer because you start talking that way. I cdr down lists and console them up and so on. Now, now that we have essentially a complete program for finding derivatives, you can add more rules if you like. What kind of behavior do we get out of it? I'll have to clear that x. Well, supposing I define foo here to be the sum of the product of ax square and bx plus c. That's the same thing we see here as the algebraic expression written in the more conventional notation over there. Well, the derivative of foo with respect to x, which we can see over here, is this horrible, horrendous mess. I would like it to be 2ax plus b. But it's not. It's equivalent to it. What is it? I have here, what do I have? I have the derivative of the product of x and x. Over here is, of course, the sum of x times 1 and 1 times x. Now, well, it's the first times the derivative of the second plus the second times the derivative of the first. It's right. That's 2x of course. a times 2x is 2ax plus 0X square doesn't count plus B over here plus a bunch of 0's. Well the answer is right. But I give people take off points on an exam for that, sadly enough. Let's worry about that in the next segment. Are there any questions? Yes? AUDIENCE: If you had left the quote when you put the plus, then would that be referring to the procedure plus and could you do a comparison between that procedure and some other procedure if you wanted to? PROFESSOR: Yes. Good question. If I had left this quotation off at this point, if I had left that quotation off at that point, then I would be referring here to the procedure which is the thing that plus is defined to be. And indeed, I could compare some procedures with each other for identity. Now what that means is not clear right now. I don't like to think about it. Because I don't know exactly what it would need to compare procedures. There are reasons why that may make no sense at all. However, the symbols, we understand. And so that's why I put that quote in. I want to talk about the symbol that's apparent on the page. Any other questions? OK. Thank you. Let's take a break. [MUSIC PLAYING] PROFESSOR: Well, let's see. We've just developed a fairly plausible program for computing the derivatives of algebraic expressions. It's an incomplete program, if you would like to add more rules. And perhaps you might extend it to deal with uses of addition with any number of arguments and multiplication with any of the number of arguments. And that's all rather easy. However, there was a little fly in that ointment. We go back to this slide. We see that the expressions that we get are rather bad. This is a rather bad expression. How do we get such an expression? Why do we have that expression? Let's look at this expression in some detail. Let's find out where all the pieces come from. As we see here, we have a sum-- just what I showed you at the end of the last time-- of X times 1 plus 1 time X. That is a derivative of this product. The produce of a times that, where a does not depend up on x, and therefore is constant with respect to x, is this sum, which goes from here all the way through here and through here. Because it is the first thing times the derivative of the second plus the derivative of the first times the second as the program we wrote on the blackboard indicated we should do. And, of course, the product of bx over here manifests itself as B times 1 plus 0 times X because we see that B does not depend upon X. And so the derivative of B is this 0, and the derivative of X with respect itself is the 1. And, of course, the derivative of the sums over here turn into these two sums of the derivatives of the parts. So what we're seeing here is exactly the thing I was trying to tell you about with Fibonacci numbers a while ago, that the form of the process is expanded from the local rules that you see in the procedure, that the procedure represents a set of local rules for the expansion of this process. And here, the process left behind some stuff, which is the answer. And it was constructed by the walk it takes of the tree structure, which is the expression. So every part in the answer we see here derives from some part of the problem. Now, we can look at, for example, the derivative of foo, which is ax square plus bx plus c, with respect to other things, like here, for example, we can see that the derivative of foo with respect to a. And it's very similar. It's, in fact, the identical algebraic expression, except for the fact that theses 0's and 1's are in different places. Because the only degree of freedom we have in this tree walk is what's constant with respect to the variable we're taking the derivative with respect to and was the same variable. In other words, if we go back to this blackboard and we look, we have no choice what to do when we take the derivative of the sum or a product. The only interesting place here is, is the expression the variable, or is the expression a constant with respect to that variable for very, very small expressions? In which case we get various1's and 0's, which if we go back to this slide, we can see that the 0's that appear here, for example, this 1 over here in derivative of foo with respect to A, which gets us an X square, because that 1 gets the multiply of X and X into the answer, that 1 is 0. Over here, we're not taking the derivative of foo with respect to c. But the shapes of these expressions are the same. See all those shapes. They're the same. Well is there anything wrong with our rules? No. They're the right rules. We've been through this one before. One of the things you're going to begin to discover is that there aren't too many good ideas. When we were looking at rational numbers yesterday, the problem was that we got 6/8 rather then 3/4. The answer was unsimplified. The problem, of course, is very similar. There are things I'd like to be identical by simplification that don't become identical. And yet the rules for doing addition a multiplication of rational numbers were correct. So the way we might solve this problem is do the thing we did last time, which always works. If something worked last time it ought to work again. It's changed representation. Perhaps in the representation we could put in a simplification step that produces a simplified representation. This may not always work, of course. I'm not trying to say that it always works. But it's one of the pieces of artillery we have in our war against complexity. You see, because we solved our problem very carefully. What we've done, is we've divided the world in several parts. There are derivatives rules and general rules for algebra of some sort at this level of detail. and i have an abstraction barrier. And i have the representation of the algebraic expressions, list structure. And in this barrier, I have the interface procedures. I have constant, and things like same - var. I have things like sum, make-sum. I have A1, A2. I have products and things like that, all the other things I might need for various kinds of algebraic expressions. Making this barrier allows me to arbitrarily change the representation without changing the rules that are written in terms of that representation. So if I can make the problem go away by changing representation, the composition of the problem into these two parts has helped me a great deal. So let's take a very simple case of this. What was one of the problems? Let's go back to this transparency again. And we see here, oh yes, there's horrible things like here is the sum of an expression and 0. Well that's no reason to think of it as anything other than the expression itself. Why should the summation operation have made up this edition? It can be smarter than that. Or here, for example, is a multiplication of something by 1. It's another thing like that. Or here is a product of something with 0, which is certainly 0. So we won't have to make this construction. So why don't we just do that? We need to change the way the representation works, almost here. Make-sum to be. Well, now it's not something so simple. I'm not going to make a li st containing the symbol plus and things unless I need to. Well, what are the possibilities? I have some sort of cases here. If I have numbers, if anyone is a number-- and here's another primitive I've just introduced, it's possible to tell whether something's number-- and if number A2, meaning they're not symbolic expressions, then why not do the addition now? The result is just a plus of A1 and A2. I'm not asking if these represent numbers. Of course all of these symbols represent numbers. I'm talking about whether the one I've got is the number 3 right now. An d, for example, supposing A1 is a number, and it's equal to 0, well then the answer is just A2. There is no reason to make anything up. And if A2 is a number, and equal A20, then the result is A1. And only if I can't figure out something better to do with this situation, well, I can start a list. Otherwise I want the representation to be the list containing the quoted symbol plus, and A1, and A2. And, of course, a very similar thing can be done for products. And I think I'll avoid boring you with them. I was going to write it on the blackboard. I don't think it's necessary. You know what to do. It's very simple. But now, let's just see the kind of results we get out of changing our program in this way. Well, here's the derivatives after having just changed the constructors for expressions. The same foo, aX square plus bX plus c, and what I get is nothing more than the derivative of that is 2aX plus B. Well, it's not completely simplified. I would like to collect common terms and sums. Well, that's more work. And, of course, programs to do this sort of thing are huge and complicated. Algebraic simplification, it's a very complicated mess. There's a very famous program you may have heard of called Maxima developed at MIT in the past, which is 5,000 pages of Lisp code, mostly the algebraic simplification operations. There we see the derivative of foo. In fact, X is at something I wouldn't take off more than 1 point for on an elementary calculus class. And the derivative of foo with respect to a, well it's gone down to X times X, which isn't so bad. And the derivative of foo with respect to b is just X itself. And the derivative of foo with respect to c comes out 1. So I'm pretty pleased with this. What you've seen is, of course, a little bit contrived, carefully organized example to show you how we can manipulate algebraic expressions, how we do that abstractly in terms of abstract syntax rather than concrete syntax and how we can use the abstraction to control what goes on in building these expressions. But the real story isn't just such a simple thing as that. The real story is, in fact, that I'm manipulating these expressions. And the expressions are the same expressions-- going back to the slide-- as the ones that are Lisp expressions. There's a pun here. I've chosen my representation to be the same as the representation in my language of similar things. By doing so, I've invoked a necessity. I created the necessity to have things like quotation because of the fact that my language is capable of writing expressions that talk about expressions of the language. I need to have something that says, this is an expression I'm talking about rather than this expression is talking about something, and I want to talk about that. So quotation stops and says, I'm talking about this expression itself. Now, given that power, if I can manipulate expressions of the language, I can begin to build even much more powerful layers upon layers of languages. Because I can write languages that not only are embedded in Lisp or whatever language you start with, but languages that are completely different, that are just, if we say, interpreted in Lisp or something like that. We'll get to understand those words more in the future. But right now I just want to leave you with the fact that we've hit a line which gives us tremendous power. And this point we've bought a sledgehammer. We have to be careful to what flies when we apply it. Thank you. [MUSIC PLAYING] MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed thismaterial in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec4a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 4A: Pattern Matching and Rule-based Substitution PROFESSOR: Well, yesterday we learned a bit about symbolic manipulation, and we wrote a rather stylized program to implement a pile of calculus rule from the calculus book. Here on the transparencies, we see a bunch of calculus rules from such a book. And, of course, what we did is sort of translate these rules into the language of the computer. But, of course, that's a sort of funny strategy. Why should we have to translate these rules into the language of the computer? And what do I really mean by that? These are--the program we wrote yesterday was very stylized. It was a conditional, a dispatch on the type of the expression as observed by the rules. What we see here are rules that say if the object being the derivative is being taken of, if that expres sion is a constant, then do one thing. If it's a variable, do another thing. If it's a product of a constant times a variable, do something and so on. There's sort of a dispatch there on a type. Well, since it has such a stylized behavior and structure, is there some other way of writing this program that's more clear? Well, what's a rule, first of all? What are these rules? Let's think about that. Rules have parts. If you look at these rules in detail, what you see, for example, is the rule has a left-hand side and a right-hand side. Each of these rules has a left-hand side and the right-hand side. The left-hand side is somehow compared with the expression you're trying to take the derivative of. The right-hand side is the replacement for that expression. So all rules on this page are something like this. I have patterns, and somehow, I have to produce, given a pattern, a skeleton. This is a rule. A pattern is something that matches, and a skeleton is something you substitute into in order to get a new expression. So what that means is that the pattern is matched against the expression, which is the source expression. And the result of the application of the rule is to produce a new expression, which I'll call a target, by instantiation of a skeleton. T hat's called instantiation. So that is the process by which these rules are described. What I'd like to do today is build a language and a means of interpreting that language, a means of executing that language, where that language allows us to directly express these rules. And what we're going to do is instead of bringing the rules to the level of the computer by writing a program that is those rules in the computer's language -- at the moment, in a Lisp-- we're going to bring the computer to the level of us by writing a way by which the computer can understand rules of this sort. This is slightly emphasizing the idea that we had last time that we're trying to make a solution to a class of problems rather than a particular one. The problem is if I want to write rules for a different piece of mathematics, say, to simple algebraic simplification or something like that, or manipulation of trigonometric functions, I would have to write a different program in using yesterday's method. Whereas I would like to encapsulate all of the things that are common to both of those programs, meaning the idea of matching, instantiation, the control structure, which turns out to be very complicated for such a thing, I'd like to encapsulate that separately from the rules themselves. So let's look at, first of all, a representation. I'd like to use the overhead here. I'd lik-- there it is. I'd like to look at a representation of the rules of calculus for derivatives in a sort of simple language that I'm writing right here. Now, I'm going to avoid--I'm going to avoid worrying about syntax. We can easily pretty this, and I'm not interested in making -- this is indeed ugly. This doesn't look like the beautiful text set dx by dt or something that I'd like to write, but that's not essential. That's sort of an accidental phenomenon. Here, we're just worrying about the fact that the structure of the rules is that there is a left- hand side here, represents the thing I want to match against the derivative expression. This is the representation I'm going to say for the derivative of a constant, which we will call c with respect to the variable we will call v. And what we will get on the right- hand side is 0. So this represents a rule. The next rule will be the derivative of a variable, which we will call v with respect to the same variable v, and we get a 1. However, if we have the derivative of a variable called u with respect to a different variables v, we will get 0. I just want you look at these rules a little bit and see how they fit together. For example, over here, we're going to have the derivative of the sum of an expression called x1 and an expression called x2. These things that begin with question marks are called pattern variables in the language that we're inventing, and you see we're just making it up, so pattern variables for matching. And so in this-- here we have the derivative of the sum of the expression which we will call x1. And the expression we will call x2 with respect to the variable we call v will be-- here is the right-hand side: the sum of the derivative of that expression x1 with respect to v -- the right-hand side is the skeleton-- and the derivative of x2 with respect to v. Colons here will stand for substitution objects. They're--we'll call them skeleton evaluations. So let me put up here on the blackboard for a second some syntax so we'll know what's going on for this rule language. First of all, we're going to have to worry about the pattern matching. We're going to have things like a symbol like foo matches exactly itself. The expression f of a and b will be used to match any list whose first element is f, whose second element is a, and whose third element is b. Also, another thing we might have in a pattern is that-- a question mark with some variable like x. And what that means, it says matches anything, which we will call x. Question mark c x will match only constants. So this is something which matches a constant colon x. And question mark v x will match a variable, which we call x. This is sort of the language we're making up now. If I match two things against each other, then they are compared element by element. But elements in the pattern may contain these syntactic variables, pattern variables, which will be used to match arbitrary objects. And we'll get that object as the value in the name x here, for example. Now, when we make skeletons for instantiation. Well, then we have things like this. foo, a symbol, instantiates to itself. Something which is a list like f of a and b, instantiates to -- well, f instantiates to a 3-list, a list of three elements, okay, which are the results of instantiating each of f, a, and b. And x well--we instantiate to the value of x as in the matched pattern. So going back to the overhead here, we see--we see that all of those kinds of objects, we see here a pattern variable which matches a constant, a pattern variable which matches a variable, a pattern variable which will match anything. And if we have two instances of the same name, like this is the derivative of the expression which is a variable only whose name will be v with respect to some arbitrary expression which we will call v, since this v appears twice, we're going to want that to mean they have to be the same. The only consistent match is that those are the same. So here, we're making up a language. And in fact, that's a very nice thing to be doing. It's so much fun to make up a language. And you do this all the time. And the really most powerful design things you ever do are sort of making up a language to solve problems like this. Now, here we go back here and look at some of these rules. Well, there's a whole set of them. I mean, there's one for addition and one for multiplication, just like we had before. The derivative of the product of x1 and x2 with respect to v is the sum of the product of x1 and the derivative x2 with respect to v and the product of the derivative of x1 and x2. And here we have exponentiation. And, of course, we run off the end down here. We get as many as we like. But the whole thing over here, I'm giving this --this list of rules the name "derivative rules." What would we do with such a thing once we have it? Well, one of the nicest ideas, first of all, is I'm going to write for you, and we're going to play with it all day. What I'm going to write for you is a program called simplifier, the general-purpose simplifier. And we're going to say something like define dsimp to be a simplifier of the derivative rules. And what simplifier is going to do is, given a set of rules, it will producfor me a procedure which will simplify expressions containing the things that are referred to by these rules. So here will be a procedure constructed for your purposes to simplify things with derivatives in them such that, after that, if we're typing at some list system, and we get a prompt, and we say dsimp, for example, of the derivative of the sum of x and y with respect to x -- note the quote here because I'm talking about the expression which is the derivative -- then I will get back as a result plus 1 0. Because the derivative of x plus y is the derivative of x plus derivative y. The derivative of x with respect to x is 1. The derivative of y with respect to x is 0. It's not what we're going to get. I haven't put any simplification at that level -- algebraic simplification -- yet. Of course, once we have such a thing, then we can--then we can look at other rules. So, for example, we can, if we go to the slide, OK? Here, for example, are other rules that we might have, algebraic manipulation rules, one s that would be used for simplifying algebraic expressions. For example, just looking at some of these, the left-hand side says any operator applied to a constant e1 and a constant e2 is the result of evaluating that operator on the constants e1 and e2. Or an operator, applied to e1, any expression e1 and a constant e2, is going to move the constant forward. So that'll turn into the operator with e2 followed by e1. Why I did that, I don't know. It wouldn't work if I had division, for example. So there's a bug in the rules, if you like. So the sum of 0 and e is e. The product of 1 and any expression e is e. The product of 0 and any expression e is 0. Just looking at some more of these rules, we could have arbitrarily complicated ones. We could have things like the product of the constant e1 and any constant e2 with e3 is the result of multiplying the result of--multiplying now the constants e1 and e2 together and putting e3 there. So it says combine the constants that I had, which was if I had a product of e1 and e2 and e3 just multiply--I mean and e1 and e2 are both constants, multiply them. And you can make up the rules as you like. There are lots of them here. There are things as complicated, for example, as-- oh, I suppose down here some distributive law, you see. The product of any object c and the sum of d and e gives the result as the same as the sum of the product of c and d and the product of c and e. Now, what exactly these rules are doesn't very much interest me. We're going to be writing the language that will allow us to interpret these rules so that we can, in fact, make up whatever rules we like, another whole language of programming. Well, let's see. I haven't told you how we're going to do this. And, of course, for a while, we're going to work on that. But there's a real question of what is--what am I going to do at all at a large scale? How do these rules work? How is the simplifier program going to manipulate these rules with your expression to produce a reasonable answer? Well, first, I'd like to think about these rules as being some sort of deck of them. So here I have a whole bunch of rules, right? Each rule-- here's a rule-- has a pattern and a skeleton. I'm trying to make up a control structure for this. Now, what I have is a matcher, and I have something which is an instantiater. And I'm going to pass from the matcher to the instantiater some set of meaning for the pattern variables, a dictionary, I'll call it. A dictionary, which will say x was matched a gainst the following subexpression and y was matched against another following subexpression. And from the instantiater, I will be making expressions, and they will go into the matcher. They will be expressions. And the patterns of the rules will be fed into the matcher, and the skeletons from the same rule will be fed into the instantiater. Now, this is a little complicated because when you have something like an algebraic expression, where someth--the rules are intended to be able to allow you to substitute equal for equal. These are equal transformation rules. So all subexpressions of the expression should be looked at. You give it an expression, this thing, and the rules should be cycled around. First of all, for every subexpression of the expressionyou feed in, all of the rules must be tried and looked at. And if any rule matches, then this process occurs. The dictionary--the dictionary is to have some values in it. The instantiater makes a new expression, which is basically replaces that part of the expression that was matched in your original expression. And then, then, of course, we're going to recheck that, going to go around these rules again, seeing if that could be simplified further. And then, then we're going to do that for every subexpression until the thing no longer changes. You can think of this as sort of an organic process. You've got some sort of stew, right? You've got bacteria or something, or enzymes in some, in some gooey mess. And there's these--and these enzymes change things. They attach to your expression, change it, and then they go away. And they have to match. The key-in-lock phenomenon. They match, they change it, they go away. You can imagine it as a parallel process of some sort. So you stick an expression into this mess, and after a while, you take it out, and it's been simplified. And it just keeps changing until it no longer can be changed. But these enzymes can attach to any part of the, of the expression. OK, at this point, I'd like to stop and ask for questions. Yes. AUDIENCE: This implies that the matching program and the instantiation program are separate programs; is that right? Or is that-- they are. PROFESSOR: They're separate little pieces. They fit together in a larger structure. AUDIENCE: So I'm going through and matching and passing the information about what I matched to an instantiater, which makes the changes. And then I pass that back to the matcher? PROFESSOR: It won't make a change. It will make a new expression, which has, which has substituted the values of the pattern variable that were matched on the left-hand side for the variables that are mentioned, the skeleton variables or evaluation variables or whatever I called them, on the right-hand side. AUDIENCE: And then that's passed back into the matcher? PROFESSOR: Then this is going to go around again. This is going to go through this mess until it no longer changes. AUDIENCE: And it seems that there would be a danger of getting into a recursive loop. PROFESSOR: Yes. Yes, if you do not write your rules nicely, you are-- indeed, in any programming language you invent, if it's sufficiently powerful to do anything, you can write programs that will go into infinite loops. And indeed, writing a program for doing algebraic manipulation for long will produce infinite loops. Go ahead. AUDIENCE: Some language designers feel that this feature is so important that it should become part of the basic language, for example, scheme in this case. What are your thoughts on-- PROFESSOR: Which language feature? AUDIENCE: The pairs matching. It's all application of such rules should be-- PROFESSOR: Oh, you mean like Prolog? AUDIENCE: Like Prolog, but it becomes a more general-- PROFESSOR: It's possible. OK, I think my feeling about that is that I would like to teach you how to do it so you don't depend upon some language designer. AUDIENCE: OK. PROFESSOR: You make it yourself. You can roll your own. Thank you. Well, let's see. Now we have to tell you how it works. It conveniently breaks up into various pieces. I'd like to look now at the matcher. The matcher has the following basic structure. It's a box that takes as its input an expression and a pattern, and it turns out a dictionary. A dictionary, remember, is a mapping of pattern variables to the values that were found by matching, and it puts out another dictionary, which is the result of augmenting this dictionary by what was found in matching this expression against this pattern. So that's the matcher. Now, this is a rather complicated program, and we can look at it on the overhead over here and see, ha, ha, it's very complicated. I just want you to look at the shape of it. It's too complicated to look at except in pieces. However, it's a fairly large, complicated program with a lot of sort of indented structure. At the largest scale-- you don't try to read those characters, but at the largest scale, you see that there is a case analysis, which is all these cases lined up. What we're now going to do is look at this in a bit more detail, attempting to understand how it works. Let's go now to the first slide, showing some of the structure of the matcher at a large scale. And we see that the matcher, the matcher takes as its input a pattern, an expression, and a dictionary. And there is a case analysis here, which is made out of several cases, some of which have been left out over here, and the general case, which I'd like you to see. Let's consider this general case. It's a very important pattern. The problem is that we have to examine two trees simultaneously. One of the trees is the tree of the expression, and the other is the tree of the pattern. We have to compare them with each other so that the subexpressions of the expression are matched against subexpressions of the pattern. Looking at that in a bit more detail, suppose I had a pattern, a pattern, which was the sum of the product of a thing which we will call x and a thing which we will call y, and the sum of that, and the same thing we call y. So we're looking for a sum of a product whose second-- whose second argument is the same as the second argument of the sum. That's a thing you might be looking for. Well, that, as a pattern, looks like this. There is a tree, which consists of a sum, and a product with a pattern variable question mark x and question mark y, the other pattern variable, and question mark y, just looking at the same, just writing down the list structure in a different way. Now, suppose we were matching that against an expression which matches it, the sum of, say, the product of 3 and x and, say, x. That's another tree. It's the sum of the product of 3 and x and of x. So what I want to do is traverse these two trees simultaneously. And what I'd like to do is walk them like this. I'm going to say are these the same? This is a complicated object. Let's look at the left branches. Well, that could be the car. How does that look? Oh yes, the plus looks just fine. But the next thing here is a complicated thing. Let's look at that. Oh yes, that's pretty fine, too. They're both asterisks. Now, whoops! My pattern variable, it matches against the 3. Remember, x equals 3 now. That's in my dictionary, and the dictionary's going to follow along with me: x equals three. Ah yes, x equals 3 and y equals x, different x. The pattern x is the expression x, the pattern y. Oh yes, the pattern variable y, I've already got a value for it. It's x. Is this an x? Oh yeah, sure it is. That's fine. Yep, done. I now have a dictionary, which I've accumulated by making this walk. Well, now let's look at this general case here and see how that works. Here we have it. I take in a pattern variable--a pattern, an expression, and a dictionary. And now I'm going to do a complicated thing here, which is the general case. The expression is made out of two parts: a left and a right half, in general. Anything that's complicated is made out of two pieces in a Lisp system. Well, now what do we have here? I'm going to match the car's of the two expressions against each other with respect to the dictionary I already have, producing a dictionary as its value, which I will then use for matching the cdr's against each other. So that's how the dictionary travels, threads the entire structure. And then theresult of that is the dictionary for the match of the car and the cdr, and that's what's going to be returned as a value. Now, at any point, a match might fail. It may be the case, for example, if we go back and look at an expression that doesn't quite match, like supposing this was a 4. Well, now these two don't match any more, because the x that had to be-- sorry, the y that had to be x here and this y has to be 4. But x and 4 were not the same object syntactically. So this wouldn't match, and that would be rejected sometimes, so matches may fail. Now, of course, because this matcher takes the dictionary from the previous match as input, it must be able to propagate the failures. And so that's what the first clause of this conditional does. It's also true that if it turned out that the pattern was not atomic-- see, if the pattern was atomic, I'd go into this stuff, which we haven't looked at yet. But if the pattern is not atomic and the expression is atomic-- it's not made out of pieces-- then that must be a failure, and so we go over here. If the pattern is not atomic and the pattern is not a pattern variable -- I have to remind myself of that-- then we go over here. So that way, failures may occur. OK, so now let's look at the insides of this thing. Well, the first place to look is what happens if I have an atomic pattern? That's very simple. A pattern that's not made out of any pieces: foo. That's a nice atomic pattern. Well, here's what we see. If the pattern is atomic, then if the expression is atomic, then if they are the same thing, then the dictionary I get is the same one as I had before. Nothing's changed. It's just that I matched plus against plus, asterisk against asterisk, x against x. That's all fine. However, if the pattern is not the one which is the expression, if I have two separate atomic objects, then it was matching plus against asterisk, which case I fail. Or if it turns out that the pattern is atomic but the expression is complicated, it's not atomic, then I get a failure. That's very simple. Now, what about the various kinds of pattern variables? We had three kinds. I give them the names. They're arbitrary constants, arbitrary variables, and arbitrary expressions. A question mark x is an arbitrary expression. A question mark cx is an arbitrary constant, and a question mark vx is an arbitrary variable. Well, what do we do here? Looking at this, we see that if I have an arbitrary constant, if the pattern is an arbitrary constant, then it had better be the case that the expressi on had better be a constant. If the expression is not a constant, then that match fails. If it is a constant, however, then I wish to extend the dictionary. I wish to extend the dictionary with that pattern being remembered to be that expression using the old dictionary as a starting point. So really, for arbitrary variables, I have to check first if the expression is a variable by matching against. If so, it's worth extending the dictionary so that the pattern is remembered to be matched against that expression, given the original dictionary, and this makes a new dictionary. Now, it has to check. There's a sorts of failure inside extend dictionary, which is that-- if one of these pattern variables already has a value and I'm trying to match the thing ag ainst something else which is not equivalent to the one that I've already matched it against once, then a failure will come flying out of here, too. And I will see that some time. And finally, an arbitrary expression does not have to check anything synta ctic about the expression that's being matched, so all it does is it's an extension of the dictionary. So you've just seen a complete, very simple matcher. Now, one of the things that's rather remarkable about this is people pay an awful lot of money these days for someone to make a, quote, AI expert system that has nothing more in it than a matcher and maybe an instantiater like this. But it's very easy to do, and now, of course, you can start up a little start-up company and make a couple of megabucks in the next week taking some people for a ride. 20 years ago, this was remarkable, this kind of program. But now, this is sort of easy. You can teach it to freshmen. Well, now there's an instantiater as well. The problem is they're all going off and making more money than I do. But that's always been true of universities. As expression, the purpose of the instantiater is to make expressions given a dictionary and a skeleton. And that's not very hard at all. We'll see that very simply in the next, the next slide here. To instantiate a skeleton, given a particular dictionary-- oh, this is easy. We're going to do a recursive tree walk over the skeleton. And for everything which is a skeleton variable -- I don't know, call it a skeleton evaluation. That's the name and the abstract syntax that I give it in this program: a skeleton evaluation, a thing beginning with a colon in the rules. For anything of that case, I'm going to look up the answer in the dictionary, and we'll worry about that in a second. Let's look at this as a whole. Here, I have-- I'm going to instantiate a skeleton, given a dictionary. Well, I'm going to define some internal loop right there, and it's going to do something very simple. Even if a skeleton--even if a skeleton is simple and atomic, in which case it's nothing more than giving the skeleton back as an answer, or in the general case, it's complicated, in which case I'm going to make up the expression which is the result of instantiating-- calling this loop recursively-- instantiating the car of the skeleton and the cdr. So here is a recursive tree walk. However, if it turns out to be a skeleton evaluation, a colon expression in the skeleton, then what I'm going to do is find the expression that's in the colon-- the CADR in this case. It's a piece of abstract syntax here, so I can change my representation of rules. I'm going to evaluate that relative to this dictionary, whatever evaluation means. We'll find out a lot about that sometime. And the result of that is my answer. so. I start up this loop-- here's my initialization -- by calling it with the whole skeleton, and this will just do a recursive decomposition into pieces. Now, one more little b it of detail is what happens inside evaluate? I can't tell you that in great detail. I'll tell you a little bit of it. Later, we're going to see--look into this in much more detail. To evaluate some form, some expression with respect to a dictionary, if the expression is an atomic object, well, I'm going to go look it up. Nothing very exciting there. Otherwise, I'm going to do something complicated here, which is I'm going to apply a procedure which is the result of looking up the operator part in somethingthat we're going to find out about someday. I want you realize you're seeing magic now. This magic will become clear very soon, but not today. Then I'm looking at--looking up all the pieces, all the arguments to that in the dictionary. So I don't want you to look at this in detail. I want you to say that there's more going on here, and we're going to see more about this. But it's-- the magic is going to stop. This part has to do with Lisp, and it's the end of that. OK, so now we know about matching and instantiation. Are there any questions for this segment? AUDIENCE: I have a question. PROFESSOR: Yes. AUDIENCE: Is it possible to bring up a previous slide? It's about this define match pattern. PROFESSOR: Yes. You'd like to see the overall slide define match pattern. Can somebody put up the-- no, the overhead. That's the biggest scale one. What part would you like to see? AUDIENCE: Well, the top would be fine. Any of the parts where you're passing failed. PROFESSOR: Yes. AUDIENCE: The idea is to pass failed back to the dictionary; is that right? PROFESSOR: The dictionary is the answer to a match, right? And it is either some mapping or there's no match. It doesn't match. AUDIENCE: Right. PROFESSOR: So what you're seeing over here is, in fact, because the fact that a match may have another match pass in the dictionary, as you see in the general case down here. Here's the general case where a match passes another match to the dictionary. When I match the cdr's, I match them in the dictionary that is resulting from matching the car's. OK, that's what I have here. So because of that, if the match of the car's fails, then it may be necessary that the match of the cdr's propagates that failure, and that's what the first line is. AUDIENCE: OK, well, I'm still unclear what matches-- what comes out of one instance of the match? PROFESSOR: One of two possibilities. Either the symbol failed, which means there is no match. AUDIENCE: Right. PROFESSOR: Or some mapping, which is an abstract thing right now, and you should know about the structure of it, which relates the pattern variables to their values as picked up in the match. AUDIENCE: OK, so it is-- PROFESSOR: That's constructed by extend dictionary. AUDIENCE: So the recursive nature brings about the fact that if ever a failed gets passed out of any calling of match, then the first condition will pick it up -- PROFESSOR: And just propagate it along without any further ado, right. AUDIENCE: Oh, right. OK. PROFESSOR: That's just the fastest way to get that failure out of there. Yes. AUDIENCE: If I don't fail, that means that I've matched a pattern, and I run the procedure extend dict and then pass in the pattern in the expression. But the substitution will not be made at that point; is that right? I'm just-- PROFESSOR: No, no. There's no substitution being there because there's no skeleton to be substituted in. AUDIENCE: Right. So what-- PROFESSOR: All you've got there is we're making up the dictionary for later substitution. AUDIENCE: And what would the dictionary look like? Is it ordered pairs? PROFESSOR: That's--that's not told to you. We're being abstract. AUDIENCE: OK. PROFESSOR: Why do you want to know? What it is, it's a function. It's a function. AUDIENCE: Well, the reason I want to know is-- PROFESSOR: A function abstractly is a set of ordered pairs. It could be implemented as a set of list pairs. It could be implemented as some fancy table mechanism. It could be implemented as a function. And somehow, I'm building up a function. But I'm not telling you. That's up to George, who's going to build that later. I know you really badly want to write concrete things. I'm not going to let you do that. AUDIENCE: Well, let me at least ask, what is the important information there that's being passed to extend dict? I want to pass the pattern I found-- PROFESSOR: Yes. The pattern that's matched against the expression. You want to have the pattern, which happens to be in those cases pattern variables, right? All of those three cases for extend dict are pattern variables. AUDIENCE: Right. PROFESSOR: So you have a pattern variable that is to be given a value in a dictionary. AUDIENCE: Mm-hmm. PROFESSOR: The value is the expression that it matched against. The dictionary is the set of things I've already figured out that I have memorized or learned. And I am going to make a new dictionary, which is extended from the originalone by having that pattern variable have a value with the new dictionary. AUDIENCE: I guess what I don't understand is why can't the substitution be made right as soon as you find-- PROFESSOR: How do I know what I'm going to substitute? I don't know anything about this skeleton. This pattern, this matcher is an independent unit. AUDIENCE: Oh, I see. OK. PROFESSOR: Right? AUDIENCE: Yeah. PROFESSOR: I take the matcher. I apply the matcher. If it matches, then it was worth doing instantiation. AUDIENCE: OK, good. Yeah. PROFESSOR: OK? AUDIENCE: Can you just do that answer again using that example on the board? You know, what you just passed back to the matcher. PROFESSOR: Oh yes. OK, yes. You're looking at this example. At this point when I' m traversing this structure, I get to here: x. I have some dictionary, presumably an empty dictionary at this point if this is the whole expression. So I have an empty dictionary, and I've matched x against 3. So now, after this point, the dictionary contains x is 3, OK? Now, I continue walking along here. I see y. Now, this is a particular x, a pattern x. I see y, a pattern y. The dictionary says, oh yes, the pattern y is the symbol x because I've got a match there. So the dictionary now contains at this point two entries. The pattern x is 3, and the pattern y is the expression x. Now, I get that, I can walk along further. I say, oh, pattern y also wants to be 4. But that isn't possible, producing a failure. Thank you. Let's take a break. OK, you're seeing your first very big and hairy program. Now, of course, one of the goals of this subsegment is to get you to be able to read something like this and not be afraid of it. This one's only about four pages of code. By the end of the subject, I hope a 50 -page program will not look particularly frightening. But I don't expect-- and I don't want you to think that I expect you to be getting it as it's coming out. You're supposed to feel the flavor of this, OK? And then you're supposed to think about it because it is a big program. There's a lot of stuff inside this program. Now, I've told you about the language we're implementing, the pattern match substitution language. I showed you some rules. And I've told you about matching and instantiation, which are the two halves of how a rule works. Now we have to understand the cont rol structure by which the rules are applied to the expressions so as to do algebraic simplification. Now, that's also a big complicated mess. The problem is that there is a variety of interlocking, interwoven loops, if you will, involved in this. For on e thing, I have to apply-- I have to examine every subexpression of my expression that I'm trying to simplify. That we know how to do. It's a car cdr recursion of some sort, or something like that, and some sort of tree walk. And that's going to be happening. Now, for every such place, every node that I get to in doing my traversal of the expression I'm trying to simplify, I want to apply all of the rules. Every rule is going to look at every node. I'm going to rotate the rules around. Now, either a rule will or will not match. If the rule does not match, then it's not very interesting. If the rule does match, then I'm going to replace that node in the expression by an alternate expression. I'm actually going to make a new expression, which contains -- everything contains that new value, the result of substituting into the skeleton, instantiating the skeleton for that rule at this level. But no one knows whether that thing that I instantiated there is in simplified form. So we're going to have to simplify that, somehow to call the simplifier on the thing that I just constructed. And then when that's done, then I sort of can build that into the expression I want as my answer. Now, there is a basic idea here, which I will call a garbage - in, garbage-out simplifier. It's a kind of recursive simplifier. And what happens is the way you simplify something is that simple objects like variables are simple. Compound objects, well, I don't know. What I'm going to do is I'm going to build up from simple objects, trying to make simple things by assuming that the pieces they're made out of are simple. That's what's happening here. Well, now, if we look at the first slide -- no, overhead, overhead. If we look at the overhead, we see a very complicated program like we saw before for the matcher, so complicated that you can't read it like that. I just want you to get the feel of the shape of it, and the shape of it is that this program has various subprograms in it. One of them--this part is the part for traversing the expression, and this part is the part for trying rules. Now, of course, we can look at that in some more detail. Let's look at--let's look at the first transparency, right? The simplifier is made out of several parts. Now, remember at the very beginning, the simplifier is the thing which takes a rules--a set of rules and produces a program which will simplify it relative to them. So here we have our simplifier. It takes a rule set. And in the context where that rule set is defined, there are various other definitions that are done here. And then the result of this simplifier procedure is, in fact, one of the procedures that was defined. Simplify x. What I'm returning as the value of calling the simplifier on a set of rules is a procedure, the simplify x procedure, which is defined in that context, which is a simplification procedure appropriate for using those set of rules. That's what I have there. Now, the first two of these procedures, this one and this one, are together going to be the recursive traversal of an expression. This one is the general simplification for any expression, and this is the thing which simplifies a list of parts of an expression. Nothing more. For each of those, we're going to do something complicated, which involves trying the rules. Now, we should look at the various parts. Well let's look first at the recursive traversal of an expression. And this is done in a sort of simple way. This is a little nest of recursive procedures. And what we have here are two procedures-- one for simplifying an expression, and one for simplifying parts of an expression. And the way this works is very simple. If the expression I'm trying to simplify is a compound expression, I'm going to simplify all the parts of it. And that's calling--that procedure, simplify parts, is going to make up a new expression with all the parts simplified, which I'm then going to try the rules on over here. If it turns out that the expression is not compound, if it's simple, like just a symbol or something like pi, then in any case, I'm going to try the rules on it because it might be that I want in my set of rules to expand pi to 3.14159265358979, dot, dot, dot. But I may not. But there is no reason not to do it. Now, if I want to simplify the parts, well, that's easy too. Either the expression is an empty one, there's no more parts, in which case I have the empty expression. Otherwise, I'm going to make a new expression by cons, which is the result of simplifying the first part of the expression, the car, and simplifying the rest of the expression, which is the cdr. Now, the reason why I'm showing you this sort of stuff this way is because I want you get the feeling for the various patterns that are very important when writing programs. And this could be written a different way. There's another way to write simplified expressions so there would be only one of them. There would only be one little procedure here. Let me just write that on the blackboard to give you a feeling for that. This in another idiom, if you will. To simplify an expression called x, what am I going to do? I'm going to try the rules on the following situation. If-- on the following expression-- compound, just like we had before. If the expression is compound, well, what am I going to do? I'm going to simplify all the parts. But I already have a cdr recursion, a common pattern of usage, which has been captured as a high -order procedure. It's called map. So I'll just write that here. Map simplify the expression, all the parts of the expression. This says apply the simplification operation, which is this one, every part of the expression, and then that cuts those up into a list. It's every element of the list which the expression is assumed to be made out of, and otherwise, I have the expression. So I don't need the helper procedure, simplify parts, because that's really this. So sometimes, you just write it this way. It doesn't matter very much. Well, now let's take a look at -- let's just look at how you try rules. If you look at this slide, we see this is a complicated mess also. I'm trying rules on an expression. It turns out the expression I'm trying it on is some subexpression now of the expression I started with. Because the thing I just arranged allowed us to try every subexpression. So now here we're taking in a subexpression of the expression we started with. That's what this is. And what we're going to define here is a procedure called scan, which is going to try every rule. And we're going to start it up on the whole set of rules. This is going to go cdr- ing down the rules, if you will, looking for a rule to apply. And when it finds one, it'll do the job. Well, let's take a look at how try rules works. It's very simple: thescan rules. Scan rules, the way of scanning. Well, is it so simple? It's a big program, of course. We take a bunch of rules, which is a sublist of the list of rules. We've tried some of them already, and they've not been appropriate, so we get to some here. We get to move to the next one. If there are no more rules, well then, there's nothing I can do with this expression, and it's simplified. However, if it turns out that there are still rules to be done, then let's match the pattern of the first rule against the expression using the empty dictionary to start with and use that as the dictionary. If that happens to be a failure, try the rest of the rules. That's all it says here. It says discard that rule. Otherwise, well, I'm going to get the skeleton ofthe first rule, instantiate that relative to the dictionary, and simplify the result, and that's the expression I want. So although that was a complicated program, every complicated program is made out of a lot of simple pieces. Now, the pattern of recursions here is very complicated. And one of the most important things is not to think about that. If you try to think about the actual pattern by which this does something, you're going to get very confused. I would. This is not a matter of you can do this with practice. These patterns are hard. But you don't have to think about it. The key to this-- it's very good programming and very good design-- is to know what not to think about. The fact is, going back to this slide, I don't have to think about it because I have specifications in my mind for what simplify x does. I don't have to know how it does it. And it may, in fact, call scan somehow through try rules, which it does. And somehow, I've got another recursion going on here. But since I know that sim plify x is assumed by wishful thinking to produce the simplified result, then I don't have to think about it anymore. I've used it. I've used it in a reasonable way. I will get a reasonable answer. And you have to learn how to program that way-- with abandon. Well, there's very little left of this thing. All there is left is a few details associated with what a dictionary is. And those of you who've been itching to know what a dictionary is, well, I will flip it up and not tell you anything about it. Dictionaries are easy. It's represented in terms of something else called an A list, which is a particular pattern of usage for making tables in lists. They're easy. They're made out of pairs, as was asked a bit ago. And there are special procedures for dealing with such things called assq, and you can find them in manuals. I'm not terribly excited about it. The only interesting thing here in extend dictionary is I have to extend the dictionary with a pattern, a datum, and a dictionary. This pattern is, in fact, at this point a pattern variable. And what do I want to do? I want to pull out the name of that pattern variable, the pattern variable name, and I'm going to look up in the dictionary and see if it already has a value. If not, I'm going to add a new on e in. If it does have one, if it has a value, then it had better be equal to the one that was already stored away. And if that's the case, the dictionary is what I expected it to be. Otherwise, I fail. So that's easy, too. If you open up any program, you're going to find inside of it lots of little pieces, all of which are easy. So at this point, I suppose, I've just told you some million-dollar valuable information. And I suppose at this point we're pretty much done with this program. I'd like to ask ab out questions. AUDIENCE: Yes, can you give me the words that describe the specification for a simplified expression? PROFESSOR: Sure. A simplified expression takes an expression and produces a simplified expression. That's it, OK? How it does it is very easy. In compound expressions, all the pieces are simplified, and then the rules are tried on the result. And for simple expressions, you just try all the rules. AUDIENCE: So an expression is simplified by virtue of the rules? PROFESSOR: That's, of course, true. AUDIENCE: Right. PROFESSOR: And the way this works is that simplifi expression, as you see here, what it does is it breaks the expression down into the smallest pieces, simplifies building up from the bottom using the rules to be the simplifier, to do the manipulations, an d constructs a new expression as the result. Eventually, one of things you see is that the rules themselves, the try rules, call a simplified expression on the results when it changes something, the results of a match. I'm sorry, the results of instantiation of a skeleton for a rule that has matched. So the spec of a simplified expression is that any expression you put into it comes out simplified according to those rules. Thank you. Let's take a break. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed thismaterial in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec4b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 4B: Generic Operators [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] PROFESSOR: So far in this course we've been talking a lot about data abstraction. And remember the idea is that we build systems that have these horizontal barriers in them, these abstraction barriers that separate use, the way you might use some data object, from the way you might represent it. Or another way to think of that is up here you have the boss who's going to be using some sort of data object. And down here is George who's implemented it. Now this notion of separating use from representation so you can think about these two problems separately is a very, very powerful programming methodology, data abstraction. On the other hand, it's not really sufficient for really complex systems. And the problem with this is George. Or actually, the problem is that there are a lot of Georges. Let's be concrete. Let's suppose there is George, and there's also Martha. OK, now George and Martha are both working on this system, both designing representations, and absolutely are incompatible. They wouldn't cooperate on a representation under any circumstances. And the problem is you would like to have some system where both George and Martha are designing representations, and yet, if you're above this abstraction barrier you don't want to have to worry about that, whether something is done by George or by Martha. And you don't want George and Martha to interfere with each other. Somehow in designing a system, you not only want these horizontal barriers, but you also want some kind of vertical barrier to keep George and Martha separate. Let me be a little bit more concrete. Imagine that you're thinking about personnel records for a large company with a lot of loosely linked divisions that don't cooper ate very well either. And imagine even that this company is formed by merging a whole bunch of companies that already have their personnel record system set up. And imagine that once these divisions are all linked in some kind of very sophisticated satelli te network, and all these databases are put together. And what you'd like to do is, from any place in the company, to be able to say things like, oh, what's the name in a personnel record? Or, what's the job description in a personnel record? And not haveto worry about the fact that each division obviously is going to have completely separate conventions for how you might implement these records. From this point you don't want to know about that. Well how could you possibly do that? One way, of course, is to send down an edict from somewhere that everybody has to change their format to some fixed compatible thing. That's what people often try, and of course it never works. Another thing that you might want to do is somehow arrange it so you can have these vertical barriers. So that when you ask for the name of a personnel record, somehow, whatever format it happens to be, name will figure out how to do the right thing. We want name to be, so-called, a generic operator. Generic operator means what it sort of precisely does depends on the kind of data that it's looking at. More than that, you'd like to design the system so that the next time a new division comes into the company they don't have to make any big changes in what they're already doing to link into this system, and the rest of the company doesn't have to make any big changes to admit their stuff to the system. So that's the problem you should be thinking about. Like it's sort of just your work. You want to be able to include new things by making minimal changes. OK, well that's the problem that we'll be talking about today. And you should have this sort of distributed personnel record system in your mind. But actually the one I'll be talking about is a problem that's a little bit more self-contained than that. that'll bring up the issues, I think, more clearly. That's the problem of doing a system that does arithmetic on complex numbers. So let's take a look here. Just as a little review, there are things called complex numbers. Complex numberyou can think of as a point in the plane, or z. And you can represent a point either by its real-part and its imaginary-part. So if this is z and its real-part is this much, and its imaginary-part is that much, and you write z equals x plus iy. Or another way to represent a complex number is by saying, what's the distance from the origin, and what's the angle? So that represents a complex number as its radius times an angle. This one's called -- the original one's called rectangular form, rectangular representation, real- and imaginary-part, or polar representation. Magnitude and angle-- and if you know the real- and imaginary-part, you can figure out the magnitude and angle. If you know x and y, you can get r by this formula. Square root of sum of the squa res, and you can get the angle as an arctangent. Or conversely, if you knew r and A you could figure out x and y. x is r times the cosine of A, and y is r times the sine of A. All right, so there's these two. They're complex numbers. You can think of them either in polar form or rectangular form. What we would like to do is make a system that does arithmetic on complex numbers. In other words, what we'd like -- just like the rational number example-- is to have some operations plus c, which is going to take two complex numbers and add them, subtract them, and multiply them, and divide them. OK, well there's little bit of mathematics behind it. What are the actual formulas for manipulating such things? And it's sort of not important where they come from, b ut just as an implementer let's see-- if you want to add two complex numbers it's pretty easy to get its real-part and its imaginary-part. The real-part of the sum of two complex numbers, the real-part of the z1 plus z2 is the real-part of z1 plus the real-part of z2. And the imaginary- part of z1 plus z2 is the imaginary part of z1 plus the imaginary part of z2. So it's pretty easy to add complex numbers. You just add the corresponding parts and make a new complex number with those parts. If you want to multiply them, it's kind of nice to do it in polar form. Because if you have two complex numbers, the magnitude of their product is here, the product of the magnitudes. And the angle of the product is the sum of the angles. So that's sort of mathematics that allows you to do arithmetic on complex numbers. Let's actually think about the implementation. Well we do it just like rational numbers. We come down, we assume we have some constructors and selectors. What would we like? Well let's assume that we make a data object cloud, which is a complex number that has some stuff in it, and that we can get out from a complex number the real-part, or the imaginary- part, or the magnitude, or the angle. We want some ways of making complex numbers-- not only selectors, but constructors. So we'll assume we have a thing called make-rectangular. What make-rectangular is going to do is take a real-part and an imaginary-part and construct a complex number with those parts. Similarly, we can have make-polar which will take a magnitude and an angle, and construct a complex number which has that magnitude and angle. So here's a system. We'll have two constructors and four selectors. And now, just like before, in terms of that abstract data we'll go ahead and implement our complex number operations. And here you can see translated into Lisp code just the arithmetic formulas I put down before. If I want to add two complex numbers I will make a complex number out of its real- and imaginary-parts. The real part of the complex number I'm going to make is the sum of the real-parts. The imaginary part of the complex number I'm going to make is the sum of the imaginary-parts. I put those together, make a complex number. That's how I implement complex number addition. Subtraction is essentially the same. All I do is subtract the parts rather than add them. To multiply two complex numbers, I use the other formula. I'll make a complex number out of a magnitude and angle. The magnitude is going to be the product of the magnitudes of the two complex numbers I'm multiplying. And the angle is going to be the sum of the angles of the two complex numbers I'm multiplying. So there's multiplication. And then division, division is almost the same. Here I divide the magnitudes and subtract the angles. Now I've implemented the operations. And what do we do? We call on George. We've done the use, let's worry about the representation. We'll call on George and say to George, go ahead and build us a complex number representation. Well that's fine. George can say, we'll implement a complex number simply as a pair that has the real-part and the imaginary- part. So if I want to make a complex number with a certain real-part and an imaginary-part, I'll just use cons to form a pair, and that will-- that's George's representation of a complex number. So if I want to get out the real-part of something, I just extract the car, the first part. If I want to get the imaginary-part, I extract the cdr. How do I deal with the magnitude and angle? Well if I want to extract the magnitude of one of these things, I get the square root of the sum of the square of the car plus the square of the cdr. If I want to get the angle, I compute the arctangent of the cdr in the car. This is a list procedure for computing arctangent. And if somebody hands me a magnitude and an angle and says, make me a complex number, well I compute the real-part and the imaginary-part, or our cosine of a and our sine of a, and stick them together into a pair. OK so we're done. In fact, what I just did, conceptually, is absolutely no different from the rational number representation that we looked at last time. It's the same sort of idea. You implement the operators, you pick a representation. Nothing different. Now let's worry about Martha. See, Martha has a different idea. She doesn't want to represent a complex number as a pair of a real-part and an imaginary-part. What she would like to do is represent a complex number as a pair of a magnitude and an angle. So if instead of calling up George we ask Martha to design our representation, we get something like this. We get make-polar. Sure, if I give you a magnitude and an angle we're just going to form a pair that has magnitude and angle. If you want to extract the magnitude, that's easy. You just pull out the car or the pair. If you want to extract the angle, sure, that's easy. You just pull out the cdr. If you want to look for real-parts and imaginary-parts, well then you have to do some work. If you want the real-part, you have to get r cosine a. In other words, r, the car of the pair, times the cosine of the cdr of the pair. So this is r times the cosine of a, and that's the real -part. If you want to get the imaginary-part, it's r times the sine of a. And if I hand you a real-part and an imaginary-part and say, make me a complex number with that real-part and imaginary-part, well I figure out what the magnitude and angle should be. The magnitude's the square root of the sum of the squares and the angle's the arctangent. I put those together to make a pair. So there's Martha's idea. Well which is better? Well if you're doing a lot of additions, probably George's is better, because you're doing a lot of real-parts and imaginary-parts. If mostly you're going to be doing multiplications and divisions, then maybe Martha's idea is better. Or maybe, and this is the real point, you can't decide. Or maybe you just have to let them both hang around, for personality reasons. Maybe you just really can't ever decide what you would like. And again, what we would really like is a system that looks like this. That somehow there's George over here, who has built rectangular complex numbers. And Martha, who has polar complex numbers. And somehow we have operations that can add, and subtract, and multiply, and divide, and it shouldn't matter that there are two incompatible representations of complex numbers floating around this system. In other words, not only like an abstraction barrier here that has things in it like a real -part, and an imaginary-part, and magnitude, and angle. So not only is there an abstraction barrier that hides the actual representation from us, but also there's some kind of vertical barrier here that allows both of these representations to exist without interfering with each other. The idea is that the things in here-- real-part, imaginary-part, magnitude, and angle-- will be generic operators. If you ask for the real-part, it will worry about what representation it's looking at. OK, well how can we do that? There's actually a really obvious idea, if you're used to thinking about complex numbers. If you're used to thinking about compound data. See, suppose you could just tell by looking at a complex number whether it was constructed by George or Martha. In other words, so it's not that what's floating around here are ordinary, just complex numbers, right? They're fancy, designer complex numbers. So you look at a complex numbers as it's not just a complex number, it's got a label on it that says, this one is by Martha. Or this is a complex number by George. Right? They're signed. See, and then whenever we looked at a complex number we could just read the label, and then we'd know how you expect to operate on that. In other words, what we want is not just ordinary data objects. We want to introduce the notion of what's called typed data. Typed data means, again, there's some sort of cloud. And what it's got in it i s an ordinary data object like we've been thinking about. Pulled out the contents, sort of the actual data. But also a thing called a type, but it's signed by either George or Martha. So we're going to go from regular data to type data. How do we build that? Well that's easy. We know how to build clouds. We build them out of pairs. So here's a little representation that supports typed data. There's a thing called take a type and attach it to a piece of contents, and we just use cons. And if we have a piec e of typed data, we can look at the type, which is the car. We can look at the contents, which is the cdr. Now along with that, the way we use our type data will test, when we're given a piece of data, what type it is. So we have some type predicates with us. For example, to see whether a complex number is one of George's, whether it's rectangular, we just check to see if the type of that is the symbol rectangular, right? The symbol rectangular. And to check whether a complex number is one of Martha's, wecheck to see whether the type is the symbol polar. So that's a way to test what kind of number we're looking at. Now let's think about how we can use that to build the system. So let's suppose that George and Martha were off working separately, and each of them had designed their complex number representation packages. What do they have to do to become part of the system, to exist compatibly? Well it's really pretty easy. Remember, George had this package. Here's George's original package, or half of it. And underlined in red are the changes he has to make. So before, when George made a complex number out of an x and y, he just put them together to make a pair. And the only difference is that now he signs them. He attaches the type, which is the symbol rectangular to that pair. Everything else George does is the same, except that-- see, George and Martha both have procedures named real-part and imaginary-part. So to allow them both to exist in the same Lisp environment, George had changed the names of hi s procedures. So we'll say, this is George's real-part procedure. It's the real-part rectangular procedure, the imaginary-part rectangular procedure. And then here's the rest of George's package. He'd had magnitude and angle, just renames them magnitude rectangular and angle rectangular. And Martha has to do basically the same thing. Martha previously, when she made a complex number out of a magnitude and angle, she just cons them. Now she attaches the type polar, and she changes the name so her real -part procedure won't conflict in name with George's. It's a real-part-polar, imaginary-part-polar, magnitude polar, and angle polar. Now we have the system. Right there's George and Martha. And now we've got to get some kind of manager to look at these types. How are these things actually going to work now that George and Martha have supplied us with typed data? Well what we have are a bunch of generic selectors. Generic selectors for complex numbers real-part, imaginary-part, magnitude, and angle. Let's look at them more closely. What does a real-part do? If I ask for the real part of a complex number, well I look at it. I look at its type. I say, is it rectangular? If so, I apply George's real part procedure to the contents of that complex number. This is a number that has a type on it. I strip off the type using contents and apply George's procedure. Or is this a polar complex number? If I want the real part, I apply Martha's real part procedure to the contents of that number. So that's how real part works. And then similarly there's imaginary-part, which is almost the same. It looks at the number and if it's rectangular, uses George's imaginary-part procedure. If it's polar, uses Martha's. And then there's a magnitude and an angle. So there's a system. Has three parts. There's sort of George, and Martha, and the manager. And that's how you get generic operators implemented. Let's look at just a simple example, just to pin it down. But exactly how this is going to work, suppose you're going to be looking at the complex number who's real-part is one, and who's imaginary-part is two. So that would be one plus 2i. What would happen is up here, up here above where the operations have to happen, that number would be represented as a pair of 1 and 2 together with typed data. That would be the contents. And the whole data would be that thing with the symbol rectangular added onto that. And that's the way that complex number would exist in the system. When you went to take the real-part, the manager would look at this and say, oh it's one of George's. He'll strip off the type and hand down to George the pair 1, 2. And that's the kind of data that George developed his system to use. So it gets stripped down. Later on, if you ask George to construct a complex number, George would construct some complex number as a pair, and before he passes it back up through the manager would attach the type rectangular. So you see what happens. There's no confusion in this system. It doesn't matter in the least that the pair 1, 2 means something completely different in Martha's world. In Martha's world this pair means the complex number whose magnitude is 1 and whose angl e is 2. And there's no confusion, because by the time any pair like this gets handed back through the manager to the main system it's going to have the type polar attached. Whereas this one would have the type rectangular attached. OK, let's take a break. [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] We just looked at a strategy for implementing generic operators. That strategy has a name: it's called dispatch type. And the idea is that you break your system into a bunch of pieces. There's George and Martha, who are making representations, and then there's the manager. Looks at the types on the data and then dispatches them to the right person. Well what criticisms can we make of that as a system organization? Well first of all the re was this little, annoying problem that George and Martha had to change the names of their procedures. George originally had a real-part procedure, and he had to go name it real-part rectangular so it wouldn't interfere with Martha's real-part procedure, which is now named real-part-polar, so it wouldn't interfere with the manager's real-part procedure, who's now named real-part. That's kind of an annoying problem. But I'm not going to talk about that one now. We'll see later on when we think about the st ructure of Lisp names and environments that there really are ways to package all those so-called name spaces separately so they don't interfere with each other. Not going to think about that problem now. The problem that I actually want to focus on is what happens when you bring somebody new into the system. What has to happen? Well George and Martha don't care. George is sitting there in his rectangular world, has his procedures and his types. Martha sits in her polar world. She doesn't care. But let's look at the manager. What's the manager have to do? The manager comes through and had these operations. There was a test for rectangular and a test for polar. If Harry comes in with some new kind of complex number, and Harry has a new type, Harry type complex number, the manager has to go in and change all those procedures. So the inflexibility in the system, the place where work has to happen to accommodate change, is in the manager. That's pretty annoying. It's even more annoying when you realize the manager's not doing anything. The manager is just being a paper pusher. Let's look again at these programs. What are they doing? What does real-part do? Real-part says, oh, is it the kind of complex number that George can handle? If so, send it off to George. Is it the kind of complex number that Martha can handle? If so, send it off to Martha. So it's really annoying that the bottleneck in this system, the thing that's preventing flexibility and change, is completely in the bureaucracy. It's not in anybody who's doing any of the work. Not an uncommon situation, unfortunately. See, what's really going on -- abstractly in the system, there's a table. So what's really happening is somewhere there's a table. There're types. There's polar and rectangular. And Harry's may be over here. And there are operators. There's an operator like real-part. Or imaginary-part. Or a magnitude and angle. And sitting in this table are the right procedures. So sitting here for the type polar and real-part is Martha's procedure real-part-polar. And over here in the table is George's procedure real-part-rectangular. And over here would be, say, Martha's procedure magnitude-polar, and George's procedure magnitude-rectangular, right, and so on. The rest of this table's filled in. And that's really what's going on. So in some sense, all the manager is doing is acting as this table. Well how do we fix our system? How do you fix bureaucracies a lot of the time? What you do is you get rid of the manager. We just take the manager and replace him by a computer. We're going to automate him out of existence. Namely, instead of having the manager who basically consults this table, we'll have our system use the table directly. What do I mean by that? Let's assume, again using data abstraction, that we have some kind of data structure that's a table. And we have ways of sticking things in and ways of getting things out. And to be explicit, let me assume that there's an operation called "put." And put is going to take, in this case two things I'll call "keys." Key1 and key2. And a value. And that stores the value in the table under key1 and key2. And then we'll assume there's a thing called "get," such that if later on I say, get me what's in the table stored under key1 and key2, it'll retrieve whatever value was stored there. And let's not worry about how tables are implemented. That's yet another data abstraction, George's problem. And maybe we'll see later-- talk about how you might actually build tables in Lisp. Well given this organization, what did George and Martha have to do? Well when they build their system, they each have the responsibility to set up their appropriate column in the table. So what George does, for example, when he defines his procedures, all he has to do is go off and put into the table under the type-rectangular. And the name of the operation is real-part, his procedure real-part-rectangular. So notice what's going into this table. The two keys here are symbols, rectangular and rea- l part. That's the quote. And what's going into the table is the actual procedure that he wrote, real-part rectangular. And then puts an imaginary part into the table, filed under the keys rectangular- and imaginary-part, and magnitude under the keys rectangular magnitude, angle under rectangular-angle. So that's what George has to do to be part of this system. Martha similarly sets up the column and the table under polar. Polar and real-part. Is the procedure real-part-polar? And imaginary-part, and magnitude, and angle. So this is what Martha has to do to be part of the system. Everyone who makes a representation has the responsibility for setting up a column in the table. And what does Harry do when Harry comes in with his brilliant idea for implementing complex numbers? Well he makes whatever procedure he wants and builds a new column in this table. OK, well what happened to the manager? The manager has been automated ou t of existence and is replaced by a procedure called operate. And this is the key procedure in the whole system. Let's say define operate. Operate is going to take an operation that you want to do, the name of an operation, and an object that you would like to apply that operation to. So for example, the real-part of some particular complex number, what does it do? Well the first thing it does, it looks in the table. Goes into the table and tries to find a procedure that's stored in the table. So it gets from the table, using as keys the type of the object and the operator, but looks on the table and sees what's stored under the type of the object and the operator, sees if anything's stored. Let's assume that get is implemented. So if nothing is stored there, it'll return the empty list. So it says, if there's actually something stored there, if the procedure here is not no, then it'll take the procedure that it found in the table and apply it to the contents of the object. And otherwise if there was nothing stored there, it'll-- well we can decide. In this case let's have it put out an error message saying, undefined operator. No operator for this type. Or some appropriate error message. OK? And that replaces the manager. How do we really use it? Well what we say is we'll go off and define our generic selectors using operate. We'll say that the real-part of an object is found by operating on the object with the name of the operation being real -part. And then similarly, imaginary -part is operate using the name imaginary-part and magnitude and angle. That's our implementation. That plus the tape plus the operate procedure. And the table effectively replaces what the manager used to do. Let's just go through that slowly to show you what's going on. Suppose I have one of Martha's complex numbers. It's got magnitude 1 and angle 2. And it's one of Martha's. So it's labeled here, polar. Let's call that z. Suppose that's z. And suppose with this implementation someone comes up and asks for the real-part of z. Well real-part now is defined in terms of operate. So that's equivalent to saying operate with the name of the operator being real-part, the symbol real-part on z. And now operate comes. It's going to look in the table, and it's going to try and find something stored under-- the operation is going to apply by looking in the table under the type of the object. And the type of z is polar. So it's going to look and say, can I get using polar? And the operation name, which was real-part. It's going to look in there and apply that to the contents of z. And that? If everything was set up correctly, this thing is the procedure that Martha put there. This is real-part-polar. And this is z without its type. The thing that Martha originally designed those procedures to work on, which is 1, 2. And so operate sort of does uniformly what the manager used to do sort of all over the system. It finds the right thing, looks in the table, strips off the type, and passes it down into the person who handles it. This is another, and, you can see, more flexible for most purposes, way of implementing generic operators. And it's called data-directed programming. And the idea of that is in some sense the data objects themselves, those little complex numbers that are floating around the system, are carrying with them the information about how you should operate on them. Let's break for questions. Yes. AUDIENCE: What do you have stored in that data object? You have the data itself, you have its type, and you have the operations for that type? Or where are the operations that you found? PROFESSOR: OK, let me-- yeah, that's a good question. Because it raises other possibilities of how you might do it. And of course there are a lot of possibilities. In this particular implementation, w hat's sitting in this data object, for example, is the data itself-- which in this case is a pair of 1 and 2-- and also a symbol. This is the symbol, the word P-O-L-A-R, and that's what's sitting in this data object. Where are the operations themselves? The operations are sitting in the table. So in this table, the rows and columns of the table are labeled by symbols. So when I store something in this table, the key might be the symbol polar and the symbol magnitude. And I think by writing it this way I'v e been very confusing. Because what's really sitting here isn't-- when I wrote magnitude polar, what I mean is the procedure magnitude polar. And probably what I really should have written-- except it's too small for me to write in this little space-- is something like lambda of z, the thing that Martha wrote to implement. And then you can see from that, there's another way that I alluded to of solving this name conflict problem, which is that George and Martha never have to name their procedures at all. They can just stick the anonymous things generated by lambda directly into the table. There's also another thing that your question raises, is the possibility that maybe what I would like somehow is to store in this data object not the symbol P-O-L-A-R but maybe actually all the operations themselves. And that's another way to organize the system, called message passing. So there are a lot of ways you can do it. AUDIENCE: Therefore if Martha and George had used the same procedure names, it would be OK because it wouldn't look [UNINTELLIGIBLE]. PROFESSOR: That's right. That's right. See, they wouldn't even have to name their procedures at all. What George could have written instead of saying put in the table under rectangular- and real-part, the procedure real-part rectangular, George could have written put under rectangular real-part, lambda of z, such and such, and such and such. And the system would work completely the same. AUDIENCE: My question is, Martha could have put key1 key2 real-part, and George could have put key1 key2 real-part, and as long as they defined them differently they wouldn't have had any conflicts, right? PROFESSOR: Yes, that would all be OK except for the fact that if you imagine George and Martha typing at the same console with the same meanings for all their names, and it would get confused by real-part, but there are ways to arrange that, too. And in principle you're absolutely right. If their names didn't conflict-- it's the objects that go in the table, not the names. OK, let's take a break. [MUSIC-- "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] All right, well we just looked at data-directed programming as a way of implementing a system that does arithmetic on complex numbers. So I had these operations in it called plus C and minus C, and multiply, and divide, and maybe some others. And that sat on top of -- and this is the key point-- sat on top of two different representations. A rectangular package here, and a polar package. And maybe some more. And we saw that the whole idea is that maybe some more are now very easy to add. But that doesn't really show the power of this methodology. Shows you what's going on. The power of the methodology only becomes apparent when you start embedding this in some more complex system. What I'm going to do now is embed this in some more complex system. Let's assume that what we really have is a general kind of arithmetic system. So called generic arithmetic system. And at the top level here, somebody can say add two things, or subtract two things, or multiply two things, or divide two things. And underneath that there's an abstraction barrier. And underneath this barrier, is, say, a complex arithmetic package. And you can say, add two complex numbers. Or you might also have-- remember we did a rational number package-- you might have that sitting there. And there might be a rational thing. And the rational number package, well, has the things we implemented. Plus rat, and times rat, and so on. Or you might have ordinary Lisp numbers. You might say add three and four. So we might have ordinary numbers, in which case we have the Lisp supplied plus, and minus, and times, and slash. OK, so we might imagine this complex number system sitting in a more complicated generic operator structure at the next level up. Well how can we make that? We already have the idea, we're just going to do it again. We've implemented a rational number package. Let's look at how it has to be changed. In fact, at this level it doesn't have to be changed at all. This is exactly the code that we wrote last time. To add two rational numbers, remember there was this formula. You make a rational number whose numerator-- the numerator of the first times the denominator of the second, plus the denominator of the first times the numerator of the second. And who's denominator is the product of the denominators. And minus rat, and star rat, and slash rat. And this is exactly the rational number package that we made before. We're ignoring the GCD problem, but let's not worry about that. As implementers of this rational number package, how do we install it in the generic arithmetic system? Well that's easy. There's only one thing we haveto do differently. Whereas previously we said that to make a rational number you built a pair of the numerator and denominator, here we'll not only build the pair, but we'll sign it. We'll attach the type rational. That's the only thing we have to do different, make it a typed data object. And now we'll stick our operations in the table. We'll put under the symbol rational and the operation add our procedure, plus rat. And, again, note this is a symbol. Right? Quote, unquote, but the actual thing we're putting in the table is the procedure. And for how to subtract, well you subtract rationals with minus rat. And multiply, and divide. And that is exactly and precisely what we have to do to fit inside this generic arithmetic system. Well how does the whole thing work? See, what we want to do is have some generic operators. Have add and sub and [UNINTELLIGIBLE] be generic operators. So we're going to define add and say, to add x and y, that will be operate-- we were going to call it operate-2. This is our operator procedure, but set up for two arguments using add on x and y. And so this is the analog to operate. Let's look at the code for second. It's almost like operate. To operate with some operator on an argument 1 and an argument 2, well the first thin g we're going to do is check and see if the two arguments have the same type. So we'll say, is the type of the first argument the same as the type of the second argument? And if they're not, we'll go off and complain, and say, that's an error. We don't know how to do that. If they do have the same type, we'll do exactly what we did before. We'll go look and filed under the type of the argument-- arg 1 and arg 2 have the same type, so it doesn't matter. So we'll look in the table, find the procedure. If there is a procedure there, then we'll apply it to the contents of the argument 1 and the contents of arg 2. And otherwise we'll say, error. Undefined operator. And so there's operate-2. And that's all we have to do. We just built the complex number package before. How do we embed that complex number package in this generic system? Almost the same. We make a procedure called make- complex that takes whatever George and Martha hand to us and add the type-complex. And then we say, to add complex numbers, plus complex, we use our internal procedure, plus c, and attach a type, make that a complex number. So our original package had names plus c and minus c that we're using to communicate with George and Martha. And then to communicate with the outside world, we have a thing called plus-complex and minus-complex. And so on. And the only difference is that these return values that are tight. So they can be looked at up here. And these are internal operations. Let's go look at that slide again. There's one more thing we do. After defining plus-complex, we put under the type complex and the symbol add, that procedure plus complex. And then similarly for subtracting complex numbers, and multiplying them, and dividing them. OK, how do we install ordinary numbers? Exactly the same way. Come off and say, well we'll make a thing called make-number. Make-number takes a number and attaches a type, which is the symbol number. We build a procedure called plus-number, which is simply, add the two things using the ordinary addition, because in this case we're talking about ordinary numbers, and attach a type to it and make that a number. And then we put into the table under the symbol number and the operation add, this procedure plus-number, and then the same thing for subtracting, and multiplying, and dividing. Let's look at an example, just to make it clear. Suppose, for instance, I'm going to perform the operation. So I sit up here and I'm going to perform the operation, which lookslike multiplying two complex numbers. So I would multiply, say, 3 plus 4i and 2 plus 6i. And that's something that I might want to take hand that to mul. I'll write mul as my generic operator here. How's that going to work? Well 3 plus 4i, say, sits in t he system at this level as something that looks like this. Let's say it was one of George's. So it would have a 3 and a 4. And attached to that would be George's type, which would say rectangular, it came from George. And attached to that-- and this itself would be the data view from the next level up, which it is-- so that itself would be a type-data object which would say complex. So that's what this object would look like up here at the very highest level, where the really super- generic operations are looking at it. Now what happens, mul eventually's going to come along and say, oh, what's it's type? It's type is complex. Go through to operate-2 and say, oh, what I want to do is apply what's in the table, which is going to be the procedure star complex,on this thing with the type stripped off. So it's going to strip off the type, take that much, and send that down into the complex world. The complex world looks at its operations and says, oh, I have to apply star c. Star c might say, oh, at some point I want to look at the magnitude of this object that it's in, that it's got. And they'll say, oh, it's rectangular, it's one of George's. So it'll then strip off the next version of type, and hand that down to George to take the magnitude of. So you see what's going on is that there are these chains of types. And the length of the chain is sort of the number of levels that you're going to be going up in this table. And what a type tells you, every time you have a vertical barrier in this table, where there's some ambiguity about where you should go down to the next level, the type is telling you where to go. And then everybody at the bottom, as they construct data and filter it up, they stick their type back on. So that's the general structure of the system. OK. Now that we've got this, let's go and make this thing even more complex. Let's talk about adding to the system not only these kinds of numbers, but it's also meaningful to start talking about adding polynomials. Might do arithmetic on polynomials. Like we could have x to the fifteenth plus 2x to the seventh plus 5. That might be some polynomial. And if we have two such gadgets we can add them or multiply them. Let's not worry about dividing them. Just add them, multiply them, then we'll subtract them. What do we have to do? Well let's think about how we might represent a polynomial. It's going to be some typed data object. So let's say a polynomial to this system might look like a thing that starts with the type polynomial. And then maybe it says the next thing is what variable its in. So I might say I'm a polynomial in the variable x. And then it'll have some information about what the terms are. And there're just tons of ways to do this, but one way is to say we're going to have a thing called a term-list. And a term-list-- well, in our case we'll use something that looks like this. We'll make it a bunch of pairs which have an order in a coefficient. So this polynomial would be represented by this term-list. And what that means is that this polynomial starts off with a term of order 15 and coefficient 1. And the next thing in it is a term of order 7 and coefficient 2, a term of order 0, which is constant in coefficient 5. And there are lots and lots of ways, and lots and lots of trade-offs when you really think about making algebraic manipulation packages about exactly how you should represent these things. But this is a fairly standard one. It's useful in a lot of contexts. OK, well how do we implement our polynomial arithmetic? Let's start out. What we'll do to make a polynomial-- we'll first have a way to make polynomials. We're going to make a polynomial out of variable like x and term -list. And all that does is we'll package them together someway. We'll put the variable together with the term list using cons, and then attached to that the type polynomial. OK, how do we add two polynomials? To add a polynomial, p1 and p2, and then just for simplicity let's say we will only add things in the same variable. So if they have the same variable, and same variable here is going to be some selector we write, whose details we don't care about. If the two polynomials have the same variable, then we'll do something. If they don't have the same variable, we'll give an error, polynomials not in the same variable. And if they do have the same variable, what we'll do is we'll make a polynomial whose variable is whatever that variable is, and whose term-list is something we'll call sum -terms. Plus terms will add the two term lists. So we'll add the two term lists to the polynomial. That'll give us a term-list. We'll add on, we'll say it's a polynomial in the variable with that term-list. That's plus poly. And then we're going to put in our table under the type polynomial, add them using plus poly. And of course we really haven't done much. What we've really done is pushed all the work onto this thing, plus-terms, which is supposed to add term-lists. Let's look at that. Here's an overview of how we might add two term-lists. So L1 and L2 were going to be two term-lists. And a term-list is a bunch of pairs, coefficient in orde r. And it's a big case analysis. And the first thing we'll check for and see if there are any terms. We're going to recursively work down these term -lists, so eventually we'll get to a place where either L1 or L2 might be empty. And if either one is empty,our answer will be the other one. So if L1 is empty we'll return L2, and if L2 is empty we'll return L1. Otherwise there are sort of three interesting cases. What we're going to do is grab the first term in each of those lists, called t1 and t2. And we're going to look at three cases, depending on whether the order of t1 is greater than the order of t2, or less than t2, or the same. Those are the three cases we're going to look at. Let's look at this case. If the order of t1 is greater than the order of t2, then what that means is that our answer is going to start with this term of the order of t1. Because it won't combine with any lower order terms. So what we do is add the lower order terms. We recursively add together all the terms in the rest of theterm-list in L1 and L2. That's going to be the lower order terms of the answer. And then we're going to adjoin to that the highest order term. And I'm using here a whole bunch of procedures I haven't defined, like a adjoin- term, and rest-terms, and selectors that get order. But you can imagine what those are. So if the first term-list has a higher order than the second, we recursively add all the lower terms and then stick on that last term. The other case, the same way. If the first term has a smaller order, well then we add the first term-list and the rest of the terms in the second one, and adjoin on this highest order term. So so far nothing's much happened, we've just sort of pushed this thing off into adding lower order terms. The last case where you actually get to a coefficients that you have to add, this will be the case where the orders are equal. What we do is, well again recursively add the lower order terms. But now we have to really combine something. What we do is we make a term whose order is the order of the term we're looking at. By now t1 and t2 have the same order. That's its order. And its coefficient is gotten by adding the coefficient of t1 and the coefficient of t2. This is a big recursive working down of terms, but really there's only one interesting symbol in this procedure, only one interesting idea. The interesting idea is this add. And the reason that's interesting is because something completely wonderful just happened. We reduced adding polynomials, not to sort of plus, but to the generic add. In other words, by implementing it that way, not only do we have our system where we can have rational numbers, or complex numbers, or ordinary numbers, we've just added on polynomials. But the coefficients of the polynomials can be anything that the system can add. So these could be polynomials whose coefficients are rational numbers or complex numbers, which in turn could be either rectangular, or polar, or ordinary numbers. So what I mean precisely is our system right now automatically can handle things like adding together polynomials that have this one: 2/3 of x squared plus 5/17 x plus 11/4. Or automatically handle polynomials that look like 3 plus 2i times x to the fifth plus 4 plus 7i, or something. You can automatically handle those things. Why is that? That's merely because, or profoundly because we reduced adding polynomials to adding their coefficients. And adding coefficients was done by the generic add operator, which said, I don't care what your types are as long as I know how to add you. So automatically for free we get the ability to handle that. What's even better than that, because remember one of the things we did is we put into the table that the way you add polynomials is using plus poly. That means that polynomia ls themselves are things that can be added. So for instance let me write one here. Here's a polynomial. So this gadget here I'm writing up, this is a polynomial in y whose coefficients are polynomials in x. So you see, simply by saying, polynomials are the mselves things that can be added, we can go off and say, well not only can we deal with rationals, or complex, or ordinary numbers, but we can deal with polynomials whose coefficients are rationals, or complex, or ordinary numbers, or polynomials whose coefficients are rationals, or complex, rectangular, polar, or ordinary numbers, or polynomials whose coefficients are rationals, complex, or ordinary numbers. And so on, and so on, and so on. So this is sort of an infinite or maybe a recursive tower of types that we've built up. And it's all exactly from that one little symbol. A -D-D. Writing "add" instead of "plus" in the polynomial thing. Slightly different way to think about it is that polynomials are a constructor for types. Namely you give it a type, like integer, and it returns for you polynomials in x whose coefficients are integers. And the important thing about that is that the operations on polynomials reduce to the operations on the coefficients. And there are a lot of things like that. So for example, let's go back and rational numbers. We thought about rational numbers as an integer over an integer, but there's the general notion of a rational object. Like we might think about 3x plus 7 over x squared plus 1. That's general rational object wh ose numerator and denominator are polynomials. And to add two of them we use the same formula, numerator times denominator plus denominator times numerator over product of denominators. How could we install that in our system? Well here's our original rational number arithmetic package. And all we have to do in order to make the entire system continue working with general rational objects, is replace these particular pluses and stars by the generic operator. So if we simply change that procedure to this one, here we've changed plus and star to add a mul, those are absolutely the only change, then suddenly our entire system can start talking about objects that look like this. So for example, here is a rational object whose numerator is a polynomial in x whose coefficients are rational numbers. Or here is a rational object whose numerator is polynomials in x whose coefficients are rational objects constructed out of complex numbers. And then there are a lot of other things like that. See, whenever you have a thing where the operations reduce to operations on the pieces, another example would be two by two matrices. I have the idea, there might be a matrix here of general things that I don't care about. But if I add two of them, the answer over here is gotten by adding this one and that one, however they like to add. So I can implement that the same way. And if I do that, then again suddenly my system can start handling things like this. So here's a matrix whose elements happen to be-- we'll say this element here is a rational object whose numerator and denominators are polynomials. And all that comes for free. What's really going on here? What's really going on is getting rid of this manager who's sitting there poking his nose into who everybody's business is. We built a system that has decentralized control. So when you come into and no one's poking around saying, gee, are you in the official list of people who can be added? Rather you say, well go off and add yourself how your parts like to be added. And the result of that is you can get this very, very, very complex hierarchy where a lot of things just get done and rooted to the right place automatically. Let's stop for questions. AUDIENCE: You say you get this for free. One thing that strikes me is that now you've lost kind of the cleanness of the break between what's on top and what's underneath. In other words, now you're defining some of the lower-level procedures in terms of things above their own line. Isn't that dangerous? Or, if nothing more, a little less structured? PROFESSOR: No, I-- the question is whether that's less structured. Depends on what you mean by structure. All this is doing is recursion. See, it's saying that the way you add these guys is to use that. And that's not less structured, it's just a recursive structure. So I don't think it's particularly any less clean. AUDIENCE: Now when you want to change the multiplier or the add operator, suddenly you've got tremendous consequences underneath that you're not even sure the extent of. PROFESSOR: That's right, but it depends what you mean. See, this goes both ways. What would be a good example? I ignored greatest common divisor, for instance. I ignored that problem just to keep the example simple. But if I suddenly decided that plus rat here should do a GCD computation and install that, then that immediately becomes available to all of these, to that guy, and that guy, and that guy, and all the way down. So it depends what you mean by the coherence of your system. It's certainly true that you might want to have a special different one that didn't filter down through the coefficients, but the nice thing about this particular example is that mostly you do. AUDIENCE: Isn't that the problem, I think, that you're getting to tied in with the fact that the structuring, the recursiveness of that structuring there is actually in execution as opposed to just definition of the actual types themselves? PROFESSOR: I think I understand the question. The point is that these types evolve and get more and more complex as the thing's actually running. Is that what -- AUDIENCE: Yes. As it's running. PROFESSOR: --what you're saying? Yes, the point is-- AUDIENCE: As opposed to the basic definitions. PROFESSOR: Right. The type structure is sort of recursive. It's not that you can make this finite list of the actual things they might look like before the system runs. It's something that evolves. So if you want to specify that system, you have to do in some other way than by this finite list. You have to do it by a recursive structure. AUDIENCE: Because the basic structure of the types is pretty clean and simple. PROFESSOR: Right. Yes? AUDIENCE: I have a question. I understand once you have your dat a structure set up, how it pulls off complex and passes that down, and then pulls off rect, passes that down. But if you're just a user and you don't know anything about rect or polar or whatever, how do you initially set up that data structure so that everything goes to the right spot? If I just have the equation over there on the left and I just want to add, multiply complex numbers -- PROFESSOR: Well that's the wonderful thing. If you're just a user you say "mul." AUDIENCE: And it figures out that I mean complex numbers? Or how do I tell it that I want- - PROFESSOR: Well you're going to have in your hands complex numbers. See what you would have at some level, as a real user, is a constructor for complex numbers. AUDIENCE: So then I have to make complex numbers? PROFESSOR: So you have to make them. What you would probably have as a user is some little thing in the reader loop, which would give you some plausible way to type in a complex number, in whatever format you like. Or it might be that you're never typing them in. Someone's just handing you a complex number. AUDIENCE: OK, so if I had a complex number that had a polynomial in it, I'd have to make my polynomial and then make my complex number. PROFESSOR: Right if you wanted it constructed from scratch. At some point you construct them from scratch. But what you don't have to know of that is when you have the object you can just say "mul." And it'll multiply. Yeah? AUDIENCE: I think the question that was being posed here is, say if I want to change my presentation of complexes, or some operation of complex, how much real code I will have to gets around with, or change to change it in one specific operation? PROFESSOR: [UNINTELLIGIBLE] what you have to change. And the point is that you only have to change what you're changing. See if Martha decides that she would rather -- let's see something silly -- like change the order in the pair. Like angle and magnitude in the other order, she just makes that change locally. And the whole thing will propagate through the system in the right way. Or if suddenly you said, gee, I have another representation for rationals. And I'm going to stick it here, by filing those operations in the table. Then suddenly all of these polynomials whose coefficients are co efficients of coefficients, or whatever, also can automatically have available that representation. That's the power of this particular one. AUDIENCE: I'm not sure if I can even pose an intelligent sounding question. But somehow this whole thing went really nicely to this beautiful finish where all the things seemed to fall into place. Sort of seemed a little contrived. That's all for the sake, I'm sure, of teaching. I doubt that the guys who first did this-- and I could be wrong-- figured it all out so that when they just all put it all together, you could all of the sudden, blam, do any kind of arithmetic on any kind of object. It seems like maybe they had to play with it for a while and had to bash it and rework it. And it seems like that's the kind of problem we're really faced with we start trying to design a really complex system, is having lots of different kinds of parts and not even knowing what kinds of operations we're going to want to do on those parts. How to organize the operations in this nice way so that no matter what you do, when you start putting them together everything starts falling out for free. PROFESSOR: OK, well that's certainly a very intelligent question. One part is this is a very good methodology that people have discovered a lot coming from symbolic algebra. Because there are a lot of complications. To allow you to implement these things before you decide what you want all the operations to be, and all of that. So in some sense it's an answer that people have discovered by wading through this stuff. In another sense, it is a very contrived example. AUDIENCE: It seems like to be able to do this you do have to wade through it for a certain amount of time before you can become good at it. PROFESSOR: Let me show you how terribly contrived this is. So you can write all these wonderful things. But the system that I wrote here, and if we had another half an hour to give this lecture I would have given this part of it, which says, notice that it breaks down if I tell it to do something as foolish as add 3 plus 7/2. Because what will happen is you'll get to operate-2, and operate-2 will say, oh this is type number, and that's type rational. I don't know how to add them. So you'd like the system at least to be able to say something like, gee, before you do that change that to 3/1. Turn it into a rational number, hand that to the rational package. That's the thing I didn't talk about in this lecture. It's a little bit in the book, which talks about the problem of what's called coercion. Where you wanted-- see, having so carefully set up all of these types as distinct objects, a lot of times you want to also put in knowledge about how to view an ordinary number as a kind of rational. Or view an ordinary number as a kind of complex. That's where the complexity in the system really starts happening, where you talk about, see where do I put that knowledge? Is it rational to know that ordinary numbers might be pieces of [UNINTELLIGIBLE] of them? Or they're terrible, terrible examples, like if I might want to add a complex number to a rational number. Bad example. 5/7. Then somebody's got to know that I have to convert these to another type, which is complex numbers whose parts might be rationals. And who worries about that? Does complex worry about that? Does rational worry about that? Does plus worry about that? That's where the real complexity comes in. And that's where it's pretty well sorted out. And a lot of, in fact, all of this message passing stuff was motivated by problems like this. And when you really push it, people are-- somehow the algebraic manipulation problem seems to be so complex that the people who are always at the edge of it are exactly in the state you said. They're wading through this thing, mucking around, seeing what they use, trying to distill stuff. AUDIENCE: I just want to come back to this issue of complexity once more. It certainly seems to be true that you have a great deal of flexibility in altering the lower level kindsof things. But it is true that you are, in a sense, freezing higher level operations. Or at least if you change them you don't know where all of the changes are going to show up, or how they are. PROFESSOR: OK, that's an extremely good question. What I have to do is, if I decide there's a new general operation called equality test, then all of these people have to decide whether or not they would like to have an equality test by looking in the table. There're ways to decentralize it even more. That's what I sort of hinted at last time, where I said you could not only have this type as a symbol, but you actually might store in each object the operations that it knows of that. So you might have things like greatest common divisor, which is a thing here whi ch is defined only for integers, and not in general for rational numbers. So it might be a very, very fragmented system. And then depending on where you want your flexibility, there's a whole spectrum of places that you can build that in. But you're pointing at the place where this starts being weak, that there has to be some agreement on top here about these general operations. Or at least people have to think about them. Or you might decide, you might have a table that's very sparse, that only has a few things in it. But there are lot of ways to play that game. OK, thank you. [MUSIC: "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec5a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 5A: Assignment, State, and Side-effects [MUSIC PLAYING] PROFESSOR: Well, so far we've invented enough programming to do some very complicated things. And you surely learned a lot about programming at this point. You've learned almost all the most important tricks that usually don't get taught to people until they have had a lot of experience. For example, data directed programming is a major trick, and yesterday you also saw an interpreted language. We did this all in a computer language, at this point, where there was no assignment statement. And presumably, for those of you who've seen your Basic or Pascal or whatever, that's usually considered the most important thing. Well today, we're going to do some thing horrible. We're going to add an assignment statement. And since we can do all these wonderful things without it, why should we add it? An important thing to understand is that today we're going to, first of all, have a rule, which is going to always be obeyed, which is the only reason we ever add a feature to our language is because there is a good reason. And the good reason is going to boil down to the ability, you now get an ability to break a problem into pieces that are different sets of pieces then you could have broken it down without that, give you another means of decomposition. However, let's just start. Let me quick begin by reviewing the kind of language that we have now. We've been writing what's called functional programs. And functional programs are a kind of encoding of mathematical truths. For example, when we look at the factorial procedure that you see on the slide here, it's basically two clauses. If n is one, the result is one, otherwise n times factorial n minus one. That's factorial of n. Well, that is factorial of n. And written down in some other obscure notation that you might have learned in calculus classes, mathematical logic, what you see there is if n equals one, for the result of n factorial is one, otherwise, greater than one, n factorial is n times n minus one factorial. True statements, that's the kind of language we've been using. And whenever we have true statements of that sort, there is a kind of, a way of understanding how they work which is that such processes can be involved by substitution. And so we see on the second slide here, that the way we understand the execution implied by those statements in arranged in that order, is that you do successive substitutions of arguments for formal parameters in the body of a procedure. This is basically a sequence of equalities. Factorial four is four times factorial three. That is four times three times factorial of two and so on. We're always preserving truth. Even though we're talking about true statements, there might be more than one organization of these true statements to describe the computation of a particular function, the computation of the value of a particular function. So, for example, looking at the next one here. Here is a way of looking at the sum of n and m. And we did this one by a recursive process. It's the increment of the sum of the decrement of n and m. And, of course, there is some piece of mathematical logic here that describes that. It's the increment of the sum of the decrement of n and m, just like that. So there's nothing particularly magic about that. And, of course, if we can also look at an iterative process for the same, a program that evolves an iterative process, for the same function. These are two things that compute the same answer. And we have equivalent mathematical truths that are arranged there. And just the way you arrange those truths determine the particular process. In the way choose and arrange them determines the process that's evolved. So we have the flexibility of talking about both the function to be computed, and the method by which it's computed. So it's not clear we need more. However, today I'm going to this awful thing. I'm going to introduce this assignment operation. Now, what is this? Well, first of all, there is going to be another kind of kind of statement, if you will, in a programming language called Set! Things that do things like assignment, I'm going to put exclamation points after. We'll talk about what that means in a second. The exclamation point, again like question mark, is an arbitrary thing we attach to the symbol which is the name, has no significance to the system. The only significance is to me and you to alert you that this is an assignment of some sort. But we're going to set a variable to a value. And what that's going to mean is that there is a time at which something happens. Here's a time. If I have time going this way, it's a time access. Time progresses by walking down the page. Then an assignment is the first thing we have that produces the difference between a before and an after. All the other programs that we've written, that have no assignments in them, the order in which they were evaluated didn't matter. But assignment is special, it produces a moment in time. So there is a moment before the set occurs and after, such that after this moment in time, the variable has the value, value. Independent of what value it had before, set! changes the value of the variable. Until this moment, we had nothing that changed. So, for example, one of the things we can think of is that the procedures we write for something like factorial are in fact pretty much identical to the function factorial. Factorial of four, if I write fact4, independent of what context it's in, and independent of how many times I write it, I always get the same answer. It's always 24. It's a unique map from the argument to the answer. And all the programs we've written so far are like that. However, once I have assignment, that isn't true. So, for example, if I were to define count to be one. And then I'm going to define also a procedure, a simple procedure called demo, which takes argument x and does the following operations. It first sets x to x plus one. My gosh, this looksjust like FORTRAN, right-- in a funny syntax. And then add to x count, Oh, I just made a mistake. I want to say, set! count to one plus count. It's this thing defined here. And then plus x count. Then I can try this procedure. Let's run it. So, suppose I get a prompt and I say, demo three. Well, what happens here? The first thing that happens is count is currently one. Currently, there is a time. We're talking about time. x gets three. At this moment, I say, oh yes, count is incremented, so count is two. two plus three is five. So the answer I get out is five. Then I say, demo of say, three again. What do I get? Well, now count is two, it's not one anymore, because I have incremented it. But now I go through this process, three goes into x, count becomes one plus count, so that's three now. The sum of those two is six, so the answer is six. And what we see is the same expression leads to two different answers, depending upon time. So demo is not a function, does not compute a mathematical function. In fact, you could also see why now, of course, this is the first place where the substitution model isn't going to work. This kills the substitution model dead. You know, with quotation there were some little problems that a philosopher might notice with the substitutions, because you have to worry about what deductions you can make when you substitute into quotes, if you're allowed to do that at all. But here the substitution model is dead, can't do anything at all. Because, supposing I wanted to use a substitution model to consider substituting for count? Well, my gosh, if I substitute for here and here, they're different ones. It's not the same count any more. I get the wrong answer. The substitution model is a static phenomenon that describes things that are true and not things that change. Here, we have truths that change. OK, Well, before I give you any understanding of this, this is very bad. Now, we've lost our model of computation. Pretty soon, I'm going to have to build you a new model of computation. But ours plays with this, just now, in an informal sense. Of course, what you already see is that when I have something like assignment, the model that we're going to need is different from the model that we had before in that the variables, thosesymbols like count, or x are no longer going to refer to the values they have, but rather to some sort of place where the value restored. We're going to have to think that way for a while. And it's going to be a very bad thing and cause a lot of trouble. And so, as I said, the very fact that we're inventing this bad thing, means that there had better be a good reason for it, otherwise, just a waste of time and a lot of effort. Let's just look at some of it just to play. Supposing we write down the functional version, functional meaning in the old style, of factorial by an iterative process. Factorial of n, we're going to iterate of m and i, which says if i is greater than n, then the result is m, otherwise, the result of iterating the product of i and m. So m is going to be the product that I'm accumulating. m is the product. And the count I'm going to increase by one. Plus, ITER, ELSE, COND, define. I'm going to start this up. And these days, you should have no trouble reading something like this. What I have here is a product there being accumulated and a counter. I start them up both at one. I'm going to buzz the counter up, i goes to i plus one every time around. But that's only our putting a time on the process, each of this is just a set of truths, true rules. And m is going to get a new values of i and m, i times m each time around, and eventually i is going to be bigger than n, in which case, the answer's going to be m. Now, I'm speaking to you, use time in this. That's just because I know how the computer works. But I didn't have to. This could be a purely mathematical description at this point, because substitution will work for this. But let's set right down a similar sort of program, using the same algorithm, but with assignments. So this is called the functional version. I want to write down an imperative version. Factorial of n. I'm going to create my two variables. Let i initialize itse lf to one, and m be initialized to one, similar. We'll create a loop which has COND greater than i, and if i is greater than n, we're done. And the result is m, the product I'm accumulating. Otherwise, I'm going to write down three things to do. I'm going to set! m to the product of i and m, set! i to the sum of i and one, and go around the loop again. Looks very familiar to you FORTRAN programmers. ELSE, COND, define, funny syntax though. Start the loop up, and that's the program. Now, this program, how do we think about it? Well, let's just say what we're seeing here. There are two local variables, i and m, that have been initialized to one. Every time around the loop, I test to see if i is greater than n, which is the input argument, and if so, the re sult is the product being accumulated in m. However, if it's not the end of the loop, if I'm not done, then what I'm going to do is change the product to be the result of multiplying i times the current product. Which is sort of what we were doing here. Except here I wasn't changing. I was making another copy, because the substitution model says, you copy the body of the procedure with the arguments substituted for the formal parameters. Here I'm not worried about copying, here I've changed the value of m. I also then change the value of i to i plus one, and go buzzing around. Seems like essentially the same program, but there are some ways of making errors here that didn't exist until today. For example, if I were to do the horrible thing of not being careful in writing my program and interchange those two assignments, the program wouldn't compute the same function. I get a timing error because there's a dependency that m depends upon having the last value of i. If I try to i first, then I've got the wrong value of i when I multiply by m. It's a bug that wasn't available until this moment, until we introduced something that had time in it. So, as I said, first we need a new model of computation, and second, we have to be damn good reason for doing this kind of ugly thing. Are there any questions? Speak loudly, David. AUDIENCE: I'm confused about, we've introduced set now, but we had let before and define before. I'm confused about the difference between the three. Wouldn't define work in the same situation as set if you introduced it a bit? PROFESSOR: No, define is intended for setting something once the first time, for making it. You've never seen me write on a blackboard two defines in a row whose intention was to change the old value of some variable to a new one. AUDIENCE: Is that by convention or-- PROFESSOR: No, it's intention. The answer is that, for example, internal to a procedure, two defines in a row are illegal, two defines in a row of the same variable. x can't be defined twice. Whether or not a system catches that error is a different question, but I legislate to you that define happens once on anything. Now, indeed, in interactive debugging, we intend that you interacting with your computer will redefine things, and so there's a special exception made for interactive debugging. But define is intended to mean to set up something which will be forever that value after that point. It's as if all the defines were done at the beginning. In fact, the only legal place to put a define in Scheme, internal to a procedure, is just at the beginning of a lambda expression, the beginning of the body of a procedure. Now, let of course does nothing like either of that. I mean, if you look at what's happening with a let, this happens again exactly once. It sets up a context where i and m are values one and one. That context exists throughout this scope, this region of t he program. However, you don't think of that let as setting i again. It doesn't change it. i never changes because of the let. i gets created because of let. In fact, the let is a very simple idea. Let does nothing more, Let a variable one to have value one; I'll write this down a little bit more neatly; Let's write, var one have value, the value of expression e1, and variable two, have this value of the expression e2, in an expression e3, is the same thing as a procedure of var one and var two, the formal parameters, and e3 being the body, where var one is bound to the value of e1, and var two gets the value of e2. So this is, in fact, a perfectly understandable thing from a substitution point of view. This is really the same expression written in two different ways. In fact, the way the actual system works is this gets translated into this before anything happens. AUDIENCE: OK, I'm still unclear as then what makes the difference between a let and a define. They could-- PROFESSOR: A define is a syntactic sugar, whereby, essentially a bunch of variables get created by lets and then set up once. OK, time for the first break, I think. Thank you. [MUSIC PLAYING] Well let's see. I now have to rebuild the model of computation, so you understand how some such mechanical mechanism could work that can do what we've just talked about. I just recently destroyed your substitution model. Unfortunately, this model is significantly more complicated than the substitution model. It's called the environment model. And I'm going to have to introduce some terminology, which is very good terminology for you to know anyway. It's about names. And we're going to give names to the kinds of names things have and the way those names are used. So this is a meta-description, if you will. Anyway, there is a pile of an unfortunate terminology here, but we're going to need this to understand what's called the environment model. We're about to do a little bit of boring, dog-work here. Let's look at the first transparency. And we see a description of a word called bound. And we're going to say that a variable, v, is bound in an expression, e, if the meaning of e is unchanged by the uniform replacement of a variable w, not occurring in e, for every occurrence of v in e. Now that's a long sentence, so, I think, I'm going to have to say a little bit about that before we even fool around at all here. Bound variables we're talking about here. And you've seen lots of them. You may not know that you've seen lots of them. Well, I suppose in your logic you saw a logical variables like, for every x there exists a y such that p is true of x and y from your calculus class. This variable, x, and this variable, y, are bound, because the meaning of this expression does not depend upon the particular letters I used to describe x and y. If I were to change the w for x, then said for every w there exists a y such that p is true of w and y, it would be the same sentence. That's what it means. Or another case of this that you've seen is integral say, from 0 to one of dx over one plus x square. Well that's something you see all the time. And this x is a bound variable. If I change that to a t, the expression is still the same thing. This is a 1/4 of the arctan of one or something like that. Yes, that's the arctan of one. So bound variables are actually fairly common, for those of you who have played a bit with mathematics. Well, let's go into the programming world. Instead of the quantifier being something like, for every, or there exists, or integral, a quantifier is a symbol that binds a variable. And we are going to use the quantifier lambda as being the essential thing that binds variables. And so we have some nice examples here like that procedure of one argument y which does the following thin g. It calls the procedure of one argument x, which multiplies x by y, and applies that to three. That procedure has the property there of two bound variables in it, x and y. This quantifier, lambda here, binds this y, and this quantifier, lambda, binds tha t x. Because, if I were to take an arbitrary symbol does not occur in this expression like w and replace all y's with w's in this expression, the expression is still the same, the same procedure. And this is an important idea. The reason why we had such things like that is a kind of modularity. If two people are writing programs, and they work together, it shouldn't matter what names they use internal to their own little machines that they're building. And so, what I'm really telling you there, is that, for example, this is equivalent to that procedure of one argument y which uses that procedure of one argument d which multiplies z by y. Because nobody cares what I used in here. It's a nice example. On the other hand, I have some variables that are not b ound. For example, that procedure of one argument x which multiplies x by y. In this case, y is not bound. Supposing y had the value three, and z had the value four, then this procedure would be the thing that multiplies its argument by three. If I were to replace every instance of y with z, I would have a different procedure which multiplies every argument that's given by four. And, in fact, we have a name for such a variable. Here, we say that a variable, v, is free in the expression, e, if the meaning of the expression, e, is changed by the uniform replacement of a variable, w, not occurring in e for every occurrence of v and e. So that's why this variable over here, y, is a free variable. And so free variables in this expression-- And other examples of that is that procedure of one argument y, which is just what we had before, which uses that procedure of one argument x that multiplies x by y-- use that on three. This procedure has a free variable in it which is asterisk. See, because, if that has a normal meaning of multiplication, then if I were to replace uniformly all asterisks with pluses, then the meaning of this expression would change. That's what you mean by a free variable. So, so far you've learned some logician words which describe the way names are used. Now, we have to do a little bit more playing around here, a little bit more. I want to tell you about the regions are over which variables are defined. You see, we've been very informal about this up till now, and, of course, many of you have probably understood very clearly or most of you, that the x that's being declared here is defined only in here. This x is the defined only in here, and this y is defined only in here. We have a name for such an idea. It's called a scope. And let me give you another piece of terminology. It's a long story. If x is a bound variable in e, then there is a lambda expression where it is bound. So the only way you can get a bound variable ultimately is by lambda expression. Then you may worry, does define quite an exception to this? And it turns out, we could always arrange things so you don't need any defines. And we'll see that in a while. It's a very magical thing. So define really can go away. The really, only thing that makes names is lambda . That's its job. And what's so amazing about a lot of things is you can compute with only lambda. But, in any case, a lambda expression has a place where it declares a variable. We call it the formal parameter list or the bound variable list. We say that the lambda expression binds -- so it's a verb-- binds the variables declared in it's found variable list. In addition, those parts of the expression where the variable is defined, which was declared by some declaration, is called the scope of that variable. So these are scopes. This is the scope of y. And this is the scope of x-- that sort of thing. OK, well, now we have enough terminology to begin to understand how to make a new model for computation, because the key thing going on here is that we destroyed the substitution model, and we now have to have a model that represents the names as referring to places. Because if we are going to change something, then we have a place where it's stored. You see, if a name only refers to a value, and if I tried to change the name's meaning, well, that's not clear. There's nothing that is the place that that name referred to. How am I really saying it? There is nothing shared among all of the instances of that name. And what we really mean, by a name, is that we fan something out. We've given something a name, and you have it, and you have it, because I'm given you a reference to it, and I've give n you a reference to it. And we'll see a lot about that. So let me tell you about environments. I need the overhead projection machine, thank you. And so here is a bunch of environment structures. An environment is a way of doing substitutions virtually. It represents a place where something is stored which is the substitutions that you haven't done. It's a place where everything accumulates, where the names of the variables are associated with the values they have such that when you say, what dose this name mean, you look it up in an environment. So an environment is a function, or a table, or something like that. But it's a structured sort of table. It's made out of things called frames. Frames are pieces of environment, and they are chained together, in some nice ways, by what's called parent links or something like that. So here, we have an environment structure consisting of three environments, basically, a, b, and c. d is also an environment, but it's the same one, they share. And that's the essen ce of assignment. If I change a variable, a value of a valuable that lives here, like that one, it should be visible from all places that you're looking at it from. Take this one, x. If I change the x to four, it's visible from other places. But I'm not going to worry about that right now. We're going to talk a lot about that in a little while. What do we have here? Well, these are called frames. Here is a frame, here's a frame, and here's a frame. a is an environment which consists of the table which is frame two, followed by the table labeled frame one. And, in this environment, in say this environment, frame two, x and y are bound. They have values. Sorry, in frame one -- In frame two, z is bound, and x is bound, and y is bound, but the value of x that we see, looking from this point of view, is this x. It's x is seven, rather than this one which is three. We say that this x shadows this x. From environment three-- from frame three, from environment b, which refers to frame three, we have variables n and y bound and also x. This y shadow this one. So the value, looking from this point of view, of y is two. The value for looking from this point of view and m is one. And the value, looking from this point of view, of x is three. So there we have a very simple environment structure made out of frames. These correspond to the applications of procedures. And we'll see that in a second. So now I have to make you some other nice little structure that we build. Next slide, we see an object, which I'm going to draw procedures. This is a procedure. A procedure is made out of two parts. It's sort of like a cons. However, it's the two parts. The first part refers to some code, something that can be executed, a set of instructions, if you will. You can think of it that way. And the second part is the environment. The procedure is the whole thing. And we're going to have to use this to capture the values of the free variables that occur in the procedure. If a variable occurs in the procedure it's either bound in that procedure or free. If it's bound, then the value will somehow be easy to find. It will be in some easy environment to get at. If it's free, we're going to have to have something that goes with the procedure that says where we'll go look for its value. And the reasons why are not obvious yet, but will be soon. So here's a procedure object. It's a composite object consisting of a piece of code and a environment structure. Now I will tell you the new rules, the complete new rules, for evaluation. The first rule is-- there's only two of them. These correspond to the substitution model rules. And the first one has to do with how do you apply a procedure to its arguments? And a procedural object is applied to a set of arguments by constructing a new frame. That frame will contain the mapping of the former parameters to the actual parameters of the arguments that were supplied in the call. As you know, when we make up a call to a procedure like lambda x times x y, and we call that with the argument three, then we're going to need some mapping of x to three. It's the same thing as later substituting, if you will, the three for the x in the old model. So I'm going to build a frame which contains x equals three as the information in that frame. Now, the body of the procedure will then have to be evaluated which is this. I will be evaluated in an environment which is constructed by adjoining the new frame that we just made to the environment which was part of the procedure that we applied. So I'm going to make a little example of that here. Supposing I have some environ ment. Here's a frame which represents it. And some procedure-- which I'm going to draw with circles here because it's easier than little triangles-- Sorry, those are rhombuses, rhomboidal little pieces of fruit jelly or something. So here's a procedure which takes this environment. And the procedure has a piece of code, which is a lambda expression, which binds x and y and then executes an expression, e. And this is the procedure. We'll call it p. I wish to apply that procedure to three and four. So I want to do p of three and four. What I'm going to do, of course, is make a new frame. I build a frame which contains x equals three, and y equals four. I'm going to connect that frame to this frame over here. And then this environment, with I will call b, is the environment in which I will evaluate the body of e. Now, e may contain references to x and y and other things. x and y will have values right here. Other things will have their values here. How do we get this frame? That we do by the construction of procedures which is the other rule. And I think that's the next slide. Rule two, when a lambda expression is evaluated, relative to a particular environment-- See, the way I get a procedure is by evaluating the lambda expression. Here's a lambda expression. By evaluating it, I get a procedure which I can apply to three. Now this lambda expression is evaluated in an environment where y is defined. And I want the body of this which contains a free version of y. y is free in here, it's bound over the whole thing, but it's free over here. I want that y to be this one. I evaluate this body of this procedure in the environment where y was created. That's this kind of thing, because that was done by application. Now, if I ever want to look up the value of y, I have to know where it is. Therefore, this procedural was created, the creation of the procedure which is the result of evaluating that lambda expression had better capture a pointer or remember the frame in which y was bound. So that's what this rule is telling us. So, for example, if I happen to be evaluating a lambda expression, lambda expression in e, lambda of say, x and y, let's call it g in e, evaluating that. Well, all that means is I now construct a procedure object. e is some environment. e issomething which has a pointer to it. I construct a procedure object that points up to that environment, where the code of that is a lambda expression or whatever that translates into. And this is the procedure. So this produces for me-- this object here, this environment pointer, captures the place where this lambda expression was evaluated, where the definition was used, where the definition was used to make a procedure, to make the procedure. So it picks up the environment from the place where that procedure was defined, stores it in the procedure itself, and then when the procedure is used, the environment where it was defined is extended with the new frame. So this gives us a locus for putting where a variable has a value. And, for example, if there are lots of guys pointing in at that environment, then they share that place. And we'll see more of that shortly. Well, now you have a new model for understanding the execution of programs. I suppose I'll take questions now, and then we'll go on and use that for something. AUDIENCE: Is it right to say then, the environment is that linked chain of frames -- PROFESSOR: That's right. AUDIENCE: starting with-- working all the way back? PROFESSOR: Yes, the environment is a sequence of frames linked together. And the way I like to think about it, it's the pointer to the first one, because once you've got that you've got them all. Anybody else? AUDIENCE: Is it possible to evaluate a procedure or to define a procedure in two different environments such that it will behave differently, and have pointers to both -- PROFESSOR: Oh, yes. The same procedure is not going to have two different environments. The same code, the same lambda expression can be evaluated in two environments producing two different procedures. Each procedure-- AUDIENCE: Their definition has the same name. Their operation-- PROFESSOR: The definition is written the same, with the same characters. I can evaluate that set of characters, whatever, that list structure that defines, that is the textual representation. I can evaluate that in two different environments producing two different procedures. Each of those procedures has its own local sets of variables, and we'll see that right now. Anybody else? OK, thank you. Let's take a break. [MUSIC PLAYING] Well, now I've done this terrible thing to you. I've introduced a very complicated thing, assignment, which destroys most of the interesting mathematical properties of our programs. Why should I have done this? What possible good could this do? Clearly not a nice thing, so I better have a good excuse. Well, let's do a little bit of playing, first of all, with some very interesting programs that have assignment. Understand s omething special about them that makes them somewhat valuable. Start with a very simple program which I'm going to call make-counter. I'm going to define make-counter to be a procedure of one argument n which returns as its value a procedure of no arguments-- a procedure that produces a procedure-- which sets n to the increment of n and returns that value of n. Now we're going to investigate the behavior of this. It's a sort of interesting thing. In order to investigate the behavior, I have to make an environment model, because we can't understand this any other way. So let's just do that. We start out with some sort of-- let's say there is a global environment that the machine is born with. Global we'll call it. And it's going to have in it a bunch of initial things. We all know what it's got. It's got things in it like say, plus, and times, and quotient, and difference, and CAR, and et cetera, lots of things. I don't know what they are, some various squiggles that are the things the machine is born with. And by doing the definition here, what I plan to do-- Well, what am I doing? I'm doing this relative to the global environment. So here's my environment pointer. In order to do that I have to evaluate this lambda expression. That means I make a procedure object. So I'm going to make a procedure object here. And the procedure object has, as the place it's defined, the global environment. The procedure object contains some code that represents a procedure of one argument n which returns a procedure ofno arguments which does something. And the define is a way of changing this environment, so that I now add to it a make-counter, a special rule for the special thing defined. But what that is, is it gives me that pointer to that procedure. So now the global environment contains make- counter as well. Now, we're going to do some operations. I'm going to use this to make some counters. We'll see what a counter is. So let's define c1 to be a counter beginning at 0. Well, we know how to do this now, according to the model. I have to evaluate the expression make-counter in the global environment, make-counter of 0. Well, I look up make-counter and see that it's a procedure. I'm going to have to apply that procedure. The way I apply the procedure is by constructing a frame. So I construct a frame which has a value for n in it which is 0, and the parent environment is the one which is the environment of definition of make-counter. So I've made an environment by applying make- counter to 0. Now, I have to evaluate the body of make-counter, which is this lambda expression, in that environment. Well evaluating this body, this body is a lambda expression. Evaluate a lambda expression means make a procedure object. So I'm going to make a procedure object. And that procedure object has the environment it was defined in being that, where n was defined to be 0. And it has some code, which is the procedure of no arguments which does something, that sets something, and returns n. And this thing is going to be the object, which in the global environment, will have the name c1. So we construct a name here, c1, and say that equals that. Now, but also make another counter, c2 to be make-counter say, starting with 10. Then I do essentially the same thing. I apply the make-counter procedure, which I got from here, to make another frame with n being 10. That frame has the global environment as its parent. I then construct a procedure which has that as it's frame of definition. The code of it is the procedure of no arguments which does something. And it does a set, and so on. And n comes out. And c2 is this. Well, you're already beginning to see something fairly interesting. There are two n's here. They are not one n. Each time I called make-counter, I made another instance of n. These are distinct and separate from each other. Now, let's do some execution, use those counters. I'm going to use those counters. Well, what happens if I say, c1 at this point? Well, I go over here, and I say, oh yes, c1 is a procedure. I'm going to call this procedure on no arguments, but it has no parameters. That's right. What's its body? Well, I have to look over here, because I didn't write it down. It said, set n to one plus n and return n, increment n. Well, the n it sees is this one. So I increment that n. That becomes one, and I return the value one. Supposing I then called c2. Well, what do I do? I say c2 is this procedure which does the same thing, but here's the n. It becomes 11. And so I have an 11 which is the value. I then can say, let's try c1 again. c1 is this, that's two, so the answer is two. And c2 gives me a 12 by the same method, by walking down here looking at that and saying, here's the n, I'm incrementing. So what I have are computational objects. There are two counters, each with its own independent local state. Let's talk about this a little. This is a strange thing. What's an object? It's not at all obvious what an object is. We like to think about objects, because it's economical to think that way. It's an intellectual economy. I am an object. You are an object. We are not the same object. I can divide the world into two parts, me and you, and there's other things as well, such that most of the things I might want to discuss about my workings do not involve you, and most of the things I want to discuss about your workings don't involve me. I have a blood pressure, a temperature, a respiration rate, a certain amount of sugar in my blood, and numerous, thousands, of state variables-- millions actually, or I don't know how many-- huge numbers of state variables in the physical sense which represent the state of me as a particle, and you have gazillions of them as well. And most of mine are uncoupled to most of yours. So we can compute the properties of me without worrying too much about the properties of you. If we had to work about both of us together, than the number of states that we have to consider is the product of the number of states you have and the number of states I have. But this way it's almost a sum. Now, indeed there are forces that couple us. I'm talking to you and your state changes. I'm looking at you and my state changes. Some of my state variables, a very few of them, therefore, are coupled to yours. If you were to suddenly yell very loud, my blood pressure would go up. However, and it may not be always appropriate to think about the world as being made out of independent states and independent particles. Lots of the bugs that occur in things like quantum mechanics, or the bugs in our minds that occur when we think about things like quantum mechanics, are due the fact that we are trying to think about things b eing broken up into independent pieces, when in fact there's more coupling than we see on the surface, or that we want to believe in, because we want to compute efficiently and effectively. We've been trained to think that way. Well, let's see. How would we know if we had objects at all? How can we tell if we have objects? Consider some possible optical illusions. This could be done. These pieces of chalk are not appropriately identical, but supposing you couldn't tell the difference of them by looking at them. Well, there's a possibility that this all a game I'm playing with mirrors. It's really the same piece of chalk, but you're seeing two of them. How would you know if you're seeing one or two? Well, there's only one way I know. You grab one of them and change it and see if the other one changed. And it didn't, so there's two of them. And, on the other hand, there is some other screwy properties of things like that. Like, how do we know if something changed? We have to look at it before and after the change. The change is an assignment, it's a moment in time. But that means we have to know it was the same one that we're looking at. So some very strange, and unusual, and obscure, and -- I don't understand the problems associated with assignment, and change, and objects. These could get very, very bad. For example, here I am, I am a particular person, a particular object. Now, I can take out my knife, and cut my fingernail. A piece of my fingernail has fallen off onto the table. I believe I am the same person I was a second ago, but I'm not physically the same in the slightest. I have changed. Why am I the same? What is the identity of me? I don't know. Except for the fact that I have some sort of identity. And so, I think by introducing assignment and objects, we have opened ourselves up to all the horrible questions of philosophy that have been plaguing philosophers for some thousands of years about this sort of thing. It's why mathematics is a lot cleaner. Let's look at the best things I know to say about actions and identity. We say that an action, a, had an effect on an object, x, or equivalently, that x was changed by a, if some property, p, which was true of x before a, became false of x after a. Let's test. It still means I have to have the x before and after. Or, the other way of saying this is, we say that two objects x and y are the same for any action which has an effect on x has the same effect on y. However, objects are very useful, as I said, for intellectual economy. One of the things that's incredibly useful about them, is that the world is, we like to think about, made out of independent objects with independent local state. We like to think that way, although it isn't completely true. When we want to make very complicated programs that deal with such a world, if we want those programs to be understandable by us and also to be changeable, so that if we change the world we change the program only a little bit, then we want there to be connections, isomorphism, between the objects in the world and the objects in our mental model. The modularity of the world can give us the modularity in our programming. So we invent things called object-oriented programming and things like that to provide us with that power. But it's even easier. Let's play a little game. I want to play a little game,show you an even easier example of where modularity can be enhanced by using an assignment statement, judiciously. One thing I want to enforce and impress on you, is don't use assignment statements the way you use it in FORTRAN or Basic or something or Pascal, to do the things you don't have to do with it. It's not the right way to think for most things. Sometimes it's essential, or maybe it's essential. We'll see more about that too. OK, let me show you a fun game here. There was mathematician by the nam e of Cesaro-- or Cesaro, Cesaro I suppose it is-- who figured out a clever way of computing pi. It turns out that if I take to random numbers, two integers at random, and compute the greatest common divisor, their greatest common divisor is either one or it's not one. If it's one, then they have no common divisors. If their greatest common divisor is one-- the probability that two random numbers, two numbers chosen at random, has as greatest common divisor one is related to pi. In fact-- yes, it's very strange-- of course there are other ways of computing pi, like dropping pins on flags, and things like that, and sort of the same kind of thing. So the probability of that the GCD of number one and number two, two random numbers chosen, is 6 over pi squared. I'm not going to try to prove that. It's actually not too hard and sort of fun. How would we estimate such probability? Well, the way we do that, the way we estimate probabilities, is by doing lots of experiments, and then computing the ratios of the ones that come out one way to the total number of experiments we do. It's called Monte Carlo, and it's useful in other contexts for doing things like integrals where you have lots and lots of variables-- the space which is limiting the dimensions you are do ing you integral in. But going back to here, Let's look at this slide, We can use Cesaro's method for estimating pi with n trials by taking the square root of six over a Monte Carlo, a Monte Carlo experiment with n trials, using Cesaro's experiment, where Cesaro's experiment is the test of whether the GCD of two random numbers-- And you can see that I've already got some assignments in here, just by what I wrote. The fact that this word rand, in parentheses, therefore, that procedure call, yields a different value than this one, at least that's what I'm assuming by writing this this way, indicates that this is not a function, that there's internal state in it which is changing. If the GCD of those two random numbers is equal to one, that's the experiment. So here I have an experimental method for estimating the value of pi. Where, I can easily divide this problem into two parts. One is the specific Monte Carlo experiment of Cesaro, which you just saw, and the other is the general technique of doing Monte Carlo experiments. And that's what this is. If I want to do Monte Carlo experiments with n trials, a certain number of trials, and a particular experiment, the way I do that is I make a little iterative procedure which has variable the number of trials remaining and the number trials that have been passed, that I've gotten true. And if the number remaining is 0, then the answer is the number past divided by this whole number of trials, was the estimate of the probability. And if it's not, if I have more trials to do, then let's do one. We do an experiment. We call the procedure which is experiment on no arguments. We do the experiment and then, if that turned out to be true, we go around the loop decrementing the number of experiments we have to do by one and incrementing the number that were passed. And if the experiment was false, we just go around the loop decrementing the number of experiments remaining and keeping the number passed the same. We start this up iterating over the total number of trials with 0 experiments past. A very elegant little program. And I don't have to just do this with Cesaro's experiment, it could be lots of Monte Carlo experiments I might do. Of course, this depends upon the existence of some sort of random number generator. And random number generators generally look something like this. There is a random number generator-- is in fact a procedure which is going to do something just like the counter. It's going to update an x to the result of applying some function to x, where this function is some screwy kind of function that you might find out in Knuth's books on the details of programming. He does these wonderful books that are full of the details of programming, because I can't remember how to make a random number generator, but I can look it up there, and I can find out. And then, eventually, I return the value of x which is the state variable internal to the random number generator. That state variable is initialized somehow, and has a value. And this procedure is defined in the context where that variable is bound. So this is a hidden piece of local state that you see here. And this procedure is defined in that context. Now, that's a very simple thing to do. And it's very nice. Supposing, I didn't want to use assignments. Supposing, I wanted to write this program without assignments. What problems would I have? Well, let's see. I'd like to use the overhead machine here, thank you. First of all, let's look at the whole thing. It's a big story. Unfortunately, which tells you there is something wrong. It's at least that big, and it's monolithic. You don't have to understand or look at the text there right now to see that it's monolithic. It isn't a thing which is Cesaro's experiment. It's not pulled out from the Monte Carlo process. It's not separated. Let's look why. Remember, the constraint here is that every procedure return the same value for the same arguments. Every procedure represents a function. That's a different kind of constraint. Because when I have assignments, I can change some internal state variable. So let's see how that causes things to go wrong. Well, start at the beginning. The estimate of pi looks sort of the same. What I'm doing is I take the square root of six over the random GCD test applied to n, whereas that's what this is. But here, we are beginning to see something funny. The random GCD test of a certain number of trials is just like we had before, an iteration on the number of trials remaining, the number of trials that have been passed, and another variable x. What's that x? That x is the state of the random number generator. And it is now going to be used here. The same random update function that I have over here is the one I would have used in a random number generator if I were building it the other way, the one I get out of Knuth's books. x is going to get transformed into x1, I need two random numbers. And x1 is going to get transformed into x2, I have two random numbers. I then have to do exactly what I did before. I take the GCD of x1 x2. If that's one, then I go around the loop with x2 being the next value of x. You see what's happened here is that the state of the random number generator is no longer confined to the insides of the random number generator. It has leaked out. It has leaked out into my procedure that does the Monte Carlo experiment. But what's worse than that, is it's also, because it was contained inside my experiment itself, Cesaro, it leaked out of that too. Because Cesaro called twice, has to have a different value each time, if I going to have a legitimate experimental test. So Cesaro can't be a function either, unless I pass it the seed of the random number generator that is going to go wandering around. So unfortunately, the seed of random number generator has leaked out into Cesaro, from the random number generator, that's leaked into the Monte Carlo experiment. And, unfortunately, my Monte Carlo experiment here is no longergeneral. The Monte Carlo experiment here knows how many random numbers I need to do the experiment. That's sort of horrible. I lost an ability to decompose a problem into pieces, because I wasn't willing to accept the little loop of information, the feedback process, that happens inside the random number generator before that was made by having an assignment to a state variable that was confined to the random number generator. So the fact that the random number generator is an object, with an internal state variable, it's affected by nothing, but it'll give you something, and it will apply it's force to you, that was what we're missing now. OK, well I think we've seen enough reason for doing this, and it all sort of looks very wonderful. Wouldn't it be nice if assignment was a good thing and maybe it's worth it, but I'm not sure. As Mr. Gilbert and Sullivan said, things are seldom what they seem, skim milk masquerades as cream. Are there any questions? Are there any philosophers here? Anybody want to argue about objects? You're just floored, right? And you haven't done your homework yet. You haven't come up with a good question. Oh, well. Sure, thank you. Let's take the long break now. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed thismaterial in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec5b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 5B: Computational Objects PROFESSOR: Well, now that we've given you some power to make independent local state and to model objects, I thought we'd do a bit of programming of a very complicated kind, just to illustrate what you can do with this sort of thing. I suppose, as I said, we were motivated by physical systems and the ways we like to think about physical systems, which is that there are these things that the world is made out of. And each of these things has particular independent local state, and therefore it is a thing. That's what makes it a thing. And then we're going to say that in the model in the world--we have a world and a model in our minds and in the computer of that world. And what I want to make is a correspondence between the objects in the world and the objects in the computer, the relationships between the objects in the world and the relationships between those same obj... --the model objects in the computer, and the functions that relate things in the world to the functions that relate things in the computer. This buys us modularity. If we really believe the world is like that, that it's made out of these little pieces, and of course we could arrange our world to be like that, we could only model those things that are like that, then we can inherit the modularity in the world into our programming. That's why we would invent some of this object -oriented programming. Well, let's take the best kind of objects I know. They're completely--they're completely wonderful: electrical systems. Electrical systems really are the physicist's best, best objects. You see over here I have some piece of machinery. Right here's a piece of machinery. And it's got an electrical wire connecting one part of the machinery with another part of the machinery. And one of the wonderful properties of the electrical world is that I can say this is an object, and this is an object, and they're-- the connection between them is clear. In principle, there is no connection that I didn't describe with these wires. Let's say if I have light b ulbs, a light bulb and a power supply that's plugged into the outlet. Then the connection is perfectly clear. There's no other connections that we know of. If I were to tie a knot in the wire that connects the light bulb to the power supply, the light remains lit up. It doesn't care. That the way the physics is arranged is such that the connection can be made abstract, at least for low frequencies and things like that. So in fact, we have captured all of the connections there really are. Well, as you can go one step further and talk about the most abstract types of electrical systems we have, digital to dual circuits. And here there are certain kinds of objects. For example, in digital circuits we have things like inverters. We have things like and -gates. We have things like or-gates. We connect them together by sort-of wires which represent abstract signals. We don't really care as physical variables whether these are voltages or currents or some combination or anything like that, or water, water pressure. These abstract variables represent certain signals. And we build systems by wiring these things together with wires. So today what I'm going to show you, right now, we're going to build up an invented language in Lisp, embedded in the same sense that Henderson's picture language was embedded, which is not the same sense as the language of pattern match and substitution was done yesterday. The pattern match/substitution language was interpreted by a Lisp program. But the embedding of Henderson's program is that we just build up more and more procedures that encapsulate the structure we want. So for example here, I'm going to have some various primitive kinds of objects, as you see, that one and that one. I'm going to use wires to combine them. The way I represent attaching-- I can make wires. So let's say A is a wire. And B is a wire. And C is a wire. And D is a wire. And E is wire. And S is a wire. Well, an or-gate that has both inputs, the inputs being A and B, and the output being Y or D, you notate like this. An and-gate, which has inputs A and B and output C, we notate like that. By making such a sequence of declarations, like this, I can wire together an arbitrary circuit. So I've just told you a set of primitives and means of combination for build ing digital circuits, when I need more in a real language than abstraction. And so for example, here I have--here I have a half adder. It's something you all know if you've done any digital design. It's used for adding numbers together on A and B and putting out a sum and a carry. And in fact, the wiring diagram is exactly what I told you. A half adder with things that come out of the box-- you see the box, the boundary, the abstraction is always a box. And there are things that come out of it, A, B, S, a nd C. Those are the declared variables--declared variables of a lambda expression, which is the one that defines half adder. And internal to that, I make up some more wires, D and E, which I'm going to use for the interconnect-- here E is this one and D is this wire, the interconnect that doesn't come through the walls of the box-- and wire things together as you just saw. And the nice thing about this that I've just shown you is this language is hierarchical in the right way. If a language isn't hierarchical in the right way, if it turns out that a compound object doesn't look like a primitive, there's something wrong with the language -- at least the way I feel about that. So here we have--here, instead of starting with mathematical functions, or things that compute mathematical functions, which is what we've been doing up until now, instead of starting with things that look like mathematical functions, or compute such thing s, we are starting with things that are electrical objects and we build up more electrical objects. And the glue we're using is basically the Lisp structure: lambdas. Lambda is the ultimate glue, if you will. And of course, half adder itself can be used in a more complicated abstraction called a full adder, which in fact involves two half adders, as you see here, hooked together with some extra wires, that you see here, S, C1, and C2, and an or-gate, to manufacture a full adder, which takes a input number, another input number, a carry in, and produces output, a sum and a carry out. And out of full adders, you can make real adder chains and big adders. So we have here a language so far that has primitives, means of combination, and means of abstraction to real language. Now, how are we going to implement this? Well, let's do it easily. Let's look at the primitives. The only problem is we have to implement the primitives. Nothing else has to be implemented, because we're picking up the means of combination and abstraction from Lisp, inheriting them in the embedding. OK, so let's look at a particular primitive. An inverter is a nice one. Now, inverter has two wires coming in, an in and an out. And somehow, it's going to have to know what to do when a signal comes in. So somehow it's going to have to tell its input wire -- and now we're going to talk about objects and we're going to see this in a little more detail soon -- but it's going to have to tell its input wire that when you change, tell me. So this object, the object which is the inverter has to tell the object which is the input wire, hi, my name is George. And my, my job is to do something with results when you change. So when you change, you get a change, tell me about it. Because I've got to do something with that. Well, that's done down here by adding an action on the input wire called invert- in, where invert-in is defined over here to be a procedure of no arguments, which gets the logical not of the signal on the input wire. And after some delay,which is the inverter delay, all these electrical objects have delays, we'll do the following thing -- set the signal on the output wire to the new value. A very simple program. Now, you have to imagine that the output wire has to be sensitive and know that when its signal changes, it may have to tell other guys, hey, wake up. My value has changed. So when you hook together inverter with an and-gate or something like that, there has to be a lot of communication going on in order to make sure that the signal propagates right. And down here is nothing very exciting. This is just the definition of logical not for some particular representations of the logical values-- 1, 0 in this case. And we can look at things more complicated like and-gates. And-gates take two inputs, A1 and A2, we'll call them, and produce an output. But the structure of the and -gate is identical to the one we just saw. There's one called an and-action procedure that's defined, which is the thing that gets called when an input is changed. And what it does, of course, is nothing more than compute the logical and of the signals on the inputs. And after some delay, called the and-gate delay, calls this procedure, which sets a signal on the output to a new value. Now, how I implement these things is all wishful thinking. As you see here, I have an assignment operation. It's not set. It's a derived assignment operation in the same way we had functions that were derived from CAR and CDR. So I, by convention, label that with an exclamation point. And over here, you see there's an action, which is to inform the wire, called A1 locally in this and -gate, to call the and-action procedure when it gets changed, and the wire A2 to call the and-action procedure when it gets changed. All very simple. Well, let's talk a little bit about this communication that must occur between these various parts. Suppose, for example, I have a very simple circuit which contains an and with wires A and B. And that connects through a wire called C to an inverter which h as a wire output called D. What are the comput...--here's the physical world. It's an abstraction of the physical world. Now I can buy these out of little pieces that you get at Radio Shack for a few cents. And there are boxes that act like this, which have little numbers on them like LS04 or something. Now supposing I were to try to say what's the computational model. What is the thing that corresponds to that, that part of reality in the mind of us and in the computer? Well, I have to assign for every object in the world an object in the computer, and for every relationship in the world between them a relationship in the computer. That's my goal. So let's do that. Well, I have some sort of thing called the signal, A. This is A. It's a signal. It's a cloudy thing like that. And I have another one down here which I'm going to call B. It's another signal. Now this signal--these two signals are somehow going to have to hook together into a box, let's call it this, which is the and-gate, action procedure. That's the and- gate's action procedure. And it's going to produce--well, it's going to interact with a signal object, which we call C --a wire object, excuse me, we call C. And then the-- this is going to put out again, or connect to, another action procedure which is one associated with the inverter in the world, not. And I'm going to have another--another wire, which we'll call D. So here's my layout of stuff. Now we have to say what's inside them and what they have to know to compute. Well, every--every one of these wires has to know what the value of the signal that's on that wire is. So there's going to be some variable inside here, we'll call it signal. And he owns a value. So there must be some environment associated with this. And for each one of these, there must be an environment that binds signal. And there must be a signal here, therefore. And presumably, signal's a value that's either 1 or 0, and signal. Now, we also have to have some list of people to inform if the signal here changes. We're going to have to inform this. So I've got that list. We'll call it the Action Procedures, AP. And it's presumably a list. But the first thing on the list, in this case, is this guy. And the action procedures of this one happens to have some list of stuff. There might be other people who are sharing A, who are looking at it. So there might be other guys on this list, like somebody over there that we don't know about. It's the other guy attached to A. And the action procedure here also has to point to that, the list of action procedures. And of course, that means this one, its action procedures has to point up to here. This is the things-- the people it has to inform. And this guy has some too. But I don't know what they are because I didn't draw it in my diagram. It's the things connected to D. Now, it's also the case that when the and-action procedure is awakened, saying one of the people who know that you've told--one of the people you've told to wake you up if their signal changes, you have to go look and ask them what's their signal so you can do the and, and produce a signal for this one. So there has to be, for example, information here saying A1, my A1 is this guy, and my A2 is this guy. And not only that, when I do my and, I'm going to have to tell this guy something. So I need an output-- being this guy. And similarly, this guy's going to have a thing called the input that he interrogates to find out what the value of the signal on the input is, when the signal wakes up and says, I've changed, and sends a message this way saying, I've changed. This guy says, OK, what's your value now? When he gets that value, then he's going to have to say, OK, output changes this guy, changes this guy. And so on. And so I have to have at least that much connected-ness. Now, let's go back and look, for example, at the and-gate. Here we are back on this slide. And we can see some of these parts. For any particular and-gate, there is an A1, there is an A2, and the output. And those are, those are an environment that was created at the --those produce a frame at the time and-gate was called, a frame where A1, A2, and output are-- have as their values, they're bound to the wires which, they are--which were passed in. In that environment, I constructed a procedure-- this one right there. And-action procedure was constructed in that environment. That was the result of evaluating a lambda expression. So it hangs onto the frame where these were defined. Local--part of its local state is that. The and-action procedure, therefore, has access to A1, A2, and output as we see here. A1, A2, and output. Now, we haven't looked inside of a wire yet. That's all that remains. Let's look at a wire. Like the overhead, very good. Well, the wire, again, is a, is a somewhat complicated mess. Ooh, wrong one. It's a big complicated mess, like that. But let's look at it in detail and see what's going on. Well, the wire is one of these. And it has to have two things that are part of it, that it's state. One of them is the signal we see here. In other words, when we call make-wire to make a wire, then the first thing we do is we create some variables which are the signal and the action procedures for this wire. And in that context, we define various functions--or procedures, excuse me, procedures. One of them is called set-my-signal to a new value. And what that does is takes a new value in. If that's equal to my current value of my signal, I'm done. Otherwise, I set the signal to the new value and call each of the action procedures that I've been, that I've been--what's the right word?-- introduced to. I get introduced when the and-gate was applied to me. I add action procedure at the bottom. Also, I have to define a way of accepting an action procedure-- which is what you see here-- - which increments my action procedures using set to the result of CONSing up a new process--a procedure, which is passed to me, on to my actions procedures list. And for technical reasons, I have to call that procedure one. So I'm not going to tell you anything about that, that has to do with event-driven simulations and getting them started, which takes a little bit of thinking. And finally, I'm going to define a thing called the dispatcher, which is a wa y of passing a message to a wire, which is going to be used to extract from it various information, like what is the current signal value? What is the method of setting your signal? I want to get that out of it. How do I--how do I add another action procedure? And I'm going to return that dispatch, that procedure as a value. So the wire that I've constructed is a message accepting object which accepts a message like, like what's your method of adding action procedures? In fact, it'll give me a procedure, which is the add action procedure, which I can then apply to an action procedure to create another action procedure in the wire. So that's a permission. So it's given me permission to change your action procedures. And in fact, you can see that over here. Next slide. Ah. This is nothing very interesting. The call each of the action procedures is just a CDRing down a list. And I'm not going to even talk about that anymore. We're too advanced for that. However, if I want to get a signal from a wire, I ask the wire-- which is, what is the wire? The wire is the dispatch returned by creating the wire. It's a procedure. I call that dispatch on the message get- signal. And what I should expect to get is a method of getting a signal. Or actually, I get the signal. If I want to set a signal, I want to change a signal, then what I'm going to do is take a wire as an argument and a new value for the signal, I'm going to ask the wire for permission to set its signal and use that permission, which is a procedure, on the new value. And if we go back to the overhead here, thank you, if we go back to the overhead here, we see that the method-- if I ask for the method of setting the signal, that's over here, it's set-my-signal, a procedure that's defined inside the wire, which if we look over here is the thing that says set my internal value called the signal, my internal variable, which is the signal, to the new value, which is passed to me as an argument, and then call each of the action procedures waking them up. Very simple. Going back to that slide, we also have the one last thing-- which I suppose now you can easily work out for yourself-- is the way you add an action. You take a wire--a wire and an action procedure. And I ask the wire for permission to add an action. Getting that permission, I use that permission to give it an action procedure. So that's a real object. There's a few more details about this. For example, how am I going to control this thing? How do I do these delays? Let's look at that for a second. The next one here. Let's see. We know when we looked at the and-gate or the not-gate that when a signal changed on the input, there was a delay. And then it was going to call the procedure, which was going to change the output. Well, how are we going to do this? We're going to make up some mechanism, a fairly complicated mechanism at that, which we're going to have to be very careful about. But after a delay, we're going to do an action. A delay is a number, and an action is a procedure. What that's going to be is they're going to have a special structure called an agenda, which is a thing that organizes time and actions. And we're going to see that in a while. I don't want to get into that right now. But the agenda has a moment at which--at which something happens. We're setting up for later at some moment, which is the sum of the time, which is the delay time plus the current time, which the agenda thinks is now. We're going to set up to do this action, and add that to the agenda. And the way this machine will now run is very simple. We have a thing called propagate, which is the way things run. If the agenda is empty, we're done--if there's nothing more to be done. Otherwise, we're going to take the first item off the agenda, and that's a procedure of no arguments. So that we're going to see extra parentheses here. We call that on no arguments. That takes the action. Then we remove that first item from the agenda, and we go around the propagation loop. So that's the overall structure of this thing. Now, there's a, a few other things we can look at. And then we're going to look into the agenda a little while from now. Now the overhead again. Well, in order to set this thing going, I just want to show you some behavior out of this simulator. By the way, you may think this simulator is very simple, and probably too simple to be useful. The fact of the matter is that this simulator has been used to manufacture a fairly large computer. So this is a real live example. Actually, not exactly this simulator, because I'll tell you the difference. The difference is that there were many more different kinds of primitives. There's not just the word inverter or and-gate. There were things like edge-triggered, flip-flops, and latches, transparent latches, and adders, and things like that. And the difficulty with that is that there's pages and pages of the definitions of all these primitives with numbers like LS04. And then there's many more parameters for them. It's not just one delay. There's things like set up times and hold times and all that. But with the exception of that part of the complexity, the structure of the simulator that we use for building a real computer, that works is exactly what you're seeing here. Well in any case, what we have here is a few simple things. Like, there's inverter delays being set up and making a new agenda. And then we can make some inputs. There's input- 1, input-2, a sum and a carry, which are wires. I'm going to put a special kind of object called a probe onto, onto some of the wires, onto sum and onto carry. A probe is a, can object that has the property that when you change a wire it's attached to, it types out a message. It's an easy thing to do. And then once we have that, of course, the way you put the probe on, the first thing it does, it says, the current value of the sum at time 0 is 0 because I just noticed it. And the value of the carry at time 0, this is the time, is 0. And then we go off and we build some structure. Like, we can build a structure here that says you have a half -adder on input-1, input-2, sum, and carry. And we're going to set the signal on input -1 to 1. We do some propagation. At time 8, which you could see going through this thing if you wanted to, the new value of sum became 1. And the thing says I'm done. That wasn't very interesting. But we can send it some more signals. Like, we set-signal on input-2 to be one. And at that time if we propagate, then it carried at 11, the carry becomes 1, and at 16, the sum's new value becomes 0. And you might want to work out that, if you like, about the digital circuitry. It's true, and it works. And it's not very interesting. But that's the kind of behavior we get out of this thing. So what I've shown you right now is a large-scale picture, how you, at a bigger, big scale, you implement an event-driven simulation of some sort. And how you might organize it to have nice hierarchical structure allowing you to build abstract boxes that you can instantiate. But I haven't told you any of the details about how this agenda and things like that work. That we'll do next. And that's going to involve change and mutation of data and things like that. Are there any questions now, before I go on? Thank you. Let's take a break. Well, we've been making a simulation. And the simulation is an event -driven simulation where the objects in the world are the objects in the computer. And the changes of state that are happening in the world in time are organized to be time in the computer, so that if something happens after something else in the world, then we have it happen after, after the corresponding events happen in the same order inthe computer. That's where we have assignments, when we make that alignment. Right now I want to show you a way of organizing time, which is an agenda or priority queue, it's sometimes called. We'll do some --we'll do a little bit of just understanding what are the things we need to be able to do to make agendas. And so we're going to have--and so right now over here, I'm going to write down a bunch of primitive operations for manipulating agendas. I'm not going to show you the code for them because they' re all very simple, and you've got listings of all that anyway. So what do we have? We have things like make-agenda which produces a new agenda. We can ask--we get the current-time of an agenda, which gives me a number, a time. We can get--we can ask whether an agenda is empty, empty-agenda. And that produces either a true or a false. We can add an object to an agenda. Actually, what we add to an agenda is an operation--an action to be done. And that takes a time, the action itself, and the agenda I want to add it to. That inserts it in the appropriate place in the agenda. I can get the first item off an agenda, the first thing I have to do, which is going to give me an action. And I can remove the first item from an agenda. That's what I have to be able to do with agendas. That is a big complicated mess. From an agenda. Well, let's see how we can organize this thing as a data structure a bit. Well, an agenda is going to be some kind of list. And it's going to be a list that I'm going to have to be able to modify. So we have to talk about modifying of lists, because I'm going to add things to it, and delete things from it, and things like that. It's organized by time. It's probably good to keep it in sorted order. But sometimes there are lots of things that happen at the same time--approximate same time. What I have to do is say, group things by the time at which they're supposed to happen. So I'm going to make an agenda as a list of segments. And so I'm going to draw you a data structure for an agenda, a perfectly reasonable one. Here's an agenda. It's a thing that begins with a name. I'm going to do it right now out of list structure. It's got a header. There's a reason for the header. We're going to see the reason soon. And it will have a segment. It will have--it will be a list of segments. Supposing this agenda has two segments, they're the car's-- successive car's of this list. Each segment is going to have a time-- say for example, 10-- that says that the things that happen in this segment are at time 10. And what I'm going to have in here is another data structure which I'm not going to describe, which is a queue of things to do at time 10. It's a queue. And we'll talk about that in a second. But abstractly, the queue is just a list of things to do at a particular time. And I can add things to a queue. This is a queue. There's a time, there's a segment. Now, I may have another segment in this agenda. Supposing this is stuff that happens at time 30. It has, of course, another queue of things that are queued up to be done at time 30. Well, there are various things I have to be able to do to an agenda. Supposing I want to add to an agenda another thing to be done at time 10. Well, that's not very hard. I'm going to walk down here, looking for the segment of time 10. It is possible that there is no segment of time 10. We'll cover that case in a second. But if I find a segment of time 10, then if I want to add another thing to be done at time 10, I just increase that queue-- "just increase" isn't such an obvious idea. But I increase the things to be done at that time. Now, supposing I want to add something to be done at time 20. There is no segment for time 20. I'm going to have to create a new segment. I want my time 20 segment to exist between time 10 and time 30. Well, that takes a little work. I'm going to have to do a CONS. I'm going to have to make a new element of the agenda list--list of segments. I'm going to have to change. Here's change. I'm going to have to change the CDR of the CDR of the agenda to point that a new CONS of the new segment and the CDR of the CDR of the CDR of the agenda, the CD-D-D-DR. And this is going to have a new segment now of time 20 with its own queue, which now has one element in it. If I wanted to add something at the end, I'm going to have to replace the CDR of this, of this list with something. We're going to have to change that piece of data structure. So I'm going to need new primitives for doing this. But I'm just showing you why I need them. And finally, if I wanted to add a thing to be done at time 5, I'm going to have to change this one, because I'm going to have to add it in over here, which is why I planned ahead and had a header cell, which has a place. If I'm going to change things, I have to have places for the change. I have to have a place to make the change. If I remove things from the agenda, that's not so hard. Removing them from the beginning is pretty easy, which is the only case I have. I can go looking for the first, the first segment. I see if it has a non-empty queue. If it has a non-empty queue, well, I'm going to delete one element from the queue, like that. If the queue ever becomes empty, then I have to delete the whole segment. And then this, this changes to point to here. So it's quite a complicated data structure manipulation going on, the details of which are not really very exciting. Now, let's talk about queues. They're similar. Because each of these agendas has a queue in it. What's a queue? A queue is going to have the following primitive operations. To make a queue, this gives me a new queue. I'm going to have to be able to insert into a queue a new item. I'm going to have to be able to delete from a queue the first item in the queue. And I want to be able to get the first thing in the queue from some queue. I also have to be able to test whether a queue is empty. And when you invent things like this, I want you to be very careful to use the kinds of conventions I use for naming things. Notice that I'm careful to say these change something and that tests it. And presumably, I did the same thing over here. OK, and there should be an empty test over here. OK, well, how would I make a queue? A queue wants to be something I can add to at the end of, and pick up the thing at the beginning of. I should be able to delete from the beginning and add to the end. Well, I'm going to show you a very simple structure for that. We can make this out of CONSes as well. Here's a queue. It has--it has a queue header, which contains two parts-- a front pointer and a rear pointer. And here I have a queue with two items in it. The first item, I don't know, it's perhaps a 1. And the second item, I don't know, let's give it a 2. The reason why I want two pointers in here, a front pointer and a rear pointer, is so I can add to the end without having to chase down from the beginning. So for example, if I wanted to add one more item to this queue, if I want to add on another item to be worried about later, all I have to do is make a CONS, which contains that item, say a 3. That's for inserting 3 into the queue. Then I have to change this pointer here to here. And I have to change this one to point to the new rear. If I wish to take the first element of the queue, the first item, I just go chasing down the front pointer until I find the first one and pick it up. If I wish to delete the first item from the queue, delete-queue, all I do is move the front pointer along this way. The new front of the queue is now this. So queues are very simple too. So what you see now is that I need a certain number of new primitive operations. And I'm going to give them some names. And then we're going to look into how they work, and how they're used. We have set the CAR of some pair, or a thing produced by CONSing, to a new value. And set the CDR of a pair to a new value. And then we're going to look into how they work. I needed setting CAR over here to delete the first element of the queue. Thisis the CAR, and I had to set it. I had to be able to set the CDR to be able to move the rear pointer, or to be able to increment the queue here. All of the operations I did were made out of those that I just showed you on the, on the last blackboard. Good. Let's pause the time, and take a little break then. When we originally introduced pairs made out of CONS, made by CONS, we only said a few axioms about them, which were of the form-- what were they-- for all X and Y, the CAR of the CONS of X and Y is X and the CDR of the CONS of X and Y is Y. Now, these say nothing about whether a CONS has an identity like a person. In fact, all they say is something sort of abstract, that a CONS is the parts it's made out of. And of course, two things are made out of the same parts, they're the same, at least from the point of view of these axioms. But by introducing assignment-- in fact, mutable data is a kind of assignment, we have a set CAR and a set CDR-- by introducing those, these axioms no longer tell the whole story. And they're still true if written exactly like this. But they don't tell the whole story. Because if I'm going to set a particular CAR in a particular CONS, the questions are, well, is that setting all CARs and all CONSes of the same two things or not? If I--if we use CONSes to make up things like rational numbers, or things like 3 over 4, supposing I had two three - fourths. Are they the same one-- or are they different? Well, in the case of numbers, it doesn't matter. Because there's no meaning to changing the denominator of a number. What you could do is make a number which has a different denominator. But the concept of changing a number which has to have a different denominator is sort of a very weird, and sort of not supported by what you think of as mathematics. However, when these CONSes represent things in the physical world, then changing something like the CAR is like removing a piece of the fingernail. And so CONSes have an identity. Let me show you what I mean about identity, first of all. Let's do some little example here. Supposing I define A to the CONS of 1 and 2. Well, what that means, first of all, is that somewhere in some environment I've made a symbol A to have a value which is a pair consisting of pointers to a 1 and a pointer to a 2, just like that. Now, supposing I also say define B to be the CONS-- it doesn't matter, but I like it better, it's prettier-- of A and A. Well, first of all, I'm using the name A twice. At this moment, I'm going to think of CONSes as having identity. This is the same one. And so what that means is I make another pair, which I'm going to call B. And it contains two pointers to A. At this point, I have three names for this object. A is its name. The CAR of B is its name. And the CDR of B is its name. It has several aliases, they're called. Now, supposing I do something like set-the-CAR, the CAR of the CAR of B to 3. What that means is I find the CAR of B, that's this. I set the CAR of that to be 3, changing this. I've changed A. If I were to ask what's the CAR of A--of A now? I would get out 3, even though here we see that A was the CONS of 1 and 2. I caused A to change by changing B. There is sharing here. That's sometimes what we want. Surely in the queues and things like that, that's exactly what we defined our--organized our data structures to facilitate-- sharing. But inadvertent sharing, unanticipated interactions between objects, is the source of most of the bugs that occur in complicated programs. So by introducing this possibility of things having identity and sharing and having multiple names for the same thing, we get a lot of power. But we're going to pay for it with lots of complexity and bugs. So also, for example, if I just looked at this just to drive that home, the CADR of B, which has nothing to do with even the CAR of B, apparently. The CADR of B, what's that? Take that CDR of B and now take the CAR of that. Oh, that's 3 also. So I can have non-local interactions by sharing. And I have to be very careful of that. Well, so far, of course, it seems I've introduced several different assignment operators-- set, set CAR, set CDR. Well, maybe I should just get rid of set CAR and set CDR. Maybe they're not worthwhile. Well, the answer is that once you let the camel's nose into the tent, the rest of him follows. All I have to have is set, and I can make all of the --all of the bad things that can happen. Let's play with that a little bit. A couple of days ago, when we introduced compound data, you saw Hal show you a definition of CONS in terms of a message acceptor. I'm going to show you even a more horrible thing, a definition of CONS in terms of nothing but air, hot air. What is the definition of CONS, of the old functional kind, in terms of purely lambdic expressions, procedures? Because I'm going to then modify this definition to get assignment to be only one kind of assignment, to get rid of the set CAR and set CDR in terms of set. So what if I define CONS of X and Y to be a procedure of one argument called a message M, which calls that message on X and Y? This [? idea ?] was invented by Alonzo Church, who was the greatest programmer of the 20th century, although he never saw a computer. It was done in the 1930s. He was a logician, I suppose at Princeton at the time. Define CAR of X to be the result of applying X to that procedure of two arguments, A and D, which selects A. I will define CDR of X to be that procedure, to be the result of applying X to that procedure of A and D, which selects D. Now, you may not recognize this as CAR, CDR, and CONS. But I'm going to demonstrate to you that it satisfies the original axioms, just once. And then we're going to do some playing of games. Consider the problem CAR of CONS of, say, 35 and 47. Well, what is that? It is the result of taking car of the result of substituting 35 and 47 for X and Y in the body of this. Well, that's easy enough. That's CAR of the result of substituting into lambda of M, M of 35 and 47. Well, what this is, is the result of substituting this object for X in the body of that. So that's just lambda of M-- that's substituted, because this object is being substituted for X, which is the beginning of a list, lambda of M-- M of 35 and 47, applied to that procedure of A and D, which gives me A. Well, that's the result of substituting this for M here. So that's the same thing as lambda of A, D, A, applied to 35 and 47. Oh, well that's 35. That's substituting 35 for A and for 47 for D in A. So I don't need any data at all, not even numbers. This is Alonso Church's hack. Well, now we're going to do something nasty to him. Being a logician, he wouldn't like this. But as programmers, let's look at the overhead. And here we go. I'm going to change the definition of CONS. It's almost the same as Alonzo Church's, but not quite. What do we have here? The CONS of two arguments, X and Y, is going to be that procedure of one argument M, which supplies M to X and Y as before, but also to two permissions, the permission to set X to N and the permission to set Y to N, given that I have an N. So besides the things that I had here in Church's definition, what I have is that the thing that CONS returns will apply its argument to not just the values of the X and Y that the CONS is made of, but also permissions to set X and Y to new values. Now, of course, just as before, CAR is exactly the same. The CAR of X is nothing more than applying X, as in Church's definition, to a procedure, in this case, of four arguments, which selects out the first one. And just as we did before, that will be the value of X that was contained in the procedure which is the result of evaluating this lambda expression in the environment where X and Y are defined over here. That's the value of CONS. Now, however, the exciting part. CDR, of course, is the same. The exciting part, set CAR and set CDR. Well, they're nothing very complicated anymore. Set CAR of a CONS X to a new value Y is nothing more than applying that CONS, which is the procedure of four--the procedure of one argument which applies its argument to four things, to a procedure which is of four arguments-- the value of X, the value of Y, permission to set X, the permission to set Y-- and using it--using that permission to set X to the new value. And similarly, set-cdr is the same thing. So what you've just seen is that I didn't introduce any new primitives at all. Whether or not I want to implement it this way is a matter of engineering. And the answer is of course I don't implement it this way for reasons that have to do with engineering. However in principle, logically, once I introduced one assignment operator, I've assigned--I've introduced them all. Are there any questions? Yes, David. AUDIENCE: I can follow you up until you get--I can follow all of that. But when we bring in the permissions, defining CONS in terms of the lambda N, I don't follow where N gets passed. PROFESSOR: Oh, I'm sorry. I'll show you. Let's follow it. Of course, we could do it on the blackboard. It's not so hard. But it's also easy here. Supposing I wish to set-cdr of X to Y. See that right there. set-cdr of X to Y. X is presumably a CONS, a thing resulting from evaluating CONS. Therefore X comes from a place over here, that that X is of the result of evaluating this lambda expression. Right? That when I evaluated that lambda expression, I evaluated it in an environment where the arguments to CONS were defined. That means that as free variables in this lambda expression, there is the--there are in the frame, which is the parent frame of this lambda expression, the procedure resulting from this lambda expression, X and Y have places. And it's possible to set them. I set them to an N, which is the argument of the permission. The permission is a procedure which is passed to M, which is the argument that the CONS object gets passed. Now, let's go back here in the set-cdr The CONS object, which is the first argument of set- cdr gets passed an argument. That--there's a procedure of four things, indeed, because that's the same thing as this M over here, which is applied to four objects. The object over here, SD, is, in fact, this permission. When I use SD, I apply it to Y, right there. So that comes from this. AUDIENCE: So what do you-- PROFESSOR: So to finish that, the N that was here is the Y which is here. How's that? AUDIENCE: Right, OK. Now, when you do a set-cdr, X is the value the CDR is going to become. PROFESSOR: The X over here. I'm sorry, that's not true. The X is--set-cdr has two arguments-- The CONS I'm changing and the value I'm changing it to. So you have them backwards, that's all. Are there any other questions? Well, thank you. It's time for lunc h. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec6a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 6A: Streams, Part 1 1 00:00:00,000 --> 00:00:18,550 2 00:00:18,550 --> 00:00:21,230 教授:好的,上次Gerry教授揭晓了秘密。 PROFESSOR: Well, last time Gerry really let the cat out 3 00:00:21,230 --> 00:00:22,230 of the bag. 4 00:00:22,230 --> 00:00:26,350 他介绍赋值这个概念。 He introduced the idea of assignment. 5 00:00:26,350 --> 00:00:33,405 赋值和状态。 Assignment and state. 6 00:00:33,405 --> 00:00:37,620 7 00:00:37,620 --> 00:00:41,500 就像我们看到的那样,把赋值和状态介绍 And as we started to see, the implications of introducing 8 00:00:41,500 --> 00:00:43,860 进语言的含义是绝对惊世骇俗的 assignment and state into the language are absolutely 9 00:00:43,860 --> 00:00:45,350 frightening. 10 00:00:45,350 --> 00:00:47,240 首先,计算的替换模型无法工作 First of all, the substitution model of 11 00:00:47,240 --> 00:00:48,865 evaluation breaks down. 12 00:00:48,865 --> 00:00:52,210 我们就不得不使用更加复杂的环境模型 And we have to use this much more complicated environment 13 00:00:52,210 --> 00:00:53,780 和这种带图解的机械化东西 model and this very mechanistic thing with 14 00:00:53,780 --> 00:00:56,530 甚至说明了声明在编程语言中的意思 diagrams, even to say what statements in the programming 15 00:00:56,530 --> 00:00:58,130 language mean. 16 00:00:58,130 --> 00:01:00,260 那不仅仅是技术上的一点 And that's not a mere technical point. 17 00:01:00,260 --> 00:01:03,090 看 我们没有这样特定的替换模型 See, it's not that we had this particular substitution model 18 00:01:03,090 --> 00:01:05,200 并且 这不能完全工作 and, well, it doesn't quite work, so we have to do 19 00:01:05,200 --> 00:01:05,870 所以我们不得不做些别的 something else. 20 00:01:05,870 --> 00:01:10,730 替换模型啥都不能做 It's that nothing like the substitution model can work. 21 00:01:10,730 --> 00:01:15,950 因为突然地,一个变量无法代表一个值 Because suddenly, a variable is not just something that 22 00:01:15,950 --> 00:01:18,080 stands for a value. 23 00:01:18,080 --> 00:01:22,390 一个变量现在不得不以某种方法来指定一个位置来存放一个值 A variable now has to somehow specify a place 24 00:01:22,390 --> 00:01:23,630 that holds a value. 25 00:01:23,630 --> 00:01:25,885 在那个地方的值可以改变 And the value that's in that place can change. 26 00:01:25,885 --> 00:01:30,280 27 00:01:30,280 --> 00:01:39,110 或者举个例子,,一个类似fx的表达式可能有副作用 Or for instance, an expression like f of x might have a side 28 00:01:39,110 --> 00:01:40,410 effect in it. 29 00:01:40,410 --> 00:01:44,160 所以如果我们说f(x)可以得到某些值 So if we say f of x and it has some value, and then later we 30 00:01:44,160 --> 00:01:48,890 那么然后 我们再求一次f(x)可能会得到一个取决于顺序的不同结果 say f of x again, we might get a different value 31 00:01:48,890 --> 00:01:49,730 depending on the order. 32 00:01:49,730 --> 00:01:52,780 所以 突然地 我们不但需要想到值,还要想的时间 So suddenly, we have to think not only about values but 33 00:01:52,780 --> 00:01:54,030 about time. 34 00:01:54,030 --> 00:01:57,970 35 00:01:57,970 --> 00:02:02,070 并且 像序对这样的东西,已经不再是它们的cars And then things like pairs are no longer just their CARs and 36 00:02:02,070 --> 00:02:02,520 和cdrs了 their CDRs. 37 00:02:02,520 --> 00:02:06,310 一个序对现在不仅仅是它的car和cdr了 A pair now is not quite its CAR and its CDR. It's rather 38 00:02:06,310 --> 00:02:08,449 而是它的“同一” its identity. 39 00:02:08,449 --> 00:02:11,650 所以一个序对有“同一” So a pair has identity. 40 00:02:11,650 --> 00:02:12,900 这是一个对象 It's an object. 41 00:02:12,900 --> 00:02:21,330 42 00:02:21,330 --> 00:02:26,280 两个有相同car和cdr的序列可能相同或不同 And two pairs that have the same CAR and CDR might be the 43 00:02:26,280 --> 00:02:29,650 因为 突然地 我们不得不担心“共享” same or different, because suddenly we have to worry 44 00:02:29,650 --> 00:02:30,900 about sharing. 45 00:02:30,900 --> 00:02:34,960 46 00:02:34,960 --> 00:02:38,910 所以所有的这些东西和赋值一起被介绍 So all of these things enter as soon as we introduce 47 00:02:38,910 --> 00:02:40,480 assignment. 48 00:02:40,480 --> 00:02:43,340 这和我们说代换的时候差别悬殊 See, this is a really far cry from where we started with 49 00:02:43,340 --> 00:02:45,400 substitution. 50 00:02:45,400 --> 00:02:50,420 这是在技术上更加困难的一种看待事情的方法 It's a technically harder way of looking at things because 51 00:02:50,420 --> 00:02:52,710 因为 我们不得不更加机械地思考我们的程序语言 we have to think more mechanistically about our 52 00:02:52,710 --> 00:02:53,540 programming language. 53 00:02:53,540 --> 00:02:55,960 我们不能仅仅的用数学来思考它。 We can't just think about it as mathematics. 54 00:02:55,960 --> 00:02:59,860 这在哲学上更加困难 因为突然 这里会出现一些 It's philosophically harder, because suddenly there are all 55 00:02:59,860 --> 00:03:02,020 搞笑的问题 关于一些东西改变或者这两个东西是一样的是什么意思 these funny issues about what does it mean that something 56 00:03:02,020 --> 00:03:04,050 changes or that two things are the same. 57 00:03:04,050 --> 00:03:07,910 并且 这在编程上更加困难 And also, it's programming harder, because as Gerry 58 00:03:07,910 --> 00:03:10,070 因为就像Gerry上次展示的那样 showed last time, there are all these bugs having to do 59 00:03:10,070 --> 00:03:14,420 在一种我们不用担心对象的语言中不存在 那些由别名和坏的顺序造成的bugs with bad sequencing and aliasing that just don't exist 60 00:03:14,420 --> 00:03:18,210 in a language where we don't worry about objects. 61 00:03:18,210 --> 00:03:23,635 我们是怎样陷入这样的困境呢 Well, how'd we get into this mess? 62 00:03:23,635 --> 00:03:27,500 记住我们以前做的 我们陷入困境的原因是 Remember what we did, the reason we got into this is 63 00:03:27,500 --> 00:03:35,750 因为我们想要去建造模块化的系统 because we were looking to build modular systems. We 64 00:03:35,750 --> 00:03:40,250 我们想要建造一个看起来自然崩碎的数据块 wanted to build systems that fall apart into chunks that 65 00:03:40,250 --> 00:03:42,760 seem natural. 66 00:03:42,760 --> 00:03:46,260 举个例子 我们想要拿一个随机数生成器 So for instance, we want to take a random number generator 67 00:03:46,260 --> 00:03:48,660 并打包那个随机数生成器的状态 and package up the state of that random number generator 68 00:03:48,660 --> 00:03:52,840 我们可以把用蒙特卡罗方法生成随机数 inside of it so that we can separate the idea of picking 69 00:03:52,840 --> 00:03:56,640 的计算过程和随机数按照 random numbers from the general Monte Carlo strategy 70 00:03:56,640 --> 00:03:59,740 cesaro的公式计算pi的计算过程分离开 of estimating something and separate that from the 71 00:03:59,740 --> 00:04:03,060 particular way that you work with random numbers in that 72 00:04:03,060 --> 00:04:06,980 formula developed by Cesaro for pi. 73 00:04:06,980 --> 00:04:11,400 相似的 当我们动身去构建一些东西的模型 And similarly, when we go off and construct some models of 74 00:04:11,400 --> 00:04:15,440 如果我们动身去构建一个我们在现实看到的系统模型 things, if we go off and model a system that we see in the 75 00:04:15,440 --> 00:04:19,050 我们想要把我们的程序分散为自然的元件 real world, we'd like our program to break into natural 76 00:04:19,050 --> 00:04:22,310 来反映我们在真实世界看到的系统的部分 pieces, pieces that mirror the parts of the system that we 77 00:04:22,310 --> 00:04:24,900 see in the real world. 78 00:04:24,900 --> 00:04:28,780 所以举一个例子 如果我们看一下这个电子电路 So for example, if we look at a digital circuit, we say, 79 00:04:28,780 --> 00:04:33,910 我们可以说 挖 这里有一个电路 它这里有一个元件 gee, there's a circuit and it has a piece and 80 00:04:33,910 --> 00:04:35,160 并且那里还有一个另一个元件 it has another piece. 81 00:04:35,160 --> 00:04:40,100 82 00:04:40,100 --> 00:04:43,580 这些不同的元件在某种程度上有“同一” And these different pieces sort of have identity. 83 00:04:43,580 --> 00:04:45,550 它们有状态 They have state. 84 00:04:45,550 --> 00:04:48,580 状态附在电线上 And the state sits on these wires. 85 00:04:48,580 --> 00:04:51,020 我们把这个元件看成一个不同于其他对象的对象 And we think of this piece as an object that's different 86 00:04:51,020 --> 00:04:52,610 from that as an object. 87 00:04:52,610 --> 00:04:54,400 当我们看到系统改变时 And when we watch the system change, we think about a 88 00:04:54,400 --> 00:04:57,500 我们想着 信号从这里过来 并且可能在这里改变了一个状态 signal coming in here and changing a state that might be 89 00:04:57,500 --> 00:04:59,860 并且到了这里 与一个可能储存在这里的状态相互作用 here and going here and interacting with a state that 90 00:04:59,860 --> 00:05:02,170 等等等等 might be stored there, and so on and so on. 91 00:05:02,170 --> 00:05:06,860 92 00:05:06,860 --> 00:05:12,760 所以我们想要做的是 我们想要建立一个分散为许多元件的计算机系统来映射我们对现实的观念 So what we'd like is we'd like to build in the computer 93 00:05:12,760 --> 00:05:17,340 systems that fall into pieces that mirror our view of 94 00:05:17,340 --> 00:05:19,870 我们构造的真实系统看起来变为许多元件 reality, of the way that the actual systems we're modeling 95 00:05:19,870 --> 00:05:23,365 seem to fall into pieces. 96 00:05:23,365 --> 00:05:28,970 好吧 可能像这样构建系统的原因 Well, maybe the reason that building systems like this 97 00:05:28,970 --> 00:05:31,600 看起来介绍如此复杂的科技对计算机没有用 seems to introduce such technical complications has 98 00:05:31,600 --> 00:05:33,610 nothing to do with computers. 99 00:05:33,610 --> 00:05:37,960 看,或许我们付出了这样的代价去写我们对现实的反映程序 See, maybe the real reason that we pay such a price to 100 00:05:37,960 --> 00:05:41,910 是我们有对现实错误的理解 write programs that mirror our view of reality is that we 101 00:05:41,910 --> 00:05:44,550 have the wrong view of reality. 102 00:05:44,550 --> 00:05:47,460 看 或许时间仅仅是错觉 See, maybe time is just an illusion, and 103 00:05:47,460 --> 00:05:50,150 什么东西都没有改变 nothing ever changes. 104 00:05:50,150 --> 00:05:52,910 看 打个比方 如果我拿起这支粉笔,然后说 See, for example, if I take this chalk, and we say, gee, 105 00:05:52,910 --> 00:05:55,820 挖 这是一个对象 并且它有状态 this is an object and it has a state. 106 00:05:55,820 --> 00:05:59,710 在每个时刻 它有位置和速度 At each moment it has a position and a velocity. 107 00:05:59,710 --> 00:06:01,240 如果我们对它做了一些事情 它的状态就会改变 And if we do something, that state can change. 108 00:06:01,240 --> 00:06:04,340 109 00:06:04,340 --> 00:06:07,900 但是如果你学习过相对论 比如 But if you studied any relativity, for instance, you 110 00:06:07,900 --> 00:06:09,760 你知道 你不会认为粉笔的路径如同某些东西 know that you don't think of the path of that chalk as 111 00:06:09,760 --> 00:06:11,340 随着时间运动 something that goes on instant by instant. 112 00:06:11,340 --> 00:06:13,870 把整个粉笔的存在性作为时空中的路径是很有见解的 It's more insightful to think of that whole chalk's 113 00:06:13,870 --> 00:06:16,020 existence as a path in space-time. 114 00:06:16,020 --> 00:06:18,040 那全部张开了 that's all splayed out. 115 00:06:18,040 --> 00:06:19,840 这里没有单体的位置和速度 There aren't individual positions and velocities. 116 00:06:19,840 --> 00:06:24,640 这里仅仅是 在时空中它们的不变的存在性 There's just its unchanging existence in space-time. 117 00:06:24,640 --> 00:06:28,080 相似的,如果我们看这些电子系统 Similarly, if we look at this electrical system, if we 118 00:06:28,080 --> 00:06:32,450 如果我们想象这些电子系统是一个实现一些类似信号处理系统 imagine this electrical system is implementing some sort of 119 00:06:32,450 --> 00:06:35,730 把这些东西放在一起的信号处理工程师 signal processing system, the signal processing engineer who 120 00:06:35,730 --> 00:06:39,010 不这样想 put that thing together doesn't think of it as, well, 121 00:06:39,010 --> 00:06:41,490 好吧 在每个瞬间 这里有电压过来 at each instance there's a voltage coming in. 122 00:06:41,490 --> 00:06:43,340 并且转换成了某些东西 And that translates into something. 123 00:06:43,340 --> 00:06:46,400 这在这里影响了状态,在这里改变了状态 And that affects the state over here, which changes the 124 00:06:46,400 --> 00:06:46,810 state over here. 125 00:06:46,810 --> 00:06:49,060 把信号处理系统放在一起的人中没有人会这么想 Nobody putting together a signal processing system 126 00:06:49,060 --> 00:06:50,420 thinks about it like that. 127 00:06:50,420 --> 00:06:56,830 作为代替 你说这里有信号在时间上伸展 Instead, you say there's this signal that's 128 00:06:56,830 --> 00:06:58,060 splayed out over time. 129 00:06:58,060 --> 00:07:01,100 如果 这表现的像filter 这整个东西 And if this is acting as a filter, this whole thing 130 00:07:01,100 --> 00:07:09,570 转换了这整个东西为了一些其他的输出 transforms this whole thing for some sort of other output. 131 00:07:09,570 --> 00:07:11,790 你不会把它想成状态随着时间的变化 You don't think of it as what's happening instant by 132 00:07:11,790 --> 00:07:14,160 instant as the state of these things. 133 00:07:14,160 --> 00:07:17,990 以某种方式 你把这个盒子做为一整个东西 And somehow you think of this box as a whole thing, not as 134 00:07:17,990 --> 00:07:20,980 而不是一个个在某个特定时刻互相传递状态的元件 little pieces sending messages of state to each other at 135 00:07:20,980 --> 00:07:22,230 particular instants. 136 00:07:22,230 --> 00:07:28,250 137 00:07:28,250 --> 00:07:30,130 现在 我们准备用另一种比思考交流传递信息的物体更加像信号处理工程师看待世界的方式去分解系统 Well, today we're going to look at another way to 138 00:07:30,130 --> 00:07:34,260 decompose systems that's more like the signal processing 139 00:07:34,260 --> 00:07:37,050 engineer's view of the world than it is like thinking about 140 00:07:37,050 --> 00:07:41,130 objects that communicate sending messages. 141 00:07:41,130 --> 00:07:43,310 那个被叫做流处理 That's called stream processing. 142 00:07:43,310 --> 00:07:54,570 143 00:07:54,570 --> 00:08:01,790 我们打算开始展示我们如何编写更加均匀的程序 And we're going to start by showing how we can make our 144 00:08:01,790 --> 00:08:08,550 并且看更多的共性 programs more uniform and see a lot more commonality if we 145 00:08:08,550 --> 00:08:12,490 如果我们抛出这些程序 throw out of these programs what you might say is an 146 00:08:12,490 --> 00:08:17,210 你们可能说的是对时间的过度关心 inordinate concern with worrying about time. 147 00:08:17,210 --> 00:08:19,910 让我们用对比两个过程来开始 Let me start by comparing two procedures. 148 00:08:19,910 --> 00:08:23,260 149 00:08:23,260 --> 00:08:25,690 第一个做了这些 The first one does this. 150 00:08:25,690 --> 00:08:27,770 我们想象这里有棵树 We imagine that there's a tree. 151 00:08:27,770 --> 00:08:30,400 152 00:08:30,400 --> 00:08:33,179 假定这是一个整数的树 Say there's a tree of integers. 153 00:08:33,179 --> 00:08:34,429 这是一个二叉树 It's a binary tree. 154 00:08:34,429 --> 00:08:39,100 155 00:08:39,100 --> 00:08:40,230 所以这长得像这样 So it looks like this. 156 00:08:40,230 --> 00:08:44,990 并且 在每个树的节点上有整数 And there's integers in each of the nodes. 157 00:08:44,990 --> 00:08:51,000 我们将要计算的事 对于每个在这里的奇数 And what we would like to compute is for each odd number 158 00:08:51,000 --> 00:08:54,210 我们想要得到它们的平方 然后再得到它们基于平方的和 sitting here, we'd like to find the square and then sum 159 00:08:54,210 --> 00:08:57,210 up all those squares. 160 00:08:57,210 --> 00:08:59,480 好吧 那应该是很常见的东西 Well, that should be a familiar kind of thing. 161 00:08:59,480 --> 00:09:02,930 做这个我们有一个递归策略 There's a recursive strategy for doing it. 162 00:09:02,930 --> 00:09:04,880 我们看每个叶子 We look at each leaf, and either it's going to 163 00:09:04,880 --> 00:09:06,690 它们要么贡献数字的平方 contribute the square of the number if it's odd 164 00:09:06,690 --> 00:09:08,680 如果它是奇数或者 如果是偶数那么就是0 or 0 if it's even. 165 00:09:08,680 --> 00:09:13,280 然后做递归,我们可以说在每个树上 And then recursively, we can say at each tree, the sum of 166 00:09:13,280 --> 00:09:15,330 所有东西的和是从右括号到左括号 all of them is the sum coming from the right branch and the 167 00:09:15,330 --> 00:09:17,640 然后随着叶的节点向下递归 left branch, and recursively down through the nodes. 168 00:09:17,640 --> 00:09:20,360 这是一个很常见的方法去思考编程 And that's a familiar way of thinking about programming. 169 00:09:20,360 --> 00:09:23,960 让我们看一下课件 Let's actually look at that on the slide. 170 00:09:23,960 --> 00:09:27,960 我们说 在树上求奇数平方的和 好吧 We say to sum the odd squares in a tree, well, there's a 171 00:09:27,960 -—> 00:09:30,520 这里有一个测试 要么这是叶节点 并且我们将要去检查 看看它是不是整数 test. Either it's a leaf node, and we're going to check to 172 00:09:30,520 --> 00:09:34,710 然后要么这是奇数 我们把它平方 要么就是0 see if it's an integer, and then either it's odd, in which 173 00:09:34,710 --> 00:09:37,160 we take the square, or else it's 0. 174 00:09:37,160 --> 00:09:40,260 然后 所有东西加起来的和是来自左右括号的和 And then the sum of the whole thing is the sum coming from 175 00:09:40,260 --> 00:09:42,120 the left branch and the right branch. 176 00:09:42,120 --> 00:09:46,340 177 00:09:46,340 --> 00:09:51,560 好的 让我们用第二个问题来对比 OK, well, let me contrast that with a second problem. 178 00:09:51,560 --> 00:09:55,810 假设我给你一个整数n Suppose I give you an integer n, and then some function to 179 00:09:55,810 --> 00:09:59,270 然后再给出一些函数来计算第一个每个在1到n中整数 compute of the first of each integer in 1 through n. 180 00:09:59,270 --> 00:10:01,810 然后 我想要将它们这些满足一些性质的所有函数值收集起来放到列表中 And then I want to collect together in a list all those 181 00:10:01,810 --> 00:10:05,600 function values that satisfy some property. 182 00:10:05,600 --> 00:10:06,880 就是这样 That's a general kind of thing. 183 00:10:06,880 --> 00:10:09,750 让我们说得具体点 让我们想象 Let's say to be specific, let's imagine that for each 184 00:10:09,750 --> 00:10:11,270 对于每个整数k 我们将要 integer, k, we're going to compute 185 00:10:11,270 --> 00:10:14,210 计算出第k个斐波那契数 the k Fibonacci number. 186 00:10:14,210 --> 00:10:17,550 然后我们将会看到哪些是奇数 And then we'll see which of those are odd and assemble 187 00:10:17,550 --> 00:10:19,050 并将其分配进列表 those into a list. 188 00:10:19,050 --> 00:10:20,710 这里有一个可以做上面这件事的过程 So here's a procedure that does that. 189 00:10:20,710 --> 00:10:23,730 190 00:10:23,730 --> 00:10:26,240 在第一个n之中 找到奇的斐波那契数 Find the odd Fibonacci numbers among the first n. 191 00:10:26,240 --> 00:10:28,910 这是我们写的标准循环方法 And here is a standard loop the way we've been writing it. 192 00:10:28,910 --> 00:10:30,800 这是一个递归 This is a recursion. 193 00:10:30,800 --> 00:10:33,740 这是一个在k上的循环 我们可以说 如果k比n大 It's a loop on k, and says if k is bigger than n, it's the 194 00:10:33,740 --> 00:10:36,990 这将会是一个空列表 否则我们将会求出第k个斐波那契数 empty list. Otherwise we compute the k-th Fibonacci 195 00:10:36,990 --> 00:10:40,370 把那个叫做f number, call that f. 196 00:10:40,370 --> 00:10:45,180 如果这是一个奇数 我们可以使用cons将其变成list If it's odd, we CONS it on to the list starting 197 00:10:45,180 --> 00:10:47,690 并以下一个作为开始 with the next one. 198 00:10:47,690 --> 00:10:50,390 否则 我们就取下一个数字 And otherwise, we just take the next one. 199 00:10:50,390 --> 00:10:52,000 这是一个写iterative loop的标准方法 And this is the standard way we've been 200 00:10:52,000 --> 00:10:53,000 writing iterative loops. 201 00:10:53,000 --> 00:10:57,600 我们用1来开始循环 And we start off calling that loop with 1. 202 00:10:57,600 --> 00:11:01,600 所以我们现在有两个过程 OK, so there are two procedures. 203 00:11:01,600 --> 00:11:02,900 这两个过程看起来很不同 Those procedures look very different. 204 00:11:02,900 --> 00:11:04,390 他们有两个非常不同的结构 They have very different structures. 205 00:11:04,390 --> 00:11:07,740 但在某些程度上 Yet from a certain point of view, those procedures are 206 00:11:07,740 --> 00:11:11,330 那些过程做了相同的事 really doing very much the same thing. 207 00:11:11,330 --> 00:11:14,930 所以 如果我像信号处理工程师那样说话的话 So if I was talking like a signal processing engineer, 208 00:11:14,930 --> 00:11:25,730 我会说的可能是第一个过程 what I might say is that the first procedure enumerates the 209 00:11:25,730 --> 00:11:26,980 enumerate了树中的例子 leaves of a tree. 210 00:11:26,980 --> 00:11:31,160 211 00:11:31,160 --> 00:11:33,510 然后 我们可以想象 一个信号从那里出来 And then we can think of a signal coming out of that, 212 00:11:33,510 --> 00:11:35,330 它是所有的树节点 which is all the leaves. 213 00:11:35,330 --> 00:11:43,970 我们将会对其进行filter 看看哪些是奇数 We'll filter them to see which ones are odd, put them through 214 00:11:43,970 --> 00:11:45,190 把这些放进类似的filter some kind of filter. 215 00:11:45,190 --> 00:11:49,000 我们将会把它们放入transducer We'll then put them through a kind of transducer. 216 00:11:49,000 --> 00:11:51,420 对于每个这样的东西 我们将会对其做平方运算 And for each one of those things, we'll take the square. 217 00:11:51,420 --> 00:11:54,200 218 00:11:54,200 --> 00:11:58,290 然后我们会对所有的这些东西做累加操作 And then we'll accumulate all of those. 219 00:11:58,290 --> 00:12:00,570 我们将要把这些东西粘住通过从0开始的加法来累加它们 We'll accumulate them by sticking them together with 220 00:12:00,570 --> 00:12:03,340 addition starting from 0. 221 00:12:03,340 --> 00:12:07,140 222 00:12:07,140 --> 00:12:08,210 这是第一个程序 That's the first program. 223 00:12:08,210 --> 00:12:10,620 第二个程序 我可以用极其相似的方法来形容 The second program, I can describe in a very, very 224 00:12:10,620 --> 00:12:11,780 similar way. 225 00:12:11,780 --> 00:12:17,450 我会说 我们将在这段1-n的区间中enumerate数字 I'll say, we'll enumerate the numbers on this interval, for 226 00:12:17,450 --> 00:12:19,080 the interval 1 through n. 227 00:12:19,080 --> 00:12:22,500 228 00:12:22,500 --> 00:12:28,080 对于每一个 我们将要计算出斐波那契数 We'll, for each one, compute the Fibonacci number, put them 229 00:12:28,080 --> 00:12:29,270 并把它们放进transducer中 through a transducer. 230 00:12:29,270 --> 00:12:31,780 我们将会得到相应的结果 We'll then take the result of that, and we'll 231 00:12:31,780 --> 00:12:35,976 并且我们将会为了奇数性而filter它 filter it for oddness. 232 00:12:35,976 --> 00:12:39,35 然后我门把它们放进accumulator And then we'll take those and put them into an accumulator. 233 00:12:39,350 --> 00:12:41,730 这回 我们将会做一个列表 This time we'll build up a list, so we'll accumulate with 234 00:12:41,730 --> 00:12:47,110 所以 我们将会用cons从空列表中进行累加 CONS starting from the empty list. 235 00:12:47,110 --> 00:12:50,940 所以 从这个角度看程序 使这两个程序 So this way of looking at the program makes the two seem 236 00:12:50,940 --> 00:12:51,900 看起来非常相似 very, very similar. 237 00:12:51,900 --> 00:12:55,880 The problem is that that commonality is completely 238 00:12:55,880 --> 00:12:58,050 当我们看我们写的程序 这个问题的共同性是完全的被遮蔽的 obscured when we look at the procedures we wrote. 239 00:12:58,050 --> 00:13:02,670 让我们返回 并再次查看一些奇数的平方 Let's go back and look at some odd squares again, and say 240 00:13:02,670 --> 00:13:06,300 然后说 enumerator在哪里 things like, where's the enumerator? 241 00:13:06,300 --> 00:13:08,140 在这个程序里 enumerator在哪里 Where's the enumerator in this program? 242 00:13:08,140 --> 00:13:11,230 它不在一个地方 Well, it's not in one place. 243 00:13:11,230 --> 00:13:15,990 其中的一部分在这个左节点的测试中 It's a little bit in this leaf-node test, 244 00:13:15,990 --> 00:13:17,160 这将要停止 which is going to stop. 245 00:13:17,160 --> 00:13:19,380 其中的一小部分在这个东西本身的递归结构中 It's a little bit in the recursive structure of the 246 00:13:19,380 --> 00:13:20,630 thing itself. 247 00:13:20,630 --> 00:13:23,150 248 00:13:23,150 --> 00:13:24,120 accumulator在哪里 Where's the accumulator? 249 00:13:24,120 --> 00:13:25,680 accumulator也不在一个地方 The accumulator isn't in one place either. 250 00:13:25,680 --> 00:13:32,180 这东西的一部分在0这 一部分在加号 It's partly in this 0 and partly in this plus. 251 00:13:32,180 --> 00:13:34,510 不在我们看到的那个东西那里 It's not there as a thing that we can look at. 252 00:13:34,510 --> 00:13:40,550 相似的 如果我们查看奇数斐波那契数 Similarly, if we look at odd Fibs, that's also, in some 253 00:13:40,550 --> 00:13:42,940 这在某些程度上 也是一个enumerator和一个accumulator sense, an enumerator and an accumulator, but 254 00:13:42,940 --> 00:13:44,470 但这看起来不一样 it looks very different. 255 00:13:44,470 --> 00:13:49,260 因为部分地 enumerator在这测试中大于的符号 Because partly, the enumerator is here in this greater than 256 00:13:49,260 --> 00:13:52,100 部分地 在整个循环的递归结构 sign in the test. And partly it's in this whole recursive 257 00:13:52,100 --> 00:13:55,680 structure in the loop, and the way that we call it. 258 00:13:55,680 --> 00:13:58,100 相似得 accumulator也像这样混合在一起 And then similarly, that's also mixed up in there with 259 00:13:58,100 --> 00:14:01,010 部分的在这里 部分的在这里 the accumulator, which is partly over there and partly 260 00:14:01,010 --> 00:14:03,600 over there. 261 00:14:03,600 --> 00:14:09,790 所以 这些非常非常自然的元件 So these very, very natural pieces, these very natural 262 00:14:09,790 --> 00:14:13,770 这个很自然的盒子不会在我们的程序中出现 boxes here don't appear in our programs. Because they're kind 263 00:14:13,770 --> 00:14:14,360 因为这些东西混合在一起了 of mixed up. 264 00:14:14,360 --> 00:14:16,290 程序没有正确地将东西切成小块 The programs don't chop things up in the right way. 265 00:14:16,290 --> 00:14:19,450 266 00:14:19,450 --> 00:14:22,240 让我们回想一下计算机科学的基本定理 Going back to this fundamental principle of computer science 267 00:14:22,240 --> 00:14:24,620 为了去控制某样东西 你需要 that in order to control something, you need the name 268 00:14:24,620 --> 00:14:27,820 给它命名 我们真的在用这种方法来思考时没有控制 of it, we don't really have control over thinking about 269 00:14:27,820 --> 00:14:30,500 因为显式上,我们在那里面没有我们的手 things this way because we don't have our hands in them 270 00:14:30,500 --> 00:14:31,060 explicitly. 271 00:14:31,060 --> 00:14:35,510 我们没有好的语言来说它们 We don't have a good language for talking about them. 272 00:14:35,510 --> 00:14:42,850 好吧 让我们发明一个合适的 可以建造这些元件的语言 Well, let's invent an appropriate language in which 273 00:14:42,850 --> 00:14:44,515 we can build these pieces. 274 00:14:44,515 --> 00:14:48,650 语言的关键是这些东西 The key to the language is these guys, is what is these 275 00:14:48,650 --> 00:14:50,480 这是一个被我叫做信号的东西 things I called signals? 276 00:14:50,480 --> 00:14:52,070 在盒子中的数组上面飞的东西是什么鬼 What are these things that are flying on the 277 00:14:52,070 --> 00:14:53,320 arrows between the boxes? 278 00:14:53,320 --> 00:14:56,880 279 00:14:56,880 --> 00:15:02,840 这些东西将变成一种叫流的数据结构 Well, those things are going to be data structures called 280 00:15:02,840 --> 00:15:04,770 那将变成发明这个语言的关键 streams. That's going to be the key to 281 00:15:04,770 --> 00:15:07,980 inventing this language. 282 00:15:07,980 --> 00:15:08,600 什么是流 What's a stream? 283 00:15:08,600 --> 00:15:10,820 好吧 一个流是 像其他东西一样 Well, a stream is, like anything else, a data 284 00:15:10,820 --> 00:15:12,220 一个数据抽象 abstraction. 285 00:15:12,220 --> 00:15:15,000 所以我们应该告诉你什么是selectors So I should tell you what its selectors and 286 00:15:15,000 --> 00:15:16,870 什么是constructors constructors are. 287 00:15:16,870 --> 00:15:20,185 对于一个流 我们将会有一个constructor For a stream, we're going to have one constructor that's 288 00:15:20,185 --> 00:15:21,435 叫做 cons流 called CONS-stream. 289 00:15:21,435 --> 00:15:25,690 290 00:15:25,690 --> 00:15:29,060 cons流将会将两个东西合在一起变为一个叫流的东西 CONS-stream is going to put two things together to form a 291 00:15:29,060 --> 00:15:32,040 thing called a stream. 292 00:15:32,040 --> 00:15:34,250 然后 从流中抽离东西 And then to extract things from the stream, we're going 293 00:15:34,250 --> 00:15:38,010 我们将会有一个selector 被叫做流的头 to have a selector called the head of the stream. 294 00:15:38,010 --> 00:15:41,340 所以如果我有一个流 我可以带这个头 So if I have a stream, I can take its head or I 295 00:15:41,340 --> 00:15:44,720 或者带这个尾 can take its tail. 296 00:15:44,720 --> 00:15:48,290 请记住 我不得不在这里告诉你乔治的合同来告诉你 And remember, I have to tell you George's contract here to 297 00:15:48,290 --> 00:15:53,160 什么是与这个相关的公理 tell you what the axioms are that relate these. 298 00:15:53,160 --> 00:16:04,080 对于所有的x和y And it's going to be for any x and y, if I form the 299 00:16:04,080 --> 00:16:11,420 如果我造了一个con流并取其头 x和y的cons流的头 CONS-stream and take the head, the head of CONS-stream of x 300 00:16:11,420 --> 00:16:26,590 将会变成x 并且x和y的cons流的尾将会变成y and y is going to be x and the tail of CONS-stream of x and y 301 00:16:26,590 --> 00:16:28,440 is going to be y. 302 00:16:28,440 --> 00:16:31,180 所以那些是对于流的constructor 对于流的2个selectors So those are the constructor, two selectors for 303 00:16:31,180 --> 00:16:34,750 和一条公理 streams, and an axiom. 304 00:16:34,750 --> 00:16:36,980 这里有一些可疑 There's something fishy here. 305 00:16:36,980 --> 00:16:41,060 你有可能发现这些完全是cons car cdr的公理 So you might notice that these are exactly the axioms for 306 00:16:41,060 --> 00:16:46,100 如果写cons流 CONS, CAR, and CDR. If instead of writing CONS-stream I wrote 307 00:16:46,100 --> 00:16:50,810 并且我说头是car 尾是cdr CONS and I said head was the CAR and tail was the CDR, 308 00:16:50,810 --> 00:16:52,810 这些完全是序对的公理 those are exactly the axioms for pairs. 309 00:16:52,810 --> 00:16:55,130 事实上 这里还有另一个东西 And in fact, there's another thing here. 310 00:16:55,130 --> 00:17:02,930 我们将会有一个像空列表的东西 叫空流 We're going to have a thing called the-empty-stream, which 311 00:17:02,930 --> 00:17:08,319 像空列表 is like the-empty-list. 312 00:17:08,319 --> 00:17:10,030 为什么我介绍这个术语呢 So why am I introducing this terminology? 313 00:17:10,030 --> 00:17:12,780 为什么我不继续说序对和列表呢? Why don't I just keep talking about pairs and lists? 314 00:17:12,780 --> 00:17:15,510 好吧 我们将会看到 Well, we'll see. 315 00:17:15,510 --> 00:17:18,440 就现在来说 如果你喜欢 为什么不把流假装 For now, if you like, why don't you just pretend that 316 00:17:18,440 --> 00:17:21,560 看成列表的一种术语 streams really are just a terminology for lists. 317 00:17:21,560 --> 00:17:24,890 而且我们等等将会看到 为什么我们想要保持这个额外的抽象层 And we'll see in a little while why we want to keep this 318 00:17:24,890 --> 00:17:28,150 而不仅仅是叫这个为列表 extra abstraction layer and not just call them lists. 319 00:17:28,150 --> 00:17:32,300 320 00:17:32,300 --> 00:17:34,860 好的 现在我们有了流 我们可以开始构建 OK, now that we have streams, we can start constructing the 321 00:17:34,860 --> 00:17:38,990 语言的元件来作用在流上 pieces of the language to operate on streams. And there 322 00:17:38,990 --> 00:17:41,330 有很多有用的东西我们可以开始做 are a whole bunch of very useful things that we could 323 00:17:41,330 --> 00:17:42,120 start making. 324 00:17:42,120 --> 00:17:54,850 举个例子 我们将会做我们的map box 来带一个流s For instance, we'll make our map box to take a stream, s, 325 00:17:54,850 --> 00:18:00,400 和一个过程 并且生成一个新的流 and a procedure, and to generate a new stream which 326 00:18:00,400 --> 00:18:03,640 那过程作用在s所有的后继节点上 has as its elements the procedure applied to all the 327 00:18:03,640 --> 00:18:05,666 作用在s所有的后继节点上 successive elements of s. 328 00:18:05,666 --> 00:18:07,400 事实上 我们已经见过了 In fact, we've seen this before. 329 00:18:07,400 --> 00:18:10,950 这是我们的过程 这个过程map 了我们在列表中做的 This is the procedure map that we did with lists. 330 00:18:10,950 --> 00:18:14,000 你看 这完全是map 除了我们要对空流进行测试 And you see it's exactly map, except we're testing for 331 00:18:14,000 --> 00:18:14,650 empty-stream. 332 00:18:14,650 --> 00:18:15,560 噢 我忘记说了 Oh, I forgot to mention that. 333 00:18:15,560 --> 00:18:19,420 空流就像null测试 所以如果它是空的 Empty-stream is like the null test. So if it's empty, we 334 00:18:19,420 --> 00:18:20,510 我们生成新的空流 generate the empty stream. 335 00:18:20,510 --> 00:18:24,700 否则 我们做一个新的流 这个流的第一个元素 Otherwise, we form a new stream whose first element is 336 00:18:24,700 --> 00:18:28,950 是过程作用在流的头 the procedure applied to the head of the stream, and whose 337 00:18:28,950 --> 00:18:31,570 剩下的将会沿着过程一直map到流的尾部 rest is gotten by mapping along with the procedure down 338 00:18:31,570 --> 00:18:33,140 the tail of the stream. 339 00:18:33,140 --> 00:18:34,920 所以这和我们以前看过的map过程完全一样 So that looks exactly like the map procedure 340 00:18:34,920 --> 00:18:37,030 we looked at before. 341 00:18:37,030 --> 00:18:38,350 这里还有另一个有用的东西 Here's another useful thing. 342 00:18:38,350 --> 00:18:40,460 filter 这是我们的filter box Filter, this is our filter box. 343 00:18:40,460 --> 00:18:43,890 我们将会有一个谓词和一个流 We're going to have a predicate and a stream. 344 00:18:43,890 --> 00:18:46,720 我们将会做一个新的包涵所有的满足于谓语元素的流 We're going to make a new stream that consists of all 345 00:18:46,720 --> 00:18:48,310 the elements of the original one 346 00:18:48,310 --> 00:18:50,160 that satisfy the predicate. 347 00:18:50,160 --> 00:18:51,270 这里是案例分析 That's case analysis. 348 00:18:51,270 --> 00:18:53,140 当在流中什么都没有 When there's nothing in the stream, we 349 00:18:53,140 --> 00:18:56,280 我返回一个空的流 return the empty stream. 350 00:18:56,280 --> 00:19:00,060 我们检测在流的头上的谓词 We test the predicate on the head of the stream. 351 00:19:00,060 --> 00:19:03,520 并且如果这是对的 我们将流的头加在 And if it's true, we add the head of the stream onto the 352 00:19:03,520 --> 00:19:08,220 filter流尾的结果 result of filtering the tail of the stream. 353 00:19:08,220 --> 00:19:10,870 否则 如果那个谓词是错的 And otherwise, if that predicate was false, we just 354 00:19:10,870 --> 00:19:13,500 我们只需要filter流的尾部 filter the tail of the stream. 355 00:19:13,500 --> 00:19:16,595 是的 这里是filter Right, so there's filter. 356 00:19:16,595 --> 00:19:18,560 让我快速的运行完这一对 Let me run through a couple more rather quickly. 357 00:19:18,560 --> 00:19:20,880 这些在书里都有 你可以去看下 They're all in the book and you can look at them. 358 00:19:20,880 --> 00:19:22,110 让我们过一遍 Let me just flash through. 359 00:19:22,110 --> 00:19:23,260 这里是accumulate Here's accumulate. 360 00:19:23,260 --> 00:19:27,690 accumulate使用一种连接的方式 Accumulate takes a way of combining things and an 361 00:19:27,690 --> 00:19:31,560 将流中的初始值粘合在一起 initial value in a stream and sticks them all together. 362 00:19:31,560 --> 00:19:33,970 如果流是空的 那么这仅仅是初始值 If the stream's empty, it's just the initial value. 363 00:19:33,970 --> 00:19:36,930 否则 我们连接流的头和累加从初始值开始的流的尾部的结果 Otherwise, we combine the head of the stream with the result 364 00:19:36,930 --> 00:19:39,550 of accumulating the tail of the stream starting from the 365 00:19:39,550 --> 00:19:40,900 initial value. 366 00:19:40,900 --> 00:19:42,830 所以 我们将会将所有东西都加进流 So that's what I'd use to add up everything in the stream. 367 00:19:42,830 --> 00:19:45,830 我会使用加法来进行累加 I'd accumulate with plus. 368 00:19:45,830 --> 00:19:48,060 我如何enumerate树上的叶子呢 How would I enumerate the leaves of a tree? 369 00:19:48,060 --> 00:19:54,530 如果树仅仅只是叶本身 Well, if the tree is just a leaf itself, I make something 370 00:19:54,530 --> 00:19:56,640 我制作一个只有节点的东西 which only has that node in it. 371 00:19:56,640 --> 00:20:01,100 否则 我把从左括号到右括号的东西附加起来 Otherwise, I append together the stuff of enumerating the 372 00:20:01,100 --> 00:20:04,340 left branch and the right branch. 373 00:20:04,340 --> 00:20:08,130 然后 在这里附加就像普通在列表中的附加 And then append here is like the ordinary append on lists. 374 00:20:08,130 --> 00:20:13,190 375 00:20:13,190 --> 00:20:13,850 你可以看这里 You can look at that. 376 00:20:13,850 --> 00:20:16,410 这类似于普通附加两个列表的过程 That's analogous to the ordinary procedure for 377 00:20:16,410 --> 00:20:19,150 appending two lists. 378 00:20:19,150 --> 00:20:21,810 我如何来enumerate间距 How would I enumerate an interval? 379 00:20:21,810 --> 00:20:24,500 这将会用到两个数 一小一大 This will take two integers, low and high, and generate a 380 00:20:24,500 --> 00:20:28,106 并且生成从小到大的整数流 stream of the integers going from low to high. 381 00:20:28,106 --> 00:20:31,890 然后我们可得到整个一串元件 And we can make a whole bunch of pieces. 382 00:20:31,890 --> 00:20:34,860 所以 那是我们说的流的一点点小语言 So that's a little language of talking about streams. Once we 383 00:20:34,860 --> 00:20:37,670 当我们有了流 我们可以制作东西来操纵它们 have streams, we can build things for manipulating them. 384 00:20:37,670 --> 00:20:40,200 再说一下 我们正在制作语言 Again, we're making a language. 385 00:20:40,200 --> 00:20:41,270 现在我们可以用这种语言来表达东西 And now we can start expressing 386 00:20:41,270 --> 00:20:43,060 things in this language. 387 00:20:43,060 --> 00:20:46,590 这里是在树中累加奇数平方的原始过程 Here's our original procedure for summing the odd 388 00:20:46,590 --> 00:20:47,310 squares in a tree. 389 00:20:47,310 --> 00:20:52,210 你将会注意到 这完全像方框图 And you'll notice it looks exactly now like the block 390 00:20:52,210 --> 00:20:54,590 像信号处理中的方框图 diagram, like the signal processing block diagram. 391 00:20:54,590 --> 00:21:00,230 所以把奇数的平方在树中求和 So to sum the odd squares in a tree, we enumerate the leaves 392 00:21:00,230 --> 00:21:01,320 我们enumerate了数中的叶子 of the tree. 393 00:21:01,320 --> 00:21:04,830 我们为了保持奇数性进行filter We filter that for oddness. 394 00:21:04,830 --> 00:21:06,220 我们为了平方性进行map We map that for squareness. 395 00:21:06,220 --> 00:21:09,320 396 00:21:09,320 --> 00:21:12,460 并且我们使用加法对结果进行累加 And we accumulate the result of that using addition, 397 00:21:12,460 --> 00:21:14,760 从0开始 starting from 0. 398 00:21:14,760 --> 00:21:17,290 所以我们可以看到我们想要的元件 So we can see the pieces that we wanted. 399 00:21:17,290 --> 00:21:22,050 相似的 斐波那契数 我们怎样得到奇数的斐波那契数 Similarly, the Fibonacci one, how do we get the odd Fibs? 400 00:21:22,050 --> 00:21:27,900 我们从1到n枚举间距 并沿着那里进行map Well, we enumerate the interval from 1 to n, we map 401 00:21:27,900 --> 00:21:30,920 计算每个的斐波那契数 along that, computing the Fibonacci of each one. 402 00:21:30,920 --> 00:21:34,810 我们为了奇数性对那些结果进行filter We filter the result of those for oddness. 403 00:21:34,810 --> 00:21:38,460 并且我们使用从空列表开始的cons累积了所有的这些东西 And we accumulate all of that stuff using CONS starting from 404 00:21:38,460 --> 00:21:43,650 the empty-list. 405 00:21:43,650 --> 00:21:47,680 好吧 那这个有神马优势 OK, what's the advantage of this? 406 00:21:47,680 --> 00:21:50,260 嗯 首先 我们现在有元件 并且我们可以开始 Well, for one thing, we now have pieces that we can start 407 00:21:50,260 --> 00:21:51,880 混合和匹配 mixing and matching. 408 00:21:51,880 --> 00:21:58,230 举个例子 如果我想要改变它 So for instance, if I wanted to change this, if I wanted to 409 00:21:58,230 --> 00:22:00,400 如果我想要得到整数的平方 然后进行filter compute the squares of the integers and then filter them, 410 00:22:00,400 --> 00:22:03,810 我需要做的是从那个平方中拿起像这样的标准元件 然后放进去 all I need to do is pick up a standard piece like this in 411 00:22:03,810 --> 00:22:06,210 that square and put it in. 412 00:22:06,210 --> 00:22:10,150 或者 如果我们想要计算整个在树上的斐波那契计算而不是一个序列 Or if we wanted to do this whole Fibonacci computation on 413 00:22:10,150 --> 00:22:12,980 the leaves of a tree rather than a sequence, all I need to 414 00:22:12,980 --> 00:22:18,030 我需要做的是用那个替换这个enumerator do is replace this enumerator with that one. 415 00:22:18,030 --> 00:22:20,650 看 流处理的优势是 See, the advantage of this stream processing is that 416 00:22:20,650 --> 00:22:21,995 我们建立了-- we're establishing-- 417 00:22:21,995 --> 00:22:25,330 这是我们课程中一个比较大的课题 this is one of the big themes of the course-- 418 00:22:25,330 --> 00:22:35,570 我们正在建立符合我们直觉的接口 并且这个接口允许我们把东西粘在一起 we're establishing conventional interfaces that 419 00:22:35,570 --> 00:22:38,130 allow us to glue things together. 420 00:22:38,130 --> 00:22:41,730 像map和filter这样的东西是一个标准的组件集合 Things like map and filter are a standard set of components 421 00:22:41,730 --> 00:22:43,900 我们可以开始使用这个 并用各种各样的方法去粘合程序 that we can start using for pasting together programs in 422 00:22:43,900 --> 00:22:45,750 all sorts of ways. 423 00:22:45,750 --> 00:22:50,090 这让我们看到程序的共性 It allows us to see the commonality of programs. 424 00:22:50,090 --> 00:22:52,390 我应该说一下 我只展示给你们2个过程 I just ought to mention, I've only showed you two 425 00:22:52,390 --> 00:22:53,860 procedures. 426 00:22:53,860 --> 00:22:57,800 但是 让我强调一下 But let me emphasize that this way of putting things together 427 00:22:57,800 --> 00:22:59,780 这种用maps filters和accumulators 把东西放在一起的方法 with maps, filters, and accumulators 428 00:22:59,780 --> 00:23:01,410 是非常非常普通的 is very, very general. 429 00:23:01,410 --> 00:23:08,010 这是程序产生和测试的范式 It's the generate and test paradigm for programs. And as 430 00:23:08,010 --> 00:23:11,970 作为一个列子 曾经的麻省理工研究生 Richard Waters an example of that, Richard Waters, who was at MIT when he 431 00:23:11,970 --> 00:23:14,060 was a graduate student, as part of his thesis research 432 00:23:14,060 --> 00:23:17,700 他把分析一个大块的ibm科学图书管子程序作为它理论研究的一部分 went and analyzed a large chunk of the IBM scientific 433 00:23:17,700 --> 00:23:22,340 他发现 大约百分之60的程序 subroutine library, and discovered that about 60% of 434 00:23:22,340 --> 00:23:26,830 可以用不超过我们放在这里的知识完整的表达 the programs in it could be expressed exactly in terms 435 00:23:26,830 --> 00:23:28,940 using no more than what we've put here-- 436 00:23:28,940 --> 00:23:30,710 map filter accumulate map, filter, and accumulate. 437 00:23:30,710 --> 00:23:31,960 好的 下面进入休息时间 All right, let's take a break. 438 00:23:31,960 --> 00:23:36,620 439 00:23:36,620 --> 00:23:37,870 有神马问题 Questions? 440 00:23:37,870 --> 00:23:40,470 441 00:23:40,470 --> 00:23:43,030 学僧 :看起来这货的本质只是 AUDIENCE: It seems like the essence of this whole thing is 442 00:23:43,033 --> 00:23:45,980 你有一个非常均匀简单的数据结构来进行工作 这个数据结构叫流 just that you have a very uniform, simple data structure 443 00:23:45,980 --> 00:23:48,380 to work with, the stream. 444 00:23:48,380 --> 00:23:48,920 教授:是的 PROFESSOR: Right. 445 00:23:48,920 --> 00:23:51,670 本质就是这个 The essence is that you, again, it's this sense of 446 00:23:51,670 --> 00:23:53,710 再说一下 这个就是感觉符合直觉的接口 conventional interfaces. 447 00:23:53,710 --> 00:23:55,610 所以你可以开始把很多东西放在一起 So you can start putting a lot of things together. 448 00:23:55,610 --> 00:23:59,830 流就像你所说的那样 一种均衡的数据结构来支持它 And the stream is as you say, the uniform data structure 449 00:23:59,830 --> 00:24:00,890 that supports that. 450 00:24:00,890 --> 00:24:03,600 顺便说一下 这非常像APL This is very much like APL, by the way. 451 00:24:03,600 --> 00:24:06,330 APL是一个几乎相同的思想 除了在APL中 APL is very much the same idea, except in APL, instead 452 00:24:06,330 --> 00:24:09,560 你可以使用数组和向量来代替这个流 of this stream, you have arrays and vectors. 453 00:24:09,560 --> 00:24:13,565 并且APL许多的威力的原因完全和这个一样 And a lot of the power of APL is exactly the same reason of 454 00:24:13,565 --> 00:24:14,815 the power of this. 455 00:24:14,815 --> 00:24:19,910 456 00:24:19,910 --> 00:24:20,910 好的 谢谢 OK, thank you. 457 00:24:20,910 --> 00:24:22,160 休息一下 Let's take a break. 458 00:24:22,160 --> 00:24:57,470 459 00:24:57,470 --> 00:24:57,610 好的 All right. 460 00:24:57,610 --> 00:25:02,830 我们已经看到使用流来做组织计算 We've been looking at ways of organizing computations using 461 00:25:02,830 --> 00:25:07,560 我现在想要做的只是展示给你们 streams. What I want to do now is just show you two somewhat 462 00:25:07,560 --> 00:25:10,810 两个更加复杂的例子 more complicated examples of that. 463 00:25:10,810 --> 00:25:15,000 让我们开始思考下面重要有用的过程 Let's start by thinking about the following kind of utility 464 00:25:15,000 --> 00:25:16,810 procedure that will come in useful. 465 00:25:16,810 --> 00:25:19,960 假设我有一个流 Suppose I've got a stream. 466 00:25:19,960 --> 00:25:23,730 流中的元素本身就是一个流 And the elements of this stream are themselves streams. 467 00:25:23,730 --> 00:25:26,530 所以一开始可能是1,2,3 So the first thing might be 1, 2, 3. 468 00:25:26,530 --> 00:25:32,600 469 00:25:32,600 --> 00:25:33,880 我得到了一个流 So I've got a stream. 470 00:25:33,880 --> 00:25:40,100 并且每个流中的元素它本身就是一个流 And each element of the stream is itself a stream. 471 00:25:40,100 --> 00:25:45,580 我想要做的是 建造一个流 And what I'd like to do is build a stream that collects 472 00:25:45,580 --> 00:25:47,870 它收集了所有的元素 将所有的元素脱离这个子流 together all of the elements, pulls all of the elements out 473 00:25:47,870 --> 00:25:50,840 然后把它们进行字符串化变成一个东西 of these sub-streams and strings them all 474 00:25:50,840 --> 00:25:52,080 together in one thing. 475 00:25:52,080 --> 00:25:56,220 只是展示给你这个语言的作用 真简单 So just to show you the use of this language, how easy it is, 476 00:25:56,220 --> 00:25:56,960 把那个叫做flatten call that flatten. 477 00:25:56,960 --> 00:26:13,020 然后我可以定义过程来flatten这个流中流 And I can define to flatten this stream of streams. Well, 478 00:26:13,020 --> 00:26:13,960 这是什么鬼 what is that? 479 00:26:13,960 --> 00:26:16,240 那只是一个accumulation That's just an accumulation. 480 00:26:16,240 --> 00:26:25,240 我想使用附加做累加 I want to accumulate using append, by 481 00:26:25,240 --> 00:26:26,450 通过连续的附加 successively appending. 482 00:26:26,450 --> 00:26:36,590 所以 我使用了 附加流进行累加 So I accumulate using append streams, starting with 483 00:26:36,590 --> 00:26:54,370 从空流往下到 流中流 the-empty-stream down that stream of streams. 484 00:26:54,370 --> 00:26:58,290 这里有一个你怎样开始使用这些更高阶的东西去做一些有趣的操作的例子 OK, so there's an example of how you can start using these 485 00:26:58,290 --> 00:27:00,830 higher order things to do some interesting operations. 486 00:27:00,830 --> 00:27:04,230 事实上 我还想做另一个有趣的东西 In fact, there's another useful thing 487 00:27:04,230 --> 00:27:05,100 that I want to do. 488 00:27:05,100 --> 00:27:18,700 我想要定义一个叫flat-map的过程 I want to define a procedure called flat-map, flat map of 489 00:27:18,700 --> 00:27:21,840 一些函数和一个流的flat map some function and a stream. 490 00:27:21,840 --> 00:27:23,920 f将会变成一个有一些元素的流 And what this is going to do is f will 491 00:27:23,920 --> 00:27:25,720 be a stream of elements. 492 00:27:25,720 --> 00:27:28,930 f将会变成一个函数 f is going to be a function that for each element in the 493 00:27:28,930 --> 00:27:31,950 这个函数在流中的每个元素可以产生另一个流 stream produces another stream. 494 00:27:31,950 --> 00:27:33,950 我想要做的是把所有的元素和所有的流合并起来 And what I want to do is take all of the elements and all of 495 00:27:33,950 --> 00:27:36,000 those streams and combine them together. 496 00:27:36,000 --> 00:27:51,350 所以那个只将会是直到s的flatten of map f So that's just going to be the flatten of map f down s. 497 00:27:51,350 --> 00:27:54,290 每次我调用对元素s调用f 我得到一个流 Each time I apply f to an element of s, I get a stream. 498 00:27:54,290 --> 00:27:56,690 如果我像下做map 我将会得到一个流中流 If I map it all the way down, I get a stream of streams, and 499 00:27:56,690 --> 00:27:58,385 并且我将会将它flatten I'll flatten that. 500 00:27:58,385 --> 00:28:04,670 好 我想要使用这个来展示给你们一种新的方法来熟悉这样的问题 Well, I want to use that to show you a new way to do a 501 00:28:04,670 --> 00:28:06,360 familiar kind of problem. 502 00:28:06,360 --> 00:28:12,310 这个问题和你以前见过的许多问题一样 The problem's going to be like a lot of problems you've seen, 503 00:28:12,310 --> 00:28:14,190 虽然这个可能不是很特别 although maybe not this particular one. 504 00:28:14,190 --> 00:28:15,490 我将会给你一个整数n I'm going to give you an integer, n. 505 00:28:15,490 --> 00:28:18,480 506 00:28:18,480 --> 00:28:31,020 我们的问题是找到所有的序对和整数i和j And the problem is going to be find all pairs and integers i 507 00:28:31,020 --> 00:28:42,740 取值为0-i j小于i 一直到n and j, between 0 and i, with j less than i, up to n, such 508 00:28:42,740 --> 00:28:51,910 并且可以满足i+j是素数 that i plus j is prime. 509 00:28:51,910 --> 00:28:55,740 510 00:28:55,740 --> 00:29:00,520 举个例子 如果n=6 让我在这里做个小表格 So for example, if n equals 6, let's make a little table 511 00:29:00,520 --> 00:29:06,640 这里i,j,i+j here, i and j and i plus j. 512 00:29:06,640 --> 00:29:09,700 513 00:29:09,700 --> 00:29:15,520 我们可以假设 i=2 j=1 我门可以得到i+j=3 So for, say, i equals 2 and j equals 1, I'd get 3. 514 00:29:15,520 --> 00:29:18,940 对于i=3 我可以使j=2 And for i equals 3, I could have j equals 2, and that 515 00:29:18,940 --> 00:29:21,210 那么i+j=5 would be 5. 516 00:29:21,210 --> 00:29:28,400 如果i=4 j=1 i+j=5 等等 直到i到了6 And 4 and 1 would be 5 and so on, up until i goes to 6. 517 00:29:28,400 --> 00:29:33,640 我想要返回去产生三倍数像这样的一个流 And what I'd like to return is to produce a stream of all the 518 00:29:33,640 --> 00:29:37,350 让我们说 i j i+j triples like this, let's say i, j, and i plus j. 519 00:29:37,350 --> 00:29:41,530 所以对于每个n 我想要产生这个流 So for each n, I want to generate this stream. 520 00:29:41,530 --> 00:29:43,680 好的 这简单 OK, well, that's easy. 521 00:29:43,680 --> 00:29:47,230 让我们做吧 Let's build it up. 522 00:29:47,230 --> 00:29:50,150 我们像这样开始 We start like this. 523 00:29:50,150 --> 00:29:55,510 我们会说 对于每个i 我们将会产生一个流 We're going to say for each i, we're going 524 00:29:55,510 --> 00:29:56,440 to generate a stream. 525 00:29:56,440 --> 00:29:58,830 对于每个1到n的i 我们将会产生一个流 For each i in the interval 1 through n, we're going to 526 00:29:58,830 --> 00:30:00,660 generate a stream. 527 00:30:00,660 --> 00:30:02,230 这个流将会变成什么呢 What's that stream going to be? 528 00:30:02,230 --> 00:30:04,180 我们将会以产生所有的序对开始 We're going to start by generating all the pairs. 529 00:30:04,180 --> 00:30:11,840 所以 对于我们产生的每个i So for each i, we're going to generate, for each j in the 530 00:30:11,840 --> 00:30:19,450 都有在这个1到i-1的区间里每个j 我们将会产生序对 interval 1 to i minus 1, we'll generate the pair, or the list 531 00:30:19,450 --> 00:30:20,710 或者是一个有两个元素i 和j的列表 with two elements i and j. 532 00:30:20,710 --> 00:30:23,780 533 00:30:23,780 --> 00:30:30,712 所以我们map整个区间 生成这些序对 So we map along the interval, generating the pairs. 534 00:30:30,712 --> 00:30:33,170 对于每个产生一个序对的流的i And for each i, that generates a stream of pairs. 535 00:30:33,170 --> 00:30:34,590 然后我们flatmap它 And we flatmap it. 536 00:30:34,590 --> 00:30:37,390 现在 我们已经拥有了所有i和j的序对 Now we have all the pairs i and j, such that i 537 00:30:37,390 --> 00:30:38,730 并且i比j小 is less than j. 538 00:30:38,730 --> 00:30:39,850 就像这样搞 So that builds that. 539 00:30:39,850 --> 00:30:42,990 现在我们对其来个测试 Now we're got to test them. 540 00:30:42,990 --> 00:30:47,160 我们把我们刚刚建的东西拿出 flatmap Well, we take that thing we just built, the flatmap, and 541 00:30:47,160 --> 00:30:50,090 并且我们把它进行filter 这个i是否 we filter it to see whether the i-- 542 00:30:50,090 --> 00:30:51,660 看 我们有一个i和j see, we had an i and a j. 543 00:30:51,660 --> 00:30:55,180 i是列表中的第一个东西 j是第二个 i was the first thing in the list, j was the second thing 544 00:30:55,180 --> 00:30:59,030 在列表中 我们有一个谓词 in the list. So we have a predicate which says in that 545 00:30:59,030 --> 00:31:00,870 这个谓词表示 在这个由2个元素构成的列表是car和cdr素数的和 list of two elements is the sum of the 546 00:31:00,870 --> 00:31:02,070 CAR and the CDR prime. 547 00:31:02,070 --> 00:31:06,540 并且我们对序对的集合进行filter And we filter that collection of pairs we just built. 548 00:31:06,540 --> 00:31:09,420 所以 那些是我们想要的序对 So those are the pairs we want. 549 00:31:09,420 --> 00:31:13,340 现在 我们继续 把filter后的结构沿着它进行map Now we go ahead and we take the result of that filter and 550 00:31:13,340 --> 00:31:19,610 生成列表i和j i+j we map along it, generating the list i and j and i plus j. 551 00:31:19,610 --> 00:31:22,910 这就是我们的程序 prime-sum-pairs And that's our procedure prime-sum-pairs. 552 00:31:22,910 --> 00:31:24,480 然后只需要过一遍 这就是我们整个过程了 And then just to flash it up, here's the whole procedure. 553 00:31:24,480 --> 00:31:27,945 554 00:31:27,945 --> 00:31:30,750 一个map 一个filter 一个flatmap A map, a filter, a flatmap. 555 00:31:30,750 --> 00:31:34,850 556 00:31:34,850 --> 00:31:36,350 所有的东西都在这里了 There's the whole thing, even though this isn't 557 00:31:36,350 --> 00:31:37,120 即使这个可读性不高 particularly readable. 558 00:31:37,120 --> 00:31:40,000 这只是一个flatmap的延伸 It's just expanding that flatmap. 559 00:31:40,000 --> 00:31:45,090 这里有一个表现嵌套循环的过程 So there's an example which illustrates the general point 560 00:31:45,090 --> 00:31:49,350 它开始像maps和那些东西的flatmaps的flatmaps的flatmaps that nested loops in this procedure start looking like 561 00:31:49,350 --> 00:31:52,370 compositions of flatmaps of flatmaps of flatmaps of maps 562 00:31:52,370 --> 00:31:54,200 and things. 563 00:31:54,200 --> 00:31:57,900 所以我们不仅仅要枚举单个个体 So not only can we enumerate individual things, but by 564 00:31:57,900 --> 00:32:00,890 还要通过使用flatmaps 使我们做一些与大部分其他语言的对应的嵌套循环 using flatmaps, we can do what would correspond to nested 565 00:32:00,890 --> 00:32:03,230 loops in most other languages. 566 00:32:03,230 --> 00:32:06,870 当然 一直写这个flatmaps中的flatmaps很烦 Of course, it's pretty awful to keep writing these flatmaps 567 00:32:06,870 --> 00:32:08,410 of flatmaps of flatmaps. 568 00:32:08,410 --> 00:32:13,830 你看的这个prime-sum-pairs很复杂 Prime-sum-pairs you saw looked fairly complicated, even 569 00:32:13,830 --> 00:32:15,480 虽然单个个体很容易 though the individual pieces were easy. 570 00:32:15,480 --> 00:32:17,800 所以如果你喜欢 你可以用一些叫collect的语法糖 So what you can do, if you like, is introduced some 571 00:32:17,800 --> 00:32:21,040 syntactic sugar that's called collect. 572 00:32:21,040 --> 00:32:23,570 collect只是一个对于嵌套的flatmaps的缩写 And collect is just an abbreviation for that nest of 573 00:32:23,570 --> 00:32:26,160 flatmaps and filters arranged in that particular way. 574 00:32:26,160 --> 00:32:29,620 这里还是prime-sum-pairs 不过是用collect来做的 Here's prime-sum-pairs again, written using collect. 575 00:32:29,620 --> 00:32:32,670 它的意思是为了找到所有的序对 我将要整和一个答案 It says to find all those pairs, I'm going to collect 576 00:32:32,670 --> 00:32:40,910 这个答案是列表i j 和i+j together a result, which is the list i, j, and i plus j, 577 00:32:40,910 --> 00:32:44,510 那将会生成i的值为1到n that's going to be generated as i runs through the interval 578 00:32:44,510 --> 00:32:51,440 j的值是1到i到1 from 1 to n and as j runs through the interval from 1 to 579 00:32:51,440 --> 00:32:58,040 并令i+j是素数 i minus 1, such that i plus j is prime. 580 00:32:58,040 --> 00:33:00,690 所以我将不会说 我会使用一般的collect So I'm not going to say what collect does in general. 581 00:33:00,690 --> 00:33:03,420 你可以在书上看到它 You can look at that by looking at it in the book. 582 00:33:03,420 --> 00:33:06,010 但是 很显然 你可以看到这些元件是我写的原始过程的元件 But pretty much, you can see that the pieces of this are 583 00:33:06,010 --> 00:33:08,820 the pieces of that original procedure I wrote. 584 00:33:08,820 --> 00:33:11,550 这个collect只是一些自动生成嵌套flatmaps的语法糖 And this collect is just some syntactic sugar for 585 00:33:11,550 --> 00:33:16,310 automatically generating that nest of flatmaps and flatmaps. 586 00:33:16,310 --> 00:33:21,120 好 让我再做一个和上面差不多的例子 OK, well, let me do one more example that shows you the 587 00:33:21,120 --> 00:33:22,120 same kind of thing. 588 00:33:22,120 --> 00:33:25,740 这里是一个非常著名的问题 Here's a very famous problem that's used to illustrate a 589 00:33:25,740 --> 00:33:28,980 这个问题以前是为了展示许多叫回溯法的计算机算法 lot of so-called backtracking computer algorithms. This is 590 00:33:28,980 --> 00:33:30,200 这是一个八皇后的问题 the eight queens problem. 591 00:33:30,200 --> 00:33:32,370 这里是棋盘 This is a chess board. 592 00:33:32,370 --> 00:33:34,570 八皇后问题说 And the eight queens problem says, find a way to put down 593 00:33:34,570 --> 00:33:37,660 找到一种八皇后两两不相攻击的方法 eight queens on a chess board so that no two are attacking 594 00:33:37,660 --> 00:33:38,000 each other. 595 00:33:38,000 --> 00:33:39,685 这里有一个特别的方法来解决这个八皇后问题 And here's a particular solution to the 596 00:33:39,685 --> 00:33:41,430 eight queens problem. 597 00:33:41,430 --> 00:33:44,450 所以 我得保证放置皇后 并且 So I have to make sure to put down queens so that no two are 598 00:33:44,450 --> 00:33:48,570 没有皇后在同一列或行或在同一个对角线 in the same row or the same column or sit 599 00:33:48,570 --> 00:33:51,410 along the same diagonal. 600 00:33:51,410 --> 00:33:56,400 现在有个做这个的标准的方法 Now, there's sort of a standard way of doing that. 601 00:33:56,400 --> 00:33:59,740 602 00:33:59,740 --> 00:34:03,200 首先我们要做的是 Well, first we need to do is below the 603 00:34:03,200 --> 00:34:04,940 站在george的层面 surface, at George's level. 604 00:34:04,940 --> 00:34:07,340 我们得找一个方法来表示棋盘和位置 We have to find some way to represent a board, and 605 00:34:07,340 --> 00:34:08,095 represent positions. 606 00:34:08,095 --> 00:34:09,800 我们不需要担心那个 And we'll not worry about that. 607 00:34:09,800 --> 00:34:12,540 但是让我们假设有一个叫safe的谓词 But let's assume that there's a predicate called safe. 608 00:34:12,540 --> 00:34:16,040 609 00:34:16,040 --> 00:34:19,090 safe所作的是 And what safe is going to do is going to say given that I 610 00:34:19,090 --> 00:34:22,520 我有一串皇后放在棋盘上 have a bunch of queens down on the chess board, is it OK to 611 00:34:22,520 --> 00:34:25,400 把queen放在特定的点上是好的吗 put a queen in this particular spot? 612 00:34:25,400 --> 00:34:32,889 所以safe将会带一行一列 So safe is going to take a row and a column. 613 00:34:32,889 --> 00:34:34,510 那将会是我尝试放置下一个皇后的地方和剩下的地方 That's going to be a place where I'm going to try and put 614 00:34:34,510 --> 00:34:42,370 down the next queen, and the rest of positions. 615 00:34:42,370 --> 00:34:45,420 616 00:34:45,420 --> 00:34:48,679 safe说的是 我已经把皇后放在这个位置上 And what safe will say is given that I already have 617 00:34:48,679 --> 00:34:53,920 queens down in these positions, is it safe to put 618 00:34:53,920 --> 00:34:58,300 那么 把皇后放在那个行或列是safe吗 another queen down in that row and that column? 619 00:34:58,300 --> 00:34:59,360 让我们不要再担心这个问题 And let's not worry about that. 620 00:34:59,360 --> 00:35:01,380 这个是乔治的问题 这也不难写 That's George's problem. and it's not hard to write. 621 00:35:01,380 --> 00:35:06,350 你只需要检查 这货是不是包含 You just have to check whether this thing contains any things 622 00:35:06,350 --> 00:35:10,530 一些在那个行 列或对角线中的东西 on that row or that column or in that diagonal. 623 00:35:10,530 --> 00:35:13,590 现在你将要怎样组织程序呢 Now, how would you organize the program given that? 624 00:35:13,590 --> 00:35:18,010 这里有一个传统的方法来解决这个问题 And there's sort of a traditional way to organize it 625 00:35:18,010 --> 00:35:20,116 我们把它叫做回溯法 它的意思是 called backtracking. 626 00:35:20,116 --> 00:35:27,570 让我们把第一个皇后放在第一个列上 And it says, well, let's think about all the ways of putting 627 00:35:27,570 --> 00:35:31,290 the first queen down in the first column. 628 00:35:31,290 --> 00:35:32,580 这里有八种方法 There are eight ways. 629 00:35:32,580 --> 00:35:35,880 让我们来试一下第一个 Well, let's say try the first column. 630 00:35:35,880 --> 00:35:37,300 来试试第一行第一列 Try column 1, row 1. 631 00:35:37,300 --> 00:35:41,300 这些分支可以表示每个的可能性 These branches are going to represent the possibilities at 632 00:35:41,300 --> 00:35:43,360 each level. 633 00:35:43,360 --> 00:35:45,875 所以我将会尝试并把皇后放在第一列中 So I'll try and put a queen down in the first column. 634 00:35:45,875 --> 00:35:48,360 现在 我们已经把它放在第一列了 And now given that it's in the first column, I'll try and put 635 00:35:48,360 --> 00:35:49,980 我们讲尝试把下一个皇后放在第一列 the next queen down in the first column. 636 00:35:49,980 --> 00:35:53,035 637 00:35:53,035 --> 00:35:55,470 我们将尝试并且把第一个皇后 I'll try and put the first queen, the one in the first 638 00:35:55,470 --> 00:35:56,920 第一列的皇后 方在第一行 column, down in the first row. 639 00:35:56,920 --> 00:35:59,050 不好意思 I'm sorry. 640 00:35:59,050 --> 00:36:00,780 然后 我们将把下一个皇后放在第一行 And then given that, we'll put the next queen down 641 00:36:00,780 --> 00:36:01,390 in the first row. 642 00:36:01,390 --> 00:36:02,090 这样不好 And that's no good. 643 00:36:02,090 --> 00:36:04,200 所以我将要返回到这里 So I'll back up to here. 644 00:36:04,200 --> 00:36:06,280 我会说 我能把第一个皇后放在第二行吗 And I'll say, oh, can I put the first queen down in the 645 00:36:06,280 --> 00:36:07,510 second row? 646 00:36:07,510 --> 00:36:08,550 好吧 这样也不好 Well, that's no good. 647 00:36:08,550 --> 00:36:09,760 喔 我能把这个放在第三行嘛 Oh, can I put it down in the third row? 648 00:36:09,760 --> 00:36:12,790 好 这样不错 Well, that's good. 649 00:36:12,790 --> 00:36:14,290 现在 我能把第一个皇后放在第一列吗 Well, now can I put the next queen down 650 00:36:14,290 --> 00:36:15,380 in the first column? 651 00:36:15,380 --> 00:36:18,030 我不能再想象棋盘 Well, I can't visualize this chess board anymore, but I 652 00:36:18,030 --> 00:36:19,195 但是我觉得这样是对的 think that's right. 653 00:36:19,195 --> 00:36:20,450 并且 我将尝试下一个 And I try the next one. 654 00:36:20,450 --> 00:36:24,170 在每个地方 我尽可能的沿着数向下 And at each place, I go as far down this tree as I can. 655 00:36:24,170 --> 00:36:25,640 然后倒退 And I back up. 656 00:36:25,640 --> 00:36:28,970 如果我到了这里 并且发现我不能再往下了 If I get down to here and find no possibilities below there, 657 00:36:28,970 --> 00:36:31,740 我返回到这里 再次开始生成这个子树 I back all the way up to here, and now start again generating 658 00:36:31,740 --> 00:36:33,260 this sub-tree. 659 00:36:33,260 --> 00:36:35,050 并且我四处绕 And I sort of walk around. 660 00:36:35,050 --> 00:36:37,870 最后 如果我可以一路求解下来 And finally, if I ever manage to get all the way down, I've 661 00:36:37,870 --> 00:36:40,090 我将会得到答案 found a solution. 662 00:36:40,090 --> 00:36:45,020 这就是以前在人工智能编程中传统的范式 So that's a typical sort of paradigm that's used a lot in 663 00:36:45,020 --> 00:36:45,930 AI programming. 664 00:36:45,930 --> 00:36:47,300 这叫做回溯查找 It's called backtracking search. 665 00:36:47,300 --> 00:36:57,470 666 00:36:57,470 --> 00:37:03,860 这真得没有必要 And it's really unnecessary. 667 00:37:03,860 --> 00:37:06,550 你看当我想象的这个东西时 我感到疑惑了 You saw me get confused when I was visualizing this thing. 668 00:37:06,550 --> 00:37:08,550 你也看到了这个复杂性 And you see the complication. 669 00:37:08,550 --> 00:37:10,760 这个东西很难说 This is a complicated thing to say. 670 00:37:10,760 --> 00:37:12,390 为什么难呢 Why is it complicated? 671 00:37:12,390 --> 00:37:16,190 因为这个很花时间 Its because somehow this program is too inordinately 672 00:37:16,190 --> 00:37:18,580 concerned with time. 673 00:37:18,580 --> 00:37:19,200 太tmd的久了 It's too much-- 674 00:37:19,200 --> 00:37:21,670 我尝试了这个 又尝试了那个 I try this one, and I try this one, and I go back to the last 675 00:37:21,670 --> 00:37:22,320 然后 我返回到最前面的可能 possibility. 676 00:37:22,320 --> 00:37:24,340 这是一个复杂的事 And that's a complicated thing. 677 00:37:24,340 --> 00:37:28,590 如果我停止担心思考时间 If I stop worrying about time so much, then there's a much 678 00:37:28,590 --> 00:37:31,200 我将会得到一个更简单的方法来表述这个 simpler way to describe this. 679 00:37:31,200 --> 00:37:40,320 这个方法是 让我们想象 我有一个有k-1层的树 It says, let's imagine that I have in my hands the tree down 680 00:37:40,320 --> 00:37:43,400 to k minus 1 levels. 681 00:37:43,400 --> 00:37:50,670 看在第一个k列中 所有的放置皇后的可能性都在我手中了 See, suppose I had in my hands all possible ways to put down 682 00:37:50,670 --> 00:37:53,560 queens in the first k columns. 683 00:37:53,560 --> 00:37:54,610 假设我有了那个 Suppose I just had that. 684 00:37:54,610 --> 00:37:57,070 让我们不要担心我们如何能搞到它 Let's not worry about how we get it. 685 00:37:57,070 --> 00:37:59,200 好吧 我怎样进行扩充呢 Well, then, how do I extend that? 686 00:37:59,200 --> 00:38:01,420 我怎样找到所有在下一个列中放皇后的可能性呢 How do I find all possible ways to put down queens in the 687 00:38:01,420 --> 00:38:02,480 next column? 688 00:38:02,480 --> 00:38:03,620 这简单 It's really easy. 689 00:38:03,620 --> 00:38:12,210 对于我有的每个位置 For each of these positions I have, I think about putting 690 00:38:12,210 --> 00:38:16,160 我想把皇后放在每个行中来做下一个东西 down a queen in each row to make the next thing. 691 00:38:16,160 --> 00:38:18,930 然后 对于每个我放置的 我使用safe来进行filter And then for each one I put down, I filter those by the 692 00:38:18,930 --> 00:38:22,080 ones that are safe. 693 00:38:22,080 --> 00:38:24,190 所以代替 把树想成一步步生成的 So instead of thinking about this tree as generated step by 694 00:38:24,190 --> 00:38:26,860 假设我已经拥有了它 step, suppose I had it all there. 695 00:38:26,860 --> 00:38:29,680 696 00:38:29,680 --> 00:38:32,990 为了从k-1到k扩充它 And to extend it from level k minus 1 to level k, I just 697 00:38:32,990 --> 00:38:36,840 我只需要用所有的可能方法来扩充每个东西 need to extend each thing in all possible ways and only 698 00:38:36,840 --> 00:38:37,800 且只保留安全的东西 keep the ones that are safe. 699 00:38:37,800 --> 00:38:39,300 这将会给我一个k层树 And that will give me the tree to level k. 700 00:38:39,300 --> 00:38:41,675 这是一个解决八皇后问题的递归策略 And that's a recursive strategy for solving the eight 701 00:38:41,675 --> 00:38:44,530 queens problem. 702 00:38:44,530 --> 00:38:45,780 好的 我们来看看 All right, well, let's look at it. 703 00:38:45,780 --> 00:38:50,280 704 00:38:50,280 --> 00:38:54,360 在特定大小的棋盘中解决八皇后问题 To solve the eight queens problem on a board of some 705 00:38:54,360 --> 00:39:00,390 我们写一个叫填满列的子过程 fill-colums specified size, we write a sub-procedure called 706 00:39:00,390 --> 00:39:01,030 fill-columns. 707 00:39:01,030 --> 00:39:04,050 这个过程将会把皇后 Fill-columns is going to put down queens up 708 00:39:04,050 --> 00:39:06,086 一直放置到列k through column k. 709 00:39:06,086 --> 00:39:07,700 这里是递归的模式 And here's the pattern of the recursion. 710 00:39:07,700 --> 00:39:12,990 最后 我将会调用有大小的填充列的方法 I'm going to call fill-columns with the size eventually. 711 00:39:12,990 --> 00:39:15,630 所以fill-columns说 怎样才能把皇后 So fill-columns says how to put down queens safely in the 712 00:39:15,630 --> 00:39:19,255 安全的放置在这个棋盘中第一个k列 并且 first k columns of this chess board with a size number of 713 00:39:19,255 --> 00:39:20,360 rows in it. 714 00:39:20,360 --> 00:39:22,946 如果k=0 那么我们啥都不用干 If k is equal to 0, well, then I don't have to 715 00:39:22,946 --> 00:39:23,940 put anything down. 716 00:39:23,940 --> 00:39:26,710 我的结果只是一个空的棋盘 So my solution is just an empty chess board. 717 00:39:26,710 --> 00:39:28,070 否则 我将会做一些其他的事 Otherwise, I'm going to do some stuff. 718 00:39:28,070 --> 00:39:30,522 我将会用collect And I'm going to use collect. 719 00:39:30,522 --> 00:39:31,772 这里有collect And here's the collect. 720 00:39:31,772 --> 00:39:34,530 721 00:39:34,530 --> 00:39:40,590 我找到了所有在第k-1列中放皇后的方法 I find all ways to put down queens in the 722 00:39:40,590 --> 00:39:41,910 first k minus 1 columns. 723 00:39:41,910 --> 00:39:43,320 这里只是我设置的 And this was just what I set for. 724 00:39:43,320 --> 00:39:48,880 想象我有这样的树往下到k-1层 Imagine I have this tree down to k minus 1 levels. 725 00:39:48,880 --> 00:39:53,230 然后我找到所有尝试行的方法 And then I find all ways of trying a row, that's just each 726 00:39:53,230 --> 00:39:54,130 那只是每个可能行 of the possible rows. 727 00:39:54,130 --> 00:39:58,040 他是一定尺寸的行 所以那时enumerate 间距 They're size rows, so that's enumerate interval. 728 00:39:58,040 --> 00:40:03,950 现在我要做的是 我把我将要尝试的新的行和列k用剩下的皇后进行整合 And now what I do is I collect together the new row I'm going 729 00:40:03,950 --> 00:40:08,950 to try and column k with the rest of the queens. 730 00:40:08,950 --> 00:40:10,200 我邻接了位置 I adjoin a position. 731 00:40:10,200 --> 00:40:11,290 这是乔治的问题 This is George's problem. 732 00:40:11,290 --> 00:40:13,640 一个邻接的问题和safe差不多 An adjoined position is like safe. 733 00:40:13,640 --> 00:40:16,530 我们所做的事 是拿一行一列 和剩下的位置 然后做一个新的位置集合 It's a thing that takes a row and a column and the rest of 734 00:40:16,530 --> 00:40:19,660 the positions and makes a new position collection. 735 00:40:19,660 --> 00:40:26,230 所以 对于剩下的皇后 我邻接了一个新行和列的位置 So I adjoin a position of a new row and a new column to 736 00:40:26,230 --> 00:40:30,310 剩下的皇后可以用尝试所有可能性的方法在k-1列来做 the rest of the queens, where the rest of the queens runs 737 00:40:30,310 --> 00:40:32,870 through all possible ways of solving the problem 738 00:40:32,870 --> 00:40:34,620 in k minus 1 columns. 739 00:40:34,620 --> 00:40:39,730 新的行运行了所有行的可能性 And the new row runs through all possible rows such that it 740 00:40:39,730 --> 00:40:43,240 使得放在这里安全 was safe to put one there. 741 00:40:43,240 --> 00:40:46,500 这就是整个程序了 And that's the whole program. 742 00:40:46,500 --> 00:40:49,840 这是整个过程 There's the whole procedure. 743 00:40:49,840 --> 00:40:51,990 不仅仅是这样 这不仅仅解决八皇后问题 Not only that, that doesn't just solve the eight queens 744 00:40:51,990 --> 00:40:56,010 还顺手给出了八皇后问题的所有解 problem, it gives you all solutions to the 745 00:40:56,010 --> 00:40:56,680 eight queens problem. 746 00:40:56,680 --> 00:40:58,480 当你搞定了 你就有一个流 When you're done, you have a stream. 747 00:40:58,480 --> 00:41:00,650 流中的元素是解决这个问题的所有可能性 And the elements of that stream are all possible ways 748 00:41:00,650 --> 00:41:01,900 of solving that problem. 749 00:41:01,900 --> 00:41:05,310 750 00:41:05,310 --> 00:41:06,260 为什么这个更加简单呢 Why is that simpler? 751 00:41:06,260 --> 00:41:10,170 好吧 我们抛出了整个想法 这个想法是一些在时间中发生的,有状态的过程 Well, we threw away the whole idea that this is some process 752 00:41:10,170 --> 00:41:12,720 that happens in time with state. 753 00:41:12,720 --> 00:41:14,420 并且 我们只会说 这是东西的整个集合 And we just said it's a whole collection of stuff. 754 00:41:14,420 --> 00:41:18,260 这就是更加简单的原因 And that's why it's simpler. 755 00:41:18,260 --> 00:41:20,110 我们改变了我们的观念 We've changed our view. 756 00:41:20,110 --> 00:41:22,820 记住我们今天开始的地方 Remember, that's where we started today. 757 00:41:22,820 --> 00:41:26,230 我们搞变了我们的这我们尝试去建模的东西是什么的观念 We've changed our view of what it is we're trying to model. 758 00:41:26,230 --> 00:41:30,570 我们停止对随着时间的发展的,并有过程和状态的物体进行建模 we stop modeling things that evolve in time and have steps 759 00:41:30,570 --> 00:41:31,750 and have state. 760 00:41:31,750 --> 00:41:33,990 作为替代 我们尽力给像粉笔飞行这样的全局的东西进行建模 And instead, we're trying to model this global thing like 761 00:41:33,990 --> 00:41:37,950 the whole flight of the chalk, rather than its 762 00:41:37,950 --> 00:41:40,750 而不是它们的在每个时间的状态 state at each instant. 763 00:41:40,750 --> 00:41:42,000 有神马问题 Any questions? 764 00:41:42,000 --> 00:41:43,810 765 00:41:43,810 --> 00:41:46,190 在我看来 回溯法将会找到它能找到的第一个解 AUDIENCE: It looks to me like backtracking would be 766 00:41:46,190 --> 00:41:49,970 searching for the first solution it can find, whereas 767 00:41:49,970 --> 00:41:54,030 但是这个递归搜索将会查找所有的解 this recursive search would be looking for all solutions. 768 00:41:54,030 --> 00:41:58,090 而且看起来 如果你有足够大的空间去查找 And it seems that if you have a large enough area to search, 769 00:41:58,090 --> 00:42:01,360 第二个将会变得不可能 that the second is going to become impossible. 770 00:42:01,360 --> 00:42:07,610 好的 这个问题的解就是我们剩下这节课所要讲的内容 PROFESSOR: OK, the answer to that question is the whole 771 00:42:07,610 --> 00:42:08,570 rest of this lecture. 772 00:42:08,570 --> 00:42:10,540 这是一个好问题 It's exactly the right question. 773 00:42:10,540 --> 00:42:13,522 774 00:42:13,522 --> 00:42:15,540 如果你不尝试提前预见到后面的课 And without trying to anticipate the lecture too 775 00:42:15,540 --> 00:42:19,910 你应该开始怀疑这个点 much, you should start being suspicious at this point, and 776 00:42:19,910 --> 00:42:22,220 这个的确是令人怀疑的 exactly those kinds of suspicions. 777 00:42:22,220 --> 00:42:24,830 这是好的 但是这不是非常的不方便吗 It's wonderful, but isn't it so terribly inefficient? 778 00:42:24,830 --> 00:42:28,100 这是我们现在进行的 That's where we're going. 779 00:42:28,100 --> 00:42:30,020 所以我现在不说 等等再揭晓答案 So I won't answer now, but I'll answer later. 780 00:42:30,020 --> 00:42:33,350 781 00:42:33,350 --> 00:42:34,600 让我们休息一下 OK, let's take a break. 782 00:42:34,600 --> 00:43:29,650 783 00:43:29,650 --> 00:43:35,600 现在你应该开始怀疑了 Well, by now you should be starting to get suspicious. 784 00:43:35,600 --> 00:43:41,450 看 我已经展示了这个简单优雅的将程序放在一起的方法 See, I've showed your this simple, elegant way of putting 785 00:43:41,450 --> 00:43:46,440 不像这些另外的累积奇数的传统方法或者算奇数的斐波那契数 programs together, very unlike these other traditional 786 00:43:46,440 --> 00:43:50,490 programs that sum the odd squares or compute the odd 787 00:43:50,490 --> 00:43:53,740 Fibonacci numbers. 788 00:43:53,740 --> 00:43:57,080 也不像这些混合enumerator filter 和accumulator的方法 Very unlike these programs that mix up the enumerator and 789 00:43:57,080 --> 00:44:00,440 the filter and the accumulator. 790 00:44:00,440 --> 00:44:04,770 通过混合 我们没有所有这些美妙的概念上的这些流元件的优点 And by mixing it up, we don't have all of these wonderful 791 00:44:04,770 --> 00:44:07,990 conceptual advantages of these streams pieces, these 792 00:44:07,990 --> 00:44:09,840 这些为了把许多程序整合在一起的美妙的混合和匹配部件 wonderful mix and match components for putting 793 00:44:09,840 --> 00:44:13,800 together lots and lots of programs. 794 00:44:13,800 --> 00:44:15,810 再另一方面 你能见到的所有程序大部分都和这个屌丝程序一样 On the other hand, most of the programs you've seen look like 795 00:44:15,810 --> 00:44:18,340 these ugly ones. 796 00:44:18,340 --> 00:44:19,460 为什么呢 Why's that? 797 00:44:19,460 --> 00:44:23,705 计算机科学家们可能没有注意到如果你仅仅做了这个事 Can it possibly be that computer scientists are so 798 00:44:23,705 --> 00:44:28,370 obtuse that they don't notice that if you'd merely did this 799 00:44:28,370 --> 00:44:33,620 然后你可以获得这个这个程序的优雅性吗 thing, then you can get this great programming elegance? 800 00:44:33,620 --> 00:44:36,760 这里得有一个catch There's got to be a catch. 801 00:44:36,760 --> 00:44:39,510 并且事实上 我们可以很容易看到 什么是catch And it's actually pretty easy to see what the catch is. 802 00:44:39,510 --> 00:44:42,030 让我们想一下下面的问题 Let's think about the following problem. 803 00:44:42,030 --> 00:44:47,510 假设我告诉你找到在10000-一百万里第二个素数 Suppose I tell you to find the second prime between 10,000 804 00:44:47,510 --> 00:44:51,020 或者如果你的计算机足够强大 and 1 million, or if your computer's larger, say between 805 00:44:51,020 --> 00:44:54,105 比如说10000到1000亿 10,000 and 100 billion, or something. 806 00:44:54,105 --> 00:44:55,550 然后你说 这很容易 And you say, oh, that's easy. 807 00:44:55,550 --> 00:44:57,080 我能用流来搞定 I can do that with a stream. 808 00:44:57,080 --> 00:45:01,530 我需要做的就是枚举从10000到1百万 All I do is I enumerate the interval 809 00:45:01,530 --> 00:45:04,160 from 10,000 to 1 million. 810 00:45:04,160 --> 00:45:06,800 然后我得到了所有从10000到1百万中挑选的数字 So I get all those integers from 10,000 to 1 million. 811 00:45:06,800 --> 00:45:10,520 我们为了素数性对它们进行filter操作 然后检测所有的数 看看是不是素数 I filter them for prime-ness, so test all of them and see if 812 00:45:10,520 --> 00:45:11,762 they're prime. 813 00:45:11,762 --> 00:45:13,170 然后我拿出第二个元素 And I take the second element. 814 00:45:13,170 --> 00:45:16,130 这是尾部的第一个 That's the head of the tail. 815 00:45:16,130 --> 00:45:17,380 这就非常搞笑了 Well, that's clearly pretty ridiculous. 816 00:45:17,380 --> 00:45:21,660 817 00:45:21,660 --> 00:45:24,620 在一开始我们甚至没有在机器中有存放整数的地方 We'd not even have room in the machine to store the integers 818 00:45:24,620 --> 00:45:27,040 更不用说来检测他们了 in the first place, much less to test them. 819 00:45:27,040 --> 00:45:29,810 然后我只要第二个 And then I only want the second one. 820 00:45:29,810 --> 00:45:36,500 这种传统的编程风格的威力也有它的弱点 See, the power of this traditional programming style 821 00:45:36,500 --> 00:45:39,860 is exactly its weakness, that we're mixing up the 822 00:45:39,860 --> 00:45:45,090 那是我们混合了enumerating testing accumulating enumerating and the testing and the accumulating. 823 00:45:45,090 --> 00:45:46,670 所以我们不做所有的事 So we don't do it all. 824 00:45:46,670 --> 00:45:52,580 所以使它在概念上更加丑陋的这个东西使它更加有效 So the very thing that makes it conceptually ugly is the 825 00:45:52,580 --> 00:45:55,210 very thing that makes it efficient. 826 00:45:55,210 --> 00:45:57,800 是这样混合的 It's this mixing up. 827 00:45:57,800 --> 00:45:59,840 所以这看起来我们在早上讲的所有的这些东西只会使你们疑惑 So it seems that all I've done this morning so far is just 828 00:45:59,840 --> 00:46:00,420 confuse you. 829 00:46:00,420 --> 00:46:02,930 我展示给你们这个优雅的编程方法可能可以工作 I showed you this wonderful way that programming might 830 00:46:02,930 --> 00:46:05,840 除了那个不行 work, except that it doesn't. 831 00:46:05,840 --> 00:46:09,040 好吧 这里是美好的事发生的地方 Well, here's where the wonderful thing happens. 832 00:46:09,040 --> 00:46:13,210 在这个游戏里 我门真正可以吃蛋糕 并吃它 It turns out in this game that we really can have our cake 833 00:46:13,210 --> 00:46:14,870 and eat it too. 834 00:46:14,870 --> 00:46:20,280 我的意思是 我们真的可以完全像我写和安排的那样使用流编程 And what I mean by that is that we really can write 835 00:46:20,280 --> 00:46:24,210 stream programs exactly like the ones I wrote and arrange 836 00:46:24,210 --> 00:46:28,830 当机器真正运行 things so that when the machine actually runs, it's as 837 00:46:28,830 --> 00:46:31,690 它运行起来和混合generation和test传统编程风格一样有效率 efficient as running this traditional programming style 838 00:46:31,690 --> 00:46:36,310 that mixes up the generation and the test. 839 00:46:36,310 --> 00:46:40,770 好吧 那听起来很神奇 Well, that sounds pretty magic. 840 00:46:40,770 --> 00:46:43,690 这个的关键是流不是列表 The key to this is that streams are not lists. 841 00:46:43,690 --> 00:46:48,090 842 00:46:48,090 --> 00:46:50,070 等等 我们将会小心的看到 We'll see this carefully in a second, but for now, let's 843 00:46:50,070 --> 00:46:52,115 但现在 让我们再次看看幻灯片 take a look at that slide again. 844 00:46:52,115 --> 00:46:55,060 你应该有的信号处理系统的图片是 The image you should have here of this signal processing 845 00:46:55,060 --> 00:47:00,940 system is that what's going to happen is there's this box 846 00:47:00,940 --> 00:47:05,360 在这里有一个盒子里面有一个整数 that has the integers sitting in it. 847 00:47:05,360 --> 00:47:08,680 这里有这个filter来连接 And there's this filter that's connected to it and it's 848 00:47:08,680 --> 00:47:10,940 并且这个揪住了它们 tugging on them. 849 00:47:10,940 --> 00:47:13,680 然后 那里有揪住这个东西的某人 And then there's someone who's tugging on this stuff saying 850 00:47:13,680 --> 00:47:16,790 说 那个从filter中出来 what comes out of the filter. 851 00:47:16,790 --> 00:47:19,630 你应该有的图片是 And the image you should have is that someone says, well, 852 00:47:19,630 --> 00:47:24,590 某些人说 好吧 第一个素数是什么 what's the first prime, and tugs on this filter. 853 00:47:24,590 --> 00:47:28,020 并且这个filter揪住了整数 And the filter tugs on the integers. 854 00:47:28,020 --> 00:47:29,830 并且你只看这些 And you look only at that much, and then say, oh, I 855 00:47:29,830 --> 00:47:30,930 然后说 噢 我真的想要第二个 really wanted the second one. 856 00:47:30,930 --> 00:47:33,710 第二个素数是什么 What's the second prime? 857 00:47:33,710 --> 00:47:37,730 没有计算完成 除了当你揪住那些东西 And that no computation gets done except when you tug on 858 00:47:37,730 --> 00:47:40,500 these things. 859 00:47:40,500 --> 00:47:41,410 让我们再来试试 Let me try that again. 860 00:47:41,410 --> 00:47:43,815 这是一个小的设备 This is a little device. 861 00:47:43,815 --> 00:47:46,400 这是一个由Eric Grimson 发明的小型的流机器 This is a little stream machine invented by Eric 862 00:47:46,400 --> 00:47:49,830 这个大神曾经在麻省理工教这门课 Grimson who's been teaching this course at MIT. 863 00:47:49,830 --> 00:47:52,940 并且这里的图片是一个东西的流 And the image is here's a stream of stuff, like a whole 864 00:47:52,940 --> 00:47:54,780 像一串整数 bunch of the integers. 865 00:47:54,780 --> 00:47:58,700 并且这里有一些处理中的元素 And here's some processing elements. 866 00:47:58,700 --> 00:48:02,600 并且 如果说 资格赛map的filter的filter或者一些东西 And if, say, it's filter of filter of map, or something. 867 00:48:02,600 --> 00:48:05,570 868 00:48:05,570 --> 00:48:08,760 并且如果我真的尝试用流作为列表实现 And if I really tried to implement that with streams as 869 00:48:08,760 --> 00:48:11,520 我想说得是 我已有了这个列表 lists, what I'd say is, well, I've got this list of things, 870 00:48:11,520 --> 00:48:12,670 现在 我开始使用第一个filter and now I do the first filter. 871 00:48:12,670 --> 00:48:14,070 做所有的这些处理 So do all this processing. 872 00:48:14,070 --> 00:48:18,570 并且我拿这个来一直进行不断处理 And I take this and I process and I process and I process 873 00:48:18,570 --> 00:48:19,610 and I process. 874 00:48:19,610 --> 00:48:21,910 现在 我已经得到了这个新的流 And now I'm got this new stream. 875 00:48:21,910 --> 00:48:24,070 现在我把这结果放在我手上某处 Now I take that result in my hand someplace. 876 00:48:24,070 --> 00:48:25,260 并且把第二个和那个接通 And I put that through the second one. 877 00:48:25,260 --> 00:48:28,110 然后 我处理整个东西 And I process the whole thing. 878 00:48:28,110 --> 00:48:29,510 这个有一个新的流 And there's this new stream. 879 00:48:29,510 --> 00:48:32,130 880 00:48:32,130 --> 00:48:35,230 然后 我拿那个结果 并且我把它和这个用相同方法接通 And then I take the result and I put it all the way through 881 00:48:35,230 --> 00:48:36,360 this one the same way. 882 00:48:36,360 --> 00:48:41,760 这些将会是流编程将会发生的 That's what would happen to these stream programs if 883 00:48:41,760 --> 00:48:43,860 如果流只是一个列表 streams were just lists. 884 00:48:43,860 --> 00:48:46,065 但是实际上 流不是列表 这只是流 But in fact, streams aren't lists, they're streams. And 885 00:48:46,065 --> 00:48:47,240 你将会有的图是一种有点更像这个的东西 the image you should have is something a little 886 00:48:47,240 --> 00:48:50,230 bit more like this. 887 00:48:50,230 --> 00:48:55,880 我通过数据把这些小玩意连接 I've got these gadgets connected up by this data 888 00:48:55,880 --> 00:48:57,130 那个将会从它们那里流出 that's flowing out of them. 889 00:48:57,130 --> 00:48:59,960 890 00:48:59,960 --> 00:49:04,190 这里是我原始的流的来源 And here's my original source of the streams. It might be 891 00:49:04,190 --> 00:49:05,980 这可能开始生成整数 starting to generate the integers. 892 00:49:05,980 --> 00:49:07,580 现在 如果我想要一个结果 会发生什么呢 And now, what happens if I want a result? 893 00:49:07,580 --> 00:49:10,200 我把在这里最后的东西揪住 I tug on the end here. 894 00:49:10,200 --> 00:49:13,090 这个元素说 挖 我需要更多的数据 And this element says, gee, I need some more data. 895 00:49:13,090 --> 00:49:15,830 所以 这个到这里 并且揪住那个 So this one comes here and tugs on that one. 896 00:49:15,830 --> 00:49:17,890 并且它说 挖 我需要更多的数据 And it says, gee, I need some more data. 897 00:49:17,890 --> 00:49:19,960 并且这个揪住了这个可能是一个filter的东西 And this one tugs on this thing, which might be a 898 00:49:19,960 --> 00:49:21,640 并且说 挖 我需要更多的数据 filter, and says, gee, I need some more data. 899 00:49:21,640 --> 00:49:24,755 并且只当 这些在这里的最后的东西和我揪住一样多时 And only as much of this thing at the end here gets generated 900 00:49:24,755 --> 00:49:25,780 as I tugged. 901 00:49:25,780 --> 00:49:28,030 并且只当 这些通过处理单元的东西和我抓得一样多时 And only as much of this stuff goes through the processing 902 00:49:28,030 --> 00:49:30,760 units as I'm pulling on the end I need. 903 00:49:30,760 --> 00:49:33,720 那才是你应该有的画面 That's the image you should have of the difference between 904 00:49:33,720 --> 00:49:36,580 实现你到底该怎样做的区别 implementing what we're actually going to do and if 905 00:49:36,580 --> 00:49:37,830 并且如果流是列表的话 streams were lists. 906 00:49:37,830 --> 00:49:40,600 907 00:49:40,600 --> 00:49:42,430 好吧 我们怎样做这些事 Well, how do we make this thing? 908 00:49:42,430 --> 00:49:43,400 我希望你能有这些图片 I hope you have the image. 909 00:49:43,400 --> 00:49:44,947 窍门是怎样做它 The trick is how to make it. 910 00:49:44,947 --> 00:49:47,930 911 00:49:47,930 --> 00:49:52,080 我们想要处理这个流 将它变成数据结构递增计算它本身 We want to arrange for a stream to be a data structure 912 00:49:52,080 --> 00:49:55,670 that computes itself incrementally, an on-demand 913 00:49:55,670 --> 00:49:56,920 按需数据结构 data structure. 914 00:49:56,920 --> 00:49:59,220 915 00:49:59,220 --> 00:50:02,700 并且基本思想是 And the basic idea is, again, one of the very basic ideas 916 00:50:02,700 --> 00:50:04,490 再说一下 这个整个课的基本思想是 that we're seeing throughout the whole course. 917 00:50:04,490 --> 00:50:07,440 那是 在程序和数据之间没有严格的界限 And that is that there's not a firm distinction between 918 00:50:07,440 --> 00:50:09,240 programs and data. 919 00:50:09,240 --> 00:50:12,260 流将会同步这些数据 So what a stream is going to be is simultaneously this data 920 00:50:12,260 --> 00:50:15,270 像这个树的叶子的流 structure that you think of, like the stream of the leaves 921 00:50:15,270 --> 00:50:16,810 of this tree. 922 00:50:16,810 --> 00:50:18,880 但同时 这将会变成聪明的并有计算方法在其中的过程 But at the same time, it's going to be a very clever 923 00:50:18,880 --> 00:50:23,550 procedure that has the method of computing in it. 924 00:50:23,550 --> 00:50:25,930 好吧 让我们来试试这个 Well, let me try this. 925 00:50:25,930 --> 00:50:28,460 这个结果是 我们不要更加多的原理 It's going to turn out that we don't need any more mechanism. 926 00:50:28,460 --> 00:50:31,150 我们已经从一个事实中有了我们需要的所有东西 We already have everything we need simply from the fact that 927 00:50:31,150 --> 00:50:32,770 我们知道如何处理作为第一级对象的过程 we know how to handle procedures 928 00:50:32,770 --> 00:50:35,460 as first-class objects. 929 00:50:35,460 --> 00:50:36,880 好吧 让我们看下这个key Well, let's go back to the key. 930 00:50:36,880 --> 00:50:39,030 关键是 记住 我们有这些操作 The key is, remember, we had these operations. 931 00:50:39,030 --> 00:50:48,080 cons流 头和尾 CONS-stream and head and tail. 932 00:50:48,080 --> 00:50:51,580 当我开始 我说 你可以将这个想象成cons When I started, I said you can think about this as CONS and 933 00:50:51,580 --> 00:50:53,340 把那个想象成car 把那个相信成cdr think about this as CAR and think about that as 934 00:50:53,340 --> 00:50:55,080 但这不是 CDR, but it's not. 935 00:50:55,080 --> 00:50:57,550 现在 让我们看看这些到底是什么 Now, let's look at what they really are. 936 00:50:57,550 --> 00:51:09,360 x和y的cons流将变成接下来东西的缩写 Well, CONS-stream of x and y is going to be an abbreviation 937 00:51:09,360 --> 00:51:19,540 for the following thing. 938 00:51:19,540 --> 00:51:24,470 cons产生一个序对 普通的cons CONS form a pair, ordinary CONS, of x to a thing called 939 00:51:24,470 --> 00:51:28,000 由一个x和一个delay y构成 delay of y. 940 00:51:28,000 --> 00:51:31,188 941 00:51:31,188 --> 00:51:34,670 在我解释那个之前,让我们来写剩余的部分 And before I explain that, let me go and write the rest. The 942 00:51:34,670 --> 00:51:39,790 流的头将会变成car head of a stream is going to be just the CAR. 943 00:51:39,790 --> 00:51:42,380 944 00:51:42,380 --> 00:51:47,610 流的尾部将会变成一种叫 force 流的cdr And the tail of a stream is going to be a thing called 945 00:51:47,610 --> 00:51:56,120 force the CDR of the stream. 946 00:51:56,120 --> 00:51:58,060 现在让我解释这些 Now let me explain this. 947 00:51:58,060 --> 00:52:01,420 延时将会变成一件特别神奇的事 Delay is going to be a special magic thing. 948 00:52:01,420 --> 00:52:06,240 延时做的是拿一个表达式产生一个计算当你要求表达式的承诺 What delay does is take an expression and produce a 949 00:52:06,240 --> 00:52:08,380 promise to compute that expression 950 00:52:08,380 --> 00:52:10,600 when you ask for it. 951 00:52:10,600 --> 00:52:11,980 在这里不做任何计算 It doesn't do any computation here. 952 00:52:11,980 --> 00:52:14,820 这仅仅给你一个延时 It just gives you a rain check. 953 00:52:14,820 --> 00:52:17,110 这产生了一个承诺 It produces a promise. 954 00:52:17,110 --> 00:52:23,280 cons流说 我将做一个x And CONS-stream says I'm going to put together in a pair x 955 00:52:23,280 --> 00:52:25,360 和一个承诺的序对来计算y and a promise to compute y. 956 00:52:25,360 --> 00:52:28,230 957 00:52:28,230 --> 00:52:30,200 现在 如果你想要头 这只是序对里的car Now, if I want the head, that's just the CAR that I put 958 00:52:30,200 --> 00:52:31,840 in the pair. 959 00:52:31,840 --> 00:52:34,350 这个的关键是 尾将会在承诺中force调用 And the key is that the tail is going to be-- 960 00:52:34,350 --> 00:52:39,110 force calls in that promise. 961 00:52:39,110 --> 00:52:43,690 尾说 好吧 取得这个承诺 然后 在那个承诺中调用 Tail says, well, take that promise and now 962 00:52:43,690 --> 00:52:44,610 call in that promise. 963 00:52:44,610 --> 00:52:47,430 然后我们计算那个东西 And then we compute that thing. 964 00:52:47,430 --> 00:52:48,740 这就是工作的方法 That's how this is going to work. 965 00:52:48,740 --> 00:52:51,550 那个就是cons流 头 和 尾了 That's what CONS-stream, head, and tail really are. 966 00:52:51,550 --> 00:52:54,196 967 00:52:54,196 --> 00:52:55,570 现在 让我们来看看这个怎样工作 Now, let's see how this works. 968 00:52:55,570 --> 00:52:58,410 我们将会非常小心地过一遍 And we'll go through this fairly carefully. 969 00:52:58,410 --> 00:53:01,990 在这个 计算在一万和一百万之间的第二个素数 的例子中 我们将会看到这是如何工作的 We're going to see how this works in this example of 970 00:53:01,990 --> 00:53:08,650 computing the second prime between 10,000 and a million. 971 00:53:08,650 --> 00:53:11,610 ok 让我们开始 我们有这个表达式 OK, so we start off and we have this expression. 972 00:53:11,610 --> 00:53:15,820 973 00:53:15,820 --> 00:53:20,380 第二个素数-- 为在一万和一百万的整数素数性进行filtering The second prime-- the head of the tail of the result of 974 00:53:20,380 --> 00:53:24,060 filtering for primality the integers between 975 00:53:24,060 --> 00:53:26,710 10,000 and 1 million. 976 00:53:26,710 --> 00:53:28,400 现在 那是什么 Now, what is that? 977 00:53:28,400 --> 00:53:35,790 这是一万和一百万之间的间距 What that is, that interval between 10,000 and 1 million, 978 00:53:35,790 --> 00:53:37,480 好吧 如果你探查enumerate的间距 well, if you trace through enumerate interval, there 979 00:53:37,480 --> 00:53:40,250 这里建立了一个cons流 builds a CONS-stream. 980 00:53:40,250 --> 00:53:45,880 并且 cons流是10000的cons的许诺来计算10001到一百万 And the CONS-stream is the CONS of 10,000 to a promise to 981 00:53:45,880 --> 00:53:54,480 compute the integers between 10,001 and 1 million. 982 00:53:54,480 --> 00:53:55,750 所以 那就是这个表达式了 So that's what this expression is. 983 00:53:55,750 --> 00:53:57,640 这里 我使用代换模型 Here I'm using the substitution model. 984 00:53:57,640 --> 00:53:59,690 我们能使用代换模型的原因是因为我们没有副作用和状态 And we can use the substitution model because we 985 00:53:59,690 --> 00:54:01,010 don't have side effects and state. 986 00:54:01,010 --> 00:54:04,270 987 00:54:04,270 --> 00:54:07,860 所以 我们有一个10000的cons的许诺来计算剩余的整数 So I have CONS of 10,000 to a promise to compute the rest of 988 00:54:07,860 --> 00:54:08,380 the integers. 989 00:54:08,380 --> 00:54:09,850 所以到现在为止只有一个整数得到了enumerated So only one integer, so far, got enumerated. 990 00:54:09,850 --> 00:54:14,380 991 00:54:14,380 --> 00:54:16,580 好的 我将会为了素数性来filter这些东西 Well, I'm going to filter that thing for primality. 992 00:54:16,580 --> 00:54:19,900 993 00:54:19,900 --> 00:54:22,360 再次 你将会回去看过了filter代码 Again, you go back and look at the filter code. 994 00:54:22,360 --> 00:54:25,460 filter首先测试头 What the filter will first do is test the head. 995 00:54:25,460 --> 00:54:31,580 所以在这种情况下 filter将会测试一万 So in this case, the filter will test 10,000 and say, oh, 996 00:54:31,580 --> 00:54:33,500 然后说一万不是素数 10,000's not prime. 997 00:54:33,500 --> 00:54:36,260 所以我不得不递归的过滤尾 Therefore, what I have to do recursively 998 00:54:36,260 --> 00:54:39,220 is filter the tail. 999 00:54:39,220 --> 00:54:42,550 这个是什么的尾呢 好吧 这是这个有许诺序对的尾序对的尾 And what's the tail of it, well, that's the tail of this 1000 00:54:42,550 --> 00:54:46,340 pair with a promise in it. 1001 00:54:46,340 --> 00:54:49,680 尾进来了 然后说 好吧 我将要迫使那个 Tail now comes in and says, well, I'm going to force that. 1002 00:54:49,680 --> 00:54:53,790 我将要迫使那个许诺 它的意思是 I'm going to force that promise, which means now I'm 1003 00:54:53,790 --> 00:55:00,880 现在我将要计算10001到一百万之中的整数 going to compute the integers between 10,001 and 1 million. 1004 00:55:00,880 --> 00:55:02,970 好的 所以这个filter现在着眼于那里 OK, so this filter now is looking at that. 1005 00:55:02,970 --> 00:55:07,810 1006 00:55:07,810 --> 00:55:10,100 那个枚举了它本身 好吧 现在我们回到原始枚举情况 That enumerate itself, well, now we're back in the original 1007 00:55:10,100 --> 00:55:11,960 enumerate situation. 1008 00:55:11,960 --> 00:55:16,920 enumerate是第一个东西的cons 10001 The enumerate is the CONS of the first thing, 10,001, onto 1009 00:55:16,920 --> 00:55:19,740 映射到一个许诺来计算剩下的 a promise to compute the rest. 1010 00:55:19,740 --> 00:55:23,060 所以 现在原始的filter将会着眼于10001 So now the primality filter is going to go look at 10,001. 1011 00:55:23,060 --> 00:55:25,120 这将要决定它像那个还是不像 It's going to decide if it likes that or not. 1012 00:55:25,120 --> 00:55:27,550 这个结果是10001不是素数 It turns out 10,001 isn't prime. 1013 00:55:27,550 --> 00:55:29,610 所以我将会再次连续不断的进行force So it'll force it again and again and again. 1014 00:55:29,610 --> 00:55:32,920 1015 00:55:32,920 --> 00:55:37,100 最后 我觉得第一个素数会是10009 And finally, I think the first prime it hits is 10,009. 1016 00:55:37,100 --> 00:55:40,465 然后 在这个点上 它将会停止 And at that point, it'll stop. 1017 00:55:40,465 --> 00:55:42,500 那个将会变成第一个素数 And that will be the first prime, and then eventually, 1018 00:55:42,500 --> 00:55:45,240 最后 这将需要第二个素数 it'll need the second prime. 1019 00:55:45,240 --> 00:55:47,030 所以在那个点上 So at that point, it will go again. 1020 00:55:47,030 --> 00:55:51,880 所以你会发现生成的不会比你实际需要的多 So you see what happens is that no more gets generated 1021 00:55:51,880 --> 00:55:53,130 than you actually need. 1022 00:55:53,130 --> 00:55:56,690 1023 00:55:56,690 --> 00:56:00,060 那个enumerator将不会比filter生成更多整数 That enumerator is not going to generate any more integers 1024 00:56:00,060 --> 00:56:02,410 引入东西来检测素数性 than the filter asks it for as it's pulling in things to 1025 00:56:02,410 --> 00:56:04,930 check for primality. 1026 00:56:04,930 --> 00:56:07,290 并且这个filter将不会生成比你要求更多的东西 And the filter is not going to generate any more stuff than 1027 00:56:07,290 --> 00:56:11,255 这是尾的头 you ask it for, which is the head of the tail. 1028 00:56:11,255 --> 00:56:17,180 你看 我们把混合的生成和测试放入计算机 You see, what's happened is we've put that mixing of 1029 00:56:17,180 --> 00:56:20,130 并且检测在电脑中究竟发生了什么 generation and test into what actually happens in the 1030 00:56:20,130 --> 00:56:24,250 虽然 那个从我们的程序看来不是很明显 computer, even though that's not apparently what's 1031 00:56:24,250 --> 00:56:28,160 happening from looking at our programs. 1032 00:56:28,160 --> 00:56:30,230 好的 那看起来简单 OK, well, that seemed easy. 1033 00:56:30,230 --> 00:56:33,326 所有的这些机制会被放入这个神奇的delay中 All of this mechanism got put into this magic delay. 1034 00:56:33,326 --> 00:56:36,900 所以 你会说 那将会是有魔法的地方 So you're saying, gee, that must be where the magic is. 1035 00:56:36,900 --> 00:56:39,070 但是看这里也没有魔法 But see there's no magic there either. 1036 00:56:39,070 --> 00:56:40,610 你知道什么是delay You know what delay is. 1037 00:56:40,610 --> 00:56:50,040 在一些表达式上的delay只是一个缩略词 Delay on some expression is just an abbreviation for-- 1038 00:56:50,040 --> 00:56:53,400 1039 00:56:53,400 --> 00:56:56,490 好吧 计算表达式的primise是什么 well, what's a promise to compute an expression? 1040 00:56:56,490 --> 00:57:00,700 lambda of nil 一个没有参数的过程 Lambda of nil, procedure of no arguments, which is that 1041 00:57:00,700 --> 00:57:03,000 就是那个表达式 expression. 1042 00:57:03,000 --> 00:57:03,930 那就是这个过程 That's what a procedure is. 1043 00:57:03,930 --> 00:57:06,050 我将会计算一个表达式 It says I'm going to compute an expression. 1044 00:57:06,050 --> 00:57:07,460 什么是force What's force? 1045 00:57:07,460 --> 00:57:10,800 我怎么着手一个许诺 How do I take up a promise? 1046 00:57:10,800 --> 00:57:15,890 好的 一些过程的force 一个许诺 只是运行它 Well, force of some procedure, a promise, is just run it. 1047 00:57:15,890 --> 00:57:18,710 1048 00:57:18,710 --> 00:57:20,120 做好了 Done. 1049 00:57:20,120 --> 00:57:23,580 所以 这里完全没有魔法 So there's no magic there at all. 1050 00:57:23,580 --> 00:57:26,440 好吧 我们做了啥 Well, what have we done? 1051 00:57:26,440 --> 00:57:29,510 我们说 老风格 We said the old style, traditional style of 1052 00:57:29,510 --> 00:57:30,960 传统的编程风格将会是更加有效的 programming is more efficient. 1053 00:57:30,960 --> 00:57:35,260 流是更加的清晰明白的 And the stream thing is more perspicuous. 1054 00:57:35,260 --> 00:57:40,070 并且我们使用delay设法使流过程运行的像其他的过程一样 And we managed to make the stream procedures run like the 1055 00:57:40,070 --> 00:57:43,350 other procedures by using delay. 1056 00:57:43,350 --> 00:57:46,880 delay为我们做的事是在我们从发生在机器中的真实顺序中程序事务上表面的顺序上进行解耦 And the thing that delay did for us was to de-couple the 1057 00:57:46,880 --> 00:57:52,150 apparent order of events in our programs from the actual 1058 00:57:52,150 --> 00:57:54,440 order of events that happened in the machine. 1059 00:57:54,440 --> 00:57:56,540 那就是delay所做的 That's really what delay is doing. 1060 00:57:56,540 --> 00:57:58,290 就是这样 That's exactly the whole point. 1061 00:57:58,290 --> 00:58:04,720 我们放弃了当我们的过程开始运行的想法 We've given up the idea that our procedures, as they run, 1062 00:58:04,720 --> 00:58:09,182 或者 当我们看到它们 映射一些时间的清晰概念 or as we look at them, mirror some clear notion of time. 1063 00:58:09,182 --> 00:58:12,960 然后 通过放弃那个 我们给delay自由来处理在计算事件的顺序 And by giving that up, we give delay the freedom to arrange 1064 00:58:12,960 --> 00:58:16,690 the order of events in the computation the way it likes. 1065 00:58:16,690 --> 00:58:17,610 整个思想就是这样 That's the whole idea. 1066 00:58:17,610 --> 00:58:20,640 我们de-couple在我们程序上事件表面上的顺序 We de-couple the apparent order of events in our 1067 00:58:20,640 --> 00:58:24,200 programs from the actual order of events in the computer. 1068 00:58:24,200 --> 00:58:25,770 好的 这里还有一个细节 OK, well there's one more detail. 1069 00:58:25,770 --> 00:58:27,750 这是是技术上的细节 It's just a technical detail, but it's actually 1070 00:58:27,750 --> 00:58:29,730 但是 这个其实是很重要的 an important one. 1071 00:58:29,730 --> 00:58:32,190 当你运行了这些递归循环的程序 As you run through these recursive programs unwinding, 1072 00:58:32,190 --> 00:58:35,360 你将会看到很多像这个的东西 像尾部的尾部的尾部 you'll see a lot of things that look like tail of the 1073 00:58:35,360 --> 00:58:39,320 tail of the tail. 1074 00:58:39,320 --> 00:58:41,840 当我使用consing往下到一个流 这将是会发生的事 That's the kind of thing that would happen as I go CONSing 1075 00:58:41,840 --> 00:58:43,860 down a stream all the way. 1076 00:58:43,860 --> 00:58:47,170 并且如果 我每次做那个事 And if each time I'm doing that, each time to compute a 1077 00:58:47,170 --> 00:58:51,830 每次计算尾部 我求出一个过程的值 tail, I evaluate a procedure which then has to go 1078 00:58:51,830 --> 00:58:54,270 然后 不得不再次计算那个尾部 然后再次计算那个尾部 re-compute its tail, and re-compute its tail and 1079 00:58:54,270 --> 00:58:56,380 然后每次计算那个尾部 recompute its tail each time, you can see that's very 1080 00:58:56,380 --> 00:58:59,610 你可以看到那真是非常的不方便 inefficient compared to just having a list where the 1081 00:58:59,610 --> 00:59:02,510 并且 我得到下一个尾部 我不需要每次再次计算每个尾 elements are all there, and I don't have to re-compute each 1082 00:59:02,510 --> 00:59:05,290 tail every time I get the next tail. 1083 00:59:05,290 --> 00:59:15,030 所以这个小小的改变 改变了delay So there's one little hack to slightly change what delay is, 1084 00:59:15,030 --> 00:59:17,380 并且使这个事-- and make it a thing which is-- 1085 00:59:17,380 --> 00:59:20,390 我将会使用这种方法来写 I'll write it this way. 1086 00:59:20,390 --> 00:59:27,360 真实的实现 延时是一个对这个东西的缩略词 The actual implementation, delay is an abbreviation for 1087 00:59:27,360 --> 00:59:31,000 memo-proc的过程 this thing, memo-proc of a procedure. 1088 00:59:31,000 --> 00:59:35,150 memo-proc是一个特别的东西 这个东西转换了一个过程 Memo-proc is a special thing that transforms a procedure. 1089 00:59:35,150 --> 00:59:39,250 拿一个没有参数的过程 What it does is it takes a procedure of no arguments and 1090 00:59:39,250 --> 00:59:42,190 然后把它转换进一个过程 it transforms it into a procedure that'll only have to 1091 00:59:42,190 --> 00:59:44,806 这个过程只需要做一次计算 do its computation once. 1092 00:59:44,806 --> 00:59:48,700 我的意思是 你给它一个过程 And what I mean by that is, you give it a procedure. 1093 00:59:48,700 --> 00:59:51,950 memo-proc的结果 将会是一个新的过程 The result of memo-proc will be a new procedure, which the 1094 00:59:51,950 --> 00:59:55,370 第一次调用这个过程后 将会运行院士的过程 first time you call it, will run the original procedure, 1095 00:59:55,370 --> 01:00:00,040 记住得到的结果 remember what result it got, and then from ever on after, 1096 01:00:00,040 --> 01:00:01,610 当你调用它 这将不会做这个计算 when you call it, it just won't have to do the 1097 01:00:01,610 --> 01:00:02,360 computation. 1098 01:00:02,360 --> 01:00:05,200 这将会在某个地点cached结果 It will have cached that result someplace. 1099 01:00:05,200 --> 01:00:06,550 这个是memo-proc的实现 And here's an implementation of memo-proc. 1100 01:00:06,550 --> 01:00:11,210 1101 01:00:11,210 --> 01:00:12,710 当你有了这个想法 实现就变得简单了 Once you have the idea, it's easy to implement. 1102 01:00:12,710 --> 01:00:15,830 memo-proc就是这个有两个flags的小东西 Memo-proc is this little thing that has two 1103 01:00:15,830 --> 01:00:17,390 little flags in there. 1104 01:00:17,390 --> 01:00:20,320 它说 我已经开始运行了吗 It says, have I already been run? 1105 01:00:20,320 --> 01:00:23,620 一开始它说 不 我还没有开始运行 And initially it says, no, I haven't already been run. 1106 01:00:23,620 --> 01:00:29,070 上次 我运行的结果是什么 And what was the result I got the last time I was run? 1107 01:00:29,070 --> 01:00:32,200 所以 memo-proc用一个叫proc的过程 So memo-proc takes a procedure called proc, and it returns a 1108 01:00:32,200 --> 01:00:34,360 这个过程返回了一个没有参数的新的过程 new procedure of no arguments. 1109 01:00:34,360 --> 01:00:38,610 prov被认为是一个没有参数的过程 Proc is supposed to be a procedure of no arguments. 1110 01:00:38,610 --> 01:00:42,970 他说 如果我没有已经运行 And it says, oh, if I'm not already run, then I'm going to 1111 01:00:42,970 --> 01:00:44,430 然后我将会做一个序列的事情 do a sequence of things. 1112 01:00:44,430 --> 01:00:48,450 我将会计算proc 我将会保存那个 I'm going to compute proc, I'm going to save that. 1113 01:00:48,450 --> 01:00:51,140 我将会存储那个在变量的结果 I'm going to stash that in the variable result. 1114 01:00:51,140 --> 01:00:53,510 我将会为我做一个笔记 来表示 我已经运行了 I'm going to make a note to myself that I've already been 1115 01:00:53,510 --> 01:00:56,610 然后 我将会返回结果 run, and then I'll return the result. 1116 01:00:56,610 --> 01:00:59,010 所以 那时如果你计算它 如果它没有运行 So that's if you compute it if it's not already run. 1117 01:00:59,010 --> 01:01:01,040 如果你调用它 并且这个已经运行了 If you call it and it's already been run, it just 1118 01:01:01,040 --> 01:01:03,420 这个只会返回结果 returns the result. 1119 01:01:03,420 --> 01:01:08,400 所以 这是一个有点聪明的hack叫memoization So that's a little clever hack called memoization. 1120 01:01:08,400 --> 01:01:12,100 在这个情况 And in this case, it short circuits having to re-compute 1121 01:01:12,100 --> 01:01:15,270 这短路不得不再次计算尾部的尾部的尾部等等等等 the tail of the tail of the tail of the tail of the tail. 1122 01:01:15,270 --> 01:01:17,810 这里甚至不是那么无效率 So there isn't even that kind of inefficiency. 1123 01:01:17,810 --> 01:01:20,590 事实上 流将会和上一个程序有一样的效率 And in fact, the streams will run with pretty much the same 1124 01:01:20,590 --> 01:01:24,210 efficiency as the other programs precisely. 1125 01:01:24,210 --> 01:01:28,110 记住 再说一下 这整个思想是 And remember, again, the whole idea of this is that we've 1126 01:01:28,110 --> 01:01:32,390 我们使用了一个事实:过程和数据之间没有一个合适的分界线 used the fact that there's no really good dividing line 1127 01:01:32,390 --> 01:01:33,610 between procedures and data. 1128 01:01:33,610 --> 01:01:36,510 我们写的数据结构在事实上 都在某些方面像过程 We've written data structures that, in fact, are sort of 1129 01:01:36,510 --> 01:01:38,760 like procedures. 1130 01:01:38,760 --> 01:01:45,280 允许我们做的是 在这个iteration位置带一个普遍的控制结构的例子 And what that's allowed us to do is take an example of a 1131 01:01:45,280 --> 01:01:49,620 common control structure, in this place iteration. 1132 01:01:49,620 --> 01:01:52,460 并且 我们建造了一个数据结构 And we've built a data structure which, since itself 1133 01:01:52,460 --> 01:01:54,530 因为它本身是一个过程 is a procedure, kind of has this iteration control 1134 01:01:54,530 --> 01:01:55,496 里面有这个iteration控制结构 structure in it. 1135 01:01:55,496 --> 01:01:58,650 那个就是流了 And that's really what streams are. 1136 01:01:58,650 --> 01:01:59,900 好的 有什么问题 OK, questions? 1137 01:01:59,900 --> 01:02:03,950 1138 01:02:03,950 --> 01:02:06,110 你的尾尾尾描述 AUDIENCE: Your description of tail-tail-tail, if I 1139 01:02:06,110 --> 01:02:10,050 如果我理解的是对的 understand it correctly, force is actually execution of a 1140 01:02:10,050 --> 01:02:13,052 force只是一个过程的执行 如果它被完成没有使用这个memo-proc procedure, if it's done without this memo-proc thing. 1141 01:02:13,052 --> 01:02:16,380 并且 你暗示那个memo-proc 避免了这个问题 And you implied that memo-proc gets around that problem. 1142 01:02:16,380 --> 01:02:20,580 这个 Doesn't it only get around it if tail-tail-tail is always 1143 01:02:20,580 --> 01:02:22,550 如果 尾尾尾 总是完全一样的执行 executing exactly the same-- 1144 01:02:22,550 --> 01:02:23,500 欧 那个是-- PROFESSOR: Oh, that's-- 1145 01:02:23,500 --> 01:02:23,910 是的 sure. 1146 01:02:23,910 --> 01:02:26,050 我估计 我漏掉了这点 AUDIENCE: I guess I missed that point. 1147 01:02:26,050 --> 01:02:26,540 欧 是的 PROFESSOR: Oh, sure. 1148 01:02:26,540 --> 01:02:27,790 我的意思是 I mean the point is-- 1149 01:02:27,790 --> 01:02:31,160 1150 01:02:31,160 --> 01:02:31,290 是的 yeah. 1151 01:02:31,290 --> 01:02:34,160 我的意思是 我不得不做这个计算来得到答案 I mean I have to do a computation to get the answer. 1152 01:02:34,160 --> 01:02:37,590 但是这个点是 当我找到流的尾部 But the point is, once I've found the tail of the stream, 1153 01:02:37,590 --> 01:02:39,530 来得到 尾的尾 to get the tail of the tail, I shouldn't have had to 1154 01:02:39,530 --> 01:02:42,980 我不应该不得不再次计算第一个尾 re-compute the first tail. 1155 01:02:42,980 --> 01:02:45,370 看 如果我没有使用memo-proc See, and if I didn't use memo-proc, that re-computation 1156 01:02:45,370 --> 01:02:46,460 那个再次计算将会被做完 would have been done. 1157 01:02:46,460 --> 01:02:47,710 我理解了 AUDIENCE: I understand now. 1158 01:02:47,710 --> 01:02:50,830 1159 01:02:50,830 --> 01:02:52,550 在你的一个例子中 AUDIENCE: In one of your examples, you mentioned that 1160 01:02:52,550 --> 01:02:55,010 你提到 我们可以使用替换模型 we were able to use the substitution model because 1161 01:02:55,010 --> 01:02:56,830 因为这里没有副作用 there are no side effects. 1162 01:02:56,830 --> 01:03:01,040 如果 我们有一个单个处理单元 What if we had a single processing unit-- 1163 01:03:01,040 --> 01:03:03,620 如果 我们有一个副作用 如果我们有状态 if we had a side effect, if we had a state? 1164 01:03:03,620 --> 01:03:09,120 我们可以建立流模型吗 Could we still practically build the stream model? 1165 01:03:09,120 --> 01:03:09,530 可能吧 PROFESSOR: Maybe. 1166 01:03:09,530 --> 01:03:10,540 这是一个难题 That's a hard question. 1167 01:03:10,540 --> 01:03:15,540 我们等等再来谈这个替换和副作用没有完全结合好的地方 I'm going to talk a little bit later about the places where 1168 01:03:15,540 --> 01:03:18,960 substitution and side effects don't really mix very well. 1169 01:03:18,960 --> 01:03:21,170 但是一般的 我觉得这个答案 除非你非常小心 But in general, I think the answer is unless you're very 1170 01:03:21,170 --> 01:03:23,920 任何数量的副作用将会把每个事情搞糟 careful, any amount of side effect is going to mess up 1171 01:03:23,920 --> 01:03:25,170 everything. 1172 01:03:25,170 --> 01:03:35,490 1173 01:03:35,490 --> 01:03:36,150 学生:不好意思 我没有完全理解 memo-proc操作 AUDIENCE: Sorry, I didn't quite understand 1174 01:03:36,150 --> 01:03:39,410 the memo-proc operation. 1175 01:03:39,410 --> 01:03:41,990 你什么时候执行lambda When do you execute the lambda? 1176 01:03:41,990 --> 01:03:46,270 换句话说 当memo-proc被执行 In other words, when memo-proc is executed, just this lambda 1177 01:03:46,270 --> 01:03:47,600 expression is being generated. 1178 01:03:47,600 --> 01:03:50,390 但死 当这个被执行 这个对我不清楚 But it's not clear to me when it's executed. 1179 01:03:50,390 --> 01:03:51,350 教授:好的 PROFESSOR: Right. 1180 01:03:51,350 --> 01:03:53,890 memo-proc做的是 记住 What memo-proc does-- remember, the thing that's 1181 01:03:53,890 --> 01:03:57,290 进入memo-proc的东西 going into memo-proc, the thing proc, is a procedure of 1182 01:03:57,290 --> 01:03:57,930 是proc 是一个没有参数的过程 no arguments. 1183 01:03:57,930 --> 01:04:00,390 某些时候 你将会调用它 And someday, you're going to call it. 1184 01:04:00,390 --> 01:04:03,350 memo-proc转换那个过程到另一个没有参数 并且你以后会调用的过程 Memo-proc translates that procedure into another 1185 01:04:03,350 --> 01:04:05,110 procedure of no arguments, which someday 1186 01:04:05,110 --> 01:04:06,620 you're going to call. 1187 01:04:06,620 --> 01:04:09,890 那个是lambda That's that lambda. 1188 01:04:09,890 --> 01:04:17,370 所以这里 当我一开始建立我流的尾部 So here, where I initially built as my tail of the 1189 01:04:17,370 --> 01:04:20,680 我们以后会调用的没有参数的过程 stream, say, this procedure of no arguments, which 1190 01:04:20,680 --> 01:04:24,100 someday I'll call. 1191 01:04:24,100 --> 01:04:27,130 反而 我将会有流的尾是它的memo-proc Instead, I'm going to have the tail of the stream be 1192 01:04:27,130 --> 01:04:30,650 这个东西将会在我们以后调用 memo-proc of it, which someday I'll call. 1193 01:04:30,650 --> 01:04:35,340 nil的lambda被调用 当你调用memo-proc So that lambda of nil, that gets called when you call the 1194 01:04:35,340 --> 01:04:40,990 当你调用那个memo-proc的结果 memo-proc, when you call the result of that memo-proc, 1195 01:04:40,990 --> 01:04:44,400 那个结果将会是一般地 当你想要调用你设置的原始的东西 which would be ordinarily when you would have called the 1196 01:04:44,400 --> 01:04:47,642 original thing that you set it. 1197 01:04:47,642 --> 01:04:49,690 好吧 我问这个的原因是 AUDIENCE: OK, the reason I ask is I had a feeling that when 1198 01:04:49,690 --> 01:04:52,610 我有一种感觉 当你调用memo-proc 你只需要返回这个lambda you call memo-proc, you just return this lambda. 1199 01:04:52,610 --> 01:04:53,770 教授:对的 PROFESSOR: That's right. 1200 01:04:53,770 --> 01:04:58,100 当你调用memo-proc 你返回lambda When you call memo-proc, you return the lambda. 1201 01:04:58,100 --> 01:05:00,090 你从不计算表达式 You never evaluate the expression at all, until the 1202 01:05:00,090 --> 01:05:02,270 直到你第一次计算它 first time that you would have evaluated it. 1203 01:05:02,270 --> 01:05:07,590 1204 01:05:07,590 --> 01:05:10,000 学生: 不知道我理解的对不对 AUDIENCE: Do I understand it right that you actually have 1205 01:05:10,000 --> 01:05:12,980 你实际建造了一个列表 但是列表中的元素没有被计算 to build the list up, but the elements of the 1206 01:05:12,980 --> 01:05:14,240 list don't get evaluated? 1207 01:05:14,240 --> 01:05:15,630 表达式没有被计算? The expressions don't get evaluated? 1208 01:05:15,630 --> 01:05:18,540 但是在每个阶段 你实际上建立了一个列表 But at each stage, you actually are building a list. 1209 01:05:18,540 --> 01:05:19,750 教授: 那个是 PROFESSOR: That's-- 1210 01:05:19,750 --> 01:05:20,700 我真的应该说的 I really should have said this. 1211 01:05:20,700 --> 01:05:22,270 这个真不错 That's a really good point. 1212 01:05:22,270 --> 01:05:23,660 不 这不是很正确的 No, it's not quite right. 1213 01:05:23,660 --> 01:05:25,080 因为就是这样发生的 Because what happens is this. 1214 01:05:25,080 --> 01:05:26,890 让我们把这个画成序对 Let me draw this as pairs. 1215 01:05:26,890 --> 01:05:29,710 假设 我将造一个大的流 Suppose I'm going to make a big stream, like enumerate 1216 01:05:29,710 --> 01:05:32,740 像enumerate 间距1到1百万 interval, 1 through 1 billion. 1217 01:05:32,740 --> 01:05:43,045 那个是 一个1和一个许诺的序对 What that is, is a pair with a 1 and a promise. 1218 01:05:43,045 --> 01:05:46,520 1219 01:05:46,520 --> 01:05:47,890 完全就是这样 That's exactly what it is. 1220 01:05:47,890 --> 01:05:49,140 什么都没有被建成 Nothing got built up. 1221 01:05:49,140 --> 01:05:51,600 1222 01:05:51,600 --> 01:05:56,370 当我force这个 然后说 会发生什么 When I go and force this, and say, what happens? 1223 01:05:56,370 --> 01:06:00,530 好的 这个东西现在也递归一个cons Well, this thing is now also recursively a CONS. 1224 01:06:00,530 --> 01:06:07,770 所以 这个许诺诺现在是下一个东西 是2和一个许诺 So that this promise now is the next thing, which is a 2 1225 01:06:07,770 --> 01:06:11,350 and a promise to do more. 1226 01:06:11,350 --> 01:06:14,470 等等等等 And so on and so on and so on. 1227 01:06:14,470 --> 01:06:18,200 所以 知道你走道流 没有东西被建造 So nothing gets built up until you walk down the stream. 1228 01:06:18,200 --> 01:06:20,790 因为这里不是列表 Because what's sitting here is not the list, but a promise to 1229 01:06:20,790 --> 01:06:24,250 而是一个产生列表的许诺 generate the list. And by promise, 1230 01:06:24,250 --> 01:06:25,500 并且通过许诺 我的意思是过程 在技术上的 technically I mean procedure. 1231 01:06:25,500 --> 01:06:28,050 1232 01:06:28,050 --> 01:06:30,485 所以 这没有建成 So it doesn't get built up. 1233 01:06:30,485 --> 01:06:34,280 是的 我应该在这点之前说过了 Yeah, I should have said that before this point. 1234 01:06:34,280 --> 01:06:34,490 好的 OK. 1235 01:06:34,490 --> 01:06:34,790 谢谢大家 Thank you. 1236 01:06:34,790 --> 01:06:36,340 下面进入休息时间 Let's take a break. 1237 01:06:36,340 --> 01:06:55,828 MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed thismaterial in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec6b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 6B: Streams, Part 2 PROFESSOR: OK, well, we've been looking at streams, this signal processing way of putting systems together. And remember, the key idea is that we decouple the apparent order of events in our programs from the actual order of events in the computer. And that means that we can start dealing with very long streams and only having to generate the elements on demand. That sort of on-demand computation is built into the stream's data structure. So if we have a very long stream, we only compute what we need. The things only get computed when we actually ask for them. Well, what are examples? Are they actually asking for them? For instance, we might ask for the n-th element of a stream. Here's a procedure that computes the n-th element of a stream. An integer n, the n-th element of some stream s, and we just recursively walk down the stream. And the end of 0, we compute the head. Otherwise, it's the n-th the minus 1 element of the tail of the stream. Those two are just like for Lisp, but the difference is those elements aren't going to get computed until we walk down, taking successive n -ths. So that's one way that the stream elements might get forced. And another way, here's a little procedure that prints a stream. We say print a stream, so to print a stream s. Well, what do we do? We print the head of the stream, and that will cause the head to be computed. And then we recursively print stream the tail of the stream. And if we're already done, maybe we have to return something about the message done. OK, and then so if you make a stream, you could say here's the stream, this very long stream. And then you say print the stream, and the elements of the stream will get computed successively as that print calls them. They won't get all computed initially. So in this way, we can deal with some very long streams. Well, how long can a stream be? Well, it can be infinitely long. Let's look at an example here on the computer. I could walk up to this computer, and I could say-- how about we'll define the stream of integers starting with some number N, the stream of positive integers starting with some number n. And that's cons-stream of n onto the integers from one more. So there are the integers. Then I could say let's get all the integers. define the stream of integersto be the integers starting with 1. And now if I say something like what's the what's the 20th integer. So it's 21 because we start counting at 0. Or I can do more complicated things. Let me to define a little predicate here. How about define no-seven. It's going to test an integer, and it's going to say it's not. I take the remainder of x by 7, I don't get 0. And then I could say define the integers with no sevens to be, take all the integers and filter them to have no sevens. So now I've got the stream of all the integers that are not divisible by seven. So if I say what's the 100th integer and the list not divisible by seven, I get 117. Or if I'd like to say well, gee, what are all of them? So I could say print stream all these integers with no seven, it goes off printing. You may have to wait a very long time to see them all. Well, you can start asking, gee, is it really true that this data structure with the integers is really all the integers? And let me draw a picture of that program I just wrote. Here's the definition of the integers again that I just typed in, Right it's a cons of the first integer under the integer starting with the rest. Now, we can make a picture of that and see what it looks like. Conceptually, what I have is a box that's the integer starting with n. It takes in some number n, and it's going to return a stream of-- this infinite stream of all integers starting with n. And what do I do? Well, this is an integers from box. What's it got in it? Well, it takes in this n, and it increments it. And then it puts the result into recursively another integer's from box. It takes the result of that and the original n and puts those together with a cons and forms a stream. So that's a picture of that program I wrote. Let's see. These kind of diagrams we first saw drawn by Peter Henderson, the same guy who did the Escher language. We call them Henderson diagrams. And the convention here is that you put these things together. And the solid lines are things coming out are streams, and dotted lines are initial values going in. So this one has the shape of -- it takes in some integer, some initial value, and outputs a stream. Again, you can ask. Is that data structure integers really all the integers? Or is it is something that's cleverly arranged so that whenever you look for an integer you find it there? That's sort of a philosophical question, right? If something is there whenever you look, is it really there or not? It's sort of the same sense in which the money in your savings account is in the bank. Well, let me do another example. Gee, we started the course with an algorithm from Alexandria, which was Heron of Alexandria's algorithm for computing the square root. Let's take a look at another Alexandrian algorithm. This one is Eratosthenes method for computing all of the primes. It is called the Sieve of Eratosthenes. And what you do is you start out, and you list all the integers, say, starting with 2. And then you take the first integer, and you say, oh, that's prime. And then you go look at the rest, and you cross out all the things divisible by 2. So I cross out this and this and this. This takes a long time because I have to do it for all of the integers. So I go through the entire list of integers, crossing the ones divisible by 2. And now when I finish with all of the integers, I go back and look and say what am I left with? Well, the first thing that starts there is 3. So 3 is a prime. And now I go back through what I'm left with, and I cross out all the things divisible by 3. So let's see, 9 a nd 15 and 21 and 27 and 33 and so on. I won't finish. Then I see what I'm left with. And the next one I have is 5. Now I can through the rest, and I find the first one that's divisible by 5. I cross out from the remainder all the ones that are divisible by 5. And I do that, and then I go through and find 7. Go through all the rest, cross out things divisible 7, and I keep doing that forever. And when I'm done, what I'm left with is a list of all the primes. So that's the Sieve of Eratosthenes. Let's look at it as a computer program. It's a procedure called sieve. Now, I just write what I did. I'll say to sieve some stream s. I'm going to build a stream whose first element is the head of this. Remember, I always found the first thing I was left with, and th e rest of it is the result of taking the tail of this, filtering it to throw away all the things that are divisible by the head of this, and now sieving the result. That's just what I did. And now to get the infinite stream of times, we just sieve all the integers starting from 2. Let's try that. We can actually do it. I typed in the definition of sieve before, I hope, so I can say something like define the primes to be the result of sieving the integers starting with 2. So now I've got this list of primes. That's all of the primes, right? So, if for example, what's the 20th prime in that list? 73. See, and that little pause, it was only at the point when I started asking for the 20th prime is that it started computing. Or I can say here let's look at all of the primes. And there it goes computing all of the primes. Of course, it will take a while again if I want to look at all of them, so let's stop it. Let me draw you a picture of that. Well, I've got a picture of that. What's that program really look like? Again, some practice with these diagrams, I have a sieve box. How does sieve work? It takes in a stream. It splits off the head from the tail. And the first thing that's going to come out of the sieve is the head of the original stream. Then it also takes the head and uses that. It takes the stream. It filters the tail and uses the head to filter for nondivisibility. It takes the result of nondivisibility and puts it through another sieve box and puts the result together. So you can think of this sieve a filter, but notice that it's an infinitely recursive filter. Because inside the sieve box is another sieve box, and inside that is another sieve box and another sieve box. So you see we start getting some very powerful things. We're starting to mix th is signal processing view of the world with things like recursion that come from computation. And there are all sorts of interesting things you can do that are like this. All right, any questions? OK, let's take a break. Well, we've been looking at a couple of examples of stream programming. All the stream procedures that we've looked at so far have the same kind of character. We've been writing these recursive procedures that kind of generate these stream elements one at a time and put them together in cons-streams. So we've been thinking a lot about generators. There's another way to think about stream processing, and that's to focus not on programs that sort of process these elements as you walk down the stream, but on things that kind of process the streams all at once. To show you what I mean, let me start by defining two procedures that will come in handy. The first one's called add streams. Add streams takes two streams: s1 and s2. and. It's going to produce a stream whose elements are the are thecorresponding sums. We just sort of add them element-wise. If either stream is empty, we just return the other one. Otherwise, we're going to make a new stream whose head is the sum of the two heads and whose tail is the result of recursively adding the tails. So that will produce the element-wise sum of two streams. And then another useful thing to have around is scale stream. Scale stream takes some constant number in a stream s and is going to produce the stream of elements of s multiplied by this constant. And that's easy, that's just a map of the function of an element that multiplies it by the constant, and we map that down the stream. So given those two, let me show you what I mean by programs that operate on streams all at once. Let's look at this. Suppose I write this. I say define-- I'll call it ones-- to be cons- stream of 1 onto ones. What's that? That's going to be an infinite stream of ones because the first thing is 1. And the tail of it is a thing whose first thing is 1 and whose tail is a thing whose first thing is 1 and so on and so on and so on. So that's an infinite stream of ones. And now using that, let me give you another definition of the integers. We can define the integers to be-- well, the first integer we'll take to be 1, this cons-stream of 1 onto the element-wise sum onto add streams of the integers to ones. The integers are a thing whose first element is 1, and the rest of them you get by taking those integers and incrementing each one by one. So the second element of the integers is the first element of the integers incremented by one. And the rest of that is the next one, and the third element of that is the same as the first element of the tail of the integers incremented by one, which is the same as the first element of the original integers incremented by one and incremented by one again and so on. That looks pretty suspicious. See, notice that it works because of delay. See, this looks like- - let's take a look at ones. This looks like it couldn't even be processed becau se it's suddenly saying in order to know what ones is, I say it's cons-stream of something onto ones. The reason that works is because of that very sneaky hidden delay in there. Because what this really is, remember, cons-stream is just an abbreviation. This really is cons of 1 onto delay of ones. So how does that work? You say I'm going to define ones. First I see what ones is supposed to be defined as. Well, ones is supposed to be defined as a cons whose first part is 1 and whose second part is, well, it's a promise to compute something that I don't worry about yet. So it doesn't bother me that at the point I do this definition, ones isn't defined. Having run the definition now, ones is defined. So that when I go and look at the tail of it, it's defined. It's very sneaky. And an integer is the same way. I can refer to integers here because hidden way down-- because of this cons-stream. It's the cons-stream of 1 onto something that I don't worry that yet. So I don't look at it, and I don't notice that inte gers isn't defined at the point where I try and run the definition. OK, let me draw a picture of that integers thing because it still maybe seems a little bit shaky. What do I do? I've got the stream of ones, and that sort of comes in and goes into an adder that's going to be this add streams thing. And that goes in-- that's going to put out the integers. And the other thing that goes into the adder here is the integer, so there's a little feedback loop. And all I need to start it off is someplace I've go t a stick that initial 1. In a real signal processing thing, this might be a delay element with that was initialized to 1. But there's a picture of that ones program. And in fact, that looks a lot like -- if you've seen real signal block diagram things, that looks a lot like accumulators, finite state accumulators. And in fact, we can modify this a little bit to change this into something that integrates a stream or a finite state accumulator, however you like to think about it. So instead of the ones coming in and getting out the integers, what we'll do is say there's a stream s coming in, and we're going to get out the integral of this, successive values of that, and it looks almost the same. The only thing we're going to do is when s comes in here, before we just add it in we're going to multiply it by some number dt. And now what we have here, this is exactly the same thing. We have a box, which is an integrator. And it takes in a stream s, and instead of 1 here, we can put the additional value for the integral. And that one looks very much like a signal processing block diagram program. In fact, here's the procedure that looks exactly like that. Find the integral of a stream. So an integral's going to take a stream and produce a new stream, and it takes in an initial value and some time constant. And what do we do? Well, we internally define this thing int, and we make this internal name so we can feed it back, loop it around itself. And int is defined to be something that starts out at the initial value, and the rest of it is gotten by adding together. We take our input stream, scale it by dt, and add that to int. And now we'll return from all that the value of integral is this thing int. And we use this internal definition syntax so we could write a little internal definition that refers to itself. Well, there are all sorts of things we can do. Let's try this one. how about the Fibonacci numbers. You can say define fibs. Well, what are the Fibonacci numbers? They're something that starts out with 0, and the next one is 1. And the rest of the Fibonacci numbers are gotten by adding the Fibonacci numbers to their own tail. There's a definition of the Fibonacci numbers. How does that work? Well, we start off, and someone says compute for us the Fibonacci numbers, and we're going to tell you it starts out with 0 and 1. And everything after the 0 and 1 is gotten by summing two streams. One is the fibs themselves, and the other one is the tail of the fibs. So if I know that these start out with 0 and 1, I know that the fibs now start out with 0 and 1, and the tail of the fibs start out with 1. So as soon as I know that, I know that the next one here is 0 plus 1 is 1, and that tells me that the next one here is 1 and the next one here is 1. And as soon as I know that, I know that the next one is 2. So the next one here is 2 and the next one here is 2. And this is 3. This one goes to 3, and this is 5. So it's a perfectly sensible definition. It's a one -line definition. And again, I could walk over to the computer and type that in, exactly that, and then say print stream the Fibonacci numbers, and they all come flying out. See, this is a lot like learning about recursion again. Instead of thinking that recursive procedures, we have recursively defined data objects. But that shouldn't s urprise you at all, because by now, you should be coming to really believe that there's no difference really between procedures and data. In fact, in some sense, the underlying streams are procedures sitting there, although we don't think of them that way. So the fact that we have recursive procedures, well, then it should be natural that we have recursive data, too. OK, well, this is all pretty neat. Unfortunately, there are problems that streams aren't going to solve. Let me show you one of them. See, in the same way, let's imagine that we're building an analog computer to solve some differential equation like, say, we want to solve the equation y prime dy dt is y squared, and I'm going to give you some initial value. I'll tell you y of 0 equals 1. Let's say dt is equal to something. Now, in the old days, people built analog computers to solve these kinds of things. And the way you do that is really simple. You get yourself an integrator, like that one, an integrator box. And we put in the initial value y of 0 is 1. And now if we feed something in and get something out, we'll say, gee, what we're getting out is the answer. And what we're going to feed in is the derivative, and the derivative is supposed to be the square of the answer. So if we take these values and map using square, and if I feed this around, that's how I build a block diagram for an analog computer that solves this differential equation. Now, what we'd like to do is write a stream program that looks exactly like that. And what do I mean exactly like that? Well, I'd say define y to be the integral of dy starting at 1 with 0.001 as a time step. And I'd like to say that says this. And then I'd like to say, well, dy is gotten by mapping the square along y. So define dy to be map square along y. So there's a stream description of this analog computer, and unfortunately, it doesn't work. And you can see why it doesn't work because when I come in and say define y to be the integral of dy, it says, oh, the integral of y-- huh? Oh, that's undefined. So I can't write this definition before I've written this one. On the other hand, if I try and write this one first, it says, oh, I define y to be the map of square along y? Oh, that's not defined yet. So I can't write this one first, and I can't write that one first. So I can't quite play this game. Well, is there a way out? See, we can do that with ones. See, over here, we did this thing ones, and we were able to define ones in terms of ones because of this delay that was built inside because cons-stream had a delay. Now, why's it sensible? Why's it sensible for cons- stream to be built with this delay? The reason is that cons-stream can do a useful thing without looking at its tail. See, if I say this is cons -stream of 1 onto something without knowing anything about something, I know that the stream starts off with 1. That's why it was sensible to build something like cons-stream. So we put a delay in there, and that allows us to have this sort of self-referential definition. Well, integral is a little bit the same way. See, notice for an integral, I can-- let's go back and look at integral for a second. See, notice integral, it makes sense to say what's the first thing in the integral without knowing the stream that you're integrating. Because the first thing in the integral is always going to be the initial value that you're handed. So integral could be a procedure like cons-stream. You could define it, and then even before it knows what it's supposed to be integrating, it knows enough to say what its initial value is. So we can make a smarter integral, which is aha, you're going to give me a stream to integrate and an initial value, but I really don't have to look at that stream that I'm supposed to integrate until you ask me to work down the stream. In other words, integral can be like cons-stream, and you can expect that there's going to be a delay around its integrand. And we can write that. Here's a procedure that does that. Another version of integral, and this is almost like the previous one, except the stream it's going to get in is going to expect to be a delayed object. And how does this integral work? Well, the little thing it's going to define inside of itself says on t he cons-stream, the initial value is the initial value, but only inside of that cons -stream, and remember, there's going to be a hidden delay inside here. Only inside of that cons-stream will I start looking at what the actual delayed object is. So my answer is the first thing's the initial value. If anybody now asks me for my tail, at that point, I'm going to force that delayed object-- and I'll call that s-- and I do the add streams. So this is an integral which is sort of like cons-stream. It's not going to actually try and see what you handed it as the thing to integrate until you look past the first element. And if we do that and we can make this work, all we have to do here is say define y to the integral of delay of y, of delay of dy. So y is going to be the integral of delay of dy starting at 1, and now this will work. Because I type in the definition of y, and that says, oh, I'm supposed to use the integral of something I don't care about right now because it's a delay. And these things, now you define dy. Now, y is defined. So when I define dy, it can see that definition for y. Everything is now started up. Both streams have their first element. And then when I start mapping down, looking at successive elements, both y and dy are defined. So there's a little game you can play that goes a little bit beyond just using the delay that's hidden inside streams. Questions? OK, let's take a break. Well, just before the break, I'm not sure if you noticed it, but something nasty started to happen. We've been going along with the streams and divorcing time in the programs from time in the computers, and all that divorcing got hidden inside the streams. And then at the very end, we saw that sometimes in order to really take advantage of this method, you have to pull out other delays. You have to write some explicit delays that are not hidden inside that cons-stream. And I did a very simple example with differential equations, but if you have some very complicated system with all kinds of self -loops, it becomes very, very difficult to see where you need those delays. And if you leave them out by mistake, it becomes very, very difficult to see why the thing maybe isn't working. So that's kind of mess, that by getting this power and allowing us to use delay, we end up with some very complicated programming sometimes, because it can't all be hidden inside the streams. Well, is there a way out of that? Yeah, there is a way out of that. We could change the language so that all procedures acted like cons-stream, so that every procedure automatically has an implicit delay around its arguments. And what would that mean? That would mean when you call a procedure, the arguments wouldn't get evaluated. Instead, they'd only be evaluated when you need them, so they might be passed off to some other procedure, which wouldn't evaluate them either. So all these procedures would be passing promises around. And then finally maybe when you finally got down to having to look at the value of something that was handed to a primitive operator would you actually start calling in all those promises. If we did that, since everything would have a uniform delay, then you wouldn't have to write any explicit delays, because it would be automatically built into the way the language works. Or another way to say that, technically what I'm describing is what's called -- if we did that, our language would be so-called normal-order evaluation language versus what we've actually been working with, which is called applicative order-- versus applicative-order evaluation. And remember the substitution model for applicative order. It says when you go and evaluate a combination, you find the values of all the pieces. You evaluate the arguments and then you substitute them in the body of the procedure. Normal order says no, don't do that. What you do is effectively substitute in the body of the procedure, but instead of evaluating the arguments, you just put a promise to compute them there. Or another way to say that is you take the expressions for the arguments, if you like, and substitute them in the body of the procedure and go on, and never really simplify anything until you get down to a primitive operator. So that would be a normal-order language. Well, why don't we do that? Because if we did, we'd get all the advantages of delayed evaluation with none of the mess. In fact, if we did that and cons was just a delayed procedure, that would make cons the same as cons-stream. We wouldn't need streams of all because lists would automatically be streams. That's how lists would behave, and data structures would behave that way. Everything would behave that way, right? You'd never really do any computation until you actually needed the answer. You wouldn't have to worry about all these explicit annoying delays. Well, why don't we do that? First of all, I should say people do do that. There's some very beautiful languages. One of the very nicest is a language called Miranda, which is developed by David Turner at the University of Kent. And that's how this language works. It's a normal-order language and its data structures, which look like lists, are actually streams. And you write ordinary procedures in Miranda, and they do these prime things and eight queens things, just without anything special. It's all built in there. But there's a price. Remember how we got here. We're decoupling time in the programs from time in the machines. And if we put delay, that sort of decouples it everywhere, not just in streams. Remember what we're trying to do. We're trying to think about programming as a way to specify processes. And if we give up too much time, our language becomes more elegant, but it becomes a little bit less expressive. There are certain distinctions that we can't draw. One of them, for instance, is iteration. Remember this old procedure, iterative factorial, that we looked at quite a long time ago. Iterative factorial had a thing, and it said there was an internal procedure, and there was a state which was a product and a counter, and we iterate that going around the loop. And we said that was an iterative procedure because it didn't build up state. And the reason it didn't build up state is because this iter that's called is just passing these things around to itself. Or in the substitution model, you could see in the substitution model that Jerry did, that in an iterative procedure, that state doesn't have to grow. And in fact, we said it doesn't, so this is an iteration. But now think about this exact same text if we had a normal-order language. What would happen is this would no longer be an iterative procedure? And if you really think about the details of the substitution model, which I'm not going to do here, this expression would grow. Why would it grow? It's because when iter calls itself, it calls itself with this product. If it's a normal-order language, that multiplication is not going to get done. That's going to say I'm to call myself with a promise to compute this product. And now iter goes around again. And I'm going to call myself wit h a promise to compute this product where now one of the one factors is a promise. And I call myself again. And if you write out the substitution model for that iterative process, you'll see exactly the same growth in state, all those promises that are getting remembered that have to get called in at the very end. So one of the disadvantages is that you can't really express iteration. Maybe that's a little theoretical reason why not, but in fact, people who are trying to write real operating systems in these languages are running into exactly these types of problems. Like it's perfectly possible to implement a text editor in languages like these. But after you work a while, you suddenly have 3 megabytes of stuff, which is -- I guess they call them the dragging tail problem of people who are looking at these, of promises that sort of haven't been called in because you couldn't quite express an iteration. And one of the research questions in these kinds of languages are figuring out the right compiler technology to get rid of the so-called dragging tails. It's not simple. But there's another kind of more striking issue about why you just don't go ahead and make your language normal order. And the reason is that normal -order evaluation and side effects just don't mix. They just don't go together very well. Somehow, you can't-- it's sort of you can't simultaneously go around trying to model objects with local state and change and at the same time do these normal-order tricks of de-coupling time. Let me just show you a really simple example, very, very simple. Suppose we had a normal-order language. And I'm going to start out in this language. This is now normal order. I'm going to define x to be 0. It's just some variable I'll initialize. And now I'm going to define this little funny function, which is an identity functio n. And what it does, it keeps track of the last time you called it using x. So the identity of n just returns n, but it sets x to be n. And now I'll define a little increment function, which is a very little, simple scenario. Now, imagine I'm interacting with this in the normal-order language, and I type the following. I say define y to be increment the identity function of 3, so y is going to be 4. Now, I say what's x? Well, x should have been the value that was remembered last when I called the identity function. So you'd expect to say, well, x is 3 at this point, but it's not. Because when I defined y here, what I really defined y to be increment of a promise to do this thing. So I didn't look at y, so that identity function didn't get run. So if I type in this definition and look at x, I'm going to get 0. Now, if I go look at y and say what's y, say y is 4, looking at y, that very active looking at y caused the identity function to be run. And now x will get remembered as 3. So here x will be 0. Here, x will be 3. That's a tiny, little, simple scenario, but you can see what kind of a mess that's going to make for debugging interactive programs when you have normal-order evaluation. It's very confusing. But it's very confusing for a very deep reason, which is that the whole idea of putting in delays is that you throw away time. That's why we can have these infinite processes. Since we've thrown away time, we don't have to wait for them to run, right? We decouple the order of events in the computer from what we write in our programs. But when we talk about state and set and change, that's exactly what we do want control of. So it's almost as if there's this fundamental contradiction in what you want. And that brings us back to these sort of philosophical mutterings about what is it that you're trying to model and how do you look at the world. Or sometimes this is called the debate over functional programming. A so-called purely functional language is one that just doesn't have any side effects. Since you have no side effects, there's no assignment operator, so there are no terrible consequences of it. You can use a substitution-like thing. Programs really are like mathematics and not like models in the real world, not like objects in the real world. There are a lot of wonderful things about functional languages. Since there's no time, you never have any synchronization problems. And if you want to put something into a parallel algorithm, you can run the pieces of that parallel processing any way you want. There's just never any synchronization to worry that, and it's a very congenial environment for doing this. The price is you give up assignment. So an advocate of a functional language would say, gee, that's just a tiny price to pay. You probably shouldn't use assignment most of the time anyway. And if you just give up assignment, you can be in this much, much nicer world than this place with objects. Well, what's the rejoinder to that? Remember how we got into this mess. We started trying to model things that had local state. So remember Jerry's random number generator. There was this random number generator that had some little state in it to compute the next random number and the next random number and the next random number. And we wanted to hide that state away from the Cesaro compute part process, and that's why we needed set. We wanted to package that stated modularly. Well, a functional programming person would say, well, you're just all wet. I mean, you can write a perfectly good modular program. It's just you're thinking about modularity wrong. You're hung up in this next random number and the next random number and the next random number. Why don't you just say let's write a program. Let's write an enumerator which just generates an infinite stream of random numbers. We can sort of have that stream all at once, and that's going to be our source of random numbers. And then if you like, you can put that through some sort of processor, which is -- I don't know-- a Cesaro test, and that can do what it wants. And what would come out of there would be a stream of successive approximations to pi. So as we looked further down this stream, we'd tug on this Cesaro thing, and it would pull out more and more random numbers. And the further and further we look down the stream, the better an approximation we'd get to pi. And it would do exactly the same as the other computation, except we're thinking about the modularity different. We're saying imagine we had all those infinite streams of random numbers all at once. You can see the details of this procedure in the book. Similarly, there are other things that we tend to get locked into on this one and that one and the next one and the next one, which don't have to be that way. Like you might think about like a banking system, which is a very simple idea. Imagine we have a program that sort of represents a bank account. The bank account might have in it -- if we looked at this in a sort of message-passing view of the world, we'd say a bank account is an object that has some local state in there, which is the balance, say. And a user using this system comes and sends a transaction request. So the user sends a transaction request, like deposit some money, and the bank account maybe -- let's say the bank account always responds with what the current balance is. The user says let's deposits some money, and the bank account sends back a message which is the balance. And the user says deposit some more, and the bank account sends back a message. And just like the random number generator, you'd say, gee, we would like to use set. We'd like to have balance be a piece of local state inside this bank account because we want to separate the state of the user from the state of the bank account. Well, that's the message-processing view. There's a stream view with that thing, which does the same thing without any set or side effects. And the idea is again we don't think about anything having local state. We think about the bank account as something that's going to process a stream of transaction requests. So think about this bank account not as something that goes message by message, but something that takes in a stream of transaction requests like maybe successive deposit announced. 1, 2, 2, 4, those might be successive amounts to deposit. And then coming out of it is the successive balances 1, 3, 5, 9. So we think of the bank account not as something that has state, but something that acts sort of on the infinite stream of requests. But remember, we've thrown away time. So what we can do is if the user's here, we can have this infinite stream of requestsbeing generated one at a time coming from the user and this transaction stream coming back on a printer being printed one at a time. And if we drew a little line here, right there to the user, the user couldn't tell that this system doesn't have state. It looks just like the other one, but there's no state in there. And by the way, just to show you, here's an actual implementation of this -- we'll call it make deposit account because you can only deposit. It takes an initial balance and then a stream of deposits you might make. And what is it? Well, it's just cons-stream of the balance onto make a new account stream whose initial balance is the old balance plus the first thing in the deposit stream and make deposit account works on the rest of which is the tail of the deposit stream. So there's sort of a very typical message-passing, object-oriented thing that's done without side effects at all. There are very many things you can do this way. Well, can you do everything without assignment? Can everybody g o over to purely functional languages? Well, we don't know, but there seem to be places where purely functional programming breaks down. Where it starts hurting is when you have things like this, but you also mix it up with the other things that we had to worry that, which are objects and sharing and two independent agents being the same. So under a typical one, suppose you want to extend this bank account. So here's a bank account. Bank accounts take in a stream of transaction requests and put out stream s of, say, balances or responses to that. But suppose you want to model the fact that this is a joint bank account between two independent people. So suppose there are two people, say, Bill and Dave, who have a joint bank account. How would you model this? Well, Bill puts out a stream of transaction requests, and Dave puts out a stream of transaction requests, and somehow, they have to merge into this bank account. So what you might do is write a little stream processing thing called merge, which sort of takes these, merges them together, produces a single stream for the bank account. Now they're both talking to the same bank account. That's all great, but how do you write merge? What's this procedure merge? You want to do something that's reasonable. Your first guess might be to say, well, we'll take alternate requests from Bill and Dave. But what happens if suddenly in the middle of this thing, Dave goes away on vacation for two years? Then Bill's sort of stuck. So what you want to do is-- well, it's hard to describe. What you want to do is what people call fair merge. The idea of fair merge is it sort of should do them alternately, but if there's nothing waiting here, it should take one twice. Notice I can't even say that without talking about time. So one of the other active researcher areas in functional languages is inventing little things like fair merge and maybe some others, which will take the places where I used to need side effects and objects and sort of hide them away in some very well-defined modules of the system so that all the problems of assignment don't sort of leak out all over the system but are captured in some fairly well-understood things. More generally, I think what you're seeing is that we're running across what I think is a v ery basic problem in computer science, which is how to define languages that somehow can talk about delayed evaluation, but also be able to reflect this view that there are objects in the world. How do we somehow get both? And I think that's a very hard problem. And it may be that it's a very hard problem that has almost nothing to do with computer science, that it really is a problem having to do with two very incompatible ways of looking at the world. OK, questions? AUDIENCE: You mentioned earlier that once you introduce assignment, the general rule for using the substitution model is you can't. Unless you're very careful, you can't. PROFESSOR: Right. AUDIENCE: Is there a set of techniques or a set of guidelines for localizing the effects of assignment so that the very careful becomes defined? PROFESSOR: I don't know. Let me think. Well, certainly, there was an assignment inside memo proc, but that was sort of hidden away. It ended up not making any difference. Part of the reason for that is once this thing triggered that it had run and gotten an answer, that answer will never change. So that was sort of a one-time assignment. So one very general thing you can do is if you only do what's called a one-time assignment and never change anything, then you can do better. One of the problems in this merge thing, people have-- let me see if this is right. I think it's true that with fair merge, with just fair merge, you can begin effectively simulating assignment in the rest of the language. It seems likeanything you do to go outside-- I'm not quite sure that's true for fair merge, but it's true of a little bit more general things that people have been doing. So it might be that any little bit you put in, suddenly if they allow you to build arbitrary stuff, it's almost as bad as having assignment altogether. But that's an area that people are thinking about now. AUDIENCE: I guess I don't see the problem here with merge if I call Bill, if Bill is a procedure, then Bill is going to increment the bank account or build the list that 's going to put in the next element. If I call Dave twice in a row, that will do that. I'm not sure where fair merge has to be involved. PROFESSOR: The problem is imagine these really as people. See, here I have the user who's interacting with this bank account. Put in a request, get an answer. Put in a request, get an answer. AUDIENCE: Right. PROFESSOR: But if the only way I can process request is to alternate them from two people-- AUDIENCE: Well, why would you alternate them? PROFESSOR: Why don't I? AUDIENCE: Yes. Why do you? PROFESSOR: Think of them as real people, right? This guy might go away for a year. And you're sitting here at the bank account window, and you can't put in two requests because it's waiting for this guy. AUDIENCE: Why does it have to be waiting for one? PROFESSOR: Because it's trying to compute a function. I have to define a function. Another way to say that is the answer to what comes out of this merge box is not a function of what goes in. Because, see, what would the function be? Suppose he puts in 1, 1, 1, 1, and he puts in 2, 2, 2, 2. What's the answer supposed to be? It's not good enough to say it's 1, 2, 1, 2, 1, 2. AUDIENCE: I understand. But when Bill puts in 1, 1 goes in. When Dave puts in 2 twice, 2 goes in twice. When Bill puts in-- PROFESSOR: Right. AUDIENCE: Why can't it be hooked to the time of the input-- the actual procedural-- PROFESSOR: Because I don't have time. See, all I can say is I'm going to define a function. I don't have time. There's no concept if it's going to alternate, except if nobody's there, it's going to wait a while for him. It's just going to say I have the stream of requests, the timeless infinite streams of all the requests that Dave would have made, right? And the timeless infinite stream of all the requests Bill would have made, and I want to operate on them. See, that's how this bank account is working. And the problem is that these poor people who are sitting at the bank account windows have the misfortune to exist in time. They don't see their infinite stream of all the requests they would have ever made. They're waiting now, and they want an answer. So if you're sitting there-- if this is the screen operation on some time-sharing system and it's working functionally, you want an answer then when you talk the character. You don't want it to have to wait for everybody in the whole system to have typed one character before it can get around to service you. So that's the problem. I mean, the fact that people live in time, apparently. If they didn't, it wouldn't be a problem. AUDIENCE: I'm afraid I miss the point of having no time in this banking transaction. Isn't time very important? For instance, the sequence of events. If Dave take out $100, then the timing sequence should be important. How do you treat transactions as streams? PROFESSOR: Well, that's the thing I'm saying. This is an example where you can't. You can't. The point is what comes out of here is simply not a function of the stream going in here and the stream going in here. It's a function of the stream going in here and the stream going in here and some kind of information about time, which is precisely what a normal-order language won't let you say. AUDIENCE: In order to brings this back into a more functional perspective, could we just explicitly time stamp all the inputs from Bill and Dave and define fair merge to just be the sort on those time stamps? PROFESSOR: Yeah, you can do that. You can do that sort of thing. Another thing you could say is imagine that really what this function is, is that it does a read every microsecond, and then if there's none there, that's considered an empty one. That's about equivalent to what you said. And yes, you can do that, but that's a clg. So it's not quite only implementation we're worried about. We're worried about expressive power in the language, and what we're running across is a real mismatch between what we can say easily and what we'd like to say. AUDIENCE: It sounds like where we're getting hung up with that is the fact it expects one input from both Bill and Dave at the same time. PROFESSOR: It's not quite one, but it's anything you define. So you can say Dave can go twice as often, but if anything you predefine, it's not the right thing. You can't decide at some particular function of their input requests. Worse yet, I mean, worse yet, there are things that even merge can't do. One thing you might want to do that's even more general is suddenly you add somebody else to this bank account system. You go and you add John to this bank account system. And now there's yet another stream that's going to come into the picture at some time which we haven't prespecified. So that's something even fair merge can't do, and they're things called-- I forget-- natagers or something. That's a generalization of fair merge to allow that. There's a whole sort of research discipline saying how far can you push this functional perspective by adding more and more mechanism? And how far does that go before the whole thing breaks down and you might as well been using set anyway. AUDIENCE: You need to set him up on automatic deposit. [LAUGHTER] PROFESSOR: OK, thank you. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec7a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 7A: Metacircular Evaluator, Part 1 PROFESSOR: Well today we're going to learn about something quite amazing. We're going to understand what we mean by a program a little bit more profoundly than we have up till now. Up till now, we've been thinking of programs as describing machines. So for example, looking at this still store, we see here is a program for factorial. And what it is, is a character string description, if you will, of the wiring diagram of a potentially infinite machine. And we can look at that a little bit and just see the idea. That this is a sort of compact notation which says, if n is 0, the result is one. Well here comes n coming into this machine, and if it's 0, then I control this switch in such a way that the switch allows the output to be one. Otherwise, it's n times factorial of n min us one. Well, I'm computing factorial of n minus one and multiplying that by n, and, in the case that it's not 0, this switch makes the output come from there. Of course, this is a machine with a potentially infinite number of parts, because factorial occurs within factorial, so we don't know how deep it has to be. But that's basically what our notation for programs really means to us at this point. It's a character string description, if you will, of a wiring diagram that could also be drawn some other way. And, in fact, many people have proposed to me, programming languages look graphical like this. I'm not sure I believe there are many advantages. The major disadvantage, of course, is that it takes up more space on a page, and, therefore, it's harder to pack into a listing or to edit very well. But in any case, there's something very remarkable that can happen in the competition world which is that you can have something called a universal machine. If we look at the second slide, what we see is a special machine called eval. There is a machine called eval, and I'm going to show it to you today. It's very simple. What is remarkable is that it will fit on the blackboard. However, eval is a machine which takes as input a description of another machine. It could take the wiring diagram of a factorial machine as input. Having done so, it becomes a simulator for the factorial machine such that, if you put a six in, out comes a 720. That's a very remarkable sort of machine. And the most amazing part of itis that it fits on a blackboard. By contrast, one could imagine in the analog electronics world a very different machine, a machine which also was, in some sense, universal, where you gave a circuit diagram as one of the inputs, for example, of this little low-pass filter, one-pole low-pass filter. And you can imagine that you could, for example, scan this out -- the scan lines are the signal that's describing what this machine is to simulate-- then the analog of that which is made out of electrical circuits, should configure itself into a filter that has the frequency response specified by the circuit diagram. That's a very hard machine to make, and, surely, there's no chance that I could put it on a blackboard. So we're going to see an amazing thing today. We're going to see, on the blackboard, the universal machine. And we'll see that among other things, it's extremely simple. Now, we're getting very close to the real spirit in the computer at this point. So I have to show a certain amount of reverence and respect, so I'm going to wear a suit jacket for the only time that you'll ever see me wear a suit jacket here. And I think I'm also going to put on an appropriate hat for the occasion. Now, this is a lecturer which I have to warn you -- let's see, normally, people under 40 and who don't have several children are advised to be careful. If they're really worried, they should leave. Because there's a certain amount of mysticism that will appear here which may be disturbing and cause trouble in your minds . Well in any case, let's see, I wish to write for you the evaluator for Lisp. Now the evaluator isn't very complicated. It's very much like all the programs we've seen already. That's the amazing part of it. It's going to be-- and I'm going to write it right here-- it's a program called eval. And it's a procedure of two arguments in expression of an environment. And like every interesting procedure, it's a case analysis. But before I start on this, I want to tel l you some things. The program we're going to write on the blackboard is ugly, dirty, disgusting, not the way I would write this is a professional. It is written with concrete syntax, meaning you've got really to use lots of CARs and CDRs which is exactly what I told you not to do. That's on purpose in this case, because I want it to be small, compact, fit on the blackboard so you can get the whole thing. So I don't want to use long names like I normally use. I want to use CAR -CDR because it's short. Now, that's a trade-off. I don't want you writing programs like this. This is purely for an effect. Now, you're going to have to work a little harder to read it, but I'm going to try to make it clear as I'm writing it. I'm also-- this is a pretty much complete interpreter, but there's going to be room for putting in more things-- I'm going to leave out definition and assignment, just because they are not essential, for a mathematical reason I'll show you later and also they take up more space. But, in any case, what do we have to do? We have to do a dispatch which breaks the types of expressions up into particular classes. So that's what we're going to have here. Well, what expressions are there? Let's look at the kinds of expressions. We can have things like the numeral three. What do I want that to do? I can make choices, but I think right now, I want it to be a three. That's what I want. So that's easy enough. That means I want, if the thing is a number, the expression, that I want the expression itself as the answer. Now the next possibility is things that we represent as symbols. Examples of symbols are things like x, n, eval, number, x. What do I mean them to be? Those are things that stand for other things. Those are the variables of our language. And so I want to be able to say, for example, that x, for example, transforms to it's value which might be three. Or I might ask something like car. I want to have as its value -- be something like some procedure, which I don't know what is inside there, perhaps a machine language code or something like that. So, well, that's easy enough. I'm going to push that off on someone else. If something is a symbol, if the expression is a symbol, then I want the answer to be the result, looking up the expression in the environment. Now the environment is a dictionary which maps the symbol names to their values. And that's all it is. How it's done? Well, we'll see that later. It's very easy. It's easy to make data structures that are tables of various sorts. But it's only a table, and this is the access routine for some table. Well, the next thing, another kind of expression-- you have things that are described constants that are not numbers, like 'foo. Well, for my convenience, I want to syntactically transform that into a list structure which is, quote foo. A quoted object, whatever it is, is going to be actually an abbreviation, which is not part of the evaluator but happens somewhere else, an abbreviation for an expression that looks like this. This way, I can test for the type of the expression as being a quotation by examining the car of the expression. So I'm not going to worry about that in the evaluator. It's happening somewhere earlier in the reader or something. If the expression of the expression is quote, then what I want, I want quote foo to itself evaluate to foo. It's a constant. This is just a way of saying that this evaluates to itself. What is that? That's the second of the list. It's the second element of the list. The second element of the list is it's CADR. So I'm just going to write here, CADR. What else do we have here? We have lambda expressions, for example, lambda of x plus x y. Well, I going have to have some representation for the procedure which is the value of an expression, of a lambda expression. The procedure here is not the expression lambda x. That's the description of it, the textual description. However, what what I going to expect to see here is something which contains an environment as one of its parts if I'm implementing a lexical language. And so what I'd like to see is some type flags. I'm going to have to be able to distinguish procedures later, procedures which were produced by lambdas, from ones that may be primitive. And so I'm going to have some flag, which I'll jus t arbitrarily call closure, just for historical reasons. Now, to say what parts of this are important. I'm going to need to know the bound variable list and the body. Well, that's the CDR of this, so it's going to be x and plus x y and some environment. Now this is not something that users should ever see, this is purely a representation, internally, for a procedure object. It contains a bound variable list, a body, and an environment, and some type tag saying, I am a procedure. I'm going to make one now. So if the CAR of the expression is quote lambda, then what I'm going to put here is-- I'm going to make a list of closure, the CDR of the procedure description was everything except the lambda, and the current environment. This implements the rule for environments in the environment model. It has to do with construction of procedures from lambda expressions. The environment that was around at the time the evaluator encountered the lambda expression is the environment where the procedure resulting interprets it's free variables. So that's part of that. And so we have to capture that environment as part of the procedure object. And we'll see how that gets used later. There are also conditional expressions of things like COND of say, p one, e one, p two, e two. Where this is a predicate, a predicate is a thing that is either true or false, and the expression to be evaluated if the predicate is true. A set of clauses, if you will, that's the name for such a thing. So I'm going put that somewhere else. We're going to worry about that in another piece of code. So EQ-- if the CAR of the expression is COND, then I'm going to do nothing more than evaluate the COND, the CDR of the expression. That's all the clauses in the environment that I'm given. Well, there's one more case, arbitrary thing like the sum of x and three, where this is an operator applied to operands, and there's nothing special about it. It's not one of the special cases, the special forms. These are the special forms. And if I were writing here a professional program, again, I would somehow make this data directed. So there wouldn't be a sequence of conditionals here, there'd be a dispatch on some bits if I were trying to do this in a more professional way. So that, in fact, I can add to the thing without changing my program much. So, for example, they would run fast, but I'm not worried about that. Here we're trying to look at this in its entirety. So it's else. Well, what do we do? In this case, I have to somehow do an addition. Well, I could find out what the plus is. I have to find out what the x and the three are. And then I have to apply the result of finding what the plus is to the result of finding out what the x and the three are. We'll have a name for that. So I'm going to apply the result of evaluating the CAR of the expression-- the car of the expression is the operator-- in the environment given. So evaluating the operator gets me the procedure. Now I have to evaluate all the operands to get the arguments. I'll call that EVLIST, the CDR of the operands, of the expression, with respect to the environment. EVLIST will come up later-- EVLIST, apply, COND pair, COND, lambda, define. So that what you are seeing here now is pretty much all there is in the evaluator itself. It's the case dispatch on the type of the expression with the default being a general application or a combination. Now there is lots of things we haven't defined yet. Let's just look at them and see what they are. We're going to have to do this later, evcond. We have to write apply. We're going to have to write EVLIST. We're going to write LOOKUP. I think that's everything, isn't there? Everything else is something which is simple, or primitive, or something like that. And, of course, we could many more special forms here, but that would be a bad idea in general in a language. You make a language very complicated by putting a lot of things in there. The number of reserve words that should exist in a language should be no more than a person could remember on his fingers and toes. And I get very upset with languages which have hundreds of reserve words. But that's where the reserve words go. Well, now let's get to the next part of this, the kernel, apply. What else is this doing? Well, apply's job is to take a procedure and apply it to its arguments after both have been evaluated to come up with a procedure and the arguments rather the operator symbols and the operand symbols, whatever they are-- symbolic expressions. So we will define apply to be a procedure of two arguments, a procedure and arguments. And what does it do? It does nothing very complicated. It's got two cases. Either the procedure is primitive-- And I don't know exactly how that is done. It's possible there's some type information just like we made closure for, here, being the description of the type of a compound thing-- probably so. But it is not essential how that works, and, in fact, it turns out, as you probably know or have deduced, that you don't need any primitives anyway. You can compute anything without them because some of the lambda that I've been playing with. But it's nice to have them. So here we're going to do some magic which I'm not going to explain. Go to machine language, apply primop. Here's how it adds. Execute an add instruction. However, the interesting part of a language is the glue by which the predicates are glued together. So let's look at that. Well, the other possibility is that this is a compound made up by executing a lambda expression, this is a compound procedure. Well, we'll check its type. If it is closure, if it's one of those, then I have to do an eval of the body. The way I do this, the way I deal with this at all, is the way I evaluate the application of a procedure to its arguments, is by evaluating the body of the procedure in the environment resulting from extending the environment of the procedure with the bindings of the formal parameters of the procedure to the arguments that were passed to it. That was a long senten ce. Well that's easy enough. Now here's going to be a lot of CAR-CDRing. I have to get the body of the procedure. Where's the body of the procedure in here? Well here's the CAR, here's the CDR is the whole rest of this. So here's the CADR. And so I see,what I have here is the body is the second element of the second element of the procedure. So it's the CADR of the CADR or the CADADR. It's the C-A-D-A-D-R, CADADR of the procedure. To evaluate the body in the result of binding that's making up more environment, well I need the formal parameters of the of the procedure, what is that? That's the CAR of the CDR. It's horrible isn't it? --of the procedure. Bind that to the arguments that were passed in the environment, which is passed also as part of the procedure. Well, that's the CAR of the CDR of the CDR of this, CADADR, of the procedure. Bind, eval, pair, COND, lamda, define-- Now, of course, if I were being really a neat character, and I was being very careful, I would actually put an extra case here for checking for certain errors like, did you try to apply one to an argument? You get a undefined procedure type. So I may as well do that anyway. -- else, some sort of error, like that. Now, of course, again, in some sort of more real system, written for professional reasons, this would be written with a case analysis done by some sort of dispatch. Over here, I would probably have other cases like, is this compiled code? It's very important. I might have distinguished the kind of code that's produced by a directly evaluating a lambda in interpretation from code that was produced by somebody's compiler or something like that. And we'll talk about that later. Or is this a piece Fortran program I have to go off and execute. It's a perfectly possible thing, at this point, to do that. In fact, in this concrete syntax evaluator I'm writing here, there's an assumption built in that this is Lisp, because I'm using CARs and CDRs. CAR means the operator, and CDR means the operand. In the text, there is an abstract syntax evaluator for which these could be-- these are given abstract names like operator, and operand, and all these other things are like that. And, in that case, you could reprogram it to be ALGOL with no problem. Well, here we have added another couple of things that we haven't defined. I don't think I'll worry about these at all, however, this one will be interesting later. Let's just proceed through this and get it done. There's only two more blackboards so it can't be very long. It's carefully tailored to exactly fit. Well, what do we have left? We have to define EVLIST, which is over here. And EVLIST is nothing more than a map down a bunch of operands producing arguments. But I'm going to write it out. And one of the reasons I'm going to writethis out is for a mystical reason, which is I want to make this evaluator so simple that it can understand itself. I'm going to really worry about that a little bit. So let's write it out completely. See, I don't want to worry about whether or not the th ing can pass functional arguments. The value evaluator is not going to use them. The evaluator is not going to produce functional values. So even if there were a different, alternative language that were very close to this, this evaluates a complex langua ge like Scheme which does allow procedural arguments, procedural values, and procedural data. But even if I were evaluating ALGOL, which doesn't allow procedural values, I could use this evaluator. And this evaluator is not making any assumptions about that. And, in fact, if this value were to be restricted to not being able to that, it wouldn't matter, because it doesn't use any of those clever things. So that's why I'm arranging this to be super simple. This is sort of the kernel of all possible language evaluators. How about that? Evlist-- well, what is it? It's the procedure of two arguments, l and an environment, where l is a list such that if the list of arguments is the empty list, then the result is the empty list. Otherwise, I want to cons up the result of evaluating the CAR of the list of operands in the environment. So I want the first operand evaluated, and I'm going to make a list of the results by CONSing that onto the result of this EVLISTing as a CDR recursion, the CDR of the list relative to the same environment. Evlist, cons, else, COND, lambda, define-- And I have one more that I want to put on the blackboard. It's the essence of this whole thing. And there's some sort of next layer down. Conditionals-- conditionals are the only thing left that are sort of substantial. Then below that, we have to worry about things like lookup and bind, and we'll look at that in a second. But of the substantial stuff at this level of detail, next important thing is how you deal with conditionals. Well, how do we have a conditional thing? It's a procedure of a set of clauses and an environment. And what does it do? It says, if I've no more clauses, well, I have to give this a value. It could be that it was an error. Supposing it run off the end of a conditional, it's pretty arbitrary. It's up to me as programmer to choose what I want to happen. It's convenient for me, right now, to write down that this has a value which is the empty list, doesn't matter. For error checking, some people might prefer something else. But the interesting things are the following ones. If I've got an else clause -- You see, if I have a list of clauses, then each clause is a list. And so the predicate part is the CAAR of the clauses. It's the CAR, which is the first part of the first clause in the list of clauses. If it's an else, then it means I want my result of the conditional to be the result of evaluating the matching expression. So I eval the CADR. So this is the first clause, the second element of it, CADAR-- CADAR of a CAR-- of the clauses, with respect to the environment. Now the next possibility is more interesting. If it's false, if the first predicate in the predicate list is not an else, and it's not false, if it's not the word else, and if it's not a false thing-- Let's write down what it is if it's a false thing. If the result of evaluating the first predicate, the clauses-- respect the environment, if that evaluation yields false, then it means, I want to look at the next clause. So I want to discard the first one. So we just go around loop, evcond, the CDR of the clauses relative to that environment. And otherwise, I had a true clause, in which case, what I want is to evaluate the CADAR of the clauses relative to that environment. Boy, it's almost done. It's quite close to done. I think we're going to finish this part off. So just buzzing through this evaluator, but so far you're seeing almost everything. Let's look at the next transparency here. Here is bind. Bind is for making more table. And what we are going to do here is make a-- we're going to make a no-frame for an environment structure. The environment structure is going to be represented as a list of frames. So given an existing environment structure, I'm going to make a new environment structure by consing a new frame onto the existing environment structure, where the new frame consists of the result of pairing up the variables, which are the bound variables of the procedure I'm applying, to the values which are the arguments that were passed that procedure. This is just making a list, adding a new element to our list of frames, which is an environment structure, to make a new environment. Where pair-up is very simple. Pair -up is nothing more than if I have a list of variables and a list of value s, well, if I run out of variables and if I run out of values, everything's OK. Otherwise, I've given too many arguments. If I've not run out of variables, but I've run out of values, that I have too few arguments. And in the general case, where I don't have any errors, and I'm not done, then I really am just adding a new pair of the first variable with the first argument, the first value, onto a list resulting from pairing -up the rest of the variables with the rest of the values. Lookup is of course equally simple. If I have to look up a symbol in an environment, well, if the environment is empty, then I've got an unbound variable. Otherwise, what I'm going to do is use a special pair list lookup procedure, which we'll have very shortly, of the symbol n i the first frame of the environment. Since I know the environment is not empty, it must have a first frame. So I lookup the symbol in the first frame. That becomes the value cell here. And then, if the value cell is empty, if there is no such value cell , then I have to continue and look at the rest of the frames. It means there was nothing found there. So that's a property of ASSQ is it returns emptiness if it doesn't find something. but if it did find something, then I'm going to use the CDR of the value cell here, which is the thing that was the pair consisting of the variable and the value. So the CDR of it is the value part. Finally, ASSQ is something you've probably seen already. ASSQ takes a symbol and a list of pairs, and if the list is empty, it's empty. If the symbol is the first thing in the list-- That's an error. That should be CAAR, C-A-A-R. Everybody note that. Right there, OK? And in any case, if the symbol is the CAAR of the A list, then I want the first, the first pair, in the A list. So, in other words, if this is the key matching the right entry, otherwise, I want to look up that symbol in the rest. Sorry for producing a bug, bugs appear. Well, in any case, you're pretty much seeing the whole thing now. It's a very beautiful thing, even though it's written in an ugly style, being the kernel of every language. I suggest that we just-- let's look at it for a while. [MUSIC PLAYING] Are there any questions? Alright, I suppose it's time to take a small break then. [MUSIC PLAYING] OK, now we're just going to do a little bit of practice understanding what it is we've just shown you. What we're going to do is go through, in detail, an evaluation by informally substituting through the interpreter. And since we have no assignments ordefinitions in this interpreter, we have no possible side effects, and so the we can do substitution with impunity and not worry about results. So the particular problem I'd like to look at is it an interesting one. It's the evaluation of quote, open, open, open, lambda of x, lambda of y plus x y, lambda, lambda, applied to three, applied to four, in some global environment which I'll call e0. So what we have here is a procedure of one argument x, which produces as its value a procedure of one argument y, which adds x to y. We are applying the procedure of one argument x to three. So x should become three. And the result of that should be procedure of one argument y, which will then apply to 4. And there is a very simple case, they will then add those results. And now in order to do that, I want to make a very simple environment model. And at this point, you should already have in your mind the environments that this produces. But we're going to start out with a global environment, which I'll call e0, which is that. And it's going to have in it things, definitions for plus, and times, and-- using Greek letters, isn't that interesting, for the objects-- and minus, and quotient, and CAR, and CDR, and CONS, and EQ, and everything else you might imagine in a global environment. It's got something there for each of those things, something the machine is born with, that's e0. Now what does it mean to do this evaluation? Well, we go through the set of special forms. First of all, this is not a number. This is not a symbol. Gee, it's not a quoted expression. This is a quoted expression, but that's not what I interested in. The question is, whether or not the thing which is quoted is quoted expression? I'm evaluating an expression. This just says it's this particular expression. This is not a quoted expression. It's not a thing that begins with lambda. It's not a thing that begins with COND. Therefore, it's an application of its of an operated operands. It's a combination. The combination thus has this as the operator and this is the operands. Well, that means that what I'm going to do is transform this into apply of eval, of quote, open, open lambda of x, lambda of y-- I'm evaluating the operator-- plus x y, in the environment, also e0, with the operands that I'm going to apply this to, the arguments being the result of EVLIST, the list containing four, fin e0. I'm using this funny notation here for e0 because this should be that environment. I haven't a name for it, because I have no environment to name it in.So this is just a representation of what would be a quoted expression, if you will. The data structure, which is the environment, goes there. Well, that's what we're seeing here. Well in order to do this, I have to do this, and I have to do that. Well this one's easy, so why don't we do that one first. This turns into apply of eval-- just copying something now. Most of the substitution rule is copying. So I'm going to not say the words when I copy, because it's faster. And then the EVLIST is going to tur n into a cons, of eval, of four, in e0-- because it was not an empty list-- onto the result of EVLISTing, on the empty list, in e0. And I'm going to start leaving out steps soon, because it's going to get boring. But this is basically the same thing as apply, of eval-- I'm going to keep doing this-- the lambda of x, the lambda of y, plus xy, 3, close, e0. I'm a pretty good machine. Well, eval of four, that's meets the question, is it a number. So that's cons, cons of 4. And EVLIST of the empty list is the empty list, so that's this. And that's very simple to understand, because that means the list containing four itself. So this is nothing more than apply of eval, quote, open, open, lambda of x, lambda of y, plus x y, three applied to, e0, applied to the list four-- bang. So that's that step. Now let's look at the next, more interesting thing. What do I do to evaluate that? Evaluating this means I have to evaluate-- Well, it's not. It's nothing but an application. It's not one of the special things. If the application of this operator, which we see here-- here's the operator-- applied to this operands, that combination. But we know how to do that, because that's the last case of the conditional. So substituting in for this evaluation, it's apply of eval of the operator in the EVLIST of the operands. Well, it's apply, of apply, of eval, of quote, open, lambda of x, lambda of y, plus x y, lambda, lambda, in environment e0. I'm going to short circuit the evaluation of the operands , because they're the same as they were before. I got a list containing three, apply that, and apply that to four. Well let's see. Eval of a lambda expression produces a procedure object. So this is apply, of apply, of the procedure object closure, which contains the body of the procedure, x, which is lambda-- which binds x [UNINTELLIGIBLE] the internals of the body, it returns the procedure of one argument y, which adds x to y. Environment e0 is now captured in it, because this was evaluated with respect to e0. e0 is part now ofthe closure object. Apply that to open, three, close, apply, to open, 4, close, apply. So going from this step to this step meant that I made up a procedure object which captured in it e0 as part of the procedure object. Now, we're going to pass those to apply. We have to apply this procedure to that set of arguments. Well, but that procedure is not primitive. It's, in fact, a thing which has got the tag closure, and, therefore, what we have to do is do a bind. We have to bind. A new environment is made at this point, which has as its parent environment the one over here, e0, that environment. And we'll call this one, e1. Now what's bound in there? x is bound to three. So I have x equal three. That's what's in there. And we'll call that e1. So what this transforms into is an eval of the body of this, which is this, the body of that procedure, in the environment that you just saw. So that's an apply, of eval, quote, open, lambda of y, plus x y-- the body-- in e1. And apply the result of that to four, open, close, 4-- list of arguments. Well, that's sensible enough because evaluating a lambda, I know what to do. That means I apply, the procedure which is closure, binds one argument y, adds x to y, with e1 captured in it. And you should really see this. I somehow manufactured a closure. I should've put this here. There was one over here too. Well, there's one here now. I've captured e1, and this is the procedure of one argument y, whatever this is. That's what that is there, that closure. I'm going to apply that to four. Well, that's easy enough. That means I have to make a new environment by copying this pointer, which was the pointer of the procedure, which binds y equal 4 with that environment. And here's my new environment, whic h I'll call e2. And, of course, this application then is evaluate the body in e2. So this is eval, the body, which is plus x y, in the environment e2. But this is an application, so this is the apply, of eval, plus in e2, an EVLIST, quote, open, x y, in e2. Well, but let's see. That is apply, the object which is a result of that and plus. So here we are in e2, plus is not here, it's not here, oh, yes, but's here as some primitive operator. So it's the primitive operator for addition. Apply that to the result of evaluating x and y in e2. But we can see that x is three and y is four. So that's a three and four, here. And that magically produces for me a seven. I wanted to go through this so you would see, essentially, one important ingredient, which is what's being passed around, and who owns what, and what his job is. So what do we have here? We have eval, and we have apply, the two main players. And there is a big loop the goes around like this. Which is eval produces a procedure and arguments for apply. Now some things eval could do by itself. Those are little self things here. They're not interesting. Also eval evaluates all of the arguments, one after another. That's not very interesting. Apply can apply some procedures like plus, not very interestin g. However, if apply can't apply a procedure like plus, it produces an expression and environment for eval. The procedural arguments wrap up essentially the state of a computation and, certainly, the expression of environment. And so what we're actually going to do next is not the complete state, because it doesn't say who wants the answers. But what we're going to do-- it's always got something like an expression of environment or procedure and arguments as the main loop that we're going around. There are minor little sub loops like eval through EVLIST, or eval through evcond, or apply through a primitive apply. But they're not the essential things. So that's what I wanted you to see. Are there any questions? Yes. AUDIENCE: I'm trying to understand how x got down to three instead of four. At the early part of the-- PROFESSOR: Here. You want to know how x got down to three? AUDIENCE: Because x is the outer procedure, and x and y are the inner procedure. PROFESSOR: Fine. Well, I was very careful and mechanical. First of all, I should write those procedures again for you, pretty printed. First order of business, because you're probably not reading them well. So I have here that procedure of-- was it x over there-- which is-- value of that procedure of y, which adds x to y, lambda, lambda, applied that to three, takes the result of that, and applied that to four. Is that not what I wrote? Now, you should immediately see that here is an application-- let me get a white piece of chalk-- here is an application, a combination. That combination has this as the operator and this as the operand. The three is going in for the x here. The result of this is a procedureof one argument y, which gets applied to four. So you just weren't reading the expression right. The way you see that over here is that here I have the actual procedure object, x. It's getting applied to three, the list containing three. What I'm left over with is something which gets applied to four. Are there any other questions? Time for our next small break then. Thank you. [MUSIC PLAYING] Let's see, at this point, you should be getting the feeling, what's this nonsense this Sussman character is feeding me? There's an awful lot of strange nonsense here. After all, he purported to explain to me Lisp, and he wrote me a Lisp program on the blackboard. The Lisp program was intended to be interpreted for Lisp, but you need a Lisp interpreter in order to understand that program. How could that program have told me anything there is to be known about Lisp? How is that not completely vacuous? It's a very strange thing. Does it tell me anything at all? Well, you see, the whole thing is sort of like these Escher's hands that we see on this slide. Yes, eval and apply each sort of draw each other and construct the real thing, which can sit out and draw itself. Escher was a very brilliant man, he just didn't know the names of these spirits. Well, I'm going to do now, is I'm going to try to convince you that both this mean something, and, as a aside, I'm going to show you why you don't need definitions. Just turns out that that sort of falls out, why definitions are not essential in a mathematical sense for doing all the things we need to do for computing. Well, let's see here. Consider the following small program, what does it mean? This is a program for computing exponentials. The exponential of x to the nth power is if-- and is zero, then the result is one. Otherwise, I want the product of x and the result of exponentiating x to the n minus one power. I think I got it right. Now this is a recursive definition. It's a definition of the exponentiation procedure in terms of itself. And, as it has been mentioned before, your high school geometry teacher probably gave you a hard time about things like that. Was that justified? Why does this self referential definition make any sense? Well, first of all, I'm going to convince you that your high school geometry teacher was I telling you nonsense. Consider the following set of definitions here. x plus y equals three, and x minus y equal one. Well, gee, this tells you x in terms of y, and this one tells you y in terms of x, presumably. And yet this happens to have a unique solution in x and y. However, I could also write two x plus two y is six. These two equations have an infinite number solutions. And I could write you, for example, x minus y equal 2, and these two equations have no solutions. Well, I have here three sets of simultaneous linear equations, this set, this set, and this set. But they have different numbers of solutions. The number of solutions is not in the form of the equations. They all three sets have the same form. The number of solutionsis in the content. I can't tell by looking at the form of a definition whether it makes sense, only by its detailed content. What are the coefficients, for example, in the case of linear equations? So I shouldn't expect to be able to tell looking at something like this, from some simple things like, oh yes, EXPT is the solution of this recursion equation. Expt is the procedure which if substituted in here, gives me EXPT back. I can't tell, looking at this form, whether or not there's a single, unique solution for EXPT, an infinite number of solutions, or no solutions. It's got to be how it counts and things like that, the details. And it's harder in programming than linear algebra. Th ere aren't too many theorems about it in programming. Well, I want to rewrite these equations a little bit, these over here. Because what we're investigating is equations like this. But I want to play a little with equations like this that we understand, just so we get some insight into this kind of question. We could rewrite our equations here, say these two, the ones that are interesting, as x equals three minus y, and y equals x minus one. What do we call this transformation? This is a linear transform ation, t. Then what we're getting here is an equation x y equals t of x y. What am I looking for? I'm looking for a fixed point of t. The solution is a fixed point of t. So the methods we should have for looking for solutions to equations, if I can doit by fixed points, might be applicable. If I have a means of finding a solution to an equations by fixed points-- just, might not work-- but it might be applicable to investigating solutions of equations like this. But what I want you to feel is that this is an equation. It's an expression with several instances of various names which puts a constraint on the name, saying what that name could have as its value, rather than some sort of mechanical process of substitution right now. This is an equation which I'm going to try to solve. Well, let's play around and solve it. First of all, I want to write down the function which corresponds to t. First I want to write down the function which corresponds to t whose fixed point is the answer to this question. Well, let's consider the following procedure f. I claim it computes that function. f is that procedure of one argument g, which is that procedure of two arguments x and n. Which have the property that if n is zero, then the result is one, otherwise, the result is the product of x and g, applied to x, and minus n1. g, times, else, COND, lambda, lambda-- Here f is a procedure, which if I had a solution to that equation, if I had a good exponentiation procedure, and I applied f to that procedure, then the result would be a good exponentiation procedure. Because, what does it do? Well, all it is is exposing g were a good exponentiation procedure, well then this would produce, as its value, a procedure to arguments x and n, such that if n were 0, the result woul d be one, which is certainly true of exponentiation. Otherwise, it will be the result of multiplying x by the exponentiation procedure given to me with x and n minus one as arguments. So if this computed the correct exponentiation for n minus one, then thi s would be the correct exponentiation for exponent n, so this would have been the right exponentiation procedure. So what I really want to say here is E-X-P-T is a fixed point of f. Now our problem is there might be more than one fixed point. There might be no fixed points. I have to go hunting for the fixed points. Got to solve this equation. Well there are various ways to hunt for fixed points. Of course, the one we played with at the beginning of this term worked for cosine. Go into radians mode on your calculator and push cosine, and just keep doing it, and you get to some number which is about 0.73 or 0.74. I can't remember which. By iterating a function, whose fixed point I'm searching for, it is sometimes the case that that function will converge in producing the fixed point. I think we luck out in this case, so let's look for it. Let's look at this slide. Consider the following sequence of procedures. e0 over here is the procedure which does nothing at all. It's the procedure which produces an error for any arguments you give it. It's basically useless. Well, however, I can make an approximation. Let's consider it the worst possible approximation to exponentiation, because it does nothing. Well, supposing I substituted e0 for g by calling f, as you see over here on e0. So you see over here, have e0 there. Then gee, what's e1? e1 is a procedure which exponentiate things to the 0th power, with no trouble. It gets the right answer, anything to the zero is one, and it makes an error on anything else. Well, now what if I take e1 and I substitute if for g by calling f on e1? Oh gosh, I have here a procedure of two arguments. Now remember e1 was appropriate for taking exponentiations of 0, for raising to the 0 exponent. So here, is n is 0, the resultis one, so this guy is good for that too. However, I can use something for raising to the 0th power to multiply it by x to raise something to the first power. So e2 is good for both power 0 and one. And e3 is constructed from e2 in the same way. And e3, of course, by the same argument is good for powers 0, one, and two. And so I will assert for you, without proof, because the proof is horribly difficult. And that's the sort of thing that people called denotational semanticists do. This great idea was invented by Scott and Strachey. They're very famous mathematician types who invented the interpretation for these programs that we have that I'm talking to you about right now. And they proved, by topology that there is such a fixed point in the cases that we want. But the assertion is E-X-P-T is limit as n goes to infinity of em. and And that we've constructed this by the following way. --is Well, it's f of, f of, f of, f of, f of-- f applied to anything at all. It didn't matter what that was, because, in fact, this always produces an error. Applied to this-- That's by infinite nesting of f's. So now my problem is to make some infinite things. We need some infinite things. How am I going to nest up an f an infinite number of times? I'd better construct this. Well, I don't know. How would I make an infinite loop at all? Let's take a very simple infinite loop, the simplest infinite loop imaginable. If I were to take that procedure of one argument x which applies x to x and apply that to the procedure of one argument x which applies x to x, then this is an infinite loop. The reason why this is an infinite loop is as follows. The way I understand this is I substitute the argument for the formal parameter in the body. But if I do that, I take for each of these x's, I substitute one of these, making a copy of the original expression I just started with, the simplest infinite loop. Now I want to tell you about a particular operator which is constructed by a perturbation from this infinite loop. I'll call it y. This is called Curry's Paradoxical Combinator of y after a fellow by the name of Curry, who was a logician of the 1930s also. And if I have a procedure of one argument f, what's it going to have in it? It's going to have a kind of infinite loop in it, which is that procedure of one argument x which applies f to x of x, applied to that procedure of one argument x, which applies f to f of x. Now what's this do? Suppose we apply y to F. Well, that's easy enough. That's this capital F over here. Well, the easiest thing to say there is, I substitute F for here. So that's going to give me, basically -- because then I'm going to substitute this for x in here. Let me actually do it in steps, so you can see it completely. I'm going to be very careful. This is open, open, lambda of x , capital F, x, x, applied to itself, F of x of x. Substituting this for this in here, this is F applied to-- what is it-- substituting this in here, open, open, lambda of x, F, of x and x, applied to lambda of x, F of x of x, F, lambda, pair, F. Oh, but what is this? This thing over here that I just computed, is this thing over here. But I just wrapped another F around it. So by applying y to F, I make an infinite series of F's. If I just let this run forever, I'll just keep making more and more F's outside. I ran an infinite loop which is useless, but it doesn't matter that the inside is useless. So y of F is F applied to y of F. So y is a magical thing which, when applied to some function, produces the object which is the fixed point of that function, if it exists, and if this all works. Because, indeed, if I take y of F and put it into F, I get y of F out. Now I want you to think this in terms of the eval-apply interpreter for a bit. I wrote down a whole bunch of recursion equations out there. They're simultaneous in the same way these are simultaneous equations. Exponentiation was not a simultaneous equation. It was only one variable I was looking for a meaning for. But what Lisp is is the fixed point of the process which says, if I knew what Lisp was and substituted it in for eval, and apply, and so on, on the right hand sides of all those recursion equations, then if it was a real good Lisp, is a real one, then the left hand side would also be Lisp. So I made sense of that definition. Now whether or not there's an answer isn't so obvious. I can't attack that. Now these arguments that I'm giving you now are quite dangerous. Let's look over here. These are limit arguments. We're talking about limits, and it's really calculus, or topology, or something like that, a kind of analysis. Now here's an argument that you all believe. And I want to make sure you realize that I could be bullshitting you. What is this? u is the sum of 1/2, 1/4, and 1/8, and so on, the sum of a geometric series. And, of course, I could play a game here. u minus one is 1/2, plus 1/4, plus 1/8, and so on. What I could do here-- oops. There is a parentheses error here. But I can put here two times u minus one is one plus 1/2, plus 1/4, plus 1/8. Can I fix that? Yes, well. But that gives me back two times u minus one is u, therefore, we conclude that u is two. And this actually is true. There's no problem like that. But supposing I did something different. Supposing I start up with something which manifestly has no sum. v is one, plus two, plus four, plus 8, plus dot, dot, dot. Well, v minus one is surely two, plus four, plus eight, plus dot, dot, dot. v minus one over two, gee, that looks like v again. From that I should be able to conclude that-- that's also wrong, apparently. v equals minus one. That should be a minus one. And that's certainly a false conclusion. So when you play with limits, arguments that may work in one case they may not work in some other case. You have to be very careful. The arguments have to be well formed. And I don't know, in general, what the story is about arguments like this. We can read a pile of topology and find out. But, surely, at least you understand now, why it might be some meaning to the things we've been writing on the blackboard. And you understand what that might mean. So, I suppose, it's almost about time for you to merit being made a member of the grand recursive order of lambda calculus hackers. This is the badge. Because you now understand, for example, what it says at the very top, y F equals F y F. Thank you. Are there any questions? Yes, Lev. AUDIENCE: With this, it seems that then there's no need to define, as you imply, to just remember a value, to apply it later. Defines were kind of a side-effect it seemed in the language. [INTERPOSING] are order dependent. Does this eliminate the side-effect from the [INTERPOSING] PROFESSOR: The answer is, this is not the way these things were implemented. Define, indeed is implemented as an operation that actually modifies an environment structure, changes the frame that the define is executed in. And there are many reasons for that, but a lot of this has to do with making an interactive system. What this is saying is that if you've made a system, and you know you're not going to do any debugging or anything like that, and you know everything there is all at once, and you want to say, what is the meaning of a final set of equations? This gives you a meaning for it. But in order to make an interactive system, where you can change the meaning of one thing without changing everything else, incrementally, you can't do that by implementing it this way. Yes. AUDIENCE: Another question on your danger slide. It seemed that the two examples that you gave had to do with convergence and non-convergence? And that may or may not have something to do with function theory in a way which would lead you to think of it in terms of linear systems, or non-linear systems. How does this convergence relate to being able to see a priori what properties of that might be violated? PROFESSOR: I don't know. The answer is, I don't know under what circumstances. I don't know how to translate that into less than an hour of talk more. What are the conditions under which, for which we know that these things converge? And v, all that was telling you that arguments that are based on convergence are flaky if you don't know the convergence beforehand. You can make wrong arguments. You can make deductions, as if you know the answer, and not be stopped somewhere by some obvious contradiction. AUDIENCE: So can we say then that if F is a convergent mathematical expression, then the recursion property can be-- PROFESSOR: Well, I think there's a technical kind of F, there is a technical description of those F's that have the property that when you iteratively apply them like this, you converge. Things that are monotonic, and continuous, and I forgot what el se. There is a whole bunch of little conditions like that which have this property. Now the real problem is deducing from looking at the F, its definition here, whether not it has those properties, and that's very hard. The properties are easy. You can write them down. You can look in a book by Joe Stoy. It's a great book-- Stoy. It's called, The Scott-Strachey Method of Denotational Semantics, and it's by Joe Stoy, MIT Press. And he works out all this in great detail, enough to horrify you. But it reallyis readable. OK, well, thank you. Time for the bigger break, I suppose. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation f ormat: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec7b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 7B: Metacircular Evaluator, Part 2 [MUSIC PLAYING] PROFESSOR: Well, let's see. What we did so far was a lot of fun, was it useful for anything? I suppose the answer is going to be yes. If these metacircular interpreters are a valuable thing to play with. Well, there have been times I spend 50% of my time, over a year, trying various design alternatives by experimenting with them with metacircular interpreters-- metacircular interpreters like the sort you just saw. Metacircular is because they are defined in terms of themselves in such a way that the language they interpret contains itself. Such interpreters are a convenient medium for exploring language issues. If you want to try adding a new feature, it's sort of a snap, it's easy, you just do it and see what happens. You play with that language for a while you say, gee, I'm didn't like that, you throw it away. Or you might want to see what the difference is if you'd make a slight difference in the binding strategy, or some more complicated things that might occur. In fact, these metacircular interpreters are an excellent medium for people exchanging ideas about language design, because they're pretty easy to understand, and they're short, and compact, and simple. If I have some idea that I want somebody to criticize like say, Dan Friedman at Indiana, I'd write a little metacircular interpreter and send him some network mail with this interpreter in it. He could whip it up on his machine and play with it and say, that's no good. And then send it back to me and say, well, why don't you try this one, it's a little better. So I want to show you some of that technology. See, because, really, it's the essential, simple technology for getting started in designing your own languages for particular purposes. Let's start by adding a very simple feature to a Lisp. Now, one thing I want to tell you about is features, before I start. There are many languages that have made a mess of themselves by adding huge numbers of features. Computer scientists have a joke about bugs that transform it to features all the time. But I like to think of it is that many systems suffer from what's called creeping featurism. Which is that George has a pet feature he'd like in the system, so he adds it. And then Harry says, gee, this system is no longer what exactly I like, so I'm going to add my favorite feature. And then Jim adds his favorite feature. And, after a while, the thing has a manual 500 pages long that no one can understand. And sometimes it's the same person who writes all of these features and produces this terribly complicated thing. In some cases, like editors, it's sort of reasonable to have lots of features, because there are a lot of things you want to be able to do and many of them arbitrary. But in computer languages, I think it's a disaster to have too much stuff in them. The other alternative you get into is something called feeping creaturism, which is where you have a box which has a display, a fancy display, and a mouse, and there is all sorts of complexity associated with all this fancy IO. And your computer language becomes a dismal, little, tiny thing that barely works because of all the swapping, and disk twitching, and so on, caused by your Windows system. And every time you go near the computer, the mouse process wakes up and says, gee do you have something for me to do, and then it goes back to sleep. And if you accidentally push mouse with you elbow, a big puff of smoke comes out of your computer and things like that. So two ways to disastrously destroy a system by adding features. But try right now to add a little, simple feature. This actually is a good one, and in fact, real Lisps have it. As you've seen, there are procedures like plus and times that take any number of arguments. So we can write things like the sum of the product of a and x and x, and the product of b and x and c. As you can see here, addition takes three arguments or two arguments, multiplication takes two arguments or three arguments, taking numbers of arguments all of which are to be treated in the same way. This is a valuable thing, indefinite numbers of arguments. Yet the particular Lisp system that I showed you is one where the numbers of arguments is fixed, because I had to match the arguments against the formal parameters in the binder, where there's a pairup. Well, I'd like to be able to define new procedures like this that can have any number of arguments. Well there's several parts to this problem. The first part is coming up with the syntactic specification, some way of notating the additional arguments, of which you don't know how many there are. And then there's the other thing, which is once we've notated it, how are we going to interpret that notation so as to do the right thing, whatever the right thing is? So let's consider an example of a sort of thing we might want to be able to do. So an example might be, that I might want to be able to define a procedure which is a procedure of one required argument x and a bunch of arguments, I don't know how many there are, called y. So x is required, and there are many y's, many argument-- y will be the list of them. Now, with such a thing, we might be able to say something like, map-- I'm going to do something to every one-- of that procedure of one argument u, which multiplies x by u, and we'll apply that to y. I've used a dot here to indicate that the thing after this is a list of all the rest of the arguments. I'm making a syntactic specification. Now, what this depends upon, the reason why this is sort of a reasonable thing to do, is because this happens to be a syntax that's used in the Lisp reader for representing conses. We've never introduced that before. You may have seen when playing with the system that if you cons two things together, you get the first, space, dot, the second, space -- the first, space, dot, space, the second with parentheses around the whole thing. So that, for example, this x dot y corresponds to a pair, which has got an x in it and a y in it. The other notations that you've seen so far are things like a procedure of arguments x and y and z which do things, and that looks like-- Just looking at the bound variable list, it looks like this, x, y, z, and the empty thing. If I have a list of arguments I wish to match this against, supposing, I have a list of arguments one, two, three, I want to match these against. So I might have here a list of three things, one, two, three. And I want to match x, y, z against one, two, three. Well, it's clear that the one matches the x, because I can just sort of follow the structure, and the two matches the y, and the three matches the z. But now, supposing I were to compare this x dot y-- this is x dot y-- supposing I compare that with a list of three arguments, one, two, three. Let's look at that again. One, two, three-- Well, I can walk along here and say, oh yes, x matches the one, the y matches the list, which is two and three. So the notation I'm choosing here is one that's very natural for Lisp system. But I'm going to choose this as a notation for representing a bunch of arguments. Now, there's an alternative possibility. If I don't want to take one special out, or two special ones out or something like that, if I don't want to do that, if I want to talk about just the list of all the arguments like in addition, well then the argument list I'm g oing to choose to be that procedure of all the arguments x which does something with x. And which, for example, if I take the procedure, which takes all the arguments x and returned the list of them, that's list. That's the procedure list. How does this work? Well, indeed what I had as the bound variable list in this case, whatever it is, is being matched against a list of arguments. This symbol now is all of the arguments. And so this is the choice I'm making for a particular syntactic specification, for the description of procedures which take indefinite numbers of arguments. There are two cases of it, this one and this one. When you make syntactic specifications, it's important that it's unambiguous, that neither of these can be confused with a representation we already have, this one. I can always tell whether I have a fixed number of explicitly named arguments made by these formal parameters, or a fixed number of named formal parameters followed by a thing which picks up all the rest of them, or a li st of all the arguments which will be matched against this particular formal parameter called x, because these are syntactically distinguishable. Many languages make terrible errors in that form where whole segments of interpretation are cut off, because there are syntactic ambiguities in the language. They are the traditional problems with ALGOL like languages having to do with the nesting of ifs in the predicate part. In any case, now, so I've told you about the syntax, now, what are we going to do ab out the semantics of this? How do we interpret it? Well this is just super easy. I'm going to modify the metacircular interpreter to do it. And that's a one liner. There it is. I'm changing the way you pair things up. Here's the procedure that pairs the variables, the formal parameters, with the arguments that were passed from the last description of the metacircular interpreter. And here's some things that are the same as they were before. In other words, if the list of variables is empty, then if the list of values is empty, then I have an empty list. Otherwise, I have too many arguments, that is, if I have empty variables but not empty values. If I have empty values, but the variables are not empty, I have too few arguments. The variables are a symbol-- interesting case-- then, what I should do is say, oh yes, this is the special case that I have a symbolic tail. I have here a thing just like we looked over here. This is a tail which is a symbol, y. It's not a nil. It's not the empty list. Here's a symbolic tail that is just the very beginning of the tail. There is nothing else. In that case, I wish to match that variable with all the values and add that to the pairing that I'm making. Otherwise, I go through the normal arrangement of making up the whole pairing. I suppose that's very simple. And that's all there is to it. And now I'll answer some questions. The first one-- Are there any questions? Yes? AUDIENCE: Could you explain that third form? PROFESSOR: This one? Well, maybe we should look at the thing as a piece of list structure. This is a procedure which contains a lambda. I'm just looking at the list structure which represents this. Here's x. These are our symbols. And then the body is nothing but x. If I were looking for the bound variable list part of this procedure, I would go looking at the CADR, and I'd find a symbol. So the, naturally, which is this pairup thing I just showed you, is going to be matching a symbolic object against a list of arguments that were passed. And it will bind that symbol to the list of arguments. In this case, if I'm looking for it, the match will be against this in the bound variable list position. Now, if what this does is it gets a list of arguments and returns it, that's list. Tha t's what the procedure is. Oh well, thank you. Let's take a break. [MUSIC PLAYING] PROFESSOR: Well let's see. Now, I'm going to tell you about a rather more substantial variation, one that's a famous variation that many early Lisps had. It's called dyn amic binding of variables. And we'll investigate a little bit about that right now. I'm going to first introduce this by showing you the sort of thing that would make someone want this idea. I'm not going to tell what it is yet, I'm going to show you why you might want it. Suppose, for example, we looked at the sum procedure again for summing up a bunch of things. To be that procedure, of a term, lower bound, method of computing the next index, and upper bound, such that, if a is greater than b then the r esult is 0, otherwise, it's the sum, of the term, procedure, applied to a and the result of adding up, terms, with the next a being the a, the next procedure passed along, and the upper bound being passed along. Blink, blink, blink-- Now, when I use this sum procedure, I can use it, for example, like this. We can define the sum of the powers to be, for example, sum of a bunch of powers x to the n, to be that procedure of a, b, and n-- lower bound, the upper bound, and n-- which is sum, of lambda of x, the procedure of one argument x, which exponentiates x to the n, with the a, the incrementer, and b, being passed along. So we're adding up x to n, given an x. x takes on values from a to b, incrementing by one. I can also write the-- That's right. Product, excuse me. The product of a bunch of powers. It's a strange name. I'm going to leave it there. Weird-- I write up what I have. I'm sure that's right. And if I want the product of a bunch of powers-- That was 12 brain cells, that double- take. I can for example use the procedure which is like sum, which is for making products, but it's similar to that, that you've seen before. There's a procedure of three arguments again. Which is the product of terms that are constructed, or factors in this case, constructed from exponentiating x to the n, where I start with a, I increment, and I go to b. Now, there's some sort of thing here that should disturb you immediately. These look the same. Why am I writing this code so many times? Here I am, in the same boat I've been in before. Wouldn't it be nice to make an abstraction here? What's an example of a good abstraction to make? Well, I see some codes that's identical. Here's one, and here's another. And so maybe I should be able to pull that out. I should be able to say, oh yes, the sum of the powers could be written in terms of something called the nth power procedure. Imagine somebody wanted to write a slightly different procedure that looks like this. The sum powers to be a procedure of a, b, and n, as the result of summing up the nth power. We're going to give a name to that idea, for starting at a, going by one, and ending at b. And similarly, I might want to write the product powers this way, abstracting out this idea. I might want this. Product powers, to be a procedure of a, b, and n, which is the product of the nth power operation on a with the incrementation and b being my arguments for the analogous-thing product. And I'd like to be able to define, I'd like to be able to define nth power--I'll put it over here. I'll put it at the top. --to be, in fact, my procedure of one argument x which is the result of exponentiating x to the n. But I have a problem. My environment model, that is my means of interpretation for the language that we've defined so far, does not give me a meaning for this n. Because, as you know, this n is free in this procedure. The environment model tells us that the meaning of a free variable is determined in the environment in which this procedure is defined. In a way I have written it, assuming these things are defined on the blackboard as is, this is defined in the global environment, where there is no end. Therefore, n is unbound variable. But it's perfectly clear, to most of us, that we would like it to be this n and this n. On the other hand, it would be nice. Certainly we've got to be careful here of keeping this to be this, and this one over here, wherever it is to be this one. Well, the desire to make this work has led to a very famous bug. I'll tell you about the famous bug. Look at this slide. This is an idea called dynamic binding. Where, instead of the free variable being interpreted in the environment of definition of a procedure, the free variable is interpreted as having its value in the environment of the caller of the procedure. So what you have is a system where you search up the chain of callers of a particular procedure, and, of course, in this case, since nth power is called from inside product whatever it is-- I had to write our own sum which is the analogous procedure -- and product is presumably called from product powers, as you see over here, then since product powers bind with variable n , then nth powers n would be derived through that chain. Similarly, this n, the nth power in n in this case, would come through nth power here being called from inside sum. You can see it being called from inside sum here. It's called term here. But sum was called from inside of sum powers, which bound n. Therefore, there would be an n available for that n to get it's value from. What we have below this white line plus over here, is what's called a dynamic binding view of the world. If that works, that's a dynamic binding view. Now, let's take a look, for example, at just what it takes to implement that. That's real easy. In fact, the very first Lisps that had any interpretations of the free variables at all, had dynamic binding interpretations for the free variables. APL has dynamic binding interpretation for the free variables, not lexical or static binding. So, of course, the change is in eval. And it's really in two places. First of all, one thing we see, is that things become a little simpler. If I don't have to have the environment be the environment of definition for procedure, the procedure need not capture the environment at the time it's defined. And so if we look here at this slide, we see that the clause for a lambda expression, which is the way a procedure is defined, do es not make up a thing which has a type closure and a attached environment structure. It's just the expression itself. And we'll decompose that some other way somewhere else. The other thing we see is the applicator must be able to get the environment of the caller. The caller of a procedure is right here. If the expression we're evaluating is anpplication or a combination, then we're going to call a procedure which is the value of the operator. The environment of the caller is the environment we have right here, available now. So all I have to do is pass that environment to the applicator, to apply. And if we look at that here, the only change we have to make is that fellow takes that environment and uses that environment for the purpose of extending that environment when abiding the formal parameters of the procedure to the arguments that were passed, not an environment that was captured in the procedure. The reason why the first Lisps were implemented this way, is the sort of the obvious, accidental implementation. And, of course, as usual, people got used to it and liked it. And there were some people said, this is the way to do it. Unfortunately that causes some serious problems. The most important, serious problem in using dynamic binding is there' s a modularity crisis that's involved it. If two people are working together on some big system, then an important thing to want is that the names used by each one don't interfere with the names of the other. It's important that when I invent some segment of code that no one can make my code stop working by using my names that I use internal to my code, internal to his code. However, dynamic binding violates that particular modularity constraint in a clear way. Consider, for example, what happens over here. Suppose it was the case that I decided to change the word next. Supposing somebody is writing sum, and somebody else is going to use sum. The writer of sum has a choice of what names he may use. Let'ssay, I'm that writer. Well, by gosh, just happens I didn't want to call this next. I called it n. So all places where you see next, I called it n. Whoops. I changed nothing about the specifications of this program, but this program stops working. Not only that, unfortunately, this one does too. Why do these programs stop working? Well, it's sort of clear. Instead of chasing out the value of the n that occurs in nth power over here or over here, through the environment of definition, where this one is always linked to this one, if it was through the environment of definition, because here is the definition. This lambda expression was executed in the environment where that n was defined. If instead of doing that, I have to chase through the call chain, then look what horrible thing happens. Well, this was called from inside sum as term, term a. I'm looking for a value of n. Instead of getting this one, I get that one. So by changing the insides of this program, this program stops working. So I no longer have a quantifier, as I described before. The lambda symbol is supposed to be a quantifier. A thing which has the property that the names that are bound by it are unimportant, that I can uniformly substitute any names for these throughout this thing, so long as they don't occur in here, the new names, and the meaning of this expression should remain unchanged. I've just changed the meaning of the expression by changing the one of the names. So lambda is no longer a well defined idea. It's a very serious problem. So for that reason, I and my buddies have given up this particular kind of abstraction, which I would like to have, in favor of a modularity principle. But this is the kind of experiment you can do if you want to play with these interpreters. You can try them out this way, that way, and the other way. You see what makes a nicer language. So that's a very important thing to be able to do. Now, I would like to give you a feeling for I think the right thing to do is here. How are you going to I get this kind of power in a lexical system? And the answer is, of course, what I really want is a something that makes up for me an exponentiator for a particular n. Given an n, it will make me an exponentiator. Oh, but that's easy too. In other words, I can write my program this way. I'm going to define a thing called PGEN, which is a procedure of n which produces for me an exponentiator.--x to the n. Given that I have that, then I can capture the abstraction I wanted even better, because now it's encapsulated in a way where I can't be destroyed by a change of names. I can define some powers to be a procedure again of a, b, and n which is the sum of the term function generated by using this generator, PGEN, n, with a, incrementer, and b. And I can define the product of powers to be a procedure of a, b, and n which is the product PGEN, n, with a, increment, and b. Now, of course, this is a very simple example where this object that I'm trying to abstract over is small. But it could be a 100 lines of code. And so, the purpose of this is, of course, to make it simple. I'd give a name to it, it's just that here it's a parameterized name. It's a name that depends upon, explicitly, the lexically apparent value of n. So you can think of this as a long name. And here, I've solved my problem by naming the term generation procedures within an n in them. Are there any questions? Oh, yes, David. AUDIENCE: Is the only solution to the problem you raise to create another procedure? In other words, can this only work in languages that are capable of defining objects as procedures? PROFESSOR: Oh, I see. My solution to making this abstraction, when I didn't want include the procedure inside the body, depends upon my ability to return a procedure or export one. And that's right. If I don't have that, then I just don't have this ability to make an abstraction in a way where I don't have possibilities of symbol conflicts that were unanticipated. That's right. I consider being able to return the procedural value and, therefore, to sort of have first class procedures, in general, as being essential to doing very good modular programming. Now, indeed there are many other ways to skin this cat. What you can do is take for each of the bad things that you have to worry about, you can make a special feature that covers that thing. You can make a package system. You can make a module system as in Ada, et cetera. And all of those work, or they cover little regions of it. The thing is that returning procedures as values cover all of those problems. And so it's the simplest mechanism that gives you the best modularity, gives you all of the known modularity mechanisms. Well, I suppose it's time for the next break, thank you. [MUSIC PLAYING] PROFESSOR: Well, yesterday when you learned about streams, Hal worried to you about the order of evaluation and delayed arguments to procedures. The way we played with streams yesterday, it was the responsibility of the caller and the callee to both agree that an argument was delayed, and the callee must force the argument if it needs the answer. So there had to be a lot of hand shaking between the designer of a procedure and user of it over delayedness. That turns out, of course, to be a fairly bad thing, it works all right with streams. But as a general thing, what you want is an idea to have a locus, a decision, a design decision in general, to have a place where it's made, explicitly, and notated in a clear way. And so it's not a very good idea to have to have an agreement, between the person who writes a procedure and the person who calls it, about such details as, maybe, the arguments of evaluation, the order of evaluation. Although, that's not so bad. I mean, we have other such agreements like, the input's a number. But it would be nice if only one of these guys could take responsibility, completely. Now this is not a new idea. ALGOL 60 had two different ways of calling a procedure. The arguments could be passed by name or by value. And what that meant was that a name argument was delayed. That when you passed an argument by name, that its value would only be obtained if you accessed that argument. So what I'd like to do now is show you, first of all, a little bit about, again, we're going to make a modification to a language. In this case, we're going to add a feature. We're going to add the feature of, by name parameters, if you will, or delayed parameters. Because, in fact, the default in our Lisp system is by the value of a pointer. A pointer is copied, but the data structure it points at is not. But I'd like to, in fact, show you is how you add name arguments as well. Now again, why would we need such a thing? Well supposing we wanted to invent certain kinds of what otherwise would be special forms, reserve words? But I'd rather not take up reserve words. I want procedures that can do things like if. If is special, or cond, or whatever it is. It's the same thing. It's special in that it determines whether or not to evaluate the consequent or the alternative based on the value of the predicate part of an expression. So taking the value of one thing determines whether or not to do something else. Whereas all the procedures like plus, the ones that we can define right now, evaluate all of their arguments before application. So, for example, supposing I wish to be able to define something like the reverse of if in terms of if. Call it unless. We've a predicate, a consequent, and an alternative. Now what I would like to sort of be able to do is say-- oh, I'll do it in terms of cond. Cond, if not the predicate, then take the consequent, otherwise, take the alternative. Now, what I'd like this to mean, is supposing I do something like this. I'd like this unless say if equals one, 0, then the answer is two, otherwise, the quotient of one and 0. What I'd like that to mean is the result of substituting equal one, 0, and two, and the quotient of one, 0 for p, c, and a. I'd like that to mean, and this is funny, I'd like it to transform into or mean cond not equal one, 0, then the result is two, otherwise I want it to be the quotient one and 0. Now, you know that if I were to type this into Lisp, I'd get a two. There's no problem with that. However, if I were to type this into Lisp, because all the arguments are evaluated before I start, then I'm going to get an error out of this. So that if the substitutions work at all, of course, I would get the right answer. But here's a case where the substitutions don't work. I don't get the wrong answer. I get no answer. I get an error. Now, however, I'd like to be able to make my definition so that this kind of thing works. What I want to do is say something special about c and a. I want them to be delayed automatically. I don't want them to be evaluated at the time I call. So I'm going to make a declaration, and then I'm going to see how to implement such a declaration. But again, I want you to say to yourself, oh, this is an interesting kluge he's adding in here. The piles of kluges make a big complicated mess. And is this going to foul up something else that might occur. First of all, is it syntactically unambiguous? Well, it will be syntactically unambiguous with what we've seen so far. But what I'm going to do may, in fact, cause trouble. It may be that the thing I had will conflict with type declarations I might want to add in the future for giving some system, some compiler or something, the ability to optimize given the types are known. Or it might conflict with other types of declarations I might want to make about the formal parameters. So I'm not making a general mechanism here where I can add declarations. And I would like to be able to do that. But I don't want to talk about that right now. So here I'm going to do, I'm going to build a kluge. So we're going to define unless of a predicate-- and I'm going to call these by name-- the consequent, and name the alternative. Huh, huh-- I got caught in the corner. If not p then the result is c, else-- that's what I'd like. Where I can explicitly declare certain of the parameters to be delayed, to be computed later. Now, this is actually a very complicated modification to an interpreter rather than a simple one. The ones you saw before, dynamic binding or addi ng indefinite argument procedures, is relatively simple. But this one changes a basic strategy. The problem here is that our interpreter, as written, evaluates a combination by evaluating the procedure, the operator producing the procedure, and evaluating the operands producing the arguments, and then doing apply of the procedure to the arguments. However, here, I don't want to evaluate the operands to produce the arguments until after I examined the procedure to see what the procedure's declarations looklike. So let's look at that. Here we have a changed evaluator. I'm starting with the simple lexical evaluator, not dynamic, but we're going to have to do something sort of similar in some ways. Because of the fact that, if I delay a procedure-- I'm sorry-- delay an argument to a procedure, I'm going to have to attach and environment to it. Remember how Hal implemented delay. Hal implemented delay as being a procedure of no arguments which does some expression. That's what delay of the expression is. --of that expression. This turned into something like this. Now, however, if I evaluate a lambda expression, I have to capture the environment. The reason why is because there are variables in there who's meaning I wish to derive from the context where this was written. So that's why a lambda does the job. It's the right thing. And such that the forcing of a delayed expression was same thing as calling that with no arguments. It's just the opposite of this. Producing an environment of the call which is, in fact, the environment where this was defined with an extra frame in it that's empty. I don't care about that. Well, if we go back to this slide, since it's the case, if we look at this for a second, everything is the same as it was before except the caseof applications or combinations. And combinations are going to do two things. One, is I have to evaluate the procedure -- forget the procedure-- by evaluating the operator. That's what you see right here. I have to make sure that that's current, that is not a delayed object, and evaluate that to the point where it's forced now. And then I have to somehow apply that to the operands. But I have to keep the environment, pass that environmental along. So some of those operands I may have to delay. I may have to attach that environment to those operands. This is a rather complicated thing happening here. Looking at that in apply. Apply, well it has a primitive procedure thing just like before. But the compound one is a little more interesting. I have to evaluate the body, just as before, in an environment which is the result of binding some formal parameters to arguments in the environment. That's true. The environment is the one that comes from the procedure now. It's a lexical language, statically bound. However, one thing I have to do is strip off the declarations to get the names of the variables. That's what this guy does, vnames. And the other thing I have to do is process these declarations, deciding which of these operands-- that's the operands now, as opposed to the arguments-- which of these operands to evaluate, and which of them are to be encapsulated in delays of some sort. The other thing you see here is that we got a primitive, a primitive like plus, had better get at the real operands. So here is a place where we're going to have to force them. And we're going to look at what evlist is going to have to do a bunch of forces. So we have two different kinds of evlist now. We have evlist and gevlist. Gevlist is going to wrap delays around some things and force others, evaluate others. And this guy's going to do some forcing of things. Just looking at this a little bit, this is a game you must play for yourself, you know. It's not something that you're going to see all possible variations on an evaluator talking to me. What you have to do is do this for yourself. And after you feel this, you play this a bit, you get to see all the possible design decisions and what they might mean, and how they interact with each other. So what languages might have in them. And what are some of the consistent sets that make a legitimate language. Whereas what things are complicated kluges that are just piles of junk. So evlist of course, over here, just as I said, is a list of operands which are going to be undelayed after evaluation. So these are going to be forced, whatever that's going to mean. And gevlist, which is the next thing-- Thank you. What we see here, well there's a couple of possibilities. Either it's a normal, ordinary thing, a symbol sitting there like the predicate in the unless, and that's what we have here. In which case, this is intended to be evaluated in applicative order. And it's, essentially, just what we had before. It's mapping eval down the list. In other words, I evaluate the first expression and continue gevlisting the CDR of the expression in the environment. However, it's possible that this is a name parameter. If it's a name parameter, I want to put a delay in which combines that expression, which I'm calling by name, with the envi ronment that's available at this time and passing that as the parameter. And this is part of the mapping process that you see here. The only other interesting place in this interpreter is cond. People tend to write this thing, and then they leave this one out. There's a place where you have to force. Conditionals have to know whether or not the answer is true or false. It's like a primitive. When you do a conditional, you have to force. Now, I'm not going to look at any more of this in any detail. It isn't very exciting. And what's left is how you make delays. Well, delays are data structures which contain an expression, an environment, and a type on them. And it says they're a thunk. That comes from ALGOL language, and it's claimed to be the sound of something being pushed on a stack. I don't know. I was not an ALGOLician or an ALGOLite or whatever, so I don't know. But that's what was claimed. And undelay is something which will recursively undelay thunks until the thunk becomes something which isn't a thunk. This is the way you implement a call by name like thing in ALGOL. And that's about all there is. Are there any questions? AUDIENCE: Gerry? PROFESSOR: Yes, Vesko? AUDIENCE: I noticed you avoided calling by name in the primitive procedures, I was wondering what cause you have on that? You never need that? PROFESSOR: Vesko is asking if it's ever reasonable to call a primitive procedure by name? The answer is, yes. There's one particular case where it's reasonable, actually two. Construction of a data structure like cons where making an array if you have arrays with any number of elements. It's unnecessary to evaluate tho se arguments. All you need is promises to evaluate those arguments if you look at them. If I cons together two things, then I could cons together the promises just as easily as I can cons together the things. And it's not even when I CAR CDR them that I have to look at them. That just gets out the promises and passes them to somebody. That's why the lambda calculus definition, the Alonzo Church definition of CAR, CDR, and cons makes sense. It's because no work is done in CAR, CDR, and cons, it's just shuffling data, it's just routing, if you will. However, the things that do have to look at data are things like plus. Because they have a look at the bits that the numbers are made out of, unless they're lambda calculus numbers which are funny. They have to look at the bits to be able to crunch them together to do the add. So, in fact, data constructors, data selectors, and, in fact, things that side -effect data objects don't need to do any forcing in the laziest possible interpreters. On the other hand predicates on data structures have to. Is this a pair? Or is it a symbol? Well, you better find out. You got to look at it then. Any other questions? Oh, well, I suppose it's time for a break. Thank you. [MUSIC PLAYING] and MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec8a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 8A: Logic Programming, Part 1 [MUSIC PLAYING BY J.S. BACH] PROFESSOR: The last time we began having a look at how languages are constructed. Remember the main point that an evaluator for, LISP, say, has two main elements. There is EVAL, and EVAL's job is to take in an expression and an environment and turn that into a procedure and some arguments and pass that off to APPLY. And APPLY takes the procedure in the arguments, turns that back into, in a general case, another expression to be evaluated in another environment and passes that of f to EVAL, which passes it to APPLY, and there's this whole big circle where things go around and around and around until you get either to some very primitive data or to a primitive procedure. See, what this cycle has to do with is unwinding the means o f combination and the means of abstraction in the language. So for instance, you have a procedure in LISP-- a procedure is a general way of saying, I want to be able to evaluate this expression for any value of the arguments, and that's sort of what's going on here. That's what APPLY does. It says the general thing coming in with the arguments reduces to the expression that's the body, and then if that's a compound expression or another procedure application, the thing will go around and around the circle. Anyway, that's sort of the basic structure of gee, pretty much any interpreter. The other thing that you saw is once you have the interpreter in your hands, you have all this power to start playing with the language. So you can make it dynamically scoped , or you can put in normal order evaluation, or you can add new forms to the language, whatever you like. Or more generally, there's this notion of metalinguistic abstraction, which says that part of your perspective as an engineer, as a software engineer,but as an engineer in general is that you can gain control of complexity by inventing new languages sometimes. See, one way to think about computer programming is that it only incidentally has to do with getting a computer to do something. Primarily what a computer program has to do with, it's a way of expressing ideas with communicating ideas. And sometimes when you want to communicate new kinds of ideas, you'd like to invent new modes of expressing that. Well, today we're going to apply this framework to build a new language. See, once we have the basic idea of the interpreter, you can pretty much go build any language that you like. So for example, we can go off and build Pascal. And gee, we would worry about syntax and parsing and various kinds of compiler optimizations, and there are people who make honest livings doing that, but at the level of abstraction that we're talking, a Pascal interpreter would not look very different at all from what you saw Gerry do last time. Instead of that, we'll spend today building a really different language, a language that encourages you to think about programming not in terms of procedures, but in a really different way. And the lecture today is going to be at two levels simultaneously. On the one hand, I'm going to show you what this language looks like, and on the other hand, I'll show you how it's implemented. And we'll build an implementation in LISP and see how that works. And you should be drawing lessons on two levels. The first is to realize just how diff erent a language can be. So if you think that the jump from Fortran to LISP is a big deal, you haven't seen anything yet. And secondly, you'll see that even with such a very different language, which will turn out to not have procedures at all and not talk about functions at all, there will still be this basic cycle of eval and apply that's unwinds the means of combination and the means an abstraction. And then thirdly, as kind of a minor but elegant technical point, you'll see a nice use of streams to avoid backtracking. OK, well, I said that this language is very different. To explain that, let's go back to the very first idea that we talked about in this course, and that was the idea of the distinction between the declarative knowledge of mathematics-- the definition of a square root as a mathematical truth-- and the idea that computer science talks about the how to knowledge- - contrast that definition of square root with a program to compute a square root. That's where we started off. Well, wouldn't it be great if you could somehow bridge this gap and make a programming language which sort of did things, but you talked about it in terms of truth, in declarative terms? So that would be a programming language in which you specify facts. You tell it what is. You say what is true. And then when you want an answer, somehow the language has built into it automatically general kinds of how to knowledge so it can just take your facts and it can evolve these methods on its on using the facts you gave it and maybe some general rules of logic. So for instance, I might go up to this program and start telling it some things. So I might tell it that the son of Adam is Abel. And I might tell it that the son of Adam is Cain. And I might tell it that the son of Cain is Enoch. And I might tell it that the son of Enoch is Irad, and all through the rest of our chapter whatever of Genesis, which ends up ending in Adah, by the way, and this shows the genealogy of Adah from Cain. Anyway, once you tell it these facts, you might ask it things. You might go up to your language and say, who's the son of Adam? And you can very easily imagine having a little general purpose search program which would be able to go through and in response to that say, oh yeah, there are two answers: the son of Adam is Abel and the son of Adam is Cain. Or you might say, based on the very same facts, who is Cain the son of? And then you can imagine generating another slightly different search program which would be able to go through and checked for who is Cain, and son of, and come up with Adam. Or you might say, what's the relationship between Cain and Enoch? And again, a minor variant on that search program. You could figure out that it said son of. But even here in this very simple example, what you see is that a single fact, see, a single fact like the son of Adam is Cain can be used to answer different kinds of questions. You can say, who's the son of, or you can say who's the son of Adam, or you can say what's the relation between Adam and Cain? Those are different questions being run by different traditional procedures all based on the same fact. And that's going to be the essence of the power of this programming style, that one piece of declarative knowledge can be used as the basis for a lot of different kinds of how-to knowledge, as opposed to the kinds of procedures we're writing where you sort of tell it what input you're giving it and what answer you want. So for instance, our square root program can perfectly well answer the question, what's the square root of 144? But in principle, the mathematical definition of square root tells you other things. Like it could say, what is 17 the square root of? And that would be have to be answered by a different program. So the mathematical definition, or in general, the facts that you give it are somehow unbiased as to what the question is. Whereas the programs we tend to write specifically because they are how-to knowledge tend to be looking for a specific answer. So that's going to be one characteristic of what we're talking about. We can go on. We can imagine that we've given our language some sort of facts. Now let's give it some rules of inference. We can say, for instance, if the-- make up some syntax here-- if the son of x is y-- I'll put question marks to indicate variables here-- if the son of x is y and the son of y is z, then the grandson of x is z. So I can imagine telling my machine that rule and then being able to say, for instance, who's the grandson of Adam? Or who is Irad the grandson of? Or deduce all grandson relationships you possibly can from this information. We can imagine somehow the language knowing how to do that automatically. Let me give you maybe a little bit more concrete example. Here's a procedure that merges two sorted lists. So x and y are two, say, lists of numbers, lists of distinct numbers, if you like, that are in increasing order. And what merge does is take two such lists and combine them into a list where everything's in increasing order, and this is a pretty easy programs that you ought to be able to write. It says, if x is empty, the answer is y. If y is empty, the answer is x. Otherwise, you compare the first two elements. So you pick out the first thing in x and the first thing in y, and then depending on which of those first elements is less, you stick the lower one on to the result a recursively merging, either chopping the first one off x or chopping the first one off y. That's a standard kind of program. Let's look at the logic. Let's forget about the program and look at the logic on which that procedure is based. See, there's some logic which says, gee, if the first one is less, then we get the answer by sticking something onto the result of recursively merging the rest. So let's try and be explicit about what that logic is that's making the program work. So here's one piece. Here's the piece of the program which recursively chops down x if the first thing in x is smaller. And if you want to be very explicit about what the logic is there, what's really going on is a deduction, which says, if you know that some list, that we'll call cdr of x, and y merged to form z, and you know that a is less than the first thing in y, then you know that if you put a onto the cdr of x, then that result and y merge to form a onto z. And what that is, that's the underlying piece of logic-- I haven't written it as a program, I wrote it a sort of deduction that's underneath this particular clause that says we can use the recursion there. And then similar, here's the other clause just to complete it. The other clause is based on this piece of logic, which is almost the same and I won't go through it, and then there's the n cases where we tested for null, and that's based on the idea that for any x, x and the empty list merge to form an x, or for any y, the empty list and y merge to form y. OK, so there's a piece of procedure and the logic on which it's based. And notice a big difference. The procedure looked like this: it said there was a box-- and all the things we've been doing have the characteristic we have boxes and things going in and things going out - - there was this box called merge, and in came an x and y, and out came an answer. That's the character of the procedure that we wrote. These rules don't look likethat. These rules talk about a relation. There's some sort of relation that in those slides I called mrege -to- form. So I said x and y merge to form z, and somehow this is a function. Right? The answer is a function of x and y, and here what I have is a relation between three things. And I'm not going to specify which is the input and which is the output. And the reason I want to say that is because in principle, we could use exactly those same logic rules to answer a lot of different questions. So we can say, for instance-- imagine giving our machine those rules of logic. Not the program, the underlying rules of logic. Then it ought to be able to say-- we could ask it-- 1, 3, 7 and 2, 4, 8 merge to form what? And that's a question it ought to be able to answer. That's exactly the same question that our list procedure answered. But the exact same rules should also be able to answer a question like this: 1, 3, 7 and what merged to form 1, 2, 3, 4, 7, 8? The same rules of logic can answer this, although the procedure we wrote can't answer that question. Or we might be able to say what and what else merge to form-- what and what else merge to form 1, 2, 3, 4, 7, 8? And the thing should be able to go through, if it really can apply that logic, and deduce all, whatever is, 2 to the sixth answers to that question. It could be 1 and the rest, or it could be 1, 2 and the rest. Or it could be 1 and 3 and 7 and the rest. There's a whole bunch of answers. And in principle, the logic should be enough to deduce that. So there are going to be two big differences in the kind of program we're going to look at and not only list, but essentially all the programming you've probably done so far in pretty much any language you can think of. The first is, we're not going to be computing functions. We're not going to be talking about things that take input and output. We're going to be talking about relations. And that means in principle, these relations don't have directionality. So the knowledge that you specify to answer this question, that same knowledge should also allow you to answer these other questions and conversely. And the second issue is that since we're talking about relations, these relations don't necessarily have one answer. So that third question down there doe sn't have a particular answer, it has a whole bunch of answers. Well, that's where we're going. This style of programming, by the way, is called logic programming, for kind of obvious reasons. And people who do logic programming say that-- they have this little phrase-- they say the point of logic programming is that you use logic to express what is true, you use logic to check whether something is true, and you use logic to find out what is true. The best known logic programming language, as you probably know, is called Prolog. The language that we're going to implement this morning is something we call the query language, and it essentially has the essence of prologue. It can do about the same stuff, although it's a lot slower because we're going to implement it in LISP rather than building a particular compiler. We're going to interpret it on top of the LISP interpreter. But other than that, it can do about the same stuff as prolog. It has about the same power and about the same limitations. All right, let's break for question. STUDENT: Yes, could you please repeat what the three things you use logic programming to find? In other words, to find what is true, learn what is true-- what is the? PROFESSOR: Right. Sort of a logic programmer's little catechism. You use logic to express what is true, like these rules. You use logic to check whether something is true, and that's the kind of question I didn't answer here. I might say-- another question I could put down here is to say, is it true that 1, 3, 7 and 2, 4, 8 merge to form 1, 2, 6, 10 And that same logic should be enough to say no. So I use logic to check what is true, and then you also use logic to find out what's true. All right. Let's break. [MUSIC PLAYING BY J.S. BACH] [MUSIC ENDS] [MUSIC PLAYING BY J.S. BACH] PROFESSOR: OK, let's go ahead and take a look at this query language and operation. The first thing you might notice, when I put up that little biblical database, is that it's nice to be able to ask this language questions in relation to some collection of facts. So let's start off and make a little collection of facts. This is a tiny fragment of personnel records for a Boston high tech company, and here's a piece of the personnel records of Ben Bitdiddle. And Ben Bitdiddle is the computer wizard in this company, he's the underpaid computer wizard in this company. His supervisor is all Oliver Warbucks, and here's his address. So the format is we're giving this information: job, salary, supervisor, address. And there are some other conventions. Computer here means that Ben works in the computer division, and his position in the computer division is wizard. Here's somebody else. Alyssa, Alyssa P. Hacker is a computer programmer, and she works for Ben, and she lives in Cambridge. And there's another programmer who works for Ben who's Lem E. Tweakit. And there's a programmer trainee, who is Louis Reasoner, and he works for Alyssa. And the big wheel of the company doesn't work for anybody, right? That's Oliver Warbucks. Anyway, what we're going to do is ask questions about that little world. And that'll be a sample world that we're going to do logic in. Let me just write up here, for probably the last time, what I said is the very most important thing you should get out of this course, and that is, when somebody tells you about a language, you say, fine-- what are the primitives, what are the means of combination, how do you put the primitives together, and then how do you abstract them, how do you abstract the compound pieces so you can use them as pieces to make something more complicated? And we've said this a whole bunch of times already, but it's worth saying again. Let's start. The primitives. Well, there's really only one primitive, and the primitive in this language is called a query. A primitive query. Let's look at some primitive queries. Job x. Who is a computer programmer? Or find every fact in the database that matches job of the x is computer programmer. And you see a little syntax here. Things without question marks are meant to be literal, question mark x means that's a variable, and this thing will match, for example, the fact that Alyssa P. Hacker is a computer programmer, or x is Alyssa P. Hacker. Or more generally, I could have something with two variables in it. I could say, the job of x is computer something, and that'll match computer wizard. So there's something here: type will match wizard, or type will match programmer, or x might match various certain things. So there are, in our little example, only threefacts in that database that match that query. Let's see, just to show you some syntax, the same query, this query doesn't match the job of x, doesn't match Lewis Reasoner, the reason for that is when I write something here, what I mean is that this is going to be a list of two symbols, of which the first is the word computer, and the second can be anything. And Lewis's job description here has three symbols, so it doesn't match. And just to show you a little bit of syntax, the more general thing I might want to type is a thing with a dot here, and this is just standard this notation for saying, this is a list, of which the first element is the word computers, and THE REST, is something that I'll call type. So this one would match. Lewis's job is computer programmer trainee, and type here would be the cdr of this list. It would be the list programmer trainee. And that kind of dot processing is done automatically by the LISP reader. Well, let's actually try this. The idea is I'm going to type in queriein this language, and answers will come out. Let's look at this. I can go up and say, who works in the computer division? Job of x is computer dot y. Doesn't matter what I call the dummy variables. It says the answers to that, and it's found four answers. Or I can go off and say, tell me about everybody's supervisor. So I'll put in the query, the primitive query, the supervisor of x is y. There are all the supervisor relationships I know. Or I could go type in, who lives in Cambridge? So I can say, the address of x is Cambridge dot anything. And only one person lives in Cambridge. OK, so those are primitive queries. And you see what happens to basic interaction with the system is you type in a query, and it types out all possible answers. Or another way to say that: it finds out all the possible values of those variables x and y or t or whatever I've called them, and it types out all ways of taking that query and instantiating it-- remember that from the rule system lecture-- instantiates the query with all possible values for those variables and then types out all of them. And there are a lot of ways you can arrange a logic language. Prolog, for instance, does something slightly different. Rather than typing back your query, prolog would type out, x equals this and y equals that, or x sequels this and y equals that. And that's a very surface level thing, you can decide what you like. OK. All right. So the primitives in this language? Only one, right? Primitive query. OK. Means of combination. Let's look at some compound queries in this language. Here's one. This one says, tell me all the people who work in the computer division. Tell me all the people who work in the computer division together with their supervisors. The way I write that is the query is and. And the job of the x is computer something or other. And job of x is computer dot y. And the supervisor of x is z. Tell me all the people in the computer division -- that's this-- together with their supervisors. And notice in this query I have three variables-- x, y, and z. And this x is supposed to be the same as that x. So x works in the computer division, and the supervisor of x is z. Let's try another one. So one means of combination is and. Who are all the people who make more than $30,000? And the salary of some person p is some amount a. And when I go and look at a, a is greater than $30,000. And LISP value here is a little piece of interface that interfaces the query language to the underlying LISP. And what the LISP value allows you to do is call any LISP predicate inside a query. So here I'm using the LISP predicate greater than, so I say LISP value. This I say and. So all the people whose salary is greater than $30,000. Or here's a more complicated one. Tell me all the people whowork in the computer division who do not have a supervisor who works in the computer division. and x works in the computer division. The job of x is computer dot y. And it's not the case that both x has a supervisor z and the job of z is computer something or other. All right, so again, this x has got to be that x, and this z is going to be that z. And then you see another means a combination, not. All right, well, let's look at that. It works the same way. I can go up to the machine and say and the job of the x is computer dot y. And the supervisor of x is z. And I typed that in like a query. And what it types back, what you see are the queries I typed in instantiated by all possible answers. And then you see there are a lot of answers. All right. So the means of combination in this language-- and this is why it's called a logic language-- are logical operations. Means of combinations are things like AND and NOT and there's one I didn't show you, which is OR. And then I showed you LISP value, which is not logic, of course, but is a little special hack to interface that to LISP so you can get more power. Those are the means of combination. OK, the means of abstraction. What we'd like to do-- let's go back for second and look at that last slide. We might like to take very complicated thing, the idea that someone works in a division but does not have a supervisor in the division. And as before, name that. Well, if someone works in a division and does not have a supervisor who works in that division, that means that person is a big shot. So let's make a rule that somebody x is a big shot in some department if x works in the department and it's not the case that x has a supervisor who works in the department. So this is our means of abstraction. This is a rule. And a rule has three parts. The thing that says it's a rule. And then there's the conclusion of the rule. And then there's the body of the rule. And you can read this as a piece of logic which says, if you know that the body of the rule is true, then you can conclude that the conclusion is true. Or in order to deduce that x is a big shot in some department, it's enough to verify that. So that's what rules look like. Let's go back and look at that merge example that I did before the break. Let's look at how that would look in terms of rules. I'm going to take the logic I put up and just change it into a bunch of rules in this format. We have a rule. Remember, there was this thing merge-to-form. There is a rule that says, the empty list and y merge to form y. This is the rule conclusion. And notice this particular rule has no body. And in this language, a rule with no body is something that is always true. You can always assume that's true. And there was another piece of logic that said anything in the empty list merged to form the anything. That's this. A rule y and the empty list merge to form y. Those corresponded to the two end cases in our merge procedure, but now we're talking about logic, not about procedures. Then we had another rule, which said if you know how shorter things merge, you can put them together. So this says, if you have a list x and y and z, and if you want to deduce that a dot x-- this means constant a onto x, or a list whose first thing is a an d whose rest is x-- so if you want to deduce that a dot x and b dot y merge to form b dot c-- that would say you merge these two lists a x and b y and you're going to get something that starts with b-- you can deduce that if you know that it's the case bot h that a dot x and y merge to form z and a is larger than b. So when I merge them, b will come first in the list. That's a little translation of the logic rule that I wrote in pseudo-English before. And then just for completeness, here's the other case. a dot x and b dot y merge to form a dot z if x and b dot y merged to form z and b is larger than a. So that's a little program that I've typed in in this language, and now let's look at it run. So I typed in the merge rules before, and I could use this like a procedure. I could say merge to form 1 and 3 and 2 and 7. So here I'm using it like the LISP procedure. Now it's going to think about that for a while and apply these rules. So it found an answer. Now it's going to see if there are any other answers but it doesn't know a priori there's only one answer. So it's sitting here checking all possibilities, and it says, no more. Done. So there I've used those rules like a procedure. Or remember the whole point is that I can ask different kinds of questions. I could say merge to form, let's see, how about 2 and a. Some list of two elements which I know starts with 2, and the other thing I don't know, and x and some other list merge to form a 1, 2, 3 and 4. So now it's going to think about that. It's got to find-- so it found one possibility. It said a could be 3, and x could be the list 1, 4. And now, again, it's got to check because it doesn't a priori know that there aren't any other possibilities going on. Or like I said, I could say something like mer ge to form, like, what and what else merge to form 1, 2, 3, 4, 5? Now it's going to think about that. And there are a lot of answers that it might get. And what you see is here you're really paying the price of slowness. And kind of for three reasons. One is that this language is doubly interpreted. Whereas in a real implementation, you would go compile this down to primitive operations. The other reason is that this particular algorithm for merges is doubly recursive. So it's going to take a very long time. And eventually, this is going to go through and find-- find what? Two to the fifth possible answers. And you see they come out in some fairly arbitrary order, depending on which order it's going to be trying these rules. In fact, what we're going to do when they edit the videotape is speed all this up. Don't you like taking out these weights? And don't you wish you could do that in your demos? Anyway, it's still grinding there. Anyway, there are 32 possibilities-- we won't wait for it to print out all of them. OK, so the needs of abstraction in this language are rules. So we take some bunch of things that are put together with logic and we name them. And you can think of that as naming a particular pattern of logic. Or you can think of that as saying, if you want to deduce some conclusion, you can apply those rules of logic. And those are three elements of this language. Let's break now, and then we'll talk about how it's actually implemented. STUDENT: Does using LISP value primitive or whateverinterfere with your means to go both directions on a query? PROFESSOR: OK, that's a-- the question is, does using LISP value interfere with the ability to go both directions on the query? We haven't really talked about the implementation yet, but the answer is, yes, it can. In general, as we'll see at the end-- although I really won't to go into details-- it's fairly complicated, especially when you use either not or LISP value-- or actually, if you use anything besides only and, it becomes very complicat ed to say when these things will work. They won't work quite in all situations. I'll talk about that at the end of the second half today. But the answer to your question is, yes, by dragging in a lot more power from LISP value, you lose some of the principal power of logic programming. That's a trade-off that you have to make. OK, let's take a break. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec8b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 8B: Logic Programming, Part 2 PROFESSOR: All right, well, we've seen how the query language works. Now, let's talk about how it's implemented. You already pretty much can guess what's going on there. At the bottom of it, there's a pattern matcher. And we looked at a pattern matcher whe n we did the rule-based control language. Just to remind you, here are some sample patterns. This is a pattern that will match any list of three things of which the first is a and the second is c and the middle one can be anything. So in this little pattern-matching syntax, there's only one distinction you make. There's either literal things or variables, and variables begin with question mark. So this matches any list of three things of which the first is a and the second is c. This one matches any list of three things of which the first is the symbol job. The second can be anything. And the third is a list of two things of which the first is the symbol computer and the second can be anything. And this one, this next one matches any list of three things , and the only difference is, here, the third list, the first is the symbol computer, and then there's some rest of the list. So this means two elements and this means arbitrary number. And our language implementation isn't even going to have to worry abou t implementing this dot because that's automatically done by Lisp's reader. Remember matchers also have some consistency in them. This match is a list of three things of which the first is a. And the second and third can be anything, but they have to be the same thing. They're both called x. And this matches a list of four things of which the first is the fourth and the second is the same as the third. And this last one matches any list that begins with a. The first thing is a, and the rest can be anything. So that's just a review of pattern matcher syntax that you've already seen. And remember, that's implemented by some procedure called match. And match takes a pattern and some data and a dictionary. And match asks the question is there any way to match this pattern against this data object subject to the bindings that are already in this dictionary? So, for instance, if we're going to match the pattern x, y, y, x against the data a, b, b, a subject to a dictionary, that says x equals a. Then the matcher would say, yes, that's consistent. These match, and it's consistent with what's in the dictionary to say that x equals a. And the result of the match is the extended dictionary that says x equals a and y equals b. So a matcher takes in pattern data dictionary, puts out an extended dictionary if it matches, or if it doesn't match, says that it fails. So, for example, if I use the same pattern here, if I say this x, y, y, x match a, b, b, a with the dictionary y equals a, then the matcher would put out fail. Well, you've already seen the code for a pattern matcher so I'm not going to go over it, but it's the same thing we've been doing before. You saw that in the system on rule -based control. It's essentially the same matcher. In fact, I think the syntax is a little bit simpler because we're not worrying about arbitrary constants and expressions and things. There's just variables and constants. OK, well, given that, what's a primitive query? Primitive query is going to be a rather complicated thing. It's going to be-- let's think about the query job of x is d dot y. That's a query we might type in. That's going to be implemented in the system. We'll think of it as this little box. Here's the primitive query. What this little box is going to do is take in two streams and put out a stream. So the shape of a primitive query is that it's a thing where two streams come in and one stream goes out. What these streams are going to be is down here is the database. So we imagine all the things in the database sort of sitting there in a stream and this thing sucks on them. So what are some things that might be in the database? Oh, job of Alyssa is something and some other job is something. So imagine all of the facts in the database sitting there in the stream. That's what comes in here. What comes in here is a stream of dictionaries. So one particular dictionary might say y equals programmer. Now, what the query does when it gets in a dictionary from this stream, it finds all possible ways of matching the query against whatever is coming in from the database. It looks at the query as a pattern, matches it against any fact from the database or all possible ways of finding and matching the database with respect to this dictionary that's coming in. So for each fact in the database, it calls the matcher using the pattern, fact, and dictionary. And every time it gets a good match, it puts out the extended dictionary. So, for example, if this one comes in and it finds a match, out will come a dictionary that in this case will have y equals programmer and x equals something. y is programmer, x is something, and d is whatever it found. And that's all. And, of course, it's going to try this for every fact in the dictionary. So it might find lots of them. It might find another one that says y equals programmer and x equals, and d equals. So for one frame coming in, it might put out-- for one dictionary coming in, it might put out a lot of dictionaries, or it might put out none. It might have something that wouldn't match like x equals FOO. This one might not match anything in which case no thing will go into this stream corresponding to this frame. Or what you might do is put in an empty frame, and an empty frame says try matching all ways-- find all possible ways of matching the query against something in the database subject to no previous restrictions. And if you think about what that means, that's just the computation that's done when you type in a query right off. It tries to find all matches. So a primitive query sets up this mechanism. And what the language does, when you type in the query at the top level, it takes this mechanism, feeds in one single empty dictionary, and then for each thing that comes out takes the original query and instantiates the result with all the different dictionaries, producing a new stream of instantiated patterns here. And that's what gets printed on the terminal. That's the basic mechanism going on there. Well, why is that so complicated? You probably can think of a lot simpler ways to arrange this match for a primitive query rather than having all of these streams floating around. And the answer is-- you probably guess already. The answer is this thing extends elegantly to implement the means of combination. So, for instance, suppose I don't only want to do this. I don't want to say who to be everybody's job description. Suppose I want to say AND the job of x is d dot y and the supervisor of x is z. Now, supervisor of x is z is going to be another primitive query that has the same shape to take in a stream of data objects, a stream of initial dictionaries, which are the restrictions to try and use when you match, and it's going to put out a stream of dictionaries. So that's what this primitive query looks like. And how do I implement the AND? Well, it's simple. I just hook them together. I take the output of this one, and I put that to the input of that one. And I take the dictionary here and I fan it out. And then you see how that's going to work, because what's going to happen is a frame will now come in here, which has a binding for x, y, and d. And then when this one gets it, it'll say, oh, gee, subject to these restrictions, which now already have values in the dictionary for y and x and d, it looks in the database and says, gee, can I find any supervisor facts? And if it finds any, out will come dictionaries which have bindings for y and x and d and z now. And then notice that because the frames coming in here have these restrictions, that's the thing that assures that when you do the AND, this x will mean the same thing as that x. Because by the time something comes floating in here, x has a value that you have to match against consistently. And then you remember from the code from the matcher, there was something in the way the matcher did dictionaries that arrange consistent matches. So there's AND. The important point to notice is the general shape. Look at what happened: the AND of two queries, say, P and Q. Here's P and Q. The AND of two queries, well, it looks like this. Each query takes in a stream from the database, a stream of inputs, and puts out a stream of outputs. And the important point to notice is that if I draw a box around this thing and say this is AND of P and Q, then that box has exactly the same overall shape. It's something that takes in a stream from the database. Here it's going to get fanned out inside, but from the outside you don't see that. It takes an input stream and puts out an output stream. So this is AND. And then similarly, OR would look like this. OR would -- although I didn't show you examples of OR. OR would say can I find all ways of matching P or Q. So I have P and Q. Each will have their shape. And the way OR is implemented is I'll take my database stream. I'll fan it out. I'll put one into P and one into Q. I'll take my initial query stream coming in and fan it out. So I'll look at all the answers I might get from P and all the answers I might get from Q, and I'll put them through some sort of thing that appends them or merges the result into one stream, and that's what will come out. And this whole thing from the outside is OR. And again, you see it has the same overall shape when looked at from the outside. What's NOT? NOT works kind of the same way. If I have some query P, I take the primitive query for P. Here, I'm going to implement NOT P. And NOT'sjust going to act as a filter. I'll take in the database and my original stream of dictionaries coming in, and what NOT P will do is it will filter these guys. And the way it will filter it, it will say when I get in a dictionary here, I'll find all the matches, and if I find any, I'll throw it away. And if I don't find any matches to something coming in here, I'll just pass that through, so NOT is a pure filter. So AND is-- think of these sort of electoral resistors or something. AND is series combination and OR is parallel combination. And then NOT is not going to extend any dictionaries at all. It's just going to filter it. It's going to throw away the ones for which it finds a way to match. And list value is sort of the same way. The filter's a little more complicated. It applies to predicate. The major point to notice here, and it's a major point we've looked at before, is this idea of closure. The things that we build as a means of combination have the same overall structure as the primitive things that we're combining. So the AND of two things when looked at from the outside has the same shape. And what that means is that this box here could be an AND or an OR or a NOT or something because it has the same shape to interface to the larger things. It's the same thing that allowed us to get complexity in the Escher picture language or allows you to immediately build up these complicated structures just out of pairs. It's closure. And that's the thing that allowed me to do what by now you took for gran ted when I said, gee, there's a query which is AND of job and salary, and I said, oh, there's another one, which is AND of job, a NOT of something. The fact that I can do that is a direct consequence of this closure principle. OK, let's break and then we'll go on. AUDIENCE: Where does the dictionary come from? PROFESSOR: The dictionary comes initially from what you type in. So when you start this up, the first thing it does is set up this whole structure. It puts in one empty dictionary. And if all you have is one primitive query, then what will come out is a bunch of dictionaries with things filled in. The general situation that I have here is when this is in the middle of some nest of combined things. Let's look at the picture over here. This supervisor query gets in some dictionary. Where did this one come from? This dictionary came from the fact that I'm looking at the output of this primitive query. So maybe to be very specific, if I literally typedin just this query at the top level, this AND, what would actually happen is it would build this structure and start up this whole thing with one empty dictionary. And now this one would process, and a whole bunch of dictionaries would come out with x, y's and d's in them. Run it through this one. So now that's the input to this one. This one would now put out some other stuff. And if this itself were buried in some larger thing, like an OR of something, then that would go feed into the next one. So you initially get only one empty dictionary when you start it, but as you're in the middle of processing these compounds things, that's where these cascades of dictionaries start getting generated. AUDIENCE: Dictionaries only come about as a result of using t he queries? Or do they become-- do they stay someplace in space like the database does? Are these temporary items? PROFESSOR: They're created temporarily in the matcher. Really, they're someplace in storage. Initially, someone creates a thing called theempty dictionary that gets initially fed to this match procedure, and then the match procedure builds some dictionaries, and they get passed on and on. AUDIENCE: OK, so they'll go way after the match? PROFESSOR: They'll go away when no one needs them again, yeah. AUDIENCE: It appears that the AND performs some redundant searches of the database. If the first clause matched, let's say, the third element and not on the first two elements, the second clause is going to look at those first two elements again, discarding them because they don't match. The match is already in the dictionary. Would it makes sense to carry the data element from the database along with the dictionary? PROFESSOR: Well, in general, there are other ways to arrange this search, and there's some analysis that you can do. I think there's a problem in the book, which talks about a different way that you can cascade AND to eliminate various kinds of redundancies. This one is meant to be-- was mainly meant to be very simple so you can see how they fit together. But you're quite right. There are redundancies here that you can get rid of. That's another reason why this language is somewhat slow. There are a lot smarter things you can do. We're just trying to show you a very simple, in principle, implementation. AUDIENCE: Did you model this language on Prolog, or did it just come out looking like Prolog? PROFESSOR: Well, Jerry insulted a whole bunch of people yesterday, so I might as well say that the MIT attitude towards Prolog is something that people did in about 1971 and decided that it wasn't really the right thing and stopped. So we modeled this on the sort of natural way that this thing was done in about 1971, except at that point, we didn't do it with streams. After we were using it for about six months, we discovered that it had all these problems, some of which I'll talk about later. And we said, gee, Prolog must have fixed those, and then we found out that it didn't. So this does about the same thing as Prolog. AUDIENCE: Does Prolog use streams? PROFESSOR: No. In how it behaves, it behaves a lot like Prolog. Prolog uses a backtracking strategy. But the other thing that's really good about Prolog that makes it a usable thing is that there's a really very, very well-engineered compiler technology that makes it run fast. So although you saw the merge spitting out these answers very, very slowly, a real Prolog will run very, very fast. Because even though it's sort of doing this, the real work that went into Prolog is a very, very excellent compiler effort. Let's take a break. We've looked at the primitive queries and the ways that streams are used to implement the means of combination: AND and OR and NOT. Now, let go on to the means of abstraction. Remember, the means of abstraction in this language are rules. So z is a boss in division d if there's some x who has a job in division d and z is the supervisor of x. That's what it means for someone to be a boss. And in effect, if you think about what we're doing with relation to this, there's the query we wrote-- the job of x is in d and the supervisor of x is z-- what we in effect want to do is take this whole mess and draw a box around it and say this whole thing inside the box is boss of z in division d. That's in effect what we want to do. So, for instance, if we've done that, and we want to check whether or not it's true that Ben Bitdiddle is a boss in the computer division, so if I want to say boss of Ben Bitdiddle in the computer division, imagine typing that in as query to the system, in effect what we want to do is set up a dictionary here, which has z to Ben Bitdiddle and d to computer. Where did that dictionary come from? Let's look at the slide for one second. That dictionary came from matching the query that said boss of Ben Bitdi ddle and computer onto the conclusion of the rule: boss of z and d. So we match the query to the conclusion of the rule. That gives us a dictionary, and that's the thing that we would now like to put into this whole big thing and process and see if anything comes out the other side. If anything comes out, it'll be true. That's the basic idea. So in general, the way we implement a rule is we match the conclusion of the rule against something we might want to check it's true. That match gives us a dictionary, and with respect to that dictionary, we process the body of the rule. Well, that's really all there is, except for two technical points. The first technical point is that I might have said something else. I might have said who's the boss in the computer division? So I might say boss of who in computer division. And if I did that, what I would really like to do in effect is start up this dictionary with a match that sort of says, well, d is computer and z is whatever who is. And our matcher won't quite do that. That's not quite matching a pattern against data. It's matching two patterns and saying are they consistent or not or what ways make them consistent. In other words, what we need is not quite a pattern matcher, but something a little bit more general called a unifier. And a unifier is a slight generalization of a pattern matcher. What a unifier does is take two patterns and say what's the most general thing you can substitute for the variables in those two patterns to make them satisfy the pattern simultaneously? Let me give you an example. If I have the pattern two-element list, which is x and x, so I have a two-element list where both elements are the same and otherwise I don't care what they are, and I unify that against the pattern that says there's a two-element list, and the first one is a and something in c and the second one is a and b and z, then what the unifier should tell me is, oh yeah, in that dictionary, x has to be a, b, c, and y has to be d and z has to be c. Those are the restrictions I'd have to put on the values of x, y, and z to make these two unify, or in other words, to make this match x and make this match x. The unifier should be able to deduce that. But the unifier may-- there are more complicated things. I might have said something a little bit more complicated. I might have said there's a list with two elements, and they're both the same, and they should unify against something of this form. And the unifier should be able to deduce from that. Like that y would have to be b. y would have to be b. Because these two are the same, so y's got to be b. And v here would have to be a. And z and w can be anything, but they have to be the same thing. And x would have to be b, followed by a, followed by whatever w is or whatever z is, which is the same. So you see, the unifier somehow has to deduce things to unify these patterns. So you might think there's some kind of magic deduction going on, but there's not. A unifier is basically a very simple modification of a pattern matche r. And if you look in the book, you'll see something like three or four lines of code added to the pattern matcher you just saw to handle the symmetric case. Remember, the pattern matcher has a place where it says is this variable matching a constant. And if so, it checks in the dictionary. There's only one other clause in the unifier, which says is this variable matching a variable, in which case you go look in the dictionary and see if that's consistent with what's in the dictionary. So all the, quote, deduction that's in this language, if you sort of look at it, sort of sits in the rule applications, which, if you look at that, sits in the unifier, which, if you look at that under a microscope, sits essentially in the pattern matcher. There's no magic at all going on in there. And the, quote, deduction that you see is just the fact that there's this recursion, which is unwinding the matches bit by bit. So it looks like this thing is being very clever, but in fact, it's not being very clever at all. There are cases where a unifier might have to be clever. Let me show you one more. Suppose I want to unify a list of two elements, x and x, with a thing that says it's y followed by a dot y. Now, if you think of what that would have to mean, it would have to mean that x had better be the same as y, but also x had better be the same as a list whose first element is a and whose rest is y. And if you think about what that would have to mean, it would have to mean that y is the infinite list of a's. In some sense, in order to do that unification, I have to solve the fixed-point equation cons of a to y is equal to y. And in general, I wrote a very simple one. Really doing unification might have to solve an arbitrary fixed-point equation: f of y equals y. And basically, you can't do that and make the thing finite all the time. So how does the logic language handle that? The answer is it doesn't. It just punts. And there's a little check in the unifier, which says, oh, is this one of the hard cases which when I go to match things would involve solving a fixed -point equation? And in this case, I will throw up my hands. And if that check were not in there, what would happen? In most cases is that the unifier would just go into an infinite loop. And other logic programming languages work like that. So there's really no magic. The easy case is done in a matcher. The hard case is not done at all. And that's about the state of this technology. Let me just say again formally how rules work now that I talked about unifiers. So the official definition is that to apply a rule, we -- well, let's start using some words we've used before. Let's talk about sticking dictionaries into these big boxes of query things as evaluating these large queries relative to an environment or a frame. So when you think of that dictionary, what's the dictionary after all? It's a bunch of meanings for symbols. That's what we've been calling frames or environments. What does it mean to do some processing relevant to an environment? That's what we'v e been calling evaluation. So we can say the way that you apply a rule is to evaluate the rule body relative to an environment that's formed by unifying the rule conclusion with the given query. And the thing I want you to notice is the complete formal similarity to the net of circular evaluator or the substitution model. To apply a procedure, we evaluate the procedure body relative to an environment that's formed by blinding the procedure parameters to the arguments. There's a complete formal similarity here between the rules, rule application, and procedure application even though these things are very, very different. And again, you have the EVAL APPLY loop. EVAL and APPLY. So in general, I might be processing some combined expression that will turn into a rule application, which will generate some dictionaries or frames or environments-- whatever you want to call them-- from match, which will then be the input to some big compound thing like this. This has pieces of it and may have other rule applications. And you have essentially the same cycle even though there's nothing here at all that looks like procedures. It really has to do with the fact you've built a language whose means of combination and abstraction unwind in certain ways. And then in general, what happens at the very top level, you might have rules in your database also, so things in this database might be rules. There are ways to check that things are true. So it might come in here and have to do a rule check. And then there's some control structure which says, well, you look at some rules, and you look atsome data elements, and you look at some rules and data elements, and these fan out and out and out. So it becomes essentially impossible to say what order it's looking at these things in, whether it's breadth first or depth first or anything. And it's even more impossible because the actual order is somehow buried in the delays of the streams. So what's very hard to tell from this is the order in which it's scanned. But what's true, because you're looking at the stream view, is that all of them eventually get looked at. Let me just mention one tiny technical problem. Suppose I tried saying boss of y is computer, then a funny thing would happen. As I stuck a dictionary with y in here, I might get-- this y is not the same as that y, which was the other piece of somebody's job description. So if I really only did literally what I said, we'd get some variable conflict problems. So I lied to you a little bit. Notice that problem is exactly a problem we've run into before. It is precisely the need for local variables in a language. When I have the sum of squares, that x had better not be that x. That's exactly the same as this y had better not be that y. And we know how to solve that. That was this whole environment model, and we built chains of frames and a ll sorts of things like that. There's a much more brutal way to solve it. In the query language, we didn't even do that. We did something completely brutal. We said every time you apply a rule, rename consistently all the variables in the rule to some new unique names that won't conflict with anything. That's conceptually simpler, but really brutal and not particularly efficient. But notice, we could have gotten rid of all of our environment structures if we defined for procedures in Lisp the same thing. If every time we applied a procedure and did the substitution model we renamed all the variables in the procedure, then we never would have had to worry about local variables because they would never arise. OK, well, that would be inefficient, and it's inefficient here in the query language, too, but we did it to keep it simple. Let's break for questions. AUDIENCE: When you started this section, you emphasized how powerful our APPLY EVAL model was that we could use it for any language. And then you say we're going to have this language which is so different. It turns out that this language, as you just pointed out, is very much the same. I'm wondering if you're arguing that all languages end up coming down to this you can apply a rule or apply a procedure or some kind of apply? PROFESSOR: I would say that pretty much any language where you really are building up these means of combination and giving them simpler names and you're saying anything of the sort, like here's a general kind of expression, likehow to square something, almost anything that you would call a procedure. If that's got to have parts, you have to unwind those parts. You have to have some kind of organization which says when I look at the abstract variables or tags or whatever you want to call them that might stand for particular things, you have to keep track of that, and that's going to be something like an environment. And then if you say this part can have parts which I have to unwind, you've got to have something like this cycle. And lots and lots of languages have that character when they sort of get put together in this way. This language again really is different because there's nothing like procedures on the outside. When you go below the surface and you see the implementatio n, of course, it starts looking the same. But from the outside, it's a very different world view. You're not computing functions of inputs. AUDIENCE: You mentioned earlier that when you build all of these rules in pattern matcher and with the delayed action of streams, you really have no way to know in what order things are evaluated. PROFESSOR: Right. AUDIENCE: And that would indicate then that you should only express declarative knowledge that's true for all-time, no-time sequence built into it. Otherwise, these things get all-- PROFESSOR: Yes. Yes. The question is this really is set up for doing declarative knowledge, and as I presented it-- and I'll show you some of the ugly warts under this after the break. As I presented it, it's just doing logic. And in principle, if it welogic, it wouldn't matter what order it's getting done. And it's quite true when you start doing things where you have side effects like adding things to the database and taking things out, and we'll see some others, you use that kind of control. So, for example, contrasting with Prolog. Say Prolog has various features where you really exploit the order of evaluation. And people write Prolog programs that way. That turns out to be very complicated in Prolog, although if you're an expert Prolog programmer, you can do it. However, here I don't think you can do it at all. It's very complicated because you really are giving up control over any prearranged order of trying things. AUDIENCE: Now, that would indicate then that you have a functional mapping. And when you started out this lecture, you said that we express the declarative knowledge which is a relation, and we don't talk about the inputs and the outputs. PROFESSOR: Well, there's a pun on functional, right? There's function in the sense of no side effects and not depending on what order is going on. And then there's functional in the sense of mathematical function, which means input and output. And it's just that pun that you're making, I think. AUDIENCE: I'm a little unclear on what you're doing with these two statements, the two boss statements. Is the first one building up the database and the second one a query or -- PROFESSOR: OK, I'm sorry. What I meant here, if I type something like this in as a query -- I should have given an example way at the very beginning. If I type in job, Ben Bitdiddle, computer wizard, what the processing will do is if it finds a match, it'll find a match to that exact thing, and it'll type out a job, Ben Bitdiddle, computer wizard. If it doesn't find a match, it won't find anything. So what I should have said is the way you use the query language to check whether something is true, remember, that's one of the things you want to do in logic programming, is you type in your query and either that comes out or it doesn't. So what I was trying to illustrate here, I wanted to start with a very simple example before talking about unifiers. So what I should have said, if I just wanted to check whether this is true, I could type that in and see if anything came out AUDIENCE: And then the second one-- PROFESSOR: The second one would be a real query. AUDIENCE: A real query, yeah. PROFESSOR: What would come out, see, it would go in here say with FOO, and in would go frame that says z is bound to who and d is bound to computer. And this will pass through, and then by the time it got out of here, who would pick up a binding. AUDIENCE: On the unifying thing there, I still am not sure what happens with who and z. If the unifying-- the rule here says-- OK, so you say that you can't make question mark equal to question mark who. PROFESSOR: Right. That's what the matcher can't do. But what this will mean to a unifier is that there's an environment with three variables. d here is computer. z is whatever who is. So if later on in the matcher routine it said, for example, who has to be 3, then when I looked up in the dictionary, it will say, oh, z is 3 because it's the same as who. And that's in some sense the only thing you need to do to extend the unifier to a matcher. AUDIENCE: OK, because it looked like when you were telling how to unify it, it looked like you would put the things together in such a way that you'd actually solve and have a value for both of them. And what it looks like now is that you're actually pass a dicti onary with two variables and the variables are linked. PROFESSOR: Right. It only looks like you're solving for both of them because you're sort of looking at the whole solution at once. If you sort of watch the thing getting built up recursively, it's merely this. AUDIENCE: OK, so you do pass off that dictionary with two variables? PROFESSOR: That's right. AUDIENCE: And link? PROFESSOR: Right. It just looks like an ordinary dictionary. AUDIENCE: When you're talking about the unifier, is it that there are some cases or some points that you are not able to use by them? PROFESSOR: Right. AUDIENCE: Can you just by building the rules or writing the forms know in advance if you are going to be able to solve to get the unification or not? Can you add some properties either to the rules itself or to the formula that you're writing so that you avoid the problem of not finding unification? PROFESSOR: I mean, you can agree, I think, to write in a fairly restricted way where you won't run into it. See, because what you're getting -- see, the place where you get into problems is when you-- well, again, you're trying to match things like that against things where these have structure, where a, y, b, y something. So this is the kind of place where you're going to get into trouble. AUDIENCE: So you can do that syntactically? PROFESSOR: So you can kind of watch your rules in the kinds of things that your writing. AUDIENCE: So that's the problem that the builder of the database has to be concerned? PROFESSOR: That's a problem. It's a problem either-- not quite the builder of the database, the person who is expressing the rules, or the builder of the database. What the unifier actually does is you can check at the next level down when you actually get to the unifier and you'll see in the code where it looks up in the dictionary. If it sort of says what does y have to be? Oh, does y have to be something that contains a y as its expression? At that point, the unifier and say, oh my God, I'm trying to solve a fixed-point equation. I'll give it up here. AUDIENCE: You make the distinction between the rules in the database. Are the rules added to the database? PROFESSOR: Yes. Yes, I should have said that. One way to think about rules is that they're just other things in the database. So if you want to check the things that have to be checked in the database, they're kind of virtual facts that are in the database . AUDIENCE: But in that explanation, you made the differentiation between database and the rules itself. PROFESSOR: Yeah, I probably should not have done that. The only reason to do that is in terms of the implementation. When you look at the implementation, there's a part which says check either primitive assertions in the database or check rules. And then the real reason why you can't tell what order things are going to come out in and is that the rules database and the data database sort of get merged in a kind of delayed evaluation way. And so that's what makes the order very complicated. OK, let's break. We've just seen how the logic language works and how rules work. Now, let's turn to a more profound question. What do these things mean? That brings us to the subtlest, most devious part of this whole query language business, and that is that it's not quite what it seems to be. AND and OR and NOT and the logical implication of rules are not really the AND and OR and NOT and logical implication of logic. Let me give you an example of that. Certainly, if we have two things in logic, it ought to be the case that AND of P and Q is the same as AND of Q and P and that OR of P and Q is the same as OR of Q and P. But let's look here. Here's an example. Let's talk about somebody outranking somebody else in our little database organization. We'll say s is outranked by b or if either the supervisor of this is b or there's some middle manager here, that supervisor of s is m, and m is outranked by b. So there's one way to define rule outranked by. Or we can write exactly the same thing, except at the bottom here, we reversed the order of these two clauses. And certainly if this were logic, those ought to mean the same thing. However, in our particular implementation, if you say something like who's outranked by Ben Bitdiddle, what you'll find is that this rule will work perfectly well and generate answers, whereas this rule will go into an infinite loop. And the reason for that is that this will come in and say, oh, who's outranked by Ben Bitdiddle? Find an s which is outranked by b, where b is Ben Bitdiddle, which is going to happen in it a subproblem. Oh gee, find an m such as m is outranked by Ben Bitdiddle with no restrictions on m. So this will say in order to solve this problem, I solve exactly the same problem. And then after I've solved that, I'll check for a supervisory relationship. Whereas this one won't get into that, because before it tries to find this outranked by, it'll already have had a re striction on m here. So these two things which ought to mean the same, in fact, one goes into an infinite loop. One does not. That's a very extreme case of a general thing that you'll find in logic programming that if you start changing the order of the things in the ANDs or ORs, you'll find tremendous differences in efficiency. And we just saw an infinitely big difference in efficiency and an infinite loop. And there are similar things having to do with the order in which you enter rules. The order in which it happens to look at rules in the database may vastly change the efficiency with which it gets out answers or, in fact, send it into an infinite loop for some orderings. And this whole thing has to do with the fact that you're checking these rules i n some order. And some rules may lead to really long paths of implication. Others might not. And you don't know a priori which ones are good and which ones are bad. And there's a whole bunch of research having to do with that, mostly having to do with thinking about making parallel implementations of logic programming languages. And in some sense, what you'd like to do is check all rules in parallel and whichever ones get answers, you bubble them up. And if some go down infinite deductive changed, well, y ou just-- you know, memory is cheap and processors are cheap, and you just let them buzz for as for as long as you want. There's a deeper problem, though, in comparing this logic language to real logic. The example I just showed you, it went into an infinite loop maybe, but at least it didn't give the wrong answer. There's an actual deeper problem when we start comparing, seriously comparing this logic language with real classical logic. So let's sort of review real classical logic. All humans are mortal. That's pretty classical logic. Then maybe we'll continue in the very best classical tradition. We'll say all-- let's make it really classical. All Greeks are human, which has the syllogism that Socrates is a Greek. And then what do you write here? I thi nk three dots, classical logic. Therefore, then the syllogism, Socrates is mortal. So there's some real honest classical logic. Let's compare that with our classical logic database. So here's a classical logic database. Socrates is a Greek. Plato is a Greek. Zeus is a Greek, and Zeus is a god. And all humans are mortal. To show that something is mortal, it's enough to show that it's human. All humans are fallible. And all Greeks are humans is not quite right. This says that all Greeks who are not gods are human. So to show something's human, it's enough to show it's a Greek and not a god. And the address of any Greek god is Mount Olympus. So there's a little classical logic database. And indeed, that would work fairly well. If we type that in and say is Socrates mortal or Socrates fallible or mortal? It'll say yes. Is Plato mortal and fallible. It'll say yes. If we say is Zeus mortal? It won't find anything. And it'll work perfectly well. However, suppose we want to extend this. Let's define what it means for someone to be a perfect being. Let's say rule: a perfect being. And I think this is right. If you're up on your medieval scholastic philosophy, I believe that perfect beings are ones who were neither mortal nor fallible. AND NOT mortal x, NOT fallible x. So we'll define this system to teach it what a perfect being is. And now what we're going to do is he ask for the address of all the perfect beings. AND the address of x is y and x is perfect. And so what we're generating here is the world's most exclusive mailing list. For the address of all the perfect things, we might have typed this in. Or we might type in this. We'll say AND perfect of x and the address of x is y. Well, suppose we type all that in and we try this query. This query is going to give us an answer. This query will say, yeah, Mount Olympus. This query, in fact, is going to give us nothing. It will say no addresses of perfect beings. Now, why is that? Why is there a difference? This is not an infinite loop question. This is a different answer question. The reason is that if you remember the implementation of NOT, NOT acted as a filter. NOT said I'm going to take some possible dictionaries, some possible frames, some possible answers, and filter out the ones that happened to satisfy some condition, and that's how I implement NOT. If you think about what's going on here, I'll build this query box where the output of an address piece gets fed into a perfect piece. What will happen is the address piece will set up some things of everyone whose address I know. Those will get filtered by the NOTs inside perfect here. So it will throw out the ones which happened to be either mortal or fallible. In the other order what happens is I set this up, started up with an empty frame. The perfect in here doesn't find anything for the NOTs to filter, so nothing comes out here at all. And there's sort of nothing there that gets fed into the address thing. So here, I don't get an answer. And again, the reason for that is NOT isn't generating anything. NOT's only throwing out things. And if I never started up with anything, there's nothing for it to throw out. So out of this thing, I get the wrong answer. How can you fix that? Well, there are ways to fix that. So you might say, well, that's sort of stupid. Why are you just doing all your NOT stuff at the beginning? The right way to implement NOT is to realize that when you have conditions like NOT, you should generate all your answers first, and then with each of these dictionaries pass along until at the very end I'll do filtering. And there are implementations of logic languages that work like that that solve this particular problem. However, there's a more profound problem, which is which one of these is the right answer? Is it Mount Olympus or is it nothing? So you might say it's Mount Olympus, because after all, Zeus is in that database, and Zeus was neither mortal nor fallible. So you might say Zeus wants to satisfy NOT mortal Zeus or NOT fallible Zeus. But let's actually look at that database. Let's look at it. There's no way-- how does it know that Zeus is not fallible? There's nothing in there about that. What's in there is that humans are fallible. How does it know that Zeus is not mortal? There's nothing in there about that. It just said I don't have any rule, which -- the only way I can deduce something's mortal is if it's human, and that's all it really knows about mor tal. And in fact, if you remember your classical mythology, you know that the Greek gods were not mortal but fallible. So the answer is not in the rules there. See, why does it deduce that? See, Socrates would certainly not have made this error of logic. What NOT needs in this language is not NOT. It's not the NOT of logic. What NOT needs in this language is not deducible from things in the database as opposed to not true. That's a very big difference. Subtle, but big. So, in fact, this is perfectly happy to say not anything that it doesn't know about. So if you ask it is it not true that Zeus likes chocolate ice cream? It will say sure, it's not true. Or anything else or anything it doesn't know about. NOT means not deducible from the things you've told me. In a world where you're identifying not deducible with, in fact, not true, this is called the closed world assumption. The closed world assumption. Anything that I cannot deduce from what I know is not true, right? If I don't know anything about x, the x isn't true. That's very dangerous. From a logical point of view, first of all, it doesn't really makes sense. Because if I don't know anything about x, I'm willing to say not x. But am I willing to say not not x? Well, sure, I don't know anything about that either maybe. So not not x is not necessarily the same as x and so on and so on and so on, so there's some sort of funny bias in there. So that's sort of funny. The second thing, if you start building up real reasoning programs based on this, thi nk how dangerous that is. You're saying I know I'm in a position to deduce everything true that's relevant to this problem. I'm reasoning, and built into my reasoning mechanism is the assumption that anything that I don't know can't possibly be relevant to this problem, right? There are a lot of big organizations that work like that, right? Most corporate marketing divisions work like that. You know the consequences to that. So it's very dangerous to start really typing in these big logical implication sy stems and going on what they say, because they have this really limiting assumption built in. So you have to be very, very careful about that. And that's a deep problem. That's not a problem about we can make a little bit cleverer implementation and do the filters and organize the infinite loops to make them go away. It's a different kind of problem. It's a different semantics. So I think to wrap this up, it's fair to say that logic programming I think is a terrifically exciting idea, the idea that you can bridge this gap from the imperative to the declarative, that you can start talking about relations and really get tremendous power by going above the abstraction of what's my input and what's my output. And linked to logic, the problem is it's a goal that I think has yet to be realized. And probably one of the very most interesting research questions going on now in languages is how do you somehow make a real logic language? And secondly, how do you bridge the gap from this world of logic and relations to the worlds of more traditional languages and somehow combine the power of both. OK, let's break. AUDIENCE: Couldn't you solve that last problem by having the extra rules that imply it? The problem here is you have the definition of something, but you don't have the definition of its opposite. If you include in the database something that says something implies mortal x, something else implies not mortal x, haven't you basically solved the problem? PROFESSOR: But the issue is do you put a finite number of those in? AUDIENCE: If things are specified always in pairs -- PROFESSOR: But the impression is then what do you do about deduction? You can't specify NOTs. But the problem is, in a big system, it turns out that might not be a finite number of things. There are also sort of two issues. Partly it might not be finite. Partly it might be that's not what you want. So a good example would be suppose I want to do connectivity. I want a reason about connectivity. And I'm going to tell you there's four things: a and b and c and d. And I'll tell you a is connected to b and c's connected to d. And now I'll tell you is a connected to d? That's the question. There's an example where I would like something like the closed world assumption. That's a tiny toy, but a lot of times, I want to be able to say something like anything that I haven't told you, assume is not true. So it's not as simple as you only want to put in explicit NOTs all over the place. It's that sometimes it really isn't clear what you even want. That having to specify both everything and not everything is too precise, and then you get down into problems there. But there are a lot of approaches that explicitly put in NOTs and reason based on that. So it's a very good idea. It's just that then it starts becoming a little cumbersome in the very large problems you'd like to use. AUDIENCE: I'm not sure how directly related to the argument this is, but one of your points was that one of the dangers of the closed rule is you never really know all the things that are there. You never really know all the parts to it. Isn't that a major problem with any programming? I always write programs where I assume that I've got all the cases, and so I check for them all or whatever, and somewhere down the road, I find out that I didn't check for one of them. PROFESSOR: Well, sure, it's true. But the problem here is it's that assumptio n which is the thing that you're making if you believe you're identifying this with logic. So you're quite right. It's a situation you're never in. The problem is if you're starting to believe that what this is doing is logic and you look at the rules you write down and say what can I deduce from them, you have to be very careful to remember that NOT means something else. And it means something else based on an assumption which is probably not true. AUDIENCE: Do I understand you correctly that you cannot fix this problem without killing off all possibilities of inference through altering NOT? PROFESSOR: No, that's not quite right. There are other-- there are ways to do logic with real NOTs. There are actually ways to do that. But they're very inefficientas far as anybody knows. And they're much more-- the, quote, inference in here is built into this unifier and this pattern matching unification algorithm. There are ways to automate real logical reasoning. But it's not based on that, and logic programming languages don't tend to do that because it's very inefficient as far as anybody knows. All right, thank you. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed this material in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec9a.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 9A: Register Machines [MUSIC PLAYING - "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] PROFESSOR: Well, up 'til now, I suppose, we've been learning about a lot of techniques for organizing big programs, symbolic manipulation a bit, some of the technology that you use for establishing languages, one in terms of another, which is used for organizing very large programs. In fact, the nicest programs I know look more like a pile of languages than like a decomposition of a problem into parts. Well, I suppose at this point, there are still, however, a few mysteries about how this sort of stuff works. And so what we'd like to do now is diverge from the plan of telling you how to organize big programs, and rather tell you something about the mechanisms by which these things can be made to work. The main reason for this is demystification, if you will, that we have a lot of mysteries left, like exactly how it is the case that a program is controlled, how a computer knows what the next thing to do is, or something like that. And what I'd like to do now is make that clear to you, that even if you've never played with a physical computer before, the mechanism is really very simple, and that you can understand it completely with no trouble. So I'd like to start by imagining that we-- well, the way we're going to do this, by the way, is we're going to take some very simple Lisp programs, very simple Lisp programs, and transform them into hardware. I'm not going to worry about some intermediate step of going through some existing computer machine language and then showing you how that computer works, because that's not as illuminating. So what I'm really going to show you is how a piece of machinery can be built to do a job that you have written down as a program. That program is, in fact, a description of a machine. We're going to start with a very simple program, proceed to show you some simple mechanisms, proceed to a few more complicated programs, and then later show you a not very complicated program, how the evaluator transformsinto a piece of hardware. And of course at that point, you have made the universal transition and can execute any program imaginable with a piece of well- defined hardware. Well, let's start up now, give you a real concrete feeling for this sort of thing.Let's start with a very simple program. Here's Euclid's algorithm. It's actually a little bit more modern than Euclid's algorithm. Euclid's algorithm for computing the greatest common divisor of two numbers was invented 350 BC, I think. It's the oldest known algorithm. But here we're going to talk about GCD of A and B, the Greatest Common Divisor or two numbers, A and B. And the algorithm is extremely simple. If B is 0, then the result is going to be A. Otherwise, the result is the GCD of B and the remainder when A is divided by B. So this we have here is a very simple iterative process. This a simple recursive procedure, recursively defined procedure, recursive definition, which yields an iterative process. And the way it works is that every step, it determines whether B was zero. And if B is 0, we got the answer in A. Otherwise, we make another step where A is the old B, and B is the remainder of the old A divided by the old B. Very simple. Now this, I've already told you some of the mechanism by jus t saying it that way. I set it in time. I said there are certain steps, and that, in fact, one of the things you can see here is that one of the reasons why this is iterative is nothing is needed of the last step to get the answer. All of the information that's needed to run this algorithm is in A and B. It has two well-defined state variables. So I'm going to define a machine for you that can compute you GCDs. Now let's see. Every computer that's ever been made that's a single-process computer, as opposed to a multiprocessor of some sort, is made according to the same plan. The plan is the computer has two parts, a part called the datapaths, and a part called the controller. The datapaths correspond to a calculator that you might have. It contains certa in registers that remember things, and you've all used calculators. It has some buttons on it and some lights. And so by pushing the various buttons, you can cause operations to happen inside there among the registers, and some of the results to be displayed. That's completely mechanical. You could imagine that box has no intelligence in it. Now it might be very impressive that it can produce the sine of a number, but that at least is apparently possibly mechanical. At least, I could open that up in the same way I'm about to open GCD. So this may have a whole computer inside of it, but that's not interesting. Addition is certainly simple. That can be done without any further mechanism. Now also, if we were to look at the other half, the controller, that's a part that's dumb, too. It pushes the buttons. It pushes them according to the sequence, which is written down on a piece of paper, and observes the lights. And every so often, it comes to a place in a sequence that says, if light A is on, do this sequence. Otherwise, do that sequence. And thereby, there's no complexity there either. Well, let's just draw that and see what we feel about that. So for computing GCDs, what I want you to think about is that there are these registers. A register is a place where I store a number, in this case. And this one's called a. And then there's another one for storing b. Now we have to see what things we can do with these registers, and they're not entirely obvious what you can do with them. Well, we have to see what things we need to do with them. We're looking at the problem we're trying to solve. One of the important things for designing a computer, which I think most designers don't do, is you study the problem you want to solve and then use what you learn from studying the problem you want to solve to put in the mechanisms needed to solve it in the computer you're building, no more no less. Now it may be that the problem you're trying to sol ve is everybody's problem, in which case you have to build in a universal interpreter of some language. But you shouldn't put any more in than required to build the universal interpreter of some language. We'll worry about that in a second. OK, going back to here, let's see. What do we have to be able to do? Well, somehow, we have to be able to get B into A. We have to be able to get the old value of B into the value of A. So we have to have some path by which stuff can flow, whatever this information is, from b to a. I'm going to draw that with by an arrow saying that it is possible to move the contents of b into a, replacing the value of a. And there's a little button here which you push which allows that to happen. That's what the little x is here. Now it's also the case that I have to be able to compute the remainder of a and b. Now that may be a complicated mess. On the other hand, I'm going to make it a small box. If we have to, we may open up that box and look inside and see what it is. So here, I'm going to have a little box, which I'm going to draw this way, which we'll call the remainder. And it's going to take in a. That's going to take in b. And it's going to put out something, the remainder of a divided by b. Another thing we have to see here is that we have to be able to test whether b is equal to 0. Well, that means somebody's got to be looking at-- a thing that's looking at the value of b. I have a light bulb here which lights up if b equals 0. That's its job. And finally, I suppose, because of the fact that we want the new value of a to be the old value of b, and simultaneously the new value of b to be something I've done with a, and if I plan to make my machine such that everything happens one at a time, one motion at a time, and I can't put two numbers in a register, then I have to have another place to put one while I'm interchanging. OK? I can't interchange the two things in my hands, unless I either put two in one hand and then pull it back the other way, or unless I put one down, pick it up, and put the other one, like that, unless I'm a juggler, which I'm not, as you can see, in which case I have a possibility of timing errors. In fact, much of the type of computer design people do involves timing errors, of some potential timing errors, which I don't much like. So for that reason, I have to have a place to put the second one of them down. So I have a place called t, which is a register just for temporary, t, with a button on it. And then I'll take the result of that, since I have to take that and put into b, over here, we'll take the result of that and go like this, and a button here. So that's the datapaths of a GCD machine. Now what's the controller? Controller's a very simple thing, too. The machine has a state. The way I like to visualize that is that I've got a maze. And the maze has a bunch of places connected by directed arrows. And what I have is a marble, which represents the state of the controller. The marble rolls around in the maze. Of course, this analogy breaksdown for energy reasons. I sometimes have to pump the marble up to the top, because it's going to otherwise be a perpetual motion machine. But not worrying about that, this is not a physical analogy. This marble rolls around. And every time it rolls around certain bumpers, like in a pinball machine, it pushes one of these buttons. And every so often, it comes to a place, which is a division, where it has to make a choice. And there's a flap, which is c ontrolled by this. So that's a really mechanical way of thinking about it. Of course, controllers these days, are not built that way in real computers. They're built with a little bit of ROM and a state register. But there was a time, like the DEC PDP-6, where that's how you built the controller of a machine. There was a bit that ran around the delay line, and it triggered things as it went by. And it would come back to the beginning and get fed round again. And of course, there were all sorts of great bugs you could have like two bits going around, two marbles. And then the machine has lost its marbles. That happens, too. Oh, well. So anyway, for this machine, what I have to do is the following. I'm going to start my maze here. And the first thing I've got to do, in a notation which many of you are familiar with, is b equal to zero, a test. And there's a possibility, either yes, in which case I'm done. Otherwise, if no, then I'm going have to roll over some bumpers. I'm going to do it in the following order. I want to do this interchange game. Now first, since I need both a and b, but then the first-- and this is not necessary-- I want to collect this. This is the thing that's going to go into b. So I'm going to say, take this, which depends upon both a and b, and put the remainder into here. So I'm going to push this button first. Then, I'm going to transfer b to a, push that button, and then I transfer the temporary into b, push that button. So a very sequential machine, it's very inefficient. But th at's fine right now. We're going to name the buttons, t gets remainder. a gets b. And b gets t. And then I'm going to go around here and it's to go back to start. And if you look, what are we seeing here? We're seeing the various-- what I really have is some sort of mechanical connection, where t gets r controls this thing. And I have here that a gets b controls this fellow over here, and this fellow over here. Boy, that's absolutely pessimal, the inverse of optimal. Every line heads across every othe r line the way I drew it. I suppose this goes here, b gets t. Now I'd like to run this machine. But before I run the machine, I want to write down a description of this controller, just so you can see that these things, of course, as usual, can be written down in some nice language, so that we don't have to always draw these diagrams. One of the problems with diagrams is that they take up a lot of space. And for a machine this small, it takes two blackboards. For a machine that's the evaluator machine, I have trouble putting it into this room, even though it isn't very big. So I'm going to make a little language for this that's just a description of that, saying define a machine we'll call GCD. Of course, once we have something like this, we have a simulator for it. And the reason why we want to build a language in this form, is because all of a sudden we can manipulate these expressions that I'm writing down. And then of course I can write things that can algebraically manipulate these things, simulate them, all that sort of things that I might want to do, perhaps transform them as a layout, who knows. Once I have a nice representation of registers, it has certain registers, which we can call A, B, and T. And there's a controller. Actually, a better language, which would be more explicit, would be one which named every button also and said what it did. Like, this button causes the contents of T to go to the contents of B. Well I don't want to do that, because it's actually harder to read to do that, and it takes up more space. So I'm going to have that in the instructions written in the controller. It's going to be implicit what the operations are. They can be deduced by reading these and collecting together all the different things that can be done. Well, let's just look at what these things are. There's a little loop that we go around which says branch, this is the representation of the little flap that decides which way you go here, if 0 fetch of B, the contents of B, and if the contents of B is 0, then go to a place called done. Now, one thing you're seeing here, this looks very much like a traditional computer language. And what you're seeing here is things like labels that represent places in a sequence written down as a sequence. The reason why they're needed is because over here, I've written something with loops. But if I'm writing English text, or something like that, it's hard to refer to a place. I don't have arrows. Arrows are represented by giving names to the places where the arrows terminate, and then referring to them by those names. Now this is just an encoding. There's nothing magical about things like that. Next thing we're going to do is we're going to say, how do we do T gets R? Oh, that's easy enough, assign. We assign to T the remainder. Assign is the name of the button. That's the button-pusher. Assign to T the remainder, and here's the representation ofthe operation, when we divide the fetch of A by the fetch of B. And we're also going to assign to A the fetch of B, assign to B the result of getting the contents of T. And now I have to refer to the beginning here. I see, why don't I call that loop like I have here? So that's that reference to that arrow. And when we're done, we're done. We go to here, which is the end of the thing. So here's just a written representation of this fragment of machinery that we've drawn here. Now the next thing I'd like to do is run this. I want us to feel it running. Never done this before, you got to do it once. So let's take a particular problem. Suppose we want to compute the GCD of a equals 30 and b equals 42. I have no idea what that is right now. But a 30 and b is 42. So that's how I start this thing up. Well, what's the first thing I do? I say is B equal to 0, no. Then assign to T the remainder of the fetch of A and the fetch of B. Well the remainder of 30 when divided by 42 is itself 30. Push that button. Now the marble has rolled to here. A gets B. That pushes this button. So 42 moves into here. B gets C. Push that button. The 30 goes here. Let met just interchange them. Now let's see, go back to the beginning. B 0, no. T gets the remainder. I suppose the remainder when dividing 42 by 30 is 12. I push that one. Next thing I do is allow the 30 to go to here, push this one, allow the 12 to go to here. Go around this thing. Is that done? No. How about-- so now I have to find out the remainder of 30 divided by 12. And I believe that's 6. So 6 goes here on this button push. Then the next thing I push is this one, which the 12 goes into here. Then I push this button. The 6 gets into here. Is 6 equal to 0? No. OK. So then at that point, the next thing to do is divide it. Ooh, this has got a remainder of 0. Looks like we're almost done. Move the 6 over here next. 0 over here. Is the answer 0? Yes. B is 0, therefore the answer is in A. The answer is 6. And indeed that's right, because if we look at the original problem, what we have is 30 is 2 times 3 times 5, and 42 is 2 times 3 times 7. So the greatest common divisor is 2 times 3, which is 6. Now normally, we write one other little line here, just to make it a little bit clearer, which is that we leave in a connection saying that this light is the guy that that flap looks at. Of course, any real machine has a lot more complicated things in it than what I've just shown you. Let's look for a second at the first still store. Wow. Well you see, for example, one thing we might want to do is worry about the operations that are of IO form. And we may have to collect something from the outside. So a state machine that we might have, the controller may have to, for example, get a value from something and put register a to load it up. I have to master load up register b with another value. And then later, when I'm done, I might want to print the answer out. And of course, that might be either simple or complicated. I'm writing, assuming print is very simple, and read is very simple. But in fact, in the real world, those are very complicated operations, usually much, much larger and more complicated than the thing you're doing as your problem you're trying to solve. On the other hand, I can remember a time when, I remember using IBM 7090 computer of sorts, where things like read and write of a single object, a single number, a number, is a primitive operation of the IO controller. OK? And so we have that kind of thing in there. And in such a machine, well, what are we really doing? We're just saying that there's a source over here called "read," which is an operation which always has a value. We have to think about this as always having a value which can be gated into either register a or b. And print is some sort of thing which when you gate it appropriately, when you push the button on it, will cause a print of the value that's currently in register a. Nothing very exciting. So that's one sort of thing you might want to have. But these are also other things that are a little bit worrisome. Like I've used here some complicated mechanisms. What you see here is remainder. What is that? That may not be so obvious how to compute. It may be something which when you open it up, you get a whole machine. OK? In fact, that's true. For example, if I write down the program for remainder, the simplest program for it is by repeated subtraction. Because of course, division can be done by repeated subtraction of numbers, of integers. So the remainder of N divided by D is nothing more than if N is less than D, then the result is N. Otherwise, it's the remainder when we subtract D from N with respect to D, when divided by D. Gee, this looks just like the GCD program. Of course, it's not a very nice way to do remainders. You'd really want to use something like binary notation and shift and things like that in a practical computer. But the point of that is that if I open this thing up, I might find inside of it a computer. Oh, we know how to do that. We just made one. And it could be another thing just like this. On the other hand, we might want to make a more efficient or better-structured machine, or maybe make use of some of the registers more than once, or some horrible mess like that that hardware designers like to do, and for very good reasons. So for example, here's a machine that you see, which you're not supposed to be able to read. It's a little bit complicated. But what it is is the integration of the remainder into the GCD machine. A nd it takes, in fact, no more registers. There are three registers in the datapaths. OK? But now there's a subtractor. There are two things that are tested. Is b equal to 0, or is t less than b? And then the controller, which you see over here, is not much more complicated. But it has two loops in it, one of which is the main one for doing the GCD, and one of which is the subtraction loop for doing the remainder sub-operation. And there are ways, of course, of, if you think about it, taking the remainder program. If I take remainder, as you see over there, as a lambda expression, substitute it in for remainder over here in the GCD program, then do some simplification by substituting a and b for remainder in there, then I can unwind this loop. And I can get this piece of machinery by basically, a little bit of algebraic simplification on the lambda expressions. So I suppose you've seen your first very simple machines now. Are there any questions? Good. This looks easy, doesn't it? Thank you. I suppose, take a break. [MUSIC PLAYING - "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] PROFESSOR: Well, let's see. Now you know how to make an iterative procedure, or a procedure that yields an iterative process, turn into a machine. I suppose the next thing we want to do is worry about things that reveal recursive processes. So let's play w ith a simple factorial procedure. We define factorial of N to be if n is 1, the result is 1, using 1 right now to decrease the amount of work I have to do to simulate it, else it's times N factorial N minus 1. And what's different with this program, as you know, is that after I've computed factorial of N minus 1 here, I have to do something to the result. I have to multiply it by N. So the only way I can visualize what this machine is doing, because of the fact -- think of it this way, that I have a machine out here which somehow needs a factorial machine in order to compute its answer. But this machine, the outer machine, has to exist before and after the factorial machine, which is inside. Whereas in the iterative case, the outer machine doesn't need to exist after the inner machine is running, because you never need to go back to the outer machine to do anything. So here we have a problem where we have a machine which has the same machine inside of it, an infinitely large machine. And it's got other t hings inside of it, like a multiplier, which takes some inputs, and there's a minus 1 box, and things like that. You can imagine that's what it looks like. But the important thing is that here I have something that happens before and after, in the outer machine, the execution of the inner machine. So this machine has to have a life. It has to exist on both times sides of this machine. So somehow, I have to have a place to store the things that this thing needs to run. Infinite objects don't exist in the real world. What we have to do is arrange an illusion that we have an infinite object, we have an infinite amount of hardware somewhere. Now of course, illusion's all that really matters. If we can arrange that every time you look at some infinite object, the part of it that you look at is there, then it's as infinite as you need it to be. And of course, one of the things we might want to do, just look at this thing over here, is the organization that we've had so far involves having a part of the machine, which is the controller, which sits right over here, which is perfectly finite and very simple. We have some datapaths, which consist of registers and operators. And what I propose to do here is decompose the machine into two parts, such that there is a part which is fundamentally finite, and some part where a certain amount of infinite stuff can be kept. On the other hand this is very simple and really isn't infinite, but it's just very large. But it's so simple that it could be cheaply reproduced in such large amounts, we call it memory, that we can make a structure called a stack out of it which will allow us to, in fact, simulate the existence of an infinite machine which is made out of a recursive nest of many machines. And the way it's going to work is that we're going to store in this place called the stack the information required after the inner machine runs to resume the operation of the outer machine. So it will remember the important things about the life of the outer machine that will be needed for this computation. Since, of course, these machines are nested in a recursive manner, then in fact the stack will only be accessed in a manner which is the last thing that goes in is the first thing that comes out. So we'll only need to access some little part of this stack memory. OK, well, let's do it. I'm going to build you a datapath now, and I'm going to write the controller. And then we're going to execute this to see how you do it. So the factorial machine isn't so bad. It's going to have a register called the value, where the answer is going to be stored, and a registered called N, which is where the number I'm taking factorial will be stored, factorial of. And it will be necessary in some instances to connect VAL to N. In fact, one nice case of this is if I just said over here, N, because that would be right for N equal 1N. And I could just move the answer over there if that's important. I'm not worried about that right now. And there are things I have to be able to do. Like I have tobe able to, as we see here, multiply N by something in VAL, because VAL is the result of computing factorial. And I have to put the result back into VAL. So here we can see that the result of computing a factorial is N times the result of computing a factorial. VAL will be the representation of the answer of the inner factorial. And so I'm going to have to have a multiplier here, which is going to sample the value of N and the value of VAL and put the result back into VAL like that. I'm also going to have to be able to see if N is 1. So I need a light bulb. And I suppose the other thing I'm going to need to have is a way of decrementing N. So I'm going to have a decrementer, which takes N and is going to put back the result into N. That's pretty much what I need in my machine. Now, there's a little bit else I need. It's a little bit more complicated, because I'm also going to need a way to store, to save away, the things that are going to be needed for resuming the computation of a factorial after I've done a sub-factorial. What's that? One thing I need is N. So I'm going to build here a thing called a stack. The stack is a bunch of stuff that I'm going to write in sequentially. I don't how long it is. The longer it is, the better my illusion of infinity. And I'm going to have to have a way of getting stuff out of N and into the stack and vice versa. So I'm going to need a connection like this, which is two -way, whereby I can save the value of N and then restore it some other time through that connection. This is the stack. I also need a way of remembering where I was in the computation of factorial in the outer program. Now in the case of this machine, it isn't very much a problem. Factorial always returns, has to go back to the place where we multiply by N, except for the last time, when it has to return to whatever needs the factorial or go to done or stop. However, in general, I'm going to have to remember where I have been, because I might have computed factorial from somewhere else. I have to go back to that place and continue there. So I'm going to have to have some way of taking the place where the marble is in the finite state controller, the state of the controller, and storing that in the stack as well. And I'm going to have to have ways of restoring that back to the state of the-- the marble. So I have to have something that moves the marble to the right place. Well, we're going to have a place which is the marble now. And it's called the continue register, called continue, which is the place to put the marble nexttime I go to continue. That's what that's for. And so there's got to be some path from that into the controller. I also have to have some way of saving that on the stack. And I have to have some way of setting that up to have various constants, a certain fixed number of constants. And that's very easy to arrange. So let's have some constants here. We'll call this one after-fact. And that's a constant which we'll get into the continue register, and also another one called fact- done. So this is the machine I want to build. That's its datapaths, at least. And it mixes a little with the controller here, because of the fact that I have to remember where I was and restore myself to that place. But let's write the program now which represents the controller.I'm not going to write the define machine thing and the register list, because that's not very interesting. I'm just going to write down the sequence of instructions that constitute the controller. So we have assign, to set up, continue to done. We have a loop which says branch if equal 1 fetch N, if N is 1, then go to the base step of the induction, the simple case. Otherwise, I have to remember the things that are necessary to perform a sub -factorial. I'm going to go over here, and I have to perform a sub-factorial. So I have to remember what's needed after I will be done with that. See, I'm about to do something terrible. I'm about to change the value of N. But this guy has to know the old value of N. But in order to make the sub-factorial work, I have to change the value of N. So I have to remember the old value. And I also have to remember where I've been. So I save up continue. And this is an instruction that says, put something in the stack. Save the contents of the continuation register, which in this case is done, because later I'm going to change that, too, because I need to go back to after-fact, as well. We'll see that. We save N, because I'm going to need that for later. Assign to N the decrement of fetch N. Assign continue, we're going to look at this now, to after, we'll call it. That's a good name for this, a little bit easier and shorter, and fits in here. Now look what I'm doing here. I'm saying, if the answer is 1, I'm done. I'm going to have to just get the answer. Otherwise, I'm going to save the continuation, save N, make N one less than N, remember I'm going to come back to someplace else, and go back and start doing another factorial. However, I've got a different machine [? in me ?] now. N is 1, and continue is something else. N is N minus 1. Now after I'm done with that, I can go there. I will restore the old value of N, which is the opposite of this save over here. I will restore the continuation. I will then go to here. I will assign to the VAL register the product of N and fetch VAL. VAL fetch product assign. And then I will be done. I will have my answer to the sub -factorial in VAL. At that point, I'm going to return by going to the place where the continuation is pointing. That says, go to fetch continue. And then I have finally a base step, which is the immediate answer. Assign to VAL fetch N, and go to fetch continue. And then I'm done. Now let's see how this executes on a very simple case, because then we'll see the use of this stack to do the job we need. This is statically what it's doing, but we have look dynamically at this. So let's see. First thing we do is continue gets done. The way that happened is I pushed this. Let's call that done the way I have it. I push that button. Done goes into there. Now I also have to set this thing up to have an initial value. Let's consider a factorial of three, a simple case. And we're going to start out with our stack growing over here. Stacks have their own little internal state saying where they are, where the next place I'm going to write is. So now we say, is N 1? The answer is no. So now I'm going to save continue, bang. Now that done goes in here. And this moves to here, the next place I'm going to write. Save N 3. OK? Assign to N the decrement of N. That means I've pushed this button. This becomes 2. Assign to continue aft. So I've pushed that button. Aft goes in here. OK, now go to loop, bang, so up to here. Is N 1? No. So I have to save continue. What's continue? Continue is aft. Push this button. So this moves to here. I have to save N. N is over here. I got to 2. Push that button. So a 2 gets written there. And then this thing moves down here. OK, save N. Assign N to the decrement of N. This becomes a 1. Assign continue to aft. A -F-T gets written there again. Go to loop. Is N equal to 1? Oh, yes, the answer is 1. OK, go to base step. Assign to VAL fetch of N. Bang, 1 gets put in there. Go to fetch continue. So we look in continue. Basically, I'm pushing a button over here that goes to the controller. The continue becomes aft, and all of a sudden, the program's running here. I now have to restore the outer version of factorial. So we go here. We say, restore N. So restore N means take the contents that's here. Push this button, and it goes into here, 2, and the pointer moves up. Restore continue, pretty easy. Go push this button. And then aft gets written in here again. That means this thing moves up. I've gotten rid of something else on my stack. Right, then I go to here, which says, assign to VAL the product of N an VAL. So I push this button over here, bang. 2 times 1 gives me a 2, get written there. Go to fetch continue. Continue is aft. I go to aft. Aft says restore N. Do your restore N, means I take the value over here, which is 3, push this up to here, and move it into here, N. Now it's pushing that button. The next thing I do is restore continue. Continue is now going to becom e done. So this moves up here when I push this button. Done may or may be there anymore, I'm not interested, but it certainly is here. Next thing I do is assign to VAL the product of the fetch of N and the fetch of VAL. That's pushing this button over here, bang. 2 times 3 is 6. So I get a 6 over here. And go to fetch continue, whoops, I go to done, and I'm done. And my answer is 6, as you can see in the VAL register. And in fact, the stack is in the state it originally was in. Now there's a bit of discipline in using these things like stacks that we have to be careful of. And we'll see that in the next segment. But first I want to ask if there are any questions for this. Are there any questions? Yes, Ron. AUDIENCE: What happens when you roll off the end of the stack with-- PROFESSOR: What do you mean, roll off of? AUDIENCE: Well, the largest number-- a larger starting point of N requires more memory, correct? PROFESSOR: Oh, yes. Well, I need to have a long enough stack. You say, what if I violate my illusion? AUDIENCE: Yes. PROFESSOR: Well, then the magic doesn't work. The truth of the matter is that every machine is finite. And for a procedure like this, there's a limit to the number of sub- factorials I could have. Remember when we were doing the y-operator a while ago, we pointed out that there was a sequence of exponentiation procedures, each of which was a little better than the previous one. Well, we're now seeing how we implement that mathematical idea. The limiting process is only so good as as far as you take the limit. If you think about it, what am I using here? I'm using about two pieces of memory for every recursion of this process. If we try to compute factorial of 10,000, that's not a lot of memory. On the other hand, it's an awful big number. So the question is, is that a valuable thing in this case. But it really turns out not to be a terrible limit, because memory is el cheapo, and people are pretty expensive. OK, thank you, let's take a break. [MUSIC PLAYING - "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] PROFESSOR: Well, let's see. What I've shown you now is how to do a simple iterative process and a simple recursive process. I just want to summarize the design of simple machines for specific applications by showing you a little bit more complicated design, that of a thing that does doubly recursive Fibonacci, because it will indicate to us, and we'll understand, a bit about the conventions required for making stacks operate correctly. So let's see. I'm just going to write down, first of all, the program I'm going to translate. I need a Fibonacci procedure, it's very simple, which says, if N is less than 2, the result is N, otherwise it's the sum of Fib of N minus 1 and Fib of N minus 2. That's the plan I have here. And we're just going to write down the controller for such a machine. We're going to assume that there are registers, N, which holds the number we're taking Fibonacci of, VAL, which is where the answer is going to get put, and continue, which is the thing that's linked to the controller, like before. But I'm not going to draw another physical datapath, because it's pretty much the same as the last one you've seen. And of course, one of the most amazing things about computation is that after a while, you build up a little more features and a few more features, and all of the sudden, you've got everything you need. So it's remarkable that it just gets there so fast. I don't need much more to make a universal computer. But in any case, let's look at the controller for the Fibonacci thing. First thing I want to do is start the thing up by assign to continue a place called done, called Fib-done here. So that means that somewhere over here, I'm going to have a label, Fib-done, which is the place where I go when I want the machine to stop. That's what that is. And I'm going to make up a loop. It's a place I'm going to go to in order to start up computing a Fib. Whatever is in N at this point, Fibonacci will be computed of, and we will return to the place specified by continue. So what you're going to see here at this place, what I want here is the contract that says, I'm going to write this with a comment syntax, the contract is N contains arg, the argument. Continue is the recipient. And that's where it is. At this point, if I ever go to this place, I'm expecting this to be true, the argument for computing the Fibonacci. Now the next thing I want to do is to branch. And if N is less than 2-- by the way, I'm using what looks like Lisp syntax. This is not Lisp. This does not run . What I'm writing here does not run as a simple Lisp program. This is a representation of another language. The reason I'm using the syntax of parentheses and so on is because I tend to use a Lisp system to write an interpreter for this which allows meto simulate the machine I'm trying to build. I don't want to confuse this to think that this is Lisp code. It's just I'm using a lot of the pieces of Lisp. I'm embedding a language in Lisp, using Lisp as pieces to make my process of making my simulator easy. So I'm inheriting from Lisp all of its properties. Fetch of N 2, I want to go to a place called immediate answer. It's the base step. Now, that's somewhere over here, just above done. And we'll see it later. Now, in the general case, which is the part I'm going to write down now, let's just do it. Well, first of all, I'm going to have to call Fibonacci twice. In each case -- well, in one case at least, I'm going to have to know what to do to come back and do the next one. I have to remember, have I done the first Fib, or have I done the second one? Do I have to come back to the place where I do the second Fib, or do I have to come back to the place where I do the add? In the first case, over the first Fibonacci, I'm going to need the value of N for c omputing for the second one. So I have to store some of these things up. So first I'm going to save continue. That's who needs the answer. And the reason I'm doing that is because I'm about to assign continue to the place which is the place I want to go to after. Let's call it Fib-N-minus-1, big long name, classic Lisp name. Because I'm going to compute the first Fib of N minus 1, and then after that, I want to come back and do something else. That's the place I want to go to after I've done the first Fibonacci calculation. And I want to do a save of N, because I'm going to need it later, after that. Now I'm going to, at this point, get ready to do the Fibonacci of N minus 1. So assign to N the difference of the fetch of N and 1. Now I'm ready to go back to doing the Fib loop. Have I satisfied my contract? And the answer is yes. N contains N minus 1, which is what I need. Continue contains a place I want to go to when I'm done with calculating N minus 1. So I've satisfied the contract. And therefore, I can write down here a label, after-Fib-N- minus-1. Now what am I going to do here? Here's a place where I now have to get ready to do Fib of N minus 2. But in order to do a Fib of N minus 2, look, I don't know. I've clobbered my N over here. And presumably my N is counted down all the way to 1 or 0 or something at this point. So I don't know what the value of N in the N register is. I want the value of N that was on the stack that I saved over here so that could restore it over here. I saved up the value of N, which is this value of N at this point, so that I could restore it after computing Fib of N minus 1, so that I could count that down to N minus 2 and then compute Fib of N minus 2. So let's restore that. Restore of N. Now I'm about to do something which is superstitious, and we will remove it shortly. I am about to finish the sequence of doing the subroutine call, if you will. I'm going to say, well, I also saved up the continuation, since I'm going to restore it now. But actually, I don't have to, because I'm not going to need it. We'll fix that in a second. So we'll do a restore of continue, which is what I would in general need to do. And we're just going to see what you would call in the compiler world a peephole optimization, which says, whoops, you didn't have to do that. OK, so the next thing I see here is that I have to get ready now to do Fibonacci of N minus 2. But I don't have to save N anymore. The reason why I don't have to save N anymore is because I don't need N after I've done Fib of N minus 2, because the next thing I do is add. So I'm just going to set up my N that way. Assign N minus difference of fetch N and 2. Now I have to finish the setup for calling Fibonacci of N minus 2. Well, I have to save up continue and assign continue, continue, to the place which is after Fib N 2, that place over here somewhere. However, I've got to be very careful. The old value, thevalue of Fib of N minus 1, I'm going to need later. The value of Fibonacci of N minus 1, I'm going to need. And I can't clobber it, because I'm going to have to add it to the value of Fib of N minus 2. That's in the value register, so I'm going to save it. So I have to save this right now, save up VAL. And now I can go off to my subroutine, go to Fib loop. Now before I go any further and finish this program, I just want to look at this segment so far and see, oh yes, there's a sequence of instructions here, if you will, that I can do something about. Here I have a restore of continue, a save of continue, and then an assign of continue, with no other references to continue in between. The restore followed by the save leaves the stack unchanged. The only difference is that I set the continue register to a value, which is the value that was on the stack. Since I now clobber that value, as in it was never referenced, these instructions are unnecessary. So we will remove these. But I couldn't have seen that unless I had written them down. Was that really true? Well, I don't know. OK, so we've now gone off to compute Fibonacci of N minus 2. So after that, what are we going to do? Well, I suppose the first thing we have to do-- we've got two things. We've got a thing in the value register which is now valuable. We also have a thing on the stack that can be restored into the value register. And what I have to be careful with now is I want to shuffle this right so I can do the multiply. Now there are various conventions I might use, but I'm going to be very picky and say, I'm only going to restore into a register I've saved from. If that's the case, I have to do a shuffle here. It's the same problem with how many hands I have. So I'm going to assign to N, because I'm not going to need N anymore, N is useless, the current value of VAL, which was the value of Fib of N minus 2. And I'm going to restore the value register now. This restore matches this save. And if you're very careful and examine very carefully what goes on, restores and saves are always matched. Now there's an outstanding save, of course, that we have to get rid of soon. And so I restored the value register. Now I restore the continue one, which matches this one, dot, dot, dot, dot, dot, dot, dot, down to here, restoring that continuation. That continuation is a continuation of Fib of N, which is the problem I was trying to solve, a major problem I'm trying to solve. So that's the guy I have to go back to who wants Fib of N. I saved them all the way up here when I realized N was not less than 2. And so I had to do a complicated operation. Now I've got everything I need to do it. So I'm going to restore that, assign to VAL the sum of fetch VAL and fetch of N, and go to continue. So now I've re turned from computing Fibonacci of N, the general case. Now what's left is we have to fix up a few details, like there's the base case of this induction, immediate answer, which is nothing more than assign to VAL fetch of N, because N was less than 2, and therefore, the answer is N in our original program, and return continue-- bobble, bobble almost-- and finally Fib done. So that's a fairly complicated program. And the reason I wanted you see to that is because I want you to see the particular flavors of stack discipline that I was obeying. It was first of all, I don't want to take anything that I'm not going to need later. I was being very careful. And it's very important. And there are all sorts of other disciplines people make with frames and things like that of some sort, where you save all sorts of junk you're not going to need later and restore it because, in some sense, it's easier to do that. That's going to lead to various disasters, which we'll see a little later. It's crucial to say exactly what you're going to need later. It's an important idea. And the responsibility of that is whoever saves something is the guy who restores it, because he needs it. And in such discipline, you can see what things are unnecessary, operations that are unimportant. Now, one other thing I want to tell you about that's very simple is that, of course, the picture you see is not the whole picture. Supposing I had systems that had things like other operations, CAR, CDR, cons, building a vector and referencing the nth element of it, or things like that. Well, at this level of detail, whatever it is, we can conceptualize those as primitive operations in the datapath. In other words, we could say that some machine that, for example, has the append machine, which has to do cons of the CAR of x with the append of the CDR of x and y, well, gee, that's exactly the same as the factorial structure. Well, it's got about the same structure. And what do we have? We have some sort of things in it which may be registers, x and y, and then x has to somehow move to y sometimes, x has to get the value of y. And then we may have to be able to do something which is a cons. I don't remember if I need to like this is in this system, but cons is sort of like subtract or add or something. It combines two things, producing a thing which is the cons, which we may then think goes into there. And then maybe a thing called the CAR, which will produce-- I can get the CAR or something. And maybe I can get the CDR of something, and so on. But we shouldn't be too afraid of saying things this way, because the worst that could happen is if we open up cons, what we're going to find is some machine. And cons may in fact overlap with CAR and CDR, and it always does, in the same way that plus and minus overlap, and really the same business. Cons, CAR, and CDR are going to overlap, and we're going to find a little controller, a little datapath, which may have some registers in it, some stuff like that. And maybe inside it, there may also be an infinite part, a part that's semi- infinite or something, which is a lot of very uniform stuff, which we'll call memory. And I wouldn't be so horrified if that were the way it works. In fact, it does, and we'll talk about that later. So are there any questions? Gee, what an unquestioning audience. Suppose I tell you a horrible pile of lies. OK. Well, thank you. Let's take our break. [MUSIC PLAYING - "JESU, JOY OF MAN'S DESIRING" BY JOHANN SEBASTIAN BACH] MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed thismaterial in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Sub/lec9b.txt ================================================ MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Transcript – 9B: Explicit-control Evaluator PROFESSOR: Well, I hope you appreciate that we have inducted you into some real magic, the magic of building languages, really building new languages. What have we looked at? We've looked at an Escher picture language: this language invented by Peter Hende rson. We looked at digital logic language. Let's see. We've looked at the query language. And the thing you should realize is, even though these were toy examples, they really are the kernels of really useful things. So, for instance, the Escher picturelanguage was taken by Henry Wu, who's a student at MIT, and developed into a real language for laying out PC boards based just on extending those structures. And the digital logic language, Jerry mentioned when he showed it to you, was really extended to be used as the basis for a simulator that was used to design a real computer. And the query language, of course, is kind of the germ of prologue. So we built all of these languages, they're all based on LISP. A lot of people ask what particular problems is LISP good for solving for? The answer is LISP is not good for solving any particular problems. What LISP is good for is constructing within it the right language to solve the problems you want to solve, and that's how you should think about it. So all of these languages were based on LISP. Now, what's LISP based on? Where's that come from? Well, we looked at that too. We looked at the meta-circular evaluator and said well, LISP is based on LISP. And when we start looking at that, we've got to do some re al magic, right? So what does that mean, right? Why operators, and fixed points, and the idea that what this means is that LISP is somehow the fixed-point equation for this funny set of things which are defined in terms of themselves. Now, it's real magic. Well, today, for a final piece of magic, we're going to make all the magic go away. We already know how to do that. The idea is, we're going to take the register machine architecture and show how to implement LISP on terms of that. And, remember, the id ea of the register machine is that there's a fixed and finite part of the machine. There's a finit- state controller, which does some particular thing with a particular amount of hardware. There are particular data paths: the operation the machine does. And then, in order to implement recursion and sustain the illusion of infinity, there's some large amount of memory, which is the stack. So, if we implement LISP in terms of a register machine, then everything ought to become, at this point, completely concrete. All the magic should go away. And, by the end of this talk, I want you get the feeling that, as opposed to this very mysterious meta -circular evaluator, that a LISP evaluator really is something that's concrete enough that you can hold in the palm of your hand. You should be able to imagine holding a LISP interpreter there. All right, how are we going to do this? We already have all the ingredients. See, what you learned last time from Jerry is how to take any particular couple of LISP procedures and hand-translate them into something that runs on a register machine. So, to implement all of LISP on a register machine, all we have to do is take the particular procedures that are the meta-circular evaluator and hand-translate them for a register machine. And that does all of LISP, right? So, in principle, we already know how to do this. And, indeed, it's going to be no different, in kind, from translating, say, recursive factorial or recursive Fibonacci. It's just bigger and there's more of it. So it'd just be more details, but nothing really conceptually new. All right, also, when we've done that, and the thing is completely explicit, and we see how to implement LISP in terms of the actual sequential register operations, that's going to be our final most explicit model of LISP in this course. And, remember, that's a progression through this course. We started out with substitution, which is sort of like algebra. And then we went to the environment model, which talked about the actual frames and how th ey got linked together. And then we made that more concrete in the meta-circular evaluator. There are things the meta-circular evaluator doesn't tell us. You should realize that. For instance, it left unanswered the question of how a procedure, like recu rsive factorial here , somehow takes space that grows. On the other hand, a procedure which also looks syntactically recursive, called fact-iter, somehow doesn't take space. We justify that it doesn't need to take space by showing the substitution model. But we didn't really say how it happens that the machine manages to do that, that that has to do with the details of how arguments are passed to procedures. And that's the thing we didn't see in the meta -circular evaluator precisely because the way arguments got passed to procedures in this LISP depended on the way arguments got passed to procedures in this LISP. But, now, that's going to become extremely explicit. OK. Well, before going on to the evaluator, let me just give you a sense of what a whole LISP system looks like so you can see the parts we're going to talk about and the parts we're not going to talk about. Let's see, over here is a happy LISP user, and the LISP user is talking to something called the reader. The reader's job in life is to take characters from the user and turn them into data structures in something called a list structure memory. All right, so the reader is going to take symbols, parentheses, and A's and B's, and ones and threes that you type in, and turn these into actual lis t structure: pairs, and pointers, and things. And so, by the time evaluator is going, there are no characters in the world. And, of course, in more modern list systems, there's sort of a big morass here that might sit between the user and the reader: Windows systems, and top levels, and mice, and all kinds of things. But conceptually, characters are coming in. All right, the reader transforms these into pointers to stuff in this memory, and that's what the evaluator sees, OK? The evaluator has a bunch of helpers. It has all possible primitive operators you might want. So there's a completely separate box, a floating point unit, or all sorts of things, which do the primitive operators. And, if you want more special primitives, you build more primitive operators, but they're separate from the evaluator. The evaluator finally gets an answer and communicates that to the printer. And now, the printer's job in life is to take this list structure coming from the evaluator, and turn it back into characters, and communicate them to the user through whatever interface there is. OK. Well, today, what we're going to talk about is this evaluator. The primitive operators have nothing particular to do with LISP, they're however you like to implement primitive operations. The reader and printer are actually complicated, but we're not going to talk about them. They sort of have to do with details of how you might build up list structure from characters. So that is a long story, but we're not going to talk about it. The list structure memory, we'll talk about next time. So, pretty much, except for the details of reading and printing, the only mystery that's going to be left after you see the evaluator is how you build list structure on conventional memories. But we'll worry about that next time too. OK. Well, let's start talking about the evaluator. The one that we're going to sho w you, of course, is not, I think, nothing special about it. It's just a particular register machine that runs LISP. And it has seven registers, and here are the seven registers. There's a register, called EXP, and its job is to hold the expression to be evaluated. And by that, I mean it's going to hold a pointer to someplace in list structure memory that holds the expression to be evaluated. There's a register, called ENV, which holds the environment in which this expression is to be evaluated. And, again, I made a pointer. The environment is some data structure. There's a register, called FUN, which will hold the procedure to be applied when you go to apply a procedure. A register, called ARGL, which wants the list of evaluated arguments. What you can start seeing here is the basic structure of the evaluator. Remember how evaluators work. There's a piece that takes expressions and environments, and there's a piece that takes functions, or procedures and arguments. And going back and forth around here is the eval/apply loop. So those are the basic pieces of the eval and apply. Then there's some other things, there's continue. You just saw before how the continue register is used to implement recursion and stack discipline. There's a register that's goin g to hold the result of some evaluation. And then, besides that, there's one temporary register, called UNEV, which typically, in the evaluator, is going to be used to hold temporary pieces of the expression you're working on, which you haven't gotten arou nd to evaluate yet, right? So there's my machine: a seven-register machine. And, of course, you might want to make a machine with a lot more registers to get better performance, but this is just a tiny, minimal one. Well, how about the data paths? This machine has a lot of special operations for LISP. So, here are some typical data paths. A typical one might be, oh, assign to the VAL register the contents of the EXP register. In terms of those diagrams you saw, that's a little button on some arrow. Here's a more complicated one. It says branch, if the thing in the expression register is a conditional to some label here, called the ev -conditional. And you can imagine this implemented in a lot of different ways. You might imagine this conditional test as a special purpose sub-routine, and conditional might be represented as some data abstraction that you don't care about at this level of detail. So that might be done as a sub-routine. This might be a machine with hardware-types, and conditional might be testing some bits for a particular code. There are all sorts of ways that's beneath the level of abstraction we're looking at. Another kind of operation, and there are a lot of different operations assigned to EXP, the first clause of what's in EXP. This might be part of processing a conditional. And, again, first clause is some selector whose details we don't care about. And you can, again, imagine that as a sub-routine which'll do some list operations, or you can imagine that as something that's built directly into hardware. The reason I keep saying you can imagine it built directly into hardware is even though there are a lot of operations, there are still a fixed number of them. I forget how many, maybe 150. So, it's plausible to think of building these d irectly into hardware. Here's a more complicated one. You can see this has to do with looking up the values of variables. It says assign to the VAL register the result of looking up the variable value of some particular expression, which, in this case, is supposed to be a variable in some environment. And this'll be some operation that searches through the environment structure, however it is represented, and goes and looks up that variable. And, again, that's below the level of detail that we're thinking about. This has to do with the details of the data structures for representing environments. But, anyway, there is this fixed and finite number of operations in the register machine. Well, what's its overall structure? Those are some typical operations.Remember what we have to do, we have to take the meta-circular evaluator-- and here's a piece of the meta- circular evaluator. This is the one using abstract syntax that's in the book. It's a little bit different from the one that Jerry shows you. And themain thing to remember about the evaluator is that it's doing some sort of case analysis on the kinds of expressions: so if it's either self-evaluated, or quoted, or whatever else. And then, in the general case where the expression it's looking at is an application, there's some tricky recursions going on. First of all, eval has to call itself both to evaluate the operator and to evaluate all the operands. So there's this sort of red recursion of values walking down the tree that's really the easy recursion. That's just a val walking down this tree of expressions. Then, in the evaluator, there's a hard recursion. There's the red to green. Eval calls apply. That's the case where evaluating a procedure or argument reduces to applying the procedure to the list of arguments. And then, apply comes over here. Apply takes a procedure and arguments and, in the general case where there's a compound procedure, apply goes around and green calls red. Apply comes around and calls eval again. Eval's the body of the procedure in the result of extending the environment with the parameters of the procedure by binding the arguments. Except in the primitive case, where it just calls something else primitive -apply, which is not really the business of the evaluator. So this sort of red to green, to red to green, that's the eval/apply loop, and that's the thing that we're going to want to see in the evaluator. All right. Well, it won't surprise you at all that the two big pieces of this evaluator correspond to eval and apply. There's a piece called eval-dispatch, and a piece called apply- dispatch. And, before we get into the details of the code, the way to understand this is to think, again, in terms of these pieces of the evaluator having contracts with the rest of the world. What do they do from the outside before getting into the grungy details? Well, the contract for eval-dispatch-- remember, it corresponds to eval. It's got to evaluate an expression in an environment. So, in particular, what this one is going to do, eval - dispatch will assume that, when you call it, that the expression you want to evaluate is in the EXP register. The environment in which you want the evaluation to take place is in the ENV register. And continue tells you the place where the machine should go next when the evaluation is done. Eval-dispatch's contract is that it'll actually perform that evaluation, and, at the end of which, it'll end up at the place specified by continue. The result of the evaluation will be in the VAL register. And it just warns you, it makes no promises about what happens to the registers. All other registers might be destroyed. So, there's one piece, OK? Together, the pieces, apply-dispatch that corresponds to apply, it's got to apply a procedure to some arguments, so it assumes that this register, ARGL, contains a list of the evaluated arguments. FUN contains the procedure. Those correspond to the arguments to the apply procedure in the meta-circular evaluator. And apply, in this particular evaluator, we're going to use a discipline which says the place the machine should go to next when apply is done is, at the moment apply-dispatch is called at the top of the stack, that's just discipline for the way this particular machine's organized. And now apply's contract is given all that. It'll perform the application. The result of that application will end up in VAL. The stack will be popped. And, again, the contents of all the other registers may be destroyed, all right? So that's the basic organization of this machine. Let's break for a little bit and see if there are any questions, and then we'll do a real example. Well, let's take the register machine now, and actually step through, and really, in real detail, so you see completely concrete how some expressions are evaluated, all right? So, let's start with a very simple expression. Let's evaluate the expression 1. And we need an environment, so let's imagine that somewhere there's an environment, we'll call it E,0. And just, since we'll use these later, we obviously don't really need anything to evaluate 1. But, just for reference later, let's assume that E,0 has in it an X that's bound to 3 and a Y that's bound to 4, OK? And now what we're going to do is we're going to evaluate 1 in this environment, and so the ENV register has a pointer to this environment, E,0, all right? So let's watch that thing go. What I'm going to do is step through the code. And, let's see, I'll be the controller. And now what I need, since this gets rather complicated, is a very little execution unit. So here's the execution unit, OK? OK. OK. All right, now we're goin g to start. We're going to start the machine at eval-dispatch, right? That's the beginning of this. Eval-dispatch is going to look at the expression in dispatch, just like eval where we look at the very first thing. We branch on whether or not this expression is self-evaluating. Self-evaluating is some abstraction we put into the machine-- it's going to be true for numbers-- to a place called ev-self-eval, right? So me, being the controller, looks at ev-self-eval, so we'll go over to there. Ev-self-eval says fine, assign to val whatever is in the expression unit, OK? And I have a bug because what I didn't do when I initialized this machine is also say what's supposed to happen when it's done, so I should have started out the machine with done being in the continue register, OK? So we assign to VAL. And now go to fetch of continue, and now change -- OK. OK, let's try something harder. Let's reset the machine here, and we'll put in the expression register, X, OK? Start again at eval-dispatch. Check, is it self-evaluating? No. Is it a variable? Yes. We go off to ev-variable. It says assign to VAL, look up the variable value in the expression register, OK? Go to fetch of continue. PROFESSOR: Done. PROFESSOR: OK. All right. Well, that's the basic idea. That's a simple operation of the machine. Now, let's actually do something a little bit more interesting. Let's look at the expression the sum of x and y. OK. And now we'll see how you start unrolling these expression trees, OK? Well, start again at eval-dispatch, all right? Self-evaluating? No. Variable? No. All the other special forms which I didn't write down, like quote, and lambda, and set, and whatever, it's none of those. It turns out to be an application, so we go off to ev-application, OK? Ev- application, remember what it's going to do overall. It is going to evaluate the operator. It's going to evaluate the arguments, and then it's going to go apply them. So, before we start, since we're being very literal, we'd better remember that, somewhere in thisenvironment, it's linked to another environment in which plus is bound to the primitive procedure plus before we get an unknown variable in our machine. OK, so we're at ev-application. OK, assign to UNEV the operands of what's in the expression register, OK? Those are the operands. UNEV's a temporary register where we're going to save them. PROFESSOR: I'm assigning. PROFESSOR: Assign to x the operator. Now, notice we've destroyed that expression in x, but the piece that we need is now in UNEV. OK. Now, we're going to get set up to recursively evaluate the operator. Save the continue register on the stack. Save the environment. Save UNEV. OK, assign to continue a label called eval -args. Now, what have we done? We've set up for a recursive call. We're about to go to eval- dispatch. We've set up for a recursive call to eval-dispatch. What did we do? We took the things we're going to need later, those operands that were in UNEV; the environme nt in which we're going to eventually have to, maybe, evaluate those operands; the place we eventually want to go to, which, in this case, was done; we've saved them on the stack. The reason we saved them on the stack is because eval-dispatch makes no promises about what registers it may destroy. So all that stuff is saved on the stack. Now, we've set up eval-dispatch's contract. There's a new expression, which is the operator plus; a new environment, although, in this case, it's the same one; and a new p lace to go to when you're done, which is eval-args. So that's set up. Now, we're going to go off to eval- dispatch. Here we are back at eval-dispatch. It's not self-evaluating. Oh, it's a variable, so we'd better go off to ev-variable, right? Ev-variable is assigned to VAL. Look up the variable value of the expression, OK? So VAL is the primitive procedure plus, OK? And go to fetch of continue. PROFESSOR: Eval-args. PROFESSOR: Right, which is now eval-args not done. So we come back here at eval-args, and what do we do? We're going to restore the stuff that we saved, so we restore UNEV. And notice, there, it wasn't necessary, although, in general, it would be. It might be some arbitrary evaluation that happened. We restore ENV. OK, we assign to FUN fetch o f VAL. OK, now, we're going to go off and start evaluating some arguments. Well, first thing we'd better do is save FUN because some arbitrary stuff might happen in that evaluation. We initialize the argument list. Assign to argl an empty argument list, and go to eval-arg-loop, OK? At eval-arg-loop, the idea of this is we're going to evaluate the pieces of the expressions that are in UNEV, one by one, and move them from unevaluated in UNEV to evaluated in the arg list, OK? So we save argl. We assign to x the first operand of the stuff in UNEV. Now, we check and see if that was the last operand. In this case, it is not, all right? So we save the environment. We save UNEV because those are all things we might need later. We're going to need the environment to do some more evaluations. We're going to need UNEV to look at what the rest of those arguments were. We're going to assign continue a place called accumulate-args, or accumulate-arg. OK, now, we've set up for another call to eval-dispatch, OK? All right, now, let me short- circuit this so we don't go through the details of eval-dispatch. Eval-dispatch's contract says I'm going to end up, the world will end up, with the value of evaluating this expression in this environment in the VAL register, and I'll end up there. So we short-circuit all of this, and a 3 ends up in VAL. And, when we return from eval -dispatch, we're going to return to accumulate-arg. PROFESSOR: Accumulate-arg. PROFESSOR: With 3 in the VAL register, OK? So that short-circuited that evaluation. Now, what do we do? We're going to go back and look at the rest of the arguments, so we restore UNEV. We restore ENV. We restore argl. One thing. PROFESSOR: Oops! Parity error. [LAUGHTER] PROFESSOR: Restore argl. PROFESSOR: OK. OK, we assign to argl consing on fetch of the value register to what's in argl. OK, we assign to UNEV the rest of the operands in fetch of UNEV, and we go back to eval-arg-loop. PROFESSOR: Eval-arg-loop. PROFESSOR: OK. Now, we're about to do the next argument, so the first thing we do is save argl. OK, we assign to x the first operand of fetch of UNEV. OK, we test and see if that's the last operand. In this case, it is, so we're going to go to a special pl ace that says evaluate the last argument because, notice, after evaluating the argument, we don't need the environment any more. That's going to be the difference. So here, at eval-last-arg, which is assigned to accumulate-last-arg, now, we're set up again for eval-dispatch. We've got a place to go to when we're done. We've got an expression. We've got an environment. OK, so we'll short-circuit the call to eval-dispatch. And what'll happen is there's a y there, it's 4 in that environment, so VAL will endup with 4 in it. And, then, we're going to end up at accumulate-last-arg, OK? So, at accumulate-last-arg, we restore argl. We assign to argl cons of fetch of the new value onto it, so we cons a 4 onto that. We restore what was saved in the function register. And notice, in this case, it had not been destroyed, but, in general, it will be. And now, we're ready to go off to apply-dispatch, all right? So we've just gone through the eval. We evaluated the argument, the operator, and the arguments, and now, we're about to apply them. So we come off to apply-dispatch here, OK? We come off to apply-dispatch, and we're going to check whether it's a primitive or a compound procedure. PROFESSOR: Yes. PROFESSOR: All right. So, in this case, it's a primitive procedure, and we go off to primitive- apply. So we go off to primitive-apply, and it says assign to VAL the result of applying primitive procedure of the function to the argument list. PROFESSOR: I don't know how to add. I'm just an execution unit. PROFESSOR: Well, I don't know how to add either. I'm just the evaluator, so we need a primitive operator. Let's see, so the primitive operator, what's the sum of 3 and 4? AUDIENCE: 7. PROFESSOR: OK, 7. PROFESSOR: Thank you. PROFESSOR: Now, we restore continue, and we go to fetch of continue. PROFESSOR: Done. PROFESSOR: OK. Well, that was in as much detail as you will ever see. We'll never do it in as much detail again. One very important thing to notice is that we just executed a recursive procedure, right? This whole thing, we used a stack and the evaluator was recursive. A lot of people think the reason that you need a stack and recursion in an evaluator is because you might be evaluating recursive procedures like factorial or Fibonacci. It's not true. So you notice we did recursion here, and all we evaluated was plus X, Y, all right? The reason that you need recursion in the evaluator is because the evaluation process, itself, is recursive, all right? It's not because the procedure that you might be evaluating in LISP is a recursive procedure. So that's an important thing that people get confused about a lot. The other thing to notice is that, when we're done here, we're really done. Not only are we at done, but there's no accumulated stuff on the stack, right? The machine is back to its initial state, all right? So that's part of what it means to be done. Another way to say that is the evaluation process has reduced the expression, plus X, Y, to the value here, 7. And by reduced, I mean a very particular thing. It means that there's nothing left on the stack. The machine is now in the same state, except there's something in the value register. It's not part of a sub-problem of anything. There's nothing to go back to. OK. Let's break. Question? AUDIENCE: The question here, in the stack, is because the data may be recursive. You may have embedded expressions, for instance. PROFESSOR: Yes, because you might have embedded expressions. But, again, don't confuse that with what people sometimes mean by the data may be recursive, which is to say you have these list-structured, recursive data list operations. That has nothing to do with it. It's simply that the expressions contain sub-expressions. Yeah? AUDIENCE: Why is it that the order of the arguments in the arg list got reversed? PROFESSOR: Ah! Yes, I should've mentioned that. Here, the reason the order is reversed-- it's a question of what you mean by reversed. I believe it was Newton. In the very early part of optics, people realized that, when you look through the lens of your eye, the image was up-side down. And there was a lot of argument about why that didn't mean you saw things up-side down. So it's sort of the same issue. Reversed from what? So we just need some convention. The reason that they're coming at 4, 3 is because we're taking UNEV and consing the result onto argl. So you have to realize you've made that convention. The place that you have to realize that-- well, there's actually two places. One is in apply - primitive-operator, which has to realize that the arguments to primitives go in, in the opposite order from the way you're writing them down. And the other one is, we'll see later when you actually go to bind a function's parameters, you should realize the arguments are going to come in from the opposite order of the variables to which you're binding them. So, if you just keep track of that, there's no problem. Also, this is completely arbitrary because, if we'd done, say, an iteration through a vector assigning them, they might come out in the other order, OK? So it's just a convention of the way this particular evaluator works. All right, let's take a break. We just saw evaluating an expression and, of course, that was very simple one. But, in essence, it would be no different if it was some big nested expression, so there would just be deeper recursion on the stack. But what I want to do now is show you the last piece. I want to walk you around this eval and apply loop, right? That's the thing we haven't seen, really. We haven't seen any compound procedures where applying a procedure reduces to evaluating the body of the procedure, so let's just suppose we had this. Suppose we were looking at the procedure define F of A and B to be the sum of A and B. So, as we typed in that procedure previously, and now we're going to evaluate F of X and Y, again, in this environment, E,0, where X is bound to 3 and Y is bound to 4. When the defined is executed, remember, there's a lambda here, and lambdas create procedures. And, basically, what will happen is, in E,0, we'll end up with a binding for F, which will say F is a procedure, and its args are A and B, and its body is plus a,b. So that's what the environment would have looked like had we made that definition. Then, when we go to evaluate F of X and Y, we'll go through exactly the same process that we did before. It's even the same expression. The only difference is that F, instead of having primitive plus in it, will have this thing. And so we'll go through exactly the same process, except this time, when we end up at apply-dispatch, the function register, instead of having primitive plus, will have a thing that will represent it saying procedure, where the args are A and B, and the body is plus A, B. And, again, what I mean, by its ENV, I mean there's a pointer to it, so don't worry that I'm writing a lot of stuff there. There's a pointer to this procedure data structure. OK, so, we're in exactly the same situation. We get to apply-dispatch, so, here, we come to apply-dispatch. Last time, we branched off to a primitive procedure. Here, it says oh, we now have a compound procedure, so we're going to go off to compound-apply. Now, what's compound-apply? Well, remember what the meta-circular evaluator did? Compound-apply said we're going to evaluate the body of the procedure in some new environment. Where does that new environment come from? We take the environment that was packaged with the procedure, we bind the parameters of the procedure to the arguments that we're passing in, and use that as a new frame to extend the procedure environment. And that's the environment in which we evaluate the procedure body, right? That's going around the apply/eval loop. That's apply coming back to call eval, all right? OK. So, now, that's all we have to do in compound-apply. What are we going to do? We're going to manufacture a new environment. And we're going to manufacture a new environment, let's see, that we'll call E,1. E,1 is going to be some environment where the parameters of the procedure, where A is bound to 3 and B is bound to 4, and it's linked to E,0 because that's where f is defined. And, in this environment, we're going to evaluate the body of the procedure. So let's look at that, all right? All right, here we are at compound-apply, which says assign to the expression register the body of the procedure that's in the function register. So I assign to the expression register the procedure body, OK? That's going to be evaluated in an environment which is formed by making some bindings using information determined by the procedure-- that's what's in FUN-- and the argument list. And let's not worry about exactly what that does, but you can see the information's there. So make bindings will say oh, the procedure, itself, had an environme nt attached to it. I didn't write that quite here. I should've said in environment because every procedure gets built with an environment. So, from that environment, it knows what the procedure's definition environment is. It knows what the arguments are. It looks at argl, and then you see a reversal convention here. It just has to know that argl is reversed, and it builds this frame, E,1. All right, so, let's assume that that's what make bindings returns, so it assigns to ENV this thing, E,1. All right, the next thing it says is restore continue. Remember what continue was here? It got put up in the last segment. Continue got stored. That was the original done, which said what are you going to do after you're done with this particular application? It was one of the very first things that happened when we evaluated the application. And now, finally, we're going to restore continue. Remember apply-dispatch's contract. It assumes that where it should go to next was on the stack, and there it was on the stack. Continue has done, and now we're going to go back to eval-dispatch. We're set up again. We have an expression, an environment, and a place to go to. We're not going to go through that because it's sort of the same expression. OK, but the thing, again, to notice is, at this point, we have reduced the original expression, F,X,Y, right? We've reduced evaluating F,X,Y in environment E,0 to evaluate plus A, B in E,1. And notice, nothing's on the stack, right? It's a reduction. At this point, the machine does not contain, as part of its state, the fact that it's in the middle of evaluat ing some procedure called f, that's gone, right? There's no accumulated state, OK? Again, that's a very important idea. That's the meaning of, when we used to write in the substitution model, this expression reduces to that expression. And you don't have to remember anything. And here, you see the meaning of reduction. At this point, there is nothing on the stack. See, that has very important consequences. Let's go back and look at iterative factorial, all right? Remember, this was some sort of loop and doing iter. And we kept saying that's an iterative procedure, right? And what we wrote, remember, are things like, we said, fact-iter of 5. We wrote things like reduces to iter of 1, and 1, and 5, which reduces to iter of 1, and 2, and 5, and so on, and so on, and so on. And we kept saying well, look, you don't have to build up any storage to do that. And we waved our hands, and said in principle, there's no storage needed. Now, you see no storage needed. Each of these is a real reduction, right? As you walk through these expressions, what you'll see are these expressions on the stack in some particular environment, and then these expressions in the EXP register in some particular environment. And, at each point, there'll be no accumulated stuff on the stack because each one's a real reduction, OK? All right, so, for example, just to go through it in a little bit more care, if I start out with an expression that says something like, oh, say, fact-iter of 5 in some environment that will, at some point, create an environment in which n is down to 5. Let's call that -- And, at some point, the machine will reduce this whole thing to a thing that says that's really iter of 1, and 1, and n, evaluated in this environment, E,1 with nothing on the stack. See, at th is moment, the machine is not remembering that evaluating this expression, iter -- which is the loop-- is part of this thing called iterative factorial. It's not remembering that. It's just reducing the expression to that, right? If we look again at the body of iterative factorial, this expression has reduced to that expression. Oh, I shouldn't have the n there. It's a slightly different convention from the slide to the program, OK? And, then, what's the body of iter? Well, iter's going to be an it, and I won't go through the details of if. It'll evaluate the predicate. In this case, it'll be false. And this iter will now reduce to the expression iter of whatever it says, star, counter product, and-- what does it say-- plus counter 1 in some other environment, by this time, E,2, where E,2 will be set up having bindings for product and counter, right? And it'll reduce to that, right? It won't be remembering that it's part of something that it has to return to. And when iter calls iter again, it'll reduce to another thing that looks like this in some environment, E,3, which has new bindings for product and counter. So, if you're wondering, see, if you've always been queasy about how it is we've been saying those procedures, that look syntactically recursive, are, in fact, iterative, run in constant space, well, I don't know if this makes you less queasy, but at least it shows you what's happening. There really isn't any buildup there. Now, you might ask well, is there buildup in principle in these environment frames? And the answer is yeah, you have to make these new environment frames, but you don't have to hang onto them when you're done. They can be garbage collected, or the space can be reused automatically. But you see the control structure of the evaluator is really using this idea that you actually have a reduction, so these procedures really are iterative procedures. All right, let's stop for questions. All right, let's break. Let me contrast the iterative procedure just so you'll see where space doesbuild up with a recursive procedure, so you can see the difference. Let's look at the evaluation of recursive factorial, all right? So, here's fact-recursive, or standard factorial definition. We said this one is still a recursive procedure, but this is actually a recursive process. And then, just to link it back to the way we started, we said oh, you can see that it's going to be recursive process by the substitution model because, if I say recursive factorial of 5, that turns into 5 times-- what is it, fact-rec, or record fact-- 5 times recursive factorial of 4, which turns into 5 times 4 times fact-rec of 3, which returns into 5 times 4 times 3 times, and so on, right? The idea is there was this chain of stuff building up, which justified, in the substitution model, the fact that it's recursive. And now, let's actually see that chain of stuff build up and where it is in the machine, OK? All right, well, let's imagine we're going to start out again. We'll tell it to evaluate recursive factorial of 5 in some environment, again, E,0 where recursive factorial is defined, OK? Well, now we know what's eventually going to happen. This is going to come along, it'll evaluate those things, figure out it's a procedure, build somewhere over here an environment, E,1 , which has n bound to 5, which hangs off of E,0, which would be, presumably, the definition environment of recursive factorial, OK? And, in this environment, it's going to go off and evaluate the body. So, again, the evaluation here will reduce to evaluating the body in E,1. That's going to look at an if, and I won't go through the details of if. It'll look at the predicate. It'll decide it eventually has to evaluate the alternative. So this whole thing, again, will reduce to the alternative of recursive factorial, the alternative clause, which says that this whole thing reduces to times n of recursive factorial of n minus 1 in the environment E,1, OK? So the original expression, now, is going to reduce to evaluating that expression, all right? Now we have an application. We did an application before. Remember what happens in an application? The first thing you do is you go off and you save the value of the continue register on the stack. So the stack here is going to have done in it. And then you're goi ng to set up to evaluate the sub-parts, OK? So here we go off to evaluate the sub-parts. First thing we're going to do is evaluate the operator. What happens when we evaluate an operator? Well, we arrange things so that the operator ends up in the expression register. The environments in the ENV register continue someplace where we're going to go evaluate the arguments. And, on the stack, we've saved the original continue, which is where we wanted to be when we're all done. And then the things we needed when we're going to get done evaluating the operator, the things we'll need to evaluate the arguments, namely, the environment and those arguments, those unevaluated arguments, so there they are sitting on the stack. And we're about to go off to evaluate the operator. Well, when we return from this particular call-- so we're about to call eval-dispatch here-- when we return from this call, the value of that operator, which, in this case, is going to be the primitive multiplier procedure, will end up in the FUN register,all right? We're going to evaluate some arguments. They will evaluate in here. That'll give us 5, in this case. We're going to put that in the argl register, and then we'll go off to evaluate the second operand. So, at the point where we go off to evaluate the second operand-- and I'll skip details like computing, and minus 1, and all of that-- but, when we go off to evaluate the second operand, that will eventually reduce to another call to fact-recursive. And, what we've got on the stack here is the operator from that combination that we're going to use it in and the other argument, OK? So, now, we're set up for another call to recursive factorial. And, when we're done with this one, we're going to go to accumulate the last arg. And remember what that'll do? That'll say oh, whatever the result of this has to get combined with that, and we're going to multiply them. But, notice now, we're at another recursive factorial. We're about to call eval-dispatch again, except we haven't really reduced it becausethere's stuff on the stack now. The stuff on the stack says oh, when you get back, you'd better multiply it by the 5 you had hanging there. So, when we go off to make another call, we evaluate the n minus 1. That gives us another environment in which the new n's going to be down to 4. And we're about to call eval-dispatch again, right? We get another call. That 4 is going to end up in the same situation. We'll end up with another call to fact-recursive n. And sitting on the stack will be the stuff from the original one and, now, the subsidiary one we're doing. And both of them are waiting for the same thing. They're going to go to accumulate a last argument. And then, of course, when we go to the fourth call, the same thing happens, right? And this goes on, and on, and on. And what you see here on the stack, exactly what's sitting here on the stack, the thing that says times and 5. And what you're going to do with that is accumulate that into a last argument. That's exactly this, right? This is exactly where that stuff is hanging. Effectively, the operator you're going to apply, the other argument that it's got to be multiplied by when you get back and the parentheses, which says yeah, what you wanted to do was accumulate them. So, you see, the substituti on model is not such a lie. That really is, in some sense, what's sitting right on the stack. OK. All right, so that, in some sense, should explain for you, or at least convince you, that, somehow, this evaluator is managing to take these procedures andexecute some of them iteratively and some of them recursively, even though, as syntactically, they look like recursive procedures. How's it managing to do that? Well, the basic reason it's managing to do that is the evaluator is set up to save only what it needs later. So, for example, at the point where you've reduced evaluating an expression and an environment to applying a procedure to some arguments, it doesn't need that original environment anymore because any environment stuff will be packaged inside the procedures where the application's going to happen. All right, similarly, when you're going along evaluating an argument list, when you've finished evaluating the list, when you're finished evaluating the last argument, you don't need that argument l ist any more, right? And you don't need the environment where those arguments would be evaluated, OK? So the basic reason that this interpreter is being so smart is that it's not being smart at all, it's being stupid. It's just saying I'm only going to save what I really need. Well, let me show you here. Here's the actual thing that's making a tail recursive. Remember, it's the restore of continue. It's saying when I go off to evaluate the procedure body, I should tell eval to come back to the place where that original evaluation was supposed to come back to. So, in some sense, you want to say what's the actual line that makes a tail recursive? It's that one. If I wanted to build a non-tail recursive evaluator, for some strange reason, all I would need to do is, instead of restoring continue at this point, I'd set up a label down here called, "Where to come back after you've finished applying the procedure." Instead, I'd set continue to that. I'd go to eval-dispatch, and then eval-dispatch would come back here. At that point, I would restore continue and go to the original one. So here, the only consequence of that would be to make it non-tail recursive. It would give you exactly the same answers, except, if you did that iterative factorial and all those i terative procedures, it would execute recursively. Well, I lied to you a little bit, but just a little bit, because I showed you a slightly over - simplified evaluator where it assumes that each procedure body has only one expression. Remember, in general, a procedure has a sequence of expressions in it. So there's nothing really conceptually new. Let me just show you the actual evaluator that handles sequences of expressions. This is compound-apply now, and the only difference from the old one is that, instead of going off to eval directly, it takes the whole body of the procedure, which, in this case, is a sequence of expressions, and goes off to eval-sequence. And eval-sequence is a little loop that, basically, does these evaluations one at a time. So it does an evaluation. Says oh, when I come back, I'd better come back here to do the next one. And, when I'm all done, when I want to get the last expression, I just restore my continue and go off to eval - dispatch. And, again, if you wanted for some reason to break tail recursion in this evaluator, all you need to do is not handle the last expression, especially. Just say, after you've done the last expression, come back to some other place after which you restore continue. And, for some reason, a lot of LISP evaluators tended to work that way. And the only consequence of that is that iterative procedures built up stack. And it's not clear why that happened. All right. Well, let me just sort of summarize, since this is a lot of details in a big program. But the main point is that it's no different, conceptually, from translating any other program. And the main idea is that we have this universal evaluator program, the meta- circular evaluator. If we translate that into LISP, then we have all of LISP. And that's all we did, OK? The second point is that the magic's gone away. There should be no more magic in this whole system, right? In principle, it should all be very clear except, maybe, for how list structured memory works, and we'll see that later. But that's not very hard. The third point is that all this tail recursion came from the discipline of eval being very careful to save only what it needs next time. It's not some arbitrary thing where we're saying well, whenever we call a sub-routine, we'll save all the registers in the world and come back, right? See, sometimes it pays to really worry about efficiency. And, when you're down in the guts of your evaluator machine, it really pays to think about things like that because it makes big consequences. Well, I hope what this has done is really made the evaluator seem concrete, right? I hope you really believe that somebody could hold a LISP evaluator in the palm of their hand. Maybe to help you believe that, here's a LISP evaluator that I'm holding the palm of my hand, right? And this is a chip which is actually quite a bit more complicated than the evaluator I showed you. Maybe, here's a better picture of it. What there is, is you can see the same overall structure. This is a register array. These are the data paths. Here'sa finite state controller. And again, finite state, that's all there is. And somewhere there's external memory that'll worry about things. And this particular one is very complicated because it's trying to run LISP fast. And it has some very, very fast parallel operations in there like, if you want to index into an array, simultaneously check that the index is an integer, check that it doesn't exceed the array bands, and go off and do the memory access, and do all those things simultaneously. And then, later, if they're all OK, actually get the value there. So there are a lot of complicated operations in these data paths for making LISP run in parallel. It's a completely non -risk philosophy of evaluating LISP. And then, this microcode is pretty complicated. Let's see, there's what? There's about 389 instructions of 220-bit microcode sitting here because these are very complicated data paths. And the whole thing has about 89,000 transistors, OK? OK. Well, I hope that that takes away a lot of the mystery. Maybe somebody wants to look at this. Yeah. OK. Let's stop. Questions? AUDIENCE: OK, now, it sounds like what you're saying is that, with the restore continue put in the proper place, that procedures that would invoke a recursive process now invoke an integer process just by the way that the eval signature is? PROFESSOR: I think the way I'd prefer to put it is that, with restore continue put in the wrong place, you can cause any syntactically-looking recursive procedure, in fact, to build up stack as it runs. But there's no reason for that, so you might want to play around with it. You can just switch around two or three instructions in the way compound -apply comes back, and you'll get something which isn't tail recursive. But the thing I wanted to emphasize is there's no magic. It's not as if there's some very clever pre-processing program that's looking at this procedure, factorial iter, and say oh, gee, I really notice that I don't have to push stack in order to do this. Some people think that that's what's going on. It's something much, much more dumb than that, it's this one place you're putting the restore instruction. It's just automatic. AUDIENCE: OK. AUDIENCE: But that's not affecting the time complexity is it? PROFESSOR: No. AUDIENCE: It's just that it's handling it recursively instead of iteratively. But, in terms of the order of time it takes to finish the operation, it's the same one way or the other, right? PROFESSOR: Yes. Tail recursion is not going to change the time complexity of anything because, in some sense, it's the same algorithm that's going on. What it's doing is really making this thing run as an iteration, right? Not going to run out of memory counting up to a giant number simply because the stack would get pushed. See, the thing you really have to believe is that, when we write-- see, we've been writing all these things called iterations, infinite loops, define loop to be called loop. That's is as much an iteration as if we wrote do forever loop, right? It's just syntactic sugar as the difference. These things are real, honest to god, iterations, right? They don't change the time complexity, but they turn them into real iterations. All right, thank you. MIT OpenCourseWare http://ocw.mit.edu 6.001 Structure and Interpretation of Computer Programs, Spring 2005 Please use the following citation format: Eric Grimson, Peter Szolovits, and Trevor Darrell, 6.001 Structure and Interpretation of Computer Programs, Spring 2005. (Massachusetts Institute of Technology: MIT OpenCourseWare). http://ocw.mit.edu (accessed MM DD, YYYY). License: Creative Commons Attribution-Noncommercial-Share Alike. Note: Please use the actual date you accessed thismaterial in your citation. For more information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms ================================================ FILE: Tools/con2table.rb ================================================ #!/usr/bin/env ruby # *encoding: UTF-8* require 'json' def avatar(contributor) "![](#{contributor['avatar']})" end def name(contributor) "[#{contributor['name']}](https://github.com/#{contributor['name']})" end db = JSON.parse(File.open('contributor.json').read) result = db.each_slice(5).map do |line| row = "" row << "|" + line.map {|contri| avatar(contri)}.join("|") + "|\n" row << "|" + line.map {|contri| name(contri)}.join("|") + "|" end.join("\n") puts result ================================================ FILE: Tools/contributor.json ================================================ [ {"name": "DeathKing", "avatar": "https://avatars0.githubusercontent.com/u/895809?s=120"}, {"name": "ChingfanTsou", "avatar": "https://avatars1.githubusercontent.com/u/2025499?s=120"}, {"name": "endyul", "avatar": "https://avatars2.githubusercontent.com/u/1056031?s=120"}, {"name": "mut0u", "avatar": "https://avatars0.githubusercontent.com/u/1238353?s=120"}, {"name": "DreamAndDead", "avatar": "https://avatars1.githubusercontent.com/u/5028822?s=120"}, {"name": "rtmagic", "avatar": "https://avatars2.githubusercontent.com/u/13829499?s=120"}, {"name": "Windfarer", "avatar": "https://avatars2.githubusercontent.com/u/7036121?s=120"}, {"name": "Rezhe", "avatar": "https://avatars1.githubusercontent.com/u/30205820?s=120"}, {"name": "ustcscgy", "avatar": "https://avatars3.githubusercontent.com/u/2822054?s=120"} ] ================================================ FILE: Tools/download-sicp-movies.sh ================================================ # Script by bjartwoIf # From https://gist.github.com/bjartwolf/3471090 wget http://ia700402.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec1a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec1b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec2a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec2b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec3a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec3b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec4a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec4b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec5a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec5b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec6a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec6b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec7a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec7b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec8a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec8b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec9a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec9b.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec10a.mp4 wget http://ia700401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/lec10b.mp4 ================================================ FILE: Tools/lec.json ================================================ [ { "id": "Lec1a", "title": "Lisp概览", "youku": "https://v.youku.com/v_show/id_XNTEzMDAyMTU2.html", "youtube": "https://youtu.be/IcZSFewqr9k", "bilibili": "https://www.bilibili.com/video/av8515129/index_1.html", "baidu": "https://pan.baidu.com/s/1kTmeMgR", "baidu-mp4": "https://pan.baidu.com/s/109WuY4ONSZddFXyE2hQGwg", "translator": ["DeathKing"] }, { "id": "Lec1b", "title": "计算过程", "youku": "https://v.youku.com/v_show/id_XNTMxODY1NTg4.html", "youtube": "https://youtu.be/WuK9NmA3aq0", "bilibili": "https://www.bilibili.com/video/av8515129/index_2.html", "baidu": "https://pan.baidu.com/s/1o6G0Qgi", "baidu-mp4": "https://pan.baidu.com/s/1C3muRwhMdK8yioHWw5P-1Q", "translator": ["ChingfanTsou"] }, { "id": "Lec2a", "title": "高阶过程", "youku": "https://v.youku.com/v_show/id_XNzAzNjI1NjU2.html", "youtube": "https://youtu.be/mrgcGvOI1bs", "bilibili": "https://www.bilibili.com/video/av8515129/index_3.html", "baidu": "https://pan.baidu.com/s/1jG3HI8A", "baidu-mp4": "https://pan.baidu.com/s/1MHiHVHfwq6x8rylBVDGV0A", "translator": ["endyul"] }, { "id": "Lec2b", "title": "复合数据", "youku": "https://v.youku.com/v_show/id_XNzAzNjg4Mjk2.html", "youtube": "https://youtu.be/ufTdeiz9dMw", "bilibili": "https://www.bilibili.com/video/av8515129/index_4.html", "baidu": "https://pan.baidu.com/s/1o6HgNgu", "baidu-mp4": "https://pan.baidu.com/s/1DfX7DJ_pMd7AtMlJwqyoRg", "translator": ["DeathKing"] }, { "id": "Lec3a", "title": "Henderson-Escher的例子", "youku": "https://v.youku.com/v_show/id_XODk4NjUwODMy.html", "youtube": "https://youtu.be/YCR03O5EUdI", "bilibili": "https://www.bilibili.com/video/av8515129/index_5.html", "baidu": "https://pan.baidu.com/s/1bnHBWmz", "baidu-mp4": "https://pan.baidu.com/s/1bOJvDO", "translator": ["DeathKing", "Michael Savior"] }, { "id": "Lec3b", "title": "符号化求导系统:引用", "youku": "https://v.youku.com/v_show/id_XODk4NjUwODA0.html", "youtube": "https://youtu.be/cgGbiMptQM0", "bilibili": "https://www.bilibili.com/video/av8515129/index_6.html", "baidu": "https://pan.baidu.com/s/1o6Jry9G", "baidu-mp4": "https://pan.baidu.com/s/1mhS2EV2", "translator": ["DeathKing"] }, { "id": "Lec4a", "title": "模式匹配:基于规则的代换", "youku": "https://v.youku.com/v_show/id_XMTM4NTY5NzE3Ng.html", "youtube": "https://youtu.be/zSxepaPtNQY", "bilibili": "https://www.bilibili.com/video/av8515129/index_7.html", "baidu": "https://pan.baidu.com/s/1c0Hjs1U", "baidu-mp4": "https://pan.baidu.com/s/1U9E33yRr5mIqrdTOjnJeGA", "translator": ["DeathKing", "Michael Savior"] }, { "id": "Lec4b", "title": "通用运算符", "youku": "https://v.youku.com/v_show/id_XMTQ3NDEwODUyNA==.html", "youtube": "https://youtu.be/RlfZridRcw0", "bilibili": "https://www.bilibili.com/video/av8515129/index_8.html", "baidu": "https://pan.baidu.com/s/1mhyap3E", "baidu-mp4": "https://pan.baidu.com/s/1vAv8Hi46f9ku2y7LHPpzzw", "translator": ["rtmagic"] }, { "id": "Lec5a", "title": "赋值,状态和副作用", "youku": "https://v.youku.com/v_show/id_XMTczMjIxNTM2NA==.html", "youtube": "https://youtu.be/ozss6dvq7ZU", "bilibili": "https://www.bilibili.com/video/av8515129/index_9.html", "baidu": "https://pan.baidu.com/s/1sl7wgqx", "baidu-mp4": "https://pan.baidu.com/s/1boWiMWB", "translator": ["Windfarer"] }, { "id": "Lec5b", "title": "计算对象", "youku": "https://v.youku.com/v_show/id_XMjY0NzE3NzQ2MA==.html", "youtube": "https://youtu.be/2Iz7agtk614", "bilibili": "https://www.bilibili.com/video/av8515129/index_10.html", "baidu": "https://pan.baidu.com/s/1kVG8SNP", "baidu-mp4": "https://pan.baidu.com/s/1c1FRLIg", "translator": ["DreamAndDead"] }, { "id": "Lec6a", "title": "流 I", "youku": "https://v.youku.com/v_show/id_XMjg4NTkwNzU3Ng==.html", "youtube": "https://youtu.be/z7jvvATswFE", "bilibili": "https://www.bilibili.com/video/av8515129/index_11.html", "baidu": "https://pan.baidu.com/s/1hs7rNwg", "baidu-mp4": "https://pan.baidu.com/s/1pLlvcLH", "translator": ["DreamAndDead"] }, { "id": "Lec6b", "title": "流 II", "youku": "https://v.youku.com/v_show/id_XMzAyMjI0MjAzNg==.html", "youtube": "https://youtu.be/0lQ6fThLhYw", "bilibili": "https://www.bilibili.com/video/av8515129/index_12.html", "baidu": "https://pan.baidu.com/s/1micH5OW", "baidu-mp4": "https://pan.baidu.com/s/1b3kbWq", "translator": ["DreamAndDead"] }, { "id": "Lec7a", "title": "元循环求值器 I", "youku": "https://v.youku.com/v_show/id_XMzAzODg2ODczNg==.html", "youtube": "https://youtu.be/RXUqgWJES0w", "bilibili": "https://www.bilibili.com/video/av8515129/index_13.html", "baidu": "https://pan.baidu.com/s/1kUYGlVp", "baidu-mp4": "https://pan.baidu.com/s/1kV1M0ab", "translator": ["DeathKing", "DreamAndDead"] }, { "id": "Lec7b", "title": "元循环求值器 II", "youku": "https://v.youku.com/v_show/id_XMzA2NDQ5MjkxMg==.html", "youtube": "https://youtu.be/HNaAEv8Xjx8", "bilibili": "https://www.bilibili.com/video/av8515129/index_14.html", "baidu": "https://pan.baidu.com/s/1eSrNSNS", "baidu-mp4": "https://pan.baidu.com/s/1qYBgrIO", "translator": ["DeathKing", "DreamAndDead"] }, { "id": "Lec8a", "title": "逻辑式程序设计 I", "youku": "https://v.youku.com/v_show/id_XMzIyODg0NTEwNA==.html", "youtube": "https://youtu.be/VNH95lmCHdE", "bilibili": "https://www.bilibili.com/video/av8515129/index_15.html", "baidu": "https://pan.baidu.com/s/1i5aQQVj", "baidu-mp4": "https://pan.baidu.com/s/1dFlOqrB", "translator": ["DeathKing"] }, { "id": "Lec8b", "title": "逻辑式程序设计 II", "youku": "https://v.youku.com/v_show/id_XMzQ4MDA1OTE3Mg==.html", "youtube": "https://youtu.be/mcik1gEEyqA", "bilibili": "https://www.bilibili.com/video/av8515129/index_16.html", "baidu": "https://pan.baidu.com/s/1P6b00XxTfaaQX5GxSbROjg", "baidu-mp4": "https://pan.baidu.com/s/1MN5ZDrnnKeE0XeMqAY6x0Q", "translator": ["DeathKing"] }, { "id": "Lec9a", "title": "寄存机器", "youku": "https://v.youku.com/v_show/id_XMzU3MzA5Mzg0OA==.html", "youtube": "https://youtu.be/oR2PwG0xh_g", "bilibili": "https://www.bilibili.com/video/av8515129/index_17.html", "baidu": "#", "baidu-mp4": "https://pan.baidu.com/s/1AFM6__x4oGq3XtI_fa3ZGQ", "translator": ["DeathKing"] }, { "id": "Lec9b", "title": "显式控制求值器", "youku": "https://v.youku.com/v_show/id_XMzcxMDAzMTA1Mg==.html", "youtube": "https://youtu.be/mrRcB4uY75M", "bilibili": "https://www.bilibili.com/video/av8515129/index_18.html", "baidu": "#", "baidu-mp4": "https://pan.baidu.com/s/1bHhuJdEQyE9Fyw06Y6tOZw", "translator": ["DeathKing", "rtmagic"] }, { "id": "Lec10a", "title": "编译", "youku": "https://v.youku.com/v_show/id_XMzYyNTcxNDYwOA==.html", "youtube": "https://youtu.be/vBEkYVrtfBE", "bilibili": "https://www.bilibili.com/video/av8515129/index_19.html", "baidu": "#", "baidu-mp4": "https://pan.baidu.com/s/1IWkeR7gM5jiVFPMVhdZ4fg", "translator": ["Windfarer"] } , { "id": "Lec10b", "title": "存储分配与垃圾收集", "youku": "https://v.youku.com/v_show/id_XMzc3NjI4MzQ4NA==.html", "youtube": "https://youtu.be/HNjPAzmSho8", "bilibili": "https://www.bilibili.com/video/av8515129/index_20.html", "baidu": "#", "baidu-mp4": "https://pan.baidu.com/s/1LKoXNWFD9lFclgNKeCBxsg", "translator": ["Windfarer"] } ] ================================================ FILE: Tools/lec2tabel.rb ================================================ #!/usr/bin/env ruby # *encoding: UTF-8* require 'json' AUTHORS = { "ChingfanTsou" => "https://github.com/ChingfanTsou", "DeathKing" => "https://github.com/DeathKing", "endyul" => "https://github.com/endyul", "Michael Savior" => "https://github.com/mut0u", "rtmagic" => "https://github.com/rtmagic", "Windfarer" => "https://github.com/Windfarer", "DreamAndDead" => "https://github.com/DreamAndDead", } # [优酷] [YouTube] [bilibili] [MP4-内嵌字幕] FORMAT = "| %-s | %-s | %-s %-s %-s %-s | %-s |" ICON = { "youtube" => "https://cloud.githubusercontent.com/assets/895809/7487454/7bcde098-f3ea-11e4-85be-d267459c4974.png", "youku" => "https://cloud.githubusercontent.com/assets/895809/7487453/7ad84a02-f3ea-11e4-9af4-2f8c4dc8679d.png", "baidu" => "https://cloud.githubusercontent.com/assets/895809/7487452/7aca0af0-f3ea-11e4-97a2-9ad4af3c6e2e.png" } def render_authors(authors) res = [] authors.each do |a| res << (AUTHORS.has_key?(a) ? render_as_mdlink(a, AUTHORS[a]) : a) end res.join(", ") end def render_as_mdlink(text, link=nil) (link.nil? || link == '#') ? text : "[#{text}](#{link})" end def render_as_mdpic(alt, link) "![#{alt}](#{link})" end def render_as_mdpiclink(picurl, text, link) render_as_mdlink render_as_mdpic(text, picurl), link end def itemize(row) FORMAT % [ row["id"], "《" + row["title"] + "》", render_as_mdlink(" [优酷] ", row["youku"]), render_as_mdlink(" [YouTube] ", row["youtube"]), render_as_mdlink(" [bilibili] ", row["bilibili"]), render_as_mdlink(" [MP4] ", row["baidu-mp4"]), render_authors(row["translator"]) ] end def table_head "| 编号 | 标题 | 下载地址 | 译者 |" end def divider "| ---- | ---- |:-----------------------:| ---- |" end content = File.open('lec.json').read db = JSON.parse(content) puts table_head puts divider db.each do |row| puts itemize(row) end ================================================ FILE: Tools/merge.rb ================================================ #!/usr/bin/env ruby # MERGE.RB: merge two subtitles into one. # # usage: merge file1 file2 [output_file] # # options: -b backup original file require_relative 'util' class IO def each_unit(lines) result = [] each_line do |line| result << line if result.size == lines yield result result = [] end end result << "" until result.size == lines yield result end end SubUnit = Struct.new(:number, :timeline, :content, :tag) target = ARGV[2] unless ARGV.size >= 3 backup_file File.expand_path(ARGV[0]) backup_file File.expand_path(ARGV[1]) target = ARGV[0] end chn = [] eng = [] open(ARGV[0]).each_unit(4) do |u| number, timeline, content, _ = *u chn << SubUnit.new(number, timeline, content, 'chn') end open(ARGV[1]).each_unit(4) do |u| number, timeline, content, _ = *u eng << SubUnit.new(number, timeline, content, 'eng') end # actual_merge merged = [] chn.zip(eng) do |p| chn, eng = *p if chn.timeline != eng.timeline puts "Some thing unmatched found:" puts "[CHN %4s %30s]%s" % [chn.number, chn.timeline, chn.content] puts "[ENG %4s %30s]%s" % [eng.number, eng.timeline, eng.content] puts "Aborted!" exit(0) end chn.content = "#{chn.content}#{eng.content}" merged << chn end open(target, "w") do |f| merged.each do |m| f.puts m.number f.puts m.timeline f.puts m.content f.puts "\n" end end ================================================ FILE: Tools/pdf2txt.rb ================================================ #!/usr/bin/env ruby # Gist from: https://gist.github.com/blazeeboy/9722831 #begin require 'pdf/reader' require 'fileutils' #ensure # puts "Oops! Must something went wrong." # puts "I think you should try `gem install pdf-reader` before excute this." # exit #end # credits to : # https://github.com/yob/pdf-reader/blob/master/examples/text.rb # usage example: # ruby pdf2txt.rb /path-to-file/file1.pdf [/path-to-file/file2.pdf..] Dir.foreach(ARGV.first) do |filename| next if [".", ".."].include? filename PDF::Reader.open(filename) do |reader| puts "Converting : #{filename}" pageno = 0 txt = reader.pages.map do |page| pageno += 1 begin print "Converting Page #{pageno}/#{reader.page_count}\r" page.text rescue puts "Page #{pageno}/#{reader.page_count} Failed to convert" '' end end # pages map puts "\nWriting text to disk" File.write filename+'.txt', txt.join("\n") end # reader end # each ================================================ FILE: Tools/separate.rb ================================================ #!/usr/bin/env ruby # encoding: utf-8 if ARGV.empty? puts "Separate - 分割单个双语字幕为两个字幕。" puts "用法: separate srt_file" puts "说明:如果出错了,尝试调整一下newline。" puts "Writen by DeathKing" exit end eng = [] chn = [] cont = [] # 换行符,由于文件比较混乱,有时需要自行调整 # 如有问题,可以尝试调整为 \n、\r、\r\n中的其它值 newline = "\n" open(ARGV[0]).each_line do |line| if line == newline # 一个块 eng << cont[0] << cont[1] chn << cont[0] << cont[1] # 非字幕块,即为制作信息时的处理 # 把内容全拷贝到中文字幕文件中 # 英文字幕用newline占位 if cont.size != 4 for i in 2...cont.size chn << cont[i] end chn << newline eng << newline << newline else # 拷贝到对应文件中去 chn << cont[2] << newline eng << cont[3] << newline end cont.clear else cont << line end end filename = ARGV[0].split(".")[0] eng_file = "#{filename}_eng.srt" chn_file = "#{filename}_chn.srt" open(eng_file, "w").puts(eng.join) open(chn_file, "w").puts(chn.join) ================================================ FILE: Tools/split.pl ================================================ #! /usr/bin/perl use 5.010; use utf8; use warnings; use strict; my $srt_file = shift(@ARGV); open SRT, '<:encoding(UTF-8)', $srt_file; my @text = ; close SRT; if (@ARGV) { $srt_file = shift(@ARGV); } open NEWSRT, '>:encoding(UTF-8)', $srt_file; foreach my $line (@text) { chomp($line); $line =~ s/((?:[,.?!;:])|(?:-+))\s/$1\n\n\n\n/g; print NEWSRT $line; } close NEWSRT; ================================================ FILE: Tools/split.rb ================================================ #!/usr/bin/env ruby # encoding: utf-8 require_relative 'util' def help doc = <<-HELP HELP end filename = ARGV.first backup_file(filename) puts File.open(filename).each_line.map do |line| line.gsub! "\n", "" line.gsub! ". ", ".\n" line.strip! line end.join ================================================ FILE: Tools/timeline.rb ================================================ #!/usr/bin/env ruby # --* encoding: utf-8 *-- require 'fileutils' cont = [] block = [] counter, flag = 1, false newline = "\n" template = "%d#{newline}00:00:00,000 --> 00:00:00,000#{newline}" if ARGV.empty? puts "Timeline - 为字幕添加初始化时间轴。" puts "用法: timeline /path/to/your/file.srt" puts "说明:本地会备份一个文件。如果使用出现了问题,请尝试调整newline。" puts "\nWriten by DeathKing" exit end FileUtils.cp ARGV[0], ARGV[0] + ".backup" open(ARGV[0]).each_line do |line| if line == newline and !flag cont << sprintf(template, counter) << block.clone << newline flag = true counter += 1 block.clear else block << line flag = false end end open(ARGV[0], "w").puts(cont.join) ================================================ FILE: Tools/util.rb ================================================ # --* encoding: utf-8 *-- require 'fileutils' def backup_filename(filename) filename + ".backup" end def backup_file(filename) FileUtils.cp(filename, backup_filename(filename)) end